[
  {
    "path": ".cargo/config.toml",
    "content": "[alias]\ncheats = \"test -p foundry-cheatcodes-spec --features schema tests::\"\ntest-debugger = \"test -p forge --test cli manual_debug_setup -- --include-ignored --nocapture\"\nbless-lints = \"test -p forge --test ui -- --bless\"\n\n# Increase the stack size to 10MB for Windows targets, which is in line with Linux\n# (whereas default for Windows is 1MB).\n[target.x86_64-pc-windows-msvc]\nrustflags = [\"-Clink-arg=/STACK:10000000\"]\n\n[target.i686-pc-windows-msvc]\nrustflags = [\"-Clink-arg=/STACK:10000000\"]\n"
  },
  {
    "path": ".config/nextest.toml",
    "content": "[test-groups]\n\n[profile.default]\nretries = { backoff = \"exponential\", count = 2, delay = \"5s\", jitter = true }\nslow-timeout = { period = \"30s\", terminate-after = 3 }\n# Exclude flaky tests from regular CI runs - they run in nightly test-flaky workflow\ndefault-filter = \"not test(/flaky_/)\"\n\n[[profile.default.overrides]]\nfilter = \"test(/ext_integration/)\"\nslow-timeout = { period = \"5m\", terminate-after = 4 }\n\n# Do not re-run so that `cargo cheats` is ran locally.\n[[profile.default.overrides]]\nfilter = \"package(foundry-cheatcodes-spec)\"\nretries = 0\n\n# Profile for running flaky tests (used by nightly CI and for local debugging)\n# Run with: cargo nextest run --profile flaky\n[profile.flaky]\ndefault-filter = \"test(/flaky_/)\"\nretries = { backoff = \"exponential\", count = 5, delay = \"10s\", jitter = true }\nslow-timeout = { period = \"60s\", terminate-after = 3 }\n"
  },
  {
    "path": ".devcontainer/Dockerfile.dev",
    "content": "FROM ubuntu:22.04\n\nARG USERNAME=foundry\nARG USER_UID=1000\nARG USER_GID=$USER_UID\nARG PYTHON_VERSION=3.14\nARG NODE_MAJOR=20\nARG VYPER_VERSION=0.4.3\n\nENV DEBIAN_FRONTEND=noninteractive\nENV CARGO_TERM_COLOR=always \\\n    RUST_BACKTRACE=full\n\nWORKDIR /workspace\n\nRUN apt-get update && apt-get install -y --no-install-recommends \\\n    # Build tools\n    build-essential \\\n    clang \\\n    lld \\\n    pkg-config \\\n    # Network/SSL\n    curl \\\n    ca-certificates \\\n    gnupg \\\n    libssl-dev \\\n    # Version control & utils\n    git \\\n    sudo \\\n    unzip \\\n    # Python\n    python${PYTHON_VERSION} \\\n    python3-pip \\\n    python${PYTHON_VERSION}-venv \\\n    # Add Node.js repo\n    && mkdir -p /etc/apt/keyrings \\\n    && curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg \\\n    && echo \"deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_${NODE_MAJOR}.x nodistro main\" | tee /etc/apt/sources.list.d/nodesource.list \\\n    # Update again after adding repo and install Node.js\n    && apt-get update && apt-get install -y --no-install-recommends \\\n    nodejs \\\n    # Clean up apt cache\n    && apt-get clean && rm -rf /var/lib/apt/lists/*\n\n# Ensure python points to the installed python version\nRUN ln -sf /usr/bin/python${PYTHON_VERSION} /usr/bin/python && \\\n    ln -sf /usr/bin/python${PYTHON_VERSION} /usr/bin/python3\n\n# Create non-root user with sudo privileges\nRUN groupadd --gid $USER_GID $USERNAME \\\n    && useradd --uid $USER_UID --gid $USER_GID -m $USERNAME -s /bin/bash \\\n    # Setup sudo without password prompt\n    && echo \"$USERNAME ALL=(ALL) NOPASSWD:ALL\" > /etc/sudoers.d/$USERNAME \\\n    && chmod 0440 /etc/sudoers.d/$USERNAME \\\n    # Add user to the sudo group (standard practice)\n    && usermod -aG sudo $USERNAME\n\n# Switch to the non-root user\nUSER $USERNAME\nWORKDIR /home/$USERNAME\n\n# --- User-specific installations ---\n\n# Install Bun\nENV BUN_INSTALL=\"/home/$USERNAME/.bun\"\nENV PATH=\"$BUN_INSTALL/bin:$PATH\"\nRUN curl -fsSL https://bun.sh/install | bash\n\n# Install Rust & cargo-nextest\nENV CARGO_HOME=\"/home/$USERNAME/.cargo\"\nENV RUSTUP_HOME=\"/home/$USERNAME/.rustup\"\nENV PATH=\"$CARGO_HOME/bin:$PATH\"\nRUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y \\\n    && cargo install cargo-nextest --locked\n\n# Install Vyper using pip\n# Ensure pip user install directory is in PATH\nENV PYTHONUSERBASE=\"/home/$USERNAME/.local\"\nENV PATH=\"$PYTHONUSERBASE/bin:$PATH\"\nRUN pip3 install --user vyper==${VYPER_VERSION}\n\n# Switch back to the main workspace directory\nWORKDIR /workspace\n\n"
  },
  {
    "path": ".devcontainer/devcontainer.json",
    "content": "// For format details, see https://aka.ms/devcontainer.json.\n{\n  \"name\": \"Foundry Development\",\n  \"build\": {\n    \"context\": \"..\",\n    \"dockerfile\": \"Dockerfile.dev\"\n  },\n\n  \"features\": {\n    \"ghcr.io/devcontainers/features/common-utils:2\": {\n      \"installZsh\": true,\n      \"configureZshAsDefaultShell\": true,\n      \"installOhMyZsh\": true,\n      \"upgradePackages\": true\n    }\n  },\n\n  \"forwardPorts\": [],\n\n  \"postCreateCommand\": \"rustup default stable && rustup update\",\n\n  \"customizations\": {\n    \"vscode\": {\n      \"extensions\": [\n        \"rust-lang.rust-analyzer\",\n        \"serayuzgur.crates\",\n        \"tamasfe.even-better-toml\",\n        \"ms-python.python\",\n        \"dbaeumer.vscode-eslint\",\n        \"oven.bun-vscode\"\n      ],\n      \"settings\": {\n        \"rust-analyzer.checkOnSave\": true,\n        \"rust-analyzer.cargo.features\": \"all\"\n      }\n    }\n  },\n\n  \"remoteUser\": \"foundry\",\n\n  \"workspaceMount\": \"source=${localWorkspaceFolder},target=/workspace,type=bind,consistency=cached\",\n\n  \"workspaceFolder\": \"/workspace\",\n\n  \"mounts\": [\n    \"source=${localEnv:HOME}/.cargo/registry,target=/home/foundry/.cargo/registry,type=bind,consistency=cached\",\n    \"source=${localEnv:HOME}/.cargo/git,target=/home/foundry/.cargo/git,type=bind,consistency=cached\"\n  ]\n}\n"
  },
  {
    "path": ".dockerignore",
    "content": "target\n.github\n"
  },
  {
    "path": ".git-blame-ignore-revs",
    "content": "# Since version 2.23 (released in August 2019), git-blame has a feature\n# to ignore or bypass certain commits.\n#\n# This file contains a list of commits that are not likely what you\n# are looking for in a blame, such as mass reformatting or renaming.\n# You can set this file as a default ignore file for blame by running\n# the following command.\n#\n# $ git config blame.ignoreRevsFile .git-blame-ignore-revs\n\n# fmt: all (#3398)\n860d083183b51a6f8d865408ef1a44aa694d6862\n\n# chore: bump to rust edition 2024 (#10802)\n710a1584aae8e0f8ca8d5ba552632dc72381091e\n"
  },
  {
    "path": ".gitattributes",
    "content": "crates/cheatcodes/assets/*.json linguist-generated\ntestdata/cheats/Vm.sol linguist-generated\nbun.lock linguist-generated\n\n# See <https://git-scm.com/docs/gitattributes#_defining_a_custom_hunk_header>\n*.rs diff=rust\ncrates/lint/testdata/* text eol=lf\ntestdata/fixtures/**/* eol=lf\n\ndprint.json linguist-language=JSON-with-Comments\n.devcontainer/devcontainer.json linguist-language=JSON-with-Comments\n\n.env.example linguist-language=Dotenv"
  },
  {
    "path": ".github/CODEOWNERS",
    "content": "* @danipopes @mattsse @grandizzy @yash-atreya @zerosnacks @onbjerg @0xrusowsky\n"
  },
  {
    "path": ".github/FLAKY_TEST_FAILURE_TEMPLATE.md",
    "content": "---\ntitle: \"bug: flaky tests workflow failed\"\nlabels: P-normal, T-bug\n---\n\nThe nightly flaky tests workflow has failed. This indicates external API rate limiting, RPC reliability issues, or other intermittent failures that may affect users.\n\nCheck the [flaky tests workflow page]({{ env.WORKFLOW_URL }}) for details.\n\nThis issue was raised by the workflow at `.github/workflows/test-flaky.yml`.\n"
  },
  {
    "path": ".github/FLAKY_TEST_ISOLATE_FAILURE_TEMPLATE.md",
    "content": "---\ntitle: \"bug: flaky tests workflow failed (isolate)\"\nlabels: P-normal, T-bug\n---\n\nThe nightly flaky tests workflow (with isolation mode enabled) has failed. This indicates external API rate limiting, RPC reliability issues, or other intermittent failures that may affect users.\n\nCheck the [flaky tests workflow page]({{ env.WORKFLOW_URL }}) for details.\n\nThis issue was raised by the workflow at `.github/workflows/test-isolate.yml`.\n"
  },
  {
    "path": ".github/INTEGRATION_FAILURE.md",
    "content": "---\ntitle: \"bug: long-running integration tests failed\"\nlabels: P-high, T-bug\n---\n\nThe heavy (long-running) integration tests have failed. This indicates a regression in Foundry.\n\nCheck the [heavy integration tests workflow page]({{ env.WORKFLOW_URL }}) for details.\n\nThis issue was raised by the workflow at `.github/workflows/heavy-integration.yml`.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/BUG-FORM.yml",
    "content": "name: Bug report\ndescription: File a bug report\ntype: Bug\nlabels: [\"T-bug\", \"T-needs-triage\"]\nbody:\n  - type: markdown\n    attributes:\n      value: |\n        Please ensure that the bug has not already been filed in the issue tracker.\n\n        Thanks for taking the time to report this bug!\n  - type: dropdown\n    id: component\n    attributes:\n      label: Component\n      description: What component is the bug in?\n      multiple: true\n      options:\n        - Forge\n        - Cast\n        - Anvil\n        - Foundryup\n        - Chisel\n        - Other (please describe)\n    validations:\n      required: true\n  - type: checkboxes\n    attributes:\n      label: Have you ensured that all of these are up to date?\n      options:\n        - label: Foundry\n        - label: Foundryup\n  - type: input\n    attributes:\n      label: What version of Foundry are you on?\n      placeholder: \"Run forge --version and paste the output here\"\n  - type: input\n    attributes:\n      label: What version of Foundryup are you on?\n      placeholder: \"Run foundryup --version and paste the output here\"\n  - type: input\n    attributes:\n      label: What command(s) is the bug in?\n      description: Leave empty if not relevant\n      placeholder: \"For example: forge test\"\n  - type: dropdown\n    attributes:\n      label: Operating System\n      description: What operating system are you on?\n      options:\n        - Windows\n        - macOS (Intel)\n        - macOS (Apple Silicon)\n        - Linux\n  - type: textarea\n    id: description\n    attributes:\n      label: Describe the bug\n      description: Please include relevant Solidity snippets as well if relevant.\n    validations:\n      required: true\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/FEATURE-FORM.yml",
    "content": "name: Feature request\ndescription: Suggest a feature\ntype: Feature\nlabels: [\"T-feature\", \"T-needs-triage\"]\nbody:\n  - type: markdown\n    attributes:\n      value: |\n        Please ensure that the feature has not already been requested in the issue tracker.\n\n        Thanks for helping us improve Foundry!\n  - type: dropdown\n    id: component\n    attributes:\n      label: Component\n      description: What component is the feature for?\n      multiple: true\n      options:\n        - Forge\n        - Cast\n        - Anvil\n        - Foundryup\n        - Chisel\n        - Other (please describe)\n    validations:\n      required: true\n  - type: textarea\n    id: description\n    attributes:\n      label: Describe the feature you would like\n      description: Please also describe what the feature is aiming to solve, if relevant.\n    validations:\n      required: true\n  - type: textarea\n    attributes:\n      label: Additional context\n      description: Add any other context to the feature (like screenshots, resources)\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "content": "blank_issues_enabled: true\ncontact_links:\n    - name: Support\n      url: https://t.me/foundry_support\n      about: This issue tracker is only for bugs and feature requests. Support is available on Telegram!\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "content": "<!--\nThank you for your Pull Request. Please provide a description above and review\nthe requirements below.\n\nBug fixes and new features should include tests.\n\nContributors guide: https://github.com/foundry-rs/foundry/blob/HEAD/CONTRIBUTING.md\n\nThe contributors guide includes instructions for running rustfmt and building the\ndocumentation.\n-->\n\n<!-- ** Please select \"Allow edits from maintainers\" in the PR Options ** -->\n\n## Motivation\n\n<!--\nExplain the context and why you're making that change. What is the problem\nyou're trying to solve? In some cases there is not a problem and this can be\nthought of as being the motivation for your change.\n-->\n\n## Solution\n\n<!--\nSummarize the solution and provide any necessary context needed to understand\nthe code change.\n-->\n\n## PR Checklist\n\n- [ ] Added Tests\n- [ ] Added Documentation\n- [ ] Breaking changes\n"
  },
  {
    "path": ".github/RELEASE_FAILURE_ISSUE_TEMPLATE.md",
    "content": "---\ntitle: \"bug: release workflow failed\"\nlabels: P-high, T-bug\n---\n\nThe release workflow has failed. Some or all binaries might have not been published correctly.\n\nCheck the [release workflow page]({{ env.WORKFLOW_URL }}) for details.\n\nThis issue was raised by the workflow at `.github/workflows/release.yml`.\n"
  },
  {
    "path": ".github/TEST_ISOLATE_FAILURE_TEMPLATE.md",
    "content": "---\ntitle: \"bug: test-isolate workflow failed\"\nlabels: P-high, T-bug\n---\n\nThe daily test-isolate workflow (tests with isolation mode enabled) has failed. This indicates a regression in Foundry's test isolation behavior.\n\nCheck the [test-isolate workflow page]({{ env.WORKFLOW_URL }}) for details.\n\nThis issue was raised by the workflow at `.github/workflows/test-isolate.yml`.\n"
  },
  {
    "path": ".github/changelog.json",
    "content": "{\n    \"categories\": [\n        {\n            \"title\": \"## Breaking changes\",\n            \"labels\": [\"T-likely-breaking \"]\n        },\n        {\n            \"title\": \"## Anvil Features\",\n            \"labels\": [\"C-anvil\", \"T-feature\"],\n            \"exhaustive\": true,\n            \"exhaustive_rules\": false\n        },\n        {\n            \"title\": \"## Anvil Fixes\",\n            \"labels\": [\"C-anvil\", \"T-bug\"],\n            \"exhaustive\": true,\n            \"exhaustive_rules\": false\n        },\n        {\n            \"title\": \"## Cast Features\",\n            \"labels\": [\"C-cast\", \"T-feature\"],\n            \"exhaustive\": true,\n            \"exhaustive_rules\": false\n        },\n        {\n            \"title\": \"## Cast Fixes\",\n            \"labels\": [\"C-cast\", \"T-bug\"],\n            \"exhaustive\": true,\n            \"exhaustive_rules\": false\n        },\n        {\n            \"title\": \"## Chisel Features\",\n            \"labels\": [\"C-chisel\", \"T-feature\"],\n            \"exhaustive\": true,\n            \"exhaustive_rules\": false\n        },\n        {\n            \"title\": \"## Chisel Fixes\",\n            \"labels\": [\"C-chisel\", \"T-bug\"],\n            \"exhaustive\": true,\n            \"exhaustive_rules\": false\n        },\n        {\n            \"title\": \"## Forge Features\",\n            \"labels\": [\"C-forge\", \"T-feature\"],\n            \"exhaustive\": true,\n            \"exhaustive_rules\": false\n        },\n        {\n            \"title\": \"## Forge Fixes\",\n            \"labels\": [\"C-forge\", \"T-bug\"],\n            \"exhaustive\": true,\n            \"exhaustive_rules\": false\n        },\n        {\n            \"title\": \"## Performance improvements\",\n            \"labels\": [\"T-perf\"]\n        }\n    ],\n    \"ignore_labels\": [\"L-ignore\"],\n    \"template\": \"${{CHANGELOG}}\\n## Other\\n\\n${{UNCATEGORIZED}}\\n## Full Changelog:\\n ${{RELEASE_DIFF}}\",\n    \"pr_template\": \"- ${{TITLE}} (#${{NUMBER}}) by @${{AUTHOR}}\",\n    \"empty_template\": \"- No changes\",\n    \"max_pull_requests\": 500,\n    \"max_back_track_time_days\": 120\n}\n"
  },
  {
    "path": ".github/dependabot.yml",
    "content": "version: 2\nupdates:\n  - package-ecosystem: \"github-actions\"\n    directory: \"/\"\n    schedule:\n      interval: \"weekly\"\n    ignore:\n      - dependency-name: \"softprops/action-gh-release\"\n"
  },
  {
    "path": ".github/scripts/combine-benchmarks.sh",
    "content": "#!/bin/bash\nset -euo pipefail\n\n# Script to combine individual benchmark results into LATEST.md\n# Usage: ./combine-benchmarks.sh <output_dir>\n\nOUTPUT_DIR=\"${1:-benches}\"\n\n# Create output directory if it doesn't exist\nmkdir -p \"$OUTPUT_DIR\"\n\n# Define the benchmark files and their section names\ndeclare -A BENCHMARK_FILES=(\n    [\"forge_test_bench.md\"]=\"Forge Test\"\n    [\"forge_isolate_test_bench.md\"]=\"Forge Test (Isolated)\"\n    [\"forge_build_bench.md\"]=\"Forge Build\"\n    [\"forge_coverage_bench.md\"]=\"Forge Coverage\"\n)\n\n# Function to extract a specific section from a benchmark file\nextract_section() {\n    local file=$1\n    local section=$2\n    local in_section=0\n\n    while IFS= read -r line; do\n        if [[ \"$line\" =~ ^##[[:space:]]+\"$section\" ]]; then\n            in_section=1\n            echo \"$line\"\n        elif [[ $in_section -eq 1 && \"$line\" =~ ^##[[:space:]] && ! \"$line\" =~ ^##[[:space:]]+\"$section\" ]]; then\n            break\n        elif [[ $in_section -eq 1 ]]; then\n            echo \"$line\"\n        fi\n    done < \"$file\"\n}\n\n# Function to extract summary info (repos and versions) from a file\nextract_summary_info() {\n    local file=$1\n    local in_summary=0\n    local in_repos=0\n    local in_versions=0\n\n    while IFS= read -r line; do\n        # Check for Summary section\n        if [[ \"$line\" =~ ^##[[:space:]]+Summary ]]; then\n            in_summary=1\n            continue\n        fi\n\n        # Check for Repositories Tested subsection\n        if [[ $in_summary -eq 1 && \"$line\" =~ ^###[[:space:]]+Repositories[[:space:]]+Tested ]]; then\n            in_repos=1\n            echo \"### Repositories Tested\"\n            echo\n            continue\n        fi\n\n        # Check for Foundry Versions subsection\n        if [[ $in_summary -eq 1 && \"$line\" =~ ^###[[:space:]]+Foundry[[:space:]]+Versions ]]; then\n            in_repos=0\n            in_versions=1\n            echo \"### Foundry Versions\"\n            echo\n            continue\n        fi\n\n        # End of summary section\n        if [[ $in_summary -eq 1 && \"$line\" =~ ^##[[:space:]] && ! \"$line\" =~ ^##[[:space:]]+Summary ]]; then\n            break\n        fi\n\n        # Output repo or version lines\n        if [[ ($in_repos -eq 1 || $in_versions -eq 1) && -n \"$line\" ]]; then\n            echo \"$line\"\n        fi\n    done < \"$file\"\n}\n\n# Function to extract benchmark table from a section\nextract_benchmark_table() {\n    local file=$1\n    local section=$2\n    local in_section=0\n    local found_table=0\n\n    while IFS= read -r line; do\n        if [[ \"$line\" =~ ^##[[:space:]]+\"$section\" ]]; then\n            in_section=1\n            continue\n        elif [[ $in_section -eq 1 && \"$line\" =~ ^##[[:space:]] && ! \"$line\" =~ ^##[[:space:]]+\"$section\" ]]; then\n            break\n        elif [[ $in_section -eq 1 ]]; then\n            # Skip empty lines before table\n            if [[ -z \"$line\" && $found_table -eq 0 ]]; then\n                continue\n            fi\n            # Detect table start\n            if [[ \"$line\" =~ ^\\|[[:space:]]*Repository ]]; then\n                found_table=1\n            fi\n            # Output table lines\n            if [[ $found_table -eq 1 && -n \"$line\" ]]; then\n                echo \"$line\"\n            fi\n        fi\n    done < \"$file\"\n}\n\n# Function to extract system information\nextract_system_info() {\n    local file=$1\n    awk '/^## System Information/ { found=1; next } found { print }' \"$file\"\n}\n\n# Start building LATEST.md\ncat > \"$OUTPUT_DIR/LATEST.md\" << EOF\n# 📊 Foundry Benchmark Results\n\n**Generated at**: $(date -u '+%Y-%m-%d %H:%M:%S UTC')\n\nEOF\n\n# Process each benchmark file\nFIRST_FILE=1\nSYSTEM_INFO=\"\"\n\nfor bench_file in \"forge_test_bench.md\" \"forge_isolate_test_bench.md\" \"forge_build_bench.md\" \"forge_coverage_bench.md\"; do\n    if [ -f \"$OUTPUT_DIR/$bench_file\" ]; then\n        echo \"Processing $bench_file...\"\n\n        SECTION_NAME=\"${BENCHMARK_FILES[$bench_file]:-$bench_file}\"\n\n        # Grouped output for ShellCheck SC2129\n        {\n            # Add section header\n            echo \"## $SECTION_NAME\"\n            echo\n\n            # Add summary info\n            extract_summary_info \"$OUTPUT_DIR/$bench_file\"\n            echo\n\n            # Handle benchmark tables\n            if [[ \"$bench_file\" == \"forge_test_bench.md\" ]]; then\n                extract_benchmark_table \"$OUTPUT_DIR/$bench_file\" \"Forge Test\"\n                echo\n                if grep -q \"^## Forge Fuzz Test\" \"$OUTPUT_DIR/$bench_file\"; then\n                    echo \"## Forge Fuzz Test\"\n                    echo\n                    extract_benchmark_table \"$OUTPUT_DIR/$bench_file\" \"Forge Fuzz Test\"\n                fi\n            elif [[ \"$bench_file\" == \"forge_build_bench.md\" ]]; then\n                echo \"### No Cache\"\n                echo\n                extract_benchmark_table \"$OUTPUT_DIR/$bench_file\" \"Forge Build (No Cache)\"\n                echo\n                echo \"### With Cache\"\n                echo\n                extract_benchmark_table \"$OUTPUT_DIR/$bench_file\" \"Forge Build (With Cache)\"\n            else\n                extract_benchmark_table \"$OUTPUT_DIR/$bench_file\" \"$SECTION_NAME\"\n            fi\n            echo\n        } >> \"$OUTPUT_DIR/LATEST.md\"\n\n        # Extract system info from first file only\n        if [[ $FIRST_FILE -eq 1 ]]; then\n            SYSTEM_INFO=$(extract_system_info \"$OUTPUT_DIR/$bench_file\")\n            FIRST_FILE=0\n        fi\n    else\n        echo \"Warning: $bench_file not found, skipping...\"\n    fi\ndone\n\n# Add system information at the end\nif [[ -n \"$SYSTEM_INFO\" ]]; then\n    {\n        echo \"## System Information\"\n        echo\n        echo \"$SYSTEM_INFO\"\n    } >> \"$OUTPUT_DIR/LATEST.md\"\nfi\n\necho \"Successfully combined benchmark results into $OUTPUT_DIR/LATEST.md\"\n"
  },
  {
    "path": ".github/scripts/commit-and-read-benchmarks.sh",
    "content": "#!/bin/bash\nset -euo pipefail\n\n# Script to commit benchmark results and read them for GitHub Actions output\n# Usage: ./commit-and-read-benchmarks.sh <output_dir> <github_event_name> <github_repository>\n\nOUTPUT_DIR=\"${1:-benches}\"\nGITHUB_EVENT_NAME=\"${2:-pull_request}\"\nGITHUB_REPOSITORY=\"${3:-}\"\n\n# Global variable for branch name\nBRANCH_NAME=\"\"\n\n# Function to commit benchmark results\ncommit_results() {\n    echo \"Configuring git...\"\n    git config --local user.email \"action@github.com\"\n    git config --local user.name \"GitHub Action\"\n\n    # For PR runs, fetch and checkout the PR branch to ensure we're up to date\n    if [ \"$GITHUB_EVENT_NAME\" = \"pull_request\" ] && [ -n \"${GITHUB_HEAD_REF:-}\" ]; then\n        echo \"Fetching latest changes for PR branch: $GITHUB_HEAD_REF\"\n        git fetch origin \"$GITHUB_HEAD_REF\"\n        git checkout -B \"$GITHUB_HEAD_REF\" \"origin/$GITHUB_HEAD_REF\"\n    fi\n\n    echo \"Adding benchmark file...\"\n    git add \"$OUTPUT_DIR/LATEST.md\"\n\n    if git diff --staged --quiet; then\n        echo \"No changes to commit\"\n    else\n        echo \"Committing benchmark results...\"\n        git commit -m \"chore(\\`benches\\`): update benchmark results\n\n🤖 Generated with [Foundry Benchmarks](https://github.com/${GITHUB_REPOSITORY}/actions)\n\nCo-Authored-By: github-actions <github-actions@github.com>\"\n        \n        echo \"Pushing to repository...\"\n        if [ \"$GITHUB_EVENT_NAME\" = \"workflow_dispatch\" ]; then\n            # For manual runs, we're on a new branch\n            git push origin \"$BRANCH_NAME\"\n        elif [ \"$GITHUB_EVENT_NAME\" = \"pull_request\" ]; then\n            # For PR runs, push to the PR branch\n            if [ -n \"${GITHUB_HEAD_REF:-}\" ]; then\n                echo \"Pushing to PR branch: $GITHUB_HEAD_REF\"\n                git push origin \"$GITHUB_HEAD_REF\"\n            else\n                echo \"Error: GITHUB_HEAD_REF not set for pull_request event\"\n                exit 1\n            fi\n        else\n            # This workflow should only run on workflow_dispatch or pull_request\n            echo \"Error: Unexpected event type: $GITHUB_EVENT_NAME\"\n            echo \"This workflow only supports 'workflow_dispatch' and 'pull_request' events\"\n            exit 1\n        fi\n        echo \"Successfully pushed benchmark results\"\n    fi\n}\n\n# Function to read benchmark results and output for GitHub Actions\nread_results() {\n    if [ -f \"$OUTPUT_DIR/LATEST.md\" ]; then\n        echo \"Reading benchmark results...\"\n        \n        # Output full results\n        {\n            echo 'results<<EOF'\n            cat \"$OUTPUT_DIR/LATEST.md\"\n            echo 'EOF'\n        } >> \"$GITHUB_OUTPUT\"\n        \n        # Format results for PR comment\n        echo \"Formatting results for PR comment...\"\n        FORMATTED_COMMENT=$(\"$(dirname \"$0\")/format-pr-comment.sh\" \"$OUTPUT_DIR/LATEST.md\")\n        \n        {\n            echo 'pr_comment<<EOF'\n            echo \"$FORMATTED_COMMENT\"\n            echo 'EOF'\n        } >> \"$GITHUB_OUTPUT\"\n        \n        echo \"Successfully read and formatted benchmark results\"\n    else\n        echo 'results=No benchmark results found.' >> \"$GITHUB_OUTPUT\"\n        echo 'pr_comment=No benchmark results found.' >> \"$GITHUB_OUTPUT\"\n        echo \"Warning: No benchmark results found at $OUTPUT_DIR/LATEST.md\"\n    fi\n}\n\n# Main execution\necho \"Starting benchmark results processing...\"\n\n# Create new branch for manual runs\nif [ \"$GITHUB_EVENT_NAME\" = \"workflow_dispatch\" ]; then\n    echo \"Manual workflow run detected, creating new branch...\"\n    BRANCH_NAME=\"benchmarks/results-$(date +%Y%m%d-%H%M%S)\"\n    git checkout -b \"$BRANCH_NAME\"\n    echo \"Created branch: $BRANCH_NAME\"\n    \n    # Output branch name for later use\n    echo \"branch_name=$BRANCH_NAME\" >> \"$GITHUB_OUTPUT\"\nfi\n\n# Always commit benchmark results\necho \"Committing benchmark results...\"\ncommit_results\n\n# Always read results for output\nread_results\n\necho \"Benchmark results processing complete\""
  },
  {
    "path": ".github/scripts/create-tag.js",
    "content": "module.exports = async ({ github, context }, tagName) => {\n    try {\n        await github.rest.git.createRef({\n            owner: context.repo.owner,\n            repo: context.repo.repo,\n            ref: `refs/tags/${tagName}`,\n            sha: context.sha,\n            force: true,\n        });\n    } catch (err) {\n        console.error(`Failed to create tag: ${tagName}`);\n        console.error(err);\n    }\n};\n"
  },
  {
    "path": ".github/scripts/format-pr-comment.sh",
    "content": "#!/bin/bash\nset -euo pipefail\n\n# Script to format benchmark results for PR comment\n# Usage: ./format-pr-comment.sh <benchmark_results_file>\n\nRESULTS_FILE=\"${1:-}\"\n\nif [ -z \"$RESULTS_FILE\" ] || [ ! -f \"$RESULTS_FILE\" ]; then\n    echo \"Error: Benchmark results file not provided or does not exist\"\n    exit 1\nfi\n\n# Read the file content\nCONTENT=$(cat \"$RESULTS_FILE\")\n\n# Find where \"## Forge Build\" starts and split the content\n# Extract everything before \"## Forge Build\"\nBEFORE_FORGE_BUILD=$(echo \"$CONTENT\" | awk '/^## Forge Build$/ {exit} {print}')\n\n# Extract everything from \"## Forge Build\" onwards\nFROM_FORGE_BUILD=$(echo \"$CONTENT\" | awk '/^## Forge Build$/ {found=1} found {print}')\n\n# Output the formatted comment with dropdown\ncat << EOF\n${BEFORE_FORGE_BUILD}\n\n<details>\n<summary>📈 View all benchmark results</summary>\n\n${FROM_FORGE_BUILD}\n\n</details>\nEOF"
  },
  {
    "path": ".github/scripts/format.sh",
    "content": "#!/usr/bin/env bash\nset -eo pipefail\n\n# We have to ignore at shell level because testdata/ is not a valid Foundry project,\n# so running `forge fmt` with `--root testdata` won't actually check anything\nsol_files=()\nwhile IFS= read -r -d '' file; do\n    sol_files+=(\"$file\")\ndone < <(find testdata -name '*.sol' ! -name Vm.sol ! -name console.sol -print0)\n\n# Run forge fmt on all found files\ncargo run --bin forge -- fmt \"$@\" \"${sol_files[@]}\"\n"
  },
  {
    "path": ".github/scripts/matrices.py",
    "content": "#!/usr/bin/env python3\n\nimport json\nimport os\n\n\n# A runner target\nclass Target:\n    # GHA runner\n    runner_label: str\n    # Rust target triple\n    target: str\n    # SVM Solc target\n    svm_target_platform: str\n\n    def __init__(self, runner_label: str, target: str, svm_target_platform: str):\n        self.runner_label = runner_label\n        self.target = target\n        self.svm_target_platform = svm_target_platform\n\n\n# A single test suite to run.\nclass Case:\n    # Name of the test suite.\n    name: str\n    # Nextest filter expression.\n    filter: str\n    # Number of partitions to split the test suite into.\n    n_partitions: int\n    # Whether to run on non-Linux platforms for PRs. All platforms and tests are run on pushes.\n    pr_cross_platform: bool\n\n    def __init__(\n        self, name: str, filter: str, n_partitions: int, pr_cross_platform: bool\n    ):\n        self.name = name\n        self.filter = filter\n        self.n_partitions = n_partitions\n        self.pr_cross_platform = pr_cross_platform\n\n\n# GHA matrix entry\nclass Expanded:\n    name: str\n    runner_label: str\n    target: str\n    svm_target_platform: str\n    flags: str\n    partition: int\n\n    def __init__(\n        self,\n        name: str,\n        runner_label: str,\n        target: str,\n        svm_target_platform: str,\n        flags: str,\n        partition: int,\n    ):\n        self.name = name\n        self.runner_label = runner_label\n        self.target = target\n        self.svm_target_platform = svm_target_platform\n        self.flags = flags\n        self.partition = partition\n\n\nprofile = os.environ.get(\"PROFILE\")\nis_pr = os.environ.get(\"EVENT_NAME\") == \"pull_request\"\nt_linux_x86 = Target(\n    \"depot-ubuntu-latest-16\", \"x86_64-unknown-linux-gnu\", \"linux-amd64\"\n)\nt_linux_arm = Target(\n    \"depot-ubuntu-latest-arm-16\", \"aarch64-unknown-linux-gnu\", \"linux-aarch64\"\n)\nt_macos = Target(\"depot-macos-latest\", \"aarch64-apple-darwin\", \"macosx-aarch64\")\nt_windows = Target(\"depot-windows-latest-16\", \"x86_64-pc-windows-msvc\", \"windows-amd64\")\ntargets = [t_linux_x86] if is_pr else [t_linux_x86, t_linux_arm, t_macos, t_windows]\n\nconfig = [\n    Case(\n        name=\"all\",\n        filter=\"!test(/\\\\bext_integration/)\",\n        n_partitions=1,\n        pr_cross_platform=True,\n    ),\n    Case(\n        name=\"external\",\n        filter=\"package(=forge) & test(/\\\\bext_integration/)\",\n        n_partitions=1,\n        pr_cross_platform=False,\n    ),\n]\n\n\ndef main():\n    expanded = []\n    for target in targets:\n        for case in config:\n            if is_pr and (not case.pr_cross_platform and target != t_linux_x86):\n                continue\n\n            for partition in range(1, case.n_partitions + 1):\n                os_str = \"\"\n                if len(targets) > 1:\n                    os_str = f\" ({target.target})\"\n\n                name = case.name\n                flags = f\"-E '{case.filter}'\"\n                if case.n_partitions > 1:\n                    s = f\"{partition}/{case.n_partitions}\"\n                    name += f\" ({s})\"\n                    flags += f\" --partition count:{s}\"\n\n                if profile == \"isolate\":\n                    flags += \" --features=isolate-by-default\"\n                name += os_str\n\n                flags += \" --no-fail-fast\"\n\n                obj = Expanded(\n                    name=name,\n                    runner_label=target.runner_label,\n                    target=target.target,\n                    svm_target_platform=target.svm_target_platform,\n                    flags=flags,\n                    partition=partition,\n                )\n                expanded.append(vars(obj))\n\n    print_json({\"include\": expanded})\n\n\ndef print_json(obj):\n    print(json.dumps(obj), end=\"\", flush=True)\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": ".github/scripts/move-tag.js",
    "content": "module.exports = async ({ github, context }, tagName) => {\n    try {\n        await github.rest.git.updateRef({\n            owner: context.repo.owner,\n            repo: context.repo.repo,\n            ref: `tags/${tagName}`,\n            sha: context.sha,\n            force: true,\n        });\n    } catch (err) {\n        console.error(`Failed to move nightly tag.`);\n        console.error(`This should only happen the first time.`);\n        console.error(err);\n    }\n};\n"
  },
  {
    "path": ".github/scripts/prune-prereleases.js",
    "content": "// In case node 21 is not used.\nfunction groupBy(array, keyOrIterator) {\n    var iterator;\n\n    // use the function passed in, or create one\n    if(typeof keyOrIterator !== 'function') {\n        const key = String(keyOrIterator);\n        iterator = function (item) { return item[key]; };\n    } else {\n        iterator = keyOrIterator;\n    }\n\n    return array.reduce(function (memo, item) {\n        const key = iterator(item);\n        memo[key] = memo[key] || [];\n        memo[key].push(item);\n        return memo;\n    }, {});\n}\n\nmodule.exports = async ({ github, context }) => {\n    console.log(\"Pruning old prereleases\");\n\n    // doc: https://docs.github.com/en/rest/releases/releases\n    const { data: releases } = await github.rest.repos.listReleases({\n        owner: context.repo.owner,\n        repo: context.repo.repo,\n    });\n\n    let nightlies = releases.filter(\n        release =>\n            // Only consider releases tagged `nightly-${SHA}` for deletion\n            release.tag_name.includes(\"nightly\") &&\n            release.tag_name !== \"nightly\"\n    );\n\n    // Pruning rules:\n    //   1. only keep the earliest (by created_at) release of the month\n    //   2. to keep the newest 30 nightlies (to make sure nightlies are kept until the next monthly release)\n    // Notes:\n    //   - This addresses https://github.com/foundry-rs/foundry/issues/6732\n    //   - Name of the release may deviate from created_at due to the usage of different timezones.\n\n    // Group releases by months.\n    // Per doc:\n    // > The latest release is the most recent non-prerelease, non-draft release, sorted by the created_at attribute.\n    const groups = groupBy(nightlies, i => i.created_at.slice(0, 7));\n    const nightliesToPrune = Object.values(groups)\n        .reduce((acc, cur) => acc.concat(cur.slice(0, -1)), []) // rule 1\n        .slice(30); // rule 2\n\n    for (const nightly of nightliesToPrune) {\n        console.log(`Deleting nightly: ${nightly.tag_name}`);\n        await github.rest.repos.deleteRelease({\n            owner: context.repo.owner,\n            repo: context.repo.repo,\n            release_id: nightly.id,\n        });\n        console.log(`Deleting nightly tag: ${nightly.tag_name}`);\n        await github.rest.git.deleteRef({\n            owner: context.repo.owner,\n            repo: context.repo.repo,\n            ref: `tags/${nightly.tag_name}`,\n        });\n    }\n\n    console.log(\"Done.\");\n};\n"
  },
  {
    "path": ".github/scripts/setup-foundryup.sh",
    "content": "#!/bin/bash\nset -euo pipefail\n\n# Script to setup foundryup in CI environment\n# This ensures foundryup is available in PATH for the benchmark binary\n\necho \"Setting up foundryup...\"\n\n# Check if foundryup script exists in the repo\nif [ ! -f \"foundryup/foundryup\" ]; then\n    echo \"Error: foundryup/foundryup script not found in repository\"\n    exit 1\nfi\n\n# Copy foundryup to a location in PATH\necho \"Copying foundryup to /usr/local/bin...\"\nsudo cp foundryup/foundryup /usr/local/bin/foundryup\nsudo chmod +x /usr/local/bin/foundryup\n\n# Verify foundryup is accessible\nif ! command -v foundryup &> /dev/null; then\n    echo \"Error: foundryup not found in PATH after installation\"\n    exit 1\nfi\n\necho \"foundryup is now available at: $(which foundryup)\"\n\n# Create foundry directories\necho \"Creating foundry directories...\"\n\n# Use FOUNDRY_DIR if set, otherwise default to $HOME/.foundry\nFOUNDRY_DIR=\"${FOUNDRY_DIR:-$HOME/.foundry}\"\necho \"Using FOUNDRY_DIR: $FOUNDRY_DIR\"\n\n# Create all necessary directories\nmkdir -p \"$FOUNDRY_DIR/bin\"\nmkdir -p \"$FOUNDRY_DIR/versions\"\nmkdir -p \"$FOUNDRY_DIR/share/man/man1\"\n\n# Export PATH for current session\nexport PATH=\"$FOUNDRY_DIR/bin:$PATH\"\n\n# Run foundryup to install default version\necho \"Installing default foundry version...\"\nfoundryup\n\n# Verify installation\nif command -v forge &> /dev/null; then\n    echo \"Forge installed successfully: $(forge --version)\"\nelse\n    echo \"Warning: forge not found in PATH after installation\"\nfi\n\necho \"Foundry setup complete!\""
  },
  {
    "path": ".github/scripts/shellcheck.sh",
    "content": "#!/usr/bin/env bash\n\n# runs shellcheck and prints GitHub Actions annotations for each warning and error\n# https://github.com/koalaman/shellcheck\n\nIGNORE_DIRS=(\n  \"./.git/*\"\n  \"./target/*\"\n)\n\nignore_args=()\nfor dir in \"${IGNORE_DIRS[@]}\"; do\n  ignore_args+=(-not -path \"$dir\")\ndone\n\nfind . -name \"*.sh\" \"${ignore_args[@]}\" -exec shellcheck -f gcc {} + | \\\n  while IFS=: read -r file line col severity msg; do\n    level=\"warning\"\n    [[ \"$severity\" == *error* ]] && level=\"error\"\n    file=\"${file#./}\"\n    echo \"::${level} file=${file},line=${line},col=${col}::${file}:${line}:${col}:${msg}\"\n  done\n\nexit \"${PIPESTATUS[0]}\"\n"
  },
  {
    "path": ".github/workflows/benchmarks.yml",
    "content": "name: Foundry Benchmarks\n\npermissions: {}\n\non:\n  workflow_dispatch:\n    inputs:\n      pr_number:\n        description: \"PR number to comment on (optional)\"\n        required: false\n        type: string\n      versions:\n        description: \"Comma-separated list of Foundry versions to benchmark (e.g., stable,nightly,v1.0.0)\"\n        required: false\n        type: string\n        default: \"stable,nightly\"\n      repos:\n        description: \"Comma-separated list of repos to benchmark (e.g., ithacaxyz/account:main,Vectorized/solady)\"\n        required: false\n        type: string\n        default: \"ithacaxyz/account:v0.3.2,Vectorized/solady:v0.1.22\"\n\nenv:\n  ITHACAXYZ_ACCOUNT: \"ithacaxyz/account:v0.3.2\"\n  VECTORIZED_SOLADY: \"Vectorized/solady:v0.1.22\"\n  DEFAULT_REPOS: \"ithacaxyz/account:v0.3.2,Vectorized/solady:v0.1.22\"\n  RUSTC_WRAPPER: \"sccache\"\n\njobs:\n  run-benchmarks:\n    name: Run All Benchmarks\n    runs-on: depot-ubuntu-24.04-32\n    permissions:\n      contents: write\n    steps:\n      - name: Checkout repository\n        uses: actions/checkout@v6\n        with:\n          persist-credentials: false\n\n      - name: Install build dependencies\n        run: |\n          sudo apt-get update\n          sudo apt-get install -y build-essential pkg-config\n\n      - name: Setup Rust toolchain\n        uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9 # master\n        with:\n          toolchain: stable\n\n      - uses: rui314/setup-mold@725a8794d15fc7563f59595bd9556495c0564878 # v1\n\n      - uses: mozilla-actions/sccache-action@7d986dd989559c6ecdb630a3fd2557667be217ad # v0.0.9\n\n      - name: Setup Foundry\n        env:\n          FOUNDRY_DIR: ${{ github.workspace }}/.foundry\n          GITHUB_WORKSPACE: ${{ github.workspace }}\n        run: |\n          ./.github/scripts/setup-foundryup.sh\n          printf '%s\\n' \"$GITHUB_WORKSPACE/.foundry/bin\" >> \"$GITHUB_PATH\"\n\n      - name: Build benchmark binary\n        run: cargo build --release --bin foundry-bench\n\n      - name: Setup Node.js\n        uses: actions/setup-node@v6\n        with:\n          node-version: \"24\"\n\n      - name: Install hyperfine\n        run: |\n          curl -L https://github.com/sharkdp/hyperfine/releases/download/v1.19.0/hyperfine-v1.19.0-x86_64-unknown-linux-gnu.tar.gz | tar xz\n          sudo mv hyperfine-v1.19.0-x86_64-unknown-linux-gnu/hyperfine /usr/local/bin/\n          rm -rf hyperfine-v1.19.0-x86_64-unknown-linux-gnu\n\n      - name: Run forge test benchmarks\n        env:\n          FOUNDRY_DIR: ${{ github.workspace }}/.foundry\n        run: |\n          VERSIONS=\"${{ github.event.inputs.versions || 'stable,nightly' }}\"\n          REPOS=\"${{ github.event.inputs.repos || env.DEFAULT_REPOS }}\"\n\n          ./target/release/foundry-bench --output-dir ./benches --force-install \\\n            --versions $VERSIONS \\\n            --repos $REPOS \\\n            --benchmarks forge_test,forge_fuzz_test \\\n            --output-file forge_test_bench.md\n\n      - name: Run forge isolate test benchmarks\n        env:\n          FOUNDRY_DIR: ${{ github.workspace }}/.foundry\n        run: |\n          VERSIONS=\"${{ github.event.inputs.versions || 'stable,nightly' }}\"\n          # Isolate tests default to Vectorized/solady but can be overridden\n          REPOS=\"${{ github.event.inputs.repos || env.VECTORIZED_SOLADY }}\"\n\n          ./target/release/foundry-bench --output-dir ./benches --force-install \\\n            --versions $VERSIONS \\\n            --repos $REPOS \\\n            --benchmarks forge_isolate_test \\\n            --output-file forge_isolate_test_bench.md\n\n      - name: Run forge build benchmarks\n        env:\n          FOUNDRY_DIR: ${{ github.workspace }}/.foundry\n        run: |\n          VERSIONS=\"${{ github.event.inputs.versions || 'stable,nightly' }}\"\n          REPOS=\"${{ github.event.inputs.repos || env.DEFAULT_REPOS }}\"\n\n          ./target/release/foundry-bench --output-dir ./benches --force-install \\\n            --versions $VERSIONS \\\n            --repos $REPOS \\\n            --benchmarks forge_build_no_cache,forge_build_with_cache \\\n            --output-file forge_build_bench.md\n\n      - name: Run forge coverage benchmarks\n        env:\n          FOUNDRY_DIR: ${{ github.workspace }}/.foundry\n        run: |\n          VERSIONS=\"${{ github.event.inputs.versions || 'stable,nightly' }}\"\n          # Coverage only runs on ithacaxyz/account:v0.3.2\n\n          ./target/release/foundry-bench --output-dir ./benches --force-install \\\n            --versions $VERSIONS \\\n            --repos ${{ env.ITHACAXYZ_ACCOUNT }} \\\n            --benchmarks forge_coverage \\\n            --output-file forge_coverage_bench.md\n\n      - name: Combine benchmark results\n        run: ./.github/scripts/combine-benchmarks.sh benches\n\n      - name: Commit and read benchmark results\n        id: benchmark_results\n        env:\n          GITHUB_HEAD_REF: ${{ github.head_ref }}\n        run: ./.github/scripts/commit-and-read-benchmarks.sh benches \"${{ github.event_name }}\" \"${{ github.repository }}\"\n\n      - name: Upload benchmark results as artifacts\n        uses: actions/upload-artifact@v7\n        with:\n          name: benchmark-results\n          path: |\n            benches/forge_test_bench.md\n            benches/forge_isolate_test_bench.md\n            benches/forge_build_bench.md\n            benches/forge_coverage_bench.md\n            benches/LATEST.md\n\n    outputs:\n      branch_name: ${{ steps.benchmark_results.outputs.branch_name }}\n      pr_comment: ${{ steps.benchmark_results.outputs.pr_comment }}\n\n  publish-results:\n    name: Publish Results\n    needs: run-benchmarks\n    runs-on: ubuntu-latest\n    permissions:\n      contents: write\n      pull-requests: write\n    steps:\n      - name: Checkout repository\n        uses: actions/checkout@v6\n        with:\n          persist-credentials: false\n\n      - name: Download benchmark results\n        uses: actions/download-artifact@v8\n        with:\n          name: benchmark-results\n          path: benches/\n\n      - name: Push branch for manual runs\n        if: github.event_name == 'workflow_dispatch'\n        run: |\n          git push origin \"${{ needs.run-benchmarks.outputs.branch_name }}\"\n          echo \"Pushed branch: ${{ needs.run-benchmarks.outputs.branch_name }}\"\n\n      - name: Create PR for manual runs\n        if: github.event_name == 'workflow_dispatch'\n        uses: actions/github-script@v8\n        with:\n          script: |\n            const branchName = '${{ needs.run-benchmarks.outputs.branch_name }}';\n            const prComment = `${{ needs.run-benchmarks.outputs.pr_comment }}`;\n\n            // Create the pull request\n            const { data: pr } = await github.rest.pulls.create({\n              owner: context.repo.owner,\n              repo: context.repo.repo,\n              title: 'chore(bench): update benchmark results',\n              head: branchName,\n              base: 'master',\n              body: `## Benchmark Results Update\n\n            This PR contains the latest benchmark results from a manual workflow run.\n\n            ${prComment}\n\n            ---\n\n            🤖 This PR was automatically generated by the [Foundry Benchmarks workflow](https://github.com/${{ github.repository }}/actions).`\n            });\n\n            console.log(`Created PR #${pr.number}: ${pr.html_url}`);\n\n      - name: Comment on PR\n        if: github.event.inputs.pr_number != '' || github.event_name == 'pull_request'\n        uses: actions/github-script@v8\n        with:\n          script: |\n            const prNumber = ${{ github.event.inputs.pr_number || github.event.pull_request.number }};\n            const prComment = `${{ needs.run-benchmarks.outputs.pr_comment }}`;\n\n            const comment = `${prComment}\n\n            ---\n\n            🤖 This comment was automatically generated by the [Foundry Benchmarks workflow](https://github.com/${{ github.repository }}/actions).\n\n            To run benchmarks manually: Go to [Actions](https://github.com/${{ github.repository }}/actions/workflows/benchmarks.yml) → \"Run workflow\"`;\n\n            github.rest.issues.createComment({\n              issue_number: prNumber,\n              owner: context.repo.owner,\n              repo: context.repo.repo,\n              body: comment\n            });\n"
  },
  {
    "path": ".github/workflows/bump-forge-std.yml",
    "content": "# Daily CI job to update forge-std version used for tests if new release has been published\n\nname: bump-forge-std\n\npermissions: {}\n\non:\n  schedule:\n    - cron: \"0 0 * * *\" # Run daily at midnight UTC\n  workflow_dispatch: # Needed so we can run it manually\n\njobs:\n  update-tag:\n    name: update forge-std tag\n    runs-on: ubuntu-latest\n    permissions:\n      contents: write\n      pull-requests: write\n    steps:\n      - uses: actions/checkout@v6\n        with:\n          persist-credentials: false\n      - name: Fetch and update forge-std tag\n        run: curl 'https://api.github.com/repos/foundry-rs/forge-std/tags' | jq '.[0].commit.sha' -jr > testdata/forge-std-rev\n      - name: Create pull request\n        uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 # v7\n        with:\n          commit-message: \"chore: bump forge-std version used for tests\"\n          title: \"chore(tests): bump forge-std version\"\n          body: |\n            New release of forge-std has been published, bump forge-std version used in tests. Likely some fixtures need to be updated.\n          branch: chore/bump-forge-std\n"
  },
  {
    "path": ".github/workflows/ci.yml",
    "content": "name: CI\n\npermissions: {}\n\non:\n  push:\n    branches: [master]\n  pull_request:\n\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}\n  cancel-in-progress: true\n\nenv:\n  CARGO_TERM_COLOR: always\n  RUST_BACKTRACE: full\n  RUSTC_WRAPPER: \"sccache\"\n\njobs:\n  test:\n    uses: ./.github/workflows/test.yml\n    permissions:\n      contents: read\n    with:\n      profile: default\n    secrets: inherit\n\n  docs:\n    uses: ./.github/workflows/docs.yml\n    permissions:\n      contents: read\n      pages: write\n      id-token: write\n    secrets: inherit\n\n  doctest:\n    runs-on: depot-ubuntu-latest\n    timeout-minutes: 30\n    permissions:\n      contents: read\n    steps:\n      - uses: actions/checkout@v6\n        with:\n          persist-credentials: false\n      - uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9 # master\n        with:\n          toolchain: stable\n      - uses: rui314/setup-mold@725a8794d15fc7563f59595bd9556495c0564878 # v1\n      - uses: mozilla-actions/sccache-action@7d986dd989559c6ecdb630a3fd2557667be217ad # v0.0.9\n      - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2\n      - run: cargo test --workspace --doc\n\n  typos:\n    runs-on: depot-ubuntu-latest\n    timeout-minutes: 30\n    permissions:\n      contents: read\n    steps:\n      - uses: actions/checkout@v6\n        with:\n          persist-credentials: false\n      - uses: crate-ci/typos@631208b7aac2daa8b707f55e7331f9112b0e062d # v1\n\n  shellcheck:\n    runs-on: depot-ubuntu-latest\n    timeout-minutes: 5\n    permissions:\n      contents: read\n    steps:\n      - uses: actions/checkout@v6\n        with:\n          persist-credentials: false\n      - name: Shellcheck\n        shell: bash\n        run: ./.github/scripts/shellcheck.sh\n\n  clippy:\n    runs-on: depot-ubuntu-latest\n    timeout-minutes: 30\n    permissions:\n      contents: read\n    steps:\n      - uses: actions/checkout@v6\n        with:\n          persist-credentials: false\n      - uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9 # master\n        with:\n          toolchain: nightly\n          components: clippy\n      - uses: rui314/setup-mold@725a8794d15fc7563f59595bd9556495c0564878 # v1\n      - uses: mozilla-actions/sccache-action@7d986dd989559c6ecdb630a3fd2557667be217ad # v0.0.9\n      - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2\n      - run: cargo clippy --workspace --all-targets --all-features\n        env:\n          RUSTFLAGS: -Dwarnings\n\n  rustfmt:\n    runs-on: depot-ubuntu-latest\n    timeout-minutes: 30\n    permissions:\n      contents: read\n    steps:\n      - uses: actions/checkout@v6\n        with:\n          persist-credentials: false\n      - uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9 # master\n        with:\n          toolchain: nightly\n          components: rustfmt\n      - run: cargo fmt --all --check\n\n  forge-fmt:\n    runs-on: depot-ubuntu-latest\n    timeout-minutes: 30\n    permissions:\n      contents: read\n    steps:\n      - uses: actions/checkout@v6\n        with:\n          persist-credentials: false\n      - uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9 # master\n        with:\n          toolchain: stable\n      - uses: rui314/setup-mold@725a8794d15fc7563f59595bd9556495c0564878 # v1\n      - uses: mozilla-actions/sccache-action@7d986dd989559c6ecdb630a3fd2557667be217ad # v0.0.9\n      - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2\n      - name: forge fmt\n        shell: bash\n        run: ./.github/scripts/format.sh --check\n\n  crate-checks:\n    runs-on: depot-ubuntu-latest\n    timeout-minutes: 30\n    permissions:\n      contents: read\n    steps:\n      - uses: actions/checkout@v6\n        with:\n          persist-credentials: false\n      - uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9 # master\n        with:\n          toolchain: stable\n      - uses: rui314/setup-mold@725a8794d15fc7563f59595bd9556495c0564878 # v1\n      - uses: taiki-e/install-action@94a7388bec5d4c8dd93e3ebf09e0ff448f3f6f4d # v2\n        with:\n          tool: cargo-hack\n      - uses: mozilla-actions/sccache-action@7d986dd989559c6ecdb630a3fd2557667be217ad # v0.0.9\n      - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2\n      - run: cargo hack check\n\n  deny:\n    uses: tempoxyz/ci/.github/workflows/deny.yml@268b3ce142717ff86c58fbbcc3abc3f109f0fb8d # main\n    permissions:\n      contents: read\n\n  codeql:\n    name: analyze (${{ matrix.language }})\n    runs-on: ubuntu-latest\n    permissions:\n      security-events: write\n      actions: read\n      contents: read\n    strategy:\n      fail-fast: false\n      matrix:\n        include:\n          - language: actions\n            build-mode: none\n    steps:\n      - name: Checkout repository\n        uses: actions/checkout@v6\n        with:\n          persist-credentials: false\n      - name: Initialize CodeQL\n        uses: github/codeql-action/init@v4\n        with:\n          languages: ${{ matrix.language }}\n          build-mode: ${{ matrix.build-mode }}\n      - name: Perform CodeQL Analysis\n        uses: github/codeql-action/analyze@v4\n        with:\n          category: \"/language:${{matrix.language}}\"\n\n  ci-success:\n    runs-on: ubuntu-latest\n    if: always()\n    permissions: {}\n    needs:\n      - test\n      - docs\n      - doctest\n      - typos\n      - clippy\n      - rustfmt\n      - forge-fmt\n      - crate-checks\n      - deny\n      - codeql\n    timeout-minutes: 30\n    steps:\n      - name: Decide whether the needed jobs succeeded or failed\n        uses: re-actors/alls-green@05ac9388f0aebcb5727afa17fcccfecd6f8ec5fe # release/v1\n        with:\n          jobs: ${{ toJSON(needs) }}\n"
  },
  {
    "path": ".github/workflows/dependencies.yml",
    "content": "# Runs `cargo update` periodically.\n\nname: dependencies\n\npermissions: {}\n\non:\n  schedule:\n    - cron: \"0 0 * * SUN\" # Run weekly on Sundays at midnight UTC\n  workflow_dispatch: # Needed so we can run it manually\n\njobs:\n  update:\n    uses: tempoxyz/ci/.github/workflows/cargo-update-pr.yml@268b3ce142717ff86c58fbbcc3abc3f109f0fb8d # main\n    permissions:\n      contents: write\n      pull-requests: write\n    secrets:\n      token: ${{ secrets.GITHUB_TOKEN }}\n"
  },
  {
    "path": ".github/workflows/docker-publish.yml",
    "content": "name: docker\n\npermissions: {}\n\non:\n  workflow_dispatch:\n    inputs:\n      tag_name:\n        default: nightly\n        description: The tag we're building for\n        type: string\n  workflow_call:\n    inputs:\n      tag_name:\n        required: true\n        type: string\n\nconcurrency:\n  group: docker-${{ github.head_ref }}\n  cancel-in-progress: ${{ github.event_name == 'pull_request' }}\n\nenv:\n  REGISTRY: ghcr.io\n  IMAGE_NAME: ${{ github.repository }}\n\n  # Keep in sync with `release.yml`.\n  RUST_PROFILE: dist\n  RUST_FEATURES: aws-kms,gcp-kms,turnkey,cli,asm-keccak,js-tracer\n\njobs:\n  build:\n    name: build and push\n    runs-on: depot-ubuntu-latest\n    permissions:\n      contents: read\n      id-token: write\n      packages: write\n    timeout-minutes: 60\n    steps:\n      - uses: actions/checkout@v6\n        with:\n          persist-credentials: false\n\n      # Login against a Docker registry except on PR\n      # https://github.com/docker/login-action\n      - name: Login into registry ${{ env.REGISTRY }}\n        uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0\n        with:\n          registry: ${{ env.REGISTRY }}\n          username: ${{ github.actor }}\n          password: ${{ secrets.GITHUB_TOKEN }}\n\n      # Extract metadata (tags, labels) for Docker\n      # https://github.com/docker/metadata-action\n      - name: Extract Docker metadata\n        id: meta\n        uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf # v6.0.0\n        with:\n          images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}\n\n      # Creates an additional 'latest' or 'nightly' tag\n      # If the job is triggered via cron schedule, tag nightly and nightly-{SHA}\n      # If the job is triggered via workflow dispatch and on a master branch, tag branch and latest\n      # Otherwise, just tag as the branch name\n      - name: Finalize Docker Metadata\n        id: docker_tagging\n        run: |\n          TAG=\"${{ inputs.tag_name }}\"\n          REGISTRY=\"${{ env.REGISTRY }}\"\n          IMAGE=\"${{ env.IMAGE_NAME }}\"\n\n          if [[ \"${{ github.event_name }}\" == \"schedule\" ]]; then\n            printf \"cron trigger, assigning nightly tag\\n\"\n            printf \"docker_tags=%s/%s:nightly,%s/%s:nightly-%s\\n\" \"$REGISTRY\" \"$IMAGE\" \"$REGISTRY\" \"$IMAGE\" \"$GITHUB_SHA\" >> \"$GITHUB_OUTPUT\"\n          elif [[ \"${GITHUB_REF##*/}\" == \"main\" ]] || [[ \"${GITHUB_REF##*/}\" == \"master\" ]]; then\n            printf \"manual trigger from master/main branch, assigning latest tag\\n\"\n            printf \"docker_tags=%s/%s:%s,%s/%s:latest\\n\" \"$REGISTRY\" \"$IMAGE\" \"${GITHUB_REF##*/}\" \"$REGISTRY\" \"$IMAGE\" >> \"$GITHUB_OUTPUT\"\n          elif [[ \"$TAG\" =~ ^v([0-9]+)\\.([0-9]+)\\.([0-9]+)$ ]]; then\n            MAJOR=\"v${BASH_REMATCH[1]}\"\n            MINOR=\"v${BASH_REMATCH[1]}.${BASH_REMATCH[2]}\"\n            printf \"version tag release, assigning %s, %s, and %s tags\\n\" \"$TAG\" \"$MINOR\" \"$MAJOR\"\n            printf \"docker_tags=%s/%s:%s,%s/%s:%s,%s/%s:%s\\n\" \"$REGISTRY\" \"$IMAGE\" \"$TAG\" \"$REGISTRY\" \"$IMAGE\" \"$MINOR\" \"$REGISTRY\" \"$IMAGE\" \"$MAJOR\" >> \"$GITHUB_OUTPUT\"\n          else\n            printf \"Neither scheduled nor manual release from main branch. Just tagging as branch name\\n\"\n            printf \"docker_tags=%s/%s:%s\\n\" \"$REGISTRY\" \"$IMAGE\" \"${GITHUB_REF##*/}\" >> \"$GITHUB_OUTPUT\"\n          fi\n\n      # Log docker metadata to explicitly know what is being pushed\n      - name: Inspect Docker Metadata\n        run: |\n          printf \"TAGS -> %s\\n\" \"${{ steps.docker_tagging.outputs.docker_tags }}\"\n          printf \"LABELS -> %s\\n\" \"${{ steps.meta.outputs.labels }}\"\n\n      - name: Set up Depot CLI\n        uses: depot/setup-action@15c09a5f77a0840ad4bce955686522a257853461 # v1\n\n      - name: Build and push Foundry image\n        uses: depot/build-push-action@5f3b3c2e5a00f0093de47f657aeaefcedff27d18 # v1\n        with:\n          build-args: |\n            RUST_PROFILE=${{ env.RUST_PROFILE }}\n            RUST_FEATURES=${{ env.RUST_FEATURES }}\n            TAG_NAME=${{ inputs.tag_name }}\n            VERGEN_GIT_SHA=${{ github.sha }}\n          project: 8gkbxxjrpw\n          context: .\n          tags: ${{ steps.docker_tagging.outputs.docker_tags }}\n          labels: ${{ steps.meta.outputs.labels }}\n          platforms: linux/amd64,linux/arm64\n          push: true\n"
  },
  {
    "path": ".github/workflows/docs.yml",
    "content": "name: docs\n\npermissions: {}\n\non:\n  push:\n    branches:\n      - master\n  workflow_call:\n\nconcurrency:\n  group: docs-${{ github.workflow }}-${{ github.head_ref || github.run_id }}\n  cancel-in-progress: true\n\nenv:\n  CARGO_TERM_COLOR: always\n  RUST_BACKTRACE: full\n  RUSTC_WRAPPER: \"sccache\"\n\njobs:\n  docs:\n    runs-on: depot-ubuntu-latest\n    timeout-minutes: 30\n    permissions:\n      contents: read\n    steps:\n      - uses: actions/checkout@v6\n        with:\n          persist-credentials: false\n      - uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9 # master\n        with:\n          toolchain: nightly\n      - uses: rui314/setup-mold@725a8794d15fc7563f59595bd9556495c0564878 # v1\n      - uses: mozilla-actions/sccache-action@7d986dd989559c6ecdb630a3fd2557667be217ad # v0.0.9\n      - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2\n      - name: Build documentation\n        run: cargo doc --workspace --all-features --no-deps --document-private-items\n        env:\n          RUSTDOCFLAGS: --cfg docsrs -D warnings --show-type-layout --generate-link-to-definition --enable-index-page -Zunstable-options\n      - name: Setup Pages\n        if: github.ref_name == 'master' && github.event_name == 'push'\n        uses: actions/configure-pages@v5\n      - name: Upload artifact\n        if: github.ref_name == 'master' && github.event_name == 'push'\n        uses: actions/upload-pages-artifact@v4\n        with:\n          path: ./target/doc\n\n  deploy-docs:\n    if: github.ref_name == 'master' && github.event_name == 'push'\n    needs: [docs]\n    runs-on: depot-ubuntu-latest\n    timeout-minutes: 30\n    permissions:\n      pages: write\n      id-token: write\n    environment:\n      name: github-pages\n      url: ${{ steps.deployment.outputs.page_url }}\n    steps:\n      - name: Deploy to GitHub Pages\n        id: deployment\n        uses: actions/deploy-pages@v4\n"
  },
  {
    "path": ".github/workflows/nix.yml",
    "content": "name: nix\n\npermissions: {}\n\non:\n  schedule:\n    - cron: \"0 0 * * SUN\" # Run weekly on Sundays at midnight UTC\n  workflow_dispatch: # Needed so we can run it manually\n\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.ref }}\n  cancel-in-progress: true\n\njobs:\n  # Opens a PR with an updated flake.lock file\n  update:\n    runs-on: ubuntu-latest\n    permissions:\n      contents: write\n      pull-requests: write\n    steps:\n      - uses: DeterminateSystems/determinate-nix-action@131015bad844610e5e6300f8a143bf625d3e74f4 # v3\n      - uses: actions/checkout@v6\n        with:\n          persist-credentials: false\n      - uses: DeterminateSystems/update-flake-lock@e80a657d7603606be0c69b117cfdc240f1e6af88 # main\n        with:\n          pr-title: \"Update flake.lock\"\n          pr-labels: |\n            L-ignore\n            A-dependencies\n\n  build:\n    strategy:\n      matrix:\n        runs-on: [ubuntu-latest, macos-latest]\n    runs-on: ${{ matrix.runs-on }}\n    permissions:\n      contents: read\n    steps:\n      - uses: DeterminateSystems/determinate-nix-action@131015bad844610e5e6300f8a143bf625d3e74f4 # v3\n      - uses: actions/checkout@v6\n        with:\n          persist-credentials: false\n\n      - name: Update flake.lock\n        run: nix flake update\n\n      - name: Activate nix env\n        run: nix develop -c echo Ok\n\n      - name: Check that we can compile all crates\n        run: nix develop -c cargo check --all-targets\n"
  },
  {
    "path": ".github/workflows/npm.yml",
    "content": "name: npm\n\npermissions: {}\n\non:\n  workflow_dispatch:\n    inputs:\n      run_id:\n        type: string\n        required: false\n        description: The run id of the release to publish\n  workflow_run:\n    types: [completed]\n    workflows: [release]\n\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.ref }}\n  cancel-in-progress: true\n\ndefaults:\n  run:\n    shell: bash\n\nenv:\n  NPM_CONFIG_PROVENANCE: true\n  NPM_REGISTRY_URL: \"https://registry.npmjs.org\"\n\njobs:\n  publish-arch:\n    permissions:\n      contents: read\n      actions: read\n      id-token: write\n    name: ${{ matrix.tool }}-${{ matrix.os }}-${{ matrix.arch }}\n    runs-on: ubuntu-latest\n    strategy:\n      max-parallel: 3\n      fail-fast: false\n      matrix:\n        include:\n          - tool: forge\n            os: linux\n            arch: amd64\n          - tool: forge\n            os: linux\n            arch: arm64\n          - tool: forge\n            os: darwin\n            arch: amd64\n          - tool: forge\n            os: darwin\n            arch: arm64\n          - tool: forge\n            os: win32\n            arch: amd64\n          - tool: cast\n            os: linux\n            arch: amd64\n          - tool: cast\n            os: linux\n            arch: arm64\n          - tool: cast\n            os: darwin\n            arch: amd64\n          - tool: cast\n            os: darwin\n            arch: arm64\n          - tool: cast\n            os: win32\n            arch: amd64\n          - tool: anvil\n            os: linux\n            arch: amd64\n          - tool: anvil\n            os: linux\n            arch: arm64\n          - tool: anvil\n            os: darwin\n            arch: amd64\n          - tool: anvil\n            os: darwin\n            arch: arm64\n          - tool: anvil\n            os: win32\n            arch: amd64\n          - tool: chisel\n            os: linux\n            arch: amd64\n          - tool: chisel\n            os: linux\n            arch: arm64\n          - tool: chisel\n            os: darwin\n            arch: amd64\n          - tool: chisel\n            os: darwin\n            arch: arm64\n          - tool: chisel\n            os: win32\n            arch: amd64\n    # Run automatically after a successful 'release' workflow, or manually if a run_id is provided\n    if: >-\n      ${{\n        (github.event_name == 'workflow_run' && github.event.workflow_run.conclusion == 'success') ||\n        (github.event_name == 'workflow_dispatch' && inputs.run_id != '')\n      }}\n    outputs:\n      RELEASE_VERSION: ${{ steps.release-version.outputs.RELEASE_VERSION }}\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v6\n        with:\n          persist-credentials: false\n\n      - name: Set Isolated Artifact Directory\n        id: paths\n        run: |\n          set -euo pipefail\n          printf 'artifact_dir=%s\\n' \"$RUNNER_TEMP/foundry_artifacts\" >> \"$GITHUB_OUTPUT\"\n\n      - name: Prepare Isolated Artifact Directory\n        env:\n          ARTIFACT_DIR: ${{ steps.paths.outputs.artifact_dir }}\n        run: |\n          mkdir -p \"$ARTIFACT_DIR\"\n          ls -la \"$ARTIFACT_DIR\" || true\n\n      - name: Download Release Assets\n        uses: actions/download-artifact@v8\n        with:\n          merge-multiple: true\n          # Download all foundry artifacts from the triggering release run\n          pattern: \"foundry_*\"\n          # Extract artifacts into an isolated temp directory, not the workspace\n          path: ${{ steps.paths.outputs.artifact_dir }}\n          github-token: ${{ secrets.GITHUB_TOKEN }}\n          run-id: ${{ github.event.workflow_run.id || inputs.run_id }}\n\n      - name: Setup Bun\n        uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2\n        with:\n          bun-version: latest\n\n      - name: Setup Node (for npm publish auth)\n        uses: actions/setup-node@v6\n        with:\n          node-version: \"24\"\n          registry-url: \"https://registry.npmjs.org\"\n\n      - name: Derive RELEASE_VERSION\n        id: release-version\n        working-directory: ./npm\n        env:\n          PROVENANCE: true\n          NPM_TOKEN: ${{ secrets.NPM_TOKEN }}\n          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}\n          NPM_REGISTRY_URL: ${{ env.NPM_REGISTRY_URL }}\n          ARTIFACT_DIR: ${{ steps.paths.outputs.artifact_dir }}\n        run: |\n          set -euo pipefail\n\n          echo \"Artifacts in $ARTIFACT_DIR:\"\n          ls -la \"$ARTIFACT_DIR\" || true\n\n          # Derive RELEASE_VERSION from any foundry artifact we downloaded\n          # Expected names: foundry_<VERSION>_<platform>_<arch>.{tar.gz,zip}\n          first_file=$(ls \"$ARTIFACT_DIR\"/foundry_* 2>/dev/null | head -n1 || true)\n          if [[ -z \"${first_file}\" ]]; then\n            echo \"No foundry artifacts found to publish\" >&2\n            exit 1\n          fi\n          version_part=$(basename \"$first_file\")\n          version_part=${version_part#foundry_}\n          export RELEASE_VERSION=${version_part%%_*}\n          echo \"Detected RELEASE_VERSION=$RELEASE_VERSION\"\n\n          printf 'RELEASE_VERSION=%s\\n' \"$RELEASE_VERSION\" >>\"$GITHUB_OUTPUT\"\n\n      - name: Stage Binary Into Package\n        working-directory: ./npm\n        env:\n          RELEASE_VERSION: ${{ steps.release-version.outputs.RELEASE_VERSION }}\n          ARTIFACT_DIR: ${{ steps.paths.outputs.artifact_dir }}\n        run: |\n          set -euo pipefail\n\n          bun ./scripts/stage-from-artifact.mjs \\\n            --tool '${{ matrix.tool }}' \\\n            --platform '${{ matrix.os }}' \\\n            --arch '${{ matrix.arch }}' \\\n            --release-version \"$RELEASE_VERSION\" \\\n            --artifact-dir \"$ARTIFACT_DIR\"\n\n      - name: Sanity Check Binary\n        working-directory: ./npm\n        run: |\n          set -euo pipefail\n          TOOL='${{ matrix.tool }}'\n          PLATFORM='${{ matrix.os }}'\n          ARCH='${{ matrix.arch }}'\n\n          PKG_DIR=\"./@foundry-rs/${TOOL}-${PLATFORM}-${ARCH}\"\n          BIN=\"$PKG_DIR/bin/${TOOL}\"\n          if [[ \"$PLATFORM\" == \"win32\" ]]; then\n            BIN=\"$PKG_DIR/bin/${TOOL}.exe\"\n          fi\n          echo \"Verifying binary at: $BIN\"\n          ls -la \"$BIN\"\n          if [[ ! -f \"$BIN\" ]]; then\n            echo \"ERROR: Binary not found at $BIN\" >&2\n            exit 1\n          fi\n\n          if [[ \"${{ matrix.os }}\" != \"win32\" ]]; then\n            if [[ ! -x \"$BIN\" ]]; then\n              echo \"ERROR: Binary not marked executable\" >&2\n              exit 1\n            fi\n          fi\n\n      - name: Publish ${{ matrix.os }}-${{ matrix.arch }} Binary\n        working-directory: ./npm\n        env:\n          PROVENANCE: true\n          VERSION_NAME: ${{ steps.release-version.outputs.RELEASE_VERSION }}\n          RELEASE_VERSION: ${{ steps.release-version.outputs.RELEASE_VERSION }}\n          NPM_TOKEN: ${{ secrets.NPM_TOKEN }}\n          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}\n        run: |\n          set -euo pipefail\n\n          TOOL='${{ matrix.tool }}'\n          PLATFORM='${{ matrix.os }}'\n          ARCH='${{ matrix.arch }}'\n\n          PACKAGE_DIR=\"./@foundry-rs/${TOOL}-${PLATFORM}-${ARCH}\"\n          ls -la \"$PACKAGE_DIR\"\n\n          bun ./scripts/publish.mjs \"$PACKAGE_DIR\"\n\n          echo \"Published @foundry-rs/${TOOL}-${PLATFORM}-${ARCH}\"\n\n  publish-meta:\n    permissions:\n      contents: read\n      actions: read\n      id-token: write\n    needs: publish-arch\n    name: Publish Meta Package\n    runs-on: ubuntu-latest\n    env:\n      NPM_TOKEN: ${{ secrets.NPM_TOKEN }}\n      NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}\n      RELEASE_VERSION: ${{ needs.publish-arch.outputs.RELEASE_VERSION }}\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v6\n        with:\n          persist-credentials: false\n\n      - name: Setup Bun\n        uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2\n        with:\n          bun-version: latest\n\n      - name: Setup Node (for npm publish auth)\n        uses: actions/setup-node@v6\n        with:\n          node-version: \"24\"\n          registry-url: \"https://registry.npmjs.org\"\n\n      - name: Install Dependencies\n        working-directory: ./npm\n        run: bun install --frozen-lockfile\n\n      - name: Typecheck\n        working-directory: ./npm\n        run: bun tsc --project tsconfig.json --noEmit\n\n      - name: Publish Meta Packages\n        working-directory: ./npm\n        run: |\n          set -euo pipefail\n          bun ./scripts/publish-meta.mjs --release-version \"$RELEASE_VERSION\"\n        env:\n          PROVENANCE: true\n          VERSION_NAME: ${{ env.RELEASE_VERSION }}\n          RELEASE_VERSION: ${{ env.RELEASE_VERSION }}\n          NPM_TOKEN: ${{ env.NPM_TOKEN }}\n          NODE_AUTH_TOKEN: ${{ env.NODE_AUTH_TOKEN }}\n          NPM_REGISTRY_URL: ${{ env.NPM_REGISTRY_URL }}\n"
  },
  {
    "path": ".github/workflows/release.yml",
    "content": "name: release\n\npermissions: {}\n\non:\n  push:\n    tags:\n      - \"stable\"\n      - \"rc\"\n      - \"rc-*\"\n      - \"v*.*.*\"\n  schedule:\n    - cron: \"0 6 * * *\"\n  workflow_dispatch:\n\nenv:\n  CARGO_TERM_COLOR: always\n  IS_NIGHTLY: ${{ github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' }}\n\n  # Keep in sync with `docker-publish.yml`.\n  RUST_PROFILE: dist\n  RUST_FEATURES: aws-kms,gcp-kms,turnkey,cli,asm-keccak,js-tracer\n\n  LAST_STABLE_VERSION: \"v1.5.1\"\n\njobs:\n  prepare:\n    name: Prepare release\n    runs-on: ubuntu-latest\n    timeout-minutes: 30\n    permissions:\n      contents: write\n      pull-requests: read\n    outputs:\n      tag_name: ${{ steps.release_info.outputs.tag_name }}\n      release_name: ${{ steps.release_info.outputs.release_name }}\n      changelog: ${{ steps.build_changelog.outputs.changelog }}\n    steps:\n      - uses: actions/checkout@v6\n        with:\n          persist-credentials: false\n          fetch-depth: 0\n\n      - name: Compute release name and tag\n        id: release_info\n        run: |\n          if [[ ${IS_NIGHTLY} == 'true' ]]; then\n            printf 'tag_name=%s\\n' \"nightly-${GITHUB_SHA}\" >> \"$GITHUB_OUTPUT\"\n            printf 'release_name=%s\\n' \"Nightly ($(date '+%Y-%m-%d'))\" >> \"$GITHUB_OUTPUT\"\n          else\n            printf 'tag_name=%s\\n' \"$GITHUB_REF_NAME\" >> \"$GITHUB_OUTPUT\"\n            printf 'release_name=%s\\n' \"$GITHUB_REF_NAME\" >> \"$GITHUB_OUTPUT\"\n          fi\n\n      # Creates a `nightly-SHA` tag for this specific nightly\n      # This tag is used for this specific nightly version's release\n      # which allows users to roll back. It is also used to build\n      # the changelog.\n      - name: Create build-specific nightly tag\n        if: ${{ env.IS_NIGHTLY == 'true' }}\n        uses: actions/github-script@v8\n        env:\n          TAG_NAME: ${{ steps.release_info.outputs.tag_name }}\n        with:\n          script: |\n            const createTag = require('./.github/scripts/create-tag.js')\n            await createTag({ github, context }, process.env.TAG_NAME)\n\n      - name: Build changelog\n        id: build_changelog\n        uses: mikepenz/release-changelog-builder-action@a34a8009a9588bb86b02a873cf592440e96a5da8 # v6\n        with:\n          configuration: \"./.github/changelog.json\"\n          fromTag: ${{ env.IS_NIGHTLY == 'true' && 'nightly' || env.STABLE_VERSION }}\n          toTag: ${{ steps.release_info.outputs.tag_name }}\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n\n  release-docker:\n    name: Release Docker\n    needs: prepare\n    uses: ./.github/workflows/docker-publish.yml\n    permissions:\n      contents: read\n      id-token: write\n      packages: write\n    with:\n      tag_name: ${{ needs.prepare.outputs.tag_name }}\n\n  release:\n    permissions:\n      id-token: write\n      contents: write\n      attestations: write\n    name: release ${{ matrix.target }} (${{ matrix.runner }})\n    runs-on: ${{ matrix.runner }}\n    timeout-minutes: 240\n    needs: prepare\n    strategy:\n      fail-fast: false\n      matrix:\n        include:\n          # `runner`: GHA runner label\n          # `target`: Rust build target triple\n          # `platform` and `arch`: Used in tarball names\n          # `svm`: target platform to use for the Solc binary: https://github.com/roynalnaruto/svm-rs/blob/84cbe0ac705becabdc13168bae28a45ad2299749/svm-builds/build.rs#L4-L24\n          # These are pinned to the oldest runner versions to support old libc/SDK versions.\n          - runner: depot-ubuntu-22.04-16\n            target: x86_64-unknown-linux-gnu\n            svm_target_platform: linux-amd64\n            platform: linux\n            arch: amd64\n          - runner: depot-ubuntu-22.04-16\n            target: x86_64-unknown-linux-musl\n            svm_target_platform: linux-amd64\n            platform: alpine\n            arch: amd64\n          - runner: depot-ubuntu-22.04-arm-16\n            target: aarch64-unknown-linux-gnu\n            svm_target_platform: linux-aarch64\n            platform: linux\n            arch: arm64\n          - runner: depot-ubuntu-22.04-16\n            target: aarch64-unknown-linux-musl\n            svm_target_platform: linux-aarch64\n            platform: alpine\n            arch: arm64\n          - runner: macos-14-large\n            target: x86_64-apple-darwin\n            svm_target_platform: macosx-amd64\n            platform: darwin\n            arch: amd64\n          - runner: macos-latest-large\n            target: aarch64-apple-darwin\n            svm_target_platform: macosx-aarch64\n            platform: darwin\n            arch: arm64\n          - runner: depot-windows-latest-16\n            target: x86_64-pc-windows-msvc\n            svm_target_platform: windows-amd64\n            platform: win32\n            arch: amd64\n    steps:\n      - uses: actions/checkout@v6\n        with:\n          persist-credentials: false\n      - uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9 # master\n        with:\n          toolchain: stable\n          targets: ${{ matrix.target }}\n      - uses: rui314/setup-mold@725a8794d15fc7563f59595bd9556495c0564878 # v1\n\n      - uses: mozilla-actions/sccache-action@7d986dd989559c6ecdb630a3fd2557667be217ad # v0.0.9\n        if: ${{ contains(matrix.runner, 'depot') }}\n      - run: printf 'RUSTC_WRAPPER=sccache\\n' >> \"$GITHUB_ENV\"\n        if: ${{ contains(matrix.runner, 'depot') }}\n\n      - name: Apple M1 setup\n        if: matrix.target == 'aarch64-apple-darwin'\n        run: |\n          printf 'SDKROOT=%s\\n' \"$(xcrun -sdk macosx --show-sdk-path)\" >> \"$GITHUB_ENV\"\n          printf 'MACOSX_DEPLOYMENT_TARGET=%s\\n' \"$(xcrun -sdk macosx --show-sdk-platform-version)\" >> \"$GITHUB_ENV\"\n\n      - name: cross setup\n        if: contains(matrix.target, 'musl')\n        uses: taiki-e/cache-cargo-install-action@59027ebf20a9617c4e819eb53ccd2673cb162b89 # v2\n        with:\n          git: https://github.com/cross-rs/cross\n          rev: baf457efc2555225af47963475bd70e8d2f5993f\n          tool: cross\n\n      - name: Build binaries\n        env:\n          TAG_NAME: ${{ (env.IS_NIGHTLY == 'true' && 'nightly') || needs.prepare.outputs.tag_name }}\n          SVM_TARGET_PLATFORM: ${{ matrix.svm_target_platform }}\n          PLATFORM_NAME: ${{ matrix.platform }}\n          TARGET: ${{ matrix.target }}\n          OUT_DIR: target/${{ matrix.target }}/${{ env.RUST_PROFILE }}\n        shell: bash\n        run: |\n          set -eo pipefail\n          flags=(--target $TARGET --profile $RUST_PROFILE --bins\n            --no-default-features --features \"$RUST_FEATURES\")\n\n          # `jemalloc` is not fully supported on MSVC or aarch64 Linux.\n          if [[ \"$TARGET\" != *msvc* && \"$TARGET\" != \"aarch64-unknown-linux-gnu\" ]]; then\n            flags+=(--features jemalloc)\n          fi\n\n          [[ \"$TARGET\" == *windows* ]] && ext=\".exe\"\n\n          if [[ \"$TARGET\" == *-musl ]]; then\n            cross build \"${flags[@]}\"\n          else\n            cargo build \"${flags[@]}\"\n          fi\n\n          bins=(anvil cast chisel forge)\n          for name in \"${bins[@]}\"; do\n            bin=\"$OUT_DIR/$name$ext\"\n            printf '\\n'\n            file \"$bin\" || true\n            du -h \"$bin\" || true\n            ldd \"$bin\" || true\n            $bin --version || true\n            printf '%s_bin_path=%s\\n' \"$name\" \"$bin\" >> \"$GITHUB_ENV\"\n          done\n\n      - name: Archive binaries\n        id: artifacts\n        env:\n          PLATFORM_NAME: ${{ matrix.platform }}\n          OUT_DIR: target/${{ matrix.target }}/${{ env.RUST_PROFILE }}\n          VERSION_NAME: ${{ (env.IS_NIGHTLY == 'true' && 'nightly') || needs.prepare.outputs.tag_name }}\n          ARCH: ${{ matrix.arch }}\n        shell: bash\n        run: |\n          if [[ \"$PLATFORM_NAME\" == \"linux\" || \"$PLATFORM_NAME\" == \"alpine\" ]]; then\n            tar -czvf \"foundry_${VERSION_NAME}_${PLATFORM_NAME}_${ARCH}.tar.gz\" -C \"$OUT_DIR\" forge cast anvil chisel\n            printf \"file_name=%s\\n\" \"foundry_${VERSION_NAME}_${PLATFORM_NAME}_${ARCH}.tar.gz\" >> \"$GITHUB_OUTPUT\"\n          elif [ \"$PLATFORM_NAME\" == \"darwin\" ]; then\n            # We need to use gtar here otherwise the archive is corrupt.\n            # See: https://github.com/actions/virtual-environments/issues/2619\n            gtar -czvf \"foundry_${VERSION_NAME}_${PLATFORM_NAME}_${ARCH}.tar.gz\" -C \"$OUT_DIR\" forge cast anvil chisel\n            printf \"file_name=%s\\n\" \"foundry_${VERSION_NAME}_${PLATFORM_NAME}_${ARCH}.tar.gz\" >> \"$GITHUB_OUTPUT\"\n          else\n            cd \"$OUT_DIR\"\n            7z a -tzip \"foundry_${VERSION_NAME}_${PLATFORM_NAME}_${ARCH}.zip\" forge.exe cast.exe anvil.exe chisel.exe\n            mv \"foundry_${VERSION_NAME}_${PLATFORM_NAME}_${ARCH}.zip\" ../../../\n            printf \"file_name=%s\\n\" \"foundry_${VERSION_NAME}_${PLATFORM_NAME}_${ARCH}.zip\" >> \"$GITHUB_OUTPUT\"\n          fi\n          printf \"foundry_attestation=%s\\n\" \"foundry_${VERSION_NAME}_${PLATFORM_NAME}_${ARCH}.attestation.txt\" >> \"$GITHUB_OUTPUT\"\n\n      - name: Upload build artifacts\n        uses: actions/upload-artifact@v7\n        with:\n          retention-days: 1\n          name: ${{ steps.artifacts.outputs.file_name }}\n          path: ${{ steps.artifacts.outputs.file_name }}\n\n      - name: Build man page\n        id: man\n        if: matrix.target == 'x86_64-unknown-linux-gnu'\n        env:\n          OUT_DIR: target/${{ matrix.target }}/${{ env.RUST_PROFILE }}\n          VERSION_NAME: ${{ (env.IS_NIGHTLY == 'true' && 'nightly') || needs.prepare.outputs.tag_name }}\n        shell: bash\n        run: |\n          sudo apt-get -y install help2man\n          help2man -N $OUT_DIR/forge > forge.1\n          help2man -N $OUT_DIR/cast > cast.1\n          help2man -N $OUT_DIR/anvil > anvil.1\n          help2man -N $OUT_DIR/chisel > chisel.1\n          gzip forge.1\n          gzip cast.1\n          gzip anvil.1\n          gzip chisel.1\n          tar -czvf \"foundry_man_${VERSION_NAME}.tar.gz\" forge.1.gz cast.1.gz anvil.1.gz chisel.1.gz\n          printf 'foundry_man=%s\\n' \"foundry_man_${VERSION_NAME}.tar.gz\" >> \"$GITHUB_OUTPUT\"\n\n      - name: Binaries attestation\n        id: attestation\n        uses: actions/attest-build-provenance@v4\n        with:\n          subject-path: |\n            ${{ env.anvil_bin_path }}\n            ${{ env.cast_bin_path }}\n            ${{ env.chisel_bin_path }}\n            ${{ env.forge_bin_path }}\n\n      - name: Record attestation URL\n        env:\n          ATTESTATION_URL: ${{ steps.attestation.outputs.attestation-url }}\n          FOUNDRY_ATTESTATION: ${{ steps.artifacts.outputs.foundry_attestation }}\n        shell: bash\n        run: |\n          set -euo pipefail\n          printf '%s\\n' \"$ATTESTATION_URL\" > \"$FOUNDRY_ATTESTATION\"\n\n      # Creates the release for this specific version\n      - name: Create release\n        uses: softprops/action-gh-release@5be0e66d93ac7ed76da52eca8bb058f665c3a5fe # v2.4.2\n        with:\n          name: ${{ needs.prepare.outputs.release_name }}\n          tag_name: ${{ needs.prepare.outputs.tag_name }}\n          prerelease: ${{ env.IS_NIGHTLY == 'true' }}\n          body: ${{ needs.prepare.outputs.changelog }}\n          files: |\n            ${{ steps.artifacts.outputs.file_name }}\n            ${{ steps.artifacts.outputs.foundry_attestation }}\n            ${{ steps.man.outputs.foundry_man }}\n\n      # If this is a nightly release, it also updates the release\n      # tagged `nightly` for compatibility with `foundryup`\n      - name: Update nightly release\n        if: ${{ env.IS_NIGHTLY == 'true' }}\n        uses: softprops/action-gh-release@5be0e66d93ac7ed76da52eca8bb058f665c3a5fe # v2.4.2\n        with:\n          name: \"Nightly\"\n          tag_name: \"nightly\"\n          prerelease: true\n          body: ${{ needs.prepare.outputs.changelog }}\n          files: |\n            ${{ steps.artifacts.outputs.file_name }}\n            ${{ steps.artifacts.outputs.foundry_attestation }}\n            ${{ steps.man.outputs.foundry_man }}\n\n  cleanup:\n    name: Release cleanup\n    runs-on: ubuntu-latest\n    timeout-minutes: 30\n    permissions:\n      contents: write\n    needs: release\n    if: always()\n    steps:\n      - uses: actions/checkout@v6\n        with:\n          persist-credentials: false\n\n      # Moves the `nightly` tag to `HEAD`\n      - name: Move nightly tag\n        if: ${{ env.IS_NIGHTLY == 'true' }}\n        uses: actions/github-script@v8\n        with:\n          script: |\n            const moveTag = require('./.github/scripts/move-tag.js')\n            await moveTag({ github, context }, 'nightly')\n\n      - name: Delete old nightlies\n        uses: actions/github-script@v8\n        with:\n          script: |\n            const prunePrereleases = require('./.github/scripts/prune-prereleases.js')\n            await prunePrereleases({github, context})\n\n  # If any of the jobs fail, this will create a high-priority issue to signal so.\n  issue:\n    name: Open an issue\n    runs-on: ubuntu-latest\n    needs: [prepare, release-docker, release, cleanup]\n    if: failure()\n    permissions:\n      contents: read\n      issues: write\n    steps:\n      - uses: actions/checkout@v6\n        with:\n          persist-credentials: false\n      - uses: JasonEtco/create-an-issue@1b14a70e4d8dc185e5cc76d3bec9eab20257b2c5 # v2\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n          WORKFLOW_URL: |\n            ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}\n        with:\n          update_existing: true\n          filename: .github/RELEASE_FAILURE_ISSUE_TEMPLATE.md\n"
  },
  {
    "path": ".github/workflows/test-flaky.yml",
    "content": "# Daily CI job to run flaky tests that are excluded from regular CI via nextest default-filter\n\nname: test-flaky\n\npermissions: {}\n\non:\n  schedule:\n    - cron: \"0 1 * * *\" # Run daily at 1 AM UTC (offset from test-isolate)\n  workflow_dispatch: # Needed so we can run it manually\n\nconcurrency:\n  group: tests-${{ github.workflow }}-${{ github.head_ref || github.run_id }}\n  cancel-in-progress: true\n\nenv:\n  CARGO_TERM_COLOR: always\n  RUST_BACKTRACE: full\n  RUSTC_WRAPPER: \"sccache\"\n\njobs:\n  test:\n    name: flaky tests\n    runs-on: depot-ubuntu-latest-16\n    timeout-minutes: 60\n    permissions:\n      contents: read\n    steps:\n      - uses: actions/checkout@v6\n        with:\n          persist-credentials: false\n      - uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9 # master\n        with:\n          toolchain: stable\n      - uses: rui314/setup-mold@725a8794d15fc7563f59595bd9556495c0564878 # v1\n      - uses: taiki-e/install-action@94a7388bec5d4c8dd93e3ebf09e0ff448f3f6f4d # v2\n        with:\n          tool: nextest\n      - uses: mozilla-actions/sccache-action@7d986dd989559c6ecdb630a3fd2557667be217ad # v0.0.9\n      - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2\n      - name: Test flaky tests\n        env:\n          SVM_TARGET_PLATFORM: linux-amd64\n          HTTP_ARCHIVE_URLS: ${{ secrets.HTTP_ARCHIVE_URLS }}\n          ETHERSCAN_KEY: ${{ secrets.ETHERSCAN_API_KEY }}\n        run: cargo nextest run --profile flaky --no-fail-fast\n\n  # If any of the jobs fail, this will create a normal-priority issue to signal so.\n  issue:\n    name: Open an issue\n    runs-on: ubuntu-latest\n    needs: [test]\n    if: failure()\n    permissions:\n      contents: read\n      issues: write\n    steps:\n      - uses: actions/checkout@v6\n        with:\n          persist-credentials: false\n      - uses: JasonEtco/create-an-issue@1b14a70e4d8dc185e5cc76d3bec9eab20257b2c5 # v2\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n          WORKFLOW_URL: |\n            ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}\n        with:\n          update_existing: true\n          filename: .github/FLAKY_TEST_FAILURE_TEMPLATE.md\n"
  },
  {
    "path": ".github/workflows/test-isolate.yml",
    "content": "# Daily CI job to run tests with isolation mode enabled by default\n\nname: test-isolate\n\npermissions: {}\n\non:\n  schedule:\n    - cron: \"0 0 * * *\" # Run daily at midnight UTC\n  workflow_dispatch: # Needed so we can run it manually\n\nenv:\n  CARGO_TERM_COLOR: always\n  RUST_BACKTRACE: full\n  RUSTC_WRAPPER: \"sccache\"\n\njobs:\n  nextest:\n    uses: ./.github/workflows/test.yml\n    permissions:\n      contents: read\n    with:\n      profile: isolate\n\n  # Run flaky tests with isolation enabled\n  flaky:\n    name: flaky tests (isolate)\n    runs-on: depot-ubuntu-latest-16\n    timeout-minutes: 60\n    permissions:\n      contents: read\n    steps:\n      - uses: actions/checkout@v6\n        with:\n          persist-credentials: false\n      - uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9 # master\n        with:\n          toolchain: stable\n      - uses: rui314/setup-mold@725a8794d15fc7563f59595bd9556495c0564878 # v1\n      - uses: taiki-e/install-action@94a7388bec5d4c8dd93e3ebf09e0ff448f3f6f4d # v2\n        with:\n          tool: nextest\n      - uses: mozilla-actions/sccache-action@7d986dd989559c6ecdb630a3fd2557667be217ad # v0.0.9\n      - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2\n      - name: Test flaky tests with isolation\n        env:\n          SVM_TARGET_PLATFORM: linux-amd64\n          HTTP_ARCHIVE_URLS: ${{ secrets.HTTP_ARCHIVE_URLS }}\n          ETHERSCAN_KEY: ${{ secrets.ETHERSCAN_API_KEY }}\n        run: cargo nextest run --profile flaky --features=isolate-by-default --no-fail-fast\n\n  # If nextest fails, create a high-priority issue for isolation failures.\n  issue-isolate:\n    name: Open isolation issue\n    runs-on: ubuntu-latest\n    needs: [nextest]\n    if: failure()\n    permissions:\n      contents: read\n      issues: write\n    steps:\n      - uses: actions/checkout@v6\n        with:\n          persist-credentials: false\n      - uses: JasonEtco/create-an-issue@1b14a70e4d8dc185e5cc76d3bec9eab20257b2c5 # v2\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n          WORKFLOW_URL: |\n            ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}\n        with:\n          update_existing: true\n          filename: .github/TEST_ISOLATE_FAILURE_TEMPLATE.md\n\n  # If flaky tests fail, create a normal-priority issue for flaky failures.\n  issue-flaky:\n    name: Open flaky issue\n    runs-on: ubuntu-latest\n    needs: [flaky]\n    if: failure()\n    permissions:\n      contents: read\n      issues: write\n    steps:\n      - uses: actions/checkout@v6\n        with:\n          persist-credentials: false\n      - uses: JasonEtco/create-an-issue@1b14a70e4d8dc185e5cc76d3bec9eab20257b2c5 # v2\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n          WORKFLOW_URL: |\n            ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}\n        with:\n          update_existing: true\n          filename: .github/FLAKY_TEST_ISOLATE_FAILURE_TEMPLATE.md\n"
  },
  {
    "path": ".github/workflows/test.yml",
    "content": "# Reusable workflow for running tests via `cargo nextest`\n\nname: test\n\npermissions: {}\n\non:\n  workflow_call:\n    inputs:\n      profile:\n        required: true\n        type: string\n\nconcurrency:\n  group: tests-${{ github.workflow }}-${{ github.head_ref || github.run_id }}\n  cancel-in-progress: true\n\nenv:\n  CARGO_TERM_COLOR: always\n  RUST_BACKTRACE: full\n  RUSTC_WRAPPER: \"sccache\"\n  RUST_MIN_STACK: 4194304 # 2 * the default (2 * 1024 * 1024)\n\njobs:\n  matrices:\n    name: build matrices\n    runs-on: ubuntu-latest\n    permissions:\n      contents: read\n    outputs:\n      test-matrix: ${{ steps.gen.outputs.test-matrix }}\n    steps:\n      - uses: actions/checkout@v6\n        with:\n          persist-credentials: false\n      - uses: actions/setup-python@v6\n        with:\n          python-version: \"3.14\"\n      - name: Generate matrices\n        id: gen\n        env:\n          EVENT_NAME: ${{ github.event_name }}\n          PROFILE: ${{ inputs.profile }}\n        shell: bash\n        run: |\n          output=$(python3 .github/scripts/matrices.py)\n          printf '::debug::test-matrix=%s\\n' \"$output\"\n          printf 'test-matrix=%s\\n' \"$output\" >> \"$GITHUB_OUTPUT\"\n\n  test:\n    name: test ${{ matrix.name }}\n    runs-on: ${{ matrix.runner_label }}\n    timeout-minutes: 60\n    permissions:\n      contents: read\n    needs: matrices\n    strategy:\n      fail-fast: false\n      matrix: ${{ fromJson(needs.matrices.outputs.test-matrix) }}\n    steps:\n      - uses: actions/checkout@v6\n        with:\n          persist-credentials: false\n      - uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9 # master\n        with:\n          toolchain: stable\n          target: ${{ matrix.target }}\n      - uses: rui314/setup-mold@725a8794d15fc7563f59595bd9556495c0564878 # v1\n      - uses: taiki-e/install-action@94a7388bec5d4c8dd93e3ebf09e0ff448f3f6f4d # v2\n        with:\n          tool: nextest\n\n      # External tests dependencies\n      - name: Setup Node.js\n        if: contains(matrix.name, 'external')\n        uses: actions/setup-node@v6\n        with:\n          node-version: 24\n      - name: Install Bun\n        if: contains(matrix.name, 'external')\n        uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2\n        with:\n          bun-version: latest\n      - name: Setup Python\n        uses: actions/setup-python@v6\n        with:\n          python-version: \"3.14\"\n      - name: Install Vyper\n        # Also update vyper version in .devcontainer/Dockerfile.dev\n        run: pip --version && pip install vyper==0.4.3\n\n      - name: Foundry test cache\n        uses: actions/cache@v5\n        with:\n          path: |\n            ~/.foundry/cache\n            ~/.config/.foundry/cache\n            testdata/cache\n            testdata/out\n          # Use a unique key for each run to always update the cache.\n          key: ${{ runner.os }}-foundry-${{ matrix.name }}-${{ github.run_id }}\n          restore-keys: |\n            ${{ runner.os }}-foundry-${{ matrix.name }}-\n      - uses: mozilla-actions/sccache-action@7d986dd989559c6ecdb630a3fd2557667be217ad # v0.0.9\n      - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2\n      - name: Setup Git config\n        run: |\n          git config --global user.name \"GitHub Actions Bot\"\n          git config --global user.email \"<>\"\n          git config --global url.\"https://github.com/\".insteadOf \"git@github.com:\"\n      - name: Test\n        env:\n          SVM_TARGET_PLATFORM: ${{ matrix.svm_target_platform }}\n          HTTP_ARCHIVE_URLS: ${{ secrets.HTTP_ARCHIVE_URLS }}\n          WS_ARCHIVE_URLS: ${{ secrets.WS_ARCHIVE_URLS }}\n          ETHERSCAN_KEY: ${{ secrets.ETHERSCAN_API_KEY }}\n          ARBITRUM_RPC: ${{ secrets.ARBITRUM_RPC }}\n          ETH_SEPOLIA_RPC: ${{ secrets.ETH_SEPOLIA_RPC }}\n        run: cargo nextest run ${{ matrix.flags }}\n"
  },
  {
    "path": ".gitignore",
    "content": ".DS_STORE\n/target*\n/*.sol\nCLAUDE.md\n\n# Foundry artifacts\nout/\nsnapshots/\n\n# IDEs and extensions\n.idea\n.vscode\n.claude\n.zed\n\n# NPM\n.env\nnode_modules\nnpm/dist\nnpm/bin\n_\n*.tgz\n.vercel\n.vite\n.wrangler\n*.zip\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "## Contributing to Foundry\n\nThanks for your interest in improving Foundry!\n\nThere are multiple opportunities to contribute at any level. It doesn't matter if you are just getting started with Rust or are the most weathered expert, we can use your help.\n\nThis document will help you get started. **Do not let the document intimidate you**.\nIt should be considered as a guide to help you navigate the process.\n\nThe [dev Telegram][dev-tg] is available for any concerns you may have that are not covered in this guide.\n\n### Code of Conduct\n\nThe Foundry project adheres to the [Rust Code of Conduct][rust-coc]. This code of conduct describes the _minimum_ behavior expected from all contributors.\n\nInstances of violations of the Code of Conduct can be reported by contacting the team at [me@gakonst.com](mailto:me@gakonst.com).\n\n### Ways to contribute\n\nThere are fundamentally four ways an individual can contribute:\n\n1. **By opening an issue:** For example, if you believe that you have uncovered a bug\n   in Foundry, creating a new issue in the issue tracker is the way to report it.\n2. **By adding context:** Providing additional context to existing issues,\n   such as screenshots and code snippets, which help resolve issues.\n3. **By resolving issues:** Typically this is done in the form of either\n   demonstrating that the issue reported is not a problem after all, or more often,\n   by opening a pull request that fixes the underlying problem, in a concrete and\n   reviewable manner.\n\n**Anybody can participate in any stage of contribution**. We urge you to participate in the discussion\naround bugs and participate in reviewing PRs.\n\n### Contributions Related to Spelling and Grammar\n\nAt this time, we will not be accepting contributions that only fix spelling or grammatical errors in documentation, code or elsewhere.\n\n### Contributions Assisted by AI\n\nIf you are using any kind of AI assistance while contributing to Foundry,\n**this must be disclosed in the pull request**, along with the extent to\nwhich AI assistance was used (e.g. docs only vs. code generation).\n\nIf PR responses are being generated by an AI, disclose that as well.\n\nAs a small exception, trivial tab-completion doesn't need to be disclosed,\nso long as it is limited to single keywords or short phrases.\n\nAn example disclosure:\n\n> This PR was written primarily by Claude Code.\n\nOr a more detailed disclosure:\n\n> I consulted ChatGPT to understand the codebase but the solution\n> was fully authored manually by myself.\n\nFailure to disclose this makes it difficult to determine how much scrutiny to apply to the contribution as it is unclear how much the contributor themselves understands the code they propose to merge.\n\nIf you do not disclose your use of AI assistance and reviewers suspect your contribution to be AI generated, it will likely be refused on those grounds.\n\n### Asking for help\n\nIf you have reviewed existing documentation and still have questions, or you are having problems, you can get help in the following ways:\n\n- **Asking in the support Telegram:** The [Foundry Support Telegram][support-tg] is a fast and easy way to ask questions.\n- **Opening a discussion:** This repository comes with a discussions board where you can also ask for help. Click the \"Discussions\" tab at the top.\n\nAs Foundry is still in heavy development, the documentation can be a bit scattered.\nThe [Foundry Book][foundry-book] is our current best-effort attempt at keeping up-to-date information.\n\n### Submitting a bug report\n\nWhen filing a new bug report in the issue tracker, you will be presented with a basic form to fill out.\n\nIf you believe that you have uncovered a bug, please fill out the form to the best of your ability. Do not worry if you cannot answer every detail; just fill in what you can. Contributors will ask follow-up questions if something is unclear.\n\nThe most important pieces of information we need in a bug report are:\n\n- The Foundry version you are on (and that it is up to date)\n- The platform you are on (Windows, macOS or Linux)\n- Code snippets if this is happening in relation to testing or building code\n- Concrete steps to reproduce the bug\n\nIn order to rule out the possibility of the bug being in your project, the code snippets should be as minimal\nas possible. It is better if you can reproduce the bug with a small snippet as opposed to an entire project!\n\nSee [this guide][mcve] on how to create a minimal, complete, and verifiable example.\n\n### Submitting a feature request\n\nWhen adding a feature request in the issue tracker, you will be presented with a basic form to fill out.\n\nPlease include as detailed of an explanation as possible of the feature you would like, adding additional context if necessary.\n\nIf you have examples of other tools that have the feature you are requesting, please include them as well.\n\n### Resolving an issue\n\nPull requests are the way concrete changes are made to the code, documentation, and dependencies of Foundry.\n\nEven minor pull requests, such as those fixing wording, are greatly appreciated. Before making a large change, it is usually\na good idea to first open an issue describing the change to solicit feedback and guidance. This will increase\nthe likelihood of the PR getting merged.\n\nPlease also make sure that the following commands pass if you have changed the code:\n\n```sh\ncargo check --all\ncargo test --all --all-features\ncargo +nightly fmt -- --check\ncargo +nightly clippy --workspace --all-targets --all-features -- -D warnings\n```\n\nor alternatively:\n\n```sh\nmake build\nmake pr\n```\n\nIf you are working in VSCode, we recommend you install the [rust-analyzer](https://rust-analyzer.github.io/) extension, and use the following VSCode user settings:\n\n```json\n\"editor.formatOnSave\": true,\n\"rust-analyzer.rustfmt.extraArgs\": [\"+nightly\"],\n\"[rust]\": {\n  \"editor.defaultFormatter\": \"rust-lang.rust-analyzer\"\n}\n```\n\nIf you are working on a larger feature, we encourage you to open up a draft pull request, to make sure that other contributors are not duplicating work.\n\nIf you would like to test the binaries built from your change, see [foundryup](https://github.com/foundry-rs/foundry/tree/HEAD/foundryup).\n\nIf you would like to use a debugger with breakpoints to debug a patch you might be working on, keep in mind we currently strip debug info for faster builds, which is _not_ the default. Therefore, to use a debugger, you need to enable it on the workspace [`Cargo.toml`'s `dev` profile](https://github.com/foundry-rs/foundry/tree/HEAD/Cargo.toml#L15-L18).\n\n#### Adding tests\n\nIf the change being proposed alters code, it is either adding new functionality to Foundry, or fixing existing, broken functionality.\nIn both of these cases, the pull request should include one or more tests to ensure that Foundry does not regress\nin the future.\n\nTypes of tests include:\n\n- **Unit tests**: Functions which have very specific tasks should be unit tested.\n- **Integration tests**: For general purpose, far reaching functionality, integration tests should be added.\n  The best way to add a new integration test is to look at existing ones and follow the style.\n\nTests that use forking must contain \"fork\" in their name.\n\n#### Commits\n\nIt is a recommended best practice to keep your changes as logically grouped as possible within individual commits. There is no limit to the number of commits any single pull request may have, and many contributors find it easier to review changes that are split across multiple commits.\n\nThat said, if you have a number of commits that are \"checkpoints\" and don't represent a single logical change, please squash those together.\n\n#### Opening the pull request\n\nFrom within GitHub, opening a new pull request will present you with a template that should be filled out. Please try your best at filling out the details, but feel free to skip parts if you're not sure what to put.\n\n#### Discuss and update\n\nYou will probably get feedback or requests for changes to your pull request.\nThis is a big part of the submission process, so don't be discouraged! Some contributors may sign off on the pull request right away, others may have more detailed comments or feedback.\nThis is a necessary part of the process in order to evaluate whether the changes are correct and necessary.\n\n**Any community member can review a PR, so you might get conflicting feedback**.\nKeep an eye out for comments from code owners to provide guidance on conflicting feedback.\n\n#### Reviewing pull requests\n\n**Any Foundry community member is welcome to review any pull request**.\n\nAll 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.\n\nReviews that are dismissive or disrespectful of the contributor or any other reviewers are strictly counter to the Code of Conduct.\n\nWhen reviewing a pull request, the primary goals are for the codebase to improve and for the person submitting the request to succeed. **Even if a pull request is not merged, the submitter should come away from the experience feeling like their effort was not unappreciated**. Every PR from a new contributor is an opportunity to grow the community.\n\n##### Review a bit at a time\n\nDo not overwhelm new contributors.\n\nIt is tempting to micro-optimize and make everything about relative performance, perfect grammar, or exact style matches. Do not succumb to that temptation..\n\nFocus first on the most significant aspects of the change:\n\n1. Does this change make sense for Foundry?\n2. Does this change make Foundry better, even if only incrementally?\n3. Are there clear bugs or larger scale issues that need attending?\n4. Are the commit messages readable and correct? If it contains a breaking change, is it clear enough?\n\nNote 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.\n\nWhen 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**.\n\nSpecific performance optimization techniques, coding styles and conventions change over time. The first impression you give to a new contributor never does.\n\nNits (requests for small changes that are not essential) are fine, but try to avoid stalling the pull request. Most nits can typically be fixed by the Foundry maintainers merging the pull request, but they can also be an opportunity for the contributor to learn a bit more about the project.\n\nIt is always good to clearly indicate nits when you comment, e.g.: `Nit: change foo() to bar(). But this is not blocking`.\n\nIf your comments were addressed but were not folded after new commits, or if they proved to be mistaken, please, [hide them][hiding-a-comment] with the appropriate reason to keep the conversation flow concise and relevant.\n\n##### Be aware of the person behind the code\n\nBe 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.\n\n##### Abandoned or stale pull requests\n\nIf a pull request appears to be abandoned or stalled, it is polite to first check with the contributor to see if they intend to continue the work before checking if they would mind if you took it over (especially if it just has nits left). When doing so, it is courteous to give the original contributor credit for the work they started, either by preserving their name and e-mail address in the commit log, or by using the `Author:` or `Co-authored-by:` metadata tag in the commits.\n\n_Adapted from the [ethers-rs contributing guide](https://github.com/gakonst/ethers-rs/blob/master/CONTRIBUTING.md)_.\n\n### Releasing\n\nReleases are automatically done by the release workflow when a tag is pushed, however, these steps still need to be taken:\n\n1. Ensure that the versions in the relevant `Cargo.toml` files are up-to-date.\n2. Update documentation links\n3. Perform a final audit for breaking changes.\n\n[rust-coc]: https://www.rust-lang.org/policies/code-of-conduct\n[dev-tg]: https://t.me/foundry_rs\n[foundry-book]: https://github.com/foundry-rs/foundry-book\n[support-tg]: https://t.me/foundry_support\n[mcve]: https://stackoverflow.com/help/mcve\n[hiding-a-comment]: https://docs.github.com/en/communities/moderating-comments-and-conversations/managing-disruptive-comments\n"
  },
  {
    "path": "Cargo.toml",
    "content": "[workspace]\nmembers = [\n    \"benches/\",\n    \"crates/anvil/\",\n    \"crates/anvil/core/\",\n    \"crates/anvil/rpc/\",\n    \"crates/anvil/server/\",\n    \"crates/cast/\",\n    \"crates/cheatcodes/\",\n    \"crates/cheatcodes/spec/\",\n    \"crates/chisel/\",\n    \"crates/cli/\",\n    \"crates/common/\",\n    \"crates/config/\",\n    \"crates/debugger/\",\n    \"crates/doc/\",\n    \"crates/evm/core/\",\n    \"crates/evm/coverage/\",\n    \"crates/evm/evm/\",\n    \"crates/evm/fuzz/\",\n    \"crates/evm/traces/\",\n    \"crates/fmt/\",\n    \"crates/forge/\",\n    \"crates/lint/\",\n    \"crates/macros/\",\n    \"crates/primitives/\",\n    \"crates/script-sequence/\",\n    \"crates/test-utils/\",\n    \"crates/cli-markdown/\",\n]\nresolver = \"2\"\n\n[workspace.package]\nversion = \"1.6.0\"\nedition = \"2024\"\nrust-version = \"1.89\"\nauthors = [\"Foundry Contributors\"]\nlicense = \"MIT OR Apache-2.0\"\nhomepage = \"https://getfoundry.sh\"\nrepository = \"https://github.com/foundry-rs/foundry\"\nexclude = [\"benches/\", \"tests/\", \"test-data/\", \"testdata/\"]\n\n[workspace.lints.clippy]\nborrow_as_ptr = \"warn\"\nbranches_sharing_code = \"warn\"\nclear_with_drain = \"warn\"\ncloned_instead_of_copied = \"warn\"\ncollection_is_never_read = \"warn\"\ndbg-macro = \"warn\"\nexplicit_iter_loop = \"warn\"\nmanual-string-new = \"warn\"\nuninlined-format-args = \"warn\"\nuse-self = \"warn\"\nredundant-clone = \"warn\"\noctal-escapes = \"allow\"\n# until <https://github.com/rust-lang/rust-clippy/issues/13885> is fixed\nliteral-string-with-formatting-args = \"allow\"\nresult_large_err = \"allow\"\n\n[workspace.lints.rust]\nredundant_imports = \"warn\"\nredundant-lifetimes = \"warn\"\nrust-2018-idioms = \"warn\"\nunused-must-use = \"warn\"\n# unreachable-pub = \"warn\"\n\n[workspace.lints.rustdoc]\nall = \"warn\"\n\n# Speed up compilation time for dev builds by reducing emitted debug info.\n# NOTE: Debuggers may provide less useful information with this setting.\n# Uncomment this section if you're using a debugger.\n[profile.dev]\n# https://davidlattimore.github.io/posts/2024/02/04/speeding-up-the-rust-edit-build-run-cycle.html\ndebug = \"line-tables-only\"\nsplit-debuginfo = \"unpacked\"\n\n[profile.release]\nopt-level = 3\nlto = \"thin\"\ndebug = \"none\"\nstrip = \"debuginfo\"\npanic = \"abort\"\ncodegen-units = 16\n\n# Use the `--profile profiling` flag to show symbols in release mode.\n# e.g. `cargo build --profile profiling`\n[profile.profiling]\ninherits = \"release\"\ndebug = \"full\"\nstrip = \"none\"\n\n[profile.bench]\ninherits = \"profiling\"\n\n[profile.dist]\ninherits = \"release\"\nlto = \"fat\"\ncodegen-units = 1\n\n# Speed up tests and dev build.\n[profile.dev.package]\n# Solc and artifacts.\nfoundry-compilers-artifacts-solc.opt-level = 3\nfoundry-compilers-core.opt-level = 3\nfoundry-compilers.opt-level = 3\nserde_json.opt-level = 3\nserde.opt-level = 3\n\nfoundry-solang-parser.opt-level = 3\nlalrpop-util.opt-level = 3\n\nsolar-compiler.opt-level = 3\nsolar-ast.opt-level = 3\nsolar-data-structures.opt-level = 3\nsolar-interface.opt-level = 3\nsolar-parse.opt-level = 3\nsolar-sema.opt-level = 3\n\n# CLI.\nclap.opt-level = 3\nclap_builder.opt-level = 3\nclap_lex.opt-level = 3\n\n# EVM.\nalloy-dyn-abi.opt-level = 3\nalloy-json-abi.opt-level = 3\nalloy-primitives.opt-level = 3\nalloy-sol-type-parser.opt-level = 3\nalloy-sol-types.opt-level = 3\nalloy-evm.opt-level = 3\n\nbitvec.opt-level = 3\nrevm.opt-level = 3\nrevm-bytecode.opt-level = 3\nrevm-context.opt-level = 3\nrevm-context-interface.opt-level = 3\nrevm-database.opt-level = 3\nrevm-database-interface.opt-level = 3\nrevm-handler.opt-level = 3\nrevm-inspector.opt-level = 3\nrevm-interpreter.opt-level = 3\nrevm-precompile.opt-level = 3\nrevm-primitives.opt-level = 3\nrevm-state.opt-level = 3\n\nrevm-inspectors.opt-level = 3\n\nruint.opt-level = 3\n\nsha2.opt-level = 3\nsha3.opt-level = 3\nkeccak.opt-level = 3\n\n# Fuzzing.\nproptest.opt-level = 3\nfoundry-evm-fuzz.opt-level = 3\nrand.opt-level = 3\nrand_chacha.opt-level = 3\nppv-lite86.opt-level = 3\n\n# Backtraces.\naddr2line.opt-level = 3\nbacktrace.opt-level = 3\ngimli.opt-level = 3\n\n# Forking.\naxum.opt-level = 3\n\n# Keystores.\nscrypt.opt-level = 3\n\n# Misc.\nhashbrown.opt-level = 3\nfoldhash.opt-level = 3\nrayon.opt-level = 3\nrayon-core.opt-level = 3\nregex.opt-level = 3\nregex-syntax.opt-level = 3\nregex-automata.opt-level = 3\nwalkdir.opt-level = 3\n\n# Override packages which aren't perf-sensitive for faster compilation speed and smaller binary size.\n[profile.release.package]\nalloy-sol-macro-expander.opt-level = \"s\"\nfigment2.opt-level = \"s\"\nfoundry-compilers-artifacts-solc.opt-level = \"s\"\nfoundry-config.opt-level = \"s\"\nhtml5ever.opt-level = \"s\"\nmdbook-driver.opt-level = \"s\"\nprettyplease.opt-level = \"s\"\nprotobuf.opt-level = \"s\"\npulldown-cmark.opt-level = \"s\"\nsyn-solidity.opt-level = \"s\"\nsyn.opt-level = \"s\"\ntrezor-client.opt-level = \"s\"\n\n# Networking stack (not perf-critical for CLI tools).\nreqwest.opt-level = \"s\"\nhyper.opt-level = \"s\"\nhyper-util.opt-level = \"s\"\nh2.opt-level = \"s\"\nrustls.opt-level = \"s\"\ntower.opt-level = \"s\"\ntower-http.opt-level = \"s\"\n\n# Doc generation / templating.\nmdbook-core.opt-level = \"s\"\nmdbook-html.opt-level = \"s\"\nfont-awesome-as-a-crate.opt-level = \"s\"\nhandlebars.opt-level = \"s\"\n\n# Watch mode.\nwatchexec.opt-level = \"s\"\nwatchexec-events.opt-level = \"s\"\nwatchexec-signals.opt-level = \"s\"\nwatchexec-supervisor.opt-level = \"s\"\n\n# Soldeer package manager.\nsoldeer-commands.opt-level = \"s\"\nsoldeer-core.opt-level = \"s\"\n\n# Parsing / editing (not perf-sensitive in CLI).\ntoml_edit.opt-level = \"s\"\ntoml.opt-level = \"s\"\n\n# Block explorers / verification.\nfoundry-block-explorers.opt-level = \"s\"\n\n# Misc CLI dependencies.\nclap_builder.opt-level = \"s\"\nclap_complete.opt-level = \"s\"\ncomfy-table.opt-level = \"s\"\nindicatif.opt-level = \"s\"\ndialoguer.opt-level = \"s\"\nratatui.opt-level = \"s\"\ncrossterm.opt-level = \"s\"\n\n# Alloy JSON (parsing, not hot path).\nalloy-json-abi.opt-level = \"s\"\n\n[workspace.dependencies]\nanvil = { path = \"crates/anvil\" }\ncast = { path = \"crates/cast\" }\nchisel = { path = \"crates/chisel\" }\nforge = { path = \"crates/forge\" }\n\nforge-doc = { path = \"crates/doc\" }\nforge-fmt = { path = \"crates/fmt\" }\nforge-lint = { path = \"crates/lint\" }\nforge-verify = { path = \"crates/verify\" }\nforge-script = { path = \"crates/script\" }\nforge-sol-macro-gen = { path = \"crates/sol-macro-gen\" }\nforge-script-sequence = { path = \"crates/script-sequence\" }\nfoundry-cheatcodes = { path = \"crates/cheatcodes\" }\nfoundry-cheatcodes-spec = { path = \"crates/cheatcodes/spec\" }\nfoundry-cli = { path = \"crates/cli\" }\nfoundry-cli-markdown = { path = \"crates/cli-markdown\" }\nfoundry-common = { path = \"crates/common\" }\nfoundry-common-fmt = { path = \"crates/common/fmt\" }\nfoundry-config = { path = \"crates/config\" }\nfoundry-debugger = { path = \"crates/debugger\" }\nfoundry-evm = { path = \"crates/evm/evm\" }\nfoundry-evm-abi = { path = \"crates/evm/abi\" }\nfoundry-evm-core = { path = \"crates/evm/core\" }\nfoundry-evm-coverage = { path = \"crates/evm/coverage\" }\nfoundry-evm-networks = { path = \"crates/evm/networks\" }\nfoundry-evm-fuzz = { path = \"crates/evm/fuzz\" }\nfoundry-evm-traces = { path = \"crates/evm/traces\" }\nfoundry-macros = { path = \"crates/macros\" }\nfoundry-test-utils = { path = \"crates/test-utils\" }\nfoundry-wallets = { path = \"crates/wallets\" }\nfoundry-linking = { path = \"crates/linking\" }\nfoundry-primitives = { path = \"crates/primitives\" }\n\n# solc & compilation utilities\nfoundry-block-explorers = { version = \"0.22.0\", default-features = false }\nfoundry-compilers = { version = \"0.19.14\", default-features = false, features = [\n    \"rustls\",\n    \"svm-solc\",\n] }\nfoundry-fork-db = \"0.23\"\nsolang-parser = { version = \"=0.3.9\", package = \"foundry-solang-parser\" }\nsolar = { package = \"solar-compiler\", version = \"=0.1.8\", default-features = false }\nsvm = { package = \"svm-rs\", version = \"0.5\", default-features = false, features = [\n    \"rustls\",\n] }\n\n## alloy\nalloy-consensus = { version = \"2.0.0-rc.0\", default-features = false }\nalloy-contract = { version = \"2.0.0-rc.0\", default-features = false }\nalloy-eips = { version = \"2.0.0-rc.0\", default-features = false }\nalloy-eip5792 = { version = \"2.0.0-rc.0\", default-features = false }\nalloy-ens = { version = \"2.0.0-rc.0\", default-features = false }\nalloy-genesis = { version = \"2.0.0-rc.0\", default-features = false }\nalloy-json-rpc = { version = \"2.0.0-rc.0\", default-features = false }\nalloy-network = { version = \"2.0.0-rc.0\", default-features = false }\nalloy-provider = { version = \"2.0.0-rc.0\", default-features = false }\nalloy-pubsub = { version = \"2.0.0-rc.0\", default-features = false }\nalloy-rpc-client = { version = \"2.0.0-rc.0\", default-features = false }\nalloy-rpc-types = { version = \"2.0.0-rc.0\", default-features = true }\nalloy-rpc-types-beacon = { version = \"2.0.0-rc.0\", default-features = true }\nalloy-rpc-types-eth = { version = \"2.0.0-rc.0\", default-features = false }\nalloy-serde = { version = \"2.0.0-rc.0\", default-features = false }\nalloy-signer = { version = \"2.0.0-rc.0\", default-features = false }\nalloy-signer-aws = { version = \"2.0.0-rc.0\", default-features = false }\nalloy-signer-gcp = { version = \"2.0.0-rc.0\", default-features = false }\nalloy-signer-ledger = { version = \"2.0.0-rc.0\", default-features = false }\nalloy-signer-local = { version = \"2.0.0-rc.0\", default-features = false }\nalloy-signer-trezor = { version = \"2.0.0-rc.0\", default-features = false }\nalloy-signer-turnkey = { version = \"2.0.0-rc.0\", default-features = false }\nalloy-transport = { version = \"2.0.0-rc.0\", default-features = false }\nalloy-transport-http = { version = \"2.0.0-rc.0\", default-features = false }\nalloy-transport-ipc = { version = \"2.0.0-rc.0\", default-features = false }\nalloy-transport-ws = { version = \"2.0.0-rc.0\", default-features = false }\nalloy-hardforks = { version = \"0.4.7\", default-features = false }\nalloy-op-hardforks = { version = \"0.4.7\", default-features = false }\n\n## alloy-core\nalloy-dyn-abi = \"1.5.2\"\nalloy-json-abi = \"1.5.2\"\nalloy-primitives = { version = \"1.5.2\", features = [\n    \"getrandom\",\n    \"rand\",\n    \"map-fxhash\",\n    \"map-foldhash\",\n] }\nalloy-sol-macro-expander = \"1.5.2\"\nalloy-sol-macro-input = \"1.5.2\"\nalloy-sol-types = \"1.5.2\"\n\nalloy-chains = \"0.2\"\nalloy-rlp = \"0.3\"\nalloy-trie = \"0.9\"\n\n## op-alloy\nop-alloy-consensus = \"0.24.0\"\nop-alloy-network = \"0.24.0\"\nop-alloy-rpc-types = \"0.24.0\"\nop-alloy-flz = \"0.13.1\"\n\n## alloy-evm\nalloy-evm = \"0.28.1\"\nalloy-op-evm = \"0.26.3\"\n\n# revm\nrevm = { version = \"34.0.0\", default-features = false }\nrevm-inspectors = { version = \"0.36.0\", features = [\"serde\"] }\nop-revm = { version = \"15.0.0\", default-features = false }\n\n## cli\nanstream = \"0.6\"\nanstyle = \"1.0\"\ndialoguer = { version = \"0.12\", default-features = false, features = [\n    \"password\",\n] }\nclap_complete = \"4\"\nclap_complete_nushell = \"4\"\n\n# macros\nproc-macro2 = \"1.0\"\nquote = \"1.0\"\nsyn = \"2.0\"\nasync-trait = \"0.1\"\nderive_more = { version = \"2.1\", features = [\"full\"] }\nthiserror = \"2\"\n\n# allocators\nmimalloc = \"0.1\"\ntikv-jemallocator = \"0.6\"\n\n# misc\nauto_impl = \"1\"\nbytes = \"1.11\"\nwalkdir = \"2\"\nprettyplease = \"0.2\"\nbase64 = \"0.22\"\nchrono = { version = \"0.4\", default-features = false, features = [\n    \"clock\",\n    \"std\",\n] }\naxum = \"0.8\"\nciborium = \"0.2\"\ncolor-eyre = \"0.6\"\ncomfy-table = \"7\"\ndirs = \"6\"\ndunce = \"1\"\nevm-disassembler = \"0.6\"\nevmole = \"0.8\"\neyre = \"0.6\"\nfigment = { package = \"figment2\", version = \"0.11\" }\nfutures = { version = \"0.3\", default-features = false }\nhyper = \"1.8\"\nindicatif = \"0.18\"\nitertools = \"0.14\"\njsonpath_lib = \"0.3\"\nk256 = \"0.13\"\nmesc = \"0.3\"\nmemchr = \"2.7\"\nnum-format = \"0.4\"\nparking_lot = \"0.12\"\nproptest = \"1.9.0\"\nrand = \"0.9\"\nrand_08 = { package = \"rand\", version = \"0.8\" }\nrayon = \"1\"\nregex = { version = \"1\", default-features = false }\nreqwest = { version = \"0.13\", default-features = false, features = [\"rustls\"] }\nrustls = \"0.23\"\nsemver = \"1\"\nserde = { version = \"1.0\", features = [\"derive\"] }\nserde_json = { version = \"1.0\", features = [\"arbitrary_precision\"] }\nsimilar-asserts = \"1.7\"\nsoldeer-commands = \"=0.10.0\"\nsoldeer-core = { version = \"=0.10.0\", features = [\"serde\"] }\nstrum = \"0.27\"\ntempfile = \"3.23\"\ntokio = \"1\"\ntoml = \"0.9\"\ntoml_edit = \"0.24\"\ntower = \"0.5\"\ntower-http = \"0.6\"\ntracing = \"0.1\"\ntracing-subscriber = \"0.3\"\nurl = \"2\"\nvergen = { package = \"vergen-gitcl\", version = \"10.0.0-beta.5\", default-features = false, features = [\n    \"build\",\n    \"cargo\",\n] }\nyansi = { version = \"1.0\", features = [\"detect-tty\", \"detect-env\"] }\npath-slash = \"0.2\"\njiff = { version = \"0.2\", default-features = false, features = [\n    \"std\",\n    \"perf-inline\",\n] }\nheck = \"0.5\"\nuuid = \"1.19.0\"\nflate2 = \"1.1\"\nethereum_ssz = \"0.10\"\n\n# Tempo\ntempo-primitives = { git = \"https://github.com/tempoxyz/tempo\", branch = \"alloy-2.0\", default-features = false, features = [\"serde\"] }\ntempo-alloy = { git = \"https://github.com/tempoxyz/tempo\", branch = \"alloy-2.0\", default-features = false }\n\n## Pinned dependencies. Enabled for the workspace in crates/test-utils.\n\n# testing\nsnapbox = { version = \"0.6\", features = [\"json\", \"regex\", \"term-svg\"] }\n\n# Use unicode-rs which has a smaller binary size than the default ICU4X as the IDNA backend, used\n# by the `url` crate.\n# See the `idna_adapter` README.md for more details: https://docs.rs/crate/idna_adapter/latest\nidna_adapter = \"=1.1.0\"\n\n[patch.crates-io]\n# https://github.com/rust-cli/rexpect/pull/106\nrexpect = { git = \"https://github.com/rust-cli/rexpect\", rev = \"2ed0b1898d7edaf6a85bedbae71a01cc578958fc\" }\n\n## alloy-core\n# alloy-dyn-abi = { path = \"../../alloy-rs/core/crates/dyn-abi\" }\n# alloy-json-abi = { path = \"../../alloy-rs/core/crates/json-abi\" }\n# alloy-primitives = { path = \"../../alloy-rs/core/crates/primitives\" }\n# alloy-sol-macro = { path = \"../../alloy-rs/core/crates/sol-macro\" }\n# alloy-sol-macro-expander = { path = \"../../alloy-rs/core/crates/sol-macro-expander\" }\n# alloy-sol-macro-input = { path = \"../../alloy-rs/core/crates/sol-macro-input\" }\n# alloy-sol-type-parser = { path = \"../../alloy-rs/core/crates/sol-type-parser\" }\n# alloy-sol-types = { path = \"../../alloy-rs/core/crates/sol-types\" }\n# syn-solidity = { path = \"../../alloy-rs/core/crates/syn-solidity\" }\n\n## alloy\nalloy-consensus = { git = \"https://github.com/alloy-rs/alloy\", rev = \"100a3325ac4d624f3eb0bd404125750e76edf8ca\" }\nalloy-contract = { git = \"https://github.com/alloy-rs/alloy\", rev = \"100a3325ac4d624f3eb0bd404125750e76edf8ca\" }\nalloy-eips = { git = \"https://github.com/alloy-rs/alloy\", rev = \"100a3325ac4d624f3eb0bd404125750e76edf8ca\" }\nalloy-eip5792 = { git = \"https://github.com/alloy-rs/alloy\", rev = \"100a3325ac4d624f3eb0bd404125750e76edf8ca\" }\nalloy-ens = { git = \"https://github.com/alloy-rs/alloy\", rev = \"100a3325ac4d624f3eb0bd404125750e76edf8ca\" }\nalloy-genesis = { git = \"https://github.com/alloy-rs/alloy\", rev = \"100a3325ac4d624f3eb0bd404125750e76edf8ca\" }\nalloy-json-rpc = { git = \"https://github.com/alloy-rs/alloy\", rev = \"100a3325ac4d624f3eb0bd404125750e76edf8ca\" }\nalloy-network = { git = \"https://github.com/alloy-rs/alloy\", rev = \"100a3325ac4d624f3eb0bd404125750e76edf8ca\" }\nalloy-network-primitives = { git = \"https://github.com/alloy-rs/alloy\", rev = \"100a3325ac4d624f3eb0bd404125750e76edf8ca\" }\nalloy-provider = { git = \"https://github.com/alloy-rs/alloy\", rev = \"100a3325ac4d624f3eb0bd404125750e76edf8ca\" }\nalloy-pubsub = { git = \"https://github.com/alloy-rs/alloy\", rev = \"100a3325ac4d624f3eb0bd404125750e76edf8ca\" }\nalloy-rpc-client = { git = \"https://github.com/alloy-rs/alloy\", rev = \"100a3325ac4d624f3eb0bd404125750e76edf8ca\" }\nalloy-rpc-types = { git = \"https://github.com/alloy-rs/alloy\", rev = \"100a3325ac4d624f3eb0bd404125750e76edf8ca\" }\nalloy-rpc-types-beacon = { git = \"https://github.com/alloy-rs/alloy\", rev = \"100a3325ac4d624f3eb0bd404125750e76edf8ca\" }\nalloy-rpc-types-eth = { git = \"https://github.com/alloy-rs/alloy\", rev = \"100a3325ac4d624f3eb0bd404125750e76edf8ca\" }\nalloy-rpc-types-trace = { git = \"https://github.com/alloy-rs/alloy\", rev = \"100a3325ac4d624f3eb0bd404125750e76edf8ca\" }\nalloy-rpc-types-engine = { git = \"https://github.com/alloy-rs/alloy\", rev = \"100a3325ac4d624f3eb0bd404125750e76edf8ca\" }\nalloy-serde = { git = \"https://github.com/alloy-rs/alloy\", rev = \"100a3325ac4d624f3eb0bd404125750e76edf8ca\" }\nalloy-signer = { git = \"https://github.com/alloy-rs/alloy\", rev = \"100a3325ac4d624f3eb0bd404125750e76edf8ca\" }\nalloy-signer-aws = { git = \"https://github.com/alloy-rs/alloy\", rev = \"100a3325ac4d624f3eb0bd404125750e76edf8ca\" }\nalloy-signer-gcp = { git = \"https://github.com/alloy-rs/alloy\", rev = \"100a3325ac4d624f3eb0bd404125750e76edf8ca\" }\nalloy-signer-ledger = { git = \"https://github.com/alloy-rs/alloy\", rev = \"100a3325ac4d624f3eb0bd404125750e76edf8ca\" }\nalloy-signer-local = { git = \"https://github.com/alloy-rs/alloy\", rev = \"100a3325ac4d624f3eb0bd404125750e76edf8ca\" }\nalloy-signer-trezor = { git = \"https://github.com/alloy-rs/alloy\", rev = \"100a3325ac4d624f3eb0bd404125750e76edf8ca\" }\nalloy-signer-turnkey = { git = \"https://github.com/alloy-rs/alloy\", rev = \"100a3325ac4d624f3eb0bd404125750e76edf8ca\" }\nalloy-transport = { git = \"https://github.com/alloy-rs/alloy\", rev = \"100a3325ac4d624f3eb0bd404125750e76edf8ca\" }\nalloy-transport-http = { git = \"https://github.com/alloy-rs/alloy\", rev = \"100a3325ac4d624f3eb0bd404125750e76edf8ca\" }\nalloy-transport-ipc = { git = \"https://github.com/alloy-rs/alloy\", rev = \"100a3325ac4d624f3eb0bd404125750e76edf8ca\" }\nalloy-transport-ws = { git = \"https://github.com/alloy-rs/alloy\", rev = \"100a3325ac4d624f3eb0bd404125750e76edf8ca\" }\n\n## alloy-evm\nalloy-evm = { git = \"https://github.com/alloy-rs/evm.git\", branch = \"alloy-2.0\" }\n\n## op-alloy / alloy-op-evm\nop-alloy-consensus = { git = \"https://github.com/foundry-rs/optimism\", branch = \"alloy-2.0\" }\nop-alloy-network = { git = \"https://github.com/foundry-rs/optimism\", branch = \"alloy-2.0\" }\nop-alloy-rpc-types = { git = \"https://github.com/foundry-rs/optimism\", branch = \"alloy-2.0\" }\nop-alloy = { git = \"https://github.com/foundry-rs/optimism\", branch = \"alloy-2.0\" }\nalloy-op-evm = { git = \"https://github.com/foundry-rs/optimism\", branch = \"alloy-2.0\" }\nalloy-op-hardforks = { git = \"https://github.com/foundry-rs/optimism\", branch = \"alloy-2.0\" }\n\n## revm\n# revm = { git = \"https://github.com/bluealloy/revm.git\", rev = \"7e59936\" }\n# op-revm = { git = \"https://github.com/bluealloy/revm.git\", rev = \"7e59936\" }\nrevm-inspectors = { git = \"https://github.com/paradigmxyz/revm-inspectors.git\", branch = \"alloy-2.0\" }\n\n## foundry\nfoundry-fork-db = { git = \"https://github.com/foundry-rs/foundry-fork-db\", branch = \"alloy-2.0\" }\n\n# solar\nsolar = { package = \"solar-compiler\", git = \"https://github.com/paradigmxyz/solar\", rev = \"530f129\" }\nsolar-interface = { package = \"solar-interface\", git = \"https://github.com/paradigmxyz/solar\", rev = \"530f129\" }\nsolar-ast = { package = \"solar-ast\", git = \"https://github.com/paradigmxyz/solar\", rev = \"530f129\" }\nsolar-sema = { package = \"solar-sema\", git = \"https://github.com/paradigmxyz/solar\", rev = \"530f129\" }"
  },
  {
    "path": "Dockerfile",
    "content": "# syntax=docker/dockerfile:1\n\nFROM rust:1-bookworm AS chef\nWORKDIR /app\n\nRUN apt update && apt install -y build-essential libssl-dev git pkg-config curl perl\nRUN curl -L --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install-from-binstall-release.sh | sh\nRUN cargo binstall cargo-chef sccache\n\n# Prepare the cargo-chef recipe.\nFROM chef AS planner\nCOPY . .\nRUN cargo chef prepare --recipe-path recipe.json\n\n# Build the project.\nFROM chef AS builder\nCOPY --from=planner /app/recipe.json recipe.json\n\nARG RUST_PROFILE\nARG RUST_FEATURES\n\nENV CARGO_INCREMENTAL=0 \\\n    RUSTC_WRAPPER=sccache \\\n    SCCACHE_DIR=/sccache\n\n# Build dependencies.\nRUN --mount=type=cache,target=/usr/local/cargo/registry,sharing=shared \\\n    --mount=type=cache,target=/usr/local/cargo/git,sharing=shared \\\n    --mount=type=cache,target=$SCCACHE_DIR,sharing=shared \\\n    cargo chef cook --recipe-path recipe.json --profile ${RUST_PROFILE} --no-default-features --features \"${RUST_FEATURES}\"\n\nARG TAG_NAME=\"dev\"\nENV TAG_NAME=$TAG_NAME\nARG VERGEN_GIT_SHA=\"ffffffffffffffffffffffffffffffffffffffff\"\nENV VERGEN_GIT_SHA=$VERGEN_GIT_SHA\n\n# Build the project.\nCOPY . .\nRUN --mount=type=cache,target=/usr/local/cargo/registry,sharing=shared \\\n    --mount=type=cache,target=/usr/local/cargo/git,sharing=shared \\\n    --mount=type=cache,target=$SCCACHE_DIR,sharing=shared \\\n    cargo build --profile ${RUST_PROFILE} --no-default-features --features \"${RUST_FEATURES}\" \\\n    && sccache --show-stats || true\n\n# `dev` profile outputs to the `target/debug` directory.\nRUN ln -s /app/target/debug /app/target/dev \\\n    && mkdir -p /app/output \\\n    && mv \\\n    /app/target/${RUST_PROFILE}/forge \\\n    /app/target/${RUST_PROFILE}/cast \\\n    /app/target/${RUST_PROFILE}/anvil \\\n    /app/target/${RUST_PROFILE}/chisel \\\n    /app/output/\n\nFROM ubuntu:22.04 AS runtime\n\n# Install runtime dependencies.\nRUN apt update && apt install -y git\n\nCOPY --from=builder /app/output/* /usr/local/bin/\n\nRUN groupadd -g 1000 foundry && \\\n    useradd -m -u 1000 -g foundry foundry\nUSER foundry\n\nENTRYPOINT [\"/bin/sh\", \"-c\"]\n\nLABEL org.label-schema.build-date=$BUILD_DATE \\\n      org.label-schema.name=\"Foundry\" \\\n      org.label-schema.description=\"Foundry\" \\\n      org.label-schema.url=\"https://getfoundry.sh\" \\\n      org.label-schema.vcs-ref=$VCS_REF \\\n      org.label-schema.vcs-url=\"https://github.com/foundry-rs/foundry.git\" \\\n      org.label-schema.vendor=\"Foundry-rs\" \\\n      org.label-schema.version=$VERSION \\\n      org.label-schema.schema-version=\"1.0\"\n"
  },
  {
    "path": "FUNDING.json",
    "content": "{\n  \"drips\": {\n    \"ethereum\": {\n      \"ownedBy\": \"0x86308c59a6005d012C51Eef104bBc21786aC5D2E\"\n    }\n  },\n  \"opRetro\": {\n    \"projectId\": \"0x4562c0630907577f433cad78c7e2cc03349d918b6c14ef982f11a2678f5999ad\"\n  }\n}\n"
  },
  {
    "path": "LICENSE-APACHE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives."
  },
  {
    "path": "LICENSE-MIT",
    "content": "Copyright (c) 2021 Georgios Konstantopoulos\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE."
  },
  {
    "path": "Makefile",
    "content": "# Heavily inspired by:\n# - Lighthouse: https://github.com/sigp/lighthouse/blob/693886b94176faa4cb450f024696cb69cda2fe58/Makefile\n# - Reth: https://github.com/paradigmxyz/reth/blob/1f642353ca083b374851ab355b5d80207b36445c/Makefile\n.DEFAULT_GOAL := help\n\n# Cargo profile for builds.\nPROFILE ?= dev\n\n# The docker image name\nDOCKER_IMAGE_NAME ?= ghcr.io/foundry-rs/foundry:latest\n\nBIN_DIR = dist/bin\nCARGO_TARGET_DIR ?= target\n\n# List of features to use when building. Can be overridden via the environment.\n# No jemalloc on Windows\nifeq ($(OS),Windows_NT)\n    FEATURES ?= aws-kms gcp-kms turnkey cli asm-keccak\nelse\n    FEATURES ?= jemalloc aws-kms gcp-kms turnkey cli asm-keccak\nendif\n\n##@ Help\n\n.PHONY: help\nhelp: ## Display this help.\n\t@awk 'BEGIN {FS = \":.*##\"; printf \"Usage:\\n  make \\033[36m<target>\\033[0m\\n\"} /^[a-zA-Z_0-9-]+:.*?##/ { printf \"  \\033[36m%-20s\\033[0m %s\\n\", $$1, $$2 } /^##@/ { printf \"\\n\\033[1m%s\\033[0m\\n\", substr($$0, 5) } ' $(MAKEFILE_LIST)\n\n##@ Build\n\n.PHONY: build\nbuild: ## Build the project.\n\tcargo build --features \"$(FEATURES)\" --profile \"$(PROFILE)\"\n\n.PHONY: build-docker\nbuild-docker: ## Build the docker image.\n\tdocker build . -t \"$(DOCKER_IMAGE_NAME)\" \\\n\t--build-arg \"RUST_PROFILE=$(PROFILE)\" \\\n\t--build-arg \"RUST_FEATURES=$(FEATURES)\" \\\n\t--build-arg \"TAG_NAME=dev\" \\\n\t--build-arg \"VERGEN_GIT_SHA=$(shell git rev-parse HEAD)\"\n\n##@ Test\n\n## Run unit/doc tests and generate html coverage report in `target/llvm-cov/html` folder.\n## Notice that `llvm-cov` supports doc tests only in nightly builds because the `--doc` flag\n## is unstable (https://github.com/taiki-e/cargo-llvm-cov/issues/2).\n.PHONY: test-coverage\ntest-coverage:\n\tcargo +nightly llvm-cov --no-report nextest -E 'kind(test) & !test(/\\b(issue|ext_integration|flaky_)/)' && \\\n\tcargo +nightly llvm-cov --no-report --doc && \\\n\tcargo +nightly llvm-cov report --doctests --open\n\n.PHONY: test-unit\ntest-unit: ## Run unit tests.\n\tcargo nextest run -E 'kind(test) & !test(/\\b(issue|ext_integration|flaky_)/)'\n\n.PHONY: test-doc\ntest-doc: ## Run doc tests.\n\tcargo test --doc --workspace\n\n.PHONY: test\ntest: ## Run all tests.\n\t$(MAKE) test-unit && \\\n\t$(MAKE) test-doc\n\n##@ Linting\n\n.PHONY: fmt\nfmt: ## Run all formatters.\n\tcargo +nightly fmt\n\t./.github/scripts/format.sh --check\n\n.PHONY: lint-clippy\nlint-clippy: ## Run clippy on the codebase.\n\tcargo +nightly clippy \\\n\t--workspace \\\n\t--all-targets \\\n\t--all-features \\\n\t-- -D warnings\n\n.PHONY: lint-clippy-fix\nlint-clippy-fix: ## Run clippy on the codebase and fix warnings.\n\tcargo +nightly clippy \\\n\t--workspace \\\n\t--all-targets \\\n\t--all-features \\\n\t--fix \\\n\t--allow-dirty \\\n\t--allow-staged \\\n\t-- -D warnings\n\n.PHONY: lint-typos\nlint-typos: ## Run typos on the codebase.\n\t@command -v typos >/dev/null || { \\\n\t\techo \"typos not found. Please install it by running the command `cargo install typos-cli` or refer to the following link for more information: https://github.com/crate-ci/typos\"; \\\n\t\texit 1; \\\n\t}\n\ttypos\n\n.PHONY: lint\nlint: ## Run all linters.\n\t$(MAKE) fmt && \\\n\t$(MAKE) lint-clippy && \\\n\t$(MAKE) lint-typos\n\n##@ Other\n\n.PHONY: clean\nclean: ## Clean the project.\n\tcargo clean\n\n.PHONY: deny\ndeny: ## Perform a `cargo` deny check.\n\tcargo deny --all-features check all\n\n.PHONY: pr\npr: ## Run all checks and tests.\n\t$(MAKE) deny && \\\n\t$(MAKE) lint && \\\n\t$(MAKE) test\n\n# dprint formatting commands\n.PHONY: dprint-fmt\ndprint-fmt: ## Format code with dprint\n\t@if ! command -v dprint > /dev/null; then \\\n\t\techo \"Installing dprint...\"; \\\n\t\tcargo install dprint; \\\n\tfi\n\tdprint fmt\n\n.PHONY: dprint-check\ndprint-check: ## Check formatting with dprint\n\t@if ! command -v dprint > /dev/null; then \\\n\t\techo \"Installing dprint...\"; \\\n\t\tcargo install dprint; \\\n\tfi\n\tdprint check\n"
  },
  {
    "path": "README.md",
    "content": "<div align=\"center\">\n  <img src=\".github/assets/banner.png\" alt=\"Foundry banner\" />\n\n&nbsp;\n\n[![Github Actions][gha-badge]][gha-url] [![Telegram Chat][tg-badge]][tg-url] [![Telegram Support][tg-support-badge]][tg-support-url]\n\n[gha-badge]: https://img.shields.io/github/actions/workflow/status/foundry-rs/foundry/test.yml?branch=master&style=flat-square\n[gha-url]: https://github.com/foundry-rs/foundry/actions\n[tg-badge]: https://img.shields.io/endpoint?color=neon&logo=telegram&label=chat&style=flat-square&url=https%3A%2F%2Ftg.sumanjay.workers.dev%2Ffoundry_rs\n[tg-url]: https://t.me/foundry_rs\n[tg-support-badge]: https://img.shields.io/endpoint?color=neon&logo=telegram&label=support&style=flat-square&url=https%3A%2F%2Ftg.sumanjay.workers.dev%2Ffoundry_support\n[tg-support-url]: https://t.me/foundry_support\n\n**[Install](https://getfoundry.sh/getting-started/installation)**\n| [Docs][foundry-docs]\n| [Benchmarks](https://www.getfoundry.sh/benchmarks)\n| [Developer Guidelines](./docs/dev/README.md)\n| [Contributing](./CONTRIBUTING.md)\n| [Crate Docs](https://foundry-rs.github.io/foundry)\n\n</div>\n\n---\n\nBlazing fast, portable and modular toolkit for Ethereum application development, written in Rust.\n\n- [**Forge**](https://getfoundry.sh/forge) — Build, test, fuzz, debug and deploy Solidity contracts.\n- [**Cast**](https://getfoundry.sh/cast) — Swiss Army knife for interacting with EVM smart contracts, sending transactions and getting chain data.\n- [**Anvil**](https://getfoundry.sh/anvil) — Fast local Ethereum development node.\n- [**Chisel**](https://getfoundry.sh/chisel) — Fast, utilitarian and verbose Solidity REPL.\n\n![Demo](.github/assets/demo.gif)\n\n## Installation\n\n```sh\ncurl -L https://foundry.paradigm.xyz | bash\nfoundryup\n```\n\nSee the [installation guide](https://getfoundry.sh/getting-started/installation) for more details.\n\n## Getting Started\n\nInitialize a new project, build and test:\n\n```sh\nforge init counter && cd counter\nforge build\nforge test\n```\n\nInteract with a live network:\n\n```sh\ncast block-number --rpc-url https://eth.merkle.io\ncast balance vitalik.eth --ether --rpc-url https://eth.merkle.io\n```\n\nFork mainnet locally:\n\n```sh\nanvil --fork-url https://eth.merkle.io\n```\n\nRead the [Foundry Docs][foundry-docs] to learn more.\n\n## Contributing\n\nContributions are welcome and highly appreciated. To get started, check out the [contributing guidelines](./CONTRIBUTING.md).\n\nJoin our [Telegram][tg-url] to chat about the development of Foundry.\n\n## Support\n\nHaving trouble? Check the [Foundry Docs][foundry-docs], join the [support Telegram][tg-support-url], or [open an issue](https://github.com/foundry-rs/foundry/issues/new).\n\n#### License\n\n<sup>\nLicensed under either of <a href=\"LICENSE-APACHE\">Apache License, Version\n2.0</a> or <a href=\"LICENSE-MIT\">MIT license</a> at your option.\n</sup>\n\n<br>\n\n<sub>\nUnless you explicitly state otherwise, any contribution intentionally submitted\nfor inclusion in these crates by you, as defined in the Apache-2.0 license,\nshall be dual licensed as above, without any additional terms or conditions.\n</sub>\n\n[foundry-docs]: https://getfoundry.sh\n"
  },
  {
    "path": "SECURITY.md",
    "content": "# Security Policy\n\n## Reporting a Vulnerability\n\nContact [security@ithaca.xyz](mailto:security@ithaca.xyz).\n"
  },
  {
    "path": "benches/Cargo.toml",
    "content": "[package]\nname = \"foundry-bench\"\ndescription = \"Foundry benchmark runner\"\n\nversion.workspace = true\nedition.workspace = true\nrust-version.workspace = true\nauthors.workspace = true\nlicense.workspace = true\nhomepage.workspace = true\nrepository.workspace = true\n\n[lints]\nworkspace = true\n\n[[bin]]\nname = \"foundry-bench\"\npath = \"src/main.rs\"\n\n[dependencies]\nfoundry-test-utils.workspace = true\nfoundry-common.workspace = true\nfoundry-compilers = { workspace = true, features = [\"project-util\"] }\neyre.workspace = true\ncolor-eyre.workspace = true\nserde.workspace = true\nserde_json.workspace = true\nchrono = { version = \"0.4\", features = [\"serde\"] }\nrayon.workspace = true\nclap = { version = \"4\", features = [\"derive\"] }\nonce_cell = \"1.21\"\n"
  },
  {
    "path": "benches/LATEST.md",
    "content": "# Foundry Benchmark Results\n\n**Date**: 2025-10-02 12:14:23\n\n## Repositories Tested\n\n1. [ithacaxyz/account](https://github.com/ithacaxyz/account)\n2. [Vectorized/solady](https://github.com/Vectorized/solady)\n3. [Uniswap/v4-core](https://github.com/Uniswap/v4-core)\n4. [sparkdotfi/spark-psm](https://github.com/sparkdotfi/spark-psm)\n\n## Foundry Versions\n\n- **v1.3.6**: forge Version: 1.3.6-v1.3.6 (d241588 2025-09-16)\n- **v1.4.0-rc1**: forge Version: 1.4.0-v1.4.0-rc1 (bd0e4a7 2025-10-01)\n\n## Forge Test\n\n| Repository           | v1.3.6  | v1.4.0-rc1 |\n| -------------------- | ------- | ---------- |\n| ithacaxyz-account    | 3.17 s  | 2.94 s     |\n| solady               | 2.28 s  | 2.10 s     |\n| Uniswap-v4-core      | 7.27 s  | 6.13 s     |\n| sparkdotfi-spark-psm | 43.04 s | 44.08 s    |\n\n## Forge Fuzz Test\n\n| Repository           | v1.3.6 | v1.4.0-rc1 |\n| -------------------- | ------ | ---------- |\n| ithacaxyz-account    | 3.18 s | 3.02 s     |\n| solady               | 2.39 s | 2.24 s     |\n| Uniswap-v4-core      | 6.84 s | 6.20 s     |\n| sparkdotfi-spark-psm | 3.07 s | 2.72 s     |\n\n## Forge Test (Isolated)\n\n| Repository           | v1.3.6  | v1.4.0-rc1 |\n| -------------------- | ------- | ---------- |\n| solady               | 2.26 s  | 2.41 s     |\n| Uniswap-v4-core      | 7.22 s  | 7.71 s     |\n| sparkdotfi-spark-psm | 45.53 s | 50.49 s    |\n\n## Forge Build (No Cache)\n\n| Repository           | v1.3.6  | v1.4.0-rc1 |\n| -------------------- | ------- | ---------- |\n| ithacaxyz-account    | 9.16 s  | 9.08 s     |\n| solady               | 14.62 s | 14.69 s    |\n| Uniswap-v4-core      | 2m 3.8s | 2m 5.3s    |\n| sparkdotfi-spark-psm | 13.17 s | 13.14 s    |\n\n## Forge Build (With Cache)\n\n| Repository           | v1.3.6  | v1.4.0-rc1 |\n| -------------------- | ------- | ---------- |\n| ithacaxyz-account    | 0.156 s | 0.113 s    |\n| solady               | 0.089 s | 0.094 s    |\n| Uniswap-v4-core      | 0.133 s | 0.127 s    |\n| sparkdotfi-spark-psm | 0.173 s | 0.131 s    |\n\n## Forge Coverage\n\n| Repository           | v1.3.6   | v1.4.0-rc1 |\n| -------------------- | -------- | ---------- |\n| ithacaxyz-account    | 14.91 s  | 13.34 s    |\n| Uniswap-v4-core      | 1m 34.8s | 1m 30.3s   |\n| sparkdotfi-spark-psm | 3m 49.3s | 3m 40.2s   |\n\n## System Information\n\n- **OS**: macos\n- **CPU**: 8\n- **Rustc**: rustc 1.90.0-nightly (3014e79f9 2025-07-15)\n"
  },
  {
    "path": "benches/README.md",
    "content": "# Foundry Benchmarks\n\nThis directory contains performance benchmarks for Foundry commands across multiple repositories and Foundry versions.\n\n## Prerequisites\n\nBefore running the benchmarks, ensure you have the following installed:\n\n1. **Rust and Cargo** - Required for building the benchmark binary\n\n   ```bash\n   curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh\n   ```\n\n2. **Foundryup** - The Foundry toolchain installer\n\n   ```bash\n   curl -L https://foundry.paradigm.xyz | bash\n   foundryup\n   ```\n\n3. **Git** - For cloning benchmark repositories\n\n4. [**Hyperfine**](https://github.com/sharkdp/hyperfine/blob/master/README.md) - The benchmarking tool used by foundry-bench\n\n5. **Node.js and npm** - Some repositories require npm dependencies\n\n## Running Benchmarks\n\nBuild and install the benchmark runner:\n\n```bash\ncargo build --release --bin foundry-bench\n```\n\nTo install `foundry-bench` to your PATH:\n\n```bash\ncd benches && cargo install --path . --bin foundry-bench\n```\n\n#### Run with default settings\n\n```bash\n# Run all benchmarks on default repos with stable and nightly versions\nfoundry-bench --versions stable,nightly\n```\n\n#### Run with custom configurations\n\n```bash\n# Bench specific versions\nfoundry-bench --versions stable,nightly,v1.0.0\n\n# Run on specific repositories. Default rev for the repo is \"main\"\nfoundry-bench --repos ithacaxyz/account,Vectorized/solady\n\n# Test specific repository with custom revision\nfoundry-bench --repos ithacaxyz/account:main,Vectorized/solady:v0.0.123\n\n# Run only specific benchmarks\nfoundry-bench --benchmarks forge_build_with_cache,forge_test\n\n# Run only fuzz tests\nfoundry-bench --benchmarks forge_fuzz_test\n\n# Run coverage benchmark\nfoundry-bench --benchmarks forge_coverage\n\n# Combine options\nfoundry-bench \\\n  --versions stable,nightly \\\n  --repos ithacaxyz/account \\\n  --benchmarks forge_build_with_cache\n\n# Force install Foundry versions\nfoundry-bench --force-install\n\n# Verbose output to see hyperfine logs\nfoundry-bench --verbose\n\n# Output to specific directory\nfoundry-bench --output-dir ./results --output-file LATEST_RESULTS.md\n```\n\n#### Command-line Options\n\n- `--versions <VERSIONS>` - Comma-separated list of Foundry versions (default: stable,nightly)\n- `--repos <REPOS>` - Comma-separated list of repos in org/repo[:rev] format (default: ithacaxyz/account:v0.3.2,Vectorized/solady:v0.1.22)\n- `--benchmarks <BENCHMARKS>` - Comma-separated list of benchmarks to run\n- `--force-install` - Force installation of Foundry versions\n- `--verbose` - Show detailed benchmark output\n- `--output-dir <DIR>` - Directory for output files (default: benches)\n- `--output-file <FILE_NAME.md>` - Name of the output file (default: LATEST.md)\n\n## Benchmark Structure\n\n- `forge_test` - Benchmarks `forge test` command across repos\n- `forge_build_no_cache` - Benchmarks `forge build` with clean cache\n- `forge_build_with_cache` - Benchmarks `forge build` with existing cache\n- `forge_fuzz_test` - Benchmarks `forge test` with only fuzz tests (tests with parameters)\n- `forge_coverage` - Benchmarks `forge coverage --ir-minimum` command across repos\n\n## Configuration\n\nThe benchmark binary uses command-line arguments to configure which repositories and versions to test. The default repositories are:\n\n- `ithacaxyz/account:v0.3.2`\n- `Vectorized/solady:v0.1.22`\n\nYou can override these using the `--repos` flag with the format `org/repo[:rev]`.\n\n## Results\n\nBenchmark results are saved to `benches/LATEST.md` (or custom output file specified with `--output-file`). The report includes:\n\n- Summary of versions and repositories tested\n- Performance comparison tables for each benchmark type showing:\n  - Mean execution time\n  - Min/Max times\n  - Standard deviation\n  - Relative performance comparison between versions\n- System information (OS, CPU cores)\n- Detailed hyperfine benchmark results in JSON format\n\n## Troubleshooting\n\n1. **Foundry version not found**: Use `--force-install` flag or manually install with `foundryup --install <version>`\n2. **Repository clone fails**: Check network connectivity and repository access\n3. **Build failures**: Some repositories may have specific dependencies - check their README files\n4. **Hyperfine not found**: Install hyperfine using the instructions in Prerequisites\n5. **npm/Node.js errors**: Ensure Node.js and npm are installed for repositories that require them\n"
  },
  {
    "path": "benches/src/lib.rs",
    "content": "//! Foundry benchmark runner.\n\nuse crate::results::{HyperfineOutput, HyperfineResult};\nuse eyre::{Result, WrapErr};\nuse foundry_common::{sh_eprintln, sh_println};\nuse foundry_compilers::project_util::TempProject;\nuse foundry_test_utils::util::clone_remote;\nuse once_cell::sync::Lazy;\nuse std::{\n    path::{Path, PathBuf},\n    process::Command,\n    str::FromStr,\n};\n\npub mod results;\n\n/// Default number of runs for benchmarks\npub const RUNS: u32 = 5;\n\n/// Configuration for repositories to benchmark\n#[derive(Debug, Clone)]\npub struct RepoConfig {\n    pub name: String,\n    pub org: String,\n    pub repo: String,\n    pub rev: String,\n}\n\nimpl FromStr for RepoConfig {\n    type Err = eyre::Error;\n\n    fn from_str(spec: &str) -> Result<Self> {\n        // Split by ':' first to separate repo path from optional rev\n        let parts: Vec<&str> = spec.splitn(2, ':').collect();\n        let repo_path = parts[0];\n        let custom_rev = parts.get(1).copied();\n\n        // Now split the repo path by '/'\n        let path_parts: Vec<&str> = repo_path.split('/').collect();\n        if path_parts.len() != 2 {\n            eyre::bail!(\"Invalid repo format '{}'. Expected 'org/repo' or 'org/repo:rev'\", spec);\n        }\n\n        let org = path_parts[0];\n        let repo = path_parts[1];\n\n        // Try to find this repo in BENCHMARK_REPOS to get the full config\n        let existing_config = BENCHMARK_REPOS.iter().find(|r| r.org == org && r.repo == repo);\n\n        let config = if let Some(existing) = existing_config {\n            // Use existing config but allow custom rev to override\n            let mut config = existing.clone();\n            if let Some(rev) = custom_rev {\n                config.rev = rev.to_string();\n            }\n            config\n        } else {\n            // Create new config with custom rev or default\n            // Name should follow the format: org-repo (with hyphen)\n            Self {\n                name: format!(\"{org}-{repo}\"),\n                org: org.to_string(),\n                repo: repo.to_string(),\n                rev: custom_rev.unwrap_or(\"main\").to_string(),\n            }\n        };\n\n        let _ = sh_println!(\"Parsed repo spec '{spec}' -> {config:?}\");\n        Ok(config)\n    }\n}\n\n/// Available repositories for benchmarking\npub fn default_benchmark_repos() -> Vec<RepoConfig> {\n    vec![\n        RepoConfig {\n            name: \"ithacaxyz-account\".to_string(),\n            org: \"ithacaxyz\".to_string(),\n            repo: \"account\".to_string(),\n            rev: \"main\".to_string(),\n        },\n        RepoConfig {\n            name: \"solady\".to_string(),\n            org: \"Vectorized\".to_string(),\n            repo: \"solady\".to_string(),\n            rev: \"main\".to_string(),\n        },\n    ]\n}\n\n// Keep a lazy static for compatibility\npub static BENCHMARK_REPOS: Lazy<Vec<RepoConfig>> = Lazy::new(default_benchmark_repos);\n\n/// Foundry versions to benchmark\n///\n/// To add more versions for comparison, install them first:\n/// ```bash\n/// foundryup --install stable\n/// foundryup --install nightly\n/// foundryup --install v0.2.0  # Example specific version\n/// ```\n///\n/// Then add the version strings to this array. Supported formats:\n/// - \"stable\" - Latest stable release\n/// - \"nightly\" - Latest nightly build\n/// - \"v0.2.0\" - Specific version tag\n/// - \"commit-hash\" - Specific commit hash\n/// - \"nightly-rev\" - Nightly build with specific revision\npub static FOUNDRY_VERSIONS: &[&str] = &[\"stable\", \"nightly\"];\n\n/// A benchmark project that represents a cloned repository ready for testing\npub struct BenchmarkProject {\n    pub name: String,\n    pub temp_project: TempProject,\n    pub root_path: PathBuf,\n}\n\nimpl BenchmarkProject {\n    /// Set up a benchmark project by cloning the repository\n    #[allow(unused_must_use)]\n    pub fn setup(config: &RepoConfig) -> Result<Self> {\n        let temp_project =\n            TempProject::dapptools().wrap_err(\"Failed to create temporary project\")?;\n\n        // Get root path before clearing\n        let root_path = temp_project.root().to_path_buf();\n        let root = root_path.to_str().unwrap();\n\n        // Remove all files in the directory\n        for entry in std::fs::read_dir(&root_path)? {\n            let entry = entry?;\n            let path = entry.path();\n            if path.is_dir() {\n                std::fs::remove_dir_all(&path).ok();\n            } else {\n                std::fs::remove_file(&path).ok();\n            }\n        }\n\n        // Clone the repository\n        let repo_url = format!(\"https://github.com/{}/{}.git\", config.org, config.repo);\n        clone_remote(&repo_url, root, true);\n\n        // Checkout specific revision if provided\n        if !config.rev.is_empty() && config.rev != \"main\" && config.rev != \"master\" {\n            let status = Command::new(\"git\")\n                .current_dir(root)\n                .args([\"checkout\", &config.rev])\n                .status()\n                .wrap_err(\"Failed to checkout revision\")?;\n\n            if !status.success() {\n                eyre::bail!(\"Git checkout failed for {}\", config.name);\n            }\n        }\n\n        // Git submodules are already cloned via --recursive flag\n        // But npm dependencies still need to be installed\n        Self::install_npm_dependencies(&root_path)?;\n\n        sh_println!(\"  ✅ Project {} setup complete at {}\", config.name, root);\n        Ok(Self { name: config.name.to_string(), root_path, temp_project })\n    }\n\n    /// Install npm dependencies if package.json exists\n    #[allow(unused_must_use)]\n    fn install_npm_dependencies(root: &Path) -> Result<()> {\n        if root.join(\"package.json\").exists() {\n            sh_println!(\"  📦 Running npm install...\");\n            let status = Command::new(\"npm\")\n                .current_dir(root)\n                .args([\"install\"])\n                .stdout(std::process::Stdio::inherit())\n                .stderr(std::process::Stdio::inherit())\n                .status()\n                .wrap_err(\"Failed to run npm install\")?;\n\n            if !status.success() {\n                sh_println!(\n                    \"  ⚠️  Warning: npm install failed with exit code: {:?}\",\n                    status.code()\n                );\n            } else {\n                sh_println!(\"  ✅ npm install completed successfully\");\n            }\n        }\n        Ok(())\n    }\n\n    /// Run a command with hyperfine and return the results\n    ///\n    /// # Arguments\n    /// * `benchmark_name` - Name of the benchmark for organizing output\n    /// * `version` - Foundry version being benchmarked\n    /// * `command` - The command to benchmark\n    /// * `runs` - Number of runs to perform\n    /// * `setup` - Optional setup command to run before the benchmark series (e.g., \"forge build\")\n    /// * `prepare` - Optional prepare command to run before each timing run (e.g., \"forge clean\")\n    /// * `conclude` - Optional conclude command to run after each timing run (e.g., cleanup)\n    /// * `verbose` - Whether to show command output\n    ///\n    /// # Hyperfine flags used:\n    /// * `--runs` - Number of timing runs\n    /// * `--setup` - Execute before the benchmark series (not before each run)\n    /// * `--prepare` - Execute before each timing run\n    /// * `--conclude` - Execute after each timing run\n    /// * `--export-json` - Export results to JSON for parsing\n    /// * `--shell=bash` - Use bash for shell command execution\n    /// * `--show-output` - Show command output (when verbose)\n    #[allow(clippy::too_many_arguments)]\n    fn hyperfine(\n        &self,\n        benchmark_name: &str,\n        version: &str,\n        command: &str,\n        runs: u32,\n        setup: Option<&str>,\n        prepare: Option<&str>,\n        conclude: Option<&str>,\n        verbose: bool,\n    ) -> Result<HyperfineResult> {\n        // Create structured temp directory for JSON output\n        // Format: <temp_dir>/<benchmark_name>/<version>/<repo_name>/<benchmark_name>.json\n        let temp_dir = std::env::temp_dir();\n        let json_dir =\n            temp_dir.join(\"foundry-bench\").join(benchmark_name).join(version).join(&self.name);\n        std::fs::create_dir_all(&json_dir)?;\n\n        let json_path = json_dir.join(format!(\"{benchmark_name}.json\"));\n\n        // Build hyperfine command\n        let mut hyperfine_cmd = Command::new(\"hyperfine\");\n        hyperfine_cmd\n            .current_dir(&self.root_path)\n            .arg(\"--runs\")\n            .arg(runs.to_string())\n            .arg(\"--export-json\")\n            .arg(&json_path)\n            .arg(\"--shell=bash\");\n\n        // Add optional setup command\n        if let Some(setup_cmd) = setup {\n            hyperfine_cmd.arg(\"--setup\").arg(setup_cmd);\n        }\n\n        // Add optional prepare command\n        if let Some(prepare_cmd) = prepare {\n            hyperfine_cmd.arg(\"--prepare\").arg(prepare_cmd);\n        }\n\n        // Add optional conclude command\n        if let Some(conclude_cmd) = conclude {\n            hyperfine_cmd.arg(\"--conclude\").arg(conclude_cmd);\n        }\n\n        if verbose {\n            hyperfine_cmd.arg(\"--show-output\");\n            hyperfine_cmd.stderr(std::process::Stdio::inherit());\n            hyperfine_cmd.stdout(std::process::Stdio::inherit());\n        }\n\n        // Add the benchmark command last\n        hyperfine_cmd.arg(command);\n\n        let status = hyperfine_cmd.status().wrap_err(\"Failed to run hyperfine\")?;\n        if !status.success() {\n            eyre::bail!(\"Hyperfine failed for command: {}\", command);\n        }\n\n        // Read and parse the JSON output\n        let json_content = std::fs::read_to_string(json_path)?;\n        let output: HyperfineOutput = serde_json::from_str(&json_content)?;\n\n        // Extract the first result (we only run one command at a time)\n        output.results.into_iter().next().ok_or_else(|| eyre::eyre!(\"No results from hyperfine\"))\n    }\n\n    /// Benchmark forge test\n    pub fn bench_forge_test(\n        &self,\n        version: &str,\n        runs: u32,\n        verbose: bool,\n    ) -> Result<HyperfineResult> {\n        // Build before running tests\n        self.hyperfine(\n            \"forge_test\",\n            version,\n            \"forge test\",\n            runs,\n            Some(\"forge build\"),\n            None,\n            None,\n            verbose,\n        )\n    }\n\n    /// Benchmark forge build with cache\n    pub fn bench_forge_build_with_cache(\n        &self,\n        version: &str,\n        runs: u32,\n        verbose: bool,\n    ) -> Result<HyperfineResult> {\n        self.hyperfine(\n            \"forge_build_with_cache\",\n            version,\n            \"FOUNDRY_LINT_LINT_ON_BUILD=false forge build\",\n            runs,\n            None,\n            Some(\"forge build\"),\n            None,\n            verbose,\n        )\n    }\n\n    /// Benchmark forge build without cache\n    pub fn bench_forge_build_no_cache(\n        &self,\n        version: &str,\n        runs: u32,\n        verbose: bool,\n    ) -> Result<HyperfineResult> {\n        // Clean before each timing run\n        self.hyperfine(\n            \"forge_build_no_cache\",\n            version,\n            \"FOUNDRY_LINT_LINT_ON_BUILD=false forge build\",\n            runs,\n            Some(\"forge clean\"),\n            None,\n            Some(\"forge clean\"),\n            verbose,\n        )\n    }\n\n    /// Benchmark forge fuzz tests\n    pub fn bench_forge_fuzz_test(\n        &self,\n        version: &str,\n        runs: u32,\n        verbose: bool,\n    ) -> Result<HyperfineResult> {\n        // Build before running fuzz tests\n        self.hyperfine(\n            \"forge_fuzz_test\",\n            version,\n            r#\"forge test --match-test \"test[^(]*\\([^)]+\\)\"\"#,\n            runs,\n            Some(\"forge build\"),\n            None,\n            None,\n            verbose,\n        )\n    }\n\n    /// Benchmark forge coverage\n    pub fn bench_forge_coverage(\n        &self,\n        version: &str,\n        runs: u32,\n        verbose: bool,\n    ) -> Result<HyperfineResult> {\n        // No setup needed, forge coverage builds internally\n        // Use --ir-minimum to avoid \"Stack too deep\" errors\n        self.hyperfine(\n            \"forge_coverage\",\n            version,\n            \"forge coverage --ir-minimum\",\n            runs,\n            None,\n            None,\n            None,\n            verbose,\n        )\n    }\n\n    /// Benchmark forge test with --isolate flag\n    pub fn bench_forge_isolate_test(\n        &self,\n        version: &str,\n        runs: u32,\n        verbose: bool,\n    ) -> Result<HyperfineResult> {\n        // Build before running tests\n        self.hyperfine(\n            \"forge_isolate_test\",\n            version,\n            \"forge test --isolate\",\n            runs,\n            Some(\"forge build\"),\n            None,\n            None,\n            verbose,\n        )\n    }\n\n    /// Get the root path of the project\n    pub fn root(&self) -> &Path {\n        &self.root_path\n    }\n\n    /// Run a specific benchmark by name\n    pub fn run(\n        &self,\n        benchmark: &str,\n        version: &str,\n        runs: u32,\n        verbose: bool,\n    ) -> Result<HyperfineResult> {\n        match benchmark {\n            \"forge_test\" => self.bench_forge_test(version, runs, verbose),\n            \"forge_build_no_cache\" => self.bench_forge_build_no_cache(version, runs, verbose),\n            \"forge_build_with_cache\" => self.bench_forge_build_with_cache(version, runs, verbose),\n            \"forge_fuzz_test\" => self.bench_forge_fuzz_test(version, runs, verbose),\n            \"forge_coverage\" => self.bench_forge_coverage(version, runs, verbose),\n            \"forge_isolate_test\" => self.bench_forge_isolate_test(version, runs, verbose),\n            _ => eyre::bail!(\"Unknown benchmark: {}\", benchmark),\n        }\n    }\n}\n\n/// Switch to a specific foundry version\n#[allow(unused_must_use)]\npub fn switch_foundry_version(version: &str) -> Result<()> {\n    let output = Command::new(\"foundryup\")\n        .args([\"--use\", version])\n        .output()\n        .wrap_err(\"Failed to run foundryup\")?;\n\n    // Check if the error is about forge --version failing\n    let stderr = String::from_utf8_lossy(&output.stderr);\n    if stderr.contains(\"command failed\") && stderr.contains(\"forge --version\") {\n        eyre::bail!(\n            \"Foundry binaries maybe corrupted. Please reinstall by running `foundryup --install <version>`\"\n        );\n    }\n\n    if !output.status.success() {\n        sh_eprintln!(\"foundryup stderr: {stderr}\");\n        eyre::bail!(\"Failed to switch to foundry version: {}\", version);\n    }\n\n    sh_println!(\"  Successfully switched to version: {version}\");\n    Ok(())\n}\n\n/// Get the current forge version\npub fn get_forge_version() -> Result<String> {\n    let output = Command::new(\"forge\")\n        .args([\"--version\"])\n        .output()\n        .wrap_err(\"Failed to get forge version\")?;\n\n    if !output.status.success() {\n        eyre::bail!(\"forge --version failed\");\n    }\n\n    let version =\n        String::from_utf8(output.stdout).wrap_err(\"Invalid UTF-8 in forge version output\")?;\n\n    Ok(version.lines().next().unwrap_or(\"unknown\").to_string())\n}\n\n/// Get the full forge version details including commit hash and date\npub fn get_forge_version_details() -> Result<String> {\n    let output = Command::new(\"forge\")\n        .args([\"--version\"])\n        .output()\n        .wrap_err(\"Failed to get forge version\")?;\n\n    if !output.status.success() {\n        eyre::bail!(\"forge --version failed\");\n    }\n\n    let full_output =\n        String::from_utf8(output.stdout).wrap_err(\"Invalid UTF-8 in forge version output\")?;\n\n    // Extract relevant lines and format them\n    let lines: Vec<&str> = full_output.lines().collect();\n    if lines.len() >= 3 {\n        // Extract version, commit, and timestamp\n        let version = lines[0].trim();\n        let commit = lines[1].trim().replace(\"Commit SHA: \", \"\");\n        let timestamp = lines[2].trim().replace(\"Build Timestamp: \", \"\");\n\n        // Format as: \"forge 1.2.3-nightly (51650ea 2025-06-27)\"\n        let short_commit = &commit[..7]; // First 7 chars of commit hash\n        let date = timestamp.split('T').next().unwrap_or(&timestamp);\n\n        Ok(format!(\"{version} ({short_commit} {date})\"))\n    } else {\n        // Fallback to just the first line if format is unexpected\n        Ok(lines.first().unwrap_or(&\"unknown\").to_string())\n    }\n}\n"
  },
  {
    "path": "benches/src/main.rs",
    "content": "use clap::Parser;\nuse eyre::{Result, WrapErr};\nuse foundry_bench::{\n    BENCHMARK_REPOS, BenchmarkProject, FOUNDRY_VERSIONS, RUNS, RepoConfig, get_forge_version,\n    get_forge_version_details,\n    results::{BenchmarkResults, HyperfineResult},\n    switch_foundry_version,\n};\nuse foundry_common::sh_println;\nuse rayon::prelude::*;\nuse std::{fs, path::PathBuf, process::Command, sync::Mutex};\n\nconst ALL_BENCHMARKS: [&str; 6] = [\n    \"forge_test\",\n    \"forge_build_no_cache\",\n    \"forge_build_with_cache\",\n    \"forge_fuzz_test\",\n    \"forge_coverage\",\n    \"forge_isolate_test\",\n];\n\n/// Foundry Benchmark Runner\n#[derive(Parser, Debug)]\n#[clap(name = \"foundry-bench\", about = \"Run Foundry benchmarks across multiple versions\")]\nstruct Cli {\n    /// Comma-separated list of Foundry versions to test (e.g., stable,nightly,v1.2.0)\n    #[clap(long, value_delimiter = ',')]\n    versions: Option<Vec<String>>,\n\n    /// Force install Foundry versions\n    #[clap(long)]\n    force_install: bool,\n\n    /// Show verbose output\n    #[clap(long)]\n    verbose: bool,\n\n    /// Directory where the aggregated benchmark results will be written.\n    #[clap(long, default_value = \".\")]\n    output_dir: PathBuf,\n\n    /// Name of the output file (default: LATEST.md)\n    #[clap(long, default_value = \"LATEST.md\")]\n    output_file: String,\n\n    /// Run only specific benchmarks (comma-separated:\n    /// forge_test,forge_build_no_cache,forge_build_with_cache,forge_fuzz_test,forge_coverage)\n    #[clap(long, value_delimiter = ',')]\n    benchmarks: Option<Vec<String>>,\n\n    /// Run only on specific repositories (comma-separated in org/repo[:rev] format:\n    /// ithacaxyz/account,Vectorized/solady:main,foundry-rs/foundry:v1.0.0)\n    #[clap(long, value_delimiter = ',')]\n    repos: Option<Vec<String>>,\n}\n\n/// Mutex to prevent concurrent foundryup calls\nstatic FOUNDRY_LOCK: Mutex<()> = Mutex::new(());\nfn switch_version_safe(version: &str) -> Result<()> {\n    let _lock = FOUNDRY_LOCK.lock().unwrap();\n    switch_foundry_version(version)\n}\n\n#[allow(unused_must_use)]\nfn main() -> Result<()> {\n    color_eyre::install()?;\n    let cli = Cli::parse();\n\n    // Check if hyperfine is installed\n    let hyperfine_check = Command::new(\"hyperfine\").arg(\"--version\").output();\n    if hyperfine_check.is_err() || !hyperfine_check.unwrap().status.success() {\n        eyre::bail!(\n            \"hyperfine is not installed. Please install it first: https://github.com/sharkdp/hyperfine\"\n        );\n    }\n\n    // Determine versions to test\n    let versions = if let Some(v) = cli.versions {\n        v\n    } else {\n        FOUNDRY_VERSIONS.iter().map(|&s| s.to_string()).collect()\n    };\n\n    // Get repo configurations\n    let repos = if let Some(repo_specs) = cli.repos.clone() {\n        repo_specs.iter().map(|spec| spec.parse::<RepoConfig>()).collect::<Result<Vec<_>>>()?\n    } else {\n        BENCHMARK_REPOS.clone()\n    };\n\n    sh_println!(\"🚀 Foundry Benchmark Runner\");\n    sh_println!(\"Running with versions: {}\", versions.join(\", \"));\n    sh_println!(\n        \"Running on repos: {}\",\n        repos.iter().map(|r| format!(\"{}/{}\", r.org, r.repo)).collect::<Vec<_>>().join(\", \")\n    );\n\n    // Install versions if requested\n    if cli.force_install {\n        install_foundry_versions(&versions)?;\n    }\n\n    // Determine benchmarks to run\n    let benchmarks = if let Some(b) = cli.benchmarks {\n        b.into_iter().filter(|b| ALL_BENCHMARKS.contains(&b.as_str())).collect()\n    } else {\n        // Default: run all benchmarks except fuzz tests and coverage (which can be slow)\n        vec![\"forge_test\", \"forge_build_no_cache\", \"forge_build_with_cache\"]\n            .into_iter()\n            .map(String::from)\n            .collect::<Vec<_>>()\n    };\n\n    sh_println!(\"Running benchmarks: {}\", benchmarks.join(\", \"));\n\n    let mut results = BenchmarkResults::new();\n    // Set the first version as baseline\n    if let Some(first_version) = versions.first() {\n        results.set_baseline_version(first_version.clone());\n    }\n\n    // Setup all projects upfront before version loop\n    sh_println!(\"📦 Setting up projects to benchmark\");\n    let projects: Vec<(RepoConfig, BenchmarkProject)> = repos\n        .par_iter()\n        .map(|repo_config| -> Result<(RepoConfig, BenchmarkProject)> {\n            sh_println!(\"Setting up {}/{}\", repo_config.org, repo_config.repo);\n            let project = BenchmarkProject::setup(repo_config).wrap_err(format!(\n                \"Failed to setup project for {}/{}\",\n                repo_config.org, repo_config.repo\n            ))?;\n            Ok((repo_config.clone(), project))\n        })\n        .collect::<Result<Vec<_>>>()?;\n\n    sh_println!(\"✅ All projects setup complete\");\n\n    // Create a list of all benchmark tasks (same for all versions)\n    let benchmark_tasks: Vec<_> = projects\n        .iter()\n        .flat_map(|(repo_config, project)| {\n            benchmarks\n                .iter()\n                .map(move |benchmark| (repo_config.clone(), project, benchmark.clone()))\n        })\n        .collect();\n\n    sh_println!(\"Will run {} benchmark tasks per version\", benchmark_tasks.len());\n\n    // Run benchmarks for each version\n    for version in &versions {\n        sh_println!(\"🔧 Switching to Foundry version: {version}\");\n        switch_version_safe(version)?;\n\n        // Verify the switch and capture full version details\n        let current = get_forge_version()?;\n        sh_println!(\"Current version: {}\", current.trim());\n\n        // Get and store the full version details with commit hash and date\n        let version_details = get_forge_version_details()?;\n        results.add_version_details(version, version_details);\n\n        sh_println!(\"Running benchmark tasks for version {version}...\");\n\n        // Run all benchmarks sequentially\n        let version_results = benchmark_tasks\n            .iter()\n            .map(|(repo_config, project, benchmark)| -> Result<(String, String, HyperfineResult)> {\n                sh_println!(\"Running {} on {}/{}\", benchmark, repo_config.org, repo_config.repo);\n\n                // Determine runs based on benchmark type\n                let runs = match benchmark.as_str() {\n                    \"forge_coverage\" => 1, // Coverage runs only once as an exception\n                    _ => RUNS,             // Use default RUNS constant for all other benchmarks\n                };\n\n                // Run the appropriate benchmark\n                let result = project.run(benchmark, version, runs, cli.verbose);\n\n                match result {\n                    Ok(hyperfine_result) => {\n                        sh_println!(\n                            \"  {} on {}/{}: {:.3}s ± {:.3}s\",\n                            benchmark,\n                            repo_config.org,\n                            repo_config.repo,\n                            hyperfine_result.mean,\n                            hyperfine_result.stddev.unwrap_or(0.0)\n                        );\n                        Ok((repo_config.name.clone(), benchmark.clone(), hyperfine_result))\n                    }\n                    Err(e) => {\n                        eyre::bail!(\n                            \"Benchmark {} failed for {}/{}: {}\",\n                            benchmark,\n                            repo_config.org,\n                            repo_config.repo,\n                            e\n                        );\n                    }\n                }\n            })\n            .collect::<Result<Vec<_>>>()?;\n\n        // Add all collected results to the main results structure\n        for (repo_name, benchmark, hyperfine_result) in version_results {\n            results.add_result(&benchmark, version, &repo_name, hyperfine_result);\n        }\n    }\n\n    // Generate markdown report\n    sh_println!(\"📝 Generating report...\");\n    let markdown = results.generate_markdown(&versions, &repos);\n    let output_path = cli.output_dir.join(cli.output_file);\n    fs::write(&output_path, markdown).wrap_err(\"Failed to write output file\")?;\n    sh_println!(\"✅ Report written to: {}\", output_path.display());\n\n    Ok(())\n}\n\n#[allow(unused_must_use)]\nfn install_foundry_versions(versions: &[String]) -> Result<()> {\n    sh_println!(\"Installing Foundry versions...\");\n\n    for version in versions {\n        sh_println!(\"Installing {version}...\");\n\n        let status = Command::new(\"foundryup\")\n            .args([\"--install\", version, \"--force\"])\n            .status()\n            .wrap_err(\"Failed to run foundryup\")?;\n\n        if !status.success() {\n            eyre::bail!(\"Failed to install Foundry version: {}\", version);\n        }\n    }\n\n    sh_println!(\"✅ All versions installed successfully\");\n    Ok(())\n}\n"
  },
  {
    "path": "benches/src/results.rs",
    "content": "use crate::RepoConfig;\nuse eyre::Result;\nuse serde::{Deserialize, Serialize};\nuse std::{collections::HashMap, process::Command, thread};\n\n/// Hyperfine benchmark result\n#[derive(Debug, Deserialize, Serialize)]\npub struct HyperfineResult {\n    pub command: String,\n    pub mean: f64,\n    pub stddev: Option<f64>,\n    pub median: f64,\n    pub user: f64,\n    pub system: f64,\n    pub min: f64,\n    pub max: f64,\n    pub times: Vec<f64>,\n    #[serde(skip_serializing_if = \"Option::is_none\")]\n    pub exit_codes: Option<Vec<i32>>,\n    #[serde(skip_serializing_if = \"Option::is_none\")]\n    pub parameters: Option<HashMap<String, serde_json::Value>>,\n}\n\n/// Hyperfine JSON output format\n#[derive(Debug, Deserialize, Serialize)]\npub struct HyperfineOutput {\n    pub results: Vec<HyperfineResult>,\n}\n\n/// Aggregated benchmark results\n#[derive(Debug, Default)]\npub struct BenchmarkResults {\n    /// Map of benchmark_name -> version -> repo -> result\n    pub data: HashMap<String, HashMap<String, HashMap<String, HyperfineResult>>>,\n    /// Track the baseline version for comparison\n    pub baseline_version: Option<String>,\n    /// Map of version name -> full version details\n    pub version_details: HashMap<String, String>,\n}\n\nimpl BenchmarkResults {\n    pub fn new() -> Self {\n        Self::default()\n    }\n\n    pub fn set_baseline_version(&mut self, version: String) {\n        self.baseline_version = Some(version);\n    }\n\n    pub fn add_result(\n        &mut self,\n        benchmark: &str,\n        version: &str,\n        repo: &str,\n        result: HyperfineResult,\n    ) {\n        self.data\n            .entry(benchmark.to_string())\n            .or_default()\n            .entry(version.to_string())\n            .or_default()\n            .insert(repo.to_string(), result);\n    }\n\n    pub fn add_version_details(&mut self, version: &str, details: String) {\n        self.version_details.insert(version.to_string(), details);\n    }\n\n    pub fn generate_markdown(&self, versions: &[String], repos: &[RepoConfig]) -> String {\n        let mut output = String::new();\n\n        // Header\n        output.push_str(\"# Foundry Benchmark Results\\n\\n\");\n        output.push_str(&format!(\n            \"**Date**: {}\\n\\n\",\n            chrono::Local::now().format(\"%Y-%m-%d %H:%M:%S\")\n        ));\n\n        // Summary\n        output.push_str(\"## Summary\\n\\n\");\n        // Count actual repos that have results\n        let mut repos_with_results = std::collections::HashSet::new();\n        for version_data in self.data.values() {\n            for repo_data in version_data.values() {\n                for repo_name in repo_data.keys() {\n                    repos_with_results.insert(repo_name.clone());\n                }\n            }\n        }\n        output.push_str(&format!(\n            \"Benchmarked {} Foundry versions across {} repositories.\\n\\n\",\n            versions.len(),\n            repos_with_results.len()\n        ));\n\n        // Repositories tested\n        output.push_str(\"### Repositories Tested\\n\\n\");\n        for (i, repo) in repos.iter().enumerate() {\n            output.push_str(&format!(\n                \"{}. [{}/{}](https://github.com/{}/{})\\n\",\n                i + 1,\n                repo.org,\n                repo.repo,\n                repo.org,\n                repo.repo\n            ));\n        }\n        output.push('\\n');\n\n        // Versions tested\n        output.push_str(\"### Foundry Versions\\n\\n\");\n        for version in versions {\n            if let Some(details) = self.version_details.get(version) {\n                output.push_str(&format!(\"- **{version}**: {}\\n\", details.trim()));\n            } else {\n                output.push_str(&format!(\"- {version}\\n\"));\n            }\n        }\n        output.push('\\n');\n\n        // Results for each benchmark type\n        for (benchmark_name, version_data) in &self.data {\n            output.push_str(&self.generate_benchmark_table(\n                benchmark_name,\n                version_data,\n                versions,\n                repos,\n            ));\n        }\n\n        // System info\n        output.push_str(\"## System Information\\n\\n\");\n        output.push_str(&format!(\"- **OS**: {}\\n\", std::env::consts::OS));\n        output.push_str(&format!(\n            \"- **CPU**: {}\\n\",\n            thread::available_parallelism().map_or(1, |n| n.get())\n        ));\n        output.push_str(&format!(\n            \"- **Rustc**: {}\\n\",\n            get_rustc_version().unwrap_or_else(|_| \"unknown\".to_string())\n        ));\n\n        output\n    }\n\n    /// Generate a complete markdown table for a single benchmark type\n    ///\n    /// This includes the section header, table header, separator, and all rows\n    fn generate_benchmark_table(\n        &self,\n        benchmark_name: &str,\n        version_data: &HashMap<String, HashMap<String, HyperfineResult>>,\n        versions: &[String],\n        repos: &[RepoConfig],\n    ) -> String {\n        let mut output = String::new();\n\n        // Section header\n        output.push_str(&format!(\"## {}\\n\\n\", format_benchmark_name(benchmark_name)));\n\n        // Create table header\n        output.push_str(\"| Repository |\");\n        for version in versions {\n            output.push_str(&format!(\" {version} |\"));\n        }\n        output.push('\\n');\n\n        // Table separator\n        output.push_str(\"|------------|\");\n        for _ in versions {\n            output.push_str(\"----------|\");\n        }\n        output.push('\\n');\n\n        // Table rows\n        output.push_str(&generate_table_rows(version_data, versions, repos));\n        output.push('\\n');\n\n        output\n    }\n}\n\n/// Generate table rows for benchmark results\n///\n/// This function creates the markdown table rows for each repository,\n/// showing the benchmark results for each version.\nfn generate_table_rows(\n    version_data: &HashMap<String, HashMap<String, HyperfineResult>>,\n    versions: &[String],\n    repos: &[RepoConfig],\n) -> String {\n    let mut output = String::new();\n\n    for repo in repos {\n        output.push_str(&format!(\"| {} |\", repo.name));\n\n        for version in versions {\n            let cell_content = get_benchmark_cell_content(version_data, version, &repo.name);\n            output.push_str(&format!(\" {cell_content} |\"));\n        }\n\n        output.push('\\n');\n    }\n\n    output\n}\n\n/// Get the content for a single benchmark table cell\n///\n/// Returns the formatted duration or \"N/A\" if no data is available.\n/// The nested if-let statements handle the following cases:\n/// 1. Check if version data exists\n/// 2. Check if repository data exists for this version\nfn get_benchmark_cell_content(\n    version_data: &HashMap<String, HashMap<String, HyperfineResult>>,\n    version: &str,\n    repo_name: &str,\n) -> String {\n    // Check if we have data for this version\n    if let Some(repo_data) = version_data.get(version) &&\n    // Check if we have data for this repository\n        let Some(result) = repo_data.get(repo_name)\n    {\n        return format_duration_seconds(result.mean);\n    }\n\n    \"N/A\".to_string()\n}\n\npub fn format_benchmark_name(name: &str) -> String {\n    match name {\n        \"forge_test\" => \"Forge Test\",\n        \"forge_build_no_cache\" => \"Forge Build (No Cache)\",\n        \"forge_build_with_cache\" => \"Forge Build (With Cache)\",\n        \"forge_fuzz_test\" => \"Forge Fuzz Test\",\n        \"forge_coverage\" => \"Forge Coverage\",\n        \"forge_isolate_test\" => \"Forge Test (Isolated)\",\n        _ => name,\n    }\n    .to_string()\n}\n\npub fn format_duration_seconds(seconds: f64) -> String {\n    if seconds < 0.001 {\n        format!(\"{:.2} ms\", seconds * 1000.0)\n    } else if seconds < 1.0 {\n        format!(\"{seconds:.3} s\")\n    } else if seconds < 60.0 {\n        format!(\"{seconds:.2} s\")\n    } else {\n        let minutes = (seconds / 60.0).floor();\n        let remaining_seconds = seconds % 60.0;\n        format!(\"{minutes:.0}m {remaining_seconds:.1}s\")\n    }\n}\n\npub fn get_rustc_version() -> Result<String> {\n    let output = Command::new(\"rustc\").arg(\"--version\").output()?;\n\n    Ok(String::from_utf8_lossy(&output.stdout).trim().to_string())\n}\n"
  },
  {
    "path": "benchmark.sh",
    "content": "#!/bin/bash\n\nversions=\"v1.3.6,v1.4.0-rc1\"\n\n# Repositories\nexport ITHACA_ACCOUNT=\"ithacaxyz/account:v0.3.2\"\nexport SOLADY_REPO=\"Vectorized/solady:v0.1.22\"\nexport UNISWAP_V4_CORE=\"Uniswap/v4-core:59d3ecf\"\nexport SPARK_PSM=\"sparkdotfi/spark-psm:v1.0.0\"\n\n# Benches\necho \"===========FORGE TEST AND BUILD BENCHMARKS===========\"\n\nfoundry-bench --versions $versions \\\n    --repos $ITHACA_ACCOUNT,$SOLADY_REPO,$UNISWAP_V4_CORE,$SPARK_PSM \\\n    --benchmarks forge_test,forge_fuzz_test,forge_build_no_cache,forge_build_with_cache \\\n    --output-dir ./benches/results \\\n    --output-file TEST_BUILD.md\n\necho \"===========FORGE COVERAGE BENCHMARKS===========\"\n\nfoundry-bench --versions $versions \\\n    --repos $ITHACA_ACCOUNT,$UNISWAP_V4_CORE,$SPARK_PSM \\\n    --benchmarks forge_coverage \\\n    --output-dir ./benches/results \\\n    --output-file COVERAGE.md\n\necho \"===========FORGE ISOLATE TEST BENCHMARKS===========\"\n\nfoundry-bench --versions $versions \\\n    --repos $SOLADY_REPO,$UNISWAP_V4_CORE,$SPARK_PSM \\\n    --benchmarks forge_isolate_test \\\n    --output-dir ./benches/results \\\n    --output-file ISOLATE_TEST.md\n\necho \"===========BENCHMARKS COMPLETED===========\"\n"
  },
  {
    "path": "clippy.toml",
    "content": "# `bytes::Bytes` is included by default and `alloy_primitives::Bytes` is a wrapper around it,\n# so it is safe to ignore it as well.\nignore-interior-mutability = [\"bytes::Bytes\", \"alloy_primitives::Bytes\"]\n\ndisallowed-macros = [\n    # See `foundry_common::shell`.\n    { path = \"std::print\", reason = \"use `sh_print` or similar macros instead\" },\n    { path = \"std::eprint\", reason = \"use `sh_eprint` or similar macros instead\" },\n    { path = \"std::println\", reason = \"use `sh_println` or similar macros instead\" },\n    { path = \"std::eprintln\", reason = \"use `sh_eprintln` or similar macros instead\" },\n]\n"
  },
  {
    "path": "crates/anvil/Cargo.toml",
    "content": "[package]\nname = \"anvil\"\ndescription = \"Local ethereum node\"\n\nversion.workspace = true\nedition.workspace = true\nrust-version.workspace = true\nauthors.workspace = true\nlicense.workspace = true\nhomepage.workspace = true\nrepository.workspace = true\n\n[lints]\nworkspace = true\n\n[[bin]]\nname = \"anvil\"\npath = \"bin/main.rs\"\nrequired-features = [\"cli\"]\n\n[dependencies]\n# foundry internal\nanvil-core = { path = \"core\" }\nanvil-rpc = { path = \"rpc\" }\nanvil-server = { path = \"server\" }\nfoundry-cli.workspace = true\nfoundry-common.workspace = true\nfoundry-config.workspace = true\nfoundry-evm.workspace = true\nfoundry-evm-networks.workspace = true\nfoundry-primitives.workspace = true\ntempo-primitives.workspace = true\n\n# alloy\nalloy-evm = { workspace = true, features = [\"call-util\"] }\nalloy-op-evm.workspace = true\nalloy-primitives = { workspace = true, features = [\"serde\"] }\nalloy-consensus = { workspace = true, features = [\"k256\", \"kzg\"] }\nalloy-contract = { workspace = true, features = [\"pubsub\"] }\nalloy-network.workspace = true\nalloy-eips.workspace = true\nalloy-rlp.workspace = true\nalloy-signer = { workspace = true, features = [\"eip712\"] }\nalloy-signer-local = { workspace = true, features = [\"mnemonic\"] }\nalloy-sol-types = { workspace = true, features = [\"std\"] }\nalloy-dyn-abi = { workspace = true, features = [\"std\", \"eip712\"] }\nalloy-rpc-types = { workspace = true, features = [\"anvil\", \"trace\", \"txpool\"] }\nalloy-rpc-types-beacon.workspace = true\nalloy-rpc-types-eth.workspace = true\nalloy-serde.workspace = true\nalloy-provider = { workspace = true, features = [\n    \"reqwest\",\n    \"ws\",\n    \"ipc\",\n    \"debug-api\",\n    \"trace-api\",\n] }\nalloy-transport.workspace = true\nalloy-chains.workspace = true\nalloy-genesis.workspace = true\nalloy-trie.workspace = true\nop-alloy-consensus = { workspace = true, features = [\"serde\"] }\n\n# revm\nrevm = { workspace = true, features = [\n    \"std\",\n    \"serde\",\n    \"memory_limit\",\n    \"c-kzg\",\n] }\nrevm-inspectors.workspace = true\nop-revm.workspace = true\n\n# axum related\naxum.workspace = true\nhyper.workspace = true\n\n# tracing\ntracing.workspace = true\ntracing-subscriber = { workspace = true, features = [\"env-filter\"] }\n\n# async\ntokio = { workspace = true, features = [\"time\"] }\nparking_lot.workspace = true\nfutures.workspace = true\nasync-trait.workspace = true\n\n# misc\nflate2.workspace = true\nserde_json.workspace = true\nserde.workspace = true\nthiserror.workspace = true\nyansi.workspace = true\ntempfile.workspace = true\nitertools.workspace = true\nrand_08.workspace = true\neyre.workspace = true\nethereum_ssz.workspace = true\n\n# cli\nclap = { version = \"4\", features = [\n    \"derive\",\n    \"env\",\n    \"wrap_help\",\n], optional = true }\nclap_complete = { workspace = true, optional = true }\nchrono.workspace = true\nctrlc = { version = \"3\", optional = true }\nfdlimit = { version = \"0.3\", optional = true }\n\n[dev-dependencies]\nalloy-provider = { workspace = true, features = [\"txpool-api\"] }\nalloy-pubsub.workspace = true\nrand.workspace = true\nreqwest.workspace = true\nfoundry-test-utils.workspace = true\ntokio = { workspace = true, features = [\"full\"] }\n\nop-alloy-rpc-types.workspace = true\n\n[features]\ndefault = [\"cli\", \"jemalloc\"]\nasm-keccak = [\"alloy-primitives/asm-keccak\"]\njemalloc = [\"foundry-cli/jemalloc\"]\nmimalloc = [\"foundry-cli/mimalloc\"]\ntracy-allocator = [\"foundry-cli/tracy-allocator\"]\ncli = [\"tokio/full\", \"cmd\"]\ncmd = [\n    \"clap\",\n    \"clap_complete\",\n    \"dep:fdlimit\",\n    \"dep:ctrlc\",\n    \"anvil-server/clap\",\n    \"tokio/signal\",\n]\njs-tracer = [\"revm-inspectors/js-tracer\"]\n"
  },
  {
    "path": "crates/anvil/bin/main.rs",
    "content": "//! The `anvil` CLI: a fast local Ethereum development node, akin to Hardhat Network, Tenderly.\n\nuse anvil::args::run;\n\n#[global_allocator]\nstatic ALLOC: foundry_cli::utils::Allocator = foundry_cli::utils::new_allocator();\n\nfn main() {\n    if let Err(err) = run() {\n        let _ = foundry_common::sh_err!(\"{err:?}\");\n        std::process::exit(1);\n    }\n}\n"
  },
  {
    "path": "crates/anvil/core/Cargo.toml",
    "content": "[package]\nname = \"anvil-core\"\n\nversion.workspace = true\nedition.workspace = true\nrust-version.workspace = true\nauthors.workspace = true\nlicense.workspace = true\nhomepage.workspace = true\nrepository.workspace = true\n\n[lints]\nworkspace = true\n\n[dependencies]\nfoundry-common.workspace = true\nfoundry-evm.workspace = true\nfoundry-primitives.workspace = true\nrevm = { workspace = true, default-features = false, features = [\n    \"std\",\n    \"serde\",\n    \"memory_limit\",\n    \"c-kzg\",\n] }\n\nalloy-primitives = { workspace = true, features = [\"serde\", \"rlp\"] }\nalloy-rpc-types = { workspace = true, features = [\"anvil\", \"trace\"] }\nalloy-serde.workspace = true\nalloy-rlp.workspace = true\nalloy-eips.workspace = true\nalloy-eip5792.workspace = true\nalloy-consensus = { workspace = true, features = [\"k256\", \"kzg\"] }\nalloy-network.workspace = true\nalloy-dyn-abi = { workspace = true, features = [\"std\", \"eip712\"] }\nserde.workspace = true\nserde_json.workspace = true\nbytes.workspace = true\n\n# misc\nrand.workspace = true\nthiserror.workspace = true\n"
  },
  {
    "path": "crates/anvil/core/src/eth/block.rs",
    "content": "use super::transaction::TransactionInfo;\nuse alloy_consensus::{\n    BlockBody, EMPTY_OMMER_ROOT_HASH, Header, proofs::calculate_transaction_root,\n};\nuse alloy_eips::eip2718::Encodable2718;\nuse alloy_network::Network;\nuse foundry_primitives::{FoundryNetwork, FoundryTxEnvelope};\nuse std::fmt::Debug;\n\nuse crate::eth::transaction::MaybeImpersonatedTransaction;\n\n/// Type alias for Ethereum Block with Anvil's transaction type, generic over the transaction\n/// envelope with a default of [`FoundryTxEnvelope`].\npub type Block<T = FoundryTxEnvelope> = alloy_consensus::Block<MaybeImpersonatedTransaction<T>>;\n\n/// Anvil's concrete block info type.\npub type BlockInfo = TypedBlockInfo<FoundryNetwork>;\n\n/// Container type that gathers all block data, generic over a [`Network`].\n#[derive(Clone, Debug)]\npub struct TypedBlockInfo<N: Network> {\n    pub block: alloy_consensus::Block<MaybeImpersonatedTransaction<N::TxEnvelope>>,\n    pub transactions: Vec<TransactionInfo>,\n    pub receipts: Vec<N::ReceiptEnvelope>,\n}\n\n/// Helper function to create a new block with Header and Anvil transactions, generic over the\n/// transaction envelope with a default of [`FoundryTxEnvelope`].\n///\n/// Note: if the `impersonate-tx` feature is enabled this will also accept\n/// `MaybeImpersonatedTransaction`.\npub fn create_block<T, Tx>(\n    mut header: Header,\n    transactions: impl IntoIterator<Item = T>,\n) -> Block<Tx>\nwhere\n    Tx: Encodable2718,\n    T: Into<MaybeImpersonatedTransaction<Tx>>,\n{\n    let transactions: Vec<_> = transactions.into_iter().map(Into::into).collect();\n    let transactions_root = calculate_transaction_root(&transactions);\n\n    header.transactions_root = transactions_root;\n    header.ommers_hash = EMPTY_OMMER_ROOT_HASH;\n\n    let body = BlockBody { transactions, ommers: Vec::new(), withdrawals: None };\n    Block::new(header, body)\n}\n\n/// Generic helper function to create a block with any transaction type that supports encoding.\npub fn create_typed_block<T>(\n    mut header: Header,\n    transactions: impl IntoIterator<Item = T>,\n) -> alloy_consensus::Block<T>\nwhere\n    T: Encodable2718,\n{\n    let transactions: Vec<_> = transactions.into_iter().collect();\n    let transactions_root = calculate_transaction_root(&transactions);\n\n    header.transactions_root = transactions_root;\n    header.ommers_hash = EMPTY_OMMER_ROOT_HASH;\n\n    let body = BlockBody { transactions, ommers: Vec::new(), withdrawals: None };\n    alloy_consensus::Block::new(header, body)\n}\n\n#[cfg(test)]\nmod tests {\n    use alloy_primitives::{\n        Address, B64, B256, Bloom, U256, b256,\n        hex::{self, FromHex},\n    };\n    use alloy_rlp::Decodable;\n\n    use super::*;\n    use std::str::FromStr;\n\n    #[test]\n    fn header_rlp_roundtrip() {\n        let mut header = Header {\n            parent_hash: Default::default(),\n            ommers_hash: Default::default(),\n            beneficiary: Default::default(),\n            state_root: Default::default(),\n            transactions_root: Default::default(),\n            receipts_root: Default::default(),\n            logs_bloom: Default::default(),\n            difficulty: Default::default(),\n            number: 124u64,\n            gas_limit: Default::default(),\n            gas_used: 1337u64,\n            timestamp: 0,\n            extra_data: Default::default(),\n            mix_hash: Default::default(),\n            nonce: B64::with_last_byte(99),\n            withdrawals_root: Default::default(),\n            blob_gas_used: Default::default(),\n            excess_blob_gas: Default::default(),\n            parent_beacon_block_root: Default::default(),\n            base_fee_per_gas: None,\n            requests_hash: None,\n        };\n\n        let encoded = alloy_rlp::encode(&header);\n        let decoded: Header = Header::decode(&mut encoded.as_ref()).unwrap();\n        assert_eq!(header, decoded);\n\n        header.base_fee_per_gas = Some(12345u64);\n\n        let encoded = alloy_rlp::encode(&header);\n        let decoded: Header = Header::decode(&mut encoded.as_ref()).unwrap();\n        assert_eq!(header, decoded);\n    }\n\n    #[test]\n    fn test_encode_block_header() {\n        use alloy_rlp::Encodable;\n\n        let expected = hex::decode(\"f901f9a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000940000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008208ae820d0582115c8215b3821a0a827788a00000000000000000000000000000000000000000000000000000000000000000880000000000000000\").unwrap();\n        let mut data = vec![];\n        let header = Header {\n            parent_hash: B256::from_str(\"0000000000000000000000000000000000000000000000000000000000000000\").unwrap(),\n            ommers_hash: B256::from_str(\"0000000000000000000000000000000000000000000000000000000000000000\").unwrap(),\n            beneficiary: Address::from_str(\"0000000000000000000000000000000000000000\").unwrap(),\n            state_root: B256::from_str(\"0000000000000000000000000000000000000000000000000000000000000000\").unwrap(),\n            transactions_root: B256::from_str(\"0000000000000000000000000000000000000000000000000000000000000000\").unwrap(),\n            receipts_root: B256::from_str(\"0000000000000000000000000000000000000000000000000000000000000000\").unwrap(),\n            logs_bloom: Bloom::from_hex(\"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\").unwrap(),\n            difficulty: U256::from(2222),\n            number: 0xd05u64,\n            gas_limit: 0x115cu64,\n            gas_used: 0x15b3u64,\n            timestamp: 0x1a0au64,\n            extra_data: hex::decode(\"7788\").unwrap().into(),\n            mix_hash: B256::from_str(\"0000000000000000000000000000000000000000000000000000000000000000\").unwrap(),\n            withdrawals_root: None,\n            blob_gas_used: None,\n            excess_blob_gas: None,\n            parent_beacon_block_root: None,\n            nonce: B64::ZERO,\n            base_fee_per_gas: None,\n            requests_hash: None,\n        };\n\n        header.encode(&mut data);\n        assert_eq!(hex::encode(&data), hex::encode(expected));\n        assert_eq!(header.length(), data.len());\n    }\n\n    #[test]\n    // Test vector from: https://eips.ethereum.org/EIPS/eip-2481\n    fn test_decode_block_header() {\n        let data = hex::decode(\"f901f9a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000940000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008208ae820d0582115c8215b3821a0a827788a00000000000000000000000000000000000000000000000000000000000000000880000000000000000\").unwrap();\n        let expected = Header {\n            parent_hash: B256::from_str(\"0000000000000000000000000000000000000000000000000000000000000000\").unwrap(),\n            ommers_hash: B256::from_str(\"0000000000000000000000000000000000000000000000000000000000000000\").unwrap(),\n            beneficiary: Address::from_str(\"0000000000000000000000000000000000000000\").unwrap(),\n            state_root: B256::from_str(\"0000000000000000000000000000000000000000000000000000000000000000\").unwrap(),\n            transactions_root: B256::from_str(\"0000000000000000000000000000000000000000000000000000000000000000\").unwrap(),\n            receipts_root: B256::from_str(\"0000000000000000000000000000000000000000000000000000000000000000\").unwrap(),\n            logs_bloom: <[u8; 256]>::from_hex(\"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\").unwrap().into(),\n            difficulty: U256::from(2222),\n            number: 0xd05u64,\n            gas_limit: 0x115cu64,\n            gas_used: 0x15b3u64,\n            timestamp: 0x1a0au64,\n            extra_data: hex::decode(\"7788\").unwrap().into(),\n            mix_hash: B256::from_str(\"0000000000000000000000000000000000000000000000000000000000000000\").unwrap(),\n            nonce: B64::ZERO,\n            withdrawals_root: None,\n            blob_gas_used: None,\n            excess_blob_gas: None,\n            parent_beacon_block_root: None,\n            base_fee_per_gas: None,\n            requests_hash: None,\n        };\n        let header = Header::decode(&mut data.as_slice()).unwrap();\n        assert_eq!(header, expected);\n    }\n\n    #[test]\n    // Test vector from: https://github.com/ethereum/tests/blob/f47bbef4da376a49c8fc3166f09ab8a6d182f765/BlockchainTests/ValidBlocks/bcEIP1559/baseFee.json#L15-L36\n    fn test_eip1559_block_header_hash() {\n        let expected_hash =\n            b256!(\"0x6a251c7c3c5dca7b42407a3752ff48f3bbca1fab7f9868371d9918daf1988d1f\");\n        let header = Header {\n            parent_hash: B256::from_str(\"e0a94a7a3c9617401586b1a27025d2d9671332d22d540e0af72b069170380f2a\").unwrap(),\n            ommers_hash: B256::from_str(\"1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347\").unwrap(),\n            beneficiary: Address::from_str(\"ba5e000000000000000000000000000000000000\").unwrap(),\n            state_root: B256::from_str(\"ec3c94b18b8a1cff7d60f8d258ec723312932928626b4c9355eb4ab3568ec7f7\").unwrap(),\n            transactions_root: B256::from_str(\"50f738580ed699f0469702c7ccc63ed2e51bc034be9479b7bff4e68dee84accf\").unwrap(),\n            receipts_root: B256::from_str(\"29b0562f7140574dd0d50dee8a271b22e1a0a7b78fca58f7c60370d8317ba2a9\").unwrap(),\n            logs_bloom: Bloom::from_hex(\"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\").unwrap(),\n            difficulty: U256::from(0x020000),\n            number: 1u64,\n            gas_limit: U256::from(0x016345785d8a0000u128).to::<u64>(),\n            gas_used: U256::from(0x015534).to::<u64>(),\n            timestamp: 0x079e,\n            extra_data: hex::decode(\"42\").unwrap().into(),\n            mix_hash: B256::from_str(\"0000000000000000000000000000000000000000000000000000000000000000\").unwrap(),\n            nonce: B64::ZERO,\n            base_fee_per_gas: Some(875),\n            withdrawals_root: None,\n            blob_gas_used: None,\n            excess_blob_gas: None,\n            parent_beacon_block_root: None,\n            requests_hash: None,\n        };\n        assert_eq!(header.hash_slow(), expected_hash);\n    }\n\n    #[test]\n    // Test vector from network\n    fn block_network_roundtrip() {\n        use alloy_rlp::Encodable;\n\n        let data = hex::decode(\"f9034df90348a0fbdbd8d2d0ac5f14bd5fa90e547fe6f1d15019c724f8e7b60972d381cd5d9cf8a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794c9577e7945db22e38fc060909f2278c7746b0f9ba05017cfa3b0247e35197215ae8d610265ffebc8edca8ea66d6567eb0adecda867a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000018355bb7b871fffffffffffff808462bd0e1ab9014bf90148a00000000000000000000000000000000000000000000000000000000000000000f85494319fa8f1bc4e53410e92d10d918659b16540e60a945a573efb304d04c1224cd012313e827eca5dce5d94a9c831c5a268031176ebf5f3de5051e8cba0dbfe94c9577e7945db22e38fc060909f2278c7746b0f9b808400000000f8c9b841a6946f2d16f68338cbcbd8b117374ab421128ce422467088456bceba9d70c34106128e6d4564659cf6776c08a4186063c0a05f7cffd695c10cf26a6f301b67f800b8412b782100c18c35102dc0a37ece1a152544f04ad7dc1868d18a9570f744ace60870f822f53d35e89a2ea9709ccbf1f4a25ee5003944faa845d02dde0a41d5704601b841d53caebd6c8a82456e85c2806a9e08381f959a31fb94a77e58f00e38ad97b2e0355b8519ab2122662cbe022f2a4ef7ff16adc0b2d5dcd123181ec79705116db300a063746963616c2062797a616e74696e65206661756c7420746f6c6572616e6365880000000000000000c0c0\").unwrap();\n\n        let block = <Block>::decode(&mut data.as_slice()).unwrap();\n\n        // encode and check that it matches the original data\n        let mut encoded = Vec::new();\n        block.encode(&mut encoded);\n        assert_eq!(data, encoded);\n\n        // check that length of encoding is the same as the output of `length`\n        assert_eq!(block.length(), encoded.len());\n    }\n}\n"
  },
  {
    "path": "crates/anvil/core/src/eth/mod.rs",
    "content": "use crate::{eth::subscription::SubscriptionId, types::ReorgOptions};\nuse alloy_primitives::{Address, B64, B256, Bytes, TxHash, U256, map::HashSet};\nuse alloy_rpc_types::{\n    BlockId, BlockNumberOrTag as BlockNumber, BlockOverrides, Filter, Index,\n    anvil::{Forking, MineOptions},\n    pubsub::{Params as SubscriptionParams, SubscriptionKind},\n    request::TransactionRequest,\n    simulate::SimulatePayload,\n    state::StateOverride,\n    trace::{\n        filter::TraceFilter,\n        geth::{GethDebugTracingCallOptions, GethDebugTracingOptions},\n        parity::TraceType,\n    },\n};\nuse alloy_serde::WithOtherFields;\nuse foundry_common::serde_helpers::{\n    deserialize_number, deserialize_number_opt, deserialize_number_seq,\n};\n\npub mod block;\npub mod subscription;\npub mod transaction;\npub mod wallet;\n\npub mod serde_helpers;\nuse self::serde_helpers::*;\n\n/// Wrapper type that ensures the type is named `params`\n#[derive(Clone, Debug, PartialEq, Eq, serde::Deserialize)]\npub struct Params<T: Default> {\n    #[serde(default)]\n    pub params: T,\n}\n\n/// Represents ethereum JSON-RPC API\n#[derive(Clone, Debug, serde::Deserialize)]\n#[serde(tag = \"method\", content = \"params\")]\n#[allow(clippy::large_enum_variant)]\npub enum EthRequest {\n    #[serde(rename = \"web3_clientVersion\", with = \"empty_params\")]\n    Web3ClientVersion(()),\n\n    #[serde(rename = \"web3_sha3\", with = \"sequence\")]\n    Web3Sha3(Bytes),\n\n    /// Returns the current Ethereum protocol version.\n    #[serde(rename = \"eth_protocolVersion\", with = \"empty_params\")]\n    EthProtocolVersion(()),\n\n    #[serde(rename = \"eth_chainId\", with = \"empty_params\")]\n    EthChainId(()),\n\n    #[serde(rename = \"eth_networkId\", alias = \"net_version\", with = \"empty_params\")]\n    EthNetworkId(()),\n\n    #[serde(rename = \"net_listening\", with = \"empty_params\")]\n    NetListening(()),\n\n    /// Returns the number of hashes per second with which the node is mining.\n    #[serde(rename = \"eth_hashrate\", with = \"empty_params\")]\n    EthHashrate(()),\n\n    #[serde(rename = \"eth_gasPrice\", with = \"empty_params\")]\n    EthGasPrice(()),\n\n    #[serde(rename = \"eth_maxPriorityFeePerGas\", with = \"empty_params\")]\n    EthMaxPriorityFeePerGas(()),\n\n    #[serde(rename = \"eth_blobBaseFee\", with = \"empty_params\")]\n    EthBlobBaseFee(()),\n\n    #[serde(rename = \"eth_accounts\", alias = \"eth_requestAccounts\", with = \"empty_params\")]\n    EthAccounts(()),\n\n    #[serde(rename = \"eth_blockNumber\", with = \"empty_params\")]\n    EthBlockNumber(()),\n\n    /// Returns the client coinbase address.\n    #[serde(rename = \"eth_coinbase\", with = \"empty_params\")]\n    EthCoinbase(()),\n\n    #[serde(rename = \"eth_getBalance\")]\n    EthGetBalance(Address, Option<BlockId>),\n\n    #[serde(rename = \"eth_getAccount\")]\n    EthGetAccount(Address, Option<BlockId>),\n\n    #[serde(rename = \"eth_getAccountInfo\")]\n    EthGetAccountInfo(Address, Option<BlockId>),\n\n    #[serde(rename = \"eth_getStorageAt\")]\n    EthGetStorageAt(Address, U256, Option<BlockId>),\n\n    #[serde(rename = \"eth_getBlockByHash\")]\n    EthGetBlockByHash(B256, bool),\n\n    #[serde(rename = \"eth_getBlockByNumber\")]\n    EthGetBlockByNumber(\n        #[serde(deserialize_with = \"lenient_block_number::lenient_block_number\")] BlockNumber,\n        bool,\n    ),\n\n    #[serde(rename = \"eth_getTransactionCount\")]\n    EthGetTransactionCount(Address, Option<BlockId>),\n\n    #[serde(rename = \"eth_getBlockTransactionCountByHash\", with = \"sequence\")]\n    EthGetTransactionCountByHash(B256),\n\n    #[serde(\n        rename = \"eth_getBlockTransactionCountByNumber\",\n        deserialize_with = \"lenient_block_number::lenient_block_number_seq\"\n    )]\n    EthGetTransactionCountByNumber(BlockNumber),\n\n    #[serde(rename = \"eth_getUncleCountByBlockHash\", with = \"sequence\")]\n    EthGetUnclesCountByHash(B256),\n\n    #[serde(\n        rename = \"eth_getUncleCountByBlockNumber\",\n        deserialize_with = \"lenient_block_number::lenient_block_number_seq\"\n    )]\n    EthGetUnclesCountByNumber(BlockNumber),\n\n    #[serde(rename = \"eth_getCode\")]\n    EthGetCodeAt(Address, Option<BlockId>),\n\n    /// Returns the account and storage values of the specified account including the Merkle-proof.\n    /// This call can be used to verify that the data you are pulling from is not tampered with.\n    #[serde(rename = \"eth_getProof\")]\n    EthGetProof(Address, Vec<B256>, Option<BlockId>),\n\n    /// The sign method calculates an Ethereum specific signature with:\n    #[serde(rename = \"eth_sign\")]\n    EthSign(Address, Bytes),\n\n    /// The sign method calculates an Ethereum specific signature, equivalent to eth_sign:\n    /// <https://docs.metamask.io/wallet/reference/personal_sign/>\n    #[serde(rename = \"personal_sign\")]\n    PersonalSign(Bytes, Address),\n\n    #[serde(rename = \"eth_signTransaction\", with = \"sequence\")]\n    EthSignTransaction(Box<WithOtherFields<TransactionRequest>>),\n\n    /// Signs data via [EIP-712](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-712.md).\n    #[serde(rename = \"eth_signTypedData\")]\n    EthSignTypedData(Address, serde_json::Value),\n\n    /// Signs data via [EIP-712](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-712.md).\n    #[serde(rename = \"eth_signTypedData_v3\")]\n    EthSignTypedDataV3(Address, serde_json::Value),\n\n    /// Signs data via [EIP-712](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-712.md), and includes full support of arrays and recursive data structures.\n    #[serde(rename = \"eth_signTypedData_v4\")]\n    EthSignTypedDataV4(Address, alloy_dyn_abi::TypedData),\n\n    #[serde(rename = \"eth_sendTransaction\", with = \"sequence\")]\n    EthSendTransaction(Box<WithOtherFields<TransactionRequest>>),\n\n    #[serde(rename = \"eth_sendTransactionSync\", with = \"sequence\")]\n    EthSendTransactionSync(Box<WithOtherFields<TransactionRequest>>),\n\n    #[serde(rename = \"eth_sendRawTransaction\", with = \"sequence\")]\n    EthSendRawTransaction(Bytes),\n\n    #[serde(rename = \"eth_sendRawTransactionSync\", with = \"sequence\")]\n    EthSendRawTransactionSync(Bytes),\n\n    #[serde(rename = \"eth_call\")]\n    EthCall(\n        WithOtherFields<TransactionRequest>,\n        #[serde(default)] Option<BlockId>,\n        #[serde(default)] Option<StateOverride>,\n        #[serde(default)] Option<Box<BlockOverrides>>,\n    ),\n\n    #[serde(rename = \"eth_simulateV1\")]\n    EthSimulateV1(SimulatePayload, #[serde(default)] Option<BlockId>),\n\n    #[serde(rename = \"eth_createAccessList\")]\n    EthCreateAccessList(WithOtherFields<TransactionRequest>, #[serde(default)] Option<BlockId>),\n\n    #[serde(rename = \"eth_estimateGas\")]\n    EthEstimateGas(\n        WithOtherFields<TransactionRequest>,\n        #[serde(default)] Option<BlockId>,\n        #[serde(default)] Option<StateOverride>,\n        #[serde(default)] Option<Box<BlockOverrides>>,\n    ),\n\n    #[serde(rename = \"eth_fillTransaction\", with = \"sequence\")]\n    EthFillTransaction(WithOtherFields<TransactionRequest>),\n\n    #[serde(rename = \"eth_getTransactionByHash\", with = \"sequence\")]\n    EthGetTransactionByHash(TxHash),\n\n    /// Returns the blob for a given blob versioned hash.\n    #[serde(rename = \"anvil_getBlobByHash\", with = \"sequence\")]\n    GetBlobByHash(B256),\n\n    /// Returns the blobs for a given transaction hash.\n    #[serde(rename = \"anvil_getBlobsByTransactionHash\", with = \"sequence\")]\n    GetBlobByTransactionHash(TxHash),\n\n    /// Returns the genesis time for the chain\n    #[serde(rename = \"anvil_getGenesisTime\", with = \"empty_params\")]\n    GetGenesisTime(()),\n\n    #[serde(rename = \"eth_getTransactionByBlockHashAndIndex\")]\n    EthGetTransactionByBlockHashAndIndex(B256, Index),\n\n    #[serde(rename = \"eth_getTransactionByBlockNumberAndIndex\")]\n    EthGetTransactionByBlockNumberAndIndex(BlockNumber, Index),\n\n    #[serde(rename = \"eth_getRawTransactionByHash\", with = \"sequence\")]\n    EthGetRawTransactionByHash(TxHash),\n\n    #[serde(rename = \"eth_getRawTransactionByBlockHashAndIndex\")]\n    EthGetRawTransactionByBlockHashAndIndex(B256, Index),\n\n    #[serde(rename = \"eth_getRawTransactionByBlockNumberAndIndex\")]\n    EthGetRawTransactionByBlockNumberAndIndex(BlockNumber, Index),\n\n    #[serde(rename = \"eth_getTransactionReceipt\", with = \"sequence\")]\n    EthGetTransactionReceipt(B256),\n\n    #[serde(rename = \"eth_getBlockReceipts\", with = \"sequence\")]\n    EthGetBlockReceipts(BlockId),\n\n    #[serde(rename = \"eth_getUncleByBlockHashAndIndex\")]\n    EthGetUncleByBlockHashAndIndex(B256, Index),\n\n    #[serde(rename = \"eth_getUncleByBlockNumberAndIndex\")]\n    EthGetUncleByBlockNumberAndIndex(\n        #[serde(deserialize_with = \"lenient_block_number::lenient_block_number\")] BlockNumber,\n        Index,\n    ),\n\n    #[serde(rename = \"eth_getLogs\", with = \"sequence\")]\n    EthGetLogs(Filter),\n\n    /// Creates a filter object, based on filter options, to notify when the state changes (logs).\n    #[serde(rename = \"eth_newFilter\", with = \"sequence\")]\n    EthNewFilter(Filter),\n\n    /// Polling method for a filter, which returns an array of logs which occurred since last poll.\n    #[serde(rename = \"eth_getFilterChanges\", with = \"sequence\")]\n    EthGetFilterChanges(String),\n\n    /// Creates a filter in the node, to notify when a new block arrives.\n    /// To check if the state has changed, call `eth_getFilterChanges`.\n    #[serde(rename = \"eth_newBlockFilter\", with = \"empty_params\")]\n    EthNewBlockFilter(()),\n\n    /// Creates a filter in the node, to notify when new pending transactions arrive.\n    /// To check if the state has changed, call `eth_getFilterChanges`.\n    #[serde(rename = \"eth_newPendingTransactionFilter\", with = \"empty_params\")]\n    EthNewPendingTransactionFilter(()),\n\n    /// Returns an array of all logs matching filter with given id.\n    #[serde(rename = \"eth_getFilterLogs\", with = \"sequence\")]\n    EthGetFilterLogs(String),\n\n    /// Removes the filter, returns true if the filter was installed\n    #[serde(rename = \"eth_uninstallFilter\", with = \"sequence\")]\n    EthUninstallFilter(String),\n\n    #[serde(rename = \"eth_getWork\", with = \"empty_params\")]\n    EthGetWork(()),\n\n    #[serde(rename = \"eth_submitWork\")]\n    EthSubmitWork(B64, B256, B256),\n\n    #[serde(rename = \"eth_submitHashrate\")]\n    EthSubmitHashRate(U256, B256),\n\n    #[serde(rename = \"eth_feeHistory\")]\n    EthFeeHistory(\n        #[serde(deserialize_with = \"deserialize_number\")] U256,\n        BlockNumber,\n        #[serde(default)] Vec<f64>,\n    ),\n\n    #[serde(rename = \"eth_syncing\", with = \"empty_params\")]\n    EthSyncing(()),\n\n    #[serde(rename = \"eth_config\", with = \"empty_params\")]\n    EthConfig(()),\n\n    /// geth's `debug_getRawTransaction`  endpoint\n    #[serde(rename = \"debug_getRawTransaction\", with = \"sequence\")]\n    DebugGetRawTransaction(TxHash),\n\n    /// geth's `debug_traceTransaction`  endpoint\n    #[serde(rename = \"debug_traceTransaction\")]\n    DebugTraceTransaction(B256, #[serde(default)] GethDebugTracingOptions),\n\n    /// geth's `debug_traceCall`  endpoint\n    #[serde(rename = \"debug_traceCall\")]\n    DebugTraceCall(\n        WithOtherFields<TransactionRequest>,\n        #[serde(default)] Option<BlockId>,\n        #[serde(default)] GethDebugTracingCallOptions,\n    ),\n\n    /// reth's `debug_codeByHash` endpoint\n    #[serde(rename = \"debug_codeByHash\")]\n    DebugCodeByHash(B256, #[serde(default)] Option<BlockId>),\n\n    /// reth's `debug_dbGet` endpoint\n    #[serde(rename = \"debug_dbGet\")]\n    DebugDbGet(String),\n\n    /// Trace transaction endpoint for parity's `trace_transaction`\n    #[serde(rename = \"trace_transaction\", with = \"sequence\")]\n    TraceTransaction(B256),\n\n    /// Trace transaction endpoint for parity's `trace_block`\n    #[serde(\n        rename = \"trace_block\",\n        deserialize_with = \"lenient_block_number::lenient_block_number_seq\"\n    )]\n    TraceBlock(BlockNumber),\n\n    // Return filtered traces over blocks\n    #[serde(rename = \"trace_filter\", with = \"sequence\")]\n    TraceFilter(TraceFilter),\n\n    /// Trace transaction endpoint for parity's `trace_replayBlockTransactions`\n    #[serde(rename = \"trace_replayBlockTransactions\")]\n    TraceReplayBlockTransactions(\n        #[serde(deserialize_with = \"lenient_block_number::lenient_block_number\")] BlockNumber,\n        HashSet<TraceType>,\n    ),\n\n    // Custom endpoints, they're not extracted to a separate type out of serde convenience\n    /// send transactions impersonating specific account and contract addresses.\n    #[serde(\n        rename = \"anvil_impersonateAccount\",\n        alias = \"hardhat_impersonateAccount\",\n        with = \"sequence\"\n    )]\n    ImpersonateAccount(Address),\n    /// Stops impersonating an account if previously set with `anvil_impersonateAccount`\n    #[serde(\n        rename = \"anvil_stopImpersonatingAccount\",\n        alias = \"hardhat_stopImpersonatingAccount\",\n        with = \"sequence\"\n    )]\n    StopImpersonatingAccount(Address),\n    /// Will make every account impersonated\n    #[serde(\n        rename = \"anvil_autoImpersonateAccount\",\n        alias = \"hardhat_autoImpersonateAccount\",\n        with = \"sequence\"\n    )]\n    AutoImpersonateAccount(bool),\n\n    /// Registers a signature/address pair for faking `ecrecover` results\n    #[serde(rename = \"anvil_impersonateSignature\", with = \"sequence\")]\n    ImpersonateSignature(Bytes, Address),\n\n    /// Returns true if automatic mining is enabled, and false.\n    #[serde(rename = \"anvil_getAutomine\", alias = \"hardhat_getAutomine\", with = \"empty_params\")]\n    GetAutoMine(()),\n    /// Mines a series of blocks\n    #[serde(rename = \"anvil_mine\", alias = \"hardhat_mine\")]\n    Mine(\n        /// Number of blocks to mine, if not set `1` block is mined\n        #[serde(default, deserialize_with = \"deserialize_number_opt\")]\n        Option<U256>,\n        /// The time interval between each block in seconds, defaults to `1` seconds\n        /// The interval is applied only to blocks mined in the given method invocation, not to\n        /// blocks mined afterwards. Set this to `0` to instantly mine _all_ blocks\n        #[serde(default, deserialize_with = \"deserialize_number_opt\")]\n        Option<U256>,\n    ),\n\n    /// Enables or disables, based on the single boolean argument, the automatic mining of new\n    /// blocks with each new transaction submitted to the network.\n    #[serde(rename = \"anvil_setAutomine\", alias = \"evm_setAutomine\", with = \"sequence\")]\n    SetAutomine(bool),\n\n    /// Sets the mining behavior to interval with the given interval (seconds)\n    #[serde(rename = \"anvil_setIntervalMining\", alias = \"evm_setIntervalMining\", with = \"sequence\")]\n    SetIntervalMining(u64),\n\n    /// Gets the current mining behavior\n    #[serde(rename = \"anvil_getIntervalMining\", with = \"empty_params\")]\n    GetIntervalMining(()),\n\n    /// Removes transactions from the pool\n    #[serde(rename = \"anvil_dropTransaction\", alias = \"hardhat_dropTransaction\", with = \"sequence\")]\n    DropTransaction(B256),\n\n    /// Removes transactions from the pool\n    #[serde(\n        rename = \"anvil_dropAllTransactions\",\n        alias = \"hardhat_dropAllTransactions\",\n        with = \"empty_params\"\n    )]\n    DropAllTransactions(),\n\n    /// Reset the fork to a fresh forked state, and optionally update the fork config\n    #[serde(rename = \"anvil_reset\", alias = \"hardhat_reset\")]\n    Reset(#[serde(default)] Option<Params<Option<Forking>>>),\n\n    /// Sets the backend rpc url\n    #[serde(rename = \"anvil_setRpcUrl\", with = \"sequence\")]\n    SetRpcUrl(String),\n\n    /// Modifies the balance of an account.\n    #[serde(\n        rename = \"anvil_setBalance\",\n        alias = \"hardhat_setBalance\",\n        alias = \"tenderly_setBalance\"\n    )]\n    SetBalance(Address, #[serde(deserialize_with = \"deserialize_number\")] U256),\n\n    /// Increases the balance of an account.\n    #[serde(\n        rename = \"anvil_addBalance\",\n        alias = \"hardhat_addBalance\",\n        alias = \"tenderly_addBalance\"\n    )]\n    AddBalance(Address, #[serde(deserialize_with = \"deserialize_number\")] U256),\n\n    /// Modifies the ERC20 balance of an account.\n    #[serde(\n        rename = \"anvil_dealERC20\",\n        alias = \"hardhat_dealERC20\",\n        alias = \"anvil_setERC20Balance\"\n    )]\n    DealERC20(Address, Address, #[serde(deserialize_with = \"deserialize_number\")] U256),\n\n    /// Sets the ERC20 allowance for a spender\n    #[serde(rename = \"anvil_setERC20Allowance\")]\n    SetERC20Allowance(\n        Address,\n        Address,\n        Address,\n        #[serde(deserialize_with = \"deserialize_number\")] U256,\n    ),\n\n    /// Sets the code of a contract\n    #[serde(rename = \"anvil_setCode\", alias = \"hardhat_setCode\")]\n    SetCode(Address, Bytes),\n\n    /// Sets the nonce of an address\n    #[serde(rename = \"anvil_setNonce\", alias = \"hardhat_setNonce\", alias = \"evm_setAccountNonce\")]\n    SetNonce(Address, #[serde(deserialize_with = \"deserialize_number\")] U256),\n\n    /// Writes a single slot of the account's storage\n    #[serde(rename = \"anvil_setStorageAt\", alias = \"hardhat_setStorageAt\")]\n    SetStorageAt(\n        Address,\n        /// slot\n        U256,\n        /// value\n        B256,\n    ),\n\n    /// Sets the coinbase address\n    #[serde(rename = \"anvil_setCoinbase\", alias = \"hardhat_setCoinbase\", with = \"sequence\")]\n    SetCoinbase(Address),\n\n    /// Sets the chain id\n    #[serde(rename = \"anvil_setChainId\", with = \"sequence\")]\n    SetChainId(u64),\n\n    /// Enable or disable logging\n    #[serde(\n        rename = \"anvil_setLoggingEnabled\",\n        alias = \"hardhat_setLoggingEnabled\",\n        with = \"sequence\"\n    )]\n    SetLogging(bool),\n\n    /// Set the minimum gas price for the node\n    #[serde(\n        rename = \"anvil_setMinGasPrice\",\n        alias = \"hardhat_setMinGasPrice\",\n        deserialize_with = \"deserialize_number_seq\"\n    )]\n    SetMinGasPrice(U256),\n\n    /// Sets the base fee of the next block\n    #[serde(\n        rename = \"anvil_setNextBlockBaseFeePerGas\",\n        alias = \"hardhat_setNextBlockBaseFeePerGas\",\n        deserialize_with = \"deserialize_number_seq\"\n    )]\n    SetNextBlockBaseFeePerGas(U256),\n\n    /// Sets the specific timestamp\n    /// Accepts timestamp (Unix epoch) with millisecond precision and returns the number of seconds\n    /// between the given timestamp and the current time.\n    #[serde(\n        rename = \"anvil_setTime\",\n        alias = \"evm_setTime\",\n        deserialize_with = \"deserialize_number_seq\"\n    )]\n    EvmSetTime(U256),\n\n    /// Serializes the current state (including contracts code, contract's storage, accounts\n    /// properties, etc.) into a saveable data blob\n    #[serde(rename = \"anvil_dumpState\", alias = \"hardhat_dumpState\")]\n    DumpState(#[serde(default)] Option<Params<Option<bool>>>),\n\n    /// Adds state previously dumped with `DumpState` to the current chain\n    #[serde(rename = \"anvil_loadState\", alias = \"hardhat_loadState\", with = \"sequence\")]\n    LoadState(Bytes),\n\n    /// Retrieves the Anvil node configuration params\n    #[serde(rename = \"anvil_nodeInfo\", with = \"empty_params\")]\n    NodeInfo(()),\n\n    /// Retrieves the Anvil node metadata.\n    #[serde(rename = \"anvil_metadata\", alias = \"hardhat_metadata\", with = \"empty_params\")]\n    AnvilMetadata(()),\n\n    // Ganache compatible calls\n    /// Snapshot the state of the blockchain at the current block.\n    ///\n    /// Ref <https://github.com/trufflesuite/ganache/blob/ef1858d5d6f27e4baeb75cccd57fb3dc77a45ae8/src/chains/ethereum/ethereum/RPC-METHODS.md#evm_snapshot>\n    #[serde(rename = \"anvil_snapshot\", alias = \"evm_snapshot\", with = \"empty_params\")]\n    EvmSnapshot(()),\n\n    /// Revert the state of the blockchain to a previous snapshot.\n    /// Takes a single parameter, which is the snapshot id to revert to.\n    ///\n    /// Ref <https://github.com/trufflesuite/ganache/blob/ef1858d5d6f27e4baeb75cccd57fb3dc77a45ae8/src/chains/ethereum/ethereum/RPC-METHODS.md#evm_revert>\n    #[serde(\n        rename = \"anvil_revert\",\n        alias = \"evm_revert\",\n        deserialize_with = \"deserialize_number_seq\"\n    )]\n    EvmRevert(U256),\n\n    /// Jump forward in time by the given amount of time, in seconds.\n    #[serde(\n        rename = \"anvil_increaseTime\",\n        alias = \"evm_increaseTime\",\n        deserialize_with = \"deserialize_number_seq\"\n    )]\n    EvmIncreaseTime(U256),\n\n    /// Similar to `evm_increaseTime` but takes the exact timestamp that you want in the next block\n    #[serde(\n        rename = \"anvil_setNextBlockTimestamp\",\n        alias = \"evm_setNextBlockTimestamp\",\n        deserialize_with = \"deserialize_number_seq\"\n    )]\n    EvmSetNextBlockTimeStamp(U256),\n\n    /// Set the exact gas limit that you want in the next block\n    #[serde(\n        rename = \"anvil_setBlockGasLimit\",\n        alias = \"evm_setBlockGasLimit\",\n        deserialize_with = \"deserialize_number_seq\"\n    )]\n    EvmSetBlockGasLimit(U256),\n\n    /// Similar to `evm_increaseTime` but takes sets a block timestamp `interval`.\n    ///\n    /// The timestamp of the next block will be computed as `lastBlock_timestamp + interval`.\n    #[serde(rename = \"anvil_setBlockTimestampInterval\", with = \"sequence\")]\n    EvmSetBlockTimeStampInterval(u64),\n\n    /// Removes a `anvil_setBlockTimestampInterval` if it exists\n    #[serde(rename = \"anvil_removeBlockTimestampInterval\", with = \"empty_params\")]\n    EvmRemoveBlockTimeStampInterval(()),\n\n    /// Mine a single block\n    #[serde(rename = \"evm_mine\")]\n    EvmMine(#[serde(default)] Option<Params<Option<MineOptions>>>),\n\n    /// Mine a single block and return detailed data\n    ///\n    /// This behaves exactly as `EvmMine` but returns different output, for compatibility reasons\n    /// this is a separate call since `evm_mine` is not an anvil original.\n    #[serde(rename = \"anvil_mine_detailed\", alias = \"evm_mine_detailed\")]\n    EvmMineDetailed(#[serde(default)] Option<Params<Option<MineOptions>>>),\n\n    /// Execute a transaction regardless of signature status\n    #[serde(rename = \"eth_sendUnsignedTransaction\", with = \"sequence\")]\n    EthSendUnsignedTransaction(Box<WithOtherFields<TransactionRequest>>),\n\n    /// Returns the number of transactions currently pending for inclusion in the next block(s), as\n    /// well as the ones that are being scheduled for future execution only.\n    /// Ref: <https://geth.ethereum.org/docs/rpc/ns-txpool#txpool_status>\n    #[serde(rename = \"txpool_status\", with = \"empty_params\")]\n    TxPoolStatus(()),\n\n    /// Returns a summary of all the transactions currently pending for inclusion in the next\n    /// block(s), as well as the ones that are being scheduled for future execution only.\n    /// Ref: <https://geth.ethereum.org/docs/rpc/ns-txpool#txpool_inspect>\n    #[serde(rename = \"txpool_inspect\", with = \"empty_params\")]\n    TxPoolInspect(()),\n\n    /// Returns the details of all transactions currently pending for inclusion in the next\n    /// block(s), as well as the ones that are being scheduled for future execution only.\n    /// Ref: <https://geth.ethereum.org/docs/rpc/ns-txpool#txpool_content>\n    #[serde(rename = \"txpool_content\", with = \"empty_params\")]\n    TxPoolContent(()),\n\n    /// Otterscan's `ots_getApiLevel` endpoint\n    /// Otterscan currently requires this endpoint, even though it's not part of the ots_*\n    /// <https://github.com/otterscan/otterscan/blob/071d8c55202badf01804f6f8d53ef9311d4a9e47/src/useProvider.ts#L71>\n    /// Related upstream issue: <https://github.com/otterscan/otterscan/issues/1081>\n    #[serde(rename = \"erigon_getHeaderByNumber\")]\n    ErigonGetHeaderByNumber(\n        #[serde(deserialize_with = \"lenient_block_number::lenient_block_number_seq\")] BlockNumber,\n    ),\n\n    /// Otterscan's `ots_getApiLevel` endpoint\n    /// Used as a simple API versioning scheme for the ots_* namespace\n    #[serde(rename = \"ots_getApiLevel\", with = \"empty_params\")]\n    OtsGetApiLevel(()),\n\n    /// Otterscan's `ots_getInternalOperations` endpoint\n    /// Traces internal ETH transfers, contracts creation (CREATE/CREATE2) and self-destructs for a\n    /// certain transaction.\n    #[serde(rename = \"ots_getInternalOperations\", with = \"sequence\")]\n    OtsGetInternalOperations(B256),\n\n    /// Otterscan's `ots_hasCode` endpoint\n    /// Check if an ETH address contains code at a certain block number.\n    #[serde(rename = \"ots_hasCode\")]\n    OtsHasCode(\n        Address,\n        #[serde(deserialize_with = \"lenient_block_number::lenient_block_number\", default)]\n        BlockNumber,\n    ),\n\n    /// Otterscan's `ots_traceTransaction` endpoint\n    /// Trace a transaction and generate a trace call tree.\n    #[serde(rename = \"ots_traceTransaction\", with = \"sequence\")]\n    OtsTraceTransaction(B256),\n\n    /// Otterscan's `ots_getTransactionError` endpoint\n    /// Given a transaction hash, returns its raw revert reason.\n    #[serde(rename = \"ots_getTransactionError\", with = \"sequence\")]\n    OtsGetTransactionError(B256),\n\n    /// Otterscan's `ots_getBlockDetails` endpoint\n    /// Given a block number, return its data. Similar to the standard eth_getBlockByNumber/Hash\n    /// method, but can be optimized by excluding unnecessary data such as transactions and\n    /// logBloom\n    #[serde(rename = \"ots_getBlockDetails\")]\n    OtsGetBlockDetails(\n        #[serde(deserialize_with = \"lenient_block_number::lenient_block_number_seq\", default)]\n        BlockNumber,\n    ),\n\n    /// Otterscan's `ots_getBlockDetails` endpoint\n    /// Same as `ots_getBlockDetails`, but receiving a block hash instead of number\n    #[serde(rename = \"ots_getBlockDetailsByHash\", with = \"sequence\")]\n    OtsGetBlockDetailsByHash(B256),\n\n    /// Otterscan's `ots_getBlockTransactions` endpoint\n    /// Gets paginated transaction data for a certain block. Return data is similar to\n    /// eth_getBlockBy* + eth_getTransactionReceipt.\n    #[serde(rename = \"ots_getBlockTransactions\")]\n    OtsGetBlockTransactions(u64, usize, usize),\n\n    /// Otterscan's `ots_searchTransactionsBefore` endpoint\n    /// Address history navigation. searches backwards from certain point in time.\n    #[serde(rename = \"ots_searchTransactionsBefore\")]\n    OtsSearchTransactionsBefore(Address, u64, usize),\n\n    /// Otterscan's `ots_searchTransactionsAfter` endpoint\n    /// Address history navigation. searches forward from certain point in time.\n    #[serde(rename = \"ots_searchTransactionsAfter\")]\n    OtsSearchTransactionsAfter(Address, u64, usize),\n\n    /// Otterscan's `ots_getTransactionBySenderAndNonce` endpoint\n    /// Given a sender address and a nonce, returns the tx hash or null if not found. It returns\n    /// only the tx hash on success, you can use the standard eth_getTransactionByHash after that\n    /// to get the full transaction data.\n    #[serde(rename = \"ots_getTransactionBySenderAndNonce\")]\n    OtsGetTransactionBySenderAndNonce(\n        Address,\n        #[serde(deserialize_with = \"deserialize_number\")] U256,\n    ),\n\n    /// Returns the transaction by sender and nonce\n    /// Returns the full transaction data.\n    #[serde(rename = \"eth_getTransactionBySenderAndNonce\")]\n    EthGetTransactionBySenderAndNonce(\n        Address,\n        #[serde(deserialize_with = \"deserialize_number\")] U256,\n    ),\n\n    /// Otterscan's `ots_getTransactionBySenderAndNonce` endpoint\n    /// Given an ETH contract address, returns the tx hash and the direct address who created the\n    /// contract.\n    #[serde(rename = \"ots_getContractCreator\", with = \"sequence\")]\n    OtsGetContractCreator(Address),\n\n    /// Removes transactions from the pool by sender origin.\n    #[serde(rename = \"anvil_removePoolTransactions\", with = \"sequence\")]\n    RemovePoolTransactions(Address),\n\n    /// Reorg the chain\n    #[serde(rename = \"anvil_reorg\")]\n    Reorg(ReorgOptions),\n\n    /// Rollback the chain\n    #[serde(rename = \"anvil_rollback\", with = \"sequence\")]\n    Rollback(Option<u64>),\n}\n\n/// Represents ethereum JSON-RPC API\n#[derive(Clone, Debug, PartialEq, Eq, serde::Deserialize)]\n#[serde(tag = \"method\", content = \"params\")]\npub enum EthPubSub {\n    /// Subscribe to an eth subscription\n    #[serde(rename = \"eth_subscribe\")]\n    EthSubscribe(SubscriptionKind, #[serde(default)] Box<SubscriptionParams>),\n\n    /// Unsubscribe from an eth subscription\n    #[serde(rename = \"eth_unsubscribe\", with = \"sequence\")]\n    EthUnSubscribe(SubscriptionId),\n}\n\n/// Container type for either a request or a pub sub\n#[derive(Clone, Debug, serde::Deserialize)]\n#[serde(untagged)]\npub enum EthRpcCall {\n    Request(Box<EthRequest>),\n    PubSub(EthPubSub),\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_web3_client_version() {\n        let s = r#\"{\"method\": \"web3_clientVersion\", \"params\":[]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n    }\n\n    #[test]\n    fn test_web3_sha3() {\n        let s = r#\"{\"method\": \"web3_sha3\", \"params\":[\"0x68656c6c6f20776f726c64\"]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n    }\n\n    #[test]\n    fn test_eth_accounts() {\n        let s = r#\"{\"method\": \"eth_accounts\", \"params\":[]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n    }\n\n    #[test]\n    fn test_eth_network_id() {\n        let s = r#\"{\"method\": \"eth_networkId\", \"params\":[]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n    }\n\n    #[test]\n    fn test_eth_get_proof() {\n        let s = r#\"{\"method\":\"eth_getProof\",\"params\":[\"0x7F0d15C7FAae65896648C8273B6d7E43f58Fa842\",[\"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\"],\"latest\"]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n    }\n\n    #[test]\n    fn test_eth_chain_id() {\n        let s = r#\"{\"method\": \"eth_chainId\", \"params\":[]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n    }\n\n    #[test]\n    fn test_net_listening() {\n        let s = r#\"{\"method\": \"net_listening\", \"params\":[]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n    }\n\n    #[test]\n    fn test_eth_block_number() {\n        let s = r#\"{\"method\": \"eth_blockNumber\", \"params\":[]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n    }\n\n    #[test]\n    fn test_eth_max_priority_fee() {\n        let s = r#\"{\"method\": \"eth_maxPriorityFeePerGas\", \"params\":[]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n    }\n\n    #[test]\n    fn test_eth_syncing() {\n        let s = r#\"{\"method\": \"eth_syncing\", \"params\":[]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n    }\n\n    #[test]\n    fn test_custom_impersonate_account() {\n        let s = r#\"{\"method\": \"anvil_impersonateAccount\", \"params\":\n[\"0xd84de507f3fada7df80908082d3239466db55a71\"]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n    }\n\n    #[test]\n    fn test_custom_stop_impersonate_account() {\n        let s = r#\"{\"method\": \"anvil_stopImpersonatingAccount\",  \"params\":\n[\"0x364d6D0333432C3Ac016Ca832fb8594A8cE43Ca6\"]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n    }\n\n    #[test]\n    fn test_custom_auto_impersonate_account() {\n        let s = r#\"{\"method\": \"anvil_autoImpersonateAccount\",  \"params\": [true]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n    }\n\n    #[test]\n    fn test_custom_get_automine() {\n        let s = r#\"{\"method\": \"anvil_getAutomine\", \"params\": []}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n    }\n\n    #[test]\n    fn test_custom_mine() {\n        let s = r#\"{\"method\": \"anvil_mine\", \"params\": []}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let req = serde_json::from_value::<EthRequest>(value).unwrap();\n        match req {\n            EthRequest::Mine(num, time) => {\n                assert!(num.is_none());\n                assert!(time.is_none());\n            }\n            _ => unreachable!(),\n        }\n        let s = r#\"{\"method\": \"anvil_mine\", \"params\":\n[\"0xd84de507f3fada7df80908082d3239466db55a71\"]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let req = serde_json::from_value::<EthRequest>(value).unwrap();\n        match req {\n            EthRequest::Mine(num, time) => {\n                assert!(num.is_some());\n                assert!(time.is_none());\n            }\n            _ => unreachable!(),\n        }\n        let s = r#\"{\"method\": \"anvil_mine\", \"params\": [\"0xd84de507f3fada7df80908082d3239466db55a71\", \"0xd84de507f3fada7df80908082d3239466db55a71\"]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let req = serde_json::from_value::<EthRequest>(value).unwrap();\n        match req {\n            EthRequest::Mine(num, time) => {\n                assert!(num.is_some());\n                assert!(time.is_some());\n            }\n            _ => unreachable!(),\n        }\n    }\n\n    #[test]\n    fn test_custom_auto_mine() {\n        let s = r#\"{\"method\": \"anvil_setAutomine\", \"params\": [false]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n        let s = r#\"{\"method\": \"evm_setAutomine\", \"params\": [false]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n    }\n\n    #[test]\n    fn test_custom_interval_mining() {\n        let s = r#\"{\"method\": \"anvil_setIntervalMining\", \"params\": [100]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n        let s = r#\"{\"method\": \"evm_setIntervalMining\", \"params\": [100]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n    }\n\n    #[test]\n    fn test_custom_drop_tx() {\n        let s = r#\"{\"method\": \"anvil_dropTransaction\", \"params\":\n[\"0x4a3b0fce2cb9707b0baa68640cf2fe858c8bb4121b2a8cb904ff369d38a560ff\"]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n    }\n\n    #[test]\n    fn test_custom_reset() {\n        let s = r#\"{\"method\": \"anvil_reset\", \"params\": [{\"forking\": {\"jsonRpcUrl\": \"https://ethereumpublicnode.com\",\n        \"blockNumber\": \"18441649\"\n      }\n    }]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let req = serde_json::from_value::<EthRequest>(value).unwrap();\n        match req {\n            EthRequest::Reset(forking) => {\n                let forking = forking.and_then(|f| f.params);\n                assert_eq!(\n                    forking,\n                    Some(Forking {\n                        json_rpc_url: Some(\"https://ethereumpublicnode.com\".into()),\n                        block_number: Some(18441649)\n                    })\n                )\n            }\n            _ => unreachable!(),\n        }\n\n        let s = r#\"{\"method\": \"anvil_reset\", \"params\": [ { \"forking\": {\n                \"jsonRpcUrl\": \"https://eth-mainnet.alchemyapi.io/v2/<key>\",\n                \"blockNumber\": 11095000\n        }}]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let req = serde_json::from_value::<EthRequest>(value).unwrap();\n        match req {\n            EthRequest::Reset(forking) => {\n                let forking = forking.and_then(|f| f.params);\n                assert_eq!(\n                    forking,\n                    Some(Forking {\n                        json_rpc_url: Some(\n                            \"https://eth-mainnet.alchemyapi.io/v2/<key>\".to_string()\n                        ),\n                        block_number: Some(11095000)\n                    })\n                )\n            }\n            _ => unreachable!(),\n        }\n\n        let s = r#\"{\"method\": \"anvil_reset\", \"params\": [ { \"forking\": {\n                \"jsonRpcUrl\": \"https://eth-mainnet.alchemyapi.io/v2/<key>\"\n        }}]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let req = serde_json::from_value::<EthRequest>(value).unwrap();\n        match req {\n            EthRequest::Reset(forking) => {\n                let forking = forking.and_then(|f| f.params);\n                assert_eq!(\n                    forking,\n                    Some(Forking {\n                        json_rpc_url: Some(\n                            \"https://eth-mainnet.alchemyapi.io/v2/<key>\".to_string()\n                        ),\n                        block_number: None\n                    })\n                )\n            }\n            _ => unreachable!(),\n        }\n\n        let s = r#\"{\"method\":\"anvil_reset\",\"params\":[{\"jsonRpcUrl\": \"http://localhost:8545\", \"blockNumber\": 14000000}]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let req = serde_json::from_value::<EthRequest>(value).unwrap();\n        match req {\n            EthRequest::Reset(forking) => {\n                let forking = forking.and_then(|f| f.params);\n                assert_eq!(\n                    forking,\n                    Some(Forking {\n                        json_rpc_url: Some(\"http://localhost:8545\".to_string()),\n                        block_number: Some(14000000)\n                    })\n                )\n            }\n            _ => unreachable!(),\n        }\n\n        let s = r#\"{\"method\":\"anvil_reset\",\"params\":[{ \"blockNumber\": 14000000}]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let req = serde_json::from_value::<EthRequest>(value).unwrap();\n        match req {\n            EthRequest::Reset(forking) => {\n                let forking = forking.and_then(|f| f.params);\n                assert_eq!(\n                    forking,\n                    Some(Forking { json_rpc_url: None, block_number: Some(14000000) })\n                )\n            }\n            _ => unreachable!(),\n        }\n\n        let s = r#\"{\"method\":\"anvil_reset\",\"params\":[{ \"blockNumber\": \"14000000\"}]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let req = serde_json::from_value::<EthRequest>(value).unwrap();\n        match req {\n            EthRequest::Reset(forking) => {\n                let forking = forking.and_then(|f| f.params);\n                assert_eq!(\n                    forking,\n                    Some(Forking { json_rpc_url: None, block_number: Some(14000000) })\n                )\n            }\n            _ => unreachable!(),\n        }\n\n        let s = r#\"{\"method\":\"anvil_reset\",\"params\":[{\"jsonRpcUrl\": \"http://localhost:8545\"}]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let req = serde_json::from_value::<EthRequest>(value).unwrap();\n        match req {\n            EthRequest::Reset(forking) => {\n                let forking = forking.and_then(|f| f.params);\n                assert_eq!(\n                    forking,\n                    Some(Forking {\n                        json_rpc_url: Some(\"http://localhost:8545\".to_string()),\n                        block_number: None\n                    })\n                )\n            }\n            _ => unreachable!(),\n        }\n\n        let s = r#\"{\"method\": \"anvil_reset\"}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let req = serde_json::from_value::<EthRequest>(value).unwrap();\n        match req {\n            EthRequest::Reset(forking) => {\n                assert!(forking.is_none())\n            }\n            _ => unreachable!(),\n        }\n    }\n\n    #[test]\n    fn test_custom_set_balance() {\n        let s = r#\"{\"method\": \"anvil_setBalance\", \"params\":\n[\"0xd84de507f3fada7df80908082d3239466db55a71\", \"0x0\"]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n\n        let s = r#\"{\"method\": \"anvil_setBalance\", \"params\":\n[\"0xd84de507f3fada7df80908082d3239466db55a71\", 1337]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n    }\n\n    #[test]\n    fn test_custom_set_code() {\n        let s = r#\"{\"method\": \"anvil_setCode\", \"params\":\n[\"0xd84de507f3fada7df80908082d3239466db55a71\", \"0x0123456789abcdef\"]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n\n        let s = r#\"{\"method\": \"anvil_setCode\", \"params\":\n[\"0xd84de507f3fada7df80908082d3239466db55a71\", \"0x\"]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n\n        let s = r#\"{\"method\": \"anvil_setCode\", \"params\":\n[\"0xd84de507f3fada7df80908082d3239466db55a71\", \"\"]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n    }\n\n    #[test]\n    fn test_custom_set_nonce() {\n        let s = r#\"{\"method\": \"anvil_setNonce\", \"params\":\n[\"0xd84de507f3fada7df80908082d3239466db55a71\", \"0x0\"]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n        let s = r#\"{\"method\":\n\"hardhat_setNonce\", \"params\": [\"0xd84de507f3fada7df80908082d3239466db55a71\", \"0x0\"]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n        let s = r#\"{\"method\": \"evm_setAccountNonce\", \"params\":\n[\"0xd84de507f3fada7df80908082d3239466db55a71\", \"0x0\"]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n    }\n\n    #[test]\n    fn test_serde_custom_set_storage_at() {\n        let s = r#\"{\"method\": \"anvil_setStorageAt\", \"params\":\n[\"0x295a70b2de5e3953354a6a8344e616ed314d7251\", \"0x0\",\n\"0x0000000000000000000000000000000000000000000000000000000000003039\"]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n\n        let s = r#\"{\"method\": \"hardhat_setStorageAt\", \"params\":\n[\"0xe9e7CEA3DedcA5984780Bafc599bD69ADd087D56\",\n\"0xa6eef7e35abe7026729641147f7915573c7e97b47efa546f5f6e3230263bcb49\",\n\"0x0000000000000000000000000000000000000000000000000000000000003039\"]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n    }\n\n    #[test]\n    fn test_serde_custom_coinbase() {\n        let s = r#\"{\"method\": \"anvil_setCoinbase\", \"params\":\n[\"0x295a70b2de5e3953354a6a8344e616ed314d7251\"]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n    }\n\n    #[test]\n    fn test_serde_custom_logging() {\n        let s = r#\"{\"method\": \"anvil_setLoggingEnabled\", \"params\": [false]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n    }\n\n    #[test]\n    fn test_serde_custom_min_gas_price() {\n        let s = r#\"{\"method\": \"anvil_setMinGasPrice\", \"params\": [\"0x0\"]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n    }\n\n    #[test]\n    fn test_serde_custom_next_block_base_fee() {\n        let s = r#\"{\"method\": \"anvil_setNextBlockBaseFeePerGas\", \"params\": [\"0x0\"]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n    }\n\n    #[test]\n    fn test_serde_set_time() {\n        let s = r#\"{\"method\": \"anvil_setTime\", \"params\": [\"0x0\"]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n\n        let s = r#\"{\"method\": \"anvil_increaseTime\", \"params\": 1}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n    }\n\n    #[test]\n    fn test_serde_custom_dump_state() {\n        let s = r#\"{\"method\": \"anvil_dumpState\", \"params\": [true]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n\n        let s = r#\"{\"method\": \"anvil_dumpState\"}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let req = serde_json::from_value::<EthRequest>(value).unwrap();\n        match req {\n            EthRequest::DumpState(param) => {\n                assert!(param.is_none());\n            }\n            _ => unreachable!(),\n        }\n    }\n\n    #[test]\n    fn test_serde_custom_load_state() {\n        let s = r#\"{\"method\": \"anvil_loadState\", \"params\": [\"0x0001\"] }\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n    }\n\n    #[test]\n    fn test_serde_custom_snapshot() {\n        let s = r#\"{\"method\": \"anvil_snapshot\", \"params\": [] }\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n\n        let s = r#\"{\"method\": \"evm_snapshot\", \"params\": [] }\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n    }\n\n    #[test]\n    fn test_serde_custom_revert() {\n        let s = r#\"{\"method\": \"anvil_revert\", \"params\": [\"0x0\"]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n    }\n\n    #[test]\n    fn test_serde_custom_increase_time() {\n        let s = r#\"{\"method\": \"anvil_increaseTime\", \"params\": [\"0x0\"]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n\n        let s = r#\"{\"method\": \"anvil_increaseTime\", \"params\": [1]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n\n        let s = r#\"{\"method\": \"anvil_increaseTime\", \"params\": 1}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n\n        let s = r#\"{\"method\": \"evm_increaseTime\", \"params\": [\"0x0\"]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n\n        let s = r#\"{\"method\": \"evm_increaseTime\", \"params\": [1]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n\n        let s = r#\"{\"method\": \"evm_increaseTime\", \"params\": 1}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n    }\n\n    #[test]\n    fn test_serde_custom_next_timestamp() {\n        let s = r#\"{\"method\": \"anvil_setNextBlockTimestamp\", \"params\": [100]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n        let s = r#\"{\"method\": \"evm_setNextBlockTimestamp\", \"params\": [100]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n        let s = r#\"{\"method\": \"evm_setNextBlockTimestamp\", \"params\": [\"0x64e0f308\"]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n    }\n\n    #[test]\n    fn test_serde_custom_timestamp_interval() {\n        let s = r#\"{\"method\": \"anvil_setBlockTimestampInterval\", \"params\": [100]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n    }\n\n    #[test]\n    fn test_serde_custom_remove_timestamp_interval() {\n        let s = r#\"{\"method\": \"anvil_removeBlockTimestampInterval\", \"params\": []}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n    }\n\n    #[test]\n    fn test_serde_custom_evm_mine() {\n        let s = r#\"{\"method\": \"evm_mine\", \"params\": [100]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n        let s = r#\"{\"method\": \"evm_mine\", \"params\": [{\n            \"timestamp\": 100,\n            \"blocks\": 100\n        }]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let req = serde_json::from_value::<EthRequest>(value).unwrap();\n        match req {\n            EthRequest::EvmMine(params) => {\n                assert_eq!(\n                    params.unwrap().params.unwrap_or_default(),\n                    MineOptions::Options { timestamp: Some(100), blocks: Some(100) }\n                )\n            }\n            _ => unreachable!(),\n        }\n\n        let s = r#\"{\"method\": \"evm_mine\"}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let req = serde_json::from_value::<EthRequest>(value).unwrap();\n\n        match req {\n            EthRequest::EvmMine(params) => {\n                assert!(params.is_none())\n            }\n            _ => unreachable!(),\n        }\n\n        let s = r#\"{\"method\": \"evm_mine\", \"params\": []}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n    }\n\n    #[test]\n    fn test_serde_custom_evm_mine_detailed() {\n        let s = r#\"{\"method\": \"anvil_mine_detailed\", \"params\": [100]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n        let s = r#\"{\"method\": \"anvil_mine_detailed\", \"params\": [{\n            \"timestamp\": 100,\n            \"blocks\": 100\n        }]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let req = serde_json::from_value::<EthRequest>(value).unwrap();\n        match req {\n            EthRequest::EvmMineDetailed(params) => {\n                assert_eq!(\n                    params.unwrap().params.unwrap_or_default(),\n                    MineOptions::Options { timestamp: Some(100), blocks: Some(100) }\n                )\n            }\n            _ => unreachable!(),\n        }\n\n        let s = r#\"{\"method\": \"evm_mine_detailed\"}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let req = serde_json::from_value::<EthRequest>(value).unwrap();\n\n        match req {\n            EthRequest::EvmMineDetailed(params) => {\n                assert!(params.is_none())\n            }\n            _ => unreachable!(),\n        }\n\n        let s = r#\"{\"method\": \"anvil_mine_detailed\", \"params\": []}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n    }\n\n    #[test]\n    fn test_serde_custom_evm_mine_hex() {\n        let s = r#\"{\"method\": \"evm_mine\", \"params\": [\"0x63b6ff08\"]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let req = serde_json::from_value::<EthRequest>(value).unwrap();\n        match req {\n            EthRequest::EvmMine(params) => {\n                assert_eq!(\n                    params.unwrap().params.unwrap_or_default(),\n                    MineOptions::Timestamp(Some(1672937224))\n                )\n            }\n            _ => unreachable!(),\n        }\n\n        let s = r#\"{\"method\": \"evm_mine\", \"params\": [{\"timestamp\": \"0x63b6ff08\"}]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let req = serde_json::from_value::<EthRequest>(value).unwrap();\n        match req {\n            EthRequest::EvmMine(params) => {\n                assert_eq!(\n                    params.unwrap().params.unwrap_or_default(),\n                    MineOptions::Options { timestamp: Some(1672937224), blocks: None }\n                )\n            }\n            _ => unreachable!(),\n        }\n    }\n\n    #[test]\n    fn test_eth_uncle_count_by_block_hash() {\n        let s = r#\"{\"jsonrpc\":\"2.0\",\"method\":\"eth_getUncleCountByBlockHash\",\"params\":[\"0x4a3b0fce2cb9707b0baa68640cf2fe858c8bb4121b2a8cb904ff369d38a560ff\"]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n    }\n\n    #[test]\n    fn test_eth_block_tx_count_by_block_hash() {\n        let s = r#\"{\"jsonrpc\":\"2.0\",\"method\":\"eth_getBlockTransactionCountByHash\",\"params\":[\"0x4a3b0fce2cb9707b0baa68640cf2fe858c8bb4121b2a8cb904ff369d38a560ff\"]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n    }\n\n    #[test]\n    fn test_eth_get_logs() {\n        let s = r#\"{\"jsonrpc\":\"2.0\",\"method\":\"eth_getLogs\",\"params\":[{\"topics\":[\"0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b\"]}],\"id\":74}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n    }\n\n    #[test]\n    fn test_eth_new_filter() {\n        let s = r#\"{\"method\": \"eth_newFilter\", \"params\": [{\"topics\":[\"0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b\"]}],\"id\":73}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n    }\n\n    #[test]\n    fn test_serde_eth_unsubscribe() {\n        let s = r#\"{\"id\": 1, \"method\": \"eth_unsubscribe\", \"params\":\n[\"0x9cef478923ff08bf67fde6c64013158d\"]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthPubSub>(value).unwrap();\n    }\n\n    #[test]\n    fn test_serde_eth_subscribe() {\n        let s = r#\"{\"id\": 1, \"method\": \"eth_subscribe\", \"params\": [\"newHeads\"]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthPubSub>(value).unwrap();\n\n        let s = r#\"{\"id\": 1, \"method\": \"eth_subscribe\", \"params\": [\"logs\", {\"address\":\n\"0x8320fe7702b96808f7bbc0d4a888ed1468216cfd\", \"topics\":\n[\"0xd78a0cb8bb633d06981248b816e7bd33c2a35a6089241d099fa519e361cab902\"]}]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthPubSub>(value).unwrap();\n\n        let s = r#\"{\"id\": 1, \"method\": \"eth_subscribe\", \"params\": [\"newPendingTransactions\"]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthPubSub>(value).unwrap();\n\n        let s = r#\"{\"id\": 1, \"method\": \"eth_subscribe\", \"params\": [\"syncing\"]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthPubSub>(value).unwrap();\n    }\n\n    #[test]\n    fn test_serde_debug_raw_transaction() {\n        let s = r#\"{\"jsonrpc\":\"2.0\",\"method\":\"debug_getRawTransaction\",\"params\":[\"0x3ed3a89bc10115a321aee238c02de214009f8532a65368e5df5eaf732ee7167c\"],\"id\":1}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n\n        let s = r#\"{\"jsonrpc\":\"2.0\",\"method\":\"eth_getRawTransactionByHash\",\"params\":[\"0x3ed3a89bc10115a321aee238c02de214009f8532a65368e5df5eaf732ee7167c\"],\"id\":1}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n\n        let s = r#\"{\"jsonrpc\":\"2.0\",\"method\":\"eth_getRawTransactionByBlockHashAndIndex\",\"params\":[\"0x3ed3a89bc10115a321aee238c02de214009f8532a65368e5df5eaf732ee7167c\",1],\"id\":1}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n\n        let s = r#\"{\"jsonrpc\":\"2.0\",\"method\":\"eth_getRawTransactionByBlockNumberAndIndex\",\"params\":[\"0x3ed3a89b\",0],\"id\":1}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n    }\n\n    #[test]\n    fn test_serde_debug_trace_transaction() {\n        let s = r#\"{\"method\": \"debug_traceTransaction\", \"params\":\n[\"0x4a3b0fce2cb9707b0baa68640cf2fe858c8bb4121b2a8cb904ff369d38a560ff\"]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n\n        let s = r#\"{\"method\": \"debug_traceTransaction\", \"params\":\n[\"0x4a3b0fce2cb9707b0baa68640cf2fe858c8bb4121b2a8cb904ff369d38a560ff\", {}]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n\n        let s = r#\"{\"method\": \"debug_traceTransaction\", \"params\":\n[\"0x4a3b0fce2cb9707b0baa68640cf2fe858c8bb4121b2a8cb904ff369d38a560ff\", {\"disableStorage\":\ntrue}]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n    }\n\n    #[test]\n    fn test_serde_debug_trace_call() {\n        let s = r#\"{\"method\": \"debug_traceCall\", \"params\": [{\"data\":\"0xcfae3217\",\"from\":\"0xd84de507f3fada7df80908082d3239466db55a71\",\"to\":\"0xcbe828fdc46e3b1c351ec90b1a5e7d9742c0398d\"}]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n\n        let s = r#\"{\"method\": \"debug_traceCall\", \"params\": [{\"data\":\"0xcfae3217\",\"from\":\"0xd84de507f3fada7df80908082d3239466db55a71\",\"to\":\"0xcbe828fdc46e3b1c351ec90b1a5e7d9742c0398d\"}, { \"blockNumber\": \"latest\" }]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n\n        let s = r#\"{\"method\": \"debug_traceCall\", \"params\": [{\"data\":\"0xcfae3217\",\"from\":\"0xd84de507f3fada7df80908082d3239466db55a71\",\"to\":\"0xcbe828fdc46e3b1c351ec90b1a5e7d9742c0398d\"}, { \"blockNumber\": \"0x0\" }]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n\n        let s = r#\"{\"method\": \"debug_traceCall\", \"params\": [{\"data\":\"0xcfae3217\",\"from\":\"0xd84de507f3fada7df80908082d3239466db55a71\",\"to\":\"0xcbe828fdc46e3b1c351ec90b1a5e7d9742c0398d\"}, { \"blockHash\": \"0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3\" }]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n\n        let s = r#\"{\"method\": \"debug_traceCall\", \"params\": [{\"data\":\"0xcfae3217\",\"from\":\"0xd84de507f3fada7df80908082d3239466db55a71\",\"to\":\"0xcbe828fdc46e3b1c351ec90b1a5e7d9742c0398d\"}, { \"blockNumber\": \"0x0\" }, {\"disableStorage\": true}]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n    }\n\n    #[test]\n    fn test_serde_eth_storage() {\n        let s = r#\"{\"method\": \"eth_getStorageAt\", \"params\":\n[\"0x295a70b2de5e3953354a6a8344e616ed314d7251\", \"0x0\", \"latest\"]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n    }\n\n    #[test]\n    fn test_eth_call() {\n        let req = r#\"{\"data\":\"0xcfae3217\",\"from\":\"0xd84de507f3fada7df80908082d3239466db55a71\",\"to\":\"0xcbe828fdc46e3b1c351ec90b1a5e7d9742c0398d\"}\"#;\n        let _req = serde_json::from_str::<TransactionRequest>(req).unwrap();\n\n        let s = r#\"{\"method\": \"eth_call\", \"params\":[{\"data\":\"0xcfae3217\",\"from\":\"0xd84de507f3fada7df80908082d3239466db55a71\",\"to\":\"0xcbe828fdc46e3b1c351ec90b1a5e7d9742c0398d\"},\"latest\"]}\"#;\n        let _req = serde_json::from_str::<EthRequest>(s).unwrap();\n\n        let s = r#\"{\"method\": \"eth_call\", \"params\":[{\"data\":\"0xcfae3217\",\"from\":\"0xd84de507f3fada7df80908082d3239466db55a71\",\"to\":\"0xcbe828fdc46e3b1c351ec90b1a5e7d9742c0398d\"}]}\"#;\n        let _req = serde_json::from_str::<EthRequest>(s).unwrap();\n\n        let s = r#\"{\"method\": \"eth_call\", \"params\":[{\"data\":\"0xcfae3217\",\"from\":\"0xd84de507f3fada7df80908082d3239466db55a71\",\"to\":\"0xcbe828fdc46e3b1c351ec90b1a5e7d9742c0398d\"}, { \"blockNumber\": \"latest\" }]}\"#;\n        let _req = serde_json::from_str::<EthRequest>(s).unwrap();\n\n        let s = r#\"{\"method\": \"eth_call\", \"params\":[{\"data\":\"0xcfae3217\",\"from\":\"0xd84de507f3fada7df80908082d3239466db55a71\",\"to\":\"0xcbe828fdc46e3b1c351ec90b1a5e7d9742c0398d\"}, { \"blockNumber\": \"0x0\" }]}\"#;\n        let _req = serde_json::from_str::<EthRequest>(s).unwrap();\n\n        let s = r#\"{\"method\": \"eth_call\", \"params\":[{\"data\":\"0xcfae3217\",\"from\":\"0xd84de507f3fada7df80908082d3239466db55a71\",\"to\":\"0xcbe828fdc46e3b1c351ec90b1a5e7d9742c0398d\"}, { \"blockHash\":\"0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3\" }]}\"#;\n        let _req = serde_json::from_str::<EthRequest>(s).unwrap();\n    }\n\n    #[test]\n    fn test_serde_eth_balance() {\n        let s = r#\"{\"method\": \"eth_getBalance\", \"params\":\n[\"0x295a70b2de5e3953354a6a8344e616ed314d7251\", \"latest\"]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n    }\n\n    #[test]\n    fn test_serde_eth_block_by_number() {\n        let s = r#\"{\"method\": \"eth_getBlockByNumber\", \"params\": [\"0x0\", true]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n        let s = r#\"{\"method\": \"eth_getBlockByNumber\", \"params\": [\"latest\", true]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n        let s = r#\"{\"method\": \"eth_getBlockByNumber\", \"params\": [\"earliest\", true]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n        let s = r#\"{\"method\": \"eth_getBlockByNumber\", \"params\": [\"pending\", true]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n\n        // this case deviates from the spec, but we're supporting this for legacy reasons: <https://github.com/foundry-rs/foundry/issues/1868>\n        let s = r#\"{\"method\": \"eth_getBlockByNumber\", \"params\": [0, true]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n    }\n\n    #[test]\n    fn test_eth_sign() {\n        let s = r#\"{\"method\": \"eth_sign\", \"params\":\n[\"0xd84de507f3fada7df80908082d3239466db55a71\", \"0x00\"]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n        let s = r#\"{\"method\": \"personal_sign\", \"params\":\n[\"0x00\", \"0xd84de507f3fada7df80908082d3239466db55a71\"]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n    }\n\n    #[test]\n    fn test_eth_sign_typed_data() {\n        let s = r#\"{\"method\":\"eth_signTypedData_v4\",\"params\":[\"0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826\", {\"types\":{\"EIP712Domain\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"version\",\"type\":\"string\"},{\"name\":\"chainId\",\"type\":\"uint256\"},{\"name\":\"verifyingContract\",\"type\":\"address\"}],\"Person\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"wallet\",\"type\":\"address\"}],\"Mail\":[{\"name\":\"from\",\"type\":\"Person\"},{\"name\":\"to\",\"type\":\"Person\"},{\"name\":\"contents\",\"type\":\"string\"}]},\"primaryType\":\"Mail\",\"domain\":{\"name\":\"Ether Mail\",\"version\":\"1\",\"chainId\":1,\"verifyingContract\":\"0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC\"},\"message\":{\"from\":{\"name\":\"Cow\",\"wallet\":\"0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826\"},\"to\":{\"name\":\"Bob\",\"wallet\":\"0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB\"},\"contents\":\"Hello, Bob!\"}}]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n    }\n\n    #[test]\n    fn test_remove_pool_transactions() {\n        let s = r#\"{\"method\": \"anvil_removePoolTransactions\",  \"params\":[\"0x364d6D0333432C3Ac016Ca832fb8594A8cE43Ca6\"]}\"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n    }\n\n    #[test]\n    fn test_serde_anvil_reorg() {\n        // TransactionData::JSON\n        let s = r#\"\n        {\n            \"method\": \"anvil_reorg\",\n            \"params\": [\n                5,\n                [\n                    [\n                        {\n                            \"from\": \"0x976EA74026E726554dB657fA54763abd0C3a0aa9\",\n                            \"to\": \"0x1199bc69f16FDD6690DC40339EC445FaE1b6DD11\",\n                            \"value\": 100\n                        },\n                        1\n                    ],\n                    [\n                        {\n                            \"from\": \"0x976EA74026E726554dB657fA54763abd0C3a0aa9\",\n                            \"to\": \"0x1199bc69f16FDD6690DC40339EC445FaE1b6DD11\",\n                            \"value\": 200\n                        },\n                        2\n                    ]\n                ]\n            ]\n        }\n        \"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n        // TransactionData::Raw\n        let s = r#\"\n        {\n            \"method\": \"anvil_reorg\",\n            \"params\": [\n                5,\n                [\n                    [\n                        \"0x19d55c67e1ba8f1bbdfed75f8ad524ebf087e4ecb848a2d19881d7a5e3d2c54e1732cb1b462da3b3fdb05bdf4c4d3c8e3c9fcebdc2ab5fa5d59a3f752888f27e1b\",\n                        1\n                    ]\n                ]\n            ]\n        }\n        \"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n        // TransactionData::Raw and TransactionData::JSON\n        let s = r#\"\n        {\n            \"method\": \"anvil_reorg\",\n            \"params\": [\n                5,\n                [\n                    [\n                        \"0x19d55c67e1ba8f1bbdfed75f8ad524ebf087e4ecb848a2d19881d7a5e3d2c54e1732cb1b462da3b3fdb05bdf4c4d3c8e3c9fcebdc2ab5fa5d59a3f752888f27e1b\",\n                        1\n                    ],\n                    [\n                        {\n                            \"from\": \"0x976EA74026E726554dB657fA54763abd0C3a0aa9\",\n                            \"to\": \"0x1199bc69f16FDD6690DC40339EC445FaE1b6DD11\",\n                            \"value\": 200\n                        },\n                        2\n                    ]\n                ]\n            ]\n        }\n        \"#;\n        let value: serde_json::Value = serde_json::from_str(s).unwrap();\n        let _req = serde_json::from_value::<EthRequest>(value).unwrap();\n    }\n}\n"
  },
  {
    "path": "crates/anvil/core/src/eth/serde_helpers.rs",
    "content": "//! custom serde helper functions\n\npub mod sequence {\n    use serde::{\n        Deserialize, Deserializer, Serialize, Serializer, de::DeserializeOwned, ser::SerializeSeq,\n    };\n\n    pub fn serialize<S, T>(val: &T, s: S) -> Result<S::Ok, S::Error>\n    where\n        S: Serializer,\n        T: Serialize,\n    {\n        let mut seq = s.serialize_seq(Some(1))?;\n        seq.serialize_element(val)?;\n        seq.end()\n    }\n\n    pub fn deserialize<'de, T, D>(d: D) -> Result<T, D::Error>\n    where\n        D: Deserializer<'de>,\n        T: DeserializeOwned,\n    {\n        let mut seq = Vec::<T>::deserialize(d)?;\n        if seq.len() != 1 {\n            return Err(serde::de::Error::custom(format!(\n                \"expected params sequence with length 1 but got {}\",\n                seq.len()\n            )));\n        }\n        Ok(seq.remove(0))\n    }\n}\n\n/// A module that deserializes `[]` optionally\npub mod empty_params {\n    use serde::{Deserialize, Deserializer};\n\n    pub fn deserialize<'de, D>(d: D) -> Result<(), D::Error>\n    where\n        D: Deserializer<'de>,\n    {\n        let seq = Option::<Vec<()>>::deserialize(d)?.unwrap_or_default();\n        if !seq.is_empty() {\n            return Err(serde::de::Error::custom(format!(\n                \"expected params sequence with length 0 but got {}\",\n                seq.len()\n            )));\n        }\n        Ok(())\n    }\n}\n\n/// A module that deserializes either a BlockNumberOrTag, or a simple number.\npub mod lenient_block_number {\n    pub use alloy_eips::eip1898::LenientBlockNumberOrTag;\n    use alloy_rpc_types::BlockNumberOrTag;\n    use serde::{Deserialize, Deserializer};\n\n    /// deserializes either a BlockNumberOrTag, or a simple number.\n    pub use alloy_eips::eip1898::lenient_block_number_or_tag::deserialize as lenient_block_number;\n\n    /// Same as `lenient_block_number` but requires to be `[num; 1]`\n    pub fn lenient_block_number_seq<'de, D>(deserializer: D) -> Result<BlockNumberOrTag, D::Error>\n    where\n        D: Deserializer<'de>,\n    {\n        let num = <[LenientBlockNumberOrTag; 1]>::deserialize(deserializer)?[0].into();\n        Ok(num)\n    }\n}\n"
  },
  {
    "path": "crates/anvil/core/src/eth/subscription.rs",
    "content": "//! Subscription types\nuse alloy_primitives::hex;\nuse rand::{Rng, distr::Alphanumeric, rng};\nuse std::fmt;\n\n/// Unique subscription id\n#[derive(Clone, PartialEq, Eq, Hash, serde::Deserialize, serde::Serialize)]\n#[serde(untagged)]\npub enum SubscriptionId {\n    /// numerical sub id\n    Number(u64),\n    /// string sub id, a hash for example\n    String(String),\n}\n\nimpl SubscriptionId {\n    /// Generates a new random hex identifier\n    pub fn random_hex() -> Self {\n        Self::String(hex_id())\n    }\n}\n\nimpl fmt::Display for SubscriptionId {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        match self {\n            Self::Number(num) => num.fmt(f),\n            Self::String(s) => s.fmt(f),\n        }\n    }\n}\n\nimpl fmt::Debug for SubscriptionId {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        match self {\n            Self::Number(num) => num.fmt(f),\n            Self::String(s) => s.fmt(f),\n        }\n    }\n}\n\n/// Provides random hex identifier with a certain length\n#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]\npub struct HexIdProvider {\n    len: usize,\n}\n\nimpl HexIdProvider {\n    /// Generates a random hex encoded Id\n    pub fn generate(&self) -> String {\n        let id: String =\n            (&mut rng()).sample_iter(Alphanumeric).map(char::from).take(self.len).collect();\n        let out = hex::encode(id);\n        format!(\"0x{out}\")\n    }\n}\n\nimpl Default for HexIdProvider {\n    fn default() -> Self {\n        Self { len: 16 }\n    }\n}\n\n/// Returns a new random hex identifier\npub fn hex_id() -> String {\n    HexIdProvider::default().generate()\n}\n"
  },
  {
    "path": "crates/anvil/core/src/eth/transaction/mod.rs",
    "content": "//! Transaction related types\nuse alloy_consensus::{\n    Transaction, Typed2718,\n    crypto::RecoveryError,\n    transaction::{SignerRecoverable, TxHashRef},\n};\n\nuse alloy_eips::eip2718::Encodable2718;\nuse alloy_primitives::{Address, B256, Bytes, TxHash};\nuse alloy_rlp::{Decodable, Encodable};\nuse bytes::BufMut;\nuse foundry_evm::traces::CallTraceNode;\nuse foundry_primitives::FoundryTxEnvelope;\nuse revm::interpreter::InstructionResult;\nuse serde::{Deserialize, Serialize};\nuse std::ops::Deref;\n\n/// A wrapper for a transaction envelope that allows impersonating accounts.\n///\n/// This is a helper that carries the `impersonated` sender so that the right hash\n/// can be created.\n#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]\npub struct MaybeImpersonatedTransaction<T> {\n    transaction: T,\n    impersonated_sender: Option<Address>,\n}\n\nimpl<T: Typed2718> Typed2718 for MaybeImpersonatedTransaction<T> {\n    fn ty(&self) -> u8 {\n        self.transaction.ty()\n    }\n}\n\nimpl<T> MaybeImpersonatedTransaction<T> {\n    /// Creates a new wrapper for the given transaction\n    pub fn new(transaction: T) -> Self {\n        Self { transaction, impersonated_sender: None }\n    }\n\n    /// Creates a new impersonated transaction wrapper using the given sender\n    pub fn impersonated(transaction: T, impersonated_sender: Address) -> Self {\n        Self { transaction, impersonated_sender: Some(impersonated_sender) }\n    }\n\n    /// Returns whether the transaction is impersonated\n    pub fn is_impersonated(&self) -> bool {\n        self.impersonated_sender.is_some()\n    }\n\n    /// Returns the inner transaction.\n    pub fn into_inner(self) -> T {\n        self.transaction\n    }\n}\n\nimpl<T: SignerRecoverable + TxHashRef + Encodable> MaybeImpersonatedTransaction<T> {\n    /// Recovers the Ethereum address which was used to sign the transaction.\n    pub fn recover(&self) -> Result<Address, RecoveryError> {\n        if let Some(sender) = self.impersonated_sender {\n            return Ok(sender);\n        }\n        self.transaction.recover_signer()\n    }\n\n    /// Returns the hash of the transaction.\n    ///\n    /// If the transaction is impersonated, returns a unique hash derived by appending the\n    /// impersonated sender address to the encoded transaction before hashing.\n    pub fn hash(&self) -> B256 {\n        if let Some(sender) = self.impersonated_sender {\n            let mut buffer = Vec::new();\n            self.transaction.encode(&mut buffer);\n            buffer.extend_from_slice(sender.as_ref());\n            return B256::from_slice(alloy_primitives::utils::keccak256(&buffer).as_slice());\n        }\n        *self.transaction.tx_hash()\n    }\n}\n\nimpl<T: Encodable2718> Encodable2718 for MaybeImpersonatedTransaction<T> {\n    fn encode_2718_len(&self) -> usize {\n        self.transaction.encode_2718_len()\n    }\n\n    fn encode_2718(&self, out: &mut dyn BufMut) {\n        self.transaction.encode_2718(out)\n    }\n}\n\nimpl<T: Encodable> Encodable for MaybeImpersonatedTransaction<T> {\n    fn encode(&self, out: &mut dyn bytes::BufMut) {\n        self.transaction.encode(out)\n    }\n}\n\nimpl From<MaybeImpersonatedTransaction<Self>> for FoundryTxEnvelope {\n    fn from(value: MaybeImpersonatedTransaction<Self>) -> Self {\n        value.transaction\n    }\n}\n\nimpl From<FoundryTxEnvelope> for MaybeImpersonatedTransaction<FoundryTxEnvelope> {\n    fn from(value: FoundryTxEnvelope) -> Self {\n        Self::new(value)\n    }\n}\n\nimpl<T: Decodable> Decodable for MaybeImpersonatedTransaction<T> {\n    fn decode(buf: &mut &[u8]) -> alloy_rlp::Result<Self> {\n        T::decode(buf).map(Self::new)\n    }\n}\n\nimpl<T> AsRef<T> for MaybeImpersonatedTransaction<T> {\n    fn as_ref(&self) -> &T {\n        &self.transaction\n    }\n}\n\nimpl<T> Deref for MaybeImpersonatedTransaction<T> {\n    type Target = T;\n\n    fn deref(&self) -> &Self::Target {\n        &self.transaction\n    }\n}\n\n/// Queued transaction\n#[derive(Clone, Debug, PartialEq, Eq)]\npub struct PendingTransaction<T> {\n    /// The actual transaction\n    pub transaction: MaybeImpersonatedTransaction<T>,\n    /// the recovered sender of this transaction\n    sender: Address,\n    /// hash of `transaction`, so it can easily be reused with encoding and hashing again\n    hash: TxHash,\n}\n\nimpl<T> PendingTransaction<T> {\n    pub fn hash(&self) -> &TxHash {\n        &self.hash\n    }\n\n    pub fn sender(&self) -> &Address {\n        &self.sender\n    }\n}\n\nimpl<T: SignerRecoverable + TxHashRef + Encodable> PendingTransaction<T> {\n    pub fn new(transaction: T) -> Result<Self, RecoveryError> {\n        let transaction = MaybeImpersonatedTransaction::new(transaction);\n        let sender = transaction.recover()?;\n        let hash = transaction.hash();\n        Ok(Self { transaction, sender, hash })\n    }\n\n    pub fn with_impersonated(transaction: T, sender: Address) -> Self {\n        let transaction = MaybeImpersonatedTransaction::impersonated(transaction, sender);\n        let hash = transaction.hash();\n        Self { transaction, sender, hash }\n    }\n\n    /// Converts a [`MaybeImpersonatedTransaction`] into a [`PendingTransaction`].\n    pub fn from_maybe_impersonated(\n        transaction: MaybeImpersonatedTransaction<T>,\n    ) -> Result<Self, RecoveryError> {\n        if let Some(impersonated) = transaction.impersonated_sender {\n            Ok(Self::with_impersonated(transaction.transaction, impersonated))\n        } else {\n            Self::new(transaction.transaction)\n        }\n    }\n}\n\nimpl<T: Transaction> PendingTransaction<T> {\n    pub fn nonce(&self) -> u64 {\n        self.transaction.nonce()\n    }\n}\n\n/// Represents all relevant information of an executed transaction\n#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]\npub struct TransactionInfo {\n    pub transaction_hash: B256,\n    pub transaction_index: u64,\n    pub from: Address,\n    pub to: Option<Address>,\n    pub contract_address: Option<Address>,\n    pub traces: Vec<CallTraceNode>,\n    pub exit: InstructionResult,\n    pub out: Option<Bytes>,\n    pub nonce: u64,\n    pub gas_used: u64,\n}\n"
  },
  {
    "path": "crates/anvil/core/src/eth/wallet.rs",
    "content": "pub use alloy_eip5792::*;\n\n#[derive(Debug, thiserror::Error)]\npub enum WalletError {\n    /// The transaction value is not 0.\n    ///\n    /// The value should be 0 to prevent draining the sequencer.\n    #[error(\"transaction value must be zero for delegated transactions\")]\n    ValueNotZero,\n    /// The from field is set on the transaction.\n    ///\n    /// Requests with the from field are rejected, since it is implied that it will always be the\n    /// sequencer.\n    #[error(\"transaction 'from' field should not be set for delegated transactions\")]\n    FromSet,\n    /// The nonce field is set on the transaction.\n    ///\n    /// Requests with the nonce field set are rejected, as this is managed by the sequencer.\n    #[error(\"transaction nonce should not be set for delegated transactions\")]\n    NonceSet,\n    /// An authorization item was invalid.\n    ///\n    /// The item is invalid if it tries to delegate an account to a contract that is not\n    /// whitelisted.\n    #[error(\"invalid authorization address: contract is not whitelisted for delegation\")]\n    InvalidAuthorization,\n    /// The to field of the transaction was invalid.\n    ///\n    /// The destination is invalid if:\n    ///\n    /// - There is no bytecode at the destination, or\n    /// - The bytecode is not an EIP-7702 delegation designator, or\n    /// - The delegation designator points to a contract that is not whitelisted\n    #[error(\"transaction destination is not a valid delegated account\")]\n    IllegalDestination,\n    /// The transaction request was invalid.\n    ///\n    /// This is likely an internal error, as most of the request is built by the sequencer.\n    #[error(\"invalid transaction request format\")]\n    InvalidTransactionRequest,\n    /// An internal error occurred.\n    #[error(\"internal server error occurred\")]\n    InternalError,\n}\n"
  },
  {
    "path": "crates/anvil/core/src/lib.rs",
    "content": "//! # anvil-core\n//!\n//! Core Ethereum types for Anvil.\n\n#![cfg_attr(not(test), warn(unused_crate_dependencies))]\n#![cfg_attr(docsrs, feature(doc_cfg))]\n\n/// Various Ethereum types\npub mod eth;\n\n/// Additional useful types\npub mod types;\n"
  },
  {
    "path": "crates/anvil/core/src/types.rs",
    "content": "use alloy_primitives::Bytes;\nuse alloy_rpc_types::TransactionRequest;\nuse serde::Deserialize;\n\n/// Represents the options used in `anvil_reorg`\n#[derive(Debug, Clone, Deserialize)]\npub struct ReorgOptions {\n    // The depth of the reorg\n    pub depth: u64,\n    // List of transaction requests and blocks pairs to be mined into the new chain\n    pub tx_block_pairs: Vec<(TransactionData, u64)>,\n}\n\n#[derive(Debug, Clone, Deserialize)]\n#[serde(untagged)]\n#[expect(clippy::large_enum_variant)]\npub enum TransactionData {\n    JSON(TransactionRequest),\n    Raw(Bytes),\n}\n"
  },
  {
    "path": "crates/anvil/rpc/Cargo.toml",
    "content": "[package]\nname = \"anvil-rpc\"\n\nversion.workspace = true\nedition.workspace = true\nrust-version.workspace = true\nauthors.workspace = true\nlicense.workspace = true\nhomepage.workspace = true\nrepository.workspace = true\n\n[lints]\nworkspace = true\n\n[dependencies]\nserde.workspace = true\nserde_json.workspace = true\n"
  },
  {
    "path": "crates/anvil/rpc/src/error.rs",
    "content": "//! JSON-RPC error bindings\nuse serde::{Deserialize, Deserializer, Serialize, Serializer};\nuse std::{borrow::Cow, fmt};\n\n/// Represents a JSON-RPC error\n#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]\n#[serde(deny_unknown_fields)]\npub struct RpcError {\n    pub code: ErrorCode,\n    /// error message\n    pub message: Cow<'static, str>,\n    #[serde(skip_serializing_if = \"Option::is_none\")]\n    pub data: Option<serde_json::Value>,\n}\n\nimpl RpcError {\n    /// New [`RpcError`] with the given [`ErrorCode`].\n    pub const fn new(code: ErrorCode) -> Self {\n        Self { message: Cow::Borrowed(code.message()), code, data: None }\n    }\n\n    /// Creates a new `ParseError` error.\n    pub const fn parse_error() -> Self {\n        Self::new(ErrorCode::ParseError)\n    }\n\n    /// Creates a new `MethodNotFound` error.\n    pub const fn method_not_found() -> Self {\n        Self::new(ErrorCode::MethodNotFound)\n    }\n\n    /// Creates a new `InvalidRequest` error.\n    pub const fn invalid_request() -> Self {\n        Self::new(ErrorCode::InvalidRequest)\n    }\n\n    /// Creates a new `InternalError` error.\n    pub const fn internal_error() -> Self {\n        Self::new(ErrorCode::InternalError)\n    }\n\n    /// Creates a new `InvalidParams` error.\n    pub fn invalid_params<M>(message: M) -> Self\n    where\n        M: Into<String>,\n    {\n        Self { code: ErrorCode::InvalidParams, message: message.into().into(), data: None }\n    }\n\n    /// Creates a new `InternalError` error with a message.\n    pub fn internal_error_with<M>(message: M) -> Self\n    where\n        M: Into<String>,\n    {\n        Self { code: ErrorCode::InternalError, message: message.into().into(), data: None }\n    }\n\n    /// Creates a new RPC error for when a transaction was rejected.\n    pub fn transaction_rejected<M>(message: M) -> Self\n    where\n        M: Into<String>,\n    {\n        Self { code: ErrorCode::TransactionRejected, message: message.into().into(), data: None }\n    }\n}\n\nimpl fmt::Display for RpcError {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        write!(f, \"{}: {}\", self.code.message(), self.message)\n    }\n}\n\n/// List of JSON-RPC error codes\n#[derive(Clone, Copy, Debug, PartialEq, Eq)]\npub enum ErrorCode {\n    /// Server received Invalid JSON.\n    /// server side error while parsing JSON\n    ParseError,\n    /// send invalid request object.\n    InvalidRequest,\n    /// method does not exist or valid\n    MethodNotFound,\n    /// invalid method parameter.\n    InvalidParams,\n    /// internal call error\n    InternalError,\n    /// Failed to send transaction, See also <https://github.com/MetaMask/rpc-errors/blob/main/src/error-constants.ts>\n    TransactionRejected,\n    /// Custom geth error code, <https://github.com/vapory-legacy/wiki/blob/master/JSON-RPC-Error-Codes-Improvement-Proposal.md>\n    ExecutionError,\n    /// Used for server specific errors.\n    ServerError(i64),\n}\n\nimpl ErrorCode {\n    /// Returns the error code as `i64`\n    pub fn code(&self) -> i64 {\n        match *self {\n            Self::ParseError => -32700,\n            Self::InvalidRequest => -32600,\n            Self::MethodNotFound => -32601,\n            Self::InvalidParams => -32602,\n            Self::InternalError => -32603,\n            Self::TransactionRejected => -32003,\n            Self::ExecutionError => 3,\n            Self::ServerError(c) => c,\n        }\n    }\n\n    /// Returns the message associated with the error\n    pub const fn message(&self) -> &'static str {\n        match *self {\n            Self::ParseError => \"Parse error\",\n            Self::InvalidRequest => \"Invalid request\",\n            Self::MethodNotFound => \"Method not found\",\n            Self::InvalidParams => \"Invalid params\",\n            Self::InternalError => \"Internal error\",\n            Self::TransactionRejected => \"Transaction rejected\",\n            Self::ServerError(_) => \"Server error\",\n            Self::ExecutionError => \"Execution error\",\n        }\n    }\n}\n\nimpl Serialize for ErrorCode {\n    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>\n    where\n        S: Serializer,\n    {\n        serializer.serialize_i64(self.code())\n    }\n}\n\nimpl<'a> Deserialize<'a> for ErrorCode {\n    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>\n    where\n        D: Deserializer<'a>,\n    {\n        i64::deserialize(deserializer).map(Into::into)\n    }\n}\n\nimpl From<i64> for ErrorCode {\n    fn from(code: i64) -> Self {\n        match code {\n            -32700 => Self::ParseError,\n            -32600 => Self::InvalidRequest,\n            -32601 => Self::MethodNotFound,\n            -32602 => Self::InvalidParams,\n            -32603 => Self::InternalError,\n            -32003 => Self::TransactionRejected,\n            3 => Self::ExecutionError,\n            _ => Self::ServerError(code),\n        }\n    }\n}\n"
  },
  {
    "path": "crates/anvil/rpc/src/lib.rs",
    "content": "//! # anvil-rpc\n//!\n//! JSON-RPC types.\n\n#![cfg_attr(not(test), warn(unused_crate_dependencies))]\n#![cfg_attr(docsrs, feature(doc_cfg))]\n\n/// JSON-RPC request bindings\npub mod request;\n\n/// JSON-RPC response bindings\npub mod response;\n\n/// JSON-RPC error bindings\npub mod error;\n"
  },
  {
    "path": "crates/anvil/rpc/src/request.rs",
    "content": "use serde::{Deserialize, Serialize};\nuse std::fmt;\n\n/// A JSON-RPC request object, a method call\n#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]\n#[serde(deny_unknown_fields)]\npub struct RpcMethodCall {\n    /// The version of the protocol\n    pub jsonrpc: Version,\n    /// The name of the method to execute\n    pub method: String,\n    /// An array or object containing the parameters to be passed to the function.\n    #[serde(default = \"no_params\")]\n    pub params: RequestParams,\n    /// The identifier for this request issued by the client,\n    /// An [Id] must be a String, null or a number.\n    /// If missing it's considered a notification in [Version::V2]\n    pub id: Id,\n}\n\nimpl RpcMethodCall {\n    pub fn id(&self) -> Id {\n        self.id.clone()\n    }\n}\n\n/// Represents a JSON-RPC request which is considered a notification (missing [Id] optional\n/// [Version])\n#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]\n#[serde(deny_unknown_fields)]\npub struct RpcNotification {\n    pub jsonrpc: Option<Version>,\n    pub method: String,\n    #[serde(default = \"no_params\")]\n    pub params: RequestParams,\n}\n\n/// Representation of a single JSON-RPC call\n#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]\n#[serde(untagged)]\npub enum RpcCall {\n    /// the RPC method to invoke\n    MethodCall(RpcMethodCall),\n    /// A notification (no [Id] provided)\n    Notification(RpcNotification),\n    /// Invalid call\n    Invalid {\n        /// id or [Id::Null]\n        #[serde(default = \"null_id\")]\n        id: Id,\n    },\n}\n\n/// Represents a JSON-RPC request.\n#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]\n#[serde(deny_unknown_fields)]\n#[serde(untagged)]\npub enum Request {\n    /// single json rpc request [RpcCall]\n    Single(RpcCall),\n    /// batch of several requests\n    Batch(Vec<RpcCall>),\n}\n\n/// Request parameters\n#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]\n#[serde(untagged, deny_unknown_fields)]\npub enum RequestParams {\n    /// no parameters provided\n    None,\n    /// An array of JSON values\n    Array(Vec<serde_json::Value>),\n    /// a map of JSON values\n    Object(serde_json::Map<String, serde_json::Value>),\n}\n\nimpl From<RequestParams> for serde_json::Value {\n    fn from(params: RequestParams) -> Self {\n        match params {\n            RequestParams::None => Self::Null,\n            RequestParams::Array(arr) => arr.into(),\n            RequestParams::Object(obj) => obj.into(),\n        }\n    }\n}\n\nfn no_params() -> RequestParams {\n    RequestParams::None\n}\n\n/// Represents the version of the RPC protocol\n#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]\npub enum Version {\n    #[serde(rename = \"2.0\")]\n    V2,\n}\n\n#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]\n#[serde(untagged)]\npub enum Id {\n    String(String),\n    Number(i64),\n    Null,\n}\n\nimpl fmt::Display for Id {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        match self {\n            Self::String(s) => s.fmt(f),\n            Self::Number(n) => n.fmt(f),\n            Self::Null => f.write_str(\"null\"),\n        }\n    }\n}\n\nfn null_id() -> Id {\n    Id::Null\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn can_serialize_batch() {\n        let batch = Request::Batch(vec![\n            RpcCall::MethodCall(RpcMethodCall {\n                jsonrpc: Version::V2,\n                method: \"eth_method\".to_owned(),\n                params: RequestParams::Array(vec![\n                    serde_json::Value::from(999),\n                    serde_json::Value::from(1337),\n                ]),\n                id: Id::Number(1),\n            }),\n            RpcCall::Notification(RpcNotification {\n                jsonrpc: Some(Version::V2),\n                method: \"eth_method\".to_owned(),\n                params: RequestParams::Array(vec![serde_json::Value::from(999)]),\n            }),\n        ]);\n\n        let obj = serde_json::to_string(&batch).unwrap();\n        assert_eq!(\n            obj,\n            r#\"[{\"jsonrpc\":\"2.0\",\"method\":\"eth_method\",\"params\":[999,1337],\"id\":1},{\"jsonrpc\":\"2.0\",\"method\":\"eth_method\",\"params\":[999]}]\"#\n        );\n    }\n\n    #[test]\n    fn can_deserialize_batch() {\n        let s = r#\"[{}, {\"jsonrpc\": \"2.0\", \"method\": \"eth_call\", \"params\": [1337,420], \"id\": 1},{\"jsonrpc\": \"2.0\", \"method\": \"notify\", \"params\": [999]}]\"#;\n        let obj: Request = serde_json::from_str(s).unwrap();\n        assert_eq!(\n            obj,\n            Request::Batch(vec![\n                RpcCall::Invalid { id: Id::Null },\n                RpcCall::MethodCall(RpcMethodCall {\n                    jsonrpc: Version::V2,\n                    method: \"eth_call\".to_owned(),\n                    params: RequestParams::Array(vec![\n                        serde_json::Value::from(1337),\n                        serde_json::Value::from(420)\n                    ]),\n                    id: Id::Number(1)\n                }),\n                RpcCall::Notification(RpcNotification {\n                    jsonrpc: Some(Version::V2),\n                    method: \"notify\".to_owned(),\n                    params: RequestParams::Array(vec![serde_json::Value::from(999)])\n                })\n            ])\n        )\n    }\n\n    #[test]\n    fn can_serialize_method() {\n        let m = RpcMethodCall {\n            jsonrpc: Version::V2,\n            method: \"eth_method\".to_owned(),\n            params: RequestParams::Array(vec![\n                serde_json::Value::from(999),\n                serde_json::Value::from(1337),\n            ]),\n            id: Id::Number(1),\n        };\n\n        let obj = serde_json::to_string(&m).unwrap();\n        assert_eq!(obj, r#\"{\"jsonrpc\":\"2.0\",\"method\":\"eth_method\",\"params\":[999,1337],\"id\":1}\"#);\n    }\n\n    #[test]\n    fn can_serialize_call_notification() {\n        let n = RpcCall::Notification(RpcNotification {\n            jsonrpc: Some(Version::V2),\n            method: \"eth_method\".to_owned(),\n            params: RequestParams::Array(vec![serde_json::Value::from(999)]),\n        });\n        let obj = serde_json::to_string(&n).unwrap();\n        assert_eq!(obj, r#\"{\"jsonrpc\":\"2.0\",\"method\":\"eth_method\",\"params\":[999]}\"#);\n    }\n\n    #[test]\n    fn can_serialize_notification() {\n        let n = RpcNotification {\n            jsonrpc: Some(Version::V2),\n            method: \"eth_method\".to_owned(),\n            params: RequestParams::Array(vec![\n                serde_json::Value::from(999),\n                serde_json::Value::from(1337),\n            ]),\n        };\n        let obj = serde_json::to_string(&n).unwrap();\n        assert_eq!(obj, r#\"{\"jsonrpc\":\"2.0\",\"method\":\"eth_method\",\"params\":[999,1337]}\"#);\n    }\n\n    #[test]\n    fn can_deserialize_notification() {\n        let s = r#\"{\"jsonrpc\": \"2.0\", \"method\": \"eth_method\", \"params\": [999,1337]}\"#;\n        let obj: RpcNotification = serde_json::from_str(s).unwrap();\n\n        assert_eq!(\n            obj,\n            RpcNotification {\n                jsonrpc: Some(Version::V2),\n                method: \"eth_method\".to_owned(),\n                params: RequestParams::Array(vec![\n                    serde_json::Value::from(999),\n                    serde_json::Value::from(1337)\n                ])\n            }\n        );\n        let s = r#\"{\"jsonrpc\": \"2.0\", \"method\": \"foobar\"}\"#;\n        let obj: RpcNotification = serde_json::from_str(s).unwrap();\n        assert_eq!(\n            obj,\n            RpcNotification {\n                jsonrpc: Some(Version::V2),\n                method: \"foobar\".to_owned(),\n                params: RequestParams::None,\n            }\n        );\n        let s = r#\"{\"jsonrpc\": \"2.0\", \"method\": \"eth_method\", \"params\": [999,1337], \"id\": 1}\"#;\n        let obj: Result<RpcNotification, _> = serde_json::from_str(s);\n        assert!(obj.is_err());\n    }\n\n    #[test]\n    fn can_deserialize_call() {\n        let s = r#\"{\"jsonrpc\": \"2.0\", \"method\": \"eth_method\", \"params\": [999]}\"#;\n        let obj: RpcCall = serde_json::from_str(s).unwrap();\n        assert_eq!(\n            obj,\n            RpcCall::Notification(RpcNotification {\n                jsonrpc: Some(Version::V2),\n                method: \"eth_method\".to_owned(),\n                params: RequestParams::Array(vec![serde_json::Value::from(999)])\n            })\n        );\n\n        let s = r#\"{\"jsonrpc\": \"2.0\", \"method\": \"eth_method\", \"params\": [999], \"id\": 1}\"#;\n        let obj: RpcCall = serde_json::from_str(s).unwrap();\n        assert_eq!(\n            obj,\n            RpcCall::MethodCall(RpcMethodCall {\n                jsonrpc: Version::V2,\n                method: \"eth_method\".to_owned(),\n                params: RequestParams::Array(vec![serde_json::Value::from(999)]),\n                id: Id::Number(1)\n            })\n        );\n\n        let s = r#\"{\"jsonrpc\": \"2.0\", \"method\": \"eth_method\", \"params\": [], \"id\": 1}\"#;\n        let obj: RpcCall = serde_json::from_str(s).unwrap();\n        assert_eq!(\n            obj,\n            RpcCall::MethodCall(RpcMethodCall {\n                jsonrpc: Version::V2,\n                method: \"eth_method\".to_owned(),\n                params: RequestParams::Array(vec![]),\n                id: Id::Number(1)\n            })\n        );\n\n        let s = r#\"{\"jsonrpc\": \"2.0\", \"method\": \"eth_method\", \"params\": null, \"id\": 1}\"#;\n        let obj: RpcCall = serde_json::from_str(s).unwrap();\n        assert_eq!(\n            obj,\n            RpcCall::MethodCall(RpcMethodCall {\n                jsonrpc: Version::V2,\n                method: \"eth_method\".to_owned(),\n                params: RequestParams::None,\n                id: Id::Number(1)\n            })\n        );\n\n        let s = r#\"{\"jsonrpc\": \"2.0\", \"method\": \"eth_method\", \"id\": 1}\"#;\n        let obj: RpcCall = serde_json::from_str(s).unwrap();\n        assert_eq!(\n            obj,\n            RpcCall::MethodCall(RpcMethodCall {\n                jsonrpc: Version::V2,\n                method: \"eth_method\".to_owned(),\n                params: RequestParams::None,\n                id: Id::Number(1)\n            })\n        );\n    }\n}\n"
  },
  {
    "path": "crates/anvil/rpc/src/response.rs",
    "content": "use crate::{\n    error::RpcError,\n    request::{Id, Version},\n};\nuse serde::{Deserialize, Serialize};\n\n/// Response of a _single_ rpc call\n#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]\n#[serde(deny_unknown_fields)]\npub struct RpcResponse {\n    // JSON RPC version\n    jsonrpc: Version,\n    id: Id,\n    #[serde(flatten)]\n    result: ResponseResult,\n}\n\nimpl From<RpcError> for RpcResponse {\n    fn from(e: RpcError) -> Self {\n        Self { jsonrpc: Version::V2, id: Id::Null, result: ResponseResult::Error(e) }\n    }\n}\n\nimpl RpcResponse {\n    pub fn new(id: Id, content: impl Into<ResponseResult>) -> Self {\n        Self { jsonrpc: Version::V2, id, result: content.into() }\n    }\n\n    pub fn invalid_request(id: Id) -> Self {\n        Self::new(id, RpcError::invalid_request())\n    }\n}\n\n/// Represents the result of a call either success or error\n#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]\n#[serde(deny_unknown_fields)]\npub enum ResponseResult {\n    #[serde(rename = \"result\")]\n    Success(serde_json::Value),\n    #[serde(rename = \"error\")]\n    Error(RpcError),\n}\n\nimpl ResponseResult {\n    pub fn success<S>(content: S) -> Self\n    where\n        S: Serialize + 'static,\n    {\n        Self::Success(serde_json::to_value(&content).unwrap())\n    }\n\n    pub fn error(error: RpcError) -> Self {\n        Self::Error(error)\n    }\n}\n\nimpl From<RpcError> for ResponseResult {\n    fn from(err: RpcError) -> Self {\n        Self::error(err)\n    }\n}\n/// Synchronous response\n#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]\n#[serde(deny_unknown_fields)]\n#[serde(untagged)]\npub enum Response {\n    /// single json rpc response\n    Single(RpcResponse),\n    /// batch of several responses\n    Batch(Vec<RpcResponse>),\n}\n\nimpl Response {\n    /// Creates new [`Response`] with the given [`RpcError`].\n    pub fn error(error: RpcError) -> Self {\n        RpcResponse::new(Id::Null, ResponseResult::Error(error)).into()\n    }\n}\n\nimpl From<RpcError> for Response {\n    fn from(err: RpcError) -> Self {\n        Self::error(err)\n    }\n}\n\nimpl From<RpcResponse> for Response {\n    fn from(resp: RpcResponse) -> Self {\n        Self::Single(resp)\n    }\n}\n"
  },
  {
    "path": "crates/anvil/server/Cargo.toml",
    "content": "[package]\nname = \"anvil-server\"\ndescription = \"Customizable RPC server\"\n\nversion.workspace = true\nedition.workspace = true\nrust-version.workspace = true\nauthors.workspace = true\nlicense.workspace = true\nhomepage.workspace = true\nrepository.workspace = true\n\n[lints]\nworkspace = true\n\n[dependencies]\nanvil-rpc = { path = \"../rpc\" }\n\n# axum related\naxum = { workspace = true, features = [\"ws\"] }\ntower-http = { workspace = true, features = [\"trace\", \"cors\"] }\n\n# tracing\ntracing.workspace = true\n\n# async\nparking_lot.workspace = true\nfutures.workspace = true\n\n# ipc\ninterprocess = { version = \"2\", optional = true, features = [\"tokio\"] }\nbytes = { workspace = true, optional = true }\ntokio-util = { version = \"0.7\", features = [\"codec\"], optional = true }\n\n# misc\nserde_json.workspace = true\nserde.workspace = true\nasync-trait.workspace = true\nthiserror.workspace = true\n\nclap = { version = \"4\", features = [\"derive\", \"env\"], optional = true }\npin-project = \"1\"\n\n[features]\ndefault = [\"ipc\"]\nipc = [\"dep:interprocess\", \"dep:bytes\", \"dep:tokio-util\"]\n"
  },
  {
    "path": "crates/anvil/server/src/config.rs",
    "content": "use crate::HeaderValue;\nuse serde::{Deserialize, Deserializer, Serialize, Serializer};\nuse std::str::FromStr;\n\n/// Additional server options.\n#[derive(Clone, Debug, Serialize, Deserialize)]\n#[cfg_attr(feature = \"clap\", derive(clap::Parser), command(next_help_heading = \"Server options\"))]\npub struct ServerConfig {\n    /// The cors `allow_origin` header\n    #[cfg_attr(feature = \"clap\", arg(long, default_value = \"*\"))]\n    pub allow_origin: HeaderValueWrapper,\n\n    /// Disable CORS.\n    #[cfg_attr(feature = \"clap\", arg(long, conflicts_with = \"allow_origin\"))]\n    pub no_cors: bool,\n\n    /// Disable the default request body size limit. At time of writing the default limit is 2MB.\n    #[cfg_attr(feature = \"clap\", arg(long))]\n    pub no_request_size_limit: bool,\n}\n\nimpl ServerConfig {\n    /// Sets the \"allow origin\" header for CORS.\n    pub fn with_allow_origin(mut self, allow_origin: impl Into<HeaderValueWrapper>) -> Self {\n        self.allow_origin = allow_origin.into();\n        self\n    }\n\n    /// Whether to enable CORS.\n    pub fn set_cors(mut self, cors: bool) -> Self {\n        self.no_cors = !cors;\n        self\n    }\n}\n\nimpl Default for ServerConfig {\n    fn default() -> Self {\n        Self {\n            allow_origin: \"*\".parse::<HeaderValue>().unwrap().into(),\n            no_cors: false,\n            no_request_size_limit: false,\n        }\n    }\n}\n\n#[derive(Clone, Debug)]\npub struct HeaderValueWrapper(pub HeaderValue);\n\nimpl FromStr for HeaderValueWrapper {\n    type Err = <HeaderValue as FromStr>::Err;\n\n    fn from_str(s: &str) -> Result<Self, Self::Err> {\n        Ok(Self(s.parse()?))\n    }\n}\n\nimpl Serialize for HeaderValueWrapper {\n    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>\n    where\n        S: Serializer,\n    {\n        serializer.serialize_str(self.0.to_str().map_err(serde::ser::Error::custom)?)\n    }\n}\n\nimpl<'de> Deserialize<'de> for HeaderValueWrapper {\n    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>\n    where\n        D: Deserializer<'de>,\n    {\n        let s = String::deserialize(deserializer)?;\n        Ok(Self(s.parse().map_err(serde::de::Error::custom)?))\n    }\n}\n\nimpl std::ops::Deref for HeaderValueWrapper {\n    type Target = HeaderValue;\n\n    fn deref(&self) -> &Self::Target {\n        &self.0\n    }\n}\n\nimpl From<HeaderValueWrapper> for HeaderValue {\n    fn from(wrapper: HeaderValueWrapper) -> Self {\n        wrapper.0\n    }\n}\n\nimpl From<HeaderValue> for HeaderValueWrapper {\n    fn from(header: HeaderValue) -> Self {\n        Self(header)\n    }\n}\n"
  },
  {
    "path": "crates/anvil/server/src/error.rs",
    "content": "//! Error variants used to unify different connection streams\n\n/// An error that can occur when reading an incoming request\n#[derive(Debug, thiserror::Error)]\npub enum RequestError {\n    #[error(transparent)]\n    Axum(#[from] axum::Error),\n    #[error(transparent)]\n    Serde(#[from] serde_json::Error),\n    #[error(transparent)]\n    Io(#[from] std::io::Error),\n    #[error(\"Disconnect\")]\n    Disconnect,\n}\n"
  },
  {
    "path": "crates/anvil/server/src/handler.rs",
    "content": "use crate::RpcHandler;\nuse anvil_rpc::{\n    error::RpcError,\n    request::{Request, RpcCall},\n    response::{Response, RpcResponse},\n};\nuse axum::{\n    Json,\n    extract::{State, rejection::JsonRejection},\n};\nuse futures::{FutureExt, future};\n\n/// Handles incoming JSON-RPC Request.\n// NOTE: `handler` must come first because the `request` extractor consumes the request body.\npub async fn handle<Http: RpcHandler, Ws>(\n    State((handler, _)): State<(Http, Ws)>,\n    request: Result<Json<Request>, JsonRejection>,\n) -> Json<Response> {\n    Json(match request {\n        Ok(Json(req)) => handle_request(req, handler)\n            .await\n            .unwrap_or_else(|| Response::error(RpcError::invalid_request())),\n        Err(err) => {\n            warn!(target: \"rpc\", ?err, \"invalid request\");\n            Response::error(RpcError::invalid_request())\n        }\n    })\n}\n\n/// Handle the JSON-RPC [Request]\n///\n/// This will try to deserialize the payload into the request type of the handler and if successful\n/// invoke the handler\npub async fn handle_request<Handler: RpcHandler>(\n    req: Request,\n    handler: Handler,\n) -> Option<Response> {\n    /// processes batch calls\n    fn responses_as_batch(outs: Vec<Option<RpcResponse>>) -> Option<Response> {\n        let batch: Vec<_> = outs.into_iter().flatten().collect();\n        (!batch.is_empty()).then_some(Response::Batch(batch))\n    }\n\n    match req {\n        Request::Single(call) => handle_call(call, handler).await.map(Response::Single),\n        Request::Batch(calls) => {\n            future::join_all(calls.into_iter().map(move |call| handle_call(call, handler.clone())))\n                .map(responses_as_batch)\n                .await\n        }\n    }\n}\n\n/// handle a single RPC method call\nasync fn handle_call<Handler: RpcHandler>(call: RpcCall, handler: Handler) -> Option<RpcResponse> {\n    match call {\n        RpcCall::MethodCall(call) => {\n            trace!(target: \"rpc\", id = ?call.id , method = ?call.method,  \"handling call\");\n            Some(handler.on_call(call).await)\n        }\n        RpcCall::Notification(notification) => {\n            trace!(target: \"rpc\", method = ?notification.method, \"received rpc notification\");\n            None\n        }\n        RpcCall::Invalid { id } => {\n            warn!(target: \"rpc\", ?id,  \"invalid rpc call\");\n            Some(RpcResponse::invalid_request(id))\n        }\n    }\n}\n"
  },
  {
    "path": "crates/anvil/server/src/ipc.rs",
    "content": "//! IPC handling\n\nuse crate::{PubSubRpcHandler, error::RequestError, pubsub::PubSubConnection};\nuse anvil_rpc::request::Request;\nuse bytes::{BufMut, BytesMut};\nuse futures::{Sink, Stream, StreamExt, ready};\nuse interprocess::local_socket::{self as ls, tokio::prelude::*};\nuse std::{\n    io,\n    pin::Pin,\n    task::{Context, Poll},\n};\n\n/// An IPC connection for anvil\n///\n/// A Future that listens for incoming connections and spawns new connections\npub struct IpcEndpoint<Handler> {\n    /// the handler for the websocket connection\n    handler: Handler,\n    /// The path to the socket\n    path: String,\n}\n\nimpl<Handler: PubSubRpcHandler> IpcEndpoint<Handler> {\n    /// Creates a new endpoint with the given handler\n    pub fn new(handler: Handler, path: String) -> Self {\n        Self { handler, path }\n    }\n\n    /// Returns a stream of incoming connection handlers.\n    ///\n    /// This establishes the IPC endpoint, converts the incoming connections into handled\n    /// connections.\n    #[instrument(target = \"ipc\", skip_all)]\n    pub fn incoming(self) -> io::Result<impl Stream<Item = impl Future<Output = ()>>> {\n        let Self { handler, path } = self;\n\n        trace!(%path, \"starting IPC server\");\n\n        if cfg!(unix) {\n            // ensure the file does not exist\n            if std::fs::remove_file(&path).is_ok() {\n                warn!(%path, \"removed existing file\");\n            }\n        }\n\n        let name = to_name(path.as_ref())?;\n        let listener = ls::ListenerOptions::new().name(name).create_tokio()?;\n        let connections = futures::stream::unfold(listener, |listener| async move {\n            let conn = listener.accept().await;\n            Some((conn, listener))\n        });\n\n        trace!(\"established connection listener\");\n\n        Ok(connections.filter_map(move |stream| {\n            let handler = handler.clone();\n            async move {\n                match stream {\n                    Ok(stream) => {\n                        trace!(\"successful incoming IPC connection\");\n                        let framed = tokio_util::codec::Decoder::framed(JsonRpcCodec, stream);\n                        Some(PubSubConnection::new(IpcConn(framed), handler))\n                    }\n                    Err(err) => {\n                        trace!(%err, \"unsuccessful incoming IPC connection\");\n                        None\n                    }\n                }\n            }\n        }))\n    }\n}\n\n#[pin_project::pin_project]\nstruct IpcConn<T>(#[pin] T);\n\nimpl<T> Stream for IpcConn<T>\nwhere\n    T: Stream<Item = io::Result<String>>,\n{\n    type Item = Result<Option<Request>, RequestError>;\n\n    fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {\n        fn on_request(msg: io::Result<String>) -> Result<Option<Request>, RequestError> {\n            let text = msg?;\n            Ok(Some(serde_json::from_str(&text)?))\n        }\n        match ready!(self.project().0.poll_next(cx)) {\n            Some(req) => Poll::Ready(Some(on_request(req))),\n            _ => Poll::Ready(None),\n        }\n    }\n}\n\nimpl<T> Sink<String> for IpcConn<T>\nwhere\n    T: Sink<String, Error = io::Error>,\n{\n    type Error = io::Error;\n\n    fn poll_ready(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {\n        // NOTE: we always flush here this prevents any backpressure buffer in the underlying\n        // `Framed` impl that would cause stalled requests\n        self.project().0.poll_flush(cx)\n    }\n\n    fn start_send(self: Pin<&mut Self>, item: String) -> Result<(), Self::Error> {\n        self.project().0.start_send(item)\n    }\n\n    fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {\n        self.project().0.poll_flush(cx)\n    }\n\n    fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {\n        self.project().0.poll_close(cx)\n    }\n}\n\nstruct JsonRpcCodec;\n\n// Adapted from <https://github.com/paritytech/jsonrpc/blob/38af3c9439aa75481805edf6c05c6622a5ab1e70/server-utils/src/stream_codec.rs#L47-L105>\nimpl tokio_util::codec::Decoder for JsonRpcCodec {\n    type Item = String;\n    type Error = io::Error;\n\n    fn decode(&mut self, buf: &mut BytesMut) -> io::Result<Option<Self::Item>> {\n        const fn is_whitespace(byte: u8) -> bool {\n            matches!(byte, 0x0D | 0x0A | 0x20 | 0x09)\n        }\n\n        let mut depth = 0;\n        let mut in_str = false;\n        let mut is_escaped = false;\n        let mut start_idx = 0;\n        let mut whitespaces = 0;\n\n        for idx in 0..buf.as_ref().len() {\n            let byte = buf.as_ref()[idx];\n\n            if (byte == b'{' || byte == b'[') && !in_str {\n                if depth == 0 {\n                    start_idx = idx;\n                }\n                depth += 1;\n            } else if (byte == b'}' || byte == b']') && !in_str {\n                depth -= 1;\n            } else if byte == b'\"' && !is_escaped {\n                in_str = !in_str;\n            } else if is_whitespace(byte) {\n                whitespaces += 1;\n            }\n            is_escaped = byte == b'\\\\' && !is_escaped && in_str;\n\n            if depth == 0 && idx != start_idx && idx - start_idx + 1 > whitespaces {\n                let bts = buf.split_to(idx + 1);\n                return match String::from_utf8(bts.as_ref().to_vec()) {\n                    Ok(val) => Ok(Some(val)),\n                    Err(_) => Ok(None),\n                };\n            }\n        }\n        Ok(None)\n    }\n}\n\nimpl tokio_util::codec::Encoder<String> for JsonRpcCodec {\n    type Error = io::Error;\n\n    fn encode(&mut self, msg: String, buf: &mut BytesMut) -> io::Result<()> {\n        buf.extend_from_slice(msg.as_bytes());\n        // Add newline character\n        buf.put_u8(b'\\n');\n        Ok(())\n    }\n}\n\nfn to_name(path: &std::ffi::OsStr) -> io::Result<ls::Name<'_>> {\n    if cfg!(windows) && !path.as_encoded_bytes().starts_with(br\"\\\\.\\pipe\\\") {\n        ls::ToNsName::to_ns_name::<ls::GenericNamespaced>(path)\n    } else {\n        ls::ToFsName::to_fs_name::<ls::GenericFilePath>(path)\n    }\n}\n"
  },
  {
    "path": "crates/anvil/server/src/lib.rs",
    "content": "//! Bootstrap [axum] RPC servers.\n\n#![cfg_attr(not(test), warn(unused_crate_dependencies))]\n#![cfg_attr(docsrs, feature(doc_cfg))]\n\n#[macro_use]\nextern crate tracing;\n\nuse anvil_rpc::{\n    error::RpcError,\n    request::RpcMethodCall,\n    response::{ResponseResult, RpcResponse},\n};\nuse axum::{\n    Router,\n    extract::DefaultBodyLimit,\n    http::{HeaderValue, Method, header},\n    routing::{MethodRouter, post},\n};\nuse serde::de::DeserializeOwned;\nuse std::fmt;\nuse tower_http::{cors::CorsLayer, trace::TraceLayer};\n\nmod config;\npub use config::ServerConfig;\n\nmod error;\nmod handler;\n\nmod pubsub;\npub use pubsub::{PubSubContext, PubSubRpcHandler};\n\nmod ws;\n\n#[cfg(feature = \"ipc\")]\npub mod ipc;\n\n/// Configures an [`axum::Router`] that handles JSON-RPC calls via both HTTP and WS.\npub fn http_ws_router<Http, Ws>(config: ServerConfig, http: Http, ws: Ws) -> Router\nwhere\n    Http: RpcHandler,\n    Ws: PubSubRpcHandler,\n{\n    router_inner(config, post(handler::handle).get(ws::handle_ws), (http, ws))\n}\n\n/// Configures an [`axum::Router`] that handles JSON-RPC calls via HTTP.\npub fn http_router<Http>(config: ServerConfig, http: Http) -> Router\nwhere\n    Http: RpcHandler,\n{\n    router_inner(config, post(handler::handle), (http, ()))\n}\n\nfn router_inner<S: Clone + Send + Sync + 'static>(\n    config: ServerConfig,\n    root_method_router: MethodRouter<S>,\n    state: S,\n) -> Router {\n    let ServerConfig { allow_origin, no_cors, no_request_size_limit } = config;\n\n    let mut router = Router::new()\n        .route(\"/\", root_method_router)\n        .with_state(state)\n        .layer(TraceLayer::new_for_http());\n    if !no_cors {\n        // See [`tower_http::cors`](https://docs.rs/tower-http/latest/tower_http/cors/index.html)\n        // for more details.\n        router = router.layer(\n            CorsLayer::new()\n                .allow_origin(allow_origin.0)\n                .allow_headers([header::CONTENT_TYPE])\n                .allow_methods([Method::GET, Method::POST]),\n        );\n    }\n    if no_request_size_limit {\n        router = router.layer(DefaultBodyLimit::disable());\n    }\n    router\n}\n\n/// Helper trait that is used to execute ethereum rpc calls\n#[async_trait::async_trait]\npub trait RpcHandler: Clone + Send + Sync + 'static {\n    /// The request type to expect\n    type Request: DeserializeOwned + Send + Sync + fmt::Debug;\n\n    /// Invoked when the request was received\n    async fn on_request(&self, request: Self::Request) -> ResponseResult;\n\n    /// Invoked for every incoming `RpcMethodCall`\n    ///\n    /// This will attempt to deserialize a `{ \"method\" : \"<name>\", \"params\": \"<params>\" }` message\n    /// into the `Request` type of this handler. If a `Request` instance was deserialized\n    /// successfully, [`Self::on_request`] will be invoked.\n    ///\n    /// **Note**: override this function if the expected `Request` deviates from `{ \"method\" :\n    /// \"<name>\", \"params\": \"<params>\" }`\n    async fn on_call(&self, call: RpcMethodCall) -> RpcResponse {\n        trace!(target: \"rpc\",  id = ?call.id , method = ?call.method, params = ?call.params, \"received method call\");\n        let RpcMethodCall { method, params, id, .. } = call;\n\n        let params: serde_json::Value = params.into();\n        let call = serde_json::json!({\n            \"method\": &method,\n            \"params\": params\n        });\n\n        match serde_json::from_value::<Self::Request>(call) {\n            Ok(req) => {\n                let result = self.on_request(req).await;\n                RpcResponse::new(id, result)\n            }\n            Err(err) => {\n                let err = err.to_string();\n                if err.contains(\"unknown variant\") {\n                    error!(target: \"rpc\", ?method, \"failed to deserialize method due to unknown variant\");\n                    RpcResponse::new(id, RpcError::method_not_found())\n                } else {\n                    error!(target: \"rpc\", ?method, ?err, \"failed to deserialize method\");\n                    RpcResponse::new(id, RpcError::invalid_params(err))\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "crates/anvil/server/src/pubsub.rs",
    "content": "use crate::{RpcHandler, error::RequestError, handler::handle_request};\nuse anvil_rpc::{\n    error::RpcError,\n    request::Request,\n    response::{Response, ResponseResult},\n};\n\nuse futures::{FutureExt, Sink, SinkExt, Stream, StreamExt};\nuse parking_lot::Mutex;\nuse serde::de::DeserializeOwned;\nuse std::{\n    collections::VecDeque,\n    fmt,\n    hash::Hash,\n    pin::Pin,\n    sync::Arc,\n    task::{Context, Poll},\n};\n\n/// The general purpose trait for handling RPC requests and subscriptions\n#[async_trait::async_trait]\npub trait PubSubRpcHandler: Clone + Send + Sync + Unpin + 'static {\n    /// The request type to expect\n    type Request: DeserializeOwned + Send + Sync + fmt::Debug;\n    /// The identifier to use for subscriptions\n    type SubscriptionId: Hash + PartialEq + Eq + Send + Sync + fmt::Debug;\n    /// The subscription type this handle may create\n    type Subscription: Stream<Item = serde_json::Value> + Send + Sync + Unpin;\n\n    /// Invoked when the request was received\n    async fn on_request(&self, request: Self::Request, cx: PubSubContext<Self>) -> ResponseResult;\n}\n\ntype Subscriptions<SubscriptionId, Subscription> = Arc<Mutex<Vec<(SubscriptionId, Subscription)>>>;\n\n/// Contains additional context and tracks subscriptions\npub struct PubSubContext<Handler: PubSubRpcHandler> {\n    /// all active subscriptions `id -> Stream`\n    subscriptions: Subscriptions<Handler::SubscriptionId, Handler::Subscription>,\n}\n\nimpl<Handler: PubSubRpcHandler> PubSubContext<Handler> {\n    /// Adds new active subscription\n    ///\n    /// Returns the previous subscription, if any\n    pub fn add_subscription(\n        &self,\n        id: Handler::SubscriptionId,\n        subscription: Handler::Subscription,\n    ) -> Option<Handler::Subscription> {\n        let mut subscriptions = self.subscriptions.lock();\n        let mut removed = None;\n        if let Some(idx) = subscriptions.iter().position(|(i, _)| id == *i) {\n            trace!(target: \"rpc\", ?id,  \"removed subscription\");\n            removed = Some(subscriptions.swap_remove(idx).1);\n        }\n        trace!(target: \"rpc\", ?id,  \"added subscription\");\n        subscriptions.push((id, subscription));\n        removed\n    }\n\n    /// Removes an existing subscription\n    pub fn remove_subscription(\n        &self,\n        id: &Handler::SubscriptionId,\n    ) -> Option<Handler::Subscription> {\n        let mut subscriptions = self.subscriptions.lock();\n        if let Some(idx) = subscriptions.iter().position(|(i, _)| id == i) {\n            trace!(target: \"rpc\", ?id,  \"removed subscription\");\n            return Some(subscriptions.swap_remove(idx).1);\n        }\n        None\n    }\n}\n\nimpl<Handler: PubSubRpcHandler> Clone for PubSubContext<Handler> {\n    fn clone(&self) -> Self {\n        Self { subscriptions: Arc::clone(&self.subscriptions) }\n    }\n}\n\nimpl<Handler: PubSubRpcHandler> Default for PubSubContext<Handler> {\n    fn default() -> Self {\n        Self { subscriptions: Arc::new(Mutex::new(Vec::new())) }\n    }\n}\n\n/// A compatibility helper type to use common `RpcHandler` functions\nstruct ContextAwareHandler<Handler: PubSubRpcHandler> {\n    handler: Handler,\n    context: PubSubContext<Handler>,\n}\n\nimpl<Handler: PubSubRpcHandler> Clone for ContextAwareHandler<Handler> {\n    fn clone(&self) -> Self {\n        Self { handler: self.handler.clone(), context: self.context.clone() }\n    }\n}\n\n#[async_trait::async_trait]\nimpl<Handler: PubSubRpcHandler> RpcHandler for ContextAwareHandler<Handler> {\n    type Request = Handler::Request;\n\n    async fn on_request(&self, request: Self::Request) -> ResponseResult {\n        self.handler.on_request(request, self.context.clone()).await\n    }\n}\n\n/// Represents a connection to a client via websocket\n///\n/// Contains the state for the entire connection\npub struct PubSubConnection<Handler: PubSubRpcHandler, Connection> {\n    /// the handler for the websocket connection\n    handler: Handler,\n    /// contains all the subscription related context\n    context: PubSubContext<Handler>,\n    /// The established connection\n    connection: Connection,\n    /// currently in progress requests\n    processing: Vec<Pin<Box<dyn Future<Output = Response> + Send>>>,\n    /// pending messages to send\n    pending: VecDeque<String>,\n}\n\nimpl<Handler: PubSubRpcHandler, Connection> PubSubConnection<Handler, Connection> {\n    pub fn new(connection: Connection, handler: Handler) -> Self {\n        Self {\n            connection,\n            handler,\n            context: Default::default(),\n            pending: Default::default(),\n            processing: Default::default(),\n        }\n    }\n\n    /// Returns a compatibility `RpcHandler`\n    fn compat_helper(&self) -> ContextAwareHandler<Handler> {\n        ContextAwareHandler { handler: self.handler.clone(), context: self.context.clone() }\n    }\n\n    fn process_request(&mut self, req: serde_json::Result<Request>) {\n        let handler = self.compat_helper();\n        self.processing.push(Box::pin(async move {\n            match req {\n                Ok(req) => handle_request(req, handler)\n                    .await\n                    .unwrap_or_else(|| Response::error(RpcError::invalid_request())),\n                Err(err) => {\n                    error!(target: \"rpc\", ?err, \"invalid request\");\n                    Response::error(RpcError::invalid_request())\n                }\n            }\n        }));\n    }\n}\n\nimpl<Handler, Connection> Future for PubSubConnection<Handler, Connection>\nwhere\n    Handler: PubSubRpcHandler,\n    Connection: Sink<String> + Stream<Item = Result<Option<Request>, RequestError>> + Unpin,\n    <Connection as Sink<String>>::Error: fmt::Debug,\n{\n    type Output = ();\n\n    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {\n        let pin = self.get_mut();\n        loop {\n            // drive the websocket\n            while matches!(pin.connection.poll_ready_unpin(cx), Poll::Ready(Ok(()))) {\n                // only start sending if socket is ready\n                if let Some(msg) = pin.pending.pop_front() {\n                    if let Err(err) = pin.connection.start_send_unpin(msg) {\n                        error!(target: \"rpc\", ?err, \"Failed to send message\");\n                    }\n                } else {\n                    break;\n                }\n            }\n\n            // Ensure any pending messages are flushed\n            // this needs to be called manually for tungsenite websocket: <https://github.com/foundry-rs/foundry/issues/6345>\n            if let Poll::Ready(Err(err)) = pin.connection.poll_flush_unpin(cx) {\n                trace!(target: \"rpc\", ?err, \"websocket err\");\n                // close the connection\n                return Poll::Ready(());\n            }\n\n            loop {\n                match pin.connection.poll_next_unpin(cx) {\n                    Poll::Ready(Some(req)) => match req {\n                        Ok(Some(req)) => {\n                            pin.process_request(Ok(req));\n                        }\n                        Err(err) => match err {\n                            RequestError::Axum(err) => {\n                                trace!(target: \"rpc\", ?err, \"client disconnected\");\n                                return Poll::Ready(());\n                            }\n                            RequestError::Io(err) => {\n                                trace!(target: \"rpc\", ?err, \"client disconnected\");\n                                return Poll::Ready(());\n                            }\n                            RequestError::Serde(err) => {\n                                pin.process_request(Err(err));\n                            }\n                            RequestError::Disconnect => {\n                                trace!(target: \"rpc\", \"client disconnected\");\n                                return Poll::Ready(());\n                            }\n                        },\n                        _ => {}\n                    },\n                    Poll::Ready(None) => {\n                        trace!(target: \"rpc\", \"socket connection finished\");\n                        return Poll::Ready(());\n                    }\n                    Poll::Pending => break,\n                }\n            }\n\n            let mut progress = false;\n            for n in (0..pin.processing.len()).rev() {\n                let mut req = pin.processing.swap_remove(n);\n                #[allow(clippy::collapsible_match)]\n                match req.poll_unpin(cx) {\n                    Poll::Ready(resp) => {\n                        if let Ok(text) = serde_json::to_string(&resp) {\n                            pin.pending.push_back(text);\n                            progress = true;\n                        }\n                    }\n                    Poll::Pending => pin.processing.push(req),\n                }\n            }\n\n            {\n                // process subscription events\n                let mut subscriptions = pin.context.subscriptions.lock();\n                'outer: for n in (0..subscriptions.len()).rev() {\n                    let (id, mut sub) = subscriptions.swap_remove(n);\n                    'inner: loop {\n                        #[allow(clippy::collapsible_match)]\n                        match sub.poll_next_unpin(cx) {\n                            Poll::Ready(Some(res)) => {\n                                if let Ok(text) = serde_json::to_string(&res) {\n                                    pin.pending.push_back(text);\n                                    progress = true;\n                                }\n                            }\n                            Poll::Ready(None) => continue 'outer,\n                            Poll::Pending => break 'inner,\n                        }\n                    }\n\n                    subscriptions.push((id, sub));\n                }\n            }\n\n            if !progress {\n                return Poll::Pending;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "crates/anvil/server/src/ws.rs",
    "content": "use crate::{PubSubRpcHandler, error::RequestError, pubsub::PubSubConnection};\nuse anvil_rpc::request::Request;\nuse axum::{\n    extract::{\n        State, WebSocketUpgrade,\n        ws::{Message, WebSocket},\n    },\n    response::Response,\n};\nuse futures::{Sink, Stream, ready};\nuse std::{\n    pin::Pin,\n    task::{Context, Poll},\n};\n\n/// Handles incoming Websocket upgrade\n///\n/// This is the entrypoint invoked by the axum server for a websocket request\npub async fn handle_ws<Http, Ws: PubSubRpcHandler>(\n    ws: WebSocketUpgrade,\n    State((_, handler)): State<(Http, Ws)>,\n) -> Response {\n    ws.on_upgrade(|socket| PubSubConnection::new(SocketConn(socket), handler))\n}\n\n#[pin_project::pin_project]\nstruct SocketConn(#[pin] WebSocket);\n\nimpl Stream for SocketConn {\n    type Item = Result<Option<Request>, RequestError>;\n\n    fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {\n        match ready!(self.project().0.poll_next(cx)) {\n            Some(msg) => Poll::Ready(Some(on_message(msg))),\n            _ => Poll::Ready(None),\n        }\n    }\n}\n\nimpl Sink<String> for SocketConn {\n    type Error = axum::Error;\n\n    fn poll_ready(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {\n        self.project().0.poll_ready(cx)\n    }\n\n    fn start_send(self: Pin<&mut Self>, item: String) -> Result<(), Self::Error> {\n        self.project().0.start_send(Message::Text(item.into()))\n    }\n\n    fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {\n        self.project().0.poll_flush(cx)\n    }\n\n    fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {\n        self.project().0.poll_close(cx)\n    }\n}\n\nfn on_message(msg: Result<Message, axum::Error>) -> Result<Option<Request>, RequestError> {\n    match msg? {\n        Message::Text(text) => Ok(Some(serde_json::from_str(&text)?)),\n        Message::Binary(data) => {\n            // the binary payload type is the request as-is but as bytes, if this is a valid\n            // `Request` then we can deserialize the Json from the data Vec\n            Ok(Some(serde_json::from_slice(&data)?))\n        }\n        Message::Close(_) => {\n            trace!(target: \"rpc::ws\", \"ws client disconnected\");\n            Err(RequestError::Disconnect)\n        }\n        _ => Ok(None),\n    }\n}\n"
  },
  {
    "path": "crates/anvil/src/args.rs",
    "content": "use crate::opts::{Anvil, AnvilSubcommand};\nuse clap::{CommandFactory, Parser};\nuse eyre::Result;\nuse foundry_cli::utils;\n\n/// Run the `anvil` command line interface.\npub fn run() -> Result<()> {\n    setup()?;\n\n    foundry_cli::opts::GlobalArgs::check_markdown_help::<Anvil>();\n\n    let mut args = Anvil::parse();\n    args.global.init()?;\n    args.node.evm.resolve_rpc_alias();\n\n    run_command(args)\n}\n\n/// Setup the exception handler and other utilities.\npub fn setup() -> Result<()> {\n    utils::common_setup();\n\n    Ok(())\n}\n\n/// Run the subcommand.\npub fn run_command(args: Anvil) -> Result<()> {\n    if let Some(cmd) = &args.cmd {\n        match cmd {\n            AnvilSubcommand::Completions { shell } => {\n                clap_complete::generate(\n                    *shell,\n                    &mut Anvil::command(),\n                    \"anvil\",\n                    &mut std::io::stdout(),\n                );\n            }\n        }\n        return Ok(());\n    }\n\n    let _ = fdlimit::raise_fd_limit();\n    args.global.tokio_runtime().block_on(args.node.run())\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn verify_cli() {\n        Anvil::command().debug_assert();\n    }\n\n    #[test]\n    fn can_parse_help() {\n        let _: Anvil = Anvil::parse_from([\"anvil\", \"--help\"]);\n    }\n\n    #[test]\n    fn can_parse_short_version() {\n        let _: Anvil = Anvil::parse_from([\"anvil\", \"-V\"]);\n    }\n\n    #[test]\n    fn can_parse_long_version() {\n        let _: Anvil = Anvil::parse_from([\"anvil\", \"--version\"]);\n    }\n\n    #[test]\n    fn can_parse_completions() {\n        let args: Anvil = Anvil::parse_from([\"anvil\", \"completions\", \"bash\"]);\n        assert!(matches!(\n            args.cmd,\n            Some(AnvilSubcommand::Completions {\n                shell: foundry_cli::clap::Shell::ClapCompleteShell(clap_complete::Shell::Bash)\n            })\n        ));\n    }\n}\n"
  },
  {
    "path": "crates/anvil/src/cmd.rs",
    "content": "use crate::{\n    AccountGenerator, CHAIN_ID, NodeConfig,\n    config::{DEFAULT_MNEMONIC, ForkChoice},\n    eth::{EthApi, backend::db::SerializableState, pool::transactions::TransactionOrder},\n};\nuse alloy_genesis::Genesis;\nuse alloy_primitives::{B256, U256, utils::Unit};\nuse alloy_signer_local::coins_bip39::{English, Mnemonic};\nuse anvil_server::ServerConfig;\nuse clap::Parser;\nuse core::fmt;\nuse foundry_common::shell;\nuse foundry_config::{Chain, Config, FigmentProviders};\nuse foundry_evm::hardfork::{EthereumHardfork, OpHardfork};\nuse foundry_evm_networks::NetworkConfigs;\nuse foundry_primitives::FoundryNetwork;\nuse futures::FutureExt;\nuse rand_08::{SeedableRng, rngs::StdRng};\nuse std::{\n    net::IpAddr,\n    path::{Path, PathBuf},\n    pin::Pin,\n    str::FromStr,\n    sync::{\n        Arc,\n        atomic::{AtomicUsize, Ordering},\n    },\n    task::{Context, Poll},\n    time::Duration,\n};\nuse tokio::time::{Instant, Interval};\n\n#[derive(Clone, Debug, Parser)]\npub struct NodeArgs {\n    /// Port number to listen on.\n    #[arg(long, short, default_value = \"8545\", value_name = \"NUM\")]\n    pub port: u16,\n\n    /// Number of dev accounts to generate and configure.\n    #[arg(long, short, default_value = \"10\", value_name = \"NUM\")]\n    pub accounts: u64,\n\n    /// The balance of every dev account in Ether.\n    #[arg(long, default_value = \"10000\", value_name = \"NUM\")]\n    pub balance: u64,\n\n    /// The timestamp of the genesis block.\n    #[arg(long, value_name = \"NUM\")]\n    pub timestamp: Option<u64>,\n\n    /// The number of the genesis block.\n    #[arg(long, value_name = \"NUM\")]\n    pub number: Option<u64>,\n\n    /// BIP39 mnemonic phrase used for generating accounts.\n    /// Cannot be used if `mnemonic_random` or `mnemonic_seed` are used.\n    #[arg(long, short, conflicts_with_all = &[\"mnemonic_seed\", \"mnemonic_random\"])]\n    pub mnemonic: Option<String>,\n\n    /// Automatically generates a BIP39 mnemonic phrase, and derives accounts from it.\n    /// Cannot be used with other `mnemonic` options.\n    /// You can specify the number of words you want in the mnemonic.\n    /// [default: 12]\n    #[arg(long, conflicts_with_all = &[\"mnemonic\", \"mnemonic_seed\"], default_missing_value = \"12\", num_args(0..=1))]\n    pub mnemonic_random: Option<usize>,\n\n    /// Generates a BIP39 mnemonic phrase from a given seed\n    /// Cannot be used with other `mnemonic` options.\n    ///\n    /// CAREFUL: This is NOT SAFE and should only be used for testing.\n    /// Never use the private keys generated in production.\n    #[arg(long = \"mnemonic-seed-unsafe\", conflicts_with_all = &[\"mnemonic\", \"mnemonic_random\"])]\n    pub mnemonic_seed: Option<u64>,\n\n    /// Sets the derivation path of the child key to be derived.\n    ///\n    /// [default: m/44'/60'/0'/0/]\n    #[arg(long)]\n    pub derivation_path: Option<String>,\n\n    /// The EVM hardfork to use.\n    ///\n    /// Choose the hardfork by name, e.g. `prague`, `cancun`, `shanghai`, `paris`, `london`, etc...\n    /// [default: latest]\n    #[arg(long)]\n    pub hardfork: Option<String>,\n\n    /// Block time in seconds for interval mining.\n    #[arg(short, long, visible_alias = \"blockTime\", value_name = \"SECONDS\", value_parser = duration_from_secs_f64)]\n    pub block_time: Option<Duration>,\n\n    /// Slots in an epoch\n    #[arg(long, value_name = \"SLOTS_IN_AN_EPOCH\", default_value_t = 32)]\n    pub slots_in_an_epoch: u64,\n\n    /// Writes output of `anvil` as json to user-specified file.\n    #[arg(long, value_name = \"FILE\", value_hint = clap::ValueHint::FilePath)]\n    pub config_out: Option<PathBuf>,\n\n    /// Disable auto and interval mining, and mine on demand instead.\n    #[arg(long, visible_alias = \"no-mine\", conflicts_with = \"block_time\")]\n    pub no_mining: bool,\n\n    #[arg(long, requires = \"block_time\")]\n    pub mixed_mining: bool,\n\n    /// The hosts the server will listen on.\n    #[arg(\n        long,\n        value_name = \"IP_ADDR\",\n        env = \"ANVIL_IP_ADDR\",\n        default_value = \"127.0.0.1\",\n        help_heading = \"Server options\",\n        value_delimiter = ','\n    )]\n    pub host: Vec<IpAddr>,\n\n    /// How transactions are sorted in the mempool.\n    #[arg(long, default_value = \"fees\")]\n    pub order: TransactionOrder,\n\n    /// Initialize the genesis block with the given `genesis.json` file.\n    #[arg(long, value_name = \"PATH\", value_parser= read_genesis_file)]\n    pub init: Option<Genesis>,\n\n    /// This is an alias for both --load-state and --dump-state.\n    ///\n    /// It initializes the chain with the state and block environment stored at the file, if it\n    /// exists, and dumps the chain's state on exit.\n    #[arg(\n        long,\n        value_name = \"PATH\",\n        value_parser = StateFile::parse,\n        conflicts_with_all = &[\n            \"init\",\n            \"dump_state\",\n            \"load_state\"\n        ]\n    )]\n    pub state: Option<StateFile>,\n\n    /// Interval in seconds at which the state and block environment is to be dumped to disk.\n    ///\n    /// See --state and --dump-state\n    #[arg(short, long, value_name = \"SECONDS\")]\n    pub state_interval: Option<u64>,\n\n    /// Dump the state and block environment of chain on exit to the given file.\n    ///\n    /// If the value is a directory, the state will be written to `<VALUE>/state.json`.\n    #[arg(long, value_name = \"PATH\", conflicts_with = \"init\")]\n    pub dump_state: Option<PathBuf>,\n\n    /// Preserve historical state snapshots when dumping the state.\n    ///\n    /// This will save the in-memory states of the chain at particular block hashes.\n    ///\n    /// These historical states will be loaded into the memory when `--load-state` / `--state`, and\n    /// aids in RPC calls beyond the block at which state was dumped.\n    #[arg(long, conflicts_with = \"init\", default_value = \"false\")]\n    pub preserve_historical_states: bool,\n\n    /// Initialize the chain from a previously saved state snapshot.\n    #[arg(\n        long,\n        value_name = \"PATH\",\n        value_parser = SerializableState::parse,\n        conflicts_with = \"init\"\n    )]\n    pub load_state: Option<SerializableState>,\n\n    #[arg(long, help = IPC_HELP, value_name = \"PATH\", visible_alias = \"ipcpath\")]\n    pub ipc: Option<Option<String>>,\n\n    /// Don't keep full chain history.\n    /// If a number argument is specified, at most this number of states is kept in memory.\n    ///\n    /// If enabled, no state will be persisted on disk, so `max_persisted_states` will be 0.\n    #[arg(long)]\n    pub prune_history: Option<Option<usize>>,\n\n    /// Max number of states to persist on disk.\n    ///\n    /// Note that `prune_history` will overwrite `max_persisted_states` to 0.\n    #[arg(long, conflicts_with = \"prune_history\")]\n    pub max_persisted_states: Option<usize>,\n\n    /// Number of blocks with transactions to keep in memory.\n    #[arg(long)]\n    pub transaction_block_keeper: Option<usize>,\n\n    /// Maximum number of transactions in a block.\n    #[arg(long)]\n    pub max_transactions: Option<usize>,\n\n    #[command(flatten)]\n    pub evm: AnvilEvmArgs,\n\n    #[command(flatten)]\n    pub server_config: ServerConfig,\n\n    /// Path to the cache directory where persisted states are stored (see\n    /// `--max-persisted-states`).\n    ///\n    /// Note: This does not affect the fork RPC cache location (`storage.json`), which is stored in\n    /// `~/.foundry/cache/rpc/<chain>/<block>/`.\n    #[arg(long, value_name = \"PATH\")]\n    pub cache_path: Option<PathBuf>,\n}\n\n#[cfg(windows)]\nconst IPC_HELP: &str =\n    \"Launch an ipc server at the given path or default path = `\\\\.\\\\pipe\\\\anvil.ipc`\";\n\n/// The default IPC endpoint\n#[cfg(not(windows))]\nconst IPC_HELP: &str = \"Launch an ipc server at the given path or default path = `/tmp/anvil.ipc`\";\n\n/// Default interval for periodically dumping the state.\nconst DEFAULT_DUMP_INTERVAL: Duration = Duration::from_secs(60);\n\nimpl NodeArgs {\n    pub fn into_node_config(self) -> eyre::Result<NodeConfig> {\n        let genesis_balance = Unit::ETHER.wei().saturating_mul(U256::from(self.balance));\n        let compute_units_per_second =\n            if self.evm.no_rate_limit { Some(u64::MAX) } else { self.evm.compute_units_per_second };\n\n        let hardfork = match &self.hardfork {\n            Some(hf) => {\n                if self.evm.networks.is_optimism() {\n                    Some(OpHardfork::from_str(hf)?.into())\n                } else {\n                    Some(EthereumHardfork::from_str(hf)?.into())\n                }\n            }\n            None => None,\n        };\n\n        Ok(NodeConfig::default()\n            .with_gas_limit(self.evm.gas_limit)\n            .disable_block_gas_limit(self.evm.disable_block_gas_limit)\n            .enable_tx_gas_limit(self.evm.enable_tx_gas_limit)\n            .with_gas_price(self.evm.gas_price)\n            .with_hardfork(hardfork)\n            .with_blocktime(self.block_time)\n            .with_no_mining(self.no_mining)\n            .with_mixed_mining(self.mixed_mining, self.block_time)\n            .with_account_generator(self.account_generator())?\n            .with_genesis_balance(genesis_balance)\n            .with_genesis_timestamp(self.timestamp)\n            .with_genesis_block_number(self.number)\n            .with_port(self.port)\n            .with_fork_choice(match (self.evm.fork_block_number, self.evm.fork_transaction_hash) {\n                (Some(block), None) => Some(ForkChoice::Block(block)),\n                (None, Some(hash)) => Some(ForkChoice::Transaction(hash)),\n                _ => self\n                    .evm\n                    .fork_url\n                    .as_ref()\n                    .and_then(|f| f.block)\n                    .map(|num| ForkChoice::Block(num as i128)),\n            })\n            .with_fork_headers(self.evm.fork_headers)\n            .with_fork_chain_id(self.evm.fork_chain_id.map(u64::from).map(U256::from))\n            .fork_request_timeout(self.evm.fork_request_timeout.map(Duration::from_millis))\n            .fork_request_retries(self.evm.fork_request_retries)\n            .fork_retry_backoff(self.evm.fork_retry_backoff.map(Duration::from_millis))\n            .fork_compute_units_per_second(compute_units_per_second)\n            .with_eth_rpc_url(self.evm.fork_url.map(|fork| fork.url))\n            .with_base_fee(self.evm.block_base_fee_per_gas)\n            .disable_min_priority_fee(self.evm.disable_min_priority_fee)\n            .with_no_storage_caching(self.evm.no_storage_caching)\n            .with_server_config(self.server_config)\n            .with_host(self.host)\n            .set_silent(shell::is_quiet())\n            .set_config_out(self.config_out)\n            .with_chain_id(self.evm.chain_id)\n            .with_transaction_order(self.order)\n            .with_genesis(self.init)\n            .with_steps_tracing(self.evm.steps_tracing)\n            .with_print_logs(!self.evm.disable_console_log)\n            .with_print_traces(self.evm.print_traces)\n            .with_auto_impersonate(self.evm.auto_impersonate)\n            .with_ipc(self.ipc)\n            .with_code_size_limit(self.evm.code_size_limit)\n            .disable_code_size_limit(self.evm.disable_code_size_limit)\n            .set_pruned_history(self.prune_history)\n            .with_init_state(self.load_state.or_else(|| self.state.and_then(|s| s.state)))\n            .with_transaction_block_keeper(self.transaction_block_keeper)\n            .with_max_transactions(self.max_transactions)\n            .with_max_persisted_states(self.max_persisted_states)\n            .with_networks(self.evm.networks)\n            .with_disable_default_create2_deployer(self.evm.disable_default_create2_deployer)\n            .with_disable_pool_balance_checks(self.evm.disable_pool_balance_checks)\n            .with_slots_in_an_epoch(self.slots_in_an_epoch)\n            .with_memory_limit(self.evm.memory_limit)\n            .with_cache_path(self.cache_path))\n    }\n\n    fn account_generator(&self) -> AccountGenerator {\n        let mut generator = AccountGenerator::new(self.accounts as usize)\n            .phrase(DEFAULT_MNEMONIC)\n            .chain_id(self.evm.chain_id.unwrap_or(CHAIN_ID.into()));\n        if let Some(ref mnemonic) = self.mnemonic {\n            generator = generator.phrase(mnemonic);\n        } else if let Some(count) = self.mnemonic_random {\n            let mut rng = rand_08::thread_rng();\n            let mnemonic = match Mnemonic::<English>::new_with_count(&mut rng, count) {\n                Ok(mnemonic) => mnemonic.to_phrase(),\n                Err(err) => {\n                    warn!(target: \"node\", ?count, %err, \"failed to generate mnemonic, falling back to 12-word random mnemonic\");\n                    // Fallback: generate a valid 12-word random mnemonic instead of using\n                    // DEFAULT_MNEMONIC\n                    Mnemonic::<English>::new_with_count(&mut rng, 12)\n                        .expect(\"valid default word count\")\n                        .to_phrase()\n                }\n            };\n            generator = generator.phrase(mnemonic);\n        } else if let Some(seed) = self.mnemonic_seed {\n            let mut seed = StdRng::seed_from_u64(seed);\n            let mnemonic = Mnemonic::<English>::new(&mut seed).to_phrase();\n            generator = generator.phrase(mnemonic);\n        }\n        if let Some(ref derivation) = self.derivation_path {\n            generator = generator.derivation_path(derivation);\n        }\n        generator\n    }\n\n    /// Returns the location where to dump the state to.\n    fn dump_state_path(&self) -> Option<PathBuf> {\n        self.dump_state.as_ref().or_else(|| self.state.as_ref().map(|s| &s.path)).cloned()\n    }\n\n    /// Starts the node\n    ///\n    /// See also [crate::spawn()]\n    pub async fn run(self) -> eyre::Result<()> {\n        let dump_state = self.dump_state_path();\n        let dump_interval =\n            self.state_interval.map(Duration::from_secs).unwrap_or(DEFAULT_DUMP_INTERVAL);\n        let preserve_historical_states = self.preserve_historical_states;\n\n        let (api, mut handle) = crate::try_spawn(self.into_node_config()?).await?;\n\n        // sets the signal handler to gracefully shutdown.\n        let mut fork = api.get_fork();\n        let running = Arc::new(AtomicUsize::new(0));\n\n        // handle for the currently running rt, this must be obtained before setting the crtlc\n        // handler, See [Handle::current]\n        let mut signal = handle.shutdown_signal_mut().take();\n\n        let task_manager = handle.task_manager();\n        let mut on_shutdown = task_manager.on_shutdown();\n\n        let mut state_dumper =\n            PeriodicStateDumper::new(api, dump_state, dump_interval, preserve_historical_states);\n\n        task_manager.spawn(async move {\n            // wait for the SIGTERM signal on unix systems\n            #[cfg(unix)]\n            let mut sigterm = Box::pin(async {\n                if let Ok(mut stream) =\n                    tokio::signal::unix::signal(tokio::signal::unix::SignalKind::terminate())\n                {\n                    stream.recv().await;\n                } else {\n                    futures::future::pending::<()>().await;\n                }\n            });\n\n            // On windows, this will never fire.\n            #[cfg(not(unix))]\n            let mut sigterm = Box::pin(futures::future::pending::<()>());\n\n            // await shutdown signal but also periodically flush state\n            tokio::select! {\n                 _ = &mut sigterm => {\n                    trace!(\"received sigterm signal, shutting down\");\n                }\n                _ = &mut on_shutdown => {}\n                _ = &mut state_dumper => {}\n            }\n\n            // shutdown received\n            state_dumper.dump().await;\n\n            // cleaning up and shutting down\n            // this will make sure that the fork RPC cache is flushed if caching is configured\n            if let Some(fork) = fork.take() {\n                trace!(\"flushing cache on shutdown\");\n                fork.database\n                    .read()\n                    .await\n                    .maybe_flush_cache()\n                    .expect(\"Could not flush cache on fork DB\");\n                // cleaning up and shutting down\n                // this will make sure that the fork RPC cache is flushed if caching is configured\n            }\n            std::process::exit(0);\n        });\n\n        ctrlc::set_handler(move || {\n            let prev = running.fetch_add(1, Ordering::SeqCst);\n            if prev == 0 {\n                trace!(\"received shutdown signal, shutting down\");\n                let _ = signal.take();\n            }\n        })\n        .expect(\"Error setting Ctrl-C handler\");\n\n        Ok(handle.await??)\n    }\n}\n\n/// Anvil's EVM related arguments.\n#[derive(Clone, Debug, Parser)]\n#[command(next_help_heading = \"EVM options\")]\npub struct AnvilEvmArgs {\n    /// Fetch state over a remote endpoint instead of starting from an empty state.\n    ///\n    /// If you want to fetch state from a specific block number, add a block number like `http://localhost:8545@1400000` or use the `--fork-block-number` argument.\n    #[arg(\n        long,\n        short,\n        visible_alias = \"rpc-url\",\n        value_name = \"URL\",\n        help_heading = \"Fork config\"\n    )]\n    pub fork_url: Option<ForkUrl>,\n\n    /// Headers to use for the rpc client, e.g. \"User-Agent: test-agent\"\n    ///\n    /// See --fork-url.\n    #[arg(\n        long = \"fork-header\",\n        value_name = \"HEADERS\",\n        help_heading = \"Fork config\",\n        requires = \"fork_url\"\n    )]\n    pub fork_headers: Vec<String>,\n\n    /// Timeout in ms for requests sent to remote JSON-RPC server in forking mode.\n    ///\n    /// Default value 45000\n    #[arg(id = \"timeout\", long = \"timeout\", help_heading = \"Fork config\", requires = \"fork_url\")]\n    pub fork_request_timeout: Option<u64>,\n\n    /// Number of retry requests for spurious networks (timed out requests)\n    ///\n    /// Default value 5\n    #[arg(id = \"retries\", long = \"retries\", help_heading = \"Fork config\", requires = \"fork_url\")]\n    pub fork_request_retries: Option<u32>,\n\n    /// Fetch state from a specific block number over a remote endpoint.\n    ///\n    /// If negative, the given value is subtracted from the `latest` block number.\n    ///\n    /// See --fork-url.\n    #[arg(\n        long,\n        requires = \"fork_url\",\n        value_name = \"BLOCK\",\n        help_heading = \"Fork config\",\n        allow_hyphen_values = true\n    )]\n    pub fork_block_number: Option<i128>,\n\n    /// Fetch state from after a specific transaction hash has been applied over a remote endpoint.\n    ///\n    /// See --fork-url.\n    #[arg(\n        long,\n        requires = \"fork_url\",\n        value_name = \"TRANSACTION\",\n        help_heading = \"Fork config\",\n        conflicts_with = \"fork_block_number\"\n    )]\n    pub fork_transaction_hash: Option<B256>,\n\n    /// Initial retry backoff on encountering errors.\n    ///\n    /// See --fork-url.\n    #[arg(long, requires = \"fork_url\", value_name = \"BACKOFF\", help_heading = \"Fork config\")]\n    pub fork_retry_backoff: Option<u64>,\n\n    /// Specify chain id to skip fetching it from remote endpoint. This enables offline-start mode.\n    ///\n    /// You still must pass both `--fork-url` and `--fork-block-number`, and already have your\n    /// required state cached on disk, anything missing locally would be fetched from the\n    /// remote.\n    #[arg(\n        long,\n        help_heading = \"Fork config\",\n        value_name = \"CHAIN\",\n        requires = \"fork_block_number\"\n    )]\n    pub fork_chain_id: Option<Chain>,\n\n    /// Sets the number of assumed available compute units per second for this provider\n    ///\n    /// default value: 330\n    ///\n    /// See also --fork-url and <https://docs.alchemy.com/reference/compute-units#what-are-cups-compute-units-per-second>\n    #[arg(\n        long,\n        requires = \"fork_url\",\n        alias = \"cups\",\n        value_name = \"CUPS\",\n        help_heading = \"Fork config\"\n    )]\n    pub compute_units_per_second: Option<u64>,\n\n    /// Disables rate limiting for this node's provider.\n    ///\n    /// default value: false\n    ///\n    /// See also --fork-url and <https://docs.alchemy.com/reference/compute-units#what-are-cups-compute-units-per-second>\n    #[arg(\n        long,\n        requires = \"fork_url\",\n        value_name = \"NO_RATE_LIMITS\",\n        help_heading = \"Fork config\",\n        visible_alias = \"no-rpc-rate-limit\"\n    )]\n    pub no_rate_limit: bool,\n\n    /// Explicitly disables the use of RPC caching.\n    ///\n    /// All storage slots are read entirely from the endpoint.\n    ///\n    /// This flag overrides the project's configuration file.\n    ///\n    /// See --fork-url.\n    #[arg(long, requires = \"fork_url\", help_heading = \"Fork config\")]\n    pub no_storage_caching: bool,\n\n    /// The block gas limit.\n    #[arg(long, alias = \"block-gas-limit\", help_heading = \"Environment config\")]\n    pub gas_limit: Option<u64>,\n\n    /// Disable the `call.gas_limit <= block.gas_limit` constraint.\n    #[arg(\n        long,\n        value_name = \"DISABLE_GAS_LIMIT\",\n        help_heading = \"Environment config\",\n        alias = \"disable-gas-limit\",\n        conflicts_with = \"gas_limit\"\n    )]\n    pub disable_block_gas_limit: bool,\n\n    /// Enable the transaction gas limit check as imposed by EIP-7825 (Osaka hardfork).\n    #[arg(long, visible_alias = \"tx-gas-limit\", help_heading = \"Environment config\")]\n    pub enable_tx_gas_limit: bool,\n\n    /// EIP-170: Contract code size limit in bytes. Useful to increase this because of tests. To\n    /// disable entirely, use `--disable-code-size-limit`. By default, it is 0x6000 (~25kb).\n    #[arg(long, value_name = \"CODE_SIZE\", help_heading = \"Environment config\")]\n    pub code_size_limit: Option<usize>,\n\n    /// Disable EIP-170: Contract code size limit.\n    #[arg(\n        long,\n        value_name = \"DISABLE_CODE_SIZE_LIMIT\",\n        conflicts_with = \"code_size_limit\",\n        help_heading = \"Environment config\"\n    )]\n    pub disable_code_size_limit: bool,\n\n    /// The gas price.\n    #[arg(long, help_heading = \"Environment config\")]\n    pub gas_price: Option<u128>,\n\n    /// The base fee in a block.\n    #[arg(\n        long,\n        visible_alias = \"base-fee\",\n        value_name = \"FEE\",\n        help_heading = \"Environment config\"\n    )]\n    pub block_base_fee_per_gas: Option<u64>,\n\n    /// Disable the enforcement of a minimum suggested priority fee.\n    #[arg(long, visible_alias = \"no-priority-fee\", help_heading = \"Environment config\")]\n    pub disable_min_priority_fee: bool,\n\n    /// The chain ID.\n    #[arg(long, alias = \"chain\", help_heading = \"Environment config\")]\n    pub chain_id: Option<Chain>,\n\n    /// Enable steps tracing used for debug calls returning geth-style traces\n    #[arg(long, visible_alias = \"tracing\")]\n    pub steps_tracing: bool,\n\n    /// Disable printing of `console.log` invocations to stdout.\n    #[arg(long, visible_alias = \"no-console-log\")]\n    pub disable_console_log: bool,\n\n    /// Enable printing of traces for executed transactions and `eth_call` to stdout.\n    #[arg(long, visible_alias = \"enable-trace-printing\")]\n    pub print_traces: bool,\n\n    /// Enables automatic impersonation on startup. This allows any transaction sender to be\n    /// simulated as different accounts, which is useful for testing contract behavior.\n    #[arg(long, visible_alias = \"auto-unlock\")]\n    pub auto_impersonate: bool,\n\n    /// Disable the default create2 deployer\n    #[arg(long, visible_alias = \"no-create2\")]\n    pub disable_default_create2_deployer: bool,\n\n    /// Disable pool balance checks\n    #[arg(long)]\n    pub disable_pool_balance_checks: bool,\n\n    /// The memory limit per EVM execution in bytes.\n    #[arg(long)]\n    pub memory_limit: Option<u64>,\n\n    #[command(flatten)]\n    pub networks: NetworkConfigs,\n}\n\n/// Resolves an alias passed as fork-url to the matching url defined in the rpc_endpoints section\n/// of the project configuration file.\n/// Does nothing if the fork-url is not a configured alias.\nimpl AnvilEvmArgs {\n    pub fn resolve_rpc_alias(&mut self) {\n        if let Some(fork_url) = &self.fork_url\n            && let Ok(config) = Config::load_with_providers(FigmentProviders::Anvil)\n            && let Some(Ok(url)) = config.get_rpc_url_with_alias(&fork_url.url)\n        {\n            self.fork_url = Some(ForkUrl { url: url.to_string(), block: fork_url.block });\n        }\n    }\n}\n\n/// Helper type to periodically dump the state of the chain to disk\nstruct PeriodicStateDumper {\n    in_progress_dump: Option<Pin<Box<dyn Future<Output = ()> + Send + Sync + 'static>>>,\n    api: EthApi<FoundryNetwork>,\n    dump_state: Option<PathBuf>,\n    preserve_historical_states: bool,\n    interval: Interval,\n}\n\nimpl PeriodicStateDumper {\n    fn new(\n        api: EthApi<FoundryNetwork>,\n        dump_state: Option<PathBuf>,\n        interval: Duration,\n        preserve_historical_states: bool,\n    ) -> Self {\n        let dump_state = dump_state.map(|mut dump_state| {\n            if dump_state.is_dir() {\n                dump_state = dump_state.join(\"state.json\");\n            }\n            dump_state\n        });\n\n        // periodically flush the state\n        let interval = tokio::time::interval_at(Instant::now() + interval, interval);\n        Self { in_progress_dump: None, api, dump_state, preserve_historical_states, interval }\n    }\n\n    async fn dump(&self) {\n        if let Some(state) = self.dump_state.clone() {\n            Self::dump_state(self.api.clone(), state, self.preserve_historical_states).await\n        }\n    }\n\n    /// Infallible state dump\n    async fn dump_state(\n        api: EthApi<FoundryNetwork>,\n        dump_state: PathBuf,\n        preserve_historical_states: bool,\n    ) {\n        trace!(path=?dump_state, \"Dumping state on shutdown\");\n        match api.serialized_state(preserve_historical_states).await {\n            Ok(state) => {\n                if let Err(err) = foundry_common::fs::write_json_file(&dump_state, &state) {\n                    error!(?err, \"Failed to dump state\");\n                } else {\n                    trace!(path=?dump_state, \"Dumped state on shutdown\");\n                }\n            }\n            Err(err) => {\n                error!(?err, \"Failed to extract state\");\n            }\n        }\n    }\n}\n\n// An endless future that periodically dumps the state to disk if configured.\nimpl Future for PeriodicStateDumper {\n    type Output = ();\n\n    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {\n        let this = self.get_mut();\n        if this.dump_state.is_none() {\n            return Poll::Pending;\n        }\n\n        loop {\n            if let Some(mut flush) = this.in_progress_dump.take() {\n                match flush.poll_unpin(cx) {\n                    Poll::Ready(_) => {\n                        this.interval.reset();\n                    }\n                    Poll::Pending => {\n                        this.in_progress_dump = Some(flush);\n                        return Poll::Pending;\n                    }\n                }\n            }\n\n            if this.interval.poll_tick(cx).is_ready() {\n                let api = this.api.clone();\n                let path = this.dump_state.clone().expect(\"exists; see above\");\n                this.in_progress_dump =\n                    Some(Box::pin(Self::dump_state(api, path, this.preserve_historical_states)));\n            } else {\n                break;\n            }\n        }\n\n        Poll::Pending\n    }\n}\n\n/// Represents the --state flag and where to load from, or dump the state to\n#[derive(Clone, Debug)]\npub struct StateFile {\n    pub path: PathBuf,\n    pub state: Option<SerializableState>,\n}\n\nimpl StateFile {\n    /// This is used as the clap `value_parser` implementation to parse from file but only if it\n    /// exists\n    fn parse(path: &str) -> Result<Self, String> {\n        Self::parse_path(path)\n    }\n\n    /// Parse from file but only if it exists\n    pub fn parse_path(path: impl AsRef<Path>) -> Result<Self, String> {\n        let mut path = path.as_ref().to_path_buf();\n        if path.is_dir() {\n            path = path.join(\"state.json\");\n        }\n        let mut state = Self { path, state: None };\n        if !state.path.exists() {\n            return Ok(state);\n        }\n\n        state.state = Some(SerializableState::load(&state.path).map_err(|err| err.to_string())?);\n\n        Ok(state)\n    }\n}\n\n/// Represents the input URL for a fork with an optional trailing block number:\n/// `http://localhost:8545@1000000`\n#[derive(Clone, Debug, PartialEq, Eq)]\npub struct ForkUrl {\n    /// The endpoint url\n    pub url: String,\n    /// Optional trailing block\n    pub block: Option<u64>,\n}\n\nimpl fmt::Display for ForkUrl {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        self.url.fmt(f)?;\n        if let Some(block) = self.block {\n            write!(f, \"@{block}\")?;\n        }\n        Ok(())\n    }\n}\n\nimpl FromStr for ForkUrl {\n    type Err = String;\n\n    fn from_str(s: &str) -> Result<Self, Self::Err> {\n        if let Some((url, block)) = s.rsplit_once('@') {\n            if block == \"latest\" {\n                return Ok(Self { url: url.to_string(), block: None });\n            }\n            // this will prevent false positives for auths `user:password@example.com`\n            if !block.is_empty() && !block.contains(':') && !block.contains('.') {\n                let block: u64 = block\n                    .parse()\n                    .map_err(|_| format!(\"Failed to parse block number: `{block}`\"))?;\n                return Ok(Self { url: url.to_string(), block: Some(block) });\n            }\n        }\n        Ok(Self { url: s.to_string(), block: None })\n    }\n}\n\n/// Clap's value parser for genesis. Loads a genesis.json file.\nfn read_genesis_file(path: &str) -> Result<Genesis, String> {\n    foundry_common::fs::read_json_file(path.as_ref()).map_err(|err| err.to_string())\n}\n\nfn duration_from_secs_f64(s: &str) -> Result<Duration, String> {\n    let s = s.parse::<f64>().map_err(|e| e.to_string())?;\n    if s == 0.0 {\n        return Err(\"Duration must be greater than 0\".to_string());\n    }\n    Duration::try_from_secs_f64(s).map_err(|e| e.to_string())\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use std::{env, net::Ipv4Addr};\n\n    #[test]\n    fn test_parse_fork_url() {\n        let fork: ForkUrl = \"http://localhost:8545@1000000\".parse().unwrap();\n        assert_eq!(\n            fork,\n            ForkUrl { url: \"http://localhost:8545\".to_string(), block: Some(1000000) }\n        );\n\n        let fork: ForkUrl = \"http://localhost:8545\".parse().unwrap();\n        assert_eq!(fork, ForkUrl { url: \"http://localhost:8545\".to_string(), block: None });\n\n        let fork: ForkUrl = \"wss://user:password@example.com/\".parse().unwrap();\n        assert_eq!(\n            fork,\n            ForkUrl { url: \"wss://user:password@example.com/\".to_string(), block: None }\n        );\n\n        let fork: ForkUrl = \"wss://user:password@example.com/@latest\".parse().unwrap();\n        assert_eq!(\n            fork,\n            ForkUrl { url: \"wss://user:password@example.com/\".to_string(), block: None }\n        );\n\n        let fork: ForkUrl = \"wss://user:password@example.com/@100000\".parse().unwrap();\n        assert_eq!(\n            fork,\n            ForkUrl { url: \"wss://user:password@example.com/\".to_string(), block: Some(100000) }\n        );\n    }\n\n    #[test]\n    fn can_parse_ethereum_hardfork() {\n        let args: NodeArgs = NodeArgs::parse_from([\"anvil\", \"--hardfork\", \"berlin\"]);\n        let config = args.into_node_config().unwrap();\n        assert_eq!(config.hardfork, Some(EthereumHardfork::Berlin.into()));\n    }\n\n    #[test]\n    fn can_parse_optimism_hardfork() {\n        let args: NodeArgs =\n            NodeArgs::parse_from([\"anvil\", \"--optimism\", \"--hardfork\", \"Regolith\"]);\n        let config = args.into_node_config().unwrap();\n        assert_eq!(config.hardfork, Some(OpHardfork::Regolith.into()));\n    }\n\n    #[test]\n    fn cant_parse_invalid_hardfork() {\n        let args: NodeArgs = NodeArgs::parse_from([\"anvil\", \"--hardfork\", \"Regolith\"]);\n        let config = args.into_node_config();\n        assert!(config.is_err());\n    }\n\n    #[test]\n    fn can_parse_fork_headers() {\n        let args: NodeArgs = NodeArgs::parse_from([\n            \"anvil\",\n            \"--fork-url\",\n            \"http,://localhost:8545\",\n            \"--fork-header\",\n            \"User-Agent: test-agent\",\n            \"--fork-header\",\n            \"Referrer: example.com\",\n        ]);\n        assert_eq!(args.evm.fork_headers, vec![\"User-Agent: test-agent\", \"Referrer: example.com\"]);\n    }\n\n    #[test]\n    fn can_parse_prune_config() {\n        let args: NodeArgs = NodeArgs::parse_from([\"anvil\", \"--prune-history\"]);\n        assert!(args.prune_history.is_some());\n\n        let args: NodeArgs = NodeArgs::parse_from([\"anvil\", \"--prune-history\", \"100\"]);\n        assert_eq!(args.prune_history, Some(Some(100)));\n    }\n\n    #[test]\n    fn can_parse_max_persisted_states_config() {\n        let args: NodeArgs = NodeArgs::parse_from([\"anvil\", \"--max-persisted-states\", \"500\"]);\n        assert_eq!(args.max_persisted_states, (Some(500)));\n    }\n\n    #[test]\n    fn can_parse_disable_block_gas_limit() {\n        let args: NodeArgs = NodeArgs::parse_from([\"anvil\", \"--disable-block-gas-limit\"]);\n        assert!(args.evm.disable_block_gas_limit);\n\n        let args =\n            NodeArgs::try_parse_from([\"anvil\", \"--disable-block-gas-limit\", \"--gas-limit\", \"100\"]);\n        assert!(args.is_err());\n    }\n\n    #[test]\n    fn can_parse_enable_tx_gas_limit() {\n        let args: NodeArgs = NodeArgs::parse_from([\"anvil\", \"--enable-tx-gas-limit\"]);\n        assert!(args.evm.enable_tx_gas_limit);\n\n        // Also test the alias\n        let args: NodeArgs = NodeArgs::parse_from([\"anvil\", \"--tx-gas-limit\"]);\n        assert!(args.evm.enable_tx_gas_limit);\n    }\n\n    #[test]\n    fn can_parse_disable_code_size_limit() {\n        let args: NodeArgs = NodeArgs::parse_from([\"anvil\", \"--disable-code-size-limit\"]);\n        assert!(args.evm.disable_code_size_limit);\n\n        let args = NodeArgs::try_parse_from([\n            \"anvil\",\n            \"--disable-code-size-limit\",\n            \"--code-size-limit\",\n            \"100\",\n        ]);\n        // can't be used together\n        assert!(args.is_err());\n    }\n\n    #[test]\n    fn can_parse_host() {\n        let args = NodeArgs::parse_from([\"anvil\"]);\n        assert_eq!(args.host, vec![IpAddr::V4(Ipv4Addr::LOCALHOST)]);\n\n        let args = NodeArgs::parse_from([\n            \"anvil\", \"--host\", \"::1\", \"--host\", \"1.1.1.1\", \"--host\", \"2.2.2.2\",\n        ]);\n        assert_eq!(\n            args.host,\n            [\"::1\", \"1.1.1.1\", \"2.2.2.2\"].map(|ip| ip.parse::<IpAddr>().unwrap()).to_vec()\n        );\n\n        let args = NodeArgs::parse_from([\"anvil\", \"--host\", \"::1,1.1.1.1,2.2.2.2\"]);\n        assert_eq!(\n            args.host,\n            [\"::1\", \"1.1.1.1\", \"2.2.2.2\"].map(|ip| ip.parse::<IpAddr>().unwrap()).to_vec()\n        );\n\n        unsafe { env::set_var(\"ANVIL_IP_ADDR\", \"1.1.1.1\") };\n        let args = NodeArgs::parse_from([\"anvil\"]);\n        assert_eq!(args.host, vec![\"1.1.1.1\".parse::<IpAddr>().unwrap()]);\n\n        unsafe { env::set_var(\"ANVIL_IP_ADDR\", \"::1,1.1.1.1,2.2.2.2\") };\n        let args = NodeArgs::parse_from([\"anvil\"]);\n        assert_eq!(\n            args.host,\n            [\"::1\", \"1.1.1.1\", \"2.2.2.2\"].map(|ip| ip.parse::<IpAddr>().unwrap()).to_vec()\n        );\n    }\n}\n"
  },
  {
    "path": "crates/anvil/src/config.rs",
    "content": "use crate::{\n    EthereumHardfork, FeeManager, PrecompileFactory,\n    eth::{\n        backend::{\n            db::{Db, SerializableState},\n            env::Env,\n            fork::{ClientFork, ClientForkConfig},\n            genesis::GenesisConfig,\n            mem::fork_db::ForkedDatabase,\n            time::duration_since_unix_epoch,\n        },\n        fees::{INITIAL_BASE_FEE, INITIAL_GAS_PRICE},\n        pool::transactions::{PoolTransaction, TransactionOrder},\n    },\n    mem::{self, in_memory_db::MemDb},\n};\nuse alloy_consensus::BlockHeader;\nuse alloy_eips::{eip1559::BaseFeeParams, eip7840::BlobParams};\nuse alloy_evm::EvmEnv;\nuse alloy_genesis::Genesis;\nuse alloy_network::{AnyNetwork, BlockResponse, TransactionResponse};\nuse alloy_primitives::{BlockNumber, TxHash, U256, hex, map::HashMap, utils::Unit};\nuse alloy_provider::Provider;\nuse alloy_rpc_types::BlockNumberOrTag;\nuse alloy_signer::Signer;\nuse alloy_signer_local::{\n    MnemonicBuilder, PrivateKeySigner,\n    coins_bip39::{English, Mnemonic},\n};\nuse alloy_transport::TransportError;\nuse anvil_server::ServerConfig;\nuse eyre::{Context, Result};\nuse foundry_common::{\n    ALCHEMY_FREE_TIER_CUPS, NON_ARCHIVE_NODE_WARNING, REQUEST_TIMEOUT,\n    provider::{ProviderBuilder, RetryProvider},\n};\nuse foundry_config::Config;\nuse foundry_evm::{\n    backend::{BlockchainDb, BlockchainDbMeta, SharedBackend},\n    constants::DEFAULT_CREATE2_DEPLOYER,\n    hardfork::{\n        FoundryHardfork, OpHardfork, ethereum_hardfork_from_block_tag,\n        spec_id_from_ethereum_hardfork,\n    },\n    utils::{\n        apply_chain_and_block_specific_env_changes, block_env_from_header,\n        get_blob_base_fee_update_fraction,\n    },\n};\nuse foundry_primitives::FoundryTxEnvelope;\nuse itertools::Itertools;\nuse op_revm::OpTransaction;\nuse parking_lot::RwLock;\nuse rand_08::thread_rng;\nuse revm::{\n    context::{BlockEnv, CfgEnv, TxEnv},\n    context_interface::block::BlobExcessGasAndPrice,\n    primitives::hardfork::SpecId,\n};\nuse serde_json::{Value, json};\nuse std::{\n    fmt::Write as FmtWrite,\n    net::{IpAddr, Ipv4Addr},\n    path::PathBuf,\n    sync::Arc,\n    time::Duration,\n};\nuse tokio::sync::RwLock as TokioRwLock;\nuse yansi::Paint;\n\npub use foundry_common::version::SHORT_VERSION as VERSION_MESSAGE;\nuse foundry_evm::{\n    traces::{CallTraceDecoderBuilder, identifier::SignaturesIdentifier},\n    utils::get_blob_params,\n};\nuse foundry_evm_networks::NetworkConfigs;\n\n/// Default port the rpc will open\npub const NODE_PORT: u16 = 8545;\n/// Default chain id of the node\npub const CHAIN_ID: u64 = 31337;\n/// The default gas limit for all transactions\npub const DEFAULT_GAS_LIMIT: u64 = 30_000_000;\n/// Default mnemonic for dev accounts\npub const DEFAULT_MNEMONIC: &str = \"test test test test test test test test test test test junk\";\n\n/// The default IPC endpoint\npub const DEFAULT_IPC_ENDPOINT: &str =\n    if cfg!(unix) { \"/tmp/anvil.ipc\" } else { r\"\\\\.\\pipe\\anvil.ipc\" };\n\nconst BANNER: &str = r\"\n                             _   _\n                            (_) | |\n      __ _   _ __   __   __  _  | |\n     / _` | | '_ \\  \\ \\ / / | | | |\n    | (_| | | | | |  \\ V /  | | | |\n     \\__,_| |_| |_|   \\_/   |_| |_|\n\";\n\n/// Configurations of the EVM node\n#[derive(Clone, Debug)]\npub struct NodeConfig {\n    /// Chain ID of the EVM chain\n    pub chain_id: Option<u64>,\n    /// Default gas limit for all txs\n    pub gas_limit: Option<u64>,\n    /// If set to `true`, disables the block gas limit\n    pub disable_block_gas_limit: bool,\n    /// If set to `true`, enables the tx gas limit as imposed by Osaka (EIP-7825)\n    pub enable_tx_gas_limit: bool,\n    /// Default gas price for all txs\n    pub gas_price: Option<u128>,\n    /// Default base fee\n    pub base_fee: Option<u64>,\n    /// If set to `true`, disables the enforcement of a minimum suggested priority fee\n    pub disable_min_priority_fee: bool,\n    /// Default blob excess gas and price\n    pub blob_excess_gas_and_price: Option<BlobExcessGasAndPrice>,\n    /// The hardfork to use\n    pub hardfork: Option<FoundryHardfork>,\n    /// Signer accounts that will be initialised with `genesis_balance` in the genesis block\n    pub genesis_accounts: Vec<PrivateKeySigner>,\n    /// Native token balance of every genesis account in the genesis block\n    pub genesis_balance: U256,\n    /// Genesis block timestamp\n    pub genesis_timestamp: Option<u64>,\n    /// Genesis block number\n    pub genesis_block_number: Option<u64>,\n    /// Signer accounts that can sign messages/transactions from the EVM node\n    pub signer_accounts: Vec<PrivateKeySigner>,\n    /// Configured block time for the EVM chain. Use `None` to mine a new block for every tx\n    pub block_time: Option<Duration>,\n    /// Disable auto, interval mining mode uns use `MiningMode::None` instead\n    pub no_mining: bool,\n    /// Enables auto and interval mining mode\n    pub mixed_mining: bool,\n    /// port to use for the server\n    pub port: u16,\n    /// maximum number of transactions in a block\n    pub max_transactions: usize,\n    /// url of the rpc server that should be used for any rpc calls\n    pub eth_rpc_url: Option<String>,\n    /// pins the block number or transaction hash for the state fork\n    pub fork_choice: Option<ForkChoice>,\n    /// headers to use with `eth_rpc_url`\n    pub fork_headers: Vec<String>,\n    /// specifies chain id for cache to skip fetching from remote in offline-start mode\n    pub fork_chain_id: Option<U256>,\n    /// The generator used to generate the dev accounts\n    pub account_generator: Option<AccountGenerator>,\n    /// whether to enable tracing\n    pub enable_tracing: bool,\n    /// Explicitly disables the use of RPC caching.\n    pub no_storage_caching: bool,\n    /// How to configure the server\n    pub server_config: ServerConfig,\n    /// The host the server will listen on\n    pub host: Vec<IpAddr>,\n    /// How transactions are sorted in the mempool\n    pub transaction_order: TransactionOrder,\n    /// Filename to write anvil output as json\n    pub config_out: Option<PathBuf>,\n    /// The genesis to use to initialize the node\n    pub genesis: Option<Genesis>,\n    /// Timeout in for requests sent to remote JSON-RPC server in forking mode\n    pub fork_request_timeout: Duration,\n    /// Number of request retries for spurious networks\n    pub fork_request_retries: u32,\n    /// The initial retry backoff\n    pub fork_retry_backoff: Duration,\n    /// available CUPS\n    pub compute_units_per_second: u64,\n    /// The ipc path\n    pub ipc_path: Option<Option<String>>,\n    /// Enable transaction/call steps tracing for debug calls returning geth-style traces\n    pub enable_steps_tracing: bool,\n    /// Enable printing of `console.log` invocations.\n    pub print_logs: bool,\n    /// Enable printing of traces.\n    pub print_traces: bool,\n    /// Enable auto impersonation of accounts on startup\n    pub enable_auto_impersonate: bool,\n    /// Configure the code size limit\n    pub code_size_limit: Option<usize>,\n    /// Configures how to remove historic state.\n    ///\n    /// If set to `Some(num)` keep latest num state in memory only.\n    pub prune_history: PruneStateHistoryConfig,\n    /// Max number of states cached on disk.\n    pub max_persisted_states: Option<usize>,\n    /// The file where to load the state from\n    pub init_state: Option<SerializableState>,\n    /// max number of blocks with transactions in memory\n    pub transaction_block_keeper: Option<usize>,\n    /// Disable the default CREATE2 deployer\n    pub disable_default_create2_deployer: bool,\n    /// Disable pool balance checks\n    pub disable_pool_balance_checks: bool,\n    /// Slots in an epoch\n    pub slots_in_an_epoch: u64,\n    /// The memory limit per EVM execution in bytes.\n    pub memory_limit: Option<u64>,\n    /// Factory used by `anvil` to extend the EVM's precompiles.\n    pub precompile_factory: Option<Arc<dyn PrecompileFactory>>,\n    /// Networks to enable features for.\n    pub networks: NetworkConfigs,\n    /// Do not print log messages.\n    pub silent: bool,\n    /// The path where persisted states are cached (used with `max_persisted_states`).\n    /// This does not affect the fork RPC cache location.\n    pub cache_path: Option<PathBuf>,\n}\n\nimpl NodeConfig {\n    fn as_string(&self, fork: Option<&ClientFork>) -> String {\n        let mut s: String = String::new();\n        let _ = write!(s, \"\\n{}\", BANNER.green());\n        let _ = write!(s, \"\\n    {VERSION_MESSAGE}\");\n        let _ = write!(s, \"\\n    {}\", \"https://github.com/foundry-rs/foundry\".green());\n\n        let _ = write!(\n            s,\n            r#\"\n\nAvailable Accounts\n==================\n\"#\n        );\n        let balance = alloy_primitives::utils::format_ether(self.genesis_balance);\n        for (idx, wallet) in self.genesis_accounts.iter().enumerate() {\n            write!(s, \"\\n({idx}) {} ({balance} ETH)\", wallet.address()).unwrap();\n        }\n\n        let _ = write!(\n            s,\n            r#\"\n\nPrivate Keys\n==================\n\"#\n        );\n\n        for (idx, wallet) in self.genesis_accounts.iter().enumerate() {\n            let hex = hex::encode(wallet.credential().to_bytes());\n            let _ = write!(s, \"\\n({idx}) 0x{hex}\");\n        }\n\n        if let Some(generator) = &self.account_generator {\n            let _ = write!(\n                s,\n                r#\"\n\nWallet\n==================\nMnemonic:          {}\nDerivation path:   {}\n\"#,\n                generator.phrase,\n                generator.get_derivation_path()\n            );\n        }\n\n        if let Some(fork) = fork {\n            let _ = write!(\n                s,\n                r#\"\n\nFork\n==================\nEndpoint:       {}\nBlock number:   {}\nBlock hash:     {:?}\nChain ID:       {}\n\"#,\n                fork.eth_rpc_url(),\n                fork.block_number(),\n                fork.block_hash(),\n                fork.chain_id()\n            );\n\n            if let Some(tx_hash) = fork.transaction_hash() {\n                let _ = writeln!(s, \"Transaction hash: {tx_hash}\");\n            }\n        } else {\n            let _ = write!(\n                s,\n                r#\"\n\nChain ID\n==================\n\n{}\n\"#,\n                self.get_chain_id().green()\n            );\n        }\n\n        if (SpecId::from(self.get_hardfork()) as u8) < (SpecId::LONDON as u8) {\n            let _ = write!(\n                s,\n                r#\"\nGas Price\n==================\n\n{}\n\"#,\n                self.get_gas_price().green()\n            );\n        } else {\n            let _ = write!(\n                s,\n                r#\"\nBase Fee\n==================\n\n{}\n\"#,\n                self.get_base_fee().green()\n            );\n        }\n\n        let _ = write!(\n            s,\n            r#\"\nGas Limit\n==================\n\n{}\n\"#,\n            {\n                if self.disable_block_gas_limit {\n                    \"Disabled\".to_string()\n                } else {\n                    self.gas_limit.map(|l| l.to_string()).unwrap_or_else(|| {\n                        if self.fork_choice.is_some() {\n                            \"Forked\".to_string()\n                        } else {\n                            DEFAULT_GAS_LIMIT.to_string()\n                        }\n                    })\n                }\n            }\n            .green()\n        );\n\n        let _ = write!(\n            s,\n            r#\"\nGenesis Timestamp\n==================\n\n{}\n\"#,\n            self.get_genesis_timestamp().green()\n        );\n\n        let _ = write!(\n            s,\n            r#\"\nGenesis Number\n==================\n\n{}\n\"#,\n            self.get_genesis_number().green()\n        );\n\n        s\n    }\n\n    fn as_json(&self, fork: Option<&ClientFork>) -> Value {\n        let mut wallet_description = HashMap::new();\n        let mut available_accounts = Vec::with_capacity(self.genesis_accounts.len());\n        let mut private_keys = Vec::with_capacity(self.genesis_accounts.len());\n\n        for wallet in &self.genesis_accounts {\n            available_accounts.push(format!(\"{:?}\", wallet.address()));\n            private_keys.push(format!(\"0x{}\", hex::encode(wallet.credential().to_bytes())));\n        }\n\n        if let Some(generator) = &self.account_generator {\n            let phrase = generator.get_phrase().to_string();\n            let derivation_path = generator.get_derivation_path().to_string();\n\n            wallet_description.insert(\"derivation_path\".to_string(), derivation_path);\n            wallet_description.insert(\"mnemonic\".to_string(), phrase);\n        };\n\n        let gas_limit = match self.gas_limit {\n            // if we have a disabled flag we should max out the limit\n            Some(_) | None if self.disable_block_gas_limit => Some(u64::MAX.to_string()),\n            Some(limit) => Some(limit.to_string()),\n            _ => None,\n        };\n\n        if let Some(fork) = fork {\n            json!({\n              \"available_accounts\": available_accounts,\n              \"private_keys\": private_keys,\n              \"endpoint\": fork.eth_rpc_url(),\n              \"block_number\": fork.block_number(),\n              \"block_hash\": fork.block_hash(),\n              \"chain_id\": fork.chain_id(),\n              \"wallet\": wallet_description,\n              \"base_fee\": format!(\"{}\", self.get_base_fee()),\n              \"gas_price\": format!(\"{}\", self.get_gas_price()),\n              \"gas_limit\": gas_limit,\n            })\n        } else {\n            json!({\n              \"available_accounts\": available_accounts,\n              \"private_keys\": private_keys,\n              \"wallet\": wallet_description,\n              \"base_fee\": format!(\"{}\", self.get_base_fee()),\n              \"gas_price\": format!(\"{}\", self.get_gas_price()),\n              \"gas_limit\": gas_limit,\n              \"genesis_timestamp\": format!(\"{}\", self.get_genesis_timestamp()),\n            })\n        }\n    }\n}\n\nimpl NodeConfig {\n    /// Returns a new config intended to be used in tests, which does not print and binds to a\n    /// random, free port by setting it to `0`\n    #[doc(hidden)]\n    pub fn test() -> Self {\n        Self { enable_tracing: true, port: 0, silent: true, ..Default::default() }\n    }\n\n    /// Returns a new config which does not initialize any accounts on node startup.\n    pub fn empty_state() -> Self {\n        Self {\n            genesis_accounts: vec![],\n            signer_accounts: vec![],\n            disable_default_create2_deployer: true,\n            ..Default::default()\n        }\n    }\n}\n\nimpl Default for NodeConfig {\n    fn default() -> Self {\n        // generate some random wallets\n        let genesis_accounts = AccountGenerator::new(10)\n            .phrase(DEFAULT_MNEMONIC)\n            .generate()\n            .expect(\"Invalid mnemonic.\");\n        Self {\n            chain_id: None,\n            gas_limit: None,\n            disable_block_gas_limit: false,\n            enable_tx_gas_limit: false,\n            gas_price: None,\n            hardfork: None,\n            signer_accounts: genesis_accounts.clone(),\n            genesis_timestamp: None,\n            genesis_block_number: None,\n            genesis_accounts,\n            // 100ETH default balance\n            genesis_balance: Unit::ETHER.wei().saturating_mul(U256::from(100u64)),\n            block_time: None,\n            no_mining: false,\n            mixed_mining: false,\n            port: NODE_PORT,\n            max_transactions: 1_000,\n            eth_rpc_url: None,\n            fork_choice: None,\n            account_generator: None,\n            base_fee: None,\n            disable_min_priority_fee: false,\n            blob_excess_gas_and_price: None,\n            enable_tracing: true,\n            enable_steps_tracing: false,\n            print_logs: true,\n            print_traces: false,\n            enable_auto_impersonate: false,\n            no_storage_caching: false,\n            server_config: Default::default(),\n            host: vec![IpAddr::V4(Ipv4Addr::LOCALHOST)],\n            transaction_order: Default::default(),\n            config_out: None,\n            genesis: None,\n            fork_request_timeout: REQUEST_TIMEOUT,\n            fork_headers: vec![],\n            fork_request_retries: 5,\n            fork_retry_backoff: Duration::from_millis(1_000),\n            fork_chain_id: None,\n            // alchemy max cpus <https://docs.alchemy.com/reference/compute-units#what-are-cups-compute-units-per-second>\n            compute_units_per_second: ALCHEMY_FREE_TIER_CUPS,\n            ipc_path: None,\n            code_size_limit: None,\n            prune_history: Default::default(),\n            max_persisted_states: None,\n            init_state: None,\n            transaction_block_keeper: None,\n            disable_default_create2_deployer: false,\n            disable_pool_balance_checks: false,\n            slots_in_an_epoch: 32,\n            memory_limit: None,\n            precompile_factory: None,\n            networks: Default::default(),\n            silent: false,\n            cache_path: None,\n        }\n    }\n}\n\nimpl NodeConfig {\n    /// Returns the memory limit of the node\n    #[must_use]\n    pub fn with_memory_limit(mut self, mems_value: Option<u64>) -> Self {\n        self.memory_limit = mems_value;\n        self\n    }\n    /// Returns the base fee to use\n    pub fn get_base_fee(&self) -> u64 {\n        self.base_fee\n            .or_else(|| self.genesis.as_ref().and_then(|g| g.base_fee_per_gas.map(|g| g as u64)))\n            .unwrap_or(INITIAL_BASE_FEE)\n    }\n\n    /// Returns the base fee to use\n    pub fn get_gas_price(&self) -> u128 {\n        self.gas_price.unwrap_or(INITIAL_GAS_PRICE)\n    }\n\n    pub fn get_blob_excess_gas_and_price(&self) -> BlobExcessGasAndPrice {\n        if let Some(value) = self.blob_excess_gas_and_price {\n            value\n        } else {\n            let excess_blob_gas =\n                self.genesis.as_ref().and_then(|g| g.excess_blob_gas).unwrap_or(0);\n            BlobExcessGasAndPrice::new(\n                excess_blob_gas,\n                get_blob_base_fee_update_fraction(\n                    self.get_chain_id(),\n                    self.get_genesis_timestamp(),\n                ),\n            )\n        }\n    }\n\n    /// Returns the [`BlobParams`] that should be used.\n    pub fn get_blob_params(&self) -> BlobParams {\n        get_blob_params(self.get_chain_id(), self.get_genesis_timestamp())\n    }\n\n    /// Returns the hardfork to use\n    pub fn get_hardfork(&self) -> FoundryHardfork {\n        if let Some(hardfork) = self.hardfork {\n            return hardfork;\n        }\n        if self.networks.is_optimism() {\n            return OpHardfork::default().into();\n        }\n        EthereumHardfork::default().into()\n    }\n\n    /// Sets a custom code size limit\n    #[must_use]\n    pub fn with_code_size_limit(mut self, code_size_limit: Option<usize>) -> Self {\n        self.code_size_limit = code_size_limit;\n        self\n    }\n    /// Disables  code size limit\n    #[must_use]\n    pub fn disable_code_size_limit(mut self, disable_code_size_limit: bool) -> Self {\n        if disable_code_size_limit {\n            self.code_size_limit = Some(usize::MAX);\n        }\n        self\n    }\n\n    /// Sets the init state if any\n    #[must_use]\n    pub fn with_init_state(mut self, init_state: Option<SerializableState>) -> Self {\n        self.init_state = init_state;\n        self\n    }\n\n    /// Loads the init state from a file if it exists\n    #[must_use]\n    #[cfg(feature = \"cmd\")]\n    pub fn with_init_state_path(mut self, path: impl AsRef<std::path::Path>) -> Self {\n        self.init_state = crate::cmd::StateFile::parse_path(path).ok().and_then(|file| file.state);\n        self\n    }\n\n    /// Sets the chain ID\n    #[must_use]\n    pub fn with_chain_id<U: Into<u64>>(mut self, chain_id: Option<U>) -> Self {\n        self.set_chain_id(chain_id);\n        self\n    }\n\n    /// Returns the chain ID to use\n    pub fn get_chain_id(&self) -> u64 {\n        self.chain_id\n            .or_else(|| self.genesis.as_ref().map(|g| g.config.chain_id))\n            .unwrap_or(CHAIN_ID)\n    }\n\n    /// Sets the chain id and updates all wallets\n    pub fn set_chain_id(&mut self, chain_id: Option<impl Into<u64>>) {\n        self.chain_id = chain_id.map(Into::into);\n        let chain_id = self.get_chain_id();\n        self.networks.with_chain_id(chain_id);\n        self.genesis_accounts.iter_mut().for_each(|wallet| {\n            *wallet = wallet.clone().with_chain_id(Some(chain_id));\n        });\n        self.signer_accounts.iter_mut().for_each(|wallet| {\n            *wallet = wallet.clone().with_chain_id(Some(chain_id));\n        })\n    }\n\n    /// Sets the gas limit\n    #[must_use]\n    pub fn with_gas_limit(mut self, gas_limit: Option<u64>) -> Self {\n        self.gas_limit = gas_limit;\n        self\n    }\n\n    /// Disable block gas limit check\n    ///\n    /// If set to `true` block gas limit will not be enforced\n    #[must_use]\n    pub fn disable_block_gas_limit(mut self, disable_block_gas_limit: bool) -> Self {\n        self.disable_block_gas_limit = disable_block_gas_limit;\n        self\n    }\n\n    /// Enable tx gas limit check\n    ///\n    /// If set to `true`, enables the tx gas limit as imposed by Osaka (EIP-7825)\n    #[must_use]\n    pub fn enable_tx_gas_limit(mut self, enable_tx_gas_limit: bool) -> Self {\n        self.enable_tx_gas_limit = enable_tx_gas_limit;\n        self\n    }\n\n    /// Sets the gas price\n    #[must_use]\n    pub fn with_gas_price(mut self, gas_price: Option<u128>) -> Self {\n        self.gas_price = gas_price;\n        self\n    }\n\n    /// Sets prune history status.\n    #[must_use]\n    pub fn set_pruned_history(mut self, prune_history: Option<Option<usize>>) -> Self {\n        self.prune_history = PruneStateHistoryConfig::from_args(prune_history);\n        self\n    }\n\n    /// Sets max number of states to cache on disk.\n    #[must_use]\n    pub fn with_max_persisted_states<U: Into<usize>>(\n        mut self,\n        max_persisted_states: Option<U>,\n    ) -> Self {\n        self.max_persisted_states = max_persisted_states.map(Into::into);\n        self\n    }\n\n    /// Sets the max number of transactions in a block\n    #[must_use]\n    pub fn with_max_transactions(mut self, max_transactions: Option<usize>) -> Self {\n        if let Some(max_transactions) = max_transactions {\n            self.max_transactions = max_transactions;\n        }\n        self\n    }\n\n    /// Sets max number of blocks with transactions to keep in memory\n    #[must_use]\n    pub fn with_transaction_block_keeper<U: Into<usize>>(\n        mut self,\n        transaction_block_keeper: Option<U>,\n    ) -> Self {\n        self.transaction_block_keeper = transaction_block_keeper.map(Into::into);\n        self\n    }\n\n    /// Sets the base fee\n    #[must_use]\n    pub fn with_base_fee(mut self, base_fee: Option<u64>) -> Self {\n        self.base_fee = base_fee;\n        self\n    }\n\n    /// Disable the enforcement of a minimum suggested priority fee\n    #[must_use]\n    pub fn disable_min_priority_fee(mut self, disable_min_priority_fee: bool) -> Self {\n        self.disable_min_priority_fee = disable_min_priority_fee;\n        self\n    }\n\n    /// Sets the init genesis (genesis.json)\n    #[must_use]\n    pub fn with_genesis(mut self, genesis: Option<Genesis>) -> Self {\n        self.genesis = genesis;\n        self\n    }\n\n    /// Returns the genesis timestamp to use\n    pub fn get_genesis_timestamp(&self) -> u64 {\n        self.genesis_timestamp\n            .or_else(|| self.genesis.as_ref().map(|g| g.timestamp))\n            .unwrap_or_else(|| duration_since_unix_epoch().as_secs())\n    }\n\n    /// Sets the genesis timestamp\n    #[must_use]\n    pub fn with_genesis_timestamp<U: Into<u64>>(mut self, timestamp: Option<U>) -> Self {\n        if let Some(timestamp) = timestamp {\n            self.genesis_timestamp = Some(timestamp.into());\n        }\n        self\n    }\n\n    /// Sets the genesis number\n    #[must_use]\n    pub fn with_genesis_block_number<U: Into<u64>>(mut self, number: Option<U>) -> Self {\n        if let Some(number) = number {\n            self.genesis_block_number = Some(number.into());\n        }\n        self\n    }\n\n    /// Returns the genesis number\n    pub fn get_genesis_number(&self) -> u64 {\n        self.genesis_block_number\n            .or_else(|| self.genesis.as_ref().and_then(|g| g.number))\n            .unwrap_or(0)\n    }\n\n    /// Sets the hardfork\n    #[must_use]\n    pub fn with_hardfork(mut self, hardfork: Option<FoundryHardfork>) -> Self {\n        self.hardfork = hardfork;\n        self\n    }\n\n    /// Sets the genesis accounts\n    #[must_use]\n    pub fn with_genesis_accounts(mut self, accounts: Vec<PrivateKeySigner>) -> Self {\n        self.genesis_accounts = accounts;\n        self\n    }\n\n    /// Sets the signer accounts\n    #[must_use]\n    pub fn with_signer_accounts(mut self, accounts: Vec<PrivateKeySigner>) -> Self {\n        self.signer_accounts = accounts;\n        self\n    }\n\n    /// Sets both the genesis accounts and the signer accounts\n    /// so that `genesis_accounts == accounts`\n    pub fn with_account_generator(mut self, generator: AccountGenerator) -> eyre::Result<Self> {\n        let accounts = generator.generate()?;\n        self.account_generator = Some(generator);\n        Ok(self.with_signer_accounts(accounts.clone()).with_genesis_accounts(accounts))\n    }\n\n    /// Sets the balance of the genesis accounts in the genesis block\n    #[must_use]\n    pub fn with_genesis_balance<U: Into<U256>>(mut self, balance: U) -> Self {\n        self.genesis_balance = balance.into();\n        self\n    }\n\n    /// Sets the block time to automine blocks\n    #[must_use]\n    pub fn with_blocktime<D: Into<Duration>>(mut self, block_time: Option<D>) -> Self {\n        self.block_time = block_time.map(Into::into);\n        self\n    }\n\n    #[must_use]\n    pub fn with_mixed_mining<D: Into<Duration>>(\n        mut self,\n        mixed_mining: bool,\n        block_time: Option<D>,\n    ) -> Self {\n        self.block_time = block_time.map(Into::into);\n        self.mixed_mining = mixed_mining;\n        self\n    }\n\n    /// If set to `true` auto mining will be disabled\n    #[must_use]\n    pub fn with_no_mining(mut self, no_mining: bool) -> Self {\n        self.no_mining = no_mining;\n        self\n    }\n\n    /// Sets the slots in an epoch\n    #[must_use]\n    pub fn with_slots_in_an_epoch(mut self, slots_in_an_epoch: u64) -> Self {\n        self.slots_in_an_epoch = slots_in_an_epoch;\n        self\n    }\n\n    /// Sets the port to use\n    #[must_use]\n    pub fn with_port(mut self, port: u16) -> Self {\n        self.port = port;\n        self\n    }\n\n    /// Sets the ipc path to use\n    ///\n    /// Note: this is a double Option for\n    ///     - `None` -> no ipc\n    ///     - `Some(None)` -> use default path\n    ///     - `Some(Some(path))` -> use custom path\n    #[must_use]\n    pub fn with_ipc(mut self, ipc_path: Option<Option<String>>) -> Self {\n        self.ipc_path = ipc_path;\n        self\n    }\n\n    /// Sets the file path to write the Anvil node's config info to.\n    #[must_use]\n    pub fn set_config_out(mut self, config_out: Option<PathBuf>) -> Self {\n        self.config_out = config_out;\n        self\n    }\n\n    #[must_use]\n    pub fn with_no_storage_caching(mut self, no_storage_caching: bool) -> Self {\n        self.no_storage_caching = no_storage_caching;\n        self\n    }\n\n    /// Sets the `eth_rpc_url` to use when forking\n    #[must_use]\n    pub fn with_eth_rpc_url<U: Into<String>>(mut self, eth_rpc_url: Option<U>) -> Self {\n        self.eth_rpc_url = eth_rpc_url.map(Into::into);\n        self\n    }\n\n    /// Sets the `fork_choice` to use to fork off from based on a block number\n    #[must_use]\n    pub fn with_fork_block_number<U: Into<u64>>(self, fork_block_number: Option<U>) -> Self {\n        self.with_fork_choice(fork_block_number.map(Into::into))\n    }\n\n    /// Sets the `fork_choice` to use to fork off from based on a transaction hash\n    #[must_use]\n    pub fn with_fork_transaction_hash<U: Into<TxHash>>(\n        self,\n        fork_transaction_hash: Option<U>,\n    ) -> Self {\n        self.with_fork_choice(fork_transaction_hash.map(Into::into))\n    }\n\n    /// Sets the `fork_choice` to use to fork off from\n    #[must_use]\n    pub fn with_fork_choice<U: Into<ForkChoice>>(mut self, fork_choice: Option<U>) -> Self {\n        self.fork_choice = fork_choice.map(Into::into);\n        self\n    }\n\n    /// Sets the `fork_chain_id` to use to fork off local cache from\n    #[must_use]\n    pub fn with_fork_chain_id(mut self, fork_chain_id: Option<U256>) -> Self {\n        self.fork_chain_id = fork_chain_id;\n        self\n    }\n\n    /// Sets the `fork_headers` to use with `eth_rpc_url`\n    #[must_use]\n    pub fn with_fork_headers(mut self, headers: Vec<String>) -> Self {\n        self.fork_headers = headers;\n        self\n    }\n\n    /// Sets the `fork_request_timeout` to use for requests\n    #[must_use]\n    pub fn fork_request_timeout(mut self, fork_request_timeout: Option<Duration>) -> Self {\n        if let Some(fork_request_timeout) = fork_request_timeout {\n            self.fork_request_timeout = fork_request_timeout;\n        }\n        self\n    }\n\n    /// Sets the `fork_request_retries` to use for spurious networks\n    #[must_use]\n    pub fn fork_request_retries(mut self, fork_request_retries: Option<u32>) -> Self {\n        if let Some(fork_request_retries) = fork_request_retries {\n            self.fork_request_retries = fork_request_retries;\n        }\n        self\n    }\n\n    /// Sets the initial `fork_retry_backoff` for rate limits\n    #[must_use]\n    pub fn fork_retry_backoff(mut self, fork_retry_backoff: Option<Duration>) -> Self {\n        if let Some(fork_retry_backoff) = fork_retry_backoff {\n            self.fork_retry_backoff = fork_retry_backoff;\n        }\n        self\n    }\n\n    /// Sets the number of assumed available compute units per second\n    ///\n    /// See also, <https://docs.alchemy.com/reference/compute-units#what-are-cups-compute-units-per-second>\n    #[must_use]\n    pub fn fork_compute_units_per_second(mut self, compute_units_per_second: Option<u64>) -> Self {\n        if let Some(compute_units_per_second) = compute_units_per_second {\n            self.compute_units_per_second = compute_units_per_second;\n        }\n        self\n    }\n\n    /// Sets whether to enable tracing\n    #[must_use]\n    pub fn with_tracing(mut self, enable_tracing: bool) -> Self {\n        self.enable_tracing = enable_tracing;\n        self\n    }\n\n    /// Sets whether to enable steps tracing\n    #[must_use]\n    pub fn with_steps_tracing(mut self, enable_steps_tracing: bool) -> Self {\n        self.enable_steps_tracing = enable_steps_tracing;\n        self\n    }\n\n    /// Sets whether to print `console.log` invocations to stdout.\n    #[must_use]\n    pub fn with_print_logs(mut self, print_logs: bool) -> Self {\n        self.print_logs = print_logs;\n        self\n    }\n\n    /// Sets whether to print traces to stdout.\n    #[must_use]\n    pub fn with_print_traces(mut self, print_traces: bool) -> Self {\n        self.print_traces = print_traces;\n        self\n    }\n\n    /// Sets whether to enable autoImpersonate\n    #[must_use]\n    pub fn with_auto_impersonate(mut self, enable_auto_impersonate: bool) -> Self {\n        self.enable_auto_impersonate = enable_auto_impersonate;\n        self\n    }\n\n    #[must_use]\n    pub fn with_server_config(mut self, config: ServerConfig) -> Self {\n        self.server_config = config;\n        self\n    }\n\n    /// Sets the host the server will listen on\n    #[must_use]\n    pub fn with_host(mut self, host: Vec<IpAddr>) -> Self {\n        self.host = if host.is_empty() { vec![IpAddr::V4(Ipv4Addr::LOCALHOST)] } else { host };\n        self\n    }\n\n    #[must_use]\n    pub fn with_transaction_order(mut self, transaction_order: TransactionOrder) -> Self {\n        self.transaction_order = transaction_order;\n        self\n    }\n\n    /// Returns the ipc path for the ipc endpoint if any\n    pub fn get_ipc_path(&self) -> Option<String> {\n        match &self.ipc_path {\n            Some(path) => path.clone().or_else(|| Some(DEFAULT_IPC_ENDPOINT.to_string())),\n            None => None,\n        }\n    }\n\n    /// Prints the config info\n    pub fn print(&self, fork: Option<&ClientFork>) -> Result<()> {\n        if let Some(path) = &self.config_out {\n            let value = self.as_json(fork);\n            foundry_common::fs::write_json_file(path, &value).wrap_err(\"failed writing JSON\")?;\n        }\n        if !self.silent {\n            sh_println!(\"{}\", self.as_string(fork))?;\n        }\n        Ok(())\n    }\n\n    /// Returns the path where the cache file should be stored\n    ///\n    /// See also [ Config::foundry_block_cache_file()]\n    pub fn block_cache_path(&self, block: u64) -> Option<PathBuf> {\n        if self.no_storage_caching || self.eth_rpc_url.is_none() {\n            return None;\n        }\n        let chain_id = self.get_chain_id();\n\n        Config::foundry_block_cache_file(chain_id, block)\n    }\n\n    /// Sets whether to disable the default create2 deployer\n    #[must_use]\n    pub fn with_disable_default_create2_deployer(mut self, yes: bool) -> Self {\n        self.disable_default_create2_deployer = yes;\n        self\n    }\n\n    /// Sets whether to disable pool balance checks\n    #[must_use]\n    pub fn with_disable_pool_balance_checks(mut self, yes: bool) -> Self {\n        self.disable_pool_balance_checks = yes;\n        self\n    }\n\n    /// Injects precompiles to `anvil`'s EVM.\n    #[must_use]\n    pub fn with_precompile_factory(mut self, factory: impl PrecompileFactory + 'static) -> Self {\n        self.precompile_factory = Some(Arc::new(factory));\n        self\n    }\n\n    /// Enable features for provided networks.\n    #[must_use]\n    pub fn with_networks(mut self, networks: NetworkConfigs) -> Self {\n        self.networks = networks;\n        self\n    }\n\n    /// Makes the node silent to not emit anything on stdout\n    #[must_use]\n    pub fn silent(self) -> Self {\n        self.set_silent(true)\n    }\n\n    #[must_use]\n    pub fn set_silent(mut self, silent: bool) -> Self {\n        self.silent = silent;\n        self\n    }\n\n    /// Sets the path where persisted states are cached (used with `max_persisted_states`).\n    ///\n    /// Note: This does not control the fork RPC cache location (`storage.json`), which uses\n    /// `~/.foundry/cache/rpc/<chain>/<block>/` via [`Config::foundry_block_cache_file`].\n    #[must_use]\n    pub fn with_cache_path(mut self, cache_path: Option<PathBuf>) -> Self {\n        self.cache_path = cache_path;\n        self\n    }\n\n    /// Configures everything related to env, backend and database and returns the\n    /// [Backend](mem::Backend)\n    ///\n    /// *Note*: only memory based backend for now\n    pub(crate) async fn setup<N>(&mut self) -> Result<mem::Backend<N>>\n    where\n        N: alloy_network::Network<\n                TxEnvelope = foundry_primitives::FoundryTxEnvelope,\n                ReceiptEnvelope = foundry_primitives::FoundryReceiptEnvelope,\n            >,\n    {\n        // configure the revm environment\n\n        let mut cfg = CfgEnv::default();\n        cfg.spec = self.get_hardfork().into();\n\n        cfg.chain_id = self.get_chain_id();\n        cfg.limit_contract_code_size = self.code_size_limit;\n        // EIP-3607 rejects transactions from senders with deployed code.\n        // If EIP-3607 is enabled it can cause issues during fuzz/invariant tests if the\n        // caller is a contract. So we disable the check by default.\n        cfg.disable_eip3607 = true;\n        cfg.disable_block_gas_limit = self.disable_block_gas_limit;\n\n        if !self.enable_tx_gas_limit {\n            cfg.tx_gas_limit_cap = Some(u64::MAX);\n        }\n\n        if let Some(value) = self.memory_limit {\n            cfg.memory_limit = value;\n        }\n\n        let spec_id = cfg.spec;\n        let mut env = Env::new(\n            EvmEnv::new(\n                cfg,\n                BlockEnv {\n                    gas_limit: self.gas_limit(),\n                    basefee: self.get_base_fee(),\n                    ..Default::default()\n                },\n            ),\n            OpTransaction {\n                base: TxEnv { chain_id: Some(self.get_chain_id()), ..Default::default() },\n                ..Default::default()\n            },\n            self.networks,\n        );\n\n        let base_fee_params: BaseFeeParams =\n            self.networks.base_fee_params(self.get_genesis_timestamp());\n\n        let fees = FeeManager::new(\n            spec_id,\n            self.get_base_fee(),\n            !self.disable_min_priority_fee,\n            self.get_gas_price(),\n            self.get_blob_excess_gas_and_price(),\n            self.get_blob_params(),\n            base_fee_params,\n        );\n\n        let (db, fork): (Arc<TokioRwLock<Box<dyn Db>>>, Option<ClientFork>) =\n            if let Some(eth_rpc_url) = self.eth_rpc_url.clone() {\n                self.setup_fork_db(eth_rpc_url, &mut env, &fees).await?\n            } else {\n                (Arc::new(TokioRwLock::new(Box::<MemDb>::default())), None)\n            };\n\n        // if provided use all settings of `genesis.json`\n        if let Some(ref genesis) = self.genesis {\n            // --chain-id flag gets precedence over the genesis.json chain id\n            // <https://github.com/foundry-rs/foundry/issues/10059>\n            if self.chain_id.is_none() {\n                env.evm_env.cfg_env.chain_id = genesis.config.chain_id;\n            }\n            env.evm_env.block_env.timestamp = U256::from(genesis.timestamp);\n            if let Some(base_fee) = genesis.base_fee_per_gas {\n                env.evm_env.block_env.basefee = base_fee.try_into()?;\n            }\n            if let Some(number) = genesis.number {\n                env.evm_env.block_env.number = U256::from(number);\n            }\n            env.evm_env.block_env.beneficiary = genesis.coinbase;\n        }\n\n        let genesis = GenesisConfig {\n            number: self.get_genesis_number(),\n            timestamp: self.get_genesis_timestamp(),\n            balance: self.genesis_balance,\n            accounts: self.genesis_accounts.iter().map(|acc| acc.address()).collect(),\n            genesis_init: self.genesis.clone(),\n        };\n\n        let mut decoder_builder = CallTraceDecoderBuilder::new();\n        if self.print_traces {\n            // if traces should get printed we configure the decoder with the signatures cache\n            if let Ok(identifier) = SignaturesIdentifier::new(false) {\n                debug!(target: \"node\", \"using signature identifier\");\n                decoder_builder = decoder_builder.with_signature_identifier(identifier);\n            }\n        }\n\n        // only memory based backend for now\n        let backend = mem::Backend::with_genesis(\n            db,\n            Arc::new(RwLock::new(env)),\n            genesis,\n            fees,\n            Arc::new(RwLock::new(fork)),\n            self.enable_steps_tracing,\n            self.print_logs,\n            self.print_traces,\n            Arc::new(decoder_builder.build()),\n            self.prune_history,\n            self.max_persisted_states,\n            self.transaction_block_keeper,\n            self.block_time,\n            self.cache_path.clone(),\n            Arc::new(TokioRwLock::new(self.clone())),\n        )\n        .await?;\n\n        // Writes the default create2 deployer to the backend,\n        // if the option is not disabled and we are not forking.\n        if !self.disable_default_create2_deployer && self.eth_rpc_url.is_none() {\n            backend\n                .set_create2_deployer(DEFAULT_CREATE2_DEPLOYER)\n                .await\n                .wrap_err(\"failed to create default create2 deployer\")?;\n        }\n\n        Ok(backend)\n    }\n\n    /// Configures everything related to forking based on the passed `eth_rpc_url`:\n    ///  - returning a tuple of a [ForkedDatabase] wrapped in an [Arc] [RwLock](TokioRwLock) and\n    ///    [ClientFork] wrapped in an [Option] which can be used in a [Backend](mem::Backend) to\n    ///    fork from.\n    ///  - modifying some parameters of the passed `env`\n    ///  - mutating some members of `self`\n    pub async fn setup_fork_db(\n        &mut self,\n        eth_rpc_url: String,\n        env: &mut Env,\n        fees: &FeeManager,\n    ) -> Result<(Arc<TokioRwLock<Box<dyn Db>>>, Option<ClientFork>)> {\n        let (db, config) = self.setup_fork_db_config(eth_rpc_url, env, fees).await?;\n        let db: Arc<TokioRwLock<Box<dyn Db>>> = Arc::new(TokioRwLock::new(Box::new(db)));\n        let fork = ClientFork::new(config, Arc::clone(&db));\n        Ok((db, Some(fork)))\n    }\n\n    /// Configures everything related to forking based on the passed `eth_rpc_url`:\n    ///  - returning a tuple of a [ForkedDatabase] and [ClientForkConfig] which can be used to build\n    ///    a [ClientFork] to fork from.\n    ///  - modifying some parameters of the passed `env`\n    ///  - mutating some members of `self`\n    pub async fn setup_fork_db_config(\n        &mut self,\n        eth_rpc_url: String,\n        env: &mut Env,\n        fees: &FeeManager,\n    ) -> Result<(ForkedDatabase<AnyNetwork>, ClientForkConfig)> {\n        debug!(target: \"node\", ?eth_rpc_url, \"setting up fork db\");\n        let provider = Arc::new(\n            ProviderBuilder::new(&eth_rpc_url)\n                .timeout(self.fork_request_timeout)\n                .initial_backoff(self.fork_retry_backoff.as_millis() as u64)\n                .compute_units_per_second(self.compute_units_per_second)\n                .max_retry(self.fork_request_retries)\n                .headers(self.fork_headers.clone())\n                .build()\n                .wrap_err(\"failed to establish provider to fork url\")?,\n        );\n\n        let (fork_block_number, fork_chain_id, force_transactions) = if let Some(fork_choice) =\n            &self.fork_choice\n        {\n            let (fork_block_number, force_transactions) =\n                derive_block_and_transactions(fork_choice, &provider).await.wrap_err(\n                    \"failed to derive fork block number and force transactions from fork choice\",\n                )?;\n            let chain_id = if let Some(chain_id) = self.fork_chain_id {\n                Some(chain_id)\n            } else if self.hardfork.is_none() {\n                // Auto-adjust hardfork if not specified, but only if we're forking mainnet.\n                let chain_id =\n                    provider.get_chain_id().await.wrap_err(\"failed to fetch network chain ID\")?;\n                if alloy_chains::NamedChain::Mainnet == chain_id {\n                    let hardfork: EthereumHardfork =\n                        ethereum_hardfork_from_block_tag(fork_block_number);\n\n                    env.evm_env.cfg_env.spec = spec_id_from_ethereum_hardfork(hardfork);\n                    self.hardfork = Some(FoundryHardfork::Ethereum(hardfork));\n                }\n                Some(U256::from(chain_id))\n            } else {\n                None\n            };\n\n            (fork_block_number, chain_id, force_transactions)\n        } else {\n            // pick the last block number but also ensure it's not pending anymore\n            let bn = find_latest_fork_block(&provider)\n                .await\n                .wrap_err(\"failed to get fork block number\")?;\n            (bn, None, None)\n        };\n\n        let block = provider\n            .get_block(BlockNumberOrTag::Number(fork_block_number).into())\n            .await\n            .wrap_err(\"failed to get fork block\")?;\n\n        let block = if let Some(block) = block {\n            block\n        } else {\n            if let Ok(latest_block) = provider.get_block_number().await {\n                let mut message = format!(\n                    \"Failed to get block for block number: {fork_block_number}\\n\\\nlatest block number: {latest_block}\"\n                );\n                // If the `eth_getBlockByNumber` call succeeds, but returns null instead of\n                // the block, and the block number is less than equal the latest block, then\n                // the user is forking from a non-archive node with an older block number.\n                if fork_block_number <= latest_block {\n                    message.push_str(&format!(\"\\n{NON_ARCHIVE_NODE_WARNING}\"));\n                }\n                eyre::bail!(\"{message}\");\n            }\n            eyre::bail!(\"failed to get block for block number: {fork_block_number}\")\n        };\n\n        let gas_limit = self.fork_gas_limit(&block);\n        self.gas_limit = Some(gas_limit);\n\n        env.evm_env.block_env = BlockEnv {\n            gas_limit,\n            // Keep previous `coinbase` and `basefee` value\n            beneficiary: env.evm_env.block_env.beneficiary,\n            basefee: env.evm_env.block_env.basefee,\n            ..block_env_from_header(&block.header)\n        };\n\n        // Determine chain_id early so we can use it consistently\n        let chain_id = if let Some(chain_id) = self.chain_id {\n            chain_id\n        } else {\n            let chain_id = if let Some(fork_chain_id) = fork_chain_id {\n                fork_chain_id.to()\n            } else {\n                provider.get_chain_id().await.wrap_err(\"failed to fetch network chain ID\")?\n            };\n\n            // need to update the dev signers and env with the chain id\n            self.set_chain_id(Some(chain_id));\n            env.evm_env.cfg_env.chain_id = chain_id;\n            env.tx.base.chain_id = chain_id.into();\n            chain_id\n        };\n\n        // if not set explicitly we use the base fee of the latest block\n        if self.base_fee.is_none()\n            && let Some(base_fee) = block.header.base_fee_per_gas()\n        {\n            self.base_fee = Some(base_fee);\n            env.evm_env.block_env.basefee = base_fee;\n            // this is the base fee of the current block, but we need the base fee of\n            // the next block\n            let next_block_base_fee = fees.get_next_block_base_fee_per_gas(\n                block.header.gas_used(),\n                gas_limit,\n                block.header.base_fee_per_gas().unwrap_or_default(),\n            );\n\n            // update next base fee\n            fees.set_base_fee(next_block_base_fee);\n        }\n\n        if let (Some(blob_excess_gas), Some(blob_gas_used)) =\n            (block.header.excess_blob_gas(), block.header.blob_gas_used())\n        {\n            // Derive blob params using the fork block timestamp regardless of explicit base fee.\n            let blob_params = get_blob_params(chain_id, block.header.timestamp());\n\n            env.evm_env.block_env.blob_excess_gas_and_price = Some(BlobExcessGasAndPrice::new(\n                blob_excess_gas,\n                blob_params.update_fraction as u64,\n            ));\n\n            fees.set_blob_params(blob_params);\n\n            let next_block_blob_excess_gas =\n                fees.get_next_block_blob_excess_gas(blob_excess_gas, blob_gas_used);\n            fees.set_blob_excess_gas_and_price(BlobExcessGasAndPrice::new(\n                next_block_blob_excess_gas,\n                blob_params.update_fraction as u64,\n            ));\n        }\n\n        // use remote gas price\n        if self.gas_price.is_none()\n            && let Ok(gas_price) = provider.get_gas_price().await\n        {\n            self.gas_price = Some(gas_price);\n            fees.set_gas_price(gas_price);\n        }\n\n        let block_hash = block.header.hash;\n\n        let override_chain_id = self.chain_id;\n        // apply changes such as difficulty -> prevrandao and chain specifics for current chain id\n        apply_chain_and_block_specific_env_changes::<AnyNetwork>(\n            &mut env.evm_env,\n            &block,\n            self.networks,\n        );\n\n        let meta = BlockchainDbMeta::new(env.evm_env.block_env.clone(), eth_rpc_url.clone());\n        let block_chain_db = if self.fork_chain_id.is_some() {\n            BlockchainDb::new_skip_check(meta, self.block_cache_path(fork_block_number))\n        } else {\n            BlockchainDb::new(meta, self.block_cache_path(fork_block_number))\n        };\n\n        // This will spawn the background thread that will use the provider to fetch\n        // blockchain data from the other client\n        let backend = SharedBackend::spawn_backend(\n            Arc::clone(&provider),\n            block_chain_db.clone(),\n            Some(fork_block_number.into()),\n        )\n        .await;\n\n        let config = ClientForkConfig {\n            eth_rpc_url,\n            block_number: fork_block_number,\n            block_hash,\n            transaction_hash: self.fork_choice.and_then(|fc| fc.transaction_hash()),\n            provider,\n            chain_id,\n            override_chain_id,\n            timestamp: block.header.timestamp(),\n            base_fee: block.header.base_fee_per_gas().map(|g| g as u128),\n            timeout: self.fork_request_timeout,\n            retries: self.fork_request_retries,\n            backoff: self.fork_retry_backoff,\n            compute_units_per_second: self.compute_units_per_second,\n            total_difficulty: block.header.total_difficulty.unwrap_or_default(),\n            blob_gas_used: block.header.blob_gas_used().map(|g| g as u128),\n            blob_excess_gas_and_price: env.evm_env.block_env.blob_excess_gas_and_price,\n            force_transactions,\n        };\n\n        debug!(target: \"node\", fork_number=config.block_number, fork_hash=%config.block_hash, \"set up fork db\");\n\n        let mut db = ForkedDatabase::new(backend, block_chain_db);\n\n        // need to insert the forked block's hash\n        db.insert_block_hash(U256::from(config.block_number), config.block_hash);\n\n        Ok((db, config))\n    }\n\n    /// we only use the gas limit value of the block if it is non-zero and the block gas\n    /// limit is enabled, since there are networks where this is not used and is always\n    /// `0x0` which would inevitably result in `OutOfGas` errors as soon as the evm is about to record gas, See also <https://github.com/foundry-rs/foundry/issues/3247>\n    pub(crate) fn fork_gas_limit<B: BlockResponse<Header: BlockHeader>>(&self, block: &B) -> u64 {\n        if !self.disable_block_gas_limit {\n            if let Some(gas_limit) = self.gas_limit {\n                return gas_limit;\n            } else if block.header().gas_limit() > 0 {\n                return block.header().gas_limit();\n            }\n        }\n\n        u64::MAX\n    }\n\n    /// Returns the gas limit for a non forked anvil instance\n    ///\n    /// Checks the config for the `disable_block_gas_limit` flag\n    pub(crate) fn gas_limit(&self) -> u64 {\n        if self.disable_block_gas_limit {\n            return u64::MAX;\n        }\n\n        self.gas_limit.unwrap_or(DEFAULT_GAS_LIMIT)\n    }\n}\n\n/// If the fork choice is a block number, simply return it with an empty list of transactions.\n/// If the fork choice is a transaction hash, determine the block that the transaction was mined in,\n/// and return the block number before the fork block along with all transactions in the fork block\n/// that are before (and including) the fork transaction.\nasync fn derive_block_and_transactions(\n    fork_choice: &ForkChoice,\n    provider: &Arc<RetryProvider>,\n) -> eyre::Result<(BlockNumber, Option<Vec<PoolTransaction<FoundryTxEnvelope>>>)> {\n    match fork_choice {\n        ForkChoice::Block(block_number) => {\n            let block_number = *block_number;\n            if block_number >= 0 {\n                return Ok((block_number as u64, None));\n            }\n            // subtract from latest block number\n            let latest = provider.get_block_number().await?;\n\n            Ok((block_number.saturating_add(latest as i128) as u64, None))\n        }\n        ForkChoice::Transaction(transaction_hash) => {\n            // Determine the block that this transaction was mined in\n            let transaction = provider\n                .get_transaction_by_hash(transaction_hash.0.into())\n                .await?\n                .ok_or_else(|| eyre::eyre!(\"failed to get fork transaction by hash\"))?;\n            let transaction_block_number = transaction.block_number().ok_or_else(|| {\n                eyre::eyre!(\"fork transaction is not mined yet (no block number)\")\n            })?;\n\n            // Get the block pertaining to the fork transaction\n            let transaction_block = provider\n                .get_block_by_number(transaction_block_number.into())\n                .full()\n                .await?\n                .ok_or_else(|| eyre::eyre!(\"failed to get fork block by number\"))?;\n\n            // Filter out transactions that are after the fork transaction\n            let filtered_transactions = transaction_block\n                .transactions\n                .as_transactions()\n                .ok_or_else(|| eyre::eyre!(\"failed to get transactions from full fork block\"))?\n                .iter()\n                .take_while_inclusive(|&transaction| transaction.tx_hash() != transaction_hash.0)\n                .collect::<Vec<_>>();\n\n            // Convert the transactions to PoolTransactions\n            let force_transactions = filtered_transactions\n                .iter()\n                .map(|&transaction| PoolTransaction::try_from(transaction.clone()))\n                .collect::<Result<Vec<_>, _>>()\n                .map_err(|e| eyre::eyre!(\"Err converting to pool transactions {e}\"))?;\n            Ok((transaction_block_number.saturating_sub(1), Some(force_transactions)))\n        }\n    }\n}\n\n/// Fork delimiter used to specify which block or transaction to fork from.\n#[derive(Clone, Copy, Debug, PartialEq, Eq)]\npub enum ForkChoice {\n    /// Block number to fork from.\n    ///\n    /// If negative, the given value is subtracted from the `latest` block number.\n    Block(i128),\n    /// Transaction hash to fork from.\n    Transaction(TxHash),\n}\n\nimpl ForkChoice {\n    /// Returns the block number to fork from\n    pub fn block_number(&self) -> Option<i128> {\n        match self {\n            Self::Block(block_number) => Some(*block_number),\n            Self::Transaction(_) => None,\n        }\n    }\n\n    /// Returns the transaction hash to fork from\n    pub fn transaction_hash(&self) -> Option<TxHash> {\n        match self {\n            Self::Block(_) => None,\n            Self::Transaction(transaction_hash) => Some(*transaction_hash),\n        }\n    }\n}\n\n/// Convert a transaction hash into a ForkChoice\nimpl From<TxHash> for ForkChoice {\n    fn from(tx_hash: TxHash) -> Self {\n        Self::Transaction(tx_hash)\n    }\n}\n\n/// Convert a decimal block number into a ForkChoice\nimpl From<u64> for ForkChoice {\n    fn from(block: u64) -> Self {\n        Self::Block(block as i128)\n    }\n}\n\n#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]\npub struct PruneStateHistoryConfig {\n    pub enabled: bool,\n    pub max_memory_history: Option<usize>,\n}\n\nimpl PruneStateHistoryConfig {\n    /// Returns `true` if writing state history is supported\n    pub fn is_state_history_supported(&self) -> bool {\n        !self.enabled || self.max_memory_history.is_some()\n    }\n\n    /// Returns true if this setting was enabled.\n    pub fn is_config_enabled(&self) -> bool {\n        self.enabled\n    }\n\n    pub fn from_args(val: Option<Option<usize>>) -> Self {\n        val.map(|max_memory_history| Self { enabled: true, max_memory_history }).unwrap_or_default()\n    }\n}\n\n/// Can create dev accounts\n#[derive(Clone, Debug)]\npub struct AccountGenerator {\n    chain_id: u64,\n    amount: usize,\n    phrase: String,\n    derivation_path: Option<String>,\n}\n\nimpl AccountGenerator {\n    pub fn new(amount: usize) -> Self {\n        Self {\n            chain_id: CHAIN_ID,\n            amount,\n            phrase: Mnemonic::<English>::new(&mut thread_rng()).to_phrase(),\n            derivation_path: None,\n        }\n    }\n\n    #[must_use]\n    pub fn phrase(mut self, phrase: impl Into<String>) -> Self {\n        self.phrase = phrase.into();\n        self\n    }\n\n    fn get_phrase(&self) -> &str {\n        &self.phrase\n    }\n\n    #[must_use]\n    pub fn chain_id(mut self, chain_id: impl Into<u64>) -> Self {\n        self.chain_id = chain_id.into();\n        self\n    }\n\n    #[must_use]\n    pub fn derivation_path(mut self, derivation_path: impl Into<String>) -> Self {\n        let mut derivation_path = derivation_path.into();\n        if !derivation_path.ends_with('/') {\n            derivation_path.push('/');\n        }\n        self.derivation_path = Some(derivation_path);\n        self\n    }\n\n    fn get_derivation_path(&self) -> &str {\n        self.derivation_path.as_deref().unwrap_or(\"m/44'/60'/0'/0/\")\n    }\n}\n\nimpl AccountGenerator {\n    pub fn generate(&self) -> eyre::Result<Vec<PrivateKeySigner>> {\n        let builder = MnemonicBuilder::<English>::default().phrase(self.phrase.as_str());\n\n        // use the derivation path\n        let derivation_path = self.get_derivation_path();\n\n        let mut wallets = Vec::with_capacity(self.amount);\n        for idx in 0..self.amount {\n            let builder =\n                builder.clone().derivation_path(format!(\"{derivation_path}{idx}\")).unwrap();\n            let wallet = builder.build()?.with_chain_id(Some(self.chain_id));\n            wallets.push(wallet)\n        }\n        Ok(wallets)\n    }\n}\n\n/// Returns the path to anvil dir `~/.foundry/anvil`\npub fn anvil_dir() -> Option<PathBuf> {\n    Config::foundry_dir().map(|p| p.join(\"anvil\"))\n}\n\n/// Returns the root path to anvil's temporary storage `~/.foundry/anvil/`\npub fn anvil_tmp_dir() -> Option<PathBuf> {\n    anvil_dir().map(|p| p.join(\"tmp\"))\n}\n\n/// Finds the latest appropriate block to fork\n///\n/// This fetches the \"latest\" block and checks whether the `Block` is fully populated (`hash` field\n/// is present). This prevents edge cases where anvil forks the \"latest\" block but `eth_getBlockByNumber` still returns a pending block, <https://github.com/foundry-rs/foundry/issues/2036>\nasync fn find_latest_fork_block<P: Provider<AnyNetwork>>(\n    provider: P,\n) -> Result<u64, TransportError> {\n    let mut num = provider.get_block_number().await?;\n\n    // walk back from the head of the chain, but at most 2 blocks, which should be more than enough\n    // leeway\n    for _ in 0..2 {\n        if let Some(block) = provider.get_block(num.into()).await?\n            && !block.header.hash.is_zero()\n        {\n            break;\n        }\n        // block not actually finalized, so we try the block before\n        num = num.saturating_sub(1)\n    }\n\n    Ok(num)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_prune_history() {\n        let config = PruneStateHistoryConfig::default();\n        assert!(config.is_state_history_supported());\n        let config = PruneStateHistoryConfig::from_args(Some(None));\n        assert!(!config.is_state_history_supported());\n        let config = PruneStateHistoryConfig::from_args(Some(Some(10)));\n        assert!(config.is_state_history_supported());\n    }\n}\n"
  },
  {
    "path": "crates/anvil/src/error.rs",
    "content": "/// Result alias\npub type NodeResult<T> = Result<T, NodeError>;\n\n/// An error that can occur when launching a anvil instance\n#[derive(Debug, thiserror::Error)]\npub enum NodeError {\n    #[error(transparent)]\n    Hyper(#[from] hyper::Error),\n    #[error(transparent)]\n    Io(#[from] std::io::Error),\n}\n"
  },
  {
    "path": "crates/anvil/src/eth/api.rs",
    "content": "use super::{\n    backend::mem::{BlockRequest, DatabaseRef, State},\n    sign::build_impersonated,\n};\nuse crate::{\n    ClientFork, LoggingManager, Miner, MiningMode, StorageInfo,\n    eth::{\n        backend::{\n            self,\n            db::SerializableState,\n            mem::{MIN_CREATE_GAS, MIN_TRANSACTION_GAS},\n            notifications::NewBlockNotifications,\n            validate::TransactionValidator,\n        },\n        error::{\n            BlockchainError, FeeHistoryError, InvalidTransactionError, Result, ToRpcResponseResult,\n        },\n        fees::{FeeDetails, FeeHistoryCache, MIN_SUGGESTED_PRIORITY_FEE},\n        macros::node_info,\n        miner::FixedBlockTimeMiner,\n        pool::{\n            Pool,\n            transactions::{\n                PoolTransaction, TransactionOrder, TransactionPriority, TxMarker, to_marker,\n            },\n        },\n        sign::{self, Signer},\n    },\n    filter::{EthFilter, Filters, LogsFilter},\n    mem::transaction_build,\n};\nuse alloy_consensus::{\n    Blob, BlockHeader, Transaction, TrieAccount, TxEip4844Variant, transaction::Recovered,\n};\nuse alloy_dyn_abi::TypedData;\nuse alloy_eips::{\n    eip2718::Encodable2718,\n    eip7910::{EthConfig, EthForkConfig},\n};\nuse alloy_evm::overrides::{OverrideBlockHashes, apply_state_overrides};\nuse alloy_network::{\n    AnyRpcBlock, AnyRpcTransaction, BlockResponse, Network, ReceiptResponse, TransactionBuilder,\n    TransactionBuilder4844, TransactionResponse, eip2718::Decodable2718,\n};\nuse alloy_primitives::{\n    Address, B64, B256, Bytes, TxHash, TxKind, U64, U256,\n    map::{HashMap, HashSet},\n};\nuse alloy_rpc_types::{\n    AccessList, AccessListResult, BlockId, BlockNumberOrTag as BlockNumber, BlockTransactions,\n    EIP1186AccountProofResponse, FeeHistory, Filter, FilteredParams, Index, Log, Work,\n    anvil::{\n        ForkedNetwork, Forking, Metadata, MineOptions, NodeEnvironment, NodeForkConfig, NodeInfo,\n    },\n    request::TransactionRequest,\n    simulate::{SimulatePayload, SimulatedBlock},\n    state::{AccountOverride, EvmOverrides, StateOverridesBuilder},\n    trace::{\n        filter::TraceFilter,\n        geth::{GethDebugTracingCallOptions, GethDebugTracingOptions, GethTrace},\n        parity::{LocalizedTransactionTrace, TraceResultsWithTransactionHash, TraceType},\n    },\n    txpool::{TxpoolContent, TxpoolInspect, TxpoolInspectSummary, TxpoolStatus},\n};\nuse alloy_rpc_types_eth::FillTransaction;\nuse alloy_serde::WithOtherFields;\nuse alloy_sol_types::{SolCall, SolValue, sol};\nuse alloy_transport::TransportErrorKind;\nuse anvil_core::{\n    eth::{\n        EthRequest,\n        block::BlockInfo,\n        transaction::{MaybeImpersonatedTransaction, PendingTransaction},\n    },\n    types::{ReorgOptions, TransactionData},\n};\nuse anvil_rpc::{error::RpcError, response::ResponseResult};\nuse foundry_common::provider::ProviderBuilder;\nuse foundry_evm::decode::RevertDecoder;\nuse foundry_primitives::{\n    FoundryNetwork, FoundryTransactionRequest, FoundryTxEnvelope, FoundryTxReceipt, FoundryTxType,\n    FoundryTypedTx,\n};\nuse futures::{\n    StreamExt, TryFutureExt,\n    channel::{mpsc::Receiver, oneshot},\n};\nuse parking_lot::RwLock;\nuse revm::{\n    context::BlockEnv,\n    context_interface::{block::BlobExcessGasAndPrice, result::Output},\n    database::CacheDB,\n    interpreter::{InstructionResult, return_ok, return_revert},\n    primitives::eip7702::PER_EMPTY_ACCOUNT_COST,\n};\nuse std::{sync::Arc, time::Duration};\nuse tokio::{\n    sync::mpsc::{UnboundedReceiver, unbounded_channel},\n    try_join,\n};\n\n/// The client version: `anvil/v{major}.{minor}.{patch}`\npub const CLIENT_VERSION: &str = concat!(\"anvil/v\", env!(\"CARGO_PKG_VERSION\"));\n\n/// The entry point for executing eth api RPC call - The Eth RPC interface.\n///\n/// This type is cheap to clone and can be used concurrently\npub struct EthApi<N: Network> {\n    /// The transaction pool\n    pool: Arc<Pool<N::TxEnvelope>>,\n    /// Holds all blockchain related data\n    /// In-Memory only for now\n    pub backend: Arc<backend::mem::Backend<N>>,\n    /// Whether this node is mining\n    is_mining: bool,\n    /// available signers\n    signers: Arc<Vec<Box<dyn Signer<N>>>>,\n    /// data required for `eth_feeHistory`\n    fee_history_cache: FeeHistoryCache,\n    /// max number of items kept in fee cache\n    fee_history_limit: u64,\n    /// access to the actual miner\n    ///\n    /// This access is required in order to adjust miner settings based on requests received from\n    /// custom RPC endpoints\n    miner: Miner<N::TxEnvelope>,\n    /// allows to enabled/disable logging\n    logger: LoggingManager,\n    /// Tracks all active filters\n    filters: Filters<N>,\n    /// How transactions are ordered in the pool\n    transaction_order: Arc<RwLock<TransactionOrder>>,\n    /// Whether we're listening for RPC calls\n    net_listening: bool,\n    /// The instance ID. Changes on every reset.\n    instance_id: Arc<RwLock<B256>>,\n}\n\nimpl<N: Network> Clone for EthApi<N> {\n    fn clone(&self) -> Self {\n        Self {\n            pool: self.pool.clone(),\n            backend: self.backend.clone(),\n            is_mining: self.is_mining,\n            signers: self.signers.clone(),\n            fee_history_cache: self.fee_history_cache.clone(),\n            fee_history_limit: self.fee_history_limit,\n            miner: self.miner.clone(),\n            logger: self.logger.clone(),\n            filters: self.filters.clone(),\n            transaction_order: self.transaction_order.clone(),\n            net_listening: self.net_listening,\n            instance_id: self.instance_id.clone(),\n        }\n    }\n}\n\n// == impl EthApi<N: Network> generic methods ==\n\nimpl<N: Network> EthApi<N> {\n    /// Creates a new instance\n    #[expect(clippy::too_many_arguments)]\n    pub fn new(\n        pool: Arc<Pool<N::TxEnvelope>>,\n        backend: Arc<backend::mem::Backend<N>>,\n        signers: Arc<Vec<Box<dyn Signer<N>>>>,\n        fee_history_cache: FeeHistoryCache,\n        fee_history_limit: u64,\n        miner: Miner<N::TxEnvelope>,\n        logger: LoggingManager,\n        filters: Filters<N>,\n        transactions_order: TransactionOrder,\n    ) -> Self {\n        Self {\n            pool,\n            backend,\n            is_mining: true,\n            signers,\n            fee_history_cache,\n            fee_history_limit,\n            miner,\n            logger,\n            filters,\n            net_listening: true,\n            transaction_order: Arc::new(RwLock::new(transactions_order)),\n            instance_id: Arc::new(RwLock::new(B256::random())),\n        }\n    }\n\n    /// Returns the current gas price\n    pub fn gas_price(&self) -> u128 {\n        if self.backend.is_eip1559() {\n            if self.backend.is_min_priority_fee_enforced() {\n                (self.backend.base_fee() as u128).saturating_add(self.lowest_suggestion_tip())\n            } else {\n                self.backend.base_fee() as u128\n            }\n        } else {\n            self.backend.fees().raw_gas_price()\n        }\n    }\n\n    /// Returns the suggested fee cap.\n    ///\n    /// Returns at least [MIN_SUGGESTED_PRIORITY_FEE]\n    fn lowest_suggestion_tip(&self) -> u128 {\n        let block_number = self.backend.best_number();\n        let latest_cached_block = self.fee_history_cache.lock().get(&block_number).cloned();\n\n        match latest_cached_block {\n            Some(block) => block.rewards.iter().copied().min(),\n            None => self.fee_history_cache.lock().values().flat_map(|b| b.rewards.clone()).min(),\n        }\n        .map(|fee| fee.max(MIN_SUGGESTED_PRIORITY_FEE))\n        .unwrap_or(MIN_SUGGESTED_PRIORITY_FEE)\n    }\n\n    /// Returns true if auto mining is enabled, and false.\n    ///\n    /// Handler for ETH RPC call: `anvil_getAutomine`\n    pub fn anvil_get_auto_mine(&self) -> Result<bool> {\n        node_info!(\"anvil_getAutomine\");\n        Ok(self.miner.is_auto_mine())\n    }\n\n    /// Returns the value of mining interval, if set.\n    ///\n    /// Handler for ETH RPC call: `anvil_getIntervalMining`.\n    pub fn anvil_get_interval_mining(&self) -> Result<Option<u64>> {\n        node_info!(\"anvil_getIntervalMining\");\n        Ok(self.miner.get_interval())\n    }\n\n    /// Enables or disables, based on the single boolean argument, the automatic mining of new\n    /// blocks with each new transaction submitted to the network.\n    ///\n    /// Handler for ETH RPC call: `evm_setAutomine`\n    pub async fn anvil_set_auto_mine(&self, enable_automine: bool) -> Result<()> {\n        node_info!(\"evm_setAutomine\");\n        if self.miner.is_auto_mine() {\n            if enable_automine {\n                return Ok(());\n            }\n            self.miner.set_mining_mode(MiningMode::None);\n        } else if enable_automine {\n            let listener = self.pool.add_ready_listener();\n            let mode = MiningMode::instant(1_000, listener);\n            self.miner.set_mining_mode(mode);\n        }\n        Ok(())\n    }\n\n    /// Sets the mining behavior to interval with the given interval (seconds)\n    ///\n    /// Handler for ETH RPC call: `evm_setIntervalMining`\n    pub fn anvil_set_interval_mining(&self, secs: u64) -> Result<()> {\n        node_info!(\"evm_setIntervalMining\");\n        let mining_mode = if secs == 0 {\n            MiningMode::None\n        } else {\n            let block_time = Duration::from_secs(secs);\n\n            // This ensures that memory limits are stricter in interval-mine mode\n            self.backend.update_interval_mine_block_time(block_time);\n\n            MiningMode::FixedBlockTime(FixedBlockTimeMiner::new(block_time))\n        };\n        self.miner.set_mining_mode(mining_mode);\n        Ok(())\n    }\n\n    /// Removes transactions from the pool\n    ///\n    /// Handler for RPC call: `anvil_dropTransaction`\n    pub async fn anvil_drop_transaction(&self, tx_hash: B256) -> Result<Option<B256>> {\n        node_info!(\"anvil_dropTransaction\");\n        Ok(self.pool.drop_transaction(tx_hash).map(|tx| tx.hash()))\n    }\n\n    /// Removes all transactions from the pool\n    ///\n    /// Handler for RPC call: `anvil_dropAllTransactions`\n    pub async fn anvil_drop_all_transactions(&self) -> Result<()> {\n        node_info!(\"anvil_dropAllTransactions\");\n        self.pool.clear();\n        Ok(())\n    }\n\n    pub async fn anvil_set_chain_id(&self, chain_id: u64) -> Result<()> {\n        node_info!(\"anvil_setChainId\");\n        self.backend.set_chain_id(chain_id);\n        Ok(())\n    }\n\n    /// Modifies the balance of an account.\n    ///\n    /// Handler for RPC call: `anvil_setBalance`\n    pub async fn anvil_set_balance(&self, address: Address, balance: U256) -> Result<()> {\n        node_info!(\"anvil_setBalance\");\n        self.backend.set_balance(address, balance).await?;\n        Ok(())\n    }\n\n    /// Sets the code of a contract.\n    ///\n    /// Handler for RPC call: `anvil_setCode`\n    pub async fn anvil_set_code(&self, address: Address, code: Bytes) -> Result<()> {\n        node_info!(\"anvil_setCode\");\n        self.backend.set_code(address, code).await?;\n        Ok(())\n    }\n\n    /// Sets the nonce of an address.\n    ///\n    /// Handler for RPC call: `anvil_setNonce`\n    pub async fn anvil_set_nonce(&self, address: Address, nonce: U256) -> Result<()> {\n        node_info!(\"anvil_setNonce\");\n        self.backend.set_nonce(address, nonce).await?;\n        Ok(())\n    }\n\n    /// Writes a single slot of the account's storage.\n    ///\n    /// Handler for RPC call: `anvil_setStorageAt`\n    pub async fn anvil_set_storage_at(\n        &self,\n        address: Address,\n        slot: U256,\n        val: B256,\n    ) -> Result<bool> {\n        node_info!(\"anvil_setStorageAt\");\n        self.backend.set_storage_at(address, slot, val).await?;\n        Ok(true)\n    }\n\n    /// Enable or disable logging.\n    ///\n    /// Handler for RPC call: `anvil_setLoggingEnabled`\n    pub async fn anvil_set_logging(&self, enable: bool) -> Result<()> {\n        node_info!(\"anvil_setLoggingEnabled\");\n        self.logger.set_enabled(enable);\n        Ok(())\n    }\n\n    /// Set the minimum gas price for the node.\n    ///\n    /// Handler for RPC call: `anvil_setMinGasPrice`\n    pub async fn anvil_set_min_gas_price(&self, gas: U256) -> Result<()> {\n        node_info!(\"anvil_setMinGasPrice\");\n        if self.backend.is_eip1559() {\n            return Err(RpcError::invalid_params(\n                \"anvil_setMinGasPrice is not supported when EIP-1559 is active\",\n            )\n            .into());\n        }\n        self.backend.set_gas_price(gas.to());\n        Ok(())\n    }\n\n    /// Sets the base fee of the next block.\n    ///\n    /// Handler for RPC call: `anvil_setNextBlockBaseFeePerGas`\n    pub async fn anvil_set_next_block_base_fee_per_gas(&self, basefee: U256) -> Result<()> {\n        node_info!(\"anvil_setNextBlockBaseFeePerGas\");\n        if !self.backend.is_eip1559() {\n            return Err(RpcError::invalid_params(\n                \"anvil_setNextBlockBaseFeePerGas is only supported when EIP-1559 is active\",\n            )\n            .into());\n        }\n        self.backend.set_base_fee(basefee.to());\n        Ok(())\n    }\n\n    /// Sets the coinbase address.\n    ///\n    /// Handler for RPC call: `anvil_setCoinbase`\n    pub async fn anvil_set_coinbase(&self, address: Address) -> Result<()> {\n        node_info!(\"anvil_setCoinbase\");\n        self.backend.set_coinbase(address);\n        Ok(())\n    }\n\n    /// Retrieves the Anvil node configuration params.\n    ///\n    /// Handler for RPC call: `anvil_nodeInfo`\n    pub async fn anvil_node_info(&self) -> Result<NodeInfo> {\n        node_info!(\"anvil_nodeInfo\");\n\n        let env = self.backend.env().read();\n        let fork_config = self.backend.get_fork();\n        let tx_order = self.transaction_order.read();\n        let hard_fork: &str = env.evm_env.cfg_env.spec.into();\n\n        Ok(NodeInfo {\n            current_block_number: self.backend.best_number(),\n            current_block_timestamp: env.evm_env.block_env.timestamp.saturating_to(),\n            current_block_hash: self.backend.best_hash(),\n            hard_fork: hard_fork.to_string(),\n            transaction_order: match *tx_order {\n                TransactionOrder::Fifo => \"fifo\".to_string(),\n                TransactionOrder::Fees => \"fees\".to_string(),\n            },\n            environment: NodeEnvironment {\n                base_fee: self.backend.base_fee() as u128,\n                chain_id: self.backend.chain_id().to::<u64>(),\n                gas_limit: self.backend.gas_limit(),\n                gas_price: self.gas_price(),\n            },\n            fork_config: fork_config\n                .map(|fork| {\n                    let config = fork.config.read();\n\n                    NodeForkConfig {\n                        fork_url: Some(config.eth_rpc_url.clone()),\n                        fork_block_number: Some(config.block_number),\n                        fork_retry_backoff: Some(config.backoff.as_millis()),\n                    }\n                })\n                .unwrap_or_default(),\n        })\n    }\n\n    /// Retrieves metadata about the Anvil instance.\n    ///\n    /// Handler for RPC call: `anvil_metadata`\n    pub async fn anvil_metadata(&self) -> Result<Metadata> {\n        node_info!(\"anvil_metadata\");\n        let fork_config = self.backend.get_fork();\n\n        Ok(Metadata {\n            client_version: CLIENT_VERSION.to_string(),\n            chain_id: self.backend.chain_id().to::<u64>(),\n            latest_block_hash: self.backend.best_hash(),\n            latest_block_number: self.backend.best_number(),\n            instance_id: *self.instance_id.read(),\n            forked_network: fork_config.map(|cfg| ForkedNetwork {\n                chain_id: cfg.chain_id(),\n                fork_block_number: cfg.block_number(),\n                fork_block_hash: cfg.block_hash(),\n            }),\n            snapshots: self.backend.list_state_snapshots(),\n        })\n    }\n\n    pub async fn anvil_remove_pool_transactions(&self, address: Address) -> Result<()> {\n        node_info!(\"anvil_removePoolTransactions\");\n        self.pool.remove_transactions_by_address(address);\n        Ok(())\n    }\n\n    /// Snapshot the state of the blockchain at the current block.\n    ///\n    /// Handler for RPC call: `evm_snapshot`\n    pub async fn evm_snapshot(&self) -> Result<U256> {\n        node_info!(\"evm_snapshot\");\n        Ok(self.backend.create_state_snapshot().await)\n    }\n\n    /// Jump forward in time by the given amount of time, in seconds.\n    ///\n    /// Handler for RPC call: `evm_increaseTime`\n    pub async fn evm_increase_time(&self, seconds: U256) -> Result<i64> {\n        node_info!(\"evm_increaseTime\");\n        Ok(self.backend.time().increase_time(seconds.try_into().unwrap_or(u64::MAX)) as i64)\n    }\n\n    /// Similar to `evm_increaseTime` but takes the exact timestamp that you want in the next block\n    ///\n    /// Handler for RPC call: `evm_setNextBlockTimestamp`\n    pub fn evm_set_next_block_timestamp(&self, seconds: u64) -> Result<()> {\n        node_info!(\"evm_setNextBlockTimestamp\");\n        self.backend.time().set_next_block_timestamp(seconds)\n    }\n\n    /// Sets the specific timestamp and returns the number of seconds between the given timestamp\n    /// and the current time.\n    ///\n    /// Handler for RPC call: `evm_setTime`\n    pub fn evm_set_time(&self, timestamp: u64) -> Result<u64> {\n        node_info!(\"evm_setTime\");\n        let now = self.backend.time().current_call_timestamp();\n        self.backend.time().reset(timestamp);\n\n        // number of seconds between the given timestamp and the current time.\n        let offset = timestamp.saturating_sub(now);\n        Ok(Duration::from_millis(offset).as_secs())\n    }\n\n    /// Set the next block gas limit\n    ///\n    /// Handler for RPC call: `evm_setBlockGasLimit`\n    pub fn evm_set_block_gas_limit(&self, gas_limit: U256) -> Result<bool> {\n        node_info!(\"evm_setBlockGasLimit\");\n        self.backend.set_gas_limit(gas_limit.to());\n        Ok(true)\n    }\n\n    /// Sets an interval for the block timestamp\n    ///\n    /// Handler for RPC call: `anvil_setBlockTimestampInterval`\n    pub fn evm_set_block_timestamp_interval(&self, seconds: u64) -> Result<()> {\n        node_info!(\"anvil_setBlockTimestampInterval\");\n        self.backend.time().set_block_timestamp_interval(seconds);\n        Ok(())\n    }\n\n    /// Sets an interval for the block timestamp\n    ///\n    /// Handler for RPC call: `anvil_removeBlockTimestampInterval`\n    pub fn evm_remove_block_timestamp_interval(&self) -> Result<bool> {\n        node_info!(\"anvil_removeBlockTimestampInterval\");\n        Ok(self.backend.time().remove_block_timestamp_interval())\n    }\n\n    /// Sets the backend rpc url\n    ///\n    /// Handler for ETH RPC call: `anvil_setRpcUrl`\n    pub fn anvil_set_rpc_url(&self, url: String) -> Result<()> {\n        node_info!(\"anvil_setRpcUrl\");\n        if let Some(fork) = self.backend.get_fork() {\n            let mut config = fork.config.write();\n            // let interval = config.provider.get_interval();\n            let new_provider = Arc::new(\n                ProviderBuilder::new(&url).max_retry(10).initial_backoff(1000).build().map_err(\n                    |_| {\n                        TransportErrorKind::custom_str(\n                            format!(\"Failed to parse invalid url {url}\").as_str(),\n                        )\n                    },\n                    // TODO: Add interval\n                )?, // .interval(interval),\n            );\n            config.provider = new_provider;\n            trace!(target: \"backend\", \"Updated fork rpc from \\\"{}\\\" to \\\"{}\\\"\", config.eth_rpc_url, url);\n            config.eth_rpc_url = url;\n        }\n        Ok(())\n    }\n\n    /// Returns the number of transactions currently pending for inclusion in the next block(s), as\n    /// well as the ones that are being scheduled for future execution only.\n    /// Ref: [Here](https://geth.ethereum.org/docs/rpc/ns-txpool#txpool_status)\n    ///\n    /// Handler for ETH RPC call: `txpool_status`\n    pub async fn txpool_status(&self) -> Result<TxpoolStatus> {\n        node_info!(\"txpool_status\");\n        Ok(self.pool.txpool_status())\n    }\n\n    /// Executes the future on a new blocking task.\n    async fn on_blocking_task<C, F, R>(&self, c: C) -> Result<R>\n    where\n        C: FnOnce(Self) -> F,\n        F: Future<Output = Result<R>> + Send + 'static,\n        R: Send + 'static,\n    {\n        let (tx, rx) = oneshot::channel();\n        let this = self.clone();\n        let f = c(this);\n        tokio::task::spawn_blocking(move || {\n            tokio::runtime::Handle::current().block_on(async move {\n                let res = f.await;\n                let _ = tx.send(res);\n            })\n        });\n        rx.await.map_err(|_| BlockchainError::Internal(\"blocking task panicked\".to_string()))?\n    }\n\n    /// Updates the `TransactionOrder`\n    pub fn set_transaction_order(&self, order: TransactionOrder) {\n        *self.transaction_order.write() = order;\n    }\n\n    /// Returns the chain ID used for transaction\n    pub fn chain_id(&self) -> u64 {\n        self.backend.chain_id().to::<u64>()\n    }\n\n    /// Returns the configured fork, if any.\n    pub fn get_fork(&self) -> Option<ClientFork> {\n        self.backend.get_fork()\n    }\n\n    /// Returns the current instance's ID.\n    pub fn instance_id(&self) -> B256 {\n        *self.instance_id.read()\n    }\n\n    /// Resets the instance ID.\n    pub fn reset_instance_id(&self) {\n        *self.instance_id.write() = B256::random();\n    }\n\n    /// Returns the first signer that can sign for the given address\n    #[expect(clippy::borrowed_box)]\n    pub fn get_signer(&self, address: Address) -> Option<&Box<dyn Signer<N>>> {\n        self.signers.iter().find(|signer| signer.is_signer_for(address))\n    }\n\n    /// Returns a new listeners for ready transactions\n    pub fn new_ready_transactions(&self) -> Receiver<TxHash> {\n        self.pool.add_ready_listener()\n    }\n\n    /// Returns true if forked\n    pub fn is_fork(&self) -> bool {\n        self.backend.is_fork()\n    }\n\n    /// Returns the current state root\n    pub async fn state_root(&self) -> Option<B256> {\n        self.backend.get_db().read().await.maybe_state_root()\n    }\n\n    /// Returns true if the `addr` is currently impersonated\n    pub fn is_impersonated(&self, addr: Address) -> bool {\n        self.backend.cheats().is_impersonated(addr)\n    }\n\n    /// Returns a new accessor for certain storage elements\n    pub fn storage_info(&self) -> StorageInfo<N> {\n        StorageInfo::new(Arc::clone(&self.backend))\n    }\n}\n\n// == impl EthApi anvil endpoints ==\n\nimpl EthApi<FoundryNetwork> {\n    /// Reset the fork to a fresh forked state, and optionally update the fork config.\n    ///\n    /// If `forking` is `None` then this will disable forking entirely.\n    ///\n    /// Handler for RPC call: `anvil_reset`\n    pub async fn anvil_reset(&self, forking: Option<Forking>) -> Result<()> {\n        self.reset_instance_id();\n        node_info!(\"anvil_reset\");\n        if let Some(forking) = forking {\n            // if we're resetting the fork we need to reset the instance id\n            self.backend.reset_fork(forking).await?;\n        } else {\n            // Reset to a fresh in-memory state\n            self.backend.reset_to_in_mem().await?;\n        }\n        // Clear pending transactions since they reference the old chain state.\n        self.pool.clear();\n        Ok(())\n    }\n\n    /// Create a buffer that represents all state on the chain, which can be loaded to separate\n    /// process by calling `anvil_loadState`\n    ///\n    /// Handler for RPC call: `anvil_dumpState`\n    pub async fn anvil_dump_state(\n        &self,\n        preserve_historical_states: Option<bool>,\n    ) -> Result<Bytes> {\n        node_info!(\"anvil_dumpState\");\n        self.backend.dump_state(preserve_historical_states.unwrap_or(false)).await\n    }\n\n    /// Returns the current state\n    pub async fn serialized_state(\n        &self,\n        preserve_historical_states: bool,\n    ) -> Result<SerializableState> {\n        self.backend.serialized_state(preserve_historical_states).await\n    }\n\n    /// Append chain state buffer to current chain. Will overwrite any conflicting addresses or\n    /// storage.\n    ///\n    /// Handler for RPC call: `anvil_loadState`\n    pub async fn anvil_load_state(&self, buf: Bytes) -> Result<bool> {\n        node_info!(\"anvil_loadState\");\n        self.backend.load_state_bytes(buf).await\n    }\n\n    /// Revert the state of the blockchain to a previous snapshot.\n    /// Takes a single parameter, which is the snapshot id to revert to.\n    ///\n    /// Handler for RPC call: `evm_revert`\n    pub async fn evm_revert(&self, id: U256) -> Result<bool> {\n        node_info!(\"evm_revert\");\n        self.backend.revert_state_snapshot(id).await\n    }\n\n    async fn block_request(\n        &self,\n        block_number: Option<BlockId>,\n    ) -> Result<BlockRequest<FoundryTxEnvelope>> {\n        let block_request = match block_number {\n            Some(BlockId::Number(BlockNumber::Pending)) => {\n                let pending_txs = self.pool.ready_transactions().collect();\n                BlockRequest::Pending(pending_txs)\n            }\n            _ => {\n                let number = self.backend.ensure_block_number(block_number).await?;\n                BlockRequest::Number(number)\n            }\n        };\n        Ok(block_request)\n    }\n\n    /// Increases the balance of an account.\n    ///\n    /// Handler for RPC call: `anvil_addBalance`\n    pub async fn anvil_add_balance(&self, address: Address, balance: U256) -> Result<()> {\n        node_info!(\"anvil_addBalance\");\n        let current_balance = self.backend.get_balance(address, None).await?;\n        self.backend.set_balance(address, current_balance.saturating_add(balance)).await?;\n        Ok(())\n    }\n\n    /// Rollback the chain to a specific depth.\n    ///\n    /// e.g depth = 3\n    ///     A  -> B  -> C  -> D  -> E\n    ///     A  -> B\n    ///\n    /// Depth specifies the height to rollback the chain back to. Depth must not exceed the current\n    /// chain height, i.e. can't rollback past the genesis block.\n    ///\n    /// Handler for RPC call: `anvil_rollback`\n    pub async fn anvil_rollback(&self, depth: Option<u64>) -> Result<()> {\n        node_info!(\"anvil_rollback\");\n        let depth = depth.unwrap_or(1);\n\n        // Check reorg depth doesn't exceed current chain height\n        let current_height = self.backend.best_number();\n        let common_height = current_height.checked_sub(depth).ok_or(BlockchainError::RpcError(\n            RpcError::invalid_params(format!(\n                \"Rollback depth must not exceed current chain height: current height {current_height}, depth {depth}\"\n            )),\n        ))?;\n\n        // Get the common ancestor block\n        let common_block =\n            self.backend.get_block(common_height).ok_or(BlockchainError::BlockNotFound)?;\n\n        self.backend.rollback(common_block).await?;\n        Ok(())\n    }\n\n    /// Estimates the gas usage of the `request` with the state.\n    ///\n    /// This will execute the transaction request and find the best gas limit via binary search.\n    fn do_estimate_gas_with_state(\n        &self,\n        mut request: WithOtherFields<TransactionRequest>,\n        state: &dyn DatabaseRef,\n        block_env: BlockEnv,\n    ) -> Result<u128> {\n        // If the request is a simple native token transfer we can optimize\n        // We assume it's a transfer if we have no input data.\n        let to = request.to.as_ref().and_then(TxKind::to);\n\n        // check certain fields to see if the request could be a simple transfer\n        let maybe_transfer = (request.input.input().is_none()\n            || request.input.input().is_some_and(|data| data.is_empty()))\n            && request.authorization_list.is_none()\n            && request.access_list.is_none()\n            && request.blob_versioned_hashes.is_none();\n\n        if maybe_transfer\n            && let Some(to) = to\n            && let Ok(target_code) = self.backend.get_code_with_state(&state, *to)\n            && target_code.as_ref().is_empty()\n        {\n            return Ok(MIN_TRANSACTION_GAS);\n        }\n\n        let fees = FeeDetails::new(\n            request.gas_price,\n            request.max_fee_per_gas,\n            request.max_priority_fee_per_gas,\n            request.max_fee_per_blob_gas,\n        )?\n        .or_zero_fees();\n\n        // get the highest possible gas limit, either the request's set value or the currently\n        // configured gas limit\n        let mut highest_gas_limit = request.gas.map_or(block_env.gas_limit.into(), |g| g as u128);\n\n        let gas_price = fees.gas_price.unwrap_or_default();\n        // If we have non-zero gas price, cap gas limit by sender balance\n        if gas_price > 0\n            && let Some(from) = request.from\n        {\n            let mut available_funds = self.backend.get_balance_with_state(state, from)?;\n            if let Some(value) = request.value {\n                if value > available_funds {\n                    return Err(InvalidTransactionError::InsufficientFunds.into());\n                }\n                // safe: value < available_funds\n                available_funds -= value;\n            }\n            // amount of gas the sender can afford with the `gas_price`\n            let allowance = available_funds.checked_div(U256::from(gas_price)).unwrap_or_default();\n            highest_gas_limit = std::cmp::min(highest_gas_limit, allowance.saturating_to());\n        }\n\n        let mut call_to_estimate = request.clone();\n        call_to_estimate.gas = Some(highest_gas_limit as u64);\n\n        // execute the call without writing to db\n        let ethres =\n            self.backend.call_with_state(&state, call_to_estimate, fees.clone(), block_env.clone());\n\n        let gas_used = match ethres.try_into()? {\n            GasEstimationCallResult::Success(gas) => Ok(gas),\n            GasEstimationCallResult::OutOfGas => {\n                Err(InvalidTransactionError::BasicOutOfGas(highest_gas_limit).into())\n            }\n            GasEstimationCallResult::Revert(output) => {\n                Err(InvalidTransactionError::Revert(output).into())\n            }\n            GasEstimationCallResult::EvmError(err) => {\n                warn!(target: \"node\", \"estimation failed due to {:?}\", err);\n                Err(BlockchainError::EvmError(err))\n            }\n        }?;\n\n        // at this point we know the call succeeded but want to find the _best_ (lowest) gas the\n        // transaction succeeds with. we find this by doing a binary search over the\n        // possible range NOTE: this is the gas the transaction used, which is less than the\n        // transaction requires to succeed\n\n        // Get the starting lowest gas needed depending on the transaction kind.\n        let mut lowest_gas_limit = determine_base_gas_by_kind(&request);\n\n        // pick a point that's close to the estimated gas\n        let mut mid_gas_limit =\n            std::cmp::min(gas_used * 3, (highest_gas_limit + lowest_gas_limit) / 2);\n\n        // Binary search for the ideal gas limit\n        while (highest_gas_limit - lowest_gas_limit) > 1 {\n            request.gas = Some(mid_gas_limit as u64);\n            let ethres = self.backend.call_with_state(\n                &state,\n                request.clone(),\n                fees.clone(),\n                block_env.clone(),\n            );\n\n            match ethres.try_into()? {\n                GasEstimationCallResult::Success(_) => {\n                    // If the transaction succeeded, we can set a ceiling for the highest gas limit\n                    // at the current midpoint, as spending any more gas would\n                    // make no sense (as the TX would still succeed).\n                    highest_gas_limit = mid_gas_limit;\n                }\n                GasEstimationCallResult::OutOfGas\n                | GasEstimationCallResult::Revert(_)\n                | GasEstimationCallResult::EvmError(_) => {\n                    // If the transaction failed, we can set a floor for the lowest gas limit at the\n                    // current midpoint, as spending any less gas would make no\n                    // sense (as the TX would still revert due to lack of gas).\n                    //\n                    // We don't care about the reason here, as we known that transaction is correct\n                    // as it succeeded earlier\n                    lowest_gas_limit = mid_gas_limit;\n                }\n            };\n            // new midpoint\n            mid_gas_limit = (highest_gas_limit + lowest_gas_limit) / 2;\n        }\n\n        trace!(target : \"node\", \"Estimated Gas for call {:?}\", highest_gas_limit);\n\n        Ok(highest_gas_limit)\n    }\n\n    /// Returns a new block event stream that yields Notifications when a new block was added\n    pub fn new_block_notifications(&self) -> NewBlockNotifications {\n        self.backend.new_block_notifications()\n    }\n\n    /// Executes the [EthRequest] and returns an RPC [ResponseResult].\n    pub async fn execute(&self, request: EthRequest) -> ResponseResult {\n        trace!(target: \"rpc::api\", \"executing eth request\");\n        let response = match request.clone() {\n            EthRequest::EthProtocolVersion(()) => self.protocol_version().to_rpc_result(),\n            EthRequest::Web3ClientVersion(()) => self.client_version().to_rpc_result(),\n            EthRequest::Web3Sha3(content) => self.sha3(content).to_rpc_result(),\n            EthRequest::EthGetAccount(addr, block) => {\n                self.get_account(addr, block).await.to_rpc_result()\n            }\n            EthRequest::EthGetAccountInfo(addr, block) => {\n                self.get_account_info(addr, block).await.to_rpc_result()\n            }\n            EthRequest::EthGetBalance(addr, block) => {\n                self.balance(addr, block).await.to_rpc_result()\n            }\n            EthRequest::EthGetTransactionByHash(hash) => {\n                self.transaction_by_hash(hash).await.to_rpc_result()\n            }\n            EthRequest::EthSendTransaction(request) => {\n                self.send_transaction(*request).await.to_rpc_result()\n            }\n            EthRequest::EthSendTransactionSync(request) => {\n                self.send_transaction_sync(*request).await.to_rpc_result()\n            }\n            EthRequest::EthChainId(_) => self.eth_chain_id().to_rpc_result(),\n            EthRequest::EthNetworkId(_) => self.network_id().to_rpc_result(),\n            EthRequest::NetListening(_) => self.net_listening().to_rpc_result(),\n            EthRequest::EthHashrate(()) => self.hashrate().to_rpc_result(),\n            EthRequest::EthGasPrice(_) => self.eth_gas_price().to_rpc_result(),\n            EthRequest::EthMaxPriorityFeePerGas(_) => {\n                self.gas_max_priority_fee_per_gas().to_rpc_result()\n            }\n            EthRequest::EthBlobBaseFee(_) => self.blob_base_fee().to_rpc_result(),\n            EthRequest::EthAccounts(_) => self.accounts().to_rpc_result(),\n            EthRequest::EthBlockNumber(_) => self.block_number().to_rpc_result(),\n            EthRequest::EthCoinbase(()) => self.author().to_rpc_result(),\n            EthRequest::EthGetStorageAt(addr, slot, block) => {\n                self.storage_at(addr, slot, block).await.to_rpc_result()\n            }\n            EthRequest::EthGetBlockByHash(hash, full) => {\n                if full {\n                    self.block_by_hash_full(hash).await.to_rpc_result()\n                } else {\n                    self.block_by_hash(hash).await.to_rpc_result()\n                }\n            }\n            EthRequest::EthGetBlockByNumber(num, full) => {\n                if full {\n                    self.block_by_number_full(num).await.to_rpc_result()\n                } else {\n                    self.block_by_number(num).await.to_rpc_result()\n                }\n            }\n            EthRequest::EthGetTransactionCount(addr, block) => {\n                self.transaction_count(addr, block).await.to_rpc_result()\n            }\n            EthRequest::EthGetTransactionCountByHash(hash) => {\n                self.block_transaction_count_by_hash(hash).await.to_rpc_result()\n            }\n            EthRequest::EthGetTransactionCountByNumber(num) => {\n                self.block_transaction_count_by_number(num).await.to_rpc_result()\n            }\n            EthRequest::EthGetUnclesCountByHash(hash) => {\n                self.block_uncles_count_by_hash(hash).await.to_rpc_result()\n            }\n            EthRequest::EthGetUnclesCountByNumber(num) => {\n                self.block_uncles_count_by_number(num).await.to_rpc_result()\n            }\n            EthRequest::EthGetCodeAt(addr, block) => {\n                self.get_code(addr, block).await.to_rpc_result()\n            }\n            EthRequest::EthGetProof(addr, keys, block) => {\n                self.get_proof(addr, keys, block).await.to_rpc_result()\n            }\n            EthRequest::EthSign(addr, content) => self.sign(addr, content).await.to_rpc_result(),\n            EthRequest::PersonalSign(content, addr) => {\n                self.sign(addr, content).await.to_rpc_result()\n            }\n            EthRequest::EthSignTransaction(request) => {\n                self.sign_transaction(*request).await.to_rpc_result()\n            }\n            EthRequest::EthSignTypedData(addr, data) => {\n                self.sign_typed_data(addr, data).await.to_rpc_result()\n            }\n            EthRequest::EthSignTypedDataV3(addr, data) => {\n                self.sign_typed_data_v3(addr, data).await.to_rpc_result()\n            }\n            EthRequest::EthSignTypedDataV4(addr, data) => {\n                self.sign_typed_data_v4(addr, &data).await.to_rpc_result()\n            }\n            EthRequest::EthSendRawTransaction(tx) => {\n                self.send_raw_transaction(tx).await.to_rpc_result()\n            }\n            EthRequest::EthSendRawTransactionSync(tx) => {\n                self.send_raw_transaction_sync(tx).await.to_rpc_result()\n            }\n            EthRequest::EthCall(call, block, state_override, block_overrides) => self\n                .call(call, block, EvmOverrides::new(state_override, block_overrides))\n                .await\n                .to_rpc_result(),\n            EthRequest::EthSimulateV1(simulation, block) => {\n                self.simulate_v1(simulation, block).await.to_rpc_result()\n            }\n            EthRequest::EthCreateAccessList(call, block) => {\n                self.create_access_list(call, block).await.to_rpc_result()\n            }\n            EthRequest::EthEstimateGas(call, block, state_override, block_overrides) => self\n                .estimate_gas(call, block, EvmOverrides::new(state_override, block_overrides))\n                .await\n                .to_rpc_result(),\n            EthRequest::EthFillTransaction(request) => {\n                self.fill_transaction(request).await.to_rpc_result()\n            }\n            EthRequest::EthGetRawTransactionByHash(hash) => {\n                self.raw_transaction(hash).await.to_rpc_result()\n            }\n            EthRequest::GetBlobByHash(hash) => {\n                self.anvil_get_blob_by_versioned_hash(hash).to_rpc_result()\n            }\n            EthRequest::GetBlobByTransactionHash(hash) => {\n                self.anvil_get_blob_by_tx_hash(hash).to_rpc_result()\n            }\n            EthRequest::GetGenesisTime(()) => self.anvil_get_genesis_time().to_rpc_result(),\n            EthRequest::EthGetRawTransactionByBlockHashAndIndex(hash, index) => {\n                self.raw_transaction_by_block_hash_and_index(hash, index).await.to_rpc_result()\n            }\n            EthRequest::EthGetRawTransactionByBlockNumberAndIndex(num, index) => {\n                self.raw_transaction_by_block_number_and_index(num, index).await.to_rpc_result()\n            }\n            EthRequest::EthGetTransactionByBlockHashAndIndex(hash, index) => {\n                self.transaction_by_block_hash_and_index(hash, index).await.to_rpc_result()\n            }\n            EthRequest::EthGetTransactionByBlockNumberAndIndex(num, index) => {\n                self.transaction_by_block_number_and_index(num, index).await.to_rpc_result()\n            }\n            EthRequest::EthGetTransactionReceipt(tx) => {\n                self.transaction_receipt(tx).await.to_rpc_result()\n            }\n            EthRequest::EthGetBlockReceipts(number) => {\n                self.block_receipts(number).await.to_rpc_result()\n            }\n            EthRequest::EthGetUncleByBlockHashAndIndex(hash, index) => {\n                self.uncle_by_block_hash_and_index(hash, index).await.to_rpc_result()\n            }\n            EthRequest::EthGetUncleByBlockNumberAndIndex(num, index) => {\n                self.uncle_by_block_number_and_index(num, index).await.to_rpc_result()\n            }\n            EthRequest::EthGetLogs(filter) => self.logs(filter).await.to_rpc_result(),\n            EthRequest::EthGetWork(_) => self.work().to_rpc_result(),\n            EthRequest::EthSyncing(_) => self.syncing().to_rpc_result(),\n            EthRequest::EthConfig(_) => self.config().to_rpc_result(),\n            EthRequest::EthSubmitWork(nonce, pow, digest) => {\n                self.submit_work(nonce, pow, digest).to_rpc_result()\n            }\n            EthRequest::EthSubmitHashRate(rate, id) => {\n                self.submit_hashrate(rate, id).to_rpc_result()\n            }\n            EthRequest::EthFeeHistory(count, newest, reward_percentiles) => {\n                self.fee_history(count, newest, reward_percentiles).await.to_rpc_result()\n            }\n            // non eth-standard rpc calls\n            EthRequest::DebugGetRawTransaction(hash) => {\n                self.raw_transaction(hash).await.to_rpc_result()\n            }\n            // non eth-standard rpc calls\n            EthRequest::DebugTraceTransaction(tx, opts) => {\n                self.debug_trace_transaction(tx, opts).await.to_rpc_result()\n            }\n            // non eth-standard rpc calls\n            EthRequest::DebugTraceCall(tx, block, opts) => {\n                self.debug_trace_call(tx, block, opts).await.to_rpc_result()\n            }\n            EthRequest::DebugCodeByHash(hash, block) => {\n                self.debug_code_by_hash(hash, block).await.to_rpc_result()\n            }\n            EthRequest::DebugDbGet(key) => self.debug_db_get(key).await.to_rpc_result(),\n            EthRequest::TraceTransaction(tx) => self.trace_transaction(tx).await.to_rpc_result(),\n            EthRequest::TraceBlock(block) => self.trace_block(block).await.to_rpc_result(),\n            EthRequest::TraceFilter(filter) => self.trace_filter(filter).await.to_rpc_result(),\n            EthRequest::TraceReplayBlockTransactions(block, trace_types) => {\n                self.trace_replay_block_transactions(block, trace_types).await.to_rpc_result()\n            }\n            EthRequest::ImpersonateAccount(addr) => {\n                self.anvil_impersonate_account(addr).await.to_rpc_result()\n            }\n            EthRequest::StopImpersonatingAccount(addr) => {\n                self.anvil_stop_impersonating_account(addr).await.to_rpc_result()\n            }\n            EthRequest::AutoImpersonateAccount(enable) => {\n                self.anvil_auto_impersonate_account(enable).await.to_rpc_result()\n            }\n            EthRequest::ImpersonateSignature(signature, address) => {\n                self.anvil_impersonate_signature(signature, address).await.to_rpc_result()\n            }\n            EthRequest::GetAutoMine(()) => self.anvil_get_auto_mine().to_rpc_result(),\n            EthRequest::Mine(blocks, interval) => {\n                self.anvil_mine(blocks, interval).await.to_rpc_result()\n            }\n            EthRequest::SetAutomine(enabled) => {\n                self.anvil_set_auto_mine(enabled).await.to_rpc_result()\n            }\n            EthRequest::SetIntervalMining(interval) => {\n                self.anvil_set_interval_mining(interval).to_rpc_result()\n            }\n            EthRequest::GetIntervalMining(()) => self.anvil_get_interval_mining().to_rpc_result(),\n            EthRequest::DropTransaction(tx) => {\n                self.anvil_drop_transaction(tx).await.to_rpc_result()\n            }\n            EthRequest::DropAllTransactions() => {\n                self.anvil_drop_all_transactions().await.to_rpc_result()\n            }\n            EthRequest::Reset(fork) => {\n                self.anvil_reset(fork.and_then(|p| p.params)).await.to_rpc_result()\n            }\n            EthRequest::SetBalance(addr, val) => {\n                self.anvil_set_balance(addr, val).await.to_rpc_result()\n            }\n            EthRequest::AddBalance(addr, val) => {\n                self.anvil_add_balance(addr, val).await.to_rpc_result()\n            }\n            EthRequest::DealERC20(addr, token_addr, val) => {\n                self.anvil_deal_erc20(addr, token_addr, val).await.to_rpc_result()\n            }\n            EthRequest::SetERC20Allowance(owner, spender, token_addr, val) => self\n                .anvil_set_erc20_allowance(owner, spender, token_addr, val)\n                .await\n                .to_rpc_result(),\n            EthRequest::SetCode(addr, code) => {\n                self.anvil_set_code(addr, code).await.to_rpc_result()\n            }\n            EthRequest::SetNonce(addr, nonce) => {\n                self.anvil_set_nonce(addr, nonce).await.to_rpc_result()\n            }\n            EthRequest::SetStorageAt(addr, slot, val) => {\n                self.anvil_set_storage_at(addr, slot, val).await.to_rpc_result()\n            }\n            EthRequest::SetCoinbase(addr) => self.anvil_set_coinbase(addr).await.to_rpc_result(),\n            EthRequest::SetChainId(id) => self.anvil_set_chain_id(id).await.to_rpc_result(),\n            EthRequest::SetLogging(log) => self.anvil_set_logging(log).await.to_rpc_result(),\n            EthRequest::SetMinGasPrice(gas) => {\n                self.anvil_set_min_gas_price(gas).await.to_rpc_result()\n            }\n            EthRequest::SetNextBlockBaseFeePerGas(gas) => {\n                self.anvil_set_next_block_base_fee_per_gas(gas).await.to_rpc_result()\n            }\n            EthRequest::DumpState(preserve_historical_states) => self\n                .anvil_dump_state(preserve_historical_states.and_then(|s| s.params))\n                .await\n                .to_rpc_result(),\n            EthRequest::LoadState(buf) => self.anvil_load_state(buf).await.to_rpc_result(),\n            EthRequest::NodeInfo(_) => self.anvil_node_info().await.to_rpc_result(),\n            EthRequest::AnvilMetadata(_) => self.anvil_metadata().await.to_rpc_result(),\n            EthRequest::EvmSnapshot(_) => self.evm_snapshot().await.to_rpc_result(),\n            EthRequest::EvmRevert(id) => self.evm_revert(id).await.to_rpc_result(),\n            EthRequest::EvmIncreaseTime(time) => self.evm_increase_time(time).await.to_rpc_result(),\n            EthRequest::EvmSetNextBlockTimeStamp(time) => {\n                if time >= U256::from(u64::MAX) {\n                    return ResponseResult::Error(RpcError::invalid_params(\n                        \"The timestamp is too big\",\n                    ));\n                }\n                let time = time.to::<u64>();\n                self.evm_set_next_block_timestamp(time).to_rpc_result()\n            }\n            EthRequest::EvmSetTime(timestamp) => {\n                if timestamp >= U256::from(u64::MAX) {\n                    return ResponseResult::Error(RpcError::invalid_params(\n                        \"The timestamp is too big\",\n                    ));\n                }\n                let time = timestamp.to::<u64>();\n                self.evm_set_time(time).to_rpc_result()\n            }\n            EthRequest::EvmSetBlockGasLimit(gas_limit) => {\n                self.evm_set_block_gas_limit(gas_limit).to_rpc_result()\n            }\n            EthRequest::EvmSetBlockTimeStampInterval(time) => {\n                self.evm_set_block_timestamp_interval(time).to_rpc_result()\n            }\n            EthRequest::EvmRemoveBlockTimeStampInterval(()) => {\n                self.evm_remove_block_timestamp_interval().to_rpc_result()\n            }\n            EthRequest::EvmMine(mine) => {\n                self.evm_mine(mine.and_then(|p| p.params)).await.to_rpc_result()\n            }\n            EthRequest::EvmMineDetailed(mine) => {\n                self.evm_mine_detailed(mine.and_then(|p| p.params)).await.to_rpc_result()\n            }\n            EthRequest::SetRpcUrl(url) => self.anvil_set_rpc_url(url).to_rpc_result(),\n            EthRequest::EthSendUnsignedTransaction(tx) => {\n                self.eth_send_unsigned_transaction(*tx).await.to_rpc_result()\n            }\n            EthRequest::EthNewFilter(filter) => self.new_filter(filter).await.to_rpc_result(),\n            EthRequest::EthGetFilterChanges(id) => self.get_filter_changes(&id).await,\n            EthRequest::EthNewBlockFilter(_) => self.new_block_filter().await.to_rpc_result(),\n            EthRequest::EthNewPendingTransactionFilter(_) => {\n                self.new_pending_transaction_filter().await.to_rpc_result()\n            }\n            EthRequest::EthGetFilterLogs(id) => self.get_filter_logs(&id).await.to_rpc_result(),\n            EthRequest::EthUninstallFilter(id) => self.uninstall_filter(&id).await.to_rpc_result(),\n            EthRequest::TxPoolStatus(_) => self.txpool_status().await.to_rpc_result(),\n            EthRequest::TxPoolInspect(_) => self.txpool_inspect().await.to_rpc_result(),\n            EthRequest::TxPoolContent(_) => self.txpool_content().await.to_rpc_result(),\n            EthRequest::ErigonGetHeaderByNumber(num) => {\n                self.erigon_get_header_by_number(num).await.to_rpc_result()\n            }\n            EthRequest::OtsGetApiLevel(_) => self.ots_get_api_level().await.to_rpc_result(),\n            EthRequest::OtsGetInternalOperations(hash) => {\n                self.ots_get_internal_operations(hash).await.to_rpc_result()\n            }\n            EthRequest::OtsHasCode(addr, num) => self.ots_has_code(addr, num).await.to_rpc_result(),\n            EthRequest::OtsTraceTransaction(hash) => {\n                self.ots_trace_transaction(hash).await.to_rpc_result()\n            }\n            EthRequest::OtsGetTransactionError(hash) => {\n                self.ots_get_transaction_error(hash).await.to_rpc_result()\n            }\n            EthRequest::OtsGetBlockDetails(num) => {\n                self.ots_get_block_details(num).await.to_rpc_result()\n            }\n            EthRequest::OtsGetBlockDetailsByHash(hash) => {\n                self.ots_get_block_details_by_hash(hash).await.to_rpc_result()\n            }\n            EthRequest::OtsGetBlockTransactions(num, page, page_size) => {\n                self.ots_get_block_transactions(num, page, page_size).await.to_rpc_result()\n            }\n            EthRequest::OtsSearchTransactionsBefore(address, num, page_size) => {\n                self.ots_search_transactions_before(address, num, page_size).await.to_rpc_result()\n            }\n            EthRequest::OtsSearchTransactionsAfter(address, num, page_size) => {\n                self.ots_search_transactions_after(address, num, page_size).await.to_rpc_result()\n            }\n            EthRequest::OtsGetTransactionBySenderAndNonce(address, nonce) => {\n                self.ots_get_transaction_by_sender_and_nonce(address, nonce).await.to_rpc_result()\n            }\n            EthRequest::EthGetTransactionBySenderAndNonce(sender, nonce) => {\n                self.transaction_by_sender_and_nonce(sender, nonce).await.to_rpc_result()\n            }\n            EthRequest::OtsGetContractCreator(address) => {\n                self.ots_get_contract_creator(address).await.to_rpc_result()\n            }\n            EthRequest::RemovePoolTransactions(address) => {\n                self.anvil_remove_pool_transactions(address).await.to_rpc_result()\n            }\n            EthRequest::Reorg(reorg_options) => {\n                self.anvil_reorg(reorg_options).await.to_rpc_result()\n            }\n            EthRequest::Rollback(depth) => self.anvil_rollback(depth).await.to_rpc_result(),\n        };\n\n        if let ResponseResult::Error(err) = &response {\n            node_info!(\"\\nRPC request failed:\");\n            node_info!(\"    Request: {:?}\", request);\n            node_info!(\"    Error: {}\\n\", err);\n        }\n\n        response\n    }\n\n    fn sign_request(&self, from: &Address, typed_tx: FoundryTypedTx) -> Result<FoundryTxEnvelope> {\n        match typed_tx {\n            FoundryTypedTx::Deposit(_) => return Ok(build_impersonated(typed_tx)),\n            _ => {\n                for signer in self.signers.iter() {\n                    if signer.accounts().contains(from) {\n                        return signer.sign_transaction_from(from, typed_tx);\n                    }\n                }\n            }\n        }\n        Err(BlockchainError::NoSignerAvailable)\n    }\n\n    async fn inner_raw_transaction(&self, hash: B256) -> Result<Option<Bytes>> {\n        match self.pool.get_transaction(hash) {\n            Some(tx) => Ok(Some(tx.transaction.encoded_2718().into())),\n            None => match self.backend.transaction_by_hash(hash).await? {\n                Some(tx) => Ok(Some(tx.as_ref().encoded_2718().into())),\n                None => Ok(None),\n            },\n        }\n    }\n\n    /// Returns the current client version.\n    ///\n    /// Handler for ETH RPC call: `web3_clientVersion`\n    pub fn client_version(&self) -> Result<String> {\n        node_info!(\"web3_clientVersion\");\n        Ok(CLIENT_VERSION.to_string())\n    }\n\n    /// Returns Keccak-256 (not the standardized SHA3-256) of the given data.\n    ///\n    /// Handler for ETH RPC call: `web3_sha3`\n    pub fn sha3(&self, bytes: Bytes) -> Result<String> {\n        node_info!(\"web3_sha3\");\n        let hash = alloy_primitives::keccak256(bytes.as_ref());\n        Ok(alloy_primitives::hex::encode_prefixed(&hash[..]))\n    }\n\n    /// Returns protocol version encoded as a string (quotes are necessary).\n    ///\n    /// Handler for ETH RPC call: `eth_protocolVersion`\n    pub fn protocol_version(&self) -> Result<u64> {\n        node_info!(\"eth_protocolVersion\");\n        Ok(1)\n    }\n\n    /// Returns the number of hashes per second that the node is mining with.\n    ///\n    /// Handler for ETH RPC call: `eth_hashrate`\n    pub fn hashrate(&self) -> Result<U256> {\n        node_info!(\"eth_hashrate\");\n        Ok(U256::ZERO)\n    }\n\n    /// Returns the client coinbase address.\n    ///\n    /// Handler for ETH RPC call: `eth_coinbase`\n    pub fn author(&self) -> Result<Address> {\n        node_info!(\"eth_coinbase\");\n        Ok(self.backend.coinbase())\n    }\n\n    /// Returns true if client is actively mining new blocks.\n    ///\n    /// Handler for ETH RPC call: `eth_mining`\n    pub fn is_mining(&self) -> Result<bool> {\n        node_info!(\"eth_mining\");\n        Ok(self.is_mining)\n    }\n\n    /// Returns the chain ID used for transaction signing at the\n    /// current best block. None is returned if not\n    /// available.\n    ///\n    /// Handler for ETH RPC call: `eth_chainId`\n    pub fn eth_chain_id(&self) -> Result<Option<U64>> {\n        node_info!(\"eth_chainId\");\n        Ok(Some(self.backend.chain_id().to::<U64>()))\n    }\n\n    /// Returns the same as `chain_id`\n    ///\n    /// Handler for ETH RPC call: `eth_networkId`\n    pub fn network_id(&self) -> Result<Option<String>> {\n        node_info!(\"eth_networkId\");\n        let chain_id = self.backend.chain_id().to::<u64>();\n        Ok(Some(format!(\"{chain_id}\")))\n    }\n\n    /// Returns true if client is actively listening for network connections.\n    ///\n    /// Handler for ETH RPC call: `net_listening`\n    pub fn net_listening(&self) -> Result<bool> {\n        node_info!(\"net_listening\");\n        Ok(self.net_listening)\n    }\n\n    /// Returns the current gas price\n    fn eth_gas_price(&self) -> Result<U256> {\n        node_info!(\"eth_gasPrice\");\n        Ok(U256::from(self.gas_price()))\n    }\n\n    /// Returns the excess blob gas and current blob gas price\n    pub fn excess_blob_gas_and_price(&self) -> Result<Option<BlobExcessGasAndPrice>> {\n        Ok(self.backend.excess_blob_gas_and_price())\n    }\n\n    /// Returns a fee per gas that is an estimate of how much you can pay as a priority fee, or\n    /// 'tip', to get a transaction included in the current block.\n    ///\n    /// Handler for ETH RPC call: `eth_maxPriorityFeePerGas`\n    pub fn gas_max_priority_fee_per_gas(&self) -> Result<U256> {\n        self.max_priority_fee_per_gas()\n    }\n\n    /// Returns the base fee per blob required to send a EIP-4844 tx.\n    ///\n    /// Handler for ETH RPC call: `eth_blobBaseFee`\n    pub fn blob_base_fee(&self) -> Result<U256> {\n        Ok(U256::from(self.backend.fees().base_fee_per_blob_gas()))\n    }\n\n    /// Returns the block gas limit\n    pub fn gas_limit(&self) -> U256 {\n        U256::from(self.backend.gas_limit())\n    }\n\n    /// Returns the accounts list\n    ///\n    /// Handler for ETH RPC call: `eth_accounts`\n    pub fn accounts(&self) -> Result<Vec<Address>> {\n        node_info!(\"eth_accounts\");\n        let mut unique = HashSet::new();\n        let mut accounts: Vec<Address> = Vec::new();\n        for signer in self.signers.iter() {\n            accounts.extend(signer.accounts().into_iter().filter(|acc| unique.insert(*acc)));\n        }\n        accounts.extend(\n            self.backend\n                .cheats()\n                .impersonated_accounts()\n                .into_iter()\n                .filter(|acc| unique.insert(*acc)),\n        );\n        Ok(accounts.into_iter().collect())\n    }\n\n    /// Returns the number of most recent block.\n    ///\n    /// Handler for ETH RPC call: `eth_blockNumber`\n    pub fn block_number(&self) -> Result<U256> {\n        node_info!(\"eth_blockNumber\");\n        Ok(U256::from(self.backend.best_number()))\n    }\n\n    /// Returns balance of the given account.\n    ///\n    /// Handler for ETH RPC call: `eth_getBalance`\n    pub async fn balance(&self, address: Address, block_number: Option<BlockId>) -> Result<U256> {\n        node_info!(\"eth_getBalance\");\n        let block_request = self.block_request(block_number).await?;\n\n        // check if the number predates the fork, if in fork mode\n        if let BlockRequest::Number(number) = block_request\n            && let Some(fork) = self.get_fork()\n            && fork.predates_fork(number)\n        {\n            return Ok(fork.get_balance(address, number).await?);\n        }\n\n        self.backend.get_balance(address, Some(block_request)).await\n    }\n\n    /// Returns the ethereum account.\n    ///\n    /// Handler for ETH RPC call: `eth_getAccount`\n    pub async fn get_account(\n        &self,\n        address: Address,\n        block_number: Option<BlockId>,\n    ) -> Result<TrieAccount> {\n        node_info!(\"eth_getAccount\");\n        let block_request = self.block_request(block_number).await?;\n\n        // check if the number predates the fork, if in fork mode\n        if let BlockRequest::Number(number) = block_request\n            && let Some(fork) = self.get_fork()\n            && fork.predates_fork(number)\n        {\n            return Ok(fork.get_account(address, number).await?);\n        }\n\n        self.backend.get_account_at_block(address, Some(block_request)).await\n    }\n\n    /// Returns the account information including balance, nonce, code and storage\n    ///\n    /// Note: This isn't support by all providers\n    pub async fn get_account_info(\n        &self,\n        address: Address,\n        block_number: Option<BlockId>,\n    ) -> Result<alloy_rpc_types::eth::AccountInfo> {\n        node_info!(\"eth_getAccountInfo\");\n\n        if let Some(fork) = self.get_fork() {\n            let block_request = self.block_request(block_number).await?;\n            // check if the number predates the fork, if in fork mode\n            if let BlockRequest::Number(number) = block_request {\n                trace!(target: \"node\", \"get_account_info: fork block {}, requested block {number}\", fork.block_number());\n                return if fork.predates_fork(number) {\n                    // if this predates the fork we need to fetch balance, nonce, code individually\n                    // because the provider might not support this endpoint\n                    let balance = fork.get_balance(address, number).map_err(BlockchainError::from);\n                    let code = fork.get_code(address, number).map_err(BlockchainError::from);\n                    let nonce = self.get_transaction_count(address, Some(number.into()));\n                    let (balance, code, nonce) = try_join!(balance, code, nonce)?;\n\n                    Ok(alloy_rpc_types::eth::AccountInfo { balance, nonce, code })\n                } else {\n                    // Anvil node is at the same block or higher than the fork block,\n                    // return account info from backend to reflect current state.\n                    let account_info = self.backend.get_account(address).await?;\n                    let code = self.backend.get_code(address, Some(block_request)).await?;\n                    Ok(alloy_rpc_types::eth::AccountInfo {\n                        balance: account_info.balance,\n                        nonce: account_info.nonce,\n                        code,\n                    })\n                };\n            }\n        }\n\n        let account = self.get_account(address, block_number);\n        let code = self.get_code(address, block_number);\n        let (account, code) = try_join!(account, code)?;\n        Ok(alloy_rpc_types::eth::AccountInfo {\n            balance: account.balance,\n            nonce: account.nonce,\n            code,\n        })\n    }\n    /// Returns content of the storage at given address.\n    ///\n    /// Handler for ETH RPC call: `eth_getStorageAt`\n    pub async fn storage_at(\n        &self,\n        address: Address,\n        index: U256,\n        block_number: Option<BlockId>,\n    ) -> Result<B256> {\n        node_info!(\"eth_getStorageAt\");\n        let block_request = self.block_request(block_number).await?;\n\n        // check if the number predates the fork, if in fork mode\n        if let BlockRequest::Number(number) = block_request\n            && let Some(fork) = self.get_fork()\n            && fork.predates_fork(number)\n        {\n            return Ok(B256::from(\n                fork.storage_at(address, index, Some(BlockNumber::Number(number))).await?,\n            ));\n        }\n\n        self.backend.storage_at(address, index, Some(block_request)).await\n    }\n\n    /// Returns block with given hash.\n    ///\n    /// Handler for ETH RPC call: `eth_getBlockByHash`\n    pub async fn block_by_hash(&self, hash: B256) -> Result<Option<AnyRpcBlock>> {\n        node_info!(\"eth_getBlockByHash\");\n        self.backend.block_by_hash(hash).await\n    }\n\n    /// Returns a _full_ block with given hash.\n    ///\n    /// Handler for ETH RPC call: `eth_getBlockByHash`\n    pub async fn block_by_hash_full(&self, hash: B256) -> Result<Option<AnyRpcBlock>> {\n        node_info!(\"eth_getBlockByHash\");\n        self.backend.block_by_hash_full(hash).await\n    }\n\n    /// Returns block with given number.\n    ///\n    /// Handler for ETH RPC call: `eth_getBlockByNumber`\n    pub async fn block_by_number(&self, number: BlockNumber) -> Result<Option<AnyRpcBlock>> {\n        node_info!(\"eth_getBlockByNumber\");\n        if number == BlockNumber::Pending {\n            return Ok(Some(self.pending_block().await));\n        }\n\n        self.backend.block_by_number(number).await\n    }\n\n    /// Returns a _full_ block with given number\n    ///\n    /// Handler for ETH RPC call: `eth_getBlockByNumber`\n    pub async fn block_by_number_full(&self, number: BlockNumber) -> Result<Option<AnyRpcBlock>> {\n        node_info!(\"eth_getBlockByNumber\");\n        if number == BlockNumber::Pending {\n            return Ok(self.pending_block_full().await);\n        }\n        self.backend.block_by_number_full(number).await\n    }\n\n    /// Returns the number of transactions sent from given address at given time (block number).\n    ///\n    /// Also checks the pending transactions if `block_number` is\n    /// `BlockId::Number(BlockNumber::Pending)`\n    ///\n    /// Handler for ETH RPC call: `eth_getTransactionCount`\n    pub async fn transaction_count(\n        &self,\n        address: Address,\n        block_number: Option<BlockId>,\n    ) -> Result<U256> {\n        node_info!(\"eth_getTransactionCount\");\n        self.get_transaction_count(address, block_number).await.map(U256::from)\n    }\n\n    /// Returns the number of transactions in a block with given hash.\n    ///\n    /// Handler for ETH RPC call: `eth_getBlockTransactionCountByHash`\n    pub async fn block_transaction_count_by_hash(&self, hash: B256) -> Result<Option<U256>> {\n        node_info!(\"eth_getBlockTransactionCountByHash\");\n        let block = self.backend.block_by_hash(hash).await?;\n        let txs = block.map(|b| match b.transactions() {\n            BlockTransactions::Full(txs) => U256::from(txs.len()),\n            BlockTransactions::Hashes(txs) => U256::from(txs.len()),\n            BlockTransactions::Uncle => U256::from(0),\n        });\n        Ok(txs)\n    }\n\n    /// Returns the number of transactions in a block with given block number.\n    ///\n    /// Handler for ETH RPC call: `eth_getBlockTransactionCountByNumber`\n    pub async fn block_transaction_count_by_number(\n        &self,\n        block_number: BlockNumber,\n    ) -> Result<Option<U256>> {\n        node_info!(\"eth_getBlockTransactionCountByNumber\");\n        let block_request = self.block_request(Some(block_number.into())).await?;\n        if let BlockRequest::Pending(txs) = block_request {\n            let block = self.backend.pending_block(txs).await;\n            return Ok(Some(U256::from(block.block.body.transactions.len())));\n        }\n        let block = self.backend.block_by_number(block_number).await?;\n        let txs = block.map(|b| match b.transactions() {\n            BlockTransactions::Full(txs) => U256::from(txs.len()),\n            BlockTransactions::Hashes(txs) => U256::from(txs.len()),\n            BlockTransactions::Uncle => U256::from(0),\n        });\n        Ok(txs)\n    }\n\n    /// Returns the number of uncles in a block with given hash.\n    ///\n    /// Handler for ETH RPC call: `eth_getUncleCountByBlockHash`\n    pub async fn block_uncles_count_by_hash(&self, hash: B256) -> Result<U256> {\n        node_info!(\"eth_getUncleCountByBlockHash\");\n        let block =\n            self.backend.block_by_hash(hash).await?.ok_or(BlockchainError::BlockNotFound)?;\n        Ok(U256::from(block.uncles.len()))\n    }\n\n    /// Returns the number of uncles in a block with given block number.\n    ///\n    /// Handler for ETH RPC call: `eth_getUncleCountByBlockNumber`\n    pub async fn block_uncles_count_by_number(&self, block_number: BlockNumber) -> Result<U256> {\n        node_info!(\"eth_getUncleCountByBlockNumber\");\n        let block = self\n            .backend\n            .block_by_number(block_number)\n            .await?\n            .ok_or(BlockchainError::BlockNotFound)?;\n        Ok(U256::from(block.uncles.len()))\n    }\n\n    /// Returns the code at given address at given time (block number).\n    ///\n    /// Handler for ETH RPC call: `eth_getCode`\n    pub async fn get_code(&self, address: Address, block_number: Option<BlockId>) -> Result<Bytes> {\n        node_info!(\"eth_getCode\");\n        let block_request = self.block_request(block_number).await?;\n        // check if the number predates the fork, if in fork mode\n        if let BlockRequest::Number(number) = block_request\n            && let Some(fork) = self.get_fork()\n            && fork.predates_fork(number)\n        {\n            return Ok(fork.get_code(address, number).await?);\n        }\n        self.backend.get_code(address, Some(block_request)).await\n    }\n\n    /// Returns the account and storage values of the specified account including the Merkle-proof.\n    /// This call can be used to verify that the data you are pulling from is not tampered with.\n    ///\n    /// Handler for ETH RPC call: `eth_getProof`\n    pub async fn get_proof(\n        &self,\n        address: Address,\n        keys: Vec<B256>,\n        block_number: Option<BlockId>,\n    ) -> Result<EIP1186AccountProofResponse> {\n        node_info!(\"eth_getProof\");\n        let block_request = self.block_request(block_number).await?;\n\n        // If we're in forking mode, or still on the forked block (no blocks mined yet) then we can\n        // delegate the call.\n        if let BlockRequest::Number(number) = block_request\n            && let Some(fork) = self.get_fork()\n            && fork.predates_fork_inclusive(number)\n        {\n            return Ok(fork.get_proof(address, keys, Some(number.into())).await?);\n        }\n\n        let proof = self.backend.prove_account_at(address, keys, Some(block_request)).await?;\n        Ok(proof)\n    }\n\n    /// Signs data via [EIP-712](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-712.md).\n    ///\n    /// Handler for ETH RPC call: `eth_signTypedData`\n    pub async fn sign_typed_data(\n        &self,\n        _address: Address,\n        _data: serde_json::Value,\n    ) -> Result<String> {\n        node_info!(\"eth_signTypedData\");\n        Err(BlockchainError::RpcUnimplemented)\n    }\n\n    /// Signs data via [EIP-712](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-712.md).\n    ///\n    /// Handler for ETH RPC call: `eth_signTypedData_v3`\n    pub async fn sign_typed_data_v3(\n        &self,\n        _address: Address,\n        _data: serde_json::Value,\n    ) -> Result<String> {\n        node_info!(\"eth_signTypedData_v3\");\n        Err(BlockchainError::RpcUnimplemented)\n    }\n\n    /// Signs data via [EIP-712](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-712.md), and includes full support of arrays and recursive data structures.\n    ///\n    /// Handler for ETH RPC call: `eth_signTypedData_v4`\n    pub async fn sign_typed_data_v4(&self, address: Address, data: &TypedData) -> Result<String> {\n        node_info!(\"eth_signTypedData_v4\");\n        let signer = self.get_signer(address).ok_or(BlockchainError::NoSignerAvailable)?;\n        let signature = signer.sign_typed_data(address, data).await?;\n        let signature = alloy_primitives::hex::encode(signature.as_bytes());\n        Ok(format!(\"0x{signature}\"))\n    }\n\n    /// The sign method calculates an Ethereum specific signature\n    ///\n    /// Handler for ETH RPC call: `eth_sign`\n    pub async fn sign(&self, address: Address, content: impl AsRef<[u8]>) -> Result<String> {\n        node_info!(\"eth_sign\");\n        let signer = self.get_signer(address).ok_or(BlockchainError::NoSignerAvailable)?;\n        let signature =\n            alloy_primitives::hex::encode(signer.sign(address, content.as_ref()).await?.as_bytes());\n        Ok(format!(\"0x{signature}\"))\n    }\n\n    /// Signs a transaction\n    ///\n    /// Handler for ETH RPC call: `eth_signTransaction`\n    pub async fn sign_transaction(\n        &self,\n        request: WithOtherFields<TransactionRequest>,\n    ) -> Result<String> {\n        node_info!(\"eth_signTransaction\");\n\n        let from = request.from.map(Ok).unwrap_or_else(|| {\n            self.accounts()?.first().copied().ok_or(BlockchainError::NoSignerAvailable)\n        })?;\n\n        let (nonce, _) = self.request_nonce(&request, from).await?;\n\n        let request = self.build_tx_request(request, nonce).await?;\n\n        let signed_transaction = self.sign_request(&from, request)?.encoded_2718();\n        Ok(alloy_primitives::hex::encode_prefixed(signed_transaction))\n    }\n\n    /// Sends a transaction\n    ///\n    /// Handler for ETH RPC call: `eth_sendTransaction`\n    pub async fn send_transaction(\n        &self,\n        request: WithOtherFields<TransactionRequest>,\n    ) -> Result<TxHash> {\n        node_info!(\"eth_sendTransaction\");\n\n        let from = request.from.map(Ok).unwrap_or_else(|| {\n            self.accounts()?.first().copied().ok_or(BlockchainError::NoSignerAvailable)\n        })?;\n        let (nonce, on_chain_nonce) = self.request_nonce(&request, from).await?;\n\n        let typed_tx = self.build_tx_request(request, nonce).await?;\n\n        // if the sender is currently impersonated we need to \"bypass\" signing\n        let pending_transaction = if self.is_impersonated(from) {\n            let transaction = sign::build_impersonated(typed_tx);\n            self.ensure_typed_transaction_supported(&transaction)?;\n            trace!(target : \"node\", ?from, \"eth_sendTransaction: impersonating\");\n            PendingTransaction::with_impersonated(transaction, from)\n        } else {\n            let transaction = self.sign_request(&from, typed_tx)?;\n            self.ensure_typed_transaction_supported(&transaction)?;\n            PendingTransaction::new(transaction)?\n        };\n        // pre-validate\n        self.backend.validate_pool_transaction(&pending_transaction).await?;\n\n        let requires = required_marker(nonce, on_chain_nonce, from);\n        let provides = vec![to_marker(nonce, from)];\n        debug_assert!(requires != provides);\n\n        self.add_pending_transaction(pending_transaction, requires, provides)\n    }\n\n    /// Waits for a transaction to be included in a block and returns its receipt (no timeout).\n    async fn await_transaction_inclusion(&self, hash: TxHash) -> Result<FoundryTxReceipt> {\n        let mut stream = self.new_block_notifications();\n        // Check if the transaction is already included before listening for new blocks.\n        if let Some(receipt) = self.backend.transaction_receipt(hash).await? {\n            return Ok(receipt);\n        }\n        while let Some(notification) = stream.next().await {\n            if let Some(block) = self.backend.get_block_by_hash(notification.hash)\n                && block.body.transactions.iter().any(|tx| tx.hash() == hash)\n                && let Some(receipt) = self.backend.transaction_receipt(hash).await?\n            {\n                return Ok(receipt);\n            }\n        }\n\n        Err(BlockchainError::Message(\"Failed to await transaction inclusion\".to_string()))\n    }\n\n    /// Waits for a transaction to be included in a block and returns its receipt, with timeout.\n    async fn check_transaction_inclusion(&self, hash: TxHash) -> Result<FoundryTxReceipt> {\n        const TIMEOUT_DURATION: Duration = Duration::from_secs(30);\n        tokio::time::timeout(TIMEOUT_DURATION, self.await_transaction_inclusion(hash))\n            .await\n            .unwrap_or_else(|_elapsed| {\n                Err(BlockchainError::TransactionConfirmationTimeout {\n                    hash,\n                    duration: TIMEOUT_DURATION,\n                })\n            })\n    }\n\n    /// Sends a transaction and waits for receipt\n    ///\n    /// Handler for ETH RPC call: `eth_sendTransactionSync`\n    pub async fn send_transaction_sync(\n        &self,\n        request: WithOtherFields<TransactionRequest>,\n    ) -> Result<FoundryTxReceipt> {\n        node_info!(\"eth_sendTransactionSync\");\n        let hash = self.send_transaction(request).await?;\n\n        let receipt = self.check_transaction_inclusion(hash).await?;\n\n        Ok(receipt)\n    }\n\n    /// Sends signed transaction, returning its hash.\n    ///\n    /// Handler for ETH RPC call: `eth_sendRawTransaction`\n    pub async fn send_raw_transaction(&self, tx: Bytes) -> Result<TxHash> {\n        node_info!(\"eth_sendRawTransaction\");\n        let mut data = tx.as_ref();\n        if data.is_empty() {\n            return Err(BlockchainError::EmptyRawTransactionData);\n        }\n\n        let transaction = FoundryTxEnvelope::decode_2718(&mut data)\n            .map_err(|_| BlockchainError::FailedToDecodeSignedTransaction)?;\n\n        self.ensure_typed_transaction_supported(&transaction)?;\n\n        let pending_transaction = PendingTransaction::new(transaction)?;\n\n        // pre-validate\n        self.backend.validate_pool_transaction(&pending_transaction).await?;\n\n        let on_chain_nonce = self.backend.current_nonce(*pending_transaction.sender()).await?;\n        let from = *pending_transaction.sender();\n        let nonce = pending_transaction.transaction.nonce();\n        let requires = required_marker(nonce, on_chain_nonce, from);\n\n        let priority = self.transaction_priority(&pending_transaction.transaction);\n        let pool_transaction = PoolTransaction {\n            requires,\n            provides: vec![to_marker(nonce, *pending_transaction.sender())],\n            pending_transaction,\n            priority,\n        };\n\n        let tx = self.pool.add_transaction(pool_transaction)?;\n        trace!(target: \"node\", \"Added transaction: [{:?}] sender={:?}\", tx.hash(), from);\n        Ok(*tx.hash())\n    }\n\n    /// Sends signed transaction, returning its receipt.\n    ///\n    /// Handler for ETH RPC call: `eth_sendRawTransactionSync`\n    pub async fn send_raw_transaction_sync(&self, tx: Bytes) -> Result<FoundryTxReceipt> {\n        node_info!(\"eth_sendRawTransactionSync\");\n\n        let hash = self.send_raw_transaction(tx).await?;\n        let receipt = self.check_transaction_inclusion(hash).await?;\n\n        Ok(receipt)\n    }\n\n    /// Call contract, returning the output data.\n    ///\n    /// Handler for ETH RPC call: `eth_call`\n    pub async fn call(\n        &self,\n        request: WithOtherFields<TransactionRequest>,\n        block_number: Option<BlockId>,\n        overrides: EvmOverrides,\n    ) -> Result<Bytes> {\n        node_info!(\"eth_call\");\n        let block_request = self.block_request(block_number).await?;\n        // check if the number predates the fork, if in fork mode\n        if let BlockRequest::Number(number) = block_request\n            && let Some(fork) = self.get_fork()\n            && fork.predates_fork(number)\n        {\n            if overrides.has_state() || overrides.has_block() {\n                return Err(BlockchainError::EvmOverrideError(\n                    \"not available on past forked blocks\".to_string(),\n                ));\n            }\n            return Ok(fork.call(&request, Some(number.into())).await?);\n        }\n\n        let fees = FeeDetails::new(\n            request.gas_price,\n            request.max_fee_per_gas,\n            request.max_priority_fee_per_gas,\n            request.max_fee_per_blob_gas,\n        )?\n        .or_zero_fees();\n        // this can be blocking for a bit, especially in forking mode\n        // <https://github.com/foundry-rs/foundry/issues/6036>\n        self.on_blocking_task(|this| async move {\n            let (exit, out, gas, _) =\n                this.backend.call(request, fees, Some(block_request), overrides).await?;\n            trace!(target : \"node\", \"Call status {:?}, gas {}\", exit, gas);\n\n            ensure_return_ok(exit, &out)\n        })\n        .await\n    }\n\n    pub async fn simulate_v1(\n        &self,\n        request: SimulatePayload,\n        block_number: Option<BlockId>,\n    ) -> Result<Vec<SimulatedBlock<AnyRpcBlock>>> {\n        node_info!(\"eth_simulateV1\");\n        let block_request = self.block_request(block_number).await?;\n        // check if the number predates the fork, if in fork mode\n        if let BlockRequest::Number(number) = block_request\n            && let Some(fork) = self.get_fork()\n            && fork.predates_fork(number)\n        {\n            return Ok(fork.simulate_v1(&request, Some(number.into())).await?);\n        }\n\n        // this can be blocking for a bit, especially in forking mode\n        // <https://github.com/foundry-rs/foundry/issues/6036>\n        self.on_blocking_task(|this| async move {\n            let simulated_blocks = this.backend.simulate(request, Some(block_request)).await?;\n            trace!(target : \"node\", \"Simulate status {:?}\", simulated_blocks);\n\n            Ok(simulated_blocks)\n        })\n        .await\n    }\n\n    /// This method creates an EIP2930 type accessList based on a given Transaction. The accessList\n    /// contains all storage slots and addresses read and written by the transaction, except for the\n    /// sender account and the precompiles.\n    ///\n    /// It returns list of addresses and storage keys used by the transaction, plus the gas\n    /// consumed when the access list is added. That is, it gives you the list of addresses and\n    /// storage keys that will be used by that transaction, plus the gas consumed if the access\n    /// list is included. Like eth_estimateGas, this is an estimation; the list could change\n    /// when the transaction is actually mined. Adding an accessList to your transaction does\n    /// not necessary result in lower gas usage compared to a transaction without an access\n    /// list.\n    ///\n    /// Handler for ETH RPC call: `eth_createAccessList`\n    pub async fn create_access_list(\n        &self,\n        mut request: WithOtherFields<TransactionRequest>,\n        block_number: Option<BlockId>,\n    ) -> Result<AccessListResult> {\n        node_info!(\"eth_createAccessList\");\n        let block_request = self.block_request(block_number).await?;\n        // check if the number predates the fork, if in fork mode\n        if let BlockRequest::Number(number) = block_request\n            && let Some(fork) = self.get_fork()\n            && fork.predates_fork(number)\n        {\n            return Ok(fork.create_access_list(&request, Some(number.into())).await?);\n        }\n\n        self.backend\n            .with_database_at(Some(block_request), |state, block_env| {\n                let (exit, out, _, access_list) = self.backend.build_access_list_with_state(\n                    &state,\n                    request.clone(),\n                    FeeDetails::zero(),\n                    block_env.clone(),\n                )?;\n                ensure_return_ok(exit, &out)?;\n\n                // execute again but with access list set\n                request.access_list = Some(access_list.clone());\n\n                let (exit, out, gas_used, _) = self.backend.call_with_state(\n                    &state,\n                    request.clone(),\n                    FeeDetails::zero(),\n                    block_env,\n                )?;\n                ensure_return_ok(exit, &out)?;\n\n                Ok(AccessListResult {\n                    access_list: AccessList(access_list.0),\n                    gas_used: U256::from(gas_used),\n                    error: None,\n                })\n            })\n            .await?\n    }\n\n    /// Estimate gas needed for execution of given contract.\n    /// If no block parameter is given, it will use the pending block by default\n    ///\n    /// Handler for ETH RPC call: `eth_estimateGas`\n    pub async fn estimate_gas(\n        &self,\n        request: WithOtherFields<TransactionRequest>,\n        block_number: Option<BlockId>,\n        overrides: EvmOverrides,\n    ) -> Result<U256> {\n        node_info!(\"eth_estimateGas\");\n        self.do_estimate_gas(\n            request,\n            block_number.or_else(|| Some(BlockNumber::Pending.into())),\n            overrides,\n        )\n        .await\n        .map(U256::from)\n    }\n\n    /// Fills a transaction request with default values for missing fields.\n    ///\n    /// This method populates missing transaction fields like nonce, gas limit,\n    /// chain ID, and fee parameters with appropriate defaults.\n    ///\n    /// Handler for ETH RPC call: `eth_fillTransaction`\n    pub async fn fill_transaction(\n        &self,\n        mut request: WithOtherFields<TransactionRequest>,\n    ) -> Result<FillTransaction<AnyRpcTransaction>> {\n        node_info!(\"eth_fillTransaction\");\n\n        let from = match request.as_ref().from() {\n            Some(from) => from,\n            None => self.accounts()?.first().copied().ok_or(BlockchainError::NoSignerAvailable)?,\n        };\n\n        let nonce = if let Some(nonce) = request.as_ref().nonce() {\n            nonce\n        } else {\n            self.request_nonce(&request, from).await?.0\n        };\n\n        // Prefill gas limit with estimated gas, bubble up the error if the gas estimation fails\n        // This is a workaround to avoid the error being swallowed by the `build_tx_request`\n        // function\n        if request.as_ref().gas_limit().is_none() {\n            let estimated_gas =\n                self.estimate_gas(request.clone(), None, EvmOverrides::default()).await?;\n            request.as_mut().set_gas_limit(estimated_gas.to());\n        }\n\n        let typed_tx = self.build_tx_request(request, nonce).await?;\n        let tx = build_impersonated(typed_tx);\n\n        let raw = tx.encoded_2718().to_vec().into();\n\n        let mut tx =\n            transaction_build(None, MaybeImpersonatedTransaction::new(tx), None, None, None);\n\n        // Set the correct `from` address (overrides the recovered zero address from dummy\n        // signature)\n        tx.0.inner.inner = Recovered::new_unchecked(tx.0.inner.inner.into_inner(), from);\n\n        Ok(FillTransaction { raw, tx })\n    }\n\n    /// Handler for RPC call: `anvil_getBlobByHash`\n    pub fn anvil_get_blob_by_versioned_hash(\n        &self,\n        hash: B256,\n    ) -> Result<Option<alloy_consensus::Blob>> {\n        node_info!(\"anvil_getBlobByHash\");\n        Ok(self.backend.get_blob_by_versioned_hash(hash)?)\n    }\n\n    /// Handler for RPC call: `anvil_getBlobsByTransactionHash`\n    pub fn anvil_get_blob_by_tx_hash(&self, hash: B256) -> Result<Option<Vec<Blob>>> {\n        node_info!(\"anvil_getBlobsByTransactionHash\");\n        Ok(self.backend.get_blob_by_tx_hash(hash)?)\n    }\n\n    /// Handler for RPC call: `anvil_getBlobsByBlockId`\n    pub fn anvil_get_blobs_by_block_id(\n        &self,\n        block_id: impl Into<BlockId>,\n        versioned_hashes: Vec<B256>,\n    ) -> Result<Option<Vec<Blob>>> {\n        node_info!(\"anvil_getBlobsByBlockId\");\n        Ok(self.backend.get_blobs_by_block_id(block_id, versioned_hashes)?)\n    }\n\n    /// Returns the genesis time for the Beacon chain\n    ///\n    /// Handler for Beacon API call: `GET /eth/v1/beacon/genesis`\n    pub fn anvil_get_genesis_time(&self) -> Result<u64> {\n        node_info!(\"anvil_getGenesisTime\");\n        Ok(self.backend.genesis_time())\n    }\n\n    /// Get transaction by its hash.\n    ///\n    /// This will check the storage for a matching transaction, if no transaction exists in storage\n    /// this will also scan the mempool for a matching pending transaction\n    ///\n    /// Handler for ETH RPC call: `eth_getTransactionByHash`\n    pub async fn transaction_by_hash(&self, hash: B256) -> Result<Option<AnyRpcTransaction>> {\n        node_info!(\"eth_getTransactionByHash\");\n        let mut tx = self.pool.get_transaction(hash).map(|pending| {\n            let from = *pending.sender();\n            let tx = transaction_build(\n                Some(*pending.hash()),\n                pending.transaction,\n                None,\n                None,\n                Some(self.backend.base_fee()),\n            );\n\n            let WithOtherFields { inner: mut tx, other } = tx.0;\n            // we set the from field here explicitly to the set sender of the pending transaction,\n            // in case the transaction is impersonated.\n            tx.inner = Recovered::new_unchecked(tx.inner.into_inner(), from);\n\n            AnyRpcTransaction(WithOtherFields { inner: tx, other })\n        });\n        if tx.is_none() {\n            tx = self.backend.transaction_by_hash(hash).await?\n        }\n\n        Ok(tx)\n    }\n\n    /// Returns transaction at given block hash and index.\n    ///\n    /// Handler for ETH RPC call: `eth_getTransactionByBlockHashAndIndex`\n    pub async fn transaction_by_block_hash_and_index(\n        &self,\n        hash: B256,\n        index: Index,\n    ) -> Result<Option<AnyRpcTransaction>> {\n        node_info!(\"eth_getTransactionByBlockHashAndIndex\");\n        self.backend.transaction_by_block_hash_and_index(hash, index).await\n    }\n\n    /// Returns transaction by given block number and index.\n    ///\n    /// Handler for ETH RPC call: `eth_getTransactionByBlockNumberAndIndex`\n    pub async fn transaction_by_block_number_and_index(\n        &self,\n        block: BlockNumber,\n        idx: Index,\n    ) -> Result<Option<AnyRpcTransaction>> {\n        node_info!(\"eth_getTransactionByBlockNumberAndIndex\");\n        self.backend.transaction_by_block_number_and_index(block, idx).await\n    }\n\n    /// Returns the transaction by sender and nonce.\n    ///\n    /// This will check the mempool for pending transactions first, then perform a binary search\n    /// over mined blocks to find the transaction.\n    ///\n    /// Handler for ETH RPC call: `eth_getTransactionBySenderAndNonce`\n    pub async fn transaction_by_sender_and_nonce(\n        &self,\n        sender: Address,\n        nonce: U256,\n    ) -> Result<Option<AnyRpcTransaction>> {\n        node_info!(\"eth_getTransactionBySenderAndNonce\");\n\n        // check pending txs first\n        for pending_tx in self.pool.ready_transactions().chain(self.pool.pending_transactions()) {\n            if U256::from(pending_tx.pending_transaction.nonce()) == nonce\n                && *pending_tx.pending_transaction.sender() == sender\n            {\n                let tx = transaction_build(\n                    Some(*pending_tx.pending_transaction.hash()),\n                    pending_tx.pending_transaction.transaction.clone(),\n                    None,\n                    None,\n                    Some(self.backend.base_fee()),\n                );\n\n                let WithOtherFields { inner: mut tx, other } = tx.0;\n                // we set the from field here explicitly to the set sender of the pending\n                // transaction, in case the transaction is impersonated.\n                let from = *pending_tx.pending_transaction.sender();\n                tx.inner = Recovered::new_unchecked(tx.inner.into_inner(), from);\n\n                return Ok(Some(AnyRpcTransaction(WithOtherFields { inner: tx, other })));\n            }\n        }\n\n        let highest_nonce = self.transaction_count(sender, None).await?.saturating_to::<u64>();\n        let target_nonce = nonce.saturating_to::<u64>();\n\n        // if the nonce is higher or equal to the highest nonce, the transaction doesn't exist\n        if target_nonce >= highest_nonce {\n            return Ok(None);\n        }\n\n        // no mined blocks yet\n        let latest_block = self.backend.best_number();\n        if latest_block == 0 {\n            return Ok(None);\n        }\n\n        // binary search for the block containing the transaction\n        let mut low = 1u64;\n        let mut high = latest_block;\n\n        while low <= high {\n            let mid = low + (high - low) / 2;\n            let mid_nonce =\n                self.transaction_count(sender, Some(mid.into())).await?.saturating_to::<u64>();\n\n            if mid_nonce > target_nonce {\n                high = mid - 1;\n            } else {\n                low = mid + 1;\n            }\n        }\n\n        // search in the target block\n        let target_block = low;\n        if target_block <= latest_block\n            && let Some(txs) =\n                self.backend.mined_transactions_by_block_number(target_block.into()).await\n        {\n            for tx in txs {\n                if tx.from() == sender && tx.nonce() == target_nonce {\n                    return Ok(Some(tx));\n                }\n            }\n        }\n\n        Ok(None)\n    }\n\n    /// Returns transaction receipt by transaction hash.\n    ///\n    /// Handler for ETH RPC call: `eth_getTransactionReceipt`\n    pub async fn transaction_receipt(&self, hash: B256) -> Result<Option<FoundryTxReceipt>> {\n        node_info!(\"eth_getTransactionReceipt\");\n        self.backend.transaction_receipt(hash).await\n    }\n\n    /// Returns block receipts by block number.\n    ///\n    /// Handler for ETH RPC call: `eth_getBlockReceipts`\n    pub async fn block_receipts(&self, number: BlockId) -> Result<Option<Vec<FoundryTxReceipt>>> {\n        node_info!(\"eth_getBlockReceipts\");\n        self.backend.block_receipts(number).await\n    }\n\n    /// Returns an uncles at given block and index.\n    ///\n    /// Handler for ETH RPC call: `eth_getUncleByBlockHashAndIndex`\n    pub async fn uncle_by_block_hash_and_index(\n        &self,\n        block_hash: B256,\n        idx: Index,\n    ) -> Result<Option<AnyRpcBlock>> {\n        node_info!(\"eth_getUncleByBlockHashAndIndex\");\n        let number =\n            self.backend.ensure_block_number(Some(BlockId::Hash(block_hash.into()))).await?;\n        if let Some(fork) = self.get_fork()\n            && fork.predates_fork_inclusive(number)\n        {\n            return Ok(fork.uncle_by_block_hash_and_index(block_hash, idx.into()).await?);\n        }\n        // It's impossible to have uncles outside of fork mode\n        Ok(None)\n    }\n\n    /// Returns an uncles at given block and index.\n    ///\n    /// Handler for ETH RPC call: `eth_getUncleByBlockNumberAndIndex`\n    pub async fn uncle_by_block_number_and_index(\n        &self,\n        block_number: BlockNumber,\n        idx: Index,\n    ) -> Result<Option<AnyRpcBlock>> {\n        node_info!(\"eth_getUncleByBlockNumberAndIndex\");\n        let number = self.backend.ensure_block_number(Some(BlockId::Number(block_number))).await?;\n        if let Some(fork) = self.get_fork()\n            && fork.predates_fork_inclusive(number)\n        {\n            return Ok(fork.uncle_by_block_number_and_index(number, idx.into()).await?);\n        }\n        // It's impossible to have uncles outside of fork mode\n        Ok(None)\n    }\n\n    /// Returns logs matching given filter object.\n    ///\n    /// Handler for ETH RPC call: `eth_getLogs`\n    pub async fn logs(&self, filter: Filter) -> Result<Vec<Log>> {\n        node_info!(\"eth_getLogs\");\n        self.backend.logs(filter).await\n    }\n\n    /// Returns the hash of the current block, the seedHash, and the boundary condition to be met.\n    ///\n    /// Handler for ETH RPC call: `eth_getWork`\n    pub fn work(&self) -> Result<Work> {\n        node_info!(\"eth_getWork\");\n        Err(BlockchainError::RpcUnimplemented)\n    }\n\n    /// Returns the sync status, always be fails.\n    ///\n    /// Handler for ETH RPC call: `eth_syncing`\n    pub fn syncing(&self) -> Result<bool> {\n        node_info!(\"eth_syncing\");\n        Ok(false)\n    }\n\n    /// Returns the current configuration of the chain.\n    /// This is useful for finding out what precompiles and system contracts are available.\n    ///\n    /// Note: the activation timestamp is always 0 as the configuration is set at genesis.\n    /// Note: the `fork_id` is always `0x00000000` as this node does not participate in any forking\n    /// on the network.\n    /// Note: the `next` and `last` fields are always `null` as this node does not participate in\n    /// any forking on the network.\n    ///\n    /// Handler for ETH RPC call: `eth_config`\n    pub fn config(&self) -> Result<EthConfig> {\n        node_info!(\"eth_config\");\n        Ok(EthConfig {\n            current: EthForkConfig {\n                activation_time: 0,\n                blob_schedule: self.backend.blob_params(),\n                chain_id: self.backend.env().read().evm_env.cfg_env.chain_id,\n                fork_id: Bytes::from_static(&[0; 4]),\n                precompiles: self.backend.precompiles(),\n                system_contracts: self.backend.system_contracts(),\n            },\n            next: None,\n            last: None,\n        })\n    }\n\n    /// Used for submitting a proof-of-work solution.\n    ///\n    /// Handler for ETH RPC call: `eth_submitWork`\n    pub fn submit_work(&self, _: B64, _: B256, _: B256) -> Result<bool> {\n        node_info!(\"eth_submitWork\");\n        Err(BlockchainError::RpcUnimplemented)\n    }\n\n    /// Used for submitting mining hashrate.\n    ///\n    /// Handler for ETH RPC call: `eth_submitHashrate`\n    pub fn submit_hashrate(&self, _: U256, _: B256) -> Result<bool> {\n        node_info!(\"eth_submitHashrate\");\n        Err(BlockchainError::RpcUnimplemented)\n    }\n\n    /// Introduced in EIP-1559 for getting information on the appropriate priority fee to use.\n    ///\n    /// Handler for ETH RPC call: `eth_feeHistory`\n    pub async fn fee_history(\n        &self,\n        block_count: U256,\n        newest_block: BlockNumber,\n        reward_percentiles: Vec<f64>,\n    ) -> Result<FeeHistory> {\n        node_info!(\"eth_feeHistory\");\n        // max number of blocks in the requested range\n\n        let current = self.backend.best_number();\n        let slots_in_an_epoch = 32u64;\n\n        let number = match newest_block {\n            BlockNumber::Latest | BlockNumber::Pending => current,\n            BlockNumber::Earliest => 0,\n            BlockNumber::Number(n) => n,\n            BlockNumber::Safe => current.saturating_sub(slots_in_an_epoch),\n            BlockNumber::Finalized => current.saturating_sub(slots_in_an_epoch * 2),\n        };\n\n        // check if the number predates the fork, if in fork mode\n        if let Some(fork) = self.get_fork() {\n            // if we're still at the forked block we don't have any history and can't compute it\n            // efficiently, instead we fetch it from the fork\n            if fork.predates_fork_inclusive(number) {\n                return fork\n                    .fee_history(block_count.to(), BlockNumber::Number(number), &reward_percentiles)\n                    .await\n                    .map_err(BlockchainError::AlloyForkProvider);\n            }\n        }\n\n        const MAX_BLOCK_COUNT: u64 = 1024u64;\n        let block_count = block_count.to::<u64>().min(MAX_BLOCK_COUNT);\n\n        // highest and lowest block num in the requested range\n        let highest = number;\n        let lowest = highest.saturating_sub(block_count.saturating_sub(1));\n\n        // only support ranges that are in cache range\n        if lowest < self.backend.best_number().saturating_sub(self.fee_history_limit) {\n            return Err(FeeHistoryError::InvalidBlockRange.into());\n        }\n\n        let mut response = FeeHistory {\n            oldest_block: lowest,\n            base_fee_per_gas: Vec::new(),\n            gas_used_ratio: Vec::new(),\n            reward: Some(Default::default()),\n            base_fee_per_blob_gas: Default::default(),\n            blob_gas_used_ratio: Default::default(),\n        };\n        let mut rewards = Vec::new();\n\n        {\n            let fee_history = self.fee_history_cache.lock();\n\n            // iter over the requested block range\n            for n in lowest..=highest {\n                // <https://eips.ethereum.org/EIPS/eip-1559>\n                if let Some(block) = fee_history.get(&n) {\n                    response.base_fee_per_gas.push(block.base_fee);\n                    response.base_fee_per_blob_gas.push(block.base_fee_per_blob_gas.unwrap_or(0));\n                    response.blob_gas_used_ratio.push(block.blob_gas_used_ratio);\n                    response.gas_used_ratio.push(block.gas_used_ratio);\n\n                    // requested percentiles\n                    if !reward_percentiles.is_empty() {\n                        let mut block_rewards = Vec::new();\n                        let resolution_per_percentile: f64 = 2.0;\n                        for p in &reward_percentiles {\n                            let p = p.clamp(0.0, 100.0);\n                            let index = ((p.round() / 2f64) * 2f64) * resolution_per_percentile;\n                            let reward = block.rewards.get(index as usize).map_or(0, |r| *r);\n                            block_rewards.push(reward);\n                        }\n                        rewards.push(block_rewards);\n                    }\n                }\n            }\n        }\n\n        response.reward = Some(rewards);\n\n        // add the next block's base fee to the response\n        // The spec states that `base_fee_per_gas` \"[..] includes the next block after the\n        // newest of the returned range, because this value can be derived from the\n        // newest block\"\n        response.base_fee_per_gas.push(self.backend.fees().base_fee() as u128);\n\n        // Same goes for the `base_fee_per_blob_gas`:\n        // > [..] includes the next block after the newest of the returned range, because this\n        // > value can be derived from the newest block.\n        response.base_fee_per_blob_gas.push(self.backend.fees().base_fee_per_blob_gas());\n\n        Ok(response)\n    }\n\n    /// Introduced in EIP-1159, a Geth-specific and simplified priority fee oracle.\n    /// Leverages the already existing fee history cache.\n    ///\n    /// Returns a suggestion for a gas tip cap for dynamic fee transactions.\n    ///\n    /// Handler for ETH RPC call: `eth_maxPriorityFeePerGas`\n    pub fn max_priority_fee_per_gas(&self) -> Result<U256> {\n        node_info!(\"eth_maxPriorityFeePerGas\");\n        Ok(U256::from(self.lowest_suggestion_tip()))\n    }\n\n    /// Creates a filter object, based on filter options, to notify when the state changes (logs).\n    ///\n    /// Handler for ETH RPC call: `eth_newFilter`\n    pub async fn new_filter(&self, filter: Filter) -> Result<String> {\n        node_info!(\"eth_newFilter\");\n        // all logs that are already available that match the filter if the filter's block range is\n        // in the past\n        let historic = if filter.block_option.get_from_block().is_some() {\n            self.backend.logs(filter.clone()).await?\n        } else {\n            vec![]\n        };\n        let filter = EthFilter::Logs(Box::new(LogsFilter {\n            blocks: self.new_block_notifications(),\n            storage: self.storage_info(),\n            filter: FilteredParams::new(Some(filter)),\n            historic: Some(historic),\n        }));\n        Ok(self.filters.add_filter(filter).await)\n    }\n\n    /// Creates a filter in the node, to notify when a new block arrives.\n    ///\n    /// Handler for ETH RPC call: `eth_newBlockFilter`\n    pub async fn new_block_filter(&self) -> Result<String> {\n        node_info!(\"eth_newBlockFilter\");\n        let filter = EthFilter::Blocks(self.new_block_notifications());\n        Ok(self.filters.add_filter(filter).await)\n    }\n\n    /// Creates a filter in the node, to notify when new pending transactions arrive.\n    ///\n    /// Handler for ETH RPC call: `eth_newPendingTransactionFilter`\n    pub async fn new_pending_transaction_filter(&self) -> Result<String> {\n        node_info!(\"eth_newPendingTransactionFilter\");\n        let filter = EthFilter::PendingTransactions(self.new_ready_transactions());\n        Ok(self.filters.add_filter(filter).await)\n    }\n\n    /// Polling method for a filter, which returns an array of logs which occurred since last poll.\n    ///\n    /// Handler for ETH RPC call: `eth_getFilterChanges`\n    pub async fn get_filter_changes(&self, id: &str) -> ResponseResult {\n        node_info!(\"eth_getFilterChanges\");\n        self.filters.get_filter_changes(id).await\n    }\n\n    /// Returns an array of all logs matching filter with given id.\n    ///\n    /// Handler for ETH RPC call: `eth_getFilterLogs`\n    pub async fn get_filter_logs(&self, id: &str) -> Result<Vec<Log>> {\n        node_info!(\"eth_getFilterLogs\");\n        if let Some(filter) = self.filters.get_log_filter(id).await {\n            self.backend.logs(filter).await\n        } else {\n            Err(BlockchainError::FilterNotFound)\n        }\n    }\n\n    /// Handler for ETH RPC call: `eth_uninstallFilter`\n    pub async fn uninstall_filter(&self, id: &str) -> Result<bool> {\n        node_info!(\"eth_uninstallFilter\");\n        Ok(self.filters.uninstall_filter(id).await.is_some())\n    }\n\n    /// Returns EIP-2718 encoded raw transaction\n    ///\n    /// Handler for RPC call: `debug_getRawTransaction`\n    pub async fn raw_transaction(&self, hash: B256) -> Result<Option<Bytes>> {\n        node_info!(\"debug_getRawTransaction\");\n        self.inner_raw_transaction(hash).await\n    }\n\n    /// Returns EIP-2718 encoded raw transaction by block hash and index\n    ///\n    /// Handler for RPC call: `eth_getRawTransactionByBlockHashAndIndex`\n    pub async fn raw_transaction_by_block_hash_and_index(\n        &self,\n        block_hash: B256,\n        index: Index,\n    ) -> Result<Option<Bytes>> {\n        node_info!(\"eth_getRawTransactionByBlockHashAndIndex\");\n        match self.backend.transaction_by_block_hash_and_index(block_hash, index).await? {\n            Some(tx) => self.inner_raw_transaction(tx.tx_hash()).await,\n            None => Ok(None),\n        }\n    }\n\n    /// Returns EIP-2718 encoded raw transaction by block number and index\n    ///\n    /// Handler for RPC call: `eth_getRawTransactionByBlockNumberAndIndex`\n    pub async fn raw_transaction_by_block_number_and_index(\n        &self,\n        block_number: BlockNumber,\n        index: Index,\n    ) -> Result<Option<Bytes>> {\n        node_info!(\"eth_getRawTransactionByBlockNumberAndIndex\");\n        match self.backend.transaction_by_block_number_and_index(block_number, index).await? {\n            Some(tx) => self.inner_raw_transaction(tx.tx_hash()).await,\n            None => Ok(None),\n        }\n    }\n\n    /// Returns traces for the transaction hash for geth's tracing endpoint\n    ///\n    /// Handler for RPC call: `debug_traceTransaction`\n    pub async fn debug_trace_transaction(\n        &self,\n        tx_hash: B256,\n        opts: GethDebugTracingOptions,\n    ) -> Result<GethTrace> {\n        node_info!(\"debug_traceTransaction\");\n        self.backend.debug_trace_transaction(tx_hash, opts).await\n    }\n\n    /// Returns traces for the transaction for geth's tracing endpoint\n    ///\n    /// Handler for RPC call: `debug_traceCall`\n    pub async fn debug_trace_call(\n        &self,\n        request: WithOtherFields<TransactionRequest>,\n        block_number: Option<BlockId>,\n        opts: GethDebugTracingCallOptions,\n    ) -> Result<GethTrace> {\n        node_info!(\"debug_traceCall\");\n        let block_request = self.block_request(block_number).await?;\n        let fees = FeeDetails::new(\n            request.gas_price,\n            request.max_fee_per_gas,\n            request.max_priority_fee_per_gas,\n            request.max_fee_per_blob_gas,\n        )?\n        .or_zero_fees();\n\n        let result: std::result::Result<GethTrace, BlockchainError> =\n            self.backend.call_with_tracing(request, fees, Some(block_request), opts).await;\n        result\n    }\n\n    /// Returns code by its hash\n    ///\n    /// Handler for RPC call: `debug_codeByHash`\n    pub async fn debug_code_by_hash(\n        &self,\n        hash: B256,\n        block_id: Option<BlockId>,\n    ) -> Result<Option<Bytes>> {\n        node_info!(\"debug_codeByHash\");\n        self.backend.debug_code_by_hash(hash, block_id).await\n    }\n\n    /// Returns the value associated with a key from the database\n    /// Only supports bytecode lookups.\n    ///\n    /// Handler for RPC call: `debug_dbGet`\n    pub async fn debug_db_get(&self, key: String) -> Result<Option<Bytes>> {\n        node_info!(\"debug_dbGet\");\n        self.backend.debug_db_get(key).await\n    }\n\n    /// Returns traces for the transaction hash via parity's tracing endpoint\n    ///\n    /// Handler for RPC call: `trace_transaction`\n    pub async fn trace_transaction(&self, tx_hash: B256) -> Result<Vec<LocalizedTransactionTrace>> {\n        node_info!(\"trace_transaction\");\n        self.backend.trace_transaction(tx_hash).await\n    }\n\n    /// Returns traces for the transaction hash via parity's tracing endpoint\n    ///\n    /// Handler for RPC call: `trace_block`\n    pub async fn trace_block(&self, block: BlockNumber) -> Result<Vec<LocalizedTransactionTrace>> {\n        node_info!(\"trace_block\");\n        self.backend.trace_block(block).await\n    }\n\n    /// Returns filtered traces over blocks\n    ///\n    /// Handler for RPC call: `trace_filter`\n    pub async fn trace_filter(\n        &self,\n        filter: TraceFilter,\n    ) -> Result<Vec<LocalizedTransactionTrace>> {\n        node_info!(\"trace_filter\");\n        self.backend.trace_filter(filter).await\n    }\n\n    /// Replays all transactions in a block returning the requested traces for each transaction\n    ///\n    /// Handler for RPC call: `trace_replayBlockTransactions`\n    pub async fn trace_replay_block_transactions(\n        &self,\n        block: BlockNumber,\n        trace_types: HashSet<TraceType>,\n    ) -> Result<Vec<TraceResultsWithTransactionHash>> {\n        node_info!(\"trace_replayBlockTransactions\");\n        self.backend.trace_replay_block_transactions(block, trace_types).await\n    }\n}\n\n// == impl EthApi anvil endpoints ==\n\nimpl EthApi<FoundryNetwork> {\n    /// Send transactions impersonating specific account and contract addresses.\n    ///\n    /// Handler for ETH RPC call: `anvil_impersonateAccount`\n    pub async fn anvil_impersonate_account(&self, address: Address) -> Result<()> {\n        node_info!(\"anvil_impersonateAccount\");\n        self.backend.impersonate(address);\n        Ok(())\n    }\n\n    /// Stops impersonating an account if previously set with `anvil_impersonateAccount`.\n    ///\n    /// Handler for ETH RPC call: `anvil_stopImpersonatingAccount`\n    pub async fn anvil_stop_impersonating_account(&self, address: Address) -> Result<()> {\n        node_info!(\"anvil_stopImpersonatingAccount\");\n        self.backend.stop_impersonating(address);\n        Ok(())\n    }\n\n    /// If set to true will make every account impersonated\n    ///\n    /// Handler for ETH RPC call: `anvil_autoImpersonateAccount`\n    pub async fn anvil_auto_impersonate_account(&self, enabled: bool) -> Result<()> {\n        node_info!(\"anvil_autoImpersonateAccount\");\n        self.backend.auto_impersonate_account(enabled);\n        Ok(())\n    }\n\n    /// Registers a new address and signature pair to impersonate.\n    pub async fn anvil_impersonate_signature(\n        &self,\n        signature: Bytes,\n        address: Address,\n    ) -> Result<()> {\n        node_info!(\"anvil_impersonateSignature\");\n        self.backend.impersonate_signature(signature, address).await\n    }\n\n    /// Mines a series of blocks.\n    ///\n    /// Handler for ETH RPC call: `anvil_mine`\n    pub async fn anvil_mine(&self, num_blocks: Option<U256>, interval: Option<U256>) -> Result<()> {\n        node_info!(\"anvil_mine\");\n        let interval = interval.map(|i| i.to::<u64>());\n        let blocks = num_blocks.unwrap_or(U256::from(1));\n        if blocks.is_zero() {\n            return Ok(());\n        }\n\n        self.on_blocking_task(|this| async move {\n            // mine all the blocks\n            for _ in 0..blocks.to::<u64>() {\n                // If we have an interval, jump forwards in time to the \"next\" timestamp\n                if let Some(interval) = interval {\n                    this.backend.time().increase_time(interval);\n                }\n                this.mine_one().await;\n            }\n            Ok(())\n        })\n        .await?;\n\n        Ok(())\n    }\n\n    /// Helper function to find the storage slot for an ERC20 function call by testing slots\n    /// from an access list until one produces the expected result.\n    ///\n    /// Rather than trying to reverse-engineer the storage layout, this function uses a\n    /// \"trial and error\" approach: try overriding each slot that the function accesses,\n    /// and see which one actually affects the function's return value.\n    ///\n    /// ## Parameters\n    /// - `token_address`: The ERC20 token contract address\n    /// - `calldata`: The encoded function call (e.g., `balanceOf(user)` or `allowance(owner,\n    ///   spender)`)\n    /// - `expected_value`: The value we want to set (balance or allowance amount)\n    ///\n    /// ## Returns\n    /// The storage slot (B256) that contains the target ERC20 data, or an error if no slot is\n    /// found.\n    async fn find_erc20_storage_slot(\n        &self,\n        token_address: Address,\n        calldata: Bytes,\n        expected_value: U256,\n    ) -> Result<B256> {\n        let tx = TransactionRequest::default().with_to(token_address).with_input(calldata.clone());\n\n        // first collect all the slots that are used by the function call\n        let access_list_result =\n            self.create_access_list(WithOtherFields::new(tx.clone()), None).await?;\n        let access_list = access_list_result.access_list;\n\n        // iterate over all the accessed slots and try to find the one that contains the\n        // target value by overriding the slot and checking the function call result\n        for item in access_list.0 {\n            if item.address != token_address {\n                continue;\n            };\n            for slot in &item.storage_keys {\n                let account_override = AccountOverride::default().with_state_diff(std::iter::once(\n                    (*slot, B256::from(expected_value.to_be_bytes())),\n                ));\n\n                let state_override = StateOverridesBuilder::default()\n                    .append(token_address, account_override)\n                    .build();\n\n                let evm_override = EvmOverrides::state(Some(state_override));\n\n                let Ok(result) =\n                    self.call(WithOtherFields::new(tx.clone()), None, evm_override).await\n                else {\n                    // overriding this slot failed\n                    continue;\n                };\n\n                let Ok(result_value) = U256::abi_decode(&result) else {\n                    // response returned something other than a U256\n                    continue;\n                };\n\n                if result_value == expected_value {\n                    return Ok(*slot);\n                }\n            }\n        }\n\n        Err(BlockchainError::Message(\"Unable to find storage slot\".to_string()))\n    }\n\n    /// Deals ERC20 tokens to a address\n    ///\n    /// Handler for RPC call: `anvil_dealERC20`\n    pub async fn anvil_deal_erc20(\n        &self,\n        address: Address,\n        token_address: Address,\n        balance: U256,\n    ) -> Result<()> {\n        node_info!(\"anvil_dealERC20\");\n\n        sol! {\n            #[sol(rpc)]\n            contract IERC20 {\n                function balanceOf(address target) external view returns (uint256);\n            }\n        }\n\n        let calldata = IERC20::balanceOfCall { target: address }.abi_encode().into();\n\n        // Find the storage slot that contains the balance\n        let slot =\n            self.find_erc20_storage_slot(token_address, calldata, balance).await.map_err(|_| {\n                BlockchainError::Message(\"Unable to set ERC20 balance, no slot found\".to_string())\n            })?;\n\n        // Set the storage slot to the desired balance\n        self.anvil_set_storage_at(\n            token_address,\n            U256::from_be_bytes(slot.0),\n            B256::from(balance.to_be_bytes()),\n        )\n        .await?;\n\n        Ok(())\n    }\n\n    /// Sets the ERC20 allowance for a spender\n    ///\n    /// Handler for RPC call: `anvil_set_erc20_allowance`\n    pub async fn anvil_set_erc20_allowance(\n        &self,\n        owner: Address,\n        spender: Address,\n        token_address: Address,\n        amount: U256,\n    ) -> Result<()> {\n        node_info!(\"anvil_setERC20Allowance\");\n\n        sol! {\n            #[sol(rpc)]\n            contract IERC20 {\n                function allowance(address owner, address spender) external view returns (uint256);\n            }\n        }\n\n        let calldata = IERC20::allowanceCall { owner, spender }.abi_encode().into();\n\n        // Find the storage slot that contains the allowance\n        let slot =\n            self.find_erc20_storage_slot(token_address, calldata, amount).await.map_err(|_| {\n                BlockchainError::Message(\"Unable to set ERC20 allowance, no slot found\".to_string())\n            })?;\n\n        // Set the storage slot to the desired allowance\n        self.anvil_set_storage_at(\n            token_address,\n            U256::from_be_bytes(slot.0),\n            B256::from(amount.to_be_bytes()),\n        )\n        .await?;\n\n        Ok(())\n    }\n\n    /// Reorg the chain to a specific depth and mine new blocks back to the canonical height.\n    ///\n    /// e.g depth = 3\n    ///     A  -> B  -> C  -> D  -> E\n    ///     A  -> B  -> C' -> D' -> E'\n    ///\n    /// Depth specifies the height to reorg the chain back to. Depth must not exceed the current\n    /// chain height, i.e. can't reorg past the genesis block.\n    ///\n    /// Optionally supply a list of transaction and block pairs that will populate the reorged\n    /// blocks. The maximum block number of the pairs must not exceed the specified depth.\n    ///\n    /// Handler for RPC call: `anvil_reorg`\n    pub async fn anvil_reorg(&self, options: ReorgOptions) -> Result<()> {\n        node_info!(\"anvil_reorg\");\n        let depth = options.depth;\n        let tx_block_pairs = options.tx_block_pairs;\n\n        // Check reorg depth doesn't exceed current chain height\n        let current_height = self.backend.best_number();\n        let common_height = current_height.checked_sub(depth).ok_or(BlockchainError::RpcError(\n            RpcError::invalid_params(format!(\n                \"Reorg depth must not exceed current chain height: current height {current_height}, depth {depth}\"\n            )),\n        ))?;\n\n        // Get the common ancestor block\n        let common_block =\n            self.backend.get_block(common_height).ok_or(BlockchainError::BlockNotFound)?;\n\n        // Convert the transaction requests to pool transactions if they exist, otherwise use empty\n        // hashmap\n        let block_pool_txs = if tx_block_pairs.is_empty() {\n            HashMap::default()\n        } else {\n            let mut pairs = tx_block_pairs;\n\n            // Check the maximum block supplied number will not exceed the reorged chain height\n            if let Some((_, num)) = pairs.iter().find(|(_, num)| *num >= depth) {\n                return Err(BlockchainError::RpcError(RpcError::invalid_params(format!(\n                    \"Block number for reorg tx will exceed the reorged chain height. Block number {num} must not exceed (depth-1) {}\",\n                    depth - 1\n                ))));\n            }\n\n            // Sort by block number to make it easier to manage new nonces\n            pairs.sort_by_key(|a| a.1);\n\n            // Manage nonces for each signer\n            // address -> cumulative nonce\n            let mut nonces: HashMap<Address, u64> = HashMap::default();\n\n            let mut txs: HashMap<u64, Vec<Arc<PoolTransaction<FoundryTxEnvelope>>>> =\n                HashMap::default();\n            for pair in pairs {\n                let (tx_data, block_index) = pair;\n\n                let pending = match tx_data {\n                    TransactionData::Raw(bytes) => {\n                        let mut data = bytes.as_ref();\n                        let decoded = FoundryTxEnvelope::decode_2718(&mut data)\n                            .map_err(|_| BlockchainError::FailedToDecodeSignedTransaction)?;\n                        PendingTransaction::new(decoded)?\n                    }\n\n                    TransactionData::JSON(request) => {\n                        let from = request.from.map(Ok).unwrap_or_else(|| {\n                            self.accounts()?\n                                .first()\n                                .copied()\n                                .ok_or(BlockchainError::NoSignerAvailable)\n                        })?;\n\n                        // Get the nonce at the common block\n                        let curr_nonce = nonces.entry(from).or_insert(\n                            self.get_transaction_count(\n                                from,\n                                Some(common_block.header.number().into()),\n                            )\n                            .await?,\n                        );\n\n                        // Build typed transaction request\n                        let typed_tx = self.build_tx_request(request.into(), *curr_nonce).await?;\n\n                        // Increment nonce\n                        *curr_nonce += 1;\n\n                        // Handle signer and convert to pending transaction\n                        if self.is_impersonated(from) {\n                            let transaction = sign::build_impersonated(typed_tx);\n                            self.ensure_typed_transaction_supported(&transaction)?;\n                            PendingTransaction::with_impersonated(transaction, from)\n                        } else {\n                            let transaction = self.sign_request(&from, typed_tx)?;\n                            self.ensure_typed_transaction_supported(&transaction)?;\n                            PendingTransaction::new(transaction)?\n                        }\n                    }\n                };\n\n                let pooled = PoolTransaction::new(pending);\n                txs.entry(block_index).or_default().push(Arc::new(pooled));\n            }\n\n            txs\n        };\n\n        self.backend.reorg(depth, block_pool_txs, common_block).await?;\n        Ok(())\n    }\n\n    /// Mine blocks, instantly.\n    ///\n    /// Handler for RPC call: `evm_mine`\n    ///\n    /// This will mine the blocks regardless of the configured mining mode.\n    /// **Note**: ganache returns `0x0` here as placeholder for additional meta-data in the future.\n    pub async fn evm_mine(&self, opts: Option<MineOptions>) -> Result<String> {\n        node_info!(\"evm_mine\");\n\n        self.do_evm_mine(opts).await?;\n\n        Ok(\"0x0\".to_string())\n    }\n\n    /// Mine blocks, instantly and return the mined blocks.\n    ///\n    /// Handler for RPC call: `evm_mine_detailed`\n    ///\n    /// This will mine the blocks regardless of the configured mining mode.\n    ///\n    /// **Note**: This behaves exactly as [Self::evm_mine] but returns different output, for\n    /// compatibility reasons, this is a separate call since `evm_mine` is not an anvil original.\n    /// and `ganache` may change the `0x0` placeholder.\n    pub async fn evm_mine_detailed(&self, opts: Option<MineOptions>) -> Result<Vec<AnyRpcBlock>> {\n        node_info!(\"evm_mine_detailed\");\n\n        let mined_blocks = self.do_evm_mine(opts).await?;\n\n        let mut blocks = Vec::with_capacity(mined_blocks as usize);\n\n        let latest = self.backend.best_number();\n        for offset in (0..mined_blocks).rev() {\n            let block_num = latest - offset;\n            if let Some(mut block) =\n                self.backend.block_by_number_full(BlockNumber::Number(block_num)).await?\n            {\n                let block_txs = match block.transactions_mut() {\n                    BlockTransactions::Full(txs) => txs,\n                    BlockTransactions::Hashes(_) | BlockTransactions::Uncle => unreachable!(),\n                };\n                for tx in block_txs.iter_mut() {\n                    if let Some(receipt) = self.backend.mined_transaction_receipt(tx.tx_hash())\n                        && let Some(output) = receipt.out\n                    {\n                        // insert revert reason if failure\n                        if !receipt.inner.as_ref().status()\n                            && let Some(reason) = RevertDecoder::new().maybe_decode(&output, None)\n                        {\n                            tx.other.insert(\n                                \"revertReason\".to_string(),\n                                serde_json::to_value(reason).expect(\"Infallible\"),\n                            );\n                        }\n                        tx.other.insert(\n                            \"output\".to_string(),\n                            serde_json::to_value(output).expect(\"Infallible\"),\n                        );\n                    }\n                }\n                block.transactions = BlockTransactions::Full(block_txs.to_vec());\n                blocks.push(block);\n            }\n        }\n\n        Ok(blocks)\n    }\n\n    /// Execute a transaction regardless of signature status\n    ///\n    /// Handler for ETH RPC call: `eth_sendUnsignedTransaction`\n    pub async fn eth_send_unsigned_transaction(\n        &self,\n        request: WithOtherFields<TransactionRequest>,\n    ) -> Result<TxHash> {\n        node_info!(\"eth_sendUnsignedTransaction\");\n        // either use the impersonated account of the request's `from` field\n        let from = request.from.ok_or(BlockchainError::NoSignerAvailable)?;\n\n        let (nonce, on_chain_nonce) = self.request_nonce(&request, from).await?;\n\n        let typed_tx = self.build_tx_request(request, nonce).await?;\n\n        let transaction = sign::build_impersonated(typed_tx);\n\n        self.ensure_typed_transaction_supported(&transaction)?;\n\n        let pending_transaction = PendingTransaction::with_impersonated(transaction, from);\n\n        // pre-validate\n        self.backend.validate_pool_transaction(&pending_transaction).await?;\n\n        let requires = required_marker(nonce, on_chain_nonce, from);\n        let provides = vec![to_marker(nonce, from)];\n\n        self.add_pending_transaction(pending_transaction, requires, provides)\n    }\n\n    /// Returns a summary of all the transactions currently pending for inclusion in the next\n    /// block(s), as well as the ones that are being scheduled for future execution only.\n    ///\n    /// See [here](https://geth.ethereum.org/docs/rpc/ns-txpool#txpool_inspect) for more details\n    ///\n    /// Handler for ETH RPC call: `txpool_inspect`\n    pub async fn txpool_inspect(&self) -> Result<TxpoolInspect> {\n        node_info!(\"txpool_inspect\");\n        let mut inspect = TxpoolInspect::default();\n\n        fn convert(tx: Arc<PoolTransaction<FoundryTxEnvelope>>) -> TxpoolInspectSummary {\n            let tx = &tx.pending_transaction.transaction;\n            let to = tx.to();\n            let gas_price = tx.max_fee_per_gas();\n            let value = tx.value();\n            let gas = tx.gas_limit();\n            TxpoolInspectSummary { to, value, gas, gas_price }\n        }\n\n        // Note: naming differs geth vs anvil:\n        //\n        // _Pending transactions_ are transactions that are ready to be processed and included in\n        // the block. _Queued transactions_ are transactions where the transaction nonce is\n        // not in sequence. The transaction nonce is an incrementing number for each transaction\n        // with the same From address.\n        for pending in self.pool.ready_transactions() {\n            let entry = inspect.pending.entry(*pending.pending_transaction.sender()).or_default();\n            let key = pending.pending_transaction.nonce().to_string();\n            entry.insert(key, convert(pending));\n        }\n        for queued in self.pool.pending_transactions() {\n            let entry = inspect.pending.entry(*queued.pending_transaction.sender()).or_default();\n            let key = queued.pending_transaction.nonce().to_string();\n            entry.insert(key, convert(queued));\n        }\n        Ok(inspect)\n    }\n\n    /// Returns the details of all transactions currently pending for inclusion in the next\n    /// block(s), as well as the ones that are being scheduled for future execution only.\n    ///\n    /// See [here](https://geth.ethereum.org/docs/rpc/ns-txpool#txpool_content) for more details\n    ///\n    /// Handler for ETH RPC call: `txpool_inspect`\n    pub async fn txpool_content(&self) -> Result<TxpoolContent<AnyRpcTransaction>> {\n        node_info!(\"txpool_content\");\n        let mut content = TxpoolContent::<AnyRpcTransaction>::default();\n        fn convert(tx: Arc<PoolTransaction<FoundryTxEnvelope>>) -> Result<AnyRpcTransaction> {\n            let from = *tx.pending_transaction.sender();\n            let tx = transaction_build(\n                Some(tx.hash()),\n                tx.pending_transaction.transaction.clone(),\n                None,\n                None,\n                None,\n            );\n\n            let WithOtherFields { inner: mut tx, other } = tx.0;\n\n            // we set the from field here explicitly to the set sender of the pending transaction,\n            // in case the transaction is impersonated.\n            tx.inner = Recovered::new_unchecked(tx.inner.into_inner(), from);\n\n            let tx = AnyRpcTransaction(WithOtherFields { inner: tx, other });\n\n            Ok(tx)\n        }\n\n        for pending in self.pool.ready_transactions() {\n            let entry = content.pending.entry(*pending.pending_transaction.sender()).or_default();\n            let key = pending.pending_transaction.nonce().to_string();\n            entry.insert(key, convert(pending)?);\n        }\n        for queued in self.pool.pending_transactions() {\n            let entry = content.pending.entry(*queued.pending_transaction.sender()).or_default();\n            let key = queued.pending_transaction.nonce().to_string();\n            entry.insert(key, convert(queued)?);\n        }\n\n        Ok(content)\n    }\n}\n\nimpl EthApi<FoundryNetwork> {\n    /// Executes the `evm_mine` and returns the number of blocks mined\n    async fn do_evm_mine(&self, opts: Option<MineOptions>) -> Result<u64> {\n        let mut blocks_to_mine = 1u64;\n\n        if let Some(opts) = opts {\n            let timestamp = match opts {\n                MineOptions::Timestamp(timestamp) => timestamp,\n                MineOptions::Options { timestamp, blocks } => {\n                    if let Some(blocks) = blocks {\n                        blocks_to_mine = blocks;\n                    }\n                    timestamp\n                }\n            };\n            if let Some(timestamp) = timestamp {\n                // timestamp was explicitly provided to be the next timestamp\n                self.evm_set_next_block_timestamp(timestamp)?;\n            }\n        }\n\n        // this can be blocking for a bit, especially in forking mode\n        // <https://github.com/foundry-rs/foundry/issues/6036>\n        self.on_blocking_task(|this| async move {\n            // mine all the blocks\n            for _ in 0..blocks_to_mine {\n                this.mine_one().await;\n            }\n            Ok(())\n        })\n        .await?;\n\n        Ok(blocks_to_mine)\n    }\n\n    async fn do_estimate_gas(\n        &self,\n        request: WithOtherFields<TransactionRequest>,\n        block_number: Option<BlockId>,\n        overrides: EvmOverrides,\n    ) -> Result<u128> {\n        let block_request = self.block_request(block_number).await?;\n        // check if the number predates the fork, if in fork mode\n        if let BlockRequest::Number(number) = block_request\n            && let Some(fork) = self.get_fork()\n            && fork.predates_fork(number)\n        {\n            if overrides.has_state() || overrides.has_block() {\n                return Err(BlockchainError::EvmOverrideError(\n                    \"not available on past forked blocks\".to_string(),\n                ));\n            }\n            return Ok(fork.estimate_gas(&request, Some(number.into())).await?);\n        }\n\n        // this can be blocking for a bit, especially in forking mode\n        // <https://github.com/foundry-rs/foundry/issues/6036>\n        self.on_blocking_task(|this| async move {\n            this.backend\n                .with_database_at(Some(block_request), |state, mut block| {\n                    let mut cache_db = CacheDB::new(state);\n                    if let Some(state_overrides) = overrides.state {\n                        apply_state_overrides(\n                            state_overrides.into_iter().collect(),\n                            &mut cache_db,\n                        )?;\n                    }\n                    if let Some(block_overrides) = overrides.block {\n                        cache_db.apply_block_overrides(*block_overrides, &mut block);\n                    }\n                    this.do_estimate_gas_with_state(request, &cache_db, block)\n                })\n                .await?\n        })\n        .await\n    }\n\n    /// Returns the priority of the transaction based on the current `TransactionOrder`\n    fn transaction_priority(&self, tx: &FoundryTxEnvelope) -> TransactionPriority {\n        self.transaction_order.read().priority(tx)\n    }\n\n    /// Returns a listener for pending transactions, yielding full transactions\n    pub fn full_pending_transactions(&self) -> UnboundedReceiver<AnyRpcTransaction> {\n        let (tx, rx) = unbounded_channel();\n        let mut hashes = self.new_ready_transactions();\n\n        let this = self.clone();\n\n        tokio::spawn(async move {\n            while let Some(hash) = hashes.next().await {\n                if let Ok(Some(txn)) = this.transaction_by_hash(hash).await\n                    && tx.send(txn).is_err()\n                {\n                    break;\n                }\n            }\n        });\n\n        rx\n    }\n\n    /// Mines exactly one block\n    pub async fn mine_one(&self) {\n        let transactions = self.pool.ready_transactions().collect::<Vec<_>>();\n        let outcome = self.backend.mine_block(transactions).await;\n\n        trace!(target: \"node\", blocknumber = ?outcome.block_number, \"mined block\");\n        self.pool.on_mined_block(outcome);\n    }\n\n    /// Returns the pending block with tx hashes\n    async fn pending_block(&self) -> AnyRpcBlock {\n        let transactions = self.pool.ready_transactions().collect::<Vec<_>>();\n        let info = self.backend.pending_block(transactions).await;\n        self.backend.convert_block(info.block)\n    }\n\n    /// Returns the full pending block with `Transaction` objects\n    async fn pending_block_full(&self) -> Option<AnyRpcBlock> {\n        let transactions = self.pool.ready_transactions().collect::<Vec<_>>();\n        let BlockInfo { block, transactions, receipts: _ } =\n            self.backend.pending_block(transactions).await;\n\n        let mut partial_block = self.backend.convert_block(block.clone());\n\n        let mut block_transactions = Vec::with_capacity(block.body.transactions.len());\n        let base_fee = self.backend.base_fee();\n\n        for info in transactions {\n            let tx = block.body.transactions.get(info.transaction_index as usize)?.clone();\n\n            let tx = transaction_build(\n                Some(info.transaction_hash),\n                tx,\n                Some(&block),\n                Some(info),\n                Some(base_fee),\n            );\n            block_transactions.push(tx);\n        }\n\n        partial_block.transactions = BlockTransactions::from(block_transactions);\n\n        Some(partial_block)\n    }\n\n    /// Prepares transaction request by filling missing fields using Anvil's API, then attempts\n    /// to build a [`FoundryTypedTx`].\n    async fn build_tx_request(\n        &self,\n        request: WithOtherFields<TransactionRequest>,\n        nonce: u64,\n    ) -> Result<FoundryTypedTx> {\n        let mut request = Into::<FoundryTransactionRequest>::into(request);\n        let from = request.from().or(self.accounts()?.first().copied());\n\n        // Fill common fields for all tx types\n        request.chain_id().is_none().then(|| request.set_chain_id(self.chain_id()));\n        request.nonce().is_none().then(|| request.set_nonce(nonce));\n        request.kind().is_none().then(|| request.set_kind(TxKind::default()));\n        if request.gas_limit().is_none() {\n            request.set_gas_limit(\n                self.do_estimate_gas(\n                    request.as_ref().clone().into(),\n                    None,\n                    EvmOverrides::default(),\n                )\n                .await\n                .map(|v| v as u64)\n                .unwrap_or(self.backend.gas_limit()),\n            );\n        }\n\n        // Fill missing tx type specific fields\n        if let Err((tx_type, _)) = request.missing_keys() {\n            if matches!(tx_type, FoundryTxType::Legacy | FoundryTxType::Eip2930) {\n                request.gas_price().is_none().then(|| request.set_gas_price(self.gas_price()));\n            }\n            if tx_type == FoundryTxType::Eip2930 {\n                request\n                    .access_list()\n                    .is_none()\n                    .then(|| request.set_access_list(Default::default()));\n            }\n            if matches!(\n                tx_type,\n                FoundryTxType::Eip1559 | FoundryTxType::Eip4844 | FoundryTxType::Eip7702\n            ) {\n                request\n                    .max_fee_per_gas()\n                    .is_none()\n                    .then(|| request.set_max_fee_per_gas(self.gas_price()));\n                request\n                    .max_priority_fee_per_gas()\n                    .is_none()\n                    .then(|| request.set_max_priority_fee_per_gas(MIN_SUGGESTED_PRIORITY_FEE));\n            }\n            if tx_type == FoundryTxType::Eip4844 {\n                request.as_ref().max_fee_per_blob_gas().is_none().then(|| {\n                    request.as_mut().set_max_fee_per_blob_gas(\n                        self.backend.fees().get_next_block_blob_base_fee_per_gas(),\n                    )\n                });\n            }\n        }\n\n        match request\n            .build_unsigned()\n            .map_err(|e| BlockchainError::InvalidTransactionRequest(e.to_string()))?\n        {\n            FoundryTypedTx::Eip4844(TxEip4844Variant::TxEip4844(_))\n                if !self.backend.skip_blob_validation(from) =>\n            {\n                // If blob validation is not skipped, reject TxEip4844 variant without sidecar.\n                Err(BlockchainError::FailedToDecodeTransaction)\n            }\n            res => Ok(res),\n        }\n    }\n\n    /// Returns the nonce of the `address` depending on the `block_number`\n    async fn get_transaction_count(\n        &self,\n        address: Address,\n        block_number: Option<BlockId>,\n    ) -> Result<u64> {\n        let block_request = self.block_request(block_number).await?;\n\n        if let BlockRequest::Number(number) = block_request\n            && let Some(fork) = self.get_fork()\n            && fork.predates_fork(number)\n        {\n            return Ok(fork.get_nonce(address, number).await?);\n        }\n\n        self.backend.get_nonce(address, block_request).await\n    }\n\n    /// Returns the nonce for this request\n    ///\n    /// This returns a tuple of `(request nonce, highest nonce)`\n    /// If the nonce field of the `request` is `None` then the tuple will be `(highest nonce,\n    /// highest nonce)`.\n    ///\n    /// This will also check the tx pool for pending transactions from the sender.\n    async fn request_nonce(\n        &self,\n        request: &TransactionRequest,\n        from: Address,\n    ) -> Result<(u64, u64)> {\n        let highest_nonce =\n            self.get_transaction_count(from, Some(BlockId::Number(BlockNumber::Pending))).await?;\n        let nonce = request.nonce.unwrap_or(highest_nonce);\n\n        Ok((nonce, highest_nonce))\n    }\n\n    /// Adds the given transaction to the pool\n    fn add_pending_transaction(\n        &self,\n        pending_transaction: PendingTransaction<FoundryTxEnvelope>,\n        requires: Vec<TxMarker>,\n        provides: Vec<TxMarker>,\n    ) -> Result<TxHash> {\n        let from = *pending_transaction.sender();\n        let priority = self.transaction_priority(&pending_transaction.transaction);\n        let pool_transaction =\n            PoolTransaction { requires, provides, pending_transaction, priority };\n        let tx = self.pool.add_transaction(pool_transaction)?;\n        trace!(target: \"node\", \"Added transaction: [{:?}] sender={:?}\", tx.hash(), from);\n        Ok(*tx.hash())\n    }\n\n    /// additional validation against hardfork\n    fn ensure_typed_transaction_supported(&self, tx: &FoundryTxEnvelope) -> Result<()> {\n        match &tx {\n            FoundryTxEnvelope::Eip2930(_) => self.backend.ensure_eip2930_active(),\n            FoundryTxEnvelope::Eip1559(_) => self.backend.ensure_eip1559_active(),\n            FoundryTxEnvelope::Eip4844(_) => self.backend.ensure_eip4844_active(),\n            FoundryTxEnvelope::Eip7702(_) => self.backend.ensure_eip7702_active(),\n            FoundryTxEnvelope::Deposit(_) => self.backend.ensure_op_deposits_active(),\n            FoundryTxEnvelope::Legacy(_) => Ok(()),\n            // TODO(onbjerg): we should impl support for Tempo transactions\n            FoundryTxEnvelope::Tempo(_) => todo!(),\n        }\n    }\n}\n\nfn required_marker(provided_nonce: u64, on_chain_nonce: u64, from: Address) -> Vec<TxMarker> {\n    if provided_nonce == on_chain_nonce {\n        return Vec::new();\n    }\n    let prev_nonce = provided_nonce.saturating_sub(1);\n    if on_chain_nonce <= prev_nonce { vec![to_marker(prev_nonce, from)] } else { Vec::new() }\n}\n\nfn convert_transact_out(out: &Option<Output>) -> Bytes {\n    match out {\n        None => Default::default(),\n        Some(Output::Call(out)) => out.to_vec().into(),\n        Some(Output::Create(out, _)) => out.to_vec().into(),\n    }\n}\n\n/// Returns an error if the `exit` code is _not_ ok\nfn ensure_return_ok(exit: InstructionResult, out: &Option<Output>) -> Result<Bytes> {\n    let out = convert_transact_out(out);\n    match exit {\n        return_ok!() => Ok(out),\n        return_revert!() => Err(InvalidTransactionError::Revert(Some(out)).into()),\n        reason => Err(BlockchainError::EvmError(reason)),\n    }\n}\n\n/// Determines the minimum gas needed for a transaction depending on the transaction kind.\nfn determine_base_gas_by_kind(request: &WithOtherFields<TransactionRequest>) -> u128 {\n    match request.kind() {\n        Some(TxKind::Call(_)) => {\n            MIN_TRANSACTION_GAS\n                + request.inner().authorization_list.as_ref().map_or(0, |auths_list| {\n                    auths_list.len() as u128 * PER_EMPTY_ACCOUNT_COST as u128\n                })\n        }\n        Some(TxKind::Create) => MIN_CREATE_GAS,\n        // Tighten the gas limit upwards if we don't know the tx kind to avoid deployments failing.\n        None => MIN_CREATE_GAS,\n    }\n}\n\n/// Keeps result of a call to revm EVM used for gas estimation\nenum GasEstimationCallResult {\n    Success(u128),\n    OutOfGas,\n    Revert(Option<Bytes>),\n    EvmError(InstructionResult),\n}\n\n/// Converts the result of a call to revm EVM into a [`GasEstimationCallResult`].\n///\n/// Expected to stay up to date with: <https://github.com/bluealloy/revm/blob/main/crates/interpreter/src/instruction_result.rs>\nimpl TryFrom<Result<(InstructionResult, Option<Output>, u128, State)>> for GasEstimationCallResult {\n    type Error = BlockchainError;\n\n    fn try_from(res: Result<(InstructionResult, Option<Output>, u128, State)>) -> Result<Self> {\n        match res {\n            // Exceptional case: init used too much gas, treated as out of gas error\n            Err(BlockchainError::InvalidTransaction(InvalidTransactionError::GasTooHigh(_))) => {\n                Ok(Self::OutOfGas)\n            }\n            Err(err) => Err(err),\n            Ok((exit, output, gas, _)) => match exit {\n                return_ok!() => Ok(Self::Success(gas)),\n\n                // Revert opcodes:\n                InstructionResult::Revert => Ok(Self::Revert(output.map(|o| o.into_data()))),\n                InstructionResult::CallTooDeep\n                | InstructionResult::OutOfFunds\n                | InstructionResult::CreateInitCodeStartingEF00\n                | InstructionResult::InvalidEOFInitCode\n                | InstructionResult::InvalidExtDelegateCallTarget => Ok(Self::EvmError(exit)),\n\n                // Out of gas errors:\n                InstructionResult::OutOfGas\n                | InstructionResult::MemoryOOG\n                | InstructionResult::MemoryLimitOOG\n                | InstructionResult::PrecompileOOG\n                | InstructionResult::InvalidOperandOOG\n                | InstructionResult::ReentrancySentryOOG => Ok(Self::OutOfGas),\n\n                // Other errors:\n                InstructionResult::OpcodeNotFound\n                | InstructionResult::CallNotAllowedInsideStatic\n                | InstructionResult::StateChangeDuringStaticCall\n                | InstructionResult::InvalidFEOpcode\n                | InstructionResult::InvalidJump\n                | InstructionResult::NotActivated\n                | InstructionResult::StackUnderflow\n                | InstructionResult::StackOverflow\n                | InstructionResult::OutOfOffset\n                | InstructionResult::CreateCollision\n                | InstructionResult::OverflowPayment\n                | InstructionResult::PrecompileError\n                | InstructionResult::NonceOverflow\n                | InstructionResult::CreateContractSizeLimit\n                | InstructionResult::CreateContractStartingWithEF\n                | InstructionResult::CreateInitCodeSizeLimit\n                | InstructionResult::FatalExternalError => Ok(Self::EvmError(exit)),\n            },\n        }\n    }\n}\n"
  },
  {
    "path": "crates/anvil/src/eth/backend/cheats.rs",
    "content": "//! Support for \"cheat codes\" / bypass functions\n\nuse alloy_evm::precompiles::{Precompile, PrecompileInput};\nuse alloy_primitives::{\n    Address, Bytes,\n    map::{AddressHashSet, foldhash::HashMap},\n};\nuse parking_lot::RwLock;\nuse revm::precompile::{\n    PrecompileError, PrecompileId, PrecompileOutput, PrecompileResult, secp256k1::ec_recover_run,\n    utilities::right_pad,\n};\nuse std::{borrow::Cow, sync::Arc};\n\n/// ID for the [`CheatEcrecover::precompile_id`] precompile.\nstatic PRECOMPILE_ID_CHEAT_ECRECOVER: PrecompileId =\n    PrecompileId::Custom(Cow::Borrowed(\"cheat_ecrecover\"));\n\n/// Manages user modifications that may affect the node's behavior\n///\n/// Contains the state of executed, non-eth standard cheat code RPC\n#[derive(Clone, Debug, Default)]\npub struct CheatsManager {\n    /// shareable state\n    state: Arc<RwLock<CheatsState>>,\n}\n\nimpl CheatsManager {\n    /// Sets the account to impersonate\n    ///\n    /// Returns `true` if the account is already impersonated\n    pub fn impersonate(&self, addr: Address) -> bool {\n        trace!(target: \"cheats\", %addr, \"start impersonating\");\n        // When somebody **explicitly** impersonates an account we need to store it so we are able\n        // to return it from `eth_accounts`. That's why we do not simply call `is_impersonated()`\n        // which does not check that list when auto impersonation is enabled.\n        !self.state.write().impersonated_accounts.insert(addr)\n    }\n\n    /// Removes the account that from the impersonated set\n    pub fn stop_impersonating(&self, addr: &Address) {\n        trace!(target: \"cheats\", %addr, \"stop impersonating\");\n        self.state.write().impersonated_accounts.remove(addr);\n    }\n\n    /// Returns true if the `addr` is currently impersonated\n    pub fn is_impersonated(&self, addr: Address) -> bool {\n        if self.auto_impersonate_accounts() {\n            true\n        } else {\n            self.state.read().impersonated_accounts.contains(&addr)\n        }\n    }\n\n    /// Returns true is auto impersonation is enabled\n    pub fn auto_impersonate_accounts(&self) -> bool {\n        self.state.read().auto_impersonate_accounts\n    }\n\n    /// Sets the auto impersonation flag which if set to true will make the `is_impersonated`\n    /// function always return true\n    pub fn set_auto_impersonate_account(&self, enabled: bool) {\n        trace!(target: \"cheats\", \"Auto impersonation set to {:?}\", enabled);\n        self.state.write().auto_impersonate_accounts = enabled\n    }\n\n    /// Returns all accounts that are currently being impersonated.\n    pub fn impersonated_accounts(&self) -> AddressHashSet {\n        self.state.read().impersonated_accounts.clone()\n    }\n\n    /// Registers an override so that `ecrecover(signature)` returns `addr`.\n    pub fn add_recover_override(&self, sig: Bytes, addr: Address) {\n        self.state.write().signature_overrides.insert(sig, addr);\n    }\n\n    /// If an override exists for `sig`, returns the address; otherwise `None`.\n    pub fn get_recover_override(&self, sig: &Bytes) -> Option<Address> {\n        self.state.read().signature_overrides.get(sig).copied()\n    }\n\n    /// Returns true if any ecrecover overrides have been registered.\n    pub fn has_recover_overrides(&self) -> bool {\n        !self.state.read().signature_overrides.is_empty()\n    }\n}\n\n/// Container type for all the state variables\n#[derive(Clone, Debug, Default)]\npub struct CheatsState {\n    /// All accounts that are currently impersonated\n    pub impersonated_accounts: AddressHashSet,\n    /// If set to true will make the `is_impersonated` function always return true\n    pub auto_impersonate_accounts: bool,\n    /// Overrides for ecrecover: Signature => Address\n    pub signature_overrides: HashMap<Bytes, Address>,\n}\n\nimpl CheatEcrecover {\n    pub fn new(cheats: Arc<CheatsManager>) -> Self {\n        Self { cheats }\n    }\n}\n\nimpl Precompile for CheatEcrecover {\n    fn call(&self, input: PrecompileInput<'_>) -> PrecompileResult {\n        if !self.cheats.has_recover_overrides() {\n            return ec_recover_run(input.data, input.gas);\n        }\n\n        const ECRECOVER_BASE: u64 = 3_000;\n        if input.gas < ECRECOVER_BASE {\n            return Err(PrecompileError::OutOfGas);\n        }\n        let padded = right_pad::<128>(input.data);\n        let v = padded[63];\n        let mut sig_bytes = [0u8; 65];\n        sig_bytes[..64].copy_from_slice(&padded[64..128]);\n        sig_bytes[64] = v;\n        let sig_bytes_wrapped = Bytes::copy_from_slice(&sig_bytes);\n        if let Some(addr) = self.cheats.get_recover_override(&sig_bytes_wrapped) {\n            let mut out = [0u8; 32];\n            out[12..].copy_from_slice(addr.as_slice());\n            return Ok(PrecompileOutput::new(ECRECOVER_BASE, Bytes::copy_from_slice(&out)));\n        }\n        ec_recover_run(input.data, input.gas)\n    }\n\n    fn precompile_id(&self) -> &PrecompileId {\n        &PRECOMPILE_ID_CHEAT_ECRECOVER\n    }\n\n    fn supports_caching(&self) -> bool {\n        false\n    }\n}\n\n/// A custom ecrecover precompile that supports cheat-based signature overrides.\n#[derive(Clone, Debug)]\npub struct CheatEcrecover {\n    cheats: Arc<CheatsManager>,\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn impersonate_returns_false_then_true() {\n        let mgr = CheatsManager::default();\n        let addr = Address::from([1u8; 20]);\n        assert!(!mgr.impersonate(addr));\n        assert!(mgr.impersonate(addr));\n    }\n}\n"
  },
  {
    "path": "crates/anvil/src/eth/backend/db.rs",
    "content": "//! Helper types for working with [revm](foundry_evm::revm)\n\nuse std::{\n    collections::BTreeMap,\n    fmt::{self, Debug},\n    path::Path,\n};\n\nuse alloy_consensus::{BlockBody, Header};\nuse alloy_eips::eip4895::Withdrawals;\nuse alloy_evm::block::StateDB;\nuse alloy_primitives::{\n    Address, B256, Bytes, U256, keccak256,\n    map::{AddressMap, HashMap},\n};\nuse alloy_rpc_types::BlockId;\nuse anvil_core::eth::{\n    block::Block,\n    transaction::{MaybeImpersonatedTransaction, TransactionInfo},\n};\nuse foundry_common::errors::FsPathError;\nuse foundry_evm::backend::{\n    BlockchainDb, DatabaseError, DatabaseResult, MemDb, RevertStateSnapshotAction, StateSnapshot,\n};\nuse foundry_primitives::{FoundryNetwork, FoundryReceiptEnvelope, FoundryTxEnvelope};\nuse revm::{\n    Database, DatabaseCommit,\n    bytecode::Bytecode,\n    context::BlockEnv,\n    context_interface::block::BlobExcessGasAndPrice,\n    database::{CacheDB, DatabaseRef, DbAccount},\n    primitives::{KECCAK_EMPTY, eip4844::BLOB_BASE_FEE_UPDATE_FRACTION_PRAGUE},\n    state::AccountInfo,\n};\nuse serde::{\n    Deserialize, Deserializer, Serialize,\n    de::{Error as DeError, MapAccess, Visitor},\n};\nuse serde_json::Value;\n\nuse crate::mem::storage::MinedTransaction;\n\n/// Helper trait get access to the full state data of the database\npub trait MaybeFullDatabase: DatabaseRef<Error = DatabaseError> + Debug {\n    fn maybe_as_full_db(&self) -> Option<&AddressMap<DbAccount>> {\n        None\n    }\n\n    /// Clear the state and move it into a new `StateSnapshot`.\n    fn clear_into_state_snapshot(&mut self) -> StateSnapshot;\n\n    /// Read the state snapshot.\n    ///\n    /// This clones all the states and returns a new `StateSnapshot`.\n    fn read_as_state_snapshot(&self) -> StateSnapshot;\n\n    /// Clears the entire database\n    fn clear(&mut self);\n\n    /// Reverses `clear_into_snapshot` by initializing the db's state with the state snapshot.\n    fn init_from_state_snapshot(&mut self, state_snapshot: StateSnapshot);\n}\n\nimpl<'a, T: 'a + MaybeFullDatabase + ?Sized> MaybeFullDatabase for &'a T\nwhere\n    &'a T: DatabaseRef<Error = DatabaseError>,\n{\n    fn maybe_as_full_db(&self) -> Option<&AddressMap<DbAccount>> {\n        T::maybe_as_full_db(self)\n    }\n\n    fn clear_into_state_snapshot(&mut self) -> StateSnapshot {\n        unreachable!(\"never called for DatabaseRef\")\n    }\n\n    fn read_as_state_snapshot(&self) -> StateSnapshot {\n        unreachable!(\"never called for DatabaseRef\")\n    }\n\n    fn clear(&mut self) {}\n\n    fn init_from_state_snapshot(&mut self, _state_snapshot: StateSnapshot) {}\n}\n\n/// Helper trait to reset the DB if it's forked\npub trait MaybeForkedDatabase {\n    fn maybe_reset(&mut self, _url: Option<String>, block_number: BlockId) -> Result<(), String>;\n\n    fn maybe_flush_cache(&self) -> Result<(), String>;\n\n    fn maybe_inner(&self) -> Result<&BlockchainDb, String>;\n}\n\n/// `dyn Db` satisfies all `alloy_evm::Database` requirements via its supertraits, but the\n/// blanket impl has an implicit `Sized` bound. Provide an explicit impl.\nimpl alloy_evm::Database for dyn Db {}\n\nimpl StateDB for dyn Db {\n    fn set_state_clear_flag(&mut self, _has_state_clear: bool) {\n        // Anvil does not use the revm State wrapper, so this is a no-op.\n    }\n}\n\n/// A wrapper around [`CacheDB`] that implements [`StateDB`].\n///\n/// `StateDB` is a foreign trait with an orphan-rule constraint, so we cannot\n/// implement it directly for `CacheDB<T>`.  This newtype sidesteps the orphan\n/// rule while delegating all [`Database`], [`DatabaseCommit`] and\n/// [`DatabaseRef`] calls to the inner `CacheDB`.\n#[derive(Debug)]\npub struct AnvilCacheDB<T>(pub CacheDB<T>);\n\nimpl<T: DatabaseRef<Error = DatabaseError>> AnvilCacheDB<T> {\n    pub fn new(inner: T) -> Self {\n        Self(CacheDB::new(inner))\n    }\n}\n\nimpl<T: DatabaseRef<Error = DatabaseError>> std::ops::Deref for AnvilCacheDB<T> {\n    type Target = CacheDB<T>;\n    fn deref(&self) -> &Self::Target {\n        &self.0\n    }\n}\n\nimpl<T: DatabaseRef<Error = DatabaseError>> std::ops::DerefMut for AnvilCacheDB<T> {\n    fn deref_mut(&mut self) -> &mut Self::Target {\n        &mut self.0\n    }\n}\n\nimpl<T: DatabaseRef<Error = DatabaseError> + fmt::Debug> Database for AnvilCacheDB<T> {\n    type Error = DatabaseError;\n\n    fn basic(&mut self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {\n        self.0.basic(address)\n    }\n\n    fn code_by_hash(&mut self, code_hash: B256) -> Result<Bytecode, Self::Error> {\n        self.0.code_by_hash(code_hash)\n    }\n\n    fn storage(&mut self, address: Address, index: U256) -> Result<U256, Self::Error> {\n        self.0.storage(address, index)\n    }\n\n    fn block_hash(&mut self, number: u64) -> Result<B256, Self::Error> {\n        self.0.block_hash(number)\n    }\n}\n\nimpl<T: DatabaseRef<Error = DatabaseError>> DatabaseRef for AnvilCacheDB<T> {\n    type Error = DatabaseError;\n\n    fn basic_ref(&self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {\n        self.0.basic_ref(address)\n    }\n\n    fn code_by_hash_ref(&self, code_hash: B256) -> Result<Bytecode, Self::Error> {\n        self.0.code_by_hash_ref(code_hash)\n    }\n\n    fn storage_ref(&self, address: Address, index: U256) -> Result<U256, Self::Error> {\n        self.0.storage_ref(address, index)\n    }\n\n    fn block_hash_ref(&self, number: u64) -> Result<B256, Self::Error> {\n        self.0.block_hash_ref(number)\n    }\n}\n\nimpl<T: DatabaseRef<Error = DatabaseError> + fmt::Debug> DatabaseCommit for AnvilCacheDB<T> {\n    fn commit(&mut self, changes: revm::state::EvmState) {\n        self.0.commit(changes)\n    }\n}\n\nimpl<T: DatabaseRef<Error = DatabaseError> + fmt::Debug> StateDB for AnvilCacheDB<T> {\n    fn set_state_clear_flag(&mut self, _has_state_clear: bool) {\n        // Anvil does not use the revm State wrapper, so this is a no-op.\n    }\n}\n\n/// This bundles all required revm traits\npub trait Db:\n    DatabaseRef<Error = DatabaseError>\n    + Database<Error = DatabaseError>\n    + DatabaseCommit\n    + MaybeFullDatabase\n    + MaybeForkedDatabase\n    + fmt::Debug\n    + Send\n    + Sync\n{\n    /// Inserts an account\n    fn insert_account(&mut self, address: Address, account: AccountInfo);\n\n    /// Sets the nonce of the given address\n    fn set_nonce(&mut self, address: Address, nonce: u64) -> DatabaseResult<()> {\n        let mut info = self.basic(address)?.unwrap_or_default();\n        info.nonce = nonce;\n        self.insert_account(address, info);\n        Ok(())\n    }\n\n    /// Sets the balance of the given address\n    fn set_balance(&mut self, address: Address, balance: U256) -> DatabaseResult<()> {\n        let mut info = self.basic(address)?.unwrap_or_default();\n        info.balance = balance;\n        self.insert_account(address, info);\n        Ok(())\n    }\n\n    /// Sets the code of the given address\n    fn set_code(&mut self, address: Address, code: Bytes) -> DatabaseResult<()> {\n        let mut info = self.basic(address)?.unwrap_or_default();\n        let code_hash = if code.as_ref().is_empty() {\n            KECCAK_EMPTY\n        } else {\n            B256::from_slice(&keccak256(code.as_ref())[..])\n        };\n        info.code_hash = code_hash;\n        info.code = Some(Bytecode::new_raw(alloy_primitives::Bytes(code.0)));\n        self.insert_account(address, info);\n        Ok(())\n    }\n\n    /// Sets the storage value at the given slot for the address\n    fn set_storage_at(&mut self, address: Address, slot: B256, val: B256) -> DatabaseResult<()>;\n\n    /// inserts a blockhash for the given number\n    fn insert_block_hash(&mut self, number: U256, hash: B256);\n\n    /// Write all chain data to serialized bytes buffer\n    fn dump_state(\n        &self,\n        at: BlockEnv,\n        best_number: u64,\n        blocks: Vec<SerializableBlock>,\n        transactions: Vec<SerializableTransaction>,\n        historical_states: Option<SerializableHistoricalStates>,\n    ) -> DatabaseResult<Option<SerializableState>>;\n\n    /// Deserialize and add all chain data to the backend storage\n    fn load_state(&mut self, state: SerializableState) -> DatabaseResult<bool> {\n        for (addr, account) in state.accounts.into_iter() {\n            let old_account_nonce = DatabaseRef::basic_ref(self, addr)\n                .ok()\n                .and_then(|acc| acc.map(|acc| acc.nonce))\n                .unwrap_or_default();\n            // use max nonce in case account is imported multiple times with difference\n            // nonces to prevent collisions\n            let nonce = std::cmp::max(old_account_nonce, account.nonce);\n\n            self.insert_account(\n                addr,\n                AccountInfo {\n                    balance: account.balance,\n                    code_hash: KECCAK_EMPTY, // will be set automatically\n                    code: if account.code.0.is_empty() {\n                        None\n                    } else {\n                        Some(Bytecode::new_raw(alloy_primitives::Bytes(account.code.0)))\n                    },\n                    nonce,\n                    account_id: None,\n                },\n            );\n\n            for (k, v) in account.storage.into_iter() {\n                self.set_storage_at(addr, k, v)?;\n            }\n        }\n        Ok(true)\n    }\n\n    /// Creates a new state snapshot.\n    fn snapshot_state(&mut self) -> U256;\n\n    /// Reverts a state snapshot.\n    ///\n    /// Returns `true` if the state snapshot was reverted.\n    fn revert_state(&mut self, state_snapshot: U256, action: RevertStateSnapshotAction) -> bool;\n\n    /// Returns the state root if possible to compute\n    fn maybe_state_root(&self) -> Option<B256> {\n        None\n    }\n\n    /// Returns the current, standalone state of the Db\n    fn current_state(&self) -> StateDb;\n}\n\n/// Convenience impl only used to use any `Db` on the fly as the db layer for revm's CacheDB\n/// This is useful to create blocks without actually writing to the `Db`, but rather in the cache of\n/// the `CacheDB` see also\n/// [Backend::pending_block()](crate::eth::backend::mem::Backend::pending_block())\nimpl<T: DatabaseRef<Error = DatabaseError> + Send + Sync + Clone + fmt::Debug> Db for CacheDB<T> {\n    fn insert_account(&mut self, address: Address, account: AccountInfo) {\n        self.insert_account_info(address, account)\n    }\n\n    fn set_storage_at(&mut self, address: Address, slot: B256, val: B256) -> DatabaseResult<()> {\n        self.insert_account_storage(address, slot.into(), val.into())\n    }\n\n    fn insert_block_hash(&mut self, number: U256, hash: B256) {\n        self.cache.block_hashes.insert(number, hash);\n    }\n\n    fn dump_state(\n        &self,\n        _at: BlockEnv,\n        _best_number: u64,\n        _blocks: Vec<SerializableBlock>,\n        _transaction: Vec<SerializableTransaction>,\n        _historical_states: Option<SerializableHistoricalStates>,\n    ) -> DatabaseResult<Option<SerializableState>> {\n        Ok(None)\n    }\n\n    fn snapshot_state(&mut self) -> U256 {\n        U256::ZERO\n    }\n\n    fn revert_state(&mut self, _state_snapshot: U256, _action: RevertStateSnapshotAction) -> bool {\n        false\n    }\n\n    fn current_state(&self) -> StateDb {\n        StateDb::new(MemDb::default())\n    }\n}\n\nimpl<T: DatabaseRef<Error = DatabaseError> + Debug> MaybeFullDatabase for CacheDB<T> {\n    fn maybe_as_full_db(&self) -> Option<&AddressMap<DbAccount>> {\n        Some(&self.cache.accounts)\n    }\n\n    fn clear_into_state_snapshot(&mut self) -> StateSnapshot {\n        let db_accounts = std::mem::take(&mut self.cache.accounts);\n        let mut accounts = HashMap::default();\n        let mut account_storage = HashMap::default();\n\n        for (addr, mut acc) in db_accounts {\n            account_storage.insert(addr, std::mem::take(&mut acc.storage));\n            let mut info = acc.info;\n            info.code = self.cache.contracts.remove(&info.code_hash);\n            accounts.insert(addr, info);\n        }\n        let block_hashes = std::mem::take(&mut self.cache.block_hashes);\n        StateSnapshot { accounts, storage: account_storage, block_hashes }\n    }\n\n    fn read_as_state_snapshot(&self) -> StateSnapshot {\n        let mut accounts = HashMap::default();\n        let mut account_storage = HashMap::default();\n\n        for (addr, acc) in &self.cache.accounts {\n            account_storage.insert(*addr, acc.storage.clone());\n            let mut info = acc.info.clone();\n            info.code = self.cache.contracts.get(&info.code_hash).cloned();\n            accounts.insert(*addr, info);\n        }\n\n        let block_hashes = self.cache.block_hashes.clone();\n        StateSnapshot { accounts, storage: account_storage, block_hashes }\n    }\n\n    fn clear(&mut self) {\n        self.clear_into_state_snapshot();\n    }\n\n    fn init_from_state_snapshot(&mut self, state_snapshot: StateSnapshot) {\n        let StateSnapshot { accounts, mut storage, block_hashes } = state_snapshot;\n\n        for (addr, mut acc) in accounts {\n            if let Some(code) = acc.code.take() {\n                self.cache.contracts.insert(acc.code_hash, code);\n            }\n            self.cache.accounts.insert(\n                addr,\n                DbAccount {\n                    info: acc,\n                    storage: storage.remove(&addr).unwrap_or_default(),\n                    ..Default::default()\n                },\n            );\n        }\n        self.cache.block_hashes = block_hashes;\n    }\n}\n\nimpl<T: DatabaseRef<Error = DatabaseError>> MaybeForkedDatabase for CacheDB<T> {\n    fn maybe_reset(&mut self, _url: Option<String>, _block_number: BlockId) -> Result<(), String> {\n        Err(\"not supported\".to_string())\n    }\n\n    fn maybe_flush_cache(&self) -> Result<(), String> {\n        Err(\"not supported\".to_string())\n    }\n\n    fn maybe_inner(&self) -> Result<&BlockchainDb, String> {\n        Err(\"not supported\".to_string())\n    }\n}\n\n/// Represents a state at certain point\n#[derive(Debug)]\npub struct StateDb(pub(crate) Box<dyn MaybeFullDatabase + Send + Sync>);\n\nimpl StateDb {\n    pub fn new(db: impl MaybeFullDatabase + Send + Sync + 'static) -> Self {\n        Self(Box::new(db))\n    }\n\n    pub fn serialize_state(&mut self) -> StateSnapshot {\n        // Using read_as_snapshot makes sures we don't clear the historical state from the current\n        // instance.\n        self.read_as_state_snapshot()\n    }\n}\n\nimpl DatabaseRef for StateDb {\n    type Error = DatabaseError;\n    fn basic_ref(&self, address: Address) -> DatabaseResult<Option<AccountInfo>> {\n        self.0.basic_ref(address)\n    }\n\n    fn code_by_hash_ref(&self, code_hash: B256) -> DatabaseResult<Bytecode> {\n        self.0.code_by_hash_ref(code_hash)\n    }\n\n    fn storage_ref(&self, address: Address, index: U256) -> DatabaseResult<U256> {\n        self.0.storage_ref(address, index)\n    }\n\n    fn block_hash_ref(&self, number: u64) -> DatabaseResult<B256> {\n        self.0.block_hash_ref(number)\n    }\n}\n\nimpl MaybeFullDatabase for StateDb {\n    fn maybe_as_full_db(&self) -> Option<&AddressMap<DbAccount>> {\n        self.0.maybe_as_full_db()\n    }\n\n    fn clear_into_state_snapshot(&mut self) -> StateSnapshot {\n        self.0.clear_into_state_snapshot()\n    }\n\n    fn read_as_state_snapshot(&self) -> StateSnapshot {\n        self.0.read_as_state_snapshot()\n    }\n\n    fn clear(&mut self) {\n        self.0.clear()\n    }\n\n    fn init_from_state_snapshot(&mut self, state_snapshot: StateSnapshot) {\n        self.0.init_from_state_snapshot(state_snapshot)\n    }\n}\n\n/// Legacy block environment from before v1.3.\n#[derive(Debug, Deserialize)]\n#[serde(rename_all = \"snake_case\")]\npub struct LegacyBlockEnv {\n    pub number: Option<StringOrU64>,\n    #[serde(alias = \"coinbase\")]\n    pub beneficiary: Option<Address>,\n    pub timestamp: Option<StringOrU64>,\n    pub gas_limit: Option<StringOrU64>,\n    pub basefee: Option<StringOrU64>,\n    pub difficulty: Option<StringOrU64>,\n    pub prevrandao: Option<B256>,\n    pub blob_excess_gas_and_price: Option<LegacyBlobExcessGasAndPrice>,\n}\n\n/// Legacy blob excess gas and price structure from before v1.3.\n#[derive(Debug, Deserialize)]\npub struct LegacyBlobExcessGasAndPrice {\n    pub excess_blob_gas: u64,\n    pub blob_gasprice: u64,\n}\n\n/// Legacy string or u64 type from before v1.3.\n#[derive(Debug, Deserialize)]\n#[serde(untagged)]\npub enum StringOrU64 {\n    Hex(String),\n    Dec(u64),\n}\n\nimpl StringOrU64 {\n    pub fn to_u64(&self) -> Option<u64> {\n        match self {\n            Self::Dec(n) => Some(*n),\n            Self::Hex(s) => s.strip_prefix(\"0x\").and_then(|s| u64::from_str_radix(s, 16).ok()),\n        }\n    }\n\n    pub fn to_u256(&self) -> Option<U256> {\n        match self {\n            Self::Dec(n) => Some(U256::from(*n)),\n            Self::Hex(s) => s.strip_prefix(\"0x\").and_then(|s| U256::from_str_radix(s, 16).ok()),\n        }\n    }\n}\n\n/// Converts a `LegacyBlockEnv` to a `BlockEnv`, handling the conversion of legacy fields.\nimpl TryFrom<LegacyBlockEnv> for BlockEnv {\n    type Error = &'static str;\n\n    fn try_from(legacy: LegacyBlockEnv) -> Result<Self, Self::Error> {\n        Ok(Self {\n            number: legacy.number.and_then(|v| v.to_u256()).unwrap_or(U256::ZERO),\n            beneficiary: legacy.beneficiary.unwrap_or(Address::ZERO),\n            timestamp: legacy.timestamp.and_then(|v| v.to_u256()).unwrap_or(U256::ONE),\n            gas_limit: legacy.gas_limit.and_then(|v| v.to_u64()).unwrap_or(u64::MAX),\n            basefee: legacy.basefee.and_then(|v| v.to_u64()).unwrap_or(0),\n            difficulty: legacy.difficulty.and_then(|v| v.to_u256()).unwrap_or(U256::ZERO),\n            prevrandao: legacy.prevrandao.or(Some(B256::ZERO)),\n            blob_excess_gas_and_price: legacy\n                .blob_excess_gas_and_price\n                .map(|v| BlobExcessGasAndPrice::new(v.excess_blob_gas, v.blob_gasprice))\n                .or_else(|| {\n                    Some(BlobExcessGasAndPrice::new(0, BLOB_BASE_FEE_UPDATE_FRACTION_PRAGUE))\n                }),\n        })\n    }\n}\n\n/// Custom deserializer for `BlockEnv` that handles both v1.2 and v1.3+ formats.\nfn deserialize_block_env_compat<'de, D>(deserializer: D) -> Result<Option<BlockEnv>, D::Error>\nwhere\n    D: Deserializer<'de>,\n{\n    let value: Option<Value> = Option::deserialize(deserializer)?;\n    let Some(value) = value else {\n        return Ok(None);\n    };\n\n    if let Ok(env) = BlockEnv::deserialize(&value) {\n        return Ok(Some(env));\n    }\n\n    let legacy: LegacyBlockEnv = serde_json::from_value(value).map_err(|e| {\n        D::Error::custom(format!(\"Legacy deserialization of `BlockEnv` failed: {e}\"))\n    })?;\n\n    Ok(Some(BlockEnv::try_from(legacy).map_err(D::Error::custom)?))\n}\n\n/// Custom deserializer for `best_block_number` that handles both v1.2 and v1.3+ formats.\nfn deserialize_best_block_number_compat<'de, D>(deserializer: D) -> Result<Option<u64>, D::Error>\nwhere\n    D: Deserializer<'de>,\n{\n    let value: Option<Value> = Option::deserialize(deserializer)?;\n    let Some(value) = value else {\n        return Ok(None);\n    };\n\n    let number = match value {\n        Value::Number(n) => n.as_u64(),\n        Value::String(s) => {\n            if let Some(s) = s.strip_prefix(\"0x\") {\n                u64::from_str_radix(s, 16).ok()\n            } else {\n                s.parse().ok()\n            }\n        }\n        _ => None,\n    };\n\n    Ok(number)\n}\n\n#[derive(Clone, Debug, Default, Serialize, Deserialize)]\npub struct SerializableState {\n    /// The block number of the state\n    ///\n    /// Note: This is an Option for backwards compatibility: <https://github.com/foundry-rs/foundry/issues/5460>\n    #[serde(deserialize_with = \"deserialize_block_env_compat\")]\n    pub block: Option<BlockEnv>,\n    pub accounts: BTreeMap<Address, SerializableAccountRecord>,\n    /// The best block number of the state, can be different from block number (Arbitrum chain).\n    #[serde(deserialize_with = \"deserialize_best_block_number_compat\")]\n    pub best_block_number: Option<u64>,\n    #[serde(default)]\n    pub blocks: Vec<SerializableBlock>,\n    #[serde(default)]\n    pub transactions: Vec<SerializableTransaction>,\n    /// Historical states of accounts and storage at particular block hashes.\n    ///\n    /// Note: This is an Option for backwards compatibility.\n    #[serde(default)]\n    pub historical_states: Option<SerializableHistoricalStates>,\n}\n\nimpl SerializableState {\n    /// Loads the `Genesis` object from the given json file path\n    pub fn load(path: impl AsRef<Path>) -> Result<Self, FsPathError> {\n        let path = path.as_ref();\n        if path.is_dir() {\n            foundry_common::fs::read_json_file(&path.join(\"state.json\"))\n        } else {\n            foundry_common::fs::read_json_file(path)\n        }\n    }\n\n    /// This is used as the clap `value_parser` implementation\n    #[cfg(feature = \"cmd\")]\n    pub(crate) fn parse(path: &str) -> Result<Self, String> {\n        Self::load(path).map_err(|err| err.to_string())\n    }\n}\n\n#[derive(Clone, Debug, Serialize, Deserialize)]\npub struct SerializableAccountRecord {\n    pub nonce: u64,\n    pub balance: U256,\n    pub code: Bytes,\n\n    #[serde(deserialize_with = \"deserialize_btree\")]\n    pub storage: BTreeMap<B256, B256>,\n}\n\nfn deserialize_btree<'de, D>(deserializer: D) -> Result<BTreeMap<B256, B256>, D::Error>\nwhere\n    D: Deserializer<'de>,\n{\n    struct BTreeVisitor;\n\n    impl<'de> Visitor<'de> for BTreeVisitor {\n        type Value = BTreeMap<B256, B256>;\n\n        fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {\n            formatter.write_str(\"a mapping of hex encoded storage slots to hex encoded state data\")\n        }\n\n        fn visit_map<M>(self, mut mapping: M) -> Result<BTreeMap<B256, B256>, M::Error>\n        where\n            M: MapAccess<'de>,\n        {\n            let mut btree = BTreeMap::new();\n            while let Some((key, value)) = mapping.next_entry::<U256, U256>()? {\n                btree.insert(B256::from(key), B256::from(value));\n            }\n\n            Ok(btree)\n        }\n    }\n\n    deserializer.deserialize_map(BTreeVisitor)\n}\n\n/// Defines a backwards-compatible enum for transactions.\n/// This is essential for maintaining compatibility with state dumps\n/// created before the changes introduced in PR #8411.\n///\n/// The enum can represent either a `TypedTransaction` or a `MaybeImpersonatedTransaction`,\n/// depending on the data being deserialized. This flexibility ensures that older state\n/// dumps can still be loaded correctly, even after the changes in #8411.\n#[derive(Clone, Debug, Serialize, Deserialize)]\n#[serde(untagged)]\npub enum SerializableTransactionType {\n    TypedTransaction(FoundryTxEnvelope),\n    MaybeImpersonatedTransaction(MaybeImpersonatedTransaction<FoundryTxEnvelope>),\n}\n\n#[derive(Clone, Debug, Serialize, Deserialize)]\npub struct SerializableBlock {\n    pub header: Header,\n    pub transactions: Vec<SerializableTransactionType>,\n    pub ommers: Vec<Header>,\n    #[serde(default)]\n    pub withdrawals: Option<Withdrawals>,\n}\n\nimpl From<Block> for SerializableBlock {\n    fn from(block: Block) -> Self {\n        Self {\n            header: block.header,\n            transactions: block.body.transactions.into_iter().map(Into::into).collect(),\n            ommers: block.body.ommers.into_iter().collect(),\n            withdrawals: block.body.withdrawals,\n        }\n    }\n}\n\nimpl From<SerializableBlock> for Block {\n    fn from(block: SerializableBlock) -> Self {\n        let transactions = block.transactions.into_iter().map(Into::into).collect();\n        let ommers = block.ommers;\n        let body = BlockBody { transactions, ommers, withdrawals: block.withdrawals };\n        Self::new(block.header, body)\n    }\n}\n\nimpl From<MaybeImpersonatedTransaction<FoundryTxEnvelope>> for SerializableTransactionType {\n    fn from(transaction: MaybeImpersonatedTransaction<FoundryTxEnvelope>) -> Self {\n        Self::MaybeImpersonatedTransaction(transaction)\n    }\n}\n\nimpl From<SerializableTransactionType> for MaybeImpersonatedTransaction<FoundryTxEnvelope> {\n    fn from(transaction: SerializableTransactionType) -> Self {\n        match transaction {\n            SerializableTransactionType::TypedTransaction(tx) => Self::new(tx),\n            SerializableTransactionType::MaybeImpersonatedTransaction(tx) => tx,\n        }\n    }\n}\n\n#[derive(Clone, Debug, Serialize, Deserialize)]\npub struct SerializableTransaction {\n    pub info: TransactionInfo,\n    pub receipt: FoundryReceiptEnvelope,\n    pub block_hash: B256,\n    pub block_number: u64,\n}\n\nimpl From<MinedTransaction<FoundryNetwork>> for SerializableTransaction {\n    fn from(transaction: MinedTransaction<FoundryNetwork>) -> Self {\n        Self {\n            info: transaction.info,\n            receipt: transaction.receipt,\n            block_hash: transaction.block_hash,\n            block_number: transaction.block_number,\n        }\n    }\n}\n\nimpl From<SerializableTransaction> for MinedTransaction<FoundryNetwork> {\n    fn from(transaction: SerializableTransaction) -> Self {\n        Self {\n            info: transaction.info,\n            receipt: transaction.receipt,\n            block_hash: transaction.block_hash,\n            block_number: transaction.block_number,\n        }\n    }\n}\n\n#[derive(Clone, Debug, Serialize, Deserialize, Default)]\npub struct SerializableHistoricalStates(Vec<(B256, StateSnapshot)>);\n\nimpl SerializableHistoricalStates {\n    pub const fn new(states: Vec<(B256, StateSnapshot)>) -> Self {\n        Self(states)\n    }\n}\n\nimpl IntoIterator for SerializableHistoricalStates {\n    type Item = (B256, StateSnapshot);\n    type IntoIter = std::vec::IntoIter<Self::Item>;\n\n    fn into_iter(self) -> Self::IntoIter {\n        self.0.into_iter()\n    }\n}\n\n#[cfg(test)]\nmod test {\n    use super::*;\n\n    #[test]\n    fn test_deser_block() {\n        let block = r#\"{\n            \"header\": {\n                \"parentHash\": \"0xceb0fe420d6f14a8eeec4319515b89acbb0bb4861cad9983d529ab4b1e4af929\",\n                \"sha3Uncles\": \"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347\",\n                \"miner\": \"0x0000000000000000000000000000000000000000\",\n                \"stateRoot\": \"0xe1423fd180478ab4fd05a7103277d64496b15eb914ecafe71eeec871b552efd1\",\n                \"transactionsRoot\": \"0x2b5598ef261e5f88e4303bb2b3986b3d5c0ebf4cd9977daebccae82a6469b988\",\n                \"receiptsRoot\": \"0xf78dfb743fbd92ade140711c8bbc542b5e307f0ab7984eff35d751969fe57efa\",\n                \"logsBloom\": \"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\n                \"difficulty\": \"0x0\",\n                \"number\": \"0x2\",\n                \"gasLimit\": \"0x1c9c380\",\n                \"gasUsed\": \"0x5208\",\n                \"timestamp\": \"0x66cdc823\",\n                \"mixHash\": \"0x0000000000000000000000000000000000000000000000000000000000000000\",\n                \"nonce\": \"0x0000000000000000\",\n                \"baseFeePerGas\": \"0x342a1c58\",\n                \"blobGasUsed\": \"0x0\",\n                \"excessBlobGas\": \"0x0\",\n                \"extraData\": \"0x\"\n            },\n            \"transactions\": [\n                {\n                    \"type\": \"0x2\",\n                    \"chainId\": \"0x7a69\",\n                    \"nonce\": \"0x0\",\n                    \"gas\": \"0x5209\",\n                    \"maxFeePerGas\": \"0x77359401\",\n                    \"maxPriorityFeePerGas\": \"0x1\",\n                    \"to\": \"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266\",\n                    \"value\": \"0x0\",\n                    \"accessList\": [],\n                    \"input\": \"0x\",\n                    \"r\": \"0x85c2794a580da137e24ccc823b45ae5cea99371ae23ee13860fcc6935f8305b0\",\n                    \"s\": \"0x41de7fa4121dab284af4453d30928241208bafa90cdb701fe9bc7054759fe3cd\",\n                    \"yParity\": \"0x0\",\n                    \"hash\": \"0x8c9b68e8947ace33028dba167354fde369ed7bbe34911b772d09b3c64b861515\"\n                }\n            ],\n            \"ommers\": []\n        }\n        \"#;\n\n        let _block: SerializableBlock = serde_json::from_str(block).unwrap();\n    }\n\n    #[test]\n    fn test_block_withdrawals_preserved() {\n        use alloy_eips::eip4895::Withdrawal;\n\n        // create a block with withdrawals (like post-Shanghai blocks)\n        let withdrawal = Withdrawal {\n            index: 42,\n            validator_index: 123,\n            address: Address::repeat_byte(1),\n            amount: 1000,\n        };\n\n        let header = Header::default();\n        let body = BlockBody {\n            transactions: vec![],\n            ommers: vec![],\n            withdrawals: Some(vec![withdrawal].into()),\n        };\n        let block = Block::new(header, body);\n\n        // convert to SerializableBlock and back\n        let serializable = SerializableBlock::from(block);\n        let restored = Block::from(serializable);\n\n        // withdrawals should be preserved\n        assert!(restored.body.withdrawals.is_some());\n        let withdrawals = restored.body.withdrawals.unwrap();\n        assert_eq!(withdrawals.len(), 1);\n        assert_eq!(withdrawals[0].index, 42);\n        assert_eq!(withdrawals[0].validator_index, 123);\n    }\n}\n"
  },
  {
    "path": "crates/anvil/src/eth/backend/env.rs",
    "content": "use alloy_evm::EvmEnv;\nuse foundry_evm_networks::NetworkConfigs;\nuse op_revm::OpTransaction;\nuse revm::context::TxEnv;\n\n/// Helper container type for [`EvmEnv`] and [`OpTransaction<TxEnd>`].\n#[derive(Clone, Debug, Default)]\npub struct Env {\n    pub evm_env: EvmEnv,\n    pub tx: OpTransaction<TxEnv>,\n    pub networks: NetworkConfigs,\n}\n\n/// Helper container type for [`EvmEnv`] and [`OpTransaction<TxEnv>`].\nimpl Env {\n    pub fn new(evm_env: EvmEnv, tx: OpTransaction<TxEnv>, networks: NetworkConfigs) -> Self {\n        Self { evm_env, tx, networks }\n    }\n}\n"
  },
  {
    "path": "crates/anvil/src/eth/backend/executor.rs",
    "content": "use crate::{\n    eth::backend::{cheats::CheatsManager, env::Env},\n    mem::inspector::AnvilInspector,\n};\nuse alloy_consensus::{Eip658Value, Transaction, TransactionEnvelope, transaction::Either};\nuse alloy_eips::{\n    Encodable2718, eip2935, eip4788,\n    eip7702::{RecoveredAuthority, RecoveredAuthorization},\n};\nuse alloy_evm::{\n    EthEvmFactory, Evm, EvmEnv, EvmFactory, FromRecoveredTx, FromTxWithEncoded, RecoveredTx,\n    block::{\n        BlockExecutionError, BlockExecutionResult, BlockExecutor, BlockValidationError,\n        ExecutableTx, OnStateHook, StateChangeSource, StateDB, TxResult,\n    },\n    eth::{\n        EthEvmContext, EthTxResult,\n        receipt_builder::{ReceiptBuilder, ReceiptBuilderCtx},\n    },\n    precompiles::PrecompilesMap,\n};\nuse alloy_op_evm::OpEvmFactory;\nuse alloy_primitives::{Address, B256, Bytes};\nuse anvil_core::eth::transaction::PendingTransaction;\nuse foundry_evm::{backend::DatabaseError, core::either_evm::EitherEvm};\nuse foundry_evm_networks::NetworkConfigs;\nuse foundry_primitives::{FoundryReceiptEnvelope, FoundryTxEnvelope, FoundryTxType};\nuse op_revm::{OpContext, OpTransaction};\nuse revm::{\n    Database, DatabaseCommit, Inspector,\n    context::{Block as RevmBlock, TxEnv},\n    context_interface::result::ResultAndState,\n};\nuse std::{fmt, fmt::Debug};\n\n/// Receipt builder for Foundry/Anvil that handles all transaction types\n#[derive(Debug, Default, Clone, Copy)]\n#[non_exhaustive]\npub struct FoundryReceiptBuilder;\n\nimpl ReceiptBuilder for FoundryReceiptBuilder {\n    type Transaction = FoundryTxEnvelope;\n    type Receipt = FoundryReceiptEnvelope;\n\n    fn build_receipt<E: Evm>(\n        &self,\n        ctx: ReceiptBuilderCtx<'_, FoundryTxType, E>,\n    ) -> FoundryReceiptEnvelope {\n        let receipt = alloy_consensus::Receipt {\n            status: Eip658Value::Eip658(ctx.result.is_success()),\n            cumulative_gas_used: ctx.cumulative_gas_used,\n            logs: ctx.result.into_logs(),\n        }\n        .with_bloom();\n\n        match ctx.tx_type {\n            FoundryTxType::Legacy => FoundryReceiptEnvelope::Legacy(receipt),\n            FoundryTxType::Eip2930 => FoundryReceiptEnvelope::Eip2930(receipt),\n            FoundryTxType::Eip1559 => FoundryReceiptEnvelope::Eip1559(receipt),\n            FoundryTxType::Eip4844 => FoundryReceiptEnvelope::Eip4844(receipt),\n            FoundryTxType::Eip7702 => FoundryReceiptEnvelope::Eip7702(receipt),\n            FoundryTxType::Deposit => {\n                unreachable!(\"deposit receipts are built in commit_transaction\")\n            }\n            FoundryTxType::Tempo => FoundryReceiptEnvelope::Tempo(receipt),\n        }\n    }\n}\n\n/// Result of executing a transaction in [`AnvilBlockExecutor`].\n///\n/// Wraps [`EthTxResult`] with the sender address, needed for deposit nonce resolution.\n#[derive(Debug)]\npub struct AnvilTxResult<H> {\n    pub inner: EthTxResult<H, FoundryTxType>,\n    pub sender: Address,\n}\n\nimpl<H> TxResult for AnvilTxResult<H> {\n    type HaltReason = H;\n\n    fn result(&self) -> &ResultAndState<Self::HaltReason> {\n        self.inner.result()\n    }\n}\n\n/// Execution context for [`AnvilBlockExecutor`], providing block-level data\n/// needed for pre/post execution system calls.\n#[derive(Debug, Clone)]\npub struct AnvilExecutionCtx {\n    /// Parent block hash — needed for EIP-2935 system call.\n    pub parent_hash: B256,\n    /// Whether Prague hardfork is active.\n    pub is_prague: bool,\n    /// Whether Cancun hardfork is active.\n    pub is_cancun: bool,\n}\n\n/// Block executor for Anvil that implements [`BlockExecutor`].\n///\n/// Wraps an EVM instance and produces [`FoundryReceiptEnvelope`] receipts.\n/// Validation (gas limits, blob gas, transaction validity) is handled by the\n/// caller before transactions are fed to this executor.\npub struct AnvilBlockExecutor<E> {\n    /// The EVM instance used for execution.\n    evm: E,\n    /// Execution context.\n    ctx: AnvilExecutionCtx,\n    /// Receipt builder.\n    receipt_builder: FoundryReceiptBuilder,\n    /// Receipts of executed transactions.\n    receipts: Vec<FoundryReceiptEnvelope>,\n    /// Total gas used by transactions in this block.\n    gas_used: u64,\n    /// Blob gas used by the block.\n    blob_gas_used: u64,\n    /// Optional state change hook.\n    state_hook: Option<Box<dyn OnStateHook>>,\n}\n\nimpl<E: fmt::Debug> fmt::Debug for AnvilBlockExecutor<E> {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.debug_struct(\"AnvilBlockExecutor\")\n            .field(\"evm\", &self.evm)\n            .field(\"ctx\", &self.ctx)\n            .field(\"gas_used\", &self.gas_used)\n            .field(\"blob_gas_used\", &self.blob_gas_used)\n            .field(\"receipts\", &self.receipts.len())\n            .finish_non_exhaustive()\n    }\n}\n\nimpl<E> AnvilBlockExecutor<E> {\n    /// Creates a new [`AnvilBlockExecutor`].\n    pub fn new(evm: E, ctx: AnvilExecutionCtx) -> Self {\n        Self {\n            evm,\n            ctx,\n            receipt_builder: FoundryReceiptBuilder,\n            receipts: Vec::new(),\n            gas_used: 0,\n            blob_gas_used: 0,\n            state_hook: None,\n        }\n    }\n}\n\nimpl<E> BlockExecutor for AnvilBlockExecutor<E>\nwhere\n    E: Evm<\n            DB: StateDB,\n            Tx: FromRecoveredTx<FoundryTxEnvelope> + FromTxWithEncoded<FoundryTxEnvelope>,\n        >,\n{\n    type Transaction = FoundryTxEnvelope;\n    type Receipt = FoundryReceiptEnvelope;\n    type Evm = E;\n    type Result = AnvilTxResult<E::HaltReason>;\n\n    fn apply_pre_execution_changes(&mut self) -> Result<(), BlockExecutionError> {\n        // EIP-2935: store parent block hash in history storage contract.\n        if self.ctx.is_prague {\n            let result = self\n                .evm\n                .transact_system_call(\n                    eip4788::SYSTEM_ADDRESS,\n                    eip2935::HISTORY_STORAGE_ADDRESS,\n                    Bytes::copy_from_slice(self.ctx.parent_hash.as_slice()),\n                )\n                .map_err(BlockExecutionError::other)?;\n\n            if let Some(hook) = &mut self.state_hook {\n                hook.on_state(\n                    StateChangeSource::PreBlock(\n                        alloy_evm::block::StateChangePreBlockSource::BlockHashesContract,\n                    ),\n                    &result.state,\n                );\n            }\n            self.evm.db_mut().commit(result.state);\n        }\n        Ok(())\n    }\n\n    fn execute_transaction_without_commit(\n        &mut self,\n        tx: impl ExecutableTx<Self>,\n    ) -> Result<Self::Result, BlockExecutionError> {\n        let (tx_env, tx) = tx.into_parts();\n\n        let block_available_gas = self.evm.block().gas_limit() - self.gas_used;\n        if tx.tx().gas_limit() > block_available_gas {\n            return Err(BlockValidationError::TransactionGasLimitMoreThanAvailableBlockGas {\n                transaction_gas_limit: tx.tx().gas_limit(),\n                block_available_gas,\n            }\n            .into());\n        }\n\n        let sender = *tx.signer();\n\n        let result = self.evm.transact(tx_env).map_err(|err| {\n            let hash = tx.tx().trie_hash();\n            BlockExecutionError::evm(err, hash)\n        })?;\n\n        Ok(AnvilTxResult {\n            inner: EthTxResult {\n                result,\n                blob_gas_used: tx.tx().blob_gas_used().unwrap_or_default(),\n                tx_type: tx.tx().tx_type(),\n            },\n            sender,\n        })\n    }\n\n    fn commit_transaction(&mut self, output: Self::Result) -> Result<u64, BlockExecutionError> {\n        let AnvilTxResult {\n            inner: EthTxResult { result: ResultAndState { result, state }, blob_gas_used, tx_type },\n            sender,\n        } = output;\n\n        if let Some(hook) = &mut self.state_hook {\n            hook.on_state(StateChangeSource::Transaction(self.receipts.len()), &state);\n        }\n\n        let gas_used = result.gas_used();\n        self.gas_used += gas_used;\n\n        if self.ctx.is_cancun {\n            self.blob_gas_used = self.blob_gas_used.saturating_add(blob_gas_used);\n        }\n\n        let receipt = if tx_type == FoundryTxType::Deposit {\n            let deposit_nonce = state.get(&sender).map(|acc| acc.info.nonce);\n            let receipt = alloy_consensus::Receipt {\n                status: Eip658Value::Eip658(result.is_success()),\n                cumulative_gas_used: self.gas_used,\n                logs: result.into_logs(),\n            }\n            .with_bloom();\n            FoundryReceiptEnvelope::Deposit(op_alloy_consensus::OpDepositReceiptWithBloom {\n                receipt: op_alloy_consensus::OpDepositReceipt {\n                    inner: receipt.receipt,\n                    deposit_nonce,\n                    deposit_receipt_version: deposit_nonce.map(|_| 1),\n                },\n                logs_bloom: receipt.logs_bloom,\n            })\n        } else {\n            self.receipt_builder.build_receipt(ReceiptBuilderCtx {\n                tx_type,\n                evm: &self.evm,\n                result,\n                state: &state,\n                cumulative_gas_used: self.gas_used,\n            })\n        };\n\n        self.receipts.push(receipt);\n        self.evm.db_mut().commit(state);\n\n        Ok(gas_used)\n    }\n\n    fn finish(\n        self,\n    ) -> Result<(Self::Evm, BlockExecutionResult<FoundryReceiptEnvelope>), BlockExecutionError>\n    {\n        Ok((\n            self.evm,\n            BlockExecutionResult {\n                receipts: self.receipts,\n                requests: Default::default(),\n                gas_used: self.gas_used,\n                blob_gas_used: self.blob_gas_used,\n            },\n        ))\n    }\n\n    fn set_state_hook(&mut self, hook: Option<Box<dyn OnStateHook>>) {\n        self.state_hook = hook;\n    }\n\n    fn evm_mut(&mut self) -> &mut Self::Evm {\n        &mut self.evm\n    }\n\n    fn evm(&self) -> &Self::Evm {\n        &self.evm\n    }\n\n    fn receipts(&self) -> &[FoundryReceiptEnvelope] {\n        &self.receipts\n    }\n}\n\npub struct AnvilBlockExecutorFactory;\n\nimpl AnvilBlockExecutorFactory {\n    pub fn create_executor<DB>(\n        evm: EitherEvm<DB, AnvilInspector, PrecompilesMap>,\n        ctx: AnvilExecutionCtx,\n    ) -> AnvilBlockExecutor<EitherEvm<DB, AnvilInspector, PrecompilesMap>>\n    where\n        DB: StateDB,\n    {\n        AnvilBlockExecutor::new(evm, ctx)\n    }\n}\n\n/// Builds the per-tx `OpTransaction<TxEnv>` from a pending transaction, replicating the logic\n/// from `TransactionExecutor::env_for`.\npub fn build_tx_env_for_pending(\n    tx: &PendingTransaction<FoundryTxEnvelope>,\n    cheats: &CheatsManager,\n    networks: NetworkConfigs,\n    _evm_env: &EvmEnv,\n) -> OpTransaction<TxEnv> {\n    let mut tx_env: OpTransaction<TxEnv> =\n        FromRecoveredTx::from_recovered_tx(tx.transaction.as_ref(), *tx.sender());\n\n    if let FoundryTxEnvelope::Eip7702(tx_7702) = tx.transaction.as_ref()\n        && cheats.has_recover_overrides()\n    {\n        let cheated_auths = tx_7702\n            .tx()\n            .authorization_list\n            .iter()\n            .zip(tx_env.base.authorization_list)\n            .map(|(signed_auth, either_auth)| {\n                either_auth.right_and_then(|recovered_auth| {\n                    if recovered_auth.authority().is_none()\n                        && let Ok(signature) = signed_auth.signature()\n                        && let Some(override_addr) =\n                            cheats.get_recover_override(&signature.as_bytes().into())\n                    {\n                        Either::Right(RecoveredAuthorization::new_unchecked(\n                            recovered_auth.into_parts().0,\n                            RecoveredAuthority::Valid(override_addr),\n                        ))\n                    } else {\n                        Either::Right(recovered_auth)\n                    }\n                })\n            })\n            .collect();\n        tx_env.base.authorization_list = cheated_auths;\n    }\n\n    if networks.is_optimism() {\n        tx_env.enveloped_tx = Some(tx.transaction.encoded_2718().into());\n    }\n\n    tx_env\n}\n\n/// Creates a database with given database and inspector.\npub fn new_eth_evm_with_inspector<DB, I>(\n    db: DB,\n    env: &Env,\n    inspector: I,\n) -> EitherEvm<DB, I, PrecompilesMap>\nwhere\n    DB: Database<Error = DatabaseError> + Debug,\n    I: Inspector<EthEvmContext<DB>> + Inspector<OpContext<DB>>,\n{\n    if env.networks.is_optimism() {\n        let evm_env = EvmEnv::new(\n            env.evm_env\n                .cfg_env\n                .clone()\n                .with_spec_and_mainnet_gas_params(op_revm::OpSpecId::ISTHMUS),\n            env.evm_env.block_env.clone(),\n        );\n        EitherEvm::Op(OpEvmFactory::default().create_evm_with_inspector(db, evm_env, inspector))\n    } else {\n        EitherEvm::Eth(EthEvmFactory::default().create_evm_with_inspector(\n            db,\n            env.evm_env.clone(),\n            inspector,\n        ))\n    }\n}\n"
  },
  {
    "path": "crates/anvil/src/eth/backend/fork.rs",
    "content": "//! Support for forking off another client\n\nuse crate::eth::{backend::db::Db, error::BlockchainError, pool::transactions::PoolTransaction};\nuse alloy_consensus::{BlockHeader, TrieAccount};\nuse alloy_eips::eip2930::AccessListResult;\nuse alloy_network::{\n    AnyNetwork, AnyRpcBlock, BlockResponse, Network, TransactionResponse,\n    primitives::HeaderResponse,\n};\nuse alloy_primitives::{\n    Address, B256, Bytes, StorageValue, U256,\n    map::{FbHashMap, HashMap, HashSet},\n};\nuse alloy_provider::{\n    Provider,\n    ext::{DebugApi, TraceApi},\n};\nuse alloy_rpc_types::{\n    BlockId, BlockNumberOrTag as BlockNumber, BlockTransactions, EIP1186AccountProofResponse,\n    FeeHistory, Filter, Log,\n    simulate::{SimulatePayload, SimulatedBlock},\n    trace::{\n        geth::{GethDebugTracingOptions, GethTrace},\n        parity::{LocalizedTransactionTrace as Trace, TraceResultsWithTransactionHash, TraceType},\n    },\n};\nuse alloy_transport::TransportError;\nuse foundry_common::provider::{ProviderBuilder, RetryProvider};\nuse foundry_primitives::{FoundryTxEnvelope, FoundryTxReceipt};\nuse parking_lot::{\n    RawRwLock, RwLock,\n    lock_api::{RwLockReadGuard, RwLockWriteGuard},\n};\nuse revm::context_interface::block::BlobExcessGasAndPrice;\nuse std::{sync::Arc, time::Duration};\nuse tokio::sync::RwLock as AsyncRwLock;\n\n/// Represents a fork of a remote client\n///\n/// This type contains a subset of the [`EthApi`](crate::eth::EthApi) functions but will exclusively\n/// fetch the requested data from the remote client, if it wasn't already fetched.\n#[derive(Clone, Debug)]\npub struct ClientFork<N: Network = AnyNetwork> {\n    /// Contains the cached data\n    pub storage: Arc<RwLock<ForkedStorage<N>>>,\n    /// contains the info how the fork is configured\n    // Wrapping this in a lock, ensures we can update this on the fly via additional custom RPC\n    // endpoints\n    pub config: Arc<RwLock<ClientForkConfig<N>>>,\n    /// This also holds a handle to the underlying database\n    pub database: Arc<AsyncRwLock<Box<dyn Db>>>,\n}\n\nimpl<N: Network> ClientFork<N> {\n    /// Creates a new instance of the fork\n    pub fn new(config: ClientForkConfig<N>, database: Arc<AsyncRwLock<Box<dyn Db>>>) -> Self {\n        Self { storage: Default::default(), config: Arc::new(RwLock::new(config)), database }\n    }\n\n    /// Removes all data cached from previous responses\n    pub fn clear_cached_storage(&self) {\n        self.storage.write().clear()\n    }\n\n    /// Returns true whether the block predates the fork\n    pub fn predates_fork(&self, block: u64) -> bool {\n        block < self.block_number()\n    }\n\n    /// Returns true whether the block predates the fork _or_ is the same block as the fork\n    pub fn predates_fork_inclusive(&self, block: u64) -> bool {\n        block <= self.block_number()\n    }\n\n    pub fn timestamp(&self) -> u64 {\n        self.config.read().timestamp\n    }\n\n    pub fn block_number(&self) -> u64 {\n        self.config.read().block_number\n    }\n\n    /// Returns the transaction hash we forked off of, if any.\n    pub fn transaction_hash(&self) -> Option<B256> {\n        self.config.read().transaction_hash\n    }\n\n    pub fn total_difficulty(&self) -> U256 {\n        self.config.read().total_difficulty\n    }\n\n    pub fn base_fee(&self) -> Option<u128> {\n        self.config.read().base_fee\n    }\n\n    pub fn block_hash(&self) -> B256 {\n        self.config.read().block_hash\n    }\n\n    pub fn eth_rpc_url(&self) -> String {\n        self.config.read().eth_rpc_url.clone()\n    }\n\n    pub fn chain_id(&self) -> u64 {\n        self.config.read().chain_id\n    }\n\n    fn provider(&self) -> Arc<RetryProvider<N>> {\n        self.config.read().provider.clone()\n    }\n\n    fn storage_read(&self) -> RwLockReadGuard<'_, RawRwLock, ForkedStorage<N>> {\n        self.storage.read()\n    }\n\n    fn storage_write(&self) -> RwLockWriteGuard<'_, RawRwLock, ForkedStorage<N>> {\n        self.storage.write()\n    }\n\n    /// Returns the fee history  `eth_feeHistory`\n    pub async fn fee_history(\n        &self,\n        block_count: u64,\n        newest_block: BlockNumber,\n        reward_percentiles: &[f64],\n    ) -> Result<FeeHistory, TransportError> {\n        self.provider().get_fee_history(block_count, newest_block, reward_percentiles).await\n    }\n\n    /// Sends `eth_getProof`\n    pub async fn get_proof(\n        &self,\n        address: Address,\n        keys: Vec<B256>,\n        block_number: Option<BlockId>,\n    ) -> Result<EIP1186AccountProofResponse, TransportError> {\n        self.provider().get_proof(address, keys).block_id(block_number.unwrap_or_default()).await\n    }\n\n    pub async fn storage_at(\n        &self,\n        address: Address,\n        index: U256,\n        number: Option<BlockNumber>,\n    ) -> Result<StorageValue, TransportError> {\n        self.provider()\n            .get_storage_at(address, index)\n            .block_id(number.unwrap_or_default().into())\n            .await\n    }\n\n    pub async fn logs(&self, filter: &Filter) -> Result<Vec<Log>, TransportError> {\n        if let Some(logs) = self.storage_read().logs.get(filter).cloned() {\n            return Ok(logs);\n        }\n\n        let logs = self.provider().get_logs(filter).await?;\n\n        let mut storage = self.storage_write();\n        storage.logs.insert(filter.clone(), logs.clone());\n        Ok(logs)\n    }\n\n    pub async fn get_code(\n        &self,\n        address: Address,\n        blocknumber: u64,\n    ) -> Result<Bytes, TransportError> {\n        trace!(target: \"backend::fork\", \"get_code={:?}\", address);\n        if let Some(code) = self.storage_read().code_at.get(&(address, blocknumber)).cloned() {\n            return Ok(code);\n        }\n\n        let block_id = BlockId::number(blocknumber);\n\n        let code = self.provider().get_code_at(address).block_id(block_id).await?;\n\n        let mut storage = self.storage_write();\n        storage.code_at.insert((address, blocknumber), code.clone());\n\n        Ok(code)\n    }\n\n    pub async fn get_balance(\n        &self,\n        address: Address,\n        blocknumber: u64,\n    ) -> Result<U256, TransportError> {\n        trace!(target: \"backend::fork\", \"get_balance={:?}\", address);\n        self.provider().get_balance(address).block_id(blocknumber.into()).await\n    }\n\n    pub async fn get_nonce(&self, address: Address, block: u64) -> Result<u64, TransportError> {\n        trace!(target: \"backend::fork\", \"get_nonce={:?}\", address);\n        self.provider().get_transaction_count(address).block_id(block.into()).await\n    }\n\n    pub async fn get_account(\n        &self,\n        address: Address,\n        blocknumber: u64,\n    ) -> Result<TrieAccount, TransportError> {\n        trace!(target: \"backend::fork\", \"get_account={:?}\", address);\n        self.provider().get_account(address).block_id(blocknumber.into()).await\n    }\n\n    pub async fn trace_transaction(&self, hash: B256) -> Result<Vec<Trace>, TransportError> {\n        if let Some(traces) = self.storage_read().transaction_traces.get(&hash).cloned() {\n            return Ok(traces);\n        }\n\n        let traces = self.provider().trace_transaction(hash).await?.into_iter().collect::<Vec<_>>();\n\n        let mut storage = self.storage_write();\n        storage.transaction_traces.insert(hash, traces.clone());\n\n        Ok(traces)\n    }\n\n    pub async fn debug_trace_transaction(\n        &self,\n        hash: B256,\n        opts: GethDebugTracingOptions,\n    ) -> Result<GethTrace, TransportError> {\n        if let Some(traces) = self.storage_read().geth_transaction_traces.get(&hash).cloned() {\n            return Ok(traces);\n        }\n\n        let trace = self.provider().debug_trace_transaction(hash, opts).await?;\n\n        let mut storage = self.storage_write();\n        storage.geth_transaction_traces.insert(hash, trace.clone());\n\n        Ok(trace)\n    }\n\n    pub async fn debug_code_by_hash(\n        &self,\n        code_hash: B256,\n        block_id: Option<BlockId>,\n    ) -> Result<Option<Bytes>, TransportError> {\n        self.provider().debug_code_by_hash(code_hash, block_id).await\n    }\n\n    pub async fn trace_block(&self, number: u64) -> Result<Vec<Trace>, TransportError> {\n        if let Some(traces) = self.storage_read().block_traces.get(&number).cloned() {\n            return Ok(traces);\n        }\n\n        let traces =\n            self.provider().trace_block(number.into()).await?.into_iter().collect::<Vec<_>>();\n\n        let mut storage = self.storage_write();\n        storage.block_traces.insert(number, traces.clone());\n\n        Ok(traces)\n    }\n\n    pub async fn trace_replay_block_transactions(\n        &self,\n        number: u64,\n        trace_types: HashSet<TraceType>,\n    ) -> Result<Vec<TraceResultsWithTransactionHash>, TransportError> {\n        // Forward to upstream provider for historical blocks\n        let params = (number, trace_types.iter().map(|t| format!(\"{t:?}\")).collect::<Vec<_>>());\n        self.provider().raw_request(\"trace_replayBlockTransactions\".into(), params).await\n    }\n\n    /// Reset the fork to a fresh forked state, and optionally update the fork config\n    pub async fn reset(\n        &self,\n        url: Option<String>,\n        block_number: impl Into<BlockId>,\n    ) -> Result<(), BlockchainError> {\n        let block_number = block_number.into();\n        {\n            self.database\n                .write()\n                .await\n                .maybe_reset(url.clone(), block_number)\n                .map_err(BlockchainError::Internal)?;\n        }\n\n        if let Some(url) = url {\n            self.config.write().update_url(url)?;\n            let override_chain_id = self.config.read().override_chain_id;\n            let chain_id = if let Some(chain_id) = override_chain_id {\n                chain_id\n            } else {\n                self.provider().get_chain_id().await?\n            };\n            self.config.write().chain_id = chain_id;\n        }\n\n        let provider = self.provider();\n        let block =\n            provider.get_block(block_number).await?.ok_or(BlockchainError::BlockNotFound)?;\n        let block_hash = block.header().hash();\n        let timestamp = block.header().timestamp();\n        let base_fee = block.header().base_fee_per_gas();\n        let total_difficulty = block.header().difficulty();\n\n        let number = block.header().number();\n        self.config.write().update_block(\n            number,\n            block_hash,\n            timestamp,\n            base_fee.map(|g| g as u128),\n            total_difficulty,\n        );\n\n        self.clear_cached_storage();\n\n        self.database.write().await.insert_block_hash(U256::from(number), block_hash);\n\n        Ok(())\n    }\n\n    /// Sends `eth_call`\n    pub async fn call(\n        &self,\n        request: &N::TransactionRequest,\n        block: Option<BlockNumber>,\n    ) -> Result<Bytes, TransportError> {\n        let block = block.unwrap_or(BlockNumber::Latest);\n        let res = self.provider().call(request.clone()).block(block.into()).await?;\n\n        Ok(res)\n    }\n\n    /// Sends `eth_simulateV1`\n    pub async fn simulate_v1(\n        &self,\n        request: &SimulatePayload,\n        block: Option<BlockNumber>,\n    ) -> Result<Vec<SimulatedBlock<N::BlockResponse>>, TransportError> {\n        let mut simulate_call = self.provider().simulate(request);\n        if let Some(n) = block {\n            simulate_call = simulate_call.number(n.as_number().unwrap());\n        }\n\n        let res = simulate_call.await?;\n\n        Ok(res)\n    }\n\n    /// Sends `eth_estimateGas`\n    pub async fn estimate_gas(\n        &self,\n        request: &N::TransactionRequest,\n        block: Option<BlockNumber>,\n    ) -> Result<u128, TransportError> {\n        let block = block.unwrap_or_default();\n        let res = self.provider().estimate_gas(request.clone()).block(block.into()).await?;\n\n        Ok(res as u128)\n    }\n\n    /// Sends `eth_createAccessList`\n    pub async fn create_access_list(\n        &self,\n        request: &N::TransactionRequest,\n        block: Option<BlockNumber>,\n    ) -> Result<AccessListResult, TransportError> {\n        self.provider().create_access_list(request).block_id(block.unwrap_or_default().into()).await\n    }\n\n    pub async fn transaction_by_block_number_and_index(\n        &self,\n        number: u64,\n        index: usize,\n    ) -> Result<Option<N::TransactionResponse>, TransportError> {\n        if let Some(block) = self.block_by_number(number).await? {\n            #[allow(clippy::collapsible_match)]\n            match block.transactions() {\n                BlockTransactions::Full(txs) => {\n                    if let Some(tx) = txs.get(index) {\n                        return Ok(Some(tx.clone()));\n                    }\n                }\n                BlockTransactions::Hashes(hashes) => {\n                    if let Some(tx_hash) = hashes.get(index) {\n                        return self.transaction_by_hash(*tx_hash).await;\n                    }\n                }\n                // TODO(evalir): Is it possible to reach this case? Should we support it\n                BlockTransactions::Uncle => panic!(\"Uncles not supported\"),\n            }\n        }\n        Ok(None)\n    }\n\n    pub async fn transaction_by_block_hash_and_index(\n        &self,\n        hash: B256,\n        index: usize,\n    ) -> Result<Option<N::TransactionResponse>, TransportError> {\n        if let Some(block) = self.block_by_hash(hash).await? {\n            #[allow(clippy::collapsible_match)]\n            match block.transactions() {\n                BlockTransactions::Full(txs) => {\n                    if let Some(tx) = txs.get(index) {\n                        return Ok(Some(tx.clone()));\n                    }\n                }\n                BlockTransactions::Hashes(hashes) => {\n                    if let Some(tx_hash) = hashes.get(index) {\n                        return self.transaction_by_hash(*tx_hash).await;\n                    }\n                }\n                // TODO(evalir): Is it possible to reach this case? Should we support it\n                BlockTransactions::Uncle => panic!(\"Uncles not supported\"),\n            }\n        }\n        Ok(None)\n    }\n\n    pub async fn transaction_by_hash(\n        &self,\n        hash: B256,\n    ) -> Result<Option<N::TransactionResponse>, TransportError> {\n        trace!(target: \"backend::fork\", \"transaction_by_hash={:?}\", hash);\n        if let tx @ Some(_) = self.storage_read().transactions.get(&hash).cloned() {\n            return Ok(tx);\n        }\n\n        let tx = self.provider().get_transaction_by_hash(hash).await?;\n        if let Some(tx) = tx.clone() {\n            let mut storage = self.storage_write();\n            storage.transactions.insert(hash, tx);\n        }\n        Ok(tx)\n    }\n\n    pub async fn block_by_hash(\n        &self,\n        hash: B256,\n    ) -> Result<Option<N::BlockResponse>, TransportError> {\n        if let Some(mut block) = self.storage_read().blocks.get(&hash).cloned() {\n            block.transactions_mut().convert_to_hashes();\n            return Ok(Some(block));\n        }\n\n        Ok(self.fetch_full_block(hash).await?.map(|mut b| {\n            b.transactions_mut().convert_to_hashes();\n            b\n        }))\n    }\n\n    pub async fn block_by_hash_full(\n        &self,\n        hash: B256,\n    ) -> Result<Option<N::BlockResponse>, TransportError> {\n        if let Some(block) = self.storage_read().blocks.get(&hash).cloned() {\n            return Ok(Some(self.convert_to_full_block(block)));\n        }\n        self.fetch_full_block(hash).await\n    }\n\n    pub async fn block_by_number(\n        &self,\n        block_number: u64,\n    ) -> Result<Option<N::BlockResponse>, TransportError> {\n        if let Some(mut block) = self\n            .storage_read()\n            .hashes\n            .get(&block_number)\n            .and_then(|hash| self.storage_read().blocks.get(hash).cloned())\n        {\n            block.transactions_mut().convert_to_hashes();\n            return Ok(Some(block));\n        }\n\n        let mut block = self.fetch_full_block(block_number).await?;\n        if let Some(block) = &mut block {\n            block.transactions_mut().convert_to_hashes();\n        }\n        Ok(block)\n    }\n\n    pub async fn block_by_number_full(\n        &self,\n        block_number: u64,\n    ) -> Result<Option<N::BlockResponse>, TransportError> {\n        if let Some(block) = self\n            .storage_read()\n            .hashes\n            .get(&block_number)\n            .copied()\n            .and_then(|hash| self.storage_read().blocks.get(&hash).cloned())\n        {\n            return Ok(Some(self.convert_to_full_block(block)));\n        }\n\n        self.fetch_full_block(block_number).await\n    }\n\n    async fn fetch_full_block(\n        &self,\n        block_id: impl Into<BlockId>,\n    ) -> Result<Option<N::BlockResponse>, TransportError> {\n        if let Some(block) = self.provider().get_block(block_id.into()).full().await? {\n            let hash = block.header().hash();\n            let block_number = block.header().number();\n            let mut storage = self.storage_write();\n            // also insert all transactions\n            let block_txs = match block.transactions() {\n                BlockTransactions::Full(txs) => txs.to_owned(),\n                _ => vec![],\n            };\n            storage.transactions.extend(block_txs.iter().map(|tx| (tx.tx_hash(), tx.clone())));\n            storage.hashes.insert(block_number, hash);\n            storage.blocks.insert(hash, block.clone());\n            return Ok(Some(block));\n        }\n\n        Ok(None)\n    }\n\n    /// Converts a block of hashes into a full block\n    fn convert_to_full_block(&self, mut block: N::BlockResponse) -> N::BlockResponse {\n        let storage = self.storage.read();\n        let transactions = block\n            .transactions()\n            .hashes()\n            .filter_map(|hash| storage.transactions.get(&hash).cloned())\n            .collect();\n        *block.transactions_mut() = BlockTransactions::Full(transactions);\n        block\n    }\n}\n\nimpl ClientFork {\n    pub async fn transaction_receipt(\n        &self,\n        hash: B256,\n    ) -> Result<Option<FoundryTxReceipt>, BlockchainError> {\n        if let Some(receipt) = self.storage_read().transaction_receipts.get(&hash).cloned() {\n            return Ok(Some(receipt));\n        }\n\n        if let Some(receipt) = self.provider().get_transaction_receipt(hash).await? {\n            let receipt = FoundryTxReceipt::try_from(receipt)\n                .map_err(|_| BlockchainError::FailedToDecodeReceipt)?;\n            let mut storage = self.storage_write();\n            storage.transaction_receipts.insert(hash, receipt.clone());\n            return Ok(Some(receipt));\n        }\n\n        Ok(None)\n    }\n\n    pub async fn block_receipts(\n        &self,\n        number: u64,\n    ) -> Result<Option<Vec<FoundryTxReceipt>>, BlockchainError> {\n        if let receipts @ Some(_) = self.storage_read().block_receipts.get(&number).cloned() {\n            return Ok(receipts);\n        }\n\n        // TODO Needs to be removed.\n        // Since alloy doesn't indicate in the result whether the block exists,\n        // this is being temporarily implemented in anvil.\n        if self.predates_fork_inclusive(number) {\n            let receipts = self.provider().get_block_receipts(BlockId::from(number)).await?;\n            let receipts = receipts\n                .map(|r| {\n                    r.into_iter()\n                        .map(|r| {\n                            FoundryTxReceipt::try_from(r)\n                                .map_err(|_| BlockchainError::FailedToDecodeReceipt)\n                        })\n                        .collect::<Result<Vec<_>, _>>()\n                })\n                .transpose()?;\n\n            if let Some(receipts) = receipts.clone() {\n                let mut storage = self.storage_write();\n                storage.block_receipts.insert(number, receipts);\n            }\n\n            return Ok(receipts);\n        }\n\n        Ok(None)\n    }\n\n    pub async fn uncle_by_block_hash_and_index(\n        &self,\n        hash: B256,\n        index: usize,\n    ) -> Result<Option<AnyRpcBlock>, TransportError> {\n        if let Some(block) = self.block_by_hash(hash).await? {\n            return self.uncles_by_block_and_index(block, index).await;\n        }\n        Ok(None)\n    }\n\n    pub async fn uncle_by_block_number_and_index(\n        &self,\n        number: u64,\n        index: usize,\n    ) -> Result<Option<AnyRpcBlock>, TransportError> {\n        if let Some(block) = self.block_by_number(number).await? {\n            return self.uncles_by_block_and_index(block, index).await;\n        }\n        Ok(None)\n    }\n\n    async fn uncles_by_block_and_index(\n        &self,\n        block: AnyRpcBlock,\n        index: usize,\n    ) -> Result<Option<AnyRpcBlock>, TransportError> {\n        let block_hash = block.header().hash();\n        let block_number = block.header().number();\n        if let Some(uncles) = self.storage_read().uncles.get(&block_hash) {\n            return Ok(uncles.get(index).cloned());\n        }\n\n        let mut uncles = Vec::with_capacity(block.uncles.len());\n        for (uncle_idx, _) in block.uncles.iter().enumerate() {\n            let uncle =\n                match self.provider().get_uncle(block_number.into(), uncle_idx as u64).await? {\n                    Some(u) => u,\n                    None => return Ok(None),\n                };\n            uncles.push(uncle);\n        }\n        self.storage_write().uncles.insert(block_hash, uncles.clone());\n        Ok(uncles.get(index).cloned())\n    }\n}\n\n/// Contains all fork metadata\n#[derive(Clone, Debug)]\npub struct ClientForkConfig<N: Network = AnyNetwork> {\n    pub eth_rpc_url: String,\n    /// The block number of the forked block\n    pub block_number: u64,\n    /// The hash of the forked block\n    pub block_hash: B256,\n    /// The transaction hash we forked off of, if any.\n    pub transaction_hash: Option<B256>,\n    pub provider: Arc<RetryProvider<N>>,\n    pub chain_id: u64,\n    pub override_chain_id: Option<u64>,\n    /// The timestamp for the forked block\n    pub timestamp: u64,\n    /// The basefee of the forked block\n    pub base_fee: Option<u128>,\n    /// Blob gas used of the forked block\n    pub blob_gas_used: Option<u128>,\n    /// Blob excess gas and price of the forked block\n    pub blob_excess_gas_and_price: Option<BlobExcessGasAndPrice>,\n    /// request timeout\n    pub timeout: Duration,\n    /// request retries for spurious networks\n    pub retries: u32,\n    /// request retries for spurious networks\n    pub backoff: Duration,\n    /// available CUPS\n    pub compute_units_per_second: u64,\n    /// total difficulty of the chain until this block\n    pub total_difficulty: U256,\n    /// Transactions to force include in the forked chain\n    pub force_transactions: Option<Vec<PoolTransaction<FoundryTxEnvelope>>>,\n}\n\nimpl<N: Network> ClientForkConfig<N> {\n    /// Updates the provider URL\n    ///\n    /// # Errors\n    ///\n    /// This will fail if no new provider could be established (erroneous URL)\n    fn update_url(&mut self, url: String) -> Result<(), BlockchainError> {\n        // let interval = self.provider.get_interval();\n        self.provider = Arc::new(\n            ProviderBuilder::<N>::new(url.as_str())\n                .timeout(self.timeout)\n                // .timeout_retry(self.retries)\n                .max_retry(self.retries)\n                .initial_backoff(self.backoff.as_millis() as u64)\n                .compute_units_per_second(self.compute_units_per_second)\n                .build()\n                .map_err(|e| BlockchainError::InvalidUrl(format!(\"{url}: {e}\")))?, /* .interval(interval), */\n        );\n        trace!(target: \"fork\", \"Updated rpc url  {}\", url);\n        self.eth_rpc_url = url;\n        Ok(())\n    }\n    /// Updates the block forked off `(block number, block hash, timestamp)`\n    pub fn update_block(\n        &mut self,\n        block_number: u64,\n        block_hash: B256,\n        timestamp: u64,\n        base_fee: Option<u128>,\n        total_difficulty: U256,\n    ) {\n        self.block_number = block_number;\n        self.block_hash = block_hash;\n        self.timestamp = timestamp;\n        self.base_fee = base_fee;\n        self.total_difficulty = total_difficulty;\n        trace!(target: \"fork\", \"Updated block number={} hash={:?}\", block_number, block_hash);\n    }\n}\n\n/// Contains cached state fetched to serve EthApi requests\n///\n/// This is used as a cache so repeated requests to the same data are not sent to the remote client\n#[derive(Clone, Debug)]\npub struct ForkedStorage<N: Network = AnyNetwork> {\n    pub uncles: FbHashMap<32, Vec<N::BlockResponse>>,\n    pub blocks: FbHashMap<32, N::BlockResponse>,\n    pub hashes: HashMap<u64, B256>,\n    pub transactions: FbHashMap<32, N::TransactionResponse>,\n    pub transaction_receipts: FbHashMap<32, FoundryTxReceipt>,\n    pub transaction_traces: FbHashMap<32, Vec<Trace>>,\n    pub logs: HashMap<Filter, Vec<Log>>,\n    pub geth_transaction_traces: FbHashMap<32, GethTrace>,\n    pub block_traces: HashMap<u64, Vec<Trace>>,\n    pub block_receipts: HashMap<u64, Vec<FoundryTxReceipt>>,\n    pub code_at: HashMap<(Address, u64), Bytes>,\n}\n\nimpl<N: Network> Default for ForkedStorage<N> {\n    fn default() -> Self {\n        Self {\n            uncles: Default::default(),\n            blocks: Default::default(),\n            hashes: Default::default(),\n            transactions: Default::default(),\n            transaction_receipts: Default::default(),\n            transaction_traces: Default::default(),\n            logs: Default::default(),\n            geth_transaction_traces: Default::default(),\n            block_traces: Default::default(),\n            block_receipts: Default::default(),\n            code_at: Default::default(),\n        }\n    }\n}\n\nimpl<N: Network> ForkedStorage<N> {\n    /// Clears all data\n    pub fn clear(&mut self) {\n        // simply replace with a completely new, empty instance\n        *self = Self::default()\n    }\n}\n"
  },
  {
    "path": "crates/anvil/src/eth/backend/genesis.rs",
    "content": "//! Genesis settings\n\nuse crate::eth::backend::db::Db;\nuse alloy_genesis::{Genesis, GenesisAccount};\nuse alloy_primitives::{Address, U256};\nuse foundry_evm::backend::DatabaseResult;\nuse revm::{bytecode::Bytecode, primitives::KECCAK_EMPTY, state::AccountInfo};\nuse tokio::sync::RwLockWriteGuard;\n\n/// Genesis settings\n#[derive(Clone, Debug, Default)]\npub struct GenesisConfig {\n    /// The initial number for the genesis block\n    pub number: u64,\n    /// The initial timestamp for the genesis block\n    pub timestamp: u64,\n    /// Balance for genesis accounts\n    pub balance: U256,\n    /// All accounts that should be initialised at genesis\n    pub accounts: Vec<Address>,\n    /// The `genesis.json` if provided\n    pub genesis_init: Option<Genesis>,\n}\n\nimpl GenesisConfig {\n    /// Returns fresh `AccountInfo`s for the configured `accounts`\n    pub fn account_infos(&self) -> impl Iterator<Item = (Address, AccountInfo)> + '_ {\n        self.accounts.iter().copied().map(|address| {\n            let info = AccountInfo {\n                balance: self.balance,\n                code_hash: KECCAK_EMPTY,\n                // we set this to empty so `Database::code_by_hash` doesn't get called\n                code: Some(Default::default()),\n                nonce: 0,\n                account_id: None,\n            };\n            (address, info)\n        })\n    }\n\n    /// If an initial `genesis.json` was provided, this applies the account alloc to the db\n    pub fn apply_genesis_json_alloc(\n        &self,\n        mut db: RwLockWriteGuard<'_, Box<dyn Db>>,\n    ) -> DatabaseResult<()> {\n        if let Some(ref genesis) = self.genesis_init {\n            for (addr, mut acc) in genesis.alloc.clone() {\n                let storage = std::mem::take(&mut acc.storage);\n                // insert all accounts\n                db.insert_account(addr, self.genesis_to_account_info(&acc));\n                // insert all storage values\n                for (k, v) in &storage.unwrap_or_default() {\n                    db.set_storage_at(addr, *k, *v)?;\n                }\n            }\n        }\n        Ok(())\n    }\n\n    /// Converts a [`GenesisAccount`] to an [`AccountInfo`]\n    fn genesis_to_account_info(&self, acc: &GenesisAccount) -> AccountInfo {\n        let GenesisAccount { code, balance, nonce, .. } = acc.clone();\n        let code = code.map(Bytecode::new_raw);\n        AccountInfo {\n            balance,\n            nonce: nonce.unwrap_or_default(),\n            code_hash: code.as_ref().map(|code| code.hash_slow()).unwrap_or(KECCAK_EMPTY),\n            code,\n            account_id: None,\n        }\n    }\n}\n"
  },
  {
    "path": "crates/anvil/src/eth/backend/info.rs",
    "content": "//! Handler that can get current storage related data\n\nuse crate::mem::Backend;\nuse alloy_consensus::TxReceipt;\nuse alloy_network::{AnyRpcBlock, Network};\nuse alloy_primitives::B256;\nuse anvil_core::eth::block::Block;\nuse std::{fmt, sync::Arc};\n\n/// A type that can fetch data related to the ethereum storage.\n///\n/// This is simply a wrapper type for the [`Backend`] but exposes a limited set of functions to\n/// fetch ethereum storage related data\n// TODO(mattsee): once we have multiple Backend types, this should be turned into a trait\n#[derive(Clone)]\npub struct StorageInfo<N: Network> {\n    backend: Arc<Backend<N>>,\n}\n\nimpl<N: Network> StorageInfo<N> {\n    pub(crate) fn new(backend: Arc<Backend<N>>) -> Self {\n        Self { backend }\n    }\n\n    /// Returns the current block\n    pub fn current_block(&self) -> Option<Block> {\n        self.backend.get_block(self.backend.best_number())\n    }\n\n    /// Returns the block with the given hash\n    pub fn block(&self, hash: B256) -> Option<Block> {\n        self.backend.get_block_by_hash(hash)\n    }\n\n    /// Returns the block with the given hash in the format of the ethereum API\n    pub fn eth_block(&self, hash: B256) -> Option<AnyRpcBlock> {\n        let block = self.block(hash)?;\n        Some(self.backend.convert_block(block))\n    }\n}\n\nimpl<N: Network> StorageInfo<N>\nwhere\n    N::ReceiptEnvelope: TxReceipt<Log = alloy_primitives::Log> + Clone,\n{\n    /// Returns the receipts of the current block\n    pub fn current_receipts(&self) -> Option<Vec<N::ReceiptEnvelope>> {\n        self.backend.mined_receipts(self.backend.best_hash())\n    }\n\n    /// Returns the receipts of the block with the given hash\n    pub fn receipts(&self, hash: B256) -> Option<Vec<N::ReceiptEnvelope>> {\n        self.backend.mined_receipts(hash)\n    }\n}\n\nimpl<N: Network> fmt::Debug for StorageInfo<N> {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.debug_struct(\"StorageInfo\").finish_non_exhaustive()\n    }\n}\n"
  },
  {
    "path": "crates/anvil/src/eth/backend/mem/cache.rs",
    "content": "use crate::config::anvil_tmp_dir;\nuse alloy_primitives::B256;\nuse foundry_evm::backend::StateSnapshot;\nuse std::{\n    io,\n    path::{Path, PathBuf},\n};\nuse tempfile::TempDir;\n\n/// On disk state cache\n///\n/// A basic tempdir which stores states on disk\npub struct DiskStateCache {\n    /// The path where to create the tempdir in\n    pub(crate) temp_path: Option<PathBuf>,\n    /// Holds the temp dir object.\n    pub(crate) temp_dir: Option<TempDir>,\n}\n\nimpl DiskStateCache {\n    /// Specify the path where to create the tempdir in\n    pub fn with_path(self, temp_path: PathBuf) -> Self {\n        Self { temp_path: Some(temp_path), temp_dir: None }\n    }\n    /// Returns the cache file for the given hash\n    fn with_cache_file<F, R>(&mut self, hash: B256, f: F) -> Option<R>\n    where\n        F: FnOnce(PathBuf) -> R,\n    {\n        if self.temp_dir.is_none() {\n            let tmp_dir = self\n                .temp_path\n                .as_ref()\n                .map(|p| -> io::Result<TempDir> {\n                    std::fs::create_dir_all(p)?;\n                    build_tmp_dir(Some(p))\n                })\n                .unwrap_or_else(|| build_tmp_dir(None));\n\n            match tmp_dir {\n                Ok(temp_dir) => {\n                    trace!(target: \"backend\", path=?temp_dir.path(), \"created disk state cache dir\");\n                    self.temp_dir = Some(temp_dir);\n                }\n                Err(err) => {\n                    error!(target: \"backend\", %err, \"failed to create disk state cache dir\");\n                }\n            }\n        }\n        if let Some(temp_dir) = &self.temp_dir {\n            let path = temp_dir.path().join(format!(\"{hash:?}.json\"));\n            Some(f(path))\n        } else {\n            None\n        }\n    }\n\n    /// Stores the snapshot for the given hash synchronously.\n    ///\n    /// Returns `true` if the write was successful, `false` otherwise.\n    pub fn write(&mut self, hash: B256, state: &StateSnapshot) -> bool {\n        self.with_cache_file(hash, |file| match foundry_common::fs::write_json_file(&file, state) {\n            Ok(_) => {\n                trace!(target: \"backend\", ?hash, \"wrote state json file\");\n                true\n            }\n            Err(err) => {\n                error!(target: \"backend\", %err, ?hash, \"Failed to write state snapshot\");\n                false\n            }\n        })\n        .unwrap_or(false)\n    }\n\n    /// Loads the snapshot file for the given hash\n    ///\n    /// Returns None if it doesn't exist or deserialization failed\n    pub fn read(&mut self, hash: B256) -> Option<StateSnapshot> {\n        self.with_cache_file(hash, |file| {\n            match foundry_common::fs::read_json_file::<StateSnapshot>(&file) {\n                Ok(state) => {\n                    trace!(target: \"backend\", ?hash,\"loaded cached state\");\n                    Some(state)\n                }\n                Err(err) => {\n                    error!(target: \"backend\", %err, ?hash, \"Failed to load state snapshot\");\n                    None\n                }\n            }\n        })\n        .flatten()\n    }\n\n    /// Removes the cache file for the given hash, if it exists\n    pub fn remove(&mut self, hash: B256) {\n        self.with_cache_file(hash, |file| {\n            foundry_common::fs::remove_file(file).map_err(|err| {\n                error!(target: \"backend\", %err, %hash, \"Failed to remove state snapshot\");\n            })\n        });\n    }\n}\n\nimpl Default for DiskStateCache {\n    fn default() -> Self {\n        Self { temp_path: anvil_tmp_dir(), temp_dir: None }\n    }\n}\n\n/// Returns the temporary dir for the cached state\n///\n/// This will create a prefixed temp dir with `anvil-state-06-11-2022-12-50`\nfn build_tmp_dir(p: Option<&Path>) -> io::Result<TempDir> {\n    let mut builder = tempfile::Builder::new();\n    let now = chrono::offset::Utc::now();\n    let prefix = now.format(\"anvil-state-%d-%m-%Y-%H-%M\").to_string();\n    builder.prefix(&prefix);\n\n    if let Some(p) = p { builder.tempdir_in(p) } else { builder.tempdir() }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use tempfile::tempdir;\n\n    #[test]\n    fn can_build_temp_dir() {\n        let dir = tempdir().unwrap();\n        let p = dir.path();\n        let cache_dir = build_tmp_dir(Some(p)).unwrap();\n        assert!(\n            cache_dir.path().file_name().unwrap().to_str().unwrap().starts_with(\"anvil-state-\")\n        );\n        let cache_dir = build_tmp_dir(None).unwrap();\n        assert!(\n            cache_dir.path().file_name().unwrap().to_str().unwrap().starts_with(\"anvil-state-\")\n        );\n    }\n}\n"
  },
  {
    "path": "crates/anvil/src/eth/backend/mem/fork_db.rs",
    "content": "use crate::eth::backend::db::{\n    Db, MaybeForkedDatabase, MaybeFullDatabase, SerializableAccountRecord, SerializableBlock,\n    SerializableHistoricalStates, SerializableState, SerializableTransaction, StateDb,\n};\nuse alloy_network::Network;\nuse alloy_primitives::{Address, B256, U256, map::AddressMap};\nuse alloy_rpc_types::BlockId;\nuse foundry_evm::{\n    backend::{BlockchainDb, DatabaseResult, RevertStateSnapshotAction, StateSnapshot},\n    fork::database::ForkDbStateSnapshot,\n};\nuse revm::{\n    context::BlockEnv,\n    database::{Database, DbAccount},\n    state::AccountInfo,\n};\n\npub use foundry_evm::fork::database::ForkedDatabase;\n\nimpl<N: Network> Db for ForkedDatabase<N> {\n    fn insert_account(&mut self, address: Address, account: AccountInfo) {\n        self.database_mut().insert_account(address, account)\n    }\n\n    fn set_storage_at(&mut self, address: Address, slot: B256, val: B256) -> DatabaseResult<()> {\n        // this ensures the account is loaded first\n        let _ = Database::basic(self, address)?;\n        self.database_mut().set_storage_at(address, slot, val)\n    }\n\n    fn insert_block_hash(&mut self, number: U256, hash: B256) {\n        self.inner().block_hashes().write().insert(number, hash);\n    }\n\n    fn dump_state(\n        &self,\n        at: BlockEnv,\n        best_number: u64,\n        blocks: Vec<SerializableBlock>,\n        transactions: Vec<SerializableTransaction>,\n        historical_states: Option<SerializableHistoricalStates>,\n    ) -> DatabaseResult<Option<SerializableState>> {\n        let mut db = self.database().clone();\n        let accounts = self\n            .database()\n            .cache\n            .accounts\n            .clone()\n            .into_iter()\n            .map(|(k, v)| -> DatabaseResult<_> {\n                let code = if let Some(code) = v.info.code {\n                    code\n                } else {\n                    db.code_by_hash(v.info.code_hash)?\n                };\n                Ok((\n                    k,\n                    SerializableAccountRecord {\n                        nonce: v.info.nonce,\n                        balance: v.info.balance,\n                        code: code.original_bytes(),\n                        storage: v.storage.into_iter().map(|(k, v)| (k.into(), v.into())).collect(),\n                    },\n                ))\n            })\n            .collect::<Result<_, _>>()?;\n        Ok(Some(SerializableState {\n            block: Some(at),\n            accounts,\n            best_block_number: Some(best_number),\n            blocks,\n            transactions,\n            historical_states,\n        }))\n    }\n\n    fn snapshot_state(&mut self) -> U256 {\n        self.insert_state_snapshot()\n    }\n\n    fn revert_state(&mut self, id: U256, action: RevertStateSnapshotAction) -> bool {\n        self.revert_state_snapshot(id, action)\n    }\n\n    fn current_state(&self) -> StateDb {\n        StateDb::new(self.create_state_snapshot())\n    }\n}\n\nimpl<N: Network> MaybeFullDatabase for ForkedDatabase<N> {\n    fn maybe_as_full_db(&self) -> Option<&AddressMap<DbAccount>> {\n        Some(&self.database().cache.accounts)\n    }\n\n    fn clear_into_state_snapshot(&mut self) -> StateSnapshot {\n        let db = self.inner().db();\n        let accounts = std::mem::take(&mut *db.accounts.write());\n        let storage = std::mem::take(&mut *db.storage.write());\n        let block_hashes = std::mem::take(&mut *db.block_hashes.write());\n        StateSnapshot { accounts, storage, block_hashes }\n    }\n\n    fn read_as_state_snapshot(&self) -> StateSnapshot {\n        let db = self.inner().db();\n        let accounts = db.accounts.read().clone();\n        let storage = db.storage.read().clone();\n        let block_hashes = db.block_hashes.read().clone();\n        StateSnapshot { accounts, storage, block_hashes }\n    }\n\n    fn clear(&mut self) {\n        self.flush_cache();\n        self.clear_into_state_snapshot();\n    }\n\n    fn init_from_state_snapshot(&mut self, state_snapshot: StateSnapshot) {\n        let db = self.inner().db();\n        let StateSnapshot { accounts, storage, block_hashes } = state_snapshot;\n        *db.accounts.write() = accounts;\n        *db.storage.write() = storage;\n        *db.block_hashes.write() = block_hashes;\n    }\n}\n\nimpl<N: Network> MaybeFullDatabase for ForkDbStateSnapshot<N> {\n    fn maybe_as_full_db(&self) -> Option<&AddressMap<DbAccount>> {\n        Some(&self.local.cache.accounts)\n    }\n\n    fn clear_into_state_snapshot(&mut self) -> StateSnapshot {\n        let mut state_snapshot = std::mem::take(&mut self.state_snapshot);\n        let local_state_snapshot = self.local.clear_into_state_snapshot();\n        state_snapshot.accounts.extend(local_state_snapshot.accounts);\n        state_snapshot.storage.extend(local_state_snapshot.storage);\n        state_snapshot.block_hashes.extend(local_state_snapshot.block_hashes);\n        state_snapshot\n    }\n\n    fn read_as_state_snapshot(&self) -> StateSnapshot {\n        let mut state_snapshot = self.state_snapshot.clone();\n        let local_state_snapshot = self.local.read_as_state_snapshot();\n        state_snapshot.accounts.extend(local_state_snapshot.accounts);\n        state_snapshot.storage.extend(local_state_snapshot.storage);\n        state_snapshot.block_hashes.extend(local_state_snapshot.block_hashes);\n        state_snapshot\n    }\n\n    fn clear(&mut self) {\n        std::mem::take(&mut self.state_snapshot);\n        self.local.clear()\n    }\n\n    fn init_from_state_snapshot(&mut self, state_snapshot: StateSnapshot) {\n        self.state_snapshot = state_snapshot;\n    }\n}\n\nimpl<N: Network> MaybeForkedDatabase for ForkedDatabase<N> {\n    fn maybe_reset(&mut self, url: Option<String>, block_number: BlockId) -> Result<(), String> {\n        self.reset(url, block_number)\n    }\n\n    fn maybe_flush_cache(&self) -> Result<(), String> {\n        self.flush_cache();\n        Ok(())\n    }\n\n    fn maybe_inner(&self) -> Result<&BlockchainDb, String> {\n        Ok(self.inner())\n    }\n}\n"
  },
  {
    "path": "crates/anvil/src/eth/backend/mem/in_memory_db.rs",
    "content": "//! The in memory DB\n\nuse crate::{\n    eth::backend::db::{\n        Db, MaybeForkedDatabase, MaybeFullDatabase, SerializableAccountRecord, SerializableBlock,\n        SerializableHistoricalStates, SerializableState, SerializableTransaction, StateDb,\n    },\n    mem::state::state_root,\n};\nuse alloy_primitives::{Address, B256, U256, map::AddressMap};\nuse alloy_rpc_types::BlockId;\nuse foundry_evm::backend::{BlockchainDb, DatabaseResult, StateSnapshot};\nuse revm::{\n    context::BlockEnv,\n    database::{DatabaseRef, DbAccount},\n    state::AccountInfo,\n};\n\n// reexport for convenience\npub use foundry_evm::backend::MemDb;\nuse foundry_evm::backend::RevertStateSnapshotAction;\n\nimpl Db for MemDb {\n    fn insert_account(&mut self, address: Address, account: AccountInfo) {\n        self.inner.insert_account_info(address, account)\n    }\n\n    fn set_storage_at(&mut self, address: Address, slot: B256, val: B256) -> DatabaseResult<()> {\n        self.inner.insert_account_storage(address, slot.into(), val.into())\n    }\n\n    fn insert_block_hash(&mut self, number: U256, hash: B256) {\n        self.inner.cache.block_hashes.insert(number, hash);\n    }\n\n    fn dump_state(\n        &self,\n        at: BlockEnv,\n        best_number: u64,\n        blocks: Vec<SerializableBlock>,\n        transactions: Vec<SerializableTransaction>,\n        historical_states: Option<SerializableHistoricalStates>,\n    ) -> DatabaseResult<Option<SerializableState>> {\n        let accounts = self\n            .inner\n            .cache\n            .accounts\n            .clone()\n            .into_iter()\n            .map(|(k, v)| -> DatabaseResult<_> {\n                let code = if let Some(code) = v.info.code {\n                    code\n                } else {\n                    self.inner.code_by_hash_ref(v.info.code_hash)?\n                };\n                Ok((\n                    k,\n                    SerializableAccountRecord {\n                        nonce: v.info.nonce,\n                        balance: v.info.balance,\n                        code: code.original_bytes(),\n                        storage: v.storage.into_iter().map(|(k, v)| (k.into(), v.into())).collect(),\n                    },\n                ))\n            })\n            .collect::<Result<_, _>>()?;\n\n        Ok(Some(SerializableState {\n            block: Some(at),\n            accounts,\n            best_block_number: Some(best_number),\n            blocks,\n            transactions,\n            historical_states,\n        }))\n    }\n\n    /// Creates a new snapshot\n    fn snapshot_state(&mut self) -> U256 {\n        let id = self.state_snapshots.insert(self.inner.clone());\n        trace!(target: \"backend::memdb\", \"Created new state snapshot {}\", id);\n        id\n    }\n\n    fn revert_state(&mut self, id: U256, action: RevertStateSnapshotAction) -> bool {\n        if let Some(state_snapshot) = self.state_snapshots.remove(id) {\n            if action.is_keep() {\n                self.state_snapshots.insert_at(state_snapshot.clone(), id);\n            }\n            self.inner = state_snapshot;\n            trace!(target: \"backend::memdb\", \"Reverted state snapshot {}\", id);\n            true\n        } else {\n            warn!(target: \"backend::memdb\", \"No state snapshot to revert for {}\", id);\n            false\n        }\n    }\n\n    fn maybe_state_root(&self) -> Option<B256> {\n        Some(state_root(&self.inner.cache.accounts))\n    }\n\n    fn current_state(&self) -> StateDb {\n        StateDb::new(Self { inner: self.inner.clone(), ..Default::default() })\n    }\n}\n\nimpl MaybeFullDatabase for MemDb {\n    fn maybe_as_full_db(&self) -> Option<&AddressMap<DbAccount>> {\n        Some(&self.inner.cache.accounts)\n    }\n\n    fn clear_into_state_snapshot(&mut self) -> StateSnapshot {\n        self.inner.clear_into_state_snapshot()\n    }\n\n    fn read_as_state_snapshot(&self) -> StateSnapshot {\n        self.inner.read_as_state_snapshot()\n    }\n\n    fn clear(&mut self) {\n        self.inner.clear();\n    }\n\n    fn init_from_state_snapshot(&mut self, snapshot: StateSnapshot) {\n        self.inner.init_from_state_snapshot(snapshot)\n    }\n}\n\nimpl MaybeForkedDatabase for MemDb {\n    fn maybe_reset(&mut self, _url: Option<String>, _block_number: BlockId) -> Result<(), String> {\n        Err(\"not supported\".to_string())\n    }\n\n    fn maybe_flush_cache(&self) -> Result<(), String> {\n        Err(\"not supported\".to_string())\n    }\n\n    fn maybe_inner(&self) -> Result<&BlockchainDb, String> {\n        Err(\"not supported\".to_string())\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use alloy_primitives::{Bytes, address};\n    use revm::{bytecode::Bytecode, primitives::KECCAK_EMPTY};\n    use std::collections::BTreeMap;\n\n    // verifies that all substantial aspects of a loaded account remain the same after an account\n    // is dumped and reloaded\n    #[test]\n    fn test_dump_reload_cycle() {\n        let test_addr: Address = address!(\"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266\");\n\n        let mut dump_db = MemDb::default();\n\n        let contract_code = Bytecode::new_raw(Bytes::from(\"fake contract code\"));\n        dump_db.insert_account(\n            test_addr,\n            AccountInfo {\n                balance: U256::from(123456),\n                code_hash: KECCAK_EMPTY,\n                code: Some(contract_code.clone()),\n                nonce: 1234,\n                account_id: None,\n            },\n        );\n        dump_db\n            .set_storage_at(test_addr, U256::from(1234567).into(), U256::from(1).into())\n            .unwrap();\n\n        // blocks dumping/loading tested in storage.rs\n        let state = dump_db\n            .dump_state(Default::default(), 0, Vec::new(), Vec::new(), Default::default())\n            .unwrap()\n            .unwrap();\n\n        let mut load_db = MemDb::default();\n\n        load_db.load_state(state).unwrap();\n\n        let loaded_account = load_db.basic_ref(test_addr).unwrap().unwrap();\n\n        assert_eq!(loaded_account.balance, U256::from(123456));\n        assert_eq!(load_db.code_by_hash_ref(loaded_account.code_hash).unwrap(), contract_code);\n        assert_eq!(loaded_account.nonce, 1234);\n        assert_eq!(load_db.storage_ref(test_addr, U256::from(1234567)).unwrap(), U256::from(1));\n    }\n\n    // verifies that multiple accounts can be loaded at a time, and storage is merged within those\n    // accounts as well.\n    #[test]\n    fn test_load_state_merge() {\n        let test_addr: Address = address!(\"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266\");\n        let test_addr2: Address = address!(\"0x70997970c51812dc3a010c7d01b50e0d17dc79c8\");\n\n        let contract_code = Bytecode::new_raw(Bytes::from(\"fake contract code\"));\n\n        let mut db = MemDb::default();\n\n        db.insert_account(\n            test_addr,\n            AccountInfo {\n                balance: U256::from(123456),\n                code_hash: KECCAK_EMPTY,\n                code: Some(contract_code.clone()),\n                nonce: 1234,\n                account_id: None,\n            },\n        );\n\n        db.set_storage_at(test_addr, U256::from(1234567).into(), U256::from(1).into()).unwrap();\n        db.set_storage_at(test_addr, U256::from(1234568).into(), U256::from(2).into()).unwrap();\n\n        let mut new_state = SerializableState::default();\n\n        new_state.accounts.insert(\n            test_addr2,\n            SerializableAccountRecord {\n                balance: Default::default(),\n                code: Default::default(),\n                nonce: 1,\n                storage: Default::default(),\n            },\n        );\n\n        let mut new_storage = BTreeMap::default();\n        new_storage.insert(U256::from(1234568).into(), U256::from(5).into());\n\n        new_state.accounts.insert(\n            test_addr,\n            SerializableAccountRecord {\n                balance: U256::from(100100),\n                code: contract_code.bytes()[..contract_code.len()].to_vec().into(),\n                nonce: 100,\n                storage: new_storage,\n            },\n        );\n\n        db.load_state(new_state).unwrap();\n\n        let loaded_account = db.basic_ref(test_addr).unwrap().unwrap();\n        let loaded_account2 = db.basic_ref(test_addr2).unwrap().unwrap();\n\n        assert_eq!(loaded_account2.nonce, 1);\n\n        assert_eq!(loaded_account.balance, U256::from(100100));\n        assert_eq!(db.code_by_hash_ref(loaded_account.code_hash).unwrap(), contract_code);\n        assert_eq!(loaded_account.nonce, 1234);\n        assert_eq!(db.storage_ref(test_addr, U256::from(1234567)).unwrap(), U256::from(1));\n        assert_eq!(db.storage_ref(test_addr, U256::from(1234568)).unwrap(), U256::from(5));\n    }\n}\n"
  },
  {
    "path": "crates/anvil/src/eth/backend/mem/inspector.rs",
    "content": "//! Anvil specific [`revm::Inspector`] implementation\n\nuse crate::eth::macros::node_info;\nuse alloy_primitives::{Address, Log, U256};\nuse foundry_evm::{\n    call_inspectors,\n    decode::decode_console_logs,\n    inspectors::{LogCollector, TracingInspector},\n    traces::{\n        CallTraceDecoder, SparsedTraceArena, TracingInspectorConfig, render_trace_arena_inner,\n    },\n};\nuse revm::{\n    Inspector,\n    context::ContextTr,\n    inspector::JournalExt,\n    interpreter::{\n        CallInputs, CallOutcome, CreateInputs, CreateOutcome, Interpreter,\n        interpreter::EthInterpreter,\n    },\n};\nuse revm_inspectors::transfer::TransferInspector;\nuse std::sync::Arc;\n\n/// The [`revm::Inspector`] used when transacting in the evm\n#[derive(Clone, Debug, Default)]\npub struct AnvilInspector {\n    /// Collects all traces\n    pub tracer: Option<TracingInspector>,\n    /// Collects all `console.sol` logs\n    pub log_collector: Option<LogCollector>,\n    /// Collects all internal ETH transfers as ERC20 transfer events.\n    pub transfer: Option<TransferInspector>,\n}\n\nimpl AnvilInspector {\n    /// Called after the inspecting the evm\n    ///\n    /// This will log all `console.sol` logs\n    pub fn print_logs(&self) {\n        if let Some(LogCollector::Capture { logs }) = &self.log_collector {\n            print_logs(logs);\n        }\n    }\n\n    /// Consumes the type and prints the traces.\n    pub fn into_print_traces(mut self, decoder: Arc<CallTraceDecoder>) {\n        if let Some(a) = self.tracer.take() {\n            print_traces(a, decoder);\n        }\n    }\n\n    /// Called after the inspecting the evm\n    /// This will log all traces\n    pub fn print_traces(&self, decoder: Arc<CallTraceDecoder>) {\n        if let Some(a) = self.tracer.clone() {\n            print_traces(a, decoder);\n        }\n    }\n\n    /// Configures the `Tracer` [`revm::Inspector`]\n    pub fn with_tracing(mut self) -> Self {\n        self.tracer = Some(TracingInspector::new(TracingInspectorConfig::all().set_steps(false)));\n        self\n    }\n\n    /// Configures the `TracingInspector` [`revm::Inspector`]\n    pub fn with_tracing_config(mut self, config: TracingInspectorConfig) -> Self {\n        self.tracer = Some(TracingInspector::new(config));\n        self\n    }\n\n    /// Enables steps recording for `Tracer`.\n    pub fn with_steps_tracing(mut self) -> Self {\n        self.tracer = Some(TracingInspector::new(TracingInspectorConfig::all().with_state_diffs()));\n        self\n    }\n\n    /// Configures the `Tracer` [`revm::Inspector`] with a log collector\n    pub fn with_log_collector(mut self) -> Self {\n        self.log_collector = Some(LogCollector::Capture { logs: Vec::new() });\n        self\n    }\n\n    /// Configures the `Tracer` [`revm::Inspector`] with a transfer event collector\n    pub fn with_transfers(mut self) -> Self {\n        self.transfer = Some(TransferInspector::new(false).with_logs(true));\n        self\n    }\n\n    /// Configures the `Tracer` [`revm::Inspector`] with a trace printer\n    pub fn with_trace_printer(mut self) -> Self {\n        self.tracer = Some(TracingInspector::new(TracingInspectorConfig::all().with_state_diffs()));\n        self\n    }\n}\n\n/// Prints the traces for the inspector\n///\n/// Caution: This blocks on call trace decoding\n///\n/// # Panics\n///\n/// If called outside tokio runtime\nfn print_traces(tracer: TracingInspector, decoder: Arc<CallTraceDecoder>) {\n    let arena = tokio::task::block_in_place(move || {\n        tokio::runtime::Handle::current().block_on(async move {\n            let mut arena = tracer.into_traces();\n            decoder.populate_traces(arena.nodes_mut()).await;\n            arena\n        })\n    });\n\n    let traces = SparsedTraceArena { arena, ignored: Default::default() };\n    let trace = render_trace_arena_inner(&traces, false, true);\n    node_info!(Traces = %format!(\"\\n{}\", trace));\n}\n\nimpl<CTX> Inspector<CTX, EthInterpreter> for AnvilInspector\nwhere\n    CTX: ContextTr<Journal: JournalExt>,\n{\n    fn initialize_interp(&mut self, interp: &mut Interpreter, ecx: &mut CTX) {\n        call_inspectors!([&mut self.tracer], |inspector| {\n            inspector.initialize_interp(interp, ecx);\n        });\n    }\n\n    fn step(&mut self, interp: &mut Interpreter, ecx: &mut CTX) {\n        call_inspectors!([&mut self.tracer], |inspector| {\n            inspector.step(interp, ecx);\n        });\n    }\n\n    fn step_end(&mut self, interp: &mut Interpreter, ecx: &mut CTX) {\n        call_inspectors!([&mut self.tracer], |inspector| {\n            inspector.step_end(interp, ecx);\n        });\n    }\n\n    #[allow(clippy::redundant_clone)]\n    fn log(&mut self, ecx: &mut CTX, log: Log) {\n        call_inspectors!([&mut self.tracer, &mut self.log_collector], |inspector| {\n            inspector.log(ecx, log.clone());\n        });\n    }\n\n    #[allow(clippy::redundant_clone)]\n    fn log_full(&mut self, interp: &mut Interpreter, ecx: &mut CTX, log: Log) {\n        call_inspectors!([&mut self.tracer, &mut self.log_collector], |inspector| {\n            inspector.log_full(interp, ecx, log.clone());\n        });\n    }\n\n    fn call(&mut self, ecx: &mut CTX, inputs: &mut CallInputs) -> Option<CallOutcome> {\n        call_inspectors!(\n            #[ret]\n            [&mut self.tracer, &mut self.log_collector, &mut self.transfer],\n            |inspector| inspector.call(ecx, inputs).map(Some),\n        );\n        None\n    }\n\n    fn call_end(&mut self, ecx: &mut CTX, inputs: &CallInputs, outcome: &mut CallOutcome) {\n        if let Some(tracer) = &mut self.tracer {\n            tracer.call_end(ecx, inputs, outcome);\n        }\n    }\n\n    fn create(&mut self, ecx: &mut CTX, inputs: &mut CreateInputs) -> Option<CreateOutcome> {\n        call_inspectors!(\n            #[ret]\n            [&mut self.tracer, &mut self.transfer],\n            |inspector| inspector.create(ecx, inputs).map(Some),\n        );\n        None\n    }\n\n    fn create_end(&mut self, ecx: &mut CTX, inputs: &CreateInputs, outcome: &mut CreateOutcome) {\n        if let Some(tracer) = &mut self.tracer {\n            tracer.create_end(ecx, inputs, outcome);\n        }\n    }\n\n    fn selfdestruct(&mut self, contract: Address, target: Address, value: U256) {\n        call_inspectors!([&mut self.tracer, &mut self.transfer], |inspector| {\n            Inspector::<CTX, EthInterpreter>::selfdestruct(inspector, contract, target, value)\n        });\n    }\n}\n\n/// Prints all the logs\npub fn print_logs(logs: &[Log]) {\n    for log in decode_console_logs(logs) {\n        tracing::info!(target: crate::logging::EVM_CONSOLE_LOG_TARGET, \"{}\", log);\n    }\n}\n"
  },
  {
    "path": "crates/anvil/src/eth/backend/mem/mod.rs",
    "content": "//! In-memory blockchain backend.\nuse self::state::trie_storage;\nuse super::executor::new_eth_evm_with_inspector;\nuse crate::{\n    ForkChoice, NodeConfig, PrecompileFactory,\n    config::PruneStateHistoryConfig,\n    eth::{\n        backend::{\n            cheats::{CheatEcrecover, CheatsManager},\n            db::{AnvilCacheDB, Db, MaybeFullDatabase, SerializableState, StateDb},\n            env::Env,\n            executor::{AnvilBlockExecutorFactory, AnvilExecutionCtx, build_tx_env_for_pending},\n            fork::ClientFork,\n            genesis::GenesisConfig,\n            mem::{\n                state::{storage_root, trie_accounts},\n                storage::MinedTransactionReceipt,\n            },\n            notifications::{NewBlockNotification, NewBlockNotifications},\n            time::{TimeManager, utc_from_secs},\n            validate::TransactionValidator,\n        },\n        error::{BlockchainError, ErrDetail, InvalidTransactionError},\n        fees::{FeeDetails, FeeManager, MIN_SUGGESTED_PRIORITY_FEE},\n        macros::node_info,\n        pool::transactions::PoolTransaction,\n        sign::build_impersonated,\n    },\n    mem::{\n        inspector::AnvilInspector,\n        storage::{BlockchainStorage, InMemoryBlockStates, MinedBlockOutcome},\n    },\n};\nuse alloy_chains::NamedChain;\nuse alloy_consensus::{\n    Blob, BlockHeader, EnvKzgSettings, Header, Signed, Transaction as TransactionTrait,\n    TrieAccount, TxEnvelope, TxReceipt, Typed2718,\n    constants::EMPTY_WITHDRAWALS,\n    proofs::{calculate_receipt_root, calculate_transaction_root},\n    transaction::Recovered,\n};\nuse alloy_eips::{\n    BlockNumHash, Encodable2718, eip2935, eip4844::kzg_to_versioned_hash,\n    eip7685::EMPTY_REQUESTS_HASH, eip7840::BlobParams, eip7910::SystemContract,\n};\nuse alloy_evm::{\n    Database, Evm, FromRecoveredTx,\n    block::BlockExecutor,\n    eth::EthEvmContext,\n    overrides::{OverrideBlockHashes, apply_state_overrides},\n    precompiles::{DynPrecompile, Precompile, PrecompilesMap},\n};\nuse alloy_network::{\n    AnyHeader, AnyRpcBlock, AnyRpcHeader, AnyRpcTransaction, AnyTxEnvelope, AnyTxType, Network,\n    ReceiptResponse, TransactionBuilder, UnknownTxEnvelope, UnknownTypedTransaction,\n};\nuse alloy_primitives::{\n    Address, B256, Bloom, BloomInput, Bytes, TxHash, TxKind, U64, U256, hex, keccak256, logs_bloom,\n    map::{AddressMap, HashMap, HashSet},\n};\nuse alloy_rpc_types::{\n    AccessList, Block as AlloyBlock, BlockId, BlockNumberOrTag as BlockNumber, BlockTransactions,\n    EIP1186AccountProofResponse as AccountProof, EIP1186StorageProof as StorageProof, Filter,\n    Header as AlloyHeader, Index, Log, Transaction, TransactionReceipt,\n    anvil::Forking,\n    request::TransactionRequest,\n    serde_helpers::JsonStorageKey,\n    simulate::{SimBlock, SimCallResult, SimulatePayload, SimulatedBlock},\n    state::EvmOverrides,\n    trace::{\n        filter::TraceFilter,\n        geth::{\n            FourByteFrame, GethDebugBuiltInTracerType, GethDebugTracerType,\n            GethDebugTracingCallOptions, GethDebugTracingOptions, GethTrace, NoopFrame,\n        },\n        parity::{LocalizedTransactionTrace, TraceResultsWithTransactionHash, TraceType},\n    },\n};\nuse alloy_serde::{OtherFields, WithOtherFields};\nuse alloy_trie::{HashBuilder, Nibbles, proof::ProofRetainer};\nuse anvil_core::eth::{\n    block::{Block, BlockInfo, TypedBlockInfo, create_block},\n    transaction::{MaybeImpersonatedTransaction, PendingTransaction, TransactionInfo},\n};\nuse anvil_rpc::error::RpcError;\nuse chrono::Datelike;\nuse eyre::{Context, Result};\nuse flate2::{Compression, read::GzDecoder, write::GzEncoder};\nuse foundry_evm::{\n    backend::{DatabaseError, DatabaseResult, RevertStateSnapshotAction},\n    constants::DEFAULT_CREATE2_DEPLOYER_RUNTIME_CODE,\n    core::{either_evm::EitherEvm, precompiles::EC_RECOVER},\n    decode::RevertDecoder,\n    inspectors::AccessListInspector,\n    traces::{\n        CallTraceDecoder, FourByteInspector, GethTraceBuilder, TracingInspector,\n        TracingInspectorConfig,\n    },\n    utils::{\n        block_env_from_header, get_blob_base_fee_update_fraction,\n        get_blob_base_fee_update_fraction_by_spec_id,\n    },\n};\nuse foundry_primitives::{\n    FoundryNetwork, FoundryReceiptEnvelope, FoundryTransactionRequest, FoundryTxEnvelope,\n    FoundryTxReceipt, get_deposit_tx_parts,\n};\nuse futures::channel::mpsc::{UnboundedSender, unbounded};\nuse op_alloy_consensus::DEPOSIT_TX_TYPE_ID;\nuse op_revm::{OpContext, OpHaltReason, OpTransaction};\nuse parking_lot::{Mutex, RwLock, RwLockUpgradableReadGuard};\nuse revm::{\n    Database as RevmDatabase, DatabaseCommit, Inspector,\n    context::{Block as RevmBlock, BlockEnv, Cfg, TxEnv},\n    context_interface::{\n        block::BlobExcessGasAndPrice,\n        result::{ExecutionResult, Output, ResultAndState},\n    },\n    database::{CacheDB, DbAccount, WrapDatabaseRef},\n    interpreter::InstructionResult,\n    precompile::{PrecompileSpecId, Precompiles},\n    primitives::{KECCAK_EMPTY, hardfork::SpecId},\n    state::AccountInfo,\n};\nuse std::{\n    collections::BTreeMap,\n    fmt::{self, Debug},\n    io::{Read, Write},\n    ops::{Mul, Not},\n    path::PathBuf,\n    sync::Arc,\n    time::Duration,\n};\nuse storage::{Blockchain, DEFAULT_HISTORY_LIMIT, MinedTransaction};\nuse tokio::sync::RwLock as AsyncRwLock;\n\npub mod cache;\npub mod fork_db;\npub mod in_memory_db;\npub mod inspector;\npub mod state;\npub mod storage;\n\n/// Helper trait that combines revm::DatabaseRef with Debug.\n/// This is needed because alloy-evm requires Debug on Database implementations.\n/// With trait upcasting now stable, we can now upcast from this trait to revm::DatabaseRef.\npub trait DatabaseRef: revm::DatabaseRef<Error = DatabaseError> + Debug {}\nimpl<T> DatabaseRef for T where T: revm::DatabaseRef<Error = DatabaseError> + Debug {}\nimpl DatabaseRef for dyn crate::eth::backend::db::Db {}\n\n// Gas per transaction not creating a contract.\npub const MIN_TRANSACTION_GAS: u128 = 21000;\n// Gas per transaction creating a contract.\npub const MIN_CREATE_GAS: u128 = 53000;\n\npub type State = foundry_evm::utils::StateChangeset;\n\n/// A block request, which includes the Pool Transactions if it's Pending\npub enum BlockRequest<T> {\n    Pending(Vec<Arc<PoolTransaction<T>>>),\n    Number(u64),\n}\n\nimpl<T> fmt::Debug for BlockRequest<T> {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        match self {\n            Self::Pending(txs) => f.debug_tuple(\"Pending\").field(&txs.len()).finish(),\n            Self::Number(n) => f.debug_tuple(\"Number\").field(n).finish(),\n        }\n    }\n}\n\nimpl<T> BlockRequest<T> {\n    pub fn block_number(&self) -> BlockNumber {\n        match *self {\n            Self::Pending(_) => BlockNumber::Pending,\n            Self::Number(n) => BlockNumber::Number(n),\n        }\n    }\n}\n\n/// Gives access to the [revm::Database]\npub struct Backend<N: Network> {\n    /// Access to [`revm::Database`] abstraction.\n    ///\n    /// This will be used in combination with [`alloy_evm::Evm`] and is responsible for feeding\n    /// data to the evm during its execution.\n    ///\n    /// At time of writing, there are two different types of `Db`:\n    ///   - [`MemDb`](crate::mem::in_memory_db::MemDb): everything is stored in memory\n    ///   - [`ForkDb`](crate::mem::fork_db::ForkedDatabase): forks off a remote client, missing\n    ///     data is retrieved via RPC-calls\n    ///\n    /// In order to commit changes to the [`revm::Database`], the [`alloy_evm::Evm`] requires\n    /// mutable access, which requires a write-lock from this `db`. In forking mode, the time\n    /// during which the write-lock is active depends on whether the `ForkDb` can provide all\n    /// requested data from memory or whether it has to retrieve it via RPC calls first. This\n    /// means that it potentially blocks for some time, even taking into account the rate\n    /// limits of RPC endpoints. Therefore the `Db` is guarded by a `tokio::sync::RwLock` here\n    /// so calls that need to read from it, while it's currently written to, don't block. E.g.\n    /// a new block is currently mined and a new [`Self::set_storage_at()`] request is being\n    /// executed.\n    db: Arc<AsyncRwLock<Box<dyn Db>>>,\n    /// stores all block related data in memory.\n    blockchain: Blockchain<N>,\n    /// Historic states of previous blocks.\n    states: Arc<RwLock<InMemoryBlockStates>>,\n    /// Env data of the chain\n    env: Arc<RwLock<Env>>,\n    /// This is set if this is currently forked off another client.\n    fork: Arc<RwLock<Option<ClientFork>>>,\n    /// Provides time related info, like timestamp.\n    time: TimeManager,\n    /// Contains state of custom overrides.\n    cheats: CheatsManager,\n    /// Contains fee data.\n    fees: FeeManager,\n    /// Initialised genesis.\n    genesis: GenesisConfig,\n    /// Listeners for new blocks that get notified when a new block was imported.\n    new_block_listeners: Arc<Mutex<Vec<UnboundedSender<NewBlockNotification>>>>,\n    /// Keeps track of active state snapshots at a specific block.\n    active_state_snapshots: Arc<Mutex<HashMap<U256, (u64, B256)>>>,\n    enable_steps_tracing: bool,\n    print_logs: bool,\n    print_traces: bool,\n    /// Recorder used for decoding traces, used together with print_traces\n    call_trace_decoder: Arc<CallTraceDecoder>,\n    /// How to keep history state\n    prune_state_history_config: PruneStateHistoryConfig,\n    /// max number of blocks with transactions in memory\n    transaction_block_keeper: Option<usize>,\n    node_config: Arc<AsyncRwLock<NodeConfig>>,\n    /// Slots in an epoch\n    slots_in_an_epoch: u64,\n    /// Precompiles to inject to the EVM.\n    precompile_factory: Option<Arc<dyn PrecompileFactory>>,\n    /// Prevent race conditions during mining\n    mining: Arc<tokio::sync::Mutex<()>>,\n    /// Disable pool balance checks\n    disable_pool_balance_checks: bool,\n}\n\nimpl<N: Network> Clone for Backend<N> {\n    fn clone(&self) -> Self {\n        Self {\n            db: self.db.clone(),\n            blockchain: self.blockchain.clone(),\n            states: self.states.clone(),\n            env: self.env.clone(),\n            fork: self.fork.clone(),\n            time: self.time.clone(),\n            cheats: self.cheats.clone(),\n            fees: self.fees.clone(),\n            genesis: self.genesis.clone(),\n            new_block_listeners: self.new_block_listeners.clone(),\n            active_state_snapshots: self.active_state_snapshots.clone(),\n            enable_steps_tracing: self.enable_steps_tracing,\n            print_logs: self.print_logs,\n            print_traces: self.print_traces,\n            call_trace_decoder: self.call_trace_decoder.clone(),\n            prune_state_history_config: self.prune_state_history_config,\n            transaction_block_keeper: self.transaction_block_keeper,\n            node_config: self.node_config.clone(),\n            slots_in_an_epoch: self.slots_in_an_epoch,\n            precompile_factory: self.precompile_factory.clone(),\n            mining: self.mining.clone(),\n            disable_pool_balance_checks: self.disable_pool_balance_checks,\n        }\n    }\n}\n\nimpl<N: Network> fmt::Debug for Backend<N> {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.debug_struct(\"Backend\").finish_non_exhaustive()\n    }\n}\n\n// Methods that are generic over any Network.\nimpl<N: Network> Backend<N> {\n    /// Sets the account to impersonate\n    ///\n    /// Returns `true` if the account is already impersonated\n    pub fn impersonate(&self, addr: Address) -> bool {\n        if self.cheats.impersonated_accounts().contains(&addr) {\n            return true;\n        }\n        // Ensure EIP-3607 is disabled\n        let mut env = self.env.write();\n        env.evm_env.cfg_env.disable_eip3607 = true;\n        self.cheats.impersonate(addr)\n    }\n\n    /// Removes the account that from the impersonated set\n    ///\n    /// If the impersonated `addr` is a contract then we also reset the code here\n    pub fn stop_impersonating(&self, addr: Address) {\n        self.cheats.stop_impersonating(&addr);\n    }\n\n    /// If set to true will make every account impersonated\n    pub fn auto_impersonate_account(&self, enabled: bool) {\n        self.cheats.set_auto_impersonate_account(enabled);\n    }\n\n    /// Returns the configured fork, if any\n    pub fn get_fork(&self) -> Option<ClientFork> {\n        self.fork.read().clone()\n    }\n\n    /// Returns the database\n    pub fn get_db(&self) -> &Arc<AsyncRwLock<Box<dyn Db>>> {\n        &self.db\n    }\n\n    /// Returns the `AccountInfo` from the database\n    pub async fn get_account(&self, address: Address) -> DatabaseResult<AccountInfo> {\n        Ok(self.db.read().await.basic_ref(address)?.unwrap_or_default())\n    }\n\n    /// Whether we're forked off some remote client\n    pub fn is_fork(&self) -> bool {\n        self.fork.read().is_some()\n    }\n\n    /// Writes the CREATE2 deployer code directly to the database at the address provided.\n    pub async fn set_create2_deployer(&self, address: Address) -> DatabaseResult<()> {\n        self.set_code(address, Bytes::from_static(DEFAULT_CREATE2_DEPLOYER_RUNTIME_CODE)).await?;\n        Ok(())\n    }\n\n    /// Updates memory limits that should be more strict when auto-mine is enabled\n    pub(crate) fn update_interval_mine_block_time(&self, block_time: Duration) {\n        self.states.write().update_interval_mine_block_time(block_time)\n    }\n\n    /// Returns the `TimeManager` responsible for timestamps\n    pub fn time(&self) -> &TimeManager {\n        &self.time\n    }\n\n    /// Returns the `CheatsManager` responsible for executing cheatcodes\n    pub fn cheats(&self) -> &CheatsManager {\n        &self.cheats\n    }\n\n    /// Whether to skip blob validation\n    pub fn skip_blob_validation(&self, impersonator: Option<Address>) -> bool {\n        self.cheats().auto_impersonate_accounts()\n            || impersonator\n                .is_some_and(|addr| self.cheats().impersonated_accounts().contains(&addr))\n    }\n\n    /// Returns the `FeeManager` that manages fee/pricings\n    pub fn fees(&self) -> &FeeManager {\n        &self.fees\n    }\n\n    /// The env data of the blockchain\n    pub fn env(&self) -> &Arc<RwLock<Env>> {\n        &self.env\n    }\n\n    /// Returns the current best hash of the chain\n    pub fn best_hash(&self) -> B256 {\n        self.blockchain.storage.read().best_hash\n    }\n\n    /// Returns the current best number of the chain\n    pub fn best_number(&self) -> u64 {\n        self.blockchain.storage.read().best_number\n    }\n\n    /// Sets the block number\n    pub fn set_block_number(&self, number: u64) {\n        let mut env = self.env.write();\n        env.evm_env.block_env.number = U256::from(number);\n    }\n\n    /// Returns the client coinbase address.\n    pub fn coinbase(&self) -> Address {\n        self.env.read().evm_env.block_env.beneficiary\n    }\n\n    /// Returns the client coinbase address.\n    pub fn chain_id(&self) -> U256 {\n        U256::from(self.env.read().evm_env.cfg_env.chain_id)\n    }\n\n    pub fn set_chain_id(&self, chain_id: u64) {\n        self.env.write().evm_env.cfg_env.chain_id = chain_id;\n    }\n\n    /// Returns the genesis data for the Beacon API.\n    pub fn genesis_time(&self) -> u64 {\n        self.genesis.timestamp\n    }\n\n    /// Returns balance of the given account.\n    pub async fn current_balance(&self, address: Address) -> DatabaseResult<U256> {\n        Ok(self.get_account(address).await?.balance)\n    }\n\n    /// Returns balance of the given account.\n    pub async fn current_nonce(&self, address: Address) -> DatabaseResult<u64> {\n        Ok(self.get_account(address).await?.nonce)\n    }\n\n    /// Sets the coinbase address\n    pub fn set_coinbase(&self, address: Address) {\n        self.env.write().evm_env.block_env.beneficiary = address;\n    }\n\n    /// Sets the nonce of the given address\n    pub async fn set_nonce(&self, address: Address, nonce: U256) -> DatabaseResult<()> {\n        self.db.write().await.set_nonce(address, nonce.try_into().unwrap_or(u64::MAX))\n    }\n\n    /// Sets the balance of the given address\n    pub async fn set_balance(&self, address: Address, balance: U256) -> DatabaseResult<()> {\n        self.db.write().await.set_balance(address, balance)\n    }\n\n    /// Sets the code of the given address\n    pub async fn set_code(&self, address: Address, code: Bytes) -> DatabaseResult<()> {\n        self.db.write().await.set_code(address, code)\n    }\n\n    /// Sets the value for the given slot of the given address\n    pub async fn set_storage_at(\n        &self,\n        address: Address,\n        slot: U256,\n        val: B256,\n    ) -> DatabaseResult<()> {\n        self.db.write().await.set_storage_at(address, slot.into(), val)\n    }\n\n    /// Returns the configured specid\n    pub fn spec_id(&self) -> SpecId {\n        self.env.read().evm_env.cfg_env.spec\n    }\n\n    /// Returns true for post London\n    pub fn is_eip1559(&self) -> bool {\n        (self.spec_id() as u8) >= (SpecId::LONDON as u8)\n    }\n\n    /// Returns true for post Merge\n    pub fn is_eip3675(&self) -> bool {\n        (self.spec_id() as u8) >= (SpecId::MERGE as u8)\n    }\n\n    /// Returns true for post Berlin\n    pub fn is_eip2930(&self) -> bool {\n        (self.spec_id() as u8) >= (SpecId::BERLIN as u8)\n    }\n\n    /// Returns true for post Cancun\n    pub fn is_eip4844(&self) -> bool {\n        (self.spec_id() as u8) >= (SpecId::CANCUN as u8)\n    }\n\n    /// Returns true for post Prague\n    pub fn is_eip7702(&self) -> bool {\n        (self.spec_id() as u8) >= (SpecId::PRAGUE as u8)\n    }\n\n    /// Returns true if op-stack deposits are active\n    pub fn is_optimism(&self) -> bool {\n        self.env.read().networks.is_optimism()\n    }\n\n    /// Returns the precompiles for the current spec.\n    pub fn precompiles(&self) -> BTreeMap<String, Address> {\n        let spec_id = self.env.read().evm_env.cfg_env.spec;\n        let precompiles = Precompiles::new(PrecompileSpecId::from_spec_id(spec_id));\n\n        let mut precompiles_map = BTreeMap::<String, Address>::default();\n        for (address, precompile) in precompiles.inner() {\n            precompiles_map.insert(precompile.id().name().to_string(), *address);\n        }\n\n        // Extend with configured network precompiles.\n        precompiles_map.extend(self.env.read().networks.precompiles());\n\n        if let Some(factory) = &self.precompile_factory {\n            for (address, precompile) in factory.precompiles() {\n                precompiles_map.insert(precompile.precompile_id().to_string(), address);\n            }\n        }\n\n        precompiles_map\n    }\n\n    /// Returns the system contracts for the current spec.\n    pub fn system_contracts(&self) -> BTreeMap<SystemContract, Address> {\n        let mut system_contracts = BTreeMap::<SystemContract, Address>::default();\n\n        let spec_id = self.env.read().evm_env.cfg_env.spec;\n\n        if spec_id >= SpecId::CANCUN {\n            system_contracts.extend(SystemContract::cancun());\n        }\n\n        if spec_id >= SpecId::PRAGUE {\n            system_contracts.extend(SystemContract::prague(None));\n        }\n\n        system_contracts\n    }\n\n    /// Returns [`BlobParams`] corresponding to the current spec.\n    pub fn blob_params(&self) -> BlobParams {\n        let spec_id = self.env.read().evm_env.cfg_env.spec;\n\n        if spec_id >= SpecId::OSAKA {\n            return BlobParams::osaka();\n        }\n\n        if spec_id >= SpecId::PRAGUE {\n            return BlobParams::prague();\n        }\n\n        BlobParams::cancun()\n    }\n\n    /// Returns an error if EIP1559 is not active (pre Berlin)\n    pub fn ensure_eip1559_active(&self) -> Result<(), BlockchainError> {\n        if self.is_eip1559() {\n            return Ok(());\n        }\n        Err(BlockchainError::EIP1559TransactionUnsupportedAtHardfork)\n    }\n\n    /// Returns an error if EIP1559 is not active (pre muirGlacier)\n    pub fn ensure_eip2930_active(&self) -> Result<(), BlockchainError> {\n        if self.is_eip2930() {\n            return Ok(());\n        }\n        Err(BlockchainError::EIP2930TransactionUnsupportedAtHardfork)\n    }\n\n    pub fn ensure_eip4844_active(&self) -> Result<(), BlockchainError> {\n        if self.is_eip4844() {\n            return Ok(());\n        }\n        Err(BlockchainError::EIP4844TransactionUnsupportedAtHardfork)\n    }\n\n    pub fn ensure_eip7702_active(&self) -> Result<(), BlockchainError> {\n        if self.is_eip7702() {\n            return Ok(());\n        }\n        Err(BlockchainError::EIP7702TransactionUnsupportedAtHardfork)\n    }\n\n    /// Returns an error if op-stack deposits are not active\n    pub fn ensure_op_deposits_active(&self) -> Result<(), BlockchainError> {\n        if self.is_optimism() {\n            return Ok(());\n        }\n        Err(BlockchainError::DepositTransactionUnsupported)\n    }\n\n    /// Returns the block gas limit\n    pub fn gas_limit(&self) -> u64 {\n        self.env.read().evm_env.block_env.gas_limit\n    }\n\n    /// Sets the block gas limit\n    pub fn set_gas_limit(&self, gas_limit: u64) {\n        self.env.write().evm_env.block_env.gas_limit = gas_limit;\n    }\n\n    /// Returns the current base fee\n    pub fn base_fee(&self) -> u64 {\n        self.fees.base_fee()\n    }\n\n    /// Returns whether the minimum suggested priority fee is enforced\n    pub fn is_min_priority_fee_enforced(&self) -> bool {\n        self.fees.is_min_priority_fee_enforced()\n    }\n\n    pub fn excess_blob_gas_and_price(&self) -> Option<BlobExcessGasAndPrice> {\n        self.fees.excess_blob_gas_and_price()\n    }\n\n    /// Sets the current basefee\n    pub fn set_base_fee(&self, basefee: u64) {\n        self.fees.set_base_fee(basefee)\n    }\n\n    /// Sets the gas price\n    pub fn set_gas_price(&self, price: u128) {\n        self.fees.set_gas_price(price)\n    }\n\n    pub fn elasticity(&self) -> f64 {\n        self.fees.elasticity()\n    }\n\n    /// Returns the total difficulty of the chain until this block\n    ///\n    /// Note: this will always be `0` in memory mode\n    /// In forking mode this will always be the total difficulty of the forked block\n    pub fn total_difficulty(&self) -> U256 {\n        self.blockchain.storage.read().total_difficulty\n    }\n\n    /// Creates a new `evm_snapshot` at the current height.\n    ///\n    /// Returns the id of the snapshot created.\n    pub async fn create_state_snapshot(&self) -> U256 {\n        let num = self.best_number();\n        let hash = self.best_hash();\n        let id = self.db.write().await.snapshot_state();\n        trace!(target: \"backend\", \"creating snapshot {} at {}\", id, num);\n        self.active_state_snapshots.lock().insert(id, (num, hash));\n        id\n    }\n\n    pub fn list_state_snapshots(&self) -> BTreeMap<U256, (u64, B256)> {\n        self.active_state_snapshots.lock().clone().into_iter().collect()\n    }\n\n    /// Returns the environment for the next block\n    fn next_env(&self) -> Env {\n        let mut env = self.env.read().clone();\n        // increase block number for this block\n        env.evm_env.block_env.number = env.evm_env.block_env.number.saturating_add(U256::from(1));\n        env.evm_env.block_env.basefee = self.base_fee();\n        env.evm_env.block_env.blob_excess_gas_and_price = self.excess_blob_gas_and_price();\n        env.evm_env.block_env.timestamp = U256::from(self.time.current_call_timestamp());\n        env\n    }\n\n    /// Builds [`Inspector`] with the configured options.\n    fn build_inspector(&self) -> AnvilInspector {\n        let mut inspector = AnvilInspector::default();\n\n        if self.print_logs {\n            inspector = inspector.with_log_collector();\n        }\n        if self.print_traces {\n            inspector = inspector.with_trace_printer();\n        }\n\n        inspector\n    }\n\n    /// Returns a new block event stream that yields Notifications when a new block was added\n    pub fn new_block_notifications(&self) -> NewBlockNotifications {\n        let (tx, rx) = unbounded();\n        self.new_block_listeners.lock().push(tx);\n        trace!(target: \"backed\", \"added new block listener\");\n        rx\n    }\n\n    /// Notifies all `new_block_listeners` about the new block\n    fn notify_on_new_block(&self, header: Header, hash: B256) {\n        // cleanup closed notification streams first, if the channel is closed we can remove the\n        // sender half for the set\n        self.new_block_listeners.lock().retain(|tx| !tx.is_closed());\n\n        let notification = NewBlockNotification { hash, header: Arc::new(header) };\n\n        self.new_block_listeners\n            .lock()\n            .retain(|tx| tx.unbounded_send(notification.clone()).is_ok());\n    }\n\n    /// Returns the block number for the given block id\n    pub fn convert_block_number(&self, block: Option<BlockNumber>) -> u64 {\n        let current = self.best_number();\n        match block.unwrap_or(BlockNumber::Latest) {\n            BlockNumber::Latest | BlockNumber::Pending => current,\n            BlockNumber::Earliest => 0,\n            BlockNumber::Number(num) => num,\n            BlockNumber::Safe => current.saturating_sub(self.slots_in_an_epoch),\n            BlockNumber::Finalized => current.saturating_sub(self.slots_in_an_epoch * 2),\n        }\n    }\n\n    /// Returns the block and its hash for the given id\n    fn get_block_with_hash(&self, id: impl Into<BlockId>) -> Option<(Block, B256)> {\n        let hash = match id.into() {\n            BlockId::Hash(hash) => hash.block_hash,\n            BlockId::Number(number) => {\n                let storage = self.blockchain.storage.read();\n                let slots_in_an_epoch = self.slots_in_an_epoch;\n                match number {\n                    BlockNumber::Latest => storage.best_hash,\n                    BlockNumber::Earliest => storage.genesis_hash,\n                    BlockNumber::Pending => return None,\n                    BlockNumber::Number(num) => *storage.hashes.get(&num)?,\n                    BlockNumber::Safe => {\n                        if storage.best_number > (slots_in_an_epoch) {\n                            *storage.hashes.get(&(storage.best_number - (slots_in_an_epoch)))?\n                        } else {\n                            storage.genesis_hash // treat the genesis block as safe \"by definition\"\n                        }\n                    }\n                    BlockNumber::Finalized => {\n                        if storage.best_number > (slots_in_an_epoch * 2) {\n                            *storage.hashes.get(&(storage.best_number - (slots_in_an_epoch * 2)))?\n                        } else {\n                            storage.genesis_hash\n                        }\n                    }\n                }\n            }\n        };\n        let block = self.get_block_by_hash(hash)?;\n        Some((block, hash))\n    }\n\n    pub fn get_block(&self, id: impl Into<BlockId>) -> Option<Block> {\n        self.get_block_with_hash(id).map(|(block, _)| block)\n    }\n\n    pub fn get_block_by_hash(&self, hash: B256) -> Option<Block> {\n        self.blockchain.get_block_by_hash(&hash)\n    }\n\n    /// Returns the traces for the given transaction\n    pub(crate) fn mined_parity_trace_transaction(\n        &self,\n        hash: B256,\n    ) -> Option<Vec<LocalizedTransactionTrace>> {\n        self.blockchain.storage.read().transactions.get(&hash).map(|tx| tx.parity_traces())\n    }\n\n    /// Returns the traces for the given block\n    pub(crate) fn mined_parity_trace_block(\n        &self,\n        block: u64,\n    ) -> Option<Vec<LocalizedTransactionTrace>> {\n        let block = self.get_block(block)?;\n        let mut traces = vec![];\n        let storage = self.blockchain.storage.read();\n        for tx in block.body.transactions {\n            traces.extend(storage.transactions.get(&tx.hash())?.parity_traces());\n        }\n        Some(traces)\n    }\n\n    /// Returns the mined transaction for the given hash\n    pub(crate) fn mined_transaction(&self, hash: B256) -> Option<MinedTransaction<N>> {\n        self.blockchain.storage.read().transactions.get(&hash).cloned()\n    }\n\n    /// Overrides the given signature to impersonate the specified address during ecrecover.\n    pub async fn impersonate_signature(\n        &self,\n        signature: Bytes,\n        address: Address,\n    ) -> Result<(), BlockchainError> {\n        self.cheats.add_recover_override(signature, address);\n        Ok(())\n    }\n\n    /// Returns code by its hash\n    pub async fn debug_code_by_hash(\n        &self,\n        code_hash: B256,\n        block_id: Option<BlockId>,\n    ) -> Result<Option<Bytes>, BlockchainError> {\n        if let Ok(code) = self.db.read().await.code_by_hash_ref(code_hash) {\n            return Ok(Some(code.original_bytes()));\n        }\n        if let Some(fork) = self.get_fork() {\n            return Ok(fork.debug_code_by_hash(code_hash, block_id).await?);\n        }\n\n        Ok(None)\n    }\n\n    /// Returns the value associated with a key from the database\n    /// Currently only supports bytecode lookups.\n    ///\n    /// Based on Reth implementation: <https://github.com/paradigmxyz/reth/blob/66cfa9ed1a8c4bc2424aacf6fb2c1e67a78ee9a2/crates/rpc/rpc/src/debug.rs#L1146-L1178>\n    ///\n    /// Key should be: 0x63 (1-byte prefix) + 32 bytes (code_hash)\n    /// Total key length must be 33 bytes.\n    pub async fn debug_db_get(&self, key: String) -> Result<Option<Bytes>, BlockchainError> {\n        let key_bytes = if key.starts_with(\"0x\") {\n            hex::decode(&key)\n                .map_err(|_| BlockchainError::Message(\"Invalid hex key\".to_string()))?\n        } else {\n            key.into_bytes()\n        };\n\n        // Validate key length: must be 33 bytes (1 byte prefix + 32 bytes code hash)\n        if key_bytes.len() != 33 {\n            return Err(BlockchainError::Message(format!(\n                \"Invalid key length: expected 33 bytes, got {}\",\n                key_bytes.len()\n            )));\n        }\n\n        // Check for bytecode prefix (0x63 = 'c' in ASCII)\n        if key_bytes[0] != 0x63 {\n            return Err(BlockchainError::Message(\n                \"Key prefix must be 0x63 for code hash lookups\".to_string(),\n            ));\n        }\n\n        let code_hash = B256::from_slice(&key_bytes[1..33]);\n\n        // Use the existing debug_code_by_hash method to retrieve the bytecode\n        self.debug_code_by_hash(code_hash, None).await\n    }\n\n    fn mined_block_by_hash(&self, hash: B256) -> Option<AnyRpcBlock> {\n        let block = self.blockchain.get_block_by_hash(&hash)?;\n        Some(self.convert_block_with_hash(block, Some(hash)))\n    }\n\n    pub(crate) async fn mined_transactions_by_block_number(\n        &self,\n        number: BlockNumber,\n    ) -> Option<Vec<AnyRpcTransaction>> {\n        if let Some(block) = self.get_block(number) {\n            return self.mined_transactions_in_block(&block);\n        }\n        None\n    }\n\n    /// Returns all transactions given a block\n    pub(crate) fn mined_transactions_in_block(\n        &self,\n        block: &Block,\n    ) -> Option<Vec<AnyRpcTransaction>> {\n        let mut transactions = Vec::with_capacity(block.body.transactions.len());\n        let base_fee = block.header.base_fee_per_gas();\n        let storage = self.blockchain.storage.read();\n        for hash in block.body.transactions.iter().map(|tx| tx.hash()) {\n            let info = storage.transactions.get(&hash)?.info.clone();\n            let tx = block.body.transactions.get(info.transaction_index as usize)?.clone();\n\n            let tx = transaction_build(Some(hash), tx, Some(block), Some(info), base_fee);\n            transactions.push(tx);\n        }\n        Some(transactions)\n    }\n\n    pub fn mined_block_by_number(&self, number: BlockNumber) -> Option<AnyRpcBlock> {\n        let (block, hash) = self.get_block_with_hash(number)?;\n        let mut block = self.convert_block_with_hash(block, Some(hash));\n        block.transactions.convert_to_hashes();\n        Some(block)\n    }\n\n    pub fn get_full_block(&self, id: impl Into<BlockId>) -> Option<AnyRpcBlock> {\n        let (block, hash) = self.get_block_with_hash(id)?;\n        let transactions = self.mined_transactions_in_block(&block)?;\n        let mut block = self.convert_block_with_hash(block, Some(hash));\n        block.inner.transactions = BlockTransactions::Full(transactions);\n        Some(block)\n    }\n\n    /// Takes a block as it's stored internally and returns the eth api conform block format.\n    pub fn convert_block(&self, block: Block) -> AnyRpcBlock {\n        self.convert_block_with_hash(block, None)\n    }\n\n    /// Takes a block as it's stored internally and returns the eth api conform block format.\n    /// If `known_hash` is provided, it will be used instead of computing `hash_slow()`.\n    pub fn convert_block_with_hash(&self, block: Block, known_hash: Option<B256>) -> AnyRpcBlock {\n        let size = U256::from(alloy_rlp::encode(&block).len() as u32);\n\n        let header = block.header.clone();\n        let transactions = block.body.transactions;\n\n        let hash = known_hash.unwrap_or_else(|| header.hash_slow());\n        let Header { number, withdrawals_root, .. } = header;\n\n        let block = AlloyBlock {\n            header: AlloyHeader {\n                inner: AnyHeader::from(header),\n                hash,\n                total_difficulty: Some(self.total_difficulty()),\n                size: Some(size),\n            },\n            transactions: alloy_rpc_types::BlockTransactions::Hashes(\n                transactions.into_iter().map(|tx| tx.hash()).collect(),\n            ),\n            uncles: vec![],\n            withdrawals: withdrawals_root.map(|_| Default::default()),\n        };\n\n        let mut block = WithOtherFields::new(block);\n\n        // If Arbitrum, apply chain specifics to converted block.\n        if is_arbitrum(self.env.read().evm_env.cfg_env.chain_id) {\n            // Set `l1BlockNumber` field.\n            block.other.insert(\"l1BlockNumber\".to_string(), number.into());\n        }\n\n        AnyRpcBlock::from(block)\n    }\n\n    pub async fn block_by_hash(&self, hash: B256) -> Result<Option<AnyRpcBlock>, BlockchainError> {\n        trace!(target: \"backend\", \"get block by hash {:?}\", hash);\n        if let tx @ Some(_) = self.mined_block_by_hash(hash) {\n            return Ok(tx);\n        }\n\n        if let Some(fork) = self.get_fork() {\n            return Ok(fork.block_by_hash(hash).await?);\n        }\n\n        Ok(None)\n    }\n\n    pub async fn block_by_hash_full(\n        &self,\n        hash: B256,\n    ) -> Result<Option<AnyRpcBlock>, BlockchainError> {\n        trace!(target: \"backend\", \"get block by hash {:?}\", hash);\n        if let tx @ Some(_) = self.get_full_block(hash) {\n            return Ok(tx);\n        }\n\n        if let Some(fork) = self.get_fork() {\n            return Ok(fork.block_by_hash_full(hash).await?);\n        }\n\n        Ok(None)\n    }\n\n    pub async fn block_by_number(\n        &self,\n        number: BlockNumber,\n    ) -> Result<Option<AnyRpcBlock>, BlockchainError> {\n        trace!(target: \"backend\", \"get block by number {:?}\", number);\n        if let tx @ Some(_) = self.mined_block_by_number(number) {\n            return Ok(tx);\n        }\n\n        if let Some(fork) = self.get_fork() {\n            let number = self.convert_block_number(Some(number));\n            if fork.predates_fork_inclusive(number) {\n                return Ok(fork.block_by_number(number).await?);\n            }\n        }\n\n        Ok(None)\n    }\n\n    pub async fn block_by_number_full(\n        &self,\n        number: BlockNumber,\n    ) -> Result<Option<AnyRpcBlock>, BlockchainError> {\n        trace!(target: \"backend\", \"get block by number {:?}\", number);\n        if let tx @ Some(_) = self.get_full_block(number) {\n            return Ok(tx);\n        }\n\n        if let Some(fork) = self.get_fork() {\n            let number = self.convert_block_number(Some(number));\n            if fork.predates_fork_inclusive(number) {\n                return Ok(fork.block_by_number_full(number).await?);\n            }\n        }\n\n        Ok(None)\n    }\n\n    /// Converts the `BlockNumber` into a numeric value\n    ///\n    /// # Errors\n    ///\n    /// returns an error if the requested number is larger than the current height\n    pub async fn ensure_block_number<T: Into<BlockId>>(\n        &self,\n        block_id: Option<T>,\n    ) -> Result<u64, BlockchainError> {\n        let current = self.best_number();\n        let requested =\n            match block_id.map(Into::into).unwrap_or(BlockId::Number(BlockNumber::Latest)) {\n                BlockId::Hash(hash) => {\n                    self.block_by_hash(hash.block_hash)\n                        .await?\n                        .ok_or(BlockchainError::BlockNotFound)?\n                        .header\n                        .number\n                }\n                BlockId::Number(num) => match num {\n                    BlockNumber::Latest | BlockNumber::Pending => current,\n                    BlockNumber::Earliest => U64::ZERO.to::<u64>(),\n                    BlockNumber::Number(num) => num,\n                    BlockNumber::Safe => current.saturating_sub(self.slots_in_an_epoch),\n                    BlockNumber::Finalized => current.saturating_sub(self.slots_in_an_epoch * 2),\n                },\n            };\n\n        if requested > current {\n            Err(BlockchainError::BlockOutOfRange(current, requested))\n        } else {\n            Ok(requested)\n        }\n    }\n\n    /// Creates an EVM instance with optionally injected precompiles.\n    fn new_eth_evm_with_inspector_ref<'db, I, DB>(\n        &self,\n        db: &'db DB,\n        env: &Env,\n        inspector: &'db mut I,\n    ) -> EitherEvm<WrapDatabaseRef<&'db DB>, &'db mut I, PrecompilesMap>\n    where\n        DB: DatabaseRef + ?Sized,\n        I: Inspector<EthEvmContext<WrapDatabaseRef<&'db DB>>>\n            + Inspector<OpContext<WrapDatabaseRef<&'db DB>>>,\n        WrapDatabaseRef<&'db DB>: Database<Error = DatabaseError>,\n    {\n        let mut evm = new_eth_evm_with_inspector(WrapDatabaseRef(db), env, inspector);\n        self.env.read().networks.inject_precompiles(evm.precompiles_mut());\n\n        if let Some(factory) = &self.precompile_factory {\n            evm.precompiles_mut().extend_precompiles(factory.precompiles());\n        }\n\n        let cheats = Arc::new(self.cheats.clone());\n        if cheats.has_recover_overrides() {\n            let cheat_ecrecover = CheatEcrecover::new(Arc::clone(&cheats));\n            evm.precompiles_mut().apply_precompile(&EC_RECOVER, move |_| {\n                Some(DynPrecompile::new_stateful(\n                    cheat_ecrecover.precompile_id().clone(),\n                    move |input| cheat_ecrecover.call(input),\n                ))\n            });\n        }\n\n        evm\n    }\n\n    /// ## EVM settings\n    ///\n    /// This modifies certain EVM settings to mirror geth's `SkipAccountChecks` when transacting requests, see also: <https://github.com/ethereum/go-ethereum/blob/380688c636a654becc8f114438c2a5d93d2db032/core/state_transition.go#L145-L148>:\n    ///\n    ///  - `disable_eip3607` is set to `true`\n    ///  - `disable_base_fee` is set to `true`\n    ///  - `tx_gas_limit_cap` is set to `Some(u64::MAX)` indicating no gas limit cap\n    ///  - `nonce` check is skipped\n    fn build_call_env(\n        &self,\n        request: WithOtherFields<TransactionRequest>,\n        fee_details: FeeDetails,\n        block_env: BlockEnv,\n    ) -> Env {\n        let tx_type = request.minimal_tx_type() as u8;\n\n        let WithOtherFields::<TransactionRequest> {\n            inner:\n                TransactionRequest {\n                    from,\n                    to,\n                    gas,\n                    value,\n                    input,\n                    access_list,\n                    blob_versioned_hashes,\n                    authorization_list,\n                    nonce,\n                    sidecar: _,\n                    chain_id,\n                    .. // Rest of the gas fees related fields are taken from `fee_details`\n                },\n            other,\n        } = request;\n\n        let FeeDetails {\n            gas_price,\n            max_fee_per_gas,\n            max_priority_fee_per_gas,\n            max_fee_per_blob_gas,\n        } = fee_details;\n\n        let gas_limit = gas.unwrap_or(block_env.gas_limit);\n        let mut env = self.env.read().clone();\n        env.evm_env.block_env = block_env;\n        // we want to disable this in eth_call, since this is common practice used by other node\n        // impls and providers <https://github.com/foundry-rs/foundry/issues/4388>\n        env.evm_env.cfg_env.disable_block_gas_limit = true;\n        env.evm_env.cfg_env.tx_gas_limit_cap = Some(u64::MAX);\n\n        // The basefee should be ignored for calls against state for\n        // - eth_call\n        // - eth_estimateGas\n        // - eth_createAccessList\n        // - tracing\n        env.evm_env.cfg_env.disable_base_fee = true;\n\n        // Disable nonce check in revm\n        env.evm_env.cfg_env.disable_nonce_check = true;\n\n        let gas_price = gas_price.or(max_fee_per_gas).unwrap_or_else(|| {\n            self.fees().raw_gas_price().saturating_add(MIN_SUGGESTED_PRIORITY_FEE)\n        });\n        let caller = from.unwrap_or_default();\n        let to = to.as_ref().and_then(TxKind::to);\n        let blob_hashes = blob_versioned_hashes.unwrap_or_default();\n        let mut base = TxEnv {\n            caller,\n            gas_limit,\n            gas_price,\n            gas_priority_fee: max_priority_fee_per_gas,\n            max_fee_per_blob_gas: max_fee_per_blob_gas\n                .or_else(|| {\n                    if !blob_hashes.is_empty() {\n                        env.evm_env.block_env.blob_gasprice()\n                    } else {\n                        Some(0)\n                    }\n                })\n                .unwrap_or_default(),\n            kind: match to {\n                Some(addr) => TxKind::Call(*addr),\n                None => TxKind::Create,\n            },\n            tx_type,\n            value: value.unwrap_or_default(),\n            data: input.into_input().unwrap_or_default(),\n            chain_id: Some(chain_id.unwrap_or(self.env.read().evm_env.cfg_env.chain_id)),\n            access_list: access_list.unwrap_or_default(),\n            blob_hashes,\n            ..Default::default()\n        };\n        base.set_signed_authorization(authorization_list.unwrap_or_default());\n        env.tx = OpTransaction { base, ..Default::default() };\n\n        if let Some(nonce) = nonce {\n            env.tx.base.nonce = nonce;\n        }\n\n        if env.evm_env.block_env.basefee == 0 {\n            // this is an edge case because the evm fails if `tx.effective_gas_price < base_fee`\n            // 0 is only possible if it's manually set\n            env.evm_env.cfg_env.disable_base_fee = true;\n        }\n\n        // Deposit transaction?\n        if let Ok(deposit) = get_deposit_tx_parts(&other) {\n            env.tx.deposit = deposit;\n        }\n\n        env\n    }\n\n    pub fn call_with_state(\n        &self,\n        state: &dyn DatabaseRef,\n        request: WithOtherFields<TransactionRequest>,\n        fee_details: FeeDetails,\n        block_env: BlockEnv,\n    ) -> Result<(InstructionResult, Option<Output>, u128, State), BlockchainError> {\n        let mut inspector = self.build_inspector();\n\n        let env = self.build_call_env(request, fee_details, block_env);\n        let mut evm = self.new_eth_evm_with_inspector_ref(state, &env, &mut inspector);\n        let ResultAndState { result, state } = evm.transact(env.tx)?;\n        let (exit_reason, gas_used, out) = match result {\n            ExecutionResult::Success { reason, gas_used, output, .. } => {\n                (reason.into(), gas_used, Some(output))\n            }\n            ExecutionResult::Revert { gas_used, output } => {\n                (InstructionResult::Revert, gas_used, Some(Output::Call(output)))\n            }\n            ExecutionResult::Halt { reason, gas_used } => {\n                (op_haltreason_to_instruction_result(reason), gas_used, None)\n            }\n        };\n        drop(evm);\n        inspector.print_logs();\n\n        if self.print_traces {\n            inspector.into_print_traces(self.call_trace_decoder.clone());\n        }\n\n        Ok((exit_reason, out, gas_used as u128, state))\n    }\n\n    pub fn build_access_list_with_state(\n        &self,\n        state: &dyn DatabaseRef,\n        request: WithOtherFields<TransactionRequest>,\n        fee_details: FeeDetails,\n        block_env: BlockEnv,\n    ) -> Result<(InstructionResult, Option<Output>, u64, AccessList), BlockchainError> {\n        let mut inspector =\n            AccessListInspector::new(request.access_list.clone().unwrap_or_default());\n\n        let env = self.build_call_env(request, fee_details, block_env);\n        let mut evm = self.new_eth_evm_with_inspector_ref(state, &env, &mut inspector);\n        let ResultAndState { result, state: _ } = evm.transact(env.tx)?;\n        let (exit_reason, gas_used, out) = match result {\n            ExecutionResult::Success { reason, gas_used, output, .. } => {\n                (reason.into(), gas_used, Some(output))\n            }\n            ExecutionResult::Revert { gas_used, output } => {\n                (InstructionResult::Revert, gas_used, Some(Output::Call(output)))\n            }\n            ExecutionResult::Halt { reason, gas_used } => {\n                (op_haltreason_to_instruction_result(reason), gas_used, None)\n            }\n        };\n        drop(evm);\n        let access_list = inspector.access_list();\n        Ok((exit_reason, out, gas_used, access_list))\n    }\n\n    pub fn get_code_with_state(\n        &self,\n        state: &dyn DatabaseRef,\n        address: Address,\n    ) -> Result<Bytes, BlockchainError> {\n        trace!(target: \"backend\", \"get code for {:?}\", address);\n        let account = state.basic_ref(address)?.unwrap_or_default();\n        if account.code_hash == KECCAK_EMPTY {\n            // if the code hash is `KECCAK_EMPTY`, we check no further\n            return Ok(Default::default());\n        }\n        let code = if let Some(code) = account.code {\n            code\n        } else {\n            state.code_by_hash_ref(account.code_hash)?\n        };\n        Ok(code.bytes()[..code.len()].to_vec().into())\n    }\n\n    pub fn get_balance_with_state<D>(\n        &self,\n        state: D,\n        address: Address,\n    ) -> Result<U256, BlockchainError>\n    where\n        D: DatabaseRef,\n    {\n        trace!(target: \"backend\", \"get balance for {:?}\", address);\n        Ok(state.basic_ref(address)?.unwrap_or_default().balance)\n    }\n\n    pub async fn transaction_by_block_number_and_index(\n        &self,\n        number: BlockNumber,\n        index: Index,\n    ) -> Result<Option<AnyRpcTransaction>, BlockchainError> {\n        if let Some(block) = self.mined_block_by_number(number) {\n            return Ok(self.mined_transaction_by_block_hash_and_index(block.header.hash, index));\n        }\n\n        if let Some(fork) = self.get_fork() {\n            let number = self.convert_block_number(Some(number));\n            if fork.predates_fork(number) {\n                return Ok(fork\n                    .transaction_by_block_number_and_index(number, index.into())\n                    .await?);\n            }\n        }\n\n        Ok(None)\n    }\n\n    pub async fn transaction_by_block_hash_and_index(\n        &self,\n        hash: B256,\n        index: Index,\n    ) -> Result<Option<AnyRpcTransaction>, BlockchainError> {\n        if let tx @ Some(_) = self.mined_transaction_by_block_hash_and_index(hash, index) {\n            return Ok(tx);\n        }\n\n        if let Some(fork) = self.get_fork() {\n            return Ok(fork.transaction_by_block_hash_and_index(hash, index.into()).await?);\n        }\n\n        Ok(None)\n    }\n\n    pub fn mined_transaction_by_block_hash_and_index(\n        &self,\n        block_hash: B256,\n        index: Index,\n    ) -> Option<AnyRpcTransaction> {\n        let (info, block, tx) = {\n            let storage = self.blockchain.storage.read();\n            let block = storage.blocks.get(&block_hash).cloned()?;\n            let index: usize = index.into();\n            let tx = block.body.transactions.get(index)?.clone();\n            let info = storage.transactions.get(&tx.hash())?.info.clone();\n            (info, block, tx)\n        };\n\n        Some(transaction_build(\n            Some(info.transaction_hash),\n            tx,\n            Some(&block),\n            Some(info),\n            block.header.base_fee_per_gas(),\n        ))\n    }\n\n    pub async fn transaction_by_hash(\n        &self,\n        hash: B256,\n    ) -> Result<Option<AnyRpcTransaction>, BlockchainError> {\n        trace!(target: \"backend\", \"transaction_by_hash={:?}\", hash);\n        if let tx @ Some(_) = self.mined_transaction_by_hash(hash) {\n            return Ok(tx);\n        }\n\n        if let Some(fork) = self.get_fork() {\n            return fork\n                .transaction_by_hash(hash)\n                .await\n                .map_err(BlockchainError::AlloyForkProvider);\n        }\n\n        Ok(None)\n    }\n\n    pub fn mined_transaction_by_hash(&self, hash: B256) -> Option<AnyRpcTransaction> {\n        let (info, block) = {\n            let storage = self.blockchain.storage.read();\n            let MinedTransaction { info, block_hash, .. } =\n                storage.transactions.get(&hash)?.clone();\n            let block = storage.blocks.get(&block_hash).cloned()?;\n            (info, block)\n        };\n        let tx = block.body.transactions.get(info.transaction_index as usize)?.clone();\n\n        Some(transaction_build(\n            Some(info.transaction_hash),\n            tx,\n            Some(&block),\n            Some(info),\n            block.header.base_fee_per_gas(),\n        ))\n    }\n\n    /// Returns the traces for the given transaction\n    pub async fn trace_transaction(\n        &self,\n        hash: B256,\n    ) -> Result<Vec<LocalizedTransactionTrace>, BlockchainError> {\n        if let Some(traces) = self.mined_parity_trace_transaction(hash) {\n            return Ok(traces);\n        }\n\n        if let Some(fork) = self.get_fork() {\n            return Ok(fork.trace_transaction(hash).await?);\n        }\n\n        Ok(vec![])\n    }\n\n    /// Returns the traces for the given block\n    pub async fn trace_block(\n        &self,\n        block: BlockNumber,\n    ) -> Result<Vec<LocalizedTransactionTrace>, BlockchainError> {\n        let number = self.convert_block_number(Some(block));\n        if let Some(traces) = self.mined_parity_trace_block(number) {\n            return Ok(traces);\n        }\n\n        if let Some(fork) = self.get_fork()\n            && fork.predates_fork(number)\n        {\n            return Ok(fork.trace_block(number).await?);\n        }\n\n        Ok(vec![])\n    }\n\n    /// Replays all transactions in a block and returns the requested traces for each transaction\n    pub async fn trace_replay_block_transactions(\n        &self,\n        block: BlockNumber,\n        trace_types: HashSet<TraceType>,\n    ) -> Result<Vec<TraceResultsWithTransactionHash>, BlockchainError> {\n        let block_number = self.convert_block_number(Some(block));\n\n        // Try mined blocks first\n        if let Some(results) =\n            self.mined_parity_trace_replay_block_transactions(block_number, &trace_types)\n        {\n            return Ok(results);\n        }\n\n        // Fallback to fork if block predates fork\n        if let Some(fork) = self.get_fork()\n            && fork.predates_fork(block_number)\n        {\n            return Ok(fork.trace_replay_block_transactions(block_number, trace_types).await?);\n        }\n\n        Ok(vec![])\n    }\n\n    /// Returns the trace results for all transactions in a mined block by replaying them\n    fn mined_parity_trace_replay_block_transactions(\n        &self,\n        block_number: u64,\n        trace_types: &HashSet<TraceType>,\n    ) -> Option<Vec<TraceResultsWithTransactionHash>> {\n        let block = self.get_block(block_number)?;\n\n        // Execute this in the context of the parent state\n        let parent_hash = block.header.parent_hash;\n        let trace_config = TracingInspectorConfig::from_parity_config(trace_types);\n\n        let read_guard = self.states.upgradable_read();\n        if let Some(state) = read_guard.get_state(&parent_hash) {\n            self.replay_block_transactions_with_inspector(&block, state, trace_config, trace_types)\n        } else {\n            let mut write_guard = RwLockUpgradableReadGuard::upgrade(read_guard);\n            let state = write_guard.get_on_disk_state(&parent_hash)?;\n            self.replay_block_transactions_with_inspector(&block, state, trace_config, trace_types)\n        }\n    }\n\n    /// Replays all transactions in a block with the tracing inspector to generate TraceResults\n    fn replay_block_transactions_with_inspector(\n        &self,\n        block: &Block,\n        parent_state: &StateDb,\n        trace_config: TracingInspectorConfig,\n        trace_types: &HashSet<TraceType>,\n    ) -> Option<Vec<TraceResultsWithTransactionHash>> {\n        let mut cache_db = CacheDB::new(Box::new(parent_state));\n        let mut results = Vec::new();\n\n        // Configure the block environment\n        let mut env = self.env.read().clone();\n        env.evm_env.block_env = block_env_from_header(&block.header);\n\n        // Execute each transaction in the block with tracing\n        for tx_envelope in &block.body.transactions {\n            let tx_hash = tx_envelope.hash();\n\n            // Create a fresh inspector for this transaction\n            let mut inspector = TracingInspector::new(trace_config);\n\n            // Prepare transaction environment\n            let pending_tx =\n                PendingTransaction::from_maybe_impersonated(tx_envelope.clone()).ok()?;\n            let mut tx_env: OpTransaction<TxEnv> = FromRecoveredTx::from_recovered_tx(\n                pending_tx.transaction.as_ref(),\n                *pending_tx.sender(),\n            );\n            if env.networks.is_optimism() {\n                tx_env.enveloped_tx = Some(pending_tx.transaction.encoded_2718().into());\n            }\n\n            // Execute the transaction with the inspector\n            let mut evm = self.new_eth_evm_with_inspector_ref(&cache_db, &env, &mut inspector);\n            let result = evm.transact(tx_env.clone()).ok()?;\n\n            // Build TraceResults from the inspector and execution result\n            let full_trace = inspector\n                .into_parity_builder()\n                .into_trace_results_with_state(&result, trace_types, &cache_db)\n                .ok()?;\n\n            results.push(TraceResultsWithTransactionHash { transaction_hash: tx_hash, full_trace });\n\n            // Commit the state changes for the next transaction\n            cache_db.commit(result.state);\n        }\n\n        Some(results)\n    }\n\n    // Returns the traces matching a given filter\n    pub async fn trace_filter(\n        &self,\n        filter: TraceFilter,\n    ) -> Result<Vec<LocalizedTransactionTrace>, BlockchainError> {\n        let matcher = filter.matcher();\n        let start = filter.from_block.unwrap_or(0);\n        let end = filter.to_block.unwrap_or_else(|| self.best_number());\n\n        if start > end {\n            return Err(BlockchainError::RpcError(RpcError::invalid_params(\n                \"invalid block range, ensure that to block is greater than from block\".to_string(),\n            )));\n        }\n\n        let dist = end - start;\n        if dist > 300 {\n            return Err(BlockchainError::RpcError(RpcError::invalid_params(\n                \"block range too large, currently limited to 300\".to_string(),\n            )));\n        }\n\n        // Accumulate tasks for block range\n        let mut trace_tasks = vec![];\n        for num in start..=end {\n            trace_tasks.push(self.trace_block(num.into()));\n        }\n\n        // Execute tasks and filter traces\n        let traces = futures::future::try_join_all(trace_tasks).await?;\n        let filtered_traces =\n            traces.into_iter().flatten().filter(|trace| matcher.matches(&trace.trace));\n\n        // Apply after and count\n        let filtered_traces: Vec<_> = if let Some(after) = filter.after {\n            filtered_traces.skip(after as usize).collect()\n        } else {\n            filtered_traces.collect()\n        };\n\n        let filtered_traces: Vec<_> = if let Some(count) = filter.count {\n            filtered_traces.into_iter().take(count as usize).collect()\n        } else {\n            filtered_traces\n        };\n\n        Ok(filtered_traces)\n    }\n\n    pub fn get_blobs_by_block_id(\n        &self,\n        id: impl Into<BlockId>,\n        versioned_hashes: Vec<B256>,\n    ) -> Result<Option<Vec<alloy_consensus::Blob>>> {\n        Ok(self.get_block(id).map(|block| {\n            block\n                .body\n                .transactions\n                .iter()\n                .filter_map(|tx| tx.as_ref().sidecar())\n                .flat_map(|sidecar| {\n                    sidecar.sidecar.blobs().iter().zip(sidecar.sidecar.commitments().iter())\n                })\n                .filter(|(_, commitment)| {\n                    // Filter blobs by versioned_hashes if provided\n                    versioned_hashes.is_empty()\n                        || versioned_hashes.contains(&kzg_to_versioned_hash(commitment.as_slice()))\n                })\n                .map(|(blob, _)| *blob)\n                .collect()\n        }))\n    }\n\n    pub fn get_blob_by_versioned_hash(&self, hash: B256) -> Result<Option<Blob>> {\n        let storage = self.blockchain.storage.read();\n        for block in storage.blocks.values() {\n            for tx in &block.body.transactions {\n                let typed_tx = tx.as_ref();\n                if let Some(sidecar) = typed_tx.sidecar() {\n                    for versioned_hash in sidecar.sidecar.versioned_hashes() {\n                        if versioned_hash == hash\n                            && let Some(index) =\n                                sidecar.sidecar.commitments().iter().position(|commitment| {\n                                    kzg_to_versioned_hash(commitment.as_slice()) == *hash\n                                })\n                            && let Some(blob) = sidecar.sidecar.blobs().get(index)\n                        {\n                            return Ok(Some(*blob));\n                        }\n                    }\n                }\n            }\n        }\n        Ok(None)\n    }\n\n    /// Initialises the balance of the given accounts\n    #[expect(clippy::too_many_arguments)]\n    pub async fn with_genesis(\n        db: Arc<AsyncRwLock<Box<dyn Db>>>,\n        env: Arc<RwLock<Env>>,\n        genesis: GenesisConfig,\n        fees: FeeManager,\n        fork: Arc<RwLock<Option<ClientFork>>>,\n        enable_steps_tracing: bool,\n        print_logs: bool,\n        print_traces: bool,\n        call_trace_decoder: Arc<CallTraceDecoder>,\n        prune_state_history_config: PruneStateHistoryConfig,\n        max_persisted_states: Option<usize>,\n        transaction_block_keeper: Option<usize>,\n        automine_block_time: Option<Duration>,\n        cache_path: Option<PathBuf>,\n        node_config: Arc<AsyncRwLock<NodeConfig>>,\n    ) -> Result<Self> {\n        // if this is a fork then adjust the blockchain storage\n        let blockchain = if let Some(fork) = fork.read().as_ref() {\n            trace!(target: \"backend\", \"using forked blockchain at {}\", fork.block_number());\n            Blockchain::forked(fork.block_number(), fork.block_hash(), fork.total_difficulty())\n        } else {\n            let env = env.read();\n            Blockchain::new(\n                &env,\n                env.evm_env.cfg_env.spec,\n                fees.is_eip1559().then(|| fees.base_fee()),\n                genesis.timestamp,\n                genesis.number,\n            )\n        };\n\n        // Sync EVM block.number with genesis for non-fork mode.\n        // Fork mode syncs in setup_fork_db_config() instead.\n        if fork.read().is_none() {\n            let mut write_env = env.write();\n            write_env.evm_env.block_env.number = U256::from(genesis.number);\n        }\n\n        let start_timestamp = if let Some(fork) = fork.read().as_ref() {\n            fork.timestamp()\n        } else {\n            genesis.timestamp\n        };\n\n        let mut states = if prune_state_history_config.is_config_enabled() {\n            // if prune state history is enabled, configure the state cache only for memory\n            prune_state_history_config\n                .max_memory_history\n                .map(|limit| InMemoryBlockStates::new(limit, 0))\n                .unwrap_or_default()\n                .memory_only()\n        } else if max_persisted_states.is_some() {\n            max_persisted_states\n                .map(|limit| InMemoryBlockStates::new(DEFAULT_HISTORY_LIMIT, limit))\n                .unwrap_or_default()\n        } else {\n            Default::default()\n        };\n\n        if let Some(cache_path) = cache_path {\n            states = states.disk_path(cache_path);\n        }\n\n        let (slots_in_an_epoch, precompile_factory, disable_pool_balance_checks) = {\n            let cfg = node_config.read().await;\n            (cfg.slots_in_an_epoch, cfg.precompile_factory.clone(), cfg.disable_pool_balance_checks)\n        };\n\n        let backend = Self {\n            db,\n            blockchain,\n            states: Arc::new(RwLock::new(states)),\n            env,\n            fork,\n            time: TimeManager::new(start_timestamp),\n            cheats: Default::default(),\n            new_block_listeners: Default::default(),\n            fees,\n            genesis,\n            active_state_snapshots: Arc::new(Mutex::new(Default::default())),\n            enable_steps_tracing,\n            print_logs,\n            print_traces,\n            call_trace_decoder,\n            prune_state_history_config,\n            transaction_block_keeper,\n            node_config,\n            slots_in_an_epoch,\n            precompile_factory,\n            mining: Arc::new(tokio::sync::Mutex::new(())),\n            disable_pool_balance_checks,\n        };\n\n        if let Some(interval_block_time) = automine_block_time {\n            backend.update_interval_mine_block_time(interval_block_time);\n        }\n\n        // Note: this can only fail in forking mode, in which case we can't recover\n        backend.apply_genesis().await.wrap_err(\"failed to create genesis\")?;\n        Ok(backend)\n    }\n\n    /// Applies the configured genesis settings\n    ///\n    /// This will fund, create the genesis accounts\n    async fn apply_genesis(&self) -> Result<(), DatabaseError> {\n        trace!(target: \"backend\", \"setting genesis balances\");\n\n        if self.fork.read().is_some() {\n            // fetch all account first\n            let mut genesis_accounts_futures = Vec::with_capacity(self.genesis.accounts.len());\n            for address in self.genesis.accounts.iter().copied() {\n                let db = Arc::clone(&self.db);\n\n                // The forking Database backend can handle concurrent requests, we can fetch all dev\n                // accounts concurrently by spawning the job to a new task\n                genesis_accounts_futures.push(tokio::task::spawn(async move {\n                    let db = db.read().await;\n                    let info = db.basic_ref(address)?.unwrap_or_default();\n                    Ok::<_, DatabaseError>((address, info))\n                }));\n            }\n\n            let genesis_accounts = futures::future::join_all(genesis_accounts_futures).await;\n\n            let mut db = self.db.write().await;\n\n            for res in genesis_accounts {\n                let (address, mut info) = res.unwrap()?;\n                info.balance = self.genesis.balance;\n                db.insert_account(address, info.clone());\n            }\n        } else {\n            let mut db = self.db.write().await;\n            for (account, info) in self.genesis.account_infos() {\n                db.insert_account(account, info);\n            }\n\n            // insert the new genesis hash to the database so it's available for the next block in\n            // the evm\n            db.insert_block_hash(U256::from(self.best_number()), self.best_hash());\n\n            // Deploy EIP-2935 blockhash history storage contract if Prague is active.\n            if self.spec_id() >= SpecId::PRAGUE {\n                db.set_code(\n                    eip2935::HISTORY_STORAGE_ADDRESS,\n                    eip2935::HISTORY_STORAGE_CODE.clone(),\n                )?;\n            }\n        }\n\n        let db = self.db.write().await;\n        // apply the genesis.json alloc\n        self.genesis.apply_genesis_json_alloc(db)?;\n\n        trace!(target: \"backend\", \"set genesis balances\");\n\n        Ok(())\n    }\n\n    /// Resets the fork to a fresh state\n    pub async fn reset_fork(&self, forking: Forking) -> Result<(), BlockchainError> {\n        if !self.is_fork() {\n            if let Some(eth_rpc_url) = forking.json_rpc_url.clone() {\n                let mut env = self.env.read().clone();\n\n                let (db, config) = {\n                    let mut node_config = self.node_config.write().await;\n\n                    // we want to force the correct base fee for the next block during\n                    // `setup_fork_db_config`\n                    node_config.base_fee.take();\n\n                    node_config.setup_fork_db_config(eth_rpc_url, &mut env, &self.fees).await?\n                };\n\n                *self.db.write().await = Box::new(db);\n\n                let fork = ClientFork::new(config, Arc::clone(&self.db));\n\n                *self.env.write() = env;\n                *self.fork.write() = Some(fork);\n            } else {\n                return Err(RpcError::invalid_params(\n                    \"Forking not enabled and RPC URL not provided to start forking\",\n                )\n                .into());\n            }\n        }\n\n        if let Some(fork) = self.get_fork() {\n            let block_number =\n                forking.block_number.map(BlockNumber::from).unwrap_or(BlockNumber::Latest);\n            // reset the fork entirely and reapply the genesis config\n            fork.reset(forking.json_rpc_url.clone(), block_number).await?;\n            let fork_block_number = fork.block_number();\n            let fork_block = fork\n                .block_by_number(fork_block_number)\n                .await?\n                .ok_or(BlockchainError::BlockNotFound)?;\n            // update all settings related to the forked block\n            {\n                if let Some(fork_url) = forking.json_rpc_url {\n                    self.reset_block_number(fork_url, fork_block_number).await?;\n                } else {\n                    // If rpc url is unspecified, then update the fork with the new block number and\n                    // existing rpc url, this updates the cache path\n                    {\n                        let maybe_fork_url = { self.node_config.read().await.eth_rpc_url.clone() };\n                        if let Some(fork_url) = maybe_fork_url {\n                            self.reset_block_number(fork_url, fork_block_number).await?;\n                        }\n                    }\n\n                    let gas_limit = self.node_config.read().await.fork_gas_limit(&fork_block);\n                    let mut env = self.env.write();\n\n                    env.evm_env.cfg_env.chain_id = fork.chain_id();\n                    env.evm_env.block_env = BlockEnv {\n                        number: U256::from(fork_block_number),\n                        timestamp: U256::from(fork_block.header.timestamp()),\n                        gas_limit,\n                        difficulty: fork_block.header.difficulty(),\n                        prevrandao: Some(fork_block.header.mix_hash().unwrap_or_default()),\n                        // Keep previous `beneficiary` and `basefee` value\n                        beneficiary: env.evm_env.block_env.beneficiary,\n                        basefee: env.evm_env.block_env.basefee,\n                        ..env.evm_env.block_env.clone()\n                    };\n\n                    // this is the base fee of the current block, but we need the base fee of\n                    // the next block\n                    let next_block_base_fee = self.fees.get_next_block_base_fee_per_gas(\n                        fork_block.header.gas_used(),\n                        gas_limit,\n                        fork_block.header.base_fee_per_gas().unwrap_or_default(),\n                    );\n\n                    self.fees.set_base_fee(next_block_base_fee);\n                }\n\n                // reset the time to the timestamp of the forked block\n                self.time.reset(fork_block.header.timestamp());\n\n                // also reset the total difficulty\n                self.blockchain.storage.write().total_difficulty = fork.total_difficulty();\n            }\n            // reset storage\n            *self.blockchain.storage.write() = BlockchainStorage::forked(\n                fork.block_number(),\n                fork.block_hash(),\n                fork.total_difficulty(),\n            );\n            self.states.write().clear();\n            self.db.write().await.clear();\n\n            self.apply_genesis().await?;\n\n            trace!(target: \"backend\", \"reset fork\");\n\n            Ok(())\n        } else {\n            Err(RpcError::invalid_params(\"Forking not enabled\").into())\n        }\n    }\n\n    /// Resets the backend to a fresh in-memory state, clearing all existing data\n    pub async fn reset_to_in_mem(&self) -> Result<(), BlockchainError> {\n        // Clear the fork if any exists\n        *self.fork.write() = None;\n\n        // Get environment and genesis config\n        let env = self.env.read().clone();\n        let genesis_timestamp = self.genesis.timestamp;\n        let genesis_number = self.genesis.number;\n        let spec_id = self.spec_id();\n\n        // Reset environment to genesis state\n        {\n            let mut env = self.env.write();\n            env.evm_env.block_env.number = U256::from(genesis_number);\n            env.evm_env.block_env.timestamp = U256::from(genesis_timestamp);\n            // Reset other block env fields to their defaults\n            env.evm_env.block_env.basefee = self.fees.base_fee();\n            env.evm_env.block_env.prevrandao = Some(B256::ZERO);\n        }\n\n        // Clear all storage and reinitialize with genesis\n        let base_fee = if self.fees.is_eip1559() { Some(self.fees.base_fee()) } else { None };\n        *self.blockchain.storage.write() =\n            BlockchainStorage::new(&env, spec_id, base_fee, genesis_timestamp, genesis_number);\n        self.states.write().clear();\n\n        // Clear the database\n        self.db.write().await.clear();\n\n        // Reset time manager\n        self.time.reset(genesis_timestamp);\n\n        // Reset fees to initial state\n        if self.fees.is_eip1559() {\n            self.fees.set_base_fee(crate::eth::fees::INITIAL_BASE_FEE);\n        }\n\n        self.fees.set_gas_price(crate::eth::fees::INITIAL_GAS_PRICE);\n\n        // Reapply genesis configuration\n        self.apply_genesis().await?;\n\n        trace!(target: \"backend\", \"reset to fresh in-memory state\");\n\n        Ok(())\n    }\n\n    async fn reset_block_number(\n        &self,\n        fork_url: String,\n        fork_block_number: u64,\n    ) -> Result<(), BlockchainError> {\n        let mut node_config = self.node_config.write().await;\n        node_config.fork_choice = Some(ForkChoice::Block(fork_block_number as i128));\n\n        let mut env = self.env.read().clone();\n        let (forked_db, client_fork_config) =\n            node_config.setup_fork_db_config(fork_url, &mut env, &self.fees).await?;\n\n        *self.db.write().await = Box::new(forked_db);\n        let fork = ClientFork::new(client_fork_config, Arc::clone(&self.db));\n        *self.fork.write() = Some(fork);\n        *self.env.write() = env;\n\n        Ok(())\n    }\n\n    /// Reverts the state to the state snapshot identified by the given `id`.\n    pub async fn revert_state_snapshot(&self, id: U256) -> Result<bool, BlockchainError> {\n        let block = { self.active_state_snapshots.lock().remove(&id) };\n        if let Some((num, hash)) = block {\n            let best_block_hash = {\n                // revert the storage that's newer than the snapshot\n                let current_height = self.best_number();\n                let mut storage = self.blockchain.storage.write();\n\n                for n in ((num + 1)..=current_height).rev() {\n                    trace!(target: \"backend\", \"reverting block {}\", n);\n                    if let Some(hash) = storage.hashes.remove(&n)\n                        && let Some(block) = storage.blocks.remove(&hash)\n                    {\n                        for tx in block.body.transactions {\n                            let _ = storage.transactions.remove(&tx.hash());\n                        }\n                    }\n                }\n\n                storage.best_number = num;\n                storage.best_hash = hash;\n                hash\n            };\n            let block =\n                self.block_by_hash(best_block_hash).await?.ok_or(BlockchainError::BlockNotFound)?;\n\n            let reset_time = block.header.timestamp();\n            self.time.reset(reset_time);\n\n            let mut env = self.env.write();\n            env.evm_env.block_env = BlockEnv {\n                number: U256::from(num),\n                timestamp: U256::from(block.header.timestamp()),\n                difficulty: block.header.difficulty(),\n                // ensures prevrandao is set\n                prevrandao: Some(block.header.mix_hash().unwrap_or_default()),\n                gas_limit: block.header.gas_limit(),\n                // Keep previous `beneficiary` and `basefee` value\n                beneficiary: env.evm_env.block_env.beneficiary,\n                basefee: env.evm_env.block_env.basefee,\n                ..Default::default()\n            }\n        }\n        Ok(self.db.write().await.revert_state(id, RevertStateSnapshotAction::RevertRemove))\n    }\n\n    /// executes the transactions without writing to the underlying database\n    pub async fn inspect_tx(\n        &self,\n        tx: Arc<PoolTransaction<FoundryTxEnvelope>>,\n    ) -> Result<\n        (InstructionResult, Option<Output>, u64, State, Vec<revm::primitives::Log>),\n        BlockchainError,\n    > {\n        let mut env = self.next_env();\n        env.tx = FromRecoveredTx::from_recovered_tx(\n            tx.pending_transaction.transaction.as_ref(),\n            *tx.pending_transaction.sender(),\n        );\n\n        if env.networks.is_optimism() {\n            env.tx.enveloped_tx = Some(tx.pending_transaction.transaction.encoded_2718().into());\n        }\n\n        let db = self.db.read().await;\n        let mut inspector = self.build_inspector();\n        let mut evm = self.new_eth_evm_with_inspector_ref(&**db, &env, &mut inspector);\n        let ResultAndState { result, state } = evm.transact(env.tx)?;\n        let (exit_reason, gas_used, out, logs) = match result {\n            ExecutionResult::Success { reason, gas_used, logs, output, .. } => {\n                (reason.into(), gas_used, Some(output), Some(logs))\n            }\n            ExecutionResult::Revert { gas_used, output } => {\n                (InstructionResult::Revert, gas_used, Some(Output::Call(output)), None)\n            }\n            ExecutionResult::Halt { reason, gas_used } => {\n                let eth_reason = op_haltreason_to_instruction_result(reason);\n                (eth_reason, gas_used, None, None)\n            }\n        };\n\n        drop(evm);\n        inspector.print_logs();\n\n        if self.print_traces {\n            inspector.print_traces(self.call_trace_decoder.clone());\n        }\n\n        Ok((exit_reason, out, gas_used, state, logs.unwrap_or_default()))\n    }\n}\n\nimpl<N: Network> Backend<N>\nwhere\n    N::ReceiptEnvelope: alloy_consensus::TxReceipt<Log = alloy_primitives::Log> + Clone,\n{\n    /// Returns all `Log`s mined by the node that were emitted in the `block` and match the `Filter`\n    fn mined_logs_for_block(&self, filter: Filter, block: Block, block_hash: B256) -> Vec<Log> {\n        let mut all_logs = Vec::new();\n        let mut block_log_index = 0u32;\n\n        let storage = self.blockchain.storage.read();\n\n        for tx in block.body.transactions {\n            let Some(tx) = storage.transactions.get(&tx.hash()) else {\n                continue;\n            };\n\n            let logs = tx.receipt.logs();\n            let transaction_hash = tx.info.transaction_hash;\n\n            for log in logs {\n                if filter.matches(log) {\n                    all_logs.push(Log {\n                        inner: log.clone(),\n                        block_hash: Some(block_hash),\n                        block_number: Some(block.header.number()),\n                        block_timestamp: Some(block.header.timestamp()),\n                        transaction_hash: Some(transaction_hash),\n                        transaction_index: Some(tx.info.transaction_index),\n                        log_index: Some(block_log_index as u64),\n                        removed: false,\n                    });\n                }\n                block_log_index += 1;\n            }\n        }\n        all_logs\n    }\n\n    /// Returns the logs of the block that match the filter\n    async fn logs_for_block(\n        &self,\n        filter: Filter,\n        hash: B256,\n    ) -> Result<Vec<Log>, BlockchainError> {\n        if let Some(block) = self.blockchain.get_block_by_hash(&hash) {\n            return Ok(self.mined_logs_for_block(filter, block, hash));\n        }\n\n        if let Some(fork) = self.get_fork() {\n            return Ok(fork.logs(&filter).await?);\n        }\n\n        Ok(Vec::new())\n    }\n\n    /// Returns the logs that match the filter in the given range of blocks\n    async fn logs_for_range(\n        &self,\n        filter: &Filter,\n        mut from: u64,\n        to: u64,\n    ) -> Result<Vec<Log>, BlockchainError> {\n        let mut all_logs = Vec::new();\n\n        // get the range that predates the fork if any\n        if let Some(fork) = self.get_fork() {\n            let mut to_on_fork = to;\n\n            if !fork.predates_fork(to) {\n                // adjust the ranges\n                to_on_fork = fork.block_number();\n            }\n\n            if fork.predates_fork_inclusive(from) {\n                // this data is only available on the forked client\n                let filter = filter.clone().from_block(from).to_block(to_on_fork);\n                all_logs = fork.logs(&filter).await?;\n\n                // update the range\n                from = fork.block_number() + 1;\n            }\n        }\n\n        for number in from..=to {\n            if let Some((block, hash)) = self.get_block_with_hash(number) {\n                all_logs.extend(self.mined_logs_for_block(filter.clone(), block, hash));\n            }\n        }\n\n        Ok(all_logs)\n    }\n\n    /// Returns the logs according to the filter\n    pub async fn logs(&self, filter: Filter) -> Result<Vec<Log>, BlockchainError> {\n        trace!(target: \"backend\", \"get logs [{:?}]\", filter);\n        if let Some(hash) = filter.get_block_hash() {\n            self.logs_for_block(filter, hash).await\n        } else {\n            let best = self.best_number();\n            let to_block =\n                self.convert_block_number(filter.block_option.get_to_block().copied()).min(best);\n            let from_block =\n                self.convert_block_number(filter.block_option.get_from_block().copied());\n            if from_block > best {\n                return Err(BlockchainError::BlockOutOfRange(best, from_block));\n            }\n\n            self.logs_for_range(&filter, from_block, to_block).await\n        }\n    }\n\n    /// Returns all receipts of the block\n    pub fn mined_receipts(&self, hash: B256) -> Option<Vec<N::ReceiptEnvelope>> {\n        let block = self.mined_block_by_hash(hash)?;\n        let mut receipts = Vec::new();\n        let storage = self.blockchain.storage.read();\n        for tx in block.transactions.hashes() {\n            let receipt = storage.transactions.get(&tx)?.receipt.clone();\n            receipts.push(receipt);\n        }\n        Some(receipts)\n    }\n}\n\n// Mining methods — generic over N: Network, with Foundry-associated-type bounds for now.\nimpl<N: Network> Backend<N>\nwhere\n    Self: TransactionValidator<FoundryTxEnvelope>,\n    N: Network<TxEnvelope = FoundryTxEnvelope, ReceiptEnvelope = FoundryReceiptEnvelope>,\n{\n    /// Mines a new block and stores it.\n    ///\n    /// this will execute all transaction in the order they come in and return all the markers they\n    /// provide.\n    pub async fn mine_block(\n        &self,\n        pool_transactions: Vec<Arc<PoolTransaction<FoundryTxEnvelope>>>,\n    ) -> MinedBlockOutcome<FoundryTxEnvelope> {\n        self.do_mine_block(pool_transactions).await\n    }\n\n    async fn do_mine_block(\n        &self,\n        pool_transactions: Vec<Arc<PoolTransaction<FoundryTxEnvelope>>>,\n    ) -> MinedBlockOutcome<FoundryTxEnvelope> {\n        let _mining_guard = self.mining.lock().await;\n        trace!(target: \"backend\", \"creating new block with {} transactions\", pool_transactions.len());\n\n        let (outcome, header, block_hash) = {\n            let current_base_fee = self.base_fee();\n            let current_excess_blob_gas_and_price = self.excess_blob_gas_and_price();\n\n            let mut env = self.env.read().clone();\n\n            if env.evm_env.block_env.basefee == 0 {\n                // this is an edge case because the evm fails if `tx.effective_gas_price < base_fee`\n                // 0 is only possible if it's manually set\n                env.evm_env.cfg_env.disable_base_fee = true;\n            }\n\n            let block_number = self.blockchain.storage.read().best_number.saturating_add(1);\n\n            // increase block number for this block\n            if is_arbitrum(env.evm_env.cfg_env.chain_id) {\n                // Temporary set `env.block.number` to `block_number` for Arbitrum chains.\n                env.evm_env.block_env.number = U256::from(block_number);\n            } else {\n                env.evm_env.block_env.number =\n                    env.evm_env.block_env.number.saturating_add(U256::from(1));\n            }\n\n            env.evm_env.block_env.basefee = current_base_fee;\n            env.evm_env.block_env.blob_excess_gas_and_price = current_excess_blob_gas_and_price;\n\n            let best_hash = self.blockchain.storage.read().best_hash;\n\n            let mut input = Vec::with_capacity(40);\n            input.extend_from_slice(best_hash.as_slice());\n            input.extend_from_slice(&block_number.to_le_bytes());\n            env.evm_env.block_env.prevrandao = Some(keccak256(&input));\n\n            if self.prune_state_history_config.is_state_history_supported() {\n                let db = self.db.read().await.current_state();\n                // store current state before executing all transactions\n                self.states.write().insert(best_hash, db);\n            }\n\n            let (block_info, included, invalid, block_hash) = {\n                let mut db = self.db.write().await;\n\n                // finally set the next block timestamp, this is done just before execution, because\n                // there can be concurrent requests that can delay acquiring the db lock and we want\n                // to ensure the timestamp is as close as possible to the actual execution.\n                env.evm_env.block_env.timestamp = U256::from(self.time.next_timestamp());\n\n                let spec_id = *env.evm_env.spec_id();\n                let is_shanghai = spec_id >= SpecId::SHANGHAI;\n                let is_cancun = spec_id >= SpecId::CANCUN;\n                let is_prague = spec_id >= SpecId::PRAGUE;\n                let gas_limit = env.evm_env.block_env.gas_limit;\n                let difficulty = env.evm_env.block_env.difficulty;\n                let mix_hash = env.evm_env.block_env.prevrandao;\n                let beneficiary = env.evm_env.block_env.beneficiary;\n                let timestamp = env.evm_env.block_env.timestamp;\n                let base_fee = if spec_id >= SpecId::LONDON {\n                    Some(env.evm_env.block_env.basefee)\n                } else {\n                    None\n                };\n                let excess_blob_gas =\n                    if is_cancun { env.evm_env.block_env.blob_excess_gas() } else { None };\n\n                // 1. Build inspector (per-block, NOT per-tx)\n                let mut inspector = AnvilInspector::default().with_tracing();\n                if self.enable_steps_tracing {\n                    inspector = inspector.with_steps_tracing();\n                }\n                if self.print_logs {\n                    inspector = inspector.with_log_collector();\n                }\n                if self.print_traces {\n                    inspector = inspector.with_trace_printer();\n                }\n\n                // 2. Create EVM\n                let env_struct = Env::new(env.evm_env.clone(), Default::default(), env.networks);\n                let mut evm = new_eth_evm_with_inspector(&mut **db, &env_struct, inspector);\n\n                // 3. Inject precompiles (once, before the tx loop)\n                env.networks.inject_precompiles(evm.precompiles_mut());\n                if let Some(factory) = &self.precompile_factory {\n                    evm.precompiles_mut().extend_precompiles(factory.precompiles());\n                }\n                let cheats = self.cheats().clone();\n                if cheats.has_recover_overrides() {\n                    let cheats_arc = Arc::new(cheats.clone());\n                    let cheat_ecrecover = CheatEcrecover::new(Arc::clone(&cheats_arc));\n                    evm.precompiles_mut().apply_precompile(&EC_RECOVER, move |_| {\n                        Some(DynPrecompile::new_stateful(\n                            cheat_ecrecover.precompile_id().clone(),\n                            move |input| cheat_ecrecover.call(input),\n                        ))\n                    });\n                }\n\n                // 4. Create executor via AnvilBlockExecutorFactory\n                let exec_ctx = AnvilExecutionCtx { parent_hash: best_hash, is_prague, is_cancun };\n                let mut executor = AnvilBlockExecutorFactory::create_executor(evm, exec_ctx);\n                executor.apply_pre_execution_changes().expect(\"pre-execution changes failed\");\n\n                // 5. Per-tx loop\n                let mut included: Vec<Arc<PoolTransaction<FoundryTxEnvelope>>> = Vec::new();\n                let mut invalid: Vec<Arc<PoolTransaction<FoundryTxEnvelope>>> = Vec::new();\n                let mut transaction_infos: Vec<TransactionInfo> = Vec::new();\n                let mut transactions = Vec::new();\n                let mut bloom = Bloom::default();\n\n                let blob_params = self.blob_params();\n                let networks = env.networks;\n                let mut cumulative_blob_gas_used = if is_cancun { Some(0u64) } else { None };\n\n                for pool_tx in pool_transactions {\n                    let pending = &pool_tx.pending_transaction;\n                    let sender = *pending.sender();\n\n                    let account = match executor\n                        .evm_mut()\n                        .db_mut()\n                        .basic(sender)\n                        .map(|a| a.unwrap_or_default())\n                    {\n                        Ok(acc) => acc,\n                        Err(err) => {\n                            trace!(target: \"backend\", ?err, \"db error for tx {:?}, skipping\", pool_tx.hash());\n                            continue;\n                        }\n                    };\n\n                    // Build the per-tx env\n                    let tx_env = build_tx_env_for_pending(pending, &cheats, networks, &env.evm_env);\n                    let full_env = Env::new(env.evm_env.clone(), tx_env.clone(), networks);\n\n                    // Gas limit checks (same logic as TransactionExecutor::next)\n                    let cumulative_gas =\n                        executor.receipts().last().map(|r| r.cumulative_gas_used()).unwrap_or(0);\n                    let max_block_gas =\n                        cumulative_gas.saturating_add(pending.transaction.gas_limit());\n                    if !env.evm_env.cfg_env.disable_block_gas_limit && max_block_gas > gas_limit {\n                        trace!(target: \"backend\", tx_gas_limit = %pending.transaction.gas_limit(), ?pool_tx, \"block gas limit exhausting, skipping transaction\");\n                        continue;\n                    }\n\n                    // Osaka EIP-7825 tx gas limit cap check\n                    if env.evm_env.cfg_env.tx_gas_limit_cap.is_none()\n                        && pending.transaction.gas_limit() > env.evm_env.cfg_env.tx_gas_limit_cap()\n                    {\n                        trace!(target: \"backend\", tx_gas_limit = %pending.transaction.gas_limit(), ?pool_tx, \"transaction gas limit exhausting, skipping transaction\");\n                        continue;\n                    }\n\n                    // Blob gas check\n                    let tx_blob_gas = pending.transaction.blob_gas_used().unwrap_or(0);\n                    let current_blob_gas = cumulative_blob_gas_used.unwrap_or(0);\n                    if current_blob_gas.saturating_add(tx_blob_gas)\n                        > blob_params.max_blob_gas_per_block()\n                    {\n                        trace!(target: \"backend\", blob_gas = %tx_blob_gas, ?pool_tx, \"block blob gas limit exhausting, skipping transaction\");\n                        continue;\n                    }\n\n                    // Validate\n                    if let Err(err) =\n                        self.validate_pool_transaction_for(pending, &account, &full_env)\n                    {\n                        warn!(target: \"backend\", \"Skipping invalid tx execution [{:?}] {}\", pool_tx.hash(), err);\n                        invalid.push(pool_tx.clone());\n                        continue;\n                    }\n\n                    let nonce = account.nonce;\n\n                    // Execute via block executor\n                    let recovered =\n                        Recovered::new_unchecked(pending.transaction.as_ref().clone(), sender);\n                    trace!(target: \"backend\", \"[{:?}] executing\", pool_tx.hash());\n                    match executor.execute_transaction_without_commit((tx_env, recovered)) {\n                        Ok(result) => {\n                            let exec_result = result.inner.result.result.clone();\n                            let gas_used = result.inner.result.result.gas_used();\n\n                            executor.commit_transaction(result).expect(\"commit failed\");\n\n                            // Drain per-tx traces from inspector\n                            let insp = executor.evm_mut().inspector_mut();\n\n                            // Print before draining so the tracer is still populated.\n                            if self.print_traces {\n                                insp.print_traces(self.call_trace_decoder.clone());\n                            }\n                            insp.print_logs();\n\n                            let traces = insp\n                                .tracer\n                                .take()\n                                .map(|t| t.into_traces().into_nodes())\n                                .unwrap_or_default();\n\n                            // Reinstall tracer for next tx\n                            if self.enable_steps_tracing {\n                                insp.tracer = Some(TracingInspector::new(\n                                    TracingInspectorConfig::all().with_state_diffs(),\n                                ));\n                            } else {\n                                insp.tracer = Some(TracingInspector::new(\n                                    TracingInspectorConfig::all().set_steps(false),\n                                ));\n                            }\n                            // Reset log collector for next tx\n                            if self.print_logs {\n                                insp.log_collector =\n                                    Some(foundry_evm::inspectors::LogCollector::Capture {\n                                        logs: Vec::new(),\n                                    });\n                            }\n\n                            // Track blob gas\n                            if is_cancun {\n                                cumulative_blob_gas_used = Some(\n                                    cumulative_blob_gas_used\n                                        .unwrap_or(0)\n                                        .saturating_add(tx_blob_gas),\n                                );\n                            }\n\n                            let (exit_reason, out, logs) = match exec_result {\n                                ExecutionResult::Success {\n                                    reason,\n                                    gas_used: _,\n                                    logs,\n                                    output,\n                                    ..\n                                } => (reason.into(), Some(output), logs),\n                                ExecutionResult::Revert { gas_used: _, output } => (\n                                    InstructionResult::Revert,\n                                    Some(Output::Call(output)),\n                                    Vec::new(),\n                                ),\n                                ExecutionResult::Halt { reason, gas_used: _ } => {\n                                    (op_haltreason_to_instruction_result(reason), None, Vec::new())\n                                }\n                            };\n\n                            if exit_reason == InstructionResult::OutOfGas {\n                                warn!(target: \"backend\", \"[{:?}] executed with out of gas\", pool_tx.hash());\n                            }\n\n                            trace!(target: \"backend\", ?exit_reason, ?gas_used, \"[{:?}] executed with out={:?}\", pool_tx.hash(), out);\n                            trace!(target: \"backend::executor\", \"transacted [{:?}], result: {:?} gas {}\", pool_tx.hash(), exit_reason, gas_used);\n\n                            // Build bloom from logs\n                            for log in &logs {\n                                bloom.accrue(BloomInput::Raw(&log.address[..]));\n                                for topic in log.topics() {\n                                    bloom.accrue(BloomInput::Raw(&topic[..]));\n                                }\n                            }\n\n                            // Contract address for creation txs\n                            let contract_address = if pending.transaction.to().is_none() {\n                                let addr = sender.create(nonce);\n                                trace!(target: \"backend\", \"Contract creation tx: computed address {:?}\", addr);\n                                Some(addr)\n                            } else {\n                                None\n                            };\n\n                            let transaction_index = transaction_infos.len() as u64;\n                            let info = TransactionInfo {\n                                transaction_hash: pool_tx.hash(),\n                                transaction_index,\n                                from: sender,\n                                to: pending.transaction.to(),\n                                contract_address,\n                                traces,\n                                exit: exit_reason,\n                                out: out.map(Output::into_data),\n                                nonce,\n                                gas_used,\n                            };\n\n                            included.push(pool_tx.clone());\n                            transaction_infos.push(info);\n                            transactions.push(pending.transaction.clone());\n                        }\n                        Err(err) => {\n                            trace!(target: \"backend\", ?err, \"tx execution error, skipping {:?}\", pool_tx.hash());\n                        }\n                    }\n                }\n\n                // 6. Finish — drop EVM BEFORE accessing db again\n                let (evm, block_result) = executor.finish().expect(\"executor finish failed\");\n                drop(evm);\n\n                let state_root = db.maybe_state_root().unwrap_or_default();\n\n                // 7. Build block header\n                let receipts_root = calculate_receipt_root(&block_result.receipts);\n\n                let cumulative_gas_used = block_result.gas_used;\n\n                let header = Header {\n                    parent_hash: best_hash,\n                    ommers_hash: Default::default(),\n                    beneficiary,\n                    state_root,\n                    transactions_root: Default::default(),\n                    receipts_root,\n                    logs_bloom: bloom,\n                    difficulty,\n                    number: block_number,\n                    gas_limit,\n                    gas_used: cumulative_gas_used,\n                    timestamp: timestamp.saturating_to(),\n                    extra_data: Default::default(),\n                    mix_hash: mix_hash.unwrap_or_default(),\n                    nonce: Default::default(),\n                    base_fee_per_gas: base_fee,\n                    parent_beacon_block_root: is_cancun.then_some(Default::default()),\n                    blob_gas_used: cumulative_blob_gas_used,\n                    excess_blob_gas,\n                    withdrawals_root: is_shanghai.then_some(EMPTY_WITHDRAWALS),\n                    requests_hash: is_prague.then_some(EMPTY_REQUESTS_HASH),\n                };\n\n                let block = create_block(header, transactions);\n                let block_info = TypedBlockInfo {\n                    block,\n                    transactions: transaction_infos,\n                    receipts: block_result.receipts,\n                };\n\n                // update the new blockhash in the db itself\n                let block_hash = block_info.block.header.hash_slow();\n                db.insert_block_hash(U256::from(block_info.block.header.number()), block_hash);\n\n                (block_info, included, invalid, block_hash)\n            };\n\n            // create the new block with the current timestamp\n            let BlockInfo { block, transactions, receipts } = block_info;\n\n            let header = block.header.clone();\n\n            trace!(\n                target: \"backend\",\n                \"Mined block {} with {} tx {:?}\",\n                block_number,\n                transactions.len(),\n                transactions.iter().map(|tx| tx.transaction_hash).collect::<Vec<_>>()\n            );\n            let mut storage = self.blockchain.storage.write();\n            // update block metadata\n            storage.best_number = block_number;\n            storage.best_hash = block_hash;\n            // Difficulty is removed and not used after Paris (aka TheMerge). Value is replaced with\n            // prevrandao. https://github.com/bluealloy/revm/blob/1839b3fce8eaeebb85025576f2519b80615aca1e/crates/interpreter/src/instructions/host_env.rs#L27\n            if !self.is_eip3675() {\n                storage.total_difficulty =\n                    storage.total_difficulty.saturating_add(header.difficulty);\n            }\n\n            storage.blocks.insert(block_hash, block);\n            storage.hashes.insert(block_number, block_hash);\n\n            node_info!(\"\");\n            // insert all transactions\n            for (info, receipt) in transactions.into_iter().zip(receipts) {\n                // log some tx info\n                node_info!(\"    Transaction: {:?}\", info.transaction_hash);\n                if let Some(contract) = &info.contract_address {\n                    node_info!(\"    Contract created: {contract}\");\n                }\n                node_info!(\"    Gas used: {}\", receipt.cumulative_gas_used());\n                if !info.exit.is_ok() {\n                    let r = RevertDecoder::new().decode(\n                        info.out.as_ref().map(|b| &b[..]).unwrap_or_default(),\n                        Some(info.exit),\n                    );\n                    node_info!(\"    Error: reverted with: {r}\");\n                }\n                node_info!(\"\");\n\n                let mined_tx = MinedTransaction { info, receipt, block_hash, block_number };\n                storage.transactions.insert(mined_tx.info.transaction_hash, mined_tx);\n            }\n\n            // remove old transactions that exceed the transaction block keeper\n            if let Some(transaction_block_keeper) = self.transaction_block_keeper\n                && storage.blocks.len() > transaction_block_keeper\n            {\n                let to_clear = block_number\n                    .saturating_sub(transaction_block_keeper.try_into().unwrap_or(u64::MAX));\n                storage.remove_block_transactions_by_number(to_clear)\n            }\n\n            // we intentionally set the difficulty to `0` for newer blocks\n            env.evm_env.block_env.difficulty = U256::from(0);\n\n            // update env with new values\n            *self.env.write() = env;\n\n            let timestamp = utc_from_secs(header.timestamp);\n\n            node_info!(\"    Block Number: {}\", block_number);\n            node_info!(\"    Block Hash: {:?}\", block_hash);\n            if timestamp.year() > 9999 {\n                // rf2822 panics with more than 4 digits\n                node_info!(\"    Block Time: {:?}\\n\", timestamp.to_rfc3339());\n            } else {\n                node_info!(\"    Block Time: {:?}\\n\", timestamp.to_rfc2822());\n            }\n\n            let outcome = MinedBlockOutcome { block_number, included, invalid };\n\n            (outcome, header, block_hash)\n        };\n        let next_block_base_fee = self.fees.get_next_block_base_fee_per_gas(\n            header.gas_used,\n            header.gas_limit,\n            header.base_fee_per_gas.unwrap_or_default(),\n        );\n        let next_block_excess_blob_gas = self.fees.get_next_block_blob_excess_gas(\n            header.excess_blob_gas.unwrap_or_default(),\n            header.blob_gas_used.unwrap_or_default(),\n        );\n\n        // update next base fee\n        self.fees.set_base_fee(next_block_base_fee);\n\n        self.fees.set_blob_excess_gas_and_price(BlobExcessGasAndPrice::new(\n            next_block_excess_blob_gas,\n            get_blob_base_fee_update_fraction_by_spec_id(*self.env.read().evm_env.spec_id()),\n        ));\n\n        // notify all listeners\n        self.notify_on_new_block(header, block_hash);\n\n        outcome\n    }\n\n    /// Reorg the chain to a common height and execute blocks to build new chain.\n    ///\n    /// The state of the chain is rewound using `rewind` to the common block, including the db,\n    /// storage, and env.\n    ///\n    /// Finally, `do_mine_block` is called to create the new chain.\n    pub async fn reorg(\n        &self,\n        depth: u64,\n        tx_pairs: HashMap<u64, Vec<Arc<PoolTransaction<FoundryTxEnvelope>>>>,\n        common_block: Block,\n    ) -> Result<(), BlockchainError> {\n        self.rollback(common_block).await?;\n        // Create the new reorged chain, filling the blocks with transactions if supplied\n        for i in 0..depth {\n            let to_be_mined = tx_pairs.get(&i).cloned().unwrap_or_else(Vec::new);\n            let outcome = self.do_mine_block(to_be_mined).await;\n            node_info!(\n                \"    Mined reorg block number {}. With {} valid txs and with invalid {} txs\",\n                outcome.block_number,\n                outcome.included.len(),\n                outcome.invalid.len()\n            );\n        }\n\n        Ok(())\n    }\n\n    /// Creates the pending block\n    ///\n    /// This will execute all transaction in the order they come but will not mine the block\n    pub async fn pending_block(\n        &self,\n        pool_transactions: Vec<Arc<PoolTransaction<FoundryTxEnvelope>>>,\n    ) -> BlockInfo {\n        self.with_pending_block(pool_transactions, |_, block| block).await\n    }\n\n    /// Creates the pending block\n    ///\n    /// This will execute all transaction in the order they come but will not mine the block\n    pub async fn with_pending_block<F, T>(\n        &self,\n        pool_transactions: Vec<Arc<PoolTransaction<FoundryTxEnvelope>>>,\n        f: F,\n    ) -> T\n    where\n        F: FnOnce(Box<dyn MaybeFullDatabase + '_>, BlockInfo) -> T,\n    {\n        let db = self.db.read().await;\n        let env = self.next_env();\n\n        let mut cache_db = AnvilCacheDB::new(&*db);\n\n        let parent_hash = self.blockchain.storage.read().best_hash;\n\n        let spec_id = *env.evm_env.spec_id();\n        let is_shanghai = spec_id >= SpecId::SHANGHAI;\n        let is_cancun = spec_id >= SpecId::CANCUN;\n        let is_prague = spec_id >= SpecId::PRAGUE;\n        let gas_limit = env.evm_env.block_env.gas_limit;\n        let difficulty = env.evm_env.block_env.difficulty;\n        let mix_hash = env.evm_env.block_env.prevrandao;\n        let beneficiary = env.evm_env.block_env.beneficiary;\n        let timestamp = env.evm_env.block_env.timestamp;\n        let base_fee =\n            if spec_id >= SpecId::LONDON { Some(env.evm_env.block_env.basefee) } else { None };\n        let excess_blob_gas =\n            if is_cancun { env.evm_env.block_env.blob_excess_gas() } else { None };\n\n        let mut inspector = AnvilInspector::default().with_tracing();\n        if self.enable_steps_tracing {\n            inspector = inspector.with_steps_tracing();\n        }\n        if self.print_logs {\n            inspector = inspector.with_log_collector();\n        }\n        if self.print_traces {\n            inspector = inspector.with_trace_printer();\n        }\n\n        let env_struct = Env::new(env.evm_env.clone(), Default::default(), env.networks);\n        let mut evm = new_eth_evm_with_inspector(&mut cache_db, &env_struct, inspector);\n\n        env.networks.inject_precompiles(evm.precompiles_mut());\n        if let Some(factory) = &self.precompile_factory {\n            evm.precompiles_mut().extend_precompiles(factory.precompiles());\n        }\n        let cheats = self.cheats().clone();\n        if cheats.has_recover_overrides() {\n            let cheats_arc = Arc::new(cheats.clone());\n            let cheat_ecrecover = CheatEcrecover::new(Arc::clone(&cheats_arc));\n            evm.precompiles_mut().apply_precompile(&EC_RECOVER, move |_| {\n                Some(DynPrecompile::new_stateful(\n                    cheat_ecrecover.precompile_id().clone(),\n                    move |input| cheat_ecrecover.call(input),\n                ))\n            });\n        }\n\n        let exec_ctx = AnvilExecutionCtx { parent_hash, is_prague, is_cancun };\n        let mut executor = AnvilBlockExecutorFactory::create_executor(evm, exec_ctx);\n        executor.apply_pre_execution_changes().expect(\"pre-execution changes failed\");\n\n        let mut transaction_infos: Vec<TransactionInfo> = Vec::new();\n        let mut transactions = Vec::new();\n        let mut bloom = Bloom::default();\n\n        let blob_params = self.blob_params();\n        let networks = env.networks;\n        let mut cumulative_blob_gas_used = if is_cancun { Some(0u64) } else { None };\n\n        for pool_tx in pool_transactions {\n            let pending = &pool_tx.pending_transaction;\n            let sender = *pending.sender();\n\n            let account = match executor\n                .evm_mut()\n                .db_mut()\n                .basic(sender)\n                .map(|a| a.unwrap_or_default())\n            {\n                Ok(acc) => acc,\n                Err(err) => {\n                    trace!(target: \"backend\", ?err, \"db error for tx {:?}, skipping\", pool_tx.hash());\n                    continue;\n                }\n            };\n\n            let tx_env = build_tx_env_for_pending(pending, &cheats, networks, &env.evm_env);\n            let full_env = Env::new(env.evm_env.clone(), tx_env.clone(), networks);\n\n            let cumulative_gas =\n                executor.receipts().last().map(|r| r.cumulative_gas_used()).unwrap_or(0);\n            let max_block_gas = cumulative_gas.saturating_add(pending.transaction.gas_limit());\n            if !env.evm_env.cfg_env.disable_block_gas_limit && max_block_gas > gas_limit {\n                trace!(target: \"backend\", tx_gas_limit = %pending.transaction.gas_limit(), ?pool_tx, \"block gas limit exhausting, skipping transaction\");\n                continue;\n            }\n\n            if env.evm_env.cfg_env.tx_gas_limit_cap.is_none()\n                && pending.transaction.gas_limit() > env.evm_env.cfg_env.tx_gas_limit_cap()\n            {\n                trace!(target: \"backend\", tx_gas_limit = %pending.transaction.gas_limit(), ?pool_tx, \"transaction gas limit exhausting, skipping transaction\");\n                continue;\n            }\n\n            let tx_blob_gas = pending.transaction.blob_gas_used().unwrap_or(0);\n            let current_blob_gas = cumulative_blob_gas_used.unwrap_or(0);\n            if current_blob_gas.saturating_add(tx_blob_gas) > blob_params.max_blob_gas_per_block() {\n                trace!(target: \"backend\", blob_gas = %tx_blob_gas, ?pool_tx, \"block blob gas limit exhausting, skipping transaction\");\n                continue;\n            }\n\n            if let Err(err) = self.validate_pool_transaction_for(pending, &account, &full_env) {\n                warn!(target: \"backend\", \"Skipping invalid tx execution [{:?}] {}\", pool_tx.hash(), err);\n                continue;\n            }\n\n            let nonce = account.nonce;\n\n            let recovered = Recovered::new_unchecked(pending.transaction.as_ref().clone(), sender);\n            trace!(target: \"backend\", \"[{:?}] executing\", pool_tx.hash());\n            match executor.execute_transaction_without_commit((tx_env, recovered)) {\n                Ok(result) => {\n                    let exec_result = result.inner.result.result.clone();\n                    let gas_used = result.inner.result.result.gas_used();\n\n                    executor.commit_transaction(result).expect(\"commit failed\");\n\n                    let insp = executor.evm_mut().inspector_mut();\n\n                    if self.print_traces {\n                        insp.print_traces(self.call_trace_decoder.clone());\n                    }\n                    insp.print_logs();\n\n                    let traces = insp\n                        .tracer\n                        .take()\n                        .map(|t| t.into_traces().into_nodes())\n                        .unwrap_or_default();\n\n                    if self.enable_steps_tracing {\n                        insp.tracer = Some(TracingInspector::new(\n                            TracingInspectorConfig::all().with_state_diffs(),\n                        ));\n                    } else {\n                        insp.tracer = Some(TracingInspector::new(\n                            TracingInspectorConfig::all().set_steps(false),\n                        ));\n                    }\n                    if self.print_logs {\n                        insp.log_collector = Some(foundry_evm::inspectors::LogCollector::Capture {\n                            logs: Vec::new(),\n                        });\n                    }\n\n                    if is_cancun {\n                        cumulative_blob_gas_used =\n                            Some(cumulative_blob_gas_used.unwrap_or(0).saturating_add(tx_blob_gas));\n                    }\n\n                    let (exit_reason, out, logs) = match exec_result {\n                        ExecutionResult::Success { reason, gas_used: _, logs, output, .. } => {\n                            (reason.into(), Some(output), logs)\n                        }\n                        ExecutionResult::Revert { gas_used: _, output } => {\n                            (InstructionResult::Revert, Some(Output::Call(output)), Vec::new())\n                        }\n                        ExecutionResult::Halt { reason, gas_used: _ } => {\n                            (op_haltreason_to_instruction_result(reason), None, Vec::new())\n                        }\n                    };\n\n                    for log in &logs {\n                        bloom.accrue(BloomInput::Raw(&log.address[..]));\n                        for topic in log.topics() {\n                            bloom.accrue(BloomInput::Raw(&topic[..]));\n                        }\n                    }\n\n                    let contract_address = if pending.transaction.to().is_none() {\n                        let addr = sender.create(nonce);\n                        Some(addr)\n                    } else {\n                        None\n                    };\n\n                    let transaction_index = transaction_infos.len() as u64;\n                    let info = TransactionInfo {\n                        transaction_hash: pool_tx.hash(),\n                        transaction_index,\n                        from: sender,\n                        to: pending.transaction.to(),\n                        contract_address,\n                        traces,\n                        exit: exit_reason,\n                        out: out.map(Output::into_data),\n                        nonce,\n                        gas_used,\n                    };\n\n                    transaction_infos.push(info);\n                    transactions.push(pending.transaction.clone());\n                }\n                Err(err) => {\n                    trace!(target: \"backend\", ?err, \"tx execution error, skipping {:?}\", pool_tx.hash());\n                }\n            }\n        }\n\n        let (evm, block_result) = executor.finish().expect(\"executor finish failed\");\n        drop(evm);\n\n        // Extract inner CacheDB (which implements MaybeFullDatabase)\n        let cache_db = cache_db.0;\n\n        let state_root = cache_db.maybe_state_root().unwrap_or_default();\n        let receipts_root = calculate_receipt_root(&block_result.receipts);\n        let cumulative_gas_used = block_result.gas_used;\n\n        let header = Header {\n            parent_hash,\n            ommers_hash: Default::default(),\n            beneficiary,\n            state_root,\n            transactions_root: Default::default(),\n            receipts_root,\n            logs_bloom: bloom,\n            difficulty,\n            number: env.evm_env.block_env.number.saturating_to(),\n            gas_limit,\n            gas_used: cumulative_gas_used,\n            timestamp: timestamp.saturating_to(),\n            extra_data: Default::default(),\n            mix_hash: mix_hash.unwrap_or_default(),\n            nonce: Default::default(),\n            base_fee_per_gas: base_fee,\n            parent_beacon_block_root: is_cancun.then_some(Default::default()),\n            blob_gas_used: cumulative_blob_gas_used,\n            excess_blob_gas,\n            withdrawals_root: is_shanghai.then_some(EMPTY_WITHDRAWALS),\n            requests_hash: is_prague.then_some(EMPTY_REQUESTS_HASH),\n        };\n\n        let block = create_block(header, transactions);\n        let block_info = TypedBlockInfo {\n            block,\n            transactions: transaction_infos,\n            receipts: block_result.receipts,\n        };\n\n        f(Box::new(cache_db), block_info)\n    }\n\n    /// Executes the [TransactionRequest] without writing to the DB\n    ///\n    /// # Errors\n    ///\n    /// Returns an error if the `block_number` is greater than the current height\n    pub async fn call(\n        &self,\n        request: WithOtherFields<TransactionRequest>,\n        fee_details: FeeDetails,\n        block_request: Option<BlockRequest<FoundryTxEnvelope>>,\n        overrides: EvmOverrides,\n    ) -> Result<(InstructionResult, Option<Output>, u128, State), BlockchainError> {\n        self.with_database_at(block_request, |state, mut block| {\n            let block_number = block.number;\n            let (exit, out, gas, state) = {\n                let mut cache_db = CacheDB::new(state);\n                if let Some(state_overrides) = overrides.state {\n                    apply_state_overrides(state_overrides.into_iter().collect(), &mut cache_db)?;\n                }\n                if let Some(block_overrides) = overrides.block {\n                    cache_db.apply_block_overrides(*block_overrides, &mut block);\n                }\n                self.call_with_state(&cache_db, request, fee_details, block)\n            }?;\n            trace!(target: \"backend\", \"call return {:?} out: {:?} gas {} on block {}\", exit, out, gas, block_number);\n            Ok((exit, out, gas, state))\n        }).await?\n    }\n\n    pub async fn call_with_tracing(\n        &self,\n        request: WithOtherFields<TransactionRequest>,\n        fee_details: FeeDetails,\n        block_request: Option<BlockRequest<FoundryTxEnvelope>>,\n        opts: GethDebugTracingCallOptions,\n    ) -> Result<GethTrace, BlockchainError> {\n        let GethDebugTracingCallOptions {\n            tracing_options, block_overrides, state_overrides, ..\n        } = opts;\n        let GethDebugTracingOptions { config, tracer, tracer_config, .. } = tracing_options;\n\n        self.with_database_at(block_request, |state, mut block| {\n            let block_number = block.number;\n\n            let mut cache_db = CacheDB::new(state);\n            if let Some(state_overrides) = state_overrides {\n                apply_state_overrides(state_overrides, &mut cache_db)?;\n            }\n            if let Some(block_overrides) = block_overrides {\n                cache_db.apply_block_overrides(block_overrides, &mut block);\n            }\n\n            if let Some(tracer) = tracer {\n                return match tracer {\n                    GethDebugTracerType::BuiltInTracer(tracer) => match tracer {\n                        GethDebugBuiltInTracerType::CallTracer => {\n                            let call_config = tracer_config\n                                .into_call_config()\n                                .map_err(|e| RpcError::invalid_params(e.to_string()))?;\n\n                            let mut inspector = self.build_inspector().with_tracing_config(\n                                TracingInspectorConfig::from_geth_call_config(&call_config),\n                            );\n\n                            let env = self.build_call_env(request, fee_details, block);\n                            let mut evm = self.new_eth_evm_with_inspector_ref(\n                                &cache_db,\n                                &env,\n                                &mut inspector,\n                            );\n                            let ResultAndState { result, state: _ } = evm.transact(env.tx)?;\n\n                            drop(evm);\n\n                            inspector.print_logs();\n                            if self.print_traces {\n                                inspector.print_traces(self.call_trace_decoder.clone());\n                            }\n\n                            let tracing_inspector = inspector.tracer.expect(\"tracer disappeared\");\n\n                            Ok(tracing_inspector\n                                .into_geth_builder()\n                                .geth_call_traces(call_config, result.gas_used())\n                                .into())\n                        }\n                        GethDebugBuiltInTracerType::PreStateTracer => {\n                            let pre_state_config = tracer_config\n                                .into_pre_state_config()\n                                .map_err(|e| RpcError::invalid_params(e.to_string()))?;\n\n                            let mut inspector = TracingInspector::new(\n                                TracingInspectorConfig::from_geth_prestate_config(\n                                    &pre_state_config,\n                                ),\n                            );\n\n                            let env = self.build_call_env(request, fee_details, block);\n                            let mut evm = self.new_eth_evm_with_inspector_ref(\n                                &cache_db,\n                                &env,\n                                &mut inspector,\n                            );\n                            let result = evm.transact(env.tx)?;\n\n                            drop(evm);\n\n                            Ok(inspector\n                                .into_geth_builder()\n                                .geth_prestate_traces(&result, &pre_state_config, cache_db)?\n                                .into())\n                        }\n                        GethDebugBuiltInTracerType::NoopTracer => Ok(NoopFrame::default().into()),\n                        GethDebugBuiltInTracerType::FourByteTracer\n                        | GethDebugBuiltInTracerType::MuxTracer\n                        | GethDebugBuiltInTracerType::FlatCallTracer\n                        | GethDebugBuiltInTracerType::Erc7562Tracer => {\n                            Err(RpcError::invalid_params(\"unsupported tracer type\").into())\n                        }\n                    },\n                    #[cfg(not(feature = \"js-tracer\"))]\n                    GethDebugTracerType::JsTracer(_) => {\n                        Err(RpcError::invalid_params(\"unsupported tracer type\").into())\n                    }\n                    #[cfg(feature = \"js-tracer\")]\n                    GethDebugTracerType::JsTracer(code) => {\n                        use alloy_evm::IntoTxEnv;\n                        let config = tracer_config.into_json();\n                        let mut inspector =\n                            revm_inspectors::tracing::js::JsInspector::new(code, config)\n                                .map_err(|err| BlockchainError::Message(err.to_string()))?;\n\n                        let env = self.build_call_env(request, fee_details, block.clone());\n                        let mut evm =\n                            self.new_eth_evm_with_inspector_ref(&cache_db, &env, &mut inspector);\n                        let result = evm.transact(env.tx.clone())?;\n                        let res = evm\n                            .inspector_mut()\n                            .json_result(result, &env.tx.into_tx_env(), &block, &cache_db)\n                            .map_err(|err| BlockchainError::Message(err.to_string()))?;\n\n                        Ok(GethTrace::JS(res))\n                    }\n                };\n            }\n\n            // defaults to StructLog tracer used since no tracer is specified\n            let mut inspector = self\n                .build_inspector()\n                .with_tracing_config(TracingInspectorConfig::from_geth_config(&config));\n\n            let env = self.build_call_env(request, fee_details, block);\n            let mut evm = self.new_eth_evm_with_inspector_ref(&cache_db, &env, &mut inspector);\n            let ResultAndState { result, state: _ } = evm.transact(env.tx)?;\n\n            let (exit_reason, gas_used, out) = match result {\n                ExecutionResult::Success { reason, gas_used, output, .. } => {\n                    (reason.into(), gas_used, Some(output))\n                }\n                ExecutionResult::Revert { gas_used, output } => {\n                    (InstructionResult::Revert, gas_used, Some(Output::Call(output)))\n                }\n                ExecutionResult::Halt { reason, gas_used } => {\n                    (op_haltreason_to_instruction_result(reason), gas_used, None)\n                }\n            };\n\n            drop(evm);\n            let tracing_inspector = inspector.tracer.expect(\"tracer disappeared\");\n            let return_value = out.as_ref().map(|o| o.data()).cloned().unwrap_or_default();\n\n            trace!(target: \"backend\", ?exit_reason, ?out, %gas_used, %block_number, \"trace call\");\n\n            let res = tracing_inspector\n                .into_geth_builder()\n                .geth_traces(gas_used, return_value, config)\n                .into();\n\n            Ok(res)\n        })\n        .await?\n    }\n\n    /// Helper function to execute a closure with the database at a specific block\n    pub async fn with_database_at<F, T>(\n        &self,\n        block_request: Option<BlockRequest<FoundryTxEnvelope>>,\n        f: F,\n    ) -> Result<T, BlockchainError>\n    where\n        F: FnOnce(Box<dyn MaybeFullDatabase + '_>, BlockEnv) -> T,\n    {\n        let block_number = match block_request {\n            Some(BlockRequest::Pending(pool_transactions)) => {\n                let result = self\n                    .with_pending_block(pool_transactions, |state, block| {\n                        let block = block.block;\n                        f(state, block_env_from_header(&block.header))\n                    })\n                    .await;\n                return Ok(result);\n            }\n            Some(BlockRequest::Number(bn)) => Some(BlockNumber::Number(bn)),\n            None => None,\n        };\n        let block_number = self.convert_block_number(block_number);\n        let current_number = self.best_number();\n\n        // Reject requests for future blocks that don't exist yet\n        if block_number > current_number {\n            return Err(BlockchainError::BlockOutOfRange(current_number, block_number));\n        }\n\n        if block_number < current_number {\n            if let Some((block_hash, block)) = self\n                .block_by_number(BlockNumber::Number(block_number))\n                .await?\n                .map(|block| (block.header.hash, block))\n            {\n                let read_guard = self.states.upgradable_read();\n                if let Some(state_db) = read_guard.get_state(&block_hash) {\n                    return Ok(f(Box::new(state_db), block_env_from_header(&block.header)));\n                } else {\n                    let mut write_guard = RwLockUpgradableReadGuard::upgrade(read_guard);\n                    if let Some(state) = write_guard.get_on_disk_state(&block_hash) {\n                        return Ok(f(Box::new(state), block_env_from_header(&block.header)));\n                    }\n                }\n            }\n\n            warn!(target: \"backend\", \"Not historic state found for block={}\", block_number);\n            return Err(BlockchainError::BlockOutOfRange(current_number, block_number));\n        }\n\n        let db = self.db.read().await;\n        let block = self.env.read().evm_env.block_env.clone();\n        Ok(f(Box::new(&**db), block))\n    }\n\n    pub async fn storage_at(\n        &self,\n        address: Address,\n        index: U256,\n        block_request: Option<BlockRequest<FoundryTxEnvelope>>,\n    ) -> Result<B256, BlockchainError> {\n        self.with_database_at(block_request, |db, _| {\n            trace!(target: \"backend\", \"get storage for {:?} at {:?}\", address, index);\n            let val = db.storage_ref(address, index)?;\n            Ok(val.into())\n        })\n        .await?\n    }\n\n    /// Returns the code of the address\n    ///\n    /// If the code is not present and fork mode is enabled then this will try to fetch it from the\n    /// forked client\n    pub async fn get_code(\n        &self,\n        address: Address,\n        block_request: Option<BlockRequest<FoundryTxEnvelope>>,\n    ) -> Result<Bytes, BlockchainError> {\n        self.with_database_at(block_request, |db, _| self.get_code_with_state(&db, address)).await?\n    }\n\n    /// Returns the balance of the address\n    ///\n    /// If the requested number predates the fork then this will fetch it from the endpoint\n    pub async fn get_balance(\n        &self,\n        address: Address,\n        block_request: Option<BlockRequest<FoundryTxEnvelope>>,\n    ) -> Result<U256, BlockchainError> {\n        self.with_database_at(block_request, |db, _| self.get_balance_with_state(db, address))\n            .await?\n    }\n\n    pub async fn get_account_at_block(\n        &self,\n        address: Address,\n        block_request: Option<BlockRequest<FoundryTxEnvelope>>,\n    ) -> Result<TrieAccount, BlockchainError> {\n        self.with_database_at(block_request, |block_db, _| {\n            let db = block_db.maybe_as_full_db().ok_or(BlockchainError::DataUnavailable)?;\n            let account = db.get(&address).cloned().unwrap_or_default();\n            let storage_root = storage_root(&account.storage);\n            let code_hash = account.info.code_hash;\n            let balance = account.info.balance;\n            let nonce = account.info.nonce;\n            Ok(TrieAccount { balance, nonce, code_hash, storage_root })\n        })\n        .await?\n    }\n\n    /// Returns the nonce of the address\n    ///\n    /// If the requested number predates the fork then this will fetch it from the endpoint\n    pub async fn get_nonce(\n        &self,\n        address: Address,\n        block_request: BlockRequest<FoundryTxEnvelope>,\n    ) -> Result<u64, BlockchainError> {\n        if let BlockRequest::Pending(pool_transactions) = &block_request\n            && let Some(value) = get_pool_transactions_nonce(pool_transactions, address)\n        {\n            return Ok(value);\n        }\n        let final_block_request = match block_request {\n            BlockRequest::Pending(_) => BlockRequest::Number(self.best_number()),\n            BlockRequest::Number(bn) => BlockRequest::Number(bn),\n        };\n\n        self.with_database_at(Some(final_block_request), |db, _| {\n            trace!(target: \"backend\", \"get nonce for {:?}\", address);\n            Ok(db.basic_ref(address)?.unwrap_or_default().nonce)\n        })\n        .await?\n    }\n\n    fn replay_tx_with_inspector<I, F, T>(\n        &self,\n        hash: B256,\n        mut inspector: I,\n        f: F,\n    ) -> Result<T, BlockchainError>\n    where\n        for<'a> I: Inspector<EthEvmContext<WrapDatabaseRef<&'a CacheDB<Box<&'a StateDb>>>>>\n            + Inspector<OpContext<WrapDatabaseRef<&'a CacheDB<Box<&'a StateDb>>>>>\n            + 'a,\n        for<'a> F:\n            FnOnce(ResultAndState<OpHaltReason>, CacheDB<Box<&'a StateDb>>, I, TxEnv, Env) -> T,\n    {\n        let block = {\n            let storage = self.blockchain.storage.read();\n            let MinedTransaction { block_hash, .. } = storage\n                .transactions\n                .get(&hash)\n                .cloned()\n                .ok_or(BlockchainError::TransactionNotFound)?;\n\n            storage.blocks.get(&block_hash).cloned().ok_or(BlockchainError::BlockNotFound)?\n        };\n\n        let index = block\n            .body\n            .transactions\n            .iter()\n            .position(|tx| tx.hash() == hash)\n            .expect(\"transaction not found in block\");\n\n        let pool_txs: Vec<Arc<PoolTransaction<FoundryTxEnvelope>>> = block.body.transactions\n            [..index]\n            .iter()\n            .map(|tx| {\n                let pending_tx =\n                    PendingTransaction::from_maybe_impersonated(tx.clone()).expect(\"is valid\");\n                Arc::new(PoolTransaction {\n                    pending_transaction: pending_tx,\n                    requires: vec![],\n                    provides: vec![],\n                    priority: crate::eth::pool::transactions::TransactionPriority(0),\n                })\n            })\n            .collect();\n\n        let trace = |parent_state: &StateDb| -> Result<T, BlockchainError> {\n            let mut cache_db = AnvilCacheDB::new(Box::new(parent_state));\n\n            // configure the blockenv for the block of the transaction\n            let mut env = self.env.read().clone();\n\n            env.evm_env.block_env = block_env_from_header(&block.header);\n\n            let spec_id = *env.evm_env.spec_id();\n            let is_cancun = spec_id >= SpecId::CANCUN;\n            let is_prague = spec_id >= SpecId::PRAGUE;\n            let gas_limit = env.evm_env.block_env.gas_limit;\n\n            let mut inspector_replay = AnvilInspector::default().with_tracing();\n            if self.enable_steps_tracing {\n                inspector_replay = inspector_replay.with_steps_tracing();\n            }\n            if self.print_logs {\n                inspector_replay = inspector_replay.with_log_collector();\n            }\n            if self.print_traces {\n                inspector_replay = inspector_replay.with_trace_printer();\n            }\n\n            let env_struct = Env::new(env.evm_env.clone(), Default::default(), env.networks);\n            let mut evm_replay =\n                new_eth_evm_with_inspector(&mut cache_db, &env_struct, inspector_replay);\n\n            env.networks.inject_precompiles(evm_replay.precompiles_mut());\n            if let Some(factory) = &self.precompile_factory {\n                evm_replay.precompiles_mut().extend_precompiles(factory.precompiles());\n            }\n            let cheats = self.cheats().clone();\n            if cheats.has_recover_overrides() {\n                let cheats_arc = Arc::new(cheats.clone());\n                let cheat_ecrecover = CheatEcrecover::new(Arc::clone(&cheats_arc));\n                evm_replay.precompiles_mut().apply_precompile(&EC_RECOVER, move |_| {\n                    Some(DynPrecompile::new_stateful(\n                        cheat_ecrecover.precompile_id().clone(),\n                        move |input| cheat_ecrecover.call(input),\n                    ))\n                });\n            }\n\n            let exec_ctx =\n                AnvilExecutionCtx { parent_hash: block.header.parent_hash, is_prague, is_cancun };\n            let mut replay_executor =\n                AnvilBlockExecutorFactory::create_executor(evm_replay, exec_ctx);\n            replay_executor.apply_pre_execution_changes().expect(\"pre-execution changes failed\");\n\n            let blob_params = self.blob_params();\n            let networks = env.networks;\n            let mut cumulative_blob_gas_used = if is_cancun { Some(0u64) } else { None };\n\n            for pool_tx in pool_txs {\n                let pending = &pool_tx.pending_transaction;\n                let sender = *pending.sender();\n\n                let account = match replay_executor\n                    .evm_mut()\n                    .db_mut()\n                    .basic(sender)\n                    .map(|a| a.unwrap_or_default())\n                {\n                    Ok(acc) => acc,\n                    Err(_) => continue,\n                };\n\n                let tx_env = build_tx_env_for_pending(pending, &cheats, networks, &env.evm_env);\n                let full_env = Env::new(env.evm_env.clone(), tx_env.clone(), networks);\n\n                let cumulative_gas =\n                    replay_executor.receipts().last().map(|r| r.cumulative_gas_used()).unwrap_or(0);\n                let max_block_gas = cumulative_gas.saturating_add(pending.transaction.gas_limit());\n                if !env.evm_env.cfg_env.disable_block_gas_limit && max_block_gas > gas_limit {\n                    continue;\n                }\n\n                if env.evm_env.cfg_env.tx_gas_limit_cap.is_none()\n                    && pending.transaction.gas_limit() > env.evm_env.cfg_env.tx_gas_limit_cap()\n                {\n                    continue;\n                }\n\n                let tx_blob_gas = pending.transaction.blob_gas_used().unwrap_or(0);\n                let current_blob_gas = cumulative_blob_gas_used.unwrap_or(0);\n                if current_blob_gas.saturating_add(tx_blob_gas)\n                    > blob_params.max_blob_gas_per_block()\n                {\n                    continue;\n                }\n\n                if self.validate_pool_transaction_for(pending, &account, &full_env).is_err() {\n                    continue;\n                }\n\n                let recovered =\n                    Recovered::new_unchecked(pending.transaction.as_ref().clone(), sender);\n                if let Ok(result) =\n                    replay_executor.execute_transaction_without_commit((tx_env, recovered))\n                {\n                    replay_executor.commit_transaction(result).expect(\"commit failed\");\n\n                    let insp = replay_executor.evm_mut().inspector_mut();\n                    insp.print_logs();\n                    if self.print_traces {\n                        insp.print_traces(self.call_trace_decoder.clone());\n                    }\n                    insp.tracer.take();\n                    if self.enable_steps_tracing {\n                        insp.tracer = Some(TracingInspector::new(\n                            TracingInspectorConfig::all().with_state_diffs(),\n                        ));\n                    } else {\n                        insp.tracer = Some(TracingInspector::new(\n                            TracingInspectorConfig::all().set_steps(false),\n                        ));\n                    }\n                    if self.print_logs {\n                        insp.log_collector = Some(foundry_evm::inspectors::LogCollector::Capture {\n                            logs: Vec::new(),\n                        });\n                    }\n\n                    if is_cancun {\n                        cumulative_blob_gas_used =\n                            Some(cumulative_blob_gas_used.unwrap_or(0).saturating_add(tx_blob_gas));\n                    }\n                }\n            }\n\n            let (evm_done, _) = replay_executor.finish().expect(\"executor finish failed\");\n            drop(evm_done);\n\n            // Extract inner CacheDB to match the expected types for the target tx execution\n            let cache_db = cache_db.0;\n\n            let target_tx = block.body.transactions[index].clone();\n            let target_tx = PendingTransaction::from_maybe_impersonated(target_tx)?;\n            let mut tx_env: OpTransaction<TxEnv> = FromRecoveredTx::from_recovered_tx(\n                target_tx.transaction.as_ref(),\n                *target_tx.sender(),\n            );\n            if env.networks.is_optimism() {\n                tx_env.enveloped_tx = Some(target_tx.transaction.encoded_2718().into());\n            }\n\n            let mut evm = self.new_eth_evm_with_inspector_ref(&cache_db, &env, &mut inspector);\n\n            let result = evm\n                .transact(tx_env.clone())\n                .map_err(|err| BlockchainError::Message(err.to_string()))?;\n\n            Ok(f(result, cache_db, inspector, tx_env.base, env))\n        };\n\n        let read_guard = self.states.upgradable_read();\n        if let Some(state) = read_guard.get_state(&block.header.parent_hash) {\n            trace(state)\n        } else {\n            let mut write_guard = RwLockUpgradableReadGuard::upgrade(read_guard);\n            let state = write_guard\n                .get_on_disk_state(&block.header.parent_hash)\n                .ok_or(BlockchainError::BlockNotFound)?;\n            trace(state)\n        }\n    }\n\n    /// Traces the transaction with the js tracer\n    #[cfg(feature = \"js-tracer\")]\n    pub async fn trace_tx_with_js_tracer(\n        &self,\n        hash: B256,\n        code: String,\n        opts: GethDebugTracingOptions,\n    ) -> Result<GethTrace, BlockchainError> {\n        let GethDebugTracingOptions { tracer_config, .. } = opts;\n        let config = tracer_config.into_json();\n        let inspector = revm_inspectors::tracing::js::JsInspector::new(code, config)\n            .map_err(|err| BlockchainError::Message(err.to_string()))?;\n        let trace = self.replay_tx_with_inspector(\n            hash,\n            inspector,\n            |result, cache_db, mut inspector, tx_env, env| {\n                inspector\n                    .json_result(\n                        result,\n                        &alloy_evm::IntoTxEnv::into_tx_env(tx_env),\n                        &env.evm_env.block_env,\n                        &cache_db,\n                    )\n                    .map_err(|e| BlockchainError::Message(e.to_string()))\n            },\n        )??;\n        Ok(GethTrace::JS(trace))\n    }\n\n    /// Prove an account's existence or nonexistence in the state trie.\n    ///\n    /// Returns a merkle proof of the account's trie node, `account_key` == keccak(address)\n    pub async fn prove_account_at(\n        &self,\n        address: Address,\n        keys: Vec<B256>,\n        block_request: Option<BlockRequest<FoundryTxEnvelope>>,\n    ) -> Result<AccountProof, BlockchainError> {\n        let block_number = block_request.as_ref().map(|r| r.block_number());\n\n        self.with_database_at(block_request, |block_db, _| {\n            trace!(target: \"backend\", \"get proof for {:?} at {:?}\", address, block_number);\n            let db = block_db.maybe_as_full_db().ok_or(BlockchainError::DataUnavailable)?;\n            let account = db.get(&address).cloned().unwrap_or_default();\n\n            let mut builder = HashBuilder::default()\n                .with_proof_retainer(ProofRetainer::new(vec![Nibbles::unpack(keccak256(address))]));\n\n            for (key, account) in trie_accounts(db) {\n                builder.add_leaf(key, &account);\n            }\n\n            let _ = builder.root();\n\n            let proof = builder\n                .take_proof_nodes()\n                .into_nodes_sorted()\n                .into_iter()\n                .map(|(_, v)| v)\n                .collect();\n            let (storage_hash, storage_proofs) = prove_storage(&account.storage, &keys);\n\n            let account_proof = AccountProof {\n                address,\n                balance: account.info.balance,\n                nonce: account.info.nonce,\n                code_hash: account.info.code_hash,\n                storage_hash,\n                account_proof: proof,\n                storage_proof: keys\n                    .into_iter()\n                    .zip(storage_proofs)\n                    .map(|(key, proof)| {\n                        let storage_key: U256 = key.into();\n                        let value = account.storage.get(&storage_key).copied().unwrap_or_default();\n                        StorageProof { key: JsonStorageKey::Hash(key), value, proof }\n                    })\n                    .collect(),\n            };\n\n            Ok(account_proof)\n        })\n        .await?\n    }\n\n    /// Rollback the chain to a common height.\n    ///\n    /// The state of the chain is rewound using `rewind` to the common block, including the db,\n    /// storage, and env.\n    pub async fn rollback(&self, common_block: Block) -> Result<(), BlockchainError> {\n        let hash = common_block.header.hash_slow();\n\n        // Get the database at the common block\n        let common_state = {\n            let return_state_or_throw_err =\n                |db: Option<&StateDb>| -> Result<AddressMap<DbAccount>, BlockchainError> {\n                    let state_db = db.ok_or(BlockchainError::DataUnavailable)?;\n                    let db_full =\n                        state_db.maybe_as_full_db().ok_or(BlockchainError::DataUnavailable)?;\n                    Ok(db_full.clone())\n                };\n\n            let read_guard = self.states.upgradable_read();\n            if let Some(db) = read_guard.get_state(&hash) {\n                return_state_or_throw_err(Some(db))?\n            } else {\n                let mut write_guard = RwLockUpgradableReadGuard::upgrade(read_guard);\n                return_state_or_throw_err(write_guard.get_on_disk_state(&hash))?\n            }\n        };\n\n        {\n            // Unwind the storage back to the common ancestor first\n            self.blockchain.storage.write().unwind_to(common_block.header.number(), hash);\n\n            // Set environment back to common block\n            let mut env = self.env.write();\n            env.evm_env.block_env.number = U256::from(common_block.header.number());\n            env.evm_env.block_env.timestamp = U256::from(common_block.header.timestamp());\n            env.evm_env.block_env.gas_limit = common_block.header.gas_limit();\n            env.evm_env.block_env.difficulty = common_block.header.difficulty();\n            env.evm_env.block_env.prevrandao = common_block.header.mix_hash();\n\n            self.time.reset(env.evm_env.block_env.timestamp.saturating_to());\n        }\n\n        {\n            // Collect block hashes before acquiring db lock to avoid holding blockchain storage\n            // lock across await. Only collect the last 256 blocks since that's all BLOCKHASH can\n            // access.\n            let block_hashes: Vec<_> = {\n                let storage = self.blockchain.storage.read();\n                let min_block = common_block.header.number().saturating_sub(256);\n                storage\n                    .hashes\n                    .iter()\n                    .filter(|(num, _)| **num >= min_block)\n                    .map(|(&num, &hash)| (num, hash))\n                    .collect()\n            };\n\n            // Acquire db lock once for the entire restore operation to reduce lock churn.\n            let mut db = self.db.write().await;\n            db.clear();\n\n            // Insert account info before storage to prevent fork-mode RPC fetches after clear.\n            for (address, acc) in common_state {\n                db.insert_account(address, acc.info);\n                for (key, value) in acc.storage {\n                    db.set_storage_at(address, key.into(), value.into())?;\n                }\n            }\n\n            // Restore block hashes from blockchain storage (now unwound, contains only valid\n            // blocks).\n            for (block_num, hash) in block_hashes {\n                db.insert_block_hash(U256::from(block_num), hash);\n            }\n        }\n\n        Ok(())\n    }\n}\n\nimpl Backend<FoundryNetwork> {\n    /// Get the current state.\n    pub async fn serialized_state(\n        &self,\n        preserve_historical_states: bool,\n    ) -> Result<SerializableState, BlockchainError> {\n        let at = self.env.read().evm_env.block_env.clone();\n        let best_number = self.blockchain.storage.read().best_number;\n        let blocks = self.blockchain.storage.read().serialized_blocks();\n        let transactions = self.blockchain.storage.read().serialized_transactions();\n        let historical_states = if preserve_historical_states {\n            Some(self.states.write().serialized_states())\n        } else {\n            None\n        };\n\n        let state = self.db.read().await.dump_state(\n            at,\n            best_number,\n            blocks,\n            transactions,\n            historical_states,\n        )?;\n        state.ok_or_else(|| {\n            RpcError::invalid_params(\"Dumping state not supported with the current configuration\")\n                .into()\n        })\n    }\n\n    /// Write all chain data to serialized bytes buffer\n    pub async fn dump_state(\n        &self,\n        preserve_historical_states: bool,\n    ) -> Result<Bytes, BlockchainError> {\n        let state = self.serialized_state(preserve_historical_states).await?;\n        let mut encoder = GzEncoder::new(Vec::new(), Compression::default());\n        encoder\n            .write_all(&serde_json::to_vec(&state).unwrap_or_default())\n            .map_err(|_| BlockchainError::DataUnavailable)?;\n        Ok(encoder.finish().unwrap_or_default().into())\n    }\n\n    /// Apply [SerializableState] data to the backend storage.\n    pub async fn load_state(&self, state: SerializableState) -> Result<bool, BlockchainError> {\n        // load the blocks and transactions into the storage\n        self.blockchain.storage.write().load_blocks(state.blocks.clone());\n        self.blockchain.storage.write().load_transactions(state.transactions.clone());\n        // reset the block env\n        if let Some(block) = state.block.clone() {\n            self.env.write().evm_env.block_env = block.clone();\n\n            // Set the current best block number.\n            // Defaults to block number for compatibility with existing state files.\n            let fork_num_and_hash = self.get_fork().map(|f| (f.block_number(), f.block_hash()));\n\n            let best_number = state.best_block_number.unwrap_or(block.number.saturating_to());\n            if let Some((number, hash)) = fork_num_and_hash {\n                trace!(target: \"backend\", state_block_number=?best_number, fork_block_number=?number);\n                // If the state.block_number is greater than the fork block number, set best number\n                // to the state block number.\n                // Ref: https://github.com/foundry-rs/foundry/issues/9539\n                if best_number > number {\n                    self.blockchain.storage.write().best_number = best_number;\n                    let best_hash =\n                        self.blockchain.storage.read().hash(best_number.into()).ok_or_else(\n                            || {\n                                BlockchainError::RpcError(RpcError::internal_error_with(format!(\n                                    \"Best hash not found for best number {best_number}\",\n                                )))\n                            },\n                        )?;\n                    self.blockchain.storage.write().best_hash = best_hash;\n                } else {\n                    // If loading state file on a fork, set best number to the fork block number.\n                    // Ref: https://github.com/foundry-rs/foundry/pull/9215#issue-2618681838\n                    self.blockchain.storage.write().best_number = number;\n                    self.blockchain.storage.write().best_hash = hash;\n                }\n            } else {\n                self.blockchain.storage.write().best_number = best_number;\n\n                // Set the current best block hash;\n                let best_hash =\n                    self.blockchain.storage.read().hash(best_number.into()).ok_or_else(|| {\n                        BlockchainError::RpcError(RpcError::internal_error_with(format!(\n                            \"Best hash not found for best number {best_number}\",\n                        )))\n                    })?;\n\n                self.blockchain.storage.write().best_hash = best_hash;\n            }\n        }\n\n        if let Some(latest) = state.blocks.iter().max_by_key(|b| b.header.number()) {\n            let header = &latest.header;\n            let next_block_base_fee = self.fees.get_next_block_base_fee_per_gas(\n                header.gas_used(),\n                header.gas_limit(),\n                header.base_fee_per_gas().unwrap_or_default(),\n            );\n            let next_block_excess_blob_gas = self.fees.get_next_block_blob_excess_gas(\n                header.excess_blob_gas().unwrap_or_default(),\n                header.blob_gas_used().unwrap_or_default(),\n            );\n\n            // update next base fee\n            self.fees.set_base_fee(next_block_base_fee);\n\n            self.fees.set_blob_excess_gas_and_price(BlobExcessGasAndPrice::new(\n                next_block_excess_blob_gas,\n                get_blob_base_fee_update_fraction(\n                    self.env.read().evm_env.cfg_env.chain_id,\n                    header.timestamp,\n                ),\n            ));\n        }\n\n        if !self.db.write().await.load_state(state.clone())? {\n            return Err(RpcError::invalid_params(\n                \"Loading state not supported with the current configuration\",\n            )\n            .into());\n        }\n\n        if let Some(historical_states) = state.historical_states {\n            self.states.write().load_states(historical_states);\n        }\n\n        Ok(true)\n    }\n\n    /// Deserialize and add all chain data to the backend storage\n    pub async fn load_state_bytes(&self, buf: Bytes) -> Result<bool, BlockchainError> {\n        let orig_buf = &buf.0[..];\n        let mut decoder = GzDecoder::new(orig_buf);\n        let mut decoded_data = Vec::new();\n\n        let state: SerializableState = serde_json::from_slice(if decoder.header().is_some() {\n            decoder\n                .read_to_end(decoded_data.as_mut())\n                .map_err(|_| BlockchainError::FailedToDecodeStateDump)?;\n            &decoded_data\n        } else {\n            &buf.0\n        })\n        .map_err(|_| BlockchainError::FailedToDecodeStateDump)?;\n\n        self.load_state(state).await\n    }\n\n    /// Simulates the payload by executing the calls in request.\n    pub async fn simulate(\n        &self,\n        request: SimulatePayload,\n        block_request: Option<BlockRequest<FoundryTxEnvelope>>,\n    ) -> Result<Vec<SimulatedBlock<AnyRpcBlock>>, BlockchainError> {\n        self.with_database_at(block_request, |state, mut block_env| {\n            let SimulatePayload {\n                block_state_calls,\n                trace_transfers,\n                validation,\n                return_full_transactions,\n            } = request;\n            let mut cache_db = CacheDB::new(state);\n            let mut block_res = Vec::with_capacity(block_state_calls.len());\n\n            // execute the blocks\n            for block in block_state_calls {\n                let SimBlock { block_overrides, state_overrides, calls } = block;\n                let mut call_res = Vec::with_capacity(calls.len());\n                let mut log_index = 0;\n                let mut gas_used = 0;\n                let mut transactions = Vec::with_capacity(calls.len());\n                let mut logs= Vec::new();\n\n                // apply state overrides before executing the transactions\n                if let Some(state_overrides) = state_overrides {\n                    apply_state_overrides(state_overrides, &mut cache_db)?;\n                }\n                if let Some(block_overrides) = block_overrides {\n                    cache_db.apply_block_overrides(block_overrides, &mut block_env);\n                }\n\n                // execute all calls in that block\n                for (req_idx, request) in calls.into_iter().enumerate() {\n                    let fee_details = FeeDetails::new(\n                        request.gas_price,\n                        request.max_fee_per_gas,\n                        request.max_priority_fee_per_gas,\n                        request.max_fee_per_blob_gas,\n                    )?\n                    .or_zero_fees();\n\n                    let mut env = self.build_call_env(\n                        WithOtherFields::new(request.clone()),\n                        fee_details,\n                        block_env.clone(),\n                    );\n\n                    // Always disable EIP-3607\n                    env.evm_env.cfg_env.disable_eip3607 = true;\n\n                    if !validation {\n                        env.evm_env.cfg_env.disable_base_fee = !validation;\n                        env.evm_env.block_env.basefee = 0;\n                    }\n\n                    let mut inspector = self.build_inspector();\n\n                    // transact\n                    let ResultAndState { result, state } = if trace_transfers {\n                        // prepare inspector to capture transfer inside the evm so they are\n                        // recorded and included in logs\n                        inspector = inspector.with_transfers();\n                        let mut evm= self.new_eth_evm_with_inspector_ref(\n                            &cache_db,\n                            &env,\n                            &mut inspector,\n                        );\n\n                        trace!(target: \"backend\", env=?env.evm_env, spec=?env.evm_env.spec_id(),\"simulate evm env\");\n                        evm.transact(env.tx)?\n                    } else {\n                        let mut evm = self.new_eth_evm_with_inspector_ref(\n                            &cache_db,\n                            &env,\n                            &mut inspector,\n                        );\n                        trace!(target: \"backend\", env=?env.evm_env, spec=?env.evm_env.spec_id(),\"simulate evm env\");\n                        evm.transact(env.tx)?\n                    };\n                    trace!(target: \"backend\", ?result, ?request, \"simulate call\");\n\n                    inspector.print_logs();\n                    if self.print_traces {\n                        inspector.into_print_traces(self.call_trace_decoder.clone());\n                    }\n\n                    // commit the transaction\n                    cache_db.commit(state);\n                    gas_used += result.gas_used();\n\n                    // create the transaction from a request\n                    let from = request.from.unwrap_or_default();\n\n                    let mut request = Into::<FoundryTransactionRequest>::into(WithOtherFields::new(request));\n                    request.prep_for_submission();\n\n                    let typed_tx = request.build_unsigned().map_err(|e| BlockchainError::InvalidTransactionRequest(e.to_string()))?;\n\n                    let tx = build_impersonated(typed_tx);\n                    let tx_hash = tx.hash();\n                    let rpc_tx = transaction_build(\n                        None,\n                        MaybeImpersonatedTransaction::impersonated(tx, from),\n                        None,\n                        None,\n                        Some(block_env.basefee),\n                    );\n                    transactions.push(rpc_tx);\n\n                    let return_data = result.output().cloned().unwrap_or_default();\n                    let sim_res = SimCallResult {\n                        return_data,\n                        gas_used: result.gas_used(),\n                        status: result.is_success(),\n                        error: result.is_success().not().then(|| {\n                            alloy_rpc_types::simulate::SimulateError {\n                                code: -3200,\n                                message: \"execution failed\".to_string(),\n                                data: None,\n                            }\n                        }),\n                        logs: result.clone()\n                            .into_logs()\n                            .into_iter()\n                            .enumerate()\n                            .map(|(idx, log)| Log {\n                                inner: log,\n                                block_number: Some(block_env.number.saturating_to()),\n                                block_timestamp: Some(block_env.timestamp.saturating_to()),\n                                transaction_index: Some(req_idx as u64),\n                                log_index: Some((idx + log_index) as u64),\n                                removed: false,\n\n                                block_hash: None,\n                                transaction_hash: Some(tx_hash),\n                            })\n                            .collect(),\n                    };\n                    logs.extend(sim_res.logs.iter().map(|log| log.inner.clone()));\n                    log_index += sim_res.logs.len();\n                    call_res.push(sim_res);\n                }\n\n                let transactions_envelopes: Vec<AnyTxEnvelope> = transactions\n                .iter()\n                .map(|tx| AnyTxEnvelope::from(tx.clone()))\n                .collect();\n                let header = Header {\n                    logs_bloom: logs_bloom(logs.iter()),\n                    transactions_root: calculate_transaction_root(&transactions_envelopes),\n                    receipts_root: calculate_receipt_root(&transactions_envelopes),\n                    parent_hash: Default::default(),\n                    beneficiary: block_env.beneficiary,\n                    state_root: Default::default(),\n                    difficulty: Default::default(),\n                    number: block_env.number.saturating_to(),\n                    gas_limit: block_env.gas_limit,\n                    gas_used,\n                    timestamp: block_env.timestamp.saturating_to(),\n                    extra_data: Default::default(),\n                    mix_hash: Default::default(),\n                    nonce: Default::default(),\n                    base_fee_per_gas: Some(block_env.basefee),\n                    withdrawals_root: None,\n                    blob_gas_used: None,\n                    excess_blob_gas: None,\n                    parent_beacon_block_root: None,\n                    requests_hash: None,\n                    ..Default::default()\n                };\n                let mut block = alloy_rpc_types::Block {\n                    header: AnyRpcHeader {\n                        hash: header.hash_slow(),\n                        inner: header.into(),\n                        total_difficulty: None,\n                        size: None,\n                    },\n                    uncles: vec![],\n                    transactions: BlockTransactions::Full(transactions),\n                    withdrawals: None,\n                };\n\n                if !return_full_transactions {\n                    block.transactions.convert_to_hashes();\n                }\n\n                for res in &mut call_res {\n                    res.logs.iter_mut().for_each(|log| {\n                        log.block_hash = Some(block.header.hash);\n                    });\n                }\n\n                let simulated_block = SimulatedBlock {\n                    inner: AnyRpcBlock::new(WithOtherFields::new(block)),\n                    calls: call_res,\n                };\n\n                // update block env\n                block_env.number += U256::from(1);\n                block_env.timestamp += U256::from(12);\n                block_env.basefee = simulated_block\n                    .inner\n                    .header\n                    .next_block_base_fee(self.fees.base_fee_params())\n                    .unwrap_or_default();\n\n                block_res.push(simulated_block);\n            }\n\n            Ok(block_res)\n        })\n        .await?\n    }\n\n    /// returns all receipts for the given transactions\n    fn get_receipts(\n        &self,\n        tx_hashes: impl IntoIterator<Item = TxHash>,\n    ) -> Vec<FoundryReceiptEnvelope> {\n        let storage = self.blockchain.storage.read();\n        let mut receipts = vec![];\n\n        for hash in tx_hashes {\n            if let Some(tx) = storage.transactions.get(&hash) {\n                receipts.push(tx.receipt.clone());\n            }\n        }\n\n        receipts\n    }\n\n    /// Returns the traces for the given transaction\n    pub async fn debug_trace_transaction(\n        &self,\n        hash: B256,\n        opts: GethDebugTracingOptions,\n    ) -> Result<GethTrace, BlockchainError> {\n        #[cfg(feature = \"js-tracer\")]\n        if let Some(tracer_type) = opts.tracer.as_ref()\n            && tracer_type.is_js()\n        {\n            return self\n                .trace_tx_with_js_tracer(hash, tracer_type.as_str().to_string(), opts.clone())\n                .await;\n        }\n\n        if let Some(trace) = self.mined_geth_trace_transaction(hash, opts.clone()).await {\n            return trace;\n        }\n\n        if let Some(fork) = self.get_fork() {\n            return Ok(fork.debug_trace_transaction(hash, opts).await?);\n        }\n\n        Ok(GethTrace::Default(Default::default()))\n    }\n\n    fn geth_trace(\n        &self,\n        tx: &MinedTransaction<FoundryNetwork>,\n        opts: GethDebugTracingOptions,\n    ) -> Result<GethTrace, BlockchainError> {\n        let GethDebugTracingOptions { config, tracer, tracer_config, .. } = opts;\n\n        if let Some(tracer) = tracer {\n            match tracer {\n                GethDebugTracerType::BuiltInTracer(tracer) => match tracer {\n                    GethDebugBuiltInTracerType::FourByteTracer => {\n                        let inspector = FourByteInspector::default();\n                        let res = self.replay_tx_with_inspector(\n                            tx.info.transaction_hash,\n                            inspector,\n                            |_, _, inspector, _, _| FourByteFrame::from(inspector).into(),\n                        )?;\n                        return Ok(res);\n                    }\n                    GethDebugBuiltInTracerType::CallTracer => {\n                        return match tracer_config.into_call_config() {\n                            Ok(call_config) => {\n                                let inspector = TracingInspector::new(\n                                    TracingInspectorConfig::from_geth_call_config(&call_config),\n                                );\n                                let frame = self.replay_tx_with_inspector(\n                                    tx.info.transaction_hash,\n                                    inspector,\n                                    |_, _, inspector, _, _| {\n                                        inspector\n                                            .geth_builder()\n                                            .geth_call_traces(\n                                                call_config,\n                                                tx.receipt.cumulative_gas_used(),\n                                            )\n                                            .into()\n                                    },\n                                )?;\n                                Ok(frame)\n                            }\n                            Err(e) => Err(RpcError::invalid_params(e.to_string()).into()),\n                        };\n                    }\n                    GethDebugBuiltInTracerType::PreStateTracer => {\n                        return match tracer_config.into_pre_state_config() {\n                            Ok(pre_state_config) => {\n                                let inspector = TracingInspector::new(\n                                    TracingInspectorConfig::from_geth_prestate_config(\n                                        &pre_state_config,\n                                    ),\n                                );\n                                let frame = self.replay_tx_with_inspector(\n                                    tx.info.transaction_hash,\n                                    inspector,\n                                    |state, db, inspector, _, _| {\n                                        inspector.geth_builder().geth_prestate_traces(\n                                            &state,\n                                            &pre_state_config,\n                                            db,\n                                        )\n                                    },\n                                )??;\n                                Ok(frame.into())\n                            }\n                            Err(e) => Err(RpcError::invalid_params(e.to_string()).into()),\n                        };\n                    }\n                    GethDebugBuiltInTracerType::NoopTracer\n                    | GethDebugBuiltInTracerType::MuxTracer\n                    | GethDebugBuiltInTracerType::Erc7562Tracer\n                    | GethDebugBuiltInTracerType::FlatCallTracer => {}\n                },\n                GethDebugTracerType::JsTracer(_code) => {}\n            }\n\n            return Ok(NoopFrame::default().into());\n        }\n\n        // default structlog tracer\n        Ok(GethTraceBuilder::new(tx.info.traces.clone())\n            .geth_traces(\n                tx.receipt.cumulative_gas_used(),\n                tx.info.out.clone().unwrap_or_default(),\n                config,\n            )\n            .into())\n    }\n\n    async fn mined_geth_trace_transaction(\n        &self,\n        hash: B256,\n        opts: GethDebugTracingOptions,\n    ) -> Option<Result<GethTrace, BlockchainError>> {\n        self.blockchain.storage.read().transactions.get(&hash).map(|tx| self.geth_trace(tx, opts))\n    }\n\n    pub async fn transaction_receipt(\n        &self,\n        hash: B256,\n    ) -> Result<Option<FoundryTxReceipt>, BlockchainError> {\n        if let Some(receipt) = self.mined_transaction_receipt(hash) {\n            return Ok(Some(receipt.inner));\n        }\n\n        if let Some(fork) = self.get_fork() {\n            let receipt = fork.transaction_receipt(hash).await?;\n            let number = self.convert_block_number(\n                receipt.clone().and_then(|r| r.block_number()).map(BlockNumber::from),\n            );\n\n            if fork.predates_fork_inclusive(number) {\n                return Ok(receipt);\n            }\n        }\n\n        Ok(None)\n    }\n\n    /// Returns all transaction receipts of the block\n    pub fn mined_block_receipts(&self, id: impl Into<BlockId>) -> Option<Vec<FoundryTxReceipt>> {\n        let mut receipts = Vec::new();\n        let block = self.get_block(id)?;\n\n        for transaction in block.body.transactions {\n            let receipt = self.mined_transaction_receipt(transaction.hash())?;\n            receipts.push(receipt.inner);\n        }\n\n        Some(receipts)\n    }\n\n    /// Returns the transaction receipt for the given hash\n    pub(crate) fn mined_transaction_receipt(\n        &self,\n        hash: B256,\n    ) -> Option<MinedTransactionReceipt<FoundryNetwork>> {\n        let MinedTransaction { info, receipt: tx_receipt, block_hash, .. } =\n            self.blockchain.get_transaction_by_hash(&hash)?;\n\n        let index = info.transaction_index as usize;\n        let block = self.blockchain.get_block_by_hash(&block_hash)?;\n        let transaction = block.body.transactions[index].clone();\n\n        // Cancun specific\n        let excess_blob_gas = block.header.excess_blob_gas();\n        let blob_gas_price =\n            alloy_eips::eip4844::calc_blob_gasprice(excess_blob_gas.unwrap_or_default());\n        let blob_gas_used = transaction.blob_gas_used();\n\n        let effective_gas_price = transaction.effective_gas_price(block.header.base_fee_per_gas());\n\n        let receipts = self.get_receipts(block.body.transactions.iter().map(|tx| tx.hash()));\n        let next_log_index = receipts[..index].iter().map(|r| r.logs().len()).sum::<usize>();\n\n        let tx_receipt = tx_receipt.convert_logs_rpc(\n            BlockNumHash::new(block.header.number(), block_hash),\n            block.header.timestamp(),\n            info.transaction_hash,\n            info.transaction_index,\n            next_log_index,\n        );\n\n        let receipt = TransactionReceipt {\n            inner: tx_receipt,\n            transaction_hash: info.transaction_hash,\n            transaction_index: Some(info.transaction_index),\n            block_number: Some(block.header.number()),\n            gas_used: info.gas_used,\n            contract_address: info.contract_address,\n            effective_gas_price,\n            block_hash: Some(block_hash),\n            from: info.from,\n            to: info.to,\n            blob_gas_price: Some(blob_gas_price),\n            blob_gas_used,\n        };\n\n        // Include timestamp in receipt to avoid extra block lookups (e.g., in Otterscan API)\n        let inner = FoundryTxReceipt::with_timestamp(receipt, block.header.timestamp());\n        Some(MinedTransactionReceipt { inner, out: info.out })\n    }\n\n    /// Returns the blocks receipts for the given number\n    pub async fn block_receipts(\n        &self,\n        number: BlockId,\n    ) -> Result<Option<Vec<FoundryTxReceipt>>, BlockchainError> {\n        if let Some(receipts) = self.mined_block_receipts(number) {\n            return Ok(Some(receipts));\n        }\n\n        if let Some(fork) = self.get_fork() {\n            let number = match self.ensure_block_number(Some(number)).await {\n                Err(_) => return Ok(None),\n                Ok(n) => n,\n            };\n\n            if fork.predates_fork_inclusive(number) {\n                let receipts = fork.block_receipts(number).await?;\n\n                return Ok(receipts);\n            }\n        }\n\n        Ok(None)\n    }\n\n    pub fn get_blob_by_tx_hash(&self, hash: B256) -> Result<Option<Vec<alloy_consensus::Blob>>> {\n        // Try to get the mined transaction by hash\n        if let Some(tx) = self.mined_transaction_by_hash(hash)\n            && let Ok(typed_tx) = FoundryTxEnvelope::try_from(tx)\n            && let Some(sidecar) = typed_tx.sidecar()\n        {\n            return Ok(Some(sidecar.sidecar.blobs().to_vec()));\n        }\n\n        Ok(None)\n    }\n}\n\n/// Get max nonce from transaction pool by address.\nfn get_pool_transactions_nonce(\n    pool_transactions: &[Arc<PoolTransaction<FoundryTxEnvelope>>],\n    address: Address,\n) -> Option<u64> {\n    if let Some(highest_nonce) = pool_transactions\n        .iter()\n        .filter(|tx| *tx.pending_transaction.sender() == address)\n        .map(|tx| tx.pending_transaction.nonce())\n        .max()\n    {\n        let tx_count = highest_nonce.saturating_add(1);\n        return Some(tx_count);\n    }\n    None\n}\n\n#[async_trait::async_trait]\nimpl TransactionValidator<FoundryTxEnvelope> for Backend<FoundryNetwork> {\n    async fn validate_pool_transaction(\n        &self,\n        tx: &PendingTransaction<FoundryTxEnvelope>,\n    ) -> Result<(), BlockchainError> {\n        let address = *tx.sender();\n        let account = self.get_account(address).await?;\n        let env = self.next_env();\n        Ok(self.validate_pool_transaction_for(tx, &account, &env)?)\n    }\n\n    fn validate_pool_transaction_for(\n        &self,\n        pending: &PendingTransaction<FoundryTxEnvelope>,\n        account: &AccountInfo,\n        env: &Env,\n    ) -> Result<(), InvalidTransactionError> {\n        let tx = &pending.transaction;\n\n        if let Some(tx_chain_id) = tx.chain_id() {\n            let chain_id = self.chain_id();\n            if chain_id.to::<u64>() != tx_chain_id {\n                if let FoundryTxEnvelope::Legacy(tx) = tx.as_ref() {\n                    // <https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md>\n                    if env.evm_env.cfg_env.spec >= SpecId::SPURIOUS_DRAGON\n                        && tx.chain_id().is_none()\n                    {\n                        warn!(target: \"backend\", ?chain_id, ?tx_chain_id, \"incompatible EIP155-based V\");\n                        return Err(InvalidTransactionError::IncompatibleEIP155);\n                    }\n                } else {\n                    warn!(target: \"backend\", ?chain_id, ?tx_chain_id, \"invalid chain id\");\n                    return Err(InvalidTransactionError::InvalidChainId);\n                }\n            }\n        }\n\n        // Nonce validation\n        let is_deposit_tx = matches!(pending.transaction.as_ref(), FoundryTxEnvelope::Deposit(_));\n        let nonce = tx.nonce();\n        if nonce < account.nonce && !is_deposit_tx {\n            warn!(target: \"backend\", \"[{:?}] nonce too low\", tx.hash());\n            return Err(InvalidTransactionError::NonceTooLow);\n        }\n\n        // EIP-4844 structural validation\n        if env.evm_env.cfg_env.spec >= SpecId::CANCUN && tx.is_eip4844() {\n            // Heavy (blob validation) checks\n            let blob_tx = match tx.as_ref() {\n                FoundryTxEnvelope::Eip4844(tx) => tx.tx(),\n                _ => unreachable!(),\n            };\n\n            let blob_count = blob_tx.tx().blob_versioned_hashes.len();\n\n            // Ensure there are blob hashes.\n            if blob_count == 0 {\n                return Err(InvalidTransactionError::NoBlobHashes);\n            }\n\n            // Ensure the tx does not exceed the max blobs per transaction.\n            let max_blobs_per_tx = self.blob_params().max_blobs_per_tx as usize;\n            if blob_count > max_blobs_per_tx {\n                return Err(InvalidTransactionError::TooManyBlobs(blob_count, max_blobs_per_tx));\n            }\n\n            // Check for any blob validation errors if not impersonating.\n            if !self.skip_blob_validation(Some(*pending.sender()))\n                && let Err(err) = blob_tx.validate(EnvKzgSettings::default().get())\n            {\n                return Err(InvalidTransactionError::BlobTransactionValidationError(err));\n            }\n        }\n\n        // EIP-3860 initcode size validation, respects --code-size-limit / --disable-code-size-limit\n        if env.evm_env.cfg_env.spec >= SpecId::SHANGHAI && tx.kind() == TxKind::Create {\n            let max_initcode_size = env\n                .evm_env\n                .cfg_env\n                .limit_contract_code_size\n                .map(|limit| limit.saturating_mul(2))\n                .unwrap_or(revm::primitives::eip3860::MAX_INITCODE_SIZE);\n            if tx.input().len() > max_initcode_size {\n                return Err(InvalidTransactionError::MaxInitCodeSizeExceeded);\n            }\n        }\n\n        // Balance and fee related checks\n        if !self.disable_pool_balance_checks {\n            // Gas limit validation\n            if tx.gas_limit() < MIN_TRANSACTION_GAS as u64 {\n                warn!(target: \"backend\", \"[{:?}] gas too low\", tx.hash());\n                return Err(InvalidTransactionError::GasTooLow);\n            }\n\n            // Check tx gas limit against block gas limit, if block gas limit is set.\n            if !env.evm_env.cfg_env.disable_block_gas_limit\n                && tx.gas_limit() > env.evm_env.block_env.gas_limit\n            {\n                warn!(target: \"backend\", \"[{:?}] gas too high\", tx.hash());\n                return Err(InvalidTransactionError::GasTooHigh(ErrDetail {\n                    detail: String::from(\"tx.gas_limit > env.block.gas_limit\"),\n                }));\n            }\n\n            // Check tx gas limit against tx gas limit cap (Osaka hard fork and later).\n            if env.evm_env.cfg_env.tx_gas_limit_cap.is_none()\n                && tx.gas_limit() > env.evm_env.cfg_env().tx_gas_limit_cap()\n            {\n                warn!(target: \"backend\", \"[{:?}] gas too high\", tx.hash());\n                return Err(InvalidTransactionError::GasTooHigh(ErrDetail {\n                    detail: String::from(\"tx.gas_limit > env.cfg.tx_gas_limit_cap\"),\n                }));\n            }\n\n            // EIP-1559 fee validation (London hard fork and later).\n            if env.evm_env.cfg_env.spec >= SpecId::LONDON {\n                if tx.max_fee_per_gas() < env.evm_env.block_env.basefee.into() && !is_deposit_tx {\n                    warn!(target: \"backend\", \"max fee per gas={}, too low, block basefee={}\", tx.max_fee_per_gas(), env.evm_env.block_env.basefee);\n                    return Err(InvalidTransactionError::FeeCapTooLow);\n                }\n\n                if let (Some(max_priority_fee_per_gas), max_fee_per_gas) =\n                    (tx.as_ref().max_priority_fee_per_gas(), tx.as_ref().max_fee_per_gas())\n                    && max_priority_fee_per_gas > max_fee_per_gas\n                {\n                    warn!(target: \"backend\", \"max priority fee per gas={}, too high, max fee per gas={}\", max_priority_fee_per_gas, max_fee_per_gas);\n                    return Err(InvalidTransactionError::TipAboveFeeCap);\n                }\n            }\n\n            // EIP-4844 blob fee validation\n            if env.evm_env.cfg_env.spec >= SpecId::CANCUN\n                && tx.is_eip4844()\n                && let Some(max_fee_per_blob_gas) = tx.max_fee_per_blob_gas()\n                && let Some(blob_gas_and_price) = &env.evm_env.block_env.blob_excess_gas_and_price\n                && max_fee_per_blob_gas < blob_gas_and_price.blob_gasprice\n            {\n                warn!(target: \"backend\", \"max fee per blob gas={}, too low, block blob gas price={}\", max_fee_per_blob_gas, blob_gas_and_price.blob_gasprice);\n                return Err(InvalidTransactionError::BlobFeeCapTooLow(\n                    max_fee_per_blob_gas,\n                    blob_gas_and_price.blob_gasprice,\n                ));\n            }\n\n            let max_cost =\n                (tx.gas_limit() as u128).saturating_mul(tx.max_fee_per_gas()).saturating_add(\n                    tx.blob_gas_used()\n                        .map(|g| g as u128)\n                        .unwrap_or(0)\n                        .mul(tx.max_fee_per_blob_gas().unwrap_or(0)),\n                );\n            let value = tx.value();\n            match tx.as_ref() {\n                FoundryTxEnvelope::Deposit(deposit_tx) => {\n                    // Deposit transactions\n                    // https://specs.optimism.io/protocol/deposits.html#execution\n                    // 1. no gas cost check required since already have prepaid gas from L1\n                    // 2. increment account balance by deposited amount before checking for\n                    //    sufficient funds `tx.value <= existing account value + deposited value`\n                    if value > account.balance + U256::from(deposit_tx.mint) {\n                        warn!(target: \"backend\", \"[{:?}] insufficient balance={}, required={} account={:?}\", tx.hash(), account.balance + U256::from(deposit_tx.mint), value, *pending.sender());\n                        return Err(InvalidTransactionError::InsufficientFunds);\n                    }\n                }\n                _ => {\n                    // check sufficient funds: `gas * price + value`\n                    let req_funds =\n                        max_cost.checked_add(value.saturating_to()).ok_or_else(|| {\n                            warn!(target: \"backend\", \"[{:?}] cost too high\", tx.hash());\n                            InvalidTransactionError::InsufficientFunds\n                        })?;\n                    if account.balance < U256::from(req_funds) {\n                        warn!(target: \"backend\", \"[{:?}] insufficient balance={}, required={} account={:?}\", tx.hash(), account.balance, req_funds, *pending.sender());\n                        return Err(InvalidTransactionError::InsufficientFunds);\n                    }\n                }\n            }\n        }\n        Ok(())\n    }\n\n    fn validate_for(\n        &self,\n        tx: &PendingTransaction<FoundryTxEnvelope>,\n        account: &AccountInfo,\n        env: &Env,\n    ) -> Result<(), InvalidTransactionError> {\n        self.validate_pool_transaction_for(tx, account, env)?;\n        if tx.nonce() > account.nonce {\n            return Err(InvalidTransactionError::NonceTooHigh);\n        }\n        Ok(())\n    }\n}\n\n/// Creates a `AnyRpcTransaction` as it's expected for the `eth` RPC api from storage data\npub fn transaction_build(\n    tx_hash: Option<B256>,\n    eth_transaction: MaybeImpersonatedTransaction<FoundryTxEnvelope>,\n    block: Option<&Block>,\n    info: Option<TransactionInfo>,\n    base_fee: Option<u64>,\n) -> AnyRpcTransaction {\n    if let FoundryTxEnvelope::Deposit(deposit_tx) = eth_transaction.as_ref() {\n        let dep_tx = deposit_tx;\n\n        let ser = serde_json::to_value(dep_tx).expect(\"could not serialize TxDeposit\");\n        let maybe_deposit_fields = OtherFields::try_from(ser);\n\n        match maybe_deposit_fields {\n            Ok(mut fields) => {\n                // Add zeroed signature fields for backwards compatibility\n                // https://specs.optimism.io/protocol/deposits.html#the-deposited-transaction-type\n                fields.insert(\"v\".to_string(), serde_json::to_value(\"0x0\").unwrap());\n                fields.insert(\"r\".to_string(), serde_json::to_value(B256::ZERO).unwrap());\n                fields.insert(String::from(\"s\"), serde_json::to_value(B256::ZERO).unwrap());\n                fields.insert(String::from(\"nonce\"), serde_json::to_value(\"0x0\").unwrap());\n\n                let inner = UnknownTypedTransaction {\n                    ty: AnyTxType(DEPOSIT_TX_TYPE_ID),\n                    fields,\n                    memo: Default::default(),\n                };\n\n                let envelope = AnyTxEnvelope::Unknown(UnknownTxEnvelope {\n                    hash: eth_transaction.hash(),\n                    inner,\n                });\n\n                let tx = Transaction {\n                    inner: Recovered::new_unchecked(envelope, deposit_tx.from),\n                    block_hash: block\n                        .as_ref()\n                        .map(|block| B256::from(keccak256(alloy_rlp::encode(&block.header)))),\n                    block_number: block.as_ref().map(|block| block.header.number()),\n                    transaction_index: info.as_ref().map(|info| info.transaction_index),\n                    effective_gas_price: None,\n                    block_timestamp: block.as_ref().map(|block| block.header.timestamp()),\n                };\n\n                return AnyRpcTransaction::from(WithOtherFields::new(tx));\n            }\n            Err(_) => {\n                error!(target: \"backend\", \"failed to serialize deposit transaction\");\n            }\n        }\n    }\n\n    let from = eth_transaction.recover().unwrap_or_default();\n    let effective_gas_price = eth_transaction.effective_gas_price(base_fee);\n\n    // if a specific hash was provided we update the transaction's hash\n    // This is important for impersonated transactions since they all use the\n    // `BYPASS_SIGNATURE` which would result in different hashes\n    // Note: for impersonated transactions this only concerns pending transactions because\n    // there's no `info` yet.\n    let hash = tx_hash.unwrap_or_else(|| eth_transaction.hash());\n\n    // TODO: this panics for non-standard tx types (e.g. Tempo) that aren't handled above\n    // (pre-existing issue from the original `into_rpc_transaction`).\n    let eth_envelope = FoundryTxEnvelope::from(eth_transaction)\n        .try_into_eth()\n        .expect(\"deposit transactions are handled above\");\n\n    let envelope = match eth_envelope {\n        TxEnvelope::Legacy(signed_tx) => {\n            let (t, sig, _) = signed_tx.into_parts();\n            let new_signed = Signed::new_unchecked(t, sig, hash);\n            AnyTxEnvelope::Ethereum(TxEnvelope::Legacy(new_signed))\n        }\n        TxEnvelope::Eip1559(signed_tx) => {\n            let (t, sig, _) = signed_tx.into_parts();\n            let new_signed = Signed::new_unchecked(t, sig, hash);\n            AnyTxEnvelope::Ethereum(TxEnvelope::Eip1559(new_signed))\n        }\n        TxEnvelope::Eip2930(signed_tx) => {\n            let (t, sig, _) = signed_tx.into_parts();\n            let new_signed = Signed::new_unchecked(t, sig, hash);\n            AnyTxEnvelope::Ethereum(TxEnvelope::Eip2930(new_signed))\n        }\n        TxEnvelope::Eip4844(signed_tx) => {\n            let (t, sig, _) = signed_tx.into_parts();\n            let new_signed = Signed::new_unchecked(t, sig, hash);\n            AnyTxEnvelope::Ethereum(TxEnvelope::Eip4844(new_signed))\n        }\n        TxEnvelope::Eip7702(signed_tx) => {\n            let (t, sig, _) = signed_tx.into_parts();\n            let new_signed = Signed::new_unchecked(t, sig, hash);\n            AnyTxEnvelope::Ethereum(TxEnvelope::Eip7702(new_signed))\n        }\n    };\n\n    let tx = Transaction {\n        inner: Recovered::new_unchecked(envelope, from),\n        block_hash: block.as_ref().map(|block| block.header.hash_slow()),\n        block_number: block.as_ref().map(|block| block.header.number()),\n        transaction_index: info.as_ref().map(|info| info.transaction_index),\n        // deprecated\n        effective_gas_price: Some(effective_gas_price),\n        block_timestamp: block.as_ref().map(|block| block.header.timestamp()),\n    };\n    AnyRpcTransaction::from(WithOtherFields::new(tx))\n}\n\n/// Prove a storage key's existence or nonexistence in the account's storage trie.\n///\n/// `storage_key` is the hash of the desired storage key, meaning\n/// this will only work correctly under a secure trie.\n/// `storage_key` == keccak(key)\npub fn prove_storage(storage: &HashMap<U256, U256>, keys: &[B256]) -> (B256, Vec<Vec<Bytes>>) {\n    let keys: Vec<_> = keys.iter().map(|key| Nibbles::unpack(keccak256(key))).collect();\n\n    let mut builder = HashBuilder::default().with_proof_retainer(ProofRetainer::new(keys.clone()));\n\n    for (key, value) in trie_storage(storage) {\n        builder.add_leaf(key, &value);\n    }\n\n    let root = builder.root();\n\n    let mut proofs = Vec::new();\n    let all_proof_nodes = builder.take_proof_nodes();\n\n    for proof_key in keys {\n        // Iterate over all proof nodes and find the matching ones.\n        // The filtered results are guaranteed to be in order.\n        let matching_proof_nodes =\n            all_proof_nodes.matching_nodes_sorted(&proof_key).into_iter().map(|(_, node)| node);\n        proofs.push(matching_proof_nodes.collect());\n    }\n\n    (root, proofs)\n}\n\npub fn is_arbitrum(chain_id: u64) -> bool {\n    if let Ok(chain) = NamedChain::try_from(chain_id) {\n        return chain.is_arbitrum();\n    }\n    false\n}\n\npub fn op_haltreason_to_instruction_result(op_reason: OpHaltReason) -> InstructionResult {\n    match op_reason {\n        OpHaltReason::Base(eth_h) => eth_h.into(),\n        OpHaltReason::FailedDeposit => InstructionResult::Stop,\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use crate::{NodeConfig, spawn};\n\n    #[tokio::test]\n    async fn test_deterministic_block_mining() {\n        // Test that mine_block produces deterministic block hashes with same initial conditions\n        let genesis_timestamp = 1743944919u64;\n\n        // Create two identical backends\n        let config_a = NodeConfig::test().with_genesis_timestamp(genesis_timestamp.into());\n        let config_b = NodeConfig::test().with_genesis_timestamp(genesis_timestamp.into());\n\n        let (api_a, _handle_a) = spawn(config_a).await;\n        let (api_b, _handle_b) = spawn(config_b).await;\n\n        // Mine empty blocks (no transactions) on both backends\n        let outcome_a_1 = api_a.backend.mine_block(vec![]).await;\n        let outcome_b_1 = api_b.backend.mine_block(vec![]).await;\n\n        // Both should mine the same block number\n        assert_eq!(outcome_a_1.block_number, outcome_b_1.block_number);\n\n        // Get the actual blocks to compare hashes\n        let block_a_1 =\n            api_a.block_by_number(outcome_a_1.block_number.into()).await.unwrap().unwrap();\n        let block_b_1 =\n            api_b.block_by_number(outcome_b_1.block_number.into()).await.unwrap().unwrap();\n\n        // The block hashes should be identical\n        assert_eq!(\n            block_a_1.header.hash, block_b_1.header.hash,\n            \"Block hashes should be deterministic. Got {} vs {}\",\n            block_a_1.header.hash, block_b_1.header.hash\n        );\n\n        // Mine another block to ensure it remains deterministic\n        let outcome_a_2 = api_a.backend.mine_block(vec![]).await;\n        let outcome_b_2 = api_b.backend.mine_block(vec![]).await;\n\n        let block_a_2 =\n            api_a.block_by_number(outcome_a_2.block_number.into()).await.unwrap().unwrap();\n        let block_b_2 =\n            api_b.block_by_number(outcome_b_2.block_number.into()).await.unwrap().unwrap();\n\n        assert_eq!(\n            block_a_2.header.hash, block_b_2.header.hash,\n            \"Second block hashes should also be deterministic. Got {} vs {}\",\n            block_a_2.header.hash, block_b_2.header.hash\n        );\n\n        // Ensure the blocks are different (sanity check)\n        assert_ne!(\n            block_a_1.header.hash, block_a_2.header.hash,\n            \"Different blocks should have different hashes\"\n        );\n    }\n}\n"
  },
  {
    "path": "crates/anvil/src/eth/backend/mem/state.rs",
    "content": "//! Support for generating the state root for memdb storage\n\nuse alloy_primitives::{\n    B256, U256, keccak256,\n    map::{AddressMap, HashMap},\n};\nuse alloy_rlp::Encodable;\nuse alloy_trie::{HashBuilder, Nibbles};\nuse revm::{database::DbAccount, state::AccountInfo};\n\npub fn build_root(values: impl IntoIterator<Item = (Nibbles, Vec<u8>)>) -> B256 {\n    let mut builder = HashBuilder::default();\n    for (key, value) in values {\n        builder.add_leaf(key, value.as_ref());\n    }\n    builder.root()\n}\n\n/// Builds state root from the given accounts\npub fn state_root(accounts: &AddressMap<DbAccount>) -> B256 {\n    build_root(trie_accounts(accounts))\n}\n\n/// Builds storage root from the given storage\npub fn storage_root(storage: &HashMap<U256, U256>) -> B256 {\n    build_root(trie_storage(storage))\n}\n\n/// Builds iterator over stored key-value pairs ready for storage trie root calculation.\npub fn trie_storage(storage: &HashMap<U256, U256>) -> Vec<(Nibbles, Vec<u8>)> {\n    let mut storage = storage\n        .iter()\n        .map(|(key, value)| {\n            let data = alloy_rlp::encode(value);\n            (Nibbles::unpack(keccak256(key.to_be_bytes::<32>())), data)\n        })\n        .collect::<Vec<_>>();\n    storage.sort_by_key(|(key, _)| *key);\n\n    storage\n}\n\n/// Builds iterator over stored key-value pairs ready for account trie root calculation.\npub fn trie_accounts(accounts: &AddressMap<DbAccount>) -> Vec<(Nibbles, Vec<u8>)> {\n    let mut accounts: Vec<(Nibbles, Vec<u8>)> = accounts\n        .iter()\n        .map(|(address, account)| {\n            let data = trie_account_rlp(&account.info, &account.storage);\n            (Nibbles::unpack(keccak256(*address)), data)\n        })\n        .collect();\n    accounts.sort_by_key(|(key, _)| *key);\n\n    accounts\n}\n\n/// Returns the RLP for this account.\npub fn trie_account_rlp(info: &AccountInfo, storage: &HashMap<U256, U256>) -> Vec<u8> {\n    let mut out: Vec<u8> = Vec::new();\n    let list: [&dyn Encodable; 4] =\n        [&info.nonce, &info.balance, &storage_root(storage), &info.code_hash];\n\n    alloy_rlp::encode_list::<_, dyn Encodable>(&list, &mut out);\n\n    out\n}\n"
  },
  {
    "path": "crates/anvil/src/eth/backend/mem/storage.rs",
    "content": "//! In-memory blockchain storage\nuse crate::eth::{\n    backend::{\n        db::{\n            MaybeFullDatabase, SerializableBlock, SerializableHistoricalStates,\n            SerializableTransaction, StateDb,\n        },\n        env::Env,\n        mem::cache::DiskStateCache,\n    },\n    pool::transactions::PoolTransaction,\n};\nuse alloy_consensus::{BlockHeader, Header, constants::EMPTY_WITHDRAWALS};\nuse alloy_eips::eip7685::EMPTY_REQUESTS_HASH;\nuse alloy_network::Network;\nuse alloy_primitives::{\n    B256, Bytes, U256,\n    map::{B256HashMap, HashMap},\n};\nuse alloy_rpc_types::{\n    BlockId, BlockNumberOrTag, TransactionInfo as RethTransactionInfo,\n    trace::{\n        otterscan::{InternalOperation, OperationType},\n        parity::LocalizedTransactionTrace,\n    },\n};\nuse anvil_core::eth::{\n    block::{Block, create_block},\n    transaction::{MaybeImpersonatedTransaction, TransactionInfo},\n};\nuse foundry_evm::{\n    backend::MemDb,\n    traces::{CallKind, ParityTraceBuilder, TracingInspectorConfig},\n};\nuse foundry_primitives::{FoundryNetwork, FoundryTxEnvelope};\nuse parking_lot::RwLock;\nuse revm::{context::Block as RevmBlock, primitives::hardfork::SpecId};\nuse std::{collections::VecDeque, fmt, path::PathBuf, sync::Arc, time::Duration};\n// use yansi::Paint;\n\n// === various limits in number of blocks ===\n\npub const DEFAULT_HISTORY_LIMIT: usize = 500;\nconst MIN_HISTORY_LIMIT: usize = 10;\n// 1hr of up-time at lowest 1s interval\nconst MAX_ON_DISK_HISTORY_LIMIT: usize = 3_600;\n\n/// Represents the complete state of single block\npub struct InMemoryBlockStates {\n    /// The states at a certain block\n    states: B256HashMap<StateDb>,\n    /// states which data is moved to disk\n    on_disk_states: B256HashMap<StateDb>,\n    /// How many states to store at most\n    in_memory_limit: usize,\n    /// minimum amount of states we keep in memory\n    min_in_memory_limit: usize,\n    /// maximum amount of states we keep on disk\n    ///\n    /// Limiting the states will prevent disk blow up, especially in interval mining mode\n    max_on_disk_limit: usize,\n    /// the oldest states written to disk\n    oldest_on_disk: VecDeque<B256>,\n    /// all states present, used to enforce `in_memory_limit`\n    present: VecDeque<B256>,\n    /// Stores old states on disk\n    disk_cache: DiskStateCache,\n}\n\nimpl InMemoryBlockStates {\n    /// Creates a new instance with limited slots\n    pub fn new(in_memory_limit: usize, on_disk_limit: usize) -> Self {\n        Self {\n            states: Default::default(),\n            on_disk_states: Default::default(),\n            in_memory_limit,\n            min_in_memory_limit: in_memory_limit.min(MIN_HISTORY_LIMIT),\n            max_on_disk_limit: on_disk_limit,\n            oldest_on_disk: Default::default(),\n            present: Default::default(),\n            disk_cache: Default::default(),\n        }\n    }\n\n    /// Configures no disk caching\n    pub fn memory_only(mut self) -> Self {\n        self.max_on_disk_limit = 0;\n        self\n    }\n\n    /// Configures the path on disk where the states will cached.\n    pub fn disk_path(mut self, path: PathBuf) -> Self {\n        self.disk_cache = self.disk_cache.with_path(path);\n        self\n    }\n\n    /// This modifies the `limit` what to keep stored in memory.\n    ///\n    /// This will ensure the new limit adjusts based on the block time.\n    /// The lowest blocktime is 1s which should increase the limit slightly\n    pub fn update_interval_mine_block_time(&mut self, block_time: Duration) {\n        let block_time = block_time.as_secs();\n        // for block times lower than 2s we increase the mem limit since we're mining _small_ blocks\n        // very fast\n        // this will gradually be decreased once the max limit was reached\n        if block_time <= 2 {\n            self.in_memory_limit = DEFAULT_HISTORY_LIMIT * 3;\n            self.enforce_limits();\n        }\n    }\n\n    /// Returns true if only memory caching is supported.\n    fn is_memory_only(&self) -> bool {\n        self.max_on_disk_limit == 0\n    }\n\n    /// Inserts a new (hash -> state) pair\n    ///\n    /// When the configured limit for the number of states that can be stored in memory is reached,\n    /// the oldest state is removed.\n    ///\n    /// Since we keep a snapshot of the entire state as history, the size of the state will increase\n    /// with the transactions processed. To counter this, we gradually decrease the cache limit with\n    /// the number of states/blocks until we reached the `min_limit`.\n    ///\n    /// When a state that was previously written to disk is requested, it is simply read from disk.\n    pub fn insert(&mut self, hash: B256, state: StateDb) {\n        if !self.is_memory_only() && self.present.len() >= self.in_memory_limit {\n            // once we hit the max limit we gradually decrease it\n            self.in_memory_limit =\n                self.in_memory_limit.saturating_sub(1).max(self.min_in_memory_limit);\n        }\n\n        self.enforce_limits();\n\n        self.states.insert(hash, state);\n        self.present.push_back(hash);\n    }\n\n    /// Enforces configured limits\n    fn enforce_limits(&mut self) {\n        // enforce memory limits\n        while self.present.len() >= self.in_memory_limit {\n            // evict the oldest block\n            if let Some((hash, mut state)) = self\n                .present\n                .pop_front()\n                .and_then(|hash| self.states.remove(&hash).map(|state| (hash, state)))\n            {\n                // only write to disk if supported\n                if !self.is_memory_only() {\n                    let state_snapshot = state.0.clear_into_state_snapshot();\n                    if self.disk_cache.write(hash, &state_snapshot) {\n                        // Write succeeded, move state to on-disk tracking\n                        self.on_disk_states.insert(hash, state);\n                        self.oldest_on_disk.push_back(hash);\n                    } else {\n                        // Write failed, restore state to memory to avoid data loss\n                        state.init_from_state_snapshot(state_snapshot);\n                        self.states.insert(hash, state);\n                        self.present.push_front(hash);\n                        // Increase limit temporarily to prevent infinite retry loop\n                        self.in_memory_limit = self.in_memory_limit.saturating_add(1);\n                        break;\n                    }\n                }\n            }\n        }\n\n        // enforce on disk limit and purge the oldest state cached on disk\n        while !self.is_memory_only() && self.oldest_on_disk.len() >= self.max_on_disk_limit {\n            // evict the oldest block\n            if let Some(hash) = self.oldest_on_disk.pop_front() {\n                self.on_disk_states.remove(&hash);\n                self.disk_cache.remove(hash);\n            }\n        }\n    }\n\n    /// Returns the in-memory state for the given `hash` if present\n    pub fn get_state(&self, hash: &B256) -> Option<&StateDb> {\n        self.states.get(hash)\n    }\n\n    /// Returns on-disk state for the given `hash` if present\n    pub fn get_on_disk_state(&mut self, hash: &B256) -> Option<&StateDb> {\n        if let Some(state) = self.on_disk_states.get_mut(hash)\n            && let Some(cached) = self.disk_cache.read(*hash)\n        {\n            state.init_from_state_snapshot(cached);\n            return Some(state);\n        }\n\n        None\n    }\n\n    /// Sets the maximum number of stats we keep in memory\n    pub fn set_cache_limit(&mut self, limit: usize) {\n        self.in_memory_limit = limit;\n    }\n\n    /// Clears all entries\n    pub fn clear(&mut self) {\n        self.states.clear();\n        self.on_disk_states.clear();\n        self.present.clear();\n        for on_disk in std::mem::take(&mut self.oldest_on_disk) {\n            self.disk_cache.remove(on_disk)\n        }\n    }\n\n    /// Serialize all states to a list of serializable historical states\n    pub fn serialized_states(&mut self) -> SerializableHistoricalStates {\n        // Get in-memory states\n        let mut states = self\n            .states\n            .iter_mut()\n            .map(|(hash, state)| (*hash, state.serialize_state()))\n            .collect::<Vec<_>>();\n\n        // Get on-disk state snapshots\n        self.on_disk_states.iter().for_each(|(hash, _)| {\n            if let Some(state_snapshot) = self.disk_cache.read(*hash) {\n                states.push((*hash, state_snapshot));\n            }\n        });\n\n        SerializableHistoricalStates::new(states)\n    }\n\n    /// Load states from serialized data\n    pub fn load_states(&mut self, states: SerializableHistoricalStates) {\n        for (hash, state_snapshot) in states {\n            let mut state_db = StateDb::new(MemDb::default());\n            state_db.init_from_state_snapshot(state_snapshot);\n            self.insert(hash, state_db);\n        }\n    }\n}\n\nimpl fmt::Debug for InMemoryBlockStates {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.debug_struct(\"InMemoryBlockStates\")\n            .field(\"in_memory_limit\", &self.in_memory_limit)\n            .field(\"min_in_memory_limit\", &self.min_in_memory_limit)\n            .field(\"max_on_disk_limit\", &self.max_on_disk_limit)\n            .field(\"oldest_on_disk\", &self.oldest_on_disk)\n            .field(\"present\", &self.present)\n            .finish_non_exhaustive()\n    }\n}\n\nimpl Default for InMemoryBlockStates {\n    fn default() -> Self {\n        // enough in memory to store `DEFAULT_HISTORY_LIMIT` blocks in memory\n        Self::new(DEFAULT_HISTORY_LIMIT, MAX_ON_DISK_HISTORY_LIMIT)\n    }\n}\n\n/// Stores the blockchain data (blocks, transactions)\n#[derive(Clone, Debug)]\npub struct BlockchainStorage<N: Network> {\n    /// all stored blocks (block hash -> block)\n    pub blocks: B256HashMap<Block>,\n    /// mapping from block number -> block hash\n    pub hashes: HashMap<u64, B256>,\n    /// The current best hash\n    pub best_hash: B256,\n    /// The current best block number\n    pub best_number: u64,\n    /// genesis hash of the chain\n    pub genesis_hash: B256,\n    /// Mapping from the transaction hash to a tuple containing the transaction as well as the\n    /// transaction receipt\n    pub transactions: B256HashMap<MinedTransaction<N>>,\n    /// The total difficulty of the chain until this block\n    pub total_difficulty: U256,\n}\n\nimpl<N: Network> BlockchainStorage<N> {\n    /// Creates a new storage with a genesis block\n    pub fn new(\n        env: &Env,\n        spec_id: SpecId,\n        base_fee: Option<u64>,\n        timestamp: u64,\n        genesis_number: u64,\n    ) -> Self {\n        let is_shanghai = spec_id >= SpecId::SHANGHAI;\n        let is_cancun = spec_id >= SpecId::CANCUN;\n        let is_prague = spec_id >= SpecId::PRAGUE;\n\n        // create a dummy genesis block\n        let header = Header {\n            timestamp,\n            base_fee_per_gas: base_fee,\n            gas_limit: env.evm_env.block_env.gas_limit,\n            beneficiary: env.evm_env.block_env.beneficiary,\n            difficulty: env.evm_env.block_env.difficulty,\n            blob_gas_used: env.evm_env.block_env.blob_excess_gas_and_price.as_ref().map(|_| 0),\n            excess_blob_gas: env.evm_env.block_env.blob_excess_gas(),\n            number: genesis_number,\n            parent_beacon_block_root: is_cancun.then_some(Default::default()),\n            withdrawals_root: is_shanghai.then_some(EMPTY_WITHDRAWALS),\n            requests_hash: is_prague.then_some(EMPTY_REQUESTS_HASH),\n            ..Default::default()\n        };\n        let block =\n            create_block(header, Vec::<MaybeImpersonatedTransaction<FoundryTxEnvelope>>::new());\n        let genesis_hash = block.header.hash_slow();\n        let best_hash = genesis_hash;\n        let best_number = genesis_number;\n\n        let mut blocks = B256HashMap::default();\n        blocks.insert(genesis_hash, block);\n\n        let mut hashes = HashMap::default();\n        hashes.insert(best_number, genesis_hash);\n        Self {\n            blocks,\n            hashes,\n            best_hash,\n            best_number,\n            genesis_hash,\n            transactions: Default::default(),\n            total_difficulty: Default::default(),\n        }\n    }\n\n    pub fn forked(block_number: u64, block_hash: B256, total_difficulty: U256) -> Self {\n        let mut hashes = HashMap::default();\n        hashes.insert(block_number, block_hash);\n\n        Self {\n            blocks: B256HashMap::default(),\n            hashes,\n            best_hash: block_hash,\n            best_number: block_number,\n            genesis_hash: Default::default(),\n            transactions: Default::default(),\n            total_difficulty,\n        }\n    }\n\n    /// Unwind the chain state back to the given block in storage.\n    ///\n    /// The block identified by `block_number` and `block_hash` is __non-inclusive__, i.e. it will\n    /// remain in the state.\n    pub fn unwind_to(&mut self, block_number: u64, block_hash: B256) -> Vec<Block> {\n        let mut removed = vec![];\n        let best_num: u64 = self.best_number;\n        for i in (block_number + 1)..=best_num {\n            if let Some(hash) = self.hashes.get(&i).copied() {\n                // First remove the block's transactions while the mappings still exist\n                self.remove_block_transactions_by_number(i);\n\n                // Now remove the block from storage (may already be empty of txs) and drop mapping\n                if let Some(block) = self.blocks.remove(&hash) {\n                    removed.push(block);\n                }\n                self.hashes.remove(&i);\n            }\n        }\n        self.best_hash = block_hash;\n        self.best_number = block_number;\n        removed\n    }\n\n    pub fn empty() -> Self {\n        Self {\n            blocks: Default::default(),\n            hashes: Default::default(),\n            best_hash: Default::default(),\n            best_number: Default::default(),\n            genesis_hash: Default::default(),\n            transactions: Default::default(),\n            total_difficulty: Default::default(),\n        }\n    }\n\n    /// Removes all stored transactions for the given block number\n    pub fn remove_block_transactions_by_number(&mut self, num: u64) {\n        if let Some(hash) = self.hashes.get(&num).copied() {\n            self.remove_block_transactions(hash);\n        }\n    }\n\n    /// Removes all stored transactions for the given block hash\n    pub fn remove_block_transactions(&mut self, block_hash: B256) {\n        if let Some(block) = self.blocks.get_mut(&block_hash) {\n            for tx in &block.body.transactions {\n                self.transactions.remove(&tx.hash());\n            }\n            block.body.transactions.clear();\n        }\n    }\n\n    /// Serialize all blocks in storage\n    pub fn serialized_blocks(&self) -> Vec<SerializableBlock> {\n        self.blocks.values().map(|block| block.clone().into()).collect()\n    }\n\n    /// Deserialize and add all blocks data to the backend storage\n    pub fn load_blocks(&mut self, serializable_blocks: Vec<SerializableBlock>) {\n        for serializable_block in &serializable_blocks {\n            let block: Block = serializable_block.clone().into();\n            let block_hash = block.header.hash_slow();\n            let block_number = block.header.number();\n            self.blocks.insert(block_hash, block);\n            self.hashes.insert(block_number, block_hash);\n\n            // Update genesis_hash if we are loading block 0, so that Finalized/Safe/Earliest\n            // block tag lookups return the correct hash.\n            // See: https://github.com/foundry-rs/foundry/issues/12645\n            if block_number == 0 {\n                self.genesis_hash = block_hash;\n            }\n        }\n    }\n\n    /// Returns the hash for [BlockNumberOrTag]\n    pub fn hash(&self, number: BlockNumberOrTag) -> Option<B256> {\n        let slots_in_an_epoch = 32;\n        match number {\n            BlockNumberOrTag::Latest => Some(self.best_hash),\n            BlockNumberOrTag::Earliest => Some(self.genesis_hash),\n            BlockNumberOrTag::Pending => None,\n            BlockNumberOrTag::Number(num) => self.hashes.get(&num).copied(),\n            BlockNumberOrTag::Safe => {\n                if self.best_number > (slots_in_an_epoch) {\n                    self.hashes.get(&(self.best_number - (slots_in_an_epoch))).copied()\n                } else {\n                    Some(self.genesis_hash) // treat the genesis block as safe \"by definition\"\n                }\n            }\n            BlockNumberOrTag::Finalized => {\n                if self.best_number > (slots_in_an_epoch * 2) {\n                    self.hashes.get(&(self.best_number - (slots_in_an_epoch * 2))).copied()\n                } else {\n                    Some(self.genesis_hash)\n                }\n            }\n        }\n    }\n}\n\nimpl BlockchainStorage<FoundryNetwork> {\n    pub fn serialized_transactions(&self) -> Vec<SerializableTransaction> {\n        self.transactions\n            .values()\n            .map(|tx: &MinedTransaction<FoundryNetwork>| tx.clone().into())\n            .collect()\n    }\n\n    /// Deserialize and add all transactions data to the backend storage\n    pub fn load_transactions(&mut self, serializable_transactions: Vec<SerializableTransaction>) {\n        for serializable_transaction in &serializable_transactions {\n            let transaction: MinedTransaction<FoundryNetwork> =\n                serializable_transaction.clone().into();\n            self.transactions.insert(transaction.info.transaction_hash, transaction);\n        }\n    }\n}\n\n/// A simple in-memory blockchain\n#[derive(Clone, Debug)]\npub struct Blockchain<N: Network> {\n    /// underlying storage that supports concurrent reads\n    pub storage: Arc<RwLock<BlockchainStorage<N>>>,\n}\n\nimpl<N: Network> Blockchain<N> {\n    /// Creates a new storage with a genesis block\n    pub fn new(\n        env: &Env,\n        spec_id: SpecId,\n        base_fee: Option<u64>,\n        timestamp: u64,\n        genesis_number: u64,\n    ) -> Self {\n        Self {\n            storage: Arc::new(RwLock::new(BlockchainStorage::new(\n                env,\n                spec_id,\n                base_fee,\n                timestamp,\n                genesis_number,\n            ))),\n        }\n    }\n\n    pub fn forked(block_number: u64, block_hash: B256, total_difficulty: U256) -> Self {\n        Self {\n            storage: Arc::new(RwLock::new(BlockchainStorage::forked(\n                block_number,\n                block_hash,\n                total_difficulty,\n            ))),\n        }\n    }\n\n    /// returns the header hash of given block\n    pub fn hash(&self, id: BlockId) -> Option<B256> {\n        match id {\n            BlockId::Hash(h) => Some(h.block_hash),\n            BlockId::Number(num) => self.storage.read().hash(num),\n        }\n    }\n\n    pub fn get_block_by_hash(&self, hash: &B256) -> Option<Block> {\n        self.storage.read().blocks.get(hash).cloned()\n    }\n\n    pub fn get_transaction_by_hash(&self, hash: &B256) -> Option<MinedTransaction<N>> {\n        self.storage.read().transactions.get(hash).cloned()\n    }\n\n    /// Returns the total number of blocks\n    pub fn blocks_count(&self) -> usize {\n        self.storage.read().blocks.len()\n    }\n}\n\n/// Represents the outcome of mining a new block\npub struct MinedBlockOutcome<T> {\n    /// The block that was mined\n    pub block_number: u64,\n    /// All transactions included in the block\n    pub included: Vec<Arc<PoolTransaction<T>>>,\n    /// All transactions that were attempted to be included but were invalid at the time of\n    /// execution\n    pub invalid: Vec<Arc<PoolTransaction<T>>>,\n}\n\nimpl<T> Clone for MinedBlockOutcome<T> {\n    fn clone(&self) -> Self {\n        Self {\n            block_number: self.block_number,\n            included: self.included.clone(),\n            invalid: self.invalid.clone(),\n        }\n    }\n}\n\nimpl<T> fmt::Debug for MinedBlockOutcome<T> {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.debug_struct(\"MinedBlockOutcome\")\n            .field(\"block_number\", &self.block_number)\n            .field(\"included\", &self.included.len())\n            .field(\"invalid\", &self.invalid.len())\n            .finish()\n    }\n}\n\n/// Container type for a mined transaction\n#[derive(Clone, Debug)]\npub struct MinedTransaction<N: Network> {\n    pub info: TransactionInfo,\n    pub receipt: N::ReceiptEnvelope,\n    pub block_hash: B256,\n    pub block_number: u64,\n}\n\nimpl<N: Network> MinedTransaction<N> {\n    /// Returns the traces of the transaction for `trace_transaction`\n    pub fn parity_traces(&self) -> Vec<LocalizedTransactionTrace> {\n        ParityTraceBuilder::new(\n            self.info.traces.clone(),\n            None,\n            TracingInspectorConfig::default_parity(),\n        )\n        .into_localized_transaction_traces(RethTransactionInfo {\n            hash: Some(self.info.transaction_hash),\n            index: Some(self.info.transaction_index),\n            block_hash: Some(self.block_hash),\n            block_number: Some(self.block_number),\n            base_fee: None,\n            block_timestamp: None,\n        })\n    }\n\n    pub fn ots_internal_operations(&self) -> Vec<InternalOperation> {\n        self.info\n            .traces\n            .iter()\n            .filter_map(|node| {\n                let r#type = match node.trace.kind {\n                    _ if node.is_selfdestruct() => OperationType::OpSelfDestruct,\n                    CallKind::Call if !node.trace.value.is_zero() => OperationType::OpTransfer,\n                    CallKind::Create => OperationType::OpCreate,\n                    CallKind::Create2 => OperationType::OpCreate2,\n                    _ => return None,\n                };\n                let mut from = node.trace.caller;\n                let mut to = node.trace.address;\n                let mut value = node.trace.value;\n                if node.is_selfdestruct() {\n                    from = node.trace.address;\n                    to = node.trace.selfdestruct_refund_target.unwrap_or_default();\n                    value = node.trace.selfdestruct_transferred_value.unwrap_or_default();\n                }\n                Some(InternalOperation { r#type, from, to, value })\n            })\n            .collect()\n    }\n}\n\n/// Intermediary Anvil representation of a receipt\n#[derive(Clone, Debug)]\npub struct MinedTransactionReceipt<N: Network> {\n    /// The actual json rpc receipt object\n    pub inner: N::ReceiptResponse,\n    /// Output data for the transaction\n    pub out: Option<Bytes>,\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use crate::eth::backend::db::Db;\n    use alloy_primitives::{Address, hex};\n    use alloy_rlp::Decodable;\n    use revm::{database::DatabaseRef, state::AccountInfo};\n\n    #[test]\n    fn test_interval_update() {\n        let mut storage = InMemoryBlockStates::default();\n        storage.update_interval_mine_block_time(Duration::from_secs(1));\n        assert_eq!(storage.in_memory_limit, DEFAULT_HISTORY_LIMIT * 3);\n    }\n\n    #[test]\n    fn test_init_state_limits() {\n        let mut storage = InMemoryBlockStates::default();\n        assert_eq!(storage.in_memory_limit, DEFAULT_HISTORY_LIMIT);\n        assert_eq!(storage.min_in_memory_limit, MIN_HISTORY_LIMIT);\n        assert_eq!(storage.max_on_disk_limit, MAX_ON_DISK_HISTORY_LIMIT);\n\n        storage = storage.memory_only();\n        assert!(storage.is_memory_only());\n\n        storage = InMemoryBlockStates::new(1, 0);\n        assert!(storage.is_memory_only());\n        assert_eq!(storage.in_memory_limit, 1);\n        assert_eq!(storage.min_in_memory_limit, 1);\n        assert_eq!(storage.max_on_disk_limit, 0);\n\n        storage = InMemoryBlockStates::new(1, 2);\n        assert!(!storage.is_memory_only());\n        assert_eq!(storage.in_memory_limit, 1);\n        assert_eq!(storage.min_in_memory_limit, 1);\n        assert_eq!(storage.max_on_disk_limit, 2);\n    }\n\n    #[tokio::test(flavor = \"multi_thread\")]\n    async fn can_read_write_cached_state() {\n        let mut storage = InMemoryBlockStates::new(1, MAX_ON_DISK_HISTORY_LIMIT);\n        let one = B256::from(U256::from(1));\n        let two = B256::from(U256::from(2));\n\n        let mut state = MemDb::default();\n        let addr = Address::random();\n        let info = AccountInfo::from_balance(U256::from(1337));\n        state.insert_account(addr, info);\n        storage.insert(one, StateDb::new(state));\n        storage.insert(two, StateDb::new(MemDb::default()));\n\n        // wait for files to be flushed\n        tokio::time::sleep(std::time::Duration::from_secs(1)).await;\n\n        assert_eq!(storage.on_disk_states.len(), 1);\n        assert!(storage.on_disk_states.contains_key(&one));\n\n        let loaded = storage.get_on_disk_state(&one).unwrap();\n\n        let acc = loaded.basic_ref(addr).unwrap().unwrap();\n        assert_eq!(acc.balance, U256::from(1337u64));\n    }\n\n    #[tokio::test(flavor = \"multi_thread\")]\n    async fn can_decrease_state_cache_size() {\n        let limit = 15;\n        let mut storage = InMemoryBlockStates::new(limit, MAX_ON_DISK_HISTORY_LIMIT);\n\n        let num_states = 30;\n        for idx in 0..num_states {\n            let mut state = MemDb::default();\n            let hash = B256::from(U256::from(idx));\n            let addr = Address::from_word(hash);\n            let balance = (idx * 2) as u64;\n            let info = AccountInfo::from_balance(U256::from(balance));\n            state.insert_account(addr, info);\n            storage.insert(hash, StateDb::new(state));\n        }\n\n        // wait for files to be flushed\n        tokio::time::sleep(std::time::Duration::from_secs(1)).await;\n\n        let on_disk_states_len = num_states - storage.min_in_memory_limit;\n\n        assert_eq!(storage.on_disk_states.len(), on_disk_states_len);\n        assert_eq!(storage.present.len(), storage.min_in_memory_limit);\n\n        for idx in 0..num_states {\n            let hash = B256::from(U256::from(idx));\n            let addr = Address::from_word(hash);\n\n            let loaded = if idx < on_disk_states_len {\n                storage.get_on_disk_state(&hash).unwrap()\n            } else {\n                storage.get_state(&hash).unwrap()\n            };\n\n            let acc = loaded.basic_ref(addr).unwrap().unwrap();\n            let balance = (idx * 2) as u64;\n            assert_eq!(acc.balance, U256::from(balance));\n        }\n    }\n\n    // verifies that blocks and transactions in BlockchainStorage remain the same when dumped and\n    // reloaded\n    #[test]\n    fn test_storage_dump_reload_cycle() {\n        let mut dump_storage = BlockchainStorage::<FoundryNetwork>::empty();\n\n        let header = Header { gas_limit: 123456, ..Default::default() };\n        let bytes_first = &mut &hex::decode(\"f86b02843b9aca00830186a094d3e8763675e4c425df46cc3b5c0f6cbdac39604687038d7ea4c68000802ba00eb96ca19e8a77102767a41fc85a36afd5c61ccb09911cec5d3e86e193d9c5aea03a456401896b1b6055311536bf00a718568c744d8c1f9df59879e8350220ca18\").unwrap()[..];\n        let tx: MaybeImpersonatedTransaction<FoundryTxEnvelope> =\n            FoundryTxEnvelope::decode(&mut &bytes_first[..]).unwrap().into();\n        let block = create_block(header.clone(), vec![tx.clone()]);\n        let block_hash = block.header.hash_slow();\n        dump_storage.blocks.insert(block_hash, block);\n\n        let serialized_blocks = dump_storage.serialized_blocks();\n        let serialized_transactions = dump_storage.serialized_transactions();\n\n        let mut load_storage = BlockchainStorage::<FoundryNetwork>::empty();\n\n        load_storage.load_blocks(serialized_blocks);\n        load_storage.load_transactions(serialized_transactions);\n\n        let loaded_block = load_storage.blocks.get(&block_hash).unwrap();\n        assert_eq!(loaded_block.header.gas_limit(), header.gas_limit());\n        let loaded_tx = loaded_block.body.transactions.first().unwrap();\n        assert_eq!(loaded_tx, &tx);\n    }\n}\n"
  },
  {
    "path": "crates/anvil/src/eth/backend/mod.rs",
    "content": "//! blockchain Backend\n\n/// [revm](foundry_evm::revm) related types\npub mod db;\n/// In-memory Backend\npub mod mem;\n\npub mod cheats;\npub mod time;\n\npub mod env;\npub mod executor;\npub mod fork;\npub mod genesis;\npub mod info;\npub mod notifications;\npub mod validate;\n"
  },
  {
    "path": "crates/anvil/src/eth/backend/notifications.rs",
    "content": "//! Notifications emitted from the backed\n\nuse alloy_consensus::Header;\nuse alloy_primitives::B256;\nuse futures::channel::mpsc::UnboundedReceiver;\nuse std::sync::Arc;\n\n/// A notification that's emitted when a new block was imported\n#[derive(Clone, Debug)]\npub struct NewBlockNotification {\n    /// Hash of the imported block\n    pub hash: B256,\n    /// block header\n    pub header: Arc<Header>,\n}\n\n/// Type alias for a receiver that receives [NewBlockNotification]\npub type NewBlockNotifications = UnboundedReceiver<NewBlockNotification>;\n"
  },
  {
    "path": "crates/anvil/src/eth/backend/time.rs",
    "content": "//! Manages the block time\n\nuse crate::eth::error::BlockchainError;\nuse chrono::{DateTime, Utc};\nuse parking_lot::RwLock;\nuse std::{sync::Arc, time::Duration};\n\n/// Returns the `Utc` datetime for the given seconds since unix epoch\npub fn utc_from_secs(secs: u64) -> DateTime<Utc> {\n    DateTime::from_timestamp(secs as i64, 0).unwrap_or(DateTime::<Utc>::MAX_UTC)\n}\n\n/// Manages block time\n#[derive(Clone, Debug)]\npub struct TimeManager {\n    /// tracks the overall applied timestamp offset\n    offset: Arc<RwLock<i128>>,\n    /// The timestamp of the last block header\n    last_timestamp: Arc<RwLock<u64>>,\n    /// Contains the next timestamp to use\n    /// if this is set then the next time `[TimeManager::current_timestamp()]` is called this value\n    /// will be taken and returned. After which the `offset` will be updated accordingly\n    next_exact_timestamp: Arc<RwLock<Option<u64>>>,\n    /// The interval to use when determining the next block's timestamp\n    interval: Arc<RwLock<Option<u64>>>,\n}\n\nimpl TimeManager {\n    pub fn new(start_timestamp: u64) -> Self {\n        let time_manager = Self {\n            last_timestamp: Default::default(),\n            offset: Default::default(),\n            next_exact_timestamp: Default::default(),\n            interval: Default::default(),\n        };\n        time_manager.reset(start_timestamp);\n        time_manager\n    }\n\n    /// Resets the current time manager to the given timestamp, resetting the offsets and\n    /// next block timestamp option\n    pub fn reset(&self, start_timestamp: u64) {\n        let current = duration_since_unix_epoch().as_secs() as i128;\n        *self.last_timestamp.write() = start_timestamp;\n        *self.offset.write() = (start_timestamp as i128) - current;\n        self.next_exact_timestamp.write().take();\n    }\n\n    pub fn offset(&self) -> i128 {\n        *self.offset.read()\n    }\n\n    /// Adds the given `offset` to the already tracked offset and returns the result\n    fn add_offset(&self, offset: i128) -> i128 {\n        let mut current = self.offset.write();\n        let next = current.saturating_add(offset);\n        trace!(target: \"time\", \"adding timestamp offset={}, total={}\", offset, next);\n        *current = next;\n        next\n    }\n\n    /// Jumps forward in time by the given seconds\n    ///\n    /// This will apply a permanent offset to the natural UNIX Epoch timestamp\n    pub fn increase_time(&self, seconds: u64) -> i128 {\n        self.add_offset(seconds as i128)\n    }\n\n    /// Sets the exact timestamp to use in the next block\n    /// Fails if it's before (or at the same time) the last timestamp\n    pub fn set_next_block_timestamp(&self, timestamp: u64) -> Result<(), BlockchainError> {\n        trace!(target: \"time\", \"override next timestamp {}\", timestamp);\n        if timestamp < *self.last_timestamp.read() {\n            return Err(BlockchainError::TimestampError(format!(\n                \"{timestamp} is lower than previous block's timestamp\"\n            )));\n        }\n        self.next_exact_timestamp.write().replace(timestamp);\n        Ok(())\n    }\n\n    /// Sets an interval to use when computing the next timestamp\n    ///\n    /// If an interval already exists, this will update the interval, otherwise a new interval will\n    /// be set starting with the current timestamp.\n    pub fn set_block_timestamp_interval(&self, interval: u64) {\n        trace!(target: \"time\", \"set interval {}\", interval);\n        self.interval.write().replace(interval);\n    }\n\n    /// Removes the interval if it exists\n    pub fn remove_block_timestamp_interval(&self) -> bool {\n        if self.interval.write().take().is_some() {\n            trace!(target: \"time\", \"removed interval\");\n            true\n        } else {\n            false\n        }\n    }\n\n    /// Computes the next timestamp without updating internals\n    fn compute_next_timestamp(&self) -> (u64, Option<i128>) {\n        let current = duration_since_unix_epoch().as_secs() as i128;\n        let last_timestamp = *self.last_timestamp.read();\n\n        let (mut next_timestamp, update_offset) =\n            if let Some(next) = *self.next_exact_timestamp.read() {\n                (next, true)\n            } else if let Some(interval) = *self.interval.read() {\n                (last_timestamp.saturating_add(interval), false)\n            } else {\n                (current.saturating_add(self.offset()) as u64, false)\n            };\n        // Ensures that the timestamp is always increasing\n        if next_timestamp < last_timestamp {\n            next_timestamp = last_timestamp + 1;\n        }\n        let next_offset = update_offset.then_some((next_timestamp as i128) - current);\n        (next_timestamp, next_offset)\n    }\n\n    /// Returns the current timestamp and updates the underlying offset and interval accordingly\n    pub fn next_timestamp(&self) -> u64 {\n        let (next_timestamp, next_offset) = self.compute_next_timestamp();\n        // Make sure we reset the `next_exact_timestamp`\n        self.next_exact_timestamp.write().take();\n        if let Some(next_offset) = next_offset {\n            *self.offset.write() = next_offset;\n        }\n        *self.last_timestamp.write() = next_timestamp;\n        next_timestamp\n    }\n\n    /// Returns the current timestamp for a call that does _not_ update the value\n    pub fn current_call_timestamp(&self) -> u64 {\n        let (next_timestamp, _) = self.compute_next_timestamp();\n        next_timestamp\n    }\n}\n\n/// Returns the current duration since unix epoch.\npub fn duration_since_unix_epoch() -> Duration {\n    use std::time::SystemTime;\n    let now = SystemTime::now();\n    now.duration_since(SystemTime::UNIX_EPOCH)\n        .unwrap_or_else(|err| panic!(\"Current time {now:?} is invalid: {err:?}\"))\n}\n"
  },
  {
    "path": "crates/anvil/src/eth/backend/validate.rs",
    "content": "//! Support for validating transactions at certain stages\n\nuse crate::eth::{\n    backend::env::Env,\n    error::{BlockchainError, InvalidTransactionError},\n};\nuse anvil_core::eth::transaction::PendingTransaction;\nuse revm::state::AccountInfo;\n\n/// A trait for validating transactions\n#[async_trait::async_trait]\npub trait TransactionValidator<T> {\n    /// Validates the transaction's validity when it comes to nonce, payment\n    ///\n    /// This is intended to be checked before the transaction makes it into the pool and whether it\n    /// should rather be outright rejected if the sender has insufficient funds.\n    async fn validate_pool_transaction(\n        &self,\n        tx: &PendingTransaction<T>,\n    ) -> Result<(), BlockchainError>;\n\n    /// Validates the transaction against a specific account before entering the pool\n    fn validate_pool_transaction_for(\n        &self,\n        tx: &PendingTransaction<T>,\n        account: &AccountInfo,\n        env: &Env,\n    ) -> Result<(), InvalidTransactionError>;\n\n    /// Validates the transaction against a specific account\n    ///\n    /// This should succeed if the transaction is ready to be executed\n    fn validate_for(\n        &self,\n        tx: &PendingTransaction<T>,\n        account: &AccountInfo,\n        env: &Env,\n    ) -> Result<(), InvalidTransactionError>;\n}\n"
  },
  {
    "path": "crates/anvil/src/eth/error.rs",
    "content": "//! Aggregated error type for this module\n\nuse alloy_consensus::crypto::RecoveryError;\nuse alloy_evm::overrides::StateOverrideError;\nuse alloy_primitives::{B256, Bytes, SignatureError, TxHash};\nuse alloy_rpc_types::BlockNumberOrTag;\nuse alloy_signer::Error as SignerError;\nuse alloy_transport::TransportError;\nuse anvil_core::eth::wallet::WalletError;\nuse anvil_rpc::{\n    error::{ErrorCode, RpcError},\n    response::ResponseResult,\n};\nuse foundry_evm::{backend::DatabaseError, decode::RevertDecoder};\nuse op_revm::OpTransactionError;\nuse revm::{\n    context_interface::result::{EVMError, InvalidHeader, InvalidTransaction},\n    interpreter::InstructionResult,\n};\nuse serde::Serialize;\nuse tokio::time::Duration;\n\npub(crate) type Result<T> = std::result::Result<T, BlockchainError>;\n\n#[derive(Debug, thiserror::Error)]\npub enum BlockchainError {\n    #[error(transparent)]\n    Pool(#[from] PoolError),\n    #[error(\"No signer available\")]\n    NoSignerAvailable,\n    #[error(\"Chain Id not available\")]\n    ChainIdNotAvailable,\n    #[error(\"Invalid input: `max_priority_fee_per_gas` greater than `max_fee_per_gas`\")]\n    InvalidFeeInput,\n    #[error(\"Transaction data is empty\")]\n    EmptyRawTransactionData,\n    #[error(\"Failed to decode signed transaction\")]\n    FailedToDecodeSignedTransaction,\n    #[error(\"Failed to decode transaction\")]\n    FailedToDecodeTransaction,\n    #[error(\"Failed to decode receipt\")]\n    FailedToDecodeReceipt,\n    #[error(\"Failed to decode state\")]\n    FailedToDecodeStateDump,\n    #[error(\"Prevrandao not in the EVM's environment after merge\")]\n    PrevrandaoNotSet,\n    #[error(transparent)]\n    SignatureError(#[from] SignatureError),\n    #[error(transparent)]\n    RecoveryError(#[from] RecoveryError),\n    #[error(transparent)]\n    SignerError(#[from] SignerError),\n    #[error(\"Rpc Endpoint not implemented\")]\n    RpcUnimplemented,\n    #[error(\"Rpc error {0:?}\")]\n    RpcError(RpcError),\n    #[error(transparent)]\n    InvalidTransaction(#[from] InvalidTransactionError),\n    #[error(transparent)]\n    FeeHistory(#[from] FeeHistoryError),\n    #[error(transparent)]\n    AlloyForkProvider(#[from] TransportError),\n    #[error(\"EVM error {0:?}\")]\n    EvmError(InstructionResult),\n    #[error(\"Evm override error: {0}\")]\n    EvmOverrideError(String),\n    #[error(\"Invalid url {0:?}\")]\n    InvalidUrl(String),\n    #[error(\"Internal error: {0:?}\")]\n    Internal(String),\n    #[error(\"BlockOutOfRangeError: block height is {0} but requested was {1}\")]\n    BlockOutOfRange(u64, u64),\n    #[error(\"Resource not found\")]\n    BlockNotFound,\n    /// Thrown when a requested transaction is not found\n    #[error(\"transaction not found\")]\n    TransactionNotFound,\n    #[error(\"Required data unavailable\")]\n    DataUnavailable,\n    #[error(\"Trie error: {0}\")]\n    TrieError(String),\n    #[error(\"{0}\")]\n    UintConversion(&'static str),\n    #[error(\"State override error: {0}\")]\n    StateOverrideError(String),\n    #[error(\"Timestamp error: {0}\")]\n    TimestampError(String),\n    #[error(transparent)]\n    DatabaseError(#[from] DatabaseError),\n    #[error(\n        \"EIP-1559 style fee params (maxFeePerGas or maxPriorityFeePerGas) received but they are not supported by the current hardfork.\\n\\nYou can use them by running anvil with '--hardfork london' or later.\"\n    )]\n    EIP1559TransactionUnsupportedAtHardfork,\n    #[error(\n        \"Access list received but is not supported by the current hardfork.\\n\\nYou can use it by running anvil with '--hardfork berlin' or later.\"\n    )]\n    EIP2930TransactionUnsupportedAtHardfork,\n    #[error(\n        \"EIP-4844 fields received but is not supported by the current hardfork.\\n\\nYou can use it by running anvil with '--hardfork cancun' or later.\"\n    )]\n    EIP4844TransactionUnsupportedAtHardfork,\n    #[error(\n        \"EIP-7702 fields received but is not supported by the current hardfork.\\n\\nYou can use it by running anvil with '--hardfork prague' or later.\"\n    )]\n    EIP7702TransactionUnsupportedAtHardfork,\n    #[error(\n        \"op-stack deposit tx received but is not supported.\\n\\nYou can use it by running anvil with '--optimism'.\"\n    )]\n    DepositTransactionUnsupported,\n    #[error(\"Unknown transaction type not supported\")]\n    UnknownTransactionType,\n    #[error(\"Excess blob gas not set.\")]\n    ExcessBlobGasNotSet,\n    #[error(\"{0}\")]\n    Message(String),\n    #[error(\"Transaction {hash} was added to the mempool but wasn't confirmed within {duration:?}\")]\n    TransactionConfirmationTimeout {\n        /// Hash of the transaction that timed out\n        hash: B256,\n        /// Duration that was waited before timing out\n        duration: Duration,\n    },\n    #[error(\"Invalid transaction request: {0}\")]\n    InvalidTransactionRequest(String),\n    #[error(\"filter not found\")]\n    FilterNotFound,\n}\n\nimpl From<eyre::Report> for BlockchainError {\n    fn from(err: eyre::Report) -> Self {\n        Self::Message(err.to_string())\n    }\n}\n\nimpl From<RpcError> for BlockchainError {\n    fn from(err: RpcError) -> Self {\n        Self::RpcError(err)\n    }\n}\n\nimpl<T> From<EVMError<T>> for BlockchainError\nwhere\n    T: Into<Self>,\n{\n    fn from(err: EVMError<T>) -> Self {\n        match err {\n            EVMError::Transaction(err) => InvalidTransactionError::from(err).into(),\n            EVMError::Header(err) => match err {\n                InvalidHeader::ExcessBlobGasNotSet => Self::ExcessBlobGasNotSet,\n                InvalidHeader::PrevrandaoNotSet => Self::PrevrandaoNotSet,\n            },\n            EVMError::Database(err) => err.into(),\n            EVMError::Custom(err) => Self::Message(err),\n        }\n    }\n}\n\nimpl<T> From<EVMError<T, OpTransactionError>> for BlockchainError\nwhere\n    T: Into<Self>,\n{\n    fn from(err: EVMError<T, OpTransactionError>) -> Self {\n        match err {\n            EVMError::Transaction(err) => match err {\n                OpTransactionError::Base(err) => InvalidTransactionError::from(err).into(),\n                OpTransactionError::DepositSystemTxPostRegolith => {\n                    Self::DepositTransactionUnsupported\n                }\n                OpTransactionError::HaltedDepositPostRegolith => {\n                    Self::DepositTransactionUnsupported\n                }\n                OpTransactionError::MissingEnvelopedTx => Self::InvalidTransaction(err.into()),\n            },\n            EVMError::Header(err) => match err {\n                InvalidHeader::ExcessBlobGasNotSet => Self::ExcessBlobGasNotSet,\n                InvalidHeader::PrevrandaoNotSet => Self::PrevrandaoNotSet,\n            },\n            EVMError::Database(err) => err.into(),\n            EVMError::Custom(err) => Self::Message(err),\n        }\n    }\n}\n\nimpl From<WalletError> for BlockchainError {\n    fn from(value: WalletError) -> Self {\n        Self::Message(value.to_string())\n    }\n}\n\nimpl<E> From<StateOverrideError<E>> for BlockchainError\nwhere\n    E: Into<Self>,\n{\n    fn from(value: StateOverrideError<E>) -> Self {\n        match value {\n            StateOverrideError::InvalidBytecode(err) => Self::StateOverrideError(err.to_string()),\n            StateOverrideError::BothStateAndStateDiff(addr) => Self::StateOverrideError(format!(\n                \"state and state_diff can't be used together for account {addr}\",\n            )),\n            StateOverrideError::Database(err) => err.into(),\n        }\n    }\n}\n\n/// Errors that can occur in the transaction pool\n#[derive(Debug, thiserror::Error)]\npub enum PoolError {\n    #[error(\"Transaction with cyclic dependent transactions\")]\n    CyclicTransaction,\n    /// Thrown if a replacement transaction's gas price is below the already imported transaction\n    #[error(\"Tx: [{0:?}] insufficient gas price to replace existing transaction\")]\n    ReplacementUnderpriced(TxHash),\n    #[error(\"Tx: [{0:?}] already Imported\")]\n    AlreadyImported(TxHash),\n}\n\n/// Errors that can occur with `eth_feeHistory`\n#[derive(Debug, thiserror::Error)]\npub enum FeeHistoryError {\n    #[error(\"requested block range is out of bounds\")]\n    InvalidBlockRange,\n    #[error(\"could not find newest block number requested: {0}\")]\n    BlockNotFound(BlockNumberOrTag),\n}\n\n#[derive(Debug)]\npub struct ErrDetail {\n    pub detail: String,\n}\n\n/// An error due to invalid transaction\n#[derive(Debug, thiserror::Error)]\npub enum InvalidTransactionError {\n    /// returned if the nonce of a transaction is lower than the one present in the local chain.\n    #[error(\"nonce too low\")]\n    NonceTooLow,\n    /// returned if the nonce of a transaction is higher than the next one expected based on the\n    /// local chain.\n    #[error(\"Nonce too high\")]\n    NonceTooHigh,\n    /// Returned if the nonce of a transaction is too high\n    /// Incrementing the nonce would lead to invalid state (overflow)\n    #[error(\"nonce has max value\")]\n    NonceMaxValue,\n    /// thrown if the transaction sender doesn't have enough funds for a transfer\n    #[error(\"insufficient funds for transfer\")]\n    InsufficientFundsForTransfer,\n    /// thrown if creation transaction provides the init code bigger than init code size limit.\n    #[error(\"max initcode size exceeded\")]\n    MaxInitCodeSizeExceeded,\n    /// Represents the inability to cover max cost + value (account balance too low).\n    #[error(\"Insufficient funds for gas * price + value\")]\n    InsufficientFunds,\n    /// Thrown when calculating gas usage\n    #[error(\"gas uint64 overflow\")]\n    GasUintOverflow,\n    /// returned if the transaction is specified to use less gas than required to start the\n    /// invocation.\n    #[error(\"intrinsic gas too low\")]\n    GasTooLow,\n    /// returned if the transaction gas exceeds the limit\n    #[error(\"intrinsic gas too high -- {}\",.0.detail)]\n    GasTooHigh(ErrDetail),\n    /// Thrown to ensure no one is able to specify a transaction with a tip higher than the total\n    /// fee cap.\n    #[error(\"max priority fee per gas higher than max fee per gas\")]\n    TipAboveFeeCap,\n    /// Thrown post London if the transaction's fee is less than the base fee of the block\n    #[error(\"max fee per gas less than block base fee\")]\n    FeeCapTooLow,\n    /// Thrown during estimate if caller has insufficient funds to cover the tx.\n    #[error(\"Out of gas: gas required exceeds allowance: {0:?}\")]\n    BasicOutOfGas(u128),\n    /// Thrown if executing a transaction failed during estimate/call\n    #[error(\"execution reverted: {0:?}\")]\n    Revert(Option<Bytes>),\n    /// Thrown if the sender of a transaction is a contract.\n    #[error(\"sender not an eoa\")]\n    SenderNoEOA,\n    /// Thrown when a tx was signed with a different chain_id\n    #[error(\"invalid chain id for signer\")]\n    InvalidChainId,\n    /// Thrown when a legacy tx was signed for a different chain\n    #[error(\"Incompatible EIP-155 transaction, signed for another chain\")]\n    IncompatibleEIP155,\n    /// Thrown when an access list is used before the berlin hard fork.\n    #[error(\"Access lists are not supported before the Berlin hardfork\")]\n    AccessListNotSupported,\n    /// Thrown when the block's `blob_gas_price` is greater than tx-specified\n    /// `max_fee_per_blob_gas` after Cancun.\n    #[error(\"Block `blob_gas_price` is greater than tx-specified `max_fee_per_blob_gas`\")]\n    BlobFeeCapTooLow(u128, u128),\n    /// Thrown when we receive a tx with `blob_versioned_hashes` and we're not on the Cancun hard\n    /// fork.\n    #[error(\"Block `blob_versioned_hashes` is not supported before the Cancun hardfork\")]\n    BlobVersionedHashesNotSupported,\n    /// Thrown when `max_fee_per_blob_gas` is not supported for blocks before the Cancun hardfork.\n    #[error(\"`max_fee_per_blob_gas` is not supported for blocks before the Cancun hardfork.\")]\n    MaxFeePerBlobGasNotSupported,\n    /// Thrown when there are no `blob_hashes` in the transaction, and it is an EIP-4844 tx.\n    #[error(\"`blob_hashes` are required for EIP-4844 transactions\")]\n    NoBlobHashes,\n    #[error(\"too many blobs in one transaction, have: {0}, max: {1}\")]\n    TooManyBlobs(usize, usize),\n    /// Thrown when there's a blob validation error\n    #[error(transparent)]\n    BlobTransactionValidationError(#[from] alloy_consensus::BlobTransactionValidationError),\n    /// Thrown when Blob transaction is a create transaction. `to` must be present.\n    #[error(\"Blob transaction can't be a create transaction. `to` must be present.\")]\n    BlobCreateTransaction,\n    /// Thrown when Blob transaction contains a versioned hash with an incorrect version.\n    #[error(\"Blob transaction contains a versioned hash with an incorrect version\")]\n    BlobVersionNotSupported,\n    /// Thrown when there are no `blob_hashes` in the transaction.\n    #[error(\"There should be at least one blob in a Blob transaction.\")]\n    EmptyBlobs,\n    /// Thrown when an access list is used before the berlin hard fork.\n    #[error(\"EIP-7702 authorization lists are not supported before the Prague hardfork\")]\n    AuthorizationListNotSupported,\n    #[error(\"Transaction gas limit is greater than the block gas limit, gas_limit: {0}, cap: {1}\")]\n    TxGasLimitGreaterThanCap(u64, u64),\n    /// Forwards error from the revm\n    #[error(transparent)]\n    Revm(revm::context_interface::result::InvalidTransaction),\n    /// Deposit transaction error post regolith\n    #[error(\"op-deposit failure post regolith\")]\n    DepositTxErrorPostRegolith,\n    /// Missing enveloped transaction\n    #[error(\"missing enveloped transaction\")]\n    MissingEnvelopedTx,\n}\n\nimpl From<InvalidTransaction> for InvalidTransactionError {\n    fn from(err: InvalidTransaction) -> Self {\n        match err {\n            InvalidTransaction::InvalidChainId => Self::InvalidChainId,\n            InvalidTransaction::PriorityFeeGreaterThanMaxFee => Self::TipAboveFeeCap,\n            InvalidTransaction::GasPriceLessThanBasefee => Self::FeeCapTooLow,\n            InvalidTransaction::CallerGasLimitMoreThanBlock => {\n                Self::GasTooHigh(ErrDetail { detail: String::from(\"CallerGasLimitMoreThanBlock\") })\n            }\n            InvalidTransaction::CallGasCostMoreThanGasLimit { .. } => {\n                Self::GasTooHigh(ErrDetail { detail: String::from(\"CallGasCostMoreThanGasLimit\") })\n            }\n            InvalidTransaction::GasFloorMoreThanGasLimit { .. } => {\n                Self::GasTooHigh(ErrDetail { detail: String::from(\"GasFloorMoreThanGasLimit\") })\n            }\n            InvalidTransaction::RejectCallerWithCode => Self::SenderNoEOA,\n            InvalidTransaction::LackOfFundForMaxFee { .. } => Self::InsufficientFunds,\n            InvalidTransaction::OverflowPaymentInTransaction => Self::GasUintOverflow,\n            InvalidTransaction::NonceOverflowInTransaction => Self::NonceMaxValue,\n            InvalidTransaction::CreateInitCodeSizeLimit => Self::MaxInitCodeSizeExceeded,\n            InvalidTransaction::NonceTooHigh { .. } => Self::NonceTooHigh,\n            InvalidTransaction::NonceTooLow { .. } => Self::NonceTooLow,\n            InvalidTransaction::AccessListNotSupported => Self::AccessListNotSupported,\n            InvalidTransaction::BlobGasPriceGreaterThanMax {\n                block_blob_gas_price,\n                tx_max_fee_per_blob_gas,\n            } => Self::BlobFeeCapTooLow(block_blob_gas_price, tx_max_fee_per_blob_gas),\n            InvalidTransaction::BlobVersionedHashesNotSupported => {\n                Self::BlobVersionedHashesNotSupported\n            }\n            InvalidTransaction::MaxFeePerBlobGasNotSupported => Self::MaxFeePerBlobGasNotSupported,\n            InvalidTransaction::BlobCreateTransaction => Self::BlobCreateTransaction,\n            InvalidTransaction::BlobVersionNotSupported => Self::BlobVersionNotSupported,\n            InvalidTransaction::EmptyBlobs => Self::EmptyBlobs,\n            InvalidTransaction::TooManyBlobs { have, max } => Self::TooManyBlobs(have, max),\n            InvalidTransaction::AuthorizationListNotSupported => {\n                Self::AuthorizationListNotSupported\n            }\n            InvalidTransaction::TxGasLimitGreaterThanCap { gas_limit, cap } => {\n                Self::TxGasLimitGreaterThanCap(gas_limit, cap)\n            }\n\n            InvalidTransaction::AuthorizationListInvalidFields\n            | InvalidTransaction::Eip1559NotSupported\n            | InvalidTransaction::Eip2930NotSupported\n            | InvalidTransaction::Eip4844NotSupported\n            | InvalidTransaction::Eip7702NotSupported\n            | InvalidTransaction::EmptyAuthorizationList\n            | InvalidTransaction::Eip7873NotSupported\n            | InvalidTransaction::Eip7873MissingTarget\n            | InvalidTransaction::MissingChainId\n            | InvalidTransaction::Str(_) => Self::Revm(err),\n        }\n    }\n}\n\nimpl From<OpTransactionError> for InvalidTransactionError {\n    fn from(value: OpTransactionError) -> Self {\n        match value {\n            OpTransactionError::Base(err) => err.into(),\n            OpTransactionError::DepositSystemTxPostRegolith\n            | OpTransactionError::HaltedDepositPostRegolith => Self::DepositTxErrorPostRegolith,\n            OpTransactionError::MissingEnvelopedTx => Self::MissingEnvelopedTx,\n        }\n    }\n}\n/// Helper trait to easily convert results to rpc results\npub(crate) trait ToRpcResponseResult {\n    fn to_rpc_result(self) -> ResponseResult;\n}\n\n/// Converts a serializable value into a `ResponseResult`\npub fn to_rpc_result<T: Serialize>(val: T) -> ResponseResult {\n    match serde_json::to_value(val) {\n        Ok(success) => ResponseResult::Success(success),\n        Err(err) => {\n            error!(%err, \"Failed serialize rpc response\");\n            ResponseResult::error(RpcError::internal_error())\n        }\n    }\n}\n\nimpl<T: Serialize> ToRpcResponseResult for Result<T> {\n    fn to_rpc_result(self) -> ResponseResult {\n        match self {\n            Ok(val) => to_rpc_result(val),\n            Err(err) => match err {\n                BlockchainError::Pool(err) => {\n                    error!(%err, \"txpool error\");\n                    match err {\n                        PoolError::CyclicTransaction => {\n                            RpcError::transaction_rejected(\"Cyclic transaction detected\")\n                        }\n                        PoolError::ReplacementUnderpriced(_) => {\n                            RpcError::transaction_rejected(\"replacement transaction underpriced\")\n                        }\n                        PoolError::AlreadyImported(_) => {\n                            RpcError::transaction_rejected(\"transaction already imported\")\n                        }\n                    }\n                }\n                BlockchainError::NoSignerAvailable => {\n                    RpcError::invalid_params(\"No Signer available\")\n                }\n                BlockchainError::ChainIdNotAvailable => {\n                    RpcError::invalid_params(\"Chain Id not available\")\n                }\n                BlockchainError::TransactionConfirmationTimeout { .. } => {\n                    RpcError::internal_error_with(\"Transaction confirmation timeout\")\n                }\n                BlockchainError::InvalidTransaction(err) => match err {\n                    InvalidTransactionError::Revert(data) => {\n                        // this mimics geth revert error\n                        let mut msg = \"execution reverted\".to_string();\n                        if let Some(reason) = data\n                            .as_ref()\n                            .and_then(|data| RevertDecoder::new().maybe_decode(data, None))\n                        {\n                            msg = format!(\"{msg}: {reason}\");\n                        }\n                        RpcError {\n                            // geth returns this error code on reverts, See <https://eips.ethereum.org/EIPS/eip-1474#specification>\n                            code: ErrorCode::ExecutionError,\n                            message: msg.into(),\n                            data: serde_json::to_value(data).ok(),\n                        }\n                    }\n                    InvalidTransactionError::GasTooLow => {\n                        // <https://eips.ethereum.org/EIPS/eip-1898>\n                        RpcError {\n                            code: ErrorCode::ServerError(-32000),\n                            message: err.to_string().into(),\n                            data: None,\n                        }\n                    }\n                    InvalidTransactionError::GasTooHigh(_) => {\n                        // <https://eips.ethereum.org/EIPS/eip-1898>\n                        RpcError {\n                            code: ErrorCode::ServerError(-32000),\n                            message: err.to_string().into(),\n                            data: None,\n                        }\n                    }\n                    _ => RpcError::transaction_rejected(err.to_string()),\n                },\n                BlockchainError::FeeHistory(err) => RpcError::invalid_params(err.to_string()),\n                BlockchainError::EmptyRawTransactionData => {\n                    RpcError::invalid_params(\"Empty transaction data\")\n                }\n                BlockchainError::FailedToDecodeSignedTransaction => {\n                    RpcError::invalid_params(\"Failed to decode transaction\")\n                }\n                BlockchainError::FailedToDecodeTransaction => {\n                    RpcError::invalid_params(\"Failed to decode transaction\")\n                }\n                BlockchainError::FailedToDecodeReceipt => {\n                    RpcError::invalid_params(\"Failed to decode receipt\")\n                }\n                BlockchainError::FailedToDecodeStateDump => {\n                    RpcError::invalid_params(\"Failed to decode state dump\")\n                }\n                BlockchainError::SignerError(err) => RpcError::invalid_params(err.to_string()),\n                BlockchainError::SignatureError(err) => RpcError::invalid_params(err.to_string()),\n                BlockchainError::RpcUnimplemented => {\n                    RpcError::internal_error_with(\"Not implemented\")\n                }\n                BlockchainError::PrevrandaoNotSet => RpcError::internal_error_with(err.to_string()),\n                BlockchainError::RpcError(err) => err,\n                BlockchainError::InvalidFeeInput => RpcError::invalid_params(\n                    \"Invalid input: `max_priority_fee_per_gas` greater than `max_fee_per_gas`\",\n                ),\n                BlockchainError::AlloyForkProvider(err) => {\n                    error!(target: \"backend\", %err, \"fork provider error\");\n                    match err {\n                        TransportError::ErrorResp(err) => RpcError {\n                            code: ErrorCode::from(err.code),\n                            message: err.message,\n                            data: err.data.and_then(|data| serde_json::to_value(data).ok()),\n                        },\n                        err => RpcError::internal_error_with(format!(\"Fork Error: {err:?}\")),\n                    }\n                }\n                err @ BlockchainError::EvmError(_) => {\n                    RpcError::internal_error_with(err.to_string())\n                }\n                err @ BlockchainError::EvmOverrideError(_) => {\n                    RpcError::invalid_params(err.to_string())\n                }\n                err @ BlockchainError::InvalidUrl(_) => RpcError::invalid_params(err.to_string()),\n                BlockchainError::Internal(err) => RpcError::internal_error_with(err),\n                err @ BlockchainError::BlockOutOfRange(_, _) => {\n                    RpcError::invalid_params(err.to_string())\n                }\n                err @ BlockchainError::BlockNotFound => RpcError {\n                    // <https://eips.ethereum.org/EIPS/eip-1898>\n                    code: ErrorCode::ServerError(-32001),\n                    message: err.to_string().into(),\n                    data: None,\n                },\n                err @ BlockchainError::TransactionNotFound => RpcError {\n                    code: ErrorCode::ServerError(-32001),\n                    message: err.to_string().into(),\n                    data: None,\n                },\n                err @ BlockchainError::DataUnavailable => {\n                    RpcError::internal_error_with(err.to_string())\n                }\n                err @ BlockchainError::TrieError(_) => {\n                    RpcError::internal_error_with(err.to_string())\n                }\n                BlockchainError::UintConversion(err) => RpcError::invalid_params(err),\n                err @ BlockchainError::StateOverrideError(_) => {\n                    RpcError::invalid_params(err.to_string())\n                }\n                err @ BlockchainError::TimestampError(_) => {\n                    RpcError::invalid_params(err.to_string())\n                }\n                BlockchainError::DatabaseError(err) => {\n                    RpcError::internal_error_with(err.to_string())\n                }\n                err @ BlockchainError::EIP1559TransactionUnsupportedAtHardfork => {\n                    RpcError::invalid_params(err.to_string())\n                }\n                err @ BlockchainError::EIP2930TransactionUnsupportedAtHardfork => {\n                    RpcError::invalid_params(err.to_string())\n                }\n                err @ BlockchainError::EIP4844TransactionUnsupportedAtHardfork => {\n                    RpcError::invalid_params(err.to_string())\n                }\n                err @ BlockchainError::EIP7702TransactionUnsupportedAtHardfork => {\n                    RpcError::invalid_params(err.to_string())\n                }\n                err @ BlockchainError::DepositTransactionUnsupported => {\n                    RpcError::invalid_params(err.to_string())\n                }\n                err @ BlockchainError::ExcessBlobGasNotSet => {\n                    RpcError::invalid_params(err.to_string())\n                }\n                err @ BlockchainError::Message(_) => RpcError::internal_error_with(err.to_string()),\n                err @ BlockchainError::UnknownTransactionType => {\n                    RpcError::invalid_params(err.to_string())\n                }\n                err @ BlockchainError::InvalidTransactionRequest(_) => {\n                    RpcError::invalid_params(err.to_string())\n                }\n                err @ BlockchainError::RecoveryError(_) => {\n                    RpcError::invalid_params(err.to_string())\n                }\n                BlockchainError::FilterNotFound => RpcError {\n                    code: ErrorCode::ServerError(-32000),\n                    message: \"filter not found\".into(),\n                    data: None,\n                },\n            }\n            .into(),\n        }\n    }\n}\n"
  },
  {
    "path": "crates/anvil/src/eth/fees.rs",
    "content": "use std::{\n    collections::BTreeMap,\n    fmt,\n    pin::Pin,\n    sync::Arc,\n    task::{Context, Poll},\n};\n\nuse alloy_consensus::{BlockHeader, Header, Transaction};\nuse alloy_eips::{calc_next_block_base_fee, eip1559::BaseFeeParams, eip7840::BlobParams};\nuse alloy_primitives::B256;\nuse futures::StreamExt;\nuse parking_lot::{Mutex, RwLock};\nuse revm::{context_interface::block::BlobExcessGasAndPrice, primitives::hardfork::SpecId};\n\nuse crate::eth::{\n    backend::{info::StorageInfo, notifications::NewBlockNotifications},\n    error::BlockchainError,\n};\nuse foundry_primitives::FoundryNetwork;\n\n/// Maximum number of entries in the fee history cache\npub const MAX_FEE_HISTORY_CACHE_SIZE: u64 = 2048u64;\n\n/// Initial base fee for EIP-1559 blocks.\npub const INITIAL_BASE_FEE: u64 = 1_000_000_000;\n\n/// Initial default gas price for the first block\npub const INITIAL_GAS_PRICE: u128 = 1_875_000_000;\n\n/// Bounds the amount the base fee can change between blocks.\npub const BASE_FEE_CHANGE_DENOMINATOR: u128 = 8;\n\n/// Minimum suggested priority fee\npub const MIN_SUGGESTED_PRIORITY_FEE: u128 = 1e9 as u128;\n\n/// Stores the fee related information\n#[derive(Clone, Debug)]\npub struct FeeManager {\n    /// Hardfork identifier\n    spec_id: SpecId,\n    /// The blob params that determine blob fees\n    blob_params: Arc<RwLock<BlobParams>>,\n    /// Tracks the base fee for the next block post London\n    ///\n    /// This value will be updated after a new block was mined\n    base_fee: Arc<RwLock<u64>>,\n    /// Whether the minimum suggested priority fee is enforced\n    is_min_priority_fee_enforced: bool,\n    /// Tracks the excess blob gas, and the base fee, for the next block post Cancun\n    ///\n    /// This value will be updated after a new block was mined\n    blob_excess_gas_and_price: Arc<RwLock<BlobExcessGasAndPrice>>,\n    /// The base price to use Pre London\n    ///\n    /// This will be constant value unless changed manually\n    gas_price: Arc<RwLock<u128>>,\n    elasticity: Arc<RwLock<f64>>,\n    /// Network-specific base fee params for EIP-1559 calculations\n    base_fee_params: BaseFeeParams,\n}\n\nimpl FeeManager {\n    pub fn new(\n        spec_id: SpecId,\n        base_fee: u64,\n        is_min_priority_fee_enforced: bool,\n        gas_price: u128,\n        blob_excess_gas_and_price: BlobExcessGasAndPrice,\n        blob_params: BlobParams,\n        base_fee_params: BaseFeeParams,\n    ) -> Self {\n        let elasticity = 1f64 / base_fee_params.elasticity_multiplier as f64;\n        Self {\n            spec_id,\n            blob_params: Arc::new(RwLock::new(blob_params)),\n            base_fee: Arc::new(RwLock::new(base_fee)),\n            is_min_priority_fee_enforced,\n            gas_price: Arc::new(RwLock::new(gas_price)),\n            blob_excess_gas_and_price: Arc::new(RwLock::new(blob_excess_gas_and_price)),\n            elasticity: Arc::new(RwLock::new(elasticity)),\n            base_fee_params,\n        }\n    }\n\n    /// Returns the base fee params used for EIP-1559 calculations\n    pub fn base_fee_params(&self) -> BaseFeeParams {\n        self.base_fee_params\n    }\n\n    pub fn elasticity(&self) -> f64 {\n        *self.elasticity.read()\n    }\n\n    /// Returns true for post London\n    pub fn is_eip1559(&self) -> bool {\n        (self.spec_id as u8) >= (SpecId::LONDON as u8)\n    }\n\n    pub fn is_eip4844(&self) -> bool {\n        (self.spec_id as u8) >= (SpecId::CANCUN as u8)\n    }\n\n    /// Calculates the current blob gas price\n    pub fn blob_gas_price(&self) -> u128 {\n        if self.is_eip4844() { self.base_fee_per_blob_gas() } else { 0 }\n    }\n\n    pub fn base_fee(&self) -> u64 {\n        if self.is_eip1559() { *self.base_fee.read() } else { 0 }\n    }\n\n    pub fn is_min_priority_fee_enforced(&self) -> bool {\n        self.is_min_priority_fee_enforced\n    }\n\n    /// Raw base gas price\n    pub fn raw_gas_price(&self) -> u128 {\n        *self.gas_price.read()\n    }\n\n    pub fn excess_blob_gas_and_price(&self) -> Option<BlobExcessGasAndPrice> {\n        if self.is_eip4844() { Some(*self.blob_excess_gas_and_price.read()) } else { None }\n    }\n\n    pub fn base_fee_per_blob_gas(&self) -> u128 {\n        if self.is_eip4844() { self.blob_excess_gas_and_price.read().blob_gasprice } else { 0 }\n    }\n\n    /// Returns the current gas price\n    pub fn set_gas_price(&self, price: u128) {\n        let mut gas = self.gas_price.write();\n        *gas = price;\n    }\n\n    /// Returns the current base fee\n    pub fn set_base_fee(&self, fee: u64) {\n        trace!(target: \"backend::fees\", \"updated base fee {:?}\", fee);\n        let mut base = self.base_fee.write();\n        *base = fee;\n    }\n\n    /// Sets the current blob excess gas and price\n    pub fn set_blob_excess_gas_and_price(&self, blob_excess_gas_and_price: BlobExcessGasAndPrice) {\n        trace!(target: \"backend::fees\", \"updated blob base fee {:?}\", blob_excess_gas_and_price);\n        let mut base = self.blob_excess_gas_and_price.write();\n        *base = blob_excess_gas_and_price;\n    }\n\n    /// Calculates the base fee for the next block\n    pub fn get_next_block_base_fee_per_gas(\n        &self,\n        gas_used: u64,\n        gas_limit: u64,\n        last_fee_per_gas: u64,\n    ) -> u64 {\n        // It's naturally impossible for base fee to be 0;\n        // It means it was set by the user deliberately and therefore we treat it as a constant.\n        // Therefore, we skip the base fee calculation altogether and we return 0.\n        if self.base_fee() == 0 {\n            return 0;\n        }\n        calc_next_block_base_fee(gas_used, gas_limit, last_fee_per_gas, self.base_fee_params)\n    }\n\n    /// Calculates the next block blob base fee.\n    pub fn get_next_block_blob_base_fee_per_gas(&self) -> u128 {\n        self.blob_params().calc_blob_fee(self.blob_excess_gas_and_price.read().excess_blob_gas)\n    }\n\n    /// Calculates the next block blob excess gas, using the provided parent blob excess gas and\n    /// parent blob gas used\n    pub fn get_next_block_blob_excess_gas(&self, blob_excess_gas: u64, blob_gas_used: u64) -> u64 {\n        self.blob_params().next_block_excess_blob_gas_osaka(\n            blob_excess_gas,\n            blob_gas_used,\n            self.base_fee(),\n        )\n    }\n\n    /// Configures the blob params\n    pub fn set_blob_params(&self, blob_params: BlobParams) {\n        *self.blob_params.write() = blob_params;\n    }\n\n    /// Returns the active [`BlobParams`]\n    pub fn blob_params(&self) -> BlobParams {\n        *self.blob_params.read()\n    }\n}\n\n/// An async service that takes care of the `FeeHistory` cache\npub struct FeeHistoryService {\n    /// blob parameters for the current spec\n    blob_params: BlobParams,\n    /// incoming notifications about new blocks\n    new_blocks: NewBlockNotifications,\n    /// contains all fee history related entries\n    cache: FeeHistoryCache,\n    /// number of items to consider\n    fee_history_limit: u64,\n    /// a type that can fetch ethereum-storage data\n    storage_info: StorageInfo<FoundryNetwork>,\n}\n\nimpl FeeHistoryService {\n    pub fn new(\n        blob_params: BlobParams,\n        new_blocks: NewBlockNotifications,\n        cache: FeeHistoryCache,\n        storage_info: StorageInfo<FoundryNetwork>,\n    ) -> Self {\n        Self {\n            blob_params,\n            new_blocks,\n            cache,\n            fee_history_limit: MAX_FEE_HISTORY_CACHE_SIZE,\n            storage_info,\n        }\n    }\n\n    /// Returns the configured history limit\n    pub fn fee_history_limit(&self) -> u64 {\n        self.fee_history_limit\n    }\n\n    /// Inserts a new cache entry for the given block\n    pub(crate) fn insert_cache_entry_for_block(&self, hash: B256, header: &Header) {\n        let (result, block_number) = self.create_cache_entry(hash, header);\n        self.insert_cache_entry(result, block_number);\n    }\n\n    /// Create a new history entry for the block\n    fn create_cache_entry(\n        &self,\n        hash: B256,\n        header: &Header,\n    ) -> (FeeHistoryCacheItem, Option<u64>) {\n        // percentile list from 0.0 to 100.0 with a 0.5 resolution.\n        // this will create 200 percentile points\n        let reward_percentiles: Vec<f64> = {\n            let mut percentile: f64 = 0.0;\n            (0..=200)\n                .map(|_| {\n                    let val = percentile;\n                    percentile += 0.5;\n                    val\n                })\n                .collect()\n        };\n\n        let mut block_number: Option<u64> = None;\n        let base_fee = header.base_fee_per_gas.unwrap_or_default();\n        let excess_blob_gas = header.excess_blob_gas.map(|g| g as u128);\n        let blob_gas_used = header.blob_gas_used.map(|g| g as u128);\n        let base_fee_per_blob_gas = header.blob_fee(self.blob_params);\n\n        let mut item = FeeHistoryCacheItem {\n            base_fee: base_fee as u128,\n            gas_used_ratio: 0f64,\n            blob_gas_used_ratio: 0f64,\n            rewards: Vec::new(),\n            excess_blob_gas,\n            base_fee_per_blob_gas,\n            blob_gas_used,\n        };\n\n        let current_block = self.storage_info.block(hash);\n        let current_receipts = self.storage_info.receipts(hash);\n\n        if let (Some(block), Some(receipts)) = (current_block, current_receipts) {\n            block_number = Some(block.header.number());\n\n            let gas_used = block.header.gas_used() as f64;\n            let blob_gas_used = block.header.blob_gas_used().map(|g| g as f64);\n            item.gas_used_ratio = gas_used / block.header.gas_limit() as f64;\n            item.blob_gas_used_ratio = blob_gas_used\n                .map(|g| {\n                    let max = self.blob_params.max_blob_gas_per_block() as f64;\n                    if max == 0.0 { 0.0 } else { g / max }\n                })\n                .unwrap_or(0.0);\n\n            // extract useful tx info (gas_used, effective_reward)\n            let mut transactions: Vec<(_, _)> = receipts\n                .iter()\n                .enumerate()\n                .map(|(i, receipt)| {\n                    let cumulative = receipt.cumulative_gas_used();\n                    let prev_cumulative =\n                        if i > 0 { receipts[i - 1].cumulative_gas_used() } else { 0 };\n                    let gas_used = cumulative - prev_cumulative;\n                    let effective_reward = block\n                        .body\n                        .transactions\n                        .get(i)\n                        .map(|tx| tx.as_ref().effective_tip_per_gas(base_fee).unwrap_or(0))\n                        .unwrap_or(0);\n\n                    (gas_used, effective_reward)\n                })\n                .collect();\n\n            // sort by effective reward asc\n            transactions.sort_by_key(|(_, reward)| *reward);\n\n            // calculate percentile rewards\n            item.rewards = reward_percentiles\n                .into_iter()\n                .filter_map(|p| {\n                    let target_gas = (p * gas_used / 100f64) as u64;\n                    let mut sum_gas = 0;\n                    for (gas_used, effective_reward) in transactions.iter().copied() {\n                        sum_gas += gas_used;\n                        if target_gas <= sum_gas {\n                            return Some(effective_reward);\n                        }\n                    }\n                    None\n                })\n                .collect();\n        } else {\n            item.rewards = vec![0; reward_percentiles.len()];\n        }\n        (item, block_number)\n    }\n\n    fn insert_cache_entry(&self, item: FeeHistoryCacheItem, block_number: Option<u64>) {\n        if let Some(block_number) = block_number {\n            trace!(target: \"fees\", \"insert new history item={:?} for {}\", item, block_number);\n            let mut cache = self.cache.lock();\n            cache.insert(block_number, item);\n\n            // adhere to cache limit\n            let pop_next = block_number.saturating_sub(self.fee_history_limit);\n\n            let num_remove = (cache.len() as u64).saturating_sub(self.fee_history_limit);\n            for num in 0..num_remove {\n                let key = pop_next - num;\n                cache.remove(&key);\n            }\n        }\n    }\n}\n\n// An endless future that listens for new blocks and updates the cache\nimpl Future for FeeHistoryService {\n    type Output = ();\n\n    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {\n        let pin = self.get_mut();\n\n        while let Poll::Ready(Some(notification)) = pin.new_blocks.poll_next_unpin(cx) {\n            // add the imported block.\n            pin.insert_cache_entry_for_block(notification.hash, notification.header.as_ref());\n        }\n\n        Poll::Pending\n    }\n}\n\npub type FeeHistoryCache = Arc<Mutex<BTreeMap<u64, FeeHistoryCacheItem>>>;\n\n/// A single item in the whole fee history cache\n#[derive(Clone, Debug)]\npub struct FeeHistoryCacheItem {\n    pub base_fee: u128,\n    pub gas_used_ratio: f64,\n    pub base_fee_per_blob_gas: Option<u128>,\n    pub blob_gas_used_ratio: f64,\n    pub excess_blob_gas: Option<u128>,\n    pub blob_gas_used: Option<u128>,\n    pub rewards: Vec<u128>,\n}\n\n#[derive(Clone, Default)]\npub struct FeeDetails {\n    pub gas_price: Option<u128>,\n    pub max_fee_per_gas: Option<u128>,\n    pub max_priority_fee_per_gas: Option<u128>,\n    pub max_fee_per_blob_gas: Option<u128>,\n}\n\nimpl FeeDetails {\n    /// All values zero\n    pub fn zero() -> Self {\n        Self {\n            gas_price: Some(0),\n            max_fee_per_gas: Some(0),\n            max_priority_fee_per_gas: Some(0),\n            max_fee_per_blob_gas: None,\n        }\n    }\n\n    /// If neither `gas_price` nor `max_fee_per_gas` is `Some`, this will set both to `0`\n    pub fn or_zero_fees(self) -> Self {\n        let Self { gas_price, max_fee_per_gas, max_priority_fee_per_gas, max_fee_per_blob_gas } =\n            self;\n\n        let no_fees = gas_price.is_none() && max_fee_per_gas.is_none();\n        let gas_price = if no_fees { Some(0) } else { gas_price };\n        let max_fee_per_gas = if no_fees { Some(0) } else { max_fee_per_gas };\n        let max_fee_per_blob_gas = if no_fees { None } else { max_fee_per_blob_gas };\n\n        Self { gas_price, max_fee_per_gas, max_priority_fee_per_gas, max_fee_per_blob_gas }\n    }\n\n    /// Turns this type into a tuple\n    pub fn split(self) -> (Option<u128>, Option<u128>, Option<u128>, Option<u128>) {\n        let Self { gas_price, max_fee_per_gas, max_priority_fee_per_gas, max_fee_per_blob_gas } =\n            self;\n        (gas_price, max_fee_per_gas, max_priority_fee_per_gas, max_fee_per_blob_gas)\n    }\n\n    /// Creates a new instance from the request's gas related values\n    pub fn new(\n        request_gas_price: Option<u128>,\n        request_max_fee: Option<u128>,\n        request_priority: Option<u128>,\n        max_fee_per_blob_gas: Option<u128>,\n    ) -> Result<Self, BlockchainError> {\n        match (request_gas_price, request_max_fee, request_priority, max_fee_per_blob_gas) {\n            (gas_price, None, None, None) => {\n                // Legacy request, all default to gas price.\n                Ok(Self {\n                    gas_price,\n                    max_fee_per_gas: gas_price,\n                    max_priority_fee_per_gas: gas_price,\n                    max_fee_per_blob_gas: None,\n                })\n            }\n            (_, max_fee, max_priority, None) => {\n                // eip-1559\n                // Ensure `max_priority_fee_per_gas` is less or equal to `max_fee_per_gas`.\n                if let Some(max_priority) = max_priority {\n                    let max_fee = max_fee.unwrap_or_default();\n                    if max_priority > max_fee {\n                        return Err(BlockchainError::InvalidFeeInput);\n                    }\n                }\n                Ok(Self {\n                    gas_price: max_fee,\n                    max_fee_per_gas: max_fee,\n                    max_priority_fee_per_gas: max_priority,\n                    max_fee_per_blob_gas: None,\n                })\n            }\n            (_, max_fee, max_priority, max_fee_per_blob_gas) => {\n                // eip-1559\n                // Ensure `max_priority_fee_per_gas` is less or equal to `max_fee_per_gas`.\n                if let Some(max_priority) = max_priority {\n                    let max_fee = max_fee.unwrap_or_default();\n                    if max_priority > max_fee {\n                        return Err(BlockchainError::InvalidFeeInput);\n                    }\n                }\n                Ok(Self {\n                    gas_price: max_fee,\n                    max_fee_per_gas: max_fee,\n                    max_priority_fee_per_gas: max_priority,\n                    max_fee_per_blob_gas,\n                })\n            }\n        }\n    }\n}\n\nimpl fmt::Debug for FeeDetails {\n    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {\n        write!(fmt, \"Fees {{ \")?;\n        write!(fmt, \"gas_price: {:?}, \", self.gas_price)?;\n        write!(fmt, \"max_fee_per_gas: {:?}, \", self.max_fee_per_gas)?;\n        write!(fmt, \"max_priority_fee_per_gas: {:?}, \", self.max_priority_fee_per_gas)?;\n        write!(fmt, \"}}\")?;\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "crates/anvil/src/eth/macros.rs",
    "content": "/// A `info!` helper macro that emits to the target, the node logger listens for\nmacro_rules! node_info {\n    ($($arg:tt)*) => {\n         tracing::info!(target: $crate::logging::NODE_USER_LOG_TARGET, $($arg)*);\n    };\n}\n\npub(crate) use node_info;\n"
  },
  {
    "path": "crates/anvil/src/eth/miner.rs",
    "content": "//! Mines transactions\n\nuse crate::eth::pool::{Pool, transactions::PoolTransaction};\nuse alloy_primitives::TxHash;\nuse futures::{\n    channel::mpsc::Receiver,\n    stream::{Fuse, StreamExt},\n    task::AtomicWaker,\n};\nuse parking_lot::{RawRwLock, RwLock, lock_api::RwLockWriteGuard};\nuse std::{\n    fmt,\n    sync::Arc,\n    task::{Context, Poll, ready},\n    time::Duration,\n};\nuse tokio::time::{Interval, MissedTickBehavior};\n\npub struct Miner<T> {\n    /// The mode this miner currently operates in\n    mode: Arc<RwLock<MiningMode>>,\n    /// used for task wake up when the mining mode was forcefully changed\n    ///\n    /// This will register the task so we can manually wake it up if the mining mode was changed\n    inner: Arc<MinerInner>,\n    /// Transactions included into the pool before any others are.\n    /// Done once on startup.\n    force_transactions: Option<Vec<Arc<PoolTransaction<T>>>>,\n}\n\nimpl<T> Clone for Miner<T> {\n    fn clone(&self) -> Self {\n        Self {\n            mode: self.mode.clone(),\n            inner: self.inner.clone(),\n            force_transactions: self.force_transactions.clone(),\n        }\n    }\n}\n\nimpl<T> fmt::Debug for Miner<T> {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.debug_struct(\"Miner\")\n            .field(\"mode\", &self.mode)\n            .field(\"force_transactions\", &self.force_transactions.as_ref().map(|txs| txs.len()))\n            .finish_non_exhaustive()\n    }\n}\n\nimpl<T> Miner<T> {\n    /// Returns a new miner with that operates in the given `mode`.\n    pub fn new(mode: MiningMode) -> Self {\n        Self {\n            mode: Arc::new(RwLock::new(mode)),\n            inner: Default::default(),\n            force_transactions: None,\n        }\n    }\n\n    /// Provide transactions that will cause a block to be mined with transactions\n    /// as soon as the miner is polled.\n    /// Providing an empty list of transactions will cause the miner to mine an empty block assuming\n    /// there are not other transactions in the pool.\n    pub fn with_forced_transactions(\n        mut self,\n        force_transactions: Option<Vec<PoolTransaction<T>>>,\n    ) -> Self {\n        self.force_transactions =\n            force_transactions.map(|tx| tx.into_iter().map(Arc::new).collect());\n        self\n    }\n\n    /// Returns the write lock of the mining mode\n    pub fn mode_write(&self) -> RwLockWriteGuard<'_, RawRwLock, MiningMode> {\n        self.mode.write()\n    }\n\n    /// Returns `true` if auto mining is enabled\n    pub fn is_auto_mine(&self) -> bool {\n        let mode = self.mode.read();\n        matches!(*mode, MiningMode::Auto(_))\n    }\n\n    pub fn get_interval(&self) -> Option<u64> {\n        let mode = self.mode.read();\n        if let MiningMode::FixedBlockTime(ref mm) = *mode {\n            return Some(mm.interval.period().as_secs());\n        }\n        None\n    }\n\n    /// Sets the mining mode to operate in\n    pub fn set_mining_mode(&self, mode: MiningMode) {\n        let new_mode = format!(\"{mode:?}\");\n        let mode = std::mem::replace(&mut *self.mode_write(), mode);\n        trace!(target: \"miner\", \"updated mining mode from {:?} to {}\", mode, new_mode);\n        self.inner.wake();\n    }\n\n    /// polls the [Pool] and returns those transactions that should be put in a block according to\n    /// the current mode.\n    ///\n    /// May return an empty list, if no transactions are ready.\n    pub fn poll(\n        &mut self,\n        pool: &Arc<Pool<T>>,\n        cx: &mut Context<'_>,\n    ) -> Poll<Vec<Arc<PoolTransaction<T>>>> {\n        self.inner.register(cx);\n        let next = ready!(self.mode.write().poll(pool, cx));\n        if let Some(mut transactions) = self.force_transactions.take() {\n            transactions.extend(next);\n            Poll::Ready(transactions)\n        } else {\n            Poll::Ready(next)\n        }\n    }\n}\n\n/// A Mining mode that does nothing\n#[derive(Debug)]\npub struct MinerInner {\n    waker: AtomicWaker,\n}\n\nimpl MinerInner {\n    /// Call the waker again\n    fn wake(&self) {\n        self.waker.wake();\n    }\n\n    fn register(&self, cx: &Context<'_>) {\n        self.waker.register(cx.waker());\n    }\n}\n\nimpl Default for MinerInner {\n    fn default() -> Self {\n        Self { waker: AtomicWaker::new() }\n    }\n}\n\n/// Mode of operations for the `Miner`\n#[derive(Debug)]\npub enum MiningMode {\n    /// A miner that does nothing\n    None,\n    /// A miner that listens for new transactions that are ready.\n    ///\n    /// Either one transaction will be mined per block, or any number of transactions will be\n    /// allowed\n    Auto(ReadyTransactionMiner),\n    /// A miner that constructs a new block every `interval` tick\n    FixedBlockTime(FixedBlockTimeMiner),\n\n    /// A miner that uses both Auto and FixedBlockTime\n    Mixed(ReadyTransactionMiner, FixedBlockTimeMiner),\n}\n\nimpl MiningMode {\n    pub fn instant(max_transactions: usize, listener: Receiver<TxHash>) -> Self {\n        Self::Auto(ReadyTransactionMiner {\n            max_transactions,\n            has_pending_txs: None,\n            rx: listener.fuse(),\n        })\n    }\n\n    pub fn interval(duration: Duration) -> Self {\n        Self::FixedBlockTime(FixedBlockTimeMiner::new(duration))\n    }\n\n    pub fn mixed(max_transactions: usize, listener: Receiver<TxHash>, duration: Duration) -> Self {\n        Self::Mixed(\n            ReadyTransactionMiner { max_transactions, has_pending_txs: None, rx: listener.fuse() },\n            FixedBlockTimeMiner::new(duration),\n        )\n    }\n\n    /// polls the [Pool] and returns those transactions that should be put in a block, if any.\n    pub fn poll<T>(\n        &mut self,\n        pool: &Arc<Pool<T>>,\n        cx: &mut Context<'_>,\n    ) -> Poll<Vec<Arc<PoolTransaction<T>>>> {\n        match self {\n            Self::None => Poll::Pending,\n            Self::Auto(miner) => miner.poll(pool, cx),\n            Self::FixedBlockTime(miner) => miner.poll(pool, cx),\n            Self::Mixed(auto, fixed) => {\n                let auto_txs = auto.poll(pool, cx);\n                let fixed_txs = fixed.poll(pool, cx);\n\n                match (auto_txs, fixed_txs) {\n                    // Both auto and fixed transactions are ready, combine them\n                    (Poll::Ready(mut auto_txs), Poll::Ready(fixed_txs)) => {\n                        for tx in fixed_txs {\n                            // filter unique transactions\n                            if auto_txs.iter().any(|auto_tx| auto_tx.hash() == tx.hash()) {\n                                continue;\n                            }\n                            auto_txs.push(tx);\n                        }\n                        Poll::Ready(auto_txs)\n                    }\n                    // Only auto transactions are ready, return them\n                    (Poll::Ready(auto_txs), Poll::Pending) => Poll::Ready(auto_txs),\n                    // Only fixed transactions are ready or both are pending,\n                    // return fixed transactions or pending status\n                    (Poll::Pending, fixed_txs) => fixed_txs,\n                }\n            }\n        }\n    }\n}\n\n/// A miner that's supposed to create a new block every `interval`, mining all transactions that are\n/// ready at that time.\n///\n/// The default blocktime is set to 6 seconds\n#[derive(Debug)]\npub struct FixedBlockTimeMiner {\n    /// The interval this fixed block time miner operates with\n    interval: Interval,\n}\n\nimpl FixedBlockTimeMiner {\n    /// Creates a new instance with an interval of `duration`\n    pub fn new(duration: Duration) -> Self {\n        let start = tokio::time::Instant::now() + duration;\n        let mut interval = tokio::time::interval_at(start, duration);\n        // we use delay here, to ensure ticks are not shortened and to tick at multiples of interval\n        // from when tick was called rather than from start\n        interval.set_missed_tick_behavior(MissedTickBehavior::Delay);\n        Self { interval }\n    }\n\n    fn poll<T>(\n        &mut self,\n        pool: &Arc<Pool<T>>,\n        cx: &mut Context<'_>,\n    ) -> Poll<Vec<Arc<PoolTransaction<T>>>> {\n        if self.interval.poll_tick(cx).is_ready() {\n            // drain the pool\n            return Poll::Ready(pool.ready_transactions().collect());\n        }\n        Poll::Pending\n    }\n}\n\nimpl Default for FixedBlockTimeMiner {\n    fn default() -> Self {\n        Self::new(Duration::from_secs(6))\n    }\n}\n\n/// A miner that Listens for new ready transactions\npub struct ReadyTransactionMiner {\n    /// how many transactions to mine per block\n    max_transactions: usize,\n    /// stores whether there are pending transactions (if known)\n    has_pending_txs: Option<bool>,\n    /// Receives hashes of transactions that are ready\n    rx: Fuse<Receiver<TxHash>>,\n}\n\nimpl ReadyTransactionMiner {\n    fn poll<T>(\n        &mut self,\n        pool: &Arc<Pool<T>>,\n        cx: &mut Context<'_>,\n    ) -> Poll<Vec<Arc<PoolTransaction<T>>>> {\n        // always drain the notification stream so that we're woken up as soon as there's a new tx\n        while let Poll::Ready(Some(_hash)) = self.rx.poll_next_unpin(cx) {\n            self.has_pending_txs = Some(true);\n        }\n\n        if self.has_pending_txs == Some(false) {\n            return Poll::Pending;\n        }\n\n        let transactions =\n            pool.ready_transactions().take(self.max_transactions).collect::<Vec<_>>();\n\n        // there are pending transactions if we didn't drain the pool\n        self.has_pending_txs = Some(transactions.len() >= self.max_transactions);\n\n        if transactions.is_empty() {\n            return Poll::Pending;\n        }\n\n        Poll::Ready(transactions)\n    }\n}\n\nimpl fmt::Debug for ReadyTransactionMiner {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.debug_struct(\"ReadyTransactionMiner\")\n            .field(\"max_transactions\", &self.max_transactions)\n            .finish_non_exhaustive()\n    }\n}\n"
  },
  {
    "path": "crates/anvil/src/eth/mod.rs",
    "content": "pub mod api;\npub mod otterscan;\npub mod sign;\npub use api::EthApi;\n\npub mod backend;\n\npub mod error;\n\npub mod fees;\npub(crate) mod macros;\npub mod miner;\npub mod pool;\npub mod util;\n"
  },
  {
    "path": "crates/anvil/src/eth/otterscan/api.rs",
    "content": "use crate::eth::{\n    EthApi,\n    error::{BlockchainError, Result},\n    macros::node_info,\n};\nuse alloy_consensus::{BlockHeader, Transaction as TransactionTrait};\nuse alloy_network::{\n    AnyHeader, AnyRpcBlock, AnyRpcHeader, AnyRpcTransaction, AnyTxEnvelope, BlockResponse,\n    ReceiptResponse, TransactionResponse,\n};\nuse alloy_primitives::{Address, B256, Bytes, U256};\nuse alloy_rpc_types::{\n    Block, BlockId, BlockNumberOrTag as BlockNumber, BlockTransactions,\n    trace::{\n        otterscan::{\n            BlockDetails, ContractCreator, InternalOperation, OtsBlock, OtsBlockTransactions,\n            OtsReceipt, OtsSlimBlock, OtsTransactionReceipt, TraceEntry, TransactionsWithReceipts,\n        },\n        parity::{Action, CreateAction, CreateOutput, TraceOutput},\n    },\n};\nuse foundry_primitives::FoundryNetwork;\nuse futures::future::join_all;\nuse itertools::Itertools;\n\nimpl EthApi<FoundryNetwork> {\n    /// Otterscan currently requires this endpoint, even though it's not part of the `ots_*`.\n    /// Ref: <https://github.com/otterscan/otterscan/blob/071d8c55202badf01804f6f8d53ef9311d4a9e47/src/useProvider.ts#L71>\n    ///\n    /// As a faster alternative to `eth_getBlockByNumber` (by excluding uncle block\n    /// information), which is not relevant in the context of an anvil node\n    pub async fn erigon_get_header_by_number(\n        &self,\n        number: BlockNumber,\n    ) -> Result<Option<AnyRpcBlock>> {\n        node_info!(\"erigon_getHeaderByNumber\");\n\n        self.backend.block_by_number(number).await\n    }\n\n    /// As per the latest Otterscan source code, at least version 8 is needed.\n    /// Ref: <https://github.com/otterscan/otterscan/blob/071d8c55202badf01804f6f8d53ef9311d4a9e47/src/params.ts#L1C2-L1C2>\n    pub async fn ots_get_api_level(&self) -> Result<u64> {\n        node_info!(\"ots_getApiLevel\");\n\n        // as required by current otterscan's source code\n        Ok(8)\n    }\n\n    /// Trace internal ETH transfers, contracts creation (CREATE/CREATE2) and self-destructs for a\n    /// certain transaction.\n    pub async fn ots_get_internal_operations(&self, hash: B256) -> Result<Vec<InternalOperation>> {\n        node_info!(\"ots_getInternalOperations\");\n\n        self.backend\n            .mined_transaction(hash)\n            .map(|tx| tx.ots_internal_operations())\n            .ok_or_else(|| BlockchainError::DataUnavailable)\n    }\n\n    /// Check if an ETH address contains code at a certain block number.\n    pub async fn ots_has_code(&self, address: Address, block_number: BlockNumber) -> Result<bool> {\n        node_info!(\"ots_hasCode\");\n        let block_id = Some(BlockId::Number(block_number));\n        Ok(!self.get_code(address, block_id).await?.is_empty())\n    }\n\n    /// Trace a transaction and generate a trace call tree.\n    /// Converts the list of traces for a transaction into the expected Otterscan format.\n    ///\n    /// Follows format specified in the [`ots_traceTransaction`](https://docs.otterscan.io/api-docs/ots-api#ots_tracetransaction) spec.\n    pub async fn ots_trace_transaction(&self, hash: B256) -> Result<Vec<TraceEntry>> {\n        node_info!(\"ots_traceTransaction\");\n        let traces = self\n            .backend\n            .trace_transaction(hash)\n            .await?\n            .into_iter()\n            .filter_map(|trace| TraceEntry::from_transaction_trace(&trace.trace))\n            .collect();\n        Ok(traces)\n    }\n\n    /// Given a transaction hash, returns its raw revert reason.\n    pub async fn ots_get_transaction_error(&self, hash: B256) -> Result<Bytes> {\n        node_info!(\"ots_getTransactionError\");\n\n        if let Some(receipt) = self.backend.mined_transaction_receipt(hash)\n            && !receipt.inner.as_ref().status()\n        {\n            return Ok(receipt.out.unwrap_or_default());\n        }\n\n        Ok(Bytes::default())\n    }\n\n    /// For simplicity purposes, we return the entire block instead of emptying the values that\n    /// Otterscan doesn't want. This is the original purpose of the endpoint (to save bandwidth),\n    /// but it doesn't seem necessary in the context of an anvil node\n    pub async fn ots_get_block_details(\n        &self,\n        number: BlockNumber,\n    ) -> Result<BlockDetails<AnyRpcHeader>> {\n        node_info!(\"ots_getBlockDetails\");\n\n        if let Some(block) = self.backend.block_by_number(number).await? {\n            let ots_block = self.build_ots_block_details(block).await?;\n            Ok(ots_block)\n        } else {\n            Err(BlockchainError::BlockNotFound)\n        }\n    }\n\n    /// For simplicity purposes, we return the entire block instead of emptying the values that\n    /// Otterscan doesn't want. This is the original purpose of the endpoint (to save bandwidth),\n    /// but it doesn't seem necessary in the context of an anvil node\n    pub async fn ots_get_block_details_by_hash(\n        &self,\n        hash: B256,\n    ) -> Result<BlockDetails<AnyRpcHeader>> {\n        node_info!(\"ots_getBlockDetailsByHash\");\n\n        if let Some(block) = self.backend.block_by_hash(hash).await? {\n            let ots_block = self.build_ots_block_details(block).await?;\n            Ok(ots_block)\n        } else {\n            Err(BlockchainError::BlockNotFound)\n        }\n    }\n\n    /// Gets paginated transaction data for a certain block. Return data is similar to\n    /// eth_getBlockBy* + eth_getTransactionReceipt.\n    pub async fn ots_get_block_transactions(\n        &self,\n        number: u64,\n        page: usize,\n        page_size: usize,\n    ) -> Result<OtsBlockTransactions<AnyRpcTransaction, AnyRpcHeader>> {\n        node_info!(\"ots_getBlockTransactions\");\n\n        match self.backend.block_by_number_full(number.into()).await? {\n            Some(block) => self.build_ots_block_tx(block, page, page_size).await,\n            None => Err(BlockchainError::BlockNotFound),\n        }\n    }\n\n    /// Address history navigation. searches backwards from certain point in time.\n    pub async fn ots_search_transactions_before(\n        &self,\n        address: Address,\n        block_number: u64,\n        page_size: usize,\n    ) -> Result<TransactionsWithReceipts<alloy_rpc_types::Transaction<AnyTxEnvelope>>> {\n        node_info!(\"ots_searchTransactionsBefore\");\n\n        let best = self.backend.best_number();\n        // we go from given block (defaulting to best) down to first block\n        // considering only post-fork\n        let from = if block_number == 0 { best } else { block_number - 1 };\n        let to = self.get_fork().map(|f| f.block_number() + 1).unwrap_or(1);\n\n        let first_page = from >= best;\n        let mut last_page = false;\n\n        let mut res: Vec<_> = vec![];\n\n        for n in (to..=from).rev() {\n            if let Some(traces) = self.backend.mined_parity_trace_block(n) {\n                let hashes = traces\n                    .into_iter()\n                    .rev()\n                    .filter(|trace| trace.contains_address(address))\n                    .filter_map(|trace| trace.transaction_hash)\n                    .unique();\n\n                if res.len() >= page_size {\n                    break;\n                }\n\n                res.extend(hashes);\n            }\n\n            if n == to {\n                last_page = true;\n            }\n        }\n\n        self.build_ots_search_transactions(res, first_page, last_page).await\n    }\n\n    /// Address history navigation. searches forward from certain point in time.\n    pub async fn ots_search_transactions_after(\n        &self,\n        address: Address,\n        block_number: u64,\n        page_size: usize,\n    ) -> Result<TransactionsWithReceipts<alloy_rpc_types::Transaction<AnyTxEnvelope>>> {\n        node_info!(\"ots_searchTransactionsAfter\");\n\n        let best = self.backend.best_number();\n        // we go from the first post-fork block, up to the tip\n        let first_block = self.get_fork().map(|f| f.block_number() + 1).unwrap_or(1);\n        let from = if block_number == 0 { first_block } else { block_number + 1 };\n        let to = best;\n\n        let mut first_page = from >= best;\n        let mut last_page = false;\n\n        let mut res: Vec<_> = vec![];\n\n        for n in from..=to {\n            if n == first_block {\n                last_page = true;\n            }\n\n            if let Some(traces) = self.backend.mined_parity_trace_block(n) {\n                let hashes = traces\n                    .into_iter()\n                    .rev()\n                    .filter(|trace| trace.contains_address(address))\n                    .filter_map(|trace| trace.transaction_hash)\n                    .unique();\n\n                if res.len() >= page_size {\n                    break;\n                }\n\n                res.extend(hashes);\n            }\n\n            if n == to {\n                first_page = true;\n            }\n        }\n\n        // Results are always sent in reverse chronological order, according to the Otterscan spec\n        res.reverse();\n        self.build_ots_search_transactions(res, first_page, last_page).await\n    }\n\n    /// Given a sender address and a nonce, returns the tx hash or null if not found. It returns\n    /// only the tx hash on success, you can use the standard eth_getTransactionByHash after that to\n    /// get the full transaction data.\n    pub async fn ots_get_transaction_by_sender_and_nonce(\n        &self,\n        address: Address,\n        nonce: U256,\n    ) -> Result<Option<B256>> {\n        node_info!(\"ots_getTransactionBySenderAndNonce\");\n\n        let from = self.get_fork().map(|f| f.block_number() + 1).unwrap_or_default();\n        let to = self.backend.best_number();\n\n        for n in (from..=to).rev() {\n            if let Some(txs) = self.backend.mined_transactions_by_block_number(n.into()).await {\n                for tx in txs {\n                    if U256::from(tx.nonce()) == nonce && tx.from() == address {\n                        return Ok(Some(tx.tx_hash()));\n                    }\n                }\n            }\n        }\n\n        Ok(None)\n    }\n\n    /// Given an ETH contract address, returns the tx hash and the direct address who created the\n    /// contract.\n    pub async fn ots_get_contract_creator(&self, addr: Address) -> Result<Option<ContractCreator>> {\n        node_info!(\"ots_getContractCreator\");\n\n        let from = self.get_fork().map(|f| f.block_number()).unwrap_or_default();\n        let to = self.backend.best_number();\n\n        // loop in reverse, since we want the latest deploy to the address\n        for n in (from..=to).rev() {\n            if let Some(traces) = self.backend.mined_parity_trace_block(n) {\n                for trace in traces.into_iter().rev() {\n                    match (trace.trace.action, trace.trace.result) {\n                        (\n                            Action::Create(CreateAction { from, .. }),\n                            Some(TraceOutput::Create(CreateOutput { address, .. })),\n                        ) if address == addr => {\n                            return Ok(Some(ContractCreator {\n                                hash: trace.transaction_hash.unwrap(),\n                                creator: from,\n                            }));\n                        }\n                        _ => {}\n                    }\n                }\n            }\n        }\n\n        Ok(None)\n    }\n    /// The response for ots_getBlockDetails includes an `issuance` object that requires computing\n    /// the total gas spent in a given block.\n    ///\n    /// The only way to do this with the existing API is to explicitly fetch all receipts, to get\n    /// their `gas_used`. This would be extremely inefficient in a real blockchain RPC, but we can\n    /// get away with that in this context.\n    ///\n    /// The [original spec](https://docs.otterscan.io/api-docs/ots-api#ots_getblockdetails)\n    /// also mentions we can hardcode `transactions` and `logsBloom` to an empty array to save\n    /// bandwidth, because fields weren't intended to be used in the Otterscan UI at this point.\n    ///\n    /// This has two problems though:\n    ///   - It makes the endpoint too specific to Otterscan's implementation\n    ///   - It breaks the abstraction built in `OtsBlock<TX>` which computes `transaction_count`\n    ///     based on the existing list.\n    ///\n    /// Therefore we keep it simple by keeping the data in the response\n    pub async fn build_ots_block_details(\n        &self,\n        block: AnyRpcBlock,\n    ) -> Result<BlockDetails<alloy_rpc_types::Header<AnyHeader>>> {\n        if block.transactions.is_uncle() {\n            return Err(BlockchainError::DataUnavailable);\n        }\n        let receipts_futs = block\n            .transactions\n            .hashes()\n            .map(|hash| async move { self.transaction_receipt(hash).await });\n\n        // fetch all receipts\n        let receipts = join_all(receipts_futs)\n            .await\n            .into_iter()\n            .map(|r| match r {\n                Ok(Some(r)) => Ok(r),\n                _ => Err(BlockchainError::DataUnavailable),\n            })\n            .collect::<Result<Vec<_>>>()?;\n\n        let total_fees = receipts.iter().fold(0, |acc, receipt| {\n            acc + (receipt.gas_used() as u128) * receipt.effective_gas_price()\n        });\n\n        let Block { header, uncles, transactions, withdrawals } = block.into_inner();\n\n        let block =\n            OtsSlimBlock { header, uncles, transaction_count: transactions.len(), withdrawals };\n\n        Ok(BlockDetails {\n            block,\n            total_fees: U256::from(total_fees),\n            // issuance has no meaningful value in anvil's backend. just default to 0\n            issuance: Default::default(),\n        })\n    }\n\n    /// Fetches all receipts for the blocks's transactions, as required by the\n    /// [`ots_getBlockTransactions`] endpoint spec, and returns the final response object.\n    ///\n    /// [`ots_getBlockTransactions`]: https://docs.otterscan.io/api-docs/ots-api#ots_getblocktransactions\n    pub async fn build_ots_block_tx(\n        &self,\n        mut block: AnyRpcBlock,\n        page: usize,\n        page_size: usize,\n    ) -> Result<OtsBlockTransactions<AnyRpcTransaction, AnyRpcHeader>> {\n        if block.transactions.is_uncle() {\n            return Err(BlockchainError::DataUnavailable);\n        }\n\n        block.transactions = match block.transactions() {\n            BlockTransactions::Full(txs) => BlockTransactions::Full(\n                txs.iter().skip(page * page_size).take(page_size).cloned().collect(),\n            ),\n            BlockTransactions::Hashes(txs) => BlockTransactions::Hashes(\n                txs.iter().skip(page * page_size).take(page_size).copied().collect(),\n            ),\n            BlockTransactions::Uncle => unreachable!(),\n        };\n\n        let receipt_futs = block.transactions.hashes().map(|hash| self.transaction_receipt(hash));\n\n        // Reuse timestamp from the block we already have\n        let timestamp = block.header.timestamp();\n\n        let receipts = join_all(receipt_futs.map(|r| async move {\n            if let Ok(Some(r)) = r.await {\n                let receipt = r.as_ref().inner.clone().map_inner(OtsReceipt::from);\n                Ok(OtsTransactionReceipt { receipt, timestamp: Some(timestamp) })\n            } else {\n                Err(BlockchainError::BlockNotFound)\n            }\n        }))\n        .await\n        .into_iter()\n        .collect::<Result<Vec<_>>>()?;\n\n        let transaction_count = block.transactions().len();\n        let fullblock = OtsBlock { block: block.inner.clone(), transaction_count };\n\n        let ots_block_txs = OtsBlockTransactions { fullblock, receipts };\n\n        Ok(ots_block_txs)\n    }\n\n    pub async fn build_ots_search_transactions(\n        &self,\n        hashes: Vec<B256>,\n        first_page: bool,\n        last_page: bool,\n    ) -> Result<TransactionsWithReceipts<alloy_rpc_types::Transaction<AnyTxEnvelope>>> {\n        let txs_futs = hashes.iter().map(|hash| async { self.transaction_by_hash(*hash).await });\n\n        let txs = join_all(txs_futs)\n            .await\n            .into_iter()\n            .map(|t| match t {\n                Ok(Some(t)) => Ok(t.into_inner()),\n                _ => Err(BlockchainError::DataUnavailable),\n            })\n            .collect::<Result<Vec<_>>>()?;\n\n        let receipt_futs = hashes.iter().map(|hash| self.transaction_receipt(*hash));\n\n        let receipts = join_all(receipt_futs.map(|r| async {\n            if let Ok(Some(r)) = r.await {\n                // Try to get timestamp from receipt's other fields first (set by mined receipts),\n                // fallback to block lookup for fork receipts that may not have it\n                let timestamp = if let Some(ts) = r.block_timestamp() {\n                    ts\n                } else {\n                    let block = self.block_by_number(r.block_number().unwrap().into()).await?;\n                    block.ok_or(BlockchainError::BlockNotFound)?.header.timestamp()\n                };\n                let receipt = r.as_ref().inner.clone().map_inner(OtsReceipt::from);\n                Ok(OtsTransactionReceipt { receipt, timestamp: Some(timestamp) })\n            } else {\n                Err(BlockchainError::BlockNotFound)\n            }\n        }))\n        .await\n        .into_iter()\n        .collect::<Result<Vec<_>>>()?;\n\n        Ok(TransactionsWithReceipts { txs, receipts, first_page, last_page })\n    }\n}\n"
  },
  {
    "path": "crates/anvil/src/eth/otterscan/mod.rs",
    "content": "pub mod api;\n"
  },
  {
    "path": "crates/anvil/src/eth/pool/mod.rs",
    "content": "//! # Transaction Pool implementation\n//!\n//! The transaction pool is responsible for managing a set of transactions that can be included in\n//! upcoming blocks.\n//!\n//! The main task of the pool is to prepare an ordered list of transactions that are ready to be\n//! included in a new block.\n//!\n//! Each imported block can affect the validity of transactions already in the pool.\n//! The miner expects the most up-to-date transactions when attempting to create a new block.\n//! After being included in a block, a transaction should be removed from the pool, this process is\n//! called _pruning_ and due to separation of concerns is triggered externally.\n//! The pool essentially performs following services:\n//!   * import transactions\n//!   * order transactions\n//!   * provide ordered set of transactions that are ready for inclusion\n//!   * prune transactions\n//!\n//! Each transaction in the pool contains markers that it _provides_ or _requires_. This property is\n//! used to determine whether it can be included in a block (transaction is ready) or whether it\n//! still _requires_ other transactions to be mined first (transaction is pending).\n//! A transaction is associated with the nonce of the account it's sent from. A unique identifying\n//! marker for a transaction is therefore the pair `(nonce + account)`. An incoming transaction with\n//! a `nonce > nonce on chain` will _require_ `(nonce -1, account)` first, before it is ready to be\n//! included in a block.\n//!\n//! This implementation is adapted from <https://github.com/paritytech/substrate/tree/master/client/transaction-pool>\n\nuse crate::{\n    eth::{\n        error::PoolError,\n        pool::transactions::{\n            PendingPoolTransaction, PendingTransactions, PoolTransaction, ReadyTransactions,\n            TransactionsIterator, TxMarker,\n        },\n    },\n    mem::storage::MinedBlockOutcome,\n};\nuse alloy_consensus::Transaction;\nuse alloy_primitives::{Address, TxHash};\nuse alloy_rpc_types::txpool::TxpoolStatus;\nuse anvil_core::eth::transaction::PendingTransaction;\nuse futures::channel::mpsc::{Receiver, Sender, channel};\nuse parking_lot::{Mutex, RwLock};\nuse std::{collections::VecDeque, fmt, sync::Arc};\n\npub mod transactions;\n\n/// Transaction pool that performs validation.\npub struct Pool<T> {\n    /// processes all pending transactions\n    inner: RwLock<PoolInner<T>>,\n    /// listeners for new ready transactions\n    transaction_listener: Mutex<Vec<Sender<TxHash>>>,\n}\n\nimpl<T> Default for Pool<T> {\n    fn default() -> Self {\n        Self { inner: RwLock::new(PoolInner::default()), transaction_listener: Default::default() }\n    }\n}\n\n// == impl Pool ==\n\nimpl<T> Pool<T> {\n    /// Returns an iterator that yields all transactions that are currently ready\n    pub fn ready_transactions(&self) -> TransactionsIterator<T> {\n        self.inner.read().ready_transactions()\n    }\n\n    /// Returns all transactions that are not ready to be included in a block yet\n    pub fn pending_transactions(&self) -> Vec<Arc<PoolTransaction<T>>> {\n        self.inner.read().pending_transactions.transactions().collect()\n    }\n\n    /// Returns the number of tx that are ready and queued for further execution\n    pub fn txpool_status(&self) -> TxpoolStatus {\n        // Note: naming differs here compared to geth's `TxpoolStatus`\n        let pending: u64 = self.inner.read().ready_transactions.len().try_into().unwrap_or(0);\n        let queued: u64 = self.inner.read().pending_transactions.len().try_into().unwrap_or(0);\n        TxpoolStatus { pending, queued }\n    }\n\n    /// Adds a new transaction listener to the pool that gets notified about every new ready\n    /// transaction\n    pub fn add_ready_listener(&self) -> Receiver<TxHash> {\n        const TX_LISTENER_BUFFER_SIZE: usize = 2048;\n        let (tx, rx) = channel(TX_LISTENER_BUFFER_SIZE);\n        self.transaction_listener.lock().push(tx);\n        rx\n    }\n\n    /// Returns true if this pool already contains the transaction\n    pub fn contains(&self, tx_hash: &TxHash) -> bool {\n        self.inner.read().contains(tx_hash)\n    }\n\n    /// Removes all transactions from the pool\n    pub fn clear(&self) {\n        let mut pool = self.inner.write();\n        pool.clear();\n    }\n\n    /// Remove the given transactions from the pool\n    pub fn remove_invalid(&self, tx_hashes: Vec<TxHash>) -> Vec<Arc<PoolTransaction<T>>> {\n        self.inner.write().remove_invalid(tx_hashes)\n    }\n\n    /// Remove transactions by sender\n    pub fn remove_transactions_by_address(&self, sender: Address) -> Vec<Arc<PoolTransaction<T>>> {\n        self.inner.write().remove_transactions_by_address(sender)\n    }\n\n    /// Removes a single transaction from the pool\n    ///\n    /// This is similar to `[Pool::remove_invalid()]` but for a single transaction.\n    ///\n    /// **Note**: this will also drop any transaction that depend on the `tx`\n    pub fn drop_transaction(&self, tx: TxHash) -> Option<Arc<PoolTransaction<T>>> {\n        trace!(target: \"txpool\", \"Dropping transaction: [{:?}]\", tx);\n        let removed = {\n            let mut pool = self.inner.write();\n            pool.ready_transactions.remove_with_markers(vec![tx], None)\n        };\n        trace!(target: \"txpool\", \"Dropped transactions: {:?}\", removed.iter().map(|tx| tx.hash()).collect::<Vec<_>>());\n\n        let mut dropped = None;\n        if !removed.is_empty() {\n            dropped = removed.into_iter().find(|t| *t.pending_transaction.hash() == tx);\n        }\n        dropped\n    }\n\n    /// Notifies listeners if the transaction was added to the ready queue.\n    fn notify_ready(&self, tx: &AddedTransaction<T>) {\n        if let AddedTransaction::Ready(ready) = tx {\n            self.notify_listener(ready.hash);\n            for promoted in ready.promoted.iter().copied() {\n                self.notify_listener(promoted);\n            }\n        }\n    }\n\n    /// notifies all listeners about the transaction\n    fn notify_listener(&self, hash: TxHash) {\n        let mut listener = self.transaction_listener.lock();\n        // this is basically a retain but with mut reference\n        for n in (0..listener.len()).rev() {\n            let mut listener_tx = listener.swap_remove(n);\n            let retain = match listener_tx.try_send(hash) {\n                Ok(()) => true,\n                Err(e) => {\n                    if e.is_full() {\n                        warn!(\n                            target: \"txpool\",\n                            \"[{:?}] Failed to send tx notification because channel is full\",\n                            hash,\n                        );\n                        true\n                    } else {\n                        false\n                    }\n                }\n            };\n            if retain {\n                listener.push(listener_tx)\n            }\n        }\n    }\n}\n\nimpl<T: Clone> Pool<T> {\n    /// Returns the _pending_ transaction for that `hash` if it exists in the mempool\n    pub fn get_transaction(&self, hash: TxHash) -> Option<PendingTransaction<T>> {\n        self.inner.read().get_transaction(hash)\n    }\n}\n\nimpl<T: Transaction> Pool<T> {\n    /// Invoked when a set of transactions ([Self::ready_transactions()]) was executed.\n    ///\n    /// This will remove the transactions from the pool.\n    pub fn on_mined_block(&self, outcome: MinedBlockOutcome<T>) -> PruneResult<T> {\n        let MinedBlockOutcome { block_number, included, invalid } = outcome;\n\n        // remove invalid transactions from the pool\n        self.remove_invalid(invalid.into_iter().map(|tx| tx.hash()).collect());\n\n        // prune all the markers the mined transactions provide\n        let res = self\n            .prune_markers(block_number, included.into_iter().flat_map(|tx| tx.provides.clone()));\n        trace!(target: \"txpool\", \"pruned transaction markers {:?}\", res);\n        res\n    }\n\n    /// Removes ready transactions for the given iterator of identifying markers.\n    ///\n    /// For each marker we can remove transactions in the pool that either provide the marker\n    /// directly or are a dependency of the transaction associated with that marker.\n    pub fn prune_markers(\n        &self,\n        block_number: u64,\n        markers: impl IntoIterator<Item = TxMarker>,\n    ) -> PruneResult<T> {\n        debug!(target: \"txpool\", ?block_number, \"pruning transactions\");\n        let res = self.inner.write().prune_markers(markers);\n        for tx in &res.promoted {\n            self.notify_ready(tx);\n        }\n        res\n    }\n\n    /// Adds a new transaction to the pool\n    pub fn add_transaction(\n        &self,\n        tx: PoolTransaction<T>,\n    ) -> Result<AddedTransaction<T>, PoolError> {\n        let added = self.inner.write().add_transaction(tx)?;\n        self.notify_ready(&added);\n        Ok(added)\n    }\n}\n\n/// A Transaction Pool\n///\n/// Contains all transactions that are ready to be executed\n#[derive(Debug)]\nstruct PoolInner<T> {\n    ready_transactions: ReadyTransactions<T>,\n    pending_transactions: PendingTransactions<T>,\n}\n\nimpl<T> Default for PoolInner<T> {\n    fn default() -> Self {\n        Self { ready_transactions: Default::default(), pending_transactions: Default::default() }\n    }\n}\n\n// == impl PoolInner ==\n\nimpl<T> PoolInner<T> {\n    /// Returns an iterator over transactions that are ready.\n    fn ready_transactions(&self) -> TransactionsIterator<T> {\n        self.ready_transactions.get_transactions()\n    }\n\n    /// Clears\n    fn clear(&mut self) {\n        self.ready_transactions.clear();\n        self.pending_transactions.clear();\n    }\n\n    /// Returns an iterator over all transactions in the pool filtered by the sender\n    pub fn transactions_by_sender(\n        &self,\n        sender: Address,\n    ) -> impl Iterator<Item = Arc<PoolTransaction<T>>> + '_ {\n        let pending_txs = self\n            .pending_transactions\n            .transactions()\n            .filter(move |tx| tx.pending_transaction.sender().eq(&sender));\n\n        let ready_txs = self\n            .ready_transactions\n            .get_transactions()\n            .filter(move |tx| tx.pending_transaction.sender().eq(&sender));\n\n        pending_txs.chain(ready_txs)\n    }\n\n    /// Returns true if this pool already contains the transaction\n    fn contains(&self, tx_hash: &TxHash) -> bool {\n        self.pending_transactions.contains(tx_hash) || self.ready_transactions.contains(tx_hash)\n    }\n\n    /// Remove the given transactions from the pool\n    fn remove_invalid(&mut self, tx_hashes: Vec<TxHash>) -> Vec<Arc<PoolTransaction<T>>> {\n        // early exit in case there is no invalid transactions.\n        if tx_hashes.is_empty() {\n            return vec![];\n        }\n        trace!(target: \"txpool\", \"Removing invalid transactions: {:?}\", tx_hashes);\n\n        let mut removed = self.ready_transactions.remove_with_markers(tx_hashes.clone(), None);\n        removed.extend(self.pending_transactions.remove(tx_hashes));\n\n        trace!(target: \"txpool\", \"Removed invalid transactions: {:?}\", removed.iter().map(|tx| tx.hash()).collect::<Vec<_>>());\n\n        removed\n    }\n\n    /// Remove transactions by sender address\n    fn remove_transactions_by_address(&mut self, sender: Address) -> Vec<Arc<PoolTransaction<T>>> {\n        let tx_hashes =\n            self.transactions_by_sender(sender).map(move |tx| tx.hash()).collect::<Vec<TxHash>>();\n\n        if tx_hashes.is_empty() {\n            return vec![];\n        }\n\n        trace!(target: \"txpool\", \"Removing transactions: {:?}\", tx_hashes);\n\n        let mut removed = self.ready_transactions.remove_with_markers(tx_hashes.clone(), None);\n        removed.extend(self.pending_transactions.remove(tx_hashes));\n\n        trace!(target: \"txpool\", \"Removed transactions: {:?}\", removed.iter().map(|tx| tx.hash()).collect::<Vec<_>>());\n\n        removed\n    }\n}\n\nimpl<T: Clone> PoolInner<T> {\n    /// checks both pools for the matching transaction\n    ///\n    /// Returns `None` if the transaction does not exist in the pool\n    fn get_transaction(&self, hash: TxHash) -> Option<PendingTransaction<T>> {\n        if let Some(pending) = self.pending_transactions.get(&hash) {\n            return Some(pending.transaction.pending_transaction.clone());\n        }\n        Some(\n            self.ready_transactions.get(&hash)?.transaction.transaction.pending_transaction.clone(),\n        )\n    }\n}\n\nimpl<T: Transaction> PoolInner<T> {\n    fn add_transaction(\n        &mut self,\n        tx: PoolTransaction<T>,\n    ) -> Result<AddedTransaction<T>, PoolError> {\n        if self.contains(&tx.hash()) {\n            warn!(target: \"txpool\", \"[{:?}] Already imported\", tx.hash());\n            return Err(PoolError::AlreadyImported(tx.hash()));\n        }\n\n        let tx = PendingPoolTransaction::new(tx, self.ready_transactions.provided_markers());\n        trace!(target: \"txpool\", \"[{:?}] ready={}\", tx.transaction.hash(), tx.is_ready());\n\n        // If all markers are not satisfied import to future\n        if !tx.is_ready() {\n            let hash = tx.transaction.hash();\n            self.pending_transactions.add_transaction(tx)?;\n            return Ok(AddedTransaction::Pending { hash });\n        }\n        self.add_ready_transaction(tx)\n    }\n\n    /// Adds the transaction to the ready queue\n    fn add_ready_transaction(\n        &mut self,\n        tx: PendingPoolTransaction<T>,\n    ) -> Result<AddedTransaction<T>, PoolError> {\n        let hash = tx.transaction.hash();\n        trace!(target: \"txpool\", \"adding ready transaction [{:?}]\", hash);\n        let mut ready = ReadyTransaction::new(hash);\n\n        let mut tx_queue = VecDeque::from([tx]);\n        // tracks whether we're processing the given `tx`\n        let mut is_new_tx = true;\n\n        // take first transaction from the list\n        while let Some(current_tx) = tx_queue.pop_front() {\n            // also add the transaction that the current transaction unlocks\n            tx_queue.extend(\n                self.pending_transactions.mark_and_unlock(&current_tx.transaction.provides),\n            );\n\n            let current_hash = current_tx.transaction.hash();\n            // try to add the transaction to the ready pool\n            match self.ready_transactions.add_transaction(current_tx) {\n                Ok(replaced_transactions) => {\n                    if !is_new_tx {\n                        ready.promoted.push(current_hash);\n                    }\n                    // tx removed from ready pool\n                    ready.removed.extend(replaced_transactions);\n                }\n                Err(err) => {\n                    // failed to add transaction\n                    if is_new_tx {\n                        debug!(target: \"txpool\", \"[{:?}] Failed to add tx: {:?}\", current_hash,\n        err);\n                        return Err(err);\n                    } else {\n                        ready.discarded.push(current_hash);\n                    }\n                }\n            }\n            is_new_tx = false;\n        }\n\n        // check for a cycle where importing a transaction resulted in pending transactions to be\n        // added while removing current transaction. in which case we move this transaction back to\n        // the pending queue\n        if ready.removed.iter().any(|tx| *tx.hash() == hash) {\n            self.ready_transactions.clear_transactions(&ready.promoted);\n            return Err(PoolError::CyclicTransaction);\n        }\n\n        Ok(AddedTransaction::Ready(ready))\n    }\n\n    /// Prunes the transactions that provide the given markers\n    ///\n    /// This will effectively remove those transactions that satisfy the markers and transactions\n    /// from the pending queue might get promoted to if the markers unlock them.\n    pub fn prune_markers(&mut self, markers: impl IntoIterator<Item = TxMarker>) -> PruneResult<T> {\n        let mut imports = vec![];\n        let mut pruned = vec![];\n\n        for marker in markers {\n            // mark as satisfied and store the transactions that got unlocked\n            imports.extend(self.pending_transactions.mark_and_unlock(Some(&marker)));\n            // prune transactions\n            pruned.extend(self.ready_transactions.prune_tags(marker.clone()));\n        }\n\n        let mut promoted = vec![];\n        let mut failed = vec![];\n        for tx in imports {\n            let hash = tx.transaction.hash();\n            match self.add_ready_transaction(tx) {\n                Ok(res) => promoted.push(res),\n                Err(e) => {\n                    warn!(target: \"txpool\", \"Failed to promote tx [{:?}] : {:?}\", hash, e);\n                    failed.push(hash)\n                }\n            }\n        }\n\n        PruneResult { pruned, failed, promoted }\n    }\n}\n\n/// Represents the outcome of a prune\npub struct PruneResult<T> {\n    /// a list of added transactions that a pruned marker satisfied\n    pub promoted: Vec<AddedTransaction<T>>,\n    /// all transactions that  failed to be promoted and now are discarded\n    pub failed: Vec<TxHash>,\n    /// all transactions that were pruned from the ready pool\n    pub pruned: Vec<Arc<PoolTransaction<T>>>,\n}\n\nimpl<T> fmt::Debug for PruneResult<T> {\n    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {\n        write!(fmt, \"PruneResult {{ \")?;\n        write!(\n            fmt,\n            \"promoted: {:?}, \",\n            self.promoted.iter().map(|tx| *tx.hash()).collect::<Vec<_>>()\n        )?;\n        write!(fmt, \"failed: {:?}, \", self.failed)?;\n        write!(\n            fmt,\n            \"pruned: {:?}, \",\n            self.pruned.iter().map(|tx| *tx.pending_transaction.hash()).collect::<Vec<_>>()\n        )?;\n        write!(fmt, \"}}\")?;\n        Ok(())\n    }\n}\n\n#[derive(Clone, Debug)]\npub struct ReadyTransaction<T> {\n    /// the hash of the submitted transaction\n    hash: TxHash,\n    /// transactions promoted to the ready queue\n    promoted: Vec<TxHash>,\n    /// transaction that failed and became discarded\n    discarded: Vec<TxHash>,\n    /// Transactions removed from the Ready pool\n    removed: Vec<Arc<PoolTransaction<T>>>,\n}\n\nimpl<T> ReadyTransaction<T> {\n    pub fn new(hash: TxHash) -> Self {\n        Self {\n            hash,\n            promoted: Default::default(),\n            discarded: Default::default(),\n            removed: Default::default(),\n        }\n    }\n}\n\n#[derive(Clone, Debug)]\npub enum AddedTransaction<T> {\n    /// transaction was successfully added and being processed\n    Ready(ReadyTransaction<T>),\n    /// Transaction was successfully added but not yet queued for processing\n    Pending {\n        /// the hash of the submitted transaction\n        hash: TxHash,\n    },\n}\n\nimpl<T> AddedTransaction<T> {\n    pub fn hash(&self) -> &TxHash {\n        match self {\n            Self::Ready(tx) => &tx.hash,\n            Self::Pending { hash } => hash,\n        }\n    }\n}\n"
  },
  {
    "path": "crates/anvil/src/eth/pool/transactions.rs",
    "content": "use crate::eth::{error::PoolError, util::hex_fmt_many};\nuse alloy_consensus::{Transaction, Typed2718};\nuse alloy_network::AnyRpcTransaction;\nuse alloy_primitives::{\n    Address, TxHash,\n    map::{HashMap, HashSet},\n};\nuse anvil_core::eth::transaction::PendingTransaction;\nuse foundry_primitives::FoundryTxEnvelope;\nuse parking_lot::RwLock;\nuse std::{cmp::Ordering, collections::BTreeSet, fmt, str::FromStr, sync::Arc, time::Instant};\n\n/// A unique identifying marker for a transaction\npub type TxMarker = Vec<u8>;\n\n/// Result type for replaced transactions: the replaced pool transactions and the hashes they\n/// unlock.\ntype ReplacedTransactions<T> = (Vec<Arc<PoolTransaction<T>>>, Vec<TxHash>);\n\n/// creates an unique identifier for aan (`nonce` + `Address`) combo\npub fn to_marker(nonce: u64, from: Address) -> TxMarker {\n    let mut data = [0u8; 28];\n    data[..8].copy_from_slice(&nonce.to_le_bytes()[..]);\n    data[8..].copy_from_slice(&from.0[..]);\n    data.to_vec()\n}\n\n/// Modes that determine the transaction ordering of the mempool\n///\n/// This type controls the transaction order via the priority metric of a transaction\n#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, serde::Serialize, serde::Deserialize)]\npub enum TransactionOrder {\n    /// Keep the pool transaction transactions sorted in the order they arrive.\n    ///\n    /// This will essentially assign every transaction the exact priority so the order is\n    /// determined by their internal id\n    Fifo,\n    /// This means that it prioritizes transactions based on the fees paid to the miner.\n    #[default]\n    Fees,\n}\n\nimpl TransactionOrder {\n    /// Returns the priority of the transactions\n    pub fn priority<T: Transaction>(&self, tx: &T) -> TransactionPriority {\n        match self {\n            Self::Fifo => TransactionPriority::default(),\n            Self::Fees => TransactionPriority(tx.max_fee_per_gas()),\n        }\n    }\n}\n\nimpl FromStr for TransactionOrder {\n    type Err = String;\n\n    fn from_str(s: &str) -> Result<Self, Self::Err> {\n        let s = s.to_lowercase();\n        let order = match s.as_str() {\n            \"fees\" => Self::Fees,\n            \"fifo\" => Self::Fifo,\n            _ => return Err(format!(\"Unknown TransactionOrder: `{s}`\")),\n        };\n        Ok(order)\n    }\n}\n\n/// Metric value for the priority of a transaction.\n///\n/// The `TransactionPriority` determines the ordering of two transactions that have all their\n/// markers satisfied.\n#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord)]\npub struct TransactionPriority(pub u128);\n\n/// Internal Transaction type\n#[derive(Clone, PartialEq, Eq)]\npub struct PoolTransaction<T> {\n    /// the pending eth transaction\n    pub pending_transaction: PendingTransaction<T>,\n    /// Markers required by the transaction\n    pub requires: Vec<TxMarker>,\n    /// Markers that this transaction provides\n    pub provides: Vec<TxMarker>,\n    /// priority of the transaction\n    pub priority: TransactionPriority,\n}\n\n// == impl PoolTransaction ==\n\nimpl<T> PoolTransaction<T> {\n    pub fn new(transaction: PendingTransaction<T>) -> Self {\n        Self {\n            pending_transaction: transaction,\n            requires: vec![],\n            provides: vec![],\n            priority: TransactionPriority(0),\n        }\n    }\n\n    /// Returns the hash of this transaction\n    pub fn hash(&self) -> TxHash {\n        *self.pending_transaction.hash()\n    }\n}\n\nimpl<T: Transaction> PoolTransaction<T> {\n    /// Returns the max fee per gas of this transaction\n    pub fn max_fee_per_gas(&self) -> u128 {\n        self.pending_transaction.transaction.max_fee_per_gas()\n    }\n}\n\nimpl<T: Typed2718> PoolTransaction<T> {\n    /// Returns the type of the transaction\n    pub fn tx_type(&self) -> u8 {\n        self.pending_transaction.transaction.ty()\n    }\n}\n\nimpl<T: fmt::Debug> fmt::Debug for PoolTransaction<T> {\n    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {\n        write!(fmt, \"Transaction {{ \")?;\n        write!(fmt, \"hash: {:?}, \", &self.pending_transaction.hash())?;\n        write!(fmt, \"requires: [{}], \", hex_fmt_many(self.requires.iter()))?;\n        write!(fmt, \"provides: [{}], \", hex_fmt_many(self.provides.iter()))?;\n        write!(fmt, \"raw tx: {:?}\", &self.pending_transaction)?;\n        write!(fmt, \"}}\")?;\n        Ok(())\n    }\n}\n\nimpl TryFrom<AnyRpcTransaction> for PoolTransaction<FoundryTxEnvelope> {\n    type Error = eyre::Error;\n    fn try_from(value: AnyRpcTransaction) -> Result<Self, Self::Error> {\n        let typed_transaction = FoundryTxEnvelope::try_from(value)?;\n        let pending_transaction = PendingTransaction::new(typed_transaction)?;\n        Ok(Self {\n            pending_transaction,\n            requires: vec![],\n            provides: vec![],\n            priority: TransactionPriority(0),\n        })\n    }\n}\n\n/// A waiting pool of transaction that are pending, but not yet ready to be included in a new block.\n///\n/// Keeps a set of transactions that are waiting for other transactions\n#[derive(Clone, Debug)]\npub struct PendingTransactions<T> {\n    /// markers that aren't yet provided by any transaction\n    required_markers: HashMap<TxMarker, HashSet<TxHash>>,\n    /// mapping of the markers of a transaction to the hash of the transaction\n    waiting_markers: HashMap<Vec<TxMarker>, TxHash>,\n    /// the transactions that are not ready yet are waiting for another tx to finish\n    waiting_queue: HashMap<TxHash, PendingPoolTransaction<T>>,\n}\n\nimpl<T> Default for PendingTransactions<T> {\n    fn default() -> Self {\n        Self {\n            required_markers: Default::default(),\n            waiting_markers: Default::default(),\n            waiting_queue: Default::default(),\n        }\n    }\n}\n\nimpl<T> PendingTransactions<T> {\n    /// Returns the number of transactions that are currently waiting\n    pub fn len(&self) -> usize {\n        self.waiting_queue.len()\n    }\n\n    pub fn is_empty(&self) -> bool {\n        self.waiting_queue.is_empty()\n    }\n\n    /// Clears internal state\n    pub fn clear(&mut self) {\n        self.required_markers.clear();\n        self.waiting_markers.clear();\n        self.waiting_queue.clear();\n    }\n\n    /// Returns an iterator over all transactions in the waiting pool\n    pub fn transactions(&self) -> impl Iterator<Item = Arc<PoolTransaction<T>>> + '_ {\n        self.waiting_queue.values().map(|tx| tx.transaction.clone())\n    }\n\n    /// Returns true if given transaction is part of the queue\n    pub fn contains(&self, hash: &TxHash) -> bool {\n        self.waiting_queue.contains_key(hash)\n    }\n\n    /// Returns the transaction for the hash if it's pending\n    pub fn get(&self, hash: &TxHash) -> Option<&PendingPoolTransaction<T>> {\n        self.waiting_queue.get(hash)\n    }\n\n    /// This will check off the markers of pending transactions.\n    ///\n    /// Returns the those transactions that become unlocked (all markers checked) and can be moved\n    /// to the ready queue.\n    pub fn mark_and_unlock(\n        &mut self,\n        markers: impl IntoIterator<Item = impl AsRef<TxMarker>>,\n    ) -> Vec<PendingPoolTransaction<T>> {\n        let mut unlocked_ready = Vec::new();\n        for mark in markers {\n            let mark = mark.as_ref();\n            if let Some(tx_hashes) = self.required_markers.remove(mark) {\n                for hash in tx_hashes {\n                    let tx = self.waiting_queue.get_mut(&hash).expect(\"tx is included;\");\n                    tx.mark(mark);\n\n                    if tx.is_ready() {\n                        let tx = self.waiting_queue.remove(&hash).expect(\"tx is included;\");\n                        self.waiting_markers.remove(&tx.transaction.provides);\n\n                        unlocked_ready.push(tx);\n                    }\n                }\n            }\n        }\n\n        unlocked_ready\n    }\n\n    /// Removes the transactions associated with the given hashes\n    ///\n    /// Returns all removed transactions.\n    pub fn remove(&mut self, hashes: Vec<TxHash>) -> Vec<Arc<PoolTransaction<T>>> {\n        let mut removed = vec![];\n        for hash in hashes {\n            if let Some(waiting_tx) = self.waiting_queue.remove(&hash) {\n                self.waiting_markers.remove(&waiting_tx.transaction.provides);\n                for marker in waiting_tx.missing_markers {\n                    let remove = if let Some(required) = self.required_markers.get_mut(&marker) {\n                        required.remove(&hash);\n                        required.is_empty()\n                    } else {\n                        false\n                    };\n                    if remove {\n                        self.required_markers.remove(&marker);\n                    }\n                }\n                removed.push(waiting_tx.transaction)\n            }\n        }\n        removed\n    }\n}\n\nimpl<T: Transaction> PendingTransactions<T> {\n    /// Adds a transaction to Pending queue of transactions\n    pub fn add_transaction(&mut self, tx: PendingPoolTransaction<T>) -> Result<(), PoolError> {\n        assert!(!tx.is_ready(), \"transaction must not be ready\");\n        assert!(\n            !self.waiting_queue.contains_key(&tx.transaction.hash()),\n            \"transaction is already added\"\n        );\n\n        if let Some(replace) = self\n            .waiting_markers\n            .get(&tx.transaction.provides)\n            .and_then(|hash| self.waiting_queue.get(hash))\n        {\n            // check if underpriced\n            if tx.transaction.max_fee_per_gas() < replace.transaction.max_fee_per_gas() {\n                warn!(target: \"txpool\", \"pending replacement transaction underpriced [{:?}]\", tx.transaction.hash());\n                return Err(PoolError::ReplacementUnderpriced(tx.transaction.hash()));\n            }\n        }\n\n        // add all missing markers\n        for marker in &tx.missing_markers {\n            self.required_markers.entry(marker.clone()).or_default().insert(tx.transaction.hash());\n        }\n\n        // also track identifying markers\n        self.waiting_markers.insert(tx.transaction.provides.clone(), tx.transaction.hash());\n        // add tx to the queue\n        self.waiting_queue.insert(tx.transaction.hash(), tx);\n\n        Ok(())\n    }\n}\n\n/// A transaction in the pool\n#[derive(Clone)]\npub struct PendingPoolTransaction<T> {\n    pub transaction: Arc<PoolTransaction<T>>,\n    /// markers required and have not been satisfied yet by other transactions in the pool\n    pub missing_markers: HashSet<TxMarker>,\n    /// timestamp when the tx was added\n    pub added_at: Instant,\n}\n\nimpl<T> PendingPoolTransaction<T> {\n    /// Creates a new `PendingPoolTransaction`.\n    ///\n    /// Determines the markers that are still missing before this transaction can be moved to the\n    /// ready queue.\n    pub fn new(transaction: PoolTransaction<T>, provided: &HashMap<TxMarker, TxHash>) -> Self {\n        let missing_markers = transaction\n            .requires\n            .iter()\n            .filter(|marker| {\n                // is true if the marker is already satisfied either via transaction in the pool\n                !provided.contains_key(&**marker)\n            })\n            .cloned()\n            .collect();\n\n        Self { transaction: Arc::new(transaction), missing_markers, added_at: Instant::now() }\n    }\n\n    /// Removes the required marker\n    pub fn mark(&mut self, marker: &TxMarker) {\n        self.missing_markers.remove(marker);\n    }\n\n    /// Returns true if transaction has all requirements satisfied.\n    pub fn is_ready(&self) -> bool {\n        self.missing_markers.is_empty()\n    }\n}\n\nimpl<T: fmt::Debug> fmt::Debug for PendingPoolTransaction<T> {\n    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {\n        write!(fmt, \"PendingTransaction {{ \")?;\n        write!(fmt, \"added_at: {:?}, \", self.added_at)?;\n        write!(fmt, \"tx: {:?}, \", self.transaction)?;\n        write!(fmt, \"missing_markers: {{{}}}\", hex_fmt_many(self.missing_markers.iter()))?;\n        write!(fmt, \"}}\")\n    }\n}\n\npub struct TransactionsIterator<T> {\n    all: HashMap<TxHash, ReadyTransaction<T>>,\n    awaiting: HashMap<TxHash, (usize, PoolTransactionRef<T>)>,\n    independent: BTreeSet<PoolTransactionRef<T>>,\n    _invalid: HashSet<TxHash>,\n}\n\nimpl<T> TransactionsIterator<T> {\n    /// Depending on number of satisfied requirements insert given ref\n    /// either to awaiting set or to best set.\n    fn independent_or_awaiting(&mut self, satisfied: usize, tx_ref: PoolTransactionRef<T>) {\n        if satisfied >= tx_ref.transaction.requires.len() {\n            // If we have satisfied all deps insert to best\n            self.independent.insert(tx_ref);\n        } else {\n            // otherwise we're still awaiting for some deps\n            self.awaiting.insert(tx_ref.transaction.hash(), (satisfied, tx_ref));\n        }\n    }\n}\n\nimpl<T> Iterator for TransactionsIterator<T> {\n    type Item = Arc<PoolTransaction<T>>;\n\n    fn next(&mut self) -> Option<Self::Item> {\n        loop {\n            let best = self.independent.iter().next_back()?.clone();\n            let best = self.independent.take(&best)?;\n            let hash = best.transaction.hash();\n\n            let ready =\n                if let Some(ready) = self.all.get(&hash).cloned() { ready } else { continue };\n\n            // Insert transactions that just got unlocked.\n            for hash in &ready.unlocks {\n                // first check local awaiting transactions\n                let res = if let Some((mut satisfied, tx_ref)) = self.awaiting.remove(hash) {\n                    satisfied += 1;\n                    Some((satisfied, tx_ref))\n                    // then get from the pool\n                } else {\n                    self.all\n                        .get(hash)\n                        .map(|next| (next.requires_offset + 1, next.transaction.clone()))\n                };\n                if let Some((satisfied, tx_ref)) = res {\n                    self.independent_or_awaiting(satisfied, tx_ref)\n                }\n            }\n\n            return Some(best.transaction);\n        }\n    }\n}\n\n/// transactions that are ready to be included in a block.\n#[derive(Clone, Debug)]\npub struct ReadyTransactions<T> {\n    /// keeps track of transactions inserted in the pool\n    ///\n    /// this way we can determine when transactions where submitted to the pool\n    id: u64,\n    /// markers that are provided by `ReadyTransaction`s\n    provided_markers: HashMap<TxMarker, TxHash>,\n    /// transactions that are ready\n    ready_tx: Arc<RwLock<HashMap<TxHash, ReadyTransaction<T>>>>,\n    /// independent transactions that can be included directly and don't require other transactions\n    /// Sorted by their id\n    independent_transactions: BTreeSet<PoolTransactionRef<T>>,\n}\n\nimpl<T> Default for ReadyTransactions<T> {\n    fn default() -> Self {\n        Self {\n            id: 0,\n            provided_markers: Default::default(),\n            ready_tx: Default::default(),\n            independent_transactions: Default::default(),\n        }\n    }\n}\n\nimpl<T> ReadyTransactions<T> {\n    /// Returns an iterator over all transactions\n    pub fn get_transactions(&self) -> TransactionsIterator<T> {\n        TransactionsIterator {\n            all: self.ready_tx.read().clone(),\n            independent: self.independent_transactions.clone(),\n            awaiting: Default::default(),\n            _invalid: Default::default(),\n        }\n    }\n\n    /// Clears the internal state\n    pub fn clear(&mut self) {\n        self.provided_markers.clear();\n        self.ready_tx.write().clear();\n        self.independent_transactions.clear();\n    }\n\n    /// Returns true if the transaction is part of the queue.\n    pub fn contains(&self, hash: &TxHash) -> bool {\n        self.ready_tx.read().contains_key(hash)\n    }\n\n    /// Returns the number of ready transactions without cloning the snapshot\n    pub fn len(&self) -> usize {\n        self.ready_tx.read().len()\n    }\n\n    /// Returns true if there are no ready transactions\n    pub fn is_empty(&self) -> bool {\n        self.ready_tx.read().is_empty()\n    }\n\n    /// Returns the transaction for the hash if it's in the ready pool but not yet mined\n    pub fn get(&self, hash: &TxHash) -> Option<ReadyTransaction<T>> {\n        self.ready_tx.read().get(hash).cloned()\n    }\n\n    pub fn provided_markers(&self) -> &HashMap<TxMarker, TxHash> {\n        &self.provided_markers\n    }\n\n    fn next_id(&mut self) -> u64 {\n        let id = self.id;\n        self.id = self.id.wrapping_add(1);\n        id\n    }\n\n    /// Removes the transactions from the ready queue and returns the removed transactions.\n    /// This will also remove all transactions that depend on those.\n    pub fn clear_transactions(&mut self, tx_hashes: &[TxHash]) -> Vec<Arc<PoolTransaction<T>>> {\n        self.remove_with_markers(tx_hashes.to_vec(), None)\n    }\n\n    /// Removes the transactions that provide the marker\n    ///\n    /// This will also remove all transactions that lead to the transaction that provides the\n    /// marker.\n    pub fn prune_tags(&mut self, marker: TxMarker) -> Vec<Arc<PoolTransaction<T>>> {\n        let mut removed_tx = vec![];\n\n        // the markers to remove\n        let mut remove = vec![marker];\n\n        while let Some(marker) = remove.pop() {\n            let res = self\n                .provided_markers\n                .remove(&marker)\n                .and_then(|hash| self.ready_tx.write().remove(&hash));\n\n            if let Some(tx) = res {\n                let unlocks = tx.unlocks;\n                self.independent_transactions.remove(&tx.transaction);\n                let tx = tx.transaction.transaction;\n\n                // also prune previous transactions\n                {\n                    let hash = tx.hash();\n                    let mut ready = self.ready_tx.write();\n\n                    let mut previous_markers = |marker| -> Option<Vec<TxMarker>> {\n                        let prev_hash = self.provided_markers.get(marker)?;\n                        let tx2 = ready.get_mut(prev_hash)?;\n                        // remove hash\n                        if let Some(idx) = tx2.unlocks.iter().position(|i| i == &hash) {\n                            tx2.unlocks.swap_remove(idx);\n                        }\n                        if tx2.unlocks.is_empty() {\n                            Some(tx2.transaction.transaction.provides.clone())\n                        } else {\n                            None\n                        }\n                    };\n\n                    // find previous transactions\n                    for marker in &tx.requires {\n                        if let Some(mut tags_to_remove) = previous_markers(marker) {\n                            remove.append(&mut tags_to_remove);\n                        }\n                    }\n                }\n\n                // add the transactions that just got unlocked to independent set\n                for hash in unlocks {\n                    if let Some(tx) = self.ready_tx.write().get_mut(&hash) {\n                        tx.requires_offset += 1;\n                        if tx.requires_offset == tx.transaction.transaction.requires.len() {\n                            self.independent_transactions.insert(tx.transaction.clone());\n                        }\n                    }\n                }\n                // finally, remove the markers that this transaction provides\n                let current_marker = &marker;\n                for marker in &tx.provides {\n                    let removed = self.provided_markers.remove(marker);\n                    assert_eq!(\n                        removed,\n                        if current_marker == marker { None } else { Some(tx.hash()) },\n                        \"The pool contains exactly one transaction providing given tag; the removed transaction\n\t\t\t\t\t\tclaims to provide that tag, so it has to be mapped to it's hash; qed\"\n                    );\n                }\n                removed_tx.push(tx);\n            }\n        }\n\n        removed_tx\n    }\n\n    /// Removes transactions and those that depend on them and satisfy at least one marker in the\n    /// given filter set.\n    pub fn remove_with_markers(\n        &mut self,\n        mut tx_hashes: Vec<TxHash>,\n        marker_filter: Option<HashSet<TxMarker>>,\n    ) -> Vec<Arc<PoolTransaction<T>>> {\n        let mut removed = Vec::new();\n        let mut ready = self.ready_tx.write();\n\n        while let Some(hash) = tx_hashes.pop() {\n            if let Some(mut tx) = ready.remove(&hash) {\n                let invalidated = tx.transaction.transaction.provides.iter().filter(|mark| {\n                    marker_filter.as_ref().map(|filter| !filter.contains(&**mark)).unwrap_or(true)\n                });\n\n                let mut removed_some_marks = false;\n                // remove entries from provided_markers\n                for mark in invalidated {\n                    removed_some_marks = true;\n                    self.provided_markers.remove(mark);\n                }\n\n                // remove from unlocks\n                for mark in &tx.transaction.transaction.requires {\n                    if let Some(provider_hash) = self.provided_markers.get(mark)\n                        && let Some(provider_tx) = ready.get_mut(provider_hash)\n                        && let Some(idx) = provider_tx.unlocks.iter().position(|i| i == &hash)\n                    {\n                        provider_tx.unlocks.swap_remove(idx);\n                    }\n                }\n\n                // remove from the independent set\n                self.independent_transactions.remove(&tx.transaction);\n\n                if removed_some_marks {\n                    // remove all transactions that the current one unlocks\n                    tx_hashes.append(&mut tx.unlocks);\n                }\n\n                // remove transaction\n                removed.push(tx.transaction.transaction);\n            }\n        }\n\n        removed\n    }\n}\n\nimpl<T: Transaction> ReadyTransactions<T> {\n    /// Adds a new transactions to the ready queue.\n    ///\n    /// # Panics\n    ///\n    /// If the pending transaction is not ready ([`PendingPoolTransaction::is_ready`])\n    /// or the transaction is already included.\n    pub fn add_transaction(\n        &mut self,\n        tx: PendingPoolTransaction<T>,\n    ) -> Result<Vec<Arc<PoolTransaction<T>>>, PoolError> {\n        assert!(tx.is_ready(), \"transaction must be ready\",);\n        assert!(\n            !self.ready_tx.read().contains_key(&tx.transaction.hash()),\n            \"transaction already included\"\n        );\n\n        let (replaced_tx, unlocks) = self.replaced_transactions(&tx.transaction)?;\n\n        let id = self.next_id();\n        let hash = tx.transaction.hash();\n\n        let mut independent = true;\n        let mut requires_offset = 0;\n        let mut ready = self.ready_tx.write();\n        // Add links to transactions that unlock the current one\n        for mark in &tx.transaction.requires {\n            // Check if the transaction that satisfies the mark is still in the queue.\n            if let Some(other) = self.provided_markers.get(mark) {\n                let tx = ready.get_mut(other).expect(\"hash included;\");\n                tx.unlocks.push(hash);\n                // tx still depends on other tx\n                independent = false;\n            } else {\n                requires_offset += 1;\n            }\n        }\n\n        // update markers\n        for mark in tx.transaction.provides.iter().cloned() {\n            self.provided_markers.insert(mark, hash);\n        }\n\n        let transaction = PoolTransactionRef { id, transaction: tx.transaction };\n\n        // add to the independent set\n        if independent {\n            self.independent_transactions.insert(transaction.clone());\n        }\n\n        // insert to ready queue\n        ready.insert(hash, ReadyTransaction { transaction, unlocks, requires_offset });\n\n        Ok(replaced_tx)\n    }\n\n    /// Removes and returns those transactions that got replaced by the `tx`\n    fn replaced_transactions(\n        &mut self,\n        tx: &PoolTransaction<T>,\n    ) -> Result<ReplacedTransactions<T>, PoolError> {\n        // check if we are replacing transactions\n        let remove_hashes: HashSet<_> =\n            tx.provides.iter().filter_map(|mark| self.provided_markers.get(mark)).collect();\n\n        // early exit if we are not replacing anything.\n        if remove_hashes.is_empty() {\n            return Ok((Vec::new(), Vec::new()));\n        }\n\n        // check if we're replacing the same transaction and if it can be replaced\n        let mut unlocked_tx = Vec::new();\n        {\n            // construct a list of unlocked transactions\n            // also check for transactions that shouldn't be replaced because underpriced\n            let ready = self.ready_tx.read();\n            for to_remove in remove_hashes.iter().filter_map(|hash| ready.get(*hash)) {\n                // if we're attempting to replace a transaction that provides the exact same markers\n                // (addr + nonce) then we check for gas price\n                if to_remove.provides() == tx.provides {\n                    // check if underpriced\n                    if tx.pending_transaction.transaction.max_fee_per_gas()\n                        <= to_remove.max_fee_per_gas()\n                    {\n                        warn!(target: \"txpool\", \"ready replacement transaction underpriced [{:?}]\", tx.hash());\n                        return Err(PoolError::ReplacementUnderpriced(tx.hash()));\n                    } else {\n                        trace!(target: \"txpool\", \"replacing ready transaction [{:?}] with higher gas price [{:?}]\", to_remove.transaction.transaction.hash(), tx.hash());\n                    }\n                }\n\n                unlocked_tx.extend(to_remove.unlocks.iter().copied())\n            }\n        }\n\n        let remove_hashes = remove_hashes.into_iter().copied().collect::<Vec<_>>();\n\n        let new_provides = tx.provides.iter().cloned().collect::<HashSet<_>>();\n        let removed_tx = self.remove_with_markers(remove_hashes, Some(new_provides));\n\n        Ok((removed_tx, unlocked_tx))\n    }\n}\n\n/// A reference to a transaction in the pool\n#[derive(Debug)]\npub struct PoolTransactionRef<T> {\n    /// actual transaction\n    pub transaction: Arc<PoolTransaction<T>>,\n    /// identifier used to internally compare the transaction in the pool\n    pub id: u64,\n}\n\nimpl<T> Clone for PoolTransactionRef<T> {\n    fn clone(&self) -> Self {\n        Self { transaction: Arc::clone(&self.transaction), id: self.id }\n    }\n}\n\nimpl<T> Eq for PoolTransactionRef<T> {}\n\nimpl<T> PartialEq<Self> for PoolTransactionRef<T> {\n    fn eq(&self, other: &Self) -> bool {\n        self.cmp(other) == Ordering::Equal\n    }\n}\n\nimpl<T> PartialOrd<Self> for PoolTransactionRef<T> {\n    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {\n        Some(self.cmp(other))\n    }\n}\n\nimpl<T> Ord for PoolTransactionRef<T> {\n    fn cmp(&self, other: &Self) -> Ordering {\n        self.transaction\n            .priority\n            .cmp(&other.transaction.priority)\n            .then_with(|| other.id.cmp(&self.id))\n    }\n}\n\n#[derive(Debug)]\npub struct ReadyTransaction<T> {\n    /// ref to the actual transaction\n    pub transaction: PoolTransactionRef<T>,\n    /// tracks the transactions that get unlocked by this transaction\n    pub unlocks: Vec<TxHash>,\n    /// amount of required markers that are inherently provided\n    pub requires_offset: usize,\n}\n\nimpl<T> Clone for ReadyTransaction<T> {\n    fn clone(&self) -> Self {\n        Self {\n            transaction: self.transaction.clone(),\n            unlocks: self.unlocks.clone(),\n            requires_offset: self.requires_offset,\n        }\n    }\n}\n\nimpl<T> ReadyTransaction<T> {\n    pub fn provides(&self) -> &[TxMarker] {\n        &self.transaction.transaction.provides\n    }\n}\n\nimpl<T: Transaction> ReadyTransaction<T> {\n    pub fn max_fee_per_gas(&self) -> u128 {\n        self.transaction.transaction.max_fee_per_gas()\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn can_id_txs() {\n        let addr = Address::random();\n        assert_eq!(to_marker(1, addr), to_marker(1, addr));\n        assert_ne!(to_marker(2, addr), to_marker(1, addr));\n    }\n}\n"
  },
  {
    "path": "crates/anvil/src/eth/sign.rs",
    "content": "use crate::eth::error::BlockchainError;\nuse alloy_consensus::{Sealed, SignableTransaction};\nuse alloy_dyn_abi::TypedData;\nuse alloy_network::{Network, TxSignerSync};\nuse alloy_primitives::{Address, B256, Signature, map::AddressHashMap};\nuse alloy_signer::Signer as AlloySigner;\nuse alloy_signer_local::PrivateKeySigner;\nuse foundry_primitives::{FoundryTxEnvelope, FoundryTypedTx};\nuse tempo_primitives::TempoSignature;\n\n/// Network-agnostic signing: messages, typed data, and hashes.\n#[async_trait::async_trait]\npub trait MessageSigner: Send + Sync {\n    /// returns the available accounts for this signer\n    fn accounts(&self) -> Vec<Address>;\n\n    /// Returns `true` whether this signer can sign for this address\n    fn is_signer_for(&self, addr: Address) -> bool {\n        self.accounts().contains(&addr)\n    }\n\n    /// Returns the signature\n    async fn sign(&self, address: Address, message: &[u8]) -> Result<Signature, BlockchainError>;\n\n    /// Encodes and signs the typed data according EIP-712. Payload must conform to the EIP-712\n    /// standard.\n    async fn sign_typed_data(\n        &self,\n        address: Address,\n        payload: &TypedData,\n    ) -> Result<Signature, BlockchainError>;\n\n    /// Signs the given hash.\n    async fn sign_hash(&self, address: Address, hash: B256) -> Result<Signature, BlockchainError>;\n}\n\n/// A transaction signer, generic over the network.\n///\n/// Modelled after alloy's `NetworkWallet<N>`: the\n/// [`sign_transaction_from`](Signer::sign_transaction_from) method takes an\n/// unsigned transaction and returns the fully-signed envelope in one step.\npub trait Signer<N: Network>: MessageSigner {\n    /// Signs an unsigned transaction and returns the signed envelope.\n    ///\n    /// Mirrors `NetworkWallet::sign_transaction_from`.\n    fn sign_transaction_from(\n        &self,\n        sender: &Address,\n        tx: N::UnsignedTx,\n    ) -> Result<N::TxEnvelope, BlockchainError>;\n}\n\n/// Maintains developer keys\npub struct DevSigner {\n    addresses: Vec<Address>,\n    accounts: AddressHashMap<PrivateKeySigner>,\n}\n\nimpl DevSigner {\n    pub fn new(accounts: Vec<PrivateKeySigner>) -> Self {\n        let addresses = accounts.iter().map(|wallet| wallet.address()).collect::<Vec<_>>();\n        let accounts = addresses.iter().copied().zip(accounts).collect();\n        Self { addresses, accounts }\n    }\n}\n\n#[async_trait::async_trait]\nimpl MessageSigner for DevSigner {\n    fn accounts(&self) -> Vec<Address> {\n        self.addresses.clone()\n    }\n\n    fn is_signer_for(&self, addr: Address) -> bool {\n        self.accounts.contains_key(&addr)\n    }\n\n    async fn sign(&self, address: Address, message: &[u8]) -> Result<Signature, BlockchainError> {\n        let signer = self.accounts.get(&address).ok_or(BlockchainError::NoSignerAvailable)?;\n\n        Ok(signer.sign_message(message).await?)\n    }\n\n    async fn sign_typed_data(\n        &self,\n        address: Address,\n        payload: &TypedData,\n    ) -> Result<Signature, BlockchainError> {\n        let mut signer =\n            self.accounts.get(&address).ok_or(BlockchainError::NoSignerAvailable)?.to_owned();\n\n        // Explicitly set chainID as none, to avoid any EIP-155 application to `v` when signing\n        // typed data.\n        signer.set_chain_id(None);\n\n        Ok(signer.sign_dynamic_typed_data(payload).await?)\n    }\n\n    async fn sign_hash(&self, address: Address, hash: B256) -> Result<Signature, BlockchainError> {\n        let signer = self.accounts.get(&address).ok_or(BlockchainError::NoSignerAvailable)?;\n\n        Ok(signer.sign_hash(&hash).await?)\n    }\n}\n\nimpl Signer<foundry_primitives::FoundryNetwork> for DevSigner {\n    fn sign_transaction_from(\n        &self,\n        sender: &Address,\n        tx: FoundryTypedTx,\n    ) -> Result<FoundryTxEnvelope, BlockchainError> {\n        let signer = self.accounts.get(sender).ok_or(BlockchainError::NoSignerAvailable)?;\n        let envelope = match tx {\n            FoundryTypedTx::Legacy(mut t) => {\n                let sig = signer.sign_transaction_sync(&mut t)?;\n                FoundryTxEnvelope::Legacy(t.into_signed(sig))\n            }\n            FoundryTypedTx::Eip2930(mut t) => {\n                let sig = signer.sign_transaction_sync(&mut t)?;\n                FoundryTxEnvelope::Eip2930(t.into_signed(sig))\n            }\n            FoundryTypedTx::Eip1559(mut t) => {\n                let sig = signer.sign_transaction_sync(&mut t)?;\n                FoundryTxEnvelope::Eip1559(t.into_signed(sig))\n            }\n            FoundryTypedTx::Eip7702(mut t) => {\n                let sig = signer.sign_transaction_sync(&mut t)?;\n                FoundryTxEnvelope::Eip7702(t.into_signed(sig))\n            }\n            FoundryTypedTx::Eip4844(mut t) => {\n                let sig = signer.sign_transaction_sync(&mut t)?;\n                FoundryTxEnvelope::Eip4844(t.into_signed(sig))\n            }\n            FoundryTypedTx::Deposit(_) => {\n                unreachable!(\"op deposit txs should not be signed\")\n            }\n            FoundryTypedTx::Tempo(mut t) => {\n                let sig = signer.sign_transaction_sync(&mut t)?;\n                FoundryTxEnvelope::Tempo(t.into_signed(sig.into()))\n            }\n        };\n        Ok(envelope)\n    }\n}\n\n/// Builds a TxEnvelope from UnsignedTx with a zeroed signature.\n///\n/// Used for impersonated accounts, where transactions are accepted without a valid signature.\npub fn build_impersonated(typed_tx: FoundryTypedTx) -> FoundryTxEnvelope {\n    let signature = Signature::new(Default::default(), Default::default(), false);\n    match typed_tx {\n        FoundryTypedTx::Legacy(tx) => FoundryTxEnvelope::Legacy(tx.into_signed(signature)),\n        FoundryTypedTx::Eip2930(tx) => FoundryTxEnvelope::Eip2930(tx.into_signed(signature)),\n        FoundryTypedTx::Eip1559(tx) => FoundryTxEnvelope::Eip1559(tx.into_signed(signature)),\n        FoundryTypedTx::Eip7702(tx) => FoundryTxEnvelope::Eip7702(tx.into_signed(signature)),\n        FoundryTypedTx::Eip4844(tx) => FoundryTxEnvelope::Eip4844(tx.into_signed(signature)),\n        FoundryTypedTx::Deposit(tx) => FoundryTxEnvelope::Deposit(Sealed::new(tx)),\n        FoundryTypedTx::Tempo(tx) => {\n            let tempo_sig: TempoSignature = signature.into();\n            FoundryTxEnvelope::Tempo(tx.into_signed(tempo_sig))\n        }\n    }\n}\n"
  },
  {
    "path": "crates/anvil/src/eth/util.rs",
    "content": "use alloy_primitives::hex;\nuse itertools::Itertools;\n\n/// Formats values as hex strings, separated by commas.\npub fn hex_fmt_many<I, T>(i: I) -> String\nwhere\n    I: IntoIterator<Item = T>,\n    T: AsRef<[u8]>,\n{\n    let items = i.into_iter().map(|item| hex::encode(item.as_ref())).format(\", \");\n    format!(\"{items}\")\n}\n"
  },
  {
    "path": "crates/anvil/src/evm.rs",
    "content": "use alloy_evm::precompiles::DynPrecompile;\nuse alloy_primitives::Address;\nuse std::fmt::Debug;\n\n/// Object-safe trait that enables injecting extra precompiles when using\n/// `anvil` as a library.\npub trait PrecompileFactory: Send + Sync + Unpin + Debug {\n    /// Returns a set of precompiles to extend the EVM with.\n    fn precompiles(&self) -> Vec<(Address, DynPrecompile)>;\n}\n\n#[cfg(test)]\nmod tests {\n    use std::convert::Infallible;\n\n    use crate::PrecompileFactory;\n    use alloy_evm::{\n        EthEvm, Evm,\n        eth::EthEvmContext,\n        precompiles::{DynPrecompile, PrecompilesMap},\n    };\n    use alloy_op_evm::OpEvm;\n    use alloy_primitives::{Address, Bytes, TxKind, U256, address};\n    use foundry_evm::core::either_evm::EitherEvm;\n    use itertools::Itertools;\n    use op_revm::{L1BlockInfo, OpContext, OpSpecId, OpTransaction, precompiles::OpPrecompiles};\n    use revm::{\n        Journal,\n        context::{BlockEnv, CfgEnv, Evm as RevmEvm, JournalTr, LocalContext, TxEnv},\n        database::{EmptyDB, EmptyDBTyped},\n        handler::{EthPrecompiles, instructions::EthInstructions},\n        inspector::NoOpInspector,\n        interpreter::interpreter::EthInterpreter,\n        precompile::{PrecompileOutput, PrecompileSpecId, Precompiles},\n        primitives::hardfork::SpecId,\n    };\n\n    // A precompile activated in the `Prague` spec (BLS12-381 G2 map).\n    const ETH_PRAGUE_PRECOMPILE: Address = address!(\"0x0000000000000000000000000000000000000011\");\n\n    // A precompile activated in the `Osaka` spec (EIP-7951).\n    const ETH_OSAKA_PRECOMPILE: Address = address!(\"0x0000000000000000000000000000000000000100\");\n\n    // A precompile activated in the `Isthmus` spec.\n    const OP_ISTHMUS_PRECOMPILE: Address = address!(\"0x0000000000000000000000000000000000000100\");\n\n    // A custom precompile address and payload for testing.\n    const PRECOMPILE_ADDR: Address = address!(\"0x0000000000000000000000000000000000000071\");\n    const PAYLOAD: &[u8] = &[0xde, 0xad, 0xbe, 0xef];\n\n    #[derive(Debug)]\n    struct CustomPrecompileFactory;\n\n    impl PrecompileFactory for CustomPrecompileFactory {\n        fn precompiles(&self) -> Vec<(Address, DynPrecompile)> {\n            use alloy_evm::precompiles::PrecompileInput;\n            vec![(\n                PRECOMPILE_ADDR,\n                DynPrecompile::from(|input: PrecompileInput<'_>| {\n                    Ok(PrecompileOutput {\n                        bytes: Bytes::copy_from_slice(input.data),\n                        gas_used: 0,\n                        gas_refunded: 0,\n                        reverted: false,\n                    })\n                }),\n            )]\n        }\n    }\n\n    /// Creates a new EVM instance with the custom precompile factory.\n    fn create_eth_evm(\n        spec: SpecId,\n    ) -> (TxEnv, EitherEvm<EmptyDBTyped<Infallible>, NoOpInspector, PrecompilesMap>) {\n        let tx_env = TxEnv {\n            kind: TxKind::Call(PRECOMPILE_ADDR),\n            data: PAYLOAD.into(),\n            ..Default::default()\n        };\n\n        let eth_evm_context = EthEvmContext {\n            journaled_state: Journal::new(EmptyDB::default()),\n            block: BlockEnv::default(),\n            cfg: CfgEnv::new_with_spec(spec),\n            tx: tx_env.clone(),\n            chain: (),\n            local: LocalContext::default(),\n            error: Ok(()),\n        };\n\n        let eth_precompiles = EthPrecompiles {\n            precompiles: Precompiles::new(PrecompileSpecId::from_spec_id(spec)),\n            spec,\n        }\n        .precompiles;\n        let eth_evm = EitherEvm::Eth(EthEvm::new(\n            RevmEvm::new_with_inspector(\n                eth_evm_context,\n                NoOpInspector,\n                EthInstructions::<EthInterpreter, EthEvmContext<EmptyDB>>::default(),\n                PrecompilesMap::from_static(eth_precompiles),\n            ),\n            true,\n        ));\n\n        (tx_env, eth_evm)\n    }\n\n    /// Creates a new OP EVM instance with the custom precompile factory.\n    fn create_op_evm(\n        spec: SpecId,\n        op_spec: OpSpecId,\n    ) -> (OpTransaction<TxEnv>, EitherEvm<EmptyDBTyped<Infallible>, NoOpInspector, PrecompilesMap>)\n    {\n        let tx = OpTransaction::<TxEnv> {\n            base: TxEnv {\n                kind: TxKind::Call(PRECOMPILE_ADDR),\n                data: PAYLOAD.into(),\n                ..Default::default()\n            },\n            ..Default::default()\n        };\n\n        let mut chain = L1BlockInfo::default();\n\n        if op_spec == OpSpecId::ISTHMUS {\n            chain.operator_fee_constant = Some(U256::from(0));\n            chain.operator_fee_scalar = Some(U256::from(0));\n        }\n\n        let op_cfg: CfgEnv<OpSpecId> = CfgEnv::new_with_spec(op_spec);\n        let op_evm_context = OpContext {\n            journaled_state: {\n                let mut journal = Journal::new(EmptyDB::default());\n                // Converting SpecId into OpSpecId\n                journal.set_spec_id(spec);\n                journal\n            },\n            block: BlockEnv::default(),\n            cfg: op_cfg.clone(),\n            tx: tx.clone(),\n            chain,\n            local: LocalContext::default(),\n            error: Ok(()),\n        };\n\n        let op_precompiles = OpPrecompiles::new_with_spec(op_cfg.spec).precompiles();\n        let op_evm = EitherEvm::Op(OpEvm::new(\n            op_revm::OpEvm(RevmEvm::new_with_inspector(\n                op_evm_context,\n                NoOpInspector,\n                EthInstructions::<EthInterpreter, OpContext<EmptyDB>>::default(),\n                PrecompilesMap::from_static(op_precompiles),\n            )),\n            true,\n        ));\n\n        (tx, op_evm)\n    }\n\n    #[test]\n    fn build_eth_evm_with_extra_precompiles_osaka_spec() {\n        let (tx_env, mut evm) = create_eth_evm(SpecId::OSAKA);\n\n        // Check that the Osaka precompile IS present when using the Osaka spec.\n        assert!(evm.precompiles().addresses().contains(&ETH_OSAKA_PRECOMPILE));\n\n        // Check that the Prague precompile IS present when using the Osaka spec.\n        assert!(evm.precompiles().addresses().contains(&ETH_PRAGUE_PRECOMPILE));\n\n        assert!(!evm.precompiles().addresses().contains(&PRECOMPILE_ADDR));\n\n        evm.precompiles_mut().extend_precompiles(CustomPrecompileFactory.precompiles());\n\n        assert!(evm.precompiles().addresses().contains(&PRECOMPILE_ADDR));\n\n        let result = match &mut evm {\n            EitherEvm::Eth(eth_evm) => eth_evm.transact(tx_env).unwrap(),\n            _ => unreachable!(),\n        };\n\n        assert!(result.result.is_success());\n        assert_eq!(result.result.output(), Some(&PAYLOAD.into()));\n    }\n\n    #[test]\n    fn build_eth_evm_with_extra_precompiles_london_spec() {\n        let (tx_env, mut evm) = create_eth_evm(SpecId::LONDON);\n\n        // Check that the Osaka precompile IS NOT present when using the London spec.\n        assert!(!evm.precompiles().addresses().contains(&ETH_OSAKA_PRECOMPILE));\n\n        // Check that the Prague precompile IS NOT present when using the London spec.\n        assert!(!evm.precompiles().addresses().contains(&ETH_PRAGUE_PRECOMPILE));\n\n        assert!(!evm.precompiles().addresses().contains(&PRECOMPILE_ADDR));\n\n        evm.precompiles_mut().extend_precompiles(CustomPrecompileFactory.precompiles());\n\n        assert!(evm.precompiles().addresses().contains(&PRECOMPILE_ADDR));\n\n        let result = match &mut evm {\n            EitherEvm::Eth(eth_evm) => eth_evm.transact(tx_env).unwrap(),\n            _ => unreachable!(),\n        };\n\n        assert!(result.result.is_success());\n        assert_eq!(result.result.output(), Some(&PAYLOAD.into()));\n    }\n\n    #[test]\n    fn build_eth_evm_with_extra_precompiles_prague_spec() {\n        let (tx_env, mut evm) = create_eth_evm(SpecId::PRAGUE);\n\n        // Check that the Osaka precompile IS NOT present when using the Prague spec.\n        assert!(!evm.precompiles().addresses().contains(&ETH_OSAKA_PRECOMPILE));\n\n        // Check that the Prague precompile IS present when using the Prague spec.\n        assert!(evm.precompiles().addresses().contains(&ETH_PRAGUE_PRECOMPILE));\n\n        assert!(!evm.precompiles().addresses().contains(&PRECOMPILE_ADDR));\n\n        evm.precompiles_mut().extend_precompiles(CustomPrecompileFactory.precompiles());\n\n        assert!(evm.precompiles().addresses().contains(&PRECOMPILE_ADDR));\n\n        let result = match &mut evm {\n            EitherEvm::Eth(eth_evm) => eth_evm.transact(tx_env).unwrap(),\n            _ => unreachable!(),\n        };\n\n        assert!(result.result.is_success());\n        assert_eq!(result.result.output(), Some(&PAYLOAD.into()));\n    }\n\n    #[test]\n    fn build_op_evm_with_extra_precompiles_isthmus_spec() {\n        let (tx, mut evm) = create_op_evm(SpecId::OSAKA, OpSpecId::ISTHMUS);\n\n        // Check that the Isthmus precompile IS present when using the Isthmus spec.\n        assert!(evm.precompiles().addresses().contains(&OP_ISTHMUS_PRECOMPILE));\n\n        // Check that the Prague precompile IS present when using the Isthmus spec.\n        assert!(evm.precompiles().addresses().contains(&ETH_PRAGUE_PRECOMPILE));\n\n        assert!(!evm.precompiles().addresses().contains(&PRECOMPILE_ADDR));\n\n        evm.precompiles_mut().extend_precompiles(CustomPrecompileFactory.precompiles());\n\n        assert!(evm.precompiles().addresses().contains(&PRECOMPILE_ADDR));\n\n        let result = match &mut evm {\n            EitherEvm::Op(op_evm) => op_evm.transact(tx).unwrap(),\n            _ => unreachable!(),\n        };\n\n        assert!(result.result.is_success());\n        assert_eq!(result.result.output(), Some(&PAYLOAD.into()));\n    }\n\n    #[test]\n    fn build_op_evm_with_extra_precompiles_bedrock_spec() {\n        let (tx, mut evm) = create_op_evm(SpecId::OSAKA, OpSpecId::BEDROCK);\n\n        // Check that the Isthmus precompile IS NOT present when using the `OpSpecId::BEDROCK` spec.\n        assert!(!evm.precompiles().addresses().contains(&OP_ISTHMUS_PRECOMPILE));\n\n        // Check that the Prague precompile IS NOT present when using the `OpSpecId::BEDROCK` spec.\n        assert!(!evm.precompiles().addresses().contains(&ETH_PRAGUE_PRECOMPILE));\n\n        assert!(!evm.precompiles().addresses().contains(&PRECOMPILE_ADDR));\n\n        evm.precompiles_mut().extend_precompiles(CustomPrecompileFactory.precompiles());\n\n        assert!(evm.precompiles().addresses().contains(&PRECOMPILE_ADDR));\n\n        let result = match &mut evm {\n            EitherEvm::Op(op_evm) => op_evm.transact(tx).unwrap(),\n            _ => unreachable!(),\n        };\n\n        assert!(result.result.is_success());\n        assert_eq!(result.result.output(), Some(&PAYLOAD.into()));\n    }\n}\n"
  },
  {
    "path": "crates/anvil/src/filter.rs",
    "content": "//! Support for polling based filters\nuse crate::{\n    StorageInfo,\n    eth::{backend::notifications::NewBlockNotifications, error::ToRpcResponseResult},\n    pubsub::filter_logs,\n};\nuse alloy_consensus::TxReceipt;\nuse alloy_network::Network;\nuse alloy_primitives::{TxHash, map::HashMap};\nuse alloy_rpc_types::{Filter, FilteredParams, Log};\nuse anvil_core::eth::subscription::SubscriptionId;\nuse anvil_rpc::{\n    error::{ErrorCode, RpcError},\n    response::ResponseResult,\n};\nuse futures::{Stream, StreamExt, channel::mpsc::Receiver};\nuse std::{\n    pin::Pin,\n    sync::Arc,\n    task::{Context, Poll},\n    time::{Duration, Instant},\n};\nuse tokio::sync::Mutex;\n\n/// Type alias for filters identified by their id and their expiration timestamp\ntype FilterMap<N> = Arc<Mutex<HashMap<String, (EthFilter<N>, Instant)>>>;\n\n/// timeout after which to remove an active filter if it wasn't polled since then\npub const ACTIVE_FILTER_TIMEOUT_SECS: u64 = 60 * 5;\n\n/// Contains all registered filters\npub struct Filters<N: Network> {\n    /// all currently active filters\n    active_filters: FilterMap<N>,\n    /// How long we keep a live the filter after the last poll\n    keepalive: Duration,\n}\n\nimpl<N: Network> Clone for Filters<N> {\n    fn clone(&self) -> Self {\n        Self { active_filters: self.active_filters.clone(), keepalive: self.keepalive }\n    }\n}\n\nimpl<N: Network> std::fmt::Debug for Filters<N> {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        f.debug_struct(\"Filters\").field(\"keepalive\", &self.keepalive).finish_non_exhaustive()\n    }\n}\n\nimpl<N: Network> Filters<N> {\n    /// Adds a new `EthFilter` to the set\n    pub async fn add_filter(&self, filter: EthFilter<N>) -> String {\n        let id = new_id();\n        trace!(target: \"node::filter\", \"Adding new filter id {}\", id);\n        let mut filters = self.active_filters.lock().await;\n        filters.insert(id.clone(), (filter, self.next_deadline()));\n        id\n    }\n\n    /// Returns the original `Filter` of an `eth_newFilter`\n    pub async fn get_log_filter(&self, id: &str) -> Option<Filter> {\n        let filters = self.active_filters.lock().await;\n        if let Some((EthFilter::Logs(log), _)) = filters.get(id) {\n            return log.filter.filter.clone();\n        }\n        None\n    }\n\n    /// Removes the filter identified with the `id`\n    pub async fn uninstall_filter(&self, id: &str) -> Option<EthFilter<N>> {\n        trace!(target: \"node::filter\", \"Uninstalling filter id {}\", id);\n        self.active_filters.lock().await.remove(id).map(|(f, _)| f)\n    }\n\n    /// The duration how long to keep alive stale filters\n    pub fn keep_alive(&self) -> Duration {\n        self.keepalive\n    }\n\n    /// Returns the timestamp after which a filter should expire\n    fn next_deadline(&self) -> Instant {\n        Instant::now() + self.keep_alive()\n    }\n\n    /// Evict all filters that weren't updated and reached there deadline\n    pub async fn evict(&self) {\n        trace!(target: \"node::filter\", \"Evicting stale filters\");\n        let now = Instant::now();\n        let mut active_filters = self.active_filters.lock().await;\n        active_filters.retain(|id, (_, deadline)| {\n            if now > *deadline {\n                trace!(target: \"node::filter\",?id, \"Evicting stale filter\");\n                return false;\n            }\n            true\n        });\n    }\n}\n\nimpl<N: Network> Filters<N>\nwhere\n    N::ReceiptEnvelope: TxReceipt<Log = alloy_primitives::Log> + Clone,\n{\n    pub async fn get_filter_changes(&self, id: &str) -> ResponseResult {\n        {\n            let mut filters = self.active_filters.lock().await;\n            if let Some((filter, deadline)) = filters.get_mut(id) {\n                let resp = filter\n                    .next()\n                    .await\n                    .unwrap_or_else(|| ResponseResult::success(Vec::<()>::new()));\n                *deadline = self.next_deadline();\n                return resp;\n            }\n        }\n        warn!(target: \"node::filter\", \"No filter found for {}\", id);\n        ResponseResult::error(RpcError {\n            code: ErrorCode::ServerError(-32000),\n            message: \"filter not found\".into(),\n            data: None,\n        })\n    }\n}\n\nimpl<N: Network> Default for Filters<N> {\n    fn default() -> Self {\n        Self {\n            active_filters: Arc::new(Default::default()),\n            keepalive: Duration::from_secs(ACTIVE_FILTER_TIMEOUT_SECS),\n        }\n    }\n}\n\n/// returns a new random hex id\nfn new_id() -> String {\n    SubscriptionId::random_hex().to_string()\n}\n\n/// Represents a poll based filter\npub enum EthFilter<N: Network> {\n    Logs(Box<LogsFilter<N>>),\n    Blocks(NewBlockNotifications),\n    PendingTransactions(Receiver<TxHash>),\n}\n\nimpl<N: Network> std::fmt::Debug for EthFilter<N> {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        match self {\n            Self::Logs(_) => f.debug_tuple(\"Logs\").finish(),\n            Self::Blocks(_) => f.debug_tuple(\"Blocks\").finish(),\n            Self::PendingTransactions(_) => f.debug_tuple(\"PendingTransactions\").finish(),\n        }\n    }\n}\n\nimpl<N: Network> Stream for EthFilter<N>\nwhere\n    N::ReceiptEnvelope: TxReceipt<Log = alloy_primitives::Log> + Clone,\n{\n    type Item = ResponseResult;\n\n    fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {\n        let pin = self.get_mut();\n        match pin {\n            Self::Logs(logs) => Poll::Ready(Some(Ok(logs.poll(cx)).to_rpc_result())),\n            Self::Blocks(blocks) => {\n                let mut new_blocks = Vec::new();\n                while let Poll::Ready(Some(block)) = blocks.poll_next_unpin(cx) {\n                    new_blocks.push(block.hash);\n                }\n                Poll::Ready(Some(Ok(new_blocks).to_rpc_result()))\n            }\n            Self::PendingTransactions(tx) => {\n                let mut new_txs = Vec::new();\n                while let Poll::Ready(Some(tx_hash)) = tx.poll_next_unpin(cx) {\n                    new_txs.push(tx_hash);\n                }\n                Poll::Ready(Some(Ok(new_txs).to_rpc_result()))\n            }\n        }\n    }\n}\n\n/// Listens for new blocks and matching logs emitted in that block\npub struct LogsFilter<N: Network> {\n    /// listener for new blocks\n    pub blocks: NewBlockNotifications,\n    /// accessor for block storage\n    pub storage: StorageInfo<N>,\n    /// matcher with all provided filter params\n    pub filter: FilteredParams,\n    /// existing logs that matched the filter when the listener was installed\n    ///\n    /// They'll be returned on the first poll\n    pub historic: Option<Vec<Log>>,\n}\n\nimpl<N: Network> std::fmt::Debug for LogsFilter<N> {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        f.debug_struct(\"LogsFilter\").field(\"filter\", &self.filter).finish_non_exhaustive()\n    }\n}\n\nimpl<N: Network> LogsFilter<N>\nwhere\n    N::ReceiptEnvelope: TxReceipt<Log = alloy_primitives::Log> + Clone,\n{\n    /// Returns all the logs since the last time this filter was polled\n    pub fn poll(&mut self, cx: &mut Context<'_>) -> Vec<Log> {\n        let mut logs = self.historic.take().unwrap_or_default();\n        while let Poll::Ready(Some(block)) = self.blocks.poll_next_unpin(cx) {\n            let b = self.storage.block(block.hash);\n            let receipts = self.storage.receipts(block.hash);\n            if let (Some(receipts), Some(block)) = (receipts, b) {\n                logs.extend(filter_logs(block, receipts, &self.filter))\n            }\n        }\n        logs\n    }\n}\n"
  },
  {
    "path": "crates/anvil/src/lib.rs",
    "content": "//! Anvil is a fast local Ethereum development node.\n\n#![cfg_attr(not(test), warn(unused_crate_dependencies))]\n#![cfg_attr(docsrs, feature(doc_cfg))]\n\nuse crate::{\n    error::{NodeError, NodeResult},\n    eth::{\n        EthApi,\n        backend::{info::StorageInfo, mem},\n        fees::{FeeHistoryService, FeeManager},\n        miner::{Miner, MiningMode},\n        pool::Pool,\n        sign::{DevSigner, Signer as EthSigner},\n    },\n    filter::Filters,\n    logging::{LoggingManager, NodeLogLayer},\n    service::NodeService,\n    shutdown::Signal,\n    tasks::TaskManager,\n};\nuse alloy_eips::eip7840::BlobParams;\nuse alloy_primitives::{Address, U256};\nuse alloy_signer_local::PrivateKeySigner;\nuse eth::backend::fork::ClientFork;\nuse eyre::{Result, WrapErr};\nuse foundry_common::provider::{ProviderBuilder, RetryProvider};\npub use foundry_evm::hardfork::EthereumHardfork;\nuse foundry_primitives::FoundryNetwork;\nuse futures::{FutureExt, TryFutureExt};\nuse parking_lot::Mutex;\nuse revm::primitives::hardfork::SpecId;\nuse server::try_spawn_ipc;\nuse std::{\n    net::SocketAddr,\n    pin::Pin,\n    sync::Arc,\n    task::{Context, Poll},\n};\nuse tokio::{\n    runtime::Handle,\n    task::{JoinError, JoinHandle},\n};\nuse tracing_subscriber::EnvFilter;\n\n/// contains the background service that drives the node\nmod service;\n\nmod config;\npub use config::{\n    AccountGenerator, CHAIN_ID, DEFAULT_GAS_LIMIT, ForkChoice, NodeConfig, VERSION_MESSAGE,\n};\n\nmod error;\n/// ethereum related implementations\npub mod eth;\n/// Evm related abstractions\nmod evm;\npub use evm::PrecompileFactory;\n\n/// support for polling filters\npub mod filter;\n/// commandline output\npub mod logging;\n/// types for subscriptions\npub mod pubsub;\n/// axum RPC server implementations\npub mod server;\n/// Futures for shutdown signal\nmod shutdown;\n/// additional task management\nmod tasks;\n\n/// contains cli command\n#[cfg(feature = \"cmd\")]\npub mod cmd;\n\n#[cfg(feature = \"cmd\")]\npub mod args;\n\n#[cfg(feature = \"cmd\")]\npub mod opts;\n\n#[macro_use]\nextern crate foundry_common;\n\n#[macro_use]\nextern crate tracing;\n\n/// Creates the node and runs the server.\n///\n/// Returns the [EthApi] that can be used to interact with the node and the [JoinHandle] of the\n/// task.\n///\n/// # Panics\n///\n/// Panics if any error occurs. For a non-panicking version, use [`try_spawn`].\n///\n///\n/// # Examples\n///\n/// ```no_run\n/// # use anvil::NodeConfig;\n/// # async fn spawn() -> eyre::Result<()> {\n/// let config = NodeConfig::default();\n/// let (api, handle) = anvil::spawn(config).await;\n///\n/// // use api\n///\n/// // wait forever\n/// handle.await.unwrap().unwrap();\n/// # Ok(())\n/// # }\n/// ```\npub async fn spawn(config: NodeConfig) -> (EthApi<FoundryNetwork>, NodeHandle) {\n    try_spawn(config).await.expect(\"failed to spawn node\")\n}\n\n/// Creates the node and runs the server\n///\n/// Returns the [EthApi] that can be used to interact with the node and the [JoinHandle] of the\n/// task.\n///\n/// # Examples\n///\n/// ```no_run\n/// # use anvil::NodeConfig;\n/// # async fn spawn() -> eyre::Result<()> {\n/// let config = NodeConfig::default();\n/// let (api, handle) = anvil::try_spawn(config).await?;\n///\n/// // use api\n///\n/// // wait forever\n/// handle.await??;\n/// # Ok(())\n/// # }\n/// ```\npub async fn try_spawn(mut config: NodeConfig) -> Result<(EthApi<FoundryNetwork>, NodeHandle)> {\n    let logger = if config.enable_tracing { init_tracing() } else { Default::default() };\n    logger.set_enabled(!config.silent);\n\n    let backend = config.setup::<FoundryNetwork>().await?;\n\n    if let Some(state) = config.init_state.clone() {\n        backend.load_state(state).await.wrap_err(\"failed to load init state\")?;\n    }\n\n    let backend = Arc::new(backend);\n\n    if config.enable_auto_impersonate {\n        backend.auto_impersonate_account(true);\n    }\n\n    let fork = backend.get_fork();\n\n    let NodeConfig {\n        signer_accounts,\n        block_time,\n        port,\n        max_transactions,\n        server_config,\n        no_mining,\n        transaction_order,\n        genesis,\n        mixed_mining,\n        ..\n    } = config.clone();\n\n    let pool = Arc::new(Pool::default());\n\n    let mode = if let Some(block_time) = block_time {\n        if mixed_mining {\n            let listener = pool.add_ready_listener();\n            MiningMode::mixed(max_transactions, listener, block_time)\n        } else {\n            MiningMode::interval(block_time)\n        }\n    } else if no_mining {\n        MiningMode::None\n    } else {\n        // get a listener for ready transactions\n        let listener = pool.add_ready_listener();\n        MiningMode::instant(max_transactions, listener)\n    };\n\n    let miner = match &fork {\n        Some(fork) => {\n            Miner::new(mode).with_forced_transactions(fork.config.read().force_transactions.clone())\n        }\n        _ => Miner::new(mode),\n    };\n\n    let dev_signer: Box<dyn EthSigner<foundry_primitives::FoundryNetwork>> =\n        Box::new(DevSigner::new(signer_accounts));\n    let mut signers = vec![dev_signer];\n    if let Some(genesis) = genesis {\n        let genesis_signers = genesis\n            .alloc\n            .values()\n            .filter_map(|acc| acc.private_key)\n            .flat_map(|k| PrivateKeySigner::from_bytes(&k))\n            .collect::<Vec<_>>();\n        if !genesis_signers.is_empty() {\n            signers.push(Box::new(DevSigner::new(genesis_signers)));\n        }\n    }\n\n    let fee_history_cache = Arc::new(Mutex::new(Default::default()));\n    let fee_history_service = FeeHistoryService::new(\n        match backend.spec_id() {\n            SpecId::OSAKA => BlobParams::osaka(),\n            SpecId::PRAGUE => BlobParams::prague(),\n            _ => BlobParams::cancun(),\n        },\n        backend.new_block_notifications(),\n        Arc::clone(&fee_history_cache),\n        StorageInfo::new(Arc::clone(&backend)),\n    );\n    // create an entry for the best block\n    if let Some(header) = backend.get_block(backend.best_number()).map(|block| block.header) {\n        fee_history_service.insert_cache_entry_for_block(header.hash_slow(), &header);\n    }\n\n    let filters = Filters::default();\n\n    // create the cloneable api wrapper\n    let api = EthApi::new(\n        Arc::clone(&pool),\n        Arc::clone(&backend),\n        Arc::new(signers),\n        fee_history_cache,\n        fee_history_service.fee_history_limit(),\n        miner.clone(),\n        logger,\n        filters.clone(),\n        transaction_order,\n    );\n\n    // spawn the node service\n    let node_service =\n        tokio::task::spawn(NodeService::new(pool, backend, miner, fee_history_service, filters));\n\n    let mut servers = Vec::with_capacity(config.host.len());\n    let mut addresses = Vec::with_capacity(config.host.len());\n\n    for addr in &config.host {\n        let sock_addr = SocketAddr::new(*addr, port);\n\n        // Create a TCP listener.\n        let tcp_listener = tokio::net::TcpListener::bind(sock_addr).await?;\n        addresses.push(tcp_listener.local_addr()?);\n\n        // Spawn the server future on a new task.\n        let srv = server::serve_on(tcp_listener, api.clone(), server_config.clone());\n        servers.push(tokio::task::spawn(srv.map_err(Into::into)));\n    }\n\n    let tokio_handle = Handle::current();\n    let (signal, on_shutdown) = shutdown::signal();\n    let task_manager = TaskManager::new(tokio_handle, on_shutdown);\n\n    let ipc_task =\n        config.get_ipc_path().map(|path| try_spawn_ipc(api.clone(), path)).transpose()?;\n\n    let handle = NodeHandle {\n        config,\n        node_service,\n        servers,\n        ipc_task,\n        addresses,\n        _signal: Some(signal),\n        task_manager,\n    };\n\n    handle.print(fork.as_ref())?;\n\n    Ok((api, handle))\n}\n\ntype IpcTask = JoinHandle<()>;\n\n/// A handle to the spawned node and server tasks.\n///\n/// This future will resolve if either the node or server task resolve/fail.\npub struct NodeHandle {\n    config: NodeConfig,\n    /// The address of the running rpc server.\n    addresses: Vec<SocketAddr>,\n    /// Join handle for the Node Service.\n    pub node_service: JoinHandle<Result<(), NodeError>>,\n    /// Join handles (one per socket) for the Anvil server.\n    pub servers: Vec<JoinHandle<Result<(), NodeError>>>,\n    /// The future that joins the ipc server, if any.\n    ipc_task: Option<IpcTask>,\n    /// A signal that fires the shutdown, fired on drop.\n    _signal: Option<Signal>,\n    /// A task manager that can be used to spawn additional tasks.\n    task_manager: TaskManager,\n}\n\nimpl Drop for NodeHandle {\n    fn drop(&mut self) {\n        // Fire shutdown signal to make sure anvil instance is terminated.\n        if let Some(signal) = self._signal.take() {\n            let _ = signal.fire();\n        }\n    }\n}\n\nimpl NodeHandle {\n    /// The [NodeConfig] the node was launched with.\n    pub fn config(&self) -> &NodeConfig {\n        &self.config\n    }\n\n    /// Prints the launch info.\n    pub(crate) fn print(&self, fork: Option<&ClientFork>) -> Result<()> {\n        self.config.print(fork)?;\n        if !self.config.silent {\n            if let Some(ipc_path) = self.ipc_path() {\n                sh_println!(\"IPC path: {ipc_path}\")?;\n            }\n            sh_println!(\n                \"Listening on {}\",\n                self.addresses\n                    .iter()\n                    .map(|addr| { addr.to_string() })\n                    .collect::<Vec<String>>()\n                    .join(\", \")\n            )?;\n        }\n        Ok(())\n    }\n\n    /// The address of the launched server.\n    ///\n    /// **N.B.** this may not necessarily be the same `host + port` as configured in the\n    /// `NodeConfig`, if port was set to 0, then the OS auto picks an available port.\n    pub fn socket_address(&self) -> &SocketAddr {\n        &self.addresses[0]\n    }\n\n    /// Returns the http endpoint.\n    pub fn http_endpoint(&self) -> String {\n        format!(\"http://{}\", self.socket_address())\n    }\n\n    /// Returns the websocket endpoint.\n    pub fn ws_endpoint(&self) -> String {\n        format!(\"ws://{}\", self.socket_address())\n    }\n\n    /// Returns the path of the launched ipc server, if any.\n    pub fn ipc_path(&self) -> Option<String> {\n        self.config.get_ipc_path()\n    }\n\n    /// Constructs a [`RetryProvider`] for this handle's HTTP endpoint.\n    pub fn http_provider(&self) -> RetryProvider {\n        ProviderBuilder::new(&self.http_endpoint()).build().expect(\"failed to build HTTP provider\")\n    }\n\n    /// Constructs a [`RetryProvider`] for this handle's WS endpoint.\n    pub fn ws_provider(&self) -> RetryProvider {\n        ProviderBuilder::new(&self.ws_endpoint()).build().expect(\"failed to build WS provider\")\n    }\n\n    /// Constructs a [`RetryProvider`] for this handle's IPC endpoint, if any.\n    pub fn ipc_provider(&self) -> Option<RetryProvider> {\n        ProviderBuilder::new(&self.config.get_ipc_path()?).build().ok()\n    }\n\n    /// Signer accounts that can sign messages/transactions from the EVM node.\n    pub fn dev_accounts(&self) -> impl Iterator<Item = Address> + '_ {\n        self.config.signer_accounts.iter().map(|wallet| wallet.address())\n    }\n\n    /// Signer accounts that can sign messages/transactions from the EVM node.\n    pub fn dev_wallets(&self) -> impl Iterator<Item = PrivateKeySigner> + '_ {\n        self.config.signer_accounts.iter().cloned()\n    }\n\n    /// Accounts that will be initialised with `genesis_balance` in the genesis block.\n    pub fn genesis_accounts(&self) -> impl Iterator<Item = Address> + '_ {\n        self.config.genesis_accounts.iter().map(|w| w.address())\n    }\n\n    /// Native token balance of every genesis account in the genesis block.\n    pub fn genesis_balance(&self) -> U256 {\n        self.config.genesis_balance\n    }\n\n    /// Default gas price for all txs.\n    pub fn gas_price(&self) -> u128 {\n        self.config.get_gas_price()\n    }\n\n    /// Returns the shutdown signal.\n    pub fn shutdown_signal(&self) -> &Option<Signal> {\n        &self._signal\n    }\n\n    /// Returns mutable access to the shutdown signal.\n    ///\n    /// This can be used to extract the Signal.\n    pub fn shutdown_signal_mut(&mut self) -> &mut Option<Signal> {\n        &mut self._signal\n    }\n\n    /// Returns the task manager that can be used to spawn new tasks.\n    ///\n    /// ```\n    /// use anvil::NodeHandle;\n    /// # fn t(handle: NodeHandle) {\n    /// let task_manager = handle.task_manager();\n    /// let on_shutdown = task_manager.on_shutdown();\n    ///\n    /// task_manager.spawn(async move {\n    ///     on_shutdown.await;\n    ///     // do something\n    /// });\n    ///\n    /// # }\n    /// ```\n    pub fn task_manager(&self) -> &TaskManager {\n        &self.task_manager\n    }\n}\n\nimpl Future for NodeHandle {\n    type Output = Result<NodeResult<()>, JoinError>;\n\n    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {\n        let pin = self.get_mut();\n\n        // poll the ipc task\n        if let Some(mut ipc) = pin.ipc_task.take() {\n            if let Poll::Ready(res) = ipc.poll_unpin(cx) {\n                return Poll::Ready(res.map(|()| Ok(())));\n            } else {\n                pin.ipc_task = Some(ipc);\n            }\n        }\n\n        // poll the node service task\n        if let Poll::Ready(res) = pin.node_service.poll_unpin(cx) {\n            return Poll::Ready(res);\n        }\n\n        // poll the axum server handles\n        for server in &mut pin.servers {\n            if let Poll::Ready(res) = server.poll_unpin(cx) {\n                return Poll::Ready(res);\n            }\n        }\n\n        Poll::Pending\n    }\n}\n\n#[doc(hidden)]\npub fn init_tracing() -> LoggingManager {\n    use tracing_subscriber::prelude::*;\n\n    let manager = LoggingManager::default();\n\n    let _ = if let Ok(rust_log_val) = std::env::var(\"RUST_LOG\")\n        && !rust_log_val.contains(\"=\")\n    {\n        // Mutate the given filter to include `node` logs if it is not already present.\n        // This prevents the unexpected behaviour of not seeing any node logs if a RUST_LOG\n        // is already present that doesn't set it.\n        let rust_log_val = if !rust_log_val.contains(\"node\") {\n            format!(\"{rust_log_val},node=info\")\n        } else {\n            rust_log_val\n        };\n\n        let env_filter: EnvFilter =\n            rust_log_val.parse().expect(\"failed to parse modified RUST_LOG\");\n        tracing_subscriber::registry()\n            .with(env_filter)\n            .with(tracing_subscriber::fmt::layer())\n            .try_init()\n    } else {\n        tracing_subscriber::Registry::default()\n            .with(NodeLogLayer::new(manager.clone()))\n            .with(\n                tracing_subscriber::fmt::layer()\n                    .without_time()\n                    .with_target(false)\n                    .with_level(false),\n            )\n            .try_init()\n    };\n\n    manager\n}\n"
  },
  {
    "path": "crates/anvil/src/logging.rs",
    "content": "//! User facing Logger\n\nuse parking_lot::RwLock;\nuse std::sync::Arc;\nuse tracing::{Metadata, subscriber::Interest};\nuse tracing_subscriber::{Layer, layer::Context};\n\n/// The target that identifies the events intended to be logged to stdout\npub(crate) const NODE_USER_LOG_TARGET: &str = \"node::user\";\n\n/// The target that identifies the events coming from the `console.log` invocations.\npub(crate) const EVM_CONSOLE_LOG_TARGET: &str = \"node::console\";\n\n/// A logger that listens for node related events and displays them.\n///\n/// This layer is intended to be used as filter for `NODE_USER_LOG_TARGET` events that will\n/// eventually be logged to stdout\n#[derive(Clone, Debug, Default)]\npub struct NodeLogLayer {\n    state: LoggingManager,\n}\n\nimpl NodeLogLayer {\n    /// Returns a new instance of this layer\n    pub fn new(state: LoggingManager) -> Self {\n        Self { state }\n    }\n}\n\n// use `Layer`'s filter function to globally enable/disable `NODE_USER_LOG_TARGET` events\nimpl<S> Layer<S> for NodeLogLayer\nwhere\n    S: tracing::Subscriber,\n{\n    fn register_callsite(&self, metadata: &'static Metadata<'static>) -> Interest {\n        if metadata.target() == NODE_USER_LOG_TARGET || metadata.target() == EVM_CONSOLE_LOG_TARGET\n        {\n            Interest::sometimes()\n        } else {\n            Interest::never()\n        }\n    }\n\n    fn enabled(&self, metadata: &Metadata<'_>, _ctx: Context<'_, S>) -> bool {\n        self.state.is_enabled()\n            && (metadata.target() == NODE_USER_LOG_TARGET\n                || metadata.target() == EVM_CONSOLE_LOG_TARGET)\n    }\n}\n\n/// Contains the configuration of the logger\n#[derive(Clone, Debug)]\npub struct LoggingManager {\n    /// Whether the logger is currently enabled\n    pub enabled: Arc<RwLock<bool>>,\n}\n\nimpl LoggingManager {\n    /// Returns true if logging is currently enabled\n    pub fn is_enabled(&self) -> bool {\n        *self.enabled.read()\n    }\n\n    /// Updates the `enabled` state\n    pub fn set_enabled(&self, enabled: bool) {\n        let mut current = self.enabled.write();\n        *current = enabled;\n    }\n}\n\nimpl Default for LoggingManager {\n    fn default() -> Self {\n        Self { enabled: Arc::new(RwLock::new(true)) }\n    }\n}\n"
  },
  {
    "path": "crates/anvil/src/opts.rs",
    "content": "use crate::cmd::NodeArgs;\nuse clap::{Parser, Subcommand};\nuse foundry_cli::opts::GlobalArgs;\nuse foundry_common::version::{LONG_VERSION, SHORT_VERSION};\n\n/// A fast local Ethereum development node.\n#[derive(Parser)]\n#[command(name = \"anvil\", version = SHORT_VERSION, long_version = LONG_VERSION, next_display_order = None)]\npub struct Anvil {\n    /// Include the global arguments.\n    #[command(flatten)]\n    pub global: GlobalArgs,\n\n    #[command(flatten)]\n    pub node: NodeArgs,\n\n    #[command(subcommand)]\n    pub cmd: Option<AnvilSubcommand>,\n}\n\n#[derive(Subcommand)]\npub enum AnvilSubcommand {\n    /// Generate shell completions script.\n    #[command(visible_alias = \"com\")]\n    Completions {\n        #[arg(value_enum)]\n        shell: foundry_cli::clap::Shell,\n    },\n}\n"
  },
  {
    "path": "crates/anvil/src/pubsub.rs",
    "content": "use crate::{\n    StorageInfo,\n    eth::{backend::notifications::NewBlockNotifications, error::to_rpc_result},\n};\nuse alloy_consensus::{BlockHeader, TxReceipt};\nuse alloy_network::{AnyRpcTransaction, Network};\nuse alloy_primitives::{B256, TxHash};\nuse alloy_rpc_types::{FilteredParams, Log, Transaction, pubsub::SubscriptionResult};\nuse anvil_core::eth::{block::Block, subscription::SubscriptionId};\nuse anvil_rpc::{request::Version, response::ResponseResult};\nuse futures::{Stream, StreamExt, channel::mpsc::Receiver, ready};\nuse serde::Serialize;\nuse std::{\n    collections::VecDeque,\n    pin::Pin,\n    task::{Context, Poll},\n};\nuse tokio::sync::mpsc::UnboundedReceiver;\n\n/// Listens for new blocks and matching logs emitted in that block\npub struct LogsSubscription<N: Network> {\n    pub blocks: NewBlockNotifications,\n    pub storage: StorageInfo<N>,\n    pub filter: FilteredParams,\n    pub queued: VecDeque<Log>,\n    pub id: SubscriptionId,\n}\n\nimpl<N: Network> std::fmt::Debug for LogsSubscription<N> {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        f.debug_struct(\"LogsSubscription\")\n            .field(\"filter\", &self.filter)\n            .field(\"id\", &self.id)\n            .finish_non_exhaustive()\n    }\n}\n\nimpl<N: Network> LogsSubscription<N>\nwhere\n    N::ReceiptEnvelope: TxReceipt<Log = alloy_primitives::Log> + Clone,\n{\n    fn poll(&mut self, cx: &mut Context<'_>) -> Poll<Option<EthSubscriptionResponse>> {\n        loop {\n            if let Some(log) = self.queued.pop_front() {\n                let params = EthSubscriptionParams {\n                    subscription: self.id.clone(),\n                    result: to_rpc_result(log),\n                };\n                return Poll::Ready(Some(EthSubscriptionResponse::new(params)));\n            }\n\n            if let Some(block) = ready!(self.blocks.poll_next_unpin(cx)) {\n                let b = self.storage.block(block.hash);\n                let receipts = self.storage.receipts(block.hash);\n                if let (Some(receipts), Some(block)) = (receipts, b) {\n                    let logs = filter_logs(block, receipts, &self.filter);\n                    if logs.is_empty() {\n                        // this ensures we poll the receiver until it is pending, in which case the\n                        // underlying `UnboundedReceiver` will register the new waker, see\n                        // [`futures::channel::mpsc::UnboundedReceiver::poll_next()`]\n                        continue;\n                    }\n                    self.queued.extend(logs)\n                }\n            } else {\n                return Poll::Ready(None);\n            }\n\n            if self.queued.is_empty() {\n                return Poll::Pending;\n            }\n        }\n    }\n}\n\n#[derive(Clone, Debug, PartialEq, Eq, Serialize)]\npub struct EthSubscriptionResponse {\n    jsonrpc: Version,\n    method: &'static str,\n    params: EthSubscriptionParams,\n}\n\nimpl EthSubscriptionResponse {\n    pub fn new(params: EthSubscriptionParams) -> Self {\n        Self { jsonrpc: Version::V2, method: \"eth_subscription\", params }\n    }\n}\n\n/// Represents the `params` field of an `eth_subscription` event\n#[derive(Clone, Debug, PartialEq, Eq, Serialize)]\npub struct EthSubscriptionParams {\n    subscription: SubscriptionId,\n    #[serde(flatten)]\n    result: ResponseResult,\n}\n\n/// Represents an ethereum Websocket subscription\npub enum EthSubscription<N: Network> {\n    Logs(Box<LogsSubscription<N>>),\n    Header(NewBlockNotifications, StorageInfo<N>, SubscriptionId),\n    PendingTransactions(Receiver<TxHash>, SubscriptionId),\n    FullPendingTransactions(UnboundedReceiver<AnyRpcTransaction>, SubscriptionId),\n}\n\nimpl<N: Network> std::fmt::Debug for EthSubscription<N> {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        match self {\n            Self::Logs(_) => f.debug_tuple(\"Logs\").finish(),\n            Self::Header(..) => f.debug_tuple(\"Header\").finish(),\n            Self::PendingTransactions(..) => f.debug_tuple(\"PendingTransactions\").finish(),\n            Self::FullPendingTransactions(..) => f.debug_tuple(\"FullPendingTransactions\").finish(),\n        }\n    }\n}\n\nimpl<N: Network> EthSubscription<N>\nwhere\n    N::ReceiptEnvelope: TxReceipt<Log = alloy_primitives::Log> + Clone,\n{\n    fn poll_response(&mut self, cx: &mut Context<'_>) -> Poll<Option<EthSubscriptionResponse>> {\n        match self {\n            Self::Logs(listener) => listener.poll(cx),\n            Self::Header(blocks, storage, id) => {\n                // this loop ensures we poll the receiver until it is pending, in which case the\n                // underlying `UnboundedReceiver` will register the new waker, see\n                // [`futures::channel::mpsc::UnboundedReceiver::poll_next()`]\n                loop {\n                    if let Some(block) = ready!(blocks.poll_next_unpin(cx)) {\n                        if let Some(block) = storage.eth_block(block.hash) {\n                            let params = EthSubscriptionParams {\n                                subscription: id.clone(),\n                                result: to_rpc_result(block),\n                            };\n                            return Poll::Ready(Some(EthSubscriptionResponse::new(params)));\n                        }\n                    } else {\n                        return Poll::Ready(None);\n                    }\n                }\n            }\n            Self::PendingTransactions(tx, id) => {\n                let res = ready!(tx.poll_next_unpin(cx))\n                    .map(SubscriptionResult::<Transaction>::TransactionHash)\n                    .map(to_rpc_result)\n                    .map(|result| {\n                        let params = EthSubscriptionParams { subscription: id.clone(), result };\n                        EthSubscriptionResponse::new(params)\n                    });\n                Poll::Ready(res)\n            }\n            Self::FullPendingTransactions(tx, id) => {\n                let res = ready!(tx.poll_recv(cx)).map(to_rpc_result).map(|result| {\n                    let params = EthSubscriptionParams { subscription: id.clone(), result };\n                    EthSubscriptionResponse::new(params)\n                });\n                Poll::Ready(res)\n            }\n        }\n    }\n}\n\nimpl<N: Network> Stream for EthSubscription<N>\nwhere\n    N::ReceiptEnvelope: TxReceipt<Log = alloy_primitives::Log> + Clone,\n{\n    type Item = serde_json::Value;\n\n    fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {\n        let pin = self.get_mut();\n        match ready!(pin.poll_response(cx)) {\n            None => Poll::Ready(None),\n            Some(res) => Poll::Ready(Some(serde_json::to_value(res).expect(\"can't fail;\"))),\n        }\n    }\n}\n\n/// Returns all the logs that match the given filter\npub fn filter_logs<R>(block: Block, receipts: Vec<R>, filter: &FilteredParams) -> Vec<Log>\nwhere\n    R: TxReceipt<Log = alloy_primitives::Log>,\n{\n    /// Determines whether to add this log\n    fn add_log(\n        block_hash: B256,\n        l: &alloy_primitives::Log,\n        block: &Block,\n        params: &FilteredParams,\n    ) -> bool {\n        if params.filter.is_some() {\n            let block_number = block.header.number();\n            if !params.filter_block_range(block_number)\n                || !params.filter_block_hash(block_hash)\n                || !params.filter_address(&l.address)\n                || !params.filter_topics(l.topics())\n            {\n                return false;\n            }\n        }\n        true\n    }\n\n    let block_hash = block.header.hash_slow();\n    let mut logs = vec![];\n    let mut log_index: u32 = 0;\n    for (receipt_index, receipt) in receipts.into_iter().enumerate() {\n        let transaction_hash = block.body.transactions[receipt_index].hash();\n        for log in receipt.logs() {\n            if add_log(block_hash, log, &block, filter) {\n                logs.push(Log {\n                    inner: log.clone(),\n                    block_hash: Some(block_hash),\n                    block_number: Some(block.header.number()),\n                    transaction_hash: Some(transaction_hash),\n                    transaction_index: Some(receipt_index as u64),\n                    log_index: Some(log_index as u64),\n                    removed: false,\n                    block_timestamp: Some(block.header.timestamp()),\n                });\n            }\n            log_index += 1;\n        }\n    }\n    logs\n}\n"
  },
  {
    "path": "crates/anvil/src/server/beacon/error.rs",
    "content": "//! Beacon API error types\n\nuse axum::{\n    Json,\n    http::StatusCode,\n    response::{IntoResponse, Response},\n};\nuse serde::{Deserialize, Serialize};\nuse std::{\n    borrow::Cow,\n    fmt::{self, Display},\n};\n\n/// Represents a Beacon API error response\n#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]\npub struct BeaconError {\n    /// HTTP status code\n    #[serde(skip)]\n    pub status_code: u16,\n    /// Error code\n    pub code: BeaconErrorCode,\n    /// Error message\n    pub message: Cow<'static, str>,\n}\n\nimpl BeaconError {\n    /// Creates a new beacon error with the given code\n    pub fn new(code: BeaconErrorCode, message: impl Into<Cow<'static, str>>) -> Self {\n        let status_code = code.status_code();\n        Self { status_code, code, message: message.into() }\n    }\n\n    /// Helper function to create a 400 Bad Request error for invalid block ID\n    pub fn invalid_block_id(block_id: impl Display) -> Self {\n        Self::new(BeaconErrorCode::BadRequest, format!(\"Invalid block ID: {block_id}\"))\n    }\n\n    /// Helper function to create a 404 Not Found error for block not found\n    pub fn block_not_found() -> Self {\n        Self::new(BeaconErrorCode::NotFound, \"Block not found\")\n    }\n\n    /// Helper function to create a 500 Internal Server Error\n    pub fn internal_error() -> Self {\n        Self::new(BeaconErrorCode::InternalError, \"Internal server error\")\n    }\n\n    /// Helper function to create a 410 Gone error for deprecated endpoints\n    pub fn deprecated_endpoint_with_hint(hint: impl Display) -> Self {\n        Self::new(BeaconErrorCode::Gone, format!(\"This endpoint is deprecated. {hint}\"))\n    }\n\n    /// Converts to an Axum response\n    pub fn into_response(self) -> Response {\n        let status =\n            StatusCode::from_u16(self.status_code).unwrap_or(StatusCode::INTERNAL_SERVER_ERROR);\n\n        (\n            status,\n            Json(serde_json::json!({\n                \"code\": self.code as u16,\n                \"message\": self.message,\n            })),\n        )\n            .into_response()\n    }\n}\n\nimpl fmt::Display for BeaconError {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        write!(f, \"{}: {}\", self.code.as_str(), self.message)\n    }\n}\n\nimpl std::error::Error for BeaconError {}\n\nimpl IntoResponse for BeaconError {\n    fn into_response(self) -> Response {\n        Self::into_response(self)\n    }\n}\n\n/// Beacon API error codes following the beacon chain specification\n#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]\n#[repr(u16)]\npub enum BeaconErrorCode {\n    BadRequest = 400,\n    NotFound = 404,\n    Gone = 410,\n    InternalError = 500,\n}\n\nimpl BeaconErrorCode {\n    /// Returns the HTTP status code for this error\n    pub const fn status_code(&self) -> u16 {\n        *self as u16\n    }\n\n    /// Returns a string representation of the error code\n    pub const fn as_str(&self) -> &'static str {\n        match self {\n            Self::BadRequest => \"Bad Request\",\n            Self::NotFound => \"Not Found\",\n            Self::Gone => \"Gone\",\n            Self::InternalError => \"Internal Server Error\",\n        }\n    }\n}\n\nimpl fmt::Display for BeaconErrorCode {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        write!(f, \"{}\", self.as_str())\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_beacon_error_codes() {\n        assert_eq!(BeaconErrorCode::BadRequest.status_code(), 400);\n        assert_eq!(BeaconErrorCode::NotFound.status_code(), 404);\n        assert_eq!(BeaconErrorCode::InternalError.status_code(), 500);\n    }\n\n    #[test]\n    fn test_beacon_error_display() {\n        let err = BeaconError::invalid_block_id(\"current\");\n        assert_eq!(err.to_string(), \"Bad Request: Invalid block ID: current\");\n    }\n}\n"
  },
  {
    "path": "crates/anvil/src/server/beacon/handlers.rs",
    "content": "use super::{error::BeaconError, utils::must_be_ssz};\nuse crate::eth::EthApi;\nuse alloy_eips::BlockId;\nuse alloy_primitives::{B256, aliases::B32};\nuse alloy_rpc_types_beacon::{\n    genesis::{GenesisData, GenesisResponse},\n    sidecar::GetBlobsResponse,\n};\nuse axum::{\n    Json,\n    extract::{Path, Query, State},\n    http::HeaderMap,\n    response::{IntoResponse, Response},\n};\nuse foundry_primitives::FoundryNetwork;\nuse ssz::Encode;\nuse std::{collections::HashMap, str::FromStr as _};\n\n/// Handles incoming Beacon API requests for blob sidecars\n///\n/// This endpoint is deprecated. Use `GET /eth/v1/beacon/blobs/{block_id}` instead.\n///\n/// GET /eth/v1/beacon/blob_sidecars/{block_id}\npub async fn handle_get_blob_sidecars(\n    State(_api): State<EthApi<FoundryNetwork>>,\n    Path(_block_id): Path<String>,\n    Query(_params): Query<HashMap<String, String>>,\n) -> Response {\n    BeaconError::deprecated_endpoint_with_hint(\"Use `GET /eth/v1/beacon/blobs/{block_id}` instead.\")\n        .into_response()\n}\n\n/// Handles incoming Beacon API requests for blobs\n///\n/// GET /eth/v1/beacon/blobs/{block_id}\npub async fn handle_get_blobs(\n    headers: HeaderMap,\n    State(api): State<EthApi<FoundryNetwork>>,\n    Path(block_id): Path<String>,\n    Query(versioned_hashes): Query<HashMap<String, String>>,\n) -> Response {\n    // Parse block_id from path parameter\n    let Ok(block_id) = BlockId::from_str(&block_id) else {\n        return BeaconError::invalid_block_id(block_id).into_response();\n    };\n\n    // Parse versioned hashes from query parameters\n    // Supports comma-separated format: ?versioned_hashes=0x...,0x...\n    let versioned_hashes: Vec<B256> = match versioned_hashes.get(\"versioned_hashes\") {\n        Some(s) => {\n            let mut hashes = Vec::new();\n            for hash in s.split(',') {\n                let hash = hash.trim();\n                if hash.is_empty() {\n                    continue;\n                }\n                match B256::from_str(hash) {\n                    Ok(h) => hashes.push(h),\n                    Err(_) => {\n                        return BeaconError::new(\n                            super::error::BeaconErrorCode::BadRequest,\n                            format!(\"Invalid versioned hash: {hash}\"),\n                        )\n                        .into_response();\n                    }\n                }\n            }\n            hashes\n        }\n        None => Vec::new(),\n    };\n\n    // Get the blob sidecars using existing EthApi logic\n    match api.anvil_get_blobs_by_block_id(block_id, versioned_hashes) {\n        Ok(Some(blobs)) => {\n            if must_be_ssz(&headers) {\n                blobs.as_ssz_bytes().into_response()\n            } else {\n                Json(GetBlobsResponse {\n                    execution_optimistic: false,\n                    finalized: false,\n                    data: blobs,\n                })\n                .into_response()\n            }\n        }\n        Ok(None) => BeaconError::block_not_found().into_response(),\n        Err(_) => BeaconError::internal_error().into_response(),\n    }\n}\n\n/// Handles incoming Beacon API requests for genesis details\n///\n/// Only returns the `genesis_time`, other fields are set to zero.\n///\n/// GET /eth/v1/beacon/genesis\npub async fn handle_get_genesis(State(api): State<EthApi<FoundryNetwork>>) -> Response {\n    match api.anvil_get_genesis_time() {\n        Ok(genesis_time) => Json(GenesisResponse {\n            data: GenesisData {\n                genesis_time,\n                genesis_validators_root: B256::ZERO,\n                genesis_fork_version: B32::ZERO,\n            },\n        })\n        .into_response(),\n        Err(_) => BeaconError::internal_error().into_response(),\n    }\n}\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use axum::http::HeaderValue;\n\n    fn header_map_with_accept(accept: &str) -> HeaderMap {\n        let mut headers = HeaderMap::new();\n        headers.insert(axum::http::header::ACCEPT, HeaderValue::from_str(accept).unwrap());\n        headers\n    }\n\n    #[test]\n    fn test_must_be_ssz() {\n        let test_cases = vec![\n            (None, false, \"no Accept header\"),\n            (Some(\"application/json\"), false, \"JSON only\"),\n            (Some(\"application/octet-stream\"), true, \"octet-stream only\"),\n            (Some(\"application/octet-stream;q=1.0,application/json;q=0.9\"), true, \"SSZ preferred\"),\n            (\n                Some(\"application/json;q=1.0,application/octet-stream;q=0.9\"),\n                false,\n                \"JSON preferred\",\n            ),\n            (Some(\"application/octet-stream;q=0.5,application/json;q=0.5\"), false, \"equal quality\"),\n            (\n                Some(\"text/html;q=0.9, application/octet-stream;q=1.0, application/json;q=0.8\"),\n                true,\n                \"multiple types\",\n            ),\n            (\n                Some(\"application/octet-stream ; q=1.0 , application/json ; q=0.9\"),\n                true,\n                \"whitespace handling\",\n            ),\n            (Some(\"application/octet-stream, application/json;q=0.9\"), true, \"default quality\"),\n        ];\n\n        for (accept_header, expected, description) in test_cases {\n            let headers = match accept_header {\n                None => HeaderMap::new(),\n                Some(header) => header_map_with_accept(header),\n            };\n            assert_eq!(\n                must_be_ssz(&headers),\n                expected,\n                \"Test case '{}' failed: expected {}, got {}\",\n                description,\n                expected,\n                !expected\n            );\n        }\n    }\n}\n"
  },
  {
    "path": "crates/anvil/src/server/beacon/mod.rs",
    "content": "//! Beacon Node REST API implementation for Anvil.\n\nuse axum::{Router, routing::get};\n\nuse crate::eth::EthApi;\nuse foundry_primitives::FoundryNetwork;\n\nmod error;\nmod handlers;\nmod utils;\n\n/// Configures an [`axum::Router`] that handles Beacon REST API calls.\npub fn router(api: EthApi<FoundryNetwork>) -> Router {\n    Router::new()\n        .route(\"/eth/v1/beacon/blob_sidecars/{block_id}\", get(handlers::handle_get_blob_sidecars))\n        .route(\"/eth/v1/beacon/blobs/{block_id}\", get(handlers::handle_get_blobs))\n        .route(\"/eth/v1/beacon/genesis\", get(handlers::handle_get_genesis))\n        .with_state(api)\n}\n"
  },
  {
    "path": "crates/anvil/src/server/beacon/utils.rs",
    "content": "use hyper::HeaderMap;\n\n/// Helper function to determine if the Accept header indicates a preference for SSZ (octet-stream)\n/// over JSON.\npub fn must_be_ssz(headers: &HeaderMap) -> bool {\n    headers\n        .get(axum::http::header::ACCEPT)\n        .and_then(|v| v.to_str().ok())\n        .map(|accept_str| {\n            let mut octet_stream_q = 0.0;\n            let mut json_q = 0.0;\n\n            // Parse each media type in the Accept header\n            for media_type in accept_str.split(',') {\n                let media_type = media_type.trim();\n                let quality = media_type\n                    .split(';')\n                    .find_map(|param| {\n                        let param = param.trim();\n                        if let Some(q) = param.strip_prefix(\"q=\") {\n                            q.parse::<f32>().ok()\n                        } else {\n                            None\n                        }\n                    })\n                    .unwrap_or(1.0); // Default quality factor is 1.0\n\n                if media_type.starts_with(\"application/octet-stream\") {\n                    octet_stream_q = quality;\n                } else if media_type.starts_with(\"application/json\") {\n                    json_q = quality;\n                }\n            }\n\n            // Prefer octet-stream if it has higher quality factor\n            octet_stream_q > json_q\n        })\n        .unwrap_or(false)\n}\n"
  },
  {
    "path": "crates/anvil/src/server/mod.rs",
    "content": "//! This module provides the infrastructure to launch an Ethereum JSON-RPC server\n//! (via HTTP, WebSocket, and IPC) and Beacon Node REST API.\n\nuse crate::{EthApi, IpcTask};\nuse anvil_server::{ServerConfig, ipc::IpcEndpoint};\nuse axum::Router;\nuse foundry_primitives::FoundryNetwork;\nuse futures::StreamExt;\nuse rpc_handlers::{HttpEthRpcHandler, PubSubEthRpcHandler};\nuse std::{io, net::SocketAddr, pin::pin};\nuse tokio::net::TcpListener;\n\nmod beacon;\nmod rpc_handlers;\n\n/// Configures a server that handles [`EthApi`] related JSON-RPC calls via HTTP and WS.\n///\n/// The returned future creates a new server, binding it to the given address, which returns another\n/// future that runs it.\npub async fn serve(\n    addr: SocketAddr,\n    api: EthApi<FoundryNetwork>,\n    config: ServerConfig,\n) -> io::Result<impl Future<Output = io::Result<()>>> {\n    let tcp_listener = TcpListener::bind(addr).await?;\n    Ok(serve_on(tcp_listener, api, config))\n}\n\n/// Configures a server that handles [`EthApi`] related JSON-RPC calls via HTTP and WS.\npub async fn serve_on(\n    tcp_listener: TcpListener,\n    api: EthApi<FoundryNetwork>,\n    config: ServerConfig,\n) -> io::Result<()> {\n    axum::serve(tcp_listener, router(api, config).into_make_service()).await\n}\n\n/// Configures an [`axum::Router`] that handles [`EthApi`] related JSON-RPC calls via HTTP and WS,\n/// and Beacon REST API calls.\npub fn router(api: EthApi<FoundryNetwork>, config: ServerConfig) -> Router {\n    let http = HttpEthRpcHandler::new(api.clone());\n    let ws = PubSubEthRpcHandler::new(api.clone());\n\n    // JSON-RPC router\n    let rpc_router = anvil_server::http_ws_router(config, http, ws);\n\n    // Beacon REST API router\n    let beacon_router = beacon::router(api);\n\n    // Merge the routers\n    rpc_router.merge(beacon_router)\n}\n\n/// Launches an ipc server at the given path in a new task\n///\n/// # Panics\n///\n/// Panics if setting up the IPC connection was unsuccessful.\n#[track_caller]\npub fn spawn_ipc(api: EthApi<FoundryNetwork>, path: String) -> IpcTask {\n    try_spawn_ipc(api, path).expect(\"failed to establish ipc connection\")\n}\n\n/// Launches an ipc server at the given path in a new task.\npub fn try_spawn_ipc(api: EthApi<FoundryNetwork>, path: String) -> io::Result<IpcTask> {\n    let handler = PubSubEthRpcHandler::new(api);\n    let ipc = IpcEndpoint::new(handler, path);\n    let incoming = ipc.incoming()?;\n\n    let task = tokio::task::spawn(async move {\n        let mut incoming = pin!(incoming);\n        while let Some(stream) = incoming.next().await {\n            trace!(target: \"ipc\", \"new ipc connection\");\n            tokio::task::spawn(stream);\n        }\n    });\n\n    Ok(task)\n}\n"
  },
  {
    "path": "crates/anvil/src/server/rpc_handlers.rs",
    "content": "//! Contains RPC handlers\nuse crate::{\n    EthApi,\n    eth::error::to_rpc_result,\n    pubsub::{EthSubscription, LogsSubscription},\n};\nuse alloy_rpc_types::{\n    FilteredParams,\n    pubsub::{Params, SubscriptionKind},\n};\nuse anvil_core::eth::{EthPubSub, EthRequest, EthRpcCall, subscription::SubscriptionId};\nuse anvil_rpc::{error::RpcError, response::ResponseResult};\nuse anvil_server::{PubSubContext, PubSubRpcHandler, RpcHandler};\nuse foundry_primitives::FoundryNetwork;\n\n/// A `RpcHandler` that expects `EthRequest` rpc calls via http\n#[derive(Clone)]\npub struct HttpEthRpcHandler {\n    /// Access to the node\n    api: EthApi<FoundryNetwork>,\n}\n\nimpl HttpEthRpcHandler {\n    /// Creates a new instance of the handler using the given `EthApi`\n    pub fn new(api: EthApi<FoundryNetwork>) -> Self {\n        Self { api }\n    }\n}\n\n#[async_trait::async_trait]\nimpl RpcHandler for HttpEthRpcHandler {\n    type Request = EthRequest;\n\n    async fn on_request(&self, request: Self::Request) -> ResponseResult {\n        self.api.execute(request).await\n    }\n}\n\n/// A `RpcHandler` that expects `EthRequest` rpc calls and `EthPubSub` via pubsub connection\n#[derive(Clone)]\npub struct PubSubEthRpcHandler {\n    /// Access to the node\n    api: EthApi<FoundryNetwork>,\n}\n\nimpl PubSubEthRpcHandler {\n    /// Creates a new instance of the handler using the given `EthApi`\n    pub fn new(api: EthApi<FoundryNetwork>) -> Self {\n        Self { api }\n    }\n\n    /// Invoked for an ethereum pubsub rpc call\n    async fn on_pub_sub(&self, pubsub: EthPubSub, cx: PubSubContext<Self>) -> ResponseResult {\n        let id = SubscriptionId::random_hex();\n        trace!(target: \"rpc::ws\", \"received pubsub request {:?}\", pubsub);\n        match pubsub {\n            EthPubSub::EthUnSubscribe(id) => {\n                trace!(target: \"rpc::ws\", \"canceling subscription {:?}\", id);\n                let canceled = cx.remove_subscription(&id).is_some();\n                ResponseResult::Success(canceled.into())\n            }\n            EthPubSub::EthSubscribe(kind, raw_params) => {\n                let filter = match &*raw_params {\n                    Params::None => None,\n                    Params::Logs(filter) => Some(filter.clone()),\n                    Params::Bool(_) => None,\n                };\n                let params = FilteredParams::new(filter.map(|b| *b));\n\n                let subscription = match kind {\n                    SubscriptionKind::Logs => {\n                        if raw_params.is_bool() {\n                            return ResponseResult::Error(RpcError::invalid_params(\n                                \"Expected params for logs subscription\",\n                            ));\n                        }\n\n                        trace!(target: \"rpc::ws\", \"received logs subscription {:?}\", params);\n                        let blocks = self.api.new_block_notifications();\n                        let storage = self.api.storage_info();\n                        EthSubscription::Logs(Box::new(LogsSubscription {\n                            blocks,\n                            storage,\n                            filter: params,\n                            queued: Default::default(),\n                            id: id.clone(),\n                        }))\n                    }\n                    SubscriptionKind::NewHeads => {\n                        trace!(target: \"rpc::ws\", \"received header subscription\");\n                        let blocks = self.api.new_block_notifications();\n                        let storage = self.api.storage_info();\n                        EthSubscription::Header(blocks, storage, id.clone())\n                    }\n                    SubscriptionKind::NewPendingTransactions => {\n                        trace!(target: \"rpc::ws\", \"received pending transactions subscription\");\n                        match *raw_params {\n                            Params::Bool(true) => EthSubscription::FullPendingTransactions(\n                                self.api.full_pending_transactions(),\n                                id.clone(),\n                            ),\n                            Params::Bool(false) | Params::None => {\n                                EthSubscription::PendingTransactions(\n                                    self.api.new_ready_transactions(),\n                                    id.clone(),\n                                )\n                            }\n                            _ => {\n                                return ResponseResult::Error(RpcError::invalid_params(\n                                    \"Expected boolean parameter for newPendingTransactions\",\n                                ));\n                            }\n                        }\n                    }\n                    SubscriptionKind::Syncing => {\n                        return RpcError::internal_error_with(\"Not implemented\").into();\n                    }\n                };\n\n                cx.add_subscription(id.clone(), subscription);\n\n                trace!(target: \"rpc::ws\", \"created new subscription: {:?}\", id);\n                to_rpc_result(id)\n            }\n        }\n    }\n}\n\n#[async_trait::async_trait]\nimpl PubSubRpcHandler for PubSubEthRpcHandler {\n    type Request = EthRpcCall;\n    type SubscriptionId = SubscriptionId;\n    type Subscription = EthSubscription<FoundryNetwork>;\n\n    async fn on_request(&self, request: Self::Request, cx: PubSubContext<Self>) -> ResponseResult {\n        trace!(target: \"rpc\", \"received pubsub request {:?}\", request);\n        match request {\n            EthRpcCall::Request(request) => self.api.execute(*request).await,\n            EthRpcCall::PubSub(pubsub) => self.on_pub_sub(pubsub, cx).await,\n        }\n    }\n}\n"
  },
  {
    "path": "crates/anvil/src/service.rs",
    "content": "//! background service\n\nuse crate::{\n    NodeResult,\n    eth::{\n        backend::validate::TransactionValidator,\n        fees::FeeHistoryService,\n        miner::Miner,\n        pool::{Pool, transactions::PoolTransaction},\n    },\n    filter::Filters,\n    mem::{Backend, storage::MinedBlockOutcome},\n};\nuse alloy_network::Network;\nuse foundry_primitives::{FoundryReceiptEnvelope, FoundryTxEnvelope};\nuse futures::{FutureExt, Stream, StreamExt};\nuse std::{\n    collections::VecDeque,\n    pin::Pin,\n    sync::Arc,\n    task::{Context, Poll},\n};\nuse tokio::{task::JoinHandle, time::Interval};\n\n/// The type that drives the blockchain's state\n///\n/// This service is basically an endless future that continuously polls the miner which returns\n/// transactions for the next block, then those transactions are handed off to the backend to\n/// construct a new block, if all transactions were successfully included in a new block they get\n/// purged from the `Pool`.\npub struct NodeService<N: Network> {\n    /// The pool that holds all transactions.\n    pool: Arc<Pool<N::TxEnvelope>>,\n    /// Creates new blocks.\n    block_producer: BlockProducer<N>,\n    /// The miner responsible to select transactions from the `pool`.\n    miner: Miner<N::TxEnvelope>,\n    /// Maintenance task for fee history related tasks.\n    fee_history: FeeHistoryService,\n    /// Tracks all active filters\n    filters: Filters<N>,\n    /// The interval at which to check for filters that need to be evicted\n    filter_eviction_interval: Interval,\n}\n\nimpl<N: Network> NodeService<N>\nwhere\n    Backend<N>: TransactionValidator<N::TxEnvelope>,\n    N: Network<TxEnvelope = FoundryTxEnvelope, ReceiptEnvelope = FoundryReceiptEnvelope>,\n{\n    pub fn new(\n        pool: Arc<Pool<N::TxEnvelope>>,\n        backend: Arc<Backend<N>>,\n        miner: Miner<N::TxEnvelope>,\n        fee_history: FeeHistoryService,\n        filters: Filters<N>,\n    ) -> Self {\n        let start = tokio::time::Instant::now() + filters.keep_alive();\n        let filter_eviction_interval = tokio::time::interval_at(start, filters.keep_alive());\n        Self {\n            pool,\n            block_producer: BlockProducer::new(backend),\n            miner,\n            fee_history,\n            filter_eviction_interval,\n            filters,\n        }\n    }\n}\n\nimpl<N: Network> Future for NodeService<N>\nwhere\n    Backend<N>: TransactionValidator<N::TxEnvelope>,\n    N: Network<TxEnvelope = FoundryTxEnvelope, ReceiptEnvelope = FoundryReceiptEnvelope>,\n{\n    type Output = NodeResult<()>;\n\n    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {\n        let pin = self.get_mut();\n\n        // this drives block production and feeds new sets of ready transactions to the block\n        // producer\n        loop {\n            // advance block production until pending\n            while let Poll::Ready(Some(outcome)) = pin.block_producer.poll_next_unpin(cx) {\n                trace!(target: \"node\", \"mined block {}\", outcome.block_number);\n                // prune the transactions from the pool\n                pin.pool.on_mined_block(outcome);\n            }\n\n            if let Poll::Ready(transactions) = pin.miner.poll(&pin.pool, cx) {\n                // miner returned a set of transaction that we feed to the producer\n                pin.block_producer.queued.push_back(transactions);\n            } else {\n                // no progress made\n                break;\n            }\n        }\n\n        // poll the fee history task\n        let _ = pin.fee_history.poll_unpin(cx);\n\n        if pin.filter_eviction_interval.poll_tick(cx).is_ready() {\n            let filters = pin.filters.clone();\n\n            // evict filters that timed out\n            tokio::task::spawn(async move { filters.evict().await });\n        }\n\n        Poll::Pending\n    }\n}\n\ntype MiningResult<N> = (MinedBlockOutcome<<N as Network>::TxEnvelope>, Arc<Backend<N>>);\n\n/// A type that exclusively mines one block at a time\n#[must_use = \"streams do nothing unless polled\"]\nstruct BlockProducer<N: Network> {\n    /// Holds the backend if no block is being mined\n    idle_backend: Option<Arc<Backend<N>>>,\n    /// Single active future that mines a new block\n    block_mining: Option<JoinHandle<MiningResult<N>>>,\n    /// backlog of sets of transactions ready to be mined\n    queued: VecDeque<Vec<Arc<PoolTransaction<N::TxEnvelope>>>>,\n}\n\nimpl<N: Network> BlockProducer<N>\nwhere\n    Backend<N>: TransactionValidator<N::TxEnvelope>,\n    N: Network<TxEnvelope = FoundryTxEnvelope, ReceiptEnvelope = FoundryReceiptEnvelope>,\n{\n    fn new(backend: Arc<Backend<N>>) -> Self {\n        Self { idle_backend: Some(backend), block_mining: None, queued: Default::default() }\n    }\n}\n\nimpl<N: Network> Stream for BlockProducer<N>\nwhere\n    Backend<N>: TransactionValidator<N::TxEnvelope> + Send + Sync + 'static,\n    N: Network<TxEnvelope = FoundryTxEnvelope, ReceiptEnvelope = FoundryReceiptEnvelope> + 'static,\n{\n    type Item = MinedBlockOutcome<N::TxEnvelope>;\n\n    fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {\n        let pin = self.get_mut();\n\n        if !pin.queued.is_empty() {\n            // only spawn a building task if there's none in progress already\n            if let Some(backend) = pin.idle_backend.take() {\n                let transactions = pin.queued.pop_front().expect(\"not empty; qed\");\n\n                // we spawn this on as blocking task because this can be blocking for a while in\n                // forking mode, because of all the rpc calls to fetch the required state\n                let handle = tokio::runtime::Handle::current();\n                let mining = tokio::task::spawn_blocking(move || {\n                    handle.block_on(async move {\n                        trace!(target: \"miner\", \"creating new block\");\n                        let block = backend.mine_block(transactions).await;\n                        trace!(target: \"miner\", \"created new block: {}\", block.block_number);\n                        (block, backend)\n                    })\n                });\n                pin.block_mining = Some(mining);\n            }\n        }\n\n        if let Some(mut mining) = pin.block_mining.take() {\n            if let Poll::Ready(res) = mining.poll_unpin(cx) {\n                return match res {\n                    Ok((outcome, backend)) => {\n                        pin.idle_backend = Some(backend);\n                        Poll::Ready(Some(outcome))\n                    }\n                    Err(err) => {\n                        panic!(\"miner task failed: {err}\");\n                    }\n                };\n            } else {\n                pin.block_mining = Some(mining)\n            }\n        }\n\n        Poll::Pending\n    }\n}\n"
  },
  {
    "path": "crates/anvil/src/shutdown.rs",
    "content": "//! Helper for shutdown signals\n\nuse futures::{\n    FutureExt,\n    channel::oneshot,\n    future::{FusedFuture, Shared},\n};\nuse std::{\n    pin::Pin,\n    task::{Context, Poll},\n};\n\n/// Future that resolves when the shutdown event has fired\n#[derive(Clone)]\npub struct Shutdown(Shared<oneshot::Receiver<()>>);\n\nimpl Future for Shutdown {\n    type Output = ();\n\n    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {\n        let pin = self.get_mut();\n        if pin.0.is_terminated() || pin.0.poll_unpin(cx).is_ready() {\n            Poll::Ready(())\n        } else {\n            Poll::Pending\n        }\n    }\n}\n\n/// Shutdown signal that fires either manually or on drop by closing the channel\npub struct Signal(oneshot::Sender<()>);\n\nimpl Signal {\n    /// Fire the signal manually.\n    pub fn fire(self) -> Result<(), ()> {\n        self.0.send(())\n    }\n}\n\n/// Create a channel pair that's used to propagate shutdown event\npub fn signal() -> (Signal, Shutdown) {\n    let (sender, receiver) = oneshot::channel();\n    (Signal(sender), Shutdown(receiver.shared()))\n}\n"
  },
  {
    "path": "crates/anvil/src/tasks/block_listener.rs",
    "content": "//! A task that listens for new blocks\n\nuse crate::shutdown::Shutdown;\nuse futures::{FutureExt, Stream, StreamExt};\nuse std::{\n    pin::Pin,\n    task::{Context, Poll},\n};\n\n/// A Future that will execute a given `task` for each new block that arrives on the stream.\npub struct BlockListener<St, F, Fut> {\n    stream: St,\n    task_factory: F,\n    task: Option<Pin<Box<Fut>>>,\n    on_shutdown: Shutdown,\n}\n\nimpl<St, F, Fut> BlockListener<St, F, Fut>\nwhere\n    St: Stream,\n    F: Fn(<St as Stream>::Item) -> Fut,\n{\n    pub fn new(on_shutdown: Shutdown, block_stream: St, task_factory: F) -> Self {\n        Self { stream: block_stream, task_factory, task: None, on_shutdown }\n    }\n}\n\nimpl<St, F, Fut> Future for BlockListener<St, F, Fut>\nwhere\n    St: Stream + Unpin,\n    F: Fn(<St as Stream>::Item) -> Fut + Unpin + Send + Sync + 'static,\n    Fut: Future<Output = ()> + Send,\n{\n    type Output = ();\n\n    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {\n        let pin = self.get_mut();\n\n        if pin.on_shutdown.poll_unpin(cx).is_ready() {\n            return Poll::Ready(());\n        }\n\n        let mut block = None;\n        // drain the stream\n        while let Poll::Ready(maybe_block) = pin.stream.poll_next_unpin(cx) {\n            if maybe_block.is_none() {\n                // stream complete\n                return Poll::Ready(());\n            }\n            block = maybe_block;\n        }\n\n        if let Some(block) = block {\n            pin.task = Some(Box::pin((pin.task_factory)(block)));\n        }\n\n        if let Some(mut task) = pin.task.take()\n            && task.poll_unpin(cx).is_pending()\n        {\n            pin.task = Some(task);\n        }\n        Poll::Pending\n    }\n}\n"
  },
  {
    "path": "crates/anvil/src/tasks/mod.rs",
    "content": "//! Task management support\n\n#![allow(rustdoc::private_doc_tests)]\n\nuse crate::{EthApi, shutdown::Shutdown, tasks::block_listener::BlockListener};\nuse alloy_consensus::BlockHeader;\nuse alloy_network::{BlockResponse, Network};\nuse alloy_primitives::B256;\nuse alloy_provider::Provider;\nuse alloy_rpc_types::anvil::Forking;\nuse foundry_primitives::FoundryNetwork;\nuse futures::StreamExt;\nuse std::fmt;\nuse tokio::{runtime::Handle, task::JoinHandle};\n\npub mod block_listener;\n\n/// A helper struct for managing additional tokio tasks.\n#[derive(Clone)]\npub struct TaskManager {\n    /// Tokio runtime handle that's used to spawn futures, See [tokio::runtime::Handle].\n    tokio_handle: Handle,\n    /// A receiver for the shutdown signal\n    on_shutdown: Shutdown,\n}\n\nimpl TaskManager {\n    /// Creates a new instance of the task manager\n    pub fn new(tokio_handle: Handle, on_shutdown: Shutdown) -> Self {\n        Self { tokio_handle, on_shutdown }\n    }\n\n    /// Returns a receiver for the shutdown event\n    pub fn on_shutdown(&self) -> Shutdown {\n        self.on_shutdown.clone()\n    }\n\n    /// Spawns the given task.\n    pub fn spawn(&self, task: impl Future<Output = ()> + Send + 'static) -> JoinHandle<()> {\n        self.tokio_handle.spawn(task)\n    }\n\n    /// Spawns the blocking task and returns a handle to it.\n    ///\n    /// Returning the `JoinHandle` allows callers to cancel the task or await its completion.\n    pub fn spawn_blocking(\n        &self,\n        task: impl Future<Output = ()> + Send + 'static,\n    ) -> JoinHandle<()> {\n        let handle = self.tokio_handle.clone();\n        self.tokio_handle.spawn_blocking(move || {\n            handle.block_on(task);\n        })\n    }\n\n    /// Spawns a new task that listens for new blocks and resets the forked provider for every new\n    /// block\n    ///\n    /// ```\n    /// use alloy_network::Ethereum;\n    /// use alloy_provider::RootProvider;\n    /// use anvil::{NodeConfig, spawn};\n    ///\n    /// # async fn t() {\n    /// let endpoint = \"http://....\";\n    /// let (api, handle) = spawn(NodeConfig::default().with_eth_rpc_url(Some(endpoint))).await;\n    ///\n    /// let provider = RootProvider::connect(endpoint).await.unwrap();\n    ///\n    /// handle.task_manager().spawn_reset_on_new_polled_blocks::<Ethereum, _>(provider, api);\n    /// # }\n    /// ```\n    pub fn spawn_reset_on_new_polled_blocks<N, P>(&self, provider: P, api: EthApi<FoundryNetwork>)\n    where\n        N: Network,\n        P: Provider<N> + Clone + Unpin + 'static,\n    {\n        self.spawn_block_poll_listener(provider.clone(), move |hash| {\n            let provider = provider.clone();\n            let api = api.clone();\n            async move {\n                if let Ok(Some(block)) = provider.get_block(hash.into()).await {\n                    let _ = api\n                        .anvil_reset(Some(Forking {\n                            json_rpc_url: None,\n                            block_number: Some(block.header().number()),\n                        }))\n                        .await;\n                }\n            }\n        })\n    }\n\n    /// Spawns a new [`BlockListener`] task that listens for new blocks (poll-based) See also\n    /// [`Provider::watch_blocks`] and executes the future the `task_factory` returns for the new\n    /// block hash\n    pub fn spawn_block_poll_listener<N, P, F, Fut>(&self, provider: P, task_factory: F)\n    where\n        N: Network,\n        P: Provider<N> + 'static,\n        F: Fn(B256) -> Fut + Unpin + Send + Sync + 'static,\n        Fut: Future<Output = ()> + Send,\n    {\n        let shutdown = self.on_shutdown.clone();\n        self.spawn(async move {\n            let blocks = provider\n                .watch_blocks()\n                .await\n                .unwrap()\n                .into_stream()\n                .flat_map(futures::stream::iter);\n            BlockListener::new(shutdown, blocks, task_factory).await;\n        });\n    }\n\n    /// Spawns a new task that listens for new blocks and resets the forked provider for every new\n    /// block\n    ///\n    /// ```\n    /// use alloy_network::Ethereum;\n    /// use alloy_provider::RootProvider;\n    /// use anvil::{NodeConfig, spawn};\n    ///\n    /// # async fn t() {\n    /// let (api, handle) = spawn(NodeConfig::default().with_eth_rpc_url(Some(\"http://....\"))).await;\n    ///\n    /// let provider = RootProvider::connect(\"ws://...\").await.unwrap();\n    ///\n    /// handle.task_manager().spawn_reset_on_subscribed_blocks::<Ethereum, _>(provider, api);\n    ///\n    /// # }\n    /// ```\n    pub fn spawn_reset_on_subscribed_blocks<N, P>(&self, provider: P, api: EthApi<FoundryNetwork>)\n    where\n        N: Network,\n        P: Provider<N> + 'static,\n    {\n        self.spawn_block_subscription(provider, move |header: N::HeaderResponse| {\n            let api = api.clone();\n            async move {\n                let _ = api\n                    .anvil_reset(Some(Forking {\n                        json_rpc_url: None,\n                        block_number: Some(header.number()),\n                    }))\n                    .await;\n            }\n        })\n    }\n\n    /// Spawns a new [`BlockListener`] task that listens for new blocks (via subscription) See also\n    /// [`Provider::subscribe_blocks()`] and executes the future the `task_factory` returns for the\n    /// new block hash\n    pub fn spawn_block_subscription<N, P, F, Fut>(&self, provider: P, task_factory: F)\n    where\n        N: Network,\n        P: Provider<N> + 'static,\n        F: Fn(N::HeaderResponse) -> Fut + Unpin + Send + Sync + 'static,\n        Fut: Future<Output = ()> + Send,\n    {\n        let shutdown = self.on_shutdown.clone();\n        self.spawn(async move {\n            let blocks = provider.subscribe_blocks().await.unwrap().into_stream();\n            BlockListener::new(shutdown, blocks, task_factory).await;\n        });\n    }\n}\n\nimpl fmt::Debug for TaskManager {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.debug_struct(\"TaskManager\").finish_non_exhaustive()\n    }\n}\n"
  },
  {
    "path": "crates/anvil/test-data/SimpleStorage.json",
    "content": "{\"abi\":[{\"inputs\":[{\"internalType\":\"string\",\"name\":\"value\",\"type\":\"string\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"author\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"oldAuthor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"oldValue\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"newValue\",\"type\":\"string\"}],\"name\":\"ValueChanged\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"_hashPuzzle\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getValue\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastSender\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"value\",\"type\":\"string\"}],\"name\":\"setValue\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"value\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"value2\",\"type\":\"string\"}],\"name\":\"setValues\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"bin\":\"60806040523480156200001157600080fd5b5060405162000d6a38038062000d6a83398181016040528101906200003791906200030f565b600073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f999b6d464c4e3383c341bdd3a22b02dda8a7e1d69c069d252e35cb2ee2f4a3c36001846040516200009a929190620004c3565b60405180910390a38060019080519060200190620000ba929190620000c2565b5050620004fe565b828054620000d0906200038f565b90600052602060002090601f016020900481019282620000f4576000855562000140565b82601f106200010f57805160ff191683800117855562000140565b8280016001018555821562000140579182015b828111156200013f57825182559160200191906001019062000122565b5b5090506200014f919062000153565b5090565b5b808211156200016e57600081600090555060010162000154565b5090565b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b620001db8262000190565b810181811067ffffffffffffffff82111715620001fd57620001fc620001a1565b5b80604052505050565b60006200021262000172565b9050620002208282620001d0565b919050565b600067ffffffffffffffff821115620002435762000242620001a1565b5b6200024e8262000190565b9050602081019050919050565b60005b838110156200027b5780820151818401526020810190506200025e565b838111156200028b576000848401525b50505050565b6000620002a8620002a28462000225565b62000206565b905082815260208101848484011115620002c757620002c66200018b565b5b620002d48482856200025b565b509392505050565b600082601f830112620002f457620002f362000186565b5b81516200030684826020860162000291565b91505092915050565b6000602082840312156200032857620003276200017c565b5b600082015167ffffffffffffffff81111562000349576200034862000181565b5b6200035784828501620002dc565b91505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b60006002820490506001821680620003a857607f821691505b60208210811415620003bf57620003be62000360565b5b50919050565b600082825260208201905092915050565b60008190508160005260206000209050919050565b60008154620003fa816200038f565b620004068186620003c5565b9450600182166000811462000424576001811462000437576200046e565b60ff19831686526020860193506200046e565b6200044285620003d6565b60005b83811015620004665781548189015260018201915060208101905062000445565b808801955050505b50505092915050565b600081519050919050565b60006200048f8262000477565b6200049b8185620003c5565b9350620004ad8185602086016200025b565b620004b88162000190565b840191505092915050565b60006040820190508181036000830152620004df8185620003eb565b90508181036020830152620004f5818462000482565b90509392505050565b61085c806200050e6000396000f3fe608060405234801561001057600080fd5b50600436106100575760003560e01c8063018ba9911461005c578063209652551461007a578063256fec88146100985780637ffaa4b6146100b657806393a09352146100d2575b600080fd5b6100646100ee565b60405161007191906103bd565b60405180910390f35b6100826100f7565b60405161008f9190610471565b60405180910390f35b6100a0610189565b6040516100ad91906104d4565b60405180910390f35b6100d060048036038101906100cb9190610638565b6101ad565b005b6100ec60048036038101906100e791906106b0565b61021f565b005b60006064905090565b60606001805461010690610728565b80601f016020809104026020016040519081016040528092919081815260200182805461013290610728565b801561017f5780601f106101545761010080835404028352916020019161017f565b820191906000526020600020905b81548152906001019060200180831161016257829003601f168201915b5050505050905090565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b81600190805190602001906101c3929190610301565b5080600290805190602001906101da929190610301565b50336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505050565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f999b6d464c4e3383c341bdd3a22b02dda8a7e1d69c069d252e35cb2ee2f4a3c360018460405161029f9291906107ef565b60405180910390a380600190805190602001906102bd929190610301565b50336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b82805461030d90610728565b90600052602060002090601f01602090048101928261032f5760008555610376565b82601f1061034857805160ff1916838001178555610376565b82800160010185558215610376579182015b8281111561037557825182559160200191906001019061035a565b5b5090506103839190610387565b5090565b5b808211156103a0576000816000905550600101610388565b5090565b6000819050919050565b6103b7816103a4565b82525050565b60006020820190506103d260008301846103ae565b92915050565b600081519050919050565b600082825260208201905092915050565b60005b838110156104125780820151818401526020810190506103f7565b83811115610421576000848401525b50505050565b6000601f19601f8301169050919050565b6000610443826103d8565b61044d81856103e3565b935061045d8185602086016103f4565b61046681610427565b840191505092915050565b6000602082019050818103600083015261048b8184610438565b905092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006104be82610493565b9050919050565b6104ce816104b3565b82525050565b60006020820190506104e960008301846104c5565b92915050565b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b61054582610427565b810181811067ffffffffffffffff821117156105645761056361050d565b5b80604052505050565b60006105776104ef565b9050610583828261053c565b919050565b600067ffffffffffffffff8211156105a3576105a261050d565b5b6105ac82610427565b9050602081019050919050565b82818337600083830152505050565b60006105db6105d684610588565b61056d565b9050828152602081018484840111156105f7576105f6610508565b5b6106028482856105b9565b509392505050565b600082601f83011261061f5761061e610503565b5b813561062f8482602086016105c8565b91505092915050565b6000806040838503121561064f5761064e6104f9565b5b600083013567ffffffffffffffff81111561066d5761066c6104fe565b5b6106798582860161060a565b925050602083013567ffffffffffffffff81111561069a576106996104fe565b5b6106a68582860161060a565b9150509250929050565b6000602082840312156106c6576106c56104f9565b5b600082013567ffffffffffffffff8111156106e4576106e36104fe565b5b6106f08482850161060a565b91505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6000600282049050600182168061074057607f821691505b60208210811415610754576107536106f9565b5b50919050565b60008190508160005260206000209050919050565b6000815461077c81610728565b61078681866103e3565b945060018216600081146107a157600181146107b3576107e6565b60ff19831686526020860193506107e6565b6107bc8561075a565b60005b838110156107de578154818901526001820191506020810190506107bf565b808801955050505b50505092915050565b60006040820190508181036000830152610809818561076f565b9050818103602083015261081d8184610438565b9050939250505056fea2646970667358221220e37ed4b56859ad0b3a3773f57ff7b4e7a99406933fc4ff9f8ae053c52cdf3e3264736f6c63430008090033\"}"
  },
  {
    "path": "crates/anvil/test-data/SimpleStorage.sol",
    "content": "pragma solidity >=0.4.24;\n\ncontract SimpleStorage {\n\n    event ValueChanged(address indexed author, address indexed oldAuthor, string oldValue, string newValue);\n\n    address public lastSender;\n    string _value;\n    string _otherValue;\n\n    constructor(string memory value) public {\n        emit ValueChanged(msg.sender, address(0), _value, value);\n        _value = value;\n    }\n\n    function getValue() view public returns (string memory) {\n        return _value;\n    }\n\n    function setValue(string memory value) public {\n        emit ValueChanged(msg.sender, lastSender, _value, value);\n        _value = value;\n        lastSender = msg.sender;\n    }\n\n    function setValues(string memory value, string memory value2) public {\n        _value = value;\n        _otherValue = value2;\n        lastSender = msg.sender;\n    }\n\n    function _hashPuzzle() public view returns (uint256) {\n        return 100;\n    }\n}\n"
  },
  {
    "path": "crates/anvil/test-data/emit_logs.json",
    "content": "{\"abi\":[{\"inputs\":[{\"internalType\":\"string\",\"name\":\"value\",\"type\":\"string\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"author\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"oldValue\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"newValue\",\"type\":\"string\"}],\"name\":\"ValueChanged\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"getValue\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"value\",\"type\":\"string\"}],\"name\":\"setValue\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"bin\":\"608060405234801561001057600080fd5b506040516105a63803806105a68339818101604052602081101561003357600080fd5b810190808051604051939291908464010000000082111561005357600080fd5b90830190602082018581111561006857600080fd5b825164010000000081118282018810171561008257600080fd5b82525081516020918201929091019080838360005b838110156100af578181015183820152602001610097565b50505050905090810190601f1680156100dc5780820380516001836020036101000a031916815260200191505b50604052505081516100f6915060009060208401906100fd565b505061019e565b828054600181600116156101000203166002900490600052602060002090601f0160209004810192826101335760008555610179565b82601f1061014c57805160ff1916838001178555610179565b82800160010185558215610179579182015b8281111561017957825182559160200191906001019061015e565b50610185929150610189565b5090565b5b80821115610185576000815560010161018a565b6103f9806101ad6000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c8063209652551461003b57806393a09352146100b8575b600080fd5b610043610160565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561007d578181015183820152602001610065565b50505050905090810190601f1680156100aa5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b61015e600480360360208110156100ce57600080fd5b8101906020810181356401000000008111156100e957600080fd5b8201836020820111156100fb57600080fd5b8035906020019184600183028401116401000000008311171561011d57600080fd5b91908080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509295506101f6945050505050565b005b60008054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156101ec5780601f106101c1576101008083540402835291602001916101ec565b820191906000526020600020905b8154815290600101906020018083116101cf57829003601f168201915b5050505050905090565b60408051818152600080546002600019610100600184161502019091160492820183905233927fe826f71647b8486f2bae59832124c70792fba044036720a54ec8dacdd5df4fcb9285918190602082019060608301908690801561029b5780601f106102705761010080835404028352916020019161029b565b820191906000526020600020905b81548152906001019060200180831161027e57829003601f168201915b5050838103825284518152845160209182019186019080838360005b838110156102cf5781810151838201526020016102b7565b50505050905090810190601f1680156102fc5780820380516001836020036101000a031916815260200191505b5094505050505060405180910390a2805161031e906000906020840190610322565b5050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282610358576000855561039e565b82601f1061037157805160ff191683800117855561039e565b8280016001018555821561039e579182015b8281111561039e578251825591602001919060010190610383565b506103aa9291506103ae565b5090565b5b808211156103aa57600081556001016103af56fea2646970667358221220c1367a0db85dfe60814cdfc5141a8fe8b95c9d051a6824343085c3ba9697244a64736f6c63430007060033\"}"
  },
  {
    "path": "crates/anvil/test-data/emit_logs.sol",
    "content": "pragma solidity >=0.4.24;\n\ncontract SimpleStorage {\n\n    event ValueChanged(address indexed author, string oldValue, string newValue);\n\n    string _value;\n\n    constructor(string memory value) public {\n        _value = value;\n    }\n\n    function getValue() view public returns (string memory) {\n        return _value;\n    }\n\n    function setValue(string memory value) public {\n        emit ValueChanged(msg.sender, _value, value);\n        _value = value;\n    }\n}\n"
  },
  {
    "path": "crates/anvil/test-data/greeter.json",
    "content": "{\"bytecode\":{\"object\":\"608060405234801561001057600080fd5b506040516104913803806104918339818101604052602081101561003357600080fd5b810190808051604051939291908464010000000082111561005357600080fd5b90830190602082018581111561006857600080fd5b825164010000000081118282018810171561008257600080fd5b82525081516020918201929091019080838360005b838110156100af578181015183820152602001610097565b50505050905090810190601f1680156100dc5780820380516001836020036101000a031916815260200191505b50604052505081516100f6915060009060208401906100fd565b505061019e565b828054600181600116156101000203166002900490600052602060002090601f0160209004810192826101335760008555610179565b82601f1061014c57805160ff1916838001178555610179565b82800160010185558215610179579182015b8281111561017957825182559160200191906001019061015e565b50610185929150610189565b5090565b5b80821115610185576000815560010161018a565b6102e4806101ad6000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c8063a41368621461003b578063cfae3217146100e3575b600080fd5b6100e16004803603602081101561005157600080fd5b81019060208101813564010000000081111561006c57600080fd5b82018360208201111561007e57600080fd5b803590602001918460018302840111640100000000831117156100a057600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550610160945050505050565b005b6100eb610177565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561012557818101518382015260200161010d565b50505050905090810190601f1680156101525780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b805161017390600090602084019061020d565b5050565b60008054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156102035780601f106101d857610100808354040283529160200191610203565b820191906000526020600020905b8154815290600101906020018083116101e657829003601f168201915b5050505050905090565b828054600181600116156101000203166002900490600052602060002090601f0160209004810192826102435760008555610289565b82601f1061025c57805160ff1916838001178555610289565b82800160010185558215610289579182015b8281111561028957825182559160200191906001019061026e565b50610295929150610299565b5090565b5b80821115610295576000815560010161029a56fea26469706673582212208b9161dfd195d53618942a72a3b481d61a7b142de919925a0b34f9c986e5707e64736f6c63430007060033\"},\"abi\":[{\"inputs\":[{\"internalType\":\"string\",\"name\":\"_greeting\",\"type\":\"string\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"greet\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"_greeting\",\"type\":\"string\"}],\"name\":\"setGreeting\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]}"
  },
  {
    "path": "crates/anvil/test-data/multicall.json",
    "content": "{\"abi\":[{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"}],\"internalType\":\"struct Multicall.Call[]\",\"name\":\"calls\",\"type\":\"tuple[]\"}],\"name\":\"aggregate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"},{\"internalType\":\"bytes[]\",\"name\":\"returnData\",\"type\":\"bytes[]\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"}],\"name\":\"getBlockHash\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"blockHash\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentBlockCoinbase\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"coinbase\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentBlockDifficulty\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"difficulty\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentBlockGasLimit\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"gaslimit\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentBlockTimestamp\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"getEthBalance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getLastBlockHash\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"blockHash\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"bin\":\"608060405234801561001057600080fd5b50610abb806100206000396000f3fe608060405234801561001057600080fd5b50600436106100885760003560e01c806372425d9d1161005b57806372425d9d1461012a57806386d516e814610148578063a8b0574e14610166578063ee82ac5e1461018457610088565b80630f28c97d1461008d578063252dba42146100ab57806327e86d6e146100dc5780634d2301cc146100fa575b600080fd5b6100956101b4565b6040516100a29190610381565b60405180910390f35b6100c560048036038101906100c091906106b0565b6101bc565b6040516100d3929190610843565b60405180910390f35b6100e461030f565b6040516100f1919061088c565b60405180910390f35b610114600480360381019061010f91906108a7565b610324565b6040516101219190610381565b60405180910390f35b610132610345565b60405161013f9190610381565b60405180910390f35b61015061034d565b60405161015d9190610381565b60405180910390f35b61016e610355565b60405161017b91906108e3565b60405180910390f35b61019e6004803603810190610199919061092a565b61035d565b6040516101ab919061088c565b60405180910390f35b600042905090565b60006060439150825167ffffffffffffffff8111156101de576101dd6103c6565b5b60405190808252806020026020018201604052801561021157816020015b60608152602001906001900390816101fc5790505b50905060005b83518110156103095760008085838151811061023657610235610957565b5b60200260200101516000015173ffffffffffffffffffffffffffffffffffffffff1686848151811061026b5761026a610957565b5b60200260200101516020015160405161028491906109c2565b6000604051808303816000865af19150503d80600081146102c1576040519150601f19603f3d011682016040523d82523d6000602084013e6102c6565b606091505b5091509150816102d557600080fd5b808484815181106102e9576102e8610957565b5b60200260200101819052505050808061030190610a08565b915050610217565b50915091565b600060014361031e9190610a51565b40905090565b60008173ffffffffffffffffffffffffffffffffffffffff16319050919050565b600044905090565b600045905090565b600041905090565b600081409050919050565b6000819050919050565b61037b81610368565b82525050565b60006020820190506103966000830184610372565b92915050565b6000604051905090565b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6103fe826103b5565b810181811067ffffffffffffffff8211171561041d5761041c6103c6565b5b80604052505050565b600061043061039c565b905061043c82826103f5565b919050565b600067ffffffffffffffff82111561045c5761045b6103c6565b5b602082029050602081019050919050565b600080fd5b600080fd5b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006104a78261047c565b9050919050565b6104b78161049c565b81146104c257600080fd5b50565b6000813590506104d4816104ae565b92915050565b600080fd5b600067ffffffffffffffff8211156104fa576104f96103c6565b5b610503826103b5565b9050602081019050919050565b82818337600083830152505050565b600061053261052d846104df565b610426565b90508281526020810184848401111561054e5761054d6104da565b5b610559848285610510565b509392505050565b600082601f830112610576576105756103b0565b5b813561058684826020860161051f565b91505092915050565b6000604082840312156105a5576105a4610472565b5b6105af6040610426565b905060006105bf848285016104c5565b600083015250602082013567ffffffffffffffff8111156105e3576105e2610477565b5b6105ef84828501610561565b60208301525092915050565b600061060e61060984610441565b610426565b905080838252602082019050602084028301858111156106315761063061046d565b5b835b8181101561067857803567ffffffffffffffff811115610656576106556103b0565b5b808601610663898261058f565b85526020850194505050602081019050610633565b5050509392505050565b600082601f830112610697576106966103b0565b5b81356106a78482602086016105fb565b91505092915050565b6000602082840312156106c6576106c56103a6565b5b600082013567ffffffffffffffff8111156106e4576106e36103ab565b5b6106f084828501610682565b91505092915050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b600081519050919050565b600082825260208201905092915050565b60005b8381101561075f578082015181840152602081019050610744565b8381111561076e576000848401525b50505050565b600061077f82610725565b6107898185610730565b9350610799818560208601610741565b6107a2816103b5565b840191505092915050565b60006107b98383610774565b905092915050565b6000602082019050919050565b60006107d9826106f9565b6107e38185610704565b9350836020820285016107f585610715565b8060005b85811015610831578484038952815161081285826107ad565b945061081d836107c1565b925060208a019950506001810190506107f9565b50829750879550505050505092915050565b60006040820190506108586000830185610372565b818103602083015261086a81846107ce565b90509392505050565b6000819050919050565b61088681610873565b82525050565b60006020820190506108a1600083018461087d565b92915050565b6000602082840312156108bd576108bc6103a6565b5b60006108cb848285016104c5565b91505092915050565b6108dd8161049c565b82525050565b60006020820190506108f860008301846108d4565b92915050565b61090781610368565b811461091257600080fd5b50565b600081359050610924816108fe565b92915050565b6000602082840312156109405761093f6103a6565b5b600061094e84828501610915565b91505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600081905092915050565b600061099c82610725565b6109a68185610986565b93506109b6818560208601610741565b80840191505092915050565b60006109ce8284610991565b915081905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000610a1382610368565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415610a4657610a456109d9565b5b600182019050919050565b6000610a5c82610368565b9150610a6783610368565b925082821015610a7a57610a796109d9565b5b82820390509291505056fea2646970667358221220e5023d90063e0939116a41565414721ba1350cd3e98b12e7b65983a039644df964736f6c634300080a0033\"}"
  },
  {
    "path": "crates/anvil/test-data/multicall.sol",
    "content": "/**\n *Submitted for verification at Etherscan.io on 2019-06-10\n*/\n\npragma solidity >=0.5.0;\npragma experimental ABIEncoderV2;\n\n/// @title Multicall - Aggregate results from multiple read-only function calls\n/// @author Michael Elliot <mike@makerdao.com>\n/// @author Joshua Levine <joshua@makerdao.com>\n/// @author Nick Johnson <arachnid@notdot.net>\n\ncontract Multicall {\n    struct Call {\n        address target;\n        bytes callData;\n    }\n    function aggregate(Call[] memory calls) public returns (uint256 blockNumber, bytes[] memory returnData) {\n        blockNumber = block.number;\n        returnData = new bytes[](calls.length);\n        for(uint256 i = 0; i < calls.length; i++) {\n            (bool success, bytes memory ret) = calls[i].target.call(calls[i].callData);\n            require(success);\n            returnData[i] = ret;\n        }\n    }\n    // Helper functions\n    function getEthBalance(address addr) public view returns (uint256 balance) {\n        balance = addr.balance;\n    }\n    function getBlockHash(uint256 blockNumber) public view returns (bytes32 blockHash) {\n        blockHash = blockhash(blockNumber);\n    }\n    function getLastBlockHash() public view returns (bytes32 blockHash) {\n        blockHash = blockhash(block.number - 1);\n    }\n    function getCurrentBlockTimestamp() public view returns (uint256 timestamp) {\n        timestamp = block.timestamp;\n    }\n    function getCurrentBlockDifficulty() public view returns (uint256 difficulty) {\n        difficulty = block.difficulty;\n    }\n    function getCurrentBlockGasLimit() public view returns (uint256 gaslimit) {\n        gaslimit = block.gaslimit;\n    }\n    function getCurrentBlockCoinbase() public view returns (address coinbase) {\n        coinbase = block.coinbase;\n    }\n}"
  },
  {
    "path": "crates/anvil/test-data/state-dump-legacy-stress.json",
    "content": "{\"block\":{\"number\":5,\"beneficiary\":\"0x0000000000000000000000000000000000000000\",\"timestamp\":1722941643,\"gas_limit\":30000000,\"basefee\":316710010,\"difficulty\":\"0x0\",\"prevrandao\":\"0xe7ef87fc7c2090741a6749a087e4ca8092cb4d07136008799e4ebeac3b69e34a\",\"blob_excess_gas_and_price\":{\"excess_blob_gas\":0,\"blob_gasprice\":1}},\"accounts\":{\"0x0000000000000000000000000000000000000000\":{\"nonce\":0,\"balance\":\"0x1088aa62285a00\",\"code\":\"0x\",\"storage\":{}},\"0x108f53faf774d7c4c56f5bce9ca6e605ce8aeadd\":{\"nonce\":1,\"balance\":\"0x0\",\"code\":\"0x6080604052600080357fffffffff0000000000000000000000000000000000000000000000000000000016905060008160e01c610251565b60006379ba509782101561015e5781631627540c811461009857632a952b2d81146100b457633659cfe681146100d0576350c946fe81146100ec576353a47bb781146101085763625ca21c81146101245763718fe928811461014057610158565b7347d08dad17ccb558b3ea74b1a0e73a9cc804a9dc9150610158565b738138ef7cf908021d117e542120b7a390650161079150610158565b7347d08dad17ccb558b3ea74b1a0e73a9cc804a9dc9150610158565b738138ef7cf908021d117e542120b7a390650161079150610158565b7347d08dad17ccb558b3ea74b1a0e73a9cc804a9dc9150610158565b738138ef7cf908021d117e542120b7a390650161079150610158565b7347d08dad17ccb558b3ea74b1a0e73a9cc804a9dc91505b5061024c565b816379ba509781146101a657638da5cb5b81146101c25763aaf10f4281146101de5763c7f62cda81146101fa5763daa250be81146102165763deba1b9881146102325761024a565b7347d08dad17ccb558b3ea74b1a0e73a9cc804a9dc915061024a565b7347d08dad17ccb558b3ea74b1a0e73a9cc804a9dc915061024a565b7347d08dad17ccb558b3ea74b1a0e73a9cc804a9dc915061024a565b7347d08dad17ccb558b3ea74b1a0e73a9cc804a9dc915061024a565b738138ef7cf908021d117e542120b7a39065016107915061024a565b738138ef7cf908021d117e542120b7a3906501610791505b505b919050565b61025a81610037565b915050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036102ce57816040517fc2a825f50000000000000000000000000000000000000000000000000000000081526004016102c5919061032f565b60405180910390fd5b3660008037600080366000845af43d6000803e80600081146102ef573d6000f35b3d6000fd5b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b610329816102f4565b82525050565b60006020820190506103446000830184610320565b9291505056fea264697066735822122017a4b7fdaaab3897a7b47abaed8d2ee92d558883d3bb2a8454f9601b2ab2c3db64736f6c63430008150033\",\"storage\":{}},\"0x14dc79964da2c08b23698b3d3cc7ca32193d9955\":{\"nonce\":0,\"balance\":\"0x21e19e0c9bab2400000\",\"code\":\"0x\",\"storage\":{}},\"0x15d34aaf54267db7d7c367839aaf71a00a2c6a65\":{\"nonce\":0,\"balance\":\"0x21e19e0c9bab2400000\",\"code\":\"0x\",\"storage\":{}},\"0x19ba1fac55eea44d12a01372a8eb0c2ebbf9ca21\":{\"nonce\":1,\"balance\":\"0x21e19df7c2963f0ac6b\",\"code\":\"0x\",\"storage\":{}},\"0x19c6ab860dbe2bc433574193a4409770a8748bf6\":{\"nonce\":1,\"balance\":\"0x21e19df8da6b7bdc410\",\"code\":\"0x\",\"storage\":{}},\"0x23618e81e3f5cdf7f54c3d65f7fbc0abf5b21e8f\":{\"nonce\":0,\"balance\":\"0x21e19e0c9bab2400000\",\"code\":\"0x\",\"storage\":{}},\"0x3c44cdddb6a900fa2b585dd299e03d12fa4293bc\":{\"nonce\":0,\"balance\":\"0x21e19e0c9bab2400000\",\"code\":\"0x\",\"storage\":{}},\"0x40567ec443c1d1872af5155755ac3803cc3fe61e\":{\"nonce\":1,\"balance\":\"0x21e19da82562f921b40\",\"code\":\"0x\",\"storage\":{}},\"0x47d08dad17ccb558b3ea74b1a0e73a9cc804a9dc\":{\"nonce\":1,\"balance\":\"0x0\",\"code\":\"0x608060405234801561001057600080fd5b50600436106100885760003560e01c806379ba50971161005b57806379ba5097146100ed5780638da5cb5b146100f7578063aaf10f4214610115578063c7f62cda1461013357610088565b80631627540c1461008d5780633659cfe6146100a957806353a47bb7146100c5578063718fe928146100e3575b600080fd5b6100a760048036038101906100a29190610d25565b61014f565b005b6100c360048036038101906100be9190610d25565b6102d0565b005b6100cd6102e4565b6040516100da9190610d61565b60405180910390f35b6100eb610317565b005b6100f56103fe565b005b6100ff61058b565b60405161010c9190610d61565b60405180910390f35b61011d6105be565b60405161012a9190610d61565b60405180910390f35b61014d60048036038101906101489190610d25565b6105f1565b005b61015761084c565b600061016161081b565b9050600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036101c9576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610252576040517fa88ee57700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b818160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055507f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce22826040516102c49190610d61565b60405180910390a15050565b6102d861084c565b6102e1816108c5565b50565b60006102ee61081b565b60010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b600061032161081b565b90503373ffffffffffffffffffffffffffffffffffffffff168160010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16146103b757336040517fa0e5a0d70000000000000000000000000000000000000000000000000000000081526004016103ae9190610d61565b60405180910390fd5b60008160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b600061040861081b565b905060008160010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146104a357336040517fa0e5a0d700000000000000000000000000000000000000000000000000000000815260040161049a9190610d61565b60405180910390fd5b7fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c8260000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16826040516104f8929190610d7c565b60405180910390a1808260000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060008260010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505050565b600061059561081b565b60000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60006105c8610b05565b60000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60006105fb610b05565b905060018160000160146101000a81548160ff02191690831515021790555060008160000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050828260000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060008373ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff16633659cfe6846040516024016106cc9190610d61565b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505060405161071b9190610e16565b600060405180830381855af49150503d8060008114610756576040519150601f19603f3d011682016040523d82523d6000602084013e61075b565b606091505b505090508015806107c357508173ffffffffffffffffffffffffffffffffffffffff16610786610b05565b60000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614155b156107fa576040517fa1cfa5a800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008360000160146101000a81548160ff0219169083151502179055600080fd5b60008060405160200161082d90610eb0565b6040516020818303038152906040528051906020012090508091505090565b610854610b36565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146108c357336040517f8e4a23d60000000000000000000000000000000000000000000000000000000081526004016108ba9190610d61565b60405180910390fd5b565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361092b576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61093481610b69565b61097557806040517f8a8b41ec00000000000000000000000000000000000000000000000000000000815260040161096c9190610d61565b60405180910390fd5b600061097f610b05565b90508060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610a0a576040517fa88ee57700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8060000160149054906101000a900460ff16158015610a2e5750610a2d82610b7c565b5b15610a7057816040517f15504301000000000000000000000000000000000000000000000000000000008152600401610a679190610d61565b60405180910390fd5b818160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055503073ffffffffffffffffffffffffffffffffffffffff167f5d611f318680d00598bb735d61bacf0c514c6b50e1e5ad30040a4df2b12791c783604051610af99190610d61565b60405180910390a25050565b600080604051602001610b1790610f42565b6040516020818303038152906040528051906020012090508091505090565b6000610b4061081b565b60000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b600080823b905060008111915050919050565b60008060003073ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff1663c7f62cda86604051602401610bc59190610d61565b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050604051610c149190610e16565b600060405180830381855af49150503d8060008114610c4f576040519150601f19603f3d011682016040523d82523d6000602084013e610c54565b606091505b509150915081158015610cb9575063a1cfa5a860e01b604051602001610c7a9190610faf565b6040516020818303038152906040528051906020012081604051602001610ca19190610e16565b60405160208183030381529060405280519060200120145b92505050919050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000610cf282610cc7565b9050919050565b610d0281610ce7565b8114610d0d57600080fd5b50565b600081359050610d1f81610cf9565b92915050565b600060208284031215610d3b57610d3a610cc2565b5b6000610d4984828501610d10565b91505092915050565b610d5b81610ce7565b82525050565b6000602082019050610d766000830184610d52565b92915050565b6000604082019050610d916000830185610d52565b610d9e6020830184610d52565b9392505050565b600081519050919050565b600081905092915050565b60005b83811015610dd9578082015181840152602081019050610dbe565b60008484015250505050565b6000610df082610da5565b610dfa8185610db0565b9350610e0a818560208601610dbb565b80840191505092915050565b6000610e228284610de5565b915081905092915050565b600082825260208201905092915050565b7f696f2e73796e7468657469782e636f72652d636f6e7472616374732e4f776e6160008201527f626c650000000000000000000000000000000000000000000000000000000000602082015250565b6000610e9a602383610e2d565b9150610ea582610e3e565b604082019050919050565b60006020820190508181036000830152610ec981610e8d565b9050919050565b7f696f2e73796e7468657469782e636f72652d636f6e7472616374732e50726f7860008201527f7900000000000000000000000000000000000000000000000000000000000000602082015250565b6000610f2c602183610e2d565b9150610f3782610ed0565b604082019050919050565b60006020820190508181036000830152610f5b81610f1f565b9050919050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b6000819050919050565b610fa9610fa482610f62565b610f8e565b82525050565b6000610fbb8284610f98565b6004820191508190509291505056fea264697066735822122023a7c33d7b91dce35ffbcf8837693364ab22a3905d0fc00016833e5fac45ca2f64736f6c63430008110033\",\"storage\":{\"0x5c7865864a2a990d80b5bb5c40e7b73a029960dc711fbb56120dfab976e92ea3\":\"0x0\"}},\"0x4e59b44847b379578588920ca78fbf26c0b4956c\":{\"nonce\":2,\"balance\":\"0x0\",\"code\":\"0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf3\",\"storage\":{}},\"0x70997970c51812dc3a010c7d01b50e0d17dc79c8\":{\"nonce\":0,\"balance\":\"0x21e19e0c9bab2400000\",\"code\":\"0x\",\"storage\":{}},\"0x8138ef7cf908021d117e542120b7a39065016107\":{\"nonce\":1,\"balance\":\"0x0\",\"code\":\"0x608060405234801561001057600080fd5b50600436106100575760003560e01c80632a952b2d1461005c57806350c946fe14610085578063625ca21c146100a5578063daa250be146100c6578063deba1b98146100d9575b600080fd5b61006f61006a366004613a63565b6100ec565b60405161007c9190613a7c565b60405180910390f35b610098610093366004613a63565b61011c565b60405161007c9190613b21565b6100b86100b3366004613c92565b610276565b60405190815260200161007c565b61006f6100d4366004613d5f565b6102bb565b6100b86100e7366004613c92565b6102d6565b6100f46139e4565b6040805160008082526020820190815281830190925261011691849190610310565b92915050565b6101416040805160608101909152806000815260200160608152602001606081525090565b61014a82610ab6565b60408051606081019091528154909190829060ff16600981111561017057610170613aa7565b600981111561018157610181613aa7565b815260200160018201805461019590613dc2565b80601f01602080910402602001604051908101604052809291908181526020018280546101c190613dc2565b801561020e5780601f106101e35761010080835404028352916020019161020e565b820191906000526020600020905b8154815290600101906020018083116101f157829003601f168201915b505050505081526020016002820180548060200260200160405190810160405280929190818152602001828054801561026657602002820191906000526020600020905b815481526020019060010190808311610252575b5050505050815250509050919050565b600080604051806060016040528086600981111561029657610296613aa7565b81526020018581526020018481525090506102b081610ac1565b9150505b9392505050565b6102c36139e4565b6102ce848484610310565b949350505050565b60008060405180606001604052808660098111156102f6576102f6613aa7565b81526020018581526020018481525090506102b081610acc565b6103186139e4565b81518351146103a05760408051634bab873760e11b81526004810191909152600d60448201526c72756e74696d6556616c75657360981b606482015260806024820152602260848201527f6d7573742062652073616d65206c656e6774682061732072756e74696d654b6560a482015261797360f01b60c482015260e4015b60405180910390fd5b60006103ab85610c26565b805490915060ff1660018160098111156103c7576103c7613aa7565b036104755761046c6103da838787610c84565b8360010180546103e990613dc2565b80601f016020809104026020016040519081016040528092919081815260200182805461041590613dc2565b80156104625780601f1061043757610100808354040283529160200191610462565b820191906000526020600020905b81548152906001019060200180831161044557829003601f168201915b5050505050610d46565b925050506102b4565b600281600981111561048957610489613aa7565b036105305761046c61049c838787610c84565b8360010180546104ab90613dc2565b80601f01602080910402602001604051908101604052809291908181526020018280546104d790613dc2565b80156105245780601f106104f957610100808354040283529160200191610524565b820191906000526020600020905b81548152906001019060200180831161050757829003601f168201915b50505050508787610ebb565b600381600981111561054457610544613aa7565b036105de5761046c82600101805461055b90613dc2565b80601f016020809104026020016040519081016040528092919081815260200182805461058790613dc2565b80156105d45780601f106105a9576101008083540402835291602001916105d4565b820191906000526020600020905b8154815290600101906020018083116105b757829003601f168201915b5050505050610f59565b60048160098111156105f2576105f2613aa7565b0361068c5761046c82600101805461060990613dc2565b80601f016020809104026020016040519081016040528092919081815260200182805461063590613dc2565b80156106825780601f1061065757610100808354040283529160200191610682565b820191906000526020600020905b81548152906001019060200180831161066557829003601f168201915b5050505050611087565b60058160098111156106a0576106a0613aa7565b0361073a5761046c8260010180546106b790613dc2565b80601f01602080910402602001604051908101604052809291908181526020018280546106e390613dc2565b80156107305780601f1061070557610100808354040283529160200191610730565b820191906000526020600020905b81548152906001019060200180831161071357829003601f168201915b505050505061131e565b600981600981111561074e5761074e613aa7565b036107ea5761046c82600101805461076590613dc2565b80601f016020809104026020016040519081016040528092919081815260200182805461079190613dc2565b80156107de5780601f106107b3576101008083540402835291602001916107de565b820191906000526020600020905b8154815290600101906020018083116107c157829003601f168201915b505050505086866114b5565b60068160098111156107fe576107fe613aa7565b036108a35761046c610811838787610c84565b83600101805461082090613dc2565b80601f016020809104026020016040519081016040528092919081815260200182805461084c90613dc2565b80156108995780601f1061086e57610100808354040283529160200191610899565b820191906000526020600020905b81548152906001019060200180831161087c57829003601f168201915b50505050506115c7565b60078160098111156108b7576108b7613aa7565b036109ec576040805160608101909152825461046c91908490829060ff1660098111156108e6576108e6613aa7565b60098111156108f7576108f7613aa7565b815260200160018201805461090b90613dc2565b80601f016020809104026020016040519081016040528092919081815260200182805461093790613dc2565b80156109845780601f1061095957610100808354040283529160200191610984565b820191906000526020600020905b81548152906001019060200180831161096757829003601f168201915b50505050508152602001600282018054806020026020016040519081016040528092919081815260200182805480156109dc57602002820191906000526020600020905b8154815260200190600101908083116109c8575b5050505050815250508686611728565b6008816009811115610a0057610a00613aa7565b03610a9a5761046c826001018054610a1790613dc2565b80601f0160208091040260200160405190810160405280929190818152602001828054610a4390613dc2565b8015610a905780601f10610a6557610100808354040283529160200191610a90565b820191906000526020600020905b815481529060010190602001808311610a7357829003601f168201915b50505050506118a5565b6040516323a9bbc960e01b815260048101879052602401610397565b600061011682610c26565b6000610116826118ea565b6000610ad782610ac1565b9050610ae28161192a565b15610b35577fcb64985827770858ec421ad26da7e558c757541643036ce44d6b4eb9e8e5dc5e81836000015184602001518560400151604051610b289493929190613e32565b60405180910390a1919050565b610b3e82611a8c565b610b5d578160405163382bbbc960e11b81526004016103979190613b21565b60005b826040015151811015610bd957610b9383604001518281518110610b8657610b86613e6a565b602002602001015161192a565b610bd15782604001518181518110610bad57610bad613e6a565b6020026020010151604051632f19f96160e11b815260040161039791815260200190565b600101610b60565b50610be382611c31565b8351602085015160408087015190519395507fcb64985827770858ec421ad26da7e558c757541643036ce44d6b4eb9e8e5dc5e9450610b28938693929190613e32565b604080516020808201839052606082018190527f696f2e73796e7468657469782e6f7261636c652d6d616e616765722e4e6f6465608080840191909152828401949094528251808303909401845260a0909101909152815191012090565b600283015460609067ffffffffffffffff811115610ca457610ca4613b9a565b604051908082528060200260200182016040528015610cdd57816020015b610cca6139e4565b815260200190600190039081610cc25790505b50905060005b6002850154811015610d3e57610d19856002018281548110610d0757610d07613e6a565b90600052602060002001548585610310565b828281518110610d2b57610d2b613e6a565b6020908102919091010152600101610ce3565b509392505050565b610d4e6139e4565b600082806020019051810190610d649190613e80565b90506000816008811115610d7a57610d7a613aa7565b03610d9057610d8884611ca5565b915050610116565b6001816008811115610da457610da4613aa7565b03610db257610d8884611d0d565b6002816008811115610dc657610dc6613aa7565b03610dd457610d8884611d90565b6003816008811115610de857610de8613aa7565b03610df657610d8884611e13565b6004816008811115610e0a57610e0a613aa7565b03610e1857610d8884611ec9565b6005816008811115610e2c57610e2c613aa7565b03610e3a57610d8884612009565b6006816008811115610e4e57610e4e613aa7565b03610e5c57610d88846120e4565b6007816008811115610e7057610e70613aa7565b03610e7e57610d888461220c565b6008816008811115610e9257610e92613aa7565b03610ea057610d88846122ce565b80604051631be413d360e11b81526004016103979190613ea1565b610ec36139e4565b600084806020019051810190610ed99190613ed3565b604051631ecba7c360e31b81529091506001600160a01b0382169063f65d3e1890610f0e908990899089908990600401613ef0565b608060405180830381865afa158015610f2b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f4f9190613f91565b9695505050505050565b610f616139e4565b600080600084806020019051810190610f7a9190613fe8565b92509250925060008390506000806000836001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015610fc8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fec9190614041565b509350509250925060008660001461100f5761100a8585858a6123c7565b611011565b825b905060128660ff161161103b5761103661102f60ff881660126140a7565b82906124c2565b611053565b61105361104c601260ff89166140a7565b82906124dc565b9050604051806080016040528082815260200183815260200160008152602001600081525098505050505050505050919050565b61108f6139e4565b600080600080600080878060200190518101906110ac91906140ba565b604080516002808252606082018352979d50959b50939950919750955093506000929060208301908036833701905050905081816000815181106110f2576110f2613e6a565b602002602001019063ffffffff16908163ffffffff168152505060008160018151811061112157611121613e6a565b63ffffffff9092166020928302919091019091015260405163883bdbfd60e01b81526000906001600160a01b0385169063883bdbfd90611165908590600401614143565b600060405180830381865afa158015611182573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526111aa91908101906141f5565b5090506000816000815181106111c2576111c2613e6a565b6020026020010151826001815181106111dd576111dd613e6a565b60200260200101516111ef91906142c1565b9050600061121761120563ffffffff87166124f6565b61120f9084614304565b60060b61252d565b905060008260060b12801561124c575061123b63ffffffff8616612569565b612569565b8260060b6112499190614342565b15155b1561125f578061125b81614356565b9150505b600061126d6012600a61445d565b9050600061128061123684848f8f612593565b905060006112908a60ff16612569565b61129c8c60ff16612569565b6112a6919061446c565b905060008082136112d1576112cc6112c56112c084614493565b612686565b84906124dc565b6112e4565b6112e46112dd83612686565b84906124c2565b905060405180608001604052808281526020014281526020016000815260200160008152509e505050505050505050505050505050919050565b6113266139e4565b60008060008480602001905181019061133f91906144bf565b91945092509050826000826113bc576040516396834ad360e01b8152600481018590526001600160a01b038316906396834ad390602401608060405180830381865afa158015611393573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113b791906144f5565b611425565b604051639474f45b60e01b8152600481018590526001600160a01b03831690639474f45b90602401608060405180830381865afa158015611401573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061142591906144f5565b90506000816040015160030b601261143d919061456f565b90506000808213611467576114626114576112c084614493565b845160070b906124dc565b61147e565b61147e61147383612686565b845160070b906124c2565b9050604051806080016040528082815260200184606001518152602001600081526020016000815250975050505050505050919050565b6114bd6139e4565b6000806000868060200190518101906114d69190614597565b92509250925060005b8651811015611545578681815181106114fa576114fa613e6a565b6020026020010151717374616c656e657373546f6c6572616e636560701b0361153d5785818151811061152f5761152f613e6a565b602002602001015160001c91505b6001016114df565b5060408051600180825281830190925260009160208083019080368337019050509050828160008151811061157c5761157c613e6a565b602002602001018181525050836001838360405160200161159f939291906145ce565b60408051601f198184030181529082905263cf2cabdf60e01b82526103979291600401614603565b6115cf6139e4565b6000828060200190518101906115e59190614627565b90506000846000815181106115fc576115fc613e6a565b602002602001015160000151905060008560018151811061161f5761161f613e6a565b6020026020010151600001519050808214611702576000611653601261164d611648858761446c565b6126a9565b906124c2565b905082158061167b5750611666836126a9565b6116709082614640565b61167985612569565b125b15611700576002875111156116b0578660028151811061169d5761169d613e6a565b6020026020010151945050505050610116565b826000036116d15760405163014cc07160e01b815260040160405180910390fd5b6116da836126a9565b6116e49082614640565b60405163dcac091960e01b815260040161039791815260200190565b505b8560008151811061171557611715613e6a565b6020026020010151935050505092915050565b6117306139e4565b6000846020015180602001905181019061174a9190614627565b905060005b84518110156117bc5784818151811061176a5761176a613e6a565b6020026020010151717374616c656e657373546f6c6572616e636560701b036117b4576117ad8482815181106117a2576117a2613e6a565b602002602001015190565b91506117bc565b60010161174f565b50600085604001516000815181106117d6576117d6613e6a565b6020026020010151905060006117ed828787610310565b60208101519091506117ff84426140a7565b1161180e5792506102b4915050565b86604001515160010361187157866040015160008151811061183257611832613e6a565b602002602001015181600001518260200151604051631808066560e21b8152600401610397939291909283526020830191909152604082015260600190565b61189a876040015160018151811061188b5761188b613e6a565b60200260200101518787610310565b979650505050505050565b6118ad6139e4565b6040518060800160405280838060200190518101906118cc9190614627565b81526020014281526020016000815260200160008152509050919050565b600081600001518260200151836040015160405160200161190d9392919061466e565b604051602081830303815290604052805190602001209050919050565b60008061193683610c26565b60408051606081019091528154909190829060ff16600981111561195c5761195c613aa7565b600981111561196d5761196d613aa7565b815260200160018201805461198190613dc2565b80601f01602080910402602001604051908101604052809291908181526020018280546119ad90613dc2565b80156119fa5780601f106119cf576101008083540402835291602001916119fa565b820191906000526020600020905b8154815290600101906020018083116119dd57829003601f168201915b5050505050815260200160028201805480602002602001604051908101604052809291908181526020018280548015611a5257602002820191906000526020600020905b815481526020019060010190808311611a3e575b505050505081525050905060006009811115611a7057611a70613aa7565b81516009811115611a8357611a83613aa7565b14159392505050565b6000600182516009811115611aa357611aa3613aa7565b1480611ac15750600682516009811115611abf57611abf613aa7565b145b80611ade5750600782516009811115611adc57611adc613aa7565b145b15611aee57611aec826126c1565b505b600182516009811115611b0357611b03613aa7565b03611b11576101168261284a565b600282516009811115611b2657611b26613aa7565b03611b3457610116826128a5565b600382516009811115611b4957611b49613aa7565b03611b575761011682612973565b600482516009811115611b6c57611b6c613aa7565b03611b7a5761011682612aae565b600582516009811115611b8f57611b8f613aa7565b03611b9d5761011682612e92565b600982516009811115611bb257611bb2613aa7565b03611bc05761011682612fcb565b600682516009811115611bd557611bd5613aa7565b03611be3576101168261300e565b600782516009811115611bf857611bf8613aa7565b03611c065761011682613052565b600882516009811115611c1b57611c1b613aa7565b03611c295761011682613078565b506000919050565b600080611c3d836118ea565b9050611c4881610c26565b8351815491935090839060ff19166001836009811115611c6a57611c6a613aa7565b021790555060208301516001830190611c8390826146ed565b5060408301518051611c9f916002850191602090910190613a0c565b50915091565b611cad6139e4565b60005b8251811015611d07578160200151838281518110611cd057611cd0613e6a565b6020026020010151602001511115611cff57828181518110611cf457611cf4613e6a565b602002602001015191505b600101611cb0565b50919050565b611d156139e4565b81600081518110611d2857611d28613e6a565b602002602001015190506000600190505b8251811015611d07578160000151838281518110611d5957611d59613e6a565b6020026020010151600001511215611d8857828181518110611d7d57611d7d613e6a565b602002602001015191505b600101611d39565b611d986139e4565b81600081518110611dab57611dab613e6a565b602002602001015190506000600190505b8251811015611d07578160000151838281518110611ddc57611ddc613e6a565b6020026020010151600001511315611e0b57828181518110611e0057611e00613e6a565b602002602001015191505b600101611dbc565b611e1b6139e4565b60005b8251811015611e9557828181518110611e3957611e39613e6a565b60200260200101516000015182600001818151611e56919061456f565b9052508251839082908110611e6d57611e6d613e6a565b60200260200101516020015182602001818151611e8a91906147ad565b905250600101611e1e565b50611ea08251612569565b8151611eac9190614640565b815281516020820151611ebf91906147c0565b6020820152919050565b611ed16139e4565b611eed826000611ee86001865161123691906140a7565b6130a4565b60028251611efb91906147d4565b600003611fd65760408051600280825260608201909252600091816020015b611f226139e4565b815260200190600190039081611f1a57905050905082600160028551611f4891906147c0565b611f5291906140a7565b81518110611f6257611f62613e6a565b602002602001015181600081518110611f7d57611f7d613e6a565b60200260200101819052508260028451611f9791906147c0565b81518110611fa757611fa7613e6a565b602002602001015181600181518110611fc257611fc2613e6a565b60200260200101819052506102b481611e13565b8160028351611fe591906147c0565b81518110611ff557611ff5613e6a565b60200260200101519050919050565b919050565b6120116139e4565b8160008151811061202457612024613e6a565b60209081029190910101515181528151829060009061204557612045613e6a565b6020908102919091018101518101519082015260015b82518110156120d25782818151811061207657612076613e6a565b6020026020010151600001518260000181815161209391906147e8565b90525082518390829081106120aa576120aa613e6a565b602002602001015160200151826020018181516120c791906147ad565b90525060010161205b565b5081518160200151611ebf91906147c0565b6120ec6139e4565b816000815181106120ff576120ff613e6a565b60209081029190910101515181528151829060009061212057612120613e6a565b6020908102919091018101518101519082015260015b82518110156120d25782818151811061215157612151613e6a565b60200260200101516000015160000361219e5782818151811061217657612176613e6a565b6020026020010151600001516040516338ee04a760e01b815260040161039791815260200190565b8281815181106121b0576121b0613e6a565b602002602001015160000151826000018181516121cd9190614640565b90525082518390829081106121e4576121e4613e6a565b6020026020010151602001518260200181815161220191906147ad565b905250600101612136565b6122146139e4565b8160008151811061222757612227613e6a565b60209081029190910101515181528151829060009061224857612248613e6a565b6020908102919091018101518101519082015260015b82518110156120d25761229083828151811061227c5761227c613e6a565b602090810291909101015151835190613264565b825282518390829081106122a6576122a6613e6a565b602002602001015160200151826020018181516122c391906147ad565b90525060010161225e565b6122d66139e4565b816000815181106122e9576122e9613e6a565b60209081029190910101515181528151829060009061230a5761230a613e6a565b6020908102919091018101518101519082015260015b82518110156120d25782818151811061233b5761233b613e6a565b6020026020010151600001516000036123605782818151811061217657612176613e6a565b61238983828151811061237557612375613e6a565b602090810291909101015151835190613283565b8252825183908290811061239f5761239f613e6a565b602002602001015160200151826020018181516123bc91906147ad565b905250600101612320565b6000826001826123d785426140a7565b90505b69ffffffffffffffffffff8716156124a3576001600160a01b038816639a6fc8f561240489614818565b6040516001600160e01b031960e084901b16815269ffffffffffffffffffff8216600482015290995060240160a060405180830381865afa925050508015612469575060408051601f3d908101601f1916820190925261246691810190614041565b60015b156124a357858210156124805750505050506124a3565b61248a848961456f565b97508661249681614834565b97505050505050506123da565b6124ac82612569565b6124b69084614640565b98975050505050505050565b60006124d261123683600a61484d565b6102b490846147e8565b60006124ec61123683600a61484d565b6102b49084614640565b6000667fffffffffffff66ffffffffffffff83161115612529576040516329d2678160e21b815260040160405180910390fd5b5090565b6000627fffff19600683900b128061254b5750627fffff600683900b135b1561252957604051630d962f7960e21b815260040160405180910390fd5b60006001600160ff1b038211156125295760405163677c430560e11b815260040160405180910390fd5b60008061259f86613298565b90506fffffffffffffffffffffffffffffffff6001600160a01b0382161161261c5760006125d66001600160a01b03831680614859565b9050836001600160a01b0316856001600160a01b03161061260557612600600160c01b87836136cd565b612614565b6126148187600160c01b6136cd565b92505061267d565b600061263b6001600160a01b03831680680100000000000000006136cd565b9050836001600160a01b0316856001600160a01b03161061266a57612665600160801b87836136cd565b612679565b6126798187600160801b6136cd565b9250505b50949350505050565b6000808212156125295760405163029f024d60e31b815260040160405180910390fd5b600080821215612529576126bc82614493565b610116565b6000805b8260400151518110156128415760006126fa846040015183815181106126ed576126ed613e6a565b6020026020010151610ab6565b60408051606081019091528154909190829060ff16600981111561272057612720613aa7565b600981111561273157612731613aa7565b815260200160018201805461274590613dc2565b80601f016020809104026020016040519081016040528092919081815260200182805461277190613dc2565b80156127be5780601f10612793576101008083540402835291602001916127be565b820191906000526020600020905b8154815290600101906020018083116127a157829003601f168201915b505050505081526020016002820180548060200260200160405190810160405280929190818152602001828054801561281657602002820191906000526020600020905b815481526020019060010190808311612802575b505050505081525050905061282a81611a8c565b612838575060009392505050565b506001016126c5565b50600192915050565b60006002826040015151101561286257506000919050565b81602001515160201461287757506000919050565b600082602001518060200190518101906128919190614627565b905060088111156128415750600092915050565b6000602082602001515110156128bd57506000919050565b600082602001518060200190518101906128d79190613ed3565b90506128ea816306e7ea3960e21b6138e2565b6128f75750600092915050565b604051633b70a5bf60e21b81526001600160a01b0382169063edc296fc90612923908690600401613b21565b6020604051808303816000875af1158015612942573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129669190614870565b6128415750600092915050565b6040810151516000901561298957506000919050565b81602001515160601461299e57506000919050565b60008083602001518060200190518101906129b99190613fe8565b92505091506000829050806001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015612a01573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a259190614041565b5050505050806001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612a68573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a8c919061488b565b60ff168260ff1614612aa357506000949350505050565b506001949350505050565b60408101515160009015612ac457506000919050565b81602001515160c014612ad957506000919050565b6000806000806000808760200151806020019051810190612afa91906140ba565b9550955095509550955095508360ff16866001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612b48573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b6c919061488b565b60ff1614612b8257506000979650505050505050565b8260ff16856001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612bc4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612be8919061488b565b60ff1614612bfe57506000979650505050505050565b6000826001600160a01b0316630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa158015612c3e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c629190613ed3565b90506000836001600160a01b031663d21220a76040518163ffffffff1660e01b8152600401602060405180830381865afa158015612ca4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cc89190613ed3565b9050876001600160a01b0316826001600160a01b0316148015612cfc5750866001600160a01b0316816001600160a01b0316145b158015612d385750866001600160a01b0316826001600160a01b0316148015612d365750876001600160a01b0316816001600160a01b0316145b155b15612d4d575060009998505050505050505050565b60128660ff161180612d62575060128560ff16115b15612d77575060009998505050505050505050565b8263ffffffff16600003612d95575060009998505050505050505050565b6040805160028082526060820183526000926020830190803683370190505090508381600081518110612dca57612dca613e6a565b602002602001019063ffffffff16908163ffffffff1681525050600081600181518110612df957612df9613e6a565b63ffffffff9092166020928302919091019091015260405163883bdbfd60e01b81526001600160a01b0386169063883bdbfd90612e3a908490600401614143565b600060405180830381865afa158015612e57573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612e7f91908101906141f5565b5060019c9b505050505050505050505050565b60408101515160009015612ea857506000919050565b816020015151606014612ebd57506000919050565b60008060008460200151806020019051810190612eda91906144bf565b919450925090508281612f55576040516396834ad360e01b8152600481018490526001600160a01b038216906396834ad390602401608060405180830381865afa158015612f2c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f5091906144f5565b612fbe565b604051639474f45b60e01b8152600481018490526001600160a01b03821690639474f45b90602401608060405180830381865afa158015612f9a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fbe91906144f5565b5060019695505050505050565b60408101515160009015612fe157506000919050565b816020015151606014612ff657506000919050565b8160200151806020019051810190612aa39190614597565b60008160400151516002148061302957508160400151516003145b61303557506000919050565b81602001515160201461304a57506000919050565b506001919050565b600081604001515160011480613029575081604001515160021461303557506000919050565b6040810151516000901561308e57506000919050565b6020826020015151101561304a57506000919050565b81818082036130b4575050505050565b6000856130da60026130c6888861446c565b6130d09190614640565b6112c0908861456f565b815181106130ea576130ea613e6a565b60200260200101516000015190505b818313613236575b808661310c85612686565b8151811061311c5761311c613e6a565b60200260200101516000015112156131405782613138816148a6565b935050613101565b8561314a83612686565b8151811061315a5761315a613e6a565b60200260200101516000015181121561317f5781613177816148be565b925050613140565b818313613231578561319083612686565b815181106131a0576131a0613e6a565b6020026020010151866131b285612686565b815181106131c2576131c2613e6a565b6020026020010151876131d486612686565b815181106131e4576131e4613e6a565b60200260200101886131f586612686565b8151811061320557613205613e6a565b602002602001018290528290525050828061321f906148a6565b935050818061322d906148be565b9250505b6130f9565b81851215613249576132498686846130a4565b8383121561325c5761325c8684866130a4565b505050505050565b6000670de0b6b3a764000061327983856147e8565b6102b49190614640565b600081613279670de0b6b3a7640000856147e8565b60008060008360020b126132b8576132b3600284900b612686565b6132c8565b6132c86112c0600285900b614493565b90506132e36112c06132dd620d89e7196148db565b60020b90565b8111156133165760405162461bcd60e51b81526020600482015260016024820152601560fa1b6044820152606401610397565b60008160011660000361332d57600160801b61333f565b6ffffcb933bd6fad37aa2d162d1a5940015b70ffffffffffffffffffffffffffffffffff169050600282161561337e576080613379826ffff97272373d413259a46990580e213a614859565b901c90505b60048216156133a85760806133a3826ffff2e50f5f656932ef12357cf3c7fdcc614859565b901c90505b60088216156133d25760806133cd826fffe5caca7e10e4e61c3624eaa0941cd0614859565b901c90505b60108216156133fc5760806133f7826fffcb9843d60f6159c9db58835c926644614859565b901c90505b6020821615613426576080613421826fff973b41fa98c081472e6896dfb254c0614859565b901c90505b604082161561345057608061344b826fff2ea16466c96a3843ec78b326b52861614859565b901c90505b608082161561347a576080613475826ffe5dee046a99a2a811c461f1969c3053614859565b901c90505b6101008216156134a55760806134a0826ffcbe86c7900a88aedcffc83b479aa3a4614859565b901c90505b6102008216156134d05760806134cb826ff987a7253ac413176f2b074cf7815e54614859565b901c90505b6104008216156134fb5760806134f6826ff3392b0822b70005940c7a398e4b70f3614859565b901c90505b610800821615613526576080613521826fe7159475a2c29b7443b29c7fa6e889d9614859565b901c90505b61100082161561355157608061354c826fd097f3bdfd2022b8845ad8f792aa5825614859565b901c90505b61200082161561357c576080613577826fa9f746462d870fdf8a65dc1f90e061e5614859565b901c90505b6140008216156135a75760806135a2826f70d869a156d2a1b890bb3df62baf32f7614859565b901c90505b6180008216156135d25760806135cd826f31be135f97d08fd981231505542fcfa6614859565b901c90505b620100008216156135fe5760806135f9826f09aa508b5b7a84e1c677de54f3e99bc9614859565b901c90505b62020000821615613629576080613624826e5d6af8dedb81196699c329225ee604614859565b901c90505b6204000082161561365357608061364e826d2216e584f5fa1ea926041bedfe98614859565b901c90505b6208000082161561367b576080613676826b048a170391f7dc42444e8fa2614859565b901c90505b60008460020b131561369657613693816000196147c0565b90505b6102ce6136a8640100000000836147d4565b156136b45760016136b7565b60005b6136c89060ff16602084901c6147ad565b6139ba565b6000808060001985870985870292508281108382030391505080600003613749576000841161373e5760405162461bcd60e51b815260206004820152601960248201527f48616e646c65206e6f6e2d6f766572666c6f77206361736573000000000000006044820152606401610397565b5082900490506102b4565b8084116137985760405162461bcd60e51b815260206004820152601960248201527f70726576656e74732064656e6f6d696e61746f72203d3d2030000000000000006044820152606401610397565b60008486880980840393811190920391905060006137d06137b887612569565b6137c188612569565b6137ca90614493565b16612686565b9586900495938490049360008190030460010190506137ef8184614859565b909317926000613800876003614859565b600218905061380f8188614859565b61381a9060026140a7565b6138249082614859565b90506138308188614859565b61383b9060026140a7565b6138459082614859565b90506138518188614859565b61385c9060026140a7565b6138669082614859565b90506138728188614859565b61387d9060026140a7565b6138879082614859565b90506138938188614859565b61389e9060026140a7565b6138a89082614859565b90506138b48188614859565b6138bf9060026140a7565b6138c99082614859565b90506138d58186614859565b9998505050505050505050565b604080516001600160e01b0319831660248083019190915282518083039091018152604490910182526020810180516001600160e01b03166301ffc9a760e01b1790529051600091829182916001600160a01b0387169161394391906148fd565b6000604051808303816000865af19150503d8060008114613980576040519150601f19603f3d011682016040523d82523d6000602084013e613985565b606091505b50915091508161399a57600092505050610116565b80516000036139ae57600092505050610116565b60200151949350505050565b60006001600160a01b038211156125295760405163dccde8ed60e01b815260040160405180910390fd5b6040518060800160405280600081526020016000815260200160008152602001600081525090565b828054828255906000526020600020908101928215613a47579160200282015b82811115613a47578251825591602001919060010190613a2c565b506125299291505b808211156125295760008155600101613a4f565b600060208284031215613a7557600080fd5b5035919050565b8151815260208083015190820152604080830151908201526060808301519082015260808101610116565b634e487b7160e01b600052602160045260246000fd5b600a8110613acd57613acd613aa7565b9052565b60005b83811015613aec578181015183820152602001613ad4565b50506000910152565b60008151808452613b0d816020860160208601613ad1565b601f01601f19169290920160200192915050565b60006020808352613b358184018551613abd565b8084015160606040850152613b4d6080850182613af5565b6040860151858203601f19016060870152805180835290840192506000918401905b80831015613b8f5783518252928401926001929092019190840190613b6f565b509695505050505050565b634e487b7160e01b600052604160045260246000fd5b6040516080810167ffffffffffffffff81118282101715613bd357613bd3613b9a565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715613c0257613c02613b9a565b604052919050565b600067ffffffffffffffff821115613c2457613c24613b9a565b5060051b60200190565b600082601f830112613c3f57600080fd5b81356020613c54613c4f83613c0a565b613bd9565b8083825260208201915060208460051b870101935086841115613c7657600080fd5b602086015b84811015613b8f5780358352918301918301613c7b565b600080600060608486031215613ca757600080fd5b8335600a8110613cb657600080fd5b925060208481013567ffffffffffffffff80821115613cd457600080fd5b818701915087601f830112613ce857600080fd5b813581811115613cfa57613cfa613b9a565b613d0c601f8201601f19168501613bd9565b8181528985838601011115613d2057600080fd5b818585018683013760009181019094015291935060408601359180831115613d4757600080fd5b5050613d5586828701613c2e565b9150509250925092565b600080600060608486031215613d7457600080fd5b83359250602084013567ffffffffffffffff80821115613d9357600080fd5b613d9f87838801613c2e565b93506040860135915080821115613db557600080fd5b50613d5586828701613c2e565b600181811c90821680613dd657607f821691505b602082108103611d0757634e487b7160e01b600052602260045260246000fd5b60008151808452602080850194506020840160005b83811015613e2757815187529582019590820190600101613e0b565b509495945050505050565b848152613e426020820185613abd565b608060408201526000613e586080830185613af5565b828103606084015261189a8185613df6565b634e487b7160e01b600052603260045260246000fd5b600060208284031215613e9257600080fd5b8151600981106102b457600080fd5b6020810160098310613eb557613eb5613aa7565b91905290565b6001600160a01b0381168114613ed057600080fd5b50565b600060208284031215613ee557600080fd5b81516102b481613ebb565b608080825285518282018190526000919060209060a0850190828a01855b82811015613f5257613f42848351805182526020810151602083015260408101516040830152606081015160608301525050565b9285019290840190600101613f0e565b5050508481036020860152613f678189613af5565b925050508281036040840152613f7d8186613df6565b9050828103606084015261189a8185613df6565b600060808284031215613fa357600080fd5b613fab613bb0565b825181526020830151602082015260408301516040820152606083015160608201528091505092915050565b805160ff8116811461200457600080fd5b600080600060608486031215613ffd57600080fd5b835161400881613ebb565b6020850151909350915061401e60408501613fd7565b90509250925092565b805169ffffffffffffffffffff8116811461200457600080fd5b600080600080600060a0868803121561405957600080fd5b61406286614027565b945060208601519350604086015192506060860151915061408560808701614027565b90509295509295909350565b634e487b7160e01b600052601160045260246000fd5b8181038181111561011657610116614091565b60008060008060008060c087890312156140d357600080fd5b86516140de81613ebb565b60208801519096506140ef81613ebb565b94506140fd60408801613fd7565b935061410b60608801613fd7565b9250608087015161411b81613ebb565b60a088015190925063ffffffff8116811461413557600080fd5b809150509295509295509295565b6020808252825182820181905260009190848201906040850190845b8181101561418157835163ffffffff168352928401929184019160010161415f565b50909695505050505050565b600082601f83011261419e57600080fd5b815160206141ae613c4f83613c0a565b8083825260208201915060208460051b8701019350868411156141d057600080fd5b602086015b84811015613b8f5780516141e881613ebb565b83529183019183016141d5565b6000806040838503121561420857600080fd5b825167ffffffffffffffff8082111561422057600080fd5b818501915085601f83011261423457600080fd5b81516020614244613c4f83613c0a565b82815260059290921b8401810191818101908984111561426357600080fd5b948201945b838610156142915785518060060b81146142825760008081fd5b82529482019490820190614268565b918801519196509093505050808211156142aa57600080fd5b506142b78582860161418d565b9150509250929050565b600682810b9082900b03667fffffffffffff198112667fffffffffffff8213171561011657610116614091565b634e487b7160e01b600052601260045260246000fd5b60008160060b8360060b8061431b5761431b6142ee565b667fffffffffffff1982146000198214161561433957614339614091565b90059392505050565b600082614351576143516142ee565b500790565b60008160020b627fffff19810361436f5761436f614091565b6000190192915050565b600181815b808511156143b457816000190482111561439a5761439a614091565b808516156143a757918102915b93841c939080029061437e565b509250929050565b6000826143cb57506001610116565b816143d857506000610116565b81600181146143ee57600281146143f857614414565b6001915050610116565b60ff84111561440957614409614091565b50506001821b610116565b5060208310610133831016604e8410600b8410161715614437575081810a610116565b6144418383614379565b806000190482111561445557614455614091565b029392505050565b60006102b460ff8416836143bc565b818103600083128015838313168383128216171561448c5761448c614091565b5092915050565b6000600160ff1b82016144a8576144a8614091565b5060000390565b8051801515811461200457600080fd5b6000806000606084860312156144d457600080fd5b83516144df81613ebb565b6020850151909350915061401e604085016144af565b60006080828403121561450757600080fd5b61450f613bb0565b82518060070b811461452057600080fd5b8152602083015167ffffffffffffffff8116811461453d57600080fd5b60208201526040830151600381900b811461455757600080fd5b60408201526060928301519281019290925250919050565b808201828112600083128015821682158216171561458f5761458f614091565b505092915050565b6000806000606084860312156145ac57600080fd5b83516145b781613ebb565b602085015160409095015190969495509392505050565b60ff8416815267ffffffffffffffff831660208201526060604082015260006145fa6060830184613df6565b95945050505050565b6001600160a01b03831681526040602082018190526000906102ce90830184613af5565b60006020828403121561463957600080fd5b5051919050565b60008261464f5761464f6142ee565b600160ff1b82146000198414161561466957614669614091565b500590565b6146788185613abd565b60606020820152600061468e6060830185613af5565b8281036040840152610f4f8185613df6565b601f8211156146e8576000816000526020600020601f850160051c810160208610156146c95750805b601f850160051c820191505b8181101561325c578281556001016146d5565b505050565b815167ffffffffffffffff81111561470757614707613b9a565b61471b816147158454613dc2565b846146a0565b602080601f83116001811461475057600084156147385750858301515b600019600386901b1c1916600185901b17855561325c565b600085815260208120601f198616915b8281101561477f57888601518255948401946001909101908401614760565b508582101561479d5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b8082018082111561011657610116614091565b6000826147cf576147cf6142ee565b500490565b6000826147e3576147e36142ee565b500690565b80820260008212600160ff1b8414161561480457614804614091565b818105831482151761011657610116614091565b600069ffffffffffffffffffff82168061436f5761436f614091565b60006001820161484657614846614091565b5060010190565b60006102b483836143bc565b808202811582820484141761011657610116614091565b60006020828403121561488257600080fd5b6102b4826144af565b60006020828403121561489d57600080fd5b6102b482613fd7565b60006001600160ff1b01820161484657614846614091565b6000600160ff1b82016148d3576148d3614091565b506000190190565b60008160020b627fffff1981036148f4576148f4614091565b60000392915050565b6000825161490f818460208701613ad1565b919091019291505056fea264697066735822122074f32fef384fdc296b0859f1c1f941c8e736c6cb972aa9e2b894956ebd6a80b364736f6c63430008160033\",\"storage\":{}},\"0x83a0444b93927c3afcbe46e522280390f748e171\":{\"nonce\":1,\"balance\":\"0x0\",\"code\":\"0x6080604052366100135761001161001d565b005b61001b61001d565b005b6000610027610093565b90503660008037600080366000845af43d6000803e806000811461004a573d6000f35b3d6000fd5b600080823b905060008111915050919050565b6000806040516020016100749061017a565b6040516020818303038152906040528051906020012090508091505090565b600061009d6100c6565b60000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b6000806040516020016100d89061020c565b6040516020818303038152906040528051906020012090508091505090565b600082825260208201905092915050565b7f696f2e73796e7468657469782e636f72652d636f6e7472616374732e4f776e6160008201527f626c650000000000000000000000000000000000000000000000000000000000602082015250565b60006101646023836100f7565b915061016f82610108565b604082019050919050565b6000602082019050818103600083015261019381610157565b9050919050565b7f696f2e73796e7468657469782e636f72652d636f6e7472616374732e50726f7860008201527f7900000000000000000000000000000000000000000000000000000000000000602082015250565b60006101f66021836100f7565b91506102018261019a565b604082019050919050565b60006020820190508181036000830152610225816101e9565b905091905056fea2646970667358221220800da1f73cebd5e4afa07496d9bca6b6c4f526bdd3f4014ec15c70fe3a1c441364736f6c63430008110033\",\"storage\":{\"0x5a648c35a2f5512218b4683cf10e03f5b7c9dc7346e1bf77d304ae97f60f592b\":\"0x108f53faf774d7c4c56f5bce9ca6e605ce8aeadd\",\"0x5c7865864a2a990d80b5bb5c40e7b73a029960dc711fbb56120dfab976e92ea3\":\"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266\"}},\"0x90f79bf6eb2c4f870365e785982e1f101e93b906\":{\"nonce\":0,\"balance\":\"0x21e19e0c9bab2400000\",\"code\":\"0x\",\"storage\":{}},\"0x976ea74026e726554db657fa54763abd0c3a0aa9\":{\"nonce\":0,\"balance\":\"0x21e19e0c9bab2400000\",\"code\":\"0x\",\"storage\":{}},\"0x9965507d1a55bcc2695c58ba16fb37d819b0a4dc\":{\"nonce\":0,\"balance\":\"0x21e19e0c9bab2400000\",\"code\":\"0x\",\"storage\":{}},\"0xa0ee7a142d267c1f36714e4a8f75612f20a79720\":{\"nonce\":0,\"balance\":\"0x21e19e0c9bab2400000\",\"code\":\"0x\",\"storage\":{}},\"0xc67e2bd3108604cf0168c0e5ef9cd6d78b9bb14b\":{\"nonce\":1,\"balance\":\"0x21e19c6edb7e2445f20\",\"code\":\"0x\",\"storage\":{}},\"0xeb045d78d273107348b0300c01d29b7552d622ab\":{\"nonce\":0,\"balance\":\"0x21e19e0c9bab2400000\",\"code\":\"0x\",\"storage\":{}},\"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266\":{\"nonce\":1,\"balance\":\"0x21e19e08b86820a43ea\",\"code\":\"0x\",\"storage\":{}}},\"best_block_number\":5,\"blocks\":[{\"header\":{\"parentHash\":\"0x08abe6e453727534d8dd708843a7522b7d500338bdfe2402ca105dcdb05eebe9\",\"sha3Uncles\":\"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347\",\"miner\":\"0x0000000000000000000000000000000000000000\",\"stateRoot\":\"0xcd346446ed010523161f40a5f2b512def549bfb79e165b4354488738416481f2\",\"transactionsRoot\":\"0xb3a4689832e0b599260ae70362ffcf224b60571b35ff8836904a3d81e2675d66\",\"receiptsRoot\":\"0x2d13fdc120ab90536fed583939de7fb68b64926a306c1f629593ca9c2c93b198\",\"logsBloom\":\"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\"difficulty\":\"0x0\",\"number\":\"0x1\",\"gasLimit\":\"0x1c9c380\",\"gasUsed\":\"0x3ea90d\",\"timestamp\":\"0x66b200ca\",\"mixHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"nonce\":\"0x0000000000000000\",\"baseFeePerGas\":\"0x2e0b6260\",\"blobGasUsed\":\"0x0\",\"excessBlobGas\":\"0x0\",\"extraData\":\"0x\"},\"transactions\":[{\"chainId\":\"0x343a\",\"nonce\":\"0x0\",\"gas\":\"0x3ea90d\",\"maxFeePerGas\":\"0x83215600\",\"maxPriorityFeePerGas\":\"0x3b9aca00\",\"value\":\"0x0\",\"accessList\":[],\"input\":\"0x608060405234801561001057600080fd5b5061494f806100206000396000f3fe608060405234801561001057600080fd5b50600436106100575760003560e01c80632a952b2d1461005c57806350c946fe14610085578063625ca21c146100a5578063daa250be146100c6578063deba1b98146100d9575b600080fd5b61006f61006a366004613a63565b6100ec565b60405161007c9190613a7c565b60405180910390f35b610098610093366004613a63565b61011c565b60405161007c9190613b21565b6100b86100b3366004613c92565b610276565b60405190815260200161007c565b61006f6100d4366004613d5f565b6102bb565b6100b86100e7366004613c92565b6102d6565b6100f46139e4565b6040805160008082526020820190815281830190925261011691849190610310565b92915050565b6101416040805160608101909152806000815260200160608152602001606081525090565b61014a82610ab6565b60408051606081019091528154909190829060ff16600981111561017057610170613aa7565b600981111561018157610181613aa7565b815260200160018201805461019590613dc2565b80601f01602080910402602001604051908101604052809291908181526020018280546101c190613dc2565b801561020e5780601f106101e35761010080835404028352916020019161020e565b820191906000526020600020905b8154815290600101906020018083116101f157829003601f168201915b505050505081526020016002820180548060200260200160405190810160405280929190818152602001828054801561026657602002820191906000526020600020905b815481526020019060010190808311610252575b5050505050815250509050919050565b600080604051806060016040528086600981111561029657610296613aa7565b81526020018581526020018481525090506102b081610ac1565b9150505b9392505050565b6102c36139e4565b6102ce848484610310565b949350505050565b60008060405180606001604052808660098111156102f6576102f6613aa7565b81526020018581526020018481525090506102b081610acc565b6103186139e4565b81518351146103a05760408051634bab873760e11b81526004810191909152600d60448201526c72756e74696d6556616c75657360981b606482015260806024820152602260848201527f6d7573742062652073616d65206c656e6774682061732072756e74696d654b6560a482015261797360f01b60c482015260e4015b60405180910390fd5b60006103ab85610c26565b805490915060ff1660018160098111156103c7576103c7613aa7565b036104755761046c6103da838787610c84565b8360010180546103e990613dc2565b80601f016020809104026020016040519081016040528092919081815260200182805461041590613dc2565b80156104625780601f1061043757610100808354040283529160200191610462565b820191906000526020600020905b81548152906001019060200180831161044557829003601f168201915b5050505050610d46565b925050506102b4565b600281600981111561048957610489613aa7565b036105305761046c61049c838787610c84565b8360010180546104ab90613dc2565b80601f01602080910402602001604051908101604052809291908181526020018280546104d790613dc2565b80156105245780601f106104f957610100808354040283529160200191610524565b820191906000526020600020905b81548152906001019060200180831161050757829003601f168201915b50505050508787610ebb565b600381600981111561054457610544613aa7565b036105de5761046c82600101805461055b90613dc2565b80601f016020809104026020016040519081016040528092919081815260200182805461058790613dc2565b80156105d45780601f106105a9576101008083540402835291602001916105d4565b820191906000526020600020905b8154815290600101906020018083116105b757829003601f168201915b5050505050610f59565b60048160098111156105f2576105f2613aa7565b0361068c5761046c82600101805461060990613dc2565b80601f016020809104026020016040519081016040528092919081815260200182805461063590613dc2565b80156106825780601f1061065757610100808354040283529160200191610682565b820191906000526020600020905b81548152906001019060200180831161066557829003601f168201915b5050505050611087565b60058160098111156106a0576106a0613aa7565b0361073a5761046c8260010180546106b790613dc2565b80601f01602080910402602001604051908101604052809291908181526020018280546106e390613dc2565b80156107305780601f1061070557610100808354040283529160200191610730565b820191906000526020600020905b81548152906001019060200180831161071357829003601f168201915b505050505061131e565b600981600981111561074e5761074e613aa7565b036107ea5761046c82600101805461076590613dc2565b80601f016020809104026020016040519081016040528092919081815260200182805461079190613dc2565b80156107de5780601f106107b3576101008083540402835291602001916107de565b820191906000526020600020905b8154815290600101906020018083116107c157829003601f168201915b505050505086866114b5565b60068160098111156107fe576107fe613aa7565b036108a35761046c610811838787610c84565b83600101805461082090613dc2565b80601f016020809104026020016040519081016040528092919081815260200182805461084c90613dc2565b80156108995780601f1061086e57610100808354040283529160200191610899565b820191906000526020600020905b81548152906001019060200180831161087c57829003601f168201915b50505050506115c7565b60078160098111156108b7576108b7613aa7565b036109ec576040805160608101909152825461046c91908490829060ff1660098111156108e6576108e6613aa7565b60098111156108f7576108f7613aa7565b815260200160018201805461090b90613dc2565b80601f016020809104026020016040519081016040528092919081815260200182805461093790613dc2565b80156109845780601f1061095957610100808354040283529160200191610984565b820191906000526020600020905b81548152906001019060200180831161096757829003601f168201915b50505050508152602001600282018054806020026020016040519081016040528092919081815260200182805480156109dc57602002820191906000526020600020905b8154815260200190600101908083116109c8575b5050505050815250508686611728565b6008816009811115610a0057610a00613aa7565b03610a9a5761046c826001018054610a1790613dc2565b80601f0160208091040260200160405190810160405280929190818152602001828054610a4390613dc2565b8015610a905780601f10610a6557610100808354040283529160200191610a90565b820191906000526020600020905b815481529060010190602001808311610a7357829003601f168201915b50505050506118a5565b6040516323a9bbc960e01b815260048101879052602401610397565b600061011682610c26565b6000610116826118ea565b6000610ad782610ac1565b9050610ae28161192a565b15610b35577fcb64985827770858ec421ad26da7e558c757541643036ce44d6b4eb9e8e5dc5e81836000015184602001518560400151604051610b289493929190613e32565b60405180910390a1919050565b610b3e82611a8c565b610b5d578160405163382bbbc960e11b81526004016103979190613b21565b60005b826040015151811015610bd957610b9383604001518281518110610b8657610b86613e6a565b602002602001015161192a565b610bd15782604001518181518110610bad57610bad613e6a565b6020026020010151604051632f19f96160e11b815260040161039791815260200190565b600101610b60565b50610be382611c31565b8351602085015160408087015190519395507fcb64985827770858ec421ad26da7e558c757541643036ce44d6b4eb9e8e5dc5e9450610b28938693929190613e32565b604080516020808201839052606082018190527f696f2e73796e7468657469782e6f7261636c652d6d616e616765722e4e6f6465608080840191909152828401949094528251808303909401845260a0909101909152815191012090565b600283015460609067ffffffffffffffff811115610ca457610ca4613b9a565b604051908082528060200260200182016040528015610cdd57816020015b610cca6139e4565b815260200190600190039081610cc25790505b50905060005b6002850154811015610d3e57610d19856002018281548110610d0757610d07613e6a565b90600052602060002001548585610310565b828281518110610d2b57610d2b613e6a565b6020908102919091010152600101610ce3565b509392505050565b610d4e6139e4565b600082806020019051810190610d649190613e80565b90506000816008811115610d7a57610d7a613aa7565b03610d9057610d8884611ca5565b915050610116565b6001816008811115610da457610da4613aa7565b03610db257610d8884611d0d565b6002816008811115610dc657610dc6613aa7565b03610dd457610d8884611d90565b6003816008811115610de857610de8613aa7565b03610df657610d8884611e13565b6004816008811115610e0a57610e0a613aa7565b03610e1857610d8884611ec9565b6005816008811115610e2c57610e2c613aa7565b03610e3a57610d8884612009565b6006816008811115610e4e57610e4e613aa7565b03610e5c57610d88846120e4565b6007816008811115610e7057610e70613aa7565b03610e7e57610d888461220c565b6008816008811115610e9257610e92613aa7565b03610ea057610d88846122ce565b80604051631be413d360e11b81526004016103979190613ea1565b610ec36139e4565b600084806020019051810190610ed99190613ed3565b604051631ecba7c360e31b81529091506001600160a01b0382169063f65d3e1890610f0e908990899089908990600401613ef0565b608060405180830381865afa158015610f2b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f4f9190613f91565b9695505050505050565b610f616139e4565b600080600084806020019051810190610f7a9190613fe8565b92509250925060008390506000806000836001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015610fc8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fec9190614041565b509350509250925060008660001461100f5761100a8585858a6123c7565b611011565b825b905060128660ff161161103b5761103661102f60ff881660126140a7565b82906124c2565b611053565b61105361104c601260ff89166140a7565b82906124dc565b9050604051806080016040528082815260200183815260200160008152602001600081525098505050505050505050919050565b61108f6139e4565b600080600080600080878060200190518101906110ac91906140ba565b604080516002808252606082018352979d50959b50939950919750955093506000929060208301908036833701905050905081816000815181106110f2576110f2613e6a565b602002602001019063ffffffff16908163ffffffff168152505060008160018151811061112157611121613e6a565b63ffffffff9092166020928302919091019091015260405163883bdbfd60e01b81526000906001600160a01b0385169063883bdbfd90611165908590600401614143565b600060405180830381865afa158015611182573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526111aa91908101906141f5565b5090506000816000815181106111c2576111c2613e6a565b6020026020010151826001815181106111dd576111dd613e6a565b60200260200101516111ef91906142c1565b9050600061121761120563ffffffff87166124f6565b61120f9084614304565b60060b61252d565b905060008260060b12801561124c575061123b63ffffffff8616612569565b612569565b8260060b6112499190614342565b15155b1561125f578061125b81614356565b9150505b600061126d6012600a61445d565b9050600061128061123684848f8f612593565b905060006112908a60ff16612569565b61129c8c60ff16612569565b6112a6919061446c565b905060008082136112d1576112cc6112c56112c084614493565b612686565b84906124dc565b6112e4565b6112e46112dd83612686565b84906124c2565b905060405180608001604052808281526020014281526020016000815260200160008152509e505050505050505050505050505050919050565b6113266139e4565b60008060008480602001905181019061133f91906144bf565b91945092509050826000826113bc576040516396834ad360e01b8152600481018590526001600160a01b038316906396834ad390602401608060405180830381865afa158015611393573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113b791906144f5565b611425565b604051639474f45b60e01b8152600481018590526001600160a01b03831690639474f45b90602401608060405180830381865afa158015611401573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061142591906144f5565b90506000816040015160030b601261143d919061456f565b90506000808213611467576114626114576112c084614493565b845160070b906124dc565b61147e565b61147e61147383612686565b845160070b906124c2565b9050604051806080016040528082815260200184606001518152602001600081526020016000815250975050505050505050919050565b6114bd6139e4565b6000806000868060200190518101906114d69190614597565b92509250925060005b8651811015611545578681815181106114fa576114fa613e6a565b6020026020010151717374616c656e657373546f6c6572616e636560701b0361153d5785818151811061152f5761152f613e6a565b602002602001015160001c91505b6001016114df565b5060408051600180825281830190925260009160208083019080368337019050509050828160008151811061157c5761157c613e6a565b602002602001018181525050836001838360405160200161159f939291906145ce565b60408051601f198184030181529082905263cf2cabdf60e01b82526103979291600401614603565b6115cf6139e4565b6000828060200190518101906115e59190614627565b90506000846000815181106115fc576115fc613e6a565b602002602001015160000151905060008560018151811061161f5761161f613e6a565b6020026020010151600001519050808214611702576000611653601261164d611648858761446c565b6126a9565b906124c2565b905082158061167b5750611666836126a9565b6116709082614640565b61167985612569565b125b15611700576002875111156116b0578660028151811061169d5761169d613e6a565b6020026020010151945050505050610116565b826000036116d15760405163014cc07160e01b815260040160405180910390fd5b6116da836126a9565b6116e49082614640565b60405163dcac091960e01b815260040161039791815260200190565b505b8560008151811061171557611715613e6a565b6020026020010151935050505092915050565b6117306139e4565b6000846020015180602001905181019061174a9190614627565b905060005b84518110156117bc5784818151811061176a5761176a613e6a565b6020026020010151717374616c656e657373546f6c6572616e636560701b036117b4576117ad8482815181106117a2576117a2613e6a565b602002602001015190565b91506117bc565b60010161174f565b50600085604001516000815181106117d6576117d6613e6a565b6020026020010151905060006117ed828787610310565b60208101519091506117ff84426140a7565b1161180e5792506102b4915050565b86604001515160010361187157866040015160008151811061183257611832613e6a565b602002602001015181600001518260200151604051631808066560e21b8152600401610397939291909283526020830191909152604082015260600190565b61189a876040015160018151811061188b5761188b613e6a565b60200260200101518787610310565b979650505050505050565b6118ad6139e4565b6040518060800160405280838060200190518101906118cc9190614627565b81526020014281526020016000815260200160008152509050919050565b600081600001518260200151836040015160405160200161190d9392919061466e565b604051602081830303815290604052805190602001209050919050565b60008061193683610c26565b60408051606081019091528154909190829060ff16600981111561195c5761195c613aa7565b600981111561196d5761196d613aa7565b815260200160018201805461198190613dc2565b80601f01602080910402602001604051908101604052809291908181526020018280546119ad90613dc2565b80156119fa5780601f106119cf576101008083540402835291602001916119fa565b820191906000526020600020905b8154815290600101906020018083116119dd57829003601f168201915b5050505050815260200160028201805480602002602001604051908101604052809291908181526020018280548015611a5257602002820191906000526020600020905b815481526020019060010190808311611a3e575b505050505081525050905060006009811115611a7057611a70613aa7565b81516009811115611a8357611a83613aa7565b14159392505050565b6000600182516009811115611aa357611aa3613aa7565b1480611ac15750600682516009811115611abf57611abf613aa7565b145b80611ade5750600782516009811115611adc57611adc613aa7565b145b15611aee57611aec826126c1565b505b600182516009811115611b0357611b03613aa7565b03611b11576101168261284a565b600282516009811115611b2657611b26613aa7565b03611b3457610116826128a5565b600382516009811115611b4957611b49613aa7565b03611b575761011682612973565b600482516009811115611b6c57611b6c613aa7565b03611b7a5761011682612aae565b600582516009811115611b8f57611b8f613aa7565b03611b9d5761011682612e92565b600982516009811115611bb257611bb2613aa7565b03611bc05761011682612fcb565b600682516009811115611bd557611bd5613aa7565b03611be3576101168261300e565b600782516009811115611bf857611bf8613aa7565b03611c065761011682613052565b600882516009811115611c1b57611c1b613aa7565b03611c295761011682613078565b506000919050565b600080611c3d836118ea565b9050611c4881610c26565b8351815491935090839060ff19166001836009811115611c6a57611c6a613aa7565b021790555060208301516001830190611c8390826146ed565b5060408301518051611c9f916002850191602090910190613a0c565b50915091565b611cad6139e4565b60005b8251811015611d07578160200151838281518110611cd057611cd0613e6a565b6020026020010151602001511115611cff57828181518110611cf457611cf4613e6a565b602002602001015191505b600101611cb0565b50919050565b611d156139e4565b81600081518110611d2857611d28613e6a565b602002602001015190506000600190505b8251811015611d07578160000151838281518110611d5957611d59613e6a565b6020026020010151600001511215611d8857828181518110611d7d57611d7d613e6a565b602002602001015191505b600101611d39565b611d986139e4565b81600081518110611dab57611dab613e6a565b602002602001015190506000600190505b8251811015611d07578160000151838281518110611ddc57611ddc613e6a565b6020026020010151600001511315611e0b57828181518110611e0057611e00613e6a565b602002602001015191505b600101611dbc565b611e1b6139e4565b60005b8251811015611e9557828181518110611e3957611e39613e6a565b60200260200101516000015182600001818151611e56919061456f565b9052508251839082908110611e6d57611e6d613e6a565b60200260200101516020015182602001818151611e8a91906147ad565b905250600101611e1e565b50611ea08251612569565b8151611eac9190614640565b815281516020820151611ebf91906147c0565b6020820152919050565b611ed16139e4565b611eed826000611ee86001865161123691906140a7565b6130a4565b60028251611efb91906147d4565b600003611fd65760408051600280825260608201909252600091816020015b611f226139e4565b815260200190600190039081611f1a57905050905082600160028551611f4891906147c0565b611f5291906140a7565b81518110611f6257611f62613e6a565b602002602001015181600081518110611f7d57611f7d613e6a565b60200260200101819052508260028451611f9791906147c0565b81518110611fa757611fa7613e6a565b602002602001015181600181518110611fc257611fc2613e6a565b60200260200101819052506102b481611e13565b8160028351611fe591906147c0565b81518110611ff557611ff5613e6a565b60200260200101519050919050565b919050565b6120116139e4565b8160008151811061202457612024613e6a565b60209081029190910101515181528151829060009061204557612045613e6a565b6020908102919091018101518101519082015260015b82518110156120d25782818151811061207657612076613e6a565b6020026020010151600001518260000181815161209391906147e8565b90525082518390829081106120aa576120aa613e6a565b602002602001015160200151826020018181516120c791906147ad565b90525060010161205b565b5081518160200151611ebf91906147c0565b6120ec6139e4565b816000815181106120ff576120ff613e6a565b60209081029190910101515181528151829060009061212057612120613e6a565b6020908102919091018101518101519082015260015b82518110156120d25782818151811061215157612151613e6a565b60200260200101516000015160000361219e5782818151811061217657612176613e6a565b6020026020010151600001516040516338ee04a760e01b815260040161039791815260200190565b8281815181106121b0576121b0613e6a565b602002602001015160000151826000018181516121cd9190614640565b90525082518390829081106121e4576121e4613e6a565b6020026020010151602001518260200181815161220191906147ad565b905250600101612136565b6122146139e4565b8160008151811061222757612227613e6a565b60209081029190910101515181528151829060009061224857612248613e6a565b6020908102919091018101518101519082015260015b82518110156120d25761229083828151811061227c5761227c613e6a565b602090810291909101015151835190613264565b825282518390829081106122a6576122a6613e6a565b602002602001015160200151826020018181516122c391906147ad565b90525060010161225e565b6122d66139e4565b816000815181106122e9576122e9613e6a565b60209081029190910101515181528151829060009061230a5761230a613e6a565b6020908102919091018101518101519082015260015b82518110156120d25782818151811061233b5761233b613e6a565b6020026020010151600001516000036123605782818151811061217657612176613e6a565b61238983828151811061237557612375613e6a565b602090810291909101015151835190613283565b8252825183908290811061239f5761239f613e6a565b602002602001015160200151826020018181516123bc91906147ad565b905250600101612320565b6000826001826123d785426140a7565b90505b69ffffffffffffffffffff8716156124a3576001600160a01b038816639a6fc8f561240489614818565b6040516001600160e01b031960e084901b16815269ffffffffffffffffffff8216600482015290995060240160a060405180830381865afa925050508015612469575060408051601f3d908101601f1916820190925261246691810190614041565b60015b156124a357858210156124805750505050506124a3565b61248a848961456f565b97508661249681614834565b97505050505050506123da565b6124ac82612569565b6124b69084614640565b98975050505050505050565b60006124d261123683600a61484d565b6102b490846147e8565b60006124ec61123683600a61484d565b6102b49084614640565b6000667fffffffffffff66ffffffffffffff83161115612529576040516329d2678160e21b815260040160405180910390fd5b5090565b6000627fffff19600683900b128061254b5750627fffff600683900b135b1561252957604051630d962f7960e21b815260040160405180910390fd5b60006001600160ff1b038211156125295760405163677c430560e11b815260040160405180910390fd5b60008061259f86613298565b90506fffffffffffffffffffffffffffffffff6001600160a01b0382161161261c5760006125d66001600160a01b03831680614859565b9050836001600160a01b0316856001600160a01b03161061260557612600600160c01b87836136cd565b612614565b6126148187600160c01b6136cd565b92505061267d565b600061263b6001600160a01b03831680680100000000000000006136cd565b9050836001600160a01b0316856001600160a01b03161061266a57612665600160801b87836136cd565b612679565b6126798187600160801b6136cd565b9250505b50949350505050565b6000808212156125295760405163029f024d60e31b815260040160405180910390fd5b600080821215612529576126bc82614493565b610116565b6000805b8260400151518110156128415760006126fa846040015183815181106126ed576126ed613e6a565b6020026020010151610ab6565b60408051606081019091528154909190829060ff16600981111561272057612720613aa7565b600981111561273157612731613aa7565b815260200160018201805461274590613dc2565b80601f016020809104026020016040519081016040528092919081815260200182805461277190613dc2565b80156127be5780601f10612793576101008083540402835291602001916127be565b820191906000526020600020905b8154815290600101906020018083116127a157829003601f168201915b505050505081526020016002820180548060200260200160405190810160405280929190818152602001828054801561281657602002820191906000526020600020905b815481526020019060010190808311612802575b505050505081525050905061282a81611a8c565b612838575060009392505050565b506001016126c5565b50600192915050565b60006002826040015151101561286257506000919050565b81602001515160201461287757506000919050565b600082602001518060200190518101906128919190614627565b905060088111156128415750600092915050565b6000602082602001515110156128bd57506000919050565b600082602001518060200190518101906128d79190613ed3565b90506128ea816306e7ea3960e21b6138e2565b6128f75750600092915050565b604051633b70a5bf60e21b81526001600160a01b0382169063edc296fc90612923908690600401613b21565b6020604051808303816000875af1158015612942573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129669190614870565b6128415750600092915050565b6040810151516000901561298957506000919050565b81602001515160601461299e57506000919050565b60008083602001518060200190518101906129b99190613fe8565b92505091506000829050806001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015612a01573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a259190614041565b5050505050806001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612a68573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a8c919061488b565b60ff168260ff1614612aa357506000949350505050565b506001949350505050565b60408101515160009015612ac457506000919050565b81602001515160c014612ad957506000919050565b6000806000806000808760200151806020019051810190612afa91906140ba565b9550955095509550955095508360ff16866001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612b48573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b6c919061488b565b60ff1614612b8257506000979650505050505050565b8260ff16856001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612bc4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612be8919061488b565b60ff1614612bfe57506000979650505050505050565b6000826001600160a01b0316630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa158015612c3e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c629190613ed3565b90506000836001600160a01b031663d21220a76040518163ffffffff1660e01b8152600401602060405180830381865afa158015612ca4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cc89190613ed3565b9050876001600160a01b0316826001600160a01b0316148015612cfc5750866001600160a01b0316816001600160a01b0316145b158015612d385750866001600160a01b0316826001600160a01b0316148015612d365750876001600160a01b0316816001600160a01b0316145b155b15612d4d575060009998505050505050505050565b60128660ff161180612d62575060128560ff16115b15612d77575060009998505050505050505050565b8263ffffffff16600003612d95575060009998505050505050505050565b6040805160028082526060820183526000926020830190803683370190505090508381600081518110612dca57612dca613e6a565b602002602001019063ffffffff16908163ffffffff1681525050600081600181518110612df957612df9613e6a565b63ffffffff9092166020928302919091019091015260405163883bdbfd60e01b81526001600160a01b0386169063883bdbfd90612e3a908490600401614143565b600060405180830381865afa158015612e57573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612e7f91908101906141f5565b5060019c9b505050505050505050505050565b60408101515160009015612ea857506000919050565b816020015151606014612ebd57506000919050565b60008060008460200151806020019051810190612eda91906144bf565b919450925090508281612f55576040516396834ad360e01b8152600481018490526001600160a01b038216906396834ad390602401608060405180830381865afa158015612f2c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f5091906144f5565b612fbe565b604051639474f45b60e01b8152600481018490526001600160a01b03821690639474f45b90602401608060405180830381865afa158015612f9a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fbe91906144f5565b5060019695505050505050565b60408101515160009015612fe157506000919050565b816020015151606014612ff657506000919050565b8160200151806020019051810190612aa39190614597565b60008160400151516002148061302957508160400151516003145b61303557506000919050565b81602001515160201461304a57506000919050565b506001919050565b600081604001515160011480613029575081604001515160021461303557506000919050565b6040810151516000901561308e57506000919050565b6020826020015151101561304a57506000919050565b81818082036130b4575050505050565b6000856130da60026130c6888861446c565b6130d09190614640565b6112c0908861456f565b815181106130ea576130ea613e6a565b60200260200101516000015190505b818313613236575b808661310c85612686565b8151811061311c5761311c613e6a565b60200260200101516000015112156131405782613138816148a6565b935050613101565b8561314a83612686565b8151811061315a5761315a613e6a565b60200260200101516000015181121561317f5781613177816148be565b925050613140565b818313613231578561319083612686565b815181106131a0576131a0613e6a565b6020026020010151866131b285612686565b815181106131c2576131c2613e6a565b6020026020010151876131d486612686565b815181106131e4576131e4613e6a565b60200260200101886131f586612686565b8151811061320557613205613e6a565b602002602001018290528290525050828061321f906148a6565b935050818061322d906148be565b9250505b6130f9565b81851215613249576132498686846130a4565b8383121561325c5761325c8684866130a4565b505050505050565b6000670de0b6b3a764000061327983856147e8565b6102b49190614640565b600081613279670de0b6b3a7640000856147e8565b60008060008360020b126132b8576132b3600284900b612686565b6132c8565b6132c86112c0600285900b614493565b90506132e36112c06132dd620d89e7196148db565b60020b90565b8111156133165760405162461bcd60e51b81526020600482015260016024820152601560fa1b6044820152606401610397565b60008160011660000361332d57600160801b61333f565b6ffffcb933bd6fad37aa2d162d1a5940015b70ffffffffffffffffffffffffffffffffff169050600282161561337e576080613379826ffff97272373d413259a46990580e213a614859565b901c90505b60048216156133a85760806133a3826ffff2e50f5f656932ef12357cf3c7fdcc614859565b901c90505b60088216156133d25760806133cd826fffe5caca7e10e4e61c3624eaa0941cd0614859565b901c90505b60108216156133fc5760806133f7826fffcb9843d60f6159c9db58835c926644614859565b901c90505b6020821615613426576080613421826fff973b41fa98c081472e6896dfb254c0614859565b901c90505b604082161561345057608061344b826fff2ea16466c96a3843ec78b326b52861614859565b901c90505b608082161561347a576080613475826ffe5dee046a99a2a811c461f1969c3053614859565b901c90505b6101008216156134a55760806134a0826ffcbe86c7900a88aedcffc83b479aa3a4614859565b901c90505b6102008216156134d05760806134cb826ff987a7253ac413176f2b074cf7815e54614859565b901c90505b6104008216156134fb5760806134f6826ff3392b0822b70005940c7a398e4b70f3614859565b901c90505b610800821615613526576080613521826fe7159475a2c29b7443b29c7fa6e889d9614859565b901c90505b61100082161561355157608061354c826fd097f3bdfd2022b8845ad8f792aa5825614859565b901c90505b61200082161561357c576080613577826fa9f746462d870fdf8a65dc1f90e061e5614859565b901c90505b6140008216156135a75760806135a2826f70d869a156d2a1b890bb3df62baf32f7614859565b901c90505b6180008216156135d25760806135cd826f31be135f97d08fd981231505542fcfa6614859565b901c90505b620100008216156135fe5760806135f9826f09aa508b5b7a84e1c677de54f3e99bc9614859565b901c90505b62020000821615613629576080613624826e5d6af8dedb81196699c329225ee604614859565b901c90505b6204000082161561365357608061364e826d2216e584f5fa1ea926041bedfe98614859565b901c90505b6208000082161561367b576080613676826b048a170391f7dc42444e8fa2614859565b901c90505b60008460020b131561369657613693816000196147c0565b90505b6102ce6136a8640100000000836147d4565b156136b45760016136b7565b60005b6136c89060ff16602084901c6147ad565b6139ba565b6000808060001985870985870292508281108382030391505080600003613749576000841161373e5760405162461bcd60e51b815260206004820152601960248201527f48616e646c65206e6f6e2d6f766572666c6f77206361736573000000000000006044820152606401610397565b5082900490506102b4565b8084116137985760405162461bcd60e51b815260206004820152601960248201527f70726576656e74732064656e6f6d696e61746f72203d3d2030000000000000006044820152606401610397565b60008486880980840393811190920391905060006137d06137b887612569565b6137c188612569565b6137ca90614493565b16612686565b9586900495938490049360008190030460010190506137ef8184614859565b909317926000613800876003614859565b600218905061380f8188614859565b61381a9060026140a7565b6138249082614859565b90506138308188614859565b61383b9060026140a7565b6138459082614859565b90506138518188614859565b61385c9060026140a7565b6138669082614859565b90506138728188614859565b61387d9060026140a7565b6138879082614859565b90506138938188614859565b61389e9060026140a7565b6138a89082614859565b90506138b48188614859565b6138bf9060026140a7565b6138c99082614859565b90506138d58186614859565b9998505050505050505050565b604080516001600160e01b0319831660248083019190915282518083039091018152604490910182526020810180516001600160e01b03166301ffc9a760e01b1790529051600091829182916001600160a01b0387169161394391906148fd565b6000604051808303816000865af19150503d8060008114613980576040519150601f19603f3d011682016040523d82523d6000602084013e613985565b606091505b50915091508161399a57600092505050610116565b80516000036139ae57600092505050610116565b60200151949350505050565b60006001600160a01b038211156125295760405163dccde8ed60e01b815260040160405180910390fd5b6040518060800160405280600081526020016000815260200160008152602001600081525090565b828054828255906000526020600020908101928215613a47579160200282015b82811115613a47578251825591602001919060010190613a2c565b506125299291505b808211156125295760008155600101613a4f565b600060208284031215613a7557600080fd5b5035919050565b8151815260208083015190820152604080830151908201526060808301519082015260808101610116565b634e487b7160e01b600052602160045260246000fd5b600a8110613acd57613acd613aa7565b9052565b60005b83811015613aec578181015183820152602001613ad4565b50506000910152565b60008151808452613b0d816020860160208601613ad1565b601f01601f19169290920160200192915050565b60006020808352613b358184018551613abd565b8084015160606040850152613b4d6080850182613af5565b6040860151858203601f19016060870152805180835290840192506000918401905b80831015613b8f5783518252928401926001929092019190840190613b6f565b509695505050505050565b634e487b7160e01b600052604160045260246000fd5b6040516080810167ffffffffffffffff81118282101715613bd357613bd3613b9a565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715613c0257613c02613b9a565b604052919050565b600067ffffffffffffffff821115613c2457613c24613b9a565b5060051b60200190565b600082601f830112613c3f57600080fd5b81356020613c54613c4f83613c0a565b613bd9565b8083825260208201915060208460051b870101935086841115613c7657600080fd5b602086015b84811015613b8f5780358352918301918301613c7b565b600080600060608486031215613ca757600080fd5b8335600a8110613cb657600080fd5b925060208481013567ffffffffffffffff80821115613cd457600080fd5b818701915087601f830112613ce857600080fd5b813581811115613cfa57613cfa613b9a565b613d0c601f8201601f19168501613bd9565b8181528985838601011115613d2057600080fd5b818585018683013760009181019094015291935060408601359180831115613d4757600080fd5b5050613d5586828701613c2e565b9150509250925092565b600080600060608486031215613d7457600080fd5b83359250602084013567ffffffffffffffff80821115613d9357600080fd5b613d9f87838801613c2e565b93506040860135915080821115613db557600080fd5b50613d5586828701613c2e565b600181811c90821680613dd657607f821691505b602082108103611d0757634e487b7160e01b600052602260045260246000fd5b60008151808452602080850194506020840160005b83811015613e2757815187529582019590820190600101613e0b565b509495945050505050565b848152613e426020820185613abd565b608060408201526000613e586080830185613af5565b828103606084015261189a8185613df6565b634e487b7160e01b600052603260045260246000fd5b600060208284031215613e9257600080fd5b8151600981106102b457600080fd5b6020810160098310613eb557613eb5613aa7565b91905290565b6001600160a01b0381168114613ed057600080fd5b50565b600060208284031215613ee557600080fd5b81516102b481613ebb565b608080825285518282018190526000919060209060a0850190828a01855b82811015613f5257613f42848351805182526020810151602083015260408101516040830152606081015160608301525050565b9285019290840190600101613f0e565b5050508481036020860152613f678189613af5565b925050508281036040840152613f7d8186613df6565b9050828103606084015261189a8185613df6565b600060808284031215613fa357600080fd5b613fab613bb0565b825181526020830151602082015260408301516040820152606083015160608201528091505092915050565b805160ff8116811461200457600080fd5b600080600060608486031215613ffd57600080fd5b835161400881613ebb565b6020850151909350915061401e60408501613fd7565b90509250925092565b805169ffffffffffffffffffff8116811461200457600080fd5b600080600080600060a0868803121561405957600080fd5b61406286614027565b945060208601519350604086015192506060860151915061408560808701614027565b90509295509295909350565b634e487b7160e01b600052601160045260246000fd5b8181038181111561011657610116614091565b60008060008060008060c087890312156140d357600080fd5b86516140de81613ebb565b60208801519096506140ef81613ebb565b94506140fd60408801613fd7565b935061410b60608801613fd7565b9250608087015161411b81613ebb565b60a088015190925063ffffffff8116811461413557600080fd5b809150509295509295509295565b6020808252825182820181905260009190848201906040850190845b8181101561418157835163ffffffff168352928401929184019160010161415f565b50909695505050505050565b600082601f83011261419e57600080fd5b815160206141ae613c4f83613c0a565b8083825260208201915060208460051b8701019350868411156141d057600080fd5b602086015b84811015613b8f5780516141e881613ebb565b83529183019183016141d5565b6000806040838503121561420857600080fd5b825167ffffffffffffffff8082111561422057600080fd5b818501915085601f83011261423457600080fd5b81516020614244613c4f83613c0a565b82815260059290921b8401810191818101908984111561426357600080fd5b948201945b838610156142915785518060060b81146142825760008081fd5b82529482019490820190614268565b918801519196509093505050808211156142aa57600080fd5b506142b78582860161418d565b9150509250929050565b600682810b9082900b03667fffffffffffff198112667fffffffffffff8213171561011657610116614091565b634e487b7160e01b600052601260045260246000fd5b60008160060b8360060b8061431b5761431b6142ee565b667fffffffffffff1982146000198214161561433957614339614091565b90059392505050565b600082614351576143516142ee565b500790565b60008160020b627fffff19810361436f5761436f614091565b6000190192915050565b600181815b808511156143b457816000190482111561439a5761439a614091565b808516156143a757918102915b93841c939080029061437e565b509250929050565b6000826143cb57506001610116565b816143d857506000610116565b81600181146143ee57600281146143f857614414565b6001915050610116565b60ff84111561440957614409614091565b50506001821b610116565b5060208310610133831016604e8410600b8410161715614437575081810a610116565b6144418383614379565b806000190482111561445557614455614091565b029392505050565b60006102b460ff8416836143bc565b818103600083128015838313168383128216171561448c5761448c614091565b5092915050565b6000600160ff1b82016144a8576144a8614091565b5060000390565b8051801515811461200457600080fd5b6000806000606084860312156144d457600080fd5b83516144df81613ebb565b6020850151909350915061401e604085016144af565b60006080828403121561450757600080fd5b61450f613bb0565b82518060070b811461452057600080fd5b8152602083015167ffffffffffffffff8116811461453d57600080fd5b60208201526040830151600381900b811461455757600080fd5b60408201526060928301519281019290925250919050565b808201828112600083128015821682158216171561458f5761458f614091565b505092915050565b6000806000606084860312156145ac57600080fd5b83516145b781613ebb565b602085015160409095015190969495509392505050565b60ff8416815267ffffffffffffffff831660208201526060604082015260006145fa6060830184613df6565b95945050505050565b6001600160a01b03831681526040602082018190526000906102ce90830184613af5565b60006020828403121561463957600080fd5b5051919050565b60008261464f5761464f6142ee565b600160ff1b82146000198414161561466957614669614091565b500590565b6146788185613abd565b60606020820152600061468e6060830185613af5565b8281036040840152610f4f8185613df6565b601f8211156146e8576000816000526020600020601f850160051c810160208610156146c95750805b601f850160051c820191505b8181101561325c578281556001016146d5565b505050565b815167ffffffffffffffff81111561470757614707613b9a565b61471b816147158454613dc2565b846146a0565b602080601f83116001811461475057600084156147385750858301515b600019600386901b1c1916600185901b17855561325c565b600085815260208120601f198616915b8281101561477f57888601518255948401946001909101908401614760565b508582101561479d5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b8082018082111561011657610116614091565b6000826147cf576147cf6142ee565b500490565b6000826147e3576147e36142ee565b500690565b80820260008212600160ff1b8414161561480457614804614091565b818105831482151761011657610116614091565b600069ffffffffffffffffffff82168061436f5761436f614091565b60006001820161484657614846614091565b5060010190565b60006102b483836143bc565b808202811582820484141761011657610116614091565b60006020828403121561488257600080fd5b6102b4826144af565b60006020828403121561489d57600080fd5b6102b482613fd7565b60006001600160ff1b01820161484657614846614091565b6000600160ff1b82016148d3576148d3614091565b506000190190565b60008160020b627fffff1981036148f4576148f4614091565b60000392915050565b6000825161490f818460208701613ad1565b919091019291505056fea264697066735822122074f32fef384fdc296b0859f1c1f941c8e736c6cb972aa9e2b894956ebd6a80b364736f6c63430008160033\",\"r\":\"0x1\",\"s\":\"0x1\",\"yParity\":\"0x0\",\"hash\":\"0xbc73db80bf4b8784ba10a8910a0b7ef85f6846d102b41dd990969ea205335354\",\"type\":\"0x2\"}],\"ommers\":[]},{\"header\":{\"parentHash\":\"0x026ae0c6ae91f186a9befa1ac8be30eea35e30e77de51a731085221e5cd39209\",\"sha3Uncles\":\"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347\",\"miner\":\"0x0000000000000000000000000000000000000000\",\"stateRoot\":\"0xb6003e7ba07a15a9e35f63daa484728ec4ceeded0c4d10ac1b04e9552d412b3c\",\"transactionsRoot\":\"0x6e4969a136061ca7a390d12830d47a151585325a8d396819fb2b958ff85e9f8f\",\"receiptsRoot\":\"0xc3e81df67d3e2a6c8345a954ef250cfcc41abcc2292a5aa263071124533fc9ad\",\"logsBloom\":\"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\"difficulty\":\"0x0\",\"number\":\"0x3\",\"gasLimit\":\"0x1c9c380\",\"gasUsed\":\"0x3c0f6\",\"timestamp\":\"0x66b200ce\",\"mixHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"nonce\":\"0x0000000000000000\",\"baseFeePerGas\":\"0x18993a68\",\"blobGasUsed\":\"0x0\",\"excessBlobGas\":\"0x0\",\"extraData\":\"0x\"},\"transactions\":[{\"chainId\":\"0x343a\",\"nonce\":\"0x0\",\"gas\":\"0x3c0f6\",\"maxFeePerGas\":\"0x5d4285cd\",\"maxPriorityFeePerGas\":\"0x3b9aca00\",\"value\":\"0x0\",\"accessList\":[],\"input\":\"0x608060405234801561001057600080fd5b50610380806100206000396000f3fe6080604052600080357fffffffff0000000000000000000000000000000000000000000000000000000016905060008160e01c610251565b60006379ba509782101561015e5781631627540c811461009857632a952b2d81146100b457633659cfe681146100d0576350c946fe81146100ec576353a47bb781146101085763625ca21c81146101245763718fe928811461014057610158565b7347d08dad17ccb558b3ea74b1a0e73a9cc804a9dc9150610158565b738138ef7cf908021d117e542120b7a390650161079150610158565b7347d08dad17ccb558b3ea74b1a0e73a9cc804a9dc9150610158565b738138ef7cf908021d117e542120b7a390650161079150610158565b7347d08dad17ccb558b3ea74b1a0e73a9cc804a9dc9150610158565b738138ef7cf908021d117e542120b7a390650161079150610158565b7347d08dad17ccb558b3ea74b1a0e73a9cc804a9dc91505b5061024c565b816379ba509781146101a657638da5cb5b81146101c25763aaf10f4281146101de5763c7f62cda81146101fa5763daa250be81146102165763deba1b9881146102325761024a565b7347d08dad17ccb558b3ea74b1a0e73a9cc804a9dc915061024a565b7347d08dad17ccb558b3ea74b1a0e73a9cc804a9dc915061024a565b7347d08dad17ccb558b3ea74b1a0e73a9cc804a9dc915061024a565b7347d08dad17ccb558b3ea74b1a0e73a9cc804a9dc915061024a565b738138ef7cf908021d117e542120b7a39065016107915061024a565b738138ef7cf908021d117e542120b7a3906501610791505b505b919050565b61025a81610037565b915050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036102ce57816040517fc2a825f50000000000000000000000000000000000000000000000000000000081526004016102c5919061032f565b60405180910390fd5b3660008037600080366000845af43d6000803e80600081146102ef573d6000f35b3d6000fd5b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b610329816102f4565b82525050565b60006020820190506103446000830184610320565b9291505056fea264697066735822122017a4b7fdaaab3897a7b47abaed8d2ee92d558883d3bb2a8454f9601b2ab2c3db64736f6c63430008150033\",\"r\":\"0x1\",\"s\":\"0x1\",\"yParity\":\"0x0\",\"hash\":\"0x2476e039803622aeb040f924f04c493f559aed3d6c9372ab405cb33c8c695328\",\"type\":\"0x2\"}],\"ommers\":[]},{\"header\":{\"parentHash\":\"0x3d22100ac0ee8d5cde334f7f926191a861b0648971ebc179547df28a0224c6d0\",\"sha3Uncles\":\"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347\",\"miner\":\"0x0000000000000000000000000000000000000000\",\"stateRoot\":\"0x9511d4711e5c30a72b0bff38a261daa75dcc5ba8b772d970a5c742244b4c861b\",\"transactionsRoot\":\"0xba5fff578d3d6c2cd63acbe9bca353eaa6fe22a5c408956eff49106e0a96c507\",\"receiptsRoot\":\"0xbae111f01cb07677e3a8c5031546138407c01bc964d3493d732dc4edf47d36d3\",\"logsBloom\":\"0x00000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000020000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000001000000000000000000000400000001000010000000000000000000000000000000000000000000000000000000000000000000000000\",\"difficulty\":\"0x0\",\"number\":\"0x5\",\"gasLimit\":\"0x1c9c380\",\"gasUsed\":\"0xcae7\",\"timestamp\":\"0x66b200cb\",\"mixHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"nonce\":\"0x0000000000000000\",\"baseFeePerGas\":\"0x12e09c7a\",\"blobGasUsed\":\"0x0\",\"excessBlobGas\":\"0x0\",\"extraData\":\"0x\"},\"transactions\":[{\"chainId\":\"0x343a\",\"nonce\":\"0x0\",\"gas\":\"0xcc4d\",\"maxFeePerGas\":\"0x557e5ec4\",\"maxPriorityFeePerGas\":\"0x3b9aca00\",\"to\":\"0x83a0444b93927c3afcbe46e522280390f748e171\",\"value\":\"0x0\",\"accessList\":[],\"input\":\"0x3659cfe6000000000000000000000000108f53faf774d7c4c56f5bce9ca6e605ce8aeadd\",\"r\":\"0x1\",\"s\":\"0x1\",\"yParity\":\"0x0\",\"hash\":\"0xf88e7b19ee347145c257e0cf7ac4ecc2bae83ca79d7edaa231e71d3213aeb151\",\"type\":\"0x2\"}],\"ommers\":[]},{\"header\":{\"parentHash\":\"0x08abe6e453727534d8dd708843a7522b7d500338bdfe2402ca105dcdb05eebe9\",\"sha3Uncles\":\"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347\",\"miner\":\"0x0000000000000000000000000000000000000000\",\"stateRoot\":\"0x9c8eaf493f8b4edce2ba1647343eadcc0989cf461e712c0a6253ff2ca1842bb7\",\"transactionsRoot\":\"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\",\"receiptsRoot\":\"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\",\"logsBloom\":\"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\"difficulty\":\"0x0\",\"number\":\"0x1\",\"gasLimit\":\"0x1c9c380\",\"gasUsed\":\"0x0\",\"timestamp\":\"0x66b200ca\",\"mixHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"nonce\":\"0x0000000000000000\",\"baseFeePerGas\":\"0x3b9aca00\",\"blobGasUsed\":\"0x0\",\"excessBlobGas\":\"0x0\",\"extraData\":\"0x\"},\"transactions\":[],\"ommers\":[]},{\"header\":{\"parentHash\":\"0xdd07c07470e1deff3749831f0f1ad8d4b6e35505e83b3c6ea14181716197cd8a\",\"sha3Uncles\":\"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347\",\"miner\":\"0x0000000000000000000000000000000000000000\",\"stateRoot\":\"0x29aa352e71b139e83b397bdd3dcf9b65d74770edaf3a9624d0dbc4f96f868680\",\"transactionsRoot\":\"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\",\"receiptsRoot\":\"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\",\"logsBloom\":\"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\"difficulty\":\"0x0\",\"number\":\"0x2\",\"gasLimit\":\"0x1c9c380\",\"gasUsed\":\"0x0\",\"timestamp\":\"0x66b200cb\",\"mixHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"nonce\":\"0x0000000000000000\",\"baseFeePerGas\":\"0x24a1ab52\",\"blobGasUsed\":\"0x0\",\"excessBlobGas\":\"0x0\",\"extraData\":\"0x\"},\"transactions\":[],\"ommers\":[]},{\"header\":{\"parentHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"sha3Uncles\":\"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347\",\"miner\":\"0x0000000000000000000000000000000000000000\",\"stateRoot\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"transactionsRoot\":\"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\",\"receiptsRoot\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"logsBloom\":\"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\"difficulty\":\"0x0\",\"number\":\"0x0\",\"gasLimit\":\"0x1c9c380\",\"gasUsed\":\"0x0\",\"timestamp\":\"0x66b200c9\",\"mixHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"nonce\":\"0x0000000000000000\",\"baseFeePerGas\":\"0x3b9aca00\",\"blobGasUsed\":\"0x0\",\"excessBlobGas\":\"0x0\",\"extraData\":\"0x\"},\"transactions\":[],\"ommers\":[]},{\"header\":{\"parentHash\":\"0xf6930be4847cac5017bbcbec2756eed19f36b4196526a98a88e311c296e3a9be\",\"sha3Uncles\":\"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347\",\"miner\":\"0x0000000000000000000000000000000000000000\",\"stateRoot\":\"0x29aa352e71b139e83b397bdd3dcf9b65d74770edaf3a9624d0dbc4f96f868680\",\"transactionsRoot\":\"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\",\"receiptsRoot\":\"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\",\"logsBloom\":\"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\"difficulty\":\"0x0\",\"number\":\"0x1\",\"gasLimit\":\"0x1c9c380\",\"gasUsed\":\"0x0\",\"timestamp\":\"0x66b200cc\",\"mixHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"nonce\":\"0x0000000000000000\",\"baseFeePerGas\":\"0x200d75e8\",\"blobGasUsed\":\"0x0\",\"excessBlobGas\":\"0x0\",\"extraData\":\"0x\"},\"transactions\":[],\"ommers\":[]},{\"header\":{\"parentHash\":\"0x08abe6e453727534d8dd708843a7522b7d500338bdfe2402ca105dcdb05eebe9\",\"sha3Uncles\":\"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347\",\"miner\":\"0x0000000000000000000000000000000000000000\",\"stateRoot\":\"0xb6003e7ba07a15a9e35f63daa484728ec4ceeded0c4d10ac1b04e9552d412b3c\",\"transactionsRoot\":\"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\",\"receiptsRoot\":\"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\",\"logsBloom\":\"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\"difficulty\":\"0x0\",\"number\":\"0x4\",\"gasLimit\":\"0x1c9c380\",\"gasUsed\":\"0x0\",\"timestamp\":\"0x66b200ca\",\"mixHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"nonce\":\"0x0000000000000000\",\"baseFeePerGas\":\"0x1592fbf9\",\"blobGasUsed\":\"0x0\",\"excessBlobGas\":\"0x0\",\"extraData\":\"0x\"},\"transactions\":[],\"ommers\":[]},{\"header\":{\"parentHash\":\"0x149d41e3b89d8324cef3feff98ef308e97bafe8745cc8461c60172bc7d4c44ba\",\"sha3Uncles\":\"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347\",\"miner\":\"0x0000000000000000000000000000000000000000\",\"stateRoot\":\"0x510f2275449c013534a25ad0b13c867caf720947b68bcbcd4863f7b172a5d023\",\"transactionsRoot\":\"0x0b44110186e52ff0ceb6b0776ca2992c94144a4ed712eef65ea038260ef0fcc7\",\"receiptsRoot\":\"0xc2823b8eb4730d9f2657137cc2ddc2c4f22ab68e0ab826236cf6a1551ca2b3a5\",\"logsBloom\":\"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\"difficulty\":\"0x0\",\"number\":\"0x2\",\"gasLimit\":\"0x1c9c380\",\"gasUsed\":\"0xe61f9\",\"timestamp\":\"0x66b200cb\",\"mixHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"nonce\":\"0x0000000000000000\",\"baseFeePerGas\":\"0x342770c0\",\"blobGasUsed\":\"0x0\",\"excessBlobGas\":\"0x0\",\"extraData\":\"0x\"},\"transactions\":[{\"chainId\":\"0x343a\",\"nonce\":\"0x0\",\"gas\":\"0xe94d1\",\"maxFeePerGas\":\"0x83215600\",\"maxPriorityFeePerGas\":\"0x3b9aca00\",\"to\":\"0x4e59b44847b379578588920ca78fbf26c0b4956c\",\"value\":\"0x0\",\"accessList\":[],\"input\":\"0x4786e4342646b3ba97c1790b6cf5a55087a36240b22570f5d3a5d6bcc929d93b608060405234801561001057600080fd5b5060008061002661006d60201b61081b1760201c565b60000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050610141565b60008060405160200161007f90610121565b6040516020818303038152906040528051906020012090508091505090565b600082825260208201905092915050565b7f696f2e73796e7468657469782e636f72652d636f6e7472616374732e4f776e6160008201527f626c650000000000000000000000000000000000000000000000000000000000602082015250565b600061010b60238361009e565b9150610116826100af565b604082019050919050565b6000602082019050818103600083015261013a816100fe565b9050919050565b611000806101506000396000f3fe608060405234801561001057600080fd5b50600436106100885760003560e01c806379ba50971161005b57806379ba5097146100ed5780638da5cb5b146100f7578063aaf10f4214610115578063c7f62cda1461013357610088565b80631627540c1461008d5780633659cfe6146100a957806353a47bb7146100c5578063718fe928146100e3575b600080fd5b6100a760048036038101906100a29190610d25565b61014f565b005b6100c360048036038101906100be9190610d25565b6102d0565b005b6100cd6102e4565b6040516100da9190610d61565b60405180910390f35b6100eb610317565b005b6100f56103fe565b005b6100ff61058b565b60405161010c9190610d61565b60405180910390f35b61011d6105be565b60405161012a9190610d61565b60405180910390f35b61014d60048036038101906101489190610d25565b6105f1565b005b61015761084c565b600061016161081b565b9050600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036101c9576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610252576040517fa88ee57700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b818160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055507f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce22826040516102c49190610d61565b60405180910390a15050565b6102d861084c565b6102e1816108c5565b50565b60006102ee61081b565b60010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b600061032161081b565b90503373ffffffffffffffffffffffffffffffffffffffff168160010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16146103b757336040517fa0e5a0d70000000000000000000000000000000000000000000000000000000081526004016103ae9190610d61565b60405180910390fd5b60008160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b600061040861081b565b905060008160010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146104a357336040517fa0e5a0d700000000000000000000000000000000000000000000000000000000815260040161049a9190610d61565b60405180910390fd5b7fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c8260000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16826040516104f8929190610d7c565b60405180910390a1808260000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060008260010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505050565b600061059561081b565b60000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60006105c8610b05565b60000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60006105fb610b05565b905060018160000160146101000a81548160ff02191690831515021790555060008160000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050828260000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060008373ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff16633659cfe6846040516024016106cc9190610d61565b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505060405161071b9190610e16565b600060405180830381855af49150503d8060008114610756576040519150601f19603f3d011682016040523d82523d6000602084013e61075b565b606091505b505090508015806107c357508173ffffffffffffffffffffffffffffffffffffffff16610786610b05565b60000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614155b156107fa576040517fa1cfa5a800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008360000160146101000a81548160ff0219169083151502179055600080fd5b60008060405160200161082d90610eb0565b6040516020818303038152906040528051906020012090508091505090565b610854610b36565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146108c357336040517f8e4a23d60000000000000000000000000000000000000000000000000000000081526004016108ba9190610d61565b60405180910390fd5b565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361092b576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61093481610b69565b61097557806040517f8a8b41ec00000000000000000000000000000000000000000000000000000000815260040161096c9190610d61565b60405180910390fd5b600061097f610b05565b90508060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610a0a576040517fa88ee57700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8060000160149054906101000a900460ff16158015610a2e5750610a2d82610b7c565b5b15610a7057816040517f15504301000000000000000000000000000000000000000000000000000000008152600401610a679190610d61565b60405180910390fd5b818160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055503073ffffffffffffffffffffffffffffffffffffffff167f5d611f318680d00598bb735d61bacf0c514c6b50e1e5ad30040a4df2b12791c783604051610af99190610d61565b60405180910390a25050565b600080604051602001610b1790610f42565b6040516020818303038152906040528051906020012090508091505090565b6000610b4061081b565b60000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b600080823b905060008111915050919050565b60008060003073ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff1663c7f62cda86604051602401610bc59190610d61565b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050604051610c149190610e16565b600060405180830381855af49150503d8060008114610c4f576040519150601f19603f3d011682016040523d82523d6000602084013e610c54565b606091505b509150915081158015610cb9575063a1cfa5a860e01b604051602001610c7a9190610faf565b6040516020818303038152906040528051906020012081604051602001610ca19190610e16565b60405160208183030381529060405280519060200120145b92505050919050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000610cf282610cc7565b9050919050565b610d0281610ce7565b8114610d0d57600080fd5b50565b600081359050610d1f81610cf9565b92915050565b600060208284031215610d3b57610d3a610cc2565b5b6000610d4984828501610d10565b91505092915050565b610d5b81610ce7565b82525050565b6000602082019050610d766000830184610d52565b92915050565b6000604082019050610d916000830185610d52565b610d9e6020830184610d52565b9392505050565b600081519050919050565b600081905092915050565b60005b83811015610dd9578082015181840152602081019050610dbe565b60008484015250505050565b6000610df082610da5565b610dfa8185610db0565b9350610e0a818560208601610dbb565b80840191505092915050565b6000610e228284610de5565b915081905092915050565b600082825260208201905092915050565b7f696f2e73796e7468657469782e636f72652d636f6e7472616374732e4f776e6160008201527f626c650000000000000000000000000000000000000000000000000000000000602082015250565b6000610e9a602383610e2d565b9150610ea582610e3e565b604082019050919050565b60006020820190508181036000830152610ec981610e8d565b9050919050565b7f696f2e73796e7468657469782e636f72652d636f6e7472616374732e50726f7860008201527f7900000000000000000000000000000000000000000000000000000000000000602082015250565b6000610f2c602183610e2d565b9150610f3782610ed0565b604082019050919050565b60006020820190508181036000830152610f5b81610f1f565b9050919050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b6000819050919050565b610fa9610fa482610f62565b610f8e565b82525050565b6000610fbb8284610f98565b6004820191508190509291505056fea264697066735822122023a7c33d7b91dce35ffbcf8837693364ab22a3905d0fc00016833e5fac45ca2f64736f6c63430008110033\",\"r\":\"0x1\",\"s\":\"0x1\",\"yParity\":\"0x0\",\"hash\":\"0x4feae6769d748b4f0f7c9bf21d782236c88f13906789a3ec602961296e4c3e43\",\"type\":\"0x2\"}],\"ommers\":[]},{\"header\":{\"parentHash\":\"0xb3535af5103fd1c2bbd6dc7ff23f0799037a6542c231ebcb85abd776560fa512\",\"sha3Uncles\":\"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347\",\"miner\":\"0x0000000000000000000000000000000000000000\",\"stateRoot\":\"0x23d74fb99ff6e42cbb5c33f92b078e37be6af2b6092459b103ff7059a6517ebc\",\"transactionsRoot\":\"0x9eab45eca206fe11c107ea985c7d02fcfa442836aea3e04ba11dc4df587d5aa6\",\"receiptsRoot\":\"0xe25abcfa973db8c55f73292137c626430de130a382ad4466337fefb0f7c8fde0\",\"logsBloom\":\"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\"difficulty\":\"0x0\",\"number\":\"0x2\",\"gasLimit\":\"0x1c9c380\",\"gasUsed\":\"0x3ce3f\",\"timestamp\":\"0x66b200cd\",\"mixHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"nonce\":\"0x0000000000000000\",\"baseFeePerGas\":\"0x1c0bc72b\",\"blobGasUsed\":\"0x0\",\"excessBlobGas\":\"0x0\",\"extraData\":\"0x\"},\"transactions\":[{\"chainId\":\"0x343a\",\"nonce\":\"0x0\",\"gas\":\"0x3d8a8\",\"maxFeePerGas\":\"0x6211577c\",\"maxPriorityFeePerGas\":\"0x3b9aca00\",\"to\":\"0x4e59b44847b379578588920ca78fbf26c0b4956c\",\"value\":\"0x0\",\"accessList\":[],\"input\":\"0x4786e4342646b3ba97c1790b6cf5a55087a36240b22570f5d3a5d6bcc929d93b608060405234801561001057600080fd5b5060405161068538038061068583398181016040528101906100329190610275565b818181600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361009b576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6100ae8161019d60201b61004f1760201c565b6100ef57806040517f8a8b41ec0000000000000000000000000000000000000000000000000000000081526004016100e691906102c4565b60405180910390fd5b806100fe6101b060201b60201c565b60000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050806101536101e160201b6100621760201c565b60000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050505050610414565b600080823b905060008111915050919050565b6000806040516020016101c290610362565b6040516020818303038152906040528051906020012090508091505090565b6000806040516020016101f3906103f4565b6040516020818303038152906040528051906020012090508091505090565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061024282610217565b9050919050565b61025281610237565b811461025d57600080fd5b50565b60008151905061026f81610249565b92915050565b6000806040838503121561028c5761028b610212565b5b600061029a85828601610260565b92505060206102ab85828601610260565b9150509250929050565b6102be81610237565b82525050565b60006020820190506102d960008301846102b5565b92915050565b600082825260208201905092915050565b7f696f2e73796e7468657469782e636f72652d636f6e7472616374732e50726f7860008201527f7900000000000000000000000000000000000000000000000000000000000000602082015250565b600061034c6021836102df565b9150610357826102f0565b604082019050919050565b6000602082019050818103600083015261037b8161033f565b9050919050565b7f696f2e73796e7468657469782e636f72652d636f6e7472616374732e4f776e6160008201527f626c650000000000000000000000000000000000000000000000000000000000602082015250565b60006103de6023836102df565b91506103e982610382565b604082019050919050565b6000602082019050818103600083015261040d816103d1565b9050919050565b610262806104236000396000f3fe6080604052366100135761001161001d565b005b61001b61001d565b005b6000610027610093565b90503660008037600080366000845af43d6000803e806000811461004a573d6000f35b3d6000fd5b600080823b905060008111915050919050565b6000806040516020016100749061017a565b6040516020818303038152906040528051906020012090508091505090565b600061009d6100c6565b60000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b6000806040516020016100d89061020c565b6040516020818303038152906040528051906020012090508091505090565b600082825260208201905092915050565b7f696f2e73796e7468657469782e636f72652d636f6e7472616374732e4f776e6160008201527f626c650000000000000000000000000000000000000000000000000000000000602082015250565b60006101646023836100f7565b915061016f82610108565b604082019050919050565b6000602082019050818103600083015261019381610157565b9050919050565b7f696f2e73796e7468657469782e636f72652d636f6e7472616374732e50726f7860008201527f7900000000000000000000000000000000000000000000000000000000000000602082015250565b60006101f66021836100f7565b91506102018261019a565b604082019050919050565b60006020820190508181036000830152610225816101e9565b905091905056fea2646970667358221220800da1f73cebd5e4afa07496d9bca6b6c4f526bdd3f4014ec15c70fe3a1c441364736f6c6343000811003300000000000000000000000047d08dad17ccb558b3ea74b1a0e73a9cc804a9dc000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266\",\"r\":\"0x1\",\"s\":\"0x1\",\"yParity\":\"0x0\",\"hash\":\"0xb6794d5c7abed6f91d447e8efb72ef2580595a6d7c8dee57ba1dbb330970146a\",\"type\":\"0x2\"}],\"ommers\":[]},{\"header\":{\"parentHash\":\"0x08abe6e453727534d8dd708843a7522b7d500338bdfe2402ca105dcdb05eebe9\",\"sha3Uncles\":\"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347\",\"miner\":\"0x0000000000000000000000000000000000000000\",\"stateRoot\":\"0x510f2275449c013534a25ad0b13c867caf720947b68bcbcd4863f7b172a5d023\",\"transactionsRoot\":\"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\",\"receiptsRoot\":\"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\",\"logsBloom\":\"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\"difficulty\":\"0x0\",\"number\":\"0x3\",\"gasLimit\":\"0x1c9c380\",\"gasUsed\":\"0x0\",\"timestamp\":\"0x66b200ca\",\"mixHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"nonce\":\"0x0000000000000000\",\"baseFeePerGas\":\"0x29dd5614\",\"blobGasUsed\":\"0x0\",\"excessBlobGas\":\"0x0\",\"extraData\":\"0x\"},\"transactions\":[],\"ommers\":[]}]}"
  },
  {
    "path": "crates/anvil/test-data/state-dump-legacy.json",
    "content": "{\"block\":{\"number\":2,\"beneficiary\":\"0x0000000000000000000000000000000000000000\",\"timestamp\":1724762147,\"gas_limit\":30000000,\"basefee\":875175000,\"difficulty\":\"0x0\",\"prevrandao\":\"0xb92480171c0235f8c6710a4047d7ee14a3be58c630839fb4422826ff3a013e44\",\"blob_excess_gas_and_price\":{\"excess_blob_gas\":0,\"blob_gasprice\":1}},\"accounts\":{\"0x0000000000000000000000000000000000000000\":{\"nonce\":0,\"balance\":\"0xa410\",\"code\":\"0x\",\"storage\":{}},\"0x14dc79964da2c08b23698b3d3cc7ca32193d9955\":{\"nonce\":0,\"balance\":\"0x21e19e0c9bab2400000\",\"code\":\"0x\",\"storage\":{}},\"0x15d34aaf54267db7d7c367839aaf71a00a2c6a65\":{\"nonce\":0,\"balance\":\"0x21e19e0c9bab2400000\",\"code\":\"0x\",\"storage\":{}},\"0x23618e81e3f5cdf7f54c3d65f7fbc0abf5b21e8f\":{\"nonce\":0,\"balance\":\"0x21e19e0c9bab2400000\",\"code\":\"0x\",\"storage\":{}},\"0x3c44cdddb6a900fa2b585dd299e03d12fa4293bc\":{\"nonce\":0,\"balance\":\"0x21e19e0c9bab2400000\",\"code\":\"0x\",\"storage\":{}},\"0x4e59b44847b379578588920ca78fbf26c0b4956c\":{\"nonce\":0,\"balance\":\"0x0\",\"code\":\"0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf3\",\"storage\":{}},\"0x70997970c51812dc3a010c7d01b50e0d17dc79c8\":{\"nonce\":1,\"balance\":\"0x21e19e0b90393da9b38\",\"code\":\"0x\",\"storage\":{}},\"0x90f79bf6eb2c4f870365e785982e1f101e93b906\":{\"nonce\":0,\"balance\":\"0x21e19e0c9bab2400000\",\"code\":\"0x\",\"storage\":{}},\"0x976ea74026e726554db657fa54763abd0c3a0aa9\":{\"nonce\":0,\"balance\":\"0x21e19e0c9bab2400000\",\"code\":\"0x\",\"storage\":{}},\"0x9965507d1a55bcc2695c58ba16fb37d819b0a4dc\":{\"nonce\":0,\"balance\":\"0x21e19e0c9bab2400000\",\"code\":\"0x\",\"storage\":{}},\"0xa0ee7a142d267c1f36714e4a8f75612f20a79720\":{\"nonce\":0,\"balance\":\"0x21e19e0c9bab2400000\",\"code\":\"0x\",\"storage\":{}},\"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266\":{\"nonce\":1,\"balance\":\"0x21e19e0b6a140b55df8\",\"code\":\"0x\",\"storage\":{}}},\"best_block_number\":2,\"blocks\":[{\"header\":{\"parentHash\":\"0xceb0fe420d6f14a8eeec4319515b89acbb0bb4861cad9983d529ab4b1e4af929\",\"sha3Uncles\":\"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347\",\"miner\":\"0x0000000000000000000000000000000000000000\",\"stateRoot\":\"0xe1423fd180478ab4fd05a7103277d64496b15eb914ecafe71eeec871b552efd1\",\"transactionsRoot\":\"0x2b5598ef261e5f88e4303bb2b3986b3d5c0ebf4cd9977daebccae82a6469b988\",\"receiptsRoot\":\"0xf78dfb743fbd92ade140711c8bbc542b5e307f0ab7984eff35d751969fe57efa\",\"logsBloom\":\"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\"difficulty\":\"0x0\",\"number\":\"0x2\",\"gasLimit\":\"0x1c9c380\",\"gasUsed\":\"0x5208\",\"timestamp\":\"0x66cdc823\",\"mixHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"nonce\":\"0x0000000000000000\",\"baseFeePerGas\":\"0x342a1c58\",\"blobGasUsed\":\"0x0\",\"excessBlobGas\":\"0x0\",\"extraData\":\"0x\"},\"transactions\":[{\"chainId\":\"0x7a69\",\"nonce\":\"0x0\",\"gas\":\"0x5209\",\"maxFeePerGas\":\"0x77359401\",\"maxPriorityFeePerGas\":\"0x1\",\"to\":\"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266\",\"value\":\"0x0\",\"accessList\":[],\"input\":\"0x\",\"r\":\"0x85c2794a580da137e24ccc823b45ae5cea99371ae23ee13860fcc6935f8305b0\",\"s\":\"0x41de7fa4121dab284af4453d30928241208bafa90cdb701fe9bc7054759fe3cd\",\"yParity\":\"0x0\",\"hash\":\"0x8c9b68e8947ace33028dba167354fde369ed7bbe34911b772d09b3c64b861515\",\"type\":\"0x2\"}],\"ommers\":[]},{\"header\":{\"parentHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"sha3Uncles\":\"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347\",\"miner\":\"0x0000000000000000000000000000000000000000\",\"stateRoot\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"transactionsRoot\":\"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\",\"receiptsRoot\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"logsBloom\":\"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\"difficulty\":\"0x0\",\"number\":\"0x0\",\"gasLimit\":\"0x1c9c380\",\"gasUsed\":\"0x0\",\"timestamp\":\"0x66cdc80e\",\"mixHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"nonce\":\"0x0000000000000000\",\"baseFeePerGas\":\"0x3b9aca00\",\"blobGasUsed\":\"0x0\",\"excessBlobGas\":\"0x0\",\"extraData\":\"0x\"},\"transactions\":[],\"ommers\":[]},{\"header\":{\"parentHash\":\"0xa00dc0c9ee9a888e67ea32d8772f8cc28eff62448c9ec985ee941fcbc921ba59\",\"sha3Uncles\":\"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347\",\"miner\":\"0x0000000000000000000000000000000000000000\",\"stateRoot\":\"0x6e5f60b37eeaece7dedfc42cc394731a0ae3ed3d3be93c402780b2e23e141175\",\"transactionsRoot\":\"0x9ceaeb1b16b924afbf4bf4df4c2c49dc9cfbe23ac7a40bf26a704158ea2d352f\",\"receiptsRoot\":\"0xf78dfb743fbd92ade140711c8bbc542b5e307f0ab7984eff35d751969fe57efa\",\"logsBloom\":\"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\"difficulty\":\"0x0\",\"number\":\"0x1\",\"gasLimit\":\"0x1c9c380\",\"gasUsed\":\"0x5208\",\"timestamp\":\"0x66cdc814\",\"mixHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"nonce\":\"0x0000000000000000\",\"baseFeePerGas\":\"0x3b9aca00\",\"blobGasUsed\":\"0x0\",\"excessBlobGas\":\"0x0\",\"extraData\":\"0x\"},\"transactions\":[{\"chainId\":\"0x7a69\",\"nonce\":\"0x0\",\"gas\":\"0x5209\",\"maxFeePerGas\":\"0x77359401\",\"maxPriorityFeePerGas\":\"0x1\",\"to\":\"0x70997970c51812dc3a010c7d01b50e0d17dc79c8\",\"value\":\"0x0\",\"accessList\":[],\"input\":\"0x\",\"r\":\"0x703a4b4d6dbff2fa2345df73263df2098faa7214863b5ec82c4c07162d87b853\",\"s\":\"0x17dea762c4ce600ad1d9d2c9ae6dd35b9e526d03c875f868ad0792fd4fad72e0\",\"yParity\":\"0x0\",\"hash\":\"0xf8d5fb22350f52ae8c30cd7f6969eb73de849c8dc010f4215d4c5c24824fe2b3\",\"type\":\"0x2\"}],\"ommers\":[]}]}"
  },
  {
    "path": "crates/anvil/test-data/state-dump.json",
    "content": "{\n  \"block\": {\n    \"number\": 2,\n    \"beneficiary\": \"0x0000000000000000000000000000000000000000\",\n    \"timestamp\": 1724763179,\n    \"gas_limit\": 30000000,\n    \"basefee\": 875175000,\n    \"difficulty\": \"0x0\",\n    \"prevrandao\": \"0xdb639d7f8af4f0ff2aa9cc49861820e72f5f8bfeeed677d1e3569f6b1625df4a\",\n    \"blob_excess_gas_and_price\": {\n      \"excess_blob_gas\": 0,\n      \"blob_gasprice\": 1\n    }\n  },\n  \"accounts\": {\n    \"0x0000000000000000000000000000000000000000\": {\n      \"nonce\": 0,\n      \"balance\": \"0xa410\",\n      \"code\": \"0x\",\n      \"storage\": {}\n    },\n    \"0x14dc79964da2c08b23698b3d3cc7ca32193d9955\": {\n      \"nonce\": 0,\n      \"balance\": \"0x21e19e0c9bab2400000\",\n      \"code\": \"0x\",\n      \"storage\": {}\n    },\n    \"0x15d34aaf54267db7d7c367839aaf71a00a2c6a65\": {\n      \"nonce\": 0,\n      \"balance\": \"0x21e19e0c9bab2400000\",\n      \"code\": \"0x\",\n      \"storage\": {}\n    },\n    \"0x23618e81e3f5cdf7f54c3d65f7fbc0abf5b21e8f\": {\n      \"nonce\": 0,\n      \"balance\": \"0x21e19e0c9bab2400000\",\n      \"code\": \"0x\",\n      \"storage\": {}\n    },\n    \"0x3c44cdddb6a900fa2b585dd299e03d12fa4293bc\": {\n      \"nonce\": 0,\n      \"balance\": \"0x21e19e0c9bab2400000\",\n      \"code\": \"0x\",\n      \"storage\": {}\n    },\n    \"0x4e59b44847b379578588920ca78fbf26c0b4956c\": {\n      \"nonce\": 0,\n      \"balance\": \"0x0\",\n      \"code\": \"0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf3\",\n      \"storage\": {}\n    },\n    \"0x70997970c51812dc3a010c7d01b50e0d17dc79c8\": {\n      \"nonce\": 1,\n      \"balance\": \"0x21e19e0b90393da9b38\",\n      \"code\": \"0x\",\n      \"storage\": {}\n    },\n    \"0x90f79bf6eb2c4f870365e785982e1f101e93b906\": {\n      \"nonce\": 0,\n      \"balance\": \"0x21e19e0c9bab2400000\",\n      \"code\": \"0x\",\n      \"storage\": {}\n    },\n    \"0x976ea74026e726554db657fa54763abd0c3a0aa9\": {\n      \"nonce\": 0,\n      \"balance\": \"0x21e19e0c9bab2400000\",\n      \"code\": \"0x\",\n      \"storage\": {}\n    },\n    \"0x9965507d1a55bcc2695c58ba16fb37d819b0a4dc\": {\n      \"nonce\": 0,\n      \"balance\": \"0x21e19e0c9bab2400000\",\n      \"code\": \"0x\",\n      \"storage\": {}\n    },\n    \"0xa0ee7a142d267c1f36714e4a8f75612f20a79720\": {\n      \"nonce\": 0,\n      \"balance\": \"0x21e19e0c9bab2400000\",\n      \"code\": \"0x\",\n      \"storage\": {}\n    },\n    \"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266\": {\n      \"nonce\": 1,\n      \"balance\": \"0x21e19e0b6a140b55df8\",\n      \"code\": \"0x\",\n      \"storage\": {}\n    }\n  },\n  \"best_block_number\": 2,\n  \"blocks\": [\n    {\n      \"header\": {\n        \"parentHash\": \"0x0000000000000000000000000000000000000000000000000000000000000000\",\n        \"sha3Uncles\": \"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347\",\n        \"miner\": \"0x0000000000000000000000000000000000000000\",\n        \"stateRoot\": \"0x0000000000000000000000000000000000000000000000000000000000000000\",\n        \"transactionsRoot\": \"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\",\n        \"receiptsRoot\": \"0x0000000000000000000000000000000000000000000000000000000000000000\",\n        \"logsBloom\": \"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\n        \"difficulty\": \"0x0\",\n        \"number\": \"0x0\",\n        \"gasLimit\": \"0x1c9c380\",\n        \"gasUsed\": \"0x0\",\n        \"timestamp\": \"0x66cdcc25\",\n        \"mixHash\": \"0x0000000000000000000000000000000000000000000000000000000000000000\",\n        \"nonce\": \"0x0000000000000000\",\n        \"baseFeePerGas\": \"0x3b9aca00\",\n        \"blobGasUsed\": \"0x0\",\n        \"excessBlobGas\": \"0x0\",\n        \"extraData\": \"0x\"\n      },\n      \"transactions\": [],\n      \"ommers\": []\n    },\n    {\n      \"header\": {\n        \"parentHash\": \"0x3a52101c98a4319c419681131d3585d70a6cf13a9af25136be20d451eed5480a\",\n        \"sha3Uncles\": \"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347\",\n        \"miner\": \"0x0000000000000000000000000000000000000000\",\n        \"stateRoot\": \"0x6e5f60b37eeaece7dedfc42cc394731a0ae3ed3d3be93c402780b2e23e141175\",\n        \"transactionsRoot\": \"0x9ceaeb1b16b924afbf4bf4df4c2c49dc9cfbe23ac7a40bf26a704158ea2d352f\",\n        \"receiptsRoot\": \"0xf78dfb743fbd92ade140711c8bbc542b5e307f0ab7984eff35d751969fe57efa\",\n        \"logsBloom\": \"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\n        \"difficulty\": \"0x0\",\n        \"number\": \"0x1\",\n        \"gasLimit\": \"0x1c9c380\",\n        \"gasUsed\": \"0x5208\",\n        \"timestamp\": \"0x66cdcc29\",\n        \"mixHash\": \"0x0000000000000000000000000000000000000000000000000000000000000000\",\n        \"nonce\": \"0x0000000000000000\",\n        \"baseFeePerGas\": \"0x3b9aca00\",\n        \"blobGasUsed\": \"0x0\",\n        \"excessBlobGas\": \"0x0\",\n        \"extraData\": \"0x\"\n      },\n      \"transactions\": [\n        {\n          \"transaction\": {\n            \"chainId\": \"0x7a69\",\n            \"nonce\": \"0x0\",\n            \"gas\": \"0x5209\",\n            \"maxFeePerGas\": \"0x77359401\",\n            \"maxPriorityFeePerGas\": \"0x1\",\n            \"to\": \"0x70997970c51812dc3a010c7d01b50e0d17dc79c8\",\n            \"value\": \"0x0\",\n            \"accessList\": [],\n            \"input\": \"0x\",\n            \"r\": \"0x703a4b4d6dbff2fa2345df73263df2098faa7214863b5ec82c4c07162d87b853\",\n            \"s\": \"0x17dea762c4ce600ad1d9d2c9ae6dd35b9e526d03c875f868ad0792fd4fad72e0\",\n            \"yParity\": \"0x0\",\n            \"hash\": \"0xf8d5fb22350f52ae8c30cd7f6969eb73de849c8dc010f4215d4c5c24824fe2b3\",\n            \"type\": \"0x2\"\n          },\n          \"impersonated_sender\": null\n        }\n      ],\n      \"ommers\": []\n    },\n    {\n      \"header\": {\n        \"parentHash\": \"0x0d575f9ca968cd483549172245483a12343afc3cabef80f0fa39855b10b98c70\",\n        \"sha3Uncles\": \"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347\",\n        \"miner\": \"0x0000000000000000000000000000000000000000\",\n        \"stateRoot\": \"0xe1423fd180478ab4fd05a7103277d64496b15eb914ecafe71eeec871b552efd1\",\n        \"transactionsRoot\": \"0x2b5598ef261e5f88e4303bb2b3986b3d5c0ebf4cd9977daebccae82a6469b988\",\n        \"receiptsRoot\": \"0xf78dfb743fbd92ade140711c8bbc542b5e307f0ab7984eff35d751969fe57efa\",\n        \"logsBloom\": \"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\n        \"difficulty\": \"0x0\",\n        \"number\": \"0x2\",\n        \"gasLimit\": \"0x1c9c380\",\n        \"gasUsed\": \"0x5208\",\n        \"timestamp\": \"0x66cdcc2b\",\n        \"mixHash\": \"0x0000000000000000000000000000000000000000000000000000000000000000\",\n        \"nonce\": \"0x0000000000000000\",\n        \"baseFeePerGas\": \"0x342a1c58\",\n        \"blobGasUsed\": \"0x0\",\n        \"excessBlobGas\": \"0x0\",\n        \"extraData\": \"0x\"\n      },\n      \"transactions\": [\n        {\n          \"transaction\": {\n            \"chainId\": \"0x7a69\",\n            \"nonce\": \"0x0\",\n            \"gas\": \"0x5209\",\n            \"maxFeePerGas\": \"0x77359401\",\n            \"maxPriorityFeePerGas\": \"0x1\",\n            \"to\": \"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266\",\n            \"value\": \"0x0\",\n            \"accessList\": [],\n            \"input\": \"0x\",\n            \"r\": \"0x85c2794a580da137e24ccc823b45ae5cea99371ae23ee13860fcc6935f8305b0\",\n            \"s\": \"0x41de7fa4121dab284af4453d30928241208bafa90cdb701fe9bc7054759fe3cd\",\n            \"yParity\": \"0x0\",\n            \"hash\": \"0x8c9b68e8947ace33028dba167354fde369ed7bbe34911b772d09b3c64b861515\",\n            \"type\": \"0x2\"\n          },\n          \"impersonated_sender\": null\n        }\n      ],\n      \"ommers\": []\n    }\n  ],\n  \"transactions\": [\n    {\n      \"info\": {\n        \"transaction_hash\": \"0xf8d5fb22350f52ae8c30cd7f6969eb73de849c8dc010f4215d4c5c24824fe2b3\",\n        \"transaction_index\": 0,\n        \"from\": \"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266\",\n        \"to\": \"0x70997970c51812dc3a010c7d01b50e0d17dc79c8\",\n        \"contract_address\": null,\n        \"traces\": [\n          {\n            \"parent\": null,\n            \"children\": [],\n            \"idx\": 0,\n            \"trace\": {\n              \"depth\": 0,\n              \"success\": true,\n              \"caller\": \"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266\",\n              \"address\": \"0x70997970c51812dc3a010c7d01b50e0d17dc79c8\",\n              \"maybe_precompile\": null,\n              \"selfdestruct_refund_target\": null,\n              \"selfdestruct_transferred_value\": null,\n              \"kind\": \"CALL\",\n              \"value\": \"0x0\",\n              \"data\": \"0x\",\n              \"output\": \"0x\",\n              \"gas_used\": 0,\n              \"gas_limit\": 1,\n              \"status\": \"Stop\",\n              \"steps\": [],\n              \"decoded\": {\n                \"label\": null,\n                \"return_data\": null,\n                \"call_data\": null\n              },\n              \"gas_refund_counter\": 0\n            },\n            \"logs\": [],\n            \"ordering\": []\n          }\n        ],\n        \"exit\": \"Stop\",\n        \"out\": \"0x\",\n        \"nonce\": 0,\n        \"gas_used\": 21000\n      },\n      \"receipt\": {\n        \"type\": \"0x2\",\n        \"status\": \"0x1\",\n        \"cumulativeGasUsed\": \"0x5208\",\n        \"logs\": [],\n        \"logsBloom\": \"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\"\n      },\n      \"block_hash\": \"0x0d575f9ca968cd483549172245483a12343afc3cabef80f0fa39855b10b98c70\",\n      \"block_number\": 1\n    },\n    {\n      \"info\": {\n        \"transaction_hash\": \"0x8c9b68e8947ace33028dba167354fde369ed7bbe34911b772d09b3c64b861515\",\n        \"transaction_index\": 0,\n        \"from\": \"0x70997970c51812dc3a010c7d01b50e0d17dc79c8\",\n        \"to\": \"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266\",\n        \"contract_address\": null,\n        \"traces\": [\n          {\n            \"parent\": null,\n            \"children\": [],\n            \"idx\": 0,\n            \"trace\": {\n              \"depth\": 0,\n              \"success\": true,\n              \"caller\": \"0x70997970c51812dc3a010c7d01b50e0d17dc79c8\",\n              \"address\": \"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266\",\n              \"maybe_precompile\": null,\n              \"selfdestruct_refund_target\": null,\n              \"selfdestruct_transferred_value\": null,\n              \"kind\": \"CALL\",\n              \"value\": \"0x0\",\n              \"data\": \"0x\",\n              \"output\": \"0x\",\n              \"gas_used\": 0,\n              \"gas_limit\": 1,\n              \"status\": \"Stop\",\n              \"steps\": [],\n              \"decoded\": {\n                \"label\": null,\n                \"return_data\": null,\n                \"call_data\": null\n              },\n              \"gas_refund_counter\": 0\n            },\n            \"logs\": [],\n            \"ordering\": []\n          }\n        ],\n        \"exit\": \"Stop\",\n        \"out\": \"0x\",\n        \"nonce\": 0,\n        \"gas_used\": 21000\n      },\n      \"receipt\": {\n        \"type\": \"0x2\",\n        \"status\": \"0x1\",\n        \"cumulativeGasUsed\": \"0x5208\",\n        \"logs\": [],\n        \"logsBloom\": \"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\"\n      },\n      \"block_hash\": \"0x1f435a603c1bf6d544a90156b572b96d7a1730028422d800839bae78bb3506d0\",\n      \"block_number\": 2\n    }\n  ]\n}\n"
  },
  {
    "path": "crates/anvil/test-data/storage_sample.json",
    "content": "{\"0x0000000000000000000000000000000000000000000000000000000000000022\":\"0xf5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b\",\"0x0000000000000000000000000000000000000000000000000000000000000023\":\"0xdb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71\",\"0x0000000000000000000000000000000000000000000000000000000000000024\":\"0xc78009fdf07fc56a11f122370658a353aaa542ed63e44c4bc15ff4cd105ab33c\",\"0x0000000000000000000000000000000000000000000000000000000000000025\":\"0x536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123c\",\"0x0000000000000000000000000000000000000000000000000000000000000026\":\"0x9efde052aa15429fae05bad4d0b1d7c64da64d03d7a1854a588c2cb8430c0d30\",\"0x0000000000000000000000000000000000000000000000000000000000000027\":\"0xd88ddfeed400a8755596b21942c1497e114c302e6118290f91e6772976041fa1\",\"0x0000000000000000000000000000000000000000000000000000000000000028\":\"0x87eb0ddba57e35f6d286673802a4af5975e22506c7cf4c64bb6be5ee11527f2c\",\"0x0000000000000000000000000000000000000000000000000000000000000029\":\"0x26846476fd5fc54a5d43385167c95144f2643f533cc85bb9d16b782f8d7db193\",\"0x000000000000000000000000000000000000000000000000000000000000002a\":\"0x506d86582d252405b840018792cad2bf1259f1ef5aa5f887e13cb2f0094f51e1\",\"0x000000000000000000000000000000000000000000000000000000000000002b\":\"0xffff0ad7e659772f9534c195c815efc4014ef1e1daed4404c06385d11192e92b\",\"0x000000000000000000000000000000000000000000000000000000000000002c\":\"0x6cf04127db05441cd833107a52be852868890e4317e6a02ab47683aa75964220\",\"0x000000000000000000000000000000000000000000000000000000000000002d\":\"0xb7d05f875f140027ef5118a2247bbb84ce8f2f0f1123623085daf7960c329f5f\",\"0x000000000000000000000000000000000000000000000000000000000000002e\":\"0xdf6af5f5bbdb6be9ef8aa618e4bf8073960867171e29676f8b284dea6a08a85e\",\"0x000000000000000000000000000000000000000000000000000000000000002f\":\"0xb58d900f5e182e3c50ef74969ea16c7726c549757cc23523c369587da7293784\",\"0x0000000000000000000000000000000000000000000000000000000000000030\":\"0xd49a7502ffcfb0340b1d7885688500ca308161a7f96b62df9d083b71fcc8f2bb\",\"0x0000000000000000000000000000000000000000000000000000000000000031\":\"0x8fe6b1689256c0d385f42f5bbe2027a22c1996e110ba97c171d3e5948de92beb\",\"0x0000000000000000000000000000000000000000000000000000000000000032\":\"0x8d0d63c39ebade8509e0ae3c9c3876fb5fa112be18f905ecacfecb92057603ab\",\"0x0000000000000000000000000000000000000000000000000000000000000033\":\"0x95eec8b2e541cad4e91de38385f2e046619f54496c2382cb6cacd5b98c26f5a4\",\"0x0000000000000000000000000000000000000000000000000000000000000034\":\"0xf893e908917775b62bff23294dbbe3a1cd8e6cc1c35b4801887b646a6f81f17f\",\"0x0000000000000000000000000000000000000000000000000000000000000035\":\"0xcddba7b592e3133393c16194fac7431abf2f5485ed711db282183c819e08ebaa\",\"0x0000000000000000000000000000000000000000000000000000000000000036\":\"0x8a8d7fe3af8caa085a7639a832001457dfb9128a8061142ad0335629ff23ff9c\",\"0x0000000000000000000000000000000000000000000000000000000000000037\":\"0xfeb3c337d7a51a6fbf00b9e34c52e1c9195c969bd4e7a0bfd51d5c5bed9c1167\",\"0x0000000000000000000000000000000000000000000000000000000000000038\":\"0xe71f0aa83cc32edfbefa9f4d3e0174ca85182eec9f3a09f6a6c0df6377a510d7\",\"0x0000000000000000000000000000000000000000000000000000000000000039\":\"0x31206fa80a50bb6abe29085058f16212212a60eec8f049fecb92d8c8e0a84bc0\",\"0x000000000000000000000000000000000000000000000000000000000000003a\":\"0x21352bfecbeddde993839f614c3dac0a3ee37543f9b412b16199dc158e23b544\",\"0x000000000000000000000000000000000000000000000000000000000000003b\":\"0x619e312724bb6d7c3153ed9de791d764a366b389af13c58bf8a8d90481a46765\",\"0x000000000000000000000000000000000000000000000000000000000000003c\":\"0x7cdd2986268250628d0c10e385c58c6191e6fbe05191bcc04f133f2cea72c1c4\",\"0x000000000000000000000000000000000000000000000000000000000000003d\":\"0x848930bd7ba8cac54661072113fb278869e07bb8587f91392933374d017bcbe1\",\"0x000000000000000000000000000000000000000000000000000000000000003e\":\"0x8869ff2c22b28cc10510d9853292803328be4fb0e80495e8bb8d271f5b889636\",\"0x000000000000000000000000000000000000000000000000000000000000003f\":\"0xb5fe28e79f1b850f8658246ce9b6a1e7b49fc06db7143e8fe0b4f2b0c5523a5c\",\"0x0000000000000000000000000000000000000000000000000000000000000040\":\"0x985e929f70af28d0bdd1a90a808f977f597c7c778c489e98d3bd8910d31ac0f7\"}"
  },
  {
    "path": "crates/anvil/tests/it/abi.rs",
    "content": "//! commonly used sol generated types\nuse alloy_sol_types::sol;\n\nsol!(\n    #[sol(rpc)]\n    Greeter,\n    \"test-data/greeter.json\"\n);\n\nsol!(\n    #[derive(Debug)]\n    #[sol(rpc)]\n    SimpleStorage,\n    \"test-data/SimpleStorage.json\"\n);\n\nsol!(\n    #[sol(rpc)]\n    Multicall,\n    \"test-data/multicall.json\"\n);\n\nsol!(\n    #[sol(rpc)]\n    contract BUSD {\n        function balanceOf(address) external view returns (uint256);\n    }\n);\n\nsol!(\n    #[sol(rpc)]\n    interface ERC721 {\n        function balanceOf(address owner) public view virtual returns (uint256);\n        function ownerOf(uint256 tokenId) public view virtual returns (address);\n        function name() public view virtual returns (string memory);\n        function symbol() public view virtual returns (string memory);\n        function tokenURI(uint256 tokenId) public view virtual returns (string memory);\n        function getApproved(uint256 tokenId) public view virtual returns (address);\n        function setApprovalForAll(address operator, bool approved) public virtual;\n        function isApprovedForAll(address owner, address operator) public view virtual returns (bool);\n        function transferFrom(address from, address to, uint256 tokenId) public virtual;\n        function safeTransferFrom(address from, address to, uint256 tokenId) public;\n        function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data) public virtual;\n        function _mint(address to, uint256 tokenId) internal;\n        function _safeMint(address to, uint256 tokenId, bytes memory data) internal virtual;\n        function _burn(uint256 tokenId) internal;\n        function _transfer(address from, address to, uint256 tokenId) internal;\n        function _approve(address to, uint256 tokenId, address auth) internal;\n    }\n);\n\n// https://docs.soliditylang.org/en/latest/control-structures.html#revert\nsol!(\n// SPDX-License-Identifier: GPL-3.0\npragma solidity ^0.8.4;\n\n#[sol(rpc, bytecode = \"6080806040523460155761011e908161001a8239f35b5f80fdfe60808060405260043610156011575f80fd5b5f3560e01c9081633ccfd60b146094575063d96a094a14602f575f80fd5b6020366003190112609057671bc16d674ec80000340460043511604e57005b60405162461bcd60e51b815260206004820152601a6024820152792737ba1032b737bab3b41022ba3432b910383937bb34b232b21760311b6044820152606490fd5b5f80fd5b346090575f3660031901126090575f546001600160a01b0316330360da575f8080804781811560d2575b3390f11560c757005b6040513d5f823e3d90fd5b506108fc60be565b6282b42960e81b8152600490fdfea2646970667358221220c143fcbf0da5cee61ae3fcc385d9f7c4d6a7fb2ea42530d70d6049478db0b8a964736f6c63430008190033\")]\ncontract VendingMachine {\n    address owner;\n    error Unauthorized();\n    #[derive(Debug)]\n    function buy(uint amount) public payable {\n        if (amount > msg.value / 2 ether)\n            revert(\"Not enough Ether provided.\");\n        // Alternative way to do it:\n        require(\n            amount <= msg.value / 2 ether,\n            \"Not enough Ether provided.\"\n        );\n        // Perform the purchase.\n    }\n    function withdraw() public {\n        if (msg.sender != owner)\n            revert Unauthorized();\n\n        payable(msg.sender).transfer(address(this).balance);\n    }\n}\n);\n"
  },
  {
    "path": "crates/anvil/tests/it/anvil.rs",
    "content": "//! tests for anvil specific logic\n\nuse alloy_consensus::EMPTY_ROOT_HASH;\nuse alloy_eips::BlockNumberOrTag;\nuse alloy_network::{ReceiptResponse, TransactionBuilder};\nuse alloy_primitives::{Address, B256, U256, bytes, hex};\nuse alloy_provider::Provider;\nuse alloy_rpc_types::TransactionRequest;\nuse alloy_sol_types::SolCall;\nuse anvil::{NodeConfig, spawn};\nuse foundry_evm::hardfork::EthereumHardfork;\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_can_change_mining_mode() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n    let provider = handle.http_provider();\n\n    assert!(api.anvil_get_auto_mine().unwrap());\n    assert!(api.anvil_get_interval_mining().unwrap().is_none());\n\n    let num = provider.get_block_number().await.unwrap();\n    assert_eq!(num, 0);\n\n    api.anvil_set_interval_mining(1).unwrap();\n    assert!(!api.anvil_get_auto_mine().unwrap());\n    assert!(matches!(api.anvil_get_interval_mining().unwrap(), Some(1)));\n    // changing the mining mode will instantly mine a new block\n    tokio::time::sleep(std::time::Duration::from_millis(500)).await;\n    let num = provider.get_block_number().await.unwrap();\n    assert_eq!(num, 0);\n\n    tokio::time::sleep(std::time::Duration::from_millis(700)).await;\n    let num = provider.get_block_number().await.unwrap();\n    assert_eq!(num, 1);\n\n    // assert that no block is mined when the interval is set to 0\n    api.anvil_set_interval_mining(0).unwrap();\n    assert!(!api.anvil_get_auto_mine().unwrap());\n    assert!(api.anvil_get_interval_mining().unwrap().is_none());\n    tokio::time::sleep(std::time::Duration::from_millis(1000)).await;\n    let num = provider.get_block_number().await.unwrap();\n    assert_eq!(num, 1);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_get_default_dev_keys() {\n    let (_api, handle) = spawn(NodeConfig::test()).await;\n    let provider = handle.http_provider();\n\n    let dev_accounts = handle.dev_accounts().collect::<Vec<_>>();\n    let accounts = provider.get_accounts().await.unwrap();\n\n    assert_eq!(dev_accounts, accounts);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_set_empty_code() {\n    let (api, _handle) = spawn(NodeConfig::test()).await;\n    let addr = Address::random();\n    api.anvil_set_code(addr, Vec::new().into()).await.unwrap();\n    let code = api.get_code(addr, None).await.unwrap();\n    assert!(code.as_ref().is_empty());\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_can_set_genesis_timestamp() {\n    let genesis_timestamp = 1000u64;\n    let (_api, handle) =\n        spawn(NodeConfig::test().with_genesis_timestamp(genesis_timestamp.into())).await;\n    let provider = handle.http_provider();\n\n    assert_eq!(\n        genesis_timestamp,\n        provider.get_block(0.into()).await.unwrap().unwrap().header.timestamp\n    );\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_can_use_default_genesis_timestamp() {\n    let (_api, handle) = spawn(NodeConfig::test()).await;\n    let provider = handle.http_provider();\n\n    assert_ne!(0u64, provider.get_block(0.into()).await.unwrap().unwrap().header.timestamp);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_can_handle_large_timestamp() {\n    let (api, _handle) = spawn(NodeConfig::test()).await;\n    let num = 317071597274;\n    api.evm_set_next_block_timestamp(num).unwrap();\n    api.mine_one().await;\n\n    let block = api.block_by_number(BlockNumberOrTag::Latest).await.unwrap().unwrap();\n    assert_eq!(block.header.timestamp, num);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_shanghai_fields() {\n    let (api, _handle) =\n        spawn(NodeConfig::test().with_hardfork(Some(EthereumHardfork::Shanghai.into()))).await;\n    api.mine_one().await;\n\n    let block = api.block_by_number(BlockNumberOrTag::Latest).await.unwrap().unwrap();\n    assert_eq!(block.header.withdrawals_root, Some(EMPTY_ROOT_HASH));\n    assert_eq!(block.withdrawals, Some(Default::default()));\n    assert!(block.header.blob_gas_used.is_none());\n    assert!(block.header.excess_blob_gas.is_none());\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_cancun_fields() {\n    let (api, _handle) =\n        spawn(NodeConfig::test().with_hardfork(Some(EthereumHardfork::Cancun.into()))).await;\n    api.mine_one().await;\n\n    let block = api.block_by_number(BlockNumberOrTag::Latest).await.unwrap().unwrap();\n    assert_eq!(block.header.withdrawals_root, Some(EMPTY_ROOT_HASH));\n    assert_eq!(block.withdrawals, Some(Default::default()));\n    assert!(block.header.blob_gas_used.is_some());\n    assert!(block.header.excess_blob_gas.is_some());\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_can_set_genesis_block_number() {\n    let (_api, handle) = spawn(NodeConfig::test().with_genesis_block_number(Some(1337u64))).await;\n    let provider = handle.http_provider();\n\n    let block_number = provider.get_block_number().await.unwrap();\n    assert_eq!(block_number, 1337u64);\n\n    assert_eq!(1337, provider.get_block(1337.into()).await.unwrap().unwrap().header.number);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_can_use_default_genesis_block_number() {\n    let (_api, handle) = spawn(NodeConfig::test()).await;\n    let provider = handle.http_provider();\n\n    assert_eq!(0, provider.get_block(0.into()).await.unwrap().unwrap().header.number);\n}\n\n/// Verify that genesis block number affects both RPC and EVM execution layer.\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_number_opcode_reflects_genesis_block_number() {\n    let genesis_number: u64 = 4242;\n    let (api, handle) =\n        spawn(NodeConfig::test().with_genesis_block_number(Some(genesis_number))).await;\n    let provider = handle.http_provider();\n\n    // RPC layer should return configured genesis number\n    let bn = provider.get_block_number().await.unwrap();\n    assert_eq!(bn, genesis_number);\n\n    // Deploy bytecode that returns block.number\n    // 0x43 (NUMBER) 0x5f (PUSH0) 0x52 (MSTORE) 0x60 0x20 (PUSH1 0x20) 0x5f (PUSH0) 0xf3 (RETURN)\n    let target = Address::random();\n    api.anvil_set_code(target, bytes!(\"435f5260205ff3\")).await.unwrap();\n\n    // EVM execution should reflect genesis number (+ 1 for pending block)\n    let tx = alloy_rpc_types::TransactionRequest::default().with_to(target);\n    let out = provider.call(tx.into()).await.unwrap();\n    let returned = U256::from_be_slice(out.as_ref());\n    assert_eq!(returned, U256::from(genesis_number + 1));\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_anvil_recover_signature() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n    let provider = handle.http_provider();\n    alloy_sol_types::sol! {\n    #[sol(rpc)]\n        contract TestRecover {\n            function testRecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s, address expected) external pure {\n                address recovered = ecrecover(hash, v, r, s);\n                require(recovered == expected, \"ecrecover failed: address mismatch\");\n            }\n        }\n    }\n    let bytecode = hex::decode(\n        \"0x60808060405234601557610125908161001a8239f35b5f80fdfe60808060405260043610156011575f80fd5b5f3560e01c63bff0b743146023575f80fd5b3460eb5760a036600319011260eb5760243560ff811680910360eb576084356001600160a01b038116929083900360eb5760805f916020936004358252848201526044356040820152606435606082015282805260015afa1560e0575f516001600160a01b031603609057005b60405162461bcd60e51b815260206004820152602260248201527f65637265636f766572206661696c65643a2061646472657373206d69736d61746044820152610c6d60f31b6064820152608490fd5b6040513d5f823e3d90fd5b5f80fdfea264697066735822122006368b42bca31c97f2c409a1cc5186dc899d4255ecc28db7bbb0ad285dc82ae464736f6c634300081c0033\",\n    ).unwrap();\n\n    let tx = TransactionRequest::default().with_deploy_code(bytecode);\n    let receipt = provider.send_transaction(tx.into()).await.unwrap().get_receipt().await.unwrap();\n    let contract_address = receipt.contract_address().unwrap();\n    let contract = TestRecover::new(contract_address, &provider);\n\n    let sig = alloy_primitives::hex::decode(\"11\".repeat(65)).unwrap();\n    let r = B256::from_slice(&sig[0..32]);\n    let s = B256::from_slice(&sig[32..64]);\n    let v = sig[64];\n    let fake_hash = B256::random();\n    let expected = alloy_primitives::address!(\"0x1234567890123456789012345678901234567890\");\n    api.anvil_impersonate_signature(sig.clone().into(), expected).await.unwrap();\n    let result = contract.testRecover(fake_hash, v, r, s, expected).call().await;\n    assert!(result.is_ok(), \"ecrecover failed: {:?}\", result.err());\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_fake_signature_transaction() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n    let provider = handle.http_provider();\n    alloy_sol_types::sol! {\n    #[sol(rpc)]\n        contract TestRecover {\n            function testRecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s, address expected) external pure {\n                address recovered = ecrecover(hash, v, r, s);\n                require(recovered == expected, \"ecrecover failed: address mismatch\");\n            }\n        }\n    }\n    let bytecode = hex::decode(\n        \"0x60808060405234601557610125908161001a8239f35b5f80fdfe60808060405260043610156011575f80fd5b5f3560e01c63bff0b743146023575f80fd5b3460eb5760a036600319011260eb5760243560ff811680910360eb576084356001600160a01b038116929083900360eb5760805f916020936004358252848201526044356040820152606435606082015282805260015afa1560e0575f516001600160a01b031603609057005b60405162461bcd60e51b815260206004820152602260248201527f65637265636f766572206661696c65643a2061646472657373206d69736d61746044820152610c6d60f31b6064820152608490fd5b6040513d5f823e3d90fd5b5f80fdfea264697066735822122006368b42bca31c97f2c409a1cc5186dc899d4255ecc28db7bbb0ad285dc82ae464736f6c634300081c0033\",\n    ).unwrap();\n\n    let tx = TransactionRequest::default().with_deploy_code(bytecode);\n    let _receipt = provider.send_transaction(tx.into()).await.unwrap().get_receipt().await.unwrap();\n\n    let sig = alloy_primitives::hex::decode(\"11\".repeat(65)).unwrap();\n    let r = B256::from_slice(&sig[0..32]);\n    let s = B256::from_slice(&sig[32..64]);\n    let v = sig[64];\n    let fake_hash = B256::random();\n    let expected = alloy_primitives::address!(\"0x1234567890123456789012345678901234567890\");\n    api.anvil_impersonate_signature(sig.clone().into(), expected).await.unwrap();\n    let calldata = TestRecover::testRecoverCall { hash: fake_hash, v, r, s, expected }.abi_encode();\n    let tx = TransactionRequest::default().with_input(calldata);\n    let pending = provider.send_transaction(tx.into()).await.unwrap();\n    let result = pending.get_receipt().await;\n\n    assert!(result.is_ok(), \"ecrecover failed: {:?}\", result.err());\n}\n"
  },
  {
    "path": "crates/anvil/tests/it/anvil_api.rs",
    "content": "//! tests for custom anvil endpoints\n\nuse crate::{\n    abi::{self, BUSD, Greeter, Multicall},\n    fork::fork_config,\n    utils::http_provider_with_signer,\n};\nuse alloy_consensus::{SignableTransaction, TxEip1559};\nuse alloy_network::{EthereumWallet, TransactionBuilder, TxSignerSync};\nuse alloy_primitives::{Address, Bytes, TxKind, U256, address, fixed_bytes};\nuse alloy_provider::{Provider, ext::TxPoolApi};\nuse alloy_rpc_types::{\n    BlockId, BlockNumberOrTag, TransactionRequest,\n    anvil::{\n        ForkedNetwork, Forking, Metadata, MineOptions, NodeEnvironment, NodeForkConfig, NodeInfo,\n    },\n};\nuse alloy_serde::WithOtherFields;\nuse anvil::{NodeConfig, eth::api::CLIENT_VERSION, spawn};\nuse anvil_core::{\n    eth::EthRequest,\n    types::{ReorgOptions, TransactionData},\n};\nuse foundry_evm::hardfork::EthereumHardfork;\n\nuse revm::primitives::hardfork::SpecId;\nuse std::{\n    str::FromStr,\n    time::{Duration, SystemTime},\n};\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_set_gas_price() {\n    let (api, handle) =\n        spawn(NodeConfig::test().with_hardfork(Some(EthereumHardfork::Berlin.into()))).await;\n    let provider = handle.http_provider();\n\n    let gas_price = U256::from(1337);\n    api.anvil_set_min_gas_price(gas_price).await.unwrap();\n    assert_eq!(gas_price.to::<u128>(), provider.get_gas_price().await.unwrap());\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_set_block_gas_limit() {\n    let (api, _) =\n        spawn(NodeConfig::test().with_hardfork(Some(EthereumHardfork::Berlin.into()))).await;\n\n    let block_gas_limit = U256::from(1337);\n    assert!(api.evm_set_block_gas_limit(block_gas_limit).unwrap());\n    // Mine a new block, and check the new block gas limit\n    api.mine_one().await;\n    let latest_block = api.block_by_number(BlockNumberOrTag::Latest).await.unwrap().unwrap();\n    assert_eq!(block_gas_limit.to::<u64>(), latest_block.header.gas_limit);\n}\n\n// Ref <https://github.com/foundry-rs/foundry/issues/2341>\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_set_storage() {\n    let (api, _handle) = spawn(NodeConfig::test()).await;\n    let s = r#\"{\"jsonrpc\": \"2.0\", \"method\": \"hardhat_setStorageAt\", \"id\": 1, \"params\": [\"0xe9e7CEA3DedcA5984780Bafc599bD69ADd087D56\", \"0xa6eef7e35abe7026729641147f7915573c7e97b47efa546f5f6e3230263bcb49\", \"0x0000000000000000000000000000000000000000000000000000000000003039\"]}\"#;\n    let req = serde_json::from_str::<EthRequest>(s).unwrap();\n    let (addr, slot, val) = match req.clone() {\n        EthRequest::SetStorageAt(addr, slot, val) => (addr, slot, val),\n        _ => unreachable!(),\n    };\n\n    api.execute(req).await;\n\n    let storage_value = api.storage_at(addr, slot, None).await.unwrap();\n    assert_eq!(val, storage_value);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_impersonate_account() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n\n    let provider = handle.http_provider();\n\n    let impersonate = Address::random();\n    let to = Address::random();\n    let val = U256::from(1337);\n    let funding = U256::from(1e18 as u64);\n    // fund the impersonated account\n    api.anvil_set_balance(impersonate, funding).await.unwrap();\n\n    let balance = api.balance(impersonate, None).await.unwrap();\n    assert_eq!(balance, funding);\n\n    let tx = TransactionRequest::default().with_from(impersonate).with_to(to).with_value(val);\n    let tx = WithOtherFields::new(tx);\n\n    let res = provider.send_transaction(tx.clone()).await;\n    res.unwrap_err();\n\n    api.anvil_impersonate_account(impersonate).await.unwrap();\n    assert!(api.accounts().unwrap().contains(&impersonate));\n\n    let res = provider.send_transaction(tx.clone()).await.unwrap().get_receipt().await.unwrap();\n    assert_eq!(res.from, impersonate);\n\n    let nonce = provider.get_transaction_count(impersonate).await.unwrap();\n    assert_eq!(nonce, 1);\n\n    let balance = provider.get_balance(to).await.unwrap();\n    assert_eq!(balance, val);\n\n    api.anvil_stop_impersonating_account(impersonate).await.unwrap();\n    let res = provider.send_transaction(tx).await;\n    res.unwrap_err();\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_auto_impersonate_account() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n\n    let provider = handle.http_provider();\n\n    let impersonate = Address::random();\n    let to = Address::random();\n    let val = U256::from(1337);\n    let funding = U256::from(1e18 as u64);\n    // fund the impersonated account\n    api.anvil_set_balance(impersonate, funding).await.unwrap();\n\n    let balance = api.balance(impersonate, None).await.unwrap();\n    assert_eq!(balance, funding);\n\n    let tx = TransactionRequest::default().with_from(impersonate).with_to(to).with_value(val);\n    let tx = WithOtherFields::new(tx);\n\n    let res = provider.send_transaction(tx.clone()).await;\n    res.unwrap_err();\n\n    api.anvil_auto_impersonate_account(true).await.unwrap();\n\n    let res = provider.send_transaction(tx.clone()).await.unwrap().get_receipt().await.unwrap();\n    assert_eq!(res.from, impersonate);\n\n    let nonce = provider.get_transaction_count(impersonate).await.unwrap();\n    assert_eq!(nonce, 1);\n\n    let balance = provider.get_balance(to).await.unwrap();\n    assert_eq!(balance, val);\n\n    api.anvil_auto_impersonate_account(false).await.unwrap();\n    let res = provider.send_transaction(tx).await;\n    res.unwrap_err();\n\n    // explicitly impersonated accounts get returned by `eth_accounts`\n    api.anvil_impersonate_account(impersonate).await.unwrap();\n    assert!(api.accounts().unwrap().contains(&impersonate));\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_impersonate_contract() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n\n    let provider = handle.http_provider();\n\n    let greeter_contract = Greeter::deploy(&provider, \"Hello World!\".to_string()).await.unwrap();\n    let impersonate = greeter_contract.address().to_owned();\n\n    let to = Address::random();\n    let val = U256::from(1337);\n\n    // // fund the impersonated account\n    api.anvil_set_balance(impersonate, U256::from(1e18 as u64)).await.unwrap();\n\n    let tx = TransactionRequest::default().with_from(impersonate).to(to).with_value(val);\n    let tx = WithOtherFields::new(tx);\n\n    let res = provider.send_transaction(tx.clone()).await;\n    res.unwrap_err();\n\n    let greeting = greeter_contract.greet().call().await.unwrap();\n    assert_eq!(\"Hello World!\", greeting);\n\n    api.anvil_impersonate_account(impersonate).await.unwrap();\n\n    let res = provider.send_transaction(tx.clone()).await.unwrap().get_receipt().await.unwrap();\n    assert_eq!(res.from, impersonate);\n\n    let balance = provider.get_balance(to).await.unwrap();\n    assert_eq!(balance, val);\n\n    api.anvil_stop_impersonating_account(impersonate).await.unwrap();\n    let res = provider.send_transaction(tx).await;\n    res.unwrap_err();\n\n    let greeting = greeter_contract.greet().call().await.unwrap();\n    assert_eq!(\"Hello World!\", greeting);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_impersonate_gnosis_safe() {\n    let (api, handle) = spawn(fork_config()).await;\n    let provider = handle.http_provider();\n\n    // <https://help.safe.global/en/articles/40824-i-don-t-remember-my-safe-address-where-can-i-find-it>\n    let safe = address!(\"0xA063Cb7CFd8E57c30c788A0572CBbf2129ae56B6\");\n\n    let code = provider.get_code_at(safe).await.unwrap();\n    assert!(!code.is_empty());\n\n    api.anvil_impersonate_account(safe).await.unwrap();\n\n    let code = provider.get_code_at(safe).await.unwrap();\n    assert!(!code.is_empty());\n\n    let balance = U256::from(1e18 as u64);\n    // fund the impersonated account\n    api.anvil_set_balance(safe, balance).await.unwrap();\n\n    let on_chain_balance = provider.get_balance(safe).await.unwrap();\n    assert_eq!(on_chain_balance, balance);\n\n    api.anvil_stop_impersonating_account(safe).await.unwrap();\n\n    let code = provider.get_code_at(safe).await.unwrap();\n    // code is added back after stop impersonating\n    assert!(!code.is_empty());\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_impersonate_multiple_accounts() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n    let provider = handle.http_provider();\n\n    let impersonate0 = Address::random();\n    let impersonate1 = Address::random();\n    let to = Address::random();\n\n    let val = U256::from(1337);\n    let funding = U256::from(1e18 as u64);\n    // fund the impersonated accounts\n    api.anvil_set_balance(impersonate0, funding).await.unwrap();\n    api.anvil_set_balance(impersonate1, funding).await.unwrap();\n\n    let tx = TransactionRequest::default().with_from(impersonate0).to(to).with_value(val);\n    let tx = WithOtherFields::new(tx);\n\n    api.anvil_impersonate_account(impersonate0).await.unwrap();\n    api.anvil_impersonate_account(impersonate1).await.unwrap();\n\n    let res0 = provider.send_transaction(tx.clone()).await.unwrap().get_receipt().await.unwrap();\n    assert_eq!(res0.from, impersonate0);\n\n    let nonce = provider.get_transaction_count(impersonate0).await.unwrap();\n    assert_eq!(nonce, 1);\n\n    let receipt = provider.get_transaction_receipt(res0.transaction_hash).await.unwrap().unwrap();\n    assert_eq!(res0.inner, receipt.inner);\n\n    let res1 = provider\n        .send_transaction(tx.with_from(impersonate1))\n        .await\n        .unwrap()\n        .get_receipt()\n        .await\n        .unwrap();\n\n    assert_eq!(res1.from, impersonate1);\n\n    let nonce = provider.get_transaction_count(impersonate1).await.unwrap();\n    assert_eq!(nonce, 1);\n\n    let receipt = provider.get_transaction_receipt(res1.transaction_hash).await.unwrap().unwrap();\n    assert_eq!(res1.inner, receipt.inner);\n\n    assert_ne!(res0.inner, res1.inner);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_mine_manually() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n    let provider = handle.http_provider();\n\n    let start_num = provider.get_block_number().await.unwrap();\n\n    for (idx, _) in std::iter::repeat_n((), 10).enumerate() {\n        api.evm_mine(None).await.unwrap();\n        let num = provider.get_block_number().await.unwrap();\n        assert_eq!(num, start_num + idx as u64 + 1);\n    }\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_set_next_timestamp() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n    let provider = handle.http_provider();\n\n    let now = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap();\n\n    let next_timestamp = now + Duration::from_secs(60);\n\n    // mock timestamp\n    api.evm_set_next_block_timestamp(next_timestamp.as_secs()).unwrap();\n\n    api.evm_mine(None).await.unwrap();\n\n    let block = provider.get_block(BlockId::default()).await.unwrap().unwrap();\n\n    assert_eq!(block.header.number, 1);\n    assert_eq!(block.header.timestamp, next_timestamp.as_secs());\n\n    api.evm_mine(None).await.unwrap();\n\n    let next = provider.get_block(BlockId::default()).await.unwrap().unwrap();\n    assert_eq!(next.header.number, 2);\n\n    assert!(next.header.timestamp >= block.header.timestamp);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_evm_set_time() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n    let provider = handle.http_provider();\n\n    let now = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap();\n\n    let timestamp = now + Duration::from_secs(120);\n\n    // mock timestamp\n    api.evm_set_time(timestamp.as_secs()).unwrap();\n\n    // mine a block\n    api.evm_mine(None).await.unwrap();\n    let block = provider.get_block(BlockId::default()).await.unwrap().unwrap();\n\n    assert!(block.header.timestamp >= timestamp.as_secs());\n\n    api.evm_mine(None).await.unwrap();\n    let next = provider.get_block(BlockId::default()).await.unwrap().unwrap();\n\n    assert!(next.header.timestamp >= block.header.timestamp);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_evm_set_time_in_past() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n    let provider = handle.http_provider();\n\n    let now = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap();\n\n    let timestamp = now - Duration::from_secs(120);\n\n    // mock timestamp\n    api.evm_set_time(timestamp.as_secs()).unwrap();\n\n    // mine a block\n    api.evm_mine(None).await.unwrap();\n    let block = provider.get_block(BlockId::default()).await.unwrap().unwrap();\n\n    assert!(block.header.timestamp >= timestamp.as_secs());\n    assert!(block.header.timestamp < now.as_secs());\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_timestamp_interval() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n    let provider = handle.http_provider();\n\n    api.evm_mine(None).await.unwrap();\n    let interval = 10;\n\n    for _ in 0..5 {\n        let block = provider.get_block(BlockId::default()).await.unwrap().unwrap();\n\n        // mock timestamp\n        api.evm_set_block_timestamp_interval(interval).unwrap();\n        api.evm_mine(None).await.unwrap();\n\n        let new_block = provider.get_block(BlockId::default()).await.unwrap().unwrap();\n\n        assert_eq!(new_block.header.timestamp, block.header.timestamp + interval);\n    }\n\n    let block = provider.get_block(BlockId::default()).await.unwrap().unwrap();\n\n    let next_timestamp = block.header.timestamp + 50;\n    api.evm_set_next_block_timestamp(next_timestamp).unwrap();\n\n    api.evm_mine(None).await.unwrap();\n    let block = provider.get_block(BlockId::default()).await.unwrap().unwrap();\n    assert_eq!(block.header.timestamp, next_timestamp);\n\n    api.evm_mine(None).await.unwrap();\n\n    let block = provider.get_block(BlockId::default()).await.unwrap().unwrap();\n    // interval also works after setting the next timestamp manually\n    assert_eq!(block.header.timestamp, next_timestamp + interval);\n\n    assert!(api.evm_remove_block_timestamp_interval().unwrap());\n\n    api.evm_mine(None).await.unwrap();\n    let new_block = provider.get_block(BlockId::default()).await.unwrap().unwrap();\n\n    // offset is applied correctly after resetting the interval\n    assert!(new_block.header.timestamp > block.header.timestamp);\n\n    api.evm_mine(None).await.unwrap();\n    let another_block = provider.get_block(BlockId::default()).await.unwrap().unwrap();\n    // check interval is disabled\n    assert!(another_block.header.timestamp - new_block.header.timestamp < interval);\n}\n\n// <https://github.com/foundry-rs/foundry/issues/2341>\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_can_set_storage_bsc_fork() {\n    let (api, handle) =\n        spawn(NodeConfig::test().with_eth_rpc_url(Some(\"https://bsc-dataseed.binance.org/\"))).await;\n    let provider = handle.http_provider();\n\n    let busd_addr = address!(\"0xe9e7CEA3DedcA5984780Bafc599bD69ADd087D56\");\n    let idx = U256::from_str(\"0xa6eef7e35abe7026729641147f7915573c7e97b47efa546f5f6e3230263bcb49\")\n        .unwrap();\n    let value = fixed_bytes!(\"0000000000000000000000000000000000000000000000000000000000003039\");\n\n    api.anvil_set_storage_at(busd_addr, idx, value).await.unwrap();\n    let storage = api.storage_at(busd_addr, idx, None).await.unwrap();\n    assert_eq!(storage, value);\n\n    let busd_contract = BUSD::new(busd_addr, &provider);\n\n    let balance = busd_contract\n        .balanceOf(address!(\"0x0000000000000000000000000000000000000000\"))\n        .call()\n        .await\n        .unwrap();\n    assert_eq!(balance, U256::from(12345u64));\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_get_node_info() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n\n    let node_info = api.anvil_node_info().await.unwrap();\n\n    let provider = handle.http_provider();\n\n    let block_number = provider.get_block_number().await.unwrap();\n    let block = provider.get_block(BlockId::from(block_number)).await.unwrap().unwrap();\n    let hard_fork: &str = SpecId::OSAKA.into();\n\n    let expected_node_info = NodeInfo {\n        current_block_number: 0_u64,\n        current_block_timestamp: 1,\n        current_block_hash: block.header.hash,\n        hard_fork: hard_fork.to_string(),\n        transaction_order: \"fees\".to_owned(),\n        environment: NodeEnvironment {\n            base_fee: U256::from_str(\"0x3b9aca00\").unwrap().to(),\n            chain_id: 0x7a69,\n            gas_limit: U256::from_str(\"0x1c9c380\").unwrap().to(),\n            gas_price: U256::from_str(\"0x77359400\").unwrap().to(),\n        },\n        fork_config: NodeForkConfig {\n            fork_url: None,\n            fork_block_number: None,\n            fork_retry_backoff: None,\n        },\n    };\n\n    assert_eq!(node_info, expected_node_info);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_get_metadata() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n\n    let metadata = api.anvil_metadata().await.unwrap();\n\n    let provider = handle.http_provider();\n\n    let block_number = provider.get_block_number().await.unwrap();\n    let chain_id = provider.get_chain_id().await.unwrap();\n    let block = provider.get_block(BlockId::from(block_number)).await.unwrap().unwrap();\n\n    let expected_metadata = Metadata {\n        latest_block_hash: block.header.hash,\n        latest_block_number: block_number,\n        chain_id,\n        client_version: CLIENT_VERSION.to_string(),\n        instance_id: api.instance_id(),\n        forked_network: None,\n        snapshots: Default::default(),\n    };\n\n    assert_eq!(metadata, expected_metadata);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_get_metadata_on_fork() {\n    let (api, handle) =\n        spawn(NodeConfig::test().with_eth_rpc_url(Some(\"https://bsc-dataseed.binance.org/\"))).await;\n    let provider = handle.http_provider();\n\n    let metadata = api.anvil_metadata().await.unwrap();\n\n    let block_number = provider.get_block_number().await.unwrap();\n    let chain_id = provider.get_chain_id().await.unwrap();\n    let block = provider.get_block(BlockId::from(block_number)).await.unwrap().unwrap();\n\n    let expected_metadata = Metadata {\n        latest_block_hash: block.header.hash,\n        latest_block_number: block_number,\n        chain_id,\n        client_version: CLIENT_VERSION.to_string(),\n        instance_id: api.instance_id(),\n        forked_network: Some(ForkedNetwork {\n            chain_id,\n            fork_block_number: block_number,\n            fork_block_hash: block.header.hash,\n        }),\n        snapshots: Default::default(),\n    };\n\n    assert_eq!(metadata, expected_metadata);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn metadata_changes_on_reset() {\n    let (api, _) =\n        spawn(NodeConfig::test().with_eth_rpc_url(Some(\"https://bsc-dataseed.binance.org/\"))).await;\n\n    let metadata = api.anvil_metadata().await.unwrap();\n    let instance_id = metadata.instance_id;\n\n    api.anvil_reset(Some(Forking { json_rpc_url: None, block_number: None })).await.unwrap();\n\n    let new_metadata = api.anvil_metadata().await.unwrap();\n    let new_instance_id = new_metadata.instance_id;\n\n    assert_ne!(instance_id, new_instance_id);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_get_transaction_receipt() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n    let provider = handle.http_provider();\n\n    // set the base fee\n    let new_base_fee = U256::from(1000);\n    api.anvil_set_next_block_base_fee_per_gas(new_base_fee).await.unwrap();\n\n    // send a EIP-1559 transaction\n    let to = Address::random();\n    let val = U256::from(1337);\n    let tx = TransactionRequest::default().with_to(to).with_value(val);\n    let tx = WithOtherFields::new(tx);\n\n    let receipt = provider.send_transaction(tx.clone()).await.unwrap().get_receipt().await.unwrap();\n\n    // the block should have the new base fee\n    let block = provider.get_block(BlockId::default()).await.unwrap().unwrap();\n    assert_eq!(block.header.base_fee_per_gas.unwrap(), new_base_fee.to::<u64>());\n\n    // mine blocks\n    api.evm_mine(None).await.unwrap();\n\n    // the transaction receipt should have the original effective gas price\n    let new_receipt = provider.get_transaction_receipt(receipt.transaction_hash).await.unwrap();\n    assert_eq!(receipt.effective_gas_price, new_receipt.unwrap().effective_gas_price);\n}\n\n// test can set chain id\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_set_chain_id() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n    let provider = handle.http_provider();\n    let chain_id = provider.get_chain_id().await.unwrap();\n    assert_eq!(chain_id, 31337);\n\n    let chain_id = 1234;\n    api.anvil_set_chain_id(chain_id).await.unwrap();\n\n    let chain_id = provider.get_chain_id().await.unwrap();\n    assert_eq!(chain_id, 1234);\n}\n\n// <https://github.com/foundry-rs/foundry/issues/6096>\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_fork_revert_next_block_timestamp() {\n    let (api, _handle) = spawn(fork_config()).await;\n\n    // Mine a new block, and check the new block gas limit\n    api.mine_one().await;\n    let latest_block = api.block_by_number(BlockNumberOrTag::Latest).await.unwrap().unwrap();\n\n    let state_snapshot = api.evm_snapshot().await.unwrap();\n    api.mine_one().await;\n    api.evm_revert(state_snapshot).await.unwrap();\n    let block = api.block_by_number(BlockNumberOrTag::Latest).await.unwrap().unwrap();\n    assert_eq!(block, latest_block);\n\n    api.mine_one().await;\n    let block = api.block_by_number(BlockNumberOrTag::Latest).await.unwrap().unwrap();\n    assert!(block.header.timestamp >= latest_block.header.timestamp);\n}\n\n// test that after a snapshot revert, the env block is reset\n// to its correct value (block number, etc.)\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_fork_revert_call_latest_block_timestamp() {\n    let (api, handle) = spawn(fork_config()).await;\n    let provider = handle.http_provider();\n\n    // Mine a new block, and check the new block gas limit\n    api.mine_one().await;\n    let latest_block = api.block_by_number(BlockNumberOrTag::Latest).await.unwrap().unwrap();\n\n    let state_snapshot = api.evm_snapshot().await.unwrap();\n    api.mine_one().await;\n    api.evm_revert(state_snapshot).await.unwrap();\n\n    let multicall_contract =\n        Multicall::new(address!(\"0xeefba1e63905ef1d7acba5a8513c70307c1ce441\"), &provider);\n\n    let timestamp = multicall_contract.getCurrentBlockTimestamp().call().await.unwrap();\n    assert_eq!(timestamp, U256::from(latest_block.header.timestamp));\n\n    let difficulty = multicall_contract.getCurrentBlockDifficulty().call().await.unwrap();\n    assert_eq!(difficulty, U256::from(latest_block.header.difficulty));\n\n    let gaslimit = multicall_contract.getCurrentBlockGasLimit().call().await.unwrap();\n    assert_eq!(gaslimit, U256::from(latest_block.header.gas_limit));\n\n    let coinbase = multicall_contract.getCurrentBlockCoinbase().call().await.unwrap();\n    assert_eq!(coinbase, latest_block.header.beneficiary);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_remove_pool_transactions() {\n    let (api, handle) =\n        spawn(NodeConfig::test().with_blocktime(Some(Duration::from_secs(5)))).await;\n\n    let wallet = handle.dev_wallets().next().unwrap();\n    let signer: EthereumWallet = wallet.clone().into();\n    let from = wallet.address();\n\n    let provider = http_provider_with_signer(&handle.http_endpoint(), signer);\n\n    let sender = Address::random();\n    let to = Address::random();\n    let val = U256::from(1337);\n    let tx = TransactionRequest::default().with_from(sender).with_to(to).with_value(val);\n    let tx = WithOtherFields::new(tx);\n\n    provider.send_transaction(tx.with_from(from)).await.unwrap().register().await.unwrap();\n\n    let initial_txs = provider.txpool_inspect().await.unwrap();\n    assert_eq!(initial_txs.pending.len(), 1);\n\n    api.anvil_remove_pool_transactions(wallet.address()).await.unwrap();\n\n    let final_txs = provider.txpool_inspect().await.unwrap();\n    assert_eq!(final_txs.pending.len(), 0);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn flaky_test_reorg() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n    let provider = handle.http_provider();\n\n    let accounts = handle.dev_wallets().collect::<Vec<_>>();\n\n    // Test calls\n    // Populate chain\n    for i in 0..10 {\n        let tx = TransactionRequest::default()\n            .to(accounts[0].address())\n            .value(U256::from(i))\n            .from(accounts[1].address());\n        let tx = WithOtherFields::new(tx);\n        api.send_transaction(tx).await.unwrap();\n\n        let tx = TransactionRequest::default()\n            .to(accounts[1].address())\n            .value(U256::from(i))\n            .from(accounts[2].address());\n        let tx = WithOtherFields::new(tx);\n        api.send_transaction(tx).await.unwrap();\n    }\n\n    // Define transactions\n    let mut txs = vec![];\n    for i in 0..3 {\n        let from = accounts[i].address();\n        let to = accounts[i + 1].address();\n        for j in 0..5 {\n            let tx = TransactionRequest::default().from(from).to(to).value(U256::from(j));\n            txs.push((TransactionData::JSON(tx), i as u64));\n        }\n    }\n\n    let prev_height = provider.get_block_number().await.unwrap();\n    api.anvil_reorg(ReorgOptions { depth: 7, tx_block_pairs: txs }).await.unwrap();\n\n    let reorged_height = provider.get_block_number().await.unwrap();\n    assert_eq!(reorged_height, prev_height);\n\n    // The first 3 reorged blocks should have 5 transactions each\n    for num in 14..17 {\n        let block = provider.get_block_by_number(num.into()).full().await.unwrap();\n        let block = block.unwrap();\n        assert_eq!(block.transactions.len(), 5);\n    }\n\n    // Verify that historic blocks are still accessible\n    for num in (0..14).rev() {\n        let block = provider.get_block_by_number(num.into()).full().await.unwrap();\n        assert!(block.is_some(), \"Historic block {num} should be accessible after reorg\");\n    }\n\n    // Send a few more transaction to verify the chain can still progress\n    for i in 0..3 {\n        let tx = TransactionRequest::default()\n            .to(accounts[0].address())\n            .value(U256::from(i))\n            .from(accounts[1].address());\n        let tx = WithOtherFields::new(tx);\n        api.send_transaction(tx).await.unwrap();\n    }\n\n    // Test reverting code\n    let greeter = abi::Greeter::deploy(provider.clone(), \"Reorg\".to_string()).await.unwrap();\n    api.anvil_reorg(ReorgOptions { depth: 5, tx_block_pairs: vec![] }).await.unwrap();\n    let code = api.get_code(*greeter.address(), Some(BlockId::latest())).await.unwrap();\n    assert_eq!(code, Bytes::default());\n\n    // Test reverting contract storage\n    let storage =\n        abi::SimpleStorage::deploy(provider.clone(), \"initial value\".to_string()).await.unwrap();\n    api.evm_mine(Some(MineOptions::Options { timestamp: None, blocks: Some(5) })).await.unwrap();\n    let _ = storage\n        .setValue(\"ReorgMe\".to_string())\n        .from(accounts[0].address())\n        .send()\n        .await\n        .unwrap()\n        .get_receipt()\n        .await\n        .unwrap();\n    api.anvil_reorg(ReorgOptions { depth: 3, tx_block_pairs: vec![] }).await.unwrap();\n    let value = storage.getValue().call().await.unwrap();\n    assert_eq!(\"initial value\".to_string(), value);\n\n    api.mine_one().await;\n    api.mine_one().await;\n\n    // Test raw transaction data\n    let mut tx = TxEip1559 {\n        chain_id: api.chain_id(),\n        to: TxKind::Call(accounts[1].address()),\n        value: U256::from(100),\n        max_priority_fee_per_gas: 1000000000000,\n        max_fee_per_gas: 10000000000000,\n        gas_limit: 21000,\n        ..Default::default()\n    };\n    let signature = accounts[5].sign_transaction_sync(&mut tx).unwrap();\n    let tx = tx.into_signed(signature);\n    let mut encoded = vec![];\n    tx.eip2718_encode(&mut encoded);\n\n    let pre_bal = provider.get_balance(accounts[5].address()).await.unwrap();\n    api.anvil_reorg(ReorgOptions {\n        depth: 1,\n        tx_block_pairs: vec![(TransactionData::Raw(encoded.into()), 0)],\n    })\n    .await\n    .unwrap();\n    let post_bal = provider.get_balance(accounts[5].address()).await.unwrap();\n    assert_ne!(pre_bal, post_bal);\n\n    // Test reorg depth exceeding current height\n    let res = api.anvil_reorg(ReorgOptions { depth: 100, tx_block_pairs: vec![] }).await;\n    assert!(res.is_err());\n\n    // Test reorg tx pairs exceeds chain length\n    let res = api\n        .anvil_reorg(ReorgOptions {\n            depth: 1,\n            tx_block_pairs: vec![(TransactionData::JSON(TransactionRequest::default()), 10)],\n        })\n        .await;\n    assert!(res.is_err());\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_reorg_blockhash_opcode_consistency() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n    let provider = handle.http_provider();\n\n    let multicall = Multicall::deploy(&provider).await.unwrap();\n\n    api.evm_mine(Some(MineOptions::Options { timestamp: None, blocks: Some(200) })).await.unwrap();\n\n    let tip_before_reorg = api.block_number().unwrap().to::<u64>();\n\n    let mut cached_hashes: Vec<(u64, alloy_primitives::B256, alloy_primitives::B256)> = Vec::new();\n    for i in 1..=10 {\n        let block_num = tip_before_reorg - i;\n        let rpc_hash =\n            provider.get_block_by_number(block_num.into()).await.unwrap().unwrap().header.hash;\n        let opcode_hash = multicall.getBlockHash(U256::from(block_num)).call().await.unwrap();\n        assert_eq!(rpc_hash, opcode_hash, \"RPC and BLOCKHASH opcode should match before reorg\");\n        cached_hashes.push((block_num, rpc_hash, opcode_hash));\n    }\n\n    let tx = TransactionRequest::default();\n    api.anvil_reorg(ReorgOptions {\n        depth: 5,\n        tx_block_pairs: vec![(TransactionData::JSON(tx), 0)],\n    })\n    .await\n    .unwrap();\n\n    api.mine_one().await;\n\n    for (block_num, rpc_before, opcode_before) in &cached_hashes {\n        let rpc_after =\n            provider.get_block_by_number((*block_num).into()).await.unwrap().unwrap().header.hash;\n        let opcode_after = multicall.getBlockHash(U256::from(*block_num)).call().await.unwrap();\n        if *block_num <= tip_before_reorg.saturating_sub(5) {\n            assert_eq!(\n                rpc_after, *rpc_before,\n                \"Block {block_num}: hash should not change for non-reorged blocks\"\n            );\n            assert_eq!(\n                opcode_after, *opcode_before,\n                \"Block {block_num}: BLOCKHASH should not change for non-reorged blocks\"\n            );\n        }\n        assert_eq!(\n            rpc_after, opcode_after,\n            \"Block {block_num}: RPC ({rpc_after}) and BLOCKHASH opcode ({opcode_after}) should match after reorg\"\n        );\n    }\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_reorg_deep_blockhash_consistency() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n    let provider = handle.http_provider();\n\n    let multicall = Multicall::deploy(&provider).await.unwrap();\n\n    // Mine 300 blocks (more than BLOCKHASH limit of 256)\n    api.evm_mine(Some(MineOptions::Options { timestamp: None, blocks: Some(300) })).await.unwrap();\n\n    let tip_before_reorg = api.block_number().unwrap().to::<u64>();\n    assert!(tip_before_reorg > 256, \"Need more than 256 blocks for this test\");\n\n    // Check blocks within the 256 window before reorg\n    let mut cached_hashes: Vec<(u64, alloy_primitives::B256)> = Vec::new();\n    for i in [1, 10, 100, 200, 255] {\n        let block_num = tip_before_reorg - i;\n        let rpc_hash =\n            provider.get_block_by_number(block_num.into()).await.unwrap().unwrap().header.hash;\n        let opcode_hash = multicall.getBlockHash(U256::from(block_num)).call().await.unwrap();\n        assert_eq!(rpc_hash, opcode_hash, \"RPC and BLOCKHASH opcode should match before reorg\");\n        cached_hashes.push((block_num, rpc_hash));\n    }\n\n    // Perform a deep reorg (50 blocks)\n    let tx = TransactionRequest::default();\n    api.anvil_reorg(ReorgOptions {\n        depth: 50,\n        tx_block_pairs: vec![(TransactionData::JSON(tx), 0)],\n    })\n    .await\n    .unwrap();\n\n    api.mine_one().await;\n\n    let tip_after_reorg = api.block_number().unwrap().to::<u64>();\n\n    // Verify blocks still in the 256 window have consistent hashes\n    for (block_num, rpc_before) in &cached_hashes {\n        // Skip blocks that were reorged\n        if *block_num > tip_after_reorg - 50 {\n            continue;\n        }\n        let rpc_after =\n            provider.get_block_by_number((*block_num).into()).await.unwrap().unwrap().header.hash;\n        let opcode_after = multicall.getBlockHash(U256::from(*block_num)).call().await.unwrap();\n        assert_eq!(\n            rpc_after, *rpc_before,\n            \"Block {block_num}: hash should not change for non-reorged blocks\"\n        );\n        assert_eq!(\n            rpc_after, opcode_after,\n            \"Block {block_num}: RPC and BLOCKHASH should match after deep reorg\"\n        );\n    }\n\n    // Verify BLOCKHASH returns 0 for blocks outside the 256 window\n    let old_block = tip_after_reorg.saturating_sub(257);\n    if old_block > 0 {\n        let opcode_hash = multicall.getBlockHash(U256::from(old_block)).call().await.unwrap();\n        assert_eq!(\n            opcode_hash,\n            alloy_primitives::B256::ZERO,\n            \"BLOCKHASH should return 0 for blocks outside 256 window\"\n        );\n    }\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_rollback() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n    let provider = handle.http_provider();\n\n    // Mine 5 blocks\n    for _ in 0..5 {\n        api.mine_one().await;\n    }\n\n    // Get block 4 for later comparison\n    let block4 = provider.get_block(4.into()).await.unwrap().unwrap();\n\n    // Rollback with None should rollback 1 block\n    api.anvil_rollback(None).await.unwrap();\n\n    // Assert we're at block 4 and the block contents are kept the same\n    let head = provider.get_block(BlockId::latest()).await.unwrap().unwrap();\n    assert_eq!(head, block4);\n\n    // Get block 1 for comparison\n    let block1 = provider.get_block(1.into()).await.unwrap().unwrap();\n\n    // Rollback to block 1\n    let depth = 3; // from block 4 to block 1\n    api.anvil_rollback(Some(depth)).await.unwrap();\n\n    // Assert we're at block 1 and the block contents are kept the same\n    let head = provider.get_block(BlockId::latest()).await.unwrap().unwrap();\n    assert_eq!(head, block1);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_arb_get_block() {\n    let (api, _handle) = spawn(NodeConfig::test().with_chain_id(Some(421611u64))).await;\n\n    // Mine two blocks\n    api.mine_one().await;\n    api.mine_one().await;\n\n    let best_number = api.block_number().unwrap().to::<u64>();\n\n    assert_eq!(best_number, 2);\n\n    let block = api.block_by_number(1.into()).await.unwrap().unwrap();\n\n    assert_eq!(block.header.number, 1);\n}\n\n// Set next_block_timestamp same as previous block\n// api.evm_set_next_block_timestamp(0).unwrap();\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_mine_blk_with_prev_timestamp() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n    let provider = handle.http_provider();\n\n    let init_blk = provider.get_block(BlockId::latest()).await.unwrap().unwrap();\n\n    let init_number = init_blk.header.number;\n    let init_timestamp = init_blk.header.timestamp;\n\n    // mock timestamp\n    api.evm_set_next_block_timestamp(init_timestamp).unwrap();\n\n    api.mine_one().await;\n\n    let block = provider.get_block(BlockId::latest()).await.unwrap().unwrap();\n\n    let next_blk_num = block.header.number;\n    let next_blk_timestamp = block.header.timestamp;\n\n    assert_eq!(next_blk_num, init_number + 1);\n    assert_eq!(next_blk_timestamp, init_timestamp);\n\n    // Sleep for 1 second\n    tokio::time::sleep(Duration::from_secs(1)).await;\n\n    // Subsequent block should have a greater timestamp than previous block\n    api.mine_one().await;\n\n    let block = provider.get_block(BlockId::latest()).await.unwrap().unwrap();\n\n    let third_blk_num = block.header.number;\n    let third_blk_timestamp = block.header.timestamp;\n\n    assert_eq!(third_blk_num, init_number + 2);\n    assert_ne!(third_blk_timestamp, next_blk_timestamp);\n    assert!(third_blk_timestamp > next_blk_timestamp);\n}\n\n// increase time by 0 seconds i.e next_block_timestamp = prev_block_timestamp\n// api.evm_increase_time(0).unwrap();\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_increase_time_by_zero() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n    let provider = handle.http_provider();\n\n    let init_blk = provider.get_block(BlockId::latest()).await.unwrap().unwrap();\n\n    let init_number = init_blk.header.number;\n    let init_timestamp = init_blk.header.timestamp;\n\n    let _ = api.evm_increase_time(U256::ZERO).await;\n\n    api.mine_one().await;\n\n    let block = provider.get_block(BlockId::latest()).await.unwrap().unwrap();\n\n    let next_blk_num = block.header.number;\n    let next_blk_timestamp = block.header.timestamp;\n\n    assert_eq!(next_blk_num, init_number + 1);\n    assert_eq!(next_blk_timestamp, init_timestamp);\n}\n\n// evm_mine(MineOptions::Timestamp(prev_block_timestamp))\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn evm_mine_blk_with_same_timestamp() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n    let provider = handle.http_provider();\n\n    let init_blk = provider.get_block(BlockId::latest()).await.unwrap().unwrap();\n\n    let init_number = init_blk.header.number;\n    let init_timestamp = init_blk.header.timestamp;\n\n    api.evm_mine(Some(MineOptions::Timestamp(Some(init_timestamp)))).await.unwrap();\n\n    let block = provider.get_block(BlockId::latest()).await.unwrap().unwrap();\n\n    let next_blk_num = block.header.number;\n    let next_blk_timestamp = block.header.timestamp;\n\n    assert_eq!(next_blk_num, init_number + 1);\n    assert_eq!(next_blk_timestamp, init_timestamp);\n}\n\n// mine 4 blocks instantly.\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_mine_blk_with_same_timestamp() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n    let provider = handle.http_provider();\n\n    let init_blk = provider.get_block(BlockId::latest()).await.unwrap().unwrap();\n\n    let init_number = init_blk.header.number;\n    let init_timestamp = init_blk.header.timestamp;\n\n    // Mine 4 blocks instantly\n    let _ = api.anvil_mine(Some(U256::from(4)), None).await;\n\n    let latest_blk_num = api.block_number().unwrap().to::<u64>();\n\n    assert_eq!(latest_blk_num, init_number + 4);\n\n    let mut blk_futs = vec![];\n    for i in 1..=4 {\n        blk_futs.push(provider.get_block(i.into()).into_future());\n    }\n\n    let timestamps = futures::future::join_all(blk_futs)\n        .await\n        .into_iter()\n        .map(|blk| blk.unwrap().unwrap().header.timestamp)\n        .collect::<Vec<_>>();\n\n    // All timestamps should be equal. Allow for 1 second difference.\n    assert!(timestamps.windows(2).all(|w| w[0] == w[1]), \"{timestamps:#?}\");\n    assert!(\n        timestamps[0] == init_timestamp || timestamps[0] == init_timestamp + 1,\n        \"{timestamps:#?} != {init_timestamp}\"\n    );\n}\n\n// <https://github.com/foundry-rs/foundry/issues/8962>\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_mine_first_block_with_interval() {\n    let (api, _) = spawn(NodeConfig::test()).await;\n\n    let init_block = api.block_by_number(0.into()).await.unwrap().unwrap();\n    let init_timestamp = init_block.header.timestamp;\n\n    // Mine 2 blocks with interval of 60.\n    let _ = api.anvil_mine(Some(U256::from(2)), Some(U256::from(60))).await;\n\n    let first_block = api.block_by_number(1.into()).await.unwrap().unwrap();\n    assert_eq!(first_block.header.timestamp, init_timestamp + 60);\n\n    let second_block = api.block_by_number(2.into()).await.unwrap().unwrap();\n    assert_eq!(second_block.header.timestamp, init_timestamp + 120);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_anvil_reset_non_fork() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n    let provider = handle.http_provider();\n\n    // Get initial state\n    let init_block = provider.get_block(BlockId::latest()).await.unwrap().unwrap();\n    let init_accounts = api.accounts().unwrap();\n    let init_balance = provider.get_balance(init_accounts[0]).await.unwrap();\n\n    // Store the instance id before reset\n    let instance_id_before = api.instance_id();\n\n    // Mine some blocks and make transactions\n    for _ in 0..5 {\n        api.mine_one().await;\n    }\n\n    // Send a transaction\n    let to = Address::random();\n    let val = U256::from(1337);\n    let tx = TransactionRequest::default().with_from(init_accounts[0]).with_to(to).with_value(val);\n    let tx = WithOtherFields::new(tx);\n\n    let _ = provider.send_transaction(tx).await.unwrap().get_receipt().await.unwrap();\n\n    // Check state has changed\n    let block_before_reset = provider.get_block(BlockId::latest()).await.unwrap().unwrap();\n    assert!(block_before_reset.header.number > init_block.header.number);\n\n    let balance_before_reset = provider.get_balance(init_accounts[0]).await.unwrap();\n    assert!(balance_before_reset < init_balance);\n\n    let to_balance_before_reset = provider.get_balance(to).await.unwrap();\n    assert_eq!(to_balance_before_reset, val);\n\n    // Reset to fresh in-memory state (non-fork)\n    api.anvil_reset(None).await.unwrap();\n\n    // Check instance id has changed\n    let instance_id_after = api.instance_id();\n    assert_ne!(instance_id_before, instance_id_after);\n\n    // Check we're back at genesis\n    let block_after_reset = provider.get_block(BlockId::latest()).await.unwrap().unwrap();\n    assert_eq!(block_after_reset.header.number, 0);\n\n    // Check accounts are restored to initial state\n    let balance_after_reset = provider.get_balance(init_accounts[0]).await.unwrap();\n    assert_eq!(balance_after_reset, init_balance);\n\n    // Check the recipient's balance is zero\n    let to_balance_after_reset = provider.get_balance(to).await.unwrap();\n    assert_eq!(to_balance_after_reset, U256::ZERO);\n\n    // Test we can continue mining after reset\n    api.mine_one().await;\n    let new_block = provider.get_block(BlockId::latest()).await.unwrap().unwrap();\n    assert_eq!(new_block.header.number, 1);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_anvil_reset_fork_to_non_fork() {\n    let (api, handle) = spawn(fork_config()).await;\n    let provider = handle.http_provider();\n\n    // Verify we're in fork mode\n    let metadata = api.anvil_metadata().await.unwrap();\n    assert!(metadata.forked_network.is_some());\n\n    // Mine some blocks\n    for _ in 0..3 {\n        api.mine_one().await;\n    }\n\n    // Reset to non-fork mode\n    api.anvil_reset(None).await.unwrap();\n\n    // Verify we're no longer in fork mode\n    let metadata_after = api.anvil_metadata().await.unwrap();\n    assert!(metadata_after.forked_network.is_none());\n\n    // Check we're at block 0\n    let block = provider.get_block(BlockId::latest()).await.unwrap().unwrap();\n    assert_eq!(block.header.number, 0);\n\n    // Verify we can still mine blocks\n    api.mine_one().await;\n    let new_block = provider.get_block(BlockId::latest()).await.unwrap().unwrap();\n    assert_eq!(new_block.header.number, 1);\n}\n"
  },
  {
    "path": "crates/anvil/tests/it/api.rs",
    "content": "//! general eth api tests\n\nuse crate::{\n    abi::{Multicall, SimpleStorage, VendingMachine},\n    utils::{connect_pubsub_with_wallet, http_provider, http_provider_with_signer},\n};\nuse alloy_consensus::{\n    BlobTransactionSidecar, SidecarBuilder, SignableTransaction, SimpleCoder, Transaction,\n    TxEip1559,\n};\nuse alloy_network::{\n    EthereumWallet, ReceiptResponse, TransactionBuilder, TransactionBuilder4844, TxSignerSync,\n};\nuse alloy_primitives::{\n    Address, B256, ChainId, U256, b256, bytes,\n    map::{AddressHashMap, B256HashMap, HashMap},\n};\nuse alloy_provider::Provider;\nuse alloy_rpc_types::{\n    BlockId, BlockNumberOrTag, BlockTransactions, request::TransactionRequest,\n    state::AccountOverride,\n};\nuse alloy_serde::WithOtherFields;\nuse alloy_sol_types::SolCall;\nuse anvil::{CHAIN_ID, EthereumHardfork, NodeConfig, eth::api::CLIENT_VERSION, spawn};\nuse foundry_test_utils::rpc;\nuse futures::join;\nuse std::time::Duration;\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_get_block_number() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n\n    let block_num = api.block_number().unwrap();\n    assert_eq!(block_num, U256::from(0));\n\n    let provider = handle.http_provider();\n\n    let num = provider.get_block_number().await.unwrap();\n    assert_eq!(num, block_num.to::<u64>());\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_dev_get_balance() {\n    let (_api, handle) = spawn(NodeConfig::test()).await;\n    let provider = handle.http_provider();\n\n    let genesis_balance = handle.genesis_balance();\n    for acc in handle.genesis_accounts() {\n        let balance = provider.get_balance(acc).await.unwrap();\n        assert_eq!(balance, genesis_balance);\n    }\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_get_price() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n    let provider = handle.http_provider();\n\n    let gas_price = provider.get_gas_price().await.unwrap();\n    assert!(gas_price > 0);\n    assert_eq!(gas_price, api.gas_price());\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_get_accounts() {\n    let (_api, handle) = spawn(NodeConfig::test()).await;\n    let provider = handle.http_provider();\n\n    let accounts = provider.get_accounts().await.unwrap();\n    let dev_accounts: Vec<_> = handle.dev_accounts().collect();\n    assert_eq!(accounts.len(), dev_accounts.len());\n    for account in dev_accounts {\n        assert!(accounts.contains(&account), \"Missing dev account {account}\");\n    }\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_get_client_version() {\n    let (_api, handle) = spawn(NodeConfig::test()).await;\n    let provider = handle.http_provider();\n\n    let version = provider.get_client_version().await.unwrap();\n    assert_eq!(CLIENT_VERSION, version);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_get_chain_id() {\n    let (_api, handle) = spawn(NodeConfig::test()).await;\n    let provider = handle.http_provider();\n\n    let chain_id = provider.get_chain_id().await.unwrap();\n    assert_eq!(chain_id, CHAIN_ID);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_modify_chain_id() {\n    let (_api, handle) =\n        spawn(NodeConfig::test().with_chain_id(Some(ChainId::from(777_u64)))).await;\n    let provider = handle.http_provider();\n\n    let chain_id = provider.get_chain_id().await.unwrap();\n    assert_eq!(chain_id, 777);\n\n    let chain_id = provider.get_net_version().await.unwrap();\n    assert_eq!(chain_id, 777);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_get_network_id() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n    let provider = handle.http_provider();\n\n    let network_id = api.network_id().unwrap().unwrap();\n    assert_eq!(network_id, CHAIN_ID.to_string());\n\n    let provider_network_id = provider.get_net_version().await.unwrap();\n    assert_eq!(provider_network_id, CHAIN_ID);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_get_block_by_number() {\n    let (_api, handle) = spawn(NodeConfig::test()).await;\n\n    let accounts: Vec<_> = handle.dev_wallets().collect();\n    let signer: EthereumWallet = accounts[0].clone().into();\n    let from = accounts[0].address();\n    let to = accounts[1].address();\n\n    let provider = http_provider_with_signer(&handle.http_endpoint(), signer);\n\n    let val = handle.genesis_balance().checked_div(U256::from(2)).unwrap();\n\n    // send a dummy transaction\n    let tx = TransactionRequest::default().with_from(from).with_to(to).with_value(val);\n    let tx = WithOtherFields::new(tx);\n\n    provider.send_transaction(tx.clone()).await.unwrap().get_receipt().await.unwrap();\n\n    let block = provider.get_block(BlockId::number(1)).full().await.unwrap().unwrap();\n    assert_eq!(block.transactions.len(), 1);\n\n    let block = provider.get_block(BlockId::hash(block.header.hash)).full().await.unwrap().unwrap();\n    assert_eq!(block.transactions.len(), 1);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_get_pending_block() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n\n    let accounts: Vec<_> = handle.dev_wallets().collect();\n    let signer: EthereumWallet = accounts[0].clone().into();\n    let from = accounts[0].address();\n    let to = accounts[1].address();\n\n    let provider = connect_pubsub_with_wallet(&handle.http_endpoint(), signer).await;\n\n    let block = provider.get_block(BlockId::pending()).await.unwrap().unwrap();\n    assert_eq!(block.header.number, 1);\n\n    let num = provider.get_block_number().await.unwrap();\n    assert_eq!(num, 0);\n\n    api.anvil_set_auto_mine(false).await.unwrap();\n\n    let tx = TransactionRequest::default().with_from(from).with_to(to).with_value(U256::from(100));\n\n    let pending = provider.send_transaction(tx.clone()).await.unwrap().register().await.unwrap();\n\n    let num = provider.get_block_number().await.unwrap();\n    assert_eq!(num, 0);\n\n    let block = provider.get_block(BlockId::pending()).await.unwrap().unwrap();\n    assert_eq!(block.header.number, 1);\n    assert_eq!(block.transactions.len(), 1);\n    assert_eq!(block.transactions, BlockTransactions::Hashes(vec![*pending.tx_hash()]));\n\n    let block = provider.get_block(BlockId::pending()).full().await.unwrap().unwrap();\n    assert_eq!(block.header.number, 1);\n    assert_eq!(block.transactions.len(), 1);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_estimate_gas_with_undersized_max_fee_per_gas() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n    let wallet = handle.dev_wallets().next().unwrap();\n    let signer: EthereumWallet = wallet.clone().into();\n\n    let provider = http_provider_with_signer(&handle.http_endpoint(), signer);\n\n    api.anvil_set_auto_mine(true).await.unwrap();\n\n    let init_value = \"toto\".to_string();\n\n    let simple_storage_contract =\n        SimpleStorage::deploy(&provider, init_value.clone()).await.unwrap();\n\n    let undersized_max_fee_per_gas = 1;\n\n    let latest_block = api.block_by_number(BlockNumberOrTag::Latest).await.unwrap().unwrap();\n    let latest_block_base_fee_per_gas = latest_block.header.base_fee_per_gas.unwrap();\n\n    assert!(undersized_max_fee_per_gas < latest_block_base_fee_per_gas);\n\n    let estimated_gas = simple_storage_contract\n        .setValue(\"new_value\".to_string())\n        .max_fee_per_gas(undersized_max_fee_per_gas.into())\n        .from(wallet.address())\n        .estimate_gas()\n        .await\n        .unwrap();\n\n    assert!(estimated_gas > 0);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_call_on_pending_block() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n\n    let wallet = handle.dev_wallets().next().unwrap();\n    let signer: EthereumWallet = wallet.clone().into();\n    let sender = wallet.address();\n\n    let provider = http_provider_with_signer(&handle.http_endpoint(), signer);\n\n    let num = provider.get_block_number().await.unwrap();\n    assert_eq!(num, 0);\n\n    api.anvil_set_auto_mine(false).await.unwrap();\n\n    let _contract_pending = Multicall::deploy_builder(&provider)\n        .from(wallet.address())\n        .send()\n        .await\n        .unwrap()\n        .register()\n        .await\n        .unwrap();\n    let contract_address = sender.create(0);\n    let contract = Multicall::new(contract_address, &provider);\n\n    let num = provider.get_block_number().await.unwrap();\n    assert_eq!(num, 0);\n\n    // Ensure that we can get the block_number from the pending contract\n    let Multicall::aggregateReturn { blockNumber: ret_block_number, .. } =\n        contract.aggregate(vec![]).block(BlockId::pending()).call().await.unwrap();\n    assert_eq!(ret_block_number, U256::from(1));\n\n    let accounts: Vec<Address> = handle.dev_wallets().map(|w| w.address()).collect();\n\n    for i in 1..10 {\n        api.anvil_set_coinbase(accounts[i % accounts.len()]).await.unwrap();\n        api.evm_set_block_gas_limit(U256::from(30_000_000 + i)).unwrap();\n\n        api.anvil_mine(Some(U256::from(1)), None).await.unwrap();\n        tokio::time::sleep(Duration::from_millis(100)).await;\n    }\n\n    // Ensure that the right header values are set when calling a past block\n    for anvil_block_number in 1..(api.block_number().unwrap().to::<usize>() + 1) {\n        let block_number = BlockNumberOrTag::Number(anvil_block_number as u64);\n        let block = api.block_by_number(block_number).await.unwrap().unwrap();\n\n        let ret_timestamp = contract\n            .getCurrentBlockTimestamp()\n            .block(BlockId::number(anvil_block_number as u64))\n            .call()\n            .await\n            .unwrap();\n        assert_eq!(block.header.timestamp, ret_timestamp.to::<u64>());\n\n        let ret_gas_limit = contract\n            .getCurrentBlockGasLimit()\n            .block(BlockId::number(anvil_block_number as u64))\n            .call()\n            .await\n            .unwrap();\n        assert_eq!(block.header.gas_limit, ret_gas_limit.to::<u64>());\n\n        let ret_coinbase = contract\n            .getCurrentBlockCoinbase()\n            .block(BlockId::number(anvil_block_number as u64))\n            .call()\n            .await\n            .unwrap();\n        assert_eq!(block.header.beneficiary, ret_coinbase);\n    }\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_call_with_undersized_max_fee_per_gas() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n    let wallet = handle.dev_wallets().next().unwrap();\n    let signer: EthereumWallet = wallet.clone().into();\n\n    let provider = http_provider_with_signer(&handle.http_endpoint(), signer);\n\n    api.anvil_set_auto_mine(true).await.unwrap();\n\n    let init_value = \"toto\".to_string();\n\n    let simple_storage_contract =\n        SimpleStorage::deploy(&provider, init_value.clone()).await.unwrap();\n\n    let latest_block = api.block_by_number(BlockNumberOrTag::Latest).await.unwrap().unwrap();\n    let latest_block_base_fee_per_gas = latest_block.header.base_fee_per_gas.unwrap();\n    let undersized_max_fee_per_gas = 1;\n\n    assert!(undersized_max_fee_per_gas < latest_block_base_fee_per_gas);\n\n    let last_sender = simple_storage_contract\n        .lastSender()\n        .max_fee_per_gas(undersized_max_fee_per_gas.into())\n        .from(wallet.address())\n        .call()\n        .await\n        .unwrap();\n    assert_eq!(last_sender, Address::ZERO);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_call_with_state_override() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n    let wallet = handle.dev_wallets().next().unwrap();\n    let signer: EthereumWallet = wallet.clone().into();\n    let account = wallet.address();\n\n    let provider = http_provider_with_signer(&handle.http_endpoint(), signer);\n\n    api.anvil_set_auto_mine(true).await.unwrap();\n\n    let multicall_contract = Multicall::deploy(&provider).await.unwrap();\n\n    let init_value = \"toto\".to_string();\n\n    let simple_storage_contract =\n        SimpleStorage::deploy(&provider, init_value.clone()).await.unwrap();\n\n    // Test the `balance` account override\n    let balance = U256::from(42u64);\n    let mut overrides = AddressHashMap::default();\n    overrides.insert(account, AccountOverride { balance: Some(balance), ..Default::default() });\n    let result = multicall_contract.getEthBalance(account).state(overrides).call().await.unwrap();\n    assert_eq!(result, balance);\n\n    // Test the `state_diff` account override\n    let mut state_diff = B256HashMap::default();\n    state_diff.insert(B256::ZERO, account.into_word());\n    let mut overrides = AddressHashMap::default();\n    overrides.insert(\n        *simple_storage_contract.address(),\n        AccountOverride {\n            // The `lastSender` is in the first storage slot\n            state_diff: Some(state_diff),\n            ..Default::default()\n        },\n    );\n\n    let last_sender =\n        simple_storage_contract.lastSender().state(HashMap::default()).call().await.unwrap();\n    // No `sender` set without override\n    assert_eq!(last_sender, Address::ZERO);\n\n    let last_sender =\n        simple_storage_contract.lastSender().state(overrides.clone()).call().await.unwrap();\n    // `sender` *is* set with override\n    assert_eq!(last_sender, account);\n\n    let value = simple_storage_contract.getValue().state(overrides).call().await.unwrap();\n    // `value` *is not* changed with state-diff\n    assert_eq!(value, init_value);\n\n    // Test the `state` account override\n    let mut state = B256HashMap::default();\n    state.insert(B256::ZERO, account.into_word());\n    let mut overrides = AddressHashMap::default();\n    overrides.insert(\n        *simple_storage_contract.address(),\n        AccountOverride {\n            // The `lastSender` is in the first storage slot\n            state: Some(state),\n            ..Default::default()\n        },\n    );\n\n    let last_sender =\n        simple_storage_contract.lastSender().state(overrides.clone()).call().await.unwrap();\n    // `sender` *is* set with override\n    assert_eq!(last_sender, account);\n\n    let value = simple_storage_contract.getValue().state(overrides).call().await.unwrap();\n    // `value` *is* changed with state\n    assert_eq!(value, \"\");\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_mine_while_mining() {\n    let (api, _) = spawn(NodeConfig::test()).await;\n\n    let total_blocks = 200;\n\n    let block_number =\n        api.block_by_number(BlockNumberOrTag::Latest).await.unwrap().unwrap().header.number;\n    assert_eq!(block_number, 0);\n\n    let block = api.block_by_number(BlockNumberOrTag::Number(block_number)).await.unwrap().unwrap();\n    assert_eq!(block.header.number, 0);\n\n    let result = join!(\n        api.anvil_mine(Some(U256::from(total_blocks / 2)), None),\n        api.anvil_mine(Some(U256::from(total_blocks / 2)), None)\n    );\n    result.0.unwrap();\n    result.1.unwrap();\n    tokio::time::sleep(Duration::from_millis(100)).await;\n\n    let block_number =\n        api.block_by_number(BlockNumberOrTag::Latest).await.unwrap().unwrap().header.number;\n    assert_eq!(block_number, total_blocks);\n\n    let block = api.block_by_number(BlockNumberOrTag::Number(block_number)).await.unwrap().unwrap();\n    assert_eq!(block.header.number, total_blocks);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_send_raw_tx_sync() {\n    let node_config = NodeConfig::test().with_hardfork(Some(EthereumHardfork::Prague.into()));\n    let (api, handle) = spawn(node_config).await;\n    let provider = http_provider(&handle.http_endpoint());\n\n    let wallets = handle.dev_wallets().collect::<Vec<_>>();\n    let eip1559_est = provider.estimate_eip1559_fees().await.unwrap();\n\n    let from = wallets[0].address();\n    let mut tx = TxEip1559 {\n        max_fee_per_gas: eip1559_est.max_fee_per_gas,\n        max_priority_fee_per_gas: eip1559_est.max_priority_fee_per_gas,\n        gas_limit: 100000,\n        chain_id: 31337,\n        to: alloy_primitives::TxKind::Call(from),\n        input: bytes!(\"11112222\"),\n        ..Default::default()\n    };\n    let signature = wallets[1].sign_transaction_sync(&mut tx).unwrap();\n\n    let tx = tx.into_signed(signature);\n    let mut encoded = Vec::new();\n    tx.eip2718_encode(&mut encoded);\n\n    let receipt = api.send_raw_transaction_sync(encoded.into()).await.unwrap();\n    assert_eq!(receipt.from(), wallets[1].address());\n    assert_eq!(receipt.to(), tx.to());\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_send_tx_sync() {\n    let node_config = NodeConfig::test().with_hardfork(Some(EthereumHardfork::Prague.into()));\n    let (api, handle) = spawn(node_config).await;\n\n    let wallets = handle.dev_wallets().collect::<Vec<_>>();\n    let logger_bytecode = bytes!(\"66365f5f37365fa05f5260076019f3\");\n\n    let from = wallets[0].address();\n    let tx = TransactionRequest::default()\n        .with_from(from)\n        .into_create()\n        .with_nonce(0)\n        .with_input(logger_bytecode);\n\n    let receipt = api.send_transaction_sync(WithOtherFields::new(tx)).await.unwrap();\n    assert_eq!(receipt.from(), wallets[0].address());\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\n#[ignore = \"no debug_\"]\nasync fn can_get_code_by_hash() {\n    let (api, _) =\n        spawn(NodeConfig::test().with_eth_rpc_url(Some(rpc::next_http_archive_rpc_url()))).await;\n\n    // The code hash for DEFAULT_CREATE2_DEPLOYER_RUNTIME_CODE\n    let code_hash = b256!(\"2fa86add0aed31f33a762c9d88e807c475bd51d0f52bd0955754b2608f7e4989\");\n\n    let code = api.debug_code_by_hash(code_hash, None).await.unwrap();\n    assert_eq!(&code.unwrap(), foundry_evm::constants::DEFAULT_CREATE2_DEPLOYER_RUNTIME_CODE);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_fill_transaction_fills_chain_id() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n    let wallet = handle.dev_wallets().next().unwrap();\n    let from = wallet.address();\n\n    let tx_req = TransactionRequest::default()\n        .with_from(from)\n        .with_to(Address::random())\n        .with_gas_limit(21_000);\n\n    let filled = api.fill_transaction(WithOtherFields::new(tx_req)).await.unwrap();\n\n    // Should fill with the chain id from provider\n    assert!(filled.tx.chain_id().is_some());\n    assert_eq!(filled.tx.chain_id().unwrap(), CHAIN_ID);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_fill_transaction_fills_nonce() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n\n    let accounts: Vec<_> = handle.dev_wallets().collect();\n    let signer: EthereumWallet = accounts[0].clone().into();\n    let from = accounts[0].address();\n    let to = accounts[1].address();\n\n    let provider = http_provider_with_signer(&handle.http_endpoint(), signer);\n\n    // Send a transaction to increment nonce\n    let tx = TransactionRequest::default().with_from(from).with_to(to).with_value(U256::from(100));\n    let tx = WithOtherFields::new(tx);\n    provider.send_transaction(tx).await.unwrap().get_receipt().await.unwrap();\n\n    // Now the account should have nonce 1\n    let tx_req = TransactionRequest::default()\n        .with_from(from)\n        .with_to(to)\n        .with_value(U256::from(1000))\n        .with_gas_limit(21_000);\n\n    let filled = api.fill_transaction(WithOtherFields::new(tx_req)).await.unwrap();\n\n    assert_eq!(filled.tx.nonce(), 1);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_fill_transaction_preserves_provided_fields() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n    let wallet = handle.dev_wallets().next().unwrap();\n    let from = wallet.address();\n\n    let provided_nonce = 100u64;\n    let provided_gas_limit = 50_000u64;\n\n    let tx_req = TransactionRequest::default()\n        .with_from(from)\n        .with_to(Address::random())\n        .with_value(U256::from(1000))\n        .with_nonce(provided_nonce)\n        .with_gas_limit(provided_gas_limit);\n\n    let filled = api.fill_transaction(WithOtherFields::new(tx_req)).await.unwrap();\n\n    // Should preserve the provided nonce and gas limit\n    assert_eq!(filled.tx.nonce(), provided_nonce);\n    assert_eq!(filled.tx.gas_limit(), provided_gas_limit);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_fill_transaction_fills_all_missing_fields() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n    let wallet = handle.dev_wallets().next().unwrap();\n    let from = wallet.address();\n\n    // Create a simple transfer transaction with minimal fields\n    let tx_req = TransactionRequest::default().with_from(from).with_to(Address::random());\n\n    let filled = api.fill_transaction(WithOtherFields::new(tx_req)).await.unwrap();\n\n    // Should fill all required fields and be EIP-1559\n    assert!(filled.tx.is_eip1559());\n    assert!(filled.tx.gas_limit() > 0);\n    assert!(filled.tx.max_fee_per_gas() > 0);\n    assert!(filled.tx.max_priority_fee_per_gas().is_some());\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_fill_transaction_eip4844_blob_fee() {\n    let node_config = NodeConfig::test().with_hardfork(Some(EthereumHardfork::Cancun.into()));\n    let (api, handle) = spawn(node_config).await;\n    let wallet = handle.dev_wallets().next().unwrap();\n    let from = wallet.address();\n\n    let mut builder = SidecarBuilder::<SimpleCoder>::new();\n    builder.ingest(b\"dummy blob\");\n    let sidecar: BlobTransactionSidecar = builder.build().unwrap();\n\n    // EIP-4844 blob transaction with sidecar but no blob fee\n    let mut tx_req = TransactionRequest::default().with_from(from).with_to(Address::random());\n    tx_req.sidecar = Some(sidecar.into());\n    tx_req.transaction_type = Some(3); // EIP-4844\n\n    let filled = api.fill_transaction(WithOtherFields::new(tx_req)).await.unwrap();\n\n    // Blob transaction should have max_fee_per_blob_gas filled\n    assert!(\n        filled.tx.max_fee_per_blob_gas().is_some(),\n        \"max_fee_per_blob_gas should be filled for blob tx\"\n    );\n    assert!(filled.tx.blob_versioned_hashes().is_some(), \"blob_versioned_hashes should be present\");\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_fill_transaction_eip4844_preserves_blob_fee() {\n    let node_config = NodeConfig::test().with_hardfork(Some(EthereumHardfork::Cancun.into()));\n    let (api, handle) = spawn(node_config).await;\n    let wallet = handle.dev_wallets().next().unwrap();\n    let from = wallet.address();\n\n    let provided_blob_fee = 5_000_000u128;\n\n    let mut builder = SidecarBuilder::<SimpleCoder>::new();\n    builder.ingest(b\"dummy blob\");\n    let sidecar: BlobTransactionSidecar = builder.build().unwrap();\n\n    // EIP-4844 blob transaction with blob fee already set\n    let mut tx_req = TransactionRequest::default()\n        .with_from(from)\n        .with_to(Address::random())\n        .with_max_fee_per_blob_gas(provided_blob_fee);\n    tx_req.sidecar = Some(sidecar.into());\n    tx_req.transaction_type = Some(3); // EIP-4844\n\n    let filled = api.fill_transaction(WithOtherFields::new(tx_req)).await.unwrap();\n\n    // Should preserve the provided blob fee\n    assert_eq!(\n        filled.tx.max_fee_per_blob_gas(),\n        Some(provided_blob_fee),\n        \"should preserve provided max_fee_per_blob_gas\"\n    );\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_fill_transaction_non_blob_tx_no_blob_fee() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n    let wallet = handle.dev_wallets().next().unwrap();\n    let from = wallet.address();\n\n    // EIP-1559 transaction without blob fields\n    let mut tx_req = TransactionRequest::default().with_from(from).with_to(Address::random());\n    tx_req.transaction_type = Some(2); // EIP-1559\n\n    let filled = api.fill_transaction(WithOtherFields::new(tx_req)).await.unwrap();\n\n    // Non-blob transaction should NOT have blob fee filled\n    assert!(\n        filled.tx.max_fee_per_blob_gas().is_none(),\n        \"max_fee_per_blob_gas should not be set for non-blob tx\"\n    );\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_fill_transaction_reverts_on_gas_estimation_failure() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n\n    let accounts: Vec<_> = handle.dev_wallets().collect();\n    let signer: EthereumWallet = accounts[0].clone().into();\n    let from = accounts[0].address();\n\n    let provider = http_provider_with_signer(&handle.http_endpoint(), signer);\n\n    // Deploy VendingMachine contract\n    let contract = VendingMachine::deploy(&provider).await.unwrap();\n    let contract_address = *contract.address();\n\n    // Call buy function with insufficient ether\n    let tx_req = TransactionRequest::default()\n        .with_from(from)\n        .with_to(contract_address)\n        .with_input(VendingMachine::buyCall { amount: U256::from(10) }.abi_encode());\n\n    // fill_transaction should fail because gas estimation fails due to revert\n    let result = api.fill_transaction(WithOtherFields::new(tx_req)).await;\n\n    assert!(result.is_err(), \"fill_transaction should return an error when gas estimation fails\");\n    let error_message = result.unwrap_err().to_string();\n    assert!(\n        error_message.contains(\"execution reverted\"),\n        \"Error should indicate a revert, got: {error_message}\"\n    );\n}\n"
  },
  {
    "path": "crates/anvil/tests/it/beacon_api.rs",
    "content": "use crate::utils::http_provider;\nuse alloy_consensus::{Blob, BlobTransactionSidecar, SidecarBuilder, SimpleCoder, Transaction};\nuse alloy_network::{TransactionBuilder, TransactionBuilder4844};\nuse alloy_primitives::{B256, FixedBytes, U256, b256};\nuse alloy_provider::Provider;\nuse alloy_rpc_types::TransactionRequest;\nuse alloy_rpc_types_beacon::{genesis::GenesisResponse, sidecar::GetBlobsResponse};\nuse alloy_serde::WithOtherFields;\nuse anvil::{NodeConfig, spawn};\nuse foundry_evm::hardfork::EthereumHardfork;\nuse ssz::Decode;\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_beacon_api_get_blob_sidecars() {\n    let node_config = NodeConfig::test().with_hardfork(Some(EthereumHardfork::Cancun.into()));\n    let (_api, handle) = spawn(node_config).await;\n\n    // Test Beacon API endpoint using HTTP client\n    let client = reqwest::Client::new();\n    let url = format!(\"{}/eth/v1/beacon/blob_sidecars/latest\", handle.http_endpoint());\n\n    // This endpoint is deprecated, so we expect a 410 Gone response\n    let response = client.get(&url).send().await.unwrap();\n    assert_eq!(\n        response.text().await.unwrap(),\n        r#\"{\"code\":410,\"message\":\"This endpoint is deprecated. Use `GET /eth/v1/beacon/blobs/{block_id}` instead.\"}\"#,\n        \"Expected deprecation message for blob_sidecars endpoint\"\n    );\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_beacon_api_get_blobs() {\n    let node_config = NodeConfig::test().with_hardfork(Some(EthereumHardfork::Cancun.into()));\n    let (api, handle) = spawn(node_config).await;\n\n    // Disable auto-mining so we can include multiple transactions in the same block\n    api.anvil_set_auto_mine(false).await.unwrap();\n\n    let wallets = handle.dev_wallets().collect::<Vec<_>>();\n    let from = wallets[0].address();\n    let to = wallets[1].address();\n\n    let provider = http_provider(&handle.http_endpoint());\n\n    let eip1559_est = provider.estimate_eip1559_fees().await.unwrap();\n    let gas_price = provider.get_gas_price().await.unwrap();\n\n    // Create multiple blob transactions to be included in the same block\n    let blob_data =\n        [b\"Hello Beacon API - Blob 1\", b\"Hello Beacon API - Blob 2\", b\"Hello Beacon API - Blob 3\"];\n\n    let mut pending_txs = Vec::new();\n\n    // Send all transactions without waiting for receipts\n    for (i, data) in blob_data.iter().enumerate() {\n        let sidecar: SidecarBuilder<SimpleCoder> = SidecarBuilder::from_slice(data.as_slice());\n        let sidecar = sidecar.build::<BlobTransactionSidecar>().unwrap();\n\n        let tx = TransactionRequest::default()\n            .with_from(from)\n            .with_to(to)\n            .with_nonce(i as u64)\n            .with_max_fee_per_blob_gas(gas_price + 1)\n            .with_max_fee_per_gas(eip1559_est.max_fee_per_gas)\n            .with_max_priority_fee_per_gas(eip1559_est.max_priority_fee_per_gas)\n            .with_blob_sidecar_4844(sidecar)\n            .value(U256::from(100));\n\n        let tx = WithOtherFields::new(tx);\n\n        let pending = provider.send_transaction(tx).await.unwrap();\n        pending_txs.push(pending);\n    }\n\n    // Mine a block to include all transactions\n    api.evm_mine(None).await.unwrap();\n\n    // Get receipts for all transactions\n    let mut receipts = Vec::new();\n    for pending in pending_txs {\n        let receipt = pending.get_receipt().await.unwrap();\n        receipts.push(receipt);\n    }\n\n    // Verify all transactions were included in the same block\n    let block_number = receipts[0].block_number.unwrap();\n    for (i, receipt) in receipts.iter().enumerate() {\n        assert_eq!(\n            receipt.block_number.unwrap(),\n            block_number,\n            \"Transaction {i} was not included in block {block_number}\"\n        );\n    }\n\n    // Extract the actual versioned hashes from the mined transactions\n    let mut actual_versioned_hashes = Vec::new();\n    for receipt in &receipts {\n        let tx = provider.get_transaction_by_hash(receipt.transaction_hash).await.unwrap().unwrap();\n        if let Some(blob_versioned_hashes) = tx.blob_versioned_hashes() {\n            actual_versioned_hashes.extend(blob_versioned_hashes.iter().copied());\n        }\n    }\n\n    // Test Beacon API endpoint using HTTP client\n    let client = reqwest::Client::new();\n    let url = format!(\"{}/eth/v1/beacon/blobs/{}\", handle.http_endpoint(), block_number);\n\n    let response = client.get(&url).send().await.unwrap();\n    assert_eq!(response.status(), reqwest::StatusCode::OK);\n    assert_eq!(\n        response.headers().get(\"content-type\").and_then(|h| h.to_str().ok()),\n        Some(\"application/json\"),\n        \"Expected application/json content-type header\"\n    );\n\n    let blobs_response: GetBlobsResponse = response.json().await.unwrap();\n    // Verify response structure\n    assert!(!blobs_response.execution_optimistic);\n    assert!(!blobs_response.finalized);\n\n    // Verify we have blob data from all transactions\n    assert_eq!(blobs_response.data.len(), 3, \"Expected 3 blobs from 3 transactions\");\n\n    // Test response with SSZ encoding\n    let url = format!(\"{}/eth/v1/beacon/blobs/{}\", handle.http_endpoint(), block_number);\n    let response = client\n        .get(&url)\n        .header(axum::http::header::ACCEPT, \"application/octet-stream\")\n        .send()\n        .await\n        .unwrap();\n    assert_eq!(response.status(), reqwest::StatusCode::OK);\n    assert_eq!(\n        response.headers().get(\"content-type\").and_then(|h| h.to_str().ok()),\n        Some(\"application/octet-stream\"),\n        \"Expected application/octet-stream content-type header\"\n    );\n\n    let body_bytes = response.bytes().await.unwrap();\n\n    // Decode the SSZ-encoded blobs in a spawned thread with larger stack to handle recursion\n    let decoded_blobs = std::thread::Builder::new()\n        .stack_size(8 * 1024 * 1024) // 8MB stack for SSZ decoding of large blobs\n        .spawn(move || Vec::<Blob>::from_ssz_bytes(&body_bytes))\n        .expect(\"Failed to spawn decode thread\")\n        .join()\n        .expect(\"Decode thread panicked\")\n        .expect(\"Failed to decode SSZ-encoded blobs\");\n\n    // Verify we got exactly 3 blobs\n    assert_eq!(\n        decoded_blobs.len(),\n        3,\n        \"Expected 3 blobs from SSZ-encoded response, got {}\",\n        decoded_blobs.len()\n    );\n\n    // Verify the decoded blobs match the JSON response blobs\n    for (i, (decoded, json)) in decoded_blobs.iter().zip(blobs_response.data.iter()).enumerate() {\n        assert_eq!(decoded, json, \"Blob {i} mismatch between SSZ and JSON responses\");\n    }\n\n    // Test filtering with versioned_hashes query parameter - single hash\n    let url = format!(\n        \"{}/eth/v1/beacon/blobs/{}?versioned_hashes={}\",\n        handle.http_endpoint(),\n        block_number,\n        actual_versioned_hashes[1]\n    );\n    let response = client.get(&url).send().await.unwrap();\n    let status = response.status();\n    if status != reqwest::StatusCode::OK {\n        let error_body = response.text().await.unwrap();\n        panic!(\"Expected OK status, got {status}: {error_body}\");\n    }\n    let blobs_response: GetBlobsResponse = response.json().await.unwrap();\n    assert_eq!(\n        blobs_response.data.len(),\n        1,\n        \"Expected 1 blob when filtering by single versioned_hash\"\n    );\n\n    // Test filtering with versioned_hashes query parameter - multiple versioned_hashes\n    // (comma-separated)\n    let url = format!(\n        \"{}/eth/v1/beacon/blobs/{}?versioned_hashes={},{}\",\n        handle.http_endpoint(),\n        block_number,\n        actual_versioned_hashes[0],\n        actual_versioned_hashes[2]\n    );\n    let response = client.get(&url).send().await.unwrap();\n    assert_eq!(response.status(), reqwest::StatusCode::OK);\n    let blobs_response: GetBlobsResponse = response.json().await.unwrap();\n    assert_eq!(\n        blobs_response.data.len(),\n        2,\n        \"Expected 2 blobs when filtering by two versioned_hashes\"\n    );\n\n    // Test filtering with non-existent versioned_hash\n    let non_existent_hash =\n        b256!(\"0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\");\n    let url = format!(\n        \"{}/eth/v1/beacon/blobs/{}?versioned_hashes={}\",\n        handle.http_endpoint(),\n        block_number,\n        non_existent_hash\n    );\n    let response = client.get(&url).send().await.unwrap();\n    assert_eq!(response.status(), reqwest::StatusCode::OK);\n    let blobs_response: GetBlobsResponse = response.json().await.unwrap();\n    assert_eq!(\n        blobs_response.data.len(),\n        0,\n        \"Expected 0 blobs when filtering by non-existent versioned_hash\"\n    );\n\n    // Test with special block identifiers\n    let test_ids = vec![\"latest\", \"finalized\", \"safe\", \"earliest\"];\n    for block_id in test_ids {\n        let url = format!(\"{}/eth/v1/beacon/blobs/{}\", handle.http_endpoint(), block_id);\n        assert_eq!(client.get(&url).send().await.unwrap().status(), reqwest::StatusCode::OK);\n    }\n    let url = format!(\"{}/eth/v1/beacon/blobs/pending\", handle.http_endpoint());\n    assert_eq!(client.get(&url).send().await.unwrap().status(), reqwest::StatusCode::NOT_FOUND);\n\n    // Test with hex block number\n    let url = format!(\"{}/eth/v1/beacon/blobs/0x{block_number:x}\", handle.http_endpoint());\n    let response = client.get(&url).send().await.unwrap();\n    assert_eq!(response.status(), reqwest::StatusCode::OK);\n\n    // Test with non-existent block\n    let url = format!(\"{}/eth/v1/beacon/blobs/999999\", handle.http_endpoint());\n    let response = client.get(&url).send().await.unwrap();\n    assert_eq!(response.status(), reqwest::StatusCode::NOT_FOUND);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_beacon_api_get_genesis() {\n    let node_config = NodeConfig::test().with_hardfork(Some(EthereumHardfork::Cancun.into()));\n    let (_api, handle) = spawn(node_config).await;\n\n    // Test Beacon API genesis endpoint using HTTP client\n    let client = reqwest::Client::new();\n    let url = format!(\"{}/eth/v1/beacon/genesis\", handle.http_endpoint());\n\n    let response = client.get(&url).send().await.unwrap();\n    assert_eq!(response.status(), reqwest::StatusCode::OK);\n\n    let genesis_response: GenesisResponse = response.json().await.unwrap();\n\n    assert!(genesis_response.data.genesis_time > 0);\n    assert_eq!(genesis_response.data.genesis_validators_root, B256::ZERO);\n    assert_eq!(\n        genesis_response.data.genesis_fork_version,\n        FixedBytes::from([0x00, 0x00, 0x00, 0x00])\n    );\n}\n"
  },
  {
    "path": "crates/anvil/tests/it/eip2935.rs",
    "content": "use crate::utils::http_provider;\nuse alloy_eips::{BlockNumberOrTag, eip2935::HISTORY_STORAGE_ADDRESS};\nuse alloy_network::TransactionBuilder;\nuse alloy_primitives::U256;\nuse alloy_provider::Provider;\nuse alloy_rpc_types::TransactionRequest;\nuse anvil::{NodeConfig, spawn};\nuse foundry_evm::hardfork::EthereumHardfork;\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn eip2935_contract_deployed_at_genesis() {\n    let node_config = NodeConfig::test().with_hardfork(Some(EthereumHardfork::Prague.into()));\n    let (_api, handle) = spawn(node_config).await;\n    let provider = http_provider(&handle.http_endpoint());\n\n    let code = provider.get_code_at(HISTORY_STORAGE_ADDRESS).await.unwrap();\n    assert!(!code.is_empty(), \"EIP-2935 history storage contract should be deployed at genesis\");\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn eip2935_stores_parent_block_hash() {\n    let node_config = NodeConfig::test().with_hardfork(Some(EthereumHardfork::Prague.into()));\n    let (api, handle) = spawn(node_config).await;\n    let provider = http_provider(&handle.http_endpoint());\n\n    // Mine a few blocks so there are parent hashes to store\n    api.mine_one().await;\n    api.mine_one().await;\n    api.mine_one().await;\n\n    // Block 1's hash should be stored when block 2 was mined\n    let block1 = provider\n        .get_block_by_number(BlockNumberOrTag::from(1))\n        .await\n        .unwrap()\n        .expect(\"block 1 should exist\");\n    let block1_hash = block1.header.hash;\n\n    // Query the history storage contract for block 1's hash.\n    // The EIP-2935 contract uses raw calldata (not ABI-encoded): pass the block number\n    // as a 32-byte big-endian word directly.\n    let call_data: [u8; 32] = U256::from(1).to_be_bytes();\n    let tx = TransactionRequest::default().with_to(HISTORY_STORAGE_ADDRESS).with_input(call_data);\n    let result = provider.call(tx.into()).await.unwrap();\n\n    let stored_hash = alloy_primitives::B256::from_slice(&result);\n    assert_eq!(stored_hash, block1_hash, \"EIP-2935 contract should store parent block hash\");\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn eip2935_no_system_call_on_genesis() {\n    let node_config = NodeConfig::test().with_hardfork(Some(EthereumHardfork::Prague.into()));\n    let (_api, handle) = spawn(node_config).await;\n    let provider = http_provider(&handle.http_endpoint());\n\n    // At genesis (block 0), the contract should exist but no system call should have\n    // written any parent hash into its storage. Check raw storage slot 0 directly.\n    let slot = provider.get_storage_at(HISTORY_STORAGE_ADDRESS, U256::from(0)).await.unwrap();\n    assert_eq!(slot, U256::ZERO, \"No hash should be stored in the contract at genesis\");\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn eip2935_not_deployed_before_prague() {\n    let node_config = NodeConfig::test().with_hardfork(Some(EthereumHardfork::Cancun.into()));\n    let (_api, handle) = spawn(node_config).await;\n    let provider = http_provider(&handle.http_endpoint());\n\n    let code = provider.get_code_at(HISTORY_STORAGE_ADDRESS).await.unwrap();\n    assert!(code.is_empty(), \"EIP-2935 contract should NOT be deployed before Prague\");\n}\n"
  },
  {
    "path": "crates/anvil/tests/it/eip4844.rs",
    "content": "use crate::utils::{http_provider, http_provider_with_signer};\nuse alloy_consensus::{BlobTransactionSidecar, SidecarBuilder, SimpleCoder, Transaction};\nuse alloy_eips::{\n    Typed2718,\n    eip4844::{BLOB_TX_MIN_BLOB_GASPRICE, DATA_GAS_PER_BLOB, MAX_DATA_GAS_PER_BLOCK_DENCUN},\n};\nuse alloy_network::{EthereumWallet, ReceiptResponse, TransactionBuilder, TransactionBuilder4844};\nuse alloy_primitives::{Address, U256, b256};\nuse alloy_provider::{Provider, ProviderBuilder};\nuse alloy_rpc_types::{BlockId, TransactionRequest};\nuse alloy_serde::WithOtherFields;\nuse anvil::{NodeConfig, spawn};\nuse foundry_evm::hardfork::EthereumHardfork;\nuse foundry_test_utils::rpc;\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_send_eip4844_transaction() {\n    let node_config = NodeConfig::test().with_hardfork(Some(EthereumHardfork::Cancun.into()));\n    let (_api, handle) = spawn(node_config).await;\n\n    let wallets = handle.dev_wallets().collect::<Vec<_>>();\n    let from = wallets[0].address();\n    let to = wallets[1].address();\n    let provider = http_provider(&handle.http_endpoint());\n\n    let eip1559_est = provider.estimate_eip1559_fees().await.unwrap();\n    let gas_price = provider.get_gas_price().await.unwrap();\n\n    let sidecar: SidecarBuilder<SimpleCoder> = SidecarBuilder::from_slice(b\"Hello World\");\n\n    let sidecar = sidecar.build().unwrap();\n    let tx = TransactionRequest::default()\n        .with_from(from)\n        .with_to(to)\n        .with_nonce(0)\n        .with_max_fee_per_blob_gas(gas_price + 1)\n        .with_max_fee_per_gas(eip1559_est.max_fee_per_gas)\n        .with_max_priority_fee_per_gas(eip1559_est.max_priority_fee_per_gas)\n        .with_blob_sidecar_4844(sidecar)\n        .value(U256::from(5));\n\n    let tx = WithOtherFields::new(tx);\n\n    let receipt = provider.send_transaction(tx).await.unwrap().get_receipt().await.unwrap();\n\n    assert_eq!(receipt.blob_gas_used, Some(131072));\n    assert_eq!(receipt.blob_gas_price, Some(0x1)); // 1 wei\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_send_eip4844_transaction_fork() {\n    let node_config = NodeConfig::test()\n        .with_eth_rpc_url(Some(rpc::next_http_archive_rpc_url()))\n        .with_fork_block_number(Some(23432306u64))\n        .with_hardfork(Some(EthereumHardfork::Cancun.into()));\n    let (api, handle) = spawn(node_config).await;\n    let provider = handle.http_provider();\n    let accounts = provider.get_accounts().await.unwrap();\n    let alice = accounts[0];\n    let bob = accounts[1];\n\n    let sidecar: SidecarBuilder<SimpleCoder> = SidecarBuilder::from_slice(b\"Blobs are fun!\");\n    let sidecar: BlobTransactionSidecar = sidecar.build().unwrap();\n\n    let tx = TransactionRequest::default()\n        .with_from(alice)\n        .with_to(bob)\n        .with_blob_sidecar_4844(sidecar.clone());\n\n    let pending_tx = provider.send_transaction(tx.into()).await.unwrap();\n    let receipt = pending_tx.get_receipt().await.unwrap();\n    let tx_hash = receipt.transaction_hash;\n\n    let _blobs = api.anvil_get_blob_by_tx_hash(tx_hash).unwrap().unwrap();\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_send_eip4844_transaction_eth_send_transaction() {\n    let node_config = NodeConfig::test()\n        .with_eth_rpc_url(Some(rpc::next_http_archive_rpc_url()))\n        .with_fork_block_number(Some(23552208u64))\n        .with_hardfork(Some(EthereumHardfork::Cancun.into()));\n    let (api, handle) = spawn(node_config).await;\n    let provider = ProviderBuilder::new().connect(handle.http_endpoint().as_str()).await.unwrap();\n    let accounts = provider.get_accounts().await.unwrap();\n    let alice = accounts[0];\n    let bob = accounts[1];\n\n    let sidecar: SidecarBuilder<SimpleCoder> = SidecarBuilder::from_slice(b\"Blobs are fun!\");\n    let sidecar: BlobTransactionSidecar = sidecar.build().unwrap();\n\n    let tx = TransactionRequest::default()\n        .with_from(alice)\n        .with_to(bob)\n        .with_blob_sidecar_4844(sidecar.clone());\n\n    let pending_tx = provider.send_transaction(tx).await.unwrap();\n    let receipt = pending_tx.get_receipt().await.unwrap();\n    let tx_hash = receipt.transaction_hash;\n\n    let _blobs = api.anvil_get_blob_by_tx_hash(tx_hash).unwrap().unwrap();\n}\n\n// <https://github.com/foundry-rs/foundry/issues/13217>\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_send_eip4844_transaction_with_eip7594_sidecar_format() {\n    let node_config = NodeConfig::test().with_hardfork(Some(EthereumHardfork::Osaka.into()));\n    let (api, handle) = spawn(node_config).await;\n    let provider = ProviderBuilder::new().connect(handle.http_endpoint().as_str()).await.unwrap();\n    let accounts = provider.get_accounts().await.unwrap();\n    let alice = accounts[0];\n    let bob = accounts[1];\n\n    let sidecar: SidecarBuilder<SimpleCoder> = SidecarBuilder::from_slice(b\"Blobs are fun!\");\n    let sidecar = sidecar.build_7594().unwrap();\n\n    let tx =\n        TransactionRequest::default().with_from(alice).with_to(bob).with_blob_sidecar_7594(sidecar);\n\n    let pending_tx = provider.send_transaction(tx).await.unwrap();\n    let receipt = pending_tx.get_receipt().await.unwrap();\n    let tx_hash = receipt.transaction_hash;\n\n    let _blobs = api.anvil_get_blob_by_tx_hash(tx_hash).unwrap().unwrap();\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_send_multiple_blobs_in_one_tx() {\n    let node_config = NodeConfig::test().with_hardfork(Some(EthereumHardfork::Cancun.into()));\n    let (_api, handle) = spawn(node_config).await;\n\n    let wallets = handle.dev_wallets().collect::<Vec<_>>();\n\n    let from = wallets[0].address();\n    let to = wallets[1].address();\n\n    let provider = http_provider(&handle.http_endpoint());\n\n    let eip1559_est = provider.estimate_eip1559_fees().await.unwrap();\n    let gas_price = provider.get_gas_price().await.unwrap();\n\n    let large_data = vec![1u8; DATA_GAS_PER_BLOB as usize * 5]; // 131072 is DATA_GAS_PER_BLOB and also BYTE_PER_BLOB\n    let sidecar: SidecarBuilder<SimpleCoder> = SidecarBuilder::from_slice(&large_data);\n\n    let sidecar = sidecar.build().unwrap();\n\n    let tx = TransactionRequest::default()\n        .with_from(from)\n        .with_to(to)\n        .with_nonce(0)\n        .with_max_fee_per_blob_gas(gas_price + 1)\n        .with_max_fee_per_gas(eip1559_est.max_fee_per_gas)\n        .with_max_priority_fee_per_gas(eip1559_est.max_priority_fee_per_gas)\n        .with_blob_sidecar_4844(sidecar);\n    let tx = WithOtherFields::new(tx);\n\n    let receipt = provider.send_transaction(tx).await.unwrap().get_receipt().await.unwrap();\n\n    assert_eq!(receipt.blob_gas_used, Some(MAX_DATA_GAS_PER_BLOCK_DENCUN));\n    assert_eq!(receipt.blob_gas_price, Some(0x1)); // 1 wei\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn cannot_exceed_six_blobs() {\n    let node_config = NodeConfig::test().with_hardfork(Some(EthereumHardfork::Cancun.into()));\n    let (_api, handle) = spawn(node_config).await;\n\n    let wallets = handle.dev_wallets().collect::<Vec<_>>();\n\n    let from = wallets[0].address();\n    let to = wallets[1].address();\n\n    let provider = http_provider(&handle.http_endpoint());\n\n    let eip1559_est = provider.estimate_eip1559_fees().await.unwrap();\n    let gas_price = provider.get_gas_price().await.unwrap();\n\n    let large_data = vec![1u8; DATA_GAS_PER_BLOB as usize * 6]; // 131072 is DATA_GAS_PER_BLOB and also BYTE_PER_BLOB\n    let sidecar: SidecarBuilder<SimpleCoder> = SidecarBuilder::from_slice(&large_data);\n\n    let sidecar = sidecar.build().unwrap();\n\n    let tx = TransactionRequest::default()\n        .with_from(from)\n        .with_to(to)\n        .with_nonce(0)\n        .with_max_fee_per_blob_gas(gas_price + 1)\n        .with_max_fee_per_gas(eip1559_est.max_fee_per_gas)\n        .with_max_priority_fee_per_gas(eip1559_est.max_priority_fee_per_gas)\n        .with_blob_sidecar_4844(sidecar);\n    let tx = WithOtherFields::new(tx);\n\n    let err = provider.send_transaction(tx).await.unwrap_err();\n\n    assert!(err.to_string().contains(\"too many blobs\"));\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_mine_blobs_when_exceeds_max_blobs() {\n    let node_config = NodeConfig::test().with_hardfork(Some(EthereumHardfork::Cancun.into()));\n    let (api, handle) = spawn(node_config).await;\n    api.anvil_set_auto_mine(false).await.unwrap();\n\n    let wallets = handle.dev_wallets().collect::<Vec<_>>();\n\n    let from = wallets[0].address();\n    let to = wallets[1].address();\n\n    let provider = http_provider(&handle.http_endpoint());\n\n    let eip1559_est = provider.estimate_eip1559_fees().await.unwrap();\n    let gas_price = provider.get_gas_price().await.unwrap();\n\n    let first_batch = vec![1u8; DATA_GAS_PER_BLOB as usize * 3];\n    let sidecar: SidecarBuilder<SimpleCoder> = SidecarBuilder::from_slice(&first_batch);\n\n    let num_blobs_first = sidecar.clone().take().len() as u64;\n\n    let sidecar = sidecar.build().unwrap();\n\n    let tx = TransactionRequest::default()\n        .with_from(from)\n        .with_to(to)\n        .with_nonce(0)\n        .with_max_fee_per_blob_gas(gas_price + 1)\n        .with_max_fee_per_gas(eip1559_est.max_fee_per_gas)\n        .with_max_priority_fee_per_gas(eip1559_est.max_priority_fee_per_gas)\n        .with_blob_sidecar_4844(sidecar);\n    let mut tx = WithOtherFields::new(tx);\n\n    let first_tx = provider.send_transaction(tx.clone()).await.unwrap();\n\n    let second_batch = vec![1u8; DATA_GAS_PER_BLOB as usize * 2];\n\n    let sidecar: SidecarBuilder<SimpleCoder> = SidecarBuilder::from_slice(&second_batch);\n\n    let num_blobs_second = sidecar.clone().take().len() as u64;\n\n    let sidecar = sidecar.build().unwrap();\n    tx.set_blob_sidecar_4844(sidecar);\n    tx.set_nonce(1);\n    let second_tx = provider.send_transaction(tx).await.unwrap();\n\n    api.mine_one().await;\n\n    let first_receipt = first_tx.get_receipt().await.unwrap();\n\n    api.mine_one().await;\n    let second_receipt = second_tx.get_receipt().await.unwrap();\n\n    let (first_block, second_block) = tokio::join!(\n        provider.get_block_by_number(first_receipt.block_number.unwrap().into()),\n        provider.get_block_by_number(second_receipt.block_number.unwrap().into())\n    );\n    assert_eq!(\n        first_block.unwrap().unwrap().header.blob_gas_used,\n        Some(DATA_GAS_PER_BLOB * num_blobs_first)\n    );\n\n    assert_eq!(\n        second_block.unwrap().unwrap().header.blob_gas_used,\n        Some(DATA_GAS_PER_BLOB * num_blobs_second)\n    );\n    // Mined in two different blocks\n    assert_eq!(first_receipt.block_number.unwrap() + 1, second_receipt.block_number.unwrap());\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_check_blob_fields_on_genesis() {\n    let node_config = NodeConfig::test().with_hardfork(Some(EthereumHardfork::Cancun.into()));\n    let (_api, handle) = spawn(node_config).await;\n\n    let provider = http_provider(&handle.http_endpoint());\n\n    let block = provider.get_block(BlockId::latest()).await.unwrap().unwrap();\n\n    assert_eq!(block.header.blob_gas_used, Some(0));\n    assert_eq!(block.header.excess_blob_gas, Some(0));\n}\n\n#[expect(clippy::disallowed_macros)]\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_correctly_estimate_blob_gas_with_recommended_fillers() {\n    let node_config = NodeConfig::test().with_hardfork(Some(EthereumHardfork::Cancun.into()));\n    let (_api, handle) = spawn(node_config).await;\n\n    let provider = http_provider(&handle.http_endpoint());\n\n    let accounts = provider.get_accounts().await.unwrap();\n    let alice = accounts[0];\n    let bob = accounts[1];\n\n    let sidecar: SidecarBuilder<SimpleCoder> = SidecarBuilder::from_slice(b\"Blobs are fun!\");\n    let sidecar = sidecar.build().unwrap();\n\n    let tx = TransactionRequest::default().with_to(bob).with_blob_sidecar_4844(sidecar);\n    let tx = WithOtherFields::new(tx);\n\n    // Send the transaction and wait for the broadcast.\n    let pending_tx = provider.send_transaction(tx).await.unwrap();\n\n    println!(\"Pending transaction... {}\", pending_tx.tx_hash());\n\n    // Wait for the transaction to be included and get the receipt.\n    let receipt = pending_tx.get_receipt().await.unwrap();\n\n    // Grab the processed transaction.\n    let tx = provider.get_transaction_by_hash(receipt.transaction_hash).await.unwrap().unwrap();\n\n    println!(\n        \"Transaction included in block {}\",\n        receipt.block_number.expect(\"Failed to get block number\")\n    );\n\n    assert!(tx.max_fee_per_blob_gas().unwrap() >= BLOB_TX_MIN_BLOB_GASPRICE);\n    assert_eq!(receipt.from, alice);\n    assert_eq!(receipt.to, Some(bob));\n    assert_eq!(\n        receipt.blob_gas_used.expect(\"Expected to be EIP-4844 transaction\"),\n        DATA_GAS_PER_BLOB\n    );\n}\n\n#[expect(clippy::disallowed_macros)]\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_correctly_estimate_blob_gas_with_recommended_fillers_with_signer() {\n    let node_config = NodeConfig::test().with_hardfork(Some(EthereumHardfork::Cancun.into()));\n    let (_api, handle) = spawn(node_config).await;\n\n    let signer = handle.dev_wallets().next().unwrap();\n    let wallet: EthereumWallet = signer.clone().into();\n\n    let provider = http_provider_with_signer(&handle.http_endpoint(), wallet);\n\n    let accounts = provider.get_accounts().await.unwrap();\n    let alice = accounts[0];\n    let bob = accounts[1];\n\n    let sidecar: SidecarBuilder<SimpleCoder> = SidecarBuilder::from_slice(b\"Blobs are fun!\");\n    let sidecar = sidecar.build().unwrap();\n\n    let tx = TransactionRequest::default().with_to(bob).with_blob_sidecar_4844(sidecar);\n    let tx = WithOtherFields::new(tx);\n\n    // Send the transaction and wait for the broadcast.\n    let pending_tx = provider.send_transaction(tx).await.unwrap();\n\n    println!(\"Pending transaction... {}\", pending_tx.tx_hash());\n\n    // Wait for the transaction to be included and get the receipt.\n    let receipt = pending_tx.get_receipt().await.unwrap();\n\n    // Grab the processed transaction.\n    let tx = provider.get_transaction_by_hash(receipt.transaction_hash).await.unwrap().unwrap();\n\n    println!(\n        \"Transaction included in block {}\",\n        receipt.block_number.expect(\"Failed to get block number\")\n    );\n\n    assert!(tx.max_fee_per_blob_gas().unwrap() >= BLOB_TX_MIN_BLOB_GASPRICE);\n    assert_eq!(receipt.from, alice);\n    assert_eq!(receipt.to, Some(bob));\n    assert_eq!(\n        receipt.blob_gas_used.expect(\"Expected to be EIP-4844 transaction\"),\n        DATA_GAS_PER_BLOB\n    );\n}\n\n// <https://github.com/foundry-rs/foundry/issues/9924>\n#[tokio::test]\nasync fn can_bypass_sidecar_requirement() {\n    crate::init_tracing();\n    let node_config = NodeConfig::test()\n        .with_hardfork(Some(EthereumHardfork::Cancun.into()))\n        .with_auto_impersonate(true);\n    let (api, handle) = spawn(node_config).await;\n    let provider = http_provider(&handle.http_endpoint());\n\n    let eip1559_est = provider.estimate_eip1559_fees().await.unwrap();\n    let gas_price = provider.get_gas_price().await.unwrap();\n\n    let from = Address::random();\n    let to = Address::random();\n\n    api.anvil_set_balance(from, U256::from(60262144030131080_u128)).await.unwrap();\n\n    let tx = TransactionRequest {\n        from: Some(from),\n        to: Some(alloy_primitives::TxKind::Call(to)),\n        nonce: Some(0),\n        value: Some(U256::from(0)),\n        max_fee_per_blob_gas: Some(gas_price + 1),\n        max_fee_per_gas: Some(eip1559_est.max_fee_per_gas),\n        max_priority_fee_per_gas: Some(eip1559_est.max_priority_fee_per_gas),\n        blob_versioned_hashes: Some(vec![b256!(\n            \"0x01d5446006b21888d0267829344ab8624fdf1b425445a8ae1ca831bf1b8fbcd4\"\n        )]),\n        sidecar: None,\n        transaction_type: Some(3),\n        ..Default::default()\n    };\n\n    let receipt = provider\n        .send_transaction(WithOtherFields::new(tx))\n        .await\n        .unwrap()\n        .get_receipt()\n        .await\n        .unwrap();\n\n    assert!(receipt.status());\n\n    let tx = provider.get_transaction_by_hash(receipt.transaction_hash).await.unwrap().unwrap();\n\n    assert_eq!(tx.inner.ty(), 3);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_get_blobs_by_versioned_hash() {\n    let node_config = NodeConfig::test().with_hardfork(Some(EthereumHardfork::Prague.into()));\n    let (api, handle) = spawn(node_config).await;\n\n    let wallets = handle.dev_wallets().collect::<Vec<_>>();\n    let from = wallets[0].address();\n    let to = wallets[1].address();\n    let provider = http_provider(&handle.http_endpoint());\n\n    let eip1559_est = provider.estimate_eip1559_fees().await.unwrap();\n    let gas_price = provider.get_gas_price().await.unwrap();\n\n    let sidecar: SidecarBuilder<SimpleCoder> = SidecarBuilder::from_slice(b\"Hello World\");\n\n    let sidecar: BlobTransactionSidecar = sidecar.build().unwrap();\n    let tx = TransactionRequest::default()\n        .with_from(from)\n        .with_to(to)\n        .with_nonce(0)\n        .with_max_fee_per_blob_gas(gas_price + 1)\n        .with_max_fee_per_gas(eip1559_est.max_fee_per_gas)\n        .with_max_priority_fee_per_gas(eip1559_est.max_priority_fee_per_gas)\n        .with_blob_sidecar_4844(sidecar.clone())\n        .value(U256::from(5));\n\n    let tx = WithOtherFields::new(tx);\n\n    let _receipt = provider.send_transaction(tx).await.unwrap().get_receipt().await.unwrap();\n\n    let hash = sidecar.versioned_hash_for_blob(0).unwrap();\n    // api.anvil_set_auto_mine(true).await.unwrap();\n    let blob = api.anvil_get_blob_by_versioned_hash(hash).unwrap().unwrap();\n    assert_eq!(blob, sidecar.blobs[0]);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_get_blobs_by_tx_hash() {\n    let node_config = NodeConfig::test().with_hardfork(Some(EthereumHardfork::Prague.into()));\n    let (api, handle) = spawn(node_config).await;\n\n    let wallets = handle.dev_wallets().collect::<Vec<_>>();\n    let from = wallets[0].address();\n    let to = wallets[1].address();\n    let provider = http_provider(&handle.http_endpoint());\n\n    let eip1559_est = provider.estimate_eip1559_fees().await.unwrap();\n    let gas_price = provider.get_gas_price().await.unwrap();\n\n    let sidecar: SidecarBuilder<SimpleCoder> = SidecarBuilder::from_slice(b\"Hello World\");\n\n    let sidecar: BlobTransactionSidecar = sidecar.build().unwrap();\n    let tx = TransactionRequest::default()\n        .with_from(from)\n        .with_to(to)\n        .with_nonce(0)\n        .with_max_fee_per_blob_gas(gas_price + 1)\n        .with_max_fee_per_gas(eip1559_est.max_fee_per_gas)\n        .with_max_priority_fee_per_gas(eip1559_est.max_priority_fee_per_gas)\n        .with_blob_sidecar_4844(sidecar.clone())\n        .value(U256::from(5));\n\n    let tx = WithOtherFields::new(tx);\n    let receipt = provider.send_transaction(tx).await.unwrap().get_receipt().await.unwrap();\n    let hash = receipt.transaction_hash;\n    api.anvil_set_auto_mine(true).await.unwrap();\n    let blobs = api.anvil_get_blob_by_tx_hash(hash).unwrap().unwrap();\n    assert_eq!(blobs, sidecar.blobs);\n}\n"
  },
  {
    "path": "crates/anvil/tests/it/eip7702.rs",
    "content": "use crate::utils::http_provider;\nuse alloy_consensus::{SignableTransaction, transaction::TxEip7702};\nuse alloy_network::{ReceiptResponse, TransactionBuilder, TxSignerSync};\nuse alloy_primitives::{U256, bytes};\nuse alloy_provider::{PendingTransactionConfig, Provider};\nuse alloy_rpc_types::{Authorization, TransactionRequest};\nuse alloy_serde::WithOtherFields;\nuse alloy_signer::{Signature, SignerSync};\nuse anvil::{NodeConfig, spawn};\nuse foundry_evm::hardfork::EthereumHardfork;\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_send_eip7702_tx() {\n    let node_config = NodeConfig::test().with_hardfork(Some(EthereumHardfork::Prague.into()));\n    let (_api, handle) = spawn(node_config).await;\n    let provider = http_provider(&handle.http_endpoint());\n\n    let wallets = handle.dev_wallets().collect::<Vec<_>>();\n\n    // deploy simple contract forwarding calldata to LOG0\n    // PUSH7(CALLDATASIZE PUSH0 PUSH0 CALLDATACOPY CALLDATASIZE PUSH0 LOG0) PUSH0 MSTORE PUSH1(7)\n    // PUSH1(25) RETURN\n    let logger_bytecode = bytes!(\"66365f5f37365fa05f5260076019f3\");\n\n    let eip1559_est = provider.estimate_eip1559_fees().await.unwrap();\n\n    let from = wallets[0].address();\n    let tx = TransactionRequest::default()\n        .with_from(from)\n        .into_create()\n        .with_nonce(0)\n        .with_max_fee_per_gas(eip1559_est.max_fee_per_gas)\n        .with_max_priority_fee_per_gas(eip1559_est.max_priority_fee_per_gas)\n        .with_input(logger_bytecode);\n\n    let receipt = provider\n        .send_transaction(WithOtherFields::new(tx))\n        .await\n        .unwrap()\n        .get_receipt()\n        .await\n        .unwrap();\n\n    assert!(receipt.status());\n\n    let contract = receipt.contract_address.unwrap();\n    let authorization = Authorization {\n        chain_id: U256::from(31337u64),\n        address: contract,\n        nonce: provider.get_transaction_count(from).await.unwrap(),\n    };\n    let signature = wallets[0].sign_hash_sync(&authorization.signature_hash()).unwrap();\n    let authorization = authorization.into_signed(signature);\n\n    let log_data = bytes!(\"11112222\");\n    let mut tx = TxEip7702 {\n        max_fee_per_gas: eip1559_est.max_fee_per_gas,\n        max_priority_fee_per_gas: eip1559_est.max_priority_fee_per_gas,\n        gas_limit: 100000,\n        chain_id: 31337,\n        to: from,\n        input: bytes!(\"11112222\"),\n        authorization_list: vec![authorization],\n        ..Default::default()\n    };\n    let signature = wallets[1].sign_transaction_sync(&mut tx).unwrap();\n\n    let tx = tx.into_signed(signature);\n    let mut encoded = Vec::new();\n    tx.eip2718_encode(&mut encoded);\n\n    let receipt =\n        provider.send_raw_transaction(&encoded).await.unwrap().get_receipt().await.unwrap();\n    let log = &receipt.inner.inner.logs()[0];\n    // assert that log was from EOA which signed authorization\n    assert_eq!(log.address(), from);\n    assert_eq!(log.topics().len(), 0);\n    assert_eq!(log.data().data, log_data);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_send_eip7702_request() {\n    let node_config = NodeConfig::test().with_hardfork(Some(EthereumHardfork::Prague.into()));\n    let (api, handle) = spawn(node_config).await;\n    let provider = http_provider(&handle.http_endpoint());\n\n    let wallets = handle.dev_wallets().collect::<Vec<_>>();\n\n    // deploy simple contract forwarding calldata to LOG0\n    // PUSH7(CALLDATASIZE PUSH0 PUSH0 CALLDATACOPY CALLDATASIZE PUSH0 LOG0) PUSH0 MSTORE PUSH1(7)\n    // PUSH1(25) RETURN\n    let logger_bytecode = bytes!(\"66365f5f37365fa05f5260076019f3\");\n\n    let eip1559_est = provider.estimate_eip1559_fees().await.unwrap();\n\n    let from = wallets[0].address();\n    let tx = TransactionRequest::default()\n        .with_from(from)\n        .into_create()\n        .with_nonce(0)\n        .with_max_fee_per_gas(eip1559_est.max_fee_per_gas)\n        .with_max_priority_fee_per_gas(eip1559_est.max_priority_fee_per_gas)\n        .with_input(logger_bytecode);\n\n    let receipt = provider\n        .send_transaction(WithOtherFields::new(tx))\n        .await\n        .unwrap()\n        .get_receipt()\n        .await\n        .unwrap();\n\n    assert!(receipt.status());\n\n    let contract = receipt.contract_address.unwrap();\n    let authorization = Authorization {\n        chain_id: U256::from(31337u64),\n        address: contract,\n        nonce: provider.get_transaction_count(from).await.unwrap(),\n    };\n    let signature = wallets[0].sign_hash_sync(&authorization.signature_hash()).unwrap();\n    let authorization = authorization.into_signed(signature);\n\n    let log_data = bytes!(\"11112222\");\n    let tx = TxEip7702 {\n        max_fee_per_gas: eip1559_est.max_fee_per_gas,\n        max_priority_fee_per_gas: eip1559_est.max_priority_fee_per_gas,\n        gas_limit: 100000,\n        chain_id: 31337,\n        to: from,\n        input: bytes!(\"11112222\"),\n        authorization_list: vec![authorization],\n        ..Default::default()\n    };\n\n    let sender = wallets[1].address();\n    let request = TransactionRequest::from_transaction(tx).with_from(sender);\n\n    api.anvil_impersonate_account(sender).await.unwrap();\n    let txhash = api.send_transaction(WithOtherFields::new(request)).await.unwrap();\n\n    let txhash = provider\n        .watch_pending_transaction(PendingTransactionConfig::new(txhash))\n        .await\n        .unwrap()\n        .await\n        .unwrap();\n\n    let receipt = provider.get_transaction_receipt(txhash).await.unwrap().unwrap();\n    let log = &receipt.inner.inner.logs()[0];\n    // assert that log was from EOA which signed authorization\n    assert_eq!(log.address(), from);\n    assert_eq!(log.topics().len(), 0);\n    assert_eq!(log.data().data, log_data);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn eip7702_authorization_bypass() {\n    let node_config = NodeConfig::test().with_hardfork(Some(EthereumHardfork::Prague.into()));\n    let (api, handle) = spawn(node_config).await;\n    let provider = http_provider(&handle.http_endpoint());\n\n    let wallets = handle.dev_wallets().collect::<Vec<_>>();\n\n    // deploy simple contract forwarding calldata to LOG0\n    // PUSH7(CALLDATASIZE PUSH0 PUSH0 CALLDATACOPY CALLDATASIZE PUSH0 LOG0) PUSH0 MSTORE PUSH1(7)\n    // PUSH1(25) RETURN\n    let logger_bytecode = bytes!(\"66365f5f37365fa05f5260076019f3\");\n\n    let eip1559_est = provider.estimate_eip1559_fees().await.unwrap();\n\n    let from = wallets[0].address();\n    let tx = TransactionRequest::default()\n        .with_from(from)\n        .into_create()\n        .with_nonce(0)\n        .with_max_fee_per_gas(eip1559_est.max_fee_per_gas)\n        .with_max_priority_fee_per_gas(eip1559_est.max_priority_fee_per_gas)\n        .with_input(logger_bytecode);\n\n    let receipt = provider\n        .send_transaction(WithOtherFields::new(tx))\n        .await\n        .unwrap()\n        .get_receipt()\n        .await\n        .unwrap();\n\n    assert!(receipt.status());\n\n    let contract = receipt.contract_address.unwrap();\n    let authorization = Authorization {\n        chain_id: U256::from(31337u64),\n        address: contract,\n        nonce: provider.get_transaction_count(from).await.unwrap(),\n    };\n    let fake_auth_sig = Signature::new(U256::ZERO, U256::ZERO, true);\n    api.anvil_impersonate_signature(fake_auth_sig.as_bytes().into(), from).await.unwrap();\n    let authorization = authorization.into_signed(fake_auth_sig);\n\n    let log_data = bytes!(\"11112222\");\n    let mut tx = TxEip7702 {\n        max_fee_per_gas: eip1559_est.max_fee_per_gas,\n        max_priority_fee_per_gas: eip1559_est.max_priority_fee_per_gas,\n        gas_limit: 100000,\n        chain_id: 31337,\n        to: from,\n        input: bytes!(\"11112222\"),\n        authorization_list: vec![authorization],\n        ..Default::default()\n    };\n    let signature = wallets[1].sign_transaction_sync(&mut tx).unwrap();\n\n    let tx = tx.into_signed(signature);\n    let mut encoded = Vec::new();\n    tx.eip2718_encode(&mut encoded);\n\n    let receipt =\n        provider.send_raw_transaction(&encoded).await.unwrap().get_receipt().await.unwrap();\n    let log = &receipt.inner.inner.logs()[0];\n    // assert that log was from EOA which signed authorization\n    assert_eq!(log.address(), from);\n    assert_eq!(log.topics().len(), 0);\n    assert_eq!(log.data().data, log_data);\n}\n"
  },
  {
    "path": "crates/anvil/tests/it/fork.rs",
    "content": "//! various fork related test\n\nuse crate::{\n    abi::{ERC721, Greeter},\n    utils::{http_provider, http_provider_with_signer},\n};\nuse alloy_chains::NamedChain;\nuse alloy_eips::{\n    eip7840::BlobParams,\n    eip7910::{EthConfig, SystemContract},\n};\nuse alloy_network::{EthereumWallet, ReceiptResponse, TransactionBuilder, TransactionResponse};\nuse alloy_primitives::{Address, Bytes, TxHash, TxKind, U64, U256, address, b256, bytes, uint};\nuse alloy_provider::Provider;\nuse alloy_rpc_types::{\n    AccountInfo, BlockId, BlockNumberOrTag,\n    anvil::Forking,\n    request::{TransactionInput, TransactionRequest},\n    state::EvmOverrides,\n};\nuse alloy_serde::WithOtherFields;\nuse alloy_signer_local::PrivateKeySigner;\nuse anvil::{EthereumHardfork, NodeConfig, NodeHandle, PrecompileFactory, eth::EthApi, spawn};\nuse foundry_common::provider::get_http_provider;\nuse foundry_config::Config;\nuse foundry_evm_networks::NetworkConfigs;\nuse foundry_primitives::FoundryNetwork;\nuse foundry_test_utils::rpc::{self, next_http_rpc_endpoint, next_rpc_endpoint};\nuse futures::StreamExt;\nuse std::{\n    collections::{BTreeMap, BTreeSet},\n    sync::Arc,\n    thread::sleep,\n    time::Duration,\n};\n\nconst BLOCK_NUMBER: u64 = 14_608_400u64;\nconst DEAD_BALANCE_AT_BLOCK_NUMBER: u128 = 12_556_069_338_441_120_059_867u128;\n\nconst BLOCK_TIMESTAMP: u64 = 1_650_274_250u64;\n\n/// Represents an anvil fork of an anvil node\n#[expect(unused)]\npub struct LocalFork {\n    origin_api: EthApi<FoundryNetwork>,\n    origin_handle: NodeHandle,\n    fork_api: EthApi<FoundryNetwork>,\n    fork_handle: NodeHandle,\n}\n\n#[expect(dead_code)]\nimpl LocalFork {\n    /// Spawns two nodes with the test config\n    pub async fn new() -> Self {\n        Self::setup(NodeConfig::test(), NodeConfig::test()).await\n    }\n\n    /// Spawns two nodes where one is a fork of the other\n    pub async fn setup(origin: NodeConfig, fork: NodeConfig) -> Self {\n        let (origin_api, origin_handle) = spawn(origin).await;\n\n        let (fork_api, fork_handle) =\n            spawn(fork.with_eth_rpc_url(Some(origin_handle.http_endpoint()))).await;\n        Self { origin_api, origin_handle, fork_api, fork_handle }\n    }\n}\n\npub fn fork_config() -> NodeConfig {\n    NodeConfig::test()\n        .with_eth_rpc_url(Some(rpc::next_http_archive_rpc_url()))\n        .with_fork_block_number(Some(BLOCK_NUMBER))\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_fork_gas_limit_applied_from_config() {\n    let (api, _handle) = spawn(fork_config().with_gas_limit(Some(10_000_000))).await;\n\n    assert_eq!(api.gas_limit(), uint!(10_000_000_U256));\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_fork_gas_limit_disabled_from_config() {\n    let (api, handle) = spawn(fork_config().disable_block_gas_limit(true)).await;\n\n    // see https://github.com/foundry-rs/foundry/pull/8933\n    assert_eq!(api.gas_limit(), U256::from(U64::MAX));\n\n    // try to mine a couple blocks\n    let provider = handle.http_provider();\n    let tx = TransactionRequest::default()\n        .to(Address::random())\n        .value(U256::from(1337u64))\n        .from(handle.dev_wallets().next().unwrap().address());\n    let tx = WithOtherFields::new(tx);\n    let _ = provider.send_transaction(tx).await.unwrap().get_receipt().await.unwrap();\n\n    let tx = TransactionRequest::default()\n        .to(Address::random())\n        .value(U256::from(1337u64))\n        .from(handle.dev_wallets().next().unwrap().address());\n    let tx = WithOtherFields::new(tx);\n    let _ = provider.send_transaction(tx).await.unwrap().get_receipt().await.unwrap();\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_spawn_fork() {\n    let (api, _handle) = spawn(fork_config()).await;\n    assert!(api.is_fork());\n\n    let head = api.block_number().unwrap();\n    assert_eq!(head, U256::from(BLOCK_NUMBER))\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_fork_eth_get_balance() {\n    let (api, handle) = spawn(fork_config()).await;\n    let provider = handle.http_provider();\n    for _ in 0..10 {\n        let addr = Address::random();\n        let balance = api.balance(addr, None).await.unwrap();\n        let provider_balance = provider.get_balance(addr).await.unwrap();\n        assert_eq!(balance, provider_balance)\n    }\n}\n\n// <https://github.com/foundry-rs/foundry/issues/4082>\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_fork_eth_get_balance_after_mine() {\n    let (api, handle) = spawn(fork_config()).await;\n    let provider = handle.http_provider();\n    let info = api.anvil_node_info().await.unwrap();\n    let number = info.fork_config.fork_block_number.unwrap();\n    assert_eq!(number, BLOCK_NUMBER);\n\n    let address = Address::random();\n\n    let _balance = provider.get_balance(address).await.unwrap();\n\n    api.evm_mine(None).await.unwrap();\n\n    let _balance = provider.get_balance(address).await.unwrap();\n}\n\n// <https://github.com/foundry-rs/foundry/issues/4082>\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_fork_eth_get_code_after_mine() {\n    let (api, handle) = spawn(fork_config()).await;\n    let provider = handle.http_provider();\n    let info = api.anvil_node_info().await.unwrap();\n    let number = info.fork_config.fork_block_number.unwrap();\n    assert_eq!(number, BLOCK_NUMBER);\n\n    let address = Address::random();\n\n    let _code = provider.get_code_at(address).block_id(BlockId::number(1)).await.unwrap();\n\n    api.evm_mine(None).await.unwrap();\n\n    let _code = provider.get_code_at(address).block_id(BlockId::number(1)).await.unwrap();\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_fork_eth_get_code() {\n    let (api, handle) = spawn(fork_config()).await;\n    let provider = handle.http_provider();\n    for _ in 0..10 {\n        let addr = Address::random();\n        let code = api.get_code(addr, None).await.unwrap();\n        let provider_code = provider.get_code_at(addr).await.unwrap();\n        assert_eq!(code, provider_code)\n    }\n\n    let addresses: Vec<Address> = vec![\n        \"0x6b175474e89094c44da98b954eedeac495271d0f\".parse().unwrap(),\n        \"0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48\".parse().unwrap(),\n        \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\".parse().unwrap(),\n        \"0x1F98431c8aD98523631AE4a59f267346ea31F984\".parse().unwrap(),\n        \"0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45\".parse().unwrap(),\n    ];\n    for address in addresses {\n        let prev_code = api\n            .get_code(address, Some(BlockNumberOrTag::Number(BLOCK_NUMBER - 10).into()))\n            .await\n            .unwrap();\n        let code = api.get_code(address, None).await.unwrap();\n        let provider_code = provider.get_code_at(address).await.unwrap();\n        assert_eq!(code, prev_code);\n        assert_eq!(code, provider_code);\n        assert!(!code.as_ref().is_empty());\n    }\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_fork_eth_get_nonce() {\n    let (api, handle) = spawn(fork_config()).await;\n    let provider = handle.http_provider();\n\n    for _ in 0..10 {\n        let addr = Address::random();\n        let api_nonce = api.transaction_count(addr, None).await.unwrap().to::<u64>();\n        let provider_nonce = provider.get_transaction_count(addr).await.unwrap();\n        assert_eq!(api_nonce, provider_nonce);\n    }\n\n    let addr = Config::DEFAULT_SENDER;\n    let api_nonce = api.transaction_count(addr, None).await.unwrap().to::<u64>();\n    let provider_nonce = provider.get_transaction_count(addr).await.unwrap();\n    assert_eq!(api_nonce, provider_nonce);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_fork_optimism_with_transaction_hash() {\n    use std::str::FromStr;\n\n    // Fork to a block with a specific transaction\n    let fork_tx_hash =\n        TxHash::from_str(\"fcb864b5a50f0f0b111dbbf9e9167b2cb6179dfd6270e1ad53aac6049c0ec038\")\n            .unwrap();\n    let (api, _handle) = spawn(\n        NodeConfig::test()\n            .with_eth_rpc_url(Some(rpc::next_rpc_endpoint(NamedChain::Optimism)))\n            .with_fork_transaction_hash(Some(fork_tx_hash)),\n    )\n    .await;\n\n    // Make sure the fork starts from previous block\n    let block_number = api.block_number().unwrap().to::<u64>();\n    assert_eq!(block_number, 125777954 - 1);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_fork_eth_fee_history() {\n    let (api, handle) = spawn(fork_config()).await;\n    let provider = handle.http_provider();\n\n    let count = 10u64;\n    let _history =\n        api.fee_history(U256::from(count), BlockNumberOrTag::Latest, vec![]).await.unwrap();\n    let _provider_history =\n        provider.get_fee_history(count, BlockNumberOrTag::Latest, &[]).await.unwrap();\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_fork_reset() {\n    let (api, handle) = spawn(fork_config()).await;\n    let provider = handle.http_provider();\n\n    let accounts: Vec<_> = handle.dev_wallets().collect();\n    let from = accounts[0].address();\n    let to = accounts[1].address();\n    let block_number = provider.get_block_number().await.unwrap();\n    let balance_before = provider.get_balance(to).await.unwrap();\n    let amount = handle.genesis_balance().checked_div(U256::from(2u64)).unwrap();\n\n    let initial_nonce = provider.get_transaction_count(from).await.unwrap();\n\n    let tx = TransactionRequest::default().to(to).value(amount).from(from);\n    let tx = WithOtherFields::new(tx);\n    let tx = provider.send_transaction(tx).await.unwrap().get_receipt().await.unwrap();\n    assert_eq!(tx.transaction_index, Some(0));\n\n    let nonce = provider.get_transaction_count(from).await.unwrap();\n\n    assert_eq!(nonce, initial_nonce + 1);\n    let to_balance = provider.get_balance(to).await.unwrap();\n    assert_eq!(balance_before.saturating_add(amount), to_balance);\n    api.anvil_reset(Some(Forking { json_rpc_url: None, block_number: Some(block_number) }))\n        .await\n        .unwrap();\n\n    // reset block number\n    assert_eq!(block_number, provider.get_block_number().await.unwrap());\n\n    let nonce = provider.get_transaction_count(from).await.unwrap();\n    assert_eq!(nonce, initial_nonce);\n    let balance = provider.get_balance(from).await.unwrap();\n    assert_eq!(balance, handle.genesis_balance());\n    let balance = provider.get_balance(to).await.unwrap();\n    assert_eq!(balance, handle.genesis_balance());\n\n    // reset to latest\n    api.anvil_reset(Some(Forking::default())).await.unwrap();\n\n    let new_block_num = provider.get_block_number().await.unwrap();\n    assert!(new_block_num > block_number);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_fork_reset_setup() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n    let provider = handle.http_provider();\n\n    let dead_addr: Address = \"000000000000000000000000000000000000dEaD\".parse().unwrap();\n\n    let block_number = provider.get_block_number().await.unwrap();\n    assert_eq!(block_number, 0);\n\n    let local_balance = provider.get_balance(dead_addr).await.unwrap();\n    assert_eq!(local_balance, U256::ZERO);\n\n    api.anvil_reset(Some(Forking {\n        json_rpc_url: Some(rpc::next_http_archive_rpc_url()),\n        block_number: Some(BLOCK_NUMBER),\n    }))\n    .await\n    .unwrap();\n\n    let block_number = provider.get_block_number().await.unwrap();\n    assert_eq!(block_number, BLOCK_NUMBER);\n\n    let remote_balance = provider.get_balance(dead_addr).await.unwrap();\n    assert_eq!(remote_balance, U256::from(DEAD_BALANCE_AT_BLOCK_NUMBER));\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_fork_state_snapshotting() {\n    let (api, handle) = spawn(fork_config()).await;\n    let provider = handle.http_provider();\n    let state_snapshot = api.evm_snapshot().await.unwrap();\n\n    let accounts: Vec<_> = handle.dev_wallets().collect();\n    let from = accounts[0].address();\n    let to = accounts[1].address();\n    let block_number = provider.get_block_number().await.unwrap();\n\n    let initial_nonce = provider.get_transaction_count(from).await.unwrap();\n    let balance_before = provider.get_balance(to).await.unwrap();\n    let amount = handle.genesis_balance().checked_div(U256::from(2u64)).unwrap();\n\n    let provider = handle.http_provider();\n    let tx = TransactionRequest::default().to(to).value(amount).from(from);\n    let tx = WithOtherFields::new(tx);\n\n    let _ = provider.send_transaction(tx).await.unwrap().get_receipt().await.unwrap();\n\n    let provider = handle.http_provider();\n\n    let nonce = provider.get_transaction_count(from).await.unwrap();\n    assert_eq!(nonce, initial_nonce + 1);\n    let to_balance = provider.get_balance(to).await.unwrap();\n    assert_eq!(balance_before.saturating_add(amount), to_balance);\n\n    assert!(api.evm_revert(state_snapshot).await.unwrap());\n\n    let nonce = provider.get_transaction_count(from).await.unwrap();\n    assert_eq!(nonce, initial_nonce);\n    let balance = provider.get_balance(from).await.unwrap();\n    assert_eq!(balance, handle.genesis_balance());\n    let balance = provider.get_balance(to).await.unwrap();\n    assert_eq!(balance, handle.genesis_balance());\n    assert_eq!(block_number, provider.get_block_number().await.unwrap());\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_fork_state_snapshotting_repeated() {\n    let (api, handle) = spawn(fork_config()).await;\n    let provider = handle.http_provider();\n\n    let state_snapshot = api.evm_snapshot().await.unwrap();\n\n    let accounts: Vec<_> = handle.dev_wallets().collect();\n    let from = accounts[0].address();\n    let to = accounts[1].address();\n    let block_number = provider.get_block_number().await.unwrap();\n\n    let initial_nonce = provider.get_transaction_count(from).await.unwrap();\n    let balance_before = provider.get_balance(to).await.unwrap();\n    let amount = handle.genesis_balance().checked_div(U256::from(92u64)).unwrap();\n\n    let tx = TransactionRequest::default().to(to).value(amount).from(from);\n    let tx = WithOtherFields::new(tx);\n    let tx_provider = handle.http_provider();\n    let _ = tx_provider.send_transaction(tx).await.unwrap().get_receipt().await.unwrap();\n\n    let nonce = provider.get_transaction_count(from).await.unwrap();\n    assert_eq!(nonce, initial_nonce + 1);\n    let to_balance = provider.get_balance(to).await.unwrap();\n    assert_eq!(balance_before.saturating_add(amount), to_balance);\n\n    let _second_state_snapshot = api.evm_snapshot().await.unwrap();\n\n    assert!(api.evm_revert(state_snapshot).await.unwrap());\n\n    let nonce = provider.get_transaction_count(from).await.unwrap();\n    assert_eq!(nonce, initial_nonce);\n    let balance = provider.get_balance(from).await.unwrap();\n    assert_eq!(balance, handle.genesis_balance());\n    let balance = provider.get_balance(to).await.unwrap();\n    assert_eq!(balance, handle.genesis_balance());\n    assert_eq!(block_number, provider.get_block_number().await.unwrap());\n\n    // invalidated\n    // TODO enable after <https://github.com/foundry-rs/foundry/pull/6366>\n    // assert!(!api.evm_revert(second_snapshot).await.unwrap());\n\n    // nothing is reverted, snapshot gone\n    assert!(!api.evm_revert(state_snapshot).await.unwrap());\n}\n\n// <https://github.com/foundry-rs/foundry/issues/6463>\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_fork_state_snapshotting_blocks() {\n    let (api, handle) = spawn(fork_config()).await;\n    let provider = handle.http_provider();\n\n    let state_snapshot = api.evm_snapshot().await.unwrap();\n\n    let accounts: Vec<_> = handle.dev_wallets().collect();\n    let from = accounts[0].address();\n    let to = accounts[1].address();\n    let block_number = provider.get_block_number().await.unwrap();\n\n    let initial_nonce = provider.get_transaction_count(from).await.unwrap();\n    let balance_before = provider.get_balance(to).await.unwrap();\n    let amount = handle.genesis_balance().checked_div(U256::from(2u64)).unwrap();\n\n    // send the transaction\n    let tx = TransactionRequest::default().to(to).value(amount).from(from);\n    let tx = WithOtherFields::new(tx);\n    let _ = provider.send_transaction(tx.clone()).await.unwrap().get_receipt().await.unwrap();\n\n    let block_number_after = provider.get_block_number().await.unwrap();\n    assert_eq!(block_number_after, block_number + 1);\n\n    let nonce = provider.get_transaction_count(from).await.unwrap();\n    assert_eq!(nonce, initial_nonce + 1);\n    let to_balance = provider.get_balance(to).await.unwrap();\n    assert_eq!(balance_before.saturating_add(amount), to_balance);\n\n    assert!(api.evm_revert(state_snapshot).await.unwrap());\n\n    assert_eq!(initial_nonce, provider.get_transaction_count(from).await.unwrap());\n    let block_number_after = provider.get_block_number().await.unwrap();\n    assert_eq!(block_number_after, block_number);\n\n    // repeat transaction\n    let _ = provider.send_transaction(tx.clone()).await.unwrap().get_receipt().await.unwrap();\n    let nonce = provider.get_transaction_count(from).await.unwrap();\n    assert_eq!(nonce, initial_nonce + 1);\n\n    // revert again: nothing to revert since state snapshot gone\n    assert!(!api.evm_revert(state_snapshot).await.unwrap());\n    let nonce = provider.get_transaction_count(from).await.unwrap();\n    assert_eq!(nonce, initial_nonce + 1);\n    let block_number_after = provider.get_block_number().await.unwrap();\n    assert_eq!(block_number_after, block_number + 1);\n}\n\n/// tests that the remote state and local state are kept separate.\n/// changes don't make into the read only Database that holds the remote state, which is flushed to\n/// a cache file.\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_separate_states() {\n    let (api, handle) = spawn(fork_config().with_fork_block_number(Some(14723772u64))).await;\n    let provider = handle.http_provider();\n\n    let addr: Address = \"000000000000000000000000000000000000dEaD\".parse().unwrap();\n\n    let remote_balance = provider.get_balance(addr).await.unwrap();\n    assert_eq!(remote_balance, U256::from(12556104082473169733500u128));\n\n    api.anvil_set_balance(addr, U256::from(1337u64)).await.unwrap();\n    let balance = provider.get_balance(addr).await.unwrap();\n    assert_eq!(balance, U256::from(1337u64));\n\n    let fork = api.get_fork().unwrap();\n    let fork_db = fork.database.read().await;\n    let acc = fork_db\n        .maybe_inner()\n        .expect(\"could not get fork db inner\")\n        .db()\n        .accounts\n        .read()\n        .get(&addr)\n        .cloned()\n        .unwrap();\n\n    assert_eq!(acc.balance, remote_balance);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_deploy_greeter_on_fork() {\n    let (_api, handle) = spawn(fork_config().with_fork_block_number(Some(14723772u64))).await;\n\n    let wallet = handle.dev_wallets().next().unwrap();\n    let signer: EthereumWallet = wallet.into();\n\n    let provider = http_provider_with_signer(&handle.http_endpoint(), signer);\n\n    let greeter_contract = Greeter::deploy(&provider, \"Hello World!\".to_string()).await.unwrap();\n\n    let greeting = greeter_contract.greet().call().await.unwrap();\n    assert_eq!(\"Hello World!\", greeting);\n\n    let greeter_contract = Greeter::deploy(&provider, \"Hello World!\".to_string()).await.unwrap();\n\n    let greeting = greeter_contract.greet().call().await.unwrap();\n    assert_eq!(\"Hello World!\", greeting);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_reset_properly() {\n    let (origin_api, origin_handle) = spawn(NodeConfig::test()).await;\n    let account = origin_handle.dev_accounts().next().unwrap();\n    let origin_provider = origin_handle.http_provider();\n    let origin_nonce = 1u64;\n    origin_api.anvil_set_nonce(account, U256::from(origin_nonce)).await.unwrap();\n\n    assert_eq!(origin_nonce, origin_provider.get_transaction_count(account).await.unwrap());\n\n    let (fork_api, fork_handle) =\n        spawn(NodeConfig::test().with_eth_rpc_url(Some(origin_handle.http_endpoint()))).await;\n\n    let fork_provider = fork_handle.http_provider();\n    let fork_tx_provider = http_provider(&fork_handle.http_endpoint());\n    assert_eq!(origin_nonce, fork_provider.get_transaction_count(account).await.unwrap());\n\n    let to = Address::random();\n    let to_balance = fork_provider.get_balance(to).await.unwrap();\n    let tx = TransactionRequest::default().from(account).to(to).value(U256::from(1337u64));\n    let tx = WithOtherFields::new(tx);\n    let tx = fork_tx_provider.send_transaction(tx).await.unwrap().get_receipt().await.unwrap();\n\n    // nonce incremented by 1\n    assert_eq!(origin_nonce + 1, fork_provider.get_transaction_count(account).await.unwrap());\n\n    // resetting to origin state\n    fork_api.anvil_reset(Some(Forking::default())).await.unwrap();\n\n    // nonce reset to origin\n    assert_eq!(origin_nonce, fork_provider.get_transaction_count(account).await.unwrap());\n\n    // balance is reset\n    assert_eq!(to_balance, fork_provider.get_balance(to).await.unwrap());\n\n    // tx does not exist anymore\n    assert!(fork_tx_provider.get_transaction_by_hash(tx.transaction_hash).await.unwrap().is_none())\n}\n\n// Ref: <https://github.com/foundry-rs/foundry/issues/8684>\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_reset_fork_to_new_fork() {\n    let eth_rpc_url = next_rpc_endpoint(NamedChain::Mainnet);\n    let (api, handle) = spawn(NodeConfig::test().with_eth_rpc_url(Some(eth_rpc_url))).await;\n    let provider = handle.http_provider();\n\n    let op = address!(\"0xC0d3c0d3c0D3c0D3C0d3C0D3C0D3c0d3c0d30007\"); // L2CrossDomainMessenger - Dead on mainnet.\n\n    let tx = TransactionRequest::default().with_to(op).with_input(\"0x54fd4d50\");\n\n    let tx = WithOtherFields::new(tx);\n\n    let mainnet_call_output = provider.call(tx).await.unwrap();\n\n    assert_eq!(mainnet_call_output, Bytes::new()); // 0x\n\n    let optimism = next_rpc_endpoint(NamedChain::Optimism);\n\n    api.anvil_reset(Some(Forking {\n        json_rpc_url: Some(optimism.to_string()),\n        block_number: Some(124659890),\n    }))\n    .await\n    .unwrap();\n\n    let code = provider.get_code_at(op).await.unwrap();\n\n    assert_ne!(code, Bytes::new());\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_fork_timestamp() {\n    let start = std::time::Instant::now();\n\n    let (api, handle) = spawn(fork_config()).await;\n    let provider = handle.http_provider();\n\n    let block = provider.get_block(BlockId::Number(BLOCK_NUMBER.into())).await.unwrap().unwrap();\n    assert_eq!(block.header.timestamp, BLOCK_TIMESTAMP);\n\n    let accounts: Vec<_> = handle.dev_wallets().collect();\n    let from = accounts[0].address();\n\n    let tx =\n        TransactionRequest::default().to(Address::random()).value(U256::from(1337u64)).from(from);\n    let tx = WithOtherFields::new(tx);\n    let tx = provider.send_transaction(tx).await.unwrap().get_receipt().await.unwrap();\n    let status = tx.inner.inner.inner.receipt.status.coerce_status();\n    assert!(status);\n\n    let block = provider.get_block(BlockId::latest()).await.unwrap().unwrap();\n\n    let elapsed = start.elapsed().as_secs() + 1;\n\n    // ensure the diff between the new mined block and the original block is within the elapsed time\n    let diff = block.header.timestamp - BLOCK_TIMESTAMP;\n    assert!(diff <= elapsed, \"diff={diff}, elapsed={elapsed}\");\n\n    let start = std::time::Instant::now();\n    // reset to check timestamp works after resetting\n    api.anvil_reset(Some(Forking { json_rpc_url: None, block_number: Some(BLOCK_NUMBER) }))\n        .await\n        .unwrap();\n    let block = provider.get_block(BlockId::Number(BLOCK_NUMBER.into())).await.unwrap().unwrap();\n    assert_eq!(block.header.timestamp, BLOCK_TIMESTAMP);\n\n    let tx =\n        TransactionRequest::default().to(Address::random()).value(U256::from(1337u64)).from(from);\n    let tx = WithOtherFields::new(tx);\n    let _ = provider.send_transaction(tx).await.unwrap().get_receipt().await.unwrap(); // FIXME: Awaits endlessly here.\n\n    let block = provider.get_block(BlockId::latest()).await.unwrap().unwrap();\n    let elapsed = start.elapsed().as_secs() + 1;\n    let diff = block.header.timestamp - BLOCK_TIMESTAMP;\n    assert!(diff <= elapsed);\n\n    // ensure that after setting a timestamp manually, then next block time is correct\n    let start = std::time::Instant::now();\n    api.anvil_reset(Some(Forking { json_rpc_url: None, block_number: Some(BLOCK_NUMBER) }))\n        .await\n        .unwrap();\n    api.evm_set_next_block_timestamp(BLOCK_TIMESTAMP + 1).unwrap();\n    let tx =\n        TransactionRequest::default().to(Address::random()).value(U256::from(1337u64)).from(from);\n    let tx = WithOtherFields::new(tx);\n    let _tx = provider.send_transaction(tx).await.unwrap().get_receipt().await.unwrap();\n\n    let block = provider.get_block(BlockId::latest()).await.unwrap().unwrap();\n    assert_eq!(block.header.timestamp, BLOCK_TIMESTAMP + 1);\n\n    let tx =\n        TransactionRequest::default().to(Address::random()).value(U256::from(1337u64)).from(from);\n    let tx = WithOtherFields::new(tx);\n    let _ = provider.send_transaction(tx).await.unwrap().get_receipt().await.unwrap();\n\n    let block = provider.get_block(BlockId::latest()).await.unwrap().unwrap();\n    let elapsed = start.elapsed().as_secs() + 1;\n    let diff = block.header.timestamp - (BLOCK_TIMESTAMP + 1);\n    assert!(diff <= elapsed);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_fork_set_empty_code() {\n    let (api, _handle) = spawn(fork_config()).await;\n    let addr = \"0x1f9840a85d5af5bf1d1762f925bdaddc4201f984\".parse().unwrap();\n    let code = api.get_code(addr, None).await.unwrap();\n    assert!(!code.as_ref().is_empty());\n    api.anvil_set_code(addr, Vec::new().into()).await.unwrap();\n    let code = api.get_code(addr, None).await.unwrap();\n    assert!(code.as_ref().is_empty());\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_fork_can_send_tx() {\n    let (api, handle) =\n        spawn(fork_config().with_blocktime(Some(std::time::Duration::from_millis(800)))).await;\n\n    let wallet = PrivateKeySigner::random();\n    let signer = wallet.address();\n    let provider = handle.http_provider();\n    // let provider = SignerMiddleware::new(provider, wallet);\n\n    api.anvil_set_balance(signer, U256::MAX).await.unwrap();\n    api.anvil_impersonate_account(signer).await.unwrap(); // Added until WalletFiller for alloy-provider is fixed.\n    let balance = provider.get_balance(signer).await.unwrap();\n    assert_eq!(balance, U256::MAX);\n\n    let addr = Address::random();\n    let val = U256::from(1337u64);\n    let tx = TransactionRequest::default().to(addr).value(val).from(signer);\n    let tx = WithOtherFields::new(tx);\n    // broadcast it via the eth_sendTransaction API\n    let _ = provider.send_transaction(tx).await.unwrap().get_receipt().await.unwrap();\n\n    let balance = provider.get_balance(addr).await.unwrap();\n    assert_eq!(balance, val);\n}\n\n// <https://github.com/foundry-rs/foundry/issues/1920>\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_fork_nft_set_approve_all() {\n    let (api, handle) = spawn(\n        fork_config()\n            .with_fork_block_number(Some(14812197u64))\n            .with_blocktime(Some(Duration::from_secs(5)))\n            .with_chain_id(1u64.into()),\n    )\n    .await;\n\n    // create and fund a random wallet\n    let wallet = PrivateKeySigner::random();\n    let signer = wallet.address();\n    api.anvil_set_balance(signer, U256::from(1000e18)).await.unwrap();\n\n    let provider = handle.http_provider();\n\n    // pick a random nft <https://opensea.io/assets/ethereum/0x9c8ff314c9bc7f6e59a9d9225fb22946427edc03/154>\n    let nouns_addr: Address = \"0x9c8ff314c9bc7f6e59a9d9225fb22946427edc03\".parse().unwrap();\n\n    let owner: Address = \"0x052564eb0fd8b340803df55def89c25c432f43f4\".parse().unwrap();\n    let token_id: U256 = U256::from(154u64);\n\n    let nouns = ERC721::new(nouns_addr, provider.clone());\n\n    let real_owner = nouns.ownerOf(token_id).call().await.unwrap();\n    assert_eq!(real_owner, owner);\n    let approval = nouns.setApprovalForAll(nouns_addr, true);\n    let tx = TransactionRequest::default()\n        .from(owner)\n        .to(nouns_addr)\n        .with_input(approval.calldata().to_owned());\n    let tx = WithOtherFields::new(tx);\n    api.anvil_impersonate_account(owner).await.unwrap();\n    let tx = provider.send_transaction(tx).await.unwrap().get_receipt().await.unwrap();\n    let status = tx.inner.inner.inner.receipt.status.coerce_status();\n    assert!(status);\n\n    // transfer: impersonate real owner and transfer nft\n    api.anvil_impersonate_account(real_owner).await.unwrap();\n\n    api.anvil_set_balance(real_owner, U256::from(10000e18 as u64)).await.unwrap();\n\n    let call = nouns.transferFrom(real_owner, signer, token_id);\n    let tx = TransactionRequest::default()\n        .from(real_owner)\n        .to(nouns_addr)\n        .with_input(call.calldata().to_owned());\n    let tx = WithOtherFields::new(tx);\n    let tx = provider.send_transaction(tx).await.unwrap().get_receipt().await.unwrap();\n    let status = tx.inner.inner.inner.receipt.status.coerce_status();\n    assert!(status);\n\n    let real_owner = nouns.ownerOf(token_id).call().await.unwrap();\n    assert_eq!(real_owner, wallet.address());\n}\n\n// <https://github.com/foundry-rs/foundry/issues/2261>\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_fork_with_custom_chain_id() {\n    // spawn a forked node with some random chainId\n    let (api, handle) = spawn(\n        fork_config()\n            .with_fork_block_number(Some(14812197u64))\n            .with_blocktime(Some(Duration::from_secs(5)))\n            .with_chain_id(3145u64.into()),\n    )\n    .await;\n\n    // get the eth chainId and the txn chainId\n    let eth_chain_id = api.eth_chain_id();\n    let txn_chain_id = api.chain_id();\n\n    // get the chainId in the config\n    let config_chain_id = handle.config().chain_id;\n\n    // check that the chainIds are the same\n    assert_eq!(eth_chain_id.unwrap().unwrap().to::<u64>(), 3145u64);\n    assert_eq!(txn_chain_id, 3145u64);\n    assert_eq!(config_chain_id, Some(3145u64));\n}\n\n// <https://github.com/foundry-rs/foundry/issues/1920>\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_fork_can_send_opensea_tx() {\n    let (api, handle) = spawn(\n        fork_config()\n            .with_fork_block_number(Some(14983338u64))\n            .with_blocktime(Some(Duration::from_millis(5000))),\n    )\n    .await;\n\n    let sender: Address = \"0x8fdbae54b6d9f3fc2c649e3dd4602961967fd42f\".parse().unwrap();\n\n    // transfer: impersonate real sender\n    api.anvil_impersonate_account(sender).await.unwrap();\n\n    let provider = handle.http_provider();\n\n    let input: Bytes = \"0xfb0f3ee1000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ff2e795f5000000000000000000000000000023f28ae3e9756ba982a6290f9081b6a84900b758000000000000000000000000004c00500000ad104d7dbd00e3ae0a5c00560c0000000000000000000000000003235b597a78eabcb08ffcb4d97411073211dbcb0000000000000000000000000000000000000000000000000000000000000e72000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000062ad47c20000000000000000000000000000000000000000000000000000000062d43104000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000df44e65d2a2cf40000007b02230091a7ed01230072f7006a004d60a8d4e71d599b8104250f00000000007b02230091a7ed01230072f7006a004d60a8d4e71d599b8104250f00000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000024000000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000001c6bf526340000000000000000000000000008de9c5a032463c561423387a9648c5c7bcc5bc900000000000000000000000000000000000000000000000000005543df729c0000000000000000000000000006eb234847a9e3a546539aac57a071c01dc3f398600000000000000000000000000000000000000000000000000000000000000416d39b5352353a22cf2d44faa696c2089b03137a13b5acfee0366306f2678fede043bc8c7e422f6f13a3453295a4a063dac7ee6216ab7bade299690afc77397a51c00000000000000000000000000000000000000000000000000000000000000\".parse().unwrap();\n    let to: Address = \"0x00000000006c3852cbef3e08e8df289169ede581\".parse().unwrap();\n    let tx = TransactionRequest::default()\n        .from(sender)\n        .to(to)\n        .value(U256::from(20000000000000000u64))\n        .with_input(input)\n        .with_gas_price(22180711707u128)\n        .with_gas_limit(150_000);\n    let tx = WithOtherFields::new(tx);\n\n    let tx = provider.send_transaction(tx).await.unwrap().get_receipt().await.unwrap();\n    let status = tx.inner.inner.inner.receipt.status.coerce_status();\n    assert!(status);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_fork_base_fee() {\n    let (api, handle) = spawn(fork_config()).await;\n\n    let accounts: Vec<_> = handle.dev_wallets().collect();\n    let from = accounts[0].address();\n\n    let provider = handle.http_provider();\n\n    api.anvil_set_next_block_base_fee_per_gas(U256::ZERO).await.unwrap();\n\n    let addr = Address::random();\n    let val = U256::from(1337u64);\n    let tx = TransactionRequest::default().from(from).to(addr).value(val);\n    let tx = WithOtherFields::new(tx);\n    let _res = provider.send_transaction(tx).await.unwrap().get_receipt().await.unwrap();\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_fork_init_base_fee() {\n    let (api, handle) = spawn(fork_config().with_fork_block_number(Some(13184859u64))).await;\n\n    let provider = handle.http_provider();\n\n    let block = provider.get_block(BlockId::latest()).await.unwrap().unwrap();\n    // <https://etherscan.io/block/13184859>\n    assert_eq!(block.header.number, 13184859u64);\n    let init_base_fee = block.header.base_fee_per_gas.unwrap();\n    assert_eq!(init_base_fee, 63739886069);\n\n    api.mine_one().await;\n\n    let block = provider.get_block(BlockId::latest()).await.unwrap().unwrap();\n\n    let next_base_fee = block.header.base_fee_per_gas.unwrap();\n    assert!(next_base_fee < init_base_fee);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_fork_init_blob_base_fee_with_explicit_base_fee() {\n    let fork_rpc_url = rpc::next_http_archive_rpc_url();\n    let fork_block_number = 24_127_158u64;\n    let (default_api, _) = spawn(\n        NodeConfig::test()\n            .with_eth_rpc_url(Some(fork_rpc_url.clone()))\n            .with_fork_block_number(Some(fork_block_number)),\n    )\n    .await;\n    let explicit_base_fee = default_api\n        .block_by_number(BlockNumberOrTag::Latest)\n        .await\n        .unwrap()\n        .unwrap()\n        .header\n        .base_fee_per_gas\n        .unwrap();\n    let (explicit_api, _) = spawn(\n        NodeConfig::test()\n            .with_eth_rpc_url(Some(fork_rpc_url))\n            .with_fork_block_number(Some(fork_block_number))\n            .with_base_fee(Some(explicit_base_fee)),\n    )\n    .await;\n\n    let default_blob_base_fee = default_api.blob_base_fee().unwrap();\n    let explicit_blob_base_fee = explicit_api.blob_base_fee().unwrap();\n\n    assert!(default_blob_base_fee > U256::from(1));\n    assert_eq!(explicit_blob_base_fee, default_blob_base_fee);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn flaky_test_reset_fork_on_new_blocks() {\n    let (api, handle) =\n        spawn(NodeConfig::test().with_eth_rpc_url(Some(rpc::next_http_archive_rpc_url()))).await;\n\n    let anvil_provider = handle.http_provider();\n    let endpoint = next_http_rpc_endpoint();\n    let provider = Arc::new(get_http_provider(&endpoint));\n\n    let current_block = anvil_provider.get_block_number().await.unwrap();\n\n    handle\n        .task_manager()\n        .spawn_reset_on_new_polled_blocks::<alloy_network::AnyNetwork, _>(provider.clone(), api);\n\n    let mut stream = provider\n        .watch_blocks()\n        .await\n        .unwrap()\n        .with_poll_interval(Duration::from_secs(2))\n        .into_stream()\n        .flat_map(futures::stream::iter);\n    // the http watcher may fetch multiple blocks at once, so we set a timeout here to offset edge\n    // cases where the stream immediately returns a block\n    tokio::time::sleep(Duration::from_secs(12)).await;\n    stream.next().await.unwrap();\n    stream.next().await.unwrap();\n\n    let next_block = anvil_provider.get_block_number().await.unwrap();\n\n    assert!(next_block > current_block, \"nextblock={next_block} currentblock={current_block}\")\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_fork_call() {\n    let input: Bytes = \"0x77c7b8fc\".parse().unwrap();\n    let to: Address = \"0x99d1Fa417f94dcD62BfE781a1213c092a47041Bc\".parse().unwrap();\n    let block_number = 14746300u64;\n\n    let provider = http_provider(rpc::next_http_archive_rpc_url().as_str());\n    let tx = TransactionRequest::default().to(to).with_input(input.clone());\n    let tx = WithOtherFields::new(tx);\n    let res0 = provider.call(tx).block(BlockId::Number(block_number.into())).await.unwrap();\n\n    let (api, _) = spawn(fork_config().with_fork_block_number(Some(block_number))).await;\n\n    let res1 = api\n        .call(\n            WithOtherFields::new(TransactionRequest {\n                to: Some(TxKind::from(to)),\n                input: input.into(),\n                ..Default::default()\n            }),\n            None,\n            EvmOverrides::default(),\n        )\n        .await\n        .unwrap();\n\n    assert_eq!(res0, res1);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_fork_block_timestamp() {\n    let (api, _) = spawn(fork_config()).await;\n\n    let initial_block = api.block_by_number(BlockNumberOrTag::Latest).await.unwrap().unwrap();\n    api.anvil_mine(Some(U256::from(1)), None).await.unwrap();\n    let latest_block = api.block_by_number(BlockNumberOrTag::Latest).await.unwrap().unwrap();\n\n    assert!(initial_block.header.timestamp <= latest_block.header.timestamp);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_fork_snapshot_block_timestamp() {\n    let (api, _) = spawn(fork_config()).await;\n\n    let snapshot_id = api.evm_snapshot().await.unwrap();\n    api.anvil_mine(Some(U256::from(1)), None).await.unwrap();\n    let initial_block = api.block_by_number(BlockNumberOrTag::Latest).await.unwrap().unwrap();\n    api.evm_revert(snapshot_id).await.unwrap();\n    api.evm_set_next_block_timestamp(initial_block.header.timestamp).unwrap();\n    api.anvil_mine(Some(U256::from(1)), None).await.unwrap();\n    let latest_block = api.block_by_number(BlockNumberOrTag::Latest).await.unwrap().unwrap();\n\n    assert_eq!(initial_block.header.timestamp, latest_block.header.timestamp);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_fork_uncles_fetch() {\n    let (api, handle) = spawn(fork_config()).await;\n    let provider = handle.http_provider();\n\n    // Block on ETH mainnet with 2 uncles\n    let block_with_uncles = 190u64;\n\n    let block =\n        api.block_by_number(BlockNumberOrTag::Number(block_with_uncles)).await.unwrap().unwrap();\n\n    assert_eq!(block.uncles.len(), 2);\n\n    let count = provider.get_uncle_count(block_with_uncles.into()).await.unwrap();\n    assert_eq!(count as usize, block.uncles.len());\n\n    let hash = BlockId::hash(block.header.hash);\n    let count = provider.get_uncle_count(hash).await.unwrap();\n    assert_eq!(count as usize, block.uncles.len());\n\n    for (uncle_idx, uncle_hash) in block.uncles.iter().enumerate() {\n        // Try with block number\n        let uncle = provider\n            .get_uncle(BlockId::number(block_with_uncles), uncle_idx as u64)\n            .await\n            .unwrap()\n            .unwrap();\n        assert_eq!(*uncle_hash, uncle.header.hash);\n\n        // Try with block hash\n        let uncle = provider\n            .get_uncle(BlockId::hash(block.header.hash), uncle_idx as u64)\n            .await\n            .unwrap()\n            .unwrap();\n        assert_eq!(*uncle_hash, uncle.header.hash);\n    }\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_fork_block_transaction_count() {\n    let (api, handle) = spawn(fork_config()).await;\n    let provider = handle.http_provider();\n\n    let accounts: Vec<_> = handle.dev_wallets().collect();\n    let sender = accounts[0].address();\n\n    // disable automine (so there are pending transactions)\n    api.anvil_set_auto_mine(false).await.unwrap();\n    // transfer: impersonate real sender\n    api.anvil_impersonate_account(sender).await.unwrap();\n\n    let tx =\n        TransactionRequest::default().from(sender).value(U256::from(42u64)).with_gas_limit(100_000);\n    let tx = WithOtherFields::new(tx);\n    let _ = provider.send_transaction(tx).await.unwrap();\n\n    let pending_txs =\n        api.block_transaction_count_by_number(BlockNumberOrTag::Pending).await.unwrap().unwrap();\n    assert_eq!(pending_txs.to::<u64>(), 1);\n\n    // mine a new block\n    api.anvil_mine(None, None).await.unwrap();\n\n    let pending_txs =\n        api.block_transaction_count_by_number(BlockNumberOrTag::Pending).await.unwrap().unwrap();\n    assert_eq!(pending_txs.to::<u64>(), 0);\n    let latest_txs =\n        api.block_transaction_count_by_number(BlockNumberOrTag::Latest).await.unwrap().unwrap();\n    assert_eq!(latest_txs.to::<u64>(), 1);\n    let latest_block = api.block_by_number(BlockNumberOrTag::Latest).await.unwrap().unwrap();\n    let latest_txs =\n        api.block_transaction_count_by_hash(latest_block.header.hash).await.unwrap().unwrap();\n    assert_eq!(latest_txs.to::<u64>(), 1);\n\n    // check txs count on an older block: 420000 has 3 txs on mainnet\n    let count_txs = api\n        .block_transaction_count_by_number(BlockNumberOrTag::Number(420000))\n        .await\n        .unwrap()\n        .unwrap();\n    assert_eq!(count_txs.to::<u64>(), 3);\n    let count_txs = api\n        .block_transaction_count_by_hash(\n            \"0xb3b0e3e0c64e23fb7f1ccfd29245ae423d2f6f1b269b63b70ff882a983ce317c\".parse().unwrap(),\n        )\n        .await\n        .unwrap()\n        .unwrap();\n    assert_eq!(count_txs.to::<u64>(), 3);\n}\n\n// <https://github.com/foundry-rs/foundry/issues/2931>\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_impersonate_in_fork() {\n    let (api, handle) = spawn(fork_config().with_fork_block_number(Some(15347924u64))).await;\n    let provider = handle.http_provider();\n\n    let token_holder: Address = \"0x2f0b23f53734252bda2277357e97e1517d6b042a\".parse().unwrap();\n    let to = Address::random();\n    let val = U256::from(1337u64);\n\n    // fund the impersonated account\n    api.anvil_set_balance(token_holder, U256::from(1e18)).await.unwrap();\n\n    let tx = TransactionRequest::default().from(token_holder).to(to).value(val);\n    let tx = WithOtherFields::new(tx);\n    let res = provider.send_transaction(tx.clone()).await;\n    res.unwrap_err();\n\n    api.anvil_impersonate_account(token_holder).await.unwrap();\n\n    let res = provider.send_transaction(tx.clone()).await.unwrap().get_receipt().await.unwrap();\n    assert_eq!(res.from, token_holder);\n    let status = res.inner.inner.inner.receipt.status.coerce_status();\n    assert!(status);\n\n    let balance = provider.get_balance(to).await.unwrap();\n    assert_eq!(balance, val);\n\n    api.anvil_stop_impersonating_account(token_holder).await.unwrap();\n    let res = provider.send_transaction(tx).await;\n    res.unwrap_err();\n}\n\n// <https://etherscan.io/block/14608400>\n#[tokio::test(flavor = \"multi_thread\")]\n#[ignore]\nasync fn test_total_difficulty_fork() {\n    let (api, handle) = spawn(fork_config()).await;\n\n    let total_difficulty = U256::from(46_673_965_560_973_856_260_636u128);\n    let difficulty = U256::from(13_680_435_288_526_144u128);\n\n    let provider = handle.http_provider();\n    let block = provider.get_block(BlockId::latest()).await.unwrap().unwrap();\n    assert_eq!(block.header.total_difficulty, Some(total_difficulty));\n    assert_eq!(block.header.difficulty, difficulty);\n\n    api.mine_one().await;\n    api.mine_one().await;\n\n    let next_total_difficulty = total_difficulty + difficulty;\n\n    let block = provider.get_block(BlockId::latest()).await.unwrap().unwrap();\n    assert_eq!(block.header.total_difficulty, Some(next_total_difficulty));\n    assert_eq!(block.header.difficulty, U256::ZERO);\n}\n\n// <https://etherscan.io/block/14608400>\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_transaction_receipt() {\n    let (api, _) = spawn(fork_config()).await;\n\n    // A transaction from the forked block (14608400)\n    let receipt = api\n        .transaction_receipt(\n            \"0xce495d665e9091613fd962351a5cbca27a992b919d6a87d542af97e2723ec1e4\".parse().unwrap(),\n        )\n        .await\n        .unwrap();\n    assert!(receipt.is_some());\n\n    // A transaction from a block in the future (14608401)\n    let receipt = api\n        .transaction_receipt(\n            \"0x1a15472088a4a97f29f2f9159511dbf89954b58d9816e58a32b8dc17171dc0e8\".parse().unwrap(),\n        )\n        .await\n        .unwrap();\n    assert!(receipt.is_none());\n}\n\n// <https://etherscan.io/block/14608400>\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_block_receipts() {\n    let (api, _) = spawn(fork_config()).await;\n\n    // Receipts from the forked block (14608400)\n    let receipts = api.block_receipts(BlockNumberOrTag::Number(BLOCK_NUMBER).into()).await.unwrap();\n    assert!(receipts.is_some());\n\n    // Receipts from a block in the future (14608401)\n    let receipts =\n        api.block_receipts(BlockNumberOrTag::Number(BLOCK_NUMBER + 1).into()).await.unwrap();\n    assert!(receipts.is_none());\n\n    // Receipts from a block hash (14608400)\n    let hash = b256!(\"0x4c1c76f89cfe4eb503b09a0993346dd82865cac9d76034efc37d878c66453f0a\");\n    let receipts = api.block_receipts(BlockId::Hash(hash.into())).await.unwrap();\n    assert!(receipts.is_some());\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_override_fork_chain_id() {\n    let chain_id_override = 5u64;\n    let (_api, handle) = spawn(\n        fork_config()\n            .with_fork_block_number(Some(16506610u64))\n            .with_chain_id(Some(chain_id_override)),\n    )\n    .await;\n\n    let wallet = handle.dev_wallets().next().unwrap();\n    let signer: EthereumWallet = wallet.into();\n    let provider = http_provider_with_signer(&handle.http_endpoint(), signer);\n\n    let greeter_contract =\n        Greeter::deploy(provider.clone(), \"Hello World!\".to_string()).await.unwrap();\n    let greeting = greeter_contract.greet().call().await.unwrap();\n\n    assert_eq!(\"Hello World!\", greeting);\n    let greeter_contract =\n        Greeter::deploy(provider.clone(), \"Hello World!\".to_string()).await.unwrap();\n    let greeting = greeter_contract.greet().call().await.unwrap();\n    assert_eq!(\"Hello World!\", greeting);\n\n    let provider = handle.http_provider();\n    let chain_id = provider.get_chain_id().await.unwrap();\n    assert_eq!(chain_id, chain_id_override);\n}\n\n// <https://github.com/foundry-rs/foundry/issues/6485>\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_fork_reset_moonbeam() {\n    crate::init_tracing();\n    let (api, handle) = spawn(\n        fork_config()\n            .with_eth_rpc_url(Some(\"https://rpc.api.moonbeam.network\".to_string()))\n            .with_fork_block_number(None::<u64>),\n    )\n    .await;\n    let provider = handle.http_provider();\n\n    let accounts: Vec<_> = handle.dev_wallets().collect();\n    let from = accounts[0].address();\n\n    let tx =\n        TransactionRequest::default().to(Address::random()).value(U256::from(1337u64)).from(from);\n    let tx = WithOtherFields::new(tx);\n    api.anvil_impersonate_account(from).await.unwrap();\n    let tx = provider.send_transaction(tx).await.unwrap().get_receipt().await.unwrap();\n    let status = tx.inner.inner.inner.receipt.status.coerce_status();\n    assert!(status);\n\n    // reset to check timestamp works after resetting\n    api.anvil_reset(Some(Forking {\n        json_rpc_url: Some(\"https://rpc.api.moonbeam.network\".to_string()),\n        block_number: None,\n    }))\n    .await\n    .unwrap();\n\n    let tx =\n        TransactionRequest::default().to(Address::random()).value(U256::from(1337u64)).from(from);\n    let tx = WithOtherFields::new(tx);\n    let tx = provider.send_transaction(tx).await.unwrap().get_receipt().await.unwrap();\n    let status = tx.inner.inner.inner.receipt.status.coerce_status();\n    assert!(status);\n}\n\n// <https://github.com/foundry-rs/foundry/issues/6640\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_fork_reset_basefee() {\n    // <https://etherscan.io/block/18835000>\n    let (api, _handle) = spawn(fork_config().with_fork_block_number(Some(18835000u64))).await;\n\n    api.mine_one().await;\n    let latest = api.block_by_number(BlockNumberOrTag::Latest).await.unwrap().unwrap();\n\n    // basefee of +1 block: <https://etherscan.io/block/18835001>\n    assert_eq!(latest.header.base_fee_per_gas.unwrap(), 59455969592u64);\n\n    // now reset to block 18835000 -1\n    api.anvil_reset(Some(Forking { json_rpc_url: None, block_number: Some(18835000u64 - 1) }))\n        .await\n        .unwrap();\n\n    api.mine_one().await;\n    let latest = api.block_by_number(BlockNumberOrTag::Latest).await.unwrap().unwrap();\n\n    // basefee of the forked block: <https://etherscan.io/block/18835000>\n    assert_eq!(latest.header.base_fee_per_gas.unwrap(), 59017001138);\n}\n\n// <https://github.com/foundry-rs/foundry/issues/6795>\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn flaky_test_arbitrum_fork_dev_balance() {\n    let (api, handle) = spawn(\n        fork_config()\n            .with_fork_block_number(None::<u64>)\n            .with_eth_rpc_url(Some(next_rpc_endpoint(NamedChain::Arbitrum))),\n    )\n    .await;\n\n    let accounts: Vec<_> = handle.dev_wallets().collect();\n    for acc in accounts {\n        let balance = api.balance(acc.address(), Some(Default::default())).await.unwrap();\n        assert_eq!(balance, U256::from(100000000000000000000u128));\n    }\n}\n\n// <https://github.com/foundry-rs/foundry/issues/9152>\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_arb_fork_mining() {\n    let fork_block_number = 394274860u64;\n    let fork_rpc = next_rpc_endpoint(NamedChain::Arbitrum);\n    let (api, _handle) = spawn(\n        fork_config()\n            .with_fork_block_number(Some(fork_block_number))\n            .with_eth_rpc_url(Some(fork_rpc)),\n    )\n    .await;\n\n    let init_blk_num = api.block_number().unwrap().to::<u64>();\n\n    // Mine one\n    api.mine_one().await;\n    let mined_blk_num = api.block_number().unwrap().to::<u64>();\n\n    assert_eq!(mined_blk_num, init_blk_num + 1);\n}\n\n// <https://github.com/foundry-rs/foundry/issues/6749>\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn flaky_test_arbitrum_fork_block_number() {\n    // fork to get initial block for test\n    let (_, handle) = spawn(\n        fork_config()\n            .with_fork_block_number(None::<u64>)\n            .with_eth_rpc_url(Some(next_rpc_endpoint(NamedChain::Arbitrum))),\n    )\n    .await;\n    let provider = handle.http_provider();\n    let initial_block_number = provider.get_block_number().await.unwrap();\n\n    // fork again at block number returned by `eth_blockNumber`\n    // if wrong block number returned (e.g. L1) then fork will fail with error code -32000: missing\n    // trie node\n    let (api, _) = spawn(\n        fork_config()\n            .with_fork_block_number(Some(initial_block_number))\n            .with_eth_rpc_url(Some(next_rpc_endpoint(NamedChain::Arbitrum))),\n    )\n    .await;\n    let block_number = api.block_number().unwrap().to::<u64>();\n    assert_eq!(block_number, initial_block_number);\n\n    // take snapshot at initial block number\n    let snapshot_state = api.evm_snapshot().await.unwrap();\n\n    // mine new block and check block number returned by `eth_blockNumber`\n    api.mine_one().await;\n    let block_number = api.block_number().unwrap().to::<u64>();\n    assert_eq!(block_number, initial_block_number + 1);\n\n    // test block by number API call returns proper block number and `l1BlockNumber` is set\n    let block_by_number = api.block_by_number(BlockNumberOrTag::Latest).await.unwrap().unwrap();\n    assert_eq!(block_by_number.header.number, initial_block_number + 1);\n    assert!(block_by_number.other.get(\"l1BlockNumber\").is_some());\n\n    // revert to recorded snapshot and check block number\n    assert!(api.evm_revert(snapshot_state).await.unwrap());\n    let block_number = api.block_number().unwrap().to::<u64>();\n    assert_eq!(block_number, initial_block_number);\n\n    // reset fork to different block number and compare with block returned by `eth_blockNumber`\n    api.anvil_reset(Some(Forking {\n        json_rpc_url: Some(next_rpc_endpoint(NamedChain::Arbitrum)),\n        block_number: Some(initial_block_number - 2),\n    }))\n    .await\n    .unwrap();\n    let block_number = api.block_number().unwrap().to::<u64>();\n    assert_eq!(block_number, initial_block_number - 2);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_base_fork_gas_limit() {\n    // fork to get initial block for test\n    let (api, handle) = spawn(\n        fork_config()\n            .with_fork_block_number(None::<u64>)\n            .with_eth_rpc_url(Some(next_rpc_endpoint(NamedChain::Base))),\n    )\n    .await;\n\n    let provider = handle.http_provider();\n    let block =\n        provider.get_block(BlockId::Number(BlockNumberOrTag::Latest)).await.unwrap().unwrap();\n\n    assert!(api.gas_limit() >= uint!(96_000_000_U256));\n    assert!(block.header.gas_limit >= 96_000_000_u64);\n}\n\n// <https://github.com/foundry-rs/foundry/issues/7023>\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_fork_execution_reverted() {\n    let target = 16681681u64;\n    let (api, _handle) = spawn(fork_config().with_fork_block_number(Some(target + 1))).await;\n\n    let resp = api\n        .call(\n            WithOtherFields::new(TransactionRequest {\n                to: Some(TxKind::from(address!(\"0xFd6CC4F251eaE6d02f9F7B41D1e80464D3d2F377\"))),\n                input: TransactionInput::new(bytes!(\"8f283b3c\")),\n                ..Default::default()\n            }),\n            Some(target.into()),\n            EvmOverrides::default(),\n        )\n        .await;\n\n    assert!(resp.is_err());\n    let err = resp.unwrap_err();\n    assert!(err.to_string().contains(\"execution reverted\"));\n}\n\n// <https://github.com/foundry-rs/foundry/issues/8227>\n#[tokio::test(flavor = \"multi_thread\")]\n#[ignore]\nasync fn test_immutable_fork_transaction_hash() {\n    use std::str::FromStr;\n\n    // Fork to a block with a specific transaction\n    // <https://explorer.immutable.com/tx/0x39d64ebf9eb3f07ede37f8681bc3b61928817276c4c4680b6ef9eac9f88b6786>\n    let fork_tx_hash =\n        TxHash::from_str(\"2ac736ce725d628ef20569a1bb501726b42b33f9d171f60b92b69de3ce705845\")\n            .unwrap();\n    let (api, _) = spawn(\n        fork_config()\n            .with_blocktime(Some(Duration::from_millis(500)))\n            .with_fork_transaction_hash(Some(fork_tx_hash))\n            .with_eth_rpc_url(Some(\"https://immutable-zkevm.drpc.org\".to_string())),\n    )\n    .await;\n\n    let fork_block_number = 21824325;\n\n    // Make sure the fork starts from previous block\n    let mut block_number = api.block_number().unwrap().to::<u64>();\n    assert_eq!(block_number, fork_block_number - 1);\n\n    // Wait for fork to pass the target block\n    while block_number < fork_block_number {\n        sleep(Duration::from_millis(250));\n        block_number = api.block_number().unwrap().to::<u64>();\n    }\n\n    let block = api\n        .block_by_number(BlockNumberOrTag::Number(fork_block_number - 1))\n        .await\n        .unwrap()\n        .unwrap();\n    assert_eq!(block.transactions.len(), 6);\n    let block = api\n        .block_by_number_full(BlockNumberOrTag::Number(fork_block_number))\n        .await\n        .unwrap()\n        .unwrap();\n    assert!(!block.transactions.is_empty());\n\n    // Validate the transactions preceding the target transaction exist\n    let expected_transactions = [\n        TxHash::from_str(\"c900784c993221ba192c53a3ff9996f6af83a951100ceb93e750f7ef86bd43d5\")\n            .unwrap(),\n        TxHash::from_str(\"f86f001bbdf69f8f64ff8a4a5fc3e684cf3a7706f204eba8439752f6f67cd2c4\")\n            .unwrap(),\n        fork_tx_hash,\n    ];\n    for expected in [\n        (expected_transactions[0], address!(\"0x0a02a416f87a13626dda0ad386859497565222aa\")),\n        (expected_transactions[1], address!(\"0x0a02a416f87a13626dda0ad386859497565222aa\")),\n        (expected_transactions[2], address!(\"0x4f07d669d76ed9a17799fc4c04c4005196240940\")),\n    ] {\n        let tx = api.backend.mined_transaction_by_hash(expected.0).unwrap();\n        assert_eq!(tx.inner.inner.signer(), expected.1);\n    }\n\n    // Validate the order of transactions in the new block\n    for expected in [\n        (expected_transactions[0], 0),\n        (expected_transactions[1], 1),\n        (expected_transactions[2], 2),\n    ] {\n        let tx = api\n            .backend\n            .mined_block_by_number(BlockNumberOrTag::Number(fork_block_number))\n            .map(|b| b.header.hash)\n            .and_then(|hash| {\n                api.backend.mined_transaction_by_block_hash_and_index(hash, expected.1.into())\n            })\n            .unwrap();\n        assert_eq!(tx.tx_hash().to_string(), expected.0.to_string());\n    }\n}\n\n// <https://github.com/foundry-rs/foundry/issues/4700>\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_fork_query_at_fork_block() {\n    let (api, handle) = spawn(fork_config()).await;\n    let provider = handle.http_provider();\n    let info = api.anvil_node_info().await.unwrap();\n    let number = info.fork_config.fork_block_number.unwrap();\n    assert_eq!(number, BLOCK_NUMBER);\n\n    let address = Address::random();\n\n    let balance = provider.get_balance(address).await.unwrap();\n    api.evm_mine(None).await.unwrap();\n    api.anvil_set_balance(address, balance + U256::from(1)).await.unwrap();\n\n    let balance_before =\n        provider.get_balance(address).block_id(BlockId::number(number)).await.unwrap();\n\n    assert_eq!(balance_before, balance);\n}\n\n// <https://github.com/foundry-rs/foundry/issues/4173>\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_reset_dev_account_nonce() {\n    let config: NodeConfig = fork_config();\n    let address = config.genesis_accounts[0].address();\n    let (api, handle) = spawn(config).await;\n    let provider = handle.http_provider();\n    let info = api.anvil_node_info().await.unwrap();\n    let number = info.fork_config.fork_block_number.unwrap();\n    assert_eq!(number, BLOCK_NUMBER);\n\n    let nonce_before = provider.get_transaction_count(address).await.unwrap();\n\n    // Reset to older block with other nonce\n    api.anvil_reset(Some(Forking {\n        json_rpc_url: None,\n        block_number: Some(BLOCK_NUMBER - 1_000_000),\n    }))\n    .await\n    .unwrap();\n\n    let nonce_after = provider.get_transaction_count(address).await.unwrap();\n\n    assert!(nonce_before > nonce_after);\n\n    let receipt = provider\n        .send_transaction(WithOtherFields::new(\n            TransactionRequest::default()\n                .from(address)\n                .to(address)\n                .nonce(nonce_after)\n                .gas_limit(21000),\n        ))\n        .await\n        .unwrap()\n        .get_receipt()\n        .await\n        .unwrap();\n\n    assert!(receipt.status());\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_set_erc20_balance() {\n    let config: NodeConfig = fork_config();\n    let address = config.genesis_accounts[0].address();\n    let (api, handle) = spawn(config).await;\n\n    let provider = handle.http_provider();\n\n    alloy_sol_types::sol! {\n       #[sol(rpc)]\n       contract ERC20 {\n            function balanceOf(address owner) public view returns (uint256);\n       }\n    }\n    let dai = address!(\"0x6B175474E89094C44Da98b954EedeAC495271d0F\");\n    let erc20 = ERC20::new(dai, provider);\n    let value = U256::from(500);\n\n    api.anvil_deal_erc20(address, dai, value).await.unwrap();\n\n    let new_balance = erc20.balanceOf(address).call().await.unwrap();\n\n    assert_eq!(new_balance, value);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_set_erc20_allowance() {\n    let config: NodeConfig = fork_config();\n    let owner = config.genesis_accounts[0].address();\n    let spender = config.genesis_accounts[1].address();\n    let (api, handle) = spawn(config).await;\n\n    let provider = handle.http_provider();\n\n    alloy_sol_types::sol! {\n       #[sol(rpc)]\n       contract ERC20 {\n            function allowance(address owner, address spender) external view returns (uint256);\n       }\n    }\n    let dai = address!(\"0x6B175474E89094C44Da98b954EedeAC495271d0F\");\n    let erc20 = ERC20::new(dai, provider);\n    let value = U256::from(500);\n\n    api.anvil_set_erc20_allowance(owner, spender, dai, value).await.unwrap();\n\n    let allowance = erc20.allowance(owner, spender).call().await.unwrap();\n    assert_eq!(allowance, value);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_add_balance() {\n    let config: NodeConfig = fork_config();\n    let address = config.genesis_accounts[0].address();\n    let (api, _handle) = spawn(config).await;\n\n    let start_balance = U256::from(100_000_u64);\n    api.anvil_set_balance(address, start_balance).await.unwrap();\n\n    let balance_increase = U256::from(50_000_u64);\n    api.anvil_add_balance(address, balance_increase).await.unwrap();\n\n    let new_balance = api.balance(address, None).await.unwrap();\n    assert_eq!(new_balance, start_balance + balance_increase);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_reset_updates_cache_path_when_rpc_url_not_provided() {\n    let config: NodeConfig = fork_config();\n\n    let (mut api, _handle) = spawn(config).await;\n    let info = api.anvil_node_info().await.unwrap();\n    let number = info.fork_config.fork_block_number.unwrap();\n    assert_eq!(number, BLOCK_NUMBER);\n\n    async fn get_block_from_cache_path(api: &mut EthApi<FoundryNetwork>) -> u64 {\n        let db = api.backend.get_db().read().await;\n        let cache_path = db.maybe_inner().unwrap().cache().cache_path().unwrap();\n        cache_path\n            .parent()\n            .expect(\"must have filename\")\n            .file_name()\n            .expect(\"must have block number as dir name\")\n            .to_str()\n            .expect(\"must be valid string\")\n            .parse::<u64>()\n            .expect(\"must be valid number\")\n    }\n\n    assert_eq!(BLOCK_NUMBER, get_block_from_cache_path(&mut api).await);\n\n    // Reset to older block without specifying a new rpc url\n    api.anvil_reset(Some(Forking {\n        json_rpc_url: None,\n        block_number: Some(BLOCK_NUMBER - 1_000_000),\n    }))\n    .await\n    .unwrap();\n\n    assert_eq!(BLOCK_NUMBER - 1_000_000, get_block_from_cache_path(&mut api).await);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_fork_get_account() {\n    let (_api, handle) = spawn(fork_config()).await;\n    let provider = handle.http_provider();\n\n    let accounts = handle.dev_accounts().collect::<Vec<_>>();\n\n    let alice = accounts[0];\n    let bob = accounts[1];\n\n    let init_block = provider.get_block_number().await.unwrap();\n    let alice_bal = provider.get_balance(alice).await.unwrap();\n    let alice_nonce = provider.get_transaction_count(alice).await.unwrap();\n    let alice_acc_init = provider.get_account(alice).await.unwrap();\n\n    assert_eq!(alice_acc_init.balance, alice_bal);\n    assert_eq!(alice_acc_init.nonce, alice_nonce);\n\n    let tx = TransactionRequest::default().from(alice).to(bob).value(U256::from(142));\n\n    let tx = WithOtherFields::new(tx);\n    let receipt = provider.send_transaction(tx).await.unwrap().get_receipt().await.unwrap();\n\n    assert!(receipt.status());\n    assert_eq!(init_block + 1, receipt.block_number.unwrap());\n\n    let alice_acc = provider.get_account(alice).await.unwrap();\n\n    assert_eq!(\n        alice_acc.balance,\n        alice_bal\n            - (U256::from(142)\n                + U256::from(receipt.gas_used as u128 * receipt.effective_gas_price)),\n    );\n    assert_eq!(alice_acc.nonce, alice_nonce + 1);\n\n    let alice_acc_prev_block = provider.get_account(alice).number(init_block).await.unwrap();\n\n    assert_eq!(alice_acc_init, alice_acc_prev_block);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_fork_get_account_info() {\n    let (api, handle) = spawn(fork_config()).await;\n    let provider = handle.http_provider();\n\n    let info = provider\n        .get_account_info(address!(\"0x19e53a7397bE5AA7908fE9eA991B03710bdC74Fd\"))\n        // predates fork\n        .number(BLOCK_NUMBER - 1)\n        .await\n        .unwrap();\n    assert_eq!(\n        info,\n        AccountInfo {\n            balance: U256::from(14353753764795095694u64),\n            nonce: 6689,\n            code: Default::default(),\n        }\n    );\n\n    // Check account info at block number, see https://github.com/foundry-rs/foundry/issues/12072\n    let info = provider\n        .get_account_info(address!(\"0x19e53a7397bE5AA7908fE9eA991B03710bdC74Fd\"))\n        // predates fork\n        .number(BLOCK_NUMBER)\n        .await\n        .unwrap();\n    assert_eq!(\n        info,\n        AccountInfo {\n            balance: U256::from(14352720829244098514u64),\n            nonce: 6690,\n            code: Default::default(),\n        }\n    );\n\n    // Mine and check account info at new block number, see https://github.com/foundry-rs/foundry/issues/12148\n    api.evm_mine(None).await.unwrap();\n    let info = provider\n        .get_account_info(address!(\"0x19e53a7397bE5AA7908fE9eA991B03710bdC74Fd\"))\n        // predates fork\n        .number(BLOCK_NUMBER + 1)\n        .await\n        .unwrap();\n    assert_eq!(\n        info,\n        AccountInfo {\n            balance: U256::from(14352720829244098514u64),\n            nonce: 6690,\n            code: Default::default(),\n        }\n    );\n}\n\nfn assert_hardfork_config(\n    config: &EthConfig,\n    expected_blob_params: &BlobParams,\n    expected_precompiles: &[Address],\n    expected_system_contracts: &BTreeMap<SystemContract, Address>,\n) {\n    assert!(config.next.is_none());\n    assert!(config.last.is_none());\n\n    let current = &config.current;\n\n    assert_eq!(current.activation_time, 0);\n    assert_eq!(current.chain_id, 31337);\n    assert_eq!(current.fork_id, Bytes::from(vec![0, 0, 0, 0]));\n\n    assert_eq!(&current.blob_schedule, expected_blob_params);\n\n    assert_eq!(\n        current.precompiles.values().copied().collect::<BTreeSet<_>>(),\n        expected_precompiles.iter().copied().collect::<BTreeSet<_>>(),\n    );\n\n    assert_eq!(current.system_contracts, *expected_system_contracts);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_config_with_cancun_hardfork() {\n    let (api, _handle) =\n        spawn(NodeConfig::test().with_hardfork(Some(EthereumHardfork::Cancun.into()))).await;\n\n    let config = api.config().unwrap();\n\n    let expected_blob_params = BlobParams {\n        target_blob_count: 3,\n        max_blob_count: 6,\n        update_fraction: 3338477,\n        min_blob_fee: 1,\n        max_blobs_per_tx: 6,\n        blob_base_cost: 0,\n    };\n\n    // <= Cancun precompiles\n    let expected_precompiles = [\n        address!(\"0000000000000000000000000000000000000001\"),\n        address!(\"0000000000000000000000000000000000000002\"),\n        address!(\"0000000000000000000000000000000000000003\"),\n        address!(\"0000000000000000000000000000000000000004\"),\n        address!(\"0000000000000000000000000000000000000005\"),\n        address!(\"0000000000000000000000000000000000000006\"),\n        address!(\"0000000000000000000000000000000000000007\"),\n        address!(\"0000000000000000000000000000000000000008\"),\n        address!(\"0000000000000000000000000000000000000009\"),\n        address!(\"000000000000000000000000000000000000000a\"),\n    ];\n\n    let expected_system_contracts = BTreeMap::from([(\n        SystemContract::BeaconRoots,\n        address!(\"000f3df6d732807ef1319fb7b8bb8522d0beac02\"),\n    )]);\n\n    assert_hardfork_config(\n        &config,\n        &expected_blob_params,\n        &expected_precompiles,\n        &expected_system_contracts,\n    );\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_config_with_prague_hardfork_with_celo() {\n    let (api, _handle) = spawn(\n        NodeConfig::test()\n            .with_hardfork(Some(EthereumHardfork::Prague.into()))\n            .with_networks(NetworkConfigs::with_celo()),\n    )\n    .await;\n\n    let config = api.config().unwrap();\n\n    let expected_blob_params = BlobParams {\n        target_blob_count: 6,\n        max_blob_count: 9,\n        update_fraction: 5007716,\n        min_blob_fee: 1,\n        max_blobs_per_tx: 9,\n        blob_base_cost: 0,\n    };\n\n    // <= Prague + Celo precompiles\n    let expected_precompiles = [\n        address!(\"0000000000000000000000000000000000000001\"),\n        address!(\"0000000000000000000000000000000000000002\"),\n        address!(\"0000000000000000000000000000000000000003\"),\n        address!(\"0000000000000000000000000000000000000004\"),\n        address!(\"0000000000000000000000000000000000000005\"),\n        address!(\"0000000000000000000000000000000000000006\"),\n        address!(\"0000000000000000000000000000000000000007\"),\n        address!(\"0000000000000000000000000000000000000008\"),\n        address!(\"0000000000000000000000000000000000000009\"),\n        address!(\"000000000000000000000000000000000000000a\"),\n        address!(\"000000000000000000000000000000000000000b\"),\n        address!(\"000000000000000000000000000000000000000c\"),\n        address!(\"000000000000000000000000000000000000000d\"),\n        address!(\"000000000000000000000000000000000000000e\"),\n        address!(\"000000000000000000000000000000000000000f\"),\n        address!(\"0000000000000000000000000000000000000010\"),\n        address!(\"0000000000000000000000000000000000000011\"),\n        address!(\"00000000000000000000000000000000000000fd\"), // `celo transfer`\n    ];\n\n    let expected_system_contracts = BTreeMap::from([\n        (SystemContract::BeaconRoots, address!(\"000f3df6d732807ef1319fb7b8bb8522d0beac02\")),\n        (\n            SystemContract::ConsolidationRequestPredeploy,\n            address!(\"0000bbddc7ce488642fb579f8b00f3a590007251\"),\n        ),\n        (SystemContract::DepositContract, address!(\"00000000219ab540356cbb839cbe05303d7705fa\")),\n        (SystemContract::HistoryStorage, address!(\"0000f90827f1c53a10cb7a02335b175320002935\")),\n        (\n            SystemContract::WithdrawalRequestPredeploy,\n            address!(\"00000961ef480eb55e80d19ad83579a64c007002\"),\n        ),\n    ]);\n\n    assert_hardfork_config(\n        &config,\n        &expected_blob_params,\n        &expected_precompiles,\n        &expected_system_contracts,\n    );\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_config_with_osaka_hardfork() {\n    let (api, _handle) =\n        spawn(NodeConfig::test().with_hardfork(Some(EthereumHardfork::Osaka.into()))).await;\n\n    let config = api.config().unwrap();\n\n    let expected_blob_params = BlobParams {\n        target_blob_count: 6,\n        max_blob_count: 9,\n        update_fraction: 5007716,\n        min_blob_fee: 1,\n        max_blobs_per_tx: 6,\n        blob_base_cost: 8192,\n    };\n\n    // <= Osaka precompiles\n    let expected_precompiles = [\n        address!(\"0000000000000000000000000000000000000001\"),\n        address!(\"0000000000000000000000000000000000000002\"),\n        address!(\"0000000000000000000000000000000000000003\"),\n        address!(\"0000000000000000000000000000000000000004\"),\n        address!(\"0000000000000000000000000000000000000005\"),\n        address!(\"0000000000000000000000000000000000000006\"),\n        address!(\"0000000000000000000000000000000000000007\"),\n        address!(\"0000000000000000000000000000000000000008\"),\n        address!(\"0000000000000000000000000000000000000009\"),\n        address!(\"000000000000000000000000000000000000000a\"),\n        address!(\"000000000000000000000000000000000000000b\"),\n        address!(\"000000000000000000000000000000000000000c\"),\n        address!(\"000000000000000000000000000000000000000d\"),\n        address!(\"000000000000000000000000000000000000000e\"),\n        address!(\"000000000000000000000000000000000000000f\"),\n        address!(\"0000000000000000000000000000000000000010\"),\n        address!(\"0000000000000000000000000000000000000011\"),\n        address!(\"0000000000000000000000000000000000000100\"),\n    ];\n\n    let expected_system_contracts = BTreeMap::from([\n        (SystemContract::BeaconRoots, address!(\"000f3df6d732807ef1319fb7b8bb8522d0beac02\")),\n        (\n            SystemContract::ConsolidationRequestPredeploy,\n            address!(\"0000bbddc7ce488642fb579f8b00f3a590007251\"),\n        ),\n        (SystemContract::DepositContract, address!(\"00000000219ab540356cbb839cbe05303d7705fa\")),\n        (SystemContract::HistoryStorage, address!(\"0000f90827f1c53a10cb7a02335b175320002935\")),\n        (\n            SystemContract::WithdrawalRequestPredeploy,\n            address!(\"00000961ef480eb55e80d19ad83579a64c007002\"),\n        ),\n    ]);\n\n    assert_hardfork_config(\n        &config,\n        &expected_blob_params,\n        &expected_precompiles,\n        &expected_system_contracts,\n    );\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_config_with_osaka_hardfork_with_precompile_factory() {\n    #[derive(Debug)]\n    struct CustomPrecompileFactory;\n\n    impl PrecompileFactory for CustomPrecompileFactory {\n        fn precompiles(&self) -> Vec<(Address, alloy_evm::precompiles::DynPrecompile)> {\n            vec![(\n                address!(\"0x0000000000000000000000000000000000000071\"),\n                alloy_evm::precompiles::DynPrecompile::from(\n                    |input: alloy_evm::precompiles::PrecompileInput<'_>| {\n                        Ok(revm::precompile::PrecompileOutput {\n                            bytes: Bytes::copy_from_slice(input.data),\n                            gas_used: 0,\n                            gas_refunded: 0,\n                            reverted: false,\n                        })\n                    },\n                ),\n            )]\n        }\n    }\n\n    let (api, _handle) = spawn(\n        NodeConfig::test()\n            .with_hardfork(Some(EthereumHardfork::Osaka.into()))\n            .with_precompile_factory(CustomPrecompileFactory),\n    )\n    .await;\n\n    let config = api.config().unwrap();\n\n    let expected_blob_params = BlobParams {\n        target_blob_count: 6,\n        max_blob_count: 9,\n        update_fraction: 5007716,\n        min_blob_fee: 1,\n        max_blobs_per_tx: 6,\n        blob_base_cost: 8192,\n    };\n\n    // <= Osaka precompiles + custom precompile\n    let expected_precompiles = [\n        address!(\"0000000000000000000000000000000000000001\"),\n        address!(\"0000000000000000000000000000000000000002\"),\n        address!(\"0000000000000000000000000000000000000003\"),\n        address!(\"0000000000000000000000000000000000000004\"),\n        address!(\"0000000000000000000000000000000000000005\"),\n        address!(\"0000000000000000000000000000000000000006\"),\n        address!(\"0000000000000000000000000000000000000007\"),\n        address!(\"0000000000000000000000000000000000000008\"),\n        address!(\"0000000000000000000000000000000000000009\"),\n        address!(\"000000000000000000000000000000000000000a\"),\n        address!(\"000000000000000000000000000000000000000b\"),\n        address!(\"000000000000000000000000000000000000000c\"),\n        address!(\"000000000000000000000000000000000000000d\"),\n        address!(\"000000000000000000000000000000000000000e\"),\n        address!(\"000000000000000000000000000000000000000f\"),\n        address!(\"0000000000000000000000000000000000000010\"),\n        address!(\"0000000000000000000000000000000000000011\"),\n        address!(\"0000000000000000000000000000000000000071\"), // `custom_echo`\n        address!(\"0000000000000000000000000000000000000100\"),\n    ];\n    let expected_system_contracts = BTreeMap::from([\n        (SystemContract::BeaconRoots, address!(\"000f3df6d732807ef1319fb7b8bb8522d0beac02\")),\n        (\n            SystemContract::ConsolidationRequestPredeploy,\n            address!(\"0000bbddc7ce488642fb579f8b00f3a590007251\"),\n        ),\n        (SystemContract::DepositContract, address!(\"00000000219ab540356cbb839cbe05303d7705fa\")),\n        (SystemContract::HistoryStorage, address!(\"0000f90827f1c53a10cb7a02335b175320002935\")),\n        (\n            SystemContract::WithdrawalRequestPredeploy,\n            address!(\"00000961ef480eb55e80d19ad83579a64c007002\"),\n        ),\n    ]);\n\n    assert_hardfork_config(\n        &config,\n        &expected_blob_params,\n        &expected_precompiles,\n        &expected_system_contracts,\n    );\n}\n"
  },
  {
    "path": "crates/anvil/tests/it/gas.rs",
    "content": "//! Gas related tests\n\nuse crate::utils::http_provider_with_signer;\nuse alloy_network::{EthereumWallet, TransactionBuilder};\nuse alloy_primitives::{Address, U64, U256, uint};\nuse alloy_provider::Provider;\nuse alloy_rpc_types::{BlockId, TransactionRequest};\nuse alloy_serde::WithOtherFields;\nuse anvil::{NodeConfig, eth::fees::INITIAL_BASE_FEE, spawn};\n\nconst GAS_TRANSFER: u64 = 21_000;\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_gas_limit_applied_from_config() {\n    let (api, _handle) = spawn(NodeConfig::test().with_gas_limit(Some(10_000_000))).await;\n\n    assert_eq!(api.gas_limit(), uint!(10_000_000_U256));\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_gas_limit_disabled_from_config() {\n    let (api, _handle) = spawn(NodeConfig::test().disable_block_gas_limit(true)).await;\n\n    // see https://github.com/foundry-rs/foundry/pull/8933\n    assert_eq!(api.gas_limit(), U256::from(U64::MAX));\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_basefee_full_block() {\n    let (_api, handle) = spawn(\n        NodeConfig::test().with_base_fee(Some(INITIAL_BASE_FEE)).with_gas_limit(Some(GAS_TRANSFER)),\n    )\n    .await;\n\n    let wallet = handle.dev_wallets().next().unwrap();\n    let signer: EthereumWallet = wallet.clone().into();\n\n    let provider = http_provider_with_signer(&handle.http_endpoint(), signer);\n\n    let tx = TransactionRequest::default().to(Address::random()).with_value(U256::from(1337));\n    let tx = WithOtherFields::new(tx);\n\n    provider.send_transaction(tx.clone()).await.unwrap().get_receipt().await.unwrap();\n\n    let base_fee = provider\n        .get_block(BlockId::latest())\n        .await\n        .unwrap()\n        .unwrap()\n        .header\n        .base_fee_per_gas\n        .unwrap();\n\n    provider.send_transaction(tx.clone()).await.unwrap().get_receipt().await.unwrap();\n\n    let next_base_fee = provider\n        .get_block(BlockId::latest())\n        .await\n        .unwrap()\n        .unwrap()\n        .header\n        .base_fee_per_gas\n        .unwrap();\n\n    assert!(next_base_fee > base_fee);\n\n    // max increase, full block\n    assert_eq!(next_base_fee, INITIAL_BASE_FEE + 125_000_000);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_basefee_half_block() {\n    let (_api, handle) = spawn(\n        NodeConfig::test()\n            .with_base_fee(Some(INITIAL_BASE_FEE))\n            .with_gas_limit(Some(GAS_TRANSFER * 2)),\n    )\n    .await;\n\n    let wallet = handle.dev_wallets().next().unwrap();\n    let signer: EthereumWallet = wallet.clone().into();\n\n    let provider = http_provider_with_signer(&handle.http_endpoint(), signer);\n\n    let tx = TransactionRequest::default().to(Address::random()).with_value(U256::from(1337));\n    let tx = WithOtherFields::new(tx);\n\n    provider.send_transaction(tx.clone()).await.unwrap().get_receipt().await.unwrap();\n\n    let tx = TransactionRequest::default().to(Address::random()).with_value(U256::from(1337));\n    let tx = WithOtherFields::new(tx);\n\n    provider.send_transaction(tx.clone()).await.unwrap().get_receipt().await.unwrap();\n\n    let next_base_fee = provider\n        .get_block(BlockId::latest())\n        .await\n        .unwrap()\n        .unwrap()\n        .header\n        .base_fee_per_gas\n        .unwrap();\n\n    // unchanged, half block\n    assert_eq!(next_base_fee, { INITIAL_BASE_FEE });\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_basefee_empty_block() {\n    let (api, handle) = spawn(NodeConfig::test().with_base_fee(Some(INITIAL_BASE_FEE))).await;\n\n    let wallet = handle.dev_wallets().next().unwrap();\n    let signer: EthereumWallet = wallet.clone().into();\n\n    let provider = http_provider_with_signer(&handle.http_endpoint(), signer);\n\n    let tx = TransactionRequest::default().with_to(Address::random()).with_value(U256::from(1337));\n    let tx = WithOtherFields::new(tx);\n\n    provider.send_transaction(tx.clone()).await.unwrap().get_receipt().await.unwrap();\n\n    let base_fee = provider\n        .get_block(BlockId::latest())\n        .await\n        .unwrap()\n        .unwrap()\n        .header\n        .base_fee_per_gas\n        .unwrap();\n\n    // mine empty block\n    api.mine_one().await;\n\n    let next_base_fee = provider\n        .get_block(BlockId::latest())\n        .await\n        .unwrap()\n        .unwrap()\n        .header\n        .base_fee_per_gas\n        .unwrap();\n\n    // empty block, decreased base fee\n    assert!(next_base_fee < base_fee);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_respect_base_fee() {\n    let base_fee = 50u128;\n    let (_api, handle) = spawn(NodeConfig::test().with_base_fee(Some(base_fee as u64))).await;\n\n    let provider = handle.http_provider();\n\n    let tx = TransactionRequest::default().with_to(Address::random()).with_value(U256::from(100));\n    let mut tx = WithOtherFields::new(tx);\n\n    let mut underpriced = tx.clone();\n    underpriced.set_gas_price(base_fee - 1);\n\n    let res = provider.send_transaction(underpriced).await;\n    assert!(res.is_err());\n    assert!(res.unwrap_err().to_string().contains(\"max fee per gas less than block base fee\"));\n\n    tx.set_gas_price(base_fee);\n    provider.send_transaction(tx.clone()).await.unwrap().get_receipt().await.unwrap();\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_tip_above_fee_cap() {\n    let base_fee = 50u128;\n    let (_api, handle) = spawn(NodeConfig::test().with_base_fee(Some(base_fee as u64))).await;\n\n    let provider = handle.http_provider();\n\n    let tx = TransactionRequest::default()\n        .max_fee_per_gas(base_fee)\n        .max_priority_fee_per_gas(base_fee + 1)\n        .with_to(Address::random())\n        .with_value(U256::from(100));\n    let tx = WithOtherFields::new(tx);\n\n    let res = provider.send_transaction(tx.clone()).await;\n    assert!(res.is_err());\n    assert!(\n        res.unwrap_err()\n            .to_string()\n            .contains(\"max priority fee per gas higher than max fee per gas\")\n    );\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_can_use_fee_history() {\n    let base_fee = 50u128;\n    let (_api, handle) = spawn(NodeConfig::test().with_base_fee(Some(base_fee as u64))).await;\n    let provider = handle.http_provider();\n\n    for _ in 0..10 {\n        let fee_history = provider.get_fee_history(1, Default::default(), &[]).await.unwrap();\n        let next_base_fee = *fee_history.base_fee_per_gas.last().unwrap();\n\n        let tx = TransactionRequest::default()\n            .with_to(Address::random())\n            .with_value(U256::from(100))\n            .with_gas_price(next_base_fee);\n        let tx = WithOtherFields::new(tx);\n\n        let receipt =\n            provider.send_transaction(tx.clone()).await.unwrap().get_receipt().await.unwrap();\n        assert!(receipt.inner.inner.is_success());\n\n        let fee_history_after = provider.get_fee_history(1, Default::default(), &[]).await.unwrap();\n        let latest_fee_history_fee = *fee_history_after.base_fee_per_gas.first().unwrap() as u64;\n        let latest_block = provider.get_block(BlockId::latest()).await.unwrap().unwrap();\n\n        assert_eq!(latest_block.header.base_fee_per_gas.unwrap(), latest_fee_history_fee);\n        assert_eq!(latest_fee_history_fee, next_base_fee as u64);\n    }\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_estimate_gas_empty_data() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n    let accounts = handle.dev_accounts().collect::<Vec<_>>();\n    let from = accounts[0];\n    let to = accounts[1];\n\n    let tx_without_data =\n        TransactionRequest::default().with_from(from).with_to(to).with_value(U256::from(1));\n\n    let gas_without_data = api\n        .estimate_gas(WithOtherFields::new(tx_without_data), None, Default::default())\n        .await\n        .unwrap();\n\n    let tx_with_empty_data = TransactionRequest::default()\n        .with_from(from)\n        .with_to(to)\n        .with_value(U256::from(1))\n        .with_input(vec![]);\n\n    let gas_with_empty_data = api\n        .estimate_gas(WithOtherFields::new(tx_with_empty_data), None, Default::default())\n        .await\n        .unwrap();\n\n    let tx_with_data = TransactionRequest::default()\n        .with_from(from)\n        .with_to(to)\n        .with_value(U256::from(1))\n        .with_input(vec![0x12, 0x34]);\n\n    let gas_with_data = api\n        .estimate_gas(WithOtherFields::new(tx_with_data), None, Default::default())\n        .await\n        .unwrap();\n\n    assert_eq!(gas_without_data, U256::from(GAS_TRANSFER));\n    assert_eq!(gas_with_empty_data, U256::from(GAS_TRANSFER));\n    assert!(gas_with_data > U256::from(GAS_TRANSFER));\n    assert_eq!(gas_without_data, gas_with_empty_data);\n}\n"
  },
  {
    "path": "crates/anvil/tests/it/genesis.rs",
    "content": "//! genesis.json tests\n\nuse crate::fork::fork_config;\nuse alloy_genesis::Genesis;\nuse alloy_primitives::{Address, U256};\nuse alloy_provider::Provider;\nuse anvil::{NodeConfig, spawn};\nuse std::str::FromStr;\n\nconst GENESIS: &str = r#\"{\n  \"config\": {\n    \"chainId\": 19763,\n    \"homesteadBlock\": 0,\n    \"eip150Block\": 0,\n    \"eip155Block\": 0,\n    \"eip158Block\": 0,\n    \"byzantiumBlock\": 0,\n    \"ethash\": {}\n  },\n  \"nonce\": \"0xdeadbeefdeadbeef\",\n  \"timestamp\": \"0x0\",\n  \"extraData\": \"0x0000000000000000000000000000000000000000000000000000000000000000\",\n  \"gasLimit\": \"0x80000000\",\n  \"difficulty\": \"0x20000\",\n  \"mixHash\": \"0x0000000000000000000000000000000000000000000000000000000000000000\",\n  \"coinbase\": \"0x0000000000000000000000000000000000000000\",\n  \"alloc\": {\n    \"71562b71999873db5b286df957af199ec94617f7\": {\n      \"balance\": \"0xffffffffffffffffffffffffff\"\n    }\n  },\n  \"number\": 73,\n  \"gasUsed\": \"0x0\",\n  \"parentHash\": \"0x0000000000000000000000000000000000000000000000000000000000000000\"\n}\n\"#;\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_apply_genesis() {\n    let genesis: Genesis = serde_json::from_str(GENESIS).unwrap();\n    let (_api, handle) = spawn(NodeConfig::test().with_genesis(Some(genesis))).await;\n\n    let provider = handle.http_provider();\n\n    assert_eq!(provider.get_chain_id().await.unwrap(), 19763u64);\n\n    let addr: Address = Address::from_str(\"71562b71999873db5b286df957af199ec94617f7\").unwrap();\n    let balance = provider.get_balance(addr).await.unwrap();\n\n    let expected: U256 = U256::from_str_radix(\"ffffffffffffffffffffffffff\", 16).unwrap();\n    assert_eq!(balance, expected);\n\n    let block_number = provider.get_block_number().await.unwrap();\n    assert_eq!(block_number, 73u64);\n}\n\n// <https://github.com/foundry-rs/foundry/issues/10059>\n// <https://github.com/foundry-rs/foundry/issues/10238>\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn chain_id_precedence() {\n    // Order: --chain-id > fork-chain-id > Genesis > default.\n\n    // --chain-id > Genesis.\n    let genesis: Genesis = serde_json::from_str(GENESIS).unwrap();\n    let (_api, handle) =\n        spawn(NodeConfig::test().with_genesis(Some(genesis.clone())).with_chain_id(Some(300u64)))\n            .await;\n    let provider = handle.http_provider();\n    let chain_id = provider.get_chain_id().await.unwrap();\n    assert_eq!(chain_id, 300u64);\n\n    // fork > Genesis.\n    let (_api, handle) = spawn(fork_config().with_genesis(Some(genesis.clone()))).await;\n    let provider = handle.http_provider();\n    let chain_id = provider.get_chain_id().await.unwrap();\n    assert_eq!(chain_id, 1);\n\n    // --chain-id > fork.\n    let (_api, handle) = spawn(fork_config().with_chain_id(Some(300u64))).await;\n    let provider = handle.http_provider();\n    let chain_id = provider.get_chain_id().await.unwrap();\n    assert_eq!(chain_id, 300u64);\n\n    // fork\n    let (_api, handle) = spawn(fork_config()).await;\n    let provider = handle.http_provider();\n    let chain_id = provider.get_chain_id().await.unwrap();\n    assert_eq!(chain_id, 1);\n\n    // Genesis\n    let (_api, handle) = spawn(NodeConfig::test().with_genesis(Some(genesis))).await;\n    let provider = handle.http_provider();\n    let chain_id = provider.get_chain_id().await.unwrap();\n    assert_eq!(chain_id, 19763u64);\n\n    // default\n    let (_api, handle) = spawn(NodeConfig::test()).await;\n    let provider = handle.http_provider();\n    let chain_id = provider.get_chain_id().await.unwrap();\n    assert_eq!(chain_id, 31337);\n}\n"
  },
  {
    "path": "crates/anvil/tests/it/ipc.rs",
    "content": "//! IPC tests\n\nuse crate::{init_tracing, utils::connect_pubsub};\nuse alloy_primitives::U256;\nuse alloy_provider::Provider;\nuse anvil::{NodeConfig, spawn};\nuse futures::StreamExt;\nuse tempfile::TempDir;\n\nfn ipc_config() -> (Option<TempDir>, NodeConfig) {\n    let path;\n    let dir;\n    if cfg!(unix) {\n        let tmp = tempfile::tempdir().unwrap();\n        path = tmp.path().join(\"anvil.ipc\").to_string_lossy().into_owned();\n        dir = Some(tmp);\n    } else {\n        dir = None;\n        path = format!(r\"\\\\.\\pipe\\anvil_test_{}.ipc\", rand::random::<u64>());\n    }\n    let config = NodeConfig::test().with_ipc(Some(Some(path)));\n    (dir, config)\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_get_block_number_ipc() {\n    init_tracing();\n\n    let (_dir, config) = ipc_config();\n    let (api, handle) = spawn(config).await;\n\n    let block_num = api.block_number().unwrap();\n    assert_eq!(block_num, U256::ZERO);\n\n    let provider = handle.ipc_provider().unwrap();\n\n    let num = provider.get_block_number().await.unwrap();\n    assert_eq!(num, block_num.to::<u64>());\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_sub_new_heads_ipc() {\n    init_tracing();\n\n    let (_dir, config) = ipc_config();\n    let (api, handle) = spawn(config).await;\n\n    let provider = connect_pubsub(handle.ipc_path().unwrap().as_str()).await;\n    // mine a block every 1 seconds\n    api.anvil_set_interval_mining(1).unwrap();\n\n    let blocks = provider.subscribe_blocks().await.unwrap().into_stream();\n\n    let blocks = blocks.take(3).collect::<Vec<_>>().await;\n    let block_numbers = blocks.into_iter().map(|b| b.number).collect::<Vec<_>>();\n\n    assert_eq!(block_numbers, vec![1, 2, 3]);\n}\n"
  },
  {
    "path": "crates/anvil/tests/it/logs.rs",
    "content": "//! log/event related tests\n\nuse crate::{\n    abi::SimpleStorage::{self},\n    utils::{http_provider_with_signer, ws_provider_with_signer},\n};\nuse alloy_network::EthereumWallet;\nuse alloy_primitives::{B256, map::B256HashSet};\nuse alloy_provider::Provider;\nuse alloy_rpc_types::{BlockNumberOrTag, Filter};\nuse anvil::{NodeConfig, spawn};\nuse futures::StreamExt;\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn get_past_events() {\n    let (_api, handle) = spawn(NodeConfig::test()).await;\n\n    let wallet = handle.dev_wallets().next().unwrap();\n    let account = wallet.address();\n    let signer: EthereumWallet = wallet.into();\n\n    let provider = http_provider_with_signer(&handle.http_endpoint(), signer);\n\n    let contract =\n        SimpleStorage::deploy(provider.clone(), \"initial value\".to_string()).await.unwrap();\n    let _ = contract\n        .setValue(\"hi\".to_string())\n        .from(account)\n        .send()\n        .await\n        .unwrap()\n        .get_receipt()\n        .await\n        .unwrap();\n    let simple_storage_address = *contract.address();\n\n    let filter = Filter::new()\n        .address(simple_storage_address)\n        .topic1(B256::from(account.into_word()))\n        .from_block(BlockNumberOrTag::from(0));\n\n    let logs = provider\n        .get_logs(&filter)\n        .await\n        .unwrap()\n        .into_iter()\n        .map(|log| log.log_decode::<SimpleStorage::ValueChanged>().unwrap())\n        .collect::<Vec<_>>();\n\n    // 2 events, 1 in constructor, 1 in call\n    assert_eq!(logs[0].inner.newValue, \"initial value\");\n    assert_eq!(logs[1].inner.newValue, \"hi\");\n    assert_eq!(logs.len(), 2);\n\n    // and we can fetch the events at a block hash\n    // let hash = provider.get_block(1).await.unwrap().unwrap().hash.unwrap();\n    let hash =\n        provider.get_block_by_number(BlockNumberOrTag::from(1)).await.unwrap().unwrap().header.hash;\n\n    let filter = Filter::new()\n        .address(simple_storage_address)\n        .topic1(B256::from(account.into_word()))\n        .at_block_hash(hash);\n\n    let logs = provider\n        .get_logs(&filter)\n        .await\n        .unwrap()\n        .into_iter()\n        .map(|log| log.log_decode::<SimpleStorage::ValueChanged>().unwrap())\n        .collect::<Vec<_>>();\n\n    assert_eq!(logs[0].inner.newValue, \"initial value\");\n    assert_eq!(logs.len(), 1);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn get_all_events() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n\n    let wallet = handle.dev_wallets().next().unwrap();\n    let account = wallet.address();\n    let signer: EthereumWallet = wallet.into();\n\n    let provider = http_provider_with_signer(&handle.http_endpoint(), signer);\n\n    let contract =\n        SimpleStorage::deploy(provider.clone(), \"initial value\".to_string()).await.unwrap();\n\n    api.anvil_set_auto_mine(false).await.unwrap();\n\n    let pre_logs =\n        provider.get_logs(&Filter::new().from_block(BlockNumberOrTag::Earliest)).await.unwrap();\n    assert_eq!(pre_logs.len(), 1);\n\n    let pre_logs =\n        provider.get_logs(&Filter::new().from_block(BlockNumberOrTag::Number(0))).await.unwrap();\n    assert_eq!(pre_logs.len(), 1);\n\n    // spread logs across several blocks\n    let num_tx = 10;\n    let tx = contract.setValue(\"hi\".to_string()).from(account);\n    for _ in 0..num_tx {\n        let tx = tx.send().await.unwrap();\n        api.mine_one().await;\n        tx.get_receipt().await.unwrap();\n    }\n\n    let logs =\n        provider.get_logs(&Filter::new().from_block(BlockNumberOrTag::Earliest)).await.unwrap();\n\n    let num_logs = num_tx + pre_logs.len();\n    assert_eq!(logs.len(), num_logs);\n\n    // test that logs returned from get_logs and get_transaction_receipt have\n    // the same log_index, block_number, and transaction_hash\n    let mut tasks = vec![];\n    let mut seen_tx_hashes = B256HashSet::default();\n    for log in &logs {\n        if seen_tx_hashes.contains(&log.transaction_hash.unwrap()) {\n            continue;\n        }\n        tasks.push(provider.get_transaction_receipt(log.transaction_hash.unwrap()));\n        seen_tx_hashes.insert(log.transaction_hash.unwrap());\n    }\n\n    let receipt_logs = futures::future::join_all(tasks)\n        .await\n        .into_iter()\n        .collect::<Result<Vec<_>, _>>()\n        .unwrap()\n        .into_iter()\n        .flat_map(|receipt| receipt.unwrap().inner.inner.inner.receipt.logs)\n        .collect::<Vec<_>>();\n\n    assert_eq!(receipt_logs.len(), logs.len());\n    for (receipt_log, log) in receipt_logs.iter().zip(logs.iter()) {\n        assert_eq!(receipt_log.transaction_hash, log.transaction_hash);\n        assert_eq!(receipt_log.block_number, log.block_number);\n        assert_eq!(receipt_log.log_index, log.log_index);\n    }\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn watch_events() {\n    let (_api, handle) = spawn(NodeConfig::test()).await;\n\n    let wallet = handle.dev_wallets().next().unwrap();\n    let account = wallet.address();\n    let signer: EthereumWallet = wallet.into();\n\n    let provider = http_provider_with_signer(&handle.http_endpoint(), signer.clone());\n\n    let contract1 =\n        SimpleStorage::deploy(provider.clone(), \"initial value\".to_string()).await.unwrap();\n\n    // Spawn the event listener.\n    let event1 = contract1.event_filter::<SimpleStorage::ValueChanged>();\n    let mut stream1 = event1.watch().await.unwrap().into_stream();\n\n    // Also set up a subscription for the same thing.\n    let ws = ws_provider_with_signer(&handle.ws_endpoint(), signer.clone());\n    let contract2 = SimpleStorage::new(*contract1.address(), ws);\n    let event2 = contract2.event_filter::<SimpleStorage::ValueChanged>();\n    let mut stream2 = event2.watch().await.unwrap().into_stream();\n\n    let num_tx = 3;\n\n    let starting_block_number = provider.get_block_number().await.unwrap();\n    for i in 0..num_tx {\n        contract1\n            .setValue(i.to_string())\n            .from(account)\n            .send()\n            .await\n            .unwrap()\n            .get_receipt()\n            .await\n            .unwrap();\n\n        let log = stream1.next().await.unwrap().unwrap();\n        let log2 = stream2.next().await.unwrap().unwrap();\n\n        assert_eq!(log.0.newValue, log2.0.newValue);\n        assert_eq!(log.0.newValue, i.to_string());\n        assert_eq!(log.1.block_number.unwrap(), starting_block_number + i + 1);\n\n        let hash = provider\n            .get_block_by_number(BlockNumberOrTag::from(starting_block_number + i + 1))\n            .await\n            .unwrap()\n            .unwrap()\n            .header\n            .hash;\n        assert_eq!(log.1.block_hash.unwrap(), hash);\n    }\n}\n"
  },
  {
    "path": "crates/anvil/tests/it/main.rs",
    "content": "mod abi;\nmod anvil;\nmod anvil_api;\nmod api;\nmod beacon_api;\nmod eip2935;\nmod eip4844;\nmod eip7702;\nmod fork;\nmod gas;\nmod genesis;\nmod ipc;\nmod logs;\nmod optimism;\nmod otterscan;\nmod proof;\nmod pubsub;\nmod revert;\nmod sign;\nmod simulate;\nmod state;\nmod traces;\nmod transaction;\nmod txpool;\npub mod utils;\nmod wsapi;\n\npub use foundry_test_utils::init_tracing;\n"
  },
  {
    "path": "crates/anvil/tests/it/optimism.rs",
    "content": "//! Tests for OP chain support.\n\nuse crate::utils::{http_provider, http_provider_with_signer};\nuse alloy_eips::eip2718::Encodable2718;\nuse alloy_network::{EthereumWallet, TransactionBuilder};\nuse alloy_primitives::{Address, Bloom, TxHash, TxKind, U256, b256};\nuse alloy_provider::Provider;\nuse alloy_rpc_types::{BlockId, TransactionRequest};\nuse alloy_serde::WithOtherFields;\nuse anvil::{NodeConfig, eth::fees::INITIAL_BASE_FEE, spawn};\nuse foundry_evm_networks::NetworkConfigs;\nuse op_alloy_consensus::TxDeposit;\nuse op_alloy_rpc_types::OpTransactionFields;\nuse serde_json::{Value, json};\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_deposits_not_supported_if_optimism_disabled() {\n    let (_api, handle) = spawn(NodeConfig::test()).await;\n    let provider = handle.http_provider();\n\n    let accounts: Vec<_> = handle.dev_wallets().collect();\n    let from = accounts[0].address();\n    let to = accounts[1].address();\n\n    let tx = TransactionRequest::default()\n        .with_from(from)\n        .with_to(to)\n        .with_value(U256::from(1234))\n        .with_gas_limit(21000);\n\n    let op_fields = OpTransactionFields {\n        source_hash: Some(b256!(\n            \"0x0000000000000000000000000000000000000000000000000000000000000000\"\n        )),\n        mint: Some(0),\n        is_system_tx: Some(true),\n        deposit_receipt_version: None,\n    };\n\n    let other = serde_json::to_value(op_fields).unwrap().try_into().unwrap();\n\n    let tx = WithOtherFields { inner: tx, other };\n\n    let err = provider.send_transaction(tx).await.unwrap_err();\n    let s = err.to_string();\n    assert!(s.contains(\"op-stack deposit tx received but is not supported\"), \"{s:?}\");\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_send_value_deposit_transaction() {\n    // enable the Optimism flag\n    let (api, handle) =\n        spawn(NodeConfig::test().with_networks(NetworkConfigs::with_optimism())).await;\n\n    let accounts: Vec<_> = handle.dev_wallets().collect();\n    let signer: EthereumWallet = accounts[0].clone().into();\n    let from = accounts[0].address();\n    let to = accounts[1].address();\n\n    let provider = http_provider_with_signer(&handle.http_endpoint(), signer);\n\n    let send_value = U256::from(1234);\n    let before_balance_to = provider.get_balance(to).await.unwrap();\n\n    let op_fields = OpTransactionFields {\n        source_hash: Some(b256!(\n            \"0x0000000000000000000000000000000000000000000000000000000000000000\"\n        )),\n        mint: Some(0),\n        is_system_tx: Some(true),\n        deposit_receipt_version: None,\n    };\n\n    let other = serde_json::to_value(op_fields).unwrap().try_into().unwrap();\n    let tx = TransactionRequest::default()\n        .with_from(from)\n        .with_to(to)\n        .with_value(send_value)\n        .with_gas_limit(21000);\n    let tx: WithOtherFields<TransactionRequest> = WithOtherFields { inner: tx, other };\n\n    let pending = provider.send_transaction(tx).await.unwrap().register().await.unwrap();\n\n    // mine block\n    api.evm_mine(None).await.unwrap();\n\n    let receipt =\n        provider.get_transaction_receipt(pending.tx_hash().to_owned()).await.unwrap().unwrap();\n    assert_eq!(receipt.from, from);\n    assert_eq!(receipt.to, Some(to));\n\n    // the recipient should have received the value\n    let after_balance_to = provider.get_balance(to).await.unwrap();\n    assert_eq!(after_balance_to, before_balance_to + send_value);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_send_value_raw_deposit_transaction() {\n    // enable the Optimism flag\n    let (api, handle) =\n        spawn(NodeConfig::test().with_networks(NetworkConfigs::with_optimism())).await;\n\n    let accounts: Vec<_> = handle.dev_wallets().collect();\n    let signer: EthereumWallet = accounts[0].clone().into();\n    let from = accounts[0].address();\n    let to = accounts[1].address();\n\n    let provider = http_provider_with_signer(&handle.http_endpoint(), signer.clone());\n\n    let send_value = U256::from(1234);\n    let before_balance_to = provider.get_balance(to).await.unwrap();\n\n    let tx = TransactionRequest::default()\n        .with_chain_id(31337)\n        .with_nonce(0)\n        .with_from(from)\n        .with_to(to)\n        .with_value(send_value)\n        .with_gas_limit(21_000)\n        .with_max_fee_per_gas(20_000_000_000)\n        .with_max_priority_fee_per_gas(1_000_000_000);\n\n    let op_fields = OpTransactionFields {\n        source_hash: Some(b256!(\n            \"0x0000000000000000000000000000000000000000000000000000000000000000\"\n        )),\n        mint: Some(0),\n        is_system_tx: Some(true),\n        deposit_receipt_version: None,\n    };\n    let other = serde_json::to_value(op_fields).unwrap().try_into().unwrap();\n    let tx = WithOtherFields { inner: tx, other };\n    let tx_envelope = tx.build(&signer).await.unwrap();\n    let mut tx_buffer = Vec::with_capacity(tx_envelope.encode_2718_len());\n    tx_envelope.encode_2718(&mut tx_buffer);\n    let tx_encoded = tx_buffer.as_slice();\n\n    let pending =\n        provider.send_raw_transaction(tx_encoded).await.unwrap().register().await.unwrap();\n\n    // mine block\n    api.evm_mine(None).await.unwrap();\n\n    let receipt =\n        provider.get_transaction_receipt(pending.tx_hash().to_owned()).await.unwrap().unwrap();\n    assert_eq!(receipt.from, from);\n    assert_eq!(receipt.to, Some(to));\n\n    // the recipient should have received the value\n    let after_balance_to = provider.get_balance(to).await.unwrap();\n    assert_eq!(after_balance_to, before_balance_to + send_value);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_deposit_transaction_hash_matches_sepolia() {\n    // enable the Optimism flag\n    let (_api, handle) =\n        spawn(NodeConfig::test().with_networks(NetworkConfigs::with_optimism())).await;\n\n    let accounts: Vec<_> = handle.dev_wallets().collect();\n    let signer: EthereumWallet = accounts[0].clone().into();\n    // https://sepolia-optimism.etherscan.io/tx/0xbf8b5f08c43e4b860715cd64fc0849bbce0d0ea20a76b269e7bc8886d112fca7\n    let tx_hash: TxHash = \"0xbf8b5f08c43e4b860715cd64fc0849bbce0d0ea20a76b269e7bc8886d112fca7\"\n        .parse::<TxHash>()\n        .unwrap();\n\n    // https://sepolia-optimism.etherscan.io/getRawTx?tx=0xbf8b5f08c43e4b860715cd64fc0849bbce0d0ea20a76b269e7bc8886d112fca7\n    let raw_deposit_tx = alloy_primitives::hex::decode(\n        \"7ef861a0dfd7ae78bf3c414cfaa77f13c0205c82eb9365e217b2daa3448c3156b69b27ac94778f2146f48179643473b82931c4cd7b8f153efd94778f2146f48179643473b82931c4cd7b8f153efd872386f26fc10000872386f26fc10000830186a08080\",\n    )\n    .unwrap();\n\n    let provider = http_provider_with_signer(&handle.http_endpoint(), signer.clone());\n\n    let receipt = provider\n        .send_raw_transaction(raw_deposit_tx.as_slice())\n        .await\n        .unwrap()\n        .get_receipt()\n        .await\n        .unwrap();\n\n    assert_eq!(receipt.transaction_hash, tx_hash);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_deposit_tx_checks_sufficient_funds_after_applying_deposited_value() {\n    // enable the Optimism flag\n    let (_api, handle) =\n        spawn(NodeConfig::test().with_networks(NetworkConfigs::with_optimism())).await;\n\n    let provider = http_provider(&handle.http_endpoint());\n\n    let sender = Address::random();\n    let recipient = Address::random();\n    let send_value = 1_000_000_000_u128;\n\n    let sender_prev_balance = provider.get_balance(sender).await.unwrap();\n    assert_eq!(sender_prev_balance, U256::from(0));\n\n    let recipient_prev_balance = provider.get_balance(recipient).await.unwrap();\n    assert_eq!(recipient_prev_balance, U256::from(0));\n\n    let deposit_tx = TxDeposit {\n        source_hash: b256!(\"0x0000000000000000000000000000000000000000000000000000000000000000\"),\n        from: sender,\n        to: TxKind::Call(recipient),\n        mint: send_value,\n        value: U256::from(send_value),\n        gas_limit: 21_000,\n        is_system_transaction: false,\n        input: Vec::new().into(),\n    };\n\n    let mut tx_buffer = Vec::new();\n    deposit_tx.encode_2718(&mut tx_buffer);\n\n    provider.send_raw_transaction(&tx_buffer).await.unwrap().get_receipt().await.unwrap();\n\n    let sender_new_balance = provider.get_balance(sender).await.unwrap();\n    // sender should've sent the entire deposited value to recipient\n    assert_eq!(sender_new_balance, U256::from(0));\n\n    let recipient_new_balance = provider.get_balance(recipient).await.unwrap();\n    // recipient should've received the entire deposited value\n    assert_eq!(recipient_new_balance, U256::from(send_value));\n}\n\n#[test]\nfn preserves_op_fields_in_convert_to_anvil_receipt() {\n    let receipt_json = json!({\n        \"status\": \"0x1\",\n        \"cumulativeGasUsed\": \"0x74e483\",\n        \"logs\": [],\n        \"logsBloom\": Bloom::default(),\n        \"type\": \"0x2\",\n        \"transactionHash\": \"0x91181b0dca3b29aa136eeb2f536be5ce7b0aebc949be1c44b5509093c516097d\",\n        \"transactionIndex\": \"0x10\",\n        \"blockHash\": \"0x54bafb12e8cea9bb355fbf03a4ac49e42a2a1a80fa6cf4364b342e2de6432b5d\",\n        \"blockNumber\": \"0x7b1ab93\",\n        \"gasUsed\": \"0xc222\",\n        \"effectiveGasPrice\": \"0x18961\",\n        \"from\": \"0x2d815240a61731c75fa01b2793e1d3ed09f289d0\",\n        \"to\":   \"0x4200000000000000000000000000000000000000\",\n        \"contractAddress\": Value::Null,\n        \"l1BaseFeeScalar\":     \"0x146b\",\n        \"l1BlobBaseFee\":       \"0x6a83078\",\n        \"l1BlobBaseFeeScalar\": \"0xf79c5\",\n        \"l1Fee\":               \"0x51a9af7fd3\",\n        \"l1GasPrice\":          \"0x972fe4acc\",\n        \"l1GasUsed\":           \"0x640\",\n    });\n\n    let receipt: alloy_network::AnyTransactionReceipt =\n        serde_json::from_value(receipt_json).expect(\"valid receipt json\");\n\n    let converted =\n        foundry_primitives::FoundryTxReceipt::try_from(receipt).expect(\"conversion should succeed\");\n    let converted_json = serde_json::to_value(&converted).expect(\"serialize to json\");\n\n    for (key, expected) in [\n        (\"l1Fee\", \"0x51a9af7fd3\"),\n        (\"l1GasPrice\", \"0x972fe4acc\"),\n        (\"l1GasUsed\", \"0x640\"),\n        (\"l1BaseFeeScalar\", \"0x146b\"),\n        (\"l1BlobBaseFee\", \"0x6a83078\"),\n        (\"l1BlobBaseFeeScalar\", \"0xf79c5\"),\n    ] {\n        let got = converted_json.get(key).and_then(Value::as_str);\n        assert_eq!(got, Some(expected), \"field `{key}` mismatch\");\n    }\n}\n\nconst GAS_TRANSFER: u64 = 21_000;\n\n/// Test that Optimism uses Canyon base fee params instead of Ethereum params.\n///\n/// Optimism Canyon uses different EIP-1559 parameters:\n/// - elasticity_multiplier: 6 (vs Ethereum's 2)\n/// - base_fee_max_change_denominator: 250 (vs Ethereum's 8)\n///\n/// This means with a full block:\n/// - Ethereum: base_fee increases by base_fee * 1 / 8 = 12.5%\n/// - Optimism: base_fee increases by base_fee * 5 / 250 = 2%\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_optimism_base_fee_params() {\n    // Spawn an Optimism node with a gas limit equal to one transfer (full block scenario)\n    let (_api, handle) = spawn(\n        NodeConfig::test()\n            .with_networks(NetworkConfigs::with_optimism())\n            .with_base_fee(Some(INITIAL_BASE_FEE))\n            .with_gas_limit(Some(GAS_TRANSFER)),\n    )\n    .await;\n\n    let wallet = handle.dev_wallets().next().unwrap();\n    let signer: EthereumWallet = wallet.clone().into();\n\n    let provider = http_provider_with_signer(&handle.http_endpoint(), signer);\n\n    let tx = TransactionRequest::default().to(Address::random()).with_value(U256::from(1337));\n    let tx = WithOtherFields::new(tx);\n\n    // Send first transaction to fill the block\n    provider.send_transaction(tx.clone()).await.unwrap().get_receipt().await.unwrap();\n\n    let base_fee = provider\n        .get_block(BlockId::latest())\n        .await\n        .unwrap()\n        .unwrap()\n        .header\n        .base_fee_per_gas\n        .unwrap();\n\n    // Send second transaction to fill the next block\n    provider.send_transaction(tx.clone()).await.unwrap().get_receipt().await.unwrap();\n\n    let next_base_fee = provider\n        .get_block(BlockId::latest())\n        .await\n        .unwrap()\n        .unwrap()\n        .header\n        .base_fee_per_gas\n        .unwrap();\n\n    assert!(next_base_fee > base_fee, \"base fee should increase with full block\");\n\n    // Optimism Canyon formula: base_fee * (elasticity - 1) / denominator = base_fee * 5 / 250\n    // = INITIAL_BASE_FEE * 5 / 250 = 1_000_000_000 * 5 / 250 = 20_000_000\n    //\n    // Note: Ethereum would be INITIAL_BASE_FEE + 125_000_000 (12.5% increase)\n    let expected_op_increase = INITIAL_BASE_FEE * 5 / 250; // 2% increase = 20_000_000\n    assert_eq!(\n        next_base_fee,\n        INITIAL_BASE_FEE + expected_op_increase,\n        \"Optimism should use Canyon base fee params (2% max increase), not Ethereum's (12.5%)\"\n    );\n\n    // Explicitly verify it's NOT using Ethereum params (which would give 12.5% increase)\n    let ethereum_increase = INITIAL_BASE_FEE / 8; // 125_000_000\n    assert_ne!(\n        next_base_fee,\n        INITIAL_BASE_FEE + ethereum_increase,\n        \"Should not be using Ethereum base fee params\"\n    );\n}\n"
  },
  {
    "path": "crates/anvil/tests/it/otterscan.rs",
    "content": "//! Tests for otterscan endpoints.\n\nuse crate::abi::Multicall;\nuse alloy_network::TransactionResponse;\nuse alloy_primitives::{Address, Bytes, U256, address};\nuse alloy_provider::Provider;\nuse alloy_rpc_types::{\n    BlockNumberOrTag, TransactionRequest,\n    trace::otterscan::{InternalOperation, OperationType, TraceEntry},\n};\nuse alloy_serde::WithOtherFields;\nuse alloy_sol_types::{SolCall, SolError, SolValue, sol};\nuse anvil::{NodeConfig, spawn};\nuse foundry_evm::hardfork::EthereumHardfork;\nuse std::collections::VecDeque;\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn erigon_get_header_by_number() {\n    let (api, _handle) = spawn(NodeConfig::test()).await;\n    api.mine_one().await;\n\n    let res0 = api.erigon_get_header_by_number(0.into()).await.unwrap().unwrap();\n    assert_eq!(res0.header.number, 0);\n\n    let res1 = api.erigon_get_header_by_number(1.into()).await.unwrap().unwrap();\n    assert_eq!(res1.header.number, 1);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn ots_get_api_level() {\n    let (api, _handle) = spawn(NodeConfig::test()).await;\n\n    assert_eq!(api.ots_get_api_level().await.unwrap(), 8);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn ots_get_internal_operations_contract_deploy() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n    let provider = handle.http_provider();\n    let sender = handle.dev_accounts().next().unwrap();\n\n    let contract_receipt =\n        Multicall::deploy_builder(&provider).send().await.unwrap().get_receipt().await.unwrap();\n\n    let res = api.ots_get_internal_operations(contract_receipt.transaction_hash).await.unwrap();\n    assert_eq!(\n        res,\n        [InternalOperation {\n            r#type: OperationType::OpCreate,\n            from: sender,\n            to: contract_receipt.contract_address.unwrap(),\n            value: U256::from(0)\n        }],\n    );\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn ots_get_internal_operations_contract_transfer() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n    let provider = handle.http_provider();\n\n    let accounts: Vec<_> = handle.dev_wallets().collect();\n    let from = accounts[0].address();\n    let to = accounts[1].address();\n\n    let amount = handle.genesis_balance().checked_div(U256::from(2u64)).unwrap();\n\n    let tx = TransactionRequest::default().to(to).value(amount).from(from);\n    let tx = WithOtherFields::new(tx);\n\n    let receipt = provider.send_transaction(tx).await.unwrap().get_receipt().await.unwrap();\n\n    let res = api.ots_get_internal_operations(receipt.transaction_hash).await.unwrap();\n    assert_eq!(\n        res,\n        [InternalOperation { r#type: OperationType::OpTransfer, from, to, value: amount }],\n    );\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn ots_get_internal_operations_contract_create2() {\n    sol!(\n        #[sol(rpc, bytecode = \"60808060405234601557610147908161001a8239f35b5f80fdfe6080600436101561000e575f80fd5b5f3560e01c636cd5c39b14610021575f80fd5b346100d0575f3660031901126100d0575f602082810191825282526001600160401b03916040810191838311828410176100d4578261008960405f959486958252606081019486865281518091608084015e81018660808201520360208101845201826100ee565b519082734e59b44847b379578588920ca78fbf26c0b4956c5af1903d156100e8573d9081116100d4576040516100c991601f01601f1916602001906100ee565b156100d057005b5f80fd5b634e487b7160e01b5f52604160045260245ffd5b506100c9565b601f909101601f19168101906001600160401b038211908210176100d45760405256fea2646970667358221220f76968e121fc002b537029df51a2aecca0793282491baf84b872ffbfbfb1c9d764736f6c63430008190033\")]\n        contract Contract {\n            address constant CREATE2_DEPLOYER = 0x4e59b44847b379578588920cA78FbF26c0B4956C;\n\n            function deployContract() public {\n                uint256 salt = 0;\n                uint256 code = 0;\n                bytes memory creationCode = abi.encodePacked(code);\n                (bool success,) = address(CREATE2_DEPLOYER).call(abi.encodePacked(salt, creationCode));\n                require(success);\n            }\n        }\n    );\n\n    let (api, handle) = spawn(NodeConfig::test()).await;\n    let provider = handle.http_provider();\n\n    let contract = Contract::deploy(&provider).await.unwrap();\n\n    let receipt = contract.deployContract().send().await.unwrap().get_receipt().await.unwrap();\n\n    let res = api.ots_get_internal_operations(receipt.transaction_hash).await.unwrap();\n    assert_eq!(\n        res,\n        [InternalOperation {\n            r#type: OperationType::OpCreate2,\n            from: address!(\"0x4e59b44847b379578588920cA78FbF26c0B4956C\"),\n            to: address!(\"0x347bcdad821abc09b8c275881b368de36476b62c\"),\n            value: U256::from(0),\n        }],\n    );\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn ots_get_internal_operations_contract_selfdestruct_london() {\n    ots_get_internal_operations_contract_selfdestruct(EthereumHardfork::London).await;\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn ots_get_internal_operations_contract_selfdestruct_cancun() {\n    ots_get_internal_operations_contract_selfdestruct(EthereumHardfork::Cancun).await;\n}\n\nasync fn ots_get_internal_operations_contract_selfdestruct(hardfork: EthereumHardfork) {\n    sol!(\n        #[sol(rpc, bytecode = \"608080604052607f908160108239f3fe6004361015600c57600080fd5b6000803560e01c6375fc8e3c14602157600080fd5b346046578060031936011260465773dcdd539da22bffaa499dbea4d37d086dde196e75ff5b80fdfea264697066735822122080a9ad005cc408b2d4e30ca11216d8e310700fbcdf58a629d6edbb91531f9c6164736f6c63430008190033\")]\n        contract Contract {\n            constructor() payable {}\n            function goodbye() public {\n                selfdestruct(payable(0xDcDD539DA22bfFAa499dBEa4d37d086Dde196E75));\n            }\n        }\n    );\n\n    let (api, handle) = spawn(NodeConfig::test().with_hardfork(Some(hardfork.into()))).await;\n    let provider = handle.http_provider();\n\n    let sender = handle.dev_accounts().next().unwrap();\n    let value = U256::from(69);\n\n    let contract_address =\n        Contract::deploy_builder(&provider).from(sender).value(value).deploy().await.unwrap();\n    let contract = Contract::new(contract_address, &provider);\n\n    let receipt = contract.goodbye().send().await.unwrap().get_receipt().await.unwrap();\n\n    let expected_to = address!(\"0xDcDD539DA22bfFAa499dBEa4d37d086Dde196E75\");\n    let expected_value = value;\n\n    let res = api.ots_get_internal_operations(receipt.transaction_hash).await.unwrap();\n    assert_eq!(\n        res,\n        [InternalOperation {\n            r#type: OperationType::OpSelfDestruct,\n            from: contract_address,\n            to: expected_to,\n            value: expected_value,\n        }],\n    );\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn ots_has_code() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n    let provider = handle.http_provider();\n    let sender = handle.dev_accounts().next().unwrap();\n\n    api.mine_one().await;\n\n    let contract_address = sender.create(0);\n\n    // no code in the address before deploying\n    assert!(!api.ots_has_code(contract_address, BlockNumberOrTag::Number(1)).await.unwrap());\n\n    let contract_builder = Multicall::deploy_builder(&provider);\n    let contract_receipt = contract_builder.send().await.unwrap().get_receipt().await.unwrap();\n\n    let num = provider.get_block_number().await.unwrap();\n    assert_eq!(num, contract_receipt.block_number.unwrap());\n\n    // code is detected after deploying\n    assert!(api.ots_has_code(contract_address, BlockNumberOrTag::Number(num)).await.unwrap());\n\n    // code is not detected for the previous block\n    assert!(!api.ots_has_code(contract_address, BlockNumberOrTag::Number(num - 1)).await.unwrap());\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_call_ots_trace_transaction() {\n    sol!(\n        #[sol(rpc, bytecode = \"608080604052346026575f80546001600160a01b0319163317905561025e908161002b8239f35b5f80fdfe6080604081815260049081361015610015575f80fd5b5f925f3560e01c9081636a6758fe1461019a5750806396385e3914610123578063a1325397146101115763c04062261461004d575f80fd5b5f3660031901126100d5578051633533ac7f60e11b81526020818481305afa80156100cb576100d9575b50303b156100d55780516396385e3960e01b8152915f83828183305af180156100cb576100a2578380f35b919250906001600160401b0383116100b8575052005b604190634e487b7160e01b5f525260245ffd5b82513d5f823e3d90fd5b5f80fd5b6020813d602011610109575b816100f2602093836101b3565b810103126100d55751801515036100d5575f610077565b3d91506100e5565b346100d5575f3660031901126100d557005b5090346100d5575f3660031901126100d5575f805481908190819047906001600160a01b03165af1506101546101ea565b50815163a132539760e01b6020820190815282825292909182820191906001600160401b038311848410176100b8575f8086868686525190305af4506101986101ea565b005b346100d5575f3660031901126100d55780600160209252f35b601f909101601f19168101906001600160401b038211908210176101d657604052565b634e487b7160e01b5f52604160045260245ffd5b3d15610223573d906001600160401b0382116101d65760405191610218601f8201601f1916602001846101b3565b82523d5f602084013e565b60609056fea264697066735822122099817ea378044f1f6434272aeb1f3f01a734645e599e69b4caf2ba7a4fb65f9d64736f6c63430008190033\")]\n        contract Contract {\n            address private owner;\n\n            constructor() {\n                owner = msg.sender;\n            }\n\n            function run() payable public {\n                this.do_staticcall();\n                this.do_call();\n            }\n\n            function do_staticcall() external view returns (bool) {\n                return true;\n            }\n\n            function do_call() external {\n                owner.call{value: address(this).balance}(\"\");\n                address(this).delegatecall(abi.encodeWithSignature(\"do_delegatecall()\"));\n            }\n\n            function do_delegatecall() external {}\n        }\n    );\n\n    let (api, handle) = spawn(NodeConfig::test()).await;\n    let provider = handle.http_provider();\n    let wallets = handle.dev_wallets().collect::<Vec<_>>();\n    let sender = wallets[0].address();\n\n    let contract_address = Contract::deploy_builder(&provider).from(sender).deploy().await.unwrap();\n    let contract = Contract::new(contract_address, &provider);\n\n    let receipt =\n        contract.run().value(U256::from(1337)).send().await.unwrap().get_receipt().await.unwrap();\n\n    let res = api.ots_trace_transaction(receipt.transaction_hash).await.unwrap();\n    let expected = vec![\n        TraceEntry {\n            r#type: \"CALL\".to_string(),\n            depth: 0,\n            from: sender,\n            to: contract_address,\n            value: Some(U256::from(1337)),\n            input: Contract::runCall::SELECTOR.into(),\n            output: Bytes::new(),\n        },\n        TraceEntry {\n            r#type: \"STATICCALL\".to_string(),\n            depth: 1,\n            from: contract_address,\n            to: contract_address,\n            value: Some(U256::ZERO),\n            input: Contract::do_staticcallCall::SELECTOR.into(),\n            output: true.abi_encode().into(),\n        },\n        TraceEntry {\n            r#type: \"CALL\".to_string(),\n            depth: 1,\n            from: contract_address,\n            to: contract_address,\n            value: Some(U256::ZERO),\n            input: Contract::do_callCall::SELECTOR.into(),\n            output: Bytes::new(),\n        },\n        TraceEntry {\n            r#type: \"CALL\".to_string(),\n            depth: 2,\n            from: contract_address,\n            to: sender,\n            value: Some(U256::from(1337)),\n            input: Bytes::new(),\n            output: Bytes::new(),\n        },\n        TraceEntry {\n            r#type: \"DELEGATECALL\".to_string(),\n            depth: 2,\n            from: contract_address,\n            to: contract_address,\n            value: Some(U256::ZERO),\n            input: Contract::do_delegatecallCall::SELECTOR.into(),\n            output: Bytes::new(),\n        },\n    ];\n    assert_eq!(res, expected);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn ots_get_transaction_error() {\n    sol!(\n        #[sol(rpc, bytecode = \"6080806040523460135760a3908160188239f35b5f80fdfe60808060405260043610156011575f80fd5b5f3560e01c63f67f4650146023575f80fd5b346069575f3660031901126069576346b7545f60e11b81526020600482015260126024820152712932bb32b93a29ba3934b733a337b7a130b960711b6044820152606490fd5b5f80fdfea264697066735822122069222918090d4d3ddc6a9c8b6ef282464076c71f923a0e8618ed25489b87f12b64736f6c63430008190033\")]\n        contract Contract {\n            error CustomError(string msg);\n\n            function trigger_revert() public {\n                revert CustomError(\"RevertStringFooBar\");\n            }\n        }\n    );\n\n    let (api, handle) = spawn(NodeConfig::test()).await;\n    let provider = handle.http_provider();\n\n    let contract = Contract::deploy(&provider).await.unwrap();\n\n    let receipt = contract.trigger_revert().send().await.unwrap().get_receipt().await.unwrap();\n\n    let err = api.ots_get_transaction_error(receipt.transaction_hash).await.unwrap();\n    let expected = Contract::CustomError { msg: String::from(\"RevertStringFooBar\") }.abi_encode();\n    assert_eq!(err, Bytes::from(expected));\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn ots_get_transaction_error_no_error() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n    let provider = handle.http_provider();\n\n    // Send a successful transaction\n    let tx = TransactionRequest::default().to(Address::random()).value(U256::from(100));\n    let tx = WithOtherFields::new(tx);\n    let receipt = provider.send_transaction(tx).await.unwrap().get_receipt().await.unwrap();\n\n    let res = api.ots_get_transaction_error(receipt.transaction_hash).await.unwrap();\n    assert!(res.is_empty(), \"{res}\");\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn ots_get_block_details() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n    let provider = handle.http_provider();\n\n    let tx = TransactionRequest::default().to(Address::random()).value(U256::from(100));\n    let tx = WithOtherFields::new(tx);\n    provider.send_transaction(tx).await.unwrap().get_receipt().await.unwrap();\n\n    let result = api.ots_get_block_details(1.into()).await.unwrap();\n\n    assert_eq!(result.block.transaction_count, 1);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn ots_get_block_details_by_hash() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n    let provider = handle.http_provider();\n\n    let tx = TransactionRequest::default().to(Address::random()).value(U256::from(100));\n    let tx = WithOtherFields::new(tx);\n    let receipt = provider.send_transaction(tx).await.unwrap().get_receipt().await.unwrap();\n\n    let block_hash = receipt.block_hash.unwrap();\n    let result = api.ots_get_block_details_by_hash(block_hash).await.unwrap();\n\n    assert_eq!(result.block.transaction_count, 1);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn ots_get_block_transactions() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n    let provider = handle.http_provider();\n\n    // disable automine\n    api.anvil_set_auto_mine(false).await.unwrap();\n\n    let mut hashes = VecDeque::new();\n    for i in 0..10 {\n        let tx =\n            TransactionRequest::default().to(Address::random()).value(U256::from(100)).nonce(i);\n        let tx = WithOtherFields::new(tx);\n        let pending_receipt =\n            provider.send_transaction(tx).await.unwrap().register().await.unwrap();\n        hashes.push_back(*pending_receipt.tx_hash());\n    }\n\n    api.mine_one().await;\n\n    let page_size = 3;\n    for page in 0..4 {\n        let result = api.ots_get_block_transactions(1, page, page_size).await.unwrap();\n\n        assert!(result.receipts.len() <= page_size);\n        let len = result.receipts.len();\n        assert!(len <= page_size);\n        assert!(result.fullblock.transaction_count == result.receipts.len());\n\n        result.receipts.iter().enumerate().for_each(|(i, receipt)| {\n            let expected = hashes.pop_front();\n            assert_eq!(expected, Some(receipt.receipt.transaction_hash));\n            assert_eq!(expected, result.fullblock.block.transactions.hashes().nth(i));\n        });\n    }\n\n    assert!(hashes.is_empty());\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn ots_search_transactions_before() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n    let provider = handle.http_provider();\n    let sender = handle.dev_accounts().next().unwrap();\n\n    let mut hashes = vec![];\n\n    for i in 0..7 {\n        let tx =\n            TransactionRequest::default().to(Address::random()).value(U256::from(100)).nonce(i);\n        let tx = WithOtherFields::new(tx);\n        let receipt = provider.send_transaction(tx).await.unwrap().get_receipt().await.unwrap();\n        hashes.push(receipt.transaction_hash);\n    }\n\n    let page_size = 2;\n    let mut block = 0;\n    for i in 0..4 {\n        let result = api.ots_search_transactions_before(sender, block, page_size).await.unwrap();\n\n        assert_eq!(result.first_page, i == 0);\n        assert_eq!(result.last_page, i == 3);\n\n        // check each individual hash\n        result.txs.iter().for_each(|tx| {\n            assert_eq!(hashes.pop(), Some(tx.tx_hash()));\n        });\n\n        block = result.txs.last().unwrap().block_number.unwrap();\n    }\n\n    assert!(hashes.is_empty());\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn ots_search_transactions_after() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n    let provider = handle.http_provider();\n    let sender = handle.dev_accounts().next().unwrap();\n\n    let mut hashes = VecDeque::new();\n\n    for i in 0..7 {\n        let tx =\n            TransactionRequest::default().to(Address::random()).value(U256::from(100)).nonce(i);\n        let tx = WithOtherFields::new(tx);\n        let receipt = provider.send_transaction(tx).await.unwrap().get_receipt().await.unwrap();\n        hashes.push_front(receipt.transaction_hash);\n    }\n\n    let page_size = 2;\n    let mut block = 0;\n    for i in 0..4 {\n        let result = api.ots_search_transactions_after(sender, block, page_size).await.unwrap();\n\n        assert_eq!(result.first_page, i == 3);\n        assert_eq!(result.last_page, i == 0);\n\n        // check each individual hash\n        result.txs.iter().rev().for_each(|tx| {\n            assert_eq!(hashes.pop_back(), Some(tx.tx_hash()));\n        });\n\n        block = result.txs.first().unwrap().block_number.unwrap();\n    }\n\n    assert!(hashes.is_empty());\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn ots_get_transaction_by_sender_and_nonce() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n    let provider = handle.http_provider();\n    let sender = handle.dev_accounts().next().unwrap();\n\n    let tx1 = WithOtherFields::new(\n        TransactionRequest::default()\n            .from(sender)\n            .to(Address::random())\n            .value(U256::from(100))\n            .nonce(0),\n    );\n    let tx2 = WithOtherFields::new(\n        TransactionRequest::default()\n            .from(sender)\n            .to(Address::random())\n            .value(U256::from(100))\n            .nonce(1),\n    );\n\n    let receipt1 = provider.send_transaction(tx1).await.unwrap().get_receipt().await.unwrap();\n    let receipt2 = provider.send_transaction(tx2).await.unwrap().get_receipt().await.unwrap();\n\n    let result1 =\n        api.ots_get_transaction_by_sender_and_nonce(sender, U256::from(0)).await.unwrap().unwrap();\n    let result2 =\n        api.ots_get_transaction_by_sender_and_nonce(sender, U256::from(1)).await.unwrap().unwrap();\n\n    assert_eq!(result1, receipt1.transaction_hash);\n    assert_eq!(result2, receipt2.transaction_hash);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn ots_get_contract_creator() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n    let provider = handle.http_provider();\n    let sender = handle.dev_accounts().next().unwrap();\n\n    let receipt =\n        Multicall::deploy_builder(&provider).send().await.unwrap().get_receipt().await.unwrap();\n    let contract_address = receipt.contract_address.unwrap();\n\n    let creator = api.ots_get_contract_creator(contract_address).await.unwrap().unwrap();\n\n    assert_eq!(creator.creator, sender);\n    assert_eq!(creator.hash, receipt.transaction_hash);\n}\n"
  },
  {
    "path": "crates/anvil/tests/it/proof.rs",
    "content": "//! tests for `eth_getProof`\n\nuse alloy_primitives::{Address, B256, Bytes, U256, address, fixed_bytes};\nuse anvil::{NodeConfig, eth::EthApi, spawn};\nuse foundry_primitives::FoundryNetwork;\nuse std::{collections::BTreeMap, str::FromStr};\n\nasync fn verify_account_proof(\n    api: &EthApi<FoundryNetwork>,\n    address: Address,\n    proof: impl IntoIterator<Item = &str>,\n) {\n    let expected_proof =\n        proof.into_iter().map(Bytes::from_str).collect::<Result<Vec<_>, _>>().unwrap();\n    let proof = api.get_proof(address, Vec::new(), None).await.unwrap();\n\n    assert_eq!(proof.account_proof, expected_proof);\n}\n\nasync fn verify_storage_proof(\n    api: &EthApi<FoundryNetwork>,\n    address: Address,\n    slot: B256,\n    proof: impl IntoIterator<Item = &str>,\n) {\n    let expected_proof =\n        proof.into_iter().map(Bytes::from_str).collect::<Result<Vec<_>, _>>().unwrap();\n    let proof = api.get_proof(address, vec![slot], None).await.unwrap();\n\n    assert_eq!(proof.storage_proof[0].proof, expected_proof);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_account_proof() {\n    let (api, _handle) = spawn(NodeConfig::empty_state()).await;\n\n    api.anvil_set_balance(\n        address!(\"0x2031f89b3ea8014eb51a78c316e42af3e0d7695f\"),\n        U256::from(45000000000000000000_u128),\n    )\n    .await\n    .unwrap();\n    api.anvil_set_balance(address!(\"0x33f0fc440b8477fcfbe9d0bf8649e7dea9baedb2\"), U256::from(1))\n        .await\n        .unwrap();\n    api.anvil_set_balance(\n        address!(\"0x62b0dd4aab2b1a0a04e279e2b828791a10755528\"),\n        U256::from(1100000000000000000_u128),\n    )\n    .await\n    .unwrap();\n    api.anvil_set_balance(\n        address!(\"0x1ed9b1dd266b607ee278726d324b855a093394a6\"),\n        U256::from(120000000000000000_u128),\n    )\n    .await\n    .unwrap();\n\n    // Note: proof values account for EIP-2935 history storage contract deployed at genesis.\n    verify_account_proof(&api, address!(\"0x2031f89b3ea8014eb51a78c316e42af3e0d7695f\"), [\n        \"0xf851808080808080a0347892f3eeb6af4d4574ad0b89706247951bbbece83ef27efc46eb96436598b5808080a07e35bed15a14b4072a0929310da6a26e34d7017a82cca3589d7d0badb53de2e3808080808080\",\n        \"0xe217a040f916999be583c572cc4dd369ec53b0a99f7de95f13880cf203d98f935ed1b3\",\n        \"0xf87180a04fb9bab4bb88c062f32452b7c94c8f64d07b5851d44a39f1e32ba4b1829fdbfb8080808080a0b61eeb2eb82808b73c4ad14140a2836689f4ab8445d69dd40554eaf1fce34bc080808080808080a0dea230ff2026e65de419288183a340125b04b8405cc61627b3b4137e2260a1e880\",\n        \"0xf8719f31355ec1c8f7e26bb3ccbcb0b75d870d15846c0b98e5cc452db46c37faea40b84ff84d80890270801d946c940000a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470\",\n    ]).await;\n\n    verify_account_proof(&api, address!(\"0x33f0fc440b8477fcfbe9d0bf8649e7dea9baedb2\"), [\n        \"0xf851808080808080a0347892f3eeb6af4d4574ad0b89706247951bbbece83ef27efc46eb96436598b5808080a07e35bed15a14b4072a0929310da6a26e34d7017a82cca3589d7d0badb53de2e3808080808080\",\n        \"0xe217a040f916999be583c572cc4dd369ec53b0a99f7de95f13880cf203d98f935ed1b3\",\n        \"0xf87180a04fb9bab4bb88c062f32452b7c94c8f64d07b5851d44a39f1e32ba4b1829fdbfb8080808080a0b61eeb2eb82808b73c4ad14140a2836689f4ab8445d69dd40554eaf1fce34bc080808080808080a0dea230ff2026e65de419288183a340125b04b8405cc61627b3b4137e2260a1e880\",\n        \"0xe48200d3a0ef957210bca5b9b402d614eb8408c88cfbf4913eb6ab83ca233c8b8f0e626b54\",\n        \"0xf851808080a02743a5addaf4cf9b8c0c073e1eaa555deaaf8c41cb2b41958e88624fa45c2d908080808080a0bfbf6937911dfb88113fecdaa6bde822e4e99dae62489fcf61a91cb2f36793d680808080808080\",\n        \"0xf8679e207781e762f3577784bab7491fcc43e291ce5a356b9bc517ac52eed3a37ab846f8448001a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470\",\n    ]).await;\n\n    verify_account_proof(&api, address!(\"0x62b0dd4aab2b1a0a04e279e2b828791a10755528\"), [\n        \"0xf851808080808080a0347892f3eeb6af4d4574ad0b89706247951bbbece83ef27efc46eb96436598b5808080a07e35bed15a14b4072a0929310da6a26e34d7017a82cca3589d7d0badb53de2e3808080808080\",\n        \"0xe217a040f916999be583c572cc4dd369ec53b0a99f7de95f13880cf203d98f935ed1b3\",\n        \"0xf87180a04fb9bab4bb88c062f32452b7c94c8f64d07b5851d44a39f1e32ba4b1829fdbfb8080808080a0b61eeb2eb82808b73c4ad14140a2836689f4ab8445d69dd40554eaf1fce34bc080808080808080a0dea230ff2026e65de419288183a340125b04b8405cc61627b3b4137e2260a1e880\",\n        \"0xf8709f3936599f93b769acf90c7178fd2ddcac1b5b4bc9949ee5a04b7e0823c2446eb84ef84c80880f43fc2c04ee0000a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470\",\n    ]).await;\n\n    verify_account_proof(&api, address!(\"0x1ed9b1dd266b607ee278726d324b855a093394a6\"), [\n        \"0xf851808080808080a0347892f3eeb6af4d4574ad0b89706247951bbbece83ef27efc46eb96436598b5808080a07e35bed15a14b4072a0929310da6a26e34d7017a82cca3589d7d0badb53de2e3808080808080\",\n        \"0xe217a040f916999be583c572cc4dd369ec53b0a99f7de95f13880cf203d98f935ed1b3\",\n        \"0xf87180a04fb9bab4bb88c062f32452b7c94c8f64d07b5851d44a39f1e32ba4b1829fdbfb8080808080a0b61eeb2eb82808b73c4ad14140a2836689f4ab8445d69dd40554eaf1fce34bc080808080808080a0dea230ff2026e65de419288183a340125b04b8405cc61627b3b4137e2260a1e880\",\n        \"0xe48200d3a0ef957210bca5b9b402d614eb8408c88cfbf4913eb6ab83ca233c8b8f0e626b54\",\n        \"0xf851808080a02743a5addaf4cf9b8c0c073e1eaa555deaaf8c41cb2b41958e88624fa45c2d908080808080a0bfbf6937911dfb88113fecdaa6bde822e4e99dae62489fcf61a91cb2f36793d680808080808080\",\n        \"0xf86f9e207a32b8ab5eb4b043c65b1f00c93f517bc8883c5cd31baf8e8a279475e3b84ef84c808801aa535d3d0c0000a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470\",\n    ]).await;\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_storage_proof() {\n    let target = address!(\"0x1ed9b1dd266b607ee278726d324b855a093394a6\");\n\n    let (api, _handle) = spawn(NodeConfig::empty_state()).await;\n    let storage: BTreeMap<U256, B256> =\n        serde_json::from_str(include_str!(\"../../test-data/storage_sample.json\")).unwrap();\n\n    for (key, value) in storage {\n        api.anvil_set_storage_at(target, key, value).await.unwrap();\n    }\n\n    verify_storage_proof(&api, target, fixed_bytes!(\"0000000000000000000000000000000000000000000000000000000000000022\"), [\n        \"0xf9019180a0aafd5b14a6edacd149e110ba6776a654f2dbffca340902be933d011113f2750380a0a502c93b1918c4c6534d4593ae03a5a23fa10ebc30ffb7080b297bff2446e42da02eb2bf45fd443bd1df8b6f9c09726a4c6252a0f7896a131a081e39a7f644b38980a0a9cf7f673a0bce76fd40332afe8601542910b48dea44e93933a3e5e930da5d19a0ddf79db0a36d0c8134ba143bcb541cd4795a9a2bae8aca0ba24b8d8963c2a77da0b973ec0f48f710bf79f63688485755cbe87f9d4c68326bb83c26af620802a80ea0f0855349af6bf84afc8bca2eda31c8ef8c5139be1929eeb3da4ba6b68a818cb0a0c271e189aeeb1db5d59d7fe87d7d6327bbe7cfa389619016459196497de3ccdea0e7503ba5799e77aa31bbe1310c312ca17b2c5bcc8fa38f266675e8f154c2516ba09278b846696d37213ab9d20a5eb42b03db3173ce490a2ef3b2f3b3600579fc63a0e9041059114f9c910adeca12dbba1fef79b2e2c8899f2d7213cd22dfe4310561a047c59da56bb2bf348c9dd2a2e8f5538a92b904b661cfe54a4298b85868bbe4858080\",\n        \"0xf85180a0776aa456ba9c5008e03b82b841a9cf2fc1e8578cfacd5c9015804eae315f17fb80808080808080808080808080a072e3e284d47badbb0a5ca1421e1179d3ea90cc10785b26b74fb8a81f0f9e841880\",\n        \"0xf843a020035b26e3e9eee00e0d72fd1ee8ddca6894550dca6916ea2ac6baa90d11e510a1a0f5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b\"\n    ]).await;\n\n    verify_storage_proof(&api, target, fixed_bytes!(\"0000000000000000000000000000000000000000000000000000000000000023\"), [\n        \"0xf9019180a0aafd5b14a6edacd149e110ba6776a654f2dbffca340902be933d011113f2750380a0a502c93b1918c4c6534d4593ae03a5a23fa10ebc30ffb7080b297bff2446e42da02eb2bf45fd443bd1df8b6f9c09726a4c6252a0f7896a131a081e39a7f644b38980a0a9cf7f673a0bce76fd40332afe8601542910b48dea44e93933a3e5e930da5d19a0ddf79db0a36d0c8134ba143bcb541cd4795a9a2bae8aca0ba24b8d8963c2a77da0b973ec0f48f710bf79f63688485755cbe87f9d4c68326bb83c26af620802a80ea0f0855349af6bf84afc8bca2eda31c8ef8c5139be1929eeb3da4ba6b68a818cb0a0c271e189aeeb1db5d59d7fe87d7d6327bbe7cfa389619016459196497de3ccdea0e7503ba5799e77aa31bbe1310c312ca17b2c5bcc8fa38f266675e8f154c2516ba09278b846696d37213ab9d20a5eb42b03db3173ce490a2ef3b2f3b3600579fc63a0e9041059114f9c910adeca12dbba1fef79b2e2c8899f2d7213cd22dfe4310561a047c59da56bb2bf348c9dd2a2e8f5538a92b904b661cfe54a4298b85868bbe4858080\",\n        \"0xf8518080808080a0d546c4ca227a267d29796643032422374624ed109b3d94848c5dc06baceaee76808080808080a027c48e210ccc6e01686be2d4a199d35f0e1e8df624a8d3a17c163be8861acd6680808080\",\n        \"0xf843a0207b2b5166478fd4318d2acc6cc2c704584312bdd8781b32d5d06abda57f4230a1a0db56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71\"\n    ]).await;\n\n    verify_storage_proof(&api, target, fixed_bytes!(\"0000000000000000000000000000000000000000000000000000000000000024\"), [\n        \"0xf9019180a0aafd5b14a6edacd149e110ba6776a654f2dbffca340902be933d011113f2750380a0a502c93b1918c4c6534d4593ae03a5a23fa10ebc30ffb7080b297bff2446e42da02eb2bf45fd443bd1df8b6f9c09726a4c6252a0f7896a131a081e39a7f644b38980a0a9cf7f673a0bce76fd40332afe8601542910b48dea44e93933a3e5e930da5d19a0ddf79db0a36d0c8134ba143bcb541cd4795a9a2bae8aca0ba24b8d8963c2a77da0b973ec0f48f710bf79f63688485755cbe87f9d4c68326bb83c26af620802a80ea0f0855349af6bf84afc8bca2eda31c8ef8c5139be1929eeb3da4ba6b68a818cb0a0c271e189aeeb1db5d59d7fe87d7d6327bbe7cfa389619016459196497de3ccdea0e7503ba5799e77aa31bbe1310c312ca17b2c5bcc8fa38f266675e8f154c2516ba09278b846696d37213ab9d20a5eb42b03db3173ce490a2ef3b2f3b3600579fc63a0e9041059114f9c910adeca12dbba1fef79b2e2c8899f2d7213cd22dfe4310561a047c59da56bb2bf348c9dd2a2e8f5538a92b904b661cfe54a4298b85868bbe4858080\",\n        \"0xf85180808080a030263404acfee103d0b1019053ff3240fce433c69b709831673285fa5887ce4c80808080808080a0f8f1fbb1f7b482d9860480feebb83ff54a8b6ec1ead61cc7d2f25d7c01659f9c80808080\",\n        \"0xf843a020d332d19b93bcabe3cce7ca0c18a052f57e5fd03b4758a09f30f5ddc4b22ec4a1a0c78009fdf07fc56a11f122370658a353aaa542ed63e44c4bc15ff4cd105ab33c\",\n    ]).await;\n\n    verify_storage_proof(&api, target, fixed_bytes!(\"0000000000000000000000000000000000000000000000000000000000000100\"), [\n        \"0xf9019180a0aafd5b14a6edacd149e110ba6776a654f2dbffca340902be933d011113f2750380a0a502c93b1918c4c6534d4593ae03a5a23fa10ebc30ffb7080b297bff2446e42da02eb2bf45fd443bd1df8b6f9c09726a4c6252a0f7896a131a081e39a7f644b38980a0a9cf7f673a0bce76fd40332afe8601542910b48dea44e93933a3e5e930da5d19a0ddf79db0a36d0c8134ba143bcb541cd4795a9a2bae8aca0ba24b8d8963c2a77da0b973ec0f48f710bf79f63688485755cbe87f9d4c68326bb83c26af620802a80ea0f0855349af6bf84afc8bca2eda31c8ef8c5139be1929eeb3da4ba6b68a818cb0a0c271e189aeeb1db5d59d7fe87d7d6327bbe7cfa389619016459196497de3ccdea0e7503ba5799e77aa31bbe1310c312ca17b2c5bcc8fa38f266675e8f154c2516ba09278b846696d37213ab9d20a5eb42b03db3173ce490a2ef3b2f3b3600579fc63a0e9041059114f9c910adeca12dbba1fef79b2e2c8899f2d7213cd22dfe4310561a047c59da56bb2bf348c9dd2a2e8f5538a92b904b661cfe54a4298b85868bbe4858080\",\n        \"0xf891a090bacef44b189ddffdc5f22edc70fe298c58e5e523e6e1dfdf7dbc6d657f7d1b80a026eed68746028bc369eb456b7d3ee475aa16f34e5eaa0c98fdedb9c59ebc53b0808080a09ce86197173e14e0633db84ce8eea32c5454eebe954779255644b45b717e8841808080a0328c7afb2c58ef3f8c4117a8ebd336f1a61d24591067ed9c5aae94796cac987d808080808080\",\n    ]).await;\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_get_random_account_proofs() {\n    let (api, _handle) = spawn(NodeConfig::test()).await;\n\n    for acc in std::iter::repeat_with(Address::random).take(10) {\n        let _ = api\n            .get_proof(acc, Vec::new(), None)\n            .await\n            .unwrap_or_else(|_| panic!(\"Failed to get proof for {acc:?}\"));\n    }\n}\n"
  },
  {
    "path": "crates/anvil/tests/it/pubsub.rs",
    "content": "//! tests for subscriptions\n\nuse crate::utils::{connect_pubsub, connect_pubsub_with_wallet};\nuse alloy_network::{EthereumWallet, TransactionBuilder};\nuse alloy_primitives::{Address, U256};\nuse alloy_provider::Provider;\nuse alloy_pubsub::Subscription;\nuse alloy_rpc_types::{Block as AlloyBlock, Filter, TransactionRequest};\nuse alloy_serde::WithOtherFields;\nuse alloy_sol_types::sol;\nuse anvil::{NodeConfig, spawn};\nuse futures::StreamExt;\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_sub_new_heads() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n\n    let provider = connect_pubsub(&handle.ws_endpoint()).await;\n\n    let blocks = provider.subscribe_blocks().await.unwrap();\n\n    // mine a block every 1 seconds\n    api.anvil_set_interval_mining(1).unwrap();\n\n    let blocks = blocks.into_stream().take(3).collect::<Vec<_>>().await;\n    let block_numbers = blocks.into_iter().map(|b| b.number).collect::<Vec<_>>();\n\n    assert_eq!(block_numbers, vec![1, 2, 3]);\n}\n\nsol!(\n    #[sol(rpc)]\n    EmitLogs,\n    \"test-data/emit_logs.json\"\n);\n// FIXME: Use .legacy() in tx when implemented in alloy\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_sub_logs_legacy() {\n    let (_api, handle) = spawn(NodeConfig::test()).await;\n    let wallet = handle.dev_wallets().next().unwrap();\n    let provider = connect_pubsub(&handle.ws_endpoint()).await;\n\n    let msg = \"First Message\".to_string();\n    let contract_addr = EmitLogs::deploy_builder(provider.clone(), msg.clone())\n        .from(wallet.address())\n        .deploy()\n        .await\n        .unwrap();\n    let contract = EmitLogs::new(contract_addr, provider.clone());\n\n    let val = contract.getValue().call().await.unwrap();\n    assert_eq!(val, msg);\n\n    // subscribe to events from the contract\n    let filter = Filter::new().address(contract.address().to_owned());\n    let logs_sub = provider.subscribe_logs(&filter).await.unwrap();\n\n    // send a tx triggering an event\n    // FIXME: Use .legacy() in tx\n    let receipt = contract\n        .setValue(\"Next Message\".to_string())\n        .send()\n        .await\n        .unwrap()\n        .get_receipt()\n        .await\n        .unwrap();\n\n    let mut logs_sub = logs_sub.into_stream();\n    // get the emitted event\n    let log = logs_sub.next().await.unwrap();\n\n    // ensure the log in the receipt is the same as received via subscription stream\n    assert_eq!(receipt.inner.logs()[0], log);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_sub_logs() {\n    let (_api, handle) = spawn(NodeConfig::test()).await;\n    let wallet = handle.dev_wallets().next().unwrap();\n    let provider = connect_pubsub(&handle.ws_endpoint()).await;\n\n    let msg = \"First Message\".to_string();\n    let contract_addr = EmitLogs::deploy_builder(provider.clone(), msg.clone())\n        .from(wallet.address())\n        .deploy()\n        .await\n        .unwrap();\n    let contract = EmitLogs::new(contract_addr, provider.clone());\n\n    let val = contract.getValue().call().await.unwrap();\n    assert_eq!(val, msg);\n\n    // subscribe to events from the contract\n    let filter = Filter::new().address(contract.address().to_owned());\n    let logs_sub = provider.subscribe_logs(&filter).await.unwrap();\n\n    // send a tx triggering an event\n    let receipt = contract\n        .setValue(\"Next Message\".to_string())\n        .send()\n        .await\n        .unwrap()\n        .get_receipt()\n        .await\n        .unwrap();\n\n    let mut logs_sub = logs_sub.into_stream();\n    // get the emitted event\n    let log = logs_sub.next().await.unwrap();\n\n    // ensure the log in the receipt is the same as received via subscription stream\n    assert_eq!(receipt.inner.logs()[0], log);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_sub_logs_impersonated() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n    let wallet = handle.dev_wallets().next().unwrap();\n    let provider =\n        connect_pubsub_with_wallet(&handle.ws_endpoint(), EthereumWallet::from(wallet.clone()))\n            .await;\n\n    // impersonate account\n    let impersonate = Address::random();\n    let funding = U256::from(1e18 as u64);\n    api.anvil_set_balance(impersonate, funding).await.unwrap();\n    api.anvil_impersonate_account(impersonate).await.unwrap();\n\n    let msg = \"First Message\".to_string();\n    let contract = EmitLogs::deploy(provider.clone(), msg.clone()).await.unwrap();\n\n    let _val = contract.getValue().call().await.unwrap();\n\n    // subscribe to events from the impersonated account\n    let filter = Filter::new().address(contract.address().to_owned());\n    let logs_sub = provider.subscribe_logs(&filter).await.unwrap();\n\n    // send a tx triggering an event\n    let data = contract.setValue(\"Next Message\".to_string());\n    let data = data.calldata().clone();\n\n    let tx =\n        TransactionRequest::default().from(impersonate).to(*contract.address()).with_input(data);\n\n    let tx = WithOtherFields::new(tx);\n    let provider = handle.http_provider();\n\n    let receipt = provider.send_transaction(tx).await.unwrap().get_receipt().await.unwrap();\n\n    let mut logs_sub = logs_sub.into_stream();\n    // get the emitted event\n    let log = logs_sub.next().await.unwrap();\n    // ensure the log in the receipt is the same as received via subscription stream\n    assert_eq!(receipt.inner.inner.logs()[0], log);\n}\n\n// FIXME: Use legacy() in tx when implemented in alloy\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_filters_legacy() {\n    let (_api, handle) = spawn(NodeConfig::test()).await;\n    let wallet = handle.dev_wallets().next().unwrap();\n    let provider =\n        connect_pubsub_with_wallet(&handle.ws_endpoint(), EthereumWallet::from(wallet.clone()))\n            .await;\n\n    let from = wallet.address();\n\n    let msg = \"First Message\".to_string();\n\n    // FIXME: Use legacy() in tx when implemented in alloy\n    let contract = EmitLogs::deploy(provider.clone(), msg.clone()).await.unwrap();\n\n    let stream = contract.ValueChanged_filter().subscribe().await.unwrap();\n\n    // send a tx triggering an event\n    // FIXME: Use legacy() in tx when implemented in alloy\n    let _receipt = contract\n        .setValue(\"Next Message\".to_string())\n        .send()\n        .await\n        .unwrap()\n        .get_receipt()\n        .await\n        .unwrap();\n\n    let mut log = stream.into_stream();\n    // get the emitted event\n    let (value_changed, _log) = log.next().await.unwrap().unwrap();\n\n    assert_eq!(value_changed.author, from);\n    assert_eq!(value_changed.oldValue, \"First Message\".to_string());\n    assert_eq!(value_changed.newValue, \"Next Message\".to_string());\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_filters() {\n    let (_api, handle) = spawn(NodeConfig::test()).await;\n    let wallet = handle.dev_wallets().next().unwrap();\n    let provider =\n        connect_pubsub_with_wallet(&handle.ws_endpoint(), EthereumWallet::from(wallet.clone()))\n            .await;\n\n    let from = wallet.address();\n\n    let msg = \"First Message\".to_string();\n\n    let contract = EmitLogs::deploy(provider.clone(), msg.clone()).await.unwrap();\n\n    let stream = contract.ValueChanged_filter().subscribe().await.unwrap();\n\n    // send a tx triggering an event\n    let _receipt = contract\n        .setValue(\"Next Message\".to_string())\n        .send()\n        .await\n        .unwrap()\n        .get_receipt()\n        .await\n        .unwrap();\n\n    let mut log = stream.into_stream();\n    // get the emitted event\n    let (value_changed, _log) = log.next().await.unwrap().unwrap();\n\n    assert_eq!(value_changed.author, from);\n    assert_eq!(value_changed.oldValue, \"First Message\".to_string());\n    assert_eq!(value_changed.newValue, \"Next Message\".to_string());\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_subscriptions() {\n    let (_api, handle) =\n        spawn(NodeConfig::test().with_blocktime(Some(std::time::Duration::from_secs(1)))).await;\n    let provider = connect_pubsub(&handle.ws_endpoint()).await;\n    let sub_id = provider.raw_request(\"eth_subscribe\".into(), [\"newHeads\"]).await.unwrap();\n    let stream: Subscription<AlloyBlock> = provider.get_subscription(sub_id).await.unwrap();\n    let blocks = stream\n        .into_stream()\n        .take(3)\n        .collect::<Vec<_>>()\n        .await\n        .into_iter()\n        .map(|b| b.header.number)\n        .collect::<Vec<_>>();\n\n    assert_eq!(blocks, vec![1, 2, 3])\n}\n\n#[expect(clippy::disallowed_macros)]\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_sub_new_heads_fast() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n\n    let provider = connect_pubsub(&handle.ws_endpoint()).await;\n\n    let blocks = provider.subscribe_blocks().await.unwrap();\n    let mut blocks = blocks.into_stream();\n\n    let num = 1000u64;\n\n    let mut block_numbers = Vec::new();\n    for _ in 0..num {\n        api.mine_one().await;\n        let block_number = blocks.next().await.unwrap().number;\n        block_numbers.push(block_number);\n    }\n\n    println!(\"Collected {} blocks\", block_numbers.len());\n\n    let numbers = (1..=num).collect::<Vec<_>>();\n    assert_eq!(block_numbers, numbers);\n}\n"
  },
  {
    "path": "crates/anvil/tests/it/revert.rs",
    "content": "use crate::abi::VendingMachine;\nuse alloy_network::TransactionBuilder;\nuse alloy_primitives::{U256, bytes};\nuse alloy_provider::Provider;\nuse alloy_rpc_types::TransactionRequest;\nuse alloy_serde::WithOtherFields;\nuse alloy_sol_types::sol;\nuse anvil::{NodeConfig, spawn};\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_deploy_reverting() {\n    let (_api, handle) = spawn(NodeConfig::test()).await;\n    let provider = handle.http_provider();\n    let sender = handle.dev_accounts().next().unwrap();\n\n    let code = bytes!(\"5f5ffd\"); // PUSH0 PUSH0 REVERT\n    let tx = TransactionRequest::default().from(sender).with_deploy_code(code);\n    let tx = WithOtherFields::new(tx);\n\n    // Calling/estimating gas fails early.\n    let err = provider.call(tx.clone()).await.unwrap_err();\n    let s = err.to_string();\n    assert!(s.contains(\"execution reverted\"), \"{s:?}\");\n\n    // Sending the transaction is successful but reverts on chain.\n    let tx = provider.send_transaction(tx).await.unwrap();\n    let receipt = tx.get_receipt().await.unwrap();\n    assert!(!receipt.inner.inner.status());\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_revert_messages() {\n    sol!(\n        #[sol(rpc, bytecode = \"608080604052346025575f80546001600160a01b031916600117905560b69081602a8239f35b5f80fdfe60808060405260043610156011575f80fd5b5f3560e01c635b9fdc30146023575f80fd5b34607c575f366003190112607c575f546001600160a01b03163303604c576020604051607b8152f35b62461bcd60e51b815260206004820152600b60248201526a08585d5d1a1bdc9a5e995960aa1b6044820152606490fd5b5f80fdfea2646970667358221220f593e5ccd46935f623185de62a72d9f1492d8d15075a111b0fa4d7e16acf4a7064736f6c63430008190033\")]\n        contract Contract {\n            address private owner;\n\n            constructor() {\n                owner = address(1);\n            }\n\n            modifier onlyOwner() {\n                require(msg.sender == owner, \"!authorized\");\n                _;\n            }\n\n            #[derive(Debug)]\n            function getSecret() public onlyOwner view returns(uint256 secret) {\n                return 123;\n            }\n        }\n    );\n\n    let (_api, handle) = spawn(NodeConfig::test()).await;\n    let provider = handle.http_provider();\n\n    let contract = Contract::deploy(&provider).await.unwrap();\n\n    let err = contract.getSecret().call().await.unwrap_err();\n    let s = err.to_string();\n    assert!(s.contains(\"!authorized\"), \"{s:?}\");\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_solc_revert_example() {\n    let (_api, handle) = spawn(NodeConfig::test()).await;\n    let sender = handle.dev_accounts().next().unwrap();\n    let provider = handle.http_provider();\n\n    let contract = VendingMachine::deploy(&provider).await.unwrap();\n\n    let err =\n        contract.buy(U256::from(100)).value(U256::from(1)).from(sender).call().await.unwrap_err();\n    let s = err.to_string();\n    assert!(s.contains(\"Not enough Ether provided.\"), \"{s:?}\");\n}\n\n// <https://github.com/foundry-rs/foundry/issues/1871>\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_another_revert_message() {\n    sol!(\n        #[sol(rpc, bytecode = \"6080806040523460135760d7908160188239f35b5f80fdfe60808060405260043610156011575f80fd5b5f3560e01c9081633fb5c1cb14604d5750638381f58a14602f575f80fd5b346049575f36600319011260495760205f54604051908152f35b5f80fd5b346049576020366003190112604957600435908115606a57505f55005b62461bcd60e51b81526020600482015260126024820152712932bb32b93a29ba3934b733a337b7a130b960711b6044820152606490fdfea2646970667358221220314bf8261cc467619137c071584f8d3bd8d9d97bf2846c138c0567040cf9828a64736f6c63430008190033\")]\n        contract Contract {\n            uint256 public number;\n\n            #[derive(Debug)]\n            function setNumber(uint256 num) public {\n                require(num != 0, \"RevertStringFooBar\");\n                number = num;\n            }\n        }\n    );\n\n    let (_api, handle) = spawn(NodeConfig::test()).await;\n    let provider = handle.http_provider();\n\n    let contract = Contract::deploy(&provider).await.unwrap();\n\n    let err = contract.setNumber(U256::from(0)).call().await.unwrap_err();\n    let s = err.to_string();\n    assert!(s.contains(\"RevertStringFooBar\"), \"{s:?}\");\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_solc_revert_custom_errors() {\n    sol!(\n        #[sol(rpc, bytecode = \"608080604052346013576081908160188239f35b5f80fdfe60808060405260043610156011575f80fd5b5f3560e01c63e57207e6146023575f80fd5b346047575f3660031901126047576373ea2a7f60e01b815260016004820152602490fd5b5f80fdfea26469706673582212202a8d69545801394af36c56ca229b52ae0b22d7b8f938b107dca8ebbf655464f764736f6c63430008190033\")]\n        contract Contract {\n            error AddressRevert(address);\n\n            #[derive(Debug)]\n            function revertAddress() public {\n                revert AddressRevert(address(1));\n            }\n        }\n    );\n\n    let (_api, handle) = spawn(NodeConfig::test()).await;\n    let provider = handle.http_provider();\n\n    let contract = Contract::deploy(&provider).await.unwrap();\n\n    let err = contract.revertAddress().call().await.unwrap_err();\n    let s = err.to_string();\n    assert!(s.contains(\"execution reverted\"), \"{s:?}\");\n}\n"
  },
  {
    "path": "crates/anvil/tests/it/sign.rs",
    "content": "use crate::utils::http_provider_with_signer;\nuse alloy_dyn_abi::TypedData;\nuse alloy_network::EthereumWallet;\nuse alloy_primitives::{Address, U256};\nuse alloy_provider::Provider;\nuse alloy_rpc_types::TransactionRequest;\nuse alloy_serde::WithOtherFields;\nuse alloy_signer::Signer;\nuse anvil::{NodeConfig, spawn};\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_sign_typed_data() {\n    let (api, _handle) = spawn(NodeConfig::test()).await;\n\n    let json = serde_json::json!(\n            {\n      \"types\": {\n        \"EIP712Domain\": [\n          {\n            \"name\": \"name\",\n            \"type\": \"string\"\n          },\n          {\n            \"name\": \"version\",\n            \"type\": \"string\"\n          },\n          {\n            \"name\": \"chainId\",\n            \"type\": \"uint256\"\n          },\n          {\n            \"name\": \"verifyingContract\",\n            \"type\": \"address\"\n          }\n        ],\n        \"Person\": [\n          {\n            \"name\": \"name\",\n            \"type\": \"string\"\n          },\n          {\n            \"name\": \"wallet\",\n            \"type\": \"address\"\n          }\n        ],\n        \"Mail\": [\n          {\n            \"name\": \"from\",\n            \"type\": \"Person\"\n          },\n          {\n            \"name\": \"to\",\n            \"type\": \"Person\"\n          },\n          {\n            \"name\": \"contents\",\n            \"type\": \"string\"\n          }\n        ]\n      },\n      \"primaryType\": \"Mail\",\n      \"domain\": {\n        \"name\": \"Ether Mail\",\n        \"version\": \"1\",\n        \"chainId\": 1,\n        \"verifyingContract\": \"0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC\"\n      },\n      \"message\": {\n        \"from\": {\n          \"name\": \"Cow\",\n          \"wallet\": \"0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826\"\n        },\n        \"to\": {\n          \"name\": \"Bob\",\n          \"wallet\": \"0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB\"\n        },\n        \"contents\": \"Hello, Bob!\"\n      }\n    });\n\n    let typed_data: TypedData = serde_json::from_value(json).unwrap();\n\n    // `curl -X POST -H \"Content-Type: application/json\" -d '{\"jsonrpc\":\"2.0\",\"method\": \"eth_signTypedData_v4\", \"params\": [\"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266\", {\"types\":{\"EIP712Domain\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"version\",\"type\":\"string\"},{\"name\":\"chainId\",\"type\":\"uint256\"},{\"name\":\"verifyingContract\",\"type\":\"address\"}],\"Person\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"wallet\",\"type\":\"address\"}],\"Mail\":[{\"name\":\"from\",\"type\":\"Person\"},{\"name\":\"to\",\"type\":\"Person\"},{\"name\":\"contents\",\"type\":\"string\"}]},\"primaryType\":\"Mail\",\"domain\":{\"name\":\"Ether Mail\",\"version\":\"1\",\"chainId\":1,\"verifyingContract\":\"0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC\"},\"message\":{\"from\":{\"name\":\"Cow\",\"wallet\":\"0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826\"},\"to\":{\"name\":\"Bob\",\"wallet\":\"0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB\"},\"contents\":\"Hello, Bob!\"}}],\"id\":67}' http://localhost:8545`\n\n    let signature = api\n        .sign_typed_data_v4(\n            \"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266\".parse().unwrap(),\n            &typed_data,\n        )\n        .await\n        .unwrap();\n    assert_eq!(\n      signature,\n      \"0x6ea8bb309a3401225701f3565e32519f94a0ea91a5910ce9229fe488e773584c0390416a2190d9560219dab757ecca2029e63fa9d1c2aebf676cc25b9f03126a1b\".to_string()\n    );\n}\n\n// <https://github.com/foundry-rs/foundry/issues/2458>\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_sign_typed_data_os() {\n    let (api, _handle) = spawn(NodeConfig::test()).await;\n\n    let json = serde_json::json!(\n    {\n      \"types\": {\n        \"EIP712Domain\": [\n          {\n            \"name\": \"name\",\n            \"type\": \"string\"\n          },\n          {\n            \"name\": \"version\",\n            \"type\": \"string\"\n          },\n          {\n            \"name\": \"chainId\",\n            \"type\": \"uint256\"\n          },\n          {\n            \"name\": \"verifyingContract\",\n            \"type\": \"address\"\n          }\n        ],\n        \"OrderComponents\": [\n          {\n            \"name\": \"offerer\",\n            \"type\": \"address\"\n          },\n          {\n            \"name\": \"zone\",\n            \"type\": \"address\"\n          },\n          {\n            \"name\": \"offer\",\n            \"type\": \"OfferItem[]\"\n          },\n          {\n            \"name\": \"consideration\",\n            \"type\": \"ConsiderationItem[]\"\n          },\n          {\n            \"name\": \"orderType\",\n            \"type\": \"uint8\"\n          },\n          {\n            \"name\": \"startTime\",\n            \"type\": \"uint256\"\n          },\n          {\n            \"name\": \"endTime\",\n            \"type\": \"uint256\"\n          },\n          {\n            \"name\": \"zoneHash\",\n            \"type\": \"bytes32\"\n          },\n          {\n            \"name\": \"salt\",\n            \"type\": \"uint256\"\n          },\n          {\n            \"name\": \"conduitKey\",\n            \"type\": \"bytes32\"\n          },\n          {\n            \"name\": \"counter\",\n            \"type\": \"uint256\"\n          }\n        ],\n        \"OfferItem\": [\n          {\n            \"name\": \"itemType\",\n            \"type\": \"uint8\"\n          },\n          {\n            \"name\": \"token\",\n            \"type\": \"address\"\n          },\n          {\n            \"name\": \"identifierOrCriteria\",\n            \"type\": \"uint256\"\n          },\n          {\n            \"name\": \"startAmount\",\n            \"type\": \"uint256\"\n          },\n          {\n            \"name\": \"endAmount\",\n            \"type\": \"uint256\"\n          }\n        ],\n        \"ConsiderationItem\": [\n          {\n            \"name\": \"itemType\",\n            \"type\": \"uint8\"\n          },\n          {\n            \"name\": \"token\",\n            \"type\": \"address\"\n          },\n          {\n            \"name\": \"identifierOrCriteria\",\n            \"type\": \"uint256\"\n          },\n          {\n            \"name\": \"startAmount\",\n            \"type\": \"uint256\"\n          },\n          {\n            \"name\": \"endAmount\",\n            \"type\": \"uint256\"\n          },\n          {\n            \"name\": \"recipient\",\n            \"type\": \"address\"\n          }\n        ]\n      },\n      \"primaryType\": \"OrderComponents\",\n      \"domain\": {\n        \"name\": \"Seaport\",\n        \"version\": \"1.1\",\n        \"chainId\": \"1\",\n        \"verifyingContract\": \"0x00000000006c3852cbEf3e08E8dF289169EdE581\"\n      },\n      \"message\": {\n        \"offerer\": \"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266\",\n        \"offer\": [\n          {\n            \"itemType\": \"3\",\n            \"token\": \"0xA604060890923Ff400e8c6f5290461A83AEDACec\",\n            \"identifierOrCriteria\": \"110194434039389003190498847789203126033799499726478230611233094448886344768909\",\n            \"startAmount\": \"1\",\n            \"endAmount\": \"1\"\n          }\n        ],\n        \"consideration\": [\n          {\n            \"itemType\": \"0\",\n            \"token\": \"0x0000000000000000000000000000000000000000\",\n            \"identifierOrCriteria\": \"0\",\n            \"startAmount\": \"487500000000000000\",\n            \"endAmount\": \"487500000000000000\",\n            \"recipient\": \"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266\"\n          },\n          {\n            \"itemType\": \"0\",\n            \"token\": \"0x0000000000000000000000000000000000000000\",\n            \"identifierOrCriteria\": \"0\",\n            \"startAmount\": \"12500000000000000\",\n            \"endAmount\": \"12500000000000000\",\n            \"recipient\": \"0x8De9C5A032463C561423387a9648c5C7BCC5BC90\"\n          }\n        ],\n        \"startTime\": \"1658645591\",\n        \"endTime\": \"1659250386\",\n        \"orderType\": \"3\",\n        \"zone\": \"0x004C00500000aD104D7DBd00e3ae0A5C00560C00\",\n        \"zoneHash\": \"0x0000000000000000000000000000000000000000000000000000000000000000\",\n        \"salt\": \"16178208897136618\",\n        \"conduitKey\": \"0x0000007b02230091a7ed01230072f7006a004d60a8d4e71d599b8104250f0000\",\n        \"totalOriginalConsiderationItems\": \"2\",\n        \"counter\": \"0\"\n      }\n    }\n        );\n\n    let typed_data: TypedData = serde_json::from_value(json).unwrap();\n\n    // `curl -X POST http://localhost:8545 -d '{\"jsonrpc\": \"2.0\", \"method\": \"eth_signTypedData_v4\", \"params\": [\"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266\", {\"types\":{\"EIP712Domain\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"version\",\"type\":\"string\"},{\"name\":\"chainId\",\"type\":\"uint256\"},{\"name\":\"verifyingContract\",\"type\":\"address\"}],\"OrderComponents\":[{\"name\":\"offerer\",\"type\":\"address\"},{\"name\":\"zone\",\"type\":\"address\"},{\"name\":\"offer\",\"type\":\"OfferItem[]\"},{\"name\":\"consideration\",\"type\":\"ConsiderationItem[]\"},{\"name\":\"orderType\",\"type\":\"uint8\"},{\"name\":\"startTime\",\"type\":\"uint256\"},{\"name\":\"endTime\",\"type\":\"uint256\"},{\"name\":\"zoneHash\",\"type\":\"bytes32\"},{\"name\":\"salt\",\"type\":\"uint256\"},{\"name\":\"conduitKey\",\"type\":\"bytes32\"},{\"name\":\"counter\",\"type\":\"uint256\"}],\"OfferItem\":[{\"name\":\"itemType\",\"type\":\"uint8\"},{\"name\":\"token\",\"type\":\"address\"},{\"name\":\"identifierOrCriteria\",\"type\":\"uint256\"},{\"name\":\"startAmount\",\"type\":\"uint256\"},{\"name\":\"endAmount\",\"type\":\"uint256\"}],\"ConsiderationItem\":[{\"name\":\"itemType\",\"type\":\"uint8\"},{\"name\":\"token\",\"type\":\"address\"},{\"name\":\"identifierOrCriteria\",\"type\":\"uint256\"},{\"name\":\"startAmount\",\"type\":\"uint256\"},{\"name\":\"endAmount\",\"type\":\"uint256\"},{\"name\":\"recipient\",\"type\":\"address\"}]},\"primaryType\":\"OrderComponents\",\"domain\":{\"name\":\"Seaport\",\"version\":\"1.1\",\"chainId\":\"1\",\"verifyingContract\":\"0x00000000006c3852cbEf3e08E8dF289169EdE581\"},\"message\":{\"offerer\":\"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266\",\"offer\":[{\"itemType\":\"3\",\"token\":\"0xA604060890923Ff400e8c6f5290461A83AEDACec\",\"identifierOrCriteria\":\"110194434039389003190498847789203126033799499726478230611233094448886344768909\",\"startAmount\":\"1\",\"endAmount\":\"1\"}],\"consideration\":[{\"itemType\":\"0\",\"token\":\"0x0000000000000000000000000000000000000000\",\"identifierOrCriteria\":\"0\",\"startAmount\":\"487500000000000000\",\"endAmount\":\"487500000000000000\",\"recipient\":\"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266\"},{\"itemType\":\"0\",\"token\":\"0x0000000000000000000000000000000000000000\",\"identifierOrCriteria\":\"0\",\"startAmount\":\"12500000000000000\",\"endAmount\":\"12500000000000000\",\"recipient\":\"0x8De9C5A032463C561423387a9648c5C7BCC5BC90\"}],\"startTime\":\"1658645591\",\"endTime\":\"1659250386\",\"orderType\":\"3\",\"zone\":\"0x004C00500000aD104D7DBd00e3ae0A5C00560C00\",\"zoneHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"salt\":\"16178208897136618\",\"conduitKey\":\"0x0000007b02230091a7ed01230072f7006a004d60a8d4e71d599b8104250f0000\",\"totalOriginalConsiderationItems\":\"2\",\"counter\":\"0\"}}], \"id\": \"1\"}' -H \"Content-Type: application/json\"`\n\n    let signature = api\n        .sign_typed_data_v4(\n            \"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266\".parse().unwrap(),\n            &typed_data,\n        )\n        .await\n        .unwrap();\n\n    assert_eq!(\n      signature,\n      \"0xedb0fa55ac67e3ca52b6bd6ee3576b193731adc2aff42151f67826932fa9f6191261ebdecc2c650204ff7625752b033293fb67ef5cfca78e16de359200040b761b\".to_string()\n    );\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_sign_transaction() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n\n    let accounts = handle.dev_wallets().collect::<Vec<_>>();\n    let from = accounts[0].address();\n    let to = accounts[1].address();\n\n    // craft the tx\n    // specify the `from` field so that the client knows which account to use\n    let tx = TransactionRequest::default()\n        .nonce(10)\n        .max_fee_per_gas(100)\n        .max_priority_fee_per_gas(101)\n        .to(to)\n        .value(U256::from(1001u64))\n        .from(from);\n    let tx = WithOtherFields::new(tx);\n    // sign it via the eth_signTransaction API\n    let signed_tx = api.sign_transaction(tx).await.unwrap();\n\n    assert_eq!(\n        signed_tx,\n        \"0x02f866827a690a65648252089470997970c51812dc3a010c7d01b50e0d17dc79c88203e980c001a0e4de88aefcf87ccb04466e60de66a83192e46aa26177d5ea35efbfd43fd0ecdca00e3148e0e8e0b9a6f9b329efd6e30c4a461920f3a27497be3dbefaba996601da\"\n    );\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn rejects_different_chain_id() {\n    let (_api, handle) = spawn(NodeConfig::test()).await;\n    let wallet = handle.dev_wallets().next().unwrap().with_chain_id(Some(1));\n    let provider = http_provider_with_signer(&handle.http_endpoint(), EthereumWallet::from(wallet));\n\n    let tx = TransactionRequest::default().to(Address::random()).value(U256::from(100));\n    let tx = WithOtherFields::new(tx);\n    let res = provider.send_transaction(tx).await;\n    let err = res.unwrap_err();\n    assert!(err.to_string().contains(\"does not match the signer's\"), \"{}\", err.to_string());\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn rejects_invalid_chain_id() {\n    let (_api, handle) = spawn(NodeConfig::test()).await;\n    let wallet = handle.dev_wallets().next().unwrap();\n    let wallet = wallet.with_chain_id(Some(99u64));\n    let provider = http_provider_with_signer(&handle.http_endpoint(), EthereumWallet::from(wallet));\n    let tx = TransactionRequest::default().to(Address::random()).value(U256::from(100u64));\n    let tx = WithOtherFields::new(tx);\n    let res = provider.send_transaction(tx).await;\n    let _err = res.unwrap_err();\n}\n\n// <https://github.com/foundry-rs/foundry/issues/3409>\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_sign_typed_seaport_data() {\n    let (api, _handle) = spawn(NodeConfig::test()).await;\n\n    let json = serde_json::json!(\n       {\n      \"types\": {\n        \"EIP712Domain\": [\n          {\n            \"name\": \"name\",\n            \"type\": \"string\"\n          },\n          {\n            \"name\": \"version\",\n            \"type\": \"string\"\n          },\n          {\n            \"name\": \"chainId\",\n            \"type\": \"uint256\"\n          },\n          {\n            \"name\": \"verifyingContract\",\n            \"type\": \"address\"\n          }\n        ],\n        \"OrderComponents\": [\n          {\n            \"name\": \"offerer\",\n            \"type\": \"address\"\n          },\n          {\n            \"name\": \"zone\",\n            \"type\": \"address\"\n          },\n          {\n            \"name\": \"offer\",\n            \"type\": \"OfferItem[]\"\n          },\n          {\n            \"name\": \"consideration\",\n            \"type\": \"ConsiderationItem[]\"\n          },\n          {\n            \"name\": \"orderType\",\n            \"type\": \"uint8\"\n          },\n          {\n            \"name\": \"startTime\",\n            \"type\": \"uint256\"\n          },\n          {\n            \"name\": \"endTime\",\n            \"type\": \"uint256\"\n          },\n          {\n            \"name\": \"zoneHash\",\n            \"type\": \"bytes32\"\n          },\n          {\n            \"name\": \"salt\",\n            \"type\": \"uint256\"\n          },\n          {\n            \"name\": \"conduitKey\",\n            \"type\": \"bytes32\"\n          },\n          {\n            \"name\": \"counter\",\n            \"type\": \"uint256\"\n          }\n        ],\n        \"OfferItem\": [\n          {\n            \"name\": \"itemType\",\n            \"type\": \"uint8\"\n          },\n          {\n            \"name\": \"token\",\n            \"type\": \"address\"\n          },\n          {\n            \"name\": \"identifierOrCriteria\",\n            \"type\": \"uint256\"\n          },\n          {\n            \"name\": \"startAmount\",\n            \"type\": \"uint256\"\n          },\n          {\n            \"name\": \"endAmount\",\n            \"type\": \"uint256\"\n          }\n        ],\n        \"ConsiderationItem\": [\n          {\n            \"name\": \"itemType\",\n            \"type\": \"uint8\"\n          },\n          {\n            \"name\": \"token\",\n            \"type\": \"address\"\n          },\n          {\n            \"name\": \"identifierOrCriteria\",\n            \"type\": \"uint256\"\n          },\n          {\n            \"name\": \"startAmount\",\n            \"type\": \"uint256\"\n          },\n          {\n            \"name\": \"endAmount\",\n            \"type\": \"uint256\"\n          },\n          {\n            \"name\": \"recipient\",\n            \"type\": \"address\"\n          }\n        ]\n      },\n      \"primaryType\": \"OrderComponents\",\n      \"domain\": {\n        \"name\": \"Seaport\",\n        \"version\": \"1.1\",\n        \"chainId\": \"137\",\n        \"verifyingContract\": \"0x00000000006c3852cbEf3e08E8dF289169EdE581\"\n      },\n      \"message\": {\n        \"offerer\": \"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266\",\n        \"offer\": [\n          {\n            \"itemType\": \"3\",\n            \"token\": \"0xA604060890923Ff400e8c6f5290461A83AEDACec\",\n            \"identifierOrCriteria\": \"110194434039389003190498847789203126033799499726478230611233094448886344768909\",\n            \"startAmount\": \"1\",\n            \"endAmount\": \"1\"\n          }\n        ],\n        \"consideration\": [\n          {\n            \"itemType\": \"0\",\n            \"token\": \"0x0000000000000000000000000000000000000000\",\n            \"identifierOrCriteria\": \"0\",\n            \"startAmount\": \"487500000000000000\",\n            \"endAmount\": \"487500000000000000\",\n            \"recipient\": \"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266\"\n          },\n          {\n            \"itemType\": \"0\",\n            \"token\": \"0x0000000000000000000000000000000000000000\",\n            \"identifierOrCriteria\": \"0\",\n            \"startAmount\": \"12500000000000000\",\n            \"endAmount\": \"12500000000000000\",\n            \"recipient\": \"0x8De9C5A032463C561423387a9648c5C7BCC5BC90\"\n          }\n        ],\n        \"startTime\": \"1658645591\",\n        \"endTime\": \"1659250386\",\n        \"orderType\": \"3\",\n        \"zone\": \"0x004C00500000aD104D7DBd00e3ae0A5C00560C00\",\n        \"zoneHash\": \"0x0000000000000000000000000000000000000000000000000000000000000000\",\n        \"salt\": \"16178208897136618\",\n        \"conduitKey\": \"0x0000007b02230091a7ed01230072f7006a004d60a8d4e71d599b8104250f0000\",\n        \"totalOriginalConsiderationItems\": \"2\",\n        \"counter\": \"0\"\n      }\n    }\n            );\n\n    let typed_data: TypedData = serde_json::from_value(json).unwrap();\n\n    // `curl -X POST http://localhost:8545 -d '{\"jsonrpc\": \"2.0\", \"method\": \"eth_signTypedData_v4\", \"params\": [\"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266\", \"{\\\"types\\\":{\\\"EIP712Domain\\\":[{\\\"name\\\":\\\"name\\\",\\\"type\\\":\\\"string\\\"},{\\\"name\\\":\\\"version\\\",\\\"type\\\":\\\"string\\\"},{\\\"name\\\":\\\"chainId\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"name\\\":\\\"verifyingContract\\\",\\\"type\\\":\\\"address\\\"}],\\\"OrderComponents\\\":[{\\\"name\\\":\\\"offerer\\\",\\\"type\\\":\\\"address\\\"},{\\\"name\\\":\\\"zone\\\",\\\"type\\\":\\\"address\\\"},{\\\"name\\\":\\\"offer\\\",\\\"type\\\":\\\"OfferItem[]\\\"},{\\\"name\\\":\\\"consideration\\\",\\\"type\\\":\\\"ConsiderationItem[]\\\"},{\\\"name\\\":\\\"orderType\\\",\\\"type\\\":\\\"uint8\\\"},{\\\"name\\\":\\\"startTime\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"name\\\":\\\"endTime\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"name\\\":\\\"zoneHash\\\",\\\"type\\\":\\\"bytes32\\\"},{\\\"name\\\":\\\"salt\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"name\\\":\\\"conduitKey\\\",\\\"type\\\":\\\"bytes32\\\"},{\\\"name\\\":\\\"counter\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"OfferItem\\\":[{\\\"name\\\":\\\"itemType\\\",\\\"type\\\":\\\"uint8\\\"},{\\\"name\\\":\\\"token\\\",\\\"type\\\":\\\"address\\\"},{\\\"name\\\":\\\"identifierOrCriteria\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"name\\\":\\\"startAmount\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"name\\\":\\\"endAmount\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"ConsiderationItem\\\":[{\\\"name\\\":\\\"itemType\\\",\\\"type\\\":\\\"uint8\\\"},{\\\"name\\\":\\\"token\\\",\\\"type\\\":\\\"address\\\"},{\\\"name\\\":\\\"identifierOrCriteria\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"name\\\":\\\"startAmount\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"name\\\":\\\"endAmount\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"name\\\":\\\"recipient\\\",\\\"type\\\":\\\"address\\\"}]},\\\"primaryType\\\":\\\"OrderComponents\\\",\\\"domain\\\":{\\\"name\\\":\\\"Seaport\\\",\\\"version\\\":\\\"1.1\\\",\\\"chainId\\\":\\\"137\\\",\\\"verifyingContract\\\":\\\"0x00000000006c3852cbEf3e08E8dF289169EdE581\\\"},\\\"message\\\":{\\\"offerer\\\":\\\"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266\\\",\\\"offer\\\":[{\\\"itemType\\\":\\\"3\\\",\\\"token\\\":\\\"0xA604060890923Ff400e8c6f5290461A83AEDACec\\\",\\\"identifierOrCriteria\\\":\\\"110194434039389003190498847789203126033799499726478230611233094448886344768909\\\",\\\"startAmount\\\":\\\"1\\\",\\\"endAmount\\\":\\\"1\\\"}],\\\"consideration\\\":[{\\\"itemType\\\":\\\"0\\\",\\\"token\\\":\\\"0x0000000000000000000000000000000000000000\\\",\\\"identifierOrCriteria\\\":\\\"0\\\",\\\"startAmount\\\":\\\"487500000000000000\\\",\\\"endAmount\\\":\\\"487500000000000000\\\",\\\"recipient\\\":\\\"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266\\\"},{\\\"itemType\\\":\\\"0\\\",\\\"token\\\":\\\"0x0000000000000000000000000000000000000000\\\",\\\"identifierOrCriteria\\\":\\\"0\\\",\\\"startAmount\\\":\\\"12500000000000000\\\",\\\"endAmount\\\":\\\"12500000000000000\\\",\\\"recipient\\\":\\\"0x8De9C5A032463C561423387a9648c5C7BCC5BC90\\\"}],\\\"startTime\\\":\\\"1658645591\\\",\\\"endTime\\\":\\\"1659250386\\\",\\\"orderType\\\":\\\"3\\\",\\\"zone\\\":\\\"0x004C00500000aD104D7DBd00e3ae0A5C00560C00\\\",\\\"zoneHash\\\":\\\"0x0000000000000000000000000000000000000000000000000000000000000000\\\",\\\"salt\\\":\\\"16178208897136618\\\",\\\"conduitKey\\\":\\\"0x0000007b02230091a7ed01230072f7006a004d60a8d4e71d599b8104250f0000\\\",\\\"totalOriginalConsiderationItems\\\":\\\"2\\\",\\\"counter\\\":\\\"0\\\"}}\"], \"id\": \"1\"}' -H \"Content-Type: application/json\"`\n\n    let signature = api\n        .sign_typed_data_v4(\n            \"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266\".parse().unwrap(),\n            &typed_data,\n        )\n        .await\n        .unwrap();\n\n    assert_eq!(\n    signature,\n    \"0xed9afe7f377155ee3a42b25b696d79b55d441aeac7790b97a51b54ad0569b9665ea30bf8e8df12d6ee801c4dcb85ecfb8b23a6f7ae166d5af9acac9befb905451c\".to_string()\n  );\n}\n"
  },
  {
    "path": "crates/anvil/tests/it/simulate.rs",
    "content": "//! general eth api tests\n\nuse alloy_primitives::{TxKind, U256, address};\nuse alloy_rpc_types::{\n    BlockOverrides,\n    request::TransactionRequest,\n    simulate::{SimBlock, SimulatePayload},\n    state::{AccountOverride, StateOverridesBuilder},\n};\nuse anvil::{NodeConfig, spawn};\nuse foundry_test_utils::rpc;\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_fork_simulate_v1() {\n    crate::init_tracing();\n    let (api, _) =\n        spawn(NodeConfig::test().with_eth_rpc_url(Some(rpc::next_http_archive_rpc_url()))).await;\n    let block_overrides =\n        Some(BlockOverrides { base_fee: Some(U256::from(9)), ..Default::default() });\n    let account_override =\n        AccountOverride { balance: Some(U256::from(999999999999u64)), ..Default::default() };\n    let state_overrides = Some(\n        StateOverridesBuilder::with_capacity(1)\n            .append(address!(\"0xc000000000000000000000000000000000000001\"), account_override)\n            .build(),\n    );\n    let tx_request = TransactionRequest {\n        from: Some(address!(\"0xc000000000000000000000000000000000000001\")),\n        to: Some(TxKind::from(address!(\"0xc000000000000000000000000000000000000001\"))),\n        value: Some(U256::from(1)),\n        ..Default::default()\n    };\n    let payload = SimulatePayload {\n        block_state_calls: vec![SimBlock {\n            block_overrides,\n            state_overrides,\n            calls: vec![tx_request],\n        }],\n        trace_transfers: true,\n        validation: false,\n        return_full_transactions: true,\n    };\n    let _res = api.simulate_v1(payload, None).await.unwrap();\n}\n"
  },
  {
    "path": "crates/anvil/tests/it/state.rs",
    "content": "//! general eth api tests\n\nuse crate::abi::Greeter;\nuse alloy_network::{ReceiptResponse, TransactionBuilder};\nuse alloy_primitives::{Bytes, U256, Uint, address, b256, utils::Unit};\nuse alloy_provider::Provider;\nuse alloy_rpc_types::{BlockId, TransactionRequest};\nuse alloy_serde::WithOtherFields;\nuse anvil::{NodeConfig, eth::backend::db::SerializableState, spawn};\nuse foundry_test_utils::rpc::next_http_archive_rpc_url;\nuse revm::{\n    context_interface::block::BlobExcessGasAndPrice,\n    primitives::eip4844::BLOB_BASE_FEE_UPDATE_FRACTION_PRAGUE,\n};\nuse serde_json::json;\nuse std::str::FromStr;\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_load_state() {\n    let tmp = tempfile::tempdir().unwrap();\n    let state_file = tmp.path().join(\"state.json\");\n\n    let (api, _handle) = spawn(NodeConfig::test()).await;\n\n    api.mine_one().await;\n    api.mine_one().await;\n\n    let num = api.block_number().unwrap();\n\n    let state = api.serialized_state(false).await.unwrap();\n    foundry_common::fs::write_json_file(&state_file, &state).unwrap();\n\n    let (api, _handle) = spawn(NodeConfig::test().with_init_state_path(state_file)).await;\n\n    let num2 = api.block_number().unwrap();\n\n    // Ref: https://github.com/foundry-rs/foundry/issues/9017\n    // Check responses of eth_blockNumber and eth_getBlockByNumber don't deviate after loading state\n    let num_from_tag = api\n        .block_by_number(alloy_eips::BlockNumberOrTag::Latest)\n        .await\n        .unwrap()\n        .unwrap()\n        .header\n        .number;\n    assert_eq!(num, num2);\n\n    assert_eq!(num, U256::from(num_from_tag));\n}\n\n// <https://github.com/foundry-rs/foundry/issues/12645>\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn finalized_block_hash_consistent_after_load_state() {\n    use alloy_eips::BlockNumberOrTag;\n\n    let tmp = tempfile::tempdir().unwrap();\n    let state_file = tmp.path().join(\"state.json\");\n\n    let (api, _handle) = spawn(NodeConfig::test()).await;\n\n    api.mine_one().await;\n\n    // Get the original genesis block hash\n    let original_genesis = api.block_by_number(BlockNumberOrTag::Number(0)).await.unwrap().unwrap();\n    let original_genesis_hash = original_genesis.header.hash;\n\n    let state = api.serialized_state(false).await.unwrap();\n    foundry_common::fs::write_json_file(&state_file, &state).unwrap();\n\n    // Load state with a different genesis timestamp.\n    // The new instance will create its own genesis block with a different timestamp,\n    // but then load_state should overwrite it. The bug is that genesis_hash field isn't updated.\n    let (api, _handle) = spawn(\n        NodeConfig::test()\n            .with_genesis_timestamp(Some(original_genesis.header.timestamp + 1000))\n            .with_init_state_path(state_file),\n    )\n    .await;\n\n    // Query finalized block - should return genesis (block 0) since best_number is small\n    let finalized_block = api.block_by_number(BlockNumberOrTag::Finalized).await.unwrap().unwrap();\n    let finalized_hash = finalized_block.header.hash;\n    let finalized_number = finalized_block.header.number;\n\n    // Query block by the finalized block's number directly\n    let block_by_number =\n        api.block_by_number(BlockNumberOrTag::Number(finalized_number)).await.unwrap().unwrap();\n    let block_by_number_hash = block_by_number.header.hash;\n\n    // Verify the loaded genesis matches the original\n    assert_eq!(\n        block_by_number_hash, original_genesis_hash,\n        \"Loaded genesis should match original genesis hash\"\n    );\n\n    // Both finalized and block 0 should return the same hash\n    assert_eq!(\n        finalized_hash, block_by_number_hash,\n        \"Finalized block hash should match block queried by number\"\n    );\n\n    // Also verify Earliest block tag returns consistent hash\n    let earliest_block = api.block_by_number(BlockNumberOrTag::Earliest).await.unwrap().unwrap();\n    assert_eq!(\n        earliest_block.header.hash, original_genesis_hash,\n        \"Earliest block hash should match original genesis hash\"\n    );\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_load_existing_state_legacy() {\n    let state_file = \"test-data/state-dump-legacy.json\";\n\n    let (api, _handle) = spawn(NodeConfig::test().with_init_state_path(state_file)).await;\n\n    let block_number = api.block_number().unwrap();\n    assert_eq!(block_number, Uint::from(2));\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_load_existing_state_legacy_stress() {\n    let state_file = \"test-data/state-dump-legacy-stress.json\";\n\n    let (api, _handle) = spawn(NodeConfig::test().with_init_state_path(state_file)).await;\n\n    let block_number = api.block_number().unwrap();\n    assert_eq!(block_number, Uint::from(5));\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_load_existing_state() {\n    let state_file = \"test-data/state-dump.json\";\n\n    let (api, _handle) = spawn(NodeConfig::test().with_init_state_path(state_file)).await;\n\n    let block_number = api.block_number().unwrap();\n    assert_eq!(block_number, Uint::from(2));\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_make_sure_historical_state_is_not_cleared_on_dump() {\n    let tmp = tempfile::tempdir().unwrap();\n    let state_file = tmp.path().join(\"state.json\");\n\n    let (api, handle) = spawn(NodeConfig::test()).await;\n\n    let provider = handle.http_provider();\n\n    let greeter = Greeter::deploy(&provider, \"Hello\".to_string()).await.unwrap();\n\n    let address = greeter.address();\n\n    let _tx = greeter\n        .setGreeting(\"World!\".to_string())\n        .send()\n        .await\n        .unwrap()\n        .get_receipt()\n        .await\n        .unwrap();\n\n    api.mine_one().await;\n\n    let ser_state = api.serialized_state(true).await.unwrap();\n    foundry_common::fs::write_json_file(&state_file, &ser_state).unwrap();\n\n    let block_number = api.block_number().unwrap();\n    assert_eq!(block_number, Uint::from(3));\n\n    // Makes sure historical states of the new instance are not cleared.\n    let code = provider.get_code_at(*address).block_id(BlockId::number(2)).await.unwrap();\n\n    assert_ne!(code, Bytes::new());\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_preserve_historical_states_between_dump_and_load() {\n    let tmp = tempfile::tempdir().unwrap();\n    let state_file = tmp.path().join(\"state.json\");\n\n    let (api, handle) = spawn(NodeConfig::test()).await;\n\n    let provider = handle.http_provider();\n\n    let greeter = Greeter::deploy(&provider, \"Hello\".to_string()).await.unwrap();\n\n    let address = greeter.address();\n\n    let deploy_blk_num = provider.get_block_number().await.unwrap();\n\n    let tx = greeter\n        .setGreeting(\"World!\".to_string())\n        .send()\n        .await\n        .unwrap()\n        .get_receipt()\n        .await\n        .unwrap();\n\n    let change_greeting_blk_num = tx.block_number.unwrap();\n\n    api.mine_one().await;\n\n    let ser_state = api.serialized_state(true).await.unwrap();\n    foundry_common::fs::write_json_file(&state_file, &ser_state).unwrap();\n\n    let (api, handle) = spawn(NodeConfig::test().with_init_state_path(state_file)).await;\n\n    let block_number = api.block_number().unwrap();\n    assert_eq!(block_number, Uint::from(3));\n\n    let provider = handle.http_provider();\n\n    let greeter = Greeter::new(*address, provider);\n\n    let greeting_at_init =\n        greeter.greet().block(BlockId::number(deploy_blk_num)).call().await.unwrap();\n\n    assert_eq!(greeting_at_init, \"Hello\");\n\n    let greeting_after_change =\n        greeter.greet().block(BlockId::number(change_greeting_blk_num)).call().await.unwrap();\n\n    assert_eq!(greeting_after_change, \"World!\");\n}\n\n// <https://github.com/foundry-rs/foundry/issues/9053>\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_fork_load_state() {\n    let (api, handle) = spawn(\n        NodeConfig::test()\n            .with_eth_rpc_url(Some(next_http_archive_rpc_url()))\n            .with_fork_block_number(Some(21070682u64)),\n    )\n    .await;\n\n    let bob = address!(\"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266\");\n    let alice = address!(\"0x9276449EaC5b4f7Bc17cFC6700f7BeeB86F9bCd0\");\n\n    let provider = handle.http_provider();\n\n    let init_nonce_bob = provider.get_transaction_count(bob).await.unwrap();\n\n    let init_balance_alice = provider.get_balance(alice).await.unwrap();\n\n    let value = Unit::ETHER.wei().saturating_mul(U256::from(1)); // 1 ether\n    let tx = TransactionRequest::default().with_to(alice).with_value(value).with_from(bob);\n    let tx = WithOtherFields::new(tx);\n\n    let receipt = provider.send_transaction(tx).await.unwrap().get_receipt().await.unwrap();\n\n    assert!(receipt.status());\n\n    let serialized_state = api.serialized_state(false).await.unwrap();\n\n    let state_dump_block = api.block_number().unwrap();\n\n    let (api, handle) = spawn(\n        NodeConfig::test()\n            .with_eth_rpc_url(Some(next_http_archive_rpc_url()))\n            .with_fork_block_number(Some(21070686u64)) // Forked chain has moved forward\n            .with_init_state(Some(serialized_state)),\n    )\n    .await;\n\n    // Ensure the initial block number is the fork_block_number and not the state_dump_block\n    let block_number = api.block_number().unwrap();\n    assert_eq!(block_number, U256::from(21070686u64));\n    assert_ne!(block_number, state_dump_block);\n\n    let provider = handle.http_provider();\n\n    let restart_nonce_bob = provider.get_transaction_count(bob).await.unwrap();\n\n    let restart_balance_alice = provider.get_balance(alice).await.unwrap();\n\n    assert_eq!(init_nonce_bob + 1, restart_nonce_bob);\n\n    assert_eq!(init_balance_alice + value, restart_balance_alice);\n\n    // Send another tx to check if the state is preserved\n\n    let tx = TransactionRequest::default().with_to(alice).with_value(value).with_from(bob);\n    let tx = WithOtherFields::new(tx);\n\n    let receipt = provider.send_transaction(tx).await.unwrap().get_receipt().await.unwrap();\n\n    assert!(receipt.status());\n\n    let nonce_bob = provider.get_transaction_count(bob).await.unwrap();\n\n    let balance_alice = provider.get_balance(alice).await.unwrap();\n\n    let tx = TransactionRequest::default()\n        .with_to(alice)\n        .with_value(value)\n        .with_from(bob)\n        .with_nonce(nonce_bob);\n    let tx = WithOtherFields::new(tx);\n\n    let receipt = provider.send_transaction(tx).await.unwrap().get_receipt().await.unwrap();\n\n    assert!(receipt.status());\n\n    let latest_nonce_bob = provider.get_transaction_count(bob).await.unwrap();\n\n    let latest_balance_alice = provider.get_balance(alice).await.unwrap();\n\n    assert_eq!(nonce_bob + 1, latest_nonce_bob);\n\n    assert_eq!(balance_alice + value, latest_balance_alice);\n}\n\n// <https://github.com/foundry-rs/foundry/issues/9539>\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_fork_load_state_with_greater_state_block() {\n    let (api, _handle) = spawn(\n        NodeConfig::test()\n            .with_eth_rpc_url(Some(next_http_archive_rpc_url()))\n            .with_fork_block_number(Some(21070682u64)),\n    )\n    .await;\n\n    api.mine_one().await;\n\n    let block_number = api.block_number().unwrap();\n\n    let serialized_state = api.serialized_state(false).await.unwrap();\n\n    assert_eq!(serialized_state.best_block_number, Some(block_number.to::<u64>()));\n\n    let (api, _handle) = spawn(\n        NodeConfig::test()\n            .with_eth_rpc_url(Some(next_http_archive_rpc_url()))\n            .with_fork_block_number(Some(21070682u64)) // Forked chain has moved forward\n            .with_init_state(Some(serialized_state)),\n    )\n    .await;\n\n    let new_block_number = api.block_number().unwrap();\n\n    assert_eq!(new_block_number, block_number);\n}\n\n// <https://github.com/foundry-rs/foundry/issues/10488>\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn computes_next_base_fee_after_loading_state() {\n    let tmp = tempfile::tempdir().unwrap();\n    let state_file = tmp.path().join(\"state.json\");\n\n    let (api, handle) = spawn(NodeConfig::test()).await;\n\n    let bob = address!(\"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266\");\n    let alice = address!(\"0x9276449EaC5b4f7Bc17cFC6700f7BeeB86F9bCd0\");\n\n    let provider = handle.http_provider();\n\n    let base_fee_empty_chain = api.backend.fees().base_fee();\n\n    let value = Unit::ETHER.wei().saturating_mul(U256::from(1)); // 1 ether\n    let tx = TransactionRequest::default().with_to(alice).with_value(value).with_from(bob);\n    let tx = WithOtherFields::new(tx);\n\n    let _receipt = provider.send_transaction(tx).await.unwrap().get_receipt().await.unwrap();\n\n    let base_fee_after_one_tx = api.backend.fees().base_fee();\n    // the test is meaningless if this does not hold\n    assert_ne!(base_fee_empty_chain, base_fee_after_one_tx);\n\n    let ser_state = api.serialized_state(true).await.unwrap();\n    foundry_common::fs::write_json_file(&state_file, &ser_state).unwrap();\n\n    let (api, _handle) = spawn(NodeConfig::test().with_init_state_path(state_file)).await;\n    let base_fee_after_reload = api.backend.fees().base_fee();\n    assert_eq!(base_fee_after_reload, base_fee_after_one_tx);\n}\n\n// <https://github.com/foundry-rs/foundry/issues/11176>\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_backward_compatibility_deserialization_v1_2() {\n    let old_format = r#\"{\n        \"block\": {\n            \"number\": \"0x5\",\n            \"coinbase\": \"0x1234567890123456789012345678901234567890\",\n            \"timestamp\": \"0x688c83b5\",\n            \"gas_limit\": \"0x1c9c380\",\n            \"basefee\": \"0x3b9aca00\",  \n            \"difficulty\": \"0x0\",\n            \"prevrandao\": \"0xecc5f0af8ff6b65c14bfdac55ba9db870d89482eb2b87200c6d7e7cd3a3a5ad5\",\n            \"blob_excess_gas_and_price\": {\n                \"excess_blob_gas\": 0,\n                \"blob_gasprice\": 1\n            }\n        },\n        \"accounts\": {},\n        \"best_block_number\": \"0x5\",\n        \"blocks\": [],\n        \"transactions\": []\n    }\"#;\n\n    let state: SerializableState = serde_json::from_str(old_format).unwrap();\n    assert!(state.block.is_some());\n    let block_env = state.block.unwrap();\n    assert_eq!(block_env.number, U256::from(5));\n    // Verify coinbase was converted to beneficiary\n    assert_eq!(block_env.beneficiary, address!(\"0x1234567890123456789012345678901234567890\"));\n\n    // New format with beneficiary and numeric values\n    let new_format = r#\"{\n        \"block\": {\n            \"number\": 6,\n            \"beneficiary\": \"0x1234567890123456789012345678901234567891\",\n            \"timestamp\": 1751619509,\n            \"gas_limit\": 30000000,\n            \"basefee\": 1000000000,\n            \"difficulty\": \"0x0\",\n            \"prevrandao\": \"0xecc5f0af8ff6b65c14bfdac55ba9db870d89482eb2b87200c6d7e7cd3a3a5ad5\",\n            \"blob_excess_gas_and_price\": {\n                \"excess_blob_gas\": 0,\n                \"blob_gasprice\": 1\n            }\n        },\n        \"accounts\": {},\n        \"best_block_number\": 6,\n        \"blocks\": [],\n        \"transactions\": []\n    }\"#;\n\n    let state: SerializableState = serde_json::from_str(new_format).unwrap();\n    assert!(state.block.is_some());\n    let block_env = state.block.unwrap();\n    assert_eq!(block_env.number, U256::from(6));\n    assert_eq!(block_env.beneficiary, address!(\"0x1234567890123456789012345678901234567891\"));\n}\n\n// <https://github.com/foundry-rs/foundry/issues/11176>\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_backward_compatibility_mixed_formats_deserialization_v1_2() {\n    let mixed_format = json!({\n        \"block\": {\n            \"number\": \"0x3\",\n            \"coinbase\": \"0x1111111111111111111111111111111111111111\",\n            \"timestamp\": 1751619509,\n            \"gas_limit\": \"0x1c9c380\",\n            \"basefee\": 1000000000,\n            \"difficulty\": \"0x0\",\n            \"prevrandao\": \"0xecc5f0af8ff6b65c14bfdac55ba9db870d89482eb2b87200c6d7e7cd3a3a5ad5\",\n            \"blob_excess_gas_and_price\": {\n                \"excess_blob_gas\": 0,\n                \"blob_gasprice\": 1\n            }\n        },\n        \"accounts\": {},\n        \"best_block_number\": 3,\n        \"blocks\": [],\n        \"transactions\": []\n    });\n\n    let state: SerializableState = serde_json::from_str(&mixed_format.to_string()).unwrap();\n    let block_env = state.block.unwrap();\n\n    assert_eq!(block_env.number, U256::from(3));\n    assert_eq!(block_env.beneficiary, address!(\"0x1111111111111111111111111111111111111111\"));\n    assert_eq!(block_env.timestamp, U256::from(1751619509));\n    assert_eq!(block_env.gas_limit, 0x1c9c380);\n    assert_eq!(block_env.basefee, 1_000_000_000);\n    assert_eq!(block_env.difficulty, U256::ZERO);\n    assert_eq!(\n        block_env.prevrandao.unwrap(),\n        b256!(\"ecc5f0af8ff6b65c14bfdac55ba9db870d89482eb2b87200c6d7e7cd3a3a5ad5\")\n    );\n\n    let blob = block_env.blob_excess_gas_and_price.unwrap();\n    assert_eq!(blob.excess_blob_gas, 0);\n    assert_eq!(blob.blob_gasprice, 1);\n\n    assert_eq!(state.best_block_number, Some(3));\n}\n\n// <https://github.com/foundry-rs/foundry/issues/11176>\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_backward_compatibility_optional_fields_deserialization_v1_2() {\n    let partial_old_format = json!({\n        \"block\": {\n            \"number\": \"0x1\",\n            \"coinbase\": \"0x0000000000000000000000000000000000000000\",\n            \"timestamp\": \"0x688c83b5\",\n            \"gas_limit\": \"0x1c9c380\",\n            \"basefee\": \"0x3b9aca00\",\n            \"difficulty\": \"0x0\",\n            \"prevrandao\": \"0xecc5f0af8ff6b65c14bfdac55ba9db870d89482eb2b87200c6d7e7cd3a3a5ad5\"\n            // Missing blob_excess_gas_and_price - should be None\n        },\n        \"accounts\": {},\n        \"best_block_number\": \"0x1\"\n        // Missing blocks and transactions arrays - should default to empty\n    });\n\n    let state: SerializableState = serde_json::from_str(&partial_old_format.to_string()).unwrap();\n\n    let block_env = state.block.unwrap();\n    assert_eq!(block_env.number, U256::from(1));\n    assert_eq!(block_env.beneficiary, address!(\"0x0000000000000000000000000000000000000000\"));\n    assert_eq!(block_env.timestamp, U256::from(0x688c83b5));\n    assert_eq!(block_env.gas_limit, 0x1c9c380);\n    assert_eq!(block_env.basefee, 0x3b9aca00);\n    assert_eq!(block_env.difficulty, U256::ZERO);\n    assert_eq!(\n        block_env.prevrandao.unwrap(),\n        b256!(\"ecc5f0af8ff6b65c14bfdac55ba9db870d89482eb2b87200c6d7e7cd3a3a5ad5\")\n    );\n    assert_eq!(\n        block_env.blob_excess_gas_and_price,\n        Some(BlobExcessGasAndPrice::new(0, BLOB_BASE_FEE_UPDATE_FRACTION_PRAGUE))\n    );\n\n    assert_eq!(state.best_block_number, Some(1));\n    assert!(state.blocks.is_empty());\n    assert!(state.transactions.is_empty());\n}\n\n// <https://github.com/foundry-rs/foundry/issues/11176>\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_backward_compatibility_state_dump_deserialization_v1_2() {\n    let tmp = tempfile::tempdir().unwrap();\n    let old_state_file = tmp.path().join(\"old_state.json\");\n\n    // A simple state dump with a single block containing one transaction of a Counter contract\n    // deployment.\n    let old_state_json = json!({\n      \"block\": {\n        \"number\": \"0x1\",\n        \"coinbase\": \"0x0000000000000000000000000000000000000001\",\n        \"timestamp\": \"0x688c83b5\",\n        \"gas_limit\": \"0x1c9c380\",\n        \"basefee\": \"0x3b9aca00\",\n        \"difficulty\": \"0x0\",\n        \"prevrandao\": \"0xecc5f0af8ff6b65c14bfdac55ba9db870d89482eb2b87200c6d7e7cd3a3a5ad5\",\n        \"blob_excess_gas_and_price\": {\n          \"excess_blob_gas\": 0,\n          \"blob_gasprice\": 1\n        }\n      },\n      \"accounts\": {\n        \"0x0000000000000000000000000000000000000000\": {\n          \"nonce\": 0,\n          \"balance\": \"0x26481\",\n          \"code\": \"0x\",\n          \"storage\": {}\n        },\n        \"0x14dc79964da2c08b23698b3d3cc7ca32193d9955\": {\n          \"nonce\": 0,\n          \"balance\": \"0x21e19e0c9bab2400000\",\n          \"code\": \"0x\",\n          \"storage\": {}\n        },\n        \"0x15d34aaf54267db7d7c367839aaf71a00a2c6a65\": {\n          \"nonce\": 0,\n          \"balance\": \"0x21e19e0c9bab2400000\",\n          \"code\": \"0x\",\n          \"storage\": {}\n        },\n        \"0x23618e81e3f5cdf7f54c3d65f7fbc0abf5b21e8f\": {\n          \"nonce\": 0,\n          \"balance\": \"0x21e19e0c9bab2400000\",\n          \"code\": \"0x\",\n          \"storage\": {}\n        },\n        \"0x3c44cdddb6a900fa2b585dd299e03d12fa4293bc\": {\n          \"nonce\": 0,\n          \"balance\": \"0x21e19e0c9bab2400000\",\n          \"code\": \"0x\",\n          \"storage\": {}\n        },\n        \"0x4e59b44847b379578588920ca78fbf26c0b4956c\": {\n          \"nonce\": 0,\n          \"balance\": \"0x0\",\n          \"code\": \"0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf3\",\n          \"storage\": {}\n        },\n        \"0x5fbdb2315678afecb367f032d93f642f64180aa3\": {\n          \"nonce\": 1,\n          \"balance\": \"0x0\",\n          \"code\": \"0x608060405234801561000f575f5ffd5b506004361061003f575f3560e01c80633fb5c1cb146100435780638381f58a1461005f578063d09de08a1461007d575b5f5ffd5b61005d600480360381019061005891906100e4565b610087565b005b610067610090565b604051610074919061011e565b60405180910390f35b610085610095565b005b805f8190555050565b5f5481565b5f5f8154809291906100a690610164565b9190505550565b5f5ffd5b5f819050919050565b6100c3816100b1565b81146100cd575f5ffd5b50565b5f813590506100de816100ba565b92915050565b5f602082840312156100f9576100f86100ad565b5b5f610106848285016100d0565b91505092915050565b610118816100b1565b82525050565b5f6020820190506101315f83018461010f565b92915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f61016e826100b1565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036101a05761019f610137565b5b60018201905091905056fea264697066735822122040b6a3cd3ec8f890002f39a8719ebee029ba9bac3d7fa9d581d4712cfe9ffec264736f6c634300081e0033\",\n          \"storage\": {}\n        },\n        \"0x70997970c51812dc3a010c7d01b50e0d17dc79c8\": {\n          \"nonce\": 0,\n          \"balance\": \"0x21e19e0c9bab2400000\",\n          \"code\": \"0x\",\n          \"storage\": {}\n        },\n        \"0x90f79bf6eb2c4f870365e785982e1f101e93b906\": {\n          \"nonce\": 0,\n          \"balance\": \"0x21e19e0c9bab2400000\",\n          \"code\": \"0x\",\n          \"storage\": {}\n        },\n        \"0x976ea74026e726554db657fa54763abd0c3a0aa9\": {\n          \"nonce\": 0,\n          \"balance\": \"0x21e19e0c9bab2400000\",\n          \"code\": \"0x\",\n          \"storage\": {}\n        },\n        \"0x9965507d1a55bcc2695c58ba16fb37d819b0a4dc\": {\n          \"nonce\": 0,\n          \"balance\": \"0x21e19e0c9bab2400000\",\n          \"code\": \"0x\",\n          \"storage\": {}\n        },\n        \"0xa0ee7a142d267c1f36714e4a8f75612f20a79720\": {\n          \"nonce\": 0,\n          \"balance\": \"0x21e19e0c9bab2400000\",\n          \"code\": \"0x\",\n          \"storage\": {}\n        },\n        \"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266\": {\n          \"nonce\": 1,\n          \"balance\": \"0x21e19e03b1e9e55d17f\",\n          \"code\": \"0x\",\n          \"storage\": {}\n        }\n      },\n      \"best_block_number\": \"0x1\",\n      \"blocks\": [\n        {\n          \"header\": {\n            \"parentHash\": \"0x0000000000000000000000000000000000000000000000000000000000000000\",\n            \"sha3Uncles\": \"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347\",\n            \"miner\": \"0x0000000000000000000000000000000000000000\",\n            \"stateRoot\": \"0x0000000000000000000000000000000000000000000000000000000000000000\",\n            \"transactionsRoot\": \"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\",\n            \"receiptsRoot\": \"0x0000000000000000000000000000000000000000000000000000000000000000\",\n            \"logsBloom\": \"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\n            \"difficulty\": \"0x0\",\n            \"number\": \"0x0\",\n            \"gasLimit\": \"0x1c9c380\",\n            \"gasUsed\": \"0x0\",\n            \"timestamp\": \"0x688c83b0\",\n            \"extraData\": \"0x\",\n            \"mixHash\": \"0x0000000000000000000000000000000000000000000000000000000000000000\",\n            \"nonce\": \"0x0000000000000000\",\n            \"baseFeePerGas\": \"0x3b9aca00\",\n            \"withdrawalsRoot\": \"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\",\n            \"blobGasUsed\": \"0x0\",\n            \"excessBlobGas\": \"0x0\",\n            \"parentBeaconBlockRoot\": \"0x0000000000000000000000000000000000000000000000000000000000000000\"\n          },\n          \"transactions\": [],\n          \"ommers\": []\n        },\n        {\n          \"header\": {\n            \"parentHash\": \"0x25097583380d90c4ac42b454ed7d2f59450ed3a16fdcf7f7bd93295aa126a901\",\n            \"sha3Uncles\": \"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347\",\n            \"miner\": \"0x0000000000000000000000000000000000000000\",\n            \"stateRoot\": \"0x6e005b459ac9acefa5f47fd2d7ff8ca81a91794fdc5f7fbc3e2faeeaefe5d516\",\n            \"transactionsRoot\": \"0x59f0457ec18e2181c186f49d9ac911b33b5f4f55db5c494022147346bcfc9837\",\n            \"receiptsRoot\": \"0x88ac48b910f796aab7407814203b3a15a04a812f387e92efeccc92a2ecf809da\",\n            \"logsBloom\": \"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\n            \"difficulty\": \"0x0\",\n            \"number\": \"0x1\",\n            \"gasLimit\": \"0x1c9c380\",\n            \"gasUsed\": \"0x26481\",\n            \"timestamp\": \"0x688c83b5\",\n            \"extraData\": \"0x\",\n            \"mixHash\": \"0x0000000000000000000000000000000000000000000000000000000000000000\",\n            \"nonce\": \"0x0000000000000000\",\n            \"baseFeePerGas\": \"0x3b9aca00\",\n            \"withdrawalsRoot\": \"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\",\n            \"blobGasUsed\": \"0x0\",\n            \"excessBlobGas\": \"0x0\",\n            \"parentBeaconBlockRoot\": \"0x0000000000000000000000000000000000000000000000000000000000000000\"\n          },\n          \"transactions\": [\n            {\n              \"transaction\": {\n                \"type\": \"0x2\",\n                \"chainId\": \"0x7a69\",\n                \"nonce\": \"0x0\",\n                \"gas\": \"0x31c41\",\n                \"maxFeePerGas\": \"0x77359401\",\n                \"maxPriorityFeePerGas\": \"0x1\",\n                \"to\": null,\n                \"value\": \"0x0\",\n                \"accessList\": [],\n                \"input\": \"0x6080604052348015600e575f5ffd5b506101e18061001c5f395ff3fe608060405234801561000f575f5ffd5b506004361061003f575f3560e01c80633fb5c1cb146100435780638381f58a1461005f578063d09de08a1461007d575b5f5ffd5b61005d600480360381019061005891906100e4565b610087565b005b610067610090565b604051610074919061011e565b60405180910390f35b610085610095565b005b805f8190555050565b5f5481565b5f5f8154809291906100a690610164565b9190505550565b5f5ffd5b5f819050919050565b6100c3816100b1565b81146100cd575f5ffd5b50565b5f813590506100de816100ba565b92915050565b5f602082840312156100f9576100f86100ad565b5b5f610106848285016100d0565b91505092915050565b610118816100b1565b82525050565b5f6020820190506101315f83018461010f565b92915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f61016e826100b1565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036101a05761019f610137565b5b60018201905091905056fea264697066735822122040b6a3cd3ec8f890002f39a8719ebee029ba9bac3d7fa9d581d4712cfe9ffec264736f6c634300081e0033\",\n                \"r\": \"0xa7398e28ca9a56b423cab87aeb3612378bac9c5684aaf778a78943f2637fd731\",\n                \"s\": \"0x583511da658f564253c8c0f9ee1820ef370f23556be504b304ac1292f869d9a0\",\n                \"yParity\": \"0x0\",\n                \"v\": \"0x0\",\n                \"hash\": \"0x9e4846328caa09cbe8086d11b7e115adf70390e79ff203d8e5f37785c2a890be\"\n              },\n              \"impersonated_sender\": null\n            }\n          ],\n          \"ommers\": []\n        }\n      ],\n      \"transactions\": [\n        {\n          \"info\": {\n            \"transaction_hash\": \"0x9e4846328caa09cbe8086d11b7e115adf70390e79ff203d8e5f37785c2a890be\",\n            \"transaction_index\": 0,\n            \"from\": \"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266\",\n            \"to\": null,\n            \"contract_address\": \"0x5fbdb2315678afecb367f032d93f642f64180aa3\",\n            \"traces\": [\n              {\n                \"parent\": null,\n                \"children\": [],\n                \"idx\": 0,\n                \"trace\": {\n                  \"depth\": 0,\n                  \"success\": true,\n                  \"caller\": \"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266\",\n                  \"address\": \"0x5fbdb2315678afecb367f032d93f642f64180aa3\",\n                  \"maybe_precompile\": false,\n                  \"selfdestruct_address\": null,\n                  \"selfdestruct_refund_target\": null,\n                  \"selfdestruct_transferred_value\": null,\n                  \"kind\": \"CREATE\",\n                  \"value\": \"0x0\",\n                  \"data\": \"0x6080604052348015600e575f5ffd5b506101e18061001c5f395ff3fe608060405234801561000f575f5ffd5b506004361061003f575f3560e01c80633fb5c1cb146100435780638381f58a1461005f578063d09de08a1461007d575b5f5ffd5b61005d600480360381019061005891906100e4565b610087565b005b610067610090565b604051610074919061011e565b60405180910390f35b610085610095565b005b805f8190555050565b5f5481565b5f5f8154809291906100a690610164565b9190505550565b5f5ffd5b5f819050919050565b6100c3816100b1565b81146100cd575f5ffd5b50565b5f813590506100de816100ba565b92915050565b5f602082840312156100f9576100f86100ad565b5b5f610106848285016100d0565b91505092915050565b610118816100b1565b82525050565b5f6020820190506101315f83018461010f565b92915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f61016e826100b1565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036101a05761019f610137565b5b60018201905091905056fea264697066735822122040b6a3cd3ec8f890002f39a8719ebee029ba9bac3d7fa9d581d4712cfe9ffec264736f6c634300081e0033\",\n                  \"output\": \"0x608060405234801561000f575f5ffd5b506004361061003f575f3560e01c80633fb5c1cb146100435780638381f58a1461005f578063d09de08a1461007d575b5f5ffd5b61005d600480360381019061005891906100e4565b610087565b005b610067610090565b604051610074919061011e565b60405180910390f35b610085610095565b005b805f8190555050565b5f5481565b5f5f8154809291906100a690610164565b9190505550565b5f5ffd5b5f819050919050565b6100c3816100b1565b81146100cd575f5ffd5b50565b5f813590506100de816100ba565b92915050565b5f602082840312156100f9576100f86100ad565b5b5f610106848285016100d0565b91505092915050565b610118816100b1565b82525050565b5f6020820190506101315f83018461010f565b92915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f61016e826100b1565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036101a05761019f610137565b5b60018201905091905056fea264697066735822122040b6a3cd3ec8f890002f39a8719ebee029ba9bac3d7fa9d581d4712cfe9ffec264736f6c634300081e0033\",\n                  \"gas_used\": 96345,\n                  \"gas_limit\": 143385,\n                  \"gas_refund_counter\": 0,\n                  \"status\": \"Return\",\n                  \"steps\": [],\n                  \"decoded\": null\n                },\n                \"logs\": [],\n                \"ordering\": []\n              }\n            ],\n            \"exit\": \"Return\",\n            \"out\": \"0x608060405234801561000f575f5ffd5b506004361061003f575f3560e01c80633fb5c1cb146100435780638381f58a1461005f578063d09de08a1461007d575b5f5ffd5b61005d600480360381019061005891906100e4565b610087565b005b610067610090565b604051610074919061011e565b60405180910390f35b610085610095565b005b805f8190555050565b5f5481565b5f5f8154809291906100a690610164565b9190505550565b5f5ffd5b5f819050919050565b6100c3816100b1565b81146100cd575f5ffd5b50565b5f813590506100de816100ba565b92915050565b5f602082840312156100f9576100f86100ad565b5b5f610106848285016100d0565b91505092915050565b610118816100b1565b82525050565b5f6020820190506101315f83018461010f565b92915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f61016e826100b1565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036101a05761019f610137565b5b60018201905091905056fea264697066735822122040b6a3cd3ec8f890002f39a8719ebee029ba9bac3d7fa9d581d4712cfe9ffec264736f6c634300081e0033\",\n            \"nonce\": 0,\n            \"gas_used\": 156801\n          },\n          \"receipt\": {\n            \"type\": \"0x2\",\n            \"status\": \"0x1\",\n            \"cumulativeGasUsed\": \"0x26481\",\n            \"logs\": [],\n            \"logsBloom\": \"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\"\n          },\n          \"block_hash\": \"0x313ea0d32d662434a55a20d7c58544e6baaea421b6eccf4b68392dec2a76d771\",\n          \"block_number\": 1\n        }\n      ],\n      \"historical_states\": null\n    });\n\n    // Write the old state to file.\n    foundry_common::fs::write_json_file(&old_state_file, &old_state_json).unwrap();\n\n    // Test deserializing the old state dump directly.\n    let deserialized_state: SerializableState = serde_json::from_value(old_state_json).unwrap();\n\n    // Verify the old state was loaded correctly with `coinbase` to `beneficiary` conversion.\n    let block_env = deserialized_state.block.unwrap();\n    assert_eq!(block_env.number, U256::from(1));\n    assert_eq!(block_env.beneficiary, address!(\"0000000000000000000000000000000000000001\"));\n    assert_eq!(block_env.gas_limit, 0x1c9c380);\n    assert_eq!(block_env.basefee, 0x3b9aca00);\n\n    // Verify best_block_number hex string parsing.\n    assert_eq!(deserialized_state.best_block_number, Some(1));\n\n    // Verify account data was preserved.\n    assert_eq!(deserialized_state.accounts.len(), 13);\n\n    // Test specific accounts from the old dump.\n    let deployer_addr = \"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266\".parse().unwrap();\n    let deployer_account = deserialized_state.accounts.get(&deployer_addr).unwrap();\n    assert_eq!(deployer_account.nonce, 1);\n    assert_eq!(deployer_account.balance, U256::from_str(\"0x21e19e03b1e9e55d17f\").unwrap());\n\n    // Test contract account.\n    let contract_addr = \"0x5fbdb2315678afecb367f032d93f642f64180aa3\".parse().unwrap();\n    let contract_account = deserialized_state.accounts.get(&contract_addr).unwrap();\n    assert_eq!(contract_account.nonce, 1);\n    assert_eq!(contract_account.balance, U256::ZERO);\n    assert!(!contract_account.code.is_empty());\n\n    // Verify blocks and transactions are preserved.\n    assert_eq!(deserialized_state.blocks.len(), 2);\n    assert_eq!(deserialized_state.transactions.len(), 1);\n\n    // Test that Anvil can load this old state dump.\n    let (api, _handle) = spawn(NodeConfig::test().with_init_state_path(&old_state_file)).await;\n\n    // Verify the state was loaded correctly.\n    let block_number = api.block_number().unwrap();\n    assert_eq!(block_number, U256::from(1));\n\n    // Verify account balances are preserved.\n    let provider = _handle.http_provider();\n    let deployer_balance = provider.get_balance(deployer_addr).await.unwrap();\n    assert_eq!(deployer_balance, U256::from_str(\"0x21e19e03b1e9e55d17f\").unwrap());\n    let contract_balance = provider.get_balance(contract_addr).await.unwrap();\n    assert_eq!(contract_balance, U256::ZERO);\n\n    // Verify contract code is preserved.\n    let contract_code = provider.get_code_at(contract_addr).await.unwrap();\n    assert!(!contract_code.is_empty());\n}\n"
  },
  {
    "path": "crates/anvil/tests/it/traces.rs",
    "content": "use std::collections::HashMap;\n\nuse crate::{\n    abi::{Multicall, SimpleStorage},\n    fork::fork_config,\n    utils::http_provider_with_signer,\n};\nuse alloy_eips::BlockId;\nuse alloy_network::{EthereumWallet, TransactionBuilder};\nuse alloy_primitives::{\n    Address, Bytes, U256,\n    hex::{self, FromHex},\n};\nuse alloy_provider::{\n    Provider,\n    ext::{DebugApi, TraceApi},\n};\nuse alloy_rpc_types::{\n    TransactionRequest,\n    state::StateOverride,\n    trace::{\n        filter::{TraceFilter, TraceFilterMode},\n        geth::{\n            AccountState, CallConfig, GethDebugBuiltInTracerType, GethDebugTracerType,\n            GethDebugTracingCallOptions, GethDebugTracingOptions, GethTrace, PreStateConfig,\n            PreStateFrame,\n        },\n        parity::{Action, ChangedType, LocalizedTransactionTrace, TraceType},\n    },\n};\nuse alloy_serde::WithOtherFields;\nuse alloy_sol_types::sol;\nuse anvil::{NodeConfig, spawn};\nuse foundry_evm::hardfork::EthereumHardfork;\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_get_transfer_parity_traces() {\n    let (_api, handle) = spawn(NodeConfig::test()).await;\n    let provider = handle.ws_provider();\n\n    let accounts = handle.dev_wallets().collect::<Vec<_>>();\n    let from = accounts[0].address();\n    let to = accounts[1].address();\n    let amount = handle.genesis_balance().checked_div(U256::from(2u64)).unwrap();\n    // specify the `from` field so that the client knows which account to use\n    let tx = TransactionRequest::default().to(to).value(amount).from(from);\n    let tx = WithOtherFields::new(tx);\n\n    // broadcast it via the eth_sendTransaction API\n    let tx = provider.send_transaction(tx).await.unwrap().get_receipt().await.unwrap();\n\n    let traces = provider.trace_transaction(tx.transaction_hash).await.unwrap();\n    assert!(!traces.is_empty());\n\n    match traces[0].trace.action {\n        Action::Call(ref call) => {\n            assert_eq!(call.from, from);\n            assert_eq!(call.to, to);\n            assert_eq!(call.value, amount);\n        }\n        _ => unreachable!(\"unexpected action\"),\n    }\n\n    let num = provider.get_block_number().await.unwrap();\n    let block_traces = provider.trace_block(num.into()).await.unwrap();\n    assert!(!block_traces.is_empty());\n\n    assert_eq!(traces, block_traces);\n}\n\nsol!(\n    #[sol(rpc, bytecode = \"0x6080604052348015600f57600080fd5b50336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060a48061005e6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c806375fc8e3c14602d575b600080fd5b60336035565b005b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16fffea26469706673582212205006867290df97c54f2df1cb94fc081197ab670e2adf5353071d2ecce1d694b864736f6c634300080d0033\")]\n    contract SuicideContract {\n        address payable private owner;\n        constructor() public {\n            owner = payable(msg.sender);\n        }\n        function goodbye() public {\n            selfdestruct(owner);\n        }\n    }\n);\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_parity_suicide_trace() {\n    let (_api, handle) =\n        spawn(NodeConfig::test().with_hardfork(Some(EthereumHardfork::Shanghai.into()))).await;\n    let provider = handle.ws_provider();\n    let wallets = handle.dev_wallets().collect::<Vec<_>>();\n    let owner = wallets[0].address();\n    let destructor = wallets[1].address();\n\n    let contract_addr =\n        SuicideContract::deploy_builder(provider.clone()).from(owner).deploy().await.unwrap();\n    let contract = SuicideContract::new(contract_addr, provider.clone());\n    let call = contract.goodbye().from(destructor);\n    let call = call.send().await.unwrap();\n    let tx = call.get_receipt().await.unwrap();\n\n    let traces = handle.http_provider().trace_transaction(tx.transaction_hash).await.unwrap();\n    assert!(!traces.is_empty());\n    assert!(traces[1].trace.action.is_selfdestruct());\n}\n\nsol!(\n    #[sol(rpc, bytecode = \"0x6080604052348015600f57600080fd5b50336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060a48061005e6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c806375fc8e3c14602d575b600080fd5b60336035565b005b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16fffea26469706673582212205006867290df97c54f2df1cb94fc081197ab670e2adf5353071d2ecce1d694b864736f6c634300080d0033\")]\n    contract DebugTraceContract {\n        address payable private owner;\n        constructor() public {\n            owner = payable(msg.sender);\n        }\n        function goodbye() public {\n            selfdestruct(owner);\n        }\n    }\n);\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_transfer_debug_trace_call() {\n    let (_api, handle) = spawn(NodeConfig::test()).await;\n    let wallets = handle.dev_wallets().collect::<Vec<_>>();\n    let deployer: EthereumWallet = wallets[0].clone().into();\n    let provider = http_provider_with_signer(&handle.http_endpoint(), deployer);\n\n    let contract_addr = DebugTraceContract::deploy_builder(provider.clone())\n        .from(wallets[0].clone().address())\n        .deploy()\n        .await\n        .unwrap();\n\n    let caller: EthereumWallet = wallets[1].clone().into();\n    let caller_provider = http_provider_with_signer(&handle.http_endpoint(), caller);\n    let contract = DebugTraceContract::new(contract_addr, caller_provider);\n\n    let call = contract.goodbye().from(wallets[1].address());\n    let calldata = call.calldata().to_owned();\n\n    let tx = TransactionRequest::default()\n        .from(wallets[1].address())\n        .to(*contract.address())\n        .with_input(calldata);\n\n    let traces = handle\n        .http_provider()\n        .debug_trace_call(\n            WithOtherFields::new(tx),\n            BlockId::latest(),\n            GethDebugTracingCallOptions::default(),\n        )\n        .await\n        .unwrap();\n\n    match traces {\n        GethTrace::Default(default_frame) => {\n            assert!(!default_frame.failed);\n        }\n        _ => {\n            unreachable!()\n        }\n    }\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_call_tracer_debug_trace_call() {\n    let (_api, handle) = spawn(NodeConfig::test()).await;\n    let wallets = handle.dev_wallets().collect::<Vec<_>>();\n    let deployer: EthereumWallet = wallets[0].clone().into();\n    let provider = http_provider_with_signer(&handle.http_endpoint(), deployer);\n\n    let multicall_contract = Multicall::deploy(&provider).await.unwrap();\n\n    let simple_storage_contract =\n        SimpleStorage::deploy(&provider, \"init value\".to_string()).await.unwrap();\n\n    let set_value = simple_storage_contract.setValue(\"bar\".to_string());\n    let set_value_calldata = set_value.calldata();\n\n    let internal_call_tx_builder = multicall_contract.aggregate(vec![Multicall::Call {\n        target: *simple_storage_contract.address(),\n        callData: set_value_calldata.to_owned(),\n    }]);\n\n    let internal_call_tx_calldata = internal_call_tx_builder.calldata().to_owned();\n\n    // calling SimpleStorage contract through Multicall should result in an internal call\n    let internal_call_tx = TransactionRequest::default()\n        .from(wallets[1].address())\n        .to(*multicall_contract.address())\n        .with_input(internal_call_tx_calldata);\n\n    let internal_call_tx_traces = handle\n        .http_provider()\n        .debug_trace_call(\n            WithOtherFields::new(internal_call_tx.clone()),\n            BlockId::latest(),\n            GethDebugTracingCallOptions::default().with_tracing_options(\n                GethDebugTracingOptions::default()\n                    .with_tracer(GethDebugTracerType::from(GethDebugBuiltInTracerType::CallTracer))\n                    .with_call_config(CallConfig::default().with_log()),\n            ),\n        )\n        .await\n        .unwrap();\n\n    match internal_call_tx_traces {\n        GethTrace::CallTracer(call_frame) => {\n            assert!(call_frame.calls.len() == 1);\n            assert!(\n                call_frame.calls.first().unwrap().to.unwrap() == *simple_storage_contract.address()\n            );\n            assert!(call_frame.calls.first().unwrap().logs.len() == 1);\n        }\n        _ => {\n            unreachable!()\n        }\n    }\n\n    // only_top_call option - should not return any internal calls\n    let internal_call_only_top_call_tx_traces = handle\n        .http_provider()\n        .debug_trace_call(\n            WithOtherFields::new(internal_call_tx.clone()),\n            BlockId::latest(),\n            GethDebugTracingCallOptions::default().with_tracing_options(\n                GethDebugTracingOptions::default()\n                    .with_tracer(GethDebugTracerType::from(GethDebugBuiltInTracerType::CallTracer))\n                    .with_call_config(CallConfig::default().with_log().only_top_call()),\n            ),\n        )\n        .await\n        .unwrap();\n\n    match internal_call_only_top_call_tx_traces {\n        GethTrace::CallTracer(call_frame) => {\n            assert!(call_frame.calls.is_empty());\n        }\n        _ => {\n            unreachable!()\n        }\n    }\n\n    // directly calling the SimpleStorage contract should not result in any internal calls\n    let direct_call_tx = TransactionRequest::default()\n        .from(wallets[1].address())\n        .to(*simple_storage_contract.address())\n        .with_input(set_value_calldata.to_owned());\n\n    let direct_call_tx_traces = handle\n        .http_provider()\n        .debug_trace_call(\n            WithOtherFields::new(direct_call_tx),\n            BlockId::latest(),\n            GethDebugTracingCallOptions::default().with_tracing_options(\n                GethDebugTracingOptions::default()\n                    .with_tracer(GethDebugTracerType::from(GethDebugBuiltInTracerType::CallTracer))\n                    .with_call_config(CallConfig::default().with_log()),\n            ),\n        )\n        .await\n        .unwrap();\n\n    match direct_call_tx_traces {\n        GethTrace::CallTracer(call_frame) => {\n            assert!(call_frame.calls.is_empty());\n            assert!(call_frame.to.unwrap() == *simple_storage_contract.address());\n            assert!(call_frame.logs.len() == 1);\n        }\n        _ => {\n            unreachable!()\n        }\n    }\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_debug_trace_call_state_override() {\n    let (_api, handle) = spawn(NodeConfig::test()).await;\n    let wallets = handle.dev_wallets().collect::<Vec<_>>();\n\n    let tx = TransactionRequest::default()\n        .from(wallets[1].address())\n        .to(\"0x1234567890123456789012345678901234567890\".parse().unwrap());\n\n    let override_json = r#\"{\n            \"0x1234567890123456789012345678901234567890\": {\n                \"balance\": \"0x01\",\n                \"code\": \"0x30315f5260205ff3\"\n            }\n        }\"#;\n\n    let state_override: StateOverride = serde_json::from_str(override_json).unwrap();\n\n    let tx_traces = handle\n        .http_provider()\n        .debug_trace_call(\n            WithOtherFields::new(tx.clone()),\n            BlockId::latest(),\n            GethDebugTracingCallOptions::default()\n                .with_tracing_options(GethDebugTracingOptions::default())\n                .with_state_overrides(state_override),\n        )\n        .await\n        .unwrap();\n\n    match tx_traces {\n        GethTrace::Default(trace_res) => {\n            assert_eq!(\n                trace_res.return_value,\n                Bytes::from_hex(\"0000000000000000000000000000000000000000000000000000000000000001\")\n                    .unwrap()\n            );\n        }\n        _ => {\n            unreachable!()\n        }\n    }\n}\n\n// <https://github.com/foundry-rs/foundry/issues/2656>\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_trace_address_fork() {\n    let (api, handle) = spawn(fork_config().with_fork_block_number(Some(15291050u64))).await;\n    let provider = handle.http_provider();\n\n    let input = hex::decode(\"43bcfab60000000000000000000000006b175474e89094c44da98b954eedeac495271d0f0000000000000000000000000000000000000000000000e0bd811c8769a824b00000000000000000000000000000000000000000000000e0ae9925047d8440b60000000000000000000000002e4777139254ff76db957e284b186a4507ff8c67\").unwrap();\n\n    let from: Address = \"0x2e4777139254ff76db957e284b186a4507ff8c67\".parse().unwrap();\n    let to: Address = \"0xe2f2a5c287993345a840db3b0845fbc70f5935a5\".parse().unwrap();\n    let tx = TransactionRequest::default()\n        .to(to)\n        .from(from)\n        .with_input::<Bytes>(input.into())\n        .with_gas_limit(300_000);\n\n    let tx = WithOtherFields::new(tx);\n    api.anvil_impersonate_account(from).await.unwrap();\n\n    let tx = provider.send_transaction(tx).await.unwrap().get_receipt().await.unwrap();\n\n    let traces = provider.trace_transaction(tx.transaction_hash).await.unwrap();\n    assert!(!traces.is_empty());\n    match traces[0].trace.action {\n        Action::Call(ref call) => {\n            assert_eq!(call.from, from);\n            assert_eq!(call.to, to);\n        }\n        _ => unreachable!(\"unexpected action\"),\n    }\n\n    let json = serde_json::json!([\n        {\n            \"action\": {\n                \"callType\": \"call\",\n                \"from\": \"0x2e4777139254ff76db957e284b186a4507ff8c67\",\n                \"gas\": \"0x262b3\",\n                \"input\": \"0x43bcfab60000000000000000000000006b175474e89094c44da98b954eedeac495271d0f0000000000000000000000000000000000000000000000e0bd811c8769a824b00000000000000000000000000000000000000000000000e0ae9925047d8440b60000000000000000000000002e4777139254ff76db957e284b186a4507ff8c67\",\n                \"to\": \"0xe2f2a5c287993345a840db3b0845fbc70f5935a5\",\n                \"value\": \"0x0\"\n            },\n            \"blockHash\": \"0xa47c8f1d8c284cb614e9c8e10d260b33eae16b1957a83141191bc335838d7e29\",\n            \"blockNumber\": 15291051,\n            \"result\": {\n                \"gasUsed\": \"0x2131b\",\n                \"output\": \"0x0000000000000000000000000000000000000000000000e0e82ca52ec6e6a4d3\"\n            },\n            \"subtraces\": 1,\n            \"traceAddress\": [],\n            \"transactionHash\": \"0x3255cce7312e9c4470e1a1883be13718e971f6faafb96199b8bd75e5b7c39e3a\",\n            \"transactionPosition\": 19,\n            \"type\": \"call\"\n        },\n        {\n            \"action\": {\n                \"callType\": \"delegatecall\",\n                \"from\": \"0xe2f2a5c287993345a840db3b0845fbc70f5935a5\",\n                \"gas\": \"0x23d88\",\n                \"input\": \"0x43bcfab60000000000000000000000006b175474e89094c44da98b954eedeac495271d0f0000000000000000000000000000000000000000000000e0bd811c8769a824b00000000000000000000000000000000000000000000000e0ae9925047d8440b60000000000000000000000002e4777139254ff76db957e284b186a4507ff8c67\",\n                \"to\": \"0x15b2838cd28cc353afbe59385db3f366d8945aee\",\n                \"value\": \"0x0\"\n            },\n            \"blockHash\": \"0xa47c8f1d8c284cb614e9c8e10d260b33eae16b1957a83141191bc335838d7e29\",\n            \"blockNumber\": 15291051,\n            \"result\": {\n                \"gasUsed\": \"0x1f6e1\",\n                \"output\": \"0x0000000000000000000000000000000000000000000000e0e82ca52ec6e6a4d3\"\n            },\n            \"subtraces\": 2,\n            \"traceAddress\": [0],\n            \"transactionHash\": \"0x3255cce7312e9c4470e1a1883be13718e971f6faafb96199b8bd75e5b7c39e3a\",\n            \"transactionPosition\": 19,\n            \"type\": \"call\"\n        },\n        {\n            \"action\": {\n                \"callType\": \"staticcall\",\n                \"from\": \"0xe2f2a5c287993345a840db3b0845fbc70f5935a5\",\n                \"gas\": \"0x192ed\",\n                \"input\": \"0x50494dc000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000e0b1ff65617f654b2f00000000000000000000000000000000000000000000000000000000000061a800000000000000000000000000000000000000000000000000b1a2bc2ec5000000000000000000000000000000000000000000000000000006f05b59d3b2000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000000000000000000000000414ec22973db48fd3a3370000000000000000000000000000000000000000000000056bc75e2d6310000000000000000000000000000000000000000000000000000000000a7314a9ba5c0000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000000000000000000000095f783edc5a5dabcb4ba70000000000000000000000000000000000000000000000056bc75e2d6310000000000000000000000000000000000000000000000000000000000a3f42df4dab\",\n                \"to\": \"0xca480d596e6717c95a62a4dc1bd4fbd7b7e7d705\",\n                \"value\": \"0x0\"\n            },\n            \"blockHash\": \"0xa47c8f1d8c284cb614e9c8e10d260b33eae16b1957a83141191bc335838d7e29\",\n            \"blockNumber\": 15291051,\n            \"result\": {\n                \"gasUsed\": \"0x661a\",\n                \"output\": \"0x0000000000000000000000000000000000000000000000e0e82ca52ec6e6a4d3\"\n            },\n            \"subtraces\": 0,\n            \"traceAddress\": [0, 0],\n            \"transactionHash\": \"0x3255cce7312e9c4470e1a1883be13718e971f6faafb96199b8bd75e5b7c39e3a\",\n            \"transactionPosition\": 19,\n            \"type\": \"call\"\n        },\n        {\n            \"action\": {\n                \"callType\": \"delegatecall\",\n                \"from\": \"0xe2f2a5c287993345a840db3b0845fbc70f5935a5\",\n                \"gas\": \"0xd2dc\",\n                \"input\": \"0x4e331a540000000000000000000000000000000000000000000000e0e82ca52ec6e6a4d30000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000a2a3cae63476891ab2d640d9a5a800755ee79d6e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000000000000000000000095f783edc5a5dabcb4ba70000000000000000000000002e4777139254ff76db957e284b186a4507ff8c6700000000000000000000000000000000000000000000f7be2b91f8a2e2df496e\",\n                \"to\": \"0x1e91f826fa8aa4fa4d3f595898af3a64dd188848\",\n                \"value\": \"0x0\"\n            },\n            \"blockHash\": \"0xa47c8f1d8c284cb614e9c8e10d260b33eae16b1957a83141191bc335838d7e29\",\n            \"blockNumber\": 15291051,\n            \"result\": {\n                \"gasUsed\": \"0x7617\",\n                \"output\": \"0x\"\n            },\n            \"subtraces\": 2,\n            \"traceAddress\": [0, 1],\n            \"transactionHash\": \"0x3255cce7312e9c4470e1a1883be13718e971f6faafb96199b8bd75e5b7c39e3a\",\n            \"transactionPosition\": 19,\n            \"type\": \"call\"\n        },\n        {\n            \"action\": {\n                \"callType\": \"staticcall\",\n                \"from\": \"0xe2f2a5c287993345a840db3b0845fbc70f5935a5\",\n                \"gas\": \"0xbf50\",\n                \"input\": \"0x70a08231000000000000000000000000a2a3cae63476891ab2d640d9a5a800755ee79d6e\",\n                \"to\": \"0x6b175474e89094c44da98b954eedeac495271d0f\",\n                \"value\": \"0x0\"\n            },\n            \"blockHash\": \"0xa47c8f1d8c284cb614e9c8e10d260b33eae16b1957a83141191bc335838d7e29\",\n            \"blockNumber\": 15291051,\n            \"result\": {\n                \"gasUsed\": \"0xa2a\",\n                \"output\": \"0x0000000000000000000000000000000000000000000020fe99f8898600d94750\"\n            },\n            \"subtraces\": 0,\n            \"traceAddress\": [0, 1, 0],\n            \"transactionHash\": \"0x3255cce7312e9c4470e1a1883be13718e971f6faafb96199b8bd75e5b7c39e3a\",\n            \"transactionPosition\": 19,\n            \"type\": \"call\"\n        },\n        {\n            \"action\": {\n                \"callType\": \"call\",\n                \"from\": \"0xe2f2a5c287993345a840db3b0845fbc70f5935a5\",\n                \"gas\": \"0xa92a\",\n                \"input\": \"0xa4e285950000000000000000000000002e4777139254ff76db957e284b186a4507ff8c670000000000000000000000006b175474e89094c44da98b954eedeac495271d0f0000000000000000000000000000000000000000000000e0e82ca52ec6e6a4d3\",\n                \"to\": \"0xa2a3cae63476891ab2d640d9a5a800755ee79d6e\",\n                \"value\": \"0x0\"\n            },\n            \"blockHash\": \"0xa47c8f1d8c284cb614e9c8e10d260b33eae16b1957a83141191bc335838d7e29\",\n            \"blockNumber\": 15291051,\n            \"result\": {\n                \"gasUsed\": \"0x4ed3\",\n                \"output\": \"0x\"\n            },\n            \"subtraces\": 1,\n            \"traceAddress\": [0, 1, 1],\n            \"transactionHash\": \"0x3255cce7312e9c4470e1a1883be13718e971f6faafb96199b8bd75e5b7c39e3a\",\n            \"transactionPosition\": 19,\n            \"type\": \"call\"\n        },\n        {\n            \"action\": {\n                \"callType\": \"call\",\n                \"from\": \"0xa2a3cae63476891ab2d640d9a5a800755ee79d6e\",\n                \"gas\": \"0x8c90\",\n                \"input\": \"0xa9059cbb0000000000000000000000002e4777139254ff76db957e284b186a4507ff8c670000000000000000000000000000000000000000000000e0e82ca52ec6e6a4d3\",\n                \"to\": \"0x6b175474e89094c44da98b954eedeac495271d0f\",\n                \"value\": \"0x0\"\n            },\n            \"blockHash\": \"0xa47c8f1d8c284cb614e9c8e10d260b33eae16b1957a83141191bc335838d7e29\",\n            \"blockNumber\": 15291051,\n            \"result\": {\n                \"gasUsed\": \"0x2b42\",\n                \"output\": \"0x0000000000000000000000000000000000000000000000000000000000000001\"\n            },\n            \"subtraces\": 0,\n            \"traceAddress\": [0, 1, 1, 0],\n            \"transactionHash\": \"0x3255cce7312e9c4470e1a1883be13718e971f6faafb96199b8bd75e5b7c39e3a\",\n            \"transactionPosition\": 19,\n            \"type\": \"call\"\n        }\n    ]);\n\n    let expected_traces: Vec<LocalizedTransactionTrace> = serde_json::from_value(json).unwrap();\n\n    // test matching traceAddress\n    traces.into_iter().zip(expected_traces).for_each(|(a, b)| {\n        assert_eq!(a.trace.trace_address, b.trace.trace_address);\n        assert_eq!(a.trace.subtraces, b.trace.subtraces);\n        match (a.trace.action, b.trace.action) {\n            (Action::Call(a), Action::Call(b)) => {\n                assert_eq!(a.from, b.from);\n                assert_eq!(a.to, b.to);\n            }\n            _ => unreachable!(\"unexpected action\"),\n        }\n    })\n}\n\n// <https://github.com/foundry-rs/foundry/issues/2705>\n// <https://etherscan.io/tx/0x2d951c5c95d374263ca99ad9c20c9797fc714330a8037429a3aa4c83d456f845>\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_trace_address_fork2() {\n    let (api, handle) = spawn(fork_config().with_fork_block_number(Some(15314401u64))).await;\n    let provider = handle.http_provider();\n\n    let input = hex::decode(\"30000003000000000000000000000000adda1059a6c6c102b0fa562b9bb2cb9a0de5b1f4000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a300000004fffffffffffffffffffffffffffffffffffffffffffff679dc91ecfe150fb980c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2f4d2888d29d722226fafa5d9b24f9164c092421e000bb8000000000000004319b52bf08b65295d49117e790000000000000000000000000000000000000000000000008b6d9e8818d6141f000000000000000000000000000000000000000000000000000000086a23af210000000000000000000000000000000000000000000000000000000000\").unwrap();\n\n    let from: Address = \"0xa009fa1ac416ec02f6f902a3a4a584b092ae6123\".parse().unwrap();\n    let to: Address = \"0x99999999d116ffa7d76590de2f427d8e15aeb0b8\".parse().unwrap();\n    let tx = TransactionRequest::default()\n        .to(to)\n        .from(from)\n        .with_input::<Bytes>(input.into())\n        .with_gas_limit(350_000);\n\n    let tx = WithOtherFields::new(tx);\n    api.anvil_impersonate_account(from).await.unwrap();\n\n    let tx = provider.send_transaction(tx).await.unwrap().get_receipt().await.unwrap();\n    let status = tx.inner.inner.inner.receipt.status.coerce_status();\n    assert!(status);\n\n    let traces = provider.trace_transaction(tx.transaction_hash).await.unwrap();\n\n    assert!(!traces.is_empty());\n    match traces[0].trace.action {\n        Action::Call(ref call) => {\n            assert_eq!(call.from, from);\n            assert_eq!(call.to, to);\n        }\n        _ => unreachable!(\"unexpected action\"),\n    }\n\n    let json = serde_json::json!([\n        {\n            \"action\": {\n                \"from\": \"0xa009fa1ac416ec02f6f902a3a4a584b092ae6123\",\n                \"callType\": \"call\",\n                \"gas\": \"0x4fabc\",\n                \"input\": \"0x30000003000000000000000000000000adda1059a6c6c102b0fa562b9bb2cb9a0de5b1f4000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a300000004fffffffffffffffffffffffffffffffffffffffffffff679dc91ecfe150fb980c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2f4d2888d29d722226fafa5d9b24f9164c092421e000bb8000000000000004319b52bf08b65295d49117e790000000000000000000000000000000000000000000000008b6d9e8818d6141f000000000000000000000000000000000000000000000000000000086a23af210000000000000000000000000000000000000000000000000000000000\",\n                \"to\": \"0x99999999d116ffa7d76590de2f427d8e15aeb0b8\",\n                \"value\": \"0x0\"\n            },\n            \"blockHash\": \"0xf689ba7749648b8c5c8f5eedd73001033f0aed7ea50b7c81048ad1533b8d3d73\",\n            \"blockNumber\": 15314402,\n            \"result\": {\n                \"gasUsed\": \"0x1d51b\",\n                \"output\": \"0x\"\n            },\n            \"subtraces\": 1,\n            \"traceAddress\": [],\n            \"transactionHash\": \"0x2d951c5c95d374263ca99ad9c20c9797fc714330a8037429a3aa4c83d456f845\",\n            \"transactionPosition\": 289,\n            \"type\": \"call\"\n        },\n        {\n            \"action\": {\n                \"from\": \"0x99999999d116ffa7d76590de2f427d8e15aeb0b8\",\n                \"callType\": \"delegatecall\",\n                \"gas\": \"0x4d594\",\n                \"input\": \"0x00000004fffffffffffffffffffffffffffffffffffffffffffff679dc91ecfe150fb980c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2f4d2888d29d722226fafa5d9b24f9164c092421e000bb8000000000000004319b52bf08b65295d49117e790000000000000000000000000000000000000000000000008b6d9e8818d6141f000000000000000000000000000000000000000000000000000000086a23af21\",\n                \"to\": \"0xadda1059a6c6c102b0fa562b9bb2cb9a0de5b1f4\",\n                \"value\": \"0x0\"\n            },\n            \"blockHash\": \"0xf689ba7749648b8c5c8f5eedd73001033f0aed7ea50b7c81048ad1533b8d3d73\",\n            \"blockNumber\": 15314402,\n            \"result\": {\n                \"gasUsed\": \"0x1c35f\",\n                \"output\": \"0x\"\n            },\n            \"subtraces\": 3,\n            \"traceAddress\": [0],\n            \"transactionHash\": \"0x2d951c5c95d374263ca99ad9c20c9797fc714330a8037429a3aa4c83d456f845\",\n            \"transactionPosition\": 289,\n            \"type\": \"call\"\n        },\n        {\n            \"action\": {\n                \"from\": \"0x99999999d116ffa7d76590de2f427d8e15aeb0b8\",\n                \"callType\": \"call\",\n                \"gas\": \"0x4b6d6\",\n                \"input\": \"0x16b2da82000000000000000000000000000000000000000000000000000000086a23af21\",\n                \"to\": \"0xd1663cfb8ceaf22039ebb98914a8c98264643710\",\n                \"value\": \"0x0\"\n            },\n            \"blockHash\": \"0xf689ba7749648b8c5c8f5eedd73001033f0aed7ea50b7c81048ad1533b8d3d73\",\n            \"blockNumber\": 15314402,\n            \"result\": {\n                \"gasUsed\": \"0xd6d\",\n                \"output\": \"0x0000000000000000000000000000000000000000000000000000000000000000\"\n            },\n            \"subtraces\": 0,\n            \"traceAddress\": [0, 0],\n            \"transactionHash\": \"0x2d951c5c95d374263ca99ad9c20c9797fc714330a8037429a3aa4c83d456f845\",\n            \"transactionPosition\": 289,\n            \"type\": \"call\"\n        },\n        {\n            \"action\": {\n                \"from\": \"0x99999999d116ffa7d76590de2f427d8e15aeb0b8\",\n                \"callType\": \"staticcall\",\n                \"gas\": \"0x49c35\",\n                \"input\": \"0x3850c7bd\",\n                \"to\": \"0x4b5ab61593a2401b1075b90c04cbcdd3f87ce011\",\n                \"value\": \"0x0\"\n            },\n            \"blockHash\": \"0xf689ba7749648b8c5c8f5eedd73001033f0aed7ea50b7c81048ad1533b8d3d73\",\n            \"blockNumber\": 15314402,\n            \"result\": {\n                \"gasUsed\": \"0xa88\",\n                \"output\": \"0x000000000000000000000000000000000000004319b52bf08b65295d49117e7900000000000000000000000000000000000000000000000000000000000148a0000000000000000000000000000000000000000000000000000000000000010e000000000000000000000000000000000000000000000000000000000000012c000000000000000000000000000000000000000000000000000000000000012c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001\"\n            },\n            \"subtraces\": 0,\n            \"traceAddress\": [0, 1],\n            \"transactionHash\": \"0x2d951c5c95d374263ca99ad9c20c9797fc714330a8037429a3aa4c83d456f845\",\n            \"transactionPosition\": 289,\n            \"type\": \"call\"\n        },\n        {\n            \"action\": {\n                \"from\": \"0x99999999d116ffa7d76590de2f427d8e15aeb0b8\",\n                \"callType\": \"call\",\n                \"gas\": \"0x48d01\",\n                \"input\": \"0x128acb0800000000000000000000000099999999d116ffa7d76590de2f427d8e15aeb0b80000000000000000000000000000000000000000000000000000000000000001fffffffffffffffffffffffffffffffffffffffffffff679dc91ecfe150fb98000000000000000000000000000000000000000000000000000000001000276a400000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000002bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2f4d2888d29d722226fafa5d9b24f9164c092421e000bb8000000000000000000000000000000000000000000\",\n                \"to\": \"0x4b5ab61593a2401b1075b90c04cbcdd3f87ce011\",\n                \"value\": \"0x0\"\n            },\n            \"blockHash\": \"0xf689ba7749648b8c5c8f5eedd73001033f0aed7ea50b7c81048ad1533b8d3d73\",\n            \"blockNumber\": 15314402,\n            \"result\": {\n                \"gasUsed\": \"0x18c20\",\n                \"output\": \"0x0000000000000000000000000000000000000000000000008b5116525f9edc3efffffffffffffffffffffffffffffffffffffffffffff679dc91ecfe150fb980\"\n            },\n            \"subtraces\": 4,\n            \"traceAddress\": [0, 2],\n            \"transactionHash\": \"0x2d951c5c95d374263ca99ad9c20c9797fc714330a8037429a3aa4c83d456f845\",\n            \"transactionPosition\": 289,\n            \"type\": \"call\"\n        },\n        {\n            \"action\": {\n                \"from\": \"0x4b5ab61593a2401b1075b90c04cbcdd3f87ce011\",\n                \"callType\": \"call\",\n                \"gas\": \"0x3802a\",\n                \"input\": \"0xa9059cbb00000000000000000000000099999999d116ffa7d76590de2f427d8e15aeb0b8000000000000000000000000000000000000000000000986236e1301eaf04680\",\n                \"to\": \"0xf4d2888d29d722226fafa5d9b24f9164c092421e\",\n                \"value\": \"0x0\"\n            },\n            \"blockHash\": \"0xf689ba7749648b8c5c8f5eedd73001033f0aed7ea50b7c81048ad1533b8d3d73\",\n            \"blockNumber\": 15314402,\n            \"result\": {\n                \"gasUsed\": \"0x31b6\",\n                \"output\": \"0x0000000000000000000000000000000000000000000000000000000000000001\"\n            },\n            \"subtraces\": 0,\n            \"traceAddress\": [0, 2, 0],\n            \"transactionHash\": \"0x2d951c5c95d374263ca99ad9c20c9797fc714330a8037429a3aa4c83d456f845\",\n            \"transactionPosition\": 289,\n            \"type\": \"call\"\n        },\n        {\n            \"action\": {\n                \"from\": \"0x4b5ab61593a2401b1075b90c04cbcdd3f87ce011\",\n                \"callType\": \"staticcall\",\n                \"gas\": \"0x34237\",\n                \"input\": \"0x70a082310000000000000000000000004b5ab61593a2401b1075b90c04cbcdd3f87ce011\",\n                \"to\": \"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2\",\n                \"value\": \"0x0\"\n            },\n            \"blockHash\": \"0xf689ba7749648b8c5c8f5eedd73001033f0aed7ea50b7c81048ad1533b8d3d73\",\n            \"blockNumber\": 15314402,\n            \"result\": {\n                \"gasUsed\": \"0x9e6\",\n                \"output\": \"0x000000000000000000000000000000000000000000000091cda6c1ce33e53b89\"\n            },\n            \"subtraces\": 0,\n            \"traceAddress\": [0, 2, 1],\n            \"transactionHash\": \"0x2d951c5c95d374263ca99ad9c20c9797fc714330a8037429a3aa4c83d456f845\",\n            \"transactionPosition\": 289,\n            \"type\": \"call\"\n        },\n        {\n            \"action\": {\n                \"from\": \"0x4b5ab61593a2401b1075b90c04cbcdd3f87ce011\",\n                \"callType\": \"call\",\n                \"gas\": \"0x3357e\",\n                \"input\": \"0xfa461e330000000000000000000000000000000000000000000000008b5116525f9edc3efffffffffffffffffffffffffffffffffffffffffffff679dc91ecfe150fb9800000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000002bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2f4d2888d29d722226fafa5d9b24f9164c092421e000bb8000000000000000000000000000000000000000000\",\n                \"to\": \"0x99999999d116ffa7d76590de2f427d8e15aeb0b8\",\n                \"value\": \"0x0\"\n            },\n            \"blockHash\": \"0xf689ba7749648b8c5c8f5eedd73001033f0aed7ea50b7c81048ad1533b8d3d73\",\n            \"blockNumber\": 15314402,\n            \"result\": {\n                \"gasUsed\": \"0x2e8b\",\n                \"output\": \"0x\"\n            },\n            \"subtraces\": 1,\n            \"traceAddress\": [0, 2, 2],\n            \"transactionHash\": \"0x2d951c5c95d374263ca99ad9c20c9797fc714330a8037429a3aa4c83d456f845\",\n            \"transactionPosition\": 289,\n            \"type\": \"call\"\n        },\n        {\n            \"action\": {\n                \"from\": \"0x99999999d116ffa7d76590de2f427d8e15aeb0b8\",\n                \"callType\": \"call\",\n                \"gas\": \"0x324db\",\n                \"input\": \"0xa9059cbb0000000000000000000000004b5ab61593a2401b1075b90c04cbcdd3f87ce0110000000000000000000000000000000000000000000000008b5116525f9edc3e\",\n                \"to\": \"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2\",\n                \"value\": \"0x0\"\n            },\n            \"blockHash\": \"0xf689ba7749648b8c5c8f5eedd73001033f0aed7ea50b7c81048ad1533b8d3d73\",\n            \"blockNumber\": 15314402,\n            \"result\": {\n                \"gasUsed\": \"0x2a6e\",\n                \"output\": \"0x0000000000000000000000000000000000000000000000000000000000000001\"\n            },\n            \"subtraces\": 0,\n            \"traceAddress\": [0, 2, 2, 0],\n            \"transactionHash\": \"0x2d951c5c95d374263ca99ad9c20c9797fc714330a8037429a3aa4c83d456f845\",\n            \"transactionPosition\": 289,\n            \"type\": \"call\"\n        },\n        {\n            \"action\": {\n                \"from\": \"0x4b5ab61593a2401b1075b90c04cbcdd3f87ce011\",\n                \"callType\": \"staticcall\",\n                \"gas\": \"0x30535\",\n                \"input\": \"0x70a082310000000000000000000000004b5ab61593a2401b1075b90c04cbcdd3f87ce011\",\n                \"to\": \"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2\",\n                \"value\": \"0x0\"\n            },\n            \"blockHash\": \"0xf689ba7749648b8c5c8f5eedd73001033f0aed7ea50b7c81048ad1533b8d3d73\",\n            \"blockNumber\": 15314402,\n            \"result\": {\n                \"gasUsed\": \"0x216\",\n                \"output\": \"0x00000000000000000000000000000000000000000000009258f7d820938417c7\"\n            },\n            \"subtraces\": 0,\n            \"traceAddress\": [0, 2, 3],\n            \"transactionHash\": \"0x2d951c5c95d374263ca99ad9c20c9797fc714330a8037429a3aa4c83d456f845\",\n            \"transactionPosition\": 289,\n            \"type\": \"call\"\n        }\n    ]);\n\n    let expected_traces: Vec<LocalizedTransactionTrace> = serde_json::from_value(json).unwrap();\n\n    // test matching traceAddress\n    traces.into_iter().zip(expected_traces).for_each(|(a, b)| {\n        assert_eq!(a.trace.trace_address, b.trace.trace_address);\n        assert_eq!(a.trace.subtraces, b.trace.subtraces);\n        match (a.trace.action, b.trace.action) {\n            (Action::Call(a), Action::Call(b)) => {\n                assert_eq!(a.from, b.from);\n                assert_eq!(a.to, b.to);\n            }\n            _ => unreachable!(\"unexpected action\"),\n        }\n    })\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_trace_filter() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n    let provider = handle.ws_provider();\n\n    let accounts = handle.dev_wallets().collect::<Vec<_>>();\n    let from = accounts[0].address();\n    let to = accounts[1].address();\n    let from_two = accounts[2].address();\n    let to_two = accounts[3].address();\n\n    // Test default block ranges.\n    // From will be earliest, to will be best/latest\n    let tracer = TraceFilter {\n        from_block: None,\n        to_block: None,\n        from_address: vec![],\n        to_address: vec![],\n        mode: TraceFilterMode::Intersection,\n        after: None,\n        count: None,\n    };\n\n    for i in 0..=5 {\n        let tx = TransactionRequest::default().to(to).value(U256::from(i)).from(from);\n        let tx = WithOtherFields::new(tx);\n        provider.send_transaction(tx).await.unwrap().get_receipt().await.unwrap();\n    }\n\n    let traces = api.trace_filter(tracer).await.unwrap();\n    assert_eq!(traces.len(), 6);\n\n    // Test filtering by address\n    let tracer = TraceFilter {\n        from_block: Some(provider.get_block_number().await.unwrap()),\n        to_block: None,\n        from_address: vec![from_two],\n        to_address: vec![to_two],\n        mode: TraceFilterMode::Intersection,\n        after: None,\n        count: None,\n    };\n\n    for i in 0..=5 {\n        let tx = TransactionRequest::default().to(to).value(U256::from(i)).from(from);\n        let tx = WithOtherFields::new(tx);\n        provider.send_transaction(tx).await.unwrap().get_receipt().await.unwrap();\n\n        let tx = TransactionRequest::default().to(to_two).value(U256::from(i)).from(from_two);\n        let tx = WithOtherFields::new(tx);\n        provider.send_transaction(tx).await.unwrap().get_receipt().await.unwrap();\n    }\n\n    let traces = api.trace_filter(tracer).await.unwrap();\n    assert_eq!(traces.len(), 6);\n\n    // Test for the following actions:\n    // Create (deploy the contract)\n    // Call (goodbye function)\n    // SelfDestruct (side-effect of goodbye)\n    let contract_addr =\n        SuicideContract::deploy_builder(provider.clone()).from(from).deploy().await.unwrap();\n    let contract = SuicideContract::new(contract_addr, provider.clone());\n\n    // Test TraceActions\n    let tracer = TraceFilter {\n        from_block: Some(provider.get_block_number().await.unwrap()),\n        to_block: None,\n        from_address: vec![from, contract_addr],\n        to_address: vec![], // Leave as 0 address\n        mode: TraceFilterMode::Union,\n        after: None,\n        count: None,\n    };\n\n    // Execute call\n    let call = contract.goodbye().from(from);\n    let call = call.send().await.unwrap();\n    call.get_receipt().await.unwrap();\n\n    // Mine transactions to filter against\n    for i in 0..=5 {\n        let tx = TransactionRequest::default().to(to_two).value(U256::from(i)).from(from_two);\n        let tx = WithOtherFields::new(tx);\n        provider.send_transaction(tx).await.unwrap().get_receipt().await.unwrap();\n    }\n\n    let traces = api.trace_filter(tracer).await.unwrap();\n    assert_eq!(traces.len(), 3);\n\n    // Test Range Error\n    let latest = provider.get_block_number().await.unwrap();\n    let tracer = TraceFilter {\n        from_block: Some(latest),\n        to_block: Some(latest + 301),\n        from_address: vec![],\n        to_address: vec![],\n        mode: TraceFilterMode::Union,\n        after: None,\n        count: None,\n    };\n\n    let traces = api.trace_filter(tracer).await;\n    assert!(traces.is_err());\n\n    // Test same from and to block is valid\n    let latest = provider.get_block_number().await.unwrap();\n    let tracer = TraceFilter {\n        from_block: Some(latest),\n        to_block: Some(latest),\n        from_address: vec![],\n        to_address: vec![],\n        mode: TraceFilterMode::Union,\n        after: None,\n        count: None,\n    };\n\n    let traces = api.trace_filter(tracer).await;\n    assert!(traces.is_ok());\n\n    // Test invalid block range\n    let latest = provider.get_block_number().await.unwrap();\n    let tracer = TraceFilter {\n        from_block: Some(latest + 10),\n        to_block: Some(latest),\n        from_address: vec![],\n        to_address: vec![],\n        mode: TraceFilterMode::Union,\n        after: None,\n        count: None,\n    };\n\n    let traces = api.trace_filter(tracer).await;\n    assert!(traces.is_err());\n\n    // Test after and count\n    let tracer = TraceFilter {\n        from_block: Some(provider.get_block_number().await.unwrap()),\n        to_block: None,\n        from_address: vec![],\n        to_address: vec![],\n        mode: TraceFilterMode::Union,\n        after: Some(3),\n        count: Some(5),\n    };\n\n    for i in 0..=10 {\n        let tx = TransactionRequest::default().to(to).value(U256::from(i)).from(from);\n        let tx = WithOtherFields::new(tx);\n        provider.send_transaction(tx).await.unwrap().get_receipt().await.unwrap();\n    }\n\n    let traces = api.trace_filter(tracer).await.unwrap();\n    assert_eq!(traces.len(), 5);\n}\n\n#[cfg(feature = \"js-tracer\")]\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_call_tracer_debug_trace_call_js_tracer() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n    let wallets = handle.dev_wallets().collect::<Vec<_>>();\n    let deployer: EthereumWallet = wallets[0].clone().into();\n    let provider = http_provider_with_signer(&handle.http_endpoint(), deployer);\n\n    let multicall_contract = Multicall::deploy(&provider).await.unwrap();\n    let simple_storage_contract =\n        SimpleStorage::deploy(&provider, \"init value\".to_string()).await.unwrap();\n\n    let set_value = simple_storage_contract.setValue(\"bar\".to_string());\n    let set_value_calldata = set_value.calldata();\n\n    let internal_call_tx_builder = multicall_contract.aggregate(vec![Multicall::Call {\n        target: *simple_storage_contract.address(),\n        callData: set_value_calldata.to_owned(),\n    }]);\n\n    let internal_call_tx_calldata = internal_call_tx_builder.calldata().to_owned();\n\n    let internal_call_tx = TransactionRequest::default()\n        .from(wallets[1].address())\n        .to(*multicall_contract.address())\n        .with_input(internal_call_tx_calldata);\n\n    let js_tracer_code = r#\"\n{\ndata: [],\nstep: function(log) {\n    var op = log.op.toString();\n    if (op === \"SLOAD\") {\n    this.data.push(log.getPC() + \": SLOAD \" + log.contract.getAddress() + \":\" + log.stack.peek(0));\n    this.data.push(\"    Result: \" + log.stack.peek(0));\n    } else if (op === \"SSTORE\") {\n    this.data.push(log.getPC() + \": SSTORE \" + log.contract.getAddress() + \":\" + log.stack.peek(1) + \" <- \" + log.stack.peek(0));\n    }\n},\nresult: function() {\n    return this.data;\n},\nfault: function(log) {}\n}\n\"#;\n\n    let result = api\n        .debug_trace_call(\n            WithOtherFields::new(internal_call_tx),\n            Some(BlockId::latest()),\n            GethDebugTracingCallOptions::default()\n                .with_tracing_options(GethDebugTracingOptions::js_tracer(js_tracer_code)),\n        )\n        .await\n        .unwrap();\n\n    let expected = vec![\n        \"547: SLOAD 231,241,114,94,119,52,206,40,143,131,103,225,187,20,62,144,187,63,5,18:0\",\n        \"    Result: 0\",\n        \"1907: SLOAD 231,241,114,94,119,52,206,40,143,131,103,225,187,20,62,144,187,63,5,18:1\",\n        \"    Result: 1\",\n        \"772: SLOAD 231,241,114,94,119,52,206,40,143,131,103,225,187,20,62,144,187,63,5,18:1\",\n        \"    Result: 1\",\n        \"835: SSTORE 231,241,114,94,119,52,206,40,143,131,103,225,187,20,62,144,187,63,5,18:44498830125527143464827115118378702402016761369235290884359940707316142178310 <- 1\",\n        \"919: SSTORE 231,241,114,94,119,52,206,40,143,131,103,225,187,20,62,144,187,63,5,18:0 <- 80084422859880547211683076133703299733277748156566366325829078699459944778998\",\n        \"712: SLOAD 231,241,114,94,119,52,206,40,143,131,103,225,187,20,62,144,187,63,5,18:0\",\n        \"    Result: 0\",\n        \"765: SSTORE 231,241,114,94,119,52,206,40,143,131,103,225,187,20,62,144,187,63,5,18:546584486846459126461364135121053344201067465379 <- 0\",\n    ];\n\n    let actual: Vec<String> = result\n        .try_into_json_value()\n        .ok()\n        .and_then(|val| val.as_array().cloned())\n        .map(|arr| arr.into_iter().filter_map(|v| v.as_str().map(|s| s.to_string())).collect())\n        .unwrap_or_default();\n\n    assert_eq!(actual, expected);\n}\n\n#[cfg(feature = \"js-tracer\")]\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_debug_trace_transaction_js_tracer() {\n    let node_config = NodeConfig::test().with_hardfork(Some(EthereumHardfork::Prague.into()));\n    let (api, handle) = spawn(node_config).await;\n    let provider = crate::utils::http_provider(&handle.http_endpoint());\n\n    let wallets = handle.dev_wallets().collect::<Vec<_>>();\n    let from = wallets[0].address();\n    api.anvil_add_balance(from, U256::MAX).await.unwrap();\n    api.anvil_add_balance(wallets[1].address(), U256::MAX).await.unwrap();\n\n    let multicall_contract = Multicall::deploy(&provider).await.unwrap();\n    let simple_storage_contract =\n        SimpleStorage::deploy(&provider, \"init value\".to_string()).await.unwrap();\n\n    let set_value = simple_storage_contract.setValue(\"bar\".to_string());\n    let set_value_calldata = set_value.calldata();\n\n    let internal_call_tx_builder = multicall_contract.aggregate(vec![Multicall::Call {\n        target: *simple_storage_contract.address(),\n        callData: set_value_calldata.to_owned(),\n    }]);\n\n    let internal_call_tx_calldata = internal_call_tx_builder.calldata().to_owned();\n\n    let internal_call_tx = TransactionRequest::default()\n        .from(wallets[1].address())\n        .to(*multicall_contract.address())\n        .with_input(internal_call_tx_calldata)\n        .with_gas_limit(1_000_000)\n        .with_max_fee_per_gas(100_000_000_000)\n        .with_max_priority_fee_per_gas(100_000_000_000);\n\n    let receipt = provider\n        .send_transaction(internal_call_tx.into())\n        .await\n        .unwrap()\n        .get_receipt()\n        .await\n        .unwrap();\n    let js_tracer_code = r#\"\n{\ndata: [],\nstep: function(log) {\n    var op = log.op.toString();\n    var pc = log.getPC();\n    var addr = log.contract.getAddress();\n\n    if (op === \"SLOAD\") {\n        this.data.push(pc + \": SLOAD \" + addr + \":\" + log.stack.peek(0));\n        this.data.push(\"    Result: \" + log.stack.peek(0));\n    } else if (op === \"SSTORE\") {\n        this.data.push(pc + \": SSTORE \" + addr + \":\" + log.stack.peek(1) + \" <- \" + log.stack.peek(0));\n    } \n},\nresult: function() {\n    return this.data;\n},\nfault: function(log) {}\n}\n\"#;\n\n    let expected = vec![\n        \"547: SLOAD 231,241,114,94,119,52,206,40,143,131,103,225,187,20,62,144,187,63,5,18:0\",\n        \"    Result: 0\",\n        \"1907: SLOAD 231,241,114,94,119,52,206,40,143,131,103,225,187,20,62,144,187,63,5,18:1\",\n        \"    Result: 1\",\n        \"772: SLOAD 231,241,114,94,119,52,206,40,143,131,103,225,187,20,62,144,187,63,5,18:1\",\n        \"    Result: 1\",\n        \"835: SSTORE 231,241,114,94,119,52,206,40,143,131,103,225,187,20,62,144,187,63,5,18:44498830125527143464827115118378702402016761369235290884359940707316142178310 <- 1\",\n        \"919: SSTORE 231,241,114,94,119,52,206,40,143,131,103,225,187,20,62,144,187,63,5,18:0 <- 80084422859880547211683076133703299733277748156566366325829078699459944778998\",\n        \"712: SLOAD 231,241,114,94,119,52,206,40,143,131,103,225,187,20,62,144,187,63,5,18:0\",\n        \"    Result: 0\",\n        \"765: SSTORE 231,241,114,94,119,52,206,40,143,131,103,225,187,20,62,144,187,63,5,18:546584486846459126461364135121053344201067465379 <- 0\",\n    ];\n    let result = api\n        .debug_trace_transaction(\n            receipt.transaction_hash,\n            GethDebugTracingOptions::js_tracer(js_tracer_code),\n        )\n        .await\n        .unwrap();\n\n    let actual: Vec<String> = result\n        .try_into_json_value()\n        .ok()\n        .and_then(|val| val.as_array().cloned())\n        .map(|arr| arr.into_iter().filter_map(|v| v.as_str().map(|s| s.to_string())).collect())\n        .unwrap_or_default();\n\n    assert_eq!(actual, expected);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_call_tracer_debug_trace_call_pre_state_tracer() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n    let wallets = handle.dev_wallets().collect::<Vec<_>>();\n    let deployer: EthereumWallet = wallets[0].clone().into();\n    let provider = http_provider_with_signer(&handle.http_endpoint(), deployer);\n\n    let multicall_contract = Multicall::deploy(&provider).await.unwrap();\n    let simple_storage_contract =\n        SimpleStorage::deploy(&provider, \"init value\".to_string()).await.unwrap();\n\n    let set_value = simple_storage_contract.setValue(\"bar\".to_string());\n    let set_value_calldata = set_value.calldata();\n\n    let internal_call_tx_builder = multicall_contract.aggregate(vec![Multicall::Call {\n        target: *simple_storage_contract.address(),\n        callData: set_value_calldata.to_owned(),\n    }]);\n\n    let internal_call_tx_calldata = internal_call_tx_builder.calldata().to_owned();\n\n    let internal_call_tx = TransactionRequest::default()\n        .from(wallets[1].address())\n        .to(*multicall_contract.address())\n        .with_input(internal_call_tx_calldata);\n\n    let result = api\n        .debug_trace_call(\n            WithOtherFields::new(internal_call_tx),\n            Some(BlockId::latest()),\n            GethDebugTracingCallOptions::default().with_tracing_options(\n                GethDebugTracingOptions::prestate_tracer(PreStateConfig::default()),\n            ),\n        )\n        .await\n        .unwrap();\n\n    let expected = r#\"\n{\n  \"0x0000000000000000000000000000000000000000\": {\n    \"balance\": \"0x12670f\"\n  },\n  \"0x5fbdb2315678afecb367f032d93f642f64180aa3\": {\n    \"balance\": \"0x0\",\n    \"nonce\": 1\n  },\n  \"0x70997970c51812dc3a010c7d01b50e0d17dc79c8\": {\n    \"balance\": \"0x56bc75e2d63100000\"\n  },\n  \"0xe7f1725e7734ce288f8367e1bb143e90bb3f0512\": {\n    \"balance\": \"0x0\",\n    \"nonce\": 1,\n    \"storage\": {\n      \"0x0000000000000000000000000000000000000000000000000000000000000000\": \"0x0000000000000000000000000000000000000000000000000000000000000000\",\n      \"0x0000000000000000000000000000000000000000000000000000000000000001\": \"0x696e69742076616c756500000000000000000000000000000000000000000014\",\n      \"0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6\": \"0x0000000000000000000000000000000000000000000000000000000000000000\"\n    }\n  }\n}\n    \"#;\n    let expected: HashMap<Address, AccountState> = serde_json::from_str(expected).unwrap();\n\n    match result {\n        GethTrace::PreStateTracer(PreStateFrame::Default(pre_state_mode)) => {\n            for (addr, acc) in pre_state_mode.0 {\n                let expected_acc = expected.get(&addr).unwrap();\n                assert_eq!(acc.balance, expected_acc.balance);\n                assert_eq!(acc.nonce, expected_acc.nonce);\n                let expected_storage = &expected_acc.storage;\n                for (slot, value) in acc.storage {\n                    assert_eq!(value, *expected_storage.get(&slot).unwrap())\n                }\n            }\n        }\n        _ => unreachable!(),\n    }\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_debug_trace_transaction_pre_state_tracer() {\n    let node_config = NodeConfig::test().with_hardfork(Some(EthereumHardfork::Prague.into()));\n    let (api, handle) = spawn(node_config).await;\n    let provider = crate::utils::http_provider(&handle.http_endpoint());\n\n    let wallets = handle.dev_wallets().collect::<Vec<_>>();\n    let from = wallets[0].address();\n    api.anvil_add_balance(from, U256::MAX).await.unwrap();\n    api.anvil_add_balance(wallets[1].address(), U256::MAX).await.unwrap();\n\n    let multicall_contract = Multicall::deploy(&provider).await.unwrap();\n    let simple_storage_contract =\n        SimpleStorage::deploy(&provider, \"init value\".to_string()).await.unwrap();\n\n    let set_value = simple_storage_contract.setValue(\"bar\".to_string());\n    let set_value_calldata = set_value.calldata();\n\n    let internal_call_tx_builder = multicall_contract.aggregate(vec![Multicall::Call {\n        target: *simple_storage_contract.address(),\n        callData: set_value_calldata.to_owned(),\n    }]);\n\n    let internal_call_tx_calldata = internal_call_tx_builder.calldata().to_owned();\n\n    let internal_call_tx = TransactionRequest::default()\n        .from(wallets[1].address())\n        .to(*multicall_contract.address())\n        .with_input(internal_call_tx_calldata)\n        .with_gas_limit(1_000_000)\n        .with_max_fee_per_gas(100_000_000_000)\n        .with_max_priority_fee_per_gas(100_000_000_000);\n\n    let receipt = provider\n        .send_transaction(internal_call_tx.into())\n        .await\n        .unwrap()\n        .get_receipt()\n        .await\n        .unwrap();\n\n    let result = api\n        .debug_trace_transaction(\n            receipt.transaction_hash,\n            GethDebugTracingOptions::prestate_tracer(PreStateConfig::default()),\n        )\n        .await\n        .unwrap();\n\n    let expected = r#\"\n{\n  \"0x0000000000000000000000000000000000000000\": {\n    \"balance\": \"1206031000000000\"\n  },\n  \"0x5fbdb2315678afecb367f032d93f642f64180aa3\": {\n    \"balance\": \"0x0\",\n    \"nonce\": 1\n  },\n  \"0x70997970c51812dc3a010c7d01b50e0d17dc79c8\": {\n    \"balance\": \"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\"\n  },\n  \"0xe7f1725e7734ce288f8367e1bb143e90bb3f0512\": {\n    \"balance\": \"0x0\",\n    \"nonce\": 1,\n    \"storage\": {\n      \"0x0000000000000000000000000000000000000000000000000000000000000000\": \"0x0000000000000000000000000000000000000000000000000000000000000000\",\n      \"0x0000000000000000000000000000000000000000000000000000000000000001\": \"0x696e69742076616c756500000000000000000000000000000000000000000014\",\n      \"0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6\": \"0x0000000000000000000000000000000000000000000000000000000000000000\"\n    }\n  }\n}\n    \"#;\n    let expected: HashMap<Address, AccountState> = serde_json::from_str(expected).unwrap();\n\n    match result {\n        GethTrace::PreStateTracer(PreStateFrame::Default(pre_state_mode)) => {\n            for (addr, acc) in pre_state_mode.0 {\n                let expected_acc = expected.get(&addr).unwrap();\n                assert_eq!(acc.balance, expected_acc.balance);\n                assert_eq!(acc.nonce, expected_acc.nonce);\n                let expected_storage = &expected_acc.storage;\n                for (slot, value) in acc.storage {\n                    assert_eq!(value, *expected_storage.get(&slot).unwrap())\n                }\n            }\n        }\n        _ => unreachable!(),\n    }\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_trace_replay_block_transactions_local() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n    let provider = handle.http_provider();\n\n    api.anvil_set_auto_mine(false).await.unwrap();\n\n    let accounts = handle.dev_wallets().collect::<Vec<_>>();\n    let from = accounts[0].address();\n    let to = accounts[1].address();\n    let amount = U256::from(1000000u64);\n\n    // Send first transaction\n    let tx1 = TransactionRequest::default().to(to).value(amount).from(from);\n    let tx1 = WithOtherFields::new(tx1);\n    let pending_tx1 = provider.send_transaction(tx1).await.unwrap();\n\n    // Send second transaction with different value\n    let tx2 = TransactionRequest::default().to(to).value(amount).from(from);\n    let tx2 = WithOtherFields::new(tx2);\n    let pending_tx2 = provider.send_transaction(tx2).await.unwrap();\n\n    api.mine_one().await;\n    let receipt1 = pending_tx1.get_receipt().await.unwrap();\n    let receipt2 = pending_tx2.get_receipt().await.unwrap();\n\n    let block_number = receipt2.block_number.unwrap();\n\n    // Replay the block transactions with call trace type\n    // Pass block number as hex string as per Ethereum RPC spec\n    let results = api\n        .trace_replay_block_transactions(\n            block_number.into(),\n            vec![TraceType::Trace, TraceType::VmTrace, TraceType::StateDiff].into_iter().collect(),\n        )\n        .await\n        .unwrap();\n\n    // Verify we have traces for both transactions\n    assert_eq!(results.len(), 2, \"Should have traces for 2 transactions\");\n\n    // Verify first transaction hash matches\n    assert_eq!(results[0].transaction_hash, receipt1.transaction_hash);\n\n    // Verify second transaction hash matches\n    assert_eq!(results[1].transaction_hash, receipt2.transaction_hash);\n\n    // Verify trace types are present and accurate\n    for result in results {\n        let full_trace = &result.full_trace;\n\n        // Verify Trace (call trace) is present and accurate\n        assert!(!full_trace.trace.is_empty(), \"Trace should not be empty\");\n        let first_trace = &full_trace.trace[0];\n        match &first_trace.action {\n            Action::Call(call) => {\n                assert_eq!(call.from, from, \"Call from address should match\");\n                assert_eq!(call.to, to, \"Call to address should match\");\n            }\n            _ => panic!(\"Expected Call action, got {:?}\", first_trace.action),\n        }\n\n        // Verify VmTrace is present\n        assert!(full_trace.vm_trace.is_some(), \"VmTrace should be present when requested\");\n\n        // Verify StateDiff is present\n        assert!(full_trace.state_diff.is_some(), \"StateDiff should be present when requested\");\n        // Verify balance change is correct in state diff\n        let ChangedType::<U256> { from, to } =\n            full_trace.state_diff.as_ref().unwrap().get(&to).unwrap().balance.as_changed().unwrap();\n        assert_eq!(\n            to.checked_sub(*from).unwrap(),\n            amount,\n            \"Incorrect balance change in state diff\"\n        );\n    }\n}\n"
  },
  {
    "path": "crates/anvil/tests/it/transaction.rs",
    "content": "use crate::{\n    abi::{Greeter, Multicall, SimpleStorage},\n    utils::{connect_pubsub, http_provider_with_signer},\n};\nuse alloy_consensus::Transaction;\nuse alloy_network::{EthereumWallet, ReceiptResponse, TransactionBuilder, TransactionResponse};\nuse alloy_primitives::{Address, Bytes, FixedBytes, U256, address, hex, map::B256HashSet};\nuse alloy_provider::{Provider, WsConnect};\nuse alloy_rpc_types::{\n    AccessList, AccessListItem, BlockId, BlockNumberOrTag, BlockOverrides, BlockTransactions,\n    TransactionRequest,\n    state::{AccountOverride, EvmOverrides, StateOverride, StateOverridesBuilder},\n};\nuse alloy_serde::WithOtherFields;\nuse alloy_sol_types::SolValue;\nuse anvil::{NodeConfig, spawn};\nuse eyre::Ok;\nuse foundry_evm::hardfork::EthereumHardfork;\nuse futures::{FutureExt, StreamExt, future::join_all};\nuse revm::primitives::eip7825::TX_GAS_LIMIT_CAP;\nuse std::{str::FromStr, time::Duration};\nuse tokio::time::timeout;\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_transfer_eth() {\n    let (_api, handle) = spawn(NodeConfig::test()).await;\n    let provider = handle.http_provider();\n\n    let accounts = handle.dev_wallets().collect::<Vec<_>>();\n    let from = accounts[0].address();\n    let to = accounts[1].address();\n\n    let nonce = provider.get_transaction_count(from).await.unwrap();\n    assert!(nonce == 0);\n\n    let balance_before = provider.get_balance(to).await.unwrap();\n\n    let amount = handle.genesis_balance().checked_div(U256::from(2u64)).unwrap();\n\n    // craft the tx\n    // specify the `from` field so that the client knows which account to use\n    let tx = TransactionRequest::default().to(to).value(amount).from(from);\n    let tx = WithOtherFields::new(tx);\n    // broadcast it via the eth_sendTransaction API\n    let tx = provider.send_transaction(tx).await.unwrap();\n\n    let tx = tx.get_receipt().await.unwrap();\n\n    assert_eq!(tx.block_number, Some(1));\n    assert_eq!(tx.transaction_index, Some(0));\n\n    let nonce = provider.get_transaction_count(from).await.unwrap();\n\n    assert_eq!(nonce, 1);\n\n    let to_balance = provider.get_balance(to).await.unwrap();\n\n    assert_eq!(balance_before.saturating_add(amount), to_balance);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_order_transactions() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n    let provider = handle.http_provider();\n\n    // disable automine\n    api.anvil_set_auto_mine(false).await.unwrap();\n\n    let accounts = handle.dev_wallets().collect::<Vec<_>>();\n    let from = accounts[0].address();\n    let to = accounts[1].address();\n\n    let amount = handle.genesis_balance().checked_div(U256::from(2u64)).unwrap();\n\n    let gas_price = provider.get_gas_price().await.unwrap();\n\n    // craft the tx with lower price\n    let mut tx = TransactionRequest::default().to(to).from(from).value(amount);\n\n    tx.set_gas_price(gas_price);\n    let tx = WithOtherFields::new(tx);\n    let tx_lower = provider.send_transaction(tx).await.unwrap();\n\n    // craft the tx with higher price\n    let mut tx = TransactionRequest::default().to(from).from(to).value(amount);\n\n    tx.set_gas_price(gas_price + 1);\n    let tx = WithOtherFields::new(tx);\n    let tx_higher = provider.send_transaction(tx).await.unwrap();\n\n    // manually mine the block with the transactions\n    api.mine_one().await;\n\n    let higher_price = tx_higher.get_receipt().await.unwrap().transaction_hash;\n    let lower_price = tx_lower.get_receipt().await.unwrap().transaction_hash;\n\n    // get the block, await receipts\n    let block = provider.get_block(BlockId::latest()).await.unwrap().unwrap();\n\n    assert_eq!(block.transactions, BlockTransactions::Hashes(vec![higher_price, lower_price]))\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_respect_nonces() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n    let provider = handle.http_provider();\n\n    let accounts = handle.dev_wallets().collect::<Vec<_>>();\n    let from = accounts[0].address();\n    let to = accounts[1].address();\n\n    let nonce = provider.get_transaction_count(from).await.unwrap();\n    let amount = handle.genesis_balance().checked_div(U256::from(3u64)).unwrap();\n\n    let tx = TransactionRequest::default().to(to).value(amount).from(from).nonce(nonce + 1);\n\n    let tx = WithOtherFields::new(tx);\n\n    // send the transaction with higher nonce than on chain\n    let higher_pending_tx = provider.send_transaction(tx).await.unwrap();\n\n    // ensure the listener for ready transactions times out\n    let mut listener = api.new_ready_transactions();\n    let res = timeout(Duration::from_millis(1500), listener.next()).await;\n    res.unwrap_err();\n\n    let tx = TransactionRequest::default().to(to).value(amount).from(from).nonce(nonce);\n\n    let tx = WithOtherFields::new(tx);\n    // send with the actual nonce which is mined immediately\n    let tx = provider.send_transaction(tx).await.unwrap();\n\n    let tx = tx.get_receipt().await.unwrap();\n    // this will unblock the currently pending tx\n    let higher_tx = higher_pending_tx.get_receipt().await.unwrap(); // Awaits endlessly here due to alloy/#389\n\n    let block = provider.get_block(1.into()).await.unwrap().unwrap();\n    assert_eq!(2, block.transactions.len());\n    assert_eq!(\n        BlockTransactions::Hashes(vec![tx.transaction_hash, higher_tx.transaction_hash]),\n        block.transactions\n    );\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_replace_transaction() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n\n    // disable auto mining\n    api.anvil_set_auto_mine(false).await.unwrap();\n\n    let provider = handle.http_provider();\n\n    let accounts = handle.dev_wallets().collect::<Vec<_>>();\n    let from = accounts[0].address();\n    let to = accounts[1].address();\n\n    let nonce = provider.get_transaction_count(from).await.unwrap();\n    let gas_price = provider.get_gas_price().await.unwrap();\n    let amount = handle.genesis_balance().checked_div(U256::from(3u64)).unwrap();\n\n    let tx = TransactionRequest::default().to(to).value(amount).from(from).nonce(nonce);\n\n    let mut tx = WithOtherFields::new(tx);\n\n    tx.set_gas_price(gas_price);\n    // send transaction with lower gas price\n    let _lower_priced_pending_tx = provider.send_transaction(tx.clone()).await.unwrap();\n\n    tx.set_gas_price(gas_price + 1);\n    // send the same transaction with higher gas price\n    let higher_priced_pending_tx = provider.send_transaction(tx).await.unwrap();\n\n    let higher_tx_hash = *higher_priced_pending_tx.tx_hash();\n    // mine exactly one block\n    api.mine_one().await;\n\n    let block = provider.get_block(1.into()).await.unwrap().unwrap();\n\n    assert_eq!(block.transactions.len(), 1);\n    assert_eq!(BlockTransactions::Hashes(vec![higher_tx_hash]), block.transactions);\n\n    // verify the higher priced transaction was included\n    let higher_priced_receipt = higher_priced_pending_tx.get_receipt().await.unwrap();\n    assert_eq!(higher_priced_receipt.transaction_hash, higher_tx_hash);\n\n    // verify only one transaction was included in the block (lower priced was replaced)\n    assert_eq!(1, block.transactions.len());\n    assert_eq!(\n        BlockTransactions::Hashes(vec![higher_priced_receipt.transaction_hash]),\n        block.transactions\n    );\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_reject_too_high_gas_limits() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n    let provider = handle.http_provider();\n\n    let accounts = handle.dev_wallets().collect::<Vec<_>>();\n    let from = accounts[0].address();\n    let to = accounts[1].address();\n\n    let gas_limit = api.gas_limit().to::<u64>();\n    let amount = handle.genesis_balance().checked_div(U256::from(3u64)).unwrap();\n\n    let tx =\n        TransactionRequest::default().to(to).value(amount).from(from).with_gas_limit(gas_limit);\n\n    let mut tx = WithOtherFields::new(tx);\n\n    // send transaction with the exact gas limit\n    let pending = provider.send_transaction(tx.clone()).await.unwrap();\n\n    let pending_receipt = pending.get_receipt().await;\n    assert!(pending_receipt.is_ok());\n\n    tx.set_gas_limit(gas_limit + 1);\n\n    // send transaction with higher gas limit\n    let pending = provider.send_transaction(tx.clone()).await;\n\n    assert!(pending.is_err());\n    let err = pending.unwrap_err();\n    assert!(err.to_string().contains(\"gas too high\"));\n\n    api.anvil_set_balance(from, U256::MAX).await.unwrap();\n\n    tx.set_gas_limit(gas_limit);\n    let pending = provider.send_transaction(tx).await;\n    let _ = pending.unwrap();\n}\n\n// <https://github.com/foundry-rs/foundry/issues/8094>\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_mine_large_gas_limit() {\n    let (_, handle) = spawn(NodeConfig::test().disable_block_gas_limit(true)).await;\n    let provider = handle.http_provider();\n\n    let accounts = handle.dev_wallets().collect::<Vec<_>>();\n    let from = accounts[0].address();\n    let to = accounts[1].address();\n\n    let gas_limit = anvil::DEFAULT_GAS_LIMIT;\n    let amount = handle.genesis_balance().checked_div(U256::from(3u64)).unwrap();\n\n    let tx =\n        TransactionRequest::default().to(to).value(amount).from(from).with_gas_limit(gas_limit);\n\n    // send transaction with higher gas limit\n    let pending = provider.send_transaction(WithOtherFields::new(tx)).await.unwrap();\n\n    let _resp = pending.get_receipt().await.unwrap();\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_reject_underpriced_replacement() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n\n    // disable auto mining\n    api.anvil_set_auto_mine(false).await.unwrap();\n\n    let provider = handle.http_provider();\n\n    let accounts = handle.dev_wallets().collect::<Vec<_>>();\n    let from = accounts[0].address();\n    let to = accounts[1].address();\n\n    let nonce = provider.get_transaction_count(from).await.unwrap();\n    let gas_price = provider.get_gas_price().await.unwrap();\n    let amount = handle.genesis_balance().checked_div(U256::from(3u64)).unwrap();\n\n    let tx = TransactionRequest::default().to(to).value(amount).from(from).nonce(nonce);\n\n    let mut tx = WithOtherFields::new(tx);\n\n    tx.set_gas_price(gas_price + 1);\n    // send transaction with higher gas price\n    let higher_priced_pending_tx = provider.send_transaction(tx.clone()).await.unwrap();\n\n    tx.set_gas_price(gas_price);\n    // send the same transaction with lower gas price\n    let lower_priced_pending_tx = provider.send_transaction(tx).await;\n\n    let replacement_err = lower_priced_pending_tx.unwrap_err();\n    assert!(replacement_err.to_string().contains(\"replacement transaction underpriced\"));\n\n    // mine exactly one block\n    api.mine_one().await;\n    let higher_priced_receipt = higher_priced_pending_tx.get_receipt().await.unwrap();\n\n    // ensure that only the higher priced tx was mined\n    let block = provider.get_block(1.into()).await.unwrap().unwrap();\n    assert_eq!(1, block.transactions.len());\n    assert_eq!(\n        BlockTransactions::Hashes(vec![higher_priced_receipt.transaction_hash]),\n        block.transactions\n    );\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_deploy_greeter_http() {\n    let (_api, handle) = spawn(NodeConfig::test()).await;\n    let wallet = handle.dev_wallets().next().unwrap();\n\n    let signer: EthereumWallet = wallet.clone().into();\n\n    let alloy_provider = http_provider_with_signer(&handle.http_endpoint(), signer);\n\n    let alloy_greeter_addr =\n        Greeter::deploy_builder(alloy_provider.clone(), \"Hello World!\".to_string())\n            // .legacy() unimplemented! in alloy\n            .deploy()\n            .await\n            .unwrap();\n\n    let alloy_greeter = Greeter::new(alloy_greeter_addr, alloy_provider);\n\n    let greeting = alloy_greeter.greet().call().await.unwrap();\n\n    assert_eq!(\"Hello World!\", greeting);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_deploy_and_mine_manually() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n\n    // can mine in auto-mine mode\n    api.evm_mine(None).await.unwrap();\n    // disable auto mine\n    api.anvil_set_auto_mine(false).await.unwrap();\n    // can mine in manual mode\n    api.evm_mine(None).await.unwrap();\n\n    let provider = handle.http_provider();\n\n    let wallet = handle.dev_wallets().next().unwrap();\n    let from = wallet.address();\n\n    let greeter_builder =\n        Greeter::deploy_builder(provider.clone(), \"Hello World!\".to_string()).from(from);\n    let greeter_calldata = greeter_builder.calldata();\n\n    let tx = TransactionRequest::default().from(from).with_input(greeter_calldata.to_owned());\n\n    let tx = WithOtherFields::new(tx);\n\n    let tx = provider.send_transaction(tx).await.unwrap();\n\n    // mine block with tx manually\n    api.evm_mine(None).await.unwrap();\n\n    let receipt = tx.get_receipt().await.unwrap();\n\n    let address = receipt.contract_address.unwrap();\n    let greeter_contract = Greeter::new(address, provider);\n    let greeting = greeter_contract.greet().call().await.unwrap();\n    assert_eq!(\"Hello World!\", greeting);\n\n    let set_greeting = greeter_contract.setGreeting(\"Another Message\".to_string());\n    let tx = set_greeting.send().await.unwrap();\n\n    // mine block manually\n    api.evm_mine(None).await.unwrap();\n\n    let _tx = tx.get_receipt().await.unwrap();\n    let greeting = greeter_contract.greet().call().await.unwrap();\n    assert_eq!(\"Another Message\", greeting);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_mine_automatically() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n    let provider = handle.http_provider();\n\n    // disable auto mine\n    api.anvil_set_auto_mine(false).await.unwrap();\n\n    let wallet = handle.dev_wallets().next().unwrap();\n\n    let greeter_builder = Greeter::deploy_builder(provider.clone(), \"Hello World!\".to_string())\n        .from(wallet.address());\n\n    let greeter_calldata = greeter_builder.calldata();\n\n    let tx = TransactionRequest::default()\n        .from(wallet.address())\n        .with_input(greeter_calldata.to_owned());\n\n    let tx = WithOtherFields::new(tx);\n\n    let sent_tx = provider.send_transaction(tx).await.unwrap();\n\n    // re-enable auto mine\n    api.anvil_set_auto_mine(true).await.unwrap();\n\n    let receipt = sent_tx.get_receipt().await.unwrap();\n    assert_eq!(receipt.block_number, Some(1));\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_call_greeter_historic() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n    let provider = handle.http_provider();\n\n    let wallet = handle.dev_wallets().next().unwrap();\n\n    let greeter_addr = Greeter::deploy_builder(provider.clone(), \"Hello World!\".to_string())\n        .from(wallet.address())\n        .deploy()\n        .await\n        .unwrap();\n\n    let greeter_contract = Greeter::new(greeter_addr, provider.clone());\n\n    let greeting = greeter_contract.greet().call().await.unwrap();\n    assert_eq!(\"Hello World!\", greeting);\n\n    let block_number = provider.get_block_number().await.unwrap();\n\n    let _receipt = greeter_contract\n        .setGreeting(\"Another Message\".to_string())\n        .send()\n        .await\n        .unwrap()\n        .get_receipt()\n        .await\n        .unwrap();\n\n    let greeting = greeter_contract.greet().call().await.unwrap();\n    assert_eq!(\"Another Message\", greeting);\n\n    // min\n    api.mine_one().await;\n\n    // returns previous state\n    let greeting =\n        greeter_contract.greet().block(BlockId::Number(block_number.into())).call().await.unwrap();\n    assert_eq!(\"Hello World!\", greeting);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_deploy_greeter_ws() {\n    let (_api, handle) = spawn(NodeConfig::test()).await;\n    let provider = handle.ws_provider();\n\n    let wallet = handle.dev_wallets().next().unwrap();\n\n    let greeter_addr = Greeter::deploy_builder(provider.clone(), \"Hello World!\".to_string())\n        .from(wallet.address())\n        // .legacy() unimplemented! in alloy\n        .deploy()\n        .await\n        .unwrap();\n\n    let greeter_contract = Greeter::new(greeter_addr, provider.clone());\n\n    let greeting = greeter_contract.greet().call().await.unwrap();\n    assert_eq!(\"Hello World!\", greeting);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_deploy_get_code() {\n    let (_api, handle) = spawn(NodeConfig::test()).await;\n    let provider = handle.ws_provider();\n\n    let wallet = handle.dev_wallets().next().unwrap();\n\n    let greeter_addr = Greeter::deploy_builder(provider.clone(), \"Hello World!\".to_string())\n        .from(wallet.address())\n        .deploy()\n        .await\n        .unwrap();\n\n    let code = provider.get_code_at(greeter_addr).await.unwrap();\n    assert!(!code.as_ref().is_empty());\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn get_blocktimestamp_works() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n    let provider = handle.http_provider();\n\n    let contract = Multicall::deploy(provider.clone()).await.unwrap();\n\n    let timestamp = contract.getCurrentBlockTimestamp().call().await.unwrap();\n\n    assert!(timestamp > U256::from(1));\n\n    let latest_block =\n        api.block_by_number(alloy_rpc_types::BlockNumberOrTag::Latest).await.unwrap().unwrap();\n\n    let timestamp = contract.getCurrentBlockTimestamp().call().await.unwrap();\n    assert_eq!(timestamp.to::<u64>(), latest_block.header.timestamp);\n\n    // repeat call same result\n    let timestamp = contract.getCurrentBlockTimestamp().call().await.unwrap();\n    assert_eq!(timestamp.to::<u64>(), latest_block.header.timestamp);\n\n    // mock timestamp\n    let next_timestamp = timestamp.to::<u64>() + 1337;\n    api.evm_set_next_block_timestamp(next_timestamp).unwrap();\n\n    let timestamp =\n        contract.getCurrentBlockTimestamp().block(BlockId::pending()).call().await.unwrap();\n    assert_eq!(timestamp, U256::from(next_timestamp));\n\n    // repeat call same result\n    let timestamp =\n        contract.getCurrentBlockTimestamp().block(BlockId::pending()).call().await.unwrap();\n    assert_eq!(timestamp, U256::from(next_timestamp));\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn call_past_state() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n    let provider = handle.http_provider();\n\n    let wallet = handle.dev_wallets().next().unwrap();\n    let contract_addr =\n        SimpleStorage::deploy_builder(provider.clone(), \"initial value\".to_string())\n            .from(wallet.address())\n            .deploy()\n            .await\n            .unwrap();\n\n    let contract = SimpleStorage::new(contract_addr, provider.clone());\n\n    let deployed_block = provider.get_block_number().await.unwrap();\n\n    let value = contract.getValue().call().await.unwrap();\n    assert_eq!(value, \"initial value\");\n\n    let gas_price = api.gas_price();\n    let set_tx = contract.setValue(\"hi\".to_string()).gas_price(gas_price + 1);\n\n    let _receipt = set_tx.send().await.unwrap().get_receipt().await.unwrap();\n\n    // assert new value\n    let value = contract.getValue().call().await.unwrap();\n    assert_eq!(value, \"hi\");\n\n    // assert previous value\n    let value =\n        contract.getValue().block(BlockId::Number(deployed_block.into())).call().await.unwrap();\n    assert_eq!(value, \"initial value\");\n\n    let hash = provider.get_block(BlockId::Number(1.into())).await.unwrap().unwrap().header.hash;\n    let value = contract.getValue().block(BlockId::Hash(hash.into())).call().await.unwrap();\n    assert_eq!(value, \"initial value\");\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_handle_multiple_concurrent_transfers_with_same_nonce() {\n    let (_api, handle) = spawn(NodeConfig::test()).await;\n\n    let provider = handle.ws_provider();\n\n    let accounts = handle.dev_wallets().collect::<Vec<_>>();\n    let from = accounts[0].address();\n    let to = accounts[1].address();\n\n    let nonce = provider.get_transaction_count(from).await.unwrap();\n\n    // explicitly set the nonce\n    let tx = TransactionRequest::default()\n        .to(to)\n        .value(U256::from(100))\n        .from(from)\n        .nonce(nonce)\n        .with_gas_limit(21000);\n\n    let tx = WithOtherFields::new(tx);\n\n    let mut tasks = Vec::new();\n    for _ in 0..10 {\n        let tx = tx.clone();\n        let provider = provider.clone();\n        let task = tokio::task::spawn(async move {\n            provider.send_transaction(tx).await.unwrap().get_receipt().await\n        });\n        tasks.push(task);\n    }\n\n    // only one succeeded\n    let successful_tx =\n        join_all(tasks).await.into_iter().filter(|res| res.as_ref().is_ok()).count();\n    assert_eq!(successful_tx, 1);\n\n    assert_eq!(provider.get_transaction_count(from).await.unwrap(), 1u64);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_handle_multiple_concurrent_deploys_with_same_nonce() {\n    let (_api, handle) = spawn(NodeConfig::test()).await;\n    let provider = handle.ws_provider();\n\n    let wallet = handle.dev_wallets().next().unwrap();\n    let from = wallet.address();\n    let nonce = provider.get_transaction_count(from).await.unwrap();\n\n    let mut tasks = Vec::new();\n\n    let greeter = Greeter::deploy_builder(provider.clone(), \"Hello World!\".to_string());\n\n    let greeter_calldata = greeter.calldata();\n\n    let tx = TransactionRequest::default()\n        .from(from)\n        .with_input(greeter_calldata.to_owned())\n        .nonce(nonce)\n        .with_gas_limit(300_000);\n\n    let tx = WithOtherFields::new(tx);\n\n    for _ in 0..10 {\n        let provider = provider.clone();\n        let tx = tx.clone();\n        let task = tokio::task::spawn(async move {\n            Ok(provider.send_transaction(tx).await?.get_receipt().await.unwrap())\n        });\n        tasks.push(task);\n    }\n\n    // only one succeeded\n    let successful_tx =\n        join_all(tasks).await.into_iter().filter(|res| res.as_ref().unwrap().is_ok()).count();\n    assert_eq!(successful_tx, 1);\n    assert_eq!(provider.get_transaction_count(from).await.unwrap(), 1u64);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_handle_multiple_concurrent_transactions_with_same_nonce() {\n    let (_api, handle) = spawn(NodeConfig::test()).await;\n    let provider = handle.ws_provider();\n\n    let wallet = handle.dev_wallets().next().unwrap();\n    let from = wallet.address();\n\n    let greeter_contract =\n        Greeter::deploy(provider.clone(), \"Hello World!\".to_string()).await.unwrap();\n\n    let nonce = provider.get_transaction_count(from).await.unwrap();\n\n    let mut tasks = Vec::new();\n\n    let deploy = Greeter::deploy_builder(provider.clone(), \"Hello World!\".to_string());\n    let deploy_calldata = deploy.calldata();\n    let deploy_tx = TransactionRequest::default()\n        .from(from)\n        .with_input(deploy_calldata.to_owned())\n        .nonce(nonce)\n        .with_gas_limit(300_000);\n    let deploy_tx = WithOtherFields::new(deploy_tx);\n\n    let set_greeting = greeter_contract.setGreeting(\"Hello\".to_string());\n    let set_greeting_calldata = set_greeting.calldata();\n\n    let set_greeting_tx = TransactionRequest::default()\n        .from(from)\n        .with_input(set_greeting_calldata.to_owned())\n        .nonce(nonce)\n        .with_gas_limit(300_000);\n    let set_greeting_tx = WithOtherFields::new(set_greeting_tx);\n\n    for idx in 0..10 {\n        let provider = provider.clone();\n        let task = if idx % 2 == 0 {\n            let tx = deploy_tx.clone();\n            tokio::task::spawn(async move {\n                Ok(provider.send_transaction(tx).await?.get_receipt().await.unwrap())\n            })\n        } else {\n            let tx = set_greeting_tx.clone();\n            tokio::task::spawn(async move {\n                Ok(provider.send_transaction(tx).await?.get_receipt().await.unwrap())\n            })\n        };\n\n        tasks.push(task);\n    }\n\n    // only one succeeded\n    let successful_tx =\n        join_all(tasks).await.into_iter().filter(|res| res.as_ref().unwrap().is_ok()).count();\n    assert_eq!(successful_tx, 1);\n    assert_eq!(provider.get_transaction_count(from).await.unwrap(), nonce + 1);\n}\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_get_pending_transaction() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n\n    // disable auto mining so we can check if we can return pending tx from the mempool\n    api.anvil_set_auto_mine(false).await.unwrap();\n\n    let provider = handle.http_provider();\n\n    let from = handle.dev_wallets().next().unwrap().address();\n    let tx = TransactionRequest::default().from(from).value(U256::from(1337)).to(Address::random());\n    let tx = WithOtherFields::new(tx);\n    let tx = provider.send_transaction(tx).await.unwrap();\n\n    let pending = provider.get_transaction_by_hash(*tx.tx_hash()).await;\n    assert!(pending.is_ok());\n\n    api.mine_one().await;\n    let mined = provider.get_transaction_by_hash(*tx.tx_hash()).await.unwrap().unwrap();\n\n    assert_eq!(mined.tx_hash(), pending.unwrap().unwrap().tx_hash());\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_listen_full_pending_transaction() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n\n    // Disable auto-mining so transactions remain pending\n    api.anvil_set_auto_mine(false).await.unwrap();\n\n    let provider = alloy_provider::ProviderBuilder::new()\n        .connect_ws(WsConnect::new(handle.ws_endpoint()))\n        .await\n        .unwrap();\n\n    // Subscribe to full pending transactions\n    let sub = provider.subscribe_full_pending_transactions().await;\n    tokio::time::sleep(Duration::from_millis(1000)).await;\n    let mut stream = sub.expect(\"Failed to subscribe to pending tx\").into_stream().take(5);\n\n    let from = handle.dev_wallets().next().unwrap().address();\n    let tx = TransactionRequest::default().from(from).value(U256::from(1337)).to(Address::random());\n\n    let tx = provider.send_transaction(tx).await.unwrap();\n\n    // Wait for the subscription to yield a transaction\n    let received = stream.next().await.expect(\"Failed to receive pending tx\");\n\n    assert_eq!(received.tx_hash(), *tx.tx_hash());\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_get_raw_transaction() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n\n    // first test the pending tx, disable auto mine\n    api.anvil_set_auto_mine(false).await.unwrap();\n\n    let provider = handle.http_provider();\n\n    let from = handle.dev_wallets().next().unwrap().address();\n    let tx = TransactionRequest::default().from(from).value(U256::from(1488)).to(Address::random());\n    let tx = WithOtherFields::new(tx);\n    let tx = provider.send_transaction(tx).await.unwrap();\n\n    let res1 = api.raw_transaction(*tx.tx_hash()).await;\n    assert!(res1.is_ok());\n\n    api.mine_one().await;\n    let res2 = api.raw_transaction(*tx.tx_hash()).await;\n\n    assert_eq!(res1.unwrap(), res2.unwrap());\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_first_nonce_is_zero() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n\n    api.anvil_set_auto_mine(false).await.unwrap();\n\n    let provider = handle.http_provider();\n    let from = handle.dev_wallets().next().unwrap().address();\n\n    let nonce = provider.get_transaction_count(from).block_id(BlockId::pending()).await.unwrap();\n\n    assert_eq!(nonce, 0);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_handle_different_sender_nonce_calculation() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n\n    api.anvil_set_auto_mine(false).await.unwrap();\n\n    let provider = handle.http_provider();\n    let accounts = handle.dev_wallets().collect::<Vec<_>>();\n    let from_first = accounts[0].address();\n    let from_second = accounts[1].address();\n\n    let tx_count = 10u64;\n\n    // send a bunch of tx to the mempool and check nonce is returned correctly\n    for idx in 1..=tx_count {\n        let tx_from_first = TransactionRequest::default()\n            .from(from_first)\n            .value(U256::from(1337u64))\n            .to(Address::random());\n        let tx_from_first = WithOtherFields::new(tx_from_first);\n        let _tx = provider.send_transaction(tx_from_first).await.unwrap();\n        let nonce_from_first =\n            provider.get_transaction_count(from_first).block_id(BlockId::pending()).await.unwrap();\n        assert_eq!(nonce_from_first, idx);\n\n        let tx_from_second = TransactionRequest::default()\n            .from(from_second)\n            .value(U256::from(1337u64))\n            .to(Address::random());\n        let tx_from_second = WithOtherFields::new(tx_from_second);\n        let _tx = provider.send_transaction(tx_from_second).await.unwrap();\n        let nonce_from_second =\n            provider.get_transaction_count(from_second).block_id(BlockId::pending()).await.unwrap();\n        assert_eq!(nonce_from_second, idx);\n    }\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn includes_pending_tx_for_transaction_count() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n\n    api.anvil_set_auto_mine(false).await.unwrap();\n\n    let provider = handle.http_provider();\n    let from = handle.dev_wallets().next().unwrap().address();\n\n    let tx_count = 10u64;\n\n    // send a bunch of tx to the mempool and check nonce is returned correctly\n    for idx in 1..=tx_count {\n        let tx =\n            TransactionRequest::default().from(from).value(U256::from(1337)).to(Address::random());\n        let tx = WithOtherFields::new(tx);\n        let _tx = provider.send_transaction(tx).await.unwrap();\n        let nonce =\n            provider.get_transaction_count(from).block_id(BlockId::pending()).await.unwrap();\n        assert_eq!(nonce, idx);\n    }\n\n    api.mine_one().await;\n    let nonce = provider.get_transaction_count(from).block_id(BlockId::pending()).await.unwrap();\n    assert_eq!(nonce, tx_count);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_get_historic_info() {\n    let (_api, handle) = spawn(NodeConfig::test()).await;\n    let provider = handle.http_provider();\n\n    let accounts = handle.dev_wallets().collect::<Vec<_>>();\n    let from = accounts[0].address();\n    let to = accounts[1].address();\n\n    let amount = handle.genesis_balance().checked_div(U256::from(2u64)).unwrap();\n    let tx = TransactionRequest::default().to(to).value(amount).from(from);\n    let tx = WithOtherFields::new(tx);\n    let tx = provider.send_transaction(tx).await.unwrap();\n    let _ = tx.get_receipt().await.unwrap();\n\n    let nonce_pre =\n        provider.get_transaction_count(from).block_id(BlockId::number(0)).await.unwrap();\n\n    let nonce_post = provider.get_transaction_count(from).await.unwrap();\n\n    assert!(nonce_pre < nonce_post);\n\n    let balance_pre = provider.get_balance(from).block_id(BlockId::number(0)).await.unwrap();\n\n    let balance_post = provider.get_balance(from).await.unwrap();\n\n    assert!(balance_post < balance_pre);\n\n    let to_balance = provider.get_balance(to).await.unwrap();\n    assert_eq!(balance_pre.saturating_add(amount), to_balance);\n}\n\n// <https://github.com/eth-brownie/brownie/issues/1549>\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_tx_receipt() {\n    let (_api, handle) = spawn(NodeConfig::test()).await;\n\n    let wallet = handle.dev_wallets().next().unwrap();\n    let provider = handle.http_provider();\n\n    let tx = TransactionRequest::default().to(Address::random()).value(U256::from(1337));\n\n    let tx = WithOtherFields::new(tx);\n    let tx = provider.send_transaction(tx).await.unwrap().get_receipt().await.unwrap();\n    assert!(tx.to.is_some());\n\n    let greeter_deploy = Greeter::deploy_builder(provider.clone(), \"Hello World!\".to_string());\n    let greeter_calldata = greeter_deploy.calldata();\n\n    let tx = TransactionRequest::default()\n        .from(wallet.address())\n        .with_input(greeter_calldata.to_owned());\n\n    let tx = WithOtherFields::new(tx);\n    let tx = provider.send_transaction(tx).await.unwrap().get_receipt().await.unwrap();\n\n    // `to` field is none if it's a contract creation transaction: https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_gettransactionreceipt\n    assert!(tx.to.is_none());\n    assert!(tx.contract_address.is_some());\n}\n\n// <https://github.com/foundry-rs/foundry/issues/12837>\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_reverted_contract_creation_has_contract_address() {\n    let (_api, handle) = spawn(NodeConfig::test()).await;\n\n    let provider = handle.http_provider();\n    let wallet = handle.dev_wallets().next().unwrap();\n\n    // Init code that immediately reverts: PUSH1 0x00 PUSH1 0x00 REVERT (0x60006000fd)\n    let reverting_init_code = hex!(\"60006000fd\");\n\n    let tx = TransactionRequest::default()\n        .from(wallet.address())\n        .with_input(reverting_init_code.to_vec());\n\n    let tx = WithOtherFields::new(tx);\n    let receipt = provider.send_transaction(tx).await.unwrap().get_receipt().await.unwrap();\n\n    // Transaction should have reverted\n    assert!(!receipt.status());\n\n    // `to` field should be none (contract creation)\n    assert!(receipt.to.is_none());\n\n    // `contractAddress` should still be set even though the transaction reverted\n    // This matches geth's behavior: https://github.com/ethereum/go-ethereum/issues/27937\n    assert!(\n        receipt.contract_address.is_some(),\n        \"contractAddress should be set for reverted contract creation\"\n    );\n\n    // Verify the computed address is correct (sender.create(nonce))\n    let expected_addr = wallet.address().create(0);\n    assert_eq!(receipt.contract_address, Some(expected_addr));\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_stream_pending_transactions() {\n    let (_api, handle) =\n        spawn(NodeConfig::test().with_blocktime(Some(Duration::from_secs(2)))).await;\n    let num_txs = 5;\n\n    let provider = handle.http_provider();\n    let ws_provider = connect_pubsub(&handle.ws_endpoint()).await;\n\n    let accounts = provider.get_accounts().await.unwrap();\n    let tx =\n        TransactionRequest::default().from(accounts[0]).to(accounts[0]).value(U256::from(1e18));\n\n    let mut sending = futures::future::join_all(\n        std::iter::repeat_n(tx.clone(), num_txs)\n            .enumerate()\n            .map(|(nonce, tx)| tx.nonce(nonce as u64))\n            .map(|tx| async {\n                let tx = WithOtherFields::new(tx);\n                provider.send_transaction(tx).await.unwrap().get_receipt().await.unwrap()\n            }),\n    )\n    .fuse();\n\n    let mut watch_tx_stream = provider\n        .watch_pending_transactions()\n        .await\n        .unwrap()\n        .into_stream()\n        .flat_map(futures::stream::iter)\n        .take(num_txs)\n        .fuse();\n\n    let mut sub_tx_stream = ws_provider\n        .subscribe_pending_transactions()\n        .await\n        .unwrap()\n        .into_stream()\n        .take(num_txs)\n        .fuse();\n\n    let mut sent = None;\n    let mut watch_received = Vec::with_capacity(num_txs);\n    let mut sub_received = Vec::with_capacity(num_txs);\n\n    loop {\n        futures::select! {\n            txs = sending => {\n                sent = Some(txs)\n            },\n            tx = watch_tx_stream.next() => {\n                if let Some(tx) = tx {\n                    watch_received.push(tx);\n                }\n            },\n            tx = sub_tx_stream.next() => {\n                if let Some(tx) = tx {\n                    sub_received.push(tx);\n                }\n            },\n            complete => unreachable!(),\n        };\n\n        if watch_received.len() == num_txs\n            && sub_received.len() == num_txs\n            && let Some(sent) = &sent\n        {\n            assert_eq!(sent.len(), watch_received.len());\n            let sent_txs = sent.iter().map(|tx| tx.transaction_hash).collect::<B256HashSet>();\n            assert_eq!(sent_txs, watch_received.iter().copied().collect());\n            assert_eq!(sent_txs, sub_received.iter().copied().collect());\n            break;\n        }\n    }\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_tx_access_list() {\n    /// returns a String representation of the AccessList, with sorted\n    /// keys (address) and storage slots\n    fn access_list_to_sorted_string(a: AccessList) -> String {\n        let mut a = a.0;\n        a.sort_by_key(|v| v.address);\n\n        let a = a\n            .iter_mut()\n            .map(|v| {\n                v.storage_keys.sort();\n                (v.address, std::mem::take(&mut v.storage_keys))\n            })\n            .collect::<Vec<_>>();\n\n        format!(\"{a:?}\")\n    }\n\n    /// asserts that the two access lists are equal, by comparing their sorted\n    /// string representation\n    fn assert_access_list_eq(a: AccessList, b: AccessList) {\n        assert_eq!(access_list_to_sorted_string(a), access_list_to_sorted_string(b))\n    }\n\n    // We want to test a couple of things:\n    //     - When calling a contract with no storage read/write, it shouldn't be in the AL\n    //     - When a contract calls a contract, the latter one should be in the AL\n    //     - No precompiles should be in the AL\n    //     - The sender shouldn't be in the AL\n    let (_api, handle) = spawn(NodeConfig::test()).await;\n\n    let provider = handle.http_provider();\n\n    let sender = Address::random();\n    let other_acc = Address::random();\n    let multicall = Multicall::deploy(provider.clone()).await.unwrap();\n    let simple_storage = SimpleStorage::deploy(provider.clone(), \"foo\".to_string()).await.unwrap();\n\n    // when calling `setValue` on SimpleStorage, both the `lastSender` and `_value` storages are\n    // modified The `_value` is a `string`, so the storage slots here (small string) are `0x1`\n    // and `keccak(0x1)`\n    let set_value = simple_storage.setValue(\"bar\".to_string());\n    let set_value_calldata = set_value.calldata();\n    let set_value_tx = TransactionRequest::default()\n        .from(sender)\n        .to(*simple_storage.address())\n        .with_input(set_value_calldata.to_owned());\n    let set_value_tx = WithOtherFields::new(set_value_tx);\n    let access_list = provider.create_access_list(&set_value_tx).await.unwrap();\n    // let set_value_tx = simple_storage.set_value(\"bar\".to_string()).from(sender).tx;\n    // let access_list = client.create_access_list(&set_value_tx, None).await.unwrap();\n    assert_access_list_eq(\n        access_list.access_list,\n        AccessList::from(vec![AccessListItem {\n            address: *simple_storage.address(),\n            storage_keys: vec![\n                FixedBytes::ZERO,\n                FixedBytes::with_last_byte(1),\n                FixedBytes::from_str(\n                    \"0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6\",\n                )\n                .unwrap(),\n            ],\n        }]),\n    );\n\n    // With a subcall that fetches the balances of an account (`other_acc`), only the address\n    // of this account should be in the Access List\n    let call_tx = multicall.getEthBalance(other_acc);\n    let call_tx_data = call_tx.calldata();\n    let call_tx = TransactionRequest::default()\n        .from(sender)\n        .to(*multicall.address())\n        .with_input(call_tx_data.to_owned());\n    let call_tx = WithOtherFields::new(call_tx);\n    let access_list = provider.create_access_list(&call_tx).await.unwrap();\n    assert_access_list_eq(\n        access_list.access_list,\n        AccessList::from(vec![AccessListItem { address: other_acc, storage_keys: vec![] }]),\n    );\n\n    // With a subcall to another contract, the AccessList should be the same as when calling the\n    // subcontract directly (given that the proxy contract doesn't read/write any state)\n    let subcall_tx = multicall.aggregate(vec![Multicall::Call {\n        target: *simple_storage.address(),\n        callData: set_value_calldata.to_owned(),\n    }]);\n\n    let subcall_tx_calldata = subcall_tx.calldata();\n\n    let subcall_tx = TransactionRequest::default()\n        .from(sender)\n        .to(*multicall.address())\n        .with_input(subcall_tx_calldata.to_owned());\n    let subcall_tx = WithOtherFields::new(subcall_tx);\n    let access_list = provider.create_access_list(&subcall_tx).await.unwrap();\n    assert_access_list_eq(\n        access_list.access_list,\n        // H256::from_uint(&(1u64.into())),\n        AccessList::from(vec![AccessListItem {\n            address: *simple_storage.address(),\n            storage_keys: vec![\n                FixedBytes::ZERO,\n                FixedBytes::with_last_byte(1),\n                FixedBytes::from_str(\n                    \"0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6\",\n                )\n                .unwrap(),\n            ],\n        }]),\n    );\n}\n\n// ensures that the gas estimate is running on pending block by default\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn estimates_gas_on_pending_by_default() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n\n    // disable auto mine\n    api.anvil_set_auto_mine(false).await.unwrap();\n\n    let provider = handle.http_provider();\n\n    let wallet = handle.dev_wallets().next().unwrap();\n    let sender = wallet.address();\n    let recipient = Address::random();\n\n    let tx = TransactionRequest::default().from(sender).to(recipient).value(U256::from(1e18));\n    let tx = WithOtherFields::new(tx);\n\n    let _pending = provider.send_transaction(tx).await.unwrap();\n\n    let tx = TransactionRequest::default()\n        .from(recipient)\n        .to(sender)\n        .value(U256::from(1e10))\n        .input(Bytes::from(vec![0x42]).into());\n    api.estimate_gas(WithOtherFields::new(tx), None, EvmOverrides::default()).await.unwrap();\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_estimate_gas() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n\n    let wallet = handle.dev_wallets().next().unwrap();\n    let sender = wallet.address();\n    let recipient = Address::random();\n\n    let tx = TransactionRequest::default()\n        .from(recipient)\n        .to(sender)\n        .value(U256::from(1e10))\n        .input(Bytes::from(vec![0x42]).into());\n    // Expect the gas estimation to fail due to insufficient funds.\n    let error_result =\n        api.estimate_gas(WithOtherFields::new(tx.clone()), None, EvmOverrides::default()).await;\n\n    assert!(error_result.is_err(), \"Expected an error due to insufficient funds\");\n    let error_message = error_result.unwrap_err().to_string();\n    assert!(\n        error_message.contains(\"Insufficient funds for gas * price + value\"),\n        \"Error message did not match expected: {error_message}\"\n    );\n\n    // Setup state override to simulate sufficient funds for the recipient.\n    let addr = recipient;\n    let account_override =\n        AccountOverride { balance: Some(alloy_primitives::U256::from(1e18)), ..Default::default() };\n    let mut state_override = StateOverride::default();\n    state_override.insert(addr, account_override);\n\n    // Estimate gas with state override implying sufficient funds.\n    let gas_estimate = api\n        .estimate_gas(WithOtherFields::new(tx), None, EvmOverrides::new(Some(state_override), None))\n        .await\n        .expect(\"Failed to estimate gas with state override\");\n\n    // Assert the gas estimate meets the expected minimum.\n    assert!(gas_estimate >= U256::from(21000), \"Gas estimate is lower than expected minimum\");\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_block_override() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n\n    let wallet = handle.dev_wallets().next().unwrap();\n    let sender = wallet.address();\n    let recipient = Address::random();\n\n    let tx = TransactionRequest::default()\n        .from(sender)\n        .to(recipient)\n        .input(Bytes::from(hex!(\"42cbb15c\").to_vec()).into());\n\n    //     function getBlockNumber() external view returns (uint256) {\n    //         return block.number;\n    //     }\n    let code = hex!(\n        \"6080604052348015600e575f5ffd5b50600436106026575f3560e01c806342cbb15c14602a575b5f5ffd5b60306044565b604051603b91906061565b60405180910390f35b5f43905090565b5f819050919050565b605b81604b565b82525050565b5f60208201905060725f8301846054565b9291505056fea26469706673582212207741266d8151c5e7d1a96fc1697f8fc94e60e730b3f2861d398339c74a2180d464736f6c634300081e0033\"\n    );\n\n    let account_override =\n        AccountOverride { balance: Some(U256::from(1e18)), ..Default::default() };\n    let state_override = StateOverridesBuilder::default()\n        .append(sender, account_override)\n        .append(recipient, AccountOverride::default().with_code(code.to_vec()))\n        .build();\n\n    let block_override = BlockOverrides { number: Some(U256::from(99)), ..Default::default() };\n\n    let output = api\n        .call(\n            WithOtherFields::new(tx),\n            None,\n            EvmOverrides::new(Some(state_override), Some(Box::new(block_override))),\n        )\n        .await\n        .expect(\"Failed to estimate gas with state override\");\n\n    assert_eq!(output, U256::from(99).abi_encode());\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_reject_gas_too_low() {\n    let (_api, handle) = spawn(NodeConfig::test()).await;\n    let provider = handle.http_provider();\n\n    let account = handle.dev_accounts().next().unwrap();\n\n    let gas = 21_000u64 - 1;\n    let tx = TransactionRequest::default()\n        .to(Address::random())\n        .value(U256::from(1337u64))\n        .from(account)\n        .with_gas_limit(gas);\n    let tx = WithOtherFields::new(tx);\n\n    let resp = provider.send_transaction(tx).await;\n\n    let err = resp.unwrap_err().to_string();\n    assert!(err.contains(\"intrinsic gas too low\"));\n}\n\n// <https://github.com/foundry-rs/foundry/issues/3783>\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_call_with_high_gas_limit() {\n    let (_api, handle) = spawn(NodeConfig::test().with_gas_limit(Some(100_000_000))).await;\n    let provider = handle.http_provider();\n\n    let greeter_contract = Greeter::deploy(provider, \"Hello World!\".to_string()).await.unwrap();\n\n    let greeting = greeter_contract.greet().gas(60_000_000).call().await.unwrap();\n    assert_eq!(\"Hello World!\", greeting);\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn test_reject_eip1559_pre_london() {\n    let (api, handle) =\n        spawn(NodeConfig::test().with_hardfork(Some(EthereumHardfork::Berlin.into()))).await;\n    let provider = handle.http_provider();\n\n    let gas_limit = api.gas_limit().to::<u64>();\n    let gas_price = api.gas_price();\n\n    let unsupported_call_builder =\n        Greeter::deploy_builder(provider.clone(), \"Hello World!\".to_string());\n    let unsupported_calldata = unsupported_call_builder.calldata();\n\n    let unsup_tx = TransactionRequest::default()\n        .from(handle.dev_accounts().next().unwrap())\n        .with_input(unsupported_calldata.to_owned())\n        .with_gas_limit(gas_limit)\n        .with_max_fee_per_gas(gas_price)\n        .with_max_priority_fee_per_gas(gas_price);\n\n    let unsup_tx = WithOtherFields::new(unsup_tx);\n\n    let unsupported = provider.send_transaction(unsup_tx).await.unwrap_err().to_string();\n    assert!(unsupported.contains(\"not supported by the current hardfork\"), \"{unsupported}\");\n\n    let greeter_contract_addr =\n        Greeter::deploy_builder(provider.clone(), \"Hello World!\".to_string())\n            .gas(gas_limit)\n            .gas_price(gas_price)\n            .deploy()\n            .await\n            .unwrap();\n\n    let greeter_contract = Greeter::new(greeter_contract_addr, provider);\n\n    let greeting = greeter_contract.greet().call().await.unwrap();\n    assert_eq!(\"Hello World!\", greeting);\n}\n\n// https://github.com/foundry-rs/foundry/issues/6931\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_mine_multiple_in_block() {\n    let (api, _handle) = spawn(NodeConfig::test()).await;\n\n    // disable auto mine\n    api.anvil_set_auto_mine(false).await.unwrap();\n\n    let tx = TransactionRequest {\n        from: Some(\"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266\".parse().unwrap()),\n        ..Default::default()\n    };\n\n    // broadcast it via the eth_sendTransaction API\n    let first = api.send_transaction(WithOtherFields::new(tx.clone())).await.unwrap();\n    let second = api.send_transaction(WithOtherFields::new(tx.clone())).await.unwrap();\n\n    api.anvil_mine(Some(U256::from(1)), Some(U256::ZERO)).await.unwrap();\n\n    let block = api.block_by_number(BlockNumberOrTag::Latest).await.unwrap().unwrap();\n\n    let txs = block.transactions.hashes().collect::<Vec<_>>();\n    assert_eq!(txs, vec![first, second]);\n}\n\n// ensures that the gas estimate is running on pending block by default\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_estimate_gas_prague() {\n    let (api, _handle) =\n        spawn(NodeConfig::test().with_hardfork(Some(EthereumHardfork::Prague.into()))).await;\n\n    // {\"data\":\"0xcafebabe\",\"from\":\"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266\",\"to\":\"\n    // 0x70997970c51812dc3a010c7d01b50e0d17dc79c8\"}\n    let req = TransactionRequest::default()\n        .with_input(hex!(\"0xcafebabe\"))\n        .with_from(address!(\"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266\"))\n        .with_to(address!(\"0x70997970c51812dc3a010c7d01b50e0d17dc79c8\"));\n    api.estimate_gas(WithOtherFields::new(req), None, EvmOverrides::default()).await.unwrap();\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_send_tx_osaka_valid_with_limit_enabled() {\n    let (_api, handle) = spawn(\n        NodeConfig::test()\n            .enable_tx_gas_limit(true)\n            .with_hardfork(Some(EthereumHardfork::Osaka.into())),\n    )\n    .await;\n    let provider = handle.http_provider();\n    let wallet = handle.dev_wallets().next().unwrap();\n    let sender = wallet.address();\n    let recipient = Address::random();\n\n    let base_tx = TransactionRequest::default().from(sender).to(recipient).value(U256::from(1e18));\n\n    // gas limit below the cap is accepted\n    let tx = base_tx.clone().gas_limit(TX_GAS_LIMIT_CAP - 1);\n    let tx = WithOtherFields::new(tx);\n    let pending_tx = provider.send_transaction(tx).await.unwrap();\n    let tx_receipt = pending_tx.get_receipt().await.unwrap();\n    assert!(tx_receipt.inner.inner.is_success());\n\n    // gas limit at the cap is accepted\n    let tx = base_tx.clone().gas_limit(TX_GAS_LIMIT_CAP);\n    let tx = WithOtherFields::new(tx);\n    let pending_tx = provider.send_transaction(tx).await.unwrap();\n    let tx_receipt = pending_tx.get_receipt().await.unwrap();\n    assert!(tx_receipt.inner.inner.is_success());\n\n    // gas limit above the cap is rejected\n    let tx = base_tx.clone().gas_limit(TX_GAS_LIMIT_CAP + 1);\n    let tx = WithOtherFields::new(tx);\n    let err = provider.send_transaction(tx).await.unwrap_err().to_string();\n    assert!(\n        err.contains(\"intrinsic gas too high -- tx.gas_limit > env.cfg.tx_gas_limit_cap\"),\n        \"{err}\"\n    );\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_send_tx_osaka_valid_with_limit_disabled() {\n    let (_api, handle) =\n        spawn(NodeConfig::test().with_hardfork(Some(EthereumHardfork::Osaka.into()))).await;\n    let provider = handle.http_provider();\n    let wallet = handle.dev_wallets().next().unwrap();\n    let sender = wallet.address();\n    let recipient = Address::random();\n\n    let base_tx = TransactionRequest::default().from(sender).to(recipient).value(U256::from(1e18));\n\n    // gas limit below the cap is accepted\n    let tx = base_tx.clone().gas_limit(TX_GAS_LIMIT_CAP - 1);\n    let tx = WithOtherFields::new(tx);\n    let pending_tx = provider.send_transaction(tx).await.unwrap();\n    let tx_receipt = pending_tx.get_receipt().await.unwrap();\n    assert!(tx_receipt.inner.inner.is_success());\n\n    // gas limit at the cap is accepted\n    let tx = base_tx.clone().gas_limit(TX_GAS_LIMIT_CAP);\n    let tx = WithOtherFields::new(tx);\n    let pending_tx = provider.send_transaction(tx).await.unwrap();\n    let tx_receipt = pending_tx.get_receipt().await.unwrap();\n    assert!(tx_receipt.inner.inner.is_success());\n\n    // gas limit above the cap is accepted when the limit is disabled\n    let tx = base_tx.clone().gas_limit(TX_GAS_LIMIT_CAP + 1);\n    let tx = WithOtherFields::new(tx);\n    let pending_tx = provider.send_transaction(tx).await.unwrap();\n    let tx_receipt = pending_tx.get_receipt().await.unwrap();\n    assert!(tx_receipt.inner.inner.is_success());\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_get_tx_by_sender_and_nonce() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n    let provider = handle.http_provider();\n\n    let accounts = handle.dev_wallets().collect::<Vec<_>>();\n    let sender = accounts[0].address();\n    let recipient = accounts[1].address();\n\n    api.anvil_set_auto_mine(false).await.unwrap();\n\n    let mut tx_hashes = std::collections::BTreeMap::new();\n\n    // send 4 transactions from the same sender with consecutive nonces\n    for i in 0..4 {\n        let tx_request = TransactionRequest::default()\n            .to(recipient)\n            .value(U256::from(1000 + i))\n            .from(sender)\n            .nonce(i as u64);\n\n        let tx = WithOtherFields::new(tx_request);\n        let pending_tx = provider.send_transaction(tx).await.unwrap();\n        tx_hashes.insert(i as u64, *pending_tx.tx_hash());\n    }\n\n    // mine all transactions\n    api.mine_one().await;\n\n    for nonce in 0..4 {\n        let result: Option<alloy_network::AnyRpcTransaction> = provider\n            .client()\n            .request(\"eth_getTransactionBySenderAndNonce\", (sender, U256::from(nonce)))\n            .await\n            .unwrap();\n\n        assert!(result.is_some());\n        let found_tx = result.unwrap();\n\n        assert_eq!(found_tx.inner.nonce(), nonce);\n        assert_eq!(found_tx.from(), sender);\n        assert_eq!(found_tx.inner.to(), Some(recipient));\n        assert_eq!(found_tx.inner.value(), U256::from(1000 + nonce));\n        assert_eq!(found_tx.inner.tx_hash(), tx_hashes[&nonce]);\n    }\n\n    let result: Option<alloy_network::AnyRpcTransaction> = provider\n        .client()\n        .request(\"eth_getTransactionBySenderAndNonce\", (sender, U256::from(999)))\n        .await\n        .unwrap();\n    assert!(result.is_none());\n\n    let different_sender = accounts[2].address();\n    let result: Option<alloy_network::AnyRpcTransaction> = provider\n        .client()\n        .request(\"eth_getTransactionBySenderAndNonce\", (different_sender, U256::from(0)))\n        .await\n        .unwrap();\n    assert!(result.is_none());\n\n    // send a pending transaction with explicit nonce 4\n    let pending_tx_request =\n        TransactionRequest::default().to(recipient).value(U256::from(5000)).from(sender).nonce(4);\n\n    let tx = WithOtherFields::new(pending_tx_request);\n    let pending_tx = provider.send_transaction(tx).await.unwrap();\n\n    // find the pending transaction with nonce 4\n    let result: Option<alloy_network::AnyRpcTransaction> = provider\n        .client()\n        .request(\"eth_getTransactionBySenderAndNonce\", (sender, U256::from(4)))\n        .await\n        .unwrap();\n\n    assert!(result.is_some());\n    let found_tx = result.unwrap();\n    assert_eq!(found_tx.inner.nonce(), 4);\n    assert_eq!(found_tx.inner.tx_hash(), *pending_tx.tx_hash());\n\n    api.mine_one().await;\n\n    let result: Option<alloy_network::AnyRpcTransaction> = provider\n        .client()\n        .request(\"eth_getTransactionBySenderAndNonce\", (sender, U256::from(4)))\n        .await\n        .unwrap();\n\n    assert!(result.is_some());\n    let found_tx = result.unwrap();\n    assert_eq!(found_tx.inner.nonce(), 4);\n}\n"
  },
  {
    "path": "crates/anvil/tests/it/txpool.rs",
    "content": "//! txpool related tests\n\nuse alloy_network::{ReceiptResponse, TransactionBuilder};\nuse alloy_primitives::U256;\nuse alloy_provider::{Provider, ext::TxPoolApi};\nuse alloy_rpc_types::TransactionRequest;\nuse alloy_serde::WithOtherFields;\nuse anvil::{NodeConfig, spawn};\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn geth_txpool() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n    let provider = handle.http_provider();\n\n    api.anvil_set_auto_mine(false).await.unwrap();\n\n    let account = provider.get_accounts().await.unwrap().remove(0);\n    let value = U256::from(42);\n    let gas_price = 221435145689u128;\n\n    let tx = TransactionRequest::default()\n        .with_to(account)\n        .with_from(account)\n        .with_value(value)\n        .with_gas_price(gas_price);\n    let tx = WithOtherFields::new(tx);\n\n    // send a few transactions\n    for _ in 0..10 {\n        let _ = provider.send_transaction(tx.clone()).await.unwrap();\n    }\n\n    // we gave a 20s block time, should be plenty for us to get the txpool's content\n    let status = provider.txpool_status().await.unwrap();\n    assert_eq!(status.pending, 10);\n    assert_eq!(status.queued, 0);\n\n    let inspect = provider.txpool_inspect().await.unwrap();\n    assert!(inspect.queued.is_empty());\n    let summary = inspect.pending.get(&account).unwrap();\n    for i in 0..10 {\n        let tx_summary = summary.get(&i.to_string()).unwrap();\n        assert_eq!(tx_summary.gas_price, gas_price);\n        assert_eq!(tx_summary.value, value);\n        assert_eq!(tx_summary.gas, 21000);\n        assert_eq!(tx_summary.to.unwrap(), account);\n    }\n\n    let content = provider.txpool_content().await.unwrap();\n    assert!(content.queued.is_empty());\n    let content = content.pending.get(&account).unwrap();\n\n    for nonce in 0..10 {\n        assert!(content.contains_key(&nonce.to_string()));\n    }\n}\n\n// Cf. https://github.com/foundry-rs/foundry/issues/11239\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn accepts_spend_after_funding_when_pool_checks_disabled() {\n    // Spawn with pool balance checks disabled\n    let (api, handle) = spawn(NodeConfig::test().with_disable_pool_balance_checks(true)).await;\n    let provider = handle.http_provider();\n\n    // Work with pending pool (no automine)\n    api.anvil_set_auto_mine(false).await.unwrap();\n\n    // Funder is a dev account controlled by the node\n    let funder = provider.get_accounts().await.unwrap().remove(0);\n\n    // Recipient/spender is a random address with zero balance that we'll impersonate\n    let spender = alloy_primitives::Address::random();\n    api.anvil_set_balance(spender, U256::from(0u64)).await.unwrap();\n    api.anvil_impersonate_account(spender).await.unwrap();\n\n    // Ensure tx1 (funding) has higher gas price so it's mined before tx2 within the same block\n    let gas_price_fund = 2_000_000_000_000u128; // 2_000 gwei\n    let gas_price_spend = 1_000_000_000u128; // 1 gwei\n\n    let fund_value = U256::from(1_000_000_000_000_000_000u128); // 1 ether\n\n    // tx1: fund spender from funder\n    let tx1 = TransactionRequest::default()\n        .with_from(funder)\n        .with_to(spender)\n        .with_value(fund_value)\n        .with_gas_price(gas_price_fund);\n    let tx1 = WithOtherFields::new(tx1);\n\n    // tx2: spender attempts to send value greater than their pre-funding balance (0),\n    // which would normally be rejected by pool balance checks, but should be accepted when disabled\n    let spend_value = fund_value - U256::from(21_000u64) * U256::from(gas_price_spend);\n    let tx2 = TransactionRequest::default()\n        .with_from(spender)\n        .with_to(funder)\n        .with_value(spend_value)\n        .with_gas_price(gas_price_spend);\n    let tx2 = WithOtherFields::new(tx2);\n\n    // Publish both transactions (funding first, then spend-before-funding-is-mined)\n    let sent1 = provider.send_transaction(tx1).await.unwrap();\n    let sent2 = provider.send_transaction(tx2).await.unwrap();\n\n    // Both should be accepted into the pool (pending)\n    let status = provider.txpool_status().await.unwrap();\n    assert_eq!(status.pending, 2);\n    assert_eq!(status.queued, 0);\n\n    // Mine a block and ensure both succeed\n    api.evm_mine(None).await.unwrap();\n\n    let receipt1 = sent1.get_receipt().await.unwrap();\n    let receipt2 = sent2.get_receipt().await.unwrap();\n    assert!(receipt1.status());\n    assert!(receipt2.status());\n}\n"
  },
  {
    "path": "crates/anvil/tests/it/utils.rs",
    "content": "use alloy_network::{Ethereum, EthereumWallet};\nuse alloy_provider::{\n    Identity, RootProvider,\n    fillers::{ChainIdFiller, FillProvider, GasFiller, JoinFill, NonceFiller, WalletFiller},\n};\nuse foundry_common::provider::{\n    ProviderBuilder, RetryProvider, RetryProviderWithSigner, get_http_provider,\n};\n\npub fn http_provider(http_endpoint: &str) -> RetryProvider {\n    get_http_provider(http_endpoint)\n}\n\npub fn http_provider_with_signer(\n    http_endpoint: &str,\n    signer: EthereumWallet,\n) -> RetryProviderWithSigner {\n    ProviderBuilder::new(http_endpoint)\n        .build_with_wallet(signer)\n        .expect(\"failed to build Alloy HTTP provider with signer\")\n}\n\npub fn ws_provider_with_signer(\n    ws_endpoint: &str,\n    signer: EthereumWallet,\n) -> RetryProviderWithSigner {\n    ProviderBuilder::new(ws_endpoint)\n        .build_with_wallet(signer)\n        .expect(\"failed to build Alloy WS provider with signer\")\n}\n\n/// Currently required to get around <https://github.com/alloy-rs/alloy/issues/296>\npub async fn connect_pubsub(conn_str: &str) -> RootProvider {\n    alloy_provider::ProviderBuilder::default().connect(conn_str).await.unwrap()\n}\n\ntype PubsubSigner = FillProvider<\n    JoinFill<\n        JoinFill<\n            Identity,\n            JoinFill<\n                GasFiller,\n                JoinFill<\n                    alloy_provider::fillers::BlobGasFiller,\n                    JoinFill<NonceFiller, ChainIdFiller>,\n                >,\n            >,\n        >,\n        WalletFiller<EthereumWallet>,\n    >,\n    RootProvider,\n    Ethereum,\n>;\n\npub async fn connect_pubsub_with_wallet(conn_str: &str, wallet: EthereumWallet) -> PubsubSigner {\n    alloy_provider::ProviderBuilder::new().wallet(wallet).connect(conn_str).await.unwrap()\n}\n\npub async fn ipc_provider_with_wallet(\n    ipc_endpoint: &str,\n    wallet: EthereumWallet,\n) -> RetryProviderWithSigner {\n    ProviderBuilder::new(ipc_endpoint)\n        .build_with_wallet(wallet)\n        .expect(\"failed to build Alloy IPC provider with signer\")\n}\n"
  },
  {
    "path": "crates/anvil/tests/it/wsapi.rs",
    "content": "//! general eth api tests with websocket provider\n\nuse alloy_primitives::U256;\nuse alloy_provider::Provider;\nuse anvil::{NodeConfig, spawn};\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_get_block_number_ws() {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n    let block_num = api.block_number().unwrap();\n    assert_eq!(block_num, U256::ZERO);\n\n    let provider = handle.ws_provider();\n\n    let num = provider.get_block_number().await.unwrap();\n    assert_eq!(num, block_num.to::<u64>());\n}\n\n#[tokio::test(flavor = \"multi_thread\")]\nasync fn can_dev_get_balance_ws() {\n    let (_api, handle) = spawn(NodeConfig::test()).await;\n    let provider = handle.ws_provider();\n\n    let genesis_balance = handle.genesis_balance();\n    for acc in handle.genesis_accounts() {\n        let balance = provider.get_balance(acc).await.unwrap();\n        assert_eq!(balance, genesis_balance);\n    }\n}\n"
  },
  {
    "path": "crates/cast/Cargo.toml",
    "content": "[package]\nname = \"cast\"\ndescription = \"Command-line tool for performing Ethereum RPC calls\"\n\nversion.workspace = true\nedition.workspace = true\nrust-version.workspace = true\nauthors.workspace = true\nlicense.workspace = true\nhomepage.workspace = true\nrepository.workspace = true\n\n[lints]\nworkspace = true\n\n[lib]\nname = \"cast\"\n\n[[bin]]\nname = \"cast\"\npath = \"bin/main.rs\"\n\n[dependencies]\n# lib\nfoundry-block-explorers.workspace = true\nfoundry-common.workspace = true\nfoundry-compilers.workspace = true\nfoundry-config.workspace = true\nfoundry-debugger.workspace = true\nfoundry-evm.workspace = true\nfoundry-wallets.workspace = true\nforge-fmt.workspace = true\nfoundry-primitives.workspace = true\n\nalloy-chains.workspace = true\nalloy-consensus = { workspace = true, features = [\"serde\", \"kzg\"] }\nalloy-contract.workspace = true\nalloy-dyn-abi.workspace = true\nalloy-json-abi.workspace = true\nalloy-json-rpc.workspace = true\nalloy-network.workspace = true\nalloy-primitives.workspace = true\nalloy-provider = { workspace = true, features = [\n    \"reqwest\",\n    \"ws\",\n    \"ipc\",\n    \"trace-api\",\n    \"txpool-api\",\n] }\nalloy-rlp.workspace = true\nalloy-rpc-types = { workspace = true, features = [\"eth\", \"trace\"] }\nalloy-rpc-types-beacon.workspace = true\nalloy-signer-local = { workspace = true, features = [\"mnemonic\", \"keystore\"] }\nalloy-signer.workspace = true\nalloy-sol-types.workspace = true\nalloy-transport.workspace = true\nalloy-ens = { workspace = true, features = [\"provider\"] }\nalloy-eips.workspace = true\ntempo-alloy.workspace = true\nalloy-evm.workspace = true\n\nop-alloy-flz.workspace = true\nop-alloy-network.workspace = true\n\nchrono.workspace = true\neyre.workspace = true\nfutures.workspace = true\nrevm = { workspace = true, features = [\"optional_balance_check\"] }\nrand.workspace = true\nrand_08.workspace = true\nrayon.workspace = true\nserde_json.workspace = true\nserde.workspace = true\n\n# bin\nfoundry-cli.workspace = true\n\nclap = { version = \"4\", features = [\"derive\", \"env\", \"unicode\", \"wrap_help\"] }\nclap_complete.workspace = true\ncomfy-table.workspace = true\ndunce.workspace = true\nitertools.workspace = true\nregex = { workspace = true, default-features = false }\nrpassword = \"7\"\nsemver.workspace = true\ntempfile.workspace = true\ntokio = { workspace = true, features = [\"macros\", \"signal\"] }\ntracing.workspace = true\nyansi.workspace = true\nevmole.workspace = true\n\n[dev-dependencies]\nalloy-hardforks.workspace = true\nalloy-serde.workspace = true\ndirs.workspace = true\nanvil.workspace = true\nfoundry-test-utils.workspace = true\n\n[features]\ndefault = [\"jemalloc\"]\nasm-keccak = [\"alloy-primitives/asm-keccak\"]\njemalloc = [\"foundry-cli/jemalloc\"]\nmimalloc = [\"foundry-cli/mimalloc\"]\ntracy-allocator = [\"foundry-cli/tracy-allocator\"]\naws-kms = [\"foundry-wallets/aws-kms\"]\ngcp-kms = [\"foundry-wallets/gcp-kms\"]\nturnkey = [\"foundry-wallets/turnkey\"]\nisolate-by-default = [\"foundry-config/isolate-by-default\"]\n"
  },
  {
    "path": "crates/cast/bin/main.rs",
    "content": "//! The `cast` CLI: a Swiss Army knife for interacting with EVM smart contracts, sending\n//! transactions and getting chain data.\n\nuse cast::args::run;\n\n#[global_allocator]\nstatic ALLOC: foundry_cli::utils::Allocator = foundry_cli::utils::new_allocator();\n\nfn main() {\n    if let Err(err) = run() {\n        let _ = foundry_common::sh_err!(\"{err:?}\");\n        std::process::exit(1);\n    }\n}\n"
  },
  {
    "path": "crates/cast/src/args.rs",
    "content": "use crate::{\n    Cast, SimpleCast,\n    cmd::erc20::IERC20,\n    opts::{Cast as CastArgs, CastSubcommand, ToBaseArgs},\n    traces::identifier::SignaturesIdentifier,\n    tx::CastTxSender,\n};\nuse alloy_consensus::transaction::Recovered;\nuse alloy_dyn_abi::{DynSolValue, ErrorExt, EventExt};\nuse alloy_eips::eip7702::SignedAuthorization;\nuse alloy_ens::{ProviderEnsExt, namehash};\nuse alloy_network::Ethereum;\nuse alloy_primitives::{Address, B256, eip191_hash_message, hex, keccak256};\nuse alloy_provider::Provider;\nuse alloy_rpc_types::{BlockId, BlockNumberOrTag::Latest};\nuse clap::{CommandFactory, Parser};\nuse clap_complete::generate;\nuse eyre::Result;\nuse foundry_cli::{\n    opts::NetworkVariant,\n    utils::{self, LoadConfig},\n};\nuse foundry_common::{\n    abi::{get_error, get_event},\n    fmt::{format_tokens, format_uint_exp, serialize_value_as_json},\n    fs,\n    provider::ProviderBuilder,\n    selectors::{\n        ParsedSignatures, SelectorImportData, SelectorKind, decode_calldata, decode_event_topic,\n        decode_function_selector, decode_selectors, import_selectors, parse_signatures,\n        pretty_calldata,\n    },\n    shell, stdin,\n};\nuse op_alloy_network::Optimism;\nuse std::time::Instant;\nuse tempo_alloy::TempoNetwork;\n\n/// Run the `cast` command-line interface.\npub fn run() -> Result<()> {\n    setup()?;\n\n    foundry_cli::opts::GlobalArgs::check_markdown_help::<CastArgs>();\n\n    let args = CastArgs::parse();\n    args.global.init()?;\n    args.global.tokio_runtime().block_on(run_command(args))\n}\n\n/// Setup the global logger and other utilities.\npub fn setup() -> Result<()> {\n    utils::common_setup();\n    utils::subscriber();\n\n    Ok(())\n}\n\n/// Run the subcommand.\npub async fn run_command(args: CastArgs) -> Result<()> {\n    match args.cmd {\n        // Constants\n        CastSubcommand::MaxInt { r#type } => {\n            sh_println!(\"{}\", SimpleCast::max_int(&r#type)?)?;\n        }\n        CastSubcommand::MinInt { r#type } => {\n            sh_println!(\"{}\", SimpleCast::min_int(&r#type)?)?;\n        }\n        CastSubcommand::MaxUint { r#type } => {\n            sh_println!(\"{}\", SimpleCast::max_int(&r#type)?)?;\n        }\n        CastSubcommand::AddressZero => {\n            sh_println!(\"{:?}\", Address::ZERO)?;\n        }\n        CastSubcommand::HashZero => {\n            sh_println!(\"{:?}\", B256::ZERO)?;\n        }\n\n        // Conversions & transformations\n        CastSubcommand::FromUtf8 { text } => {\n            let value = stdin::unwrap(text, false)?;\n            sh_println!(\"{}\", SimpleCast::from_utf8(&value))?\n        }\n        CastSubcommand::ToAscii { hexdata } => {\n            let value = stdin::unwrap(hexdata, false)?;\n            sh_println!(\"{}\", SimpleCast::to_ascii(value.trim())?)?\n        }\n        CastSubcommand::ToUtf8 { hexdata } => {\n            let value = stdin::unwrap(hexdata, false)?;\n            sh_println!(\"{}\", SimpleCast::to_utf8(&value)?)?\n        }\n        CastSubcommand::FromFixedPoint { value, decimals } => {\n            let (value, decimals) = stdin::unwrap2(value, decimals)?;\n            sh_println!(\"{}\", SimpleCast::from_fixed_point(&value, &decimals)?)?\n        }\n        CastSubcommand::ToFixedPoint { value, decimals } => {\n            let (value, decimals) = stdin::unwrap2(value, decimals)?;\n            sh_println!(\"{}\", SimpleCast::to_fixed_point(&value, &decimals)?)?\n        }\n        CastSubcommand::ConcatHex { data } => {\n            if data.is_empty() {\n                let s = stdin::read(true)?;\n                sh_println!(\"{}\", SimpleCast::concat_hex(s.split_whitespace()))?\n            } else {\n                sh_println!(\"{}\", SimpleCast::concat_hex(data))?\n            }\n        }\n        CastSubcommand::FromBin => {\n            let hex = stdin::read_bytes(false)?;\n            sh_println!(\"{}\", hex::encode_prefixed(hex))?\n        }\n        CastSubcommand::ToHexdata { input } => {\n            let value = stdin::unwrap_line(input)?;\n            let output = match value {\n                s if s.starts_with('@') => hex::encode(std::env::var(&s[1..])?),\n                s if s.starts_with('/') => hex::encode(fs::read(s)?),\n                s => s.split(':').map(|s| s.trim_start_matches(\"0x\").to_lowercase()).collect(),\n            };\n            sh_println!(\"0x{output}\")?\n        }\n        CastSubcommand::ToCheckSumAddress { address, chain_id } => {\n            let value = stdin::unwrap_line(address)?;\n            sh_println!(\"{}\", value.to_checksum(chain_id))?\n        }\n        CastSubcommand::ToUint256 { value } => {\n            let value = stdin::unwrap_line(value)?;\n            sh_println!(\"{}\", SimpleCast::to_uint256(&value)?)?\n        }\n        CastSubcommand::ToInt256 { value } => {\n            let value = stdin::unwrap_line(value)?;\n            sh_println!(\"{}\", SimpleCast::to_int256(&value)?)?\n        }\n        CastSubcommand::ToUnit { value, unit } => {\n            let value = stdin::unwrap_line(value)?;\n            sh_println!(\"{}\", SimpleCast::to_unit(&value, &unit)?)?\n        }\n        CastSubcommand::ParseUnits { value, unit } => {\n            let value = stdin::unwrap_line(value)?;\n            sh_println!(\"{}\", SimpleCast::parse_units(&value, unit)?)?;\n        }\n        CastSubcommand::FormatUnits { value, unit } => {\n            let value = stdin::unwrap_line(value)?;\n            sh_println!(\"{}\", SimpleCast::format_units(&value, unit)?)?;\n        }\n        CastSubcommand::FromWei { value, unit } => {\n            let value = stdin::unwrap_line(value)?;\n            sh_println!(\"{}\", SimpleCast::from_wei(&value, &unit)?)?\n        }\n        CastSubcommand::ToWei { value, unit } => {\n            let value = stdin::unwrap_line(value)?;\n            sh_println!(\"{}\", SimpleCast::to_wei(&value, &unit)?)?\n        }\n        CastSubcommand::FromRlp { value, as_int } => {\n            let value = stdin::unwrap_line(value)?;\n            sh_println!(\"{}\", SimpleCast::from_rlp(value, as_int)?)?\n        }\n        CastSubcommand::ToRlp { value } => {\n            let value = stdin::unwrap_line(value)?;\n            sh_println!(\"{}\", SimpleCast::to_rlp(&value)?)?\n        }\n        CastSubcommand::ToHex(ToBaseArgs { value, base_in }) => {\n            let value = stdin::unwrap_line(value)?;\n            sh_println!(\"{}\", SimpleCast::to_base(&value, base_in.as_deref(), \"hex\")?)?\n        }\n        CastSubcommand::ToDec(ToBaseArgs { value, base_in }) => {\n            let value = stdin::unwrap_line(value)?;\n            sh_println!(\"{}\", SimpleCast::to_base(&value, base_in.as_deref(), \"dec\")?)?\n        }\n        CastSubcommand::ToBase { base: ToBaseArgs { value, base_in }, base_out } => {\n            let (value, base_out) = stdin::unwrap2(value, base_out)?;\n            sh_println!(\"{}\", SimpleCast::to_base(&value, base_in.as_deref(), &base_out)?)?\n        }\n        CastSubcommand::ToBytes32 { bytes } => {\n            let value = stdin::unwrap_line(bytes)?;\n            sh_println!(\"{}\", SimpleCast::to_bytes32(&value)?)?\n        }\n        CastSubcommand::Pad { data, right, left: _, len } => {\n            let value = stdin::unwrap_line(data)?;\n            sh_println!(\"{}\", SimpleCast::pad(&value, right, len)?)?\n        }\n        CastSubcommand::FormatBytes32String { string } => {\n            let value = stdin::unwrap_line(string)?;\n            sh_println!(\"{}\", SimpleCast::format_bytes32_string(&value)?)?\n        }\n        CastSubcommand::ParseBytes32String { bytes } => {\n            let value = stdin::unwrap_line(bytes)?;\n            sh_println!(\"{}\", SimpleCast::parse_bytes32_string(&value)?)?\n        }\n        CastSubcommand::ParseBytes32Address { bytes } => {\n            let value = stdin::unwrap_line(bytes)?;\n            sh_println!(\"{}\", SimpleCast::parse_bytes32_address(&value)?)?\n        }\n\n        // ABI encoding & decoding\n        CastSubcommand::DecodeAbi { sig, calldata, input } => {\n            let tokens = SimpleCast::abi_decode(&sig, &calldata, input)?;\n            print_tokens(&tokens);\n        }\n        CastSubcommand::AbiEncode { sig, packed, args } => {\n            if !packed {\n                sh_println!(\"{}\", SimpleCast::abi_encode(&sig, &args)?)?\n            } else {\n                sh_println!(\"{}\", SimpleCast::abi_encode_packed(&sig, &args)?)?\n            }\n        }\n        CastSubcommand::AbiEncodeEvent { sig, args } => {\n            let log_data = SimpleCast::abi_encode_event(&sig, &args)?;\n            for (i, topic) in log_data.topics().iter().enumerate() {\n                sh_println!(\"[topic{}]: {}\", i, topic)?;\n            }\n            if !log_data.data.is_empty() {\n                sh_println!(\"[data]: {}\", hex::encode_prefixed(log_data.data))?;\n            }\n        }\n        CastSubcommand::DecodeCalldata { sig, calldata, file } => {\n            let raw_hex = if let Some(file_path) = file {\n                let contents = fs::read_to_string(&file_path)?;\n                contents.trim().to_string()\n            } else {\n                calldata.unwrap()\n            };\n\n            let tokens = SimpleCast::calldata_decode(&sig, &raw_hex, true)?;\n            print_tokens(&tokens);\n        }\n        CastSubcommand::CalldataEncode { sig, args, file } => {\n            let final_args = if let Some(file_path) = file {\n                let contents = fs::read_to_string(file_path)?;\n                contents\n                    .lines()\n                    .map(str::trim)\n                    .filter(|line| !line.is_empty())\n                    .map(String::from)\n                    .collect()\n            } else {\n                args\n            };\n            sh_println!(\"{}\", SimpleCast::calldata_encode(sig, &final_args)?)?;\n        }\n        CastSubcommand::DecodeString { data } => {\n            let tokens = SimpleCast::calldata_decode(\"Any(string)\", &data, true)?;\n            print_tokens(&tokens);\n        }\n        CastSubcommand::DecodeEvent { sig, data } => {\n            let decoded_event = if let Some(event_sig) = sig {\n                let event = get_event(event_sig.as_str())?;\n                event.decode_log_parts(core::iter::once(event.selector()), &hex::decode(data)?)?\n            } else {\n                let data = crate::strip_0x(&data);\n                let selector = data.get(..64).unwrap_or_default();\n                let selector = selector.parse()?;\n                let identified_event =\n                    SignaturesIdentifier::new(false)?.identify_event(selector).await;\n                if let Some(event) = identified_event {\n                    let _ = sh_println!(\"{}\", event.signature());\n                    let data = data.get(64..).unwrap_or_default();\n                    get_event(event.signature().as_str())?\n                        .decode_log_parts(core::iter::once(selector), &hex::decode(data)?)?\n                } else {\n                    eyre::bail!(\"No matching event signature found for selector `{selector}`\")\n                }\n            };\n            print_tokens(&decoded_event.body);\n        }\n        CastSubcommand::DecodeError { sig, data } => {\n            let error = if let Some(err_sig) = sig {\n                get_error(err_sig.as_str())?\n            } else {\n                let data = crate::strip_0x(&data);\n                let selector = data.get(..8).unwrap_or_default();\n                let identified_error =\n                    SignaturesIdentifier::new(false)?.identify_error(selector.parse()?).await;\n                if let Some(error) = identified_error {\n                    let _ = sh_println!(\"{}\", error.signature());\n                    error\n                } else {\n                    eyre::bail!(\"No matching error signature found for selector `{selector}`\")\n                }\n            };\n            let decoded_error = error.decode_error(&hex::decode(data)?)?;\n            print_tokens(&decoded_error.body);\n        }\n        CastSubcommand::Interface(cmd) => cmd.run().await?,\n        CastSubcommand::CreationCode(cmd) => cmd.run().await?,\n        CastSubcommand::ConstructorArgs(cmd) => cmd.run().await?,\n        CastSubcommand::Artifact(cmd) => cmd.run().await?,\n        CastSubcommand::Bind(cmd) => cmd.run().await?,\n        CastSubcommand::B2EPayload(cmd) => cmd.run().await?,\n        CastSubcommand::PrettyCalldata { calldata, offline } => {\n            let calldata = stdin::unwrap_line(calldata)?;\n            sh_println!(\"{}\", pretty_calldata(&calldata, offline).await?)?;\n        }\n        CastSubcommand::Sig { sig, optimize } => {\n            let sig = stdin::unwrap_line(sig)?;\n            match optimize {\n                Some(opt) => {\n                    sh_println!(\"Starting to optimize signature...\")?;\n                    let start_time = Instant::now();\n                    let (selector, signature) = SimpleCast::get_selector(&sig, opt)?;\n                    sh_println!(\"Successfully generated in {:?}\", start_time.elapsed())?;\n                    sh_println!(\"Selector: {selector}\")?;\n                    sh_println!(\"Optimized signature: {signature}\")?;\n                }\n                None => sh_println!(\"{}\", SimpleCast::get_selector(&sig, 0)?.0)?,\n            }\n        }\n\n        // Blockchain & RPC queries\n        CastSubcommand::AccessList(cmd) => cmd.run().await?,\n        CastSubcommand::Age { block, rpc } => {\n            let config = rpc.load_config()?;\n            let provider = utils::get_provider(&config)?;\n            sh_println!(\n                \"{} UTC\",\n                Cast::new(provider).age(block.unwrap_or(BlockId::Number(Latest))).await?\n            )?\n        }\n        CastSubcommand::Balance { block, who, ether, rpc, erc20 } => {\n            let config = rpc.load_config()?;\n            let provider = utils::get_provider(&config)?;\n            let account_addr = who.resolve(&provider).await?;\n\n            match erc20 {\n                Some(token) => {\n                    let balance = IERC20::new(token, &provider)\n                        .balanceOf(account_addr)\n                        .block(block.unwrap_or_default())\n                        .call()\n                        .await?;\n\n                    sh_warn!(\"--erc20 flag is deprecated, use `cast erc20 balance` instead\")?;\n                    sh_println!(\"{}\", format_uint_exp(balance))?\n                }\n                None => {\n                    let value = Cast::new(&provider).balance(account_addr, block).await?;\n                    if ether {\n                        sh_println!(\"{}\", SimpleCast::from_wei(&value.to_string(), \"eth\")?)?\n                    } else {\n                        sh_println!(\"{value}\")?\n                    }\n                }\n            }\n        }\n        CastSubcommand::BaseFee { block, rpc } => {\n            let config = rpc.load_config()?;\n            let provider = utils::get_provider(&config)?;\n            sh_println!(\n                \"{}\",\n                Cast::new(provider).base_fee(block.unwrap_or(BlockId::Number(Latest))).await?\n            )?\n        }\n        CastSubcommand::Block { block, full, fields, raw, rpc, network } => {\n            let config = rpc.load_config()?;\n            // Can use either --raw or specify raw as a field\n            let output = if raw || fields.contains(&\"raw\".into()) {\n                match network {\n                    Some(NetworkVariant::Optimism) => {\n                        let provider =\n                            ProviderBuilder::<Optimism>::from_config(&config)?.build()?;\n\n                        Cast::new(&provider)\n                            .block_raw(block.unwrap_or(BlockId::Number(Latest)), full)\n                            .await?\n                    }\n                    Some(NetworkVariant::Tempo) => {\n                        let provider =\n                            ProviderBuilder::<TempoNetwork>::from_config(&config)?.build()?;\n                        Cast::new(&provider)\n                            .block_raw(block.unwrap_or(BlockId::Number(Latest)), full)\n                            .await?\n                    }\n                    // Ethereum (default) or no --raw flag\n                    _ => {\n                        let provider =\n                            ProviderBuilder::<Ethereum>::from_config(&config)?.build()?;\n                        Cast::new(&provider)\n                            .block_raw(block.unwrap_or(BlockId::Number(Latest)), full)\n                            .await?\n                    }\n                }\n            } else {\n                let provider = utils::get_provider(&config)?;\n                Cast::new(provider)\n                    .block(block.unwrap_or(BlockId::Number(Latest)), full, fields)\n                    .await?\n            };\n            sh_println!(\"{}\", output)?\n        }\n        CastSubcommand::BlockNumber { rpc, block } => {\n            let config = rpc.load_config()?;\n            let provider = utils::get_provider(&config)?;\n            let number = match block {\n                Some(id) => {\n                    provider\n                        .get_block(id)\n                        .await?\n                        .ok_or_else(|| eyre::eyre!(\"block {id:?} not found\"))?\n                        .header\n                        .number\n                }\n                None => Cast::new(provider).block_number().await?,\n            };\n            sh_println!(\"{number}\")?\n        }\n        CastSubcommand::Chain { rpc } => {\n            let config = rpc.load_config()?;\n            let provider = utils::get_provider(&config)?;\n            sh_println!(\"{}\", Cast::new(provider).chain().await?)?\n        }\n        CastSubcommand::ChainId { rpc } => {\n            let config = rpc.load_config()?;\n            let provider = utils::get_provider(&config)?;\n            sh_println!(\"{}\", Cast::new(provider).chain_id().await?)?\n        }\n        CastSubcommand::Client { rpc } => {\n            let config = rpc.load_config()?;\n            let provider = utils::get_provider(&config)?;\n            sh_println!(\"{}\", provider.get_client_version().await?)?\n        }\n        CastSubcommand::Code { block, who, disassemble, rpc } => {\n            let config = rpc.load_config()?;\n            let provider = utils::get_provider(&config)?;\n            let who = who.resolve(&provider).await?;\n            sh_println!(\"{}\", Cast::new(provider).code(who, block, disassemble).await?)?\n        }\n        CastSubcommand::Codesize { block, who, rpc } => {\n            let config = rpc.load_config()?;\n            let provider = utils::get_provider(&config)?;\n            let who = who.resolve(&provider).await?;\n            sh_println!(\"{}\", Cast::new(provider).codesize(who, block).await?)?\n        }\n        CastSubcommand::ComputeAddress { address, nonce, salt, init_code, init_code_hash, rpc } => {\n            let address = stdin::unwrap_line(address)?;\n            let computed = {\n                // For CREATE2, init_code_hash is needed to compute the address\n                if let Some(init_code_hash) = init_code_hash {\n                    address.create2(salt.unwrap_or(B256::ZERO), init_code_hash)\n                } else if let Some(init_code) = init_code {\n                    address.create2(salt.unwrap_or(B256::ZERO), keccak256(hex::decode(init_code)?))\n                } else {\n                    // For CREATE, rpc is needed to compute the address\n                    let config = rpc.load_config()?;\n                    let provider = utils::get_provider(&config)?;\n                    Cast::new(provider).compute_address(address, nonce).await?\n                }\n            };\n            sh_println!(\"Computed Address: {}\", computed.to_checksum(None))?\n        }\n        CastSubcommand::Disassemble { bytecode } => {\n            let bytecode = stdin::unwrap_line(bytecode)?;\n            sh_println!(\"{}\", SimpleCast::disassemble(&hex::decode(bytecode)?)?)?\n        }\n        CastSubcommand::Selectors { bytecode, resolve } => {\n            let bytecode = stdin::unwrap_line(bytecode)?;\n            let functions = SimpleCast::extract_functions(&bytecode)?;\n            let max_args_len = functions.iter().map(|r| r.1.len()).max().unwrap_or(0);\n            let max_mutability_len = functions.iter().map(|r| r.2.len()).max().unwrap_or(0);\n\n            let resolve_results = if resolve {\n                let selectors = functions\n                    .iter()\n                    .map(|&(selector, ..)| SelectorKind::Function(selector))\n                    .collect::<Vec<_>>();\n                let ds = decode_selectors(&selectors).await?;\n                ds.into_iter().map(|v| v.join(\"|\")).collect()\n            } else {\n                vec![]\n            };\n            for (pos, (selector, arguments, state_mutability)) in functions.into_iter().enumerate()\n            {\n                if resolve {\n                    let resolved = &resolve_results[pos];\n                    sh_println!(\n                        \"{selector}\\t{arguments:max_args_len$}\\t{state_mutability:max_mutability_len$}\\t{resolved}\"\n                    )?\n                } else {\n                    sh_println!(\"{selector}\\t{arguments:max_args_len$}\\t{state_mutability}\")?\n                }\n            }\n        }\n        CastSubcommand::FindBlock(cmd) => cmd.run().await?,\n        CastSubcommand::GasPrice { rpc } => {\n            let config = rpc.load_config()?;\n            let provider = utils::get_provider(&config)?;\n            sh_println!(\"{}\", Cast::new(provider).gas_price().await?)?;\n        }\n        CastSubcommand::Index { key_type, key, slot_number } => {\n            sh_println!(\"{}\", SimpleCast::index(&key_type, &key, &slot_number)?)?;\n        }\n        CastSubcommand::IndexErc7201 { id, formula_id } => {\n            eyre::ensure!(formula_id == \"erc7201\", \"unsupported formula ID: {formula_id}\");\n            let id = stdin::unwrap_line(id)?;\n            sh_println!(\"{}\", foundry_common::erc7201(&id))?;\n        }\n        CastSubcommand::Implementation { block, beacon, who, rpc } => {\n            let config = rpc.load_config()?;\n            let provider = utils::get_provider(&config)?;\n            let who = who.resolve(&provider).await?;\n            sh_println!(\"{}\", Cast::new(provider).implementation(who, beacon, block).await?)?;\n        }\n        CastSubcommand::Admin { block, who, rpc } => {\n            let config = rpc.load_config()?;\n            let provider = utils::get_provider(&config)?;\n            let who = who.resolve(&provider).await?;\n            sh_println!(\"{}\", Cast::new(provider).admin(who, block).await?)?;\n        }\n        CastSubcommand::Nonce { block, who, rpc } => {\n            let config = rpc.load_config()?;\n            let provider = utils::get_provider(&config)?;\n            let who = who.resolve(&provider).await?;\n            sh_println!(\"{}\", Cast::new(provider).nonce(who, block).await?)?;\n        }\n        CastSubcommand::Codehash { block, who, slots, rpc } => {\n            let config = rpc.load_config()?;\n            let provider = utils::get_provider(&config)?;\n            let who = who.resolve(&provider).await?;\n            sh_println!(\"{}\", Cast::new(provider).codehash(who, slots, block).await?)?;\n        }\n        CastSubcommand::StorageRoot { block, who, slots, rpc } => {\n            let config = rpc.load_config()?;\n            let provider = utils::get_provider(&config)?;\n            let who = who.resolve(&provider).await?;\n            sh_println!(\"{}\", Cast::new(provider).storage_root(who, slots, block).await?)?;\n        }\n        CastSubcommand::Proof { address, slots, rpc, block } => {\n            let config = rpc.load_config()?;\n            let provider = utils::get_provider(&config)?;\n            let address = address.resolve(&provider).await?;\n            let value = provider\n                .get_proof(address, slots.into_iter().collect())\n                .block_id(block.unwrap_or_default())\n                .await?;\n            sh_println!(\"{}\", serde_json::to_string(&value)?)?;\n        }\n        CastSubcommand::Rpc(cmd) => cmd.run().await?,\n        CastSubcommand::Storage(cmd) => cmd.run().await?,\n\n        // Calls & transactions\n        CastSubcommand::Call(cmd) => cmd.run().await?,\n        CastSubcommand::Estimate(cmd) => cmd.run().await?,\n        CastSubcommand::MakeTx(cmd) => cmd.run().await?,\n        CastSubcommand::PublishTx { raw_tx, cast_async, rpc } => {\n            let config = rpc.load_config()?;\n            let provider = utils::get_provider(&config)?;\n            let cast = Cast::new(&provider);\n            let pending_tx = cast.publish(raw_tx).await?;\n            let tx_hash = pending_tx.inner().tx_hash();\n\n            if cast_async {\n                sh_println!(\"{tx_hash:#x}\")?;\n            } else {\n                let receipt = pending_tx.get_receipt().await?;\n                sh_println!(\"{}\", serde_json::json!(receipt))?;\n            }\n        }\n        CastSubcommand::Receipt { tx_hash, field, cast_async, confirmations, rpc } => {\n            let config = rpc.load_config()?;\n            let provider = utils::get_provider(&config)?;\n            sh_println!(\n                \"{}\",\n                CastTxSender::new(provider)\n                    .receipt(tx_hash, field, confirmations, None, cast_async)\n                    .await?\n            )?\n        }\n        CastSubcommand::Run(cmd) => cmd.run().await?,\n        CastSubcommand::SendTx(cmd) => cmd.run().await?,\n        CastSubcommand::Tx { tx_hash, from, nonce, field, raw, rpc, to_request, network } => {\n            let config = rpc.load_config()?;\n            // Can use either --raw or specify raw as a field\n            let is_raw = raw || field.as_ref().is_some_and(|f| f == \"raw\");\n            let output = match network {\n                Some(NetworkVariant::Optimism) => {\n                    let provider = ProviderBuilder::<Optimism>::from_config(&config)?.build()?;\n\n                    Cast::new(&provider)\n                        .transaction(tx_hash, from, nonce, field, is_raw, to_request)\n                        .await?\n                }\n                Some(NetworkVariant::Tempo) => {\n                    let provider =\n                        ProviderBuilder::<TempoNetwork>::from_config(&config)?.build()?;\n                    Cast::new(&provider)\n                        .transaction(tx_hash, from, nonce, field, is_raw, to_request)\n                        .await?\n                }\n                // Ethereum (default) or no --raw flag\n                _ => {\n                    let provider = utils::get_provider(&config)?;\n                    Cast::new(&provider)\n                        .transaction(tx_hash, from, nonce, field, is_raw, to_request)\n                        .await?\n                }\n            };\n            sh_println!(\"{}\", output)?\n        }\n\n        // 4Byte\n        CastSubcommand::FourByte { selector } => {\n            let selector = stdin::unwrap_line(selector)?;\n            let sigs = decode_function_selector(selector).await?;\n            if sigs.is_empty() {\n                eyre::bail!(\"No matching function signatures found for selector `{selector}`\");\n            }\n            for sig in sigs {\n                sh_println!(\"{sig}\")?\n            }\n        }\n\n        CastSubcommand::FourByteCalldata { calldata } => {\n            let calldata = stdin::unwrap_line(calldata)?;\n\n            if calldata.len() == 10 {\n                let sigs = decode_function_selector(calldata.parse()?).await?;\n                if sigs.is_empty() {\n                    eyre::bail!(\"No matching function signatures found for calldata `{calldata}`\");\n                }\n                for sig in sigs {\n                    sh_println!(\"{sig}\")?\n                }\n                return Ok(());\n            }\n\n            let sigs = decode_calldata(&calldata).await?;\n            sigs.iter().enumerate().for_each(|(i, sig)| {\n                let _ = sh_println!(\"{}) \\\"{sig}\\\"\", i + 1);\n            });\n\n            let sig = match sigs.len() {\n                0 => eyre::bail!(\"No signatures found\"),\n                1 => sigs.first().unwrap(),\n                _ => {\n                    let i: usize = prompt!(\"Select a function signature by number: \")?;\n                    sigs.get(i - 1).ok_or_else(|| eyre::eyre!(\"Invalid signature index\"))?\n                }\n            };\n\n            let tokens = SimpleCast::calldata_decode(sig, &calldata, true)?;\n            print_tokens(&tokens);\n        }\n\n        CastSubcommand::FourByteEvent { topic } => {\n            let topic = stdin::unwrap_line(topic)?;\n            let sigs = decode_event_topic(topic).await?;\n            if sigs.is_empty() {\n                eyre::bail!(\"No matching event signatures found for topic `{topic}`\");\n            }\n            for sig in sigs {\n                sh_println!(\"{sig}\")?\n            }\n        }\n        CastSubcommand::UploadSignature { signatures } => {\n            let signatures = stdin::unwrap_vec(signatures)?;\n            let ParsedSignatures { signatures, abis } = parse_signatures(signatures);\n            if !abis.is_empty() {\n                import_selectors(SelectorImportData::Abi(abis)).await?.describe();\n            }\n            if !signatures.is_empty() {\n                import_selectors(SelectorImportData::Raw(signatures)).await?.describe();\n            }\n        }\n\n        // ENS\n        CastSubcommand::Namehash { name } => {\n            let name = stdin::unwrap_line(name)?;\n            sh_println!(\"{}\", namehash(&name))?\n        }\n        CastSubcommand::LookupAddress { who, rpc, verify } => {\n            let config = rpc.load_config()?;\n            let provider = utils::get_provider(&config)?;\n\n            let who = stdin::unwrap_line(who)?;\n            let name = provider.lookup_address(&who).await?;\n            if verify {\n                let address = provider.resolve_name(&name).await?;\n                eyre::ensure!(\n                    address == who,\n                    \"Reverse lookup verification failed: got `{address}`, expected `{who}`\"\n                );\n            }\n            sh_println!(\"{name}\")?\n        }\n        CastSubcommand::ResolveName { who, rpc, verify } => {\n            let config = rpc.load_config()?;\n            let provider = utils::get_provider(&config)?;\n\n            let who = stdin::unwrap_line(who)?;\n            let address = provider.resolve_name(&who).await?;\n            if verify {\n                let name = provider.lookup_address(&address).await?;\n                eyre::ensure!(\n                    name == who,\n                    \"Forward lookup verification failed: got `{name}`, expected `{who}`\"\n                );\n            }\n            sh_println!(\"{address}\")?\n        }\n\n        // Misc\n        CastSubcommand::Keccak { data } => {\n            let bytes = match data {\n                Some(data) => data.into_bytes(),\n                None => stdin::read_bytes(false)?,\n            };\n            match String::from_utf8(bytes) {\n                Ok(s) => {\n                    let s = SimpleCast::keccak(&s)?;\n                    sh_println!(\"{s}\")?\n                }\n                Err(e) => {\n                    let hash = keccak256(e.as_bytes());\n                    let s = hex::encode(hash);\n                    sh_println!(\"0x{s}\")?\n                }\n            };\n        }\n        CastSubcommand::HashMessage { message } => {\n            let message = stdin::unwrap(message, false)?;\n            sh_println!(\"{}\", eip191_hash_message(message))?\n        }\n        CastSubcommand::SigEvent { event_string } => {\n            let event_string = stdin::unwrap_line(event_string)?;\n            let parsed_event = get_event(&event_string)?;\n            sh_println!(\"{:?}\", parsed_event.selector())?\n        }\n        CastSubcommand::LeftShift { value, bits, base_in, base_out } => sh_println!(\n            \"{}\",\n            SimpleCast::left_shift(&value, &bits, base_in.as_deref(), &base_out)?\n        )?,\n        CastSubcommand::RightShift { value, bits, base_in, base_out } => sh_println!(\n            \"{}\",\n            SimpleCast::right_shift(&value, &bits, base_in.as_deref(), &base_out)?\n        )?,\n        CastSubcommand::Source {\n            address,\n            directory,\n            explorer_api_url,\n            explorer_url,\n            etherscan,\n            flatten,\n        } => {\n            let config = etherscan.load_config()?;\n            let chain = config.chain.unwrap_or_default();\n            let api_key = config.get_etherscan_api_key(Some(chain));\n            match (directory, flatten) {\n                (Some(dir), false) => {\n                    SimpleCast::expand_etherscan_source_to_directory(\n                        chain,\n                        address,\n                        api_key,\n                        dir,\n                        explorer_api_url,\n                        explorer_url,\n                    )\n                    .await?\n                }\n                (None, false) => sh_println!(\n                    \"{}\",\n                    SimpleCast::etherscan_source(\n                        chain,\n                        address,\n                        api_key,\n                        explorer_api_url,\n                        explorer_url\n                    )\n                    .await?\n                )?,\n                (dir, true) => {\n                    SimpleCast::etherscan_source_flatten(\n                        chain,\n                        address,\n                        api_key,\n                        dir,\n                        explorer_api_url,\n                        explorer_url,\n                    )\n                    .await?;\n                }\n            }\n        }\n        CastSubcommand::Create2(cmd) => {\n            cmd.run()?;\n        }\n        CastSubcommand::Wallet { command } => command.run().await?,\n        CastSubcommand::Completions { shell } => {\n            generate(shell, &mut CastArgs::command(), \"cast\", &mut std::io::stdout())\n        }\n        CastSubcommand::Logs(cmd) => cmd.run().await?,\n        CastSubcommand::DecodeTransaction { tx } => {\n            let tx = stdin::unwrap_line(tx)?;\n            let tx = SimpleCast::decode_raw_transaction(&tx)?;\n\n            if let Ok(signer) = tx.recover() {\n                let recovered = Recovered::new_unchecked(tx, signer);\n                sh_println!(\"{}\", serde_json::to_string_pretty(&recovered)?)?;\n            } else {\n                sh_println!(\"{}\", serde_json::to_string_pretty(&tx)?)?;\n            }\n        }\n        CastSubcommand::RecoverAuthority { auth } => {\n            let auth: SignedAuthorization = serde_json::from_str(&auth)?;\n            sh_println!(\"{}\", auth.recover_authority()?)?;\n        }\n        CastSubcommand::TxPool { command } => command.run().await?,\n        CastSubcommand::Erc20Token { command } => command.run().await?,\n        CastSubcommand::DAEstimate(cmd) => {\n            cmd.run().await?;\n        }\n        CastSubcommand::Trace(cmd) => cmd.run().await?,\n    };\n\n    /// Prints slice of tokens using [`format_tokens`] or [`serialize_value_as_json`] depending\n    /// whether the shell is in JSON mode.\n    ///\n    /// This is included here to avoid a cyclic dependency between `fmt` and `common`.\n    fn print_tokens(tokens: &[DynSolValue]) {\n        if shell::is_json() {\n            let tokens: Vec<serde_json::Value> = tokens\n                .iter()\n                .cloned()\n                .map(|t| serialize_value_as_json(t, None))\n                .collect::<Result<Vec<_>>>()\n                .unwrap();\n            let _ = sh_println!(\"{}\", serde_json::to_string_pretty(&tokens).unwrap());\n        } else {\n            let tokens = format_tokens(tokens);\n            tokens.for_each(|t| {\n                let _ = sh_println!(\"{t}\");\n            });\n        }\n    }\n\n    Ok(())\n}\n"
  },
  {
    "path": "crates/cast/src/base.rs",
    "content": "use alloy_primitives::{I256, Sign, U256, utils::ParseUnits};\nuse eyre::Result;\nuse std::{\n    convert::Infallible,\n    fmt::{Binary, Debug, Display, Formatter, LowerHex, Octal, Result as FmtResult, UpperHex},\n    num::IntErrorKind,\n    str::FromStr,\n};\n\n/* -------------------------------------------- Base -------------------------------------------- */\n\n/// Represents a number's [radix] or base. Currently it supports the same bases that [std::fmt]\n/// supports.\n///\n/// [radix]: https://en.wikipedia.org/wiki/Radix\n#[repr(u32)]\n#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord)]\npub enum Base {\n    Binary = 2,\n    Octal = 8,\n    #[default]\n    Decimal = 10,\n    Hexadecimal = 16,\n}\n\nimpl Display for Base {\n    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {\n        Display::fmt(&(*self as u32), f)\n    }\n}\n\nimpl FromStr for Base {\n    type Err = eyre::Report;\n\n    fn from_str(s: &str) -> Result<Self, Self::Err> {\n        match s.to_lowercase().as_str() {\n            \"2\" | \"b\" | \"bin\" | \"binary\" => Ok(Self::Binary),\n            \"8\" | \"o\" | \"oct\" | \"octal\" => Ok(Self::Octal),\n            \"10\" | \"d\" | \"dec\" | \"decimal\" => Ok(Self::Decimal),\n            \"16\" | \"h\" | \"hex\" | \"hexadecimal\" => Ok(Self::Hexadecimal),\n            s => Err(eyre::eyre!(\n                \"\\\nInvalid base \\\"{s}\\\". Possible values:\n 2, b, bin, binary\n 8, o, oct, octal\n10, d, dec, decimal\n16, h, hex, hexadecimal\"\n            )),\n        }\n    }\n}\n\nimpl TryFrom<String> for Base {\n    type Error = eyre::Report;\n\n    fn try_from(s: String) -> Result<Self, Self::Error> {\n        Self::from_str(&s)\n    }\n}\n\nimpl TryFrom<u32> for Base {\n    type Error = eyre::Report;\n\n    fn try_from(n: u32) -> Result<Self, Self::Error> {\n        match n {\n            2 => Ok(Self::Binary),\n            8 => Ok(Self::Octal),\n            10 => Ok(Self::Decimal),\n            16 => Ok(Self::Hexadecimal),\n            n => Err(eyre::eyre!(\"Invalid base \\\"{}\\\". Possible values: 2, 8, 10, 16\", n)),\n        }\n    }\n}\n\nimpl TryFrom<I256> for Base {\n    type Error = eyre::Report;\n\n    fn try_from(n: I256) -> Result<Self, Self::Error> {\n        Self::try_from(n.low_u32())\n    }\n}\n\nimpl TryFrom<U256> for Base {\n    type Error = eyre::Report;\n\n    fn try_from(n: U256) -> Result<Self, Self::Error> {\n        Self::try_from(n.saturating_to::<u32>())\n    }\n}\n\nimpl From<Base> for u32 {\n    fn from(b: Base) -> Self {\n        b as Self\n    }\n}\n\nimpl From<Base> for String {\n    fn from(b: Base) -> Self {\n        b.to_string()\n    }\n}\n\nimpl Base {\n    pub fn unwrap_or_detect(base: Option<&str>, s: impl AsRef<str>) -> Result<Self> {\n        match base {\n            Some(base) => base.parse(),\n            None => Self::detect(s),\n        }\n    }\n\n    /// Try parsing a number's base from a string.\n    pub fn detect(s: impl AsRef<str>) -> Result<Self> {\n        let s = s.as_ref();\n        match s {\n            // Ignore sign\n            _ if s.starts_with(['+', '-']) => Self::detect(&s[1..]),\n            // Verify binary and octal values with u128::from_str_radix as U256 does not support\n            // them;\n            // assume overflows are within u128::MAX and U256::MAX, we're not using the parsed value\n            // anyway;\n            // strip prefix when using u128::from_str_radix because it does not recognize it as\n            // valid.\n            _ if s.starts_with(\"0b\") => match u64::from_str_radix(&s[2..], 2) {\n                Ok(_) => Ok(Self::Binary),\n                Err(e) => match e.kind() {\n                    IntErrorKind::PosOverflow => Ok(Self::Binary),\n                    _ => Err(eyre::eyre!(\"could not parse binary value: {}\", e)),\n                },\n            },\n            _ if s.starts_with(\"0o\") => match u64::from_str_radix(&s[2..], 8) {\n                Ok(_) => Ok(Self::Octal),\n                Err(e) => match e.kind() {\n                    IntErrorKind::PosOverflow => Ok(Self::Octal),\n                    _ => Err(eyre::eyre!(\"could not parse octal value: {e}\")),\n                },\n            },\n            _ if s.starts_with(\"0x\") => match u64::from_str_radix(&s[2..], 16) {\n                Ok(_) => Ok(Self::Hexadecimal),\n                Err(e) => match e.kind() {\n                    IntErrorKind::PosOverflow => Ok(Self::Hexadecimal),\n                    _ => Err(eyre::eyre!(\"could not parse hexadecimal value: {e}\")),\n                },\n            },\n            // No prefix => first try parsing as decimal\n            _ => match U256::from_str_radix(s, 10) {\n                // Can be both, ambiguous but default to Decimal\n                Ok(_) => Ok(Self::Decimal),\n                Err(_) => match U256::from_str_radix(s, 16) {\n                    Ok(_) => Ok(Self::Hexadecimal),\n                    Err(e) => Err(eyre::eyre!(\n                        \"could not autodetect base as neither decimal or hexadecimal: {e}\"\n                    )),\n                },\n            },\n        }\n    }\n\n    /// Returns the Rust standard prefix for a base\n    pub const fn prefix(&self) -> &str {\n        match self {\n            Self::Binary => \"0b\",\n            Self::Octal => \"0o\",\n            Self::Decimal => \"\",\n            Self::Hexadecimal => \"0x\",\n        }\n    }\n}\n\n/* --------------------------------------- NumberWithBase --------------------------------------- */\n\n/// Utility struct for parsing numbers and formatting them into different [bases][Base].\n///\n/// # Example\n///\n/// ```\n/// use cast::base::NumberWithBase;\n/// use alloy_primitives::U256;\n///\n/// let number: NumberWithBase = U256::from(12345).into();\n/// assert_eq!(number.format(), \"12345\");\n///\n/// // Debug uses number.base() to determine which base to format to, which defaults to Base::Decimal\n/// assert_eq!(format!(\"{:?}\", number), \"12345\");\n///\n/// // Display uses Base::Decimal\n/// assert_eq!(format!(\"{}\", number), \"12345\");\n///\n/// // The alternate formatter (\"#\") prepends the base's prefix\n/// assert_eq!(format!(\"{:x}\", number), \"3039\");\n/// assert_eq!(format!(\"{:#x}\", number), \"0x3039\");\n///\n/// assert_eq!(format!(\"{:b}\", number), \"11000000111001\");\n/// assert_eq!(format!(\"{:#b}\", number), \"0b11000000111001\");\n///\n/// assert_eq!(format!(\"{:o}\", number), \"30071\");\n/// assert_eq!(format!(\"{:#o}\", number), \"0o30071\");\n/// ```\n#[derive(Clone, Copy)]\npub struct NumberWithBase {\n    /// The number.\n    number: U256,\n    /// Whether the number is positive or zero.\n    is_nonnegative: bool,\n    /// The base to format to.\n    base: Base,\n}\n\nimpl std::ops::Deref for NumberWithBase {\n    type Target = U256;\n\n    fn deref(&self) -> &Self::Target {\n        &self.number\n    }\n}\n\n// Format using self.base\nimpl Debug for NumberWithBase {\n    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {\n        let prefix = self.base.prefix();\n        if self.number.is_zero() {\n            f.pad_integral(true, prefix, \"0\")\n        } else {\n            // Add sign only for decimal\n            let is_nonnegative = match self.base {\n                Base::Decimal => self.is_nonnegative,\n                _ => true,\n            };\n            f.pad_integral(is_nonnegative, prefix, &self.format())\n        }\n    }\n}\n\nimpl Binary for NumberWithBase {\n    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {\n        Debug::fmt(&self.with_base(Base::Binary), f)\n    }\n}\n\nimpl Octal for NumberWithBase {\n    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {\n        Debug::fmt(&self.with_base(Base::Octal), f)\n    }\n}\n\nimpl Display for NumberWithBase {\n    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {\n        Debug::fmt(&self.with_base(Base::Decimal), f)\n    }\n}\n\nimpl LowerHex for NumberWithBase {\n    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {\n        Debug::fmt(&self.with_base(Base::Hexadecimal), f)\n    }\n}\n\nimpl UpperHex for NumberWithBase {\n    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {\n        let n = format!(\"{self:x}\").to_uppercase();\n        f.pad_integral(true, Base::Hexadecimal.prefix(), &n)\n    }\n}\n\nimpl FromStr for NumberWithBase {\n    type Err = eyre::Report;\n\n    fn from_str(s: &str) -> Result<Self, Self::Err> {\n        Self::parse_int(s, None)\n    }\n}\n\nimpl From<I256> for NumberWithBase {\n    fn from(number: I256) -> Self {\n        // both is_positive and is_negative return false for 0\n        Self::new(number.into_raw(), !number.is_negative(), Base::default())\n    }\n}\n\nimpl From<ParseUnits> for NumberWithBase {\n    fn from(value: ParseUnits) -> Self {\n        match value {\n            ParseUnits::U256(val) => val.into(),\n            ParseUnits::I256(val) => val.into(),\n        }\n    }\n}\n\nimpl From<U256> for NumberWithBase {\n    fn from(number: U256) -> Self {\n        Self::new(number, true, Base::default())\n    }\n}\n\nimpl From<NumberWithBase> for I256 {\n    fn from(n: NumberWithBase) -> Self {\n        Self::from_raw(n.number)\n    }\n}\n\nimpl From<NumberWithBase> for U256 {\n    fn from(n: NumberWithBase) -> Self {\n        n.number\n    }\n}\n\nimpl From<NumberWithBase> for String {\n    /// Formats the number into the specified base. See [NumberWithBase::format].\n    ///\n    /// [NumberWithBase::format]: NumberWithBase\n    fn from(n: NumberWithBase) -> Self {\n        n.format()\n    }\n}\n\nimpl NumberWithBase {\n    pub fn new(number: impl Into<U256>, is_nonnegative: bool, base: Base) -> Self {\n        Self { number: number.into(), is_nonnegative, base }\n    }\n\n    /// Creates a copy of the number with the provided base.\n    pub fn with_base(&self, base: Base) -> Self {\n        Self { number: self.number, is_nonnegative: self.is_nonnegative, base }\n    }\n\n    /// Parses a string slice into a signed integer. If base is None then it tries to determine base\n    /// from the prefix, otherwise defaults to Decimal.\n    pub fn parse_int(s: &str, base: Option<&str>) -> Result<Self> {\n        let base = Base::unwrap_or_detect(base, s)?;\n        let (number, is_nonnegative) = Self::_parse_int(s, base)?;\n        Ok(Self { number, is_nonnegative, base })\n    }\n\n    /// Parses a string slice into an unsigned integer. If base is None then it tries to determine\n    /// base from the prefix, otherwise defaults to Decimal.\n    pub fn parse_uint(s: &str, base: Option<&str>) -> Result<Self> {\n        let base = Base::unwrap_or_detect(base, s)?;\n        let number = Self::_parse_uint(s, base)?;\n        Ok(Self { number, is_nonnegative: true, base })\n    }\n\n    /// Returns a copy of the underlying number as an unsigned integer. If the value is negative\n    /// then the two's complement of its absolute value will be returned.\n    pub fn number(&self) -> U256 {\n        self.number\n    }\n\n    /// Returns whether the underlying number is positive or zero.\n    pub fn is_nonnegative(&self) -> bool {\n        self.is_nonnegative\n    }\n\n    /// Returns the underlying base. Defaults to [Decimal][Base].\n    pub fn base(&self) -> Base {\n        self.base\n    }\n\n    /// Returns the Rust standard prefix for the base.\n    pub const fn prefix(&self) -> &str {\n        self.base.prefix()\n    }\n\n    /// Sets the number's base to format to.\n    pub fn set_base(&mut self, base: Base) -> &mut Self {\n        self.base = base;\n        self\n    }\n\n    /// Formats the number into the specified base.\n    ///\n    /// **Note**: this method only formats the number into the base, without adding any prefixes,\n    /// signs or padding. Refer to the [std::fmt] module documentation on how to format this\n    /// number with the aforementioned properties.\n    pub fn format(&self) -> String {\n        let s = match self.base {\n            Base::Binary => format!(\"{:b}\", self.number),\n            Base::Octal => format!(\"{:o}\", self.number),\n            Base::Decimal => {\n                if self.is_nonnegative {\n                    self.number.to_string()\n                } else {\n                    let s = I256::from_raw(self.number).to_string();\n                    s.strip_prefix('-').unwrap_or(&s).to_string()\n                }\n            }\n            Base::Hexadecimal => format!(\"{:x}\", self.number),\n        };\n        if s.starts_with('0') { s.trim_start_matches('0').to_string() } else { s }\n    }\n\n    fn _parse_int(s: &str, base: Base) -> Result<(U256, bool)> {\n        let (s, sign) = get_sign(s);\n        let mut n = Self::_parse_uint(s, base)?;\n\n        let is_neg = matches!(sign, Sign::Negative);\n        if is_neg {\n            n = (!n).overflowing_add(U256::from(1)).0;\n        }\n\n        Ok((n, !is_neg))\n    }\n\n    fn _parse_uint(s: &str, base: Base) -> Result<U256> {\n        let s = match s.get(0..2) {\n            Some(\"0x\" | \"0X\" | \"0o\" | \"0O\" | \"0b\" | \"0B\") => &s[2..],\n            _ => s,\n        };\n        U256::from_str_radix(s, base as u64).map_err(Into::into)\n    }\n}\n\n/* ------------------------------------------- ToBase ------------------------------------------- */\n\n/// Facilitates formatting an integer into a [Base].\npub trait ToBase {\n    type Err;\n\n    /// Formats self into a base, specifying whether to add the base prefix or not.\n    ///\n    /// Tries converting `self` into a [NumberWithBase] and then formats into the provided base by\n    /// using the [Debug] implementation.\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// use alloy_primitives::U256;\n    /// use cast::base::{Base, ToBase};\n    ///\n    /// // Any type that implements ToBase\n    /// let number = U256::from(12345);\n    /// assert_eq!(number.to_base(Base::Decimal, false).unwrap(), \"12345\");\n    /// assert_eq!(number.to_base(Base::Hexadecimal, false).unwrap(), \"3039\");\n    /// assert_eq!(number.to_base(Base::Hexadecimal, true).unwrap(), \"0x3039\");\n    /// assert_eq!(number.to_base(Base::Binary, true).unwrap(), \"0b11000000111001\");\n    /// assert_eq!(number.to_base(Base::Octal, true).unwrap(), \"0o30071\");\n    /// ```\n    fn to_base(&self, base: Base, add_prefix: bool) -> Result<String, Self::Err>;\n}\n\nimpl ToBase for NumberWithBase {\n    type Err = Infallible;\n\n    fn to_base(&self, base: Base, add_prefix: bool) -> Result<String, Self::Err> {\n        let n = self.with_base(base);\n        if add_prefix { Ok(format!(\"{n:#?}\")) } else { Ok(format!(\"{n:?}\")) }\n    }\n}\n\nimpl ToBase for I256 {\n    type Err = Infallible;\n\n    fn to_base(&self, base: Base, add_prefix: bool) -> Result<String, Self::Err> {\n        let n = NumberWithBase::from(*self).with_base(base);\n        if add_prefix { Ok(format!(\"{n:#?}\")) } else { Ok(format!(\"{n:?}\")) }\n    }\n}\n\nimpl ToBase for U256 {\n    type Err = Infallible;\n\n    fn to_base(&self, base: Base, add_prefix: bool) -> Result<String, Self::Err> {\n        let n = NumberWithBase::from(*self).with_base(base);\n        if add_prefix { Ok(format!(\"{n:#?}\")) } else { Ok(format!(\"{n:?}\")) }\n    }\n}\n\nimpl ToBase for String {\n    type Err = eyre::Report;\n\n    fn to_base(&self, base: Base, add_prefix: bool) -> Result<String, Self::Err> {\n        str::to_base(self, base, add_prefix)\n    }\n}\n\nimpl ToBase for str {\n    type Err = eyre::Report;\n\n    fn to_base(&self, base: Base, add_prefix: bool) -> Result<String, Self::Err> {\n        let n = NumberWithBase::from_str(self)?.with_base(base);\n        if add_prefix { Ok(format!(\"{n:#?}\")) } else { Ok(format!(\"{n:?}\")) }\n    }\n}\n\nfn get_sign(s: &str) -> (&str, Sign) {\n    match s.as_bytes().first() {\n        Some(b'+') => (&s[1..], Sign::Positive),\n        Some(b'-') => (&s[1..], Sign::Negative),\n        _ => (s, Sign::Positive),\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use Base::*;\n\n    const POS_NUM: [i128; 44] = [\n        1,\n        2,\n        3,\n        5,\n        7,\n        8,\n        10,\n        11,\n        13,\n        16,\n        17,\n        19,\n        23,\n        29,\n        31,\n        32,\n        37,\n        41,\n        43,\n        47,\n        53,\n        59,\n        61,\n        64,\n        67,\n        71,\n        73,\n        79,\n        83,\n        89,\n        97,\n        100,\n        128,\n        200,\n        333,\n        500,\n        666,\n        1000,\n        6666,\n        10000,\n        i16::MAX as i128,\n        i32::MAX as i128,\n        i64::MAX as i128,\n        i128::MAX,\n    ];\n\n    const NEG_NUM: [i128; 44] = [\n        -1,\n        -2,\n        -3,\n        -5,\n        -7,\n        -8,\n        -10,\n        -11,\n        -13,\n        -16,\n        -17,\n        -19,\n        -23,\n        -29,\n        -31,\n        -32,\n        -37,\n        -41,\n        -43,\n        -47,\n        -53,\n        -59,\n        -61,\n        -64,\n        -67,\n        -71,\n        -73,\n        -79,\n        -83,\n        -89,\n        -97,\n        -100,\n        -128,\n        -200,\n        -333,\n        -500,\n        -666,\n        -1000,\n        -6666,\n        -10000,\n        i16::MIN as i128,\n        i32::MIN as i128,\n        i64::MIN as i128,\n        i128::MIN,\n    ];\n\n    #[test]\n    fn test_defaults() {\n        let def: Base = Default::default();\n        assert!(matches!(def, Decimal));\n\n        let n: NumberWithBase = U256::ZERO.into();\n        assert!(matches!(n.base, Decimal));\n        let n: NumberWithBase = I256::ZERO.into();\n        assert!(matches!(n.base, Decimal));\n    }\n\n    #[test]\n    fn can_parse_base() {\n        assert_eq!(\"2\".parse::<Base>().unwrap(), Binary);\n        assert_eq!(\"b\".parse::<Base>().unwrap(), Binary);\n        assert_eq!(\"bin\".parse::<Base>().unwrap(), Binary);\n        assert_eq!(\"binary\".parse::<Base>().unwrap(), Binary);\n\n        assert_eq!(\"8\".parse::<Base>().unwrap(), Octal);\n        assert_eq!(\"o\".parse::<Base>().unwrap(), Octal);\n        assert_eq!(\"oct\".parse::<Base>().unwrap(), Octal);\n        assert_eq!(\"octal\".parse::<Base>().unwrap(), Octal);\n\n        assert_eq!(\"10\".parse::<Base>().unwrap(), Decimal);\n        assert_eq!(\"d\".parse::<Base>().unwrap(), Decimal);\n        assert_eq!(\"dec\".parse::<Base>().unwrap(), Decimal);\n        assert_eq!(\"decimal\".parse::<Base>().unwrap(), Decimal);\n\n        assert_eq!(\"16\".parse::<Base>().unwrap(), Hexadecimal);\n        assert_eq!(\"h\".parse::<Base>().unwrap(), Hexadecimal);\n        assert_eq!(\"hex\".parse::<Base>().unwrap(), Hexadecimal);\n        assert_eq!(\"hexadecimal\".parse::<Base>().unwrap(), Hexadecimal);\n    }\n\n    #[test]\n    fn can_detect_base() {\n        assert_eq!(Base::detect(\"0b100\").unwrap(), Binary);\n        assert_eq!(Base::detect(\"0o100\").unwrap(), Octal);\n        assert_eq!(Base::detect(\"100\").unwrap(), Decimal);\n        assert_eq!(Base::detect(\"0x100\").unwrap(), Hexadecimal);\n\n        assert_eq!(Base::detect(\"0123456789abcdef\").unwrap(), Hexadecimal);\n\n        let _ = Base::detect(\"0b234abc\").unwrap_err();\n        let _ = Base::detect(\"0o89cba\").unwrap_err();\n        let _ = Base::detect(\"0123456789abcdefg\").unwrap_err();\n        let _ = Base::detect(\"0x123abclpmk\").unwrap_err();\n        let _ = Base::detect(\"hello world\").unwrap_err();\n    }\n\n    #[test]\n    fn test_format_pos() {\n        let expected_2: Vec<_> = POS_NUM.iter().map(|n| format!(\"{n:b}\")).collect();\n        let expected_8: Vec<_> = POS_NUM.iter().map(|n| format!(\"{n:o}\")).collect();\n        let expected_10: Vec<_> = POS_NUM.iter().map(|n| format!(\"{n:}\")).collect();\n        let expected_l16: Vec<_> = POS_NUM.iter().map(|n| format!(\"{n:x}\")).collect();\n        let expected_u16: Vec<_> = POS_NUM.iter().map(|n| format!(\"{n:X}\")).collect();\n\n        for (i, n) in POS_NUM.into_iter().enumerate() {\n            let mut num: NumberWithBase = I256::try_from(n).unwrap().into();\n\n            assert_eq!(num.set_base(Binary).format(), expected_2[i]);\n            assert_eq!(num.set_base(Octal).format(), expected_8[i]);\n            assert_eq!(num.set_base(Decimal).format(), expected_10[i]);\n            assert_eq!(num.set_base(Hexadecimal).format(), expected_l16[i]);\n            assert_eq!(num.set_base(Hexadecimal).format().to_uppercase(), expected_u16[i]);\n        }\n    }\n\n    #[test]\n    fn test_format_neg() {\n        // underlying is 256 bits so we have to pad left manually\n\n        let expected_2: Vec<_> = NEG_NUM.iter().map(|n| format!(\"{n:1>256b}\")).collect();\n        let expected_8: Vec<_> = NEG_NUM\n            .iter()\n            .map(|n| {\n                let i = I256::try_from(*n).unwrap();\n                let mut u = NumberWithBase::from(i);\n                u.set_base(Octal);\n                u.format()\n            })\n            .collect();\n        // Sign not included, see NumberWithBase::format\n        let expected_10: Vec<_> =\n            NEG_NUM.iter().map(|n| format!(\"{n:}\").trim_matches('-').to_string()).collect();\n        let expected_l16: Vec<_> = NEG_NUM.iter().map(|n| format!(\"{n:f>64x}\")).collect();\n        let expected_u16: Vec<_> = NEG_NUM.iter().map(|n| format!(\"{n:F>64X}\")).collect();\n\n        for (i, n) in NEG_NUM.into_iter().enumerate() {\n            let mut num: NumberWithBase = I256::try_from(n).unwrap().into();\n\n            assert_eq!(num.set_base(Binary).format(), expected_2[i]);\n            assert_eq!(num.set_base(Octal).format(), expected_8[i]);\n            assert_eq!(num.set_base(Decimal).format(), expected_10[i]);\n            assert_eq!(num.set_base(Hexadecimal).format(), expected_l16[i]);\n            assert_eq!(num.set_base(Hexadecimal).format().to_uppercase(), expected_u16[i]);\n        }\n    }\n\n    #[test]\n    fn test_fmt_macro() {\n        let nums: Vec<_> =\n            POS_NUM.into_iter().map(|n| NumberWithBase::from(I256::try_from(n).unwrap())).collect();\n\n        let actual_2: Vec<_> = nums.iter().map(|n| format!(\"{n:b}\")).collect();\n        let actual_2_alt: Vec<_> = nums.iter().map(|n| format!(\"{n:#b}\")).collect();\n        let actual_8: Vec<_> = nums.iter().map(|n| format!(\"{n:o}\")).collect();\n        let actual_8_alt: Vec<_> = nums.iter().map(|n| format!(\"{n:#o}\")).collect();\n        let actual_10: Vec<_> = nums.iter().map(|n| format!(\"{n:}\")).collect();\n        let actual_10_alt: Vec<_> = nums.iter().map(|n| format!(\"{n:#}\")).collect();\n        let actual_l16: Vec<_> = nums.iter().map(|n| format!(\"{n:x}\")).collect();\n        let actual_l16_alt: Vec<_> = nums.iter().map(|n| format!(\"{n:#x}\")).collect();\n        let actual_u16: Vec<_> = nums.iter().map(|n| format!(\"{n:X}\")).collect();\n        let actual_u16_alt: Vec<_> = nums.iter().map(|n| format!(\"{n:#X}\")).collect();\n\n        let expected_2: Vec<_> = POS_NUM.iter().map(|n| format!(\"{n:b}\")).collect();\n        let expected_2_alt: Vec<_> = POS_NUM.iter().map(|n| format!(\"{n:#b}\")).collect();\n        let expected_8: Vec<_> = POS_NUM.iter().map(|n| format!(\"{n:o}\")).collect();\n        let expected_8_alt: Vec<_> = POS_NUM.iter().map(|n| format!(\"{n:#o}\")).collect();\n        let expected_10: Vec<_> = POS_NUM.iter().map(|n| format!(\"{n:}\")).collect();\n        let expected_10_alt: Vec<_> = POS_NUM.iter().map(|n| format!(\"{n:#}\")).collect();\n        let expected_l16: Vec<_> = POS_NUM.iter().map(|n| format!(\"{n:x}\")).collect();\n        let expected_l16_alt: Vec<_> = POS_NUM.iter().map(|n| format!(\"{n:#x}\")).collect();\n        let expected_u16: Vec<_> = POS_NUM.iter().map(|n| format!(\"{n:X}\")).collect();\n        let expected_u16_alt: Vec<_> = POS_NUM.iter().map(|n| format!(\"{n:#X}\")).collect();\n\n        for (i, _) in POS_NUM.iter().enumerate() {\n            assert_eq!(actual_2[i], expected_2[i]);\n            assert_eq!(actual_2_alt[i], expected_2_alt[i]);\n\n            assert_eq!(actual_8[i], expected_8[i]);\n            assert_eq!(actual_8_alt[i], expected_8_alt[i]);\n\n            assert_eq!(actual_10[i], expected_10[i]);\n            assert_eq!(actual_10_alt[i], expected_10_alt[i]);\n\n            assert_eq!(actual_l16[i], expected_l16[i]);\n            assert_eq!(actual_l16_alt[i], expected_l16_alt[i]);\n\n            assert_eq!(actual_u16[i], expected_u16[i]);\n            assert_eq!(actual_u16_alt[i], expected_u16_alt[i]);\n        }\n    }\n}\n"
  },
  {
    "path": "crates/cast/src/cmd/access_list.rs",
    "content": "use crate::{\n    Cast,\n    tx::{CastTxBuilder, SenderKind},\n};\nuse alloy_ens::NameOrAddress;\nuse alloy_network::{AnyNetwork, Network};\nuse alloy_rpc_types::BlockId;\nuse clap::Parser;\nuse eyre::Result;\nuse foundry_cli::{\n    opts::{RpcOpts, TransactionOpts},\n    utils::LoadConfig,\n};\nuse foundry_common::provider::ProviderBuilder;\nuse foundry_primitives::FoundryTransactionBuilder;\nuse foundry_wallets::WalletOpts;\nuse std::str::FromStr;\nuse tempo_alloy::TempoNetwork;\n\n/// CLI arguments for `cast access-list`.\n#[derive(Debug, Parser)]\npub struct AccessListArgs {\n    /// The destination of the transaction.\n    #[arg(\n        value_name = \"TO\",\n        value_parser = NameOrAddress::from_str\n    )]\n    to: Option<NameOrAddress>,\n\n    /// The signature of the function to call.\n    #[arg(value_name = \"SIG\")]\n    sig: Option<String>,\n\n    /// The arguments of the function to call.\n    #[arg(value_name = \"ARGS\", allow_negative_numbers = true)]\n    args: Vec<String>,\n\n    /// Raw hex-encoded data for the transaction. Used instead of \\[SIG\\] and \\[ARGS\\].\n    #[arg(\n        long,\n        conflicts_with_all = &[\"sig\", \"args\"]\n    )]\n    data: Option<String>,\n\n    /// The block height to query at.\n    ///\n    /// Can also be the tags earliest, finalized, safe, latest, or pending.\n    #[arg(long, short = 'B')]\n    block: Option<BlockId>,\n\n    #[command(flatten)]\n    tx: TransactionOpts,\n\n    #[command(flatten)]\n    rpc: RpcOpts,\n\n    #[command(flatten)]\n    wallet: WalletOpts,\n}\n\nimpl AccessListArgs {\n    pub async fn run(self) -> Result<()> {\n        if self.tx.tempo.is_tempo() {\n            self.run_with_network::<TempoNetwork>().await\n        } else {\n            self.run_with_network::<AnyNetwork>().await\n        }\n    }\n\n    pub async fn run_with_network<N: Network + Unpin>(self) -> Result<()>\n    where\n        N::TransactionRequest: FoundryTransactionBuilder<N>,\n    {\n        let Self { to, mut sig, args, data, tx, rpc, wallet, block } = self;\n\n        if let Some(data) = data {\n            sig = Some(data);\n        }\n\n        let config = rpc.load_config()?;\n        let provider = ProviderBuilder::<N>::from_config(&config)?.build()?;\n        let sender = SenderKind::from_wallet_opts(wallet).await?;\n\n        let (tx, _) = CastTxBuilder::new(&provider, tx, &config)\n            .await?\n            .with_to(to)\n            .await?\n            .with_code_sig_and_args(None, sig, args)\n            .await?\n            .raw()\n            .build(sender)\n            .await?;\n\n        let access_list: String = Cast::new(&provider).access_list(&tx, block).await?;\n\n        sh_println!(\"{access_list}\")?;\n\n        Ok(())\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use alloy_primitives::hex;\n    use clap::error::ErrorKind;\n\n    #[test]\n    fn can_parse_access_list_data() {\n        let data = hex::encode(\"hello\");\n        let args = AccessListArgs::parse_from([\"foundry-cli\", \"--data\", data.as_str()]);\n        assert_eq!(args.data, Some(data));\n\n        let data = hex::encode_prefixed(\"hello\");\n        let args = AccessListArgs::parse_from([\"foundry-cli\", \"--data\", data.as_str()]);\n        assert_eq!(args.data, Some(data));\n    }\n\n    #[test]\n    fn data_conflicts_with_sig_and_args() {\n        let err = AccessListArgs::try_parse_from([\n            \"foundry-cli\",\n            \"0x0000000000000000000000000000000000000001\",\n            \"transfer(address,uint256)\",\n            \"0x0000000000000000000000000000000000000002\",\n            \"1\",\n            \"--data\",\n            \"0x1234\",\n        ])\n        .unwrap_err();\n\n        assert_eq!(err.kind(), ErrorKind::ArgumentConflict);\n    }\n}\n"
  },
  {
    "path": "crates/cast/src/cmd/artifact.rs",
    "content": "use super::{\n    creation_code::{fetch_creation_code_from_etherscan, parse_code_output},\n    interface::load_abi_from_file,\n};\nuse alloy_primitives::Address;\nuse alloy_provider::Provider;\nuse clap::Parser;\nuse eyre::Result;\nuse foundry_cli::{\n    opts::{EtherscanOpts, RpcOpts},\n    utils::{self, LoadConfig, fetch_abi_from_etherscan},\n};\nuse foundry_common::fs;\nuse serde_json::json;\nuse std::path::PathBuf;\n\nfoundry_config::impl_figment_convert!(ArtifactArgs, etherscan, rpc);\n\n/// CLI arguments for `cast artifact`.\n#[derive(Parser)]\npub struct ArtifactArgs {\n    /// An Ethereum address, for which the artifact will be produced.\n    contract: Address,\n\n    /// Path to file containing the contract's JSON ABI. It's necessary if the target contract is\n    /// not verified on Etherscan.\n    #[arg(long)]\n    abi_path: Option<String>,\n\n    /// The path to the output file.\n    ///\n    /// If not specified, the artifact will be output to stdout.\n    #[arg(\n        short,\n        long,\n        value_hint = clap::ValueHint::FilePath,\n        value_name = \"PATH\",\n    )]\n    output: Option<PathBuf>,\n\n    #[command(flatten)]\n    etherscan: EtherscanOpts,\n\n    #[command(flatten)]\n    rpc: RpcOpts,\n}\n\nimpl ArtifactArgs {\n    pub async fn run(self) -> Result<()> {\n        let mut config = self.load_config()?;\n\n        let Self { contract, output: output_location, abi_path, etherscan: _, rpc: _ } = self;\n\n        let provider = utils::get_provider(&config)?;\n        let chain = provider.get_chain_id().await?;\n        config.chain = Some(chain.into());\n\n        let abi = if let Some(ref abi_path) = abi_path {\n            load_abi_from_file(abi_path, None)?\n        } else {\n            fetch_abi_from_etherscan(contract, &config).await?\n        };\n\n        let (abi, _) = abi.first().ok_or_else(|| eyre::eyre!(\"No ABI found\"))?;\n\n        let bytecode = fetch_creation_code_from_etherscan(contract, &config, provider).await?;\n        let bytecode =\n            parse_code_output(bytecode, contract, &config, abi_path.as_deref(), true, false)\n                .await?;\n\n        let artifact = json!({\n            \"abi\": abi,\n            \"bytecode\": {\n              \"object\": bytecode\n            }\n        });\n\n        let artifact = serde_json::to_string_pretty(&artifact)?;\n\n        if let Some(loc) = output_location {\n            if let Some(parent) = loc.parent() {\n                fs::create_dir_all(parent)?;\n            }\n            fs::write(&loc, artifact)?;\n            sh_println!(\"Saved artifact at {}\", loc.display())?;\n        } else {\n            sh_println!(\"{artifact}\")?;\n        }\n\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "crates/cast/src/cmd/b2e_payload.rs",
    "content": "//! Command Line handler to convert Beacon block's execution payload to Execution format.\n\nuse std::path::PathBuf;\n\nuse alloy_rpc_types_beacon::payload::BeaconBlockData;\nuse clap::{Parser, builder::ValueParser};\nuse eyre::{Result, eyre};\nuse foundry_common::{fs, sh_print};\n\n/// CLI arguments for `cast b2e-payload`, convert Beacon block's execution payload to Execution\n/// format.\n#[derive(Parser)]\npub struct B2EPayloadArgs {\n    /// Input data, it can be either a file path to JSON file or raw JSON string containing the\n    /// beacon block\n    #[arg(value_name = \"INPUT\", value_parser=ValueParser::new(parse_input_source), help = \"File path to JSON file or raw JSON string containing the beacon block\")]\n    pub input: InputSource,\n}\n\nimpl B2EPayloadArgs {\n    pub async fn run(self) -> Result<()> {\n        let beacon_block_json = match self.input {\n            InputSource::Json(json) => json,\n            InputSource::File(path) => fs::read_to_string(&path)\n                .map_err(|e| eyre!(\"Failed to read JSON file '{}': {}\", path.display(), e))?,\n        };\n\n        let beacon_block_data: BeaconBlockData = serde_json::from_str(&beacon_block_json)\n            .map_err(|e| eyre!(\"Failed to parse beacon block JSON: {}\", e))?;\n\n        let execution_payload = beacon_block_data.execution_payload();\n\n        // Output raw execution payload\n        let output = serde_json::to_string(&execution_payload)\n            .map_err(|e| eyre!(\"Failed to serialize execution payload: {}\", e))?;\n        sh_print!(\"{}\", output)?;\n\n        Ok(())\n    }\n}\n\n/// Represents the different input sources for beacon block data\n#[derive(Debug, Clone)]\npub enum InputSource {\n    /// Path to a JSON file containing beacon block data\n    File(PathBuf),\n    /// Raw JSON string containing beacon block data\n    Json(String),\n}\n\nfn parse_input_source(s: &str) -> Result<InputSource, String> {\n    // Try parsing as JSON first\n    if serde_json::from_str::<serde_json::Value>(s).is_ok() {\n        return Ok(InputSource::Json(s.to_string()));\n    }\n\n    // Otherwise treat as file path\n    Ok(InputSource::File(PathBuf::from(s)))\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_parse_input_source_json_object() {\n        let json_input = r#\"{\"execution_payload\": {\"block_hash\": \"0x123\"}}\"#;\n        let result = parse_input_source(json_input).unwrap();\n\n        match result {\n            InputSource::Json(json) => assert_eq!(json, json_input),\n            InputSource::File(_) => panic!(\"Expected JSON input, got File\"),\n        }\n    }\n\n    #[test]\n    fn test_parse_input_source_json_array() {\n        let json_input = r#\"[{\"block\": \"data\"}]\"#;\n        let result = parse_input_source(json_input).unwrap();\n\n        match result {\n            InputSource::Json(json) => assert_eq!(json, json_input),\n            InputSource::File(_) => panic!(\"Expected JSON input, got File\"),\n        }\n    }\n\n    #[test]\n    fn test_parse_input_source_file_path() {\n        let file_path =\n            \"block-12225729-6ceadbf2a6adbbd64cbec33fdebbc582f25171cd30ac43f641cbe76ac7313ddf.json\";\n        let result = parse_input_source(file_path).unwrap();\n\n        match result {\n            InputSource::File(path) => assert_eq!(path, PathBuf::from(file_path)),\n            InputSource::Json(_) => panic!(\"Expected File input, got JSON\"),\n        }\n    }\n\n    #[test]\n    fn test_parse_input_source_malformed_but_not_json() {\n        let malformed = \"not-json-{\";\n        let result = parse_input_source(malformed).unwrap();\n\n        // Should be treated as file path since it's not valid JSON\n        match result {\n            InputSource::File(path) => assert_eq!(path, PathBuf::from(malformed)),\n            InputSource::Json(_) => panic!(\"Expected File input, got File\"),\n        }\n    }\n}\n"
  },
  {
    "path": "crates/cast/src/cmd/bind.rs",
    "content": "use clap::{Parser, ValueHint};\nuse eyre::Result;\nuse foundry_cli::opts::EtherscanOpts;\nuse std::path::PathBuf;\n\nconst DEFAULT_CRATE_NAME: &str = \"foundry-contracts\";\nconst DEFAULT_CRATE_VERSION: &str = \"0.0.1\";\n\n/// CLI arguments for `cast bind`.\n#[derive(Clone, Debug, Parser)]\npub struct BindArgs {\n    /// The contract address, or the path to an ABI Directory\n    ///\n    /// If an address is specified, then the ABI is fetched from Etherscan.\n    path_or_address: String,\n\n    /// Path to where bindings will be stored\n    #[arg(\n        short,\n        long,\n        value_hint = ValueHint::DirPath,\n        value_name = \"PATH\"\n    )]\n    pub output_dir: Option<PathBuf>,\n\n    /// The name of the Rust crate to generate.\n    ///\n    /// This should be a valid crates.io crate name. However, this is currently not validated by\n    /// this command.\n    #[arg(\n        long,\n        default_value = DEFAULT_CRATE_NAME,\n        value_name = \"NAME\"\n    )]\n    crate_name: String,\n\n    /// The version of the Rust crate to generate.\n    ///\n    /// This should be a standard semver version string. However, it is not currently validated by\n    /// this command.\n    #[arg(\n        long,\n        default_value = DEFAULT_CRATE_VERSION,\n        value_name = \"VERSION\"\n    )]\n    crate_version: String,\n\n    /// Generate bindings as separate files.\n    #[arg(long)]\n    separate_files: bool,\n\n    #[command(flatten)]\n    etherscan: EtherscanOpts,\n}\n\nimpl BindArgs {\n    pub async fn run(self) -> Result<()> {\n        Err(eyre::eyre!(\n            \"`cast bind` has been removed.\\n\\\n             Please use `cast source` to create a Forge project from a block explorer source\\n\\\n             and `forge bind` to generate the bindings to it instead.\"\n        ))\n    }\n}\n"
  },
  {
    "path": "crates/cast/src/cmd/call.rs",
    "content": "use super::run::fetch_contracts_bytecode_from_trace;\nuse crate::{\n    Cast,\n    debug::handle_traces,\n    traces::TraceKind,\n    tx::{CastTxBuilder, SenderKind},\n};\nuse alloy_ens::NameOrAddress;\nuse alloy_network::{AnyNetwork, Network, TransactionBuilder};\nuse alloy_primitives::{Address, B256, Bytes, TxKind, U256, hex, map::HashMap};\nuse alloy_provider::Provider;\nuse alloy_rpc_types::{\n    BlockId, BlockNumberOrTag, BlockOverrides,\n    state::{StateOverride, StateOverridesBuilder},\n};\nuse clap::Parser;\nuse eyre::Result;\nuse foundry_cli::{\n    opts::{ChainValueParser, RpcOpts, TransactionOpts},\n    utils::{LoadConfig, TraceResult, parse_ether_value},\n};\nuse foundry_common::{\n    abi::{encode_function_args, get_func},\n    provider::{ProviderBuilder, curl_transport::generate_curl_command},\n    sh_println, shell,\n};\nuse foundry_compilers::artifacts::EvmVersion;\nuse foundry_config::{\n    Chain, Config,\n    figment::{\n        self, Metadata, Profile,\n        value::{Dict, Map},\n    },\n};\nuse foundry_evm::{\n    executors::TracingExecutor,\n    opts::EvmOpts,\n    traces::{InternalTraceMode, TraceMode},\n};\nuse foundry_primitives::FoundryTransactionBuilder;\nuse foundry_wallets::WalletOpts;\nuse itertools::Either;\nuse regex::Regex;\nuse revm::context::TransactionType;\nuse std::{str::FromStr, sync::LazyLock};\nuse tempo_alloy::TempoNetwork;\n\n// matches override pattern <address>:<slot>:<value>\n// e.g. 0x123:0x1:0x1234\nstatic OVERRIDE_PATTERN: LazyLock<Regex> =\n    LazyLock::new(|| Regex::new(r\"^([^:]+):([^:]+):([^:]+)$\").unwrap());\n\n/// CLI arguments for `cast call`.\n///\n/// ## State Override Flags\n///\n/// The following flags can be used to override the state for the call:\n///\n/// * `--override-balance <address>:<balance>` - Override the balance of an account\n/// * `--override-nonce <address>:<nonce>` - Override the nonce of an account\n/// * `--override-code <address>:<code>` - Override the code of an account\n/// * `--override-state <address>:<slot>:<value>` - Override a storage slot of an account\n///\n/// Multiple overrides can be specified for the same account. For example:\n///\n/// ```bash\n/// cast call 0x... \"transfer(address,uint256)\" 0x... 100 \\\n///   --override-balance 0x123:0x1234 \\\n///   --override-nonce 0x123:1 \\\n///   --override-code 0x123:0x1234 \\\n///   --override-state 0x123:0x1:0x1234\n///   --override-state-diff 0x123:0x1:0x1234\n/// ```\n#[derive(Debug, Parser)]\npub struct CallArgs {\n    /// The destination of the transaction.\n    #[arg(value_parser = NameOrAddress::from_str)]\n    to: Option<NameOrAddress>,\n\n    /// The signature of the function to call.\n    sig: Option<String>,\n\n    /// The arguments of the function to call.\n    #[arg(allow_negative_numbers = true)]\n    args: Vec<String>,\n\n    /// Raw hex-encoded data for the transaction. Used instead of \\[SIG\\] and \\[ARGS\\].\n    #[arg(\n        long,\n        conflicts_with_all = &[\"sig\", \"args\"]\n    )]\n    data: Option<String>,\n\n    /// Forks the remote rpc, executes the transaction locally and prints a trace\n    #[arg(long, default_value_t = false)]\n    trace: bool,\n\n    /// Disables the labels in the traces.\n    /// Can only be set with `--trace`.\n    #[arg(long, default_value_t = false, requires = \"trace\")]\n    disable_labels: bool,\n\n    /// Opens an interactive debugger.\n    /// Can only be used with `--trace`.\n    #[arg(long, requires = \"trace\")]\n    debug: bool,\n\n    /// Identify internal functions in traces.\n    ///\n    /// This will trace internal functions and decode stack parameters.\n    ///\n    /// Parameters stored in memory (such as bytes or arrays) are currently decoded only when a\n    /// single function is matched, similarly to `--debug`, for performance reasons.\n    #[arg(long, requires = \"trace\")]\n    decode_internal: bool,\n\n    /// Labels to apply to the traces; format: `address:label`.\n    /// Can only be used with `--trace`.\n    #[arg(long, requires = \"trace\")]\n    labels: Vec<String>,\n\n    /// The EVM Version to use.\n    /// Can only be used with `--trace`.\n    #[arg(long, requires = \"trace\")]\n    evm_version: Option<EvmVersion>,\n\n    /// The block height to query at.\n    ///\n    /// Can also be the tags earliest, finalized, safe, latest, or pending.\n    #[arg(long, short)]\n    block: Option<BlockId>,\n\n    #[command(subcommand)]\n    command: Option<CallSubcommands>,\n\n    #[command(flatten)]\n    tx: TransactionOpts,\n\n    #[command(flatten)]\n    rpc: RpcOpts,\n\n    #[command(flatten)]\n    wallet: WalletOpts,\n\n    #[arg(\n        short,\n        long,\n        alias = \"chain-id\",\n        env = \"CHAIN\",\n        value_parser = ChainValueParser::default(),\n    )]\n    pub chain: Option<Chain>,\n\n    /// Use current project artifacts for trace decoding.\n    #[arg(long, visible_alias = \"la\")]\n    pub with_local_artifacts: bool,\n\n    /// Override the accounts balance.\n    /// Format: \"address:balance,address:balance\"\n    #[arg(long = \"override-balance\", value_name = \"ADDRESS:BALANCE\", value_delimiter = ',')]\n    pub balance_overrides: Option<Vec<String>>,\n\n    /// Override the accounts nonce.\n    /// Format: \"address:nonce,address:nonce\"\n    #[arg(long = \"override-nonce\", value_name = \"ADDRESS:NONCE\", value_delimiter = ',')]\n    pub nonce_overrides: Option<Vec<String>>,\n\n    /// Override the accounts code.\n    /// Format: \"address:code,address:code\"\n    #[arg(long = \"override-code\", value_name = \"ADDRESS:CODE\", value_delimiter = ',')]\n    pub code_overrides: Option<Vec<String>>,\n\n    /// Override the accounts state and replace the current state entirely with the new one.\n    /// Format: \"address:slot:value,address:slot:value\"\n    #[arg(long = \"override-state\", value_name = \"ADDRESS:SLOT:VALUE\", value_delimiter = ',')]\n    pub state_overrides: Option<Vec<String>>,\n\n    /// Override the accounts state specific slots and preserve the rest of the state.\n    /// Format: \"address:slot:value,address:slot:value\"\n    #[arg(long = \"override-state-diff\", value_name = \"ADDRESS:SLOT:VALUE\", value_delimiter = ',')]\n    pub state_diff_overrides: Option<Vec<String>>,\n\n    /// Override the block timestamp.\n    #[arg(long = \"block.time\", value_name = \"TIME\")]\n    pub block_time: Option<u64>,\n\n    /// Override the block number.\n    #[arg(long = \"block.number\", value_name = \"NUMBER\")]\n    pub block_number: Option<u64>,\n}\n\n#[derive(Debug, Parser)]\npub enum CallSubcommands {\n    /// ignores the address field and simulates creating a contract\n    #[command(name = \"--create\")]\n    Create {\n        /// Bytecode of contract.\n        code: String,\n\n        /// The signature of the constructor.\n        sig: Option<String>,\n\n        /// The arguments of the constructor.\n        #[arg(allow_negative_numbers = true)]\n        args: Vec<String>,\n\n        /// Ether to send in the transaction.\n        ///\n        /// Either specified in wei, or as a string with a unit type.\n        ///\n        /// Examples: 1ether, 10gwei, 0.01ether\n        #[arg(long, value_parser = parse_ether_value)]\n        value: Option<U256>,\n    },\n}\n\nimpl CallArgs {\n    pub async fn run(self) -> Result<()> {\n        // Handle --curl mode early, before any provider interaction\n        if self.rpc.curl {\n            return self.run_curl().await;\n        }\n        if self.tx.tempo.is_tempo() {\n            self.run_with_network::<TempoNetwork>().await\n        } else {\n            self.run_with_network::<AnyNetwork>().await\n        }\n    }\n\n    pub async fn run_with_network<N: Network + Unpin>(self) -> Result<()>\n    where\n        N::TransactionRequest: FoundryTransactionBuilder<N>,\n    {\n        let figment = self.rpc.clone().into_figment(self.with_local_artifacts).merge(&self);\n        let evm_opts = figment.extract::<EvmOpts>()?;\n        let mut config = Config::from_provider(figment)?.sanitized();\n        let state_overrides = self.get_state_overrides()?;\n        let block_overrides = self.get_block_overrides()?;\n\n        let Self {\n            to,\n            mut sig,\n            mut args,\n            mut tx,\n            command,\n            block,\n            trace,\n            evm_version,\n            debug,\n            decode_internal,\n            labels,\n            data,\n            with_local_artifacts,\n            disable_labels,\n            wallet,\n            ..\n        } = self;\n\n        if let Some(data) = data {\n            sig = Some(data);\n        }\n\n        let provider = ProviderBuilder::<N>::from_config(&config)?.build()?;\n        let sender = SenderKind::from_wallet_opts(wallet).await?;\n        let from = sender.address();\n\n        let code = if let Some(CallSubcommands::Create {\n            code,\n            sig: create_sig,\n            args: create_args,\n            value,\n        }) = command\n        {\n            sig = create_sig;\n            args = create_args;\n            if let Some(value) = value {\n                tx.value = Some(value);\n            }\n            Some(code)\n        } else {\n            None\n        };\n\n        let (tx, func) = CastTxBuilder::new(&provider, tx, &config)\n            .await?\n            .with_to(to)\n            .await?\n            .with_code_sig_and_args(code, sig, args)\n            .await?\n            .raw()\n            .build(sender)\n            .await?;\n\n        if trace {\n            if let Some(BlockId::Number(BlockNumberOrTag::Number(block_number))) = self.block {\n                // Override Config `fork_block_number` (if set) with CLI value.\n                config.fork_block_number = Some(block_number);\n            }\n\n            let create2_deployer = evm_opts.create2_deployer;\n            let (mut evm_env, tx_env, fork, chain, networks) =\n                TracingExecutor::get_fork_material(&mut config, evm_opts).await?;\n\n            // modify settings that usually set in eth_call\n            evm_env.cfg_env.disable_block_gas_limit = true;\n            evm_env.cfg_env.tx_gas_limit_cap = Some(u64::MAX);\n            evm_env.block_env.gas_limit = u64::MAX;\n\n            // Apply the block overrides.\n            if let Some(block_overrides) = block_overrides {\n                if let Some(number) = block_overrides.number {\n                    evm_env.block_env.number = number.to();\n                }\n                if let Some(time) = block_overrides.time {\n                    evm_env.block_env.timestamp = U256::from(time);\n                }\n            }\n\n            let trace_mode = TraceMode::Call\n                .with_debug(debug)\n                .with_decode_internal(if decode_internal {\n                    InternalTraceMode::Full\n                } else {\n                    InternalTraceMode::None\n                })\n                .with_state_changes(shell::verbosity() > 4);\n            let mut executor = TracingExecutor::new(\n                (evm_env, tx_env),\n                fork,\n                evm_version,\n                trace_mode,\n                networks,\n                create2_deployer,\n                state_overrides,\n            )?;\n\n            let value = tx.value().unwrap_or_default();\n            let input = tx.input().cloned().unwrap_or_default();\n            let tx_kind = tx.kind().expect(\"set by builder\");\n            let env_tx = executor.tx_env_mut();\n\n            // Set transaction options with --trace\n            if let Some(gas_limit) = tx.gas_limit() {\n                env_tx.gas_limit = gas_limit;\n            }\n\n            if let Some(gas_price) = tx.gas_price() {\n                env_tx.gas_price = gas_price;\n            }\n\n            if let Some(max_fee_per_gas) = tx.max_fee_per_gas() {\n                env_tx.gas_price = max_fee_per_gas;\n            }\n\n            if let Some(max_priority_fee_per_gas) = tx.max_priority_fee_per_gas() {\n                env_tx.gas_priority_fee = Some(max_priority_fee_per_gas);\n            }\n\n            if let Some(max_fee_per_blob_gas) = tx.max_fee_per_blob_gas() {\n                env_tx.max_fee_per_blob_gas = max_fee_per_blob_gas;\n            }\n\n            if let Some(nonce) = tx.nonce() {\n                env_tx.nonce = nonce;\n            }\n\n            env_tx.tx_type = tx.output_tx_type().into();\n\n            if let Some(access_list) = tx.access_list().cloned() {\n                env_tx.access_list = access_list;\n\n                if env_tx.tx_type == TransactionType::Legacy as u8 {\n                    env_tx.tx_type = TransactionType::Eip2930 as u8;\n                }\n            }\n\n            if let Some(auth) = tx.authorization_list().cloned() {\n                env_tx.authorization_list = auth.into_iter().map(Either::Left).collect();\n\n                env_tx.tx_type = TransactionType::Eip7702 as u8;\n            }\n\n            let trace = match tx_kind {\n                TxKind::Create => {\n                    let deploy_result = executor.deploy(from, input, value, None);\n                    TraceResult::try_from(deploy_result)?\n                }\n                TxKind::Call(to) => TraceResult::from_raw(\n                    executor.transact_raw(from, to, input, value)?,\n                    TraceKind::Execution,\n                ),\n            };\n\n            let contracts_bytecode = fetch_contracts_bytecode_from_trace(&executor, &trace)?;\n            handle_traces(\n                trace,\n                &config,\n                chain,\n                &contracts_bytecode,\n                labels,\n                with_local_artifacts,\n                debug,\n                decode_internal,\n                disable_labels,\n                None,\n            )\n            .await?;\n\n            return Ok(());\n        }\n\n        let response = Cast::new(&provider)\n            .call(&tx, func.as_ref(), block, state_overrides, block_overrides)\n            .await?;\n\n        if response == \"0x\"\n            && let Some(contract_address) = tx.to()\n        {\n            let code = provider.get_code_at(contract_address).await?;\n            if code.is_empty() {\n                sh_warn!(\"Contract code is empty\")?;\n            }\n        }\n        sh_println!(\"{}\", response)?;\n\n        Ok(())\n    }\n\n    /// Handle --curl mode by generating curl command without any RPC interaction.\n    async fn run_curl(self) -> Result<()> {\n        let config = self.rpc.load_config()?;\n        let url = config.get_rpc_url_or_localhost_http()?;\n        let jwt = config.get_rpc_jwt_secret()?;\n\n        // Get call data - either from --data or from sig + args\n        let data = if let Some(data) = &self.data {\n            hex::decode(data)?\n        } else if let Some(sig) = &self.sig {\n            // If sig is already hex data, use it directly\n            if let Ok(data) = hex::decode(sig) {\n                data\n            } else {\n                // Parse function signature and encode args\n                let func = get_func(sig)?;\n                encode_function_args(&func, &self.args)?\n            }\n        } else {\n            Vec::new()\n        };\n\n        // Resolve the destination address (must be a raw address for curl mode)\n        let to = self.to.as_ref().map(|n| match n {\n            NameOrAddress::Address(addr) => Ok(*addr),\n            NameOrAddress::Name(name) => {\n                eyre::bail!(\"ENS names are not supported with --curl. Please use a raw address instead of '{}'\", name)\n            }\n        }).transpose()?;\n\n        // Build eth_call params\n        let call_object = serde_json::json!({\n            \"to\": to,\n            \"data\": format!(\"0x{}\", hex::encode(&data)),\n        });\n\n        let block_param = self\n            .block\n            .map(|b| serde_json::to_value(b).unwrap_or(serde_json::json!(\"latest\")))\n            .unwrap_or(serde_json::json!(\"latest\"));\n\n        let params = serde_json::json!([call_object, block_param]);\n\n        let curl_cmd = generate_curl_command(\n            url.as_ref(),\n            \"eth_call\",\n            params,\n            config.eth_rpc_headers.as_deref(),\n            jwt.as_deref(),\n        );\n\n        sh_println!(\"{}\", curl_cmd)?;\n        Ok(())\n    }\n\n    /// Parse state overrides from command line arguments.\n    pub fn get_state_overrides(&self) -> eyre::Result<Option<StateOverride>> {\n        // Early return if no override set - <https://github.com/foundry-rs/foundry/issues/10705>\n        if [\n            self.balance_overrides.as_ref(),\n            self.nonce_overrides.as_ref(),\n            self.code_overrides.as_ref(),\n            self.state_overrides.as_ref(),\n            self.state_diff_overrides.as_ref(),\n        ]\n        .iter()\n        .all(Option::is_none)\n        {\n            return Ok(None);\n        }\n\n        let mut state_overrides_builder = StateOverridesBuilder::default();\n\n        // Parse balance overrides\n        for override_str in self.balance_overrides.iter().flatten() {\n            let (addr, balance) = address_value_override(override_str)?;\n            state_overrides_builder =\n                state_overrides_builder.with_balance(addr.parse()?, balance.parse()?);\n        }\n\n        // Parse nonce overrides\n        for override_str in self.nonce_overrides.iter().flatten() {\n            let (addr, nonce) = address_value_override(override_str)?;\n            state_overrides_builder =\n                state_overrides_builder.with_nonce(addr.parse()?, nonce.parse()?);\n        }\n\n        // Parse code overrides\n        for override_str in self.code_overrides.iter().flatten() {\n            let (addr, code_str) = address_value_override(override_str)?;\n            state_overrides_builder =\n                state_overrides_builder.with_code(addr.parse()?, Bytes::from_str(code_str)?);\n        }\n\n        type StateOverrides = HashMap<Address, HashMap<B256, B256>>;\n        let parse_state_overrides =\n            |overrides: &Option<Vec<String>>| -> Result<StateOverrides, eyre::Report> {\n                let mut state_overrides: StateOverrides = StateOverrides::default();\n\n                overrides.iter().flatten().try_for_each(|s| -> Result<(), eyre::Report> {\n                    let (addr, slot, value) = address_slot_value_override(s)?;\n                    state_overrides.entry(addr).or_default().insert(slot.into(), value.into());\n                    Ok(())\n                })?;\n\n                Ok(state_overrides)\n            };\n\n        // Parse and apply state overrides\n        for (addr, entries) in parse_state_overrides(&self.state_overrides)? {\n            state_overrides_builder = state_overrides_builder.with_state(addr, entries);\n        }\n\n        // Parse and apply state diff overrides\n        for (addr, entries) in parse_state_overrides(&self.state_diff_overrides)? {\n            state_overrides_builder = state_overrides_builder.with_state_diff(addr, entries)\n        }\n\n        Ok(Some(state_overrides_builder.build()))\n    }\n\n    /// Parse block overrides from command line arguments.\n    pub fn get_block_overrides(&self) -> eyre::Result<Option<BlockOverrides>> {\n        let mut overrides = BlockOverrides::default();\n        if let Some(number) = self.block_number {\n            overrides = overrides.with_number(U256::from(number));\n        }\n        if let Some(time) = self.block_time {\n            overrides = overrides.with_time(time);\n        }\n        if overrides.is_empty() { Ok(None) } else { Ok(Some(overrides)) }\n    }\n}\n\nimpl figment::Provider for CallArgs {\n    fn metadata(&self) -> Metadata {\n        Metadata::named(\"CallArgs\")\n    }\n\n    fn data(&self) -> Result<Map<Profile, Dict>, figment::Error> {\n        let mut map = Map::new();\n\n        if let Some(evm_version) = self.evm_version {\n            map.insert(\"evm_version\".into(), figment::value::Value::serialize(evm_version)?);\n        }\n\n        Ok(Map::from([(Config::selected_profile(), map)]))\n    }\n}\n\n/// Parse an override string in the format address:value.\nfn address_value_override(address_override: &str) -> Result<(&str, &str)> {\n    address_override.split_once(':').ok_or_else(|| {\n        eyre::eyre!(\"Invalid override {address_override}. Expected <address>:<value>\")\n    })\n}\n\n/// Parse an override string in the format address:slot:value.\nfn address_slot_value_override(address_override: &str) -> Result<(Address, U256, U256)> {\n    let captures = OVERRIDE_PATTERN.captures(address_override).ok_or_else(|| {\n        eyre::eyre!(\"Invalid override {address_override}. Expected <address>:<slot>:<value>\")\n    })?;\n\n    Ok((\n        captures[1].parse()?, // Address\n        captures[2].parse()?, // Slot (U256)\n        captures[3].parse()?, // Value (U256)\n    ))\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use alloy_primitives::{U64, address, b256, fixed_bytes};\n\n    #[test]\n    fn test_get_state_overrides() {\n        let call_args = CallArgs::parse_from([\n            \"foundry-cli\",\n            \"--override-balance\",\n            \"0x0000000000000000000000000000000000000001:2\",\n            \"--override-nonce\",\n            \"0x0000000000000000000000000000000000000001:3\",\n            \"--override-code\",\n            \"0x0000000000000000000000000000000000000001:0x04\",\n            \"--override-state\",\n            \"0x0000000000000000000000000000000000000001:5:6\",\n            \"--override-state-diff\",\n            \"0x0000000000000000000000000000000000000001:7:8\",\n        ]);\n        let overrides = call_args.get_state_overrides().unwrap().unwrap();\n        let address = address!(\"0x0000000000000000000000000000000000000001\");\n        if let Some(account_override) = overrides.get(&address) {\n            if let Some(balance) = account_override.balance {\n                assert_eq!(balance, U256::from(2));\n            }\n            if let Some(nonce) = account_override.nonce {\n                assert_eq!(nonce, 3);\n            }\n            if let Some(code) = &account_override.code {\n                assert_eq!(*code, Bytes::from([0x04]));\n            }\n            if let Some(state) = &account_override.state\n                && let Some(value) = state.get(&b256!(\n                    \"0x0000000000000000000000000000000000000000000000000000000000000005\"\n                ))\n            {\n                assert_eq!(\n                    *value,\n                    b256!(\"0x0000000000000000000000000000000000000000000000000000000000000006\")\n                );\n            }\n            if let Some(state_diff) = &account_override.state_diff\n                && let Some(value) = state_diff.get(&b256!(\n                    \"0x0000000000000000000000000000000000000000000000000000000000000007\"\n                ))\n            {\n                assert_eq!(\n                    *value,\n                    b256!(\"0x0000000000000000000000000000000000000000000000000000000000000008\")\n                );\n            }\n        }\n    }\n\n    #[test]\n    fn test_get_state_overrides_empty() {\n        let call_args = CallArgs::parse_from([\"\"]);\n        let overrides = call_args.get_state_overrides().unwrap();\n        assert_eq!(overrides, None);\n    }\n\n    #[test]\n    fn test_get_block_overrides() {\n        let mut call_args = CallArgs::parse_from([\"\"]);\n        call_args.block_number = Some(1);\n        call_args.block_time = Some(2);\n        let overrides = call_args.get_block_overrides().unwrap().unwrap();\n        assert_eq!(overrides.number, Some(U256::from(1)));\n        assert_eq!(overrides.time, Some(2));\n    }\n\n    #[test]\n    fn test_get_block_overrides_empty() {\n        let call_args = CallArgs::parse_from([\"\"]);\n        let overrides = call_args.get_block_overrides().unwrap();\n        assert_eq!(overrides, None);\n    }\n\n    #[test]\n    fn test_address_value_override_success() {\n        let text = \"0x0000000000000000000000000000000000000001:2\";\n        let (address, value) = address_value_override(text).unwrap();\n        assert_eq!(address, \"0x0000000000000000000000000000000000000001\");\n        assert_eq!(value, \"2\");\n    }\n\n    #[test]\n    fn test_address_value_override_error() {\n        let text = \"invalid_value\";\n        let error = address_value_override(text).unwrap_err();\n        assert_eq!(error.to_string(), \"Invalid override invalid_value. Expected <address>:<value>\");\n    }\n\n    #[test]\n    fn test_address_slot_value_override_success() {\n        let text = \"0x0000000000000000000000000000000000000001:2:3\";\n        let (address, slot, value) = address_slot_value_override(text).unwrap();\n        assert_eq!(*address, fixed_bytes!(\"0x0000000000000000000000000000000000000001\"));\n        assert_eq!(slot, U256::from(2));\n        assert_eq!(value, U256::from(3));\n    }\n\n    #[test]\n    fn test_address_slot_value_override_error() {\n        let text = \"invalid_value\";\n        let error = address_slot_value_override(text).unwrap_err();\n        assert_eq!(\n            error.to_string(),\n            \"Invalid override invalid_value. Expected <address>:<slot>:<value>\"\n        );\n    }\n\n    #[test]\n    fn can_parse_call_data() {\n        let data = hex::encode(\"hello\");\n        let args = CallArgs::parse_from([\"foundry-cli\", \"--data\", data.as_str()]);\n        assert_eq!(args.data, Some(data));\n\n        let data = hex::encode_prefixed(\"hello\");\n        let args = CallArgs::parse_from([\"foundry-cli\", \"--data\", data.as_str()]);\n        assert_eq!(args.data, Some(data));\n    }\n\n    #[test]\n    fn can_parse_state_overrides() {\n        let args = CallArgs::parse_from([\n            \"foundry-cli\",\n            \"--override-balance\",\n            \"0x123:0x1234\",\n            \"--override-nonce\",\n            \"0x123:1\",\n            \"--override-code\",\n            \"0x123:0x1234\",\n            \"--override-state\",\n            \"0x123:0x1:0x1234\",\n        ]);\n\n        assert_eq!(args.balance_overrides, Some(vec![\"0x123:0x1234\".to_string()]));\n        assert_eq!(args.nonce_overrides, Some(vec![\"0x123:1\".to_string()]));\n        assert_eq!(args.code_overrides, Some(vec![\"0x123:0x1234\".to_string()]));\n        assert_eq!(args.state_overrides, Some(vec![\"0x123:0x1:0x1234\".to_string()]));\n    }\n\n    #[test]\n    fn can_parse_multiple_state_overrides() {\n        let args = CallArgs::parse_from([\n            \"foundry-cli\",\n            \"--override-balance\",\n            \"0x123:0x1234\",\n            \"--override-balance\",\n            \"0x456:0x5678\",\n            \"--override-nonce\",\n            \"0x123:1\",\n            \"--override-nonce\",\n            \"0x456:2\",\n            \"--override-code\",\n            \"0x123:0x1234\",\n            \"--override-code\",\n            \"0x456:0x5678\",\n            \"--override-state\",\n            \"0x123:0x1:0x1234\",\n            \"--override-state\",\n            \"0x456:0x2:0x5678\",\n        ]);\n\n        assert_eq!(\n            args.balance_overrides,\n            Some(vec![\"0x123:0x1234\".to_string(), \"0x456:0x5678\".to_string()])\n        );\n        assert_eq!(args.nonce_overrides, Some(vec![\"0x123:1\".to_string(), \"0x456:2\".to_string()]));\n        assert_eq!(\n            args.code_overrides,\n            Some(vec![\"0x123:0x1234\".to_string(), \"0x456:0x5678\".to_string()])\n        );\n        assert_eq!(\n            args.state_overrides,\n            Some(vec![\"0x123:0x1:0x1234\".to_string(), \"0x456:0x2:0x5678\".to_string()])\n        );\n    }\n\n    #[test]\n    fn test_negative_args_with_flags() {\n        // Test that negative args work with flags\n        let args = CallArgs::parse_from([\n            \"foundry-cli\",\n            \"--trace\",\n            \"0xDeaDBeeFcAfEbAbEfAcEfEeDcBaDbEeFcAfEbAbE\",\n            \"process(int256)\",\n            \"-999999\",\n            \"--debug\",\n        ]);\n\n        assert!(args.trace);\n        assert!(args.debug);\n        assert_eq!(args.args, vec![\"-999999\"]);\n    }\n\n    #[test]\n    fn test_transaction_opts_with_trace() {\n        // Test that transaction options are correctly parsed when using --trace\n        let args = CallArgs::parse_from([\n            \"foundry-cli\",\n            \"--trace\",\n            \"--gas-limit\",\n            \"1000000\",\n            \"--gas-price\",\n            \"20000000000\",\n            \"--priority-gas-price\",\n            \"2000000000\",\n            \"--nonce\",\n            \"42\",\n            \"--value\",\n            \"1000000000000000000\", // 1 ETH\n            \"--blob-gas-price\",\n            \"10000000000\",\n            \"0xDeaDBeeFcAfEbAbEfAcEfEeDcBaDbEeFcAfEbAbE\",\n            \"balanceOf(address)\",\n            \"0x123456789abcdef123456789abcdef123456789a\",\n        ]);\n\n        assert!(args.trace);\n        assert_eq!(args.tx.gas_limit, Some(U256::from(1000000u32)));\n        assert_eq!(args.tx.gas_price, Some(U256::from(20000000000u64)));\n        assert_eq!(args.tx.priority_gas_price, Some(U256::from(2000000000u64)));\n        assert_eq!(args.tx.nonce, Some(U64::from(42)));\n        assert_eq!(args.tx.value, Some(U256::from(1000000000000000000u64)));\n        assert_eq!(args.tx.blob_gas_price, Some(U256::from(10000000000u64)));\n    }\n}\n"
  },
  {
    "path": "crates/cast/src/cmd/constructor_args.rs",
    "content": "use super::{creation_code::fetch_creation_code_from_etherscan, interface::load_abi_from_file};\nuse alloy_dyn_abi::DynSolType;\nuse alloy_primitives::{Address, Bytes};\nuse alloy_provider::Provider;\nuse clap::Parser;\nuse eyre::{OptionExt, Result, eyre};\nuse foundry_cli::{\n    opts::{EtherscanOpts, RpcOpts},\n    utils::{self, LoadConfig, fetch_abi_from_etherscan},\n};\nuse foundry_config::Config;\n\nfoundry_config::impl_figment_convert!(ConstructorArgsArgs, etherscan, rpc);\n\n/// CLI arguments for `cast creation-args`.\n#[derive(Parser)]\npub struct ConstructorArgsArgs {\n    /// An Ethereum address, for which the bytecode will be fetched.\n    contract: Address,\n\n    /// Path to file containing the contract's JSON ABI. It's necessary if the target contract is\n    /// not verified on Etherscan\n    #[arg(long)]\n    abi_path: Option<String>,\n\n    #[command(flatten)]\n    etherscan: EtherscanOpts,\n\n    #[command(flatten)]\n    rpc: RpcOpts,\n}\n\nimpl ConstructorArgsArgs {\n    pub async fn run(self) -> Result<()> {\n        let mut config = self.load_config()?;\n\n        let Self { contract, abi_path, etherscan: _, rpc: _ } = self;\n\n        let provider = utils::get_provider(&config)?;\n        config.chain = Some(provider.get_chain_id().await?.into());\n\n        let bytecode = fetch_creation_code_from_etherscan(contract, &config, provider).await?;\n\n        let args_arr = parse_constructor_args(bytecode, contract, &config, abi_path).await?;\n        for arg in args_arr {\n            let _ = sh_println!(\"{arg}\");\n        }\n\n        Ok(())\n    }\n}\n\n/// Fetches the constructor arguments values and types from the creation bytecode and ABI.\nasync fn parse_constructor_args(\n    bytecode: Bytes,\n    contract: Address,\n    config: &Config,\n    abi_path: Option<String>,\n) -> Result<Vec<String>> {\n    let abi = if let Some(abi_path) = abi_path {\n        load_abi_from_file(&abi_path, None)?\n    } else {\n        fetch_abi_from_etherscan(contract, config).await?\n    };\n\n    let abi = abi.into_iter().next().ok_or_eyre(\"No ABI found.\")?;\n    let (abi, _) = abi;\n\n    let constructor = abi.constructor.ok_or_else(|| eyre!(\"No constructor found.\"))?;\n\n    if constructor.inputs.is_empty() {\n        return Err(eyre!(\"No constructor arguments found.\"));\n    }\n\n    let args_size = constructor.inputs.len() * 32;\n    if bytecode.len() < args_size {\n        return Err(eyre!(\n            \"Invalid creation bytecode length: have {} bytes, need at least {} for {} constructor inputs\",\n            bytecode.len(),\n            args_size,\n            constructor.inputs.len()\n        ));\n    }\n    let args_bytes = Bytes::from(bytecode[bytecode.len() - args_size..].to_vec());\n\n    let display_args: Vec<String> = args_bytes\n        .chunks(32)\n        .enumerate()\n        .map(|(i, arg)| format_arg(&constructor.inputs[i].ty, arg))\n        .collect::<Result<Vec<_>>>()?;\n\n    Ok(display_args)\n}\n\nfn format_arg(ty: &str, arg: &[u8]) -> Result<String> {\n    let arg_type: DynSolType = ty.parse()?;\n    let decoded = arg_type.abi_decode(arg)?;\n    let bytes = Bytes::from(arg.to_vec());\n\n    Ok(format!(\"{bytes} → {decoded:?}\"))\n}\n"
  },
  {
    "path": "crates/cast/src/cmd/create2.rs",
    "content": "use alloy_primitives::{Address, B256, U256, hex, keccak256};\nuse clap::Parser;\nuse eyre::{Result, WrapErr};\nuse rand::{RngCore, SeedableRng, rngs::StdRng};\nuse regex::RegexSetBuilder;\nuse std::{\n    sync::{\n        Arc,\n        atomic::{AtomicBool, Ordering},\n    },\n    time::Instant,\n};\n\n// https://etherscan.io/address/0x4e59b44847b379578588920ca78fbf26c0b4956c#code\nconst DEPLOYER: &str = \"0x4e59b44847b379578588920ca78fbf26c0b4956c\";\n\n/// CLI arguments for `cast create2`.\n#[derive(Clone, Debug, Parser)]\npub struct Create2Args {\n    /// Prefix for the contract address.\n    #[arg(\n        long,\n        short,\n        required_unless_present_any = &[\"ends_with\", \"matching\", \"salt\"],\n        value_name = \"HEX\"\n    )]\n    starts_with: Option<String>,\n\n    /// Suffix for the contract address.\n    #[arg(long, short, value_name = \"HEX\")]\n    ends_with: Option<String>,\n\n    /// Sequence that the address has to match.\n    #[arg(long, short, value_name = \"HEX\")]\n    matching: Option<String>,\n\n    /// Case sensitive matching.\n    #[arg(short, long)]\n    case_sensitive: bool,\n\n    /// Address of the contract deployer.\n    #[arg(\n        short,\n        long,\n        default_value = DEPLOYER,\n        value_name = \"ADDRESS\"\n    )]\n    deployer: Address,\n\n    /// Salt to be used for the contract deployment. This option separate from the default salt\n    /// mining with filters.\n    #[arg(\n        long,\n        conflicts_with_all = [\n            \"starts_with\",\n            \"ends_with\",\n            \"matching\",\n            \"case_sensitive\",\n            \"caller\",\n            \"seed\",\n            \"no_random\"\n        ],\n        value_name = \"HEX\"\n    )]\n    salt: Option<String>,\n\n    /// Init code of the contract to be deployed.\n    #[arg(short, long, value_name = \"HEX\")]\n    init_code: Option<String>,\n\n    /// Init code hash of the contract to be deployed.\n    #[arg(alias = \"ch\", long, value_name = \"HASH\", required_unless_present = \"init_code\")]\n    init_code_hash: Option<String>,\n\n    /// Number of threads to use. Specifying 0 defaults to the number of logical cores.\n    #[arg(global = true, long, short = 'j', visible_alias = \"jobs\")]\n    threads: Option<usize>,\n\n    /// Address of the caller. Used for the first 20 bytes of the salt.\n    #[arg(long, value_name = \"ADDRESS\")]\n    caller: Option<Address>,\n\n    /// The random number generator's seed, used to initialize the salt.\n    #[arg(long, value_name = \"HEX\")]\n    seed: Option<B256>,\n\n    /// Don't initialize the salt with a random value, and instead use the default value of 0.\n    #[arg(long, conflicts_with = \"seed\")]\n    no_random: bool,\n}\n\npub struct Create2Output {\n    pub address: Address,\n    pub salt: B256,\n}\n\nimpl Create2Args {\n    pub fn run(self) -> Result<Create2Output> {\n        let Self {\n            starts_with,\n            ends_with,\n            matching,\n            case_sensitive,\n            deployer,\n            salt,\n            init_code,\n            init_code_hash,\n            threads,\n            caller,\n            seed,\n            no_random,\n        } = self;\n\n        let init_code_hash = if let Some(init_code_hash) = init_code_hash {\n            hex::FromHex::from_hex(init_code_hash)\n        } else if let Some(init_code) = init_code {\n            hex::decode(init_code).map(keccak256)\n        } else {\n            unreachable!();\n        }?;\n\n        if let Some(salt) = salt {\n            let salt = hex::FromHex::from_hex(salt)?;\n            let address = deployer.create2(salt, init_code_hash);\n            sh_println!(\"{address}\")?;\n            return Ok(Create2Output { address, salt });\n        }\n\n        let mut regexs = vec![];\n\n        if let Some(matches) = matching {\n            if starts_with.is_some() || ends_with.is_some() {\n                eyre::bail!(\"Either use --matching or --starts/ends-with\");\n            }\n\n            let matches = matches.trim_start_matches(\"0x\");\n\n            if matches.len() != 40 {\n                eyre::bail!(\"Please provide a 40 characters long sequence for matching\");\n            }\n\n            hex::decode(matches.replace('X', \"0\")).wrap_err(\"invalid matching hex provided\")?;\n            // replacing X placeholders by . to match any character at these positions\n\n            regexs.push(matches.replace('X', \".\"));\n        }\n\n        if let Some(prefix) = starts_with {\n            regexs.push(format!(\n                r\"^{}\",\n                get_regex_hex_string(prefix).wrap_err(\"invalid prefix hex provided\")?\n            ));\n        }\n        if let Some(suffix) = ends_with {\n            regexs.push(format!(\n                r\"{}$\",\n                get_regex_hex_string(suffix).wrap_err(\"invalid suffix hex provided\")?\n            ))\n        }\n\n        debug_assert!(\n            regexs.iter().map(|p| p.len() - 1).sum::<usize>() <= 40,\n            \"vanity patterns length exceeded. cannot be more than 40 characters\",\n        );\n\n        let regex = RegexSetBuilder::new(regexs).case_insensitive(!case_sensitive).build()?;\n\n        let mut n_threads = threads.unwrap_or(0);\n        if n_threads == 0 {\n            n_threads = std::thread::available_parallelism().map_or(1, |n| n.get());\n        }\n        if cfg!(test) {\n            n_threads = n_threads.min(2);\n        }\n\n        let mut salt = B256::ZERO;\n        let remaining = if let Some(caller_address) = caller {\n            salt[..20].copy_from_slice(&caller_address.into_array());\n            &mut salt[20..]\n        } else {\n            &mut salt[..]\n        };\n\n        if !no_random {\n            let mut rng = match seed {\n                Some(seed) => StdRng::from_seed(seed.0),\n                None => StdRng::from_os_rng(),\n            };\n            rng.fill_bytes(remaining);\n        }\n\n        sh_println!(\"Configuration:\")?;\n        sh_println!(\"Init code hash: {init_code_hash}\")?;\n        sh_println!(\"Regex patterns: {:?}\\n\", regex.patterns())?;\n        sh_println!(\n            \"Starting to generate deterministic contract address with {n_threads} threads...\"\n        )?;\n        let mut handles = Vec::with_capacity(n_threads);\n        let found = Arc::new(AtomicBool::new(false));\n        let timer = Instant::now();\n\n        // Loops through all possible salts in parallel until a result is found.\n        // Each thread iterates over `(i..).step_by(n_threads)`.\n        for i in 0..n_threads {\n            // Create local copies for the thread.\n            let increment = n_threads;\n            let regex = regex.clone();\n            let regex_len = regex.patterns().len();\n            let found = Arc::clone(&found);\n            handles.push(std::thread::spawn(move || {\n                // Read the first bytes of the salt as a usize to be able to increment it.\n                struct B256Aligned(B256, [usize; 0]);\n                let mut salt = B256Aligned(salt, []);\n                // SAFETY: B256 is aligned to `usize`.\n                let salt_word = unsafe {\n                    &mut *salt.0.as_mut_ptr().add(32 - usize::BITS as usize / 8).cast::<usize>()\n                };\n                // Important: add the thread index to the salt to avoid duplicate results.\n                *salt_word = salt_word.wrapping_add(i);\n\n                // Use checksum format only when case_sensitive is enabled.\n                // This avoids an extra keccak256 call per iteration when not needed.\n                let mut checksum_buf = [0u8; 42];\n                let mut hex_buf = [0u8; 40];\n                loop {\n                    // Stop if a result was found in another thread.\n                    if found.load(Ordering::Relaxed) {\n                        break None;\n                    }\n\n                    // Calculate the `CREATE2` address.\n                    #[expect(clippy::needless_borrows_for_generic_args)]\n                    let addr = deployer.create2(&salt.0, &init_code_hash);\n\n                    // Check if the regex matches the calculated address.\n                    // When case_sensitive is true, use EIP-55 checksum format (requires keccak256).\n                    // Otherwise, use lowercase hex to avoid the extra hash computation.\n                    let s = if case_sensitive {\n                        let _ = addr.to_checksum_raw(&mut checksum_buf, None);\n                        // SAFETY: stripping 2 ASCII bytes (\"0x\") off of an already valid UTF-8\n                        // string is safe.\n                        unsafe { std::str::from_utf8_unchecked(checksum_buf.get_unchecked(2..)) }\n                    } else {\n                        // SAFETY: hex::encode_to_slice always produces valid UTF-8 (hex digits).\n                        let _ = hex::encode_to_slice(addr.as_slice(), &mut hex_buf);\n                        unsafe { std::str::from_utf8_unchecked(&hex_buf) }\n                    };\n                    if regex.matches(s).into_iter().count() == regex_len {\n                        // Notify other threads that we found a result.\n                        found.store(true, Ordering::Relaxed);\n                        break Some((addr, salt.0));\n                    }\n\n                    // Increment the salt for the next iteration.\n                    *salt_word = salt_word.wrapping_add(increment);\n                }\n            }));\n        }\n\n        let results = handles.into_iter().filter_map(|h| h.join().unwrap()).collect::<Vec<_>>();\n        let (address, salt) = results.into_iter().next().unwrap();\n        sh_println!(\"Successfully found contract address in {:?}\", timer.elapsed())?;\n        sh_println!(\"Address: {address}\")?;\n        sh_println!(\"Salt: {salt} ({})\", U256::from_be_bytes(salt.0))?;\n\n        Ok(Create2Output { address, salt })\n    }\n}\n\nfn get_regex_hex_string(s: String) -> Result<String> {\n    let s = s.strip_prefix(\"0x\").unwrap_or(&s);\n    let pad_width = s.len() + s.len() % 2;\n    hex::decode(format!(\"{s:0<pad_width$}\"))?;\n    Ok(s.to_string())\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use alloy_primitives::{address, b256};\n    use std::str::FromStr;\n\n    #[test]\n    fn basic_create2() {\n        let mk_args = |args: &[&str]| {\n            Create2Args::parse_from([\"foundry-cli\", \"--init-code-hash=0x0000000000000000000000000000000000000000000000000000000000000000\"].iter().chain(args))\n        };\n\n        // even hex chars\n        let args = mk_args(&[\"--starts-with\", \"aa\"]);\n        let create2_out = args.run().unwrap();\n        assert!(format!(\"{:x}\", create2_out.address).starts_with(\"aa\"));\n\n        let args = mk_args(&[\"--ends-with\", \"bb\"]);\n        let create2_out = args.run().unwrap();\n        assert!(format!(\"{:x}\", create2_out.address).ends_with(\"bb\"));\n\n        // odd hex chars\n        let args = mk_args(&[\"--starts-with\", \"aaa\"]);\n        let create2_out = args.run().unwrap();\n        assert!(format!(\"{:x}\", create2_out.address).starts_with(\"aaa\"));\n\n        let args = mk_args(&[\"--ends-with\", \"bbb\"]);\n        let create2_out = args.run().unwrap();\n        assert!(format!(\"{:x}\", create2_out.address).ends_with(\"bbb\"));\n\n        // even hex chars with 0x prefix\n        let args = mk_args(&[\"--starts-with\", \"0xaa\"]);\n        let create2_out = args.run().unwrap();\n        assert!(format!(\"{:x}\", create2_out.address).starts_with(\"aa\"));\n\n        // odd hex chars with 0x prefix\n        let args = mk_args(&[\"--starts-with\", \"0xaaa\"]);\n        let create2_out = args.run().unwrap();\n        assert!(format!(\"{:x}\", create2_out.address).starts_with(\"aaa\"));\n\n        // check fails on wrong chars\n        let args = mk_args(&[\"--starts-with\", \"0xerr\"]);\n        let create2_out = args.run();\n        assert!(create2_out.is_err());\n\n        // check fails on wrong x prefixed string provided\n        let args = mk_args(&[\"--starts-with\", \"x00\"]);\n        let create2_out = args.run();\n        assert!(create2_out.is_err());\n    }\n\n    #[test]\n    fn matches_pattern() {\n        let args = Create2Args::parse_from([\n            \"foundry-cli\",\n            \"--init-code-hash=0x0000000000000000000000000000000000000000000000000000000000000000\",\n            \"--matching=0xbbXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\",\n        ]);\n        let create2_out = args.run().unwrap();\n        let address = create2_out.address;\n        assert!(format!(\"{address:x}\").starts_with(\"bb\"));\n    }\n\n    #[test]\n    fn create2_salt() {\n        let args = Create2Args::parse_from([\n            \"foundry-cli\",\n            \"--deployer=0x8ba1f109551bD432803012645Ac136ddd64DBA72\",\n            \"--salt=0x7c5ea36004851c764c44143b1dcb59679b11c9a68e5f41497f6cf3d480715331\",\n            \"--init-code=0x6394198df16000526103ff60206004601c335afa6040516060f3\",\n        ]);\n        let create2_out = args.run().unwrap();\n        let address = create2_out.address;\n        assert_eq!(address, address!(\"0x533AE9D683B10C02EBDB05471642F85230071FC3\"));\n    }\n\n    #[test]\n    fn create2_init_code() {\n        let init_code = \"00\";\n        let args =\n            Create2Args::parse_from([\"foundry-cli\", \"--starts-with=cc\", \"--init-code\", init_code]);\n        let create2_out = args.run().unwrap();\n        let address = create2_out.address;\n        assert!(format!(\"{address:x}\").starts_with(\"cc\"));\n        let salt = create2_out.salt;\n        let deployer = Address::from_str(DEPLOYER).unwrap();\n        assert_eq!(address, deployer.create2_from_code(salt, hex::decode(init_code).unwrap()));\n    }\n\n    #[test]\n    fn create2_init_code_hash() {\n        let init_code_hash = \"bc36789e7a1e281436464229828f817d6612f7b477d66591ff96a9e064bcc98a\";\n        let args = Create2Args::parse_from([\n            \"foundry-cli\",\n            \"--starts-with=dd\",\n            \"--init-code-hash\",\n            init_code_hash,\n        ]);\n        let create2_out = args.run().unwrap();\n        let address = create2_out.address;\n        assert!(format!(\"{address:x}\").starts_with(\"dd\"));\n\n        let salt = create2_out.salt;\n        let deployer = Address::from_str(DEPLOYER).unwrap();\n\n        assert_eq!(\n            address,\n            deployer\n                .create2(salt, B256::from_slice(hex::decode(init_code_hash).unwrap().as_slice()))\n        );\n    }\n\n    #[test]\n    fn create2_caller() {\n        let init_code_hash = \"bc36789e7a1e281436464229828f817d6612f7b477d66591ff96a9e064bcc98a\";\n        let args = Create2Args::parse_from([\n            \"foundry-cli\",\n            \"--starts-with=dd\",\n            \"--init-code-hash\",\n            init_code_hash,\n            \"--caller=0x66f9664f97F2b50F62D13eA064982f936dE76657\",\n        ]);\n        let create2_out = args.run().unwrap();\n        let address = create2_out.address;\n        let salt = create2_out.salt;\n        assert!(format!(\"{address:x}\").starts_with(\"dd\"));\n        assert!(format!(\"{salt:x}\").starts_with(\"66f9664f97f2b50f62d13ea064982f936de76657\"));\n    }\n\n    #[test]\n    fn deterministic_seed() {\n        let args = Create2Args::parse_from([\n            \"foundry-cli\",\n            \"--starts-with=0x00\",\n            \"--init-code-hash=0x479d7e8f31234e208d704ba1a123c76385cea8a6981fd675b784fbd9cffb918d\",\n            \"--seed=0x479d7e8f31234e208d704ba1a123c76385cea8a6981fd675b784fbd9cffb918d\",\n            \"-j1\",\n        ]);\n        let out = args.run().unwrap();\n        assert_eq!(out.address, address!(\"0x00614b3D65ac4a09A376a264fE1aE5E5E12A6C43\"));\n        assert_eq!(\n            out.salt,\n            b256!(\"0x322113f523203e2c0eb00bbc8e69208b0eb0c8dad0eaac7b01d64ff016edb40d\"),\n        );\n    }\n\n    #[test]\n    fn deterministic_output() {\n        let args = Create2Args::parse_from([\n            \"foundry-cli\",\n            \"--starts-with=0x00\",\n            \"--init-code-hash=0x479d7e8f31234e208d704ba1a123c76385cea8a6981fd675b784fbd9cffb918d\",\n            \"--no-random\",\n            \"-j1\",\n        ]);\n        let out = args.run().unwrap();\n        assert_eq!(out.address, address!(\"0x00bF495b8b42fdFeb91c8bCEB42CA4eE7186AEd2\"));\n        assert_eq!(\n            out.salt,\n            b256!(\"0x000000000000000000000000000000000000000000000000df00000000000000\"),\n        );\n    }\n\n    #[test]\n    fn j0() {\n        let args = Create2Args::try_parse_from([\n            \"foundry-cli\",\n            \"--starts-with=00\",\n            \"--init-code-hash\",\n            &B256::ZERO.to_string(),\n            \"-j0\",\n        ])\n        .unwrap();\n        assert_eq!(args.threads, Some(0));\n    }\n}\n"
  },
  {
    "path": "crates/cast/src/cmd/creation_code.rs",
    "content": "use super::interface::load_abi_from_file;\nuse crate::SimpleCast;\nuse alloy_consensus::Transaction;\nuse alloy_network::AnyNetwork;\nuse alloy_primitives::{Address, Bytes};\nuse alloy_provider::{Provider, RootProvider, ext::TraceApi};\nuse alloy_rpc_types::trace::parity::{Action, CreateAction, CreateOutput, TraceOutput};\nuse clap::Parser;\nuse eyre::{OptionExt, Result, eyre};\nuse foundry_block_explorers::Client;\nuse foundry_cli::{\n    opts::{EtherscanOpts, RpcOpts},\n    utils::{self, LoadConfig, fetch_abi_from_etherscan},\n};\nuse foundry_config::Config;\n\nfoundry_config::impl_figment_convert!(CreationCodeArgs, etherscan, rpc);\n\n/// CLI arguments for `cast creation-code`.\n#[derive(Parser)]\npub struct CreationCodeArgs {\n    /// An Ethereum address, for which the bytecode will be fetched.\n    contract: Address,\n\n    /// Path to file containing the contract's JSON ABI. It's necessary if the target contract is\n    /// not verified on Etherscan.\n    #[arg(long)]\n    abi_path: Option<String>,\n\n    /// Disassemble bytecodes into individual opcodes.\n    #[arg(long)]\n    disassemble: bool,\n\n    /// Return creation bytecode without constructor arguments appended.\n    #[arg(long, conflicts_with = \"only_args\")]\n    without_args: bool,\n\n    /// Return only constructor arguments.\n    #[arg(long)]\n    only_args: bool,\n\n    #[command(flatten)]\n    etherscan: EtherscanOpts,\n\n    #[command(flatten)]\n    rpc: RpcOpts,\n}\n\nimpl CreationCodeArgs {\n    pub async fn run(self) -> Result<()> {\n        let mut config = self.load_config()?;\n\n        let Self { contract, disassemble, without_args, only_args, abi_path, etherscan: _, rpc: _ } =\n            self;\n\n        let provider = utils::get_provider(&config)?;\n        let chain = provider.get_chain_id().await?;\n        config.chain = Some(chain.into());\n\n        let bytecode = fetch_creation_code_from_etherscan(contract, &config, provider).await?;\n\n        let bytecode = parse_code_output(\n            bytecode,\n            contract,\n            &config,\n            abi_path.as_deref(),\n            without_args,\n            only_args,\n        )\n        .await?;\n\n        if disassemble {\n            let _ = sh_println!(\"{}\", SimpleCast::disassemble(&bytecode)?);\n        } else {\n            let _ = sh_println!(\"{bytecode}\");\n        }\n\n        Ok(())\n    }\n}\n\n/// Parses the creation bytecode and returns one of the following:\n/// - The complete bytecode\n/// - The bytecode without constructor arguments\n/// - Only the constructor arguments\npub async fn parse_code_output(\n    bytecode: Bytes,\n    contract: Address,\n    config: &Config,\n    abi_path: Option<&str>,\n    without_args: bool,\n    only_args: bool,\n) -> Result<Bytes> {\n    if !without_args && !only_args {\n        return Ok(bytecode);\n    }\n\n    let abi = if let Some(abi_path) = abi_path {\n        load_abi_from_file(abi_path, None)?\n    } else {\n        fetch_abi_from_etherscan(contract, config).await?\n    };\n\n    let abi = abi.into_iter().next().ok_or_eyre(\"No ABI found.\")?;\n    let (abi, _) = abi;\n\n    if abi.constructor.is_none() {\n        if only_args {\n            return Err(eyre!(\"No constructor found.\"));\n        }\n        return Ok(bytecode);\n    }\n\n    let constructor = abi.constructor.unwrap();\n    if constructor.inputs.is_empty() {\n        if only_args {\n            return Err(eyre!(\"No constructor arguments found.\"));\n        }\n        return Ok(bytecode);\n    }\n\n    let args_size = constructor.inputs.len() * 32;\n\n    let bytecode = if without_args {\n        Bytes::from(bytecode[..bytecode.len() - args_size].to_vec())\n    } else if only_args {\n        Bytes::from(bytecode[bytecode.len() - args_size..].to_vec())\n    } else {\n        unreachable!();\n    };\n\n    Ok(bytecode)\n}\n\n/// Fetches the creation code of a contract from Etherscan and RPC.\npub async fn fetch_creation_code_from_etherscan(\n    contract: Address,\n    config: &Config,\n    provider: RootProvider<AnyNetwork>,\n) -> Result<Bytes> {\n    let chain = config.chain.unwrap_or_default();\n    let api_key = config.get_etherscan_api_key(Some(chain)).unwrap_or_default();\n    let client = Client::new(chain, api_key)?;\n    let creation_data = client.contract_creation_data(contract).await?;\n    let creation_tx_hash = creation_data.transaction_hash;\n    let tx_data = provider.get_transaction_by_hash(creation_tx_hash).await?;\n    let tx_data = tx_data.ok_or_eyre(\"Could not find creation tx data.\")?;\n\n    let bytecode = if tx_data.to().is_none() {\n        // Contract was created using a standard transaction\n        tx_data.input().clone()\n    } else {\n        // Contract was created using a factory pattern or create2\n        // Extract creation code from tx traces\n        let mut creation_bytecode = None;\n\n        let traces = provider.trace_transaction(creation_tx_hash).await.map_err(|e| {\n            eyre!(\"Could not fetch traces for transaction {}: {}\", creation_tx_hash, e)\n        })?;\n\n        for trace in traces {\n            if let Some(TraceOutput::Create(CreateOutput { address, .. })) = trace.trace.result\n                && address == contract\n            {\n                creation_bytecode = match trace.trace.action {\n                    Action::Create(CreateAction { init, .. }) => Some(init),\n                    _ => None,\n                };\n            }\n        }\n\n        creation_bytecode.ok_or_else(|| eyre!(\"Could not find contract creation trace.\"))?\n    };\n\n    Ok(bytecode)\n}\n"
  },
  {
    "path": "crates/cast/src/cmd/da_estimate.rs",
    "content": "//! Estimates the data availability size of a block for opstack.\n\nuse alloy_consensus::BlockHeader;\nuse alloy_network::eip2718::Encodable2718;\nuse alloy_provider::Provider;\nuse alloy_rpc_types::BlockId;\nuse clap::Parser;\nuse foundry_cli::{\n    opts::RpcOpts,\n    utils::{self, LoadConfig},\n};\nuse foundry_primitives::FoundryTxEnvelope;\n\n/// CLI arguments for `cast da-estimate`.\n#[derive(Debug, Parser)]\npub struct DAEstimateArgs {\n    /// The block to estimate the data availability size for.\n    pub block: BlockId,\n    #[command(flatten)]\n    pub rpc: RpcOpts,\n}\n\nimpl DAEstimateArgs {\n    /// Load the RPC URL from the config file.\n    pub async fn run(self) -> eyre::Result<()> {\n        let Self { block, rpc } = self;\n        let config = rpc.load_config()?;\n        let provider = utils::get_provider(&config)?;\n        let block = provider\n            .get_block(block)\n            .full()\n            .await?\n            .ok_or_else(|| eyre::eyre!(\"Block not found\"))?;\n\n        let block_number = block.header.number();\n        let tx_count = block.transactions.len();\n        let mut da_estimate = 0;\n        for tx in block.into_transactions_iter() {\n            // convert into FoundryTxEnvelope to support all foundry tx types\n            let tx = FoundryTxEnvelope::try_from(tx)?;\n            da_estimate += op_alloy_flz::tx_estimated_size_fjord(&tx.encoded_2718());\n        }\n\n        sh_println!(\n            \"Estimated data availability size for block {block_number} with {tx_count} transactions: {da_estimate}\"\n        )?;\n\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "crates/cast/src/cmd/erc20.rs",
    "content": "use std::{str::FromStr, time::Duration};\n\nuse crate::{cmd::send::cast_send, format_uint_exp, tx::SendTxOpts};\nuse alloy_consensus::{SignableTransaction, Signed};\nuse alloy_eips::BlockId;\nuse alloy_ens::NameOrAddress;\nuse alloy_network::{AnyNetwork, EthereumWallet, Network, TransactionBuilder};\nuse alloy_primitives::{U64, U256};\nuse alloy_provider::{Provider, fillers::RecommendedFillers};\nuse alloy_signer::Signature;\nuse alloy_sol_types::sol;\nuse clap::{Args, Parser};\nuse foundry_cli::{\n    opts::{RpcOpts, TempoOpts},\n    utils::{LoadConfig, get_chain, get_provider},\n};\nuse foundry_common::{\n    fmt::{UIfmt, UIfmtReceiptExt},\n    provider::{ProviderBuilder, RetryProviderWithSigner},\n    shell,\n};\n#[doc(hidden)]\npub use foundry_config::{Chain, utils::*};\nuse foundry_primitives::FoundryTransactionBuilder;\nuse tempo_alloy::TempoNetwork;\n\nsol! {\n    #[sol(rpc)]\n    interface IERC20 {\n        #[derive(Debug)]\n        function name() external view returns (string);\n        function symbol() external view returns (string);\n        function decimals() external view returns (uint8);\n        function totalSupply() external view returns (uint256);\n        function balanceOf(address owner) external view returns (uint256);\n        function transfer(address to, uint256 amount) external returns (bool);\n        function approve(address spender, uint256 amount) external returns (bool);\n        function allowance(address owner, address spender) external view returns (uint256);\n        function mint(address to, uint256 amount) external;\n        function burn(uint256 amount) external;\n    }\n}\n\n/// Transaction options for ERC20 operations.\n///\n/// This struct contains only the transaction options relevant to ERC20 token interactions\n#[derive(Debug, Clone, Args)]\npub struct Erc20TxOpts {\n    /// Gas limit for the transaction.\n    #[arg(long, env = \"ETH_GAS_LIMIT\")]\n    pub gas_limit: Option<U256>,\n\n    /// Gas price for legacy transactions, or max fee per gas for EIP1559 transactions.\n    #[arg(long, env = \"ETH_GAS_PRICE\")]\n    pub gas_price: Option<U256>,\n\n    /// Max priority fee per gas for EIP1559 transactions.\n    #[arg(long, env = \"ETH_PRIORITY_GAS_PRICE\")]\n    pub priority_gas_price: Option<U256>,\n\n    /// Nonce for the transaction.\n    #[arg(long)]\n    pub nonce: Option<U64>,\n\n    #[command(flatten)]\n    pub tempo: TempoOpts,\n}\n\n/// Creates a provider with wallet for signing transactions locally.\npub(crate) async fn get_provider_with_wallet<N: Network + RecommendedFillers>(\n    tx_opts: &SendTxOpts,\n) -> eyre::Result<RetryProviderWithSigner<N>>\nwhere\n    N::TxEnvelope: From<Signed<N::UnsignedTx>>,\n    N::UnsignedTx: SignableTransaction<Signature>,\n{\n    let config = tx_opts.eth.load_config()?;\n    let signer = tx_opts.eth.wallet.signer().await?;\n    let wallet = EthereumWallet::from(signer);\n    let provider = ProviderBuilder::<N>::from_config(&config)?.build_with_wallet(wallet)?;\n    if let Some(interval) = tx_opts.poll_interval {\n        provider.client().set_poll_interval(Duration::from_secs(interval))\n    }\n    Ok(provider)\n}\n\nimpl Erc20TxOpts {\n    /// Applies gas, fee, nonce, and Tempo options to a transaction request.\n    fn apply<N: Network>(&self, tx: &mut N::TransactionRequest, legacy: bool)\n    where\n        N::TransactionRequest: FoundryTransactionBuilder<N>,\n    {\n        if let Some(gas_limit) = self.gas_limit {\n            tx.set_gas_limit(gas_limit.to());\n        }\n\n        if let Some(gas_price) = self.gas_price {\n            if legacy {\n                tx.set_gas_price(gas_price.to());\n            } else {\n                tx.set_max_fee_per_gas(gas_price.to());\n            }\n        }\n\n        if !legacy && let Some(priority_fee) = self.priority_gas_price {\n            tx.set_max_priority_fee_per_gas(priority_fee.to());\n        }\n\n        self.tempo.apply::<N>(tx, self.nonce.map(|n| n.to()));\n    }\n}\n\n/// Interact with ERC20 tokens.\n#[derive(Debug, Parser, Clone)]\npub enum Erc20Subcommand {\n    /// Query ERC20 token balance.\n    #[command(visible_alias = \"b\")]\n    Balance {\n        /// The ERC20 token contract address.\n        #[arg(value_parser = NameOrAddress::from_str)]\n        token: NameOrAddress,\n\n        /// The owner to query balance for.\n        #[arg(value_parser = NameOrAddress::from_str)]\n        owner: NameOrAddress,\n\n        /// The block height to query at.\n        #[arg(long, short = 'B')]\n        block: Option<BlockId>,\n\n        #[command(flatten)]\n        rpc: RpcOpts,\n    },\n\n    /// Transfer ERC20 tokens.\n    #[command(visible_aliases = [\"t\", \"send\"])]\n    Transfer {\n        /// The ERC20 token contract address.\n        #[arg(value_parser = NameOrAddress::from_str)]\n        token: NameOrAddress,\n\n        /// The recipient address.\n        #[arg(value_parser = NameOrAddress::from_str)]\n        to: NameOrAddress,\n\n        /// The amount to transfer.\n        amount: String,\n\n        #[command(flatten)]\n        send_tx: SendTxOpts,\n\n        #[command(flatten)]\n        tx: Erc20TxOpts,\n    },\n\n    /// Approve ERC20 token spending.\n    #[command(visible_alias = \"a\")]\n    Approve {\n        /// The ERC20 token contract address.\n        #[arg(value_parser = NameOrAddress::from_str)]\n        token: NameOrAddress,\n\n        /// The spender address.\n        #[arg(value_parser = NameOrAddress::from_str)]\n        spender: NameOrAddress,\n\n        /// The amount to approve.\n        amount: String,\n\n        #[command(flatten)]\n        send_tx: SendTxOpts,\n\n        #[command(flatten)]\n        tx: Erc20TxOpts,\n    },\n\n    /// Query ERC20 token allowance.\n    #[command(visible_alias = \"al\")]\n    Allowance {\n        /// The ERC20 token contract address.\n        #[arg(value_parser = NameOrAddress::from_str)]\n        token: NameOrAddress,\n\n        /// The owner address.\n        #[arg(value_parser = NameOrAddress::from_str)]\n        owner: NameOrAddress,\n\n        /// The spender address.\n        #[arg(value_parser = NameOrAddress::from_str)]\n        spender: NameOrAddress,\n\n        /// The block height to query at.\n        #[arg(long, short = 'B')]\n        block: Option<BlockId>,\n\n        #[command(flatten)]\n        rpc: RpcOpts,\n    },\n\n    /// Query ERC20 token name.\n    #[command(visible_alias = \"n\")]\n    Name {\n        /// The ERC20 token contract address.\n        #[arg(value_parser = NameOrAddress::from_str)]\n        token: NameOrAddress,\n\n        /// The block height to query at.\n        #[arg(long, short = 'B')]\n        block: Option<BlockId>,\n\n        #[command(flatten)]\n        rpc: RpcOpts,\n    },\n\n    /// Query ERC20 token symbol.\n    #[command(visible_alias = \"s\")]\n    Symbol {\n        /// The ERC20 token contract address.\n        #[arg(value_parser = NameOrAddress::from_str)]\n        token: NameOrAddress,\n\n        /// The block height to query at.\n        #[arg(long, short = 'B')]\n        block: Option<BlockId>,\n\n        #[command(flatten)]\n        rpc: RpcOpts,\n    },\n\n    /// Query ERC20 token decimals.\n    #[command(visible_alias = \"d\")]\n    Decimals {\n        /// The ERC20 token contract address.\n        #[arg(value_parser = NameOrAddress::from_str)]\n        token: NameOrAddress,\n\n        /// The block height to query at.\n        #[arg(long, short = 'B')]\n        block: Option<BlockId>,\n\n        #[command(flatten)]\n        rpc: RpcOpts,\n    },\n\n    /// Query ERC20 token total supply.\n    #[command(visible_alias = \"ts\")]\n    TotalSupply {\n        /// The ERC20 token contract address.\n        #[arg(value_parser = NameOrAddress::from_str)]\n        token: NameOrAddress,\n\n        /// The block height to query at.\n        #[arg(long, short = 'B')]\n        block: Option<BlockId>,\n\n        #[command(flatten)]\n        rpc: RpcOpts,\n    },\n\n    /// Mint ERC20 tokens (if the token supports minting).\n    #[command(visible_alias = \"m\")]\n    Mint {\n        /// The ERC20 token contract address.\n        #[arg(value_parser = NameOrAddress::from_str)]\n        token: NameOrAddress,\n\n        /// The recipient address.\n        #[arg(value_parser = NameOrAddress::from_str)]\n        to: NameOrAddress,\n\n        /// The amount to mint.\n        amount: String,\n\n        #[command(flatten)]\n        send_tx: SendTxOpts,\n\n        #[command(flatten)]\n        tx: Erc20TxOpts,\n    },\n\n    /// Burn ERC20 tokens.\n    #[command(visible_alias = \"bu\")]\n    Burn {\n        /// The ERC20 token contract address.\n        #[arg(value_parser = NameOrAddress::from_str)]\n        token: NameOrAddress,\n\n        /// The amount to burn.\n        amount: String,\n\n        #[command(flatten)]\n        send_tx: SendTxOpts,\n\n        #[command(flatten)]\n        tx: Erc20TxOpts,\n    },\n}\n\nimpl Erc20Subcommand {\n    fn rpc_opts(&self) -> &RpcOpts {\n        match self {\n            Self::Allowance { rpc, .. } => rpc,\n            Self::Approve { send_tx, .. } => &send_tx.eth.rpc,\n            Self::Balance { rpc, .. } => rpc,\n            Self::Transfer { send_tx, .. } => &send_tx.eth.rpc,\n            Self::Name { rpc, .. } => rpc,\n            Self::Symbol { rpc, .. } => rpc,\n            Self::Decimals { rpc, .. } => rpc,\n            Self::TotalSupply { rpc, .. } => rpc,\n            Self::Mint { send_tx, .. } => &send_tx.eth.rpc,\n            Self::Burn { send_tx, .. } => &send_tx.eth.rpc,\n        }\n    }\n\n    fn erc20_opts(&self) -> Option<&Erc20TxOpts> {\n        match self {\n            Self::Approve { tx, .. }\n            | Self::Transfer { tx, .. }\n            | Self::Mint { tx, .. }\n            | Self::Burn { tx, .. } => Some(tx),\n            Self::Allowance { .. }\n            | Self::Balance { .. }\n            | Self::Name { .. }\n            | Self::Symbol { .. }\n            | Self::Decimals { .. }\n            | Self::TotalSupply { .. } => None,\n        }\n    }\n\n    pub async fn run(self) -> eyre::Result<()> {\n        if let Some(erc20) = self.erc20_opts()\n            && erc20.tempo.is_tempo()\n        {\n            self.run_generic::<TempoNetwork>().await\n        } else {\n            self.run_generic::<AnyNetwork>().await\n        }\n    }\n\n    pub async fn run_generic<N: Network + RecommendedFillers>(self) -> eyre::Result<()>\n    where\n        N::TxEnvelope: From<Signed<N::UnsignedTx>>,\n        N::UnsignedTx: SignableTransaction<Signature>,\n        N::TransactionRequest: FoundryTransactionBuilder<N>,\n        N::ReceiptResponse: UIfmt + UIfmtReceiptExt,\n    {\n        let config = self.rpc_opts().load_config()?;\n\n        match self {\n            // Read-only\n            Self::Allowance { token, owner, spender, block, .. } => {\n                let provider = get_provider(&config)?;\n                let token = token.resolve(&provider).await?;\n                let owner = owner.resolve(&provider).await?;\n                let spender = spender.resolve(&provider).await?;\n\n                let allowance = IERC20::new(token, &provider)\n                    .allowance(owner, spender)\n                    .block(block.unwrap_or_default())\n                    .call()\n                    .await?;\n\n                if shell::is_json() {\n                    sh_println!(\"{}\", serde_json::to_string(&allowance.to_string())?)?\n                } else {\n                    sh_println!(\"{}\", format_uint_exp(allowance))?\n                }\n            }\n            Self::Balance { token, owner, block, .. } => {\n                let provider = get_provider(&config)?;\n                let token = token.resolve(&provider).await?;\n                let owner = owner.resolve(&provider).await?;\n\n                let balance = IERC20::new(token, &provider)\n                    .balanceOf(owner)\n                    .block(block.unwrap_or_default())\n                    .call()\n                    .await?;\n\n                if shell::is_json() {\n                    sh_println!(\"{}\", serde_json::to_string(&balance.to_string())?)?\n                } else {\n                    sh_println!(\"{}\", format_uint_exp(balance))?\n                }\n            }\n            Self::Name { token, block, .. } => {\n                let provider = get_provider(&config)?;\n                let token = token.resolve(&provider).await?;\n\n                let name = IERC20::new(token, &provider)\n                    .name()\n                    .block(block.unwrap_or_default())\n                    .call()\n                    .await?;\n\n                if shell::is_json() {\n                    sh_println!(\"{}\", serde_json::to_string(&name)?)?\n                } else {\n                    sh_println!(\"{}\", name)?\n                }\n            }\n            Self::Symbol { token, block, .. } => {\n                let provider = get_provider(&config)?;\n                let token = token.resolve(&provider).await?;\n\n                let symbol = IERC20::new(token, &provider)\n                    .symbol()\n                    .block(block.unwrap_or_default())\n                    .call()\n                    .await?;\n\n                if shell::is_json() {\n                    sh_println!(\"{}\", serde_json::to_string(&symbol)?)?\n                } else {\n                    sh_println!(\"{}\", symbol)?\n                }\n            }\n            Self::Decimals { token, block, .. } => {\n                let provider = get_provider(&config)?;\n                let token = token.resolve(&provider).await?;\n\n                let decimals = IERC20::new(token, &provider)\n                    .decimals()\n                    .block(block.unwrap_or_default())\n                    .call()\n                    .await?;\n                if shell::is_json() {\n                    sh_println!(\"{}\", serde_json::to_string(&decimals)?)?\n                } else {\n                    sh_println!(\"{}\", decimals)?\n                }\n            }\n            Self::TotalSupply { token, block, .. } => {\n                let provider = get_provider(&config)?;\n                let token = token.resolve(&provider).await?;\n\n                let total_supply = IERC20::new(token, &provider)\n                    .totalSupply()\n                    .block(block.unwrap_or_default())\n                    .call()\n                    .await?;\n\n                if shell::is_json() {\n                    sh_println!(\"{}\", serde_json::to_string(&total_supply.to_string())?)?\n                } else {\n                    sh_println!(\"{}\", format_uint_exp(total_supply))?\n                }\n            }\n            // State-changing\n            Self::Transfer { token, to, amount, send_tx, tx: tx_opts, .. } => {\n                let provider = get_provider_with_wallet::<N>(&send_tx).await?;\n                let mut tx = IERC20::new(token.resolve(&provider).await?, &provider)\n                    .transfer(to.resolve(&provider).await?, U256::from_str(&amount)?)\n                    .into_transaction_request();\n\n                tx_opts.apply::<N>(&mut tx, get_chain(config.chain, &provider).await?.is_legacy());\n\n                cast_send(\n                    provider,\n                    tx,\n                    send_tx.cast_async,\n                    send_tx.sync,\n                    send_tx.confirmations,\n                    send_tx.timeout.unwrap_or(config.transaction_timeout),\n                )\n                .await?\n            }\n            Self::Approve { token, spender, amount, send_tx, tx: tx_opts, .. } => {\n                let provider = get_provider_with_wallet::<N>(&send_tx).await?;\n                let mut tx = IERC20::new(token.resolve(&provider).await?, &provider)\n                    .approve(spender.resolve(&provider).await?, U256::from_str(&amount)?)\n                    .into_transaction_request();\n\n                tx_opts.apply::<N>(&mut tx, get_chain(config.chain, &provider).await?.is_legacy());\n\n                cast_send(\n                    provider,\n                    tx,\n                    send_tx.cast_async,\n                    send_tx.sync,\n                    send_tx.confirmations,\n                    send_tx.timeout.unwrap_or(config.transaction_timeout),\n                )\n                .await?\n            }\n            Self::Mint { token, to, amount, send_tx, tx: tx_opts, .. } => {\n                let provider = get_provider_with_wallet::<N>(&send_tx).await?;\n                let mut tx = IERC20::new(token.resolve(&provider).await?, &provider)\n                    .mint(to.resolve(&provider).await?, U256::from_str(&amount)?)\n                    .into_transaction_request();\n\n                tx_opts.apply::<N>(&mut tx, get_chain(config.chain, &provider).await?.is_legacy());\n\n                cast_send(\n                    provider,\n                    tx,\n                    send_tx.cast_async,\n                    send_tx.sync,\n                    send_tx.confirmations,\n                    send_tx.timeout.unwrap_or(config.transaction_timeout),\n                )\n                .await?\n            }\n            Self::Burn { token, amount, send_tx, tx: tx_opts, .. } => {\n                let provider = get_provider_with_wallet::<N>(&send_tx).await?;\n                let mut tx = IERC20::new(token.resolve(&provider).await?, &provider)\n                    .burn(U256::from_str(&amount)?)\n                    .into_transaction_request();\n\n                tx_opts.apply::<N>(&mut tx, get_chain(config.chain, &provider).await?.is_legacy());\n\n                cast_send(\n                    provider,\n                    tx,\n                    send_tx.cast_async,\n                    send_tx.sync,\n                    send_tx.confirmations,\n                    send_tx.timeout.unwrap_or(config.transaction_timeout),\n                )\n                .await?\n            }\n        };\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "crates/cast/src/cmd/estimate.rs",
    "content": "use crate::tx::{CastTxBuilder, SenderKind};\nuse alloy_ens::NameOrAddress;\nuse alloy_network::{AnyNetwork, Network};\nuse alloy_primitives::U256;\nuse alloy_provider::Provider;\nuse alloy_rpc_types::BlockId;\nuse clap::Parser;\nuse eyre::Result;\nuse foundry_cli::{\n    opts::{RpcOpts, TransactionOpts},\n    utils::{LoadConfig, parse_ether_value},\n};\nuse foundry_common::provider::ProviderBuilder;\nuse foundry_primitives::FoundryTransactionBuilder;\nuse foundry_wallets::WalletOpts;\nuse std::str::FromStr;\nuse tempo_alloy::TempoNetwork;\n\n/// CLI arguments for `cast estimate`.\n#[derive(Debug, Parser)]\npub struct EstimateArgs {\n    /// The destination of the transaction.\n    #[arg(value_parser = NameOrAddress::from_str)]\n    to: Option<NameOrAddress>,\n\n    /// The signature of the function to call.\n    sig: Option<String>,\n\n    /// The arguments of the function to call.\n    #[arg(allow_negative_numbers = true)]\n    args: Vec<String>,\n\n    /// The block height to query at.\n    ///\n    /// Can also be the tags earliest, finalized, safe, latest, or pending.\n    #[arg(long, short = 'B')]\n    block: Option<BlockId>,\n\n    /// Calculate the cost of a transaction using the network gas price.\n    ///\n    /// If not specified the amount of gas will be estimated.\n    #[arg(long)]\n    cost: bool,\n\n    #[command(flatten)]\n    wallet: WalletOpts,\n\n    #[command(subcommand)]\n    command: Option<EstimateSubcommands>,\n\n    #[command(flatten)]\n    tx: TransactionOpts,\n\n    #[command(flatten)]\n    rpc: RpcOpts,\n}\n\n#[derive(Debug, Parser)]\npub enum EstimateSubcommands {\n    /// Estimate gas cost to deploy a smart contract\n    #[command(name = \"--create\")]\n    Create {\n        /// The bytecode of contract\n        code: String,\n\n        /// The signature of the constructor\n        sig: Option<String>,\n\n        /// Constructor arguments\n        #[arg(allow_negative_numbers = true)]\n        args: Vec<String>,\n\n        /// Ether to send in the transaction\n        ///\n        /// Either specified in wei, or as a string with a unit type:\n        ///\n        /// Examples: 1ether, 10gwei, 0.01ether\n        #[arg(long, value_parser = parse_ether_value)]\n        value: Option<U256>,\n    },\n}\n\nimpl EstimateArgs {\n    pub async fn run(self) -> Result<()> {\n        if self.tx.tempo.is_tempo() {\n            self.run_with_network::<TempoNetwork>().await\n        } else {\n            self.run_with_network::<AnyNetwork>().await\n        }\n    }\n\n    pub async fn run_with_network<N: Network>(self) -> Result<()>\n    where\n        N::TransactionRequest: FoundryTransactionBuilder<N>,\n    {\n        let Self { to, mut sig, mut args, mut tx, block, cost, wallet, rpc, command } = self;\n\n        let config = rpc.load_config()?;\n        let provider = ProviderBuilder::<N>::from_config(&config)?.build()?;\n        let sender = SenderKind::from_wallet_opts(wallet).await?;\n\n        let code = if let Some(EstimateSubcommands::Create {\n            code,\n            sig: create_sig,\n            args: create_args,\n            value,\n        }) = command\n        {\n            sig = create_sig;\n            args = create_args;\n            if let Some(value) = value {\n                tx.value = Some(value);\n            }\n            Some(code)\n        } else {\n            None\n        };\n\n        let (tx, _) = CastTxBuilder::new(&provider, tx, &config)\n            .await?\n            .with_to(to)\n            .await?\n            .with_code_sig_and_args(code, sig, args)\n            .await?\n            .raw()\n            .build(sender)\n            .await?;\n\n        let gas = provider.estimate_gas(tx).block(block.unwrap_or_default()).await?;\n        if cost {\n            let gas_price_wei = provider.get_gas_price().await?;\n            let cost = gas_price_wei * gas as u128;\n            let cost_eth = cost as f64 / 1e18;\n            sh_println!(\"{cost_eth}\")?;\n        } else {\n            sh_println!(\"{gas}\")?;\n        }\n        Ok(())\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn parse_estimate_value() {\n        let args: EstimateArgs = EstimateArgs::parse_from([\"foundry-cli\", \"--value\", \"100\"]);\n        assert!(args.tx.value.is_some());\n    }\n}\n"
  },
  {
    "path": "crates/cast/src/cmd/find_block.rs",
    "content": "use crate::Cast;\nuse alloy_provider::Provider;\nuse clap::Parser;\nuse eyre::Result;\nuse foundry_cli::{\n    opts::RpcOpts,\n    utils::{self, LoadConfig},\n};\nuse futures::join;\n\n/// CLI arguments for `cast find-block`.\n#[derive(Clone, Debug, Parser)]\npub struct FindBlockArgs {\n    /// The UNIX timestamp to search for, in seconds.\n    timestamp: u64,\n\n    #[command(flatten)]\n    rpc: RpcOpts,\n}\n\nimpl FindBlockArgs {\n    pub async fn run(self) -> Result<()> {\n        let Self { timestamp, rpc } = self;\n\n        let ts_target = timestamp;\n        let config = rpc.load_config()?;\n        let provider = utils::get_provider(&config)?;\n\n        let last_block_num = provider.get_block_number().await?;\n        let cast_provider = Cast::new(provider);\n\n        let res = join!(cast_provider.timestamp(last_block_num), cast_provider.timestamp(1));\n        let ts_block_latest: u64 = res.0?.to();\n        let ts_block_1: u64 = res.1?.to();\n\n        let block_num = if ts_block_latest < ts_target {\n            // If the most recent block's timestamp is below the target, return it\n            last_block_num\n        } else if ts_block_1 > ts_target {\n            // If the target timestamp is below block 1's timestamp, return that\n            1\n        } else {\n            // Otherwise, find the block that is closest to the timestamp\n            let mut low_block = 1_u64; // block 0 has a timestamp of 0: https://github.com/ethereum/go-ethereum/issues/17042#issuecomment-559414137\n            let mut high_block = last_block_num;\n            let mut matching_block = None;\n            while high_block > low_block && matching_block.is_none() {\n                // Get timestamp of middle block (this approach to avoids overflow)\n                let high_minus_low_over_2 = high_block\n                    .checked_sub(low_block)\n                    .ok_or_else(|| eyre::eyre!(\"unexpected underflow\"))\n                    .unwrap()\n                    .checked_div(2_u64)\n                    .unwrap();\n                let mid_block = high_block.checked_sub(high_minus_low_over_2).unwrap();\n                let ts_mid_block = cast_provider.timestamp(mid_block).await?.to::<u64>();\n\n                // Check if we've found a match or should keep searching\n                if ts_mid_block == ts_target {\n                    matching_block = Some(mid_block)\n                } else if high_block.checked_sub(low_block).unwrap() == 1_u64 {\n                    // The target timestamp is in between these blocks. This rounds to the\n                    // highest block if timestamp is equidistant between blocks\n                    let res = join!(\n                        cast_provider.timestamp(high_block),\n                        cast_provider.timestamp(low_block)\n                    );\n                    let ts_high: u64 = res.0.unwrap().to();\n                    let ts_low: u64 = res.1.unwrap().to();\n                    let high_diff = ts_high.checked_sub(ts_target).unwrap();\n                    let low_diff = ts_target.checked_sub(ts_low).unwrap();\n                    let is_low = low_diff < high_diff;\n                    matching_block = if is_low { Some(low_block) } else { Some(high_block) }\n                } else if ts_mid_block < ts_target {\n                    low_block = mid_block;\n                } else {\n                    high_block = mid_block;\n                }\n            }\n            matching_block.unwrap_or(low_block)\n        };\n        sh_println!(\"{block_num}\")?;\n\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "crates/cast/src/cmd/interface.rs",
    "content": "use alloy_json_abi::{ContractObject, JsonAbi, ToSolConfig};\nuse alloy_primitives::Address;\nuse clap::Parser;\nuse eyre::{Context, Result};\nuse forge_fmt::FormatterConfig;\nuse foundry_cli::{\n    opts::EtherscanOpts,\n    utils::{LoadConfig, fetch_abi_from_etherscan},\n};\nuse foundry_common::{\n    ContractsByArtifact,\n    compile::{PathOrContractInfo, ProjectCompiler},\n    find_target_path, fs, shell,\n};\nuse foundry_config::load_config;\nuse itertools::Itertools;\nuse serde_json::Value;\nuse std::{\n    path::{Path, PathBuf},\n    str::FromStr,\n};\n\n/// CLI arguments for `cast interface`.\n#[derive(Clone, Debug, Parser)]\npub struct InterfaceArgs {\n    /// The target contract, which can be one of:\n    /// - A file path to an ABI JSON file.\n    /// - A contract identifier in the form `<path>:<contractname>` or just `<contractname>`.\n    /// - An Ethereum address, for which the ABI will be fetched from Etherscan.\n    contract: String,\n\n    /// The name to use for the generated interface.\n    ///\n    /// Only relevant when retrieving the ABI from a file.\n    #[arg(long, short)]\n    name: Option<String>,\n\n    /// Solidity pragma version.\n    #[arg(long, short, default_value = \"^0.8.4\", value_name = \"VERSION\")]\n    pragma: String,\n\n    /// The path to the output file.\n    ///\n    /// If not specified, the interface will be output to stdout.\n    #[arg(\n        short,\n        long,\n        value_hint = clap::ValueHint::FilePath,\n        value_name = \"PATH\",\n    )]\n    output: Option<PathBuf>,\n\n    /// If set, generate all types in a single interface, inlining any inherited or library types.\n    ///\n    /// This can fail if there are structs with the same name in different interfaces.\n    #[arg(long)]\n    flatten: bool,\n\n    #[command(flatten)]\n    etherscan: EtherscanOpts,\n}\n\nimpl InterfaceArgs {\n    pub async fn run(self) -> Result<()> {\n        let Self { contract, name, pragma, output: output_location, flatten, etherscan } = self;\n\n        // Determine if the target contract is an ABI file, a local contract or an Ethereum address.\n        let abis = if Path::new(&contract).is_file()\n            && fs::read_to_string(&contract)\n                .ok()\n                .and_then(|content| serde_json::from_str::<Value>(&content).ok())\n                .is_some()\n        {\n            load_abi_from_file(&contract, name)?\n        } else {\n            match Address::from_str(&contract) {\n                Ok(address) => fetch_abi_from_etherscan(address, &etherscan.load_config()?).await?,\n                Err(_) => load_abi_from_artifact(&contract)?,\n            }\n        };\n\n        // Build config for to_sol conversion.\n        let config = if flatten { Some(ToSolConfig::new().one_contract(true)) } else { None };\n\n        // Retrieve interfaces from the array of ABIs.\n        let interfaces = get_interfaces(abis, config)?;\n\n        // Print result or write to file.\n        let res = if shell::is_json() {\n            // Format as JSON.\n            interfaces.iter().map(|iface| &iface.json_abi).format(\"\\n\").to_string()\n        } else {\n            // Format as Solidity.\n            format!(\n                \"// SPDX-License-Identifier: UNLICENSED\\n\\\n                 pragma solidity {pragma};\\n\\n\\\n                 {}\",\n                interfaces.iter().map(|iface| &iface.source).format(\"\\n\")\n            )\n        };\n\n        if let Some(loc) = output_location {\n            if let Some(parent) = loc.parent() {\n                fs::create_dir_all(parent)?;\n            }\n            fs::write(&loc, res)?;\n            sh_println!(\"Saved interface at {}\", loc.display())?;\n        } else {\n            sh_print!(\"{res}\")?;\n        }\n\n        Ok(())\n    }\n}\n\nstruct InterfaceSource {\n    json_abi: String,\n    source: String,\n}\n\n/// Load the ABI from a file.\npub fn load_abi_from_file(path: &str, name: Option<String>) -> Result<Vec<(JsonAbi, String)>> {\n    let file = std::fs::read_to_string(path).wrap_err(\"unable to read abi file\")?;\n    let obj: ContractObject = serde_json::from_str(&file)?;\n    let abi = obj.abi.ok_or_else(|| eyre::eyre!(\"could not find ABI in file {path}\"))?;\n    let name = name.unwrap_or_else(|| \"Interface\".to_owned());\n    Ok(vec![(abi, name)])\n}\n\n/// Load the ABI from the artifact of a locally compiled contract.\nfn load_abi_from_artifact(path_or_contract: &str) -> Result<Vec<(JsonAbi, String)>> {\n    let config = load_config()?;\n    let project = config.project()?;\n    let compiler = ProjectCompiler::new().quiet(true);\n\n    let contract = PathOrContractInfo::from_str(path_or_contract)?;\n\n    let target_path = find_target_path(&project, &contract)?;\n    let output = compiler.files([target_path.clone()]).compile(&project)?;\n\n    let contracts_by_artifact = ContractsByArtifact::from(output);\n\n    let maybe_abi = contracts_by_artifact\n        .find_abi_by_name_or_src_path(contract.name().unwrap_or(&target_path.to_string_lossy()));\n\n    let (abi, name) =\n        maybe_abi.as_ref().ok_or_else(|| eyre::eyre!(\"Failed to fetch lossless ABI\"))?;\n\n    Ok(vec![(abi.clone(), contract.name().unwrap_or(name).to_string())])\n}\n\n/// Converts a vector of tuples containing the ABI and contract name into a vector of\n/// `InterfaceSource` objects.\nfn get_interfaces(\n    abis: Vec<(JsonAbi, String)>,\n    config: Option<ToSolConfig>,\n) -> Result<Vec<InterfaceSource>> {\n    abis.into_iter()\n        .map(|(contract_abi, name)| {\n            let source = match forge_fmt::format(\n                &contract_abi.to_sol(&name, config.clone()),\n                FormatterConfig::default(),\n            )\n            .into_result()\n            {\n                Ok(generated_source) => generated_source,\n                Err(e) => {\n                    sh_warn!(\"Failed to format interface for {name}: {e}\")?;\n                    contract_abi.to_sol(&name, config.clone())\n                }\n            };\n\n            Ok(InterfaceSource { json_abi: serde_json::to_string_pretty(&contract_abi)?, source })\n        })\n        .collect()\n}\n"
  },
  {
    "path": "crates/cast/src/cmd/logs.rs",
    "content": "use crate::Cast;\nuse alloy_dyn_abi::{DynSolType, DynSolValue, Specifier};\nuse alloy_ens::NameOrAddress;\nuse alloy_json_abi::Event;\nuse alloy_network::AnyNetwork;\nuse alloy_primitives::{Address, B256, hex::FromHex};\nuse alloy_rpc_types::{BlockId, BlockNumberOrTag, Filter, FilterBlockOption, FilterSet, Topic};\nuse clap::Parser;\nuse eyre::Result;\nuse foundry_cli::{\n    opts::RpcOpts,\n    utils::{self, LoadConfig},\n};\nuse itertools::Itertools;\nuse std::{io, str::FromStr};\n\n/// CLI arguments for `cast logs`.\n#[derive(Debug, Parser)]\npub struct LogsArgs {\n    /// The block height to start query at.\n    ///\n    /// Can also be the tags earliest, finalized, safe, latest, or pending.\n    #[arg(long)]\n    from_block: Option<BlockId>,\n\n    /// The block height to stop query at.\n    ///\n    /// Can also be the tags earliest, finalized, safe, latest, or pending.\n    #[arg(long)]\n    to_block: Option<BlockId>,\n\n    /// The contract address to filter on.\n    #[arg(long, value_parser = NameOrAddress::from_str)]\n    address: Option<Vec<NameOrAddress>>,\n\n    /// The signature of the event to filter logs by which will be converted to the first topic or\n    /// a topic to filter on.\n    #[arg(value_name = \"SIG_OR_TOPIC\")]\n    sig_or_topic: Option<String>,\n\n    /// If used with a signature, the indexed fields of the event to filter by. Otherwise, the\n    /// remaining topics of the filter.\n    #[arg(value_name = \"TOPICS_OR_ARGS\")]\n    topics_or_args: Vec<String>,\n\n    /// If the RPC type and endpoints supports `eth_subscribe` stream logs instead of printing and\n    /// exiting. Will continue until interrupted or TO_BLOCK is reached.\n    #[arg(long)]\n    subscribe: bool,\n\n    /// Number of blocks to query in each chunk when the provider has range limits.\n    /// Defaults to 10000 blocks per chunk.\n    #[arg(long, default_value_t = 10000)]\n    query_size: u64,\n\n    #[command(flatten)]\n    rpc: RpcOpts,\n}\n\nimpl LogsArgs {\n    pub async fn run(self) -> Result<()> {\n        let Self {\n            from_block,\n            to_block,\n            address,\n            sig_or_topic,\n            topics_or_args,\n            subscribe,\n            query_size,\n            rpc,\n        } = self;\n\n        let config = rpc.load_config()?;\n        let provider = utils::get_provider(&config)?;\n\n        let cast = Cast::new(&provider);\n        let addresses = match address {\n            Some(addresses) => Some(\n                futures::future::try_join_all(addresses.into_iter().map(|address| {\n                    let provider = provider.clone();\n                    async move { address.resolve(&provider).await }\n                }))\n                .await?,\n            ),\n            None => None,\n        };\n\n        let from_block =\n            cast.convert_block_number(Some(from_block.unwrap_or_else(BlockId::earliest))).await?;\n        let to_block =\n            cast.convert_block_number(Some(to_block.unwrap_or_else(BlockId::latest))).await?;\n\n        let filter = build_filter(from_block, to_block, addresses, sig_or_topic, topics_or_args)?;\n\n        if !subscribe {\n            let logs = cast.filter_logs_chunked(filter, query_size).await?;\n            sh_println!(\"{logs}\")?;\n            return Ok(());\n        }\n\n        // FIXME: this is a hotfix for <https://github.com/foundry-rs/foundry/issues/7682>\n        //  currently the alloy `eth_subscribe` impl does not work with all transports, so we use\n        // the builtin transport here for now\n        let url = config.get_rpc_url_or_localhost_http()?;\n        let provider = alloy_provider::ProviderBuilder::<_, _, AnyNetwork>::default()\n            .connect(url.as_ref())\n            .await?;\n        let cast = Cast::new(&provider);\n        let mut stdout = io::stdout();\n        cast.subscribe(filter, &mut stdout).await?;\n\n        Ok(())\n    }\n}\n\n/// Builds a Filter by first trying to parse the `sig_or_topic` as an event signature. If\n/// successful, `topics_or_args` is parsed as indexed inputs and converted to topics. Otherwise,\n/// `sig_or_topic` is prepended to `topics_or_args` and used as raw topics.\nfn build_filter(\n    from_block: Option<BlockNumberOrTag>,\n    to_block: Option<BlockNumberOrTag>,\n    address: Option<Vec<Address>>,\n    sig_or_topic: Option<String>,\n    topics_or_args: Vec<String>,\n) -> Result<Filter, eyre::Error> {\n    let block_option = FilterBlockOption::Range { from_block, to_block };\n    let filter = match sig_or_topic {\n        // Try and parse the signature as an event signature\n        Some(sig_or_topic) => match foundry_common::abi::get_event(sig_or_topic.as_str()) {\n            Ok(event) => build_filter_event_sig(event, topics_or_args)?,\n            Err(_) => {\n                let topics = [vec![sig_or_topic], topics_or_args].concat();\n                build_filter_topics(topics)?\n            }\n        },\n        None => Filter::default(),\n    };\n\n    let mut filter = filter.select(block_option);\n\n    if let Some(address) = address {\n        filter = filter.address(address)\n    }\n\n    Ok(filter)\n}\n\n/// Creates a [Filter] from the given event signature and arguments.\nfn build_filter_event_sig(event: Event, args: Vec<String>) -> Result<Filter, eyre::Error> {\n    let args = args.iter().map(|arg| arg.as_str()).collect::<Vec<_>>();\n\n    // Match the args to indexed inputs. Enumerate so that the ordering can be restored\n    // when merging the inputs with arguments and without arguments\n    let (with_args, without_args): (Vec<_>, Vec<_>) = event\n        .inputs\n        .iter()\n        .zip(args)\n        .filter(|(input, _)| input.indexed)\n        .map(|(input, arg)| {\n            let kind = input.resolve()?;\n            Ok((kind, arg))\n        })\n        .collect::<Result<Vec<(DynSolType, &str)>>>()?\n        .into_iter()\n        .enumerate()\n        .partition(|(_, (_, arg))| !arg.is_empty());\n\n    // Only parse the inputs with arguments\n    let indexed_tokens = with_args\n        .iter()\n        .map(|(_, (kind, arg))| kind.coerce_str(arg))\n        .collect::<Result<Vec<DynSolValue>, _>>()?;\n\n    // Merge the inputs restoring the original ordering\n    let mut topics = with_args\n        .into_iter()\n        .zip(indexed_tokens)\n        .map(|((i, _), t)| (i, Some(t)))\n        .chain(without_args.into_iter().map(|(i, _)| (i, None)))\n        .sorted_by(|(i1, _), (i2, _)| i1.cmp(i2))\n        .map(|(_, token)| {\n            token\n                .map(|token| Topic::from(B256::from_slice(token.abi_encode().as_slice())))\n                .unwrap_or(Topic::default())\n        })\n        .collect::<Vec<Topic>>();\n\n    topics.resize(3, Topic::default());\n\n    let filter = Filter::new()\n        .event_signature(event.selector())\n        .topic1(topics[0].clone())\n        .topic2(topics[1].clone())\n        .topic3(topics[2].clone());\n\n    Ok(filter)\n}\n\n/// Creates a [Filter] from raw topic hashes.\nfn build_filter_topics(topics: Vec<String>) -> Result<Filter, eyre::Error> {\n    let mut topics = topics\n        .into_iter()\n        .map(|topic| {\n            if topic.is_empty() {\n                Ok(Topic::default())\n            } else {\n                Ok(Topic::from(B256::from_hex(topic.as_str())?))\n            }\n        })\n        .collect::<Result<Vec<FilterSet<_>>>>()?;\n\n    topics.resize(4, Topic::default());\n\n    let filter = Filter::new()\n        .event_signature(topics[0].clone())\n        .topic1(topics[1].clone())\n        .topic2(topics[2].clone())\n        .topic3(topics[3].clone());\n\n    Ok(filter)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use alloy_primitives::{U160, U256};\n    use alloy_rpc_types::ValueOrArray;\n\n    const ADDRESS: &str = \"0x4D1A2e2bB4F88F0250f26Ffff098B0b30B26BF38\";\n    const TRANSFER_SIG: &str = \"Transfer(address indexed,address indexed,uint256)\";\n    const TRANSFER_TOPIC: &str =\n        \"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef\";\n\n    #[test]\n    fn test_build_filter_basic() {\n        let from_block = Some(BlockNumberOrTag::from(1337));\n        let to_block = Some(BlockNumberOrTag::Latest);\n        let address = Address::from_str(ADDRESS).ok();\n        let expected = Filter {\n            block_option: FilterBlockOption::Range { from_block, to_block },\n            address: ValueOrArray::Value(address.unwrap()).into(),\n            topics: [vec![].into(), vec![].into(), vec![].into(), vec![].into()],\n        };\n        let filter =\n            build_filter(from_block, to_block, address.map(|addr| vec![addr]), None, vec![])\n                .unwrap();\n        assert_eq!(filter, expected)\n    }\n\n    #[test]\n    fn test_build_filter_sig() {\n        let expected = Filter {\n            block_option: FilterBlockOption::Range { from_block: None, to_block: None },\n            address: vec![].into(),\n            topics: [\n                B256::from_str(TRANSFER_TOPIC).unwrap().into(),\n                vec![].into(),\n                vec![].into(),\n                vec![].into(),\n            ],\n        };\n        let filter =\n            build_filter(None, None, None, Some(TRANSFER_SIG.to_string()), vec![]).unwrap();\n        assert_eq!(filter, expected)\n    }\n\n    #[test]\n    fn test_build_filter_mismatch() {\n        let expected = Filter {\n            block_option: FilterBlockOption::Range { from_block: None, to_block: None },\n            address: vec![].into(),\n            topics: [\n                B256::from_str(TRANSFER_TOPIC).unwrap().into(),\n                vec![].into(),\n                vec![].into(),\n                vec![].into(),\n            ],\n        };\n        let filter = build_filter(\n            None,\n            None,\n            None,\n            Some(\"Swap(address indexed from, address indexed to, uint256 value)\".to_string()), // Change signature, should result in error\n            vec![],\n        )\n        .unwrap();\n        assert_ne!(filter, expected)\n    }\n\n    #[test]\n    fn test_build_filter_sig_with_arguments() {\n        let addr = Address::from_str(ADDRESS).unwrap();\n        let addr = U256::from(U160::from_be_bytes(addr.0.0));\n        let expected = Filter {\n            block_option: FilterBlockOption::Range { from_block: None, to_block: None },\n            address: vec![].into(),\n            topics: [\n                B256::from_str(TRANSFER_TOPIC).unwrap().into(),\n                addr.into(),\n                vec![].into(),\n                vec![].into(),\n            ],\n        };\n        let filter = build_filter(\n            None,\n            None,\n            None,\n            Some(TRANSFER_SIG.to_string()),\n            vec![ADDRESS.to_string()],\n        )\n        .unwrap();\n        assert_eq!(filter, expected)\n    }\n\n    #[test]\n    fn test_build_filter_sig_with_skipped_arguments() {\n        let addr = Address::from_str(ADDRESS).unwrap();\n        let addr = U256::from(U160::from_be_bytes(addr.0.0));\n        let expected = Filter {\n            block_option: FilterBlockOption::Range { from_block: None, to_block: None },\n            address: vec![].into(),\n            topics: [\n                vec![B256::from_str(TRANSFER_TOPIC).unwrap()].into(),\n                vec![].into(),\n                addr.into(),\n                vec![].into(),\n            ],\n        };\n        let filter = build_filter(\n            None,\n            None,\n            None,\n            Some(TRANSFER_SIG.to_string()),\n            vec![String::new(), ADDRESS.to_string()],\n        )\n        .unwrap();\n        assert_eq!(filter, expected)\n    }\n\n    #[test]\n    fn test_build_filter_with_topics() {\n        let expected = Filter {\n            block_option: FilterBlockOption::Range { from_block: None, to_block: None },\n            address: vec![].into(),\n            topics: [\n                vec![B256::from_str(TRANSFER_TOPIC).unwrap()].into(),\n                vec![B256::from_str(TRANSFER_TOPIC).unwrap()].into(),\n                vec![].into(),\n                vec![].into(),\n            ],\n        };\n        let filter = build_filter(\n            None,\n            None,\n            None,\n            Some(TRANSFER_TOPIC.to_string()),\n            vec![TRANSFER_TOPIC.to_string()],\n        )\n        .unwrap();\n\n        assert_eq!(filter, expected)\n    }\n\n    #[test]\n    fn test_build_filter_with_skipped_topic() {\n        let expected = Filter {\n            block_option: FilterBlockOption::Range { from_block: None, to_block: None },\n            address: vec![].into(),\n            topics: [\n                vec![B256::from_str(TRANSFER_TOPIC).unwrap()].into(),\n                vec![].into(),\n                vec![B256::from_str(TRANSFER_TOPIC).unwrap()].into(),\n                vec![].into(),\n            ],\n        };\n        let filter = build_filter(\n            None,\n            None,\n            None,\n            Some(TRANSFER_TOPIC.to_string()),\n            vec![String::new(), TRANSFER_TOPIC.to_string()],\n        )\n        .unwrap();\n\n        assert_eq!(filter, expected)\n    }\n\n    #[test]\n    fn test_build_filter_with_multiple_addresses() {\n        let expected = Filter {\n            block_option: FilterBlockOption::Range { from_block: None, to_block: None },\n            address: vec![Address::ZERO, ADDRESS.parse().unwrap()].into(),\n            topics: [\n                vec![TRANSFER_TOPIC.parse().unwrap()].into(),\n                vec![].into(),\n                vec![].into(),\n                vec![].into(),\n            ],\n        };\n        let filter = build_filter(\n            None,\n            None,\n            Some(vec![Address::ZERO, ADDRESS.parse().unwrap()]),\n            Some(TRANSFER_TOPIC.to_string()),\n            vec![],\n        )\n        .unwrap();\n        assert_eq!(filter, expected)\n    }\n\n    #[test]\n    fn test_build_filter_sig_with_mismatched_argument() {\n        let err = build_filter(\n            None,\n            None,\n            None,\n            Some(TRANSFER_SIG.to_string()),\n            vec![\"1234\".to_string()],\n        )\n        .err()\n        .unwrap()\n        .to_string()\n        .to_lowercase();\n\n        assert_eq!(err, \"parser error:\\n1234\\n^\\ninvalid string length\");\n    }\n\n    #[test]\n    fn test_build_filter_with_invalid_sig_or_topic() {\n        let err = build_filter(None, None, None, Some(\"asdasdasd\".to_string()), vec![])\n            .err()\n            .unwrap()\n            .to_string()\n            .to_lowercase();\n\n        assert_eq!(err, \"odd number of digits\");\n    }\n\n    #[test]\n    fn test_build_filter_with_invalid_sig_or_topic_hex() {\n        let err = build_filter(None, None, None, Some(ADDRESS.to_string()), vec![])\n            .err()\n            .unwrap()\n            .to_string()\n            .to_lowercase();\n\n        assert_eq!(err, \"invalid string length\");\n    }\n\n    #[test]\n    fn test_build_filter_with_invalid_topic() {\n        let err = build_filter(\n            None,\n            None,\n            None,\n            Some(TRANSFER_TOPIC.to_string()),\n            vec![\"1234\".to_string()],\n        )\n        .err()\n        .unwrap()\n        .to_string()\n        .to_lowercase();\n\n        assert_eq!(err, \"invalid string length\");\n    }\n}\n"
  },
  {
    "path": "crates/cast/src/cmd/mktx.rs",
    "content": "use crate::tx::{self, CastTxBuilder};\nuse alloy_consensus::{SignableTransaction, Signed};\nuse alloy_eips::Encodable2718;\nuse alloy_ens::NameOrAddress;\nuse alloy_network::{AnyNetwork, EthereumWallet, Network, TransactionBuilder};\nuse alloy_primitives::{Address, hex};\nuse alloy_provider::Provider;\nuse alloy_signer::{Signature, Signer};\nuse clap::Parser;\nuse eyre::Result;\nuse foundry_cli::{\n    opts::{EthereumOpts, TransactionOpts},\n    utils::LoadConfig,\n};\nuse foundry_common::provider::ProviderBuilder;\nuse foundry_primitives::FoundryTransactionBuilder;\nuse std::{path::PathBuf, str::FromStr};\nuse tempo_alloy::TempoNetwork;\n\n/// CLI arguments for `cast mktx`.\n#[derive(Debug, Parser)]\npub struct MakeTxArgs {\n    /// The destination of the transaction.\n    ///\n    /// If not provided, you must use `cast mktx --create`.\n    #[arg(value_parser = NameOrAddress::from_str)]\n    to: Option<NameOrAddress>,\n\n    /// The signature of the function to call.\n    sig: Option<String>,\n\n    /// The arguments of the function to call.\n    #[arg(allow_negative_numbers = true)]\n    args: Vec<String>,\n\n    #[command(subcommand)]\n    command: Option<MakeTxSubcommands>,\n\n    #[command(flatten)]\n    tx: TransactionOpts,\n\n    /// The path of blob data to be sent.\n    #[arg(\n        long,\n        value_name = \"BLOB_DATA_PATH\",\n        conflicts_with = \"legacy\",\n        requires = \"blob\",\n        help_heading = \"Transaction options\"\n    )]\n    path: Option<PathBuf>,\n\n    #[command(flatten)]\n    eth: EthereumOpts,\n\n    /// Generate a raw RLP-encoded unsigned transaction.\n    ///\n    /// Relaxes the wallet requirement.\n    #[arg(long)]\n    raw_unsigned: bool,\n\n    /// Call `eth_signTransaction` using the `--from` argument or $ETH_FROM as sender\n    #[arg(long, requires = \"from\", conflicts_with = \"raw_unsigned\")]\n    ethsign: bool,\n}\n\n#[derive(Debug, Parser)]\npub enum MakeTxSubcommands {\n    /// Use to deploy raw contract bytecode.\n    #[command(name = \"--create\")]\n    Create {\n        /// The initialization bytecode of the contract to deploy.\n        code: String,\n\n        /// The signature of the constructor.\n        sig: Option<String>,\n\n        /// The constructor arguments.\n        #[arg(allow_negative_numbers = true)]\n        args: Vec<String>,\n    },\n}\n\nimpl MakeTxArgs {\n    pub async fn run(self) -> Result<()> {\n        if self.tx.tempo.is_tempo() {\n            self.run_generic::<TempoNetwork>().await\n        } else {\n            self.run_generic::<AnyNetwork>().await\n        }\n    }\n\n    pub async fn run_generic<N: Network>(self) -> Result<()>\n    where\n        N::TxEnvelope: From<Signed<N::UnsignedTx>>,\n        N::UnsignedTx: SignableTransaction<Signature>,\n        N::TransactionRequest: FoundryTransactionBuilder<N>,\n    {\n        let Self { to, mut sig, mut args, command, tx, path, eth, raw_unsigned, ethsign } = self;\n\n        let print_sponsor_hash = tx.tempo.print_sponsor_hash;\n\n        let blob_data = if let Some(path) = path { Some(std::fs::read(path)?) } else { None };\n\n        let code = if let Some(MakeTxSubcommands::Create {\n            code,\n            sig: constructor_sig,\n            args: constructor_args,\n        }) = command\n        {\n            sig = constructor_sig;\n            args = constructor_args;\n            Some(code)\n        } else {\n            None\n        };\n\n        let config = eth.load_config()?;\n\n        let provider = ProviderBuilder::<N>::from_config(&config)?.build()?;\n\n        let tx_builder = CastTxBuilder::new(&provider, tx.clone(), &config)\n            .await?\n            .with_to(to)\n            .await?\n            .with_code_sig_and_args(code, sig, args)\n            .await?\n            .with_blob_data(blob_data)?;\n\n        // If --tempo.print-sponsor-hash was passed, build the tx, print the hash, and exit.\n        if print_sponsor_hash {\n            let from = eth.wallet.from.unwrap_or(Address::ZERO);\n            let (tx, _) = tx_builder.build(from).await?;\n            let hash = tx.compute_sponsor_hash(from).ok_or_else(|| {\n                eyre::eyre!(\"This network does not support sponsored transactions\")\n            })?;\n            sh_println!(\"{hash:?}\")?;\n            return Ok(());\n        }\n\n        if raw_unsigned {\n            // Build unsigned raw tx\n            // Check if nonce is provided when --from is not specified\n            // See: <https://github.com/foundry-rs/foundry/issues/11110>\n            if eth.wallet.from.is_none() && tx.nonce.is_none() {\n                eyre::bail!(\n                    \"Missing required parameters for raw unsigned transaction. When --from is not provided, you must specify: --nonce\"\n                );\n            }\n\n            // Use zero address as placeholder for unsigned transactions\n            let from = eth.wallet.from.unwrap_or(Address::ZERO);\n\n            let (tx, _) = tx_builder.build(from).await?;\n            let raw_tx = hex::encode_prefixed(tx.build_unsigned()?.encoded_for_signing());\n\n            sh_println!(\"{raw_tx}\")?;\n            return Ok(());\n        }\n\n        if ethsign {\n            // Use \"eth_signTransaction\" to sign the transaction only works if the node/RPC has\n            // unlocked accounts.\n            let (tx, _) = tx_builder.build(config.sender).await?;\n            let signed_tx = provider.sign_transaction(tx).await?;\n\n            sh_println!(\"{signed_tx}\")?;\n            return Ok(());\n        }\n\n        // Default to using the local signer.\n        // Get the signer from the wallet, and fail if it can't be constructed.\n        let signer = eth.wallet.signer().await?;\n        let from = signer.address();\n\n        tx::validate_from_address(eth.wallet.from, from)?;\n\n        let (tx, _) = tx_builder.build(&signer).await?;\n\n        let tx = tx.build(&EthereumWallet::new(signer)).await?;\n\n        let signed_tx = hex::encode(tx.encoded_2718());\n        sh_println!(\"0x{signed_tx}\")?;\n\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "crates/cast/src/cmd/mod.rs",
    "content": "//! `cast` subcommands.\n//!\n//! All subcommands should respect the `foundry_config::Config`.\n//! If a subcommand accepts values that are supported by the `Config`, then the subcommand should\n//! implement `figment::Provider` which allows the subcommand to override the config's defaults, see\n//! [`foundry_config::Config`].\n\npub mod access_list;\npub mod artifact;\npub mod b2e_payload;\npub mod bind;\npub mod call;\npub mod constructor_args;\npub mod create2;\npub mod creation_code;\npub mod da_estimate;\npub mod erc20;\npub mod estimate;\npub mod find_block;\npub mod interface;\npub mod logs;\npub mod mktx;\npub mod rpc;\npub mod run;\npub mod send;\npub mod storage;\npub mod trace;\npub mod txpool;\npub mod wallet;\n"
  },
  {
    "path": "crates/cast/src/cmd/rpc.rs",
    "content": "use crate::Cast;\nuse clap::Parser;\nuse eyre::Result;\nuse foundry_cli::{opts::RpcOpts, utils, utils::LoadConfig};\nuse foundry_common::shell;\nuse itertools::Itertools;\n\n/// CLI arguments for `cast rpc`.\n#[derive(Clone, Debug, Parser)]\npub struct RpcArgs {\n    /// RPC method name\n    method: String,\n\n    /// RPC parameters\n    ///\n    /// Interpreted as JSON:\n    ///\n    /// cast rpc eth_getBlockByNumber 0x123 false\n    /// => {\"method\": \"eth_getBlockByNumber\", \"params\": [\"0x123\", false] ... }\n    params: Vec<String>,\n\n    /// Send raw JSON parameters\n    ///\n    /// The first param will be interpreted as a raw JSON array of params.\n    /// If no params are given, stdin will be used. For example:\n    ///\n    /// cast rpc eth_getBlockByNumber '[\"0x123\", false]' --raw\n    ///     => {\"method\": \"eth_getBlockByNumber\", \"params\": [\"0x123\", false] ... }\n    #[arg(long, short = 'w')]\n    raw: bool,\n\n    #[command(flatten)]\n    rpc: RpcOpts,\n}\n\nimpl RpcArgs {\n    pub async fn run(self) -> Result<()> {\n        let Self { raw, method, params, rpc } = self;\n\n        let config = rpc.load_config()?;\n\n        let params = if raw {\n            if params.is_empty() {\n                serde_json::Deserializer::from_reader(std::io::stdin())\n                    .into_iter()\n                    .next()\n                    .transpose()?\n                    .ok_or_else(|| eyre::format_err!(\"Empty JSON parameters\"))?\n            } else {\n                value_or_string(params.into_iter().join(\" \"))\n            }\n        } else {\n            serde_json::Value::Array(params.into_iter().map(value_or_string).collect())\n        };\n\n        let provider = utils::get_provider(&config)?;\n        let result = Cast::new(provider).rpc(&method, params).await?;\n        if shell::is_json() {\n            let result: serde_json::Value = serde_json::from_str(&result)?;\n            sh_println!(\"{}\", serde_json::to_string_pretty(&result)?)?;\n        } else {\n            sh_println!(\"{}\", result)?;\n        }\n        Ok(())\n    }\n}\n\nfn value_or_string(value: String) -> serde_json::Value {\n    serde_json::from_str(&value).unwrap_or(serde_json::Value::String(value))\n}\n"
  },
  {
    "path": "crates/cast/src/cmd/run.rs",
    "content": "use crate::{\n    debug::handle_traces,\n    utils::{apply_chain_and_block_specific_env_changes, block_env_from_header},\n};\nuse alloy_consensus::{BlockHeader, Transaction};\nuse alloy_evm::FromRecoveredTx;\nuse alloy_network::{AnyNetwork, TransactionResponse};\nuse alloy_primitives::{\n    Address, Bytes, U256,\n    map::{AddressSet, HashMap},\n};\nuse alloy_provider::Provider;\nuse alloy_rpc_types::BlockTransactions;\nuse clap::Parser;\nuse eyre::{Result, WrapErr};\nuse foundry_cli::{\n    opts::{EtherscanOpts, RpcOpts},\n    utils::{TraceResult, init_progress},\n};\nuse foundry_common::{SYSTEM_TRANSACTION_TYPE, is_impersonated_tx, is_known_system_sender, shell};\nuse foundry_compilers::artifacts::EvmVersion;\nuse foundry_config::{\n    Config,\n    figment::{\n        self, Metadata, Profile,\n        value::{Dict, Map},\n    },\n};\nuse foundry_evm::{\n    executors::{EvmError, Executor, TracingExecutor},\n    opts::EvmOpts,\n    traces::{InternalTraceMode, TraceMode, Traces},\n};\nuse futures::TryFutureExt;\nuse revm::{DatabaseRef, context::TxEnv};\n\n/// CLI arguments for `cast run`.\n#[derive(Clone, Debug, Parser)]\npub struct RunArgs {\n    /// The transaction hash.\n    tx_hash: String,\n\n    /// Opens the transaction in the debugger.\n    #[arg(long, short)]\n    debug: bool,\n\n    /// Whether to identify internal functions in traces.\n    #[arg(long)]\n    decode_internal: bool,\n\n    /// Defines the depth of a trace\n    #[arg(long)]\n    trace_depth: Option<usize>,\n\n    /// Print out opcode traces.\n    #[arg(long, short)]\n    trace_printer: bool,\n\n    /// Executes the transaction only with the state from the previous block.\n    ///\n    /// May result in different results than the live execution!\n    #[arg(long)]\n    quick: bool,\n\n    /// Whether to replay system transactions.\n    #[arg(long, alias = \"sys\")]\n    replay_system_txes: bool,\n\n    /// Disables the labels in the traces.\n    #[arg(long, default_value_t = false)]\n    disable_labels: bool,\n\n    /// Label addresses in the trace.\n    ///\n    /// Example: 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045:vitalik.eth\n    #[arg(long, short)]\n    label: Vec<String>,\n\n    #[command(flatten)]\n    etherscan: EtherscanOpts,\n\n    #[command(flatten)]\n    rpc: RpcOpts,\n\n    /// The EVM version to use.\n    ///\n    /// Overrides the version specified in the config.\n    #[arg(long)]\n    evm_version: Option<EvmVersion>,\n\n    /// Sets the number of assumed available compute units per second for this provider\n    ///\n    /// default value: 330\n    ///\n    /// See also, <https://docs.alchemy.com/reference/compute-units#what-are-cups-compute-units-per-second>\n    #[arg(long, alias = \"cups\", value_name = \"CUPS\")]\n    pub compute_units_per_second: Option<u64>,\n\n    /// Disables rate limiting for this node's provider.\n    ///\n    /// default value: false\n    ///\n    /// See also, <https://docs.alchemy.com/reference/compute-units#what-are-cups-compute-units-per-second>\n    #[arg(long, value_name = \"NO_RATE_LIMITS\", visible_alias = \"no-rpc-rate-limit\")]\n    pub no_rate_limit: bool,\n\n    /// Use current project artifacts for trace decoding.\n    #[arg(long, visible_alias = \"la\")]\n    pub with_local_artifacts: bool,\n\n    /// Disable block gas limit check.\n    #[arg(long)]\n    pub disable_block_gas_limit: bool,\n\n    /// Enable the tx gas limit checks as imposed by Osaka (EIP-7825).\n    #[arg(long)]\n    pub enable_tx_gas_limit: bool,\n}\n\nimpl RunArgs {\n    /// Executes the transaction by replaying it\n    ///\n    /// This replays the entire block the transaction was mined in unless `quick` is set to true\n    ///\n    /// Note: This executes the transaction(s) as is: Cheatcodes are disabled\n    pub async fn run(self) -> Result<()> {\n        let figment = self.rpc.clone().into_figment(self.with_local_artifacts).merge(&self);\n        let evm_opts = figment.extract::<EvmOpts>()?;\n        let mut config = Config::from_provider(figment)?.sanitized();\n\n        let label = self.label;\n        let with_local_artifacts = self.with_local_artifacts;\n        let debug = self.debug;\n        let decode_internal = self.decode_internal;\n        let disable_labels = self.disable_labels;\n        let compute_units_per_second =\n            if self.no_rate_limit { Some(u64::MAX) } else { self.compute_units_per_second };\n\n        let provider = foundry_cli::utils::get_provider_builder(&config)?\n            .compute_units_per_second_opt(compute_units_per_second)\n            .build()?;\n\n        let tx_hash = self.tx_hash.parse().wrap_err(\"invalid tx hash\")?;\n        let tx = provider\n            .get_transaction_by_hash(tx_hash)\n            .await\n            .wrap_err_with(|| format!(\"tx not found: {tx_hash:?}\"))?\n            .ok_or_else(|| eyre::eyre!(\"tx not found: {:?}\", tx_hash))?;\n\n        // check if the tx is a system transaction\n        if !self.replay_system_txes\n            && (is_known_system_sender(tx.from())\n                || tx.transaction_type() == Some(SYSTEM_TRANSACTION_TYPE))\n        {\n            return Err(eyre::eyre!(\n                \"{:?} is a system transaction.\\nReplaying system transactions is currently not supported.\",\n                tx.tx_hash()\n            ));\n        }\n\n        let tx_block_number =\n            tx.block_number.ok_or_else(|| eyre::eyre!(\"tx may still be pending: {:?}\", tx_hash))?;\n\n        // we need to fork off the parent block\n        config.fork_block_number = Some(tx_block_number - 1);\n\n        let create2_deployer = evm_opts.create2_deployer;\n        let (block, (mut evm_env, tx_env, fork, chain, networks)) = tokio::try_join!(\n            // fetch the block the transaction was mined in\n            provider.get_block(tx_block_number.into()).full().into_future().map_err(Into::into),\n            TracingExecutor::get_fork_material(&mut config, evm_opts)\n        )?;\n\n        let mut evm_version = self.evm_version;\n\n        evm_env.cfg_env.disable_block_gas_limit = self.disable_block_gas_limit;\n\n        // By default do not enforce transaction gas limits imposed by Osaka (EIP-7825).\n        // Users can opt-in to enable these limits by setting `enable_tx_gas_limit` to true.\n        if !self.enable_tx_gas_limit {\n            evm_env.cfg_env.tx_gas_limit_cap = Some(u64::MAX);\n        }\n\n        evm_env.cfg_env.limit_contract_code_size = None;\n        evm_env.block_env.number = U256::from(tx_block_number);\n\n        if let Some(block) = &block {\n            evm_env.block_env = block_env_from_header(&block.header);\n\n            // TODO: we need a smarter way to map the block to the corresponding evm_version for\n            // commonly used chains\n            if evm_version.is_none() {\n                // if the block has the excess_blob_gas field, we assume it's a Cancun block\n                if block.header.excess_blob_gas().is_some() {\n                    evm_version = Some(EvmVersion::Prague);\n                }\n            }\n            apply_chain_and_block_specific_env_changes::<AnyNetwork>(\n                &mut evm_env,\n                block,\n                config.networks,\n            );\n        }\n\n        let trace_mode = TraceMode::Call\n            .with_debug(self.debug)\n            .with_decode_internal(if self.decode_internal {\n                InternalTraceMode::Full\n            } else {\n                InternalTraceMode::None\n            })\n            .with_state_changes(shell::verbosity() > 4);\n        let mut executor = TracingExecutor::new(\n            (evm_env.clone(), tx_env),\n            fork,\n            evm_version,\n            trace_mode,\n            networks,\n            create2_deployer,\n            None,\n        )?;\n\n        evm_env.cfg_env.set_spec(executor.spec_id());\n\n        // Set the state to the moment right before the transaction\n        if !self.quick {\n            if !shell::is_json() {\n                sh_println!(\"Executing previous transactions from the block.\")?;\n            }\n\n            if let Some(block) = block {\n                let pb = init_progress(block.transactions.len() as u64, \"tx\");\n                pb.set_position(0);\n\n                let BlockTransactions::Full(ref txs) = block.transactions else {\n                    return Err(eyre::eyre!(\"Could not get block txs\"));\n                };\n\n                for (index, tx) in txs.iter().enumerate() {\n                    // Replay system transactions only if running with `sys` option.\n                    // System transactions such as on L2s don't contain any pricing info so it\n                    // could cause reverts.\n                    if !self.replay_system_txes\n                        && (is_known_system_sender(tx.from())\n                            || tx.transaction_type() == Some(SYSTEM_TRANSACTION_TYPE))\n                    {\n                        pb.set_position((index + 1) as u64);\n                        continue;\n                    }\n                    if tx.tx_hash() == tx_hash {\n                        break;\n                    }\n\n                    let tx_env = tx.as_envelope().map_or(Default::default(), |tx_envelope| {\n                        TxEnv::from_recovered_tx(tx_envelope, tx.from())\n                    });\n\n                    evm_env.cfg_env.disable_balance_check = true;\n\n                    if let Some(to) = Transaction::to(tx) {\n                        trace!(tx=?tx.tx_hash(),?to, \"executing previous call transaction\");\n                        executor.transact_with_env(evm_env.clone(), tx_env.clone()).wrap_err_with(\n                            || {\n                                format!(\n                                    \"Failed to execute transaction: {:?} in block {}\",\n                                    tx.tx_hash(),\n                                    evm_env.block_env.number\n                                )\n                            },\n                        )?;\n                    } else {\n                        trace!(tx=?tx.tx_hash(), \"executing previous create transaction\");\n                        if let Err(error) =\n                            executor.deploy_with_env(evm_env.clone(), tx_env.clone(), None)\n                        {\n                            match error {\n                                // Reverted transactions should be skipped\n                                EvmError::Execution(_) => (),\n                                error => {\n                                    return Err(error).wrap_err_with(|| {\n                                        format!(\n                                            \"Failed to deploy transaction: {:?} in block {}\",\n                                            tx.tx_hash(),\n                                            evm_env.block_env.number\n                                        )\n                                    });\n                                }\n                            }\n                        }\n                    }\n\n                    pb.set_position((index + 1) as u64);\n                }\n            }\n        }\n\n        // Execute our transaction\n        let result = {\n            executor.set_trace_printer(self.trace_printer);\n\n            let tx_env = tx.as_envelope().map_or(Default::default(), |tx_envelope| {\n                TxEnv::from_recovered_tx(tx_envelope, tx.from())\n            });\n\n            if is_impersonated_tx(tx.as_ref()) {\n                evm_env.cfg_env.disable_balance_check = true;\n            }\n\n            if let Some(to) = Transaction::to(&tx) {\n                trace!(tx=?tx.tx_hash(), to=?to, \"executing call transaction\");\n                TraceResult::try_from(executor.transact_with_env(evm_env, tx_env))?\n            } else {\n                trace!(tx=?tx.tx_hash(), \"executing create transaction\");\n                TraceResult::try_from(executor.deploy_with_env(evm_env, tx_env, None))?\n            }\n        };\n\n        let contracts_bytecode = fetch_contracts_bytecode_from_trace(&executor, &result)?;\n        handle_traces(\n            result,\n            &config,\n            chain,\n            &contracts_bytecode,\n            label,\n            with_local_artifacts,\n            debug,\n            decode_internal,\n            disable_labels,\n            self.trace_depth,\n        )\n        .await?;\n\n        Ok(())\n    }\n}\n\npub fn fetch_contracts_bytecode_from_trace(\n    executor: &Executor,\n    result: &TraceResult,\n) -> Result<HashMap<Address, Bytes>> {\n    let mut contracts_bytecode = HashMap::default();\n    if let Some(ref traces) = result.traces {\n        contracts_bytecode.extend(gather_trace_addresses(traces).filter_map(|addr| {\n            // All relevant bytecodes should already be cached in the executor.\n            let code = executor\n                .backend()\n                .basic_ref(addr)\n                .inspect_err(|e| _ = sh_warn!(\"Failed to fetch code for {addr}: {e}\"))\n                .ok()??\n                .code?\n                .bytes();\n            if code.is_empty() {\n                return None;\n            }\n            Some((addr, code))\n        }));\n    }\n    Ok(contracts_bytecode)\n}\n\nfn gather_trace_addresses(traces: &Traces) -> impl Iterator<Item = Address> {\n    let mut addresses = AddressSet::default();\n    for (_, trace) in traces {\n        for node in trace.arena.nodes() {\n            if !node.trace.address.is_zero() {\n                addresses.insert(node.trace.address);\n            }\n            if !node.trace.caller.is_zero() {\n                addresses.insert(node.trace.caller);\n            }\n        }\n    }\n    addresses.into_iter()\n}\n\nimpl figment::Provider for RunArgs {\n    fn metadata(&self) -> Metadata {\n        Metadata::named(\"RunArgs\")\n    }\n\n    fn data(&self) -> Result<Map<Profile, Dict>, figment::Error> {\n        let mut map = Map::new();\n\n        if let Some(api_key) = &self.etherscan.key {\n            map.insert(\"etherscan_api_key\".into(), api_key.as_str().into());\n        }\n\n        if let Some(evm_version) = self.evm_version {\n            map.insert(\"evm_version\".into(), figment::value::Value::serialize(evm_version)?);\n        }\n\n        Ok(Map::from([(Config::selected_profile(), map)]))\n    }\n}\n"
  },
  {
    "path": "crates/cast/src/cmd/send.rs",
    "content": "use std::{path::PathBuf, str::FromStr, time::Duration};\n\nuse alloy_consensus::{SignableTransaction, Signed};\nuse alloy_ens::NameOrAddress;\nuse alloy_network::{AnyNetwork, EthereumWallet, Network};\nuse alloy_provider::{Provider, ProviderBuilder as AlloyProviderBuilder};\nuse alloy_signer::{Signature, Signer};\nuse clap::Parser;\nuse eyre::{Result, eyre};\nuse foundry_cli::{opts::TransactionOpts, utils::LoadConfig};\nuse foundry_common::{\n    fmt::{UIfmt, UIfmtReceiptExt},\n    provider::ProviderBuilder,\n};\nuse foundry_primitives::FoundryTransactionBuilder;\nuse tempo_alloy::TempoNetwork;\n\nuse crate::tx::{self, CastTxBuilder, CastTxSender, SendTxOpts};\n\n/// CLI arguments for `cast send`.\n#[derive(Debug, Parser)]\npub struct SendTxArgs {\n    /// The destination of the transaction.\n    ///\n    /// If not provided, you must use cast send --create.\n    #[arg(value_parser = NameOrAddress::from_str)]\n    to: Option<NameOrAddress>,\n\n    /// The signature of the function to call.\n    sig: Option<String>,\n\n    /// The arguments of the function to call.\n    #[arg(allow_negative_numbers = true)]\n    args: Vec<String>,\n\n    /// Raw hex-encoded data for the transaction. Used instead of \\[SIG\\] and \\[ARGS\\].\n    #[arg(\n        long,\n        conflicts_with_all = &[\"sig\", \"args\"]\n    )]\n    data: Option<String>,\n\n    #[command(flatten)]\n    send_tx: SendTxOpts,\n\n    #[command(subcommand)]\n    command: Option<SendTxSubcommands>,\n\n    /// Send via `eth_sendTransaction` using the `--from` argument or $ETH_FROM as sender\n    #[arg(long, requires = \"from\")]\n    unlocked: bool,\n\n    #[command(flatten)]\n    tx: TransactionOpts,\n\n    /// The path of blob data to be sent.\n    #[arg(\n        long,\n        value_name = \"BLOB_DATA_PATH\",\n        conflicts_with = \"legacy\",\n        requires = \"blob\",\n        help_heading = \"Transaction options\"\n    )]\n    path: Option<PathBuf>,\n}\n\n#[derive(Debug, Parser)]\npub enum SendTxSubcommands {\n    /// Use to deploy raw contract bytecode.\n    #[command(name = \"--create\")]\n    Create {\n        /// The bytecode of the contract to deploy.\n        code: String,\n\n        /// The signature of the function to call.\n        sig: Option<String>,\n\n        /// The arguments of the function to call.\n        #[arg(allow_negative_numbers = true)]\n        args: Vec<String>,\n    },\n}\n\nimpl SendTxArgs {\n    pub async fn run(self) -> Result<()> {\n        if self.tx.tempo.is_tempo() {\n            self.run_generic::<TempoNetwork>().await\n        } else {\n            self.run_generic::<AnyNetwork>().await\n        }\n    }\n\n    pub async fn run_generic<N: Network>(self) -> Result<()>\n    where\n        N::TxEnvelope: From<Signed<N::UnsignedTx>>,\n        N::UnsignedTx: SignableTransaction<Signature>,\n        N::TransactionRequest: FoundryTransactionBuilder<N>,\n        N::ReceiptResponse: UIfmt + UIfmtReceiptExt,\n    {\n        let Self { to, mut sig, mut args, data, send_tx, tx, command, unlocked, path } = self;\n\n        let print_sponsor_hash = tx.tempo.print_sponsor_hash;\n\n        let blob_data = if let Some(path) = path { Some(std::fs::read(path)?) } else { None };\n\n        if let Some(data) = data {\n            sig = Some(data);\n        }\n\n        let code = if let Some(SendTxSubcommands::Create {\n            code,\n            sig: constructor_sig,\n            args: constructor_args,\n        }) = command\n        {\n            // ensure we don't violate settings for transactions that can't be CREATE: 7702 and 4844\n            // which require mandatory target\n            if to.is_none() && !tx.auth.is_empty() {\n                return Err(eyre!(\n                    \"EIP-7702 transactions can't be CREATE transactions and require a destination address\"\n                ));\n            }\n            // ensure we don't violate settings for transactions that can't be CREATE: 7702 and 4844\n            // which require mandatory target\n            if to.is_none() && blob_data.is_some() {\n                return Err(eyre!(\n                    \"EIP-4844 transactions can't be CREATE transactions and require a destination address\"\n                ));\n            }\n\n            sig = constructor_sig;\n            args = constructor_args;\n            Some(code)\n        } else {\n            None\n        };\n\n        let config = send_tx.eth.load_config()?;\n        let provider = ProviderBuilder::<N>::from_config(&config)?.build()?;\n\n        if let Some(interval) = send_tx.poll_interval {\n            provider.client().set_poll_interval(Duration::from_secs(interval))\n        }\n\n        let builder = CastTxBuilder::new(&provider, tx, &config)\n            .await?\n            .with_to(to)\n            .await?\n            .with_code_sig_and_args(code, sig, args)\n            .await?\n            .with_blob_data(blob_data)?;\n\n        // If --tempo.print-sponsor-hash was passed, build the tx, print the hash, and exit.\n        if print_sponsor_hash {\n            let from = send_tx.eth.wallet.from.unwrap_or(config.sender);\n            let (tx, _) = builder.build(from).await?;\n            let hash = tx\n                .compute_sponsor_hash(from)\n                .ok_or_else(|| eyre!(\"This network does not support sponsored transactions\"))?;\n            sh_println!(\"{hash:?}\")?;\n            return Ok(());\n        }\n\n        let timeout = send_tx.timeout.unwrap_or(config.transaction_timeout);\n\n        // Launch browser signer if `--browser` flag is set\n        let browser = send_tx.browser.run::<N>().await?;\n\n        // Case 1:\n        // Default to sending via eth_sendTransaction if the --unlocked flag is passed.\n        // This should be the only way this RPC method is used as it requires a local node\n        // or remote RPC with unlocked accounts.\n        if unlocked && browser.is_none() {\n            // only check current chain id if it was specified in the config\n            if let Some(config_chain) = config.chain {\n                let current_chain_id = provider.get_chain_id().await?;\n                let config_chain_id = config_chain.id();\n                // switch chain if current chain id is not the same as the one specified in the\n                // config\n                if config_chain_id != current_chain_id {\n                    sh_warn!(\"Switching to chain {}\", config_chain)?;\n                    provider\n                        .raw_request::<_, ()>(\n                            \"wallet_switchEthereumChain\".into(),\n                            [serde_json::json!({\n                                \"chainId\": format!(\"0x{:x}\", config_chain_id),\n                            })],\n                        )\n                        .await?;\n                }\n            }\n\n            let (tx, _) = builder.build(config.sender).await?;\n\n            cast_send(\n                provider,\n                tx,\n                send_tx.cast_async,\n                send_tx.sync,\n                send_tx.confirmations,\n                timeout,\n            )\n            .await\n        // Case 2:\n        // Browser wallet signs and sends the transaction in one step.\n        } else if let Some(browser) = browser {\n            let (tx_request, _) = builder.build(browser.address()).await?;\n            let tx_hash = browser.send_transaction_via_browser(tx_request).await?;\n\n            let cast = CastTxSender::new(&provider);\n            cast.print_tx_result(tx_hash, send_tx.cast_async, send_tx.confirmations, timeout).await\n        // Case 3:\n        // An option to use a local signer was provided.\n        // If we cannot successfully instantiate a local signer, then we will assume we don't have\n        // enough information to sign and we must bail.\n        } else {\n            let signer = send_tx.eth.wallet.signer().await?;\n            let from = signer.address();\n\n            tx::validate_from_address(send_tx.eth.wallet.from, from)?;\n\n            let (tx_request, _) = builder.build(&signer).await?;\n\n            let wallet = EthereumWallet::from(signer);\n            let provider = AlloyProviderBuilder::<_, _, N>::default()\n                .wallet(wallet)\n                .connect_provider(&provider);\n\n            cast_send(\n                provider,\n                tx_request,\n                send_tx.cast_async,\n                send_tx.sync,\n                send_tx.confirmations,\n                timeout,\n            )\n            .await\n        }\n    }\n}\n\npub(crate) async fn cast_send<N: Network, P: Provider<N>>(\n    provider: P,\n    tx: N::TransactionRequest,\n    cast_async: bool,\n    sync: bool,\n    confs: u64,\n    timeout: u64,\n) -> Result<()>\nwhere\n    N::TransactionRequest: FoundryTransactionBuilder<N>,\n    N::ReceiptResponse: UIfmt + UIfmtReceiptExt,\n{\n    let cast = CastTxSender::new(provider);\n\n    if sync {\n        // Send transaction and wait for receipt synchronously\n        let receipt = cast.send_sync(tx).await?;\n        sh_println!(\"{receipt}\")?;\n    } else {\n        let pending_tx = cast.send(tx).await?;\n        let tx_hash = *pending_tx.inner().tx_hash();\n        cast.print_tx_result(tx_hash, cast_async, confs, timeout).await?;\n    }\n\n    Ok(())\n}\n"
  },
  {
    "path": "crates/cast/src/cmd/storage.rs",
    "content": "use crate::{Cast, opts::parse_slot};\nuse alloy_ens::NameOrAddress;\nuse alloy_network::AnyNetwork;\nuse alloy_primitives::{Address, B256, U256};\nuse alloy_provider::Provider;\nuse alloy_rpc_types::BlockId;\nuse clap::Parser;\nuse comfy_table::{Cell, Table, modifiers::UTF8_ROUND_CORNERS, presets::ASCII_MARKDOWN};\nuse eyre::Result;\nuse foundry_block_explorers::Client;\nuse foundry_cli::{\n    opts::{BuildOpts, EtherscanOpts, RpcOpts},\n    utils,\n    utils::LoadConfig,\n};\nuse foundry_common::{\n    abi::find_source,\n    compile::{ProjectCompiler, etherscan_project},\n    shell,\n};\nuse foundry_compilers::{\n    Artifact, Project,\n    artifacts::{ConfigurableContractArtifact, Contract, StorageLayout},\n    compilers::{\n        Compiler,\n        solc::{Solc, SolcCompiler},\n    },\n};\nuse foundry_config::{\n    Config,\n    figment::{self, Metadata, Profile, value::Dict},\n    impl_figment_convert_cast,\n};\nuse semver::Version;\nuse serde::{Deserialize, Serialize};\nuse std::str::FromStr;\n\n/// The minimum Solc version for outputting storage layouts.\n///\n/// <https://github.com/ethereum/solidity/blob/develop/Changelog.md#065-2020-04-06>\nconst MIN_SOLC: Version = Version::new(0, 6, 5);\n\n/// CLI arguments for `cast storage`.\n#[derive(Clone, Debug, Parser)]\npub struct StorageArgs {\n    /// The contract address.\n    #[arg(value_parser = NameOrAddress::from_str)]\n    address: NameOrAddress,\n\n    /// The storage slot number. If not provided, it gets the full storage layout.\n    #[arg(value_parser = parse_slot)]\n    base_slot: Option<B256>,\n\n    /// The storage offset from the base slot. If not provided, it is assumed to be zero.\n    #[arg(value_parser = str::parse::<U256>, default_value_t = U256::ZERO)]\n    offset: U256,\n\n    /// The known proxy address. If provided, the storage layout is retrieved from this address.\n    #[arg(long,value_parser = NameOrAddress::from_str)]\n    proxy: Option<NameOrAddress>,\n\n    /// The block height to query at.\n    ///\n    /// Can also be the tags earliest, finalized, safe, latest, or pending.\n    #[arg(long, short)]\n    block: Option<BlockId>,\n\n    #[command(flatten)]\n    rpc: RpcOpts,\n\n    #[command(flatten)]\n    etherscan: EtherscanOpts,\n\n    #[command(flatten)]\n    build: BuildOpts,\n\n    /// Specify the solc version to compile with. Overrides detected version.\n    #[arg(long, value_parser = Version::parse)]\n    solc_version: Option<Version>,\n}\n\nimpl_figment_convert_cast!(StorageArgs);\n\nimpl figment::Provider for StorageArgs {\n    fn metadata(&self) -> Metadata {\n        Metadata::named(\"StorageArgs\")\n    }\n\n    fn data(&self) -> Result<figment::value::Map<Profile, Dict>, figment::Error> {\n        let mut map = self.build.data()?;\n        let dict = map.get_mut(&Config::selected_profile()).unwrap();\n        dict.extend(self.rpc.dict());\n        dict.extend(self.etherscan.dict());\n        Ok(map)\n    }\n}\n\nimpl StorageArgs {\n    pub async fn run(self) -> Result<()> {\n        let config = self.load_config()?;\n\n        let Self { address, base_slot, offset, block, build, .. } = self;\n        let provider = utils::get_provider(&config)?;\n        let address = address.resolve(&provider).await?;\n\n        // Slot was provided, perform a simple RPC call\n        if let Some(slot) = base_slot {\n            let cast = Cast::new(provider);\n            sh_println!(\n                \"{}\",\n                cast.storage(\n                    address,\n                    (Into::<U256>::into(slot).saturating_add(offset)).into(),\n                    block\n                )\n                .await?\n            )?;\n            return Ok(());\n        }\n\n        // No slot was provided\n        // Get deployed bytecode at given address\n        let address_code =\n            provider.get_code_at(address).block_id(block.unwrap_or_default()).await?;\n        if address_code.is_empty() {\n            eyre::bail!(\"Provided address has no deployed code and thus no storage\");\n        }\n\n        // Check if we're in a forge project and if we can find the address' code\n        let mut project = build.project()?;\n        if project.paths.has_input_files() {\n            // Find in artifacts and pretty print\n            add_storage_layout_output(&mut project);\n            let out = ProjectCompiler::new().quiet(shell::is_json()).compile(&project)?;\n            let artifact = out.artifacts().find(|(_, artifact)| {\n                artifact.get_deployed_bytecode_bytes().is_some_and(|b| *b == address_code)\n            });\n            if let Some((_, artifact)) = artifact {\n                return fetch_and_print_storage(provider, address, block, artifact).await;\n            }\n        }\n\n        let chain = utils::get_chain(config.chain, &provider).await?;\n        let api_key = config.get_etherscan_api_key(Some(chain)).or_else(|| self.etherscan.key()).ok_or_else(|| {\n            eyre::eyre!(\"You must provide an Etherscan API key if you're fetching a remote contract's storage.\")\n        })?;\n        let client = Client::new(chain, api_key)?;\n        let source = if let Some(proxy) = self.proxy {\n            find_source(client, proxy.resolve(&provider).await?).await?\n        } else {\n            find_source(client, address).await?\n        };\n        let metadata = source.items.first().unwrap();\n        if metadata.is_vyper() {\n            eyre::bail!(\"Contract at provided address is not a valid Solidity contract\")\n        }\n\n        // Create or reuse a persistent cache for Etherscan sources; fall back to a temp dir\n        let mut temp_dir = None;\n        let root_path = if let Some(cache_root) =\n            foundry_config::Config::foundry_etherscan_chain_cache_dir(chain)\n        {\n            let sources_root = cache_root.join(\"sources\");\n            let contract_root = sources_root.join(format!(\"{address}\"));\n            if let Err(err) = std::fs::create_dir_all(&contract_root) {\n                sh_warn!(\"Could not create etherscan cache dir, falling back to temp: {err}\")?;\n                let tmp = tempfile::tempdir()?;\n                let path = tmp.path().to_path_buf();\n                temp_dir = Some(tmp);\n                path\n            } else {\n                contract_root\n            }\n        } else {\n            let tmp = tempfile::tempdir()?;\n            let path = tmp.path().to_path_buf();\n            temp_dir = Some(tmp);\n            path\n        };\n        let mut project = etherscan_project(metadata, &root_path)?;\n        add_storage_layout_output(&mut project);\n\n        // Decide on compiler to use (user override -> metadata -> autodetect)\n        let meta_version = metadata.compiler_version()?;\n        let mut auto_detect = false;\n        let desired = if let Some(user_version) = self.solc_version {\n            if user_version < MIN_SOLC {\n                sh_warn!(\n                    \"The provided --solc-version is {user_version} while the minimum version for \\\n                     storage layouts is {MIN_SOLC} and as a result the output may be empty.\"\n                )?;\n            }\n            SolcCompiler::Specific(Solc::find_or_install(&user_version)?)\n        } else if meta_version < MIN_SOLC {\n            auto_detect = true;\n            SolcCompiler::AutoDetect\n        } else {\n            SolcCompiler::Specific(Solc::find_or_install(&meta_version)?)\n        };\n        project.compiler.solc = Some(desired);\n\n        // Compile\n        let mut out = ProjectCompiler::new().quiet(true).compile(&project)?;\n        let artifact = {\n            let (_, mut artifact) = out\n                .artifacts()\n                .find(|(name, _)| name == &metadata.contract_name)\n                .ok_or_else(|| eyre::eyre!(\"Could not find artifact\"))?;\n\n            if auto_detect && is_storage_layout_empty(&artifact.storage_layout) {\n                // try recompiling with the minimum version\n                sh_warn!(\n                    \"The requested contract was compiled with {meta_version} while the minimum version \\\n                     for storage layouts is {MIN_SOLC} and as a result the output may be empty.\",\n                )?;\n                let solc = Solc::find_or_install(&MIN_SOLC)?;\n                project.compiler.solc = Some(SolcCompiler::Specific(solc));\n                if let Ok(output) = ProjectCompiler::new().quiet(true).compile(&project) {\n                    out = output;\n                    let (_, new_artifact) = out\n                        .artifacts()\n                        .find(|(name, _)| name == &metadata.contract_name)\n                        .ok_or_else(|| eyre::eyre!(\"Could not find artifact\"))?;\n                    artifact = new_artifact;\n                }\n            }\n\n            artifact\n        };\n\n        drop(temp_dir);\n        fetch_and_print_storage(provider, address, block, artifact).await\n    }\n}\n\n/// Represents the value of a storage slot `eth_getStorageAt` call.\n#[derive(Clone, Debug, PartialEq, Eq)]\nstruct StorageValue {\n    /// The slot number.\n    slot: B256,\n    /// The value as returned by `eth_getStorageAt`.\n    raw_slot_value: B256,\n}\n\nimpl StorageValue {\n    /// Returns the value of the storage slot, applying the offset if necessary.\n    fn value(&self, offset: i64, number_of_bytes: Option<usize>) -> B256 {\n        let offset = offset as usize;\n        let mut end = 32;\n        if let Some(number_of_bytes) = number_of_bytes {\n            end = offset + number_of_bytes;\n            if end > 32 {\n                end = 32;\n            }\n        }\n\n        // reverse range, because the value is stored in big endian\n        let raw_sliced_value = &self.raw_slot_value.as_slice()[32 - end..32 - offset];\n\n        // copy the raw sliced value as tail\n        let mut value = [0u8; 32];\n        value[32 - raw_sliced_value.len()..32].copy_from_slice(raw_sliced_value);\n        B256::from(value)\n    }\n}\n\n/// Represents the storage layout of a contract and its values.\n#[derive(Clone, Debug, Serialize, Deserialize)]\nstruct StorageReport {\n    #[serde(flatten)]\n    layout: StorageLayout,\n    values: Vec<B256>,\n}\n\nasync fn fetch_and_print_storage<P: Provider<AnyNetwork>>(\n    provider: P,\n    address: Address,\n    block: Option<BlockId>,\n    artifact: &ConfigurableContractArtifact,\n) -> Result<()> {\n    if is_storage_layout_empty(&artifact.storage_layout) {\n        sh_warn!(\"Storage layout is empty.\")?;\n        Ok(())\n    } else {\n        let layout = artifact.storage_layout.as_ref().unwrap().clone();\n        let values = fetch_storage_slots(provider, address, block, &layout).await?;\n        print_storage(layout, values)\n    }\n}\n\nasync fn fetch_storage_slots<P: Provider<AnyNetwork>>(\n    provider: P,\n    address: Address,\n    block: Option<BlockId>,\n    layout: &StorageLayout,\n) -> Result<Vec<StorageValue>> {\n    let requests = layout.storage.iter().map(|storage_slot| async {\n        let slot = B256::from(U256::from_str(&storage_slot.slot)?);\n        let raw_slot_value = provider\n            .get_storage_at(address, slot.into())\n            .block_id(block.unwrap_or_default())\n            .await?;\n\n        let value = StorageValue { slot, raw_slot_value: raw_slot_value.into() };\n\n        Ok(value)\n    });\n\n    futures::future::try_join_all(requests).await\n}\n\nfn print_storage(layout: StorageLayout, values: Vec<StorageValue>) -> Result<()> {\n    if shell::is_json() {\n        let values: Vec<_> = layout\n            .storage\n            .iter()\n            .zip(&values)\n            .map(|(slot, storage_value)| {\n                let storage_type = layout.types.get(&slot.storage_type);\n                storage_value.value(\n                    slot.offset,\n                    storage_type.and_then(|t| t.number_of_bytes.parse::<usize>().ok()),\n                )\n            })\n            .collect();\n        sh_println!(\n            \"{}\",\n            serde_json::to_string_pretty(&serde_json::to_value(StorageReport { layout, values })?)?\n        )?;\n        return Ok(());\n    }\n\n    let mut table = Table::new();\n    if shell::is_markdown() {\n        table.load_preset(ASCII_MARKDOWN);\n    } else {\n        table.apply_modifier(UTF8_ROUND_CORNERS);\n    }\n\n    table.set_header(vec![\n        Cell::new(\"Name\"),\n        Cell::new(\"Type\"),\n        Cell::new(\"Slot\"),\n        Cell::new(\"Offset\"),\n        Cell::new(\"Bytes\"),\n        Cell::new(\"Value\"),\n        Cell::new(\"Hex Value\"),\n        Cell::new(\"Contract\"),\n    ]);\n\n    for (slot, storage_value) in layout.storage.into_iter().zip(values) {\n        let storage_type = layout.types.get(&slot.storage_type);\n        let value = storage_value\n            .value(slot.offset, storage_type.and_then(|t| t.number_of_bytes.parse::<usize>().ok()));\n        let converted_value = U256::from_be_bytes(value.0);\n\n        table.add_row([\n            slot.label.as_str(),\n            storage_type.map_or(\"?\", |t| &t.label),\n            &slot.slot,\n            &slot.offset.to_string(),\n            storage_type.map_or(\"?\", |t| &t.number_of_bytes),\n            &converted_value.to_string(),\n            &value.to_string(),\n            &slot.contract,\n        ]);\n    }\n\n    sh_println!(\"\\n{table}\\n\")?;\n\n    Ok(())\n}\n\nfn add_storage_layout_output<C: Compiler<CompilerContract = Contract>>(project: &mut Project<C>) {\n    project.artifacts.additional_values.storage_layout = true;\n    project.update_output_selection(|selection| {\n        selection.0.values_mut().for_each(|contract_selection| {\n            contract_selection\n                .values_mut()\n                .for_each(|selection| selection.push(\"storageLayout\".to_string()))\n        });\n    })\n}\n\nfn is_storage_layout_empty(storage_layout: &Option<StorageLayout>) -> bool {\n    if let Some(s) = storage_layout { s.storage.is_empty() } else { true }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn parse_storage_etherscan_api_key() {\n        let args =\n            StorageArgs::parse_from([\"foundry-cli\", \"addr.eth\", \"--etherscan-api-key\", \"dummykey\"]);\n        assert_eq!(args.etherscan.key(), Some(\"dummykey\".to_string()));\n\n        unsafe {\n            std::env::set_var(\"ETHERSCAN_API_KEY\", \"FXY\");\n        }\n        let config = args.load_config().unwrap();\n        unsafe {\n            std::env::remove_var(\"ETHERSCAN_API_KEY\");\n        }\n        assert_eq!(config.etherscan_api_key, Some(\"dummykey\".to_string()));\n\n        let key = config.get_etherscan_api_key(None).unwrap();\n        assert_eq!(key, \"dummykey\".to_string());\n    }\n\n    #[test]\n    fn parse_solc_version_arg() {\n        let args = StorageArgs::parse_from([\"foundry-cli\", \"addr.eth\", \"--solc-version\", \"0.8.10\"]);\n        assert_eq!(args.solc_version, Some(Version::parse(\"0.8.10\").unwrap()));\n    }\n}\n"
  },
  {
    "path": "crates/cast/src/cmd/trace.rs",
    "content": "use alloy_eips::Encodable2718;\nuse alloy_network::AnyRpcTransaction;\nuse alloy_primitives::hex;\nuse alloy_provider::ext::TraceApi;\nuse clap::Parser;\nuse eyre::Result;\nuse foundry_cli::{\n    opts::RpcOpts,\n    utils::{self, LoadConfig},\n};\nuse foundry_common::stdin;\n\n/// CLI arguments for `cast trace`.\n#[derive(Debug, Parser)]\npub struct TraceArgs {\n    /// Transaction hash (for trace_transaction) or raw tx hex/JSON (for trace_rawTransaction\n    /// with --raw)\n    tx: Option<String>,\n\n    /// Use trace_rawTransaction instead of trace_transaction.\n    /// Required when passing raw transaction hex or JSON instead of a tx hash.\n    #[arg(long)]\n    raw: bool,\n\n    /// Include the basic trace of the transaction.\n    #[arg(long, requires = \"raw\")]\n    trace: bool,\n\n    /// Include the full trace of the virtual machine's state during transaction execution\n    #[arg(long, requires = \"raw\")]\n    vm_trace: bool,\n\n    /// Include state changes caused by the transaction (requires --raw).\n    #[arg(long, requires = \"raw\")]\n    state_diff: bool,\n\n    #[command(flatten)]\n    rpc: RpcOpts,\n}\n\nimpl TraceArgs {\n    pub async fn run(self) -> Result<()> {\n        let config = self.rpc.load_config()?;\n        let provider = utils::get_provider(&config)?;\n        let input = stdin::unwrap_line(self.tx)?;\n\n        let trimmed = input.trim();\n        let is_json = trimmed.starts_with('{');\n        let is_raw_hex = trimmed.starts_with(\"0x\") && trimmed.len() > 66;\n\n        let result = if self.raw {\n            // trace_rawTransaction: accepts raw hex OR JSON tx\n            let raw_bytes = if is_raw_hex {\n                hex::decode(trimmed.strip_prefix(\"0x\").unwrap_or(trimmed))?\n            } else if is_json {\n                let tx: AnyRpcTransaction = serde_json::from_str(trimmed)?;\n                tx.as_ref().encoded_2718().to_vec()\n            } else {\n                hex::decode(trimmed)?\n            };\n\n            let mut trace_builder = provider.trace_raw_transaction(&raw_bytes);\n\n            if self.trace {\n                trace_builder = trace_builder.trace();\n            }\n            if self.vm_trace {\n                trace_builder = trace_builder.vm_trace();\n            }\n            if self.state_diff {\n                trace_builder = trace_builder.state_diff();\n            }\n\n            if trace_builder.get_trace_types().map(|t| t.is_empty()).unwrap_or(true) {\n                eyre::bail!(\"No trace type specified. Use --trace, --vm-trace, or --state-diff\");\n            }\n\n            serde_json::to_string_pretty(&trace_builder.await?)?\n        } else {\n            // trace_transaction: use tx hash directly\n            let hash = input.parse()?;\n            let traces = provider.trace_transaction(hash).await?;\n            serde_json::to_string_pretty(&traces)?\n        };\n\n        sh_println!(\"{}\", result)?;\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "crates/cast/src/cmd/txpool.rs",
    "content": "use alloy_primitives::Address;\nuse alloy_provider::ext::TxPoolApi;\nuse clap::Parser;\nuse foundry_cli::{\n    opts::RpcOpts,\n    utils::{self, LoadConfig},\n};\n\n/// CLI arguments for `cast tx-pool`.\n#[derive(Debug, Parser, Clone)]\npub enum TxPoolSubcommands {\n    /// Fetches the content of the transaction pool.\n    Content {\n        #[command(flatten)]\n        args: RpcOpts,\n    },\n    /// Fetches the content of the transaction pool filtered by a specific address.\n    ContentFrom {\n        /// The Signer to filter the transactions by.\n        #[arg(short, long)]\n        from: Address,\n        #[command(flatten)]\n        args: RpcOpts,\n    },\n    /// Fetches a textual summary of each transaction in the pool.\n    Inspect {\n        #[command(flatten)]\n        args: RpcOpts,\n    },\n    /// Fetches the current status of the transaction pool.\n    Status {\n        #[command(flatten)]\n        args: RpcOpts,\n    },\n}\n\nimpl TxPoolSubcommands {\n    pub async fn run(self) -> eyre::Result<()> {\n        match self {\n            Self::Content { args } => {\n                let config = args.load_config()?;\n                let provider = utils::get_provider(&config)?;\n                let content = provider.txpool_content().await?;\n                sh_println!(\"{}\", serde_json::to_string_pretty(&content)?)?;\n            }\n            Self::ContentFrom { from, args } => {\n                let config = args.load_config()?;\n                let provider = utils::get_provider(&config)?;\n                let content = provider.txpool_content_from(from).await?;\n                sh_println!(\"{}\", serde_json::to_string_pretty(&content)?)?;\n            }\n            Self::Inspect { args } => {\n                let config = args.load_config()?;\n                let provider = utils::get_provider(&config)?;\n                let inspect = provider.txpool_inspect().await?;\n                sh_println!(\"{}\", serde_json::to_string_pretty(&inspect)?)?;\n            }\n            Self::Status { args } => {\n                let config = args.load_config()?;\n                let provider = utils::get_provider(&config)?;\n                let status = provider.txpool_status().await?;\n                sh_println!(\"{}\", serde_json::to_string_pretty(&status)?)?;\n            }\n        };\n\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "crates/cast/src/cmd/wallet/list.rs",
    "content": "use clap::Parser;\nuse eyre::Result;\nuse std::env;\n\nuse foundry_common::{fs, sh_err, sh_println};\nuse foundry_config::Config;\nuse foundry_wallets::wallet_multi::MultiWalletOptsBuilder;\n\n/// CLI arguments for `cast wallet list`.\n#[derive(Clone, Debug, Parser)]\npub struct ListArgs {\n    /// List all the accounts in the keystore directory.\n    /// Default keystore directory is used if no path provided.\n    #[arg(long, default_missing_value = \"\", num_args(0..=1))]\n    dir: Option<String>,\n\n    /// List accounts from a Ledger hardware wallet.\n    #[arg(long, short, group = \"hw-wallets\")]\n    ledger: bool,\n\n    /// List accounts from a Trezor hardware wallet.\n    #[arg(long, short, group = \"hw-wallets\")]\n    trezor: bool,\n\n    /// List accounts from AWS KMS.\n    ///\n    /// Ensure either one of AWS_KMS_KEY_IDS (comma-separated) or AWS_KMS_KEY_ID environment\n    /// variables are set.\n    #[arg(long, hide = !cfg!(feature = \"aws-kms\"))]\n    aws: bool,\n\n    /// List accounts from Google Cloud KMS.\n    ///\n    /// Ensure the following environment variables are set: GCP_PROJECT_ID, GCP_LOCATION,\n    /// GCP_KEY_RING, GCP_KEY_NAME, GCP_KEY_VERSION.\n    ///\n    /// See: <https://cloud.google.com/kms/docs>\n    #[arg(long, hide = !cfg!(feature = \"gcp-kms\"))]\n    gcp: bool,\n\n    /// List accounts from Turnkey.\n    #[arg(long, hide = !cfg!(feature = \"turnkey\"))]\n    turnkey: bool,\n\n    /// List all configured accounts.\n    #[arg(long, group = \"hw-wallets\")]\n    all: bool,\n\n    /// Max number of addresses to display from hardware wallets.\n    #[arg(long, short, default_value = \"3\", requires = \"hw-wallets\")]\n    max_senders: Option<usize>,\n}\n\nimpl ListArgs {\n    pub async fn run(self) -> Result<()> {\n        // list local accounts as files in keystore dir, no need to unlock / provide password\n        if self.dir.is_some()\n            || self.all\n            || (!self.ledger && !self.trezor && !self.aws && !self.gcp)\n        {\n            match self.list_local_senders() {\n                Ok(()) => {}\n                Err(e) if !self.all => {\n                    sh_err!(\"{}\", e)?;\n                }\n                _ => {}\n            }\n        }\n\n        // Create options for multi wallet - ledger, trezor and AWS\n        let list_opts = MultiWalletOptsBuilder::default()\n            .ledger(self.ledger || self.all)\n            .mnemonic_indexes(Some(vec![0]))\n            .trezor(self.trezor || self.all)\n            .aws(self.aws || self.all)\n            .gcp(self.gcp || (self.all && gcp_env_vars_set()))\n            .turnkey(self.turnkey || self.all)\n            .interactives(0)\n            .interactive(false)\n            .browser(Default::default())\n            .build()\n            .expect(\"build multi wallet\");\n\n        // macro to print senders for a list of signers\n        macro_rules! list_senders {\n            ($signers:expr, $label:literal) => {\n                match $signers.await {\n                    Ok(signers) => {\n                        for signer in signers.unwrap_or_default().iter() {\n                            signer\n                                .available_senders(self.max_senders.unwrap())\n                                .await?\n                                .iter()\n                                .for_each(|sender| {\n                                    let _ = sh_println!(\"{} ({})\", sender, $label);\n                                })\n                        }\n                    }\n                    Err(e) if !self.all => {\n                        sh_err!(\"{}\", e)?;\n                    }\n                    _ => {}\n                }\n            };\n        }\n\n        list_senders!(list_opts.ledgers(), \"Ledger\");\n        list_senders!(list_opts.trezors(), \"Trezor\");\n        list_senders!(list_opts.aws_signers(), \"AWS\");\n        list_senders!(list_opts.gcp_signers(), \"GCP\");\n\n        Ok(())\n    }\n\n    fn list_local_senders(&self) -> Result<()> {\n        let keystore_path = self.dir.as_deref().unwrap_or_default();\n        let keystore_dir = if keystore_path.is_empty() {\n            // Create the keystore default directory if it doesn't exist\n            let default_dir = Config::foundry_keystores_dir().unwrap();\n            fs::create_dir_all(&default_dir)?;\n            default_dir\n        } else {\n            dunce::canonicalize(keystore_path)?\n        };\n\n        // List all files within the keystore directory.\n        for entry in std::fs::read_dir(keystore_dir)? {\n            let path = entry?.path();\n            if path.is_file()\n                && let Some(file_name) = path.file_name()\n                && let Some(name) = file_name.to_str()\n            {\n                // Extract address from keystore filename format: UTC--{timestamp}--{address}\n                if let Some(address) = name.split(\"--\").last() {\n                    sh_println!(\"0x{} (Local)\", address)?;\n                }\n            }\n        }\n\n        Ok(())\n    }\n}\n\nfn gcp_env_vars_set() -> bool {\n    let required_vars =\n        [\"GCP_PROJECT_ID\", \"GCP_LOCATION\", \"GCP_KEY_RING\", \"GCP_KEY_NAME\", \"GCP_KEY_VERSION\"];\n\n    required_vars.iter().all(|&var| env::var(var).is_ok())\n}\n"
  },
  {
    "path": "crates/cast/src/cmd/wallet/mod.rs",
    "content": "use alloy_chains::Chain;\nuse alloy_dyn_abi::TypedData;\nuse alloy_primitives::{Address, B256, Signature, U256, hex};\nuse alloy_provider::Provider;\nuse alloy_rpc_types::Authorization;\nuse alloy_signer::Signer;\nuse alloy_signer_local::{\n    MnemonicBuilder, PrivateKeySigner,\n    coins_bip39::{English, Entropy, Mnemonic},\n};\nuse clap::Parser;\nuse eyre::{Context, Result};\nuse foundry_cli::{opts::RpcOpts, utils, utils::LoadConfig};\nuse foundry_common::{fs, sh_println, shell};\nuse foundry_config::Config;\nuse foundry_wallets::{RawWalletOpts, WalletOpts, WalletSigner};\nuse rand_08::thread_rng;\nuse serde_json::json;\nuse std::path::Path;\nuse yansi::Paint;\n\npub mod vanity;\nuse vanity::VanityArgs;\n\npub mod list;\nuse list::ListArgs;\n\n/// CLI arguments for `cast wallet`.\n#[derive(Debug, Parser)]\npub enum WalletSubcommands {\n    /// Create a new random keypair.\n    #[command(visible_alias = \"n\")]\n    New {\n        /// If provided, then keypair will be written to an encrypted JSON keystore.\n        path: Option<String>,\n\n        /// Account name for the keystore file. If provided, the keystore file\n        /// will be named using this account name.\n        #[arg(value_name = \"ACCOUNT_NAME\")]\n        account_name: Option<String>,\n\n        /// Triggers a hidden password prompt for the JSON keystore.\n        ///\n        /// Deprecated: prompting for a hidden password is now the default.\n        #[arg(long, short, conflicts_with = \"unsafe_password\")]\n        password: bool,\n\n        /// Password for the JSON keystore in cleartext.\n        ///\n        /// This is UNSAFE to use and we recommend using the --password.\n        #[arg(long, env = \"CAST_PASSWORD\", value_name = \"PASSWORD\")]\n        unsafe_password: Option<String>,\n\n        /// Number of wallets to generate.\n        #[arg(long, short, default_value = \"1\")]\n        number: u32,\n\n        /// Overwrite existing keystore files without prompting.\n        #[arg(long)]\n        force: bool,\n    },\n\n    /// Generates a random BIP39 mnemonic phrase\n    #[command(visible_alias = \"nm\")]\n    NewMnemonic {\n        /// Number of words for the mnemonic\n        #[arg(long, short, default_value = \"12\")]\n        words: usize,\n\n        /// Number of accounts to display\n        #[arg(long, short, default_value = \"1\")]\n        accounts: u8,\n\n        /// Entropy to use for the mnemonic\n        #[arg(long, short, conflicts_with = \"words\")]\n        entropy: Option<String>,\n    },\n\n    /// Generate a vanity address.\n    #[command(visible_alias = \"va\")]\n    Vanity(VanityArgs),\n\n    /// Convert a private key to an address.\n    #[command(visible_aliases = &[\"a\", \"addr\"])]\n    Address {\n        /// If provided, the address will be derived from the specified private key.\n        #[arg(value_name = \"PRIVATE_KEY\")]\n        private_key_override: Option<String>,\n\n        #[command(flatten)]\n        wallet: WalletOpts,\n    },\n\n    /// Derive accounts from a mnemonic\n    #[command(visible_alias = \"d\")]\n    Derive {\n        /// The accounts will be derived from the specified mnemonic phrase.\n        #[arg(value_name = \"MNEMONIC\")]\n        mnemonic: String,\n\n        /// Number of accounts to display.\n        #[arg(long, short, default_value = \"1\")]\n        accounts: Option<u8>,\n\n        /// Insecure mode: display private keys in the terminal.\n        #[arg(long, default_value = \"false\")]\n        insecure: bool,\n    },\n\n    /// Sign a message or typed data.\n    #[command(visible_alias = \"s\")]\n    Sign {\n        /// The message, typed data, or hash to sign.\n        ///\n        /// Messages starting with 0x are expected to be hex encoded, which get decoded before\n        /// being signed.\n        ///\n        /// The message will be prefixed with the Ethereum Signed Message header and hashed before\n        /// signing, unless `--no-hash` is provided.\n        ///\n        /// Typed data can be provided as a json string or a file name.\n        /// Use --data flag to denote the message is a string of typed data.\n        /// Use --data --from-file to denote the message is a file name containing typed data.\n        /// The data will be combined and hashed using the EIP712 specification before signing.\n        /// The data should be formatted as JSON.\n        message: String,\n\n        /// Treat the message as JSON typed data.\n        #[arg(long)]\n        data: bool,\n\n        /// Treat the message as a file containing JSON typed data. Requires `--data`.\n        #[arg(long, requires = \"data\")]\n        from_file: bool,\n\n        /// Treat the message as a raw 32-byte hash and sign it directly without hashing it again.\n        #[arg(long, conflicts_with = \"data\")]\n        no_hash: bool,\n\n        #[command(flatten)]\n        wallet: WalletOpts,\n    },\n\n    /// EIP-7702 sign authorization.\n    #[command(visible_alias = \"sa\")]\n    SignAuth {\n        /// Address to sign authorization for.\n        address: Address,\n\n        #[command(flatten)]\n        rpc: RpcOpts,\n\n        #[arg(long)]\n        nonce: Option<u64>,\n\n        #[arg(long)]\n        chain: Option<Chain>,\n\n        /// If set, indicates the authorization will be broadcast by the signing account itself.\n        /// This means the nonce used will be the current nonce + 1 (to account for the\n        /// transaction that will include this authorization).\n        #[arg(long, conflicts_with = \"nonce\")]\n        self_broadcast: bool,\n\n        #[command(flatten)]\n        wallet: WalletOpts,\n    },\n\n    /// Verify the signature of a message.\n    #[command(visible_alias = \"v\")]\n    Verify {\n        /// The original message.\n        ///\n        /// Treats 0x-prefixed strings as hex encoded bytes.\n        /// Non 0x-prefixed strings are treated as raw input message.\n        ///\n        /// The message will be prefixed with the Ethereum Signed Message header and hashed before\n        /// signing, unless `--no-hash` is provided.\n        ///\n        /// Typed data can be provided as a json string or a file name.\n        /// Use --data flag to denote the message is a string of typed data.\n        /// Use --data --from-file to denote the message is a file name containing typed data.\n        /// The data will be combined and hashed using the EIP712 specification before signing.\n        /// The data should be formatted as JSON.\n        message: String,\n\n        /// The signature to verify.\n        signature: Signature,\n\n        /// The address of the message signer.\n        #[arg(long, short)]\n        address: Address,\n\n        /// Treat the message as JSON typed data.\n        #[arg(long)]\n        data: bool,\n\n        /// Treat the message as a file containing JSON typed data. Requires `--data`.\n        #[arg(long, requires = \"data\")]\n        from_file: bool,\n\n        /// Treat the message as a raw 32-byte hash and sign it directly without hashing it again.\n        #[arg(long, conflicts_with = \"data\")]\n        no_hash: bool,\n    },\n\n    /// Import a private key into an encrypted keystore.\n    #[command(visible_alias = \"i\")]\n    Import {\n        /// The name for the account in the keystore.\n        #[arg(value_name = \"ACCOUNT_NAME\")]\n        account_name: String,\n        /// If provided, keystore will be saved here instead of the default keystores directory\n        /// (~/.foundry/keystores)\n        #[arg(long, short)]\n        keystore_dir: Option<String>,\n        /// Password for the JSON keystore in cleartext\n        /// This is unsafe, we recommend using the default hidden password prompt\n        #[arg(long, env = \"CAST_UNSAFE_PASSWORD\", value_name = \"PASSWORD\")]\n        unsafe_password: Option<String>,\n        #[command(flatten)]\n        raw_wallet_options: RawWalletOpts,\n    },\n\n    /// List all the accounts in the keystore default directory\n    #[command(visible_alias = \"ls\")]\n    List(ListArgs),\n\n    /// Remove a wallet from the keystore.\n    ///\n    /// This command requires the wallet alias and will prompt for a password to ensure that only\n    /// an authorized user can remove the wallet.\n    #[command(visible_aliases = &[\"rm\"], override_usage = \"cast wallet remove --name <NAME>\")]\n    Remove {\n        /// The alias (or name) of the wallet to remove.\n        #[arg(long, required = true)]\n        name: String,\n        /// Optionally provide the keystore directory if not provided. default directory will be\n        /// used (~/.foundry/keystores).\n        #[arg(long)]\n        dir: Option<String>,\n        /// Password for the JSON keystore in cleartext\n        /// This is unsafe, we recommend using the default hidden password prompt\n        #[arg(long, env = \"CAST_UNSAFE_PASSWORD\", value_name = \"PASSWORD\")]\n        unsafe_password: Option<String>,\n    },\n\n    /// Derives private key from mnemonic\n    #[command(name = \"private-key\", visible_alias = \"pk\", aliases = &[\"derive-private-key\", \"--derive-private-key\"])]\n    PrivateKey {\n        /// If provided, the private key will be derived from the specified mnemonic phrase.\n        #[arg(value_name = \"MNEMONIC\")]\n        mnemonic_override: Option<String>,\n\n        /// If provided, the private key will be derived using the\n        /// specified mnemonic index (if integer) or derivation path.\n        #[arg(value_name = \"MNEMONIC_INDEX_OR_DERIVATION_PATH\")]\n        mnemonic_index_or_derivation_path_override: Option<String>,\n\n        #[command(flatten)]\n        wallet: WalletOpts,\n    },\n    /// Get the public key for the given private key.\n    #[command(visible_aliases = &[\"pubkey\"])]\n    PublicKey {\n        /// If provided, the public key will be derived from the specified private key.\n        #[arg(long = \"raw-private-key\", value_name = \"PRIVATE_KEY\")]\n        private_key_override: Option<String>,\n\n        #[command(flatten)]\n        wallet: WalletOpts,\n    },\n    /// Decrypt a keystore file to get the private key\n    #[command(name = \"decrypt-keystore\", visible_alias = \"dk\")]\n    DecryptKeystore {\n        /// The name for the account in the keystore.\n        #[arg(value_name = \"ACCOUNT_NAME\")]\n        account_name: String,\n        /// If not provided, keystore will try to be located at the default keystores directory\n        /// (~/.foundry/keystores)\n        #[arg(long, short)]\n        keystore_dir: Option<String>,\n        /// Password for the JSON keystore in cleartext\n        /// This is unsafe, we recommend using the default hidden password prompt\n        #[arg(long, env = \"CAST_UNSAFE_PASSWORD\", value_name = \"PASSWORD\")]\n        unsafe_password: Option<String>,\n    },\n\n    /// Change the password of a keystore file\n    #[command(name = \"change-password\", visible_alias = \"cp\")]\n    ChangePassword {\n        /// The name for the account in the keystore.\n        #[arg(value_name = \"ACCOUNT_NAME\")]\n        account_name: String,\n        /// If not provided, keystore will try to be located at the default keystores directory\n        /// (~/.foundry/keystores)\n        #[arg(long, short)]\n        keystore_dir: Option<String>,\n        /// Current password for the JSON keystore in cleartext\n        /// This is unsafe, we recommend using the default hidden password prompt\n        #[arg(long, env = \"CAST_UNSAFE_PASSWORD\", value_name = \"PASSWORD\")]\n        unsafe_password: Option<String>,\n        /// New password for the JSON keystore in cleartext\n        /// This is unsafe, we recommend using the default hidden password prompt\n        #[arg(long, env = \"CAST_UNSAFE_NEW_PASSWORD\", value_name = \"NEW_PASSWORD\")]\n        unsafe_new_password: Option<String>,\n    },\n}\n\nimpl WalletSubcommands {\n    pub async fn run(self) -> Result<()> {\n        match self {\n            Self::New { path, account_name, unsafe_password, number, password, force } => {\n                let mut rng = thread_rng();\n\n                let mut json_values = if shell::is_json() { Some(vec![]) } else { None };\n\n                let path = if let Some(path) = path {\n                    match dunce::canonicalize(&path) {\n                        Ok(path) => {\n                            if !path.is_dir() {\n                                // we require path to be an existing directory\n                                eyre::bail!(\"`{}` is not a directory\", path.display());\n                            }\n                            Some(path)\n                        }\n                        Err(e) => {\n                            eyre::bail!(\n                                \"If you specified a directory, please make sure it exists, or create it before running `cast wallet new <DIR>`.\\n{path} is not a directory.\\nError: {}\",\n                                e\n                            );\n                        }\n                    }\n                } else if unsafe_password.is_some() || password {\n                    let path = Config::foundry_keystores_dir().ok_or_else(|| {\n                        eyre::eyre!(\"Could not find the default keystore directory.\")\n                    })?;\n                    fs::create_dir_all(&path)?;\n                    Some(path)\n                } else {\n                    None\n                };\n\n                match path {\n                    Some(path) => {\n                        let password = if let Some(password) = unsafe_password {\n                            password\n                        } else {\n                            // if no --unsafe-password was provided read via stdin\n                            rpassword::prompt_password(\"Enter secret: \")?\n                        };\n\n                        // Prevent accidental overwriting: check all target files upfront\n                        if !force && let Some(ref acc_name) = account_name {\n                            let mut existing_files = Vec::new();\n\n                            for i in 0..number {\n                                let name = match number {\n                                    1 => acc_name.to_string(),\n                                    _ => format!(\"{}_{}\", acc_name, i + 1),\n                                };\n                                let file_path = path.join(&name);\n                                if file_path.exists() {\n                                    existing_files.push(name);\n                                }\n                            }\n\n                            if !existing_files.is_empty() {\n                                use std::io::Write;\n\n                                sh_eprintln!(\"The following keystore file(s) already exist:\")?;\n                                for file in &existing_files {\n                                    sh_eprintln!(\"   - {file}\")?;\n                                }\n                                sh_print!(\n                                    \"\\nDo you want to overwrite all {} file(s)? [y/N]: \",\n                                    existing_files.len()\n                                )?;\n                                std::io::stdout().flush()?;\n\n                                let mut input = String::new();\n                                std::io::stdin().read_line(&mut input)?;\n\n                                if !input.trim().eq_ignore_ascii_case(\"y\") {\n                                    eyre::bail!(\"Operation cancelled. No keystores were modified.\");\n                                }\n                            }\n                        }\n                        for i in 0..number {\n                            let account_name_ref =\n                                account_name.as_deref().map(|name| match number {\n                                    1 => name.to_string(),\n                                    _ => format!(\"{}_{}\", name, i + 1),\n                                });\n\n                            let (wallet, uuid) = PrivateKeySigner::new_keystore(\n                                &path,\n                                &mut rng,\n                                password.clone(),\n                                account_name_ref.as_deref(),\n                            )?;\n                            let identifier = account_name_ref.as_deref().unwrap_or(&uuid);\n\n                            if let Some(json) = json_values.as_mut() {\n                                json.push(if shell::verbosity() > 0 {\n                                json!({\n                                    \"address\": wallet.address().to_checksum(None),\n                                    \"public_key\": format!(\"0x{}\", hex::encode(wallet.public_key())),\n                                    \"path\": format!(\"{}\", path.join(identifier).display()),\n                                })\n                            } else {\n                                json!({\n                                    \"address\": wallet.address().to_checksum(None),\n                                    \"path\": format!(\"{}\", path.join(identifier).display()),\n                                })\n                            });\n                            } else {\n                                sh_println!(\n                                    \"Created new encrypted keystore file: {}\",\n                                    path.join(identifier).display()\n                                )?;\n                                sh_println!(\"Address:    {}\", wallet.address().to_checksum(None))?;\n                                if shell::verbosity() > 0 {\n                                    sh_println!(\n                                        \"Public key: 0x{}\",\n                                        hex::encode(wallet.public_key())\n                                    )?;\n                                }\n                            }\n                        }\n                    }\n                    None => {\n                        for _ in 0..number {\n                            let wallet = PrivateKeySigner::random_with(&mut rng);\n\n                            if let Some(json) = json_values.as_mut() {\n                                json.push(if shell::verbosity() > 0 {\n                                json!({\n                                    \"address\": wallet.address().to_checksum(None),\n                                    \"public_key\": format!(\"0x{}\", hex::encode(wallet.public_key())),\n                                    \"private_key\": format!(\"0x{}\", hex::encode(wallet.credential().to_bytes())),\n                                })\n                            } else {\n                                json!({\n                                    \"address\": wallet.address().to_checksum(None),\n                                    \"private_key\": format!(\"0x{}\", hex::encode(wallet.credential().to_bytes())),\n                                })\n                            });\n                            } else {\n                                sh_println!(\"Successfully created new keypair.\")?;\n                                sh_println!(\"Address:     {}\", wallet.address().to_checksum(None))?;\n                                if shell::verbosity() > 0 {\n                                    sh_println!(\n                                        \"Public key:  0x{}\",\n                                        hex::encode(wallet.public_key())\n                                    )?;\n                                }\n                                sh_println!(\n                                    \"Private key: 0x{}\",\n                                    hex::encode(wallet.credential().to_bytes())\n                                )?;\n                            }\n                        }\n                    }\n                }\n\n                if let Some(json) = json_values.as_ref() {\n                    sh_println!(\"{}\", serde_json::to_string_pretty(json)?)?;\n                }\n            }\n            Self::NewMnemonic { words, accounts, entropy } => {\n                let phrase = if let Some(entropy) = entropy {\n                    let entropy = Entropy::from_slice(hex::decode(entropy)?)?;\n                    Mnemonic::<English>::new_from_entropy(entropy).to_phrase()\n                } else {\n                    let mut rng = thread_rng();\n                    Mnemonic::<English>::new_with_count(&mut rng, words)?.to_phrase()\n                };\n\n                let format_json = shell::is_json();\n\n                if !format_json {\n                    sh_println!(\"{}\", \"Generating mnemonic from provided entropy...\".yellow())?;\n                }\n\n                let builder = MnemonicBuilder::<English>::default().phrase(phrase.as_str());\n                let derivation_path = \"m/44'/60'/0'/0/\";\n                let wallets = (0..accounts)\n                    .map(|i| builder.clone().derivation_path(format!(\"{derivation_path}{i}\")))\n                    .collect::<Result<Vec<_>, _>>()?;\n                let wallets =\n                    wallets.into_iter().map(|b| b.build()).collect::<Result<Vec<_>, _>>()?;\n\n                if !format_json {\n                    sh_println!(\"{}\", \"Successfully generated a new mnemonic.\".green())?;\n                    sh_println!(\"Phrase:\\n{phrase}\")?;\n                    sh_println!(\"\\nAccounts:\")?;\n                }\n\n                let mut accounts = json!([]);\n                for (i, wallet) in wallets.iter().enumerate() {\n                    let public_key = hex::encode(wallet.public_key());\n                    let private_key = hex::encode(wallet.credential().to_bytes());\n                    if format_json {\n                        accounts.as_array_mut().unwrap().push(if shell::verbosity() > 0 {\n                            json!({\n                                \"address\": format!(\"{}\", wallet.address()),\n                                \"public_key\": format!(\"0x{}\", public_key),\n                                \"private_key\": format!(\"0x{}\", private_key),\n                            })\n                        } else {\n                            json!({\n                                \"address\": format!(\"{}\", wallet.address()),\n                                \"private_key\": format!(\"0x{}\", private_key),\n                            })\n                        });\n                    } else {\n                        sh_println!(\"- Account {i}:\")?;\n                        sh_println!(\"Address:     {}\", wallet.address())?;\n                        if shell::verbosity() > 0 {\n                            sh_println!(\"Public key:  0x{}\", public_key)?;\n                        }\n                        sh_println!(\"Private key: 0x{}\\n\", private_key)?;\n                    }\n                }\n\n                if format_json {\n                    let obj = json!({\n                        \"mnemonic\": phrase,\n                        \"accounts\": accounts,\n                    });\n                    sh_println!(\"{}\", serde_json::to_string_pretty(&obj)?)?;\n                }\n            }\n            Self::Vanity(cmd) => {\n                cmd.run()?;\n            }\n            Self::Address { wallet, private_key_override } => {\n                let wallet = private_key_override\n                    .map(|pk| WalletOpts {\n                        raw: RawWalletOpts { private_key: Some(pk), ..Default::default() },\n                        ..Default::default()\n                    })\n                    .unwrap_or(wallet)\n                    .signer()\n                    .await?;\n                let addr = wallet.address();\n                sh_println!(\"{}\", addr.to_checksum(None))?;\n            }\n            Self::Derive { mnemonic, accounts, insecure } => {\n                let format_json = shell::is_json();\n                let mut accounts_json = json!([]);\n                for i in 0..accounts.unwrap_or(1) {\n                    let wallet = WalletOpts {\n                        raw: RawWalletOpts {\n                            mnemonic: Some(mnemonic.clone()),\n                            mnemonic_index: i as u32,\n                            ..Default::default()\n                        },\n                        ..Default::default()\n                    }\n                    .signer()\n                    .await?;\n\n                    match wallet {\n                        WalletSigner::Local(local_wallet) => {\n                            let address = local_wallet.address().to_checksum(None);\n                            let private_key = hex::encode(local_wallet.credential().to_bytes());\n                            if format_json {\n                                if insecure {\n                                    accounts_json.as_array_mut().unwrap().push(json!({\n                                        \"address\": format!(\"{}\", address),\n                                        \"private_key\": format!(\"0x{}\", private_key),\n                                    }));\n                                } else {\n                                    accounts_json.as_array_mut().unwrap().push(json!({\n                                        \"address\": format!(\"{}\", address)\n                                    }));\n                                }\n                            } else {\n                                sh_println!(\"- Account {i}:\")?;\n                                if insecure {\n                                    sh_println!(\"Address:     {}\", address)?;\n                                    sh_println!(\"Private key: 0x{}\\n\", private_key)?;\n                                } else {\n                                    sh_println!(\"Address:     {}\\n\", address)?;\n                                }\n                            }\n                        }\n                        _ => eyre::bail!(\"Only local wallets are supported by this command\"),\n                    }\n                }\n\n                if format_json {\n                    sh_println!(\"{}\", serde_json::to_string_pretty(&accounts_json)?)?;\n                }\n            }\n            Self::PublicKey { wallet, private_key_override } => {\n                let wallet = private_key_override\n                    .map(|pk| WalletOpts {\n                        raw: RawWalletOpts { private_key: Some(pk), ..Default::default() },\n                        ..Default::default()\n                    })\n                    .unwrap_or(wallet)\n                    .signer()\n                    .await?;\n\n                let public_key = match wallet {\n                    WalletSigner::Local(wallet) => wallet.public_key(),\n                    _ => eyre::bail!(\"Only local wallets are supported by this command\"),\n                };\n\n                sh_println!(\"0x{}\", hex::encode(public_key))?;\n            }\n            Self::Sign { message, data, from_file, no_hash, wallet } => {\n                let wallet = wallet.signer().await?;\n                let sig = if data {\n                    let typed_data: TypedData = if from_file {\n                        // data is a file name, read json from file\n                        foundry_common::fs::read_json_file(message.as_ref())?\n                    } else {\n                        // data is a json string\n                        serde_json::from_str(&message)?\n                    };\n                    wallet.sign_dynamic_typed_data(&typed_data).await?\n                } else if no_hash {\n                    wallet.sign_hash(&hex::decode(&message)?[..].try_into()?).await?\n                } else {\n                    wallet.sign_message(&Self::hex_str_to_bytes(&message)?).await?\n                };\n\n                if shell::verbosity() > 0 {\n                    if shell::is_json() {\n                        sh_println!(\n                            \"{}\",\n                            serde_json::to_string_pretty(&json!({\n                                \"message\": message,\n                                \"address\": wallet.address(),\n                                \"signature\": hex::encode(sig.as_bytes()),\n                            }))?\n                        )?;\n                    } else {\n                        sh_println!(\n                            \"Successfully signed!\\n   Message: {}\\n   Address: {}\\n   Signature: 0x{}\",\n                            message,\n                            wallet.address(),\n                            hex::encode(sig.as_bytes()),\n                        )?;\n                    }\n                } else {\n                    // Pipe friendly output\n                    sh_println!(\"0x{}\", hex::encode(sig.as_bytes()))?;\n                }\n            }\n            Self::SignAuth { rpc, nonce, chain, wallet, address, self_broadcast } => {\n                let wallet = wallet.signer().await?;\n                let provider = utils::get_provider(&rpc.load_config()?)?;\n                let nonce = if let Some(nonce) = nonce {\n                    nonce\n                } else {\n                    let current_nonce = provider.get_transaction_count(wallet.address()).await?;\n                    if self_broadcast {\n                        // When self-broadcasting, the authorization nonce needs to be +1\n                        // because the transaction itself will consume the current nonce\n                        current_nonce + 1\n                    } else {\n                        current_nonce\n                    }\n                };\n                let chain_id = if let Some(chain) = chain {\n                    chain.id()\n                } else {\n                    provider.get_chain_id().await?\n                };\n                let auth = Authorization { chain_id: U256::from(chain_id), address, nonce };\n                let signature = wallet.sign_hash(&auth.signature_hash()).await?;\n                let auth = auth.into_signed(signature);\n\n                if shell::verbosity() > 0 {\n                    if shell::is_json() {\n                        sh_println!(\n                            \"{}\",\n                            serde_json::to_string_pretty(&json!({\n                                \"nonce\": nonce,\n                                \"chain_id\": chain_id,\n                                \"address\": wallet.address(),\n                                \"signature\": hex::encode_prefixed(alloy_rlp::encode(&auth)),\n                            }))?\n                        )?;\n                    } else {\n                        sh_println!(\n                            \"Successfully signed!\\n   Nonce: {}\\n   Chain ID: {}\\n   Address: {}\\n   Signature: 0x{}\",\n                            nonce,\n                            chain_id,\n                            wallet.address(),\n                            hex::encode_prefixed(alloy_rlp::encode(&auth)),\n                        )?;\n                    }\n                } else {\n                    // Pipe friendly output\n                    sh_println!(\"{}\", hex::encode_prefixed(alloy_rlp::encode(&auth)))?;\n                }\n            }\n            Self::Verify { message, signature, address, data, from_file, no_hash } => {\n                let recovered_address = if data {\n                    let typed_data: TypedData = if from_file {\n                        // data is a file name, read json from file\n                        foundry_common::fs::read_json_file(message.as_ref())?\n                    } else {\n                        // data is a json string\n                        serde_json::from_str(&message)?\n                    };\n                    Self::recover_address_from_typed_data(&typed_data, &signature)?\n                } else if no_hash {\n                    Self::recover_address_from_message_no_hash(\n                        &hex::decode(&message)?[..].try_into()?,\n                        &signature,\n                    )?\n                } else {\n                    Self::recover_address_from_message(&message, &signature)?\n                };\n\n                if address == recovered_address {\n                    sh_println!(\"Validation succeeded. Address {address} signed this message.\")?;\n                } else {\n                    eyre::bail!(\"Validation failed. Address {address} did not sign this message.\");\n                }\n            }\n            Self::Import { account_name, keystore_dir, unsafe_password, raw_wallet_options } => {\n                // Set up keystore directory\n                let dir = if let Some(path) = keystore_dir {\n                    Path::new(&path).to_path_buf()\n                } else {\n                    Config::foundry_keystores_dir().ok_or_else(|| {\n                        eyre::eyre!(\"Could not find the default keystore directory.\")\n                    })?\n                };\n\n                fs::create_dir_all(&dir)?;\n\n                // check if account exists already\n                let keystore_path = Path::new(&dir).join(&account_name);\n                if keystore_path.exists() {\n                    eyre::bail!(\"Keystore file already exists at {}\", keystore_path.display());\n                }\n\n                // get wallet\n                let wallet = raw_wallet_options\n                    .signer()?\n                    .and_then(|s| match s {\n                        WalletSigner::Local(s) => Some(s),\n                        _ => None,\n                    })\n                    .ok_or_else(|| {\n                        eyre::eyre!(\n                            \"\\\nDid you set a private key or mnemonic?\nRun `cast wallet import --help` and use the corresponding CLI\nflag to set your key via:\n--private-key, --mnemonic-path or --interactive.\"\n                        )\n                    })?;\n\n                let private_key = wallet.credential().to_bytes();\n                let password = if let Some(password) = unsafe_password {\n                    password\n                } else {\n                    // if no --unsafe-password was provided read via stdin\n                    rpassword::prompt_password(\"Enter password: \")?\n                };\n\n                let mut rng = thread_rng();\n                let (wallet, _) = PrivateKeySigner::encrypt_keystore(\n                    dir,\n                    &mut rng,\n                    private_key,\n                    password,\n                    Some(&account_name),\n                )?;\n                let address = wallet.address();\n                let success_message = format!(\n                    \"`{}` keystore was saved successfully. Address: {:?}\",\n                    &account_name, address,\n                );\n                sh_println!(\"{}\", success_message.green())?;\n            }\n            Self::List(cmd) => {\n                cmd.run().await?;\n            }\n            Self::Remove { name, dir, unsafe_password } => {\n                let dir = if let Some(path) = dir {\n                    Path::new(&path).to_path_buf()\n                } else {\n                    Config::foundry_keystores_dir().ok_or_else(|| {\n                        eyre::eyre!(\"Could not find the default keystore directory.\")\n                    })?\n                };\n\n                let keystore_path = Path::new(&dir).join(&name);\n                if !keystore_path.exists() {\n                    eyre::bail!(\"Keystore file does not exist at {}\", keystore_path.display());\n                }\n\n                let password = if let Some(pwd) = unsafe_password {\n                    pwd\n                } else {\n                    rpassword::prompt_password(\"Enter password: \")?\n                };\n\n                if PrivateKeySigner::decrypt_keystore(&keystore_path, password).is_err() {\n                    eyre::bail!(\"Invalid password - wallet removal cancelled\");\n                }\n\n                std::fs::remove_file(&keystore_path).wrap_err_with(|| {\n                    format!(\"Failed to remove keystore file at {}\", keystore_path.display())\n                })?;\n\n                let success_message = format!(\"`{}` keystore was removed successfully.\", &name);\n                sh_println!(\"{}\", success_message.green())?;\n            }\n            Self::PrivateKey {\n                wallet,\n                mnemonic_override,\n                mnemonic_index_or_derivation_path_override,\n            } => {\n                let (index_override, derivation_path_override) =\n                    match mnemonic_index_or_derivation_path_override {\n                        Some(value) => match value.parse::<u32>() {\n                            Ok(index) => (Some(index), None),\n                            Err(_) => (None, Some(value)),\n                        },\n                        None => (None, None),\n                    };\n                let wallet = WalletOpts {\n                    raw: RawWalletOpts {\n                        mnemonic: mnemonic_override.or(wallet.raw.mnemonic),\n                        mnemonic_index: index_override.unwrap_or(wallet.raw.mnemonic_index),\n                        hd_path: derivation_path_override.or(wallet.raw.hd_path),\n                        ..wallet.raw\n                    },\n                    ..wallet\n                }\n                .signer()\n                .await?;\n                match wallet {\n                    WalletSigner::Local(wallet) => {\n                        if shell::verbosity() > 0 {\n                            sh_println!(\"Address:     {}\", wallet.address())?;\n                            sh_println!(\n                                \"Private key: 0x{}\",\n                                hex::encode(wallet.credential().to_bytes())\n                            )?;\n                        } else {\n                            sh_println!(\"0x{}\", hex::encode(wallet.credential().to_bytes()))?;\n                        }\n                    }\n                    _ => {\n                        eyre::bail!(\"Only local wallets are supported by this command.\");\n                    }\n                }\n            }\n            Self::DecryptKeystore { account_name, keystore_dir, unsafe_password } => {\n                // Set up keystore directory\n                let dir = if let Some(path) = keystore_dir {\n                    Path::new(&path).to_path_buf()\n                } else {\n                    Config::foundry_keystores_dir().ok_or_else(|| {\n                        eyre::eyre!(\"Could not find the default keystore directory.\")\n                    })?\n                };\n\n                let keypath = dir.join(&account_name);\n\n                if !keypath.exists() {\n                    eyre::bail!(\"Keystore file does not exist at {}\", keypath.display());\n                }\n\n                let password = if let Some(password) = unsafe_password {\n                    password\n                } else {\n                    // if no --unsafe-password was provided read via stdin\n                    rpassword::prompt_password(\"Enter password: \")?\n                };\n\n                let wallet = PrivateKeySigner::decrypt_keystore(keypath, password)?;\n\n                let private_key = B256::from_slice(&wallet.credential().to_bytes());\n\n                let success_message =\n                    format!(\"{}'s private key is: {}\", &account_name, private_key);\n\n                sh_println!(\"{}\", success_message.green())?;\n            }\n            Self::ChangePassword {\n                account_name,\n                keystore_dir,\n                unsafe_password,\n                unsafe_new_password,\n            } => {\n                // Set up keystore directory\n                let dir = if let Some(path) = keystore_dir {\n                    Path::new(&path).to_path_buf()\n                } else {\n                    Config::foundry_keystores_dir().ok_or_else(|| {\n                        eyre::eyre!(\"Could not find the default keystore directory.\")\n                    })?\n                };\n\n                let keypath = dir.join(&account_name);\n\n                if !keypath.exists() {\n                    eyre::bail!(\"Keystore file does not exist at {}\", keypath.display());\n                }\n\n                let current_password = if let Some(password) = unsafe_password {\n                    password\n                } else {\n                    // if no --unsafe-password was provided read via stdin\n                    rpassword::prompt_password(\"Enter current password: \")?\n                };\n\n                // decrypt the keystore to verify the current password and get the private key\n                let wallet = PrivateKeySigner::decrypt_keystore(&keypath, current_password.clone())\n                    .map_err(|_| eyre::eyre!(\"Invalid password - password change cancelled\"))?;\n\n                let new_password = if let Some(password) = unsafe_new_password {\n                    password\n                } else {\n                    // if no --unsafe-new-password was provided read via stdin\n                    rpassword::prompt_password(\"Enter new password: \")?\n                };\n\n                if current_password == new_password {\n                    eyre::bail!(\"New password cannot be the same as the current password\");\n                }\n\n                // Create a new keystore with the new password\n                let private_key = wallet.credential().to_bytes();\n                let mut rng = thread_rng();\n                let (wallet, _) = PrivateKeySigner::encrypt_keystore(\n                    dir,\n                    &mut rng,\n                    private_key,\n                    new_password,\n                    Some(&account_name),\n                )?;\n\n                let success_message = format!(\n                    \"Password for keystore `{}` was changed successfully. Address: {:?}\",\n                    &account_name,\n                    wallet.address(),\n                );\n                sh_println!(\"{}\", success_message.green())?;\n            }\n        };\n\n        Ok(())\n    }\n\n    /// Recovers an address from the specified message and signature.\n    ///\n    /// Note: This attempts to decode the message as hex if it starts with 0x.\n    fn recover_address_from_message(message: &str, signature: &Signature) -> Result<Address> {\n        let message = Self::hex_str_to_bytes(message)?;\n        Ok(signature.recover_address_from_msg(message)?)\n    }\n\n    /// Recovers an address from the specified message and signature.\n    fn recover_address_from_message_no_hash(\n        prehash: &B256,\n        signature: &Signature,\n    ) -> Result<Address> {\n        Ok(signature.recover_address_from_prehash(prehash)?)\n    }\n\n    /// Recovers an address from the specified EIP-712 typed data and signature.\n    fn recover_address_from_typed_data(\n        typed_data: &TypedData,\n        signature: &Signature,\n    ) -> Result<Address> {\n        Ok(signature.recover_address_from_prehash(&typed_data.eip712_signing_hash()?)?)\n    }\n\n    /// Strips the 0x prefix from a hex string and decodes it to bytes.\n    ///\n    /// Treats the string as raw bytes if it doesn't start with 0x.\n    fn hex_str_to_bytes(s: &str) -> Result<Vec<u8>> {\n        Ok(match s.strip_prefix(\"0x\") {\n            Some(data) => hex::decode(data).wrap_err(\"Could not decode 0x-prefixed string.\")?,\n            None => s.as_bytes().to_vec(),\n        })\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use alloy_primitives::{address, keccak256};\n    use std::str::FromStr;\n\n    #[test]\n    fn can_parse_wallet_sign_message() {\n        let args = WalletSubcommands::parse_from([\"foundry-cli\", \"sign\", \"deadbeef\"]);\n        match args {\n            WalletSubcommands::Sign { message, data, from_file, .. } => {\n                assert_eq!(message, \"deadbeef\".to_string());\n                assert!(!data);\n                assert!(!from_file);\n            }\n            _ => panic!(\"expected WalletSubcommands::Sign\"),\n        }\n    }\n\n    #[test]\n    fn can_parse_wallet_sign_hex_message() {\n        let args = WalletSubcommands::parse_from([\"foundry-cli\", \"sign\", \"0xdeadbeef\"]);\n        match args {\n            WalletSubcommands::Sign { message, data, from_file, .. } => {\n                assert_eq!(message, \"0xdeadbeef\".to_string());\n                assert!(!data);\n                assert!(!from_file);\n            }\n            _ => panic!(\"expected WalletSubcommands::Sign\"),\n        }\n    }\n\n    #[test]\n    fn can_verify_signed_hex_message() {\n        let message = \"hello\";\n        let signature = Signature::from_str(\"f2dd00eac33840c04b6fc8a5ec8c4a47eff63575c2bc7312ecb269383de0c668045309c423484c8d097df306e690c653f8e1ec92f7f6f45d1f517027771c3e801c\").unwrap();\n        let address = address!(\"0x28A4F420a619974a2393365BCe5a7b560078Cc13\");\n        let recovered_address =\n            WalletSubcommands::recover_address_from_message(message, &signature);\n        assert!(recovered_address.is_ok());\n        assert_eq!(address, recovered_address.unwrap());\n    }\n\n    #[test]\n    fn can_verify_signed_hex_message_no_hash() {\n        let prehash = keccak256(\"hello\");\n        let signature = Signature::from_str(\"433ec3d37e4f1253df15e2dea412fed8e915737730f74b3dfb1353268f932ef5557c9158e0b34bce39de28d11797b42e9b1acb2749230885fe075aedc3e491a41b\").unwrap();\n        let address = address!(\"0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf\"); // private key = 1\n        let recovered_address =\n            WalletSubcommands::recover_address_from_message_no_hash(&prehash, &signature);\n        assert!(recovered_address.is_ok());\n        assert_eq!(address, recovered_address.unwrap());\n    }\n\n    #[test]\n    fn can_verify_signed_typed_data() {\n        let typed_data: TypedData = serde_json::from_str(r#\"{\"domain\":{\"name\":\"Test\",\"version\":\"1\",\"chainId\":1,\"verifyingContract\":\"0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF\"},\"message\":{\"value\":123},\"primaryType\":\"Data\",\"types\":{\"Data\":[{\"name\":\"value\",\"type\":\"uint256\"}]}}\"#).unwrap();\n        let signature = Signature::from_str(\"0285ff83b93bd01c14e201943af7454fe2bc6c98be707a73888c397d6ae3b0b92f73ca559f81cbb19fe4e0f1dc4105bd7b647c6a84b033057977cf2ec982daf71b\").unwrap();\n        let address = address!(\"0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf\"); // private key = 1\n        let recovered_address =\n            WalletSubcommands::recover_address_from_typed_data(&typed_data, &signature);\n        assert!(recovered_address.is_ok());\n        assert_eq!(address, recovered_address.unwrap());\n    }\n\n    #[test]\n    fn can_parse_wallet_sign_data() {\n        let args = WalletSubcommands::parse_from([\"foundry-cli\", \"sign\", \"--data\", \"{ ... }\"]);\n        match args {\n            WalletSubcommands::Sign { message, data, from_file, .. } => {\n                assert_eq!(message, \"{ ... }\".to_string());\n                assert!(data);\n                assert!(!from_file);\n            }\n            _ => panic!(\"expected WalletSubcommands::Sign\"),\n        }\n    }\n\n    #[test]\n    fn can_parse_wallet_sign_data_file() {\n        let args = WalletSubcommands::parse_from([\n            \"foundry-cli\",\n            \"sign\",\n            \"--data\",\n            \"--from-file\",\n            \"tests/data/typed_data.json\",\n        ]);\n        match args {\n            WalletSubcommands::Sign { message, data, from_file, .. } => {\n                assert_eq!(message, \"tests/data/typed_data.json\".to_string());\n                assert!(data);\n                assert!(from_file);\n            }\n            _ => panic!(\"expected WalletSubcommands::Sign\"),\n        }\n    }\n\n    #[test]\n    fn can_parse_wallet_change_password() {\n        let args = WalletSubcommands::parse_from([\n            \"foundry-cli\",\n            \"change-password\",\n            \"my_account\",\n            \"--unsafe-password\",\n            \"old_password\",\n            \"--unsafe-new-password\",\n            \"new_password\",\n        ]);\n        match args {\n            WalletSubcommands::ChangePassword {\n                account_name,\n                keystore_dir,\n                unsafe_password,\n                unsafe_new_password,\n            } => {\n                assert_eq!(account_name, \"my_account\".to_string());\n                assert_eq!(unsafe_password, Some(\"old_password\".to_string()));\n                assert_eq!(unsafe_new_password, Some(\"new_password\".to_string()));\n                assert!(keystore_dir.is_none());\n            }\n            _ => panic!(\"expected WalletSubcommands::ChangePassword\"),\n        }\n    }\n\n    #[test]\n    fn wallet_sign_auth_nonce_and_self_broadcast_conflict() {\n        let result = WalletSubcommands::try_parse_from([\n            \"foundry-cli\",\n            \"sign-auth\",\n            \"0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF\",\n            \"--nonce\",\n            \"42\",\n            \"--self-broadcast\",\n        ]);\n        assert!(\n            result.is_err(),\n            \"expected error when both --nonce and --self-broadcast are provided\"\n        );\n    }\n}\n"
  },
  {
    "path": "crates/cast/src/cmd/wallet/vanity.rs",
    "content": "use alloy_primitives::{Address, hex};\nuse alloy_signer::{k256::ecdsa::SigningKey, utils::secret_key_to_address};\nuse alloy_signer_local::PrivateKeySigner;\nuse clap::Parser;\nuse eyre::Result;\nuse foundry_common::sh_println;\nuse itertools::Either;\nuse rayon::iter::{self, ParallelIterator};\nuse regex::Regex;\nuse serde::{Deserialize, Serialize};\nuse std::{\n    fs,\n    path::{Path, PathBuf},\n    time::Instant,\n};\n\n/// Type alias for the result of [generate_wallet].\npub type GeneratedWallet = (SigningKey, Address);\n\n/// CLI arguments for `cast wallet vanity`.\n#[derive(Clone, Debug, Parser)]\npub struct VanityArgs {\n    /// Prefix regex pattern or hex string.\n    #[arg(long, value_name = \"PATTERN\", required_unless_present = \"ends_with\")]\n    pub starts_with: Option<String>,\n\n    /// Suffix regex pattern or hex string.\n    #[arg(long, value_name = \"PATTERN\")]\n    pub ends_with: Option<String>,\n\n    // 2^64-1 is max possible nonce per [eip-2681](https://eips.ethereum.org/EIPS/eip-2681).\n    /// Generate a vanity contract address created by the generated keypair with the specified\n    /// nonce.\n    #[arg(long)]\n    pub nonce: Option<u64>,\n\n    /// Path to save the generated vanity contract address to.\n    ///\n    /// If provided, the generated vanity addresses will appended to a JSON array in the specified\n    /// file.\n    #[arg(\n        long,\n        value_hint = clap::ValueHint::FilePath,\n        value_name = \"PATH\",\n    )]\n    pub save_path: Option<PathBuf>,\n}\n\n/// WalletData contains address and private_key information for a wallet.\n#[derive(Serialize, Deserialize)]\nstruct WalletData {\n    address: String,\n    private_key: String,\n}\n\n/// Wallets is a collection of WalletData.\n#[derive(Default, Serialize, Deserialize)]\nstruct Wallets {\n    wallets: Vec<WalletData>,\n}\n\nimpl WalletData {\n    pub fn new(wallet: &PrivateKeySigner) -> Self {\n        Self {\n            address: wallet.address().to_checksum(None),\n            private_key: format!(\"0x{}\", hex::encode(wallet.credential().to_bytes())),\n        }\n    }\n}\n\nimpl VanityArgs {\n    pub fn run(self) -> Result<PrivateKeySigner> {\n        let Self { starts_with, ends_with, nonce, save_path } = self;\n\n        let mut left_exact_hex = None;\n        let mut left_regex = None;\n        if let Some(prefix) = starts_with {\n            match parse_pattern(&prefix, true)? {\n                Either::Left(left) => left_exact_hex = Some(left),\n                Either::Right(re) => left_regex = Some(re),\n            }\n        }\n\n        let mut right_exact_hex = None;\n        let mut right_regex = None;\n        if let Some(suffix) = ends_with {\n            match parse_pattern(&suffix, false)? {\n                Either::Left(right) => right_exact_hex = Some(right),\n                Either::Right(re) => right_regex = Some(re),\n            }\n        }\n\n        macro_rules! find_vanity {\n            ($m:ident, $nonce:ident) => {\n                if let Some(nonce) = $nonce {\n                    find_vanity_address_with_nonce($m, nonce)\n                } else {\n                    find_vanity_address($m)\n                }\n            };\n        }\n\n        sh_println!(\"Starting to generate vanity address...\")?;\n        let timer = Instant::now();\n\n        let wallet = match (left_exact_hex, left_regex, right_exact_hex, right_regex) {\n            (Some(left), _, Some(right), _) => {\n                let matcher = HexMatcher { left, right };\n                find_vanity!(matcher, nonce)\n            }\n            (Some(left), _, _, Some(right)) => {\n                let matcher = LeftExactRightRegexMatcher { left, right };\n                find_vanity!(matcher, nonce)\n            }\n            (_, Some(left), _, Some(right)) => {\n                let matcher = RegexMatcher { left, right };\n                find_vanity!(matcher, nonce)\n            }\n            (_, Some(left), Some(right), _) => {\n                let matcher = LeftRegexRightExactMatcher { left, right };\n                find_vanity!(matcher, nonce)\n            }\n            (Some(left), None, None, None) => {\n                let matcher = LeftHexMatcher { left };\n                find_vanity!(matcher, nonce)\n            }\n            (None, None, Some(right), None) => {\n                let matcher = RightHexMatcher { right };\n                find_vanity!(matcher, nonce)\n            }\n            (None, Some(re), None, None) => {\n                let matcher = SingleRegexMatcher { re };\n                find_vanity!(matcher, nonce)\n            }\n            (None, None, None, Some(re)) => {\n                let matcher = SingleRegexMatcher { re };\n                find_vanity!(matcher, nonce)\n            }\n            _ => unreachable!(),\n        }\n        .expect(\"failed to generate vanity wallet\");\n\n        // If a save path is provided, save the generated vanity wallet to the specified path.\n        if let Some(save_path) = save_path {\n            save_wallet_to_file(&wallet, &save_path)?;\n        }\n\n        sh_println!(\n            \"Successfully found vanity address in {:.3} seconds.{}{}\\nAddress: {}\\nPrivate Key: 0x{}\",\n            timer.elapsed().as_secs_f64(),\n            if nonce.is_some() { \"\\nContract address: \" } else { \"\" },\n            if let Some(nonce_val) = nonce {\n                wallet.address().create(nonce_val).to_checksum(None)\n            } else {\n                String::new()\n            },\n            wallet.address().to_checksum(None),\n            hex::encode(wallet.credential().to_bytes()),\n        )?;\n\n        Ok(wallet)\n    }\n}\n\n/// Saves the specified `wallet` to a 'vanity_addresses.json' file at the given `save_path`.\n/// If the file exists, the wallet data is appended to the existing content;\n/// otherwise, a new file is created.\nfn save_wallet_to_file(wallet: &PrivateKeySigner, path: &Path) -> Result<()> {\n    let mut wallets = if path.exists() {\n        let data = fs::read_to_string(path)?;\n        serde_json::from_str::<Wallets>(&data).unwrap_or_default()\n    } else {\n        Wallets::default()\n    };\n\n    wallets.wallets.push(WalletData::new(wallet));\n\n    fs::write(path, serde_json::to_string_pretty(&wallets)?)?;\n    Ok(())\n}\n\n/// Generates random wallets until `matcher` matches the wallet address, returning the wallet.\npub fn find_vanity_address<T: VanityMatcher>(matcher: T) -> Option<PrivateKeySigner> {\n    wallet_generator().find_any(create_matcher(matcher)).map(|(key, _)| key.into())\n}\n\n/// Generates random wallets until `matcher` matches the contract address created at `nonce`,\n/// returning the wallet.\npub fn find_vanity_address_with_nonce<T: VanityMatcher>(\n    matcher: T,\n    nonce: u64,\n) -> Option<PrivateKeySigner> {\n    wallet_generator().find_any(create_nonce_matcher(matcher, nonce)).map(|(key, _)| key.into())\n}\n\n/// Creates a matcher function, which takes a reference to a [GeneratedWallet] and returns\n/// whether it found a match or not by using `matcher`.\n#[inline]\npub fn create_matcher<T: VanityMatcher>(matcher: T) -> impl Fn(&GeneratedWallet) -> bool {\n    move |(_, addr)| matcher.is_match(addr)\n}\n\n/// Creates a contract address matcher function that uses the specified nonce.\n/// The returned function takes a reference to a [GeneratedWallet] and returns\n/// whether the contract address created with the nonce matches using `matcher`.\n#[inline]\npub fn create_nonce_matcher<T: VanityMatcher>(\n    matcher: T,\n    nonce: u64,\n) -> impl Fn(&GeneratedWallet) -> bool {\n    move |(_, addr)| {\n        let contract_addr = addr.create(nonce);\n        matcher.is_match(&contract_addr)\n    }\n}\n\n/// Returns an infinite parallel iterator which yields a [GeneratedWallet].\n#[inline]\npub fn wallet_generator() -> iter::Map<iter::Repeat<()>, impl Fn(()) -> GeneratedWallet> {\n    iter::repeat(()).map(|()| generate_wallet())\n}\n\n/// Generates a random K-256 signing key and derives its Ethereum address.\npub fn generate_wallet() -> GeneratedWallet {\n    let key = SigningKey::random(&mut rand_08::thread_rng());\n    let address = secret_key_to_address(&key);\n    (key, address)\n}\n\n/// A trait to match vanity addresses.\npub trait VanityMatcher: Send + Sync {\n    fn is_match(&self, addr: &Address) -> bool;\n}\n\n/// Matches start and end hex.\npub struct HexMatcher {\n    pub left: Vec<u8>,\n    pub right: Vec<u8>,\n}\n\nimpl VanityMatcher for HexMatcher {\n    #[inline]\n    fn is_match(&self, addr: &Address) -> bool {\n        let bytes = addr.as_slice();\n        bytes.starts_with(&self.left) && bytes.ends_with(&self.right)\n    }\n}\n\n/// Matches only start hex.\npub struct LeftHexMatcher {\n    pub left: Vec<u8>,\n}\n\nimpl VanityMatcher for LeftHexMatcher {\n    #[inline]\n    fn is_match(&self, addr: &Address) -> bool {\n        let bytes = addr.as_slice();\n        bytes.starts_with(&self.left)\n    }\n}\n\n/// Matches only end hex.\npub struct RightHexMatcher {\n    pub right: Vec<u8>,\n}\n\nimpl VanityMatcher for RightHexMatcher {\n    #[inline]\n    fn is_match(&self, addr: &Address) -> bool {\n        let bytes = addr.as_slice();\n        bytes.ends_with(&self.right)\n    }\n}\n\n/// Matches start hex and end regex.\npub struct LeftExactRightRegexMatcher {\n    pub left: Vec<u8>,\n    pub right: Regex,\n}\n\nimpl VanityMatcher for LeftExactRightRegexMatcher {\n    #[inline]\n    fn is_match(&self, addr: &Address) -> bool {\n        let bytes = addr.as_slice();\n        bytes.starts_with(&self.left) && self.right.is_match(&hex::encode(bytes))\n    }\n}\n\n/// Matches start regex and end hex.\npub struct LeftRegexRightExactMatcher {\n    pub left: Regex,\n    pub right: Vec<u8>,\n}\n\nimpl VanityMatcher for LeftRegexRightExactMatcher {\n    #[inline]\n    fn is_match(&self, addr: &Address) -> bool {\n        let bytes = addr.as_slice();\n        bytes.ends_with(&self.right) && self.left.is_match(&hex::encode(bytes))\n    }\n}\n\n/// Matches a single regex.\npub struct SingleRegexMatcher {\n    pub re: Regex,\n}\n\nimpl VanityMatcher for SingleRegexMatcher {\n    #[inline]\n    fn is_match(&self, addr: &Address) -> bool {\n        let addr = hex::encode(addr);\n        self.re.is_match(&addr)\n    }\n}\n\n/// Matches start and end regex.\npub struct RegexMatcher {\n    pub left: Regex,\n    pub right: Regex,\n}\n\nimpl VanityMatcher for RegexMatcher {\n    #[inline]\n    fn is_match(&self, addr: &Address) -> bool {\n        let addr = hex::encode(addr);\n        self.left.is_match(&addr) && self.right.is_match(&addr)\n    }\n}\n\nfn parse_pattern(pattern: &str, is_start: bool) -> Result<Either<Vec<u8>, Regex>> {\n    if let Ok(decoded) = hex::decode(pattern) {\n        if decoded.len() > 20 {\n            return Err(eyre::eyre!(\"Hex pattern must be less than 20 bytes\"));\n        }\n        Ok(Either::Left(decoded))\n    } else {\n        let (prefix, suffix) = if is_start { (\"^\", \"\") } else { (\"\", \"$\") };\n        Ok(Either::Right(Regex::new(&format!(\"{prefix}{pattern}{suffix}\"))?))\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn find_simple_vanity_start() {\n        let args: VanityArgs = VanityArgs::parse_from([\"foundry-cli\", \"--starts-with\", \"00\"]);\n        let wallet = args.run().unwrap();\n        let addr = wallet.address();\n        let addr = format!(\"{addr:x}\");\n        assert!(addr.starts_with(\"00\"));\n    }\n\n    #[test]\n    fn find_simple_vanity_start2() {\n        let args: VanityArgs = VanityArgs::parse_from([\"foundry-cli\", \"--starts-with\", \"9\"]);\n        let wallet = args.run().unwrap();\n        let addr = wallet.address();\n        let addr = format!(\"{addr:x}\");\n        assert!(addr.starts_with('9'));\n    }\n\n    #[test]\n    fn find_simple_vanity_end() {\n        let args: VanityArgs = VanityArgs::parse_from([\"foundry-cli\", \"--ends-with\", \"00\"]);\n        let wallet = args.run().unwrap();\n        let addr = wallet.address();\n        let addr = format!(\"{addr:x}\");\n        assert!(addr.ends_with(\"00\"));\n    }\n\n    #[test]\n    fn save_path() {\n        let tmp = tempfile::NamedTempFile::new().unwrap();\n        let args: VanityArgs = VanityArgs::parse_from([\n            \"foundry-cli\",\n            \"--starts-with\",\n            \"00\",\n            \"--save-path\",\n            tmp.path().to_str().unwrap(),\n        ]);\n        args.run().unwrap();\n        assert!(tmp.path().exists());\n        let s = fs::read_to_string(tmp.path()).unwrap();\n        let wallets: Wallets = serde_json::from_str(&s).unwrap();\n        assert!(!wallets.wallets.is_empty());\n    }\n}\n"
  },
  {
    "path": "crates/cast/src/debug.rs",
    "content": "use std::str::FromStr;\n\nuse alloy_chains::Chain;\nuse alloy_primitives::{Address, Bytes, map::HashMap};\nuse foundry_cli::utils::{TraceResult, print_traces};\nuse foundry_common::{ContractsByArtifact, compile::ProjectCompiler, shell};\nuse foundry_config::Config;\nuse foundry_debugger::Debugger;\nuse foundry_evm::traces::{\n    CallTraceDecoderBuilder, DebugTraceIdentifier,\n    debug::ContractSources,\n    identifier::{SignaturesIdentifier, TraceIdentifiers},\n};\n\n/// labels the traces, conditionally prints them or opens the debugger\n#[expect(clippy::too_many_arguments)]\npub(crate) async fn handle_traces(\n    mut result: TraceResult,\n    config: &Config,\n    chain: Chain,\n    contracts_bytecode: &HashMap<Address, Bytes>,\n    labels: Vec<String>,\n    with_local_artifacts: bool,\n    debug: bool,\n    decode_internal: bool,\n    disable_label: bool,\n    trace_depth: Option<usize>,\n) -> eyre::Result<()> {\n    let (known_contracts, mut sources) = if with_local_artifacts {\n        let _ = sh_println!(\"Compiling project to generate artifacts\");\n        let project = config.project()?;\n        let compiler = ProjectCompiler::new();\n        let output = compiler.compile(&project)?;\n        (\n            Some(ContractsByArtifact::new(\n                output.artifact_ids().map(|(id, artifact)| (id, artifact.clone().into())),\n            )),\n            ContractSources::from_project_output(&output, project.root(), None)?,\n        )\n    } else {\n        (None, ContractSources::default())\n    };\n\n    let labels = labels.iter().filter_map(|label_str| {\n        let mut iter = label_str.split(':');\n\n        if let Some(addr) = iter.next()\n            && let (Ok(address), Some(label)) = (Address::from_str(addr), iter.next())\n        {\n            return Some((address, label.to_string()));\n        }\n        None\n    });\n    let config_labels = config.labels.clone().into_iter();\n\n    let mut builder = CallTraceDecoderBuilder::new()\n        .with_labels(labels.chain(config_labels))\n        .with_signature_identifier(SignaturesIdentifier::from_config(config)?)\n        .with_label_disabled(disable_label);\n    let mut identifier = TraceIdentifiers::new().with_external(config, Some(chain))?;\n    if let Some(contracts) = &known_contracts {\n        builder = builder.with_known_contracts(contracts);\n        identifier = identifier.with_local_and_bytecodes(contracts, contracts_bytecode);\n    }\n\n    let mut decoder = builder.build();\n\n    for (_, trace) in result.traces.as_deref_mut().unwrap_or_default() {\n        decoder.identify(trace, &mut identifier);\n    }\n\n    if decode_internal || debug {\n        if let Some(ref etherscan_identifier) = identifier.external {\n            sources.merge(etherscan_identifier.get_compiled_contracts().await?);\n        }\n\n        if debug {\n            let mut debugger = Debugger::builder()\n                .traces(result.traces.expect(\"missing traces\"))\n                .decoder(&decoder)\n                .sources(sources)\n                .build();\n            debugger.try_run_tui()?;\n            return Ok(());\n        }\n\n        decoder.debug_identifier = Some(DebugTraceIdentifier::new(sources));\n    }\n\n    print_traces(\n        &mut result,\n        &decoder,\n        shell::verbosity() > 0,\n        shell::verbosity() > 4,\n        trace_depth,\n    )\n    .await?;\n\n    Ok(())\n}\n"
  },
  {
    "path": "crates/cast/src/errors.rs",
    "content": "//! Errors for this crate\n\nuse foundry_config::Chain;\nuse std::fmt;\n\n/// An error thrown when resolving a function via signature failed\n#[derive(Clone, Debug)]\npub enum FunctionSignatureError {\n    MissingSignature,\n    MissingEtherscan { sig: String },\n    UnknownChain(Chain),\n    MissingToAddress,\n}\n\nimpl fmt::Display for FunctionSignatureError {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        match self {\n            Self::MissingSignature => {\n                writeln!(f, \"Function signature must be set\")\n            }\n            Self::MissingEtherscan { sig } => {\n                writeln!(f, \"Failed to determine function signature for `{sig}`\")?;\n                writeln!(\n                    f,\n                    \"To lookup a function signature of a deployed contract by name, a valid ETHERSCAN_API_KEY must be set.\"\n                )?;\n                write!(f, \"\\tOr did you mean:\\t {sig}()\")\n            }\n            Self::UnknownChain(chain) => {\n                write!(f, \"Resolving via etherscan requires a known chain. Unknown chain: {chain}\")\n            }\n            Self::MissingToAddress => f.write_str(\"Target address must be set\"),\n        }\n    }\n}\n\nimpl std::error::Error for FunctionSignatureError {}\n"
  },
  {
    "path": "crates/cast/src/lib.rs",
    "content": "//! Cast is a Swiss Army knife for interacting with Ethereum applications from the command line.\n\n#![cfg_attr(not(test), warn(unused_crate_dependencies))]\n#![cfg_attr(docsrs, feature(doc_cfg))]\n\n#[macro_use]\nextern crate foundry_common;\n#[macro_use]\nextern crate tracing;\nuse alloy_consensus::BlockHeader;\nuse alloy_dyn_abi::{DynSolType, DynSolValue, FunctionExt};\nuse alloy_eips::Encodable2718;\nuse alloy_ens::NameOrAddress;\nuse alloy_json_abi::Function;\nuse alloy_network::{AnyNetwork, BlockResponse, Network, TransactionBuilder};\nuse alloy_primitives::{\n    Address, B256, I256, Keccak256, LogData, Selector, TxHash, U64, U256, hex,\n    utils::{ParseUnits, Unit, keccak256},\n};\nuse alloy_provider::{PendingTransactionBuilder, Provider, network::eip2718::Decodable2718};\nuse alloy_rlp::{Decodable, Encodable};\nuse alloy_rpc_types::{\n    BlockId, BlockNumberOrTag, BlockOverrides, Filter, FilterBlockOption, Log, state::StateOverride,\n};\nuse base::{Base, NumberWithBase, ToBase};\nuse chrono::DateTime;\nuse eyre::{Context, ContextCompat, OptionExt, Result};\nuse foundry_block_explorers::Client;\nuse foundry_common::{\n    abi::{coerce_value, encode_function_args, encode_function_args_packed, get_event, get_func},\n    compile::etherscan_project,\n    flatten,\n    fmt::*,\n    fs, shell,\n};\nuse foundry_config::Chain;\nuse foundry_evm::core::bytecode::InstIter;\nuse foundry_primitives::FoundryTxEnvelope;\nuse futures::{FutureExt, StreamExt, future::Either};\n\nuse rayon::prelude::*;\nuse serde::Serialize;\nuse std::{\n    borrow::Cow,\n    fmt::Write,\n    io,\n    marker::PhantomData,\n    path::PathBuf,\n    str::FromStr,\n    sync::atomic::{AtomicBool, Ordering},\n};\nuse tokio::signal::ctrl_c;\n\npub use foundry_evm::*;\n\npub mod args;\npub mod cmd;\npub mod opts;\n\npub mod base;\npub(crate) mod debug;\npub mod errors;\nmod rlp_converter;\npub mod tx;\n\nuse rlp_converter::Item;\n\n// TODO: CastContract with common contract initializers? Same for CastProviders?\n\npub struct Cast<P, N = AnyNetwork> {\n    provider: P,\n    _phantom: PhantomData<N>,\n}\n\nimpl<P: Provider<N> + Clone + Unpin, N: Network> Cast<P, N> {\n    /// Creates a new Cast instance from the provided client\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// use alloy_provider::{ProviderBuilder, RootProvider, network::AnyNetwork};\n    /// use cast::Cast;\n    ///\n    /// # async fn foo() -> eyre::Result<()> {\n    /// let provider =\n    ///     ProviderBuilder::<_, _, AnyNetwork>::default().connect(\"http://localhost:8545\").await?;\n    /// let cast = Cast::new(provider);\n    /// # Ok(())\n    /// # }\n    /// ```\n    pub fn new(provider: P) -> Self {\n        Self { provider, _phantom: PhantomData }\n    }\n\n    /// Makes a read-only call to the specified address\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// use alloy_primitives::{Address, U256, Bytes};\n    /// use alloy_rpc_types::{TransactionRequest, BlockOverrides, state::{StateOverride, AccountOverride}};\n    /// use alloy_serde::WithOtherFields;\n    /// use cast::Cast;\n    /// use alloy_provider::{RootProvider, ProviderBuilder, network::AnyNetwork};\n    /// use std::{str::FromStr, collections::HashMap};\n    /// use alloy_rpc_types::state::StateOverridesBuilder;\n    /// use alloy_sol_types::{sol, SolCall};\n    ///\n    /// sol!(\n    ///     function greeting(uint256 i) public returns (string);\n    /// );\n    ///\n    /// # async fn foo() -> eyre::Result<()> {\n    /// let alloy_provider = ProviderBuilder::<_,_, AnyNetwork>::default().connect(\"http://localhost:8545\").await?;;\n    /// let to = Address::from_str(\"0xB3C95ff08316fb2F2e3E52Ee82F8e7b605Aa1304\")?;\n    /// let greeting = greetingCall { i: U256::from(5) }.abi_encode();\n    /// let bytes = Bytes::from_iter(greeting.iter());\n    /// let tx = TransactionRequest::default().to(to).input(bytes.into());\n    /// let tx = WithOtherFields::new(tx);\n    ///\n    /// // Create state overrides\n    /// let mut state_override = StateOverride::default();\n    /// let mut account_override = AccountOverride::default();\n    /// account_override.balance = Some(U256::from(1000));\n    /// state_override.insert(to, account_override);\n    /// let state_override_object = StateOverridesBuilder::default().build();\n    /// let block_override_object = BlockOverrides::default();\n    ///\n    /// let cast = Cast::new(alloy_provider);\n    /// let data = cast.call(&tx, None, None, Some(state_override_object), Some(block_override_object)).await?;\n    /// println!(\"{}\", data);\n    /// # Ok(())\n    /// # }\n    /// ```\n    pub async fn call(\n        &self,\n        req: &N::TransactionRequest,\n        func: Option<&Function>,\n        block: Option<BlockId>,\n        state_override: Option<StateOverride>,\n        block_override: Option<BlockOverrides>,\n    ) -> Result<String> {\n        let mut call = self\n            .provider\n            .call(req.clone())\n            .block(block.unwrap_or_default())\n            .with_block_overrides_opt(block_override);\n        if let Some(state_override) = state_override {\n            call = call.overrides(state_override)\n        }\n\n        let res = call.await?;\n        let mut decoded = vec![];\n\n        if let Some(func) = func {\n            // decode args into tokens\n            decoded = match func.abi_decode_output(res.as_ref()) {\n                Ok(decoded) => decoded,\n                Err(err) => {\n                    // ensure the address is a contract\n                    if res.is_empty() {\n                        // check that the recipient is a contract that can be called\n                        if let Some(addr) = req.to() {\n                            if let Ok(code) = self\n                                .provider\n                                .get_code_at(addr)\n                                .block_id(block.unwrap_or_default())\n                                .await\n                                && code.is_empty()\n                            {\n                                eyre::bail!(\"contract {addr:?} does not have any code\")\n                            }\n                        } else if req.to().is_none() {\n                            eyre::bail!(\"tx req is a contract deployment\");\n                        } else {\n                            eyre::bail!(\"recipient is None\");\n                        }\n                    }\n                    return Err(err).wrap_err(\n                        \"could not decode output; did you specify the wrong function return data type?\"\n                    );\n                }\n            };\n        }\n\n        // handle case when return type is not specified\n        Ok(if decoded.is_empty() {\n            res.to_string()\n        } else if shell::is_json() {\n            let tokens = decoded\n                .into_iter()\n                .map(|value| serialize_value_as_json(value, None))\n                .collect::<eyre::Result<Vec<_>>>()?;\n            serde_json::to_string_pretty(&tokens).unwrap()\n        } else {\n            // seth compatible user-friendly return type conversions\n            decoded.iter().map(format_token).collect::<Vec<_>>().join(\"\\n\")\n        })\n    }\n\n    /// Generates an access list for the specified transaction\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// use cast::{Cast};\n    /// use alloy_primitives::{Address, U256, Bytes};\n    /// use alloy_rpc_types::{TransactionRequest};\n    /// use alloy_serde::WithOtherFields;\n    /// use alloy_provider::{RootProvider, ProviderBuilder, network::AnyNetwork};\n    /// use std::str::FromStr;\n    /// use alloy_sol_types::{sol, SolCall};\n    ///\n    /// sol!(\n    ///     function greeting(uint256 i) public returns (string);\n    /// );\n    ///\n    /// # async fn foo() -> eyre::Result<()> {\n    /// let provider = ProviderBuilder::<_,_, AnyNetwork>::default().connect(\"http://localhost:8545\").await?;;\n    /// let to = Address::from_str(\"0xB3C95ff08316fb2F2e3E52Ee82F8e7b605Aa1304\")?;\n    /// let greeting = greetingCall { i: U256::from(5) }.abi_encode();\n    /// let bytes = Bytes::from_iter(greeting.iter());\n    /// let tx = TransactionRequest::default().to(to).input(bytes.into());\n    /// let tx = WithOtherFields::new(tx);\n    /// let cast = Cast::new(&provider);\n    /// let access_list = cast.access_list(&tx, None).await?;\n    /// println!(\"{}\", access_list);\n    /// # Ok(())\n    /// # }\n    /// ```\n    pub async fn access_list(\n        &self,\n        req: &N::TransactionRequest,\n        block: Option<BlockId>,\n    ) -> Result<String> {\n        let access_list =\n            self.provider.create_access_list(req).block_id(block.unwrap_or_default()).await?;\n        let res = if shell::is_json() {\n            serde_json::to_string(&access_list)?\n        } else {\n            let mut s =\n                vec![format!(\"gas used: {}\", access_list.gas_used), \"access list:\".to_string()];\n            for al in access_list.access_list.0 {\n                s.push(format!(\"- address: {}\", &al.address.to_checksum(None)));\n                if !al.storage_keys.is_empty() {\n                    s.push(\"  keys:\".to_string());\n                    for key in al.storage_keys {\n                        s.push(format!(\"    {key:?}\"));\n                    }\n                }\n            }\n            s.join(\"\\n\")\n        };\n\n        Ok(res)\n    }\n\n    pub async fn balance(&self, who: Address, block: Option<BlockId>) -> Result<U256> {\n        Ok(self.provider.get_balance(who).block_id(block.unwrap_or_default()).await?)\n    }\n\n    /// Publishes a raw transaction to the network\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// use alloy_provider::{ProviderBuilder, RootProvider, network::AnyNetwork};\n    /// use cast::Cast;\n    ///\n    /// # async fn foo() -> eyre::Result<()> {\n    /// let provider =\n    ///     ProviderBuilder::<_, _, AnyNetwork>::default().connect(\"http://localhost:8545\").await?;\n    /// let cast = Cast::new(provider);\n    /// let res = cast.publish(\"0x1234\".to_string()).await?;\n    /// println!(\"{:?}\", res);\n    /// # Ok(())\n    /// # }\n    /// ```\n    pub async fn publish(&self, raw_tx: String) -> Result<PendingTransactionBuilder<N>> {\n        let tx = hex::decode(strip_0x(&raw_tx))?;\n        let res = self.provider.send_raw_transaction(&tx).await?;\n\n        Ok(res)\n    }\n\n    pub async fn chain_id(&self) -> Result<u64> {\n        Ok(self.provider.get_chain_id().await?)\n    }\n\n    pub async fn block_number(&self) -> Result<u64> {\n        Ok(self.provider.get_block_number().await?)\n    }\n\n    pub async fn gas_price(&self) -> Result<u128> {\n        Ok(self.provider.get_gas_price().await?)\n    }\n\n    /// # Example\n    ///\n    /// ```\n    /// use alloy_primitives::Address;\n    /// use alloy_provider::{ProviderBuilder, RootProvider, network::AnyNetwork};\n    /// use cast::Cast;\n    /// use std::str::FromStr;\n    ///\n    /// # async fn foo() -> eyre::Result<()> {\n    /// let provider =\n    ///     ProviderBuilder::<_, _, AnyNetwork>::default().connect(\"http://localhost:8545\").await?;\n    /// let cast = Cast::new(provider);\n    /// let addr = Address::from_str(\"0x7eD52863829AB99354F3a0503A622e82AcD5F7d3\")?;\n    /// let nonce = cast.nonce(addr, None).await?;\n    /// println!(\"{}\", nonce);\n    /// # Ok(())\n    /// # }\n    /// ```\n    pub async fn nonce(&self, who: Address, block: Option<BlockId>) -> Result<u64> {\n        Ok(self.provider.get_transaction_count(who).block_id(block.unwrap_or_default()).await?)\n    }\n\n    /// #Example\n    ///\n    /// ```\n    /// use alloy_primitives::{Address, FixedBytes};\n    /// use alloy_provider::{network::AnyNetwork, ProviderBuilder, RootProvider};\n    /// use cast::Cast;\n    /// use std::str::FromStr;\n    ///\n    /// # async fn foo() -> eyre::Result<()> {\n    /// let provider =\n    ///     ProviderBuilder::<_, _, AnyNetwork>::default().connect(\"http://localhost:8545\").await?;\n    /// let cast = Cast::new(provider);\n    /// let addr = Address::from_str(\"0x7eD52863829AB99354F3a0503A622e82AcD5F7d3\")?;\n    /// let slots = vec![FixedBytes::from_str(\"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\")?];\n    /// let codehash = cast.codehash(addr, slots, None).await?;\n    /// println!(\"{}\", codehash);\n    /// # Ok(())\n    /// # }\n    pub async fn codehash(\n        &self,\n        who: Address,\n        slots: Vec<B256>,\n        block: Option<BlockId>,\n    ) -> Result<String> {\n        Ok(self\n            .provider\n            .get_proof(who, slots)\n            .block_id(block.unwrap_or_default())\n            .await?\n            .code_hash\n            .to_string())\n    }\n\n    /// #Example\n    ///\n    /// ```\n    /// use alloy_primitives::{Address, FixedBytes};\n    /// use alloy_provider::{network::AnyNetwork, ProviderBuilder, RootProvider};\n    /// use cast::Cast;\n    /// use std::str::FromStr;\n    ///\n    /// # async fn foo() -> eyre::Result<()> {\n    /// let provider =\n    ///     ProviderBuilder::<_, _, AnyNetwork>::default().connect(\"http://localhost:8545\").await?;\n    /// let cast = Cast::new(provider);\n    /// let addr = Address::from_str(\"0x7eD52863829AB99354F3a0503A622e82AcD5F7d3\")?;\n    /// let slots = vec![FixedBytes::from_str(\"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\")?];\n    /// let storage_root = cast.storage_root(addr, slots, None).await?;\n    /// println!(\"{}\", storage_root);\n    /// # Ok(())\n    /// # }\n    pub async fn storage_root(\n        &self,\n        who: Address,\n        slots: Vec<B256>,\n        block: Option<BlockId>,\n    ) -> Result<String> {\n        Ok(self\n            .provider\n            .get_proof(who, slots)\n            .block_id(block.unwrap_or_default())\n            .await?\n            .storage_hash\n            .to_string())\n    }\n\n    /// # Example\n    ///\n    /// ```\n    /// use alloy_primitives::Address;\n    /// use alloy_provider::{ProviderBuilder, RootProvider, network::AnyNetwork};\n    /// use cast::Cast;\n    /// use std::str::FromStr;\n    ///\n    /// # async fn foo() -> eyre::Result<()> {\n    /// let provider =\n    ///     ProviderBuilder::<_, _, AnyNetwork>::default().connect(\"http://localhost:8545\").await?;\n    /// let cast = Cast::new(provider);\n    /// let addr = Address::from_str(\"0x7eD52863829AB99354F3a0503A622e82AcD5F7d3\")?;\n    /// let implementation = cast.implementation(addr, false, None).await?;\n    /// println!(\"{}\", implementation);\n    /// # Ok(())\n    /// # }\n    /// ```\n    pub async fn implementation(\n        &self,\n        who: Address,\n        is_beacon: bool,\n        block: Option<BlockId>,\n    ) -> Result<String> {\n        let slot = match is_beacon {\n            true => {\n                // Use the beacon slot : bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)\n                B256::from_str(\n                    \"0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50\",\n                )?\n            }\n            false => {\n                // Use the implementation slot :\n                // bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1)\n                B256::from_str(\n                    \"0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc\",\n                )?\n            }\n        };\n\n        let value = self\n            .provider\n            .get_storage_at(who, slot.into())\n            .block_id(block.unwrap_or_default())\n            .await?;\n        let addr = Address::from_word(value.into());\n        Ok(format!(\"{addr:?}\"))\n    }\n\n    /// # Example\n    ///\n    /// ```\n    /// use alloy_primitives::Address;\n    /// use alloy_provider::{ProviderBuilder, RootProvider, network::AnyNetwork};\n    /// use cast::Cast;\n    /// use std::str::FromStr;\n    ///\n    /// # async fn foo() -> eyre::Result<()> {\n    /// let provider =\n    ///     ProviderBuilder::<_, _, AnyNetwork>::default().connect(\"http://localhost:8545\").await?;\n    /// let cast = Cast::new(provider);\n    /// let addr = Address::from_str(\"0x7eD52863829AB99354F3a0503A622e82AcD5F7d3\")?;\n    /// let admin = cast.admin(addr, None).await?;\n    /// println!(\"{}\", admin);\n    /// # Ok(())\n    /// # }\n    /// ```\n    pub async fn admin(&self, who: Address, block: Option<BlockId>) -> Result<String> {\n        let slot =\n            B256::from_str(\"0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103\")?;\n        let value = self\n            .provider\n            .get_storage_at(who, slot.into())\n            .block_id(block.unwrap_or_default())\n            .await?;\n        let addr = Address::from_word(value.into());\n        Ok(format!(\"{addr:?}\"))\n    }\n\n    /// # Example\n    ///\n    /// ```\n    /// use alloy_primitives::{Address, U256};\n    /// use alloy_provider::{ProviderBuilder, RootProvider, network::AnyNetwork};\n    /// use cast::Cast;\n    /// use std::str::FromStr;\n    ///\n    /// # async fn foo() -> eyre::Result<()> {\n    /// let provider =\n    ///     ProviderBuilder::<_, _, AnyNetwork>::default().connect(\"http://localhost:8545\").await?;\n    /// let cast = Cast::new(provider);\n    /// let addr = Address::from_str(\"7eD52863829AB99354F3a0503A622e82AcD5F7d3\")?;\n    /// let computed_address = cast.compute_address(addr, None).await?;\n    /// println!(\"Computed address for address {addr}: {computed_address}\");\n    /// # Ok(())\n    /// # }\n    /// ```\n    pub async fn compute_address(&self, address: Address, nonce: Option<u64>) -> Result<Address> {\n        let unpacked = if let Some(n) = nonce { n } else { self.nonce(address, None).await? };\n        Ok(address.create(unpacked))\n    }\n\n    /// # Example\n    ///\n    /// ```\n    /// use alloy_primitives::Address;\n    /// use alloy_provider::{ProviderBuilder, RootProvider, network::AnyNetwork};\n    /// use cast::Cast;\n    /// use std::str::FromStr;\n    ///\n    /// # async fn foo() -> eyre::Result<()> {\n    /// let provider =\n    ///     ProviderBuilder::<_, _, AnyNetwork>::default().connect(\"http://localhost:8545\").await?;\n    /// let cast = Cast::new(provider);\n    /// let addr = Address::from_str(\"0x00000000219ab540356cbb839cbe05303d7705fa\")?;\n    /// let code = cast.code(addr, None, false).await?;\n    /// println!(\"{}\", code);\n    /// # Ok(())\n    /// # }\n    /// ```\n    pub async fn code(\n        &self,\n        who: Address,\n        block: Option<BlockId>,\n        disassemble: bool,\n    ) -> Result<String> {\n        if disassemble {\n            let code =\n                self.provider.get_code_at(who).block_id(block.unwrap_or_default()).await?.to_vec();\n            SimpleCast::disassemble(&code)\n        } else {\n            Ok(format!(\n                \"{}\",\n                self.provider.get_code_at(who).block_id(block.unwrap_or_default()).await?\n            ))\n        }\n    }\n\n    /// Example\n    ///\n    /// ```\n    /// use alloy_primitives::Address;\n    /// use alloy_provider::{ProviderBuilder, RootProvider, network::AnyNetwork};\n    /// use cast::Cast;\n    /// use std::str::FromStr;\n    ///\n    /// # async fn foo() -> eyre::Result<()> {\n    /// let provider =\n    ///     ProviderBuilder::<_, _, AnyNetwork>::default().connect(\"http://localhost:8545\").await?;\n    /// let cast = Cast::new(provider);\n    /// let addr = Address::from_str(\"0x00000000219ab540356cbb839cbe05303d7705fa\")?;\n    /// let codesize = cast.codesize(addr, None).await?;\n    /// println!(\"{}\", codesize);\n    /// # Ok(())\n    /// # }\n    /// ```\n    pub async fn codesize(&self, who: Address, block: Option<BlockId>) -> Result<String> {\n        let code =\n            self.provider.get_code_at(who).block_id(block.unwrap_or_default()).await?.to_vec();\n        Ok(code.len().to_string())\n    }\n\n    /// Perform a raw JSON-RPC request\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// use alloy_provider::{ProviderBuilder, RootProvider, network::AnyNetwork};\n    /// use cast::Cast;\n    ///\n    /// # async fn foo() -> eyre::Result<()> {\n    /// let provider =\n    ///     ProviderBuilder::<_, _, AnyNetwork>::default().connect(\"http://localhost:8545\").await?;\n    /// let cast = Cast::new(provider);\n    /// let result = cast\n    ///     .rpc(\"eth_getBalance\", &[\"0xc94770007dda54cF92009BFF0dE90c06F603a09f\", \"latest\"])\n    ///     .await?;\n    /// println!(\"{}\", result);\n    /// # Ok(())\n    /// # }\n    /// ```\n    pub async fn rpc<V>(&self, method: &str, params: V) -> Result<String>\n    where\n        V: alloy_json_rpc::RpcSend,\n    {\n        let res = self\n            .provider\n            .raw_request::<V, serde_json::Value>(Cow::Owned(method.to_string()), params)\n            .await?;\n        Ok(serde_json::to_string(&res)?)\n    }\n\n    /// Returns the slot\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// use alloy_primitives::{Address, B256};\n    /// use alloy_provider::{ProviderBuilder, RootProvider, network::AnyNetwork};\n    /// use cast::Cast;\n    /// use std::str::FromStr;\n    ///\n    /// # async fn foo() -> eyre::Result<()> {\n    /// let provider =\n    ///     ProviderBuilder::<_, _, AnyNetwork>::default().connect(\"http://localhost:8545\").await?;\n    /// let cast = Cast::new(provider);\n    /// let addr = Address::from_str(\"0x00000000006c3852cbEf3e08E8dF289169EdE581\")?;\n    /// let slot = B256::ZERO;\n    /// let storage = cast.storage(addr, slot, None).await?;\n    /// println!(\"{}\", storage);\n    /// # Ok(())\n    /// # }\n    /// ```\n    pub async fn storage(\n        &self,\n        from: Address,\n        slot: B256,\n        block: Option<BlockId>,\n    ) -> Result<String> {\n        Ok(format!(\n            \"{:?}\",\n            B256::from(\n                self.provider\n                    .get_storage_at(from, slot.into())\n                    .block_id(block.unwrap_or_default())\n                    .await?\n            )\n        ))\n    }\n\n    pub async fn filter_logs(&self, filter: Filter) -> Result<String> {\n        let logs = self.provider.get_logs(&filter).await?;\n        Self::format_logs(logs)\n    }\n\n    /// Retrieves logs using chunked requests to handle large block ranges.\n    ///\n    /// Automatically divides large block ranges into smaller chunks to avoid provider limits\n    /// and processes them with controlled concurrency to prevent rate limiting.\n    pub async fn filter_logs_chunked(&self, filter: Filter, chunk_size: u64) -> Result<String> {\n        let logs = self.get_logs_chunked(&filter, chunk_size).await?;\n        Self::format_logs(logs)\n    }\n\n    fn format_logs(logs: Vec<Log>) -> Result<String> {\n        let res = if shell::is_json() {\n            serde_json::to_string(&logs)?\n        } else {\n            let mut s = vec![];\n            for log in logs {\n                let pretty = log\n                    .pretty()\n                    .replacen('\\n', \"- \", 1) // Remove empty first line\n                    .replace('\\n', \"\\n  \"); // Indent\n                s.push(pretty);\n            }\n            s.join(\"\\n\")\n        };\n        Ok(res)\n    }\n\n    fn extract_block_range(filter: &Filter) -> (Option<u64>, Option<u64>) {\n        let FilterBlockOption::Range { from_block, to_block } = &filter.block_option else {\n            return (None, None);\n        };\n\n        (from_block.and_then(|b| b.as_number()), to_block.and_then(|b| b.as_number()))\n    }\n\n    /// Retrieves logs with automatic chunking fallback.\n    ///\n    /// First tries to fetch logs for the entire range. If that fails,\n    /// falls back to concurrent chunked requests with rate limiting.\n    async fn get_logs_chunked(&self, filter: &Filter, chunk_size: u64) -> Result<Vec<Log>>\n    where\n        P: Clone + Unpin,\n    {\n        // Try the full range first\n        if let Ok(logs) = self.provider.get_logs(filter).await {\n            return Ok(logs);\n        }\n\n        // Fallback: use concurrent chunked approach\n        self.get_logs_chunked_concurrent(filter, chunk_size).await\n    }\n\n    /// Retrieves logs using concurrent chunked requests with rate limiting.\n    ///\n    /// Divides the block range into chunks and processes them with a maximum of\n    /// 5 concurrent requests. Falls back to single-block queries if chunks fail.\n    async fn get_logs_chunked_concurrent(\n        &self,\n        filter: &Filter,\n        chunk_size: u64,\n    ) -> Result<Vec<Log>>\n    where\n        P: Clone + Unpin,\n    {\n        let (from_block, to_block) = Self::extract_block_range(filter);\n        let (Some(from), Some(to)) = (from_block, to_block) else {\n            return self.provider.get_logs(filter).await.map_err(Into::into);\n        };\n\n        if from >= to {\n            return Ok(vec![]);\n        }\n\n        // Create chunk ranges using iterator\n        let chunk_ranges: Vec<(u64, u64)> = (from..to)\n            .step_by(chunk_size as usize)\n            .map(|chunk_start| (chunk_start, (chunk_start + chunk_size).min(to)))\n            .collect();\n\n        // Process chunks with controlled concurrency using buffered stream\n        let mut all_results: Vec<(u64, Vec<Log>)> = futures::stream::iter(chunk_ranges)\n            .map(|(start_block, chunk_end)| {\n                let chunk_filter = filter.clone().from_block(start_block).to_block(chunk_end - 1);\n                let provider = self.provider.clone();\n\n                async move {\n                    // Try direct chunk request with simplified fallback\n                    match provider.get_logs(&chunk_filter).await {\n                        Ok(logs) => (start_block, logs),\n                        Err(_) => {\n                            // Simple fallback: try individual blocks in this chunk\n                            let mut fallback_logs = Vec::new();\n                            for single_block in start_block..chunk_end {\n                                let single_filter = chunk_filter\n                                    .clone()\n                                    .from_block(single_block)\n                                    .to_block(single_block);\n                                if let Ok(logs) = provider.get_logs(&single_filter).await {\n                                    fallback_logs.extend(logs);\n                                }\n                            }\n                            (start_block, fallback_logs)\n                        }\n                    }\n                }\n            })\n            .buffered(5) // Limit to 5 concurrent requests to avoid rate limits\n            .collect()\n            .await;\n\n        // Sort once at the end by block number and flatten\n        all_results.sort_by_key(|(block_num, _)| *block_num);\n\n        let mut all_logs = Vec::new();\n        for (_, logs) in all_results {\n            all_logs.extend(logs);\n        }\n\n        Ok(all_logs)\n    }\n\n    /// Converts a block identifier into a block number.\n    ///\n    /// If the block identifier is a block number, then this function returns the block number. If\n    /// the block identifier is a block hash, then this function returns the block number of\n    /// that block hash. If the block identifier is `None`, then this function returns `None`.\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// use alloy_primitives::fixed_bytes;\n    /// use alloy_provider::{ProviderBuilder, RootProvider, network::AnyNetwork};\n    /// use alloy_rpc_types::{BlockId, BlockNumberOrTag};\n    /// use cast::Cast;\n    /// use std::{convert::TryFrom, str::FromStr};\n    ///\n    /// # async fn foo() -> eyre::Result<()> {\n    /// let provider =\n    ///     ProviderBuilder::<_, _, AnyNetwork>::default().connect(\"http://localhost:8545\").await?;\n    /// let cast = Cast::new(provider);\n    ///\n    /// let block_number = cast.convert_block_number(Some(BlockId::number(5))).await?;\n    /// assert_eq!(block_number, Some(BlockNumberOrTag::Number(5)));\n    ///\n    /// let block_number = cast\n    ///     .convert_block_number(Some(BlockId::hash(fixed_bytes!(\n    ///         \"0000000000000000000000000000000000000000000000000000000000001234\"\n    ///     ))))\n    ///     .await?;\n    /// assert_eq!(block_number, Some(BlockNumberOrTag::Number(4660)));\n    ///\n    /// let block_number = cast.convert_block_number(None).await?;\n    /// assert_eq!(block_number, None);\n    /// # Ok(())\n    /// # }\n    /// ```\n    pub async fn convert_block_number(\n        &self,\n        block: Option<BlockId>,\n    ) -> Result<Option<BlockNumberOrTag>, eyre::Error> {\n        match block {\n            Some(block) => match block {\n                BlockId::Number(block_number) => Ok(Some(block_number)),\n                BlockId::Hash(hash) => {\n                    let block = self.provider.get_block_by_hash(hash.block_hash).await?;\n                    Ok(block.map(|block| block.header().number()).map(BlockNumberOrTag::from))\n                }\n            },\n            None => Ok(None),\n        }\n    }\n\n    /// Sets up a subscription to the given filter and writes the logs to the given output.\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// use alloy_primitives::Address;\n    /// use alloy_provider::{ProviderBuilder, RootProvider, network::AnyNetwork};\n    /// use alloy_rpc_types::Filter;\n    /// use alloy_transport::BoxTransport;\n    /// use cast::Cast;\n    /// use std::{io, str::FromStr};\n    ///\n    /// # async fn foo() -> eyre::Result<()> {\n    /// let provider =\n    ///     ProviderBuilder::<_, _, AnyNetwork>::default().connect(\"wss://localhost:8545\").await?;\n    /// let cast = Cast::new(provider);\n    ///\n    /// let filter =\n    ///     Filter::new().address(Address::from_str(\"0x00000000006c3852cbEf3e08E8dF289169EdE581\")?);\n    /// let mut output = io::stdout();\n    /// cast.subscribe(filter, &mut output).await?;\n    /// # Ok(())\n    /// # }\n    /// ```\n    pub async fn subscribe(&self, filter: Filter, output: &mut dyn io::Write) -> Result<()> {\n        // Initialize the subscription stream for logs\n        let mut subscription = self.provider.subscribe_logs(&filter).await?.into_stream();\n\n        // Check if a to_block is specified, if so, subscribe to blocks\n        let mut block_subscription = if filter.get_to_block().is_some() {\n            Some(self.provider.subscribe_blocks().await?.into_stream())\n        } else {\n            None\n        };\n\n        let format_json = shell::is_json();\n        let to_block_number = filter.get_to_block();\n\n        // If output should be JSON, start with an opening bracket\n        if format_json {\n            write!(output, \"[\")?;\n        }\n\n        let mut first = true;\n\n        loop {\n            tokio::select! {\n                // If block subscription is present, listen to it to avoid blocking indefinitely past the desired to_block\n                block = if let Some(bs) = &mut block_subscription {\n                    Either::Left(bs.next().fuse())\n                } else {\n                    Either::Right(futures::future::pending())\n                } => {\n                    if let (Some(block), Some(to_block)) = (block, to_block_number)\n                        && block.number()  > to_block {\n                            break;\n                        }\n                },\n                // Process incoming log\n                log = subscription.next() => {\n                    if format_json {\n                        if !first {\n                            write!(output, \",\")?;\n                        }\n                        first = false;\n                        let log_str = serde_json::to_string(&log).unwrap();\n                        write!(output, \"{log_str}\")?;\n                    } else {\n                        let log_str = log.pretty()\n                            .replacen('\\n', \"- \", 1)  // Remove empty first line\n                            .replace('\\n', \"\\n  \");  // Indent\n                        writeln!(output, \"{log_str}\")?;\n                    }\n                },\n                // Break on cancel signal, to allow for closing JSON bracket\n                _ = ctrl_c() => {\n                    break;\n                },\n                else => break,\n            }\n        }\n\n        // If output was JSON, end with a closing bracket\n        if format_json {\n            write!(output, \"]\")?;\n        }\n\n        Ok(())\n    }\n}\n\nimpl<P: Provider<N>, N: Network> Cast<P, N>\nwhere\n    N::HeaderResponse: UIfmtHeaderExt,\n    N::BlockResponse: UIfmt,\n{\n    /// # Example\n    ///\n    /// ```\n    /// use alloy_provider::{ProviderBuilder, RootProvider, network::AnyNetwork};\n    /// use cast::Cast;\n    ///\n    /// # async fn foo() -> eyre::Result<()> {\n    /// let provider =\n    ///     ProviderBuilder::<_, _, AnyNetwork>::default().connect(\"http://localhost:8545\").await?;\n    /// let cast = Cast::new(provider);\n    /// let block = cast.block(5, true, vec![]).await?;\n    /// println!(\"{}\", block);\n    /// # Ok(())\n    /// # }\n    /// ```\n    pub async fn block<B: Into<BlockId>>(\n        &self,\n        block: B,\n        full: bool,\n        fields: Vec<String>,\n    ) -> Result<String> {\n        let block = block.into();\n        if fields.contains(&\"transactions\".into()) && !full {\n            eyre::bail!(\"use --full to view transactions\")\n        }\n\n        let block = self\n            .provider\n            .get_block(block)\n            .kind(full.into())\n            .await?\n            .ok_or_else(|| eyre::eyre!(\"block {:?} not found\", block))?;\n\n        Ok(if !fields.is_empty() {\n            let mut result = String::new();\n            for field in fields {\n                result.push_str(\n                    &get_pretty_block_attr::<N>(&block, &field)\n                        .unwrap_or_else(|| format!(\"{field} is not a valid block field\")),\n                );\n\n                result.push('\\n');\n            }\n            result.trim_end().to_string()\n        } else if shell::is_json() {\n            serde_json::to_value(&block).unwrap().to_string()\n        } else {\n            block.pretty()\n        })\n    }\n\n    async fn block_field_as_num<B: Into<BlockId>>(&self, block: B, field: String) -> Result<U256> {\n        Self::block(\n            self,\n            block.into(),\n            false,\n            // Select only select field\n            vec![field],\n        )\n        .await?\n        .parse()\n        .map_err(Into::into)\n    }\n\n    pub async fn base_fee<B: Into<BlockId>>(&self, block: B) -> Result<U256> {\n        Self::block_field_as_num(self, block, String::from(\"baseFeePerGas\")).await\n    }\n\n    pub async fn age<B: Into<BlockId>>(&self, block: B) -> Result<String> {\n        let timestamp_str =\n            Self::block_field_as_num(self, block, String::from(\"timestamp\")).await?.to_string();\n        let datetime = DateTime::from_timestamp(timestamp_str.parse::<i64>().unwrap(), 0).unwrap();\n        Ok(datetime.format(\"%a %b %e %H:%M:%S %Y\").to_string())\n    }\n\n    pub async fn timestamp<B: Into<BlockId>>(&self, block: B) -> Result<U256> {\n        Self::block_field_as_num(self, block, \"timestamp\".to_string()).await\n    }\n\n    pub async fn chain(&self) -> Result<&str> {\n        let genesis_hash = Self::block(\n            self,\n            0,\n            false,\n            // Select only block hash\n            vec![String::from(\"hash\")],\n        )\n        .await?;\n\n        Ok(match &genesis_hash[..] {\n            \"0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3\" => {\n                match &(Self::block(self, 1920000, false, vec![String::from(\"hash\")]).await?)[..] {\n                    \"0x94365e3a8c0b35089c1d1195081fe7489b528a84b22199c916180db8b28ade7f\" => {\n                        \"etclive\"\n                    }\n                    _ => \"ethlive\",\n                }\n            }\n            \"0xa3c565fc15c7478862d50ccd6561e3c06b24cc509bf388941c25ea985ce32cb9\" => \"kovan\",\n            \"0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d\" => \"ropsten\",\n            \"0x7ca38a1916c42007829c55e69d3e9a73265554b586a499015373241b8a3fa48b\" => {\n                \"optimism-mainnet\"\n            }\n            \"0xc1fc15cd51159b1f1e5cbc4b82e85c1447ddfa33c52cf1d98d14fba0d6354be1\" => {\n                \"optimism-goerli\"\n            }\n            \"0x02adc9b449ff5f2467b8c674ece7ff9b21319d76c4ad62a67a70d552655927e5\" => {\n                \"optimism-kovan\"\n            }\n            \"0x521982bd54239dc71269eefb58601762cc15cfb2978e0becb46af7962ed6bfaa\" => \"fraxtal\",\n            \"0x910f5c4084b63fd860d0c2f9a04615115a5a991254700b39ba072290dbd77489\" => {\n                \"fraxtal-testnet\"\n            }\n            \"0x7ee576b35482195fc49205cec9af72ce14f003b9ae69f6ba0faef4514be8b442\" => {\n                \"arbitrum-mainnet\"\n            }\n            \"0x0cd786a2425d16f152c658316c423e6ce1181e15c3295826d7c9904cba9ce303\" => \"morden\",\n            \"0x6341fd3daf94b748c72ced5a5b26028f2474f5f00d824504e4fa37a75767e177\" => \"rinkeby\",\n            \"0xbf7e331f7f7c1dd2e05159666b3bf8bc7a8a3a9eb1d518969eab529dd9b88c1a\" => \"goerli\",\n            \"0x14c2283285a88fe5fce9bf5c573ab03d6616695d717b12a127188bcacfc743c4\" => \"kotti\",\n            \"0xa9c28ce2141b56c474f1dc504bee9b01eb1bd7d1a507580d5519d4437a97de1b\" => \"polygon-pos\",\n            \"0x7202b2b53c5a0836e773e319d18922cc756dd67432f9a1f65352b61f4406c697\" => {\n                \"polygon-pos-amoy-testnet\"\n            }\n            \"0x81005434635456a16f74ff7023fbe0bf423abbc8a8deb093ffff455c0ad3b741\" => \"polygon-zkevm\",\n            \"0x676c1a76a6c5855a32bdf7c61977a0d1510088a4eeac1330466453b3d08b60b9\" => {\n                \"polygon-zkevm-cardona-testnet\"\n            }\n            \"0x4f1dd23188aab3a76b463e4af801b52b1248ef073c648cbdc4c9333d3da79756\" => \"gnosis\",\n            \"0xada44fd8d2ecab8b08f256af07ad3e777f17fb434f8f8e678b312f576212ba9a\" => \"chiado\",\n            \"0x6d3c66c5357ec91d5c43af47e234a939b22557cbb552dc45bebbceeed90fbe34\" => \"bsctest\",\n            \"0x0d21840abff46b96c84b2ac9e10e4f5cdaeb5693cb665db62a2f3b02d2d57b5b\" => \"bsc\",\n            \"0x31ced5b9beb7f8782b014660da0cb18cc409f121f408186886e1ca3e8eeca96b\" => {\n                match &(Self::block(self, 1, false, vec![String::from(\"hash\")]).await?)[..] {\n                    \"0x738639479dc82d199365626f90caa82f7eafcfe9ed354b456fb3d294597ceb53\" => {\n                        \"avalanche-fuji\"\n                    }\n                    _ => \"avalanche\",\n                }\n            }\n            \"0x23a2658170ba70d014ba0d0d2709f8fbfe2fa660cd868c5f282f991eecbe38ee\" => \"ink\",\n            \"0xe5fd5cf0be56af58ad5751b401410d6b7a09d830fa459789746a3d0dd1c79834\" => \"ink-sepolia\",\n            _ => \"unknown\",\n        })\n    }\n}\n\nimpl<P: Provider<N>, N: Network> Cast<P, N>\nwhere\n    N::Header: Encodable,\n{\n    /// # Example\n    ///\n    /// ```\n    /// use alloy_provider::{ProviderBuilder, RootProvider, network::Ethereum};\n    /// use cast::Cast;\n    ///\n    /// # async fn foo() -> eyre::Result<()> {\n    /// let provider =\n    ///     ProviderBuilder::<_, _, Ethereum>::default().connect(\"http://localhost:8545\").await?;\n    /// let cast = Cast::new(provider);\n    /// let block = cast.block_raw(5, true).await?;\n    /// println!(\"{}\", block);\n    /// # Ok(())\n    /// # }\n    /// ```\n    pub async fn block_raw<B: Into<BlockId>>(&self, block: B, full: bool) -> Result<String> {\n        let block_id = block.into();\n\n        let block = self\n            .provider\n            .get_block(block_id)\n            .kind(full.into())\n            .await?\n            .ok_or_else(|| eyre::eyre!(\"block {:?} not found\", block_id))?;\n\n        let encoded = alloy_rlp::encode(block.header().as_ref());\n\n        Ok(format!(\"0x{}\", hex::encode(encoded)))\n    }\n}\n\nimpl<P: Provider<N>, N: Network> Cast<P, N>\nwhere\n    N::TxEnvelope: Serialize + UIfmtSignatureExt,\n    N::TransactionResponse: UIfmt,\n{\n    /// # Example\n    ///\n    /// ```\n    /// use alloy_provider::{ProviderBuilder, RootProvider, network::AnyNetwork};\n    /// use cast::Cast;\n    ///\n    /// # async fn foo() -> eyre::Result<()> {\n    /// let provider =\n    ///     ProviderBuilder::<_, _, AnyNetwork>::default().connect(\"http://localhost:8545\").await?;\n    /// let cast = Cast::new(provider);\n    /// let tx_hash = \"0xf8d1713ea15a81482958fb7ddf884baee8d3bcc478c5f2f604e008dc788ee4fc\";\n    /// let tx = cast.transaction(Some(tx_hash.to_string()), None, None, None, false, false).await?;\n    /// println!(\"{}\", tx);\n    /// # Ok(())\n    /// # }\n    /// ```\n    pub async fn transaction(\n        &self,\n        tx_hash: Option<String>,\n        from: Option<NameOrAddress>,\n        nonce: Option<u64>,\n        field: Option<String>,\n        raw: bool,\n        to_request: bool,\n    ) -> Result<String> {\n        let tx = if let Some(tx_hash) = tx_hash {\n            let tx_hash = TxHash::from_str(&tx_hash).wrap_err(\"invalid tx hash\")?;\n            self.provider\n                .get_transaction_by_hash(tx_hash)\n                .await?\n                .ok_or_else(|| eyre::eyre!(\"tx not found: {:?}\", tx_hash))?\n        } else if let Some(from) = from {\n            // If nonce is not provided, uses 0.\n            let nonce = U64::from(nonce.unwrap_or_default());\n            let from = from.resolve(self.provider.root()).await?;\n\n            self.provider\n                .raw_request::<_, Option<N::TransactionResponse>>(\n                    \"eth_getTransactionBySenderAndNonce\".into(),\n                    (from, nonce),\n                )\n                .await?\n                .ok_or_else(|| {\n                    eyre::eyre!(\"tx not found for sender {from} and nonce {:?}\", nonce.to::<u64>())\n                })?\n        } else {\n            eyre::bail!(\"tx hash or from address is required\")\n        };\n\n        Ok(if raw {\n            let encoded = tx.as_ref().encoded_2718();\n            format!(\"0x{}\", hex::encode(encoded))\n        } else if let Some(ref field) = field {\n            get_pretty_tx_attr::<N>(&tx, field.as_str())\n                .ok_or_else(|| eyre::eyre!(\"invalid tx field: {}\", field.to_string()))?\n        } else if shell::is_json() {\n            // to_value first to sort json object keys\n            serde_json::to_value(&tx)?.to_string()\n        } else if to_request {\n            serde_json::to_string_pretty(&Into::<N::TransactionRequest>::into(tx))?\n        } else {\n            tx.pretty()\n        })\n    }\n}\n\npub struct SimpleCast;\n\nimpl SimpleCast {\n    /// Returns the maximum value of the given integer type\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// use alloy_primitives::{I256, U256};\n    /// use cast::SimpleCast;\n    ///\n    /// assert_eq!(SimpleCast::max_int(\"uint256\")?, U256::MAX.to_string());\n    /// assert_eq!(SimpleCast::max_int(\"int256\")?, I256::MAX.to_string());\n    /// assert_eq!(SimpleCast::max_int(\"int32\")?, i32::MAX.to_string());\n    /// # Ok::<(), eyre::Report>(())\n    /// ```\n    pub fn max_int(s: &str) -> Result<String> {\n        Self::max_min_int::<true>(s)\n    }\n\n    /// Returns the maximum value of the given integer type\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// use alloy_primitives::{I256, U256};\n    /// use cast::SimpleCast;\n    ///\n    /// assert_eq!(SimpleCast::min_int(\"uint256\")?, \"0\");\n    /// assert_eq!(SimpleCast::min_int(\"int256\")?, I256::MIN.to_string());\n    /// assert_eq!(SimpleCast::min_int(\"int32\")?, i32::MIN.to_string());\n    /// # Ok::<(), eyre::Report>(())\n    /// ```\n    pub fn min_int(s: &str) -> Result<String> {\n        Self::max_min_int::<false>(s)\n    }\n\n    fn max_min_int<const MAX: bool>(s: &str) -> Result<String> {\n        let ty = DynSolType::parse(s).wrap_err(\"Invalid type, expected `(u)int<bit size>`\")?;\n        match ty {\n            DynSolType::Int(n) => {\n                let mask = U256::from(1).wrapping_shl(n - 1);\n                let max = (U256::MAX & mask).saturating_sub(U256::from(1));\n                if MAX {\n                    Ok(max.to_string())\n                } else {\n                    let min = I256::from_raw(max).wrapping_neg() + I256::MINUS_ONE;\n                    Ok(min.to_string())\n                }\n            }\n            DynSolType::Uint(n) => {\n                if MAX {\n                    let mut max = U256::MAX;\n                    if n < 256 {\n                        max &= U256::from(1).wrapping_shl(n).wrapping_sub(U256::from(1));\n                    }\n                    Ok(max.to_string())\n                } else {\n                    Ok(\"0\".to_string())\n                }\n            }\n            _ => Err(eyre::eyre!(\"Type is not int/uint: {s}\")),\n        }\n    }\n\n    /// Converts UTF-8 text input to hex\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// use cast::SimpleCast as Cast;\n    ///\n    /// assert_eq!(Cast::from_utf8(\"yo\"), \"0x796f\");\n    /// assert_eq!(Cast::from_utf8(\"Hello, World!\"), \"0x48656c6c6f2c20576f726c6421\");\n    /// assert_eq!(Cast::from_utf8(\"TurboDappTools\"), \"0x547572626f44617070546f6f6c73\");\n    /// # Ok::<_, eyre::Report>(())\n    /// ```\n    pub fn from_utf8(s: &str) -> String {\n        hex::encode_prefixed(s)\n    }\n\n    /// Converts hex input to UTF-8 text\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// use cast::SimpleCast as Cast;\n    ///\n    /// assert_eq!(Cast::to_utf8(\"0x796f\")?, \"yo\");\n    /// assert_eq!(Cast::to_utf8(\"0x48656c6c6f2c20576f726c6421\")?, \"Hello, World!\");\n    /// assert_eq!(Cast::to_utf8(\"0x547572626f44617070546f6f6c73\")?, \"TurboDappTools\");\n    /// assert_eq!(Cast::to_utf8(\"0xe4bda0e5a5bd\")?, \"你好\");\n    /// # Ok::<_, eyre::Report>(())\n    /// ```\n    pub fn to_utf8(s: &str) -> Result<String> {\n        let bytes = hex::decode(s)?;\n        Ok(String::from_utf8_lossy(bytes.as_ref()).to_string())\n    }\n\n    /// Converts hex data into text data\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// use cast::SimpleCast as Cast;\n    ///\n    /// assert_eq!(Cast::to_ascii(\"0x796f\")?, \"yo\");\n    /// assert_eq!(Cast::to_ascii(\"48656c6c6f2c20576f726c6421\")?, \"Hello, World!\");\n    /// assert_eq!(Cast::to_ascii(\"0x547572626f44617070546f6f6c73\")?, \"TurboDappTools\");\n    /// # Ok::<_, eyre::Report>(())\n    /// ```\n    pub fn to_ascii(hex: &str) -> Result<String> {\n        let bytes = hex::decode(hex)?;\n        if !bytes.iter().all(u8::is_ascii) {\n            return Err(eyre::eyre!(\"Invalid ASCII bytes\"));\n        }\n        Ok(String::from_utf8(bytes).unwrap())\n    }\n\n    /// Converts fixed point number into specified number of decimals\n    /// ```\n    /// use alloy_primitives::U256;\n    /// use cast::SimpleCast as Cast;\n    ///\n    /// assert_eq!(Cast::from_fixed_point(\"10\", \"0\")?, \"10\");\n    /// assert_eq!(Cast::from_fixed_point(\"1.0\", \"1\")?, \"10\");\n    /// assert_eq!(Cast::from_fixed_point(\"0.10\", \"2\")?, \"10\");\n    /// assert_eq!(Cast::from_fixed_point(\"0.010\", \"3\")?, \"10\");\n    /// # Ok::<_, eyre::Report>(())\n    /// ```\n    pub fn from_fixed_point(value: &str, decimals: &str) -> Result<String> {\n        let units: Unit = Unit::from_str(decimals)?;\n        let n = ParseUnits::parse_units(value, units)?;\n        Ok(n.to_string())\n    }\n\n    /// Converts integers with specified decimals into fixed point numbers\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// use alloy_primitives::U256;\n    /// use cast::SimpleCast as Cast;\n    ///\n    /// assert_eq!(Cast::to_fixed_point(\"10\", \"0\")?, \"10.\");\n    /// assert_eq!(Cast::to_fixed_point(\"10\", \"1\")?, \"1.0\");\n    /// assert_eq!(Cast::to_fixed_point(\"10\", \"2\")?, \"0.10\");\n    /// assert_eq!(Cast::to_fixed_point(\"10\", \"3\")?, \"0.010\");\n    ///\n    /// assert_eq!(Cast::to_fixed_point(\"-10\", \"0\")?, \"-10.\");\n    /// assert_eq!(Cast::to_fixed_point(\"-10\", \"1\")?, \"-1.0\");\n    /// assert_eq!(Cast::to_fixed_point(\"-10\", \"2\")?, \"-0.10\");\n    /// assert_eq!(Cast::to_fixed_point(\"-10\", \"3\")?, \"-0.010\");\n    /// # Ok::<_, eyre::Report>(())\n    /// ```\n    pub fn to_fixed_point(value: &str, decimals: &str) -> Result<String> {\n        let (sign, mut value, value_len) = {\n            let number = NumberWithBase::parse_int(value, None)?;\n            let sign = if number.is_nonnegative() { \"\" } else { \"-\" };\n            let value = format!(\"{number:#}\");\n            let value_stripped = value.strip_prefix('-').unwrap_or(&value).to_string();\n            let value_len = value_stripped.len();\n            (sign, value_stripped, value_len)\n        };\n        let decimals = NumberWithBase::parse_uint(decimals, None)?.number().to::<usize>();\n\n        let value = if decimals >= value_len {\n            // Add \"0.\" and pad with 0s\n            format!(\"0.{value:0>decimals$}\")\n        } else {\n            // Insert decimal at -idx (i.e 1 => decimal idx = -1)\n            value.insert(value_len - decimals, '.');\n            value\n        };\n\n        Ok(format!(\"{sign}{value}\"))\n    }\n\n    /// Concatencates hex strings\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// use cast::SimpleCast as Cast;\n    ///\n    /// assert_eq!(Cast::concat_hex([\"0x00\", \"0x01\"]), \"0x0001\");\n    /// assert_eq!(Cast::concat_hex([\"1\", \"2\"]), \"0x12\");\n    /// # Ok::<_, eyre::Report>(())\n    /// ```\n    pub fn concat_hex<T: AsRef<str>>(values: impl IntoIterator<Item = T>) -> String {\n        let mut out = String::new();\n        for s in values {\n            let s = s.as_ref();\n            out.push_str(strip_0x(s))\n        }\n        format!(\"0x{out}\")\n    }\n\n    /// Converts a number into uint256 hex string with 0x prefix\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// use cast::SimpleCast as Cast;\n    ///\n    /// assert_eq!(\n    ///     Cast::to_uint256(\"100\")?,\n    ///     \"0x0000000000000000000000000000000000000000000000000000000000000064\"\n    /// );\n    /// assert_eq!(\n    ///     Cast::to_uint256(\"192038293923\")?,\n    ///     \"0x0000000000000000000000000000000000000000000000000000002cb65fd1a3\"\n    /// );\n    /// assert_eq!(\n    ///     Cast::to_uint256(\n    ///         \"115792089237316195423570985008687907853269984665640564039457584007913129639935\"\n    ///     )?,\n    ///     \"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\"\n    /// );\n    /// # Ok::<_, eyre::Report>(())\n    /// ```\n    pub fn to_uint256(value: &str) -> Result<String> {\n        let n = NumberWithBase::parse_uint(value, None)?;\n        Ok(format!(\"{n:#066x}\"))\n    }\n\n    /// Converts a number into int256 hex string with 0x prefix\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// use cast::SimpleCast as Cast;\n    ///\n    /// assert_eq!(\n    ///     Cast::to_int256(\"0\")?,\n    ///     \"0x0000000000000000000000000000000000000000000000000000000000000000\"\n    /// );\n    /// assert_eq!(\n    ///     Cast::to_int256(\"100\")?,\n    ///     \"0x0000000000000000000000000000000000000000000000000000000000000064\"\n    /// );\n    /// assert_eq!(\n    ///     Cast::to_int256(\"-100\")?,\n    ///     \"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9c\"\n    /// );\n    /// assert_eq!(\n    ///     Cast::to_int256(\"192038293923\")?,\n    ///     \"0x0000000000000000000000000000000000000000000000000000002cb65fd1a3\"\n    /// );\n    /// assert_eq!(\n    ///     Cast::to_int256(\"-192038293923\")?,\n    ///     \"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffd349a02e5d\"\n    /// );\n    /// assert_eq!(\n    ///     Cast::to_int256(\n    ///         \"57896044618658097711785492504343953926634992332820282019728792003956564819967\"\n    ///     )?,\n    ///     \"0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\"\n    /// );\n    /// assert_eq!(\n    ///     Cast::to_int256(\n    ///         \"-57896044618658097711785492504343953926634992332820282019728792003956564819968\"\n    ///     )?,\n    ///     \"0x8000000000000000000000000000000000000000000000000000000000000000\"\n    /// );\n    /// # Ok::<_, eyre::Report>(())\n    /// ```\n    pub fn to_int256(value: &str) -> Result<String> {\n        let n = NumberWithBase::parse_int(value, None)?;\n        Ok(format!(\"{n:#066x}\"))\n    }\n\n    /// Converts an eth amount into a specified unit\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// use cast::SimpleCast as Cast;\n    ///\n    /// assert_eq!(Cast::to_unit(\"1 wei\", \"wei\")?, \"1\");\n    /// assert_eq!(Cast::to_unit(\"1\", \"wei\")?, \"1\");\n    /// assert_eq!(Cast::to_unit(\"1ether\", \"wei\")?, \"1000000000000000000\");\n    /// # Ok::<_, eyre::Report>(())\n    /// ```\n    pub fn to_unit(value: &str, unit: &str) -> Result<String> {\n        let value = DynSolType::coerce_str(&DynSolType::Uint(256), value)?\n            .as_uint()\n            .wrap_err(\"Could not convert to uint\")?\n            .0;\n        let unit = unit.parse().wrap_err(\"could not parse units\")?;\n        Ok(Self::format_unit_as_string(value, unit))\n    }\n\n    /// Convert a number into a uint with arbitrary decimals.\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// use cast::SimpleCast as Cast;\n    ///\n    /// # fn main() -> eyre::Result<()> {\n    /// assert_eq!(Cast::parse_units(\"1.0\", 6)?, \"1000000\"); // USDC (6 decimals)\n    /// assert_eq!(Cast::parse_units(\"2.5\", 6)?, \"2500000\");\n    /// assert_eq!(Cast::parse_units(\"1.0\", 12)?, \"1000000000000\"); // 12 decimals\n    /// assert_eq!(Cast::parse_units(\"1.23\", 3)?, \"1230\"); // 3 decimals\n    ///\n    /// # Ok(())\n    /// # }\n    /// ```\n    pub fn parse_units(value: &str, unit: u8) -> Result<String> {\n        let unit = Unit::new(unit).ok_or_else(|| eyre::eyre!(\"invalid unit\"))?;\n\n        Ok(ParseUnits::parse_units(value, unit)?.to_string())\n    }\n\n    /// Format a number from smallest unit to decimal with arbitrary decimals.\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// use cast::SimpleCast as Cast;\n    ///\n    /// # fn main() -> eyre::Result<()> {\n    /// assert_eq!(Cast::format_units(\"1000000\", 6)?, \"1\"); // USDC (6 decimals)\n    /// assert_eq!(Cast::format_units(\"2500000\", 6)?, \"2.500000\");\n    /// assert_eq!(Cast::format_units(\"1000000000000\", 12)?, \"1\"); // 12 decimals\n    /// assert_eq!(Cast::format_units(\"1230\", 3)?, \"1.230\"); // 3 decimals\n    ///\n    /// # Ok(())\n    /// # }\n    /// ```\n    pub fn format_units(value: &str, unit: u8) -> Result<String> {\n        let value = NumberWithBase::parse_int(value, None)?.number();\n        let unit = Unit::new(unit).ok_or_else(|| eyre::eyre!(\"invalid unit\"))?;\n        Ok(Self::format_unit_as_string(value, unit))\n    }\n\n    // Helper function to format units as a string\n    fn format_unit_as_string(value: U256, unit: Unit) -> String {\n        let mut formatted = ParseUnits::U256(value).format_units(unit);\n        // Trim empty fractional part.\n        if let Some(dot) = formatted.find('.') {\n            let fractional = &formatted[dot + 1..];\n            if fractional.chars().all(|c: char| c == '0') {\n                formatted = formatted[..dot].to_string();\n            }\n        }\n        formatted\n    }\n\n    /// Converts wei into an eth amount\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// use cast::SimpleCast as Cast;\n    ///\n    /// assert_eq!(Cast::from_wei(\"1\", \"gwei\")?, \"0.000000001\");\n    /// assert_eq!(Cast::from_wei(\"12340000005\", \"gwei\")?, \"12.340000005\");\n    /// assert_eq!(Cast::from_wei(\"10\", \"ether\")?, \"0.000000000000000010\");\n    /// assert_eq!(Cast::from_wei(\"100\", \"eth\")?, \"0.000000000000000100\");\n    /// assert_eq!(Cast::from_wei(\"17\", \"ether\")?, \"0.000000000000000017\");\n    /// # Ok::<_, eyre::Report>(())\n    /// ```\n    pub fn from_wei(value: &str, unit: &str) -> Result<String> {\n        let value = NumberWithBase::parse_int(value, None)?.number();\n        Ok(ParseUnits::U256(value).format_units(unit.parse()?))\n    }\n\n    /// Converts an eth amount into wei\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// use cast::SimpleCast as Cast;\n    ///\n    /// assert_eq!(Cast::to_wei(\"100\", \"gwei\")?, \"100000000000\");\n    /// assert_eq!(Cast::to_wei(\"100\", \"eth\")?, \"100000000000000000000\");\n    /// assert_eq!(Cast::to_wei(\"1000\", \"ether\")?, \"1000000000000000000000\");\n    /// # Ok::<_, eyre::Report>(())\n    /// ```\n    pub fn to_wei(value: &str, unit: &str) -> Result<String> {\n        let unit = unit.parse().wrap_err(\"could not parse units\")?;\n        Ok(ParseUnits::parse_units(value, unit)?.to_string())\n    }\n\n    // Decodes RLP encoded data with validation for canonical integer representation\n    ///\n    /// # Examples\n    /// ```\n    /// use cast::SimpleCast as Cast;\n    ///\n    /// assert_eq!(Cast::from_rlp(\"0xc0\", false).unwrap(), \"[]\");\n    /// assert_eq!(Cast::from_rlp(\"0x0f\", false).unwrap(), \"\\\"0x0f\\\"\");\n    /// assert_eq!(Cast::from_rlp(\"0x33\", false).unwrap(), \"\\\"0x33\\\"\");\n    /// assert_eq!(Cast::from_rlp(\"0xc161\", false).unwrap(), \"[\\\"0x61\\\"]\");\n    /// assert_eq!(Cast::from_rlp(\"820002\", true).is_err(), true);\n    /// assert_eq!(Cast::from_rlp(\"820002\", false).unwrap(), \"\\\"0x0002\\\"\");\n    /// assert_eq!(Cast::from_rlp(\"00\", true).is_err(), true);\n    /// assert_eq!(Cast::from_rlp(\"00\", false).unwrap(), \"\\\"0x00\\\"\");\n    /// # Ok::<_, eyre::Report>(())\n    /// ```\n    pub fn from_rlp(value: impl AsRef<str>, as_int: bool) -> Result<String> {\n        let bytes = hex::decode(value.as_ref()).wrap_err(\"Could not decode hex\")?;\n\n        if as_int {\n            return Ok(U256::decode(&mut &bytes[..])?.to_string());\n        }\n\n        let item = Item::decode(&mut &bytes[..]).wrap_err(\"Could not decode rlp\")?;\n\n        Ok(item.to_string())\n    }\n\n    /// Encodes hex data or list of hex data to hexadecimal rlp\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// use cast::SimpleCast as Cast;\n    ///\n    /// assert_eq!(Cast::to_rlp(\"[]\").unwrap(), \"0xc0\".to_string());\n    /// assert_eq!(Cast::to_rlp(\"0x22\").unwrap(), \"0x22\".to_string());\n    /// assert_eq!(Cast::to_rlp(\"[\\\"0x61\\\"]\",).unwrap(), \"0xc161\".to_string());\n    /// assert_eq!(Cast::to_rlp(\"[\\\"0xf1\\\", \\\"f2\\\"]\").unwrap(), \"0xc481f181f2\".to_string());\n    /// # Ok::<_, eyre::Report>(())\n    /// ```\n    pub fn to_rlp(value: &str) -> Result<String> {\n        let val = serde_json::from_str(value)\n            .unwrap_or_else(|_| serde_json::Value::String(value.to_string()));\n        let item = Item::value_to_item(&val)?;\n        Ok(format!(\"0x{}\", hex::encode(alloy_rlp::encode(item))))\n    }\n\n    /// Converts a number of one base to another\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// use alloy_primitives::I256;\n    /// use cast::SimpleCast as Cast;\n    ///\n    /// assert_eq!(Cast::to_base(\"100\", Some(\"10\"), \"16\")?, \"0x64\");\n    /// assert_eq!(Cast::to_base(\"100\", Some(\"10\"), \"oct\")?, \"0o144\");\n    /// assert_eq!(Cast::to_base(\"100\", Some(\"10\"), \"binary\")?, \"0b1100100\");\n    ///\n    /// assert_eq!(Cast::to_base(\"0xffffffffffffffff\", None, \"10\")?, u64::MAX.to_string());\n    /// assert_eq!(\n    ///     Cast::to_base(\"0xffffffffffffffffffffffffffffffff\", None, \"dec\")?,\n    ///     u128::MAX.to_string()\n    /// );\n    /// // U256::MAX overflows as internally it is being parsed as I256\n    /// assert_eq!(\n    ///     Cast::to_base(\n    ///         \"0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\",\n    ///         None,\n    ///         \"decimal\"\n    ///     )?,\n    ///     I256::MAX.to_string()\n    /// );\n    /// # Ok::<_, eyre::Report>(())\n    /// ```\n    pub fn to_base(value: &str, base_in: Option<&str>, base_out: &str) -> Result<String> {\n        let base_in = Base::unwrap_or_detect(base_in, value)?;\n        let base_out: Base = base_out.parse()?;\n        if base_in == base_out {\n            return Ok(value.to_string());\n        }\n\n        let mut n = NumberWithBase::parse_int(value, Some(&base_in.to_string()))?;\n        n.set_base(base_out);\n\n        // Use Debug fmt\n        Ok(format!(\"{n:#?}\"))\n    }\n\n    /// Converts hexdata into bytes32 value\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// use cast::SimpleCast as Cast;\n    ///\n    /// let bytes = Cast::to_bytes32(\"1234\")?;\n    /// assert_eq!(bytes, \"0x1234000000000000000000000000000000000000000000000000000000000000\");\n    ///\n    /// let bytes = Cast::to_bytes32(\"0x1234\")?;\n    /// assert_eq!(bytes, \"0x1234000000000000000000000000000000000000000000000000000000000000\");\n    ///\n    /// let err = Cast::to_bytes32(\"0x123400000000000000000000000000000000000000000000000000000000000011\").unwrap_err();\n    /// assert_eq!(err.to_string(), \"string >32 bytes\");\n    /// # Ok::<_, eyre::Report>(())\n    pub fn to_bytes32(s: &str) -> Result<String> {\n        let s = strip_0x(s);\n        if s.len() > 64 {\n            eyre::bail!(\"string >32 bytes\");\n        }\n\n        let padded = format!(\"{s:0<64}\");\n        Ok(padded.parse::<B256>()?.to_string())\n    }\n\n    /// Encodes string into bytes32 value\n    pub fn format_bytes32_string(s: &str) -> Result<String> {\n        let str_bytes: &[u8] = s.as_bytes();\n        eyre::ensure!(str_bytes.len() <= 32, \"bytes32 strings must not exceed 32 bytes in length\");\n\n        let mut bytes32: [u8; 32] = [0u8; 32];\n        bytes32[..str_bytes.len()].copy_from_slice(str_bytes);\n        Ok(hex::encode_prefixed(bytes32))\n    }\n\n    /// Pads hex data to a specified length\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// use cast::SimpleCast as Cast;\n    ///\n    /// let padded = Cast::pad(\"abcd\", true, 20)?;\n    /// assert_eq!(padded, \"0xabcd000000000000000000000000000000000000\");\n    ///\n    /// let padded = Cast::pad(\"abcd\", false, 20)?;\n    /// assert_eq!(padded, \"0x000000000000000000000000000000000000abcd\");\n    ///\n    /// let padded = Cast::pad(\"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\", true, 32)?;\n    /// assert_eq!(padded, \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2000000000000000000000000\");\n    ///\n    /// let padded = Cast::pad(\"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\", false, 32)?;\n    /// assert_eq!(padded, \"0x000000000000000000000000C02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\");\n    ///\n    /// let err = Cast::pad(\"1234\", false, 1).unwrap_err();\n    /// assert_eq!(err.to_string(), \"input length exceeds target length\");\n    ///\n    /// let err = Cast::pad(\"foobar\", false, 32).unwrap_err();\n    /// assert_eq!(err.to_string(), \"input is not a valid hex\");\n    ///\n    /// # Ok::<_, eyre::Report>(())\n    /// ```\n    pub fn pad(s: &str, right: bool, len: usize) -> Result<String> {\n        let s = strip_0x(s);\n        let hex_len = len * 2;\n\n        // Validate input\n        if s.len() > hex_len {\n            eyre::bail!(\"input length exceeds target length\");\n        }\n        if !s.chars().all(|c| c.is_ascii_hexdigit()) {\n            eyre::bail!(\"input is not a valid hex\");\n        }\n\n        Ok(if right { format!(\"0x{s:0<hex_len$}\") } else { format!(\"0x{s:0>hex_len$}\") })\n    }\n\n    /// Decodes string from bytes32 value\n    pub fn parse_bytes32_string(s: &str) -> Result<String> {\n        let bytes = hex::decode(s)?;\n        eyre::ensure!(bytes.len() == 32, \"expected 32 byte hex-string\");\n        let len = bytes.iter().take_while(|x| **x != 0).count();\n        Ok(std::str::from_utf8(&bytes[..len])?.into())\n    }\n\n    /// Decodes checksummed address from bytes32 value\n    pub fn parse_bytes32_address(s: &str) -> Result<String> {\n        let s = strip_0x(s);\n        if s.len() != 64 {\n            eyre::bail!(\"expected 64 byte hex-string, got {s}\");\n        }\n\n        let s = if let Some(stripped) = s.strip_prefix(\"000000000000000000000000\") {\n            stripped\n        } else {\n            return Err(eyre::eyre!(\"Not convertible to address, there are non-zero bytes\"));\n        };\n\n        let lowercase_address_string = format!(\"0x{s}\");\n        let lowercase_address = Address::from_str(&lowercase_address_string)?;\n\n        Ok(lowercase_address.to_checksum(None))\n    }\n\n    /// Decodes abi-encoded hex input or output\n    ///\n    /// When `input=true`, `calldata` string MUST not be prefixed with function selector\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// use cast::SimpleCast as Cast;\n    /// use alloy_primitives::hex;\n    ///\n    ///     // Passing `input = false` will decode the data as the output type.\n    ///     // The input data types and the full function sig are ignored, i.e.\n    ///     // you could also pass `balanceOf()(uint256)` and it'd still work.\n    ///     let data = \"0x0000000000000000000000000000000000000000000000000000000000000001\";\n    ///     let sig = \"balanceOf(address, uint256)(uint256)\";\n    ///     let decoded = Cast::abi_decode(sig, data, false)?[0].as_uint().unwrap().0.to_string();\n    ///     assert_eq!(decoded, \"1\");\n    ///\n    ///     // Passing `input = true` will decode the data with the input function signature.\n    ///     // We exclude the \"prefixed\" function selector from the data field (the first 4 bytes).\n    ///     let data = \"0x0000000000000000000000008dbd1b711dc621e1404633da156fcc779e1c6f3e000000000000000000000000d9f3c9cc99548bf3b44a43e0a2d07399eb918adc000000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000\";\n    ///     let sig = \"safeTransferFrom(address, address, uint256, uint256, bytes)\";\n    ///     let decoded = Cast::abi_decode(sig, data, true)?;\n    ///     let decoded = [\n    ///         decoded[0].as_address().unwrap().to_string().to_lowercase(),\n    ///         decoded[1].as_address().unwrap().to_string().to_lowercase(),\n    ///         decoded[2].as_uint().unwrap().0.to_string(),\n    ///         decoded[3].as_uint().unwrap().0.to_string(),\n    ///         hex::encode(decoded[4].as_bytes().unwrap())\n    ///     ]\n    ///     .into_iter()\n    ///     .collect::<Vec<_>>();\n    ///\n    ///     assert_eq!(\n    ///         decoded,\n    ///         vec![\"0x8dbd1b711dc621e1404633da156fcc779e1c6f3e\", \"0xd9f3c9cc99548bf3b44a43e0a2d07399eb918adc\", \"42\", \"1\", \"\"]\n    ///     );\n    /// # Ok::<_, eyre::Report>(())\n    /// ```\n    pub fn abi_decode(sig: &str, calldata: &str, input: bool) -> Result<Vec<DynSolValue>> {\n        foundry_common::abi::abi_decode_calldata(sig, calldata, input, false)\n    }\n\n    /// Decodes calldata-encoded hex input or output\n    ///\n    /// Similar to `abi_decode`, but `calldata` string MUST be prefixed with function selector\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// use cast::SimpleCast as Cast;\n    /// use alloy_primitives::hex;\n    ///\n    /// // Passing `input = false` will decode the data as the output type.\n    /// // The input data types and the full function sig are ignored, i.e.\n    /// // you could also pass `balanceOf()(uint256)` and it'd still work.\n    /// let data = \"0x0000000000000000000000000000000000000000000000000000000000000001\";\n    /// let sig = \"balanceOf(address, uint256)(uint256)\";\n    /// let decoded = Cast::calldata_decode(sig, data, false)?[0].as_uint().unwrap().0.to_string();\n    /// assert_eq!(decoded, \"1\");\n    ///\n    ///     // Passing `input = true` will decode the data with the input function signature.\n    ///     let data = \"0xf242432a0000000000000000000000008dbd1b711dc621e1404633da156fcc779e1c6f3e000000000000000000000000d9f3c9cc99548bf3b44a43e0a2d07399eb918adc000000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000\";\n    ///     let sig = \"safeTransferFrom(address, address, uint256, uint256, bytes)\";\n    ///     let decoded = Cast::calldata_decode(sig, data, true)?;\n    ///     let decoded = [\n    ///         decoded[0].as_address().unwrap().to_string().to_lowercase(),\n    ///         decoded[1].as_address().unwrap().to_string().to_lowercase(),\n    ///         decoded[2].as_uint().unwrap().0.to_string(),\n    ///         decoded[3].as_uint().unwrap().0.to_string(),\n    ///         hex::encode(decoded[4].as_bytes().unwrap()),\n    ///    ]\n    ///    .into_iter()\n    ///    .collect::<Vec<_>>();\n    ///     assert_eq!(\n    ///         decoded,\n    ///         vec![\"0x8dbd1b711dc621e1404633da156fcc779e1c6f3e\", \"0xd9f3c9cc99548bf3b44a43e0a2d07399eb918adc\", \"42\", \"1\", \"\"]\n    ///     );\n    /// # Ok::<_, eyre::Report>(())\n    /// ```\n    pub fn calldata_decode(sig: &str, calldata: &str, input: bool) -> Result<Vec<DynSolValue>> {\n        foundry_common::abi::abi_decode_calldata(sig, calldata, input, true)\n    }\n\n    /// Performs ABI encoding based off of the function signature. Does not include\n    /// the function selector in the result.\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// use cast::SimpleCast as Cast;\n    ///\n    /// assert_eq!(\n    ///     \"0x0000000000000000000000000000000000000000000000000000000000000001\",\n    ///     Cast::abi_encode(\"f(uint a)\", &[\"1\"]).unwrap().as_str()\n    /// );\n    /// assert_eq!(\n    ///     \"0x0000000000000000000000000000000000000000000000000000000000000001\",\n    ///     Cast::abi_encode(\"constructor(uint a)\", &[\"1\"]).unwrap().as_str()\n    /// );\n    /// # Ok::<_, eyre::Report>(())\n    /// ```\n    pub fn abi_encode(sig: &str, args: &[impl AsRef<str>]) -> Result<String> {\n        let func = get_func(sig)?;\n        match encode_function_args(&func, args) {\n            Ok(res) => Ok(hex::encode_prefixed(&res[4..])),\n            Err(e) => eyre::bail!(\"Could not ABI encode the function and arguments: {e}\"),\n        }\n    }\n\n    /// Performs packed ABI encoding based off of the function signature or tuple.\n    ///\n    /// # Examplez\n    ///\n    /// ```\n    /// use cast::SimpleCast as Cast;\n    ///\n    /// assert_eq!(\n    ///     \"0x0000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000000012c00000000000000c8\",\n    ///     Cast::abi_encode_packed(\"(uint128[] a, uint64 b)\", &[\"[100, 300]\", \"200\"]).unwrap().as_str()\n    /// );\n    ///\n    /// assert_eq!(\n    ///     \"0x8dbd1b711dc621e1404633da156fcc779e1c6f3e68656c6c6f20776f726c64\",\n    ///     Cast::abi_encode_packed(\"foo(address a, string b)\", &[\"0x8dbd1b711dc621e1404633da156fcc779e1c6f3e\", \"hello world\"]).unwrap().as_str()\n    /// );\n    /// # Ok::<_, eyre::Report>(())\n    /// ```\n    pub fn abi_encode_packed(sig: &str, args: &[impl AsRef<str>]) -> Result<String> {\n        // If the signature is a tuple, we need to prefix it to make it a function\n        let sig =\n            if sig.trim_start().starts_with('(') { format!(\"foo{sig}\") } else { sig.to_string() };\n\n        let func = get_func(sig.as_str())?;\n        let encoded = match encode_function_args_packed(&func, args) {\n            Ok(res) => hex::encode(res),\n            Err(e) => eyre::bail!(\"Could not ABI encode the function and arguments: {e}\"),\n        };\n        Ok(format!(\"0x{encoded}\"))\n    }\n\n    /// Performs ABI encoding of an event to produce the topics and data.\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// use alloy_primitives::hex;\n    /// use cast::SimpleCast as Cast;\n    ///\n    /// let log_data = Cast::abi_encode_event(\n    ///     \"Transfer(address indexed from, address indexed to, uint256 value)\",\n    ///     &[\n    ///         \"0x1234567890123456789012345678901234567890\",\n    ///         \"0xabcdefabcdefabcdefabcdefabcdefabcdefabcd\",\n    ///         \"1000\",\n    ///     ],\n    /// )\n    /// .unwrap();\n    ///\n    /// // topic0 is the event selector\n    /// assert_eq!(log_data.topics().len(), 3);\n    /// assert_eq!(\n    ///     log_data.topics()[0].to_string(),\n    ///     \"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef\"\n    /// );\n    /// assert_eq!(\n    ///     log_data.topics()[1].to_string(),\n    ///     \"0x0000000000000000000000001234567890123456789012345678901234567890\"\n    /// );\n    /// assert_eq!(\n    ///     log_data.topics()[2].to_string(),\n    ///     \"0x000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd\"\n    /// );\n    /// assert_eq!(\n    ///     hex::encode_prefixed(log_data.data),\n    ///     \"0x00000000000000000000000000000000000000000000000000000000000003e8\"\n    /// );\n    /// # Ok::<_, eyre::Report>(())\n    /// ```\n    pub fn abi_encode_event(sig: &str, args: &[impl AsRef<str>]) -> Result<LogData> {\n        let event = get_event(sig)?;\n        let tokens = std::iter::zip(&event.inputs, args)\n            .map(|(input, arg)| coerce_value(&input.ty, arg.as_ref()))\n            .collect::<Result<Vec<_>>>()?;\n\n        let mut topics = vec![event.selector()];\n        let mut data_tokens: Vec<u8> = Vec::new();\n\n        for (input, token) in event.inputs.iter().zip(tokens) {\n            if input.indexed {\n                let ty = DynSolType::parse(&input.ty)?;\n                if matches!(\n                    ty,\n                    DynSolType::String\n                        | DynSolType::Bytes\n                        | DynSolType::Array(_)\n                        | DynSolType::Tuple(_)\n                ) {\n                    // For dynamic types, hash the encoded value\n                    let encoded = token.abi_encode();\n                    let hash = keccak256(encoded);\n                    topics.push(hash);\n                } else {\n                    // For fixed-size types, encode directly to 32 bytes\n                    let mut encoded = [0u8; 32];\n                    let token_encoded = token.abi_encode();\n                    if token_encoded.len() <= 32 {\n                        let start = 32 - token_encoded.len();\n                        encoded[start..].copy_from_slice(&token_encoded);\n                    }\n                    topics.push(B256::from(encoded));\n                }\n            } else {\n                // Non-indexed parameters go into data\n                data_tokens.extend_from_slice(&token.abi_encode());\n            }\n        }\n\n        Ok(LogData::new_unchecked(topics, data_tokens.into()))\n    }\n\n    /// Performs ABI encoding to produce the hexadecimal calldata with the given arguments.\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// use cast::SimpleCast as Cast;\n    ///\n    /// assert_eq!(\n    ///     \"0xb3de648b0000000000000000000000000000000000000000000000000000000000000001\",\n    ///     Cast::calldata_encode(\"f(uint256 a)\", &[\"1\"]).unwrap().as_str()\n    /// );\n    /// # Ok::<_, eyre::Report>(())\n    /// ```\n    pub fn calldata_encode(sig: impl AsRef<str>, args: &[impl AsRef<str>]) -> Result<String> {\n        let func = get_func(sig.as_ref())?;\n        let calldata = encode_function_args(&func, args)?;\n        Ok(hex::encode_prefixed(calldata))\n    }\n\n    /// Returns the slot number for a given mapping key and slot.\n    ///\n    /// Given `mapping(k => v) m`, for a key `k` the slot number of its associated `v` is\n    /// `keccak256(concat(h(k), p))`, where `h` is the padding function for `k`'s type, and `p`\n    /// is slot number of the mapping `m`.\n    ///\n    /// See [the Solidity documentation](https://docs.soliditylang.org/en/latest/internals/layout_in_storage.html#mappings-and-dynamic-arrays)\n    /// for more details.\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// # use cast::SimpleCast as Cast;\n    ///\n    /// // Value types.\n    /// assert_eq!(\n    ///     Cast::index(\"address\", \"0xD0074F4E6490ae3f888d1d4f7E3E43326bD3f0f5\", \"2\").unwrap().as_str(),\n    ///     \"0x9525a448a9000053a4d151336329d6563b7e80b24f8e628e95527f218e8ab5fb\"\n    /// );\n    /// assert_eq!(\n    ///     Cast::index(\"uint256\", \"42\", \"6\").unwrap().as_str(),\n    ///     \"0xfc808b0f31a1e6b9cf25ff6289feae9b51017b392cc8e25620a94a38dcdafcc1\"\n    /// );\n    ///\n    /// // Strings and byte arrays.\n    /// assert_eq!(\n    ///     Cast::index(\"string\", \"hello\", \"1\").unwrap().as_str(),\n    ///     \"0x8404bb4d805e9ca2bd5dd5c43a107e935c8ec393caa7851b353b3192cd5379ae\"\n    /// );\n    /// # Ok::<_, eyre::Report>(())\n    /// ```\n    pub fn index(key_type: &str, key: &str, slot_number: &str) -> Result<String> {\n        let mut hasher = Keccak256::new();\n\n        let k_ty = DynSolType::parse(key_type).wrap_err(\"Could not parse type\")?;\n        let k = k_ty.coerce_str(key).wrap_err(\"Could not parse value\")?;\n        match k_ty {\n            // For value types, `h` pads the value to 32 bytes in the same way as when storing the\n            // value in memory.\n            DynSolType::Bool\n            | DynSolType::Int(_)\n            | DynSolType::Uint(_)\n            | DynSolType::FixedBytes(_)\n            | DynSolType::Address\n            | DynSolType::Function => hasher.update(k.as_word().unwrap()),\n\n            // For strings and byte arrays, `h(k)` is just the unpadded data.\n            DynSolType::String | DynSolType::Bytes => hasher.update(k.as_packed_seq().unwrap()),\n\n            DynSolType::Array(..)\n            | DynSolType::FixedArray(..)\n            | DynSolType::Tuple(..)\n            | DynSolType::CustomStruct { .. } => {\n                eyre::bail!(\"Type `{k_ty}` is not supported as a mapping key\")\n            }\n        }\n\n        let p = DynSolType::Uint(256)\n            .coerce_str(slot_number)\n            .wrap_err(\"Could not parse slot number\")?;\n        let p = p.as_word().unwrap();\n        hasher.update(p);\n\n        let location = hasher.finalize();\n        Ok(location.to_string())\n    }\n\n    /// Keccak-256 hashes arbitrary data\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// use cast::SimpleCast as Cast;\n    ///\n    /// assert_eq!(\n    ///     Cast::keccak(\"foo\")?,\n    ///     \"0x41b1a0649752af1b28b3dc29a1556eee781e4a4c3a1f7f53f90fa834de098c4d\"\n    /// );\n    /// assert_eq!(\n    ///     Cast::keccak(\"123abc\")?,\n    ///     \"0xb1f1c74a1ba56f07a892ea1110a39349d40f66ca01d245e704621033cb7046a4\"\n    /// );\n    /// assert_eq!(\n    ///     Cast::keccak(\"0x12\")?,\n    ///     \"0x5fa2358263196dbbf23d1ca7a509451f7a2f64c15837bfbb81298b1e3e24e4fa\"\n    /// );\n    /// assert_eq!(\n    ///     Cast::keccak(\"12\")?,\n    ///     \"0x7f8b6b088b6d74c2852fc86c796dca07b44eed6fb3daf5e6b59f7c364db14528\"\n    /// );\n    /// # Ok::<_, eyre::Report>(())\n    /// ```\n    pub fn keccak(data: &str) -> Result<String> {\n        // Hex-decode if data starts with 0x.\n        let hash = if data.starts_with(\"0x\") {\n            keccak256(hex::decode(data.trim_end())?)\n        } else {\n            keccak256(data)\n        };\n        Ok(hash.to_string())\n    }\n\n    /// Performs the left shift operation (<<) on a number\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// use cast::SimpleCast as Cast;\n    ///\n    /// assert_eq!(Cast::left_shift(\"16\", \"10\", Some(\"10\"), \"hex\")?, \"0x4000\");\n    /// assert_eq!(Cast::left_shift(\"255\", \"16\", Some(\"dec\"), \"hex\")?, \"0xff0000\");\n    /// assert_eq!(Cast::left_shift(\"0xff\", \"16\", None, \"hex\")?, \"0xff0000\");\n    /// # Ok::<_, eyre::Report>(())\n    /// ```\n    pub fn left_shift(\n        value: &str,\n        bits: &str,\n        base_in: Option<&str>,\n        base_out: &str,\n    ) -> Result<String> {\n        let base_out: Base = base_out.parse()?;\n        let value = NumberWithBase::parse_uint(value, base_in)?;\n        let bits = NumberWithBase::parse_uint(bits, None)?;\n\n        let res = value.number() << bits.number();\n\n        Ok(res.to_base(base_out, true)?)\n    }\n\n    /// Performs the right shift operation (>>) on a number\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// use cast::SimpleCast as Cast;\n    ///\n    /// assert_eq!(Cast::right_shift(\"0x4000\", \"10\", None, \"dec\")?, \"16\");\n    /// assert_eq!(Cast::right_shift(\"16711680\", \"16\", Some(\"10\"), \"hex\")?, \"0xff\");\n    /// assert_eq!(Cast::right_shift(\"0xff0000\", \"16\", None, \"hex\")?, \"0xff\");\n    /// # Ok::<(), eyre::Report>(())\n    /// ```\n    pub fn right_shift(\n        value: &str,\n        bits: &str,\n        base_in: Option<&str>,\n        base_out: &str,\n    ) -> Result<String> {\n        let base_out: Base = base_out.parse()?;\n        let value = NumberWithBase::parse_uint(value, base_in)?;\n        let bits = NumberWithBase::parse_uint(bits, None)?;\n\n        let res = value.number().wrapping_shr(bits.number().saturating_to());\n\n        Ok(res.to_base(base_out, true)?)\n    }\n\n    /// Fetches source code of verified contracts from etherscan.\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// # use cast::SimpleCast as Cast;\n    /// # use foundry_config::NamedChain;\n    /// # async fn foo() -> eyre::Result<()> {\n    /// assert_eq!(\n    ///     \"/*\n    ///             - Bytecode Verification performed was compared on second iteration -\n    ///             This file is part of the DAO.....\",\n    ///     Cast::etherscan_source(\n    ///         NamedChain::Mainnet.into(),\n    ///         \"0xBB9bc244D798123fDe783fCc1C72d3Bb8C189413\".to_string(),\n    ///         Some(\"<etherscan_api_key>\".to_string()),\n    ///         None,\n    ///         None\n    ///     )\n    ///     .await\n    ///     .unwrap()\n    ///     .as_str()\n    /// );\n    /// # Ok(())\n    /// # }\n    /// ```\n    pub async fn etherscan_source(\n        chain: Chain,\n        contract_address: String,\n        etherscan_api_key: Option<String>,\n        explorer_api_url: Option<String>,\n        explorer_url: Option<String>,\n    ) -> Result<String> {\n        let client = explorer_client(chain, etherscan_api_key, explorer_api_url, explorer_url)?;\n        let metadata = client.contract_source_code(contract_address.parse()?).await?;\n        Ok(metadata.source_code())\n    }\n\n    /// Fetches the source code of verified contracts from etherscan and expands the resulting\n    /// files to a directory for easy perusal.\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// # use cast::SimpleCast as Cast;\n    /// # use foundry_config::NamedChain;\n    /// # use std::path::PathBuf;\n    /// # async fn expand() -> eyre::Result<()> {\n    /// Cast::expand_etherscan_source_to_directory(\n    ///     NamedChain::Mainnet.into(),\n    ///     \"0xBB9bc244D798123fDe783fCc1C72d3Bb8C189413\".to_string(),\n    ///     Some(\"<etherscan_api_key>\".to_string()),\n    ///     PathBuf::from(\"output_dir\"),\n    ///     None,\n    ///     None,\n    /// )\n    /// .await?;\n    /// # Ok(())\n    /// # }\n    /// ```\n    pub async fn expand_etherscan_source_to_directory(\n        chain: Chain,\n        contract_address: String,\n        etherscan_api_key: Option<String>,\n        output_directory: PathBuf,\n        explorer_api_url: Option<String>,\n        explorer_url: Option<String>,\n    ) -> eyre::Result<()> {\n        let client = explorer_client(chain, etherscan_api_key, explorer_api_url, explorer_url)?;\n        let meta = client.contract_source_code(contract_address.parse()?).await?;\n        let source_tree = meta.source_tree();\n        source_tree.write_to(&output_directory)?;\n        Ok(())\n    }\n\n    /// Fetches the source code of verified contracts from etherscan, flattens it and writes it to\n    /// the given path or stdout.\n    pub async fn etherscan_source_flatten(\n        chain: Chain,\n        contract_address: String,\n        etherscan_api_key: Option<String>,\n        output_path: Option<PathBuf>,\n        explorer_api_url: Option<String>,\n        explorer_url: Option<String>,\n    ) -> Result<()> {\n        let client = explorer_client(chain, etherscan_api_key, explorer_api_url, explorer_url)?;\n        let metadata = client.contract_source_code(contract_address.parse()?).await?;\n        let Some(metadata) = metadata.items.first() else {\n            eyre::bail!(\"Empty contract source code\")\n        };\n\n        let tmp = tempfile::tempdir()?;\n        let project = etherscan_project(metadata, tmp.path())?;\n        let target_path = project.find_contract_path(&metadata.contract_name)?;\n\n        let flattened = flatten(project, &target_path)?;\n\n        if let Some(path) = output_path {\n            fs::create_dir_all(path.parent().unwrap())?;\n            fs::write(&path, flattened)?;\n            sh_println!(\"Flattened file written at {}\", path.display())?\n        } else {\n            sh_println!(\"{flattened}\")?\n        }\n\n        Ok(())\n    }\n\n    /// Disassembles hex encoded bytecode into individual / human readable opcodes\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// use alloy_primitives::hex;\n    /// use cast::SimpleCast as Cast;\n    ///\n    /// # async fn foo() -> eyre::Result<()> {\n    /// let bytecode = \"0x608060405260043610603f57600035\";\n    /// let opcodes = Cast::disassemble(&hex::decode(bytecode)?)?;\n    /// println!(\"{}\", opcodes);\n    /// # Ok(())\n    /// # }\n    /// ```\n    pub fn disassemble(code: &[u8]) -> Result<String> {\n        let mut output = String::new();\n        for (pc, inst) in InstIter::new(code).with_pc() {\n            writeln!(output, \"{pc:08x}: {inst}\")?;\n        }\n        Ok(output)\n    }\n\n    /// Gets the selector for a given function signature\n    /// Optimizes if the `optimize` parameter is set to a number of leading zeroes\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// use cast::SimpleCast as Cast;\n    ///\n    /// assert_eq!(Cast::get_selector(\"foo(address,uint256)\", 0)?.0, String::from(\"0xbd0d639f\"));\n    /// # Ok::<(), eyre::Error>(())\n    /// ```\n    pub fn get_selector(signature: &str, optimize: usize) -> Result<(String, String)> {\n        if optimize > 4 {\n            eyre::bail!(\"number of leading zeroes must not be greater than 4\");\n        }\n        if optimize == 0 {\n            let selector = get_func(signature)?.selector();\n            return Ok((selector.to_string(), String::from(signature)));\n        }\n        let Some((name, params)) = signature.split_once('(') else {\n            eyre::bail!(\"invalid function signature\");\n        };\n\n        let num_threads = rayon::current_num_threads();\n        let found = AtomicBool::new(false);\n\n        let result: Option<(u32, String, String)> =\n            (0..num_threads).into_par_iter().find_map_any(|i| {\n                let nonce_start = i as u32;\n                let nonce_step = num_threads as u32;\n\n                let mut nonce = nonce_start;\n                while nonce < u32::MAX && !found.load(Ordering::Relaxed) {\n                    let input = format!(\"{name}{nonce}({params}\");\n                    let hash = keccak256(input.as_bytes());\n                    let selector = &hash[..4];\n\n                    if selector.iter().take_while(|&&byte| byte == 0).count() == optimize {\n                        found.store(true, Ordering::Relaxed);\n                        return Some((nonce, hex::encode_prefixed(selector), input));\n                    }\n\n                    nonce += nonce_step;\n                }\n                None\n            });\n\n        match result {\n            Some((_nonce, selector, signature)) => Ok((selector, signature)),\n            None => eyre::bail!(\"No selector found\"),\n        }\n    }\n\n    /// Extracts function selectors, arguments and state mutability from bytecode\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// use alloy_primitives::fixed_bytes;\n    /// use cast::SimpleCast as Cast;\n    ///\n    /// let bytecode = \"6080604052348015600e575f80fd5b50600436106026575f3560e01c80632125b65b14602a575b5f80fd5b603a6035366004603c565b505050565b005b5f805f60608486031215604d575f80fd5b833563ffffffff81168114605f575f80fd5b925060208401356001600160a01b03811681146079575f80fd5b915060408401356001600160e01b03811681146093575f80fd5b80915050925092509256\";\n    /// let functions = Cast::extract_functions(bytecode)?;\n    /// assert_eq!(functions, vec![(fixed_bytes!(\"0x2125b65b\"), \"uint32,address,uint224\".to_string(), \"pure\")]);\n    /// # Ok::<(), eyre::Report>(())\n    /// ```\n    pub fn extract_functions(bytecode: &str) -> Result<Vec<(Selector, String, &str)>> {\n        let code = hex::decode(bytecode)?;\n        let info = evmole::contract_info(\n            evmole::ContractInfoArgs::new(&code)\n                .with_selectors()\n                .with_arguments()\n                .with_state_mutability(),\n        );\n        Ok(info\n            .functions\n            .expect(\"functions extraction was requested\")\n            .into_iter()\n            .map(|f| {\n                (\n                    f.selector.into(),\n                    f.arguments\n                        .expect(\"arguments extraction was requested\")\n                        .into_iter()\n                        .map(|t| t.sol_type_name().to_string())\n                        .collect::<Vec<String>>()\n                        .join(\",\"),\n                    f.state_mutability\n                        .expect(\"state_mutability extraction was requested\")\n                        .as_json_str(),\n                )\n            })\n            .collect())\n    }\n\n    /// Decodes a raw EIP2718 transaction payload\n    /// Returns details about the typed transaction and ECSDA signature components\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// use cast::SimpleCast as Cast;\n    ///\n    /// let tx = \"0x02f8f582a86a82058d8459682f008508351050808303fd84948e42f2f4101563bf679975178e880fd87d3efd4e80b884659ac74b00000000000000000000000080f0c1c49891dcfdd40b6e0f960f84e6042bcb6f000000000000000000000000b97ef9ef8734c71904d8002f8b6bc66dd9c48a6e00000000000000000000000000000000000000000000000000000000007ff4e20000000000000000000000000000000000000000000000000000000000000064c001a05d429597befe2835396206781b199122f2e8297327ed4a05483339e7a8b2022aa04c23a7f70fb29dda1b4ee342fb10a625e9b8ddc6a603fb4e170d4f6f37700cb8\";\n    /// let tx_envelope = Cast::decode_raw_transaction(&tx)?;\n    /// # Ok::<(), eyre::Report>(())\n    pub fn decode_raw_transaction(tx: &str) -> Result<FoundryTxEnvelope> {\n        let tx_hex = hex::decode(tx)?;\n        let tx = Decodable2718::decode_2718(&mut tx_hex.as_slice())?;\n        Ok(tx)\n    }\n}\n\npub(crate) fn strip_0x(s: &str) -> &str {\n    s.strip_prefix(\"0x\").unwrap_or(s)\n}\n\nfn explorer_client(\n    chain: Chain,\n    api_key: Option<String>,\n    api_url: Option<String>,\n    explorer_url: Option<String>,\n) -> Result<Client> {\n    let mut builder = Client::builder();\n\n    let deduced = chain.etherscan_urls();\n\n    let explorer_url = explorer_url\n        .or(deduced.map(|d| d.1.to_string()))\n        .ok_or_eyre(\"Please provide the explorer browser URL using `--explorer-url`\")?;\n    builder = builder.with_url(explorer_url)?;\n\n    let api_url = api_url\n        .or(deduced.map(|d| d.0.to_string()))\n        .ok_or_eyre(\"Please provide the explorer API URL using `--explorer-api-url`\")?;\n    builder = builder.with_api_url(api_url)?;\n\n    if let Some(api_key) = api_key {\n        builder = builder.with_api_key(api_key);\n    }\n\n    builder.build().map_err(Into::into)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::{DynSolValue, SimpleCast as Cast, serialize_value_as_json};\n    use alloy_primitives::hex;\n\n    #[test]\n    fn simple_selector() {\n        assert_eq!(\"0xc2985578\", Cast::get_selector(\"foo()\", 0).unwrap().0.as_str())\n    }\n\n    #[test]\n    fn selector_with_arg() {\n        assert_eq!(\"0xbd0d639f\", Cast::get_selector(\"foo(address,uint256)\", 0).unwrap().0.as_str())\n    }\n\n    #[test]\n    fn calldata_uint() {\n        assert_eq!(\n            \"0xb3de648b0000000000000000000000000000000000000000000000000000000000000001\",\n            Cast::calldata_encode(\"f(uint256 a)\", &[\"1\"]).unwrap().as_str()\n        );\n    }\n\n    // <https://github.com/foundry-rs/foundry/issues/2681>\n    #[test]\n    fn calldata_array() {\n        assert_eq!(\n            \"0xcde2baba0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000\",\n            Cast::calldata_encode(\"propose(string[])\", &[\"[\\\"\\\"]\"]).unwrap().as_str()\n        );\n    }\n\n    #[test]\n    fn calldata_bool() {\n        assert_eq!(\n            \"0x6fae94120000000000000000000000000000000000000000000000000000000000000000\",\n            Cast::calldata_encode(\"bar(bool)\", &[\"false\"]).unwrap().as_str()\n        );\n    }\n\n    #[test]\n    fn abi_decode() {\n        let data = \"0x0000000000000000000000000000000000000000000000000000000000000001\";\n        let sig = \"balanceOf(address, uint256)(uint256)\";\n        assert_eq!(\n            \"1\",\n            Cast::abi_decode(sig, data, false).unwrap()[0].as_uint().unwrap().0.to_string()\n        );\n\n        let data = \"0x0000000000000000000000008dbd1b711dc621e1404633da156fcc779e1c6f3e000000000000000000000000d9f3c9cc99548bf3b44a43e0a2d07399eb918adc000000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000\";\n        let sig = \"safeTransferFrom(address,address,uint256,uint256,bytes)\";\n        let decoded = Cast::abi_decode(sig, data, true).unwrap();\n        let decoded = [\n            decoded[0]\n                .as_address()\n                .unwrap()\n                .to_string()\n                .strip_prefix(\"0x\")\n                .unwrap()\n                .to_owned()\n                .to_lowercase(),\n            decoded[1]\n                .as_address()\n                .unwrap()\n                .to_string()\n                .strip_prefix(\"0x\")\n                .unwrap()\n                .to_owned()\n                .to_lowercase(),\n            decoded[2].as_uint().unwrap().0.to_string(),\n            decoded[3].as_uint().unwrap().0.to_string(),\n            hex::encode(decoded[4].as_bytes().unwrap()),\n        ]\n        .to_vec();\n        assert_eq!(\n            decoded,\n            vec![\n                \"8dbd1b711dc621e1404633da156fcc779e1c6f3e\",\n                \"d9f3c9cc99548bf3b44a43e0a2d07399eb918adc\",\n                \"42\",\n                \"1\",\n                \"\"\n            ]\n        );\n    }\n\n    #[test]\n    fn calldata_decode() {\n        let data = \"0x0000000000000000000000000000000000000000000000000000000000000001\";\n        let sig = \"balanceOf(address, uint256)(uint256)\";\n        let decoded =\n            Cast::calldata_decode(sig, data, false).unwrap()[0].as_uint().unwrap().0.to_string();\n        assert_eq!(decoded, \"1\");\n\n        // Passing `input = true` will decode the data with the input function signature.\n        // We exclude the \"prefixed\" function selector from the data field (the first 4 bytes).\n        let data = \"0xf242432a0000000000000000000000008dbd1b711dc621e1404633da156fcc779e1c6f3e000000000000000000000000d9f3c9cc99548bf3b44a43e0a2d07399eb918adc000000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000\";\n        let sig = \"safeTransferFrom(address, address, uint256, uint256, bytes)\";\n        let decoded = Cast::calldata_decode(sig, data, true).unwrap();\n        let decoded = [\n            decoded[0].as_address().unwrap().to_string().to_lowercase(),\n            decoded[1].as_address().unwrap().to_string().to_lowercase(),\n            decoded[2].as_uint().unwrap().0.to_string(),\n            decoded[3].as_uint().unwrap().0.to_string(),\n            hex::encode(decoded[4].as_bytes().unwrap()),\n        ]\n        .into_iter()\n        .collect::<Vec<_>>();\n        assert_eq!(\n            decoded,\n            vec![\n                \"0x8dbd1b711dc621e1404633da156fcc779e1c6f3e\",\n                \"0xd9f3c9cc99548bf3b44a43e0a2d07399eb918adc\",\n                \"42\",\n                \"1\",\n                \"\"\n            ]\n        );\n    }\n\n    #[test]\n    fn calldata_decode_nested_json() {\n        let calldata = \"0xdb5b0ed700000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000006772bf190000000000000000000000000000000000000000000000000000000000020716000000000000000000000000af9d27ffe4d51ed54ac8eec78f2785d7e11e5ab100000000000000000000000000000000000000000000000000000000000002c0000000000000000000000000000000000000000000000000000000000000000404366a6dc4b2f348a85e0066e46f0cc206fca6512e0ed7f17ca7afb88e9a4c27000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000093922dee6e380c28a50c008ab167b7800bb24c2026cd1b22f1c6fb884ceed7400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060f85e59ecad6c1a6be343a945abedb7d5b5bfad7817c4d8cc668da7d391faf700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000093dfbf04395fbec1f1aed4ad0f9d3ba880ff58a60485df5d33f8f5e0fb73188600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000aa334a426ea9e21d5f84eb2d4723ca56b92382b9260ab2b6769b7c23d437b6b512322a25cecc954127e60cf91ef056ac1da25f90b73be81c3ff1872fa48d10c7ef1ccb4087bbeedb54b1417a24abbb76f6cd57010a65bb03c7b6602b1eaf0e32c67c54168232d4edc0bfa1b815b2af2a2d0a5c109d675a4f2de684e51df9abb324ab1b19a81bac80f9ce3a45095f3df3a7cf69ef18fc08e94ac3cbc1c7effeacca68e3bfe5d81e26a659b5\";\n        let sig = \"sequenceBatchesValidium((bytes32,bytes32,uint64,bytes32)[],uint64,uint64,address,bytes)\";\n        let decoded = Cast::calldata_decode(sig, calldata, true).unwrap();\n        let json_value = serialize_value_as_json(DynSolValue::Array(decoded), None).unwrap();\n        let expected = serde_json::json!([\n            [\n                [\n                    \"0x04366a6dc4b2f348a85e0066e46f0cc206fca6512e0ed7f17ca7afb88e9a4c27\",\n                    \"0x0000000000000000000000000000000000000000000000000000000000000000\",\n                    0,\n                    \"0x0000000000000000000000000000000000000000000000000000000000000000\"\n                ],\n                [\n                    \"0x093922dee6e380c28a50c008ab167b7800bb24c2026cd1b22f1c6fb884ceed74\",\n                    \"0x0000000000000000000000000000000000000000000000000000000000000000\",\n                    0,\n                    \"0x0000000000000000000000000000000000000000000000000000000000000000\"\n                ],\n                [\n                    \"0x60f85e59ecad6c1a6be343a945abedb7d5b5bfad7817c4d8cc668da7d391faf7\",\n                    \"0x0000000000000000000000000000000000000000000000000000000000000000\",\n                    0,\n                    \"0x0000000000000000000000000000000000000000000000000000000000000000\"\n                ],\n                [\n                    \"0x93dfbf04395fbec1f1aed4ad0f9d3ba880ff58a60485df5d33f8f5e0fb731886\",\n                    \"0x0000000000000000000000000000000000000000000000000000000000000000\",\n                    0,\n                    \"0x0000000000000000000000000000000000000000000000000000000000000000\"\n                ]\n            ],\n            1735573273,\n            132886,\n            \"0xAF9d27ffe4d51eD54AC8eEc78f2785D7E11E5ab1\",\n            \"0x334a426ea9e21d5f84eb2d4723ca56b92382b9260ab2b6769b7c23d437b6b512322a25cecc954127e60cf91ef056ac1da25f90b73be81c3ff1872fa48d10c7ef1ccb4087bbeedb54b1417a24abbb76f6cd57010a65bb03c7b6602b1eaf0e32c67c54168232d4edc0bfa1b815b2af2a2d0a5c109d675a4f2de684e51df9abb324ab1b19a81bac80f9ce3a45095f3df3a7cf69ef18fc08e94ac3cbc1c7effeacca68e3bfe5d81e26a659b5\"\n        ]);\n        assert_eq!(json_value, expected);\n    }\n\n    #[test]\n    fn concat_hex() {\n        assert_eq!(Cast::concat_hex([\"0x00\", \"0x01\"]), \"0x0001\");\n        assert_eq!(Cast::concat_hex([\"1\", \"2\"]), \"0x12\");\n    }\n\n    #[test]\n    fn from_rlp() {\n        let rlp = \"0xf8b1a02b5df5f0757397573e8ff34a8b987b21680357de1f6c8d10273aa528a851eaca8080a02838ac1d2d2721ba883169179b48480b2ba4f43d70fcf806956746bd9e83f90380a0e46fff283b0ab96a32a7cc375cecc3ed7b6303a43d64e0a12eceb0bc6bd8754980a01d818c1c414c665a9c9a0e0c0ef1ef87cacb380b8c1f6223cb2a68a4b2d023f5808080a0236e8f61ecde6abfebc6c529441f782f62469d8a2cc47b7aace2c136bd3b1ff08080808080\";\n        let item = Cast::from_rlp(rlp, false).unwrap();\n        assert_eq!(\n            item,\n            r#\"[\"0x2b5df5f0757397573e8ff34a8b987b21680357de1f6c8d10273aa528a851eaca\",\"0x\",\"0x\",\"0x2838ac1d2d2721ba883169179b48480b2ba4f43d70fcf806956746bd9e83f903\",\"0x\",\"0xe46fff283b0ab96a32a7cc375cecc3ed7b6303a43d64e0a12eceb0bc6bd87549\",\"0x\",\"0x1d818c1c414c665a9c9a0e0c0ef1ef87cacb380b8c1f6223cb2a68a4b2d023f5\",\"0x\",\"0x\",\"0x\",\"0x236e8f61ecde6abfebc6c529441f782f62469d8a2cc47b7aace2c136bd3b1ff0\",\"0x\",\"0x\",\"0x\",\"0x\",\"0x\"]\"#\n        )\n    }\n\n    #[test]\n    fn disassemble_incomplete_sequence() {\n        let incomplete = &hex!(\"60\"); // PUSH1\n        let disassembled = Cast::disassemble(incomplete).unwrap();\n        assert_eq!(disassembled, \"00000000: PUSH1\\n\");\n\n        let complete = &hex!(\"6000\"); // PUSH1 0x00\n        let disassembled = Cast::disassemble(complete).unwrap();\n        assert_eq!(disassembled, \"00000000: PUSH1 0x00\\n\");\n\n        let incomplete = &hex!(\"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\"); // PUSH32 with 31 bytes\n        let disassembled = Cast::disassemble(incomplete).unwrap();\n        assert_eq!(disassembled, \"00000000: PUSH32\\n\");\n\n        let complete = &hex!(\"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\"); // PUSH32 with 32 bytes\n        let disassembled = Cast::disassemble(complete).unwrap();\n        assert_eq!(\n            disassembled,\n            \"00000000: PUSH32 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\\n\"\n        );\n    }\n}\n"
  },
  {
    "path": "crates/cast/src/opts.rs",
    "content": "use crate::cmd::{\n    access_list::AccessListArgs, artifact::ArtifactArgs, b2e_payload::B2EPayloadArgs,\n    bind::BindArgs, call::CallArgs, constructor_args::ConstructorArgsArgs, create2::Create2Args,\n    creation_code::CreationCodeArgs, da_estimate::DAEstimateArgs, erc20::Erc20Subcommand,\n    estimate::EstimateArgs, find_block::FindBlockArgs, interface::InterfaceArgs, logs::LogsArgs,\n    mktx::MakeTxArgs, rpc::RpcArgs, run::RunArgs, send::SendTxArgs, storage::StorageArgs,\n    trace::TraceArgs, txpool::TxPoolSubcommands, wallet::WalletSubcommands,\n};\nuse alloy_ens::NameOrAddress;\nuse alloy_primitives::{Address, B256, Selector, U256};\nuse alloy_rpc_types::BlockId;\nuse clap::{ArgAction, Parser, Subcommand, ValueHint};\nuse eyre::Result;\nuse foundry_cli::opts::{EtherscanOpts, GlobalArgs, NetworkVariant, RpcOpts};\nuse foundry_common::version::{LONG_VERSION, SHORT_VERSION};\nuse std::{path::PathBuf, str::FromStr};\n/// A Swiss Army knife for interacting with Ethereum applications from the command line.\n#[derive(Parser)]\n#[command(\n    name = \"cast\",\n    version = SHORT_VERSION,\n    long_version = LONG_VERSION,\n    after_help = \"Find more information in the book: https://getfoundry.sh/cast/overview\",\n    next_display_order = None,\n)]\npub struct Cast {\n    /// Include the global arguments.\n    #[command(flatten)]\n    pub global: GlobalArgs,\n\n    #[command(subcommand)]\n    pub cmd: CastSubcommand,\n}\n\n#[derive(Subcommand)]\npub enum CastSubcommand {\n    /// Prints the maximum value of the given integer type.\n    #[command(visible_aliases = &[\"--max-int\", \"maxi\"])]\n    MaxInt {\n        /// The integer type to get the maximum value of.\n        #[arg(default_value = \"int256\")]\n        r#type: String,\n    },\n\n    /// Prints the minimum value of the given integer type.\n    #[command(visible_aliases = &[\"--min-int\", \"mini\"])]\n    MinInt {\n        /// The integer type to get the minimum value of.\n        #[arg(default_value = \"int256\")]\n        r#type: String,\n    },\n\n    /// Prints the maximum value of the given integer type.\n    #[command(visible_aliases = &[\"--max-uint\", \"maxu\"])]\n    MaxUint {\n        /// The unsigned integer type to get the maximum value of.\n        #[arg(default_value = \"uint256\")]\n        r#type: String,\n    },\n\n    /// Prints the zero address.\n    #[command(visible_aliases = &[\"--address-zero\", \"az\"])]\n    AddressZero,\n\n    /// Prints the zero hash.\n    #[command(visible_aliases = &[\"--hash-zero\", \"hz\"])]\n    HashZero,\n\n    /// Convert UTF8 text to hex.\n    #[command(\n        visible_aliases = &[\n        \"--from-ascii\",\n        \"--from-utf8\",\n        \"from-ascii\",\n        \"fu\",\n        \"fa\"]\n    )]\n    FromUtf8 {\n        /// The text to convert.\n        text: Option<String>,\n    },\n\n    /// Concatenate hex strings.\n    #[command(visible_aliases = &[\"--concat-hex\", \"ch\"])]\n    ConcatHex {\n        /// The data to concatenate.\n        data: Vec<String>,\n    },\n\n    /// Convert binary data into hex data.\n    #[command(visible_aliases = &[\"--from-bin\", \"from-binx\", \"fb\"])]\n    FromBin,\n\n    /// Normalize the input to lowercase, 0x-prefixed hex.\n    ///\n    /// The input can be:\n    /// - mixed case hex with or without 0x prefix\n    /// - 0x prefixed hex, concatenated with a ':'\n    /// - an absolute path to file\n    /// - @tag, where the tag is defined in an environment variable\n    #[command(visible_aliases = &[\"--to-hexdata\", \"thd\", \"2hd\"])]\n    ToHexdata {\n        /// The input to normalize.\n        input: Option<String>,\n    },\n\n    /// Convert an address to a checksummed format (EIP-55).\n    #[command(\n        visible_aliases = &[\"--to-checksum-address\",\n        \"--to-checksum\",\n        \"to-checksum\",\n        \"ta\",\n        \"2a\"]\n    )]\n    ToCheckSumAddress {\n        /// The address to convert.\n        address: Option<Address>,\n        /// EIP-155 chain ID to encode the address using EIP-1191.\n        chain_id: Option<u64>,\n    },\n\n    /// Convert hex data to an ASCII string.\n    #[command(visible_aliases = &[\"--to-ascii\", \"tas\", \"2as\"])]\n    ToAscii {\n        /// The hex data to convert.\n        hexdata: Option<String>,\n    },\n\n    /// Convert hex data to a utf-8 string.\n    #[command(visible_aliases = &[\"--to-utf8\", \"tu8\", \"2u8\"])]\n    ToUtf8 {\n        /// The hex data to convert.\n        hexdata: Option<String>,\n    },\n\n    /// Convert a fixed point number into an integer.\n    #[command(visible_aliases = &[\"--from-fix\", \"ff\"])]\n    FromFixedPoint {\n        /// The number of decimals to use.\n        decimals: Option<String>,\n\n        /// The value to convert.\n        #[arg(allow_hyphen_values = true)]\n        value: Option<String>,\n    },\n\n    /// Right-pads hex data to 32 bytes.\n    #[command(visible_aliases = &[\"--to-bytes32\", \"tb\", \"2b\"])]\n    ToBytes32 {\n        /// The hex data to convert.\n        bytes: Option<String>,\n    },\n\n    /// Pads hex data to a specified length.\n    #[command(visible_aliases = &[\"pd\"])]\n    Pad {\n        /// The hex data to pad.\n        data: Option<String>,\n\n        /// Right-pad the data (instead of left-pad).\n        #[arg(long)]\n        right: bool,\n\n        /// Left-pad the data (default).\n        #[arg(long, conflicts_with = \"right\")]\n        left: bool,\n\n        /// Target length in bytes (default: 32).\n        #[arg(long, default_value = \"32\")]\n        len: usize,\n    },\n\n    /// Convert an integer into a fixed point number.\n    #[command(visible_aliases = &[\"--to-fix\", \"tf\", \"2f\"])]\n    ToFixedPoint {\n        /// The number of decimals to use.\n        decimals: Option<String>,\n\n        /// The value to convert.\n        #[arg(allow_hyphen_values = true)]\n        value: Option<String>,\n    },\n\n    /// Convert a number to a hex-encoded uint256.\n    #[command(name = \"to-uint256\", visible_aliases = &[\"--to-uint256\", \"tu\", \"2u\"])]\n    ToUint256 {\n        /// The value to convert.\n        value: Option<String>,\n    },\n\n    /// Convert a number to a hex-encoded int256.\n    #[command(name = \"to-int256\", visible_aliases = &[\"--to-int256\", \"ti\", \"2i\"])]\n    ToInt256 {\n        /// The value to convert.\n        value: Option<String>,\n    },\n\n    /// Perform a left shifting operation\n    #[command(name = \"shl\")]\n    LeftShift {\n        /// The value to shift.\n        value: String,\n\n        /// The number of bits to shift.\n        bits: String,\n\n        /// The input base.\n        #[arg(long)]\n        base_in: Option<String>,\n\n        /// The output base.\n        #[arg(long, default_value = \"16\")]\n        base_out: String,\n    },\n\n    /// Perform a right shifting operation\n    #[command(name = \"shr\")]\n    RightShift {\n        /// The value to shift.\n        value: String,\n\n        /// The number of bits to shift.\n        bits: String,\n\n        /// The input base,\n        #[arg(long)]\n        base_in: Option<String>,\n\n        /// The output base,\n        #[arg(long, default_value = \"16\")]\n        base_out: String,\n    },\n\n    /// Convert an ETH amount into another unit (ether, gwei or wei).\n    ///\n    /// Examples:\n    /// - 1ether wei\n    /// - \"1 ether\" wei\n    /// - 1ether\n    /// - 1 gwei\n    /// - 1gwei ether\n    #[command(visible_aliases = &[\"--to-unit\", \"tun\", \"2un\"])]\n    ToUnit {\n        /// The value to convert.\n        value: Option<String>,\n\n        /// The unit to convert to (ether, gwei, wei).\n        #[arg(default_value = \"wei\")]\n        unit: String,\n    },\n\n    /// Convert a number from decimal to smallest unit with arbitrary decimals.\n    ///\n    /// Examples:\n    /// - 1.0 6    (for USDC, result: 1000000)\n    /// - 2.5 12   (for 12 decimals token, result: 2500000000000)\n    /// - 1.23 3   (for 3 decimals token, result: 1230)\n    #[command(visible_aliases = &[\"--parse-units\", \"pun\"])]\n    ParseUnits {\n        /// The value to convert.\n        value: Option<String>,\n\n        /// The unit to convert to.\n        #[arg(default_value = \"18\")]\n        unit: u8,\n    },\n\n    /// Format a number from smallest unit to decimal with arbitrary decimals.\n    ///\n    /// Examples:\n    /// - 1000000 6       (for USDC, result: 1.0)\n    /// - 2500000000000 12 (for 12 decimals, result: 2.5)\n    /// - 1230 3          (for 3 decimals, result: 1.23)\n    #[command(visible_aliases = &[\"--format-units\", \"fun\"])]\n    FormatUnits {\n        /// The value to format.\n        value: Option<String>,\n\n        /// The unit to format to.\n        #[arg(default_value = \"18\")]\n        unit: u8,\n    },\n\n    /// Convert an ETH amount to wei.\n    ///\n    /// Consider using --to-unit.\n    #[command(visible_aliases = &[\"--to-wei\", \"tw\", \"2w\"])]\n    ToWei {\n        /// The value to convert.\n        #[arg(allow_hyphen_values = true)]\n        value: Option<String>,\n\n        /// The unit to convert from (ether, gwei, wei).\n        #[arg(default_value = \"eth\")]\n        unit: String,\n    },\n\n    /// Convert wei into an ETH amount.\n    ///\n    /// Consider using --to-unit.\n    #[command(visible_aliases = &[\"--from-wei\", \"fw\"])]\n    FromWei {\n        /// The value to convert.\n        #[arg(allow_hyphen_values = true)]\n        value: Option<String>,\n\n        /// The unit to convert from (ether, gwei, wei).\n        #[arg(default_value = \"eth\")]\n        unit: String,\n    },\n\n    /// RLP encodes hex data, or an array of hex data.\n    ///\n    /// Accepts a hex-encoded string, or an array of hex-encoded strings.\n    /// Can be arbitrarily recursive.\n    ///\n    /// Examples:\n    /// - `cast to-rlp \"[]\"` -> `0xc0`\n    /// - `cast to-rlp \"0x22\"` -> `0x22`\n    /// - `cast to-rlp \"[\\\"0x61\\\"]\"` -> `0xc161`\n    /// - `cast to-rlp \"[\\\"0xf1\\\", \\\"f2\\\"]\"` -> `0xc481f181f2`\n    #[command(visible_aliases = &[\"--to-rlp\"])]\n    ToRlp {\n        /// The value to convert.\n        ///\n        /// This is a hex-encoded string, or an array of hex-encoded strings.\n        /// Can be arbitrarily recursive.\n        value: Option<String>,\n    },\n\n    /// Decodes RLP hex-encoded data.\n    #[command(visible_aliases = &[\"--from-rlp\"])]\n    FromRlp {\n        /// The RLP hex-encoded data.\n        value: Option<String>,\n\n        /// Decode the RLP data as int\n        #[arg(long, alias = \"int\")]\n        as_int: bool,\n    },\n\n    /// Converts a number of one base to another\n    #[command(visible_aliases = &[\"--to-hex\", \"th\", \"2h\"])]\n    ToHex(ToBaseArgs),\n\n    /// Converts a number of one base to decimal\n    #[command(visible_aliases = &[\"--to-dec\", \"td\", \"2d\"])]\n    ToDec(ToBaseArgs),\n\n    /// Converts a number of one base to another\n    #[command(\n        visible_aliases = &[\"--to-base\",\n        \"--to-radix\",\n        \"to-radix\",\n        \"tr\",\n        \"2r\"]\n    )]\n    ToBase {\n        #[command(flatten)]\n        base: ToBaseArgs,\n\n        /// The output base.\n        #[arg(value_name = \"BASE\")]\n        base_out: Option<String>,\n    },\n    /// Create an access list for a transaction.\n    #[command(visible_aliases = &[\"ac\", \"acl\"])]\n    AccessList(AccessListArgs),\n    /// Get logs by signature or topic.\n    #[command(visible_alias = \"l\")]\n    Logs(LogsArgs),\n    /// Get information about a block.\n    #[command(visible_alias = \"bl\")]\n    Block {\n        /// The block height to query at.\n        ///\n        /// Can also be the tags earliest, finalized, safe, latest, or pending.\n        block: Option<BlockId>,\n\n        /// If specified, only get the given field of the block.\n        #[arg(short, long = \"field\", aliases = [\"fields\"], num_args = 0.., action = ArgAction::Append, value_delimiter = ',')]\n        fields: Vec<String>,\n\n        /// Print the raw RLP encoded block header.\n        #[arg(long, conflicts_with = \"fields\")]\n        raw: bool,\n\n        #[arg(long, env = \"CAST_FULL_BLOCK\")]\n        full: bool,\n\n        #[command(flatten)]\n        rpc: RpcOpts,\n\n        /// Specify the Network for correct encoding.\n        #[arg(long, short, num_args = 1, value_name = \"NETWORK\")]\n        network: Option<NetworkVariant>,\n    },\n\n    /// Get the latest block number.\n    #[command(visible_alias = \"bn\")]\n    BlockNumber {\n        /// The hash or tag to query. If not specified, the latest number is returned.\n        block: Option<BlockId>,\n        #[command(flatten)]\n        rpc: RpcOpts,\n    },\n\n    /// Perform a call on an account without publishing a transaction.\n    #[command(visible_alias = \"c\")]\n    Call(CallArgs),\n\n    /// ABI-encode a function with arguments.\n    #[command(name = \"calldata\", visible_alias = \"cd\")]\n    CalldataEncode {\n        /// The function signature in the format `<name>(<in-types>)(<out-types>)`\n        sig: String,\n\n        /// The arguments to encode.\n        #[arg(allow_hyphen_values = true)]\n        args: Vec<String>,\n\n        // Path to file containing arguments to encode.\n        #[arg(long, value_name = \"PATH\")]\n        file: Option<PathBuf>,\n    },\n\n    /// Get the symbolic name of the current chain.\n    Chain {\n        #[command(flatten)]\n        rpc: RpcOpts,\n    },\n\n    /// Get the Ethereum chain ID.\n    #[command(visible_aliases = &[\"ci\", \"cid\"])]\n    ChainId {\n        #[command(flatten)]\n        rpc: RpcOpts,\n    },\n\n    /// Get the current client version.\n    #[command(visible_alias = \"cl\")]\n    Client {\n        #[command(flatten)]\n        rpc: RpcOpts,\n    },\n\n    /// Compute the contract address from a given nonce and deployer address.\n    #[command(visible_alias = \"ca\")]\n    ComputeAddress {\n        /// The deployer address.\n        address: Option<Address>,\n\n        /// The nonce of the deployer address.\n        #[arg(\n            long,\n            conflicts_with = \"salt\",\n            conflicts_with = \"init_code\",\n            conflicts_with = \"init_code_hash\"\n        )]\n        nonce: Option<u64>,\n\n        /// The salt for CREATE2 address computation.\n        #[arg(long, conflicts_with = \"nonce\")]\n        salt: Option<B256>,\n\n        /// The init code for CREATE2 address computation.\n        #[arg(\n            long,\n            requires = \"salt\",\n            conflicts_with = \"init_code_hash\",\n            conflicts_with = \"nonce\"\n        )]\n        init_code: Option<String>,\n\n        /// The init code hash for CREATE2 address computation.\n        #[arg(long, requires = \"salt\", conflicts_with = \"init_code\", conflicts_with = \"nonce\")]\n        init_code_hash: Option<B256>,\n\n        #[command(flatten)]\n        rpc: RpcOpts,\n    },\n\n    /// Disassembles a hex-encoded bytecode into a human-readable representation.\n    #[command(visible_alias = \"da\")]\n    Disassemble {\n        /// The hex-encoded bytecode.\n        bytecode: Option<String>,\n    },\n\n    /// Build and sign a transaction.\n    #[command(name = \"mktx\", visible_alias = \"m\")]\n    MakeTx(MakeTxArgs),\n\n    /// Calculate the ENS namehash of a name.\n    #[command(visible_aliases = &[\"na\", \"nh\"])]\n    Namehash { name: Option<String> },\n\n    /// Get information about a transaction.\n    #[command(visible_alias = \"t\")]\n    Tx {\n        /// The transaction hash.\n        tx_hash: Option<String>,\n\n        /// The sender of the transaction.\n        #[arg(long, value_parser = NameOrAddress::from_str)]\n        from: Option<NameOrAddress>,\n\n        /// Nonce of the transaction.\n        #[arg(long)]\n        nonce: Option<u64>,\n\n        /// If specified, only get the given field of the transaction. If \"raw\", the RLP encoded\n        /// transaction will be printed.\n        field: Option<String>,\n\n        /// Print the raw RLP encoded transaction.\n        #[arg(long, conflicts_with = \"field\")]\n        raw: bool,\n\n        #[command(flatten)]\n        rpc: RpcOpts,\n\n        /// If specified, the transaction will be converted to a TransactionRequest JSON format.\n        #[arg(long)]\n        to_request: bool,\n\n        /// Specify the Network for correct encoding.\n        #[arg(long, short, num_args = 1, value_name = \"NETWORK\")]\n        network: Option<NetworkVariant>,\n    },\n\n    /// Get the transaction receipt for a transaction.\n    #[command(visible_alias = \"re\")]\n    Receipt {\n        /// The transaction hash.\n        tx_hash: String,\n\n        /// If specified, only get the given field of the transaction.\n        field: Option<String>,\n\n        /// The number of confirmations until the receipt is fetched\n        #[arg(long, default_value = \"1\")]\n        confirmations: u64,\n\n        /// Exit immediately if the transaction was not found.\n        #[arg(id = \"async\", long = \"async\", env = \"CAST_ASYNC\", alias = \"cast-async\")]\n        cast_async: bool,\n\n        #[command(flatten)]\n        rpc: RpcOpts,\n    },\n\n    /// Sign and publish a transaction.\n    #[command(name = \"send\", visible_alias = \"s\")]\n    SendTx(SendTxArgs),\n\n    /// Publish a raw transaction to the network.\n    #[command(name = \"publish\", visible_alias = \"p\")]\n    PublishTx {\n        /// The raw transaction\n        raw_tx: String,\n\n        /// Only print the transaction hash and exit immediately.\n        #[arg(id = \"async\", long = \"async\", env = \"CAST_ASYNC\", alias = \"cast-async\")]\n        cast_async: bool,\n\n        #[command(flatten)]\n        rpc: RpcOpts,\n    },\n\n    /// Estimate the gas cost of a transaction.\n    #[command(visible_alias = \"e\")]\n    Estimate(EstimateArgs),\n\n    /// Decode ABI-encoded input data.\n    ///\n    /// Similar to `abi-decode --input`, but function selector MUST be prefixed in `calldata`\n    /// string\n    #[command(visible_aliases = &[\"calldata-decode\", \"--calldata-decode\", \"cdd\"])]\n    DecodeCalldata {\n        /// The function signature in the format `<name>(<in-types>)(<out-types>)`.\n        sig: String,\n\n        /// The ABI-encoded calldata.\n        #[arg(required_unless_present = \"file\", index = 2)]\n        calldata: Option<String>,\n\n        /// Load ABI-encoded calldata from a file instead.\n        #[arg(long = \"file\", short = 'f', conflicts_with = \"calldata\")]\n        file: Option<PathBuf>,\n    },\n\n    /// Decode ABI-encoded string.\n    ///\n    /// Similar to `calldata-decode --input`, but the function argument is a `string`\n    #[command(visible_aliases = &[\"string-decode\", \"--string-decode\", \"sd\"])]\n    DecodeString {\n        /// The ABI-encoded string.\n        data: String,\n    },\n\n    /// Decode event data.\n    #[command(visible_aliases = &[\"event-decode\", \"--event-decode\", \"ed\"])]\n    DecodeEvent {\n        /// The event signature. If none provided then tries to decode from local cache or <https://api.openchain.xyz>.\n        #[arg(long, visible_alias = \"event-sig\")]\n        sig: Option<String>,\n        /// The event data to decode.\n        data: String,\n    },\n\n    /// Decode custom error data.\n    #[command(visible_aliases = &[\"error-decode\", \"--error-decode\", \"erd\"])]\n    DecodeError {\n        /// The error signature. If none provided then tries to decode from local cache or <https://api.openchain.xyz>.\n        #[arg(long, visible_alias = \"error-sig\")]\n        sig: Option<String>,\n        /// The error data to decode.\n        data: String,\n    },\n\n    /// Decode ABI-encoded input or output data.\n    ///\n    /// Defaults to decoding output data. To decode input data pass --input.\n    ///\n    /// When passing `--input`, function selector must NOT be prefixed in `calldata` string\n    #[command(name = \"decode-abi\", visible_aliases = &[\"abi-decode\", \"--abi-decode\", \"ad\"])]\n    DecodeAbi {\n        /// The function signature in the format `<name>(<in-types>)(<out-types>)`.\n        sig: String,\n\n        /// The ABI-encoded calldata.\n        calldata: String,\n\n        /// Whether to decode the input or output data.\n        #[arg(long, short, help_heading = \"Decode input data instead of output data\")]\n        input: bool,\n    },\n\n    /// ABI encode the given function argument, excluding the selector.\n    #[command(visible_alias = \"ae\")]\n    AbiEncode {\n        /// The function signature.\n        sig: String,\n\n        /// Whether to use packed encoding.\n        #[arg(long)]\n        packed: bool,\n\n        /// The arguments of the function.\n        #[arg(allow_hyphen_values = true)]\n        args: Vec<String>,\n    },\n\n    /// ABI encode an event and its arguments to generate topics and data.\n    #[command(visible_alias = \"aee\")]\n    AbiEncodeEvent {\n        /// The event signature.\n        sig: String,\n\n        /// The arguments of the event.\n        #[arg(allow_hyphen_values = true)]\n        args: Vec<String>,\n    },\n\n    /// Compute the storage slot for an entry in a mapping.\n    #[command(visible_alias = \"in\")]\n    Index {\n        /// The mapping key type.\n        key_type: String,\n\n        /// The mapping key.\n        key: String,\n\n        /// The storage slot of the mapping.\n        slot_number: String,\n    },\n\n    /// Compute storage slots as specified by `ERC-7201: Namespaced Storage Layout`.\n    #[command(name = \"index-erc7201\", alias = \"index-erc-7201\", visible_aliases = &[\"index7201\", \"in7201\"])]\n    IndexErc7201 {\n        /// The arbitrary identifier.\n        id: Option<String>,\n        /// The formula ID. Currently the only supported formula is `erc7201`.\n        #[arg(long, default_value = \"erc7201\")]\n        formula_id: String,\n    },\n\n    /// Fetch the EIP-1967 implementation for a contract\n    /// Can read from the implementation slot or the beacon slot.\n    #[command(visible_alias = \"impl\")]\n    Implementation {\n        /// The block height to query at.\n        ///\n        /// Can also be the tags earliest, finalized, safe, latest, or pending.\n        #[arg(long, short = 'B')]\n        block: Option<BlockId>,\n\n        /// Fetch the implementation from the beacon slot.\n        ///\n        /// If not specified, the implementation slot is used.\n        #[arg(long)]\n        beacon: bool,\n\n        /// The address for which the implementation will be fetched.\n        #[arg(value_parser = NameOrAddress::from_str)]\n        who: NameOrAddress,\n\n        #[command(flatten)]\n        rpc: RpcOpts,\n    },\n\n    /// Fetch the EIP-1967 admin account\n    #[command(visible_alias = \"adm\")]\n    Admin {\n        /// The block height to query at.\n        ///\n        /// Can also be the tags earliest, finalized, safe, latest, or pending.\n        #[arg(long, short = 'B')]\n        block: Option<BlockId>,\n\n        /// The address from which the admin account will be fetched.\n        #[arg(value_parser = NameOrAddress::from_str)]\n        who: NameOrAddress,\n\n        #[command(flatten)]\n        rpc: RpcOpts,\n    },\n\n    /// Get the function signatures for the given selector from <https://openchain.xyz>.\n    #[command(name = \"4byte\", visible_aliases = &[\"4\", \"4b\"])]\n    FourByte {\n        /// The function selector.\n        selector: Option<Selector>,\n    },\n\n    /// Decode ABI-encoded calldata using <https://openchain.xyz>.\n    #[command(name = \"4byte-calldata\", aliases = &[\"4byte-decode\", \"4d\", \"4bd\"], visible_aliases = &[\"4c\", \"4bc\"])]\n    FourByteCalldata {\n        /// The ABI-encoded calldata.\n        calldata: Option<String>,\n    },\n\n    /// Get the event signature for a given topic 0 from <https://openchain.xyz>.\n    #[command(name = \"4byte-event\", visible_aliases = &[\"4e\", \"4be\", \"topic0-event\", \"t0e\"])]\n    FourByteEvent {\n        /// Topic 0\n        #[arg(value_name = \"TOPIC_0\")]\n        topic: Option<B256>,\n    },\n\n    /// Upload the given signatures to <https://openchain.xyz>.\n    ///\n    /// Example inputs:\n    /// - \"transfer(address,uint256)\"\n    /// - \"function transfer(address,uint256)\"\n    /// - \"function transfer(address,uint256)\" \"event Transfer(address,address,uint256)\"\n    /// - \"./out/Contract.sol/Contract.json\"\n    #[command(visible_aliases = &[\"ups\"])]\n    UploadSignature {\n        /// The signatures to upload.\n        ///\n        /// Prefix with 'function', 'event', or 'error'. Defaults to function if no prefix given.\n        /// Can also take paths to contract artifact JSON.\n        signatures: Vec<String>,\n    },\n\n    /// Pretty print calldata.\n    ///\n    /// Tries to decode the calldata using <https://openchain.xyz> unless --offline is passed.\n    #[command(visible_alias = \"pc\")]\n    PrettyCalldata {\n        /// The calldata.\n        calldata: Option<String>,\n\n        /// Skip the <https://openchain.xyz> lookup.\n        #[arg(long, short)]\n        offline: bool,\n    },\n\n    /// Get the timestamp of a block.\n    #[command(visible_alias = \"a\")]\n    Age {\n        /// The block height to query at.\n        ///\n        /// Can also be the tags earliest, finalized, safe, latest, or pending.\n        block: Option<BlockId>,\n\n        #[command(flatten)]\n        rpc: RpcOpts,\n    },\n\n    /// Get the balance of an account in wei.\n    #[command(visible_alias = \"b\")]\n    Balance {\n        /// The block height to query at.\n        ///\n        /// Can also be the tags earliest, finalized, safe, latest, or pending.\n        #[arg(long, short = 'B')]\n        block: Option<BlockId>,\n\n        /// The account to query.\n        #[arg(value_parser = NameOrAddress::from_str)]\n        who: NameOrAddress,\n\n        /// Format the balance in ether.\n        #[arg(long, short)]\n        ether: bool,\n\n        #[command(flatten)]\n        rpc: RpcOpts,\n\n        /// erc20 address to query, with the method `balanceOf(address) return (uint256)`, alias\n        /// with '--erc721'\n        #[arg(long, alias = \"erc721\")]\n        erc20: Option<Address>,\n    },\n\n    /// Get the basefee of a block.\n    #[command(visible_aliases = &[\"ba\", \"fee\", \"basefee\"])]\n    BaseFee {\n        /// The block height to query at.\n        ///\n        /// Can also be the tags earliest, finalized, safe, latest, or pending.\n        block: Option<BlockId>,\n\n        #[command(flatten)]\n        rpc: RpcOpts,\n    },\n\n    /// Get the runtime bytecode of a contract.\n    #[command(visible_alias = \"co\")]\n    Code {\n        /// The block height to query at.\n        ///\n        /// Can also be the tags earliest, finalized, safe, latest, or pending.\n        #[arg(long, short = 'B')]\n        block: Option<BlockId>,\n\n        /// The contract address.\n        #[arg(value_parser = NameOrAddress::from_str)]\n        who: NameOrAddress,\n\n        /// Disassemble bytecodes.\n        #[arg(long, short)]\n        disassemble: bool,\n\n        #[command(flatten)]\n        rpc: RpcOpts,\n    },\n\n    /// Get the runtime bytecode size of a contract.\n    #[command(visible_alias = \"cs\")]\n    Codesize {\n        /// The block height to query at.\n        ///\n        /// Can also be the tags earliest, finalized, safe, latest, or pending.\n        #[arg(long, short = 'B')]\n        block: Option<BlockId>,\n\n        /// The contract address.\n        #[arg(value_parser = NameOrAddress::from_str)]\n        who: NameOrAddress,\n\n        #[command(flatten)]\n        rpc: RpcOpts,\n    },\n\n    /// Get the current gas price.\n    #[command(visible_alias = \"g\")]\n    GasPrice {\n        #[command(flatten)]\n        rpc: RpcOpts,\n    },\n\n    /// Generate event signatures from event string.\n    #[command(visible_alias = \"se\")]\n    SigEvent {\n        /// The event string.\n        event_string: Option<String>,\n    },\n\n    /// Hash arbitrary data using Keccak-256.\n    #[command(visible_aliases = &[\"k\", \"keccak256\"])]\n    Keccak {\n        /// The data to hash.\n        data: Option<String>,\n    },\n\n    /// Hash a message according to EIP-191.\n    #[command(visible_aliases = &[\"--hash-message\", \"hm\"])]\n    HashMessage {\n        /// The message to hash.\n        message: Option<String>,\n    },\n\n    /// Perform an ENS lookup.\n    #[command(visible_alias = \"rn\")]\n    ResolveName {\n        /// The name to lookup.\n        who: Option<String>,\n\n        /// Perform a reverse lookup to verify that the name is correct.\n        #[arg(long)]\n        verify: bool,\n\n        #[command(flatten)]\n        rpc: RpcOpts,\n    },\n\n    /// Perform an ENS reverse lookup.\n    #[command(visible_alias = \"la\")]\n    LookupAddress {\n        /// The account to perform the lookup for.\n        who: Option<Address>,\n\n        /// Perform a normal lookup to verify that the address is correct.\n        #[arg(long)]\n        verify: bool,\n\n        #[command(flatten)]\n        rpc: RpcOpts,\n    },\n\n    /// Get the raw value of a contract's storage slot.\n    #[command(visible_alias = \"st\")]\n    Storage(StorageArgs),\n\n    /// Generate a storage proof for a given storage slot.\n    #[command(visible_alias = \"pr\")]\n    Proof {\n        /// The contract address.\n        #[arg(value_parser = NameOrAddress::from_str)]\n        address: NameOrAddress,\n\n        /// The storage slot numbers (hex or decimal).\n        #[arg(value_parser = parse_slot)]\n        slots: Vec<B256>,\n\n        /// The block height to query at.\n        ///\n        /// Can also be the tags earliest, finalized, safe, latest, or pending.\n        #[arg(long, short = 'B')]\n        block: Option<BlockId>,\n\n        #[command(flatten)]\n        rpc: RpcOpts,\n    },\n\n    /// Get the nonce for an account.\n    #[command(visible_alias = \"n\")]\n    Nonce {\n        /// The block height to query at.\n        ///\n        /// Can also be the tags earliest, finalized, safe, latest, or pending.\n        #[arg(long, short = 'B')]\n        block: Option<BlockId>,\n\n        /// The address to get the nonce for.\n        #[arg(value_parser = NameOrAddress::from_str)]\n        who: NameOrAddress,\n\n        #[command(flatten)]\n        rpc: RpcOpts,\n    },\n\n    /// Get the codehash for an account.\n    #[command()]\n    Codehash {\n        /// The block height to query at.\n        ///\n        /// Can also be the tags earliest, finalized, safe, latest, or pending.\n        #[arg(long, short = 'B')]\n        block: Option<BlockId>,\n\n        /// The address to get the codehash for.\n        #[arg(value_parser = NameOrAddress::from_str)]\n        who: NameOrAddress,\n\n        /// The storage slot numbers (hex or decimal).\n        #[arg(value_parser = parse_slot)]\n        slots: Vec<B256>,\n\n        #[command(flatten)]\n        rpc: RpcOpts,\n    },\n\n    /// Get the storage root for an account.\n    #[command(visible_alias = \"sr\")]\n    StorageRoot {\n        /// The block height to query at.\n        ///\n        /// Can also be the tags earliest, finalized, safe, latest, or pending.\n        #[arg(long, short = 'B')]\n        block: Option<BlockId>,\n\n        /// The address to get the storage root for.\n        #[arg(value_parser = NameOrAddress::from_str)]\n        who: NameOrAddress,\n\n        /// The storage slot numbers (hex or decimal).\n        #[arg(value_parser = parse_slot)]\n        slots: Vec<B256>,\n\n        #[command(flatten)]\n        rpc: RpcOpts,\n    },\n\n    /// Get the source code of a contract from a block explorer.\n    #[command(visible_aliases = &[\"et\", \"src\"])]\n    Source {\n        /// The contract's address.\n        address: String,\n\n        /// Whether to flatten the source code.\n        #[arg(long, short)]\n        flatten: bool,\n\n        /// The output directory/file to expand source tree into.\n        #[arg(short, value_hint = ValueHint::DirPath, alias = \"path\")]\n        directory: Option<PathBuf>,\n\n        #[command(flatten)]\n        etherscan: EtherscanOpts,\n\n        /// Alternative explorer API URL to use that adheres to the Etherscan API. If not provided,\n        /// defaults to Etherscan.\n        #[arg(long, env = \"EXPLORER_API_URL\")]\n        explorer_api_url: Option<String>,\n\n        /// Alternative explorer browser URL.\n        #[arg(long, env = \"EXPLORER_URL\")]\n        explorer_url: Option<String>,\n    },\n\n    /// Wallet management utilities.\n    #[command(visible_alias = \"w\")]\n    Wallet {\n        #[command(subcommand)]\n        command: WalletSubcommands,\n    },\n\n    /// Download a contract creation code from Etherscan and RPC.\n    #[command(visible_alias = \"cc\")]\n    CreationCode(CreationCodeArgs),\n\n    /// Generate an artifact file, that can be used to deploy a contract locally.\n    #[command(visible_alias = \"ar\")]\n    Artifact(ArtifactArgs),\n\n    /// Display constructor arguments used for the contract initialization.\n    #[command(visible_alias = \"cra\")]\n    ConstructorArgs(ConstructorArgsArgs),\n\n    /// Generate a Solidity interface from a given ABI.\n    ///\n    /// Currently does not support ABI encoder v2.\n    #[command(visible_alias = \"i\")]\n    Interface(InterfaceArgs),\n\n    /// Generate a rust binding from a given ABI.\n    #[command(visible_alias = \"bi\")]\n    Bind(BindArgs),\n\n    /// Convert Beacon payload to execution payload.\n    #[command(visible_alias = \"b2e\")]\n    B2EPayload(B2EPayloadArgs),\n\n    /// Get the selector for a function.\n    #[command(visible_alias = \"si\")]\n    Sig {\n        /// The function signature, e.g. transfer(address,uint256).\n        sig: Option<String>,\n\n        /// Optimize signature to contain provided amount of leading zeroes in selector.\n        optimize: Option<usize>,\n    },\n\n    /// Generate a deterministic contract address using CREATE2.\n    #[command(visible_alias = \"c2\")]\n    Create2(Create2Args),\n\n    /// Get the block number closest to the provided timestamp.\n    #[command(visible_alias = \"f\")]\n    FindBlock(FindBlockArgs),\n\n    /// Generate shell completions script.\n    #[command(visible_alias = \"com\")]\n    Completions {\n        #[arg(value_enum)]\n        shell: foundry_cli::clap::Shell,\n    },\n\n    /// Runs a published transaction in a local environment and prints the trace.\n    #[command(visible_alias = \"r\")]\n    Run(RunArgs),\n\n    /// Perform a raw JSON-RPC request.\n    #[command(visible_alias = \"rp\")]\n    Rpc(RpcArgs),\n\n    /// Formats a string into bytes32 encoding.\n    #[command(name = \"format-bytes32-string\", visible_aliases = &[\"--format-bytes32-string\"])]\n    FormatBytes32String {\n        /// The string to format.\n        string: Option<String>,\n    },\n\n    /// Parses a string from bytes32 encoding.\n    #[command(name = \"parse-bytes32-string\", visible_aliases = &[\"--parse-bytes32-string\"])]\n    ParseBytes32String {\n        /// The string to parse.\n        bytes: Option<String>,\n    },\n    #[command(name = \"parse-bytes32-address\", visible_aliases = &[\"--parse-bytes32-address\"])]\n    #[command(about = \"Parses a checksummed address from bytes32 encoding.\")]\n    ParseBytes32Address {\n        #[arg(value_name = \"BYTES\")]\n        bytes: Option<String>,\n    },\n\n    /// Decodes a raw signed EIP 2718 typed transaction\n    #[command(visible_aliases = &[\"dt\", \"decode-tx\"])]\n    DecodeTransaction { tx: Option<String> },\n\n    /// Recovery an EIP-7702 authority from a Authorization JSON string.\n    #[command(visible_aliases = &[\"decode-auth\"])]\n    RecoverAuthority { auth: String },\n\n    /// Extracts function selectors and arguments from bytecode\n    #[command(visible_alias = \"sel\")]\n    Selectors {\n        /// The hex-encoded bytecode.\n        bytecode: Option<String>,\n\n        /// Resolve the function signatures for the extracted selectors using <https://openchain.xyz>\n        #[arg(long, short)]\n        resolve: bool,\n    },\n\n    /// Inspect the TxPool of a node.\n    #[command(visible_alias = \"tp\")]\n    TxPool {\n        #[command(subcommand)]\n        command: TxPoolSubcommands,\n    },\n    /// Estimates the data availability size of a given opstack block.\n    #[command(name = \"da-estimate\")]\n    DAEstimate(DAEstimateArgs),\n\n    /// ERC20 token operations.\n    #[command(visible_alias = \"erc20\")]\n    Erc20Token {\n        #[command(subcommand)]\n        command: Erc20Subcommand,\n    },\n    #[command(name = \"trace\")]\n    Trace(TraceArgs),\n}\n\n/// CLI arguments for `cast --to-base`.\n#[derive(Debug, Parser)]\npub struct ToBaseArgs {\n    /// The value to convert.\n    #[arg(allow_hyphen_values = true)]\n    pub value: Option<String>,\n\n    /// The input base.\n    #[arg(long, short = 'i')]\n    pub base_in: Option<String>,\n}\n\npub fn parse_slot(s: &str) -> Result<B256> {\n    let slot = U256::from_str(s).map_err(|e| eyre::eyre!(\"Could not parse slot number: {e}\"))?;\n    Ok(B256::from(slot))\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use crate::SimpleCast;\n    use alloy_rpc_types::{BlockNumberOrTag, RpcBlockHash};\n    use clap::CommandFactory;\n\n    #[test]\n    fn verify_cli() {\n        Cast::command().debug_assert();\n    }\n\n    #[test]\n    fn parse_proof_slot() {\n        let args: Cast = Cast::parse_from([\n            \"foundry-cli\",\n            \"proof\",\n            \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\",\n            \"0\",\n            \"1\",\n            \"0x0000000000000000000000000000000000000000000000000000000000000000\",\n            \"0x1\",\n            \"0x01\",\n        ]);\n        match args.cmd {\n            CastSubcommand::Proof { slots, .. } => {\n                assert_eq!(\n                    slots,\n                    vec![\n                        B256::ZERO,\n                        U256::from(1).into(),\n                        B256::ZERO,\n                        U256::from(1).into(),\n                        U256::from(1).into()\n                    ]\n                );\n            }\n            _ => unreachable!(),\n        };\n    }\n\n    #[test]\n    fn parse_call_data() {\n        let args: Cast = Cast::parse_from([\n            \"foundry-cli\",\n            \"calldata\",\n            \"f()\",\n            \"5c9d55b78febcc2061715ba4f57ecf8ea2711f2c\",\n            \"2\",\n        ]);\n        match args.cmd {\n            CastSubcommand::CalldataEncode { args, .. } => {\n                assert_eq!(\n                    args,\n                    vec![\"5c9d55b78febcc2061715ba4f57ecf8ea2711f2c\".to_string(), \"2\".to_string()]\n                )\n            }\n            _ => unreachable!(),\n        };\n    }\n\n    #[test]\n    fn parse_call_data_with_file() {\n        let args: Cast = Cast::parse_from([\"foundry-cli\", \"calldata\", \"f()\", \"--file\", \"test.txt\"]);\n        match args.cmd {\n            CastSubcommand::CalldataEncode { sig, file, args } => {\n                assert_eq!(sig, \"f()\".to_string());\n                assert_eq!(file, Some(PathBuf::from(\"test.txt\")));\n                assert!(args.is_empty());\n            }\n            _ => unreachable!(),\n        };\n    }\n\n    // <https://github.com/foundry-rs/book/issues/1019>\n    #[test]\n    fn parse_signature() {\n        let args: Cast = Cast::parse_from([\n            \"foundry-cli\",\n            \"sig\",\n            \"__$_$__$$$$$__$$_$$$_$$__$$___$$(address,address,uint256)\",\n        ]);\n        match args.cmd {\n            CastSubcommand::Sig { sig, .. } => {\n                let sig = sig.unwrap();\n                assert_eq!(\n                    sig,\n                    \"__$_$__$$$$$__$$_$$$_$$__$$___$$(address,address,uint256)\".to_string()\n                );\n\n                let selector = SimpleCast::get_selector(&sig, 0).unwrap();\n                assert_eq!(selector.0, \"0x23b872dd\".to_string());\n            }\n            _ => unreachable!(),\n        };\n    }\n\n    #[test]\n    fn parse_block_ids() {\n        struct TestCase {\n            input: String,\n            expect: BlockId,\n        }\n\n        let test_cases = [\n            TestCase {\n                input: \"0\".to_string(),\n                expect: BlockId::Number(BlockNumberOrTag::Number(0u64)),\n            },\n            TestCase {\n                input: \"0x56462c47c03df160f66819f0a79ea07def1569f8aac0fe91bb3a081159b61b4a\"\n                    .to_string(),\n                expect: BlockId::Hash(RpcBlockHash::from_hash(\n                    \"0x56462c47c03df160f66819f0a79ea07def1569f8aac0fe91bb3a081159b61b4a\"\n                        .parse()\n                        .unwrap(),\n                    None,\n                )),\n            },\n            TestCase {\n                input: \"latest\".to_string(),\n                expect: BlockId::Number(BlockNumberOrTag::Latest),\n            },\n            TestCase {\n                input: \"earliest\".to_string(),\n                expect: BlockId::Number(BlockNumberOrTag::Earliest),\n            },\n            TestCase {\n                input: \"pending\".to_string(),\n                expect: BlockId::Number(BlockNumberOrTag::Pending),\n            },\n            TestCase { input: \"safe\".to_string(), expect: BlockId::Number(BlockNumberOrTag::Safe) },\n            TestCase {\n                input: \"finalized\".to_string(),\n                expect: BlockId::Number(BlockNumberOrTag::Finalized),\n            },\n        ];\n\n        for test in test_cases {\n            let result: BlockId = test.input.parse().unwrap();\n            assert_eq!(result, test.expect);\n        }\n    }\n}\n"
  },
  {
    "path": "crates/cast/src/rlp_converter.rs",
    "content": "use alloy_primitives::{U256, hex};\nuse alloy_rlp::{Buf, Decodable, Encodable, Header};\nuse eyre::Context;\nuse serde_json::Value;\nuse std::fmt;\n\n/// Arbitrary nested data.\n///\n/// - `Item::Array(vec![])` is equivalent to `[]`.\n/// - `Item::Array(vec![Item::Data(vec![])])` is equivalent to `[\"\"]` or `[null]`.\n#[derive(Clone, Debug, PartialEq, Eq)]\npub enum Item {\n    Data(Vec<u8>),\n    Array(Vec<Self>),\n}\n\nimpl Encodable for Item {\n    fn encode(&self, out: &mut dyn alloy_rlp::BufMut) {\n        match self {\n            Self::Array(arr) => arr.encode(out),\n            Self::Data(data) => <[u8]>::encode(data, out),\n        }\n    }\n}\n\nimpl Decodable for Item {\n    fn decode(buf: &mut &[u8]) -> alloy_rlp::Result<Self> {\n        let h = Header::decode(buf)?;\n        if buf.len() < h.payload_length {\n            return Err(alloy_rlp::Error::InputTooShort);\n        }\n        let mut d = &buf[..h.payload_length];\n        let r = if h.list {\n            let view = &mut d;\n            let mut v = Vec::new();\n            while !view.is_empty() {\n                v.push(Self::decode(view)?);\n            }\n            Ok(Self::Array(v))\n        } else {\n            Ok(Self::Data(d.to_vec()))\n        };\n        buf.advance(h.payload_length);\n        r\n    }\n}\n\nimpl Item {\n    pub(crate) fn value_to_item(value: &Value) -> eyre::Result<Self> {\n        match value {\n            Value::Null => Ok(Self::Data(vec![])),\n            Value::Bool(_) => {\n                eyre::bail!(\"RLP input can not contain booleans\")\n            }\n            Value::Number(n) => {\n                Ok(Self::Data(n.to_string().parse::<U256>()?.to_be_bytes_trimmed_vec()))\n            }\n            Value::String(s) => Ok(Self::Data(hex::decode(s).wrap_err(\"Could not decode hex\")?)),\n            Value::Array(values) => values.iter().map(Self::value_to_item).collect(),\n            Value::Object(_) => {\n                eyre::bail!(\"RLP input can not contain objects\")\n            }\n        }\n    }\n}\n\nimpl FromIterator<Self> for Item {\n    fn from_iter<T: IntoIterator<Item = Self>>(iter: T) -> Self {\n        Self::Array(Vec::from_iter(iter))\n    }\n}\n\n// Display as hex values\nimpl fmt::Display for Item {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::fmt::Result {\n        match self {\n            Self::Data(dat) => {\n                write!(f, \"\\\"0x{}\\\"\", hex::encode(dat))?;\n            }\n            Self::Array(items) => {\n                f.write_str(\"[\")?;\n                for (i, item) in items.iter().enumerate() {\n                    if i > 0 {\n                        f.write_str(\",\")?;\n                    }\n                    fmt::Display::fmt(item, f)?;\n                }\n                f.write_str(\"]\")?;\n            }\n        };\n        Ok(())\n    }\n}\n\n#[cfg(test)]\nmod test {\n    use crate::rlp_converter::Item;\n    use alloy_primitives::hex;\n    use alloy_rlp::{Bytes, Decodable};\n    use serde_json::Result as JsonResult;\n\n    // https://en.wikipedia.org/wiki/Set-theoretic_definition_of_natural_numbers\n    fn array_von_neuman() -> Item {\n        Item::Array(vec![\n            Item::Array(vec![]),\n            Item::Array(vec![Item::Array(vec![])]),\n            Item::Array(vec![Item::Array(vec![]), Item::Array(vec![Item::Array(vec![])])]),\n        ])\n    }\n\n    #[test]\n    #[expect(clippy::disallowed_macros)]\n    fn encode_decode_test() -> alloy_rlp::Result<()> {\n        let parameters = vec![\n            (1, b\"\\xc0\".to_vec(), Item::Array(vec![])),\n            (2, b\"\\xc1\\x80\".to_vec(), Item::Array(vec![Item::Data(vec![])])),\n            (3, b\"\\xc4\\x83dog\".to_vec(), Item::Array(vec![Item::Data(vec![0x64, 0x6f, 0x67])])),\n            (\n                4,\n                b\"\\xc5\\xc4\\x83dog\".to_vec(),\n                Item::Array(vec![Item::Array(vec![Item::Data(vec![0x64, 0x6f, 0x67])])]),\n            ),\n            (\n                5,\n                b\"\\xc8\\x83dog\\x83cat\".to_vec(),\n                Item::Array(vec![\n                    Item::Data(vec![0x64, 0x6f, 0x67]),\n                    Item::Data(vec![0x63, 0x61, 0x74]),\n                ]),\n            ),\n            (6, b\"\\xc7\\xc0\\xc1\\xc0\\xc3\\xc0\\xc1\\xc0\".to_vec(), array_von_neuman()),\n            (\n                7,\n                b\"\\xcd\\x83\\x6c\\x6f\\x6c\\xc3\\xc2\\xc1\\xc0\\xc4\\x83\\x6f\\x6c\\x6f\".to_vec(),\n                Item::Array(vec![\n                    Item::Data(vec![b'\\x6c', b'\\x6f', b'\\x6c']),\n                    Item::Array(vec![Item::Array(vec![Item::Array(vec![Item::Array(vec![])])])]),\n                    Item::Array(vec![Item::Data(vec![b'\\x6f', b'\\x6c', b'\\x6f'])]),\n                ]),\n            ),\n        ];\n        for params in parameters {\n            let encoded = alloy_rlp::encode(&params.2);\n            assert_eq!(Item::decode(&mut &encoded[..])?, params.2);\n            let decoded = Item::decode(&mut &params.1[..])?;\n            assert_eq!(alloy_rlp::encode(&decoded), params.1);\n            println!(\"case {} validated\", params.0)\n        }\n\n        Ok(())\n    }\n\n    #[test]\n    #[expect(clippy::disallowed_macros)]\n    fn deserialize_from_str_test_hex() -> JsonResult<()> {\n        let parameters = vec![\n            (1, \"[\\\"\\\"]\", Item::Array(vec![Item::Data(vec![])])),\n            (2, \"[\\\"0x646f67\\\"]\", Item::Array(vec![Item::Data(vec![0x64, 0x6f, 0x67])])),\n            (\n                3,\n                \"[[\\\"646f67\\\"]]\",\n                Item::Array(vec![Item::Array(vec![Item::Data(vec![0x64, 0x6f, 0x67])])]),\n            ),\n            (\n                4,\n                \"[\\\"646f67\\\",\\\"0x636174\\\"]\",\n                Item::Array(vec![\n                    Item::Data(vec![0x64, 0x6f, 0x67]),\n                    Item::Data(vec![0x63, 0x61, 0x74]),\n                ]),\n            ),\n            (6, \"[[],[[]],[[],[[]]]]\", array_von_neuman()),\n        ];\n        for params in parameters {\n            let val = serde_json::from_str(params.1)?;\n            let item = Item::value_to_item(&val).unwrap();\n            assert_eq!(item, params.2);\n            println!(\"case {} validated\", params.0);\n        }\n\n        Ok(())\n    }\n\n    #[test]\n    fn rlp_data() {\n        // <https://github.com/foundry-rs/foundry/issues/9197>\n        let hex_val_rlp = hex!(\"820002\");\n        let item = Item::decode(&mut &hex_val_rlp[..]).unwrap();\n\n        let data = hex!(\"0002\");\n        let encoded = alloy_rlp::encode(&data[..]);\n        let decoded: Bytes = alloy_rlp::decode_exact(&encoded[..]).unwrap();\n        assert_eq!(Item::Data(decoded.to_vec()), item);\n\n        let hex_val_rlp = hex!(\"00\");\n        let item = Item::decode(&mut &hex_val_rlp[..]).unwrap();\n\n        let data = hex!(\"00\");\n        let encoded = alloy_rlp::encode(&data[..]);\n        let decoded: Bytes = alloy_rlp::decode_exact(&encoded[..]).unwrap();\n        assert_eq!(Item::Data(decoded.to_vec()), item);\n    }\n}\n"
  },
  {
    "path": "crates/cast/src/tx.rs",
    "content": "use crate::traces::identifier::SignaturesIdentifier;\nuse alloy_consensus::{SidecarBuilder, SimpleCoder};\nuse alloy_dyn_abi::ErrorExt;\nuse alloy_ens::NameOrAddress;\nuse alloy_json_abi::Function;\nuse alloy_network::{Network, TransactionBuilder};\nuse alloy_primitives::{Address, B256, Bytes, TxHash, TxKind, U256, hex};\nuse alloy_provider::{PendingTransactionBuilder, Provider};\nuse alloy_rpc_types::{AccessList, Authorization, TransactionInputKind};\nuse alloy_signer::Signer;\nuse alloy_transport::TransportError;\nuse clap::Args;\nuse eyre::{Result, WrapErr};\nuse foundry_cli::{\n    opts::{CliAuthorizationList, EthereumOpts, TransactionOpts},\n    utils::{self, parse_function_args},\n};\nuse foundry_common::{\n    TransactionReceiptWithRevertReason, fmt::*, get_pretty_receipt_w_reason_attr, shell,\n};\nuse foundry_config::{Chain, Config};\nuse foundry_primitives::FoundryTransactionBuilder;\nuse foundry_wallets::{BrowserWalletOpts, WalletOpts, WalletSigner};\nuse itertools::Itertools;\nuse serde_json::value::RawValue;\nuse std::{fmt::Write, marker::PhantomData, str::FromStr, time::Duration};\n\n#[derive(Debug, Clone, Args)]\npub struct SendTxOpts {\n    /// Only print the transaction hash and exit immediately.\n    #[arg(id = \"async\", long = \"async\", alias = \"cast-async\", env = \"CAST_ASYNC\")]\n    pub cast_async: bool,\n\n    /// Wait for transaction receipt synchronously instead of polling.\n    /// Note: uses `eth_sendTransactionSync` which may not be supported by all clients.\n    #[arg(long, conflicts_with = \"async\")]\n    pub sync: bool,\n\n    /// The number of confirmations until the receipt is fetched.\n    #[arg(long, default_value = \"1\")]\n    pub confirmations: u64,\n\n    /// Timeout for sending the transaction.\n    #[arg(long, env = \"ETH_TIMEOUT\")]\n    pub timeout: Option<u64>,\n\n    /// Polling interval for transaction receipts (in seconds).\n    #[arg(long, alias = \"poll-interval\", env = \"ETH_POLL_INTERVAL\")]\n    pub poll_interval: Option<u64>,\n\n    /// Ethereum options\n    #[command(flatten)]\n    pub eth: EthereumOpts,\n\n    /// Browser wallet options\n    #[command(flatten)]\n    pub browser: BrowserWalletOpts,\n}\n\n/// Different sender kinds used by [`CastTxBuilder`].\npub enum SenderKind<'a> {\n    /// An address without signer. Used for read-only calls and transactions sent through unlocked\n    /// accounts.\n    Address(Address),\n    /// A reference to a signer.\n    Signer(&'a WalletSigner),\n    /// An owned signer.\n    OwnedSigner(Box<WalletSigner>),\n}\n\nimpl SenderKind<'_> {\n    /// Resolves the name to an Ethereum Address.\n    pub fn address(&self) -> Address {\n        match self {\n            Self::Address(addr) => *addr,\n            Self::Signer(signer) => signer.address(),\n            Self::OwnedSigner(signer) => signer.address(),\n        }\n    }\n\n    /// Resolves the sender from the wallet options.\n    ///\n    /// This function prefers the `from` field and may return a different address from the\n    /// configured signer\n    /// If from is specified, returns it\n    /// If from is not specified, but there is a signer configured, returns the signer's address\n    /// If from is not specified and there is no signer configured, returns zero address\n    pub async fn from_wallet_opts(opts: WalletOpts) -> Result<Self> {\n        if let Some(from) = opts.from {\n            Ok(from.into())\n        } else if let Ok(signer) = opts.signer().await {\n            Ok(Self::OwnedSigner(Box::new(signer)))\n        } else {\n            Ok(Address::ZERO.into())\n        }\n    }\n\n    /// Returns the signer if available.\n    pub fn as_signer(&self) -> Option<&WalletSigner> {\n        match self {\n            Self::Signer(signer) => Some(signer),\n            Self::OwnedSigner(signer) => Some(signer.as_ref()),\n            _ => None,\n        }\n    }\n}\n\nimpl From<Address> for SenderKind<'_> {\n    fn from(addr: Address) -> Self {\n        Self::Address(addr)\n    }\n}\n\nimpl<'a> From<&'a WalletSigner> for SenderKind<'a> {\n    fn from(signer: &'a WalletSigner) -> Self {\n        Self::Signer(signer)\n    }\n}\n\nimpl From<WalletSigner> for SenderKind<'_> {\n    fn from(signer: WalletSigner) -> Self {\n        Self::OwnedSigner(Box::new(signer))\n    }\n}\n\n/// Prevents a misconfigured hwlib from sending a transaction that defies user-specified --from\npub fn validate_from_address(\n    specified_from: Option<Address>,\n    signer_address: Address,\n) -> Result<()> {\n    if let Some(specified_from) = specified_from\n        && specified_from != signer_address\n    {\n        eyre::bail!(\n                \"\\\nThe specified sender via CLI/env vars does not match the sender configured via\nthe hardware wallet's HD Path.\nPlease use the `--hd-path <PATH>` parameter to specify the BIP32 Path which\ncorresponds to the sender, or let foundry automatically detect it by not specifying any sender address.\"\n            )\n    }\n    Ok(())\n}\n\n/// Initial state.\n#[derive(Debug)]\npub struct InitState;\n\n/// State with known [TxKind].\n#[derive(Debug)]\npub struct ToState {\n    to: Option<Address>,\n}\n\n/// State with known input for the transaction.\n#[derive(Debug)]\npub struct InputState {\n    kind: TxKind,\n    input: Vec<u8>,\n    func: Option<Function>,\n}\n\npub struct CastTxSender<N, P> {\n    provider: P,\n    _phantom: PhantomData<N>,\n}\n\nimpl<N: Network, P: Provider<N>> CastTxSender<N, P>\nwhere\n    N::TransactionRequest: FoundryTransactionBuilder<N>,\n    N::ReceiptResponse: UIfmt + UIfmtReceiptExt,\n{\n    /// Creates a new Cast instance responsible for sending transactions.\n    pub fn new(provider: P) -> Self {\n        Self { provider, _phantom: PhantomData }\n    }\n\n    /// Sends a transaction and waits for receipt synchronously\n    pub async fn send_sync(&self, tx: N::TransactionRequest) -> Result<String> {\n        let mut receipt = TransactionReceiptWithRevertReason::<N> {\n            receipt: self.provider.send_transaction_sync(tx).await?,\n            revert_reason: None,\n        };\n        // Allow to fail silently\n        let _ = receipt.update_revert_reason(&self.provider).await;\n\n        self.format_receipt(receipt, None)\n    }\n\n    /// Sends a transaction to the specified address\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// use cast::tx::CastTxSender;\n    /// use alloy_primitives::{Address, U256, Bytes};\n    /// use alloy_serde::WithOtherFields;\n    /// use alloy_rpc_types::{TransactionRequest};\n    /// use alloy_provider::{RootProvider, ProviderBuilder, network::AnyNetwork};\n    /// use std::str::FromStr;\n    /// use alloy_sol_types::{sol, SolCall};    ///\n    ///\n    /// sol!(\n    ///     function greet(string greeting) public;\n    /// );\n    ///\n    /// # async fn foo() -> eyre::Result<()> {\n    /// let provider = ProviderBuilder::<_,_, AnyNetwork>::default().connect(\"http://localhost:8545\").await?;;\n    /// let from = Address::from_str(\"0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045\")?;\n    /// let to = Address::from_str(\"0xB3C95ff08316fb2F2e3E52Ee82F8e7b605Aa1304\")?;\n    /// let greeting = greetCall { greeting: \"hello\".to_string() }.abi_encode();\n    /// let bytes = Bytes::from_iter(greeting.iter());\n    /// let gas = U256::from_str(\"200000\").unwrap();\n    /// let value = U256::from_str(\"1\").unwrap();\n    /// let nonce = U256::from_str(\"1\").unwrap();\n    /// let tx = TransactionRequest::default().to(to).input(bytes.into()).from(from);\n    /// let tx = WithOtherFields::new(tx);\n    /// let cast = CastTxSender::new(provider);\n    /// let data = cast.send(tx).await?;\n    /// println!(\"{:#?}\", data);\n    /// # Ok(())\n    /// # }\n    /// ```\n    pub async fn send(&self, tx: N::TransactionRequest) -> Result<PendingTransactionBuilder<N>> {\n        let res = self.provider.send_transaction(tx).await?;\n\n        Ok(res)\n    }\n\n    /// Sends a raw RLP-encoded transaction via `eth_sendRawTransaction`.\n    ///\n    /// Used for transaction types that the standard Alloy network stack doesn't understand\n    /// (e.g., Tempo transactions).\n    pub async fn send_raw(&self, raw_tx: &[u8]) -> Result<PendingTransactionBuilder<N>> {\n        let res = self.provider.send_raw_transaction(raw_tx).await?;\n        Ok(res)\n    }\n\n    /// Prints the transaction hash (if async) or waits for the receipt and prints it.\n    ///\n    /// This is the shared \"output\" path used by both the normal send flow and the browser wallet\n    /// flow (which sends the transaction out-of-band and only has a tx hash).\n    pub async fn print_tx_result(\n        &self,\n        tx_hash: B256,\n        cast_async: bool,\n        confs: u64,\n        timeout: u64,\n    ) -> Result<()> {\n        if cast_async {\n            sh_println!(\"{tx_hash:#x}\")?;\n        } else {\n            let receipt =\n                self.receipt(format!(\"{tx_hash:#x}\"), None, confs, Some(timeout), false).await?;\n            sh_println!(\"{receipt}\")?;\n        }\n        Ok(())\n    }\n\n    /// # Example\n    ///\n    /// ```\n    /// use alloy_provider::{ProviderBuilder, RootProvider, network::AnyNetwork};\n    /// use cast::tx::CastTxSender;\n    ///\n    /// async fn foo() -> eyre::Result<()> {\n    /// let provider =\n    ///     ProviderBuilder::<_, _, AnyNetwork>::default().connect(\"http://localhost:8545\").await?;\n    /// let cast = CastTxSender::new(provider);\n    /// let tx_hash = \"0xf8d1713ea15a81482958fb7ddf884baee8d3bcc478c5f2f604e008dc788ee4fc\";\n    /// let receipt = cast.receipt(tx_hash.to_string(), None, 1, None, false).await?;\n    /// println!(\"{}\", receipt);\n    /// # Ok(())\n    /// # }\n    /// ```\n    pub async fn receipt(\n        &self,\n        tx_hash: String,\n        field: Option<String>,\n        confs: u64,\n        timeout: Option<u64>,\n        cast_async: bool,\n    ) -> Result<String> {\n        let tx_hash = TxHash::from_str(&tx_hash).wrap_err(\"invalid tx hash\")?;\n\n        let mut receipt = TransactionReceiptWithRevertReason::<N> {\n            receipt: match self.provider.get_transaction_receipt(tx_hash).await? {\n                Some(r) => r,\n                None => {\n                    // if the async flag is provided, immediately exit if no tx is found, otherwise\n                    // try to poll for it\n                    if cast_async {\n                        eyre::bail!(\"tx not found: {:?}\", tx_hash)\n                    } else {\n                        PendingTransactionBuilder::<N>::new(self.provider.root().clone(), tx_hash)\n                            .with_required_confirmations(confs)\n                            .with_timeout(timeout.map(Duration::from_secs))\n                            .get_receipt()\n                            .await?\n                    }\n                }\n            },\n            revert_reason: None,\n        };\n\n        // Allow to fail silently\n        let _ = receipt.update_revert_reason(&self.provider).await;\n\n        self.format_receipt(receipt, field)\n    }\n\n    /// Helper method to format transaction receipts consistently\n    fn format_receipt(\n        &self,\n        receipt: TransactionReceiptWithRevertReason<N>,\n        field: Option<String>,\n    ) -> Result<String> {\n        Ok(if let Some(ref field) = field {\n            get_pretty_receipt_w_reason_attr(&receipt, field)\n                .ok_or_else(|| eyre::eyre!(\"invalid receipt field: {}\", field))?\n        } else if shell::is_json() {\n            // to_value first to sort json object keys\n            serde_json::to_value(&receipt)?.to_string()\n        } else {\n            receipt.pretty()\n        })\n    }\n}\n\n/// Builder type constructing generic TransactionRequest from cast send/mktx inputs.\n///\n/// It is implemented as a stateful builder with expected state transition of [InitState] ->\n/// [ToState] -> [InputState].\n#[derive(Debug)]\npub struct CastTxBuilder<N: Network, P, S> {\n    provider: P,\n    tx: N::TransactionRequest,\n    /// Whether the transaction should be sent as a legacy transaction.\n    legacy: bool,\n    blob: bool,\n    /// Whether the blob transaction should use EIP-4844 (legacy) format instead of EIP-7594.\n    eip4844: bool,\n    /// Whether to fill gas, fees and nonce. Set to `false` for read-only calls\n    /// (eth_call, eth_estimateGas, eth_createAccessList).\n    fill: bool,\n    auth: Vec<CliAuthorizationList>,\n    chain: Chain,\n    etherscan_api_key: Option<String>,\n    access_list: Option<Option<AccessList>>,\n    state: S,\n}\n\nimpl<N: Network, P: Provider<N>> CastTxBuilder<N, P, InitState>\nwhere\n    N::TransactionRequest: FoundryTransactionBuilder<N>,\n{\n    /// Creates a new instance of [CastTxBuilder] filling transaction with fields present in\n    /// provided [TransactionOpts].\n    pub async fn new(provider: P, tx_opts: TransactionOpts, config: &Config) -> Result<Self> {\n        let mut tx = N::TransactionRequest::default();\n\n        let chain = utils::get_chain(config.chain, &provider).await?;\n        let etherscan_api_key = config.get_etherscan_api_key(Some(chain));\n        // mark it as legacy if requested or the chain is legacy and no 7702 is provided.\n        let legacy = tx_opts.legacy || (chain.is_legacy() && tx_opts.auth.is_empty());\n\n        // Apply gas, value, fee, and network-specific options.\n        tx_opts.apply::<N>(&mut tx, legacy);\n\n        Ok(Self {\n            provider,\n            tx,\n            legacy,\n            blob: tx_opts.blob,\n            eip4844: tx_opts.eip4844,\n            fill: true,\n            chain,\n            etherscan_api_key,\n            auth: tx_opts.auth,\n            access_list: tx_opts.access_list,\n            state: InitState,\n        })\n    }\n\n    /// Sets [TxKind] for this builder and changes state to [ToState].\n    pub async fn with_to(self, to: Option<NameOrAddress>) -> Result<CastTxBuilder<N, P, ToState>> {\n        let to = if let Some(to) = to { Some(to.resolve(&self.provider).await?) } else { None };\n        Ok(CastTxBuilder {\n            provider: self.provider,\n            tx: self.tx,\n            legacy: self.legacy,\n            blob: self.blob,\n            eip4844: self.eip4844,\n            fill: self.fill,\n            chain: self.chain,\n            etherscan_api_key: self.etherscan_api_key,\n            auth: self.auth,\n            access_list: self.access_list,\n            state: ToState { to },\n        })\n    }\n}\n\nimpl<N: Network, P: Provider<N>> CastTxBuilder<N, P, ToState>\nwhere\n    N::TransactionRequest: FoundryTransactionBuilder<N>,\n{\n    /// Accepts user-provided code, sig and args params and constructs calldata for the transaction.\n    /// If code is present, input will be set to code + encoded constructor arguments. If no code is\n    /// present, input is set to just provided arguments.\n    pub async fn with_code_sig_and_args(\n        self,\n        code: Option<String>,\n        sig: Option<String>,\n        args: Vec<String>,\n    ) -> Result<CastTxBuilder<N, P, InputState>> {\n        let (mut args, func) = if let Some(sig) = sig {\n            parse_function_args(\n                &sig,\n                args,\n                self.state.to,\n                self.chain,\n                &self.provider,\n                self.etherscan_api_key.as_deref(),\n            )\n            .await?\n        } else {\n            (Vec::new(), None)\n        };\n\n        let input = if let Some(code) = &code {\n            let mut code = hex::decode(code)?;\n            code.append(&mut args);\n            code\n        } else {\n            args\n        };\n\n        if self.state.to.is_none() && code.is_none() {\n            let has_value = self.tx.value().is_some_and(|v| !v.is_zero());\n            let has_auth = !self.auth.is_empty();\n            // We only allow user to omit the recipient address if transaction is an EIP-7702 tx\n            // without a value.\n            if !has_auth || has_value {\n                eyre::bail!(\"Must specify a recipient address or contract code to deploy\");\n            }\n        }\n\n        Ok(CastTxBuilder {\n            provider: self.provider,\n            tx: self.tx,\n            legacy: self.legacy,\n            blob: self.blob,\n            eip4844: self.eip4844,\n            fill: self.fill,\n            chain: self.chain,\n            etherscan_api_key: self.etherscan_api_key,\n            auth: self.auth,\n            access_list: self.access_list,\n            state: InputState { kind: self.state.to.into(), input, func },\n        })\n    }\n}\n\nimpl<N: Network, P: Provider<N>> CastTxBuilder<N, P, InputState>\nwhere\n    N::TransactionRequest: FoundryTransactionBuilder<N>,\n{\n    /// Builds the TransactionRequest. Fills gas, fees and nonce unless [`raw`](Self::raw) was\n    /// called.\n    pub async fn build(\n        self,\n        sender: impl Into<SenderKind<'_>>,\n    ) -> Result<(N::TransactionRequest, Option<Function>)> {\n        let fill = self.fill;\n        self._build(sender, fill).await\n    }\n\n    async fn _build(\n        mut self,\n        sender: impl Into<SenderKind<'_>>,\n        fill: bool,\n    ) -> Result<(N::TransactionRequest, Option<Function>)> {\n        // prepare\n        let sender = sender.into();\n        self.prepare(&sender);\n\n        // resolve\n        let tx_nonce = self.resolve_nonce(sender.address(), fill).await?;\n        self.resolve_auth(&sender, tx_nonce).await?;\n        self.resolve_access_list().await?;\n\n        // fill\n        if fill {\n            self.fill_fees().await?;\n        }\n\n        Ok((self.tx, self.state.func))\n    }\n\n    /// Sets the core transaction fields from the builder state: kind, input, from, and chain id.\n    fn prepare(&mut self, sender: &SenderKind<'_>) {\n        self.tx.set_kind(self.state.kind);\n        // We set both fields to the same value because some nodes only accept the legacy\n        // `data` field: https://github.com/foundry-rs/foundry/issues/7764#issuecomment-2210453249\n        self.tx.set_input_kind(self.state.input.clone(), TransactionInputKind::Both);\n        self.tx.set_from(sender.address());\n        self.tx.set_chain_id(self.chain.id());\n    }\n\n    /// Resolves the transaction nonce. Returns the existing nonce or fetches one from the\n    /// provider. Only sets it on the transaction when `fill` is true.\n    async fn resolve_nonce(&mut self, from: Address, fill: bool) -> Result<u64> {\n        if let Some(nonce) = self.tx.nonce() {\n            Ok(nonce)\n        } else {\n            let nonce = self.provider.get_transaction_count(from).await?;\n            if fill {\n                self.tx.set_nonce(nonce);\n            }\n            Ok(nonce)\n        }\n    }\n\n    /// Resolves the access list. Fetches from the provider if `--access-list` was passed without\n    /// a value.\n    async fn resolve_access_list(&mut self) -> Result<()> {\n        if let Some(access_list) = match self.access_list.take() {\n            None => None,\n            Some(None) => Some(self.provider.create_access_list(&self.tx).await?.access_list),\n            Some(Some(access_list)) => Some(access_list),\n        } {\n            self.tx.set_access_list(access_list);\n        }\n        Ok(())\n    }\n\n    /// Parses the passed --auth values and sets the authorization list on the transaction.\n    ///\n    /// If a signer is available in `sender`, address-based auths will be signed.\n    /// If no signer is available, all auths must be pre-signed.\n    async fn resolve_auth(&mut self, sender: &SenderKind<'_>, tx_nonce: u64) -> Result<()> {\n        if self.auth.is_empty() {\n            return Ok(());\n        }\n\n        let auths = std::mem::take(&mut self.auth);\n\n        // Validate that at most one address-based auth is provided (multiple addresses are\n        // almost always unintended).\n        let address_auth_count =\n            auths.iter().filter(|a| matches!(a, CliAuthorizationList::Address(_))).count();\n        if address_auth_count > 1 {\n            eyre::bail!(\n                \"Multiple address-based authorizations provided. Only one address can be specified; \\\n                use pre-signed authorizations (hex-encoded) for multiple authorizations.\"\n            );\n        }\n\n        let mut signed_auths = Vec::with_capacity(auths.len());\n\n        for auth in auths {\n            let signed_auth = match auth {\n                CliAuthorizationList::Address(address) => {\n                    let auth = Authorization {\n                        chain_id: U256::from(self.chain.id()),\n                        nonce: tx_nonce + 1,\n                        address,\n                    };\n\n                    let Some(signer) = sender.as_signer() else {\n                        eyre::bail!(\n                            \"No signer available to sign authorization. \\\n                            Provide a pre-signed authorization (hex-encoded) instead.\"\n                        );\n                    };\n                    let signature = signer.sign_hash(&auth.signature_hash()).await?;\n\n                    auth.into_signed(signature)\n                }\n                CliAuthorizationList::Signed(auth) => auth,\n            };\n            signed_auths.push(signed_auth);\n        }\n\n        self.tx.set_authorization_list(signed_auths);\n\n        Ok(())\n    }\n\n    /// Fills gas price, EIP-1559 fees, blob fees, and gas limit from the provider.\n    ///\n    /// Only fills values that haven't been explicitly set by the user.\n    async fn fill_fees(&mut self) -> Result<()> {\n        if self.legacy && self.tx.gas_price().is_none() {\n            self.tx.set_gas_price(self.provider.get_gas_price().await?);\n        }\n\n        if self.blob && self.tx.max_fee_per_blob_gas().is_none() {\n            self.tx.set_max_fee_per_blob_gas(self.provider.get_blob_base_fee().await?)\n        }\n\n        if !self.legacy\n            && (self.tx.max_fee_per_gas().is_none() || self.tx.max_priority_fee_per_gas().is_none())\n        {\n            let estimate = self.provider.estimate_eip1559_fees().await?;\n\n            if self.tx.max_fee_per_gas().is_none() {\n                self.tx.set_max_fee_per_gas(estimate.max_fee_per_gas);\n            }\n\n            if self.tx.max_priority_fee_per_gas().is_none() {\n                self.tx.set_max_priority_fee_per_gas(estimate.max_priority_fee_per_gas);\n            }\n        }\n\n        if self.tx.gas_limit().is_none() {\n            self.estimate_gas().await?;\n        }\n\n        Ok(())\n    }\n\n    /// Estimate tx gas from provider call. Tries to decode custom error if execution reverted.\n    async fn estimate_gas(&mut self) -> Result<()> {\n        match self.provider.estimate_gas(self.tx.clone()).await {\n            Ok(estimated) => {\n                self.tx.set_gas_limit(estimated);\n                Ok(())\n            }\n            Err(err) => {\n                if let TransportError::ErrorResp(payload) = &err {\n                    // If execution reverted with code 3 during provider gas estimation then try\n                    // to decode custom errors and append it to the error message.\n                    if payload.code == 3\n                        && let Some(data) = &payload.data\n                        && let Ok(Some(decoded_error)) = decode_execution_revert(data).await\n                    {\n                        eyre::bail!(\"Failed to estimate gas: {}: {}\", err, decoded_error)\n                    }\n                }\n                eyre::bail!(\"Failed to estimate gas: {}\", err)\n            }\n        }\n    }\n\n    /// Populates the blob sidecar for the transaction if any blob data was provided.\n    pub fn with_blob_data(mut self, blob_data: Option<Vec<u8>>) -> Result<Self> {\n        let Some(blob_data) = blob_data else { return Ok(self) };\n\n        let mut coder = SidecarBuilder::<SimpleCoder>::default();\n        coder.ingest(&blob_data);\n\n        if self.eip4844 {\n            let sidecar = coder.build_4844()?;\n            self.tx.set_blob_sidecar_4844(sidecar);\n        } else {\n            let sidecar = coder.build_7594()?;\n            self.tx.set_blob_sidecar_7594(sidecar);\n        }\n\n        Ok(self)\n    }\n\n    /// Skips gas, fee and nonce filling. Use for read-only calls\n    /// (eth_call, eth_estimateGas, eth_createAccessList).\n    pub fn raw(mut self) -> Self {\n        self.fill = false;\n        self\n    }\n}\n\n/// Helper function that tries to decode custom error name and inputs from error payload data.\nasync fn decode_execution_revert(data: &RawValue) -> Result<Option<String>> {\n    let err_data = serde_json::from_str::<Bytes>(data.get())?;\n    let Some(selector) = err_data.get(..4) else { return Ok(None) };\n    if let Some(known_error) =\n        SignaturesIdentifier::new(false)?.identify_error(selector.try_into().unwrap()).await\n    {\n        let mut decoded_error = known_error.name.clone();\n        if !known_error.inputs.is_empty()\n            && let Ok(error) = known_error.decode_error(&err_data)\n        {\n            write!(decoded_error, \"({})\", format_tokens(&error.body).format(\", \"))?;\n        }\n        return Ok(Some(decoded_error));\n    }\n    Ok(None)\n}\n"
  },
  {
    "path": "crates/cast/tests/cli/erc20.rs",
    "content": "//! Contains various tests for checking cast erc20 subcommands\n\nuse alloy_primitives::U256;\nuse anvil::NodeConfig;\nuse foundry_test_utils::util::OutputExt;\n\nmod anvil_const {\n    /// First Anvil account\n    pub const PK1: &str = \"0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80\";\n    pub const ADDR1: &str = \"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266\";\n\n    /// Second Anvil account\n    pub const _PK2: &str = \"0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d\";\n    pub const ADDR2: &str = \"0x70997970C51812dc3A010C7d01b50e0d17dc79C8\";\n\n    /// Contract address deploying from ADDR1 with nonce 0\n    pub const TOKEN: &str = \"0x5FbDB2315678afecb367f032d93F642f64180aa3\";\n}\n\nfn get_u256_from_cmd(cmd: &mut foundry_test_utils::TestCommand, args: &[&str]) -> U256 {\n    let output = cmd.cast_fuse().args(args).assert_success().get_output().stdout_lossy();\n\n    // Parse balance from output (format: \"100000000000000000000 [1e20]\")\n    output.split_whitespace().next().unwrap().parse().unwrap()\n}\n\nfn get_balance(\n    cmd: &mut foundry_test_utils::TestCommand,\n    token: &str,\n    address: &str,\n    rpc: &str,\n) -> U256 {\n    get_u256_from_cmd(cmd, &[\"erc20\", \"balance\", token, address, \"--rpc-url\", rpc])\n}\n\nfn get_allowance(\n    cmd: &mut foundry_test_utils::TestCommand,\n    token: &str,\n    owner: &str,\n    spender: &str,\n    rpc: &str,\n) -> U256 {\n    get_u256_from_cmd(cmd, &[\"erc20\", \"allowance\", token, owner, spender, \"--rpc-url\", rpc])\n}\n\n/// Helper function to deploy TestToken contract\nfn deploy_test_token(\n    cmd: &mut foundry_test_utils::TestCommand,\n    rpc: &str,\n    private_key: &str,\n) -> String {\n    cmd.args([\n        \"create\",\n        \"--private-key\",\n        private_key,\n        \"--rpc-url\",\n        rpc,\n        \"--broadcast\",\n        \"src/TestToken.sol:TestToken\",\n    ])\n    .assert_success();\n\n    // Return the standard deployment address (nonce 0 from first account)\n    anvil_const::TOKEN.to_string()\n}\n\n/// Helper to setup anvil node and deploy test token\nasync fn setup_token_test(\n    prj: &foundry_test_utils::TestProject,\n    cmd: &mut foundry_test_utils::TestCommand,\n) -> (String, String) {\n    let (_, handle) = anvil::spawn(NodeConfig::test()).await;\n    let rpc = handle.http_endpoint();\n\n    // Deploy TestToken contract\n    foundry_test_utils::util::initialize(prj.root());\n    prj.add_source(\"TestToken.sol\", include_str!(\"../fixtures/TestToken.sol\"));\n    let token = deploy_test_token(cmd, &rpc, anvil_const::PK1);\n\n    (rpc, token)\n}\n\n// tests that `balance` and `transfer` commands works correctly\nforgetest_async!(erc20_transfer_approve_success, |prj, cmd| {\n    let (rpc, token) = setup_token_test(&prj, &mut cmd).await;\n\n    // Test constants\n    let transfer_amount = U256::from(100_000_000_000_000_000_000u128); // 100 tokens (18 decimals)\n    let initial_supply = U256::from(1_000_000_000_000_000_000_000u128); // 1000 tokens total supply\n\n    // Verify initial balances\n    let addr1_balance_before = get_balance(&mut cmd, &token, anvil_const::ADDR1, &rpc);\n    let addr2_balance_before = get_balance(&mut cmd, &token, anvil_const::ADDR2, &rpc);\n    assert_eq!(addr1_balance_before, initial_supply);\n    assert_eq!(addr2_balance_before, U256::ZERO);\n\n    // Test ERC20 transfer from ADDR1 to ADDR2\n    cmd.cast_fuse()\n        .args([\n            \"erc20\",\n            \"transfer\",\n            &token,\n            anvil_const::ADDR2,\n            &transfer_amount.to_string(),\n            \"--rpc-url\",\n            &rpc,\n            \"--private-key\",\n            anvil_const::PK1,\n        ])\n        .assert_success();\n\n    // Verify balance changes after transfer\n    let addr1_balance_after = get_balance(&mut cmd, &token, anvil_const::ADDR1, &rpc);\n    let addr2_balance_after = get_balance(&mut cmd, &token, anvil_const::ADDR2, &rpc);\n    assert_eq!(addr1_balance_after, addr1_balance_before - transfer_amount);\n    assert_eq!(addr2_balance_after, addr2_balance_before + transfer_amount);\n});\n\n// tests that `approve` and `allowance` commands works correctly\nforgetest_async!(erc20_approval_allowance, |prj, cmd| {\n    let (rpc, token) = setup_token_test(&prj, &mut cmd).await;\n\n    // ADDR1 approves ADDR2 to spend their tokens\n    let approve_amount = U256::from(50_000_000_000_000_000_000u128); // 50 tokens\n    cmd.cast_fuse()\n        .args([\n            \"erc20\",\n            \"approve\",\n            &token,\n            anvil_const::ADDR2,\n            &approve_amount.to_string(),\n            \"--rpc-url\",\n            &rpc,\n            \"--private-key\",\n            anvil_const::PK1,\n        ])\n        .assert_success();\n\n    // Verify allowance was set\n    let allowance = get_allowance(&mut cmd, &token, anvil_const::ADDR1, anvil_const::ADDR2, &rpc);\n    assert_eq!(allowance, approve_amount);\n});\n\n// tests that `name`, `symbol`, `decimals`, and `totalSupply` commands work correctly\nforgetest_async!(erc20_metadata_success, |prj, cmd| {\n    let (rpc, token) = setup_token_test(&prj, &mut cmd).await;\n\n    // Test name\n    let output = cmd\n        .cast_fuse()\n        .args([\"erc20\", \"name\", &token, \"--rpc-url\", &rpc])\n        .assert_success()\n        .get_output()\n        .stdout_lossy();\n    assert_eq!(output.trim(), \"Test Token\");\n\n    // Test symbol\n    let output = cmd\n        .cast_fuse()\n        .args([\"erc20\", \"symbol\", &token, \"--rpc-url\", &rpc])\n        .assert_success()\n        .get_output()\n        .stdout_lossy();\n    assert_eq!(output.trim(), \"TEST\");\n\n    // Test decimals\n    let output = cmd\n        .cast_fuse()\n        .args([\"erc20\", \"decimals\", &token, \"--rpc-url\", &rpc])\n        .assert_success()\n        .get_output()\n        .stdout_lossy();\n    assert_eq!(output.trim(), \"18\");\n\n    // Test totalSupply\n    let output = cmd\n        .cast_fuse()\n        .args([\"erc20\", \"total-supply\", &token, \"--rpc-url\", &rpc])\n        .assert_success()\n        .get_output()\n        .stdout_lossy();\n    let total_supply: U256 = output.split_whitespace().next().unwrap().parse().unwrap();\n    assert_eq!(total_supply, U256::from(1_000_000_000_000_000_000_000u128));\n});\n\n// tests that `mint` command works correctly\nforgetest_async!(erc20_mint_success, |prj, cmd| {\n    let (rpc, token) = setup_token_test(&prj, &mut cmd).await;\n\n    let mint_amount = U256::from(500_000_000_000_000_000_000u128); // 500 tokens\n    let initial_supply = U256::from(1_000_000_000_000_000_000_000u128); // 1000 tokens\n\n    // Get initial balance and supply\n    let addr2_balance_before = get_balance(&mut cmd, &token, anvil_const::ADDR2, &rpc);\n    assert_eq!(addr2_balance_before, U256::ZERO);\n\n    // Mint tokens to ADDR2 (only owner can mint)\n    cmd.cast_fuse()\n        .args([\n            \"erc20\",\n            \"mint\",\n            &token,\n            anvil_const::ADDR2,\n            &mint_amount.to_string(),\n            \"--rpc-url\",\n            &rpc,\n            \"--private-key\",\n            anvil_const::PK1, // PK1 is the owner/deployer\n        ])\n        .assert_success();\n\n    // Verify balance increased\n    let addr2_balance_after = get_balance(&mut cmd, &token, anvil_const::ADDR2, &rpc);\n    assert_eq!(addr2_balance_after, mint_amount);\n\n    // Verify totalSupply increased\n    let output = cmd\n        .cast_fuse()\n        .args([\"erc20\", \"total-supply\", &token, \"--rpc-url\", &rpc])\n        .assert_success()\n        .get_output()\n        .stdout_lossy();\n    let total_supply: U256 = output.split_whitespace().next().unwrap().parse().unwrap();\n    assert_eq!(total_supply, initial_supply + mint_amount);\n});\n\n// tests that `burn` command works correctly\nforgetest_async!(erc20_burn_success, |prj, cmd| {\n    let (rpc, token) = setup_token_test(&prj, &mut cmd).await;\n\n    let burn_amount = U256::from(200_000_000_000_000_000_000u128); // 200 tokens\n    let initial_supply = U256::from(1_000_000_000_000_000_000_000u128); // 1000 tokens\n\n    // Get initial balance\n    let addr1_balance_before = get_balance(&mut cmd, &token, anvil_const::ADDR1, &rpc);\n    assert_eq!(addr1_balance_before, initial_supply);\n\n    // Burn tokens from ADDR1\n    cmd.cast_fuse()\n        .args([\n            \"erc20\",\n            \"burn\",\n            &token,\n            &burn_amount.to_string(),\n            \"--rpc-url\",\n            &rpc,\n            \"--private-key\",\n            anvil_const::PK1,\n        ])\n        .assert_success();\n\n    // Verify balance decreased\n    let addr1_balance_after = get_balance(&mut cmd, &token, anvil_const::ADDR1, &rpc);\n    assert_eq!(addr1_balance_after, addr1_balance_before - burn_amount);\n\n    // Verify totalSupply decreased\n    let output = cmd\n        .cast_fuse()\n        .args([\"erc20\", \"total-supply\", &token, \"--rpc-url\", &rpc])\n        .assert_success()\n        .get_output()\n        .stdout_lossy();\n    let total_supply: U256 = output.split_whitespace().next().unwrap().parse().unwrap();\n    assert_eq!(total_supply, initial_supply - burn_amount);\n});\n\n// tests that `transfer` command works with gas options\nforgetest_async!(erc20_transfer_with_gas_opts, |prj, cmd| {\n    let (rpc, token) = setup_token_test(&prj, &mut cmd).await;\n\n    let transfer_amount = U256::from(100_000_000_000_000_000_000u128); // 100 tokens\n\n    // Transfer with explicit gas limit and gas price\n    cmd.cast_fuse()\n        .args([\n            \"erc20\",\n            \"transfer\",\n            &token,\n            anvil_const::ADDR2,\n            &transfer_amount.to_string(),\n            \"--rpc-url\",\n            &rpc,\n            \"--private-key\",\n            anvil_const::PK1,\n            \"--gas-limit\",\n            \"100000\",\n            \"--gas-price\",\n            \"2000000000\",\n        ])\n        .assert_success();\n\n    // Verify transfer succeeded\n    let balance = get_balance(&mut cmd, &token, anvil_const::ADDR2, &rpc);\n    assert_eq!(balance, transfer_amount);\n});\n\n// tests that `transfer` command fails with insufficient gas limit\nforgetest_async!(erc20_transfer_insufficient_gas, |prj, cmd| {\n    let (rpc, token) = setup_token_test(&prj, &mut cmd).await;\n\n    let transfer_amount = U256::from(50_000_000_000_000_000_000u128); // 50 tokens\n\n    // Transfer with insufficient gas limit (ERC20 transfer needs ~50k gas)\n    cmd.cast_fuse()\n        .args([\n            \"erc20\",\n            \"transfer\",\n            &token,\n            anvil_const::ADDR2,\n            &transfer_amount.to_string(),\n            \"--rpc-url\",\n            &rpc,\n            \"--private-key\",\n            anvil_const::PK1,\n            \"--gas-limit\",\n            \"1000\", // Way too low for ERC20 transfer\n        ])\n        .assert_failure();\n\n    // Verify transfer did NOT occur\n    let balance = get_balance(&mut cmd, &token, anvil_const::ADDR2, &rpc);\n    assert_eq!(balance, U256::ZERO);\n});\n\n// tests that `transfer` command fails with incorrect nonce\nforgetest_async!(erc20_transfer_incorrect_nonce, |prj, cmd| {\n    let (rpc, token) = setup_token_test(&prj, &mut cmd).await;\n\n    let transfer_amount = U256::from(50_000_000_000_000_000_000u128); // 50 tokens\n\n    cmd.cast_fuse()\n        .args([\n            \"erc20\",\n            \"transfer\",\n            &token,\n            anvil_const::ADDR2,\n            &transfer_amount.to_string(),\n            \"--rpc-url\",\n            &rpc,\n            \"--private-key\",\n            anvil_const::PK1,\n        ])\n        .assert_success();\n\n    // Transfer with nonce too low\n    cmd.cast_fuse()\n        .args([\n            \"erc20\",\n            \"transfer\",\n            &token,\n            anvil_const::ADDR2,\n            &transfer_amount.to_string(),\n            \"--rpc-url\",\n            &rpc,\n            \"--private-key\",\n            anvil_const::PK1,\n            \"--nonce\",\n            \"0\", // Too low nonce\n        ])\n        .assert_failure();\n\n    // Verify transfer did NOT occur\n    let balance = get_balance(&mut cmd, &token, anvil_const::ADDR2, &rpc);\n    assert_eq!(balance, transfer_amount); // 2nd transfer failed\n});\n\n// tests that the --curl flag outputs a valid curl command for cast erc20 balance\ncasttest!(curl_erc20_balance, |_prj, cmd| {\n    let rpc = \"https://eth.example.com\";\n    let token = \"0xdead000000000000000000000000000000000000\";\n    let owner = \"0xbeef000000000000000000000000000000000000\";\n\n    let output = cmd\n        .args([\"erc20\", \"balance\", token, owner, \"--rpc-url\", rpc, \"--curl\"])\n        .assert_success()\n        .get_output()\n        .stdout_lossy();\n\n    // Verify curl command structure\n    assert!(output.contains(\"curl -X POST\"));\n    assert!(output.contains(\"eth_call\"));\n    assert!(output.contains(rpc));\n});\n\n// tests that the --curl flag outputs a valid curl command for cast erc20 name\ncasttest!(curl_erc20_name, |_prj, cmd| {\n    let rpc = \"https://eth.example.com\";\n    let token = \"0xdead000000000000000000000000000000000000\";\n\n    let output = cmd\n        .args([\"erc20\", \"name\", token, \"--rpc-url\", rpc, \"--curl\"])\n        .assert_success()\n        .get_output()\n        .stdout_lossy();\n\n    // Verify curl command structure\n    assert!(output.contains(\"curl -X POST\"));\n    assert!(output.contains(\"eth_call\"));\n    assert!(output.contains(rpc));\n});\n\n// tests that the --curl flag outputs a valid curl command for cast erc20 decimals\ncasttest!(curl_erc20_decimals, |_prj, cmd| {\n    let rpc = \"https://eth.example.com\";\n    let token = \"0xdead000000000000000000000000000000000000\";\n\n    let output = cmd\n        .args([\"erc20\", \"decimals\", token, \"--rpc-url\", rpc, \"--curl\"])\n        .assert_success()\n        .get_output()\n        .stdout_lossy();\n\n    // Verify curl command structure\n    assert!(output.contains(\"curl -X POST\"));\n    assert!(output.contains(\"eth_call\"));\n    assert!(output.contains(rpc));\n});\n\n// tests that the --curl flag outputs a valid curl command for cast erc20 total-supply\ncasttest!(curl_erc20_total_supply, |_prj, cmd| {\n    let rpc = \"https://eth.example.com\";\n    let token = \"0xdead000000000000000000000000000000000000\";\n\n    let output = cmd\n        .args([\"erc20\", \"total-supply\", token, \"--rpc-url\", rpc, \"--curl\"])\n        .assert_success()\n        .get_output()\n        .stdout_lossy();\n\n    // Verify curl command structure\n    assert!(output.contains(\"curl -X POST\"));\n    assert!(output.contains(\"eth_call\"));\n    assert!(output.contains(rpc));\n});\n\n// tests that the --curl flag outputs a valid curl command for erc20 balance\ncasttest!(erc20_curl_balance, |_prj, cmd| {\n    let rpc = \"https://eth.example.com\";\n    let token = \"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48\"; // USDC\n    let owner = \"0xdead000000000000000000000000000000000000\";\n\n    let output = cmd\n        .args([\"erc20\", \"balance\", token, owner, \"--rpc-url\", rpc, \"--curl\"])\n        .assert_success()\n        .get_output()\n        .stdout_lossy();\n\n    // Verify curl command structure\n    assert!(output.contains(\"curl -X POST\"));\n    assert!(output.contains(\"eth_call\"));\n    assert!(output.contains(rpc));\n});\n\n// tests that the --curl flag outputs a valid curl command for erc20 name\ncasttest!(erc20_curl_name, |_prj, cmd| {\n    let rpc = \"https://eth.example.com\";\n    let token = \"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48\"; // USDC\n\n    let output = cmd\n        .args([\"erc20\", \"name\", token, \"--rpc-url\", rpc, \"--curl\"])\n        .assert_success()\n        .get_output()\n        .stdout_lossy();\n\n    // Verify curl command structure\n    assert!(output.contains(\"curl -X POST\"));\n    assert!(output.contains(\"eth_call\"));\n    assert!(output.contains(rpc));\n});\n\n// tests that the --curl flag outputs a valid curl command for erc20 decimals\ncasttest!(erc20_curl_decimals, |_prj, cmd| {\n    let rpc = \"https://eth.example.com\";\n    let token = \"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48\"; // USDC\n\n    let output = cmd\n        .args([\"erc20\", \"decimals\", token, \"--rpc-url\", rpc, \"--curl\"])\n        .assert_success()\n        .get_output()\n        .stdout_lossy();\n\n    // Verify curl command structure\n    assert!(output.contains(\"curl -X POST\"));\n    assert!(output.contains(\"eth_call\"));\n    assert!(output.contains(rpc));\n});\n\n// tests that the --curl flag outputs a valid curl command for erc20 total-supply\ncasttest!(erc20_curl_total_supply, |_prj, cmd| {\n    let rpc = \"https://eth.example.com\";\n    let token = \"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48\"; // USDC\n\n    let output = cmd\n        .args([\"erc20\", \"total-supply\", token, \"--rpc-url\", rpc, \"--curl\"])\n        .assert_success()\n        .get_output()\n        .stdout_lossy();\n\n    // Verify curl command structure\n    assert!(output.contains(\"curl -X POST\"));\n    assert!(output.contains(\"eth_call\"));\n    assert!(output.contains(rpc));\n});\n\n// tests that `balance` command works correctly with --json flag\nforgetest_async!(erc20_balance_json, |prj, cmd| {\n    let (rpc, token) = setup_token_test(&prj, &mut cmd).await;\n\n    let output = cmd\n        .cast_fuse()\n        .args([\"--json\", \"erc20\", \"balance\", &token, anvil_const::ADDR1, \"--rpc-url\", &rpc])\n        .assert_success()\n        .get_output()\n        .stdout_lossy();\n\n    let balance_str: String = serde_json::from_str(&output).expect(\"valid json string\");\n    let balance: U256 = balance_str.parse().unwrap();\n    assert_eq!(balance, U256::from(1_000_000_000_000_000_000_000u128));\n});\n\n// tests that `allowance` command works correctly with --json flag\nforgetest_async!(erc20_allowance_json, |prj, cmd| {\n    let (rpc, token) = setup_token_test(&prj, &mut cmd).await;\n\n    // First approve some tokens\n    let approve_amount = U256::from(50_000_000_000_000_000_000u128);\n    cmd.cast_fuse()\n        .args([\n            \"erc20\",\n            \"approve\",\n            &token,\n            anvil_const::ADDR2,\n            &approve_amount.to_string(),\n            \"--rpc-url\",\n            &rpc,\n            \"--private-key\",\n            anvil_const::PK1,\n        ])\n        .assert_success();\n\n    // Check allowance with JSON flag\n    let output = cmd\n        .cast_fuse()\n        .args([\n            \"--json\",\n            \"erc20\",\n            \"allowance\",\n            &token,\n            anvil_const::ADDR1,\n            anvil_const::ADDR2,\n            \"--rpc-url\",\n            &rpc,\n        ])\n        .assert_success()\n        .get_output()\n        .stdout_lossy();\n\n    let allowance_str: String = serde_json::from_str(&output).expect(\"valid json string\");\n    let allowance: U256 = allowance_str.parse().unwrap();\n    assert_eq!(allowance, approve_amount);\n});\n\n// tests that `name`, `symbol`, `decimals`, and `totalSupply` commands work correctly with --json\n// flag\nforgetest_async!(erc20_metadata_json, |prj, cmd| {\n    let (rpc, token) = setup_token_test(&prj, &mut cmd).await;\n\n    // Test name with --json\n    let output = cmd\n        .cast_fuse()\n        .args([\"--json\", \"erc20\", \"name\", &token, \"--rpc-url\", &rpc])\n        .assert_success()\n        .get_output()\n        .stdout_lossy();\n    let name: String = serde_json::from_str(&output).expect(\"valid json string\");\n    assert_eq!(name, \"Test Token\");\n\n    // Test symbol with --json\n    let output = cmd\n        .cast_fuse()\n        .args([\"--json\", \"erc20\", \"symbol\", &token, \"--rpc-url\", &rpc])\n        .assert_success()\n        .get_output()\n        .stdout_lossy();\n    let symbol: String = serde_json::from_str(&output).expect(\"valid json string\");\n    assert_eq!(symbol, \"TEST\");\n\n    // Test decimals with --json\n    let output = cmd\n        .cast_fuse()\n        .args([\"--json\", \"erc20\", \"decimals\", &token, \"--rpc-url\", &rpc])\n        .assert_success()\n        .get_output()\n        .stdout_lossy();\n    let decimals: u8 = output.trim().parse().expect(\"valid number\");\n    assert_eq!(decimals, 18);\n\n    // Test totalSupply with --json\n    let output = cmd\n        .cast_fuse()\n        .args([\"--json\", \"erc20\", \"total-supply\", &token, \"--rpc-url\", &rpc])\n        .assert_success()\n        .get_output()\n        .stdout_lossy();\n    let total_supply_str: String = serde_json::from_str(&output).expect(\"valid json string\");\n    let total_supply: U256 = total_supply_str.parse().unwrap();\n    assert_eq!(total_supply, U256::from(1_000_000_000_000_000_000_000u128));\n});\n"
  },
  {
    "path": "crates/cast/tests/cli/main.rs",
    "content": "//! Contains various tests for checking cast commands\n\nuse alloy_chains::NamedChain;\nuse alloy_hardforks::EthereumHardfork;\nuse alloy_network::{TransactionBuilder, TransactionResponse};\nuse alloy_primitives::{B256, Bytes, U256, address, b256, hex};\nuse alloy_provider::{Provider, ProviderBuilder};\nuse alloy_rpc_types::{Authorization, BlockNumberOrTag, Index, TransactionRequest};\nuse alloy_signer::Signer;\nuse alloy_signer_local::PrivateKeySigner;\nuse anvil::NodeConfig;\nuse foundry_test_utils::{\n    rpc::{\n        next_etherscan_api_key, next_http_archive_rpc_url, next_http_rpc_endpoint,\n        next_rpc_endpoint, next_ws_rpc_endpoint,\n    },\n    snapbox::IntoData as _,\n    str,\n    util::OutputExt,\n};\nuse serde_json::json;\nuse std::{fs, path::Path, str::FromStr};\n\n#[macro_use]\nextern crate foundry_test_utils;\n\nmod erc20;\nmod selectors;\n\ncasttest!(print_short_version, |_prj, cmd| {\n    cmd.arg(\"-V\").assert_success().stdout_eq(str![[r#\"\ncast [..]-[..] ([..] [..])\n\n\"#]]);\n});\n\ncasttest!(print_long_version, |_prj, cmd| {\n    cmd.arg(\"--version\").assert_success().stdout_eq(str![[r#\"\ncast Version: [..]\nCommit SHA: [..]\nBuild Timestamp: [..]\nBuild Profile: [..]\n\n\"#]]);\n});\n\n// tests `--help` is printed to std out\ncasttest!(print_help, |_prj, cmd| {\n    cmd.arg(\"--help\").assert_success().stdout_eq(str![[r#\"\nA Swiss Army knife for interacting with Ethereum applications from the command line\n\nUsage: cast[..] <COMMAND>\n\nCommands:\n...\n\nOptions:\n  -h, --help\n          Print help (see a summary with '-h')\n\n  -j, --threads <THREADS>\n          Number of threads to use. Specifying 0 defaults to the number of logical cores\n...\n          [aliases: --jobs]\n\n  -V, --version\n          Print version\n\nDisplay options:\n      --color <COLOR>\n          The color of the log messages\n\n          Possible values:\n          - auto:   Intelligently guess whether to use color output (default)\n          - always: Force color output\n          - never:  Force disable color output\n\n      --json\n          Format log messages as JSON\n\n      --md\n          Format log messages as Markdown\n\n  -q, --quiet\n          Do not print log messages\n\n  -v, --verbosity...\n          Verbosity level of the log messages.\n...\n          Pass multiple times to increase the verbosity (e.g. -v, -vv, -vvv).\n...\n          Depending on the context the verbosity levels have different meanings.\n...\n          For example, the verbosity levels of the EVM are:\n          - 2 (-vv): Print logs for all tests.\n          - 3 (-vvv): Print execution traces for failing tests.\n          - 4 (-vvvv): Print execution traces for all tests, and setup traces for failing tests.\n          - 5 (-vvvvv): Print execution and setup traces for all tests, including storage changes\n          and\n            backtraces with line numbers.\n\nFind more information in the book: https://getfoundry.sh/cast/overview\n\n\"#]]);\n});\n\n// tests that the `cast block` command works correctly\ncasttest!(latest_block, |_prj, cmd| {\n    let eth_rpc_url = next_http_rpc_endpoint();\n\n    // Call `cast find-block`\n    cmd.args([\"block\", \"latest\", \"--rpc-url\", eth_rpc_url.as_str()]);\n    cmd.assert_success().stdout_eq(str![[r#\"\n\n\nbaseFeePerGas        [..]\ndifficulty           [..]\nextraData            [..]\ngasLimit             [..]\ngasUsed              [..]\nhash                 [..]\nlogsBloom            [..]\nminer                [..]\nmixHash              [..]\nnonce                [..]\nnumber               [..]\nparentHash           [..]\nparentBeaconRoot     [..]\ntransactionsRoot     [..]\nreceiptsRoot         [..]\nsha3Uncles           [..]\nsize                 [..]\nstateRoot            [..]\ntimestamp            [..]\nwithdrawalsRoot      [..]\ntotalDifficulty      [..]\nblobGasUsed          [..]\nexcessBlobGas        [..]\nrequestsHash         [..]\ntransactions:        [\n...\n]\n\n\"#]]);\n\n    // <https://etherscan.io/block/15007840>\n    cmd.cast_fuse().args([\n        \"block\",\n        \"15007840\",\n        \"-f\",\n        \"hash,timestamp\",\n        \"--rpc-url\",\n        eth_rpc_url.as_str(),\n    ]);\n    cmd.assert_success().stdout_eq(str![[r#\"\n0x950091817a57e22b6c1f3b951a15f52d41ac89b299cc8f9c89bb6d185f80c415\n1655904485\n\n\"#]]);\n});\n\ncasttest!(block_raw, |_prj, cmd| {\n    let eth_rpc_url = next_http_rpc_endpoint();\n\n    let output = cmd\n        .args([\"block\", \"22934900\", \"--rpc-url\", eth_rpc_url.as_str(), \"--raw\"])\n        .assert_success()\n        .get_output()\n        .stdout_lossy()\n        .trim()\n        .to_string();\n\n    // Hash the output with keccak256\n    let hash = alloy_primitives::keccak256(hex::decode(output).unwrap());\n\n    // Verify the Mainnet's block #22934900 header hash equals the expected value\n    // obtained with go-ethereum's `block.Header().Hash()` method\n    assert_eq!(\n        hash.to_string(),\n        \"0x49fd7f3b9ba5d67fa60197027f09454d4cac945e8f271edcc84c3fd5872446d3\"\n    );\n});\n\ncasttest!(block_raw_tempo, |_prj, cmd| {\n    // https://explore.tempo.xyz/block/8386710\n    let output = cmd\n        .args([\n            \"block\",\n            \"8386710\",\n            \"--rpc-url\",\n            \"https://rpc.moderato.tempo.xyz\",\n            \"--raw\",\n            \"-n\",\n            \"tempo\",\n        ])\n        .assert_success()\n        .get_output()\n        .stdout_lossy()\n        .trim()\n        .to_string();\n\n    let hash = alloy_primitives::keccak256(hex::decode(output).unwrap());\n\n    assert_eq!(\n        hash.to_string(),\n        \"0xcd6170dc28b888bcb93ed1ad76a6bea4ad9977b678db5d462df83d35ec9b8d15\"\n    );\n});\n\n// tests that the `cast find-block` command works correctly\ncasttest!(finds_block, |_prj, cmd| {\n    // Construct args\n    let timestamp = \"1647843609\".to_string();\n    let eth_rpc_url = next_http_rpc_endpoint();\n\n    // Call `cast find-block`\n    // <https://etherscan.io/block/14428082>\n    cmd.args([\"find-block\", \"--rpc-url\", eth_rpc_url.as_str(), &timestamp])\n        .assert_success()\n        .stdout_eq(str![[r#\"\n14428082\n\n\"#]]);\n});\n\n// tests that we can create a new wallet\ncasttest!(new_wallet, |_prj, cmd| {\n    cmd.args([\"wallet\", \"new\"]).assert_success().stdout_eq(str![[r#\"\nSuccessfully created new keypair.\n[ADDRESS]\n[PRIVATE_KEY]\n\n\"#]]);\n});\n\n// tests that we can create a new wallet (verbose variant)\ncasttest!(new_wallet_verbose, |_prj, cmd| {\n    cmd.args([\"wallet\", \"new\", \"-v\"]).assert_success().stdout_eq(str![[r#\"\nSuccessfully created new keypair.\n[ADDRESS]\n[PUBLIC_KEY]\n[PRIVATE_KEY]\n\n\"#]]);\n});\n\n// tests that we can create a new wallet with json output\ncasttest!(new_wallet_json, |_prj, cmd| {\n    cmd.args([\"wallet\", \"new\", \"--json\"]).assert_success().stdout_eq(\n        str![[r#\"\n[\n  {\n    \"address\": \"{...}\",\n    \"private_key\": \"{...}\"\n  }\n]\n\n\"#]]\n        .is_json(),\n    );\n});\n\n// tests that we can create a new wallet with json output (verbose variant)\ncasttest!(new_wallet_json_verbose, |_prj, cmd| {\n    cmd.args([\"wallet\", \"new\", \"--json\", \"-v\"]).assert_success().stdout_eq(\n        str![[r#\"\n[\n  {\n    \"address\": \"{...}\",\n    \"public_key\": \"{...}\",\n    \"private_key\": \"{...}\"\n  }\n]\n\n\"#]]\n        .is_json(),\n    );\n});\n\n// tests that we can create a new wallet with keystore\ncasttest!(new_wallet_keystore_with_password, |_prj, cmd| {\n    cmd.args([\"wallet\", \"new\", \".\", \"test-account\", \"--unsafe-password\", \"test\"])\n        .assert_success()\n        .stdout_eq(str![[r#\"\nCreated new encrypted keystore file: [..]\n[ADDRESS]\n\n\"#]]);\n});\n\n// tests that we can create a new wallet with keystore (verbose variant)\ncasttest!(new_wallet_keystore_with_password_verbose, |_prj, cmd| {\n    cmd.args([\"wallet\", \"new\", \".\", \"test-account\", \"--unsafe-password\", \"test\", \"-v\"])\n        .assert_success()\n        .stdout_eq(str![[r#\"\nCreated new encrypted keystore file: [..]\n[ADDRESS]\n[PUBLIC_KEY]\n\n\"#]]);\n});\n\n// tests that `cast wallet new` prompts before overwriting an existing keystore file\ncasttest!(new_wallet_keystore_overwrite_protection, |prj, cmd| {\n    // Create the initial keystore\n    cmd.args([\"wallet\", \"new\", \".\", \"test-account\", \"--unsafe-password\", \"test\"]).assert_success();\n\n    // Attempt to overwrite with stdin \"n\" — should be cancelled\n    cmd.cast_fuse()\n        .current_dir(prj.root())\n        .args([\"wallet\", \"new\", \".\", \"test-account\", \"--unsafe-password\", \"test\"])\n        .stdin(\"n\\n\")\n        .assert_failure()\n        .stderr_eq(str![[r#\"\nThe following keystore file(s) already exist:\n   - test-account\nError: Operation cancelled. No keystores were modified.\n\n\"#]]);\n});\n\n// tests that `cast wallet new --force` overwrites existing keystore files without prompting\ncasttest!(new_wallet_keystore_overwrite_force, |prj, cmd| {\n    // Create the initial keystore\n    cmd.args([\"wallet\", \"new\", \".\", \"test-account\", \"--unsafe-password\", \"test\"]).assert_success();\n\n    // Overwrite with --force — should succeed without prompting\n    cmd.cast_fuse()\n        .current_dir(prj.root())\n        .args([\"wallet\", \"new\", \".\", \"test-account\", \"--unsafe-password\", \"test\", \"--force\"])\n        .assert_success()\n        .stdout_eq(str![[r#\"\nCreated new encrypted keystore file: [..]\n[ADDRESS]\n\n\"#]]);\n});\n\n// tests that `cast wallet new -n 2` prompts before overwriting existing keystore files\ncasttest!(new_wallet_keystore_overwrite_protection_multiple, |prj, cmd| {\n    // Create 2 keystores: test-account_1 and test-account_2\n    cmd.args([\"wallet\", \"new\", \".\", \"test-account\", \"--unsafe-password\", \"test\", \"-n\", \"2\"])\n        .assert_success();\n\n    // Attempt to overwrite with stdin \"n\" — should list both and cancel\n    cmd.cast_fuse()\n        .current_dir(prj.root())\n        .args([\"wallet\", \"new\", \".\", \"test-account\", \"--unsafe-password\", \"test\", \"-n\", \"2\"])\n        .stdin(\"n\\n\")\n        .assert_failure()\n        .stderr_eq(str![[r#\"\nThe following keystore file(s) already exist:\n   - test-account_1\n   - test-account_2\nError: Operation cancelled. No keystores were modified.\n\n\"#]]);\n});\n\n// tests that we can create a new wallet with default keystore location\ncasttest!(new_wallet_default_keystore, |_prj, cmd| {\n    cmd.args([\"wallet\", \"new\", \"--unsafe-password\", \"test\"]).assert_success().stdout_eq(str![[\n        r#\"\nCreated new encrypted keystore file: [..]\n[ADDRESS]\n\n\"#\n    ]]);\n\n    // Verify the default keystore directory was created\n    let keystore_path = dirs::home_dir().unwrap().join(\".foundry\").join(\"keystores\");\n    assert!(keystore_path.exists());\n    assert!(keystore_path.is_dir());\n});\n\n// tests that we can outputting multiple keys without a keystore path\ncasttest!(new_wallet_multiple_keys, |_prj, cmd| {\n    cmd.args([\"wallet\", \"new\", \"-n\", \"2\"]).assert_success().stdout_eq(str![[r#\"\nSuccessfully created new keypair.\n[ADDRESS]\n[PRIVATE_KEY]\nSuccessfully created new keypair.\n[ADDRESS]\n[PRIVATE_KEY]\n\n\"#]]);\n});\n\n// tests that we can get the address of a keystore file\ncasttest!(wallet_address_keystore_with_password_file, |_prj, cmd| {\n    let keystore_dir = Path::new(env!(\"CARGO_MANIFEST_DIR\")).join(\"tests/fixtures/keystore\");\n\n    cmd.args([\n        \"wallet\",\n        \"address\",\n        \"--keystore\",\n        keystore_dir\n            .join(\"UTC--2022-12-20T10-30-43.591916000Z--ec554aeafe75601aaab43bd4621a22284db566c2\")\n            .to_str()\n            .unwrap(),\n        \"--password-file\",\n        keystore_dir.join(\"password-ec554\").to_str().unwrap(),\n    ])\n    .assert_success()\n    .stdout_eq(str![[r#\"\n0xeC554aeAFE75601AaAb43Bd4621A22284dB566C2\n\n\"#]]);\n});\n\n// tests that `cast wallet remove` can successfully remove a keystore file and validates password\ncasttest!(wallet_remove_keystore_with_unsafe_password, |prj, cmd| {\n    let keystore_path = prj.root().join(\"keystore\");\n\n    cmd.set_current_dir(prj.root());\n\n    let account_name = \"testAccount\";\n\n    // Default Anvil private key\n    let test_private_key =\n        b256!(\"0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80\");\n\n    // import private key\n    cmd.cast_fuse()\n        .args([\n            \"wallet\",\n            \"import\",\n            account_name,\n            \"--private-key\",\n            &test_private_key.to_string(),\n            \"-k\",\n            \"keystore\",\n            \"--unsafe-password\",\n            \"test\",\n        ])\n        .assert_success()\n        .stdout_eq(str![[r#\"\n`testAccount` keystore was saved successfully. [ADDRESS]\n\n\"#]]);\n\n    // check that the keystore file was created\n    let keystore_file = keystore_path.join(account_name);\n\n    assert!(keystore_file.exists());\n    // Remove the wallet\n    cmd.cast_fuse()\n        .args([\n            \"wallet\",\n            \"remove\",\n            \"--name\",\n            account_name,\n            \"--dir\",\n            keystore_path.to_str().unwrap(),\n            \"--unsafe-password\",\n            \"test\",\n        ])\n        .assert_success()\n        .stdout_eq(str![[r#\"\n`testAccount` keystore was removed successfully.\n\n\"#]]);\n\n    assert!(!keystore_file.exists());\n});\n\n// tests that `cast wallet sign message` outputs the expected signature\ncasttest!(wallet_sign_message_utf8_data, |_prj, cmd| {\n    let pk = \"0x0000000000000000000000000000000000000000000000000000000000000001\";\n    let address = \"0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf\";\n    let msg = \"test\";\n    let expected = \"0xfe28833983d6faa0715c7e8c3873c725ddab6fa5bf84d40e780676e463e6bea20fc6aea97dc273a98eb26b0914e224c8dd5c615ceaab69ddddcf9b0ae3de0e371c\";\n\n    cmd.args([\"wallet\", \"sign\", \"--private-key\", pk, msg]).assert_success().stdout_eq(str![[r#\"\n0xfe28833983d6faa0715c7e8c3873c725ddab6fa5bf84d40e780676e463e6bea20fc6aea97dc273a98eb26b0914e224c8dd5c615ceaab69ddddcf9b0ae3de0e371c\n\n\"#]]);\n\n    // Success.\n    cmd.cast_fuse()\n        .args([\"wallet\", \"verify\", \"-a\", address, msg, expected])\n        .assert_success()\n        .stdout_eq(str![[r#\"\nValidation succeeded. Address 0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf signed this message.\n\n\"#]]);\n\n    // Fail.\n    cmd.cast_fuse()\n        .args([\"wallet\", \"verify\", \"-a\", address, \"other msg\", expected])\n        .assert_failure()\n        .stderr_eq(str![[r#\"\nError: Validation failed. Address 0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf did not sign this message.\n\n\"#]]);\n});\n\n// tests that `cast wallet sign message` outputs the expected signature, given a 0x-prefixed data\ncasttest!(wallet_sign_message_hex_data, |_prj, cmd| {\n    cmd.args([\n        \"wallet\",\n        \"sign\",\n        \"--private-key\",\n        \"0x0000000000000000000000000000000000000000000000000000000000000001\",\n        \"0x0000000000000000000000000000000000000000000000000000000000000000\",\n    ]).assert_success().stdout_eq(str![[r#\"\n0x23a42ca5616ee730ff3735890c32fc7b9491a9f633faca9434797f2c845f5abf4d9ba23bd7edb8577acebaa3644dc5a4995296db420522bb40060f1693c33c9b1c\n\n\"#]]);\n});\n\n// <https://github.com/foundry-rs/foundry/issues/10613>\n// tests that `cast wallet sign` and `cast wallet verify` work with the same message as input\ncasttest!(wallet_sign_and_verify_message_hex_data, |_prj, cmd| {\n    //     message=\"$1\"\n    //     mnemonic=\"test test test test test test test test test test test junk\"\n    //     key=$(cast wallet private-key --mnemonic \"$mnemonic\")\n    //     address=$(cast wallet address --mnemonic \"$mnemonic\")\n    //     signature=$(cast wallet sign --private-key \"$key\" \"$message\")\n    //     cast wallet verify --address \"$address\" \"$message\" \"$signature\"\n    let mnemonic = \"test test test test test test test test test test test junk\";\n    let key = \"0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80\";\n    let address = \"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266\";\n    cmd.args([\"wallet\", \"private-key\", \"--mnemonic\", mnemonic]).assert_success().stdout_eq(str![[\n        r#\"\n0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80\n\n\"#\n    ]]);\n    cmd.cast_fuse().args([\"wallet\", \"address\", \"--mnemonic\", mnemonic]).assert_success().stdout_eq(\n        str![[r#\"\n0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266\n\n\"#]],\n    );\n\n    let msg_hex = \"0x0000000000000000000000000000000000000000000000000000000000000001\";\n    let signature_hex = \"0xed769da87f78d0166b30aebf2767ceed5a3867da21b2fba8c6527af256bbcebe24a1e758ec8ad1ffc29cfefa540ea7ba7966c0edf6907af82348f894ba4f40fa1b\";\n    cmd.cast_fuse().args([\n        \"wallet\", \"sign\", \"--private-key\",key, msg_hex\n    ]).assert_success().stdout_eq(str![[r#\"\n0xed769da87f78d0166b30aebf2767ceed5a3867da21b2fba8c6527af256bbcebe24a1e758ec8ad1ffc29cfefa540ea7ba7966c0edf6907af82348f894ba4f40fa1b\n\n\"#]]);\n\n    cmd.cast_fuse()\n        .args([\"wallet\", \"verify\", \"--address\", address, msg_hex, signature_hex])\n        .assert_success()\n        .stdout_eq(str![[r#\"\nValidation succeeded. Address 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 signed this message.\n\n\"#]]);\n\n    let msg_raw = \"0000000000000000000000000000000000000000000000000000000000000001\";\n    let signature_raw = \"0x27a97b378477d9d004bd19cbd838d59bbb9847074ae4cc5b5975cc5566065eea76ee5b752fcdd483073e1baba548d82d9accc8603b3781bcc9abf195614cd3411c\";\n    cmd.cast_fuse().args([\n        \"wallet\", \"sign\", \"--private-key\",key, msg_raw\n    ]).assert_success().stdout_eq(str![[r#\"\n0x27a97b378477d9d004bd19cbd838d59bbb9847074ae4cc5b5975cc5566065eea76ee5b752fcdd483073e1baba548d82d9accc8603b3781bcc9abf195614cd3411c\n\n\"#]]);\n\n    cmd.cast_fuse()\n        .args([\"wallet\", \"verify\", \"--address\", address, msg_raw, signature_raw])\n        .assert_success()\n        .stdout_eq(str![[r#\"\nValidation succeeded. Address 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 signed this message.\n\n\"#]]);\n});\n\n// tests that `cast wallet sign typed-data` outputs the expected signature, given a JSON string\ncasttest!(wallet_sign_typed_data_string, |_prj, cmd| {\n    cmd.args([\n        \"wallet\",\n        \"sign\",\n        \"--private-key\",\n        \"0x0000000000000000000000000000000000000000000000000000000000000001\",\n        \"--data\",\n        \"{\\\"types\\\": {\\\"EIP712Domain\\\": [{\\\"name\\\": \\\"name\\\",\\\"type\\\": \\\"string\\\"},{\\\"name\\\": \\\"version\\\",\\\"type\\\": \\\"string\\\"},{\\\"name\\\": \\\"chainId\\\",\\\"type\\\": \\\"uint256\\\"},{\\\"name\\\": \\\"verifyingContract\\\",\\\"type\\\": \\\"address\\\"}],\\\"Message\\\": [{\\\"name\\\": \\\"data\\\",\\\"type\\\": \\\"string\\\"}]},\\\"primaryType\\\": \\\"Message\\\",\\\"domain\\\": {\\\"name\\\": \\\"example.metamask.io\\\",\\\"version\\\": \\\"1\\\",\\\"chainId\\\": \\\"1\\\",\\\"verifyingContract\\\": \\\"0x0000000000000000000000000000000000000000\\\"},\\\"message\\\": {\\\"data\\\": \\\"Hello!\\\"}}\",\n    ]).assert_success().stdout_eq(str![[r#\"\n0x06c18bdc8163219fddc9afaf5a0550e381326474bb757c86dc32317040cf384e07a2c72ce66c1a0626b6750ca9b6c035bf6f03e7ed67ae2d1134171e9085c0b51b\n\n\"#]]);\n});\n\n// tests that `cast wallet sign typed-data` outputs the expected signature, given a JSON file\ncasttest!(wallet_sign_typed_data_file, |_prj, cmd| {\n    cmd.args([\n        \"wallet\",\n        \"sign\",\n        \"--private-key\",\n        \"0x0000000000000000000000000000000000000000000000000000000000000001\",\n        \"--data\",\n        \"--from-file\",\n        Path::new(env!(\"CARGO_MANIFEST_DIR\"))\n            .join(\"tests/fixtures/sign_typed_data.json\")\n            .into_os_string()\n            .into_string()\n            .unwrap()\n            .as_str(),\n    ]).assert_success().stdout_eq(str![[r#\"\n0x06c18bdc8163219fddc9afaf5a0550e381326474bb757c86dc32317040cf384e07a2c72ce66c1a0626b6750ca9b6c035bf6f03e7ed67ae2d1134171e9085c0b51b\n\n\"#]]);\n});\n\n// tests that `cast wallet sign typed-data` passes with type names containing colons\n//  <https://github.com/foundry-rs/foundry/issues/10765>\ncasttest!(wallet_sign_typed_data_with_colon_succeeds, |_prj, cmd| {\n    let typed_data_with_colon = r#\"{\n        \"types\": {\n            \"EIP712Domain\": [\n                {\"name\": \"name\", \"type\": \"string\"},\n                {\"name\": \"version\", \"type\": \"string\"},\n                {\"name\": \"chainId\", \"type\": \"uint256\"},\n                {\"name\": \"verifyingContract\", \"type\": \"address\"}\n            ],\n            \"Test:Message\": [\n                {\"name\": \"content\", \"type\": \"string\"}\n            ]\n        },\n        \"primaryType\": \"Test:Message\",\n        \"domain\": {\n            \"name\": \"TestDomain\",\n            \"version\": \"1\",\n            \"chainId\": 1,\n            \"verifyingContract\": \"0x0000000000000000000000000000000000000000\"\n        },\n        \"message\": {\n            \"content\": \"Hello\"\n        }\n    }\"#;\n\n    cmd.args([\n        \"wallet\",\n        \"sign\",\n        \"--private-key\",\n        \"0x0000000000000000000000000000000000000000000000000000000000000001\",\n        \"--data\",\n        typed_data_with_colon,\n    ]).assert_success().stdout_eq(str![[r#\"\n0xf91c67e845a4d468d1f876f457ffa01e65468641fc121453705242d21de39b266c278592b085814ab1e9adc938cc26b1d64bb61f80b437df077777c4283612291b\n\n\"#]]);\n});\n\n// tests that the same data without colon works correctly\n// <https://github.com/foundry-rs/foundry/issues/10765>\ncasttest!(wallet_sign_typed_data_without_colon_works, |_prj, cmd| {\n    let typed_data_without_colon = r#\"{\n        \"types\": {\n            \"EIP712Domain\": [\n                {\"name\": \"name\", \"type\": \"string\"},\n                {\"name\": \"version\", \"type\": \"string\"},\n                {\"name\": \"chainId\", \"type\": \"uint256\"},\n                {\"name\": \"verifyingContract\", \"type\": \"address\"}\n            ],\n            \"TestMessage\": [\n                {\"name\": \"content\", \"type\": \"string\"}\n            ]\n        },\n        \"primaryType\": \"TestMessage\",\n        \"domain\": {\n            \"name\": \"TestDomain\",\n            \"version\": \"1\",\n            \"chainId\": 1,\n            \"verifyingContract\": \"0x0000000000000000000000000000000000000000\"\n        },\n        \"message\": {\n            \"content\": \"Hello\"\n        }\n    }\"#;\n\n    cmd.args([\n        \"wallet\",\n        \"sign\",\n        \"--private-key\",\n        \"0x0000000000000000000000000000000000000000000000000000000000000001\",\n        \"--data\",\n        typed_data_without_colon,\n    ])\n    .assert_success();\n});\n\n// tests that `cast wallet sign-auth message` outputs the expected signature\ncasttest!(wallet_sign_auth, |_prj, cmd| {\n    cmd.args([\n        \"wallet\",\n        \"sign-auth\",\n        \"--private-key\",\n        \"0x0000000000000000000000000000000000000000000000000000000000000001\",\n        \"--nonce\",\n        \"100\",\n        \"--chain\",\n        \"1\",\n        \"0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf\"]).assert_success().stdout_eq(str![[r#\"\n0xf85a01947e5f4552091a69125d5dfcb7b8c2659029395bdf6401a0ad489ee0314497c3f06567f3080a46a63908edc1c7cdf2ac2d609ca911212086a065a6ba951c8748dd8634740fe498efb61770097d99ff5fdcb9a863b62ea899f6\n\n\"#]]);\n});\n\n// tests that `cast wallet sign-auth --self-broadcast` uses nonce + 1\ncasttest!(wallet_sign_auth_self_broadcast, async |_prj, cmd| {\n    use alloy_rlp::Decodable;\n    use alloy_signer_local::PrivateKeySigner;\n\n    let (_, handle) =\n        anvil::spawn(NodeConfig::test().with_hardfork(Some(EthereumHardfork::Prague.into()))).await;\n    let endpoint = handle.http_endpoint();\n\n    let private_key = \"0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80\";\n    let signer: PrivateKeySigner = private_key.parse().unwrap();\n    let signer_address = signer.address();\n    let delegate_address = address!(\"0x70997970C51812dc3A010C7d01b50e0d17dc79C8\");\n\n    // Get the current nonce from the RPC\n    let provider = ProviderBuilder::new().connect_http(endpoint.parse().unwrap());\n    let current_nonce = provider.get_transaction_count(signer_address).await.unwrap();\n\n    // First, get the auth without --self-broadcast (should use current nonce)\n    let output_normal = cmd\n        .args([\n            \"wallet\",\n            \"sign-auth\",\n            \"--private-key\",\n            private_key,\n            \"--rpc-url\",\n            &endpoint,\n            &delegate_address.to_string(),\n        ])\n        .assert_success()\n        .get_output()\n        .stdout_lossy()\n        .trim()\n        .to_string();\n\n    // Then, get the auth with --self-broadcast (should use current nonce + 1)\n    let output_self_broadcast = cmd\n        .cast_fuse()\n        .args([\n            \"wallet\",\n            \"sign-auth\",\n            \"--private-key\",\n            private_key,\n            \"--rpc-url\",\n            &endpoint,\n            \"--self-broadcast\",\n            &delegate_address.to_string(),\n        ])\n        .assert_success()\n        .get_output()\n        .stdout_lossy()\n        .trim()\n        .to_string();\n\n    // The outputs should be different due to different nonces\n    assert_ne!(\n        output_normal, output_self_broadcast,\n        \"self-broadcast should produce different signature due to nonce + 1\"\n    );\n\n    // Decode the RLP to verify the nonces\n    let normal_bytes = hex::decode(output_normal.strip_prefix(\"0x\").unwrap()).unwrap();\n    let self_broadcast_bytes =\n        hex::decode(output_self_broadcast.strip_prefix(\"0x\").unwrap()).unwrap();\n\n    let normal_auth =\n        alloy_eips::eip7702::SignedAuthorization::decode(&mut normal_bytes.as_slice()).unwrap();\n    let self_broadcast_auth =\n        alloy_eips::eip7702::SignedAuthorization::decode(&mut self_broadcast_bytes.as_slice())\n            .unwrap();\n\n    assert_eq!(normal_auth.nonce(), current_nonce, \"normal auth should have current nonce\");\n    assert_eq!(\n        self_broadcast_auth.nonce(),\n        current_nonce + 1,\n        \"self-broadcast auth should have current nonce + 1\"\n    );\n});\n\n// tests that `cast wallet list` outputs the local accounts\ncasttest!(wallet_list_local_accounts, |prj, cmd| {\n    let keystore_path = prj.root().join(\"keystore\");\n    fs::create_dir_all(keystore_path).unwrap();\n    cmd.set_current_dir(prj.root());\n\n    // empty results\n    cmd.cast_fuse()\n        .args([\"wallet\", \"list\", \"--dir\", \"keystore\"])\n        .assert_success()\n        .stdout_eq(str![\"\"]);\n\n    // create 10 wallets\n    cmd.cast_fuse()\n        .args([\"wallet\", \"new\", \"keystore\", \"-n\", \"10\", \"--unsafe-password\", \"test\"])\n        .assert_success()\n        .stdout_eq(str![[r#\"\nCreated new encrypted keystore file: [..]\n[ADDRESS]\nCreated new encrypted keystore file: [..]\n[ADDRESS]\nCreated new encrypted keystore file: [..]\n[ADDRESS]\nCreated new encrypted keystore file: [..]\n[ADDRESS]\nCreated new encrypted keystore file: [..]\n[ADDRESS]\nCreated new encrypted keystore file: [..]\n[ADDRESS]\nCreated new encrypted keystore file: [..]\n[ADDRESS]\nCreated new encrypted keystore file: [..]\n[ADDRESS]\nCreated new encrypted keystore file: [..]\n[ADDRESS]\nCreated new encrypted keystore file: [..]\n[ADDRESS]\n\n\"#]]);\n\n    // test list new wallet\n    cmd.cast_fuse().args([\"wallet\", \"list\", \"--dir\", \"keystore\"]).assert_success().stdout_eq(str![\n        [r#\"\n[..] (Local)\n[..] (Local)\n[..] (Local)\n[..] (Local)\n[..] (Local)\n[..] (Local)\n[..] (Local)\n[..] (Local)\n[..] (Local)\n[..] (Local)\n\n\"#]\n    ]);\n});\n\n// tests that `cast wallet new-mnemonic --entropy` outputs the expected mnemonic\ncasttest!(wallet_mnemonic_from_entropy, |_prj, cmd| {\n    cmd.args([\n        \"wallet\",\n        \"new-mnemonic\",\n        \"--accounts\",\n        \"3\",\n        \"--entropy\",\n        \"0xdf9bf37e6fcdf9bf37e6fcdf9bf37e3c\",\n    ])\n    .assert_success()\n    .stdout_eq(\n        str![[r#\"\nGenerating mnemonic from provided entropy...\nSuccessfully generated a new mnemonic.\nPhrase:\ntest test test test test test test test test test test junk\n\nAccounts:\n- Account 0:\nAddress:     0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266\nPrivate key: 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80\n\n- Account 1:\nAddress:     0x70997970C51812dc3A010C7d01b50e0d17dc79C8\nPrivate key: 0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d\n\n- Account 2:\nAddress:     0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC\nPrivate key: 0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a\n\n\n\"#]]\n        .raw(),\n    );\n});\n\n// tests that `cast wallet new-mnemonic --entropy` outputs the expected mnemonic (verbose variant)\ncasttest!(wallet_mnemonic_from_entropy_verbose, |_prj, cmd| {\n    cmd.args([\n        \"wallet\",\n        \"new-mnemonic\",\n        \"--accounts\",\n        \"3\",\n        \"--entropy\",\n        \"0xdf9bf37e6fcdf9bf37e6fcdf9bf37e3c\",\n        \"-v\",\n    ])\n    .assert_success()\n    .stdout_eq(\n        str![[r#\"\nGenerating mnemonic from provided entropy...\nSuccessfully generated a new mnemonic.\nPhrase:\ntest test test test test test test test test test test junk\n\nAccounts:\n- Account 0:\nAddress:     0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266\nPublic key:  0x8318535b54105d4a7aae60c08fc45f9687181b4fdfc625bd1a753fa7397fed753547f11ca8696646f2f3acb08e31016afac23e630c5d11f59f61fef57b0d2aa5\nPrivate key: 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80\n\n- Account 1:\nAddress:     0x70997970C51812dc3A010C7d01b50e0d17dc79C8\nPublic key:  0xba5734d8f7091719471e7f7ed6b9df170dc70cc661ca05e688601ad984f068b0d67351e5f06073092499336ab0839ef8a521afd334e53807205fa2f08eec74f4\nPrivate key: 0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d\n\n- Account 2:\nAddress:     0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC\nPublic key:  0x9d9031e97dd78ff8c15aa86939de9b1e791066a0224e331bc962a2099a7b1f0464b8bbafe1535f2301c72c2cb3535b172da30b02686ab0393d348614f157fbdb\nPrivate key: 0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a\n\n\n\"#]]\n        .raw(),\n    );\n});\n\n// tests that `cast wallet new-mnemonic --json` outputs the expected mnemonic\ncasttest!(wallet_mnemonic_from_entropy_json, |_prj, cmd| {\n    cmd.args([\n        \"wallet\",\n        \"new-mnemonic\",\n        \"--accounts\",\n        \"3\",\n        \"--entropy\",\n        \"0xdf9bf37e6fcdf9bf37e6fcdf9bf37e3c\",\n        \"--json\",\n    ])\n    .assert_success()\n    .stdout_eq(str![[r#\"\n{\n  \"mnemonic\": \"test test test test test test test test test test test junk\",\n  \"accounts\": [\n    {\n      \"address\": \"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266\",\n      \"private_key\": \"0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80\"\n    },\n    {\n      \"address\": \"0x70997970C51812dc3A010C7d01b50e0d17dc79C8\",\n      \"private_key\": \"0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d\"\n    },\n    {\n      \"address\": \"0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC\",\n      \"private_key\": \"0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a\"\n    }\n  ]\n}\n\n\"#]]);\n});\n\n// tests that `cast wallet new-mnemonic --json` outputs the expected mnemonic (verbose variant)\ncasttest!(wallet_mnemonic_from_entropy_json_verbose, |_prj, cmd| {\n    cmd.args([\n        \"wallet\",\n        \"new-mnemonic\",\n        \"--accounts\",\n        \"3\",\n        \"--entropy\",\n        \"0xdf9bf37e6fcdf9bf37e6fcdf9bf37e3c\",\n        \"--json\",\n        \"-v\",\n    ])\n    .assert_success()\n    .stdout_eq(str![[r#\"\n{\n  \"mnemonic\": \"test test test test test test test test test test test junk\",\n  \"accounts\": [\n    {\n      \"address\": \"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266\",\n      \"public_key\": \"0x8318535b54105d4a7aae60c08fc45f9687181b4fdfc625bd1a753fa7397fed753547f11ca8696646f2f3acb08e31016afac23e630c5d11f59f61fef57b0d2aa5\",\n      \"private_key\": \"0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80\"\n    },\n    {\n      \"address\": \"0x70997970C51812dc3A010C7d01b50e0d17dc79C8\",\n      \"public_key\": \"0xba5734d8f7091719471e7f7ed6b9df170dc70cc661ca05e688601ad984f068b0d67351e5f06073092499336ab0839ef8a521afd334e53807205fa2f08eec74f4\",\n      \"private_key\": \"0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d\"\n    },\n    {\n      \"address\": \"0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC\",\n      \"public_key\": \"0x9d9031e97dd78ff8c15aa86939de9b1e791066a0224e331bc962a2099a7b1f0464b8bbafe1535f2301c72c2cb3535b172da30b02686ab0393d348614f157fbdb\",\n      \"private_key\": \"0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a\"\n    }\n  ]\n}\n\n\"#]]);\n});\n\n// tests that `cast wallet derive` outputs the addresses of the accounts derived from the mnemonic\ncasttest!(wallet_derive_mnemonic, |_prj, cmd| {\n    cmd.args([\n        \"wallet\",\n        \"derive\",\n        \"--accounts\",\n        \"3\",\n        \"test test test test test test test test test test test junk\",\n    ])\n    .assert_success()\n    .stdout_eq(str![[r#\"\n- Account 0:\n[ADDRESS]\n\n- Account 1:\n[ADDRESS]\n\n- Account 2:\n[ADDRESS]\n\n\n\"#]]);\n});\n\n// tests that `cast wallet derive` with insecure flag outputs the addresses and private keys of the\n// accounts derived from the mnemonic\ncasttest!(wallet_derive_mnemonic_insecure, |_prj, cmd| {\n    cmd.args([\n        \"wallet\",\n        \"derive\",\n        \"--accounts\",\n        \"3\",\n        \"--insecure\",\n        \"test test test test test test test test test test test junk\",\n    ])\n    .assert_success()\n    .stdout_eq(str![[r#\"\n- Account 0:\n[ADDRESS]\n[PRIVATE_KEY]\n\n- Account 1:\n[ADDRESS]\n[PRIVATE_KEY]\n\n- Account 2:\n[ADDRESS]\n[PRIVATE_KEY]\n\n\n\"#]]);\n});\n\n// tests that `cast wallet derive` with json flag outputs the addresses of the accounts derived from\n// the mnemonic in JSON format\ncasttest!(wallet_derive_mnemonic_json, |_prj, cmd| {\n    cmd.args([\n        \"wallet\",\n        \"derive\",\n        \"--accounts\",\n        \"3\",\n        \"--json\",\n        \"test test test test test test test test test test test junk\",\n    ])\n    .assert_success()\n    .stdout_eq(str![[r#\"\n[\n  {\n    \"address\": \"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266\"\n  },\n  {\n    \"address\": \"0x70997970C51812dc3A010C7d01b50e0d17dc79C8\"\n  },\n  {\n    \"address\": \"0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC\"\n  }\n]\n\n\"#]]);\n});\n\n// tests that `cast wallet derive` with insecure and json flag outputs the addresses and private\n// keys of the accounts derived from the mnemonic in JSON format\ncasttest!(wallet_derive_mnemonic_insecure_json, |_prj, cmd| {\n    cmd.args([\n        \"wallet\",\n        \"derive\",\n        \"--accounts\",\n        \"3\",\n        \"--insecure\",\n        \"--json\",\n        \"test test test test test test test test test test test junk\",\n    ])\n    .assert_success()\n    .stdout_eq(str![[r#\"\n[\n  {\n    \"address\": \"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266\",\n    \"private_key\": \"0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80\"\n  },\n  {\n    \"address\": \"0x70997970C51812dc3A010C7d01b50e0d17dc79C8\",\n    \"private_key\": \"0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d\"\n  },\n  {\n    \"address\": \"0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC\",\n    \"private_key\": \"0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a\"\n  }\n]\n\n\"#]]);\n});\n\n// tests that `cast wallet private-key` with arguments outputs the private key\ncasttest!(wallet_private_key_from_mnemonic_arg, |_prj, cmd| {\n    cmd.args([\n        \"wallet\",\n        \"private-key\",\n        \"test test test test test test test test test test test junk\",\n        \"1\",\n    ])\n    .assert_success()\n    .stdout_eq(str![[r#\"\n0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d\n\n\"#]]);\n});\n\n// tests that `cast wallet private-key` with options outputs the private key\ncasttest!(wallet_private_key_from_mnemonic_option, |_prj, cmd| {\n    cmd.args([\n        \"wallet\",\n        \"private-key\",\n        \"--mnemonic\",\n        \"test test test test test test test test test test test junk\",\n        \"--mnemonic-index\",\n        \"1\",\n    ])\n    .assert_success()\n    .stdout_eq(str![[r#\"\n0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d\n\n\"#]]);\n});\n// tests that `cast wallet public-key` correctly derives and outputs the public key\ncasttest!(wallet_public_key_with_private_key, |_prj, cmd| {\n    cmd.args([\n        \"wallet\",\n        \"public-key\",\n        \"--raw-private-key\",\n        \"0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d\"\n    ])\n    .assert_success()\n    .stdout_eq(str![[r#\"\n0xba5734d8f7091719471e7f7ed6b9df170dc70cc661ca05e688601ad984f068b0d67351e5f06073092499336ab0839ef8a521afd334e53807205fa2f08eec74f4\n\n\"#]]);\n});\n// tests that `cast wallet private-key` with derivation path outputs the private key\ncasttest!(wallet_private_key_with_derivation_path, |_prj, cmd| {\n    cmd.args([\n        \"wallet\",\n        \"private-key\",\n        \"--mnemonic\",\n        \"test test test test test test test test test test test junk\",\n        \"--mnemonic-derivation-path\",\n        \"m/44'/60'/0'/0/1\",\n    ])\n    .assert_success()\n    .stdout_eq(str![[r#\"\n0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d\n\n\"#]]);\n});\n\n// tests that `cast wallet import` creates a keystore for a private key and that `cast wallet\n// decrypt-keystore` can access it\ncasttest!(wallet_import_and_decrypt, |prj, cmd| {\n    let keystore_path = prj.root().join(\"keystore\");\n\n    cmd.set_current_dir(prj.root());\n\n    let account_name = \"testAccount\";\n\n    // Default Anvil private key\n    let test_private_key =\n        b256!(\"0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80\");\n\n    // import private key\n    cmd.cast_fuse()\n        .args([\n            \"wallet\",\n            \"import\",\n            account_name,\n            \"--private-key\",\n            &test_private_key.to_string(),\n            \"-k\",\n            \"keystore\",\n            \"--unsafe-password\",\n            \"test\",\n        ])\n        .assert_success()\n        .stdout_eq(str![[r#\"\n`testAccount` keystore was saved successfully. [ADDRESS]\n\n\"#]]);\n\n    // check that the keystore file was created\n    let keystore_file = keystore_path.join(account_name);\n\n    assert!(keystore_file.exists());\n\n    // decrypt the keystore file\n    let decrypt_output = cmd.cast_fuse().args([\n        \"wallet\",\n        \"decrypt-keystore\",\n        account_name,\n        \"-k\",\n        \"keystore\",\n        \"--unsafe-password\",\n        \"test\",\n    ]);\n\n    // get the PK out of the output (last word in the output)\n    let decrypt_output = decrypt_output.assert_success().get_output().stdout_lossy();\n    let private_key_string = decrypt_output.split_whitespace().last().unwrap();\n    // check that the decrypted private key matches the imported private key\n    let decrypted_private_key = B256::from_str(private_key_string).unwrap();\n    // the form\n    assert_eq!(decrypted_private_key, test_private_key);\n});\n\n// tests that `cast wallet change-password` can successfully change the password of a keystore file\ncasttest!(wallet_change_password, |prj, cmd| {\n    let keystore_path = prj.root().join(\"keystore\");\n\n    cmd.set_current_dir(prj.root());\n\n    let account_name = \"testAccount\";\n\n    // Default Anvil private key\n    let test_private_key =\n        b256!(\"0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80\");\n\n    // import private key with initial password\n    cmd.cast_fuse()\n        .args([\n            \"wallet\",\n            \"import\",\n            account_name,\n            \"--private-key\",\n            &test_private_key.to_string(),\n            \"-k\",\n            \"keystore\",\n            \"--unsafe-password\",\n            \"old_password\",\n        ])\n        .assert_success()\n        .stdout_eq(str![[r#\"\n`testAccount` keystore was saved successfully. [ADDRESS]\n\n\"#]]);\n\n    // check that the keystore file was created\n    let keystore_file = keystore_path.join(account_name);\n    assert!(keystore_file.exists());\n\n    // change the password\n    cmd.cast_fuse()\n        .args([\n            \"wallet\",\n            \"change-password\",\n            account_name,\n            \"--keystore-dir\",\n            \"keystore\",\n            \"--unsafe-password\",\n            \"old_password\",\n            \"--unsafe-new-password\",\n            \"new_password\",\n        ])\n        .assert_success()\n        .stdout_eq(str![[r#\"\nPassword for keystore `testAccount` was changed successfully. [ADDRESS]\n\n\"#]]);\n\n    // verify the old password no longer works\n    cmd.cast_fuse()\n        .args([\n            \"wallet\",\n            \"decrypt-keystore\",\n            account_name,\n            \"-k\",\n            \"keystore\",\n            \"--unsafe-password\",\n            \"old_password\",\n        ])\n        .assert_failure();\n\n    // verify the new password works\n    let decrypt_output = cmd.cast_fuse().args([\n        \"wallet\",\n        \"decrypt-keystore\",\n        account_name,\n        \"-k\",\n        \"keystore\",\n        \"--unsafe-password\",\n        \"new_password\",\n    ]);\n\n    // get the PK out of the output (last word in the output)\n    let decrypt_output = decrypt_output.assert_success().get_output().stdout_lossy();\n    let private_key_string = decrypt_output.split_whitespace().last().unwrap();\n\n    // check that the decrypted private key matches the imported private key\n    let decrypted_private_key = B256::from_str(private_key_string).unwrap();\n    assert_eq!(decrypted_private_key, test_private_key);\n});\n\n// tests that `cast estimate` is working correctly.\ncasttest!(estimate_function_gas, |_prj, cmd| {\n    let eth_rpc_url = next_http_rpc_endpoint();\n\n    // ensure we get a positive non-error value for gas estimate\n    let output: u32 = cmd\n        .args([\n            \"estimate\",\n            \"0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045\", // vitalik.eth\n            \"--value\",\n            \"100\",\n            \"deposit()\",\n            \"--rpc-url\",\n            eth_rpc_url.as_str(),\n        ])\n        .assert_success()\n        .get_output()\n        .stdout_lossy()\n        .trim()\n        .parse()\n        .unwrap();\n    assert!(output.ge(&0));\n});\n\n// tests that `cast estimate --cost` is working correctly.\ncasttest!(estimate_function_cost, |_prj, cmd| {\n    let eth_rpc_url = next_http_rpc_endpoint();\n\n    // ensure we get a positive non-error value for cost estimate\n    let output: f64 = cmd\n        .args([\n            \"estimate\",\n            \"0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045\", // vitalik.eth\n            \"--value\",\n            \"100\",\n            \"deposit()\",\n            \"--rpc-url\",\n            eth_rpc_url.as_str(),\n            \"--cost\",\n        ])\n        .assert_success()\n        .get_output()\n        .stdout_lossy()\n        .trim()\n        .parse()\n        .unwrap();\n    assert!(output > 0f64);\n});\n\n// tests that `cast estimate --create` is working correctly.\ncasttest!(estimate_contract_deploy_gas, |_prj, cmd| {\n    let eth_rpc_url = next_http_rpc_endpoint();\n    // sample contract code bytecode. Wouldn't run but is valid bytecode that the estimate method\n    // accepts and could be deployed.\n    let output = cmd\n        .args([\n            \"estimate\",\n            \"--rpc-url\",\n            eth_rpc_url.as_str(),\n            \"--create\",\n            \"0000\",\n            \"ERC20(uint256,string,string)\",\n            \"100\",\n            \"Test\",\n            \"TST\",\n        ])\n        .assert_success()\n        .get_output()\n        .stdout_lossy();\n\n    // ensure we get a positive non-error value for gas estimate\n    let output: u32 = output.trim().parse().unwrap();\n    assert!(output > 0);\n});\n\n// tests that the `cast to-rlp` and `cast from-rlp` commands work correctly\ncasttest!(rlp, |_prj, cmd| {\n    cmd.args([\"--to-rlp\", \"[\\\"0xaa\\\", [[\\\"bb\\\"]], \\\"0xcc\\\"]\"]).assert_success().stdout_eq(str![[\n        r#\"\n0xc881aac3c281bb81cc\n\n\"#\n    ]]);\n\n    cmd.cast_fuse();\n    cmd.args([\"--from-rlp\", \"0xcbc58455556666c0c0c2c1c0\"]).assert_success().stdout_eq(str![[r#\"\n[[\"0x55556666\"],[],[],[[[]]]]\n\n\"#]]);\n});\n\n// test that `cast impl` works correctly for both the implementation slot and the beacon slot\ncasttest!(impl_slot, |_prj, cmd| {\n    let eth_rpc_url = next_http_archive_rpc_url();\n\n    // Call `cast impl` for the implementation slot (AAVE Proxy)\n    cmd.args([\n        \"impl\",\n        \"0x4965f6FA20fE9728deCf5165016fc338a5a85aBF\",\n        \"--rpc-url\",\n        eth_rpc_url.as_str(),\n        \"--block\",\n        \"21422087\",\n    ])\n    .assert_success()\n    .stdout_eq(str![[r#\"\n0xb61306c8eb34a2104d9eb8d84f1bb1001067fa4b\n\n\"#]]);\n});\n\ncasttest!(impl_slot_beacon, |_prj, cmd| {\n    let eth_rpc_url = next_http_archive_rpc_url();\n\n    // Call `cast impl` for the beacon slot\n    cmd.args([\n        \"impl\",\n        \"0xc63d9f0040d35f328274312fc8771a986fc4ba86\",\n        \"--beacon\",\n        \"--rpc-url\",\n        eth_rpc_url.as_str(),\n        \"--block\",\n        \"21422087\",\n    ])\n    .assert_success()\n    .stdout_eq(str![[r#\"\n0xa748ae65ba11606492a9c57effa0d4b7be551ec2\n\n\"#]]);\n});\n\n// test for cast_rpc without arguments\ncasttest!(rpc_no_args, |_prj, cmd| {\n    let eth_rpc_url = next_http_rpc_endpoint();\n\n    // Call `cast rpc eth_chainId`\n    cmd.args([\"rpc\", \"--rpc-url\", eth_rpc_url.as_str(), \"eth_chainId\"]).assert_success().stdout_eq(\n        str![[r#\"\n\"0x1\"\n\n\"#]],\n    );\n});\n\n// test for cast_rpc without arguments using websocket\ncasttest!(ws_rpc_no_args, |_prj, cmd| {\n    let eth_rpc_url = next_ws_rpc_endpoint();\n\n    // Call `cast rpc eth_chainId`\n    cmd.args([\"rpc\", \"--rpc-url\", eth_rpc_url.as_str(), \"eth_chainId\"]).assert_success().stdout_eq(\n        str![[r#\"\n\"0x1\"\n\n\"#]],\n    );\n});\n\n// test for cast_rpc with arguments\ncasttest!(rpc_with_args, |_prj, cmd| {\n    let eth_rpc_url = next_http_rpc_endpoint();\n\n    // Call `cast rpc eth_getBlockByNumber 0x123 false`\n    cmd.args([\"rpc\", \"--rpc-url\", eth_rpc_url.as_str(), \"eth_getBlockByNumber\", \"0x123\", \"false\"])\n    .assert_json_stdout(str![[r#\"\n{\"number\":\"0x123\",\"hash\":\"0xc5dab4e189004a1312e9db43a40abb2de91ad7dd25e75880bf36016d8e9df524\",\"transactions\":[],\"logsBloom\":\"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\"receiptsRoot\":\"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\",\"extraData\":\"0x476574682f4c5649562f76312e302e302f6c696e75782f676f312e342e32\",\"nonce\":\"0x29d6547c196e00e0\",\"miner\":\"0xbb7b8287f3f0a933474a79eae42cbca977791171\",\"difficulty\":\"0x494433b31\",\"gasLimit\":\"0x1388\",\"gasUsed\":\"0x0\",\"uncles\":[],\"sha3Uncles\":\"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347\",\"size\":\"0x220\",\"transactionsRoot\":\"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\",\"stateRoot\":\"0x3fe6bd17aa85376c7d566df97d9f2e536f37f7a87abb3a6f9e2891cf9442f2e4\",\"mixHash\":\"0x943056aa305aa6d22a3c06110942980342d1f4d4b11c17711961436a0f963ea0\",\"parentHash\":\"0x7abfd11e862ccde76d6ea8ee20978aac26f4bcb55de1188cc0335be13e817017\",\"timestamp\":\"0x55ba4564\"}\n\n\"#]]);\n});\n\n// test for cast_rpc with arguments\ncasttest!(rpc_format_as_json, |_prj, cmd| {\n    let eth_rpc_url = next_http_rpc_endpoint();\n\n    // Call `cast rpc eth_getBlockByNumber 0x123 false`\n    cmd.args([\"rpc\", \"--rpc-url\", eth_rpc_url.as_str(), \"eth_getBlockByNumber\", \"0x123\", \"false\", \"--json\"])\n    .assert_json_stdout(str![[r#\"\n{\n  \"hash\": \"0xc5dab4e189004a1312e9db43a40abb2de91ad7dd25e75880bf36016d8e9df524\",\n  \"parentHash\": \"0x7abfd11e862ccde76d6ea8ee20978aac26f4bcb55de1188cc0335be13e817017\",\n  \"sha3Uncles\": \"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347\",\n  \"miner\": \"0xbb7b8287f3f0a933474a79eae42cbca977791171\",\n  \"stateRoot\": \"0x3fe6bd17aa85376c7d566df97d9f2e536f37f7a87abb3a6f9e2891cf9442f2e4\",\n  \"transactionsRoot\": \"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\",\n  \"receiptsRoot\": \"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\",\n  \"logsBloom\": \"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\n  \"difficulty\": \"0x494433b31\",\n  \"number\": \"0x123\",\n  \"gasLimit\": \"0x1388\",\n  \"gasUsed\": \"0x0\",\n  \"timestamp\": \"0x55ba4564\",\n  \"extraData\": \"0x476574682f4c5649562f76312e302e302f6c696e75782f676f312e342e32\",\n  \"mixHash\": \"0x943056aa305aa6d22a3c06110942980342d1f4d4b11c17711961436a0f963ea0\",\n  \"nonce\": \"0x29d6547c196e00e0\",\n  \"size\": \"0x220\",\n  \"uncles\": [],\n  \"transactions\": []\n}\n\n\"#]]);\n});\n\n// test for cast_rpc with raw params\ncasttest!(rpc_raw_params, |_prj, cmd| {\n    let eth_rpc_url = next_http_rpc_endpoint();\n\n    // Call `cast rpc eth_getBlockByNumber --raw '[\"0x123\", false]'`\n    cmd.args([\n        \"rpc\",\n        \"--rpc-url\",\n        eth_rpc_url.as_str(),\n        \"eth_getBlockByNumber\",\n        \"--raw\",\n        r#\"[\"0x123\", false]\"#,\n    ])\n    .assert_json_stdout(str![[r#\"\n{\"number\":\"0x123\",\"hash\":\"0xc5dab4e189004a1312e9db43a40abb2de91ad7dd25e75880bf36016d8e9df524\",\"transactions\":[],\"logsBloom\":\"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\"receiptsRoot\":\"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\",\"extraData\":\"0x476574682f4c5649562f76312e302e302f6c696e75782f676f312e342e32\",\"nonce\":\"0x29d6547c196e00e0\",\"miner\":\"0xbb7b8287f3f0a933474a79eae42cbca977791171\",\"difficulty\":\"0x494433b31\",\"gasLimit\":\"0x1388\",\"gasUsed\":\"0x0\",\"uncles\":[],\"sha3Uncles\":\"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347\",\"size\":\"0x220\",\"transactionsRoot\":\"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\",\"stateRoot\":\"0x3fe6bd17aa85376c7d566df97d9f2e536f37f7a87abb3a6f9e2891cf9442f2e4\",\"mixHash\":\"0x943056aa305aa6d22a3c06110942980342d1f4d4b11c17711961436a0f963ea0\",\"parentHash\":\"0x7abfd11e862ccde76d6ea8ee20978aac26f4bcb55de1188cc0335be13e817017\",\"timestamp\":\"0x55ba4564\"}\n\n\"#]]);\n});\n\n// test for cast_rpc with direct params\ncasttest!(rpc_raw_params_stdin, |_prj, cmd| {\n    let eth_rpc_url = next_http_rpc_endpoint();\n\n    // Call `echo \"\\n[\\n\\\"0x123\\\",\\nfalse\\n]\\n\" | cast rpc eth_getBlockByNumber --raw\n    cmd.args([\"rpc\", \"--rpc-url\", eth_rpc_url.as_str(), \"eth_getBlockByNumber\", \"--raw\"]).stdin(\n        b\"\\n[\\n\\\"0x123\\\",\\nfalse\\n]\\n\"\n    )\n    .assert_json_stdout(str![[r#\"\n{\"number\":\"0x123\",\"hash\":\"0xc5dab4e189004a1312e9db43a40abb2de91ad7dd25e75880bf36016d8e9df524\",\"transactions\":[],\"logsBloom\":\"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\"receiptsRoot\":\"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\",\"extraData\":\"0x476574682f4c5649562f76312e302e302f6c696e75782f676f312e342e32\",\"nonce\":\"0x29d6547c196e00e0\",\"miner\":\"0xbb7b8287f3f0a933474a79eae42cbca977791171\",\"difficulty\":\"0x494433b31\",\"gasLimit\":\"0x1388\",\"gasUsed\":\"0x0\",\"uncles\":[],\"sha3Uncles\":\"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347\",\"size\":\"0x220\",\"transactionsRoot\":\"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\",\"stateRoot\":\"0x3fe6bd17aa85376c7d566df97d9f2e536f37f7a87abb3a6f9e2891cf9442f2e4\",\"mixHash\":\"0x943056aa305aa6d22a3c06110942980342d1f4d4b11c17711961436a0f963ea0\",\"parentHash\":\"0x7abfd11e862ccde76d6ea8ee20978aac26f4bcb55de1188cc0335be13e817017\",\"timestamp\":\"0x55ba4564\"}\n\n\"#]]);\n});\n\n// checks `cast calldata` can handle arrays\ncasttest!(calldata_array, |_prj, cmd| {\n    cmd.args([\"calldata\", \"propose(string[])\", \"[\\\"\\\"]\"]).assert_success().stdout_eq(str![[r#\"\n0xcde2baba0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000\n\n\"#]]);\n});\n\n// <https://github.com/foundry-rs/foundry/issues/2705>\ncasttest!(run_succeeds, |_prj, cmd| {\n    let rpc = next_http_archive_rpc_url();\n    cmd.args([\n        \"run\",\n        \"-v\",\n        \"0x2d951c5c95d374263ca99ad9c20c9797fc714330a8037429a3aa4c83d456f845\",\n        \"--quick\",\n        \"--rpc-url\",\n        rpc.as_str(),\n    ])\n    .assert_success()\n    .stdout_eq(str![[r#\"\n...\nTransaction successfully executed.\n[GAS]\n\n\"#]]);\n});\n\n// tests that `cast --to-base` commands are working correctly.\ncasttest!(to_base, |_prj, cmd| {\n    let values = [\n        \"1\",\n        \"100\",\n        \"100000\",\n        \"115792089237316195423570985008687907853269984665640564039457584007913129639935\",\n        \"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\",\n        \"-1\",\n        \"-100\",\n        \"-100000\",\n        \"-57896044618658097711785492504343953926634992332820282019728792003956564819968\",\n    ];\n    for value in values {\n        for subcmd in [\"--to-base\", \"--to-hex\", \"--to-dec\"] {\n            if subcmd == \"--to-base\" {\n                for base in [\"bin\", \"oct\", \"dec\", \"hex\"] {\n                    cmd.cast_fuse().args([subcmd, value, base]);\n                    assert!(!cmd.assert_success().get_output().stdout_lossy().trim().is_empty());\n                }\n            } else {\n                cmd.cast_fuse().args([subcmd, value]);\n                assert!(!cmd.assert_success().get_output().stdout_lossy().trim().is_empty());\n            }\n        }\n    }\n});\n\n// tests that revert reason is only present if transaction has reverted.\n\ncasttest!(receipt_revert_reason, |_prj, cmd| {\n    let rpc = next_http_archive_rpc_url();\n\n    // <https://etherscan.io/tx/0x44f2aaa351460c074f2cb1e5a9e28cbc7d83f33e425101d2de14331c7b7ec31e>\n    cmd.args([\n        \"receipt\",\n        \"0x44f2aaa351460c074f2cb1e5a9e28cbc7d83f33e425101d2de14331c7b7ec31e\",\n        \"--rpc-url\",\n        rpc.as_str(),\n    ])\n    .assert_success()\n    .stdout_eq(format!(r#\"\nblockHash            0x2cfe65be49863676b6dbc04d58176a14f39b123f1e2f4fea0383a2d82c2c50d0\nblockNumber          16239315\ncontractAddress      {}\ncumulativeGasUsed    10743428\neffectiveGasPrice    10539984136\nfrom                 0x199D5ED7F45F4eE35960cF22EAde2076e95B253F\ngasUsed              21000\nlogs                 []\nlogsBloom            0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\nroot                 {}\nstatus               1 (success)\ntransactionHash      0x44f2aaa351460c074f2cb1e5a9e28cbc7d83f33e425101d2de14331c7b7ec31e\ntransactionIndex     116\ntype                 0\nblobGasPrice         {}\nblobGasUsed          {}\nto                   0x91da5bf3F8Eb72724E6f50Ec6C3D199C6355c59c\n\"#,\"\", \"\", \"\", \"\"));\n\n    let rpc = next_http_archive_rpc_url();\n\n    // <https://etherscan.io/tx/0x0e07d8b53ed3d91314c80e53cf25bcde02084939395845cbb625b029d568135c>\n    cmd.cast_fuse()\n        .args([\n            \"receipt\",\n            \"0x0e07d8b53ed3d91314c80e53cf25bcde02084939395845cbb625b029d568135c\",\n            \"--rpc-url\",\n            rpc.as_str(),\n        ])\n        .assert_success()\n        .stdout_eq(format!(r#\"\nblockHash            0x883f974b17ca7b28cb970798d1c80f4d4bb427473dc6d39b2a7fe24edc02902d\nblockNumber          14839405\ncontractAddress      {}\ncumulativeGasUsed    20273649\neffectiveGasPrice    21491736378\nfrom                 0x3cF412d970474804623bb4e3a42dE13F9bCa5436\ngasUsed              24952\nlogs                 []\nlogsBloom            0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\nroot                 {}\nstatus               0 (failed)\ntransactionHash      0x0e07d8b53ed3d91314c80e53cf25bcde02084939395845cbb625b029d568135c\ntransactionIndex     173\ntype                 2\nblobGasPrice         {}\nblobGasUsed          {}\nto                   0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45\nrevertReason         [..]Transaction too old, data: \"0x08c379a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000135472616e73616374696f6e20746f6f206f6c6400000000000000000000000000\"\n\"#,\"\",\"\",\"\",\"\"));\n});\n// tests that the revert reason is loaded using the correct `from` address.\n// Flaky: Sepolia RPC may not return the revertReason field depending on provider\n// support for debug/trace APIs.\ncasttest!(flaky_revert_reason_from, |_prj, cmd| {\n    let rpc = next_rpc_endpoint(NamedChain::Sepolia);\n    // https://sepolia.etherscan.io/tx/0x10ee70cf9f5ced5c515e8d53bfab5ea9f5c72cd61b25fba455c8355ee286c4e4\n    cmd.args([\n        \"receipt\",\n        \"0x10ee70cf9f5ced5c515e8d53bfab5ea9f5c72cd61b25fba455c8355ee286c4e4\",\n        \"--rpc-url\",\n        rpc.as_str(),\n    ])\n    .assert_success()\n    .stdout_eq(format!(r#\"\nblockHash            0x32663d7730c9ea8e1de6d99854483e25fcc05bb56c91c0cc82f9f04944fbffc1\nblockNumber          7823353\ncontractAddress      {}\ncumulativeGasUsed    7500797\neffectiveGasPrice    14296851013\nfrom                 0x3583fF95f96b356d716881C871aF7Eb55ea34a93\ngasUsed              25815\nlogs                 []\nlogsBloom            0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\nroot                 {}\nstatus               0 (failed)\ntransactionHash      0x10ee70cf9f5ced5c515e8d53bfab5ea9f5c72cd61b25fba455c8355ee286c4e4\ntransactionIndex     96\ntype                 0\nblobGasPrice         {}\nblobGasUsed          {}\nto                   0x91b5d4111a4C038153b24e31F75ccdC47123595d\n...\n\"#, \"\", \"\", \"\", \"\"));\n});\n\n// tests that `cast --parse-bytes32-address` command is working correctly.\ncasttest!(parse_bytes32_address, |_prj, cmd| {\n    cmd.args([\n        \"--parse-bytes32-address\",\n        \"0x000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa96045\",\n    ])\n    .assert_success()\n    .stdout_eq(str![[r#\"\n0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045\n\n\"#]]);\n});\n\ncasttest!(access_list, |_prj, cmd| {\n    let rpc = next_http_rpc_endpoint();\n    cmd.args([\n        \"access-list\",\n        \"0xbb2b8038a1640196fbe3e38816f3e67cba72d940\",\n        \"skim(address)\",\n        \"0xbb2b8038a1640196fbe3e38816f3e67cba72d940\",\n        \"--rpc-url\",\n        rpc.as_str(),\n        \"--gas-limit\", // need to set this for alchemy.io to avoid \"intrinsic gas too low\" error\n        \"100000\",\n    ])\n    .assert_success()\n    .stdout_eq(str![[r#\"\n[GAS]\naccess list:\n- address: [..]\n  keys:\n...\n- address: [..]\n  keys:\n...\n- address: [..]\n  keys:\n...\n\n\"#]]);\n});\n\ncasttest!(logs_topics, |_prj, cmd| {\n    let rpc = next_http_archive_rpc_url();\n    cmd.args([\n        \"logs\",\n        \"--rpc-url\",\n        rpc.as_str(),\n        \"--from-block\",\n        \"12421181\",\n        \"--to-block\",\n        \"12421182\",\n        \"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef\",\n        \"0x000000000000000000000000ab5801a7d398351b8be11c439e05c5b3259aec9b\",\n    ])\n    .assert_success()\n    .stdout_eq(file![\"../fixtures/cast_logs.stdout\"]);\n});\n\ncasttest!(logs_topic_2, |_prj, cmd| {\n    let rpc = next_http_archive_rpc_url();\n    cmd.args([\n        \"logs\",\n        \"--rpc-url\",\n        rpc.as_str(),\n        \"--from-block\",\n        \"12421181\",\n        \"--to-block\",\n        \"12421182\",\n        \"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef\",\n        \"\",\n        \"0x00000000000000000000000068a99f89e475a078645f4bac491360afe255dff1\", /* Filter on the\n                                                                               * `to` address */\n    ])\n    .assert_success()\n    .stdout_eq(file![\"../fixtures/cast_logs.stdout\"]);\n});\n\ncasttest!(logs_sig, |_prj, cmd| {\n    let rpc = next_http_archive_rpc_url();\n    cmd.args([\n        \"logs\",\n        \"--rpc-url\",\n        rpc.as_str(),\n        \"--from-block\",\n        \"12421181\",\n        \"--to-block\",\n        \"12421182\",\n        \"Transfer(address indexed from, address indexed to, uint256 value)\",\n        \"0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B\",\n    ])\n    .assert_success()\n    .stdout_eq(file![\"../fixtures/cast_logs.stdout\"]);\n});\n\ncasttest!(logs_sig_2, |_prj, cmd| {\n    let rpc = next_http_archive_rpc_url();\n    cmd.args([\n        \"logs\",\n        \"--rpc-url\",\n        rpc.as_str(),\n        \"--from-block\",\n        \"12421181\",\n        \"--to-block\",\n        \"12421182\",\n        \"Transfer(address indexed from, address indexed to, uint256 value)\",\n        \"\",\n        \"0x68A99f89E475a078645f4BAC491360aFe255Dff1\",\n    ])\n    .assert_success()\n    .stdout_eq(file![\"../fixtures/cast_logs.stdout\"]);\n});\n\ncasttest!(logs_chunked_large_range, |_prj, cmd| {\n    let rpc = next_http_archive_rpc_url();\n    cmd.args([\n        \"logs\",\n        \"--rpc-url\",\n        rpc.as_str(),\n        \"--from-block\",\n        \"18000000\",\n        \"--to-block\",\n        \"18050000\",\n        \"--query-size\",\n        \"1000\",\n        \"Transfer(address indexed from, address indexed to, uint256 value)\",\n        \"0xA0b86a33E6441d02dd8C6B2b7E5D1E3eD7F73b4b\",\n    ])\n    .assert_success();\n});\n\ncasttest!(mktx, |_prj, cmd| {\n    cmd.args([\n        \"mktx\",\n        \"--private-key\",\n        \"0x0000000000000000000000000000000000000000000000000000000000000001\",\n        \"--chain\",\n        \"1\",\n        \"--nonce\",\n        \"0\",\n        \"--value\",\n        \"100\",\n        \"--gas-limit\",\n        \"21000\",\n        \"--gas-price\",\n        \"10000000000\",\n        \"--priority-gas-price\",\n        \"1000000000\",\n        \"0x0000000000000000000000000000000000000001\",\n    ]).assert_success().stdout_eq(str![[r#\"\n0x02f86b0180843b9aca008502540be4008252089400000000000000000000000000000000000000016480c001a070d55e79ed3ac9fc8f51e78eb91fd054720d943d66633f2eb1bc960f0126b0eca052eda05a792680de3181e49bab4093541f75b49d1ecbe443077b3660c836016a\n\n\"#]]);\n});\n\n// ensure recipient or code is required\ncasttest!(mktx_requires_to, |_prj, cmd| {\n    cmd.args([\n        \"mktx\",\n        \"--private-key\",\n        \"0x0000000000000000000000000000000000000000000000000000000000000001\",\n        \"--chain\",\n        \"1\",\n    ]);\n    cmd.assert_failure().stderr_eq(str![[r#\"\nError: Must specify a recipient address or contract code to deploy\n\n\"#]]);\n});\n\ncasttest!(mktx_signer_from_mismatch, |_prj, cmd| {\n    cmd.args([\n        \"mktx\",\n        \"--private-key\",\n        \"0x0000000000000000000000000000000000000000000000000000000000000001\",\n        \"--from\",\n        \"0x0000000000000000000000000000000000000001\",\n        \"--chain\",\n        \"1\",\n        \"0x0000000000000000000000000000000000000001\",\n    ]);\n    cmd.assert_failure().stderr_eq(str![[r#\"\nError: The specified sender via CLI/env vars does not match the sender configured via\nthe hardware wallet's HD Path.\nPlease use the `--hd-path <PATH>` parameter to specify the BIP32 Path which\ncorresponds to the sender, or let foundry automatically detect it by not specifying any sender address.\n\n\"#]]);\n});\n\ncasttest!(mktx_signer_from_match, |_prj, cmd| {\n    cmd.args([\n        \"mktx\",\n        \"--private-key\",\n        \"0x0000000000000000000000000000000000000000000000000000000000000001\",\n        \"--from\",\n        \"0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf\",\n        \"--chain\",\n        \"1\",\n        \"--nonce\",\n        \"0\",\n        \"--gas-limit\",\n        \"21000\",\n        \"--gas-price\",\n        \"10000000000\",\n        \"--priority-gas-price\",\n        \"1000000000\",\n        \"0x0000000000000000000000000000000000000001\",\n    ]).assert_success().stdout_eq(str![[r#\"\n0x02f86b0180843b9aca008502540be4008252089400000000000000000000000000000000000000018080c001a0cce9a61187b5d18a89ecd27ec675e3b3f10d37f165627ef89a15a7fe76395ce8a07537f5bffb358ffbef22cda84b1c92f7211723f9e09ae037e81686805d3e5505\n\n\"#]]);\n});\n\ncasttest!(mktx_raw_unsigned, |_prj, cmd| {\n    cmd.args([\n        \"mktx\",\n        \"--from\",\n        \"0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf\",\n        \"--chain\",\n        \"1\",\n        \"--nonce\",\n        \"0\",\n        \"--gas-limit\",\n        \"21000\",\n        \"--gas-price\",\n        \"10000000000\",\n        \"--priority-gas-price\",\n        \"1000000000\",\n        \"0x0000000000000000000000000000000000000001\",\n        \"--raw-unsigned\",\n    ])\n    .assert_success()\n    .stdout_eq(str![[\n        r#\"0x02e80180843b9aca008502540be4008252089400000000000000000000000000000000000000018080c0\n\n\"#\n    ]]);\n});\n\ncasttest!(mktx_raw_unsigned_no_from_missing_chain, async |_prj, cmd| {\n    // As chain is not provided, a query is made to the provider to get the chain id, before the\n    // tx is built. Anvil is configured to use chain id 1 so that the produced tx will\n    // be the same as in the `mktx_raw_unsigned` test.\n    let (_, handle) = anvil::spawn(NodeConfig::test().with_chain_id(Some(1u64))).await;\n    cmd.args([\n        \"mktx\",\n        \"--nonce\",\n        \"0\",\n        \"--gas-limit\",\n        \"21000\",\n        \"--gas-price\",\n        \"10000000000\",\n        \"--priority-gas-price\",\n        \"1000000000\",\n        \"0x0000000000000000000000000000000000000001\",\n        \"--raw-unsigned\",\n        \"--rpc-url\",\n        &handle.http_endpoint(),\n    ])\n    .assert_success()\n    .stdout_eq(str![[\n        r#\"0x02e80180843b9aca008502540be4008252089400000000000000000000000000000000000000018080c0\n\n\"#\n    ]]);\n});\n\ncasttest!(mktx_raw_unsigned_no_from_missing_gas_pricing, async |_prj, cmd| {\n    let (_, handle) = anvil::spawn(NodeConfig::test()).await;\n    cmd.args([\n        \"mktx\",\n        \"--nonce\",\n        \"0\",\n        \"0x0000000000000000000000000000000000000001\",\n        \"--raw-unsigned\",\n        \"--rpc-url\",\n        &handle.http_endpoint(),\n    ])\n    .assert_success()\n    .stdout_eq(str![[\n        r#\"0x02e5827a69800184773594018252089400000000000000000000000000000000000000018080c0\n\n\"#\n    ]]);\n});\n\ncasttest!(mktx_raw_unsigned_no_from_missing_nonce, |_prj, cmd| {\n    cmd.args([\n        \"mktx\",\n        \"--chain\",\n        \"1\",\n        \"--gas-limit\",\n        \"21000\",\n        \"--gas-price\",\n        \"20000000000\",\n        \"0x742d35Cc6634C0532925a3b8D6Ac6F67C9c2b7FD\",\n        \"--raw-unsigned\",\n    ])\n    .assert_failure()\n    .stderr_eq(str![[\n        r#\"Error: Missing required parameters for raw unsigned transaction. When --from is not provided, you must specify: --nonce\n\n\"#\n    ]]);\n});\n\ncasttest!(mktx_ethsign, async |_prj, cmd| {\n    let (_api, handle) = anvil::spawn(NodeConfig::test()).await;\n    let rpc = handle.http_endpoint();\n    cmd.args([\n        \"mktx\",\n        \"--from\",\n        \"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266\",\n        \"--chain\",\n        \"31337\",\n        \"--nonce\",\n        \"0\",\n        \"--gas-limit\",\n        \"21000\",\n        \"--gas-price\",\n        \"10000000000\",\n        \"--priority-gas-price\",\n        \"1000000000\",\n        \"0x0000000000000000000000000000000000000001\",\n        \"--ethsign\",\n        \"--rpc-url\",\n        rpc.as_str(),\n    ])\n    .assert_success()\n    .stdout_eq(str![[\n        r#\"\n0x02f86d827a6980843b9aca008502540be4008252089400000000000000000000000000000000000000018080c001a0b8eeb1ded87b085859c510c5692bed231e3ee8b068ccf71142bbf28da0e95987a07813b676a248ae8055f28495021d78dee6695479d339a6ad9d260d9eaf20674c\n\n\"#\n    ]]);\n});\n\n// tests that the raw encoded transaction is returned\ncasttest!(tx_raw, |_prj, cmd| {\n    let rpc = next_http_rpc_endpoint();\n\n    // <https://etherscan.io/getRawTx?tx=0x44f2aaa351460c074f2cb1e5a9e28cbc7d83f33e425101d2de14331c7b7ec31e>\n    cmd.args([\n        \"tx\",\n        \"0x44f2aaa351460c074f2cb1e5a9e28cbc7d83f33e425101d2de14331c7b7ec31e\",\n        \"raw\",\n        \"--rpc-url\",\n        rpc.as_str(),\n    ]).assert_success().stdout_eq(str![[r#\"\n0xf86d824c548502743b65088275309491da5bf3f8eb72724e6f50ec6c3d199c6355c59c87a0a73f33e9e4cc8025a0428518b1748a08bbeb2392ea055b418538944d30adfc2accbbfa8362a401d3a4a07d6093ab2580efd17c11b277de7664fce56e6953cae8e925bec3313399860470\n\n\"#]]);\n\n    // <https://etherscan.io/getRawTx?tx=0x44f2aaa351460c074f2cb1e5a9e28cbc7d83f33e425101d2de14331c7b7ec31e>\n    cmd.cast_fuse().args([\n        \"tx\",\n        \"0x44f2aaa351460c074f2cb1e5a9e28cbc7d83f33e425101d2de14331c7b7ec31e\",\n        \"--raw\",\n        \"--rpc-url\",\n        rpc.as_str(),\n    ]).assert_success().stdout_eq(str![[r#\"\n0xf86d824c548502743b65088275309491da5bf3f8eb72724e6f50ec6c3d199c6355c59c87a0a73f33e9e4cc8025a0428518b1748a08bbeb2392ea055b418538944d30adfc2accbbfa8362a401d3a4a07d6093ab2580efd17c11b277de7664fce56e6953cae8e925bec3313399860470\n\n\"#]]);\n});\n\ncasttest!(tx_to_request_json, |_prj, cmd| {\n    let rpc = next_http_rpc_endpoint();\n\n    // <https://etherscan.io/getRawTx?tx=0x44f2aaa351460c074f2cb1e5a9e28cbc7d83f33e425101d2de14331c7b7ec31e>\n    cmd.args([\n        \"tx\",\n        \"0x44f2aaa351460c074f2cb1e5a9e28cbc7d83f33e425101d2de14331c7b7ec31e\",\n        \"--to-request\",\n        \"--rpc-url\",\n        rpc.as_str(),\n    ])\n    .assert_success()\n    .stdout_eq(str![[r#\"\n{\n  \"from\": \"0x199d5ed7f45f4ee35960cf22eade2076e95b253f\",\n  \"to\": \"0x91da5bf3f8eb72724e6f50ec6c3d199c6355c59c\",\n  \"gasPrice\": \"0x2743b6508\",\n  \"gas\": \"0x7530\",\n  \"value\": \"0xa0a73f33e9e4cc\",\n  \"input\": \"0x\",\n  \"nonce\": \"0x4c54\",\n  \"chainId\": \"0x1\",\n  \"type\": \"0x0\"\n}\n\n\"#]]);\n});\n\ncasttest!(tx_using_sender_and_nonce, |_prj, cmd| {\n    let rpc = next_http_archive_rpc_url();\n    // <https://etherscan.io/tx/0x5bcd22734cca2385dc25b2d38a3d33a640c5961bd46d390dff184c894204b594>\n    let args = vec![\n        \"tx\",\n        \"--from\",\n        \"0x4648451b5F87FF8F0F7D622bD40574bb97E25980\",\n        \"--nonce\",\n        \"113642\",\n        \"--rpc-url\",\n        rpc.as_str(),\n    ];\n    cmd.args(args).assert_success().stdout_eq(str![[r#\"\n\nblockHash            0x29518c1cea251b1bda5949a9b039722604ec1fb99bf9d8124cfe001c95a50bdc\nblockNumber          22287055\nfrom                 0x4648451b5F87FF8F0F7D622bD40574bb97E25980\ntransactionIndex     230\neffectiveGasPrice    363392048\nhash                 0x5bcd22734cca2385dc25b2d38a3d33a640c5961bd46d390dff184c894204b594\ntype                 2\nchainId              1\nnonce                113642\ngasLimit             350000\nmaxFeePerGas         675979146\nmaxPriorityFeePerGas 1337\nto                   0xdAC17F958D2ee523a2206206994597C13D831ec7\nvalue                0\naccessList           []\ninput                0xa9059cbb000000000000000000000000568766d218d82333dd4dae933ddfcda5da26625000000000000000000000000000000000000000000000000000000000cc3ed109\nr                    0x1e92d3e1ca69109a1743fc4b3cf9dff58630bc9f429cea3c3fe311506264e36c\ns                    0x793947d4bbdce56a1a5b2b3525c46f01569414a22355f4883b5429668ab0f51a\nyParity              1\n...\n\"#]]);\n});\n\n// ensure receipt or code is required\ncasttest!(send_requires_to, |_prj, cmd| {\n    cmd.args([\n        \"send\",\n        \"--private-key\",\n        \"0x0000000000000000000000000000000000000000000000000000000000000001\",\n        \"--chain\",\n        \"1\",\n    ]);\n    cmd.assert_failure().stderr_eq(str![[r#\"\nError: Must specify a recipient address or contract code to deploy\n\n\"#]]);\n});\n\n// <https://github.com/foundry-rs/foundry/issues/9918>\ncasttest!(send_7702_conflicts_with_create, |_prj, cmd| {\n    cmd.args([\n        \"send\", \"--private-key\", \"0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80\" ,\"--auth\", \"0xf85c827a6994f39fd6e51aad88f6f4ce6ab8827279cfffb922668001a03e1a66234e71242afcc7bc46c8950c3b2997b102db257774865f1232d2e7bf48a045e252dad189b27b2306792047745eba86bff0dd18aca813dbf3fba8c4e94576\", \"--create\",  \"0x60806040523373ffffffffffffffffffffffffffffffffffffffff163273ffffffffffffffffffffffffffffffffffffffff1614610072576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610069906100e5565b60405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff16ff5b5f82825260208201905092915050565b7f74782e6f726967696e203d3d206d73672e73656e6465720000000000000000005f82015250565b5f6100cf60178361008b565b91506100da8261009b565b602082019050919050565b5f6020820190508181035f8301526100fc816100c3565b905091905056fe\"\n    ]);\n    cmd.assert_failure().stderr_eq(str![[r#\"\nError: EIP-7702 transactions can't be CREATE transactions and require a destination address\n\n\"#]]);\n});\n\ncasttest!(storage, |_prj, cmd| {\n    let rpc = next_http_archive_rpc_url();\n    cmd.args([\"storage\", \"vitalik.eth\", \"1\", \"--rpc-url\", &rpc]).assert_success().stdout_eq(str![\n        [r#\"\n0x0000000000000000000000000000000000000000000000000000000000000000\n\n\"#]\n    ]);\n\n    let rpc = next_http_archive_rpc_url();\n    cmd.cast_fuse()\n        .args([\"storage\", \"vitalik.eth\", \"0x01\", \"--rpc-url\", &rpc])\n        .assert_success()\n        .stdout_eq(str![[r#\"\n0x0000000000000000000000000000000000000000000000000000000000000000\n\n\"#]]);\n\n    let rpc = next_http_archive_rpc_url();\n    let usdt = \"0xdac17f958d2ee523a2206206994597c13d831ec7\";\n    let decimals_slot = \"0x09\";\n    cmd.cast_fuse()\n        .args([\"storage\", usdt, decimals_slot, \"--rpc-url\", &rpc])\n        .assert_success()\n        .stdout_eq(str![[r#\"\n0x0000000000000000000000000000000000000000000000000000000000000006\n\n\"#]]);\n\n    let rpc = next_http_archive_rpc_url();\n    let total_supply_slot = \"0x01\";\n    let block_before = \"4634747\";\n    let block_after = \"4634748\";\n    cmd.cast_fuse()\n        .args([\"storage\", usdt, total_supply_slot, \"--rpc-url\", &rpc, \"--block\", block_before])\n        .assert_success()\n        .stdout_eq(str![[r#\"\n0x0000000000000000000000000000000000000000000000000000000000000000\n\n\"#]]);\n\n    let rpc = next_http_archive_rpc_url();\n    cmd.cast_fuse()\n        .args([\"storage\", usdt, total_supply_slot, \"--rpc-url\", &rpc, \"--block\", block_after])\n        .assert_success()\n        .stdout_eq(str![[r#\"\n0x000000000000000000000000000000000000000000000000000000174876e800\n\n\"#]]);\n\n    let decimal_slot_offset_from_total_supply_slot = \"0x08\";\n    let decimal_slot_offset_from_total_supply_slot_uint = \"8\";\n    let rpc = next_http_archive_rpc_url();\n    cmd.cast_fuse()\n        .args([\n            \"storage\",\n            usdt,\n            total_supply_slot,\n            decimal_slot_offset_from_total_supply_slot,\n            \"--rpc-url\",\n            &rpc,\n        ])\n        .assert_success()\n        .stdout_eq(str![[r#\"\n0x0000000000000000000000000000000000000000000000000000000000000006\n\n\"#]]);\n\n    let rpc = next_http_archive_rpc_url();\n    cmd.cast_fuse()\n        .args([\n            \"storage\",\n            usdt,\n            total_supply_slot,\n            decimal_slot_offset_from_total_supply_slot_uint,\n            \"--rpc-url\",\n            &rpc,\n        ])\n        .assert_success()\n        .stdout_eq(str![[r#\"\n0x0000000000000000000000000000000000000000000000000000000000000006\n\n\"#]]);\n});\n\ncasttest!(flaky_storage_with_valid_solc_version_1, |_prj, cmd| {\n    cmd.args([\n        \"storage\",\n        \"0x13b0D85CcB8bf860b6b79AF3029fCA081AE9beF2\",\n        \"--solc-version\",\n        \"0.8.10\",\n        \"--rpc-url\",\n        next_http_archive_rpc_url().as_str(),\n        \"--etherscan-api-key\",\n        next_etherscan_api_key().as_str(),\n    ])\n    .assert_success();\n});\n\ncasttest!(flaky_storage_with_valid_solc_version_2, |_prj, cmd| {\n    cmd.args([\n        \"storage\",\n        \"0x13b0D85CcB8bf860b6b79AF3029fCA081AE9beF2\",\n        \"--solc-version\",\n        \"0.8.23\",\n        \"--rpc-url\",\n        next_http_archive_rpc_url().as_str(),\n        \"--etherscan-api-key\",\n        next_etherscan_api_key().as_str(),\n    ])\n    .assert_success();\n});\n\ncasttest!(flaky_storage_with_invalid_solc_version_1, |_prj, cmd| {\n    let output = cmd\n        .args([\n            \"storage\",\n            \"0x13b0D85CcB8bf860b6b79AF3029fCA081AE9beF2\",\n            \"--solc-version\",\n            \"0.4.0\",\n            \"--rpc-url\",\n            next_http_archive_rpc_url().as_str(),\n            \"--etherscan-api-key\",\n            next_etherscan_api_key().as_str(),\n        ])\n        .assert_failure()\n        .get_output()\n        .stderr\n        .clone();\n    let stderr = String::from_utf8_lossy(&output);\n    assert!(\n        stderr.contains(\n            \"Warning: The provided --solc-version is 0.4.0 while the minimum version for storage layouts is 0.6.5\"\n        ),\n        \"stderr did not contain expected warning. Full stderr:\\n{stderr}\"\n    );\n});\n\ncasttest!(flaky_storage_with_invalid_solc_version_2, |_prj, cmd| {\n    cmd.args([\n        \"storage\",\n        \"0x13b0D85CcB8bf860b6b79AF3029fCA081AE9beF2\",\n        \"--solc-version\",\n        \"0.8.2\",\n        \"--rpc-url\",\n        next_http_archive_rpc_url().as_str(),\n        \"--etherscan-api-key\",\n        next_etherscan_api_key().as_str(),\n    ])\n    .assert_failure()\n    .stderr_eq(str![[r#\"\nError: Encountered invalid solc version in contracts/Create2Deployer.sol: No solc version exists that matches the version requirement: ^0.8.9\n\n\"#]]);\n});\n\n// <https://github.com/foundry-rs/foundry/issues/6319>\ncasttest!(flaky_storage_layout_simple, |_prj, cmd| {\n    cmd.args([\n        \"storage\",\n        \"--rpc-url\",\n        next_http_archive_rpc_url().as_str(),\n        \"--block\",\n        \"21034138\",\n        \"--etherscan-api-key\",\n        next_etherscan_api_key().as_str(),\n        \"0x13b0D85CcB8bf860b6b79AF3029fCA081AE9beF2\",\n    ])\n    .assert_success()\n    .stdout_eq(str![[r#\"\n\n╭---------+---------+------+--------+-------+-------+--------------------------------------------------------------------+-----------------------------------------------╮\n| Name    | Type    | Slot | Offset | Bytes | Value | Hex Value                                                          | Contract                                      |\n+========================================================================================================================================================================+\n| _owner  | address | 0    | 0      | 20    | 0     | 0x0000000000000000000000000000000000000000000000000000000000000000 | contracts/Create2Deployer.sol:Create2Deployer |\n|---------+---------+------+--------+-------+-------+--------------------------------------------------------------------+-----------------------------------------------|\n| _paused | bool    | 0    | 20     | 1     | 0     | 0x0000000000000000000000000000000000000000000000000000000000000000 | contracts/Create2Deployer.sol:Create2Deployer |\n╰---------+---------+------+--------+-------+-------+--------------------------------------------------------------------+-----------------------------------------------╯\n\n\n\"#]]);\n});\n\n// <https://github.com/foundry-rs/foundry/pull/9332>\ncasttest!(flaky_storage_layout_simple_json, |_prj, cmd| {\n    cmd.args([\n        \"storage\",\n        \"--rpc-url\",\n        next_http_archive_rpc_url().as_str(),\n        \"--block\",\n        \"21034138\",\n        \"--etherscan-api-key\",\n        next_etherscan_api_key().as_str(),\n        \"0x13b0D85CcB8bf860b6b79AF3029fCA081AE9beF2\",\n        \"--json\",\n    ])\n    .assert_success()\n    .stdout_eq(file![\"../fixtures/storage_layout_simple.json\": Json]);\n});\n\n// <https://github.com/foundry-rs/foundry/issues/6319>\ncasttest!(flaky_storage_layout_complex, |_prj, cmd| {\n    cmd.args([\n        \"storage\",\n        \"--rpc-url\",\n        next_http_archive_rpc_url().as_str(),\n        \"--block\",\n        \"21034138\",\n        \"--etherscan-api-key\",\n        next_etherscan_api_key().as_str(),\n        \"0xBA12222222228d8Ba445958a75a0704d566BF2C8\",\n    ])\n    .assert_success()\n    .stdout_eq(str![[r#\"\n\n╭-------------------------------+--------------------------------------------------------------------+------+--------+-------+--------------------------------------------------+--------------------------------------------------------------------+---------------------------------╮\n| Name                          | Type                                                               | Slot | Offset | Bytes | Value                                            | Hex Value                                                          | Contract                        |\n+======================================================================================================================================================================================================================================================================================+\n| _status                       | uint256                                                            | 0    | 0      | 32    | 1                                                | 0x0000000000000000000000000000000000000000000000000000000000000001 | contracts/vault/Vault.sol:Vault |\n|-------------------------------+--------------------------------------------------------------------+------+--------+-------+--------------------------------------------------+--------------------------------------------------------------------+---------------------------------|\n| _generalPoolsBalances         | mapping(bytes32 => struct EnumerableMap.IERC20ToBytes32Map)        | 1    | 0      | 32    | 0                                                | 0x0000000000000000000000000000000000000000000000000000000000000000 | contracts/vault/Vault.sol:Vault |\n|-------------------------------+--------------------------------------------------------------------+------+--------+-------+--------------------------------------------------+--------------------------------------------------------------------+---------------------------------|\n| _nextNonce                    | mapping(address => uint256)                                        | 2    | 0      | 32    | 0                                                | 0x0000000000000000000000000000000000000000000000000000000000000000 | contracts/vault/Vault.sol:Vault |\n|-------------------------------+--------------------------------------------------------------------+------+--------+-------+--------------------------------------------------+--------------------------------------------------------------------+---------------------------------|\n| _paused                       | bool                                                               | 3    | 0      | 1     | 0                                                | 0x0000000000000000000000000000000000000000000000000000000000000000 | contracts/vault/Vault.sol:Vault |\n|-------------------------------+--------------------------------------------------------------------+------+--------+-------+--------------------------------------------------+--------------------------------------------------------------------+---------------------------------|\n| _authorizer                   | contract IAuthorizer                                               | 3    | 1      | 20    | 549683469959765988649777481110995959958745616871 | 0x0000000000000000000000006048a8c631fb7e77eca533cf9c29784e482391e7 | contracts/vault/Vault.sol:Vault |\n|-------------------------------+--------------------------------------------------------------------+------+--------+-------+--------------------------------------------------+--------------------------------------------------------------------+---------------------------------|\n| _approvedRelayers             | mapping(address => mapping(address => bool))                       | 4    | 0      | 32    | 0                                                | 0x0000000000000000000000000000000000000000000000000000000000000000 | contracts/vault/Vault.sol:Vault |\n|-------------------------------+--------------------------------------------------------------------+------+--------+-------+--------------------------------------------------+--------------------------------------------------------------------+---------------------------------|\n| _isPoolRegistered             | mapping(bytes32 => bool)                                           | 5    | 0      | 32    | 0                                                | 0x0000000000000000000000000000000000000000000000000000000000000000 | contracts/vault/Vault.sol:Vault |\n|-------------------------------+--------------------------------------------------------------------+------+--------+-------+--------------------------------------------------+--------------------------------------------------------------------+---------------------------------|\n| _nextPoolNonce                | uint256                                                            | 6    | 0      | 32    | 1760                                             | 0x00000000000000000000000000000000000000000000000000000000000006e0 | contracts/vault/Vault.sol:Vault |\n|-------------------------------+--------------------------------------------------------------------+------+--------+-------+--------------------------------------------------+--------------------------------------------------------------------+---------------------------------|\n| _minimalSwapInfoPoolsBalances | mapping(bytes32 => mapping(contract IERC20 => bytes32))            | 7    | 0      | 32    | 0                                                | 0x0000000000000000000000000000000000000000000000000000000000000000 | contracts/vault/Vault.sol:Vault |\n|-------------------------------+--------------------------------------------------------------------+------+--------+-------+--------------------------------------------------+--------------------------------------------------------------------+---------------------------------|\n| _minimalSwapInfoPoolsTokens   | mapping(bytes32 => struct EnumerableSet.AddressSet)                | 8    | 0      | 32    | 0                                                | 0x0000000000000000000000000000000000000000000000000000000000000000 | contracts/vault/Vault.sol:Vault |\n|-------------------------------+--------------------------------------------------------------------+------+--------+-------+--------------------------------------------------+--------------------------------------------------------------------+---------------------------------|\n| _twoTokenPoolTokens           | mapping(bytes32 => struct TwoTokenPoolsBalance.TwoTokenPoolTokens) | 9    | 0      | 32    | 0                                                | 0x0000000000000000000000000000000000000000000000000000000000000000 | contracts/vault/Vault.sol:Vault |\n|-------------------------------+--------------------------------------------------------------------+------+--------+-------+--------------------------------------------------+--------------------------------------------------------------------+---------------------------------|\n| _poolAssetManagers            | mapping(bytes32 => mapping(contract IERC20 => address))            | 10   | 0      | 32    | 0                                                | 0x0000000000000000000000000000000000000000000000000000000000000000 | contracts/vault/Vault.sol:Vault |\n|-------------------------------+--------------------------------------------------------------------+------+--------+-------+--------------------------------------------------+--------------------------------------------------------------------+---------------------------------|\n| _internalTokenBalance         | mapping(address => mapping(contract IERC20 => uint256))            | 11   | 0      | 32    | 0                                                | 0x0000000000000000000000000000000000000000000000000000000000000000 | contracts/vault/Vault.sol:Vault |\n╰-------------------------------+--------------------------------------------------------------------+------+--------+-------+--------------------------------------------------+--------------------------------------------------------------------+---------------------------------╯\n\n\n\"#]]);\n});\n\ncasttest!(flaky_storage_layout_complex_md, |_prj, cmd| {\n    cmd.args([\n        \"storage\",\n        \"--rpc-url\",\n        next_http_archive_rpc_url().as_str(),\n        \"--block\",\n        \"21034138\",\n        \"--etherscan-api-key\",\n        next_etherscan_api_key().as_str(),\n        \"0xBA12222222228d8Ba445958a75a0704d566BF2C8\",\n        \"--md\",\n    ])\n    .assert_success()\n    .stdout_eq(str![[r#\"\n\n| Name                          | Type                                                               | Slot | Offset | Bytes | Value                                            | Hex Value                                                          | Contract                        |\n|-------------------------------|--------------------------------------------------------------------|------|--------|-------|--------------------------------------------------|--------------------------------------------------------------------|---------------------------------|\n| _status                       | uint256                                                            | 0    | 0      | 32    | 1                                                | 0x0000000000000000000000000000000000000000000000000000000000000001 | contracts/vault/Vault.sol:Vault |\n| _generalPoolsBalances         | mapping(bytes32 => struct EnumerableMap.IERC20ToBytes32Map)        | 1    | 0      | 32    | 0                                                | 0x0000000000000000000000000000000000000000000000000000000000000000 | contracts/vault/Vault.sol:Vault |\n| _nextNonce                    | mapping(address => uint256)                                        | 2    | 0      | 32    | 0                                                | 0x0000000000000000000000000000000000000000000000000000000000000000 | contracts/vault/Vault.sol:Vault |\n| _paused                       | bool                                                               | 3    | 0      | 1     | 0                                                | 0x0000000000000000000000000000000000000000000000000000000000000000 | contracts/vault/Vault.sol:Vault |\n| _authorizer                   | contract IAuthorizer                                               | 3    | 1      | 20    | 549683469959765988649777481110995959958745616871 | 0x0000000000000000000000006048a8c631fb7e77eca533cf9c29784e482391e7 | contracts/vault/Vault.sol:Vault |\n| _approvedRelayers             | mapping(address => mapping(address => bool))                       | 4    | 0      | 32    | 0                                                | 0x0000000000000000000000000000000000000000000000000000000000000000 | contracts/vault/Vault.sol:Vault |\n| _isPoolRegistered             | mapping(bytes32 => bool)                                           | 5    | 0      | 32    | 0                                                | 0x0000000000000000000000000000000000000000000000000000000000000000 | contracts/vault/Vault.sol:Vault |\n| _nextPoolNonce                | uint256                                                            | 6    | 0      | 32    | 1760                                             | 0x00000000000000000000000000000000000000000000000000000000000006e0 | contracts/vault/Vault.sol:Vault |\n| _minimalSwapInfoPoolsBalances | mapping(bytes32 => mapping(contract IERC20 => bytes32))            | 7    | 0      | 32    | 0                                                | 0x0000000000000000000000000000000000000000000000000000000000000000 | contracts/vault/Vault.sol:Vault |\n| _minimalSwapInfoPoolsTokens   | mapping(bytes32 => struct EnumerableSet.AddressSet)                | 8    | 0      | 32    | 0                                                | 0x0000000000000000000000000000000000000000000000000000000000000000 | contracts/vault/Vault.sol:Vault |\n| _twoTokenPoolTokens           | mapping(bytes32 => struct TwoTokenPoolsBalance.TwoTokenPoolTokens) | 9    | 0      | 32    | 0                                                | 0x0000000000000000000000000000000000000000000000000000000000000000 | contracts/vault/Vault.sol:Vault |\n| _poolAssetManagers            | mapping(bytes32 => mapping(contract IERC20 => address))            | 10   | 0      | 32    | 0                                                | 0x0000000000000000000000000000000000000000000000000000000000000000 | contracts/vault/Vault.sol:Vault |\n| _internalTokenBalance         | mapping(address => mapping(contract IERC20 => uint256))            | 11   | 0      | 32    | 0                                                | 0x0000000000000000000000000000000000000000000000000000000000000000 | contracts/vault/Vault.sol:Vault |\n\n\n\"#]]);\n});\n\ncasttest!(flaky_storage_layout_complex_proxy, |_prj, cmd| {\n    cmd.args([\n        \"storage\",\n        \"--rpc-url\",\n        next_rpc_endpoint(NamedChain::Sepolia).as_str(),\n        \"--block\",\n        \"7857852\",\n        \"--etherscan-api-key\",\n        next_etherscan_api_key().as_str(),\n        \"0xE2588A9CAb7Ea877206E35f615a39f84a64A7A3b\",\n        \"--proxy\",\n        \"0x29fcb43b46531bca003ddc8fcb67ffe91900c762\"\n    ])\n    .assert_success()\n    .stdout_eq(str![[r#\"\n\n╭----------------------------+-------------------------------------------------+------+--------+-------+--------------------------------------------------+--------------------------------------------------------------------+-----------------------------╮\n| Name                       | Type                                            | Slot | Offset | Bytes | Value                                            | Hex Value                                                          | Contract                    |\n+============================================================================================================================================================================================================================================================+\n| singleton                  | address                                         | 0    | 0      | 20    | 239704109775411986678417050956533140837380441954 | 0x00000000000000000000000029fcb43b46531bca003ddc8fcb67ffe91900c762 | contracts/SafeL2.sol:SafeL2 |\n|----------------------------+-------------------------------------------------+------+--------+-------+--------------------------------------------------+--------------------------------------------------------------------+-----------------------------|\n| modules                    | mapping(address => address)                     | 1    | 0      | 32    | 0                                                | 0x0000000000000000000000000000000000000000000000000000000000000000 | contracts/SafeL2.sol:SafeL2 |\n|----------------------------+-------------------------------------------------+------+--------+-------+--------------------------------------------------+--------------------------------------------------------------------+-----------------------------|\n| owners                     | mapping(address => address)                     | 2    | 0      | 32    | 0                                                | 0x0000000000000000000000000000000000000000000000000000000000000000 | contracts/SafeL2.sol:SafeL2 |\n|----------------------------+-------------------------------------------------+------+--------+-------+--------------------------------------------------+--------------------------------------------------------------------+-----------------------------|\n| ownerCount                 | uint256                                         | 3    | 0      | 32    | 1                                                | 0x0000000000000000000000000000000000000000000000000000000000000001 | contracts/SafeL2.sol:SafeL2 |\n|----------------------------+-------------------------------------------------+------+--------+-------+--------------------------------------------------+--------------------------------------------------------------------+-----------------------------|\n| threshold                  | uint256                                         | 4    | 0      | 32    | 1                                                | 0x0000000000000000000000000000000000000000000000000000000000000001 | contracts/SafeL2.sol:SafeL2 |\n|----------------------------+-------------------------------------------------+------+--------+-------+--------------------------------------------------+--------------------------------------------------------------------+-----------------------------|\n| nonce                      | uint256                                         | 5    | 0      | 32    | 0                                                | 0x0000000000000000000000000000000000000000000000000000000000000000 | contracts/SafeL2.sol:SafeL2 |\n|----------------------------+-------------------------------------------------+------+--------+-------+--------------------------------------------------+--------------------------------------------------------------------+-----------------------------|\n| _deprecatedDomainSeparator | bytes32                                         | 6    | 0      | 32    | 0                                                | 0x0000000000000000000000000000000000000000000000000000000000000000 | contracts/SafeL2.sol:SafeL2 |\n|----------------------------+-------------------------------------------------+------+--------+-------+--------------------------------------------------+--------------------------------------------------------------------+-----------------------------|\n| signedMessages             | mapping(bytes32 => uint256)                     | 7    | 0      | 32    | 0                                                | 0x0000000000000000000000000000000000000000000000000000000000000000 | contracts/SafeL2.sol:SafeL2 |\n|----------------------------+-------------------------------------------------+------+--------+-------+--------------------------------------------------+--------------------------------------------------------------------+-----------------------------|\n| approvedHashes             | mapping(address => mapping(bytes32 => uint256)) | 8    | 0      | 32    | 0                                                | 0x0000000000000000000000000000000000000000000000000000000000000000 | contracts/SafeL2.sol:SafeL2 |\n╰----------------------------+-------------------------------------------------+------+--------+-------+--------------------------------------------------+--------------------------------------------------------------------+-----------------------------╯\n\n\n\"#]]);\n});\n\ncasttest!(flaky_storage_layout_complex_json, |_prj, cmd| {\n    cmd.args([\n        \"storage\",\n        \"--rpc-url\",\n        next_http_archive_rpc_url().as_str(),\n        \"--block\",\n        \"21034138\",\n        \"--etherscan-api-key\",\n        next_etherscan_api_key().as_str(),\n        \"0xBA12222222228d8Ba445958a75a0704d566BF2C8\",\n        \"--json\",\n    ])\n    .assert_success()\n    .stdout_eq(file![\"../fixtures/storage_layout_complex.json\": Json]);\n});\n\ncasttest!(balance, |_prj, cmd| {\n    let rpc = next_http_rpc_endpoint();\n    let dai = \"0x6B175474E89094C44Da98b954EedeAC495271d0F\";\n\n    let dai_result = cmd\n        .args([\n            \"balance\",\n            \"0x0000000000000000000000000000000000000000\",\n            \"--erc20\",\n            dai,\n            \"--rpc-url\",\n            &rpc,\n        ])\n        .assert_success()\n        .get_output()\n        .stdout_lossy()\n        .trim()\n        .to_string();\n\n    let alias_result = cmd\n        .cast_fuse()\n        .args([\n            \"balance\",\n            \"0x0000000000000000000000000000000000000000\",\n            \"--erc721\",\n            dai,\n            \"--rpc-url\",\n            &rpc,\n        ])\n        .assert_success()\n        .get_output()\n        .stdout_lossy()\n        .trim()\n        .to_string();\n\n    assert_ne!(dai_result, \"0\");\n    assert_eq!(alias_result, dai_result);\n});\n\n// tests that `cast interface` excludes the constructor\n// <https://github.com/alloy-rs/core/issues/555>\ncasttest!(interface_no_constructor, |prj, cmd| {\n    let interface = include_str!(\"../fixtures/interface.json\");\n\n    let path = prj.root().join(\"interface.json\");\n    fs::write(&path, interface).unwrap();\n    // Call `cast find-block`\n    cmd.arg(\"interface\").arg(&path).assert_success().stdout_eq(str![[\n        r#\"// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.4;\n\nlibrary IIntegrationManager {\n    type SpendAssetsHandleType is uint8;\n}\n\ninterface Interface {\n    function getIntegrationManager() external view returns (address integrationManager_);\n    function lend(address _vaultProxy, bytes memory, bytes memory _assetData) external;\n    function parseAssetsForAction(address, bytes4 _selector, bytes memory _actionData)\n        external\n        view\n        returns (\n            IIntegrationManager.SpendAssetsHandleType spendAssetsHandleType_,\n            address[] memory spendAssets_,\n            uint256[] memory spendAssetAmounts_,\n            address[] memory incomingAssets_,\n            uint256[] memory minIncomingAssetAmounts_\n        );\n    function redeem(address _vaultProxy, bytes memory, bytes memory _assetData) external;\n}\n\n\"#\n    ]]);\n});\n\n// tests that `cast interface --flatten` inlines inherited struct types into the interface\n// <https://github.com/foundry-rs/foundry/issues/9960>\ncasttest!(interface_flatten, |prj, cmd| {\n    let interface = include_str!(\"../fixtures/interface_inherited_struct.json\");\n\n    let path = prj.root().join(\"interface_inherited_struct.json\");\n    fs::write(&path, interface).unwrap();\n\n    // Without --flatten, a separate library is generated for the struct\n    cmd.arg(\"interface\").arg(&path).assert_success().stdout_eq(str![[\n        r#\"// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.4;\n\nlibrary IBase {\n    struct TestStruct {\n        address asset;\n    }\n}\n\ninterface Interface {\n    function test(IBase.TestStruct memory param) external;\n}\n\n\"#\n    ]]);\n\n    // With --flatten, the struct is inlined into the interface\n    cmd.cast_fuse().arg(\"interface\").arg(\"--flatten\").arg(&path).assert_success().stdout_eq(str![\n        [r#\"// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.4;\n\ninterface Interface {\n    // Types from `IBase`\n    struct TestStruct {\n        address asset;\n    }\n\n    function test(TestStruct memory param) external;\n}\n\n\"#]\n    ]);\n});\n\n// tests that fetches WETH interface from etherscan\n// <https://etherscan.io/token/0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2>\ncasttest!(flaky_fetch_weth_interface_from_etherscan, |_prj, cmd| {\n    cmd.args([\n        \"interface\",\n        \"--etherscan-api-key\",\n        &next_etherscan_api_key(),\n        \"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2\",\n    ])\n    .assert_success()\n    .stdout_eq(str![[r#\"\n// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.4;\n\ninterface WETH9 {\n    event Approval(address indexed src, address indexed guy, uint256 wad);\n    event Deposit(address indexed dst, uint256 wad);\n    event Transfer(address indexed src, address indexed dst, uint256 wad);\n    event Withdrawal(address indexed src, uint256 wad);\n\n    fallback() external payable;\n\n    function allowance(address, address) external view returns (uint256);\n    function approve(address guy, uint256 wad) external returns (bool);\n    function balanceOf(address) external view returns (uint256);\n    function decimals() external view returns (uint8);\n    function deposit() external payable;\n    function name() external view returns (string memory);\n    function symbol() external view returns (string memory);\n    function totalSupply() external view returns (uint256);\n    function transfer(address dst, uint256 wad) external returns (bool);\n    function transferFrom(address src, address dst, uint256 wad) external returns (bool);\n    function withdraw(uint256 wad) external;\n}\n\n\"#]]);\n});\n\ncasttest!(ens_namehash, |_prj, cmd| {\n    cmd.args([\"namehash\", \"emo.eth\"]).assert_success().stdout_eq(str![[r#\"\n0x0a21aaf2f6414aa664deb341d1114351fdb023cad07bf53b28e57c26db681910\n\n\"#]]);\n});\n\ncasttest!(ens_lookup, |_prj, cmd| {\n    let eth_rpc_url = next_http_rpc_endpoint();\n    cmd.args([\n        \"lookup-address\",\n        \"0x28679A1a632125fbBf7A68d850E50623194A709E\",\n        \"--rpc-url\",\n        &eth_rpc_url,\n        \"--verify\",\n    ])\n    .assert_success()\n    .stdout_eq(str![[r#\"\nemo.eth\n\n\"#]]);\n});\n\ncasttest!(ens_resolve, |_prj, cmd| {\n    let eth_rpc_url = next_http_rpc_endpoint();\n    cmd.args([\"resolve-name\", \"emo.eth\", \"--rpc-url\", &eth_rpc_url, \"--verify\"])\n        .assert_success()\n        .stdout_eq(str![[r#\"\n0x28679A1a632125fbBf7A68d850E50623194A709E\n\n\"#]]);\n});\n\ncasttest!(ens_resolve_no_dot_eth, |_prj, cmd| {\n    let eth_rpc_url = next_http_rpc_endpoint();\n    cmd.args([\"resolve-name\", \"emo\", \"--rpc-url\", &eth_rpc_url, \"--verify\"])\n        .assert_failure()\n        .stderr_eq(str![[r#\"\nError: ENS resolver not found for name \"emo\"\n\n\"#]]);\n});\n\ncasttest!(index7201, |_prj, cmd| {\n    cmd.args([\"index-erc7201\", \"example.main\"]).assert_success().stdout_eq(str![[r#\"\n0x183a6125c38840424c4a85fa12bab2ab606c4b6d0e7cc73c0c06ba5300eab500\n\n\"#]]);\n});\n\ncasttest!(index7201_unknown_formula_id, |_prj, cmd| {\n    cmd.args([\"index-erc7201\", \"test\", \"--formula-id\", \"unknown\"]).assert_failure().stderr_eq(\n        str![[r#\"\nError: unsupported formula ID: unknown\n\n\"#]],\n    );\n});\n\ncasttest!(block_number, |_prj, cmd| {\n    let eth_rpc_url = next_http_rpc_endpoint();\n    let s = cmd\n        .args([\"block-number\", \"--rpc-url\", eth_rpc_url.as_str()])\n        .assert_success()\n        .get_output()\n        .stdout_lossy();\n    assert!(s.trim().parse::<u64>().unwrap() > 0, \"{s}\")\n});\n\ncasttest!(block_number_latest, |_prj, cmd| {\n    let eth_rpc_url = next_http_rpc_endpoint();\n    let s = cmd\n        .args([\"block-number\", \"--rpc-url\", eth_rpc_url.as_str(), \"latest\"])\n        .assert_success()\n        .get_output()\n        .stdout_lossy();\n    assert!(s.trim().parse::<u64>().unwrap() > 0, \"{s}\")\n});\n\ncasttest!(block_number_hash, |_prj, cmd| {\n    let eth_rpc_url = next_http_rpc_endpoint();\n    let s = cmd\n        .args([\n            \"block-number\",\n            \"--rpc-url\",\n            eth_rpc_url.as_str(),\n            \"0x88e96d4537bea4d9c05d12549907b32561d3bf31f45aae734cdc119f13406cb6\",\n        ])\n        .assert_success()\n        .get_output()\n        .stdout_lossy();\n    assert_eq!(s.trim().parse::<u64>().unwrap(), 1, \"{s}\")\n});\n\n// Tests that `cast --disable-block-gas-limit` commands are working correctly for BSC\n// <https://github.com/foundry-rs/foundry/pull/9996>\n// Equivalent transaction on Binance Smart Chain Testnet:\n// <https://testnet.bscscan.com/tx/0x0db4f279fc4d47dca1e6ace180f45f50c5bf12e2b968f210c217f57031e02744>\ncasttest!(run_disable_block_gas_limit_check, |_prj, cmd| {\n    let bsc_testnet_rpc_url = next_rpc_endpoint(NamedChain::BinanceSmartChainTestnet);\n\n    let latest_block_json: serde_json::Value = serde_json::from_str(\n        &cmd.args([\"block\", \"--rpc-url\", bsc_testnet_rpc_url.as_str(), \"--json\"])\n            .assert_success()\n            .get_output()\n            .stdout_lossy(),\n    )\n    .expect(\"Failed to parse latest block\");\n\n    let latest_excessive_gas_limit_tx =\n        latest_block_json[\"transactions\"].as_array().and_then(|txs| {\n            txs.iter()\n                .find(|tx| tx.get(\"gas\").and_then(|gas| gas.as_str()) == Some(\"0x7fffffffffffffff\"))\n        });\n\n    match latest_excessive_gas_limit_tx {\n        Some(tx) => {\n            let tx_hash =\n                tx.get(\"hash\").and_then(|h| h.as_str()).expect(\"Transaction missing hash\");\n\n            // If --disable-block-gas-limit is not provided, the transaction should fail as the gas\n            // limit exceeds the block gas limit.\n            cmd.cast_fuse()\n                .args([\"run\", \"-v\", tx_hash, \"--quick\", \"--rpc-url\", bsc_testnet_rpc_url.as_str()])\n                .assert_failure()\n                .stderr_eq(str![[r#\"\nError: EVM error; transaction validation error: caller gas limit exceeds the block gas limit\n\n\"#]]);\n\n            // If --disable-block-gas-limit is provided, the transaction should succeed\n            // despite the gas limit exceeding the block gas limit.\n            cmd.cast_fuse()\n                .args([\n                    \"run\",\n                    \"-v\",\n                    tx_hash,\n                    \"--quick\",\n                    \"--rpc-url\",\n                    bsc_testnet_rpc_url.as_str(),\n                    \"--disable-block-gas-limit\",\n                ])\n                .assert_success()\n                .stdout_eq(str![[r#\"\n...\nTransaction successfully executed.\n[GAS]\n\n\"#]]);\n        }\n        None => {\n            eprintln!(\n                \"Skipping test: No transaction with gas = 0x7fffffffffffffff found in the latest block.\"\n            );\n        }\n    }\n});\n\ncasttest!(send_eip7702, async |_prj, cmd| {\n    let (_api, handle) =\n        anvil::spawn(NodeConfig::test().with_hardfork(Some(EthereumHardfork::Prague.into()))).await;\n    let endpoint = handle.http_endpoint();\n\n    cmd.args([\n        \"send\",\n        \"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266\",\n        \"--auth\",\n        \"0x70997970C51812dc3A010C7d01b50e0d17dc79C8\",\n        \"--private-key\",\n        \"0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80\",\n        \"--rpc-url\",\n        &endpoint,\n    ])\n    .assert_success();\n\n    cmd.cast_fuse()\n        .args([\"code\", \"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266\", \"--rpc-url\", &endpoint])\n        .assert_success()\n        .stdout_eq(str![[r#\"\n0xef010070997970c51812dc3a010c7d01b50e0d17dc79c8\n\n\"#]]);\n});\n\ncasttest!(send_eip7702_multiple_auth, async |_prj, cmd| {\n    let (_api, handle) =\n        anvil::spawn(NodeConfig::test().with_hardfork(Some(EthereumHardfork::Prague.into()))).await;\n    let endpoint = handle.http_endpoint();\n\n    // Create a pre-signed authorization using a different signer (account index 1)\n    let signer: PrivateKeySigner =\n        \"0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d\".parse().unwrap();\n    // Anvil default chain_id is 31337\n    let auth = Authorization {\n        chain_id: U256::from(31337),\n        // Delegate to account index 2\n        address: address!(\"0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC\"),\n        nonce: 0,\n    };\n    let signature = signer.sign_hash(&auth.signature_hash()).await.unwrap();\n    let signed_auth = auth.into_signed(signature);\n    let encoded_auth = hex::encode_prefixed(alloy_rlp::encode(&signed_auth));\n\n    // Send transaction with multiple --auth flags: one address and one pre-signed authorization\n    let output = cmd\n        .args([\n            \"send\",\n            \"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266\",\n            \"--auth\",\n            \"0x70997970C51812dc3A010C7d01b50e0d17dc79C8\",\n            \"--auth\",\n            &encoded_auth,\n            \"--private-key\",\n            \"0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80\",\n            \"--rpc-url\",\n            &endpoint,\n            \"--gas-limit\",\n            \"100000\",\n            \"--json\",\n        ])\n        .assert_success()\n        .get_output()\n        .stdout_lossy();\n\n    // Extract transaction hash from JSON output\n    let json: serde_json::Value = serde_json::from_str(&output).unwrap();\n    let tx_hash = json[\"transactionHash\"].as_str().unwrap();\n\n    // Use cast tx to verify multiple authorizations were included\n    let tx_output = cmd\n        .cast_fuse()\n        .args([\"tx\", tx_hash, \"--rpc-url\", &endpoint, \"--json\"])\n        .assert_success()\n        .get_output()\n        .stdout_lossy();\n\n    let tx_json: serde_json::Value = serde_json::from_str(&tx_output).unwrap();\n    let auth_list = tx_json[\"authorizationList\"].as_array().unwrap();\n\n    // Verify we have 2 authorizations\n    assert_eq!(auth_list.len(), 2, \"Expected 2 authorizations in the transaction\");\n});\n\n// Test that multiple address-based authorizations are rejected\ncasttest!(send_eip7702_multiple_address_auth_rejected, async |_prj, cmd| {\n    let (_api, handle) =\n        anvil::spawn(NodeConfig::test().with_hardfork(Some(EthereumHardfork::Prague.into()))).await;\n    let endpoint = handle.http_endpoint();\n\n    cmd.args([\n        \"send\",\n        \"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266\",\n        \"--auth\",\n        \"0x70997970C51812dc3A010C7d01b50e0d17dc79C8\",\n        \"--auth\",\n        \"0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC\",\n        \"--private-key\",\n        \"0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80\",\n        \"--rpc-url\",\n        &endpoint,\n    ]);\n    cmd.assert_failure().stderr_eq(str![[r#\"\nError: Multiple address-based authorizations provided. Only one address can be specified; use pre-signed authorizations (hex-encoded) for multiple authorizations.\n\n\"#]]);\n});\n\ncasttest!(send_sync, async |_prj, cmd| {\n    let (_api, handle) = anvil::spawn(NodeConfig::test()).await;\n    let endpoint = handle.http_endpoint();\n\n    let output = cmd\n        .args([\n            \"send\",\n            \"0x70997970C51812dc3A010C7d01b50e0d17dc79C8\",\n            \"--value\",\n            \"1\",\n            \"--private-key\",\n            \"0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80\",\n            \"--rpc-url\",\n            &endpoint,\n            \"--sync\",\n        ])\n        .assert_success()\n        .get_output()\n        .stdout_lossy();\n\n    assert!(output.contains(\"transactionHash\"));\n    assert!(output.contains(\"blockNumber\"));\n    assert!(output.contains(\"gasUsed\"));\n});\n\ncasttest!(hash_message, |_prj, cmd| {\n    cmd.args([\"hash-message\", \"hello\"]).assert_success().stdout_eq(str![[r#\"\n0x50b2c43fd39106bafbba0da34fc430e1f91e3c96ea2acee2bc34119f92b37750\n\n\"#]]);\n\n    cmd.cast_fuse().args([\"hash-message\", \"0x68656c6c6f\"]).assert_success().stdout_eq(str![[r#\"\n0x83a0870b6c63a71efdd3b2749ef700653d97454152c4b53fa9b102dc430c7c32\n\n\"#]]);\n});\n\ncasttest!(parse_units, |_prj, cmd| {\n    cmd.args([\"parse-units\", \"1.5\", \"6\"]).assert_success().stdout_eq(str![[r#\"\n1500000\n\n\"#]]);\n\n    cmd.cast_fuse().args([\"pun\", \"1.23\", \"18\"]).assert_success().stdout_eq(str![[r#\"\n1230000000000000000\n\n\"#]]);\n\n    cmd.cast_fuse().args([\"--parse-units\", \"1.23\", \"3\"]).assert_success().stdout_eq(str![[r#\"\n1230\n\n\"#]]);\n});\n\ncasttest!(string_decode, |_prj, cmd| {\n    cmd.args([\"string-decode\", \"0x88c379a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000054753303235000000000000000000000000000000000000000000000000000000\"]).assert_success().stdout_eq(str![[r#\"\n\"GS025\"\n\n\"#]]);\n});\n\ncasttest!(format_units, |_prj, cmd| {\n    cmd.args([\"format-units\", \"1000000\", \"6\"]).assert_success().stdout_eq(str![[r#\"\n1\n\n\"#]]);\n\n    cmd.cast_fuse().args([\"--format-units\", \"2500000\", \"6\"]).assert_success().stdout_eq(str![[\n        r#\"\n2.500000\n\n\"#\n    ]]);\n\n    cmd.cast_fuse().args([\"fun\", \"1230\", \"3\"]).assert_success().stdout_eq(str![[r#\"\n1.230\n\n\"#]]);\n});\n\n// tests that fetches a sample contract creation code\n// <https://etherscan.io/address/0x0923cad07f06b2d0e5e49e63b8b35738d4156b95>\ncasttest!(flaky_fetch_creation_code_from_etherscan, |_prj, cmd| {\n    let eth_rpc_url = next_http_rpc_endpoint();\n    cmd.args([\n        \"creation-code\",\n        \"--etherscan-api-key\",\n        &next_etherscan_api_key(),\n        \"0x0923cad07f06b2d0e5e49e63b8b35738d4156b95\",\n        \"--rpc-url\",\n        eth_rpc_url.as_str(),\n    ])\n    .assert_success()\n    .stdout_eq(str![[r#\"\n0x60566050600b82828239805160001a6073146043577f4e487b7100000000000000000000000000000000000000000000000000000000600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea264697066735822122074c61e8e4eefd410ca92eec26e8112ec6e831d0a4bf35718fdd78b45d68220d064736f6c63430008070033\n\n\"#]]);\n});\n\n// tests that fetches a sample contract creation args bytes\n// <https://etherscan.io/address/0x0923cad07f06b2d0e5e49e63b8b35738d4156b95>\ncasttest!(flaky_fetch_creation_code_only_args_from_etherscan, |_prj, cmd| {\n    let eth_rpc_url = next_http_rpc_endpoint();\n    cmd.args([\n        \"creation-code\",\n        \"--etherscan-api-key\",\n        &next_etherscan_api_key(),\n        \"0x6982508145454ce325ddbe47a25d4ec3d2311933\",\n        \"--rpc-url\",\n        eth_rpc_url.as_str(),\n        \"--only-args\",\n    ])\n    .assert_success()\n    .stdout_eq(str![[r#\"\n0x00000000000000000000000000000000000014bddab3e51a57cff87a50000000\n\n\"#]]);\n});\n\n// tests that displays a sample contract creation args\n// <https://etherscan.io/address/0x0923cad07f06b2d0e5e49e63b8b35738d4156b95>\ncasttest!(flaky_fetch_constructor_args_from_etherscan, |_prj, cmd| {\n    let eth_rpc_url = next_http_rpc_endpoint();\n    cmd.args([\n        \"constructor-args\",\n        \"--etherscan-api-key\",\n        &next_etherscan_api_key(),\n        \"0x6982508145454ce325ddbe47a25d4ec3d2311933\",\n        \"--rpc-url\",\n        eth_rpc_url.as_str(),\n    ])\n    .assert_success()\n    .stdout_eq(str![[r#\"\n0x00000000000000000000000000000000000014bddab3e51a57cff87a50000000 → Uint(420690000000000000000000000000000, 256)\n\n\"#]]);\n});\n\n// <https://github.com/foundry-rs/foundry/issues/3473>\ncasttest!(flaky_test_non_mainnet_traces, |prj, cmd| {\n    prj.clear();\n    cmd.args([\n        \"run\",\n        \"0xa003e419e2d7502269eb5eda56947b580120e00abfd5b5460d08f8af44a0c24f\",\n        \"--rpc-url\",\n        next_rpc_endpoint(NamedChain::Optimism).as_str(),\n        \"--etherscan-api-key\",\n        next_etherscan_api_key().as_str(),\n    ])\n    .assert_success()\n    .stdout_eq(str![[r#\"\nExecuting previous transactions from the block.\nTraces:\n  [33841] FiatTokenProxy::fallback(0x111111125421cA6dc452d289314280a0f8842A65, 164054805 [1.64e8])\n    ├─ [26673] FiatTokenV2_2::approve(0x111111125421cA6dc452d289314280a0f8842A65, 164054805 [1.64e8]) [delegatecall]\n    │   ├─ emit Approval(owner: 0x9a95Af47C51562acfb2107F44d7967DF253197df, spender: 0x111111125421cA6dc452d289314280a0f8842A65, value: 164054805 [1.64e8])\n    │   └─ ← [Return] true\n    └─ ← [Return] true\n...\n\n\"#]]);\n});\n\n// tests that displays a sample contract artifact\n// <https://etherscan.io/address/0x0923cad07f06b2d0e5e49e63b8b35738d4156b95>\ncasttest!(flaky_fetch_artifact_from_etherscan, |_prj, cmd| {\n    let eth_rpc_url = next_http_rpc_endpoint();\n    cmd.args([\n        \"artifact\",\n        \"--etherscan-api-key\",\n        &next_etherscan_api_key(),\n        \"0x0923cad07f06b2d0e5e49e63b8b35738d4156b95\",\n        \"--rpc-url\",\n        eth_rpc_url.as_str(),\n    ])\n    .assert_success()\n    .stdout_eq(str![[r#\"{\n  \"abi\": [],\n  \"bytecode\": {\n    \"object\": \"0x60566050600b82828239805160001a6073146043577f4e487b7100000000000000000000000000000000000000000000000000000000600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea264697066735822122074c61e8e4eefd410ca92eec26e8112ec6e831d0a4bf35718fdd78b45d68220d064736f6c63430008070033\"\n  }\n}\n\n\"#]]);\n});\n\n// tests cast can decode traces when using project artifacts\nforgetest_async!(decode_traces_with_project_artifacts, |prj, cmd| {\n    let (api, handle) =\n        anvil::spawn(NodeConfig::test().with_disable_default_create2_deployer(true)).await;\n\n    foundry_test_utils::util::initialize(prj.root());\n    prj.add_source(\n        \"LocalProjectContract\",\n        r#\"\ncontract LocalProjectContract {\n    event LocalProjectContractCreated(address owner);\n\n    constructor() {\n        emit LocalProjectContractCreated(msg.sender);\n    }\n}\n   \"#,\n    );\n    prj.add_script(\n        \"LocalProjectScript\",\n        r#\"\nimport \"forge-std/Script.sol\";\nimport {LocalProjectContract} from \"../src/LocalProjectContract.sol\";\n\ncontract LocalProjectScript is Script {\n    function run() public {\n        vm.startBroadcast();\n        new LocalProjectContract();\n        vm.stopBroadcast();\n    }\n}\n   \"#,\n    );\n\n    cmd.args([\n        \"script\",\n        \"--private-key\",\n        \"0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80\",\n        \"--rpc-url\",\n        &handle.http_endpoint(),\n        \"--broadcast\",\n        \"LocalProjectScript\",\n    ]);\n\n    cmd.assert_success();\n\n    let tx_hash = api\n        .transaction_by_block_number_and_index(BlockNumberOrTag::Latest, Index::from(0))\n        .await\n        .unwrap()\n        .unwrap()\n        .tx_hash();\n\n    // Assert cast with local artifacts from outside the project.\n    cmd.cast_fuse()\n        .args([\"run\", \"--la\", format!(\"{tx_hash}\").as_str(), \"--rpc-url\", &handle.http_endpoint()])\n        .assert_success()\n        .stdout_eq(str![[r#\"\nExecuting previous transactions from the block.\nCompiling project to generate artifacts\nNothing to compile\n\n\"#]]);\n\n    // Run cast from project dir.\n    cmd.cast_fuse().set_current_dir(prj.root());\n\n    // Assert cast without local artifacts cannot decode traces.\n    cmd.cast_fuse()\n        .args([\"run\", format!(\"{tx_hash}\").as_str(), \"--rpc-url\", &handle.http_endpoint()])\n        .assert_success()\n        .stdout_eq(str![[r#\"\nExecuting previous transactions from the block.\nTraces:\n  [..] → new <unknown>@0x5FbDB2315678afecb367f032d93F642f64180aa3\n    ├─  emit topic 0: 0xa7263295d3a687d750d1fd377b5df47de69d7db8decc745aaa4bbee44dc1688d\n    │           data: 0x000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266\n    └─ ← [Return] 62 bytes of code\n\n\nTransaction successfully executed.\n[GAS]\n\n\"#]]);\n\n    // Assert cast with local artifacts can decode traces.\n    cmd.cast_fuse()\n        .args([\"run\", \"--la\", format!(\"{tx_hash}\").as_str(), \"--rpc-url\", &handle.http_endpoint()])\n        .assert_success()\n        .stdout_eq(str![[r#\"\nExecuting previous transactions from the block.\nCompiling project to generate artifacts\nNo files changed, compilation skipped\nTraces:\n  [..] → new LocalProjectContract@0x5FbDB2315678afecb367f032d93F642f64180aa3\n    ├─ emit LocalProjectContractCreated(owner: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266)\n    └─ ← [Return] 62 bytes of code\n\n\nTransaction successfully executed.\n[GAS]\n\n\"#]]);\n});\n\n// tests cast can decode traces when running with verbosity level > 4\nforgetest_async!(show_state_changes_in_traces, |prj, cmd| {\n    let (api, handle) = anvil::spawn(NodeConfig::test()).await;\n\n    foundry_test_utils::util::initialize(prj.root());\n    prj.initialize_default_contracts();\n    // Deploy counter contract.\n    cmd.args([\n        \"script\",\n        \"--private-key\",\n        \"0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80\",\n        \"--rpc-url\",\n        &handle.http_endpoint(),\n        \"--broadcast\",\n        \"CounterScript\",\n    ])\n    .assert_success();\n\n    // Send tx to change counter storage value.\n    cmd.cast_fuse()\n        .args([\n            \"send\",\n            \"0x5FbDB2315678afecb367f032d93F642f64180aa3\",\n            \"setNumber(uint256)\",\n            \"111\",\n            \"--private-key\",\n            \"0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80\",\n            \"--rpc-url\",\n            &handle.http_endpoint(),\n        ])\n        .assert_success();\n\n    let tx_hash = api\n        .transaction_by_block_number_and_index(BlockNumberOrTag::Latest, Index::from(0))\n        .await\n        .unwrap()\n        .unwrap()\n        .tx_hash();\n\n    // Assert cast with verbosity displays storage changes.\n    cmd.cast_fuse()\n        .args([\n            \"run\",\n            format!(\"{tx_hash}\").as_str(),\n            \"-vvvvv\",\n            \"--rpc-url\",\n            &handle.http_endpoint(),\n        ])\n        .assert_success()\n        .stdout_eq(str![[r#\"\nExecuting previous transactions from the block.\nTraces:\n  [..] 0x5FbDB2315678afecb367f032d93F642f64180aa3::setNumber(111)\n    ├─  storage changes:\n    │   @ 0: 0 → 111\n    └─ ← [Stop]\n\n\nTransaction successfully executed.\n[GAS]\n\n\"#]]);\n});\n\n// tests cast can decode external libraries traces with project cached selectors\nforgetest_async!(flaky_decode_external_libraries_with_cached_selectors, |prj, cmd| {\n    let (api, handle) = anvil::spawn(NodeConfig::test()).await;\n\n    foundry_test_utils::util::initialize(prj.root());\n    prj.add_source(\n        \"ExternalLib\",\n        r#\"\nimport \"./CounterInExternalLib.sol\";\nlibrary ExternalLib {\n    function updateCounterInExternalLib(CounterInExternalLib.Info storage counterInfo, uint256 counter) public {\n        counterInfo.counter = counter + 1;\n    }\n}\n   \"#,\n    );\n    prj.add_source(\n        \"CounterInExternalLib\",\n        r#\"\nimport \"./ExternalLib.sol\";\ncontract CounterInExternalLib {\n    struct Info {\n        uint256 counter;\n    }\n    Info info;\n    constructor() {\n        ExternalLib.updateCounterInExternalLib(info, 100);\n    }\n}\n   \"#,\n    );\n    prj.add_script(\n        \"CounterInExternalLibScript\",\n        r#\"\nimport \"forge-std/Script.sol\";\nimport {CounterInExternalLib} from \"../src/CounterInExternalLib.sol\";\ncontract CounterInExternalLibScript is Script {\n    function run() public {\n        vm.startBroadcast();\n        new CounterInExternalLib();\n        vm.stopBroadcast();\n    }\n}\n   \"#,\n    );\n\n    cmd.args([\n        \"script\",\n        \"--private-key\",\n        \"0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80\",\n        \"--rpc-url\",\n        &handle.http_endpoint(),\n        \"--broadcast\",\n        \"CounterInExternalLibScript\",\n    ])\n    .assert_success();\n\n    let tx_hash = api\n        .transaction_by_block_number_and_index(BlockNumberOrTag::Latest, Index::from(0))\n        .await\n        .unwrap()\n        .unwrap()\n        .tx_hash();\n\n    // Build and cache project selectors.\n    cmd.forge_fuse().args([\"build\"]).assert_success();\n    cmd.forge_fuse().args([\"selectors\", \"cache\"]).assert_success();\n    // Assert cast with local artifacts can decode external lib signature.\n    cmd.cast_fuse()\n        .args([\"run\", format!(\"{tx_hash}\").as_str(), \"--rpc-url\", &handle.http_endpoint()])\n        .assert_success()\n        .stdout_eq(str![[r#\"\n...\nTraces:\n  [..] → new <unknown>@0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512\n    ├─ [..] [..]::updateCounterInExternalLib(0, 100) [delegatecall]\n    │   └─ ← [Stop]\n    └─ ← [Return] [..] bytes of code\n\n\nTransaction successfully executed.\n[GAS]\n\n\"#]]);\n});\n\n// https://github.com/foundry-rs/foundry/issues/9476\nforgetest_async!(cast_call_custom_chain_id, |_prj, cmd| {\n    let chain_id = 55555u64;\n    let (_api, handle) = anvil::spawn(NodeConfig::test().with_chain_id(Some(chain_id))).await;\n\n    let http_endpoint = handle.http_endpoint();\n\n    cmd.cast_fuse()\n        .args([\n            \"call\",\n            \"5FbDB2315678afecb367f032d93F642f64180aa3\",\n            \"--rpc-url\",\n            &http_endpoint,\n            \"--chain\",\n            &chain_id.to_string(),\n        ])\n        .assert_success();\n});\n\n// https://github.com/foundry-rs/foundry/issues/10848\nforgetest_async!(cast_call_disable_labels, |prj, cmd| {\n    let (_, handle) = anvil::spawn(NodeConfig::test()).await;\n\n    foundry_test_utils::util::initialize(prj.root());\n    prj.initialize_default_contracts();\n    prj.add_source(\n        \"Counter\",\n        r#\"\ncontract Counter {\n    uint256 public number;\n\n    function getBalance(address target) public returns (uint256) {\n        return target.balance;\n    }\n}\n   \"#,\n    );\n\n    // Deploy counter contract.\n    cmd.args([\n        \"script\",\n        \"--private-key\",\n        \"0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80\",\n        \"--rpc-url\",\n        &handle.http_endpoint(),\n        \"--broadcast\",\n        \"CounterScript\",\n    ])\n    .assert_success();\n\n    // Override state, `number()` should return overridden value.\n    cmd.cast_fuse()\n        .args([\n            \"call\",\n            \"0x5FbDB2315678afecb367f032d93F642f64180aa3\",\n            \"--rpc-url\",\n            &handle.http_endpoint(),\n            \"--override-state\",\n            \"0x5FbDB2315678afecb367f032d93F642f64180aa3:0x0:0x1234\",\n            \"number()(uint256)\",\n        ])\n        .assert_success()\n        .stdout_eq(str![[r#\"\n4660\n\n\"#]]);\n\n    // Override state, `number()` should return overridden value.\n    cmd.cast_fuse()\n        .args([\n            \"call\",\n            \"0x5FbDB2315678afecb367f032d93F642f64180aa3\",\n            \"--labels\",\n            \"0x5FbDB2315678afecb367f032d93F642f64180aa3:WETH\",\n            \"--rpc-url\",\n            &handle.http_endpoint(),\n            \"--override-state\",\n            \"0x5FbDB2315678afecb367f032d93F642f64180aa3:0x0:0x1234\",\n            \"number()(uint256)\",\n            \"--trace\",\n        ])\n        .assert_success()\n        .stdout_eq(str![[r#\"\nTraces:\n  [2402] WETH::number()\n    └─ ← [Return] 0x0000000000000000000000000000000000000000000000000000000000001234\n\n\nTransaction successfully executed.\n[GAS]\n\n\"#]]);\n\n    // Override state, `number()` with `disable_labels`.\n    cmd.cast_fuse()\n        .args([\n            \"call\",\n            \"0x5FbDB2315678afecb367f032d93F642f64180aa3\",\n            \"--labels\",\n            \"0x5FbDB2315678afecb367f032d93F642f64180aa3:WETH\",\n            \"--rpc-url\",\n            &handle.http_endpoint(),\n            \"--override-state\",\n            \"0x5FbDB2315678afecb367f032d93F642f64180aa3:0x0:0x1234\",\n            \"number()(uint256)\",\n            \"--trace\",\n            \"--disable-labels\",\n        ])\n        .assert_success()\n        .stdout_eq(str![[r#\"\nTraces:\n  [2402] 0x5FbDB2315678afecb367f032d93F642f64180aa3::number()\n    └─ ← [Return] 0x0000000000000000000000000000000000000000000000000000000000001234\n\n\nTransaction successfully executed.\n[GAS]\n\n\"#]]);\n});\n\n// https://github.com/foundry-rs/foundry/issues/10189\nforgetest_async!(cast_call_custom_override, |prj, cmd| {\n    let (_, handle) = anvil::spawn(NodeConfig::test()).await;\n\n    foundry_test_utils::util::initialize(prj.root());\n    prj.initialize_default_contracts();\n    prj.add_source(\n        \"Counter\",\n        r#\"\ncontract Counter {\n    uint256 public number;\n\n    function getBalance(address target) public returns (uint256) {\n        return target.balance;\n    }\n}\n   \"#,\n    );\n\n    // Deploy counter contract.\n    cmd.args([\n        \"script\",\n        \"--private-key\",\n        \"0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80\",\n        \"--rpc-url\",\n        &handle.http_endpoint(),\n        \"--broadcast\",\n        \"CounterScript\",\n    ])\n    .assert_success();\n\n    // Override state, `number()` should return overridden value.\n    cmd.cast_fuse()\n        .args([\n            \"call\",\n            \"0x5FbDB2315678afecb367f032d93F642f64180aa3\",\n            \"--rpc-url\",\n            &handle.http_endpoint(),\n            \"--override-state\",\n            \"0x5FbDB2315678afecb367f032d93F642f64180aa3:0x0:0x1234\",\n            \"number()(uint256)\",\n        ])\n        .assert_success()\n        .stdout_eq(str![[r#\"\n4660\n\n\"#]]);\n\n    // Override state, `number()` should return overridden value.\n    cmd.cast_fuse()\n        .args([\n            \"call\",\n            \"0x5FbDB2315678afecb367f032d93F642f64180aa3\",\n            \"--rpc-url\",\n            &handle.http_endpoint(),\n            \"--override-state\",\n            \"0x5FbDB2315678afecb367f032d93F642f64180aa3:0x0:0x1234\",\n            \"number()(uint256)\",\n            \"--trace\",\n        ])\n        .assert_success()\n        .stdout_eq(str![[r#\"\nTraces:\n  [2402] 0x5FbDB2315678afecb367f032d93F642f64180aa3::number()\n    └─ ← [Return] 0x0000000000000000000000000000000000000000000000000000000000001234\n\n\nTransaction successfully executed.\n[GAS]\n\n\"#]]);\n\n    // Override balance, `getBalance()` should return overridden value.\n    cmd.cast_fuse()\n        .args([\n            \"call\",\n            \"0x5FbDB2315678afecb367f032d93F642f64180aa3\",\n            \"--rpc-url\",\n            &handle.http_endpoint(),\n            \"--override-balance\",\n            \"0x5FbDB2315678afecb367f032d93F642f64180aa3:0x1111\",\n            \"getBalance(address)(uint256)\",\n            \"0x5FbDB2315678afecb367f032d93F642f64180aa3\",\n        ])\n        .assert_success()\n        .stdout_eq(str![[r#\"\n4369\n\n\"#]]);\n\n    // Override balance, `getBalance()` should return overridden value.\n    cmd.cast_fuse()\n        .args([\n            \"call\",\n            \"0x5FbDB2315678afecb367f032d93F642f64180aa3\",\n            \"--rpc-url\",\n            &handle.http_endpoint(),\n            \"--override-balance\",\n            \"0x5FbDB2315678afecb367f032d93F642f64180aa3:0x1111\",\n            \"getBalance(address)(uint256)\",\n            \"0x5FbDB2315678afecb367f032d93F642f64180aa3\",\n            \"--trace\",\n        ])\n        .assert_success()\n        .stdout_eq(str![[r#\"\nTraces:\n  [747] 0x5FbDB2315678afecb367f032d93F642f64180aa3::getBalance(0x5FbDB2315678afecb367f032d93F642f64180aa3)\n    └─ ← [Return] 0x0000000000000000000000000000000000000000000000000000000000001111\n\n\nTransaction successfully executed.\n[GAS]\n\n\"#]]);\n\n    // Override code with\n    // contract Counter {\n    //     uint256 public number1;\n    // }\n    // Calling `number()` should fail.\n    cmd.cast_fuse()\n        .args([\n            \"call\",\n            \"0x5FbDB2315678afecb367f032d93F642f64180aa3\",\n            \"--rpc-url\",\n            &handle.http_endpoint(),\n            \"--override-code\",\n            \"0x5FbDB2315678afecb367f032d93F642f64180aa3:0x6080604052348015600e575f5ffd5b50600436106026575f3560e01c8063c223a39e14602a575b5f5ffd5b60306044565b604051603b9190605f565b60405180910390f35b5f5481565b5f819050919050565b6059816049565b82525050565b5f60208201905060705f8301846052565b9291505056fea26469706673582212202a0acfb9083efed3e0e9f27177b090731d4392cf196d58e27e05088f59008d0964736f6c634300081d0033\",\n            \"number()(uint256)\",\n        ])\n        .assert_failure()\n        .stderr_eq(str![[r#\"\nError: server returned an error response: error code 3: execution reverted, data: \"0x\"\n\n\"#]]);\n\n    // Override code with\n    // contract Counter {\n    //     uint256 public number1;\n    // }\n    // Calling `number()` should revert.\n    cmd.cast_fuse()\n        .args([\n            \"call\",\n            \"0x5FbDB2315678afecb367f032d93F642f64180aa3\",\n            \"--rpc-url\",\n            &handle.http_endpoint(),\n            \"--override-code\",\n            \"0x5FbDB2315678afecb367f032d93F642f64180aa3:0x6080604052348015600e575f5ffd5b50600436106026575f3560e01c8063c223a39e14602a575b5f5ffd5b60306044565b604051603b9190605f565b60405180910390f35b5f5481565b5f819050919050565b6059816049565b82525050565b5f60208201905060705f8301846052565b9291505056fea26469706673582212202a0acfb9083efed3e0e9f27177b090731d4392cf196d58e27e05088f59008d0964736f6c634300081d0033\",\n            \"number()(uint256)\",\n            \"--trace\"\n        ])\n        .assert_success()\n        .stderr_eq(str![[r#\"\nError: Transaction failed.\n\n\"#]]);\n\n    // Calling `number1()` with overridden state should return new value.\n    cmd.cast_fuse()\n        .args([\n            \"call\",\n            \"0x5FbDB2315678afecb367f032d93F642f64180aa3\",\n            \"--rpc-url\",\n            &handle.http_endpoint(),\n            \"--override-code\",\n            \"0x5FbDB2315678afecb367f032d93F642f64180aa3:0x6080604052348015600e575f5ffd5b50600436106026575f3560e01c8063c223a39e14602a575b5f5ffd5b60306044565b604051603b9190605f565b60405180910390f35b5f5481565b5f819050919050565b6059816049565b82525050565b5f60208201905060705f8301846052565b9291505056fea26469706673582212202a0acfb9083efed3e0e9f27177b090731d4392cf196d58e27e05088f59008d0964736f6c634300081d0033\",\n            \"--override-state\",\n            \"0x5FbDB2315678afecb367f032d93F642f64180aa3:0x0:0x2222\",\n            \"number1()(uint256)\",\n        ])\n        .assert_success()\n        .stdout_eq(str![[r#\"\n8738\n\n\"#]]);\n\n    // Calling `number1()` with overridden state should return new value.\n    cmd.cast_fuse()\n        .args([\n            \"call\",\n            \"0x5FbDB2315678afecb367f032d93F642f64180aa3\",\n            \"--rpc-url\",\n            &handle.http_endpoint(),\n            \"--override-code\",\n            \"0x5FbDB2315678afecb367f032d93F642f64180aa3:0x6080604052348015600e575f5ffd5b50600436106026575f3560e01c8063c223a39e14602a575b5f5ffd5b60306044565b604051603b9190605f565b60405180910390f35b5f5481565b5f819050919050565b6059816049565b82525050565b5f60208201905060705f8301846052565b9291505056fea26469706673582212202a0acfb9083efed3e0e9f27177b090731d4392cf196d58e27e05088f59008d0964736f6c634300081d0033\",\n            \"--override-state\",\n            \"0x5FbDB2315678afecb367f032d93F642f64180aa3:0x0:0x2222\",\n            \"number1()(uint256)\",\n            \"--trace\"\n        ])\n        .assert_success()\n        .stdout_eq(str![[r#\"\nTraces:\n  [2402] 0x5FbDB2315678afecb367f032d93F642f64180aa3::number1()\n    └─ ← [Return] 0x0000000000000000000000000000000000000000000000000000000000002222\n\n\nTransaction successfully executed.\n[GAS]\n\n\"#]]);\n\n    // Calling `number1()` with overridden state should return new value.\n    cmd.cast_fuse()\n        .args([\n            \"call\",\n            \"0x5FbDB2315678afecb367f032d93F642f64180aa3\",\n            \"--rpc-url\",\n            &handle.http_endpoint(),\n            \"--override-code\",\n            \"0x5FbDB2315678afecb367f032d93F642f64180aa3:0x6080604052348015600e575f5ffd5b50600436106026575f3560e01c8063c223a39e14602a575b5f5ffd5b60306044565b604051603b9190605f565b60405180910390f35b5f5481565b5f819050919050565b6059816049565b82525050565b5f60208201905060705f8301846052565b9291505056fea26469706673582212202a0acfb9083efed3e0e9f27177b090731d4392cf196d58e27e05088f59008d0964736f6c634300081d0033\",\n            \"--override-state-diff\",\n            \"0x5FbDB2315678afecb367f032d93F642f64180aa3:0x0:0x2222\",\n            \"number1()(uint256)\",\n        ])\n        .assert_success()\n        .stdout_eq(str![[r#\"\n8738\n\n\"#]]);\n\n    // Calling `number1()` with overridden state should return new value.\n    cmd.cast_fuse()\n        .args([\n            \"call\",\n            \"0x5FbDB2315678afecb367f032d93F642f64180aa3\",\n            \"--rpc-url\",\n            &handle.http_endpoint(),\n            \"--override-code\",\n            \"0x5FbDB2315678afecb367f032d93F642f64180aa3:0x6080604052348015600e575f5ffd5b50600436106026575f3560e01c8063c223a39e14602a575b5f5ffd5b60306044565b604051603b9190605f565b60405180910390f35b5f5481565b5f819050919050565b6059816049565b82525050565b5f60208201905060705f8301846052565b9291505056fea26469706673582212202a0acfb9083efed3e0e9f27177b090731d4392cf196d58e27e05088f59008d0964736f6c634300081d0033\",\n            \"--override-state-diff\",\n            \"0x5FbDB2315678afecb367f032d93F642f64180aa3:0x0:0x2222\",\n            \"number1()(uint256)\",\n            \"--trace\",\n        ])\n        .assert_success()\n        .stdout_eq(str![[r#\"\nTraces:\n  [2402] 0x5FbDB2315678afecb367f032d93F642f64180aa3::number1()\n    └─ ← [Return] 0x0000000000000000000000000000000000000000000000000000000000002222\n\n\nTransaction successfully executed.\n[GAS]\n\n\"#]]);\n});\n\n// https://github.com/foundry-rs/foundry/issues/9541\nforgetest_async!(flaky_cast_run_impersonated_tx, |_prj, cmd| {\n    let (_api, handle) = anvil::spawn(\n        NodeConfig::test()\n            .with_auto_impersonate(true)\n            .with_eth_rpc_url(Some(\"https://sepolia.base.org\")),\n    )\n    .await;\n\n    let http_endpoint = handle.http_endpoint();\n\n    let provider = ProviderBuilder::new().connect_http(http_endpoint.parse().unwrap());\n\n    // send impersonated tx\n    let tx = TransactionRequest::default()\n        .with_from(address!(\"0x041563c07028Fc89106788185763Fc73028e8511\"))\n        .with_to(address!(\"0xF38aA5909D89F5d98fCeA857e708F6a6033f6CF8\"))\n        .with_input(\n            Bytes::from_str(\n                \"0x60fe47b1000000000000000000000000000000000000000000000000000000000000000c\",\n            )\n            .unwrap(),\n        );\n\n    let receipt = provider.send_transaction(tx).await.unwrap().get_receipt().await.unwrap();\n\n    assert!(receipt.status());\n\n    // run impersonated tx\n    cmd.cast_fuse()\n        .args([\"run\", &receipt.transaction_hash.to_string(), \"--rpc-url\", &http_endpoint])\n        .assert_success();\n});\n\n// <https://github.com/foundry-rs/foundry/issues/4776>\ncasttest!(flaky_fetch_src_blockscout, |_prj, cmd| {\n    let url = \"https://eth.blockscout.com/api\";\n\n    let weth = address!(\"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\");\n\n    cmd.args([\n        \"source\",\n        &weth.to_string(),\n        \"--chain-id\",\n        \"1\",\n        \"--explorer-api-url\",\n        url,\n        \"--flatten\",\n    ])\n    .assert_success()\n    .stdout_eq(str![[r#\"\n...\ncontract WETH9 {\n    string public name     = \"Wrapped Ether\";\n    string public symbol   = \"WETH\";\n    uint8  public decimals = 18;\n...\"#]]);\n});\n\ncasttest!(flaky_fetch_src_default, |_prj, cmd| {\n    let weth = address!(\"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\");\n    let etherscan_api_key = next_etherscan_api_key();\n\n    cmd.args([\"source\", &weth.to_string(), \"--flatten\", \"--etherscan-api-key\", &etherscan_api_key])\n        .assert_success()\n        .stdout_eq(str![[r#\"\n...\ncontract WETH9 {\n    string public name     = \"Wrapped Ether\";\n    string public symbol   = \"WETH\";\n    uint8  public decimals = 18;\n...\"#]]);\n});\n\n// <https://github.com/foundry-rs/foundry/issues/10553>\n// <https://basescan.org/tx/0x17b2de59ebd7dfd2452a3638a16737b6b65ae816c1c5571631dc0d80b63c41de>\ncasttest!(flaky_osaka_can_run_p256_precompile, |_prj, cmd| {\n    cmd.args([\n        \"run\",\n        \"0x17b2de59ebd7dfd2452a3638a16737b6b65ae816c1c5571631dc0d80b63c41de\",\n        \"--rpc-url\",\n        next_rpc_endpoint(NamedChain::Base).as_str(),\n        \"--quick\",\n        \"--evm-version\",\n        \"osaka\",\n    ])\n    .assert_success()\n    .stdout_eq(str![[r#\"\nTraces:\n  [91537] 0xc2FF493F28e894742b968A7DB5D3F21F0aD80C6c::execute(0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000a12384c5e52fd646e7bc7f6b3b33a605651f566e000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000170000000000000000000000000000000000000000000000000000000000000000000000000000000000000000833589fcd6edb6e08f4c7c32d4f71b54bda02913000000000000000000000000000000000000000000000000000000000000060f000000000000000000000000000000000000000000000000000000000000060f0000000000000000000000000000000000000000000000000000000000036cd000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000060f000000000000000000000000000000000000000000000000000000000000060f000000000000000000000000327a25ad5cfe5c4d4339c1a4267d4a83e8c93312000000000000000000000000000000000000000000000000000000000000034000000000000000000000000000000000000000000000000000000000000005a00000000000000000000000000b55b053230e4effb6609de652fca73fd1c2980400000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000221000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000006cdd519280ec730727f07aa36550bde31a1d5f3097818f3425c2f083ed33a91f080fa2afac0071f6e1af9a0e9c09b851bf01e68bc8a1c1f89f686c48205762f92500000000000000000000000000000000000000000000000000000000000000244242424242424242424242424242424242424242424242424242424242424242010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000827b226368616c6c656e6765223a224b51704d51446e7841757a726f68522d483878472d5a536b625249702d76515f5f5f4a714259357a655038222c2263726f73734f726967696e223a66616c73652c226f726967696e223a2268747470732f2f6974686163612e78797a222c2274797065223a22776562617574686e2e676574227d0000000000000000000000000000000000000000000000000000000000001bde17b8de18819c9eb86cefc3920ddb5d3d4254de276e3d6e18dd2b399f732b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000)\n    ├─ [2241] 0xA12384c5E52fD646E7BC7F6B3b33A605651F566E::fallback(00) [staticcall]\n    │   └─ ← [Return] 0x0000000000000000000000000b55b053230e4effb6609de652fca73fd1c29804\n    ├─ [9750] 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913::balanceOf(0xA12384c5E52fD646E7BC7F6B3b33A605651F566E) [staticcall]\n    │   ├─ [2553] 0x2Ce6311ddAE708829bc0784C967b7d77D19FD779::balanceOf(0xA12384c5E52fD646E7BC7F6B3b33A605651F566E) [delegatecall]\n    │   │   └─ ← [Return] 0x000000000000000000000000000000000000000000000000000000000000f3b9\n    │   └─ ← [Return] 0x000000000000000000000000000000000000000000000000000000000000f3b9\n    ├─ [65442] 0xc2FF493F28e894742b968A7DB5D3F21F0aD80C6c::fulfillBasicOrder_efficient_6GL6yc()\n    │   ├─ [25070] 0xA12384c5E52fD646E7BC7F6B3b33A605651F566E::unwrapAndValidateSignature(0x290a4c4039f102eceba2147e1fcc46f994a46d1229faf43ffff26a058e7378ff, 0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000006cdd519280ec730727f07aa36550bde31a1d5f3097818f3425c2f083ed33a91f080fa2afac0071f6e1af9a0e9c09b851bf01e68bc8a1c1f89f686c48205762f92500000000000000000000000000000000000000000000000000000000000000244242424242424242424242424242424242424242424242424242424242424242010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000827b226368616c6c656e6765223a224b51704d51446e7841757a726f68522d483878472d5a536b625249702d76515f5f5f4a714259357a655038222c2263726f73734f726967696e223a66616c73652c226f726967696e223a2268747470732f2f6974686163612e78797a222c2274797065223a22776562617574686e2e676574227d0000000000000000000000000000000000000000000000000000000000001bde17b8de18819c9eb86cefc3920ddb5d3d4254de276e3d6e18dd2b399f732b00) [staticcall]\n    │   │   ├─ [22067] 0x0B55b053230E4EFFb6609de652fCa73Fd1C29804::unwrapAndValidateSignature(0x290a4c4039f102eceba2147e1fcc46f994a46d1229faf43ffff26a058e7378ff, 0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000006cdd519280ec730727f07aa36550bde31a1d5f3097818f3425c2f083ed33a91f080fa2afac0071f6e1af9a0e9c09b851bf01e68bc8a1c1f89f686c48205762f92500000000000000000000000000000000000000000000000000000000000000244242424242424242424242424242424242424242424242424242424242424242010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000827b226368616c6c656e6765223a224b51704d51446e7841757a726f68522d483878472d5a536b625249702d76515f5f5f4a714259357a655038222c2263726f73734f726967696e223a66616c73652c226f726967696e223a2268747470732f2f6974686163612e78797a222c2274797065223a22776562617574686e2e676574227d0000000000000000000000000000000000000000000000000000000000001bde17b8de18819c9eb86cefc3920ddb5d3d4254de276e3d6e18dd2b399f732b00) [delegatecall]\n    │   │   │   ├─ [2369] 0xc2FF493F28e894742b968A7DB5D3F21F0aD80C6c::pauseFlag() [staticcall]\n    │   │   │   │   └─ ← [Return] 0x0000000000000000000000000000000000000000000000000000000000000000\n    │   │   │   ├─ [120] PRECOMPILES::sha256(0x7b226368616c6c656e6765223a224b51704d51446e7841757a726f68522d483878472d5a536b625249702d76515f5f5f4a714259357a655038222c2263726f73734f726967696e223a66616c73652c226f726967696e223a2268747470732f2f6974686163612e78797a222c2274797065223a22776562617574686e2e676574227d) [staticcall]\n    │   │   │   │   └─ ← [Return] 0xc13089327d3c20c0ce35f2f058c423de29977e6950e406c095e366a8fabd463f\n    │   │   │   ├─ [96] PRECOMPILES::sha256(0x424242424242424242424242424242424242424242424242424242424242424201000000c13089327d3c20c0ce35f2f058c423de29977e6950e406c095e366a8fabd463f) [staticcall]\n    │   │   │   │   └─ ← [Return] 0xc544bd9a4ea526dda3a008f43c21b6f0be3031b1ff71832b9876915dc91deea0\n    │   │   │   ├─ [6900] P256VERIFY::c544bd9a(4ea526dda3a008f43c21b6f0be3031b1ff71832b9876915dc91deea0dd519280ec730727f07aa36550bde31a1d5f3097818f3425c2f083ed33a91f080fa2afac0071f6e1af9a0e9c09b851bf01e68bc8a1c1f89f686c48205762f925bf54fa13f88658092efa36c51b1e3c4db31d3afb92812fb852dac7cf9614bc479bf5da7241d9c4ab1b431b57ec3369587b4c831d7a564438990da053708c3289) [staticcall]\n    │   │   │   │   └─ ← [Return] 0x0000000000000000000000000000000000000000000000000000000000000001\n    │   │   │   └─ ← [Return] 0x00000000000000000000000000000000000000000000000000000000000000011bde17b8de18819c9eb86cefc3920ddb5d3d4254de276e3d6e18dd2b399f732b\n    │   │   └─ ← [Return] 0x00000000000000000000000000000000000000000000000000000000000000011bde17b8de18819c9eb86cefc3920ddb5d3d4254de276e3d6e18dd2b399f732b\n    │   ├─ [5994] 0xA12384c5E52fD646E7BC7F6B3b33A605651F566E::checkAndIncrementNonce(23)\n    │   │   ├─ [5608] 0x0B55b053230E4EFFb6609de652fCa73Fd1C29804::checkAndIncrementNonce(23) [delegatecall]\n    │   │   │   └─ ← [Stop]\n    │   │   └─ ← [Return]\n    │   ├─ [3250] 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913::balanceOf(0x327a25aD5Cfe5c4D4339C1A4267D4a83E8c93312) [staticcall]\n    │   │   ├─ [2553] 0x2Ce6311ddAE708829bc0784C967b7d77D19FD779::balanceOf(0x327a25aD5Cfe5c4D4339C1A4267D4a83E8c93312) [delegatecall]\n    │   │   │   └─ ← [Return] 0x000000000000000000000000000000000000000000000000000000000000968b\n    │   │   └─ ← [Return] 0x000000000000000000000000000000000000000000000000000000000000968b\n    │   ├─ [16411] 0xA12384c5E52fD646E7BC7F6B3b33A605651F566E::pay(1551, 0x1bde17b8de18819c9eb86cefc3920ddb5d3d4254de276e3d6e18dd2b399f732b, 0x290a4c4039f102eceba2147e1fcc46f994a46d1229faf43ffff26a058e7378ff, 0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000a12384c5e52fd646e7bc7f6b3b33a605651f566e000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000170000000000000000000000000000000000000000000000000000000000000000000000000000000000000000833589fcd6edb6e08f4c7c32d4f71b54bda02913000000000000000000000000000000000000000000000000000000000000060f000000000000000000000000000000000000000000000000000000000000060f0000000000000000000000000000000000000000000000000000000000036cd000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000060f000000000000000000000000000000000000000000000000000000000000060f000000000000000000000000327a25ad5cfe5c4d4339c1a4267d4a83e8c93312000000000000000000000000000000000000000000000000000000000000034000000000000000000000000000000000000000000000000000000000000005a00000000000000000000000000b55b053230e4effb6609de652fca73fd1c2980400000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000221000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000006cdd519280ec730727f07aa36550bde31a1d5f3097818f3425c2f083ed33a91f080fa2afac0071f6e1af9a0e9c09b851bf01e68bc8a1c1f89f686c48205762f92500000000000000000000000000000000000000000000000000000000000000244242424242424242424242424242424242424242424242424242424242424242010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000827b226368616c6c656e6765223a224b51704d51446e7841757a726f68522d483878472d5a536b625249702d76515f5f5f4a714259357a655038222c2263726f73734f726967696e223a66616c73652c226f726967696e223a2268747470732f2f6974686163612e78797a222c2274797065223a22776562617574686e2e676574227d0000000000000000000000000000000000000000000000000000000000001bde17b8de18819c9eb86cefc3920ddb5d3d4254de276e3d6e18dd2b399f732b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000)\n    │   │   ├─ [15711] 0x0B55b053230E4EFFb6609de652fCa73Fd1C29804::pay(1551, 0x1bde17b8de18819c9eb86cefc3920ddb5d3d4254de276e3d6e18dd2b399f732b, 0x290a4c4039f102eceba2147e1fcc46f994a46d1229faf43ffff26a058e7378ff, 0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000a12384c5e52fd646e7bc7f6b3b33a605651f566e000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000170000000000000000000000000000000000000000000000000000000000000000000000000000000000000000833589fcd6edb6e08f4c7c32d4f71b54bda02913000000000000000000000000000000000000000000000000000000000000060f000000000000000000000000000000000000000000000000000000000000060f0000000000000000000000000000000000000000000000000000000000036cd000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000060f000000000000000000000000000000000000000000000000000000000000060f000000000000000000000000327a25ad5cfe5c4d4339c1a4267d4a83e8c93312000000000000000000000000000000000000000000000000000000000000034000000000000000000000000000000000000000000000000000000000000005a00000000000000000000000000b55b053230e4effb6609de652fca73fd1c2980400000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000221000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000006cdd519280ec730727f07aa36550bde31a1d5f3097818f3425c2f083ed33a91f080fa2afac0071f6e1af9a0e9c09b851bf01e68bc8a1c1f89f686c48205762f92500000000000000000000000000000000000000000000000000000000000000244242424242424242424242424242424242424242424242424242424242424242010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000827b226368616c6c656e6765223a224b51704d51446e7841757a726f68522d483878472d5a536b625249702d76515f5f5f4a714259357a655038222c2263726f73734f726967696e223a66616c73652c226f726967696e223a2268747470732f2f6974686163612e78797a222c2274797065223a22776562617574686e2e676574227d0000000000000000000000000000000000000000000000000000000000001bde17b8de18819c9eb86cefc3920ddb5d3d4254de276e3d6e18dd2b399f732b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000) [delegatecall]\n    │   │   │   ├─ [12963] 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913::transfer(0x327a25aD5Cfe5c4D4339C1A4267D4a83E8c93312, 1551)\n    │   │   │   │   ├─ [12263] 0x2Ce6311ddAE708829bc0784C967b7d77D19FD779::transfer(0x327a25aD5Cfe5c4D4339C1A4267D4a83E8c93312, 1551) [delegatecall]\n    │   │   │   │   │   ├─ emit Transfer(param0: 0xA12384c5E52fD646E7BC7F6B3b33A605651F566E, param1: 0x327a25aD5Cfe5c4D4339C1A4267D4a83E8c93312, param2: 1551)\n    │   │   │   │   │   └─ ← [Return] 0x0000000000000000000000000000000000000000000000000000000000000001\n    │   │   │   │   └─ ← [Return] 0x0000000000000000000000000000000000000000000000000000000000000001\n    │   │   │   └─ ← [Stop]\n    │   │   └─ ← [Return]\n    │   ├─ [1250] 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913::balanceOf(0x327a25aD5Cfe5c4D4339C1A4267D4a83E8c93312) [staticcall]\n    │   │   ├─ [553] 0x2Ce6311ddAE708829bc0784C967b7d77D19FD779::balanceOf(0x327a25aD5Cfe5c4D4339C1A4267D4a83E8c93312) [delegatecall]\n    │   │   │   └─ ← [Return] 0x0000000000000000000000000000000000000000000000000000000000009c9a\n    │   │   └─ ← [Return] 0x0000000000000000000000000000000000000000000000000000000000009c9a\n    │   ├─ [5675] 0xc2FF493F28e894742b968A7DB5D3F21F0aD80C6c::multicallN2M_001Taw5z()\n    │   │   ├─ [4148] 0xA12384c5E52fD646E7BC7F6B3b33A605651F566E::execute(0x0100000000007821000100000000000000000000000000000000000000000000, 0x0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000201bde17b8de18819c9eb86cefc3920ddb5d3d4254de276e3d6e18dd2b399f732b)\n    │   │   │   ├─ [3693] 0x0B55b053230E4EFFb6609de652fCa73Fd1C29804::execute(0x0100000000007821000100000000000000000000000000000000000000000000, 0x0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000201bde17b8de18819c9eb86cefc3920ddb5d3d4254de276e3d6e18dd2b399f732b) [delegatecall]\n    │   │   │   │   ├─ [435] 0xA12384c5E52fD646E7BC7F6B3b33A605651F566E::fallback()\n    │   │   │   │   │   ├─ [55] 0x0B55b053230E4EFFb6609de652fCa73Fd1C29804::fallback() [delegatecall]\n    │   │   │   │   │   │   └─ ← [Stop]\n    │   │   │   │   │   └─ ← [Return]\n    │   │   │   │   └─ ← [Stop]\n    │   │   │   └─ ← [Return]\n    │   │   └─ ← [Return] 0x0000000000000000000000000000000000000000000000000000000000000000\n    │   └─ ← [Stop]\n    ├─  emit topic 0: 0x31e2fdd22f7eeca688d70008a7bee8e41aa5640885c2bc592419ae8d09d889f1\n    │        topic 1: 0x000000000000000000000000a12384c5e52fd646e7bc7f6b3b33a605651f566e\n    │        topic 2: 0x0000000000000000000000000000000000000000000000000000000000000017\n    │           data: 0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000\n    └─ ← [Return] 0x0000000000000000000000000000000000000000000000000000000000000000\n\n\nTransaction successfully executed.\n[GAS]\n\n\"#]]);\n});\n\n// tests cast send gas estimate execution failure message contains decoded custom error\n// <https://github.com/foundry-rs/foundry/issues/9789>\nforgetest_async!(cast_send_estimate_gas_error, |prj, cmd| {\n    let (_, handle) = anvil::spawn(NodeConfig::test()).await;\n\n    foundry_test_utils::util::initialize(prj.root());\n    prj.add_source(\n        \"SimpleStorage\",\n        r#\"\ncontract SimpleStorage {\n    uint256 private storedValue;\n    error AddressInsufficientBalance(address account, uint256 newValue);\n    function setValue(uint256 _newValue) public {\n        if (_newValue > 100) {\n            revert AddressInsufficientBalance(msg.sender, _newValue);\n        }\n        storedValue = _newValue;\n    }\n}\n   \"#,\n    );\n    prj.add_script(\n        \"SimpleStorageScript\",\n        r#\"\nimport \"forge-std/Script.sol\";\nimport {SimpleStorage} from \"../src/SimpleStorage.sol\";\ncontract SimpleStorageScript is Script {\n    function run() public {\n        vm.startBroadcast();\n        new SimpleStorage();\n        vm.stopBroadcast();\n    }\n}\n   \"#,\n    );\n\n    cmd.args([\n        \"script\",\n        \"--private-key\",\n        \"0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80\",\n        \"--rpc-url\",\n        &handle.http_endpoint(),\n        \"--broadcast\",\n        \"SimpleStorageScript\",\n    ])\n    .assert_success();\n\n    // Cache project selectors.\n    cmd.forge_fuse().set_current_dir(prj.root());\n    cmd.forge_fuse().args([\"selectors\", \"cache\"]).assert_success();\n\n    // Assert cast send can decode custom error on estimate gas execution failure.\n    cmd.cast_fuse()\n        .args([\n            \"send\",\n            \"0x5FbDB2315678afecb367f032d93F642f64180aa3\",\n            \"setValue(uint256)\",\n            \"1000\",\n            \"--private-key\",\n            \"0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80\",\n            \"--rpc-url\",\n            &handle.http_endpoint(),\n        ])\n        .assert_failure().stderr_eq(str![[r#\"\nError: Failed to estimate gas: server returned an error response: error code 3: execution reverted: custom error 0x6786ad34: 000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb9226600000000000000000000000000000000000000000000000000000000000003e8, data: \"0x6786ad34000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb9226600000000000000000000000000000000000000000000000000000000000003e8\"[..]\n\n\"#]]);\n});\n\n// <https://basescan.org/block/30558838>\ncasttest!(estimate_base_da, |_prj, cmd| {\n    cmd.args([\"da-estimate\", \"30558838\", \"-r\", \"https://mainnet.base.org/\"])\n        .assert_success()\n        .stdout_eq(str![[r#\"\nEstimated data availability size for block 30558838 with 225 transactions: 52916546100\n\n\"#]]);\n});\n\n// <https://github.com/foundry-rs/foundry/issues/10705>\ncasttest!(cast_call_return_array_of_tuples, |_prj, cmd| {\n    cmd.args([\n        \"call\",\n        \"0x198FC70Dfe05E755C81e54bd67Bff3F729344B9b\",\n        \"facets() returns ((address,bytes4[])[])\",\n        \"--rpc-url\",\n        \"https://rpc.viction.xyz\",\n    ])\n    .assert_success()\n    .stdout_eq(str![[r#\"\n[[..]]\n\n\"#]]);\n});\n\n// <https://github.com/foundry-rs/foundry/issues/7541>\ncasttest!(cast_call_on_contract_with_no_code_prints_warning, |_prj, cmd| {\n    let eth_rpc_url = next_http_rpc_endpoint();\n    cmd.args([\n        \"call\",\n        \"0x0000000000000000000000000000000000000000\",\n        \"--rpc-url\",\n        eth_rpc_url.as_str(),\n    ])\n    .assert_success()\n    .stderr_eq(str![[r#\"\nWarning: Contract code is empty\n\n\"#]])\n    .stdout_eq(str![[r#\"\n0x\n\n\"#]]);\n});\n\n// <https://github.com/foundry-rs/foundry/issues/10740>\ncasttest!(tx_raw_opstack_deposit, |_prj, cmd| {\n    cmd.args([\n        \"tx\",\n        \"0xf403cba612d1c01c027455c0d97427ccd5f7f99aac30017e065f81d1e30244ea\",\n        \"--raw\",\n        \"-n\",\n        \"optimism\",\n        \"--rpc-url\",\n        \"https://sepolia.base.org\",\n    ]).assert_success()\n            .stdout_eq(str![[r#\"\n0x7ef90207a0cbde10ec697aff886f95d2514bab434e455620627b9bb8ba33baaaa4d537d62794d45955f4de64f1840e5686e64278da901e263031944200000000000000000000000000000000000007872386f26fc10000872386f26fc1000083096c4980b901a4d764ad0b0001000000000000000000000000000000000000000000000000000000065132000000000000000000000000fd0bf71f60660e2f608ed56e1659c450eb1131200000000000000000000000004200000000000000000000000000000000000010000000000000000000000000000000000000000000000000002386f26fc1000000000000000000000000000000000000000000000000000000000000000493e000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000a41635f5fd000000000000000000000000ca11bde05977b3631167028862be2a173976ca110000000000000000000000005703b26fe5a7be820db1bf34c901a79da1a46ba4000000000000000000000000000000000000000000000000002386f26fc100000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n\n\"#]]);\n});\n\ncasttest!(tx_raw_tempo, |_prj, cmd| {\n    cmd.args([\n        \"tx\",\n        \"0xa24c6bbeea629a80be79e970a9749d0cbc6ee31625a0b75f585c173ab15a18ec\",\n        \"--raw\",\n        \"-n\",\n        \"tempo\",\n        \"--rpc-url\",\n        \"https://rpc.moderato.tempo.xyz\",\n    ]).assert_success()\n            .stdout_eq(str![[r#\"\n0x76f8cf82a5bf1485059682f018830494e5f85ef85c9420c0000000000000000000007d9cc57068833ea780b84440c10f190000000000000000000000008a871f4189067637cfc4cc1500abd6244bf1df740000000000000000000000000000000000000000000000000000000005f5e100c08082057e80809420c000000000000000000000000000000000000080c0b841eb100c4cbd96903bf9e97968c0982670bb90fc191ee4544c7ff32d44e901dbea3f6fbdd58255051135c2fe1aa81583a270d96009cbe375f4605ef15971273a4f1b\n\n\"#]]);\n});\n\n// Test that cast send --create works correctly with constructor arguments\n// <https://github.com/foundry-rs/foundry/issues/10947>\nforgetest_async!(cast_send_create_with_constructor_args, |prj, cmd| {\n    let (_api, handle) = anvil::spawn(NodeConfig::test()).await;\n    let endpoint = handle.http_endpoint();\n\n    // Deploy a simple contract with constructor arguments\n    // Contract source that takes constructor args\n    prj.add_source(\n        \"ConstructorContract\",\n        r#\"\ncontract ConstructorContract {\n    uint256 public value;\n    string public name;\n\n    constructor(uint256 _value, string memory _name) {\n        value = _value;\n        name = _name;\n    }\n\n    function getValue() public view returns (uint256) {\n        return value;\n    }\n}\n\"#,\n    );\n\n    // Compile to get bytecode\n    cmd.forge_fuse().args([\"build\"]).assert_success();\n\n    // Get the compiled bytecode\n    let bytecode_path = prj.root().join(\"out/ConstructorContract.sol/ConstructorContract.json\");\n    let contract_json = std::fs::read_to_string(bytecode_path).unwrap();\n    let contract_data: serde_json::Value = serde_json::from_str(&contract_json).unwrap();\n    let bytecode = contract_data[\"bytecode\"][\"object\"].as_str().unwrap();\n\n    // Use cast send --create with constructor arguments\n    let output = cmd\n        .cast_fuse()\n        .args([\n            \"send\",\n            \"--private-key\",\n            \"0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80\",\n            \"--rpc-url\",\n            &endpoint,\n            \"--create\",\n            bytecode,\n            \"constructor(uint256,string)\",\n            \"42\",\n            \"TestContract\",\n        ])\n        .assert_success()\n        .get_output()\n        .stdout_lossy();\n\n    // Extract the deployed contract address from output\n    let lines: Vec<&str> = output.lines().collect();\n    let mut address = None;\n    for line in lines {\n        if line.contains(\"contractAddress\") {\n            let parts: Vec<&str> = line.split_whitespace().collect();\n            address = Some(parts[1]);\n            break;\n        }\n    }\n    let address = address.expect(\"Contract address not found in output\");\n\n    // Verify the contract was deployed correctly by calling getValue()\n    let value_output = cmd\n        .cast_fuse()\n        .args([\"call\", address, \"getValue()\", \"--rpc-url\", &endpoint])\n        .assert_success()\n        .get_output()\n        .stdout_lossy();\n\n    // The value should be 42 (0x2a in hex)\n    assert!(\n        value_output.contains(\"0x000000000000000000000000000000000000000000000000000000000000002a\")\n    );\n});\n\n// Test that cast estimate --create works correctly with constructor arguments\n// <https://github.com/foundry-rs/foundry/issues/10947>\ncasttest!(cast_estimate_create_with_constructor_args, |prj, cmd| {\n    let eth_rpc_url = next_http_rpc_endpoint();\n\n    // Add a simple contract with constructor arguments\n    prj.add_source(\n        \"EstimateContract\",\n        r#\"\ncontract EstimateContract {\n    uint256 public value;\n    string public name;\n\n    constructor(uint256 _value, string memory _name) {\n        value = _value;\n        name = _name;\n    }\n}\n\"#,\n    );\n\n    // Compile to get bytecode\n    cmd.forge_fuse().args([\"build\"]).assert_success();\n\n    // Get the compiled bytecode\n    let bytecode_path = prj.root().join(\"out/EstimateContract.sol/EstimateContract.json\");\n    let contract_json = std::fs::read_to_string(bytecode_path).unwrap();\n    let contract_data: serde_json::Value = serde_json::from_str(&contract_json).unwrap();\n    let bytecode = contract_data[\"bytecode\"][\"object\"].as_str().unwrap();\n\n    let output = cmd\n        .cast_fuse()\n        .args([\n            \"estimate\",\n            \"--rpc-url\",\n            eth_rpc_url.as_str(),\n            \"--create\",\n            bytecode,\n            \"constructor(uint256,string)\",\n            \"100\",\n            \"TestContract\",\n        ])\n        .assert_success()\n        .get_output()\n        .stdout_lossy();\n\n    // Parse the gas estimate\n    let gas_estimate = output.trim().parse::<u64>().expect(\"Failed to parse gas estimate\");\n\n    // Gas estimate should be positive and reasonable for contract deployment\n    assert!(gas_estimate > 50000, \"Gas estimate too low for contract deployment\");\n    assert!(gas_estimate < 5000000, \"Gas estimate unreasonably high\");\n});\n\n// Test edge case: empty constructor arguments\n// <https://github.com/foundry-rs/foundry/issues/10947>\nforgetest_async!(cast_send_create_empty_constructor, |prj, cmd| {\n    let (_api, handle) = anvil::spawn(NodeConfig::test()).await;\n    let endpoint = handle.http_endpoint();\n\n    // Simple contract with no constructor arguments\n    prj.add_source(\n        \"SimpleContract\",\n        r#\"\ncontract SimpleContract {\n    uint256 public constant VALUE = 42;\n}\n\"#,\n    );\n\n    // Compile\n    cmd.forge_fuse().args([\"build\"]).assert_success();\n\n    // Get bytecode\n    let bytecode_path = prj.root().join(\"out/SimpleContract.sol/SimpleContract.json\");\n    let contract_json = std::fs::read_to_string(bytecode_path).unwrap();\n    let contract_data: serde_json::Value = serde_json::from_str(&contract_json).unwrap();\n    let bytecode = contract_data[\"bytecode\"][\"object\"].as_str().unwrap();\n\n    // Deploy with empty constructor\n    let output = cmd\n        .cast_fuse()\n        .args([\n            \"send\",\n            \"--private-key\",\n            \"0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80\",\n            \"--rpc-url\",\n            &endpoint,\n            \"--create\",\n            bytecode,\n            \"constructor()\",\n        ])\n        .assert_success()\n        .get_output()\n        .stdout_lossy();\n\n    // Verify deployment succeeded\n    assert!(output.contains(\"contractAddress\"));\n});\n\n// Test complex constructor arguments (multiple types)\n// <https://github.com/foundry-rs/foundry/issues/10947>\nforgetest_async!(cast_send_create_complex_constructor, |prj, cmd| {\n    let (_api, handle) = anvil::spawn(NodeConfig::test()).await;\n    let endpoint = handle.http_endpoint();\n\n    // Contract with complex constructor\n    prj.add_source(\n        \"ComplexContract\",\n        r#\"\ncontract ComplexContract {\n    address public owner;\n    uint256[] public values;\n    bool public active;\n\n    constructor(address _owner, uint256[] memory _values, bool _active) {\n        owner = _owner;\n        values = _values;\n        active = _active;\n    }\n\n    function getValuesLength() public view returns (uint256) {\n        return values.length;\n    }\n}\n\"#,\n    );\n\n    // Compile\n    cmd.forge_fuse().args([\"build\"]).assert_success();\n\n    // Get bytecode\n    let bytecode_path = prj.root().join(\"out/ComplexContract.sol/ComplexContract.json\");\n    let contract_json = std::fs::read_to_string(bytecode_path).unwrap();\n    let contract_data: serde_json::Value = serde_json::from_str(&contract_json).unwrap();\n    let bytecode = contract_data[\"bytecode\"][\"object\"].as_str().unwrap();\n\n    // Deploy with complex arguments\n    let output = cmd\n        .cast_fuse()\n        .args([\n            \"send\",\n            \"--private-key\",\n            \"0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80\",\n            \"--rpc-url\",\n            &endpoint,\n            \"--create\",\n            bytecode,\n            \"constructor(address,uint256[],bool)\",\n            \"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266\",\n            \"[1,2,3,4,5]\",\n            \"true\",\n        ])\n        .assert_success()\n        .get_output()\n        .stdout_lossy();\n\n    // Extract deployed address\n    let lines: Vec<&str> = output.lines().collect();\n    let mut address = None;\n    for line in lines {\n        if line.contains(\"contractAddress\") {\n            let parts: Vec<&str> = line.split_whitespace().collect();\n            if parts.len() >= 2 {\n                address = Some(parts[1]);\n                break;\n            }\n        }\n    }\n    let address = address.expect(\"Contract address not found in output\");\n\n    // Verify the array length was set correctly\n    let length_output = cmd\n        .cast_fuse()\n        .args([\"call\", address, \"getValuesLength()\", \"--rpc-url\", &endpoint])\n        .assert_success()\n        .get_output()\n        .stdout_lossy();\n\n    // Should return 5 (0x5 in hex)\n    assert!(\n        length_output\n            .contains(\"0x0000000000000000000000000000000000000000000000000000000000000005\")\n    );\n});\n\ncasttest!(recover_authority, |_prj, cmd| {\n    let auth = r#\"{\n        \"chainId\": \"0x1\",\n        \"address\": \"0xb684710e6d5914ad6e64493de2a3c424cc43e970\",\n        \"nonce\": \"0x3dc1\",\n        \"yParity\": \"0x1\",\n        \"r\": \"0x2f15ba55009fcd3682cd0f9c9645dd94e616f9a969ba3f1a5a2d871f9fe0f2b4\",\n        \"s\": \"0x53c332a83312d0b17dd4c16eeb15b1ff5223398b14e0a55c70762e8f3972b7a5\"\n    }\"#;\n    cmd.args([\"recover-authority\", auth]).assert_success().stdout_eq(str![[r#\"\n0x17816E9A858b161c3E37016D139cf618056CaCD4\n\n\"#]]);\n});\n\n// <https://github.com/foundry-rs/foundry/issues/10945>\n// tests `cast code --disassemble`\ncasttest!(can_disassemble_contract_code, |_prj, cmd| {\n    let rpc = next_rpc_endpoint(NamedChain::Mainnet);\n    cmd.args([\n        \"code\",\n        \"--disassemble\",\n        \"--rpc-url\",\n        rpc.as_str(),\n        \"0x1F573D6Fb3F13d689FF844B4cE37794d79a7FF1C\",\n    ])\n    .assert_success()\n    .stdout_eq(str![[r#\"\n00000000: PUSH1 0x60\n00000002: PUSH1 0x40\n00000004: MSTORE\n00000005: CALLDATASIZE\n00000006: ISZERO\n00000007: PUSH2 0x010f\n0000000a: JUMPI\n0000000b: PUSH4 0xffffffff\n00000010: PUSH29 0x0100000000000000000000000000000000000000000000000000000000\n0000002e: PUSH1 0x00\n...\n\"#]]);\n});\n\n// tests that cast call properly applies state diff override\n// <https://github.com/foundry-rs/foundry/issues/10930>\ncasttest!(cast_call_can_override_state_diff, |_prj, cmd| {\n    let rpc = next_rpc_endpoint(NamedChain::Sepolia);\n    cmd.args([\n        \"call\",\n        \"--rpc-url\",\n        rpc.as_str(),\n        \"--data\",\n        \"0x\",\n        \"0x1EA77b250eF79e917A5A637D5BB82D0980653F1B\",\n        \"--override-state-diff\",\n        \"0x1EA77b250eF79e917A5A637D5BB82D0980653F1B:1:1\",\n    ])\n    .assert_success()\n    .stdout_eq(str![[r#\"\n0x1337\n\n\"#]]);\n    cmd.args([\"--trace\"]).assert_success().stdout_eq(str![[r#\"\nTraces:\n  [7281] 0x1EA77b250eF79e917A5A637D5BB82D0980653F1B::fallback()\n    ├─ [2275] 0xe537cb8a46Bd179c0C36aB7E3Fdecd759C8B80fc::fallback() [delegatecall]\n    │   └─ ← [Return] 0x1337\n    └─ ← [Return] 0x1337\n\n\nTransaction successfully executed.\n[GAS]\n\n\"#]]);\n});\n\n// Tests for negative number argument parsing\n// Ensures that negative numbers in function arguments are properly parsed\n// instead of being treated as command flags\n\n// Test that cast call accepts negative numbers as function arguments\ncasttest!(cast_call_negative_numbers, |_prj, cmd| {\n    let rpc = next_rpc_endpoint(NamedChain::Sepolia);\n    // Test with negative int parameter - should not treat -456789 as a flag\n    cmd.args([\n        \"call\",\n        \"0xAbCdEf1234567890aBcDeF1234567890aBcDeF12\",\n        \"processValue(int128)\",\n        \"-456789\",\n        \"--rpc-url\",\n        rpc.as_str(),\n    ])\n    .assert_success();\n});\n\n// Test negative numbers with multiple parameters\ncasttest!(cast_call_multiple_negative_numbers, |_prj, cmd| {\n    let rpc = next_rpc_endpoint(NamedChain::Sepolia);\n    cmd.args([\n        \"call\",\n        \"--rpc-url\",\n        rpc.as_str(),\n        \"0xDeaDBeeFcAfEbAbEfAcEfEeDcBaDbEeFcAfEbAbE\",\n        \"calculateDelta(int64,int32,uint16)\",\n        \"-987654321\",\n        \"-42\",\n        \"65535\",\n    ])\n    .assert_success();\n});\n\n// Test negative numbers mixed with flags\ncasttest!(cast_call_negative_with_flags, |_prj, cmd| {\n    let rpc = next_rpc_endpoint(NamedChain::Sepolia);\n    cmd.args([\n        \"call\",\n        \"--trace\", // flag before\n        \"0x9876543210FeDcBa9876543210FeDcBa98765432\",\n        \"updateBalance(int256)\",\n        \"-777888\",\n        \"--rpc-url\",\n        rpc.as_str(), // flag after\n    ])\n    .assert_success();\n});\n\n// Test that actual invalid flags are still caught\ncasttest!(cast_call_invalid_flag_still_caught, |_prj, cmd| {\n    cmd.args([\n        \"call\",\n        \"--invalid-flag\", // This should be caught as invalid\n        \"0x5555555555555555555555555555555555555555\",\n    ])\n    .assert_failure()\n    .stderr_eq(str![[r#\"\nerror: unexpected argument '--invalid-flag' found\n\n  tip: to pass '--invalid-flag' as a value, use '-- --invalid-flag'\n\nUsage: cast[..] call [OPTIONS] [TO] [SIG] [ARGS]... [COMMAND]\n\nFor more information, try '--help'.\n\n\"#]]);\n});\n\n// Test cast estimate with negative numbers\ncasttest!(cast_estimate_negative_numbers, |_prj, cmd| {\n    let rpc = next_rpc_endpoint(NamedChain::Sepolia);\n    cmd.args([\n        \"estimate\",\n        \"0xBbBbBbBbBbBbBbBbBbBbBbBbBbBbBbBbBbBbBbBb\",\n        \"rebalance(int64)\",\n        \"-8888\",\n        \"--rpc-url\",\n        rpc.as_str(),\n    ])\n    .assert_success();\n});\n\n// Test cast mktx with negative numbers\ncasttest!(cast_mktx_negative_numbers, |_prj, cmd| {\n    let rpc = next_rpc_endpoint(NamedChain::Sepolia);\n    cmd.args([\n        \"mktx\",\n        \"0x1111111111111111111111111111111111111111\",\n        \"settleDebt(int256)\",\n        \"-15000\",\n        \"--private-key\",\n        \"0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80\", // anvil wallet #0\n        \"--rpc-url\",\n        rpc.as_str(),\n        \"--gas-limit\",\n        \"100000\",\n    ])\n    .assert_success();\n});\n\n// Test cast mktx with EIP-4844 blob transaction (legacy format)\ncasttest!(cast_mktx_eip4844_blob, |prj, cmd| {\n    // Create a temporary blob data file\n    let blob_data = b\"dummy blob data for testing\";\n    let blob_path = prj.root().join(\"blob_data.bin\");\n    fs::write(&blob_path, blob_data).unwrap();\n\n    cmd.args([\n        \"mktx\",\n        \"--private-key\",\n        \"0x0000000000000000000000000000000000000000000000000000000000000001\",\n        \"--chain\",\n        \"1\",\n        \"--nonce\",\n        \"0\",\n        \"--gas-limit\",\n        \"100000\",\n        \"--gas-price\",\n        \"10000000000\",\n        \"--priority-gas-price\",\n        \"1000000000\",\n        \"--blob\",\n        \"--eip4844\",\n        \"--blob-gas-price\",\n        \"1000000\",\n        \"--path\",\n        blob_path.to_str().unwrap(),\n        \"0x0000000000000000000000000000000000000001\",\n    ])\n    .assert_success();\n});\n\n// Test cast mktx with EIP-7594 blob transaction (default format)\ncasttest!(cast_mktx_eip7594_blob, |prj, cmd| {\n    // Create a temporary blob data file\n    let blob_data = b\"dummy peerdas blob data for testing\";\n    let blob_path = prj.root().join(\"peerdas_blob_data.bin\");\n    fs::write(&blob_path, blob_data).unwrap();\n\n    cmd.args([\n        \"mktx\",\n        \"--private-key\",\n        \"0x0000000000000000000000000000000000000000000000000000000000000001\",\n        \"--chain\",\n        \"1\",\n        \"--nonce\",\n        \"0\",\n        \"--gas-limit\",\n        \"100000\",\n        \"--gas-price\",\n        \"10000000000\",\n        \"--priority-gas-price\",\n        \"1000000000\",\n        \"--blob\",\n        \"--blob-gas-price\",\n        \"1000000\",\n        \"--path\",\n        blob_path.to_str().unwrap(),\n        \"0x0000000000000000000000000000000000000001\",\n    ])\n    .assert_success();\n});\n\n// Test cast access-list with negative numbers\ncasttest!(cast_access_list_negative_numbers, |_prj, cmd| {\n    let rpc = next_rpc_endpoint(NamedChain::Sepolia);\n    cmd.args([\n        \"access-list\",\n        \"0x9999999999999999999999999999999999999999\",\n        \"adjustPosition(int128)\",\n        \"-33333\",\n        \"--gas-limit\",\n        \"1000000\",\n        \"--rpc-url\",\n        rpc.as_str(),\n    ])\n    .assert_success();\n});\n\n// tests that cast call properly applies multiple state diff overrides\n// <https://github.com/foundry-rs/foundry/issues/11551>\ncasttest!(cast_call_can_override_several_state_diff, |_prj, cmd| {\n    let rpc = next_http_archive_rpc_url();\n    cmd.args([\n        \"call\",\n        \"--trace\",\n        \"--from\",\n        \"0xf6F444fD3B0088c1375671c05A7513661beFa4e6\",\n        \"0x5EA1d9A6dDC3A0329378a327746D71A2019eC332\",\n        \"--rpc-url\",\n        rpc.as_str(),\n        \"--block\",\n        \"23290753\",\n        \"--data\",\n        \"0xe75235b8\",\n        \"--override-state-diff\",\n        \"0x5EA1d9A6dDC3A0329378a327746D71A2019eC332:0xf0af0268363540b847b4c07f2f9a0401c607c1b11ebca511724a71755dfd4137:1,0x5EA1d9A6dDC3A0329378a327746D71A2019eC332:4:1,0x5EA1d9A6dDC3A0329378a327746D71A2019eC332:0x4a204f620c8c5ccdca3fd54d003badd85ba500436a431f0cbda4f558c93c34c8:0,0x5EA1d9A6dDC3A0329378a327746D71A2019eC332:0xb104e0b93118902c651344349b610029d694cfdec91c589c91ebafbcd0289947:0\",\n    ])\n    .assert_success()\n    .stdout_eq(str![[r#\"\n...\n  [..] 0x5EA1d9A6dDC3A0329378a327746D71A2019eC332::getThreshold()\n...\n\n\"#]]);\n\n    cmd.cast_fuse().args([\n        \"call\",\n        \"--trace\",\n        \"--from\",\n        \"0x2066901073a33ba2500274704aB04763875cF210\",\n        \"0x5EA1d9A6dDC3A0329378a327746D71A2019eC332\",\n        \"--rpc-url\",\n        rpc.as_str(),\n        \"--block\",\n        \"23290753\",\n        \"--data\",\n        \"0x2f54bf6e0000000000000000000000002066901073a33ba2500274704ab04763875cf210\",\n        \"--override-state-diff\",\n        \"0x5EA1d9A6dDC3A0329378a327746D71A2019eC332:0xf0af0268363540b847b4c07f2f9a0401c607c1b11ebca511724a71755dfd4137:1,0x5EA1d9A6dDC3A0329378a327746D71A2019eC332:4:1,0x5EA1d9A6dDC3A0329378a327746D71A2019eC332:0x4a204f620c8c5ccdca3fd54d003badd85ba500436a431f0cbda4f558c93c34c8:0,0x5EA1d9A6dDC3A0329378a327746D71A2019eC332:0xb104e0b93118902c651344349b610029d694cfdec91c589c91ebafbcd0289947:0\",\n    ])\n    .assert_success()\n    .stdout_eq(str![[r#\"\n...\n  [..] 0x5EA1d9A6dDC3A0329378a327746D71A2019eC332::isOwner(0x2066901073a33ba2500274704aB04763875cF210)\n...\n\"#]]);\n});\n\ncasttest!(correct_json_serialization, |_prj, cmd| {\n    let rpc = next_http_archive_rpc_url();\n    // cast calldata \"decimals()\"\n    let calldata = \"0x313ce567\";\n    let tokens = [\n        \"0xdac17f958d2ee523a2206206994597c13d831ec7\", // USDT\n        \"0x6b175474e89094c44da98b954eedeac495271d0f\", // DAI\n        \"0x6b175474e89094c44da98b954eedeac495271d0f\", // WETH\n    ];\n    let calldata_args = format!(\n        \"[{}]\",\n        tokens\n            .iter()\n            .map(|token| format!(\"({token},false,{calldata})\"))\n            .collect::<Vec<_>>()\n            .join(\",\")\n    );\n    let args = vec![\n        \"call\",\n        \"--json\",\n        \"--rpc-url\",\n        rpc.as_str(),\n        \"0xcA11bde05977b3631167028862bE2a173976CA11\",\n        \"aggregate3((address,bool,bytes)[])((bool,bytes)[])\",\n        &calldata_args,\n    ];\n    let expected_output = json!([[\n        [true, \"0x0000000000000000000000000000000000000000000000000000000000000006\"],\n        [true, \"0x0000000000000000000000000000000000000000000000000000000000000012\"],\n        [true, \"0x0000000000000000000000000000000000000000000000000000000000000012\"]\n    ]]);\n    let decoded: serde_json::Value =\n        serde_json::from_slice(&cmd.args(args).assert_success().get_output().stdout)\n            .expect(\"not valid json\");\n    assert_eq!(decoded, expected_output);\n});\n\n// Test cast abi-encode-event with indexed parameters\ncasttest!(abi_encode_event_indexed, |_prj, cmd| {\n    cmd.args([\n        \"abi-encode-event\",\n        \"Transfer(address indexed from, address indexed to, uint256 value)\",\n        \"0x1234567890123456789012345678901234567890\",\n        \"0xabcdefabcdefabcdefabcdefabcdefabcdefabcd\",\n        \"1000\",\n    ])\n    .assert_success()\n    .stdout_eq(str![[r#\"\n[topic0]: 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef\n[topic1]: 0x0000000000000000000000001234567890123456789012345678901234567890\n[topic2]: 0x000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd\n[data]: 0x00000000000000000000000000000000000000000000000000000000000003e8\n\n\"#]]);\n});\n\n// Test cast abi-encode-event with no indexed parameters\ncasttest!(abi_encode_event_no_indexed, |_prj, cmd| {\n    cmd.args([\n        \"abi-encode-event\",\n        \"Approval(address owner, address spender, uint256 value)\",\n        \"0x1234567890123456789012345678901234567890\",\n        \"0xabcdefabcdefabcdefabcdefabcdefabcdefabcd\",\n        \"2000\"\n    ])\n    .assert_success()\n    .stdout_eq(str![[r#\"\n[topic0]: 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925\n[data]: 0x0000000000000000000000001234567890123456789012345678901234567890000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd00000000000000000000000000000000000000000000000000000000000007d0\n\n\"#]]);\n});\n\n// Test cast abi-encode-event with dynamic indexed parameter (string)\ncasttest!(abi_encode_event_dynamic_indexed, |_prj, cmd| {\n    cmd.args([\"abi-encode-event\", \"Log(string indexed message, uint256 data)\", \"hello\", \"42\"])\n        .assert_success()\n        .stdout_eq(str![[r#\"\n[topic0]: 0xdd970dd9b5bfe707922155b058a407655cb18288b807e2216442bca8ad83d6b5\n[topic1]: 0x984002fcc0ca639f96622add24c2edd2fe72c65e71ca3faa243e091e0bc7cdab\n[data]: 0x000000000000000000000000000000000000000000000000000000000000002a\n\n\"#]]);\n});\n\n// Test cast run Celo transfer with precompiles.\ncasttest!(\n    #[ignore = \"requires debug_traceTransaction, which most free Celo RPC endpoints no longer support\"]\n    flaky_run_celo_with_precompiles,\n    |_prj, cmd| {\n        let rpc = next_rpc_endpoint(NamedChain::Celo);\n        cmd.args([\n            \"run\",\n            \"0xa652b9f41bb1a617ea6b2835b3316e79f0f21b8264e7bcd20e57c4092a70a0f6\",\n            \"--quick\",\n            \"--rpc-url\",\n            rpc.as_str(),\n        ])\n        .assert_success()\n        .stdout_eq(str![[r#\"\nTraces:\n  [17776] 0x471EcE3750Da237f93B8E339c536989b8978a438::transfer(0xD2eB2d37d238Caeff39CFA36A013299C6DbAC56A, 138000000000000000 [1.38e17])\n    ├─ [12370] 0xFeA1B35f1D5f2A58532a70e7A32e6F2D3Bc4F7B1::transfer(0xD2eB2d37d238Caeff39CFA36A013299C6DbAC56A, 138000000000000000 [1.38e17]) [delegatecall]\n    │   ├─ [9000] CELO_TRANSFER_PRECOMPILE::00000000(00000000000000008106680ba7095cfd8f4351a8b7041da3060afb83000000000000000000000000d2eb2d37d238caeff39cfa36a013299c6dbac56a00000000000000000000000000000000000000000000000001ea4644d3010000)\n    │   │   └─ ← [Return]\n    │   ├─ emit Transfer(param0: 0x8106680Ba7095CfD8F4351a8B7041da3060Afb83, param1: 0xD2eB2d37d238Caeff39CFA36A013299C6DbAC56A, param2: 138000000000000000 [1.38e17])\n    │   └─ ← [Return] 0x0000000000000000000000000000000000000000000000000000000000000001\n    └─ ← [Return] 0x0000000000000000000000000000000000000000000000000000000000000001\n\n\nTransaction successfully executed.\n[GAS]\n\n\"#]]);\n    }\n);\ncasttest!(keccak_stdin_bytes, |_prj, cmd| {\n    cmd.args([\"keccak\"]).stdin(\"0x12\").assert_success().stdout_eq(str![[r#\"\n0x5fa2358263196dbbf23d1ca7a509451f7a2f64c15837bfbb81298b1e3e24e4fa\n\n\"#]]);\n});\n\ncasttest!(keccak_stdin_bytes_with_newline, |_prj, cmd| {\n    cmd.args([\"keccak\"]).stdin(\"0x12\\n\").assert_success().stdout_eq(str![[r#\"\n0x5fa2358263196dbbf23d1ca7a509451f7a2f64c15837bfbb81298b1e3e24e4fa\n\n\"#]]);\n});\n\n// Test cast send with raw --data flag using encoded calldata\nforgetest_async!(cast_send_with_data, |prj, cmd| {\n    let (api, handle) = anvil::spawn(NodeConfig::test()).await;\n\n    foundry_test_utils::util::initialize(prj.root());\n    prj.initialize_default_contracts();\n\n    // Deploy counter contract\n    cmd.args([\n        \"script\",\n        \"--private-key\",\n        \"0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80\",\n        \"--rpc-url\",\n        &handle.http_endpoint(),\n        \"--broadcast\",\n        \"CounterScript\",\n    ])\n    .assert_success();\n\n    // setNumber(111) encoded: selector 0x3fb5c1cb + uint256(111)\n    let calldata = \"0x3fb5c1cb000000000000000000000000000000000000000000000000000000000000006f\";\n\n    // Send tx using --data instead of sig+args\n    cmd.cast_fuse()\n        .args([\n            \"send\",\n            \"0x5FbDB2315678afecb367f032d93F642f64180aa3\",\n            \"--data\",\n            calldata,\n            \"--private-key\",\n            \"0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80\",\n            \"--rpc-url\",\n            &handle.http_endpoint(),\n        ])\n        .assert_success();\n\n    // Verify via trace that setNumber(111) was called\n    let tx_hash = api\n        .transaction_by_block_number_and_index(BlockNumberOrTag::Latest, Index::from(0))\n        .await\n        .unwrap()\n        .unwrap()\n        .tx_hash();\n\n    cmd.cast_fuse()\n        .args([\n            \"run\",\n            format!(\"{tx_hash}\").as_str(),\n            \"-vvvvv\",\n            \"--rpc-url\",\n            &handle.http_endpoint(),\n        ])\n        .assert_success()\n        .stdout_eq(str![[r#\"\nExecuting previous transactions from the block.\nTraces:\n  [..] 0x5FbDB2315678afecb367f032d93F642f64180aa3::setNumber(111)\n    ├─  storage changes:\n    │   @ 0: 0 → 111\n    └─ ← [Stop]\n\n\nTransaction successfully executed.\n[GAS]\n\n\"#]]);\n});\n\n// tests that the --curl flag outputs a valid curl command for cast rpc\ncasttest!(curl_rpc, |_prj, cmd| {\n    let rpc = \"https://eth.example.com\";\n\n    let output = cmd\n        .args([\"rpc\", \"eth_blockNumber\", \"--rpc-url\", rpc, \"--curl\"])\n        .assert_success()\n        .get_output()\n        .stdout_lossy();\n\n    // Verify curl command structure\n    assert!(output.contains(\"curl -X POST\"));\n    assert!(output.contains(\"-H 'Content-Type: application/json'\"));\n    assert!(output.contains(\"eth_blockNumber\"));\n    assert!(output.contains(\"jsonrpc\"));\n    assert!(output.contains(rpc));\n});\n\n// tests that the --curl flag outputs a valid curl command for cast block-number\ncasttest!(curl_block_number, |_prj, cmd| {\n    let rpc = \"https://eth.example.com\";\n\n    let output = cmd\n        .args([\"block-number\", \"--rpc-url\", rpc, \"--curl\"])\n        .assert_success()\n        .get_output()\n        .stdout_lossy();\n\n    // Verify curl command structure\n    assert!(output.contains(\"curl -X POST\"));\n    assert!(output.contains(\"eth_blockNumber\"));\n    assert!(output.contains(rpc));\n});\n\n// tests that the --curl flag outputs a valid curl command for cast chain-id\ncasttest!(curl_chain_id, |_prj, cmd| {\n    let rpc = \"https://eth.example.com\";\n\n    let output = cmd\n        .args([\"chain-id\", \"--rpc-url\", rpc, \"--curl\"])\n        .assert_success()\n        .get_output()\n        .stdout_lossy();\n\n    // Verify curl command structure\n    assert!(output.contains(\"curl -X POST\"));\n    assert!(output.contains(\"eth_chainId\"));\n    assert!(output.contains(rpc));\n});\n\n// tests that the --curl flag outputs a valid curl command for cast gas-price\ncasttest!(curl_gas_price, |_prj, cmd| {\n    let rpc = \"https://eth.example.com\";\n\n    let output = cmd\n        .args([\"gas-price\", \"--rpc-url\", rpc, \"--curl\"])\n        .assert_success()\n        .get_output()\n        .stdout_lossy();\n\n    // Verify curl command structure\n    assert!(output.contains(\"curl -X POST\"));\n    assert!(output.contains(\"eth_gasPrice\"));\n    assert!(output.contains(rpc));\n});\n\n// tests that the --curl flag outputs a valid curl command for cast call\ncasttest!(curl_call, |_prj, cmd| {\n    let rpc = \"https://eth.example.com\";\n    let to = \"0xdead000000000000000000000000000000000000\";\n\n    let output = cmd\n        .args([\"call\", to, \"balanceOf(address)(uint256)\", to, \"--rpc-url\", rpc, \"--curl\"])\n        .assert_success()\n        .get_output()\n        .stdout_lossy();\n\n    // Verify curl command structure\n    assert!(output.contains(\"curl -X POST\"));\n    assert!(output.contains(\"eth_call\"));\n    assert!(output.contains(rpc));\n});\n\n// https://github.com/foundry-rs/foundry/issues/11584\n// Tests that invalid hex calldata (odd length) produces a clear error message\ncasttest!(cast_call_invalid_hex_calldata_error, |_prj, cmd| {\n    let rpc = next_rpc_endpoint(NamedChain::Mainnet);\n    cmd.args([\n        \"call\",\n        \"0xdead000000000000000000000000000000000000\",\n        \"--data\",\n        \"0x0\", // Invalid: odd length hex\n        \"--rpc-url\",\n        rpc.as_str(),\n    ])\n    .assert_failure()\n    .stderr_eq(str![[r#\"\nError: Invalid hex calldata '0x0': odd number of digits\n\n\"#]]);\n});\n\n// https://github.com/foundry-rs/foundry/issues/11584\n// Tests that valid hex calldata works correctly\ncasttest!(cast_call_valid_hex_calldata, |_prj, cmd| {\n    let rpc = next_rpc_endpoint(NamedChain::Mainnet);\n    cmd.args([\n        \"call\",\n        \"0xdead000000000000000000000000000000000000\",\n        \"--data\",\n        \"0x00\", // Valid: even length hex\n        \"--rpc-url\",\n        rpc.as_str(),\n    ])\n    .assert_success();\n});\n\n// https://github.com/foundry-rs/foundry/issues/11584\n// Tests that invalid hex with uppercase 0X prefix also produces clear error\ncasttest!(cast_call_invalid_hex_uppercase_prefix, |_prj, cmd| {\n    let rpc = next_rpc_endpoint(NamedChain::Mainnet);\n    cmd.args([\n        \"call\",\n        \"0xdead000000000000000000000000000000000000\",\n        \"--data\",\n        \"0X1\", // Invalid: odd length hex with uppercase prefix\n        \"--rpc-url\",\n        rpc.as_str(),\n    ])\n    .assert_failure()\n    .stderr_eq(str![[r#\"\nError: Invalid hex calldata '0X1': odd number of digits\n\n\"#]]);\n});\n"
  },
  {
    "path": "crates/cast/tests/cli/selectors.rs",
    "content": "use foundry_test_utils::util::OutputExt;\nuse std::path::Path;\n\ncasttest!(flaky_error_decode_with_openchain, |prj, cmd| {\n    prj.clear_cache();\n    cmd.args([\"decode-error\", \"0x7a0e198500000000000000000000000000000000000000000000000000000000000000650000000000000000000000000000000000000000000000000000000000000064\"]).assert_success().stdout_eq(str![[r#\"\nValueTooHigh(uint256,uint256)\n101\n100\n\n\"#]]);\n});\n\ncasttest!(flaky_fourbyte, |_prj, cmd| {\n    cmd.args([\"4byte\", \"0xa9059cbb\"]).assert_success().stdout_eq(str![[r#\"\ntransfer(address,uint256)\n\n\"#]]);\n});\n\ncasttest!(fourbyte_invalid, |_prj, cmd| {\n    cmd.args([\"4byte\", \"0xa9059c\"]).assert_failure().stderr_eq(str![[r#\"\nerror: invalid value '0xa9059c' for '[SELECTOR]': invalid string length\n\nFor more information, try '--help'.\n\n\"#]]);\n});\n\ncasttest!(flaky_fourbyte_calldata, |_prj, cmd| {\n    cmd.args([\"4byte-calldata\", \"0xa9059cbb0000000000000000000000000a2ac0c368dc8ec680a0c98c907656bd970675950000000000000000000000000000000000000000000000000000000767954a79\"]).assert_success().stdout_eq(str![[r#\"\n1) \"transfer(address,uint256)\"\n0x0A2AC0c368Dc8eC680a0c98C907656BD97067595\n31802608249 [3.18e10]\n\n\"#]]);\n});\n\ncasttest!(flaky_fourbyte_calldata_only_selector, |_prj, cmd| {\n    cmd.args([\"4byte-calldata\", \"0xa9059cbb\"]).assert_success().stdout_eq(str![[r#\"\ntransfer(address,uint256)\n\n\"#]]);\n});\n\ncasttest!(flaky_fourbyte_calldata_alias, |_prj, cmd| {\n    cmd.args([\"4byte-decode\", \"0xa9059cbb0000000000000000000000000a2ac0c368dc8ec680a0c98c907656bd970675950000000000000000000000000000000000000000000000000000000767954a79\"]).assert_success().stdout_eq(str![[r#\"\n1) \"transfer(address,uint256)\"\n0x0A2AC0c368Dc8eC680a0c98C907656BD97067595\n31802608249 [3.18e10]\n\n\"#]]);\n});\n\ncasttest!(flaky_fourbyte_event, |_prj, cmd| {\n    cmd.args([\"4byte-event\", \"0x7e1db2a1cd12f0506ecd806dba508035b290666b84b096a87af2fd2a1516ede6\"])\n        .assert_success()\n        .stdout_eq(str![[r#\"\nupdateAuthority(address,uint8)\n\n\"#]]);\n});\n\ncasttest!(flaky_fourbyte_event_2, |_prj, cmd| {\n    cmd.args([\"4byte-event\", \"0xb7009613e63fb13fd59a2fa4c206a992c1f090a44e5d530be255aa17fed0b3dd\"])\n        .assert_success()\n        .stdout_eq(str![[r#\"\ncanCall(address,address,bytes4)\n\n\"#]]);\n});\n\ncasttest!(flaky_upload_signatures, |_prj, cmd| {\n    // test no prefix is accepted as function\n    let output = cmd\n        .args([\"upload-signature\", \"transfer(address,uint256)\"])\n        .assert_success()\n        .get_output()\n        .stdout_lossy();\n    assert!(output.contains(\"Function transfer(address,uint256): 0xa9059cbb\"), \"{}\", output);\n\n    // test event prefix\n    cmd.args([\"upload-signature\", \"event Transfer(address,uint256)\"]);\n    let output = cmd.assert_success().get_output().stdout_lossy();\n    assert!(output.contains(\"Event Transfer(address,uint256): 0x69ca02dd4edd7bf0a4abb9ed3b7af3f14778db5d61921c7dc7cd545266326de2\"), \"{}\", output);\n\n    // test error prefix\n    cmd.args([\"upload-signature\", \"error ERC20InsufficientBalance(address,uint256,uint256)\"]);\n    let output = cmd.assert_success().get_output().stdout_lossy();\n    assert!(\n        output.contains(\"Function ERC20InsufficientBalance(address,uint256,uint256): 0xe450d38c\"),\n        \"{}\",\n        output\n    ); // Custom error is interpreted as function\n\n    // test multiple sigs\n    cmd.args([\n        \"upload-signature\",\n        \"event Transfer(address,uint256)\",\n        \"transfer(address,uint256)\",\n        \"approve(address,uint256)\",\n    ]);\n    let output = cmd.assert_success().get_output().stdout_lossy();\n    assert!(output.contains(\"Event Transfer(address,uint256): 0x69ca02dd4edd7bf0a4abb9ed3b7af3f14778db5d61921c7dc7cd545266326de2\"), \"{}\", output);\n    assert!(output.contains(\"Function transfer(address,uint256): 0xa9059cbb\"), \"{}\", output);\n    assert!(output.contains(\"Function approve(address,uint256): 0x095ea7b3\"), \"{}\", output);\n\n    // test abi\n    cmd.args([\n        \"upload-signature\",\n        \"event Transfer(address,uint256)\",\n        \"transfer(address,uint256)\",\n        \"error ERC20InsufficientBalance(address,uint256,uint256)\",\n        Path::new(env!(\"CARGO_MANIFEST_DIR\"))\n            .join(\"tests/fixtures/ERC20Artifact.json\")\n            .as_os_str()\n            .to_str()\n            .unwrap(),\n    ]);\n    let output = cmd.assert_success().get_output().stdout_lossy();\n    assert!(output.contains(\"Event Transfer(address,uint256): 0x69ca02dd4edd7bf0a4abb9ed3b7af3f14778db5d61921c7dc7cd545266326de2\"), \"{}\", output);\n    assert!(output.contains(\"Function transfer(address,uint256): 0xa9059cbb\"), \"{}\", output);\n    assert!(output.contains(\"Function approve(address,uint256): 0x095ea7b3\"), \"{}\", output);\n    assert!(output.contains(\"Function decimals(): 0x313ce567\"), \"{}\", output);\n    assert!(output.contains(\"Function allowance(address,address): 0xdd62ed3e\"), \"{}\", output);\n    assert!(\n        output.contains(\"Function ERC20InsufficientBalance(address,uint256,uint256): 0xe450d38c\"),\n        \"{}\",\n        output\n    );\n});\n\n// tests cast can decode event with provided signature\ncasttest!(event_decode_with_sig, |_prj, cmd| {\n    cmd.args([\"decode-event\", \"--sig\", \"MyEvent(uint256,address)\", \"0x000000000000000000000000000000000000000000000000000000000000004e0000000000000000000000000000000000000000000000000000000000d0004f\"]).assert_success().stdout_eq(str![[r#\"\n78\n0x0000000000000000000000000000000000D0004F\n\n\"#]]);\n\n    cmd.args([\"--json\"]).assert_success().stdout_eq(str![[r#\"\n[\n  78,\n  \"0x0000000000000000000000000000000000D0004F\"\n]\n\n\"#]]);\n});\n\n// tests cast can decode event with Openchain API\ncasttest!(flaky_event_decode_with_openchain, |prj, cmd| {\n    prj.clear_cache();\n    cmd.args([\"decode-event\", \"0xe27c4c1372396a3d15a9922f74f9dfc7c72b1ad6d63868470787249c356454c1000000000000000000000000000000000000000000000000000000000000004e00000000000000000000000000000000000000000000000000000dd00000004e\"]).assert_success().stdout_eq(str![[r#\"\nBaseCurrencySet(address,uint256)\n0x000000000000000000000000000000000000004e\n15187004358734 [1.518e13]\n\n\"#]]);\n});\n\n// tests cast can decode error with provided signature\ncasttest!(error_decode_with_sig, |_prj, cmd| {\n    cmd.args([\"decode-error\", \"--sig\", \"AnotherValueTooHigh(uint256,address)\", \"0x7191bc6200000000000000000000000000000000000000000000000000000000000000650000000000000000000000000000000000000000000000000000000000D0004F\"]).assert_success().stdout_eq(str![[r#\"\n101\n0x0000000000000000000000000000000000D0004F\n\n\"#]]);\n\n    cmd.args([\"--json\"]).assert_success().stdout_eq(str![[r#\"\n[\n  101,\n  \"0x0000000000000000000000000000000000D0004F\"\n]\n\n\"#]]);\n});\n\n// tests cast can decode error and event when using local sig identifiers cache\nforgetest_init!(flaky_error_event_decode_with_cache, |prj, cmd| {\n    prj.add_source(\n        \"LocalProjectContract\",\n        r#\"\ncontract ContractWithCustomError {\n    error AnotherValueTooHigh(uint256, address);\n    event MyUniqueEventWithinLocalProject(uint256 a, address b);\n}\n   \"#,\n    );\n    // Build and cache project selectors.\n    cmd.forge_fuse().args([\"build\"]).assert_success();\n    cmd.forge_fuse().args([\"selectors\", \"cache\"]).assert_success();\n\n    // Assert cast can decode custom error with local cache.\n    cmd.cast_fuse()\n        .args([\"decode-error\", \"0x7191bc6200000000000000000000000000000000000000000000000000000000000000650000000000000000000000000000000000000000000000000000000000D0004F\"])\n        .assert_success()\n        .stdout_eq(str![[r#\"\nAnotherValueTooHigh(uint256,address)\n101\n0x0000000000000000000000000000000000D0004F\n\n\"#]]);\n    // Assert cast can decode event with local cache.\n    cmd.cast_fuse()\n        .args([\"decode-event\", \"0xbd3699995dcc867b64dbb607be2c33be38df9134bef1178df13bfb9446e73104000000000000000000000000000000000000000000000000000000000000004e00000000000000000000000000000000000000000000000000000dd00000004e\"])\n        .assert_success()\n        .stdout_eq(str![[r#\"\nMyUniqueEventWithinLocalProject(uint256,address)\n78\n0x00000000000000000000000000000DD00000004e\n\n\"#]]);\n});\n\nforgetest!(flaky_cache_selectors_from_extra_abis, |prj, cmd| {\n    // Create folder with ABI JSON files containing a unique error\n    let abis_dir = prj.root().join(\"external_abis\");\n    std::fs::create_dir(&abis_dir).unwrap();\n    std::fs::write(\n        abis_dir.join(\"test.json\"),\n        r#\"[{\n          \"type\": \"error\",\n          \"name\": \"MyUniqueExtraAbiError\",\n          \"inputs\": [\n              {\"name\": \"value\", \"type\": \"uint256\"},\n              {\"name\": \"flag\", \"type\": \"bool\"}\n          ]\n      }]\"#,\n    )\n    .unwrap();\n\n    cmd.forge_fuse()\n        .args([\"selectors\", \"cache\", \"--extra-abis-path\", abis_dir.to_str().unwrap()])\n        .assert_success();\n\n    // Verify with cast decode-error (uses local cache via SignaturesIdentifier)\n    // Selector for MyUniqueExtraAbiError(uint256,bool) is 0x7819b107\n    // Encoded: selector + uint256(42) + bool(true)\n    cmd.cast_fuse()\n        .args([\"decode-error\", \"0x7819b107000000000000000000000000000000000000000000000000000000000000002a0000000000000000000000000000000000000000000000000000000000000001\"])\n        .assert_success()\n        .stdout_eq(str![[r#\"\nMyUniqueExtraAbiError(uint256,bool)\n42\ntrue\n\n\"#]]);\n});\n"
  },
  {
    "path": "crates/cast/tests/fixtures/ERC20Artifact.json",
    "content": "{\"abi\":[{\"inputs\":[{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"symbol\",\"type\":\"string\"},{\"internalType\":\"uint8\",\"name\":\"decimals\",\"type\":\"uint8\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DOMAIN_SEPARATOR\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"decimals\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"mint\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"nonces\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"r\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"s\",\"type\":\"bytes32\"}],\"name\":\"permit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"transfer\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"bytecode\":{\"object\":\"0x60e06040523480156200001157600080fd5b5060405162000f7738038062000f7783398101604081905262000034916200029a565b82828282600090805190602001906200004f92919062000127565b5081516200006590600190602085019062000127565b5060ff81166080524660a0526200007b6200008b565b60c0525062000400945050505050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6000604051620000bf91906200035c565b6040805191829003822060208301939093528101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b82805462000135906200031f565b90600052602060002090601f016020900481019282620001595760008555620001a4565b82601f106200017457805160ff1916838001178555620001a4565b82800160010185558215620001a4579182015b82811115620001a457825182559160200191906001019062000187565b50620001b2929150620001b6565b5090565b5b80821115620001b25760008155600101620001b7565b634e487b7160e01b600052604160045260246000fd5b600082601f830112620001f557600080fd5b81516001600160401b0380821115620002125762000212620001cd565b604051601f8301601f19908116603f011681019082821181831017156200023d576200023d620001cd565b816040528381526020925086838588010111156200025a57600080fd5b600091505b838210156200027e57858201830151818301840152908201906200025f565b83821115620002905760008385830101525b9695505050505050565b600080600060608486031215620002b057600080fd5b83516001600160401b0380821115620002c857600080fd5b620002d687838801620001e3565b94506020860151915080821115620002ed57600080fd5b50620002fc86828701620001e3565b925050604084015160ff811681146200031457600080fd5b809150509250925092565b600181811c908216806200033457607f821691505b602082108114156200035657634e487b7160e01b600052602260045260246000fd5b50919050565b600080835481600182811c9150808316806200037957607f831692505b60208084108214156200039a57634e487b7160e01b86526022600452602486fd5b818015620003b15760018114620003c357620003f2565b60ff19861689528489019650620003f2565b60008a81526020902060005b86811015620003ea5781548b820152908501908301620003cf565b505084890196505b509498975050505050505050565b60805160a05160c051610b476200043060003960006104530152600061041e015260006101440152610b476000f3fe608060405234801561001057600080fd5b50600436106100cf5760003560e01c806340c10f191161008c57806395d89b411161006657806395d89b41146101d5578063a9059cbb146101dd578063d505accf146101f0578063dd62ed3e1461020357600080fd5b806340c10f191461018057806370a08231146101955780637ecebe00146101b557600080fd5b806306fdde03146100d4578063095ea7b3146100f257806318160ddd1461011557806323b872dd1461012c578063313ce5671461013f5780633644e51514610178575b600080fd5b6100dc61022e565b6040516100e99190610856565b60405180910390f35b6101056101003660046108c7565b6102bc565b60405190151581526020016100e9565b61011e60025481565b6040519081526020016100e9565b61010561013a3660046108f1565b610328565b6101667f000000000000000000000000000000000000000000000000000000000000000081565b60405160ff90911681526020016100e9565b61011e61041a565b61019361018e3660046108c7565b610475565b005b61011e6101a336600461092d565b60036020526000908152604090205481565b61011e6101c336600461092d565b60056020526000908152604090205481565b6100dc610483565b6101056101eb3660046108c7565b610490565b6101936101fe36600461094f565b610508565b61011e6102113660046109c2565b600460209081526000928352604080842090915290825290205481565b6000805461023b906109f5565b80601f0160208091040260200160405190810160405280929190818152602001828054610267906109f5565b80156102b45780601f10610289576101008083540402835291602001916102b4565b820191906000526020600020905b81548152906001019060200180831161029757829003601f168201915b505050505081565b3360008181526004602090815260408083206001600160a01b038716808552925280832085905551919290917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925906103179086815260200190565b60405180910390a350600192915050565b6001600160a01b038316600090815260046020908152604080832033845290915281205460001981146103845761035f8382610a46565b6001600160a01b03861660009081526004602090815260408083203384529091529020555b6001600160a01b038516600090815260036020526040812080548592906103ac908490610a46565b90915550506001600160a01b03808516600081815260036020526040908190208054870190555190918716907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906104079087815260200190565b60405180910390a3506001949350505050565b60007f000000000000000000000000000000000000000000000000000000000000000046146104505761044b610751565b905090565b507f000000000000000000000000000000000000000000000000000000000000000090565b61047f82826107eb565b5050565b6001805461023b906109f5565b336000908152600360205260408120805483919083906104b1908490610a46565b90915550506001600160a01b038316600081815260036020526040908190208054850190555133907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906103179086815260200190565b4284101561055d5760405162461bcd60e51b815260206004820152601760248201527f5045524d49545f444541444c494e455f4558504952454400000000000000000060448201526064015b60405180910390fd5b6000600161056961041a565b6001600160a01b038a811660008181526005602090815260409182902080546001810190915582517f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98184015280840194909452938d166060840152608083018c905260a083019390935260c08083018b90528151808403909101815260e08301909152805192019190912061190160f01b6101008301526101028201929092526101228101919091526101420160408051601f198184030181528282528051602091820120600084529083018083525260ff871690820152606081018590526080810184905260a0016020604051602081039080840390855afa158015610675573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116158015906106ab5750876001600160a01b0316816001600160a01b0316145b6106e85760405162461bcd60e51b815260206004820152600e60248201526d24a72b20a624a22fa9a4a3a722a960911b6044820152606401610554565b6001600160a01b0390811660009081526004602090815260408083208a8516808552908352928190208990555188815291928a16917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a350505050505050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60006040516107839190610a5d565b6040805191829003822060208301939093528101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b80600260008282546107fd9190610af9565b90915550506001600160a01b0382166000818152600360209081526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b600060208083528351808285015260005b8181101561088357858101830151858201604001528201610867565b81811115610895576000604083870101525b50601f01601f1916929092016040019392505050565b80356001600160a01b03811681146108c257600080fd5b919050565b600080604083850312156108da57600080fd5b6108e3836108ab565b946020939093013593505050565b60008060006060848603121561090657600080fd5b61090f846108ab565b925061091d602085016108ab565b9150604084013590509250925092565b60006020828403121561093f57600080fd5b610948826108ab565b9392505050565b600080600080600080600060e0888a03121561096a57600080fd5b610973886108ab565b9650610981602089016108ab565b95506040880135945060608801359350608088013560ff811681146109a557600080fd5b9699959850939692959460a0840135945060c09093013592915050565b600080604083850312156109d557600080fd5b6109de836108ab565b91506109ec602084016108ab565b90509250929050565b600181811c90821680610a0957607f821691505b60208210811415610a2a57634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b600082821015610a5857610a58610a30565b500390565b600080835481600182811c915080831680610a7957607f831692505b6020808410821415610a9957634e487b7160e01b86526022600452602486fd5b818015610aad5760018114610abe57610aeb565b60ff19861689528489019650610aeb565b60008a81526020902060005b86811015610ae35781548b820152908501908301610aca565b505084890196505b509498975050505050505050565b60008219821115610b0c57610b0c610a30565b50019056fea26469706673582212209ca55739676d094f8ef4b3b5cfcc08f600b805843c4c3027beb2b4159a02f63664736f6c634300080a0033\",\"sourceMap\":\"113:230:22:-:0;;;148:102;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;224:4;230:6;238:8;2098:5:10;2091:4;:12;;;;;;;;;;;;:::i;:::-;-1:-1:-1;2113:16:10;;;;:6;;:16;;;;;:::i;:::-;-1:-1:-1;2139:20:10;;;;;2189:13;2170:32;;2239:24;:22;:24::i;:::-;2212:51;;-1:-1:-1;113:230:22;;-1:-1:-1;;;;;113:230:22;5507:446:10;5572:7;5669:95;5802:4;5786:22;;;;;;:::i;:::-;;;;;;;;;;5637:295;;;3635:25:23;;;;3676:18;;3669:34;;;;5830:14:10;3719:18:23;;;3712:34;5866:13:10;3762:18:23;;;3755:34;5909:4:10;3805:19:23;;;3798:61;3607:19;;5637:295:10;;;;;;;;;;;;5610:336;;;;;;5591:355;;5507:446;:::o;113:230:22:-;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;113:230:22;;;-1:-1:-1;113:230:22;:::i;:::-;;;:::o;:::-;;;;;;;;;;;;;;;14:127:23;75:10;70:3;66:20;63:1;56:31;106:4;103:1;96:15;130:4;127:1;120:15;146:885;200:5;253:3;246:4;238:6;234:17;230:27;220:55;;271:1;268;261:12;220:55;294:13;;-1:-1:-1;;;;;356:10:23;;;353:36;;;369:18;;:::i;:::-;444:2;438:9;412:2;498:13;;-1:-1:-1;;494:22:23;;;518:2;490:31;486:40;474:53;;;542:18;;;562:22;;;539:46;536:72;;;588:18;;:::i;:::-;628:10;624:2;617:22;663:2;655:6;648:18;685:4;675:14;;730:3;725:2;720;712:6;708:15;704:24;701:33;698:53;;;747:1;744;737:12;698:53;769:1;760:10;;779:133;793:2;790:1;787:9;779:133;;;881:14;;;877:23;;871:30;850:14;;;846:23;;839:63;804:10;;;;779:133;;;930:2;927:1;924:9;921:80;;;989:1;984:2;979;971:6;967:15;963:24;956:35;921:80;1019:6;146:885;-1:-1:-1;;;;;;146:885:23:o;1036:712::-;1142:6;1150;1158;1211:2;1199:9;1190:7;1186:23;1182:32;1179:52;;;1227:1;1224;1217:12;1179:52;1254:16;;-1:-1:-1;;;;;1319:14:23;;;1316:34;;;1346:1;1343;1336:12;1316:34;1369:61;1422:7;1413:6;1402:9;1398:22;1369:61;:::i;:::-;1359:71;;1476:2;1465:9;1461:18;1455:25;1439:41;;1505:2;1495:8;1492:16;1489:36;;;1521:1;1518;1511:12;1489:36;;1544:63;1599:7;1588:8;1577:9;1573:24;1544:63;:::i;:::-;1534:73;;;1650:2;1639:9;1635:18;1629:25;1694:4;1687:5;1683:16;1676:5;1673:27;1663:55;;1714:1;1711;1704:12;1663:55;1737:5;1727:15;;;1036:712;;;;;:::o;1753:380::-;1832:1;1828:12;;;;1875;;;1896:61;;1950:4;1942:6;1938:17;1928:27;;1896:61;2003:2;1995:6;1992:14;1972:18;1969:38;1966:161;;;2049:10;2044:3;2040:20;2037:1;2030:31;2084:4;2081:1;2074:15;2112:4;2109:1;2102:15;1966:161;;1753:380;;;:::o;2267:1104::-;2397:3;2426:1;2459:6;2453:13;2489:3;2511:1;2539:9;2535:2;2531:18;2521:28;;2599:2;2588:9;2584:18;2621;2611:61;;2665:4;2657:6;2653:17;2643:27;;2611:61;2691:2;2739;2731:6;2728:14;2708:18;2705:38;2702:165;;;-1:-1:-1;;;2766:33:23;;2822:4;2819:1;2812:15;2852:4;2773:3;2840:17;2702:165;2883:18;2910:104;;;;3028:1;3023:323;;;;2876:470;;2910:104;-1:-1:-1;;2943:24:23;;2931:37;;2988:16;;;;-1:-1:-1;2910:104:23;;3023:323;2214:1;2207:14;;;2251:4;2238:18;;3121:1;3135:165;3149:6;3146:1;3143:13;3135:165;;;3227:14;;3214:11;;;3207:35;3270:16;;;;3164:10;;3135:165;;;3139:3;;3329:6;3324:3;3320:16;3313:23;;2876:470;-1:-1:-1;3362:3:23;;2267:1104;-1:-1:-1;;;;;;;;2267:1104:23:o;3376:489::-;113:230:22;;;;;;;;;;;;;;;;;;;;;;;;\",\"linkReferences\":{}},\"deployedBytecode\":{\"object\":\"0x608060405234801561001057600080fd5b50600436106100cf5760003560e01c806340c10f191161008c57806395d89b411161006657806395d89b41146101d5578063a9059cbb146101dd578063d505accf146101f0578063dd62ed3e1461020357600080fd5b806340c10f191461018057806370a08231146101955780637ecebe00146101b557600080fd5b806306fdde03146100d4578063095ea7b3146100f257806318160ddd1461011557806323b872dd1461012c578063313ce5671461013f5780633644e51514610178575b600080fd5b6100dc61022e565b6040516100e99190610856565b60405180910390f35b6101056101003660046108c7565b6102bc565b60405190151581526020016100e9565b61011e60025481565b6040519081526020016100e9565b61010561013a3660046108f1565b610328565b6101667f000000000000000000000000000000000000000000000000000000000000000081565b60405160ff90911681526020016100e9565b61011e61041a565b61019361018e3660046108c7565b610475565b005b61011e6101a336600461092d565b60036020526000908152604090205481565b61011e6101c336600461092d565b60056020526000908152604090205481565b6100dc610483565b6101056101eb3660046108c7565b610490565b6101936101fe36600461094f565b610508565b61011e6102113660046109c2565b600460209081526000928352604080842090915290825290205481565b6000805461023b906109f5565b80601f0160208091040260200160405190810160405280929190818152602001828054610267906109f5565b80156102b45780601f10610289576101008083540402835291602001916102b4565b820191906000526020600020905b81548152906001019060200180831161029757829003601f168201915b505050505081565b3360008181526004602090815260408083206001600160a01b038716808552925280832085905551919290917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925906103179086815260200190565b60405180910390a350600192915050565b6001600160a01b038316600090815260046020908152604080832033845290915281205460001981146103845761035f8382610a46565b6001600160a01b03861660009081526004602090815260408083203384529091529020555b6001600160a01b038516600090815260036020526040812080548592906103ac908490610a46565b90915550506001600160a01b03808516600081815260036020526040908190208054870190555190918716907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906104079087815260200190565b60405180910390a3506001949350505050565b60007f000000000000000000000000000000000000000000000000000000000000000046146104505761044b610751565b905090565b507f000000000000000000000000000000000000000000000000000000000000000090565b61047f82826107eb565b5050565b6001805461023b906109f5565b336000908152600360205260408120805483919083906104b1908490610a46565b90915550506001600160a01b038316600081815260036020526040908190208054850190555133907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906103179086815260200190565b4284101561055d5760405162461bcd60e51b815260206004820152601760248201527f5045524d49545f444541444c494e455f4558504952454400000000000000000060448201526064015b60405180910390fd5b6000600161056961041a565b6001600160a01b038a811660008181526005602090815260409182902080546001810190915582517f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98184015280840194909452938d166060840152608083018c905260a083019390935260c08083018b90528151808403909101815260e08301909152805192019190912061190160f01b6101008301526101028201929092526101228101919091526101420160408051601f198184030181528282528051602091820120600084529083018083525260ff871690820152606081018590526080810184905260a0016020604051602081039080840390855afa158015610675573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116158015906106ab5750876001600160a01b0316816001600160a01b0316145b6106e85760405162461bcd60e51b815260206004820152600e60248201526d24a72b20a624a22fa9a4a3a722a960911b6044820152606401610554565b6001600160a01b0390811660009081526004602090815260408083208a8516808552908352928190208990555188815291928a16917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a350505050505050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60006040516107839190610a5d565b6040805191829003822060208301939093528101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b80600260008282546107fd9190610af9565b90915550506001600160a01b0382166000818152600360209081526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b600060208083528351808285015260005b8181101561088357858101830151858201604001528201610867565b81811115610895576000604083870101525b50601f01601f1916929092016040019392505050565b80356001600160a01b03811681146108c257600080fd5b919050565b600080604083850312156108da57600080fd5b6108e3836108ab565b946020939093013593505050565b60008060006060848603121561090657600080fd5b61090f846108ab565b925061091d602085016108ab565b9150604084013590509250925092565b60006020828403121561093f57600080fd5b610948826108ab565b9392505050565b600080600080600080600060e0888a03121561096a57600080fd5b610973886108ab565b9650610981602089016108ab565b95506040880135945060608801359350608088013560ff811681146109a557600080fd5b9699959850939692959460a0840135945060c09093013592915050565b600080604083850312156109d557600080fd5b6109de836108ab565b91506109ec602084016108ab565b90509250929050565b600181811c90821680610a0957607f821691505b60208210811415610a2a57634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b600082821015610a5857610a58610a30565b500390565b600080835481600182811c915080831680610a7957607f831692505b6020808410821415610a9957634e487b7160e01b86526022600452602486fd5b818015610aad5760018114610abe57610aeb565b60ff19861689528489019650610aeb565b60008a81526020902060005b86811015610ae35781548b820152908501908301610aca565b505084890196505b509498975050505050505050565b60008219821115610b0c57610b0c610a30565b50019056fea26469706673582212209ca55739676d094f8ef4b3b5cfcc08f600b805843c4c3027beb2b4159a02f63664736f6c634300080a0033\",\"sourceMap\":\"113:230:22:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1028:18:10;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;2458:211;;;;;;:::i;:::-;;:::i;:::-;;;1218:14:23;;1211:22;1193:41;;1181:2;1166:18;2458:211:10;1053:187:23;1301:26:10;;;;;;;;;1391:25:23;;;1379:2;1364:18;1301:26:10;1245:177:23;3054:592:10;;;;;;:::i;:::-;;:::i;1080:31::-;;;;;;;;1932:4:23;1920:17;;;1902:36;;1890:2;1875:18;1080:31:10;1760:184:23;5324:177:10;;;:::i;256:85:22:-;;;;;;:::i;:::-;;:::i;:::-;;1334:44:10;;;;;;:::i;:::-;;;;;;;;;;;;;;1748:41;;;;;;:::i;:::-;;;;;;;;;;;;;;1053:20;;;:::i;2675:373::-;;;;;;:::i;:::-;;:::i;3835:1483::-;;;;;;:::i;:::-;;:::i;1385:64::-;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;1028:18;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;2458:211::-;2558:10;2532:4;2548:21;;;:9;:21;;;;;;;;-1:-1:-1;;;;;2548:30:10;;;;;;;;;;:39;;;2603:37;2532:4;;2548:30;;2603:37;;;;2581:6;1391:25:23;;1379:2;1364:18;;1245:177;2603:37:10;;;;;;;;-1:-1:-1;2658:4:10;2458:211;;;;:::o;3054:592::-;-1:-1:-1;;;;;3206:15:10;;3172:4;3206:15;;;:9;:15;;;;;;;;3222:10;3206:27;;;;;;;;-1:-1:-1;;3284:28:10;;3280:80;;3344:16;3354:6;3344:7;:16;:::i;:::-;-1:-1:-1;;;;;3314:15:10;;;;;;:9;:15;;;;;;;;3330:10;3314:27;;;;;;;:46;3280:80;-1:-1:-1;;;;;3371:15:10;;;;;;:9;:15;;;;;:25;;3390:6;;3371:15;:25;;3390:6;;3371:25;:::i;:::-;;;;-1:-1:-1;;;;;;;3542:13:10;;;;;;;:9;:13;;;;;;;:23;;;;;;3591:26;3542:13;;3591:26;;;;;;;3559:6;1391:25:23;;1379:2;1364:18;;1245:177;3591:26:10;;;;;;;;-1:-1:-1;3635:4:10;;3054:592;-1:-1:-1;;;;3054:592:10:o;5324:177::-;5381:7;5424:16;5407:13;:33;:87;;5470:24;:22;:24::i;:::-;5400:94;;5324:177;:::o;5407:87::-;-1:-1:-1;5443:24:10;;5324:177::o;256:85:22:-;317:17;323:2;327:6;317:5;:17::i;:::-;256:85;;:::o;1053:20:10:-;;;;;;;:::i;2675:373::-;2771:10;2745:4;2761:21;;;:9;:21;;;;;:31;;2786:6;;2761:21;2745:4;;2761:31;;2786:6;;2761:31;:::i;:::-;;;;-1:-1:-1;;;;;;;2938:13:10;;;;;;:9;:13;;;;;;;:23;;;;;;2987:32;2996:10;;2987:32;;;;2955:6;1391:25:23;;1379:2;1364:18;;1245:177;3835:1483:10;4054:15;4042:8;:27;;4034:63;;;;-1:-1:-1;;;4034:63:10;;4134:2:23;4034:63:10;;;4116:21:23;4173:2;4153:18;;;4146:30;4212:25;4192:18;;;4185:53;4255:18;;4034:63:10;;;;;;;;;4262:24;4289:805;4425:18;:16;:18::i;:::-;-1:-1:-1;;;;;4870:13:10;;;;;;;:6;:13;;;;;;;;;:15;;;;;;;;4508:449;;4552:165;4508:449;;;4571:25:23;4650:18;;;4643:43;;;;4722:15;;;4702:18;;;4695:43;4754:18;;;4747:34;;;4797:19;;;4790:35;;;;4841:19;;;;4834:35;;;4508:449:10;;;;;;;;;;4543:19:23;;;4508:449:10;;;4469:514;;;;;;;;-1:-1:-1;;;4347:658:10;;;5138:27:23;5181:11;;;5174:27;;;;5217:12;;;5210:28;;;;5254:12;;4347:658:10;;;-1:-1:-1;;4347:658:10;;;;;;;;;4316:707;;4347:658;4316:707;;;;4289:805;;;;;;;;;5504:25:23;5577:4;5565:17;;5545:18;;;5538:45;5599:18;;;5592:34;;;5642:18;;;5635:34;;;5476:19;;4289:805:10;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;4289:805:10;;-1:-1:-1;;4289:805:10;;;-1:-1:-1;;;;;;;5117:30:10;;;;;;:59;;;5171:5;-1:-1:-1;;;;;5151:25:10;:16;-1:-1:-1;;;;;5151:25:10;;5117:59;5109:86;;;;-1:-1:-1;;;5109:86:10;;5882:2:23;5109:86:10;;;5864:21:23;5921:2;5901:18;;;5894:30;-1:-1:-1;;;5940:18:23;;;5933:44;5994:18;;5109:86:10;5680:338:23;5109:86:10;-1:-1:-1;;;;;5210:27:10;;;;;;;:9;:27;;;;;;;;:36;;;;;;;;;;;;;:44;;;5280:31;1391:25:23;;;5210:36:10;;5280:31;;;;;1364:18:23;5280:31:10;;;;;;;3835:1483;;;;;;;:::o;5507:446::-;5572:7;5669:95;5802:4;5786:22;;;;;;:::i;:::-;;;;;;;;;;5637:295;;;7520:25:23;;;;7561:18;;7554:34;;;;5830:14:10;7604:18:23;;;7597:34;5866:13:10;7647:18:23;;;7640:34;5909:4:10;7690:19:23;;;7683:61;7492:19;;5637:295:10;;;;;;;;;;;;5610:336;;;;;;5591:355;;5507:446;:::o;6147:325::-;6232:6;6217:11;;:21;;;;;;;:::i;:::-;;;;-1:-1:-1;;;;;;;6384:13:10;;;;;;:9;:13;;;;;;;;:23;;;;;;6433:32;1391:25:23;;;6433:32:10;;1364:18:23;6433:32:10;;;;;;;6147:325;;:::o;14:597:23:-;126:4;155:2;184;173:9;166:21;216:6;210:13;259:6;254:2;243:9;239:18;232:34;284:1;294:140;308:6;305:1;302:13;294:140;;;403:14;;;399:23;;393:30;369:17;;;388:2;365:26;358:66;323:10;;294:140;;;452:6;449:1;446:13;443:91;;;522:1;517:2;508:6;497:9;493:22;489:31;482:42;443:91;-1:-1:-1;595:2:23;574:15;-1:-1:-1;;570:29:23;555:45;;;;602:2;551:54;;14:597;-1:-1:-1;;;14:597:23:o;616:173::-;684:20;;-1:-1:-1;;;;;733:31:23;;723:42;;713:70;;779:1;776;769:12;713:70;616:173;;;:::o;794:254::-;862:6;870;923:2;911:9;902:7;898:23;894:32;891:52;;;939:1;936;929:12;891:52;962:29;981:9;962:29;:::i;:::-;952:39;1038:2;1023:18;;;;1010:32;;-1:-1:-1;;;794:254:23:o;1427:328::-;1504:6;1512;1520;1573:2;1561:9;1552:7;1548:23;1544:32;1541:52;;;1589:1;1586;1579:12;1541:52;1612:29;1631:9;1612:29;:::i;:::-;1602:39;;1660:38;1694:2;1683:9;1679:18;1660:38;:::i;:::-;1650:48;;1745:2;1734:9;1730:18;1717:32;1707:42;;1427:328;;;;;:::o;2131:186::-;2190:6;2243:2;2231:9;2222:7;2218:23;2214:32;2211:52;;;2259:1;2256;2249:12;2211:52;2282:29;2301:9;2282:29;:::i;:::-;2272:39;2131:186;-1:-1:-1;;;2131:186:23:o;2322:693::-;2433:6;2441;2449;2457;2465;2473;2481;2534:3;2522:9;2513:7;2509:23;2505:33;2502:53;;;2551:1;2548;2541:12;2502:53;2574:29;2593:9;2574:29;:::i;:::-;2564:39;;2622:38;2656:2;2645:9;2641:18;2622:38;:::i;:::-;2612:48;;2707:2;2696:9;2692:18;2679:32;2669:42;;2758:2;2747:9;2743:18;2730:32;2720:42;;2812:3;2801:9;2797:19;2784:33;2857:4;2850:5;2846:16;2839:5;2836:27;2826:55;;2877:1;2874;2867:12;2826:55;2322:693;;;;-1:-1:-1;2322:693:23;;;;2900:5;2952:3;2937:19;;2924:33;;-1:-1:-1;3004:3:23;2989:19;;;2976:33;;2322:693;-1:-1:-1;;2322:693:23:o;3020:260::-;3088:6;3096;3149:2;3137:9;3128:7;3124:23;3120:32;3117:52;;;3165:1;3162;3155:12;3117:52;3188:29;3207:9;3188:29;:::i;:::-;3178:39;;3236:38;3270:2;3259:9;3255:18;3236:38;:::i;:::-;3226:48;;3020:260;;;;;:::o;3285:380::-;3364:1;3360:12;;;;3407;;;3428:61;;3482:4;3474:6;3470:17;3460:27;;3428:61;3535:2;3527:6;3524:14;3504:18;3501:38;3498:161;;;3581:10;3576:3;3572:20;3569:1;3562:31;3616:4;3613:1;3606:15;3644:4;3641:1;3634:15;3498:161;;3285:380;;;:::o;3670:127::-;3731:10;3726:3;3722:20;3719:1;3712:31;3762:4;3759:1;3752:15;3786:4;3783:1;3776:15;3802:125;3842:4;3870:1;3867;3864:8;3861:34;;;3875:18;;:::i;:::-;-1:-1:-1;3912:9:23;;3802:125::o;6152:1104::-;6282:3;6311:1;6344:6;6338:13;6374:3;6396:1;6424:9;6420:2;6416:18;6406:28;;6484:2;6473:9;6469:18;6506;6496:61;;6550:4;6542:6;6538:17;6528:27;;6496:61;6576:2;6624;6616:6;6613:14;6593:18;6590:38;6587:165;;;-1:-1:-1;;;6651:33:23;;6707:4;6704:1;6697:15;6737:4;6658:3;6725:17;6587:165;6768:18;6795:104;;;;6913:1;6908:323;;;;6761:470;;6795:104;-1:-1:-1;;6828:24:23;;6816:37;;6873:16;;;;-1:-1:-1;6795:104:23;;6908:323;6099:1;6092:14;;;6136:4;6123:18;;7006:1;7020:165;7034:6;7031:1;7028:13;7020:165;;;7112:14;;7099:11;;;7092:35;7155:16;;;;7049:10;;7020:165;;;7024:3;;7214:6;7209:3;7205:16;7198:23;;6761:470;-1:-1:-1;7247:3:23;;6152:1104;-1:-1:-1;;;;;;;;6152:1104:23:o;7755:128::-;7795:3;7826:1;7822:6;7819:1;7816:13;7813:39;;;7832:18;;:::i;:::-;-1:-1:-1;7868:9:23;;7755:128::o\",\"linkReferences\":{},\"immutableReferences\":{\"3499\":[{\"start\":324,\"length\":32}],\"3513\":[{\"start\":1054,\"length\":32}],\"3515\":[{\"start\":1107,\"length\":32}]}},\"methodIdentifiers\":{\"DOMAIN_SEPARATOR()\":\"3644e515\",\"allowance(address,address)\":\"dd62ed3e\",\"approve(address,uint256)\":\"095ea7b3\",\"balanceOf(address)\":\"70a08231\",\"decimals()\":\"313ce567\",\"mint(address,uint256)\":\"40c10f19\",\"name()\":\"06fdde03\",\"nonces(address)\":\"7ecebe00\",\"permit(address,address,uint256,uint256,uint8,bytes32,bytes32)\":\"d505accf\",\"symbol()\":\"95d89b41\",\"totalSupply()\":\"18160ddd\",\"transfer(address,uint256)\":\"a9059cbb\",\"transferFrom(address,address,uint256)\":\"23b872dd\"}}"
  },
  {
    "path": "crates/cast/tests/fixtures/TestToken.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ncontract TestToken {\n    string public name = \"Test Token\";\n    string public symbol = \"TEST\";\n    uint8 public decimals = 18;\n    uint256 public totalSupply;\n\n    mapping(address => uint256) public balanceOf;\n    mapping(address => mapping(address => uint256)) public allowance;\n\n    event Transfer(address indexed from, address indexed to, uint256 value);\n    event Approval(address indexed owner, address indexed spender, uint256 value);\n\n    constructor() {\n        totalSupply = 1000 * 10**decimals;\n        balanceOf[msg.sender] = totalSupply;\n        emit Transfer(address(0), msg.sender, totalSupply);\n    }\n\n    function transfer(address to, uint256 amount) external returns (bool) {\n        require(balanceOf[msg.sender] >= amount, \"Insufficient balance\");\n        balanceOf[msg.sender] -= amount;\n        balanceOf[to] += amount;\n        emit Transfer(msg.sender, to, amount);\n        return true;\n    }\n\n    function approve(address spender, uint256 amount) external returns (bool) {\n        allowance[msg.sender][spender] = amount;\n        emit Approval(msg.sender, spender, amount);\n        return true;\n    }\n\n    function transferFrom(address from, address to, uint256 amount) external returns (bool) {\n        require(balanceOf[from] >= amount, \"Insufficient balance\");\n        require(allowance[from][msg.sender] >= amount, \"Insufficient allowance\");\n\n        balanceOf[from] -= amount;\n        balanceOf[to] += amount;\n        allowance[from][msg.sender] -= amount;\n\n        emit Transfer(from, to, amount);\n        return true;\n    }\n\n    function mint(address to, uint256 amount) external {\n        totalSupply += amount;\n        balanceOf[to] += amount;\n        emit Transfer(address(0), to, amount);\n    }\n\n    function burn(uint256 amount) external {\n        uint256 balance = balanceOf[msg.sender];\n        amount = (amount > balance) ? balance : amount;\n\n        totalSupply -= amount;\n        balanceOf[msg.sender] -= amount;\n        emit Transfer(msg.sender, address(0), amount);\n    }\n}\n"
  },
  {
    "path": "crates/cast/tests/fixtures/cast_logs.stdout",
    "content": "- address: 0x95aD61b0a150d79219dCF64E1E6Cc01f0B64C4cE\n  blockHash: 0x439b61565dacbc09a6d54378dff60d9b0400496d7a5a060cfdfdd899262f466c\n  blockNumber: 12421182\n  data: 0x000000000000000000000000000000000000027fd7b375dda5ef932dac18d302\n  logIndex: 15\n  removed: false\n  topics: [\n  \t0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef\n  \t0x000000000000000000000000ab5801a7d398351b8be11c439e05c5b3259aec9b\n  \t0x00000000000000000000000068a99f89e475a078645f4bac491360afe255dff1\n  ]\n  transactionHash: 0xb65bcbb85c1633b0ab4e4886c3cd8eeaeb63edbb39cacdb9223fdcf4454fd2c7\n  transactionIndex: 8\n"
  },
  {
    "path": "crates/cast/tests/fixtures/interface.json",
    "content": "[{\"type\":\"constructor\",\"inputs\":[{\"name\":\"_integrationManager\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"_addressListRegistry\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"_aTokenListId\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"_pool\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"_referralCode\",\"type\":\"uint16\",\"internalType\":\"uint16\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"getIntegrationManager\",\"inputs\":[],\"outputs\":[{\"name\":\"integrationManager_\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"lend\",\"inputs\":[{\"name\":\"_vaultProxy\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"_assetData\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"parseAssetsForAction\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"_selector\",\"type\":\"bytes4\",\"internalType\":\"bytes4\"},{\"name\":\"_actionData\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[{\"name\":\"spendAssetsHandleType_\",\"type\":\"uint8\",\"internalType\":\"enum IIntegrationManager.SpendAssetsHandleType\"},{\"name\":\"spendAssets_\",\"type\":\"address[]\",\"internalType\":\"address[]\"},{\"name\":\"spendAssetAmounts_\",\"type\":\"uint256[]\",\"internalType\":\"uint256[]\"},{\"name\":\"incomingAssets_\",\"type\":\"address[]\",\"internalType\":\"address[]\"},{\"name\":\"minIncomingAssetAmounts_\",\"type\":\"uint256[]\",\"internalType\":\"uint256[]\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"redeem\",\"inputs\":[{\"name\":\"_vaultProxy\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"_assetData\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"}]"
  },
  {
    "path": "crates/cast/tests/fixtures/interface_inherited_struct.json",
    "content": "[{\"type\":\"function\",\"name\":\"test\",\"inputs\":[{\"name\":\"param\",\"type\":\"tuple\",\"internalType\":\"struct IBase.TestStruct\",\"components\":[{\"name\":\"asset\",\"type\":\"address\",\"internalType\":\"address\"}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"}]\n"
  },
  {
    "path": "crates/cast/tests/fixtures/keystore/UTC--2022-10-30T06-51-20.130356000Z--560d246fcddc9ea98a8b032c9a2f474efb493c28",
    "content": "{\"address\":\"560d246fcddc9ea98a8b032c9a2f474efb493c28\",\"crypto\":{\"cipher\":\"aes-128-ctr\",\"ciphertext\":\"0b0012edfc7a1b22c7c616a78562807c363482490359ae23858c49d6a369b2ff\",\"cipherparams\":{\"iv\":\"9d72960fe04dd987300e91c101c890b8\"},\"kdf\":\"scrypt\",\"kdfparams\":{\"dklen\":32,\"n\":262144,\"p\":1,\"r\":8,\"salt\":\"f7d24eae5e746700a1fdc0e0886801b0e7aff7e298f9409f74355a5387827181\"},\"mac\":\"981cae42a43ce975b9ff13d19a99ae755ad3f6125c94a4da517c50067ca87f07\"},\"id\":\"852dbcfc-726a-416e-9321-29f9b5d7e2de\",\"version\":3}"
  },
  {
    "path": "crates/cast/tests/fixtures/keystore/UTC--2022-12-20T10-30-43.591916000Z--ec554aeafe75601aaab43bd4621a22284db566c2",
    "content": "{\"address\":\"ec554aeafe75601aaab43bd4621a22284db566c2\",\"crypto\":{\"cipher\":\"aes-128-ctr\",\"ciphertext\":\"f4e11a2667d97f42ad820f2aa735cd557ff608f47e2738d763a834b889611e18\",\"cipherparams\":{\"iv\":\"99c3e2f1c98ccac50cb19f0a148e02ee\"},\"kdf\":\"scrypt\",\"kdfparams\":{\"dklen\":32,\"n\":262144,\"p\":1,\"r\":8,\"salt\":\"81f3033ffcc9fec9939eaec246a4037d9bc0c47cfb33247c98132b7d477b7e64\"},\"mac\":\"13bb4eac9a8d8f72905bca0c6f947c440d990baa649b0697b2083f3ab57d2cc5\"},\"id\":\"279ce8c3-dd94-43a8-aa46-15c3a45adbd1\",\"version\":3}"
  },
  {
    "path": "crates/cast/tests/fixtures/keystore/password",
    "content": "this is keystore password\n"
  },
  {
    "path": "crates/cast/tests/fixtures/keystore/password-ec554",
    "content": "keystorepassword"
  },
  {
    "path": "crates/cast/tests/fixtures/sign_typed_data.json",
    "content": "{\"types\":{\"EIP712Domain\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"version\",\"type\":\"string\"},{\"name\":\"chainId\",\"type\":\"uint256\"},{\"name\":\"verifyingContract\",\"type\":\"address\"}],\"Message\":[{\"name\":\"data\",\"type\":\"string\"}]},\"primaryType\":\"Message\",\"domain\":{\"name\":\"example.metamask.io\",\"version\":\"1\",\"chainId\":\"1\",\"verifyingContract\":\"0x0000000000000000000000000000000000000000\"},\"message\":{\"data\":\"Hello!\"}}"
  },
  {
    "path": "crates/cast/tests/fixtures/storage_layout_complex.json",
    "content": "{\n    \"storage\": [\n        {\n            \"astId\": 3805,\n            \"contract\": \"contracts/vault/Vault.sol:Vault\",\n            \"label\": \"_status\",\n            \"offset\": 0,\n            \"slot\": \"0\",\n            \"type\": \"t_uint256\"\n        },\n        {\n            \"astId\": 9499,\n            \"contract\": \"contracts/vault/Vault.sol:Vault\",\n            \"label\": \"_generalPoolsBalances\",\n            \"offset\": 0,\n            \"slot\": \"1\",\n            \"type\": \"t_mapping(t_bytes32,t_struct(IERC20ToBytes32Map)3177_storage)\"\n        },\n        {\n            \"astId\": 716,\n            \"contract\": \"contracts/vault/Vault.sol:Vault\",\n            \"label\": \"_nextNonce\",\n            \"offset\": 0,\n            \"slot\": \"2\",\n            \"type\": \"t_mapping(t_address,t_uint256)\"\n        },\n        {\n            \"astId\": 967,\n            \"contract\": \"contracts/vault/Vault.sol:Vault\",\n            \"label\": \"_paused\",\n            \"offset\": 0,\n            \"slot\": \"3\",\n            \"type\": \"t_bool\"\n        },\n        {\n            \"astId\": 8639,\n            \"contract\": \"contracts/vault/Vault.sol:Vault\",\n            \"label\": \"_authorizer\",\n            \"offset\": 1,\n            \"slot\": \"3\",\n            \"type\": \"t_contract(IAuthorizer)11086\"\n        },\n        {\n            \"astId\": 8645,\n            \"contract\": \"contracts/vault/Vault.sol:Vault\",\n            \"label\": \"_approvedRelayers\",\n            \"offset\": 0,\n            \"slot\": \"4\",\n            \"type\": \"t_mapping(t_address,t_mapping(t_address,t_bool))\"\n        },\n        {\n            \"astId\": 5769,\n            \"contract\": \"contracts/vault/Vault.sol:Vault\",\n            \"label\": \"_isPoolRegistered\",\n            \"offset\": 0,\n            \"slot\": \"5\",\n            \"type\": \"t_mapping(t_bytes32,t_bool)\"\n        },\n        {\n            \"astId\": 5771,\n            \"contract\": \"contracts/vault/Vault.sol:Vault\",\n            \"label\": \"_nextPoolNonce\",\n            \"offset\": 0,\n            \"slot\": \"6\",\n            \"type\": \"t_uint256\"\n        },\n        {\n            \"astId\": 9915,\n            \"contract\": \"contracts/vault/Vault.sol:Vault\",\n            \"label\": \"_minimalSwapInfoPoolsBalances\",\n            \"offset\": 0,\n            \"slot\": \"7\",\n            \"type\": \"t_mapping(t_bytes32,t_mapping(t_contract(IERC20)3793,t_bytes32))\"\n        },\n        {\n            \"astId\": 9919,\n            \"contract\": \"contracts/vault/Vault.sol:Vault\",\n            \"label\": \"_minimalSwapInfoPoolsTokens\",\n            \"offset\": 0,\n            \"slot\": \"8\",\n            \"type\": \"t_mapping(t_bytes32,t_struct(AddressSet)3520_storage)\"\n        },\n        {\n            \"astId\": 10373,\n            \"contract\": \"contracts/vault/Vault.sol:Vault\",\n            \"label\": \"_twoTokenPoolTokens\",\n            \"offset\": 0,\n            \"slot\": \"9\",\n            \"type\": \"t_mapping(t_bytes32,t_struct(TwoTokenPoolTokens)10369_storage)\"\n        },\n        {\n            \"astId\": 4007,\n            \"contract\": \"contracts/vault/Vault.sol:Vault\",\n            \"label\": \"_poolAssetManagers\",\n            \"offset\": 0,\n            \"slot\": \"10\",\n            \"type\": \"t_mapping(t_bytes32,t_mapping(t_contract(IERC20)3793,t_address))\"\n        },\n        {\n            \"astId\": 8019,\n            \"contract\": \"contracts/vault/Vault.sol:Vault\",\n            \"label\": \"_internalTokenBalance\",\n            \"offset\": 0,\n            \"slot\": \"11\",\n            \"type\": \"t_mapping(t_address,t_mapping(t_contract(IERC20)3793,t_uint256))\"\n        }\n    ],\n    \"types\": {\n        \"t_address\": {\n            \"encoding\": \"inplace\",\n            \"label\": \"address\",\n            \"numberOfBytes\": \"20\"\n        },\n        \"t_array(t_address)dyn_storage\": {\n            \"encoding\": \"dynamic_array\",\n            \"label\": \"address[]\",\n            \"numberOfBytes\": \"32\",\n            \"base\": \"t_address\"\n        },\n        \"t_bool\": {\n            \"encoding\": \"inplace\",\n            \"label\": \"bool\",\n            \"numberOfBytes\": \"1\"\n        },\n        \"t_bytes32\": {\n            \"encoding\": \"inplace\",\n            \"label\": \"bytes32\",\n            \"numberOfBytes\": \"32\"\n        },\n        \"t_contract(IAuthorizer)11086\": {\n            \"encoding\": \"inplace\",\n            \"label\": \"contract IAuthorizer\",\n            \"numberOfBytes\": \"20\"\n        },\n        \"t_contract(IERC20)3793\": {\n            \"encoding\": \"inplace\",\n            \"label\": \"contract IERC20\",\n            \"numberOfBytes\": \"20\"\n        },\n        \"t_mapping(t_address,t_bool)\": {\n            \"encoding\": \"mapping\",\n            \"key\": \"t_address\",\n            \"label\": \"mapping(address => bool)\",\n            \"numberOfBytes\": \"32\",\n            \"value\": \"t_bool\"\n        },\n        \"t_mapping(t_address,t_mapping(t_address,t_bool))\": {\n            \"encoding\": \"mapping\",\n            \"key\": \"t_address\",\n            \"label\": \"mapping(address => mapping(address => bool))\",\n            \"numberOfBytes\": \"32\",\n            \"value\": \"t_mapping(t_address,t_bool)\"\n        },\n        \"t_mapping(t_address,t_mapping(t_contract(IERC20)3793,t_uint256))\": {\n            \"encoding\": \"mapping\",\n            \"key\": \"t_address\",\n            \"label\": \"mapping(address => mapping(contract IERC20 => uint256))\",\n            \"numberOfBytes\": \"32\",\n            \"value\": \"t_mapping(t_contract(IERC20)3793,t_uint256)\"\n        },\n        \"t_mapping(t_address,t_uint256)\": {\n            \"encoding\": \"mapping\",\n            \"key\": \"t_address\",\n            \"label\": \"mapping(address => uint256)\",\n            \"numberOfBytes\": \"32\",\n            \"value\": \"t_uint256\"\n        },\n        \"t_mapping(t_bytes32,t_bool)\": {\n            \"encoding\": \"mapping\",\n            \"key\": \"t_bytes32\",\n            \"label\": \"mapping(bytes32 => bool)\",\n            \"numberOfBytes\": \"32\",\n            \"value\": \"t_bool\"\n        },\n        \"t_mapping(t_bytes32,t_mapping(t_contract(IERC20)3793,t_address))\": {\n            \"encoding\": \"mapping\",\n            \"key\": \"t_bytes32\",\n            \"label\": \"mapping(bytes32 => mapping(contract IERC20 => address))\",\n            \"numberOfBytes\": \"32\",\n            \"value\": \"t_mapping(t_contract(IERC20)3793,t_address)\"\n        },\n        \"t_mapping(t_bytes32,t_mapping(t_contract(IERC20)3793,t_bytes32))\": {\n            \"encoding\": \"mapping\",\n            \"key\": \"t_bytes32\",\n            \"label\": \"mapping(bytes32 => mapping(contract IERC20 => bytes32))\",\n            \"numberOfBytes\": \"32\",\n            \"value\": \"t_mapping(t_contract(IERC20)3793,t_bytes32)\"\n        },\n        \"t_mapping(t_bytes32,t_struct(AddressSet)3520_storage)\": {\n            \"encoding\": \"mapping\",\n            \"key\": \"t_bytes32\",\n            \"label\": \"mapping(bytes32 => struct EnumerableSet.AddressSet)\",\n            \"numberOfBytes\": \"32\",\n            \"value\": \"t_struct(AddressSet)3520_storage\"\n        },\n        \"t_mapping(t_bytes32,t_struct(IERC20ToBytes32Map)3177_storage)\": {\n            \"encoding\": \"mapping\",\n            \"key\": \"t_bytes32\",\n            \"label\": \"mapping(bytes32 => struct EnumerableMap.IERC20ToBytes32Map)\",\n            \"numberOfBytes\": \"32\",\n            \"value\": \"t_struct(IERC20ToBytes32Map)3177_storage\"\n        },\n        \"t_mapping(t_bytes32,t_struct(TwoTokenPoolBalances)10360_storage)\": {\n            \"encoding\": \"mapping\",\n            \"key\": \"t_bytes32\",\n            \"label\": \"mapping(bytes32 => struct TwoTokenPoolsBalance.TwoTokenPoolBalances)\",\n            \"numberOfBytes\": \"32\",\n            \"value\": \"t_struct(TwoTokenPoolBalances)10360_storage\"\n        },\n        \"t_mapping(t_bytes32,t_struct(TwoTokenPoolTokens)10369_storage)\": {\n            \"encoding\": \"mapping\",\n            \"key\": \"t_bytes32\",\n            \"label\": \"mapping(bytes32 => struct TwoTokenPoolsBalance.TwoTokenPoolTokens)\",\n            \"numberOfBytes\": \"32\",\n            \"value\": \"t_struct(TwoTokenPoolTokens)10369_storage\"\n        },\n        \"t_mapping(t_contract(IERC20)3793,t_address)\": {\n            \"encoding\": \"mapping\",\n            \"key\": \"t_contract(IERC20)3793\",\n            \"label\": \"mapping(contract IERC20 => address)\",\n            \"numberOfBytes\": \"32\",\n            \"value\": \"t_address\"\n        },\n        \"t_mapping(t_contract(IERC20)3793,t_bytes32)\": {\n            \"encoding\": \"mapping\",\n            \"key\": \"t_contract(IERC20)3793\",\n            \"label\": \"mapping(contract IERC20 => bytes32)\",\n            \"numberOfBytes\": \"32\",\n            \"value\": \"t_bytes32\"\n        },\n        \"t_mapping(t_contract(IERC20)3793,t_uint256)\": {\n            \"encoding\": \"mapping\",\n            \"key\": \"t_contract(IERC20)3793\",\n            \"label\": \"mapping(contract IERC20 => uint256)\",\n            \"numberOfBytes\": \"32\",\n            \"value\": \"t_uint256\"\n        },\n        \"t_mapping(t_uint256,t_struct(IERC20ToBytes32MapEntry)3166_storage)\": {\n            \"encoding\": \"mapping\",\n            \"key\": \"t_uint256\",\n            \"label\": \"mapping(uint256 => struct EnumerableMap.IERC20ToBytes32MapEntry)\",\n            \"numberOfBytes\": \"32\",\n            \"value\": \"t_struct(IERC20ToBytes32MapEntry)3166_storage\"\n        },\n        \"t_struct(AddressSet)3520_storage\": {\n            \"encoding\": \"inplace\",\n            \"label\": \"struct EnumerableSet.AddressSet\",\n            \"numberOfBytes\": \"64\",\n            \"members\": [\n                {\n                    \"astId\": 3515,\n                    \"contract\": \"contracts/vault/Vault.sol:Vault\",\n                    \"label\": \"_values\",\n                    \"offset\": 0,\n                    \"slot\": \"0\",\n                    \"type\": \"t_array(t_address)dyn_storage\"\n                },\n                {\n                    \"astId\": 3519,\n                    \"contract\": \"contracts/vault/Vault.sol:Vault\",\n                    \"label\": \"_indexes\",\n                    \"offset\": 0,\n                    \"slot\": \"1\",\n                    \"type\": \"t_mapping(t_address,t_uint256)\"\n                }\n            ]\n        },\n        \"t_struct(IERC20ToBytes32Map)3177_storage\": {\n            \"encoding\": \"inplace\",\n            \"label\": \"struct EnumerableMap.IERC20ToBytes32Map\",\n            \"numberOfBytes\": \"96\",\n            \"members\": [\n                {\n                    \"astId\": 3168,\n                    \"contract\": \"contracts/vault/Vault.sol:Vault\",\n                    \"label\": \"_length\",\n                    \"offset\": 0,\n                    \"slot\": \"0\",\n                    \"type\": \"t_uint256\"\n                },\n                {\n                    \"astId\": 3172,\n                    \"contract\": \"contracts/vault/Vault.sol:Vault\",\n                    \"label\": \"_entries\",\n                    \"offset\": 0,\n                    \"slot\": \"1\",\n                    \"type\": \"t_mapping(t_uint256,t_struct(IERC20ToBytes32MapEntry)3166_storage)\"\n                },\n                {\n                    \"astId\": 3176,\n                    \"contract\": \"contracts/vault/Vault.sol:Vault\",\n                    \"label\": \"_indexes\",\n                    \"offset\": 0,\n                    \"slot\": \"2\",\n                    \"type\": \"t_mapping(t_contract(IERC20)3793,t_uint256)\"\n                }\n            ]\n        },\n        \"t_struct(IERC20ToBytes32MapEntry)3166_storage\": {\n            \"encoding\": \"inplace\",\n            \"label\": \"struct EnumerableMap.IERC20ToBytes32MapEntry\",\n            \"numberOfBytes\": \"64\",\n            \"members\": [\n                {\n                    \"astId\": 3163,\n                    \"contract\": \"contracts/vault/Vault.sol:Vault\",\n                    \"label\": \"_key\",\n                    \"offset\": 0,\n                    \"slot\": \"0\",\n                    \"type\": \"t_contract(IERC20)3793\"\n                },\n                {\n                    \"astId\": 3165,\n                    \"contract\": \"contracts/vault/Vault.sol:Vault\",\n                    \"label\": \"_value\",\n                    \"offset\": 0,\n                    \"slot\": \"1\",\n                    \"type\": \"t_bytes32\"\n                }\n            ]\n        },\n        \"t_struct(TwoTokenPoolBalances)10360_storage\": {\n            \"encoding\": \"inplace\",\n            \"label\": \"struct TwoTokenPoolsBalance.TwoTokenPoolBalances\",\n            \"numberOfBytes\": \"64\",\n            \"members\": [\n                {\n                    \"astId\": 10357,\n                    \"contract\": \"contracts/vault/Vault.sol:Vault\",\n                    \"label\": \"sharedCash\",\n                    \"offset\": 0,\n                    \"slot\": \"0\",\n                    \"type\": \"t_bytes32\"\n                },\n                {\n                    \"astId\": 10359,\n                    \"contract\": \"contracts/vault/Vault.sol:Vault\",\n                    \"label\": \"sharedManaged\",\n                    \"offset\": 0,\n                    \"slot\": \"1\",\n                    \"type\": \"t_bytes32\"\n                }\n            ]\n        },\n        \"t_struct(TwoTokenPoolTokens)10369_storage\": {\n            \"encoding\": \"inplace\",\n            \"label\": \"struct TwoTokenPoolsBalance.TwoTokenPoolTokens\",\n            \"numberOfBytes\": \"96\",\n            \"members\": [\n                {\n                    \"astId\": 10362,\n                    \"contract\": \"contracts/vault/Vault.sol:Vault\",\n                    \"label\": \"tokenA\",\n                    \"offset\": 0,\n                    \"slot\": \"0\",\n                    \"type\": \"t_contract(IERC20)3793\"\n                },\n                {\n                    \"astId\": 10364,\n                    \"contract\": \"contracts/vault/Vault.sol:Vault\",\n                    \"label\": \"tokenB\",\n                    \"offset\": 0,\n                    \"slot\": \"1\",\n                    \"type\": \"t_contract(IERC20)3793\"\n                },\n                {\n                    \"astId\": 10368,\n                    \"contract\": \"contracts/vault/Vault.sol:Vault\",\n                    \"label\": \"balances\",\n                    \"offset\": 0,\n                    \"slot\": \"2\",\n                    \"type\": \"t_mapping(t_bytes32,t_struct(TwoTokenPoolBalances)10360_storage)\"\n                }\n            ]\n        },\n        \"t_uint256\": {\n            \"encoding\": \"inplace\",\n            \"label\": \"uint256\",\n            \"numberOfBytes\": \"32\"\n        }\n    },\n    \"values\": [\n        \"0x0000000000000000000000000000000000000000000000000000000000000001\",\n        \"0x0000000000000000000000000000000000000000000000000000000000000000\",\n        \"0x0000000000000000000000000000000000000000000000000000000000000000\",\n        \"0x0000000000000000000000000000000000000000000000000000000000000000\",\n        \"0x0000000000000000000000006048a8c631fb7e77eca533cf9c29784e482391e7\",\n        \"0x0000000000000000000000000000000000000000000000000000000000000000\",\n        \"0x0000000000000000000000000000000000000000000000000000000000000000\",\n        \"0x00000000000000000000000000000000000000000000000000000000000006e0\",\n        \"0x0000000000000000000000000000000000000000000000000000000000000000\",\n        \"0x0000000000000000000000000000000000000000000000000000000000000000\",\n        \"0x0000000000000000000000000000000000000000000000000000000000000000\",\n        \"0x0000000000000000000000000000000000000000000000000000000000000000\",\n        \"0x0000000000000000000000000000000000000000000000000000000000000000\"\n    ]\n}"
  },
  {
    "path": "crates/cast/tests/fixtures/storage_layout_simple.json",
    "content": "{\n    \"storage\": [\n        {\n            \"astId\": 7,\n            \"contract\": \"contracts/Create2Deployer.sol:Create2Deployer\",\n            \"label\": \"_owner\",\n            \"offset\": 0,\n            \"slot\": \"0\",\n            \"type\": \"t_address\"\n        },\n        {\n            \"astId\": 122,\n            \"contract\": \"contracts/Create2Deployer.sol:Create2Deployer\",\n            \"label\": \"_paused\",\n            \"offset\": 20,\n            \"slot\": \"0\",\n            \"type\": \"t_bool\"\n        }\n    ],\n    \"types\": {\n        \"t_address\": {\n            \"encoding\": \"inplace\",\n            \"label\": \"address\",\n            \"numberOfBytes\": \"20\"\n        },\n        \"t_bool\": {\n            \"encoding\": \"inplace\",\n            \"label\": \"bool\",\n            \"numberOfBytes\": \"1\"\n        }\n    },\n    \"values\": [\n        \"0x0000000000000000000000000000000000000000000000000000000000000000\",\n        \"0x0000000000000000000000000000000000000000000000000000000000000000\"\n    ]\n}"
  },
  {
    "path": "crates/cheatcodes/Cargo.toml",
    "content": "[package]\nname = \"foundry-cheatcodes\"\ndescription = \"Foundry cheatcodes definitions and implementations\"\n\nversion.workspace = true\nedition.workspace = true\nrust-version.workspace = true\nauthors.workspace = true\nlicense.workspace = true\nhomepage.workspace = true\nrepository.workspace = true\nexclude.workspace = true\n\n[lints]\nworkspace = true\n\n[dependencies]\nfoundry-cheatcodes-spec.workspace = true\nfoundry-common.workspace = true\nfoundry-compilers.workspace = true\nfoundry-config.workspace = true\nfoundry-evm-core.workspace = true\nfoundry-primitives.workspace = true\nfoundry-evm-fuzz.workspace = true\nfoundry-evm-traces.workspace = true\nfoundry-wallets.workspace = true\nforge-script-sequence.workspace = true\n\nsolar.workspace = true\n\nalloy-dyn-abi.workspace = true\nalloy-evm.workspace = true\nalloy-json-abi.workspace = true\nalloy-primitives.workspace = true\nalloy-genesis.workspace = true\nalloy-sol-types.workspace = true\nalloy-provider.workspace = true\nalloy-rpc-types = { workspace = true, features = [\"k256\"] }\nalloy-signer.workspace = true\nalloy-signer-local = { workspace = true, features = [\n    \"mnemonic-all-languages\",\n    \"keystore\",\n] }\nparking_lot.workspace = true\nalloy-consensus = { workspace = true, features = [\"k256\", \"kzg\"] }\nalloy-network.workspace = true\nalloy-rlp.workspace = true\nalloy-chains.workspace = true\nalloy-ens.workspace = true\n\nbase64.workspace = true\ndialoguer.workspace = true\neyre.workspace = true\nitertools.workspace = true\njsonpath_lib.workspace = true\nk256.workspace = true\nmemchr.workspace = true\np256 = \"0.13\"\ned25519-consensus = \"2.1\"\necdsa = \"0.16\"\nrand.workspace = true\nrevm.workspace = true\nrevm-inspectors.workspace = true\nsemver.workspace = true\nserde_json.workspace = true\nthiserror.workspace = true\ntoml = { workspace = true, features = [\"preserve_order\"] }\ntracing.workspace = true\nwalkdir.workspace = true\nproptest.workspace = true\nserde.workspace = true\n"
  },
  {
    "path": "crates/cheatcodes/README.md",
    "content": "# foundry-cheatcodes\n\nFoundry cheatcodes definitions and implementations.\n\n## Structure\n\n- [`assets/`](./assets/): JSON interface and specification\n- [`spec/`](./spec/src/lib.rs): Defines common traits and structs\n- [`src/`](./src/lib.rs): Rust implementations of the cheatcodes\n\n## Overview\n\nAll cheatcodes are defined in a single [`sol!`] macro call in [`spec/src/vm.rs`].\n\nThis, combined with the use of an internal [`Cheatcode`](../../crates/cheatcodes/spec/src/cheatcode.rs) derive macro,\nallows us to generate both the Rust definitions and the JSON specification of the cheatcodes.\n\nCheatcodes are manually implemented through the `Cheatcode` trait, which is called in the\n`Cheatcodes` inspector implementation.\n\nSee the [cheatcodes dev documentation](../../docs/dev/cheatcodes.md#cheatcodes-implementation) for more details.\n\n### JSON interface\n\nThe JSON interface is guaranteed to be stable, and can be used by third-party tools to interact with\nthe Foundry cheatcodes externally.\n\nFor example, here are some tools that make use of the JSON interface:\n\n- Internally, this is used to generate [a simple Solidity interface](../../testdata/cheats/Vm.sol) for testing\n- Used by [`forge-std`](https://github.com/foundry-rs/forge-std) to generate [user-friendly Solidity interfaces](https://github.com/foundry-rs/forge-std/blob/master/src/Vm.sol)\n- (WIP) Used by [the Foundry book](https://github.com/foundry-rs/book) to generate [the cheatcodes reference](https://book.getfoundry.sh/cheatcodes)\n- ...\n\nIf you are making use of the JSON interface, please don't hesitate to open a PR to add your project to this list!\n\n### Adding a new cheatcode\n\nPlease see the [cheatcodes dev documentation](../../docs/dev/cheatcodes.md#adding-a-new-cheatcode) on how to add new cheatcodes.\n\n[`sol!`]: https://docs.rs/alloy-sol-macro/latest/alloy_sol_macro/macro.sol.html\n[`spec/src/vm.rs`]: ./spec/src/vm.rs\n"
  },
  {
    "path": "crates/cheatcodes/assets/cheatcodes.json",
    "content": "{\n  \"errors\": [\n    {\n      \"name\": \"CheatcodeError\",\n      \"description\": \"Error thrown by cheatcodes.\",\n      \"declaration\": \"error CheatcodeError(string message);\"\n    }\n  ],\n  \"events\": [],\n  \"enums\": [\n    {\n      \"name\": \"CallerMode\",\n      \"description\": \"A modification applied to either `msg.sender` or `tx.origin`. Returned by `readCallers`.\",\n      \"variants\": [\n        {\n          \"name\": \"None\",\n          \"description\": \"No caller modification is currently active.\"\n        },\n        {\n          \"name\": \"Broadcast\",\n          \"description\": \"A one time broadcast triggered by a `vm.broadcast()` call is currently active.\"\n        },\n        {\n          \"name\": \"RecurrentBroadcast\",\n          \"description\": \"A recurrent broadcast triggered by a `vm.startBroadcast()` call is currently active.\"\n        },\n        {\n          \"name\": \"Prank\",\n          \"description\": \"A one time prank triggered by a `vm.prank()` call is currently active.\"\n        },\n        {\n          \"name\": \"RecurrentPrank\",\n          \"description\": \"A recurrent prank triggered by a `vm.startPrank()` call is currently active.\"\n        }\n      ]\n    },\n    {\n      \"name\": \"AccountAccessKind\",\n      \"description\": \"The kind of account access that occurred.\",\n      \"variants\": [\n        {\n          \"name\": \"Call\",\n          \"description\": \"The account was called.\"\n        },\n        {\n          \"name\": \"DelegateCall\",\n          \"description\": \"The account was called via delegatecall.\"\n        },\n        {\n          \"name\": \"CallCode\",\n          \"description\": \"The account was called via callcode.\"\n        },\n        {\n          \"name\": \"StaticCall\",\n          \"description\": \"The account was called via staticcall.\"\n        },\n        {\n          \"name\": \"Create\",\n          \"description\": \"The account was created.\"\n        },\n        {\n          \"name\": \"SelfDestruct\",\n          \"description\": \"The account was selfdestructed.\"\n        },\n        {\n          \"name\": \"Resume\",\n          \"description\": \"Synthetic access indicating the current context has resumed after a previous sub-context (AccountAccess).\"\n        },\n        {\n          \"name\": \"Balance\",\n          \"description\": \"The account's balance was read.\"\n        },\n        {\n          \"name\": \"Extcodesize\",\n          \"description\": \"The account's codesize was read.\"\n        },\n        {\n          \"name\": \"Extcodehash\",\n          \"description\": \"The account's codehash was read.\"\n        },\n        {\n          \"name\": \"Extcodecopy\",\n          \"description\": \"The account's code was copied.\"\n        }\n      ]\n    },\n    {\n      \"name\": \"ForgeContext\",\n      \"description\": \"Forge execution contexts.\",\n      \"variants\": [\n        {\n          \"name\": \"TestGroup\",\n          \"description\": \"Test group execution context (test, coverage or snapshot).\"\n        },\n        {\n          \"name\": \"Test\",\n          \"description\": \"`forge test` execution context.\"\n        },\n        {\n          \"name\": \"Coverage\",\n          \"description\": \"`forge coverage` execution context.\"\n        },\n        {\n          \"name\": \"Snapshot\",\n          \"description\": \"`forge snapshot` execution context.\"\n        },\n        {\n          \"name\": \"ScriptGroup\",\n          \"description\": \"Script group execution context (dry run, broadcast or resume).\"\n        },\n        {\n          \"name\": \"ScriptDryRun\",\n          \"description\": \"`forge script` execution context.\"\n        },\n        {\n          \"name\": \"ScriptBroadcast\",\n          \"description\": \"`forge script --broadcast` execution context.\"\n        },\n        {\n          \"name\": \"ScriptResume\",\n          \"description\": \"`forge script --resume` execution context.\"\n        },\n        {\n          \"name\": \"Unknown\",\n          \"description\": \"Unknown `forge` execution context.\"\n        }\n      ]\n    },\n    {\n      \"name\": \"BroadcastTxType\",\n      \"description\": \"The transaction type (`txType`) of the broadcast.\",\n      \"variants\": [\n        {\n          \"name\": \"Call\",\n          \"description\": \"Represents a CALL broadcast tx.\"\n        },\n        {\n          \"name\": \"Create\",\n          \"description\": \"Represents a CREATE broadcast tx.\"\n        },\n        {\n          \"name\": \"Create2\",\n          \"description\": \"Represents a CREATE2 broadcast tx.\"\n        }\n      ]\n    }\n  ],\n  \"structs\": [\n    {\n      \"name\": \"Log\",\n      \"description\": \"An Ethereum log. Returned by `getRecordedLogs`.\",\n      \"fields\": [\n        {\n          \"name\": \"topics\",\n          \"ty\": \"bytes32[]\",\n          \"description\": \"The topics of the log, including the signature, if any.\"\n        },\n        {\n          \"name\": \"data\",\n          \"ty\": \"bytes\",\n          \"description\": \"The raw data of the log.\"\n        },\n        {\n          \"name\": \"emitter\",\n          \"ty\": \"address\",\n          \"description\": \"The address of the log's emitter.\"\n        }\n      ]\n    },\n    {\n      \"name\": \"Rpc\",\n      \"description\": \"An RPC URL and its alias. Returned by `rpcUrlStructs`.\",\n      \"fields\": [\n        {\n          \"name\": \"key\",\n          \"ty\": \"string\",\n          \"description\": \"The alias of the RPC URL.\"\n        },\n        {\n          \"name\": \"url\",\n          \"ty\": \"string\",\n          \"description\": \"The RPC URL.\"\n        }\n      ]\n    },\n    {\n      \"name\": \"EthGetLogs\",\n      \"description\": \"An RPC log object. Returned by `eth_getLogs`.\",\n      \"fields\": [\n        {\n          \"name\": \"emitter\",\n          \"ty\": \"address\",\n          \"description\": \"The address of the log's emitter.\"\n        },\n        {\n          \"name\": \"topics\",\n          \"ty\": \"bytes32[]\",\n          \"description\": \"The topics of the log, including the signature, if any.\"\n        },\n        {\n          \"name\": \"data\",\n          \"ty\": \"bytes\",\n          \"description\": \"The raw data of the log.\"\n        },\n        {\n          \"name\": \"blockHash\",\n          \"ty\": \"bytes32\",\n          \"description\": \"The block hash.\"\n        },\n        {\n          \"name\": \"blockNumber\",\n          \"ty\": \"uint64\",\n          \"description\": \"The block number.\"\n        },\n        {\n          \"name\": \"transactionHash\",\n          \"ty\": \"bytes32\",\n          \"description\": \"The transaction hash.\"\n        },\n        {\n          \"name\": \"transactionIndex\",\n          \"ty\": \"uint64\",\n          \"description\": \"The transaction index in the block.\"\n        },\n        {\n          \"name\": \"logIndex\",\n          \"ty\": \"uint256\",\n          \"description\": \"The log index.\"\n        },\n        {\n          \"name\": \"removed\",\n          \"ty\": \"bool\",\n          \"description\": \"Whether the log was removed.\"\n        }\n      ]\n    },\n    {\n      \"name\": \"DirEntry\",\n      \"description\": \"A single entry in a directory listing. Returned by `readDir`.\",\n      \"fields\": [\n        {\n          \"name\": \"errorMessage\",\n          \"ty\": \"string\",\n          \"description\": \"The error message, if any.\"\n        },\n        {\n          \"name\": \"path\",\n          \"ty\": \"string\",\n          \"description\": \"The path of the entry.\"\n        },\n        {\n          \"name\": \"depth\",\n          \"ty\": \"uint64\",\n          \"description\": \"The depth of the entry.\"\n        },\n        {\n          \"name\": \"isDir\",\n          \"ty\": \"bool\",\n          \"description\": \"Whether the entry is a directory.\"\n        },\n        {\n          \"name\": \"isSymlink\",\n          \"ty\": \"bool\",\n          \"description\": \"Whether the entry is a symlink.\"\n        }\n      ]\n    },\n    {\n      \"name\": \"FsMetadata\",\n      \"description\": \"Metadata information about a file.\\n This structure is returned from the `fsMetadata` function and represents known\\n metadata about a file such as its permissions, size, modification\\n times, etc.\",\n      \"fields\": [\n        {\n          \"name\": \"isDir\",\n          \"ty\": \"bool\",\n          \"description\": \"True if this metadata is for a directory.\"\n        },\n        {\n          \"name\": \"isSymlink\",\n          \"ty\": \"bool\",\n          \"description\": \"True if this metadata is for a symlink.\"\n        },\n        {\n          \"name\": \"length\",\n          \"ty\": \"uint256\",\n          \"description\": \"The size of the file, in bytes, this metadata is for.\"\n        },\n        {\n          \"name\": \"readOnly\",\n          \"ty\": \"bool\",\n          \"description\": \"True if this metadata is for a readonly (unwritable) file.\"\n        },\n        {\n          \"name\": \"modified\",\n          \"ty\": \"uint256\",\n          \"description\": \"The last modification time listed in this metadata.\"\n        },\n        {\n          \"name\": \"accessed\",\n          \"ty\": \"uint256\",\n          \"description\": \"The last access time of this metadata.\"\n        },\n        {\n          \"name\": \"created\",\n          \"ty\": \"uint256\",\n          \"description\": \"The creation time listed in this metadata.\"\n        }\n      ]\n    },\n    {\n      \"name\": \"Wallet\",\n      \"description\": \"A wallet with a public and private key.\",\n      \"fields\": [\n        {\n          \"name\": \"addr\",\n          \"ty\": \"address\",\n          \"description\": \"The wallet's address.\"\n        },\n        {\n          \"name\": \"publicKeyX\",\n          \"ty\": \"uint256\",\n          \"description\": \"The wallet's public key `X`.\"\n        },\n        {\n          \"name\": \"publicKeyY\",\n          \"ty\": \"uint256\",\n          \"description\": \"The wallet's public key `Y`.\"\n        },\n        {\n          \"name\": \"privateKey\",\n          \"ty\": \"uint256\",\n          \"description\": \"The wallet's private key.\"\n        }\n      ]\n    },\n    {\n      \"name\": \"FfiResult\",\n      \"description\": \"The result of a `tryFfi` call.\",\n      \"fields\": [\n        {\n          \"name\": \"exitCode\",\n          \"ty\": \"int32\",\n          \"description\": \"The exit code of the call.\"\n        },\n        {\n          \"name\": \"stdout\",\n          \"ty\": \"bytes\",\n          \"description\": \"The optionally hex-decoded `stdout` data.\"\n        },\n        {\n          \"name\": \"stderr\",\n          \"ty\": \"bytes\",\n          \"description\": \"The `stderr` data.\"\n        }\n      ]\n    },\n    {\n      \"name\": \"ChainInfo\",\n      \"description\": \"Information on the chain and fork.\",\n      \"fields\": [\n        {\n          \"name\": \"forkId\",\n          \"ty\": \"uint256\",\n          \"description\": \"The fork identifier. Set to zero if no fork is active.\"\n        },\n        {\n          \"name\": \"chainId\",\n          \"ty\": \"uint256\",\n          \"description\": \"The chain ID of the current fork.\"\n        }\n      ]\n    },\n    {\n      \"name\": \"Chain\",\n      \"description\": \"Information about a blockchain.\",\n      \"fields\": [\n        {\n          \"name\": \"name\",\n          \"ty\": \"string\",\n          \"description\": \"The chain name.\"\n        },\n        {\n          \"name\": \"chainId\",\n          \"ty\": \"uint256\",\n          \"description\": \"The chain's Chain ID.\"\n        },\n        {\n          \"name\": \"chainAlias\",\n          \"ty\": \"string\",\n          \"description\": \"The chain's alias. (i.e. what gets specified in `foundry.toml`).\"\n        },\n        {\n          \"name\": \"rpcUrl\",\n          \"ty\": \"string\",\n          \"description\": \"A default RPC endpoint for this chain.\"\n        }\n      ]\n    },\n    {\n      \"name\": \"AccountAccess\",\n      \"description\": \"The result of a `stopAndReturnStateDiff` call.\",\n      \"fields\": [\n        {\n          \"name\": \"chainInfo\",\n          \"ty\": \"ChainInfo\",\n          \"description\": \"The chain and fork the access occurred.\"\n        },\n        {\n          \"name\": \"kind\",\n          \"ty\": \"AccountAccessKind\",\n          \"description\": \"The kind of account access that determines what the account is.\\n If kind is Call, DelegateCall, StaticCall or CallCode, then the account is the callee.\\n If kind is Create, then the account is the newly created account.\\n If kind is SelfDestruct, then the account is the selfdestruct recipient.\\n If kind is a Resume, then account represents a account context that has resumed.\"\n        },\n        {\n          \"name\": \"account\",\n          \"ty\": \"address\",\n          \"description\": \"The account that was accessed.\\n It's either the account created, callee or a selfdestruct recipient for CREATE, CALL or SELFDESTRUCT.\"\n        },\n        {\n          \"name\": \"accessor\",\n          \"ty\": \"address\",\n          \"description\": \"What accessed the account.\"\n        },\n        {\n          \"name\": \"initialized\",\n          \"ty\": \"bool\",\n          \"description\": \"If the account was initialized or empty prior to the access.\\n An account is considered initialized if it has code, a\\n non-zero nonce, or a non-zero balance.\"\n        },\n        {\n          \"name\": \"oldBalance\",\n          \"ty\": \"uint256\",\n          \"description\": \"The previous balance of the accessed account.\"\n        },\n        {\n          \"name\": \"newBalance\",\n          \"ty\": \"uint256\",\n          \"description\": \"The potential new balance of the accessed account.\\n That is, all balance changes are recorded here, even if reverts occurred.\"\n        },\n        {\n          \"name\": \"deployedCode\",\n          \"ty\": \"bytes\",\n          \"description\": \"Code of the account deployed by CREATE.\"\n        },\n        {\n          \"name\": \"value\",\n          \"ty\": \"uint256\",\n          \"description\": \"Value passed along with the account access\"\n        },\n        {\n          \"name\": \"data\",\n          \"ty\": \"bytes\",\n          \"description\": \"Input data provided to the CREATE or CALL\"\n        },\n        {\n          \"name\": \"reverted\",\n          \"ty\": \"bool\",\n          \"description\": \"If this access reverted in either the current or parent context.\"\n        },\n        {\n          \"name\": \"storageAccesses\",\n          \"ty\": \"StorageAccess[]\",\n          \"description\": \"An ordered list of storage accesses made during an account access operation.\"\n        },\n        {\n          \"name\": \"depth\",\n          \"ty\": \"uint64\",\n          \"description\": \"Call depth traversed during the recording of state differences\"\n        },\n        {\n          \"name\": \"oldNonce\",\n          \"ty\": \"uint64\",\n          \"description\": \"The previous nonce of the accessed account.\"\n        },\n        {\n          \"name\": \"newNonce\",\n          \"ty\": \"uint64\",\n          \"description\": \"The new nonce of the accessed account.\"\n        }\n      ]\n    },\n    {\n      \"name\": \"StorageAccess\",\n      \"description\": \"The storage accessed during an `AccountAccess`.\",\n      \"fields\": [\n        {\n          \"name\": \"account\",\n          \"ty\": \"address\",\n          \"description\": \"The account whose storage was accessed.\"\n        },\n        {\n          \"name\": \"slot\",\n          \"ty\": \"bytes32\",\n          \"description\": \"The slot that was accessed.\"\n        },\n        {\n          \"name\": \"isWrite\",\n          \"ty\": \"bool\",\n          \"description\": \"If the access was a write.\"\n        },\n        {\n          \"name\": \"previousValue\",\n          \"ty\": \"bytes32\",\n          \"description\": \"The previous value of the slot.\"\n        },\n        {\n          \"name\": \"newValue\",\n          \"ty\": \"bytes32\",\n          \"description\": \"The new value of the slot.\"\n        },\n        {\n          \"name\": \"reverted\",\n          \"ty\": \"bool\",\n          \"description\": \"If the access was reverted.\"\n        }\n      ]\n    },\n    {\n      \"name\": \"Gas\",\n      \"description\": \"Gas used. Returned by `lastCallGas`.\",\n      \"fields\": [\n        {\n          \"name\": \"gasLimit\",\n          \"ty\": \"uint64\",\n          \"description\": \"The gas limit of the call.\"\n        },\n        {\n          \"name\": \"gasTotalUsed\",\n          \"ty\": \"uint64\",\n          \"description\": \"The total gas used.\"\n        },\n        {\n          \"name\": \"gasMemoryUsed\",\n          \"ty\": \"uint64\",\n          \"description\": \"DEPRECATED: The amount of gas used for memory expansion. Ref: <https://github.com/foundry-rs/foundry/pull/7934#pullrequestreview-2069236939>\"\n        },\n        {\n          \"name\": \"gasRefunded\",\n          \"ty\": \"int64\",\n          \"description\": \"The amount of gas refunded.\"\n        },\n        {\n          \"name\": \"gasRemaining\",\n          \"ty\": \"uint64\",\n          \"description\": \"The amount of gas remaining.\"\n        }\n      ]\n    },\n    {\n      \"name\": \"DebugStep\",\n      \"description\": \"The result of the `stopDebugTraceRecording` call\",\n      \"fields\": [\n        {\n          \"name\": \"stack\",\n          \"ty\": \"uint256[]\",\n          \"description\": \"The stack before executing the step of the run.\\n stack\\\\[0\\\\] represents the top of the stack.\\n and only stack data relevant to the opcode execution is contained.\"\n        },\n        {\n          \"name\": \"memoryInput\",\n          \"ty\": \"bytes\",\n          \"description\": \"The memory input data before executing the step of the run.\\n only input data relevant to the opcode execution is contained.\\n e.g. for MLOAD, it will have memory\\\\[offset:offset+32\\\\] copied here.\\n the offset value can be get by the stack data.\"\n        },\n        {\n          \"name\": \"opcode\",\n          \"ty\": \"uint8\",\n          \"description\": \"The opcode that was accessed.\"\n        },\n        {\n          \"name\": \"depth\",\n          \"ty\": \"uint64\",\n          \"description\": \"The call depth of the step.\"\n        },\n        {\n          \"name\": \"isOutOfGas\",\n          \"ty\": \"bool\",\n          \"description\": \"Whether the call end up with out of gas error.\"\n        },\n        {\n          \"name\": \"contractAddr\",\n          \"ty\": \"address\",\n          \"description\": \"The contract address where the opcode is running\"\n        }\n      ]\n    },\n    {\n      \"name\": \"BroadcastTxSummary\",\n      \"description\": \"Represents a transaction's broadcast details.\",\n      \"fields\": [\n        {\n          \"name\": \"txHash\",\n          \"ty\": \"bytes32\",\n          \"description\": \"The hash of the transaction that was broadcasted\"\n        },\n        {\n          \"name\": \"txType\",\n          \"ty\": \"BroadcastTxType\",\n          \"description\": \"Represent the type of transaction among CALL, CREATE, CREATE2\"\n        },\n        {\n          \"name\": \"contractAddress\",\n          \"ty\": \"address\",\n          \"description\": \"The address of the contract that was called or created.\\n This is address of the contract that is created if the txType is CREATE or CREATE2.\"\n        },\n        {\n          \"name\": \"blockNumber\",\n          \"ty\": \"uint64\",\n          \"description\": \"The block number the transaction landed in.\"\n        },\n        {\n          \"name\": \"success\",\n          \"ty\": \"bool\",\n          \"description\": \"Status of the transaction, retrieved from the transaction receipt.\"\n        }\n      ]\n    },\n    {\n      \"name\": \"SignedDelegation\",\n      \"description\": \"Holds a signed EIP-7702 authorization for an authority account to delegate to an implementation.\",\n      \"fields\": [\n        {\n          \"name\": \"v\",\n          \"ty\": \"uint8\",\n          \"description\": \"The y-parity of the recovered secp256k1 signature (0 or 1).\"\n        },\n        {\n          \"name\": \"r\",\n          \"ty\": \"bytes32\",\n          \"description\": \"First 32 bytes of the signature.\"\n        },\n        {\n          \"name\": \"s\",\n          \"ty\": \"bytes32\",\n          \"description\": \"Second 32 bytes of the signature.\"\n        },\n        {\n          \"name\": \"nonce\",\n          \"ty\": \"uint64\",\n          \"description\": \"The current nonce of the authority account at signing time.\\n Used to ensure signature can't be replayed after account nonce changes.\"\n        },\n        {\n          \"name\": \"implementation\",\n          \"ty\": \"address\",\n          \"description\": \"Address of the contract implementation that will be delegated to.\\n Gets encoded into delegation code: 0xef0100 || implementation.\"\n        }\n      ]\n    },\n    {\n      \"name\": \"PotentialRevert\",\n      \"description\": \"Represents a \\\"potential\\\" revert reason from a single subsequent call when using `vm.assumeNoReverts`.\\n Reverts that match will result in a FOUNDRY::ASSUME rejection, whereas unmatched reverts will be surfaced\\n as normal.\",\n      \"fields\": [\n        {\n          \"name\": \"reverter\",\n          \"ty\": \"address\",\n          \"description\": \"The allowed origin of the revert opcode; address(0) allows reverts from any address\"\n        },\n        {\n          \"name\": \"partialMatch\",\n          \"ty\": \"bool\",\n          \"description\": \"When true, only matches on the beginning of the revert data, otherwise, matches on entire revert data\"\n        },\n        {\n          \"name\": \"revertData\",\n          \"ty\": \"bytes\",\n          \"description\": \"The data to use to match encountered reverts\"\n        }\n      ]\n    },\n    {\n      \"name\": \"AccessListItem\",\n      \"description\": \"An EIP-2930 access list item.\",\n      \"fields\": [\n        {\n          \"name\": \"target\",\n          \"ty\": \"address\",\n          \"description\": \"The address to be added in access list.\"\n        },\n        {\n          \"name\": \"storageKeys\",\n          \"ty\": \"bytes32[]\",\n          \"description\": \"The storage keys to be added in access list.\"\n        }\n      ]\n    }\n  ],\n  \"cheatcodes\": [\n    {\n      \"func\": {\n        \"id\": \"_expectCheatcodeRevert_0\",\n        \"description\": \"Expects an error on next cheatcode call with any revert data.\",\n        \"declaration\": \"function _expectCheatcodeRevert() external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"_expectCheatcodeRevert()\",\n        \"selector\": \"0x79a4f48a\",\n        \"selectorBytes\": [\n          121,\n          164,\n          244,\n          138\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"internal\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"_expectCheatcodeRevert_1\",\n        \"description\": \"Expects an error on next cheatcode call that starts with the revert data.\",\n        \"declaration\": \"function _expectCheatcodeRevert(bytes4 revertData) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"_expectCheatcodeRevert(bytes4)\",\n        \"selector\": \"0x884cb0ae\",\n        \"selectorBytes\": [\n          136,\n          76,\n          176,\n          174\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"internal\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"_expectCheatcodeRevert_2\",\n        \"description\": \"Expects an error on next cheatcode call that exactly matches the revert data.\",\n        \"declaration\": \"function _expectCheatcodeRevert(bytes calldata revertData) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"_expectCheatcodeRevert(bytes)\",\n        \"selector\": \"0x7843b44d\",\n        \"selectorBytes\": [\n          120,\n          67,\n          180,\n          77\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"internal\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"accessList\",\n        \"description\": \"Utility cheatcode to set an EIP-2930 access list for all subsequent transactions.\",\n        \"declaration\": \"function accessList(AccessListItem[] calldata access) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"accessList((address,bytes32[])[])\",\n        \"selector\": \"0x743e4cb7\",\n        \"selectorBytes\": [\n          116,\n          62,\n          76,\n          183\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"accesses\",\n        \"description\": \"Gets all accessed reads and write slot from a `vm.record` session, for a given address.\",\n        \"declaration\": \"function accesses(address target) external view returns (bytes32[] memory readSlots, bytes32[] memory writeSlots);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"accesses(address)\",\n        \"selector\": \"0x65bc9481\",\n        \"selectorBytes\": [\n          101,\n          188,\n          148,\n          129\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"activeFork\",\n        \"description\": \"Returns the identifier of the currently active fork. Reverts if no fork is currently active.\",\n        \"declaration\": \"function activeFork() external view returns (uint256 forkId);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"activeFork()\",\n        \"selector\": \"0x2f103f22\",\n        \"selectorBytes\": [\n          47,\n          16,\n          63,\n          34\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"addr\",\n        \"description\": \"Gets the address for a given private key.\",\n        \"declaration\": \"function addr(uint256 privateKey) external pure returns (address keyAddr);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"addr(uint256)\",\n        \"selector\": \"0xffa18649\",\n        \"selectorBytes\": [\n          255,\n          161,\n          134,\n          73\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"allowCheatcodes\",\n        \"description\": \"In forking mode, explicitly grant the given address cheatcode access.\",\n        \"declaration\": \"function allowCheatcodes(address account) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"allowCheatcodes(address)\",\n        \"selector\": \"0xea060291\",\n        \"selectorBytes\": [\n          234,\n          6,\n          2,\n          145\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertApproxEqAbsDecimal_0\",\n        \"description\": \"Compares two `uint256` values. Expects difference to be less than or equal to `maxDelta`.\\nFormats values with decimals in failure message.\",\n        \"declaration\": \"function assertApproxEqAbsDecimal(uint256 left, uint256 right, uint256 maxDelta, uint256 decimals) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertApproxEqAbsDecimal(uint256,uint256,uint256,uint256)\",\n        \"selector\": \"0x045c55ce\",\n        \"selectorBytes\": [\n          4,\n          92,\n          85,\n          206\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertApproxEqAbsDecimal_1\",\n        \"description\": \"Compares two `uint256` values. Expects difference to be less than or equal to `maxDelta`.\\nFormats values with decimals in failure message. Includes error message into revert string on failure.\",\n        \"declaration\": \"function assertApproxEqAbsDecimal(uint256 left, uint256 right, uint256 maxDelta, uint256 decimals, string calldata error) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertApproxEqAbsDecimal(uint256,uint256,uint256,uint256,string)\",\n        \"selector\": \"0x60429eb2\",\n        \"selectorBytes\": [\n          96,\n          66,\n          158,\n          178\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertApproxEqAbsDecimal_2\",\n        \"description\": \"Compares two `int256` values. Expects difference to be less than or equal to `maxDelta`.\\nFormats values with decimals in failure message.\",\n        \"declaration\": \"function assertApproxEqAbsDecimal(int256 left, int256 right, uint256 maxDelta, uint256 decimals) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertApproxEqAbsDecimal(int256,int256,uint256,uint256)\",\n        \"selector\": \"0x3d5bc8bc\",\n        \"selectorBytes\": [\n          61,\n          91,\n          200,\n          188\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertApproxEqAbsDecimal_3\",\n        \"description\": \"Compares two `int256` values. Expects difference to be less than or equal to `maxDelta`.\\nFormats values with decimals in failure message. Includes error message into revert string on failure.\",\n        \"declaration\": \"function assertApproxEqAbsDecimal(int256 left, int256 right, uint256 maxDelta, uint256 decimals, string calldata error) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertApproxEqAbsDecimal(int256,int256,uint256,uint256,string)\",\n        \"selector\": \"0x6a5066d4\",\n        \"selectorBytes\": [\n          106,\n          80,\n          102,\n          212\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertApproxEqAbs_0\",\n        \"description\": \"Compares two `uint256` values. Expects difference to be less than or equal to `maxDelta`.\",\n        \"declaration\": \"function assertApproxEqAbs(uint256 left, uint256 right, uint256 maxDelta) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertApproxEqAbs(uint256,uint256,uint256)\",\n        \"selector\": \"0x16d207c6\",\n        \"selectorBytes\": [\n          22,\n          210,\n          7,\n          198\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertApproxEqAbs_1\",\n        \"description\": \"Compares two `uint256` values. Expects difference to be less than or equal to `maxDelta`.\\nIncludes error message into revert string on failure.\",\n        \"declaration\": \"function assertApproxEqAbs(uint256 left, uint256 right, uint256 maxDelta, string calldata error) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertApproxEqAbs(uint256,uint256,uint256,string)\",\n        \"selector\": \"0xf710b062\",\n        \"selectorBytes\": [\n          247,\n          16,\n          176,\n          98\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertApproxEqAbs_2\",\n        \"description\": \"Compares two `int256` values. Expects difference to be less than or equal to `maxDelta`.\",\n        \"declaration\": \"function assertApproxEqAbs(int256 left, int256 right, uint256 maxDelta) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertApproxEqAbs(int256,int256,uint256)\",\n        \"selector\": \"0x240f839d\",\n        \"selectorBytes\": [\n          36,\n          15,\n          131,\n          157\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertApproxEqAbs_3\",\n        \"description\": \"Compares two `int256` values. Expects difference to be less than or equal to `maxDelta`.\\nIncludes error message into revert string on failure.\",\n        \"declaration\": \"function assertApproxEqAbs(int256 left, int256 right, uint256 maxDelta, string calldata error) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertApproxEqAbs(int256,int256,uint256,string)\",\n        \"selector\": \"0x8289e621\",\n        \"selectorBytes\": [\n          130,\n          137,\n          230,\n          33\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertApproxEqRelDecimal_0\",\n        \"description\": \"Compares two `uint256` values. Expects relative difference in percents to be less than or equal to `maxPercentDelta`.\\n`maxPercentDelta` is an 18 decimal fixed point number, where 1e18 == 100%\\nFormats values with decimals in failure message.\",\n        \"declaration\": \"function assertApproxEqRelDecimal(uint256 left, uint256 right, uint256 maxPercentDelta, uint256 decimals) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertApproxEqRelDecimal(uint256,uint256,uint256,uint256)\",\n        \"selector\": \"0x21ed2977\",\n        \"selectorBytes\": [\n          33,\n          237,\n          41,\n          119\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertApproxEqRelDecimal_1\",\n        \"description\": \"Compares two `uint256` values. Expects relative difference in percents to be less than or equal to `maxPercentDelta`.\\n`maxPercentDelta` is an 18 decimal fixed point number, where 1e18 == 100%\\nFormats values with decimals in failure message. Includes error message into revert string on failure.\",\n        \"declaration\": \"function assertApproxEqRelDecimal(uint256 left, uint256 right, uint256 maxPercentDelta, uint256 decimals, string calldata error) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertApproxEqRelDecimal(uint256,uint256,uint256,uint256,string)\",\n        \"selector\": \"0x82d6c8fd\",\n        \"selectorBytes\": [\n          130,\n          214,\n          200,\n          253\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertApproxEqRelDecimal_2\",\n        \"description\": \"Compares two `int256` values. Expects relative difference in percents to be less than or equal to `maxPercentDelta`.\\n`maxPercentDelta` is an 18 decimal fixed point number, where 1e18 == 100%\\nFormats values with decimals in failure message.\",\n        \"declaration\": \"function assertApproxEqRelDecimal(int256 left, int256 right, uint256 maxPercentDelta, uint256 decimals) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertApproxEqRelDecimal(int256,int256,uint256,uint256)\",\n        \"selector\": \"0xabbf21cc\",\n        \"selectorBytes\": [\n          171,\n          191,\n          33,\n          204\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertApproxEqRelDecimal_3\",\n        \"description\": \"Compares two `int256` values. Expects relative difference in percents to be less than or equal to `maxPercentDelta`.\\n`maxPercentDelta` is an 18 decimal fixed point number, where 1e18 == 100%\\nFormats values with decimals in failure message. Includes error message into revert string on failure.\",\n        \"declaration\": \"function assertApproxEqRelDecimal(int256 left, int256 right, uint256 maxPercentDelta, uint256 decimals, string calldata error) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertApproxEqRelDecimal(int256,int256,uint256,uint256,string)\",\n        \"selector\": \"0xfccc11c4\",\n        \"selectorBytes\": [\n          252,\n          204,\n          17,\n          196\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertApproxEqRel_0\",\n        \"description\": \"Compares two `uint256` values. Expects relative difference in percents to be less than or equal to `maxPercentDelta`.\\n`maxPercentDelta` is an 18 decimal fixed point number, where 1e18 == 100%\",\n        \"declaration\": \"function assertApproxEqRel(uint256 left, uint256 right, uint256 maxPercentDelta) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertApproxEqRel(uint256,uint256,uint256)\",\n        \"selector\": \"0x8cf25ef4\",\n        \"selectorBytes\": [\n          140,\n          242,\n          94,\n          244\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertApproxEqRel_1\",\n        \"description\": \"Compares two `uint256` values. Expects relative difference in percents to be less than or equal to `maxPercentDelta`.\\n`maxPercentDelta` is an 18 decimal fixed point number, where 1e18 == 100%\\nIncludes error message into revert string on failure.\",\n        \"declaration\": \"function assertApproxEqRel(uint256 left, uint256 right, uint256 maxPercentDelta, string calldata error) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertApproxEqRel(uint256,uint256,uint256,string)\",\n        \"selector\": \"0x1ecb7d33\",\n        \"selectorBytes\": [\n          30,\n          203,\n          125,\n          51\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertApproxEqRel_2\",\n        \"description\": \"Compares two `int256` values. Expects relative difference in percents to be less than or equal to `maxPercentDelta`.\\n`maxPercentDelta` is an 18 decimal fixed point number, where 1e18 == 100%\",\n        \"declaration\": \"function assertApproxEqRel(int256 left, int256 right, uint256 maxPercentDelta) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertApproxEqRel(int256,int256,uint256)\",\n        \"selector\": \"0xfea2d14f\",\n        \"selectorBytes\": [\n          254,\n          162,\n          209,\n          79\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertApproxEqRel_3\",\n        \"description\": \"Compares two `int256` values. Expects relative difference in percents to be less than or equal to `maxPercentDelta`.\\n`maxPercentDelta` is an 18 decimal fixed point number, where 1e18 == 100%\\nIncludes error message into revert string on failure.\",\n        \"declaration\": \"function assertApproxEqRel(int256 left, int256 right, uint256 maxPercentDelta, string calldata error) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertApproxEqRel(int256,int256,uint256,string)\",\n        \"selector\": \"0xef277d72\",\n        \"selectorBytes\": [\n          239,\n          39,\n          125,\n          114\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertEqDecimal_0\",\n        \"description\": \"Asserts that two `uint256` values are equal, formatting them with decimals in failure message.\",\n        \"declaration\": \"function assertEqDecimal(uint256 left, uint256 right, uint256 decimals) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertEqDecimal(uint256,uint256,uint256)\",\n        \"selector\": \"0x27af7d9c\",\n        \"selectorBytes\": [\n          39,\n          175,\n          125,\n          156\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertEqDecimal_1\",\n        \"description\": \"Asserts that two `uint256` values are equal, formatting them with decimals in failure message.\\nIncludes error message into revert string on failure.\",\n        \"declaration\": \"function assertEqDecimal(uint256 left, uint256 right, uint256 decimals, string calldata error) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertEqDecimal(uint256,uint256,uint256,string)\",\n        \"selector\": \"0xd0cbbdef\",\n        \"selectorBytes\": [\n          208,\n          203,\n          189,\n          239\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertEqDecimal_2\",\n        \"description\": \"Asserts that two `int256` values are equal, formatting them with decimals in failure message.\",\n        \"declaration\": \"function assertEqDecimal(int256 left, int256 right, uint256 decimals) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertEqDecimal(int256,int256,uint256)\",\n        \"selector\": \"0x48016c04\",\n        \"selectorBytes\": [\n          72,\n          1,\n          108,\n          4\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertEqDecimal_3\",\n        \"description\": \"Asserts that two `int256` values are equal, formatting them with decimals in failure message.\\nIncludes error message into revert string on failure.\",\n        \"declaration\": \"function assertEqDecimal(int256 left, int256 right, uint256 decimals, string calldata error) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertEqDecimal(int256,int256,uint256,string)\",\n        \"selector\": \"0x7e77b0c5\",\n        \"selectorBytes\": [\n          126,\n          119,\n          176,\n          197\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertEq_0\",\n        \"description\": \"Asserts that two `bool` values are equal.\",\n        \"declaration\": \"function assertEq(bool left, bool right) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertEq(bool,bool)\",\n        \"selector\": \"0xf7fe3477\",\n        \"selectorBytes\": [\n          247,\n          254,\n          52,\n          119\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertEq_1\",\n        \"description\": \"Asserts that two `bool` values are equal and includes error message into revert string on failure.\",\n        \"declaration\": \"function assertEq(bool left, bool right, string calldata error) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertEq(bool,bool,string)\",\n        \"selector\": \"0x4db19e7e\",\n        \"selectorBytes\": [\n          77,\n          177,\n          158,\n          126\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertEq_10\",\n        \"description\": \"Asserts that two `string` values are equal.\",\n        \"declaration\": \"function assertEq(string calldata left, string calldata right) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertEq(string,string)\",\n        \"selector\": \"0xf320d963\",\n        \"selectorBytes\": [\n          243,\n          32,\n          217,\n          99\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertEq_11\",\n        \"description\": \"Asserts that two `string` values are equal and includes error message into revert string on failure.\",\n        \"declaration\": \"function assertEq(string calldata left, string calldata right, string calldata error) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertEq(string,string,string)\",\n        \"selector\": \"0x36f656d8\",\n        \"selectorBytes\": [\n          54,\n          246,\n          86,\n          216\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertEq_12\",\n        \"description\": \"Asserts that two `bytes` values are equal.\",\n        \"declaration\": \"function assertEq(bytes calldata left, bytes calldata right) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertEq(bytes,bytes)\",\n        \"selector\": \"0x97624631\",\n        \"selectorBytes\": [\n          151,\n          98,\n          70,\n          49\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertEq_13\",\n        \"description\": \"Asserts that two `bytes` values are equal and includes error message into revert string on failure.\",\n        \"declaration\": \"function assertEq(bytes calldata left, bytes calldata right, string calldata error) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertEq(bytes,bytes,string)\",\n        \"selector\": \"0xe24fed00\",\n        \"selectorBytes\": [\n          226,\n          79,\n          237,\n          0\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertEq_14\",\n        \"description\": \"Asserts that two arrays of `bool` values are equal.\",\n        \"declaration\": \"function assertEq(bool[] calldata left, bool[] calldata right) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertEq(bool[],bool[])\",\n        \"selector\": \"0x707df785\",\n        \"selectorBytes\": [\n          112,\n          125,\n          247,\n          133\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertEq_15\",\n        \"description\": \"Asserts that two arrays of `bool` values are equal and includes error message into revert string on failure.\",\n        \"declaration\": \"function assertEq(bool[] calldata left, bool[] calldata right, string calldata error) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertEq(bool[],bool[],string)\",\n        \"selector\": \"0xe48a8f8d\",\n        \"selectorBytes\": [\n          228,\n          138,\n          143,\n          141\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertEq_16\",\n        \"description\": \"Asserts that two arrays of `uint256 values are equal.\",\n        \"declaration\": \"function assertEq(uint256[] calldata left, uint256[] calldata right) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertEq(uint256[],uint256[])\",\n        \"selector\": \"0x975d5a12\",\n        \"selectorBytes\": [\n          151,\n          93,\n          90,\n          18\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertEq_17\",\n        \"description\": \"Asserts that two arrays of `uint256` values are equal and includes error message into revert string on failure.\",\n        \"declaration\": \"function assertEq(uint256[] calldata left, uint256[] calldata right, string calldata error) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertEq(uint256[],uint256[],string)\",\n        \"selector\": \"0x5d18c73a\",\n        \"selectorBytes\": [\n          93,\n          24,\n          199,\n          58\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertEq_18\",\n        \"description\": \"Asserts that two arrays of `int256` values are equal.\",\n        \"declaration\": \"function assertEq(int256[] calldata left, int256[] calldata right) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertEq(int256[],int256[])\",\n        \"selector\": \"0x711043ac\",\n        \"selectorBytes\": [\n          113,\n          16,\n          67,\n          172\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertEq_19\",\n        \"description\": \"Asserts that two arrays of `int256` values are equal and includes error message into revert string on failure.\",\n        \"declaration\": \"function assertEq(int256[] calldata left, int256[] calldata right, string calldata error) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertEq(int256[],int256[],string)\",\n        \"selector\": \"0x191f1b30\",\n        \"selectorBytes\": [\n          25,\n          31,\n          27,\n          48\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertEq_2\",\n        \"description\": \"Asserts that two `uint256` values are equal.\",\n        \"declaration\": \"function assertEq(uint256 left, uint256 right) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertEq(uint256,uint256)\",\n        \"selector\": \"0x98296c54\",\n        \"selectorBytes\": [\n          152,\n          41,\n          108,\n          84\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertEq_20\",\n        \"description\": \"Asserts that two arrays of `address` values are equal.\",\n        \"declaration\": \"function assertEq(address[] calldata left, address[] calldata right) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertEq(address[],address[])\",\n        \"selector\": \"0x3868ac34\",\n        \"selectorBytes\": [\n          56,\n          104,\n          172,\n          52\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertEq_21\",\n        \"description\": \"Asserts that two arrays of `address` values are equal and includes error message into revert string on failure.\",\n        \"declaration\": \"function assertEq(address[] calldata left, address[] calldata right, string calldata error) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertEq(address[],address[],string)\",\n        \"selector\": \"0x3e9173c5\",\n        \"selectorBytes\": [\n          62,\n          145,\n          115,\n          197\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertEq_22\",\n        \"description\": \"Asserts that two arrays of `bytes32` values are equal.\",\n        \"declaration\": \"function assertEq(bytes32[] calldata left, bytes32[] calldata right) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertEq(bytes32[],bytes32[])\",\n        \"selector\": \"0x0cc9ee84\",\n        \"selectorBytes\": [\n          12,\n          201,\n          238,\n          132\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertEq_23\",\n        \"description\": \"Asserts that two arrays of `bytes32` values are equal and includes error message into revert string on failure.\",\n        \"declaration\": \"function assertEq(bytes32[] calldata left, bytes32[] calldata right, string calldata error) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertEq(bytes32[],bytes32[],string)\",\n        \"selector\": \"0xe03e9177\",\n        \"selectorBytes\": [\n          224,\n          62,\n          145,\n          119\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertEq_24\",\n        \"description\": \"Asserts that two arrays of `string` values are equal.\",\n        \"declaration\": \"function assertEq(string[] calldata left, string[] calldata right) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertEq(string[],string[])\",\n        \"selector\": \"0xcf1c049c\",\n        \"selectorBytes\": [\n          207,\n          28,\n          4,\n          156\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertEq_25\",\n        \"description\": \"Asserts that two arrays of `string` values are equal and includes error message into revert string on failure.\",\n        \"declaration\": \"function assertEq(string[] calldata left, string[] calldata right, string calldata error) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertEq(string[],string[],string)\",\n        \"selector\": \"0xeff6b27d\",\n        \"selectorBytes\": [\n          239,\n          246,\n          178,\n          125\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertEq_26\",\n        \"description\": \"Asserts that two arrays of `bytes` values are equal.\",\n        \"declaration\": \"function assertEq(bytes[] calldata left, bytes[] calldata right) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertEq(bytes[],bytes[])\",\n        \"selector\": \"0xe5fb9b4a\",\n        \"selectorBytes\": [\n          229,\n          251,\n          155,\n          74\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertEq_27\",\n        \"description\": \"Asserts that two arrays of `bytes` values are equal and includes error message into revert string on failure.\",\n        \"declaration\": \"function assertEq(bytes[] calldata left, bytes[] calldata right, string calldata error) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertEq(bytes[],bytes[],string)\",\n        \"selector\": \"0xf413f0b6\",\n        \"selectorBytes\": [\n          244,\n          19,\n          240,\n          182\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertEq_3\",\n        \"description\": \"Asserts that two `uint256` values are equal and includes error message into revert string on failure.\",\n        \"declaration\": \"function assertEq(uint256 left, uint256 right, string calldata error) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertEq(uint256,uint256,string)\",\n        \"selector\": \"0x88b44c85\",\n        \"selectorBytes\": [\n          136,\n          180,\n          76,\n          133\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertEq_4\",\n        \"description\": \"Asserts that two `int256` values are equal.\",\n        \"declaration\": \"function assertEq(int256 left, int256 right) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertEq(int256,int256)\",\n        \"selector\": \"0xfe74f05b\",\n        \"selectorBytes\": [\n          254,\n          116,\n          240,\n          91\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertEq_5\",\n        \"description\": \"Asserts that two `int256` values are equal and includes error message into revert string on failure.\",\n        \"declaration\": \"function assertEq(int256 left, int256 right, string calldata error) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertEq(int256,int256,string)\",\n        \"selector\": \"0x714a2f13\",\n        \"selectorBytes\": [\n          113,\n          74,\n          47,\n          19\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertEq_6\",\n        \"description\": \"Asserts that two `address` values are equal.\",\n        \"declaration\": \"function assertEq(address left, address right) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertEq(address,address)\",\n        \"selector\": \"0x515361f6\",\n        \"selectorBytes\": [\n          81,\n          83,\n          97,\n          246\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertEq_7\",\n        \"description\": \"Asserts that two `address` values are equal and includes error message into revert string on failure.\",\n        \"declaration\": \"function assertEq(address left, address right, string calldata error) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertEq(address,address,string)\",\n        \"selector\": \"0x2f2769d1\",\n        \"selectorBytes\": [\n          47,\n          39,\n          105,\n          209\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertEq_8\",\n        \"description\": \"Asserts that two `bytes32` values are equal.\",\n        \"declaration\": \"function assertEq(bytes32 left, bytes32 right) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertEq(bytes32,bytes32)\",\n        \"selector\": \"0x7c84c69b\",\n        \"selectorBytes\": [\n          124,\n          132,\n          198,\n          155\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertEq_9\",\n        \"description\": \"Asserts that two `bytes32` values are equal and includes error message into revert string on failure.\",\n        \"declaration\": \"function assertEq(bytes32 left, bytes32 right, string calldata error) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertEq(bytes32,bytes32,string)\",\n        \"selector\": \"0xc1fa1ed0\",\n        \"selectorBytes\": [\n          193,\n          250,\n          30,\n          208\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertFalse_0\",\n        \"description\": \"Asserts that the given condition is false.\",\n        \"declaration\": \"function assertFalse(bool condition) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertFalse(bool)\",\n        \"selector\": \"0xa5982885\",\n        \"selectorBytes\": [\n          165,\n          152,\n          40,\n          133\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertFalse_1\",\n        \"description\": \"Asserts that the given condition is false and includes error message into revert string on failure.\",\n        \"declaration\": \"function assertFalse(bool condition, string calldata error) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertFalse(bool,string)\",\n        \"selector\": \"0x7ba04809\",\n        \"selectorBytes\": [\n          123,\n          160,\n          72,\n          9\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertGeDecimal_0\",\n        \"description\": \"Compares two `uint256` values. Expects first value to be greater than or equal to second.\\nFormats values with decimals in failure message.\",\n        \"declaration\": \"function assertGeDecimal(uint256 left, uint256 right, uint256 decimals) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertGeDecimal(uint256,uint256,uint256)\",\n        \"selector\": \"0x3d1fe08a\",\n        \"selectorBytes\": [\n          61,\n          31,\n          224,\n          138\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertGeDecimal_1\",\n        \"description\": \"Compares two `uint256` values. Expects first value to be greater than or equal to second.\\nFormats values with decimals in failure message. Includes error message into revert string on failure.\",\n        \"declaration\": \"function assertGeDecimal(uint256 left, uint256 right, uint256 decimals, string calldata error) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertGeDecimal(uint256,uint256,uint256,string)\",\n        \"selector\": \"0x8bff9133\",\n        \"selectorBytes\": [\n          139,\n          255,\n          145,\n          51\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertGeDecimal_2\",\n        \"description\": \"Compares two `int256` values. Expects first value to be greater than or equal to second.\\nFormats values with decimals in failure message.\",\n        \"declaration\": \"function assertGeDecimal(int256 left, int256 right, uint256 decimals) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertGeDecimal(int256,int256,uint256)\",\n        \"selector\": \"0xdc28c0f1\",\n        \"selectorBytes\": [\n          220,\n          40,\n          192,\n          241\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertGeDecimal_3\",\n        \"description\": \"Compares two `int256` values. Expects first value to be greater than or equal to second.\\nFormats values with decimals in failure message. Includes error message into revert string on failure.\",\n        \"declaration\": \"function assertGeDecimal(int256 left, int256 right, uint256 decimals, string calldata error) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertGeDecimal(int256,int256,uint256,string)\",\n        \"selector\": \"0x5df93c9b\",\n        \"selectorBytes\": [\n          93,\n          249,\n          60,\n          155\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertGe_0\",\n        \"description\": \"Compares two `uint256` values. Expects first value to be greater than or equal to second.\",\n        \"declaration\": \"function assertGe(uint256 left, uint256 right) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertGe(uint256,uint256)\",\n        \"selector\": \"0xa8d4d1d9\",\n        \"selectorBytes\": [\n          168,\n          212,\n          209,\n          217\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertGe_1\",\n        \"description\": \"Compares two `uint256` values. Expects first value to be greater than or equal to second.\\nIncludes error message into revert string on failure.\",\n        \"declaration\": \"function assertGe(uint256 left, uint256 right, string calldata error) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertGe(uint256,uint256,string)\",\n        \"selector\": \"0xe25242c0\",\n        \"selectorBytes\": [\n          226,\n          82,\n          66,\n          192\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertGe_2\",\n        \"description\": \"Compares two `int256` values. Expects first value to be greater than or equal to second.\",\n        \"declaration\": \"function assertGe(int256 left, int256 right) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertGe(int256,int256)\",\n        \"selector\": \"0x0a30b771\",\n        \"selectorBytes\": [\n          10,\n          48,\n          183,\n          113\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertGe_3\",\n        \"description\": \"Compares two `int256` values. Expects first value to be greater than or equal to second.\\nIncludes error message into revert string on failure.\",\n        \"declaration\": \"function assertGe(int256 left, int256 right, string calldata error) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertGe(int256,int256,string)\",\n        \"selector\": \"0xa84328dd\",\n        \"selectorBytes\": [\n          168,\n          67,\n          40,\n          221\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertGtDecimal_0\",\n        \"description\": \"Compares two `uint256` values. Expects first value to be greater than second.\\nFormats values with decimals in failure message.\",\n        \"declaration\": \"function assertGtDecimal(uint256 left, uint256 right, uint256 decimals) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertGtDecimal(uint256,uint256,uint256)\",\n        \"selector\": \"0xeccd2437\",\n        \"selectorBytes\": [\n          236,\n          205,\n          36,\n          55\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertGtDecimal_1\",\n        \"description\": \"Compares two `uint256` values. Expects first value to be greater than second.\\nFormats values with decimals in failure message. Includes error message into revert string on failure.\",\n        \"declaration\": \"function assertGtDecimal(uint256 left, uint256 right, uint256 decimals, string calldata error) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertGtDecimal(uint256,uint256,uint256,string)\",\n        \"selector\": \"0x64949a8d\",\n        \"selectorBytes\": [\n          100,\n          148,\n          154,\n          141\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertGtDecimal_2\",\n        \"description\": \"Compares two `int256` values. Expects first value to be greater than second.\\nFormats values with decimals in failure message.\",\n        \"declaration\": \"function assertGtDecimal(int256 left, int256 right, uint256 decimals) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertGtDecimal(int256,int256,uint256)\",\n        \"selector\": \"0x78611f0e\",\n        \"selectorBytes\": [\n          120,\n          97,\n          31,\n          14\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertGtDecimal_3\",\n        \"description\": \"Compares two `int256` values. Expects first value to be greater than second.\\nFormats values with decimals in failure message. Includes error message into revert string on failure.\",\n        \"declaration\": \"function assertGtDecimal(int256 left, int256 right, uint256 decimals, string calldata error) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertGtDecimal(int256,int256,uint256,string)\",\n        \"selector\": \"0x04a5c7ab\",\n        \"selectorBytes\": [\n          4,\n          165,\n          199,\n          171\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertGt_0\",\n        \"description\": \"Compares two `uint256` values. Expects first value to be greater than second.\",\n        \"declaration\": \"function assertGt(uint256 left, uint256 right) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertGt(uint256,uint256)\",\n        \"selector\": \"0xdb07fcd2\",\n        \"selectorBytes\": [\n          219,\n          7,\n          252,\n          210\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertGt_1\",\n        \"description\": \"Compares two `uint256` values. Expects first value to be greater than second.\\nIncludes error message into revert string on failure.\",\n        \"declaration\": \"function assertGt(uint256 left, uint256 right, string calldata error) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertGt(uint256,uint256,string)\",\n        \"selector\": \"0xd9a3c4d2\",\n        \"selectorBytes\": [\n          217,\n          163,\n          196,\n          210\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertGt_2\",\n        \"description\": \"Compares two `int256` values. Expects first value to be greater than second.\",\n        \"declaration\": \"function assertGt(int256 left, int256 right) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertGt(int256,int256)\",\n        \"selector\": \"0x5a362d45\",\n        \"selectorBytes\": [\n          90,\n          54,\n          45,\n          69\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertGt_3\",\n        \"description\": \"Compares two `int256` values. Expects first value to be greater than second.\\nIncludes error message into revert string on failure.\",\n        \"declaration\": \"function assertGt(int256 left, int256 right, string calldata error) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertGt(int256,int256,string)\",\n        \"selector\": \"0xf8d33b9b\",\n        \"selectorBytes\": [\n          248,\n          211,\n          59,\n          155\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertLeDecimal_0\",\n        \"description\": \"Compares two `uint256` values. Expects first value to be less than or equal to second.\\nFormats values with decimals in failure message.\",\n        \"declaration\": \"function assertLeDecimal(uint256 left, uint256 right, uint256 decimals) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertLeDecimal(uint256,uint256,uint256)\",\n        \"selector\": \"0xc304aab7\",\n        \"selectorBytes\": [\n          195,\n          4,\n          170,\n          183\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertLeDecimal_1\",\n        \"description\": \"Compares two `uint256` values. Expects first value to be less than or equal to second.\\nFormats values with decimals in failure message. Includes error message into revert string on failure.\",\n        \"declaration\": \"function assertLeDecimal(uint256 left, uint256 right, uint256 decimals, string calldata error) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertLeDecimal(uint256,uint256,uint256,string)\",\n        \"selector\": \"0x7fefbbe0\",\n        \"selectorBytes\": [\n          127,\n          239,\n          187,\n          224\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertLeDecimal_2\",\n        \"description\": \"Compares two `int256` values. Expects first value to be less than or equal to second.\\nFormats values with decimals in failure message.\",\n        \"declaration\": \"function assertLeDecimal(int256 left, int256 right, uint256 decimals) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertLeDecimal(int256,int256,uint256)\",\n        \"selector\": \"0x11d1364a\",\n        \"selectorBytes\": [\n          17,\n          209,\n          54,\n          74\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertLeDecimal_3\",\n        \"description\": \"Compares two `int256` values. Expects first value to be less than or equal to second.\\nFormats values with decimals in failure message. Includes error message into revert string on failure.\",\n        \"declaration\": \"function assertLeDecimal(int256 left, int256 right, uint256 decimals, string calldata error) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertLeDecimal(int256,int256,uint256,string)\",\n        \"selector\": \"0xaa5cf788\",\n        \"selectorBytes\": [\n          170,\n          92,\n          247,\n          136\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertLe_0\",\n        \"description\": \"Compares two `uint256` values. Expects first value to be less than or equal to second.\",\n        \"declaration\": \"function assertLe(uint256 left, uint256 right) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertLe(uint256,uint256)\",\n        \"selector\": \"0x8466f415\",\n        \"selectorBytes\": [\n          132,\n          102,\n          244,\n          21\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertLe_1\",\n        \"description\": \"Compares two `uint256` values. Expects first value to be less than or equal to second.\\nIncludes error message into revert string on failure.\",\n        \"declaration\": \"function assertLe(uint256 left, uint256 right, string calldata error) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertLe(uint256,uint256,string)\",\n        \"selector\": \"0xd17d4b0d\",\n        \"selectorBytes\": [\n          209,\n          125,\n          75,\n          13\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertLe_2\",\n        \"description\": \"Compares two `int256` values. Expects first value to be less than or equal to second.\",\n        \"declaration\": \"function assertLe(int256 left, int256 right) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertLe(int256,int256)\",\n        \"selector\": \"0x95fd154e\",\n        \"selectorBytes\": [\n          149,\n          253,\n          21,\n          78\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertLe_3\",\n        \"description\": \"Compares two `int256` values. Expects first value to be less than or equal to second.\\nIncludes error message into revert string on failure.\",\n        \"declaration\": \"function assertLe(int256 left, int256 right, string calldata error) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertLe(int256,int256,string)\",\n        \"selector\": \"0x4dfe692c\",\n        \"selectorBytes\": [\n          77,\n          254,\n          105,\n          44\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertLtDecimal_0\",\n        \"description\": \"Compares two `uint256` values. Expects first value to be less than second.\\nFormats values with decimals in failure message.\",\n        \"declaration\": \"function assertLtDecimal(uint256 left, uint256 right, uint256 decimals) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertLtDecimal(uint256,uint256,uint256)\",\n        \"selector\": \"0x2077337e\",\n        \"selectorBytes\": [\n          32,\n          119,\n          51,\n          126\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertLtDecimal_1\",\n        \"description\": \"Compares two `uint256` values. Expects first value to be less than second.\\nFormats values with decimals in failure message. Includes error message into revert string on failure.\",\n        \"declaration\": \"function assertLtDecimal(uint256 left, uint256 right, uint256 decimals, string calldata error) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertLtDecimal(uint256,uint256,uint256,string)\",\n        \"selector\": \"0xa972d037\",\n        \"selectorBytes\": [\n          169,\n          114,\n          208,\n          55\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertLtDecimal_2\",\n        \"description\": \"Compares two `int256` values. Expects first value to be less than second.\\nFormats values with decimals in failure message.\",\n        \"declaration\": \"function assertLtDecimal(int256 left, int256 right, uint256 decimals) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertLtDecimal(int256,int256,uint256)\",\n        \"selector\": \"0xdbe8d88b\",\n        \"selectorBytes\": [\n          219,\n          232,\n          216,\n          139\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertLtDecimal_3\",\n        \"description\": \"Compares two `int256` values. Expects first value to be less than second.\\nFormats values with decimals in failure message. Includes error message into revert string on failure.\",\n        \"declaration\": \"function assertLtDecimal(int256 left, int256 right, uint256 decimals, string calldata error) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertLtDecimal(int256,int256,uint256,string)\",\n        \"selector\": \"0x40f0b4e0\",\n        \"selectorBytes\": [\n          64,\n          240,\n          180,\n          224\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertLt_0\",\n        \"description\": \"Compares two `uint256` values. Expects first value to be less than second.\",\n        \"declaration\": \"function assertLt(uint256 left, uint256 right) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertLt(uint256,uint256)\",\n        \"selector\": \"0xb12fc005\",\n        \"selectorBytes\": [\n          177,\n          47,\n          192,\n          5\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertLt_1\",\n        \"description\": \"Compares two `uint256` values. Expects first value to be less than second.\\nIncludes error message into revert string on failure.\",\n        \"declaration\": \"function assertLt(uint256 left, uint256 right, string calldata error) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertLt(uint256,uint256,string)\",\n        \"selector\": \"0x65d5c135\",\n        \"selectorBytes\": [\n          101,\n          213,\n          193,\n          53\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertLt_2\",\n        \"description\": \"Compares two `int256` values. Expects first value to be less than second.\",\n        \"declaration\": \"function assertLt(int256 left, int256 right) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertLt(int256,int256)\",\n        \"selector\": \"0x3e914080\",\n        \"selectorBytes\": [\n          62,\n          145,\n          64,\n          128\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertLt_3\",\n        \"description\": \"Compares two `int256` values. Expects first value to be less than second.\\nIncludes error message into revert string on failure.\",\n        \"declaration\": \"function assertLt(int256 left, int256 right, string calldata error) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertLt(int256,int256,string)\",\n        \"selector\": \"0x9ff531e3\",\n        \"selectorBytes\": [\n          159,\n          245,\n          49,\n          227\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertNotEqDecimal_0\",\n        \"description\": \"Asserts that two `uint256` values are not equal, formatting them with decimals in failure message.\",\n        \"declaration\": \"function assertNotEqDecimal(uint256 left, uint256 right, uint256 decimals) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertNotEqDecimal(uint256,uint256,uint256)\",\n        \"selector\": \"0x669efca7\",\n        \"selectorBytes\": [\n          102,\n          158,\n          252,\n          167\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertNotEqDecimal_1\",\n        \"description\": \"Asserts that two `uint256` values are not equal, formatting them with decimals in failure message.\\nIncludes error message into revert string on failure.\",\n        \"declaration\": \"function assertNotEqDecimal(uint256 left, uint256 right, uint256 decimals, string calldata error) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertNotEqDecimal(uint256,uint256,uint256,string)\",\n        \"selector\": \"0xf5a55558\",\n        \"selectorBytes\": [\n          245,\n          165,\n          85,\n          88\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertNotEqDecimal_2\",\n        \"description\": \"Asserts that two `int256` values are not equal, formatting them with decimals in failure message.\",\n        \"declaration\": \"function assertNotEqDecimal(int256 left, int256 right, uint256 decimals) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertNotEqDecimal(int256,int256,uint256)\",\n        \"selector\": \"0x14e75680\",\n        \"selectorBytes\": [\n          20,\n          231,\n          86,\n          128\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertNotEqDecimal_3\",\n        \"description\": \"Asserts that two `int256` values are not equal, formatting them with decimals in failure message.\\nIncludes error message into revert string on failure.\",\n        \"declaration\": \"function assertNotEqDecimal(int256 left, int256 right, uint256 decimals, string calldata error) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertNotEqDecimal(int256,int256,uint256,string)\",\n        \"selector\": \"0x33949f0b\",\n        \"selectorBytes\": [\n          51,\n          148,\n          159,\n          11\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertNotEq_0\",\n        \"description\": \"Asserts that two `bool` values are not equal.\",\n        \"declaration\": \"function assertNotEq(bool left, bool right) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertNotEq(bool,bool)\",\n        \"selector\": \"0x236e4d66\",\n        \"selectorBytes\": [\n          35,\n          110,\n          77,\n          102\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertNotEq_1\",\n        \"description\": \"Asserts that two `bool` values are not equal and includes error message into revert string on failure.\",\n        \"declaration\": \"function assertNotEq(bool left, bool right, string calldata error) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertNotEq(bool,bool,string)\",\n        \"selector\": \"0x1091a261\",\n        \"selectorBytes\": [\n          16,\n          145,\n          162,\n          97\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertNotEq_10\",\n        \"description\": \"Asserts that two `string` values are not equal.\",\n        \"declaration\": \"function assertNotEq(string calldata left, string calldata right) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertNotEq(string,string)\",\n        \"selector\": \"0x6a8237b3\",\n        \"selectorBytes\": [\n          106,\n          130,\n          55,\n          179\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertNotEq_11\",\n        \"description\": \"Asserts that two `string` values are not equal and includes error message into revert string on failure.\",\n        \"declaration\": \"function assertNotEq(string calldata left, string calldata right, string calldata error) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertNotEq(string,string,string)\",\n        \"selector\": \"0x78bdcea7\",\n        \"selectorBytes\": [\n          120,\n          189,\n          206,\n          167\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertNotEq_12\",\n        \"description\": \"Asserts that two `bytes` values are not equal.\",\n        \"declaration\": \"function assertNotEq(bytes calldata left, bytes calldata right) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertNotEq(bytes,bytes)\",\n        \"selector\": \"0x3cf78e28\",\n        \"selectorBytes\": [\n          60,\n          247,\n          142,\n          40\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertNotEq_13\",\n        \"description\": \"Asserts that two `bytes` values are not equal and includes error message into revert string on failure.\",\n        \"declaration\": \"function assertNotEq(bytes calldata left, bytes calldata right, string calldata error) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertNotEq(bytes,bytes,string)\",\n        \"selector\": \"0x9507540e\",\n        \"selectorBytes\": [\n          149,\n          7,\n          84,\n          14\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertNotEq_14\",\n        \"description\": \"Asserts that two arrays of `bool` values are not equal.\",\n        \"declaration\": \"function assertNotEq(bool[] calldata left, bool[] calldata right) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertNotEq(bool[],bool[])\",\n        \"selector\": \"0x286fafea\",\n        \"selectorBytes\": [\n          40,\n          111,\n          175,\n          234\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertNotEq_15\",\n        \"description\": \"Asserts that two arrays of `bool` values are not equal and includes error message into revert string on failure.\",\n        \"declaration\": \"function assertNotEq(bool[] calldata left, bool[] calldata right, string calldata error) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertNotEq(bool[],bool[],string)\",\n        \"selector\": \"0x62c6f9fb\",\n        \"selectorBytes\": [\n          98,\n          198,\n          249,\n          251\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertNotEq_16\",\n        \"description\": \"Asserts that two arrays of `uint256` values are not equal.\",\n        \"declaration\": \"function assertNotEq(uint256[] calldata left, uint256[] calldata right) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertNotEq(uint256[],uint256[])\",\n        \"selector\": \"0x56f29cba\",\n        \"selectorBytes\": [\n          86,\n          242,\n          156,\n          186\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertNotEq_17\",\n        \"description\": \"Asserts that two arrays of `uint256` values are not equal and includes error message into revert string on failure.\",\n        \"declaration\": \"function assertNotEq(uint256[] calldata left, uint256[] calldata right, string calldata error) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertNotEq(uint256[],uint256[],string)\",\n        \"selector\": \"0x9a7fbd8f\",\n        \"selectorBytes\": [\n          154,\n          127,\n          189,\n          143\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertNotEq_18\",\n        \"description\": \"Asserts that two arrays of `int256` values are not equal.\",\n        \"declaration\": \"function assertNotEq(int256[] calldata left, int256[] calldata right) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertNotEq(int256[],int256[])\",\n        \"selector\": \"0x0b72f4ef\",\n        \"selectorBytes\": [\n          11,\n          114,\n          244,\n          239\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertNotEq_19\",\n        \"description\": \"Asserts that two arrays of `int256` values are not equal and includes error message into revert string on failure.\",\n        \"declaration\": \"function assertNotEq(int256[] calldata left, int256[] calldata right, string calldata error) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertNotEq(int256[],int256[],string)\",\n        \"selector\": \"0xd3977322\",\n        \"selectorBytes\": [\n          211,\n          151,\n          115,\n          34\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertNotEq_2\",\n        \"description\": \"Asserts that two `uint256` values are not equal.\",\n        \"declaration\": \"function assertNotEq(uint256 left, uint256 right) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertNotEq(uint256,uint256)\",\n        \"selector\": \"0xb7909320\",\n        \"selectorBytes\": [\n          183,\n          144,\n          147,\n          32\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertNotEq_20\",\n        \"description\": \"Asserts that two arrays of `address` values are not equal.\",\n        \"declaration\": \"function assertNotEq(address[] calldata left, address[] calldata right) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertNotEq(address[],address[])\",\n        \"selector\": \"0x46d0b252\",\n        \"selectorBytes\": [\n          70,\n          208,\n          178,\n          82\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertNotEq_21\",\n        \"description\": \"Asserts that two arrays of `address` values are not equal and includes error message into revert string on failure.\",\n        \"declaration\": \"function assertNotEq(address[] calldata left, address[] calldata right, string calldata error) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertNotEq(address[],address[],string)\",\n        \"selector\": \"0x72c7e0b5\",\n        \"selectorBytes\": [\n          114,\n          199,\n          224,\n          181\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertNotEq_22\",\n        \"description\": \"Asserts that two arrays of `bytes32` values are not equal.\",\n        \"declaration\": \"function assertNotEq(bytes32[] calldata left, bytes32[] calldata right) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertNotEq(bytes32[],bytes32[])\",\n        \"selector\": \"0x0603ea68\",\n        \"selectorBytes\": [\n          6,\n          3,\n          234,\n          104\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertNotEq_23\",\n        \"description\": \"Asserts that two arrays of `bytes32` values are not equal and includes error message into revert string on failure.\",\n        \"declaration\": \"function assertNotEq(bytes32[] calldata left, bytes32[] calldata right, string calldata error) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertNotEq(bytes32[],bytes32[],string)\",\n        \"selector\": \"0xb873634c\",\n        \"selectorBytes\": [\n          184,\n          115,\n          99,\n          76\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertNotEq_24\",\n        \"description\": \"Asserts that two arrays of `string` values are not equal.\",\n        \"declaration\": \"function assertNotEq(string[] calldata left, string[] calldata right) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertNotEq(string[],string[])\",\n        \"selector\": \"0xbdfacbe8\",\n        \"selectorBytes\": [\n          189,\n          250,\n          203,\n          232\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertNotEq_25\",\n        \"description\": \"Asserts that two arrays of `string` values are not equal and includes error message into revert string on failure.\",\n        \"declaration\": \"function assertNotEq(string[] calldata left, string[] calldata right, string calldata error) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertNotEq(string[],string[],string)\",\n        \"selector\": \"0xb67187f3\",\n        \"selectorBytes\": [\n          182,\n          113,\n          135,\n          243\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertNotEq_26\",\n        \"description\": \"Asserts that two arrays of `bytes` values are not equal.\",\n        \"declaration\": \"function assertNotEq(bytes[] calldata left, bytes[] calldata right) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertNotEq(bytes[],bytes[])\",\n        \"selector\": \"0xedecd035\",\n        \"selectorBytes\": [\n          237,\n          236,\n          208,\n          53\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertNotEq_27\",\n        \"description\": \"Asserts that two arrays of `bytes` values are not equal and includes error message into revert string on failure.\",\n        \"declaration\": \"function assertNotEq(bytes[] calldata left, bytes[] calldata right, string calldata error) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertNotEq(bytes[],bytes[],string)\",\n        \"selector\": \"0x1dcd1f68\",\n        \"selectorBytes\": [\n          29,\n          205,\n          31,\n          104\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertNotEq_3\",\n        \"description\": \"Asserts that two `uint256` values are not equal and includes error message into revert string on failure.\",\n        \"declaration\": \"function assertNotEq(uint256 left, uint256 right, string calldata error) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertNotEq(uint256,uint256,string)\",\n        \"selector\": \"0x98f9bdbd\",\n        \"selectorBytes\": [\n          152,\n          249,\n          189,\n          189\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertNotEq_4\",\n        \"description\": \"Asserts that two `int256` values are not equal.\",\n        \"declaration\": \"function assertNotEq(int256 left, int256 right) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertNotEq(int256,int256)\",\n        \"selector\": \"0xf4c004e3\",\n        \"selectorBytes\": [\n          244,\n          192,\n          4,\n          227\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertNotEq_5\",\n        \"description\": \"Asserts that two `int256` values are not equal and includes error message into revert string on failure.\",\n        \"declaration\": \"function assertNotEq(int256 left, int256 right, string calldata error) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertNotEq(int256,int256,string)\",\n        \"selector\": \"0x4724c5b9\",\n        \"selectorBytes\": [\n          71,\n          36,\n          197,\n          185\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertNotEq_6\",\n        \"description\": \"Asserts that two `address` values are not equal.\",\n        \"declaration\": \"function assertNotEq(address left, address right) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertNotEq(address,address)\",\n        \"selector\": \"0xb12e1694\",\n        \"selectorBytes\": [\n          177,\n          46,\n          22,\n          148\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertNotEq_7\",\n        \"description\": \"Asserts that two `address` values are not equal and includes error message into revert string on failure.\",\n        \"declaration\": \"function assertNotEq(address left, address right, string calldata error) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertNotEq(address,address,string)\",\n        \"selector\": \"0x8775a591\",\n        \"selectorBytes\": [\n          135,\n          117,\n          165,\n          145\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertNotEq_8\",\n        \"description\": \"Asserts that two `bytes32` values are not equal.\",\n        \"declaration\": \"function assertNotEq(bytes32 left, bytes32 right) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertNotEq(bytes32,bytes32)\",\n        \"selector\": \"0x898e83fc\",\n        \"selectorBytes\": [\n          137,\n          142,\n          131,\n          252\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertNotEq_9\",\n        \"description\": \"Asserts that two `bytes32` values are not equal and includes error message into revert string on failure.\",\n        \"declaration\": \"function assertNotEq(bytes32 left, bytes32 right, string calldata error) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertNotEq(bytes32,bytes32,string)\",\n        \"selector\": \"0xb2332f51\",\n        \"selectorBytes\": [\n          178,\n          51,\n          47,\n          81\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertTrue_0\",\n        \"description\": \"Asserts that the given condition is true.\",\n        \"declaration\": \"function assertTrue(bool condition) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertTrue(bool)\",\n        \"selector\": \"0x0c9fd581\",\n        \"selectorBytes\": [\n          12,\n          159,\n          213,\n          129\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assertTrue_1\",\n        \"description\": \"Asserts that the given condition is true and includes error message into revert string on failure.\",\n        \"declaration\": \"function assertTrue(bool condition, string calldata error) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assertTrue(bool,string)\",\n        \"selector\": \"0xa34edc03\",\n        \"selectorBytes\": [\n          163,\n          78,\n          220,\n          3\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assume\",\n        \"description\": \"If the condition is false, discard this run's fuzz inputs and generate new ones.\",\n        \"declaration\": \"function assume(bool condition) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assume(bool)\",\n        \"selector\": \"0x4c63e562\",\n        \"selectorBytes\": [\n          76,\n          99,\n          229,\n          98\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assumeNoRevert_0\",\n        \"description\": \"Discard this run's fuzz inputs and generate new ones if next call reverted.\",\n        \"declaration\": \"function assumeNoRevert() external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assumeNoRevert()\",\n        \"selector\": \"0x285b366a\",\n        \"selectorBytes\": [\n          40,\n          91,\n          54,\n          106\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assumeNoRevert_1\",\n        \"description\": \"Discard this run's fuzz inputs and generate new ones if next call reverts with the potential revert parameters.\",\n        \"declaration\": \"function assumeNoRevert(PotentialRevert calldata potentialRevert) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assumeNoRevert((address,bool,bytes))\",\n        \"selector\": \"0xd8591eeb\",\n        \"selectorBytes\": [\n          216,\n          89,\n          30,\n          235\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"assumeNoRevert_2\",\n        \"description\": \"Discard this run's fuzz inputs and generate new ones if next call reverts with the any of the potential revert parameters.\",\n        \"declaration\": \"function assumeNoRevert(PotentialRevert[] calldata potentialReverts) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"assumeNoRevert((address,bool,bytes)[])\",\n        \"selector\": \"0x8a4592cc\",\n        \"selectorBytes\": [\n          138,\n          69,\n          146,\n          204\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"attachBlob\",\n        \"description\": \"Attach an EIP-4844 blob to the next call\",\n        \"declaration\": \"function attachBlob(bytes calldata blob) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"attachBlob(bytes)\",\n        \"selector\": \"0x10cb385c\",\n        \"selectorBytes\": [\n          16,\n          203,\n          56,\n          92\n        ]\n      },\n      \"group\": \"scripting\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"attachDelegation_0\",\n        \"description\": \"Designate the next call as an EIP-7702 transaction\",\n        \"declaration\": \"function attachDelegation(SignedDelegation calldata signedDelegation) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"attachDelegation((uint8,bytes32,bytes32,uint64,address))\",\n        \"selector\": \"0x14ae3519\",\n        \"selectorBytes\": [\n          20,\n          174,\n          53,\n          25\n        ]\n      },\n      \"group\": \"scripting\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"attachDelegation_1\",\n        \"description\": \"Designate the next call as an EIP-7702 transaction, with optional cross-chain validity.\",\n        \"declaration\": \"function attachDelegation(SignedDelegation calldata signedDelegation, bool crossChain) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"attachDelegation((uint8,bytes32,bytes32,uint64,address),bool)\",\n        \"selector\": \"0xf4460d34\",\n        \"selectorBytes\": [\n          244,\n          70,\n          13,\n          52\n        ]\n      },\n      \"group\": \"scripting\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"blobBaseFee\",\n        \"description\": \"Sets `block.blobbasefee`\",\n        \"declaration\": \"function blobBaseFee(uint256 newBlobBaseFee) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"blobBaseFee(uint256)\",\n        \"selector\": \"0x6d315d7e\",\n        \"selectorBytes\": [\n          109,\n          49,\n          93,\n          126\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"blobhashes\",\n        \"description\": \"Sets the blobhashes in the transaction.\\nNot available on EVM versions before Cancun.\\nIf used on unsupported EVM versions it will revert.\",\n        \"declaration\": \"function blobhashes(bytes32[] calldata hashes) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"blobhashes(bytes32[])\",\n        \"selector\": \"0x129de7eb\",\n        \"selectorBytes\": [\n          18,\n          157,\n          231,\n          235\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"bound_0\",\n        \"description\": \"Returns an uint256 value bounded in given range and different from the current one.\",\n        \"declaration\": \"function bound(uint256 current, uint256 min, uint256 max) external view returns (uint256);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"bound(uint256,uint256,uint256)\",\n        \"selector\": \"0x5a6c1eed\",\n        \"selectorBytes\": [\n          90,\n          108,\n          30,\n          237\n        ]\n      },\n      \"group\": \"utilities\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"bound_1\",\n        \"description\": \"Returns an int256 value bounded in given range and different from the current one.\",\n        \"declaration\": \"function bound(int256 current, int256 min, int256 max) external view returns (int256);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"bound(int256,int256,int256)\",\n        \"selector\": \"0x8f48fc07\",\n        \"selectorBytes\": [\n          143,\n          72,\n          252,\n          7\n        ]\n      },\n      \"group\": \"utilities\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"breakpoint_0\",\n        \"description\": \"Writes a breakpoint to jump to in the debugger.\",\n        \"declaration\": \"function breakpoint(string calldata char) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"breakpoint(string)\",\n        \"selector\": \"0xf0259e92\",\n        \"selectorBytes\": [\n          240,\n          37,\n          158,\n          146\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"breakpoint_1\",\n        \"description\": \"Writes a conditional breakpoint to jump to in the debugger.\",\n        \"declaration\": \"function breakpoint(string calldata char, bool value) external pure;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"breakpoint(string,bool)\",\n        \"selector\": \"0xf7d39a8d\",\n        \"selectorBytes\": [\n          247,\n          211,\n          154,\n          141\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"broadcastRawTransaction\",\n        \"description\": \"Takes a signed transaction and broadcasts it to the network.\",\n        \"declaration\": \"function broadcastRawTransaction(bytes calldata data) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"broadcastRawTransaction(bytes)\",\n        \"selector\": \"0x8c0c72e0\",\n        \"selectorBytes\": [\n          140,\n          12,\n          114,\n          224\n        ]\n      },\n      \"group\": \"scripting\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"broadcast_0\",\n        \"description\": \"Has the next call (at this call depth only) create transactions that can later be signed and sent onchain.\\nBroadcasting address is determined by checking the following in order:\\n1. If `--sender` argument was provided, that address is used.\\n2. If exactly one signer (e.g. private key, hw wallet, keystore) is set when `forge broadcast` is invoked, that signer is used.\\n3. Otherwise, default foundry sender (1804c8AB1F12E6bbf3894d4083f33e07309d1f38) is used.\",\n        \"declaration\": \"function broadcast() external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"broadcast()\",\n        \"selector\": \"0xafc98040\",\n        \"selectorBytes\": [\n          175,\n          201,\n          128,\n          64\n        ]\n      },\n      \"group\": \"scripting\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"broadcast_1\",\n        \"description\": \"Has the next call (at this call depth only) create a transaction with the address provided\\nas the sender that can later be signed and sent onchain.\",\n        \"declaration\": \"function broadcast(address signer) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"broadcast(address)\",\n        \"selector\": \"0xe6962cdb\",\n        \"selectorBytes\": [\n          230,\n          150,\n          44,\n          219\n        ]\n      },\n      \"group\": \"scripting\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"broadcast_2\",\n        \"description\": \"Has the next call (at this call depth only) create a transaction with the private key\\nprovided as the sender that can later be signed and sent onchain.\",\n        \"declaration\": \"function broadcast(uint256 privateKey) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"broadcast(uint256)\",\n        \"selector\": \"0xf67a965b\",\n        \"selectorBytes\": [\n          246,\n          122,\n          150,\n          91\n        ]\n      },\n      \"group\": \"scripting\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"chainId\",\n        \"description\": \"Sets `block.chainid`.\",\n        \"declaration\": \"function chainId(uint256 newChainId) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"chainId(uint256)\",\n        \"selector\": \"0x4049ddd2\",\n        \"selectorBytes\": [\n          64,\n          73,\n          221,\n          210\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"clearMockedCalls\",\n        \"description\": \"Clears all mocked calls.\",\n        \"declaration\": \"function clearMockedCalls() external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"clearMockedCalls()\",\n        \"selector\": \"0x3fdf4e15\",\n        \"selectorBytes\": [\n          63,\n          223,\n          78,\n          21\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"cloneAccount\",\n        \"description\": \"Clones a source account code, state, balance and nonce to a target account and updates in-memory EVM state.\",\n        \"declaration\": \"function cloneAccount(address source, address target) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"cloneAccount(address,address)\",\n        \"selector\": \"0x533d61c9\",\n        \"selectorBytes\": [\n          83,\n          61,\n          97,\n          201\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"closeFile\",\n        \"description\": \"Closes file for reading, resetting the offset and allowing to read it from beginning with readLine.\\n`path` is relative to the project root.\",\n        \"declaration\": \"function closeFile(string calldata path) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"closeFile(string)\",\n        \"selector\": \"0x48c3241f\",\n        \"selectorBytes\": [\n          72,\n          195,\n          36,\n          31\n        ]\n      },\n      \"group\": \"filesystem\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"coinbase\",\n        \"description\": \"Sets `block.coinbase`.\",\n        \"declaration\": \"function coinbase(address newCoinbase) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"coinbase(address)\",\n        \"selector\": \"0xff483c54\",\n        \"selectorBytes\": [\n          255,\n          72,\n          60,\n          84\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"computeCreate2Address_0\",\n        \"description\": \"Compute the address of a contract created with CREATE2 using the given CREATE2 deployer.\",\n        \"declaration\": \"function computeCreate2Address(bytes32 salt, bytes32 initCodeHash, address deployer) external pure returns (address);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"computeCreate2Address(bytes32,bytes32,address)\",\n        \"selector\": \"0xd323826a\",\n        \"selectorBytes\": [\n          211,\n          35,\n          130,\n          106\n        ]\n      },\n      \"group\": \"utilities\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"computeCreate2Address_1\",\n        \"description\": \"Compute the address of a contract created with CREATE2 using the default CREATE2 deployer.\",\n        \"declaration\": \"function computeCreate2Address(bytes32 salt, bytes32 initCodeHash) external pure returns (address);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"computeCreate2Address(bytes32,bytes32)\",\n        \"selector\": \"0x890c283b\",\n        \"selectorBytes\": [\n          137,\n          12,\n          40,\n          59\n        ]\n      },\n      \"group\": \"utilities\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"computeCreateAddress\",\n        \"description\": \"Compute the address a contract will be deployed at for a given deployer address and nonce.\",\n        \"declaration\": \"function computeCreateAddress(address deployer, uint256 nonce) external pure returns (address);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"computeCreateAddress(address,uint256)\",\n        \"selector\": \"0x74637a7a\",\n        \"selectorBytes\": [\n          116,\n          99,\n          122,\n          122\n        ]\n      },\n      \"group\": \"utilities\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"contains\",\n        \"description\": \"Returns true if `search` is found in `subject`, false otherwise.\",\n        \"declaration\": \"function contains(string calldata subject, string calldata search) external pure returns (bool result);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"contains(string,string)\",\n        \"selector\": \"0x3fb18aec\",\n        \"selectorBytes\": [\n          63,\n          177,\n          138,\n          236\n        ]\n      },\n      \"group\": \"string\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"cool\",\n        \"description\": \"Marks the slots of an account and the account address as cold.\",\n        \"declaration\": \"function cool(address target) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"cool(address)\",\n        \"selector\": \"0x40ff9f21\",\n        \"selectorBytes\": [\n          64,\n          255,\n          159,\n          33\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"coolSlot\",\n        \"description\": \"Utility cheatcode to mark specific storage slot as cold, simulating no prior read.\",\n        \"declaration\": \"function coolSlot(address target, bytes32 slot) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"coolSlot(address,bytes32)\",\n        \"selector\": \"0x8c78e654\",\n        \"selectorBytes\": [\n          140,\n          120,\n          230,\n          84\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"copyFile\",\n        \"description\": \"Copies the contents of one file to another. This function will **overwrite** the contents of `to`.\\nOn success, the total number of bytes copied is returned and it is equal to the length of the `to` file as reported by `metadata`.\\nBoth `from` and `to` are relative to the project root.\",\n        \"declaration\": \"function copyFile(string calldata from, string calldata to) external returns (uint64 copied);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"copyFile(string,string)\",\n        \"selector\": \"0xa54a87d8\",\n        \"selectorBytes\": [\n          165,\n          74,\n          135,\n          216\n        ]\n      },\n      \"group\": \"filesystem\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"copyStorage\",\n        \"description\": \"Utility cheatcode to copy storage of `from` contract to another `to` contract.\",\n        \"declaration\": \"function copyStorage(address from, address to) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"copyStorage(address,address)\",\n        \"selector\": \"0x203dac0d\",\n        \"selectorBytes\": [\n          32,\n          61,\n          172,\n          13\n        ]\n      },\n      \"group\": \"utilities\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"createDir\",\n        \"description\": \"Creates a new, empty directory at the provided path.\\nThis cheatcode will revert in the following situations, but is not limited to just these cases:\\n- User lacks permissions to modify `path`.\\n- A parent of the given path doesn't exist and `recursive` is false.\\n- `path` already exists and `recursive` is false.\\n`path` is relative to the project root.\",\n        \"declaration\": \"function createDir(string calldata path, bool recursive) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"createDir(string,bool)\",\n        \"selector\": \"0x168b64d3\",\n        \"selectorBytes\": [\n          22,\n          139,\n          100,\n          211\n        ]\n      },\n      \"group\": \"filesystem\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"createEd25519Key\",\n        \"description\": \"Generates an Ed25519 key pair from a deterministic salt.\\nReturns (publicKey, privateKey) as 32-byte values.\",\n        \"declaration\": \"function createEd25519Key(bytes32 salt) external pure returns (bytes32 publicKey, bytes32 privateKey);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"createEd25519Key(bytes32)\",\n        \"selector\": \"0x1ef3f27a\",\n        \"selectorBytes\": [\n          30,\n          243,\n          242,\n          122\n        ]\n      },\n      \"group\": \"crypto\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"createFork_0\",\n        \"description\": \"Creates a new fork with the given endpoint and the _latest_ block and returns the identifier of the fork.\",\n        \"declaration\": \"function createFork(string calldata urlOrAlias) external returns (uint256 forkId);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"createFork(string)\",\n        \"selector\": \"0x31ba3498\",\n        \"selectorBytes\": [\n          49,\n          186,\n          52,\n          152\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"createFork_1\",\n        \"description\": \"Creates a new fork with the given endpoint and block and returns the identifier of the fork.\",\n        \"declaration\": \"function createFork(string calldata urlOrAlias, uint256 blockNumber) external returns (uint256 forkId);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"createFork(string,uint256)\",\n        \"selector\": \"0x6ba3ba2b\",\n        \"selectorBytes\": [\n          107,\n          163,\n          186,\n          43\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"createFork_2\",\n        \"description\": \"Creates a new fork with the given endpoint and at the block the given transaction was mined in,\\nreplays all transaction mined in the block before the transaction, and returns the identifier of the fork.\",\n        \"declaration\": \"function createFork(string calldata urlOrAlias, bytes32 txHash) external returns (uint256 forkId);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"createFork(string,bytes32)\",\n        \"selector\": \"0x7ca29682\",\n        \"selectorBytes\": [\n          124,\n          162,\n          150,\n          130\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"createSelectFork_0\",\n        \"description\": \"Creates and also selects a new fork with the given endpoint and the latest block and returns the identifier of the fork.\",\n        \"declaration\": \"function createSelectFork(string calldata urlOrAlias) external returns (uint256 forkId);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"createSelectFork(string)\",\n        \"selector\": \"0x98680034\",\n        \"selectorBytes\": [\n          152,\n          104,\n          0,\n          52\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"createSelectFork_1\",\n        \"description\": \"Creates and also selects a new fork with the given endpoint and block and returns the identifier of the fork.\",\n        \"declaration\": \"function createSelectFork(string calldata urlOrAlias, uint256 blockNumber) external returns (uint256 forkId);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"createSelectFork(string,uint256)\",\n        \"selector\": \"0x71ee464d\",\n        \"selectorBytes\": [\n          113,\n          238,\n          70,\n          77\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"createSelectFork_2\",\n        \"description\": \"Creates and also selects new fork with the given endpoint and at the block the given transaction was mined in,\\nreplays all transaction mined in the block before the transaction, returns the identifier of the fork.\",\n        \"declaration\": \"function createSelectFork(string calldata urlOrAlias, bytes32 txHash) external returns (uint256 forkId);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"createSelectFork(string,bytes32)\",\n        \"selector\": \"0x84d52b7a\",\n        \"selectorBytes\": [\n          132,\n          213,\n          43,\n          122\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"createWallet_0\",\n        \"description\": \"Derives a private key from the name, labels the account with that name, and returns the wallet.\",\n        \"declaration\": \"function createWallet(string calldata walletLabel) external returns (Wallet memory wallet);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"createWallet(string)\",\n        \"selector\": \"0x7404f1d2\",\n        \"selectorBytes\": [\n          116,\n          4,\n          241,\n          210\n        ]\n      },\n      \"group\": \"crypto\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"createWallet_1\",\n        \"description\": \"Generates a wallet from the private key and returns the wallet.\",\n        \"declaration\": \"function createWallet(uint256 privateKey) external returns (Wallet memory wallet);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"createWallet(uint256)\",\n        \"selector\": \"0x7a675bb6\",\n        \"selectorBytes\": [\n          122,\n          103,\n          91,\n          182\n        ]\n      },\n      \"group\": \"crypto\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"createWallet_2\",\n        \"description\": \"Generates a wallet from the private key, labels the account with that name, and returns the wallet.\",\n        \"declaration\": \"function createWallet(uint256 privateKey, string calldata walletLabel) external returns (Wallet memory wallet);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"createWallet(uint256,string)\",\n        \"selector\": \"0xed7c5462\",\n        \"selectorBytes\": [\n          237,\n          124,\n          84,\n          98\n        ]\n      },\n      \"group\": \"crypto\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"currentFilePath\",\n        \"description\": \"Get the source file path of the currently running test or script contract,\\nrelative to the project root.\",\n        \"declaration\": \"function currentFilePath() external view returns (string memory path);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"currentFilePath()\",\n        \"selector\": \"0x9b45555c\",\n        \"selectorBytes\": [\n          155,\n          69,\n          85,\n          92\n        ]\n      },\n      \"group\": \"filesystem\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"deal\",\n        \"description\": \"Sets an address' balance.\",\n        \"declaration\": \"function deal(address account, uint256 newBalance) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"deal(address,uint256)\",\n        \"selector\": \"0xc88a5e6d\",\n        \"selectorBytes\": [\n          200,\n          138,\n          94,\n          109\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"deleteSnapshot\",\n        \"description\": \"`deleteSnapshot` is being deprecated in favor of `deleteStateSnapshot`. It will be removed in future versions.\",\n        \"declaration\": \"function deleteSnapshot(uint256 snapshotId) external returns (bool success);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"deleteSnapshot(uint256)\",\n        \"selector\": \"0xa6368557\",\n        \"selectorBytes\": [\n          166,\n          54,\n          133,\n          87\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": {\n        \"deprecated\": \"replaced by `deleteStateSnapshot`\"\n      },\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"deleteSnapshots\",\n        \"description\": \"`deleteSnapshots` is being deprecated in favor of `deleteStateSnapshots`. It will be removed in future versions.\",\n        \"declaration\": \"function deleteSnapshots() external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"deleteSnapshots()\",\n        \"selector\": \"0x421ae469\",\n        \"selectorBytes\": [\n          66,\n          26,\n          228,\n          105\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": {\n        \"deprecated\": \"replaced by `deleteStateSnapshots`\"\n      },\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"deleteStateSnapshot\",\n        \"description\": \"Removes the snapshot with the given ID created by `snapshot`.\\nTakes the snapshot ID to delete.\\nReturns `true` if the snapshot was successfully deleted.\\nReturns `false` if the snapshot does not exist.\",\n        \"declaration\": \"function deleteStateSnapshot(uint256 snapshotId) external returns (bool success);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"deleteStateSnapshot(uint256)\",\n        \"selector\": \"0x08d6b37a\",\n        \"selectorBytes\": [\n          8,\n          214,\n          179,\n          122\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"deleteStateSnapshots\",\n        \"description\": \"Removes _all_ snapshots previously created by `snapshot`.\",\n        \"declaration\": \"function deleteStateSnapshots() external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"deleteStateSnapshots()\",\n        \"selector\": \"0xe0933c74\",\n        \"selectorBytes\": [\n          224,\n          147,\n          60,\n          116\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"deployCode_0\",\n        \"description\": \"Deploys a contract from an artifact file. Takes in the relative path to the json file or the path to the\\nartifact in the form of <path>:<contract>:<version> where <contract> and <version> parts are optional.\\nReverts if the target artifact contains unlinked library placeholders.\",\n        \"declaration\": \"function deployCode(string calldata artifactPath) external returns (address deployedAddress);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"deployCode(string)\",\n        \"selector\": \"0x9a8325a0\",\n        \"selectorBytes\": [\n          154,\n          131,\n          37,\n          160\n        ]\n      },\n      \"group\": \"filesystem\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"deployCode_1\",\n        \"description\": \"Deploys a contract from an artifact file. Takes in the relative path to the json file or the path to the\\nartifact in the form of <path>:<contract>:<version> where <contract> and <version> parts are optional.\\nReverts if the target artifact contains unlinked library placeholders.\\nAdditionally accepts abi-encoded constructor arguments.\",\n        \"declaration\": \"function deployCode(string calldata artifactPath, bytes calldata constructorArgs) external returns (address deployedAddress);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"deployCode(string,bytes)\",\n        \"selector\": \"0x29ce9dde\",\n        \"selectorBytes\": [\n          41,\n          206,\n          157,\n          222\n        ]\n      },\n      \"group\": \"filesystem\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"deployCode_2\",\n        \"description\": \"Deploys a contract from an artifact file. Takes in the relative path to the json file or the path to the\\nartifact in the form of <path>:<contract>:<version> where <contract> and <version> parts are optional.\\nReverts if the target artifact contains unlinked library placeholders.\\nAdditionally accepts `msg.value`.\",\n        \"declaration\": \"function deployCode(string calldata artifactPath, uint256 value) external returns (address deployedAddress);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"deployCode(string,uint256)\",\n        \"selector\": \"0x0af6a701\",\n        \"selectorBytes\": [\n          10,\n          246,\n          167,\n          1\n        ]\n      },\n      \"group\": \"filesystem\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"deployCode_3\",\n        \"description\": \"Deploys a contract from an artifact file. Takes in the relative path to the json file or the path to the\\nartifact in the form of <path>:<contract>:<version> where <contract> and <version> parts are optional.\\nReverts if the target artifact contains unlinked library placeholders.\\nAdditionally accepts abi-encoded constructor arguments and `msg.value`.\",\n        \"declaration\": \"function deployCode(string calldata artifactPath, bytes calldata constructorArgs, uint256 value) external returns (address deployedAddress);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"deployCode(string,bytes,uint256)\",\n        \"selector\": \"0xff5d64e4\",\n        \"selectorBytes\": [\n          255,\n          93,\n          100,\n          228\n        ]\n      },\n      \"group\": \"filesystem\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"deployCode_4\",\n        \"description\": \"Deploys a contract from an artifact file, using the CREATE2 salt. Takes in the relative path to the json file or the path to the\\nartifact in the form of <path>:<contract>:<version> where <contract> and <version> parts are optional.\\nReverts if the target artifact contains unlinked library placeholders.\",\n        \"declaration\": \"function deployCode(string calldata artifactPath, bytes32 salt) external returns (address deployedAddress);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"deployCode(string,bytes32)\",\n        \"selector\": \"0x17ab1d79\",\n        \"selectorBytes\": [\n          23,\n          171,\n          29,\n          121\n        ]\n      },\n      \"group\": \"filesystem\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"deployCode_5\",\n        \"description\": \"Deploys a contract from an artifact file, using the CREATE2 salt. Takes in the relative path to the json file or the path to the\\nartifact in the form of <path>:<contract>:<version> where <contract> and <version> parts are optional.\\nReverts if the target artifact contains unlinked library placeholders.\\nAdditionally accepts abi-encoded constructor arguments.\",\n        \"declaration\": \"function deployCode(string calldata artifactPath, bytes calldata constructorArgs, bytes32 salt) external returns (address deployedAddress);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"deployCode(string,bytes,bytes32)\",\n        \"selector\": \"0x016155bf\",\n        \"selectorBytes\": [\n          1,\n          97,\n          85,\n          191\n        ]\n      },\n      \"group\": \"filesystem\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"deployCode_6\",\n        \"description\": \"Deploys a contract from an artifact file, using the CREATE2 salt. Takes in the relative path to the json file or the path to the\\nartifact in the form of <path>:<contract>:<version> where <contract> and <version> parts are optional.\\nReverts if the target artifact contains unlinked library placeholders.\\nAdditionally accepts `msg.value`.\",\n        \"declaration\": \"function deployCode(string calldata artifactPath, uint256 value, bytes32 salt) external returns (address deployedAddress);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"deployCode(string,uint256,bytes32)\",\n        \"selector\": \"0x002cb687\",\n        \"selectorBytes\": [\n          0,\n          44,\n          182,\n          135\n        ]\n      },\n      \"group\": \"filesystem\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"deployCode_7\",\n        \"description\": \"Deploys a contract from an artifact file, using the CREATE2 salt. Takes in the relative path to the json file or the path to the\\nartifact in the form of <path>:<contract>:<version> where <contract> and <version> parts are optional.\\nReverts if the target artifact contains unlinked library placeholders.\\nAdditionally accepts abi-encoded constructor arguments and `msg.value`.\",\n        \"declaration\": \"function deployCode(string calldata artifactPath, bytes calldata constructorArgs, uint256 value, bytes32 salt) external returns (address deployedAddress);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"deployCode(string,bytes,uint256,bytes32)\",\n        \"selector\": \"0x3aa773ea\",\n        \"selectorBytes\": [\n          58,\n          167,\n          115,\n          234\n        ]\n      },\n      \"group\": \"filesystem\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"deriveKey_0\",\n        \"description\": \"Derive a private key from a provided mnemonic string (or mnemonic file path)\\nat the derivation path `m/44'/60'/0'/0/{index}`.\",\n        \"declaration\": \"function deriveKey(string calldata mnemonic, uint32 index) external pure returns (uint256 privateKey);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"deriveKey(string,uint32)\",\n        \"selector\": \"0x6229498b\",\n        \"selectorBytes\": [\n          98,\n          41,\n          73,\n          139\n        ]\n      },\n      \"group\": \"crypto\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"deriveKey_1\",\n        \"description\": \"Derive a private key from a provided mnemonic string (or mnemonic file path)\\nat `{derivationPath}{index}`.\",\n        \"declaration\": \"function deriveKey(string calldata mnemonic, string calldata derivationPath, uint32 index) external pure returns (uint256 privateKey);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"deriveKey(string,string,uint32)\",\n        \"selector\": \"0x6bcb2c1b\",\n        \"selectorBytes\": [\n          107,\n          203,\n          44,\n          27\n        ]\n      },\n      \"group\": \"crypto\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"deriveKey_2\",\n        \"description\": \"Derive a private key from a provided mnemonic string (or mnemonic file path) in the specified language\\nat the derivation path `m/44'/60'/0'/0/{index}`.\",\n        \"declaration\": \"function deriveKey(string calldata mnemonic, uint32 index, string calldata language) external pure returns (uint256 privateKey);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"deriveKey(string,uint32,string)\",\n        \"selector\": \"0x32c8176d\",\n        \"selectorBytes\": [\n          50,\n          200,\n          23,\n          109\n        ]\n      },\n      \"group\": \"crypto\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"deriveKey_3\",\n        \"description\": \"Derive a private key from a provided mnemonic string (or mnemonic file path) in the specified language\\nat `{derivationPath}{index}`.\",\n        \"declaration\": \"function deriveKey(string calldata mnemonic, string calldata derivationPath, uint32 index, string calldata language) external pure returns (uint256 privateKey);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"deriveKey(string,string,uint32,string)\",\n        \"selector\": \"0x29233b1f\",\n        \"selectorBytes\": [\n          41,\n          35,\n          59,\n          31\n        ]\n      },\n      \"group\": \"crypto\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"difficulty\",\n        \"description\": \"Sets `block.difficulty`.\\nNot available on EVM versions from Paris onwards. Use `prevrandao` instead.\\nReverts if used on unsupported EVM versions.\",\n        \"declaration\": \"function difficulty(uint256 newDifficulty) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"difficulty(uint256)\",\n        \"selector\": \"0x46cc92d9\",\n        \"selectorBytes\": [\n          70,\n          204,\n          146,\n          217\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"dumpState\",\n        \"description\": \"Dump a genesis JSON file's `allocs` to disk.\",\n        \"declaration\": \"function dumpState(string calldata pathToStateJson) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"dumpState(string)\",\n        \"selector\": \"0x709ecd3f\",\n        \"selectorBytes\": [\n          112,\n          158,\n          205,\n          63\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"eip712HashStruct_0\",\n        \"description\": \"Generates the struct hash of the canonical EIP-712 type representation and its abi-encoded data.\\nSupports 2 different inputs:\\n 1. Name of the type (i.e. \\\"PermitSingle\\\"):\\n    * requires previous binding generation with `forge bind-json`.\\n    * bindings will be retrieved from the path configured in `foundry.toml`.\\n 2. String representation of the type (i.e. \\\"Foo(Bar bar) Bar(uint256 baz)\\\").\\n    * Note: the cheatcode will use the canonical type even if the input is malformated\\n            with the wrong order of elements or with extra whitespaces.\",\n        \"declaration\": \"function eip712HashStruct(string calldata typeNameOrDefinition, bytes calldata abiEncodedData) external pure returns (bytes32 typeHash);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"eip712HashStruct(string,bytes)\",\n        \"selector\": \"0xaedeaebc\",\n        \"selectorBytes\": [\n          174,\n          222,\n          174,\n          188\n        ]\n      },\n      \"group\": \"utilities\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"eip712HashStruct_1\",\n        \"description\": \"Generates the struct hash of the canonical EIP-712 type representation and its abi-encoded data.\\nRequires previous binding generation with `forge bind-json`.\\nParams:\\n * `bindingsPath`: path where the output of `forge bind-json` is stored.\\n * `typeName`: Name of the type (i.e. \\\"PermitSingle\\\").\\n * `abiEncodedData`: ABI-encoded data for the struct that is being hashed.\",\n        \"declaration\": \"function eip712HashStruct(string calldata bindingsPath, string calldata typeName, bytes calldata abiEncodedData) external pure returns (bytes32 typeHash);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"eip712HashStruct(string,string,bytes)\",\n        \"selector\": \"0x6d06c57c\",\n        \"selectorBytes\": [\n          109,\n          6,\n          197,\n          124\n        ]\n      },\n      \"group\": \"utilities\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"eip712HashType_0\",\n        \"description\": \"Generates the hash of the canonical EIP-712 type representation.\\nSupports 2 different inputs:\\n 1. Name of the type (i.e. \\\"Transaction\\\"):\\n    * requires previous binding generation with `forge bind-json`.\\n    * bindings will be retrieved from the path configured in `foundry.toml`.\\n 2. String representation of the type (i.e. \\\"Foo(Bar bar) Bar(uint256 baz)\\\").\\n    * Note: the cheatcode will output the canonical type even if the input is malformated\\n            with the wrong order of elements or with extra whitespaces.\",\n        \"declaration\": \"function eip712HashType(string calldata typeNameOrDefinition) external pure returns (bytes32 typeHash);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"eip712HashType(string)\",\n        \"selector\": \"0x6792e9e2\",\n        \"selectorBytes\": [\n          103,\n          146,\n          233,\n          226\n        ]\n      },\n      \"group\": \"utilities\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"eip712HashType_1\",\n        \"description\": \"Generates the hash of the canonical EIP-712 type representation.\\nRequires previous binding generation with `forge bind-json`.\\nParams:\\n * `bindingsPath`: path where the output of `forge bind-json` is stored.\\n * `typeName`: Name of the type (i.e. \\\"Transaction\\\").\",\n        \"declaration\": \"function eip712HashType(string calldata bindingsPath, string calldata typeName) external pure returns (bytes32 typeHash);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"eip712HashType(string,string)\",\n        \"selector\": \"0x18fb6406\",\n        \"selectorBytes\": [\n          24,\n          251,\n          100,\n          6\n        ]\n      },\n      \"group\": \"utilities\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"eip712HashTypedData\",\n        \"description\": \"Generates a ready-to-sign digest of human-readable typed data following the EIP-712 standard.\",\n        \"declaration\": \"function eip712HashTypedData(string calldata jsonData) external pure returns (bytes32 digest);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"eip712HashTypedData(string)\",\n        \"selector\": \"0xea25e615\",\n        \"selectorBytes\": [\n          234,\n          37,\n          230,\n          21\n        ]\n      },\n      \"group\": \"utilities\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"ensNamehash\",\n        \"description\": \"Returns ENS namehash for provided string.\",\n        \"declaration\": \"function ensNamehash(string calldata name) external pure returns (bytes32);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"ensNamehash(string)\",\n        \"selector\": \"0x8c374c65\",\n        \"selectorBytes\": [\n          140,\n          55,\n          76,\n          101\n        ]\n      },\n      \"group\": \"utilities\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"envAddress_0\",\n        \"description\": \"Gets the environment variable `name` and parses it as `address`.\\nReverts if the variable was not found or could not be parsed.\",\n        \"declaration\": \"function envAddress(string calldata name) external view returns (address value);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"envAddress(string)\",\n        \"selector\": \"0x350d56bf\",\n        \"selectorBytes\": [\n          53,\n          13,\n          86,\n          191\n        ]\n      },\n      \"group\": \"environment\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"envAddress_1\",\n        \"description\": \"Gets the environment variable `name` and parses it as an array of `address`, delimited by `delim`.\\nReverts if the variable was not found or could not be parsed.\",\n        \"declaration\": \"function envAddress(string calldata name, string calldata delim) external view returns (address[] memory value);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"envAddress(string,string)\",\n        \"selector\": \"0xad31b9fa\",\n        \"selectorBytes\": [\n          173,\n          49,\n          185,\n          250\n        ]\n      },\n      \"group\": \"environment\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"envBool_0\",\n        \"description\": \"Gets the environment variable `name` and parses it as `bool`.\\nReverts if the variable was not found or could not be parsed.\",\n        \"declaration\": \"function envBool(string calldata name) external view returns (bool value);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"envBool(string)\",\n        \"selector\": \"0x7ed1ec7d\",\n        \"selectorBytes\": [\n          126,\n          209,\n          236,\n          125\n        ]\n      },\n      \"group\": \"environment\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"envBool_1\",\n        \"description\": \"Gets the environment variable `name` and parses it as an array of `bool`, delimited by `delim`.\\nReverts if the variable was not found or could not be parsed.\",\n        \"declaration\": \"function envBool(string calldata name, string calldata delim) external view returns (bool[] memory value);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"envBool(string,string)\",\n        \"selector\": \"0xaaaddeaf\",\n        \"selectorBytes\": [\n          170,\n          173,\n          222,\n          175\n        ]\n      },\n      \"group\": \"environment\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"envBytes32_0\",\n        \"description\": \"Gets the environment variable `name` and parses it as `bytes32`.\\nReverts if the variable was not found or could not be parsed.\",\n        \"declaration\": \"function envBytes32(string calldata name) external view returns (bytes32 value);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"envBytes32(string)\",\n        \"selector\": \"0x97949042\",\n        \"selectorBytes\": [\n          151,\n          148,\n          144,\n          66\n        ]\n      },\n      \"group\": \"environment\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"envBytes32_1\",\n        \"description\": \"Gets the environment variable `name` and parses it as an array of `bytes32`, delimited by `delim`.\\nReverts if the variable was not found or could not be parsed.\",\n        \"declaration\": \"function envBytes32(string calldata name, string calldata delim) external view returns (bytes32[] memory value);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"envBytes32(string,string)\",\n        \"selector\": \"0x5af231c1\",\n        \"selectorBytes\": [\n          90,\n          242,\n          49,\n          193\n        ]\n      },\n      \"group\": \"environment\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"envBytes_0\",\n        \"description\": \"Gets the environment variable `name` and parses it as `bytes`.\\nReverts if the variable was not found or could not be parsed.\",\n        \"declaration\": \"function envBytes(string calldata name) external view returns (bytes memory value);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"envBytes(string)\",\n        \"selector\": \"0x4d7baf06\",\n        \"selectorBytes\": [\n          77,\n          123,\n          175,\n          6\n        ]\n      },\n      \"group\": \"environment\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"envBytes_1\",\n        \"description\": \"Gets the environment variable `name` and parses it as an array of `bytes`, delimited by `delim`.\\nReverts if the variable was not found or could not be parsed.\",\n        \"declaration\": \"function envBytes(string calldata name, string calldata delim) external view returns (bytes[] memory value);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"envBytes(string,string)\",\n        \"selector\": \"0xddc2651b\",\n        \"selectorBytes\": [\n          221,\n          194,\n          101,\n          27\n        ]\n      },\n      \"group\": \"environment\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"envExists\",\n        \"description\": \"Gets the environment variable `name` and returns true if it exists, else returns false.\",\n        \"declaration\": \"function envExists(string calldata name) external view returns (bool result);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"envExists(string)\",\n        \"selector\": \"0xce8365f9\",\n        \"selectorBytes\": [\n          206,\n          131,\n          101,\n          249\n        ]\n      },\n      \"group\": \"environment\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"envInt_0\",\n        \"description\": \"Gets the environment variable `name` and parses it as `int256`.\\nReverts if the variable was not found or could not be parsed.\",\n        \"declaration\": \"function envInt(string calldata name) external view returns (int256 value);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"envInt(string)\",\n        \"selector\": \"0x892a0c61\",\n        \"selectorBytes\": [\n          137,\n          42,\n          12,\n          97\n        ]\n      },\n      \"group\": \"environment\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"envInt_1\",\n        \"description\": \"Gets the environment variable `name` and parses it as an array of `int256`, delimited by `delim`.\\nReverts if the variable was not found or could not be parsed.\",\n        \"declaration\": \"function envInt(string calldata name, string calldata delim) external view returns (int256[] memory value);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"envInt(string,string)\",\n        \"selector\": \"0x42181150\",\n        \"selectorBytes\": [\n          66,\n          24,\n          17,\n          80\n        ]\n      },\n      \"group\": \"environment\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"envOr_0\",\n        \"description\": \"Gets the environment variable `name` and parses it as `bool`.\\nReverts if the variable could not be parsed.\\nReturns `defaultValue` if the variable was not found.\",\n        \"declaration\": \"function envOr(string calldata name, bool defaultValue) external view returns (bool value);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"envOr(string,bool)\",\n        \"selector\": \"0x4777f3cf\",\n        \"selectorBytes\": [\n          71,\n          119,\n          243,\n          207\n        ]\n      },\n      \"group\": \"environment\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"envOr_1\",\n        \"description\": \"Gets the environment variable `name` and parses it as `uint256`.\\nReverts if the variable could not be parsed.\\nReturns `defaultValue` if the variable was not found.\",\n        \"declaration\": \"function envOr(string calldata name, uint256 defaultValue) external view returns (uint256 value);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"envOr(string,uint256)\",\n        \"selector\": \"0x5e97348f\",\n        \"selectorBytes\": [\n          94,\n          151,\n          52,\n          143\n        ]\n      },\n      \"group\": \"environment\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"envOr_10\",\n        \"description\": \"Gets the environment variable `name` and parses it as an array of `address`, delimited by `delim`.\\nReverts if the variable could not be parsed.\\nReturns `defaultValue` if the variable was not found.\",\n        \"declaration\": \"function envOr(string calldata name, string calldata delim, address[] calldata defaultValue) external view returns (address[] memory value);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"envOr(string,string,address[])\",\n        \"selector\": \"0xc74e9deb\",\n        \"selectorBytes\": [\n          199,\n          78,\n          157,\n          235\n        ]\n      },\n      \"group\": \"environment\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"envOr_11\",\n        \"description\": \"Gets the environment variable `name` and parses it as an array of `bytes32`, delimited by `delim`.\\nReverts if the variable could not be parsed.\\nReturns `defaultValue` if the variable was not found.\",\n        \"declaration\": \"function envOr(string calldata name, string calldata delim, bytes32[] calldata defaultValue) external view returns (bytes32[] memory value);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"envOr(string,string,bytes32[])\",\n        \"selector\": \"0x2281f367\",\n        \"selectorBytes\": [\n          34,\n          129,\n          243,\n          103\n        ]\n      },\n      \"group\": \"environment\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"envOr_12\",\n        \"description\": \"Gets the environment variable `name` and parses it as an array of `string`, delimited by `delim`.\\nReverts if the variable could not be parsed.\\nReturns `defaultValue` if the variable was not found.\",\n        \"declaration\": \"function envOr(string calldata name, string calldata delim, string[] calldata defaultValue) external view returns (string[] memory value);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"envOr(string,string,string[])\",\n        \"selector\": \"0x859216bc\",\n        \"selectorBytes\": [\n          133,\n          146,\n          22,\n          188\n        ]\n      },\n      \"group\": \"environment\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"envOr_13\",\n        \"description\": \"Gets the environment variable `name` and parses it as an array of `bytes`, delimited by `delim`.\\nReverts if the variable could not be parsed.\\nReturns `defaultValue` if the variable was not found.\",\n        \"declaration\": \"function envOr(string calldata name, string calldata delim, bytes[] calldata defaultValue) external view returns (bytes[] memory value);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"envOr(string,string,bytes[])\",\n        \"selector\": \"0x64bc3e64\",\n        \"selectorBytes\": [\n          100,\n          188,\n          62,\n          100\n        ]\n      },\n      \"group\": \"environment\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"envOr_2\",\n        \"description\": \"Gets the environment variable `name` and parses it as `int256`.\\nReverts if the variable could not be parsed.\\nReturns `defaultValue` if the variable was not found.\",\n        \"declaration\": \"function envOr(string calldata name, int256 defaultValue) external view returns (int256 value);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"envOr(string,int256)\",\n        \"selector\": \"0xbbcb713e\",\n        \"selectorBytes\": [\n          187,\n          203,\n          113,\n          62\n        ]\n      },\n      \"group\": \"environment\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"envOr_3\",\n        \"description\": \"Gets the environment variable `name` and parses it as `address`.\\nReverts if the variable could not be parsed.\\nReturns `defaultValue` if the variable was not found.\",\n        \"declaration\": \"function envOr(string calldata name, address defaultValue) external view returns (address value);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"envOr(string,address)\",\n        \"selector\": \"0x561fe540\",\n        \"selectorBytes\": [\n          86,\n          31,\n          229,\n          64\n        ]\n      },\n      \"group\": \"environment\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"envOr_4\",\n        \"description\": \"Gets the environment variable `name` and parses it as `bytes32`.\\nReverts if the variable could not be parsed.\\nReturns `defaultValue` if the variable was not found.\",\n        \"declaration\": \"function envOr(string calldata name, bytes32 defaultValue) external view returns (bytes32 value);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"envOr(string,bytes32)\",\n        \"selector\": \"0xb4a85892\",\n        \"selectorBytes\": [\n          180,\n          168,\n          88,\n          146\n        ]\n      },\n      \"group\": \"environment\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"envOr_5\",\n        \"description\": \"Gets the environment variable `name` and parses it as `string`.\\nReverts if the variable could not be parsed.\\nReturns `defaultValue` if the variable was not found.\",\n        \"declaration\": \"function envOr(string calldata name, string calldata defaultValue) external view returns (string memory value);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"envOr(string,string)\",\n        \"selector\": \"0xd145736c\",\n        \"selectorBytes\": [\n          209,\n          69,\n          115,\n          108\n        ]\n      },\n      \"group\": \"environment\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"envOr_6\",\n        \"description\": \"Gets the environment variable `name` and parses it as `bytes`.\\nReverts if the variable could not be parsed.\\nReturns `defaultValue` if the variable was not found.\",\n        \"declaration\": \"function envOr(string calldata name, bytes calldata defaultValue) external view returns (bytes memory value);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"envOr(string,bytes)\",\n        \"selector\": \"0xb3e47705\",\n        \"selectorBytes\": [\n          179,\n          228,\n          119,\n          5\n        ]\n      },\n      \"group\": \"environment\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"envOr_7\",\n        \"description\": \"Gets the environment variable `name` and parses it as an array of `bool`, delimited by `delim`.\\nReverts if the variable could not be parsed.\\nReturns `defaultValue` if the variable was not found.\",\n        \"declaration\": \"function envOr(string calldata name, string calldata delim, bool[] calldata defaultValue) external view returns (bool[] memory value);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"envOr(string,string,bool[])\",\n        \"selector\": \"0xeb85e83b\",\n        \"selectorBytes\": [\n          235,\n          133,\n          232,\n          59\n        ]\n      },\n      \"group\": \"environment\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"envOr_8\",\n        \"description\": \"Gets the environment variable `name` and parses it as an array of `uint256`, delimited by `delim`.\\nReverts if the variable could not be parsed.\\nReturns `defaultValue` if the variable was not found.\",\n        \"declaration\": \"function envOr(string calldata name, string calldata delim, uint256[] calldata defaultValue) external view returns (uint256[] memory value);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"envOr(string,string,uint256[])\",\n        \"selector\": \"0x74318528\",\n        \"selectorBytes\": [\n          116,\n          49,\n          133,\n          40\n        ]\n      },\n      \"group\": \"environment\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"envOr_9\",\n        \"description\": \"Gets the environment variable `name` and parses it as an array of `int256`, delimited by `delim`.\\nReverts if the variable could not be parsed.\\nReturns `defaultValue` if the variable was not found.\",\n        \"declaration\": \"function envOr(string calldata name, string calldata delim, int256[] calldata defaultValue) external view returns (int256[] memory value);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"envOr(string,string,int256[])\",\n        \"selector\": \"0x4700d74b\",\n        \"selectorBytes\": [\n          71,\n          0,\n          215,\n          75\n        ]\n      },\n      \"group\": \"environment\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"envString_0\",\n        \"description\": \"Gets the environment variable `name` and parses it as `string`.\\nReverts if the variable was not found or could not be parsed.\",\n        \"declaration\": \"function envString(string calldata name) external view returns (string memory value);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"envString(string)\",\n        \"selector\": \"0xf877cb19\",\n        \"selectorBytes\": [\n          248,\n          119,\n          203,\n          25\n        ]\n      },\n      \"group\": \"environment\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"envString_1\",\n        \"description\": \"Gets the environment variable `name` and parses it as an array of `string`, delimited by `delim`.\\nReverts if the variable was not found or could not be parsed.\",\n        \"declaration\": \"function envString(string calldata name, string calldata delim) external view returns (string[] memory value);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"envString(string,string)\",\n        \"selector\": \"0x14b02bc9\",\n        \"selectorBytes\": [\n          20,\n          176,\n          43,\n          201\n        ]\n      },\n      \"group\": \"environment\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"envUint_0\",\n        \"description\": \"Gets the environment variable `name` and parses it as `uint256`.\\nReverts if the variable was not found or could not be parsed.\",\n        \"declaration\": \"function envUint(string calldata name) external view returns (uint256 value);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"envUint(string)\",\n        \"selector\": \"0xc1978d1f\",\n        \"selectorBytes\": [\n          193,\n          151,\n          141,\n          31\n        ]\n      },\n      \"group\": \"environment\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"envUint_1\",\n        \"description\": \"Gets the environment variable `name` and parses it as an array of `uint256`, delimited by `delim`.\\nReverts if the variable was not found or could not be parsed.\",\n        \"declaration\": \"function envUint(string calldata name, string calldata delim) external view returns (uint256[] memory value);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"envUint(string,string)\",\n        \"selector\": \"0xf3dec099\",\n        \"selectorBytes\": [\n          243,\n          222,\n          192,\n          153\n        ]\n      },\n      \"group\": \"environment\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"etch\",\n        \"description\": \"Sets an address' code.\",\n        \"declaration\": \"function etch(address target, bytes calldata newRuntimeBytecode) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"etch(address,bytes)\",\n        \"selector\": \"0xb4d6c782\",\n        \"selectorBytes\": [\n          180,\n          214,\n          199,\n          130\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"eth_getLogs\",\n        \"description\": \"Gets all the logs according to specified filter.\",\n        \"declaration\": \"function eth_getLogs(uint256 fromBlock, uint256 toBlock, address target, bytes32[] calldata topics) external view returns (EthGetLogs[] memory logs);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"eth_getLogs(uint256,uint256,address,bytes32[])\",\n        \"selector\": \"0x35e1349b\",\n        \"selectorBytes\": [\n          53,\n          225,\n          52,\n          155\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"executeTransaction\",\n        \"description\": \"Executes an RLP-encoded signed transaction with full EVM semantics (like `--isolate` mode).\\nThe transaction is decoded from EIP-2718 format (type byte prefix + RLP payload) or legacy RLP.\\nReturns the execution output bytes.\\nThis cheatcode is not allowed in `forge script` contexts.\",\n        \"declaration\": \"function executeTransaction(bytes calldata rawTx) external returns (bytes memory);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"executeTransaction(bytes)\",\n        \"selector\": \"0x943d7209\",\n        \"selectorBytes\": [\n          148,\n          61,\n          114,\n          9\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"exists\",\n        \"description\": \"Returns true if the given path points to an existing entity, else returns false.\",\n        \"declaration\": \"function exists(string calldata path) external view returns (bool result);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"exists(string)\",\n        \"selector\": \"0x261a323e\",\n        \"selectorBytes\": [\n          38,\n          26,\n          50,\n          62\n        ]\n      },\n      \"group\": \"filesystem\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"expectCallMinGas_0\",\n        \"description\": \"Expect a call to an address with the specified `msg.value` and calldata, and a *minimum* amount of gas.\",\n        \"declaration\": \"function expectCallMinGas(address callee, uint256 msgValue, uint64 minGas, bytes calldata data) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"expectCallMinGas(address,uint256,uint64,bytes)\",\n        \"selector\": \"0x08e4e116\",\n        \"selectorBytes\": [\n          8,\n          228,\n          225,\n          22\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"expectCallMinGas_1\",\n        \"description\": \"Expect given number of calls to an address with the specified `msg.value` and calldata, and a *minimum* amount of gas.\",\n        \"declaration\": \"function expectCallMinGas(address callee, uint256 msgValue, uint64 minGas, bytes calldata data, uint64 count) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"expectCallMinGas(address,uint256,uint64,bytes,uint64)\",\n        \"selector\": \"0xe13a1834\",\n        \"selectorBytes\": [\n          225,\n          58,\n          24,\n          52\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"expectCall_0\",\n        \"description\": \"Expects a call to an address with the specified calldata.\\nCalldata can either be a strict or a partial match.\",\n        \"declaration\": \"function expectCall(address callee, bytes calldata data) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"expectCall(address,bytes)\",\n        \"selector\": \"0xbd6af434\",\n        \"selectorBytes\": [\n          189,\n          106,\n          244,\n          52\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"expectCall_1\",\n        \"description\": \"Expects given number of calls to an address with the specified calldata.\",\n        \"declaration\": \"function expectCall(address callee, bytes calldata data, uint64 count) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"expectCall(address,bytes,uint64)\",\n        \"selector\": \"0xc1adbbff\",\n        \"selectorBytes\": [\n          193,\n          173,\n          187,\n          255\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"expectCall_2\",\n        \"description\": \"Expects a call to an address with the specified `msg.value` and calldata.\",\n        \"declaration\": \"function expectCall(address callee, uint256 msgValue, bytes calldata data) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"expectCall(address,uint256,bytes)\",\n        \"selector\": \"0xf30c7ba3\",\n        \"selectorBytes\": [\n          243,\n          12,\n          123,\n          163\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"expectCall_3\",\n        \"description\": \"Expects given number of calls to an address with the specified `msg.value` and calldata.\",\n        \"declaration\": \"function expectCall(address callee, uint256 msgValue, bytes calldata data, uint64 count) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"expectCall(address,uint256,bytes,uint64)\",\n        \"selector\": \"0xa2b1a1ae\",\n        \"selectorBytes\": [\n          162,\n          177,\n          161,\n          174\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"expectCall_4\",\n        \"description\": \"Expect a call to an address with the specified `msg.value`, gas, and calldata.\",\n        \"declaration\": \"function expectCall(address callee, uint256 msgValue, uint64 gas, bytes calldata data) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"expectCall(address,uint256,uint64,bytes)\",\n        \"selector\": \"0x23361207\",\n        \"selectorBytes\": [\n          35,\n          54,\n          18,\n          7\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"expectCall_5\",\n        \"description\": \"Expects given number of calls to an address with the specified `msg.value`, gas, and calldata.\",\n        \"declaration\": \"function expectCall(address callee, uint256 msgValue, uint64 gas, bytes calldata data, uint64 count) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"expectCall(address,uint256,uint64,bytes,uint64)\",\n        \"selector\": \"0x65b7b7cc\",\n        \"selectorBytes\": [\n          101,\n          183,\n          183,\n          204\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"expectCreate\",\n        \"description\": \"Expects the deployment of the specified bytecode by the specified address using the CREATE opcode\",\n        \"declaration\": \"function expectCreate(bytes calldata bytecode, address deployer) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"expectCreate(bytes,address)\",\n        \"selector\": \"0x73cdce36\",\n        \"selectorBytes\": [\n          115,\n          205,\n          206,\n          54\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"expectCreate2\",\n        \"description\": \"Expects the deployment of the specified bytecode by the specified address using the CREATE2 opcode\",\n        \"declaration\": \"function expectCreate2(bytes calldata bytecode, address deployer) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"expectCreate2(bytes,address)\",\n        \"selector\": \"0xea54a472\",\n        \"selectorBytes\": [\n          234,\n          84,\n          164,\n          114\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"expectEmitAnonymous_0\",\n        \"description\": \"Prepare an expected anonymous log with (bool checkTopic1, bool checkTopic2, bool checkTopic3, bool checkData.).\\nCall this function, then emit an anonymous event, then call a function. Internally after the call, we check if\\nlogs were emitted in the expected order with the expected topics and data (as specified by the booleans).\",\n        \"declaration\": \"function expectEmitAnonymous(bool checkTopic0, bool checkTopic1, bool checkTopic2, bool checkTopic3, bool checkData) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"expectEmitAnonymous(bool,bool,bool,bool,bool)\",\n        \"selector\": \"0xc948db5e\",\n        \"selectorBytes\": [\n          201,\n          72,\n          219,\n          94\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"expectEmitAnonymous_1\",\n        \"description\": \"Same as the previous method, but also checks supplied address against emitting contract.\",\n        \"declaration\": \"function expectEmitAnonymous(bool checkTopic0, bool checkTopic1, bool checkTopic2, bool checkTopic3, bool checkData, address emitter) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"expectEmitAnonymous(bool,bool,bool,bool,bool,address)\",\n        \"selector\": \"0x71c95899\",\n        \"selectorBytes\": [\n          113,\n          201,\n          88,\n          153\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"expectEmitAnonymous_2\",\n        \"description\": \"Prepare an expected anonymous log with all topic and data checks enabled.\\nCall this function, then emit an anonymous event, then call a function. Internally after the call, we check if\\nlogs were emitted in the expected order with the expected topics and data.\",\n        \"declaration\": \"function expectEmitAnonymous() external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"expectEmitAnonymous()\",\n        \"selector\": \"0x2e5f270c\",\n        \"selectorBytes\": [\n          46,\n          95,\n          39,\n          12\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"expectEmitAnonymous_3\",\n        \"description\": \"Same as the previous method, but also checks supplied address against emitting contract.\",\n        \"declaration\": \"function expectEmitAnonymous(address emitter) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"expectEmitAnonymous(address)\",\n        \"selector\": \"0x6fc68705\",\n        \"selectorBytes\": [\n          111,\n          198,\n          135,\n          5\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"expectEmit_0\",\n        \"description\": \"Prepare an expected log with (bool checkTopic1, bool checkTopic2, bool checkTopic3, bool checkData.).\\nCall this function, then emit an event, then call a function. Internally after the call, we check if\\nlogs were emitted in the expected order with the expected topics and data (as specified by the booleans).\",\n        \"declaration\": \"function expectEmit(bool checkTopic1, bool checkTopic2, bool checkTopic3, bool checkData) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"expectEmit(bool,bool,bool,bool)\",\n        \"selector\": \"0x491cc7c2\",\n        \"selectorBytes\": [\n          73,\n          28,\n          199,\n          194\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"expectEmit_1\",\n        \"description\": \"Same as the previous method, but also checks supplied address against emitting contract.\",\n        \"declaration\": \"function expectEmit(bool checkTopic1, bool checkTopic2, bool checkTopic3, bool checkData, address emitter) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"expectEmit(bool,bool,bool,bool,address)\",\n        \"selector\": \"0x81bad6f3\",\n        \"selectorBytes\": [\n          129,\n          186,\n          214,\n          243\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"expectEmit_2\",\n        \"description\": \"Prepare an expected log with all topic and data checks enabled.\\nCall this function, then emit an event, then call a function. Internally after the call, we check if\\nlogs were emitted in the expected order with the expected topics and data.\",\n        \"declaration\": \"function expectEmit() external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"expectEmit()\",\n        \"selector\": \"0x440ed10d\",\n        \"selectorBytes\": [\n          68,\n          14,\n          209,\n          13\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"expectEmit_3\",\n        \"description\": \"Same as the previous method, but also checks supplied address against emitting contract.\",\n        \"declaration\": \"function expectEmit(address emitter) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"expectEmit(address)\",\n        \"selector\": \"0x86b9620d\",\n        \"selectorBytes\": [\n          134,\n          185,\n          98,\n          13\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"expectEmit_4\",\n        \"description\": \"Expect a given number of logs with the provided topics.\",\n        \"declaration\": \"function expectEmit(bool checkTopic1, bool checkTopic2, bool checkTopic3, bool checkData, uint64 count) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"expectEmit(bool,bool,bool,bool,uint64)\",\n        \"selector\": \"0x5e1d1c33\",\n        \"selectorBytes\": [\n          94,\n          29,\n          28,\n          51\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"expectEmit_5\",\n        \"description\": \"Expect a given number of logs from a specific emitter with the provided topics.\",\n        \"declaration\": \"function expectEmit(bool checkTopic1, bool checkTopic2, bool checkTopic3, bool checkData, address emitter, uint64 count) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"expectEmit(bool,bool,bool,bool,address,uint64)\",\n        \"selector\": \"0xc339d02c\",\n        \"selectorBytes\": [\n          195,\n          57,\n          208,\n          44\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"expectEmit_6\",\n        \"description\": \"Expect a given number of logs with all topic and data checks enabled.\",\n        \"declaration\": \"function expectEmit(uint64 count) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"expectEmit(uint64)\",\n        \"selector\": \"0x4c74a335\",\n        \"selectorBytes\": [\n          76,\n          116,\n          163,\n          53\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"expectEmit_7\",\n        \"description\": \"Expect a given number of logs from a specific emitter with all topic and data checks enabled.\",\n        \"declaration\": \"function expectEmit(address emitter, uint64 count) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"expectEmit(address,uint64)\",\n        \"selector\": \"0xb43aece3\",\n        \"selectorBytes\": [\n          180,\n          58,\n          236,\n          227\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"expectPartialRevert_0\",\n        \"description\": \"Expects an error on next call that starts with the revert data.\",\n        \"declaration\": \"function expectPartialRevert(bytes4 revertData) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"expectPartialRevert(bytes4)\",\n        \"selector\": \"0x11fb5b9c\",\n        \"selectorBytes\": [\n          17,\n          251,\n          91,\n          156\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"expectPartialRevert_1\",\n        \"description\": \"Expects an error on next call to reverter address, that starts with the revert data.\",\n        \"declaration\": \"function expectPartialRevert(bytes4 revertData, address reverter) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"expectPartialRevert(bytes4,address)\",\n        \"selector\": \"0x51aa008a\",\n        \"selectorBytes\": [\n          81,\n          170,\n          0,\n          138\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"expectRevert_0\",\n        \"description\": \"Expects an error on next call with any revert data.\",\n        \"declaration\": \"function expectRevert() external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"expectRevert()\",\n        \"selector\": \"0xf4844814\",\n        \"selectorBytes\": [\n          244,\n          132,\n          72,\n          20\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"expectRevert_1\",\n        \"description\": \"Expects an error on next call that exactly matches the revert data.\",\n        \"declaration\": \"function expectRevert(bytes4 revertData) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"expectRevert(bytes4)\",\n        \"selector\": \"0xc31eb0e0\",\n        \"selectorBytes\": [\n          195,\n          30,\n          176,\n          224\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"expectRevert_10\",\n        \"description\": \"Expects a `count` number of reverts from the upcoming calls from the reverter address that match the revert data.\",\n        \"declaration\": \"function expectRevert(bytes4 revertData, address reverter, uint64 count) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"expectRevert(bytes4,address,uint64)\",\n        \"selector\": \"0xb0762d73\",\n        \"selectorBytes\": [\n          176,\n          118,\n          45,\n          115\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"expectRevert_11\",\n        \"description\": \"Expects a `count` number of reverts from the upcoming calls from the reverter address that exactly match the revert data.\",\n        \"declaration\": \"function expectRevert(bytes calldata revertData, address reverter, uint64 count) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"expectRevert(bytes,address,uint64)\",\n        \"selector\": \"0xd345fb1f\",\n        \"selectorBytes\": [\n          211,\n          69,\n          251,\n          31\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"expectRevert_2\",\n        \"description\": \"Expects an error on next call that exactly matches the revert data.\",\n        \"declaration\": \"function expectRevert(bytes calldata revertData) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"expectRevert(bytes)\",\n        \"selector\": \"0xf28dceb3\",\n        \"selectorBytes\": [\n          242,\n          141,\n          206,\n          179\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"expectRevert_3\",\n        \"description\": \"Expects an error with any revert data on next call to reverter address.\",\n        \"declaration\": \"function expectRevert(address reverter) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"expectRevert(address)\",\n        \"selector\": \"0xd814f38a\",\n        \"selectorBytes\": [\n          216,\n          20,\n          243,\n          138\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"expectRevert_4\",\n        \"description\": \"Expects an error from reverter address on next call, with any revert data.\",\n        \"declaration\": \"function expectRevert(bytes4 revertData, address reverter) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"expectRevert(bytes4,address)\",\n        \"selector\": \"0x260bc5de\",\n        \"selectorBytes\": [\n          38,\n          11,\n          197,\n          222\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"expectRevert_5\",\n        \"description\": \"Expects an error from reverter address on next call, that exactly matches the revert data.\",\n        \"declaration\": \"function expectRevert(bytes calldata revertData, address reverter) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"expectRevert(bytes,address)\",\n        \"selector\": \"0x61ebcf12\",\n        \"selectorBytes\": [\n          97,\n          235,\n          207,\n          18\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"expectRevert_6\",\n        \"description\": \"Expects a `count` number of reverts from the upcoming calls with any revert data or reverter.\",\n        \"declaration\": \"function expectRevert(uint64 count) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"expectRevert(uint64)\",\n        \"selector\": \"0x4ee38244\",\n        \"selectorBytes\": [\n          78,\n          227,\n          130,\n          68\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"expectRevert_7\",\n        \"description\": \"Expects a `count` number of reverts from the upcoming calls that match the revert data.\",\n        \"declaration\": \"function expectRevert(bytes4 revertData, uint64 count) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"expectRevert(bytes4,uint64)\",\n        \"selector\": \"0xe45ca72d\",\n        \"selectorBytes\": [\n          228,\n          92,\n          167,\n          45\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"expectRevert_8\",\n        \"description\": \"Expects a `count` number of reverts from the upcoming calls that exactly match the revert data.\",\n        \"declaration\": \"function expectRevert(bytes calldata revertData, uint64 count) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"expectRevert(bytes,uint64)\",\n        \"selector\": \"0x4994c273\",\n        \"selectorBytes\": [\n          73,\n          148,\n          194,\n          115\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"expectRevert_9\",\n        \"description\": \"Expects a `count` number of reverts from the upcoming calls from the reverter address.\",\n        \"declaration\": \"function expectRevert(address reverter, uint64 count) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"expectRevert(address,uint64)\",\n        \"selector\": \"0x1ff5f952\",\n        \"selectorBytes\": [\n          31,\n          245,\n          249,\n          82\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"expectSafeMemory\",\n        \"description\": \"Only allows memory writes to offsets [0x00, 0x60) ∪ [min, max) in the current subcontext. If any other\\nmemory is written to, the test will fail. Can be called multiple times to add more ranges to the set.\",\n        \"declaration\": \"function expectSafeMemory(uint64 min, uint64 max) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"expectSafeMemory(uint64,uint64)\",\n        \"selector\": \"0x6d016688\",\n        \"selectorBytes\": [\n          109,\n          1,\n          102,\n          136\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"expectSafeMemoryCall\",\n        \"description\": \"Only allows memory writes to offsets [0x00, 0x60) ∪ [min, max) in the next created subcontext.\\nIf any other memory is written to, the test will fail. Can be called multiple times to add more ranges\\nto the set.\",\n        \"declaration\": \"function expectSafeMemoryCall(uint64 min, uint64 max) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"expectSafeMemoryCall(uint64,uint64)\",\n        \"selector\": \"0x05838bf4\",\n        \"selectorBytes\": [\n          5,\n          131,\n          139,\n          244\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"fee\",\n        \"description\": \"Sets `block.basefee`.\",\n        \"declaration\": \"function fee(uint256 newBasefee) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"fee(uint256)\",\n        \"selector\": \"0x39b37ab0\",\n        \"selectorBytes\": [\n          57,\n          179,\n          122,\n          176\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"ffi\",\n        \"description\": \"Performs a foreign function call via the terminal.\",\n        \"declaration\": \"function ffi(string[] calldata commandInput) external returns (bytes memory result);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"ffi(string[])\",\n        \"selector\": \"0x89160467\",\n        \"selectorBytes\": [\n          137,\n          22,\n          4,\n          103\n        ]\n      },\n      \"group\": \"filesystem\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"foundryVersionAtLeast\",\n        \"description\": \"Returns true if the current Foundry version is greater than or equal to the given version.\\nThe given version string must be in the format `major.minor.patch`.\\nThis is equivalent to `foundryVersionCmp(version) >= 0`.\",\n        \"declaration\": \"function foundryVersionAtLeast(string calldata version) external view returns (bool);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"foundryVersionAtLeast(string)\",\n        \"selector\": \"0x6248be1f\",\n        \"selectorBytes\": [\n          98,\n          72,\n          190,\n          31\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"foundryVersionCmp\",\n        \"description\": \"Compares the current Foundry version with the given version string.\\nThe given version string must be in the format `major.minor.patch`.\\nReturns:\\n-1 if current Foundry version is less than the given version\\n0 if current Foundry version equals the given version\\n1 if current Foundry version is greater than the given version\\nThis result can then be used with a comparison operator against `0`.\\nFor example, to check if the current Foundry version is greater than or equal to `1.0.0`:\\n`if (foundryVersionCmp(\\\"1.0.0\\\") >= 0) { ... }`\",\n        \"declaration\": \"function foundryVersionCmp(string calldata version) external view returns (int256);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"foundryVersionCmp(string)\",\n        \"selector\": \"0xca7b0a09\",\n        \"selectorBytes\": [\n          202,\n          123,\n          10,\n          9\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"fromRlp\",\n        \"description\": \"RLP decodes an RLP payload into a list of bytes.\",\n        \"declaration\": \"function fromRlp(bytes calldata rlp) external pure returns (bytes[] memory data);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"fromRlp(bytes)\",\n        \"selector\": \"0x1e1d8b63\",\n        \"selectorBytes\": [\n          30,\n          29,\n          139,\n          99\n        ]\n      },\n      \"group\": \"utilities\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"fsMetadata\",\n        \"description\": \"Given a path, query the file system to get information about a file, directory, etc.\",\n        \"declaration\": \"function fsMetadata(string calldata path) external view returns (FsMetadata memory metadata);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"fsMetadata(string)\",\n        \"selector\": \"0xaf368a08\",\n        \"selectorBytes\": [\n          175,\n          54,\n          138,\n          8\n        ]\n      },\n      \"group\": \"filesystem\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"getArtifactPathByCode\",\n        \"description\": \"Gets the artifact path from code (aka. creation code).\",\n        \"declaration\": \"function getArtifactPathByCode(bytes calldata code) external view returns (string memory path);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"getArtifactPathByCode(bytes)\",\n        \"selector\": \"0xeb74848c\",\n        \"selectorBytes\": [\n          235,\n          116,\n          132,\n          140\n        ]\n      },\n      \"group\": \"filesystem\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"getArtifactPathByDeployedCode\",\n        \"description\": \"Gets the artifact path from deployed code (aka. runtime code).\",\n        \"declaration\": \"function getArtifactPathByDeployedCode(bytes calldata deployedCode) external view returns (string memory path);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"getArtifactPathByDeployedCode(bytes)\",\n        \"selector\": \"0x6d853ba5\",\n        \"selectorBytes\": [\n          109,\n          133,\n          59,\n          165\n        ]\n      },\n      \"group\": \"filesystem\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"getBlobBaseFee\",\n        \"description\": \"Gets the current `block.blobbasefee`.\\nYou should use this instead of `block.blobbasefee` if you use `vm.blobBaseFee`, as `block.blobbasefee` is assumed to be constant across a transaction,\\nand as a result will get optimized out by the compiler.\\nSee https://github.com/foundry-rs/foundry/issues/6180\",\n        \"declaration\": \"function getBlobBaseFee() external view returns (uint256 blobBaseFee);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"getBlobBaseFee()\",\n        \"selector\": \"0x1f6d6ef7\",\n        \"selectorBytes\": [\n          31,\n          109,\n          110,\n          247\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"getBlobhashes\",\n        \"description\": \"Gets the blockhashes from the current transaction.\\nNot available on EVM versions before Cancun.\\nIf used on unsupported EVM versions it will revert.\",\n        \"declaration\": \"function getBlobhashes() external view returns (bytes32[] memory hashes);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"getBlobhashes()\",\n        \"selector\": \"0xf56ff18b\",\n        \"selectorBytes\": [\n          245,\n          111,\n          241,\n          139\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"getBlockNumber\",\n        \"description\": \"Gets the current `block.number`.\\nYou should use this instead of `block.number` if you use `vm.roll`, as `block.number` is assumed to be constant across a transaction,\\nand as a result will get optimized out by the compiler.\\nSee https://github.com/foundry-rs/foundry/issues/6180\",\n        \"declaration\": \"function getBlockNumber() external view returns (uint256 height);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"getBlockNumber()\",\n        \"selector\": \"0x42cbb15c\",\n        \"selectorBytes\": [\n          66,\n          203,\n          177,\n          92\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"getBlockTimestamp\",\n        \"description\": \"Gets the current `block.timestamp`.\\nYou should use this instead of `block.timestamp` if you use `vm.warp`, as `block.timestamp` is assumed to be constant across a transaction,\\nand as a result will get optimized out by the compiler.\\nSee https://github.com/foundry-rs/foundry/issues/6180\",\n        \"declaration\": \"function getBlockTimestamp() external view returns (uint256 timestamp);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"getBlockTimestamp()\",\n        \"selector\": \"0x796b89b9\",\n        \"selectorBytes\": [\n          121,\n          107,\n          137,\n          185\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"getBroadcast\",\n        \"description\": \"Returns the most recent broadcast for the given contract on `chainId` matching `txType`.\\nFor example:\\nThe most recent deployment can be fetched by passing `txType` as `CREATE` or `CREATE2`.\\nThe most recent call can be fetched by passing `txType` as `CALL`.\",\n        \"declaration\": \"function getBroadcast(string calldata contractName, uint64 chainId, BroadcastTxType txType) external view returns (BroadcastTxSummary memory);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"getBroadcast(string,uint64,uint8)\",\n        \"selector\": \"0x3dc90cb3\",\n        \"selectorBytes\": [\n          61,\n          201,\n          12,\n          179\n        ]\n      },\n      \"group\": \"filesystem\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"getBroadcasts_0\",\n        \"description\": \"Returns all broadcasts for the given contract on `chainId` with the specified `txType`.\\nSorted such that the most recent broadcast is the first element, and the oldest is the last. i.e descending order of BroadcastTxSummary.blockNumber.\",\n        \"declaration\": \"function getBroadcasts(string calldata contractName, uint64 chainId, BroadcastTxType txType) external view returns (BroadcastTxSummary[] memory);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"getBroadcasts(string,uint64,uint8)\",\n        \"selector\": \"0xf7afe919\",\n        \"selectorBytes\": [\n          247,\n          175,\n          233,\n          25\n        ]\n      },\n      \"group\": \"filesystem\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"getBroadcasts_1\",\n        \"description\": \"Returns all broadcasts for the given contract on `chainId`.\\nSorted such that the most recent broadcast is the first element, and the oldest is the last. i.e descending order of BroadcastTxSummary.blockNumber.\",\n        \"declaration\": \"function getBroadcasts(string calldata contractName, uint64 chainId) external view returns (BroadcastTxSummary[] memory);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"getBroadcasts(string,uint64)\",\n        \"selector\": \"0xf2fa4a26\",\n        \"selectorBytes\": [\n          242,\n          250,\n          74,\n          38\n        ]\n      },\n      \"group\": \"filesystem\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"getChainId\",\n        \"description\": \"Gets the current `block.chainid` of the currently selected environment.\\nYou should use this instead of `block.chainid` if you use `vm.selectFork` or `vm.createSelectFork`, as `block.chainid` could be assumed\\nto be constant across a transaction, and as a result will get optimized out by the compiler.\\nSee https://github.com/foundry-rs/foundry/issues/6180\",\n        \"declaration\": \"function getChainId() external view returns (uint256 blockChainId);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"getChainId()\",\n        \"selector\": \"0x3408e470\",\n        \"selectorBytes\": [\n          52,\n          8,\n          228,\n          112\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"getChain_0\",\n        \"description\": \"Returns a Chain struct for specific alias\",\n        \"declaration\": \"function getChain(string calldata chainAlias) external view returns (Chain memory chain);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"getChain(string)\",\n        \"selector\": \"0x4cc1c2bb\",\n        \"selectorBytes\": [\n          76,\n          193,\n          194,\n          187\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"getChain_1\",\n        \"description\": \"Returns a Chain struct for specific chainId\",\n        \"declaration\": \"function getChain(uint256 chainId) external view returns (Chain memory chain);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"getChain(uint256)\",\n        \"selector\": \"0xb6791ad4\",\n        \"selectorBytes\": [\n          182,\n          121,\n          26,\n          212\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"getCode\",\n        \"description\": \"Gets the creation bytecode from an artifact file. Takes in the relative path to the json file or the path to the\\nartifact in the form of <path>:<contract>:<version> where <contract> and <version> parts are optional.\",\n        \"declaration\": \"function getCode(string calldata artifactPath) external view returns (bytes memory creationBytecode);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"getCode(string)\",\n        \"selector\": \"0x8d1cc925\",\n        \"selectorBytes\": [\n          141,\n          28,\n          201,\n          37\n        ]\n      },\n      \"group\": \"filesystem\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"getDeployedCode\",\n        \"description\": \"Gets the deployed bytecode from an artifact file. Takes in the relative path to the json file or the path to the\\nartifact in the form of <path>:<contract>:<version> where <contract> and <version> parts are optional.\",\n        \"declaration\": \"function getDeployedCode(string calldata artifactPath) external view returns (bytes memory runtimeBytecode);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"getDeployedCode(string)\",\n        \"selector\": \"0x3ebf73b4\",\n        \"selectorBytes\": [\n          62,\n          191,\n          115,\n          180\n        ]\n      },\n      \"group\": \"filesystem\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"getDeployment_0\",\n        \"description\": \"Returns the most recent deployment for the current `chainId`.\",\n        \"declaration\": \"function getDeployment(string calldata contractName) external view returns (address deployedAddress);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"getDeployment(string)\",\n        \"selector\": \"0xa8091d97\",\n        \"selectorBytes\": [\n          168,\n          9,\n          29,\n          151\n        ]\n      },\n      \"group\": \"filesystem\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"getDeployment_1\",\n        \"description\": \"Returns the most recent deployment for the given contract on `chainId`\",\n        \"declaration\": \"function getDeployment(string calldata contractName, uint64 chainId) external view returns (address deployedAddress);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"getDeployment(string,uint64)\",\n        \"selector\": \"0x0debd5d6\",\n        \"selectorBytes\": [\n          13,\n          235,\n          213,\n          214\n        ]\n      },\n      \"group\": \"filesystem\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"getDeployments\",\n        \"description\": \"Returns all deployments for the given contract on `chainId`\\nSorted in descending order of deployment time i.e descending order of BroadcastTxSummary.blockNumber.\\nThe most recent deployment is the first element, and the oldest is the last.\",\n        \"declaration\": \"function getDeployments(string calldata contractName, uint64 chainId) external view returns (address[] memory deployedAddresses);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"getDeployments(string,uint64)\",\n        \"selector\": \"0x74e133dd\",\n        \"selectorBytes\": [\n          116,\n          225,\n          51,\n          221\n        ]\n      },\n      \"group\": \"filesystem\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"getEvmVersion\",\n        \"description\": \"Returns the test or script execution evm version.\\n**Note:** The execution evm version is not the same as the compilation one.\",\n        \"declaration\": \"function getEvmVersion() external pure returns (string memory evm);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"getEvmVersion()\",\n        \"selector\": \"0xaa2bb222\",\n        \"selectorBytes\": [\n          170,\n          43,\n          178,\n          34\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"getFoundryVersion\",\n        \"description\": \"Returns the Foundry version.\\nFormat: <cargo_version>-<tag>+<git_sha_short>.<unix_build_timestamp>.<profile>\\nSample output: 0.3.0-nightly+3cb96bde9b.1737036656.debug\\nNote: Build timestamps may vary slightly across platforms due to separate CI jobs.\\nFor reliable version comparisons, use UNIX format (e.g., >= 1700000000)\\nto compare timestamps while ignoring minor time differences.\",\n        \"declaration\": \"function getFoundryVersion() external view returns (string memory version);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"getFoundryVersion()\",\n        \"selector\": \"0xea991bb5\",\n        \"selectorBytes\": [\n          234,\n          153,\n          27,\n          181\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"getLabel\",\n        \"description\": \"Gets the label for the specified address.\",\n        \"declaration\": \"function getLabel(address account) external view returns (string memory currentLabel);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"getLabel(address)\",\n        \"selector\": \"0x28a249b0\",\n        \"selectorBytes\": [\n          40,\n          162,\n          73,\n          176\n        ]\n      },\n      \"group\": \"utilities\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"getMappingKeyAndParentOf\",\n        \"description\": \"Gets the map key and parent of a mapping at a given slot, for a given address.\",\n        \"declaration\": \"function getMappingKeyAndParentOf(address target, bytes32 elementSlot) external view returns (bool found, bytes32 key, bytes32 parent);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"getMappingKeyAndParentOf(address,bytes32)\",\n        \"selector\": \"0x876e24e6\",\n        \"selectorBytes\": [\n          135,\n          110,\n          36,\n          230\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"getMappingLength\",\n        \"description\": \"Gets the number of elements in the mapping at the given slot, for a given address.\",\n        \"declaration\": \"function getMappingLength(address target, bytes32 mappingSlot) external view returns (uint256 length);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"getMappingLength(address,bytes32)\",\n        \"selector\": \"0x2f2fd63f\",\n        \"selectorBytes\": [\n          47,\n          47,\n          214,\n          63\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"getMappingSlotAt\",\n        \"description\": \"Gets the elements at index idx of the mapping at the given slot, for a given address. The\\nindex must be less than the length of the mapping (i.e. the number of keys in the mapping).\",\n        \"declaration\": \"function getMappingSlotAt(address target, bytes32 mappingSlot, uint256 idx) external view returns (bytes32 value);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"getMappingSlotAt(address,bytes32,uint256)\",\n        \"selector\": \"0xebc73ab4\",\n        \"selectorBytes\": [\n          235,\n          199,\n          58,\n          180\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"getNonce_0\",\n        \"description\": \"Gets the nonce of an account.\",\n        \"declaration\": \"function getNonce(address account) external view returns (uint64 nonce);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"getNonce(address)\",\n        \"selector\": \"0x2d0335ab\",\n        \"selectorBytes\": [\n          45,\n          3,\n          53,\n          171\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"getNonce_1\",\n        \"description\": \"Get the nonce of a `Wallet`.\",\n        \"declaration\": \"function getNonce(Wallet calldata wallet) external view returns (uint64 nonce);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"getNonce((address,uint256,uint256,uint256))\",\n        \"selector\": \"0xa5748aad\",\n        \"selectorBytes\": [\n          165,\n          116,\n          138,\n          173\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"getRawBlockHeader\",\n        \"description\": \"Gets the RLP encoded block header for a given block number.\\nReturns the block header in the same format as `cast block <block_number> --raw`.\",\n        \"declaration\": \"function getRawBlockHeader(uint256 blockNumber) external view returns (bytes memory rlpHeader);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"getRawBlockHeader(uint256)\",\n        \"selector\": \"0x2c667606\",\n        \"selectorBytes\": [\n          44,\n          102,\n          118,\n          6\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"getRecordedLogs\",\n        \"description\": \"Gets all the recorded logs.\",\n        \"declaration\": \"function getRecordedLogs() external view returns (Log[] memory logs);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"getRecordedLogs()\",\n        \"selector\": \"0x191553a4\",\n        \"selectorBytes\": [\n          25,\n          21,\n          83,\n          164\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"getRecordedLogsJson\",\n        \"description\": \"Gets all the recorded logs, in JSON format.\",\n        \"declaration\": \"function getRecordedLogsJson() external view returns (string memory logsJson);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"getRecordedLogsJson()\",\n        \"selector\": \"0x3b171111\",\n        \"selectorBytes\": [\n          59,\n          23,\n          17,\n          17\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"getStateDiff\",\n        \"description\": \"Returns state diffs from current `vm.startStateDiffRecording` session.\",\n        \"declaration\": \"function getStateDiff() external view returns (string memory diff);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"getStateDiff()\",\n        \"selector\": \"0x80df01cc\",\n        \"selectorBytes\": [\n          128,\n          223,\n          1,\n          204\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"getStateDiffJson\",\n        \"description\": \"Returns state diffs from current `vm.startStateDiffRecording` session, in json format.\",\n        \"declaration\": \"function getStateDiffJson() external view returns (string memory diff);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"getStateDiffJson()\",\n        \"selector\": \"0xf54fe009\",\n        \"selectorBytes\": [\n          245,\n          79,\n          224,\n          9\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"getStorageAccesses\",\n        \"description\": \"Returns an array of `StorageAccess` from current `vm.stateStateDiffRecording` session\",\n        \"declaration\": \"function getStorageAccesses() external view returns (StorageAccess[] memory storageAccesses);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"getStorageAccesses()\",\n        \"selector\": \"0x2899b1d0\",\n        \"selectorBytes\": [\n          40,\n          153,\n          177,\n          208\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"getStorageSlots\",\n        \"description\": \"Returns an array of storage slots occupied by the specified variable.\",\n        \"declaration\": \"function getStorageSlots(address target, string calldata variableName) external view returns (uint256[] memory slots);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"getStorageSlots(address,string)\",\n        \"selector\": \"0xefa136d9\",\n        \"selectorBytes\": [\n          239,\n          161,\n          54,\n          217\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"getWallets\",\n        \"description\": \"Returns addresses of available unlocked wallets in the script environment.\",\n        \"declaration\": \"function getWallets() external view returns (address[] memory wallets);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"getWallets()\",\n        \"selector\": \"0xdb7a4605\",\n        \"selectorBytes\": [\n          219,\n          122,\n          70,\n          5\n        ]\n      },\n      \"group\": \"scripting\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"indexOf\",\n        \"description\": \"Returns the index of the first occurrence of a `key` in an `input` string.\\nReturns `NOT_FOUND` (i.e. `type(uint256).max`) if the `key` is not found.\\nReturns 0 in case of an empty `key`.\",\n        \"declaration\": \"function indexOf(string calldata input, string calldata key) external pure returns (uint256);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"indexOf(string,string)\",\n        \"selector\": \"0x8a0807b7\",\n        \"selectorBytes\": [\n          138,\n          8,\n          7,\n          183\n        ]\n      },\n      \"group\": \"string\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"interceptInitcode\",\n        \"description\": \"Causes the next contract creation (via new) to fail and return its initcode in the returndata buffer.\\nThis allows type-safe access to the initcode payload that would be used for contract creation.\\nExample usage:\\nvm.interceptInitcode();\\nbytes memory initcode;\\ntry new MyContract(param1, param2) { assert(false); }\\ncatch (bytes memory interceptedInitcode) { initcode = interceptedInitcode; }\",\n        \"declaration\": \"function interceptInitcode() external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"interceptInitcode()\",\n        \"selector\": \"0x838653c7\",\n        \"selectorBytes\": [\n          131,\n          134,\n          83,\n          199\n        ]\n      },\n      \"group\": \"utilities\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"isContext\",\n        \"description\": \"Returns true if `forge` command was executed in given context.\",\n        \"declaration\": \"function isContext(ForgeContext context) external view returns (bool result);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"isContext(uint8)\",\n        \"selector\": \"0x64af255d\",\n        \"selectorBytes\": [\n          100,\n          175,\n          37,\n          93\n        ]\n      },\n      \"group\": \"environment\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"isDir\",\n        \"description\": \"Returns true if the path exists on disk and is pointing at a directory, else returns false.\",\n        \"declaration\": \"function isDir(string calldata path) external view returns (bool result);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"isDir(string)\",\n        \"selector\": \"0x7d15d019\",\n        \"selectorBytes\": [\n          125,\n          21,\n          208,\n          25\n        ]\n      },\n      \"group\": \"filesystem\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"isFile\",\n        \"description\": \"Returns true if the path exists on disk and is pointing at a regular file, else returns false.\",\n        \"declaration\": \"function isFile(string calldata path) external view returns (bool result);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"isFile(string)\",\n        \"selector\": \"0xe0eb04d4\",\n        \"selectorBytes\": [\n          224,\n          235,\n          4,\n          212\n        ]\n      },\n      \"group\": \"filesystem\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"isPersistent\",\n        \"description\": \"Returns true if the account is marked as persistent.\",\n        \"declaration\": \"function isPersistent(address account) external view returns (bool persistent);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"isPersistent(address)\",\n        \"selector\": \"0xd92d8efd\",\n        \"selectorBytes\": [\n          217,\n          45,\n          142,\n          253\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"keyExists\",\n        \"description\": \"Checks if `key` exists in a JSON object\\n`keyExists` is being deprecated in favor of `keyExistsJson`. It will be removed in future versions.\",\n        \"declaration\": \"function keyExists(string calldata json, string calldata key) external view returns (bool);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"keyExists(string,string)\",\n        \"selector\": \"0x528a683c\",\n        \"selectorBytes\": [\n          82,\n          138,\n          104,\n          60\n        ]\n      },\n      \"group\": \"json\",\n      \"status\": {\n        \"deprecated\": \"replaced by `keyExistsJson`\"\n      },\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"keyExistsJson\",\n        \"description\": \"Checks if `key` exists in a JSON object.\",\n        \"declaration\": \"function keyExistsJson(string calldata json, string calldata key) external view returns (bool);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"keyExistsJson(string,string)\",\n        \"selector\": \"0xdb4235f6\",\n        \"selectorBytes\": [\n          219,\n          66,\n          53,\n          246\n        ]\n      },\n      \"group\": \"json\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"keyExistsToml\",\n        \"description\": \"Checks if `key` exists in a TOML table.\",\n        \"declaration\": \"function keyExistsToml(string calldata toml, string calldata key) external view returns (bool);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"keyExistsToml(string,string)\",\n        \"selector\": \"0x600903ad\",\n        \"selectorBytes\": [\n          96,\n          9,\n          3,\n          173\n        ]\n      },\n      \"group\": \"toml\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"label\",\n        \"description\": \"Labels an address in call traces.\",\n        \"declaration\": \"function label(address account, string calldata newLabel) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"label(address,string)\",\n        \"selector\": \"0xc657c718\",\n        \"selectorBytes\": [\n          198,\n          87,\n          199,\n          24\n        ]\n      },\n      \"group\": \"utilities\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"lastCallGas\",\n        \"description\": \"Gets the gas used in the last call from the callee perspective.\",\n        \"declaration\": \"function lastCallGas() external view returns (Gas memory gas);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"lastCallGas()\",\n        \"selector\": \"0x2b589b28\",\n        \"selectorBytes\": [\n          43,\n          88,\n          155,\n          40\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"load\",\n        \"description\": \"Loads a storage slot from an address.\",\n        \"declaration\": \"function load(address target, bytes32 slot) external view returns (bytes32 data);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"load(address,bytes32)\",\n        \"selector\": \"0x667f9d70\",\n        \"selectorBytes\": [\n          102,\n          127,\n          157,\n          112\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"loadAllocs\",\n        \"description\": \"Load a genesis JSON file's `allocs` into the in-memory EVM state.\",\n        \"declaration\": \"function loadAllocs(string calldata pathToAllocsJson) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"loadAllocs(string)\",\n        \"selector\": \"0xb3a056d7\",\n        \"selectorBytes\": [\n          179,\n          160,\n          86,\n          215\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"makePersistent_0\",\n        \"description\": \"Marks that the account(s) should use persistent storage across fork swaps in a multifork setup\\nMeaning, changes made to the state of this account will be kept when switching forks.\",\n        \"declaration\": \"function makePersistent(address account) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"makePersistent(address)\",\n        \"selector\": \"0x57e22dde\",\n        \"selectorBytes\": [\n          87,\n          226,\n          45,\n          222\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"makePersistent_1\",\n        \"description\": \"See `makePersistent(address)`.\",\n        \"declaration\": \"function makePersistent(address account0, address account1) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"makePersistent(address,address)\",\n        \"selector\": \"0x4074e0a8\",\n        \"selectorBytes\": [\n          64,\n          116,\n          224,\n          168\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"makePersistent_2\",\n        \"description\": \"See `makePersistent(address)`.\",\n        \"declaration\": \"function makePersistent(address account0, address account1, address account2) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"makePersistent(address,address,address)\",\n        \"selector\": \"0xefb77a75\",\n        \"selectorBytes\": [\n          239,\n          183,\n          122,\n          117\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"makePersistent_3\",\n        \"description\": \"See `makePersistent(address)`.\",\n        \"declaration\": \"function makePersistent(address[] calldata accounts) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"makePersistent(address[])\",\n        \"selector\": \"0x1d9e269e\",\n        \"selectorBytes\": [\n          29,\n          158,\n          38,\n          158\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"mockCallRevert_0\",\n        \"description\": \"Reverts a call to an address with specified revert data.\",\n        \"declaration\": \"function mockCallRevert(address callee, bytes calldata data, bytes calldata revertData) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"mockCallRevert(address,bytes,bytes)\",\n        \"selector\": \"0xdbaad147\",\n        \"selectorBytes\": [\n          219,\n          170,\n          209,\n          71\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"mockCallRevert_1\",\n        \"description\": \"Reverts a call to an address with a specific `msg.value`, with specified revert data.\",\n        \"declaration\": \"function mockCallRevert(address callee, uint256 msgValue, bytes calldata data, bytes calldata revertData) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"mockCallRevert(address,uint256,bytes,bytes)\",\n        \"selector\": \"0xd23cd037\",\n        \"selectorBytes\": [\n          210,\n          60,\n          208,\n          55\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"mockCallRevert_2\",\n        \"description\": \"Reverts a call to an address with specified revert data.\\nOverload to pass the function selector directly `token.approve.selector` instead of `abi.encodeWithSelector(token.approve.selector)`.\",\n        \"declaration\": \"function mockCallRevert(address callee, bytes4 data, bytes calldata revertData) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"mockCallRevert(address,bytes4,bytes)\",\n        \"selector\": \"0x2dfba5df\",\n        \"selectorBytes\": [\n          45,\n          251,\n          165,\n          223\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"mockCallRevert_3\",\n        \"description\": \"Reverts a call to an address with a specific `msg.value`, with specified revert data.\\nOverload to pass the function selector directly `token.approve.selector` instead of `abi.encodeWithSelector(token.approve.selector)`.\",\n        \"declaration\": \"function mockCallRevert(address callee, uint256 msgValue, bytes4 data, bytes calldata revertData) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"mockCallRevert(address,uint256,bytes4,bytes)\",\n        \"selector\": \"0x596c8f04\",\n        \"selectorBytes\": [\n          89,\n          108,\n          143,\n          4\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"mockCall_0\",\n        \"description\": \"Mocks a call to an address, returning specified data.\\nCalldata can either be strict or a partial match, e.g. if you only\\npass a Solidity selector to the expected calldata, then the entire Solidity\\nfunction will be mocked.\",\n        \"declaration\": \"function mockCall(address callee, bytes calldata data, bytes calldata returnData) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"mockCall(address,bytes,bytes)\",\n        \"selector\": \"0xb96213e4\",\n        \"selectorBytes\": [\n          185,\n          98,\n          19,\n          228\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"mockCall_1\",\n        \"description\": \"Mocks a call to an address with a specific `msg.value`, returning specified data.\\nCalldata match takes precedence over `msg.value` in case of ambiguity.\",\n        \"declaration\": \"function mockCall(address callee, uint256 msgValue, bytes calldata data, bytes calldata returnData) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"mockCall(address,uint256,bytes,bytes)\",\n        \"selector\": \"0x81409b91\",\n        \"selectorBytes\": [\n          129,\n          64,\n          155,\n          145\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"mockCall_2\",\n        \"description\": \"Mocks a call to an address, returning specified data.\\nCalldata can either be strict or a partial match, e.g. if you only\\npass a Solidity selector to the expected calldata, then the entire Solidity\\nfunction will be mocked.\\nOverload to pass the function selector directly `token.approve.selector` instead of `abi.encodeWithSelector(token.approve.selector)`.\",\n        \"declaration\": \"function mockCall(address callee, bytes4 data, bytes calldata returnData) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"mockCall(address,bytes4,bytes)\",\n        \"selector\": \"0x08e0c537\",\n        \"selectorBytes\": [\n          8,\n          224,\n          197,\n          55\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"mockCall_3\",\n        \"description\": \"Mocks a call to an address with a specific `msg.value`, returning specified data.\\nCalldata match takes precedence over `msg.value` in case of ambiguity.\\nOverload to pass the function selector directly `token.approve.selector` instead of `abi.encodeWithSelector(token.approve.selector)`.\",\n        \"declaration\": \"function mockCall(address callee, uint256 msgValue, bytes4 data, bytes calldata returnData) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"mockCall(address,uint256,bytes4,bytes)\",\n        \"selector\": \"0xe7b36a3d\",\n        \"selectorBytes\": [\n          231,\n          179,\n          106,\n          61\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"mockCalls_0\",\n        \"description\": \"Mocks multiple calls to an address, returning specified data for each call.\",\n        \"declaration\": \"function mockCalls(address callee, bytes calldata data, bytes[] calldata returnData) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"mockCalls(address,bytes,bytes[])\",\n        \"selector\": \"0x5c5c3de9\",\n        \"selectorBytes\": [\n          92,\n          92,\n          61,\n          233\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"mockCalls_1\",\n        \"description\": \"Mocks multiple calls to an address with a specific `msg.value`, returning specified data for each call.\",\n        \"declaration\": \"function mockCalls(address callee, uint256 msgValue, bytes calldata data, bytes[] calldata returnData) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"mockCalls(address,uint256,bytes,bytes[])\",\n        \"selector\": \"0x08bcbae1\",\n        \"selectorBytes\": [\n          8,\n          188,\n          186,\n          225\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"mockFunction\",\n        \"description\": \"Whenever a call is made to `callee` with calldata `data`, this cheatcode instead calls\\n`target` with the same calldata. This functionality is similar to a delegate call made to\\n`target` contract from `callee`.\\nCan be used to substitute a call to a function with another implementation that captures\\nthe primary logic of the original function but is easier to reason about.\\nIf calldata is not a strict match then partial match by selector is attempted.\",\n        \"declaration\": \"function mockFunction(address callee, address target, bytes calldata data) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"mockFunction(address,address,bytes)\",\n        \"selector\": \"0xadf84d21\",\n        \"selectorBytes\": [\n          173,\n          248,\n          77,\n          33\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"noAccessList\",\n        \"description\": \"Utility cheatcode to remove any EIP-2930 access list set by `accessList` cheatcode.\",\n        \"declaration\": \"function noAccessList() external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"noAccessList()\",\n        \"selector\": \"0x238ad778\",\n        \"selectorBytes\": [\n          35,\n          138,\n          215,\n          120\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"parseAddress\",\n        \"description\": \"Parses the given `string` into an `address`.\",\n        \"declaration\": \"function parseAddress(string calldata stringifiedValue) external pure returns (address parsedValue);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"parseAddress(string)\",\n        \"selector\": \"0xc6ce059d\",\n        \"selectorBytes\": [\n          198,\n          206,\n          5,\n          157\n        ]\n      },\n      \"group\": \"string\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"parseBool\",\n        \"description\": \"Parses the given `string` into a `bool`.\",\n        \"declaration\": \"function parseBool(string calldata stringifiedValue) external pure returns (bool parsedValue);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"parseBool(string)\",\n        \"selector\": \"0x974ef924\",\n        \"selectorBytes\": [\n          151,\n          78,\n          249,\n          36\n        ]\n      },\n      \"group\": \"string\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"parseBytes\",\n        \"description\": \"Parses the given `string` into `bytes`.\",\n        \"declaration\": \"function parseBytes(string calldata stringifiedValue) external pure returns (bytes memory parsedValue);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"parseBytes(string)\",\n        \"selector\": \"0x8f5d232d\",\n        \"selectorBytes\": [\n          143,\n          93,\n          35,\n          45\n        ]\n      },\n      \"group\": \"string\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"parseBytes32\",\n        \"description\": \"Parses the given `string` into a `bytes32`.\",\n        \"declaration\": \"function parseBytes32(string calldata stringifiedValue) external pure returns (bytes32 parsedValue);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"parseBytes32(string)\",\n        \"selector\": \"0x087e6e81\",\n        \"selectorBytes\": [\n          8,\n          126,\n          110,\n          129\n        ]\n      },\n      \"group\": \"string\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"parseInt\",\n        \"description\": \"Parses the given `string` into a `int256`.\",\n        \"declaration\": \"function parseInt(string calldata stringifiedValue) external pure returns (int256 parsedValue);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"parseInt(string)\",\n        \"selector\": \"0x42346c5e\",\n        \"selectorBytes\": [\n          66,\n          52,\n          108,\n          94\n        ]\n      },\n      \"group\": \"string\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"parseJsonAddress\",\n        \"description\": \"Parses a string of JSON data at `key` and coerces it to `address`.\",\n        \"declaration\": \"function parseJsonAddress(string calldata json, string calldata key) external pure returns (address);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"parseJsonAddress(string,string)\",\n        \"selector\": \"0x1e19e657\",\n        \"selectorBytes\": [\n          30,\n          25,\n          230,\n          87\n        ]\n      },\n      \"group\": \"json\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"parseJsonAddressArray\",\n        \"description\": \"Parses a string of JSON data at `key` and coerces it to `address[]`.\",\n        \"declaration\": \"function parseJsonAddressArray(string calldata json, string calldata key) external pure returns (address[] memory);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"parseJsonAddressArray(string,string)\",\n        \"selector\": \"0x2fce7883\",\n        \"selectorBytes\": [\n          47,\n          206,\n          120,\n          131\n        ]\n      },\n      \"group\": \"json\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"parseJsonBool\",\n        \"description\": \"Parses a string of JSON data at `key` and coerces it to `bool`.\",\n        \"declaration\": \"function parseJsonBool(string calldata json, string calldata key) external pure returns (bool);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"parseJsonBool(string,string)\",\n        \"selector\": \"0x9f86dc91\",\n        \"selectorBytes\": [\n          159,\n          134,\n          220,\n          145\n        ]\n      },\n      \"group\": \"json\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"parseJsonBoolArray\",\n        \"description\": \"Parses a string of JSON data at `key` and coerces it to `bool[]`.\",\n        \"declaration\": \"function parseJsonBoolArray(string calldata json, string calldata key) external pure returns (bool[] memory);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"parseJsonBoolArray(string,string)\",\n        \"selector\": \"0x91f3b94f\",\n        \"selectorBytes\": [\n          145,\n          243,\n          185,\n          79\n        ]\n      },\n      \"group\": \"json\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"parseJsonBytes\",\n        \"description\": \"Parses a string of JSON data at `key` and coerces it to `bytes`.\",\n        \"declaration\": \"function parseJsonBytes(string calldata json, string calldata key) external pure returns (bytes memory);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"parseJsonBytes(string,string)\",\n        \"selector\": \"0xfd921be8\",\n        \"selectorBytes\": [\n          253,\n          146,\n          27,\n          232\n        ]\n      },\n      \"group\": \"json\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"parseJsonBytes32\",\n        \"description\": \"Parses a string of JSON data at `key` and coerces it to `bytes32`.\",\n        \"declaration\": \"function parseJsonBytes32(string calldata json, string calldata key) external pure returns (bytes32);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"parseJsonBytes32(string,string)\",\n        \"selector\": \"0x1777e59d\",\n        \"selectorBytes\": [\n          23,\n          119,\n          229,\n          157\n        ]\n      },\n      \"group\": \"json\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"parseJsonBytes32Array\",\n        \"description\": \"Parses a string of JSON data at `key` and coerces it to `bytes32[]`.\",\n        \"declaration\": \"function parseJsonBytes32Array(string calldata json, string calldata key) external pure returns (bytes32[] memory);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"parseJsonBytes32Array(string,string)\",\n        \"selector\": \"0x91c75bc3\",\n        \"selectorBytes\": [\n          145,\n          199,\n          91,\n          195\n        ]\n      },\n      \"group\": \"json\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"parseJsonBytesArray\",\n        \"description\": \"Parses a string of JSON data at `key` and coerces it to `bytes[]`.\",\n        \"declaration\": \"function parseJsonBytesArray(string calldata json, string calldata key) external pure returns (bytes[] memory);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"parseJsonBytesArray(string,string)\",\n        \"selector\": \"0x6631aa99\",\n        \"selectorBytes\": [\n          102,\n          49,\n          170,\n          153\n        ]\n      },\n      \"group\": \"json\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"parseJsonInt\",\n        \"description\": \"Parses a string of JSON data at `key` and coerces it to `int256`.\",\n        \"declaration\": \"function parseJsonInt(string calldata json, string calldata key) external pure returns (int256);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"parseJsonInt(string,string)\",\n        \"selector\": \"0x7b048ccd\",\n        \"selectorBytes\": [\n          123,\n          4,\n          140,\n          205\n        ]\n      },\n      \"group\": \"json\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"parseJsonIntArray\",\n        \"description\": \"Parses a string of JSON data at `key` and coerces it to `int256[]`.\",\n        \"declaration\": \"function parseJsonIntArray(string calldata json, string calldata key) external pure returns (int256[] memory);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"parseJsonIntArray(string,string)\",\n        \"selector\": \"0x9983c28a\",\n        \"selectorBytes\": [\n          153,\n          131,\n          194,\n          138\n        ]\n      },\n      \"group\": \"json\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"parseJsonKeys\",\n        \"description\": \"Returns an array of all the keys in a JSON object.\",\n        \"declaration\": \"function parseJsonKeys(string calldata json, string calldata key) external pure returns (string[] memory keys);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"parseJsonKeys(string,string)\",\n        \"selector\": \"0x213e4198\",\n        \"selectorBytes\": [\n          33,\n          62,\n          65,\n          152\n        ]\n      },\n      \"group\": \"json\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"parseJsonString\",\n        \"description\": \"Parses a string of JSON data at `key` and coerces it to `string`.\",\n        \"declaration\": \"function parseJsonString(string calldata json, string calldata key) external pure returns (string memory);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"parseJsonString(string,string)\",\n        \"selector\": \"0x49c4fac8\",\n        \"selectorBytes\": [\n          73,\n          196,\n          250,\n          200\n        ]\n      },\n      \"group\": \"json\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"parseJsonStringArray\",\n        \"description\": \"Parses a string of JSON data at `key` and coerces it to `string[]`.\",\n        \"declaration\": \"function parseJsonStringArray(string calldata json, string calldata key) external pure returns (string[] memory);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"parseJsonStringArray(string,string)\",\n        \"selector\": \"0x498fdcf4\",\n        \"selectorBytes\": [\n          73,\n          143,\n          220,\n          244\n        ]\n      },\n      \"group\": \"json\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"parseJsonTypeArray\",\n        \"description\": \"Parses a string of JSON data at `key` and coerces it to type array corresponding to `typeDescription`.\",\n        \"declaration\": \"function parseJsonTypeArray(string calldata json, string calldata key, string calldata typeDescription) external pure returns (bytes memory);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"parseJsonTypeArray(string,string,string)\",\n        \"selector\": \"0x0175d535\",\n        \"selectorBytes\": [\n          1,\n          117,\n          213,\n          53\n        ]\n      },\n      \"group\": \"json\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"parseJsonType_0\",\n        \"description\": \"Parses a string of JSON data and coerces it to type corresponding to `typeDescription`.\",\n        \"declaration\": \"function parseJsonType(string calldata json, string calldata typeDescription) external pure returns (bytes memory);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"parseJsonType(string,string)\",\n        \"selector\": \"0xa9da313b\",\n        \"selectorBytes\": [\n          169,\n          218,\n          49,\n          59\n        ]\n      },\n      \"group\": \"json\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"parseJsonType_1\",\n        \"description\": \"Parses a string of JSON data at `key` and coerces it to type corresponding to `typeDescription`.\",\n        \"declaration\": \"function parseJsonType(string calldata json, string calldata key, string calldata typeDescription) external pure returns (bytes memory);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"parseJsonType(string,string,string)\",\n        \"selector\": \"0xe3f5ae33\",\n        \"selectorBytes\": [\n          227,\n          245,\n          174,\n          51\n        ]\n      },\n      \"group\": \"json\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"parseJsonUint\",\n        \"description\": \"Parses a string of JSON data at `key` and coerces it to `uint256`.\",\n        \"declaration\": \"function parseJsonUint(string calldata json, string calldata key) external pure returns (uint256);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"parseJsonUint(string,string)\",\n        \"selector\": \"0xaddde2b6\",\n        \"selectorBytes\": [\n          173,\n          221,\n          226,\n          182\n        ]\n      },\n      \"group\": \"json\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"parseJsonUintArray\",\n        \"description\": \"Parses a string of JSON data at `key` and coerces it to `uint256[]`.\",\n        \"declaration\": \"function parseJsonUintArray(string calldata json, string calldata key) external pure returns (uint256[] memory);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"parseJsonUintArray(string,string)\",\n        \"selector\": \"0x522074ab\",\n        \"selectorBytes\": [\n          82,\n          32,\n          116,\n          171\n        ]\n      },\n      \"group\": \"json\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"parseJson_0\",\n        \"description\": \"ABI-encodes a JSON object.\",\n        \"declaration\": \"function parseJson(string calldata json) external pure returns (bytes memory abiEncodedData);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"parseJson(string)\",\n        \"selector\": \"0x6a82600a\",\n        \"selectorBytes\": [\n          106,\n          130,\n          96,\n          10\n        ]\n      },\n      \"group\": \"json\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"parseJson_1\",\n        \"description\": \"ABI-encodes a JSON object at `key`.\",\n        \"declaration\": \"function parseJson(string calldata json, string calldata key) external pure returns (bytes memory abiEncodedData);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"parseJson(string,string)\",\n        \"selector\": \"0x85940ef1\",\n        \"selectorBytes\": [\n          133,\n          148,\n          14,\n          241\n        ]\n      },\n      \"group\": \"json\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"parseTomlAddress\",\n        \"description\": \"Parses a string of TOML data at `key` and coerces it to `address`.\",\n        \"declaration\": \"function parseTomlAddress(string calldata toml, string calldata key) external pure returns (address);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"parseTomlAddress(string,string)\",\n        \"selector\": \"0x65e7c844\",\n        \"selectorBytes\": [\n          101,\n          231,\n          200,\n          68\n        ]\n      },\n      \"group\": \"toml\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"parseTomlAddressArray\",\n        \"description\": \"Parses a string of TOML data at `key` and coerces it to `address[]`.\",\n        \"declaration\": \"function parseTomlAddressArray(string calldata toml, string calldata key) external pure returns (address[] memory);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"parseTomlAddressArray(string,string)\",\n        \"selector\": \"0x65c428e7\",\n        \"selectorBytes\": [\n          101,\n          196,\n          40,\n          231\n        ]\n      },\n      \"group\": \"toml\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"parseTomlBool\",\n        \"description\": \"Parses a string of TOML data at `key` and coerces it to `bool`.\",\n        \"declaration\": \"function parseTomlBool(string calldata toml, string calldata key) external pure returns (bool);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"parseTomlBool(string,string)\",\n        \"selector\": \"0xd30dced6\",\n        \"selectorBytes\": [\n          211,\n          13,\n          206,\n          214\n        ]\n      },\n      \"group\": \"toml\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"parseTomlBoolArray\",\n        \"description\": \"Parses a string of TOML data at `key` and coerces it to `bool[]`.\",\n        \"declaration\": \"function parseTomlBoolArray(string calldata toml, string calldata key) external pure returns (bool[] memory);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"parseTomlBoolArray(string,string)\",\n        \"selector\": \"0x127cfe9a\",\n        \"selectorBytes\": [\n          18,\n          124,\n          254,\n          154\n        ]\n      },\n      \"group\": \"toml\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"parseTomlBytes\",\n        \"description\": \"Parses a string of TOML data at `key` and coerces it to `bytes`.\",\n        \"declaration\": \"function parseTomlBytes(string calldata toml, string calldata key) external pure returns (bytes memory);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"parseTomlBytes(string,string)\",\n        \"selector\": \"0xd77bfdb9\",\n        \"selectorBytes\": [\n          215,\n          123,\n          253,\n          185\n        ]\n      },\n      \"group\": \"toml\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"parseTomlBytes32\",\n        \"description\": \"Parses a string of TOML data at `key` and coerces it to `bytes32`.\",\n        \"declaration\": \"function parseTomlBytes32(string calldata toml, string calldata key) external pure returns (bytes32);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"parseTomlBytes32(string,string)\",\n        \"selector\": \"0x8e214810\",\n        \"selectorBytes\": [\n          142,\n          33,\n          72,\n          16\n        ]\n      },\n      \"group\": \"toml\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"parseTomlBytes32Array\",\n        \"description\": \"Parses a string of TOML data at `key` and coerces it to `bytes32[]`.\",\n        \"declaration\": \"function parseTomlBytes32Array(string calldata toml, string calldata key) external pure returns (bytes32[] memory);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"parseTomlBytes32Array(string,string)\",\n        \"selector\": \"0x3e716f81\",\n        \"selectorBytes\": [\n          62,\n          113,\n          111,\n          129\n        ]\n      },\n      \"group\": \"toml\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"parseTomlBytesArray\",\n        \"description\": \"Parses a string of TOML data at `key` and coerces it to `bytes[]`.\",\n        \"declaration\": \"function parseTomlBytesArray(string calldata toml, string calldata key) external pure returns (bytes[] memory);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"parseTomlBytesArray(string,string)\",\n        \"selector\": \"0xb197c247\",\n        \"selectorBytes\": [\n          177,\n          151,\n          194,\n          71\n        ]\n      },\n      \"group\": \"toml\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"parseTomlInt\",\n        \"description\": \"Parses a string of TOML data at `key` and coerces it to `int256`.\",\n        \"declaration\": \"function parseTomlInt(string calldata toml, string calldata key) external pure returns (int256);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"parseTomlInt(string,string)\",\n        \"selector\": \"0xc1350739\",\n        \"selectorBytes\": [\n          193,\n          53,\n          7,\n          57\n        ]\n      },\n      \"group\": \"toml\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"parseTomlIntArray\",\n        \"description\": \"Parses a string of TOML data at `key` and coerces it to `int256[]`.\",\n        \"declaration\": \"function parseTomlIntArray(string calldata toml, string calldata key) external pure returns (int256[] memory);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"parseTomlIntArray(string,string)\",\n        \"selector\": \"0xd3522ae6\",\n        \"selectorBytes\": [\n          211,\n          82,\n          42,\n          230\n        ]\n      },\n      \"group\": \"toml\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"parseTomlKeys\",\n        \"description\": \"Returns an array of all the keys in a TOML table.\",\n        \"declaration\": \"function parseTomlKeys(string calldata toml, string calldata key) external pure returns (string[] memory keys);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"parseTomlKeys(string,string)\",\n        \"selector\": \"0x812a44b2\",\n        \"selectorBytes\": [\n          129,\n          42,\n          68,\n          178\n        ]\n      },\n      \"group\": \"toml\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"parseTomlString\",\n        \"description\": \"Parses a string of TOML data at `key` and coerces it to `string`.\",\n        \"declaration\": \"function parseTomlString(string calldata toml, string calldata key) external pure returns (string memory);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"parseTomlString(string,string)\",\n        \"selector\": \"0x8bb8dd43\",\n        \"selectorBytes\": [\n          139,\n          184,\n          221,\n          67\n        ]\n      },\n      \"group\": \"toml\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"parseTomlStringArray\",\n        \"description\": \"Parses a string of TOML data at `key` and coerces it to `string[]`.\",\n        \"declaration\": \"function parseTomlStringArray(string calldata toml, string calldata key) external pure returns (string[] memory);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"parseTomlStringArray(string,string)\",\n        \"selector\": \"0x9f629281\",\n        \"selectorBytes\": [\n          159,\n          98,\n          146,\n          129\n        ]\n      },\n      \"group\": \"toml\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"parseTomlTypeArray\",\n        \"description\": \"Parses a string of TOML data at `key` and coerces it to type array corresponding to `typeDescription`.\",\n        \"declaration\": \"function parseTomlTypeArray(string calldata toml, string calldata key, string calldata typeDescription) external pure returns (bytes memory);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"parseTomlTypeArray(string,string,string)\",\n        \"selector\": \"0x49be3743\",\n        \"selectorBytes\": [\n          73,\n          190,\n          55,\n          67\n        ]\n      },\n      \"group\": \"toml\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"parseTomlType_0\",\n        \"description\": \"Parses a string of TOML data and coerces it to type corresponding to `typeDescription`.\",\n        \"declaration\": \"function parseTomlType(string calldata toml, string calldata typeDescription) external pure returns (bytes memory);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"parseTomlType(string,string)\",\n        \"selector\": \"0x47fa5e11\",\n        \"selectorBytes\": [\n          71,\n          250,\n          94,\n          17\n        ]\n      },\n      \"group\": \"toml\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"parseTomlType_1\",\n        \"description\": \"Parses a string of TOML data at `key` and coerces it to type corresponding to `typeDescription`.\",\n        \"declaration\": \"function parseTomlType(string calldata toml, string calldata key, string calldata typeDescription) external pure returns (bytes memory);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"parseTomlType(string,string,string)\",\n        \"selector\": \"0xf9fa5cdb\",\n        \"selectorBytes\": [\n          249,\n          250,\n          92,\n          219\n        ]\n      },\n      \"group\": \"toml\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"parseTomlUint\",\n        \"description\": \"Parses a string of TOML data at `key` and coerces it to `uint256`.\",\n        \"declaration\": \"function parseTomlUint(string calldata toml, string calldata key) external pure returns (uint256);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"parseTomlUint(string,string)\",\n        \"selector\": \"0xcc7b0487\",\n        \"selectorBytes\": [\n          204,\n          123,\n          4,\n          135\n        ]\n      },\n      \"group\": \"toml\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"parseTomlUintArray\",\n        \"description\": \"Parses a string of TOML data at `key` and coerces it to `uint256[]`.\",\n        \"declaration\": \"function parseTomlUintArray(string calldata toml, string calldata key) external pure returns (uint256[] memory);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"parseTomlUintArray(string,string)\",\n        \"selector\": \"0xb5df27c8\",\n        \"selectorBytes\": [\n          181,\n          223,\n          39,\n          200\n        ]\n      },\n      \"group\": \"toml\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"parseToml_0\",\n        \"description\": \"ABI-encodes a TOML table.\",\n        \"declaration\": \"function parseToml(string calldata toml) external pure returns (bytes memory abiEncodedData);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"parseToml(string)\",\n        \"selector\": \"0x592151f0\",\n        \"selectorBytes\": [\n          89,\n          33,\n          81,\n          240\n        ]\n      },\n      \"group\": \"toml\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"parseToml_1\",\n        \"description\": \"ABI-encodes a TOML table at `key`.\",\n        \"declaration\": \"function parseToml(string calldata toml, string calldata key) external pure returns (bytes memory abiEncodedData);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"parseToml(string,string)\",\n        \"selector\": \"0x37736e08\",\n        \"selectorBytes\": [\n          55,\n          115,\n          110,\n          8\n        ]\n      },\n      \"group\": \"toml\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"parseUint\",\n        \"description\": \"Parses the given `string` into a `uint256`.\",\n        \"declaration\": \"function parseUint(string calldata stringifiedValue) external pure returns (uint256 parsedValue);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"parseUint(string)\",\n        \"selector\": \"0xfa91454d\",\n        \"selectorBytes\": [\n          250,\n          145,\n          69,\n          77\n        ]\n      },\n      \"group\": \"string\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"pauseGasMetering\",\n        \"description\": \"Pauses gas metering (i.e. gas usage is not counted). Noop if already paused.\",\n        \"declaration\": \"function pauseGasMetering() external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"pauseGasMetering()\",\n        \"selector\": \"0xd1a5b36f\",\n        \"selectorBytes\": [\n          209,\n          165,\n          179,\n          111\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"pauseTracing\",\n        \"description\": \"Pauses collection of call traces. Useful in cases when you want to skip tracing of\\ncomplex calls which are not useful for debugging.\",\n        \"declaration\": \"function pauseTracing() external view;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"pauseTracing()\",\n        \"selector\": \"0xc94d1f90\",\n        \"selectorBytes\": [\n          201,\n          77,\n          31,\n          144\n        ]\n      },\n      \"group\": \"utilities\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"prank_0\",\n        \"description\": \"Sets the *next* call's `msg.sender` to be the input address.\",\n        \"declaration\": \"function prank(address msgSender) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"prank(address)\",\n        \"selector\": \"0xca669fa7\",\n        \"selectorBytes\": [\n          202,\n          102,\n          159,\n          167\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"prank_1\",\n        \"description\": \"Sets the *next* call's `msg.sender` to be the input address, and the `tx.origin` to be the second input.\",\n        \"declaration\": \"function prank(address msgSender, address txOrigin) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"prank(address,address)\",\n        \"selector\": \"0x47e50cce\",\n        \"selectorBytes\": [\n          71,\n          229,\n          12,\n          206\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"prank_2\",\n        \"description\": \"Sets the *next* delegate call's `msg.sender` to be the input address.\",\n        \"declaration\": \"function prank(address msgSender, bool delegateCall) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"prank(address,bool)\",\n        \"selector\": \"0xa7f8bf5c\",\n        \"selectorBytes\": [\n          167,\n          248,\n          191,\n          92\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"prank_3\",\n        \"description\": \"Sets the *next* delegate call's `msg.sender` to be the input address, and the `tx.origin` to be the second input.\",\n        \"declaration\": \"function prank(address msgSender, address txOrigin, bool delegateCall) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"prank(address,address,bool)\",\n        \"selector\": \"0x7d73d042\",\n        \"selectorBytes\": [\n          125,\n          115,\n          208,\n          66\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"prevrandao_0\",\n        \"description\": \"Sets `block.prevrandao`.\\nNot available on EVM versions before Paris. Use `difficulty` instead.\\nIf used on unsupported EVM versions it will revert.\",\n        \"declaration\": \"function prevrandao(bytes32 newPrevrandao) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"prevrandao(bytes32)\",\n        \"selector\": \"0x3b925549\",\n        \"selectorBytes\": [\n          59,\n          146,\n          85,\n          73\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"prevrandao_1\",\n        \"description\": \"Sets `block.prevrandao`.\\nNot available on EVM versions before Paris. Use `difficulty` instead.\\nIf used on unsupported EVM versions it will revert.\",\n        \"declaration\": \"function prevrandao(uint256 newPrevrandao) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"prevrandao(uint256)\",\n        \"selector\": \"0x9cb1c0d4\",\n        \"selectorBytes\": [\n          156,\n          177,\n          192,\n          212\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"projectRoot\",\n        \"description\": \"Get the path of the current project root.\",\n        \"declaration\": \"function projectRoot() external view returns (string memory path);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"projectRoot()\",\n        \"selector\": \"0xd930a0e6\",\n        \"selectorBytes\": [\n          217,\n          48,\n          160,\n          230\n        ]\n      },\n      \"group\": \"filesystem\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"prompt\",\n        \"description\": \"Prompts the user for a string value in the terminal.\",\n        \"declaration\": \"function prompt(string calldata promptText) external returns (string memory input);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"prompt(string)\",\n        \"selector\": \"0x47eaf474\",\n        \"selectorBytes\": [\n          71,\n          234,\n          244,\n          116\n        ]\n      },\n      \"group\": \"filesystem\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"promptAddress\",\n        \"description\": \"Prompts the user for an address in the terminal.\",\n        \"declaration\": \"function promptAddress(string calldata promptText) external returns (address);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"promptAddress(string)\",\n        \"selector\": \"0x62ee05f4\",\n        \"selectorBytes\": [\n          98,\n          238,\n          5,\n          244\n        ]\n      },\n      \"group\": \"filesystem\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"promptSecret\",\n        \"description\": \"Prompts the user for a hidden string value in the terminal.\",\n        \"declaration\": \"function promptSecret(string calldata promptText) external returns (string memory input);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"promptSecret(string)\",\n        \"selector\": \"0x1e279d41\",\n        \"selectorBytes\": [\n          30,\n          39,\n          157,\n          65\n        ]\n      },\n      \"group\": \"filesystem\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"promptSecretUint\",\n        \"description\": \"Prompts the user for hidden uint256 in the terminal (usually pk).\",\n        \"declaration\": \"function promptSecretUint(string calldata promptText) external returns (uint256);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"promptSecretUint(string)\",\n        \"selector\": \"0x69ca02b7\",\n        \"selectorBytes\": [\n          105,\n          202,\n          2,\n          183\n        ]\n      },\n      \"group\": \"filesystem\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"promptUint\",\n        \"description\": \"Prompts the user for uint256 in the terminal.\",\n        \"declaration\": \"function promptUint(string calldata promptText) external returns (uint256);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"promptUint(string)\",\n        \"selector\": \"0x652fd489\",\n        \"selectorBytes\": [\n          101,\n          47,\n          212,\n          137\n        ]\n      },\n      \"group\": \"filesystem\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"publicKeyEd25519\",\n        \"description\": \"Derives the Ed25519 public key from a private key.\",\n        \"declaration\": \"function publicKeyEd25519(bytes32 privateKey) external pure returns (bytes32 publicKey);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"publicKeyEd25519(bytes32)\",\n        \"selector\": \"0x27f44236\",\n        \"selectorBytes\": [\n          39,\n          244,\n          66,\n          54\n        ]\n      },\n      \"group\": \"crypto\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"publicKeyP256\",\n        \"description\": \"Derives secp256r1 public key from the provided `privateKey`.\",\n        \"declaration\": \"function publicKeyP256(uint256 privateKey) external pure returns (uint256 publicKeyX, uint256 publicKeyY);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"publicKeyP256(uint256)\",\n        \"selector\": \"0xc453949e\",\n        \"selectorBytes\": [\n          196,\n          83,\n          148,\n          158\n        ]\n      },\n      \"group\": \"crypto\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"randomAddress\",\n        \"description\": \"Returns a random `address`.\",\n        \"declaration\": \"function randomAddress() external view returns (address);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"randomAddress()\",\n        \"selector\": \"0xd5bee9f5\",\n        \"selectorBytes\": [\n          213,\n          190,\n          233,\n          245\n        ]\n      },\n      \"group\": \"utilities\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"randomBool\",\n        \"description\": \"Returns a random `bool`.\",\n        \"declaration\": \"function randomBool() external view returns (bool);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"randomBool()\",\n        \"selector\": \"0xcdc126bd\",\n        \"selectorBytes\": [\n          205,\n          193,\n          38,\n          189\n        ]\n      },\n      \"group\": \"utilities\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"randomBytes\",\n        \"description\": \"Returns a random byte array value of the given length.\",\n        \"declaration\": \"function randomBytes(uint256 len) external view returns (bytes memory);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"randomBytes(uint256)\",\n        \"selector\": \"0x6c5d32a9\",\n        \"selectorBytes\": [\n          108,\n          93,\n          50,\n          169\n        ]\n      },\n      \"group\": \"utilities\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"randomBytes4\",\n        \"description\": \"Returns a random fixed-size byte array of length 4.\",\n        \"declaration\": \"function randomBytes4() external view returns (bytes4);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"randomBytes4()\",\n        \"selector\": \"0x9b7cd579\",\n        \"selectorBytes\": [\n          155,\n          124,\n          213,\n          121\n        ]\n      },\n      \"group\": \"utilities\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"randomBytes8\",\n        \"description\": \"Returns a random fixed-size byte array of length 8.\",\n        \"declaration\": \"function randomBytes8() external view returns (bytes8);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"randomBytes8()\",\n        \"selector\": \"0x0497b0a5\",\n        \"selectorBytes\": [\n          4,\n          151,\n          176,\n          165\n        ]\n      },\n      \"group\": \"utilities\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"randomInt_0\",\n        \"description\": \"Returns a random `int256` value.\",\n        \"declaration\": \"function randomInt() external view returns (int256);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"randomInt()\",\n        \"selector\": \"0x111f1202\",\n        \"selectorBytes\": [\n          17,\n          31,\n          18,\n          2\n        ]\n      },\n      \"group\": \"utilities\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"randomInt_1\",\n        \"description\": \"Returns a random `int256` value of given bits.\",\n        \"declaration\": \"function randomInt(uint256 bits) external view returns (int256);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"randomInt(uint256)\",\n        \"selector\": \"0x12845966\",\n        \"selectorBytes\": [\n          18,\n          132,\n          89,\n          102\n        ]\n      },\n      \"group\": \"utilities\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"randomUint_0\",\n        \"description\": \"Returns a random uint256 value.\",\n        \"declaration\": \"function randomUint() external view returns (uint256);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"randomUint()\",\n        \"selector\": \"0x25124730\",\n        \"selectorBytes\": [\n          37,\n          18,\n          71,\n          48\n        ]\n      },\n      \"group\": \"utilities\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"randomUint_1\",\n        \"description\": \"Returns random uint256 value between the provided range (=min..=max).\",\n        \"declaration\": \"function randomUint(uint256 min, uint256 max) external view returns (uint256);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"randomUint(uint256,uint256)\",\n        \"selector\": \"0xd61b051b\",\n        \"selectorBytes\": [\n          214,\n          27,\n          5,\n          27\n        ]\n      },\n      \"group\": \"utilities\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"randomUint_2\",\n        \"description\": \"Returns a random `uint256` value of given bits.\",\n        \"declaration\": \"function randomUint(uint256 bits) external view returns (uint256);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"randomUint(uint256)\",\n        \"selector\": \"0xcf81e69c\",\n        \"selectorBytes\": [\n          207,\n          129,\n          230,\n          156\n        ]\n      },\n      \"group\": \"utilities\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"readCallers\",\n        \"description\": \"Reads the current `msg.sender` and `tx.origin` from state and reports if there is any active caller modification.\",\n        \"declaration\": \"function readCallers() external view returns (CallerMode callerMode, address msgSender, address txOrigin);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"readCallers()\",\n        \"selector\": \"0x4ad0bac9\",\n        \"selectorBytes\": [\n          74,\n          208,\n          186,\n          201\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"readDir_0\",\n        \"description\": \"Reads the directory at the given path recursively, up to `maxDepth`.\\n`maxDepth` defaults to 1, meaning only the direct children of the given directory will be returned.\\nFollows symbolic links if `followLinks` is true.\",\n        \"declaration\": \"function readDir(string calldata path) external view returns (DirEntry[] memory entries);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"readDir(string)\",\n        \"selector\": \"0xc4bc59e0\",\n        \"selectorBytes\": [\n          196,\n          188,\n          89,\n          224\n        ]\n      },\n      \"group\": \"filesystem\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"readDir_1\",\n        \"description\": \"See `readDir(string)`.\",\n        \"declaration\": \"function readDir(string calldata path, uint64 maxDepth) external view returns (DirEntry[] memory entries);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"readDir(string,uint64)\",\n        \"selector\": \"0x1497876c\",\n        \"selectorBytes\": [\n          20,\n          151,\n          135,\n          108\n        ]\n      },\n      \"group\": \"filesystem\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"readDir_2\",\n        \"description\": \"See `readDir(string)`.\",\n        \"declaration\": \"function readDir(string calldata path, uint64 maxDepth, bool followLinks) external view returns (DirEntry[] memory entries);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"readDir(string,uint64,bool)\",\n        \"selector\": \"0x8102d70d\",\n        \"selectorBytes\": [\n          129,\n          2,\n          215,\n          13\n        ]\n      },\n      \"group\": \"filesystem\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"readFile\",\n        \"description\": \"Reads the entire content of file to string. `path` is relative to the project root.\",\n        \"declaration\": \"function readFile(string calldata path) external view returns (string memory data);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"readFile(string)\",\n        \"selector\": \"0x60f9bb11\",\n        \"selectorBytes\": [\n          96,\n          249,\n          187,\n          17\n        ]\n      },\n      \"group\": \"filesystem\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"readFileBinary\",\n        \"description\": \"Reads the entire content of file as binary. `path` is relative to the project root.\",\n        \"declaration\": \"function readFileBinary(string calldata path) external view returns (bytes memory data);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"readFileBinary(string)\",\n        \"selector\": \"0x16ed7bc4\",\n        \"selectorBytes\": [\n          22,\n          237,\n          123,\n          196\n        ]\n      },\n      \"group\": \"filesystem\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"readLine\",\n        \"description\": \"Reads next line of file to string.\",\n        \"declaration\": \"function readLine(string calldata path) external view returns (string memory line);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"readLine(string)\",\n        \"selector\": \"0x70f55728\",\n        \"selectorBytes\": [\n          112,\n          245,\n          87,\n          40\n        ]\n      },\n      \"group\": \"filesystem\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"readLink\",\n        \"description\": \"Reads a symbolic link, returning the path that the link points to.\\nThis cheatcode will revert in the following situations, but is not limited to just these cases:\\n- `path` is not a symbolic link.\\n- `path` does not exist.\",\n        \"declaration\": \"function readLink(string calldata linkPath) external view returns (string memory targetPath);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"readLink(string)\",\n        \"selector\": \"0x9f5684a2\",\n        \"selectorBytes\": [\n          159,\n          86,\n          132,\n          162\n        ]\n      },\n      \"group\": \"filesystem\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"record\",\n        \"description\": \"Records all storage reads and writes. Use `accesses` to get the recorded data.\\nSubsequent calls to `record` will clear the previous data.\",\n        \"declaration\": \"function record() external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"record()\",\n        \"selector\": \"0x266cf109\",\n        \"selectorBytes\": [\n          38,\n          108,\n          241,\n          9\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"recordLogs\",\n        \"description\": \"Record all the transaction logs.\",\n        \"declaration\": \"function recordLogs() external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"recordLogs()\",\n        \"selector\": \"0x41af2f52\",\n        \"selectorBytes\": [\n          65,\n          175,\n          47,\n          82\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"rememberKey\",\n        \"description\": \"Adds a private key to the local forge wallet and returns the address.\",\n        \"declaration\": \"function rememberKey(uint256 privateKey) external returns (address keyAddr);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"rememberKey(uint256)\",\n        \"selector\": \"0x22100064\",\n        \"selectorBytes\": [\n          34,\n          16,\n          0,\n          100\n        ]\n      },\n      \"group\": \"crypto\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"rememberKeys_0\",\n        \"description\": \"Derive a set number of wallets from a mnemonic at the derivation path `m/44'/60'/0'/0/{0..count}`.\\nThe respective private keys are saved to the local forge wallet for later use and their addresses are returned.\",\n        \"declaration\": \"function rememberKeys(string calldata mnemonic, string calldata derivationPath, uint32 count) external returns (address[] memory keyAddrs);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"rememberKeys(string,string,uint32)\",\n        \"selector\": \"0x97cb9189\",\n        \"selectorBytes\": [\n          151,\n          203,\n          145,\n          137\n        ]\n      },\n      \"group\": \"crypto\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"rememberKeys_1\",\n        \"description\": \"Derive a set number of wallets from a mnemonic in the specified language at the derivation path `m/44'/60'/0'/0/{0..count}`.\\nThe respective private keys are saved to the local forge wallet for later use and their addresses are returned.\",\n        \"declaration\": \"function rememberKeys(string calldata mnemonic, string calldata derivationPath, string calldata language, uint32 count) external returns (address[] memory keyAddrs);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"rememberKeys(string,string,string,uint32)\",\n        \"selector\": \"0xf8d58eaf\",\n        \"selectorBytes\": [\n          248,\n          213,\n          142,\n          175\n        ]\n      },\n      \"group\": \"crypto\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"removeDir\",\n        \"description\": \"Removes a directory at the provided path.\\nThis cheatcode will revert in the following situations, but is not limited to just these cases:\\n- `path` doesn't exist.\\n- `path` isn't a directory.\\n- User lacks permissions to modify `path`.\\n- The directory is not empty and `recursive` is false.\\n`path` is relative to the project root.\",\n        \"declaration\": \"function removeDir(string calldata path, bool recursive) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"removeDir(string,bool)\",\n        \"selector\": \"0x45c62011\",\n        \"selectorBytes\": [\n          69,\n          198,\n          32,\n          17\n        ]\n      },\n      \"group\": \"filesystem\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"removeFile\",\n        \"description\": \"Removes a file from the filesystem.\\nThis cheatcode will revert in the following situations, but is not limited to just these cases:\\n- `path` points to a directory.\\n- The file doesn't exist.\\n- The user lacks permissions to remove the file.\\n`path` is relative to the project root.\",\n        \"declaration\": \"function removeFile(string calldata path) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"removeFile(string)\",\n        \"selector\": \"0xf1afe04d\",\n        \"selectorBytes\": [\n          241,\n          175,\n          224,\n          77\n        ]\n      },\n      \"group\": \"filesystem\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"replace\",\n        \"description\": \"Replaces occurrences of `from` in the given `string` with `to`.\",\n        \"declaration\": \"function replace(string calldata input, string calldata from, string calldata to) external pure returns (string memory output);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"replace(string,string,string)\",\n        \"selector\": \"0xe00ad03e\",\n        \"selectorBytes\": [\n          224,\n          10,\n          208,\n          62\n        ]\n      },\n      \"group\": \"string\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"resetGasMetering\",\n        \"description\": \"Reset gas metering (i.e. gas usage is set to gas limit).\",\n        \"declaration\": \"function resetGasMetering() external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"resetGasMetering()\",\n        \"selector\": \"0xbe367dd3\",\n        \"selectorBytes\": [\n          190,\n          54,\n          125,\n          211\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"resetNonce\",\n        \"description\": \"Resets the nonce of an account to 0 for EOAs and 1 for contract accounts.\",\n        \"declaration\": \"function resetNonce(address account) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"resetNonce(address)\",\n        \"selector\": \"0x1c72346d\",\n        \"selectorBytes\": [\n          28,\n          114,\n          52,\n          109\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"resolveEnv\",\n        \"description\": \"Resolves the env variable placeholders of a given input string.\",\n        \"declaration\": \"function resolveEnv(string calldata input) external returns (string memory);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"resolveEnv(string)\",\n        \"selector\": \"0xddd2128d\",\n        \"selectorBytes\": [\n          221,\n          210,\n          18,\n          141\n        ]\n      },\n      \"group\": \"environment\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"resumeGasMetering\",\n        \"description\": \"Resumes gas metering (i.e. gas usage is counted again). Noop if already on.\",\n        \"declaration\": \"function resumeGasMetering() external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"resumeGasMetering()\",\n        \"selector\": \"0x2bcd50e0\",\n        \"selectorBytes\": [\n          43,\n          205,\n          80,\n          224\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"resumeTracing\",\n        \"description\": \"Unpauses collection of call traces.\",\n        \"declaration\": \"function resumeTracing() external view;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"resumeTracing()\",\n        \"selector\": \"0x72a09ccb\",\n        \"selectorBytes\": [\n          114,\n          160,\n          156,\n          203\n        ]\n      },\n      \"group\": \"utilities\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"revertTo\",\n        \"description\": \"`revertTo` is being deprecated in favor of `revertToState`. It will be removed in future versions.\",\n        \"declaration\": \"function revertTo(uint256 snapshotId) external returns (bool success);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"revertTo(uint256)\",\n        \"selector\": \"0x44d7f0a4\",\n        \"selectorBytes\": [\n          68,\n          215,\n          240,\n          164\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": {\n        \"deprecated\": \"replaced by `revertToState`\"\n      },\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"revertToAndDelete\",\n        \"description\": \"`revertToAndDelete` is being deprecated in favor of `revertToStateAndDelete`. It will be removed in future versions.\",\n        \"declaration\": \"function revertToAndDelete(uint256 snapshotId) external returns (bool success);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"revertToAndDelete(uint256)\",\n        \"selector\": \"0x03e0aca9\",\n        \"selectorBytes\": [\n          3,\n          224,\n          172,\n          169\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": {\n        \"deprecated\": \"replaced by `revertToStateAndDelete`\"\n      },\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"revertToState\",\n        \"description\": \"Revert the state of the EVM to a previous snapshot\\nTakes the snapshot ID to revert to.\\nReturns `true` if the snapshot was successfully reverted.\\nReturns `false` if the snapshot does not exist.\\n**Note:** This does not automatically delete the snapshot. To delete the snapshot use `deleteStateSnapshot`.\",\n        \"declaration\": \"function revertToState(uint256 snapshotId) external returns (bool success);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"revertToState(uint256)\",\n        \"selector\": \"0xc2527405\",\n        \"selectorBytes\": [\n          194,\n          82,\n          116,\n          5\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"revertToStateAndDelete\",\n        \"description\": \"Revert the state of the EVM to a previous snapshot and automatically deletes the snapshots\\nTakes the snapshot ID to revert to.\\nReturns `true` if the snapshot was successfully reverted and deleted.\\nReturns `false` if the snapshot does not exist.\",\n        \"declaration\": \"function revertToStateAndDelete(uint256 snapshotId) external returns (bool success);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"revertToStateAndDelete(uint256)\",\n        \"selector\": \"0x3a1985dc\",\n        \"selectorBytes\": [\n          58,\n          25,\n          133,\n          220\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"revokePersistent_0\",\n        \"description\": \"Revokes persistent status from the address, previously added via `makePersistent`.\",\n        \"declaration\": \"function revokePersistent(address account) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"revokePersistent(address)\",\n        \"selector\": \"0x997a0222\",\n        \"selectorBytes\": [\n          153,\n          122,\n          2,\n          34\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"revokePersistent_1\",\n        \"description\": \"See `revokePersistent(address)`.\",\n        \"declaration\": \"function revokePersistent(address[] calldata accounts) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"revokePersistent(address[])\",\n        \"selector\": \"0x3ce969e6\",\n        \"selectorBytes\": [\n          60,\n          233,\n          105,\n          230\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"roll\",\n        \"description\": \"Sets `block.height`.\",\n        \"declaration\": \"function roll(uint256 newHeight) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"roll(uint256)\",\n        \"selector\": \"0x1f7b4f30\",\n        \"selectorBytes\": [\n          31,\n          123,\n          79,\n          48\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"rollFork_0\",\n        \"description\": \"Updates the currently active fork to given block number\\nThis is similar to `roll` but for the currently active fork.\",\n        \"declaration\": \"function rollFork(uint256 blockNumber) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"rollFork(uint256)\",\n        \"selector\": \"0xd9bbf3a1\",\n        \"selectorBytes\": [\n          217,\n          187,\n          243,\n          161\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"rollFork_1\",\n        \"description\": \"Updates the currently active fork to given transaction. This will `rollFork` with the number\\nof the block the transaction was mined in and replays all transaction mined before it in the block.\",\n        \"declaration\": \"function rollFork(bytes32 txHash) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"rollFork(bytes32)\",\n        \"selector\": \"0x0f29772b\",\n        \"selectorBytes\": [\n          15,\n          41,\n          119,\n          43\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"rollFork_2\",\n        \"description\": \"Updates the given fork to given block number.\",\n        \"declaration\": \"function rollFork(uint256 forkId, uint256 blockNumber) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"rollFork(uint256,uint256)\",\n        \"selector\": \"0xd74c83a4\",\n        \"selectorBytes\": [\n          215,\n          76,\n          131,\n          164\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"rollFork_3\",\n        \"description\": \"Updates the given fork to block number of the given transaction and replays all transaction mined before it in the block.\",\n        \"declaration\": \"function rollFork(uint256 forkId, bytes32 txHash) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"rollFork(uint256,bytes32)\",\n        \"selector\": \"0xf2830f7b\",\n        \"selectorBytes\": [\n          242,\n          131,\n          15,\n          123\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"rpcUrl\",\n        \"description\": \"Returns the RPC url for the given alias.\",\n        \"declaration\": \"function rpcUrl(string calldata rpcAlias) external view returns (string memory json);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"rpcUrl(string)\",\n        \"selector\": \"0x975a6ce9\",\n        \"selectorBytes\": [\n          151,\n          90,\n          108,\n          233\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"rpcUrlStructs\",\n        \"description\": \"Returns all rpc urls and their aliases as structs.\",\n        \"declaration\": \"function rpcUrlStructs() external view returns (Rpc[] memory urls);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"rpcUrlStructs()\",\n        \"selector\": \"0x9d2ad72a\",\n        \"selectorBytes\": [\n          157,\n          42,\n          215,\n          42\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"rpcUrls\",\n        \"description\": \"Returns all rpc urls and their aliases `[alias, url][]`.\",\n        \"declaration\": \"function rpcUrls() external view returns (string[2][] memory urls);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"rpcUrls()\",\n        \"selector\": \"0xa85a8418\",\n        \"selectorBytes\": [\n          168,\n          90,\n          132,\n          24\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"rpc_0\",\n        \"description\": \"Performs an Ethereum JSON-RPC request to the current fork URL.\",\n        \"declaration\": \"function rpc(string calldata method, string calldata params) external returns (bytes memory data);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"rpc(string,string)\",\n        \"selector\": \"0x1206c8a8\",\n        \"selectorBytes\": [\n          18,\n          6,\n          200,\n          168\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"rpc_1\",\n        \"description\": \"Performs an Ethereum JSON-RPC request to the given endpoint.\",\n        \"declaration\": \"function rpc(string calldata urlOrAlias, string calldata method, string calldata params) external returns (bytes memory data);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"rpc(string,string,string)\",\n        \"selector\": \"0x0199a220\",\n        \"selectorBytes\": [\n          1,\n          153,\n          162,\n          32\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"selectFork\",\n        \"description\": \"Takes a fork identifier created by `createFork` and sets the corresponding forked state as active.\",\n        \"declaration\": \"function selectFork(uint256 forkId) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"selectFork(uint256)\",\n        \"selector\": \"0x9ebf6827\",\n        \"selectorBytes\": [\n          158,\n          191,\n          104,\n          39\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"serializeAddress_0\",\n        \"description\": \"See `serializeJson`.\",\n        \"declaration\": \"function serializeAddress(string calldata objectKey, string calldata valueKey, address value) external returns (string memory json);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"serializeAddress(string,string,address)\",\n        \"selector\": \"0x972c6062\",\n        \"selectorBytes\": [\n          151,\n          44,\n          96,\n          98\n        ]\n      },\n      \"group\": \"json\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"serializeAddress_1\",\n        \"description\": \"See `serializeJson`.\",\n        \"declaration\": \"function serializeAddress(string calldata objectKey, string calldata valueKey, address[] calldata values) external returns (string memory json);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"serializeAddress(string,string,address[])\",\n        \"selector\": \"0x1e356e1a\",\n        \"selectorBytes\": [\n          30,\n          53,\n          110,\n          26\n        ]\n      },\n      \"group\": \"json\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"serializeBool_0\",\n        \"description\": \"See `serializeJson`.\",\n        \"declaration\": \"function serializeBool(string calldata objectKey, string calldata valueKey, bool value) external returns (string memory json);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"serializeBool(string,string,bool)\",\n        \"selector\": \"0xac22e971\",\n        \"selectorBytes\": [\n          172,\n          34,\n          233,\n          113\n        ]\n      },\n      \"group\": \"json\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"serializeBool_1\",\n        \"description\": \"See `serializeJson`.\",\n        \"declaration\": \"function serializeBool(string calldata objectKey, string calldata valueKey, bool[] calldata values) external returns (string memory json);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"serializeBool(string,string,bool[])\",\n        \"selector\": \"0x92925aa1\",\n        \"selectorBytes\": [\n          146,\n          146,\n          90,\n          161\n        ]\n      },\n      \"group\": \"json\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"serializeBytes32_0\",\n        \"description\": \"See `serializeJson`.\",\n        \"declaration\": \"function serializeBytes32(string calldata objectKey, string calldata valueKey, bytes32 value) external returns (string memory json);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"serializeBytes32(string,string,bytes32)\",\n        \"selector\": \"0x2d812b44\",\n        \"selectorBytes\": [\n          45,\n          129,\n          43,\n          68\n        ]\n      },\n      \"group\": \"json\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"serializeBytes32_1\",\n        \"description\": \"See `serializeJson`.\",\n        \"declaration\": \"function serializeBytes32(string calldata objectKey, string calldata valueKey, bytes32[] calldata values) external returns (string memory json);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"serializeBytes32(string,string,bytes32[])\",\n        \"selector\": \"0x201e43e2\",\n        \"selectorBytes\": [\n          32,\n          30,\n          67,\n          226\n        ]\n      },\n      \"group\": \"json\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"serializeBytes_0\",\n        \"description\": \"See `serializeJson`.\",\n        \"declaration\": \"function serializeBytes(string calldata objectKey, string calldata valueKey, bytes calldata value) external returns (string memory json);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"serializeBytes(string,string,bytes)\",\n        \"selector\": \"0xf21d52c7\",\n        \"selectorBytes\": [\n          242,\n          29,\n          82,\n          199\n        ]\n      },\n      \"group\": \"json\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"serializeBytes_1\",\n        \"description\": \"See `serializeJson`.\",\n        \"declaration\": \"function serializeBytes(string calldata objectKey, string calldata valueKey, bytes[] calldata values) external returns (string memory json);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"serializeBytes(string,string,bytes[])\",\n        \"selector\": \"0x9884b232\",\n        \"selectorBytes\": [\n          152,\n          132,\n          178,\n          50\n        ]\n      },\n      \"group\": \"json\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"serializeInt_0\",\n        \"description\": \"See `serializeJson`.\",\n        \"declaration\": \"function serializeInt(string calldata objectKey, string calldata valueKey, int256 value) external returns (string memory json);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"serializeInt(string,string,int256)\",\n        \"selector\": \"0x3f33db60\",\n        \"selectorBytes\": [\n          63,\n          51,\n          219,\n          96\n        ]\n      },\n      \"group\": \"json\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"serializeInt_1\",\n        \"description\": \"See `serializeJson`.\",\n        \"declaration\": \"function serializeInt(string calldata objectKey, string calldata valueKey, int256[] calldata values) external returns (string memory json);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"serializeInt(string,string,int256[])\",\n        \"selector\": \"0x7676e127\",\n        \"selectorBytes\": [\n          118,\n          118,\n          225,\n          39\n        ]\n      },\n      \"group\": \"json\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"serializeJson\",\n        \"description\": \"Serializes a key and value to a JSON object stored in-memory that can be later written to a file.\\nReturns the stringified version of the specific JSON file up to that moment.\",\n        \"declaration\": \"function serializeJson(string calldata objectKey, string calldata value) external returns (string memory json);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"serializeJson(string,string)\",\n        \"selector\": \"0x9b3358b0\",\n        \"selectorBytes\": [\n          155,\n          51,\n          88,\n          176\n        ]\n      },\n      \"group\": \"json\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"serializeJsonType_0\",\n        \"description\": \"See `serializeJson`.\",\n        \"declaration\": \"function serializeJsonType(string calldata typeDescription, bytes calldata value) external pure returns (string memory json);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"serializeJsonType(string,bytes)\",\n        \"selector\": \"0x6d4f96a6\",\n        \"selectorBytes\": [\n          109,\n          79,\n          150,\n          166\n        ]\n      },\n      \"group\": \"json\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"serializeJsonType_1\",\n        \"description\": \"See `serializeJson`.\",\n        \"declaration\": \"function serializeJsonType(string calldata objectKey, string calldata valueKey, string calldata typeDescription, bytes calldata value) external returns (string memory json);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"serializeJsonType(string,string,string,bytes)\",\n        \"selector\": \"0x6f93bccb\",\n        \"selectorBytes\": [\n          111,\n          147,\n          188,\n          203\n        ]\n      },\n      \"group\": \"json\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"serializeString_0\",\n        \"description\": \"See `serializeJson`.\",\n        \"declaration\": \"function serializeString(string calldata objectKey, string calldata valueKey, string calldata value) external returns (string memory json);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"serializeString(string,string,string)\",\n        \"selector\": \"0x88da6d35\",\n        \"selectorBytes\": [\n          136,\n          218,\n          109,\n          53\n        ]\n      },\n      \"group\": \"json\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"serializeString_1\",\n        \"description\": \"See `serializeJson`.\",\n        \"declaration\": \"function serializeString(string calldata objectKey, string calldata valueKey, string[] calldata values) external returns (string memory json);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"serializeString(string,string,string[])\",\n        \"selector\": \"0x561cd6f3\",\n        \"selectorBytes\": [\n          86,\n          28,\n          214,\n          243\n        ]\n      },\n      \"group\": \"json\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"serializeUintToHex\",\n        \"description\": \"See `serializeJson`.\",\n        \"declaration\": \"function serializeUintToHex(string calldata objectKey, string calldata valueKey, uint256 value) external returns (string memory json);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"serializeUintToHex(string,string,uint256)\",\n        \"selector\": \"0xae5a2ae8\",\n        \"selectorBytes\": [\n          174,\n          90,\n          42,\n          232\n        ]\n      },\n      \"group\": \"json\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"serializeUint_0\",\n        \"description\": \"See `serializeJson`.\",\n        \"declaration\": \"function serializeUint(string calldata objectKey, string calldata valueKey, uint256 value) external returns (string memory json);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"serializeUint(string,string,uint256)\",\n        \"selector\": \"0x129e9002\",\n        \"selectorBytes\": [\n          18,\n          158,\n          144,\n          2\n        ]\n      },\n      \"group\": \"json\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"serializeUint_1\",\n        \"description\": \"See `serializeJson`.\",\n        \"declaration\": \"function serializeUint(string calldata objectKey, string calldata valueKey, uint256[] calldata values) external returns (string memory json);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"serializeUint(string,string,uint256[])\",\n        \"selector\": \"0xfee9a469\",\n        \"selectorBytes\": [\n          254,\n          233,\n          164,\n          105\n        ]\n      },\n      \"group\": \"json\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"setArbitraryStorage_0\",\n        \"description\": \"Utility cheatcode to set arbitrary storage for given target address.\",\n        \"declaration\": \"function setArbitraryStorage(address target) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"setArbitraryStorage(address)\",\n        \"selector\": \"0xe1631837\",\n        \"selectorBytes\": [\n          225,\n          99,\n          24,\n          55\n        ]\n      },\n      \"group\": \"utilities\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"setArbitraryStorage_1\",\n        \"description\": \"Utility cheatcode to set arbitrary storage for given target address and overwrite\\nany storage slots that have been previously set.\",\n        \"declaration\": \"function setArbitraryStorage(address target, bool overwrite) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"setArbitraryStorage(address,bool)\",\n        \"selector\": \"0xd3ec2a0b\",\n        \"selectorBytes\": [\n          211,\n          236,\n          42,\n          11\n        ]\n      },\n      \"group\": \"utilities\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"setBlockhash\",\n        \"description\": \"Set blockhash for the current block.\\nIt only sets the blockhash for blocks where `block.number - 256 <= number < block.number`.\",\n        \"declaration\": \"function setBlockhash(uint256 blockNumber, bytes32 blockHash) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"setBlockhash(uint256,bytes32)\",\n        \"selector\": \"0x5314b54a\",\n        \"selectorBytes\": [\n          83,\n          20,\n          181,\n          74\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"setEnv\",\n        \"description\": \"Sets environment variables.\",\n        \"declaration\": \"function setEnv(string calldata name, string calldata value) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"setEnv(string,string)\",\n        \"selector\": \"0x3d5923ee\",\n        \"selectorBytes\": [\n          61,\n          89,\n          35,\n          238\n        ]\n      },\n      \"group\": \"environment\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"setEvmVersion\",\n        \"description\": \"Set the exact test or script execution evm version, e.g. `berlin`, `cancun`.\\n**Note:** The execution evm version is not the same as the compilation one.\",\n        \"declaration\": \"function setEvmVersion(string calldata evm) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"setEvmVersion(string)\",\n        \"selector\": \"0x43179f5a\",\n        \"selectorBytes\": [\n          67,\n          23,\n          159,\n          90\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"setNonce\",\n        \"description\": \"Sets the nonce of an account. Must be higher than the current nonce of the account.\",\n        \"declaration\": \"function setNonce(address account, uint64 newNonce) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"setNonce(address,uint64)\",\n        \"selector\": \"0xf8e18b57\",\n        \"selectorBytes\": [\n          248,\n          225,\n          139,\n          87\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"setNonceUnsafe\",\n        \"description\": \"Sets the nonce of an account to an arbitrary value.\",\n        \"declaration\": \"function setNonceUnsafe(address account, uint64 newNonce) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"setNonceUnsafe(address,uint64)\",\n        \"selector\": \"0x9b67b21c\",\n        \"selectorBytes\": [\n          155,\n          103,\n          178,\n          28\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"setSeed\",\n        \"description\": \"Set RNG seed.\",\n        \"declaration\": \"function setSeed(uint256 seed) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"setSeed(uint256)\",\n        \"selector\": \"0xc32a50f9\",\n        \"selectorBytes\": [\n          195,\n          42,\n          80,\n          249\n        ]\n      },\n      \"group\": \"utilities\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"shuffle\",\n        \"description\": \"Randomly shuffles an array.\",\n        \"declaration\": \"function shuffle(uint256[] calldata array) external returns (uint256[] memory);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"shuffle(uint256[])\",\n        \"selector\": \"0x54f1469c\",\n        \"selectorBytes\": [\n          84,\n          241,\n          70,\n          156\n        ]\n      },\n      \"group\": \"utilities\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"signAndAttachDelegation_0\",\n        \"description\": \"Sign an EIP-7702 authorization and designate the next call as an EIP-7702 transaction\",\n        \"declaration\": \"function signAndAttachDelegation(address implementation, uint256 privateKey) external returns (SignedDelegation memory signedDelegation);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"signAndAttachDelegation(address,uint256)\",\n        \"selector\": \"0xc7fa7288\",\n        \"selectorBytes\": [\n          199,\n          250,\n          114,\n          136\n        ]\n      },\n      \"group\": \"scripting\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"signAndAttachDelegation_1\",\n        \"description\": \"Sign an EIP-7702 authorization and designate the next call as an EIP-7702 transaction for specific nonce\",\n        \"declaration\": \"function signAndAttachDelegation(address implementation, uint256 privateKey, uint64 nonce) external returns (SignedDelegation memory signedDelegation);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"signAndAttachDelegation(address,uint256,uint64)\",\n        \"selector\": \"0xcde3e5be\",\n        \"selectorBytes\": [\n          205,\n          227,\n          229,\n          190\n        ]\n      },\n      \"group\": \"scripting\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"signAndAttachDelegation_2\",\n        \"description\": \"Sign an EIP-7702 authorization and designate the next call as an EIP-7702 transaction, with optional cross-chain validity.\",\n        \"declaration\": \"function signAndAttachDelegation(address implementation, uint256 privateKey, bool crossChain) external returns (SignedDelegation memory signedDelegation);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"signAndAttachDelegation(address,uint256,bool)\",\n        \"selector\": \"0xd936e146\",\n        \"selectorBytes\": [\n          217,\n          54,\n          225,\n          70\n        ]\n      },\n      \"group\": \"scripting\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"signCompact_0\",\n        \"description\": \"Signs data with a `Wallet`.\\nReturns a compact signature (`r`, `vs`) as per EIP-2098, where `vs` encodes both the\\nsignature's `s` value, and the recovery id `v` in a single bytes32.\\nThis format reduces the signature size from 65 to 64 bytes.\",\n        \"declaration\": \"function signCompact(Wallet calldata wallet, bytes32 digest) external pure returns (bytes32 r, bytes32 vs);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"signCompact((address,uint256,uint256,uint256),bytes32)\",\n        \"selector\": \"0x3d0e292f\",\n        \"selectorBytes\": [\n          61,\n          14,\n          41,\n          47\n        ]\n      },\n      \"group\": \"crypto\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"signCompact_1\",\n        \"description\": \"Signs `digest` with `privateKey` using the secp256k1 curve.\\nReturns a compact signature (`r`, `vs`) as per EIP-2098, where `vs` encodes both the\\nsignature's `s` value, and the recovery id `v` in a single bytes32.\\nThis format reduces the signature size from 65 to 64 bytes.\",\n        \"declaration\": \"function signCompact(uint256 privateKey, bytes32 digest) external pure returns (bytes32 r, bytes32 vs);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"signCompact(uint256,bytes32)\",\n        \"selector\": \"0xcc2a781f\",\n        \"selectorBytes\": [\n          204,\n          42,\n          120,\n          31\n        ]\n      },\n      \"group\": \"crypto\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"signCompact_2\",\n        \"description\": \"Signs `digest` with signer provided to script using the secp256k1 curve.\\nReturns a compact signature (`r`, `vs`) as per EIP-2098, where `vs` encodes both the\\nsignature's `s` value, and the recovery id `v` in a single bytes32.\\nThis format reduces the signature size from 65 to 64 bytes.\\nIf `--sender` is provided, the signer with provided address is used, otherwise,\\nif exactly one signer is provided to the script, that signer is used.\\nRaises error if signer passed through `--sender` does not match any unlocked signers or\\nif `--sender` is not provided and not exactly one signer is passed to the script.\",\n        \"declaration\": \"function signCompact(bytes32 digest) external pure returns (bytes32 r, bytes32 vs);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"signCompact(bytes32)\",\n        \"selector\": \"0xa282dc4b\",\n        \"selectorBytes\": [\n          162,\n          130,\n          220,\n          75\n        ]\n      },\n      \"group\": \"crypto\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"signCompact_3\",\n        \"description\": \"Signs `digest` with signer provided to script using the secp256k1 curve.\\nReturns a compact signature (`r`, `vs`) as per EIP-2098, where `vs` encodes both the\\nsignature's `s` value, and the recovery id `v` in a single bytes32.\\nThis format reduces the signature size from 65 to 64 bytes.\\nRaises error if none of the signers passed into the script have provided address.\",\n        \"declaration\": \"function signCompact(address signer, bytes32 digest) external pure returns (bytes32 r, bytes32 vs);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"signCompact(address,bytes32)\",\n        \"selector\": \"0x8e2f97bf\",\n        \"selectorBytes\": [\n          142,\n          47,\n          151,\n          191\n        ]\n      },\n      \"group\": \"crypto\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"signDelegation_0\",\n        \"description\": \"Sign an EIP-7702 authorization for delegation\",\n        \"declaration\": \"function signDelegation(address implementation, uint256 privateKey) external returns (SignedDelegation memory signedDelegation);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"signDelegation(address,uint256)\",\n        \"selector\": \"0x5b593c7b\",\n        \"selectorBytes\": [\n          91,\n          89,\n          60,\n          123\n        ]\n      },\n      \"group\": \"scripting\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"signDelegation_1\",\n        \"description\": \"Sign an EIP-7702 authorization for delegation for specific nonce\",\n        \"declaration\": \"function signDelegation(address implementation, uint256 privateKey, uint64 nonce) external returns (SignedDelegation memory signedDelegation);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"signDelegation(address,uint256,uint64)\",\n        \"selector\": \"0xceba2ec3\",\n        \"selectorBytes\": [\n          206,\n          186,\n          46,\n          195\n        ]\n      },\n      \"group\": \"scripting\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"signDelegation_2\",\n        \"description\": \"Sign an EIP-7702 authorization for delegation, with optional cross-chain validity.\",\n        \"declaration\": \"function signDelegation(address implementation, uint256 privateKey, bool crossChain) external returns (SignedDelegation memory signedDelegation);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"signDelegation(address,uint256,bool)\",\n        \"selector\": \"0xcdd7563d\",\n        \"selectorBytes\": [\n          205,\n          215,\n          86,\n          61\n        ]\n      },\n      \"group\": \"scripting\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"signEd25519\",\n        \"description\": \"Signs a message with namespace using Ed25519.\\nThe signature covers namespace || message for domain separation.\\nReturns a 64-byte Ed25519 signature.\",\n        \"declaration\": \"function signEd25519(bytes calldata namespace, bytes calldata message, bytes32 privateKey) external pure returns (bytes memory signature);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"signEd25519(bytes,bytes,bytes32)\",\n        \"selector\": \"0xef609c65\",\n        \"selectorBytes\": [\n          239,\n          96,\n          156,\n          101\n        ]\n      },\n      \"group\": \"crypto\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"signP256\",\n        \"description\": \"Signs `digest` with `privateKey` using the secp256r1 curve.\",\n        \"declaration\": \"function signP256(uint256 privateKey, bytes32 digest) external pure returns (bytes32 r, bytes32 s);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"signP256(uint256,bytes32)\",\n        \"selector\": \"0x83211b40\",\n        \"selectorBytes\": [\n          131,\n          33,\n          27,\n          64\n        ]\n      },\n      \"group\": \"crypto\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"signWithNonceUnsafe\",\n        \"description\": \"Signs `digest` with `privateKey` on the secp256k1 curve, using the given `nonce`\\nas the raw ephemeral k value in ECDSA (instead of deriving it deterministically).\",\n        \"declaration\": \"function signWithNonceUnsafe(uint256 privateKey, bytes32 digest, uint256 nonce) external pure returns (uint8 v, bytes32 r, bytes32 s);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"signWithNonceUnsafe(uint256,bytes32,uint256)\",\n        \"selector\": \"0x2012783a\",\n        \"selectorBytes\": [\n          32,\n          18,\n          120,\n          58\n        ]\n      },\n      \"group\": \"crypto\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"sign_0\",\n        \"description\": \"Signs data with a `Wallet`.\",\n        \"declaration\": \"function sign(Wallet calldata wallet, bytes32 digest) external pure returns (uint8 v, bytes32 r, bytes32 s);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"sign((address,uint256,uint256,uint256),bytes32)\",\n        \"selector\": \"0xb25c5a25\",\n        \"selectorBytes\": [\n          178,\n          92,\n          90,\n          37\n        ]\n      },\n      \"group\": \"crypto\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"sign_1\",\n        \"description\": \"Signs `digest` with `privateKey` using the secp256k1 curve.\",\n        \"declaration\": \"function sign(uint256 privateKey, bytes32 digest) external pure returns (uint8 v, bytes32 r, bytes32 s);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"sign(uint256,bytes32)\",\n        \"selector\": \"0xe341eaa4\",\n        \"selectorBytes\": [\n          227,\n          65,\n          234,\n          164\n        ]\n      },\n      \"group\": \"crypto\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"sign_2\",\n        \"description\": \"Signs `digest` with signer provided to script using the secp256k1 curve.\\nIf `--sender` is provided, the signer with provided address is used, otherwise,\\nif exactly one signer is provided to the script, that signer is used.\\nRaises error if signer passed through `--sender` does not match any unlocked signers or\\nif `--sender` is not provided and not exactly one signer is passed to the script.\",\n        \"declaration\": \"function sign(bytes32 digest) external pure returns (uint8 v, bytes32 r, bytes32 s);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"sign(bytes32)\",\n        \"selector\": \"0x799cd333\",\n        \"selectorBytes\": [\n          121,\n          156,\n          211,\n          51\n        ]\n      },\n      \"group\": \"crypto\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"sign_3\",\n        \"description\": \"Signs `digest` with signer provided to script using the secp256k1 curve.\\nRaises error if none of the signers passed into the script have provided address.\",\n        \"declaration\": \"function sign(address signer, bytes32 digest) external pure returns (uint8 v, bytes32 r, bytes32 s);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"sign(address,bytes32)\",\n        \"selector\": \"0x8c1aa205\",\n        \"selectorBytes\": [\n          140,\n          26,\n          162,\n          5\n        ]\n      },\n      \"group\": \"crypto\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"skip_0\",\n        \"description\": \"Marks a test as skipped. Must be called at the top level of a test.\",\n        \"declaration\": \"function skip(bool skipTest) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"skip(bool)\",\n        \"selector\": \"0xdd82d13e\",\n        \"selectorBytes\": [\n          221,\n          130,\n          209,\n          62\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"skip_1\",\n        \"description\": \"Marks a test as skipped with a reason. Must be called at the top level of a test.\",\n        \"declaration\": \"function skip(bool skipTest, string calldata reason) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"skip(bool,string)\",\n        \"selector\": \"0xc42a80a7\",\n        \"selectorBytes\": [\n          196,\n          42,\n          128,\n          167\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"sleep\",\n        \"description\": \"Suspends execution of the main thread for `duration` milliseconds.\",\n        \"declaration\": \"function sleep(uint256 duration) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"sleep(uint256)\",\n        \"selector\": \"0xfa9d8713\",\n        \"selectorBytes\": [\n          250,\n          157,\n          135,\n          19\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"snapshot\",\n        \"description\": \"`snapshot` is being deprecated in favor of `snapshotState`. It will be removed in future versions.\",\n        \"declaration\": \"function snapshot() external returns (uint256 snapshotId);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"snapshot()\",\n        \"selector\": \"0x9711715a\",\n        \"selectorBytes\": [\n          151,\n          17,\n          113,\n          90\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": {\n        \"deprecated\": \"replaced by `snapshotState`\"\n      },\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"snapshotGasLastCall_0\",\n        \"description\": \"Snapshot capture the gas usage of the last call by name from the callee perspective.\",\n        \"declaration\": \"function snapshotGasLastCall(string calldata name) external returns (uint256 gasUsed);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"snapshotGasLastCall(string)\",\n        \"selector\": \"0xdd9fca12\",\n        \"selectorBytes\": [\n          221,\n          159,\n          202,\n          18\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"snapshotGasLastCall_1\",\n        \"description\": \"Snapshot capture the gas usage of the last call by name in a group from the callee perspective.\",\n        \"declaration\": \"function snapshotGasLastCall(string calldata group, string calldata name) external returns (uint256 gasUsed);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"snapshotGasLastCall(string,string)\",\n        \"selector\": \"0x200c6772\",\n        \"selectorBytes\": [\n          32,\n          12,\n          103,\n          114\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"snapshotState\",\n        \"description\": \"Snapshot the current state of the evm.\\nReturns the ID of the snapshot that was created.\\nTo revert a snapshot use `revertToState`.\",\n        \"declaration\": \"function snapshotState() external returns (uint256 snapshotId);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"snapshotState()\",\n        \"selector\": \"0x9cd23835\",\n        \"selectorBytes\": [\n          156,\n          210,\n          56,\n          53\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"snapshotValue_0\",\n        \"description\": \"Snapshot capture an arbitrary numerical value by name.\\nThe group name is derived from the contract name.\",\n        \"declaration\": \"function snapshotValue(string calldata name, uint256 value) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"snapshotValue(string,uint256)\",\n        \"selector\": \"0x51db805a\",\n        \"selectorBytes\": [\n          81,\n          219,\n          128,\n          90\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"snapshotValue_1\",\n        \"description\": \"Snapshot capture an arbitrary numerical value by name in a group.\",\n        \"declaration\": \"function snapshotValue(string calldata group, string calldata name, uint256 value) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"snapshotValue(string,string,uint256)\",\n        \"selector\": \"0x6d2b27d8\",\n        \"selectorBytes\": [\n          109,\n          43,\n          39,\n          216\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"sort\",\n        \"description\": \"Sorts an array in ascending order.\",\n        \"declaration\": \"function sort(uint256[] calldata array) external returns (uint256[] memory);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"sort(uint256[])\",\n        \"selector\": \"0x9ec8b026\",\n        \"selectorBytes\": [\n          158,\n          200,\n          176,\n          38\n        ]\n      },\n      \"group\": \"utilities\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"split\",\n        \"description\": \"Splits the given `string` into an array of strings divided by the `delimiter`.\",\n        \"declaration\": \"function split(string calldata input, string calldata delimiter) external pure returns (string[] memory outputs);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"split(string,string)\",\n        \"selector\": \"0x8bb75533\",\n        \"selectorBytes\": [\n          139,\n          183,\n          85,\n          51\n        ]\n      },\n      \"group\": \"string\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"startBroadcast_0\",\n        \"description\": \"Has all subsequent calls (at this call depth only) create transactions that can later be signed and sent onchain.\\nBroadcasting address is determined by checking the following in order:\\n1. If `--sender` argument was provided, that address is used.\\n2. If exactly one signer (e.g. private key, hw wallet, keystore) is set when `forge broadcast` is invoked, that signer is used.\\n3. Otherwise, default foundry sender (1804c8AB1F12E6bbf3894d4083f33e07309d1f38) is used.\",\n        \"declaration\": \"function startBroadcast() external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"startBroadcast()\",\n        \"selector\": \"0x7fb5297f\",\n        \"selectorBytes\": [\n          127,\n          181,\n          41,\n          127\n        ]\n      },\n      \"group\": \"scripting\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"startBroadcast_1\",\n        \"description\": \"Has all subsequent calls (at this call depth only) create transactions with the address\\nprovided that can later be signed and sent onchain.\",\n        \"declaration\": \"function startBroadcast(address signer) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"startBroadcast(address)\",\n        \"selector\": \"0x7fec2a8d\",\n        \"selectorBytes\": [\n          127,\n          236,\n          42,\n          141\n        ]\n      },\n      \"group\": \"scripting\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"startBroadcast_2\",\n        \"description\": \"Has all subsequent calls (at this call depth only) create transactions with the private key\\nprovided that can later be signed and sent onchain.\",\n        \"declaration\": \"function startBroadcast(uint256 privateKey) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"startBroadcast(uint256)\",\n        \"selector\": \"0xce817d47\",\n        \"selectorBytes\": [\n          206,\n          129,\n          125,\n          71\n        ]\n      },\n      \"group\": \"scripting\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"startDebugTraceRecording\",\n        \"description\": \"Records the debug trace during the run.\",\n        \"declaration\": \"function startDebugTraceRecording() external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"startDebugTraceRecording()\",\n        \"selector\": \"0x419c8832\",\n        \"selectorBytes\": [\n          65,\n          156,\n          136,\n          50\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"startMappingRecording\",\n        \"description\": \"Starts recording all map SSTOREs for later retrieval.\",\n        \"declaration\": \"function startMappingRecording() external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"startMappingRecording()\",\n        \"selector\": \"0x3e9705c0\",\n        \"selectorBytes\": [\n          62,\n          151,\n          5,\n          192\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"startPrank_0\",\n        \"description\": \"Sets all subsequent calls' `msg.sender` to be the input address until `stopPrank` is called.\",\n        \"declaration\": \"function startPrank(address msgSender) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"startPrank(address)\",\n        \"selector\": \"0x06447d56\",\n        \"selectorBytes\": [\n          6,\n          68,\n          125,\n          86\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"startPrank_1\",\n        \"description\": \"Sets all subsequent calls' `msg.sender` to be the input address until `stopPrank` is called, and the `tx.origin` to be the second input.\",\n        \"declaration\": \"function startPrank(address msgSender, address txOrigin) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"startPrank(address,address)\",\n        \"selector\": \"0x45b56078\",\n        \"selectorBytes\": [\n          69,\n          181,\n          96,\n          120\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"startPrank_2\",\n        \"description\": \"Sets all subsequent delegate calls' `msg.sender` to be the input address until `stopPrank` is called.\",\n        \"declaration\": \"function startPrank(address msgSender, bool delegateCall) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"startPrank(address,bool)\",\n        \"selector\": \"0x1cc0b435\",\n        \"selectorBytes\": [\n          28,\n          192,\n          180,\n          53\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"startPrank_3\",\n        \"description\": \"Sets all subsequent delegate calls' `msg.sender` to be the input address until `stopPrank` is called, and the `tx.origin` to be the second input.\",\n        \"declaration\": \"function startPrank(address msgSender, address txOrigin, bool delegateCall) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"startPrank(address,address,bool)\",\n        \"selector\": \"0x4eb859b5\",\n        \"selectorBytes\": [\n          78,\n          184,\n          89,\n          181\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"startSnapshotGas_0\",\n        \"description\": \"Start a snapshot capture of the current gas usage by name.\\nThe group name is derived from the contract name.\",\n        \"declaration\": \"function startSnapshotGas(string calldata name) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"startSnapshotGas(string)\",\n        \"selector\": \"0x3cad9d7b\",\n        \"selectorBytes\": [\n          60,\n          173,\n          157,\n          123\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"startSnapshotGas_1\",\n        \"description\": \"Start a snapshot capture of the current gas usage by name in a group.\",\n        \"declaration\": \"function startSnapshotGas(string calldata group, string calldata name) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"startSnapshotGas(string,string)\",\n        \"selector\": \"0x6cd0cc53\",\n        \"selectorBytes\": [\n          108,\n          208,\n          204,\n          83\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"startStateDiffRecording\",\n        \"description\": \"Record all account accesses as part of CREATE, CALL or SELFDESTRUCT opcodes in order,\\nalong with the context of the calls\",\n        \"declaration\": \"function startStateDiffRecording() external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"startStateDiffRecording()\",\n        \"selector\": \"0xcf22e3c9\",\n        \"selectorBytes\": [\n          207,\n          34,\n          227,\n          201\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"stopAndReturnDebugTraceRecording\",\n        \"description\": \"Stop debug trace recording and returns the recorded debug trace.\",\n        \"declaration\": \"function stopAndReturnDebugTraceRecording() external returns (DebugStep[] memory step);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"stopAndReturnDebugTraceRecording()\",\n        \"selector\": \"0xced398a2\",\n        \"selectorBytes\": [\n          206,\n          211,\n          152,\n          162\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"stopAndReturnStateDiff\",\n        \"description\": \"Returns an ordered array of all account accesses from a `vm.startStateDiffRecording` session.\",\n        \"declaration\": \"function stopAndReturnStateDiff() external returns (AccountAccess[] memory accountAccesses);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"stopAndReturnStateDiff()\",\n        \"selector\": \"0xaa5cf90e\",\n        \"selectorBytes\": [\n          170,\n          92,\n          249,\n          14\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"stopBroadcast\",\n        \"description\": \"Stops collecting onchain transactions.\",\n        \"declaration\": \"function stopBroadcast() external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"stopBroadcast()\",\n        \"selector\": \"0x76eadd36\",\n        \"selectorBytes\": [\n          118,\n          234,\n          221,\n          54\n        ]\n      },\n      \"group\": \"scripting\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"stopExpectSafeMemory\",\n        \"description\": \"Stops all safe memory expectation in the current subcontext.\",\n        \"declaration\": \"function stopExpectSafeMemory() external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"stopExpectSafeMemory()\",\n        \"selector\": \"0x0956441b\",\n        \"selectorBytes\": [\n          9,\n          86,\n          68,\n          27\n        ]\n      },\n      \"group\": \"testing\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"stopMappingRecording\",\n        \"description\": \"Stops recording all map SSTOREs for later retrieval and clears the recorded data.\",\n        \"declaration\": \"function stopMappingRecording() external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"stopMappingRecording()\",\n        \"selector\": \"0x0d4aae9b\",\n        \"selectorBytes\": [\n          13,\n          74,\n          174,\n          155\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"stopPrank\",\n        \"description\": \"Resets subsequent calls' `msg.sender` to be `address(this)`.\",\n        \"declaration\": \"function stopPrank() external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"stopPrank()\",\n        \"selector\": \"0x90c5013b\",\n        \"selectorBytes\": [\n          144,\n          197,\n          1,\n          59\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"stopRecord\",\n        \"description\": \"Stops recording storage reads and writes.\",\n        \"declaration\": \"function stopRecord() external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"stopRecord()\",\n        \"selector\": \"0x996be76d\",\n        \"selectorBytes\": [\n          153,\n          107,\n          231,\n          109\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"stopSnapshotGas_0\",\n        \"description\": \"Stop the snapshot capture of the current gas by latest snapshot name, capturing the gas used since the start.\",\n        \"declaration\": \"function stopSnapshotGas() external returns (uint256 gasUsed);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"stopSnapshotGas()\",\n        \"selector\": \"0xf6402eda\",\n        \"selectorBytes\": [\n          246,\n          64,\n          46,\n          218\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"stopSnapshotGas_1\",\n        \"description\": \"Stop the snapshot capture of the current gas usage by name, capturing the gas used since the start.\\nThe group name is derived from the contract name.\",\n        \"declaration\": \"function stopSnapshotGas(string calldata name) external returns (uint256 gasUsed);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"stopSnapshotGas(string)\",\n        \"selector\": \"0x773b2805\",\n        \"selectorBytes\": [\n          119,\n          59,\n          40,\n          5\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"stopSnapshotGas_2\",\n        \"description\": \"Stop the snapshot capture of the current gas usage by name in a group, capturing the gas used since the start.\",\n        \"declaration\": \"function stopSnapshotGas(string calldata group, string calldata name) external returns (uint256 gasUsed);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"stopSnapshotGas(string,string)\",\n        \"selector\": \"0x0c9db707\",\n        \"selectorBytes\": [\n          12,\n          157,\n          183,\n          7\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"store\",\n        \"description\": \"Stores a value to an address' storage slot.\",\n        \"declaration\": \"function store(address target, bytes32 slot, bytes32 value) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"store(address,bytes32,bytes32)\",\n        \"selector\": \"0x70ca10bb\",\n        \"selectorBytes\": [\n          112,\n          202,\n          16,\n          187\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"toBase64URL_0\",\n        \"description\": \"Encodes a `bytes` value to a base64url string.\",\n        \"declaration\": \"function toBase64URL(bytes calldata data) external pure returns (string memory);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"toBase64URL(bytes)\",\n        \"selector\": \"0xc8bd0e4a\",\n        \"selectorBytes\": [\n          200,\n          189,\n          14,\n          74\n        ]\n      },\n      \"group\": \"utilities\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"toBase64URL_1\",\n        \"description\": \"Encodes a `string` value to a base64url string.\",\n        \"declaration\": \"function toBase64URL(string calldata data) external pure returns (string memory);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"toBase64URL(string)\",\n        \"selector\": \"0xae3165b3\",\n        \"selectorBytes\": [\n          174,\n          49,\n          101,\n          179\n        ]\n      },\n      \"group\": \"utilities\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"toBase64_0\",\n        \"description\": \"Encodes a `bytes` value to a base64 string.\",\n        \"declaration\": \"function toBase64(bytes calldata data) external pure returns (string memory);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"toBase64(bytes)\",\n        \"selector\": \"0xa5cbfe65\",\n        \"selectorBytes\": [\n          165,\n          203,\n          254,\n          101\n        ]\n      },\n      \"group\": \"utilities\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"toBase64_1\",\n        \"description\": \"Encodes a `string` value to a base64 string.\",\n        \"declaration\": \"function toBase64(string calldata data) external pure returns (string memory);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"toBase64(string)\",\n        \"selector\": \"0x3f8be2c8\",\n        \"selectorBytes\": [\n          63,\n          139,\n          226,\n          200\n        ]\n      },\n      \"group\": \"utilities\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"toLowercase\",\n        \"description\": \"Converts the given `string` value to Lowercase.\",\n        \"declaration\": \"function toLowercase(string calldata input) external pure returns (string memory output);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"toLowercase(string)\",\n        \"selector\": \"0x50bb0884\",\n        \"selectorBytes\": [\n          80,\n          187,\n          8,\n          132\n        ]\n      },\n      \"group\": \"string\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"toRlp\",\n        \"description\": \"RLP encodes a list of bytes into an RLP payload.\",\n        \"declaration\": \"function toRlp(bytes[] calldata data) external pure returns (bytes memory);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"toRlp(bytes[])\",\n        \"selector\": \"0xa7ed3885\",\n        \"selectorBytes\": [\n          167,\n          237,\n          56,\n          133\n        ]\n      },\n      \"group\": \"utilities\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"toString_0\",\n        \"description\": \"Converts the given value to a `string`.\",\n        \"declaration\": \"function toString(address value) external pure returns (string memory stringifiedValue);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"toString(address)\",\n        \"selector\": \"0x56ca623e\",\n        \"selectorBytes\": [\n          86,\n          202,\n          98,\n          62\n        ]\n      },\n      \"group\": \"string\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"toString_1\",\n        \"description\": \"Converts the given value to a `string`.\",\n        \"declaration\": \"function toString(bytes calldata value) external pure returns (string memory stringifiedValue);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"toString(bytes)\",\n        \"selector\": \"0x71aad10d\",\n        \"selectorBytes\": [\n          113,\n          170,\n          209,\n          13\n        ]\n      },\n      \"group\": \"string\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"toString_2\",\n        \"description\": \"Converts the given value to a `string`.\",\n        \"declaration\": \"function toString(bytes32 value) external pure returns (string memory stringifiedValue);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"toString(bytes32)\",\n        \"selector\": \"0xb11a19e8\",\n        \"selectorBytes\": [\n          177,\n          26,\n          25,\n          232\n        ]\n      },\n      \"group\": \"string\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"toString_3\",\n        \"description\": \"Converts the given value to a `string`.\",\n        \"declaration\": \"function toString(bool value) external pure returns (string memory stringifiedValue);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"toString(bool)\",\n        \"selector\": \"0x71dce7da\",\n        \"selectorBytes\": [\n          113,\n          220,\n          231,\n          218\n        ]\n      },\n      \"group\": \"string\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"toString_4\",\n        \"description\": \"Converts the given value to a `string`.\",\n        \"declaration\": \"function toString(uint256 value) external pure returns (string memory stringifiedValue);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"toString(uint256)\",\n        \"selector\": \"0x6900a3ae\",\n        \"selectorBytes\": [\n          105,\n          0,\n          163,\n          174\n        ]\n      },\n      \"group\": \"string\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"toString_5\",\n        \"description\": \"Converts the given value to a `string`.\",\n        \"declaration\": \"function toString(int256 value) external pure returns (string memory stringifiedValue);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"toString(int256)\",\n        \"selector\": \"0xa322c40e\",\n        \"selectorBytes\": [\n          163,\n          34,\n          196,\n          14\n        ]\n      },\n      \"group\": \"string\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"toUppercase\",\n        \"description\": \"Converts the given `string` value to Uppercase.\",\n        \"declaration\": \"function toUppercase(string calldata input) external pure returns (string memory output);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"toUppercase(string)\",\n        \"selector\": \"0x074ae3d7\",\n        \"selectorBytes\": [\n          7,\n          74,\n          227,\n          215\n        ]\n      },\n      \"group\": \"string\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"transact_0\",\n        \"description\": \"Fetches the given transaction from the active fork and executes it on the current state.\",\n        \"declaration\": \"function transact(bytes32 txHash) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"transact(bytes32)\",\n        \"selector\": \"0xbe646da1\",\n        \"selectorBytes\": [\n          190,\n          100,\n          109,\n          161\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"transact_1\",\n        \"description\": \"Fetches the given transaction from the given fork and executes it on the current state.\",\n        \"declaration\": \"function transact(uint256 forkId, bytes32 txHash) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"transact(uint256,bytes32)\",\n        \"selector\": \"0x4d8abc4b\",\n        \"selectorBytes\": [\n          77,\n          138,\n          188,\n          75\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"trim\",\n        \"description\": \"Trims leading and trailing whitespace from the given `string` value.\",\n        \"declaration\": \"function trim(string calldata input) external pure returns (string memory output);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"trim(string)\",\n        \"selector\": \"0xb2dad155\",\n        \"selectorBytes\": [\n          178,\n          218,\n          209,\n          85\n        ]\n      },\n      \"group\": \"string\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"tryFfi\",\n        \"description\": \"Performs a foreign function call via terminal and returns the exit code, stdout, and stderr.\",\n        \"declaration\": \"function tryFfi(string[] calldata commandInput) external returns (FfiResult memory result);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"tryFfi(string[])\",\n        \"selector\": \"0xf45c1ce7\",\n        \"selectorBytes\": [\n          244,\n          92,\n          28,\n          231\n        ]\n      },\n      \"group\": \"filesystem\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"txGasPrice\",\n        \"description\": \"Sets `tx.gasprice`.\",\n        \"declaration\": \"function txGasPrice(uint256 newGasPrice) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"txGasPrice(uint256)\",\n        \"selector\": \"0x48f50c0f\",\n        \"selectorBytes\": [\n          72,\n          245,\n          12,\n          15\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"unixTime\",\n        \"description\": \"Returns the time since unix epoch in milliseconds.\",\n        \"declaration\": \"function unixTime() external view returns (uint256 milliseconds);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"view\",\n        \"signature\": \"unixTime()\",\n        \"selector\": \"0x625387dc\",\n        \"selectorBytes\": [\n          98,\n          83,\n          135,\n          220\n        ]\n      },\n      \"group\": \"filesystem\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"verifyEd25519\",\n        \"description\": \"Verifies an Ed25519 signature over namespace || message.\\nReturns true if signature is valid, false otherwise.\",\n        \"declaration\": \"function verifyEd25519(bytes calldata signature, bytes calldata namespace, bytes calldata message, bytes32 publicKey) external pure returns (bool valid);\",\n        \"visibility\": \"external\",\n        \"mutability\": \"pure\",\n        \"signature\": \"verifyEd25519(bytes,bytes,bytes,bytes32)\",\n        \"selector\": \"0xd08c2888\",\n        \"selectorBytes\": [\n          208,\n          140,\n          40,\n          136\n        ]\n      },\n      \"group\": \"crypto\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"warmSlot\",\n        \"description\": \"Utility cheatcode to mark specific storage slot as warm, simulating a prior read.\",\n        \"declaration\": \"function warmSlot(address target, bytes32 slot) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"warmSlot(address,bytes32)\",\n        \"selector\": \"0xb23184cf\",\n        \"selectorBytes\": [\n          178,\n          49,\n          132,\n          207\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"warp\",\n        \"description\": \"Sets `block.timestamp`.\",\n        \"declaration\": \"function warp(uint256 newTimestamp) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"warp(uint256)\",\n        \"selector\": \"0xe5d6bf02\",\n        \"selectorBytes\": [\n          229,\n          214,\n          191,\n          2\n        ]\n      },\n      \"group\": \"evm\",\n      \"status\": \"stable\",\n      \"safety\": \"unsafe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"writeFile\",\n        \"description\": \"Writes data to file, creating a file if it does not exist, and entirely replacing its contents if it does.\\n`path` is relative to the project root.\",\n        \"declaration\": \"function writeFile(string calldata path, string calldata data) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"writeFile(string,string)\",\n        \"selector\": \"0x897e0a97\",\n        \"selectorBytes\": [\n          137,\n          126,\n          10,\n          151\n        ]\n      },\n      \"group\": \"filesystem\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"writeFileBinary\",\n        \"description\": \"Writes binary data to a file, creating a file if it does not exist, and entirely replacing its contents if it does.\\n`path` is relative to the project root.\",\n        \"declaration\": \"function writeFileBinary(string calldata path, bytes calldata data) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"writeFileBinary(string,bytes)\",\n        \"selector\": \"0x1f21fc80\",\n        \"selectorBytes\": [\n          31,\n          33,\n          252,\n          128\n        ]\n      },\n      \"group\": \"filesystem\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"writeJson_0\",\n        \"description\": \"Write a serialized JSON object to a file. If the file exists, it will be overwritten.\",\n        \"declaration\": \"function writeJson(string calldata json, string calldata path) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"writeJson(string,string)\",\n        \"selector\": \"0xe23cd19f\",\n        \"selectorBytes\": [\n          226,\n          60,\n          209,\n          159\n        ]\n      },\n      \"group\": \"json\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"writeJson_1\",\n        \"description\": \"Write a serialized JSON object to an **existing** JSON file, replacing a value with key = <value_key.>\\nThis is useful to replace a specific value of a JSON file, without having to parse the entire thing.\\nThis cheatcode will create new keys if they didn't previously exist.\",\n        \"declaration\": \"function writeJson(string calldata json, string calldata path, string calldata valueKey) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"writeJson(string,string,string)\",\n        \"selector\": \"0x35d6ad46\",\n        \"selectorBytes\": [\n          53,\n          214,\n          173,\n          70\n        ]\n      },\n      \"group\": \"json\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"writeLine\",\n        \"description\": \"Writes line to file, creating a file if it does not exist.\\n`path` is relative to the project root.\",\n        \"declaration\": \"function writeLine(string calldata path, string calldata data) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"writeLine(string,string)\",\n        \"selector\": \"0x619d897f\",\n        \"selectorBytes\": [\n          97,\n          157,\n          137,\n          127\n        ]\n      },\n      \"group\": \"filesystem\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"writeToml_0\",\n        \"description\": \"Takes serialized JSON, converts to TOML and write a serialized TOML to a file.\",\n        \"declaration\": \"function writeToml(string calldata json, string calldata path) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"writeToml(string,string)\",\n        \"selector\": \"0xc0865ba7\",\n        \"selectorBytes\": [\n          192,\n          134,\n          91,\n          167\n        ]\n      },\n      \"group\": \"toml\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    },\n    {\n      \"func\": {\n        \"id\": \"writeToml_1\",\n        \"description\": \"Takes serialized JSON, converts to TOML and write a serialized TOML table to an **existing** TOML file, replacing a value with key = <value_key.>\\nThis is useful to replace a specific value of a TOML file, without having to parse the entire thing.\\nThis cheatcode will create new keys if they didn't previously exist.\",\n        \"declaration\": \"function writeToml(string calldata json, string calldata path, string calldata valueKey) external;\",\n        \"visibility\": \"external\",\n        \"mutability\": \"\",\n        \"signature\": \"writeToml(string,string,string)\",\n        \"selector\": \"0x51ac6a33\",\n        \"selectorBytes\": [\n          81,\n          172,\n          106,\n          51\n        ]\n      },\n      \"group\": \"toml\",\n      \"status\": \"stable\",\n      \"safety\": \"safe\"\n    }\n  ]\n}"
  },
  {
    "path": "crates/cheatcodes/assets/cheatcodes.schema.json",
    "content": "{\n  \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\n  \"title\": \"Cheatcodes\",\n  \"description\": \"Foundry cheatcodes. Learn more: <https://book.getfoundry.sh/cheatcodes/>\",\n  \"type\": \"object\",\n  \"properties\": {\n    \"cheatcodes\": {\n      \"description\": \"All the cheatcodes.\",\n      \"type\": \"array\",\n      \"items\": {\n        \"$ref\": \"#/$defs/Cheatcode\"\n      }\n    },\n    \"enums\": {\n      \"description\": \"Cheatcode enums.\",\n      \"type\": \"array\",\n      \"items\": {\n        \"$ref\": \"#/$defs/Enum\"\n      }\n    },\n    \"errors\": {\n      \"description\": \"Cheatcode errors.\",\n      \"type\": \"array\",\n      \"items\": {\n        \"$ref\": \"#/$defs/Error\"\n      }\n    },\n    \"events\": {\n      \"description\": \"Cheatcode events.\",\n      \"type\": \"array\",\n      \"items\": {\n        \"$ref\": \"#/$defs/Event\"\n      }\n    },\n    \"structs\": {\n      \"description\": \"Cheatcode structs.\",\n      \"type\": \"array\",\n      \"items\": {\n        \"$ref\": \"#/$defs/Struct\"\n      }\n    }\n  },\n  \"required\": [\n    \"errors\",\n    \"events\",\n    \"enums\",\n    \"structs\",\n    \"cheatcodes\"\n  ],\n  \"$defs\": {\n    \"Cheatcode\": {\n      \"description\": \"Specification of a single cheatcode. Extends [`Function`] with additional metadata.\",\n      \"type\": \"object\",\n      \"properties\": {\n        \"func\": {\n          \"description\": \"The Solidity function declaration.\",\n          \"$ref\": \"#/$defs/Function\"\n        },\n        \"group\": {\n          \"description\": \"The group that the cheatcode belongs to.\",\n          \"$ref\": \"#/$defs/Group\"\n        },\n        \"safety\": {\n          \"description\": \"Whether the cheatcode is safe to use inside of scripts. E.g. it does not change state in an\\nunexpected way.\",\n          \"$ref\": \"#/$defs/Safety\"\n        },\n        \"status\": {\n          \"description\": \"The current status of the cheatcode. E.g. whether it is stable or experimental, etc.\",\n          \"$ref\": \"#/$defs/Status\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"required\": [\n        \"func\",\n        \"group\",\n        \"status\",\n        \"safety\"\n      ]\n    },\n    \"Enum\": {\n      \"description\": \"A Solidity enumeration.\",\n      \"type\": \"object\",\n      \"properties\": {\n        \"description\": {\n          \"description\": \"The description of the enum.\\nThis is a markdown string derived from the NatSpec documentation.\",\n          \"type\": \"string\"\n        },\n        \"name\": {\n          \"description\": \"The name of the enum.\",\n          \"type\": \"string\"\n        },\n        \"variants\": {\n          \"description\": \"The variants of the enum.\",\n          \"type\": \"array\",\n          \"items\": {\n            \"$ref\": \"#/$defs/EnumVariant\"\n          }\n        }\n      },\n      \"required\": [\n        \"name\",\n        \"description\",\n        \"variants\"\n      ]\n    },\n    \"EnumVariant\": {\n      \"description\": \"A variant of an [`Enum`].\",\n      \"type\": \"object\",\n      \"properties\": {\n        \"description\": {\n          \"description\": \"The description of the variant.\\nThis is a markdown string derived from the NatSpec documentation.\",\n          \"type\": \"string\"\n        },\n        \"name\": {\n          \"description\": \"The name of the variant.\",\n          \"type\": \"string\"\n        }\n      },\n      \"required\": [\n        \"name\",\n        \"description\"\n      ]\n    },\n    \"Error\": {\n      \"description\": \"A Solidity custom error.\",\n      \"type\": \"object\",\n      \"properties\": {\n        \"declaration\": {\n          \"description\": \"The Solidity error declaration, including full type, parameter names, etc.\",\n          \"type\": \"string\"\n        },\n        \"description\": {\n          \"description\": \"The description of the error.\\nThis is a markdown string derived from the NatSpec documentation.\",\n          \"type\": \"string\"\n        },\n        \"name\": {\n          \"description\": \"The name of the error.\",\n          \"type\": \"string\"\n        }\n      },\n      \"required\": [\n        \"name\",\n        \"description\",\n        \"declaration\"\n      ]\n    },\n    \"Event\": {\n      \"description\": \"A Solidity event.\",\n      \"type\": \"object\",\n      \"properties\": {\n        \"declaration\": {\n          \"description\": \"The Solidity event declaration, including full type, parameter names, etc.\",\n          \"type\": \"string\"\n        },\n        \"description\": {\n          \"description\": \"The description of the event.\\nThis is a markdown string derived from the NatSpec documentation.\",\n          \"type\": \"string\"\n        },\n        \"name\": {\n          \"description\": \"The name of the event.\",\n          \"type\": \"string\"\n        }\n      },\n      \"required\": [\n        \"name\",\n        \"description\",\n        \"declaration\"\n      ]\n    },\n    \"Function\": {\n      \"description\": \"Solidity function.\",\n      \"type\": \"object\",\n      \"properties\": {\n        \"declaration\": {\n          \"description\": \"The Solidity function declaration, including full type and parameter names, visibility,\\netc.\",\n          \"type\": \"string\"\n        },\n        \"description\": {\n          \"description\": \"The description of the function.\\nThis is a markdown string derived from the NatSpec documentation.\",\n          \"type\": \"string\"\n        },\n        \"id\": {\n          \"description\": \"The function's unique identifier. This is the function name, optionally appended with an\\nindex if it is overloaded.\",\n          \"type\": \"string\"\n        },\n        \"mutability\": {\n          \"description\": \"The Solidity function state mutability attribute.\",\n          \"$ref\": \"#/$defs/Mutability\"\n        },\n        \"selector\": {\n          \"description\": \"The hex-encoded, \\\"0x\\\"-prefixed 4-byte function selector,\\nwhich is the Keccak-256 hash of `signature`.\",\n          \"type\": \"string\"\n        },\n        \"selectorBytes\": {\n          \"description\": \"The 4-byte function selector as a byte array.\",\n          \"type\": \"array\",\n          \"items\": {\n            \"type\": \"integer\",\n            \"format\": \"uint8\",\n            \"maximum\": 255,\n            \"minimum\": 0\n          },\n          \"maxItems\": 4,\n          \"minItems\": 4\n        },\n        \"signature\": {\n          \"description\": \"The standard function signature used to calculate `selector`.\\nSee the [Solidity docs] for more information.\\n\\n[Solidity docs]: https://docs.soliditylang.org/en/latest/abi-spec.html#function-selector\",\n          \"type\": \"string\"\n        },\n        \"visibility\": {\n          \"description\": \"The Solidity function visibility attribute. This is currently always `external`, but this\\nmay change in the future.\",\n          \"$ref\": \"#/$defs/Visibility\"\n        }\n      },\n      \"required\": [\n        \"id\",\n        \"description\",\n        \"declaration\",\n        \"visibility\",\n        \"mutability\",\n        \"signature\",\n        \"selector\",\n        \"selectorBytes\"\n      ]\n    },\n    \"Group\": {\n      \"description\": \"Cheatcode groups.\\nInitially derived and modified from inline comments in [`forge-std`'s `Vm.sol`][vmsol].\\n\\n[vmsol]: https://github.com/foundry-rs/forge-std/blob/dcb0d52bc4399d37a6545848e3b8f9d03c77b98d/src/Vm.sol\",\n      \"oneOf\": [\n        {\n          \"description\": \"Cheatcodes that read from, or write to the current EVM execution state.\\n\\nExamples: any of the `record` cheatcodes, `chainId`, `coinbase`.\\n\\nSafety: ambiguous, depends on whether the cheatcode is read-only or not.\",\n          \"type\": \"string\",\n          \"const\": \"evm\"\n        },\n        {\n          \"description\": \"Cheatcodes that interact with how a test is run.\\n\\nExamples: `assume`, `skip`, `expectRevert`.\\n\\nSafety: ambiguous, depends on whether the cheatcode is read-only or not.\",\n          \"type\": \"string\",\n          \"const\": \"testing\"\n        },\n        {\n          \"description\": \"Cheatcodes that interact with how a script is run.\\n\\nExamples: `broadcast`, `startBroadcast`, `stopBroadcast`.\\n\\nSafety: safe.\",\n          \"type\": \"string\",\n          \"const\": \"scripting\"\n        },\n        {\n          \"description\": \"Cheatcodes that interact with the OS or filesystem.\\n\\nExamples: `ffi`, `projectRoot`, `writeFile`.\\n\\nSafety: safe.\",\n          \"type\": \"string\",\n          \"const\": \"filesystem\"\n        },\n        {\n          \"description\": \"Cheatcodes that interact with the program's environment variables.\\n\\nExamples: `setEnv`, `envBool`, `envOr`.\\n\\nSafety: safe.\",\n          \"type\": \"string\",\n          \"const\": \"environment\"\n        },\n        {\n          \"description\": \"Utility cheatcodes that deal with string parsing and manipulation.\\n\\nExamples: `toString`. `parseBytes`.\\n\\nSafety: safe.\",\n          \"type\": \"string\",\n          \"const\": \"string\"\n        },\n        {\n          \"description\": \"Utility cheatcodes that deal with parsing values from and converting values to JSON.\\n\\nExamples: `serializeJson`, `parseJsonUint`, `writeJson`.\\n\\nSafety: safe.\",\n          \"type\": \"string\",\n          \"const\": \"json\"\n        },\n        {\n          \"description\": \"Utility cheatcodes that deal with parsing values from and converting values to TOML.\\n\\nExamples: `parseToml`, `writeToml`.\\n\\nSafety: safe.\",\n          \"type\": \"string\",\n          \"const\": \"toml\"\n        },\n        {\n          \"description\": \"Cryptography-related cheatcodes.\\n\\nExamples: `sign*`.\\n\\nSafety: safe.\",\n          \"type\": \"string\",\n          \"const\": \"crypto\"\n        },\n        {\n          \"description\": \"Generic, uncategorized utilities.\\n\\nExamples: `toString`, `parse*`, `serialize*`.\\n\\nSafety: safe.\",\n          \"type\": \"string\",\n          \"const\": \"utilities\"\n        }\n      ]\n    },\n    \"Mutability\": {\n      \"description\": \"Solidity function state mutability attribute. See the [Solidity docs] for more information.\\n\\n[Solidity docs]: https://docs.soliditylang.org/en/latest/contracts.html#state-mutability\",\n      \"oneOf\": [\n        {\n          \"description\": \"Disallows modification or access of state.\",\n          \"type\": \"string\",\n          \"const\": \"pure\"\n        },\n        {\n          \"description\": \"Disallows modification of state.\",\n          \"type\": \"string\",\n          \"const\": \"view\"\n        },\n        {\n          \"description\": \"Allows modification of state.\",\n          \"type\": \"string\",\n          \"const\": \"\"\n        }\n      ]\n    },\n    \"Safety\": {\n      \"description\": \"Cheatcode safety.\",\n      \"oneOf\": [\n        {\n          \"description\": \"The cheatcode is not safe to use in scripts.\",\n          \"type\": \"string\",\n          \"const\": \"unsafe\"\n        },\n        {\n          \"description\": \"The cheatcode is safe to use in scripts.\",\n          \"type\": \"string\",\n          \"const\": \"safe\"\n        }\n      ]\n    },\n    \"Status\": {\n      \"description\": \"The status of a cheatcode.\",\n      \"oneOf\": [\n        {\n          \"description\": \"The cheatcode and its API is currently stable.\",\n          \"type\": \"string\",\n          \"const\": \"stable\"\n        },\n        {\n          \"description\": \"The cheatcode is unstable, meaning it may contain bugs and may break its API on any\\nrelease.\\n\\nUse of experimental cheatcodes will result in a warning.\",\n          \"type\": \"string\",\n          \"const\": \"experimental\"\n        },\n        {\n          \"description\": \"The cheatcode has been deprecated, meaning it will be removed in a future release.\\n\\nContains the optional reason for deprecation.\\n\\nUse of deprecated cheatcodes is discouraged and will result in a warning.\",\n          \"type\": \"object\",\n          \"properties\": {\n            \"deprecated\": {\n              \"type\": [\n                \"string\",\n                \"null\"\n              ]\n            }\n          },\n          \"additionalProperties\": false,\n          \"required\": [\n            \"deprecated\"\n          ]\n        },\n        {\n          \"description\": \"The cheatcode has been removed and is no longer available for use.\\n\\nUse of removed cheatcodes will result in a hard error.\",\n          \"type\": \"string\",\n          \"const\": \"removed\"\n        },\n        {\n          \"description\": \"The cheatcode is only used internally for foundry testing and may be changed or removed at\\nany time.\\n\\nUse of internal cheatcodes is discouraged and will result in a warning.\",\n          \"type\": \"string\",\n          \"const\": \"internal\"\n        }\n      ]\n    },\n    \"Struct\": {\n      \"description\": \"A Solidity struct.\",\n      \"type\": \"object\",\n      \"properties\": {\n        \"description\": {\n          \"description\": \"The description of the struct.\\nThis is a markdown string derived from the NatSpec documentation.\",\n          \"type\": \"string\"\n        },\n        \"fields\": {\n          \"description\": \"The fields of the struct.\",\n          \"type\": \"array\",\n          \"items\": {\n            \"$ref\": \"#/$defs/StructField\"\n          }\n        },\n        \"name\": {\n          \"description\": \"The name of the struct.\",\n          \"type\": \"string\"\n        }\n      },\n      \"required\": [\n        \"name\",\n        \"description\",\n        \"fields\"\n      ]\n    },\n    \"StructField\": {\n      \"description\": \"A [`Struct`] field.\",\n      \"type\": \"object\",\n      \"properties\": {\n        \"description\": {\n          \"description\": \"The description of the field.\\nThis is a markdown string derived from the NatSpec documentation.\",\n          \"type\": \"string\"\n        },\n        \"name\": {\n          \"description\": \"The name of the field.\",\n          \"type\": \"string\"\n        },\n        \"ty\": {\n          \"description\": \"The type of the field.\",\n          \"type\": \"string\"\n        }\n      },\n      \"required\": [\n        \"name\",\n        \"ty\",\n        \"description\"\n      ]\n    },\n    \"Visibility\": {\n      \"description\": \"Solidity function visibility attribute. See the [Solidity docs] for more information.\\n\\n[Solidity docs]: https://docs.soliditylang.org/en/latest/contracts.html#function-visibility\",\n      \"oneOf\": [\n        {\n          \"description\": \"The function is only visible externally.\",\n          \"type\": \"string\",\n          \"const\": \"external\"\n        },\n        {\n          \"description\": \"Visible externally and internally.\",\n          \"type\": \"string\",\n          \"const\": \"public\"\n        },\n        {\n          \"description\": \"Only visible internally.\",\n          \"type\": \"string\",\n          \"const\": \"internal\"\n        },\n        {\n          \"description\": \"Only visible in the current contract\",\n          \"type\": \"string\",\n          \"const\": \"private\"\n        }\n      ]\n    }\n  }\n}"
  },
  {
    "path": "crates/cheatcodes/spec/Cargo.toml",
    "content": "[package]\nname = \"foundry-cheatcodes-spec\"\ndescription = \"Foundry cheatcodes specification\"\n\nversion.workspace = true\nedition.workspace = true\nrust-version.workspace = true\nauthors.workspace = true\nlicense.workspace = true\nhomepage.workspace = true\nrepository.workspace = true\nexclude.workspace = true\n\n[lints]\nworkspace = true\n\n[dependencies]\nfoundry-macros.workspace = true\nalloy-sol-types = { workspace = true, features = [\"json\"] }\nserde.workspace = true\n\n# schema\nschemars = { version = \"1.1\", optional = true }\n\n[dev-dependencies]\nserde_json.workspace = true\n\n[features]\nschema = [\"dep:schemars\"]\n"
  },
  {
    "path": "crates/cheatcodes/spec/src/cheatcode.rs",
    "content": "use super::Function;\nuse alloy_sol_types::SolCall;\nuse serde::{Deserialize, Serialize};\n\n/// Cheatcode definition trait. Implemented by all [`Vm`](crate::Vm) functions.\npub trait CheatcodeDef: std::fmt::Debug + Clone + SolCall {\n    /// The static cheatcode definition.\n    const CHEATCODE: &'static Cheatcode<'static>;\n}\n\n/// Specification of a single cheatcode. Extends [`Function`] with additional metadata.\n#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]\n#[cfg_attr(feature = \"schema\", derive(schemars::JsonSchema))]\n#[serde(deny_unknown_fields, rename_all = \"camelCase\")]\n#[non_exhaustive]\npub struct Cheatcode<'a> {\n    // Automatically-generated fields.\n    /// The Solidity function declaration.\n    #[serde(borrow)]\n    pub func: Function<'a>,\n\n    // Manually-specified fields.\n    /// The group that the cheatcode belongs to.\n    pub group: Group,\n    /// The current status of the cheatcode. E.g. whether it is stable or experimental, etc.\n    pub status: Status<'a>,\n    /// Whether the cheatcode is safe to use inside of scripts. E.g. it does not change state in an\n    /// unexpected way.\n    pub safety: Safety,\n}\n\n/// The status of a cheatcode.\n#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]\n#[cfg_attr(feature = \"schema\", derive(schemars::JsonSchema))]\n#[serde(rename_all = \"camelCase\")]\n#[non_exhaustive]\npub enum Status<'a> {\n    /// The cheatcode and its API is currently stable.\n    Stable,\n    /// The cheatcode is unstable, meaning it may contain bugs and may break its API on any\n    /// release.\n    ///\n    /// Use of experimental cheatcodes will result in a warning.\n    Experimental,\n    /// The cheatcode has been deprecated, meaning it will be removed in a future release.\n    ///\n    /// Contains the optional reason for deprecation.\n    ///\n    /// Use of deprecated cheatcodes is discouraged and will result in a warning.\n    Deprecated(Option<&'a str>),\n    /// The cheatcode has been removed and is no longer available for use.\n    ///\n    /// Use of removed cheatcodes will result in a hard error.\n    Removed,\n    /// The cheatcode is only used internally for foundry testing and may be changed or removed at\n    /// any time.\n    ///\n    /// Use of internal cheatcodes is discouraged and will result in a warning.\n    Internal,\n}\n\n/// Cheatcode groups.\n/// Initially derived and modified from inline comments in [`forge-std`'s `Vm.sol`][vmsol].\n///\n/// [vmsol]: https://github.com/foundry-rs/forge-std/blob/dcb0d52bc4399d37a6545848e3b8f9d03c77b98d/src/Vm.sol\n#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]\n#[cfg_attr(feature = \"schema\", derive(schemars::JsonSchema))]\n#[serde(rename_all = \"camelCase\")]\n#[non_exhaustive]\npub enum Group {\n    /// Cheatcodes that read from, or write to the current EVM execution state.\n    ///\n    /// Examples: any of the `record` cheatcodes, `chainId`, `coinbase`.\n    ///\n    /// Safety: ambiguous, depends on whether the cheatcode is read-only or not.\n    Evm,\n    /// Cheatcodes that interact with how a test is run.\n    ///\n    /// Examples: `assume`, `skip`, `expectRevert`.\n    ///\n    /// Safety: ambiguous, depends on whether the cheatcode is read-only or not.\n    Testing,\n    /// Cheatcodes that interact with how a script is run.\n    ///\n    /// Examples: `broadcast`, `startBroadcast`, `stopBroadcast`.\n    ///\n    /// Safety: safe.\n    Scripting,\n    /// Cheatcodes that interact with the OS or filesystem.\n    ///\n    /// Examples: `ffi`, `projectRoot`, `writeFile`.\n    ///\n    /// Safety: safe.\n    Filesystem,\n    /// Cheatcodes that interact with the program's environment variables.\n    ///\n    /// Examples: `setEnv`, `envBool`, `envOr`.\n    ///\n    /// Safety: safe.\n    Environment,\n    /// Utility cheatcodes that deal with string parsing and manipulation.\n    ///\n    /// Examples: `toString`. `parseBytes`.\n    ///\n    /// Safety: safe.\n    String,\n    /// Utility cheatcodes that deal with parsing values from and converting values to JSON.\n    ///\n    /// Examples: `serializeJson`, `parseJsonUint`, `writeJson`.\n    ///\n    /// Safety: safe.\n    Json,\n    /// Utility cheatcodes that deal with parsing values from and converting values to TOML.\n    ///\n    /// Examples: `parseToml`, `writeToml`.\n    ///\n    /// Safety: safe.\n    Toml,\n    /// Cryptography-related cheatcodes.\n    ///\n    /// Examples: `sign*`.\n    ///\n    /// Safety: safe.\n    Crypto,\n    /// Generic, uncategorized utilities.\n    ///\n    /// Examples: `toString`, `parse*`, `serialize*`.\n    ///\n    /// Safety: safe.\n    Utilities,\n}\n\nimpl Group {\n    /// Returns the safety of this cheatcode group.\n    ///\n    /// Some groups are inherently safe or unsafe, while others are ambiguous and will return\n    /// `None`.\n    pub const fn safety(self) -> Option<Safety> {\n        match self {\n            Self::Evm | Self::Testing => None,\n            Self::Scripting\n            | Self::Filesystem\n            | Self::Environment\n            | Self::String\n            | Self::Json\n            | Self::Toml\n            | Self::Crypto\n            | Self::Utilities => Some(Safety::Safe),\n        }\n    }\n\n    /// Returns this value as a string.\n    pub const fn as_str(self) -> &'static str {\n        match self {\n            Self::Evm => \"evm\",\n            Self::Testing => \"testing\",\n            Self::Scripting => \"scripting\",\n            Self::Filesystem => \"filesystem\",\n            Self::Environment => \"environment\",\n            Self::String => \"string\",\n            Self::Json => \"json\",\n            Self::Toml => \"toml\",\n            Self::Crypto => \"crypto\",\n            Self::Utilities => \"utilities\",\n        }\n    }\n}\n\n// TODO: Find a better name for this\n/// Cheatcode safety.\n#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]\n#[cfg_attr(feature = \"schema\", derive(schemars::JsonSchema))]\n#[serde(rename_all = \"camelCase\")]\n#[non_exhaustive]\npub enum Safety {\n    /// The cheatcode is not safe to use in scripts.\n    Unsafe,\n    /// The cheatcode is safe to use in scripts.\n    #[default]\n    Safe,\n}\n\nimpl Safety {\n    /// Returns this value as a string.\n    pub const fn as_str(self) -> &'static str {\n        match self {\n            Self::Safe => \"safe\",\n            Self::Unsafe => \"unsafe\",\n        }\n    }\n\n    /// Returns whether this value is safe.\n    pub const fn is_safe(self) -> bool {\n        matches!(self, Self::Safe)\n    }\n}\n"
  },
  {
    "path": "crates/cheatcodes/spec/src/function.rs",
    "content": "use serde::{Deserialize, Serialize};\nuse std::fmt;\n\n/// Solidity function.\n#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]\n#[cfg_attr(feature = \"schema\", derive(schemars::JsonSchema))]\n#[serde(rename_all = \"camelCase\")]\n#[non_exhaustive]\npub struct Function<'a> {\n    /// The function's unique identifier. This is the function name, optionally appended with an\n    /// index if it is overloaded.\n    pub id: &'a str,\n    /// The description of the function.\n    /// This is a markdown string derived from the NatSpec documentation.\n    pub description: &'a str,\n    /// The Solidity function declaration, including full type and parameter names, visibility,\n    /// etc.\n    pub declaration: &'a str,\n    /// The Solidity function visibility attribute. This is currently always `external`, but this\n    /// may change in the future.\n    pub visibility: Visibility,\n    /// The Solidity function state mutability attribute.\n    pub mutability: Mutability,\n    /// The standard function signature used to calculate `selector`.\n    /// See the [Solidity docs] for more information.\n    ///\n    /// [Solidity docs]: https://docs.soliditylang.org/en/latest/abi-spec.html#function-selector\n    pub signature: &'a str,\n    /// The hex-encoded, \"0x\"-prefixed 4-byte function selector,\n    /// which is the Keccak-256 hash of `signature`.\n    pub selector: &'a str,\n    /// The 4-byte function selector as a byte array.\n    pub selector_bytes: [u8; 4],\n}\n\nimpl fmt::Display for Function<'_> {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.write_str(self.declaration)\n    }\n}\n\n/// Solidity function visibility attribute. See the [Solidity docs] for more information.\n///\n/// [Solidity docs]: https://docs.soliditylang.org/en/latest/contracts.html#function-visibility\n#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]\n#[cfg_attr(feature = \"schema\", derive(schemars::JsonSchema))]\n#[serde(rename_all = \"camelCase\")]\npub enum Visibility {\n    /// The function is only visible externally.\n    External,\n    /// Visible externally and internally.\n    Public,\n    /// Only visible internally.\n    Internal,\n    /// Only visible in the current contract\n    Private,\n}\n\nimpl fmt::Display for Visibility {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.write_str(self.as_str())\n    }\n}\n\nimpl Visibility {\n    /// Returns the string representation of the visibility.\n    pub const fn as_str(self) -> &'static str {\n        match self {\n            Self::External => \"external\",\n            Self::Public => \"public\",\n            Self::Internal => \"internal\",\n            Self::Private => \"private\",\n        }\n    }\n}\n\n/// Solidity function state mutability attribute. See the [Solidity docs] for more information.\n///\n/// [Solidity docs]: https://docs.soliditylang.org/en/latest/contracts.html#state-mutability\n#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]\n#[cfg_attr(feature = \"schema\", derive(schemars::JsonSchema))]\n#[serde(rename_all = \"camelCase\")]\npub enum Mutability {\n    /// Disallows modification or access of state.\n    Pure,\n    /// Disallows modification of state.\n    View,\n    /// Allows modification of state.\n    #[serde(rename = \"\")]\n    None,\n}\n\nimpl fmt::Display for Mutability {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.write_str(self.as_str())\n    }\n}\n\nimpl Mutability {\n    /// Returns the string representation of the mutability.\n    pub const fn as_str(self) -> &'static str {\n        match self {\n            Self::Pure => \"pure\",\n            Self::View => \"view\",\n            Self::None => \"\",\n        }\n    }\n}\n"
  },
  {
    "path": "crates/cheatcodes/spec/src/items.rs",
    "content": "use serde::{Deserialize, Serialize};\nuse std::{borrow::Cow, fmt};\n\n/// A Solidity custom error.\n#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]\n#[cfg_attr(feature = \"schema\", derive(schemars::JsonSchema))]\n#[serde(rename_all = \"camelCase\")]\npub struct Error<'a> {\n    /// The name of the error.\n    pub name: &'a str,\n    /// The description of the error.\n    /// This is a markdown string derived from the NatSpec documentation.\n    pub description: &'a str,\n    /// The Solidity error declaration, including full type, parameter names, etc.\n    pub declaration: &'a str,\n}\n\nimpl fmt::Display for Error<'_> {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.write_str(self.declaration)\n    }\n}\n\n/// A Solidity event.\n#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]\n#[cfg_attr(feature = \"schema\", derive(schemars::JsonSchema))]\n#[serde(rename_all = \"camelCase\")]\npub struct Event<'a> {\n    /// The name of the event.\n    pub name: &'a str,\n    /// The description of the event.\n    /// This is a markdown string derived from the NatSpec documentation.\n    pub description: &'a str,\n    /// The Solidity event declaration, including full type, parameter names, etc.\n    pub declaration: &'a str,\n}\n\nimpl fmt::Display for Event<'_> {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.write_str(self.declaration)\n    }\n}\n\n/// A Solidity enumeration.\n#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]\n#[cfg_attr(feature = \"schema\", derive(schemars::JsonSchema))]\n#[serde(rename_all = \"camelCase\")]\npub struct Enum<'a> {\n    /// The name of the enum.\n    pub name: &'a str,\n    /// The description of the enum.\n    /// This is a markdown string derived from the NatSpec documentation.\n    pub description: &'a str,\n    /// The variants of the enum.\n    #[serde(borrow)]\n    pub variants: Cow<'a, [EnumVariant<'a>]>,\n}\n\nimpl fmt::Display for Enum<'_> {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        write!(f, \"enum {} {{ \", self.name)?;\n        for (i, variant) in self.variants.iter().enumerate() {\n            if i > 0 {\n                f.write_str(\", \")?;\n            }\n            f.write_str(variant.name)?;\n        }\n        f.write_str(\" }\")\n    }\n}\n\n/// A variant of an [`Enum`].\n#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]\n#[cfg_attr(feature = \"schema\", derive(schemars::JsonSchema))]\n#[serde(rename_all = \"camelCase\")]\npub struct EnumVariant<'a> {\n    /// The name of the variant.\n    pub name: &'a str,\n    /// The description of the variant.\n    /// This is a markdown string derived from the NatSpec documentation.\n    pub description: &'a str,\n}\n\n/// A Solidity struct.\n#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]\n#[cfg_attr(feature = \"schema\", derive(schemars::JsonSchema))]\n#[serde(rename_all = \"camelCase\")]\npub struct Struct<'a> {\n    /// The name of the struct.\n    pub name: &'a str,\n    /// The description of the struct.\n    /// This is a markdown string derived from the NatSpec documentation.\n    pub description: &'a str,\n    /// The fields of the struct.\n    #[serde(borrow)]\n    pub fields: Cow<'a, [StructField<'a>]>,\n}\n\nimpl fmt::Display for Struct<'_> {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        write!(f, \"struct {} {{ \", self.name)?;\n        for field in self.fields.iter() {\n            write!(f, \"{} {}; \", field.ty, field.name)?;\n        }\n        f.write_str(\"}\")\n    }\n}\n\n/// A [`Struct`] field.\n#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]\n#[cfg_attr(feature = \"schema\", derive(schemars::JsonSchema))]\n#[serde(rename_all = \"camelCase\")]\npub struct StructField<'a> {\n    /// The name of the field.\n    pub name: &'a str,\n    /// The type of the field.\n    pub ty: &'a str,\n    /// The description of the field.\n    /// This is a markdown string derived from the NatSpec documentation.\n    pub description: &'a str,\n}\n"
  },
  {
    "path": "crates/cheatcodes/spec/src/lib.rs",
    "content": "//! Cheatcode specification for Foundry.\n\n#![cfg_attr(not(test), warn(unused_crate_dependencies))]\n#![cfg_attr(docsrs, feature(doc_cfg))]\n\nuse serde::{Deserialize, Serialize};\nuse std::{borrow::Cow, fmt};\n\nmod cheatcode;\npub use cheatcode::{Cheatcode, CheatcodeDef, Group, Safety, Status};\n\nmod function;\npub use function::{Function, Mutability, Visibility};\n\nmod items;\npub use items::{Enum, EnumVariant, Error, Event, Struct, StructField};\n\nmod vm;\npub use vm::Vm;\n\n// The `cheatcodes.json` schema.\n/// Foundry cheatcodes. Learn more: <https://book.getfoundry.sh/cheatcodes/>\n#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]\n#[cfg_attr(feature = \"schema\", derive(schemars::JsonSchema))]\n#[serde(rename_all = \"camelCase\")]\npub struct Cheatcodes<'a> {\n    /// Cheatcode errors.\n    #[serde(borrow)]\n    pub errors: Cow<'a, [Error<'a>]>,\n    /// Cheatcode events.\n    #[serde(borrow)]\n    pub events: Cow<'a, [Event<'a>]>,\n    /// Cheatcode enums.\n    #[serde(borrow)]\n    pub enums: Cow<'a, [Enum<'a>]>,\n    /// Cheatcode structs.\n    #[serde(borrow)]\n    pub structs: Cow<'a, [Struct<'a>]>,\n    /// All the cheatcodes.\n    #[serde(borrow)]\n    pub cheatcodes: Cow<'a, [Cheatcode<'a>]>,\n}\n\nimpl fmt::Display for Cheatcodes<'_> {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        for error in self.errors.iter() {\n            writeln!(f, \"{error}\")?;\n        }\n        for event in self.events.iter() {\n            writeln!(f, \"{event}\")?;\n        }\n        for enumm in self.enums.iter() {\n            writeln!(f, \"{enumm}\")?;\n        }\n        for strukt in self.structs.iter() {\n            writeln!(f, \"{strukt}\")?;\n        }\n        for cheatcode in self.cheatcodes.iter() {\n            writeln!(f, \"{}\", cheatcode.func)?;\n        }\n        Ok(())\n    }\n}\n\nimpl Default for Cheatcodes<'static> {\n    fn default() -> Self {\n        Self::new()\n    }\n}\n\nimpl Cheatcodes<'static> {\n    /// Returns the default cheatcodes.\n    pub fn new() -> Self {\n        Self {\n            // unfortunately technology has not yet advanced to the point where we can get all\n            // items of a certain type in a module, so we have to hardcode them here\n            structs: Cow::Owned(vec![\n                Vm::Log::STRUCT.clone(),\n                Vm::Rpc::STRUCT.clone(),\n                Vm::EthGetLogs::STRUCT.clone(),\n                Vm::DirEntry::STRUCT.clone(),\n                Vm::FsMetadata::STRUCT.clone(),\n                Vm::Wallet::STRUCT.clone(),\n                Vm::FfiResult::STRUCT.clone(),\n                Vm::ChainInfo::STRUCT.clone(),\n                Vm::Chain::STRUCT.clone(),\n                Vm::AccountAccess::STRUCT.clone(),\n                Vm::StorageAccess::STRUCT.clone(),\n                Vm::Gas::STRUCT.clone(),\n                Vm::DebugStep::STRUCT.clone(),\n                Vm::BroadcastTxSummary::STRUCT.clone(),\n                Vm::SignedDelegation::STRUCT.clone(),\n                Vm::PotentialRevert::STRUCT.clone(),\n                Vm::AccessListItem::STRUCT.clone(),\n            ]),\n            enums: Cow::Owned(vec![\n                Vm::CallerMode::ENUM.clone(),\n                Vm::AccountAccessKind::ENUM.clone(),\n                Vm::ForgeContext::ENUM.clone(),\n                Vm::BroadcastTxType::ENUM.clone(),\n            ]),\n            errors: Vm::VM_ERRORS.iter().copied().cloned().collect(),\n            events: Cow::Borrowed(&[]),\n            // events: Vm::VM_EVENTS.iter().copied().cloned().collect(),\n            cheatcodes: Vm::CHEATCODES.iter().copied().cloned().collect(),\n        }\n    }\n}\n\n#[cfg(test)]\n#[expect(clippy::disallowed_macros)]\nmod tests {\n    use super::*;\n    use std::{fs, path::Path};\n\n    const JSON_PATH: &str = concat!(env!(\"CARGO_MANIFEST_DIR\"), \"/../assets/cheatcodes.json\");\n    #[cfg(feature = \"schema\")]\n    const SCHEMA_PATH: &str =\n        concat!(env!(\"CARGO_MANIFEST_DIR\"), \"/../assets/cheatcodes.schema.json\");\n    const IFACE_PATH: &str = concat!(env!(\"CARGO_MANIFEST_DIR\"), \"/../../../testdata/utils/Vm.sol\");\n\n    /// Generates the `cheatcodes.json` file contents.\n    fn json_cheatcodes() -> String {\n        serde_json::to_string_pretty(&Cheatcodes::new()).unwrap()\n    }\n\n    /// Generates the [cheatcodes](json_cheatcodes) JSON schema.\n    #[cfg(feature = \"schema\")]\n    fn json_schema() -> String {\n        serde_json::to_string_pretty(&schemars::schema_for!(Cheatcodes<'_>)).unwrap()\n    }\n\n    fn sol_iface() -> String {\n        let mut cheats = Cheatcodes::new();\n        cheats.errors = Default::default(); // Skip errors to allow <0.8.4.\n        let cheats = cheats.to_string().trim().replace('\\n', \"\\n    \");\n        format!(\n            \"\\\n// Automatically generated from `foundry-cheatcodes` Vm definitions. Do not modify manually.\n// This interface is just for internal testing purposes. Use `forge-std` instead.\n\n// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity >=0.6.2 <0.9.0;\npragma experimental ABIEncoderV2;\n\ninterface Vm {{\n    {cheats}\n}}\n\"\n        )\n    }\n\n    #[test]\n    fn spec_up_to_date() {\n        ensure_file_contents(Path::new(JSON_PATH), &json_cheatcodes());\n    }\n\n    #[test]\n    #[cfg(feature = \"schema\")]\n    fn schema_up_to_date() {\n        ensure_file_contents(Path::new(SCHEMA_PATH), &json_schema());\n    }\n\n    #[test]\n    fn iface_up_to_date() {\n        ensure_file_contents(Path::new(IFACE_PATH), &sol_iface());\n    }\n\n    /// Checks that the `file` has the specified `contents`. If that is not the\n    /// case, updates the file and then fails the test.\n    fn ensure_file_contents(file: &Path, contents: &str) {\n        if let Ok(old_contents) = fs::read_to_string(file)\n            && normalize_newlines(&old_contents) == normalize_newlines(contents)\n        {\n            // File is already up to date.\n            return;\n        }\n\n        eprintln!(\"\\n\\x1b[31;1merror\\x1b[0m: {} was not up-to-date, updating\\n\", file.display());\n        if std::env::var(\"CI\").is_ok() {\n            eprintln!(\"    NOTE: run `cargo cheats` locally and commit the updated files\\n\");\n        }\n        if let Some(parent) = file.parent() {\n            let _ = fs::create_dir_all(parent);\n        }\n        fs::write(file, contents).unwrap();\n        panic!(\"some file was not up to date and has been updated, simply re-run the tests\");\n    }\n\n    fn normalize_newlines(s: &str) -> String {\n        s.replace(\"\\r\\n\", \"\\n\")\n    }\n}\n"
  },
  {
    "path": "crates/cheatcodes/spec/src/vm.rs",
    "content": "// We don't document function parameters individually so we can't enable `missing_docs` for this\n// module. Instead, we emit custom diagnostics in `#[derive(Cheatcode)]`.\n#![allow(missing_docs)]\n\nuse super::*;\nuse crate::Vm::ForgeContext;\nuse alloy_sol_types::sol;\nuse foundry_macros::Cheatcode;\n\nsol! {\n// Cheatcodes are marked as view/pure/none using the following rules:\n// 0. A call's observable behaviour includes its return value, logs, reverts and state writes,\n// 1. If you can influence a later call's observable behaviour, you're neither `view` nor `pure`\n//    (you are modifying some state be it the EVM, interpreter, filesystem, etc),\n// 2. Otherwise if you can be influenced by an earlier call, or if reading some state, you're `view`,\n// 3. Otherwise you're `pure`.\n\n/// Foundry cheatcodes interface.\n#[derive(Debug, Cheatcode)] // Keep this list small to avoid unnecessary bloat.\n#[sol(abi)]\ninterface Vm {\n    //  ======== Types ========\n\n    /// Error thrown by cheatcodes.\n    error CheatcodeError(string message);\n\n    /// A modification applied to either `msg.sender` or `tx.origin`. Returned by `readCallers`.\n    enum CallerMode {\n        /// No caller modification is currently active.\n        None,\n        /// A one time broadcast triggered by a `vm.broadcast()` call is currently active.\n        Broadcast,\n        /// A recurrent broadcast triggered by a `vm.startBroadcast()` call is currently active.\n        RecurrentBroadcast,\n        /// A one time prank triggered by a `vm.prank()` call is currently active.\n        Prank,\n        /// A recurrent prank triggered by a `vm.startPrank()` call is currently active.\n        RecurrentPrank,\n    }\n\n    /// The kind of account access that occurred.\n    enum AccountAccessKind {\n        /// The account was called.\n        Call,\n        /// The account was called via delegatecall.\n        DelegateCall,\n        /// The account was called via callcode.\n        CallCode,\n        /// The account was called via staticcall.\n        StaticCall,\n        /// The account was created.\n        Create,\n        /// The account was selfdestructed.\n        SelfDestruct,\n        /// Synthetic access indicating the current context has resumed after a previous sub-context (AccountAccess).\n        Resume,\n        /// The account's balance was read.\n        Balance,\n        /// The account's codesize was read.\n        Extcodesize,\n        /// The account's codehash was read.\n        Extcodehash,\n        /// The account's code was copied.\n        Extcodecopy,\n    }\n\n    /// Forge execution contexts.\n    enum ForgeContext {\n        /// Test group execution context (test, coverage or snapshot).\n        TestGroup,\n        /// `forge test` execution context.\n        Test,\n        /// `forge coverage` execution context.\n        Coverage,\n        /// `forge snapshot` execution context.\n        Snapshot,\n        /// Script group execution context (dry run, broadcast or resume).\n        ScriptGroup,\n        /// `forge script` execution context.\n        ScriptDryRun,\n        /// `forge script --broadcast` execution context.\n        ScriptBroadcast,\n        /// `forge script --resume` execution context.\n        ScriptResume,\n        /// Unknown `forge` execution context.\n        Unknown,\n    }\n\n    /// An Ethereum log. Returned by `getRecordedLogs`.\n    struct Log {\n        /// The topics of the log, including the signature, if any.\n        bytes32[] topics;\n        /// The raw data of the log.\n        bytes data;\n        /// The address of the log's emitter.\n        address emitter;\n    }\n\n    /// Gas used. Returned by `lastCallGas`.\n    struct Gas {\n        /// The gas limit of the call.\n        uint64 gasLimit;\n        /// The total gas used.\n        uint64 gasTotalUsed;\n        /// DEPRECATED: The amount of gas used for memory expansion. Ref: <https://github.com/foundry-rs/foundry/pull/7934#pullrequestreview-2069236939>\n        uint64 gasMemoryUsed;\n        /// The amount of gas refunded.\n        int64 gasRefunded;\n        /// The amount of gas remaining.\n        uint64 gasRemaining;\n    }\n\n    /// An RPC URL and its alias. Returned by `rpcUrlStructs`.\n    struct Rpc {\n        /// The alias of the RPC URL.\n        string key;\n        /// The RPC URL.\n        string url;\n    }\n\n    /// An RPC log object. Returned by `eth_getLogs`.\n    struct EthGetLogs {\n        /// The address of the log's emitter.\n        address emitter;\n        /// The topics of the log, including the signature, if any.\n        bytes32[] topics;\n        /// The raw data of the log.\n        bytes data;\n        /// The block hash.\n        bytes32 blockHash;\n        /// The block number.\n        uint64 blockNumber;\n        /// The transaction hash.\n        bytes32 transactionHash;\n        /// The transaction index in the block.\n        uint64 transactionIndex;\n        /// The log index.\n        uint256 logIndex;\n        /// Whether the log was removed.\n        bool removed;\n    }\n\n    /// A single entry in a directory listing. Returned by `readDir`.\n    struct DirEntry {\n        /// The error message, if any.\n        string errorMessage;\n        /// The path of the entry.\n        string path;\n        /// The depth of the entry.\n        uint64 depth;\n        /// Whether the entry is a directory.\n        bool isDir;\n        /// Whether the entry is a symlink.\n        bool isSymlink;\n    }\n\n    /// Metadata information about a file.\n    ///\n    /// This structure is returned from the `fsMetadata` function and represents known\n    /// metadata about a file such as its permissions, size, modification\n    /// times, etc.\n    struct FsMetadata {\n        /// True if this metadata is for a directory.\n        bool isDir;\n        /// True if this metadata is for a symlink.\n        bool isSymlink;\n        /// The size of the file, in bytes, this metadata is for.\n        uint256 length;\n        /// True if this metadata is for a readonly (unwritable) file.\n        bool readOnly;\n        /// The last modification time listed in this metadata.\n        uint256 modified;\n        /// The last access time of this metadata.\n        uint256 accessed;\n        /// The creation time listed in this metadata.\n        uint256 created;\n    }\n\n    /// A wallet with a public and private key.\n    struct Wallet {\n        /// The wallet's address.\n        address addr;\n        /// The wallet's public key `X`.\n        uint256 publicKeyX;\n        /// The wallet's public key `Y`.\n        uint256 publicKeyY;\n        /// The wallet's private key.\n        uint256 privateKey;\n    }\n\n    /// The result of a `tryFfi` call.\n    struct FfiResult {\n        /// The exit code of the call.\n        int32 exitCode;\n        /// The optionally hex-decoded `stdout` data.\n        bytes stdout;\n        /// The `stderr` data.\n        bytes stderr;\n    }\n\n    /// Information on the chain and fork.\n    struct ChainInfo {\n        /// The fork identifier. Set to zero if no fork is active.\n        uint256 forkId;\n        /// The chain ID of the current fork.\n        uint256 chainId;\n    }\n\n    /// Information about a blockchain.\n    struct Chain {\n        /// The chain name.\n        string name;\n        /// The chain's Chain ID.\n        uint256 chainId;\n        /// The chain's alias. (i.e. what gets specified in `foundry.toml`).\n        string chainAlias;\n        /// A default RPC endpoint for this chain.\n        string rpcUrl;\n    }\n\n    /// The storage accessed during an `AccountAccess`.\n    struct StorageAccess {\n        /// The account whose storage was accessed.\n        address account;\n        /// The slot that was accessed.\n        bytes32 slot;\n        /// If the access was a write.\n        bool isWrite;\n        /// The previous value of the slot.\n        bytes32 previousValue;\n        /// The new value of the slot.\n        bytes32 newValue;\n        /// If the access was reverted.\n        bool reverted;\n    }\n\n    /// An EIP-2930 access list item.\n    struct AccessListItem {\n        /// The address to be added in access list.\n        address target;\n        /// The storage keys to be added in access list.\n        bytes32[] storageKeys;\n    }\n\n    /// The result of a `stopAndReturnStateDiff` call.\n    struct AccountAccess {\n        /// The chain and fork the access occurred.\n        ChainInfo chainInfo;\n        /// The kind of account access that determines what the account is.\n        /// If kind is Call, DelegateCall, StaticCall or CallCode, then the account is the callee.\n        /// If kind is Create, then the account is the newly created account.\n        /// If kind is SelfDestruct, then the account is the selfdestruct recipient.\n        /// If kind is a Resume, then account represents a account context that has resumed.\n        AccountAccessKind kind;\n        /// The account that was accessed.\n        /// It's either the account created, callee or a selfdestruct recipient for CREATE, CALL or SELFDESTRUCT.\n        address account;\n        /// What accessed the account.\n        address accessor;\n        /// If the account was initialized or empty prior to the access.\n        /// An account is considered initialized if it has code, a\n        /// non-zero nonce, or a non-zero balance.\n        bool initialized;\n        /// The previous balance of the accessed account.\n        uint256 oldBalance;\n        /// The potential new balance of the accessed account.\n        /// That is, all balance changes are recorded here, even if reverts occurred.\n        uint256 newBalance;\n        /// Code of the account deployed by CREATE.\n        bytes deployedCode;\n        /// Value passed along with the account access\n        uint256 value;\n        /// Input data provided to the CREATE or CALL\n        bytes data;\n        /// If this access reverted in either the current or parent context.\n        bool reverted;\n        /// An ordered list of storage accesses made during an account access operation.\n        StorageAccess[] storageAccesses;\n        /// Call depth traversed during the recording of state differences\n        uint64 depth;\n        /// The previous nonce of the accessed account.\n        uint64 oldNonce;\n        /// The new nonce of the accessed account.\n        uint64 newNonce;\n    }\n\n    /// The result of the `stopDebugTraceRecording` call\n    struct DebugStep {\n        /// The stack before executing the step of the run.\n        /// stack\\[0\\] represents the top of the stack.\n        /// and only stack data relevant to the opcode execution is contained.\n        uint256[] stack;\n        /// The memory input data before executing the step of the run.\n        /// only input data relevant to the opcode execution is contained.\n        ///\n        /// e.g. for MLOAD, it will have memory\\[offset:offset+32\\] copied here.\n        /// the offset value can be get by the stack data.\n        bytes memoryInput;\n        /// The opcode that was accessed.\n        uint8 opcode;\n        /// The call depth of the step.\n        uint64 depth;\n        /// Whether the call end up with out of gas error.\n        bool isOutOfGas;\n        /// The contract address where the opcode is running\n        address contractAddr;\n    }\n\n    /// The transaction type (`txType`) of the broadcast.\n    enum BroadcastTxType {\n        /// Represents a CALL broadcast tx.\n        Call,\n        /// Represents a CREATE broadcast tx.\n        Create,\n        /// Represents a CREATE2 broadcast tx.\n        Create2\n    }\n\n    /// Represents a transaction's broadcast details.\n    struct BroadcastTxSummary {\n        /// The hash of the transaction that was broadcasted\n        bytes32 txHash;\n        /// Represent the type of transaction among CALL, CREATE, CREATE2\n        BroadcastTxType txType;\n        /// The address of the contract that was called or created.\n        /// This is address of the contract that is created if the txType is CREATE or CREATE2.\n        address contractAddress;\n        /// The block number the transaction landed in.\n        uint64 blockNumber;\n        /// Status of the transaction, retrieved from the transaction receipt.\n        bool success;\n    }\n\n    /// Holds a signed EIP-7702 authorization for an authority account to delegate to an implementation.\n    struct SignedDelegation {\n        /// The y-parity of the recovered secp256k1 signature (0 or 1).\n        uint8 v;\n        /// First 32 bytes of the signature.\n        bytes32 r;\n        /// Second 32 bytes of the signature.\n        bytes32 s;\n        /// The current nonce of the authority account at signing time.\n        /// Used to ensure signature can't be replayed after account nonce changes.\n        uint64 nonce;\n        /// Address of the contract implementation that will be delegated to.\n        /// Gets encoded into delegation code: 0xef0100 || implementation.\n        address implementation;\n    }\n\n    /// Represents a \"potential\" revert reason from a single subsequent call when using `vm.assumeNoReverts`.\n    /// Reverts that match will result in a FOUNDRY::ASSUME rejection, whereas unmatched reverts will be surfaced\n    /// as normal.\n    struct PotentialRevert {\n        /// The allowed origin of the revert opcode; address(0) allows reverts from any address\n        address reverter;\n        /// When true, only matches on the beginning of the revert data, otherwise, matches on entire revert data\n        bool partialMatch;\n        /// The data to use to match encountered reverts\n        bytes revertData;\n    }\n\n    // ======== EVM ========\n\n    /// Gets the address for a given private key.\n    #[cheatcode(group = Evm, safety = Safe)]\n    function addr(uint256 privateKey) external pure returns (address keyAddr);\n\n    /// Dump a genesis JSON file's `allocs` to disk.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function dumpState(string calldata pathToStateJson) external;\n\n    /// Gets the nonce of an account.\n    #[cheatcode(group = Evm, safety = Safe)]\n    function getNonce(address account) external view returns (uint64 nonce);\n\n    /// Get the nonce of a `Wallet`.\n    #[cheatcode(group = Evm, safety = Safe)]\n    function getNonce(Wallet calldata wallet) external view returns (uint64 nonce);\n\n    /// Loads a storage slot from an address.\n    #[cheatcode(group = Evm, safety = Safe)]\n    function load(address target, bytes32 slot) external view returns (bytes32 data);\n\n    /// Load a genesis JSON file's `allocs` into the in-memory EVM state.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function loadAllocs(string calldata pathToAllocsJson) external;\n\n    // -------- Record Debug Traces --------\n\n    /// Records the debug trace during the run.\n    #[cheatcode(group = Evm, safety = Safe)]\n    function startDebugTraceRecording() external;\n\n    /// Stop debug trace recording and returns the recorded debug trace.\n    #[cheatcode(group = Evm, safety = Safe)]\n    function stopAndReturnDebugTraceRecording() external returns (DebugStep[] memory step);\n\n\n    /// Clones a source account code, state, balance and nonce to a target account and updates in-memory EVM state.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function cloneAccount(address source, address target) external;\n\n    // -------- Record Storage --------\n\n    /// Records all storage reads and writes. Use `accesses` to get the recorded data.\n    /// Subsequent calls to `record` will clear the previous data.\n    #[cheatcode(group = Evm, safety = Safe)]\n    function record() external;\n\n    /// Stops recording storage reads and writes.\n    #[cheatcode(group = Evm, safety = Safe)]\n    function stopRecord() external;\n\n    /// Gets all accessed reads and write slot from a `vm.record` session, for a given address.\n    #[cheatcode(group = Evm, safety = Safe)]\n    function accesses(address target) external view returns (bytes32[] memory readSlots, bytes32[] memory writeSlots);\n\n    /// Record all account accesses as part of CREATE, CALL or SELFDESTRUCT opcodes in order,\n    /// along with the context of the calls\n    #[cheatcode(group = Evm, safety = Safe)]\n    function startStateDiffRecording() external;\n\n    /// Returns an ordered array of all account accesses from a `vm.startStateDiffRecording` session.\n    #[cheatcode(group = Evm, safety = Safe)]\n    function stopAndReturnStateDiff() external returns (AccountAccess[] memory accountAccesses);\n\n    /// Returns state diffs from current `vm.startStateDiffRecording` session.\n    #[cheatcode(group = Evm, safety = Safe)]\n    function getStateDiff() external view returns (string memory diff);\n\n    /// Returns state diffs from current `vm.startStateDiffRecording` session, in json format.\n    #[cheatcode(group = Evm, safety = Safe)]\n    function getStateDiffJson() external view returns (string memory diff);\n\n    /// Returns an array of storage slots occupied by the specified variable.\n    #[cheatcode(group = Evm, safety = Safe)]\n    function getStorageSlots(address target, string calldata variableName) external view returns (uint256[] memory slots);\n\n    /// Returns an array of `StorageAccess` from current `vm.stateStateDiffRecording` session\n    #[cheatcode(group = Evm, safety = Safe)]\n    function getStorageAccesses() external view returns (StorageAccess[] memory storageAccesses);\n\n    // -------- Recording Map Writes --------\n\n    /// Starts recording all map SSTOREs for later retrieval.\n    #[cheatcode(group = Evm, safety = Safe)]\n    function startMappingRecording() external;\n\n    /// Stops recording all map SSTOREs for later retrieval and clears the recorded data.\n    #[cheatcode(group = Evm, safety = Safe)]\n    function stopMappingRecording() external;\n\n    /// Gets the number of elements in the mapping at the given slot, for a given address.\n    #[cheatcode(group = Evm, safety = Safe)]\n    function getMappingLength(address target, bytes32 mappingSlot) external view returns (uint256 length);\n\n    /// Gets the elements at index idx of the mapping at the given slot, for a given address. The\n    /// index must be less than the length of the mapping (i.e. the number of keys in the mapping).\n    #[cheatcode(group = Evm, safety = Safe)]\n    function getMappingSlotAt(address target, bytes32 mappingSlot, uint256 idx) external view returns (bytes32 value);\n\n    /// Gets the map key and parent of a mapping at a given slot, for a given address.\n    #[cheatcode(group = Evm, safety = Safe)]\n    function getMappingKeyAndParentOf(address target, bytes32 elementSlot)\n        external\n        view\n        returns (bool found, bytes32 key, bytes32 parent);\n\n    // -------- Block and Transaction Properties --------\n\n    /// Gets the current `block.chainid` of the currently selected environment.\n    /// You should use this instead of `block.chainid` if you use `vm.selectFork` or `vm.createSelectFork`, as `block.chainid` could be assumed\n    /// to be constant across a transaction, and as a result will get optimized out by the compiler.\n    /// See https://github.com/foundry-rs/foundry/issues/6180\n    #[cheatcode(group = Evm, safety = Safe)]\n    function getChainId() external view returns (uint256 blockChainId);\n\n    /// Sets `block.chainid`.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function chainId(uint256 newChainId) external;\n\n    /// Sets `block.coinbase`.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function coinbase(address newCoinbase) external;\n\n    /// Sets `block.difficulty`.\n    /// Not available on EVM versions from Paris onwards. Use `prevrandao` instead.\n    /// Reverts if used on unsupported EVM versions.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function difficulty(uint256 newDifficulty) external;\n\n    /// Sets `block.basefee`.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function fee(uint256 newBasefee) external;\n\n    /// Sets `block.prevrandao`.\n    /// Not available on EVM versions before Paris. Use `difficulty` instead.\n    /// If used on unsupported EVM versions it will revert.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function prevrandao(bytes32 newPrevrandao) external;\n    /// Sets `block.prevrandao`.\n    /// Not available on EVM versions before Paris. Use `difficulty` instead.\n    /// If used on unsupported EVM versions it will revert.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function prevrandao(uint256 newPrevrandao) external;\n\n    /// Sets the blobhashes in the transaction.\n    /// Not available on EVM versions before Cancun.\n    /// If used on unsupported EVM versions it will revert.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function blobhashes(bytes32[] calldata hashes) external;\n\n    /// Gets the blockhashes from the current transaction.\n    /// Not available on EVM versions before Cancun.\n    /// If used on unsupported EVM versions it will revert.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function getBlobhashes() external view returns (bytes32[] memory hashes);\n\n    /// Sets `block.height`.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function roll(uint256 newHeight) external;\n\n    /// Gets the current `block.number`.\n    /// You should use this instead of `block.number` if you use `vm.roll`, as `block.number` is assumed to be constant across a transaction,\n    /// and as a result will get optimized out by the compiler.\n    /// See https://github.com/foundry-rs/foundry/issues/6180\n    #[cheatcode(group = Evm, safety = Safe)]\n    function getBlockNumber() external view returns (uint256 height);\n\n    /// Sets `tx.gasprice`.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function txGasPrice(uint256 newGasPrice) external;\n\n    /// Sets `block.timestamp`.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function warp(uint256 newTimestamp) external;\n\n    /// Gets the current `block.timestamp`.\n    /// You should use this instead of `block.timestamp` if you use `vm.warp`, as `block.timestamp` is assumed to be constant across a transaction,\n    /// and as a result will get optimized out by the compiler.\n    /// See https://github.com/foundry-rs/foundry/issues/6180\n    #[cheatcode(group = Evm, safety = Safe)]\n    function getBlockTimestamp() external view returns (uint256 timestamp);\n\n    /// Gets the RLP encoded block header for a given block number.\n    /// Returns the block header in the same format as `cast block <block_number> --raw`.\n    #[cheatcode(group = Evm, safety = Safe)]\n    function getRawBlockHeader(uint256 blockNumber) external view returns (bytes memory rlpHeader);\n\n    /// Sets `block.blobbasefee`\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function blobBaseFee(uint256 newBlobBaseFee) external;\n\n    /// Gets the current `block.blobbasefee`.\n    /// You should use this instead of `block.blobbasefee` if you use `vm.blobBaseFee`, as `block.blobbasefee` is assumed to be constant across a transaction,\n    /// and as a result will get optimized out by the compiler.\n    /// See https://github.com/foundry-rs/foundry/issues/6180\n    #[cheatcode(group = Evm, safety = Safe)]\n    function getBlobBaseFee() external view returns (uint256 blobBaseFee);\n\n    /// Set blockhash for the current block.\n    /// It only sets the blockhash for blocks where `block.number - 256 <= number < block.number`.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function setBlockhash(uint256 blockNumber, bytes32 blockHash) external;\n\n    /// Executes an RLP-encoded signed transaction with full EVM semantics (like `--isolate` mode).\n    /// The transaction is decoded from EIP-2718 format (type byte prefix + RLP payload) or legacy RLP.\n    /// Returns the execution output bytes.\n    ///\n    /// This cheatcode is not allowed in `forge script` contexts.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function executeTransaction(bytes calldata rawTx) external returns (bytes memory);\n\n    // -------- Account State --------\n\n    /// Sets an address' balance.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function deal(address account, uint256 newBalance) external;\n\n    /// Sets an address' code.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function etch(address target, bytes calldata newRuntimeBytecode) external;\n\n    /// Resets the nonce of an account to 0 for EOAs and 1 for contract accounts.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function resetNonce(address account) external;\n\n    /// Sets the nonce of an account. Must be higher than the current nonce of the account.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function setNonce(address account, uint64 newNonce) external;\n\n    /// Sets the nonce of an account to an arbitrary value.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function setNonceUnsafe(address account, uint64 newNonce) external;\n\n    /// Stores a value to an address' storage slot.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function store(address target, bytes32 slot, bytes32 value) external;\n\n    /// Marks the slots of an account and the account address as cold.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function cool(address target) external;\n\n    /// Utility cheatcode to set an EIP-2930 access list for all subsequent transactions.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function accessList(AccessListItem[] calldata access) external;\n\n    /// Utility cheatcode to remove any EIP-2930 access list set by `accessList` cheatcode.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function noAccessList() external;\n\n    /// Utility cheatcode to mark specific storage slot as warm, simulating a prior read.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function warmSlot(address target, bytes32 slot) external;\n\n    /// Utility cheatcode to mark specific storage slot as cold, simulating no prior read.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function coolSlot(address target, bytes32 slot) external;\n\n    /// Returns the test or script execution evm version.\n    ///\n    /// **Note:** The execution evm version is not the same as the compilation one.\n    #[cheatcode(group = Evm, safety = Safe)]\n    function getEvmVersion() external pure returns (string memory evm);\n\n    /// Set the exact test or script execution evm version, e.g. `berlin`, `cancun`.\n    ///\n    /// **Note:** The execution evm version is not the same as the compilation one.\n    #[cheatcode(group = Evm, safety = Safe)]\n    function setEvmVersion(string calldata evm) external;\n\n    // -------- Call Manipulation --------\n    // --- Mocks ---\n\n    /// Clears all mocked calls.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function clearMockedCalls() external;\n\n    /// Mocks a call to an address, returning specified data.\n    /// Calldata can either be strict or a partial match, e.g. if you only\n    /// pass a Solidity selector to the expected calldata, then the entire Solidity\n    /// function will be mocked.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function mockCall(address callee, bytes calldata data, bytes calldata returnData) external;\n\n    /// Mocks a call to an address with a specific `msg.value`, returning specified data.\n    /// Calldata match takes precedence over `msg.value` in case of ambiguity.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function mockCall(address callee, uint256 msgValue, bytes calldata data, bytes calldata returnData) external;\n\n    /// Mocks a call to an address, returning specified data.\n    /// Calldata can either be strict or a partial match, e.g. if you only\n    /// pass a Solidity selector to the expected calldata, then the entire Solidity\n    /// function will be mocked.\n    ///\n    /// Overload to pass the function selector directly `token.approve.selector` instead of `abi.encodeWithSelector(token.approve.selector)`.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function mockCall(address callee, bytes4 data, bytes calldata returnData) external;\n\n    /// Mocks a call to an address with a specific `msg.value`, returning specified data.\n    /// Calldata match takes precedence over `msg.value` in case of ambiguity.\n    ///\n    /// Overload to pass the function selector directly `token.approve.selector` instead of `abi.encodeWithSelector(token.approve.selector)`.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function mockCall(address callee, uint256 msgValue, bytes4 data, bytes calldata returnData) external;\n\n    /// Mocks multiple calls to an address, returning specified data for each call.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function mockCalls(address callee, bytes calldata data, bytes[] calldata returnData) external;\n\n    /// Mocks multiple calls to an address with a specific `msg.value`, returning specified data for each call.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function mockCalls(address callee, uint256 msgValue, bytes calldata data, bytes[] calldata returnData) external;\n\n    /// Reverts a call to an address with specified revert data.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function mockCallRevert(address callee, bytes calldata data, bytes calldata revertData) external;\n\n    /// Reverts a call to an address with a specific `msg.value`, with specified revert data.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function mockCallRevert(address callee, uint256 msgValue, bytes calldata data, bytes calldata revertData)\n        external;\n\n    /// Reverts a call to an address with specified revert data.\n    ///\n    /// Overload to pass the function selector directly `token.approve.selector` instead of `abi.encodeWithSelector(token.approve.selector)`.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function mockCallRevert(address callee, bytes4 data, bytes calldata revertData) external;\n\n    /// Reverts a call to an address with a specific `msg.value`, with specified revert data.\n    ///\n    /// Overload to pass the function selector directly `token.approve.selector` instead of `abi.encodeWithSelector(token.approve.selector)`.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function mockCallRevert(address callee, uint256 msgValue, bytes4 data, bytes calldata revertData)\n        external;\n\n    /// Whenever a call is made to `callee` with calldata `data`, this cheatcode instead calls\n    /// `target` with the same calldata. This functionality is similar to a delegate call made to\n    /// `target` contract from `callee`.\n    /// Can be used to substitute a call to a function with another implementation that captures\n    /// the primary logic of the original function but is easier to reason about.\n    /// If calldata is not a strict match then partial match by selector is attempted.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function mockFunction(address callee, address target, bytes calldata data) external;\n\n    // --- Impersonation (pranks) ---\n\n    /// Sets the *next* call's `msg.sender` to be the input address.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function prank(address msgSender) external;\n\n    /// Sets all subsequent calls' `msg.sender` to be the input address until `stopPrank` is called.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function startPrank(address msgSender) external;\n\n    /// Sets the *next* call's `msg.sender` to be the input address, and the `tx.origin` to be the second input.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function prank(address msgSender, address txOrigin) external;\n\n    /// Sets all subsequent calls' `msg.sender` to be the input address until `stopPrank` is called, and the `tx.origin` to be the second input.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function startPrank(address msgSender, address txOrigin) external;\n\n    /// Sets the *next* delegate call's `msg.sender` to be the input address.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function prank(address msgSender, bool delegateCall) external;\n\n    /// Sets all subsequent delegate calls' `msg.sender` to be the input address until `stopPrank` is called.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function startPrank(address msgSender, bool delegateCall) external;\n\n    /// Sets the *next* delegate call's `msg.sender` to be the input address, and the `tx.origin` to be the second input.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function prank(address msgSender, address txOrigin, bool delegateCall) external;\n\n    /// Sets all subsequent delegate calls' `msg.sender` to be the input address until `stopPrank` is called, and the `tx.origin` to be the second input.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function startPrank(address msgSender, address txOrigin, bool delegateCall) external;\n\n    /// Resets subsequent calls' `msg.sender` to be `address(this)`.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function stopPrank() external;\n\n    /// Reads the current `msg.sender` and `tx.origin` from state and reports if there is any active caller modification.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function readCallers() external view returns (CallerMode callerMode, address msgSender, address txOrigin);\n\n    // ----- Arbitrary Snapshots -----\n\n    /// Snapshot capture an arbitrary numerical value by name.\n    /// The group name is derived from the contract name.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function snapshotValue(string calldata name, uint256 value) external;\n\n    /// Snapshot capture an arbitrary numerical value by name in a group.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function snapshotValue(string calldata group, string calldata name, uint256 value) external;\n\n    // -------- Gas Snapshots --------\n\n    /// Snapshot capture the gas usage of the last call by name from the callee perspective.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function snapshotGasLastCall(string calldata name) external returns (uint256 gasUsed);\n\n    /// Snapshot capture the gas usage of the last call by name in a group from the callee perspective.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function snapshotGasLastCall(string calldata group, string calldata name) external returns (uint256 gasUsed);\n\n    /// Start a snapshot capture of the current gas usage by name.\n    /// The group name is derived from the contract name.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function startSnapshotGas(string calldata name) external;\n\n    /// Start a snapshot capture of the current gas usage by name in a group.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function startSnapshotGas(string calldata group, string calldata name) external;\n\n    /// Stop the snapshot capture of the current gas by latest snapshot name, capturing the gas used since the start.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function stopSnapshotGas() external returns (uint256 gasUsed);\n\n    /// Stop the snapshot capture of the current gas usage by name, capturing the gas used since the start.\n    /// The group name is derived from the contract name.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function stopSnapshotGas(string calldata name) external returns (uint256 gasUsed);\n\n    /// Stop the snapshot capture of the current gas usage by name in a group, capturing the gas used since the start.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function stopSnapshotGas(string calldata group, string calldata name) external returns (uint256 gasUsed);\n\n    // -------- State Snapshots --------\n\n    /// `snapshot` is being deprecated in favor of `snapshotState`. It will be removed in future versions.\n    #[cheatcode(group = Evm, safety = Unsafe, status = Deprecated(Some(\"replaced by `snapshotState`\")))]\n    function snapshot() external returns (uint256 snapshotId);\n\n    /// Snapshot the current state of the evm.\n    /// Returns the ID of the snapshot that was created.\n    /// To revert a snapshot use `revertToState`.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function snapshotState() external returns (uint256 snapshotId);\n\n    /// `revertTo` is being deprecated in favor of `revertToState`. It will be removed in future versions.\n    #[cheatcode(group = Evm, safety = Unsafe, status = Deprecated(Some(\"replaced by `revertToState`\")))]\n    function revertTo(uint256 snapshotId) external returns (bool success);\n\n    /// Revert the state of the EVM to a previous snapshot\n    /// Takes the snapshot ID to revert to.\n    ///\n    /// Returns `true` if the snapshot was successfully reverted.\n    /// Returns `false` if the snapshot does not exist.\n    ///\n    /// **Note:** This does not automatically delete the snapshot. To delete the snapshot use `deleteStateSnapshot`.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function revertToState(uint256 snapshotId) external returns (bool success);\n\n    /// `revertToAndDelete` is being deprecated in favor of `revertToStateAndDelete`. It will be removed in future versions.\n    #[cheatcode(group = Evm, safety = Unsafe, status = Deprecated(Some(\"replaced by `revertToStateAndDelete`\")))]\n    function revertToAndDelete(uint256 snapshotId) external returns (bool success);\n\n    /// Revert the state of the EVM to a previous snapshot and automatically deletes the snapshots\n    /// Takes the snapshot ID to revert to.\n    ///\n    /// Returns `true` if the snapshot was successfully reverted and deleted.\n    /// Returns `false` if the snapshot does not exist.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function revertToStateAndDelete(uint256 snapshotId) external returns (bool success);\n\n    /// `deleteSnapshot` is being deprecated in favor of `deleteStateSnapshot`. It will be removed in future versions.\n    #[cheatcode(group = Evm, safety = Unsafe, status = Deprecated(Some(\"replaced by `deleteStateSnapshot`\")))]\n    function deleteSnapshot(uint256 snapshotId) external returns (bool success);\n\n    /// Removes the snapshot with the given ID created by `snapshot`.\n    /// Takes the snapshot ID to delete.\n    ///\n    /// Returns `true` if the snapshot was successfully deleted.\n    /// Returns `false` if the snapshot does not exist.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function deleteStateSnapshot(uint256 snapshotId) external returns (bool success);\n\n    /// `deleteSnapshots` is being deprecated in favor of `deleteStateSnapshots`. It will be removed in future versions.\n    #[cheatcode(group = Evm, safety = Unsafe, status = Deprecated(Some(\"replaced by `deleteStateSnapshots`\")))]\n    function deleteSnapshots() external;\n\n    /// Removes _all_ snapshots previously created by `snapshot`.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function deleteStateSnapshots() external;\n\n    // -------- Forking --------\n    // --- Creation and Selection ---\n\n    /// Returns the identifier of the currently active fork. Reverts if no fork is currently active.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function activeFork() external view returns (uint256 forkId);\n\n    /// Creates a new fork with the given endpoint and the _latest_ block and returns the identifier of the fork.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function createFork(string calldata urlOrAlias) external returns (uint256 forkId);\n    /// Creates a new fork with the given endpoint and block and returns the identifier of the fork.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function createFork(string calldata urlOrAlias, uint256 blockNumber) external returns (uint256 forkId);\n    /// Creates a new fork with the given endpoint and at the block the given transaction was mined in,\n    /// replays all transaction mined in the block before the transaction, and returns the identifier of the fork.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function createFork(string calldata urlOrAlias, bytes32 txHash) external returns (uint256 forkId);\n\n    /// Creates and also selects a new fork with the given endpoint and the latest block and returns the identifier of the fork.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function createSelectFork(string calldata urlOrAlias) external returns (uint256 forkId);\n    /// Creates and also selects a new fork with the given endpoint and block and returns the identifier of the fork.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function createSelectFork(string calldata urlOrAlias, uint256 blockNumber) external returns (uint256 forkId);\n    /// Creates and also selects new fork with the given endpoint and at the block the given transaction was mined in,\n    /// replays all transaction mined in the block before the transaction, returns the identifier of the fork.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function createSelectFork(string calldata urlOrAlias, bytes32 txHash) external returns (uint256 forkId);\n\n    /// Updates the currently active fork to given block number\n    /// This is similar to `roll` but for the currently active fork.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function rollFork(uint256 blockNumber) external;\n    /// Updates the currently active fork to given transaction. This will `rollFork` with the number\n    /// of the block the transaction was mined in and replays all transaction mined before it in the block.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function rollFork(bytes32 txHash) external;\n    /// Updates the given fork to given block number.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function rollFork(uint256 forkId, uint256 blockNumber) external;\n    /// Updates the given fork to block number of the given transaction and replays all transaction mined before it in the block.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function rollFork(uint256 forkId, bytes32 txHash) external;\n\n    /// Takes a fork identifier created by `createFork` and sets the corresponding forked state as active.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function selectFork(uint256 forkId) external;\n\n    /// Fetches the given transaction from the active fork and executes it on the current state.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function transact(bytes32 txHash) external;\n    /// Fetches the given transaction from the given fork and executes it on the current state.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function transact(uint256 forkId, bytes32 txHash) external;\n\n    /// Performs an Ethereum JSON-RPC request to the current fork URL.\n    #[cheatcode(group = Evm, safety = Safe)]\n    function rpc(string calldata method, string calldata params) external returns (bytes memory data);\n\n    /// Performs an Ethereum JSON-RPC request to the given endpoint.\n    #[cheatcode(group = Evm, safety = Safe)]\n    function rpc(string calldata urlOrAlias, string calldata method, string calldata params)\n        external\n        returns (bytes memory data);\n\n    /// Gets all the logs according to specified filter.\n    #[cheatcode(group = Evm, safety = Safe)]\n    function eth_getLogs(uint256 fromBlock, uint256 toBlock, address target, bytes32[] calldata topics)\n        external\n        view\n        returns (EthGetLogs[] memory logs);\n\n    // --- Behavior ---\n\n    /// In forking mode, explicitly grant the given address cheatcode access.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function allowCheatcodes(address account) external;\n\n    /// Marks that the account(s) should use persistent storage across fork swaps in a multifork setup\n    /// Meaning, changes made to the state of this account will be kept when switching forks.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function makePersistent(address account) external;\n    /// See `makePersistent(address)`.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function makePersistent(address account0, address account1) external;\n    /// See `makePersistent(address)`.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function makePersistent(address account0, address account1, address account2) external;\n    /// See `makePersistent(address)`.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function makePersistent(address[] calldata accounts) external;\n\n    /// Revokes persistent status from the address, previously added via `makePersistent`.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function revokePersistent(address account) external;\n    /// See `revokePersistent(address)`.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function revokePersistent(address[] calldata accounts) external;\n\n    /// Returns true if the account is marked as persistent.\n    #[cheatcode(group = Evm, safety = Unsafe)]\n    function isPersistent(address account) external view returns (bool persistent);\n\n    // -------- Record Logs --------\n\n    /// Record all the transaction logs.\n    #[cheatcode(group = Evm, safety = Safe)]\n    function recordLogs() external;\n\n    /// Gets all the recorded logs.\n    #[cheatcode(group = Evm, safety = Safe)]\n    function getRecordedLogs() external view returns (Log[] memory logs);\n\n    /// Gets all the recorded logs, in JSON format.\n    #[cheatcode(group = Evm, safety = Safe)]\n    function getRecordedLogsJson() external view returns (string memory logsJson);\n\n    // -------- Gas Metering --------\n\n    // It's recommend to use the `noGasMetering` modifier included with forge-std, instead of\n    // using these functions directly.\n\n    /// Pauses gas metering (i.e. gas usage is not counted). Noop if already paused.\n    #[cheatcode(group = Evm, safety = Safe)]\n    function pauseGasMetering() external;\n\n    /// Resumes gas metering (i.e. gas usage is counted again). Noop if already on.\n    #[cheatcode(group = Evm, safety = Safe)]\n    function resumeGasMetering() external;\n\n    /// Reset gas metering (i.e. gas usage is set to gas limit).\n    #[cheatcode(group = Evm, safety = Safe)]\n    function resetGasMetering() external;\n\n    // -------- Gas Measurement --------\n\n    /// Gets the gas used in the last call from the callee perspective.\n    #[cheatcode(group = Evm, safety = Safe)]\n    function lastCallGas() external view returns (Gas memory gas);\n\n    // ======== Test Assertions and Utilities ========\n\n    /// If the condition is false, discard this run's fuzz inputs and generate new ones.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assume(bool condition) external pure;\n\n    /// Discard this run's fuzz inputs and generate new ones if next call reverted.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assumeNoRevert() external pure;\n\n    /// Discard this run's fuzz inputs and generate new ones if next call reverts with the potential revert parameters.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assumeNoRevert(PotentialRevert calldata potentialRevert) external pure;\n\n    /// Discard this run's fuzz inputs and generate new ones if next call reverts with the any of the potential revert parameters.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assumeNoRevert(PotentialRevert[] calldata potentialReverts) external pure;\n\n    /// Writes a breakpoint to jump to in the debugger.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function breakpoint(string calldata char) external pure;\n\n    /// Writes a conditional breakpoint to jump to in the debugger.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function breakpoint(string calldata char, bool value) external pure;\n\n    /// Returns the Foundry version.\n    /// Format: <cargo_version>-<tag>+<git_sha_short>.<unix_build_timestamp>.<profile>\n    /// Sample output: 0.3.0-nightly+3cb96bde9b.1737036656.debug\n    /// Note: Build timestamps may vary slightly across platforms due to separate CI jobs.\n    /// For reliable version comparisons, use UNIX format (e.g., >= 1700000000)\n    /// to compare timestamps while ignoring minor time differences.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function getFoundryVersion() external view returns (string memory version);\n\n    /// Returns the RPC url for the given alias.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function rpcUrl(string calldata rpcAlias) external view returns (string memory json);\n\n    /// Returns all rpc urls and their aliases `[alias, url][]`.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function rpcUrls() external view returns (string[2][] memory urls);\n\n    /// Returns all rpc urls and their aliases as structs.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function rpcUrlStructs() external view returns (Rpc[] memory urls);\n\n    /// Returns a Chain struct for specific alias\n    #[cheatcode(group = Testing, safety = Safe)]\n    function getChain(string calldata chainAlias) external view returns (Chain memory chain);\n\n    /// Returns a Chain struct for specific chainId\n    #[cheatcode(group = Testing, safety = Safe)]\n    function getChain(uint256 chainId) external view returns (Chain memory chain);\n\n    /// Suspends execution of the main thread for `duration` milliseconds.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function sleep(uint256 duration) external;\n\n    /// Expects a call to an address with the specified calldata.\n    /// Calldata can either be a strict or a partial match.\n    #[cheatcode(group = Testing, safety = Unsafe)]\n    function expectCall(address callee, bytes calldata data) external;\n\n    /// Expects given number of calls to an address with the specified calldata.\n    #[cheatcode(group = Testing, safety = Unsafe)]\n    function expectCall(address callee, bytes calldata data, uint64 count) external;\n\n    /// Expects a call to an address with the specified `msg.value` and calldata.\n    #[cheatcode(group = Testing, safety = Unsafe)]\n    function expectCall(address callee, uint256 msgValue, bytes calldata data) external;\n\n    /// Expects given number of calls to an address with the specified `msg.value` and calldata.\n    #[cheatcode(group = Testing, safety = Unsafe)]\n    function expectCall(address callee, uint256 msgValue, bytes calldata data, uint64 count) external;\n\n    /// Expect a call to an address with the specified `msg.value`, gas, and calldata.\n    #[cheatcode(group = Testing, safety = Unsafe)]\n    function expectCall(address callee, uint256 msgValue, uint64 gas, bytes calldata data) external;\n\n    /// Expects given number of calls to an address with the specified `msg.value`, gas, and calldata.\n    #[cheatcode(group = Testing, safety = Unsafe)]\n    function expectCall(address callee, uint256 msgValue, uint64 gas, bytes calldata data, uint64 count) external;\n\n    /// Expect a call to an address with the specified `msg.value` and calldata, and a *minimum* amount of gas.\n    #[cheatcode(group = Testing, safety = Unsafe)]\n    function expectCallMinGas(address callee, uint256 msgValue, uint64 minGas, bytes calldata data) external;\n\n    /// Expect given number of calls to an address with the specified `msg.value` and calldata, and a *minimum* amount of gas.\n    #[cheatcode(group = Testing, safety = Unsafe)]\n    function expectCallMinGas(address callee, uint256 msgValue, uint64 minGas, bytes calldata data, uint64 count)\n        external;\n\n    /// Prepare an expected log with (bool checkTopic1, bool checkTopic2, bool checkTopic3, bool checkData.).\n    /// Call this function, then emit an event, then call a function. Internally after the call, we check if\n    /// logs were emitted in the expected order with the expected topics and data (as specified by the booleans).\n    #[cheatcode(group = Testing, safety = Unsafe)]\n    function expectEmit(bool checkTopic1, bool checkTopic2, bool checkTopic3, bool checkData) external;\n\n    /// Same as the previous method, but also checks supplied address against emitting contract.\n    #[cheatcode(group = Testing, safety = Unsafe)]\n    function expectEmit(bool checkTopic1, bool checkTopic2, bool checkTopic3, bool checkData, address emitter)\n        external;\n\n    /// Prepare an expected log with all topic and data checks enabled.\n    /// Call this function, then emit an event, then call a function. Internally after the call, we check if\n    /// logs were emitted in the expected order with the expected topics and data.\n    #[cheatcode(group = Testing, safety = Unsafe)]\n    function expectEmit() external;\n\n    /// Same as the previous method, but also checks supplied address against emitting contract.\n    #[cheatcode(group = Testing, safety = Unsafe)]\n    function expectEmit(address emitter) external;\n\n    /// Expect a given number of logs with the provided topics.\n    #[cheatcode(group = Testing, safety = Unsafe)]\n    function expectEmit(bool checkTopic1, bool checkTopic2, bool checkTopic3, bool checkData, uint64 count) external;\n\n    /// Expect a given number of logs from a specific emitter with the provided topics.\n    #[cheatcode(group = Testing, safety = Unsafe)]\n    function expectEmit(bool checkTopic1, bool checkTopic2, bool checkTopic3, bool checkData, address emitter, uint64 count)\n        external;\n\n    /// Expect a given number of logs with all topic and data checks enabled.\n    #[cheatcode(group = Testing, safety = Unsafe)]\n    function expectEmit(uint64 count) external;\n\n    /// Expect a given number of logs from a specific emitter with all topic and data checks enabled.\n    #[cheatcode(group = Testing, safety = Unsafe)]\n    function expectEmit(address emitter, uint64 count) external;\n\n    /// Prepare an expected anonymous log with (bool checkTopic1, bool checkTopic2, bool checkTopic3, bool checkData.).\n    /// Call this function, then emit an anonymous event, then call a function. Internally after the call, we check if\n    /// logs were emitted in the expected order with the expected topics and data (as specified by the booleans).\n    #[cheatcode(group = Testing, safety = Unsafe)]\n    function expectEmitAnonymous(bool checkTopic0, bool checkTopic1, bool checkTopic2, bool checkTopic3, bool checkData) external;\n\n    /// Same as the previous method, but also checks supplied address against emitting contract.\n    #[cheatcode(group = Testing, safety = Unsafe)]\n    function expectEmitAnonymous(bool checkTopic0, bool checkTopic1, bool checkTopic2, bool checkTopic3, bool checkData, address emitter)\n        external;\n\n    /// Prepare an expected anonymous log with all topic and data checks enabled.\n    /// Call this function, then emit an anonymous event, then call a function. Internally after the call, we check if\n    /// logs were emitted in the expected order with the expected topics and data.\n    #[cheatcode(group = Testing, safety = Unsafe)]\n    function expectEmitAnonymous() external;\n\n    /// Same as the previous method, but also checks supplied address against emitting contract.\n    #[cheatcode(group = Testing, safety = Unsafe)]\n    function expectEmitAnonymous(address emitter) external;\n\n    /// Expects the deployment of the specified bytecode by the specified address using the CREATE opcode\n    #[cheatcode(group = Testing, safety = Unsafe)]\n    function expectCreate(bytes calldata bytecode, address deployer) external;\n\n    /// Expects the deployment of the specified bytecode by the specified address using the CREATE2 opcode\n    #[cheatcode(group = Testing, safety = Unsafe)]\n    function expectCreate2(bytes calldata bytecode, address deployer) external;\n\n    /// Expects an error on next call with any revert data.\n    #[cheatcode(group = Testing, safety = Unsafe)]\n    function expectRevert() external;\n\n    /// Expects an error on next call that exactly matches the revert data.\n    #[cheatcode(group = Testing, safety = Unsafe)]\n    function expectRevert(bytes4 revertData) external;\n\n    /// Expects an error on next call that exactly matches the revert data.\n    #[cheatcode(group = Testing, safety = Unsafe)]\n    function expectRevert(bytes calldata revertData) external;\n\n    /// Expects an error with any revert data on next call to reverter address.\n    #[cheatcode(group = Testing, safety = Unsafe)]\n    function expectRevert(address reverter) external;\n\n    /// Expects an error from reverter address on next call, with any revert data.\n    #[cheatcode(group = Testing, safety = Unsafe)]\n    function expectRevert(bytes4 revertData, address reverter) external;\n\n    /// Expects an error from reverter address on next call, that exactly matches the revert data.\n    #[cheatcode(group = Testing, safety = Unsafe)]\n    function expectRevert(bytes calldata revertData, address reverter) external;\n\n    /// Expects a `count` number of reverts from the upcoming calls with any revert data or reverter.\n    #[cheatcode(group = Testing, safety = Unsafe)]\n    function expectRevert(uint64 count) external;\n\n    /// Expects a `count` number of reverts from the upcoming calls that match the revert data.\n    #[cheatcode(group = Testing, safety = Unsafe)]\n    function expectRevert(bytes4 revertData, uint64 count) external;\n\n    /// Expects a `count` number of reverts from the upcoming calls that exactly match the revert data.\n    #[cheatcode(group = Testing, safety = Unsafe)]\n    function expectRevert(bytes calldata revertData, uint64 count) external;\n\n    /// Expects a `count` number of reverts from the upcoming calls from the reverter address.\n    #[cheatcode(group = Testing, safety = Unsafe)]\n    function expectRevert(address reverter, uint64 count) external;\n\n    /// Expects a `count` number of reverts from the upcoming calls from the reverter address that match the revert data.\n    #[cheatcode(group = Testing, safety = Unsafe)]\n    function expectRevert(bytes4 revertData, address reverter, uint64 count) external;\n\n    /// Expects a `count` number of reverts from the upcoming calls from the reverter address that exactly match the revert data.\n    #[cheatcode(group = Testing, safety = Unsafe)]\n    function expectRevert(bytes calldata revertData, address reverter, uint64 count) external;\n\n    /// Expects an error on next call that starts with the revert data.\n    #[cheatcode(group = Testing, safety = Unsafe)]\n    function expectPartialRevert(bytes4 revertData) external;\n\n    /// Expects an error on next call to reverter address, that starts with the revert data.\n    #[cheatcode(group = Testing, safety = Unsafe)]\n    function expectPartialRevert(bytes4 revertData, address reverter) external;\n\n    /// Expects an error on next cheatcode call with any revert data.\n    #[cheatcode(group = Testing, safety = Unsafe, status = Internal)]\n    function _expectCheatcodeRevert() external;\n\n    /// Expects an error on next cheatcode call that starts with the revert data.\n    #[cheatcode(group = Testing, safety = Unsafe, status = Internal)]\n    function _expectCheatcodeRevert(bytes4 revertData) external;\n\n    /// Expects an error on next cheatcode call that exactly matches the revert data.\n    #[cheatcode(group = Testing, safety = Unsafe, status = Internal)]\n    function _expectCheatcodeRevert(bytes calldata revertData) external;\n\n    /// Only allows memory writes to offsets [0x00, 0x60) ∪ [min, max) in the current subcontext. If any other\n    /// memory is written to, the test will fail. Can be called multiple times to add more ranges to the set.\n    #[cheatcode(group = Testing, safety = Unsafe)]\n    function expectSafeMemory(uint64 min, uint64 max) external;\n\n    /// Stops all safe memory expectation in the current subcontext.\n    #[cheatcode(group = Testing, safety = Unsafe)]\n    function stopExpectSafeMemory() external;\n\n    /// Only allows memory writes to offsets [0x00, 0x60) ∪ [min, max) in the next created subcontext.\n    /// If any other memory is written to, the test will fail. Can be called multiple times to add more ranges\n    /// to the set.\n    #[cheatcode(group = Testing, safety = Unsafe)]\n    function expectSafeMemoryCall(uint64 min, uint64 max) external;\n\n    /// Marks a test as skipped. Must be called at the top level of a test.\n    #[cheatcode(group = Testing, safety = Unsafe)]\n    function skip(bool skipTest) external;\n\n    /// Marks a test as skipped with a reason. Must be called at the top level of a test.\n    #[cheatcode(group = Testing, safety = Unsafe)]\n    function skip(bool skipTest, string calldata reason) external;\n\n    /// Asserts that the given condition is true.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertTrue(bool condition) external pure;\n\n    /// Asserts that the given condition is true and includes error message into revert string on failure.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertTrue(bool condition, string calldata error) external pure;\n\n    /// Asserts that the given condition is false.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertFalse(bool condition) external pure;\n\n    /// Asserts that the given condition is false and includes error message into revert string on failure.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertFalse(bool condition, string calldata error) external pure;\n\n    /// Asserts that two `bool` values are equal.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertEq(bool left, bool right) external pure;\n\n    /// Asserts that two `bool` values are equal and includes error message into revert string on failure.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertEq(bool left, bool right, string calldata error) external pure;\n\n    /// Asserts that two `uint256` values are equal.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertEq(uint256 left, uint256 right) external pure;\n\n    /// Asserts that two `uint256` values are equal and includes error message into revert string on failure.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertEq(uint256 left, uint256 right, string calldata error) external pure;\n\n    /// Asserts that two `int256` values are equal.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertEq(int256 left, int256 right) external pure;\n\n    /// Asserts that two `int256` values are equal and includes error message into revert string on failure.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertEq(int256 left, int256 right, string calldata error) external pure;\n\n    /// Asserts that two `address` values are equal.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertEq(address left, address right) external pure;\n\n    /// Asserts that two `address` values are equal and includes error message into revert string on failure.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertEq(address left, address right, string calldata error) external pure;\n\n    /// Asserts that two `bytes32` values are equal.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertEq(bytes32 left, bytes32 right) external pure;\n\n    /// Asserts that two `bytes32` values are equal and includes error message into revert string on failure.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertEq(bytes32 left, bytes32 right, string calldata error) external pure;\n\n    /// Asserts that two `string` values are equal.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertEq(string calldata left, string calldata right) external pure;\n\n    /// Asserts that two `string` values are equal and includes error message into revert string on failure.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertEq(string calldata left, string calldata right, string calldata error) external pure;\n\n    /// Asserts that two `bytes` values are equal.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertEq(bytes calldata left, bytes calldata right) external pure;\n\n    /// Asserts that two `bytes` values are equal and includes error message into revert string on failure.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertEq(bytes calldata left, bytes calldata right, string calldata error) external pure;\n\n    /// Asserts that two arrays of `bool` values are equal.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertEq(bool[] calldata left, bool[] calldata right) external pure;\n\n    /// Asserts that two arrays of `bool` values are equal and includes error message into revert string on failure.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertEq(bool[] calldata left, bool[] calldata right, string calldata error) external pure;\n\n    /// Asserts that two arrays of `uint256 values are equal.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertEq(uint256[] calldata left, uint256[] calldata right) external pure;\n\n    /// Asserts that two arrays of `uint256` values are equal and includes error message into revert string on failure.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertEq(uint256[] calldata left, uint256[] calldata right, string calldata error) external pure;\n\n    /// Asserts that two arrays of `int256` values are equal.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertEq(int256[] calldata left, int256[] calldata right) external pure;\n\n    /// Asserts that two arrays of `int256` values are equal and includes error message into revert string on failure.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertEq(int256[] calldata left, int256[] calldata right, string calldata error) external pure;\n\n    /// Asserts that two arrays of `address` values are equal.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertEq(address[] calldata left, address[] calldata right) external pure;\n\n    /// Asserts that two arrays of `address` values are equal and includes error message into revert string on failure.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertEq(address[] calldata left, address[] calldata right, string calldata error) external pure;\n\n    /// Asserts that two arrays of `bytes32` values are equal.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertEq(bytes32[] calldata left, bytes32[] calldata right) external pure;\n\n    /// Asserts that two arrays of `bytes32` values are equal and includes error message into revert string on failure.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertEq(bytes32[] calldata left, bytes32[] calldata right, string calldata error) external pure;\n\n    /// Asserts that two arrays of `string` values are equal.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertEq(string[] calldata left, string[] calldata right) external pure;\n\n    /// Asserts that two arrays of `string` values are equal and includes error message into revert string on failure.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertEq(string[] calldata left, string[] calldata right, string calldata error) external pure;\n\n    /// Asserts that two arrays of `bytes` values are equal.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertEq(bytes[] calldata left, bytes[] calldata right) external pure;\n\n    /// Asserts that two arrays of `bytes` values are equal and includes error message into revert string on failure.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertEq(bytes[] calldata left, bytes[] calldata right, string calldata error) external pure;\n\n    /// Asserts that two `uint256` values are equal, formatting them with decimals in failure message.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertEqDecimal(uint256 left, uint256 right, uint256 decimals) external pure;\n\n    /// Asserts that two `uint256` values are equal, formatting them with decimals in failure message.\n    /// Includes error message into revert string on failure.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertEqDecimal(uint256 left, uint256 right, uint256 decimals, string calldata error) external pure;\n\n    /// Asserts that two `int256` values are equal, formatting them with decimals in failure message.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertEqDecimal(int256 left, int256 right, uint256 decimals) external pure;\n\n    /// Asserts that two `int256` values are equal, formatting them with decimals in failure message.\n    /// Includes error message into revert string on failure.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertEqDecimal(int256 left, int256 right, uint256 decimals, string calldata error) external pure;\n\n    /// Asserts that two `bool` values are not equal.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertNotEq(bool left, bool right) external pure;\n\n    /// Asserts that two `bool` values are not equal and includes error message into revert string on failure.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertNotEq(bool left, bool right, string calldata error) external pure;\n\n    /// Asserts that two `uint256` values are not equal.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertNotEq(uint256 left, uint256 right) external pure;\n\n    /// Asserts that two `uint256` values are not equal and includes error message into revert string on failure.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertNotEq(uint256 left, uint256 right, string calldata error) external pure;\n\n    /// Asserts that two `int256` values are not equal.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertNotEq(int256 left, int256 right) external pure;\n\n    /// Asserts that two `int256` values are not equal and includes error message into revert string on failure.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertNotEq(int256 left, int256 right, string calldata error) external pure;\n\n    /// Asserts that two `address` values are not equal.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertNotEq(address left, address right) external pure;\n\n    /// Asserts that two `address` values are not equal and includes error message into revert string on failure.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertNotEq(address left, address right, string calldata error) external pure;\n\n    /// Asserts that two `bytes32` values are not equal.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertNotEq(bytes32 left, bytes32 right) external pure;\n\n    /// Asserts that two `bytes32` values are not equal and includes error message into revert string on failure.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertNotEq(bytes32 left, bytes32 right, string calldata error) external pure;\n\n    /// Asserts that two `string` values are not equal.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertNotEq(string calldata left, string calldata right) external pure;\n\n    /// Asserts that two `string` values are not equal and includes error message into revert string on failure.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertNotEq(string calldata left, string calldata right, string calldata error) external pure;\n\n    /// Asserts that two `bytes` values are not equal.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertNotEq(bytes calldata left, bytes calldata right) external pure;\n\n    /// Asserts that two `bytes` values are not equal and includes error message into revert string on failure.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertNotEq(bytes calldata left, bytes calldata right, string calldata error) external pure;\n\n    /// Asserts that two arrays of `bool` values are not equal.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertNotEq(bool[] calldata left, bool[] calldata right) external pure;\n\n    /// Asserts that two arrays of `bool` values are not equal and includes error message into revert string on failure.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertNotEq(bool[] calldata left, bool[] calldata right, string calldata error) external pure;\n\n    /// Asserts that two arrays of `uint256` values are not equal.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertNotEq(uint256[] calldata left, uint256[] calldata right) external pure;\n\n    /// Asserts that two arrays of `uint256` values are not equal and includes error message into revert string on failure.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertNotEq(uint256[] calldata left, uint256[] calldata right, string calldata error) external pure;\n\n    /// Asserts that two arrays of `int256` values are not equal.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertNotEq(int256[] calldata left, int256[] calldata right) external pure;\n\n    /// Asserts that two arrays of `int256` values are not equal and includes error message into revert string on failure.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertNotEq(int256[] calldata left, int256[] calldata right, string calldata error) external pure;\n\n    /// Asserts that two arrays of `address` values are not equal.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertNotEq(address[] calldata left, address[] calldata right) external pure;\n\n    /// Asserts that two arrays of `address` values are not equal and includes error message into revert string on failure.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertNotEq(address[] calldata left, address[] calldata right, string calldata error) external pure;\n\n    /// Asserts that two arrays of `bytes32` values are not equal.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertNotEq(bytes32[] calldata left, bytes32[] calldata right) external pure;\n\n    /// Asserts that two arrays of `bytes32` values are not equal and includes error message into revert string on failure.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertNotEq(bytes32[] calldata left, bytes32[] calldata right, string calldata error) external pure;\n\n    /// Asserts that two arrays of `string` values are not equal.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertNotEq(string[] calldata left, string[] calldata right) external pure;\n\n    /// Asserts that two arrays of `string` values are not equal and includes error message into revert string on failure.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertNotEq(string[] calldata left, string[] calldata right, string calldata error) external pure;\n\n    /// Asserts that two arrays of `bytes` values are not equal.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertNotEq(bytes[] calldata left, bytes[] calldata right) external pure;\n\n    /// Asserts that two arrays of `bytes` values are not equal and includes error message into revert string on failure.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertNotEq(bytes[] calldata left, bytes[] calldata right, string calldata error) external pure;\n\n    /// Asserts that two `uint256` values are not equal, formatting them with decimals in failure message.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertNotEqDecimal(uint256 left, uint256 right, uint256 decimals) external pure;\n\n    /// Asserts that two `uint256` values are not equal, formatting them with decimals in failure message.\n    /// Includes error message into revert string on failure.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertNotEqDecimal(uint256 left, uint256 right, uint256 decimals, string calldata error) external pure;\n\n    /// Asserts that two `int256` values are not equal, formatting them with decimals in failure message.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertNotEqDecimal(int256 left, int256 right, uint256 decimals) external pure;\n\n    /// Asserts that two `int256` values are not equal, formatting them with decimals in failure message.\n    /// Includes error message into revert string on failure.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertNotEqDecimal(int256 left, int256 right, uint256 decimals, string calldata error) external pure;\n\n    /// Compares two `uint256` values. Expects first value to be greater than second.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertGt(uint256 left, uint256 right) external pure;\n\n    /// Compares two `uint256` values. Expects first value to be greater than second.\n    /// Includes error message into revert string on failure.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertGt(uint256 left, uint256 right, string calldata error) external pure;\n\n    /// Compares two `int256` values. Expects first value to be greater than second.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertGt(int256 left, int256 right) external pure;\n\n    /// Compares two `int256` values. Expects first value to be greater than second.\n    /// Includes error message into revert string on failure.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertGt(int256 left, int256 right, string calldata error) external pure;\n\n    /// Compares two `uint256` values. Expects first value to be greater than second.\n    /// Formats values with decimals in failure message.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertGtDecimal(uint256 left, uint256 right, uint256 decimals) external pure;\n\n    /// Compares two `uint256` values. Expects first value to be greater than second.\n    /// Formats values with decimals in failure message. Includes error message into revert string on failure.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertGtDecimal(uint256 left, uint256 right, uint256 decimals, string calldata error) external pure;\n\n    /// Compares two `int256` values. Expects first value to be greater than second.\n    /// Formats values with decimals in failure message.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertGtDecimal(int256 left, int256 right, uint256 decimals) external pure;\n\n    /// Compares two `int256` values. Expects first value to be greater than second.\n    /// Formats values with decimals in failure message. Includes error message into revert string on failure.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertGtDecimal(int256 left, int256 right, uint256 decimals, string calldata error) external pure;\n\n    /// Compares two `uint256` values. Expects first value to be greater than or equal to second.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertGe(uint256 left, uint256 right) external pure;\n\n    /// Compares two `uint256` values. Expects first value to be greater than or equal to second.\n    /// Includes error message into revert string on failure.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertGe(uint256 left, uint256 right, string calldata error) external pure;\n\n    /// Compares two `int256` values. Expects first value to be greater than or equal to second.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertGe(int256 left, int256 right) external pure;\n\n    /// Compares two `int256` values. Expects first value to be greater than or equal to second.\n    /// Includes error message into revert string on failure.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertGe(int256 left, int256 right, string calldata error) external pure;\n\n    /// Compares two `uint256` values. Expects first value to be greater than or equal to second.\n    /// Formats values with decimals in failure message.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertGeDecimal(uint256 left, uint256 right, uint256 decimals) external pure;\n\n    /// Compares two `uint256` values. Expects first value to be greater than or equal to second.\n    /// Formats values with decimals in failure message. Includes error message into revert string on failure.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertGeDecimal(uint256 left, uint256 right, uint256 decimals, string calldata error) external pure;\n\n    /// Compares two `int256` values. Expects first value to be greater than or equal to second.\n    /// Formats values with decimals in failure message.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertGeDecimal(int256 left, int256 right, uint256 decimals) external pure;\n\n    /// Compares two `int256` values. Expects first value to be greater than or equal to second.\n    /// Formats values with decimals in failure message. Includes error message into revert string on failure.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertGeDecimal(int256 left, int256 right, uint256 decimals, string calldata error) external pure;\n\n    /// Compares two `uint256` values. Expects first value to be less than second.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertLt(uint256 left, uint256 right) external pure;\n\n    /// Compares two `uint256` values. Expects first value to be less than second.\n    /// Includes error message into revert string on failure.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertLt(uint256 left, uint256 right, string calldata error) external pure;\n\n    /// Compares two `int256` values. Expects first value to be less than second.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertLt(int256 left, int256 right) external pure;\n\n    /// Compares two `int256` values. Expects first value to be less than second.\n    /// Includes error message into revert string on failure.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertLt(int256 left, int256 right, string calldata error) external pure;\n\n    /// Compares two `uint256` values. Expects first value to be less than second.\n    /// Formats values with decimals in failure message.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertLtDecimal(uint256 left, uint256 right, uint256 decimals) external pure;\n\n    /// Compares two `uint256` values. Expects first value to be less than second.\n    /// Formats values with decimals in failure message. Includes error message into revert string on failure.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertLtDecimal(uint256 left, uint256 right, uint256 decimals, string calldata error) external pure;\n\n    /// Compares two `int256` values. Expects first value to be less than second.\n    /// Formats values with decimals in failure message.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertLtDecimal(int256 left, int256 right, uint256 decimals) external pure;\n\n    /// Compares two `int256` values. Expects first value to be less than second.\n    /// Formats values with decimals in failure message. Includes error message into revert string on failure.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertLtDecimal(int256 left, int256 right, uint256 decimals, string calldata error) external pure;\n\n    /// Compares two `uint256` values. Expects first value to be less than or equal to second.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertLe(uint256 left, uint256 right) external pure;\n\n    /// Compares two `uint256` values. Expects first value to be less than or equal to second.\n    /// Includes error message into revert string on failure.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertLe(uint256 left, uint256 right, string calldata error) external pure;\n\n    /// Compares two `int256` values. Expects first value to be less than or equal to second.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertLe(int256 left, int256 right) external pure;\n\n    /// Compares two `int256` values. Expects first value to be less than or equal to second.\n    /// Includes error message into revert string on failure.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertLe(int256 left, int256 right, string calldata error) external pure;\n\n    /// Compares two `uint256` values. Expects first value to be less than or equal to second.\n    /// Formats values with decimals in failure message.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertLeDecimal(uint256 left, uint256 right, uint256 decimals) external pure;\n\n    /// Compares two `uint256` values. Expects first value to be less than or equal to second.\n    /// Formats values with decimals in failure message. Includes error message into revert string on failure.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertLeDecimal(uint256 left, uint256 right, uint256 decimals, string calldata error) external pure;\n\n    /// Compares two `int256` values. Expects first value to be less than or equal to second.\n    /// Formats values with decimals in failure message.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertLeDecimal(int256 left, int256 right, uint256 decimals) external pure;\n\n    /// Compares two `int256` values. Expects first value to be less than or equal to second.\n    /// Formats values with decimals in failure message. Includes error message into revert string on failure.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertLeDecimal(int256 left, int256 right, uint256 decimals, string calldata error) external pure;\n\n    /// Compares two `uint256` values. Expects difference to be less than or equal to `maxDelta`.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertApproxEqAbs(uint256 left, uint256 right, uint256 maxDelta) external pure;\n\n    /// Compares two `uint256` values. Expects difference to be less than or equal to `maxDelta`.\n    /// Includes error message into revert string on failure.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertApproxEqAbs(uint256 left, uint256 right, uint256 maxDelta, string calldata error) external pure;\n\n    /// Compares two `int256` values. Expects difference to be less than or equal to `maxDelta`.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertApproxEqAbs(int256 left, int256 right, uint256 maxDelta) external pure;\n\n    /// Compares two `int256` values. Expects difference to be less than or equal to `maxDelta`.\n    /// Includes error message into revert string on failure.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertApproxEqAbs(int256 left, int256 right, uint256 maxDelta, string calldata error) external pure;\n\n    /// Compares two `uint256` values. Expects difference to be less than or equal to `maxDelta`.\n    /// Formats values with decimals in failure message.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertApproxEqAbsDecimal(uint256 left, uint256 right, uint256 maxDelta, uint256 decimals) external pure;\n\n    /// Compares two `uint256` values. Expects difference to be less than or equal to `maxDelta`.\n    /// Formats values with decimals in failure message. Includes error message into revert string on failure.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertApproxEqAbsDecimal(\n        uint256 left,\n        uint256 right,\n        uint256 maxDelta,\n        uint256 decimals,\n        string calldata error\n    ) external pure;\n\n    /// Compares two `int256` values. Expects difference to be less than or equal to `maxDelta`.\n    /// Formats values with decimals in failure message.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertApproxEqAbsDecimal(int256 left, int256 right, uint256 maxDelta, uint256 decimals) external pure;\n\n    /// Compares two `int256` values. Expects difference to be less than or equal to `maxDelta`.\n    /// Formats values with decimals in failure message. Includes error message into revert string on failure.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertApproxEqAbsDecimal(\n        int256 left,\n        int256 right,\n        uint256 maxDelta,\n        uint256 decimals,\n        string calldata error\n    ) external pure;\n\n    /// Compares two `uint256` values. Expects relative difference in percents to be less than or equal to `maxPercentDelta`.\n    /// `maxPercentDelta` is an 18 decimal fixed point number, where 1e18 == 100%\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertApproxEqRel(uint256 left, uint256 right, uint256 maxPercentDelta) external pure;\n\n    /// Compares two `uint256` values. Expects relative difference in percents to be less than or equal to `maxPercentDelta`.\n    /// `maxPercentDelta` is an 18 decimal fixed point number, where 1e18 == 100%\n    /// Includes error message into revert string on failure.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertApproxEqRel(uint256 left, uint256 right, uint256 maxPercentDelta, string calldata error) external pure;\n\n    /// Compares two `int256` values. Expects relative difference in percents to be less than or equal to `maxPercentDelta`.\n    /// `maxPercentDelta` is an 18 decimal fixed point number, where 1e18 == 100%\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertApproxEqRel(int256 left, int256 right, uint256 maxPercentDelta) external pure;\n\n    /// Compares two `int256` values. Expects relative difference in percents to be less than or equal to `maxPercentDelta`.\n    /// `maxPercentDelta` is an 18 decimal fixed point number, where 1e18 == 100%\n    /// Includes error message into revert string on failure.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertApproxEqRel(int256 left, int256 right, uint256 maxPercentDelta, string calldata error) external pure;\n\n    /// Compares two `uint256` values. Expects relative difference in percents to be less than or equal to `maxPercentDelta`.\n    /// `maxPercentDelta` is an 18 decimal fixed point number, where 1e18 == 100%\n    /// Formats values with decimals in failure message.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertApproxEqRelDecimal(\n        uint256 left,\n        uint256 right,\n        uint256 maxPercentDelta,\n        uint256 decimals\n    ) external pure;\n\n    /// Compares two `uint256` values. Expects relative difference in percents to be less than or equal to `maxPercentDelta`.\n    /// `maxPercentDelta` is an 18 decimal fixed point number, where 1e18 == 100%\n    /// Formats values with decimals in failure message. Includes error message into revert string on failure.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertApproxEqRelDecimal(\n        uint256 left,\n        uint256 right,\n        uint256 maxPercentDelta,\n        uint256 decimals,\n        string calldata error\n    ) external pure;\n\n    /// Compares two `int256` values. Expects relative difference in percents to be less than or equal to `maxPercentDelta`.\n    /// `maxPercentDelta` is an 18 decimal fixed point number, where 1e18 == 100%\n    /// Formats values with decimals in failure message.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertApproxEqRelDecimal(\n        int256 left,\n        int256 right,\n        uint256 maxPercentDelta,\n        uint256 decimals\n    ) external pure;\n\n    /// Compares two `int256` values. Expects relative difference in percents to be less than or equal to `maxPercentDelta`.\n    /// `maxPercentDelta` is an 18 decimal fixed point number, where 1e18 == 100%\n    /// Formats values with decimals in failure message. Includes error message into revert string on failure.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function assertApproxEqRelDecimal(\n        int256 left,\n        int256 right,\n        uint256 maxPercentDelta,\n        uint256 decimals,\n        string calldata error\n    ) external pure;\n\n    /// Returns true if the current Foundry version is greater than or equal to the given version.\n    /// The given version string must be in the format `major.minor.patch`.\n    ///\n    /// This is equivalent to `foundryVersionCmp(version) >= 0`.\n    #[cheatcode(group = Testing, safety = Safe)]\n    function foundryVersionAtLeast(string calldata version) external view returns (bool);\n\n    /// Compares the current Foundry version with the given version string.\n    /// The given version string must be in the format `major.minor.patch`.\n    ///\n    /// Returns:\n    /// -1 if current Foundry version is less than the given version\n    /// 0 if current Foundry version equals the given version\n    /// 1 if current Foundry version is greater than the given version\n    ///\n    /// This result can then be used with a comparison operator against `0`.\n    /// For example, to check if the current Foundry version is greater than or equal to `1.0.0`:\n    /// `if (foundryVersionCmp(\"1.0.0\") >= 0) { ... }`\n    #[cheatcode(group = Testing, safety = Safe)]\n    function foundryVersionCmp(string calldata version) external view returns (int256);\n\n    // ======== OS and Filesystem ========\n\n    // -------- Metadata --------\n\n    /// Returns true if the given path points to an existing entity, else returns false.\n    #[cheatcode(group = Filesystem)]\n    function exists(string calldata path) external view returns (bool result);\n\n    /// Given a path, query the file system to get information about a file, directory, etc.\n    #[cheatcode(group = Filesystem)]\n    function fsMetadata(string calldata path) external view returns (FsMetadata memory metadata);\n\n    /// Returns true if the path exists on disk and is pointing at a directory, else returns false.\n    #[cheatcode(group = Filesystem)]\n    function isDir(string calldata path) external view returns (bool result);\n\n    /// Returns true if the path exists on disk and is pointing at a regular file, else returns false.\n    #[cheatcode(group = Filesystem)]\n    function isFile(string calldata path) external view returns (bool result);\n\n    /// Get the path of the current project root.\n    #[cheatcode(group = Filesystem)]\n    function projectRoot() external view returns (string memory path);\n\n    /// Get the source file path of the currently running test or script contract,\n    /// relative to the project root.\n    #[cheatcode(group = Filesystem)]\n    function currentFilePath() external view returns (string memory path);\n\n    /// Returns the time since unix epoch in milliseconds.\n    #[cheatcode(group = Filesystem)]\n    function unixTime() external view returns (uint256 milliseconds);\n\n    // -------- Reading and writing --------\n\n    /// Closes file for reading, resetting the offset and allowing to read it from beginning with readLine.\n    /// `path` is relative to the project root.\n    #[cheatcode(group = Filesystem)]\n    function closeFile(string calldata path) external;\n\n    /// Copies the contents of one file to another. This function will **overwrite** the contents of `to`.\n    /// On success, the total number of bytes copied is returned and it is equal to the length of the `to` file as reported by `metadata`.\n    /// Both `from` and `to` are relative to the project root.\n    #[cheatcode(group = Filesystem)]\n    function copyFile(string calldata from, string calldata to) external returns (uint64 copied);\n\n    /// Creates a new, empty directory at the provided path.\n    /// This cheatcode will revert in the following situations, but is not limited to just these cases:\n    /// - User lacks permissions to modify `path`.\n    /// - A parent of the given path doesn't exist and `recursive` is false.\n    /// - `path` already exists and `recursive` is false.\n    /// `path` is relative to the project root.\n    #[cheatcode(group = Filesystem)]\n    function createDir(string calldata path, bool recursive) external;\n\n    /// Reads the directory at the given path recursively, up to `maxDepth`.\n    /// `maxDepth` defaults to 1, meaning only the direct children of the given directory will be returned.\n    /// Follows symbolic links if `followLinks` is true.\n    #[cheatcode(group = Filesystem)]\n    function readDir(string calldata path) external view returns (DirEntry[] memory entries);\n    /// See `readDir(string)`.\n    #[cheatcode(group = Filesystem)]\n    function readDir(string calldata path, uint64 maxDepth) external view returns (DirEntry[] memory entries);\n    /// See `readDir(string)`.\n    #[cheatcode(group = Filesystem)]\n    function readDir(string calldata path, uint64 maxDepth, bool followLinks)\n        external\n        view\n        returns (DirEntry[] memory entries);\n\n    /// Reads the entire content of file to string. `path` is relative to the project root.\n    #[cheatcode(group = Filesystem)]\n    function readFile(string calldata path) external view returns (string memory data);\n\n    /// Reads the entire content of file as binary. `path` is relative to the project root.\n    #[cheatcode(group = Filesystem)]\n    function readFileBinary(string calldata path) external view returns (bytes memory data);\n\n    /// Reads next line of file to string.\n    #[cheatcode(group = Filesystem)]\n    function readLine(string calldata path) external view returns (string memory line);\n\n    /// Reads a symbolic link, returning the path that the link points to.\n    /// This cheatcode will revert in the following situations, but is not limited to just these cases:\n    /// - `path` is not a symbolic link.\n    /// - `path` does not exist.\n    #[cheatcode(group = Filesystem)]\n    function readLink(string calldata linkPath) external view returns (string memory targetPath);\n\n    /// Removes a directory at the provided path.\n    /// This cheatcode will revert in the following situations, but is not limited to just these cases:\n    /// - `path` doesn't exist.\n    /// - `path` isn't a directory.\n    /// - User lacks permissions to modify `path`.\n    /// - The directory is not empty and `recursive` is false.\n    /// `path` is relative to the project root.\n    #[cheatcode(group = Filesystem)]\n    function removeDir(string calldata path, bool recursive) external;\n\n    /// Removes a file from the filesystem.\n    /// This cheatcode will revert in the following situations, but is not limited to just these cases:\n    /// - `path` points to a directory.\n    /// - The file doesn't exist.\n    /// - The user lacks permissions to remove the file.\n    /// `path` is relative to the project root.\n    #[cheatcode(group = Filesystem)]\n    function removeFile(string calldata path) external;\n\n    /// Writes data to file, creating a file if it does not exist, and entirely replacing its contents if it does.\n    /// `path` is relative to the project root.\n    #[cheatcode(group = Filesystem)]\n    function writeFile(string calldata path, string calldata data) external;\n\n    /// Writes binary data to a file, creating a file if it does not exist, and entirely replacing its contents if it does.\n    /// `path` is relative to the project root.\n    #[cheatcode(group = Filesystem)]\n    function writeFileBinary(string calldata path, bytes calldata data) external;\n\n    /// Writes line to file, creating a file if it does not exist.\n    /// `path` is relative to the project root.\n    #[cheatcode(group = Filesystem)]\n    function writeLine(string calldata path, string calldata data) external;\n\n    /// Gets the artifact path from code (aka. creation code).\n    #[cheatcode(group = Filesystem)]\n    function getArtifactPathByCode(bytes calldata code) external view returns (string memory path);\n\n    /// Gets the artifact path from deployed code (aka. runtime code).\n    #[cheatcode(group = Filesystem)]\n    function getArtifactPathByDeployedCode(bytes calldata deployedCode) external view returns (string memory path);\n\n    /// Gets the creation bytecode from an artifact file. Takes in the relative path to the json file or the path to the\n    /// artifact in the form of <path>:<contract>:<version> where <contract> and <version> parts are optional.\n    #[cheatcode(group = Filesystem)]\n    function getCode(string calldata artifactPath) external view returns (bytes memory creationBytecode);\n\n    /// Deploys a contract from an artifact file. Takes in the relative path to the json file or the path to the\n    /// artifact in the form of <path>:<contract>:<version> where <contract> and <version> parts are optional.\n    /// Reverts if the target artifact contains unlinked library placeholders.\n    #[cheatcode(group = Filesystem)]\n    function deployCode(string calldata artifactPath) external returns (address deployedAddress);\n\n    /// Deploys a contract from an artifact file. Takes in the relative path to the json file or the path to the\n    /// artifact in the form of <path>:<contract>:<version> where <contract> and <version> parts are optional.\n    /// Reverts if the target artifact contains unlinked library placeholders.\n    ///\n    /// Additionally accepts abi-encoded constructor arguments.\n    #[cheatcode(group = Filesystem)]\n    function deployCode(string calldata artifactPath, bytes calldata constructorArgs) external returns (address deployedAddress);\n\n    /// Deploys a contract from an artifact file. Takes in the relative path to the json file or the path to the\n    /// artifact in the form of <path>:<contract>:<version> where <contract> and <version> parts are optional.\n    /// Reverts if the target artifact contains unlinked library placeholders.\n    ///\n    /// Additionally accepts `msg.value`.\n    #[cheatcode(group = Filesystem)]\n    function deployCode(string calldata artifactPath, uint256 value) external returns (address deployedAddress);\n\n    /// Deploys a contract from an artifact file. Takes in the relative path to the json file or the path to the\n    /// artifact in the form of <path>:<contract>:<version> where <contract> and <version> parts are optional.\n    /// Reverts if the target artifact contains unlinked library placeholders.\n    ///\n    /// Additionally accepts abi-encoded constructor arguments and `msg.value`.\n    #[cheatcode(group = Filesystem)]\n    function deployCode(string calldata artifactPath, bytes calldata constructorArgs, uint256 value) external returns (address deployedAddress);\n\n    /// Deploys a contract from an artifact file, using the CREATE2 salt. Takes in the relative path to the json file or the path to the\n    /// artifact in the form of <path>:<contract>:<version> where <contract> and <version> parts are optional.\n    /// Reverts if the target artifact contains unlinked library placeholders.\n    #[cheatcode(group = Filesystem)]\n    function deployCode(string calldata artifactPath, bytes32 salt) external returns (address deployedAddress);\n\n    /// Deploys a contract from an artifact file, using the CREATE2 salt. Takes in the relative path to the json file or the path to the\n    /// artifact in the form of <path>:<contract>:<version> where <contract> and <version> parts are optional.\n    /// Reverts if the target artifact contains unlinked library placeholders.\n    ///\n    /// Additionally accepts abi-encoded constructor arguments.\n    #[cheatcode(group = Filesystem)]\n    function deployCode(string calldata artifactPath, bytes calldata constructorArgs, bytes32 salt) external returns (address deployedAddress);\n\n    /// Deploys a contract from an artifact file, using the CREATE2 salt. Takes in the relative path to the json file or the path to the\n    /// artifact in the form of <path>:<contract>:<version> where <contract> and <version> parts are optional.\n    /// Reverts if the target artifact contains unlinked library placeholders.\n    ///\n    /// Additionally accepts `msg.value`.\n    #[cheatcode(group = Filesystem)]\n    function deployCode(string calldata artifactPath, uint256 value, bytes32 salt) external returns (address deployedAddress);\n\n    /// Deploys a contract from an artifact file, using the CREATE2 salt. Takes in the relative path to the json file or the path to the\n    /// artifact in the form of <path>:<contract>:<version> where <contract> and <version> parts are optional.\n    /// Reverts if the target artifact contains unlinked library placeholders.\n    ///\n    /// Additionally accepts abi-encoded constructor arguments and `msg.value`.\n    #[cheatcode(group = Filesystem)]\n    function deployCode(string calldata artifactPath, bytes calldata constructorArgs, uint256 value, bytes32 salt) external returns (address deployedAddress);\n\n    /// Gets the deployed bytecode from an artifact file. Takes in the relative path to the json file or the path to the\n    /// artifact in the form of <path>:<contract>:<version> where <contract> and <version> parts are optional.\n    #[cheatcode(group = Filesystem)]\n    function getDeployedCode(string calldata artifactPath) external view returns (bytes memory runtimeBytecode);\n\n    /// Returns the most recent broadcast for the given contract on `chainId` matching `txType`.\n    ///\n    /// For example:\n    ///\n    /// The most recent deployment can be fetched by passing `txType` as `CREATE` or `CREATE2`.\n    ///\n    /// The most recent call can be fetched by passing `txType` as `CALL`.\n    #[cheatcode(group = Filesystem)]\n    function getBroadcast(string calldata contractName, uint64 chainId, BroadcastTxType txType) external view returns (BroadcastTxSummary memory);\n\n    /// Returns all broadcasts for the given contract on `chainId` with the specified `txType`.\n    ///\n    /// Sorted such that the most recent broadcast is the first element, and the oldest is the last. i.e descending order of BroadcastTxSummary.blockNumber.\n    #[cheatcode(group = Filesystem)]\n    function getBroadcasts(string calldata contractName, uint64 chainId, BroadcastTxType txType) external view returns (BroadcastTxSummary[] memory);\n\n    /// Returns all broadcasts for the given contract on `chainId`.\n    ///\n    /// Sorted such that the most recent broadcast is the first element, and the oldest is the last. i.e descending order of BroadcastTxSummary.blockNumber.\n    #[cheatcode(group = Filesystem)]\n    function getBroadcasts(string calldata contractName, uint64 chainId) external view returns (BroadcastTxSummary[] memory);\n\n    /// Returns the most recent deployment for the current `chainId`.\n    #[cheatcode(group = Filesystem)]\n    function getDeployment(string calldata contractName) external view returns (address deployedAddress);\n\n    /// Returns the most recent deployment for the given contract on `chainId`\n    #[cheatcode(group = Filesystem)]\n    function getDeployment(string calldata contractName, uint64 chainId) external view returns (address deployedAddress);\n\n    /// Returns all deployments for the given contract on `chainId`\n    ///\n    /// Sorted in descending order of deployment time i.e descending order of BroadcastTxSummary.blockNumber.\n    ///\n    /// The most recent deployment is the first element, and the oldest is the last.\n    #[cheatcode(group = Filesystem)]\n    function getDeployments(string calldata contractName, uint64 chainId) external view returns (address[] memory deployedAddresses);\n\n    // -------- Foreign Function Interface --------\n\n    /// Performs a foreign function call via the terminal.\n    #[cheatcode(group = Filesystem)]\n    function ffi(string[] calldata commandInput) external returns (bytes memory result);\n\n    /// Performs a foreign function call via terminal and returns the exit code, stdout, and stderr.\n    #[cheatcode(group = Filesystem)]\n    function tryFfi(string[] calldata commandInput) external returns (FfiResult memory result);\n\n    // -------- User Interaction --------\n\n    /// Prompts the user for a string value in the terminal.\n    #[cheatcode(group = Filesystem)]\n    function prompt(string calldata promptText) external returns (string memory input);\n\n    /// Prompts the user for a hidden string value in the terminal.\n    #[cheatcode(group = Filesystem)]\n    function promptSecret(string calldata promptText) external returns (string memory input);\n\n    /// Prompts the user for hidden uint256 in the terminal (usually pk).\n    #[cheatcode(group = Filesystem)]\n    function promptSecretUint(string calldata promptText) external returns (uint256);\n\n    /// Prompts the user for an address in the terminal.\n    #[cheatcode(group = Filesystem)]\n    function promptAddress(string calldata promptText) external returns (address);\n\n    /// Prompts the user for uint256 in the terminal.\n    #[cheatcode(group = Filesystem)]\n    function promptUint(string calldata promptText) external returns (uint256);\n\n    // ======== Environment Variables ========\n\n    /// Resolves the env variable placeholders of a given input string.\n    #[cheatcode(group = Environment)]\n    function resolveEnv(string calldata input) external returns (string memory);\n\n    /// Sets environment variables.\n    #[cheatcode(group = Environment)]\n    function setEnv(string calldata name, string calldata value) external;\n\n    /// Gets the environment variable `name` and returns true if it exists, else returns false.\n    #[cheatcode(group = Environment)]\n    function envExists(string calldata name) external view returns (bool result);\n\n    /// Gets the environment variable `name` and parses it as `bool`.\n    /// Reverts if the variable was not found or could not be parsed.\n    #[cheatcode(group = Environment)]\n    function envBool(string calldata name) external view returns (bool value);\n    /// Gets the environment variable `name` and parses it as `uint256`.\n    /// Reverts if the variable was not found or could not be parsed.\n    #[cheatcode(group = Environment)]\n    function envUint(string calldata name) external view returns (uint256 value);\n    /// Gets the environment variable `name` and parses it as `int256`.\n    /// Reverts if the variable was not found or could not be parsed.\n    #[cheatcode(group = Environment)]\n    function envInt(string calldata name) external view returns (int256 value);\n    /// Gets the environment variable `name` and parses it as `address`.\n    /// Reverts if the variable was not found or could not be parsed.\n    #[cheatcode(group = Environment)]\n    function envAddress(string calldata name) external view returns (address value);\n    /// Gets the environment variable `name` and parses it as `bytes32`.\n    /// Reverts if the variable was not found or could not be parsed.\n    #[cheatcode(group = Environment)]\n    function envBytes32(string calldata name) external view returns (bytes32 value);\n    /// Gets the environment variable `name` and parses it as `string`.\n    /// Reverts if the variable was not found or could not be parsed.\n    #[cheatcode(group = Environment)]\n    function envString(string calldata name) external view returns (string memory value);\n    /// Gets the environment variable `name` and parses it as `bytes`.\n    /// Reverts if the variable was not found or could not be parsed.\n    #[cheatcode(group = Environment)]\n    function envBytes(string calldata name) external view returns (bytes memory value);\n\n    /// Gets the environment variable `name` and parses it as an array of `bool`, delimited by `delim`.\n    /// Reverts if the variable was not found or could not be parsed.\n    #[cheatcode(group = Environment)]\n    function envBool(string calldata name, string calldata delim) external view returns (bool[] memory value);\n    /// Gets the environment variable `name` and parses it as an array of `uint256`, delimited by `delim`.\n    /// Reverts if the variable was not found or could not be parsed.\n    #[cheatcode(group = Environment)]\n    function envUint(string calldata name, string calldata delim) external view returns (uint256[] memory value);\n    /// Gets the environment variable `name` and parses it as an array of `int256`, delimited by `delim`.\n    /// Reverts if the variable was not found or could not be parsed.\n    #[cheatcode(group = Environment)]\n    function envInt(string calldata name, string calldata delim) external view returns (int256[] memory value);\n    /// Gets the environment variable `name` and parses it as an array of `address`, delimited by `delim`.\n    /// Reverts if the variable was not found or could not be parsed.\n    #[cheatcode(group = Environment)]\n    function envAddress(string calldata name, string calldata delim) external view returns (address[] memory value);\n    /// Gets the environment variable `name` and parses it as an array of `bytes32`, delimited by `delim`.\n    /// Reverts if the variable was not found or could not be parsed.\n    #[cheatcode(group = Environment)]\n    function envBytes32(string calldata name, string calldata delim) external view returns (bytes32[] memory value);\n    /// Gets the environment variable `name` and parses it as an array of `string`, delimited by `delim`.\n    /// Reverts if the variable was not found or could not be parsed.\n    #[cheatcode(group = Environment)]\n    function envString(string calldata name, string calldata delim) external view returns (string[] memory value);\n    /// Gets the environment variable `name` and parses it as an array of `bytes`, delimited by `delim`.\n    /// Reverts if the variable was not found or could not be parsed.\n    #[cheatcode(group = Environment)]\n    function envBytes(string calldata name, string calldata delim) external view returns (bytes[] memory value);\n\n    /// Gets the environment variable `name` and parses it as `bool`.\n    /// Reverts if the variable could not be parsed.\n    /// Returns `defaultValue` if the variable was not found.\n    #[cheatcode(group = Environment)]\n    function envOr(string calldata name, bool defaultValue) external view returns (bool value);\n    /// Gets the environment variable `name` and parses it as `uint256`.\n    /// Reverts if the variable could not be parsed.\n    /// Returns `defaultValue` if the variable was not found.\n    #[cheatcode(group = Environment)]\n    function envOr(string calldata name, uint256 defaultValue) external view returns (uint256 value);\n    /// Gets the environment variable `name` and parses it as `int256`.\n    /// Reverts if the variable could not be parsed.\n    /// Returns `defaultValue` if the variable was not found.\n    #[cheatcode(group = Environment)]\n    function envOr(string calldata name, int256 defaultValue) external view returns (int256 value);\n    /// Gets the environment variable `name` and parses it as `address`.\n    /// Reverts if the variable could not be parsed.\n    /// Returns `defaultValue` if the variable was not found.\n    #[cheatcode(group = Environment)]\n    function envOr(string calldata name, address defaultValue) external view returns (address value);\n    /// Gets the environment variable `name` and parses it as `bytes32`.\n    /// Reverts if the variable could not be parsed.\n    /// Returns `defaultValue` if the variable was not found.\n    #[cheatcode(group = Environment)]\n    function envOr(string calldata name, bytes32 defaultValue) external view returns (bytes32 value);\n    /// Gets the environment variable `name` and parses it as `string`.\n    /// Reverts if the variable could not be parsed.\n    /// Returns `defaultValue` if the variable was not found.\n    #[cheatcode(group = Environment)]\n    function envOr(string calldata name, string calldata defaultValue) external view returns (string memory value);\n    /// Gets the environment variable `name` and parses it as `bytes`.\n    /// Reverts if the variable could not be parsed.\n    /// Returns `defaultValue` if the variable was not found.\n    #[cheatcode(group = Environment)]\n    function envOr(string calldata name, bytes calldata defaultValue) external view returns (bytes memory value);\n\n    /// Gets the environment variable `name` and parses it as an array of `bool`, delimited by `delim`.\n    /// Reverts if the variable could not be parsed.\n    /// Returns `defaultValue` if the variable was not found.\n    #[cheatcode(group = Environment)]\n    function envOr(string calldata name, string calldata delim, bool[] calldata defaultValue)\n        external view\n        returns (bool[] memory value);\n    /// Gets the environment variable `name` and parses it as an array of `uint256`, delimited by `delim`.\n    /// Reverts if the variable could not be parsed.\n    /// Returns `defaultValue` if the variable was not found.\n    #[cheatcode(group = Environment)]\n    function envOr(string calldata name, string calldata delim, uint256[] calldata defaultValue)\n        external view\n        returns (uint256[] memory value);\n    /// Gets the environment variable `name` and parses it as an array of `int256`, delimited by `delim`.\n    /// Reverts if the variable could not be parsed.\n    /// Returns `defaultValue` if the variable was not found.\n    #[cheatcode(group = Environment)]\n    function envOr(string calldata name, string calldata delim, int256[] calldata defaultValue)\n        external view\n        returns (int256[] memory value);\n    /// Gets the environment variable `name` and parses it as an array of `address`, delimited by `delim`.\n    /// Reverts if the variable could not be parsed.\n    /// Returns `defaultValue` if the variable was not found.\n    #[cheatcode(group = Environment)]\n    function envOr(string calldata name, string calldata delim, address[] calldata defaultValue)\n        external view\n        returns (address[] memory value);\n    /// Gets the environment variable `name` and parses it as an array of `bytes32`, delimited by `delim`.\n    /// Reverts if the variable could not be parsed.\n    /// Returns `defaultValue` if the variable was not found.\n    #[cheatcode(group = Environment)]\n    function envOr(string calldata name, string calldata delim, bytes32[] calldata defaultValue)\n        external view\n        returns (bytes32[] memory value);\n    /// Gets the environment variable `name` and parses it as an array of `string`, delimited by `delim`.\n    /// Reverts if the variable could not be parsed.\n    /// Returns `defaultValue` if the variable was not found.\n    #[cheatcode(group = Environment)]\n    function envOr(string calldata name, string calldata delim, string[] calldata defaultValue)\n        external view\n        returns (string[] memory value);\n    /// Gets the environment variable `name` and parses it as an array of `bytes`, delimited by `delim`.\n    /// Reverts if the variable could not be parsed.\n    /// Returns `defaultValue` if the variable was not found.\n    #[cheatcode(group = Environment)]\n    function envOr(string calldata name, string calldata delim, bytes[] calldata defaultValue)\n        external view\n        returns (bytes[] memory value);\n\n    /// Returns true if `forge` command was executed in given context.\n    #[cheatcode(group = Environment)]\n    function isContext(ForgeContext context) external view returns (bool result);\n\n    // ======== Scripts ========\n    // -------- Broadcasting Transactions --------\n\n    /// Has the next call (at this call depth only) create transactions that can later be signed and sent onchain.\n    ///\n    /// Broadcasting address is determined by checking the following in order:\n    /// 1. If `--sender` argument was provided, that address is used.\n    /// 2. If exactly one signer (e.g. private key, hw wallet, keystore) is set when `forge broadcast` is invoked, that signer is used.\n    /// 3. Otherwise, default foundry sender (1804c8AB1F12E6bbf3894d4083f33e07309d1f38) is used.\n    #[cheatcode(group = Scripting)]\n    function broadcast() external;\n\n    /// Has the next call (at this call depth only) create a transaction with the address provided\n    /// as the sender that can later be signed and sent onchain.\n    #[cheatcode(group = Scripting)]\n    function broadcast(address signer) external;\n\n    /// Has the next call (at this call depth only) create a transaction with the private key\n    /// provided as the sender that can later be signed and sent onchain.\n    #[cheatcode(group = Scripting)]\n    function broadcast(uint256 privateKey) external;\n\n    /// Has all subsequent calls (at this call depth only) create transactions that can later be signed and sent onchain.\n    ///\n    /// Broadcasting address is determined by checking the following in order:\n    /// 1. If `--sender` argument was provided, that address is used.\n    /// 2. If exactly one signer (e.g. private key, hw wallet, keystore) is set when `forge broadcast` is invoked, that signer is used.\n    /// 3. Otherwise, default foundry sender (1804c8AB1F12E6bbf3894d4083f33e07309d1f38) is used.\n    #[cheatcode(group = Scripting)]\n    function startBroadcast() external;\n\n    /// Has all subsequent calls (at this call depth only) create transactions with the address\n    /// provided that can later be signed and sent onchain.\n    #[cheatcode(group = Scripting)]\n    function startBroadcast(address signer) external;\n\n    /// Has all subsequent calls (at this call depth only) create transactions with the private key\n    /// provided that can later be signed and sent onchain.\n    #[cheatcode(group = Scripting)]\n    function startBroadcast(uint256 privateKey) external;\n\n    /// Stops collecting onchain transactions.\n    #[cheatcode(group = Scripting)]\n    function stopBroadcast() external;\n\n    /// Takes a signed transaction and broadcasts it to the network.\n    #[cheatcode(group = Scripting)]\n    function broadcastRawTransaction(bytes calldata data) external;\n\n    /// Sign an EIP-7702 authorization for delegation\n    #[cheatcode(group = Scripting)]\n    function signDelegation(address implementation, uint256 privateKey) external returns (SignedDelegation memory signedDelegation);\n\n    /// Sign an EIP-7702 authorization for delegation for specific nonce\n    #[cheatcode(group = Scripting)]\n    function signDelegation(address implementation, uint256 privateKey, uint64 nonce) external returns (SignedDelegation memory signedDelegation);\n\n    /// Sign an EIP-7702 authorization for delegation, with optional cross-chain validity.\n    #[cheatcode(group = Scripting)]\n    function signDelegation(address implementation, uint256 privateKey, bool crossChain) external returns (SignedDelegation memory signedDelegation);\n\n    /// Designate the next call as an EIP-7702 transaction\n    #[cheatcode(group = Scripting)]\n    function attachDelegation(SignedDelegation calldata signedDelegation) external;\n\n    /// Designate the next call as an EIP-7702 transaction, with optional cross-chain validity.\n    #[cheatcode(group = Scripting)]\n    function attachDelegation(SignedDelegation calldata signedDelegation, bool crossChain) external;\n\n    /// Sign an EIP-7702 authorization and designate the next call as an EIP-7702 transaction\n    #[cheatcode(group = Scripting)]\n    function signAndAttachDelegation(address implementation, uint256 privateKey) external returns (SignedDelegation memory signedDelegation);\n\n    /// Sign an EIP-7702 authorization and designate the next call as an EIP-7702 transaction for specific nonce\n    #[cheatcode(group = Scripting)]\n    function signAndAttachDelegation(address implementation, uint256 privateKey, uint64 nonce) external returns (SignedDelegation memory signedDelegation);\n\n    /// Sign an EIP-7702 authorization and designate the next call as an EIP-7702 transaction, with optional cross-chain validity.\n    #[cheatcode(group = Scripting)]\n    function signAndAttachDelegation(address implementation, uint256 privateKey, bool crossChain) external returns (SignedDelegation memory signedDelegation);\n\n    /// Attach an EIP-4844 blob to the next call\n    #[cheatcode(group = Scripting)]\n    function attachBlob(bytes calldata blob) external;\n\n    /// Returns addresses of available unlocked wallets in the script environment.\n    #[cheatcode(group = Scripting)]\n    function getWallets() external view returns (address[] memory wallets);\n\n    // ======== Utilities ========\n\n    // -------- Strings --------\n\n    /// Converts the given value to a `string`.\n    #[cheatcode(group = String)]\n    function toString(address value) external pure returns (string memory stringifiedValue);\n    /// Converts the given value to a `string`.\n    #[cheatcode(group = String)]\n    function toString(bytes calldata value) external pure returns (string memory stringifiedValue);\n    /// Converts the given value to a `string`.\n    #[cheatcode(group = String)]\n    function toString(bytes32 value) external pure returns (string memory stringifiedValue);\n    /// Converts the given value to a `string`.\n    #[cheatcode(group = String)]\n    function toString(bool value) external pure returns (string memory stringifiedValue);\n    /// Converts the given value to a `string`.\n    #[cheatcode(group = String)]\n    function toString(uint256 value) external pure returns (string memory stringifiedValue);\n    /// Converts the given value to a `string`.\n    #[cheatcode(group = String)]\n    function toString(int256 value) external pure returns (string memory stringifiedValue);\n\n    /// Parses the given `string` into `bytes`.\n    #[cheatcode(group = String)]\n    function parseBytes(string calldata stringifiedValue) external pure returns (bytes memory parsedValue);\n    /// Parses the given `string` into an `address`.\n    #[cheatcode(group = String)]\n    function parseAddress(string calldata stringifiedValue) external pure returns (address parsedValue);\n    /// Parses the given `string` into a `uint256`.\n    #[cheatcode(group = String)]\n    function parseUint(string calldata stringifiedValue) external pure returns (uint256 parsedValue);\n    /// Parses the given `string` into a `int256`.\n    #[cheatcode(group = String)]\n    function parseInt(string calldata stringifiedValue) external pure returns (int256 parsedValue);\n    /// Parses the given `string` into a `bytes32`.\n    #[cheatcode(group = String)]\n    function parseBytes32(string calldata stringifiedValue) external pure returns (bytes32 parsedValue);\n    /// Parses the given `string` into a `bool`.\n    #[cheatcode(group = String)]\n    function parseBool(string calldata stringifiedValue) external pure returns (bool parsedValue);\n\n    /// Converts the given `string` value to Lowercase.\n    #[cheatcode(group = String)]\n    function toLowercase(string calldata input) external pure returns (string memory output);\n    /// Converts the given `string` value to Uppercase.\n    #[cheatcode(group = String)]\n    function toUppercase(string calldata input) external pure returns (string memory output);\n    /// Trims leading and trailing whitespace from the given `string` value.\n    #[cheatcode(group = String)]\n    function trim(string calldata input) external pure returns (string memory output);\n    /// Replaces occurrences of `from` in the given `string` with `to`.\n    #[cheatcode(group = String)]\n    function replace(string calldata input, string calldata from, string calldata to) external pure returns (string memory output);\n    /// Splits the given `string` into an array of strings divided by the `delimiter`.\n    #[cheatcode(group = String)]\n    function split(string calldata input, string calldata delimiter) external pure returns (string[] memory outputs);\n    /// Returns the index of the first occurrence of a `key` in an `input` string.\n    /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `key` is not found.\n    /// Returns 0 in case of an empty `key`.\n    #[cheatcode(group = String)]\n    function indexOf(string calldata input, string calldata key) external pure returns (uint256);\n    /// Returns true if `search` is found in `subject`, false otherwise.\n    #[cheatcode(group = String)]\n    function contains(string calldata subject, string calldata search) external pure returns (bool result);\n\n    // ======== JSON Parsing and Manipulation ========\n\n    // -------- Reading --------\n\n    // NOTE: Please read https://book.getfoundry.sh/cheatcodes/parse-json to understand the\n    // limitations and caveats of the JSON parsing cheats.\n\n    /// Checks if `key` exists in a JSON object\n    /// `keyExists` is being deprecated in favor of `keyExistsJson`. It will be removed in future versions.\n    #[cheatcode(group = Json, status = Deprecated(Some(\"replaced by `keyExistsJson`\")))]\n    function keyExists(string calldata json, string calldata key) external view returns (bool);\n    /// Checks if `key` exists in a JSON object.\n    #[cheatcode(group = Json)]\n    function keyExistsJson(string calldata json, string calldata key) external view returns (bool);\n\n    /// ABI-encodes a JSON object.\n    #[cheatcode(group = Json)]\n    function parseJson(string calldata json) external pure returns (bytes memory abiEncodedData);\n    /// ABI-encodes a JSON object at `key`.\n    #[cheatcode(group = Json)]\n    function parseJson(string calldata json, string calldata key) external pure returns (bytes memory abiEncodedData);\n\n    // The following parseJson cheatcodes will do type coercion, for the type that they indicate.\n    // For example, parseJsonUint will coerce all values to a uint256. That includes stringified numbers '12.'\n    // and hex numbers '0xEF.'.\n    // Type coercion works ONLY for discrete values or arrays. That means that the key must return a value or array, not\n    // a JSON object.\n\n    /// Parses a string of JSON data at `key` and coerces it to `uint256`.\n    #[cheatcode(group = Json)]\n    function parseJsonUint(string calldata json, string calldata key) external pure returns (uint256);\n    /// Parses a string of JSON data at `key` and coerces it to `uint256[]`.\n    #[cheatcode(group = Json)]\n    function parseJsonUintArray(string calldata json, string calldata key) external pure returns (uint256[] memory);\n    /// Parses a string of JSON data at `key` and coerces it to `int256`.\n    #[cheatcode(group = Json)]\n    function parseJsonInt(string calldata json, string calldata key) external pure returns (int256);\n    /// Parses a string of JSON data at `key` and coerces it to `int256[]`.\n    #[cheatcode(group = Json)]\n    function parseJsonIntArray(string calldata json, string calldata key) external pure returns (int256[] memory);\n    /// Parses a string of JSON data at `key` and coerces it to `bool`.\n    #[cheatcode(group = Json)]\n    function parseJsonBool(string calldata json, string calldata key) external pure returns (bool);\n    /// Parses a string of JSON data at `key` and coerces it to `bool[]`.\n    #[cheatcode(group = Json)]\n    function parseJsonBoolArray(string calldata json, string calldata key) external pure returns (bool[] memory);\n    /// Parses a string of JSON data at `key` and coerces it to `address`.\n    #[cheatcode(group = Json)]\n    function parseJsonAddress(string calldata json, string calldata key) external pure returns (address);\n    /// Parses a string of JSON data at `key` and coerces it to `address[]`.\n    #[cheatcode(group = Json)]\n    function parseJsonAddressArray(string calldata json, string calldata key)\n        external\n        pure\n        returns (address[] memory);\n    /// Parses a string of JSON data at `key` and coerces it to `string`.\n    #[cheatcode(group = Json)]\n    function parseJsonString(string calldata json, string calldata key) external pure returns (string memory);\n    /// Parses a string of JSON data at `key` and coerces it to `string[]`.\n    #[cheatcode(group = Json)]\n    function parseJsonStringArray(string calldata json, string calldata key) external pure returns (string[] memory);\n    /// Parses a string of JSON data at `key` and coerces it to `bytes`.\n    #[cheatcode(group = Json)]\n    function parseJsonBytes(string calldata json, string calldata key) external pure returns (bytes memory);\n    /// Parses a string of JSON data at `key` and coerces it to `bytes[]`.\n    #[cheatcode(group = Json)]\n    function parseJsonBytesArray(string calldata json, string calldata key) external pure returns (bytes[] memory);\n    /// Parses a string of JSON data at `key` and coerces it to `bytes32`.\n    #[cheatcode(group = Json)]\n    function parseJsonBytes32(string calldata json, string calldata key) external pure returns (bytes32);\n    /// Parses a string of JSON data at `key` and coerces it to `bytes32[]`.\n    #[cheatcode(group = Json)]\n    function parseJsonBytes32Array(string calldata json, string calldata key)\n        external\n        pure\n        returns (bytes32[] memory);\n\n    /// Parses a string of JSON data and coerces it to type corresponding to `typeDescription`.\n    #[cheatcode(group = Json)]\n    function parseJsonType(string calldata json, string calldata typeDescription) external pure returns (bytes memory);\n    /// Parses a string of JSON data at `key` and coerces it to type corresponding to `typeDescription`.\n    #[cheatcode(group = Json)]\n    function parseJsonType(string calldata json, string calldata key, string calldata typeDescription) external pure returns (bytes memory);\n    /// Parses a string of JSON data at `key` and coerces it to type array corresponding to `typeDescription`.\n    #[cheatcode(group = Json)]\n    function parseJsonTypeArray(string calldata json, string calldata key, string calldata typeDescription)\n        external\n        pure\n        returns (bytes memory);\n\n    /// Returns an array of all the keys in a JSON object.\n    #[cheatcode(group = Json)]\n    function parseJsonKeys(string calldata json, string calldata key) external pure returns (string[] memory keys);\n\n    // -------- Writing --------\n\n    // NOTE: Please read https://book.getfoundry.sh/cheatcodes/serialize-json to understand how\n    // to use the serialization cheats.\n\n    /// Serializes a key and value to a JSON object stored in-memory that can be later written to a file.\n    /// Returns the stringified version of the specific JSON file up to that moment.\n    #[cheatcode(group = Json)]\n    function serializeJson(string calldata objectKey, string calldata value) external returns (string memory json);\n\n    /// See `serializeJson`.\n    #[cheatcode(group = Json)]\n    function serializeBool(string calldata objectKey, string calldata valueKey, bool value)\n        external\n        returns (string memory json);\n    /// See `serializeJson`.\n    #[cheatcode(group = Json)]\n    function serializeUint(string calldata objectKey, string calldata valueKey, uint256 value)\n        external\n        returns (string memory json);\n    /// See `serializeJson`.\n    #[cheatcode(group = Json)]\n    function serializeUintToHex(string calldata objectKey, string calldata valueKey, uint256 value)\n        external\n        returns (string memory json);\n    /// See `serializeJson`.\n    #[cheatcode(group = Json)]\n    function serializeInt(string calldata objectKey, string calldata valueKey, int256 value)\n        external\n        returns (string memory json);\n    /// See `serializeJson`.\n    #[cheatcode(group = Json)]\n    function serializeAddress(string calldata objectKey, string calldata valueKey, address value)\n        external\n        returns (string memory json);\n    /// See `serializeJson`.\n    #[cheatcode(group = Json)]\n    function serializeBytes32(string calldata objectKey, string calldata valueKey, bytes32 value)\n        external\n        returns (string memory json);\n    /// See `serializeJson`.\n    #[cheatcode(group = Json)]\n    function serializeString(string calldata objectKey, string calldata valueKey, string calldata value)\n        external\n        returns (string memory json);\n    /// See `serializeJson`.\n    #[cheatcode(group = Json)]\n    function serializeBytes(string calldata objectKey, string calldata valueKey, bytes calldata value)\n        external\n        returns (string memory json);\n\n    /// See `serializeJson`.\n    #[cheatcode(group = Json)]\n    function serializeBool(string calldata objectKey, string calldata valueKey, bool[] calldata values)\n        external\n        returns (string memory json);\n    /// See `serializeJson`.\n    #[cheatcode(group = Json)]\n    function serializeUint(string calldata objectKey, string calldata valueKey, uint256[] calldata values)\n        external\n        returns (string memory json);\n    /// See `serializeJson`.\n    #[cheatcode(group = Json)]\n    function serializeInt(string calldata objectKey, string calldata valueKey, int256[] calldata values)\n        external\n        returns (string memory json);\n    /// See `serializeJson`.\n    #[cheatcode(group = Json)]\n    function serializeAddress(string calldata objectKey, string calldata valueKey, address[] calldata values)\n        external\n        returns (string memory json);\n    /// See `serializeJson`.\n    #[cheatcode(group = Json)]\n    function serializeBytes32(string calldata objectKey, string calldata valueKey, bytes32[] calldata values)\n        external\n        returns (string memory json);\n    /// See `serializeJson`.\n    #[cheatcode(group = Json)]\n    function serializeString(string calldata objectKey, string calldata valueKey, string[] calldata values)\n        external\n        returns (string memory json);\n    /// See `serializeJson`.\n    #[cheatcode(group = Json)]\n    function serializeBytes(string calldata objectKey, string calldata valueKey, bytes[] calldata values)\n        external\n        returns (string memory json);\n    /// See `serializeJson`.\n    #[cheatcode(group = Json)]\n    function serializeJsonType(string calldata typeDescription, bytes calldata value)\n        external\n        pure\n        returns (string memory json);\n    /// See `serializeJson`.\n    #[cheatcode(group = Json)]\n    function serializeJsonType(string calldata objectKey, string calldata valueKey, string calldata typeDescription, bytes calldata value)\n        external\n        returns (string memory json);\n\n    // NOTE: Please read https://book.getfoundry.sh/cheatcodes/write-json to understand how\n    // to use the JSON writing cheats.\n\n    /// Write a serialized JSON object to a file. If the file exists, it will be overwritten.\n    #[cheatcode(group = Json)]\n    function writeJson(string calldata json, string calldata path) external;\n\n    /// Write a serialized JSON object to an **existing** JSON file, replacing a value with key = <value_key.>\n    /// This is useful to replace a specific value of a JSON file, without having to parse the entire thing.\n    /// This cheatcode will create new keys if they didn't previously exist.\n    #[cheatcode(group = Json)]\n    function writeJson(string calldata json, string calldata path, string calldata valueKey) external;\n\n    // ======== TOML Parsing and Manipulation ========\n\n    // -------- Reading --------\n\n    // NOTE: Please read https://book.getfoundry.sh/cheatcodes/parse-toml to understand the\n    // limitations and caveats of the TOML parsing cheat.\n\n    /// Checks if `key` exists in a TOML table.\n    #[cheatcode(group = Toml)]\n    function keyExistsToml(string calldata toml, string calldata key) external view returns (bool);\n\n    /// ABI-encodes a TOML table.\n    #[cheatcode(group = Toml)]\n    function parseToml(string calldata toml) external pure returns (bytes memory abiEncodedData);\n\n    /// ABI-encodes a TOML table at `key`.\n    #[cheatcode(group = Toml)]\n    function parseToml(string calldata toml, string calldata key) external pure returns (bytes memory abiEncodedData);\n\n    // The following parseToml cheatcodes will do type coercion, for the type that they indicate.\n    // For example, parseTomlUint will coerce all values to a uint256. That includes stringified numbers '12.'\n    // and hex numbers '0xEF.'.\n    // Type coercion works ONLY for discrete values or arrays. That means that the key must return a value or array, not\n    // a TOML table.\n\n    /// Parses a string of TOML data at `key` and coerces it to `uint256`.\n    #[cheatcode(group = Toml)]\n    function parseTomlUint(string calldata toml, string calldata key) external pure returns (uint256);\n    /// Parses a string of TOML data at `key` and coerces it to `uint256[]`.\n    #[cheatcode(group = Toml)]\n    function parseTomlUintArray(string calldata toml, string calldata key) external pure returns (uint256[] memory);\n    /// Parses a string of TOML data at `key` and coerces it to `int256`.\n    #[cheatcode(group = Toml)]\n    function parseTomlInt(string calldata toml, string calldata key) external pure returns (int256);\n    /// Parses a string of TOML data at `key` and coerces it to `int256[]`.\n    #[cheatcode(group = Toml)]\n    function parseTomlIntArray(string calldata toml, string calldata key) external pure returns (int256[] memory);\n    /// Parses a string of TOML data at `key` and coerces it to `bool`.\n    #[cheatcode(group = Toml)]\n    function parseTomlBool(string calldata toml, string calldata key) external pure returns (bool);\n    /// Parses a string of TOML data at `key` and coerces it to `bool[]`.\n    #[cheatcode(group = Toml)]\n    function parseTomlBoolArray(string calldata toml, string calldata key) external pure returns (bool[] memory);\n    /// Parses a string of TOML data at `key` and coerces it to `address`.\n    #[cheatcode(group = Toml)]\n    function parseTomlAddress(string calldata toml, string calldata key) external pure returns (address);\n    /// Parses a string of TOML data at `key` and coerces it to `address[]`.\n    #[cheatcode(group = Toml)]\n    function parseTomlAddressArray(string calldata toml, string calldata key)\n        external\n        pure\n        returns (address[] memory);\n    /// Parses a string of TOML data at `key` and coerces it to `string`.\n    #[cheatcode(group = Toml)]\n    function parseTomlString(string calldata toml, string calldata key) external pure returns (string memory);\n    /// Parses a string of TOML data at `key` and coerces it to `string[]`.\n    #[cheatcode(group = Toml)]\n    function parseTomlStringArray(string calldata toml, string calldata key) external pure returns (string[] memory);\n    /// Parses a string of TOML data at `key` and coerces it to `bytes`.\n    #[cheatcode(group = Toml)]\n    function parseTomlBytes(string calldata toml, string calldata key) external pure returns (bytes memory);\n    /// Parses a string of TOML data at `key` and coerces it to `bytes[]`.\n    #[cheatcode(group = Toml)]\n    function parseTomlBytesArray(string calldata toml, string calldata key) external pure returns (bytes[] memory);\n    /// Parses a string of TOML data at `key` and coerces it to `bytes32`.\n    #[cheatcode(group = Toml)]\n    function parseTomlBytes32(string calldata toml, string calldata key) external pure returns (bytes32);\n    /// Parses a string of TOML data at `key` and coerces it to `bytes32[]`.\n    #[cheatcode(group = Toml)]\n    function parseTomlBytes32Array(string calldata toml, string calldata key)\n        external\n        pure\n        returns (bytes32[] memory);\n\n    /// Parses a string of TOML data and coerces it to type corresponding to `typeDescription`.\n    #[cheatcode(group = Toml)]\n    function parseTomlType(string calldata toml, string calldata typeDescription) external pure returns (bytes memory);\n    /// Parses a string of TOML data at `key` and coerces it to type corresponding to `typeDescription`.\n    #[cheatcode(group = Toml)]\n    function parseTomlType(string calldata toml, string calldata key, string calldata typeDescription) external pure returns (bytes memory);\n    /// Parses a string of TOML data at `key` and coerces it to type array corresponding to `typeDescription`.\n    #[cheatcode(group = Toml)]\n    function parseTomlTypeArray(string calldata toml, string calldata key, string calldata typeDescription)\n        external\n        pure\n        returns (bytes memory);\n\n    /// Returns an array of all the keys in a TOML table.\n    #[cheatcode(group = Toml)]\n    function parseTomlKeys(string calldata toml, string calldata key) external pure returns (string[] memory keys);\n\n    // -------- Writing --------\n\n    // NOTE: Please read https://book.getfoundry.sh/cheatcodes/write-toml to understand how\n    // to use the TOML writing cheat.\n\n    /// Takes serialized JSON, converts to TOML and write a serialized TOML to a file.\n    #[cheatcode(group = Toml)]\n    function writeToml(string calldata json, string calldata path) external;\n\n    /// Takes serialized JSON, converts to TOML and write a serialized TOML table to an **existing** TOML file, replacing a value with key = <value_key.>\n    /// This is useful to replace a specific value of a TOML file, without having to parse the entire thing.\n    /// This cheatcode will create new keys if they didn't previously exist.\n    #[cheatcode(group = Toml)]\n    function writeToml(string calldata json, string calldata path, string calldata valueKey) external;\n\n    // ======== Cryptography ========\n\n    // -------- Key Management --------\n\n    /// Derives a private key from the name, labels the account with that name, and returns the wallet.\n    #[cheatcode(group = Crypto)]\n    function createWallet(string calldata walletLabel) external returns (Wallet memory wallet);\n\n    /// Generates a wallet from the private key and returns the wallet.\n    #[cheatcode(group = Crypto)]\n    function createWallet(uint256 privateKey) external returns (Wallet memory wallet);\n\n    /// Generates a wallet from the private key, labels the account with that name, and returns the wallet.\n    #[cheatcode(group = Crypto)]\n    function createWallet(uint256 privateKey, string calldata walletLabel) external returns (Wallet memory wallet);\n\n    /// Signs data with a `Wallet`.\n    #[cheatcode(group = Crypto)]\n    function sign(Wallet calldata wallet, bytes32 digest) external pure returns (uint8 v, bytes32 r, bytes32 s);\n\n    /// Signs data with a `Wallet`.\n    ///\n    /// Returns a compact signature (`r`, `vs`) as per EIP-2098, where `vs` encodes both the\n    /// signature's `s` value, and the recovery id `v` in a single bytes32.\n    /// This format reduces the signature size from 65 to 64 bytes.\n    #[cheatcode(group = Crypto)]\n    function signCompact(Wallet calldata wallet, bytes32 digest) external pure returns (bytes32 r, bytes32 vs);\n\n    /// Signs `digest` with `privateKey` using the secp256k1 curve.\n    #[cheatcode(group = Crypto)]\n    function sign(uint256 privateKey, bytes32 digest) external pure returns (uint8 v, bytes32 r, bytes32 s);\n\n    /// Signs `digest` with `privateKey` on the secp256k1 curve, using the given `nonce`\n    /// as the raw ephemeral k value in ECDSA (instead of deriving it deterministically).\n    #[cheatcode(group = Crypto)]\n    function signWithNonceUnsafe(uint256 privateKey, bytes32 digest, uint256 nonce) external pure returns (uint8 v, bytes32 r, bytes32 s);\n\n    /// Signs `digest` with `privateKey` using the secp256k1 curve.\n    ///\n    /// Returns a compact signature (`r`, `vs`) as per EIP-2098, where `vs` encodes both the\n    /// signature's `s` value, and the recovery id `v` in a single bytes32.\n    /// This format reduces the signature size from 65 to 64 bytes.\n    #[cheatcode(group = Crypto)]\n    function signCompact(uint256 privateKey, bytes32 digest) external pure returns (bytes32 r, bytes32 vs);\n\n    /// Signs `digest` with signer provided to script using the secp256k1 curve.\n    ///\n    /// If `--sender` is provided, the signer with provided address is used, otherwise,\n    /// if exactly one signer is provided to the script, that signer is used.\n    ///\n    /// Raises error if signer passed through `--sender` does not match any unlocked signers or\n    /// if `--sender` is not provided and not exactly one signer is passed to the script.\n    #[cheatcode(group = Crypto)]\n    function sign(bytes32 digest) external pure returns (uint8 v, bytes32 r, bytes32 s);\n\n    /// Signs `digest` with signer provided to script using the secp256k1 curve.\n    ///\n    /// Returns a compact signature (`r`, `vs`) as per EIP-2098, where `vs` encodes both the\n    /// signature's `s` value, and the recovery id `v` in a single bytes32.\n    /// This format reduces the signature size from 65 to 64 bytes.\n    ///\n    /// If `--sender` is provided, the signer with provided address is used, otherwise,\n    /// if exactly one signer is provided to the script, that signer is used.\n    ///\n    /// Raises error if signer passed through `--sender` does not match any unlocked signers or\n    /// if `--sender` is not provided and not exactly one signer is passed to the script.\n    #[cheatcode(group = Crypto)]\n    function signCompact(bytes32 digest) external pure returns (bytes32 r, bytes32 vs);\n\n    /// Signs `digest` with signer provided to script using the secp256k1 curve.\n    ///\n    /// Raises error if none of the signers passed into the script have provided address.\n    #[cheatcode(group = Crypto)]\n    function sign(address signer, bytes32 digest) external pure returns (uint8 v, bytes32 r, bytes32 s);\n\n    /// Signs `digest` with signer provided to script using the secp256k1 curve.\n    ///\n    /// Returns a compact signature (`r`, `vs`) as per EIP-2098, where `vs` encodes both the\n    /// signature's `s` value, and the recovery id `v` in a single bytes32.\n    /// This format reduces the signature size from 65 to 64 bytes.\n    ///\n    /// Raises error if none of the signers passed into the script have provided address.\n    #[cheatcode(group = Crypto)]\n    function signCompact(address signer, bytes32 digest) external pure returns (bytes32 r, bytes32 vs);\n\n    /// Signs `digest` with `privateKey` using the secp256r1 curve.\n    #[cheatcode(group = Crypto)]\n    function signP256(uint256 privateKey, bytes32 digest) external pure returns (bytes32 r, bytes32 s);\n\n    /// Derives secp256r1 public key from the provided `privateKey`.\n    #[cheatcode(group = Crypto)]\n    function publicKeyP256(uint256 privateKey) external pure returns (uint256 publicKeyX, uint256 publicKeyY);\n\n    /// Generates an Ed25519 key pair from a deterministic salt.\n    /// Returns (publicKey, privateKey) as 32-byte values.\n    #[cheatcode(group = Crypto, safety = Safe)]\n    function createEd25519Key(bytes32 salt) external pure returns (bytes32 publicKey, bytes32 privateKey);\n\n    /// Derives the Ed25519 public key from a private key.\n    #[cheatcode(group = Crypto, safety = Safe)]\n    function publicKeyEd25519(bytes32 privateKey) external pure returns (bytes32 publicKey);\n\n    /// Signs a message with namespace using Ed25519.\n    /// The signature covers namespace || message for domain separation.\n    /// Returns a 64-byte Ed25519 signature.\n    #[cheatcode(group = Crypto, safety = Safe)]\n    function signEd25519(bytes calldata namespace, bytes calldata message, bytes32 privateKey)\n        external\n        pure\n        returns (bytes memory signature);\n\n    /// Verifies an Ed25519 signature over namespace || message.\n    /// Returns true if signature is valid, false otherwise.\n    #[cheatcode(group = Crypto, safety = Safe)]\n    function verifyEd25519(\n        bytes calldata signature,\n        bytes calldata namespace,\n        bytes calldata message,\n        bytes32 publicKey\n    ) external pure returns (bool valid);\n\n    /// Derive a private key from a provided mnemonic string (or mnemonic file path)\n    /// at the derivation path `m/44'/60'/0'/0/{index}`.\n    #[cheatcode(group = Crypto)]\n    function deriveKey(string calldata mnemonic, uint32 index) external pure returns (uint256 privateKey);\n    /// Derive a private key from a provided mnemonic string (or mnemonic file path)\n    /// at `{derivationPath}{index}`.\n    #[cheatcode(group = Crypto)]\n    function deriveKey(string calldata mnemonic, string calldata derivationPath, uint32 index)\n        external\n        pure\n        returns (uint256 privateKey);\n    /// Derive a private key from a provided mnemonic string (or mnemonic file path) in the specified language\n    /// at the derivation path `m/44'/60'/0'/0/{index}`.\n    #[cheatcode(group = Crypto)]\n    function deriveKey(string calldata mnemonic, uint32 index, string calldata language)\n        external\n        pure\n        returns (uint256 privateKey);\n    /// Derive a private key from a provided mnemonic string (or mnemonic file path) in the specified language\n    /// at `{derivationPath}{index}`.\n    #[cheatcode(group = Crypto)]\n    function deriveKey(string calldata mnemonic, string calldata derivationPath, uint32 index, string calldata language)\n        external\n        pure\n        returns (uint256 privateKey);\n\n    /// Adds a private key to the local forge wallet and returns the address.\n    #[cheatcode(group = Crypto)]\n    function rememberKey(uint256 privateKey) external returns (address keyAddr);\n\n    /// Derive a set number of wallets from a mnemonic at the derivation path `m/44'/60'/0'/0/{0..count}`.\n    ///\n    /// The respective private keys are saved to the local forge wallet for later use and their addresses are returned.\n    #[cheatcode(group = Crypto)]\n    function rememberKeys(string calldata mnemonic, string calldata derivationPath, uint32 count) external returns (address[] memory keyAddrs);\n\n    /// Derive a set number of wallets from a mnemonic in the specified language at the derivation path `m/44'/60'/0'/0/{0..count}`.\n    ///\n    /// The respective private keys are saved to the local forge wallet for later use and their addresses are returned.\n    #[cheatcode(group = Crypto)]\n    function rememberKeys(string calldata mnemonic, string calldata derivationPath, string calldata language, uint32 count)\n        external\n        returns (address[] memory keyAddrs);\n\n    // -------- Uncategorized Utilities --------\n\n    /// Labels an address in call traces.\n    #[cheatcode(group = Utilities)]\n    function label(address account, string calldata newLabel) external;\n\n    /// Gets the label for the specified address.\n    #[cheatcode(group = Utilities)]\n    function getLabel(address account) external view returns (string memory currentLabel);\n\n    /// Compute the address a contract will be deployed at for a given deployer address and nonce.\n    #[cheatcode(group = Utilities)]\n    function computeCreateAddress(address deployer, uint256 nonce) external pure returns (address);\n\n    /// Compute the address of a contract created with CREATE2 using the given CREATE2 deployer.\n    #[cheatcode(group = Utilities)]\n    function computeCreate2Address(bytes32 salt, bytes32 initCodeHash, address deployer) external pure returns (address);\n\n    /// Compute the address of a contract created with CREATE2 using the default CREATE2 deployer.\n    #[cheatcode(group = Utilities)]\n    function computeCreate2Address(bytes32 salt, bytes32 initCodeHash) external pure returns (address);\n\n    /// Encodes a `bytes` value to a base64 string.\n    #[cheatcode(group = Utilities)]\n    function toBase64(bytes calldata data) external pure returns (string memory);\n\n    /// Encodes a `string` value to a base64 string.\n    #[cheatcode(group = Utilities)]\n    function toBase64(string calldata data) external pure returns (string memory);\n\n    /// Encodes a `bytes` value to a base64url string.\n    #[cheatcode(group = Utilities)]\n    function toBase64URL(bytes calldata data) external pure returns (string memory);\n\n    /// Encodes a `string` value to a base64url string.\n    #[cheatcode(group = Utilities)]\n    function toBase64URL(string calldata data) external pure returns (string memory);\n\n    /// Returns ENS namehash for provided string.\n    #[cheatcode(group = Utilities)]\n    function ensNamehash(string calldata name) external pure returns (bytes32);\n\n    /// Returns an uint256 value bounded in given range and different from the current one.\n    #[cheatcode(group = Utilities)]\n    function bound(uint256 current, uint256 min, uint256 max) external view returns (uint256);\n\n    /// Returns a random uint256 value.\n    #[cheatcode(group = Utilities)]\n    function randomUint() external view returns (uint256);\n\n    /// Returns random uint256 value between the provided range (=min..=max).\n    #[cheatcode(group = Utilities)]\n    function randomUint(uint256 min, uint256 max) external view returns (uint256);\n\n    /// Returns a random `uint256` value of given bits.\n    #[cheatcode(group = Utilities)]\n    function randomUint(uint256 bits) external view returns (uint256);\n\n    /// Returns a random `address`.\n    #[cheatcode(group = Utilities)]\n    function randomAddress() external view returns (address);\n\n    /// Returns an int256 value bounded in given range and different from the current one.\n    #[cheatcode(group = Utilities)]\n    function bound(int256 current, int256 min, int256 max) external view returns (int256);\n\n    /// Returns a random `int256` value.\n    #[cheatcode(group = Utilities)]\n    function randomInt() external view returns (int256);\n\n    /// Returns a random `int256` value of given bits.\n    #[cheatcode(group = Utilities)]\n    function randomInt(uint256 bits) external view returns (int256);\n\n    /// Returns a random `bool`.\n    #[cheatcode(group = Utilities)]\n    function randomBool() external view returns (bool);\n\n    /// Returns a random byte array value of the given length.\n    #[cheatcode(group = Utilities)]\n    function randomBytes(uint256 len) external view returns (bytes memory);\n\n    /// Returns a random fixed-size byte array of length 4.\n    #[cheatcode(group = Utilities)]\n    function randomBytes4() external view returns (bytes4);\n\n    /// Returns a random fixed-size byte array of length 8.\n    #[cheatcode(group = Utilities)]\n    function randomBytes8() external view returns (bytes8);\n\n    /// Pauses collection of call traces. Useful in cases when you want to skip tracing of\n    /// complex calls which are not useful for debugging.\n    #[cheatcode(group = Utilities)]\n    function pauseTracing() external view;\n\n    /// Unpauses collection of call traces.\n    #[cheatcode(group = Utilities)]\n    function resumeTracing() external view;\n\n    /// Utility cheatcode to copy storage of `from` contract to another `to` contract.\n    #[cheatcode(group = Utilities)]\n    function copyStorage(address from, address to) external;\n\n    /// Utility cheatcode to set arbitrary storage for given target address.\n    #[cheatcode(group = Utilities)]\n    function setArbitraryStorage(address target) external;\n\n    /// Utility cheatcode to set arbitrary storage for given target address and overwrite\n    /// any storage slots that have been previously set.\n    #[cheatcode(group = Utilities)]\n    function setArbitraryStorage(address target, bool overwrite) external;\n\n    /// Sorts an array in ascending order.\n    #[cheatcode(group = Utilities)]\n    function sort(uint256[] calldata array) external returns (uint256[] memory);\n\n    /// Randomly shuffles an array.\n    #[cheatcode(group = Utilities)]\n    function shuffle(uint256[] calldata array) external returns (uint256[] memory);\n\n    /// Set RNG seed.\n    #[cheatcode(group = Utilities)]\n    function setSeed(uint256 seed) external;\n\n    /// Causes the next contract creation (via new) to fail and return its initcode in the returndata buffer.\n    /// This allows type-safe access to the initcode payload that would be used for contract creation.\n    /// Example usage:\n    /// vm.interceptInitcode();\n    /// bytes memory initcode;\n    /// try new MyContract(param1, param2) { assert(false); }\n    /// catch (bytes memory interceptedInitcode) { initcode = interceptedInitcode; }\n    #[cheatcode(group = Utilities, safety = Unsafe)]\n    function interceptInitcode() external;\n\n    /// Generates the hash of the canonical EIP-712 type representation.\n    ///\n    /// Supports 2 different inputs:\n    ///  1. Name of the type (i.e. \"Transaction\"):\n    ///     * requires previous binding generation with `forge bind-json`.\n    ///     * bindings will be retrieved from the path configured in `foundry.toml`.\n    ///\n    ///  2. String representation of the type (i.e. \"Foo(Bar bar) Bar(uint256 baz)\").\n    ///     * Note: the cheatcode will output the canonical type even if the input is malformated\n    ///             with the wrong order of elements or with extra whitespaces.\n    #[cheatcode(group = Utilities)]\n    function eip712HashType(string calldata typeNameOrDefinition) external pure returns (bytes32 typeHash);\n\n    /// Generates the hash of the canonical EIP-712 type representation.\n    /// Requires previous binding generation with `forge bind-json`.\n    ///\n    /// Params:\n    ///  * `bindingsPath`: path where the output of `forge bind-json` is stored.\n    ///  * `typeName`: Name of the type (i.e. \"Transaction\").\n    #[cheatcode(group = Utilities)]\n    function eip712HashType(string calldata bindingsPath, string calldata typeName) external pure returns (bytes32 typeHash);\n\n    /// Generates the struct hash of the canonical EIP-712 type representation and its abi-encoded data.\n    ///\n    /// Supports 2 different inputs:\n    ///  1. Name of the type (i.e. \"PermitSingle\"):\n    ///     * requires previous binding generation with `forge bind-json`.\n    ///     * bindings will be retrieved from the path configured in `foundry.toml`.\n    ///\n    ///  2. String representation of the type (i.e. \"Foo(Bar bar) Bar(uint256 baz)\").\n    ///     * Note: the cheatcode will use the canonical type even if the input is malformated\n    ///             with the wrong order of elements or with extra whitespaces.\n    #[cheatcode(group = Utilities)]\n    function eip712HashStruct(string calldata typeNameOrDefinition, bytes calldata abiEncodedData) external pure returns (bytes32 typeHash);\n\n    /// Generates the struct hash of the canonical EIP-712 type representation and its abi-encoded data.\n    /// Requires previous binding generation with `forge bind-json`.\n    ///\n    /// Params:\n    ///  * `bindingsPath`: path where the output of `forge bind-json` is stored.\n    ///  * `typeName`: Name of the type (i.e. \"PermitSingle\").\n    ///  * `abiEncodedData`: ABI-encoded data for the struct that is being hashed.\n    #[cheatcode(group = Utilities)]\n    function eip712HashStruct(string calldata bindingsPath, string calldata typeName, bytes calldata abiEncodedData) external pure returns (bytes32 typeHash);\n\n    /// Generates a ready-to-sign digest of human-readable typed data following the EIP-712 standard.\n    #[cheatcode(group = Utilities)]\n    function eip712HashTypedData(string calldata jsonData) external pure returns (bytes32 digest);\n\n    /// RLP encodes a list of bytes into an RLP payload.\n    #[cheatcode(group = Utilities)]\n    function toRlp(bytes[] calldata data) external pure returns (bytes memory);\n    /// RLP decodes an RLP payload into a list of bytes.\n    #[cheatcode(group = Utilities)]\n    function fromRlp(bytes calldata rlp) external pure returns (bytes[] memory data);\n}\n}\n\nimpl PartialEq for ForgeContext {\n    // Handles test group case (any of test, coverage or snapshot)\n    // and script group case (any of dry run, broadcast or resume).\n    fn eq(&self, other: &Self) -> bool {\n        match (self, other) {\n            (_, Self::TestGroup) => {\n                matches!(self, Self::Test | Self::Snapshot | Self::Coverage)\n            }\n            (_, Self::ScriptGroup) => {\n                matches!(self, Self::ScriptDryRun | Self::ScriptBroadcast | Self::ScriptResume)\n            }\n            (Self::Test, Self::Test)\n            | (Self::Snapshot, Self::Snapshot)\n            | (Self::Coverage, Self::Coverage)\n            | (Self::ScriptDryRun, Self::ScriptDryRun)\n            | (Self::ScriptBroadcast, Self::ScriptBroadcast)\n            | (Self::ScriptResume, Self::ScriptResume)\n            | (Self::Unknown, Self::Unknown) => true,\n            _ => false,\n        }\n    }\n}\n\nimpl fmt::Display for Vm::CheatcodeError {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        self.message.fmt(f)\n    }\n}\n\nimpl fmt::Display for Vm::VmErrors {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        match self {\n            Self::CheatcodeError(err) => err.fmt(f),\n        }\n    }\n}\n\n#[track_caller]\nconst fn panic_unknown_safety() -> ! {\n    panic!(\"cannot determine safety from the group, add a `#[cheatcode(safety = ...)]` attribute\")\n}\n"
  },
  {
    "path": "crates/cheatcodes/src/base64.rs",
    "content": "use crate::{Cheatcode, Cheatcodes, Result, Vm::*};\nuse alloy_sol_types::SolValue;\nuse base64::prelude::*;\n\nimpl Cheatcode for toBase64_0Call {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { data } = self;\n        Ok(BASE64_STANDARD.encode(data).abi_encode())\n    }\n}\n\nimpl Cheatcode for toBase64_1Call {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { data } = self;\n        Ok(BASE64_STANDARD.encode(data).abi_encode())\n    }\n}\n\nimpl Cheatcode for toBase64URL_0Call {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { data } = self;\n        Ok(BASE64_URL_SAFE.encode(data).abi_encode())\n    }\n}\n\nimpl Cheatcode for toBase64URL_1Call {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { data } = self;\n        Ok(BASE64_URL_SAFE.encode(data).abi_encode())\n    }\n}\n"
  },
  {
    "path": "crates/cheatcodes/src/config.rs",
    "content": "use super::Result;\nuse crate::Vm::Rpc;\nuse alloy_primitives::{U256, map::AddressHashMap};\nuse foundry_common::{ContractsByArtifact, fs::normalize_path};\nuse foundry_compilers::{ArtifactId, ProjectPathsConfig, utils::canonicalize};\nuse foundry_config::{\n    Config, FsPermissions, ResolvedRpcEndpoint, ResolvedRpcEndpoints, RpcEndpoint, RpcEndpointUrl,\n    cache::StorageCachingConfig, fs_permissions::FsAccessKind,\n};\nuse foundry_evm_core::opts::EvmOpts;\nuse std::{\n    path::{Path, PathBuf},\n    time::Duration,\n};\n\n/// Additional, configurable context the `Cheatcodes` inspector has access to\n///\n/// This is essentially a subset of various `Config` settings `Cheatcodes` needs to know.\n#[derive(Clone, Debug)]\npub struct CheatsConfig {\n    /// Whether the FFI cheatcode is enabled.\n    pub ffi: bool,\n    /// Use the create 2 factory in all cases including tests and non-broadcasting scripts.\n    pub always_use_create_2_factory: bool,\n    /// Sets a timeout for vm.prompt cheatcodes\n    pub prompt_timeout: Duration,\n    /// RPC storage caching settings determines what chains and endpoints to cache\n    pub rpc_storage_caching: StorageCachingConfig,\n    /// Disables storage caching entirely.\n    pub no_storage_caching: bool,\n    /// All known endpoints and their aliases\n    pub rpc_endpoints: ResolvedRpcEndpoints,\n    /// Project's paths as configured\n    pub paths: ProjectPathsConfig,\n    /// Path to the directory that contains the bindings generated by `forge bind-json`.\n    pub bind_json_path: PathBuf,\n    /// Filesystem permissions for cheatcodes like `writeFile`, `readFile`\n    pub fs_permissions: FsPermissions,\n    /// Project root\n    pub root: PathBuf,\n    /// Absolute Path to broadcast dir i.e project_root/broadcast\n    pub broadcast: PathBuf,\n    /// How the evm was configured by the user\n    pub evm_opts: EvmOpts,\n    /// Address labels from config\n    pub labels: AddressHashMap<String>,\n    /// Artifacts which are guaranteed to be fresh (either recompiled or cached).\n    /// If Some, `vm.getDeployedCode` invocations are validated to be in scope of this list.\n    /// If None, no validation is performed.\n    pub available_artifacts: Option<ContractsByArtifact>,\n    /// Currently running artifact.\n    pub running_artifact: Option<ArtifactId>,\n    /// Whether to enable legacy (non-reverting) assertions.\n    pub assertions_revert: bool,\n    /// Optional seed for the RNG algorithm.\n    pub seed: Option<U256>,\n    /// Whether to allow `expectRevert` to work for internal calls.\n    pub internal_expect_revert: bool,\n}\n\nimpl CheatsConfig {\n    /// Extracts the necessary settings from the Config\n    pub fn new(\n        config: &Config,\n        evm_opts: EvmOpts,\n        available_artifacts: Option<ContractsByArtifact>,\n        running_artifact: Option<ArtifactId>,\n    ) -> Self {\n        let rpc_endpoints = config.rpc_endpoints.clone().resolved();\n        trace!(?rpc_endpoints, \"using resolved rpc endpoints\");\n\n        // If user explicitly disabled safety checks, do not set available_artifacts\n        let available_artifacts =\n            if config.unchecked_cheatcode_artifacts { None } else { available_artifacts };\n\n        Self {\n            ffi: evm_opts.ffi,\n            always_use_create_2_factory: evm_opts.always_use_create_2_factory,\n            prompt_timeout: Duration::from_secs(config.prompt_timeout),\n            rpc_storage_caching: config.rpc_storage_caching.clone(),\n            no_storage_caching: config.no_storage_caching,\n            rpc_endpoints,\n            paths: config.project_paths(),\n            bind_json_path: config.bind_json.out.clone(),\n            fs_permissions: config.fs_permissions.clone().joined(config.root.as_ref()),\n            root: config.root.clone(),\n            broadcast: config.root.clone().join(&config.broadcast),\n            evm_opts,\n            labels: config.labels.clone(),\n            available_artifacts,\n            running_artifact,\n            assertions_revert: config.assertions_revert,\n            seed: config.fuzz.seed,\n            internal_expect_revert: config.allow_internal_expect_revert,\n        }\n    }\n\n    /// Returns a new `CheatsConfig` configured with the given `Config` and `EvmOpts`.\n    pub fn clone_with(&self, config: &Config, evm_opts: EvmOpts) -> Self {\n        Self::new(config, evm_opts, self.available_artifacts.clone(), self.running_artifact.clone())\n    }\n\n    /// Attempts to canonicalize (see [std::fs::canonicalize]) the path.\n    ///\n    /// Canonicalization fails for non-existing paths, in which case we just normalize the path.\n    pub fn normalized_path(&self, path: impl AsRef<Path>) -> PathBuf {\n        let path = self.root.join(path);\n        canonicalize(&path).unwrap_or_else(|_| normalize_path(&path))\n    }\n\n    /// Returns true if the given path is allowed, if any path `allowed_paths` is an ancestor of the\n    /// path\n    ///\n    /// We only allow paths that are inside  allowed paths. To prevent path traversal\n    /// (\"../../etc/passwd\") we canonicalize/normalize the path first. We always join with the\n    /// configured root directory.\n    pub fn is_path_allowed(&self, path: impl AsRef<Path>, kind: FsAccessKind) -> bool {\n        self.is_normalized_path_allowed(&self.normalized_path(path), kind)\n    }\n\n    fn is_normalized_path_allowed(&self, path: &Path, kind: FsAccessKind) -> bool {\n        self.fs_permissions.is_path_allowed(path, kind)\n    }\n\n    /// Returns an error if no access is granted to access `path`, See also [Self::is_path_allowed]\n    ///\n    /// Returns the normalized version of `path`, see [`CheatsConfig::normalized_path`]\n    pub fn ensure_path_allowed(\n        &self,\n        path: impl AsRef<Path>,\n        kind: FsAccessKind,\n    ) -> Result<PathBuf> {\n        let path = path.as_ref();\n        let normalized = self.normalized_path(path);\n        ensure!(\n            self.is_normalized_path_allowed(&normalized, kind),\n            \"the path {} is not allowed to be accessed for {kind} operations\",\n            normalized.strip_prefix(&self.root).unwrap_or(path).display()\n        );\n        Ok(normalized)\n    }\n\n    /// Returns true if the given `path` is the project's foundry.toml file\n    ///\n    /// Note: this should be called with normalized path\n    pub fn is_foundry_toml(&self, path: impl AsRef<Path>) -> bool {\n        // path methods that do not access the filesystem are such as [`Path::starts_with`], are\n        // case-sensitive no matter the platform or filesystem. to make this case-sensitive\n        // we convert the underlying `OssStr` to lowercase checking that `path` and\n        // `foundry.toml` are the same file by comparing the FD, because it may not exist\n        let foundry_toml = self.root.join(Config::FILE_NAME);\n        Path::new(&foundry_toml.to_string_lossy().to_lowercase())\n            .starts_with(Path::new(&path.as_ref().to_string_lossy().to_lowercase()))\n    }\n\n    /// Same as [`Self::is_foundry_toml`] but returns an `Err` if [`Self::is_foundry_toml`] returns\n    /// true\n    pub fn ensure_not_foundry_toml(&self, path: impl AsRef<Path>) -> Result<()> {\n        ensure!(!self.is_foundry_toml(path), \"access to `foundry.toml` is not allowed\");\n        Ok(())\n    }\n\n    /// Returns the RPC to use\n    ///\n    /// If `url_or_alias` is a known alias in the `ResolvedRpcEndpoints` then it returns the\n    /// corresponding URL of that alias. otherwise this assumes `url_or_alias` is itself a URL\n    /// if it starts with a `http` or `ws` scheme.\n    ///\n    /// If the url is a path to an existing file, it is also considered a valid RPC URL, IPC path.\n    ///\n    /// # Errors\n    ///\n    ///  - Returns an error if `url_or_alias` is a known alias but references an unresolved env var.\n    ///  - Returns an error if `url_or_alias` is not an alias but does not start with a `http` or\n    ///    `ws` `scheme` and is not a path to an existing file\n    pub fn rpc_endpoint(&self, url_or_alias: &str) -> Result<ResolvedRpcEndpoint> {\n        if let Some(endpoint) = self.rpc_endpoints.get(url_or_alias) {\n            Ok(endpoint.clone().try_resolve())\n        } else {\n            // check if it's a URL or a path to an existing file to an ipc socket\n            if url_or_alias.starts_with(\"http\") ||\n                url_or_alias.starts_with(\"ws\") ||\n                // check for existing ipc file\n                Path::new(url_or_alias).exists()\n            {\n                let url = RpcEndpointUrl::Env(url_or_alias.to_string());\n                Ok(RpcEndpoint::new(url).resolve())\n            } else {\n                Err(fmt_err!(\"invalid rpc url: {url_or_alias}\"))\n            }\n        }\n    }\n    /// Returns all the RPC urls and their alias.\n    pub fn rpc_urls(&self) -> Result<Vec<Rpc>> {\n        let mut urls = Vec::with_capacity(self.rpc_endpoints.len());\n        for alias in self.rpc_endpoints.keys() {\n            let url = self.rpc_endpoint(alias)?.url()?;\n            urls.push(Rpc { key: alias.clone(), url });\n        }\n        Ok(urls)\n    }\n}\n\nimpl Default for CheatsConfig {\n    fn default() -> Self {\n        Self {\n            ffi: false,\n            always_use_create_2_factory: false,\n            prompt_timeout: Duration::from_secs(120),\n            rpc_storage_caching: Default::default(),\n            no_storage_caching: false,\n            rpc_endpoints: Default::default(),\n            paths: ProjectPathsConfig::builder().build_with_root(\"./\"),\n            fs_permissions: Default::default(),\n            root: Default::default(),\n            bind_json_path: PathBuf::default().join(\"utils\").join(\"jsonBindings.sol\"),\n            broadcast: Default::default(),\n            evm_opts: Default::default(),\n            labels: Default::default(),\n            available_artifacts: Default::default(),\n            running_artifact: Default::default(),\n            assertions_revert: true,\n            seed: None,\n            internal_expect_revert: false,\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use foundry_config::fs_permissions::PathPermission;\n\n    fn config(root: &str, fs_permissions: FsPermissions) -> CheatsConfig {\n        CheatsConfig::new(\n            &Config { root: root.into(), fs_permissions, ..Default::default() },\n            Default::default(),\n            None,\n            None,\n        )\n    }\n\n    #[test]\n    fn test_allowed_paths() {\n        let root = \"/my/project/root/\";\n        let config = config(root, FsPermissions::new(vec![PathPermission::read_write(\"./\")]));\n\n        assert!(config.ensure_path_allowed(\"./t.txt\", FsAccessKind::Read).is_ok());\n        assert!(config.ensure_path_allowed(\"./t.txt\", FsAccessKind::Write).is_ok());\n        assert!(config.ensure_path_allowed(\"../root/t.txt\", FsAccessKind::Read).is_ok());\n        assert!(config.ensure_path_allowed(\"../root/t.txt\", FsAccessKind::Write).is_ok());\n        assert!(config.ensure_path_allowed(\"../../root/t.txt\", FsAccessKind::Read).is_err());\n        assert!(config.ensure_path_allowed(\"../../root/t.txt\", FsAccessKind::Write).is_err());\n    }\n\n    #[test]\n    fn test_is_foundry_toml() {\n        let root = \"/my/project/root/\";\n        let config = config(root, FsPermissions::new(vec![PathPermission::read_write(\"./\")]));\n\n        let f = format!(\"{root}foundry.toml\");\n        assert!(config.is_foundry_toml(f));\n\n        let f = format!(\"{root}Foundry.toml\");\n        assert!(config.is_foundry_toml(f));\n\n        let f = format!(\"{root}lib/other/foundry.toml\");\n        assert!(!config.is_foundry_toml(f));\n    }\n}\n"
  },
  {
    "path": "crates/cheatcodes/src/crypto.rs",
    "content": "//! Implementations of [`Crypto`](spec::Group::Crypto) Cheatcodes.\n\nuse crate::{Cheatcode, Cheatcodes, Result, Vm::*};\nuse alloy_primitives::{Address, B256, U256, keccak256};\nuse alloy_signer::{Signer, SignerSync};\nuse alloy_signer_local::{\n    LocalSigner, MnemonicBuilder, PrivateKeySigner,\n    coins_bip39::{\n        ChineseSimplified, ChineseTraditional, Czech, English, French, Italian, Japanese, Korean,\n        Portuguese, Spanish, Wordlist,\n    },\n};\nuse alloy_sol_types::SolValue;\nuse k256::{\n    FieldBytes, Scalar,\n    ecdsa::{SigningKey, hazmat},\n    elliptic_curve::{bigint::ArrayEncoding, sec1::ToEncodedPoint},\n};\n\nuse p256::ecdsa::{\n    Signature as P256Signature, SigningKey as P256SigningKey, signature::hazmat::PrehashSigner,\n};\n\nuse ed25519_consensus::{\n    Signature as Ed25519Signature, SigningKey as Ed25519SigningKey,\n    VerificationKey as Ed25519VerificationKey,\n};\n\n/// The BIP32 default derivation path prefix.\nconst DEFAULT_DERIVATION_PATH_PREFIX: &str = \"m/44'/60'/0'/0/\";\n\nimpl Cheatcode for createWallet_0Call {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { walletLabel } = self;\n        create_wallet(&U256::from_be_bytes(keccak256(walletLabel).0), Some(walletLabel), state)\n    }\n}\n\nimpl Cheatcode for createWallet_1Call {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { privateKey } = self;\n        create_wallet(privateKey, None, state)\n    }\n}\n\nimpl Cheatcode for createWallet_2Call {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { privateKey, walletLabel } = self;\n        create_wallet(privateKey, Some(walletLabel), state)\n    }\n}\n\nimpl Cheatcode for sign_0Call {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { wallet, digest } = self;\n        let sig = sign(&wallet.privateKey, digest)?;\n        Ok(encode_full_sig(sig))\n    }\n}\n\nimpl Cheatcode for signWithNonceUnsafeCall {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let pk: U256 = self.privateKey;\n        let digest: B256 = self.digest;\n        let nonce: U256 = self.nonce;\n        let sig: alloy_primitives::Signature = sign_with_nonce(&pk, &digest, &nonce)?;\n        Ok(encode_full_sig(sig))\n    }\n}\n\nimpl Cheatcode for signCompact_0Call {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { wallet, digest } = self;\n        let sig = sign(&wallet.privateKey, digest)?;\n        Ok(encode_compact_sig(sig))\n    }\n}\n\nimpl Cheatcode for deriveKey_0Call {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { mnemonic, index } = self;\n        derive_key::<English>(mnemonic, DEFAULT_DERIVATION_PATH_PREFIX, *index)\n    }\n}\n\nimpl Cheatcode for deriveKey_1Call {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { mnemonic, derivationPath, index } = self;\n        derive_key::<English>(mnemonic, derivationPath, *index)\n    }\n}\n\nimpl Cheatcode for deriveKey_2Call {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { mnemonic, index, language } = self;\n        derive_key_str(mnemonic, DEFAULT_DERIVATION_PATH_PREFIX, *index, language)\n    }\n}\n\nimpl Cheatcode for deriveKey_3Call {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { mnemonic, derivationPath, index, language } = self;\n        derive_key_str(mnemonic, derivationPath, *index, language)\n    }\n}\n\nimpl Cheatcode for rememberKeyCall {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { privateKey } = self;\n        let wallet = parse_wallet(privateKey)?;\n        let address = inject_wallet(state, wallet);\n        Ok(address.abi_encode())\n    }\n}\n\nimpl Cheatcode for rememberKeys_0Call {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { mnemonic, derivationPath, count } = self;\n        let wallets = derive_wallets::<English>(mnemonic, derivationPath, *count)?;\n        let mut addresses = Vec::<Address>::with_capacity(wallets.len());\n        for wallet in wallets {\n            let addr = inject_wallet(state, wallet);\n            addresses.push(addr);\n        }\n\n        Ok(addresses.abi_encode())\n    }\n}\n\nimpl Cheatcode for rememberKeys_1Call {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { mnemonic, derivationPath, language, count } = self;\n        let wallets = derive_wallets_str(mnemonic, derivationPath, language, *count)?;\n        let mut addresses = Vec::<Address>::with_capacity(wallets.len());\n        for wallet in wallets {\n            let addr = inject_wallet(state, wallet);\n            addresses.push(addr);\n        }\n\n        Ok(addresses.abi_encode())\n    }\n}\n\nfn inject_wallet(state: &mut Cheatcodes, wallet: LocalSigner<SigningKey>) -> Address {\n    let address = wallet.address();\n    state.wallets().add_local_signer(wallet);\n    address\n}\n\nimpl Cheatcode for sign_1Call {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { privateKey, digest } = self;\n        let sig = sign(privateKey, digest)?;\n        Ok(encode_full_sig(sig))\n    }\n}\n\nimpl Cheatcode for signCompact_1Call {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { privateKey, digest } = self;\n        let sig = sign(privateKey, digest)?;\n        Ok(encode_compact_sig(sig))\n    }\n}\n\nimpl Cheatcode for sign_2Call {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { digest } = self;\n        let sig = sign_with_wallet(state, None, digest)?;\n        Ok(encode_full_sig(sig))\n    }\n}\n\nimpl Cheatcode for signCompact_2Call {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { digest } = self;\n        let sig = sign_with_wallet(state, None, digest)?;\n        Ok(encode_compact_sig(sig))\n    }\n}\n\nimpl Cheatcode for sign_3Call {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { signer, digest } = self;\n        let sig = sign_with_wallet(state, Some(*signer), digest)?;\n        Ok(encode_full_sig(sig))\n    }\n}\n\nimpl Cheatcode for signCompact_3Call {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { signer, digest } = self;\n        let sig = sign_with_wallet(state, Some(*signer), digest)?;\n        Ok(encode_compact_sig(sig))\n    }\n}\n\nimpl Cheatcode for signP256Call {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { privateKey, digest } = self;\n        sign_p256(privateKey, digest)\n    }\n}\n\nimpl Cheatcode for publicKeyP256Call {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { privateKey } = self;\n        let pub_key =\n            parse_private_key_p256(privateKey)?.verifying_key().as_affine().to_encoded_point(false);\n        let pub_key_x = U256::from_be_bytes((*pub_key.x().unwrap()).into());\n        let pub_key_y = U256::from_be_bytes((*pub_key.y().unwrap()).into());\n\n        Ok((pub_key_x, pub_key_y).abi_encode())\n    }\n}\n\nimpl Cheatcode for createEd25519KeyCall {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { salt } = self;\n        create_ed25519_key(salt)\n    }\n}\n\nimpl Cheatcode for publicKeyEd25519Call {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { privateKey } = self;\n        public_key_ed25519(privateKey)\n    }\n}\n\nimpl Cheatcode for signEd25519Call {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { namespace, message, privateKey } = self;\n        sign_ed25519(namespace, message, privateKey)\n    }\n}\n\nimpl Cheatcode for verifyEd25519Call {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { signature, namespace, message, publicKey } = self;\n        verify_ed25519(signature, namespace, message, publicKey)\n    }\n}\n\n/// Using a given private key, return its public ETH address, its public key affine x and y\n/// coordinates, and its private key (see the 'Wallet' struct)\n///\n/// If 'label' is set to 'Some()', assign that label to the associated ETH address in state\nfn create_wallet(private_key: &U256, label: Option<&str>, state: &mut Cheatcodes) -> Result {\n    let key = parse_private_key(private_key)?;\n    let addr = alloy_signer::utils::secret_key_to_address(&key);\n\n    let pub_key = key.verifying_key().as_affine().to_encoded_point(false);\n    let pub_key_x = U256::from_be_bytes((*pub_key.x().unwrap()).into());\n    let pub_key_y = U256::from_be_bytes((*pub_key.y().unwrap()).into());\n\n    if let Some(label) = label {\n        state.labels.insert(addr, label.into());\n    }\n\n    Ok(Wallet { addr, publicKeyX: pub_key_x, publicKeyY: pub_key_y, privateKey: *private_key }\n        .abi_encode())\n}\n\nfn encode_full_sig(sig: alloy_primitives::Signature) -> Vec<u8> {\n    // Retrieve v, r and s from signature.\n    let v = U256::from(sig.v() as u64 + 27);\n    let r = B256::from(sig.r());\n    let s = B256::from(sig.s());\n    (v, r, s).abi_encode()\n}\n\nfn encode_compact_sig(sig: alloy_primitives::Signature) -> Vec<u8> {\n    // Implement EIP-2098 compact signature.\n    let r = B256::from(sig.r());\n    let mut vs = sig.s();\n    vs.set_bit(255, sig.v());\n    (r, vs).abi_encode()\n}\n\nfn sign(private_key: &U256, digest: &B256) -> Result<alloy_primitives::Signature> {\n    // The `ecrecover` precompile does not use EIP-155. No chain ID is needed.\n    let wallet = parse_wallet(private_key)?;\n    let sig = wallet.sign_hash_sync(digest)?;\n    debug_assert_eq!(sig.recover_address_from_prehash(digest)?, wallet.address());\n    Ok(sig)\n}\n\n/// Signs `digest` on secp256k1 using a user-supplied ephemeral nonce `k` (no RFC6979).\n/// - `private_key` and `nonce` must be in (0, n)\n/// - `digest` is a 32-byte prehash.\n///\n/// # Warning\n///\n/// Use [`sign_with_nonce`] with extreme caution!\n/// Reusing the same nonce (`k`) with the same private key in ECDSA will leak the private key.\n/// Always generate `nonce` with a cryptographically secure RNG, and never reuse it across\n/// signatures.\nfn sign_with_nonce(\n    private_key: &U256,\n    digest: &B256,\n    nonce: &U256,\n) -> Result<alloy_primitives::Signature> {\n    let d_scalar: Scalar =\n        <Scalar as k256::elliptic_curve::PrimeField>::from_repr(private_key.to_be_bytes().into())\n            .into_option()\n            .ok_or_else(|| fmt_err!(\"invalid private key scalar\"))?;\n    if bool::from(d_scalar.is_zero()) {\n        return Err(fmt_err!(\"private key cannot be 0\"));\n    }\n\n    let k_scalar: Scalar =\n        <Scalar as k256::elliptic_curve::PrimeField>::from_repr(nonce.to_be_bytes().into())\n            .into_option()\n            .ok_or_else(|| fmt_err!(\"invalid nonce scalar\"))?;\n    if bool::from(k_scalar.is_zero()) {\n        return Err(fmt_err!(\"nonce cannot be 0\"));\n    }\n\n    let mut z = [0u8; 32];\n    z.copy_from_slice(digest.as_slice());\n    let z_fb: FieldBytes = FieldBytes::from(z);\n\n    // Hazmat signing using the scalar `d` (SignPrimitive is implemented for `Scalar`)\n    // Note: returns (Signature, Option<RecoveryId>)\n    let (sig_raw, recid_opt) =\n        <Scalar as hazmat::SignPrimitive<k256::Secp256k1>>::try_sign_prehashed(\n            &d_scalar, k_scalar, &z_fb,\n        )\n        .map_err(|e| fmt_err!(\"sign_prehashed failed: {e}\"))?;\n\n    // Enforce low-s; if mirrored, parity flips (we’ll account for it below if we use recid)\n    let (sig_low, flipped) =\n        if let Some(norm) = sig_raw.normalize_s() { (norm, true) } else { (sig_raw, false) };\n\n    let r_u256 = U256::from_be_bytes(sig_low.r().to_bytes().into());\n    let s_u256 = U256::from_be_bytes(sig_low.s().to_bytes().into());\n\n    // Determine v parity in {0,1}\n    let v_parity = if let Some(id) = recid_opt {\n        let mut v = id.to_byte() & 1;\n        if flipped {\n            v ^= 1;\n        }\n        v\n    } else {\n        // Fallback: choose parity by recovery to expected address\n        let expected_addr = {\n            let sk: SigningKey = parse_private_key(private_key)?;\n            alloy_signer::utils::secret_key_to_address(&sk)\n        };\n        // Try v = 0\n        let cand0 = alloy_primitives::Signature::new(r_u256, s_u256, false);\n        if cand0.recover_address_from_prehash(digest).ok() == Some(expected_addr) {\n            return Ok(cand0);\n        }\n        // Try v = 1\n        let cand1 = alloy_primitives::Signature::new(r_u256, s_u256, true);\n        if cand1.recover_address_from_prehash(digest).ok() == Some(expected_addr) {\n            return Ok(cand1);\n        }\n        return Err(fmt_err!(\"failed to determine recovery id for signature\"));\n    };\n\n    let y_parity = v_parity != 0;\n    Ok(alloy_primitives::Signature::new(r_u256, s_u256, y_parity))\n}\n\nfn sign_with_wallet(\n    state: &mut Cheatcodes,\n    signer: Option<Address>,\n    digest: &B256,\n) -> Result<alloy_primitives::Signature> {\n    if state.wallets().is_empty() {\n        bail!(\"no wallets available\");\n    }\n\n    let mut wallets = state.wallets().inner.lock();\n    let maybe_provided_sender = wallets.provided_sender;\n    let signers = wallets.multi_wallet.signers()?;\n\n    let signer = if let Some(signer) = signer {\n        signer\n    } else if let Some(provided_sender) = maybe_provided_sender {\n        provided_sender\n    } else if signers.len() == 1 {\n        *signers.keys().next().unwrap()\n    } else {\n        bail!(\n            \"could not determine signer, there are multiple signers available use vm.sign(signer, digest) to specify one\"\n        );\n    };\n\n    let wallet = signers\n        .get(&signer)\n        .ok_or_else(|| fmt_err!(\"signer with address {signer} is not available\"))?;\n\n    let sig = foundry_common::block_on(wallet.sign_hash(digest))?;\n    debug_assert_eq!(sig.recover_address_from_prehash(digest)?, signer);\n    Ok(sig)\n}\n\nfn sign_p256(private_key: &U256, digest: &B256) -> Result {\n    let signing_key = parse_private_key_p256(private_key)?;\n    let signature: P256Signature = signing_key.sign_prehash(digest.as_slice())?;\n    let signature = signature.normalize_s().unwrap_or(signature);\n    let r_bytes: [u8; 32] = signature.r().to_bytes().into();\n    let s_bytes: [u8; 32] = signature.s().to_bytes().into();\n\n    Ok((r_bytes, s_bytes).abi_encode())\n}\n\nfn validate_private_key<C: ecdsa::PrimeCurve>(private_key: &U256) -> Result<()> {\n    ensure!(*private_key != U256::ZERO, \"private key cannot be 0\");\n    let order = U256::from_be_slice(&C::ORDER.to_be_byte_array());\n    ensure!(\n        *private_key < order,\n        \"private key must be less than the {curve:?} curve order ({order})\",\n        curve = C::default(),\n    );\n\n    Ok(())\n}\n\nfn parse_private_key(private_key: &U256) -> Result<SigningKey> {\n    validate_private_key::<k256::Secp256k1>(private_key)?;\n    Ok(SigningKey::from_bytes((&private_key.to_be_bytes()).into())?)\n}\n\nfn parse_private_key_p256(private_key: &U256) -> Result<P256SigningKey> {\n    validate_private_key::<p256::NistP256>(private_key)?;\n    Ok(P256SigningKey::from_bytes((&private_key.to_be_bytes()).into())?)\n}\n\nfn parse_signing_key_ed25519(private_key: &B256) -> Result<Ed25519SigningKey> {\n    Ed25519SigningKey::try_from(private_key.as_slice())\n        .map_err(|e| fmt_err!(\"invalid Ed25519 private key: {e}\"))\n}\n\nfn create_ed25519_key(salt: &B256) -> Result {\n    let signing_key = parse_signing_key_ed25519(salt)?;\n    let public_key = B256::from_slice(signing_key.verification_key().as_ref());\n    Ok((public_key, *salt).abi_encode())\n}\n\nfn public_key_ed25519(private_key: &B256) -> Result {\n    let signing_key = parse_signing_key_ed25519(private_key)?;\n    Ok(B256::from_slice(signing_key.verification_key().as_ref()).abi_encode())\n}\n\nfn sign_ed25519(namespace: &[u8], message: &[u8], private_key: &B256) -> Result {\n    let signing_key = parse_signing_key_ed25519(private_key)?;\n    let combined = [namespace, message].concat();\n    let signature: [u8; 64] = signing_key.sign(&combined).into();\n    Ok(signature.to_vec().abi_encode())\n}\n\nfn verify_ed25519(signature: &[u8], namespace: &[u8], message: &[u8], public_key: &B256) -> Result {\n    if signature.len() != 64 {\n        return Ok(false.abi_encode());\n    }\n\n    let Ok(verification_key) = Ed25519VerificationKey::try_from(public_key.as_slice()) else {\n        return Ok(false.abi_encode());\n    };\n\n    let Ok(sig_bytes): Result<[u8; 64], _> = signature.try_into() else {\n        return Ok(false.abi_encode());\n    };\n\n    let combined = [namespace, message].concat();\n    let valid = verification_key.verify(&Ed25519Signature::from(sig_bytes), &combined).is_ok();\n    Ok(valid.abi_encode())\n}\n\npub(super) fn parse_wallet(private_key: &U256) -> Result<PrivateKeySigner> {\n    parse_private_key(private_key).map(PrivateKeySigner::from)\n}\n\nfn derive_key_str(mnemonic: &str, path: &str, index: u32, language: &str) -> Result {\n    match language {\n        \"chinese_simplified\" => derive_key::<ChineseSimplified>(mnemonic, path, index),\n        \"chinese_traditional\" => derive_key::<ChineseTraditional>(mnemonic, path, index),\n        \"czech\" => derive_key::<Czech>(mnemonic, path, index),\n        \"english\" => derive_key::<English>(mnemonic, path, index),\n        \"french\" => derive_key::<French>(mnemonic, path, index),\n        \"italian\" => derive_key::<Italian>(mnemonic, path, index),\n        \"japanese\" => derive_key::<Japanese>(mnemonic, path, index),\n        \"korean\" => derive_key::<Korean>(mnemonic, path, index),\n        \"portuguese\" => derive_key::<Portuguese>(mnemonic, path, index),\n        \"spanish\" => derive_key::<Spanish>(mnemonic, path, index),\n        _ => Err(fmt_err!(\"unsupported mnemonic language: {language:?}\")),\n    }\n}\n\nfn derive_key<W: Wordlist>(mnemonic: &str, path: &str, index: u32) -> Result {\n    fn derive_key_path(path: &str, index: u32) -> String {\n        let mut out = path.to_string();\n        if !out.ends_with('/') {\n            out.push('/');\n        }\n        out.push_str(&index.to_string());\n        out\n    }\n\n    let wallet = MnemonicBuilder::<W>::default()\n        .phrase(mnemonic)\n        .derivation_path(derive_key_path(path, index))?\n        .build()?;\n    let private_key = U256::from_be_bytes(wallet.credential().to_bytes().into());\n    Ok(private_key.abi_encode())\n}\n\nfn derive_wallets_str(\n    mnemonic: &str,\n    path: &str,\n    language: &str,\n    count: u32,\n) -> Result<Vec<LocalSigner<SigningKey>>> {\n    match language {\n        \"chinese_simplified\" => derive_wallets::<ChineseSimplified>(mnemonic, path, count),\n        \"chinese_traditional\" => derive_wallets::<ChineseTraditional>(mnemonic, path, count),\n        \"czech\" => derive_wallets::<Czech>(mnemonic, path, count),\n        \"english\" => derive_wallets::<English>(mnemonic, path, count),\n        \"french\" => derive_wallets::<French>(mnemonic, path, count),\n        \"italian\" => derive_wallets::<Italian>(mnemonic, path, count),\n        \"japanese\" => derive_wallets::<Japanese>(mnemonic, path, count),\n        \"korean\" => derive_wallets::<Korean>(mnemonic, path, count),\n        \"portuguese\" => derive_wallets::<Portuguese>(mnemonic, path, count),\n        \"spanish\" => derive_wallets::<Spanish>(mnemonic, path, count),\n        _ => Err(fmt_err!(\"unsupported mnemonic language: {language:?}\")),\n    }\n}\n\nfn derive_wallets<W: Wordlist>(\n    mnemonic: &str,\n    path: &str,\n    count: u32,\n) -> Result<Vec<LocalSigner<SigningKey>>> {\n    let mut out = path.to_string();\n\n    if !out.ends_with('/') {\n        out.push('/');\n    }\n\n    let mut wallets = Vec::with_capacity(count as usize);\n    for idx in 0..count {\n        let wallet = MnemonicBuilder::<W>::default()\n            .phrase(mnemonic)\n            .derivation_path(format!(\"{out}{idx}\"))?\n            .build()?;\n        wallets.push(wallet);\n    }\n\n    Ok(wallets)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use alloy_primitives::{FixedBytes, hex::FromHex};\n    use k256::elliptic_curve::Curve;\n    use p256::ecdsa::signature::hazmat::PrehashVerifier;\n\n    #[test]\n    fn test_sign_p256() {\n        use p256::ecdsa::VerifyingKey;\n\n        let pk_u256: U256 = \"1\".parse().unwrap();\n        let signing_key = P256SigningKey::from_bytes(&pk_u256.to_be_bytes().into()).unwrap();\n        let digest = FixedBytes::from_hex(\n            \"0x44acf6b7e36c1342c2c5897204fe09504e1e2efb1a900377dbc4e7a6a133ec56\",\n        )\n        .unwrap();\n\n        let result = sign_p256(&pk_u256, &digest).unwrap();\n        let result_bytes: [u8; 64] = result.try_into().unwrap();\n        let signature = P256Signature::from_bytes(&result_bytes.into()).unwrap();\n        let verifying_key = VerifyingKey::from(&signing_key);\n        assert!(verifying_key.verify_prehash(digest.as_slice(), &signature).is_ok());\n    }\n\n    #[test]\n    fn test_sign_p256_pk_too_large() {\n        // max n from https://neuromancer.sk/std/secg/secp256r1\n        let pk =\n            \"0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551\".parse().unwrap();\n        let digest = FixedBytes::from_hex(\n            \"0x54705ba3baafdbdfba8c5f9a70f7a89bee98d906b53e31074da7baecdc0da9ad\",\n        )\n        .unwrap();\n        let result = sign_p256(&pk, &digest);\n        assert_eq!(\n            result.err().unwrap().to_string(),\n            \"private key must be less than the NistP256 curve order (115792089210356248762697446949407573529996955224135760342422259061068512044369)\"\n        );\n    }\n\n    #[test]\n    fn test_sign_p256_pk_0() {\n        let digest = FixedBytes::from_hex(\n            \"0x54705ba3baafdbdfba8c5f9a70f7a89bee98d906b53e31074da7baecdc0da9ad\",\n        )\n        .unwrap();\n        let result = sign_p256(&U256::ZERO, &digest);\n        assert_eq!(result.err().unwrap().to_string(), \"private key cannot be 0\");\n    }\n\n    #[test]\n    fn test_sign_with_nonce_varies_and_recovers() {\n        // Given a fixed private key and digest\n        let pk_u256: U256 = U256::from(1u64);\n        let digest = FixedBytes::from_hex(\n            \"0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\n        )\n        .unwrap();\n\n        // Two distinct nonces\n        let n1: U256 = U256::from(123u64);\n        let n2: U256 = U256::from(456u64);\n\n        // Sign with both nonces\n        let sig1 = sign_with_nonce(&pk_u256, &digest, &n1).expect(\"sig1\");\n        let sig2 = sign_with_nonce(&pk_u256, &digest, &n2).expect(\"sig2\");\n\n        // (r,s) must differ when nonce differs\n        assert!(\n            sig1.r() != sig2.r() || sig1.s() != sig2.s(),\n            \"signatures should differ with different nonces\"\n        );\n\n        // ecrecover must yield the address for both signatures\n        let sk = parse_private_key(&pk_u256).unwrap();\n        let expected = alloy_signer::utils::secret_key_to_address(&sk);\n\n        assert_eq!(sig1.recover_address_from_prehash(&digest).unwrap(), expected);\n        assert_eq!(sig2.recover_address_from_prehash(&digest).unwrap(), expected);\n    }\n\n    #[test]\n    fn test_sign_with_nonce_zero_nonce_errors() {\n        // nonce = 0 should be rejected\n        let pk_u256: U256 = U256::from(1u64);\n        let digest = FixedBytes::from_hex(\n            \"0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\n        )\n        .unwrap();\n        let n0: U256 = U256::ZERO;\n\n        let err = sign_with_nonce(&pk_u256, &digest, &n0).unwrap_err();\n        let msg = err.to_string();\n        assert!(msg.contains(\"nonce cannot be 0\"), \"unexpected error: {msg}\");\n    }\n\n    #[test]\n    fn test_sign_with_nonce_nonce_ge_order_errors() {\n        // nonce >= n should be rejected\n        use k256::Secp256k1;\n        // Curve order n as U256\n        let n_u256 = U256::from_be_slice(&Secp256k1::ORDER.to_be_byte_array());\n\n        let pk_u256: U256 = U256::from(1u64);\n        let digest = FixedBytes::from_hex(\n            \"0xcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc\",\n        )\n        .unwrap();\n\n        // Try exactly n (>= n invalid)\n        let err = sign_with_nonce(&pk_u256, &digest, &n_u256).unwrap_err();\n        let msg = err.to_string();\n        assert!(msg.contains(\"invalid nonce scalar\"), \"unexpected error: {msg}\");\n    }\n\n    #[test]\n    fn test_create_ed25519_key_determinism() {\n        let salt = B256::from([1u8; 32]);\n        let result1 = create_ed25519_key(&salt).unwrap();\n        let result2 = create_ed25519_key(&salt).unwrap();\n        assert_eq!(result1, result2, \"same salt should produce same keys\");\n    }\n\n    #[test]\n    fn test_create_ed25519_key_different_salts() {\n        let salt1 = B256::from([1u8; 32]);\n        let salt2 = B256::from([2u8; 32]);\n        let result1 = create_ed25519_key(&salt1).unwrap();\n        let result2 = create_ed25519_key(&salt2).unwrap();\n        assert_ne!(result1, result2, \"different salts should produce different keys\");\n    }\n\n    #[test]\n    fn test_public_key_ed25519_consistency() {\n        let salt = B256::from([42u8; 32]);\n        let create_result = create_ed25519_key(&salt).unwrap();\n        let (expected_public, private): (B256, B256) =\n            <(B256, B256)>::abi_decode(&create_result).unwrap();\n\n        let derived_public_result = public_key_ed25519(&private).unwrap();\n        let derived_public = B256::abi_decode(&derived_public_result).unwrap();\n\n        assert_eq!(expected_public, derived_public, \"derived public key should match\");\n    }\n\n    #[test]\n    fn test_sign_and_verify_ed25519_valid() {\n        let salt = B256::from([123u8; 32]);\n        let create_result = create_ed25519_key(&salt).unwrap();\n        let (public_key, private_key): (B256, B256) =\n            <(B256, B256)>::abi_decode(&create_result).unwrap();\n\n        let namespace = b\"test.namespace\";\n        let message = b\"hello world\";\n        let sig_result = sign_ed25519(namespace, message, &private_key).unwrap();\n        let sig_bytes: Vec<u8> = Vec::abi_decode(&sig_result).unwrap();\n\n        let verify_result = verify_ed25519(&sig_bytes, namespace, message, &public_key).unwrap();\n        let valid = bool::abi_decode(&verify_result).unwrap();\n\n        assert!(valid, \"signature should be valid\");\n    }\n\n    #[test]\n    fn test_verify_ed25519_invalid_signature() {\n        let salt = B256::from([123u8; 32]);\n        let create_result = create_ed25519_key(&salt).unwrap();\n        let (public_key, _): (B256, B256) = <(B256, B256)>::abi_decode(&create_result).unwrap();\n\n        let invalid_sig = [0u8; 64];\n        let namespace = b\"test.namespace\";\n        let message = b\"hello world\";\n\n        let verify_result = verify_ed25519(&invalid_sig, namespace, message, &public_key).unwrap();\n        let valid = bool::abi_decode(&verify_result).unwrap();\n\n        assert!(!valid, \"invalid signature should not verify\");\n    }\n\n    #[test]\n    fn test_verify_ed25519_namespace_separation() {\n        let salt = B256::from([123u8; 32]);\n        let create_result = create_ed25519_key(&salt).unwrap();\n        let (public_key, private_key): (B256, B256) =\n            <(B256, B256)>::abi_decode(&create_result).unwrap();\n\n        let namespace_a = b\"namespace.a\";\n        let message = b\"message\";\n        let sig_result = sign_ed25519(namespace_a, message, &private_key).unwrap();\n        let sig_bytes: Vec<u8> = Vec::abi_decode(&sig_result).unwrap();\n\n        let namespace_b = b\"namespace.b\";\n        let verify_result = verify_ed25519(&sig_bytes, namespace_b, message, &public_key).unwrap();\n        let valid = bool::abi_decode(&verify_result).unwrap();\n        assert!(!valid, \"signature with namespace A should not verify with namespace B\");\n\n        let verify_result = verify_ed25519(&sig_bytes, namespace_a, message, &public_key).unwrap();\n        let valid = bool::abi_decode(&verify_result).unwrap();\n        assert!(valid, \"signature should verify with correct namespace\");\n    }\n\n    #[test]\n    fn test_verify_ed25519_invalid_signature_length() {\n        let salt = B256::from([123u8; 32]);\n        let create_result = create_ed25519_key(&salt).unwrap();\n        let (public_key, _): (B256, B256) = <(B256, B256)>::abi_decode(&create_result).unwrap();\n\n        let invalid_sig = [0u8; 32];\n        let namespace = b\"test\";\n        let message = b\"message\";\n\n        let verify_result = verify_ed25519(&invalid_sig, namespace, message, &public_key).unwrap();\n        let valid = bool::abi_decode(&verify_result).unwrap();\n        assert!(!valid, \"signature with wrong length should not verify\");\n    }\n}\n"
  },
  {
    "path": "crates/cheatcodes/src/env.rs",
    "content": "//! Implementations of [`Environment`](spec::Group::Environment) cheatcodes.\n\nuse crate::{Cheatcode, Cheatcodes, Error, Result, Vm::*, string};\nuse alloy_dyn_abi::DynSolType;\nuse alloy_sol_types::SolValue;\nuse std::{env, sync::OnceLock};\n\n/// Stores the forge execution context for the duration of the program.\npub static FORGE_CONTEXT: OnceLock<ForgeContext> = OnceLock::new();\n\nimpl Cheatcode for setEnvCall {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { name: key, value } = self;\n        if key.is_empty() {\n            Err(fmt_err!(\"environment variable key can't be empty\"))\n        } else if key.contains('=') {\n            Err(fmt_err!(\"environment variable key can't contain equal sign `=`\"))\n        } else if key.contains('\\0') {\n            Err(fmt_err!(\"environment variable key can't contain NUL character `\\\\0`\"))\n        } else if value.contains('\\0') {\n            Err(fmt_err!(\"environment variable value can't contain NUL character `\\\\0`\"))\n        } else {\n            unsafe {\n                env::set_var(key, value);\n            }\n            Ok(Default::default())\n        }\n    }\n}\n\nimpl Cheatcode for resolveEnvCall {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { input } = self;\n        let resolved = foundry_config::resolve::interpolate(input)\n            .map_err(|e| fmt_err!(\"failed to resolve env var: {e}\"))?;\n        Ok(resolved.abi_encode())\n    }\n}\n\nimpl Cheatcode for envExistsCall {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { name } = self;\n        Ok(env::var(name).is_ok().abi_encode())\n    }\n}\n\nimpl Cheatcode for envBool_0Call {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { name } = self;\n        env(name, &DynSolType::Bool)\n    }\n}\n\nimpl Cheatcode for envUint_0Call {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { name } = self;\n        env(name, &DynSolType::Uint(256))\n    }\n}\n\nimpl Cheatcode for envInt_0Call {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { name } = self;\n        env(name, &DynSolType::Int(256))\n    }\n}\n\nimpl Cheatcode for envAddress_0Call {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { name } = self;\n        env(name, &DynSolType::Address)\n    }\n}\n\nimpl Cheatcode for envBytes32_0Call {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { name } = self;\n        env(name, &DynSolType::FixedBytes(32))\n    }\n}\n\nimpl Cheatcode for envString_0Call {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { name } = self;\n        env(name, &DynSolType::String)\n    }\n}\n\nimpl Cheatcode for envBytes_0Call {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { name } = self;\n        env(name, &DynSolType::Bytes)\n    }\n}\n\nimpl Cheatcode for envBool_1Call {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { name, delim } = self;\n        env_array(name, delim, &DynSolType::Bool)\n    }\n}\n\nimpl Cheatcode for envUint_1Call {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { name, delim } = self;\n        env_array(name, delim, &DynSolType::Uint(256))\n    }\n}\n\nimpl Cheatcode for envInt_1Call {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { name, delim } = self;\n        env_array(name, delim, &DynSolType::Int(256))\n    }\n}\n\nimpl Cheatcode for envAddress_1Call {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { name, delim } = self;\n        env_array(name, delim, &DynSolType::Address)\n    }\n}\n\nimpl Cheatcode for envBytes32_1Call {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { name, delim } = self;\n        env_array(name, delim, &DynSolType::FixedBytes(32))\n    }\n}\n\nimpl Cheatcode for envString_1Call {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { name, delim } = self;\n        env_array(name, delim, &DynSolType::String)\n    }\n}\n\nimpl Cheatcode for envBytes_1Call {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { name, delim } = self;\n        env_array(name, delim, &DynSolType::Bytes)\n    }\n}\n\n// bool\nimpl Cheatcode for envOr_0Call {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { name, defaultValue } = self;\n        env_default(name, defaultValue, &DynSolType::Bool)\n    }\n}\n\n// uint256\nimpl Cheatcode for envOr_1Call {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { name, defaultValue } = self;\n        env_default(name, defaultValue, &DynSolType::Uint(256))\n    }\n}\n\n// int256\nimpl Cheatcode for envOr_2Call {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { name, defaultValue } = self;\n        env_default(name, defaultValue, &DynSolType::Int(256))\n    }\n}\n\n// address\nimpl Cheatcode for envOr_3Call {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { name, defaultValue } = self;\n        env_default(name, defaultValue, &DynSolType::Address)\n    }\n}\n\n// bytes32\nimpl Cheatcode for envOr_4Call {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { name, defaultValue } = self;\n        env_default(name, defaultValue, &DynSolType::FixedBytes(32))\n    }\n}\n\n// string\nimpl Cheatcode for envOr_5Call {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { name, defaultValue } = self;\n        env_default(name, defaultValue, &DynSolType::String)\n    }\n}\n\n// bytes\nimpl Cheatcode for envOr_6Call {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { name, defaultValue } = self;\n        env_default(name, defaultValue, &DynSolType::Bytes)\n    }\n}\n\n// bool[]\nimpl Cheatcode for envOr_7Call {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { name, delim, defaultValue } = self;\n        env_array_default(name, delim, defaultValue, &DynSolType::Bool)\n    }\n}\n\n// uint256[]\nimpl Cheatcode for envOr_8Call {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { name, delim, defaultValue } = self;\n        env_array_default(name, delim, defaultValue, &DynSolType::Uint(256))\n    }\n}\n\n// int256[]\nimpl Cheatcode for envOr_9Call {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { name, delim, defaultValue } = self;\n        env_array_default(name, delim, defaultValue, &DynSolType::Int(256))\n    }\n}\n\n// address[]\nimpl Cheatcode for envOr_10Call {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { name, delim, defaultValue } = self;\n        env_array_default(name, delim, defaultValue, &DynSolType::Address)\n    }\n}\n\n// bytes32[]\nimpl Cheatcode for envOr_11Call {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { name, delim, defaultValue } = self;\n        env_array_default(name, delim, defaultValue, &DynSolType::FixedBytes(32))\n    }\n}\n\n// string[]\nimpl Cheatcode for envOr_12Call {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { name, delim, defaultValue } = self;\n        env_array_default(name, delim, defaultValue, &DynSolType::String)\n    }\n}\n\n// bytes[]\nimpl Cheatcode for envOr_13Call {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { name, delim, defaultValue } = self;\n        let default = defaultValue.to_vec();\n        env_array_default(name, delim, &default, &DynSolType::Bytes)\n    }\n}\n\nimpl Cheatcode for isContextCall {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { context } = self;\n        Ok((FORGE_CONTEXT.get() == Some(context)).abi_encode())\n    }\n}\n\n/// Set `forge` command current execution context for the duration of the program.\n/// Execution context is immutable, subsequent calls of this function won't change the context.\npub fn set_execution_context(context: ForgeContext) {\n    let _ = FORGE_CONTEXT.set(context);\n}\n\nfn env(key: &str, ty: &DynSolType) -> Result {\n    get_env(key).and_then(|val| string::parse(&val, ty).map_err(map_env_err(key, &val)))\n}\n\nfn env_default<T: SolValue>(key: &str, default: &T, ty: &DynSolType) -> Result {\n    Ok(env(key, ty).unwrap_or_else(|_| default.abi_encode()))\n}\n\nfn env_array(key: &str, delim: &str, ty: &DynSolType) -> Result {\n    get_env(key).and_then(|val| {\n        string::parse_array(val.split(delim).map(str::trim), ty).map_err(map_env_err(key, &val))\n    })\n}\n\nfn env_array_default<T: SolValue>(key: &str, delim: &str, default: &T, ty: &DynSolType) -> Result {\n    Ok(env_array(key, delim, ty).unwrap_or_else(|_| default.abi_encode()))\n}\n\nfn get_env(key: &str) -> Result<String> {\n    match env::var(key) {\n        Ok(val) => Ok(val),\n        Err(env::VarError::NotPresent) => Err(fmt_err!(\"environment variable {key:?} not found\")),\n        Err(env::VarError::NotUnicode(s)) => {\n            Err(fmt_err!(\"environment variable {key:?} was not valid unicode: {s:?}\"))\n        }\n    }\n}\n\n/// Converts the error message of a failed parsing attempt to a more user-friendly message that\n/// doesn't leak the value.\nfn map_env_err<'a>(key: &'a str, value: &'a str) -> impl FnOnce(Error) -> Error + 'a {\n    move |e| {\n        // failed parsing <value> as type `uint256`: parser error:\n        // <value>\n        //   ^\n        //   expected at least one digit\n        let mut e = e.to_string();\n        e = e.replacen(&format!(\"\\\"{value}\\\"\"), &format!(\"${key}\"), 1);\n        e = e.replacen(&format!(\"\\n{value}\\n\"), &format!(\"\\n${key}\\n\"), 1);\n        Error::from(e)\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn parse_env_uint() {\n        let key = \"parse_env_uint\";\n        let value = \"t\";\n        unsafe {\n            env::set_var(key, value);\n        }\n\n        let err = env(key, &DynSolType::Uint(256)).unwrap_err().to_string();\n        assert_eq!(err.matches(\"$parse_env_uint\").count(), 2, \"{err:?}\");\n        unsafe {\n            env::remove_var(key);\n        }\n    }\n}\n"
  },
  {
    "path": "crates/cheatcodes/src/error.rs",
    "content": "use crate::Vm;\nuse alloy_primitives::{Bytes, hex};\nuse alloy_signer::Error as SignerError;\nuse alloy_signer_local::LocalSignerError;\nuse alloy_sol_types::SolError;\nuse foundry_common::errors::FsPathError;\nuse foundry_config::UnresolvedEnvVarError;\nuse foundry_evm_core::backend::{BackendError, DatabaseError};\nuse foundry_wallets::error::WalletSignerError;\nuse k256::ecdsa::signature::Error as SignatureError;\nuse revm::context_interface::result::EVMError;\nuse std::{borrow::Cow, fmt};\n\n/// Cheatcode result type.\n///\n/// Type alias with a default Ok type of [`Vec<u8>`], and default Err type of [`Error`].\npub type Result<T = Vec<u8>, E = Error> = std::result::Result<T, E>;\n\nmacro_rules! fmt_err {\n    ($msg:literal $(,)?) => {\n        $crate::Error::fmt(::std::format_args!($msg))\n    };\n    ($err:expr $(,)?) => {\n        <$crate::Error as ::std::convert::From<_>>::from($err)\n    };\n    ($fmt:expr, $($arg:tt)*) => {\n        $crate::Error::fmt(::std::format_args!($fmt, $($arg)*))\n    };\n}\n\nmacro_rules! bail {\n    ($msg:literal $(,)?) => {\n        return ::std::result::Result::Err(fmt_err!($msg))\n    };\n    ($err:expr $(,)?) => {\n        return ::std::result::Result::Err(fmt_err!($err))\n    };\n    ($fmt:expr, $($arg:tt)*) => {\n        return ::std::result::Result::Err(fmt_err!($fmt, $($arg)*))\n    };\n}\n\nmacro_rules! ensure {\n    ($cond:expr $(,)?) => {\n        if !$cond {\n            return ::std::result::Result::Err($crate::Error::custom(\n                ::std::concat!(\"Condition failed: `\", ::std::stringify!($cond), \"`\")\n            ));\n        }\n    };\n    ($cond:expr, $msg:literal $(,)?) => {\n        if !$cond {\n            return ::std::result::Result::Err(fmt_err!($msg));\n        }\n    };\n    ($cond:expr, $err:expr $(,)?) => {\n        if !$cond {\n            return ::std::result::Result::Err(fmt_err!($err));\n        }\n    };\n    ($cond:expr, $fmt:expr, $($arg:tt)*) => {\n        if !$cond {\n            return ::std::result::Result::Err(fmt_err!($fmt, $($arg)*));\n        }\n    };\n}\n\n/// Error thrown by cheatcodes.\n// This uses a custom repr to minimize the size of the error.\n// The repr is basically `enum { Cow<'static, str>, Cow<'static, [u8]> }`\npub struct Error {\n    /// If true, encode `data` as `Error(string)`, otherwise encode it directly as `bytes`.\n    is_str: bool,\n    /// Whether this was constructed from an owned byte vec, which means we have to drop the data\n    /// in `impl Drop`.\n    drop: bool,\n    /// The error data. Always a valid pointer, and never modified.\n    data: *const [u8],\n}\n\nimpl std::error::Error for Error {}\n\nimpl fmt::Debug for Error {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.write_str(\"Error::\")?;\n        self.kind().fmt(f)\n    }\n}\n\nimpl fmt::Display for Error {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        self.kind().fmt(f)\n    }\n}\n\n/// Kind of cheatcode errors.\n///\n/// Constructed by [`Error::kind`].\n#[derive(Debug)]\npub enum ErrorKind<'a> {\n    /// A string error, ABI-encoded as `CheatcodeError(string)`.\n    String(&'a str),\n    /// A raw bytes error. Does not get encoded.\n    Bytes(&'a [u8]),\n}\n\nimpl fmt::Display for ErrorKind<'_> {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        match *self {\n            Self::String(ss) => f.write_str(ss),\n            Self::Bytes(b) => f.write_str(&hex::encode_prefixed(b)),\n        }\n    }\n}\n\nimpl Error {\n    /// Creates a new error and ABI encodes it as `CheatcodeError(string)`.\n    pub fn encode(error: impl Into<Self>) -> Bytes {\n        error.into().abi_encode().into()\n    }\n\n    /// Creates a new error with a custom message.\n    pub fn display(msg: impl fmt::Display) -> Self {\n        Self::fmt(format_args!(\"{msg}\"))\n    }\n\n    /// Creates a new error with a custom [`fmt::Arguments`] message.\n    pub fn fmt(args: fmt::Arguments<'_>) -> Self {\n        match args.as_str() {\n            Some(s) => Self::new_str(s),\n            None => Self::new_string(std::fmt::format(args)),\n        }\n    }\n\n    /// ABI-encodes this error as `CheatcodeError(string)` if the inner message is a string,\n    /// otherwise returns the raw bytes.\n    pub fn abi_encode(&self) -> Vec<u8> {\n        match self.kind() {\n            ErrorKind::String(string) => Vm::CheatcodeError { message: string.into() }.abi_encode(),\n            ErrorKind::Bytes(bytes) => bytes.into(),\n        }\n    }\n\n    /// Returns the kind of this error.\n    pub fn kind(&self) -> ErrorKind<'_> {\n        let data = self.data();\n        if self.is_str {\n            debug_assert!(std::str::from_utf8(data).is_ok());\n            ErrorKind::String(unsafe { std::str::from_utf8_unchecked(data) })\n        } else {\n            ErrorKind::Bytes(data)\n        }\n    }\n\n    /// Returns the raw data of this error.\n    pub fn data(&self) -> &[u8] {\n        unsafe { &*self.data }\n    }\n\n    /// Returns `true` if this error is a human-readable string.\n    pub fn is_str(&self) -> bool {\n        self.is_str\n    }\n\n    fn new_str(data: &'static str) -> Self {\n        Self::_new(true, false, data.as_bytes())\n    }\n\n    fn new_string(data: String) -> Self {\n        Self::_new(true, true, Box::into_raw(data.into_boxed_str().into_boxed_bytes()))\n    }\n\n    fn new_bytes(data: &'static [u8]) -> Self {\n        Self::_new(false, false, data)\n    }\n\n    fn new_vec(data: Vec<u8>) -> Self {\n        Self::_new(false, true, Box::into_raw(data.into_boxed_slice()))\n    }\n\n    fn _new(is_str: bool, drop: bool, data: *const [u8]) -> Self {\n        debug_assert!(!data.is_null());\n        Self { is_str, drop, data }\n    }\n}\n\nimpl Drop for Error {\n    fn drop(&mut self) {\n        if self.drop {\n            drop(unsafe { Box::<[u8]>::from_raw(self.data.cast_mut()) });\n        }\n    }\n}\n\nimpl From<Cow<'static, str>> for Error {\n    fn from(value: Cow<'static, str>) -> Self {\n        match value {\n            Cow::Borrowed(str) => Self::new_str(str),\n            Cow::Owned(string) => Self::new_string(string),\n        }\n    }\n}\n\nimpl From<String> for Error {\n    fn from(value: String) -> Self {\n        Self::new_string(value)\n    }\n}\n\nimpl From<&'static str> for Error {\n    fn from(value: &'static str) -> Self {\n        Self::new_str(value)\n    }\n}\n\nimpl From<Cow<'static, [u8]>> for Error {\n    fn from(value: Cow<'static, [u8]>) -> Self {\n        match value {\n            Cow::Borrowed(bytes) => Self::new_bytes(bytes),\n            Cow::Owned(vec) => Self::new_vec(vec),\n        }\n    }\n}\n\nimpl From<&'static [u8]> for Error {\n    fn from(value: &'static [u8]) -> Self {\n        Self::new_bytes(value)\n    }\n}\n\nimpl<const N: usize> From<&'static [u8; N]> for Error {\n    fn from(value: &'static [u8; N]) -> Self {\n        Self::new_bytes(value)\n    }\n}\n\nimpl From<Vec<u8>> for Error {\n    fn from(value: Vec<u8>) -> Self {\n        Self::new_vec(value)\n    }\n}\n\nimpl From<Bytes> for Error {\n    fn from(value: Bytes) -> Self {\n        Self::new_vec(value.into())\n    }\n}\n\n// So we can use `?` on `Result<_, Error>`.\nmacro_rules! impl_from {\n    ($($t:ty),* $(,)?) => {$(\n        impl From<$t> for Error {\n            fn from(value: $t) -> Self {\n                Self::display(value)\n            }\n        }\n    )*};\n}\n\nimpl_from!(\n    alloy_sol_types::Error,\n    alloy_dyn_abi::Error,\n    alloy_primitives::SignatureError,\n    alloy_consensus::crypto::RecoveryError,\n    FsPathError,\n    hex::FromHexError,\n    BackendError,\n    DatabaseError,\n    jsonpath_lib::JsonPathError,\n    serde_json::Error,\n    SignatureError,\n    std::io::Error,\n    std::num::TryFromIntError,\n    std::str::Utf8Error,\n    std::string::FromUtf8Error,\n    UnresolvedEnvVarError,\n    LocalSignerError,\n    SignerError,\n    WalletSignerError,\n);\n\nimpl<T: Into<BackendError>> From<EVMError<T>> for Error {\n    fn from(err: EVMError<T>) -> Self {\n        Self::display(BackendError::from(err))\n    }\n}\n\nimpl From<eyre::Report> for Error {\n    fn from(err: eyre::Report) -> Self {\n        Self::new_string(foundry_common::errors::display_chain(&err))\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn encode() {\n        let error = Vm::CheatcodeError { message: \"hello\".into() }.abi_encode();\n        assert_eq!(Error::from(\"hello\").abi_encode(), error);\n        assert_eq!(Error::encode(\"hello\"), error);\n\n        assert_eq!(Error::from(b\"hello\").abi_encode(), b\"hello\");\n        assert_eq!(Error::encode(b\"hello\"), b\"hello\"[..]);\n    }\n}\n"
  },
  {
    "path": "crates/cheatcodes/src/evm/fork.rs",
    "content": "use crate::{\n    Cheatcode, Cheatcodes, CheatcodesExecutor, CheatsCtxt, DatabaseExt, EthCheatCtx, Result, Vm::*,\n    json::json_value_to_token,\n};\nuse alloy_dyn_abi::DynSolValue;\nuse alloy_evm::EvmEnv;\nuse alloy_network::AnyNetwork;\nuse alloy_primitives::{B256, U256};\nuse alloy_provider::Provider;\nuse alloy_rpc_types::Filter;\nuse alloy_sol_types::SolValue;\nuse foundry_common::provider::ProviderBuilder;\nuse foundry_evm_core::{FoundryContextExt, backend::JournaledState, fork::CreateFork};\nuse revm::context::{Cfg, ContextTr};\n\nimpl Cheatcode for activeForkCall {\n    fn apply_stateful<CTX: ContextTr<Db: DatabaseExt>>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n    ) -> Result {\n        let Self {} = self;\n        ccx.ecx\n            .db()\n            .active_fork_id()\n            .map(|id| id.abi_encode())\n            .ok_or_else(|| fmt_err!(\"no active fork\"))\n    }\n}\n\nimpl Cheatcode for createFork_0Call {\n    fn apply_stateful<CTX: EthCheatCtx>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self { urlOrAlias } = self;\n        create_fork(ccx, urlOrAlias, None)\n    }\n}\n\nimpl Cheatcode for createFork_1Call {\n    fn apply_stateful<CTX: EthCheatCtx>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self { urlOrAlias, blockNumber } = self;\n        create_fork(ccx, urlOrAlias, Some(blockNumber.saturating_to()))\n    }\n}\n\nimpl Cheatcode for createFork_2Call {\n    fn apply_stateful<CTX: EthCheatCtx>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self { urlOrAlias, txHash } = self;\n        create_fork_at_transaction(ccx, urlOrAlias, txHash)\n    }\n}\n\nimpl Cheatcode for createSelectFork_0Call {\n    fn apply_stateful<CTX: EthCheatCtx>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self { urlOrAlias } = self;\n        create_select_fork(ccx, urlOrAlias, None)\n    }\n}\n\nimpl Cheatcode for createSelectFork_1Call {\n    fn apply_stateful<CTX: EthCheatCtx>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self { urlOrAlias, blockNumber } = self;\n        create_select_fork(ccx, urlOrAlias, Some(blockNumber.saturating_to()))\n    }\n}\n\nimpl Cheatcode for createSelectFork_2Call {\n    fn apply_stateful<CTX: EthCheatCtx>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self { urlOrAlias, txHash } = self;\n        create_select_fork_at_transaction(ccx, urlOrAlias, txHash)\n    }\n}\n\nimpl Cheatcode for rollFork_0Call {\n    fn apply_stateful<CTX: EthCheatCtx>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self { blockNumber } = self;\n        persist_caller(ccx);\n        fork_env_op(ccx, |db, evm_env, tx_env, inner| {\n            db.roll_fork(None, (*blockNumber).to(), evm_env, tx_env, inner)\n        })\n    }\n}\n\nimpl Cheatcode for rollFork_1Call {\n    fn apply_stateful<CTX: EthCheatCtx>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self { txHash } = self;\n        persist_caller(ccx);\n        fork_env_op(ccx, |db, evm_env, tx_env, inner| {\n            db.roll_fork_to_transaction(None, *txHash, evm_env, tx_env, inner)\n        })\n    }\n}\n\nimpl Cheatcode for rollFork_2Call {\n    fn apply_stateful<CTX: EthCheatCtx>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self { forkId, blockNumber } = self;\n        persist_caller(ccx);\n        fork_env_op(ccx, |db, evm_env, tx_env, inner| {\n            db.roll_fork(Some(*forkId), (*blockNumber).to(), evm_env, tx_env, inner)\n        })\n    }\n}\n\nimpl Cheatcode for rollFork_3Call {\n    fn apply_stateful<CTX: EthCheatCtx>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self { forkId, txHash } = self;\n        persist_caller(ccx);\n        fork_env_op(ccx, |db, evm_env, tx_env, inner| {\n            db.roll_fork_to_transaction(Some(*forkId), *txHash, evm_env, tx_env, inner)\n        })\n    }\n}\n\nimpl Cheatcode for selectForkCall {\n    fn apply_stateful<CTX: EthCheatCtx>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self { forkId } = self;\n        persist_caller(ccx);\n        check_broadcast(ccx.state)?;\n        fork_env_op(ccx, |db, evm_env, tx_env, inner| {\n            db.select_fork(*forkId, evm_env, tx_env, inner)\n        })\n    }\n}\n\nimpl Cheatcode for transact_0Call {\n    fn apply_full<CTX: FoundryContextExt>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n        executor: &mut dyn CheatcodesExecutor<CTX>,\n    ) -> Result {\n        let Self { txHash } = *self;\n        transact(ccx, executor, txHash, None)\n    }\n}\n\nimpl Cheatcode for transact_1Call {\n    fn apply_full<CTX: FoundryContextExt>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n        executor: &mut dyn CheatcodesExecutor<CTX>,\n    ) -> Result {\n        let Self { forkId, txHash } = *self;\n        transact(ccx, executor, txHash, Some(forkId))\n    }\n}\n\nimpl Cheatcode for allowCheatcodesCall {\n    fn apply_stateful<CTX: ContextTr<Db: DatabaseExt>>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n    ) -> Result {\n        let Self { account } = self;\n        ccx.ecx.db_mut().allow_cheatcode_access(*account);\n        Ok(Default::default())\n    }\n}\n\nimpl Cheatcode for makePersistent_0Call {\n    fn apply_stateful<CTX: ContextTr<Db: DatabaseExt>>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n    ) -> Result {\n        let Self { account } = self;\n        ccx.ecx.db_mut().add_persistent_account(*account);\n        Ok(Default::default())\n    }\n}\n\nimpl Cheatcode for makePersistent_1Call {\n    fn apply_stateful<CTX: ContextTr<Db: DatabaseExt>>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n    ) -> Result {\n        let Self { account0, account1 } = self;\n        ccx.ecx.db_mut().add_persistent_account(*account0);\n        ccx.ecx.db_mut().add_persistent_account(*account1);\n        Ok(Default::default())\n    }\n}\n\nimpl Cheatcode for makePersistent_2Call {\n    fn apply_stateful<CTX: ContextTr<Db: DatabaseExt>>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n    ) -> Result {\n        let Self { account0, account1, account2 } = self;\n        ccx.ecx.db_mut().add_persistent_account(*account0);\n        ccx.ecx.db_mut().add_persistent_account(*account1);\n        ccx.ecx.db_mut().add_persistent_account(*account2);\n        Ok(Default::default())\n    }\n}\n\nimpl Cheatcode for makePersistent_3Call {\n    fn apply_stateful<CTX: ContextTr<Db: DatabaseExt>>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n    ) -> Result {\n        let Self { accounts } = self;\n        for account in accounts {\n            ccx.ecx.db_mut().add_persistent_account(*account);\n        }\n        Ok(Default::default())\n    }\n}\n\nimpl Cheatcode for revokePersistent_0Call {\n    fn apply_stateful<CTX: ContextTr<Db: DatabaseExt>>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n    ) -> Result {\n        let Self { account } = self;\n        ccx.ecx.db_mut().remove_persistent_account(account);\n        Ok(Default::default())\n    }\n}\n\nimpl Cheatcode for revokePersistent_1Call {\n    fn apply_stateful<CTX: ContextTr<Db: DatabaseExt>>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n    ) -> Result {\n        let Self { accounts } = self;\n        for account in accounts {\n            ccx.ecx.db_mut().remove_persistent_account(account);\n        }\n        Ok(Default::default())\n    }\n}\n\nimpl Cheatcode for isPersistentCall {\n    fn apply_stateful<CTX: ContextTr<Db: DatabaseExt>>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n    ) -> Result {\n        let Self { account } = self;\n        Ok(ccx.ecx.db().is_persistent(account).abi_encode())\n    }\n}\n\nimpl Cheatcode for rpc_0Call {\n    fn apply_stateful<CTX: ContextTr<Db: DatabaseExt>>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n    ) -> Result {\n        let Self { method, params } = self;\n        let url =\n            ccx.ecx.db().active_fork_url().ok_or_else(|| fmt_err!(\"no active fork URL found\"))?;\n        rpc_call(&url, method, params)\n    }\n}\n\nimpl Cheatcode for rpc_1Call {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { urlOrAlias, method, params } = self;\n        let url = state.config.rpc_endpoint(urlOrAlias)?.url()?;\n        rpc_call(&url, method, params)\n    }\n}\n\nimpl Cheatcode for eth_getLogsCall {\n    fn apply_stateful<CTX: ContextTr<Db: DatabaseExt>>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n    ) -> Result {\n        let Self { fromBlock, toBlock, target, topics } = self;\n        let (Ok(from_block), Ok(to_block)) = (u64::try_from(fromBlock), u64::try_from(toBlock))\n        else {\n            bail!(\"blocks in block range must be less than 2^64\")\n        };\n\n        if topics.len() > 4 {\n            bail!(\"topics array must contain at most 4 elements\")\n        }\n\n        let url =\n            ccx.ecx.db().active_fork_url().ok_or_else(|| fmt_err!(\"no active fork URL found\"))?;\n        let provider = ProviderBuilder::<AnyNetwork>::new(&url).build()?;\n        let mut filter = Filter::new().address(*target).from_block(from_block).to_block(to_block);\n        for (i, &topic) in topics.iter().enumerate() {\n            filter.topics[i] = topic.into();\n        }\n\n        let logs = foundry_common::block_on(provider.get_logs(&filter))\n            .map_err(|e| fmt_err!(\"failed to get logs: {e}\"))?;\n\n        let eth_logs = logs\n            .into_iter()\n            .map(|log| EthGetLogs {\n                emitter: log.address(),\n                topics: log.topics().to_vec(),\n                data: log.inner.data.data,\n                blockHash: log.block_hash.unwrap_or_default(),\n                blockNumber: log.block_number.unwrap_or_default(),\n                transactionHash: log.transaction_hash.unwrap_or_default(),\n                transactionIndex: log.transaction_index.unwrap_or_default(),\n                logIndex: U256::from(log.log_index.unwrap_or_default()),\n                removed: log.removed,\n            })\n            .collect::<Vec<_>>();\n\n        Ok(eth_logs.abi_encode())\n    }\n}\n\nimpl Cheatcode for getRawBlockHeaderCall {\n    fn apply_stateful<CTX: ContextTr<Db: DatabaseExt>>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n    ) -> Result {\n        let Self { blockNumber } = self;\n        let url = ccx.ecx.db().active_fork_url().ok_or_else(|| fmt_err!(\"no active fork\"))?;\n        let provider = ProviderBuilder::<AnyNetwork>::new(&url).build()?;\n        let block_number = u64::try_from(blockNumber)\n            .map_err(|_| fmt_err!(\"block number must be less than 2^64\"))?;\n        let block =\n            foundry_common::block_on(async move { provider.get_block(block_number.into()).await })\n                .map_err(|e| fmt_err!(\"failed to get block: {e}\"))?\n                .ok_or_else(|| fmt_err!(\"block {block_number} not found\"))?;\n\n        let header: alloy_consensus::Header = block\n            .into_inner()\n            .header\n            .inner\n            .try_into_header()\n            .map_err(|e| fmt_err!(\"failed to convert to header: {e}\"))?;\n        Ok(alloy_rlp::encode(&header).abi_encode())\n    }\n}\n\n/// Creates and then also selects the new fork\nfn create_select_fork<CTX: EthCheatCtx>(\n    ccx: &mut CheatsCtxt<'_, CTX>,\n    url_or_alias: &str,\n    block: Option<u64>,\n) -> Result {\n    check_broadcast(ccx.state)?;\n\n    let fork = create_fork_request(ccx, url_or_alias, block)?;\n    fork_env_op(ccx, |db, evm_env, tx_env, inner| {\n        db.create_select_fork(fork, evm_env, tx_env, inner)\n    })\n}\n\n/// Creates a new fork\nfn create_fork<CTX: EthCheatCtx>(\n    ccx: &mut CheatsCtxt<'_, CTX>,\n    url_or_alias: &str,\n    block: Option<u64>,\n) -> Result {\n    let fork = create_fork_request(ccx, url_or_alias, block)?;\n    let id = ccx.ecx.db_mut().create_fork(fork)?;\n    Ok(id.abi_encode())\n}\n\n/// Creates and then also selects the new fork at the given transaction\nfn create_select_fork_at_transaction<CTX: EthCheatCtx>(\n    ccx: &mut CheatsCtxt<'_, CTX>,\n    url_or_alias: &str,\n    transaction: &B256,\n) -> Result {\n    check_broadcast(ccx.state)?;\n\n    let fork = create_fork_request(ccx, url_or_alias, None)?;\n    fork_env_op(ccx, |db, evm_env, tx_env, inner| {\n        db.create_select_fork_at_transaction(fork, evm_env, tx_env, inner, *transaction)\n    })\n}\n\n/// Creates a new fork at the given transaction\nfn create_fork_at_transaction<CTX: EthCheatCtx>(\n    ccx: &mut CheatsCtxt<'_, CTX>,\n    url_or_alias: &str,\n    transaction: &B256,\n) -> Result {\n    let fork = create_fork_request(ccx, url_or_alias, None)?;\n    let id = ccx.ecx.db_mut().create_fork_at_transaction(fork, *transaction)?;\n    Ok(id.abi_encode())\n}\n\n/// Creates the request object for a new fork request\nfn create_fork_request<CTX: EthCheatCtx>(\n    ccx: &mut CheatsCtxt<'_, CTX>,\n    url_or_alias: &str,\n    block: Option<u64>,\n) -> Result<CreateFork> {\n    persist_caller(ccx);\n\n    let rpc_endpoint = ccx.state.config.rpc_endpoint(url_or_alias)?;\n    let url = rpc_endpoint.url()?;\n    let mut evm_opts = ccx.state.config.evm_opts.clone();\n    evm_opts.fork_block_number = block;\n    evm_opts.fork_retries = rpc_endpoint.config.retries;\n    evm_opts.fork_retry_backoff = rpc_endpoint.config.retry_backoff;\n    if let Some(Ok(auth)) = rpc_endpoint.auth {\n        evm_opts.fork_headers = Some(vec![format!(\"Authorization: {auth}\")]);\n    }\n    let fork = CreateFork {\n        enable_caching: !ccx.state.config.no_storage_caching\n            && ccx.state.config.rpc_storage_caching.enable_for_endpoint(&url),\n        url,\n        evm_env: EvmEnv {\n            cfg_env: ccx.ecx.cfg_mut().clone(),\n            block_env: ccx.ecx.block_mut().clone(),\n        },\n        evm_opts,\n    };\n    Ok(fork)\n}\n\n/// Clones the EVM and tx environments, runs a fork operation that may modify them, then writes\n/// them back. This is the common pattern for all fork-switching cheatcodes (rollFork, selectFork,\n/// createSelectFork).\nfn fork_env_op<CTX: EthCheatCtx, T: SolValue>(\n    ccx: &mut CheatsCtxt<'_, CTX>,\n    f: impl FnOnce(\n        &mut dyn DatabaseExt<CTX::Block, CTX::Tx, <CTX::Cfg as Cfg>::Spec>,\n        &mut EvmEnv<<CTX::Cfg as Cfg>::Spec, CTX::Block>,\n        &mut CTX::Tx,\n        &mut JournaledState,\n    ) -> eyre::Result<T>,\n) -> Result {\n    let mut evm_env = ccx.ecx.evm_clone();\n    let mut tx_env = ccx.ecx.tx_clone();\n    let (db, inner) = ccx.ecx.db_journal_inner_mut();\n    let result = f(db, &mut evm_env, &mut tx_env, inner)?;\n    ccx.ecx.set_evm(evm_env);\n    ccx.ecx.set_tx(tx_env);\n    Ok(result.abi_encode())\n}\n\nfn check_broadcast(state: &Cheatcodes) -> Result<()> {\n    if state.broadcast.is_none() {\n        Ok(())\n    } else {\n        Err(fmt_err!(\"cannot select forks during a broadcast\"))\n    }\n}\n\nfn transact<CTX: FoundryContextExt>(\n    ccx: &mut CheatsCtxt<'_, CTX>,\n    executor: &mut dyn CheatcodesExecutor<CTX>,\n    transaction: B256,\n    fork_id: Option<U256>,\n) -> Result {\n    executor.transact_on_db(ccx.state, ccx.ecx, fork_id, transaction)?;\n    Ok(Default::default())\n}\n\n// Helper to add the caller of fork cheat code as persistent account (in order to make sure that the\n// state of caller contract is not lost when fork changes).\n// Applies to create, select and roll forks actions.\n// https://github.com/foundry-rs/foundry/issues/8004\nfn persist_caller<CTX: ContextTr<Db: DatabaseExt>>(ccx: &mut CheatsCtxt<'_, CTX>) {\n    ccx.ecx.db_mut().add_persistent_account(ccx.caller);\n}\n\n/// Performs an Ethereum JSON-RPC request to the given endpoint.\nfn rpc_call(url: &str, method: &str, params: &str) -> Result {\n    let provider = ProviderBuilder::<AnyNetwork>::new(url).build()?;\n    let params_json: serde_json::Value = serde_json::from_str(params)?;\n    let result =\n        foundry_common::block_on(provider.raw_request(method.to_string().into(), params_json))\n            .map_err(|err| fmt_err!(\"{method:?}: {err}\"))?;\n    let result_as_tokens = convert_to_bytes(\n        &json_value_to_token(&result, None)\n            .map_err(|err| fmt_err!(\"failed to parse result: {err}\"))?,\n    );\n\n    Ok(result_as_tokens.abi_encode())\n}\n\n/// Convert fixed bytes and address values to bytes in order to prevent encoding issues.\nfn convert_to_bytes(token: &DynSolValue) -> DynSolValue {\n    match token {\n        // Convert fixed bytes to prevent encoding issues.\n        // See: <https://github.com/foundry-rs/foundry/issues/8287>\n        DynSolValue::FixedBytes(bytes, size) => {\n            DynSolValue::Bytes(bytes.as_slice()[..*size].to_vec())\n        }\n        DynSolValue::Address(addr) => DynSolValue::Bytes(addr.to_vec()),\n        //  Convert tuple values to prevent encoding issues.\n        // See: <https://github.com/foundry-rs/foundry/issues/7858>\n        DynSolValue::Tuple(vals) => DynSolValue::Tuple(vals.iter().map(convert_to_bytes).collect()),\n        val => val.clone(),\n    }\n}\n"
  },
  {
    "path": "crates/cheatcodes/src/evm/mapping.rs",
    "content": "use crate::{Cheatcode, Cheatcodes, Result, Vm::*};\nuse alloy_primitives::{Address, B256};\nuse alloy_sol_types::SolValue;\nuse foundry_common::mapping_slots::MappingSlots;\n\nimpl Cheatcode for startMappingRecordingCall {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self {} = self;\n        state.mapping_slots.get_or_insert_default();\n        Ok(Default::default())\n    }\n}\n\nimpl Cheatcode for stopMappingRecordingCall {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self {} = self;\n        state.mapping_slots = None;\n        Ok(Default::default())\n    }\n}\n\nimpl Cheatcode for getMappingLengthCall {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { target, mappingSlot } = self;\n        let result = slot_child(state, target, mappingSlot).map(Vec::len).unwrap_or(0);\n        Ok((result as u64).abi_encode())\n    }\n}\n\nimpl Cheatcode for getMappingSlotAtCall {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { target, mappingSlot, idx } = self;\n        let result = slot_child(state, target, mappingSlot)\n            .and_then(|set| set.get(idx.saturating_to::<usize>()))\n            .copied()\n            .unwrap_or_default();\n        Ok(result.abi_encode())\n    }\n}\n\nimpl Cheatcode for getMappingKeyAndParentOfCall {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { target, elementSlot: slot } = self;\n        let mut found = false;\n        let mut key = &B256::ZERO;\n        let mut parent = &B256::ZERO;\n        if let Some(slots) = mapping_slot(state, target) {\n            if let Some(key2) = slots.keys.get(slot) {\n                found = true;\n                key = key2;\n                parent = &slots.parent_slots[slot];\n            } else if let Some((key2, parent2)) = slots.seen_sha3.get(slot) {\n                found = true;\n                key = key2;\n                parent = parent2;\n            }\n        }\n        Ok((found, key, parent).abi_encode_params())\n    }\n}\n\nfn mapping_slot<'a>(state: &'a Cheatcodes, target: &'a Address) -> Option<&'a MappingSlots> {\n    state.mapping_slots.as_ref()?.get(target)\n}\n\nfn slot_child<'a>(\n    state: &'a Cheatcodes,\n    target: &'a Address,\n    slot: &'a B256,\n) -> Option<&'a Vec<B256>> {\n    mapping_slot(state, target)?.children.get(slot)\n}\n"
  },
  {
    "path": "crates/cheatcodes/src/evm/mock.rs",
    "content": "use crate::{Cheatcode, Cheatcodes, CheatsCtxt, Result, Vm::*};\nuse alloy_primitives::{Address, Bytes, U256};\nuse foundry_evm_core::backend::DatabaseExt;\nuse revm::{\n    bytecode::Bytecode,\n    context::{ContextTr, JournalTr},\n    interpreter::InstructionResult,\n};\nuse std::{cmp::Ordering, collections::VecDeque};\n\n/// Mocked call data.\n#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]\npub struct MockCallDataContext {\n    /// The partial calldata to match for mock\n    pub calldata: Bytes,\n    /// The value to match for mock\n    pub value: Option<U256>,\n}\n\n/// Mocked return data.\n#[derive(Clone, Debug)]\npub struct MockCallReturnData {\n    /// The return type for the mocked call\n    pub ret_type: InstructionResult,\n    /// Return data or error\n    pub data: Bytes,\n}\n\nimpl PartialOrd for MockCallDataContext {\n    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {\n        Some(self.cmp(other))\n    }\n}\n\nimpl Ord for MockCallDataContext {\n    fn cmp(&self, other: &Self) -> Ordering {\n        // Calldata matching is reversed to ensure that a tighter match is\n        // returned if an exact match is not found. In case, there is\n        // a partial match to calldata that is more specific than\n        // a match to a msg.value, then the more specific calldata takes\n        // precedence.\n        self.calldata.cmp(&other.calldata).reverse().then(self.value.cmp(&other.value).reverse())\n    }\n}\n\nimpl Cheatcode for clearMockedCallsCall {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self {} = self;\n        state.mocked_calls = Default::default();\n        Ok(Default::default())\n    }\n}\n\nimpl Cheatcode for mockCall_0Call {\n    fn apply_stateful<CTX: ContextTr<Db: DatabaseExt>>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n    ) -> Result {\n        let Self { callee, data, returnData } = self;\n        let _ = make_acc_non_empty(callee, ccx)?;\n\n        mock_call(ccx.state, callee, data, None, returnData, InstructionResult::Return);\n        Ok(Default::default())\n    }\n}\n\nimpl Cheatcode for mockCall_1Call {\n    fn apply_stateful<CTX: ContextTr<Db: DatabaseExt>>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n    ) -> Result {\n        let Self { callee, msgValue, data, returnData } = self;\n        let _ = make_acc_non_empty(callee, ccx)?;\n\n        mock_call(ccx.state, callee, data, Some(msgValue), returnData, InstructionResult::Return);\n        Ok(Default::default())\n    }\n}\n\nimpl Cheatcode for mockCall_2Call {\n    fn apply_stateful<CTX: ContextTr<Db: DatabaseExt>>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n    ) -> Result {\n        let Self { callee, data, returnData } = self;\n        let _ = make_acc_non_empty(callee, ccx)?;\n\n        mock_call(\n            ccx.state,\n            callee,\n            &Bytes::from(*data),\n            None,\n            returnData,\n            InstructionResult::Return,\n        );\n        Ok(Default::default())\n    }\n}\n\nimpl Cheatcode for mockCall_3Call {\n    fn apply_stateful<CTX: ContextTr<Db: DatabaseExt>>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n    ) -> Result {\n        let Self { callee, msgValue, data, returnData } = self;\n        let _ = make_acc_non_empty(callee, ccx)?;\n\n        mock_call(\n            ccx.state,\n            callee,\n            &Bytes::from(*data),\n            Some(msgValue),\n            returnData,\n            InstructionResult::Return,\n        );\n        Ok(Default::default())\n    }\n}\n\nimpl Cheatcode for mockCalls_0Call {\n    fn apply_stateful<CTX: ContextTr<Db: DatabaseExt>>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n    ) -> Result {\n        let Self { callee, data, returnData } = self;\n        let _ = make_acc_non_empty(callee, ccx)?;\n\n        mock_calls(ccx.state, callee, data, None, returnData, InstructionResult::Return);\n        Ok(Default::default())\n    }\n}\n\nimpl Cheatcode for mockCalls_1Call {\n    fn apply_stateful<CTX: ContextTr<Db: DatabaseExt>>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n    ) -> Result {\n        let Self { callee, msgValue, data, returnData } = self;\n        let _ = make_acc_non_empty(callee, ccx)?;\n\n        mock_calls(ccx.state, callee, data, Some(msgValue), returnData, InstructionResult::Return);\n        Ok(Default::default())\n    }\n}\n\nimpl Cheatcode for mockCallRevert_0Call {\n    fn apply_stateful<CTX: ContextTr<Db: DatabaseExt>>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n    ) -> Result {\n        let Self { callee, data, revertData } = self;\n        let _ = make_acc_non_empty(callee, ccx)?;\n\n        mock_call(ccx.state, callee, data, None, revertData, InstructionResult::Revert);\n        Ok(Default::default())\n    }\n}\n\nimpl Cheatcode for mockCallRevert_1Call {\n    fn apply_stateful<CTX: ContextTr<Db: DatabaseExt>>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n    ) -> Result {\n        let Self { callee, msgValue, data, revertData } = self;\n        let _ = make_acc_non_empty(callee, ccx)?;\n\n        mock_call(ccx.state, callee, data, Some(msgValue), revertData, InstructionResult::Revert);\n        Ok(Default::default())\n    }\n}\n\nimpl Cheatcode for mockCallRevert_2Call {\n    fn apply_stateful<CTX: ContextTr<Db: DatabaseExt>>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n    ) -> Result {\n        let Self { callee, data, revertData } = self;\n        let _ = make_acc_non_empty(callee, ccx)?;\n\n        mock_call(\n            ccx.state,\n            callee,\n            &Bytes::from(*data),\n            None,\n            revertData,\n            InstructionResult::Revert,\n        );\n        Ok(Default::default())\n    }\n}\n\nimpl Cheatcode for mockCallRevert_3Call {\n    fn apply_stateful<CTX: ContextTr<Db: DatabaseExt>>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n    ) -> Result {\n        let Self { callee, msgValue, data, revertData } = self;\n        let _ = make_acc_non_empty(callee, ccx)?;\n\n        mock_call(\n            ccx.state,\n            callee,\n            &Bytes::from(*data),\n            Some(msgValue),\n            revertData,\n            InstructionResult::Revert,\n        );\n        Ok(Default::default())\n    }\n}\n\nimpl Cheatcode for mockFunctionCall {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { callee, target, data } = self;\n        state.mocked_functions.entry(*callee).or_default().insert(data.clone(), *target);\n\n        Ok(Default::default())\n    }\n}\n\nfn mock_call(\n    state: &mut Cheatcodes,\n    callee: &Address,\n    cdata: &Bytes,\n    value: Option<&U256>,\n    rdata: &Bytes,\n    ret_type: InstructionResult,\n) {\n    mock_calls(state, callee, cdata, value, std::slice::from_ref(rdata), ret_type)\n}\n\nfn mock_calls(\n    state: &mut Cheatcodes,\n    callee: &Address,\n    cdata: &Bytes,\n    value: Option<&U256>,\n    rdata_vec: &[Bytes],\n    ret_type: InstructionResult,\n) {\n    state.mocked_calls.entry(*callee).or_default().insert(\n        MockCallDataContext { calldata: cdata.clone(), value: value.copied() },\n        rdata_vec\n            .iter()\n            .map(|rdata| MockCallReturnData { ret_type, data: rdata.clone() })\n            .collect::<VecDeque<_>>(),\n    );\n}\n\n// Etches a single byte onto the account if it is empty to circumvent the `extcodesize`\n// check Solidity might perform.\nfn make_acc_non_empty<CTX: ContextTr<Db: DatabaseExt>>(\n    callee: &Address,\n    ccx: &mut CheatsCtxt<'_, CTX>,\n) -> Result {\n    let empty_bytecode = {\n        let acc = ccx.ecx.journal_mut().load_account(*callee)?;\n        acc.info.code.as_ref().is_none_or(Bytecode::is_empty)\n    };\n    if empty_bytecode {\n        let code = Bytecode::new_raw(Bytes::from_static(&[0u8]));\n        ccx.ecx.journal_mut().set_code(*callee, code);\n    }\n\n    Ok(Default::default())\n}\n"
  },
  {
    "path": "crates/cheatcodes/src/evm/prank.rs",
    "content": "use crate::{Cheatcode, CheatsCtxt, Result, Vm::*, evm::journaled_account};\nuse alloy_primitives::Address;\nuse foundry_evm_core::backend::DatabaseExt;\nuse revm::{\n    context::{ContextTr, JournalTr, Transaction},\n    inspector::JournalExt,\n};\n\n/// Prank information.\n#[derive(Clone, Copy, Debug, Default)]\npub struct Prank {\n    /// Address of the contract that initiated the prank\n    pub prank_caller: Address,\n    /// Address of `tx.origin` when the prank was initiated\n    pub prank_origin: Address,\n    /// The address to assign to `msg.sender`\n    pub new_caller: Address,\n    /// The address to assign to `tx.origin`\n    pub new_origin: Option<Address>,\n    /// The depth at which the prank was called\n    pub depth: usize,\n    /// Whether the prank stops by itself after the next call\n    pub single_call: bool,\n    /// Whether the prank should be applied to delegate call\n    pub delegate_call: bool,\n    /// Whether the prank has been used yet (false if unused)\n    pub used: bool,\n}\n\nimpl Prank {\n    /// Create a new prank.\n    pub fn new(\n        prank_caller: Address,\n        prank_origin: Address,\n        new_caller: Address,\n        new_origin: Option<Address>,\n        depth: usize,\n        single_call: bool,\n        delegate_call: bool,\n    ) -> Self {\n        Self {\n            prank_caller,\n            prank_origin,\n            new_caller,\n            new_origin,\n            depth,\n            single_call,\n            delegate_call,\n            used: false,\n        }\n    }\n\n    /// Apply the prank by setting `used` to true if it is false\n    /// Only returns self in the case it is updated (first application)\n    pub fn first_time_applied(&self) -> Option<Self> {\n        if self.used { None } else { Some(Self { used: true, ..*self }) }\n    }\n}\n\nimpl Cheatcode for prank_0Call {\n    fn apply_stateful<CTX: ContextTr<Journal: JournalExt, Db: DatabaseExt>>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n    ) -> Result {\n        let Self { msgSender } = self;\n        prank(ccx, msgSender, None, true, false)\n    }\n}\n\nimpl Cheatcode for startPrank_0Call {\n    fn apply_stateful<CTX: ContextTr<Journal: JournalExt, Db: DatabaseExt>>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n    ) -> Result {\n        let Self { msgSender } = self;\n        prank(ccx, msgSender, None, false, false)\n    }\n}\n\nimpl Cheatcode for prank_1Call {\n    fn apply_stateful<CTX: ContextTr<Journal: JournalExt, Db: DatabaseExt>>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n    ) -> Result {\n        let Self { msgSender, txOrigin } = self;\n        prank(ccx, msgSender, Some(txOrigin), true, false)\n    }\n}\n\nimpl Cheatcode for startPrank_1Call {\n    fn apply_stateful<CTX: ContextTr<Journal: JournalExt, Db: DatabaseExt>>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n    ) -> Result {\n        let Self { msgSender, txOrigin } = self;\n        prank(ccx, msgSender, Some(txOrigin), false, false)\n    }\n}\n\nimpl Cheatcode for prank_2Call {\n    fn apply_stateful<CTX: ContextTr<Journal: JournalExt, Db: DatabaseExt>>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n    ) -> Result {\n        let Self { msgSender, delegateCall } = self;\n        prank(ccx, msgSender, None, true, *delegateCall)\n    }\n}\n\nimpl Cheatcode for startPrank_2Call {\n    fn apply_stateful<CTX: ContextTr<Journal: JournalExt, Db: DatabaseExt>>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n    ) -> Result {\n        let Self { msgSender, delegateCall } = self;\n        prank(ccx, msgSender, None, false, *delegateCall)\n    }\n}\n\nimpl Cheatcode for prank_3Call {\n    fn apply_stateful<CTX: ContextTr<Journal: JournalExt, Db: DatabaseExt>>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n    ) -> Result {\n        let Self { msgSender, txOrigin, delegateCall } = self;\n        prank(ccx, msgSender, Some(txOrigin), true, *delegateCall)\n    }\n}\n\nimpl Cheatcode for startPrank_3Call {\n    fn apply_stateful<CTX: ContextTr<Journal: JournalExt, Db: DatabaseExt>>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n    ) -> Result {\n        let Self { msgSender, txOrigin, delegateCall } = self;\n        prank(ccx, msgSender, Some(txOrigin), false, *delegateCall)\n    }\n}\n\nimpl Cheatcode for stopPrankCall {\n    fn apply_stateful<CTX: ContextTr<Journal: JournalExt, Db: DatabaseExt>>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n    ) -> Result {\n        let Self {} = self;\n        ccx.state.pranks.remove(&ccx.ecx.journal().depth());\n        Ok(Default::default())\n    }\n}\n\nfn prank<CTX: ContextTr<Journal: JournalExt, Db: DatabaseExt>>(\n    ccx: &mut CheatsCtxt<'_, CTX>,\n    new_caller: &Address,\n    new_origin: Option<&Address>,\n    single_call: bool,\n    delegate_call: bool,\n) -> Result {\n    // Ensure that we load the account of the pranked address and mark it as touched.\n    // This is necessary to ensure that account state changes (such as the account's `nonce`) are\n    // properly tracked.\n    let account = journaled_account(ccx.ecx, *new_caller)?;\n\n    // Ensure that code exists at `msg.sender` if delegate calling.\n    if delegate_call {\n        ensure!(\n            account.info.code.as_ref().is_some_and(|code| !code.is_empty()),\n            \"cannot `prank` delegate call from an EOA\"\n        );\n    }\n\n    let depth = ccx.ecx.journal().depth();\n    if let Some(Prank { used, single_call: current_single_call, .. }) = ccx.state.get_prank(depth) {\n        ensure!(used, \"cannot overwrite a prank until it is applied at least once\");\n        // This case can only fail if the user calls `vm.startPrank` and then `vm.prank` later on.\n        // This should not be possible without first calling `stopPrank`\n        ensure!(\n            single_call == *current_single_call,\n            \"cannot override an ongoing prank with a single vm.prank; \\\n             use vm.startPrank to override the current prank\"\n        );\n    }\n\n    let prank = Prank::new(\n        ccx.caller,\n        ccx.ecx.tx().caller(),\n        *new_caller,\n        new_origin.copied(),\n        depth,\n        single_call,\n        delegate_call,\n    );\n\n    ensure!(\n        ccx.state.broadcast.is_none(),\n        \"cannot `prank` for a broadcasted transaction; \\\n         pass the desired `tx.origin` into the `broadcast` cheatcode call\"\n    );\n\n    ccx.state.pranks.insert(prank.depth, prank);\n    Ok(Default::default())\n}\n"
  },
  {
    "path": "crates/cheatcodes/src/evm/record_debug_step.rs",
    "content": "use alloy_primitives::{Bytes, U256};\n\nuse foundry_evm_traces::CallTraceArena;\nuse revm::{bytecode::opcode::OpCode, interpreter::InstructionResult};\n\nuse foundry_evm_core::buffer::{BufferKind, get_buffer_accesses};\nuse revm_inspectors::tracing::types::{\n    CallTraceNode, CallTraceStep, RecordedMemory, TraceMemberOrder,\n};\nuse spec::Vm::DebugStep;\n\n// Context for a CallTraceStep, includes depth and contract address.\npub(crate) struct CallTraceCtx<'a> {\n    pub node: &'a CallTraceNode,\n    pub step: &'a CallTraceStep,\n}\n\n// Do a depth first traverse of the nodes and steps and return steps\n// that are after `node_start_idx`\npub(crate) fn flatten_call_trace<'a>(\n    root: usize,\n    arena: &'a CallTraceArena,\n    node_start_idx: usize,\n) -> Vec<CallTraceCtx<'a>> {\n    let mut steps = Vec::new();\n    let mut record_started = false;\n\n    // Start the recursion from the root node\n    recursive_flatten_call_trace(root, arena, node_start_idx, &mut record_started, &mut steps);\n    steps\n}\n\n// Inner recursive function to process nodes.\n// This implementation directly mutates `record_started` and `flatten_steps`.\n// So the recursive call can change the `record_started` flag even for the parent\n// unfinished processing, and append steps to the `flatten_steps` as the final result.\nfn recursive_flatten_call_trace<'a>(\n    node_idx: usize,\n    arena: &'a CallTraceArena,\n    node_start_idx: usize,\n    record_started: &mut bool,\n    flatten_steps: &mut Vec<CallTraceCtx<'a>>,\n) {\n    // Once node_idx exceeds node_start_idx, start recording steps\n    // for all the recursive processing.\n    if !*record_started && node_idx >= node_start_idx {\n        *record_started = true;\n    }\n\n    let node = &arena.nodes()[node_idx];\n\n    for order in &node.ordering {\n        match order {\n            TraceMemberOrder::Step(step_idx) if *record_started => {\n                let step = &node.trace.steps[*step_idx];\n                flatten_steps.push(CallTraceCtx { node, step });\n            }\n            TraceMemberOrder::Call(call_idx) => {\n                let child_node_idx = node.children[*call_idx];\n                recursive_flatten_call_trace(\n                    child_node_idx,\n                    arena,\n                    node_start_idx,\n                    record_started,\n                    flatten_steps,\n                );\n            }\n            _ => {}\n        }\n    }\n}\n\n// Function to convert CallTraceStep to DebugStep\npub(crate) fn convert_call_trace_ctx_to_debug_step(ctx: &CallTraceCtx) -> DebugStep {\n    let opcode = ctx.step.op.get();\n    let stack = get_stack_inputs_for_opcode(opcode, ctx.step.stack.as_deref());\n\n    let memory =\n        get_memory_input_for_opcode(opcode, ctx.step.stack.as_deref(), ctx.step.memory.as_ref());\n\n    let is_out_of_gas = matches!(\n        ctx.step.status,\n        Some(\n            InstructionResult::OutOfGas\n                | InstructionResult::MemoryOOG\n                | InstructionResult::MemoryLimitOOG\n                | InstructionResult::PrecompileOOG\n                | InstructionResult::InvalidOperandOOG\n        )\n    );\n\n    let depth = ctx.node.trace.depth as u64 + 1;\n    let contract_addr = ctx.node.execution_address();\n\n    DebugStep {\n        stack,\n        memoryInput: memory,\n        opcode: ctx.step.op.get(),\n        depth,\n        isOutOfGas: is_out_of_gas,\n        contractAddr: contract_addr,\n    }\n}\n\n// The expected `stack` here is from the trace stack, where the top of the stack\n// is the last value of the vector\nfn get_memory_input_for_opcode(\n    opcode: u8,\n    stack: Option<&[U256]>,\n    memory: Option<&RecordedMemory>,\n) -> Bytes {\n    let mut memory_input = Bytes::new();\n    let Some(stack_data) = stack else { return memory_input };\n    let Some(memory_data) = memory else { return memory_input };\n\n    if let Some(accesses) = get_buffer_accesses(opcode, stack_data)\n        && let Some((BufferKind::Memory, access)) = accesses.read\n    {\n        memory_input = get_slice_from_memory(memory_data.as_bytes(), access.offset, access.len);\n    };\n\n    memory_input\n}\n\n// The expected `stack` here is from the trace stack, where the top of the stack\n// is the last value of the vector\nfn get_stack_inputs_for_opcode(opcode: u8, stack: Option<&[U256]>) -> Vec<U256> {\n    let mut inputs = Vec::new();\n\n    let Some(op) = OpCode::new(opcode) else { return inputs };\n    let Some(stack_data) = stack else { return inputs };\n\n    let stack_input_size = op.inputs() as usize;\n    for i in 0..stack_input_size {\n        inputs.push(stack_data[stack_data.len() - 1 - i]);\n    }\n    inputs\n}\n\nfn get_slice_from_memory(memory: &Bytes, start_index: usize, size: usize) -> Bytes {\n    let memory_len = memory.len();\n\n    let end_bound = start_index + size;\n\n    // Return the bytes if data is within the range.\n    if start_index < memory_len && end_bound <= memory_len {\n        return memory.slice(start_index..end_bound);\n    }\n\n    // Pad zero bytes if attempting to load memory partially out of range.\n    if start_index < memory_len && end_bound > memory_len {\n        let mut result = memory.slice(start_index..memory_len).to_vec();\n        result.resize(size, 0u8);\n        return Bytes::from(result);\n    }\n\n    // Return empty bytes with the size if not in range at all.\n    Bytes::from(vec![0u8; size])\n}\n"
  },
  {
    "path": "crates/cheatcodes/src/evm.rs",
    "content": "//! Implementations of [`Evm`](spec::Group::Evm) cheatcodes.\n\nuse crate::{\n    BroadcastableTransaction, Cheatcode, Cheatcodes, CheatcodesExecutor, CheatsCtxt, Error,\n    EthCheatCtx, Result,\n    Vm::*,\n    inspector::{BroadcastKind, RecordDebugStepInfo},\n};\nuse alloy_consensus::{\n    Transaction as TransactionTrait, TxEnvelope, transaction::SignerRecoverable,\n};\nuse alloy_evm::{EvmEnv, FromRecoveredTx};\nuse alloy_genesis::{Genesis, GenesisAccount};\nuse alloy_network::eip2718::EIP4844_TX_TYPE_ID;\nuse alloy_primitives::{\n    Address, B256, Bytes, U256, hex, keccak256,\n    map::{B256Map, HashMap},\n};\nuse alloy_rlp::Decodable;\nuse alloy_sol_types::SolValue;\nuse foundry_common::{\n    fs::{read_json_file, write_json_file},\n    slot_identifier::{\n        ENCODING_BYTES, ENCODING_DYN_ARRAY, ENCODING_INPLACE, ENCODING_MAPPING, SlotIdentifier,\n        SlotInfo,\n    },\n};\nuse foundry_compilers::artifacts::EvmVersion;\nuse foundry_evm_core::{\n    FoundryBlock, FoundryTransaction,\n    backend::{DatabaseExt, RevertStateSnapshotAction},\n    constants::{CALLER, CHEATCODE_ADDRESS, HARDHAT_CONSOLE_ADDRESS, TEST_CONTRACT_ADDRESS},\n    env::FoundryContextExt,\n    utils::get_blob_base_fee_update_fraction_by_spec_id,\n};\nuse foundry_evm_traces::TraceMode;\nuse foundry_primitives::FoundryTxEnvelope;\nuse itertools::Itertools;\nuse rand::Rng;\nuse revm::{\n    bytecode::Bytecode,\n    context::{Block, Cfg, ContextTr, JournalTr, Transaction, TxEnv, result::ExecutionResult},\n    inspector::JournalExt,\n    primitives::{KECCAK_EMPTY, hardfork::SpecId},\n    state::{Account, AccountStatus},\n};\nuse std::{\n    collections::{BTreeMap, HashSet, btree_map::Entry},\n    fmt::Display,\n    path::Path,\n    str::FromStr,\n};\n\nmod record_debug_step;\nuse foundry_common::fmt::format_token_raw;\nuse foundry_config::evm_spec_id;\nuse record_debug_step::{convert_call_trace_ctx_to_debug_step, flatten_call_trace};\nuse serde::Serialize;\n\nmod fork;\npub(crate) mod mapping;\npub(crate) mod mock;\npub(crate) mod prank;\n\n/// JSON-serializable log entry for `getRecordedLogsJson`.\n#[derive(Serialize)]\n#[serde(rename_all = \"camelCase\")]\nstruct LogJson {\n    /// The topics of the log, including the signature, if any.\n    topics: Vec<String>,\n    /// The raw data of the log, hex-encoded with 0x prefix.\n    data: String,\n    /// The address of the log's emitter.\n    emitter: String,\n}\n\n/// Records storage slots reads and writes.\n#[derive(Clone, Debug, Default)]\npub struct RecordAccess {\n    /// Storage slots reads.\n    pub reads: HashMap<Address, Vec<U256>>,\n    /// Storage slots writes.\n    pub writes: HashMap<Address, Vec<U256>>,\n}\n\nimpl RecordAccess {\n    /// Records a read access to a storage slot.\n    pub fn record_read(&mut self, target: Address, slot: U256) {\n        self.reads.entry(target).or_default().push(slot);\n    }\n\n    /// Records a write access to a storage slot.\n    ///\n    /// This also records a read internally as `SSTORE` does an implicit `SLOAD`.\n    pub fn record_write(&mut self, target: Address, slot: U256) {\n        self.record_read(target, slot);\n        self.writes.entry(target).or_default().push(slot);\n    }\n\n    /// Clears the recorded reads and writes.\n    pub fn clear(&mut self) {\n        // Also frees memory.\n        *self = Default::default();\n    }\n}\n\n/// Records the `snapshotGas*` cheatcodes.\n#[derive(Clone, Debug)]\npub struct GasRecord {\n    /// The group name of the gas snapshot.\n    pub group: String,\n    /// The name of the gas snapshot.\n    pub name: String,\n    /// The total gas used in the gas snapshot.\n    pub gas_used: u64,\n    /// Depth at which the gas snapshot was taken.\n    pub depth: usize,\n}\n\n/// Records `deal` cheatcodes\n#[derive(Clone, Debug)]\npub struct DealRecord {\n    /// Target of the deal.\n    pub address: Address,\n    /// The balance of the address before deal was applied\n    pub old_balance: U256,\n    /// Balance after deal was applied\n    pub new_balance: U256,\n}\n\n/// Storage slot diff info.\n#[derive(Serialize, Default)]\n#[serde(rename_all = \"camelCase\")]\nstruct SlotStateDiff {\n    /// Initial storage value.\n    previous_value: B256,\n    /// Current storage value.\n    new_value: B256,\n    /// Storage layout metadata (variable name, type, offset).\n    /// Only present when contract has storage layout output.\n    /// This includes decoded values when available.\n    #[serde(skip_serializing_if = \"Option::is_none\", flatten)]\n    slot_info: Option<SlotInfo>,\n}\n\n/// Balance diff info.\n#[derive(Serialize, Default)]\n#[serde(rename_all = \"camelCase\")]\nstruct BalanceDiff {\n    /// Initial storage value.\n    previous_value: U256,\n    /// Current storage value.\n    new_value: U256,\n}\n\n/// Nonce diff info.\n#[derive(Serialize, Default)]\n#[serde(rename_all = \"camelCase\")]\nstruct NonceDiff {\n    /// Initial nonce value.\n    previous_value: u64,\n    /// Current nonce value.\n    new_value: u64,\n}\n\n/// Account state diff info.\n#[derive(Serialize, Default)]\n#[serde(rename_all = \"camelCase\")]\nstruct AccountStateDiffs {\n    /// Address label, if any set.\n    label: Option<String>,\n    /// Contract identifier from artifact. e.g \"src/Counter.sol:Counter\"\n    contract: Option<String>,\n    /// Account balance changes.\n    balance_diff: Option<BalanceDiff>,\n    /// Account nonce changes.\n    nonce_diff: Option<NonceDiff>,\n    /// State changes, per slot.\n    state_diff: BTreeMap<B256, SlotStateDiff>,\n}\n\nimpl Display for AccountStateDiffs {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> eyre::Result<(), std::fmt::Error> {\n        // Print changed account.\n        if let Some(label) = &self.label {\n            writeln!(f, \"label: {label}\")?;\n        }\n        if let Some(contract) = &self.contract {\n            writeln!(f, \"contract: {contract}\")?;\n        }\n        // Print balance diff if changed.\n        if let Some(balance_diff) = &self.balance_diff\n            && balance_diff.previous_value != balance_diff.new_value\n        {\n            writeln!(\n                f,\n                \"- balance diff: {} → {}\",\n                balance_diff.previous_value, balance_diff.new_value\n            )?;\n        }\n        // Print nonce diff if changed.\n        if let Some(nonce_diff) = &self.nonce_diff\n            && nonce_diff.previous_value != nonce_diff.new_value\n        {\n            writeln!(f, \"- nonce diff: {} → {}\", nonce_diff.previous_value, nonce_diff.new_value)?;\n        }\n        // Print state diff if any.\n        if !&self.state_diff.is_empty() {\n            writeln!(f, \"- state diff:\")?;\n            for (slot, slot_changes) in &self.state_diff {\n                match &slot_changes.slot_info {\n                    Some(slot_info) => {\n                        if let Some(decoded) = &slot_info.decoded {\n                            // Have slot info with decoded values - show decoded values\n                            writeln!(\n                                f,\n                                \"@ {slot} ({}, {}): {} → {}\",\n                                slot_info.label,\n                                slot_info.slot_type.dyn_sol_type,\n                                format_token_raw(&decoded.previous_value),\n                                format_token_raw(&decoded.new_value)\n                            )?;\n                        } else {\n                            // Have slot info but no decoded values - show raw hex values\n                            writeln!(\n                                f,\n                                \"@ {slot} ({}, {}): {} → {}\",\n                                slot_info.label,\n                                slot_info.slot_type.dyn_sol_type,\n                                slot_changes.previous_value,\n                                slot_changes.new_value\n                            )?;\n                        }\n                    }\n                    None => {\n                        // No slot info - show raw hex values\n                        writeln!(\n                            f,\n                            \"@ {slot}: {} → {}\",\n                            slot_changes.previous_value, slot_changes.new_value\n                        )?;\n                    }\n                }\n            }\n        }\n\n        Ok(())\n    }\n}\n\nimpl Cheatcode for addrCall {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { privateKey } = self;\n        let wallet = super::crypto::parse_wallet(privateKey)?;\n        Ok(wallet.address().abi_encode())\n    }\n}\n\nimpl Cheatcode for getNonce_0Call {\n    fn apply_stateful<CTX: ContextTr<Db: DatabaseExt>>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n    ) -> Result {\n        let Self { account } = self;\n        get_nonce(ccx, account)\n    }\n}\n\nimpl Cheatcode for getNonce_1Call {\n    fn apply_stateful<CTX: ContextTr<Db: DatabaseExt>>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n    ) -> Result {\n        let Self { wallet } = self;\n        get_nonce(ccx, &wallet.addr)\n    }\n}\n\nimpl Cheatcode for loadCall {\n    fn apply_stateful<CTX: ContextTr<Db: DatabaseExt>>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n    ) -> Result {\n        let Self { target, slot } = *self;\n        ccx.ensure_not_precompile(&target)?;\n\n        ccx.ecx.journal_mut().load_account(target)?;\n        let mut val = ccx\n            .ecx\n            .journal_mut()\n            .sload(target, slot.into())\n            .map_err(|e| fmt_err!(\"failed to load storage slot: {:?}\", e))?;\n\n        if val.is_cold && val.data.is_zero() {\n            if ccx.state.has_arbitrary_storage(&target) {\n                // If storage slot is untouched and load from a target with arbitrary storage,\n                // then set random value for current slot.\n                let rand_value = ccx.state.rng().random();\n                ccx.state.arbitrary_storage.as_mut().unwrap().save(\n                    ccx.ecx,\n                    target,\n                    slot.into(),\n                    rand_value,\n                );\n                val.data = rand_value;\n            } else if ccx.state.is_arbitrary_storage_copy(&target) {\n                // If storage slot is untouched and load from a target that copies storage from\n                // a source address with arbitrary storage, then copy existing arbitrary value.\n                // If no arbitrary value generated yet, then the random one is saved and set.\n                let rand_value = ccx.state.rng().random();\n                val.data = ccx.state.arbitrary_storage.as_mut().unwrap().copy(\n                    ccx.ecx,\n                    target,\n                    slot.into(),\n                    rand_value,\n                );\n            }\n        }\n\n        Ok(val.abi_encode())\n    }\n}\n\nimpl Cheatcode for loadAllocsCall {\n    fn apply_stateful<CTX: FoundryContextExt<Db: DatabaseExt>>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n    ) -> Result {\n        let Self { pathToAllocsJson } = self;\n\n        let path = Path::new(pathToAllocsJson);\n        ensure!(path.exists(), \"allocs file does not exist: {pathToAllocsJson}\");\n\n        // Let's first assume we're reading a file with only the allocs.\n        let allocs: BTreeMap<Address, GenesisAccount> = match read_json_file(path) {\n            Ok(allocs) => allocs,\n            Err(_) => {\n                // Let's try and read from a genesis file, and extract allocs.\n                let genesis = read_json_file::<Genesis>(path)?;\n                genesis.alloc\n            }\n        };\n\n        // Then, load the allocs into the database.\n        let (db, inner) = ccx.ecx.db_journal_inner_mut();\n        db.load_allocs(&allocs, inner)\n            .map(|()| Vec::default())\n            .map_err(|e| fmt_err!(\"failed to load allocs: {e}\"))\n    }\n}\n\nimpl Cheatcode for cloneAccountCall {\n    fn apply_stateful<CTX: FoundryContextExt<Db: DatabaseExt>>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n    ) -> Result {\n        let Self { source, target } = self;\n\n        let account = ccx.ecx.journal_mut().load_account(*source)?;\n        let genesis = genesis_account(account.data);\n        let (db, inner) = ccx.ecx.db_journal_inner_mut();\n        db.clone_account(&genesis, target, inner)?;\n        // Cloned account should persist in forked envs.\n        ccx.ecx.db_mut().add_persistent_account(*target);\n        Ok(Default::default())\n    }\n}\n\nimpl Cheatcode for dumpStateCall {\n    fn apply_stateful<CTX: ContextTr<Journal: JournalExt>>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n    ) -> Result {\n        let Self { pathToStateJson } = self;\n        let path = Path::new(pathToStateJson);\n\n        // Do not include system account or empty accounts in the dump.\n        let skip = |key: &Address, val: &Account| {\n            key == &CHEATCODE_ADDRESS\n                || key == &CALLER\n                || key == &HARDHAT_CONSOLE_ADDRESS\n                || key == &TEST_CONTRACT_ADDRESS\n                || key == &ccx.caller\n                || key == &ccx.state.config.evm_opts.sender\n                || val.is_empty()\n        };\n\n        let alloc = ccx\n            .ecx\n            .journal_mut()\n            .evm_state_mut()\n            .iter_mut()\n            .filter(|(key, val)| !skip(key, val))\n            .map(|(key, val)| (key, genesis_account(val)))\n            .collect::<BTreeMap<_, _>>();\n\n        write_json_file(path, &alloc)?;\n        Ok(Default::default())\n    }\n}\n\nimpl Cheatcode for recordCall {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self {} = self;\n        state.recording_accesses = true;\n        state.accesses.clear();\n        Ok(Default::default())\n    }\n}\n\nimpl Cheatcode for stopRecordCall {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        state.recording_accesses = false;\n        Ok(Default::default())\n    }\n}\n\nimpl Cheatcode for accessesCall {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { target } = *self;\n        let result = (\n            state.accesses.reads.entry(target).or_default().as_slice(),\n            state.accesses.writes.entry(target).or_default().as_slice(),\n        );\n        Ok(result.abi_encode_params())\n    }\n}\n\nimpl Cheatcode for recordLogsCall {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self {} = self;\n        state.recorded_logs = Some(Default::default());\n        Ok(Default::default())\n    }\n}\n\nimpl Cheatcode for getRecordedLogsCall {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self {} = self;\n        Ok(state.recorded_logs.replace(Default::default()).unwrap_or_default().abi_encode())\n    }\n}\n\nimpl Cheatcode for getRecordedLogsJsonCall {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self {} = self;\n        let logs = state.recorded_logs.replace(Default::default()).unwrap_or_default();\n        let json_logs: Vec<_> = logs\n            .into_iter()\n            .map(|log| LogJson {\n                topics: log.topics.iter().map(|t| format!(\"{t}\")).collect(),\n                data: hex::encode_prefixed(&log.data),\n                emitter: format!(\"{}\", log.emitter),\n            })\n            .collect();\n        Ok(serde_json::to_string(&json_logs)?.abi_encode())\n    }\n}\n\nimpl Cheatcode for pauseGasMeteringCall {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self {} = self;\n        state.gas_metering.paused = true;\n        Ok(Default::default())\n    }\n}\n\nimpl Cheatcode for resumeGasMeteringCall {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self {} = self;\n        state.gas_metering.resume();\n        Ok(Default::default())\n    }\n}\n\nimpl Cheatcode for resetGasMeteringCall {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self {} = self;\n        state.gas_metering.reset();\n        Ok(Default::default())\n    }\n}\n\nimpl Cheatcode for lastCallGasCall {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self {} = self;\n        let Some(last_call_gas) = &state.gas_metering.last_call_gas else {\n            bail!(\"no external call was made yet\");\n        };\n        Ok(last_call_gas.abi_encode())\n    }\n}\n\nimpl Cheatcode for getChainIdCall {\n    fn apply_stateful<CTX: ContextTr>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self {} = self;\n        Ok(U256::from(ccx.ecx.cfg().chain_id()).abi_encode())\n    }\n}\n\nimpl Cheatcode for chainIdCall {\n    fn apply_stateful<CTX: EthCheatCtx>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self { newChainId } = self;\n        ensure!(*newChainId <= U256::from(u64::MAX), \"chain ID must be less than 2^64\");\n        ccx.ecx.cfg_mut().chain_id = newChainId.to();\n        Ok(Default::default())\n    }\n}\n\nimpl Cheatcode for coinbaseCall {\n    fn apply_stateful<CTX: FoundryContextExt>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self { newCoinbase } = self;\n        ccx.ecx.block_mut().set_beneficiary(*newCoinbase);\n        Ok(Default::default())\n    }\n}\n\nimpl Cheatcode for difficultyCall {\n    fn apply_stateful<CTX: FoundryContextExt>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self { newDifficulty } = self;\n        ensure!(\n            ccx.ecx.cfg().spec().into() < SpecId::MERGE,\n            \"`difficulty` is not supported after the Paris hard fork, use `prevrandao` instead; \\\n             see EIP-4399: https://eips.ethereum.org/EIPS/eip-4399\"\n        );\n        ccx.ecx.block_mut().set_difficulty(*newDifficulty);\n        Ok(Default::default())\n    }\n}\n\nimpl Cheatcode for feeCall {\n    fn apply_stateful<CTX: FoundryContextExt>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self { newBasefee } = self;\n        ensure!(*newBasefee <= U256::from(u64::MAX), \"base fee must be less than 2^64\");\n        ccx.ecx.block_mut().set_basefee(newBasefee.saturating_to());\n        Ok(Default::default())\n    }\n}\n\nimpl Cheatcode for prevrandao_0Call {\n    fn apply_stateful<CTX: FoundryContextExt>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self { newPrevrandao } = self;\n        ensure!(\n            ccx.ecx.cfg().spec().into() >= SpecId::MERGE,\n            \"`prevrandao` is not supported before the Paris hard fork, use `difficulty` instead; \\\n             see EIP-4399: https://eips.ethereum.org/EIPS/eip-4399\"\n        );\n        ccx.ecx.block_mut().set_prevrandao(Some(*newPrevrandao));\n        Ok(Default::default())\n    }\n}\n\nimpl Cheatcode for prevrandao_1Call {\n    fn apply_stateful<CTX: FoundryContextExt>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self { newPrevrandao } = self;\n        ensure!(\n            ccx.ecx.cfg().spec().into() >= SpecId::MERGE,\n            \"`prevrandao` is not supported before the Paris hard fork, use `difficulty` instead; \\\n             see EIP-4399: https://eips.ethereum.org/EIPS/eip-4399\"\n        );\n        ccx.ecx.block_mut().set_prevrandao(Some((*newPrevrandao).into()));\n        Ok(Default::default())\n    }\n}\n\nimpl Cheatcode for blobhashesCall {\n    fn apply_stateful<CTX: FoundryContextExt>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self { hashes } = self;\n        ensure!(\n            ccx.ecx.cfg().spec().into() >= SpecId::CANCUN,\n            \"`blobhashes` is not supported before the Cancun hard fork; \\\n             see EIP-4844: https://eips.ethereum.org/EIPS/eip-4844\"\n        );\n        ccx.ecx.tx_mut().set_blob_hashes(hashes.clone());\n        // force this as 4844 txtype\n        ccx.ecx.tx_mut().set_tx_type(EIP4844_TX_TYPE_ID);\n        Ok(Default::default())\n    }\n}\n\nimpl Cheatcode for getBlobhashesCall {\n    fn apply_stateful<CTX: ContextTr>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self {} = self;\n        ensure!(\n            ccx.ecx.cfg().spec().into() >= SpecId::CANCUN,\n            \"`getBlobhashes` is not supported before the Cancun hard fork; \\\n             see EIP-4844: https://eips.ethereum.org/EIPS/eip-4844\"\n        );\n        Ok(ccx.ecx.tx().blob_versioned_hashes().to_vec().abi_encode())\n    }\n}\n\nimpl Cheatcode for rollCall {\n    fn apply_stateful<CTX: FoundryContextExt>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self { newHeight } = self;\n        ccx.ecx.block_mut().set_number(*newHeight);\n        Ok(Default::default())\n    }\n}\n\nimpl Cheatcode for getBlockNumberCall {\n    fn apply_stateful<CTX: ContextTr>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self {} = self;\n        Ok(ccx.ecx.block().number().abi_encode())\n    }\n}\n\nimpl Cheatcode for txGasPriceCall {\n    fn apply_stateful<CTX: FoundryContextExt>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self { newGasPrice } = self;\n        ensure!(*newGasPrice <= U256::from(u64::MAX), \"gas price must be less than 2^64\");\n        ccx.ecx.tx_mut().set_gas_price(newGasPrice.saturating_to());\n        Ok(Default::default())\n    }\n}\n\nimpl Cheatcode for warpCall {\n    fn apply_stateful<CTX: FoundryContextExt>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self { newTimestamp } = self;\n        ccx.ecx.block_mut().set_timestamp(*newTimestamp);\n        Ok(Default::default())\n    }\n}\n\nimpl Cheatcode for getBlockTimestampCall {\n    fn apply_stateful<CTX: ContextTr>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self {} = self;\n        Ok(ccx.ecx.block().timestamp().abi_encode())\n    }\n}\n\nimpl Cheatcode for blobBaseFeeCall {\n    fn apply_stateful<CTX: FoundryContextExt>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self { newBlobBaseFee } = self;\n        ensure!(\n            ccx.ecx.cfg().spec().into() >= SpecId::CANCUN,\n            \"`blobBaseFee` is not supported before the Cancun hard fork; \\\n             see EIP-4844: https://eips.ethereum.org/EIPS/eip-4844\"\n        );\n\n        let spec: SpecId = ccx.ecx.cfg().spec().into();\n        ccx.ecx.block_mut().set_blob_excess_gas_and_price(\n            (*newBlobBaseFee).to(),\n            get_blob_base_fee_update_fraction_by_spec_id(spec),\n        );\n        Ok(Default::default())\n    }\n}\n\nimpl Cheatcode for getBlobBaseFeeCall {\n    fn apply_stateful<CTX: ContextTr>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self {} = self;\n        Ok(ccx.ecx.block().blob_excess_gas().unwrap_or(0).abi_encode())\n    }\n}\n\nimpl Cheatcode for dealCall {\n    fn apply_stateful<CTX: ContextTr<Db: DatabaseExt, Journal: JournalExt>>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n    ) -> Result {\n        let Self { account: address, newBalance: new_balance } = *self;\n        let account = journaled_account(ccx.ecx, address)?;\n        let old_balance = std::mem::replace(&mut account.info.balance, new_balance);\n        let record = DealRecord { address, old_balance, new_balance };\n        ccx.state.eth_deals.push(record);\n        Ok(Default::default())\n    }\n}\n\nimpl Cheatcode for etchCall {\n    fn apply_stateful<CTX: ContextTr<Db: DatabaseExt>>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n    ) -> Result {\n        let Self { target, newRuntimeBytecode } = self;\n        ccx.ensure_not_precompile(target)?;\n        ccx.ecx.journal_mut().load_account(*target)?;\n        let bytecode = Bytecode::new_raw_checked(newRuntimeBytecode.clone())\n            .map_err(|e| fmt_err!(\"failed to create bytecode: {e}\"))?;\n        ccx.ecx.journal_mut().set_code(*target, bytecode);\n        Ok(Default::default())\n    }\n}\n\nimpl Cheatcode for resetNonceCall {\n    fn apply_stateful<CTX: ContextTr<Db: DatabaseExt, Journal: JournalExt>>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n    ) -> Result {\n        let Self { account } = self;\n        let account = journaled_account(ccx.ecx, *account)?;\n        // Per EIP-161, EOA nonces start at 0, but contract nonces\n        // start at 1. Comparing by code_hash instead of code\n        // to avoid hitting the case where account's code is None.\n        let empty = account.info.code_hash == KECCAK_EMPTY;\n        let nonce = if empty { 0 } else { 1 };\n        account.info.nonce = nonce;\n        debug!(target: \"cheatcodes\", nonce, \"reset\");\n        Ok(Default::default())\n    }\n}\n\nimpl Cheatcode for setNonceCall {\n    fn apply_stateful<CTX: ContextTr<Db: DatabaseExt, Journal: JournalExt>>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n    ) -> Result {\n        let Self { account, newNonce } = *self;\n        let account = journaled_account(ccx.ecx, account)?;\n        // nonce must increment only\n        let current = account.info.nonce;\n        ensure!(\n            newNonce >= current,\n            \"new nonce ({newNonce}) must be strictly equal to or higher than the \\\n             account's current nonce ({current})\"\n        );\n        account.info.nonce = newNonce;\n        Ok(Default::default())\n    }\n}\n\nimpl Cheatcode for setNonceUnsafeCall {\n    fn apply_stateful<CTX: ContextTr<Db: DatabaseExt, Journal: JournalExt>>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n    ) -> Result {\n        let Self { account, newNonce } = *self;\n        let account = journaled_account(ccx.ecx, account)?;\n        account.info.nonce = newNonce;\n        Ok(Default::default())\n    }\n}\n\nimpl Cheatcode for storeCall {\n    fn apply_stateful<CTX: ContextTr<Db: DatabaseExt>>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n    ) -> Result {\n        let Self { target, slot, value } = *self;\n        ccx.ensure_not_precompile(&target)?;\n        ensure_loaded_account(ccx.ecx, target)?;\n        ccx.ecx\n            .journal_mut()\n            .sstore(target, slot.into(), value.into())\n            .map_err(|e| fmt_err!(\"failed to store storage slot: {:?}\", e))?;\n        Ok(Default::default())\n    }\n}\n\nimpl Cheatcode for coolCall {\n    fn apply_stateful<CTX: ContextTr<Journal: JournalExt>>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n    ) -> Result {\n        let Self { target } = self;\n        if let Some(account) = ccx.ecx.journal_mut().evm_state_mut().get_mut(target) {\n            account.unmark_touch();\n            account.storage.values_mut().for_each(|slot| slot.mark_cold());\n        }\n        Ok(Default::default())\n    }\n}\n\nimpl Cheatcode for accessListCall {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { access } = self;\n        let access_list = access\n            .iter()\n            .map(|item| {\n                let keys = item.storageKeys.iter().map(|key| B256::from(*key)).collect_vec();\n                alloy_rpc_types::AccessListItem { address: item.target, storage_keys: keys }\n            })\n            .collect_vec();\n        state.access_list = Some(alloy_rpc_types::AccessList::from(access_list));\n        Ok(Default::default())\n    }\n}\n\nimpl Cheatcode for noAccessListCall {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self {} = self;\n        // Set to empty option in order to override previous applied access list.\n        if state.access_list.is_some() {\n            state.access_list = Some(alloy_rpc_types::AccessList::default());\n        }\n        Ok(Default::default())\n    }\n}\n\nimpl Cheatcode for warmSlotCall {\n    fn apply_stateful<CTX: ContextTr<Journal: JournalExt>>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n    ) -> Result {\n        let Self { target, slot } = *self;\n        set_cold_slot(ccx, target, slot.into(), false);\n        Ok(Default::default())\n    }\n}\n\nimpl Cheatcode for coolSlotCall {\n    fn apply_stateful<CTX: ContextTr<Journal: JournalExt>>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n    ) -> Result {\n        let Self { target, slot } = *self;\n        set_cold_slot(ccx, target, slot.into(), true);\n        Ok(Default::default())\n    }\n}\n\nimpl Cheatcode for readCallersCall {\n    fn apply_stateful<CTX: ContextTr>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self {} = self;\n        read_callers(ccx.state, &ccx.ecx.tx().caller(), ccx.ecx.journal().depth())\n    }\n}\n\nimpl Cheatcode for snapshotValue_0Call {\n    fn apply_stateful<CTX>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self { name, value } = self;\n        inner_value_snapshot(ccx, None, Some(name.clone()), value.to_string())\n    }\n}\n\nimpl Cheatcode for snapshotValue_1Call {\n    fn apply_stateful<CTX>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self { group, name, value } = self;\n        inner_value_snapshot(ccx, Some(group.clone()), Some(name.clone()), value.to_string())\n    }\n}\n\nimpl Cheatcode for snapshotGasLastCall_0Call {\n    fn apply_stateful<CTX>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self { name } = self;\n        let Some(last_call_gas) = &ccx.state.gas_metering.last_call_gas else {\n            bail!(\"no external call was made yet\");\n        };\n        inner_last_gas_snapshot(ccx, None, Some(name.clone()), last_call_gas.gasTotalUsed)\n    }\n}\n\nimpl Cheatcode for snapshotGasLastCall_1Call {\n    fn apply_stateful<CTX>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self { name, group } = self;\n        let Some(last_call_gas) = &ccx.state.gas_metering.last_call_gas else {\n            bail!(\"no external call was made yet\");\n        };\n        inner_last_gas_snapshot(\n            ccx,\n            Some(group.clone()),\n            Some(name.clone()),\n            last_call_gas.gasTotalUsed,\n        )\n    }\n}\n\nimpl Cheatcode for startSnapshotGas_0Call {\n    fn apply_stateful<CTX: ContextTr>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self { name } = self;\n        inner_start_gas_snapshot(ccx, None, Some(name.clone()))\n    }\n}\n\nimpl Cheatcode for startSnapshotGas_1Call {\n    fn apply_stateful<CTX: ContextTr>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self { group, name } = self;\n        inner_start_gas_snapshot(ccx, Some(group.clone()), Some(name.clone()))\n    }\n}\n\nimpl Cheatcode for stopSnapshotGas_0Call {\n    fn apply_stateful<CTX>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self {} = self;\n        inner_stop_gas_snapshot(ccx, None, None)\n    }\n}\n\nimpl Cheatcode for stopSnapshotGas_1Call {\n    fn apply_stateful<CTX>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self { name } = self;\n        inner_stop_gas_snapshot(ccx, None, Some(name.clone()))\n    }\n}\n\nimpl Cheatcode for stopSnapshotGas_2Call {\n    fn apply_stateful<CTX>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self { group, name } = self;\n        inner_stop_gas_snapshot(ccx, Some(group.clone()), Some(name.clone()))\n    }\n}\n\n// Deprecated in favor of `snapshotStateCall`\nimpl Cheatcode for snapshotCall {\n    fn apply_stateful<CTX: EthCheatCtx>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self {} = self;\n        inner_snapshot_state(ccx)\n    }\n}\n\nimpl Cheatcode for snapshotStateCall {\n    fn apply_stateful<CTX: EthCheatCtx>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self {} = self;\n        inner_snapshot_state(ccx)\n    }\n}\n\n// Deprecated in favor of `revertToStateCall`\nimpl Cheatcode for revertToCall {\n    fn apply_stateful<CTX: EthCheatCtx>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self { snapshotId } = self;\n        inner_revert_to_state(ccx, *snapshotId)\n    }\n}\n\nimpl Cheatcode for revertToStateCall {\n    fn apply_stateful<CTX: EthCheatCtx>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self { snapshotId } = self;\n        inner_revert_to_state(ccx, *snapshotId)\n    }\n}\n\n// Deprecated in favor of `revertToStateAndDeleteCall`\nimpl Cheatcode for revertToAndDeleteCall {\n    fn apply_stateful<CTX: EthCheatCtx>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self { snapshotId } = self;\n        inner_revert_to_state_and_delete(ccx, *snapshotId)\n    }\n}\n\nimpl Cheatcode for revertToStateAndDeleteCall {\n    fn apply_stateful<CTX: EthCheatCtx>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self { snapshotId } = self;\n        inner_revert_to_state_and_delete(ccx, *snapshotId)\n    }\n}\n\n// Deprecated in favor of `deleteStateSnapshotCall`\nimpl Cheatcode for deleteSnapshotCall {\n    fn apply_stateful<CTX: FoundryContextExt<Db: DatabaseExt>>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n    ) -> Result {\n        let Self { snapshotId } = self;\n        inner_delete_state_snapshot(ccx, *snapshotId)\n    }\n}\n\nimpl Cheatcode for deleteStateSnapshotCall {\n    fn apply_stateful<CTX: ContextTr<Db: DatabaseExt>>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n    ) -> Result {\n        let Self { snapshotId } = self;\n        inner_delete_state_snapshot(ccx, *snapshotId)\n    }\n}\n\n// Deprecated in favor of `deleteStateSnapshotsCall`\nimpl Cheatcode for deleteSnapshotsCall {\n    fn apply_stateful<CTX: ContextTr<Db: DatabaseExt>>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n    ) -> Result {\n        let Self {} = self;\n        inner_delete_state_snapshots(ccx)\n    }\n}\n\nimpl Cheatcode for deleteStateSnapshotsCall {\n    fn apply_stateful<CTX: ContextTr<Db: DatabaseExt>>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n    ) -> Result {\n        let Self {} = self;\n        inner_delete_state_snapshots(ccx)\n    }\n}\n\nimpl Cheatcode for startStateDiffRecordingCall {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self {} = self;\n        state.recorded_account_diffs_stack = Some(Default::default());\n        // Enable mapping recording to track mapping slot accesses\n        state.mapping_slots.get_or_insert_default();\n        Ok(Default::default())\n    }\n}\n\nimpl Cheatcode for stopAndReturnStateDiffCall {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self {} = self;\n        get_state_diff(state)\n    }\n}\n\nimpl Cheatcode for getStateDiffCall {\n    fn apply_stateful<CTX: ContextTr<Db: DatabaseExt>>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n    ) -> Result {\n        let mut diffs = String::new();\n        let state_diffs = get_recorded_state_diffs(ccx);\n        for (address, state_diffs) in state_diffs {\n            diffs.push_str(&format!(\"{address}\\n\"));\n            diffs.push_str(&format!(\"{state_diffs}\\n\"));\n        }\n        Ok(diffs.abi_encode())\n    }\n}\n\nimpl Cheatcode for getStateDiffJsonCall {\n    fn apply_stateful<CTX: ContextTr<Db: DatabaseExt>>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n    ) -> Result {\n        let state_diffs = get_recorded_state_diffs(ccx);\n        Ok(serde_json::to_string(&state_diffs)?.abi_encode())\n    }\n}\n\nimpl Cheatcode for getStorageSlotsCall {\n    fn apply_stateful<CTX: ContextTr<Db: DatabaseExt>>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n    ) -> Result {\n        let Self { target, variableName } = self;\n\n        let storage_layout = get_contract_data(ccx, *target)\n            .and_then(|(_, data)| data.storage_layout.as_ref().map(|layout| layout.clone()))\n            .ok_or_else(|| fmt_err!(\"Storage layout not available for contract at {target}. Try compiling contracts with `--extra-output storageLayout`\"))?;\n\n        trace!(storage = ?storage_layout.storage, \"fetched storage\");\n\n        let variable_name_lower = variableName.to_lowercase();\n        let storage = storage_layout\n            .storage\n            .iter()\n            .find(|s| s.label.to_lowercase() == variable_name_lower)\n            .ok_or_else(|| fmt_err!(\"variable '{variableName}' not found in storage layout\"))?;\n\n        let storage_type = storage_layout\n            .types\n            .get(&storage.storage_type)\n            .ok_or_else(|| fmt_err!(\"storage type not found for variable {variableName}\"))?;\n\n        if storage_type.encoding == ENCODING_MAPPING || storage_type.encoding == ENCODING_DYN_ARRAY\n        {\n            return Err(fmt_err!(\n                \"cannot get storage slots for variables with mapping or dynamic array types\"\n            ));\n        }\n\n        let slot = U256::from_str(&storage.slot).map_err(|_| {\n            fmt_err!(\"invalid slot {} format for variable {variableName}\", storage.slot)\n        })?;\n\n        let mut slots = Vec::new();\n\n        // Always push the base slot\n        slots.push(slot);\n\n        if storage_type.encoding == ENCODING_INPLACE {\n            // For inplace encoding, calculate the number of slots needed\n            let num_bytes = U256::from_str(&storage_type.number_of_bytes).map_err(|_| {\n                fmt_err!(\n                    \"invalid number_of_bytes {} for variable {variableName}\",\n                    storage_type.number_of_bytes\n                )\n            })?;\n            let num_slots = num_bytes.div_ceil(U256::from(32));\n\n            // Start from 1 since base slot is already added\n            for i in 1..num_slots.to::<usize>() {\n                slots.push(slot + U256::from(i));\n            }\n        }\n\n        if storage_type.encoding == ENCODING_BYTES {\n            // Try to check if it's a long bytes/string by reading the current storage\n            // value\n            if let Ok(value) = ccx.ecx.journal_mut().sload(*target, slot) {\n                let value_bytes = value.data.to_be_bytes::<32>();\n                let length_byte = value_bytes[31];\n                // Check if it's a long bytes/string (LSB is 1)\n                if length_byte & 1 == 1 {\n                    // Calculate data slots for long bytes/string\n                    let length: U256 = value.data >> 1;\n                    let num_data_slots = length.to::<usize>().div_ceil(32);\n                    let data_start = U256::from_be_bytes(keccak256(B256::from(slot).0).0);\n\n                    for i in 0..num_data_slots {\n                        slots.push(data_start + U256::from(i));\n                    }\n                }\n            }\n        }\n\n        Ok(slots.abi_encode())\n    }\n}\n\nimpl Cheatcode for getStorageAccessesCall {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let mut storage_accesses = Vec::new();\n\n        if let Some(recorded_diffs) = &state.recorded_account_diffs_stack {\n            for account_accesses in recorded_diffs.iter().flatten() {\n                storage_accesses.extend(account_accesses.storageAccesses.clone());\n            }\n        }\n\n        Ok(storage_accesses.abi_encode())\n    }\n}\n\nimpl Cheatcode for broadcastRawTransactionCall {\n    fn apply_full<CTX: EthCheatCtx>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n        executor: &mut dyn CheatcodesExecutor<CTX>,\n    ) -> Result {\n        let tx = TxEnvelope::decode(&mut self.data.as_ref())\n            .map_err(|err| fmt_err!(\"failed to decode RLP-encoded transaction: {err}\"))?;\n\n        let from = tx.recover_signer()?;\n        let tx_env = FromRecoveredTx::from_recovered_tx(&tx, from);\n\n        executor.transact_from_tx_on_db(ccx.state, ccx.ecx, &tx_env)?;\n\n        if ccx.state.broadcast.is_some() {\n            ccx.state.broadcastable_transactions.push_back(BroadcastableTransaction {\n                rpc: ccx.ecx.db().active_fork_url(),\n                from,\n                to: Some(tx.kind()),\n                value: tx.value(),\n                input: tx.input().clone(),\n                nonce: tx.nonce(),\n                gas: Some(tx.gas_limit()),\n                kind: BroadcastKind::Signed(Bytes::copy_from_slice(&self.data)),\n            });\n        }\n\n        Ok(Default::default())\n    }\n}\n\nimpl Cheatcode for setBlockhashCall {\n    fn apply_stateful<CTX: ContextTr<Db: DatabaseExt>>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n    ) -> Result {\n        let Self { blockNumber, blockHash } = *self;\n        ensure!(blockNumber <= U256::from(u64::MAX), \"blockNumber must be less than 2^64\");\n        ensure!(\n            blockNumber <= U256::from(ccx.ecx.block().number()),\n            \"block number must be less than or equal to the current block number\"\n        );\n\n        ccx.ecx.db_mut().set_blockhash(blockNumber, blockHash);\n\n        Ok(Default::default())\n    }\n}\n\nimpl Cheatcode for executeTransactionCall {\n    fn apply_full<CTX: EthCheatCtx>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n        executor: &mut dyn CheatcodesExecutor<CTX>,\n    ) -> Result {\n        use crate::env::FORGE_CONTEXT;\n\n        // Block in script contexts.\n        if let Some(ctx) = FORGE_CONTEXT.get()\n            && *ctx == ForgeContext::ScriptGroup\n        {\n            return Err(fmt_err!(\"executeTransaction is not allowed in forge script\"));\n        }\n\n        // Decode the RLP-encoded signed transaction.\n        let tx = FoundryTxEnvelope::decode(&mut self.rawTx.as_ref())\n            .map_err(|err| fmt_err!(\"failed to decode RLP-encoded transaction: {err}\"))?;\n\n        // Reject unsupported transaction types.\n        // TODO: add support for OP deposit transactions.\n        if matches!(tx, FoundryTxEnvelope::Deposit(_)) {\n            return Err(fmt_err!(\n                \"OP deposit transactions are not yet supported by executeTransaction\"\n            ));\n        }\n        // TODO: add support for Tempo AA transactions.\n        if matches!(tx, FoundryTxEnvelope::Tempo(_)) {\n            return Err(fmt_err!(\"Tempo transactions are not yet supported by executeTransaction\"));\n        }\n\n        // Recover signer from the transaction signature.\n        let sender = tx.recover().map_err(|err| fmt_err!(\"failed to recover signer: {err}\"))?;\n\n        // Build TxEnv from the recovered transaction.\n        let tx_env = <TxEnv as FromRecoveredTx<FoundryTxEnvelope>>::from_recovered_tx(&tx, sender);\n\n        // Save current env for restoration after execution.\n        let cached_evm_env = ccx.ecx.evm_clone();\n        let cached_tx_env = ccx.ecx.tx_clone();\n\n        // Override env for isolated execution.\n        ccx.ecx.block_mut().set_basefee(0);\n        ccx.ecx.set_tx(tx_env);\n        ccx.ecx.tx_mut().set_gas_price(0);\n        ccx.ecx.tx_mut().set_gas_priority_fee(None);\n\n        // Enable nonce checks for realistic simulation.\n        ccx.ecx.cfg_mut().disable_nonce_check = false;\n\n        // EIP-3860: enforce initcode size limit.\n        ccx.ecx.cfg_mut().limit_contract_initcode_size =\n            Some(revm::primitives::eip3860::MAX_INITCODE_SIZE);\n\n        // Snapshot the modified env for EVM construction.\n        let modified_evm_env = ccx.ecx.evm_clone();\n        let modified_tx_env = ccx.ecx.tx_clone();\n\n        // Mark as inner context so isolation mode doesn't trigger a nested transact_inner\n        // when the inner EVM executes calls at depth == 1.\n        executor.set_in_inner_context(true, Some(sender));\n\n        // Clone journaled state and mark all accounts/slots cold.\n        let cold_state = {\n            let (_, journal) = ccx.ecx.db_journal_inner_mut();\n            let mut state = journal.state.clone();\n            for (addr, acc_mut) in &mut state {\n                if journal.warm_addresses.is_cold(addr) {\n                    acc_mut.mark_cold();\n                }\n                for slot_mut in acc_mut.storage.values_mut() {\n                    slot_mut.is_cold = true;\n                    slot_mut.original_value = slot_mut.present_value;\n                }\n            }\n            state\n        };\n\n        let mut res = None;\n        let mut nested_env = None;\n        let mut cold_state = Some(cold_state);\n        let modified_tx = modified_tx_env.clone();\n        {\n            let (db, _) = ccx.ecx.db_journal_inner_mut();\n            executor.with_fresh_nested_evm(\n                ccx.state,\n                db,\n                modified_evm_env,\n                modified_tx_env,\n                &mut |evm| {\n                    // SAFETY: closure is called exactly once by the executor.\n                    evm.journal_inner_mut().state = cold_state.take().expect(\"called once\");\n                    // Set depth to 1 for proper trace collection.\n                    evm.journal_inner_mut().depth = 1;\n                    res = Some(evm.transact(modified_tx.clone()));\n                    nested_env = Some(evm.to_evm_env());\n                    Ok(())\n                },\n            )?;\n        }\n        let (res, mut nested_evm_env) = (res.unwrap(), nested_env.unwrap());\n\n        // Restore env, preserving cheatcode cfg/block changes from the nested EVM\n        // but restoring the original tx and basefee (which we zeroed for the nested call)\n        // as well as cfg overrides that were applied only for the nested execution.\n        nested_evm_env.block_env.basefee = cached_evm_env.block_env.basefee;\n        nested_evm_env.cfg_env.disable_nonce_check = cached_evm_env.cfg_env.disable_nonce_check;\n        nested_evm_env.cfg_env.limit_contract_initcode_size =\n            cached_evm_env.cfg_env.limit_contract_initcode_size;\n        ccx.ecx.set_evm(nested_evm_env);\n        ccx.ecx.set_tx(cached_tx_env);\n\n        // Reset inner context flag.\n        executor.set_in_inner_context(false, None);\n\n        let res = res.map_err(|e| fmt_err!(\"transaction execution failed: {e}\"))?;\n\n        // Merge state changes back into the parent journaled state.\n        for (addr, mut acc) in res.state {\n            let Some(acc_mut) = ccx.ecx.journal_mut().evm_state_mut().get_mut(&addr) else {\n                ccx.ecx.journal_mut().evm_state_mut().insert(addr, acc);\n                continue;\n            };\n\n            // Preserve warm account status from parent context.\n            if acc.status.contains(AccountStatus::Cold)\n                && !acc_mut.status.contains(AccountStatus::Cold)\n            {\n                acc.status -= AccountStatus::Cold;\n            }\n            acc_mut.info = acc.info;\n            acc_mut.status |= acc.status;\n\n            // Merge storage changes.\n            for (key, val) in acc.storage {\n                let Some(slot_mut) = acc_mut.storage.get_mut(&key) else {\n                    acc_mut.storage.insert(key, val);\n                    continue;\n                };\n                slot_mut.present_value = val.present_value;\n                slot_mut.is_cold &= val.is_cold;\n            }\n        }\n\n        // Return output bytes.\n        let output = match res.result {\n            ExecutionResult::Success { output, .. } => output.into_data(),\n            ExecutionResult::Halt { reason, .. } => {\n                return Err(fmt_err!(\"transaction halted: {reason:?}\"));\n            }\n            ExecutionResult::Revert { output, .. } => {\n                return Err(fmt_err!(\"transaction reverted: {}\", hex::encode_prefixed(&output)));\n            }\n        };\n\n        Ok(output.abi_encode())\n    }\n}\n\nimpl Cheatcode for startDebugTraceRecordingCall {\n    fn apply_full<CTX: ContextTr>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n        executor: &mut dyn CheatcodesExecutor<CTX>,\n    ) -> Result {\n        let Some(tracer) = executor.tracing_inspector() else {\n            return Err(Error::from(\"no tracer initiated, consider adding -vvv flag\"));\n        };\n\n        let mut info = RecordDebugStepInfo {\n            // will be updated later\n            start_node_idx: 0,\n            // keep the original config to revert back later\n            original_tracer_config: *tracer.config(),\n        };\n\n        // turn on tracer debug configuration for recording\n        *tracer.config_mut() = TraceMode::Debug.into_config().expect(\"cannot be None\");\n\n        // track where the recording starts\n        if let Some(last_node) = tracer.traces().nodes().last() {\n            info.start_node_idx = last_node.idx;\n        }\n\n        ccx.state.record_debug_steps_info = Some(info);\n        Ok(Default::default())\n    }\n}\n\nimpl Cheatcode for stopAndReturnDebugTraceRecordingCall {\n    fn apply_full<CTX: ContextTr>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n        executor: &mut dyn CheatcodesExecutor<CTX>,\n    ) -> Result {\n        let Some(tracer) = executor.tracing_inspector() else {\n            return Err(Error::from(\"no tracer initiated, consider adding -vvv flag\"));\n        };\n\n        let Some(record_info) = ccx.state.record_debug_steps_info else {\n            return Err(Error::from(\"nothing recorded\"));\n        };\n\n        // Use the trace nodes to flatten the call trace\n        let root = tracer.traces();\n        let steps = flatten_call_trace(0, root, record_info.start_node_idx);\n\n        let debug_steps: Vec<DebugStep> =\n            steps.iter().map(|step| convert_call_trace_ctx_to_debug_step(step)).collect();\n        // Free up memory by clearing the steps if they are not recorded outside of cheatcode usage.\n        if !record_info.original_tracer_config.record_steps {\n            tracer.traces_mut().nodes_mut().iter_mut().for_each(|node| {\n                node.trace.steps = Vec::new();\n                node.logs = Vec::new();\n                node.ordering = Vec::new();\n            });\n        }\n\n        // Revert the tracer config to the one before recording\n        tracer.update_config(|_config| record_info.original_tracer_config);\n\n        // Clean up the recording info\n        ccx.state.record_debug_steps_info = None;\n\n        Ok(debug_steps.abi_encode())\n    }\n}\n\nimpl Cheatcode for setEvmVersionCall {\n    fn apply_stateful<CTX>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self { evm } = self;\n        let spec_id = evm_spec_id(\n            EvmVersion::from_str(evm)\n                .map_err(|_| Error::from(format!(\"invalid evm version {evm}\")))?,\n        );\n        ccx.state.execution_evm_version = Some(spec_id);\n        Ok(Default::default())\n    }\n}\n\nimpl Cheatcode for getEvmVersionCall {\n    fn apply_stateful<CTX: ContextTr>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let spec: SpecId = ccx.ecx.cfg().spec().into();\n        Ok(spec.to_string().to_lowercase().abi_encode())\n    }\n}\n\npub(super) fn get_nonce<CTX: ContextTr<Db: DatabaseExt>>(\n    ccx: &mut CheatsCtxt<'_, CTX>,\n    address: &Address,\n) -> Result {\n    let account = ccx.ecx.journal_mut().load_account(*address)?;\n    Ok(account.data.info.nonce.abi_encode())\n}\n\nfn inner_snapshot_state<CTX: EthCheatCtx>(ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n    let evm_env =\n        EvmEnv { cfg_env: ccx.ecx.cfg_mut().clone(), block_env: ccx.ecx.block_mut().clone() };\n    let (db, inner) = ccx.ecx.db_journal_inner_mut();\n    let id = db.snapshot_state(inner, &evm_env);\n    Ok(id.abi_encode())\n}\n\nfn inner_revert_to_state<CTX: EthCheatCtx>(\n    ccx: &mut CheatsCtxt<'_, CTX>,\n    snapshot_id: U256,\n) -> Result {\n    let mut evm_env = ccx.ecx.evm_clone();\n    let mut tx_env = ccx.ecx.tx_clone();\n    let (db, inner) = ccx.ecx.db_journal_inner_mut();\n    if let Some(restored) = db.revert_state(\n        snapshot_id,\n        inner,\n        &mut evm_env,\n        &mut tx_env,\n        RevertStateSnapshotAction::RevertKeep,\n    ) {\n        *inner = restored;\n        ccx.ecx.set_evm(evm_env);\n        ccx.ecx.set_tx(tx_env);\n        Ok(true.abi_encode())\n    } else {\n        Ok(false.abi_encode())\n    }\n}\n\nfn inner_revert_to_state_and_delete<CTX: EthCheatCtx>(\n    ccx: &mut CheatsCtxt<'_, CTX>,\n    snapshot_id: U256,\n) -> Result {\n    let mut evm_env = ccx.ecx.evm_clone();\n    let mut tx_env = ccx.ecx.tx_clone();\n    let (db, inner) = ccx.ecx.db_journal_inner_mut();\n    if let Some(restored) = db.revert_state(\n        snapshot_id,\n        inner,\n        &mut evm_env,\n        &mut tx_env,\n        RevertStateSnapshotAction::RevertRemove,\n    ) {\n        *inner = restored;\n        ccx.ecx.set_evm(evm_env);\n        ccx.ecx.set_tx(tx_env);\n        Ok(true.abi_encode())\n    } else {\n        Ok(false.abi_encode())\n    }\n}\n\nfn inner_delete_state_snapshot<CTX: ContextTr<Db: DatabaseExt>>(\n    ccx: &mut CheatsCtxt<'_, CTX>,\n    snapshot_id: U256,\n) -> Result {\n    let result = ccx.ecx.db_mut().delete_state_snapshot(snapshot_id);\n    Ok(result.abi_encode())\n}\n\nfn inner_delete_state_snapshots<CTX: ContextTr<Db: DatabaseExt>>(\n    ccx: &mut CheatsCtxt<'_, CTX>,\n) -> Result {\n    ccx.ecx.db_mut().delete_state_snapshots();\n    Ok(Default::default())\n}\n\nfn inner_value_snapshot<CTX>(\n    ccx: &mut CheatsCtxt<'_, CTX>,\n    group: Option<String>,\n    name: Option<String>,\n    value: String,\n) -> Result {\n    let (group, name) = derive_snapshot_name(ccx, group, name);\n\n    ccx.state.gas_snapshots.entry(group).or_default().insert(name, value);\n\n    Ok(Default::default())\n}\n\nfn inner_last_gas_snapshot<CTX>(\n    ccx: &mut CheatsCtxt<'_, CTX>,\n    group: Option<String>,\n    name: Option<String>,\n    value: u64,\n) -> Result {\n    let (group, name) = derive_snapshot_name(ccx, group, name);\n\n    ccx.state.gas_snapshots.entry(group).or_default().insert(name, value.to_string());\n\n    Ok(value.abi_encode())\n}\n\nfn inner_start_gas_snapshot<CTX: ContextTr>(\n    ccx: &mut CheatsCtxt<'_, CTX>,\n    group: Option<String>,\n    name: Option<String>,\n) -> Result {\n    // Revert if there is an active gas snapshot as we can only have one active snapshot at a time.\n    if let Some((group, name)) = &ccx.state.gas_metering.active_gas_snapshot {\n        bail!(\"gas snapshot was already started with group: {group} and name: {name}\");\n    }\n\n    let (group, name) = derive_snapshot_name(ccx, group, name);\n\n    ccx.state.gas_metering.gas_records.push(GasRecord {\n        group: group.clone(),\n        name: name.clone(),\n        gas_used: 0,\n        depth: ccx.ecx.journal().depth(),\n    });\n\n    ccx.state.gas_metering.active_gas_snapshot = Some((group, name));\n\n    ccx.state.gas_metering.start();\n\n    Ok(Default::default())\n}\n\nfn inner_stop_gas_snapshot<CTX>(\n    ccx: &mut CheatsCtxt<'_, CTX>,\n    group: Option<String>,\n    name: Option<String>,\n) -> Result {\n    // If group and name are not provided, use the last snapshot group and name.\n    let (group, name) = group\n        .zip(name)\n        .or_else(|| ccx.state.gas_metering.active_gas_snapshot.clone())\n        .ok_or_else(|| fmt_err!(\"no active gas snapshot; call `startGasSnapshot` first\"))?;\n\n    if let Some(record) = ccx\n        .state\n        .gas_metering\n        .gas_records\n        .iter_mut()\n        .find(|record| record.group == group && record.name == name)\n    {\n        // Calculate the gas used since the snapshot was started.\n        // We subtract 171 from the gas used to account for gas used by the snapshot itself.\n        let value = record.gas_used.saturating_sub(171);\n\n        ccx.state\n            .gas_snapshots\n            .entry(group.clone())\n            .or_default()\n            .insert(name.clone(), value.to_string());\n\n        // Stop the gas metering.\n        ccx.state.gas_metering.stop();\n\n        // Remove the gas record.\n        ccx.state\n            .gas_metering\n            .gas_records\n            .retain(|record| record.group != group && record.name != name);\n\n        // Clear last snapshot cache if we have an exact match.\n        if let Some((snapshot_group, snapshot_name)) = &ccx.state.gas_metering.active_gas_snapshot\n            && snapshot_group == &group\n            && snapshot_name == &name\n        {\n            ccx.state.gas_metering.active_gas_snapshot = None;\n        }\n\n        Ok(value.abi_encode())\n    } else {\n        bail!(\"no gas snapshot was started with the name: {name} in group: {group}\");\n    }\n}\n\n// Derives the snapshot group and name from the provided group and name or the running contract.\nfn derive_snapshot_name<CTX>(\n    ccx: &CheatsCtxt<'_, CTX>,\n    group: Option<String>,\n    name: Option<String>,\n) -> (String, String) {\n    let group = group.unwrap_or_else(|| {\n        ccx.state.config.running_artifact.clone().expect(\"expected running contract\").name\n    });\n    let name = name.unwrap_or_else(|| \"default\".to_string());\n    (group, name)\n}\n\n/// Reads the current caller information and returns the current [CallerMode], `msg.sender` and\n/// `tx.origin`.\n///\n/// Depending on the current caller mode, one of the following results will be returned:\n/// - If there is an active prank:\n///     - caller_mode will be equal to:\n///         - [CallerMode::Prank] if the prank has been set with `vm.prank(..)`.\n///         - [CallerMode::RecurrentPrank] if the prank has been set with `vm.startPrank(..)`.\n///     - `msg.sender` will be equal to the address set for the prank.\n///     - `tx.origin` will be equal to the default sender address unless an alternative one has been\n///       set when configuring the prank.\n///\n/// - If there is an active broadcast:\n///     - caller_mode will be equal to:\n///         - [CallerMode::Broadcast] if the broadcast has been set with `vm.broadcast(..)`.\n///         - [CallerMode::RecurrentBroadcast] if the broadcast has been set with\n///           `vm.startBroadcast(..)`.\n///     - `msg.sender` and `tx.origin` will be equal to the address provided when setting the\n///       broadcast.\n///\n/// - If no caller modification is active:\n///     - caller_mode will be equal to [CallerMode::None],\n///     - `msg.sender` and `tx.origin` will be equal to the default sender address.\nfn read_callers(state: &Cheatcodes, default_sender: &Address, call_depth: usize) -> Result {\n    let mut mode = CallerMode::None;\n    let mut new_caller = default_sender;\n    let mut new_origin = default_sender;\n    if let Some(prank) = state.get_prank(call_depth) {\n        mode = if prank.single_call { CallerMode::Prank } else { CallerMode::RecurrentPrank };\n        new_caller = &prank.new_caller;\n        if let Some(new) = &prank.new_origin {\n            new_origin = new;\n        }\n    } else if let Some(broadcast) = &state.broadcast {\n        mode = if broadcast.single_call {\n            CallerMode::Broadcast\n        } else {\n            CallerMode::RecurrentBroadcast\n        };\n        new_caller = &broadcast.new_origin;\n        new_origin = &broadcast.new_origin;\n    }\n\n    Ok((mode, new_caller, new_origin).abi_encode_params())\n}\n\n/// Ensures the `Account` is loaded and touched.\npub(super) fn journaled_account<CTX: ContextTr<Db: DatabaseExt, Journal: JournalExt>>(\n    ecx: &mut CTX,\n    addr: Address,\n) -> Result<&mut Account> {\n    ensure_loaded_account(ecx, addr)?;\n    Ok(ecx.journal_mut().evm_state_mut().get_mut(&addr).expect(\"account is loaded\"))\n}\n\npub(super) fn ensure_loaded_account<CTX: ContextTr<Db: DatabaseExt>>(\n    ecx: &mut CTX,\n    addr: Address,\n) -> Result<()> {\n    ecx.journal_mut().load_account(addr)?;\n    ecx.journal_mut().touch_account(addr);\n    Ok(())\n}\n\n/// Consumes recorded account accesses and returns them as an abi encoded\n/// array of [AccountAccess]. If there are no accounts were\n/// recorded as accessed, an abi encoded empty array is returned.\n///\n/// In the case where `stopAndReturnStateDiff` is called at a lower\n/// depth than `startStateDiffRecording`, multiple `Vec<RecordedAccountAccesses>`\n/// will be flattened, preserving the order of the accesses.\nfn get_state_diff(state: &mut Cheatcodes) -> Result {\n    let res = state\n        .recorded_account_diffs_stack\n        .replace(Default::default())\n        .unwrap_or_default()\n        .into_iter()\n        .flatten()\n        .collect::<Vec<_>>();\n    Ok(res.abi_encode())\n}\n\n/// Helper function that creates a `GenesisAccount` from a regular `Account`.\nfn genesis_account(account: &Account) -> GenesisAccount {\n    GenesisAccount {\n        nonce: Some(account.info.nonce),\n        balance: account.info.balance,\n        code: account.info.code.as_ref().map(|o| o.original_bytes()),\n        storage: Some(\n            account\n                .storage\n                .iter()\n                .map(|(k, v)| (B256::from(*k), B256::from(v.present_value())))\n                .collect(),\n        ),\n        private_key: None,\n    }\n}\n\n/// Helper function to returns state diffs recorded for each changed account.\nfn get_recorded_state_diffs<CTX: ContextTr<Db: DatabaseExt>>(\n    ccx: &mut CheatsCtxt<'_, CTX>,\n) -> BTreeMap<Address, AccountStateDiffs> {\n    let mut state_diffs: BTreeMap<Address, AccountStateDiffs> = BTreeMap::default();\n\n    // First, collect all unique addresses we need to look up\n    let mut addresses_to_lookup = HashSet::new();\n    if let Some(records) = &ccx.state.recorded_account_diffs_stack {\n        for account_access in records.iter().flatten() {\n            if !account_access.storageAccesses.is_empty()\n                || account_access.oldBalance != account_access.newBalance\n            {\n                addresses_to_lookup.insert(account_access.account);\n                for storage_access in &account_access.storageAccesses {\n                    if storage_access.isWrite && !storage_access.reverted {\n                        addresses_to_lookup.insert(storage_access.account);\n                    }\n                }\n            }\n        }\n    }\n\n    // Look up contract names and storage layouts for all addresses\n    let mut contract_names = HashMap::new();\n    let mut storage_layouts = HashMap::new();\n    for address in addresses_to_lookup {\n        if let Some((artifact_id, contract_data)) = get_contract_data(ccx, address) {\n            contract_names.insert(address, artifact_id.identifier());\n\n            // Also get storage layout if available\n            if let Some(storage_layout) = &contract_data.storage_layout {\n                storage_layouts.insert(address, storage_layout.clone());\n            }\n        }\n    }\n\n    // Now process the records\n    if let Some(records) = &ccx.state.recorded_account_diffs_stack {\n        records\n            .iter()\n            .flatten()\n            .filter(|account_access| {\n                !account_access.storageAccesses.is_empty()\n                    || account_access.oldBalance != account_access.newBalance\n                    || account_access.oldNonce != account_access.newNonce\n            })\n            .for_each(|account_access| {\n                // Record account balance diffs.\n                if account_access.oldBalance != account_access.newBalance {\n                    let account_diff =\n                        state_diffs.entry(account_access.account).or_insert_with(|| {\n                            AccountStateDiffs {\n                                label: ccx.state.labels.get(&account_access.account).cloned(),\n                                contract: contract_names.get(&account_access.account).cloned(),\n                                ..Default::default()\n                            }\n                        });\n                    // Update balance diff. Do not overwrite the initial balance if already set.\n                    if let Some(diff) = &mut account_diff.balance_diff {\n                        diff.new_value = account_access.newBalance;\n                    } else {\n                        account_diff.balance_diff = Some(BalanceDiff {\n                            previous_value: account_access.oldBalance,\n                            new_value: account_access.newBalance,\n                        });\n                    }\n                }\n\n                // Record account nonce diffs.\n                if account_access.oldNonce != account_access.newNonce {\n                    let account_diff =\n                        state_diffs.entry(account_access.account).or_insert_with(|| {\n                            AccountStateDiffs {\n                                label: ccx.state.labels.get(&account_access.account).cloned(),\n                                contract: contract_names.get(&account_access.account).cloned(),\n                                ..Default::default()\n                            }\n                        });\n                    // Update nonce diff. Do not overwrite the initial nonce if already set.\n                    if let Some(diff) = &mut account_diff.nonce_diff {\n                        diff.new_value = account_access.newNonce;\n                    } else {\n                        account_diff.nonce_diff = Some(NonceDiff {\n                            previous_value: account_access.oldNonce,\n                            new_value: account_access.newNonce,\n                        });\n                    }\n                }\n\n                // Collect all storage accesses for this account\n                let raw_changes_by_slot = account_access\n                    .storageAccesses\n                    .iter()\n                    .filter_map(|access| {\n                        (access.isWrite && !access.reverted)\n                            .then_some((access.slot, (access.previousValue, access.newValue)))\n                    })\n                    .collect::<BTreeMap<_, _>>();\n\n                // Record account state diffs.\n                for storage_access in &account_access.storageAccesses {\n                    if storage_access.isWrite && !storage_access.reverted {\n                        let account_diff = state_diffs\n                            .entry(storage_access.account)\n                            .or_insert_with(|| AccountStateDiffs {\n                                label: ccx.state.labels.get(&storage_access.account).cloned(),\n                                contract: contract_names.get(&storage_access.account).cloned(),\n                                ..Default::default()\n                            });\n                        let layout = storage_layouts.get(&storage_access.account);\n                        // Update state diff. Do not overwrite the initial value if already set.\n                        let entry = match account_diff.state_diff.entry(storage_access.slot) {\n                            Entry::Vacant(slot_state_diff) => {\n                                // Get storage layout info for this slot\n                                // Include mapping slots if available for the account\n                                let mapping_slots = ccx\n                                    .state\n                                    .mapping_slots\n                                    .as_ref()\n                                    .and_then(|slots| slots.get(&storage_access.account));\n\n                                let slot_info = layout.and_then(|layout| {\n                                    let decoder = SlotIdentifier::new(layout.clone());\n                                    decoder.identify(&storage_access.slot, mapping_slots).or_else(\n                                        || {\n                                            // Create a map of new values for bytes/string\n                                            // identification. These values are used to determine\n                                            // the length of the data which helps determine how many\n                                            // slots to search\n                                            let current_base_slot_values = raw_changes_by_slot\n                                                .iter()\n                                                .map(|(slot, (_, new_val))| (*slot, *new_val))\n                                                .collect::<B256Map<_>>();\n                                            decoder.identify_bytes_or_string(\n                                                &storage_access.slot,\n                                                &current_base_slot_values,\n                                            )\n                                        },\n                                    )\n                                });\n\n                                slot_state_diff.insert(SlotStateDiff {\n                                    previous_value: storage_access.previousValue,\n                                    new_value: storage_access.newValue,\n                                    slot_info,\n                                })\n                            }\n                            Entry::Occupied(slot_state_diff) => {\n                                let entry = slot_state_diff.into_mut();\n                                entry.new_value = storage_access.newValue;\n                                entry\n                            }\n                        };\n\n                        // Update decoded values if we have slot info\n                        if let Some(slot_info) = &mut entry.slot_info {\n                            slot_info.decode_values(entry.previous_value, storage_access.newValue);\n                            if slot_info.is_bytes_or_string() {\n                                slot_info.decode_bytes_or_string_values(\n                                    &storage_access.slot,\n                                    &raw_changes_by_slot,\n                                );\n                            }\n                        }\n                    }\n                }\n            });\n    }\n    state_diffs\n}\n\n/// EIP-1967 implementation storage slot\nconst EIP1967_IMPL_SLOT: &str = \"360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc\";\n\n/// EIP-1822 UUPS implementation storage slot: keccak256(\"PROXIABLE\")\nconst EIP1822_PROXIABLE_SLOT: &str =\n    \"c5f16f0fcc639fa48a6947836d9850f504798523bf8c9a3a87d5876cf622bcf7\";\n\n/// Helper function to get the contract data from the deployed code at an address.\nfn get_contract_data<'a, CTX: ContextTr<Db: DatabaseExt>>(\n    ccx: &'a mut CheatsCtxt<'_, CTX>,\n    address: Address,\n) -> Option<(&'a foundry_compilers::ArtifactId, &'a foundry_common::contracts::ContractData)> {\n    // Check if we have available artifacts to match against\n    let artifacts = ccx.state.config.available_artifacts.as_ref()?;\n\n    // Try to load the account and get its code\n    let account = ccx.ecx.journal_mut().load_account(address).ok()?;\n    let code = account.data.info.code.as_ref()?;\n\n    // Skip if code is empty\n    if code.is_empty() {\n        return None;\n    }\n\n    // Try to find the artifact by deployed code\n    let code_bytes = code.original_bytes();\n    // First check for proxy patterns\n    let hex_str = hex::encode(&code_bytes);\n    let find_by_suffix =\n        |suffix: &str| artifacts.iter().find(|(a, _)| a.identifier().ends_with(suffix));\n    // Simple proxy detection based on storage slot patterns\n    if hex_str.contains(EIP1967_IMPL_SLOT)\n        && let Some(result) = find_by_suffix(\":TransparentUpgradeableProxy\")\n    {\n        return Some(result);\n    } else if hex_str.contains(EIP1822_PROXIABLE_SLOT)\n        && let Some(result) = find_by_suffix(\":UUPSUpgradeable\")\n    {\n        return Some(result);\n    }\n\n    // Try exact match\n    if let Some(result) = artifacts.find_by_deployed_code_exact(&code_bytes) {\n        return Some(result);\n    }\n\n    // Fallback to fuzzy matching if exact match fails\n    artifacts.find_by_deployed_code(&code_bytes)\n}\n\n/// Helper function to set / unset cold storage slot of the target address.\nfn set_cold_slot<CTX: ContextTr<Journal: JournalExt>>(\n    ccx: &mut CheatsCtxt<'_, CTX>,\n    target: Address,\n    slot: U256,\n    cold: bool,\n) {\n    if let Some(account) = ccx.ecx.journal_mut().evm_state_mut().get_mut(&target)\n        && let Some(storage_slot) = account.storage.get_mut(&slot)\n    {\n        storage_slot.is_cold = cold;\n    }\n}\n"
  },
  {
    "path": "crates/cheatcodes/src/fs.rs",
    "content": "//! Implementations of [`Filesystem`](spec::Group::Filesystem) cheatcodes.\n\nuse super::string::parse;\nuse crate::{\n    Cheatcode, Cheatcodes, CheatcodesExecutor, CheatsCtxt, EthCheatCtx, Result, Vm::*,\n    inspector::exec_create,\n};\nuse alloy_dyn_abi::DynSolType;\nuse alloy_json_abi::ContractObject;\nuse alloy_network::{Ethereum, Network, ReceiptResponse};\nuse alloy_primitives::{Bytes, U256, hex, map::Entry};\nuse alloy_sol_types::SolValue;\nuse dialoguer::{Input, Password};\nuse forge_script_sequence::{BroadcastReader, TransactionWithMetadata};\nuse foundry_common::fs;\nuse foundry_config::fs_permissions::FsAccessKind;\nuse revm::{\n    context::{Cfg, ContextTr, CreateScheme, JournalTr},\n    interpreter::CreateInputs,\n};\nuse revm_inspectors::tracing::types::CallKind;\nuse semver::Version;\nuse std::{\n    io::{BufRead, BufReader},\n    path::{Path, PathBuf},\n    process::Command,\n    sync::mpsc,\n    thread,\n    time::{SystemTime, UNIX_EPOCH},\n};\nuse walkdir::WalkDir;\n\nimpl Cheatcode for existsCall {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { path } = self;\n        let path = state.config.ensure_path_allowed(path, FsAccessKind::Read)?;\n        Ok(path.exists().abi_encode())\n    }\n}\n\nimpl Cheatcode for fsMetadataCall {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { path } = self;\n        let path = state.config.ensure_path_allowed(path, FsAccessKind::Read)?;\n\n        let metadata = path.metadata()?;\n\n        // These fields not available on all platforms; default to 0\n        let [modified, accessed, created] =\n            [metadata.modified(), metadata.accessed(), metadata.created()].map(|time| {\n                time.unwrap_or(UNIX_EPOCH).duration_since(UNIX_EPOCH).unwrap_or_default().as_secs()\n            });\n\n        Ok(FsMetadata {\n            isDir: metadata.is_dir(),\n            isSymlink: metadata.is_symlink(),\n            length: U256::from(metadata.len()),\n            readOnly: metadata.permissions().readonly(),\n            modified: U256::from(modified),\n            accessed: U256::from(accessed),\n            created: U256::from(created),\n        }\n        .abi_encode())\n    }\n}\n\nimpl Cheatcode for isDirCall {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { path } = self;\n        let path = state.config.ensure_path_allowed(path, FsAccessKind::Read)?;\n        Ok(path.is_dir().abi_encode())\n    }\n}\n\nimpl Cheatcode for isFileCall {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { path } = self;\n        let path = state.config.ensure_path_allowed(path, FsAccessKind::Read)?;\n        Ok(path.is_file().abi_encode())\n    }\n}\n\nimpl Cheatcode for projectRootCall {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self {} = self;\n        Ok(state.config.root.display().to_string().abi_encode())\n    }\n}\n\nimpl Cheatcode for currentFilePathCall {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self {} = self;\n        let artifact = state\n            .config\n            .running_artifact\n            .as_ref()\n            .ok_or_else(|| fmt_err!(\"no running contract found\"))?;\n        let relative = artifact.source.strip_prefix(&state.config.root).unwrap_or(&artifact.source);\n        Ok(relative.display().to_string().abi_encode())\n    }\n}\n\nimpl Cheatcode for unixTimeCall {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self {} = self;\n        let difference = SystemTime::now()\n            .duration_since(UNIX_EPOCH)\n            .map_err(|e| fmt_err!(\"failed getting Unix timestamp: {e}\"))?;\n        Ok(difference.as_millis().abi_encode())\n    }\n}\n\nimpl Cheatcode for closeFileCall {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { path } = self;\n        let path = state.config.ensure_path_allowed(path, FsAccessKind::Read)?;\n\n        state.test_context.opened_read_files.remove(&path);\n\n        Ok(Default::default())\n    }\n}\n\nimpl Cheatcode for copyFileCall {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { from, to } = self;\n        let from = state.config.ensure_path_allowed(from, FsAccessKind::Read)?;\n        let to = state.config.ensure_path_allowed(to, FsAccessKind::Write)?;\n        state.config.ensure_not_foundry_toml(&to)?;\n\n        let n = fs::copy(from, to)?;\n        Ok(n.abi_encode())\n    }\n}\n\nimpl Cheatcode for createDirCall {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { path, recursive } = self;\n        let path = state.config.ensure_path_allowed(path, FsAccessKind::Write)?;\n        if *recursive { fs::create_dir_all(path) } else { fs::create_dir(path) }?;\n        Ok(Default::default())\n    }\n}\n\nimpl Cheatcode for readDir_0Call {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { path } = self;\n        read_dir(state, path.as_ref(), 1, false)\n    }\n}\n\nimpl Cheatcode for readDir_1Call {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { path, maxDepth } = self;\n        read_dir(state, path.as_ref(), *maxDepth, false)\n    }\n}\n\nimpl Cheatcode for readDir_2Call {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { path, maxDepth, followLinks } = self;\n        read_dir(state, path.as_ref(), *maxDepth, *followLinks)\n    }\n}\n\nimpl Cheatcode for readFileCall {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { path } = self;\n        let path = state.config.ensure_path_allowed(path, FsAccessKind::Read)?;\n        Ok(fs::locked_read_to_string(path)?.abi_encode())\n    }\n}\n\nimpl Cheatcode for readFileBinaryCall {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { path } = self;\n        let path = state.config.ensure_path_allowed(path, FsAccessKind::Read)?;\n        Ok(fs::locked_read(path)?.abi_encode())\n    }\n}\n\nimpl Cheatcode for readLineCall {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { path } = self;\n        let path = state.config.ensure_path_allowed(path, FsAccessKind::Read)?;\n\n        // Get reader for previously opened file to continue reading OR initialize new reader\n        let reader = match state.test_context.opened_read_files.entry(path.clone()) {\n            Entry::Occupied(entry) => entry.into_mut(),\n            Entry::Vacant(entry) => entry.insert(BufReader::new(fs::open(path)?)),\n        };\n\n        let mut line: String = String::new();\n        reader.read_line(&mut line)?;\n\n        // Remove trailing newline character, preserving others for cases where it may be important\n        if line.ends_with('\\n') {\n            line.pop();\n            if line.ends_with('\\r') {\n                line.pop();\n            }\n        }\n\n        Ok(line.abi_encode())\n    }\n}\n\nimpl Cheatcode for readLinkCall {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { linkPath: path } = self;\n        let path = state.config.ensure_path_allowed(path, FsAccessKind::Read)?;\n        let target = fs::read_link(path)?;\n        Ok(target.display().to_string().abi_encode())\n    }\n}\n\nimpl Cheatcode for removeDirCall {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { path, recursive } = self;\n        let path = state.config.ensure_path_allowed(path, FsAccessKind::Write)?;\n        if *recursive { fs::remove_dir_all(path) } else { fs::remove_dir(path) }?;\n        Ok(Default::default())\n    }\n}\n\nimpl Cheatcode for removeFileCall {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { path } = self;\n        let path = state.config.ensure_path_allowed(path, FsAccessKind::Write)?;\n        state.config.ensure_not_foundry_toml(&path)?;\n\n        // also remove from the set if opened previously\n        state.test_context.opened_read_files.remove(&path);\n\n        if state.fs_commit {\n            fs::remove_file(&path)?;\n        }\n\n        Ok(Default::default())\n    }\n}\n\nimpl Cheatcode for writeFileCall {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { path, data } = self;\n        write_file(state, path.as_ref(), data.as_bytes())\n    }\n}\n\nimpl Cheatcode for writeFileBinaryCall {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { path, data } = self;\n        write_file(state, path.as_ref(), data)\n    }\n}\n\nimpl Cheatcode for writeLineCall {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { path, data: line } = self;\n        let path = state.config.ensure_path_allowed(path, FsAccessKind::Write)?;\n        state.config.ensure_not_foundry_toml(&path)?;\n\n        if state.fs_commit {\n            fs::locked_write_line(path, line)?;\n        }\n\n        Ok(Default::default())\n    }\n}\n\nimpl Cheatcode for getArtifactPathByCodeCall {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { code } = self;\n        let (artifact_id, _) = state\n            .config\n            .available_artifacts\n            .as_ref()\n            .and_then(|artifacts| artifacts.find_by_creation_code(code))\n            .ok_or_else(|| fmt_err!(\"no matching artifact found\"))?;\n\n        Ok(artifact_id.path.to_string_lossy().abi_encode())\n    }\n}\n\nimpl Cheatcode for getArtifactPathByDeployedCodeCall {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { deployedCode } = self;\n        let (artifact_id, _) = state\n            .config\n            .available_artifacts\n            .as_ref()\n            .and_then(|artifacts| artifacts.find_by_deployed_code(deployedCode))\n            .ok_or_else(|| fmt_err!(\"no matching artifact found\"))?;\n\n        Ok(artifact_id.path.to_string_lossy().abi_encode())\n    }\n}\n\nimpl Cheatcode for getCodeCall {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { artifactPath: path } = self;\n        Ok(get_artifact_code(state, path, false)?.abi_encode())\n    }\n}\n\nimpl Cheatcode for getDeployedCodeCall {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { artifactPath: path } = self;\n        Ok(get_artifact_code(state, path, true)?.abi_encode())\n    }\n}\n\nimpl Cheatcode for deployCode_0Call {\n    fn apply_full<CTX: EthCheatCtx>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n        executor: &mut dyn CheatcodesExecutor<CTX>,\n    ) -> Result {\n        let Self { artifactPath: path } = self;\n        deploy_code(ccx, executor, path, None, None, None)\n    }\n}\n\nimpl Cheatcode for deployCode_1Call {\n    fn apply_full<CTX: EthCheatCtx>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n        executor: &mut dyn CheatcodesExecutor<CTX>,\n    ) -> Result {\n        let Self { artifactPath: path, constructorArgs: args } = self;\n        deploy_code(ccx, executor, path, Some(args), None, None)\n    }\n}\n\nimpl Cheatcode for deployCode_2Call {\n    fn apply_full<CTX: EthCheatCtx>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n        executor: &mut dyn CheatcodesExecutor<CTX>,\n    ) -> Result {\n        let Self { artifactPath: path, value } = self;\n        deploy_code(ccx, executor, path, None, Some(*value), None)\n    }\n}\n\nimpl Cheatcode for deployCode_3Call {\n    fn apply_full<CTX: EthCheatCtx>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n        executor: &mut dyn CheatcodesExecutor<CTX>,\n    ) -> Result {\n        let Self { artifactPath: path, constructorArgs: args, value } = self;\n        deploy_code(ccx, executor, path, Some(args), Some(*value), None)\n    }\n}\n\nimpl Cheatcode for deployCode_4Call {\n    fn apply_full<CTX: EthCheatCtx>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n        executor: &mut dyn CheatcodesExecutor<CTX>,\n    ) -> Result {\n        let Self { artifactPath: path, salt } = self;\n        deploy_code(ccx, executor, path, None, None, Some((*salt).into()))\n    }\n}\n\nimpl Cheatcode for deployCode_5Call {\n    fn apply_full<CTX: EthCheatCtx>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n        executor: &mut dyn CheatcodesExecutor<CTX>,\n    ) -> Result {\n        let Self { artifactPath: path, constructorArgs: args, salt } = self;\n        deploy_code(ccx, executor, path, Some(args), None, Some((*salt).into()))\n    }\n}\n\nimpl Cheatcode for deployCode_6Call {\n    fn apply_full<CTX: EthCheatCtx>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n        executor: &mut dyn CheatcodesExecutor<CTX>,\n    ) -> Result {\n        let Self { artifactPath: path, value, salt } = self;\n        deploy_code(ccx, executor, path, None, Some(*value), Some((*salt).into()))\n    }\n}\n\nimpl Cheatcode for deployCode_7Call {\n    fn apply_full<CTX: EthCheatCtx>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n        executor: &mut dyn CheatcodesExecutor<CTX>,\n    ) -> Result {\n        let Self { artifactPath: path, constructorArgs: args, value, salt } = self;\n        deploy_code(ccx, executor, path, Some(args), Some(*value), Some((*salt).into()))\n    }\n}\n\n/// Helper function to deploy contract from artifact code.\n/// Uses CREATE2 scheme if salt specified.\nfn deploy_code<CTX: EthCheatCtx>(\n    ccx: &mut CheatsCtxt<'_, CTX>,\n    executor: &mut dyn CheatcodesExecutor<CTX>,\n    path: &str,\n    constructor_args: Option<&Bytes>,\n    value: Option<U256>,\n    salt: Option<U256>,\n) -> Result {\n    let mut bytecode = get_artifact_code(ccx.state, path, false)?.to_vec();\n\n    // If active broadcast then set flag to deploy from code.\n    if let Some(broadcast) = &mut ccx.state.broadcast {\n        broadcast.deploy_from_code = true;\n    }\n\n    if let Some(args) = constructor_args {\n        bytecode.extend_from_slice(args);\n    }\n\n    let scheme =\n        if let Some(salt) = salt { CreateScheme::Create2 { salt } } else { CreateScheme::Create };\n\n    // If prank active at current depth, then use it as caller for create input.\n    let caller =\n        ccx.state.get_prank(ccx.ecx.journal().depth()).map_or(ccx.caller, |prank| prank.new_caller);\n\n    let outcome = exec_create(\n        executor,\n        CreateInputs::new(\n            caller,\n            scheme,\n            value.unwrap_or(U256::ZERO),\n            bytecode.into(),\n            ccx.gas_limit,\n        ),\n        ccx,\n    )?;\n\n    if !outcome.result.result.is_ok() {\n        return Err(crate::Error::from(outcome.result.output));\n    }\n\n    let address = outcome.address.ok_or_else(|| fmt_err!(\"contract creation failed\"))?;\n\n    Ok(address.abi_encode())\n}\n\n/// Returns the bytecode from a JSON artifact file.\n///\n/// Can parse following input formats:\n/// - `path/to/artifact.json`\n/// - `path/to/contract.sol`\n/// - `path/to/contract.sol:ContractName`\n/// - `path/to/contract.sol:ContractName:0.8.23`\n/// - `path/to/contract.sol:0.8.23`\n/// - `ContractName`\n/// - `ContractName:0.8.23`\n///\n/// This function is safe to use with contracts that have library dependencies.\n/// `alloy_json_abi::ContractObject` validates bytecode during JSON parsing and will\n/// reject artifacts with unlinked library placeholders.\nfn get_artifact_code(state: &Cheatcodes, path: &str, deployed: bool) -> Result<Bytes> {\n    let path = if path.ends_with(\".json\") {\n        PathBuf::from(path)\n    } else {\n        let mut parts = path.split(':');\n\n        let mut file = None;\n        let mut contract_name = None;\n        let mut version = None;\n\n        let path_or_name = parts.next().unwrap();\n        if path_or_name.contains('.') {\n            file = Some(PathBuf::from(path_or_name));\n            if let Some(name_or_version) = parts.next() {\n                if name_or_version.contains('.') {\n                    version = Some(name_or_version);\n                } else {\n                    contract_name = Some(name_or_version);\n                    version = parts.next();\n                }\n            }\n        } else {\n            contract_name = Some(path_or_name);\n            version = parts.next();\n        }\n\n        let version = if let Some(version) = version {\n            Some(Version::parse(version).map_err(|e| fmt_err!(\"failed parsing version: {e}\"))?)\n        } else {\n            None\n        };\n\n        // Use available artifacts list if present\n        if let Some(artifacts) = &state.config.available_artifacts {\n            let filtered = artifacts\n                .iter()\n                .filter(|(id, _)| {\n                    // name might be in the form of \"Counter.0.8.23\"\n                    let id_name = id.name.split('.').next().unwrap();\n\n                    if let Some(path) = &file\n                        && !id.source.ends_with(path)\n                    {\n                        return false;\n                    }\n                    if let Some(name) = contract_name\n                        && id_name != name\n                    {\n                        return false;\n                    }\n                    if let Some(ref version) = version\n                        && (id.version.minor != version.minor\n                            || id.version.major != version.major\n                            || id.version.patch != version.patch)\n                    {\n                        return false;\n                    }\n                    true\n                })\n                .collect::<Vec<_>>();\n\n            let artifact = match &filtered[..] {\n                [] => None,\n                [artifact] => Some(Ok(*artifact)),\n                filtered => {\n                    let mut filtered = filtered.to_vec();\n                    // If we know the current script/test contract solc version, try to filter by it\n                    Some(\n                        state\n                            .config\n                            .running_artifact\n                            .as_ref()\n                            .and_then(|running| {\n                                // Firstly filter by version\n                                filtered.retain(|(id, _)| id.version == running.version);\n\n                                // Return artifact if only one matched\n                                if filtered.len() == 1 {\n                                    return Some(filtered[0]);\n                                }\n\n                                // Try filtering by profile as well\n                                filtered.retain(|(id, _)| id.profile == running.profile);\n\n                                if filtered.len() == 1 { Some(filtered[0]) } else { None }\n                            })\n                            .ok_or_else(|| fmt_err!(\"multiple matching artifacts found\")),\n                    )\n                }\n            };\n\n            if let Some(artifact) = artifact {\n                let artifact = artifact?;\n                let maybe_bytecode = if deployed {\n                    artifact.1.deployed_bytecode().cloned()\n                } else {\n                    artifact.1.bytecode().cloned()\n                };\n\n                return maybe_bytecode.ok_or_else(|| {\n                    fmt_err!(\"no bytecode for contract; is it abstract or unlinked?\")\n                });\n            }\n        }\n\n        // Fallback: construct path manually when no artifacts list or no match found\n        let path_in_artifacts = match (file.map(|f| f.to_string_lossy().to_string()), contract_name)\n        {\n            (Some(file), Some(contract_name)) => {\n                PathBuf::from(format!(\"{file}/{contract_name}.json\"))\n            }\n            (None, Some(contract_name)) => {\n                PathBuf::from(format!(\"{contract_name}.sol/{contract_name}.json\"))\n            }\n            (Some(file), None) => {\n                let name = file.replace(\".sol\", \"\");\n                PathBuf::from(format!(\"{file}/{name}.json\"))\n            }\n            _ => bail!(\"invalid artifact path\"),\n        };\n\n        state.config.paths.artifacts.join(path_in_artifacts)\n    };\n\n    let path = state.config.ensure_path_allowed(path, FsAccessKind::Read)?;\n    let data = fs::read_to_string(path).map_err(|e| {\n        if state.config.available_artifacts.is_some() {\n            fmt_err!(\"no matching artifact found\")\n        } else {\n            e.into()\n        }\n    })?;\n    let artifact = serde_json::from_str::<ContractObject>(&data)?;\n    let maybe_bytecode = if deployed { artifact.deployed_bytecode } else { artifact.bytecode };\n    maybe_bytecode.ok_or_else(|| fmt_err!(\"no bytecode for contract; is it abstract or unlinked?\"))\n}\n\nimpl Cheatcode for ffiCall {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { commandInput: input } = self;\n\n        let output = ffi(state, input)?;\n\n        // Check the exit code of the command.\n        if output.exitCode != 0 {\n            // If the command failed, return an error with the exit code and stderr.\n            return Err(fmt_err!(\n                \"ffi command {:?} exited with code {}. stderr: {}\",\n                input,\n                output.exitCode,\n                String::from_utf8_lossy(&output.stderr)\n            ));\n        }\n\n        // If the command succeeded but still wrote to stderr, log it as a warning.\n        if !output.stderr.is_empty() {\n            let stderr = String::from_utf8_lossy(&output.stderr);\n            warn!(target: \"cheatcodes\", ?input, ?stderr, \"ffi command wrote to stderr\");\n        }\n\n        // We already hex-decoded the stdout in the `ffi` helper function.\n        Ok(output.stdout.abi_encode())\n    }\n}\n\nimpl Cheatcode for tryFfiCall {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { commandInput: input } = self;\n        ffi(state, input).map(|res| res.abi_encode())\n    }\n}\n\nimpl Cheatcode for promptCall {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { promptText: text } = self;\n        prompt(state, text, prompt_input).map(|res| res.abi_encode())\n    }\n}\n\nimpl Cheatcode for promptSecretCall {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { promptText: text } = self;\n        prompt(state, text, prompt_password).map(|res| res.abi_encode())\n    }\n}\n\nimpl Cheatcode for promptSecretUintCall {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { promptText: text } = self;\n        parse(&prompt(state, text, prompt_password)?, &DynSolType::Uint(256))\n    }\n}\n\nimpl Cheatcode for promptAddressCall {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { promptText: text } = self;\n        parse(&prompt(state, text, prompt_input)?, &DynSolType::Address)\n    }\n}\n\nimpl Cheatcode for promptUintCall {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { promptText: text } = self;\n        parse(&prompt(state, text, prompt_input)?, &DynSolType::Uint(256))\n    }\n}\n\npub(super) fn write_file(state: &Cheatcodes, path: &Path, contents: &[u8]) -> Result {\n    let path = state.config.ensure_path_allowed(path, FsAccessKind::Write)?;\n    // write access to foundry.toml is not allowed\n    state.config.ensure_not_foundry_toml(&path)?;\n\n    if state.fs_commit {\n        fs::locked_write(path, contents)?;\n    }\n\n    Ok(Default::default())\n}\n\nfn read_dir(state: &Cheatcodes, path: &Path, max_depth: u64, follow_links: bool) -> Result {\n    let root = state.config.ensure_path_allowed(path, FsAccessKind::Read)?;\n    let paths: Vec<DirEntry> = WalkDir::new(root)\n        .min_depth(1)\n        .max_depth(max_depth.try_into().unwrap_or(usize::MAX))\n        .follow_links(follow_links)\n        .contents_first(false)\n        .same_file_system(true)\n        .sort_by_file_name()\n        .into_iter()\n        .map(|entry| match entry {\n            Ok(entry) => DirEntry {\n                errorMessage: String::new(),\n                path: entry.path().display().to_string(),\n                depth: entry.depth() as u64,\n                isDir: entry.file_type().is_dir(),\n                isSymlink: entry.path_is_symlink(),\n            },\n            Err(e) => DirEntry {\n                errorMessage: e.to_string(),\n                path: e.path().map(|p| p.display().to_string()).unwrap_or_default(),\n                depth: e.depth() as u64,\n                isDir: false,\n                isSymlink: false,\n            },\n        })\n        .collect();\n    Ok(paths.abi_encode())\n}\n\nfn ffi(state: &Cheatcodes, input: &[String]) -> Result<FfiResult> {\n    ensure!(\n        state.config.ffi,\n        \"FFI is disabled; add the `--ffi` flag to allow tests to call external commands\"\n    );\n    ensure!(!input.is_empty() && !input[0].is_empty(), \"can't execute empty command\");\n    let mut cmd = Command::new(&input[0]);\n    cmd.args(&input[1..]);\n\n    debug!(target: \"cheatcodes\", ?cmd, \"invoking ffi\");\n\n    let output = cmd\n        .current_dir(&state.config.root)\n        .output()\n        .map_err(|err| fmt_err!(\"failed to execute command {cmd:?}: {err}\"))?;\n\n    // The stdout might be encoded on valid hex, or it might just be a string,\n    // so we need to determine which it is to avoid improperly encoding later.\n    let trimmed_stdout = String::from_utf8(output.stdout)?;\n    let trimmed_stdout = trimmed_stdout.trim();\n    let encoded_stdout = if let Ok(hex) = hex::decode(trimmed_stdout) {\n        hex\n    } else {\n        trimmed_stdout.as_bytes().to_vec()\n    };\n    Ok(FfiResult {\n        exitCode: output.status.code().unwrap_or(69),\n        stdout: encoded_stdout.into(),\n        stderr: output.stderr.into(),\n    })\n}\n\nfn prompt_input(prompt_text: &str) -> Result<String, dialoguer::Error> {\n    Input::new().allow_empty(true).with_prompt(prompt_text).interact_text()\n}\n\nfn prompt_password(prompt_text: &str) -> Result<String, dialoguer::Error> {\n    Password::new().with_prompt(prompt_text).interact()\n}\n\nfn prompt(\n    state: &Cheatcodes,\n    prompt_text: &str,\n    input: fn(&str) -> Result<String, dialoguer::Error>,\n) -> Result<String> {\n    let text_clone = prompt_text.to_string();\n    let timeout = state.config.prompt_timeout;\n    let (tx, rx) = mpsc::channel();\n\n    thread::spawn(move || {\n        let _ = tx.send(input(&text_clone));\n    });\n\n    match rx.recv_timeout(timeout) {\n        Ok(res) => res.map_err(|err| {\n            let _ = sh_println!();\n            err.to_string().into()\n        }),\n        Err(_) => {\n            let _ = sh_eprintln!();\n            Err(\"Prompt timed out\".into())\n        }\n    }\n}\n\nimpl Cheatcode for getBroadcastCall {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { contractName, chainId, txType } = self;\n\n        let latest_broadcast = latest_broadcast(\n            contractName,\n            *chainId,\n            &state.config.broadcast,\n            vec![map_broadcast_tx_type(*txType)],\n        )?;\n\n        Ok(latest_broadcast.abi_encode())\n    }\n}\n\nimpl Cheatcode for getBroadcasts_0Call {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { contractName, chainId, txType } = self;\n\n        let reader = BroadcastReader::new(contractName.clone(), *chainId, &state.config.broadcast)?\n            .with_tx_type(map_broadcast_tx_type(*txType));\n\n        let broadcasts = reader.read::<Ethereum>()?;\n\n        let summaries = broadcasts\n            .into_iter()\n            .flat_map(|broadcast| {\n                let results = reader.into_tx_receipts(broadcast);\n                parse_broadcast_results(results)\n            })\n            .collect::<Vec<_>>();\n\n        Ok(summaries.abi_encode())\n    }\n}\n\nimpl Cheatcode for getBroadcasts_1Call {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { contractName, chainId } = self;\n\n        let reader = BroadcastReader::new(contractName.clone(), *chainId, &state.config.broadcast)?;\n\n        let broadcasts = reader.read::<Ethereum>()?;\n\n        let summaries = broadcasts\n            .into_iter()\n            .flat_map(|broadcast| {\n                let results = reader.into_tx_receipts(broadcast);\n                parse_broadcast_results(results)\n            })\n            .collect::<Vec<_>>();\n\n        Ok(summaries.abi_encode())\n    }\n}\n\nimpl Cheatcode for getDeployment_0Call {\n    fn apply_stateful<CTX: ContextTr>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self { contractName } = self;\n        let chain_id = ccx.ecx.cfg().chain_id();\n\n        let latest_broadcast = latest_broadcast(\n            contractName,\n            chain_id,\n            &ccx.state.config.broadcast,\n            vec![CallKind::Create, CallKind::Create2],\n        )?;\n\n        Ok(latest_broadcast.contractAddress.abi_encode())\n    }\n}\n\nimpl Cheatcode for getDeployment_1Call {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { contractName, chainId } = self;\n\n        let latest_broadcast = latest_broadcast(\n            contractName,\n            *chainId,\n            &state.config.broadcast,\n            vec![CallKind::Create, CallKind::Create2],\n        )?;\n\n        Ok(latest_broadcast.contractAddress.abi_encode())\n    }\n}\n\nimpl Cheatcode for getDeploymentsCall {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { contractName, chainId } = self;\n\n        let reader = BroadcastReader::new(contractName.clone(), *chainId, &state.config.broadcast)?\n            .with_tx_type(CallKind::Create)\n            .with_tx_type(CallKind::Create2);\n\n        let broadcasts = reader.read::<Ethereum>()?;\n\n        let summaries = broadcasts\n            .into_iter()\n            .flat_map(|broadcast| {\n                let results = reader.into_tx_receipts(broadcast);\n                parse_broadcast_results(results)\n            })\n            .collect::<Vec<_>>();\n\n        let deployed_addresses =\n            summaries.into_iter().map(|summary| summary.contractAddress).collect::<Vec<_>>();\n\n        Ok(deployed_addresses.abi_encode())\n    }\n}\n\nfn map_broadcast_tx_type(tx_type: BroadcastTxType) -> CallKind {\n    match tx_type {\n        BroadcastTxType::Call => CallKind::Call,\n        BroadcastTxType::Create => CallKind::Create,\n        BroadcastTxType::Create2 => CallKind::Create2,\n        _ => unreachable!(\"invalid tx type\"),\n    }\n}\n\nfn parse_broadcast_results<N: Network>(\n    results: Vec<(TransactionWithMetadata<N>, N::ReceiptResponse)>,\n) -> Vec<BroadcastTxSummary> {\n    results\n        .into_iter()\n        .map(|(tx, receipt)| BroadcastTxSummary {\n            txHash: receipt.transaction_hash(),\n            blockNumber: receipt.block_number().unwrap_or_default(),\n            txType: match tx.opcode {\n                CallKind::Call => BroadcastTxType::Call,\n                CallKind::Create => BroadcastTxType::Create,\n                CallKind::Create2 => BroadcastTxType::Create2,\n                _ => unreachable!(\"invalid tx type\"),\n            },\n            contractAddress: tx.contract_address.unwrap_or_default(),\n            success: receipt.status(),\n        })\n        .collect()\n}\n\nfn latest_broadcast(\n    contract_name: &String,\n    chain_id: u64,\n    broadcast_path: &Path,\n    filters: Vec<CallKind>,\n) -> Result<BroadcastTxSummary> {\n    let mut reader = BroadcastReader::new(contract_name.clone(), chain_id, broadcast_path)?;\n\n    for filter in filters {\n        reader = reader.with_tx_type(filter);\n    }\n\n    let broadcast = reader.read_latest::<Ethereum>()?;\n\n    let results = reader.into_tx_receipts(broadcast);\n\n    let summaries = parse_broadcast_results(results);\n\n    summaries\n        .first()\n        .ok_or_else(|| fmt_err!(\"no deployment found for {contract_name} on chain {chain_id}\"))\n        .cloned()\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use crate::CheatsConfig;\n    use std::sync::Arc;\n\n    fn cheats() -> Cheatcodes {\n        let config = CheatsConfig {\n            ffi: true,\n            root: PathBuf::from(&env!(\"CARGO_MANIFEST_DIR\")),\n            ..Default::default()\n        };\n        Cheatcodes::new(Arc::new(config))\n    }\n\n    #[test]\n    fn test_ffi_hex() {\n        let msg = b\"gm\";\n        let cheats = cheats();\n        let args = [\"echo\".to_string(), hex::encode(msg)];\n        let output = ffi(&cheats, &args).unwrap();\n        assert_eq!(output.stdout, Bytes::from(msg));\n    }\n\n    #[test]\n    fn test_ffi_string() {\n        let msg = \"gm\";\n        let cheats = cheats();\n        let args = [\"echo\".to_string(), msg.to_string()];\n        let output = ffi(&cheats, &args).unwrap();\n        assert_eq!(output.stdout, Bytes::from(msg.as_bytes()));\n    }\n\n    #[test]\n    fn test_ffi_fails_on_error_code() {\n        let mut cheats = cheats();\n\n        // Use a command that is guaranteed to fail with a non-zero exit code on any platform.\n        #[cfg(unix)]\n        let args = vec![\"false\".to_string()];\n        #[cfg(windows)]\n        let args = vec![\"cmd\".to_string(), \"/c\".to_string(), \"exit 1\".to_string()];\n\n        let result = Cheatcode::apply(&ffiCall { commandInput: args }, &mut cheats);\n\n        // Assert that the cheatcode returned an error.\n        assert!(result.is_err(), \"Expected ffi cheatcode to fail, but it succeeded\");\n\n        // Assert that the error message contains the expected information.\n        let err_msg = result.unwrap_err().to_string();\n        assert!(\n            err_msg.contains(\"exited with code 1\"),\n            \"Error message did not contain exit code: {err_msg}\"\n        );\n    }\n\n    #[test]\n    fn test_artifact_parsing() {\n        let s = include_str!(\"../../evm/test-data/solc-obj.json\");\n        let artifact: ContractObject = serde_json::from_str(s).unwrap();\n        assert!(artifact.bytecode.is_some());\n\n        let artifact: ContractObject = serde_json::from_str(s).unwrap();\n        assert!(artifact.deployed_bytecode.is_some());\n    }\n\n    #[test]\n    fn test_alloy_json_abi_rejects_unlinked_bytecode() {\n        let artifact_json = r#\"{\n            \"abi\": [],\n            \"bytecode\": \"0x73__$987e73aeca5e61ce83e4cb0814d87beda9$__63baf2f868\"\n        }\"#;\n\n        let result: Result<ContractObject, _> = serde_json::from_str(artifact_json);\n        assert!(result.is_err(), \"should reject unlinked bytecode with placeholders\");\n        let err = result.unwrap_err().to_string();\n        assert!(err.contains(\"expected bytecode, found unlinked bytecode with placeholder\"));\n    }\n}\n"
  },
  {
    "path": "crates/cheatcodes/src/inspector/analysis.rs",
    "content": "//! Cheatcode information, extracted from the syntactic and semantic analysis of the sources.\n\nuse foundry_common::fmt::{StructDefinitions, TypeDefMap};\nuse solar::sema::{self, Compiler, Gcx, hir};\nuse std::sync::{Arc, OnceLock};\nuse thiserror::Error;\n\n/// Represents a failure in one of the lazy analysis steps.\n#[derive(Debug, Clone, PartialEq, Eq, Error)]\npub enum AnalysisError {\n    /// Indicates that the resolution of struct definitions failed.\n    #[error(\"unable to resolve struct definitions\")]\n    StructDefinitionsResolutionFailed,\n}\n\n/// Provides cached, on-demand syntactic and semantic analysis of a completed `Compiler` instance.\n///\n/// This struct acts as a facade over the `Compiler`, offering lazy-loaded analysis for tools like\n/// cheatcode inspectors. It assumes the compiler has already completed parsing and lowering.\n///\n/// # Adding with new analyses types\n///\n/// To add support for a new type of cached analysis, follow this pattern:\n///\n/// 1. Add a new `pub OnceCell<Result<T, AnalysisError>>` field to `CheatcodeAnalysis`, where `T` is\n///    the type of the data that you are adding support for.\n///\n/// 2. Implement a getter method for the new field. Inside the getter, use\n///    `self.field.get_or_init()` to compute and cache the value on the first call.\n///\n/// 3. Inside the closure passed to `get_or_init()`, create a dedicated visitor to traverse the HIR\n///    using `self.compiler.enter()` and collect the required data.\n///\n/// This ensures all analyses remain lazy, efficient, and consistent with the existing design.\n#[derive(Clone)]\npub struct CheatcodeAnalysis {\n    /// A shared, thread-safe reference to solar's `Compiler` instance.\n    pub compiler: Arc<Compiler>,\n\n    /// Cached struct definitions in the sources.\n    /// Used to keep field order when parsing JSON values.\n    struct_defs: OnceLock<Result<StructDefinitions, AnalysisError>>,\n}\n\nimpl std::fmt::Debug for CheatcodeAnalysis {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        f.debug_struct(\"CheatcodeAnalysis\")\n            .field(\"compiler\", &\"<compiler>\")\n            .field(\"struct_defs\", &self.struct_defs)\n            .finish()\n    }\n}\n\nimpl CheatcodeAnalysis {\n    pub fn new(compiler: Arc<solar::sema::Compiler>) -> Self {\n        Self { compiler, struct_defs: OnceLock::new() }\n    }\n\n    /// Lazily initializes and returns the struct definitions.\n    pub fn struct_defs(&self) -> Result<&StructDefinitions, &AnalysisError> {\n        self.struct_defs\n            .get_or_init(|| {\n                self.compiler.enter(|compiler| {\n                    let gcx = compiler.gcx();\n\n                    StructDefinitionResolver::new(gcx).process()\n                })\n            })\n            .as_ref()\n    }\n}\n\n// -- STRUCT DEFINITIONS -------------------------------------------------------\n\n/// Generates a map of all struct definitions from the HIR using the resolved `Ty` system.\nstruct StructDefinitionResolver<'gcx> {\n    gcx: Gcx<'gcx>,\n    struct_defs: TypeDefMap,\n}\n\nimpl<'gcx> StructDefinitionResolver<'gcx> {\n    /// Constructs a new generator.\n    pub fn new(gcx: Gcx<'gcx>) -> Self {\n        Self { gcx, struct_defs: TypeDefMap::new() }\n    }\n\n    /// Processes the HIR to generate all the struct definitions.\n    pub fn process(mut self) -> Result<StructDefinitions, AnalysisError> {\n        for id in self.hir().strukt_ids() {\n            self.resolve_struct_definition(id)?;\n        }\n        Ok(self.struct_defs.into())\n    }\n\n    #[inline]\n    fn hir(&self) -> &'gcx hir::Hir<'gcx> {\n        &self.gcx.hir\n    }\n\n    /// The recursive core of the generator. Resolves a single struct and adds it to the cache.\n    fn resolve_struct_definition(&mut self, id: hir::StructId) -> Result<(), AnalysisError> {\n        let qualified_name = self.get_fully_qualified_name(id);\n        if self.struct_defs.contains_key(&qualified_name) {\n            return Ok(());\n        }\n\n        let hir = self.hir();\n        let strukt = hir.strukt(id);\n        let mut fields = Vec::with_capacity(strukt.fields.len());\n\n        for &field_id in strukt.fields {\n            let var = hir.variable(field_id);\n            let name =\n                var.name.ok_or(AnalysisError::StructDefinitionsResolutionFailed)?.to_string();\n            if let Some(ty_str) = self.ty_to_string(self.gcx.type_of_hir_ty(&var.ty)) {\n                fields.push((name, ty_str));\n            }\n        }\n\n        // Only insert if there are fields, to avoid adding empty entries\n        if !fields.is_empty() {\n            self.struct_defs.insert(qualified_name, fields);\n        }\n\n        Ok(())\n    }\n\n    /// Converts a resolved `Ty` into its canonical string representation.\n    fn ty_to_string(&mut self, ty: sema::Ty<'gcx>) -> Option<String> {\n        let ty = ty.peel_refs();\n        let res = match ty.kind {\n            sema::ty::TyKind::Elementary(e) => e.to_string(),\n            sema::ty::TyKind::Array(ty, size) => {\n                let inner_type = self.ty_to_string(ty)?;\n                format!(\"{inner_type}[{size}]\")\n            }\n            sema::ty::TyKind::DynArray(ty) => {\n                let inner_type = self.ty_to_string(ty)?;\n                format!(\"{inner_type}[]\")\n            }\n            sema::ty::TyKind::Struct(id) => {\n                // Ensure the nested struct is resolved before proceeding.\n                self.resolve_struct_definition(id).ok()?;\n                self.get_fully_qualified_name(id)\n            }\n            sema::ty::TyKind::Udvt(ty, _) => self.ty_to_string(ty)?,\n            // For now, map enums to `uint8`\n            sema::ty::TyKind::Enum(_) => \"uint8\".to_string(),\n            // For now, map contracts to `address`\n            sema::ty::TyKind::Contract(_) => \"address\".to_string(),\n            // Explicitly disallow unsupported types\n            _ => return None,\n        };\n\n        Some(res)\n    }\n\n    /// Helper to get the fully qualified name `Contract.Struct`.\n    fn get_fully_qualified_name(&self, id: hir::StructId) -> String {\n        let hir = self.hir();\n        let strukt = hir.strukt(id);\n        if let Some(contract_id) = strukt.contract {\n            format!(\"{}.{}\", hir.contract(contract_id).name.as_str(), strukt.name.as_str())\n        } else {\n            strukt.name.as_str().into()\n        }\n    }\n}\n"
  },
  {
    "path": "crates/cheatcodes/src/inspector/utils.rs",
    "content": "use crate::inspector::Cheatcodes;\nuse alloy_primitives::{Address, Bytes, U256};\nuse foundry_evm_core::backend::DatabaseExt;\nuse revm::{\n    context::ContextTr,\n    inspector::JournalExt,\n    interpreter::{CreateInputs, CreateScheme},\n};\n\n/// Common behaviour of legacy and EOF create inputs.\npub(crate) trait CommonCreateInput {\n    fn caller(&self) -> Address;\n    fn gas_limit(&self) -> u64;\n    fn value(&self) -> U256;\n    fn init_code(&self) -> Bytes;\n    fn scheme(&self) -> Option<CreateScheme>;\n    fn set_caller(&mut self, caller: Address);\n    fn log_debug(&self, cheatcode: &mut Cheatcodes, scheme: &CreateScheme);\n    fn allow_cheatcodes<CTX: ContextTr<Journal: JournalExt, Db: DatabaseExt>>(\n        &self,\n        cheatcodes: &mut Cheatcodes,\n        ecx: &mut CTX,\n    ) -> Address;\n}\n\nimpl CommonCreateInput for &mut CreateInputs {\n    fn caller(&self) -> Address {\n        CreateInputs::caller(self)\n    }\n    fn gas_limit(&self) -> u64 {\n        CreateInputs::gas_limit(self)\n    }\n    fn value(&self) -> U256 {\n        CreateInputs::value(self)\n    }\n    fn init_code(&self) -> Bytes {\n        CreateInputs::init_code(self).clone()\n    }\n    fn scheme(&self) -> Option<CreateScheme> {\n        Some(CreateInputs::scheme(self))\n    }\n    fn set_caller(&mut self, caller: Address) {\n        CreateInputs::set_call(self, caller);\n    }\n    fn log_debug(&self, cheatcode: &mut Cheatcodes, scheme: &CreateScheme) {\n        let kind = match scheme {\n            CreateScheme::Create => \"create\",\n            CreateScheme::Create2 { .. } => \"create2\",\n            CreateScheme::Custom { .. } => \"custom\",\n        };\n        debug!(target: \"cheatcodes\", tx=?cheatcode.broadcastable_transactions.back().unwrap(), \"broadcastable {kind}\");\n    }\n    fn allow_cheatcodes<CTX: ContextTr<Journal: JournalExt, Db: DatabaseExt>>(\n        &self,\n        cheatcodes: &mut Cheatcodes,\n        ecx: &mut CTX,\n    ) -> Address {\n        let caller = CreateInputs::caller(self);\n        let old_nonce =\n            ecx.journal().evm_state().get(&caller).map(|acc| acc.info.nonce).unwrap_or_default();\n        let created_address = self.created_address(old_nonce);\n        cheatcodes.allow_cheatcodes_on_create(ecx, caller, created_address);\n        created_address\n    }\n}\n"
  },
  {
    "path": "crates/cheatcodes/src/inspector.rs",
    "content": "//! Cheatcode EVM inspector.\n\nuse crate::{\n    Cheatcode, CheatsConfig, CheatsCtxt, Error, Result,\n    Vm::{self, AccountAccess},\n    evm::{\n        DealRecord, GasRecord, RecordAccess, journaled_account,\n        mock::{MockCallDataContext, MockCallReturnData},\n        prank::Prank,\n    },\n    inspector::utils::CommonCreateInput,\n    script::{Broadcast, Wallets},\n    test::{\n        assume::AssumeNoRevert,\n        expect::{\n            self, ExpectedCallData, ExpectedCallTracker, ExpectedCallType, ExpectedCreate,\n            ExpectedEmitTracker, ExpectedRevert, ExpectedRevertKind,\n        },\n        revert_handlers,\n    },\n    utils::IgnoredTraces,\n};\nuse alloy_consensus::BlobTransactionSidecarVariant;\nuse alloy_primitives::{\n    Address, B256, Bytes, Log, TxKind, U256, hex,\n    map::{AddressHashMap, HashMap, HashSet},\n};\nuse alloy_rpc_types::AccessList;\nuse alloy_sol_types::{SolCall, SolInterface, SolValue};\nuse foundry_common::{\n    SELECTOR_LEN,\n    mapping_slots::{MappingSlots, step as mapping_step},\n};\nuse foundry_evm_core::{\n    Breakpoints, EthCheatCtx, EvmEnv, FoundryInspectorExt, FoundryTransaction,\n    abi::Vm::stopExpectSafeMemoryCall,\n    backend::{DatabaseError, DatabaseExt, RevertDiagnostic},\n    constants::{CHEATCODE_ADDRESS, HARDHAT_CONSOLE_ADDRESS, MAGIC_ASSUME},\n    env::FoundryContextExt,\n    evm::{NestedEvm, NestedEvmClosure, new_eth_evm_with_inspector, with_cloned_context},\n};\nuse foundry_evm_traces::{\n    TracingInspector, TracingInspectorConfig, identifier::SignaturesIdentifier,\n};\nuse foundry_wallets::wallet_multi::MultiWallet;\nuse itertools::Itertools;\nuse proptest::test_runner::{RngAlgorithm, TestRng, TestRunner};\nuse rand::Rng;\nuse revm::{\n    Inspector,\n    bytecode::opcode as op,\n    context::{\n        BlockEnv, Cfg, ContextTr, JournalTr, Transaction, TransactionType, result::EVMError,\n    },\n    context_interface::{CreateScheme, transaction::SignedAuthorization},\n    handler::FrameResult,\n    inspector::JournalExt,\n    interpreter::{\n        CallInputs, CallOutcome, CallScheme, CreateInputs, CreateOutcome, FrameInput, Gas,\n        InstructionResult, Interpreter, InterpreterAction, InterpreterResult,\n        interpreter_types::{Jumps, LoopControl, MemoryTr},\n    },\n    primitives::hardfork::SpecId,\n};\nuse serde_json::Value;\nuse std::{\n    cmp::max,\n    collections::{BTreeMap, VecDeque},\n    fmt::Debug,\n    fs::File,\n    io::BufReader,\n    ops::Range,\n    path::PathBuf,\n    sync::{Arc, OnceLock},\n};\n\nmod utils;\n\npub mod analysis;\npub use analysis::CheatcodeAnalysis;\n\n/// Helper trait for running nested EVM operations from inside cheatcode implementations.\npub trait CheatcodesExecutor<CTX: ContextTr> {\n    /// Runs a closure with a nested EVM built from the current context.\n    /// The inspector is assembled internally — never exposed to the caller.\n    fn with_nested_evm(\n        &mut self,\n        cheats: &mut Cheatcodes,\n        ecx: &mut CTX,\n        f: NestedEvmClosure<'_, CTX::Block, CTX::Tx, <CTX::Cfg as Cfg>::Spec>,\n    ) -> Result<(), EVMError<DatabaseError>>;\n\n    /// Replays a historical transaction on the database. Inspector is assembled internally.\n    fn transact_on_db(\n        &mut self,\n        cheats: &mut Cheatcodes,\n        ecx: &mut CTX,\n        fork_id: Option<U256>,\n        transaction: B256,\n    ) -> eyre::Result<()>;\n\n    /// Executes a `TransactionRequest` on the database. Inspector is assembled internally.\n    fn transact_from_tx_on_db(\n        &mut self,\n        cheats: &mut Cheatcodes,\n        ecx: &mut CTX,\n        tx: &CTX::Tx,\n    ) -> eyre::Result<()>;\n\n    /// Runs a closure with a fresh nested EVM built from a raw database and environment.\n    /// Unlike `with_nested_evm`, this does NOT clone from `ecx` and does NOT write back.\n    /// The caller is responsible for state merging. Used by `executeTransactionCall`.\n    fn with_fresh_nested_evm(\n        &mut self,\n        cheats: &mut Cheatcodes,\n        db: &mut dyn DatabaseExt<CTX::Block, CTX::Tx, <CTX::Cfg as Cfg>::Spec>,\n        evm_env: EvmEnv<<CTX::Cfg as Cfg>::Spec, CTX::Block>,\n        tx_env: CTX::Tx,\n        f: NestedEvmClosure<'_, CTX::Block, CTX::Tx, <CTX::Cfg as Cfg>::Spec>,\n    ) -> Result<(), EVMError<DatabaseError>>;\n\n    /// Simulates `console.log` invocation.\n    fn console_log(&mut self, cheats: &mut Cheatcodes, msg: &str);\n\n    /// Returns a mutable reference to the tracing inspector if it is available.\n    fn tracing_inspector(&mut self) -> Option<&mut TracingInspector> {\n        None\n    }\n\n    /// Marks that the next EVM frame is an \"inner context\" so that isolation mode does not\n    /// trigger a nested `transact_inner`. `original_origin` is stored for the existing\n    /// inner-context adjustment logic that restores `tx.origin`.\n    fn set_in_inner_context(&mut self, _enabled: bool, _original_origin: Option<Address>) {}\n}\n\n/// Builds a sub-EVM from the current context and executes the given CREATE frame.\npub(crate) fn exec_create<CTX: EthCheatCtx>(\n    executor: &mut dyn CheatcodesExecutor<CTX>,\n    inputs: CreateInputs,\n    ccx: &mut CheatsCtxt<'_, CTX>,\n) -> std::result::Result<CreateOutcome, EVMError<DatabaseError>> {\n    let mut inputs = Some(inputs);\n    let mut outcome = None;\n    executor.with_nested_evm(ccx.state, ccx.ecx, &mut |evm| {\n        let inputs = inputs.take().unwrap();\n        evm.journal_inner_mut().depth += 1;\n\n        let frame = FrameInput::Create(Box::new(inputs));\n\n        let result = match evm.run_execution(frame)? {\n            FrameResult::Call(_) => unreachable!(),\n            FrameResult::Create(create) => create,\n        };\n\n        evm.journal_inner_mut().depth -= 1;\n\n        outcome = Some(result);\n        Ok(())\n    })?;\n    Ok(outcome.unwrap())\n}\n\n/// Basic implementation of [CheatcodesExecutor] that simply returns the [Cheatcodes] instance as an\n/// inspector.\n#[derive(Debug, Default, Clone, Copy)]\nstruct TransparentCheatcodesExecutor;\n\nimpl<CTX: EthCheatCtx> CheatcodesExecutor<CTX> for TransparentCheatcodesExecutor {\n    fn with_nested_evm(\n        &mut self,\n        cheats: &mut Cheatcodes,\n        ecx: &mut CTX,\n        f: NestedEvmClosure<'_, CTX::Block, CTX::Tx, <CTX::Cfg as Cfg>::Spec>,\n    ) -> Result<(), EVMError<DatabaseError>> {\n        with_cloned_context(ecx, |db, evm_env, tx_env, journal_inner| {\n            let mut evm = new_eth_evm_with_inspector(db, evm_env, tx_env, cheats);\n            *evm.journal_inner_mut() = journal_inner;\n            f(&mut evm)?;\n            let sub_evm_env = evm.to_evm_env();\n            let sub_inner = evm.journaled_state.inner.clone();\n            Ok((sub_evm_env, sub_inner))\n        })\n    }\n\n    fn with_fresh_nested_evm(\n        &mut self,\n        cheats: &mut Cheatcodes,\n        db: &mut dyn DatabaseExt<CTX::Block, CTX::Tx, <CTX::Cfg as Cfg>::Spec>,\n        evm_env: EvmEnv<<CTX::Cfg as Cfg>::Spec, CTX::Block>,\n        tx_env: CTX::Tx,\n        f: NestedEvmClosure<'_, CTX::Block, CTX::Tx, <CTX::Cfg as Cfg>::Spec>,\n    ) -> Result<(), EVMError<DatabaseError>> {\n        let mut evm = new_eth_evm_with_inspector(db, evm_env, tx_env, cheats);\n        f(&mut evm)\n    }\n\n    fn transact_on_db(\n        &mut self,\n        cheats: &mut Cheatcodes,\n        ecx: &mut CTX,\n        fork_id: Option<U256>,\n        transaction: B256,\n    ) -> eyre::Result<()> {\n        let evm_env = ecx.evm_clone();\n        let tx_env = ecx.tx_clone();\n        let (db, inner) = ecx.db_journal_inner_mut();\n        db.transact(fork_id, transaction, evm_env, tx_env, inner, cheats)\n    }\n\n    fn transact_from_tx_on_db(\n        &mut self,\n        cheats: &mut Cheatcodes,\n        ecx: &mut CTX,\n        tx: &CTX::Tx,\n    ) -> eyre::Result<()> {\n        let evm_env = ecx.evm_clone();\n        let (db, inner) = ecx.db_journal_inner_mut();\n        db.transact_from_tx(tx, evm_env, inner, cheats)\n    }\n\n    fn console_log(&mut self, _cheats: &mut Cheatcodes, _msg: &str) {}\n}\n\nmacro_rules! try_or_return {\n    ($e:expr) => {\n        match $e {\n            Ok(v) => v,\n            Err(_) => return,\n        }\n    };\n}\n\n/// Contains additional, test specific resources that should be kept for the duration of the test\n#[derive(Debug, Default)]\npub struct TestContext {\n    /// Buffered readers for files opened for reading (path => BufReader mapping)\n    pub opened_read_files: HashMap<PathBuf, BufReader<File>>,\n}\n\n/// Every time we clone `Context`, we want it to be empty\nimpl Clone for TestContext {\n    fn clone(&self) -> Self {\n        Default::default()\n    }\n}\n\nimpl TestContext {\n    /// Clears the context.\n    pub fn clear(&mut self) {\n        self.opened_read_files.clear();\n    }\n}\n\n/// Helps collecting transactions from different forks.\n///\n/// This type is intentionally network-agnostic — it stores raw EVM data (from, to, value, input,\n/// etc.) without requiring a `Network` type parameter. Conversion to network-specific types\n/// (e.g. `TransactionRequest`, `TxEnvelope`) happens later in the script layer.\n#[derive(Clone, Debug)]\npub struct BroadcastableTransaction {\n    /// The optional RPC URL.\n    pub rpc: Option<String>,\n    /// Sender address.\n    pub from: Address,\n    /// Recipient (None for contract creation).\n    pub to: Option<TxKind>,\n    /// Ether value.\n    pub value: U256,\n    /// Calldata or init code.\n    pub input: Bytes,\n    /// Sender nonce.\n    pub nonce: u64,\n    /// Gas limit, if explicitly set.\n    pub gas: Option<u64>,\n    /// Whether this transaction was pre-signed or needs signing.\n    pub kind: BroadcastKind,\n}\n\n/// Distinguishes between unsigned transactions (from `startBroadcast`) that need signing, and\n/// pre-signed transactions (from `broadcastRawTransaction`) that carry raw RLP-encoded bytes.\n#[derive(Clone, Debug)]\npub enum BroadcastKind {\n    /// Unsigned transaction collected during `startBroadcast`. Needs signing before broadcast.\n    Unsigned {\n        chain_id: Option<u64>,\n        blob_sidecar: Option<BlobTransactionSidecarVariant>,\n        authorization_list: Option<Vec<SignedAuthorization>>,\n    },\n    /// Pre-signed transaction from `broadcastRawTransaction`. Contains raw RLP-encoded bytes.\n    Signed(Bytes),\n}\n\nimpl BroadcastKind {\n    /// Creates an unsigned broadcast with no chain-specific fields set.\n    pub fn unsigned() -> Self {\n        Self::Unsigned { chain_id: None, blob_sidecar: None, authorization_list: None }\n    }\n}\n\n#[derive(Clone, Debug, Copy)]\npub struct RecordDebugStepInfo {\n    /// The debug trace node index when the recording starts.\n    pub start_node_idx: usize,\n    /// The original tracer config when the recording starts.\n    pub original_tracer_config: TracingInspectorConfig,\n}\n\n/// Holds gas metering state.\n#[derive(Clone, Debug, Default)]\npub struct GasMetering {\n    /// True if gas metering is paused.\n    pub paused: bool,\n    /// True if gas metering was resumed or reset during the test.\n    /// Used to reconcile gas when frame ends (if spent less than refunded).\n    pub touched: bool,\n    /// True if gas metering should be reset to frame limit.\n    pub reset: bool,\n    /// Stores paused gas frames.\n    pub paused_frames: Vec<Gas>,\n\n    /// The group and name of the active snapshot.\n    pub active_gas_snapshot: Option<(String, String)>,\n\n    /// Cache of the amount of gas used in previous call.\n    /// This is used by the `lastCallGas` cheatcode.\n    pub last_call_gas: Option<crate::Vm::Gas>,\n\n    /// True if gas recording is enabled.\n    pub recording: bool,\n    /// The gas used in the last frame.\n    pub last_gas_used: u64,\n    /// Gas records for the active snapshots.\n    pub gas_records: Vec<GasRecord>,\n}\n\nimpl GasMetering {\n    /// Start the gas recording.\n    pub fn start(&mut self) {\n        self.recording = true;\n    }\n\n    /// Stop the gas recording.\n    pub fn stop(&mut self) {\n        self.recording = false;\n    }\n\n    /// Resume paused gas metering.\n    pub fn resume(&mut self) {\n        if self.paused {\n            self.paused = false;\n            self.touched = true;\n        }\n        self.paused_frames.clear();\n    }\n\n    /// Reset gas to limit.\n    pub fn reset(&mut self) {\n        self.paused = false;\n        self.touched = true;\n        self.reset = true;\n        self.paused_frames.clear();\n    }\n}\n\n/// Holds data about arbitrary storage.\n#[derive(Clone, Debug, Default)]\npub struct ArbitraryStorage {\n    /// Mapping of arbitrary storage addresses to generated values (slot, arbitrary value).\n    /// (SLOADs return random value if storage slot wasn't accessed).\n    /// Changed values are recorded and used to copy storage to different addresses.\n    pub values: HashMap<Address, HashMap<U256, U256>>,\n    /// Mapping of address with storage copied to arbitrary storage address source.\n    pub copies: HashMap<Address, Address>,\n    /// Address with storage slots that should be overwritten even if previously set.\n    pub overwrites: HashSet<Address>,\n}\n\nimpl ArbitraryStorage {\n    /// Marks an address with arbitrary storage.\n    pub fn mark_arbitrary(&mut self, address: &Address, overwrite: bool) {\n        self.values.insert(*address, HashMap::default());\n        if overwrite {\n            self.overwrites.insert(*address);\n        } else {\n            self.overwrites.remove(address);\n        }\n    }\n\n    /// Maps an address that copies storage with the arbitrary storage address.\n    pub fn mark_copy(&mut self, from: &Address, to: &Address) {\n        if self.values.contains_key(from) {\n            self.copies.insert(*to, *from);\n        }\n    }\n\n    /// Saves arbitrary storage value for a given address:\n    /// - store value in changed values cache.\n    /// - update account's storage with given value.\n    pub fn save<CTX: ContextTr>(\n        &mut self,\n        ecx: &mut CTX,\n        address: Address,\n        slot: U256,\n        data: U256,\n    ) {\n        self.values.get_mut(&address).expect(\"missing arbitrary address entry\").insert(slot, data);\n        if ecx.journal_mut().load_account(address).is_ok() {\n            ecx.journal_mut()\n                .sstore(address, slot, data)\n                .expect(\"could not set arbitrary storage value\");\n        }\n    }\n\n    /// Copies arbitrary storage value from source address to the given target address:\n    /// - if a value is present in arbitrary values cache, then update target storage and return\n    ///   existing value.\n    /// - if no value was yet generated for given slot, then save new value in cache and update both\n    ///   source and target storages.\n    pub fn copy<CTX: ContextTr>(\n        &mut self,\n        ecx: &mut CTX,\n        target: Address,\n        slot: U256,\n        new_value: U256,\n    ) -> U256 {\n        let source = self.copies.get(&target).expect(\"missing arbitrary copy target entry\");\n        let storage_cache = self.values.get_mut(source).expect(\"missing arbitrary source storage\");\n        let value = match storage_cache.get(&slot) {\n            Some(value) => *value,\n            None => {\n                storage_cache.insert(slot, new_value);\n                // Update source storage with new value.\n                if ecx.journal_mut().load_account(*source).is_ok() {\n                    ecx.journal_mut()\n                        .sstore(*source, slot, new_value)\n                        .expect(\"could not copy arbitrary storage value\");\n                }\n                new_value\n            }\n        };\n        // Update target storage with new value.\n        if ecx.journal_mut().load_account(target).is_ok() {\n            ecx.journal_mut().sstore(target, slot, value).expect(\"could not set storage\");\n        }\n        value\n    }\n}\n\n/// List of transactions that can be broadcasted.\npub type BroadcastableTransactions = VecDeque<BroadcastableTransaction>;\n\n/// An EVM inspector that handles calls to various cheatcodes, each with their own behavior.\n///\n/// Cheatcodes can be called by contracts during execution to modify the VM environment, such as\n/// mocking addresses, signatures and altering call reverts.\n///\n/// Executing cheatcodes can be very powerful. Most cheatcodes are limited to evm internals, but\n/// there are also cheatcodes like `ffi` which can execute arbitrary commands or `writeFile` and\n/// `readFile` which can manipulate files of the filesystem. Therefore, several restrictions are\n/// implemented for these cheatcodes:\n/// - `ffi`, and file cheatcodes are _always_ opt-in (via foundry config) and never enabled by\n///   default: all respective cheatcode handlers implement the appropriate checks\n/// - File cheatcodes require explicit permissions which paths are allowed for which operation, see\n///   `Config.fs_permission`\n/// - Only permitted accounts are allowed to execute cheatcodes in forking mode, this ensures no\n///   contract deployed on the live network is able to execute cheatcodes by simply calling the\n///   cheatcode address: by default, the caller, test contract and newly deployed contracts are\n///   allowed to execute cheatcodes\n#[derive(Clone, Debug)]\npub struct Cheatcodes {\n    /// Solar compiler instance, to grant syntactic and semantic analysis capabilities\n    pub analysis: Option<CheatcodeAnalysis>,\n\n    /// The block environment\n    ///\n    /// Used in the cheatcode handler to overwrite the block environment separately from the\n    /// execution block environment.\n    pub block: Option<BlockEnv>,\n\n    /// Currently active EIP-7702 delegations that will be consumed when building the next\n    /// transaction. Set by `vm.attachDelegation()` and consumed via `.take()` during\n    /// transaction construction.\n    pub active_delegations: Vec<SignedAuthorization>,\n\n    /// The active EIP-4844 blob that will be attached to the next call.\n    pub active_blob_sidecar: Option<BlobTransactionSidecarVariant>,\n\n    /// The gas price.\n    ///\n    /// Used in the cheatcode handler to overwrite the gas price separately from the gas price\n    /// in the execution environment.\n    pub gas_price: Option<u128>,\n\n    /// Address labels\n    pub labels: AddressHashMap<String>,\n\n    /// Prank information, mapped to the call depth where pranks were added.\n    pub pranks: BTreeMap<usize, Prank>,\n\n    /// Expected revert information\n    pub expected_revert: Option<ExpectedRevert>,\n\n    /// Assume next call can revert and discard fuzz run if it does.\n    pub assume_no_revert: Option<AssumeNoRevert>,\n\n    /// Additional diagnostic for reverts\n    pub fork_revert_diagnostic: Option<RevertDiagnostic>,\n\n    /// Recorded storage reads and writes\n    pub accesses: RecordAccess,\n\n    /// Whether storage access recording is currently active\n    pub recording_accesses: bool,\n\n    /// Recorded account accesses (calls, creates) organized by relative call depth, where the\n    /// topmost vector corresponds to accesses at the depth at which account access recording\n    /// began. Each vector in the matrix represents a list of accesses at a specific call\n    /// depth. Once that call context has ended, the last vector is removed from the matrix and\n    /// merged into the previous vector.\n    pub recorded_account_diffs_stack: Option<Vec<Vec<AccountAccess>>>,\n\n    /// The information of the debug step recording.\n    pub record_debug_steps_info: Option<RecordDebugStepInfo>,\n\n    /// Recorded logs\n    pub recorded_logs: Option<Vec<crate::Vm::Log>>,\n\n    /// Mocked calls\n    // **Note**: inner must a BTreeMap because of special `Ord` impl for `MockCallDataContext`\n    pub mocked_calls: HashMap<Address, BTreeMap<MockCallDataContext, VecDeque<MockCallReturnData>>>,\n\n    /// Mocked functions. Maps target address to be mocked to pair of (calldata, mock address).\n    pub mocked_functions: HashMap<Address, HashMap<Bytes, Address>>,\n\n    /// Expected calls\n    pub expected_calls: ExpectedCallTracker,\n    /// Expected emits\n    pub expected_emits: ExpectedEmitTracker,\n    /// Expected creates\n    pub expected_creates: Vec<ExpectedCreate>,\n\n    /// Map of context depths to memory offset ranges that may be written to within the call depth.\n    pub allowed_mem_writes: HashMap<u64, Vec<Range<u64>>>,\n\n    /// Current broadcasting information\n    pub broadcast: Option<Broadcast>,\n\n    /// Scripting based transactions\n    pub broadcastable_transactions: BroadcastableTransactions,\n\n    /// Current EIP-2930 access lists.\n    pub access_list: Option<AccessList>,\n\n    /// Additional, user configurable context this Inspector has access to when inspecting a call.\n    pub config: Arc<CheatsConfig>,\n\n    /// Test-scoped context holding data that needs to be reset every test run\n    pub test_context: TestContext,\n\n    /// Whether to commit FS changes such as file creations, writes and deletes.\n    /// Used to prevent duplicate changes file executing non-committing calls.\n    pub fs_commit: bool,\n\n    /// Serialized JSON values.\n    // **Note**: both must a BTreeMap to ensure the order of the keys is deterministic.\n    pub serialized_jsons: BTreeMap<String, BTreeMap<String, Value>>,\n\n    /// All recorded ETH `deal`s.\n    pub eth_deals: Vec<DealRecord>,\n\n    /// Gas metering state.\n    pub gas_metering: GasMetering,\n\n    /// Contains gas snapshots made over the course of a test suite.\n    // **Note**: both must a BTreeMap to ensure the order of the keys is deterministic.\n    pub gas_snapshots: BTreeMap<String, BTreeMap<String, String>>,\n\n    /// Mapping slots.\n    pub mapping_slots: Option<AddressHashMap<MappingSlots>>,\n\n    /// The current program counter.\n    pub pc: usize,\n    /// Breakpoints supplied by the `breakpoint` cheatcode.\n    /// `char -> (address, pc)`\n    pub breakpoints: Breakpoints,\n\n    /// Whether the next contract creation should be intercepted to return its initcode.\n    pub intercept_next_create_call: bool,\n\n    /// Optional cheatcodes `TestRunner`. Used for generating random values from uint and int\n    /// strategies.\n    test_runner: Option<TestRunner>,\n\n    /// Ignored traces.\n    pub ignored_traces: IgnoredTraces,\n\n    /// Addresses with arbitrary storage.\n    pub arbitrary_storage: Option<ArbitraryStorage>,\n\n    /// Deprecated cheatcodes mapped to the reason. Used to report warnings on test results.\n    pub deprecated: HashMap<&'static str, Option<&'static str>>,\n    /// Unlocked wallets used in scripts and testing of scripts.\n    pub wallets: Option<Wallets>,\n    /// Signatures identifier for decoding events and functions\n    signatures_identifier: OnceLock<Option<SignaturesIdentifier>>,\n    /// Used to determine whether the broadcasted call has dynamic gas limit.\n    pub dynamic_gas_limit: bool,\n    // Custom execution evm version.\n    pub execution_evm_version: Option<SpecId>,\n}\n\n// This is not derived because calling this in `fn new` with `..Default::default()` creates a second\n// `CheatsConfig` which is unused, and inside it `ProjectPathsConfig` is relatively expensive to\n// create.\nimpl Default for Cheatcodes {\n    fn default() -> Self {\n        Self::new(Arc::default())\n    }\n}\n\nimpl Cheatcodes {\n    /// Creates a new `Cheatcodes` with the given settings.\n    pub fn new(config: Arc<CheatsConfig>) -> Self {\n        Self {\n            analysis: None,\n            fs_commit: true,\n            labels: config.labels.clone(),\n            config,\n            block: Default::default(),\n            active_delegations: Default::default(),\n            active_blob_sidecar: Default::default(),\n            gas_price: Default::default(),\n            pranks: Default::default(),\n            expected_revert: Default::default(),\n            assume_no_revert: Default::default(),\n            fork_revert_diagnostic: Default::default(),\n            accesses: Default::default(),\n            recording_accesses: Default::default(),\n            recorded_account_diffs_stack: Default::default(),\n            recorded_logs: Default::default(),\n            record_debug_steps_info: Default::default(),\n            mocked_calls: Default::default(),\n            mocked_functions: Default::default(),\n            expected_calls: Default::default(),\n            expected_emits: Default::default(),\n            expected_creates: Default::default(),\n            allowed_mem_writes: Default::default(),\n            broadcast: Default::default(),\n            broadcastable_transactions: Default::default(),\n            access_list: Default::default(),\n            test_context: Default::default(),\n            serialized_jsons: Default::default(),\n            eth_deals: Default::default(),\n            gas_metering: Default::default(),\n            gas_snapshots: Default::default(),\n            mapping_slots: Default::default(),\n            pc: Default::default(),\n            breakpoints: Default::default(),\n            intercept_next_create_call: Default::default(),\n            test_runner: Default::default(),\n            ignored_traces: Default::default(),\n            arbitrary_storage: Default::default(),\n            deprecated: Default::default(),\n            wallets: Default::default(),\n            signatures_identifier: Default::default(),\n            dynamic_gas_limit: Default::default(),\n            execution_evm_version: None,\n        }\n    }\n\n    /// Enables cheatcode analysis capabilities by providing a solar compiler instance.\n    pub fn set_analysis(&mut self, analysis: CheatcodeAnalysis) {\n        self.analysis = Some(analysis);\n    }\n\n    /// Returns the configured prank at given depth or the first prank configured at a lower depth.\n    /// For example, if pranks configured for depth 1, 3 and 5, the prank for depth 4 is the one\n    /// configured at depth 3.\n    pub fn get_prank(&self, depth: usize) -> Option<&Prank> {\n        self.pranks.range(..=depth).last().map(|(_, prank)| prank)\n    }\n\n    /// Returns the configured wallets if available, else creates a new instance.\n    pub fn wallets(&mut self) -> &Wallets {\n        self.wallets.get_or_insert_with(|| Wallets::new(MultiWallet::default(), None))\n    }\n\n    /// Sets the unlocked wallets.\n    pub fn set_wallets(&mut self, wallets: Wallets) {\n        self.wallets = Some(wallets);\n    }\n\n    /// Adds a delegation to the active delegations list.\n    pub fn add_delegation(&mut self, authorization: SignedAuthorization) {\n        self.active_delegations.push(authorization);\n    }\n\n    /// Returns the signatures identifier.\n    pub fn signatures_identifier(&self) -> Option<&SignaturesIdentifier> {\n        self.signatures_identifier.get_or_init(|| SignaturesIdentifier::new(true).ok()).as_ref()\n    }\n\n    /// Decodes the input data and applies the cheatcode.\n    fn apply_cheatcode<CTX: EthCheatCtx>(\n        &mut self,\n        ecx: &mut CTX,\n        call: &CallInputs,\n        executor: &mut dyn CheatcodesExecutor<CTX>,\n    ) -> Result {\n        // decode the cheatcode call\n        let decoded = Vm::VmCalls::abi_decode(&call.input.bytes(ecx)).map_err(|e| {\n            if let alloy_sol_types::Error::UnknownSelector { name: _, selector } = e {\n                let msg = format!(\n                    \"unknown cheatcode with selector {selector}; \\\n                     you may have a mismatch between the `Vm` interface (likely in `forge-std`) \\\n                     and the `forge` version\"\n                );\n                return alloy_sol_types::Error::Other(std::borrow::Cow::Owned(msg));\n            }\n            e\n        })?;\n\n        let caller = call.caller;\n\n        // ensure the caller is allowed to execute cheatcodes,\n        // but only if the backend is in forking mode\n        ecx.db_mut().ensure_cheatcode_access_forking_mode(&caller)?;\n\n        apply_dispatch(\n            &decoded,\n            &mut CheatsCtxt { state: self, ecx, gas_limit: call.gas_limit, caller },\n            executor,\n        )\n    }\n\n    /// Grants cheat code access for new contracts if the caller also has\n    /// cheatcode access or the new contract is created in top most call.\n    ///\n    /// There may be cheatcodes in the constructor of the new contract, in order to allow them\n    /// automatically we need to determine the new address.\n    fn allow_cheatcodes_on_create<CTX: ContextTr<Db: DatabaseExt>>(\n        &self,\n        ecx: &mut CTX,\n        caller: Address,\n        created_address: Address,\n    ) {\n        if ecx.journal().depth() <= 1 || ecx.db().has_cheatcode_access(&caller) {\n            ecx.db_mut().allow_cheatcode_access(created_address);\n        }\n    }\n\n    /// Apply EIP-2930 access list.\n    ///\n    /// If the transaction type is [TransactionType::Legacy] we need to upgrade it to\n    /// [TransactionType::Eip2930] in order to use access lists. Other transaction types support\n    /// access lists themselves.\n    fn apply_accesslist<CTX: FoundryContextExt>(&mut self, ecx: &mut CTX) {\n        if let Some(access_list) = &self.access_list {\n            ecx.tx_mut().set_access_list(access_list.clone());\n\n            if ecx.tx().tx_type() == TransactionType::Legacy as u8 {\n                ecx.tx_mut().set_tx_type(TransactionType::Eip2930 as u8);\n            }\n        }\n    }\n\n    /// Called when there was a revert.\n    ///\n    /// Cleanup any previously applied cheatcodes that altered the state in such a way that revm's\n    /// revert would run into issues.\n    pub fn on_revert<CTX: ContextTr<Journal: JournalExt>>(&mut self, ecx: &mut CTX) {\n        trace!(deals=?self.eth_deals.len(), \"rolling back deals\");\n\n        // Delay revert clean up until expected revert is handled, if set.\n        if self.expected_revert.is_some() {\n            return;\n        }\n\n        // we only want to apply cleanup top level\n        if ecx.journal().depth() > 0 {\n            return;\n        }\n\n        // Roll back all previously applied deals\n        // This will prevent overflow issues in revm's [`JournaledState::journal_revert`] routine\n        // which rolls back any transfers.\n        while let Some(record) = self.eth_deals.pop() {\n            if let Some(acc) = ecx.journal_mut().evm_state_mut().get_mut(&record.address) {\n                acc.info.balance = record.old_balance;\n            }\n        }\n    }\n\n    pub fn call_with_executor<CTX: EthCheatCtx>(\n        &mut self,\n        ecx: &mut CTX,\n        call: &mut CallInputs,\n        executor: &mut dyn CheatcodesExecutor<CTX>,\n    ) -> Option<CallOutcome> {\n        // Apply custom execution evm version.\n        if let Some(spec_id) = self.execution_evm_version {\n            ecx.cfg_mut().set_spec(spec_id);\n        }\n\n        let gas = Gas::new(call.gas_limit);\n        let curr_depth = ecx.journal().depth();\n\n        // At the root call to test function or script `run()`/`setUp()` functions, we are\n        // decreasing sender nonce to ensure that it matches on-chain nonce once we start\n        // broadcasting.\n        if curr_depth == 0 {\n            let sender = ecx.tx().caller();\n            let account = match super::evm::journaled_account(ecx, sender) {\n                Ok(account) => account,\n                Err(err) => {\n                    return Some(CallOutcome {\n                        result: InterpreterResult {\n                            result: InstructionResult::Revert,\n                            output: err.abi_encode().into(),\n                            gas,\n                        },\n                        memory_offset: call.return_memory_offset.clone(),\n                        was_precompile_called: false,\n                        precompile_call_logs: vec![],\n                    });\n                }\n            };\n            let prev = account.info.nonce;\n            account.info.nonce = prev.saturating_sub(1);\n\n            trace!(target: \"cheatcodes\", %sender, nonce=account.info.nonce, prev, \"corrected nonce\");\n        }\n\n        if call.target_address == CHEATCODE_ADDRESS {\n            return match self.apply_cheatcode(ecx, call, executor) {\n                Ok(retdata) => Some(CallOutcome {\n                    result: InterpreterResult {\n                        result: InstructionResult::Return,\n                        output: retdata.into(),\n                        gas,\n                    },\n                    memory_offset: call.return_memory_offset.clone(),\n                    was_precompile_called: true,\n                    precompile_call_logs: vec![],\n                }),\n                Err(err) => Some(CallOutcome {\n                    result: InterpreterResult {\n                        result: InstructionResult::Revert,\n                        output: err.abi_encode().into(),\n                        gas,\n                    },\n                    memory_offset: call.return_memory_offset.clone(),\n                    was_precompile_called: false,\n                    precompile_call_logs: vec![],\n                }),\n            };\n        }\n\n        if call.target_address == HARDHAT_CONSOLE_ADDRESS {\n            return None;\n        }\n\n        // `expectRevert`: track max call depth. This is also done in `initialize_interp`, but\n        // precompile calls don't create an interpreter frame so we must also track it here.\n        // The callee executes at `curr_depth + 1`.\n        if let Some(expected) = &mut self.expected_revert {\n            expected.max_depth = max(curr_depth + 1, expected.max_depth);\n        }\n\n        // Handle expected calls\n\n        // Grab the different calldatas expected.\n        if let Some(expected_calls_for_target) = self.expected_calls.get_mut(&call.bytecode_address)\n        {\n            // Match every partial/full calldata\n            for (calldata, (expected, actual_count)) in expected_calls_for_target {\n                // Increment actual times seen if...\n                // The calldata is at most, as big as this call's input, and\n                if calldata.len() <= call.input.len() &&\n                    // Both calldata match, taking the length of the assumed smaller one (which will have at least the selector), and\n                    *calldata == call.input.bytes(ecx)[..calldata.len()] &&\n                    // The value matches, if provided\n                    expected\n                        .value.is_none_or(|value| Some(value) == call.transfer_value()) &&\n                    // The gas matches, if provided\n                    expected.gas.is_none_or(|gas| gas == call.gas_limit) &&\n                    // The minimum gas matches, if provided\n                    expected.min_gas.is_none_or(|min_gas| min_gas <= call.gas_limit)\n                {\n                    *actual_count += 1;\n                }\n            }\n        }\n\n        // Handle mocked calls\n        if let Some(mocks) = self.mocked_calls.get_mut(&call.bytecode_address) {\n            let ctx = MockCallDataContext {\n                calldata: call.input.bytes(ecx),\n                value: call.transfer_value(),\n            };\n\n            if let Some(return_data_queue) = match mocks.get_mut(&ctx) {\n                Some(queue) => Some(queue),\n                None => mocks\n                    .iter_mut()\n                    .find(|(mock, _)| {\n                        call.input.bytes(ecx).get(..mock.calldata.len()) == Some(&mock.calldata[..])\n                            && mock.value.is_none_or(|value| Some(value) == call.transfer_value())\n                    })\n                    .map(|(_, v)| v),\n            } && let Some(return_data) = if return_data_queue.len() == 1 {\n                // If the mocked calls stack has a single element in it, don't empty it\n                return_data_queue.front().map(|x| x.to_owned())\n            } else {\n                // Else, we pop the front element\n                return_data_queue.pop_front()\n            } {\n                return Some(CallOutcome {\n                    result: InterpreterResult {\n                        result: return_data.ret_type,\n                        output: return_data.data,\n                        gas,\n                    },\n                    memory_offset: call.return_memory_offset.clone(),\n                    was_precompile_called: true,\n                    precompile_call_logs: vec![],\n                });\n            }\n        }\n\n        // Apply our prank\n        if let Some(prank) = &self.get_prank(curr_depth) {\n            // Apply delegate call, `call.caller`` will not equal `prank.prank_caller`\n            if prank.delegate_call\n                && curr_depth == prank.depth\n                && let CallScheme::DelegateCall = call.scheme\n            {\n                call.target_address = prank.new_caller;\n                call.caller = prank.new_caller;\n                if let Some(new_origin) = prank.new_origin {\n                    ecx.tx_mut().set_caller(new_origin);\n                }\n            }\n\n            if curr_depth >= prank.depth && call.caller == prank.prank_caller {\n                let mut prank_applied = false;\n\n                // At the target depth we set `msg.sender`\n                if curr_depth == prank.depth {\n                    // Ensure new caller is loaded and touched\n                    let _ = journaled_account(ecx, prank.new_caller);\n                    call.caller = prank.new_caller;\n                    prank_applied = true;\n                }\n\n                // At the target depth, or deeper, we set `tx.origin`\n                if let Some(new_origin) = prank.new_origin {\n                    ecx.tx_mut().set_caller(new_origin);\n                    prank_applied = true;\n                }\n\n                // If prank applied for first time, then update\n                if prank_applied && let Some(applied_prank) = prank.first_time_applied() {\n                    self.pranks.insert(curr_depth, applied_prank);\n                }\n            }\n        }\n\n        // Apply EIP-2930 access list\n        self.apply_accesslist(ecx);\n\n        // Apply our broadcast\n        if let Some(broadcast) = &self.broadcast {\n            // Additional check as transfers in forge scripts seem to be estimated at 2300\n            // by revm leading to \"Intrinsic gas too low\" failure when simulated on chain.\n            let is_fixed_gas_limit = call.gas_limit >= 21_000 && !self.dynamic_gas_limit;\n            self.dynamic_gas_limit = false;\n\n            // We only apply a broadcast *to a specific depth*.\n            //\n            // We do this because any subsequent contract calls *must* exist on chain and\n            // we only want to grab *this* call, not internal ones\n            if curr_depth == broadcast.depth && call.caller == broadcast.original_caller {\n                // At the target depth we set `msg.sender` & tx.origin.\n                // We are simulating the caller as being an EOA, so *both* must be set to the\n                // broadcast.origin.\n                ecx.tx_mut().set_caller(broadcast.new_origin);\n\n                call.caller = broadcast.new_origin;\n                // Add a `legacy` transaction to the VecDeque. We use a legacy transaction here\n                // because we only need the from, to, value, and data. We can later change this\n                // into 1559, in the cli package, relatively easily once we\n                // know the target chain supports EIP-1559.\n                if !call.is_static {\n                    if let Err(err) = ecx.journal_mut().load_account(broadcast.new_origin) {\n                        return Some(CallOutcome {\n                            result: InterpreterResult {\n                                result: InstructionResult::Revert,\n                                output: Error::encode(err),\n                                gas,\n                            },\n                            memory_offset: call.return_memory_offset.clone(),\n                            was_precompile_called: false,\n                            precompile_call_logs: vec![],\n                        });\n                    }\n\n                    let input = call.input.bytes(ecx);\n                    let chain_id = ecx.cfg().chain_id();\n                    let rpc = ecx.db().active_fork_url();\n                    let account =\n                        ecx.journal_mut().evm_state_mut().get_mut(&broadcast.new_origin).unwrap();\n\n                    let blob_sidecar = self.active_blob_sidecar.take();\n                    let active_delegations = std::mem::take(&mut self.active_delegations);\n\n                    // Ensure blob and delegation are not set for the same tx.\n                    if blob_sidecar.is_some() && !active_delegations.is_empty() {\n                        let msg = \"both delegation and blob are active; `attachBlob` and `attachDelegation` are not compatible\";\n                        return Some(CallOutcome {\n                            result: InterpreterResult {\n                                result: InstructionResult::Revert,\n                                output: Error::encode(msg),\n                                gas,\n                            },\n                            memory_offset: call.return_memory_offset.clone(),\n                            was_precompile_called: false,\n                            precompile_call_logs: vec![],\n                        });\n                    }\n\n                    // Capture nonce before delegation bump (delegations increment the\n                    // account nonce but the transaction itself uses the pre-bump nonce).\n                    let nonce = account.info.nonce;\n\n                    // Apply active EIP-7702 delegations, if any.\n                    let authorization_list = if !active_delegations.is_empty() {\n                        for auth in &active_delegations {\n                            let Ok(authority) = auth.recover_authority() else {\n                                continue;\n                            };\n                            if authority == broadcast.new_origin {\n                                // Increment nonce of broadcasting account to reflect signed\n                                // authorization.\n                                account.info.nonce += 1;\n                            }\n                        }\n                        Some(active_delegations)\n                    } else {\n                        None\n                    };\n\n                    self.broadcastable_transactions.push_back(BroadcastableTransaction {\n                        rpc,\n                        from: broadcast.new_origin,\n                        to: Some(TxKind::from(Some(call.target_address))),\n                        value: call.transfer_value().unwrap_or_default(),\n                        input,\n                        nonce,\n                        gas: if is_fixed_gas_limit { Some(call.gas_limit) } else { None },\n                        kind: BroadcastKind::Unsigned {\n                            chain_id: Some(chain_id),\n                            blob_sidecar,\n                            authorization_list,\n                        },\n                    });\n                    debug!(target: \"cheatcodes\", tx=?self.broadcastable_transactions.back().unwrap(), \"broadcastable call\");\n\n                    // Explicitly increment nonce if calls are not isolated.\n                    if !self.config.evm_opts.isolate {\n                        let prev = account.info.nonce;\n                        account.info.nonce += 1;\n                        debug!(target: \"cheatcodes\", address=%broadcast.new_origin, nonce=prev+1, prev, \"incremented nonce\");\n                    }\n                } else if broadcast.single_call {\n                    let msg = \"`staticcall`s are not allowed after `broadcast`; use `startBroadcast` instead\";\n                    return Some(CallOutcome {\n                        result: InterpreterResult {\n                            result: InstructionResult::Revert,\n                            output: Error::encode(msg),\n                            gas,\n                        },\n                        memory_offset: call.return_memory_offset.clone(),\n                        was_precompile_called: false,\n                        precompile_call_logs: vec![],\n                    });\n                }\n            }\n        }\n\n        // Record called accounts if `startStateDiffRecording` has been called\n        if let Some(recorded_account_diffs_stack) = &mut self.recorded_account_diffs_stack {\n            // Determine if account is \"initialized,\" ie, it has a non-zero balance, a non-zero\n            // nonce, a non-zero KECCAK_EMPTY codehash, or non-empty code\n            let initialized;\n            let old_balance;\n            let old_nonce;\n\n            if let Ok(acc) = ecx.journal_mut().load_account(call.target_address) {\n                initialized = acc.data.info.exists();\n                old_balance = acc.data.info.balance;\n                old_nonce = acc.data.info.nonce;\n            } else {\n                initialized = false;\n                old_balance = U256::ZERO;\n                old_nonce = 0;\n            }\n\n            let kind = match call.scheme {\n                CallScheme::Call => crate::Vm::AccountAccessKind::Call,\n                CallScheme::CallCode => crate::Vm::AccountAccessKind::CallCode,\n                CallScheme::DelegateCall => crate::Vm::AccountAccessKind::DelegateCall,\n                CallScheme::StaticCall => crate::Vm::AccountAccessKind::StaticCall,\n            };\n\n            // Record this call by pushing it to a new pending vector; all subsequent calls at\n            // that depth will be pushed to the same vector. When the call ends, the\n            // RecordedAccountAccess (and all subsequent RecordedAccountAccesses) will be\n            // updated with the revert status of this call, since the EVM does not mark accounts\n            // as \"warm\" if the call from which they were accessed is reverted\n            recorded_account_diffs_stack.push(vec![AccountAccess {\n                chainInfo: crate::Vm::ChainInfo {\n                    forkId: ecx.db().active_fork_id().unwrap_or_default(),\n                    chainId: U256::from(ecx.cfg().chain_id()),\n                },\n                accessor: call.caller,\n                account: call.bytecode_address,\n                kind,\n                initialized,\n                oldBalance: old_balance,\n                newBalance: U256::ZERO, // updated on call_end\n                oldNonce: old_nonce,\n                newNonce: 0, // updated on call_end\n                value: call.call_value(),\n                data: call.input.bytes(ecx),\n                reverted: false,\n                deployedCode: Bytes::new(),\n                storageAccesses: vec![], // updated on step\n                depth: ecx.journal().depth().try_into().expect(\"journaled state depth exceeds u64\"),\n            }]);\n        }\n\n        None\n    }\n\n    pub fn rng(&mut self) -> &mut impl Rng {\n        self.test_runner().rng()\n    }\n\n    pub fn test_runner(&mut self) -> &mut TestRunner {\n        self.test_runner.get_or_insert_with(|| match self.config.seed {\n            Some(seed) => TestRunner::new_with_rng(\n                proptest::test_runner::Config::default(),\n                TestRng::from_seed(RngAlgorithm::ChaCha, &seed.to_be_bytes::<32>()),\n            ),\n            None => TestRunner::new(proptest::test_runner::Config::default()),\n        })\n    }\n\n    pub fn set_seed(&mut self, seed: U256) {\n        self.test_runner = Some(TestRunner::new_with_rng(\n            proptest::test_runner::Config::default(),\n            TestRng::from_seed(RngAlgorithm::ChaCha, &seed.to_be_bytes::<32>()),\n        ));\n    }\n\n    /// Returns existing or set a default `ArbitraryStorage` option.\n    /// Used by `setArbitraryStorage` cheatcode to track addresses with arbitrary storage.\n    pub fn arbitrary_storage(&mut self) -> &mut ArbitraryStorage {\n        self.arbitrary_storage.get_or_insert_with(ArbitraryStorage::default)\n    }\n\n    /// Whether the given address has arbitrary storage.\n    pub fn has_arbitrary_storage(&self, address: &Address) -> bool {\n        match &self.arbitrary_storage {\n            Some(storage) => storage.values.contains_key(address),\n            None => false,\n        }\n    }\n\n    /// Whether the given slot of address with arbitrary storage should be overwritten.\n    /// True if address is marked as and overwrite and if no value was previously generated for\n    /// given slot.\n    pub fn should_overwrite_arbitrary_storage(\n        &self,\n        address: &Address,\n        storage_slot: U256,\n    ) -> bool {\n        match &self.arbitrary_storage {\n            Some(storage) => {\n                storage.overwrites.contains(address)\n                    && storage\n                        .values\n                        .get(address)\n                        .and_then(|arbitrary_values| arbitrary_values.get(&storage_slot))\n                        .is_none()\n            }\n            None => false,\n        }\n    }\n\n    /// Whether the given address is a copy of an address with arbitrary storage.\n    pub fn is_arbitrary_storage_copy(&self, address: &Address) -> bool {\n        match &self.arbitrary_storage {\n            Some(storage) => storage.copies.contains_key(address),\n            None => false,\n        }\n    }\n\n    /// Returns struct definitions from the analysis, if available.\n    pub fn struct_defs(&self) -> Option<&foundry_common::fmt::StructDefinitions> {\n        self.analysis.as_ref().and_then(|analysis| analysis.struct_defs().ok())\n    }\n}\n\nimpl<CTX: EthCheatCtx> Inspector<CTX> for Cheatcodes {\n    fn initialize_interp(&mut self, interpreter: &mut Interpreter, ecx: &mut CTX) {\n        // When the first interpreter is initialized we've circumvented the balance and gas checks,\n        // so we apply our actual block data with the correct fees and all.\n        if let Some(block) = self.block.take() {\n            ecx.set_block(block);\n        }\n        if let Some(gas_price) = self.gas_price.take() {\n            ecx.tx_mut().set_gas_price(gas_price);\n        }\n\n        // Record gas for current frame.\n        if self.gas_metering.paused {\n            self.gas_metering.paused_frames.push(interpreter.gas);\n        }\n\n        // `expectRevert`: track the max call depth during `expectRevert`\n        if let Some(expected) = &mut self.expected_revert {\n            expected.max_depth = max(ecx.journal().depth(), expected.max_depth);\n        }\n    }\n\n    fn step(&mut self, interpreter: &mut Interpreter, ecx: &mut CTX) {\n        self.pc = interpreter.bytecode.pc();\n\n        if self.broadcast.is_some() {\n            self.set_gas_limit_type(interpreter);\n        }\n\n        // `pauseGasMetering`: pause / resume interpreter gas.\n        if self.gas_metering.paused {\n            self.meter_gas(interpreter);\n        }\n\n        // `resetGasMetering`: reset interpreter gas.\n        if self.gas_metering.reset {\n            self.meter_gas_reset(interpreter);\n        }\n\n        // `record`: record storage reads and writes.\n        if self.recording_accesses {\n            self.record_accesses(interpreter);\n        }\n\n        // `startStateDiffRecording`: record granular ordered storage accesses.\n        if self.recorded_account_diffs_stack.is_some() {\n            self.record_state_diffs(interpreter, ecx);\n        }\n\n        // `expectSafeMemory`: check if the current opcode is allowed to interact with memory.\n        if !self.allowed_mem_writes.is_empty() {\n            self.check_mem_opcodes(\n                interpreter,\n                ecx.journal().depth().try_into().expect(\"journaled state depth exceeds u64\"),\n            );\n        }\n\n        // `startMappingRecording`: record SSTORE and KECCAK256.\n        if let Some(mapping_slots) = &mut self.mapping_slots {\n            mapping_step(mapping_slots, interpreter);\n        }\n\n        // `snapshotGas*`: take a snapshot of the current gas.\n        if self.gas_metering.recording {\n            self.meter_gas_record(interpreter, ecx);\n        }\n    }\n\n    fn step_end(&mut self, interpreter: &mut Interpreter, ecx: &mut CTX) {\n        if self.gas_metering.paused {\n            self.meter_gas_end(interpreter);\n        }\n\n        if self.gas_metering.touched {\n            self.meter_gas_check(interpreter);\n        }\n\n        // `setArbitraryStorage` and `copyStorage`: add arbitrary values to storage.\n        if self.arbitrary_storage.is_some() {\n            self.arbitrary_storage_end(interpreter, ecx);\n        }\n    }\n\n    fn log(&mut self, _ecx: &mut CTX, log: Log) {\n        if !self.expected_emits.is_empty()\n            && let Some(err) = expect::handle_expect_emit(self, &log, None)\n        {\n            // Because we do not have access to the interpreter here, we cannot fail the test\n            // immediately. In most cases the failure will still be caught on `call_end`.\n            // In the rare case it is not, we log the error here.\n            let _ = sh_err!(\"{err:?}\");\n        }\n\n        // `recordLogs`\n        record_logs(&mut self.recorded_logs, &log);\n    }\n\n    fn log_full(&mut self, interpreter: &mut Interpreter, _ecx: &mut CTX, log: Log) {\n        if !self.expected_emits.is_empty() {\n            expect::handle_expect_emit(self, &log, Some(interpreter));\n        }\n\n        // `recordLogs`\n        record_logs(&mut self.recorded_logs, &log);\n    }\n\n    fn call(&mut self, ecx: &mut CTX, inputs: &mut CallInputs) -> Option<CallOutcome> {\n        Self::call_with_executor(self, ecx, inputs, &mut TransparentCheatcodesExecutor)\n    }\n\n    fn call_end(&mut self, ecx: &mut CTX, call: &CallInputs, outcome: &mut CallOutcome) {\n        let cheatcode_call = call.target_address == CHEATCODE_ADDRESS\n            || call.target_address == HARDHAT_CONSOLE_ADDRESS;\n\n        // Clean up pranks/broadcasts if it's not a cheatcode call end. We shouldn't do\n        // it for cheatcode calls because they are not applied for cheatcodes in the `call` hook.\n        // This should be placed before the revert handling, because we might exit early there\n        if !cheatcode_call {\n            // Clean up pranks\n            let curr_depth = ecx.journal().depth();\n            if let Some(prank) = &self.get_prank(curr_depth)\n                && curr_depth == prank.depth\n            {\n                ecx.tx_mut().set_caller(prank.prank_origin);\n\n                // Clean single-call prank once we have returned to the original depth\n                if prank.single_call {\n                    self.pranks.remove(&curr_depth);\n                }\n            }\n\n            // Clean up broadcast\n            if let Some(broadcast) = &self.broadcast\n                && curr_depth == broadcast.depth\n            {\n                ecx.tx_mut().set_caller(broadcast.original_origin);\n\n                // Clean single-call broadcast once we have returned to the original depth\n                if broadcast.single_call {\n                    let _ = self.broadcast.take();\n                }\n            }\n        }\n\n        // Handle assume no revert cheatcode.\n        if let Some(assume_no_revert) = &mut self.assume_no_revert {\n            // Record current reverter address before processing the expect revert if call reverted,\n            // expect revert is set with expected reverter address and no actual reverter set yet.\n            if outcome.result.is_revert() && assume_no_revert.reverted_by.is_none() {\n                assume_no_revert.reverted_by = Some(call.target_address);\n            }\n\n            // allow multiple cheatcode calls at the same depth\n            let curr_depth = ecx.journal().depth();\n            if curr_depth <= assume_no_revert.depth && !cheatcode_call {\n                // Discard run if we're at the same depth as cheatcode, call reverted, and no\n                // specific reason was supplied\n                if outcome.result.is_revert() {\n                    let assume_no_revert = std::mem::take(&mut self.assume_no_revert).unwrap();\n                    return match revert_handlers::handle_assume_no_revert(\n                        &assume_no_revert,\n                        outcome.result.result,\n                        &outcome.result.output,\n                        &self.config.available_artifacts,\n                    ) {\n                        // if result is Ok, it was an anticipated revert; return an \"assume\" error\n                        // to reject this run\n                        Ok(_) => {\n                            outcome.result.output = Error::from(MAGIC_ASSUME).abi_encode().into();\n                        }\n                        // if result is Error, it was an unanticipated revert; should revert\n                        // normally\n                        Err(error) => {\n                            trace!(expected=?assume_no_revert, ?error, status=?outcome.result.result, \"Expected revert mismatch\");\n                            outcome.result.result = InstructionResult::Revert;\n                            outcome.result.output = error.abi_encode().into();\n                        }\n                    };\n                } else {\n                    // Call didn't revert, reset `assume_no_revert` state.\n                    self.assume_no_revert = None;\n                }\n            }\n        }\n\n        // Handle expected reverts.\n        if let Some(expected_revert) = &mut self.expected_revert {\n            // Record current reverter address and call scheme before processing the expect revert\n            // if call reverted.\n            if outcome.result.is_revert() {\n                // Record current reverter address if expect revert is set with expected reverter\n                // address and no actual reverter was set yet or if we're expecting more than one\n                // revert.\n                if expected_revert.reverter.is_some()\n                    && (expected_revert.reverted_by.is_none() || expected_revert.count > 1)\n                {\n                    expected_revert.reverted_by = Some(call.target_address);\n                }\n            }\n\n            let curr_depth = ecx.journal().depth();\n            if curr_depth <= expected_revert.depth {\n                let needs_processing = match expected_revert.kind {\n                    ExpectedRevertKind::Default => !cheatcode_call,\n                    // `pending_processing` == true means that we're in the `call_end` hook for\n                    // `vm.expectCheatcodeRevert` and shouldn't expect revert here\n                    ExpectedRevertKind::Cheatcode { pending_processing } => {\n                        cheatcode_call && !pending_processing\n                    }\n                };\n\n                if needs_processing {\n                    let mut expected_revert = std::mem::take(&mut self.expected_revert).unwrap();\n                    return match revert_handlers::handle_expect_revert(\n                        cheatcode_call,\n                        false,\n                        self.config.internal_expect_revert,\n                        &expected_revert,\n                        outcome.result.result,\n                        outcome.result.output.clone(),\n                        &self.config.available_artifacts,\n                    ) {\n                        Err(error) => {\n                            trace!(expected=?expected_revert, ?error, status=?outcome.result.result, \"Expected revert mismatch\");\n                            outcome.result.result = InstructionResult::Revert;\n                            outcome.result.output = error.abi_encode().into();\n                        }\n                        Ok((_, retdata)) => {\n                            expected_revert.actual_count += 1;\n                            if expected_revert.actual_count < expected_revert.count {\n                                self.expected_revert = Some(expected_revert);\n                            }\n                            outcome.result.result = InstructionResult::Return;\n                            outcome.result.output = retdata;\n                        }\n                    };\n                }\n\n                // Flip `pending_processing` flag for cheatcode revert expectations, marking that\n                // we've exited the `expectCheatcodeRevert` call scope\n                if let ExpectedRevertKind::Cheatcode { pending_processing } =\n                    &mut self.expected_revert.as_mut().unwrap().kind\n                {\n                    *pending_processing = false;\n                }\n            }\n        }\n\n        // Exit early for calls to cheatcodes as other logic is not relevant for cheatcode\n        // invocations\n        if cheatcode_call {\n            return;\n        }\n\n        // Record the gas usage of the call, this allows the `lastCallGas` cheatcode to\n        // retrieve the gas usage of the last call.\n        let gas = outcome.result.gas;\n        self.gas_metering.last_call_gas = Some(crate::Vm::Gas {\n            gasLimit: gas.limit(),\n            gasTotalUsed: gas.spent(),\n            gasMemoryUsed: 0,\n            gasRefunded: gas.refunded(),\n            gasRemaining: gas.remaining(),\n        });\n\n        // If `startStateDiffRecording` has been called, update the `reverted` status of the\n        // previous call depth's recorded accesses, if any\n        if let Some(recorded_account_diffs_stack) = &mut self.recorded_account_diffs_stack {\n            // The root call cannot be recorded.\n            if ecx.journal().depth() > 0\n                && let Some(mut last_recorded_depth) = recorded_account_diffs_stack.pop()\n            {\n                // Update the reverted status of all deeper calls if this call reverted, in\n                // accordance with EVM behavior\n                if outcome.result.is_revert() {\n                    last_recorded_depth.iter_mut().for_each(|element| {\n                        element.reverted = true;\n                        element\n                            .storageAccesses\n                            .iter_mut()\n                            .for_each(|storage_access| storage_access.reverted = true);\n                    })\n                }\n\n                if let Some(call_access) = last_recorded_depth.first_mut() {\n                    // Assert that we're at the correct depth before recording post-call state\n                    // changes. Depending on the depth the cheat was\n                    // called at, there may not be any pending\n                    // calls to update if execution has percolated up to a higher depth.\n                    let curr_depth = ecx.journal().depth();\n                    if call_access.depth == curr_depth as u64\n                        && let Ok(acc) = ecx.journal_mut().load_account(call.target_address)\n                    {\n                        debug_assert!(access_is_call(call_access.kind));\n                        call_access.newBalance = acc.data.info.balance;\n                        call_access.newNonce = acc.data.info.nonce;\n                    }\n                    // Merge the last depth's AccountAccesses into the AccountAccesses at the\n                    // current depth, or push them back onto the pending\n                    // vector if higher depths were not recorded. This\n                    // preserves ordering of accesses.\n                    if let Some(last) = recorded_account_diffs_stack.last_mut() {\n                        last.extend(last_recorded_depth);\n                    } else {\n                        recorded_account_diffs_stack.push(last_recorded_depth);\n                    }\n                }\n            }\n        }\n\n        // At the end of the call,\n        // we need to check if we've found all the emits.\n        // We know we've found all the expected emits in the right order\n        // if the queue is fully matched.\n        // If it's not fully matched, then either:\n        // 1. Not enough events were emitted (we'll know this because the amount of times we\n        // inspected events will be less than the size of the queue) 2. The wrong events\n        // were emitted (The inspected events should match the size of the queue, but still some\n        // events will not be matched)\n\n        // First, check that we're at the call depth where the emits were declared from.\n        let should_check_emits = self\n            .expected_emits\n            .iter()\n            .any(|(expected, _)| {\n                let curr_depth = ecx.journal().depth();\n                expected.depth == curr_depth\n            }) &&\n            // Ignore staticcalls\n            !call.is_static;\n        if should_check_emits {\n            let expected_counts = self\n                .expected_emits\n                .iter()\n                .filter_map(|(expected, count_map)| {\n                    let count = match expected.address {\n                        Some(emitter) => match count_map.get(&emitter) {\n                            Some(log_count) => expected\n                                .log\n                                .as_ref()\n                                .map(|l| log_count.count(l))\n                                .unwrap_or_else(|| log_count.count_unchecked()),\n                            None => 0,\n                        },\n                        None => match &expected.log {\n                            Some(log) => count_map.values().map(|logs| logs.count(log)).sum(),\n                            None => count_map.values().map(|logs| logs.count_unchecked()).sum(),\n                        },\n                    };\n\n                    if count != expected.count { Some((expected, count)) } else { None }\n                })\n                .collect::<Vec<_>>();\n\n            // Revert if not all emits expected were matched.\n            if let Some((expected, _)) = self\n                .expected_emits\n                .iter()\n                .find(|(expected, _)| !expected.found && expected.count > 0)\n            {\n                outcome.result.result = InstructionResult::Revert;\n                let error_msg = expected.mismatch_error.as_deref().unwrap_or(\"log != expected log\");\n                outcome.result.output = error_msg.abi_encode().into();\n                return;\n            }\n\n            if !expected_counts.is_empty() {\n                let msg = if outcome.result.is_ok() {\n                    let (expected, count) = expected_counts.first().unwrap();\n                    format!(\"log emitted {count} times, expected {}\", expected.count)\n                } else {\n                    \"expected an emit, but the call reverted instead. \\\n                     ensure you're testing the happy path when using `expectEmit`\"\n                        .to_string()\n                };\n\n                outcome.result.result = InstructionResult::Revert;\n                outcome.result.output = Error::encode(msg);\n                return;\n            }\n\n            // All emits were found, we're good.\n            // Clear the queue, as we expect the user to declare more events for the next call\n            // if they wanna match further events.\n            self.expected_emits.clear()\n        }\n\n        // this will ensure we don't have false positives when trying to diagnose reverts in fork\n        // mode\n        let diag = self.fork_revert_diagnostic.take();\n\n        // if there's a revert and a previous call was diagnosed as fork related revert then we can\n        // return a better error here\n        if outcome.result.is_revert()\n            && let Some(err) = diag\n        {\n            outcome.result.output = Error::encode(err.to_error_msg(&self.labels));\n            return;\n        }\n\n        // try to diagnose reverts in multi-fork mode where a call is made to an address that does\n        // not exist\n        if let TxKind::Call(test_contract) = ecx.tx().kind() {\n            // if a call to a different contract than the original test contract returned with\n            // `Stop` we check if the contract actually exists on the active fork\n            if ecx.db().is_forked_mode()\n                && outcome.result.result == InstructionResult::Stop\n                && call.target_address != test_contract\n            {\n                self.fork_revert_diagnostic =\n                    ecx.db().diagnose_revert(call.target_address, ecx.journal().evm_state());\n            }\n        }\n\n        // If the depth is 0, then this is the root call terminating\n        if ecx.journal().depth() == 0 {\n            // If we already have a revert, we shouldn't run the below logic as it can obfuscate an\n            // earlier error that happened first with unrelated information about\n            // another error when using cheatcodes.\n            if outcome.result.is_revert() {\n                return;\n            }\n\n            // If there's not a revert, we can continue on to run the last logic for expect*\n            // cheatcodes.\n\n            // Match expected calls\n            for (address, calldatas) in &self.expected_calls {\n                // Loop over each address, and for each address, loop over each calldata it expects.\n                for (calldata, (expected, actual_count)) in calldatas {\n                    // Grab the values we expect to see\n                    let ExpectedCallData { gas, min_gas, value, count, call_type } = expected;\n\n                    let failed = match call_type {\n                        // If the cheatcode was called with a `count` argument,\n                        // we must check that the EVM performed a CALL with this calldata exactly\n                        // `count` times.\n                        ExpectedCallType::Count => *count != *actual_count,\n                        // If the cheatcode was called without a `count` argument,\n                        // we must check that the EVM performed a CALL with this calldata at least\n                        // `count` times. The amount of times to check was\n                        // the amount of time the cheatcode was called.\n                        ExpectedCallType::NonCount => *count > *actual_count,\n                    };\n                    if failed {\n                        let expected_values = [\n                            Some(format!(\"data {}\", hex::encode_prefixed(calldata))),\n                            value.as_ref().map(|v| format!(\"value {v}\")),\n                            gas.map(|g| format!(\"gas {g}\")),\n                            min_gas.map(|g| format!(\"minimum gas {g}\")),\n                        ]\n                        .into_iter()\n                        .flatten()\n                        .join(\", \");\n                        let but = if outcome.result.is_ok() {\n                            let s = if *actual_count == 1 { \"\" } else { \"s\" };\n                            format!(\"was called {actual_count} time{s}\")\n                        } else {\n                            \"the call reverted instead; \\\n                             ensure you're testing the happy path when using `expectCall`\"\n                                .to_string()\n                        };\n                        let s = if *count == 1 { \"\" } else { \"s\" };\n                        let msg = format!(\n                            \"expected call to {address} with {expected_values} \\\n                             to be called {count} time{s}, but {but}\"\n                        );\n                        outcome.result.result = InstructionResult::Revert;\n                        outcome.result.output = Error::encode(msg);\n\n                        return;\n                    }\n                }\n            }\n\n            // Check if we have any leftover expected emits\n            // First, if any emits were found at the root call, then we its ok and we remove them.\n            // For count=0 expectations, NOT being found is success, so mark them as found\n            for (expected, _) in &mut self.expected_emits {\n                if expected.count == 0 && !expected.found {\n                    expected.found = true;\n                }\n            }\n            self.expected_emits.retain(|(expected, _)| !expected.found);\n            // If not empty, we got mismatched emits\n            if !self.expected_emits.is_empty() {\n                let msg = if outcome.result.is_ok() {\n                    \"expected an emit, but no logs were emitted afterwards. \\\n                     you might have mismatched events or not enough events were emitted\"\n                } else {\n                    \"expected an emit, but the call reverted instead. \\\n                     ensure you're testing the happy path when using `expectEmit`\"\n                };\n                outcome.result.result = InstructionResult::Revert;\n                outcome.result.output = Error::encode(msg);\n                return;\n            }\n\n            // Check for leftover expected creates\n            if let Some(expected_create) = self.expected_creates.first() {\n                let msg = format!(\n                    \"expected {} call by address {} for bytecode {} but not found\",\n                    expected_create.create_scheme,\n                    hex::encode_prefixed(expected_create.deployer),\n                    hex::encode_prefixed(&expected_create.bytecode),\n                );\n                outcome.result.result = InstructionResult::Revert;\n                outcome.result.output = Error::encode(msg);\n            }\n        }\n    }\n\n    fn create(&mut self, ecx: &mut CTX, mut input: &mut CreateInputs) -> Option<CreateOutcome> {\n        // Apply custom execution evm version.\n        if let Some(spec_id) = self.execution_evm_version {\n            ecx.cfg_mut().set_spec(spec_id);\n        }\n\n        let gas = Gas::new(input.gas_limit());\n        // Check if we should intercept this create\n        if self.intercept_next_create_call {\n            // Reset the flag\n            self.intercept_next_create_call = false;\n\n            // Get initcode from the input\n            let output = input.init_code();\n\n            // Return a revert with the initcode as error data\n            return Some(CreateOutcome {\n                result: InterpreterResult { result: InstructionResult::Revert, output, gas },\n                address: None,\n            });\n        }\n\n        let curr_depth = ecx.journal().depth();\n\n        // Apply our prank\n        if let Some(prank) = &self.get_prank(curr_depth)\n            && curr_depth >= prank.depth\n            && input.caller() == prank.prank_caller\n        {\n            let mut prank_applied = false;\n\n            // At the target depth we set `msg.sender`\n            if curr_depth == prank.depth {\n                // Ensure new caller is loaded and touched\n                let _ = journaled_account(ecx, prank.new_caller);\n                input.set_caller(prank.new_caller);\n                prank_applied = true;\n            }\n\n            // At the target depth, or deeper, we set `tx.origin`\n            if let Some(new_origin) = prank.new_origin {\n                ecx.tx_mut().set_caller(new_origin);\n                prank_applied = true;\n            }\n\n            // If prank applied for first time, then update\n            if prank_applied && let Some(applied_prank) = prank.first_time_applied() {\n                self.pranks.insert(curr_depth, applied_prank);\n            }\n        }\n\n        // Apply EIP-2930 access list\n        self.apply_accesslist(ecx);\n\n        // Apply our broadcast\n        if let Some(broadcast) = &mut self.broadcast\n            && curr_depth >= broadcast.depth\n            && input.caller() == broadcast.original_caller\n        {\n            if let Err(err) = ecx.journal_mut().load_account(broadcast.new_origin) {\n                return Some(CreateOutcome {\n                    result: InterpreterResult {\n                        result: InstructionResult::Revert,\n                        output: Error::encode(err),\n                        gas,\n                    },\n                    address: None,\n                });\n            }\n\n            ecx.tx_mut().set_caller(broadcast.new_origin);\n\n            if curr_depth == broadcast.depth || broadcast.deploy_from_code {\n                // Reset deploy from code flag for upcoming calls;\n                broadcast.deploy_from_code = false;\n\n                input.set_caller(broadcast.new_origin);\n\n                let rpc = ecx.db().active_fork_url();\n                let account = &ecx.journal().evm_state()[&broadcast.new_origin];\n                self.broadcastable_transactions.push_back(BroadcastableTransaction {\n                    rpc,\n                    from: broadcast.new_origin,\n                    to: None,\n                    value: input.value(),\n                    input: input.init_code(),\n                    nonce: account.info.nonce,\n                    gas: None,\n                    kind: BroadcastKind::unsigned(),\n                });\n\n                input.log_debug(self, &input.scheme().unwrap_or(CreateScheme::Create));\n            }\n        }\n\n        // Allow cheatcodes from the address of the new contract\n        let address = input.allow_cheatcodes(self, ecx);\n\n        // If `recordAccountAccesses` has been called, record the create\n        if let Some(recorded_account_diffs_stack) = &mut self.recorded_account_diffs_stack {\n            recorded_account_diffs_stack.push(vec![AccountAccess {\n                chainInfo: crate::Vm::ChainInfo {\n                    forkId: ecx.db().active_fork_id().unwrap_or_default(),\n                    chainId: U256::from(ecx.cfg().chain_id()),\n                },\n                accessor: input.caller(),\n                account: address,\n                kind: crate::Vm::AccountAccessKind::Create,\n                initialized: true,\n                oldBalance: U256::ZERO, // updated on create_end\n                newBalance: U256::ZERO, // updated on create_end\n                oldNonce: 0,            // new contract starts with nonce 0\n                newNonce: 1,            // updated on create_end (contracts start with nonce 1)\n                value: input.value(),\n                data: input.init_code(),\n                reverted: false,\n                deployedCode: Bytes::new(), // updated on create_end\n                storageAccesses: vec![],    // updated on create_end\n                depth: curr_depth as u64,\n            }]);\n        }\n\n        None\n    }\n\n    fn create_end(&mut self, ecx: &mut CTX, call: &CreateInputs, outcome: &mut CreateOutcome) {\n        let call = Some(call);\n        let curr_depth = ecx.journal().depth();\n\n        // Clean up pranks\n        if let Some(prank) = &self.get_prank(curr_depth)\n            && curr_depth == prank.depth\n        {\n            ecx.tx_mut().set_caller(prank.prank_origin);\n\n            // Clean single-call prank once we have returned to the original depth\n            if prank.single_call {\n                std::mem::take(&mut self.pranks);\n            }\n        }\n\n        // Clean up broadcasts\n        if let Some(broadcast) = &self.broadcast\n            && curr_depth == broadcast.depth\n        {\n            ecx.tx_mut().set_caller(broadcast.original_origin);\n\n            // Clean single-call broadcast once we have returned to the original depth\n            if broadcast.single_call {\n                std::mem::take(&mut self.broadcast);\n            }\n        }\n\n        // Handle expected reverts\n        if let Some(expected_revert) = &self.expected_revert\n            && curr_depth <= expected_revert.depth\n            && matches!(expected_revert.kind, ExpectedRevertKind::Default)\n        {\n            let mut expected_revert = std::mem::take(&mut self.expected_revert).unwrap();\n            return match revert_handlers::handle_expect_revert(\n                false,\n                true,\n                self.config.internal_expect_revert,\n                &expected_revert,\n                outcome.result.result,\n                outcome.result.output.clone(),\n                &self.config.available_artifacts,\n            ) {\n                Ok((address, retdata)) => {\n                    expected_revert.actual_count += 1;\n                    if expected_revert.actual_count < expected_revert.count {\n                        self.expected_revert = Some(expected_revert.clone());\n                    }\n\n                    outcome.result.result = InstructionResult::Return;\n                    outcome.result.output = retdata;\n                    outcome.address = address;\n                }\n                Err(err) => {\n                    outcome.result.result = InstructionResult::Revert;\n                    outcome.result.output = err.abi_encode().into();\n                }\n            };\n        }\n\n        // If `startStateDiffRecording` has been called, update the `reverted` status of the\n        // previous call depth's recorded accesses, if any\n        if let Some(recorded_account_diffs_stack) = &mut self.recorded_account_diffs_stack {\n            // The root call cannot be recorded.\n            if curr_depth > 0\n                && let Some(last_depth) = &mut recorded_account_diffs_stack.pop()\n            {\n                // Update the reverted status of all deeper calls if this call reverted, in\n                // accordance with EVM behavior\n                if outcome.result.is_revert() {\n                    last_depth.iter_mut().for_each(|element| {\n                        element.reverted = true;\n                        element\n                            .storageAccesses\n                            .iter_mut()\n                            .for_each(|storage_access| storage_access.reverted = true);\n                    })\n                }\n\n                if let Some(create_access) = last_depth.first_mut() {\n                    // Assert that we're at the correct depth before recording post-create state\n                    // changes. Depending on what depth the cheat was called at, there\n                    // may not be any pending calls to update if execution has\n                    // percolated up to a higher depth.\n                    let depth = ecx.journal().depth();\n                    if create_access.depth == depth as u64 {\n                        debug_assert_eq!(\n                            create_access.kind as u8,\n                            crate::Vm::AccountAccessKind::Create as u8\n                        );\n                        if let Some(address) = outcome.address\n                            && let Ok(created_acc) = ecx.journal_mut().load_account(address)\n                        {\n                            create_access.newBalance = created_acc.data.info.balance;\n                            create_access.newNonce = created_acc.data.info.nonce;\n                            create_access.deployedCode = created_acc\n                                .data\n                                .info\n                                .code\n                                .clone()\n                                .unwrap_or_default()\n                                .original_bytes();\n                        }\n                    }\n                    // Merge the last depth's AccountAccesses into the AccountAccesses at the\n                    // current depth, or push them back onto the pending\n                    // vector if higher depths were not recorded. This\n                    // preserves ordering of accesses.\n                    if let Some(last) = recorded_account_diffs_stack.last_mut() {\n                        last.append(last_depth);\n                    } else {\n                        recorded_account_diffs_stack.push(last_depth.clone());\n                    }\n                }\n            }\n        }\n\n        // Match the create against expected_creates\n        if !self.expected_creates.is_empty()\n            && let (Some(address), Some(call)) = (outcome.address, call)\n            && let Ok(created_acc) = ecx.journal_mut().load_account(address)\n        {\n            let bytecode = created_acc.data.info.code.clone().unwrap_or_default().original_bytes();\n            if let Some((index, _)) =\n                self.expected_creates.iter().find_position(|expected_create| {\n                    expected_create.deployer == call.caller()\n                        && expected_create.create_scheme.eq(call.scheme().into())\n                        && expected_create.bytecode == bytecode\n                })\n            {\n                self.expected_creates.swap_remove(index);\n            }\n        }\n    }\n}\n\nimpl FoundryInspectorExt for Cheatcodes {\n    fn should_use_create2_factory(&mut self, depth: usize, inputs: &CreateInputs) -> bool {\n        if let CreateScheme::Create2 { .. } = inputs.scheme() {\n            let target_depth = if let Some(prank) = &self.get_prank(depth) {\n                prank.depth\n            } else if let Some(broadcast) = &self.broadcast {\n                broadcast.depth\n            } else {\n                1\n            };\n\n            depth == target_depth\n                && (self.broadcast.is_some() || self.config.always_use_create_2_factory)\n        } else {\n            false\n        }\n    }\n\n    fn create2_deployer(&self) -> Address {\n        self.config.evm_opts.create2_deployer\n    }\n}\n\nimpl Cheatcodes {\n    #[cold]\n    fn meter_gas(&mut self, interpreter: &mut Interpreter) {\n        if let Some(paused_gas) = self.gas_metering.paused_frames.last() {\n            // Keep gas constant if paused.\n            // Make sure we record the memory changes so that memory expansion is not paused.\n            let memory = *interpreter.gas.memory();\n            interpreter.gas = *paused_gas;\n            interpreter.gas.memory_mut().words_num = memory.words_num;\n            interpreter.gas.memory_mut().expansion_cost = memory.expansion_cost;\n        } else {\n            // Record frame paused gas.\n            self.gas_metering.paused_frames.push(interpreter.gas);\n        }\n    }\n\n    #[cold]\n    fn meter_gas_record<CTX: ContextTr>(&mut self, interpreter: &mut Interpreter, ecx: &mut CTX) {\n        if interpreter.bytecode.action.as_ref().and_then(|i| i.instruction_result()).is_none() {\n            self.gas_metering.gas_records.iter_mut().for_each(|record| {\n                let curr_depth = ecx.journal().depth();\n                if curr_depth == record.depth {\n                    // Skip the first opcode of the first call frame as it includes the gas cost of\n                    // creating the snapshot.\n                    if self.gas_metering.last_gas_used != 0 {\n                        let gas_diff =\n                            interpreter.gas.spent().saturating_sub(self.gas_metering.last_gas_used);\n                        record.gas_used = record.gas_used.saturating_add(gas_diff);\n                    }\n\n                    // Update `last_gas_used` to the current spent gas for the next iteration to\n                    // compare against.\n                    self.gas_metering.last_gas_used = interpreter.gas.spent();\n                }\n            });\n        }\n    }\n\n    #[cold]\n    fn meter_gas_end(&mut self, interpreter: &mut Interpreter) {\n        // Remove recorded gas if we exit frame.\n        if let Some(interpreter_action) = interpreter.bytecode.action.as_ref()\n            && will_exit(interpreter_action)\n        {\n            self.gas_metering.paused_frames.pop();\n        }\n    }\n\n    #[cold]\n    fn meter_gas_reset(&mut self, interpreter: &mut Interpreter) {\n        let mut gas = Gas::new(interpreter.gas.limit());\n        gas.memory_mut().words_num = interpreter.gas.memory().words_num;\n        gas.memory_mut().expansion_cost = interpreter.gas.memory().expansion_cost;\n        interpreter.gas = gas;\n        self.gas_metering.reset = false;\n    }\n\n    #[cold]\n    fn meter_gas_check(&mut self, interpreter: &mut Interpreter) {\n        if let Some(interpreter_action) = interpreter.bytecode.action.as_ref()\n            && will_exit(interpreter_action)\n        {\n            // Reset gas if spent is less than refunded.\n            // This can happen if gas was paused / resumed or reset.\n            // https://github.com/foundry-rs/foundry/issues/4370\n            if interpreter.gas.spent()\n                < u64::try_from(interpreter.gas.refunded()).unwrap_or_default()\n            {\n                interpreter.gas = Gas::new(interpreter.gas.limit());\n            }\n        }\n    }\n\n    /// Generates or copies arbitrary values for storage slots.\n    /// Invoked in inspector `step_end` (when the current opcode is not executed), if current opcode\n    /// to execute is `SLOAD` and storage slot is cold.\n    /// Ensures that in next step (when `SLOAD` opcode is executed) an arbitrary value is returned:\n    /// - copies the existing arbitrary storage value (or the new generated one if no value in\n    ///   cache) from mapped source address to the target address.\n    /// - generates arbitrary value and saves it in target address storage.\n    #[cold]\n    fn arbitrary_storage_end<CTX: ContextTr>(\n        &mut self,\n        interpreter: &mut Interpreter,\n        ecx: &mut CTX,\n    ) {\n        let (key, target_address) = if interpreter.bytecode.opcode() == op::SLOAD {\n            (try_or_return!(interpreter.stack.peek(0)), interpreter.input.target_address)\n        } else {\n            return;\n        };\n\n        let Some(value) = ecx.sload(target_address, key) else {\n            return;\n        };\n\n        if (value.is_cold && value.data.is_zero())\n            || self.should_overwrite_arbitrary_storage(&target_address, key)\n        {\n            if self.has_arbitrary_storage(&target_address) {\n                let arbitrary_value = self.rng().random();\n                self.arbitrary_storage.as_mut().unwrap().save(\n                    ecx,\n                    target_address,\n                    key,\n                    arbitrary_value,\n                );\n            } else if self.is_arbitrary_storage_copy(&target_address) {\n                let arbitrary_value = self.rng().random();\n                self.arbitrary_storage.as_mut().unwrap().copy(\n                    ecx,\n                    target_address,\n                    key,\n                    arbitrary_value,\n                );\n            }\n        }\n    }\n\n    /// Records storage slots reads and writes.\n    #[cold]\n    fn record_accesses(&mut self, interpreter: &mut Interpreter) {\n        let access = &mut self.accesses;\n        match interpreter.bytecode.opcode() {\n            op::SLOAD => {\n                let key = try_or_return!(interpreter.stack.peek(0));\n                access.record_read(interpreter.input.target_address, key);\n            }\n            op::SSTORE => {\n                let key = try_or_return!(interpreter.stack.peek(0));\n                access.record_write(interpreter.input.target_address, key);\n            }\n            _ => {}\n        }\n    }\n\n    #[cold]\n    fn record_state_diffs<CTX: ContextTr<Db: DatabaseExt>>(\n        &mut self,\n        interpreter: &mut Interpreter,\n        ecx: &mut CTX,\n    ) {\n        let Some(account_accesses) = &mut self.recorded_account_diffs_stack else { return };\n        match interpreter.bytecode.opcode() {\n            op::SELFDESTRUCT => {\n                // Ensure that we're not selfdestructing a context recording was initiated on\n                let Some(last) = account_accesses.last_mut() else { return };\n\n                // get previous balance, nonce and initialized status of the target account\n                let target = try_or_return!(interpreter.stack.peek(0));\n                let target = Address::from_word(B256::from(target));\n                let (initialized, old_balance, old_nonce) = ecx\n                    .journal_mut()\n                    .load_account(target)\n                    .map(|account| {\n                        (\n                            account.data.info.exists(),\n                            account.data.info.balance,\n                            account.data.info.nonce,\n                        )\n                    })\n                    .unwrap_or_default();\n\n                // load balance of this account\n                let value = ecx\n                    .balance(interpreter.input.target_address)\n                    .map(|b| b.data)\n                    .unwrap_or(U256::ZERO);\n\n                // register access for the target account\n                last.push(crate::Vm::AccountAccess {\n                    chainInfo: crate::Vm::ChainInfo {\n                        forkId: ecx.db().active_fork_id().unwrap_or_default(),\n                        chainId: U256::from(ecx.cfg().chain_id()),\n                    },\n                    accessor: interpreter.input.target_address,\n                    account: target,\n                    kind: crate::Vm::AccountAccessKind::SelfDestruct,\n                    initialized,\n                    oldBalance: old_balance,\n                    newBalance: old_balance + value,\n                    oldNonce: old_nonce,\n                    newNonce: old_nonce, // nonce doesn't change on selfdestruct\n                    value,\n                    data: Bytes::new(),\n                    reverted: false,\n                    deployedCode: Bytes::new(),\n                    storageAccesses: vec![],\n                    depth: ecx\n                        .journal()\n                        .depth()\n                        .try_into()\n                        .expect(\"journaled state depth exceeds u64\"),\n                });\n            }\n\n            op::SLOAD => {\n                let Some(last) = account_accesses.last_mut() else { return };\n\n                let key = try_or_return!(interpreter.stack.peek(0));\n                let address = interpreter.input.target_address;\n\n                // Try to include present value for informational purposes, otherwise assume\n                // it's not set (zero value)\n                let mut present_value = U256::ZERO;\n                // Try to load the account and the slot's present value\n                if ecx.journal_mut().load_account(address).is_ok()\n                    && let Some(previous) = ecx.sload(address, key)\n                {\n                    present_value = previous.data;\n                }\n                let access = crate::Vm::StorageAccess {\n                    account: interpreter.input.target_address,\n                    slot: key.into(),\n                    isWrite: false,\n                    previousValue: present_value.into(),\n                    newValue: present_value.into(),\n                    reverted: false,\n                };\n                let curr_depth =\n                    ecx.journal().depth().try_into().expect(\"journaled state depth exceeds u64\");\n                append_storage_access(last, access, curr_depth);\n            }\n            op::SSTORE => {\n                let Some(last) = account_accesses.last_mut() else { return };\n\n                let key = try_or_return!(interpreter.stack.peek(0));\n                let value = try_or_return!(interpreter.stack.peek(1));\n                let address = interpreter.input.target_address;\n                // Try to load the account and the slot's previous value, otherwise, assume it's\n                // not set (zero value)\n                let mut previous_value = U256::ZERO;\n                if ecx.journal_mut().load_account(address).is_ok()\n                    && let Some(previous) = ecx.sload(address, key)\n                {\n                    previous_value = previous.data;\n                }\n\n                let access = crate::Vm::StorageAccess {\n                    account: address,\n                    slot: key.into(),\n                    isWrite: true,\n                    previousValue: previous_value.into(),\n                    newValue: value.into(),\n                    reverted: false,\n                };\n                let curr_depth =\n                    ecx.journal().depth().try_into().expect(\"journaled state depth exceeds u64\");\n                append_storage_access(last, access, curr_depth);\n            }\n\n            // Record account accesses via the EXT family of opcodes\n            op::EXTCODECOPY | op::EXTCODESIZE | op::EXTCODEHASH | op::BALANCE => {\n                let kind = match interpreter.bytecode.opcode() {\n                    op::EXTCODECOPY => crate::Vm::AccountAccessKind::Extcodecopy,\n                    op::EXTCODESIZE => crate::Vm::AccountAccessKind::Extcodesize,\n                    op::EXTCODEHASH => crate::Vm::AccountAccessKind::Extcodehash,\n                    op::BALANCE => crate::Vm::AccountAccessKind::Balance,\n                    _ => unreachable!(),\n                };\n                let address =\n                    Address::from_word(B256::from(try_or_return!(interpreter.stack.peek(0))));\n                let initialized;\n                let balance;\n                let nonce;\n                if let Ok(acc) = ecx.journal_mut().load_account(address) {\n                    initialized = acc.data.info.exists();\n                    balance = acc.data.info.balance;\n                    nonce = acc.data.info.nonce;\n                } else {\n                    initialized = false;\n                    balance = U256::ZERO;\n                    nonce = 0;\n                }\n                let curr_depth =\n                    ecx.journal().depth().try_into().expect(\"journaled state depth exceeds u64\");\n                let account_access = crate::Vm::AccountAccess {\n                    chainInfo: crate::Vm::ChainInfo {\n                        forkId: ecx.db().active_fork_id().unwrap_or_default(),\n                        chainId: U256::from(ecx.cfg().chain_id()),\n                    },\n                    accessor: interpreter.input.target_address,\n                    account: address,\n                    kind,\n                    initialized,\n                    oldBalance: balance,\n                    newBalance: balance,\n                    oldNonce: nonce,\n                    newNonce: nonce, // EXT* operations don't change nonce\n                    value: U256::ZERO,\n                    data: Bytes::new(),\n                    reverted: false,\n                    deployedCode: Bytes::new(),\n                    storageAccesses: vec![],\n                    depth: curr_depth,\n                };\n                // Record the EXT* call as an account access at the current depth\n                // (future storage accesses will be recorded in a new \"Resume\" context)\n                if let Some(last) = account_accesses.last_mut() {\n                    last.push(account_access);\n                } else {\n                    account_accesses.push(vec![account_access]);\n                }\n            }\n            _ => {}\n        }\n    }\n\n    /// Checks to see if the current opcode can either mutate directly or expand memory.\n    ///\n    /// If the opcode at the current program counter is a match, check if the modified memory lies\n    /// within the allowed ranges. If not, revert and fail the test.\n    #[cold]\n    fn check_mem_opcodes(&self, interpreter: &mut Interpreter, depth: u64) {\n        let Some(ranges) = self.allowed_mem_writes.get(&depth) else {\n            return;\n        };\n\n        // The `mem_opcode_match` macro is used to match the current opcode against a list of\n        // opcodes that can mutate memory (either directly or expansion via reading). If the\n        // opcode is a match, the memory offsets that are being written to are checked to be\n        // within the allowed ranges. If not, the test is failed and the transaction is\n        // reverted. For all opcodes that can mutate memory aside from MSTORE,\n        // MSTORE8, and MLOAD, the size and destination offset are on the stack, and\n        // the macro expands all of these cases. For MSTORE, MSTORE8, and MLOAD, the\n        // size of the memory write is implicit, so these cases are hard-coded.\n        macro_rules! mem_opcode_match {\n            ($(($opcode:ident, $offset_depth:expr, $size_depth:expr, $writes:expr)),* $(,)?) => {\n                match interpreter.bytecode.opcode() {\n                    ////////////////////////////////////////////////////////////////\n                    //    OPERATIONS THAT CAN EXPAND/MUTATE MEMORY BY WRITING     //\n                    ////////////////////////////////////////////////////////////////\n\n                    op::MSTORE => {\n                        // The offset of the mstore operation is at the top of the stack.\n                        let offset = try_or_return!(interpreter.stack.peek(0)).saturating_to::<u64>();\n\n                        // If none of the allowed ranges contain [offset, offset + 32), memory has been\n                        // unexpectedly mutated.\n                        if !ranges.iter().any(|range| {\n                            range.contains(&offset) && range.contains(&(offset + 31))\n                        }) {\n                            // SPECIAL CASE: When the compiler attempts to store the selector for\n                            // `stopExpectSafeMemory`, this is allowed. It will do so at the current free memory\n                            // pointer, which could have been updated to the exclusive upper bound during\n                            // execution.\n                            let value = try_or_return!(interpreter.stack.peek(1)).to_be_bytes::<32>();\n                            if value[..SELECTOR_LEN] == stopExpectSafeMemoryCall::SELECTOR {\n                                return\n                            }\n\n                            disallowed_mem_write(offset, 32, interpreter, ranges);\n                            return\n                        }\n                    }\n                    op::MSTORE8 => {\n                        // The offset of the mstore8 operation is at the top of the stack.\n                        let offset = try_or_return!(interpreter.stack.peek(0)).saturating_to::<u64>();\n\n                        // If none of the allowed ranges contain the offset, memory has been\n                        // unexpectedly mutated.\n                        if !ranges.iter().any(|range| range.contains(&offset)) {\n                            disallowed_mem_write(offset, 1, interpreter, ranges);\n                            return\n                        }\n                    }\n\n                    ////////////////////////////////////////////////////////////////\n                    //        OPERATIONS THAT CAN EXPAND MEMORY BY READING        //\n                    ////////////////////////////////////////////////////////////////\n\n                    op::MLOAD => {\n                        // The offset of the mload operation is at the top of the stack\n                        let offset = try_or_return!(interpreter.stack.peek(0)).saturating_to::<u64>();\n\n                        // If the offset being loaded is >= than the memory size, the\n                        // memory is being expanded. If none of the allowed ranges contain\n                        // [offset, offset + 32), memory has been unexpectedly mutated.\n                        if offset >= interpreter.memory.size() as u64 && !ranges.iter().any(|range| {\n                            range.contains(&offset) && range.contains(&(offset + 31))\n                        }) {\n                            disallowed_mem_write(offset, 32, interpreter, ranges);\n                            return\n                        }\n                    }\n\n                    ////////////////////////////////////////////////////////////////\n                    //          OPERATIONS WITH OFFSET AND SIZE ON STACK          //\n                    ////////////////////////////////////////////////////////////////\n\n                    op::CALL => {\n                        // The destination offset of the operation is the fifth element on the stack.\n                        let dest_offset = try_or_return!(interpreter.stack.peek(5)).saturating_to::<u64>();\n\n                        // The size of the data that will be copied is the sixth element on the stack.\n                        let size = try_or_return!(interpreter.stack.peek(6)).saturating_to::<u64>();\n\n                        // If none of the allowed ranges contain [dest_offset, dest_offset + size),\n                        // memory outside of the expected ranges has been touched. If the opcode\n                        // only reads from memory, this is okay as long as the memory is not expanded.\n                        let fail_cond = !ranges.iter().any(|range| {\n                            range.contains(&dest_offset) &&\n                                range.contains(&(dest_offset + size.saturating_sub(1)))\n                        });\n\n                        // If the failure condition is met, set the output buffer to a revert string\n                        // that gives information about the allowed ranges and revert.\n                        if fail_cond {\n                            // SPECIAL CASE: When a call to `stopExpectSafeMemory` is performed, this is allowed.\n                            // It allocated calldata at the current free memory pointer, and will attempt to read\n                            // from this memory region to perform the call.\n                            let to = Address::from_word(try_or_return!(interpreter.stack.peek(1)).to_be_bytes::<32>().into());\n                            if to == CHEATCODE_ADDRESS {\n                                let args_offset = try_or_return!(interpreter.stack.peek(3)).saturating_to::<usize>();\n                                let args_size = try_or_return!(interpreter.stack.peek(4)).saturating_to::<usize>();\n                                let memory_word = interpreter.memory.slice_len(args_offset, args_size);\n                                if memory_word[..SELECTOR_LEN] == stopExpectSafeMemoryCall::SELECTOR {\n                                    return\n                                }\n                            }\n\n                            disallowed_mem_write(dest_offset, size, interpreter, ranges);\n                            return\n                        }\n                    }\n\n                    $(op::$opcode => {\n                        // The destination offset of the operation.\n                        let dest_offset = try_or_return!(interpreter.stack.peek($offset_depth)).saturating_to::<u64>();\n\n                        // The size of the data that will be copied.\n                        let size = try_or_return!(interpreter.stack.peek($size_depth)).saturating_to::<u64>();\n\n                        // If none of the allowed ranges contain [dest_offset, dest_offset + size),\n                        // memory outside of the expected ranges has been touched. If the opcode\n                        // only reads from memory, this is okay as long as the memory is not expanded.\n                        let fail_cond = !ranges.iter().any(|range| {\n                                range.contains(&dest_offset) &&\n                                    range.contains(&(dest_offset + size.saturating_sub(1)))\n                            }) && ($writes ||\n                                [dest_offset, (dest_offset + size).saturating_sub(1)].into_iter().any(|offset| {\n                                    offset >= interpreter.memory.size() as u64\n                                })\n                            );\n\n                        // If the failure condition is met, set the output buffer to a revert string\n                        // that gives information about the allowed ranges and revert.\n                        if fail_cond {\n                            disallowed_mem_write(dest_offset, size, interpreter, ranges);\n                            return\n                        }\n                    })*\n\n                    _ => {}\n                }\n            }\n        }\n\n        // Check if the current opcode can write to memory, and if so, check if the memory\n        // being written to is registered as safe to modify.\n        mem_opcode_match!(\n            (CALLDATACOPY, 0, 2, true),\n            (CODECOPY, 0, 2, true),\n            (RETURNDATACOPY, 0, 2, true),\n            (EXTCODECOPY, 1, 3, true),\n            (CALLCODE, 5, 6, true),\n            (STATICCALL, 4, 5, true),\n            (DELEGATECALL, 4, 5, true),\n            (KECCAK256, 0, 1, false),\n            (LOG0, 0, 1, false),\n            (LOG1, 0, 1, false),\n            (LOG2, 0, 1, false),\n            (LOG3, 0, 1, false),\n            (LOG4, 0, 1, false),\n            (CREATE, 1, 2, false),\n            (CREATE2, 1, 2, false),\n            (RETURN, 0, 1, false),\n            (REVERT, 0, 1, false),\n        );\n    }\n\n    #[cold]\n    fn set_gas_limit_type(&mut self, interpreter: &mut Interpreter) {\n        match interpreter.bytecode.opcode() {\n            op::CREATE2 => self.dynamic_gas_limit = true,\n            op::CALL => {\n                // If first element of the stack is close to current remaining gas then assume\n                // dynamic gas limit.\n                self.dynamic_gas_limit =\n                    try_or_return!(interpreter.stack.peek(0)) >= interpreter.gas.remaining() - 100\n            }\n            _ => self.dynamic_gas_limit = false,\n        }\n    }\n}\n\n/// Helper that expands memory, stores a revert string pertaining to a disallowed memory write,\n/// and sets the return range to the revert string's location in memory.\n///\n/// This will set the interpreter's next action to a return with the revert string as the output.\n/// And trigger a revert.\nfn disallowed_mem_write(\n    dest_offset: u64,\n    size: u64,\n    interpreter: &mut Interpreter,\n    ranges: &[Range<u64>],\n) {\n    let revert_string = format!(\n        \"memory write at offset 0x{:02X} of size 0x{:02X} not allowed; safe range: {}\",\n        dest_offset,\n        size,\n        ranges.iter().map(|r| format!(\"(0x{:02X}, 0x{:02X}]\", r.start, r.end)).join(\" U \")\n    );\n\n    interpreter.bytecode.set_action(InterpreterAction::new_return(\n        InstructionResult::Revert,\n        Bytes::from(revert_string.into_bytes()),\n        interpreter.gas,\n    ));\n}\n\n/// Returns true if the kind of account access is a call.\nfn access_is_call(kind: crate::Vm::AccountAccessKind) -> bool {\n    matches!(\n        kind,\n        crate::Vm::AccountAccessKind::Call\n            | crate::Vm::AccountAccessKind::StaticCall\n            | crate::Vm::AccountAccessKind::CallCode\n            | crate::Vm::AccountAccessKind::DelegateCall\n    )\n}\n\n/// Records a log into the recorded logs vector, if it exists.\nfn record_logs(recorded_logs: &mut Option<Vec<Vm::Log>>, log: &Log) {\n    if let Some(storage_recorded_logs) = recorded_logs {\n        storage_recorded_logs.push(Vm::Log {\n            topics: log.data.topics().to_vec(),\n            data: log.data.data.clone(),\n            emitter: log.address,\n        });\n    }\n}\n\n/// Appends an AccountAccess that resumes the recording of the current context.\nfn append_storage_access(\n    last: &mut Vec<AccountAccess>,\n    storage_access: crate::Vm::StorageAccess,\n    storage_depth: u64,\n) {\n    // Assert that there's an existing record for the current context.\n    if !last.is_empty() && last.first().unwrap().depth < storage_depth {\n        // Three cases to consider:\n        // 1. If there hasn't been a context switch since the start of this context, then add the\n        //    storage access to the current context record.\n        // 2. If there's an existing Resume record, then add the storage access to it.\n        // 3. Otherwise, create a new Resume record based on the current context.\n        if last.len() == 1 {\n            last.first_mut().unwrap().storageAccesses.push(storage_access);\n        } else {\n            let last_record = last.last_mut().unwrap();\n            if last_record.kind as u8 == crate::Vm::AccountAccessKind::Resume as u8 {\n                last_record.storageAccesses.push(storage_access);\n            } else {\n                let entry = last.first().unwrap();\n                let resume_record = crate::Vm::AccountAccess {\n                    chainInfo: crate::Vm::ChainInfo {\n                        forkId: entry.chainInfo.forkId,\n                        chainId: entry.chainInfo.chainId,\n                    },\n                    accessor: entry.accessor,\n                    account: entry.account,\n                    kind: crate::Vm::AccountAccessKind::Resume,\n                    initialized: entry.initialized,\n                    storageAccesses: vec![storage_access],\n                    reverted: entry.reverted,\n                    // The remaining fields are defaults\n                    oldBalance: U256::ZERO,\n                    newBalance: U256::ZERO,\n                    oldNonce: 0,\n                    newNonce: 0,\n                    value: U256::ZERO,\n                    data: Bytes::new(),\n                    deployedCode: Bytes::new(),\n                    depth: entry.depth,\n                };\n                last.push(resume_record);\n            }\n        }\n    }\n}\n\n/// Returns the [`spec::Cheatcode`] definition for a given [`spec::CheatcodeDef`] implementor.\nfn cheatcode_of<T: spec::CheatcodeDef>(_: &T) -> &'static spec::Cheatcode<'static> {\n    T::CHEATCODE\n}\n\nfn cheatcode_name(cheat: &spec::Cheatcode<'static>) -> &'static str {\n    cheat.func.signature.split('(').next().unwrap()\n}\n\nfn cheatcode_id(cheat: &spec::Cheatcode<'static>) -> &'static str {\n    cheat.func.id\n}\n\nfn cheatcode_signature(cheat: &spec::Cheatcode<'static>) -> &'static str {\n    cheat.func.signature\n}\n\n/// Dispatches the cheatcode call to the appropriate function.\nfn apply_dispatch<CTX: EthCheatCtx>(\n    calls: &Vm::VmCalls,\n    ccx: &mut CheatsCtxt<'_, CTX>,\n    executor: &mut dyn CheatcodesExecutor<CTX>,\n) -> Result {\n    // Extract metadata for logging/deprecation via CheatcodeDef.\n    macro_rules! get_cheatcode {\n        ($($variant:ident),*) => {\n            match calls {\n                $(Vm::VmCalls::$variant(cheat) => cheatcode_of(cheat),)*\n            }\n        };\n    }\n    let cheat = vm_calls!(get_cheatcode);\n\n    let _guard = debug_span!(target: \"cheatcodes\", \"apply\", id = %cheatcode_id(cheat)).entered();\n    trace!(target: \"cheatcodes\", cheat = %cheatcode_signature(cheat), \"applying\");\n\n    if let spec::Status::Deprecated(replacement) = cheat.status {\n        ccx.state.deprecated.insert(cheatcode_signature(cheat), replacement);\n    }\n\n    // Monomorphized dispatch: calls apply_full directly, no trait objects.\n    macro_rules! dispatch {\n        ($($variant:ident),*) => {\n            match calls {\n                $(Vm::VmCalls::$variant(cheat) => Cheatcode::apply_full(cheat, ccx, executor),)*\n            }\n        };\n    }\n    let mut result = vm_calls!(dispatch);\n\n    // Format the error message to include the cheatcode name.\n    if let Err(e) = &mut result\n        && e.is_str()\n    {\n        let name = cheatcode_name(cheat);\n        // Skip showing the cheatcode name for:\n        // - assertions: too verbose, and can already be inferred from the error message\n        // - `rpcUrl`: forge-std relies on it in `getChainWithUpdatedRpcUrl`\n        if !name.contains(\"assert\") && name != \"rpcUrl\" {\n            *e = fmt_err!(\"vm.{name}: {e}\");\n        }\n    }\n\n    trace!(\n        target: \"cheatcodes\",\n        return = %match &result {\n            Ok(b) => hex::encode(b),\n            Err(e) => e.to_string(),\n        }\n    );\n\n    result\n}\n\n/// Helper function to check if frame execution will exit.\nfn will_exit(action: &InterpreterAction) -> bool {\n    match action {\n        InterpreterAction::Return(result) => {\n            result.result.is_ok_or_revert() || result.result.is_error()\n        }\n        _ => false,\n    }\n}\n"
  },
  {
    "path": "crates/cheatcodes/src/json.rs",
    "content": "//! Implementations of [`Json`](spec::Group::Json) cheatcodes.\n\nuse crate::{Cheatcode, Cheatcodes, Result, Vm::*, string};\nuse alloy_dyn_abi::{DynSolType, DynSolValue, Resolver, eip712_parser::EncodeType};\nuse alloy_primitives::{Address, B256, I256, U256, hex};\nuse alloy_sol_types::SolValue;\nuse foundry_common::{fmt::StructDefinitions, fs};\nuse foundry_config::fs_permissions::FsAccessKind;\nuse serde_json::{Map, Value};\nuse std::{\n    borrow::Cow,\n    collections::{BTreeMap, BTreeSet},\n};\n\nimpl Cheatcode for keyExistsCall {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { json, key } = self;\n        check_json_key_exists(json, key)\n    }\n}\n\nimpl Cheatcode for keyExistsJsonCall {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { json, key } = self;\n        check_json_key_exists(json, key)\n    }\n}\n\nimpl Cheatcode for parseJson_0Call {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { json } = self;\n        parse_json(json, \"$\", state.struct_defs())\n    }\n}\n\nimpl Cheatcode for parseJson_1Call {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { json, key } = self;\n        parse_json(json, key, state.struct_defs())\n    }\n}\n\nimpl Cheatcode for parseJsonUintCall {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { json, key } = self;\n        parse_json_coerce(json, key, &DynSolType::Uint(256))\n    }\n}\n\nimpl Cheatcode for parseJsonUintArrayCall {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { json, key } = self;\n        parse_json_coerce(json, key, &DynSolType::Array(Box::new(DynSolType::Uint(256))))\n    }\n}\n\nimpl Cheatcode for parseJsonIntCall {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { json, key } = self;\n        parse_json_coerce(json, key, &DynSolType::Int(256))\n    }\n}\n\nimpl Cheatcode for parseJsonIntArrayCall {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { json, key } = self;\n        parse_json_coerce(json, key, &DynSolType::Array(Box::new(DynSolType::Int(256))))\n    }\n}\n\nimpl Cheatcode for parseJsonBoolCall {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { json, key } = self;\n        parse_json_coerce(json, key, &DynSolType::Bool)\n    }\n}\n\nimpl Cheatcode for parseJsonBoolArrayCall {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { json, key } = self;\n        parse_json_coerce(json, key, &DynSolType::Array(Box::new(DynSolType::Bool)))\n    }\n}\n\nimpl Cheatcode for parseJsonAddressCall {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { json, key } = self;\n        parse_json_coerce(json, key, &DynSolType::Address)\n    }\n}\n\nimpl Cheatcode for parseJsonAddressArrayCall {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { json, key } = self;\n        parse_json_coerce(json, key, &DynSolType::Array(Box::new(DynSolType::Address)))\n    }\n}\n\nimpl Cheatcode for parseJsonStringCall {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { json, key } = self;\n        parse_json_coerce(json, key, &DynSolType::String)\n    }\n}\n\nimpl Cheatcode for parseJsonStringArrayCall {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { json, key } = self;\n        parse_json_coerce(json, key, &DynSolType::Array(Box::new(DynSolType::String)))\n    }\n}\n\nimpl Cheatcode for parseJsonBytesCall {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { json, key } = self;\n        parse_json_coerce(json, key, &DynSolType::Bytes)\n    }\n}\n\nimpl Cheatcode for parseJsonBytesArrayCall {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { json, key } = self;\n        parse_json_coerce(json, key, &DynSolType::Array(Box::new(DynSolType::Bytes)))\n    }\n}\n\nimpl Cheatcode for parseJsonBytes32Call {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { json, key } = self;\n        parse_json_coerce(json, key, &DynSolType::FixedBytes(32))\n    }\n}\n\nimpl Cheatcode for parseJsonBytes32ArrayCall {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { json, key } = self;\n        parse_json_coerce(json, key, &DynSolType::Array(Box::new(DynSolType::FixedBytes(32))))\n    }\n}\n\nimpl Cheatcode for parseJsonType_0Call {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { json, typeDescription } = self;\n        parse_json_coerce(json, \"$\", &resolve_type(typeDescription, state.struct_defs())?)\n            .map(|v| v.abi_encode())\n    }\n}\n\nimpl Cheatcode for parseJsonType_1Call {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { json, key, typeDescription } = self;\n        parse_json_coerce(json, key, &resolve_type(typeDescription, state.struct_defs())?)\n            .map(|v| v.abi_encode())\n    }\n}\n\nimpl Cheatcode for parseJsonTypeArrayCall {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { json, key, typeDescription } = self;\n        let ty = resolve_type(typeDescription, state.struct_defs())?;\n        parse_json_coerce(json, key, &DynSolType::Array(Box::new(ty))).map(|v| v.abi_encode())\n    }\n}\n\nimpl Cheatcode for parseJsonKeysCall {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { json, key } = self;\n        parse_json_keys(json, key)\n    }\n}\n\nimpl Cheatcode for serializeJsonCall {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { objectKey, value } = self;\n        *state.serialized_jsons.entry(objectKey.into()).or_default() = serde_json::from_str(value)?;\n        Ok(value.abi_encode())\n    }\n}\n\nimpl Cheatcode for serializeBool_0Call {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { objectKey, valueKey, value } = self;\n        serialize_json(state, objectKey, valueKey, (*value).into())\n    }\n}\n\nimpl Cheatcode for serializeUint_0Call {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { objectKey, valueKey, value } = self;\n        serialize_json(state, objectKey, valueKey, (*value).into())\n    }\n}\n\nimpl Cheatcode for serializeInt_0Call {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { objectKey, valueKey, value } = self;\n        serialize_json(state, objectKey, valueKey, (*value).into())\n    }\n}\n\nimpl Cheatcode for serializeAddress_0Call {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { objectKey, valueKey, value } = self;\n        serialize_json(state, objectKey, valueKey, (*value).into())\n    }\n}\n\nimpl Cheatcode for serializeBytes32_0Call {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { objectKey, valueKey, value } = self;\n        serialize_json(state, objectKey, valueKey, DynSolValue::FixedBytes(*value, 32))\n    }\n}\n\nimpl Cheatcode for serializeString_0Call {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { objectKey, valueKey, value } = self;\n        serialize_json(state, objectKey, valueKey, value.clone().into())\n    }\n}\n\nimpl Cheatcode for serializeBytes_0Call {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { objectKey, valueKey, value } = self;\n        serialize_json(state, objectKey, valueKey, value.to_vec().into())\n    }\n}\n\nimpl Cheatcode for serializeBool_1Call {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { objectKey, valueKey, values } = self;\n        serialize_json(\n            state,\n            objectKey,\n            valueKey,\n            DynSolValue::Array(values.iter().copied().map(DynSolValue::Bool).collect()),\n        )\n    }\n}\n\nimpl Cheatcode for serializeUint_1Call {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { objectKey, valueKey, values } = self;\n        serialize_json(\n            state,\n            objectKey,\n            valueKey,\n            DynSolValue::Array(values.iter().map(|v| DynSolValue::Uint(*v, 256)).collect()),\n        )\n    }\n}\n\nimpl Cheatcode for serializeInt_1Call {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { objectKey, valueKey, values } = self;\n        serialize_json(\n            state,\n            objectKey,\n            valueKey,\n            DynSolValue::Array(values.iter().map(|v| DynSolValue::Int(*v, 256)).collect()),\n        )\n    }\n}\n\nimpl Cheatcode for serializeAddress_1Call {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { objectKey, valueKey, values } = self;\n        serialize_json(\n            state,\n            objectKey,\n            valueKey,\n            DynSolValue::Array(values.iter().copied().map(DynSolValue::Address).collect()),\n        )\n    }\n}\n\nimpl Cheatcode for serializeBytes32_1Call {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { objectKey, valueKey, values } = self;\n        serialize_json(\n            state,\n            objectKey,\n            valueKey,\n            DynSolValue::Array(values.iter().map(|v| DynSolValue::FixedBytes(*v, 32)).collect()),\n        )\n    }\n}\n\nimpl Cheatcode for serializeString_1Call {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { objectKey, valueKey, values } = self;\n        serialize_json(\n            state,\n            objectKey,\n            valueKey,\n            DynSolValue::Array(values.iter().cloned().map(DynSolValue::String).collect()),\n        )\n    }\n}\n\nimpl Cheatcode for serializeBytes_1Call {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { objectKey, valueKey, values } = self;\n        serialize_json(\n            state,\n            objectKey,\n            valueKey,\n            DynSolValue::Array(\n                values.iter().cloned().map(Into::into).map(DynSolValue::Bytes).collect(),\n            ),\n        )\n    }\n}\n\nimpl Cheatcode for serializeJsonType_0Call {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { typeDescription, value } = self;\n        let ty = resolve_type(typeDescription, state.struct_defs())?;\n        let value = ty.abi_decode(value)?;\n        let value = foundry_common::fmt::serialize_value_as_json(value, state.struct_defs())?;\n        Ok(value.to_string().abi_encode())\n    }\n}\n\nimpl Cheatcode for serializeJsonType_1Call {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { objectKey, valueKey, typeDescription, value } = self;\n        let ty = resolve_type(typeDescription, state.struct_defs())?;\n        let value = ty.abi_decode(value)?;\n        serialize_json(state, objectKey, valueKey, value)\n    }\n}\n\nimpl Cheatcode for serializeUintToHexCall {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { objectKey, valueKey, value } = self;\n        let hex = format!(\"0x{value:x}\");\n        serialize_json(state, objectKey, valueKey, hex.into())\n    }\n}\n\nimpl Cheatcode for writeJson_0Call {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { json, path } = self;\n        let json = serde_json::from_str(json).unwrap_or_else(|_| Value::String(json.to_owned()));\n        let json_string = serde_json::to_string_pretty(&json)?;\n        super::fs::write_file(state, path.as_ref(), json_string.as_bytes())\n    }\n}\n\nimpl Cheatcode for writeJson_1Call {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { json: value, path, valueKey } = self;\n\n        // Read, parse, and update the JSON object.\n        // If the file doesn't exist, start with an empty JSON object so the file is created.\n        let data_path = state.config.ensure_path_allowed(path, FsAccessKind::Read)?;\n        let mut data = if data_path.exists() {\n            let data_string = fs::locked_read_to_string(&data_path)?;\n            serde_json::from_str(&data_string).unwrap_or_else(|_| Value::String(data_string))\n        } else {\n            Value::Object(Default::default())\n        };\n        upsert_json_value(&mut data, value, valueKey)?;\n\n        // Write the updated content back to the file\n        let json_string = serde_json::to_string_pretty(&data)?;\n        super::fs::write_file(state, path.as_ref(), json_string.as_bytes())\n    }\n}\n\npub(super) fn check_json_key_exists(json: &str, key: &str) -> Result {\n    let json = parse_json_str(json)?;\n    let values = select(&json, key)?;\n    let exists = !values.is_empty();\n    Ok(exists.abi_encode())\n}\n\npub(super) fn parse_json(json: &str, path: &str, defs: Option<&StructDefinitions>) -> Result {\n    let value = parse_json_str(json)?;\n    let selected = select(&value, path)?;\n    let sol = json_to_sol(defs, &selected)?;\n    Ok(encode(sol))\n}\n\npub(super) fn parse_json_coerce(json: &str, path: &str, ty: &DynSolType) -> Result {\n    let json = parse_json_str(json)?;\n    let [value] = select(&json, path)?[..] else {\n        bail!(\"path {path:?} must return exactly one JSON value\");\n    };\n\n    parse_json_as(value, ty).map(|v| v.abi_encode())\n}\n\n/// Parses given [serde_json::Value] as a [DynSolValue].\npub(super) fn parse_json_as(value: &Value, ty: &DynSolType) -> Result<DynSolValue> {\n    let to_string = |v: &Value| {\n        let mut s = v.to_string();\n        s.retain(|c: char| c != '\"');\n        s\n    };\n\n    match (value, ty) {\n        (Value::Array(array), ty) => parse_json_array(array, ty),\n        (Value::Object(object), ty) => parse_json_map(object, ty),\n        (Value::String(s), DynSolType::String) => Ok(DynSolValue::String(s.clone())),\n        (Value::String(s), DynSolType::Uint(_) | DynSolType::Int(_)) => string::parse_value(s, ty),\n        _ => string::parse_value(&to_string(value), ty),\n    }\n}\n\npub(super) fn parse_json_array(array: &[Value], ty: &DynSolType) -> Result<DynSolValue> {\n    match ty {\n        DynSolType::Tuple(types) => {\n            ensure!(array.len() == types.len(), \"array length mismatch\");\n            let values = array\n                .iter()\n                .zip(types)\n                .map(|(e, ty)| parse_json_as(e, ty))\n                .collect::<Result<Vec<_>>>()?;\n\n            Ok(DynSolValue::Tuple(values))\n        }\n        DynSolType::Array(inner) => {\n            let values =\n                array.iter().map(|e| parse_json_as(e, inner)).collect::<Result<Vec<_>>>()?;\n            Ok(DynSolValue::Array(values))\n        }\n        DynSolType::FixedArray(inner, len) => {\n            ensure!(array.len() == *len, \"array length mismatch\");\n            let values =\n                array.iter().map(|e| parse_json_as(e, inner)).collect::<Result<Vec<_>>>()?;\n            Ok(DynSolValue::FixedArray(values))\n        }\n        _ => bail!(\"expected {ty}, found array\"),\n    }\n}\n\npub(super) fn parse_json_map(map: &Map<String, Value>, ty: &DynSolType) -> Result<DynSolValue> {\n    let Some((name, fields, types)) = ty.as_custom_struct() else {\n        bail!(\"expected {ty}, found JSON object\");\n    };\n\n    let mut values = Vec::with_capacity(fields.len());\n    for (field, ty) in fields.iter().zip(types.iter()) {\n        let Some(value) = map.get(field) else { bail!(\"field {field:?} not found in JSON object\") };\n        values.push(parse_json_as(value, ty)?);\n    }\n\n    Ok(DynSolValue::CustomStruct {\n        name: name.to_string(),\n        prop_names: fields.to_vec(),\n        tuple: values,\n    })\n}\n\npub(super) fn parse_json_keys(json: &str, key: &str) -> Result {\n    let json = parse_json_str(json)?;\n    let values = select(&json, key)?;\n    let [value] = values[..] else {\n        bail!(\"key {key:?} must return exactly one JSON object\");\n    };\n    let Value::Object(object) = value else {\n        bail!(\"JSON value at {key:?} is not an object\");\n    };\n    let keys = object.keys().collect::<Vec<_>>();\n    Ok(keys.abi_encode())\n}\n\nfn parse_json_str(json: &str) -> Result<Value> {\n    serde_json::from_str(json).map_err(|e| fmt_err!(\"failed parsing JSON: {e}\"))\n}\n\nfn json_to_sol(defs: Option<&StructDefinitions>, json: &[&Value]) -> Result<Vec<DynSolValue>> {\n    let mut sol = Vec::with_capacity(json.len());\n    for value in json {\n        sol.push(json_value_to_token(value, defs)?);\n    }\n    Ok(sol)\n}\n\nfn select<'a>(value: &'a Value, mut path: &str) -> Result<Vec<&'a Value>> {\n    // Handle the special case of the root key\n    if path == \".\" {\n        path = \"$\";\n    }\n    // format error with debug string because json_path errors may contain newlines\n    jsonpath_lib::select(value, &canonicalize_json_path(path))\n        .map_err(|e| fmt_err!(\"failed selecting from JSON: {:?}\", e.to_string()))\n}\n\nfn encode(values: Vec<DynSolValue>) -> Vec<u8> {\n    // Double `abi_encode` is intentional\n    let bytes = match &values[..] {\n        [] => Vec::new(),\n        [one] => one.abi_encode(),\n        _ => DynSolValue::Array(values).abi_encode(),\n    };\n    bytes.abi_encode()\n}\n\n/// Canonicalize a json path key to always start from the root of the document.\n/// Read more about json path syntax: <https://goessner.net/articles/JsonPath/>\npub(super) fn canonicalize_json_path(path: &str) -> Cow<'_, str> {\n    if !path.starts_with('$') { format!(\"${path}\").into() } else { path.into() }\n}\n\n/// Converts a JSON [`Value`] to a [`DynSolValue`] by trying to guess encoded type. For safer\n/// decoding, use [`parse_json_as`].\n///\n/// The function is designed to run recursively, so that in case of an object\n/// it will call itself to convert each of it's value and encode the whole as a\n/// Tuple\n#[instrument(target = \"cheatcodes\", level = \"trace\", ret)]\npub(super) fn json_value_to_token(\n    value: &Value,\n    defs: Option<&StructDefinitions>,\n) -> Result<DynSolValue> {\n    if let Some(defs) = defs {\n        _json_value_to_token(value, defs)\n    } else {\n        _json_value_to_token(value, &StructDefinitions::default())\n    }\n}\n\nfn _json_value_to_token(value: &Value, defs: &StructDefinitions) -> Result<DynSolValue> {\n    match value {\n        Value::Null => Ok(DynSolValue::FixedBytes(B256::ZERO, 32)),\n        Value::Bool(boolean) => Ok(DynSolValue::Bool(*boolean)),\n        Value::Array(array) => array\n            .iter()\n            .map(|v| _json_value_to_token(v, defs))\n            .collect::<Result<_>>()\n            .map(DynSolValue::Array),\n        Value::Object(map) => {\n            // Try to find a struct definition that matches the object keys.\n            let keys: BTreeSet<_> = map.keys().map(|s| s.as_str()).collect();\n            let matching_def = defs.values().find(|fields| {\n                fields.len() == keys.len()\n                    && fields.iter().map(|(name, _)| name.as_str()).collect::<BTreeSet<_>>() == keys\n            });\n\n            if let Some(fields) = matching_def {\n                // Found a struct with matching field names, use the order from the definition.\n                fields\n                    .iter()\n                    .map(|(name, _)| {\n                        // unwrap is safe because we know the key exists.\n                        _json_value_to_token(map.get(name).unwrap(), defs)\n                    })\n                    .collect::<Result<_>>()\n                    .map(DynSolValue::Tuple)\n            } else {\n                // Fallback to alphabetical sorting if no matching struct is found.\n                // See: [#3647](https://github.com/foundry-rs/foundry/pull/3647)\n                let ordered_object: BTreeMap<_, _> =\n                    map.iter().map(|(k, v)| (k.clone(), v.clone())).collect();\n                ordered_object\n                    .values()\n                    .map(|value| _json_value_to_token(value, defs))\n                    .collect::<Result<_>>()\n                    .map(DynSolValue::Tuple)\n            }\n        }\n        Value::Number(number) => {\n            if let Some(f) = number.as_f64() {\n                // Check if the number has decimal digits because the EVM does not support floating\n                // point math\n                if f.fract() == 0.0 {\n                    // Use the string representation of the `serde_json` Number type instead of\n                    // calling f.to_string(), because some numbers are wrongly rounded up after\n                    // being convented to f64.\n                    // Example: 18446744073709551615 becomes 18446744073709552000 after parsing it\n                    // to f64.\n                    let s = number.to_string();\n\n                    // Coerced to scientific notation, so short-circuit to using fallback.\n                    // This will not have a problem with hex numbers, as for parsing these\n                    // We'd need to prefix this with 0x.\n                    // See also <https://docs.soliditylang.org/en/latest/types.html#rational-and-integer-literals>\n                    if s.contains('e') {\n                        // Calling Number::to_string with powers of ten formats the number using\n                        // scientific notation and causes from_dec_str to fail. Using format! with\n                        // f64 keeps the full number representation.\n                        // Example: 100000000000000000000 becomes 1e20 when Number::to_string is\n                        // used.\n                        let fallback_s = f.to_string();\n                        if let Ok(n) = fallback_s.parse() {\n                            return Ok(DynSolValue::Uint(n, 256));\n                        }\n                        if let Ok(n) = I256::from_dec_str(&fallback_s) {\n                            return Ok(DynSolValue::Int(n, 256));\n                        }\n                    }\n\n                    if let Ok(n) = s.parse() {\n                        return Ok(DynSolValue::Uint(n, 256));\n                    }\n                    if let Ok(n) = s.parse() {\n                        return Ok(DynSolValue::Int(n, 256));\n                    }\n                }\n            }\n\n            Err(fmt_err!(\"unsupported JSON number: {number}\"))\n        }\n        Value::String(string) => {\n            //  Hanfl hex strings\n            if let Some(mut val) = string.strip_prefix(\"0x\") {\n                let s;\n                if val.len() == 39 {\n                    return Err(format!(\"Cannot parse \\\"{val}\\\" as an address. If you want to specify address, prepend zero to the value.\").into());\n                }\n                if !val.len().is_multiple_of(2) {\n                    s = format!(\"0{val}\");\n                    val = &s[..];\n                }\n                if let Ok(bytes) = hex::decode(val) {\n                    return Ok(match bytes.len() {\n                        20 => DynSolValue::Address(Address::from_slice(&bytes)),\n                        32 => DynSolValue::FixedBytes(B256::from_slice(&bytes), 32),\n                        _ => DynSolValue::Bytes(bytes),\n                    });\n                }\n            }\n\n            // Handle large numbers that were potentially encoded as strings because they exceed the\n            // capacity of a 64-bit integer.\n            // Note that number-like strings that *could* fit in an `i64`/`u64` will fall through\n            // and be treated as literal strings.\n            if let Ok(n) = string.parse::<I256>()\n                && i64::try_from(n).is_err()\n            {\n                return Ok(DynSolValue::Int(n, 256));\n            } else if let Ok(n) = string.parse::<U256>()\n                && u64::try_from(n).is_err()\n            {\n                return Ok(DynSolValue::Uint(n, 256));\n            }\n\n            // Otherwise, treat as a regular string\n            Ok(DynSolValue::String(string.to_owned()))\n        }\n    }\n}\n\n/// Serializes a key:value pair to a specific object. If the key is valueKey, the value is\n/// expected to be an object, which will be set as the root object for the provided object key,\n/// overriding the whole root object if the object key already exists. By calling this function\n/// multiple times, the user can serialize multiple KV pairs to the same object. The value can be of\n/// any type, even a new object in itself. The function will return a stringified version of the\n/// object, so that the user can use that as a value to a new invocation of the same function with a\n/// new object key. This enables the user to reuse the same function to crate arbitrarily complex\n/// object structures (JSON).\nfn serialize_json(\n    state: &mut Cheatcodes,\n    object_key: &str,\n    value_key: &str,\n    value: DynSolValue,\n) -> Result {\n    let value = foundry_common::fmt::serialize_value_as_json(value, state.struct_defs())?;\n    let map = state.serialized_jsons.entry(object_key.into()).or_default();\n    map.insert(value_key.into(), value);\n    let stringified = serde_json::to_string(map).unwrap();\n    Ok(stringified.abi_encode())\n}\n\n/// Resolves a [DynSolType] from user input.\npub(super) fn resolve_type(\n    type_description: &str,\n    struct_defs: Option<&StructDefinitions>,\n) -> Result<DynSolType> {\n    let ordered_ty = |ty| -> Result<DynSolType> {\n        if let Some(defs) = struct_defs { reorder_type(ty, defs) } else { Ok(ty) }\n    };\n\n    if let Ok(ty) = DynSolType::parse(type_description) {\n        return ordered_ty(ty);\n    };\n\n    if let Ok(encoded) = EncodeType::parse(type_description) {\n        let main_type = encoded.types[0].type_name;\n        let mut resolver = Resolver::default();\n        for t in &encoded.types {\n            resolver.ingest(t.to_owned());\n        }\n\n        // Get the alphabetically-sorted type from the resolver, and reorder if necessary.\n        return ordered_ty(resolver.resolve(main_type)?);\n    }\n\n    bail!(\"type description should be a valid Solidity type or a EIP712 `encodeType` string\")\n}\n\n/// Upserts a value into a JSON object based on a dot-separated key.\n///\n/// This function navigates through a mutable `serde_json::Value` object using a\n/// path-like key. It creates nested JSON objects if they do not exist along the path.\n/// The value is inserted at the final key in the path.\n///\n/// # Arguments\n///\n/// * `data` - A mutable reference to the `serde_json::Value` to be modified.\n/// * `value` - The string representation of the value to upsert. This string is first parsed as\n///   JSON, and if that fails, it's treated as a plain JSON string.\n/// * `key` - A dot-separated string representing the path to the location for upserting.\npub(super) fn upsert_json_value(data: &mut Value, value: &str, key: &str) -> Result<()> {\n    // Parse the path key into segments.\n    let canonical_key = canonicalize_json_path(key);\n    let parts: Vec<&str> = canonical_key\n        .strip_prefix(\"$.\")\n        .unwrap_or(key)\n        .split('.')\n        .filter(|s| !s.is_empty())\n        .collect();\n\n    if parts.is_empty() {\n        return Err(fmt_err!(\"'valueKey' cannot be empty or just '$'\"));\n    }\n\n    // Separate the final key from the path.\n    // Traverse the objects, creating intermediary ones if necessary.\n    if let Some((key_to_insert, path_to_parent)) = parts.split_last() {\n        let mut current_level = data;\n\n        for segment in path_to_parent {\n            if !current_level.is_object() {\n                return Err(fmt_err!(\"path segment '{segment}' does not resolve to an object.\"));\n            }\n            current_level = current_level\n                .as_object_mut()\n                .unwrap()\n                .entry(segment.to_string())\n                .or_insert(Value::Object(Map::new()));\n        }\n\n        // Upsert the new value\n        if let Some(parent_obj) = current_level.as_object_mut() {\n            parent_obj.insert(\n                key_to_insert.to_string(),\n                serde_json::from_str(value).unwrap_or_else(|_| Value::String(value.to_owned())),\n            );\n        } else {\n            return Err(fmt_err!(\"final destination is not an object, cannot insert key.\"));\n        }\n    }\n\n    Ok(())\n}\n\n/// Recursively traverses a `DynSolType` and reorders the fields of any\n/// `CustomStruct` variants according to the provided `StructDefinitions`.\n///\n/// This is necessary because the EIP-712 resolver sorts struct fields alphabetically,\n/// but we want to respect the order defined in the Solidity source code.\nfn reorder_type(ty: DynSolType, struct_defs: &StructDefinitions) -> Result<DynSolType> {\n    match ty {\n        DynSolType::CustomStruct { name, prop_names, tuple } => {\n            if let Some(def) = struct_defs.get(&name)? {\n                // The incoming `prop_names` and `tuple` are alphabetically sorted.\n                let type_map: std::collections::HashMap<String, DynSolType> =\n                    prop_names.into_iter().zip(tuple).collect();\n\n                let mut sorted_props = Vec::with_capacity(def.len());\n                let mut sorted_tuple = Vec::with_capacity(def.len());\n                for (field_name, _) in def {\n                    sorted_props.push(field_name.clone());\n                    if let Some(field_ty) = type_map.get(field_name) {\n                        sorted_tuple.push(reorder_type(field_ty.clone(), struct_defs)?);\n                    } else {\n                        bail!(\n                            \"mismatch between struct definition and type description: field '{field_name}' not found in provided type for struct '{name}'\"\n                        );\n                    }\n                }\n                Ok(DynSolType::CustomStruct { name, prop_names: sorted_props, tuple: sorted_tuple })\n            } else {\n                // No definition found, so we can't reorder. However, we still reorder its children\n                // in case they have known structs.\n                let new_tuple = tuple\n                    .into_iter()\n                    .map(|t| reorder_type(t, struct_defs))\n                    .collect::<Result<Vec<_>>>()?;\n                Ok(DynSolType::CustomStruct { name, prop_names, tuple: new_tuple })\n            }\n        }\n        DynSolType::Array(inner) => {\n            Ok(DynSolType::Array(Box::new(reorder_type(*inner, struct_defs)?)))\n        }\n        DynSolType::FixedArray(inner, len) => {\n            Ok(DynSolType::FixedArray(Box::new(reorder_type(*inner, struct_defs)?), len))\n        }\n        DynSolType::Tuple(inner) => Ok(DynSolType::Tuple(\n            inner.into_iter().map(|t| reorder_type(t, struct_defs)).collect::<Result<Vec<_>>>()?,\n        )),\n        _ => Ok(ty),\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use alloy_primitives::FixedBytes;\n    use foundry_common::fmt::{TypeDefMap, serialize_value_as_json};\n    use proptest::{arbitrary::any, prop_oneof, strategy::Strategy};\n    use std::collections::HashSet;\n\n    fn valid_value(value: &DynSolValue) -> bool {\n        (match value {\n            DynSolValue::String(s) if s == \"{}\" => false,\n\n            DynSolValue::Tuple(_) | DynSolValue::CustomStruct { .. } => false,\n\n            DynSolValue::Array(v) | DynSolValue::FixedArray(v) => v.iter().all(valid_value),\n            _ => true,\n        }) && value.as_type().is_some()\n    }\n\n    /// [DynSolValue::Bytes] of length 32 and 20 are converted to [DynSolValue::FixedBytes] and\n    /// [DynSolValue::Address] respectively. Thus, we can't distinguish between address and bytes of\n    /// length 20 during decoding. Because of that, there are issues with handling of arrays of\n    /// those types.\n    fn fixup_guessable(value: DynSolValue) -> DynSolValue {\n        match value {\n            DynSolValue::Array(mut v) | DynSolValue::FixedArray(mut v) => {\n                if let Some(DynSolValue::Bytes(_)) = v.first() {\n                    v.retain(|v| {\n                        let len = v.as_bytes().unwrap().len();\n                        len != 32 && len != 20\n                    })\n                }\n                DynSolValue::Array(v.into_iter().map(fixup_guessable).collect())\n            }\n            DynSolValue::FixedBytes(v, _) => DynSolValue::FixedBytes(v, 32),\n            DynSolValue::Bytes(v) if v.len() == 32 => {\n                DynSolValue::FixedBytes(FixedBytes::from_slice(&v), 32)\n            }\n            DynSolValue::Bytes(v) if v.len() == 20 => DynSolValue::Address(Address::from_slice(&v)),\n            _ => value,\n        }\n    }\n\n    fn guessable_types() -> impl proptest::strategy::Strategy<Value = DynSolValue> {\n        any::<DynSolValue>().prop_map(fixup_guessable).prop_filter(\"invalid value\", valid_value)\n    }\n\n    /// A proptest strategy for generating a (simple) `DynSolValue::CustomStruct`\n    /// and its corresponding `StructDefinitions` object.\n    fn custom_struct_strategy() -> impl Strategy<Value = (StructDefinitions, DynSolValue)> {\n        // Define a strategy for basic field names and values.\n        let field_name_strat = \"[a-z]{4,12}\";\n        let field_value_strat = prop_oneof![\n            any::<bool>().prop_map(DynSolValue::Bool),\n            any::<u32>().prop_map(|v| DynSolValue::Uint(U256::from(v), 256)),\n            any::<[u8; 20]>().prop_map(Address::from).prop_map(DynSolValue::Address),\n            any::<[u8; 32]>().prop_map(B256::from).prop_map(|b| DynSolValue::FixedBytes(b, 32)),\n            \".*\".prop_map(DynSolValue::String),\n        ];\n\n        // Combine them to create a list of unique fields that preserve the random order.\n        let fields_strat = proptest::collection::vec((field_name_strat, field_value_strat), 1..8)\n            .prop_map(|fields| {\n                let mut unique_fields = Vec::with_capacity(fields.len());\n                let mut seen_names = HashSet::new();\n                for (name, value) in fields {\n                    if seen_names.insert(name.clone()) {\n                        unique_fields.push((name, value));\n                    }\n                }\n                unique_fields\n            });\n\n        // Generate the `CustomStruct` and its definition.\n        (\"[A-Z][a-z]{4,8}\", fields_strat).prop_map(|(struct_name, fields)| {\n            let (prop_names, tuple): (Vec<String>, Vec<DynSolValue>) =\n                fields.clone().into_iter().unzip();\n            let def_fields: Vec<(String, String)> = fields\n                .iter()\n                .map(|(name, value)| (name.clone(), value.as_type().unwrap().to_string()))\n                .collect();\n            let mut defs_map = TypeDefMap::default();\n            defs_map.insert(struct_name.clone(), def_fields);\n            (defs_map.into(), DynSolValue::CustomStruct { name: struct_name, prop_names, tuple })\n        })\n    }\n\n    // Tests to ensure that conversion [DynSolValue] -> [serde_json::Value] -> [DynSolValue]\n    proptest::proptest! {\n        #[test]\n        fn test_json_roundtrip_guessed(v in guessable_types()) {\n            let json = serialize_value_as_json(v.clone(), None).unwrap();\n            let value = json_value_to_token(&json, None).unwrap();\n\n            // do additional abi_encode -> abi_decode to avoid zero signed integers getting decoded as unsigned and causing assert_eq to fail.\n            let decoded = v.as_type().unwrap().abi_decode(&value.abi_encode()).unwrap();\n            assert_eq!(decoded, v);\n        }\n\n        #[test]\n        fn test_json_roundtrip(v in any::<DynSolValue>().prop_filter(\"filter out values without type\", |v| v.as_type().is_some())) {\n            let json = serialize_value_as_json(v.clone(), None).unwrap();\n            let value = parse_json_as(&json, &v.as_type().unwrap()).unwrap();\n            assert_eq!(value, v);\n        }\n\n        #[test]\n        fn test_json_roundtrip_with_struct_defs((struct_defs, v) in custom_struct_strategy()) {\n            let json = serialize_value_as_json(v.clone(), Some(&struct_defs)).unwrap();\n            let sol_type = v.as_type().unwrap();\n            let parsed_value = parse_json_as(&json, &sol_type).unwrap();\n            assert_eq!(parsed_value, v);\n        }\n    }\n\n    #[test]\n    fn test_resolve_type_with_definitions() -> Result<()> {\n        // Define a struct with fields in a specific order (not alphabetical)\n        let mut struct_defs = TypeDefMap::new();\n        struct_defs.insert(\n            \"Apple\".to_string(),\n            vec![\n                (\"color\".to_string(), \"string\".to_string()),\n                (\"sweetness\".to_string(), \"uint8\".to_string()),\n                (\"sourness\".to_string(), \"uint8\".to_string()),\n            ],\n        );\n        struct_defs.insert(\n            \"FruitStall\".to_string(),\n            vec![\n                (\"name\".to_string(), \"string\".to_string()),\n                (\"apples\".to_string(), \"Apple[]\".to_string()),\n            ],\n        );\n\n        // Simulate resolver output: type string, using alphabetical order for fields.\n        let ty_desc = \"FruitStall(Apple[] apples,string name)Apple(string color,uint8 sourness,uint8 sweetness)\";\n\n        // Resolve type and ensure struct definition order is preserved.\n        let ty = resolve_type(ty_desc, Some(&struct_defs.into())).unwrap();\n        if let DynSolType::CustomStruct { name, prop_names, tuple } = ty {\n            assert_eq!(name, \"FruitStall\");\n            assert_eq!(prop_names, vec![\"name\", \"apples\"]);\n            assert_eq!(tuple.len(), 2);\n            assert_eq!(tuple[0], DynSolType::String);\n\n            if let DynSolType::Array(apple_ty_boxed) = &tuple[1]\n                && let DynSolType::CustomStruct { name, prop_names, tuple } = &**apple_ty_boxed\n            {\n                assert_eq!(*name, \"Apple\");\n                // Check that the inner struct's fields are also in definition order.\n                assert_eq!(*prop_names, vec![\"color\", \"sweetness\", \"sourness\"]);\n                assert_eq!(\n                    *tuple,\n                    vec![DynSolType::String, DynSolType::Uint(8), DynSolType::Uint(8)]\n                );\n\n                return Ok(());\n            }\n        }\n        panic!(\"Expected FruitStall and Apple to be CustomStruct\");\n    }\n\n    #[test]\n    fn test_resolve_type_without_definitions() -> Result<()> {\n        // Simulate resolver output: type string, using alphabetical order for fields.\n        let ty_desc = \"Person(bool active,uint256 age,string name)\";\n\n        // Resolve the type without providing any struct definitions and ensure that original\n        // (alphabetical) order is unchanged.\n        let ty = resolve_type(ty_desc, None).unwrap();\n        if let DynSolType::CustomStruct { name, prop_names, tuple } = ty {\n            assert_eq!(name, \"Person\");\n            assert_eq!(prop_names, vec![\"active\", \"age\", \"name\"]);\n            assert_eq!(tuple.len(), 3);\n            assert_eq!(tuple, vec![DynSolType::Bool, DynSolType::Uint(256), DynSolType::String]);\n            return Ok(());\n        }\n        panic!(\"Expected Person to be CustomStruct\");\n    }\n\n    #[test]\n    fn test_resolve_type_for_array_of_structs() -> Result<()> {\n        // Define a struct with fields in a specific, non-alphabetical order.\n        let mut struct_defs = TypeDefMap::new();\n        struct_defs.insert(\n            \"Item\".to_string(),\n            vec![\n                (\"name\".to_string(), \"string\".to_string()),\n                (\"price\".to_string(), \"uint256\".to_string()),\n                (\"id\".to_string(), \"uint256\".to_string()),\n            ],\n        );\n\n        // Simulate resolver output: type string, using alphabetical order for fields.\n        let ty_desc = \"Item(uint256 id,string name,uint256 price)\";\n\n        // Resolve type and ensure struct definition order is preserved.\n        let ty = resolve_type(ty_desc, Some(&struct_defs.into())).unwrap();\n        let array_ty = DynSolType::Array(Box::new(ty));\n        if let DynSolType::Array(item_ty) = array_ty\n            && let DynSolType::CustomStruct { name, prop_names, tuple } = *item_ty\n        {\n            assert_eq!(name, \"Item\");\n            assert_eq!(prop_names, vec![\"name\", \"price\", \"id\"]);\n            assert_eq!(\n                tuple,\n                vec![DynSolType::String, DynSolType::Uint(256), DynSolType::Uint(256)]\n            );\n            return Ok(());\n        }\n        panic!(\"Expected CustomStruct in array\");\n    }\n\n    #[test]\n    fn test_parse_json_missing_field() {\n        // Define a struct with a specific field order.\n        let mut struct_defs = TypeDefMap::new();\n        struct_defs.insert(\n            \"Person\".to_string(),\n            vec![\n                (\"name\".to_string(), \"string\".to_string()),\n                (\"age\".to_string(), \"uint256\".to_string()),\n            ],\n        );\n\n        // JSON missing the \"age\" field\n        let json_str = r#\"{ \"name\": \"Alice\" }\"#;\n\n        // Simulate resolver output: type string, using alphabetical order for fields.\n        let type_description = \"Person(uint256 age,string name)\";\n        let ty = resolve_type(type_description, Some(&struct_defs.into())).unwrap();\n\n        // Now, attempt to parse the incomplete JSON using the ordered type.\n        let json_value: Value = serde_json::from_str(json_str).unwrap();\n        let result = parse_json_as(&json_value, &ty);\n\n        // Should fail with a missing field error because `parse_json_map` requires all fields.\n        assert!(result.is_err());\n        assert!(result.unwrap_err().to_string().contains(\"field \\\"age\\\" not found in JSON object\"));\n    }\n\n    #[test]\n    fn test_serialize_json_with_struct_def_order() {\n        // Define a struct with a specific, non-alphabetical field order.\n        let mut struct_defs = TypeDefMap::new();\n        struct_defs.insert(\n            \"Item\".to_string(),\n            vec![\n                (\"name\".to_string(), \"string\".to_string()),\n                (\"id\".to_string(), \"uint256\".to_string()),\n                (\"active\".to_string(), \"bool\".to_string()),\n            ],\n        );\n\n        // Create a DynSolValue instance for the struct.\n        let item_struct = DynSolValue::CustomStruct {\n            name: \"Item\".to_string(),\n            prop_names: vec![\"name\".to_string(), \"id\".to_string(), \"active\".to_string()],\n            tuple: vec![\n                DynSolValue::String(\"Test Item\".to_string()),\n                DynSolValue::Uint(U256::from(123), 256),\n                DynSolValue::Bool(true),\n            ],\n        };\n\n        // Serialize the value to JSON and verify that the order is preserved.\n        let json_value = serialize_value_as_json(item_struct, Some(&struct_defs.into())).unwrap();\n        let json_string = serde_json::to_string(&json_value).unwrap();\n        assert_eq!(json_string, r#\"{\"name\":\"Test Item\",\"id\":123,\"active\":true}\"#);\n    }\n\n    #[test]\n    fn test_json_full_cycle_typed_with_struct_defs() {\n        // Define a struct with a specific, non-alphabetical field order.\n        let mut struct_defs = TypeDefMap::new();\n        struct_defs.insert(\n            \"Wallet\".to_string(),\n            vec![\n                (\"owner\".to_string(), \"address\".to_string()),\n                (\"balance\".to_string(), \"uint256\".to_string()),\n                (\"id\".to_string(), \"bytes32\".to_string()),\n            ],\n        );\n\n        // Create the \"original\" DynSolValue instance.\n        let owner_address = Address::from([1; 20]);\n        let wallet_id = B256::from([2; 32]);\n        let original_wallet = DynSolValue::CustomStruct {\n            name: \"Wallet\".to_string(),\n            prop_names: vec![\"owner\".to_string(), \"balance\".to_string(), \"id\".to_string()],\n            tuple: vec![\n                DynSolValue::Address(owner_address),\n                DynSolValue::Uint(U256::from(5000), 256),\n                DynSolValue::FixedBytes(wallet_id, 32),\n            ],\n        };\n\n        // Serialize it. The resulting JSON should respect the struct definition order.\n        let json_value =\n            serialize_value_as_json(original_wallet.clone(), Some(&struct_defs.clone().into()))\n                .unwrap();\n        let json_string = serde_json::to_string(&json_value).unwrap();\n        assert_eq!(\n            json_string,\n            format!(r#\"{{\"owner\":\"{owner_address}\",\"balance\":5000,\"id\":\"{wallet_id}\"}}\"#)\n        );\n\n        // Resolve the type, which should also respect the struct definition order.\n        let type_description = \"Wallet(uint256 balance,bytes32 id,address owner)\";\n        let resolved_type = resolve_type(type_description, Some(&struct_defs.into())).unwrap();\n\n        // Parse the JSON using the correctly ordered resolved type. Ensure that it is identical to\n        // the original one.\n        let parsed_value = parse_json_as(&json_value, &resolved_type).unwrap();\n        assert_eq!(parsed_value, original_wallet);\n    }\n}\n"
  },
  {
    "path": "crates/cheatcodes/src/lib.rs",
    "content": "//! # foundry-cheatcodes\n//!\n//! Foundry cheatcodes implementations.\n\n#![cfg_attr(not(test), warn(unused_crate_dependencies))]\n#![cfg_attr(docsrs, feature(doc_cfg))]\n#![allow(elided_lifetimes_in_paths)] // Cheats context uses 3 lifetimes\n\n#[macro_use]\nextern crate foundry_common;\n\n#[macro_use]\npub extern crate foundry_cheatcodes_spec as spec;\n\n#[macro_use]\nextern crate tracing;\n\nuse alloy_primitives::Address;\nuse foundry_evm_core::backend::DatabaseExt;\nuse revm::context::{ContextTr, JournalTr};\n\npub use Vm::ForgeContext;\npub use config::CheatsConfig;\npub use error::{Error, ErrorKind, Result};\npub use foundry_evm_core::{EthCheatCtx, evm::NestedEvmClosure};\npub use inspector::{\n    BroadcastKind, BroadcastableTransaction, BroadcastableTransactions, Cheatcodes,\n    CheatcodesExecutor,\n};\npub use spec::{CheatcodeDef, Vm};\n\n#[macro_use]\nmod error;\n\nmod base64;\n\nmod config;\n\nmod crypto;\n\nmod version;\n\nmod env;\npub use env::set_execution_context;\n\nmod evm;\n\nmod fs;\n\nmod inspector;\npub use inspector::CheatcodeAnalysis;\n\nmod json;\n\nmod script;\npub use script::{Wallets, WalletsInner};\n\nmod string;\n\nmod test;\npub use test::expect::ExpectedCallTracker;\n\nmod toml;\n\nmod utils;\n\n/// Cheatcode implementation.\npub(crate) trait Cheatcode: CheatcodeDef {\n    /// Applies this cheatcode to the given state.\n    ///\n    /// Implement this function if you don't need access to the EVM data.\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let _ = state;\n        unimplemented!(\"{}\", Self::CHEATCODE.func.id)\n    }\n\n    /// Applies this cheatcode to the given context.\n    ///\n    /// Implement this function if you need access to the EVM data.\n    #[inline(always)]\n    fn apply_stateful<CTX: EthCheatCtx>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        self.apply(ccx.state)\n    }\n\n    /// Applies this cheatcode to the given context and executor.\n    ///\n    /// Implement this function if you need access to the executor.\n    #[inline(always)]\n    fn apply_full<CTX: EthCheatCtx>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n        executor: &mut dyn CheatcodesExecutor<CTX>,\n    ) -> Result {\n        let _ = executor;\n        self.apply_stateful(ccx)\n    }\n}\n\n/// The cheatcode context.\npub struct CheatsCtxt<'a, CTX> {\n    /// The cheatcodes inspector state.\n    pub(crate) state: &'a mut Cheatcodes,\n    /// The EVM context.\n    pub(crate) ecx: &'a mut CTX,\n    /// The original `msg.sender`.\n    pub(crate) caller: Address,\n    /// Gas limit of the current cheatcode call.\n    pub(crate) gas_limit: u64,\n}\n\nimpl<CTX> std::ops::Deref for CheatsCtxt<'_, CTX> {\n    type Target = CTX;\n\n    #[inline(always)]\n    fn deref(&self) -> &Self::Target {\n        self.ecx\n    }\n}\n\nimpl<CTX> std::ops::DerefMut for CheatsCtxt<'_, CTX> {\n    #[inline(always)]\n    fn deref_mut(&mut self) -> &mut Self::Target {\n        self.ecx\n    }\n}\n\nimpl<CTX: ContextTr> CheatsCtxt<'_, CTX> {\n    pub(crate) fn ensure_not_precompile(&self, address: &Address) -> Result<()> {\n        if self.is_precompile(address) { Err(precompile_error(address)) } else { Ok(()) }\n    }\n\n    pub(crate) fn is_precompile(&self, address: &Address) -> bool {\n        self.ecx.journal().precompile_addresses().contains(address)\n    }\n}\n\n#[cold]\nfn precompile_error(address: &Address) -> Error {\n    fmt_err!(\"cannot use precompile {address} as an argument\")\n}\n"
  },
  {
    "path": "crates/cheatcodes/src/script.rs",
    "content": "//! Implementations of [`Scripting`](spec::Group::Scripting) cheatcodes.\n\nuse crate::{Cheatcode, CheatsCtxt, Result, Vm::*, evm::journaled_account};\nuse alloy_consensus::{SidecarBuilder, SimpleCoder};\nuse alloy_primitives::{Address, B256, U256, Uint};\nuse alloy_rpc_types::Authorization;\nuse alloy_signer::SignerSync;\nuse alloy_signer_local::PrivateKeySigner;\nuse alloy_sol_types::SolValue;\nuse foundry_evm_core::backend::DatabaseExt;\nuse foundry_wallets::{WalletSigner, wallet_multi::MultiWallet};\nuse parking_lot::Mutex;\nuse revm::{\n    bytecode::Bytecode,\n    context::{Cfg, ContextTr, JournalTr, Transaction},\n    context_interface::transaction::SignedAuthorization,\n    inspector::JournalExt,\n    primitives::{KECCAK_EMPTY, hardfork::SpecId},\n};\nuse std::sync::Arc;\n\nimpl Cheatcode for broadcast_0Call {\n    fn apply_stateful<CTX: ContextTr<Journal: JournalExt, Db: DatabaseExt>>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n    ) -> Result {\n        let Self {} = self;\n        broadcast(ccx, None, true)\n    }\n}\n\nimpl Cheatcode for broadcast_1Call {\n    fn apply_stateful<CTX: ContextTr<Journal: JournalExt, Db: DatabaseExt>>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n    ) -> Result {\n        let Self { signer } = self;\n        broadcast(ccx, Some(signer), true)\n    }\n}\n\nimpl Cheatcode for broadcast_2Call {\n    fn apply_stateful<CTX: ContextTr<Journal: JournalExt, Db: DatabaseExt>>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n    ) -> Result {\n        let Self { privateKey } = self;\n        broadcast_key(ccx, privateKey, true)\n    }\n}\n\nimpl Cheatcode for attachDelegation_0Call {\n    fn apply_stateful<CTX: ContextTr<Db: DatabaseExt>>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n    ) -> Result {\n        let Self { signedDelegation } = self;\n        attach_delegation(ccx, signedDelegation, false)\n    }\n}\n\nimpl Cheatcode for attachDelegation_1Call {\n    fn apply_stateful<CTX: ContextTr<Db: DatabaseExt>>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n    ) -> Result {\n        let Self { signedDelegation, crossChain } = self;\n        attach_delegation(ccx, signedDelegation, *crossChain)\n    }\n}\n\nimpl Cheatcode for signDelegation_0Call {\n    fn apply_stateful<CTX: ContextTr<Db: DatabaseExt>>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n    ) -> Result {\n        let Self { implementation, privateKey } = *self;\n        sign_delegation(ccx, privateKey, implementation, None, false, false)\n    }\n}\n\nimpl Cheatcode for signDelegation_1Call {\n    fn apply_stateful<CTX: ContextTr<Db: DatabaseExt>>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n    ) -> Result {\n        let Self { implementation, privateKey, nonce } = *self;\n        sign_delegation(ccx, privateKey, implementation, Some(nonce), false, false)\n    }\n}\n\nimpl Cheatcode for signDelegation_2Call {\n    fn apply_stateful<CTX: ContextTr<Db: DatabaseExt>>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n    ) -> Result {\n        let Self { implementation, privateKey, crossChain } = *self;\n        sign_delegation(ccx, privateKey, implementation, None, crossChain, false)\n    }\n}\n\nimpl Cheatcode for signAndAttachDelegation_0Call {\n    fn apply_stateful<CTX: ContextTr<Db: DatabaseExt>>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n    ) -> Result {\n        let Self { implementation, privateKey } = *self;\n        sign_delegation(ccx, privateKey, implementation, None, false, true)\n    }\n}\n\nimpl Cheatcode for signAndAttachDelegation_1Call {\n    fn apply_stateful<CTX: ContextTr<Db: DatabaseExt>>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n    ) -> Result {\n        let Self { implementation, privateKey, nonce } = *self;\n        sign_delegation(ccx, privateKey, implementation, Some(nonce), false, true)\n    }\n}\n\nimpl Cheatcode for signAndAttachDelegation_2Call {\n    fn apply_stateful<CTX: ContextTr<Db: DatabaseExt>>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n    ) -> Result {\n        let Self { implementation, privateKey, crossChain } = *self;\n        sign_delegation(ccx, privateKey, implementation, None, crossChain, true)\n    }\n}\n\n/// Helper function to attach an EIP-7702 delegation.\nfn attach_delegation<CTX: ContextTr<Db: DatabaseExt>>(\n    ccx: &mut CheatsCtxt<'_, CTX>,\n    delegation: &SignedDelegation,\n    cross_chain: bool,\n) -> Result {\n    let SignedDelegation { v, r, s, nonce, implementation } = delegation;\n    // Set chain id to 0 if universal deployment is preferred.\n    // See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-7702.md#protection-from-malleability-cross-chain\n    let chain_id = if cross_chain { U256::from(0) } else { U256::from(ccx.ecx.cfg().chain_id()) };\n\n    let auth = Authorization { address: *implementation, nonce: *nonce, chain_id };\n    let signed_auth = SignedAuthorization::new_unchecked(\n        auth,\n        *v,\n        U256::from_be_bytes(r.0),\n        U256::from_be_bytes(s.0),\n    );\n    write_delegation(ccx, signed_auth.clone())?;\n    ccx.state.add_delegation(signed_auth);\n    Ok(Default::default())\n}\n\n/// Helper function to sign and attach (if needed) an EIP-7702 delegation.\n/// Uses the provided nonce, otherwise retrieves and increments the nonce of the EOA.\nfn sign_delegation<CTX: ContextTr<Db: DatabaseExt>>(\n    ccx: &mut CheatsCtxt<'_, CTX>,\n    private_key: Uint<256, 4>,\n    implementation: Address,\n    nonce: Option<u64>,\n    cross_chain: bool,\n    attach: bool,\n) -> Result<Vec<u8>> {\n    let signer = PrivateKeySigner::from_bytes(&B256::from(private_key))?;\n    let nonce = if let Some(nonce) = nonce {\n        nonce\n    } else {\n        let account_nonce = {\n            let authority_acc = ccx.ecx.journal_mut().load_account(signer.address())?;\n            authority_acc.info.nonce\n        };\n        // Calculate next nonce considering existing active delegations\n        next_delegation_nonce(\n            &ccx.state.active_delegations,\n            signer.address(),\n            &ccx.state.broadcast,\n            account_nonce,\n        )\n    };\n    let chain_id = if cross_chain { U256::from(0) } else { U256::from(ccx.ecx.cfg().chain_id()) };\n\n    let auth = Authorization { address: implementation, nonce, chain_id };\n    let sig = signer.sign_hash_sync(&auth.signature_hash())?;\n    // Attach delegation.\n    if attach {\n        let signed_auth = SignedAuthorization::new_unchecked(auth, sig.v() as u8, sig.r(), sig.s());\n        write_delegation(ccx, signed_auth.clone())?;\n        ccx.state.add_delegation(signed_auth);\n    }\n    Ok(SignedDelegation {\n        v: sig.v() as u8,\n        r: sig.r().into(),\n        s: sig.s().into(),\n        nonce,\n        implementation,\n    }\n    .abi_encode())\n}\n\n/// Returns the next valid nonce for a delegation, considering existing active delegations.\nfn next_delegation_nonce(\n    active_delegations: &[SignedAuthorization],\n    authority: Address,\n    broadcast: &Option<Broadcast>,\n    account_nonce: u64,\n) -> u64 {\n    match active_delegations\n        .iter()\n        .rfind(|auth| auth.recover_authority().is_ok_and(|recovered| recovered == authority))\n    {\n        Some(auth) => {\n            // Increment nonce of last recorded delegation.\n            auth.nonce + 1\n        }\n        None => {\n            // First time a delegation is added for this authority.\n            if let Some(broadcast) = broadcast {\n                // Increment nonce if authority is the sender of transaction.\n                if broadcast.new_origin == authority {\n                    return account_nonce + 1;\n                }\n            }\n            // Return current nonce if authority is not the sender of transaction.\n            account_nonce\n        }\n    }\n}\n\nfn write_delegation<CTX: ContextTr<Db: DatabaseExt>>(\n    ccx: &mut CheatsCtxt<'_, CTX>,\n    auth: SignedAuthorization,\n) -> Result<()> {\n    let authority = auth.recover_authority().map_err(|e| format!(\"{e}\"))?;\n    let account_nonce = {\n        let authority_acc = ccx.ecx.journal_mut().load_account(authority)?;\n        authority_acc.info.nonce\n    };\n\n    let expected_nonce = next_delegation_nonce(\n        &ccx.state.active_delegations,\n        authority,\n        &ccx.state.broadcast,\n        account_nonce,\n    );\n\n    if expected_nonce != auth.nonce {\n        return Err(format!(\n            \"invalid nonce for {authority:?}: expected {expected_nonce}, got {}\",\n            auth.nonce\n        )\n        .into());\n    }\n\n    if auth.address.is_zero() {\n        // Set empty code if the delegation address of authority is 0x.\n        // See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-7702.md#behavior.\n        ccx.ecx.journal_mut().set_code_with_hash(authority, Bytecode::default(), KECCAK_EMPTY);\n    } else {\n        let bytecode = Bytecode::new_eip7702(*auth.address());\n        ccx.ecx.journal_mut().set_code(authority, bytecode);\n    }\n    Ok(())\n}\n\nimpl Cheatcode for attachBlobCall {\n    fn apply_stateful<CTX: ContextTr>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self { blob } = self;\n        ensure!(\n            ccx.ecx.cfg().spec().into() >= SpecId::CANCUN,\n            \"`attachBlob` is not supported before the Cancun hard fork; \\\n             see EIP-4844: https://eips.ethereum.org/EIPS/eip-4844\"\n        );\n        let sidecar: SidecarBuilder<SimpleCoder> = SidecarBuilder::from_slice(blob);\n        let sidecar_variant = if ccx.ecx.cfg().spec().into() < SpecId::OSAKA {\n            sidecar.build_4844().map_err(|e| format!(\"{e}\"))?.into()\n        } else {\n            sidecar.build_7594().map_err(|e| format!(\"{e}\"))?.into()\n        };\n        ccx.state.active_blob_sidecar = Some(sidecar_variant);\n        Ok(Default::default())\n    }\n}\n\nimpl Cheatcode for startBroadcast_0Call {\n    fn apply_stateful<CTX: ContextTr<Journal: JournalExt, Db: DatabaseExt>>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n    ) -> Result {\n        let Self {} = self;\n        broadcast(ccx, None, false)\n    }\n}\n\nimpl Cheatcode for startBroadcast_1Call {\n    fn apply_stateful<CTX: ContextTr<Journal: JournalExt, Db: DatabaseExt>>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n    ) -> Result {\n        let Self { signer } = self;\n        broadcast(ccx, Some(signer), false)\n    }\n}\n\nimpl Cheatcode for startBroadcast_2Call {\n    fn apply_stateful<CTX: ContextTr<Journal: JournalExt, Db: DatabaseExt>>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n    ) -> Result {\n        let Self { privateKey } = self;\n        broadcast_key(ccx, privateKey, false)\n    }\n}\n\nimpl Cheatcode for stopBroadcastCall {\n    fn apply_stateful<CTX>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self {} = self;\n        let Some(broadcast) = ccx.state.broadcast.take() else {\n            bail!(\"no broadcast in progress to stop\");\n        };\n        debug!(target: \"cheatcodes\", ?broadcast, \"stopped\");\n        Ok(Default::default())\n    }\n}\n\nimpl Cheatcode for getWalletsCall {\n    fn apply_stateful<CTX>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let wallets = ccx.state.wallets().signers().unwrap_or_default();\n        Ok(wallets.abi_encode())\n    }\n}\n\n#[derive(Clone, Debug, Default)]\npub struct Broadcast {\n    /// Address of the transaction origin\n    pub new_origin: Address,\n    /// Original caller\n    pub original_caller: Address,\n    /// Original `tx.origin`\n    pub original_origin: Address,\n    /// Depth of the broadcast\n    pub depth: usize,\n    /// Whether the prank stops by itself after the next call\n    pub single_call: bool,\n    /// Whether `vm.deployCode` cheatcode is used to deploy from code.\n    pub deploy_from_code: bool,\n}\n\n/// Contains context for wallet management.\n#[derive(Debug)]\npub struct WalletsInner {\n    /// All signers in scope of the script.\n    pub multi_wallet: MultiWallet,\n    /// Optional signer provided as `--sender` flag.\n    pub provided_sender: Option<Address>,\n}\n\n/// Cloneable wrapper around [`WalletsInner`].\n#[derive(Debug, Clone)]\npub struct Wallets {\n    /// Inner data.\n    pub inner: Arc<Mutex<WalletsInner>>,\n}\n\nimpl Wallets {\n    #[expect(missing_docs)]\n    pub fn new(multi_wallet: MultiWallet, provided_sender: Option<Address>) -> Self {\n        Self { inner: Arc::new(Mutex::new(WalletsInner { multi_wallet, provided_sender })) }\n    }\n\n    /// Consumes [Wallets] and returns [MultiWallet].\n    ///\n    /// Panics if [Wallets] is still in use.\n    pub fn into_multi_wallet(self) -> MultiWallet {\n        Arc::into_inner(self.inner)\n            .map(|m| m.into_inner().multi_wallet)\n            .unwrap_or_else(|| panic!(\"not all instances were dropped\"))\n    }\n\n    /// Locks inner Mutex and adds a signer to the [MultiWallet].\n    pub fn add_local_signer(&self, wallet: PrivateKeySigner) {\n        self.inner.lock().multi_wallet.add_signer(WalletSigner::Local(wallet));\n    }\n\n    /// Locks inner Mutex and returns all signer addresses in the [MultiWallet].\n    pub fn signers(&self) -> Result<Vec<Address>> {\n        Ok(self.inner.lock().multi_wallet.signers()?.keys().copied().collect())\n    }\n\n    /// Number of signers in the [MultiWallet].\n    pub fn len(&self) -> usize {\n        let mut inner = self.inner.lock();\n        inner.multi_wallet.signers().map_or(0, |signers| signers.len())\n    }\n\n    /// Whether the [MultiWallet] is empty.\n    pub fn is_empty(&self) -> bool {\n        self.len() == 0\n    }\n}\n\n/// Sets up broadcasting from a script using `new_origin` as the sender.\nfn broadcast<CTX: ContextTr<Journal: JournalExt, Db: DatabaseExt>>(\n    ccx: &mut CheatsCtxt<'_, CTX>,\n    new_origin: Option<&Address>,\n    single_call: bool,\n) -> Result {\n    let depth = ccx.ecx.journal().depth();\n    ensure!(\n        ccx.state.get_prank(depth).is_none(),\n        \"you have an active prank; broadcasting and pranks are not compatible\"\n    );\n    ensure!(ccx.state.broadcast.is_none(), \"a broadcast is active already\");\n\n    let mut new_origin = new_origin.copied();\n\n    if new_origin.is_none() {\n        let mut wallets = ccx.state.wallets().inner.lock();\n        if let Some(provided_sender) = wallets.provided_sender {\n            new_origin = Some(provided_sender);\n        } else {\n            let signers = wallets.multi_wallet.signers()?;\n            if signers.len() == 1 {\n                let address = signers.keys().next().unwrap();\n                new_origin = Some(*address);\n            }\n        }\n    }\n    let new_origin = new_origin.unwrap_or(ccx.ecx.tx().caller());\n    // Ensure new origin is loaded and touched.\n    let _ = journaled_account(ccx.ecx, new_origin)?;\n\n    let broadcast = Broadcast {\n        new_origin,\n        original_caller: ccx.caller,\n        original_origin: ccx.ecx.tx().caller(),\n        depth,\n        single_call,\n        deploy_from_code: false,\n    };\n    debug!(target: \"cheatcodes\", ?broadcast, \"started\");\n    ccx.state.broadcast = Some(broadcast);\n    Ok(Default::default())\n}\n\n/// Sets up broadcasting from a script with the sender derived from `private_key`.\n/// Adds this private key to `state`'s `wallets` vector to later be used for signing\n/// if broadcast is successful.\nfn broadcast_key<CTX: ContextTr<Journal: JournalExt, Db: DatabaseExt>>(\n    ccx: &mut CheatsCtxt<'_, CTX>,\n    private_key: &U256,\n    single_call: bool,\n) -> Result {\n    let wallet = super::crypto::parse_wallet(private_key)?;\n    let new_origin = wallet.address();\n\n    let result = broadcast(ccx, Some(&new_origin), single_call);\n    if result.is_ok() {\n        let wallets = ccx.state.wallets();\n        wallets.add_local_signer(wallet);\n    }\n    result\n}\n"
  },
  {
    "path": "crates/cheatcodes/src/string.rs",
    "content": "//! Implementations of [`String`](spec::Group::String) cheatcodes.\n\nuse crate::{Cheatcode, Cheatcodes, Result, Vm::*};\nuse alloy_dyn_abi::{DynSolType, DynSolValue};\nuse alloy_primitives::{U256, hex};\nuse alloy_sol_types::SolValue;\n\n// address\nimpl Cheatcode for toString_0Call {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { value } = self;\n        Ok(value.to_string().abi_encode())\n    }\n}\n\n// bytes\nimpl Cheatcode for toString_1Call {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { value } = self;\n        Ok(value.to_string().abi_encode())\n    }\n}\n\n// bytes32\nimpl Cheatcode for toString_2Call {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { value } = self;\n        Ok(value.to_string().abi_encode())\n    }\n}\n\n// bool\nimpl Cheatcode for toString_3Call {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { value } = self;\n        Ok(value.to_string().abi_encode())\n    }\n}\n\n// uint256\nimpl Cheatcode for toString_4Call {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { value } = self;\n        Ok(value.to_string().abi_encode())\n    }\n}\n\n// int256\nimpl Cheatcode for toString_5Call {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { value } = self;\n        Ok(value.to_string().abi_encode())\n    }\n}\n\nimpl Cheatcode for parseBytesCall {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { stringifiedValue } = self;\n        parse(stringifiedValue, &DynSolType::Bytes)\n    }\n}\n\nimpl Cheatcode for parseAddressCall {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { stringifiedValue } = self;\n        parse(stringifiedValue, &DynSolType::Address)\n    }\n}\n\nimpl Cheatcode for parseUintCall {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { stringifiedValue } = self;\n        parse(stringifiedValue, &DynSolType::Uint(256))\n    }\n}\n\nimpl Cheatcode for parseIntCall {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { stringifiedValue } = self;\n        parse(stringifiedValue, &DynSolType::Int(256))\n    }\n}\n\nimpl Cheatcode for parseBytes32Call {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { stringifiedValue } = self;\n        parse(stringifiedValue, &DynSolType::FixedBytes(32))\n    }\n}\n\nimpl Cheatcode for parseBoolCall {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { stringifiedValue } = self;\n        parse(stringifiedValue, &DynSolType::Bool)\n    }\n}\n\nimpl Cheatcode for toLowercaseCall {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { input } = self;\n        Ok(input.to_lowercase().abi_encode())\n    }\n}\n\nimpl Cheatcode for toUppercaseCall {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { input } = self;\n        Ok(input.to_uppercase().abi_encode())\n    }\n}\n\nimpl Cheatcode for trimCall {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { input } = self;\n        Ok(input.trim().abi_encode())\n    }\n}\n\nimpl Cheatcode for replaceCall {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { input, from, to } = self;\n        Ok(input.replace(from, to).abi_encode())\n    }\n}\n\nimpl Cheatcode for splitCall {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { input, delimiter } = self;\n        let parts: Vec<&str> = input.split(delimiter).collect();\n        Ok(parts.abi_encode())\n    }\n}\n\nimpl Cheatcode for indexOfCall {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { input, key } = self;\n        Ok(input.find(key).map(U256::from).unwrap_or(U256::MAX).abi_encode())\n    }\n}\n\nimpl Cheatcode for containsCall {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { subject, search } = self;\n        Ok(subject.contains(search).abi_encode())\n    }\n}\n\npub(super) fn parse(s: &str, ty: &DynSolType) -> Result {\n    parse_value(s, ty).map(|v| v.abi_encode())\n}\n\npub(super) fn parse_array<I, S>(values: I, ty: &DynSolType) -> Result\nwhere\n    I: IntoIterator<Item = S>,\n    S: AsRef<str>,\n{\n    let mut values = values.into_iter();\n    match values.next() {\n        Some(first) if !first.as_ref().is_empty() => std::iter::once(first)\n            .chain(values)\n            .map(|s| parse_value(s.as_ref(), ty))\n            .collect::<Result<Vec<_>, _>>()\n            .map(|vec| DynSolValue::Array(vec).abi_encode()),\n        // return the empty encoded Bytes when values is empty or the first element is empty\n        _ => Ok(\"\".abi_encode()),\n    }\n}\n\npub(super) fn parse_value(s: &str, ty: &DynSolType) -> Result<DynSolValue> {\n    match ty.coerce_str(s) {\n        Ok(value) => Ok(value),\n        Err(e) => match parse_value_fallback(s, ty) {\n            Some(Ok(value)) => Ok(value),\n            Some(Err(e2)) => Err(fmt_err!(\"failed parsing {s:?} as type `{ty}`: {e2}\")),\n            None => Err(fmt_err!(\"failed parsing {s:?} as type `{ty}`: {e}\")),\n        },\n    }\n}\n\n// More lenient parsers than `coerce_str`.\nfn parse_value_fallback(s: &str, ty: &DynSolType) -> Option<Result<DynSolValue, &'static str>> {\n    match ty {\n        DynSolType::Bool => {\n            let b = match s {\n                \"1\" => true,\n                \"0\" => false,\n                s if s.eq_ignore_ascii_case(\"true\") => true,\n                s if s.eq_ignore_ascii_case(\"false\") => false,\n                _ => return None,\n            };\n            return Some(Ok(DynSolValue::Bool(b)));\n        }\n        DynSolType::Int(_)\n        | DynSolType::Uint(_)\n        | DynSolType::FixedBytes(_)\n        | DynSolType::Bytes\n            if !s.starts_with(\"0x\") && hex::check_raw(s) =>\n        {\n            return Some(Err(\"missing hex prefix (\\\"0x\\\") for hex string\"));\n        }\n        _ => {}\n    }\n    None\n}\n"
  },
  {
    "path": "crates/cheatcodes/src/test/assert.rs",
    "content": "use crate::{CheatcodesExecutor, CheatsCtxt, EthCheatCtx, Result, Vm::*};\nuse alloy_primitives::{I256, U256, U512};\nuse foundry_evm_core::{\n    abi::console::{format_units_int, format_units_uint},\n    backend::{DatabaseExt, GLOBAL_FAIL_SLOT},\n    constants::CHEATCODE_ADDRESS,\n};\nuse itertools::Itertools;\nuse revm::context::{ContextTr, JournalTr};\nuse std::{borrow::Cow, fmt};\n\nconst EQ_REL_DELTA_RESOLUTION: U256 = U256::from_limbs([18, 0, 0, 0]);\n\nstruct ComparisonAssertionError<'a, T> {\n    kind: AssertionKind,\n    left: &'a T,\n    right: &'a T,\n}\n\n#[derive(Clone, Copy)]\nenum AssertionKind {\n    Eq,\n    Ne,\n    Gt,\n    Ge,\n    Lt,\n    Le,\n}\n\nimpl AssertionKind {\n    fn inverse(self) -> Self {\n        match self {\n            Self::Eq => Self::Ne,\n            Self::Ne => Self::Eq,\n            Self::Gt => Self::Le,\n            Self::Ge => Self::Lt,\n            Self::Lt => Self::Ge,\n            Self::Le => Self::Gt,\n        }\n    }\n\n    fn to_str(self) -> &'static str {\n        match self {\n            Self::Eq => \"==\",\n            Self::Ne => \"!=\",\n            Self::Gt => \">\",\n            Self::Ge => \">=\",\n            Self::Lt => \"<\",\n            Self::Le => \"<=\",\n        }\n    }\n}\n\nimpl<T> ComparisonAssertionError<'_, T> {\n    fn format_values<D: fmt::Display>(&self, f: impl Fn(&T) -> D) -> String {\n        format!(\"{} {} {}\", f(self.left), self.kind.inverse().to_str(), f(self.right))\n    }\n}\n\nimpl<T: fmt::Display> ComparisonAssertionError<'_, T> {\n    fn format_for_values(&self) -> String {\n        self.format_values(T::to_string)\n    }\n}\n\nimpl<T: fmt::Display> ComparisonAssertionError<'_, Vec<T>> {\n    fn format_for_arrays(&self) -> String {\n        self.format_values(|v| format!(\"[{}]\", v.iter().format(\", \")))\n    }\n}\n\nimpl ComparisonAssertionError<'_, U256> {\n    fn format_with_decimals(&self, decimals: &U256) -> String {\n        self.format_values(|v| format_units_uint(v, decimals))\n    }\n}\n\nimpl ComparisonAssertionError<'_, I256> {\n    fn format_with_decimals(&self, decimals: &U256) -> String {\n        self.format_values(|v| format_units_int(v, decimals))\n    }\n}\n\n#[derive(thiserror::Error, Debug)]\n#[error(\"{left} !~= {right} (max delta: {max_delta}, real delta: {real_delta})\")]\nstruct EqAbsAssertionError<T, D> {\n    left: T,\n    right: T,\n    max_delta: D,\n    real_delta: D,\n}\n\nimpl EqAbsAssertionError<U256, U256> {\n    fn format_with_decimals(&self, decimals: &U256) -> String {\n        format!(\n            \"{} !~= {} (max delta: {}, real delta: {})\",\n            format_units_uint(&self.left, decimals),\n            format_units_uint(&self.right, decimals),\n            format_units_uint(&self.max_delta, decimals),\n            format_units_uint(&self.real_delta, decimals),\n        )\n    }\n}\n\nimpl EqAbsAssertionError<I256, U256> {\n    fn format_with_decimals(&self, decimals: &U256) -> String {\n        format!(\n            \"{} !~= {} (max delta: {}, real delta: {})\",\n            format_units_int(&self.left, decimals),\n            format_units_int(&self.right, decimals),\n            format_units_uint(&self.max_delta, decimals),\n            format_units_uint(&self.real_delta, decimals),\n        )\n    }\n}\n\nfn format_delta_percent(delta: &U256) -> String {\n    format!(\"{}%\", format_units_uint(delta, &(EQ_REL_DELTA_RESOLUTION - U256::from(2))))\n}\n\n#[derive(Debug)]\nenum EqRelDelta {\n    Defined(U256),\n    Undefined,\n}\n\nimpl fmt::Display for EqRelDelta {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        match self {\n            Self::Defined(delta) => write!(f, \"{}\", format_delta_percent(delta)),\n            Self::Undefined => write!(f, \"undefined\"),\n        }\n    }\n}\n\n#[derive(thiserror::Error, Debug)]\n#[error(\n    \"{left} !~= {right} (max delta: {}, real delta: {})\",\n    format_delta_percent(max_delta),\n    real_delta\n)]\nstruct EqRelAssertionFailure<T> {\n    left: T,\n    right: T,\n    max_delta: U256,\n    real_delta: EqRelDelta,\n}\n\n#[derive(thiserror::Error, Debug)]\nenum EqRelAssertionError<T> {\n    #[error(transparent)]\n    Failure(Box<EqRelAssertionFailure<T>>),\n    #[error(\"overflow in delta calculation\")]\n    Overflow,\n}\n\nimpl EqRelAssertionError<U256> {\n    fn format_with_decimals(&self, decimals: &U256) -> String {\n        match self {\n            Self::Failure(f) => format!(\n                \"{} !~= {} (max delta: {}, real delta: {})\",\n                format_units_uint(&f.left, decimals),\n                format_units_uint(&f.right, decimals),\n                format_delta_percent(&f.max_delta),\n                &f.real_delta,\n            ),\n            Self::Overflow => self.to_string(),\n        }\n    }\n}\n\nimpl EqRelAssertionError<I256> {\n    fn format_with_decimals(&self, decimals: &U256) -> String {\n        match self {\n            Self::Failure(f) => format!(\n                \"{} !~= {} (max delta: {}, real delta: {})\",\n                format_units_int(&f.left, decimals),\n                format_units_int(&f.right, decimals),\n                format_delta_percent(&f.max_delta),\n                &f.real_delta,\n            ),\n            Self::Overflow => self.to_string(),\n        }\n    }\n}\n\ntype ComparisonResult<'a, T> = Result<(), ComparisonAssertionError<'a, T>>;\n\n#[cold]\nfn handle_assertion_result<CTX: ContextTr<Db: DatabaseExt>, E>(\n    ccx: &mut CheatsCtxt<'_, CTX>,\n    executor: &mut dyn CheatcodesExecutor<CTX>,\n    err: E,\n    error_formatter: Option<&dyn Fn(&E) -> String>,\n    error_msg: Option<&str>,\n) -> Result {\n    let error_msg = error_msg.unwrap_or(\"assertion failed\");\n    let msg = if let Some(error_formatter) = error_formatter {\n        Cow::Owned(format!(\"{error_msg}: {}\", error_formatter(&err)))\n    } else {\n        Cow::Borrowed(error_msg)\n    };\n    handle_assertion_result_mono(ccx, executor, msg)\n}\n\nfn handle_assertion_result_mono<CTX: ContextTr<Db: DatabaseExt>>(\n    ccx: &mut CheatsCtxt<'_, CTX>,\n    executor: &mut dyn CheatcodesExecutor<CTX>,\n    msg: Cow<'_, str>,\n) -> Result {\n    if ccx.state.config.assertions_revert {\n        Err(msg.into_owned().into())\n    } else {\n        executor.console_log(ccx.state, &msg);\n        ccx.ecx.journal_mut().sstore(CHEATCODE_ADDRESS, GLOBAL_FAIL_SLOT, U256::from(1))?;\n        Ok(Default::default())\n    }\n}\n\n/// Implements [crate::Cheatcode] for pairs of cheatcodes.\n///\n/// Accepts a list of pairs of cheatcodes, where the first cheatcode is the one that doesn't contain\n/// a custom error message, and the second one contains it at `error` field.\n///\n/// Passed `args` are the common arguments for both cheatcode structs (excluding `error` field).\n///\n/// Macro also accepts an optional closure that formats the error returned by the assertion.\nmacro_rules! impl_assertions {\n    (|$($arg:ident),*| $body:expr, false, $(($no_error:ident, $with_error:ident)),* $(,)?) => {\n        impl_assertions! { @args_tt |($($arg),*)| $body, None, $(($no_error, $with_error)),* }\n    };\n    (|$($arg:ident),*| $body:expr, $(($no_error:ident, $with_error:ident)),* $(,)?) => {\n        impl_assertions! { @args_tt |($($arg),*)| $body, Some(&ToString::to_string), $(($no_error, $with_error)),* }\n    };\n    (|$($arg:ident),*| $body:expr, $error_formatter:expr, $(($no_error:ident, $with_error:ident)),* $(,)?) => {\n        impl_assertions! { @args_tt |($($arg),*)| $body, Some(&$error_formatter), $(($no_error, $with_error)),* }\n    };\n\n    // We convert args to `tt` and later expand them back into tuple to allow usage of expanded args inside of\n    // each assertion type context.\n    (@args_tt |$args:tt| $body:expr, $error_formatter:expr, $(($no_error:ident, $with_error:ident)),* $(,)?) => {\n        $(\n            impl_assertions! { @impl $no_error, $with_error, $args, $body, $error_formatter }\n        )*\n    };\n\n    (@impl $no_error:ident, $with_error:ident, ($($arg:ident),*), $body:expr, $error_formatter:expr) => {\n        impl crate::Cheatcode for $no_error {\n            fn apply_full<CTX: EthCheatCtx>(\n                &self,\n                ccx: &mut CheatsCtxt<'_, CTX>,\n                executor: &mut dyn CheatcodesExecutor<CTX>,\n            ) -> Result {\n                let Self { $($arg),* } = self;\n                match $body {\n                    Ok(()) => Ok(Default::default()),\n                    Err(err) => handle_assertion_result(ccx, executor, err, $error_formatter, None)\n                }\n            }\n        }\n\n        impl crate::Cheatcode for $with_error {\n            fn apply_full<CTX: EthCheatCtx>(\n                &self,\n                ccx: &mut CheatsCtxt<'_, CTX>,\n                executor: &mut dyn CheatcodesExecutor<CTX>,\n            ) -> Result {\n                let Self { $($arg,)* error } = self;\n                match $body {\n                    Ok(()) => Ok(Default::default()),\n                    Err(err) => handle_assertion_result(ccx, executor, err, $error_formatter, Some(error))\n                }\n            }\n        }\n    };\n}\n\nimpl_assertions! {\n    |condition| assert_true(*condition),\n    false,\n    (assertTrue_0Call, assertTrue_1Call),\n}\n\nimpl_assertions! {\n    |condition| assert_false(*condition),\n    false,\n    (assertFalse_0Call, assertFalse_1Call),\n}\n\nimpl_assertions! {\n    |left, right| assert_eq(left, right),\n    ComparisonAssertionError::format_for_values,\n    (assertEq_0Call, assertEq_1Call),\n    (assertEq_2Call, assertEq_3Call),\n    (assertEq_4Call, assertEq_5Call),\n    (assertEq_6Call, assertEq_7Call),\n    (assertEq_8Call, assertEq_9Call),\n    (assertEq_10Call, assertEq_11Call),\n    (assertEq_12Call, assertEq_13Call),\n}\n\nimpl_assertions! {\n    |left, right| assert_eq(left, right),\n    ComparisonAssertionError::format_for_arrays,\n    (assertEq_14Call, assertEq_15Call),\n    (assertEq_16Call, assertEq_17Call),\n    (assertEq_18Call, assertEq_19Call),\n    (assertEq_20Call, assertEq_21Call),\n    (assertEq_22Call, assertEq_23Call),\n    (assertEq_24Call, assertEq_25Call),\n    (assertEq_26Call, assertEq_27Call),\n}\n\nimpl_assertions! {\n    |left, right, decimals| assert_eq(left, right),\n    |e| e.format_with_decimals(decimals),\n    (assertEqDecimal_0Call, assertEqDecimal_1Call),\n    (assertEqDecimal_2Call, assertEqDecimal_3Call),\n}\n\nimpl_assertions! {\n    |left, right| assert_not_eq(left, right),\n    ComparisonAssertionError::format_for_values,\n    (assertNotEq_0Call, assertNotEq_1Call),\n    (assertNotEq_2Call, assertNotEq_3Call),\n    (assertNotEq_4Call, assertNotEq_5Call),\n    (assertNotEq_6Call, assertNotEq_7Call),\n    (assertNotEq_8Call, assertNotEq_9Call),\n    (assertNotEq_10Call, assertNotEq_11Call),\n    (assertNotEq_12Call, assertNotEq_13Call),\n}\n\nimpl_assertions! {\n    |left, right| assert_not_eq(left, right),\n    ComparisonAssertionError::format_for_arrays,\n    (assertNotEq_14Call, assertNotEq_15Call),\n    (assertNotEq_16Call, assertNotEq_17Call),\n    (assertNotEq_18Call, assertNotEq_19Call),\n    (assertNotEq_20Call, assertNotEq_21Call),\n    (assertNotEq_22Call, assertNotEq_23Call),\n    (assertNotEq_24Call, assertNotEq_25Call),\n    (assertNotEq_26Call, assertNotEq_27Call),\n}\n\nimpl_assertions! {\n    |left, right, decimals| assert_not_eq(left, right),\n    |e| e.format_with_decimals(decimals),\n    (assertNotEqDecimal_0Call, assertNotEqDecimal_1Call),\n    (assertNotEqDecimal_2Call, assertNotEqDecimal_3Call),\n}\n\nimpl_assertions! {\n    |left, right| assert_gt(left, right),\n    ComparisonAssertionError::format_for_values,\n    (assertGt_0Call, assertGt_1Call),\n    (assertGt_2Call, assertGt_3Call),\n}\n\nimpl_assertions! {\n    |left, right, decimals| assert_gt(left, right),\n    |e| e.format_with_decimals(decimals),\n    (assertGtDecimal_0Call, assertGtDecimal_1Call),\n    (assertGtDecimal_2Call, assertGtDecimal_3Call),\n}\n\nimpl_assertions! {\n    |left, right| assert_ge(left, right),\n    ComparisonAssertionError::format_for_values,\n    (assertGe_0Call, assertGe_1Call),\n    (assertGe_2Call, assertGe_3Call),\n}\n\nimpl_assertions! {\n    |left, right, decimals| assert_ge(left, right),\n    |e| e.format_with_decimals(decimals),\n    (assertGeDecimal_0Call, assertGeDecimal_1Call),\n    (assertGeDecimal_2Call, assertGeDecimal_3Call),\n}\n\nimpl_assertions! {\n    |left, right| assert_lt(left, right),\n    ComparisonAssertionError::format_for_values,\n    (assertLt_0Call, assertLt_1Call),\n    (assertLt_2Call, assertLt_3Call),\n}\n\nimpl_assertions! {\n    |left, right, decimals| assert_lt(left, right),\n    |e| e.format_with_decimals(decimals),\n    (assertLtDecimal_0Call, assertLtDecimal_1Call),\n    (assertLtDecimal_2Call, assertLtDecimal_3Call),\n}\n\nimpl_assertions! {\n    |left, right| assert_le(left, right),\n    ComparisonAssertionError::format_for_values,\n    (assertLe_0Call, assertLe_1Call),\n    (assertLe_2Call, assertLe_3Call),\n}\n\nimpl_assertions! {\n    |left, right, decimals| assert_le(left, right),\n    |e| e.format_with_decimals(decimals),\n    (assertLeDecimal_0Call, assertLeDecimal_1Call),\n    (assertLeDecimal_2Call, assertLeDecimal_3Call),\n}\n\nimpl_assertions! {\n    |left, right, maxDelta| uint_assert_approx_eq_abs(*left, *right, *maxDelta),\n    (assertApproxEqAbs_0Call, assertApproxEqAbs_1Call),\n}\n\nimpl_assertions! {\n    |left, right, maxDelta| int_assert_approx_eq_abs(*left, *right, *maxDelta),\n    (assertApproxEqAbs_2Call, assertApproxEqAbs_3Call),\n}\n\nimpl_assertions! {\n    |left, right, decimals, maxDelta| uint_assert_approx_eq_abs(*left, *right, *maxDelta),\n    |e| e.format_with_decimals(decimals),\n    (assertApproxEqAbsDecimal_0Call, assertApproxEqAbsDecimal_1Call),\n}\n\nimpl_assertions! {\n    |left, right, decimals, maxDelta| int_assert_approx_eq_abs(*left, *right, *maxDelta),\n    |e| e.format_with_decimals(decimals),\n    (assertApproxEqAbsDecimal_2Call, assertApproxEqAbsDecimal_3Call),\n}\n\nimpl_assertions! {\n    |left, right, maxPercentDelta| uint_assert_approx_eq_rel(*left, *right, *maxPercentDelta),\n    (assertApproxEqRel_0Call, assertApproxEqRel_1Call),\n}\n\nimpl_assertions! {\n    |left, right, maxPercentDelta| int_assert_approx_eq_rel(*left, *right, *maxPercentDelta),\n    (assertApproxEqRel_2Call, assertApproxEqRel_3Call),\n}\n\nimpl_assertions! {\n    |left, right, decimals, maxPercentDelta| uint_assert_approx_eq_rel(*left, *right, *maxPercentDelta),\n    |e| e.format_with_decimals(decimals),\n    (assertApproxEqRelDecimal_0Call, assertApproxEqRelDecimal_1Call),\n}\n\nimpl_assertions! {\n    |left, right, decimals, maxPercentDelta| int_assert_approx_eq_rel(*left, *right, *maxPercentDelta),\n    |e| e.format_with_decimals(decimals),\n    (assertApproxEqRelDecimal_2Call, assertApproxEqRelDecimal_3Call),\n}\n\nfn assert_true(condition: bool) -> Result<(), ()> {\n    if condition { Ok(()) } else { Err(()) }\n}\n\nfn assert_false(condition: bool) -> Result<(), ()> {\n    assert_true(!condition)\n}\n\nfn assert_eq<'a, T: PartialEq>(left: &'a T, right: &'a T) -> ComparisonResult<'a, T> {\n    if left == right {\n        Ok(())\n    } else {\n        Err(ComparisonAssertionError { kind: AssertionKind::Eq, left, right })\n    }\n}\n\nfn assert_not_eq<'a, T: PartialEq>(left: &'a T, right: &'a T) -> ComparisonResult<'a, T> {\n    if left != right {\n        Ok(())\n    } else {\n        Err(ComparisonAssertionError { kind: AssertionKind::Ne, left, right })\n    }\n}\n\nfn assert_gt<'a, T: PartialOrd>(left: &'a T, right: &'a T) -> ComparisonResult<'a, T> {\n    if left > right {\n        Ok(())\n    } else {\n        Err(ComparisonAssertionError { kind: AssertionKind::Gt, left, right })\n    }\n}\n\nfn assert_ge<'a, T: PartialOrd>(left: &'a T, right: &'a T) -> ComparisonResult<'a, T> {\n    if left >= right {\n        Ok(())\n    } else {\n        Err(ComparisonAssertionError { kind: AssertionKind::Ge, left, right })\n    }\n}\n\nfn assert_lt<'a, T: PartialOrd>(left: &'a T, right: &'a T) -> ComparisonResult<'a, T> {\n    if left < right {\n        Ok(())\n    } else {\n        Err(ComparisonAssertionError { kind: AssertionKind::Lt, left, right })\n    }\n}\n\nfn assert_le<'a, T: PartialOrd>(left: &'a T, right: &'a T) -> ComparisonResult<'a, T> {\n    if left <= right {\n        Ok(())\n    } else {\n        Err(ComparisonAssertionError { kind: AssertionKind::Le, left, right })\n    }\n}\n\nfn get_delta_int(left: I256, right: I256) -> U256 {\n    let (left_sign, left_abs) = left.into_sign_and_abs();\n    let (right_sign, right_abs) = right.into_sign_and_abs();\n\n    if left_sign == right_sign {\n        if left_abs > right_abs { left_abs - right_abs } else { right_abs - left_abs }\n    } else {\n        left_abs.wrapping_add(right_abs)\n    }\n}\n\n/// Calculates the relative delta for an absolute difference.\n///\n/// Avoids overflow in the multiplication by using [`U512`] to hold the intermediary result.\nfn calc_delta_full<T>(abs_diff: U256, right: U256) -> Result<U256, EqRelAssertionError<T>> {\n    let delta = U512::from(abs_diff) * U512::from(10).pow(U512::from(EQ_REL_DELTA_RESOLUTION))\n        / U512::from(right);\n    U256::checked_from_limbs_slice(delta.as_limbs()).ok_or(EqRelAssertionError::Overflow)\n}\n\nfn uint_assert_approx_eq_abs(\n    left: U256,\n    right: U256,\n    max_delta: U256,\n) -> Result<(), Box<EqAbsAssertionError<U256, U256>>> {\n    let delta = left.abs_diff(right);\n\n    if delta <= max_delta {\n        Ok(())\n    } else {\n        Err(Box::new(EqAbsAssertionError { left, right, max_delta, real_delta: delta }))\n    }\n}\n\nfn int_assert_approx_eq_abs(\n    left: I256,\n    right: I256,\n    max_delta: U256,\n) -> Result<(), Box<EqAbsAssertionError<I256, U256>>> {\n    let delta = get_delta_int(left, right);\n\n    if delta <= max_delta {\n        Ok(())\n    } else {\n        Err(Box::new(EqAbsAssertionError { left, right, max_delta, real_delta: delta }))\n    }\n}\n\nfn uint_assert_approx_eq_rel(\n    left: U256,\n    right: U256,\n    max_delta: U256,\n) -> Result<(), EqRelAssertionError<U256>> {\n    if right.is_zero() {\n        if left.is_zero() {\n            return Ok(());\n        } else {\n            return Err(EqRelAssertionError::Failure(Box::new(EqRelAssertionFailure {\n                left,\n                right,\n                max_delta,\n                real_delta: EqRelDelta::Undefined,\n            })));\n        };\n    }\n\n    let delta = calc_delta_full::<U256>(left.abs_diff(right), right)?;\n\n    if delta <= max_delta {\n        Ok(())\n    } else {\n        Err(EqRelAssertionError::Failure(Box::new(EqRelAssertionFailure {\n            left,\n            right,\n            max_delta,\n            real_delta: EqRelDelta::Defined(delta),\n        })))\n    }\n}\n\nfn int_assert_approx_eq_rel(\n    left: I256,\n    right: I256,\n    max_delta: U256,\n) -> Result<(), EqRelAssertionError<I256>> {\n    if right.is_zero() {\n        if left.is_zero() {\n            return Ok(());\n        } else {\n            return Err(EqRelAssertionError::Failure(Box::new(EqRelAssertionFailure {\n                left,\n                right,\n                max_delta,\n                real_delta: EqRelDelta::Undefined,\n            })));\n        }\n    }\n\n    let delta = calc_delta_full::<I256>(get_delta_int(left, right), right.unsigned_abs())?;\n\n    if delta <= max_delta {\n        Ok(())\n    } else {\n        Err(EqRelAssertionError::Failure(Box::new(EqRelAssertionFailure {\n            left,\n            right,\n            max_delta,\n            real_delta: EqRelDelta::Defined(delta),\n        })))\n    }\n}\n"
  },
  {
    "path": "crates/cheatcodes/src/test/assume.rs",
    "content": "use crate::{Cheatcode, Cheatcodes, CheatsCtxt, Error, Result};\nuse alloy_primitives::Address;\nuse foundry_evm_core::constants::MAGIC_ASSUME;\nuse revm::context::{ContextTr, JournalTr};\nuse spec::Vm::{\n    PotentialRevert, assumeCall, assumeNoRevert_0Call, assumeNoRevert_1Call, assumeNoRevert_2Call,\n};\nuse std::fmt::Debug;\n\n#[derive(Clone, Debug)]\npub struct AssumeNoRevert {\n    /// The call depth at which the cheatcode was added.\n    pub depth: usize,\n    /// Acceptable revert parameters for the next call, to be thrown out if they are encountered;\n    /// reverts with parameters not specified here will count as normal reverts and not rejects\n    /// towards the counter.\n    pub reasons: Vec<AcceptableRevertParameters>,\n    /// Address that reverted the call.\n    pub reverted_by: Option<Address>,\n}\n\n/// Parameters for a single anticipated revert, to be thrown out if encountered.\n#[derive(Clone, Debug)]\npub struct AcceptableRevertParameters {\n    /// The expected revert data returned by the revert\n    pub reason: Vec<u8>,\n    /// If true then only the first 4 bytes of expected data returned by the revert are checked.\n    pub partial_match: bool,\n    /// Contract expected to revert next call.\n    pub reverter: Option<Address>,\n}\n\nimpl AcceptableRevertParameters {\n    fn from(potential_revert: &PotentialRevert) -> Self {\n        Self {\n            reason: potential_revert.revertData.to_vec(),\n            partial_match: potential_revert.partialMatch,\n            reverter: if potential_revert.reverter == Address::ZERO {\n                None\n            } else {\n                Some(potential_revert.reverter)\n            },\n        }\n    }\n}\n\nimpl Cheatcode for assumeCall {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { condition } = self;\n        if *condition { Ok(Default::default()) } else { Err(Error::from(MAGIC_ASSUME)) }\n    }\n}\n\nimpl Cheatcode for assumeNoRevert_0Call {\n    fn apply_stateful<CTX: ContextTr>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        assume_no_revert(ccx.state, ccx.ecx.journal().depth(), vec![])\n    }\n}\n\nimpl Cheatcode for assumeNoRevert_1Call {\n    fn apply_stateful<CTX: ContextTr>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self { potentialRevert } = self;\n        assume_no_revert(\n            ccx.state,\n            ccx.ecx.journal().depth(),\n            vec![AcceptableRevertParameters::from(potentialRevert)],\n        )\n    }\n}\n\nimpl Cheatcode for assumeNoRevert_2Call {\n    fn apply_stateful<CTX: ContextTr>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self { potentialReverts } = self;\n        assume_no_revert(\n            ccx.state,\n            ccx.ecx.journal().depth(),\n            potentialReverts.iter().map(AcceptableRevertParameters::from).collect(),\n        )\n    }\n}\n\nfn assume_no_revert(\n    state: &mut Cheatcodes,\n    depth: usize,\n    parameters: Vec<AcceptableRevertParameters>,\n) -> Result {\n    ensure!(\n        state.assume_no_revert.is_none(),\n        \"you must make another external call prior to calling assumeNoRevert again\"\n    );\n\n    state.assume_no_revert = Some(AssumeNoRevert { depth, reasons: parameters, reverted_by: None });\n\n    Ok(Default::default())\n}\n"
  },
  {
    "path": "crates/cheatcodes/src/test/expect.rs",
    "content": "use std::{\n    collections::VecDeque,\n    fmt::{self, Display},\n};\n\nuse crate::{Cheatcode, Cheatcodes, CheatsCtxt, Error, Result, Vm::*};\nuse alloy_dyn_abi::{DynSolValue, EventExt};\nuse alloy_json_abi::Event;\nuse alloy_primitives::{\n    Address, Bytes, LogData as RawLog, U256, hex,\n    map::{AddressHashMap, HashMap, hash_map::Entry},\n};\nuse foundry_common::{abi::get_indexed_event, fmt::format_token};\nuse foundry_evm_traces::DecodedCallLog;\nuse revm::{\n    context::{ContextTr, JournalTr},\n    interpreter::{\n        InstructionResult, Interpreter, InterpreterAction, interpreter_types::LoopControl,\n    },\n};\n\nuse super::revert_handlers::RevertParameters;\n/// Tracks the expected calls per address.\n///\n/// For each address, we track the expected calls per call data. We track it in such manner\n/// so that we don't mix together calldatas that only contain selectors and calldatas that contain\n/// selector and arguments (partial and full matches).\n///\n/// This then allows us to customize the matching behavior for each call data on the\n/// `ExpectedCallData` struct and track how many times we've actually seen the call on the second\n/// element of the tuple.\npub type ExpectedCallTracker = HashMap<Address, HashMap<Bytes, (ExpectedCallData, u64)>>;\n\n#[derive(Clone, Debug)]\npub struct ExpectedCallData {\n    /// The expected value sent in the call\n    pub value: Option<U256>,\n    /// The expected gas supplied to the call\n    pub gas: Option<u64>,\n    /// The expected *minimum* gas supplied to the call\n    pub min_gas: Option<u64>,\n    /// The number of times the call is expected to be made.\n    /// If the type of call is `NonCount`, this is the lower bound for the number of calls\n    /// that must be seen.\n    /// If the type of call is `Count`, this is the exact number of calls that must be seen.\n    pub count: u64,\n    /// The type of expected call.\n    pub call_type: ExpectedCallType,\n}\n\n/// The type of expected call.\n#[derive(Clone, Debug, PartialEq, Eq)]\npub enum ExpectedCallType {\n    /// The call is expected to be made at least once.\n    NonCount,\n    /// The exact number of calls expected.\n    Count,\n}\n\n/// The type of expected revert.\n#[derive(Clone, Debug)]\npub enum ExpectedRevertKind {\n    /// Expects revert from the next non-cheatcode call.\n    Default,\n    /// Expects revert from the next cheatcode call.\n    ///\n    /// The `pending_processing` flag is used to track whether we have exited\n    /// `expectCheatcodeRevert` context or not.\n    /// We have to track it to avoid expecting `expectCheatcodeRevert` call to revert itself.\n    Cheatcode { pending_processing: bool },\n}\n\n#[derive(Clone, Debug)]\npub struct ExpectedRevert {\n    /// The expected data returned by the revert, None being any.\n    pub reason: Option<Bytes>,\n    /// The depth at which the revert is expected.\n    pub depth: usize,\n    /// The type of expected revert.\n    pub kind: ExpectedRevertKind,\n    /// If true then only the first 4 bytes of expected data returned by the revert are checked.\n    pub partial_match: bool,\n    /// Contract expected to revert next call.\n    pub reverter: Option<Address>,\n    /// Address that reverted the call.\n    pub reverted_by: Option<Address>,\n    /// Max call depth reached during next call execution.\n    pub max_depth: usize,\n    /// Number of times this revert is expected.\n    pub count: u64,\n    /// Actual number of times this revert has been seen.\n    pub actual_count: u64,\n}\n\n#[derive(Clone, Debug)]\npub struct ExpectedEmit {\n    /// The depth at which we expect this emit to have occurred\n    pub depth: usize,\n    /// The log we expect\n    pub log: Option<RawLog>,\n    /// The checks to perform:\n    /// ```text\n    /// ┌───────┬───────┬───────┬───────┬────┐\n    /// │topic 0│topic 1│topic 2│topic 3│data│\n    /// └───────┴───────┴───────┴───────┴────┘\n    /// ```\n    pub checks: [bool; 5],\n    /// If present, check originating address against this\n    pub address: Option<Address>,\n    /// If present, relax the requirement that topic 0 must be present. This allows anonymous\n    /// events with no indexed topics to be matched.\n    pub anonymous: bool,\n    /// Whether the log was actually found in the subcalls\n    pub found: bool,\n    /// Number of times the log is expected to be emitted\n    pub count: u64,\n    /// Stores mismatch details if a log didn't match\n    pub mismatch_error: Option<String>,\n}\n\n#[derive(Clone, Debug)]\npub struct ExpectedCreate {\n    /// The address that deployed the contract\n    pub deployer: Address,\n    /// Runtime bytecode of the contract\n    pub bytecode: Bytes,\n    /// Whether deployed with CREATE or CREATE2\n    pub create_scheme: CreateScheme,\n}\n\n#[derive(Clone, Debug)]\npub enum CreateScheme {\n    Create,\n    Create2,\n}\n\nimpl Display for CreateScheme {\n    fn fmt(&self, f: &mut fmt::Formatter) -> std::fmt::Result {\n        match self {\n            Self::Create => write!(f, \"CREATE\"),\n            Self::Create2 => write!(f, \"CREATE2\"),\n        }\n    }\n}\n\nimpl From<revm::context_interface::CreateScheme> for CreateScheme {\n    fn from(scheme: revm::context_interface::CreateScheme) -> Self {\n        match scheme {\n            revm::context_interface::CreateScheme::Create => Self::Create,\n            revm::context_interface::CreateScheme::Create2 { .. } => Self::Create2,\n            _ => unimplemented!(\"Unsupported create scheme\"),\n        }\n    }\n}\n\nimpl CreateScheme {\n    pub fn eq(&self, create_scheme: Self) -> bool {\n        matches!(\n            (self, create_scheme),\n            (Self::Create, Self::Create) | (Self::Create2, Self::Create2 { .. })\n        )\n    }\n}\n\nimpl Cheatcode for expectCall_0Call {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { callee, data } = self;\n        expect_call(state, callee, data, None, None, None, 1, ExpectedCallType::NonCount)\n    }\n}\n\nimpl Cheatcode for expectCall_1Call {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { callee, data, count } = self;\n        expect_call(state, callee, data, None, None, None, *count, ExpectedCallType::Count)\n    }\n}\n\nimpl Cheatcode for expectCall_2Call {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { callee, msgValue, data } = self;\n        expect_call(state, callee, data, Some(msgValue), None, None, 1, ExpectedCallType::NonCount)\n    }\n}\n\nimpl Cheatcode for expectCall_3Call {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { callee, msgValue, data, count } = self;\n        expect_call(\n            state,\n            callee,\n            data,\n            Some(msgValue),\n            None,\n            None,\n            *count,\n            ExpectedCallType::Count,\n        )\n    }\n}\n\nimpl Cheatcode for expectCall_4Call {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { callee, msgValue, gas, data } = self;\n        expect_call(\n            state,\n            callee,\n            data,\n            Some(msgValue),\n            Some(*gas),\n            None,\n            1,\n            ExpectedCallType::NonCount,\n        )\n    }\n}\n\nimpl Cheatcode for expectCall_5Call {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { callee, msgValue, gas, data, count } = self;\n        expect_call(\n            state,\n            callee,\n            data,\n            Some(msgValue),\n            Some(*gas),\n            None,\n            *count,\n            ExpectedCallType::Count,\n        )\n    }\n}\n\nimpl Cheatcode for expectCallMinGas_0Call {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { callee, msgValue, minGas, data } = self;\n        expect_call(\n            state,\n            callee,\n            data,\n            Some(msgValue),\n            None,\n            Some(*minGas),\n            1,\n            ExpectedCallType::NonCount,\n        )\n    }\n}\n\nimpl Cheatcode for expectCallMinGas_1Call {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { callee, msgValue, minGas, data, count } = self;\n        expect_call(\n            state,\n            callee,\n            data,\n            Some(msgValue),\n            None,\n            Some(*minGas),\n            *count,\n            ExpectedCallType::Count,\n        )\n    }\n}\n\nimpl Cheatcode for expectEmit_0Call {\n    fn apply_stateful<CTX: ContextTr>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self { checkTopic1, checkTopic2, checkTopic3, checkData } = *self;\n        expect_emit(\n            ccx.state,\n            ccx.ecx.journal().depth(),\n            [true, checkTopic1, checkTopic2, checkTopic3, checkData],\n            None,\n            false,\n            1,\n        )\n    }\n}\n\nimpl Cheatcode for expectEmit_1Call {\n    fn apply_stateful<CTX: ContextTr>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self { checkTopic1, checkTopic2, checkTopic3, checkData, emitter } = *self;\n        expect_emit(\n            ccx.state,\n            ccx.ecx.journal().depth(),\n            [true, checkTopic1, checkTopic2, checkTopic3, checkData],\n            Some(emitter),\n            false,\n            1,\n        )\n    }\n}\n\nimpl Cheatcode for expectEmit_2Call {\n    fn apply_stateful<CTX: ContextTr>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self {} = self;\n        expect_emit(ccx.state, ccx.ecx.journal().depth(), [true; 5], None, false, 1)\n    }\n}\n\nimpl Cheatcode for expectEmit_3Call {\n    fn apply_stateful<CTX: ContextTr>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self { emitter } = *self;\n        expect_emit(ccx.state, ccx.ecx.journal().depth(), [true; 5], Some(emitter), false, 1)\n    }\n}\n\nimpl Cheatcode for expectEmit_4Call {\n    fn apply_stateful<CTX: ContextTr>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self { checkTopic1, checkTopic2, checkTopic3, checkData, count } = *self;\n        expect_emit(\n            ccx.state,\n            ccx.ecx.journal().depth(),\n            [true, checkTopic1, checkTopic2, checkTopic3, checkData],\n            None,\n            false,\n            count,\n        )\n    }\n}\n\nimpl Cheatcode for expectEmit_5Call {\n    fn apply_stateful<CTX: ContextTr>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self { checkTopic1, checkTopic2, checkTopic3, checkData, emitter, count } = *self;\n        expect_emit(\n            ccx.state,\n            ccx.ecx.journal().depth(),\n            [true, checkTopic1, checkTopic2, checkTopic3, checkData],\n            Some(emitter),\n            false,\n            count,\n        )\n    }\n}\n\nimpl Cheatcode for expectEmit_6Call {\n    fn apply_stateful<CTX: ContextTr>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self { count } = *self;\n        expect_emit(ccx.state, ccx.ecx.journal().depth(), [true; 5], None, false, count)\n    }\n}\n\nimpl Cheatcode for expectEmit_7Call {\n    fn apply_stateful<CTX: ContextTr>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self { emitter, count } = *self;\n        expect_emit(ccx.state, ccx.ecx.journal().depth(), [true; 5], Some(emitter), false, count)\n    }\n}\n\nimpl Cheatcode for expectEmitAnonymous_0Call {\n    fn apply_stateful<CTX: ContextTr>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self { checkTopic0, checkTopic1, checkTopic2, checkTopic3, checkData } = *self;\n        expect_emit(\n            ccx.state,\n            ccx.ecx.journal().depth(),\n            [checkTopic0, checkTopic1, checkTopic2, checkTopic3, checkData],\n            None,\n            true,\n            1,\n        )\n    }\n}\n\nimpl Cheatcode for expectEmitAnonymous_1Call {\n    fn apply_stateful<CTX: ContextTr>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self { checkTopic0, checkTopic1, checkTopic2, checkTopic3, checkData, emitter } = *self;\n        expect_emit(\n            ccx.state,\n            ccx.ecx.journal().depth(),\n            [checkTopic0, checkTopic1, checkTopic2, checkTopic3, checkData],\n            Some(emitter),\n            true,\n            1,\n        )\n    }\n}\n\nimpl Cheatcode for expectEmitAnonymous_2Call {\n    fn apply_stateful<CTX: ContextTr>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self {} = self;\n        expect_emit(ccx.state, ccx.ecx.journal().depth(), [true; 5], None, true, 1)\n    }\n}\n\nimpl Cheatcode for expectEmitAnonymous_3Call {\n    fn apply_stateful<CTX: ContextTr>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self { emitter } = *self;\n        expect_emit(ccx.state, ccx.ecx.journal().depth(), [true; 5], Some(emitter), true, 1)\n    }\n}\n\nimpl Cheatcode for expectCreateCall {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { bytecode, deployer } = self;\n        expect_create(state, bytecode.clone(), *deployer, CreateScheme::Create)\n    }\n}\n\nimpl Cheatcode for expectCreate2Call {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { bytecode, deployer } = self;\n        expect_create(state, bytecode.clone(), *deployer, CreateScheme::Create2)\n    }\n}\n\nimpl Cheatcode for expectRevert_0Call {\n    fn apply_stateful<CTX: ContextTr>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self {} = self;\n        expect_revert(ccx.state, None, ccx.ecx.journal().depth(), false, false, None, 1)\n    }\n}\n\nimpl Cheatcode for expectRevert_1Call {\n    fn apply_stateful<CTX: ContextTr>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self { revertData } = self;\n        expect_revert(\n            ccx.state,\n            Some(revertData.as_ref()),\n            ccx.ecx.journal().depth(),\n            false,\n            false,\n            None,\n            1,\n        )\n    }\n}\n\nimpl Cheatcode for expectRevert_2Call {\n    fn apply_stateful<CTX: ContextTr>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self { revertData } = self;\n        expect_revert(ccx.state, Some(revertData), ccx.ecx.journal().depth(), false, false, None, 1)\n    }\n}\n\nimpl Cheatcode for expectRevert_3Call {\n    fn apply_stateful<CTX: ContextTr>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self { reverter } = self;\n        expect_revert(ccx.state, None, ccx.ecx.journal().depth(), false, false, Some(*reverter), 1)\n    }\n}\n\nimpl Cheatcode for expectRevert_4Call {\n    fn apply_stateful<CTX: ContextTr>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self { revertData, reverter } = self;\n        expect_revert(\n            ccx.state,\n            Some(revertData.as_ref()),\n            ccx.ecx.journal().depth(),\n            false,\n            false,\n            Some(*reverter),\n            1,\n        )\n    }\n}\n\nimpl Cheatcode for expectRevert_5Call {\n    fn apply_stateful<CTX: ContextTr>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self { revertData, reverter } = self;\n        expect_revert(\n            ccx.state,\n            Some(revertData),\n            ccx.ecx.journal().depth(),\n            false,\n            false,\n            Some(*reverter),\n            1,\n        )\n    }\n}\n\nimpl Cheatcode for expectRevert_6Call {\n    fn apply_stateful<CTX: ContextTr>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self { count } = self;\n        expect_revert(ccx.state, None, ccx.ecx.journal().depth(), false, false, None, *count)\n    }\n}\n\nimpl Cheatcode for expectRevert_7Call {\n    fn apply_stateful<CTX: ContextTr>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self { revertData, count } = self;\n        expect_revert(\n            ccx.state,\n            Some(revertData.as_ref()),\n            ccx.ecx.journal().depth(),\n            false,\n            false,\n            None,\n            *count,\n        )\n    }\n}\n\nimpl Cheatcode for expectRevert_8Call {\n    fn apply_stateful<CTX: ContextTr>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self { revertData, count } = self;\n        expect_revert(\n            ccx.state,\n            Some(revertData),\n            ccx.ecx.journal().depth(),\n            false,\n            false,\n            None,\n            *count,\n        )\n    }\n}\n\nimpl Cheatcode for expectRevert_9Call {\n    fn apply_stateful<CTX: ContextTr>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self { reverter, count } = self;\n        expect_revert(\n            ccx.state,\n            None,\n            ccx.ecx.journal().depth(),\n            false,\n            false,\n            Some(*reverter),\n            *count,\n        )\n    }\n}\n\nimpl Cheatcode for expectRevert_10Call {\n    fn apply_stateful<CTX: ContextTr>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self { revertData, reverter, count } = self;\n        expect_revert(\n            ccx.state,\n            Some(revertData.as_ref()),\n            ccx.ecx.journal().depth(),\n            false,\n            false,\n            Some(*reverter),\n            *count,\n        )\n    }\n}\n\nimpl Cheatcode for expectRevert_11Call {\n    fn apply_stateful<CTX: ContextTr>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self { revertData, reverter, count } = self;\n        expect_revert(\n            ccx.state,\n            Some(revertData),\n            ccx.ecx.journal().depth(),\n            false,\n            false,\n            Some(*reverter),\n            *count,\n        )\n    }\n}\n\nimpl Cheatcode for expectPartialRevert_0Call {\n    fn apply_stateful<CTX: ContextTr>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self { revertData } = self;\n        expect_revert(\n            ccx.state,\n            Some(revertData.as_ref()),\n            ccx.ecx.journal().depth(),\n            false,\n            true,\n            None,\n            1,\n        )\n    }\n}\n\nimpl Cheatcode for expectPartialRevert_1Call {\n    fn apply_stateful<CTX: ContextTr>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self { revertData, reverter } = self;\n        expect_revert(\n            ccx.state,\n            Some(revertData.as_ref()),\n            ccx.ecx.journal().depth(),\n            false,\n            true,\n            Some(*reverter),\n            1,\n        )\n    }\n}\n\nimpl Cheatcode for _expectCheatcodeRevert_0Call {\n    fn apply_stateful<CTX: ContextTr>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        expect_revert(ccx.state, None, ccx.ecx.journal().depth(), true, false, None, 1)\n    }\n}\n\nimpl Cheatcode for _expectCheatcodeRevert_1Call {\n    fn apply_stateful<CTX: ContextTr>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self { revertData } = self;\n        expect_revert(\n            ccx.state,\n            Some(revertData.as_ref()),\n            ccx.ecx.journal().depth(),\n            true,\n            false,\n            None,\n            1,\n        )\n    }\n}\n\nimpl Cheatcode for _expectCheatcodeRevert_2Call {\n    fn apply_stateful<CTX: ContextTr>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self { revertData } = self;\n        expect_revert(ccx.state, Some(revertData), ccx.ecx.journal().depth(), true, false, None, 1)\n    }\n}\n\nimpl Cheatcode for expectSafeMemoryCall {\n    fn apply_stateful<CTX: ContextTr>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self { min, max } = *self;\n        expect_safe_memory(ccx.state, min, max, ccx.ecx.journal().depth().try_into()?)\n    }\n}\n\nimpl Cheatcode for stopExpectSafeMemoryCall {\n    fn apply_stateful<CTX: ContextTr>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self {} = self;\n        ccx.state.allowed_mem_writes.remove(&ccx.ecx.journal().depth().try_into()?);\n        Ok(Default::default())\n    }\n}\n\nimpl Cheatcode for expectSafeMemoryCallCall {\n    fn apply_stateful<CTX: ContextTr>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self { min, max } = *self;\n        expect_safe_memory(ccx.state, min, max, (ccx.ecx.journal().depth() + 1).try_into()?)\n    }\n}\n\nimpl RevertParameters for ExpectedRevert {\n    fn reverter(&self) -> Option<Address> {\n        self.reverter\n    }\n\n    fn reason(&self) -> Option<&[u8]> {\n        self.reason.as_ref().map(|b| &***b)\n    }\n\n    fn partial_match(&self) -> bool {\n        self.partial_match\n    }\n}\n\n/// Handles expected calls specified by the `expectCall` cheatcodes.\n///\n/// It can handle calls in two ways:\n/// - If the cheatcode was used with a `count` argument, it will expect the call to be made exactly\n///   `count` times. e.g. `vm.expectCall(address(0xc4f3), abi.encodeWithSelector(0xd34db33f), 4)`\n///   will expect the call to address(0xc4f3) with selector `0xd34db33f` to be made exactly 4 times.\n///   If the amount of calls is less or more than 4, the test will fail. Note that the `count`\n///   argument cannot be overwritten with another `vm.expectCall`. If this is attempted,\n///   `expectCall` will revert.\n/// - If the cheatcode was used without a `count` argument, it will expect the call to be made at\n///   least the amount of times the cheatcode was called. This means that `vm.expectCall` without a\n///   count argument can be called many times, but cannot be called with a `count` argument after it\n///   was called without one. If the latter happens, `expectCall` will revert. e.g\n///   `vm.expectCall(address(0xc4f3), abi.encodeWithSelector(0xd34db33f))` will expect the call to\n///   address(0xc4f3) and selector `0xd34db33f` to be made at least once. If the amount of calls is\n///   0, the test will fail. If the call is made more than once, the test will pass.\n#[expect(clippy::too_many_arguments)] // It is what it is\nfn expect_call(\n    state: &mut Cheatcodes,\n    target: &Address,\n    calldata: &Bytes,\n    value: Option<&U256>,\n    mut gas: Option<u64>,\n    mut min_gas: Option<u64>,\n    count: u64,\n    call_type: ExpectedCallType,\n) -> Result {\n    let expecteds = state.expected_calls.entry(*target).or_default();\n\n    if let Some(val) = value\n        && *val > U256::ZERO\n    {\n        // If the value of the transaction is non-zero, the EVM adds a call stipend of 2300 gas\n        // to ensure that the basic fallback function can be called.\n        let positive_value_cost_stipend = 2300;\n        if let Some(gas) = &mut gas {\n            *gas += positive_value_cost_stipend;\n        }\n        if let Some(min_gas) = &mut min_gas {\n            *min_gas += positive_value_cost_stipend;\n        }\n    }\n\n    match call_type {\n        ExpectedCallType::Count => {\n            // Get the expected calls for this target.\n            // In this case, as we're using counted expectCalls, we should not be able to set them\n            // more than once.\n            ensure!(\n                !expecteds.contains_key(calldata),\n                \"counted expected calls can only bet set once\"\n            );\n            expecteds.insert(\n                calldata.clone(),\n                (ExpectedCallData { value: value.copied(), gas, min_gas, count, call_type }, 0),\n            );\n        }\n        ExpectedCallType::NonCount => {\n            // Check if the expected calldata exists.\n            // If it does, increment the count by one as we expect to see it one more time.\n            match expecteds.entry(calldata.clone()) {\n                Entry::Occupied(mut entry) => {\n                    let (expected, _) = entry.get_mut();\n                    // Ensure we're not overwriting a counted expectCall.\n                    ensure!(\n                        expected.call_type == ExpectedCallType::NonCount,\n                        \"cannot overwrite a counted expectCall with a non-counted expectCall\"\n                    );\n                    expected.count += 1;\n                }\n                // If it does not exist, then create it.\n                Entry::Vacant(entry) => {\n                    entry.insert((\n                        ExpectedCallData { value: value.copied(), gas, min_gas, count, call_type },\n                        0,\n                    ));\n                }\n            }\n        }\n    }\n\n    Ok(Default::default())\n}\n\nfn expect_emit(\n    state: &mut Cheatcodes,\n    depth: usize,\n    checks: [bool; 5],\n    address: Option<Address>,\n    anonymous: bool,\n    count: u64,\n) -> Result {\n    let expected_emit = ExpectedEmit {\n        depth,\n        checks,\n        address,\n        found: false,\n        log: None,\n        anonymous,\n        count,\n        mismatch_error: None,\n    };\n    if let Some(found_emit_pos) = state.expected_emits.iter().position(|(emit, _)| emit.found) {\n        // The order of emits already found (back of queue) should not be modified, hence push any\n        // new emit before first found emit.\n        state.expected_emits.insert(found_emit_pos, (expected_emit, Default::default()));\n    } else {\n        // If no expected emits then push new one at the back of queue.\n        state.expected_emits.push_back((expected_emit, Default::default()));\n    }\n\n    Ok(Default::default())\n}\n\npub(crate) fn handle_expect_emit(\n    state: &mut Cheatcodes,\n    log: &alloy_primitives::Log,\n    mut interpreter: Option<&mut Interpreter>,\n) -> Option<&'static str> {\n    // This function returns an optional string indicating a failure reason.\n    // If the string is `Some`, it indicates that the expectation failed with the provided reason.\n    let mut should_fail = None;\n\n    // Fill or check the expected emits.\n    // We expect for emit checks to be filled as they're declared (from oldest to newest),\n    // so we fill them and push them to the back of the queue.\n    // If the user has properly filled all the emits, they'll end up in their original order.\n    // If not, the queue will not be in the order the events will be intended to be filled,\n    // and we'll be able to later detect this and bail.\n\n    // First, we can return early if all events have been matched.\n    // This allows a contract to arbitrarily emit more events than expected (additive behavior),\n    // as long as all the previous events were matched in the order they were expected to be.\n    if state.expected_emits.iter().all(|(expected, _)| expected.found) {\n        return should_fail;\n    }\n\n    // Check count=0 expectations against this log - fail immediately if violated\n    for (expected_emit, _) in &state.expected_emits {\n        if expected_emit.count == 0\n            && !expected_emit.found\n            && let Some(expected_log) = &expected_emit.log\n            && checks_topics_and_data(expected_emit.checks, expected_log, log)\n            // Check revert address \n            && (expected_emit.address.is_none() || expected_emit.address == Some(log.address))\n        {\n            if let Some(interpreter) = &mut interpreter {\n                // This event was emitted but we expected it NOT to be (count=0)\n                // Fail immediately\n                interpreter.bytecode.set_action(InterpreterAction::new_return(\n                    InstructionResult::Revert,\n                    Error::encode(\"log emitted but expected 0 times\"),\n                    interpreter.gas,\n                ));\n            } else {\n                should_fail = Some(\"log emitted but expected 0 times\");\n            }\n\n            return should_fail;\n        }\n    }\n\n    let should_fill_logs = state.expected_emits.iter().any(|(expected, _)| expected.log.is_none());\n    let index_to_fill_or_check = if should_fill_logs {\n        // If there's anything to fill, we start with the last event to match in the queue\n        // (without taking into account events already matched).\n        state\n            .expected_emits\n            .iter()\n            .position(|(emit, _)| emit.found)\n            .unwrap_or(state.expected_emits.len())\n            .saturating_sub(1)\n    } else {\n        // if all expected logs are filled, check any unmatched event\n        // in the declared order, so we start from the front (like a queue).\n        // Skip count=0 expectations as they are handled separately above\n        state.expected_emits.iter().position(|(emit, _)| !emit.found && emit.count > 0).unwrap_or(0)\n    };\n\n    // If there are only count=0 expectations left, we can return early\n    if !should_fill_logs\n        && state.expected_emits.iter().all(|(emit, _)| emit.found || emit.count == 0)\n    {\n        return should_fail;\n    }\n\n    let (mut event_to_fill_or_check, mut count_map) = state\n        .expected_emits\n        .remove(index_to_fill_or_check)\n        .expect(\"we should have an emit to fill or check\");\n\n    let Some(expected) = &event_to_fill_or_check.log else {\n        // Unless the caller is trying to match an anonymous event, the first topic must be\n        // filled.\n        if event_to_fill_or_check.anonymous || !log.topics().is_empty() {\n            event_to_fill_or_check.log = Some(log.data.clone());\n            // If we only filled the expected log then we put it back at the same position.\n            state\n                .expected_emits\n                .insert(index_to_fill_or_check, (event_to_fill_or_check, count_map));\n        } else if let Some(interpreter) = &mut interpreter {\n            interpreter.bytecode.set_action(InterpreterAction::new_return(\n                InstructionResult::Revert,\n                Error::encode(\"use vm.expectEmitAnonymous to match anonymous events\"),\n                interpreter.gas,\n            ));\n        } else {\n            should_fail = Some(\"use vm.expectEmitAnonymous to match anonymous events\");\n        }\n\n        return should_fail;\n    };\n\n    // Increment/set `count` for `log.address` and `log.data`\n    match count_map.entry(log.address) {\n        Entry::Occupied(mut entry) => {\n            let log_count_map = entry.get_mut();\n            log_count_map.insert(&log.data);\n        }\n        Entry::Vacant(entry) => {\n            let mut log_count_map = LogCountMap::new(&event_to_fill_or_check);\n            if log_count_map.satisfies_checks(&log.data) {\n                log_count_map.insert(&log.data);\n                entry.insert(log_count_map);\n            }\n        }\n    }\n\n    event_to_fill_or_check.found = || -> bool {\n        if !checks_topics_and_data(event_to_fill_or_check.checks, expected, log) {\n            // Store detailed mismatch information\n\n            // Try to decode the events if we have a signature identifier\n            let (expected_decoded, actual_decoded) = if let Some(signatures_identifier) =\n                state.signatures_identifier()\n                && !event_to_fill_or_check.anonymous\n            {\n                (\n                    decode_event(signatures_identifier, expected),\n                    decode_event(signatures_identifier, log),\n                )\n            } else {\n                (None, None)\n            };\n            event_to_fill_or_check.mismatch_error = Some(get_emit_mismatch_message(\n                event_to_fill_or_check.checks,\n                expected,\n                log,\n                event_to_fill_or_check.anonymous,\n                expected_decoded.as_ref(),\n                actual_decoded.as_ref(),\n            ));\n            return false;\n        }\n\n        // Maybe match source address.\n        if event_to_fill_or_check.address.is_some_and(|addr| addr != log.address) {\n            event_to_fill_or_check.mismatch_error = Some(format!(\n                \"log emitter mismatch: expected={:#x}, got={:#x}\",\n                event_to_fill_or_check.address.unwrap(),\n                log.address\n            ));\n            return false;\n        }\n\n        let expected_count = event_to_fill_or_check.count;\n        match event_to_fill_or_check.address {\n            Some(emitter) => count_map\n                .get(&emitter)\n                .is_some_and(|log_map| log_map.count(&log.data) >= expected_count),\n            None => count_map\n                .values()\n                .find(|log_map| log_map.satisfies_checks(&log.data))\n                .is_some_and(|map| map.count(&log.data) >= expected_count),\n        }\n    }();\n\n    // If we found the event, we can push it to the back of the queue\n    // and begin expecting the next event.\n    if event_to_fill_or_check.found {\n        state.expected_emits.push_back((event_to_fill_or_check, count_map));\n    } else {\n        // We did not match this event, so we need to keep waiting for the right one to\n        // appear.\n        state.expected_emits.push_front((event_to_fill_or_check, count_map));\n    }\n\n    should_fail\n}\n\n/// Handles expected emits specified by the `expectEmit` cheatcodes.\n///\n/// The second element of the tuple counts the number of times the log has been emitted by a\n/// particular address\npub type ExpectedEmitTracker = VecDeque<(ExpectedEmit, AddressHashMap<LogCountMap>)>;\n\n#[derive(Clone, Debug, Default)]\npub struct LogCountMap {\n    checks: [bool; 5],\n    expected_log: RawLog,\n    map: HashMap<RawLog, u64>,\n}\n\nimpl LogCountMap {\n    /// Instantiates `LogCountMap`.\n    fn new(expected_emit: &ExpectedEmit) -> Self {\n        Self {\n            checks: expected_emit.checks,\n            expected_log: expected_emit.log.clone().expect(\"log should be filled here\"),\n            map: Default::default(),\n        }\n    }\n\n    /// Inserts a log into the map and increments the count.\n    ///\n    /// The log must pass all checks against the expected log for the count to increment.\n    ///\n    /// Returns true if the log was inserted and count was incremented.\n    fn insert(&mut self, log: &RawLog) -> bool {\n        // If its already in the map, increment the count without checking.\n        if self.map.contains_key(log) {\n            self.map.entry(log.clone()).and_modify(|c| *c += 1);\n\n            return true;\n        }\n\n        if !self.satisfies_checks(log) {\n            return false;\n        }\n\n        self.map.entry(log.clone()).and_modify(|c| *c += 1).or_insert(1);\n\n        true\n    }\n\n    /// Checks the incoming raw log against the expected logs topics and data.\n    fn satisfies_checks(&self, log: &RawLog) -> bool {\n        checks_topics_and_data(self.checks, &self.expected_log, log)\n    }\n\n    pub fn count(&self, log: &RawLog) -> u64 {\n        if !self.satisfies_checks(log) {\n            return 0;\n        }\n\n        self.count_unchecked()\n    }\n\n    pub fn count_unchecked(&self) -> u64 {\n        self.map.values().sum()\n    }\n}\n\nfn expect_create(\n    state: &mut Cheatcodes,\n    bytecode: Bytes,\n    deployer: Address,\n    create_scheme: CreateScheme,\n) -> Result {\n    let expected_create = ExpectedCreate { bytecode, deployer, create_scheme };\n    state.expected_creates.push(expected_create);\n\n    Ok(Default::default())\n}\n\nfn expect_revert(\n    state: &mut Cheatcodes,\n    reason: Option<&[u8]>,\n    depth: usize,\n    cheatcode: bool,\n    partial_match: bool,\n    reverter: Option<Address>,\n    count: u64,\n) -> Result {\n    ensure!(\n        state.expected_revert.is_none(),\n        \"you must call another function prior to expecting a second revert\"\n    );\n    state.expected_revert = Some(ExpectedRevert {\n        reason: reason.map(Bytes::copy_from_slice),\n        depth,\n        kind: if cheatcode {\n            ExpectedRevertKind::Cheatcode { pending_processing: true }\n        } else {\n            ExpectedRevertKind::Default\n        },\n        partial_match,\n        reverter,\n        reverted_by: None,\n        max_depth: depth,\n        count,\n        actual_count: 0,\n    });\n    Ok(Default::default())\n}\n\nfn checks_topics_and_data(checks: [bool; 5], expected: &RawLog, log: &RawLog) -> bool {\n    if log.topics().len() != expected.topics().len() {\n        return false;\n    }\n\n    // Check topics.\n    if !log\n        .topics()\n        .iter()\n        .enumerate()\n        .filter(|(i, _)| checks[*i])\n        .all(|(i, topic)| topic == &expected.topics()[i])\n    {\n        return false;\n    }\n\n    // Check data\n    if checks[4] && expected.data.as_ref() != log.data.as_ref() {\n        return false;\n    }\n\n    true\n}\n\nfn decode_event(\n    identifier: &foundry_evm_traces::identifier::SignaturesIdentifier,\n    log: &RawLog,\n) -> Option<DecodedCallLog> {\n    let topics = log.topics();\n    if topics.is_empty() {\n        return None;\n    }\n    let t0 = topics[0]; // event sig\n    // Try to identify the event\n    let event = foundry_common::block_on(identifier.identify_event(t0))?;\n\n    // Check if event already has indexed information from signatures\n    let has_indexed_info = event.inputs.iter().any(|p| p.indexed);\n    // Only use get_indexed_event if the event doesn't have indexing info\n    let indexed_event = if has_indexed_info { event } else { get_indexed_event(event, log) };\n\n    // Try to decode the event\n    if let Ok(decoded) = indexed_event.decode_log(log) {\n        let params = reconstruct_params(&indexed_event, &decoded);\n\n        let decoded_params = params\n            .into_iter()\n            .zip(indexed_event.inputs.iter())\n            .map(|(param, input)| (input.name.clone(), format_token(&param)))\n            .collect();\n\n        return Some(DecodedCallLog {\n            name: Some(indexed_event.name),\n            params: Some(decoded_params),\n        });\n    }\n\n    None\n}\n\n/// Restore the order of the params of a decoded event\nfn reconstruct_params(event: &Event, decoded: &alloy_dyn_abi::DecodedEvent) -> Vec<DynSolValue> {\n    let mut indexed = 0;\n    let mut unindexed = 0;\n    let mut inputs = vec![];\n    for input in &event.inputs {\n        if input.indexed && indexed < decoded.indexed.len() {\n            inputs.push(decoded.indexed[indexed].clone());\n            indexed += 1;\n        } else if unindexed < decoded.body.len() {\n            inputs.push(decoded.body[unindexed].clone());\n            unindexed += 1;\n        }\n    }\n    inputs\n}\n\n/// Gets a detailed mismatch message for emit assertions\npub(crate) fn get_emit_mismatch_message(\n    checks: [bool; 5],\n    expected: &RawLog,\n    actual: &RawLog,\n    is_anonymous: bool,\n    expected_decoded: Option<&DecodedCallLog>,\n    actual_decoded: Option<&DecodedCallLog>,\n) -> String {\n    // Early return for completely different events or incompatible structures\n\n    // 1. Different number of topics\n    if actual.topics().len() != expected.topics().len() {\n        return name_mismatched_logs(expected_decoded, actual_decoded);\n    }\n\n    // 2. Different event signatures (for non-anonymous events)\n    if !is_anonymous\n        && checks[0]\n        && (!expected.topics().is_empty() && !actual.topics().is_empty())\n        && expected.topics()[0] != actual.topics()[0]\n    {\n        return name_mismatched_logs(expected_decoded, actual_decoded);\n    }\n\n    let expected_data = expected.data.as_ref();\n    let actual_data = actual.data.as_ref();\n\n    // 3. Check data\n    if checks[4] && expected_data != actual_data {\n        // Different lengths or not ABI-encoded\n        if expected_data.len() != actual_data.len()\n            || !expected_data.len().is_multiple_of(32)\n            || expected_data.is_empty()\n        {\n            return name_mismatched_logs(expected_decoded, actual_decoded);\n        }\n    }\n\n    // expected and actual events are the same, so check individual parameters\n    let mut mismatches = Vec::new();\n\n    // Check topics (indexed parameters)\n    for (i, (expected_topic, actual_topic)) in\n        expected.topics().iter().zip(actual.topics().iter()).enumerate()\n    {\n        // Skip topic[0] for non-anonymous events (already checked above)\n        if i == 0 && !is_anonymous {\n            continue;\n        }\n\n        // Only check if the corresponding check flag is set\n        if i < checks.len() && checks[i] && expected_topic != actual_topic {\n            let param_idx = if is_anonymous {\n                i // For anonymous events, topic[0] is param 0\n            } else {\n                i - 1 // For regular events, topic[0] is event signature, so topic[1] is param 0\n            };\n            mismatches\n                .push(format!(\"param {param_idx}: expected={expected_topic}, got={actual_topic}\"));\n        }\n    }\n\n    // Check data (non-indexed parameters)\n    if checks[4] && expected_data != actual_data {\n        let num_indexed_params = if is_anonymous {\n            expected.topics().len()\n        } else {\n            expected.topics().len().saturating_sub(1)\n        };\n\n        for (i, (expected_chunk, actual_chunk)) in\n            expected_data.chunks(32).zip(actual_data.chunks(32)).enumerate()\n        {\n            if expected_chunk != actual_chunk {\n                let param_idx = num_indexed_params + i;\n                mismatches.push(format!(\n                    \"param {}: expected={}, got={}\",\n                    param_idx,\n                    hex::encode_prefixed(expected_chunk),\n                    hex::encode_prefixed(actual_chunk)\n                ));\n            }\n        }\n    }\n\n    if mismatches.is_empty() {\n        name_mismatched_logs(expected_decoded, actual_decoded)\n    } else {\n        // Build the error message with event names if available\n        let event_prefix = match (expected_decoded, actual_decoded) {\n            (Some(expected_dec), Some(actual_dec)) if expected_dec.name == actual_dec.name => {\n                format!(\n                    \"{} param mismatch\",\n                    expected_dec.name.as_ref().unwrap_or(&\"log\".to_string())\n                )\n            }\n            _ => {\n                if is_anonymous {\n                    \"anonymous log mismatch\".to_string()\n                } else {\n                    \"log mismatch\".to_string()\n                }\n            }\n        };\n\n        // Add parameter details if available from decoded events\n        let detailed_mismatches = if let (Some(expected_dec), Some(actual_dec)) =\n            (expected_decoded, actual_decoded)\n            && let (Some(expected_params), Some(actual_params)) =\n                (&expected_dec.params, &actual_dec.params)\n        {\n            mismatches\n                .into_iter()\n                .map(|basic_mismatch| {\n                    // Try to find the parameter name and decoded value\n                    if let Some(param_idx) = basic_mismatch\n                        .split(' ')\n                        .nth(1)\n                        .and_then(|s| s.trim_end_matches(':').parse::<usize>().ok())\n                        && param_idx < expected_params.len()\n                        && param_idx < actual_params.len()\n                    {\n                        let (expected_name, expected_value) = &expected_params[param_idx];\n                        let (_actual_name, actual_value) = &actual_params[param_idx];\n                        let param_name = if !expected_name.is_empty() {\n                            expected_name\n                        } else {\n                            &format!(\"param{param_idx}\")\n                        };\n                        return format!(\n                            \"{param_name}: expected={expected_value}, got={actual_value}\",\n                        );\n                    }\n                    basic_mismatch\n                })\n                .collect::<Vec<_>>()\n        } else {\n            mismatches\n        };\n\n        format!(\"{} at {}\", event_prefix, detailed_mismatches.join(\", \"))\n    }\n}\n\n/// Formats the generic mismatch message: \"log != expected log\" to include event names if available\nfn name_mismatched_logs(\n    expected_decoded: Option<&DecodedCallLog>,\n    actual_decoded: Option<&DecodedCallLog>,\n) -> String {\n    let expected_name = expected_decoded.and_then(|d| d.name.as_deref()).unwrap_or(\"log\");\n    let actual_name = actual_decoded.and_then(|d| d.name.as_deref()).unwrap_or(\"log\");\n    format!(\"{actual_name} != expected {expected_name}\")\n}\n\nfn expect_safe_memory(state: &mut Cheatcodes, start: u64, end: u64, depth: u64) -> Result {\n    ensure!(start < end, \"memory range start ({start}) is greater than end ({end})\");\n    #[expect(clippy::single_range_in_vec_init)] // Wanted behaviour\n    let offsets = state.allowed_mem_writes.entry(depth).or_insert_with(|| vec![0..0x60]);\n    offsets.push(start..end);\n    Ok(Default::default())\n}\n"
  },
  {
    "path": "crates/cheatcodes/src/test/revert_handlers.rs",
    "content": "use crate::{Error, Result};\nuse alloy_dyn_abi::{DynSolValue, ErrorExt};\nuse alloy_primitives::{Address, Bytes, address, hex};\nuse alloy_sol_types::{SolError, SolValue};\nuse foundry_common::{ContractsByArtifact, abi::get_error};\nuse foundry_evm_core::decode::RevertDecoder;\nuse revm::interpreter::{InstructionResult, return_ok};\nuse spec::Vm;\n\nuse super::{\n    assume::{AcceptableRevertParameters, AssumeNoRevert},\n    expect::ExpectedRevert,\n};\n\n/// For some cheatcodes we may internally change the status of the call, i.e. in `expectRevert`.\n/// Solidity will see a successful call and attempt to decode the return data. Therefore, we need\n/// to populate the return with dummy bytes so the decode doesn't fail.\n///\n/// 8192 bytes was arbitrarily chosen because it is long enough for return values up to 256 words in\n/// size.\nstatic DUMMY_CALL_OUTPUT: Bytes = Bytes::from_static(&[0u8; 8192]);\n\n/// Same reasoning as [DUMMY_CALL_OUTPUT], but for creates.\nconst DUMMY_CREATE_ADDRESS: Address = address!(\"0x0000000000000000000000000000000000000001\");\n\nfn stringify(data: &[u8]) -> String {\n    if let Ok(s) = String::abi_decode(data) {\n        return s;\n    }\n    if data.is_ascii() {\n        return std::str::from_utf8(data).unwrap().to_owned();\n    }\n    hex::encode_prefixed(data)\n}\n\n/// Common parameters for expected or assumed reverts. Allows for code reuse.\npub(crate) trait RevertParameters {\n    fn reverter(&self) -> Option<Address>;\n    fn reason(&self) -> Option<&[u8]>;\n    fn partial_match(&self) -> bool;\n}\n\nimpl RevertParameters for AcceptableRevertParameters {\n    fn reverter(&self) -> Option<Address> {\n        self.reverter\n    }\n\n    fn reason(&self) -> Option<&[u8]> {\n        Some(&self.reason)\n    }\n\n    fn partial_match(&self) -> bool {\n        self.partial_match\n    }\n}\n\n/// Core logic for handling reverts that may or may not be expected (or assumed).\nfn handle_revert(\n    is_cheatcode: bool,\n    revert_params: &impl RevertParameters,\n    status: InstructionResult,\n    retdata: &Bytes,\n    known_contracts: &Option<ContractsByArtifact>,\n    reverter: Option<&Address>,\n) -> Result<(), Error> {\n    // If expected reverter address is set then check it matches the actual reverter.\n    if let (Some(expected_reverter), Some(&actual_reverter)) = (revert_params.reverter(), reverter)\n        && expected_reverter != actual_reverter\n    {\n        return Err(fmt_err!(\n            \"Reverter != expected reverter: {} != {}\",\n            actual_reverter,\n            expected_reverter\n        ));\n    }\n\n    let expected_reason = revert_params.reason();\n    // If None, accept any revert.\n    let Some(expected_reason) = expected_reason else {\n        return Ok(());\n    };\n\n    if !expected_reason.is_empty() && retdata.is_empty() {\n        bail!(\"call reverted as expected, but without data\");\n    }\n\n    let mut actual_revert: Vec<u8> = retdata.to_vec();\n\n    // Compare only the first 4 bytes if partial match.\n    if revert_params.partial_match() && actual_revert.get(..4) == expected_reason.get(..4) {\n        return Ok(());\n    }\n\n    // Try decoding as known errors.\n    actual_revert = decode_revert(actual_revert);\n\n    if actual_revert == expected_reason\n        || (is_cheatcode && memchr::memmem::find(&actual_revert, expected_reason).is_some())\n    {\n        return Ok(());\n    }\n\n    // If expected reason is `Error(string)` then decode and compare with actual revert.\n    // See <https://github.com/foundry-rs/foundry/issues/12511>\n    if expected_reason.len() >= 4\n        && let Ok(e) = get_error(\"Error(string)\")\n        && let Ok(dec) = e.decode_error(expected_reason)\n        && let Some(DynSolValue::String(revert_str)) = dec.body.first()\n        && revert_str.as_str() == String::from_utf8_lossy(&actual_revert)\n    {\n        return Ok(());\n    }\n\n    let (actual, expected) = if let Some(contracts) = known_contracts {\n        let decoder = RevertDecoder::new().with_abis(contracts.values().map(|c| &c.abi));\n        (\n            &decoder.decode(actual_revert.as_slice(), Some(status)),\n            &decoder.decode(expected_reason, Some(status)),\n        )\n    } else {\n        (&stringify(&actual_revert), &stringify(expected_reason))\n    };\n\n    if expected == actual {\n        return Ok(());\n    }\n\n    Err(fmt_err!(\"Error != expected error: {} != {}\", actual, expected))\n}\n\npub(crate) fn handle_assume_no_revert(\n    assume_no_revert: &AssumeNoRevert,\n    status: InstructionResult,\n    retdata: &Bytes,\n    known_contracts: &Option<ContractsByArtifact>,\n) -> Result<()> {\n    // if a generic AssumeNoRevert, return Ok(). Otherwise, iterate over acceptable reasons and try\n    // to match against any, otherwise, return an Error with the revert data\n    if assume_no_revert.reasons.is_empty() {\n        Ok(())\n    } else {\n        assume_no_revert\n            .reasons\n            .iter()\n            .find_map(|reason| {\n                handle_revert(\n                    false,\n                    reason,\n                    status,\n                    retdata,\n                    known_contracts,\n                    assume_no_revert.reverted_by.as_ref(),\n                )\n                .ok()\n            })\n            .ok_or_else(|| retdata.clone().into())\n    }\n}\n\npub(crate) fn handle_expect_revert(\n    is_cheatcode: bool,\n    is_create: bool,\n    internal_expect_revert: bool,\n    expected_revert: &ExpectedRevert,\n    status: InstructionResult,\n    retdata: Bytes,\n    known_contracts: &Option<ContractsByArtifact>,\n) -> Result<(Option<Address>, Bytes)> {\n    let success_return = || {\n        if is_create {\n            (Some(DUMMY_CREATE_ADDRESS), Bytes::new())\n        } else {\n            (None, DUMMY_CALL_OUTPUT.clone())\n        }\n    };\n\n    // Check depths if it's not an expect cheatcode call and if internal expect reverts not enabled.\n    if !is_cheatcode && !internal_expect_revert {\n        ensure!(\n            expected_revert.max_depth > expected_revert.depth,\n            \"call didn't revert at a lower depth than cheatcode call depth\"\n        );\n    }\n\n    if expected_revert.count == 0 {\n        // If no specific reason or reverter is expected, we just check if it reverted\n        if expected_revert.reverter.is_none() && expected_revert.reason.is_none() {\n            ensure!(\n                matches!(status, return_ok!()),\n                \"call reverted when it was expected not to revert\"\n            );\n            return Ok(success_return());\n        }\n\n        // Flags to track if the reason and reverter match.\n        let mut reason_match = expected_revert.reason.as_ref().map(|_| false);\n        let mut reverter_match = expected_revert.reverter.as_ref().map(|_| false);\n\n        // If we expect no reverts with a specific reason/reverter, but got a revert,\n        // we need to check if it matches our criteria\n        if !matches!(status, return_ok!()) {\n            // We got a revert, but we expected 0 reverts\n            // We need to check if this revert matches our expected criteria\n\n            // Reverter check\n            if let (Some(expected_reverter), Some(actual_reverter)) =\n                (expected_revert.reverter, expected_revert.reverted_by)\n                && expected_reverter == actual_reverter\n            {\n                reverter_match = Some(true);\n            }\n\n            // Reason check\n            let expected_reason = expected_revert.reason();\n            if let Some(expected_reason) = expected_reason {\n                let mut actual_revert: Vec<u8> = retdata.to_vec();\n                actual_revert = decode_revert(actual_revert);\n\n                if actual_revert == expected_reason {\n                    reason_match = Some(true);\n                }\n            }\n\n            match (reason_match, reverter_match) {\n                (Some(true), Some(true)) => Err(fmt_err!(\n                    \"expected 0 reverts with reason: {}, from address: {}, but got one\",\n                    stringify(expected_reason.unwrap_or_default()),\n                    expected_revert.reverter.unwrap()\n                )),\n                (Some(true), None) => Err(fmt_err!(\n                    \"expected 0 reverts with reason: {}, but got one\",\n                    stringify(expected_reason.unwrap_or_default())\n                )),\n                (None, Some(true)) => Err(fmt_err!(\n                    \"expected 0 reverts from address: {}, but got one\",\n                    expected_revert.reverter.unwrap()\n                )),\n                _ => {\n                    // The revert doesn't match our criteria, which means it's a different revert\n                    // For expectRevert with count=0, any revert should fail the test\n                    let decoded_revert = decode_revert(retdata.to_vec());\n\n                    // Provide more specific error messages based on what was expected\n                    if let Some(reverter) = expected_revert.reverter {\n                        if expected_revert.reason.is_some() {\n                            Err(fmt_err!(\n                                \"call reverted with '{}' from {}, but expected 0 reverts with reason '{}' from {}\",\n                                stringify(&decoded_revert),\n                                expected_revert.reverted_by.unwrap_or_default(),\n                                stringify(expected_reason.unwrap_or_default()),\n                                reverter\n                            ))\n                        } else {\n                            Err(fmt_err!(\n                                \"call reverted with '{}' from {}, but expected 0 reverts from {}\",\n                                stringify(&decoded_revert),\n                                expected_revert.reverted_by.unwrap_or_default(),\n                                reverter\n                            ))\n                        }\n                    } else {\n                        Err(fmt_err!(\n                            \"call reverted with '{}' when it was expected not to revert\",\n                            stringify(&decoded_revert)\n                        ))\n                    }\n                }\n            }\n        } else {\n            // No revert occurred, which is what we expected\n            Ok(success_return())\n        }\n    } else {\n        ensure!(!matches!(status, return_ok!()), \"next call did not revert as expected\");\n\n        handle_revert(\n            is_cheatcode,\n            expected_revert,\n            status,\n            &retdata,\n            known_contracts,\n            expected_revert.reverted_by.as_ref(),\n        )?;\n        Ok(success_return())\n    }\n}\n\nfn decode_revert(revert: Vec<u8>) -> Vec<u8> {\n    if matches!(\n        revert.get(..4).map(|s| s.try_into().unwrap()),\n        Some(Vm::CheatcodeError::SELECTOR | alloy_sol_types::Revert::SELECTOR)\n    ) && let Ok(decoded) = Vec::<u8>::abi_decode(&revert[4..])\n    {\n        return decoded;\n    }\n    revert\n}\n"
  },
  {
    "path": "crates/cheatcodes/src/test.rs",
    "content": "//! Implementations of [`Testing`](spec::Group::Testing) cheatcodes.\n\nuse crate::{Cheatcode, Cheatcodes, CheatsCtxt, EthCheatCtx, Result, Vm::*};\nuse alloy_chains::Chain as AlloyChain;\nuse alloy_primitives::{Address, U256};\nuse alloy_sol_types::SolValue;\nuse foundry_common::version::SEMVER_VERSION;\nuse foundry_evm_core::constants::MAGIC_SKIP;\nuse revm::context::{ContextTr, JournalTr};\nuse std::str::FromStr;\n\npub(crate) mod assert;\npub(crate) mod assume;\npub(crate) mod expect;\npub(crate) mod revert_handlers;\n\nimpl Cheatcode for breakpoint_0Call {\n    fn apply_stateful<CTX>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self { char } = self;\n        breakpoint(ccx.state, &ccx.caller, char, true)\n    }\n}\n\nimpl Cheatcode for breakpoint_1Call {\n    fn apply_stateful<CTX>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self { char, value } = self;\n        breakpoint(ccx.state, &ccx.caller, char, *value)\n    }\n}\n\nimpl Cheatcode for getFoundryVersionCall {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self {} = self;\n        Ok(SEMVER_VERSION.abi_encode())\n    }\n}\n\nimpl Cheatcode for rpcUrlCall {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { rpcAlias } = self;\n        let url = state.config.rpc_endpoint(rpcAlias)?.url()?.abi_encode();\n        Ok(url)\n    }\n}\n\nimpl Cheatcode for rpcUrlsCall {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self {} = self;\n        state.config.rpc_urls().map(|urls| urls.abi_encode())\n    }\n}\n\nimpl Cheatcode for rpcUrlStructsCall {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self {} = self;\n        state.config.rpc_urls().map(|urls| urls.abi_encode())\n    }\n}\n\nimpl Cheatcode for sleepCall {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { duration } = self;\n        let sleep_duration = std::time::Duration::from_millis(duration.saturating_to());\n        std::thread::sleep(sleep_duration);\n        Ok(Default::default())\n    }\n}\n\nimpl Cheatcode for skip_0Call {\n    fn apply_stateful<CTX: EthCheatCtx>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self { skipTest } = *self;\n        skip_1Call { skipTest, reason: String::new() }.apply_stateful(ccx)\n    }\n}\n\nimpl Cheatcode for skip_1Call {\n    fn apply_stateful<CTX: ContextTr>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self { skipTest, reason } = self;\n        if *skipTest {\n            // Skip should not work if called deeper than at test level.\n            // Since we're not returning the magic skip bytes, this will cause a test failure.\n            ensure!(ccx.ecx.journal().depth() <= 1, \"`skip` can only be used at test level\");\n            Err([MAGIC_SKIP, reason.as_bytes()].concat().into())\n        } else {\n            Ok(Default::default())\n        }\n    }\n}\n\nimpl Cheatcode for getChain_0Call {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { chainAlias } = self;\n        get_chain(state, chainAlias)\n    }\n}\n\nimpl Cheatcode for getChain_1Call {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { chainId } = self;\n        // Convert the chainId to a string and use the existing get_chain function\n        let chain_id_str = chainId.to_string();\n        get_chain(state, &chain_id_str)\n    }\n}\n\n/// Adds or removes the given breakpoint to the state.\nfn breakpoint(state: &mut Cheatcodes, caller: &Address, s: &str, add: bool) -> Result {\n    let mut chars = s.chars();\n    let (Some(point), None) = (chars.next(), chars.next()) else {\n        bail!(\"breakpoints must be exactly one character\");\n    };\n    ensure!(point.is_alphabetic(), \"only alphabetic characters are accepted as breakpoints\");\n\n    if add {\n        state.breakpoints.insert(point, (*caller, state.pc));\n    } else {\n        state.breakpoints.remove(&point);\n    }\n\n    Ok(Default::default())\n}\n\n/// Gets chain information for the given alias.\nfn get_chain(state: &mut Cheatcodes, chain_alias: &str) -> Result {\n    // Parse the chain alias - works for both chain names and IDs\n    let alloy_chain = AlloyChain::from_str(chain_alias)\n        .map_err(|_| fmt_err!(\"invalid chain alias: {chain_alias}\"))?;\n    let chain_name = alloy_chain.to_string();\n    let chain_id = alloy_chain.id();\n\n    // Check if this is an unknown chain ID by comparing the name to the chain ID\n    // When a numeric ID is passed for an unknown chain, alloy_chain.to_string() will return the ID\n    // So if they match, it's likely an unknown chain ID\n    if chain_name == chain_id.to_string() {\n        return Err(fmt_err!(\"invalid chain alias: {chain_alias}\"));\n    }\n\n    // Try to retrieve RPC URL and chain alias from user's config in foundry.toml.\n    let (rpc_url, chain_alias) = if let Some(rpc_url) =\n        state.config.rpc_endpoint(&chain_name).ok().and_then(|e| e.url().ok())\n    {\n        (rpc_url, chain_name.clone())\n    } else {\n        (String::new(), chain_alias.to_string())\n    };\n\n    let chain_struct = Chain {\n        name: chain_name,\n        chainId: U256::from(chain_id),\n        chainAlias: chain_alias,\n        rpcUrl: rpc_url,\n    };\n\n    Ok(chain_struct.abi_encode())\n}\n"
  },
  {
    "path": "crates/cheatcodes/src/toml.rs",
    "content": "//! Implementations of [`Toml`](spec::Group::Toml) cheatcodes.\n\nuse crate::{\n    Cheatcode, Cheatcodes, Result,\n    Vm::*,\n    json::{\n        check_json_key_exists, parse_json, parse_json_coerce, parse_json_keys, resolve_type,\n        upsert_json_value,\n    },\n};\nuse alloy_dyn_abi::DynSolType;\nuse alloy_sol_types::SolValue;\nuse foundry_common::{fmt::StructDefinitions, fs};\nuse foundry_config::fs_permissions::FsAccessKind;\nuse serde_json::Value as JsonValue;\nuse toml::Value as TomlValue;\n\nimpl Cheatcode for keyExistsTomlCall {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { toml, key } = self;\n        check_json_key_exists(&toml_to_json_string(toml)?, key)\n    }\n}\n\nimpl Cheatcode for parseToml_0Call {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { toml } = self;\n        parse_toml(\n            toml,\n            \"$\",\n            state.analysis.as_ref().and_then(|analysis| analysis.struct_defs().ok()),\n        )\n    }\n}\n\nimpl Cheatcode for parseToml_1Call {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { toml, key } = self;\n        parse_toml(\n            toml,\n            key,\n            state.analysis.as_ref().and_then(|analysis| analysis.struct_defs().ok()),\n        )\n    }\n}\n\nimpl Cheatcode for parseTomlUintCall {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { toml, key } = self;\n        parse_toml_coerce(toml, key, &DynSolType::Uint(256))\n    }\n}\n\nimpl Cheatcode for parseTomlUintArrayCall {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { toml, key } = self;\n        parse_toml_coerce(toml, key, &DynSolType::Array(Box::new(DynSolType::Uint(256))))\n    }\n}\n\nimpl Cheatcode for parseTomlIntCall {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { toml, key } = self;\n        parse_toml_coerce(toml, key, &DynSolType::Int(256))\n    }\n}\n\nimpl Cheatcode for parseTomlIntArrayCall {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { toml, key } = self;\n        parse_toml_coerce(toml, key, &DynSolType::Array(Box::new(DynSolType::Int(256))))\n    }\n}\n\nimpl Cheatcode for parseTomlBoolCall {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { toml, key } = self;\n        parse_toml_coerce(toml, key, &DynSolType::Bool)\n    }\n}\n\nimpl Cheatcode for parseTomlBoolArrayCall {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { toml, key } = self;\n        parse_toml_coerce(toml, key, &DynSolType::Array(Box::new(DynSolType::Bool)))\n    }\n}\n\nimpl Cheatcode for parseTomlAddressCall {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { toml, key } = self;\n        parse_toml_coerce(toml, key, &DynSolType::Address)\n    }\n}\n\nimpl Cheatcode for parseTomlAddressArrayCall {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { toml, key } = self;\n        parse_toml_coerce(toml, key, &DynSolType::Array(Box::new(DynSolType::Address)))\n    }\n}\n\nimpl Cheatcode for parseTomlStringCall {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { toml, key } = self;\n        parse_toml_coerce(toml, key, &DynSolType::String)\n    }\n}\n\nimpl Cheatcode for parseTomlStringArrayCall {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { toml, key } = self;\n        parse_toml_coerce(toml, key, &DynSolType::Array(Box::new(DynSolType::String)))\n    }\n}\n\nimpl Cheatcode for parseTomlBytesCall {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { toml, key } = self;\n        parse_toml_coerce(toml, key, &DynSolType::Bytes)\n    }\n}\n\nimpl Cheatcode for parseTomlBytesArrayCall {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { toml, key } = self;\n        parse_toml_coerce(toml, key, &DynSolType::Array(Box::new(DynSolType::Bytes)))\n    }\n}\n\nimpl Cheatcode for parseTomlBytes32Call {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { toml, key } = self;\n        parse_toml_coerce(toml, key, &DynSolType::FixedBytes(32))\n    }\n}\n\nimpl Cheatcode for parseTomlBytes32ArrayCall {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { toml, key } = self;\n        parse_toml_coerce(toml, key, &DynSolType::Array(Box::new(DynSolType::FixedBytes(32))))\n    }\n}\n\nimpl Cheatcode for parseTomlType_0Call {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { toml, typeDescription } = self;\n        parse_toml_coerce(\n            toml,\n            \"$\",\n            &resolve_type(\n                typeDescription,\n                state.analysis.as_ref().and_then(|analysis| analysis.struct_defs().ok()),\n            )?,\n        )\n        .map(|v| v.abi_encode())\n    }\n}\n\nimpl Cheatcode for parseTomlType_1Call {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { toml, key, typeDescription } = self;\n        parse_toml_coerce(\n            toml,\n            key,\n            &resolve_type(\n                typeDescription,\n                state.analysis.as_ref().and_then(|analysis| analysis.struct_defs().ok()),\n            )?,\n        )\n        .map(|v| v.abi_encode())\n    }\n}\n\nimpl Cheatcode for parseTomlTypeArrayCall {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { toml, key, typeDescription } = self;\n        let ty = resolve_type(\n            typeDescription,\n            state.analysis.as_ref().and_then(|analysis| analysis.struct_defs().ok()),\n        )?;\n        parse_toml_coerce(toml, key, &DynSolType::Array(Box::new(ty))).map(|v| v.abi_encode())\n    }\n}\n\nimpl Cheatcode for parseTomlKeysCall {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { toml, key } = self;\n        parse_toml_keys(toml, key)\n    }\n}\n\nimpl Cheatcode for writeToml_0Call {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { json, path } = self;\n        let value =\n            serde_json::from_str(json).unwrap_or_else(|_| JsonValue::String(json.to_owned()));\n\n        let toml_string = format_json_to_toml(value)?;\n        super::fs::write_file(state, path.as_ref(), toml_string.as_bytes())\n    }\n}\n\nimpl Cheatcode for writeToml_1Call {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { json: value, path, valueKey } = self;\n\n        // Read and parse the TOML file.\n        // If the file doesn't exist, start with an empty object so the file is created.\n        let data_path = state.config.ensure_path_allowed(path, FsAccessKind::Read)?;\n        let mut json_data: JsonValue = if data_path.exists() {\n            let toml_data = fs::locked_read_to_string(&data_path)?;\n            toml::from_str(&toml_data).map_err(|e| fmt_err!(\"failed parsing TOML: {e}\"))?\n        } else {\n            JsonValue::Object(Default::default())\n        };\n        upsert_json_value(&mut json_data, value, valueKey)?;\n\n        // Serialize back to TOML and write the updated content back to the file\n        let toml_string = format_json_to_toml(json_data)?;\n        super::fs::write_file(state, path.as_ref(), toml_string.as_bytes())\n    }\n}\n\n/// Parse\nfn parse_toml_str(toml: &str) -> Result<TomlValue> {\n    toml::from_str(toml).map_err(|e| fmt_err!(\"failed parsing TOML: {e}\"))\n}\n\n/// Parse a TOML string and return the value at the given path.\nfn parse_toml(toml: &str, key: &str, struct_defs: Option<&StructDefinitions>) -> Result {\n    parse_json(&toml_to_json_string(toml)?, key, struct_defs)\n}\n\n/// Parse a TOML string and return the value at the given path, coercing it to the given type.\nfn parse_toml_coerce(toml: &str, key: &str, ty: &DynSolType) -> Result {\n    parse_json_coerce(&toml_to_json_string(toml)?, key, ty)\n}\n\n/// Parse a TOML string and return an array of all keys at the given path.\nfn parse_toml_keys(toml: &str, key: &str) -> Result {\n    parse_json_keys(&toml_to_json_string(toml)?, key)\n}\n\n/// Convert a TOML string to a JSON string.\nfn toml_to_json_string(toml: &str) -> Result<String> {\n    let toml = parse_toml_str(toml)?;\n    let json = toml_to_json_value(toml);\n    serde_json::to_string(&json).map_err(|e| fmt_err!(\"failed to serialize JSON: {e}\"))\n}\n\n/// Format a JSON value to a TOML pretty string.\nfn format_json_to_toml(json: JsonValue) -> Result<String> {\n    let toml = json_to_toml_value(json);\n    toml::to_string_pretty(&toml).map_err(|e| fmt_err!(\"failed to serialize TOML: {e}\"))\n}\n\n/// Convert a TOML value to a JSON value.\npub(super) fn toml_to_json_value(toml: TomlValue) -> JsonValue {\n    match toml {\n        TomlValue::String(s) => match s.as_str() {\n            \"null\" => JsonValue::Null,\n            _ => JsonValue::String(s),\n        },\n        TomlValue::Integer(i) => JsonValue::Number(i.into()),\n        TomlValue::Float(f) => match serde_json::Number::from_f64(f) {\n            Some(n) => JsonValue::Number(n),\n            None => JsonValue::String(f.to_string()),\n        },\n        TomlValue::Boolean(b) => JsonValue::Bool(b),\n        TomlValue::Array(a) => JsonValue::Array(a.into_iter().map(toml_to_json_value).collect()),\n        TomlValue::Table(t) => {\n            JsonValue::Object(t.into_iter().map(|(k, v)| (k, toml_to_json_value(v))).collect())\n        }\n        TomlValue::Datetime(d) => JsonValue::String(d.to_string()),\n    }\n}\n\n/// Convert a JSON value to a TOML value.\nfn json_to_toml_value(json: JsonValue) -> TomlValue {\n    match json {\n        JsonValue::String(s) => TomlValue::String(s),\n        JsonValue::Number(n) => match n.as_i64() {\n            Some(i) => TomlValue::Integer(i),\n            None => match n.as_f64() {\n                Some(f) => TomlValue::Float(f),\n                None => TomlValue::String(n.to_string()),\n            },\n        },\n        JsonValue::Bool(b) => TomlValue::Boolean(b),\n        JsonValue::Array(a) => TomlValue::Array(a.into_iter().map(json_to_toml_value).collect()),\n        JsonValue::Object(o) => {\n            TomlValue::Table(o.into_iter().map(|(k, v)| (k, json_to_toml_value(v))).collect())\n        }\n        JsonValue::Null => TomlValue::String(\"null\".to_string()),\n    }\n}\n"
  },
  {
    "path": "crates/cheatcodes/src/utils.rs",
    "content": "//! Implementations of [`Utilities`](spec::Group::Utilities) cheatcodes.\n\nuse crate::{Cheatcode, Cheatcodes, CheatcodesExecutor, CheatsCtxt, Result, Vm::*};\nuse alloy_dyn_abi::{DynSolType, DynSolValue, Resolver, TypedData, eip712_parser::EncodeType};\nuse alloy_ens::namehash;\nuse alloy_primitives::{B64, Bytes, I256, U256, aliases::B32, keccak256, map::HashMap};\nuse alloy_rlp::{Decodable, Encodable};\nuse alloy_sol_types::SolValue;\nuse foundry_common::{TYPE_BINDING_PREFIX, fs};\nuse foundry_config::fs_permissions::FsAccessKind;\nuse foundry_evm_core::constants::DEFAULT_CREATE2_DEPLOYER;\nuse foundry_evm_fuzz::strategies::BoundMutator;\nuse proptest::prelude::Strategy;\nuse rand::{Rng, RngCore, seq::SliceRandom};\nuse revm::{\n    context::{ContextTr, JournalTr},\n    inspector::JournalExt,\n};\nuse std::path::PathBuf;\n\n/// Contains locations of traces ignored via cheatcodes.\n///\n/// The way we identify location in traces is by (node_idx, item_idx) tuple where node_idx is an\n/// index of a call trace node, and item_idx is a value between 0 and `node.ordering.len()` where i\n/// represents point after ith item, and 0 represents the beginning of the node trace.\n#[derive(Debug, Default, Clone)]\npub struct IgnoredTraces {\n    /// Mapping from (start_node_idx, start_item_idx) to (end_node_idx, end_item_idx) representing\n    /// ranges of trace nodes to ignore.\n    pub ignored: HashMap<(usize, usize), (usize, usize)>,\n    /// Keeps track of (start_node_idx, start_item_idx) of the last `vm.pauseTracing` call.\n    pub last_pause_call: Option<(usize, usize)>,\n}\n\nimpl Cheatcode for labelCall {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { account, newLabel } = self;\n        state.labels.insert(*account, newLabel.clone());\n        Ok(Default::default())\n    }\n}\n\nimpl Cheatcode for getLabelCall {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { account } = self;\n        Ok(match state.labels.get(account) {\n            Some(label) => label.abi_encode(),\n            None => format!(\"unlabeled:{account}\").abi_encode(),\n        })\n    }\n}\n\nimpl Cheatcode for computeCreateAddressCall {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { nonce, deployer } = self;\n        ensure!(*nonce <= U256::from(u64::MAX), \"nonce must be less than 2^64\");\n        Ok(deployer.create(nonce.to()).abi_encode())\n    }\n}\n\nimpl Cheatcode for computeCreate2Address_0Call {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { salt, initCodeHash, deployer } = self;\n        Ok(deployer.create2(salt, initCodeHash).abi_encode())\n    }\n}\n\nimpl Cheatcode for computeCreate2Address_1Call {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { salt, initCodeHash } = self;\n        Ok(DEFAULT_CREATE2_DEPLOYER.create2(salt, initCodeHash).abi_encode())\n    }\n}\n\nimpl Cheatcode for ensNamehashCall {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { name } = self;\n        Ok(namehash(name).abi_encode())\n    }\n}\n\nimpl Cheatcode for bound_0Call {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { current, min, max } = *self;\n        let Some(mutated) = U256::bound(current, min, max, state.test_runner()) else {\n            bail!(\"cannot bound {current} in [{min}, {max}] range\")\n        };\n        Ok(mutated.abi_encode())\n    }\n}\n\nimpl Cheatcode for bound_1Call {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { current, min, max } = *self;\n        let Some(mutated) = I256::bound(current, min, max, state.test_runner()) else {\n            bail!(\"cannot bound {current} in [{min}, {max}] range\")\n        };\n        Ok(mutated.abi_encode())\n    }\n}\n\nimpl Cheatcode for randomUint_0Call {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        random_uint(state, None, None)\n    }\n}\n\nimpl Cheatcode for randomUint_1Call {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { min, max } = *self;\n        random_uint(state, None, Some((min, max)))\n    }\n}\n\nimpl Cheatcode for randomUint_2Call {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { bits } = *self;\n        random_uint(state, Some(bits), None)\n    }\n}\n\nimpl Cheatcode for randomAddressCall {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        Ok(DynSolValue::type_strategy(&DynSolType::Address)\n            .new_tree(state.test_runner())\n            .unwrap()\n            .current()\n            .abi_encode())\n    }\n}\n\nimpl Cheatcode for randomInt_0Call {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        random_int(state, None)\n    }\n}\n\nimpl Cheatcode for randomInt_1Call {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { bits } = *self;\n        random_int(state, Some(bits))\n    }\n}\n\nimpl Cheatcode for randomBoolCall {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let rand_bool: bool = state.rng().random();\n        Ok(rand_bool.abi_encode())\n    }\n}\n\nimpl Cheatcode for randomBytesCall {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { len } = *self;\n        ensure!(\n            len <= U256::from(usize::MAX),\n            format!(\"bytes length cannot exceed {}\", usize::MAX)\n        );\n        let mut bytes = vec![0u8; len.to::<usize>()];\n        state.rng().fill_bytes(&mut bytes);\n        Ok(bytes.abi_encode())\n    }\n}\n\nimpl Cheatcode for randomBytes4Call {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let rand_u32 = state.rng().next_u32();\n        Ok(B32::from(rand_u32).abi_encode())\n    }\n}\n\nimpl Cheatcode for randomBytes8Call {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let rand_u64 = state.rng().next_u64();\n        Ok(B64::from(rand_u64).abi_encode())\n    }\n}\n\nimpl Cheatcode for pauseTracingCall {\n    fn apply_full<CTX: ContextTr>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n        executor: &mut dyn CheatcodesExecutor<CTX>,\n    ) -> Result {\n        let Some(tracer) = executor.tracing_inspector() else {\n            // No tracer -> nothing to pause\n            return Ok(Default::default());\n        };\n\n        // If paused earlier, ignore the call\n        if ccx.state.ignored_traces.last_pause_call.is_some() {\n            return Ok(Default::default());\n        }\n\n        let cur_node = &tracer.traces().nodes().last().expect(\"no trace nodes\");\n        ccx.state.ignored_traces.last_pause_call = Some((cur_node.idx, cur_node.ordering.len()));\n\n        Ok(Default::default())\n    }\n}\n\nimpl Cheatcode for resumeTracingCall {\n    fn apply_full<CTX: ContextTr>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n        executor: &mut dyn CheatcodesExecutor<CTX>,\n    ) -> Result {\n        let Some(tracer) = executor.tracing_inspector() else {\n            // No tracer -> nothing to unpause\n            return Ok(Default::default());\n        };\n\n        let Some(start) = ccx.state.ignored_traces.last_pause_call.take() else {\n            // Nothing to unpause\n            return Ok(Default::default());\n        };\n\n        let node = &tracer.traces().nodes().last().expect(\"no trace nodes\");\n        ccx.state.ignored_traces.ignored.insert(start, (node.idx, node.ordering.len()));\n\n        Ok(Default::default())\n    }\n}\n\nimpl Cheatcode for interceptInitcodeCall {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self {} = self;\n        if !state.intercept_next_create_call {\n            state.intercept_next_create_call = true;\n        } else {\n            bail!(\"vm.interceptInitcode() has already been called\")\n        }\n        Ok(Default::default())\n    }\n}\n\nimpl Cheatcode for setArbitraryStorage_0Call {\n    fn apply_stateful<CTX>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self { target } = self;\n        ccx.state.arbitrary_storage().mark_arbitrary(target, false);\n\n        Ok(Default::default())\n    }\n}\n\nimpl Cheatcode for setArbitraryStorage_1Call {\n    fn apply_stateful<CTX>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self { target, overwrite } = self;\n        ccx.state.arbitrary_storage().mark_arbitrary(target, *overwrite);\n\n        Ok(Default::default())\n    }\n}\n\nimpl Cheatcode for copyStorageCall {\n    fn apply_stateful<CTX: ContextTr<Journal: JournalExt>>(\n        &self,\n        ccx: &mut CheatsCtxt<'_, CTX>,\n    ) -> Result {\n        let Self { from, to } = self;\n\n        ensure!(\n            !ccx.state.has_arbitrary_storage(to),\n            \"target address cannot have arbitrary storage\"\n        );\n\n        if let Ok(from_account) = ccx.ecx.journal_mut().load_account(*from) {\n            let from_storage = from_account.storage.clone();\n            if ccx.ecx.journal_mut().load_account(*to).is_ok() {\n                // SAFETY: We ensured the account was already loaded.\n                ccx.ecx.journal_mut().evm_state_mut().get_mut(to).unwrap().storage = from_storage;\n                if let Some(arbitrary_storage) = &mut ccx.state.arbitrary_storage {\n                    arbitrary_storage.mark_copy(from, to);\n                }\n            }\n        }\n\n        Ok(Default::default())\n    }\n}\n\nimpl Cheatcode for sortCall {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { array } = self;\n\n        let mut sorted_values = array.clone();\n        sorted_values.sort();\n\n        Ok(sorted_values.abi_encode())\n    }\n}\n\nimpl Cheatcode for shuffleCall {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { array } = self;\n\n        let mut shuffled_values = array.clone();\n        let rng = state.rng();\n        shuffled_values.shuffle(rng);\n\n        Ok(shuffled_values.abi_encode())\n    }\n}\n\nimpl Cheatcode for setSeedCall {\n    fn apply_stateful<CTX>(&self, ccx: &mut CheatsCtxt<'_, CTX>) -> Result {\n        let Self { seed } = self;\n        ccx.state.set_seed(*seed);\n        Ok(Default::default())\n    }\n}\n\n/// Helper to generate a random `uint` value (with given bits or bounded if specified)\n/// from type strategy.\nfn random_uint(state: &mut Cheatcodes, bits: Option<U256>, bounds: Option<(U256, U256)>) -> Result {\n    if let Some(bits) = bits {\n        // Generate random with specified bits.\n        ensure!(bits <= U256::from(256), \"number of bits cannot exceed 256\");\n        return Ok(DynSolValue::type_strategy(&DynSolType::Uint(bits.to::<usize>()))\n            .new_tree(state.test_runner())\n            .unwrap()\n            .current()\n            .abi_encode());\n    }\n\n    if let Some((min, max)) = bounds {\n        ensure!(min <= max, \"min must be less than or equal to max\");\n        // Generate random between range min..=max\n        let exclusive_modulo = max - min;\n        let mut random_number: U256 = state.rng().random();\n        if exclusive_modulo != U256::MAX {\n            let inclusive_modulo = exclusive_modulo + U256::from(1);\n            random_number %= inclusive_modulo;\n        }\n        random_number += min;\n        return Ok(random_number.abi_encode());\n    }\n\n    // Generate random `uint256` value.\n    Ok(DynSolValue::type_strategy(&DynSolType::Uint(256))\n        .new_tree(state.test_runner())\n        .unwrap()\n        .current()\n        .abi_encode())\n}\n\n/// Helper to generate a random `int` value (with given bits if specified) from type strategy.\nfn random_int(state: &mut Cheatcodes, bits: Option<U256>) -> Result {\n    let no_bits = bits.unwrap_or(U256::from(256));\n    ensure!(no_bits <= U256::from(256), \"number of bits cannot exceed 256\");\n    Ok(DynSolValue::type_strategy(&DynSolType::Int(no_bits.to::<usize>()))\n        .new_tree(state.test_runner())\n        .unwrap()\n        .current()\n        .abi_encode())\n}\n\nimpl Cheatcode for eip712HashType_0Call {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { typeNameOrDefinition } = self;\n\n        let type_def = get_canonical_type_def(typeNameOrDefinition, state, None)?;\n\n        Ok(keccak256(type_def.as_bytes()).to_vec())\n    }\n}\n\nimpl Cheatcode for eip712HashType_1Call {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { bindingsPath, typeName } = self;\n\n        let path = state.config.ensure_path_allowed(bindingsPath, FsAccessKind::Read)?;\n        let type_def = get_type_def_from_bindings(typeName, path, &state.config.root)?;\n\n        Ok(keccak256(type_def.as_bytes()).to_vec())\n    }\n}\n\nimpl Cheatcode for eip712HashStruct_0Call {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { typeNameOrDefinition, abiEncodedData } = self;\n\n        let type_def = get_canonical_type_def(typeNameOrDefinition, state, None)?;\n        let primary = &type_def[..type_def.find('(').unwrap_or(type_def.len())];\n\n        get_struct_hash(primary, &type_def, abiEncodedData)\n    }\n}\n\nimpl Cheatcode for eip712HashStruct_1Call {\n    fn apply(&self, state: &mut Cheatcodes) -> Result {\n        let Self { bindingsPath, typeName, abiEncodedData } = self;\n\n        let path = state.config.ensure_path_allowed(bindingsPath, FsAccessKind::Read)?;\n        let type_def = get_type_def_from_bindings(typeName, path, &state.config.root)?;\n\n        get_struct_hash(typeName, &type_def, abiEncodedData)\n    }\n}\n\nimpl Cheatcode for eip712HashTypedDataCall {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { jsonData } = self;\n        let typed_data: TypedData = serde_json::from_str(jsonData)?;\n        let digest = typed_data.eip712_signing_hash()?;\n\n        Ok(digest.to_vec())\n    }\n}\n\n/// Returns EIP-712 canonical type definition from the provided string type representation or type\n/// name. If type name provided, then it looks up bindings from file generated by `forge bind-json`.\nfn get_canonical_type_def(\n    name_or_def: &String,\n    state: &mut Cheatcodes,\n    path: Option<PathBuf>,\n) -> Result<String> {\n    let type_def = if name_or_def.contains('(') {\n        // If the input contains '(', it must be the type definition.\n        EncodeType::parse(name_or_def).and_then(|parsed| parsed.canonicalize())?\n    } else {\n        // Otherwise, it must be the type name.\n        let path = path.as_ref().unwrap_or(&state.config.bind_json_path);\n        let path = state.config.ensure_path_allowed(path, FsAccessKind::Read)?;\n        get_type_def_from_bindings(name_or_def, path, &state.config.root)?\n    };\n\n    Ok(type_def)\n}\n\n/// Returns the EIP-712 type definition from the bindings in the provided path.\n/// Assumes that read validation for the path has already been checked.\nfn get_type_def_from_bindings(name: &String, path: PathBuf, root: &PathBuf) -> Result<String> {\n    let content = fs::read_to_string(&path)?;\n\n    let type_defs: HashMap<&str, &str> = content\n        .lines()\n        .filter_map(|line| {\n            let relevant = line.trim().strip_prefix(TYPE_BINDING_PREFIX)?;\n            let (name, def) = relevant.split_once('=')?;\n            Some((name.trim(), def.trim().strip_prefix('\"')?.strip_suffix(\"\\\";\")?))\n        })\n        .collect();\n\n    match type_defs.get(name.as_str()) {\n        Some(value) => Ok(value.to_string()),\n        None => {\n            let bindings =\n                type_defs.keys().map(|k| format!(\" - {k}\")).collect::<Vec<String>>().join(\"\\n\");\n\n            bail!(\n                \"'{}' not found in '{}'.{}\",\n                name,\n                path.strip_prefix(root).unwrap_or(&path).to_string_lossy(),\n                if bindings.is_empty() {\n                    String::new()\n                } else {\n                    format!(\"\\nAvailable bindings:\\n{bindings}\\n\")\n                }\n            );\n        }\n    }\n}\n\n/// Returns the EIP-712 struct hash for provided name, definition and ABI encoded data.\nfn get_struct_hash(primary: &str, type_def: &String, abi_encoded_data: &Bytes) -> Result {\n    let mut resolver = Resolver::default();\n\n    // Populate the resolver by ingesting the canonical type definition, and then get the\n    // corresponding `DynSolType` of the primary type.\n    resolver\n        .ingest_string(type_def)\n        .map_err(|e| fmt_err!(\"Resolver failed to ingest type definition: {e}\"))?;\n\n    let resolved_sol_type = resolver\n        .resolve(primary)\n        .map_err(|e| fmt_err!(\"Failed to resolve EIP-712 primary type '{primary}': {e}\"))?;\n\n    // ABI-decode the bytes into `DynSolValue::CustomStruct`.\n    let sol_value = resolved_sol_type.abi_decode(abi_encoded_data.as_ref()).map_err(|e| {\n        fmt_err!(\"Failed to ABI decode using resolved_sol_type directly for '{primary}': {e}.\")\n    })?;\n\n    // Use the resolver to properly encode the data.\n    let encoded_data: Vec<u8> = resolver\n        .encode_data(&sol_value)\n        .map_err(|e| fmt_err!(\"Failed to EIP-712 encode data for struct '{primary}': {e}\"))?\n        .ok_or_else(|| fmt_err!(\"EIP-712 data encoding returned 'None' for struct '{primary}'\"))?;\n\n    // Compute the type hash of the primary type.\n    let type_hash = resolver\n        .type_hash(primary)\n        .map_err(|e| fmt_err!(\"Failed to compute typeHash for EIP712 type '{primary}': {e}\"))?;\n\n    // Compute the struct hash of the concatenated type hash and encoded data.\n    let mut bytes_to_hash = Vec::with_capacity(32 + encoded_data.len());\n    bytes_to_hash.extend_from_slice(type_hash.as_slice());\n    bytes_to_hash.extend_from_slice(&encoded_data);\n\n    Ok(keccak256(&bytes_to_hash).to_vec())\n}\n\nimpl Cheatcode for toRlpCall {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { data } = self;\n\n        let mut buf = Vec::new();\n        data.encode(&mut buf);\n\n        Ok(Bytes::from(buf).abi_encode())\n    }\n}\n\nimpl Cheatcode for fromRlpCall {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { rlp } = self;\n\n        let decoded: Vec<Bytes> = Vec::<Bytes>::decode(&mut rlp.as_ref())\n            .map_err(|e| fmt_err!(\"Failed to decode RLP: {e}\"))?;\n\n        Ok(decoded.abi_encode())\n    }\n}\n"
  },
  {
    "path": "crates/cheatcodes/src/version.rs",
    "content": "use crate::{Cheatcode, Cheatcodes, Result, Vm::*};\nuse alloy_sol_types::SolValue;\nuse foundry_common::version::SEMVER_VERSION;\nuse semver::Version;\nuse std::cmp::Ordering;\n\nimpl Cheatcode for foundryVersionCmpCall {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { version } = self;\n        foundry_version_cmp(version).map(|cmp| (cmp as i8).abi_encode())\n    }\n}\n\nimpl Cheatcode for foundryVersionAtLeastCall {\n    fn apply(&self, _state: &mut Cheatcodes) -> Result {\n        let Self { version } = self;\n        foundry_version_cmp(version).map(|cmp| cmp.is_ge().abi_encode())\n    }\n}\n\nfn foundry_version_cmp(version: &str) -> Result<Ordering> {\n    version_cmp(SEMVER_VERSION.split('-').next().unwrap(), version)\n}\n\nfn version_cmp(version_a: &str, version_b: &str) -> Result<Ordering> {\n    let version_a = parse_version(version_a)?;\n    let version_b = parse_version(version_b)?;\n    Ok(version_a.cmp(&version_b))\n}\n\nfn parse_version(version: &str) -> Result<Version> {\n    let version =\n        Version::parse(version).map_err(|e| fmt_err!(\"invalid version `{version}`: {e}\"))?;\n    if !version.pre.is_empty() {\n        return Err(fmt_err!(\n            \"invalid version `{version}`: pre-release versions are not supported\"\n        ));\n    }\n    if !version.build.is_empty() {\n        return Err(fmt_err!(\"invalid version `{version}`: build metadata is not supported\"));\n    }\n    Ok(version)\n}\n"
  },
  {
    "path": "crates/chisel/Cargo.toml",
    "content": "[package]\nname = \"chisel\"\ndescription = \"Fast, utilitarian, and verbose Solidity REPL\"\n\nauthors.workspace = true\nversion.workspace = true\nedition.workspace = true\nrust-version.workspace = true\nlicense.workspace = true\nhomepage.workspace = true\nrepository.workspace = true\n\n[lints]\nworkspace = true\n\n[[bin]]\nname = \"chisel\"\npath = \"bin/main.rs\"\n\n[dependencies]\n# forge\nforge-doc.workspace = true\nforge-fmt.workspace = true\nfoundry-cli.workspace = true\nfoundry-common.workspace = true\nfoundry-compilers.workspace = true\nfoundry-config.workspace = true\nfoundry-evm.workspace = true\n\ntempfile.workspace = true\n\nsolar.workspace = true\n\nalloy-dyn-abi = { workspace = true, features = [\"arbitrary\"] }\nalloy-primitives = { workspace = true, features = [\n    \"serde\",\n    \"getrandom\",\n    \"arbitrary\",\n    \"rlp\",\n] }\nalloy-json-abi.workspace = true\n\nclap = { version = \"4\", features = [\"derive\", \"env\", \"wrap_help\"] }\ndirs.workspace = true\neyre.workspace = true\nreqwest.workspace = true\nrustyline = \"17\"\nitertools.workspace = true\nsemver.workspace = true\nserde_json.workspace = true\nserde.workspace = true\nsolang-parser.workspace = true\ntime = { version = \"0.3\", features = [\"formatting\"] }\nyansi.workspace = true\ntracing.workspace = true\nwalkdir.workspace = true\n\n[dev-dependencies]\ntracing-subscriber.workspace = true\n\n# REPL tests only work on Unix.\n[target.'cfg(unix)'.dev-dependencies]\nfoundry-test-utils.workspace = true\nrexpect = \"0.6\"\n\n[features]\ndefault = [\"jemalloc\"]\nasm-keccak = [\"alloy-primitives/asm-keccak\"]\njemalloc = [\"foundry-cli/jemalloc\"]\nmimalloc = [\"foundry-cli/mimalloc\"]\ntracy-allocator = [\"foundry-cli/tracy-allocator\"]\n"
  },
  {
    "path": "crates/chisel/assets/preview.tape",
    "content": "# VHS File source\n# https://github.com/charmbracelet/vhs\n#\n# Output:\n#   Output <path>.gif               Create a GIF output at the given <path>\n#   Output <path>.mp4               Create an MP4 output at the given <path>\n#   Output <path>.webm              Create a WebM output at the given <path>\n#\n# Settings:\n#   Set FontSize <number>           Set the font size of the terminal\n#   Set FontFamily <string>         Set the font family of the terminal\n#   Set Height <number>             Set the height of the terminal\n#   Set Width <number>              Set the width of the terminal\n#   Set LetterSpacing <float>       Set the font letter spacing (tracking)\n#   Set LineHeight <float>          Set the font line height\n#   Set Theme <string>              Set the theme of the terminal (JSON)\n#   Set Padding <number>            Set the padding of the terminal\n#   Set Framerate <number>          Set the framerate of the recording\n#   Set PlaybackSpeed <float>       Set the playback speed of the recording\n#\n# Sleep:\n#   Sleep <time>                    Sleep for a set amount of <time> in seconds\n#\n# Type:\n#   Type[@<time>] \"<characters>\"    Type <characters> into the terminal with a\n#                                   <time> delay between each character\n#\n# Keys:\n#   Backspace[@<time>] [number]     Press the Backspace key\n#   Down[@<time>] [number]          Press the Down key\n#   Enter[@<time>] [number]         Press the Enter key\n#   Space[@<time>] [number]         Press the Space key\n#   Tab[@<time>] [number]           Press the Tab key\n#   Left[@<time>] [number]          Press the Left Arrow key\n#   Right[@<time>] [number]         Press the Right Arrow key\n#   Up[@<time>] [number]            Press the Up Arrow key\n#   Down[@<time>] [number]          Press the Down Arrow key\n#   Ctrl+<key>                      Press the Control key + <key> (e.g. Ctrl+C)\n#\n# Display:\n#   Hide                            Hide the subsequent commands from the output\n#   Show                            Show the subsequent commands in the output\n\nOutput assets/preview.gif\n\nSet FontSize 16\nSet Width 1920\nSet Height 1080\n\nType \"chisel\"\nEnter\nSleep 500ms\n\nType \"!help\" Enter\nSleep 500ms\n\nType \"contract Test { uint public b = 0xa57b; }\"\nEnter\nSleep 500ms\n\nType \"!t\"\nEnter\nSleep 500ms\n\nType \"new Test().b()\"\nEnter\nSleep 1.5s\n\nType 'address payable emptyRipe = payable(address(ripemd160(hex\"\")))'\nEnter\nSleep 500ms\n\nType \"vm.deal(address(this), 5 ether)\"\nEnter\nSleep 500ms\n\nType \"emptyRipe.transfer(1 ether)\"\nEnter\nSleep 500ms\n\nType \"address(emptyRipe).balance\"\nEnter\nSleep 1.5s\n\nHide\nType \"!t\"\nEnter\nShow\n\nType@5ms \"function hash64(bytes32 a, bytes32 b) internal pure returns (bytes32 hash) {\"\nEnter\nType@5ms \"    assembly {\"\nEnter\nType@5ms \"        mstore(0x00, a)\"\nEnter\nType@5ms \"        mstore(0x20, b)\"\nEnter\nType@5ms \"        hash := keccak256(0x00, 0x40)\"\nEnter\nType@5ms \"    }\"\nEnter\nType@5ms \"}\"\nEnter\nSleep 500ms\n\nType \"hash64(bytes32(0), bytes32(uint(256)))\"\nEnter\nSleep 1s\n\nType \"!fork mainnet\"\nEnter\nSleep 500ms\n\nType@2ms \"!fetch 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 IWETH\"\nEnter\nSleep 1.5s\n\nType@2ms \"IWETH weth = IWETH(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2)\"\nEnter\nSleep 3s\n\nType \"weth.name()\"\nEnter\nSleep 3s\n\nType \"weth.balanceOf(address(weth))\"\nEnter\nSleep 3s\n\nType \"!so\"\nEnter\nSleep 2s\n\nType \"!s example\"\nEnter\nSleep 5s\n"
  },
  {
    "path": "crates/chisel/bin/main.rs",
    "content": "//! The `chisel` CLI: a fast, utilitarian, and verbose Solidity REPL.\n\nuse chisel::args::run;\n\n#[global_allocator]\nstatic ALLOC: foundry_cli::utils::Allocator = foundry_cli::utils::new_allocator();\n\nfn main() {\n    if let Err(err) = run() {\n        let _ = foundry_common::sh_err!(\"{err:?}\");\n        std::process::exit(1);\n    }\n}\n"
  },
  {
    "path": "crates/chisel/src/args.rs",
    "content": "use crate::{\n    opts::{Chisel, ChiselSubcommand},\n    prelude::{ChiselCommand, ChiselDispatcher, SolidityHelper},\n};\nuse clap::Parser;\nuse eyre::{Context, Result};\nuse foundry_cli::utils::{self, LoadConfig};\nuse foundry_common::fs;\nuse rustyline::{Editor, config::Configurer, error::ReadlineError};\nuse std::{ops::ControlFlow, path::PathBuf};\nuse yansi::Paint;\n\n/// Run the `chisel` command line interface.\npub fn run() -> Result<()> {\n    setup()?;\n\n    foundry_cli::opts::GlobalArgs::check_markdown_help::<Chisel>();\n\n    let args = Chisel::parse();\n    args.global.init()?;\n    args.global.tokio_runtime().block_on(run_command(args))\n}\n\n/// Setup the global logger and other utilities.\npub fn setup() -> Result<()> {\n    utils::common_setup();\n    utils::subscriber();\n\n    Ok(())\n}\n\nmacro_rules! try_cf {\n    ($e:expr) => {\n        match $e {\n            ControlFlow::Continue(()) => {}\n            ControlFlow::Break(()) => return Ok(()),\n        }\n    };\n}\n\n/// Run the subcommand.\npub async fn run_command(args: Chisel) -> Result<()> {\n    // Load configuration\n    let (config, evm_opts) = args.load_config_and_evm_opts()?;\n\n    // Create a new cli dispatcher\n    let mut dispatcher = ChiselDispatcher::new(crate::source::SessionSourceConfig {\n        // Enable traces if any level of verbosity was passed\n        traces: config.verbosity > 0,\n        foundry_config: config,\n        no_vm: args.no_vm,\n        evm_opts,\n        backend: None,\n        calldata: None,\n        ir_minimum: args.ir_minimum,\n    })?;\n\n    // Execute prelude Solidity source files\n    evaluate_prelude(&mut dispatcher, args.prelude).await?;\n\n    if let Some(cmd) = args.cmd {\n        try_cf!(handle_cli_command(&mut dispatcher, cmd).await?);\n        return Ok(());\n    }\n\n    let mut rl = Editor::<SolidityHelper, _>::new()?;\n    rl.set_helper(Some(dispatcher.helper.clone()));\n    rl.set_auto_add_history(true);\n    if let Some(path) = chisel_history_file() {\n        let _ = rl.load_history(&path);\n    }\n\n    sh_println!(\"Welcome to Chisel! Type `{}` to show available commands.\", \"!help\".green())?;\n\n    // REPL loop.\n    let mut interrupt = false;\n    loop {\n        match rl.readline(&dispatcher.get_prompt()) {\n            Ok(line) => {\n                debug!(\"dispatching next line: {line}\");\n                // Clear interrupt flag.\n                interrupt = false;\n\n                // Dispatch and match results.\n                let r = dispatcher.dispatch(&line).await;\n                dispatcher.helper.set_errored(r.is_err());\n                match r {\n                    Ok(ControlFlow::Continue(())) => {}\n                    Ok(ControlFlow::Break(())) => break,\n                    Err(e) => {\n                        sh_err!(\"{}\", foundry_common::errors::display_chain(&e))?;\n                    }\n                }\n            }\n            Err(ReadlineError::Interrupted) => {\n                if interrupt {\n                    break;\n                } else {\n                    sh_println!(\"(To exit, press Ctrl+C again)\")?;\n                    interrupt = true;\n                }\n            }\n            Err(ReadlineError::Eof) => break,\n            Err(err) => {\n                sh_err!(\"{err}\")?;\n                break;\n            }\n        }\n    }\n\n    if let Some(path) = chisel_history_file() {\n        let _ = rl.save_history(&path);\n    }\n\n    Ok(())\n}\n\n/// Evaluate multiple Solidity source files contained within a\n/// Chisel prelude directory.\nasync fn evaluate_prelude(\n    dispatcher: &mut ChiselDispatcher,\n    maybe_prelude: Option<PathBuf>,\n) -> Result<()> {\n    let Some(prelude_dir) = maybe_prelude else { return Ok(()) };\n    if prelude_dir.is_file() {\n        sh_println!(\"{} {}\", \"Loading prelude source file:\".yellow(), prelude_dir.display())?;\n        try_cf!(load_prelude_file(dispatcher, prelude_dir).await?);\n        sh_println!(\"{}\\n\", \"Prelude source file loaded successfully!\".green())?;\n    } else {\n        let prelude_sources = fs::files_with_ext(&prelude_dir, \"sol\");\n        let mut print_success_msg = false;\n        for source_file in prelude_sources {\n            print_success_msg = true;\n            sh_println!(\"{} {}\", \"Loading prelude source file:\".yellow(), source_file.display())?;\n            try_cf!(load_prelude_file(dispatcher, source_file).await?);\n        }\n\n        if print_success_msg {\n            sh_println!(\"{}\\n\", \"All prelude source files loaded successfully!\".green())?;\n        }\n    }\n    Ok(())\n}\n\n/// Loads a single Solidity file into the prelude.\nasync fn load_prelude_file(\n    dispatcher: &mut ChiselDispatcher,\n    file: PathBuf,\n) -> Result<ControlFlow<()>> {\n    let prelude = fs::read_to_string(file)\n        .wrap_err(\"Could not load source file. Are you sure this path is correct?\")?;\n    dispatcher.dispatch(&prelude).await\n}\n\nasync fn handle_cli_command(\n    d: &mut ChiselDispatcher,\n    cmd: ChiselSubcommand,\n) -> Result<ControlFlow<()>> {\n    match cmd {\n        ChiselSubcommand::List => d.dispatch_command(ChiselCommand::ListSessions).await,\n        ChiselSubcommand::Load { id } => d.dispatch_command(ChiselCommand::Load { id }).await,\n        ChiselSubcommand::View { id } => {\n            let ControlFlow::Continue(()) = d.dispatch_command(ChiselCommand::Load { id }).await?\n            else {\n                return Ok(ControlFlow::Break(()));\n            };\n            d.dispatch_command(ChiselCommand::Source).await\n        }\n        ChiselSubcommand::ClearCache => d.dispatch_command(ChiselCommand::ClearCache).await,\n        ChiselSubcommand::Eval { command } => d.dispatch(&command).await,\n    }\n}\n\nfn chisel_history_file() -> Option<PathBuf> {\n    foundry_config::Config::foundry_dir().map(|p| p.join(\".chisel_history\"))\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use clap::CommandFactory;\n\n    #[test]\n    fn verify_cli() {\n        Chisel::command().debug_assert();\n    }\n}\n"
  },
  {
    "path": "crates/chisel/src/cmd.rs",
    "content": "use crate::prelude::CHISEL_CHAR;\nuse alloy_primitives::Address;\nuse clap::{CommandFactory, Parser};\nuse itertools::Itertools;\nuse yansi::Paint;\n\n/// Chisel REPL commands.\n#[derive(Debug, Parser)]\n#[command(disable_help_flag = true, disable_help_subcommand = true)]\npub enum ChiselCommand {\n    /// Display all commands.\n    #[command(visible_alias = \"h\", next_help_heading = \"General\")]\n    Help,\n\n    /// Quit the REPL.\n    #[command(visible_alias = \"q\")]\n    Quit,\n\n    /// Executes a shell command.\n    #[command(visible_alias = \"e\")]\n    Exec {\n        /// Command to execute.\n        command: String,\n        /// Command arguments.\n        #[arg(trailing_var_arg = true)]\n        args: Vec<String>,\n    },\n\n    /// Clear the current session source.\n    #[command(visible_alias = \"c\", next_help_heading = \"Session\")]\n    Clear,\n\n    /// Print the generated source contract.\n    #[command(visible_alias = \"so\")]\n    Source,\n\n    /// Save the current session to the cache.\n    #[command(visible_alias = \"s\")]\n    Save {\n        /// Optional session ID.\n        id: Option<String>,\n    },\n\n    /// Load a previous session from cache.\n    /// WARNING: This will overwrite the current session (though the current session will be\n    /// optimistically cached).\n    #[command(visible_alias = \"l\")]\n    Load {\n        /// Session ID to load.\n        id: String,\n    },\n\n    /// List all cached sessions.\n    #[command(name = \"list\", visible_alias = \"ls\")]\n    ListSessions,\n\n    /// Clear the cache of all stored sessions.\n    #[command(name = \"clearcache\", visible_alias = \"cc\")]\n    ClearCache,\n\n    /// Export the current REPL session source to a Script file.\n    #[command(visible_alias = \"ex\")]\n    Export,\n\n    /// Fetch an interface of a verified contract on Etherscan.\n    #[command(visible_alias = \"fe\")]\n    Fetch {\n        /// Contract address.\n        addr: Address,\n        /// Interface name.\n        name: String,\n    },\n\n    /// Open the current session in an editor.\n    Edit,\n\n    /// Fork an RPC in the current session.\n    #[command(visible_alias = \"f\", next_help_heading = \"Environment\")]\n    Fork {\n        /// Fork URL, environment variable, or RPC endpoints alias (empty to return to local\n        /// network).\n        url: Option<String>,\n    },\n\n    /// Enable / disable traces for the current session.\n    #[command(visible_alias = \"t\")]\n    Traces,\n\n    /// Set calldata (`msg.data`) for the current session (appended after function selector). Clears\n    /// it if no argument provided.\n    #[command(visible_alias = \"cd\")]\n    Calldata {\n        /// Calldata (empty to clear).\n        data: Option<String>,\n    },\n\n    /// Dump the raw memory.\n    #[command(name = \"memdump\", visible_alias = \"md\", next_help_heading = \"Debug\")]\n    MemDump,\n\n    /// Dump the raw stack.\n    #[command(name = \"stackdump\", visible_alias = \"sd\")]\n    StackDump,\n\n    /// Display the raw value of a variable's stack allocation. For variables that are > 32 bytes in\n    /// length, this will display their memory pointer.\n    #[command(name = \"rawstack\", visible_alias = \"rs\")]\n    RawStack {\n        /// Variable name.\n        var: String,\n    },\n}\n\nimpl ChiselCommand {\n    pub fn parse(input: &str) -> eyre::Result<Self> {\n        let args = input.split_whitespace();\n        let args = std::iter::once(\"chisel\").chain(args);\n        Self::try_parse_from(args)\n            .map_err(|e| eyre::eyre!(\"{}; for more information, see `!help`\", e.kind()))\n    }\n\n    pub fn format_help() -> String {\n        let cmd = Self::command();\n        let mut categories = Vec::new();\n        let mut cat = None;\n        for sub in cmd.get_subcommands() {\n            if let Some(cat_) = sub.get_next_help_heading()\n                && Some(cat_) != cat\n            {\n                cat = Some(cat_);\n                categories.push((cat_, vec![]));\n            }\n            categories.last_mut().unwrap().1.push(sub);\n        }\n        format!(\n            \"{}\\n{}\",\n            format!(\"{CHISEL_CHAR} Chisel help\\n=============\").cyan(),\n            categories\n                .iter()\n                .map(|(cat, cat_cmds)| {\n                    format!(\n                        \"{}\\n{}\\n\",\n                        cat.magenta(),\n                        cat_cmds\n                            .iter()\n                            .map(|&cmd| format!(\n                                \"\\t{}{} - {}\",\n                                std::iter::once(cmd.get_name())\n                                    .chain(cmd.get_visible_aliases())\n                                    .map(|s| format!(\"!{}\", s.green()))\n                                    .format(\" | \"),\n                                {\n                                    let usage = get_usage(cmd);\n                                    if usage.is_empty() {\n                                        String::new()\n                                    } else {\n                                        format!(\" {usage}\")\n                                    }\n                                }\n                                .green(),\n                                cmd.get_about().expect(\"command is missing about\"),\n                            ))\n                            .format(\"\\n\")\n                    )\n                })\n                .format(\"\\n\")\n        )\n    }\n}\n\nfn get_usage(cmd: &clap::Command) -> String {\n    let s = cmd.clone().render_usage().to_string();\n    if let Some(idx) = s.find(['[', '<']) {\n        return s[idx..].to_string();\n    }\n    String::new()\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn print_help() {\n        let _ = sh_eprintln!(\"{}\", ChiselCommand::format_help());\n    }\n}\n"
  },
  {
    "path": "crates/chisel/src/dispatcher.rs",
    "content": "//! Dispatcher\n//!\n//! This module contains the `ChiselDispatcher` struct, which handles the dispatching\n//! of both builtin commands and Solidity snippets.\n\nuse crate::{\n    prelude::{ChiselCommand, ChiselResult, ChiselSession, SessionSourceConfig, SolidityHelper},\n    source::SessionSource,\n};\nuse alloy_primitives::{Address, hex};\nuse eyre::{Context, Result};\nuse forge_fmt::FormatterConfig;\nuse foundry_cli::utils::fetch_abi_from_etherscan;\nuse foundry_config::RpcEndpointUrl;\nuse foundry_evm::{\n    decode::decode_console_logs,\n    traces::{\n        CallTraceDecoder, CallTraceDecoderBuilder, TraceKind, decode_trace_arena,\n        identifier::{SignaturesIdentifier, TraceIdentifiers},\n        render_trace_arena,\n    },\n};\nuse reqwest::Url;\nuse solar::{\n    parse::lexer::token::{RawLiteralKind, RawTokenKind},\n    sema::ast::Base,\n};\nuse std::{\n    borrow::Cow,\n    io::Write,\n    ops::ControlFlow,\n    path::{Path, PathBuf},\n    process::Command,\n};\nuse tempfile::Builder;\nuse yansi::Paint;\n\n/// Prompt arrow character.\npub const PROMPT_ARROW: char = '➜';\n/// Prompt arrow string.\npub const PROMPT_ARROW_STR: &str = \"➜\";\nconst DEFAULT_PROMPT: &str = \"➜ \";\n\n/// Command leader character\npub const COMMAND_LEADER: char = '!';\n/// Chisel character\npub const CHISEL_CHAR: &str = \"⚒️\";\n\n/// Chisel input dispatcher\n#[derive(Debug)]\npub struct ChiselDispatcher {\n    pub session: ChiselSession,\n    pub helper: SolidityHelper,\n}\n\n/// Helper function that formats solidity source with the given [FormatterConfig]\npub fn format_source(source: &str, config: FormatterConfig) -> eyre::Result<String> {\n    let formatted = forge_fmt::format(source, config).into_result()?;\n    Ok(formatted)\n}\n\nimpl ChiselDispatcher {\n    /// Associated public function to create a new Dispatcher instance\n    pub fn new(config: SessionSourceConfig) -> eyre::Result<Self> {\n        let session = ChiselSession::new(config)?;\n        Ok(Self { session, helper: Default::default() })\n    }\n\n    /// Returns the optional ID of the current session.\n    pub fn id(&self) -> Option<&str> {\n        self.session.id.as_deref()\n    }\n\n    /// Returns the [`SessionSource`].\n    pub fn source(&self) -> &SessionSource {\n        &self.session.source\n    }\n\n    /// Returns the [`SessionSource`].\n    pub fn source_mut(&mut self) -> &mut SessionSource {\n        &mut self.session.source\n    }\n\n    fn format_source(&self) -> eyre::Result<String> {\n        format_source(\n            &self.source().to_repl_source(),\n            self.source().config.foundry_config.fmt.clone(),\n        )\n    }\n\n    /// Returns the prompt based on the current status of the Dispatcher\n    pub fn get_prompt(&self) -> Cow<'static, str> {\n        match self.session.id.as_deref() {\n            // `(ID: {id}) ➜ `\n            Some(id) => {\n                let mut prompt = String::with_capacity(DEFAULT_PROMPT.len() + id.len() + 7);\n                prompt.push_str(\"(ID: \");\n                prompt.push_str(id);\n                prompt.push_str(\") \");\n                prompt.push_str(DEFAULT_PROMPT);\n                Cow::Owned(prompt)\n            }\n            // `➜ `\n            None => Cow::Borrowed(DEFAULT_PROMPT),\n        }\n    }\n\n    /// Dispatches an input as a command via [Self::dispatch_command] or as a Solidity snippet.\n    pub async fn dispatch(&mut self, mut input: &str) -> Result<ControlFlow<()>> {\n        if let Some(command) = input.strip_prefix(COMMAND_LEADER) {\n            return match ChiselCommand::parse(command) {\n                Ok(cmd) => self.dispatch_command(cmd).await,\n                Err(e) => eyre::bail!(\"unrecognized command: {e}\"),\n            };\n        }\n\n        let source = self.source_mut();\n\n        input = input.trim();\n        let (only_trivia, new_input) = preprocess(input);\n        input = &*new_input;\n\n        // If the input is a comment, add it to the run code so we avoid running with empty input\n        if only_trivia {\n            debug!(?input, \"matched trivia\");\n            if !input.is_empty() {\n                source.add_run_code(input);\n            }\n            return Ok(ControlFlow::Continue(()));\n        }\n\n        // Create new source with exact input appended and parse\n        let (new_source, do_execute) = source.clone_with_new_line(input.to_string())?;\n\n        let (cf, res) = source.inspect(input).await?;\n        if let Some(res) = &res {\n            let _ = sh_println!(\"{res}\");\n        }\n        if cf.is_break() {\n            debug!(%input, ?res, \"inspect success\");\n            return Ok(ControlFlow::Continue(()));\n        }\n\n        if do_execute {\n            self.execute_and_replace(new_source).await.map(ControlFlow::Continue)\n        } else {\n            let out = new_source.build()?;\n            debug!(%input, ?out, \"skipped execute and rebuild source\");\n            *self.source_mut() = new_source;\n            Ok(ControlFlow::Continue(()))\n        }\n    }\n\n    /// Decodes traces in the given [`ChiselResult`].\n    // TODO: Add `known_contracts` back in.\n    pub async fn decode_traces(\n        session_config: &SessionSourceConfig,\n        result: &mut ChiselResult,\n        // known_contracts: &ContractsByArtifact,\n    ) -> eyre::Result<CallTraceDecoder> {\n        let mut decoder = CallTraceDecoderBuilder::new()\n            .with_labels(result.labeled_addresses.clone())\n            .with_signature_identifier(SignaturesIdentifier::from_config(\n                &session_config.foundry_config,\n            )?)\n            .build();\n\n        let mut identifier = TraceIdentifiers::new().with_external(\n            &session_config.foundry_config,\n            session_config.evm_opts.get_remote_chain_id().await,\n        )?;\n        if !identifier.is_empty() {\n            for (_, trace) in &mut result.traces {\n                decoder.identify(trace, &mut identifier);\n            }\n        }\n        Ok(decoder)\n    }\n\n    /// Display the gathered traces of a REPL execution.\n    pub async fn show_traces(\n        decoder: &CallTraceDecoder,\n        result: &mut ChiselResult,\n    ) -> eyre::Result<()> {\n        if result.traces.is_empty() {\n            return Ok(());\n        }\n\n        sh_println!(\"{}\", \"Traces:\".green())?;\n        for (kind, trace) in &mut result.traces {\n            // Display all Setup + Execution traces.\n            if matches!(kind, TraceKind::Setup | TraceKind::Execution) {\n                decode_trace_arena(trace, decoder).await;\n                sh_println!(\"{}\", render_trace_arena(trace))?;\n            }\n        }\n\n        Ok(())\n    }\n\n    async fn execute_and_replace(&mut self, mut new_source: SessionSource) -> Result<()> {\n        let mut res = new_source.execute().await?;\n        let failed = !res.success;\n        if new_source.config.traces || failed {\n            if let Ok(decoder) = Self::decode_traces(&new_source.config, &mut res).await {\n                Self::show_traces(&decoder, &mut res).await?;\n\n                // Show console logs, if there are any\n                let decoded_logs = decode_console_logs(&res.logs);\n                if !decoded_logs.is_empty() {\n                    let _ = sh_println!(\"{}\", \"Logs:\".green());\n                    for log in decoded_logs {\n                        let _ = sh_println!(\"  {log}\");\n                    }\n                }\n            }\n\n            if failed {\n                // If the contract execution failed, continue on without\n                // updating the source.\n                eyre::bail!(\"Failed to execute edited contract!\");\n            }\n        }\n\n        // the code could be compiled, save it\n        *self.source_mut() = new_source;\n\n        Ok(())\n    }\n}\n\n/// [`ChiselCommand`] implementations.\nimpl ChiselDispatcher {\n    /// Dispatches a [`ChiselCommand`].\n    pub async fn dispatch_command(&mut self, cmd: ChiselCommand) -> Result<ControlFlow<()>> {\n        match cmd {\n            ChiselCommand::Quit => Ok(ControlFlow::Break(())),\n            cmd => self.dispatch_command_impl(cmd).await.map(ControlFlow::Continue),\n        }\n    }\n\n    async fn dispatch_command_impl(&mut self, cmd: ChiselCommand) -> Result<()> {\n        match cmd {\n            ChiselCommand::Help => self.show_help(),\n            ChiselCommand::Quit => unreachable!(),\n            ChiselCommand::Clear => self.clear_source(),\n            ChiselCommand::Save { id } => self.save_session(id),\n            ChiselCommand::Load { id } => self.load_session(&id),\n            ChiselCommand::ListSessions => self.list_sessions(),\n            ChiselCommand::Source => self.show_source(),\n            ChiselCommand::ClearCache => self.clear_cache(),\n            ChiselCommand::Fork { url } => self.set_fork(url),\n            ChiselCommand::Traces => self.toggle_traces(),\n            ChiselCommand::Calldata { data } => self.set_calldata(data.as_deref()),\n            ChiselCommand::MemDump => self.show_mem_dump().await,\n            ChiselCommand::StackDump => self.show_stack_dump().await,\n            ChiselCommand::Export => self.export(),\n            ChiselCommand::Fetch { addr, name } => self.fetch_interface(addr, name).await,\n            ChiselCommand::Exec { command, args } => self.exec_command(command, args),\n            ChiselCommand::Edit => self.edit_session().await,\n            ChiselCommand::RawStack { var } => self.show_raw_stack(var).await,\n        }\n    }\n\n    pub(crate) fn show_help(&self) -> Result<()> {\n        sh_println!(\"{}\", ChiselCommand::format_help())\n    }\n\n    pub(crate) fn clear_source(&mut self) -> Result<()> {\n        self.source_mut().clear();\n        sh_println!(\"Cleared session!\")\n    }\n\n    pub(crate) fn save_session(&mut self, id: Option<String>) -> Result<()> {\n        // If a new name was supplied, overwrite the ID of the current session.\n        if let Some(id) = id {\n            // TODO: Should we delete the old cache file if the id of the session changes?\n            self.session.id = Some(id);\n        }\n\n        self.session.write()?;\n        sh_println!(\"Saved session to cache with ID = {}\", self.session.id.as_ref().unwrap())\n    }\n\n    pub(crate) fn load_session(&mut self, id: &str) -> Result<()> {\n        // Try to save the current session before loading another.\n        // Don't save an empty session.\n        if !self.source().run_code.is_empty() {\n            self.session.write()?;\n            sh_println!(\"{}\", \"Saved current session!\".green())?;\n        }\n\n        let new_session = match id {\n            \"latest\" => ChiselSession::latest(),\n            id => ChiselSession::load(id),\n        }\n        .wrap_err(\"failed to load session\")?;\n\n        new_session.source.build()?;\n        self.session = new_session;\n        sh_println!(\"Loaded Chisel session! (ID = {})\", self.session.id.as_ref().unwrap())\n    }\n\n    pub(crate) fn list_sessions(&self) -> Result<()> {\n        let sessions = ChiselSession::get_sessions()?;\n        if sessions.is_empty() {\n            eyre::bail!(\"No sessions found. Use the `!save` command to save a session.\");\n        }\n        sh_println!(\n            \"{}\\n{}\",\n            format!(\"{CHISEL_CHAR} Chisel Sessions\").cyan(),\n            sessions\n                .iter()\n                .map(|(time, name)| format!(\"{} - {}\", format!(\"{time:?}\").blue(), name))\n                .collect::<Vec<String>>()\n                .join(\"\\n\")\n        )\n    }\n\n    pub(crate) fn show_source(&self) -> Result<()> {\n        let formatted = self.format_source().wrap_err(\"failed to format session source\")?;\n        let highlighted = self.helper.highlight(&formatted);\n        sh_println!(\"{highlighted}\")\n    }\n\n    pub(crate) fn clear_cache(&mut self) -> Result<()> {\n        ChiselSession::clear_cache().wrap_err(\"failed to clear cache\")?;\n        self.session.id = None;\n        sh_println!(\"Cleared chisel cache!\")\n    }\n\n    pub(crate) fn set_fork(&mut self, url: Option<String>) -> Result<()> {\n        let Some(url) = url else {\n            self.source_mut().config.evm_opts.fork_url = None;\n            sh_println!(\"Now using local environment.\")?;\n            return Ok(());\n        };\n\n        // If the argument is an RPC alias designated in the\n        // `[rpc_endpoints]` section of the `foundry.toml` within\n        // the pwd, use the URL matched to the key.\n        let endpoint = if let Some(endpoint) =\n            self.source_mut().config.foundry_config.rpc_endpoints.get(&url)\n        {\n            endpoint.clone()\n        } else {\n            RpcEndpointUrl::Env(url).into()\n        };\n        let fork_url = endpoint.resolve().url()?;\n\n        if let Err(e) = Url::parse(&fork_url) {\n            eyre::bail!(\"invalid fork URL: {e}\");\n        }\n\n        sh_println!(\"Set fork URL to {}\", fork_url.yellow())?;\n\n        self.source_mut().config.evm_opts.fork_url = Some(fork_url);\n        // Clear the backend so that it is re-instantiated with the new fork\n        // upon the next execution of the session source.\n        self.source_mut().config.backend = None;\n\n        Ok(())\n    }\n\n    pub(crate) fn toggle_traces(&mut self) -> Result<()> {\n        let t = &mut self.source_mut().config.traces;\n        *t = !*t;\n        sh_println!(\"{} traces!\", if *t { \"Enabled\" } else { \"Disabled\" })\n    }\n\n    pub(crate) fn set_calldata(&mut self, data: Option<&str>) -> Result<()> {\n        // remove empty space, double quotes, and 0x prefix\n        let arg = data\n            .map(|s| s.trim_matches(|c: char| c.is_whitespace() || c == '\"' || c == '\\''))\n            .map(|s| s.strip_prefix(\"0x\").unwrap_or(s))\n            .unwrap_or(\"\");\n\n        if arg.is_empty() {\n            self.source_mut().config.calldata = None;\n            sh_println!(\"Calldata cleared.\")?;\n            return Ok(());\n        }\n\n        let calldata = hex::decode(arg);\n        match calldata {\n            Ok(calldata) => {\n                self.source_mut().config.calldata = Some(calldata);\n                sh_println!(\"Set calldata to '{}'\", arg.yellow())\n            }\n            Err(e) => {\n                eyre::bail!(\"Invalid calldata: {e}\")\n            }\n        }\n    }\n\n    pub(crate) async fn show_mem_dump(&mut self) -> Result<()> {\n        let res = self.source_mut().execute().await?;\n        let Some((_, mem)) = res.state.as_ref() else {\n            eyre::bail!(\"Run function is empty.\");\n        };\n        for i in (0..mem.len()).step_by(32) {\n            let _ = sh_println!(\n                \"{}: {}\",\n                format!(\"[0x{:02x}:0x{:02x}]\", i, i + 32).yellow(),\n                hex::encode_prefixed(&mem[i..i + 32]).cyan()\n            );\n        }\n        Ok(())\n    }\n\n    pub(crate) async fn show_stack_dump(&mut self) -> Result<()> {\n        let res = self.source_mut().execute().await?;\n        let Some((stack, _)) = res.state.as_ref() else {\n            eyre::bail!(\"Run function is empty.\");\n        };\n        for i in (0..stack.len()).rev() {\n            let _ = sh_println!(\n                \"{}: {}\",\n                format!(\"[{}]\", stack.len() - i - 1).yellow(),\n                format!(\"0x{:02x}\", stack[i]).cyan()\n            );\n        }\n        Ok(())\n    }\n\n    pub(crate) fn export(&self) -> Result<()> {\n        // Check if the pwd is a foundry project\n        if !Path::new(\"foundry.toml\").exists() {\n            eyre::bail!(\"Must be in a foundry project to export source to script.\");\n        }\n\n        // Create \"script\" dir if it does not already exist.\n        if !Path::new(\"script\").exists() {\n            std::fs::create_dir_all(\"script\")?;\n        }\n\n        let formatted_source = self.format_source()?;\n        std::fs::write(PathBuf::from(\"script/REPL.s.sol\"), formatted_source)?;\n        sh_println!(\"Exported session source to script/REPL.s.sol!\")\n    }\n\n    /// Fetches an interface from Etherscan\n    pub(crate) async fn fetch_interface(&mut self, address: Address, name: String) -> Result<()> {\n        let abis = fetch_abi_from_etherscan(address, &self.source().config.foundry_config)\n            .await\n            .wrap_err(\"Failed to fetch ABI from Etherscan\")?;\n        let (abi, _) = abis\n            .into_iter()\n            .next()\n            .ok_or_else(|| eyre::eyre!(\"No ABI found for address {address} on Etherscan\"))?;\n        let code = forge_fmt::format(&abi.to_sol(&name, None), FormatterConfig::default())\n            .into_result()?;\n        self.source_mut().add_global_code(&code);\n        sh_println!(\"Added {address}'s interface to source as `{name}`\")\n    }\n\n    pub(crate) fn exec_command(&self, command: String, args: Vec<String>) -> Result<()> {\n        let mut cmd = Command::new(command);\n        cmd.args(args);\n        let _ = cmd.status()?;\n        Ok(())\n    }\n\n    pub(crate) async fn edit_session(&mut self) -> Result<()> {\n        // create a temp file with the content of the run code\n        let mut tmp = Builder::new()\n            .prefix(\"chisel-\")\n            .suffix(\".sol\")\n            .tempfile()\n            .wrap_err(\"Could not create temporary file\")?;\n        tmp.as_file_mut()\n            .write_all(self.source().run_code.as_bytes())\n            .wrap_err(\"Could not write to temporary file\")?;\n\n        // open the temp file with the editor\n        let editor = std::env::var(\"EDITOR\").unwrap_or_else(|_| \"vim\".to_string());\n        let mut cmd = Command::new(editor);\n        cmd.arg(tmp.path());\n        let st = cmd.status()?;\n        if !st.success() {\n            eyre::bail!(\"Editor exited with {st}\");\n        }\n\n        let edited_code = std::fs::read_to_string(tmp.path())?;\n        let mut new_source = self.source().clone();\n        new_source.clear_run();\n        new_source.add_run_code(&edited_code);\n\n        // if the editor exited successfully, try to compile the new code\n        self.execute_and_replace(new_source).await?;\n        sh_println!(\"Successfully edited `run()` function's body!\")\n    }\n\n    pub(crate) async fn show_raw_stack(&mut self, var: String) -> Result<()> {\n        let source = self.source_mut();\n        let line = format!(\"bytes32 __raw__; assembly {{ __raw__ := {var} }}\");\n        if let Ok((new_source, _)) = source.clone_with_new_line(line)\n            && let (_, Some(res)) = new_source.inspect(\"__raw__\").await?\n        {\n            sh_println!(\"{res}\")?;\n            return Ok(());\n        }\n\n        eyre::bail!(\"Variable must exist within `run()` function.\")\n    }\n}\n\n/// Preprocesses addresses to ensure they are correctly checksummed and returns whether the input\n/// only contained trivia (comments, whitespace).\nfn preprocess(input: &str) -> (bool, Cow<'_, str>) {\n    let mut only_trivia = true;\n    let mut new_input = Cow::Borrowed(input);\n    for (pos, token) in solar::parse::Cursor::new(input).with_position() {\n        use RawTokenKind::*;\n\n        if matches!(token.kind, Whitespace | LineComment { .. } | BlockComment { .. }) {\n            continue;\n        }\n        only_trivia = false;\n\n        // Ensure that addresses are correctly checksummed.\n        if let Literal { kind: RawLiteralKind::Int { base: Base::Hexadecimal, .. } } = token.kind\n            && token.len == 42\n        {\n            let range = pos..pos + 42;\n            if let Ok(addr) = input[range.clone()].parse::<Address>() {\n                new_input.to_mut().replace_range(range, addr.to_checksum_buffer(None).as_str());\n            }\n        }\n    }\n    (only_trivia, new_input)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_trivia() {\n        fn only_trivia(s: &str) -> bool {\n            let (only_trivia, _new_input) = preprocess(s);\n            only_trivia\n        }\n        assert!(only_trivia(\"// line comment\"));\n        assert!(only_trivia(\"  \\n// line \\tcomment\\n\"));\n        assert!(!only_trivia(\"// line \\ncomment\"));\n\n        assert!(only_trivia(\"/* block comment */\"));\n        assert!(only_trivia(\" \\t\\n  /* block \\n \\t comment */\\n\"));\n        assert!(!only_trivia(\"/* block \\n \\t comment */\\nwith \\tother\"));\n    }\n}\n"
  },
  {
    "path": "crates/chisel/src/executor.rs",
    "content": "//! Executor\n//!\n//! This module contains the execution logic for the [SessionSource].\n\nuse crate::{\n    prelude::{ChiselDispatcher, ChiselResult, ChiselRunner, SessionSource, SolidityHelper},\n    source::IntermediateOutput,\n};\nuse alloy_dyn_abi::{DynSolType, DynSolValue};\nuse alloy_json_abi::EventParam;\nuse alloy_primitives::{Address, B256, U256, hex};\nuse eyre::{Result, WrapErr};\nuse foundry_compilers::Artifact;\nuse foundry_evm::{\n    backend::Backend, decode::decode_console_logs, executors::ExecutorBuilder,\n    inspectors::CheatsConfig, traces::TraceMode,\n};\nuse solang_parser::pt;\nuse std::ops::ControlFlow;\nuse yansi::Paint;\n\n/// Executor implementation for [SessionSource]\nimpl SessionSource {\n    /// Runs the source with the [ChiselRunner]\n    pub async fn execute(&mut self) -> Result<ChiselResult> {\n        // Recompile the project and ensure no errors occurred.\n        let output = self.build()?;\n\n        let (bytecode, final_pc) = output.enter(|output| -> Result<_> {\n            let contract = output\n                .repl_contract()\n                .ok_or_else(|| eyre::eyre!(\"failed to find REPL contract\"))?;\n            trace!(?contract, \"REPL contract\");\n            let bytecode = contract\n                .get_bytecode_bytes()\n                .ok_or_else(|| eyre::eyre!(\"No bytecode found for `REPL` contract\"))?;\n            Ok((bytecode.into_owned(), output.final_pc(contract)?))\n        })?;\n        let final_pc = final_pc.unwrap_or_default();\n        let mut runner = self.build_runner(final_pc).await?;\n        runner.run(bytecode)\n    }\n\n    /// Inspect a contract element inside of the current session\n    ///\n    /// ### Takes\n    ///\n    /// A solidity snippet\n    ///\n    /// ### Returns\n    ///\n    /// If the input is valid `Ok((continue, formatted_output))` where:\n    /// - `continue` is true if the input should be appended to the source\n    /// - `formatted_output` is the formatted value, if any\n    pub async fn inspect(&self, input: &str) -> Result<(ControlFlow<()>, Option<String>)> {\n        let line = format!(\"bytes memory inspectoor = abi.encode({input});\");\n        let mut source = match self.clone_with_new_line(line) {\n            Ok((source, _)) => source,\n            Err(err) => {\n                debug!(%err, \"failed to build new source for inspection\");\n                return Ok((ControlFlow::Continue(()), None));\n            }\n        };\n\n        let mut source_without_inspector = self.clone();\n\n        // Events and tuples fails compilation due to it not being able to be encoded in\n        // `inspectoor`. If that happens, try executing without the inspector.\n        let (mut res, err) = match source.execute().await {\n            Ok(res) => (res, None),\n            Err(err) => {\n                debug!(?err, %input, \"execution failed\");\n                match source_without_inspector.execute().await {\n                    Ok(res) => (res, Some(err)),\n                    Err(_) => {\n                        if self.config.foundry_config.verbosity >= 3 {\n                            sh_err!(\"Could not inspect: {err}\")?;\n                        }\n                        return Ok((ControlFlow::Continue(()), None));\n                    }\n                }\n            }\n        };\n\n        // If abi-encoding the input failed, check whether it is an event\n        if let Some(err) = err {\n            let output = source_without_inspector.build()?;\n\n            let formatted_event =\n                output.enter(|output| output.get_event(input).map(format_event_definition));\n            if let Some(formatted_event) = formatted_event {\n                return Ok((ControlFlow::Break(()), Some(formatted_event?)));\n            }\n\n            // we were unable to check the event\n            if self.config.foundry_config.verbosity >= 3 {\n                sh_err!(\"Failed eval: {err}\")?;\n            }\n\n            debug!(%err, %input, \"failed abi encode input\");\n            return Ok((ControlFlow::Break(()), None));\n        }\n        drop(source_without_inspector);\n\n        let Some((stack, memory)) = &res.state else {\n            // Show traces and logs, if there are any, and return an error\n            if let Ok(decoder) = ChiselDispatcher::decode_traces(&source.config, &mut res).await {\n                ChiselDispatcher::show_traces(&decoder, &mut res).await?;\n            }\n            let decoded_logs = decode_console_logs(&res.logs);\n            if !decoded_logs.is_empty() {\n                sh_println!(\"{}\", \"Logs:\".green())?;\n                for log in decoded_logs {\n                    sh_println!(\"  {log}\")?;\n                }\n            }\n\n            return Err(eyre::eyre!(\"Failed to inspect expression\"));\n        };\n\n        // Either the expression referred to by `input`, or the last expression,\n        // which was wrapped in `abi.encode`.\n        let generated_output = source.build()?;\n\n        // If the expression is a variable declaration within the REPL contract, use its type;\n        // otherwise, attempt to infer the type.\n        let contract_expr = generated_output\n            .intermediate\n            .repl_contract_expressions\n            .get(input)\n            .or_else(|| source.infer_inner_expr_type());\n\n        // If the current action is a function call, we get its return type\n        // otherwise it returns None\n        let function_call_return_type =\n            Type::get_function_return_type(contract_expr, &generated_output.intermediate);\n\n        let (contract_expr, ty) = if let Some(function_call_return_type) = function_call_return_type\n        {\n            (function_call_return_type.0, function_call_return_type.1)\n        } else {\n            match contract_expr.and_then(|e| {\n                Type::ethabi(e, Some(&generated_output.intermediate)).map(|ty| (e, ty))\n            }) {\n                Some(res) => res,\n                // this type was denied for inspection, continue\n                None => return Ok((ControlFlow::Continue(()), None)),\n            }\n        };\n\n        // the file compiled correctly, thus the last stack item must be the memory offset of\n        // the `bytes memory inspectoor` value\n        let data = (|| -> Option<_> {\n            let mut offset: usize = stack.last()?.try_into().ok()?;\n            debug!(\"inspect memory @ {offset}: {}\", hex::encode(memory));\n            let mem_offset = memory.get(offset..offset + 32)?;\n            let len: usize = U256::try_from_be_slice(mem_offset)?.try_into().ok()?;\n            offset += 32;\n            memory.get(offset..offset + len)\n        })();\n        let Some(data) = data else {\n            eyre::bail!(\"Failed to inspect last expression: could not retrieve data from memory\")\n        };\n        let token = ty.abi_decode(data).wrap_err(\"Could not decode inspected values\")?;\n        let c = if should_continue(contract_expr) {\n            ControlFlow::Continue(())\n        } else {\n            ControlFlow::Break(())\n        };\n        Ok((c, Some(format_token(token))))\n    }\n\n    /// Gracefully attempts to extract the type of the expression within the `abi.encode(...)`\n    /// call inserted by the inspect function.\n    ///\n    /// ### Takes\n    ///\n    /// A reference to a [SessionSource]\n    ///\n    /// ### Returns\n    ///\n    /// Optionally, a [Type]\n    fn infer_inner_expr_type(&self) -> Option<&pt::Expression> {\n        let out = self.build().ok()?;\n        let run = out.run_func_body().ok()?.last();\n        match run {\n            Some(pt::Statement::VariableDefinition(\n                _,\n                _,\n                Some(pt::Expression::FunctionCall(_, _, args)),\n            )) => {\n                // We can safely unwrap the first expression because this function\n                // will only be called on a session source that has just had an\n                // `inspectoor` variable appended to it.\n                Some(args.first().unwrap())\n            }\n            _ => None,\n        }\n    }\n\n    async fn build_runner(&mut self, final_pc: usize) -> Result<ChiselRunner> {\n        let (evm_env, tx_env) = self.config.evm_opts.env().await?;\n\n        let backend = match self.config.backend.clone() {\n            Some(backend) => backend,\n            None => {\n                let fork =\n                    self.config.evm_opts.get_fork(&self.config.foundry_config, evm_env.clone());\n                let backend = Backend::spawn(fork)?;\n                self.config.backend = Some(backend.clone());\n                backend\n            }\n        };\n\n        let executor = ExecutorBuilder::new()\n            .inspectors(|stack| {\n                stack\n                    .logs(self.config.foundry_config.live_logs)\n                    .chisel_state(final_pc)\n                    .trace_mode(TraceMode::Call)\n                    .cheatcodes(\n                        CheatsConfig::new(\n                            &self.config.foundry_config,\n                            self.config.evm_opts.clone(),\n                            None,\n                            None,\n                        )\n                        .into(),\n                    )\n            })\n            .gas_limit(self.config.evm_opts.gas_limit())\n            .spec_id(self.config.foundry_config.evm_spec_id())\n            .legacy_assertions(self.config.foundry_config.legacy_assertions)\n            .build(evm_env, tx_env, backend);\n\n        Ok(ChiselRunner::new(executor, U256::MAX, Address::ZERO, self.config.calldata.clone()))\n    }\n}\n\n/// Formats a value into an inspection message\n// TODO: Verbosity option\nfn format_token(token: DynSolValue) -> String {\n    match token {\n        DynSolValue::Address(a) => {\n            format!(\"Type: {}\\n└ Data: {}\", \"address\".red(), a.cyan())\n        }\n        DynSolValue::FixedBytes(b, byte_len) => {\n            format!(\n                \"Type: {}\\n└ Data: {}\",\n                format!(\"bytes{byte_len}\").red(),\n                hex::encode_prefixed(b).cyan()\n            )\n        }\n        DynSolValue::Int(i, bit_len) => {\n            format!(\n                \"Type: {}\\n├ Hex: {}\\n├ Hex (full word): {}\\n└ Decimal: {}\",\n                format!(\"int{bit_len}\").red(),\n                format!(\n                    \"0x{}\",\n                    format!(\"{i:x}\")\n                        .chars()\n                        .skip(if i.is_negative() { 64 - bit_len / 4 } else { 0 })\n                        .collect::<String>()\n                )\n                .cyan(),\n                hex::encode_prefixed(B256::from(i)).cyan(),\n                i.cyan()\n            )\n        }\n        DynSolValue::Uint(i, bit_len) => {\n            format!(\n                \"Type: {}\\n├ Hex: {}\\n├ Hex (full word): {}\\n└ Decimal: {}\",\n                format!(\"uint{bit_len}\").red(),\n                format!(\"0x{i:x}\").cyan(),\n                hex::encode_prefixed(B256::from(i)).cyan(),\n                i.cyan()\n            )\n        }\n        DynSolValue::Bool(b) => {\n            format!(\"Type: {}\\n└ Value: {}\", \"bool\".red(), b.cyan())\n        }\n        DynSolValue::String(_) | DynSolValue::Bytes(_) => {\n            let hex = hex::encode(token.abi_encode());\n            let s = token.as_str();\n            format!(\n                \"Type: {}\\n{}├ Hex (Memory):\\n├─ Length ({}): {}\\n├─ Contents ({}): {}\\n├ Hex (Tuple Encoded):\\n├─ Pointer ({}): {}\\n├─ Length ({}): {}\\n└─ Contents ({}): {}\",\n                if s.is_some() { \"string\" } else { \"dynamic bytes\" }.red(),\n                if let Some(s) = s {\n                    format!(\"├ UTF-8: {}\\n\", s.cyan())\n                } else {\n                    String::default()\n                },\n                \"[0x00:0x20]\".yellow(),\n                format!(\"0x{}\", &hex[64..128]).cyan(),\n                \"[0x20:..]\".yellow(),\n                format!(\"0x{}\", &hex[128..]).cyan(),\n                \"[0x00:0x20]\".yellow(),\n                format!(\"0x{}\", &hex[..64]).cyan(),\n                \"[0x20:0x40]\".yellow(),\n                format!(\"0x{}\", &hex[64..128]).cyan(),\n                \"[0x40:..]\".yellow(),\n                format!(\"0x{}\", &hex[128..]).cyan(),\n            )\n        }\n        DynSolValue::FixedArray(tokens) | DynSolValue::Array(tokens) => {\n            let mut out = format!(\n                \"{}({}) = {}\",\n                \"array\".red(),\n                format!(\"{}\", tokens.len()).yellow(),\n                '['.red()\n            );\n            for token in tokens {\n                out.push_str(\"\\n  ├ \");\n                out.push_str(&format_token(token).replace('\\n', \"\\n  \"));\n                out.push('\\n');\n            }\n            out.push_str(&']'.red().to_string());\n            out\n        }\n        DynSolValue::Tuple(tokens) => {\n            let displayed_types = tokens\n                .iter()\n                .map(|t| t.sol_type_name().unwrap_or_default())\n                .collect::<Vec<_>>()\n                .join(\", \");\n            let mut out =\n                format!(\"{}({}) = {}\", \"tuple\".red(), displayed_types.yellow(), '('.red());\n            for token in tokens {\n                out.push_str(\"\\n  ├ \");\n                out.push_str(&format_token(token).replace('\\n', \"\\n  \"));\n                out.push('\\n');\n            }\n            out.push_str(&')'.red().to_string());\n            out\n        }\n        _ => {\n            unimplemented!()\n        }\n    }\n}\n\n/// Formats a [pt::EventDefinition] into an inspection message\n///\n/// ### Takes\n///\n/// An borrowed [pt::EventDefinition]\n///\n/// ### Returns\n///\n/// A formatted [pt::EventDefinition] for use in inspection output.\n// TODO: Verbosity option\nfn format_event_definition(event_definition: &pt::EventDefinition) -> Result<String> {\n    let event_name = event_definition.name.as_ref().expect(\"Event has a name\").to_string();\n    let inputs = event_definition\n        .fields\n        .iter()\n        .map(|param| {\n            let name = param\n                .name\n                .as_ref()\n                .map(ToString::to_string)\n                .unwrap_or_else(|| \"<anonymous>\".to_string());\n            let kind = Type::from_expression(&param.ty)\n                .and_then(Type::into_builtin)\n                .ok_or_else(|| eyre::eyre!(\"Invalid type in event {event_name}\"))?;\n            Ok(EventParam {\n                name,\n                ty: kind.to_string(),\n                components: vec![],\n                indexed: param.indexed,\n                internal_type: None,\n            })\n        })\n        .collect::<Result<Vec<_>>>()?;\n    let event =\n        alloy_json_abi::Event { name: event_name, inputs, anonymous: event_definition.anonymous };\n\n    Ok(format!(\n        \"Type: {}\\n├ Name: {}\\n├ Signature: {:?}\\n└ Selector: {:?}\",\n        \"event\".red(),\n        SolidityHelper::new().highlight(&format!(\n            \"{}({})\",\n            &event.name,\n            &event\n                .inputs\n                .iter()\n                .map(|param| format!(\n                    \"{}{}{}\",\n                    param.ty,\n                    if param.indexed { \" indexed\" } else { \"\" },\n                    if param.name.is_empty() {\n                        String::default()\n                    } else {\n                        format!(\" {}\", &param.name)\n                    },\n                ))\n                .collect::<Vec<_>>()\n                .join(\", \")\n        )),\n        event.signature().cyan(),\n        event.selector().cyan(),\n    ))\n}\n\n// =============================================\n// Modified from\n// [soli](https://github.com/jpopesculian/soli)\n// =============================================\n\n#[derive(Clone, Debug, PartialEq)]\nenum Type {\n    /// (type)\n    Builtin(DynSolType),\n\n    /// (type)\n    Array(Box<Self>),\n\n    /// (type, length)\n    FixedArray(Box<Self>, usize),\n\n    /// (type, index)\n    ArrayIndex(Box<Self>, Option<usize>),\n\n    /// (types)\n    Tuple(Vec<Option<Self>>),\n\n    /// (name, params, returns)\n    Function(Box<Self>, Vec<Option<Self>>, Vec<Option<Self>>),\n\n    /// (lhs, rhs)\n    Access(Box<Self>, String),\n\n    /// (types)\n    Custom(Vec<String>),\n}\n\nimpl Type {\n    /// Convert a [pt::Expression] to a [Type]\n    ///\n    /// ### Takes\n    ///\n    /// A reference to a [pt::Expression] to convert.\n    ///\n    /// ### Returns\n    ///\n    /// Optionally, an owned [Type]\n    fn from_expression(expr: &pt::Expression) -> Option<Self> {\n        match expr {\n            pt::Expression::Type(_, ty) => Self::from_type(ty),\n\n            pt::Expression::Variable(ident) => Some(Self::Custom(vec![ident.name.clone()])),\n\n            // array\n            pt::Expression::ArraySubscript(_, expr, num) => {\n                // if num is Some then this is either an index operation (arr[<num>])\n                // or a FixedArray statement (new uint256[<num>])\n                Self::from_expression(expr).and_then(|ty| {\n                    let boxed = Box::new(ty);\n                    let num = num.as_deref().and_then(parse_number_literal).and_then(|n| {\n                        usize::try_from(n).ok()\n                    });\n                    match expr.as_ref() {\n                        // statement\n                        pt::Expression::Type(_, _) => {\n                            if let Some(num) = num {\n                                Some(Self::FixedArray(boxed, num))\n                            } else {\n                                Some(Self::Array(boxed))\n                            }\n                        }\n                        // index\n                        pt::Expression::Variable(_) => {\n                            Some(Self::ArrayIndex(boxed, num))\n                        }\n                        _ => None\n                    }\n                })\n            }\n            pt::Expression::ArrayLiteral(_, values) => {\n                values.first().and_then(Self::from_expression).map(|ty| {\n                    Self::FixedArray(Box::new(ty), values.len())\n                })\n            }\n\n            // tuple\n            pt::Expression::List(_, params) => Some(Self::Tuple(map_parameters(params))),\n\n            // <lhs>.<rhs>\n            pt::Expression::MemberAccess(_, lhs, rhs) => {\n                Self::from_expression(lhs).map(|lhs| {\n                    Self::Access(Box::new(lhs), rhs.name.clone())\n                })\n            }\n\n            // <inner>\n            pt::Expression::Parenthesis(_, inner) |         // (<inner>)\n            pt::Expression::New(_, inner) |                 // new <inner>\n            pt::Expression::UnaryPlus(_, inner) |           // +<inner>\n            // ops\n            pt::Expression::BitwiseNot(_, inner) |          // ~<inner>\n            pt::Expression::ArraySlice(_, inner, _, _) |    // <inner>[*start*:*end*]\n            // assign ops\n            pt::Expression::PreDecrement(_, inner) |        // --<inner>\n            pt::Expression::PostDecrement(_, inner) |       // <inner>--\n            pt::Expression::PreIncrement(_, inner) |        // ++<inner>\n            pt::Expression::PostIncrement(_, inner) |       // <inner>++\n            pt::Expression::Assign(_, inner, _) |           // <inner>   = ...\n            pt::Expression::AssignAdd(_, inner, _) |        // <inner>  += ...\n            pt::Expression::AssignSubtract(_, inner, _) |   // <inner>  -= ...\n            pt::Expression::AssignMultiply(_, inner, _) |   // <inner>  *= ...\n            pt::Expression::AssignDivide(_, inner, _) |     // <inner>  /= ...\n            pt::Expression::AssignModulo(_, inner, _) |     // <inner>  %= ...\n            pt::Expression::AssignAnd(_, inner, _) |        // <inner>  &= ...\n            pt::Expression::AssignOr(_, inner, _) |         // <inner>  |= ...\n            pt::Expression::AssignXor(_, inner, _) |        // <inner>  ^= ...\n            pt::Expression::AssignShiftLeft(_, inner, _) |  // <inner> <<= ...\n            pt::Expression::AssignShiftRight(_, inner, _)   // <inner> >>= ...\n            => Self::from_expression(inner),\n\n            // *condition* ? <if_true> : <if_false>\n            pt::Expression::ConditionalOperator(_, _, if_true, if_false) => {\n                Self::from_expression(if_true).or_else(|| Self::from_expression(if_false))\n            }\n\n            // address\n            pt::Expression::AddressLiteral(_, _) => Some(Self::Builtin(DynSolType::Address)),\n            pt::Expression::HexNumberLiteral(_, s, _) => {\n                match s.parse::<Address>() {\n                    Ok(addr) if *s == addr.to_checksum(None) => {\n                        Some(Self::Builtin(DynSolType::Address))\n                    }\n                    _ => Some(Self::Builtin(DynSolType::Uint(256))),\n                }\n            }\n\n            // uint and int\n            // invert\n            pt::Expression::Negate(_, inner) => Self::from_expression(inner).map(Self::invert_int),\n\n            // int if either operand is int\n            // TODO: will need an update for Solidity v0.8.18 user defined operators:\n            // https://github.com/ethereum/solidity/issues/13718#issuecomment-1341058649\n            pt::Expression::Add(_, lhs, rhs) |\n            pt::Expression::Subtract(_, lhs, rhs) |\n            pt::Expression::Multiply(_, lhs, rhs) |\n            pt::Expression::Divide(_, lhs, rhs) => {\n                match (Self::ethabi(lhs, None), Self::ethabi(rhs, None)) {\n                    (Some(DynSolType::Int(_)), Some(DynSolType::Int(_))) |\n                    (Some(DynSolType::Int(_)), Some(DynSolType::Uint(_))) |\n                    (Some(DynSolType::Uint(_)), Some(DynSolType::Int(_))) => {\n                        Some(Self::Builtin(DynSolType::Int(256)))\n                    }\n                    _ => {\n                        Some(Self::Builtin(DynSolType::Uint(256)))\n                    }\n                }\n            }\n\n            // always assume uint\n            pt::Expression::Modulo(_, _, _) |\n            pt::Expression::Power(_, _, _) |\n            pt::Expression::BitwiseOr(_, _, _) |\n            pt::Expression::BitwiseAnd(_, _, _) |\n            pt::Expression::BitwiseXor(_, _, _) |\n            pt::Expression::ShiftRight(_, _, _) |\n            pt::Expression::ShiftLeft(_, _, _) |\n            pt::Expression::NumberLiteral(_, _, _, _) => Some(Self::Builtin(DynSolType::Uint(256))),\n\n            // TODO: Rational numbers\n            pt::Expression::RationalNumberLiteral(_, _, _, _, _) => {\n                Some(Self::Builtin(DynSolType::Uint(256)))\n            }\n\n            // bool\n            pt::Expression::BoolLiteral(_, _) |\n            pt::Expression::And(_, _, _) |\n            pt::Expression::Or(_, _, _) |\n            pt::Expression::Equal(_, _, _) |\n            pt::Expression::NotEqual(_, _, _) |\n            pt::Expression::Less(_, _, _) |\n            pt::Expression::LessEqual(_, _, _) |\n            pt::Expression::More(_, _, _) |\n            pt::Expression::MoreEqual(_, _, _) |\n            pt::Expression::Not(_, _) => Some(Self::Builtin(DynSolType::Bool)),\n\n            // string\n            pt::Expression::StringLiteral(_) => Some(Self::Builtin(DynSolType::String)),\n\n            // bytes\n            pt::Expression::HexLiteral(_) => Some(Self::Builtin(DynSolType::Bytes)),\n\n            // function\n            pt::Expression::FunctionCall(_, name, args) => {\n                Self::from_expression(name).map(|name| {\n                    let args = args.iter().map(Self::from_expression).collect();\n                    Self::Function(Box::new(name), args, vec![])\n                })\n            }\n            pt::Expression::NamedFunctionCall(_, name, args) => {\n                Self::from_expression(name).map(|name| {\n                    let args = args.iter().map(|arg| Self::from_expression(&arg.expr)).collect();\n                    Self::Function(Box::new(name), args, vec![])\n                })\n            }\n\n            // explicitly None\n            pt::Expression::Delete(_, _) | pt::Expression::FunctionCallBlock(_, _, _) => None,\n        }\n    }\n\n    /// Convert a [pt::Type] to a [Type]\n    ///\n    /// ### Takes\n    ///\n    /// A reference to a [pt::Type] to convert.\n    ///\n    /// ### Returns\n    ///\n    /// Optionally, an owned [Type]\n    fn from_type(ty: &pt::Type) -> Option<Self> {\n        let ty = match ty {\n            pt::Type::Address | pt::Type::AddressPayable | pt::Type::Payable => {\n                Self::Builtin(DynSolType::Address)\n            }\n            pt::Type::Bool => Self::Builtin(DynSolType::Bool),\n            pt::Type::String => Self::Builtin(DynSolType::String),\n            pt::Type::Int(size) => Self::Builtin(DynSolType::Int(*size as usize)),\n            pt::Type::Uint(size) => Self::Builtin(DynSolType::Uint(*size as usize)),\n            pt::Type::Bytes(size) => Self::Builtin(DynSolType::FixedBytes(*size as usize)),\n            pt::Type::DynamicBytes => Self::Builtin(DynSolType::Bytes),\n            pt::Type::Mapping { value, .. } => Self::from_expression(value)?,\n            pt::Type::Function { params, returns, .. } => {\n                let params = map_parameters(params);\n                let returns = returns\n                    .as_ref()\n                    .map(|(returns, _)| map_parameters(returns))\n                    .unwrap_or_default();\n                Self::Function(\n                    Box::new(Self::Custom(vec![\"__fn_type__\".to_string()])),\n                    params,\n                    returns,\n                )\n            }\n            // TODO: Rational numbers\n            pt::Type::Rational => return None,\n        };\n        Some(ty)\n    }\n\n    /// Handle special expressions like [global variables](https://docs.soliditylang.org/en/latest/cheatsheet.html#global-variables)\n    ///\n    /// See: <https://github.com/ethereum/solidity/blob/81268e336573721819e39fbb3fefbc9344ad176c/libsolidity/ast/Types.cpp#L4106>\n    fn map_special(self) -> Self {\n        if !matches!(self, Self::Function(_, _, _) | Self::Access(_, _) | Self::Custom(_)) {\n            return self;\n        }\n\n        let mut types = Vec::with_capacity(5);\n        let mut args = None;\n        self.recurse(&mut types, &mut args);\n\n        let len = types.len();\n        if len == 0 {\n            return self;\n        }\n\n        // Type members, like array, bytes etc\n        #[expect(clippy::single_match)]\n        #[allow(clippy::collapsible_match)]\n        match &self {\n            Self::Access(inner, access) => {\n                if let Some(ty) = inner.as_ref().clone().try_as_ethabi(None) {\n                    // Array / bytes members\n                    let ty = Self::Builtin(ty);\n                    match access.as_str() {\n                        \"length\" if ty.is_dynamic() || ty.is_array() || ty.is_fixed_bytes() => {\n                            return Self::Builtin(DynSolType::Uint(256));\n                        }\n                        \"pop\" if ty.is_dynamic_array() => return ty,\n                        _ => {}\n                    }\n                }\n            }\n            _ => {}\n        }\n\n        let this = {\n            let name = types.last().unwrap().as_str();\n            match len {\n                0 => unreachable!(),\n                1 => match name {\n                    \"gasleft\" | \"addmod\" | \"mulmod\" => Some(DynSolType::Uint(256)),\n                    \"keccak256\" | \"sha256\" | \"blockhash\" => Some(DynSolType::FixedBytes(32)),\n                    \"ripemd160\" => Some(DynSolType::FixedBytes(20)),\n                    \"ecrecover\" => Some(DynSolType::Address),\n                    _ => None,\n                },\n                2 => {\n                    let access = types.first().unwrap().as_str();\n                    match name {\n                        \"block\" => match access {\n                            \"coinbase\" => Some(DynSolType::Address),\n                            \"timestamp\" | \"difficulty\" | \"prevrandao\" | \"number\" | \"gaslimit\"\n                            | \"chainid\" | \"basefee\" | \"blobbasefee\" => Some(DynSolType::Uint(256)),\n                            _ => None,\n                        },\n                        \"msg\" => match access {\n                            \"sender\" => Some(DynSolType::Address),\n                            \"gas\" => Some(DynSolType::Uint(256)),\n                            \"value\" => Some(DynSolType::Uint(256)),\n                            \"data\" => Some(DynSolType::Bytes),\n                            \"sig\" => Some(DynSolType::FixedBytes(4)),\n                            _ => None,\n                        },\n                        \"tx\" => match access {\n                            \"origin\" => Some(DynSolType::Address),\n                            \"gasprice\" => Some(DynSolType::Uint(256)),\n                            _ => None,\n                        },\n                        \"abi\" => match access {\n                            \"decode\" => {\n                                // args = Some([Bytes(_), Tuple(args)])\n                                // unwrapping is safe because this is first compiled by solc so\n                                // it is guaranteed to be a valid call\n                                let mut args = args.unwrap();\n                                let last = args.pop().unwrap();\n                                match last {\n                                    Some(ty) => {\n                                        return match ty {\n                                            Self::Tuple(_) => ty,\n                                            ty => Self::Tuple(vec![Some(ty)]),\n                                        };\n                                    }\n                                    None => None,\n                                }\n                            }\n                            s if s.starts_with(\"encode\") => Some(DynSolType::Bytes),\n                            _ => None,\n                        },\n                        \"address\" => match access {\n                            \"balance\" => Some(DynSolType::Uint(256)),\n                            \"code\" => Some(DynSolType::Bytes),\n                            \"codehash\" => Some(DynSolType::FixedBytes(32)),\n                            \"send\" => Some(DynSolType::Bool),\n                            _ => None,\n                        },\n                        \"type\" => match access {\n                            \"name\" => Some(DynSolType::String),\n                            \"creationCode\" | \"runtimeCode\" => Some(DynSolType::Bytes),\n                            \"interfaceId\" => Some(DynSolType::FixedBytes(4)),\n                            \"min\" | \"max\" => Some(\n                                // Either a builtin or an enum\n                                (|| args?.pop()??.into_builtin())()\n                                    .unwrap_or(DynSolType::Uint(256)),\n                            ),\n                            _ => None,\n                        },\n                        \"string\" => match access {\n                            \"concat\" => Some(DynSolType::String),\n                            _ => None,\n                        },\n                        \"bytes\" => match access {\n                            \"concat\" => Some(DynSolType::Bytes),\n                            _ => None,\n                        },\n                        _ => None,\n                    }\n                }\n                _ => None,\n            }\n        };\n\n        this.map(Self::Builtin).unwrap_or_else(|| match types.last().unwrap().as_str() {\n            \"this\" | \"super\" => Self::Custom(types),\n            _ => match self {\n                Self::Custom(_) | Self::Access(_, _) => Self::Custom(types),\n                Self::Function(_, _, _) => self,\n                _ => unreachable!(),\n            },\n        })\n    }\n\n    /// Recurses over itself, appending all the idents and function arguments in the order that they\n    /// are found\n    fn recurse(&self, types: &mut Vec<String>, args: &mut Option<Vec<Option<Self>>>) {\n        match self {\n            Self::Builtin(ty) => types.push(ty.to_string()),\n            Self::Custom(tys) => types.extend(tys.clone()),\n            Self::Access(expr, name) => {\n                types.push(name.clone());\n                expr.recurse(types, args);\n            }\n            Self::Function(fn_name, fn_args, _fn_ret) => {\n                if args.is_none() && !fn_args.is_empty() {\n                    *args = Some(fn_args.clone());\n                }\n                fn_name.recurse(types, args);\n            }\n            _ => {}\n        }\n    }\n\n    /// Infers a custom type's true type by recursing up the parse tree\n    ///\n    /// ### Takes\n    /// - A reference to the [IntermediateOutput]\n    /// - An array of custom types generated by the `MemberAccess` arm of [Self::from_expression]\n    /// - An optional contract name. This should always be `None` when this function is first\n    ///   called.\n    ///\n    /// ### Returns\n    ///\n    /// If successful, an `Ok(Some(DynSolType))` variant.\n    /// If gracefully failed, an `Ok(None)` variant.\n    /// If failed, an `Err(e)` variant.\n    fn infer_custom_type(\n        intermediate: &IntermediateOutput,\n        custom_type: &mut Vec<String>,\n        contract_name: Option<String>,\n    ) -> Result<Option<DynSolType>> {\n        if let Some(\"this\") | Some(\"super\") = custom_type.last().map(String::as_str) {\n            custom_type.pop();\n        }\n        if custom_type.is_empty() {\n            return Ok(None);\n        }\n\n        // If a contract exists with the given name, check its definitions for a match.\n        // Otherwise look in the `run`\n        if let Some(contract_name) = contract_name {\n            let intermediate_contract = intermediate\n                .intermediate_contracts\n                .get(&contract_name)\n                .ok_or_else(|| eyre::eyre!(\"Could not find intermediate contract!\"))?;\n\n            let cur_type = custom_type.last().unwrap();\n            if let Some(func) = intermediate_contract.function_definitions.get(cur_type) {\n                // Check if the custom type is a function pointer member access\n                if let res @ Some(_) = func_members(func, custom_type) {\n                    return Ok(res);\n                }\n\n                // Because tuple types cannot be passed to `abi.encode`, we will only be\n                // receiving functions that have 0 or 1 return parameters here.\n                if func.returns.is_empty() {\n                    eyre::bail!(\n                        \"This call expression does not return any values to inspect. Insert as statement.\"\n                    )\n                }\n\n                // Empty return types check is done above\n                let (_, param) = func.returns.first().unwrap();\n                // Return type should always be present\n                let return_ty = &param.as_ref().unwrap().ty;\n\n                // If the return type is a variable (not a type expression), re-enter the recursion\n                // on the same contract for a variable / struct search. It could be a contract,\n                // struct, array, etc.\n                if let pt::Expression::Variable(ident) = return_ty {\n                    custom_type.push(ident.name.clone());\n                    return Self::infer_custom_type(intermediate, custom_type, Some(contract_name));\n                }\n\n                // Check if our final function call alters the state. If it does, we bail so that it\n                // will be inserted normally without inspecting. If the state mutability was not\n                // expressly set, the function is inferred to alter state.\n                if let Some(pt::FunctionAttribute::Mutability(_mut)) = func\n                    .attributes\n                    .iter()\n                    .find(|attr| matches!(attr, pt::FunctionAttribute::Mutability(_)))\n                {\n                    if let pt::Mutability::Payable(_) = _mut {\n                        eyre::bail!(\"This function mutates state. Insert as a statement.\")\n                    }\n                } else {\n                    eyre::bail!(\"This function mutates state. Insert as a statement.\")\n                }\n\n                Ok(Self::ethabi(return_ty, Some(intermediate)))\n            } else if let Some(var) = intermediate_contract.variable_definitions.get(cur_type) {\n                Self::infer_var_expr(&var.ty, Some(intermediate), custom_type)\n            } else if let Some(strukt) = intermediate_contract.struct_definitions.get(cur_type) {\n                let inner_types = strukt\n                    .fields\n                    .iter()\n                    .map(|var| {\n                        Self::ethabi(&var.ty, Some(intermediate))\n                            .ok_or_else(|| eyre::eyre!(\"Struct `{cur_type}` has invalid fields\"))\n                    })\n                    .collect::<Result<Vec<_>>>()?;\n                Ok(Some(DynSolType::Tuple(inner_types)))\n            } else {\n                eyre::bail!(\n                    \"Could not find any definition in contract \\\"{contract_name}\\\" for type: {custom_type:?}\"\n                )\n            }\n        } else {\n            // Check if the custom type is a variable or function within the REPL contract before\n            // anything. If it is, we can stop here.\n            if let Ok(res) = Self::infer_custom_type(intermediate, custom_type, Some(\"REPL\".into()))\n            {\n                return Ok(res);\n            }\n\n            // Check if the first element of the custom type is a known contract. If it is, begin\n            // our recursion on that contract's definitions.\n            let name = custom_type.last().unwrap();\n            let contract = intermediate.intermediate_contracts.get(name);\n            if contract.is_some() {\n                let contract_name = custom_type.pop();\n                return Self::infer_custom_type(intermediate, custom_type, contract_name);\n            }\n\n            // See [`Type::infer_var_expr`]\n            let name = custom_type.last().unwrap();\n            if let Some(expr) = intermediate.repl_contract_expressions.get(name) {\n                return Self::infer_var_expr(expr, Some(intermediate), custom_type);\n            }\n\n            // The first element of our custom type was neither a variable or a function within the\n            // REPL contract, move on to globally available types gracefully.\n            Ok(None)\n        }\n    }\n\n    /// Infers the type from a variable's type\n    fn infer_var_expr(\n        expr: &pt::Expression,\n        intermediate: Option<&IntermediateOutput>,\n        custom_type: &mut Vec<String>,\n    ) -> Result<Option<DynSolType>> {\n        // Resolve local (in `run` function) or global (in the `REPL` or other contract) variable\n        let res = match &expr {\n            // Custom variable handling\n            pt::Expression::Variable(ident) => {\n                let name = &ident.name;\n\n                if let Some(intermediate) = intermediate {\n                    // expression in `run`\n                    if let Some(expr) = intermediate.repl_contract_expressions.get(name) {\n                        Self::infer_var_expr(expr, Some(intermediate), custom_type)\n                    } else if intermediate.intermediate_contracts.contains_key(name) {\n                        if custom_type.len() > 1 {\n                            // There is still some recursing left to do: jump into the contract.\n                            custom_type.pop();\n                            Self::infer_custom_type(intermediate, custom_type, Some(name.clone()))\n                        } else {\n                            // We have no types left to recurse: return the address of the contract.\n                            Ok(Some(DynSolType::Address))\n                        }\n                    } else {\n                        Err(eyre::eyre!(\"Could not infer variable type\"))\n                    }\n                } else {\n                    Ok(None)\n                }\n            }\n            ty => Ok(Self::ethabi(ty, intermediate)),\n        };\n        // re-run everything with the resolved variable in case we're accessing a builtin member\n        // for example array or bytes length etc\n        match res {\n            Ok(Some(ty)) => {\n                let box_ty = Box::new(Self::Builtin(ty.clone()));\n                let access = Self::Access(box_ty, custom_type.drain(..).next().unwrap_or_default());\n                if let Some(mapped) = access.map_special().try_as_ethabi(intermediate) {\n                    Ok(Some(mapped))\n                } else {\n                    Ok(Some(ty))\n                }\n            }\n            res => res,\n        }\n    }\n\n    /// Attempt to convert this type into a [DynSolType]\n    ///\n    /// ### Takes\n    /// An immutable reference to an [IntermediateOutput]\n    ///\n    /// ### Returns\n    /// Optionally, a [DynSolType]\n    fn try_as_ethabi(self, intermediate: Option<&IntermediateOutput>) -> Option<DynSolType> {\n        match self {\n            Self::Builtin(ty) => Some(ty),\n            Self::Tuple(types) => Some(DynSolType::Tuple(types_to_parameters(types, intermediate))),\n            Self::Array(inner) => match *inner {\n                ty @ Self::Custom(_) => ty.try_as_ethabi(intermediate),\n                _ => inner\n                    .try_as_ethabi(intermediate)\n                    .map(|inner| DynSolType::Array(Box::new(inner))),\n            },\n            Self::FixedArray(inner, size) => match *inner {\n                ty @ Self::Custom(_) => ty.try_as_ethabi(intermediate),\n                _ => inner\n                    .try_as_ethabi(intermediate)\n                    .map(|inner| DynSolType::FixedArray(Box::new(inner), size)),\n            },\n            ty @ Self::ArrayIndex(_, _) => ty.into_array_index(intermediate),\n            Self::Function(ty, _, _) => ty.try_as_ethabi(intermediate),\n            // should have been mapped to `Custom` in previous steps\n            Self::Access(_, _) => None,\n            Self::Custom(mut types) => {\n                // Cover any local non-state-modifying function call expressions\n                intermediate.and_then(|intermediate| {\n                    Self::infer_custom_type(intermediate, &mut types, None).ok().flatten()\n                })\n            }\n        }\n    }\n\n    /// Equivalent to `Type::from_expression` + `Type::map_special` + `Type::try_as_ethabi`\n    fn ethabi(\n        expr: &pt::Expression,\n        intermediate: Option<&IntermediateOutput>,\n    ) -> Option<DynSolType> {\n        Self::from_expression(expr)\n            .map(Self::map_special)\n            .and_then(|ty| ty.try_as_ethabi(intermediate))\n    }\n\n    /// Get the return type of a function call expression.\n    fn get_function_return_type<'a>(\n        contract_expr: Option<&'a pt::Expression>,\n        intermediate: &IntermediateOutput,\n    ) -> Option<(&'a pt::Expression, DynSolType)> {\n        let function_call = match contract_expr? {\n            pt::Expression::FunctionCall(_, function_call, _) => function_call,\n            _ => return None,\n        };\n        let (contract_name, function_name) = match function_call.as_ref() {\n            pt::Expression::MemberAccess(_, contract_name, function_name) => {\n                (contract_name, function_name)\n            }\n            _ => return None,\n        };\n        let contract_name = match contract_name.as_ref() {\n            pt::Expression::Variable(contract_name) => contract_name.to_owned(),\n            _ => return None,\n        };\n\n        let pt::Expression::Variable(contract_name) =\n            intermediate.repl_contract_expressions.get(&contract_name.name)?\n        else {\n            return None;\n        };\n\n        let contract = intermediate\n            .intermediate_contracts\n            .get(&contract_name.name)?\n            .function_definitions\n            .get(&function_name.name)?;\n        let return_parameter = contract.as_ref().returns.first()?.to_owned().1?;\n        Self::ethabi(&return_parameter.ty, Some(intermediate)).map(|p| (contract_expr.unwrap(), p))\n    }\n\n    /// Inverts Int to Uint and vice-versa.\n    fn invert_int(self) -> Self {\n        match self {\n            Self::Builtin(DynSolType::Uint(n)) => Self::Builtin(DynSolType::Int(n)),\n            Self::Builtin(DynSolType::Int(n)) => Self::Builtin(DynSolType::Uint(n)),\n            x => x,\n        }\n    }\n\n    /// Returns the `DynSolType` contained by `Type::Builtin`\n    #[inline]\n    fn into_builtin(self) -> Option<DynSolType> {\n        match self {\n            Self::Builtin(ty) => Some(ty),\n            _ => None,\n        }\n    }\n\n    /// Returns the resulting `DynSolType` of indexing self\n    fn into_array_index(self, intermediate: Option<&IntermediateOutput>) -> Option<DynSolType> {\n        match self {\n            Self::Array(inner) | Self::FixedArray(inner, _) | Self::ArrayIndex(inner, _) => {\n                match inner.try_as_ethabi(intermediate) {\n                    Some(DynSolType::Array(inner)) | Some(DynSolType::FixedArray(inner, _)) => {\n                        Some(*inner)\n                    }\n                    Some(DynSolType::Bytes)\n                    | Some(DynSolType::String)\n                    | Some(DynSolType::FixedBytes(_)) => Some(DynSolType::FixedBytes(1)),\n                    ty => ty,\n                }\n            }\n            _ => None,\n        }\n    }\n\n    /// Returns whether this type is dynamic\n    #[inline]\n    fn is_dynamic(&self) -> bool {\n        match self {\n            // TODO: Note, this is not entirely correct. Fixed arrays of non-dynamic types are\n            // not dynamic, nor are tuples of non-dynamic types.\n            Self::Builtin(DynSolType::Bytes | DynSolType::String | DynSolType::Array(_)) => true,\n            Self::Array(_) => true,\n            _ => false,\n        }\n    }\n\n    /// Returns whether this type is an array\n    #[inline]\n    fn is_array(&self) -> bool {\n        matches!(\n            self,\n            Self::Array(_)\n                | Self::FixedArray(_, _)\n                | Self::Builtin(DynSolType::Array(_))\n                | Self::Builtin(DynSolType::FixedArray(_, _))\n        )\n    }\n\n    /// Returns whether this type is a dynamic array (can call push, pop)\n    #[inline]\n    fn is_dynamic_array(&self) -> bool {\n        matches!(self, Self::Array(_) | Self::Builtin(DynSolType::Array(_)))\n    }\n\n    fn is_fixed_bytes(&self) -> bool {\n        matches!(self, Self::Builtin(DynSolType::FixedBytes(_)))\n    }\n}\n\n/// Returns Some if the custom type is a function member access\n///\n/// Ref: <https://docs.soliditylang.org/en/latest/types.html#function-types>\n#[inline]\nfn func_members(func: &pt::FunctionDefinition, custom_type: &[String]) -> Option<DynSolType> {\n    if !matches!(func.ty, pt::FunctionTy::Function) {\n        return None;\n    }\n\n    let vis = func.attributes.iter().find_map(|attr| match attr {\n        pt::FunctionAttribute::Visibility(vis) => Some(vis),\n        _ => None,\n    });\n    match vis {\n        Some(pt::Visibility::External(_)) | Some(pt::Visibility::Public(_)) => {\n            match custom_type.first().unwrap().as_str() {\n                \"address\" => Some(DynSolType::Address),\n                \"selector\" => Some(DynSolType::FixedBytes(4)),\n                _ => None,\n            }\n        }\n        _ => None,\n    }\n}\n\n/// Whether execution should continue after inspecting this expression\n#[inline]\nfn should_continue(expr: &pt::Expression) -> bool {\n    match expr {\n        // assignments\n        pt::Expression::PreDecrement(_, _) |       // --<inner>\n        pt::Expression::PostDecrement(_, _) |      // <inner>--\n        pt::Expression::PreIncrement(_, _) |       // ++<inner>\n        pt::Expression::PostIncrement(_, _) |      // <inner>++\n        pt::Expression::Assign(_, _, _) |          // <inner>   = ...\n        pt::Expression::AssignAdd(_, _, _) |       // <inner>  += ...\n        pt::Expression::AssignSubtract(_, _, _) |  // <inner>  -= ...\n        pt::Expression::AssignMultiply(_, _, _) |  // <inner>  *= ...\n        pt::Expression::AssignDivide(_, _, _) |    // <inner>  /= ...\n        pt::Expression::AssignModulo(_, _, _) |    // <inner>  %= ...\n        pt::Expression::AssignAnd(_, _, _) |       // <inner>  &= ...\n        pt::Expression::AssignOr(_, _, _) |        // <inner>  |= ...\n        pt::Expression::AssignXor(_, _, _) |       // <inner>  ^= ...\n        pt::Expression::AssignShiftLeft(_, _, _) | // <inner> <<= ...\n        pt::Expression::AssignShiftRight(_, _, _)  // <inner> >>= ...\n        => {\n            true\n        }\n\n        // Array.pop()\n        pt::Expression::FunctionCall(_, lhs, _) => {\n            match lhs.as_ref() {\n                pt::Expression::MemberAccess(_, _inner, access) => access.name == \"pop\",\n                _ => false\n            }\n        }\n\n        _ => false\n    }\n}\n\nfn map_parameters(params: &[(pt::Loc, Option<pt::Parameter>)]) -> Vec<Option<Type>> {\n    params\n        .iter()\n        .map(|(_, param)| param.as_ref().and_then(|param| Type::from_expression(&param.ty)))\n        .collect()\n}\n\nfn types_to_parameters(\n    types: Vec<Option<Type>>,\n    intermediate: Option<&IntermediateOutput>,\n) -> Vec<DynSolType> {\n    types.into_iter().filter_map(|ty| ty.and_then(|ty| ty.try_as_ethabi(intermediate))).collect()\n}\n\nfn parse_number_literal(expr: &pt::Expression) -> Option<U256> {\n    match expr {\n        pt::Expression::NumberLiteral(_, num, exp, unit) => {\n            let num = num.parse::<U256>().unwrap_or(U256::ZERO);\n            let exp = exp.parse().unwrap_or(0u32);\n            if exp > 77 {\n                None\n            } else {\n                let exp = U256::from(10usize.pow(exp));\n                let unit_mul = unit_multiplier(unit).ok()?;\n                Some(num * exp * unit_mul)\n            }\n        }\n        pt::Expression::HexNumberLiteral(_, num, unit) => {\n            let unit_mul = unit_multiplier(unit).ok()?;\n            num.parse::<U256>().map(|num| num * unit_mul).ok()\n        }\n        // TODO: Rational numbers\n        pt::Expression::RationalNumberLiteral(..) => None,\n        _ => None,\n    }\n}\n\n#[inline]\nfn unit_multiplier(unit: &Option<pt::Identifier>) -> Result<U256> {\n    if let Some(unit) = unit {\n        let mul = match unit.name.as_str() {\n            \"seconds\" => 1,\n            \"minutes\" => 60,\n            \"hours\" => 60 * 60,\n            \"days\" => 60 * 60 * 24,\n            \"weeks\" => 60 * 60 * 24 * 7,\n            \"wei\" => 1,\n            \"gwei\" => 10_usize.pow(9),\n            \"ether\" => 10_usize.pow(18),\n            other => eyre::bail!(\"unknown unit: {other}\"),\n        };\n        Ok(U256::from(mul))\n    } else {\n        Ok(U256::from(1))\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use foundry_compilers::{error::SolcError, solc::Solc};\n    use std::sync::Mutex;\n\n    #[test]\n    fn test_expressions() {\n        static EXPRESSIONS: &[(&str, DynSolType)] = {\n            use DynSolType::*;\n            &[\n                // units\n                // uint\n                (\"1 seconds\", Uint(256)),\n                (\"1 minutes\", Uint(256)),\n                (\"1 hours\", Uint(256)),\n                (\"1 days\", Uint(256)),\n                (\"1 weeks\", Uint(256)),\n                (\"1 wei\", Uint(256)),\n                (\"1 gwei\", Uint(256)),\n                (\"1 ether\", Uint(256)),\n                // int\n                (\"-1 seconds\", Int(256)),\n                (\"-1 minutes\", Int(256)),\n                (\"-1 hours\", Int(256)),\n                (\"-1 days\", Int(256)),\n                (\"-1 weeks\", Int(256)),\n                (\"-1 wei\", Int(256)),\n                (\"-1 gwei\", Int(256)),\n                (\"-1 ether\", Int(256)),\n                //\n                (\"true ? 1 : 0\", Uint(256)),\n                (\"true ? -1 : 0\", Int(256)),\n                // misc\n                //\n\n                // ops\n                // uint\n                (\"1 + 1\", Uint(256)),\n                (\"1 - 1\", Uint(256)),\n                (\"1 * 1\", Uint(256)),\n                (\"1 / 1\", Uint(256)),\n                (\"1 % 1\", Uint(256)),\n                (\"1 ** 1\", Uint(256)),\n                (\"1 | 1\", Uint(256)),\n                (\"1 & 1\", Uint(256)),\n                (\"1 ^ 1\", Uint(256)),\n                (\"1 >> 1\", Uint(256)),\n                (\"1 << 1\", Uint(256)),\n                // int\n                (\"int(1) + 1\", Int(256)),\n                (\"int(1) - 1\", Int(256)),\n                (\"int(1) * 1\", Int(256)),\n                (\"int(1) / 1\", Int(256)),\n                (\"1 + int(1)\", Int(256)),\n                (\"1 - int(1)\", Int(256)),\n                (\"1 * int(1)\", Int(256)),\n                (\"1 / int(1)\", Int(256)),\n                //\n\n                // assign\n                (\"uint256 a; a--\", Uint(256)),\n                (\"uint256 a; --a\", Uint(256)),\n                (\"uint256 a; a++\", Uint(256)),\n                (\"uint256 a; ++a\", Uint(256)),\n                (\"uint256 a; a   = 1\", Uint(256)),\n                (\"uint256 a; a  += 1\", Uint(256)),\n                (\"uint256 a; a  -= 1\", Uint(256)),\n                (\"uint256 a; a  *= 1\", Uint(256)),\n                (\"uint256 a; a  /= 1\", Uint(256)),\n                (\"uint256 a; a  %= 1\", Uint(256)),\n                (\"uint256 a; a  &= 1\", Uint(256)),\n                (\"uint256 a; a  |= 1\", Uint(256)),\n                (\"uint256 a; a  ^= 1\", Uint(256)),\n                (\"uint256 a; a <<= 1\", Uint(256)),\n                (\"uint256 a; a >>= 1\", Uint(256)),\n                //\n\n                // bool\n                (\"true && true\", Bool),\n                (\"true || true\", Bool),\n                (\"true == true\", Bool),\n                (\"true != true\", Bool),\n                (\"true < true\", Bool),\n                (\"true <= true\", Bool),\n                (\"true > true\", Bool),\n                (\"true >= true\", Bool),\n                (\"!true\", Bool),\n                //\n            ]\n        };\n\n        let source = &mut source();\n\n        let array_expressions: &[(&str, DynSolType)] = &[\n            (\"[1, 2, 3]\", fixed_array(DynSolType::Uint(256), 3)),\n            (\"[uint8(1), 2, 3]\", fixed_array(DynSolType::Uint(8), 3)),\n            (\"[int8(1), 2, 3]\", fixed_array(DynSolType::Int(8), 3)),\n            (\"new uint256[](3)\", array(DynSolType::Uint(256))),\n            (\"uint256[] memory a = new uint256[](3);\\na[0]\", DynSolType::Uint(256)),\n            (\"uint256[] memory a = new uint256[](3);\\na[0:3]\", array(DynSolType::Uint(256))),\n        ];\n        generic_type_test(source, array_expressions);\n        generic_type_test(source, EXPRESSIONS);\n    }\n\n    #[test]\n    fn test_types() {\n        static TYPES: &[(&str, DynSolType)] = {\n            use DynSolType::*;\n            &[\n                // bool\n                (\"bool\", Bool),\n                (\"true\", Bool),\n                (\"false\", Bool),\n                //\n\n                // int and uint\n                (\"uint\", Uint(256)),\n                (\"uint(1)\", Uint(256)),\n                (\"1\", Uint(256)),\n                (\"0x01\", Uint(256)),\n                (\"int\", Int(256)),\n                (\"int(1)\", Int(256)),\n                (\"int(-1)\", Int(256)),\n                (\"-1\", Int(256)),\n                (\"-0x01\", Int(256)),\n                //\n\n                // address\n                (\"address\", Address),\n                (\"address(0)\", Address),\n                (\"0x690B9A9E9aa1C9dB991C7721a92d351Db4FaC990\", Address),\n                (\"payable(0)\", Address),\n                (\"payable(address(0))\", Address),\n                //\n\n                // string\n                (\"string\", String),\n                (\"string(\\\"hello world\\\")\", String),\n                (\"\\\"hello world\\\"\", String),\n                (\"unicode\\\"hello world 😀\\\"\", String),\n                //\n\n                // bytes\n                (\"bytes\", Bytes),\n                (\"bytes(\\\"hello world\\\")\", Bytes),\n                (\"bytes(unicode\\\"hello world 😀\\\")\", Bytes),\n                (\"hex\\\"68656c6c6f20776f726c64\\\"\", Bytes),\n                //\n            ]\n        };\n\n        let mut types: Vec<(String, DynSolType)> = Vec::with_capacity(96 + 32 + 100);\n        for (n, b) in (8..=256).step_by(8).zip(1..=32) {\n            types.push((format!(\"uint{n}(0)\"), DynSolType::Uint(n)));\n            types.push((format!(\"int{n}(0)\"), DynSolType::Int(n)));\n            types.push((format!(\"bytes{b}(0x00)\"), DynSolType::FixedBytes(b)));\n        }\n\n        for n in 0..=32 {\n            types.push((\n                format!(\"uint256[{n}]\"),\n                DynSolType::FixedArray(Box::new(DynSolType::Uint(256)), n),\n            ));\n        }\n\n        generic_type_test(&mut source(), TYPES);\n        generic_type_test(&mut source(), &types);\n    }\n\n    #[test]\n    fn test_global_vars() {\n        init_tracing();\n\n        // https://docs.soliditylang.org/en/latest/cheatsheet.html#global-variables\n        let global_variables = {\n            use DynSolType::*;\n            &[\n                // abi\n                (\"abi.decode(bytes, (uint8[13]))\", Tuple(vec![FixedArray(Box::new(Uint(8)), 13)])),\n                (\"abi.decode(bytes, (address, bytes))\", Tuple(vec![Address, Bytes])),\n                (\"abi.decode(bytes, (uint112, uint48))\", Tuple(vec![Uint(112), Uint(48)])),\n                (\"abi.encode(_, _)\", Bytes),\n                (\"abi.encodePacked(_, _)\", Bytes),\n                (\"abi.encodeWithSelector(bytes4, _, _)\", Bytes),\n                (\"abi.encodeCall(func(), (_, _))\", Bytes),\n                (\"abi.encodeWithSignature(string, _, _)\", Bytes),\n                //\n\n                //\n                (\"bytes.concat()\", Bytes),\n                (\"bytes.concat(_)\", Bytes),\n                (\"bytes.concat(_, _)\", Bytes),\n                (\"string.concat()\", String),\n                (\"string.concat(_)\", String),\n                (\"string.concat(_, _)\", String),\n                //\n\n                // block\n                (\"block.basefee\", Uint(256)),\n                (\"block.chainid\", Uint(256)),\n                (\"block.coinbase\", Address),\n                (\"block.difficulty\", Uint(256)),\n                (\"block.gaslimit\", Uint(256)),\n                (\"block.number\", Uint(256)),\n                (\"block.timestamp\", Uint(256)),\n                //\n\n                // tx\n                (\"gasleft()\", Uint(256)),\n                (\"msg.data\", Bytes),\n                (\"msg.sender\", Address),\n                (\"msg.sig\", FixedBytes(4)),\n                (\"msg.value\", Uint(256)),\n                (\"tx.gasprice\", Uint(256)),\n                (\"tx.origin\", Address),\n                //\n\n                // assertions\n                // assert(bool)\n                // require(bool)\n                // revert()\n                // revert(string)\n                //\n\n                //\n                (\"blockhash(uint)\", FixedBytes(32)),\n                (\"keccak256(bytes)\", FixedBytes(32)),\n                (\"sha256(bytes)\", FixedBytes(32)),\n                (\"ripemd160(bytes)\", FixedBytes(20)),\n                (\"ecrecover(bytes32, uint8, bytes32, bytes32)\", Address),\n                (\"addmod(uint, uint, uint)\", Uint(256)),\n                (\"mulmod(uint, uint, uint)\", Uint(256)),\n                //\n\n                // address\n                (\"address(_)\", Address),\n                (\"address(this)\", Address),\n                // (\"super\", Type::Custom(\"super\".to_string))\n                // (selfdestruct(address payable), None)\n                (\"address.balance\", Uint(256)),\n                (\"address.code\", Bytes),\n                (\"address.codehash\", FixedBytes(32)),\n                (\"address.send(uint256)\", Bool),\n                // (address.transfer(uint256), None)\n                //\n\n                // type\n                (\"type(C).name\", String),\n                (\"type(C).creationCode\", Bytes),\n                (\"type(C).runtimeCode\", Bytes),\n                (\"type(I).interfaceId\", FixedBytes(4)),\n                (\"type(uint256).min\", Uint(256)),\n                (\"type(int128).min\", Int(128)),\n                (\"type(int256).min\", Int(256)),\n                (\"type(uint256).max\", Uint(256)),\n                (\"type(int128).max\", Int(128)),\n                (\"type(int256).max\", Int(256)),\n                (\"type(Enum1).min\", Uint(256)),\n                (\"type(Enum1).max\", Uint(256)),\n                // function\n                (\"this.run.address\", Address),\n                (\"this.run.selector\", FixedBytes(4)),\n            ]\n        };\n\n        generic_type_test(&mut source(), global_variables);\n    }\n\n    #[track_caller]\n    fn source() -> SessionSource {\n        // synchronize solc install\n        static PRE_INSTALL_SOLC_LOCK: Mutex<bool> = Mutex::new(false);\n\n        // on some CI targets installing results in weird malformed solc files, we try installing it\n        // multiple times\n        let version = \"0.8.20\";\n        for _ in 0..3 {\n            let mut is_preinstalled = PRE_INSTALL_SOLC_LOCK.lock().unwrap();\n            if !*is_preinstalled {\n                let solc = Solc::find_or_install(&version.parse().unwrap())\n                    .map(|solc| (solc.version.clone(), solc));\n                match solc {\n                    Ok((v, solc)) => {\n                        // successfully installed\n                        let _ = sh_println!(\"found installed Solc v{v} @ {}\", solc.solc.display());\n                        break;\n                    }\n                    Err(e) => {\n                        // try reinstalling\n                        let _ = sh_err!(\"error while trying to re-install Solc v{version}: {e}\");\n                        let solc = Solc::blocking_install(&version.parse().unwrap());\n                        if solc.map_err(SolcError::from).is_ok() {\n                            *is_preinstalled = true;\n                            break;\n                        }\n                    }\n                }\n            }\n        }\n\n        SessionSource::new(Default::default()).unwrap()\n    }\n\n    fn array(ty: DynSolType) -> DynSolType {\n        DynSolType::Array(Box::new(ty))\n    }\n\n    fn fixed_array(ty: DynSolType, len: usize) -> DynSolType {\n        DynSolType::FixedArray(Box::new(ty), len)\n    }\n\n    fn parse(s: &mut SessionSource, input: &str, clear: bool) -> IntermediateOutput {\n        if clear {\n            s.clear();\n        }\n\n        *s = s.clone_with_new_line(\"enum Enum1 { A }\".into()).unwrap().0;\n\n        let input = format!(\"{};\", input.trim_end().trim_end_matches(';'));\n        let (mut _s, _) = s.clone_with_new_line(input).unwrap();\n        *s = _s.clone();\n        let s = &mut _s;\n\n        if let Err(e) = s.parse() {\n            let source = s.to_repl_source();\n            panic!(\"{e}\\n\\ncould not parse input:\\n{source}\")\n        }\n        s.generate_intermediate_output().expect(\"could not generate intermediate output\")\n    }\n\n    fn expr(stmts: &[pt::Statement]) -> pt::Expression {\n        match stmts.last().expect(\"no statements\") {\n            pt::Statement::Expression(_, e) => e.clone(),\n            s => panic!(\"Not an expression: {s:?}\"),\n        }\n    }\n\n    fn get_type(\n        s: &mut SessionSource,\n        input: &str,\n        clear: bool,\n    ) -> (Option<Type>, IntermediateOutput) {\n        let intermediate = parse(s, input, clear);\n        let run_func_body = intermediate.run_func_body().expect(\"no run func body\");\n        let expr = expr(run_func_body);\n        (Type::from_expression(&expr).map(Type::map_special), intermediate)\n    }\n\n    fn get_type_ethabi(s: &mut SessionSource, input: &str, clear: bool) -> Option<DynSolType> {\n        let (ty, intermediate) = get_type(s, input, clear);\n        ty.and_then(|ty| ty.try_as_ethabi(Some(&intermediate)))\n    }\n\n    fn generic_type_test<'a, T, I>(s: &mut SessionSource, input: I)\n    where\n        T: AsRef<str> + std::fmt::Display + 'a,\n        I: IntoIterator<Item = &'a (T, DynSolType)> + 'a,\n    {\n        for (input, expected) in input.into_iter() {\n            let input = input.as_ref();\n            let ty = get_type_ethabi(s, input, true);\n            assert_eq!(ty.as_ref(), Some(expected), \"\\n{input}\");\n        }\n    }\n\n    fn init_tracing() {\n        let _ = tracing_subscriber::FmtSubscriber::builder()\n            .with_env_filter(tracing_subscriber::EnvFilter::from_default_env())\n            .try_init();\n    }\n}\n"
  },
  {
    "path": "crates/chisel/src/lib.rs",
    "content": "//! Chisel is a fast, utilitarian, and verbose Solidity REPL.\n\n#![cfg_attr(not(test), warn(unused_crate_dependencies))]\n#![cfg_attr(docsrs, feature(doc_cfg))]\n\n#[macro_use]\nextern crate foundry_common;\n#[macro_use]\nextern crate tracing;\n\npub mod args;\n\npub mod cmd;\n\npub mod dispatcher;\n\npub mod executor;\n\npub mod opts;\n\npub mod runner;\n\npub mod session;\n\npub mod source;\n\nmod solidity_helper;\npub use solidity_helper::SolidityHelper;\n\npub mod prelude {\n    pub use crate::{cmd::*, dispatcher::*, runner::*, session::*, solidity_helper::*, source::*};\n}\n"
  },
  {
    "path": "crates/chisel/src/opts.rs",
    "content": "use clap::{Parser, Subcommand};\nuse foundry_cli::opts::{BuildOpts, EvmArgs, GlobalArgs};\nuse foundry_common::version::{LONG_VERSION, SHORT_VERSION};\nuse std::path::PathBuf;\n\nfoundry_config::impl_figment_convert!(Chisel, build, evm);\n\n/// Fast, utilitarian, and verbose Solidity REPL.\n#[derive(Debug, Parser)]\n#[command(name = \"chisel\", version = SHORT_VERSION, long_version = LONG_VERSION)]\npub struct Chisel {\n    /// Include the global arguments.\n    #[command(flatten)]\n    pub global: GlobalArgs,\n\n    #[command(subcommand)]\n    pub cmd: Option<ChiselSubcommand>,\n\n    /// Path to a directory containing Solidity files to import, or path to a single Solidity file.\n    ///\n    /// These files will be evaluated before the top-level of the\n    /// REPL, therefore functioning as a prelude\n    #[arg(long, help_heading = \"REPL options\")]\n    pub prelude: Option<PathBuf>,\n\n    /// Disable the default `Vm` import.\n    #[arg(long, help_heading = \"REPL options\", long_help = format!(\n        \"Disable the default `Vm` import.\\n\\n\\\n         The import is disabled by default if the Solc version is less than {}.\",\n        crate::source::MIN_VM_VERSION\n    ))]\n    pub no_vm: bool,\n\n    /// Enable viaIR with minimum optimization\n    ///\n    /// This can fix most of the \"stack too deep\" errors while resulting a\n    /// relatively accurate source map.\n    #[arg(long, help_heading = \"REPL options\")]\n    pub ir_minimum: bool,\n\n    #[command(flatten)]\n    pub build: BuildOpts,\n\n    #[command(flatten)]\n    pub evm: EvmArgs,\n}\n\n/// Chisel binary subcommands\n#[derive(Debug, Subcommand)]\npub enum ChiselSubcommand {\n    /// List all cached sessions.\n    List,\n\n    /// Load a cached session.\n    Load {\n        /// The ID of the session to load.\n        id: String,\n    },\n\n    /// View the source of a cached session.\n    View {\n        /// The ID of the session to load.\n        id: String,\n    },\n\n    /// Clear all cached chisel sessions from the cache directory.\n    ClearCache,\n\n    /// Simple evaluation of a command without entering the REPL.\n    Eval {\n        /// The command to be evaluated.\n        command: String,\n    },\n}\n"
  },
  {
    "path": "crates/chisel/src/runner.rs",
    "content": "//! ChiselRunner\n//!\n//! This module contains the `ChiselRunner` struct, which assists with deploying\n//! and calling the REPL contract on a in-memory REVM instance.\n\nuse alloy_primitives::{Address, Bytes, Log, U256, map::AddressHashMap};\nuse eyre::Result;\nuse foundry_evm::{\n    executors::{DeployResult, Executor, RawCallResult},\n    traces::{TraceKind, Traces},\n};\n\n/// The function selector of the REPL contract's entrypoint, the `run()` function.\nstatic RUN_SELECTOR: [u8; 4] = [0xc0, 0x40, 0x62, 0x26];\n\n/// The Chisel Runner\n///\n/// Based off of foundry's forge cli runner for scripting.\n/// See: [runner](cli::cmd::forge::script::runner.rs)\n#[derive(Debug)]\npub struct ChiselRunner {\n    /// The Executor\n    pub executor: Executor,\n    /// An initial balance\n    pub initial_balance: U256,\n    /// The sender\n    pub sender: Address,\n    /// Input calldata appended to `RUN_SELECTOR`\n    pub input: Option<Vec<u8>>,\n}\n\n/// Represents the result of a Chisel REPL run\n#[derive(Debug, Default)]\npub struct ChiselResult {\n    /// Was the run a success?\n    pub success: bool,\n    /// Transaction logs\n    pub logs: Vec<Log>,\n    /// Call traces\n    pub traces: Traces,\n    /// Amount of gas used in the transaction\n    pub gas_used: u64,\n    /// Map of addresses to their labels\n    pub labeled_addresses: AddressHashMap<String>,\n    /// Return data\n    pub returned: Bytes,\n    /// Called address\n    pub address: Address,\n    /// EVM State at the final instruction of the `run()` function\n    pub state: Option<(Vec<U256>, Vec<u8>)>,\n}\n\n/// ChiselRunner implementation\nimpl ChiselRunner {\n    /// Create a new [ChiselRunner]\n    ///\n    /// ### Takes\n    ///\n    /// An [Executor], the initial balance of the sender, and the sender's [Address].\n    ///\n    /// ### Returns\n    ///\n    /// A new [ChiselRunner]\n    pub fn new(\n        executor: Executor,\n        initial_balance: U256,\n        sender: Address,\n        input: Option<Vec<u8>>,\n    ) -> Self {\n        Self { executor, initial_balance, sender, input }\n    }\n\n    /// Run a contract as a REPL session\n    pub fn run(&mut self, bytecode: Bytes) -> Result<ChiselResult> {\n        // Set the sender's balance to [U256::MAX] for deployment of the REPL contract.\n        self.executor.set_balance(self.sender, U256::MAX)?;\n\n        // Deploy an instance of the REPL contract\n        // We don't care about deployment traces / logs here\n        let DeployResult { address, .. } = self\n            .executor\n            .deploy(self.sender, bytecode, U256::ZERO, None)\n            .map_err(|err| eyre::eyre!(\"Failed to deploy REPL contract:\\n{}\", err))?;\n\n        // Reset the sender's balance to the initial balance for calls.\n        self.executor.set_balance(self.sender, self.initial_balance)?;\n\n        // Append the input to the `RUN_SELECTOR` to form the calldata\n        let mut calldata = RUN_SELECTOR.to_vec();\n        if let Some(mut input) = self.input.clone() {\n            calldata.append(&mut input);\n        }\n\n        let res = self.executor.transact_raw(self.sender, address, calldata.into(), U256::ZERO)?;\n\n        let RawCallResult {\n            result, reverted, logs, traces, labels, chisel_state, gas_used, ..\n        } = res;\n\n        Ok(ChiselResult {\n            returned: result,\n            success: !reverted,\n            gas_used,\n            logs,\n            traces: traces.map(|traces| vec![(TraceKind::Execution, traces)]).unwrap_or_default(),\n            labeled_addresses: labels,\n            address,\n            state: chisel_state,\n        })\n    }\n}\n"
  },
  {
    "path": "crates/chisel/src/session.rs",
    "content": "//! ChiselSession\n//!\n//! This module contains the `ChiselSession` struct, which is the top-level\n//! wrapper for a serializable REPL session.\n\nuse crate::prelude::{SessionSource, SessionSourceConfig};\nuse eyre::Result;\nuse serde::{Deserialize, Serialize};\nuse std::path::Path;\nuse time::{OffsetDateTime, format_description};\n\n/// A Chisel REPL Session\n#[derive(Debug, Serialize, Deserialize)]\npub struct ChiselSession {\n    /// The `SessionSource` object that houses the REPL session.\n    pub source: SessionSource,\n    /// The current session's identifier\n    pub id: Option<String>,\n}\n\n// ChiselSession Common Associated Functions\nimpl ChiselSession {\n    /// Create a new `ChiselSession` with a specified `solc` version and configuration.\n    ///\n    /// ### Takes\n    ///\n    /// An instance of [SessionSourceConfig]\n    ///\n    /// ### Returns\n    ///\n    /// A new instance of [ChiselSession]\n    pub fn new(config: SessionSourceConfig) -> Result<Self> {\n        // Return initialized ChiselSession with set solc version\n        Ok(Self { source: SessionSource::new(config)?, id: None })\n    }\n\n    /// Render the full source code for the current session.\n    ///\n    /// ### Returns\n    ///\n    /// Returns the full, flattened source code for the current session.\n    ///\n    /// ### Notes\n    ///\n    /// This function will not panic, but will return a blank string if the\n    /// session's [SessionSource] is None.\n    pub fn contract_source(&self) -> String {\n        self.source.to_repl_source()\n    }\n\n    /// Clears the cache directory\n    ///\n    /// ### WARNING\n    ///\n    /// This will delete all sessions from the cache.\n    /// There is no method of recovering these deleted sessions.\n    pub fn clear_cache() -> Result<()> {\n        let cache_dir = Self::cache_dir()?;\n        for entry in std::fs::read_dir(cache_dir)? {\n            let entry = entry?;\n            let path = entry.path();\n            if path.is_dir() {\n                std::fs::remove_dir_all(path)?;\n            } else {\n                std::fs::remove_file(path)?;\n            }\n        }\n        Ok(())\n    }\n\n    /// Writes the ChiselSession to a file by serializing it to a JSON string\n    ///\n    /// ### Returns\n    ///\n    /// Returns the path of the new cache file\n    pub fn write(&mut self) -> Result<String> {\n        // Try to create the cache directory\n        let cache_dir = Self::cache_dir()?;\n        std::fs::create_dir_all(&cache_dir)?;\n\n        let cache_file_name = match self.id.as_ref() {\n            Some(id) => {\n                // ID is already set- use the existing cache file.\n                format!(\"{cache_dir}chisel-{id}.json\")\n            }\n            None => {\n                // Get the next session cache ID / file\n                let (id, file_name) = Self::next_cached_session()?;\n                // Set the session's ID\n                self.id = Some(id);\n                // Return the new session's cache file name\n                file_name\n            }\n        };\n\n        // Write the current ChiselSession to that file\n        let serialized_contents = serde_json::to_string_pretty(self)?;\n        std::fs::write(&cache_file_name, serialized_contents)?;\n\n        // Return the full cache file path\n        // Ex: /home/user/.foundry/cache/chisel/chisel-0.json\n        Ok(cache_file_name)\n    }\n\n    /// Get the next default session cache file name\n    ///\n    /// ### Returns\n    ///\n    /// Optionally, returns a tuple containing the next cached session's id and file name.\n    pub fn next_cached_session() -> Result<(String, String)> {\n        let cache_dir = Self::cache_dir()?;\n        let mut entries = std::fs::read_dir(&cache_dir)?;\n\n        // If there are no existing cached sessions, just create the first one: \"chisel-0.json\"\n        let mut latest = if let Some(e) = entries.next() {\n            e?\n        } else {\n            return Ok((String::from(\"0\"), format!(\"{cache_dir}chisel-0.json\")));\n        };\n\n        let mut session_num = 1;\n        // Get the latest cached session\n        for entry in entries {\n            let entry = entry?;\n            if entry.metadata()?.modified()? >= latest.metadata()?.modified()? {\n                latest = entry;\n            }\n\n            // Increase session_num counter rather than cloning the iterator and using `.count`\n            session_num += 1;\n        }\n\n        Ok((format!(\"{session_num}\"), format!(\"{cache_dir}chisel-{session_num}.json\")))\n    }\n\n    /// The Chisel Cache Directory\n    ///\n    /// ### Returns\n    ///\n    /// Optionally, the directory of the chisel cache.\n    pub fn cache_dir() -> Result<String> {\n        let home_dir =\n            dirs::home_dir().ok_or_else(|| eyre::eyre!(\"Failed to grab home directory\"))?;\n        let home_dir_str = home_dir\n            .to_str()\n            .ok_or_else(|| eyre::eyre!(\"Failed to convert home directory to string\"))?;\n        Ok(format!(\"{home_dir_str}/.foundry/cache/chisel/\"))\n    }\n\n    /// Create the cache directory if it does not exist\n    ///\n    /// ### Returns\n    ///\n    /// The unit type if the operation was successful.\n    pub fn create_cache_dir() -> Result<()> {\n        let cache_dir = Self::cache_dir()?;\n        if !Path::new(&cache_dir).exists() {\n            std::fs::create_dir_all(&cache_dir)?;\n        }\n        Ok(())\n    }\n\n    /// Returns a list of all available cached sessions.\n    pub fn get_sessions() -> Result<Vec<(String, String)>> {\n        // Read the cache directory entries\n        let cache_dir = Self::cache_dir()?;\n        let entries = std::fs::read_dir(cache_dir)?;\n\n        // For each entry, get the file name and modified time\n        let mut sessions = Vec::new();\n        for entry in entries {\n            let entry = entry?;\n            let modified_time = entry.metadata()?.modified()?;\n            let file_name = entry.file_name();\n            let file_name = file_name\n                .into_string()\n                .map_err(|e| eyre::eyre!(format!(\"{}\", e.to_string_lossy())))?;\n            sessions.push((\n                systemtime_strftime(modified_time, \"[year]-[month]-[day] [hour]:[minute]:[second]\")\n                    .unwrap(),\n                file_name,\n            ));\n        }\n        Ok(sessions)\n    }\n\n    /// Loads a specific ChiselSession from the specified cache file\n    ///\n    /// ### Takes\n    ///\n    /// The ID of the chisel session that you wish to load.\n    ///\n    /// ### Returns\n    ///\n    /// Optionally, an owned instance of the loaded chisel session.\n    pub fn load(id: &str) -> Result<Self> {\n        let cache_dir = Self::cache_dir()?;\n        let contents = std::fs::read_to_string(Path::new(&format!(\"{cache_dir}chisel-{id}.json\")))?;\n        let chisel_env: Self = serde_json::from_str(&contents)?;\n        Ok(chisel_env)\n    }\n\n    /// Gets the most recent chisel session from the cache dir\n    ///\n    /// ### Returns\n    ///\n    /// Optionally, the file name of the most recently modified cached session.\n    pub fn latest_cached_session() -> Result<String> {\n        let cache_dir = Self::cache_dir()?;\n        let mut entries = std::fs::read_dir(cache_dir)?;\n        let mut latest = entries.next().ok_or_else(|| eyre::eyre!(\"No entries found!\"))??;\n        for entry in entries {\n            let entry = entry?;\n            if entry.metadata()?.modified()? > latest.metadata()?.modified()? {\n                latest = entry;\n            }\n        }\n        Ok(latest\n            .path()\n            .to_str()\n            .ok_or_else(|| eyre::eyre!(\"Failed to get session path!\"))?\n            .to_string())\n    }\n\n    /// Loads the latest ChiselSession from the cache file\n    ///\n    /// ### Returns\n    ///\n    /// Optionally, an owned instance of the most recently modified cached session.\n    pub fn latest() -> Result<Self> {\n        let last_session = Self::latest_cached_session()?;\n        let last_session_contents = std::fs::read_to_string(Path::new(&last_session))?;\n        let chisel_env: Self = serde_json::from_str(&last_session_contents)?;\n        Ok(chisel_env)\n    }\n}\n\n/// Generic helper function that attempts to convert a type that has\n/// an [`Into<OffsetDateTime>`] implementation into a formatted date string.\nfn systemtime_strftime<T>(dt: T, format: &str) -> Result<String>\nwhere\n    T: Into<OffsetDateTime>,\n{\n    Ok(dt.into().format(&format_description::parse(format)?)?)\n}\n"
  },
  {
    "path": "crates/chisel/src/solidity_helper.rs",
    "content": "//! This module contains the `SolidityHelper`, a [rustyline::Helper] implementation for\n//! usage in Chisel. It was originally ported from [soli](https://github.com/jpopesculian/soli/blob/master/src/main.rs).\n\nuse crate::{\n    dispatcher::PROMPT_ARROW,\n    prelude::{COMMAND_LEADER, ChiselCommand, PROMPT_ARROW_STR},\n};\nuse rustyline::{\n    Helper,\n    completion::Completer,\n    highlight::{CmdKind, Highlighter},\n    hint::Hinter,\n    validate::{ValidationContext, ValidationResult, Validator},\n};\nuse solar::parse::{\n    Cursor, Lexer,\n    interface::Session,\n    lexer::token::{RawLiteralKind, RawTokenKind},\n    token::Token,\n};\nuse std::{borrow::Cow, cell::RefCell, fmt, ops::Range, rc::Rc};\nuse yansi::{Color, Style};\n\n/// The maximum length of an ANSI prefix + suffix characters using [SolidityHelper].\n///\n/// * 5 - prefix:\n///   * 2 - start: `\\x1B[`\n///   * 2 - fg: `3<fg_code>`\n///   * 1 - end: `m`\n/// * 4 - suffix: `\\x1B[0m`\nconst MAX_ANSI_LEN: usize = 9;\n\n/// A rustyline helper for Solidity code.\n#[derive(Clone)]\npub struct SolidityHelper {\n    inner: Rc<RefCell<Inner>>,\n}\n\nstruct Inner {\n    errored: bool,\n\n    do_paint: bool,\n    sess: Session,\n}\n\nimpl Default for SolidityHelper {\n    fn default() -> Self {\n        Self::new()\n    }\n}\n\nimpl fmt::Debug for SolidityHelper {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        let this = self.inner.borrow();\n        f.debug_struct(\"SolidityHelper\")\n            .field(\"errored\", &this.errored)\n            .field(\"do_paint\", &this.do_paint)\n            .finish_non_exhaustive()\n    }\n}\n\nimpl SolidityHelper {\n    /// Create a new SolidityHelper.\n    pub fn new() -> Self {\n        Self {\n            inner: Rc::new(RefCell::new(Inner {\n                errored: false,\n                do_paint: yansi::is_enabled(),\n                sess: Session::builder().with_silent_emitter(None).build(),\n            })),\n        }\n    }\n\n    /// Returns whether the helper is in an errored state.\n    pub fn errored(&self) -> bool {\n        self.inner.borrow().errored\n    }\n\n    /// Set the errored field.\n    pub fn set_errored(&mut self, errored: bool) -> &mut Self {\n        self.inner.borrow_mut().errored = errored;\n        self\n    }\n\n    /// Highlights a Solidity source string.\n    pub fn highlight<'a>(&self, input: &'a str) -> Cow<'a, str> {\n        if !self.do_paint() {\n            return Cow::Borrowed(input);\n        }\n\n        // Highlight commands separately\n        if let Some(full_cmd) = input.strip_prefix(COMMAND_LEADER) {\n            let (cmd, rest) = match input.split_once(' ') {\n                Some((cmd, rest)) => (cmd, Some(rest)),\n                None => (input, None),\n            };\n            let cmd = cmd.strip_prefix(COMMAND_LEADER).unwrap_or(cmd);\n\n            let mut out = String::with_capacity(input.len() + MAX_ANSI_LEN);\n\n            // cmd\n            out.push(COMMAND_LEADER);\n            let cmd_res = ChiselCommand::parse(full_cmd);\n            let style = (if cmd_res.is_ok() { Color::Green } else { Color::Red }).foreground();\n            Self::paint_unchecked(cmd, style, &mut out);\n\n            // rest\n            match rest {\n                Some(rest) if !rest.is_empty() => {\n                    out.push(' ');\n                    out.push_str(rest);\n                }\n                _ => {}\n            }\n\n            Cow::Owned(out)\n        } else {\n            let mut out = String::with_capacity(input.len() * 2);\n            self.with_contiguous_styles(input, |style, range| {\n                Self::paint_unchecked(&input[range], style, &mut out);\n            });\n            Cow::Owned(out)\n        }\n    }\n\n    /// Returns a list of styles and the ranges they should be applied to.\n    ///\n    /// Covers the entire source string, including any whitespace.\n    fn with_contiguous_styles(&self, input: &str, mut f: impl FnMut(Style, Range<usize>)) {\n        self.enter(|sess| {\n            let len = input.len();\n            let mut index = 0;\n            for token in Lexer::new(sess, input) {\n                let range = token.span.lo().to_usize()..token.span.hi().to_usize();\n                let style = token_style(&token);\n                if index < range.start {\n                    f(Style::default(), index..range.start);\n                }\n                index = range.end;\n                f(style, range);\n            }\n            if index < len {\n                f(Style::default(), index..len);\n            }\n        });\n    }\n\n    /// Validate that a source snippet is closed (i.e., all braces and parenthesis are matched).\n    fn validate_closed(&self, input: &str) -> ValidationResult {\n        use RawLiteralKind::*;\n        use RawTokenKind::*;\n        let mut stack = vec![];\n        for token in Cursor::new(input) {\n            match token.kind {\n                OpenDelim(delim) => stack.push(delim),\n                CloseDelim(delim) => match (stack.pop(), delim) {\n                    (Some(open), close) if open == close => {}\n                    (Some(wanted), _) => {\n                        let wanted = wanted.to_open_str();\n                        return ValidationResult::Invalid(Some(format!(\n                            \"Mismatched brackets: `{wanted}` is not properly closed\"\n                        )));\n                    }\n                    (None, c) => {\n                        let c = c.to_close_str();\n                        return ValidationResult::Invalid(Some(format!(\n                            \"Mismatched brackets: `{c}` is unpaired\"\n                        )));\n                    }\n                },\n\n                Literal { kind: Str { terminated, .. } } if !terminated => {\n                    return ValidationResult::Incomplete;\n                }\n\n                BlockComment { terminated, .. } if !terminated => {\n                    return ValidationResult::Incomplete;\n                }\n\n                _ => {}\n            }\n        }\n\n        // There are open brackets that are not properly closed.\n        if !stack.is_empty() {\n            return ValidationResult::Incomplete;\n        }\n\n        ValidationResult::Valid(None)\n    }\n\n    /// Formats `input` with `style` into `out`, without checking `style.wrapping` or\n    /// `self.do_paint`.\n    fn paint_unchecked(string: &str, style: Style, out: &mut String) {\n        if style == Style::default() {\n            out.push_str(string);\n        } else {\n            let _ = style.fmt_prefix(out);\n            out.push_str(string);\n            let _ = style.fmt_suffix(out);\n        }\n    }\n\n    fn paint_unchecked_owned(string: &str, style: Style) -> String {\n        let mut out = String::with_capacity(MAX_ANSI_LEN + string.len());\n        Self::paint_unchecked(string, style, &mut out);\n        out\n    }\n\n    /// Returns whether to color the output.\n    fn do_paint(&self) -> bool {\n        self.inner.borrow().do_paint\n    }\n\n    /// Enters the session.\n    fn enter(&self, f: impl FnOnce(&Session)) {\n        let this = self.inner.borrow();\n        this.sess.enter_sequential(|| f(&this.sess));\n    }\n}\n\nimpl Highlighter for SolidityHelper {\n    fn highlight<'l>(&self, line: &'l str, _pos: usize) -> Cow<'l, str> {\n        self.highlight(line)\n    }\n\n    fn highlight_char(&self, line: &str, pos: usize, _kind: CmdKind) -> bool {\n        pos == line.len()\n    }\n\n    fn highlight_prompt<'b, 's: 'b, 'p: 'b>(\n        &'s self,\n        prompt: &'p str,\n        _default: bool,\n    ) -> Cow<'b, str> {\n        if !self.do_paint() {\n            return Cow::Borrowed(prompt);\n        }\n\n        let mut out = prompt.to_string();\n\n        // `^(\\(ID: .*?\\) )? ➜ `\n        if prompt.starts_with(\"(ID: \") {\n            let id_end = prompt.find(')').unwrap();\n            let id_span = 5..id_end;\n            let id = &prompt[id_span.clone()];\n            out.replace_range(\n                id_span,\n                &Self::paint_unchecked_owned(id, Color::Yellow.foreground()),\n            );\n            out.replace_range(1..=2, &Self::paint_unchecked_owned(\"ID\", Color::Cyan.foreground()));\n        }\n\n        if let Some(i) = out.find(PROMPT_ARROW) {\n            let style =\n                if self.errored() { Color::Red.foreground() } else { Color::Green.foreground() };\n            out.replace_range(i..=i + 2, &Self::paint_unchecked_owned(PROMPT_ARROW_STR, style));\n        }\n\n        Cow::Owned(out)\n    }\n}\n\nimpl Validator for SolidityHelper {\n    fn validate(&self, ctx: &mut ValidationContext<'_>) -> rustyline::Result<ValidationResult> {\n        Ok(self.validate_closed(ctx.input()))\n    }\n}\n\nimpl Completer for SolidityHelper {\n    type Candidate = String;\n}\n\nimpl Hinter for SolidityHelper {\n    type Hint = String;\n}\n\nimpl Helper for SolidityHelper {}\n\n#[expect(non_upper_case_globals)]\n#[deny(unreachable_patterns)]\nfn token_style(token: &Token) -> Style {\n    use solar::parse::{\n        interface::kw::*,\n        token::{TokenKind::*, TokenLitKind::*},\n    };\n\n    match token.kind {\n        Literal(Str | HexStr | UnicodeStr, _) => Color::Green.foreground(),\n        Literal(..) => Color::Yellow.foreground(),\n\n        Ident(\n            Memory | Storage | Calldata | Public | Private | Internal | External | Constant | Pure\n            | View | Payable | Anonymous | Indexed | Abstract | Virtual | Override | Modifier\n            | Immutable | Unchecked,\n        ) => Color::Cyan.foreground(),\n\n        Ident(s) if s.is_elementary_type() => Color::Blue.foreground(),\n        Ident(Mapping) => Color::Blue.foreground(),\n\n        Ident(s) if s.is_used_keyword() || s.is_yul_keyword() => Color::Magenta.foreground(),\n        Arrow | FatArrow => Color::Magenta.foreground(),\n\n        Comment(..) => Color::Primary.dim(),\n\n        _ => Color::Primary.foreground(),\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn validate() {\n        let helper = SolidityHelper::new();\n        let dbg_r = |r: ValidationResult| match r {\n            ValidationResult::Incomplete => \"Incomplete\".to_string(),\n            ValidationResult::Invalid(inner) => format!(\"Invalid({inner:?})\"),\n            ValidationResult::Valid(inner) => format!(\"Valid({inner:?})\"),\n            _ => \"Unknown result\".to_string(),\n        };\n        let valid = |input: &str| {\n            let r = helper.validate_closed(input);\n            assert!(matches!(r, ValidationResult::Valid(None)), \"{input:?}: {}\", dbg_r(r))\n        };\n        let incomplete = |input: &str| {\n            let r = helper.validate_closed(input);\n            assert!(matches!(r, ValidationResult::Incomplete), \"{input:?}: {}\", dbg_r(r))\n        };\n        let invalid = |input: &str| {\n            let r = helper.validate_closed(input);\n            assert!(matches!(r, ValidationResult::Invalid(Some(_))), \"{input:?}: {}\", dbg_r(r))\n        };\n\n        valid(\"1\");\n        valid(\"1 + 2\");\n\n        valid(\"()\");\n        valid(\"{}\");\n        valid(\"[]\");\n\n        incomplete(\"(\");\n        incomplete(\"((\");\n        incomplete(\"[\");\n        incomplete(\"{\");\n        incomplete(\"({\");\n        valid(\"({})\");\n\n        invalid(\")\");\n        invalid(\"]\");\n        invalid(\"}\");\n        invalid(\"(}\");\n        invalid(\"(})\");\n        invalid(\"[}\");\n        invalid(\"[}]\");\n\n        incomplete(\"\\\"\");\n        incomplete(\"\\'\");\n        valid(\"\\\"\\\"\");\n        valid(\"\\'\\'\");\n\n        incomplete(\"/*\");\n        incomplete(\"/*/*\");\n        valid(\"/* */\");\n        valid(\"/* /* */\");\n        valid(\"/* /* */ */\");\n    }\n}\n"
  },
  {
    "path": "crates/chisel/src/source.rs",
    "content": "//! Session Source\n//!\n//! This module contains the `SessionSource` struct, which is a minimal wrapper around\n//! the REPL contract's source code. It provides simple compilation, parsing, and\n//! execution helpers.\n\nuse eyre::Result;\nuse forge_doc::solang_ext::{CodeLocationExt, SafeUnwrap};\nuse foundry_common::fs;\nuse foundry_compilers::{\n    Artifact, ProjectCompileOutput,\n    artifacts::{ConfigurableContractArtifact, Source, Sources},\n    project::ProjectCompiler,\n    solc::Solc,\n};\nuse foundry_config::{Config, SolcReq};\nuse foundry_evm::{backend::Backend, core::bytecode::InstIter, opts::EvmOpts};\nuse semver::Version;\nuse serde::{Deserialize, Serialize};\nuse solang_parser::pt;\nuse solar::interface::diagnostics::EmittedDiagnostics;\nuse std::{cell::OnceCell, collections::HashMap, fmt, path::PathBuf};\nuse walkdir::WalkDir;\n\n/// The minimum Solidity version of the `Vm` interface.\npub const MIN_VM_VERSION: Version = Version::new(0, 6, 2);\n\n/// Solidity source for the `Vm` interface in [forge-std](https://github.com/foundry-rs/forge-std)\nstatic VM_SOURCE: &str = include_str!(\"../../../testdata/utils/Vm.sol\");\n\n/// [`SessionSource`] build output.\npub struct GeneratedOutput {\n    output: ProjectCompileOutput,\n    pub(crate) intermediate: IntermediateOutput,\n}\n\npub struct GeneratedOutputRef<'a> {\n    output: &'a ProjectCompileOutput,\n    // compiler: &'b solar::sema::CompilerRef<'c>,\n    pub(crate) intermediate: &'a IntermediateOutput,\n}\n\n/// Intermediate output for the compiled [SessionSource]\n#[derive(Clone, Debug, PartialEq, Eq)]\npub struct IntermediateOutput {\n    /// All expressions within the REPL contract's run function and top level scope.\n    pub repl_contract_expressions: HashMap<String, pt::Expression>,\n    /// Intermediate contracts\n    pub intermediate_contracts: IntermediateContracts,\n}\n\n/// A refined intermediate parse tree for a contract that enables easy lookups\n/// of definitions.\n#[derive(Clone, Debug, Default, PartialEq, Eq)]\npub struct IntermediateContract {\n    /// All function definitions within the contract\n    pub function_definitions: HashMap<String, Box<pt::FunctionDefinition>>,\n    /// All event definitions within the contract\n    pub event_definitions: HashMap<String, Box<pt::EventDefinition>>,\n    /// All struct definitions within the contract\n    pub struct_definitions: HashMap<String, Box<pt::StructDefinition>>,\n    /// All variable definitions within the top level scope of the contract\n    pub variable_definitions: HashMap<String, Box<pt::VariableDefinition>>,\n}\n\n/// A defined type for a map of contract names to [IntermediateContract]s\ntype IntermediateContracts = HashMap<String, IntermediateContract>;\n\nimpl fmt::Debug for GeneratedOutput {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.debug_struct(\"GeneratedOutput\").finish_non_exhaustive()\n    }\n}\n\nimpl GeneratedOutput {\n    pub fn enter<T: Send>(&self, f: impl FnOnce(GeneratedOutputRef<'_>) -> T + Send) -> T {\n        // TODO(dani): once intermediate is removed\n        // self.output\n        //     .parser()\n        //     .solc()\n        //     .compiler()\n        //     .enter(|compiler| f(GeneratedOutputRef { output: &self.output, compiler }))\n        f(GeneratedOutputRef { output: &self.output, intermediate: &self.intermediate })\n    }\n}\n\nimpl GeneratedOutputRef<'_> {\n    pub fn repl_contract(&self) -> Option<&ConfigurableContractArtifact> {\n        self.output.find_first(\"REPL\")\n    }\n}\n\nimpl std::ops::Deref for GeneratedOutput {\n    type Target = IntermediateOutput;\n    fn deref(&self) -> &Self::Target {\n        &self.intermediate\n    }\n}\nimpl std::ops::Deref for GeneratedOutputRef<'_> {\n    type Target = IntermediateOutput;\n    fn deref(&self) -> &Self::Target {\n        self.intermediate\n    }\n}\n\nimpl IntermediateOutput {\n    pub fn get_event(&self, input: &str) -> Option<&pt::EventDefinition> {\n        self.intermediate_contracts\n            .get(\"REPL\")\n            .and_then(|contract| contract.event_definitions.get(input).map(std::ops::Deref::deref))\n    }\n\n    pub fn final_pc(&self, contract: &ConfigurableContractArtifact) -> Result<Option<usize>> {\n        let deployed_bytecode = contract\n            .get_deployed_bytecode()\n            .ok_or_else(|| eyre::eyre!(\"No deployed bytecode found for `REPL` contract\"))?;\n        let deployed_bytecode_bytes = deployed_bytecode\n            .bytes()\n            .ok_or_else(|| eyre::eyre!(\"No deployed bytecode found for `REPL` contract\"))?;\n\n        let run_func_statements = self.run_func_body()?;\n\n        // Record loc of first yul block return statement (if any).\n        // This is used to decide which is the final statement within the `run()` method.\n        // see <https://github.com/foundry-rs/foundry/issues/4617>.\n        let last_yul_return = run_func_statements.iter().find_map(|statement| {\n            if let pt::Statement::Assembly { loc: _, dialect: _, flags: _, block } = statement\n                && let Some(statement) = block.statements.last()\n                && let pt::YulStatement::FunctionCall(yul_call) = statement\n                && yul_call.id.name == \"return\"\n            {\n                return Some(statement.loc());\n            }\n            None\n        });\n\n        // Find the last statement within the \"run()\" method and get the program\n        // counter via the source map.\n        let Some(final_statement) = run_func_statements.last() else { return Ok(None) };\n\n        // If the final statement is some type of block (assembly, unchecked, or regular),\n        // we need to find the final statement within that block. Otherwise, default to\n        // the source loc of the final statement of the `run()` function's block.\n        //\n        // There is some code duplication within the arms due to the difference between\n        // the [pt::Statement] type and the [pt::YulStatement] types.\n        let mut source_loc = match final_statement {\n            pt::Statement::Assembly { loc: _, dialect: _, flags: _, block } => {\n                // Select last non variable declaration statement, see <https://github.com/foundry-rs/foundry/issues/4938>.\n                let last_statement = block.statements.iter().rev().find(|statement| {\n                    !matches!(statement, pt::YulStatement::VariableDeclaration(_, _, _))\n                });\n                if let Some(statement) = last_statement {\n                    statement.loc()\n                } else {\n                    // In the case where the block is empty, attempt to grab the statement\n                    // before the asm block. Because we use saturating sub to get the second\n                    // to last index, this can always be safely unwrapped.\n                    run_func_statements\n                        .get(run_func_statements.len().saturating_sub(2))\n                        .unwrap()\n                        .loc()\n                }\n            }\n            pt::Statement::Block { loc: _, unchecked: _, statements } => {\n                if let Some(statement) = statements.last() {\n                    statement.loc()\n                } else {\n                    // In the case where the block is empty, attempt to grab the statement\n                    // before the block. Because we use saturating sub to get the second to\n                    // last index, this can always be safely unwrapped.\n                    run_func_statements\n                        .get(run_func_statements.len().saturating_sub(2))\n                        .unwrap()\n                        .loc()\n                }\n            }\n            _ => final_statement.loc(),\n        };\n\n        // Consider yul return statement as final statement (if it's loc is lower) .\n        if let Some(yul_return) = last_yul_return\n            && yul_return.end() < source_loc.start()\n        {\n            source_loc = yul_return;\n        }\n\n        // Map the source location of the final statement of the `run()` function to its\n        // corresponding runtime program counter\n        let final_pc = {\n            let offset = source_loc.start() as u32;\n            let length = (source_loc.end() - source_loc.start()) as u32;\n            trace!(%offset, %length, \"find pc\");\n            contract\n                .get_source_map_deployed()\n                .unwrap()\n                .unwrap()\n                .into_iter()\n                .zip(InstIter::new(deployed_bytecode_bytes).with_pc().map(|(pc, _)| pc))\n                .filter(|(s, _)| s.offset() == offset && s.length() == length)\n                .map(|(_, pc)| pc)\n                .max()\n        };\n        trace!(?final_pc);\n        Ok(final_pc)\n    }\n\n    pub fn run_func_body(&self) -> Result<&Vec<pt::Statement>> {\n        match self\n            .intermediate_contracts\n            .get(\"REPL\")\n            .ok_or_else(|| eyre::eyre!(\"Could not find REPL intermediate contract!\"))?\n            .function_definitions\n            .get(\"run\")\n            .ok_or_else(|| eyre::eyre!(\"Could not find run function definition in REPL contract!\"))?\n            .body\n            .as_ref()\n            .ok_or_else(|| eyre::eyre!(\"Could not find run function body!\"))?\n        {\n            pt::Statement::Block { statements, .. } => Ok(statements),\n            _ => eyre::bail!(\"Could not find statements within run function body!\"),\n        }\n    }\n}\n\n// TODO(dani): further migration blocked on upstream work\n#[cfg(false)]\nimpl<'gcx> GeneratedOutputRef<'_, '_, 'gcx> {\n    pub fn gcx(&self) -> Gcx<'gcx> {\n        self.compiler.gcx()\n    }\n\n    pub fn repl_contract(&self) -> Option<&ConfigurableContractArtifact> {\n        self.output.find_first(\"REPL\")\n    }\n\n    pub fn get_event(&self, input: &str) -> Option<hir::EventId> {\n        self.gcx().hir.events_enumerated().find(|(_, e)| e.name.as_str() == input).map(|(id, _)| id)\n    }\n\n    pub fn final_pc(&self, contract: &ConfigurableContractArtifact) -> Result<Option<usize>> {\n        let deployed_bytecode = contract\n            .get_deployed_bytecode()\n            .ok_or_else(|| eyre::eyre!(\"No deployed bytecode found for `REPL` contract\"))?;\n        let deployed_bytecode_bytes = deployed_bytecode\n            .bytes()\n            .ok_or_else(|| eyre::eyre!(\"No deployed bytecode found for `REPL` contract\"))?;\n\n        // Fetch the run function's body statement\n        let run_body = self.run_func_body();\n\n        // Record loc of first yul block return statement (if any).\n        // This is used to decide which is the final statement within the `run()` method.\n        // see <https://github.com/foundry-rs/foundry/issues/4617>.\n        let last_yul_return_span: Option<Span> = run_body.iter().find_map(|stmt| {\n            // TODO(dani): Yul is not yet lowered to HIR.\n            let _ = stmt;\n            /*\n            if let hir::StmtKind::Assembly { block, .. } = stmt {\n                if let Some(stmt) = block.last() {\n                    if let pt::YulStatement::FunctionCall(yul_call) = stmt {\n                        if yul_call.id.name == \"return\" {\n                            return Some(stmt.loc())\n                        }\n                    }\n                }\n            }\n            */\n            None\n        });\n\n        // Find the last statement within the \"run()\" method and get the program\n        // counter via the source map.\n        let Some(last_stmt) = run_body.last() else { return Ok(None) };\n\n        // If the final statement is some type of block (assembly, unchecked, or regular),\n        // we need to find the final statement within that block. Otherwise, default to\n        // the source loc of the final statement of the `run()` function's block.\n        //\n        // There is some code duplication within the arms due to the difference between\n        // the [pt::Statement] type and the [pt::YulStatement] types.\n        let source_stmt = match &last_stmt.kind {\n            // TODO(dani): Yul is not yet lowered to HIR.\n            /*\n            pt::Statement::Assembly { loc: _, dialect: _, flags: _, block } => {\n                // Select last non variable declaration statement, see <https://github.com/foundry-rs/foundry/issues/4938>.\n                let last_statement = block.statements.iter().rev().find(|statement| {\n                    !matches!(statement, pt::YulStatement::VariableDeclaration(_, _, _))\n                });\n                if let Some(stmt) = last_statement {\n                    stmt\n                } else {\n                    // In the case where the block is empty, attempt to grab the statement\n                    // before the block. Because we use saturating sub to get the second to\n                    // last index, this can always be safely unwrapped.\n                    &run_body[run_body.len().saturating_sub(2)]\n                }\n            }\n            */\n            hir::StmtKind::UncheckedBlock(stmts) | hir::StmtKind::Block(stmts) => {\n                if let Some(stmt) = stmts.last() {\n                    stmt\n                } else {\n                    // In the case where the block is empty, attempt to grab the statement\n                    // before the block. Because we use saturating sub to get the second to\n                    // last index, this can always be safely unwrapped.\n                    &run_body[run_body.len().saturating_sub(2)]\n                }\n            }\n            _ => last_stmt,\n        };\n        let mut source_span = self.stmt_span_without_semicolon(source_stmt);\n\n        // Consider yul return statement as final statement (if it's loc is lower) .\n        if let Some(yul_return_span) = last_yul_return_span\n            && yul_return_span.hi() < source_span.lo()\n        {\n            source_span = yul_return_span;\n        }\n\n        // Map the source location of the final statement of the `run()` function to its\n        // corresponding runtime program counter\n        let (_sf, range) = self.compiler.sess().source_map().span_to_source(source_span).unwrap();\n        dbg!(source_span, &range, &_sf.src[range.clone()]);\n        let offset = range.start as u32;\n        let length = range.len() as u32;\n        let final_pc = deployed_bytecode\n            .source_map()\n            .ok_or_else(|| eyre::eyre!(\"No source map found for `REPL` contract\"))??\n            .into_iter()\n            .zip(InstructionIter::new(deployed_bytecode_bytes))\n            .filter(|(s, _)| s.offset() == offset && s.length() == length)\n            .map(|(_, i)| i.pc)\n            .max()\n            .unwrap_or_default();\n        Ok(Some(final_pc))\n    }\n\n    /// Statements' ranges in the solc source map do not include the semicolon.\n    fn stmt_span_without_semicolon(&self, stmt: &hir::Stmt<'_>) -> Span {\n        match stmt.kind {\n            hir::StmtKind::DeclSingle(id) => {\n                let decl = self.gcx().hir.variable(id);\n                if let Some(expr) = decl.initializer {\n                    stmt.span.with_hi(expr.span.hi())\n                } else {\n                    stmt.span\n                }\n            }\n            hir::StmtKind::DeclMulti(_, expr) => stmt.span.with_hi(expr.span.hi()),\n            hir::StmtKind::Expr(expr) => expr.span,\n            _ => stmt.span,\n        }\n    }\n\n    fn run_func_body(&self) -> hir::Block<'_> {\n        let c = self.repl_contract_hir().expect(\"REPL contract not found in HIR\");\n        let f = c\n            .functions()\n            .find(|&f| self.gcx().hir.function(f).name.as_ref().map(|n| n.as_str()) == Some(\"run\"))\n            .expect(\"`run()` function not found in REPL contract\");\n        self.gcx().hir.function(f).body.expect(\"`run()` function does not have a body\")\n    }\n\n    fn repl_contract_hir(&self) -> Option<&hir::Contract<'_>> {\n        self.gcx().hir.contracts().find(|c| c.name.as_str() == \"REPL\")\n    }\n}\n\n/// Configuration for the [SessionSource]\n#[derive(Clone, Debug, Default, Serialize, Deserialize)]\npub struct SessionSourceConfig {\n    /// Foundry configuration\n    pub foundry_config: Config,\n    /// EVM Options\n    pub evm_opts: EvmOpts,\n    /// Disable the default `Vm` import.\n    pub no_vm: bool,\n    /// In-memory REVM db for the session's runner.\n    #[serde(skip)]\n    pub backend: Option<Backend>,\n    /// Optionally enable traces for the REPL contract execution\n    pub traces: bool,\n    /// Optionally set calldata for the REPL contract execution\n    pub calldata: Option<Vec<u8>>,\n    /// Enable viaIR with minimum optimization\n    ///\n    /// This can fix most of the \"stack too deep\" errors while resulting a\n    /// relatively accurate source map.\n    pub ir_minimum: bool,\n}\n\nimpl SessionSourceConfig {\n    /// Detect the solc version to know if VM can be injected.\n    pub fn detect_solc(&mut self) -> Result<()> {\n        if self.foundry_config.solc.is_none() {\n            let version = Solc::ensure_installed(&\"*\".parse().unwrap())?;\n            self.foundry_config.solc = Some(SolcReq::Version(version));\n        }\n        if !self.no_vm\n            && let Some(version) = self.foundry_config.solc_version()\n            && version < MIN_VM_VERSION\n        {\n            info!(%version, minimum=%MIN_VM_VERSION, \"Disabling VM injection\");\n            self.no_vm = true;\n        }\n        Ok(())\n    }\n}\n\n/// REPL Session Source wrapper\n///\n/// Heavily based on soli's [`ConstructedSource`](https://github.com/jpopesculian/soli/blob/master/src/main.rs#L166)\n#[derive(Debug, Serialize, Deserialize)]\npub struct SessionSource {\n    /// The file name\n    pub file_name: String,\n    /// The contract name\n    pub contract_name: String,\n\n    /// Session Source configuration\n    pub config: SessionSourceConfig,\n\n    /// Global level Solidity code.\n    ///\n    /// Above and outside all contract declarations, in the global context.\n    pub global_code: String,\n    /// Top level Solidity code.\n    ///\n    /// Within the contract declaration, but outside of the `run()` function.\n    pub contract_code: String,\n    /// The code to be executed in the `run()` function.\n    pub run_code: String,\n\n    /// Cached VM source code.\n    #[serde(skip, default = \"vm_source\")]\n    vm_source: Source,\n    /// The generated output\n    #[serde(skip)]\n    output: OnceCell<GeneratedOutput>,\n}\n\nfn vm_source() -> Source {\n    Source::new(VM_SOURCE)\n}\n\nimpl Clone for SessionSource {\n    fn clone(&self) -> Self {\n        Self {\n            file_name: self.file_name.clone(),\n            contract_name: self.contract_name.clone(),\n            global_code: self.global_code.clone(),\n            contract_code: self.contract_code.clone(),\n            run_code: self.run_code.clone(),\n            config: self.config.clone(),\n            vm_source: self.vm_source.clone(),\n            output: Default::default(),\n        }\n    }\n}\n\nimpl SessionSource {\n    /// Creates a new source given a solidity compiler version\n    ///\n    /// # Panics\n    ///\n    /// If no Solc binary is set, cannot be found or the `--version` command fails\n    ///\n    /// ### Takes\n    ///\n    /// - An instance of [Solc]\n    /// - An instance of [SessionSourceConfig]\n    ///\n    /// ### Returns\n    ///\n    /// A new instance of [SessionSource]\n    pub fn new(mut config: SessionSourceConfig) -> Result<Self> {\n        config.detect_solc()?;\n        Ok(Self {\n            file_name: \"ReplContract.sol\".to_string(),\n            contract_name: \"REPL\".to_string(),\n            config,\n            global_code: Default::default(),\n            contract_code: Default::default(),\n            run_code: Default::default(),\n            vm_source: vm_source(),\n            output: Default::default(),\n        })\n    }\n\n    /// Clones the [SessionSource] and appends a new line of code.\n    ///\n    /// Returns `true` if the new line was added to `run()`.\n    pub fn clone_with_new_line(&self, mut content: String) -> Result<(Self, bool)> {\n        if let Some((new_source, fragment)) = self\n            .parse_fragment(&content)\n            .or_else(|| {\n                content.push(';');\n                self.parse_fragment(&content)\n            })\n            .or_else(|| {\n                content = content.trim_end().trim_end_matches(';').to_string();\n                self.parse_fragment(&content)\n            })\n        {\n            Ok((new_source, matches!(fragment, ParseTreeFragment::Function)))\n        } else {\n            eyre::bail!(\"\\\"{}\\\"\", content.trim());\n        }\n    }\n\n    /// Parses a fragment of Solidity code in memory and assigns it a scope within the\n    /// [`SessionSource`].\n    fn parse_fragment(&self, buffer: &str) -> Option<(Self, ParseTreeFragment)> {\n        #[track_caller]\n        fn debug_errors(errors: &EmittedDiagnostics) {\n            debug!(\"{errors}\");\n        }\n\n        let mut this = self.clone();\n        match this.add_run_code(buffer).parse() {\n            Ok(()) => return Some((this, ParseTreeFragment::Function)),\n            Err(e) => debug_errors(&e),\n        }\n        this = self.clone();\n        match this.add_contract_code(buffer).parse() {\n            Ok(()) => return Some((this, ParseTreeFragment::Contract)),\n            Err(e) => debug_errors(&e),\n        }\n        this = self.clone();\n        match this.add_global_code(buffer).parse() {\n            Ok(()) => return Some((this, ParseTreeFragment::Source)),\n            Err(e) => debug_errors(&e),\n        }\n        None\n    }\n\n    /// Append global-level code to the source.\n    pub fn add_global_code(&mut self, content: &str) -> &mut Self {\n        self.global_code.push_str(content.trim());\n        self.global_code.push('\\n');\n        self.clear_output();\n        self\n    }\n\n    /// Append contract-level code to the source.\n    pub fn add_contract_code(&mut self, content: &str) -> &mut Self {\n        self.contract_code.push_str(content.trim());\n        self.contract_code.push('\\n');\n        self.clear_output();\n        self\n    }\n\n    /// Append code to the `run()` function of the REPL contract.\n    pub fn add_run_code(&mut self, content: &str) -> &mut Self {\n        self.run_code.push_str(content.trim());\n        self.run_code.push('\\n');\n        self.clear_output();\n        self\n    }\n\n    /// Clears all source code.\n    pub fn clear(&mut self) {\n        String::clear(&mut self.global_code);\n        String::clear(&mut self.contract_code);\n        String::clear(&mut self.run_code);\n        self.clear_output();\n    }\n\n    /// Clear the `run()` function code.\n    pub fn clear_run(&mut self) -> &mut Self {\n        String::clear(&mut self.run_code);\n        self.clear_output();\n        self\n    }\n\n    fn clear_output(&mut self) {\n        self.output.take();\n    }\n\n    /// Compiles the source if necessary.\n    pub fn build(&self) -> Result<&GeneratedOutput> {\n        // TODO: mimics `get_or_try_init`\n        if let Some(output) = self.output.get() {\n            return Ok(output);\n        }\n        let output = self.compile()?;\n        let intermediate = self.generate_intermediate_output()?;\n        let output = GeneratedOutput { output, intermediate };\n        Ok(self.output.get_or_init(|| output))\n    }\n\n    /// Compiles the source.\n    #[cold]\n    fn compile(&self) -> Result<ProjectCompileOutput> {\n        let sources = self.get_sources();\n\n        let mut project = self.config.foundry_config.ephemeral_project()?;\n        self.config.foundry_config.disable_optimizations(&mut project, self.config.ir_minimum);\n        let mut output = ProjectCompiler::with_sources(&project, sources)?.compile()?;\n\n        if output.has_compiler_errors() {\n            eyre::bail!(\"{output}\");\n        }\n\n        // TODO(dani): re-enable\n        if cfg!(false) {\n            output.parser_mut().solc_mut().compiler_mut().enter_mut(|c| {\n                let _ = c.lower_asts();\n            });\n        }\n\n        Ok(output)\n    }\n\n    fn get_sources(&self) -> Sources {\n        let mut sources = Sources::new();\n\n        let src = self.to_repl_source();\n        sources.insert(self.file_name.clone().into(), Source::new(src));\n\n        // Include Vm.sol if forge-std remapping is not available.\n        if !self.config.no_vm\n            && !self\n                .config\n                .foundry_config\n                .get_all_remappings()\n                .any(|r| r.name.starts_with(\"forge-std\"))\n        {\n            sources.insert(\"forge-std/Vm.sol\".into(), self.vm_source.clone());\n        }\n\n        sources\n    }\n\n    /// Generate intermediate contracts for all contract definitions in the compilation source.\n    ///\n    /// ### Returns\n    ///\n    /// Optionally, a map of contract names to a vec of [IntermediateContract]s.\n    pub fn generate_intermediate_contracts(&self) -> Result<HashMap<String, IntermediateContract>> {\n        let mut res_map = HashMap::default();\n        let parsed_map = self.get_sources();\n        for source in parsed_map.values() {\n            Self::get_intermediate_contract(&source.content, &mut res_map);\n        }\n        Ok(res_map)\n    }\n\n    /// Generate intermediate output for the REPL contract\n    pub fn generate_intermediate_output(&self) -> Result<IntermediateOutput> {\n        // Parse generate intermediate contracts\n        let intermediate_contracts = self.generate_intermediate_contracts()?;\n\n        // Construct variable definitions\n        let variable_definitions = intermediate_contracts\n            .get(\"REPL\")\n            .ok_or_else(|| eyre::eyre!(\"Could not find intermediate REPL contract!\"))?\n            .variable_definitions\n            .clone()\n            .into_iter()\n            .map(|(k, v)| (k, v.ty))\n            .collect::<HashMap<String, pt::Expression>>();\n        // Construct intermediate output\n        let mut intermediate_output = IntermediateOutput {\n            repl_contract_expressions: variable_definitions,\n            intermediate_contracts,\n        };\n\n        // Add all statements within the run function to the repl_contract_expressions map\n        for (key, val) in intermediate_output\n            .run_func_body()?\n            .clone()\n            .iter()\n            .flat_map(Self::get_statement_definitions)\n        {\n            intermediate_output.repl_contract_expressions.insert(key, val);\n        }\n\n        Ok(intermediate_output)\n    }\n\n    /// Construct the REPL source.\n    pub fn to_repl_source(&self) -> String {\n        let Self {\n            contract_name,\n            global_code,\n            contract_code: top_level_code,\n            run_code,\n            config,\n            ..\n        } = self;\n        let (mut vm_import, mut vm_constant) = (String::new(), String::new());\n        // Check if there's any `forge-std` remapping and determine proper path to it by\n        // searching remapping path.\n        if !config.no_vm\n            && let Some(remapping) = config\n                .foundry_config\n                .remappings\n                .iter()\n                .find(|remapping| remapping.name == \"forge-std/\")\n            && let Some(vm_path) = WalkDir::new(&remapping.path.path)\n                .into_iter()\n                .filter_map(|e| e.ok())\n                .find(|e| e.file_name() == \"Vm.sol\")\n        {\n            vm_import = format!(\"import {{Vm}} from \\\"{}\\\";\\n\", vm_path.path().display());\n            vm_constant = \"Vm internal constant vm = Vm(address(uint160(uint256(keccak256(\\\"hevm cheat code\\\")))));\\n\".to_string();\n        }\n\n        format!(\n            r#\"\n// SPDX-License-Identifier: UNLICENSED\npragma solidity 0;\n\n{vm_import}\n{global_code}\n\ncontract {contract_name} {{\n    {vm_constant}\n    {top_level_code}\n\n    /// @notice REPL contract entry point\n    function run() public {{\n        {run_code}\n    }}\n}}\"#,\n        )\n    }\n\n    /// Parse the current source in memory using Solar.\n    pub(crate) fn parse(&self) -> Result<(), EmittedDiagnostics> {\n        let sess =\n            solar::interface::Session::builder().with_buffer_emitter(Default::default()).build();\n        let _ = sess.enter_sequential(|| -> solar::interface::Result<()> {\n            let arena = solar::ast::Arena::new();\n            let filename = self.file_name.clone().into();\n            let src = self.to_repl_source();\n            let mut parser = solar::parse::Parser::from_source_code(&sess, &arena, filename, src)?;\n            let _ast = parser.parse_file().map_err(|e| e.emit())?;\n            Ok(())\n        });\n        sess.dcx.emitted_errors().unwrap()\n    }\n\n    /// Gets the [IntermediateContract] for a Solidity source string and inserts it into the\n    /// passed `res_map`. In addition, recurses on any imported files as well.\n    ///\n    /// ### Takes\n    /// - `content` - A Solidity source string\n    /// - `res_map` - A mutable reference to a map of contract names to [IntermediateContract]s\n    pub fn get_intermediate_contract(\n        content: &str,\n        res_map: &mut HashMap<String, IntermediateContract>,\n    ) {\n        if let Ok((pt::SourceUnit(source_unit_parts), _)) = solang_parser::parse(content, 0) {\n            let func_defs = source_unit_parts\n                .into_iter()\n                .filter_map(|sup| match sup {\n                    pt::SourceUnitPart::ImportDirective(i) => match i {\n                        pt::Import::Plain(s, _)\n                        | pt::Import::Rename(s, _, _)\n                        | pt::Import::GlobalSymbol(s, _, _) => {\n                            let s = match s {\n                                pt::ImportPath::Filename(s) => s.string,\n                                pt::ImportPath::Path(p) => p.to_string(),\n                            };\n                            let path = PathBuf::from(s);\n\n                            match fs::read_to_string(path) {\n                                Ok(source) => {\n                                    Self::get_intermediate_contract(&source, res_map);\n                                    None\n                                }\n                                Err(_) => None,\n                            }\n                        }\n                    },\n                    pt::SourceUnitPart::ContractDefinition(cd) => {\n                        let mut intermediate = IntermediateContract::default();\n\n                        cd.parts.into_iter().for_each(|part| match part {\n                            pt::ContractPart::FunctionDefinition(def) => {\n                                // Only match normal function definitions here.\n                                if matches!(def.ty, pt::FunctionTy::Function) {\n                                    intermediate\n                                        .function_definitions\n                                        .insert(def.name.clone().unwrap().name, def);\n                                }\n                            }\n                            pt::ContractPart::EventDefinition(def) => {\n                                let event_name = def.name.safe_unwrap().name.clone();\n                                intermediate.event_definitions.insert(event_name, def);\n                            }\n                            pt::ContractPart::StructDefinition(def) => {\n                                let struct_name = def.name.safe_unwrap().name.clone();\n                                intermediate.struct_definitions.insert(struct_name, def);\n                            }\n                            pt::ContractPart::VariableDefinition(def) => {\n                                let var_name = def.name.safe_unwrap().name.clone();\n                                intermediate.variable_definitions.insert(var_name, def);\n                            }\n                            _ => {}\n                        });\n                        Some((cd.name.safe_unwrap().name.clone(), intermediate))\n                    }\n                    _ => None,\n                })\n                .collect::<HashMap<String, IntermediateContract>>();\n            res_map.extend(func_defs);\n        }\n    }\n\n    /// Helper to deconstruct a statement\n    ///\n    /// ### Takes\n    ///\n    /// A reference to a [pt::Statement]\n    ///\n    /// ### Returns\n    ///\n    /// A vector containing tuples of the inner expressions' names, types, and storage locations.\n    pub fn get_statement_definitions(statement: &pt::Statement) -> Vec<(String, pt::Expression)> {\n        match statement {\n            pt::Statement::VariableDefinition(_, def, _) => {\n                vec![(def.name.safe_unwrap().name.clone(), def.ty.clone())]\n            }\n            pt::Statement::Expression(_, pt::Expression::Assign(_, left, _)) => {\n                if let pt::Expression::List(_, list) = left.as_ref() {\n                    list.iter()\n                        .filter_map(|(_, param)| {\n                            param.as_ref().and_then(|param| {\n                                param\n                                    .name\n                                    .as_ref()\n                                    .map(|name| (name.name.clone(), param.ty.clone()))\n                            })\n                        })\n                        .collect()\n                } else {\n                    Vec::default()\n                }\n            }\n            _ => Vec::default(),\n        }\n    }\n}\n\n/// A Parse Tree Fragment\n///\n/// Used to determine whether an input will go to the \"run()\" function,\n/// the top level of the contract, or in global scope.\n#[derive(Debug)]\nenum ParseTreeFragment {\n    /// Code for the global scope\n    Source,\n    /// Code for the top level of the contract\n    Contract,\n    /// Code for the \"run()\" function\n    Function,\n}\n"
  },
  {
    "path": "crates/chisel/tests/it/main.rs",
    "content": "#[cfg(unix)]\nmod repl;\n"
  },
  {
    "path": "crates/chisel/tests/it/repl/mod.rs",
    "content": "mod session;\nuse session::ChiselSession;\n\nmacro_rules! repl_test {\n    ($name:ident, | $cmd:ident | $test:expr) => {\n        repl_test!($name, \"\", |$cmd| $test);\n    };\n    ($name:ident, $flags:expr, | $cmd:ident | $test:expr) => {\n        repl_test!($name, $flags, init = false, |$cmd| $test);\n    };\n    ($name:ident, $flags:expr,init = $init:expr, | $cmd:ident | $test:expr) => {\n        #[test]\n        #[allow(unused_mut)]\n        fn $name() {\n            let mut $cmd = ChiselSession::new(stringify!($name), $flags, $init);\n            $test;\n            return (); // Fix \"go to definition\" due to `tokio::test`.\n        }\n    };\n}\n\nrepl_test!(repl_help, |repl| {\n    repl.sendln_raw(\"!h\");\n    repl.expect(\"Chisel help\");\n    repl.expect_prompt();\n});\n\n// Test abi encode/decode.\nrepl_test!(abi_encode_decode, |repl| {\n    repl.sendln(\"bytes memory encoded = abi.encode(42, \\\"hello\\\")\");\n    repl.sendln(\"(uint num, string memory str) = abi.decode(encoded, (uint, string))\");\n    repl.sendln(\"num\");\n    repl.expect(\"42\");\n    repl.sendln(\"str\");\n    repl.expect(\"hello\");\n});\n\n// Test 0x prefixed strings.\nrepl_test!(hex_string_interpretation, |repl| {\n    repl.sendln(\"string memory s = \\\"0x1234\\\"\");\n    repl.sendln(\"s\");\n    // Should be treated as string, not hex literal.\n    repl.expect(\"0x1234\");\n});\n\n// Test cheatcodes availability.\nrepl_test!(cheatcodes_available, \"\", init = true, |repl| {\n    repl.sendln(\"address alice = address(0x1)\");\n\n    repl.sendln(\"alice.balance\");\n    repl.expect(\"Decimal: 0\");\n\n    repl.sendln(\"vm.deal();\");\n    repl.expect(\"Wrong argument count for function call\");\n\n    repl.sendln(\"vm.deal(alice, 1 ether);\");\n\n    repl.sendln(\"alice.balance\");\n    repl.expect(\"Decimal: 1000000000000000000\");\n});\n\n// Test empty inputs.\nrepl_test!(empty_input, |repl| {\n    repl.sendln(\"   \\n \\n\\n    \\t \\t \\n \\n\\t\\t\\t\\t \\n \\n\");\n});\n\n// Issue #4130: Test type(intN).min correctness.\nrepl_test!(int_min_values, |repl| {\n    repl.sendln(\"type(int8).min\");\n    repl.expect(\"-128\");\n    repl.sendln(\"type(int256).min\");\n    repl.expect(\"-57896044618658097711785492504343953926634992332820282019728792003956564819968\");\n});\n\n// Issue #4393: Test edit command with traces.\n// TODO: test `!edit`\n// repl_test!(edit_with_traces, |repl| {\n//     repl.sendln(\"!traces\");\n//     repl.sendln(\"uint x = 42\");\n//     repl.sendln(\"!edit\");\n//     // Should open editor without errors.\n//     repl.expect(\"Running\");\n// });\n\n// Test tuple support.\nrepl_test!(tuples, |repl| {\n    repl.sendln(\"(uint a, uint b) = (1, 2)\");\n    repl.sendln(\"a\");\n    repl.expect(\"Decimal: 1\");\n    repl.sendln(\"b\");\n    repl.expect(\"Decimal: 2\");\n});\n\n// Issue #4467: Test import.\nrepl_test!(import, \"\", init = true, |repl| {\n    repl.sendln(\"import {Counter} from \\\"src/Counter.sol\\\"\");\n    repl.sendln(\"Counter c = new Counter()\");\n    // TODO: pre-existing inspection failure.\n    // repl.sendln(\"c.number()\");\n    repl.sendln(\"uint x = c.number();\\nx\");\n    repl.expect(\"Decimal: 0\");\n    repl.sendln(\"c.increment();\");\n    // repl.sendln(\"c.number()\");\n    repl.sendln(\"x = c.number();\\nx\");\n    repl.expect(\"Decimal: 1\");\n});\n\n// Issue #4617: Test code after assembly return.\nrepl_test!(assembly_return, |repl| {\n    repl.sendln(\"uint x = 1;\");\n    repl.sendln(\"assembly { mstore(0x0, 0x1337) return(0x0, 0x20) }\");\n    repl.sendln(\"x = 2;\");\n    repl.sendln(\"!md\");\n    // Should work without errors.\n    repl.expect(\"[0x00:0x20]: 0x0000000000000000000000000000000000000000000000000000000000001337\");\n});\n\n// Issue #4652: Test commands with trailing whitespace.\nrepl_test!(trailing_whitespace, |repl| {\n    repl.sendln(\"uint x = 42   \");\n    repl.sendln(\"x\");\n    repl.expect(\"Decimal: 42\");\n});\n\n// Issue #4652: Test that solc flags are respected.\nrepl_test!(solc_flags, \"--use 0.8.23\", |repl| {\n    repl.sendln(\"pragma solidity 0.8.24;\");\n    repl.expect(\"invalid solc version\");\n});\n\n// Issue #4915: `chisel eval`\nrepl_test!(eval_subcommand, \"eval type(uint8).max\", |repl| {\n    repl.expect(\"Decimal: 255\");\n});\n\n// Issue #4938: Test memory/stack dumps with assembly.\nrepl_test!(assembly_memory_dump, |repl| {\n    let input = r#\"\nuint256 value = 12345;\nstring memory str;\nassembly {\n    str := add(mload(0x40), 0x80)\n    mstore(0x40, add(str, 0x20))\n    mstore(str, 0)\n    let end := str\n}\n\"#;\n    repl.sendln_raw(input.trim());\n    repl.expect_prompts(3);\n    repl.sendln(\"value\");\n    repl.expect(\"Decimal: 12345\");\n    repl.sendln(\"!md\");\n    repl.expect(\"[0x00:0x20]\");\n});\n\n// Issue #5051, #8978: Test EVM version normalization.\nrepl_test!(evm_version_normalization, \"--use 0.7.6 --evm-version london\", |repl| {\n    repl.sendln(\"uint x;\\nx\");\n    repl.expect(\"Decimal: 0\");\n});\n\n// Issue #5481: Test function return values are displayed.\nrepl_test!(function_return_display, |repl| {\n    repl.sendln(\"function add(uint a, uint b) public pure returns (uint) { return a + b; }\");\n    repl.sendln(\"add(2, 3)\");\n    repl.expect(\"Decimal: 5\");\n});\n\n// Issue #5737: Test bytesN return types.\nrepl_test!(bytes_length_type, |repl| {\n    repl.sendln(\"bytes10 b = bytes10(0)\");\n    repl.sendln(\"b.length\");\n    repl.expect(\"Decimal: 10\");\n});\n\n// Issue #5737: Test bytesN indexing return type.\nrepl_test!(bytes_index_type, |repl| {\n    repl.sendln(\"bytes32 b = bytes32(uint256(0x0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20))\");\n    repl.sendln(\"b[3]\");\n    repl.expect(\"Data: 0x0400000000000000000000000000000000000000000000000000000000000000\");\n});\n\n// Issue #6618: Test fetching interface with structs.\nrepl_test!(fetch_interface_with_structs, |repl| {\n    repl.sendln_raw(\"!fe 0x5ff137d4b0fdcd49dca30c7cf57e578a026d2789 IEntryPoint\");\n    repl.expect(\n        \"Added 0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789's interface to source as `IEntryPoint`\",\n    );\n    repl.expect_prompt();\n    repl.sendln(\"uint256 x = 1;\\nx\");\n    repl.expect(\"Decimal: 1\");\n});\n\n// Issue #7035: Test that hex strings aren't checksummed as addresses.\nrepl_test!(hex_string_no_checksum, |repl| {\n    repl.sendln(\"function test(string memory s) public pure returns (string memory) { return s; }\");\n    repl.sendln(\"test(\\\"0xe5f3af50fe5d0bf402a3c6f55ccc47d4307922d4\\\")\");\n    // Should return the exact string, not checksummed.\n    repl.expect(\"0xe5f3af50fe5d0bf402a3c6f55ccc47d4307922d4\");\n});\n\n// Issue #7050: Test enum min/max operations.\nrepl_test!(enum_min_max, |repl| {\n    repl.sendln(\"enum Color { Red, Green, Blue }\");\n    repl.sendln(\"type(Color).min\");\n    repl.expect(\"Decimal: 0\");\n    repl.sendln(\"type(Color).max\");\n    repl.expect(\"Decimal: 2\");\n});\n\n// Issue #9377: Test correct hex formatting for uint256.\nrepl_test!(uint256_hex_formatting, |repl| {\n    repl.sendln(\"uint256 x = 42\");\n    // Full word hex should be 64 chars (256 bits).\n    repl.sendln(\"x\");\n    repl.expect(\"0x000000000000000000000000000000000000000000000000000000000000002a\");\n});\n\n// Issue #9377: Test that full words are printed correctly.\nrepl_test!(full_word_hex_formatting, |repl| {\n    repl.sendln(r#\"keccak256(abi.encode(uint256(keccak256(\"AgoraStableSwapStorage.OracleStorage\")) - 1)) & ~bytes32(uint256(0xff))\"#);\n    repl.expect(\n        \"Hex (full word): 0x0a6b316b47a0cd26c1b582ae3dcffbd175283c221c3cb3d1c614e3e47f62a700\",\n    );\n});\n\n// Test that uint is printed properly with any size.\nrepl_test!(uint_formatting, |repl| {\n    for size in (8..=256).step_by(8) {\n        repl.sendln(&format!(\"type(uint{size}).max\"));\n        repl.expect(&format!(\"Hex: 0x{}\", \"f\".repeat(size / 4)));\n\n        repl.sendln(&format!(\"uint{size}(2)\"));\n        repl.expect(\"Hex: 0x2\");\n    }\n});\n\n// Test that int is printed properly with any size.\nrepl_test!(int_formatting, |repl| {\n    for size in (8..=256).step_by(8) {\n        let size_minus_1: usize = size / 4 - 1;\n        repl.sendln(&format!(\"type(int{size}).max\"));\n        repl.expect(&format!(\"Hex: 0x7{}\", \"f\".repeat(size_minus_1)));\n\n        repl.sendln(&format!(\"int{size}(2)\"));\n        repl.expect(\"Hex: 0x2\");\n\n        repl.sendln(&format!(\"type(int{size}).min\"));\n        repl.expect(&format!(\"Hex: 0x8{}\", \"0\".repeat(size_minus_1)));\n\n        repl.sendln(&format!(\"int{size}(-2)\"));\n        repl.expect(&format!(\"Hex: 0x{}e\", \"f\".repeat(size_minus_1)));\n    }\n});\n\nrepl_test!(uninitialized_variables, |repl| {\n    repl.sendln(\"uint256 x;\");\n    repl.sendln(\"address y;\");\n    repl.sendln(\"assembly { y := not(x) }\");\n\n    repl.sendln(\"x\");\n    repl.expect(\"Hex: 0x0\");\n\n    repl.sendln(\"y\");\n    repl.expect(\"Data: 0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF\");\n});\n\nrepl_test!(chisel_can_run_with_live_logs_flag, \"--live-logs\", init = true, |repl| {\n    repl.sendln(\"import {console} from 'forge-std/Script.sol';\");\n    repl.sendln(\"console.log('Hello, World!');\");\n    repl.expect(\"Hello, World!\");\n\n    repl.sendln(\"console.log('Goodbye, World!');\");\n    repl.expect(\"Hello, World!\"); // old log is also printed\n    repl.expect(\"Goodbye, World!\");\n});\n"
  },
  {
    "path": "crates/chisel/tests/it/repl/session.rs",
    "content": "use foundry_compilers::PathStyle;\nuse foundry_test_utils::TestProject;\nuse rexpect::{reader::Options, session::PtySession, spawn_with_options};\n\nconst TIMEOUT_SECS: u64 = 3;\nconst PROMPT: &str = \"➜ \";\n\n/// Testing session for Chisel.\npub struct ChiselSession {\n    session: Box<PtySession>,\n    project: Box<TestProject>,\n    is_repl: bool,\n}\n\nstatic SUBCOMMANDS: &[&str] = &[\"list\", \"load\", \"view\", \"clear-cache\", \"eval\", \"help\"];\n\nfn is_repl(args: &[String]) -> bool {\n    args.is_empty()\n        || !SUBCOMMANDS.iter().any(|subcommand| args.iter().any(|arg| arg == subcommand))\n}\n\n#[allow(dead_code)]\nimpl ChiselSession {\n    pub fn new(name: &str, flags: &str, init: bool) -> Self {\n        let project = foundry_test_utils::TestProject::new(name, PathStyle::Dapptools);\n        if init {\n            foundry_test_utils::util::initialize(project.root());\n            project.initialize_default_contracts();\n        }\n\n        let bin = env!(\"CARGO_BIN_EXE_chisel\");\n        let mut command = std::process::Command::new(bin);\n\n        // TODO: TTY works but logs become unreadable.\n        command.current_dir(project.root());\n        command.env(\"NO_COLOR\", \"1\");\n        command.env(\"TERM\", \"dumb\");\n\n        command.env(\"ETHERSCAN_API_KEY\", foundry_test_utils::rpc::next_etherscan_api_key());\n\n        if !flags.is_empty() {\n            command.args(flags.split_whitespace());\n        }\n        let args = command.get_args().map(|s| s.to_str().unwrap().to_string()).collect::<Vec<_>>();\n\n        let session = spawn_with_options(\n            command,\n            Options {\n                timeout_ms: Some(TIMEOUT_SECS * 1000),\n                strip_ansi_escape_codes: false,\n                encoding: rexpect::Encoding::UTF8,\n            },\n        )\n        .unwrap();\n\n        let is_repl = is_repl(&args);\n        let mut session = Self { session: Box::new(session), project: Box::new(project), is_repl };\n\n        // Expect initial prompt only if we're in the REPL.\n        if session.is_repl() {\n            session.expect(\"Welcome to Chisel!\");\n        }\n\n        session\n    }\n\n    pub fn project(&self) -> &TestProject {\n        &self.project\n    }\n\n    pub fn is_repl(&self) -> bool {\n        self.is_repl\n    }\n\n    /// Send a line to the REPL and expects the prompt to appear.\n    #[track_caller]\n    pub fn sendln(&mut self, line: &str) {\n        self.sendln_raw(line);\n        if self.is_repl() {\n            self.expect_prompt();\n        }\n    }\n\n    /// Send a line to the REPL without expecting the prompt to appear.\n    ///\n    /// You might want to call `expect_prompt` after this.\n    #[track_caller]\n    pub fn sendln_raw(&mut self, line: &str) {\n        match self.session.send_line(line) {\n            Ok(_) => (),\n            Err(e) => {\n                panic!(\"failed to send line {line:?}: {e}\")\n            }\n        }\n    }\n\n    /// Expect the needle to appear.\n    #[track_caller]\n    pub fn expect(&mut self, needle: &str) {\n        match self.session.exp_string(needle) {\n            Ok(_) => (),\n            Err(e) => {\n                panic!(\"failed to expect {needle:?}: {e}\")\n            }\n        }\n    }\n\n    /// Expect the prompt to appear.\n    #[track_caller]\n    pub fn expect_prompt(&mut self) {\n        self.expect(PROMPT);\n    }\n\n    /// Expect the prompt to appear `n` times.\n    #[track_caller]\n    pub fn expect_prompts(&mut self, n: usize) {\n        for _ in 0..n {\n            self.expect_prompt();\n        }\n    }\n}\n"
  },
  {
    "path": "crates/cli/Cargo.toml",
    "content": "[package]\nname = \"foundry-cli\"\n\nversion.workspace = true\nedition.workspace = true\nrust-version.workspace = true\nauthors.workspace = true\nlicense.workspace = true\nhomepage.workspace = true\nrepository.workspace = true\n\n[lints]\nworkspace = true\n\n[dependencies]\nfoundry-block-explorers.workspace = true\nfoundry-cli-markdown.workspace = true\nfoundry-common.workspace = true\nfoundry-config.workspace = true\nfoundry-evm.workspace = true\nfoundry-primitives.workspace = true\nfoundry-wallets.workspace = true\n\nfoundry-compilers.workspace = true\nsolar.workspace = true\n\nalloy-eips.workspace = true\nalloy-dyn-abi.workspace = true\nalloy-network.workspace = true\nalloy-signer.workspace = true\nalloy-json-abi.workspace = true\nalloy-primitives.workspace = true\nalloy-provider.workspace = true\nalloy-rlp.workspace = true\nalloy-chains.workspace = true\nalloy-ens = { workspace = true, features = [\"provider\"] }\n\ncfg-if = \"1.0\"\nclap = { version = \"4\", features = [\"derive\", \"env\", \"unicode\", \"wrap_help\"] }\nclap_complete.workspace = true\nclap_complete_nushell.workspace = true\ncolor-eyre.workspace = true\ndotenvy = \"0.15\"\neyre.workspace = true\nfutures.workspace = true\nindicatif.workspace = true\nitertools.workspace = true\nmimalloc = { workspace = true, optional = true }\npath-slash.workspace = true\nrayon.workspace = true\nregex = { workspace = true, default-features = false }\nserde_json.workspace = true\nserde.workspace = true\nstrsim = \"0.11\"\nstrum = { workspace = true, features = [\"derive\"] }\ntokio = { workspace = true, features = [\"macros\"] }\ntracing-subscriber = { workspace = true, features = [\"registry\", \"env-filter\"] }\ntracing.workspace = true\nyansi.workspace = true\nrustls = { workspace = true, features = [\"ring\"] }\ndunce.workspace = true\n\ntracing-tracy = { version = \"0.11\", optional = true, features = [\"demangle\"] }\n\n[dev-dependencies]\ntempfile.workspace = true\n\n[target.'cfg(unix)'.dependencies]\ntikv-jemallocator = { workspace = true, optional = true }\n\n[features]\ntracy = [\"dep:tracing-tracy\"]\ntracy-allocator = [\"tracy\"]\njemalloc = [\"dep:tikv-jemallocator\"]\nmimalloc = [\"dep:mimalloc\"]\n"
  },
  {
    "path": "crates/cli/README.md",
    "content": "# Foundry CLIs\n\nThe CLIs are written using [clap's](https://docs.rs/clap) [derive feature](https://docs.rs/clap/latest/clap/_derive).\n\n## Installation\n\nSee [Installation](../../README.md#Installation).\n\n## Usage\n\nRead the [📖 Foundry Book][foundry-book]\n\n## Debugging\n\nDebug logs are printed with\n[`tracing`](https://docs.rs/tracing/latest/tracing/). You can configure the\nverbosity level via the\n[`RUST_LOG`](https://docs.rs/tracing-subscriber/latest/tracing_subscriber/fmt/index.html#filtering-events-with-environment-variables)\nenvironment variable, on a per package level,\ne.g.:`RUST_LOG=forge,foundry_evm forge test`\n\n[foundry-book]: https://book.getfoundry.sh\n"
  },
  {
    "path": "crates/cli/src/clap.rs",
    "content": "use clap_complete::{Shell as ClapCompleteShell, aot::Generator};\nuse clap_complete_nushell::Nushell;\n\n#[derive(Clone, Copy)]\npub enum Shell {\n    ClapCompleteShell(ClapCompleteShell),\n    Nushell,\n}\n\nimpl clap::ValueEnum for Shell {\n    fn value_variants<'a>() -> &'a [Self] {\n        &[\n            Self::ClapCompleteShell(ClapCompleteShell::Bash),\n            Self::ClapCompleteShell(ClapCompleteShell::Zsh),\n            Self::ClapCompleteShell(ClapCompleteShell::Fish),\n            Self::ClapCompleteShell(ClapCompleteShell::PowerShell),\n            Self::ClapCompleteShell(ClapCompleteShell::Elvish),\n            Self::Nushell,\n        ]\n    }\n\n    fn to_possible_value(&self) -> Option<clap::builder::PossibleValue> {\n        match self {\n            Self::ClapCompleteShell(shell) => shell.to_possible_value(),\n            Self::Nushell => Some(clap::builder::PossibleValue::new(\"nushell\")),\n        }\n    }\n}\n\nimpl Generator for Shell {\n    fn file_name(&self, name: &str) -> String {\n        match self {\n            Self::ClapCompleteShell(shell) => shell.file_name(name),\n            Self::Nushell => Nushell.file_name(name),\n        }\n    }\n\n    fn generate(&self, cmd: &clap::Command, buf: &mut dyn std::io::Write) {\n        match self {\n            Self::ClapCompleteShell(shell) => shell.generate(cmd, buf),\n            Self::Nushell => Nushell.generate(cmd, buf),\n        }\n    }\n}\n"
  },
  {
    "path": "crates/cli/src/handler.rs",
    "content": "use eyre::EyreHandler;\nuse std::{error::Error, fmt};\n\n/// A custom context type for Foundry specific error reporting via `eyre`.\n#[derive(Default)]\npub struct Handler {\n    debug_handler: Option<Box<dyn EyreHandler>>,\n}\n\nimpl Handler {\n    /// Create a new instance of the `Handler`.\n    pub fn new() -> Self {\n        Self::default()\n    }\n\n    /// Override the debug handler with a custom one.\n    pub fn debug_handler(mut self, debug_handler: Option<Box<dyn EyreHandler>>) -> Self {\n        self.debug_handler = debug_handler;\n        self\n    }\n}\n\nimpl EyreHandler for Handler {\n    fn display(&self, error: &(dyn Error + 'static), f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.write_str(&foundry_common::errors::display_chain(error))\n    }\n\n    fn debug(&self, error: &(dyn Error + 'static), f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        if let Some(debug_handler) = &self.debug_handler {\n            return debug_handler.debug(error, f);\n        }\n\n        if f.alternate() {\n            return fmt::Debug::fmt(error, f);\n        }\n        let errors = foundry_common::errors::dedup_chain(error);\n\n        let (error, sources) = errors.split_first().unwrap();\n        write!(f, \"{error}\")?;\n\n        if !sources.is_empty() {\n            write!(f, \"\\n\\nContext:\")?;\n\n            let multiple = sources.len() > 1;\n            for (n, error) in sources.iter().enumerate() {\n                writeln!(f)?;\n                if multiple {\n                    write!(f, \"- Error #{n}: {error}\")?;\n                } else {\n                    write!(f, \"- {error}\")?;\n                }\n            }\n        }\n\n        Ok(())\n    }\n\n    fn track_caller(&mut self, location: &'static std::panic::Location<'static>) {\n        if let Some(debug_handler) = &mut self.debug_handler {\n            debug_handler.track_caller(location);\n        }\n    }\n}\n\n/// Installs the Foundry [`eyre`] and [`panic`](mod@std::panic) hooks as the global ones.\n///\n/// # Details\n///\n/// By default a simple user-centric handler is installed, unless\n/// `FOUNDRY_DEBUG` is set in the environment, in which case a more\n/// verbose debug-centric handler is installed.\n///\n/// Panics are always caught by the more debug-centric handler.\npub fn install() {\n    if std::env::var_os(\"RUST_BACKTRACE\").is_none() {\n        unsafe {\n            std::env::set_var(\"RUST_BACKTRACE\", \"1\");\n        }\n    }\n\n    let panic_section =\n        \"This is a bug. Consider reporting it at https://github.com/foundry-rs/foundry\";\n    let (panic_hook, debug_hook) =\n        color_eyre::config::HookBuilder::default().panic_section(panic_section).into_hooks();\n    panic_hook.install();\n    let debug_hook = debug_hook.into_eyre_hook();\n    let debug = std::env::var_os(\"FOUNDRY_DEBUG\").is_some();\n    if let Err(e) = eyre::set_hook(Box::new(move |e| {\n        Box::new(Handler::new().debug_handler(debug.then(|| debug_hook(e))))\n    })) {\n        debug!(\"failed to install eyre error hook: {e}\");\n    }\n}\n"
  },
  {
    "path": "crates/cli/src/lib.rs",
    "content": "//! # foundry-cli\n//!\n//! Common CLI utilities.\n\n#![cfg_attr(not(test), warn(unused_crate_dependencies))]\n#![cfg_attr(docsrs, feature(doc_cfg))]\n\n#[macro_use]\nextern crate foundry_common;\n\n#[macro_use]\nextern crate tracing;\n\npub mod clap;\npub mod handler;\npub mod opts;\npub mod utils;\n\n#[cfg(feature = \"tracy\")]\ntracing_tracy::client::register_demangler!();\n"
  },
  {
    "path": "crates/cli/src/opts/build/core.rs",
    "content": "use super::ProjectPathOpts;\nuse crate::{opts::CompilerOpts, utils::LoadConfig};\nuse clap::{Parser, ValueHint};\nuse eyre::Result;\nuse foundry_compilers::{\n    Project,\n    artifacts::{RevertStrings, remappings::Remapping},\n    compilers::multi::MultiCompiler,\n    utils::canonicalized,\n};\nuse foundry_config::{\n    Config, DenyLevel, Remappings,\n    figment::{\n        self, Figment, Metadata, Profile, Provider,\n        error::Kind::InvalidType,\n        value::{Dict, Map, Value},\n    },\n    filter::SkipBuildFilter,\n};\nuse serde::Serialize;\nuse std::path::PathBuf;\n\n#[derive(Clone, Debug, Default, Serialize, Parser)]\n#[command(next_help_heading = \"Build options\")]\npub struct BuildOpts {\n    /// Clear the cache and artifacts folder and recompile.\n    #[arg(long, help_heading = \"Cache options\")]\n    #[serde(skip)]\n    pub force: bool,\n\n    /// Disable the cache.\n    #[arg(long)]\n    #[serde(skip)]\n    pub no_cache: bool,\n\n    /// Enable dynamic test linking.\n    #[arg(long, conflicts_with = \"no_cache\")]\n    #[serde(skip)]\n    pub dynamic_test_linking: bool,\n\n    /// Set pre-linked libraries.\n    #[arg(long, help_heading = \"Linker options\", env = \"DAPP_LIBRARIES\")]\n    #[serde(skip_serializing_if = \"Vec::is_empty\")]\n    pub libraries: Vec<String>,\n\n    /// Ignore solc warnings by error code.\n    #[arg(long, help_heading = \"Compiler options\", value_name = \"ERROR_CODES\")]\n    #[serde(skip_serializing_if = \"Vec::is_empty\")]\n    pub ignored_error_codes: Vec<u64>,\n\n    /// A compiler error will be triggered at the specified diagnostic level.\n    ///\n    /// Replaces the deprecated `--deny-warnings` flag.\n    ///\n    /// Possible values:\n    ///  - `never`: Do not treat any diagnostics as errors.\n    ///  - `warnings`: Treat warnings as errors.\n    ///  - `notes`: Treat both, warnings and notes, as errors.\n    #[arg(\n        long,\n        short = 'D',\n        help_heading = \"Compiler options\",\n        value_name = \"LEVEL\",\n        conflicts_with = \"deny_warnings\"\n    )]\n    #[serde(skip)]\n    pub deny: Option<DenyLevel>,\n\n    /// Deprecated: use `--deny=warnings` instead.\n    #[arg(long = \"deny-warnings\", hide = true)]\n    pub deny_warnings: bool,\n\n    /// Do not auto-detect the `solc` version.\n    #[arg(long, help_heading = \"Compiler options\")]\n    #[serde(skip)]\n    pub no_auto_detect: bool,\n\n    /// Specify the solc version, or a path to a local solc, to build with.\n    ///\n    /// Valid values are in the format `x.y.z`, `solc:x.y.z` or `path/to/solc`.\n    #[arg(\n        long = \"use\",\n        alias = \"compiler-version\",\n        help_heading = \"Compiler options\",\n        value_name = \"SOLC_VERSION\"\n    )]\n    #[serde(skip)]\n    pub use_solc: Option<String>,\n\n    /// Do not access the network.\n    ///\n    /// Missing solc versions will not be installed.\n    #[arg(help_heading = \"Compiler options\", long)]\n    #[serde(skip)]\n    pub offline: bool,\n\n    /// Use the Yul intermediate representation compilation pipeline.\n    #[arg(long, help_heading = \"Compiler options\")]\n    #[serde(skip)]\n    pub via_ir: bool,\n\n    /// Changes compilation to only use literal content and not URLs.\n    #[arg(long, help_heading = \"Compiler options\")]\n    #[serde(skip)]\n    pub use_literal_content: bool,\n\n    /// Do not append any metadata to the bytecode.\n    ///\n    /// This is equivalent to setting `bytecode_hash` to `none` and `cbor_metadata` to `false`.\n    #[arg(long, help_heading = \"Compiler options\")]\n    #[serde(skip)]\n    pub no_metadata: bool,\n\n    /// The path to the contract artifacts folder.\n    #[arg(\n        long = \"out\",\n        short,\n        help_heading = \"Project options\",\n        value_hint = ValueHint::DirPath,\n        value_name = \"PATH\",\n    )]\n    #[serde(rename = \"out\", skip_serializing_if = \"Option::is_none\")]\n    pub out_path: Option<PathBuf>,\n\n    /// Revert string configuration.\n    ///\n    /// Possible values are \"default\", \"strip\" (remove),\n    /// \"debug\" (Solidity-generated revert strings) and \"verboseDebug\"\n    #[arg(long, help_heading = \"Project options\", value_name = \"REVERT\")]\n    #[serde(skip)]\n    pub revert_strings: Option<RevertStrings>,\n\n    /// Generate build info files.\n    #[arg(long, help_heading = \"Project options\")]\n    #[serde(skip)]\n    pub build_info: bool,\n\n    /// Output path to directory that build info files will be written to.\n    #[arg(\n        long,\n        help_heading = \"Project options\",\n        value_hint = ValueHint::DirPath,\n        value_name = \"PATH\",\n        requires = \"build_info\",\n    )]\n    #[serde(skip_serializing_if = \"Option::is_none\")]\n    pub build_info_path: Option<PathBuf>,\n\n    /// Skip building files whose names contain the given filter.\n    ///\n    /// `test` and `script` are aliases for `.t.sol` and `.s.sol`.\n    #[arg(long, num_args(1..))]\n    #[serde(skip)]\n    pub skip: Option<Vec<SkipBuildFilter>>,\n\n    #[command(flatten)]\n    #[serde(flatten)]\n    pub compiler: CompilerOpts,\n\n    #[command(flatten)]\n    #[serde(flatten)]\n    pub project_paths: ProjectPathOpts,\n}\n\nimpl BuildOpts {\n    /// Returns the `Project` for the current workspace\n    ///\n    /// This loads the `foundry_config::Config` for the current workspace (see\n    /// `find_project_root` and merges the cli `BuildArgs` into it before returning\n    /// [`foundry_config::Config::project()`]).\n    pub fn project(&self) -> Result<Project<MultiCompiler>> {\n        let config = self.load_config()?;\n        Ok(config.project()?)\n    }\n\n    /// Returns the remappings to add to the config\n    #[deprecated(note = \"Use ProjectPathsArgs::get_remappings() instead\")]\n    pub fn get_remappings(&self) -> Vec<Remapping> {\n        self.project_paths.get_remappings()\n    }\n}\n\n// Loads project's figment and merges the build cli arguments into it\nimpl<'a> From<&'a BuildOpts> for Figment {\n    fn from(args: &'a BuildOpts) -> Self {\n        let root = if let Some(config_path) = &args.project_paths.config_path {\n            if !config_path.exists() {\n                panic!(\"error: config-path `{}` does not exist\", config_path.display())\n            }\n            if !config_path.ends_with(Config::FILE_NAME) {\n                panic!(\"error: the config-path must be a path to a foundry.toml file\")\n            }\n            let config_path = canonicalized(config_path);\n            config_path.parent().unwrap().to_path_buf()\n        } else {\n            args.project_paths.project_root()\n        };\n        let mut figment = Config::figment_with_root(root);\n\n        // remappings should stack\n        let mut remappings = Remappings::new_with_remappings(args.project_paths.get_remappings())\n            .with_figment(&figment);\n        remappings\n            .extend(figment.extract_inner::<Vec<Remapping>>(\"remappings\").unwrap_or_default());\n        figment = figment.merge((\"remappings\", remappings.into_inner())).merge(args);\n\n        if let Some(skip) = &args.skip {\n            let mut skip = skip.iter().map(|s| s.file_pattern().to_string()).collect::<Vec<_>>();\n            skip.extend(figment.extract_inner::<Vec<String>>(\"skip\").unwrap_or_default());\n            figment = figment.merge((\"skip\", skip));\n        };\n\n        figment\n    }\n}\n\nimpl Provider for BuildOpts {\n    fn metadata(&self) -> Metadata {\n        Metadata::named(\"Core Build Args Provider\")\n    }\n\n    fn data(&self) -> Result<Map<Profile, Dict>, figment::Error> {\n        let value = Value::serialize(self)?;\n        let error = InvalidType(value.to_actual(), \"map\".into());\n        let mut dict = value.into_dict().ok_or(error)?;\n\n        if self.no_auto_detect {\n            dict.insert(\"auto_detect_solc\".to_string(), false.into());\n        }\n\n        if let Some(ref solc) = self.use_solc {\n            dict.insert(\"solc\".to_string(), solc.trim_start_matches(\"solc:\").into());\n        }\n\n        if self.offline {\n            dict.insert(\"offline\".to_string(), true.into());\n        }\n\n        if self.deny_warnings {\n            dict.insert(\"deny\".to_string(), figment::value::Value::serialize(DenyLevel::Warnings)?);\n            _ = sh_warn!(\"`--deny-warnings` is being deprecated in favor of `--deny warnings`.\");\n        } else if let Some(deny) = self.deny {\n            dict.insert(\"deny\".to_string(), figment::value::Value::serialize(deny)?);\n        }\n\n        if self.via_ir {\n            dict.insert(\"via_ir\".to_string(), true.into());\n        }\n\n        if self.use_literal_content {\n            dict.insert(\"use_literal_content\".to_string(), true.into());\n        }\n\n        if self.no_metadata {\n            dict.insert(\"bytecode_hash\".to_string(), \"none\".into());\n            dict.insert(\"cbor_metadata\".to_string(), false.into());\n        }\n\n        if self.force {\n            dict.insert(\"force\".to_string(), self.force.into());\n        }\n\n        // we need to ensure no_cache set accordingly\n        if self.no_cache {\n            dict.insert(\"cache\".to_string(), false.into());\n        }\n\n        if self.dynamic_test_linking {\n            dict.insert(\"dynamic_test_linking\".to_string(), true.into());\n        }\n\n        if self.build_info {\n            dict.insert(\"build_info\".to_string(), self.build_info.into());\n        }\n\n        if self.compiler.ast {\n            dict.insert(\"ast\".to_string(), true.into());\n        }\n\n        if let Some(optimize) = self.compiler.optimize {\n            dict.insert(\"optimizer\".to_string(), optimize.into());\n        }\n\n        if !self.compiler.extra_output.is_empty() {\n            let selection: Vec<_> =\n                self.compiler.extra_output.iter().map(|s| s.to_string()).collect();\n            dict.insert(\"extra_output\".to_string(), selection.into());\n        }\n\n        if !self.compiler.extra_output_files.is_empty() {\n            let selection: Vec<_> =\n                self.compiler.extra_output_files.iter().map(|s| s.to_string()).collect();\n            dict.insert(\"extra_output_files\".to_string(), selection.into());\n        }\n\n        if let Some(ref revert) = self.revert_strings {\n            dict.insert(\"revert_strings\".to_string(), revert.to_string().into());\n        }\n\n        Ok(Map::from([(Config::selected_profile(), dict)]))\n    }\n}\n"
  },
  {
    "path": "crates/cli/src/opts/build/mod.rs",
    "content": "use clap::Parser;\nuse foundry_compilers::artifacts::{EvmVersion, output_selection::ContractOutputSelection};\nuse serde::Serialize;\n\nmod core;\npub use self::core::BuildOpts;\n\nmod paths;\npub use self::paths::ProjectPathOpts;\n\nmod utils;\npub use self::utils::*;\n\n// A set of solc compiler settings that can be set via command line arguments, which are intended\n// to be merged into an existing `foundry_config::Config`.\n//\n// See also `BuildArgs`.\n#[derive(Clone, Debug, Default, Serialize, Parser)]\n#[command(next_help_heading = \"Compiler options\")]\npub struct CompilerOpts {\n    /// Includes the AST as JSON in the compiler output.\n    #[arg(long, help_heading = \"Compiler options\")]\n    #[serde(skip)]\n    pub ast: bool,\n\n    /// The target EVM version.\n    #[arg(long, value_name = \"VERSION\")]\n    #[serde(skip_serializing_if = \"Option::is_none\")]\n    pub evm_version: Option<EvmVersion>,\n\n    /// Activate the Solidity optimizer.\n    #[arg(long, default_missing_value=\"true\", num_args = 0..=1)]\n    #[serde(skip)]\n    pub optimize: Option<bool>,\n\n    /// The number of runs specifies roughly how often each opcode of the deployed code will be\n    /// executed across the life-time of the contract. This means it is a trade-off parameter\n    /// between code size (deploy cost) and code execution cost (cost after deployment).\n    /// An `optimizer_runs` parameter of `1` will produce short but expensive code. In contrast, a\n    /// larger `optimizer_runs` parameter will produce longer but more gas efficient code.\n    #[arg(long, value_name = \"RUNS\")]\n    #[serde(skip_serializing_if = \"Option::is_none\")]\n    pub optimizer_runs: Option<usize>,\n\n    /// Extra output to include in the contract's artifact.\n    ///\n    /// Example keys: evm.assembly, ewasm, ir, irOptimized, metadata\n    ///\n    /// For a full description, see <https://docs.soliditylang.org/en/v0.8.13/using-the-compiler.html#input-description>\n    #[arg(long, num_args(1..), value_name = \"SELECTOR\")]\n    #[serde(skip_serializing_if = \"Vec::is_empty\")]\n    pub extra_output: Vec<ContractOutputSelection>,\n\n    /// Extra output to write to separate files.\n    ///\n    /// Valid values: metadata, ir, irOptimized, ewasm, evm.assembly\n    #[arg(long, num_args(1..), value_name = \"SELECTOR\")]\n    #[serde(skip_serializing_if = \"Vec::is_empty\")]\n    pub extra_output_files: Vec<ContractOutputSelection>,\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn can_parse_evm_version() {\n        let args: CompilerOpts =\n            CompilerOpts::parse_from([\"foundry-cli\", \"--evm-version\", \"london\"]);\n        assert_eq!(args.evm_version, Some(EvmVersion::London));\n    }\n\n    #[test]\n    fn can_parse_extra_output() {\n        let args: CompilerOpts =\n            CompilerOpts::parse_from([\"foundry-cli\", \"--extra-output\", \"metadata\", \"ir-optimized\"]);\n        assert_eq!(\n            args.extra_output,\n            vec![ContractOutputSelection::Metadata, ContractOutputSelection::IrOptimized]\n        );\n    }\n\n    #[test]\n    fn can_parse_extra_output_files() {\n        let args: CompilerOpts = CompilerOpts::parse_from([\n            \"foundry-cli\",\n            \"--extra-output-files\",\n            \"metadata\",\n            \"ir-optimized\",\n        ]);\n        assert_eq!(\n            args.extra_output_files,\n            vec![ContractOutputSelection::Metadata, ContractOutputSelection::IrOptimized]\n        );\n    }\n}\n"
  },
  {
    "path": "crates/cli/src/opts/build/paths.rs",
    "content": "use clap::{Parser, ValueHint};\nuse eyre::Result;\nuse foundry_compilers::artifacts::remappings::Remapping;\nuse foundry_config::{\n    Config, figment,\n    figment::{\n        Metadata, Profile, Provider,\n        error::Kind::InvalidType,\n        value::{Dict, Map, Value},\n    },\n    find_project_root, remappings_from_env_var,\n};\nuse serde::Serialize;\nuse std::path::PathBuf;\n\n/// Common arguments for a project's paths.\n#[derive(Clone, Debug, Default, Serialize, Parser)]\n#[command(next_help_heading = \"Project options\")]\npub struct ProjectPathOpts {\n    /// The project's root path.\n    ///\n    /// By default root of the Git repository, if in one,\n    /// or the current working directory.\n    #[arg(long, value_hint = ValueHint::DirPath, value_name = \"PATH\")]\n    #[serde(skip)]\n    pub root: Option<PathBuf>,\n\n    /// The contracts source directory.\n    #[arg(long, short = 'C', value_hint = ValueHint::DirPath, value_name = \"PATH\")]\n    #[serde(rename = \"src\", skip_serializing_if = \"Option::is_none\")]\n    pub contracts: Option<PathBuf>,\n\n    /// The project's remappings.\n    #[arg(long, short = 'R')]\n    #[serde(skip)]\n    pub remappings: Vec<Remapping>,\n\n    /// The project's remappings from the environment.\n    #[arg(long, value_name = \"ENV\")]\n    #[serde(skip)]\n    pub remappings_env: Option<String>,\n\n    /// The path to the compiler cache.\n    #[arg(long, value_hint = ValueHint::DirPath, value_name = \"PATH\")]\n    #[serde(skip_serializing_if = \"Option::is_none\")]\n    pub cache_path: Option<PathBuf>,\n\n    /// The path to the library folder.\n    #[arg(long, value_hint = ValueHint::DirPath, value_name = \"PATH\")]\n    #[serde(rename = \"libs\", skip_serializing_if = \"Vec::is_empty\")]\n    pub lib_paths: Vec<PathBuf>,\n\n    /// Use the Hardhat-style project layout.\n    ///\n    /// This is the same as using: `--contracts contracts --lib-paths node_modules`.\n    #[arg(long, conflicts_with = \"contracts\", visible_alias = \"hh\")]\n    #[serde(skip)]\n    pub hardhat: bool,\n\n    /// Path to the config file.\n    #[arg(long, value_hint = ValueHint::FilePath, value_name = \"FILE\")]\n    #[serde(skip)]\n    pub config_path: Option<PathBuf>,\n}\n\nimpl ProjectPathOpts {\n    /// Returns the root directory to use for configuring the project.\n    ///\n    /// This will be the `--root` argument if provided, otherwise see [`find_project_root`].\n    ///\n    /// # Panics\n    ///\n    /// Panics if the project root directory cannot be found. See [`find_project_root`].\n    #[track_caller]\n    pub fn project_root(&self) -> PathBuf {\n        self.root\n            .clone()\n            .unwrap_or_else(|| find_project_root(None).expect(\"could not determine project root\"))\n    }\n\n    /// Returns the remappings to add to the config\n    pub fn get_remappings(&self) -> Vec<Remapping> {\n        let mut remappings = self.remappings.clone();\n        if let Some(env_remappings) =\n            self.remappings_env.as_ref().and_then(|env| remappings_from_env_var(env))\n        {\n            remappings.extend(env_remappings.expect(\"Failed to parse env var remappings\"));\n        }\n        remappings\n    }\n}\n\nfoundry_config::impl_figment_convert!(ProjectPathOpts);\n\n// Make this args a `figment::Provider` so that it can be merged into the `Config`\nimpl Provider for ProjectPathOpts {\n    fn metadata(&self) -> Metadata {\n        Metadata::named(\"Project Paths Args Provider\")\n    }\n\n    fn data(&self) -> Result<Map<Profile, Dict>, figment::Error> {\n        let value = Value::serialize(self)?;\n        let error = InvalidType(value.to_actual(), \"map\".into());\n        let mut dict = value.into_dict().ok_or(error)?;\n\n        let mut libs =\n            self.lib_paths.iter().map(|p| format!(\"{}\", p.display())).collect::<Vec<_>>();\n\n        if self.hardhat {\n            dict.insert(\"src\".to_string(), \"contracts\".to_string().into());\n            libs.push(\"node_modules\".to_string());\n        }\n\n        if !libs.is_empty() {\n            dict.insert(\"libs\".to_string(), libs.into());\n        }\n\n        Ok(Map::from([(Config::selected_profile(), dict)]))\n    }\n}\n"
  },
  {
    "path": "crates/cli/src/opts/build/utils.rs",
    "content": "use eyre::Result;\nuse foundry_compilers::{\n    CompilerInput, Graph, Project, ProjectCompileOutput, ProjectPathsConfig,\n    artifacts::{Source, Sources},\n    multi::{MultiCompilerLanguage, MultiCompilerParser},\n    solc::{SOLC_EXTENSIONS, SolcLanguage, SolcVersionedInput},\n};\nuse foundry_config::Config;\nuse rayon::prelude::*;\nuse solar::{interface::MIN_SOLIDITY_VERSION, sema::ParsingContext};\nuse std::{\n    collections::{HashSet, VecDeque},\n    path::{Path, PathBuf},\n};\n\n/// Configures a [`ParsingContext`] from [`Config`].\n///\n/// - Configures include paths, remappings\n/// - Source files are added if `add_source_file` is set\n/// - If no `project` is provided, it will spin up a new ephemeral project.\n/// - If no `target_paths` are provided, all project files are processed.\n/// - Only processes the subset of sources with the most up-to-date Solidity version.\npub fn configure_pcx(\n    pcx: &mut ParsingContext<'_>,\n    config: &Config,\n    project: Option<&Project>,\n    target_paths: Option<&[PathBuf]>,\n) -> Result<()> {\n    // Process build options\n    let project = match project {\n        Some(project) => project,\n        None => &config.ephemeral_project()?,\n    };\n\n    let sources = match target_paths {\n        // If target files are provided, only process those sources\n        Some(targets) => {\n            let mut sources = Sources::new();\n            for t in targets {\n                let path = dunce::canonicalize(t)?;\n                let source = Source::read(&path)?;\n                sources.insert(path, source);\n            }\n            sources\n        }\n        // Otherwise, process all project files\n        None => project.paths.read_input_files()?,\n    };\n\n    // Only process sources with latest Solidity version to avoid conflicts.\n    let graph = Graph::<MultiCompilerParser>::resolve_sources(&project.paths, sources)?;\n    let (version, sources) = graph\n        // Resolve graph into mapping language -> version -> sources\n        .into_sources_by_version(project)?\n        .sources\n        .into_iter()\n        // Only interested in Solidity sources\n        .find(|(lang, _)| *lang == MultiCompilerLanguage::Solc(SolcLanguage::Solidity))\n        .ok_or_else(|| eyre::eyre!(\"no Solidity sources\"))?\n        .1\n        .into_iter()\n        // Filter unsupported versions\n        .filter(|(v, _, _)| v >= &MIN_SOLIDITY_VERSION)\n        // Always pick the latest version\n        .max_by(|(v1, _, _), (v2, _, _)| v1.cmp(v2))\n        .map_or((MIN_SOLIDITY_VERSION, Sources::default()), |(v, s, _)| (v, s));\n\n    if sources.is_empty() {\n        sh_warn!(\"no files found. Solar doesn't support Solidity versions prior to 0.8.0\")?;\n    }\n\n    let solc = SolcVersionedInput::build(\n        sources,\n        config.solc_settings()?,\n        SolcLanguage::Solidity,\n        version,\n    );\n\n    configure_pcx_from_solc(pcx, &project.paths, &solc, true);\n\n    Ok(())\n}\n\n/// Extracts Solar-compatible sources from a [`ProjectCompileOutput`].\n///\n/// # Note:\n/// uses `output.graph().source_files()` and `output.artifact_ids()` rather than `output.sources()`\n/// because sources aren't populated when build is skipped when there are no changes in the source\n/// code. <https://github.com/foundry-rs/foundry/issues/12018>\npub fn get_solar_sources_from_compile_output(\n    config: &Config,\n    output: &ProjectCompileOutput,\n    target_paths: Option<&[PathBuf]>,\n    ignored_paths: Option<&[PathBuf]>,\n) -> Result<SolcVersionedInput> {\n    let is_solidity_file = |path: &Path| -> bool {\n        path.extension().and_then(|s| s.to_str()).is_some_and(|ext| SOLC_EXTENSIONS.contains(&ext))\n    };\n\n    let is_ignored = |path: &Path| -> bool {\n        if let Some(ignored) = ignored_paths {\n            ignored.iter().any(|ignored_path| path == ignored_path)\n        } else {\n            false\n        }\n    };\n\n    // Collect source path targets\n    let mut source_paths: HashSet<PathBuf> = if let Some(targets) = target_paths\n        && !targets.is_empty()\n    {\n        let mut source_paths = HashSet::new();\n        let mut queue: VecDeque<PathBuf> = targets\n            .iter()\n            .filter_map(|path| {\n                is_solidity_file(path).then(|| dunce::canonicalize(path).ok()).flatten()\n            })\n            .collect();\n\n        while let Some(path) = queue.pop_front() {\n            if source_paths.insert(path.clone()) {\n                for import in output.graph().imports(path.as_path()) {\n                    // Skip ignored imports to prevent solar from trying to compile them\n                    if !is_ignored(import) {\n                        queue.push_back(import.to_path_buf());\n                    }\n                }\n            }\n        }\n\n        source_paths\n    } else {\n        output\n            .graph()\n            .source_files()\n            .filter_map(|idx| {\n                let path = output.graph().node_path(idx).to_path_buf();\n                is_solidity_file(&path).then_some(path)\n            })\n            .collect()\n    };\n\n    // Read all sources and find the latest version.\n    let (version, sources) = {\n        let (mut max_version, mut sources) = (MIN_SOLIDITY_VERSION, Sources::new());\n        for (id, _) in output.artifact_ids() {\n            if let Ok(path) = dunce::canonicalize(&id.source)\n                && source_paths.remove(&path)\n            {\n                if id.version < MIN_SOLIDITY_VERSION {\n                    continue;\n                } else if max_version < id.version {\n                    max_version = id.version;\n                };\n\n                let source = Source::read(&path)?;\n                sources.insert(path, source);\n            }\n        }\n\n        (max_version, sources)\n    };\n\n    let solc = SolcVersionedInput::build(\n        sources,\n        config.solc_settings()?,\n        SolcLanguage::Solidity,\n        version,\n    );\n\n    Ok(solc)\n}\n\n/// Configures a [`ParsingContext`] from a [`ProjectCompileOutput`].\npub fn configure_pcx_from_compile_output(\n    pcx: &mut ParsingContext<'_>,\n    config: &Config,\n    output: &ProjectCompileOutput,\n    target_paths: Option<&[PathBuf]>,\n) -> Result<()> {\n    let solc = get_solar_sources_from_compile_output(config, output, target_paths, None)?;\n    configure_pcx_from_solc(pcx, &config.project_paths(), &solc, true);\n    Ok(())\n}\n\n/// Configures a [`ParsingContext`] from [`ProjectPathsConfig`] and [`SolcVersionedInput`].\n///\n/// - Configures include paths, remappings.\n/// - Source files are added if `add_source_file` is set\npub fn configure_pcx_from_solc(\n    pcx: &mut ParsingContext<'_>,\n    project_paths: &ProjectPathsConfig,\n    vinput: &SolcVersionedInput,\n    add_source_files: bool,\n) {\n    configure_pcx_from_solc_cli(pcx, project_paths, &vinput.cli_settings);\n    if add_source_files {\n        let sources = vinput\n            .input\n            .sources\n            .par_iter()\n            .filter_map(|(path, source)| {\n                pcx.sess.source_map().new_source_file(path.clone(), source.content.as_str()).ok()\n            })\n            .collect::<Vec<_>>();\n        pcx.add_files(sources);\n    }\n}\n\nfn configure_pcx_from_solc_cli(\n    pcx: &mut ParsingContext<'_>,\n    project_paths: &ProjectPathsConfig,\n    cli_settings: &foundry_compilers::solc::CliSettings,\n) {\n    pcx.file_resolver\n        .set_current_dir(cli_settings.base_path.as_ref().unwrap_or(&project_paths.root));\n    for remapping in &project_paths.remappings {\n        pcx.file_resolver.add_import_remapping(solar::sema::interface::config::ImportRemapping {\n            context: remapping.context.clone().unwrap_or_default(),\n            prefix: remapping.name.clone(),\n            path: remapping.path.clone(),\n        });\n    }\n    pcx.file_resolver.add_include_paths(cli_settings.include_paths.iter().cloned());\n}\n"
  },
  {
    "path": "crates/cli/src/opts/chain.rs",
    "content": "use clap::builder::{PossibleValuesParser, TypedValueParser};\nuse eyre::Result;\nuse foundry_config::{Chain, NamedChain};\nuse std::ffi::OsStr;\nuse strum::VariantNames;\n\n/// Custom Clap value parser for [`Chain`]s.\n///\n/// Displays all possible chains when an invalid chain is provided.\n#[derive(Clone, Debug)]\npub struct ChainValueParser {\n    pub inner: PossibleValuesParser,\n}\n\nimpl Default for ChainValueParser {\n    fn default() -> Self {\n        Self { inner: PossibleValuesParser::from(NamedChain::VARIANTS) }\n    }\n}\n\nimpl TypedValueParser for ChainValueParser {\n    type Value = Chain;\n\n    fn parse_ref(\n        &self,\n        cmd: &clap::Command,\n        arg: Option<&clap::Arg>,\n        value: &OsStr,\n    ) -> Result<Self::Value, clap::Error> {\n        let s =\n            value.to_str().ok_or_else(|| clap::Error::new(clap::error::ErrorKind::InvalidUtf8))?;\n        if let Ok(id) = s.parse() {\n            Ok(Chain::from_id(id))\n        } else {\n            // NamedChain::VARIANTS is a subset of all possible variants, since there are aliases:\n            // amoy instead of polygon-amoy etc\n            //\n            // Parse first as NamedChain, if it fails parse with NamedChain::VARIANTS for displaying\n            // the error to the user\n            s.parse()\n                .map_err(|_| self.inner.parse_ref(cmd, arg, value).unwrap_err())\n                .map(Chain::from_named)\n        }\n    }\n}\n"
  },
  {
    "path": "crates/cli/src/opts/dependency.rs",
    "content": "//! CLI dependency parsing\n\nuse eyre::Result;\nuse regex::Regex;\nuse std::{str::FromStr, sync::LazyLock};\n\nstatic GH_REPO_REGEX: LazyLock<Regex> = LazyLock::new(|| Regex::new(r\"[\\w-]+/[\\w.-]+\").unwrap());\n\n/// Git repo prefix regex\npub static GH_REPO_PREFIX_REGEX: LazyLock<Regex> = LazyLock::new(|| {\n    Regex::new(r\"((git@)|(git\\+https://)|(https://)|https://(?P<token>[^@]+)@|(org-([A-Za-z0-9-])+@))?(?P<brand>[A-Za-z0-9-]+)\\.(?P<tld>[A-Za-z0-9-]+)(/|:)\")\n        .unwrap()\n});\n\nstatic VERSION_PREFIX_REGEX: LazyLock<Regex> =\n    LazyLock::new(|| Regex::new(r#\"@(tag|branch|rev)=\"#).unwrap());\n\nconst GITHUB: &str = \"github.com\";\nconst VERSION_SEPARATOR: char = '@';\nconst ALIAS_SEPARATOR: char = '=';\n\n/// Commonly used aliases for solidity repos,\n///\n/// These will be autocorrected when used in place of the `org`\nconst COMMON_ORG_ALIASES: &[(&str, &str); 2] =\n    &[(\"@openzeppelin\", \"openzeppelin\"), (\"@aave\", \"aave\")];\n\n/// A git dependency which will be installed as a submodule\n///\n/// A dependency can be provided as a raw URL, or as a path to a Github repository\n/// e.g. `org-name/repo-name`\n///\n/// Providing a ref can be done in the following 3 ways:\n/// * branch: master\n/// * tag: v0.1.1\n/// * commit: 8e8128\n///\n/// Non Github URLs must be provided with an https:// prefix.\n/// Adding dependencies as local paths is not supported yet.\n#[derive(Clone, Debug, PartialEq, Eq)]\npub struct Dependency {\n    /// The name of the dependency\n    pub name: String,\n    /// The url to the git repository corresponding to the dependency\n    pub url: Option<String>,\n    /// Optional tag corresponding to a Git SHA, tag, or branch.\n    pub tag: Option<String>,\n    /// Optional alias of the dependency\n    pub alias: Option<String>,\n}\n\nimpl FromStr for Dependency {\n    type Err = eyre::Error;\n    fn from_str(dependency: &str) -> Result<Self, Self::Err> {\n        // Handle dependency exact ref type (`@tag=`, `@branch=` or `@rev=`)`.\n        // Only extract version for first tag/branch/commit specified.\n        let url_and_version: Vec<&str> = VERSION_PREFIX_REGEX.split(dependency).collect();\n        let dependency = url_and_version[0];\n        let mut tag_or_branch = url_and_version.get(1).map(|version| version.to_string());\n\n        // everything before \"=\" should be considered the alias\n        let (mut alias, dependency) = if let Some(split) = dependency.split_once(ALIAS_SEPARATOR) {\n            (Some(String::from(split.0)), split.1.to_string())\n        } else {\n            let mut dependency = dependency.to_string();\n            // this will autocorrect wrong conventional aliases for tag, but only autocorrect if\n            // it's not used as alias\n            for (alias, real_org) in COMMON_ORG_ALIASES {\n                if dependency.starts_with(alias) {\n                    dependency = dependency.replacen(alias, real_org, 1);\n                    break;\n                }\n            }\n\n            (None, dependency)\n        };\n\n        let dependency = dependency.as_str();\n\n        let url_with_version = if let Some(captures) = GH_REPO_PREFIX_REGEX.captures(dependency) {\n            let brand = captures.name(\"brand\").unwrap().as_str();\n            let tld = captures.name(\"tld\").unwrap().as_str();\n            let project = GH_REPO_PREFIX_REGEX.replace(dependency, \"\");\n            if let Some(token) = captures.name(\"token\") {\n                Some(format!(\n                    \"https://{}@{brand}.{tld}/{}\",\n                    token.as_str(),\n                    project.trim_end_matches(\".git\")\n                ))\n            } else if dependency.starts_with(\"git@\") {\n                Some(format!(\"git@{brand}.{tld}:{}\", project.trim_end_matches(\".git\")))\n            } else {\n                Some(format!(\"https://{brand}.{tld}/{}\", project.trim_end_matches(\".git\")))\n            }\n        } else {\n            // If we don't have a URL and we don't have a valid\n            // GitHub repository name, then we assume this is the alias.\n            //\n            // This is to allow for conveniently removing aliased dependencies\n            // using `forge remove <alias>`\n            if GH_REPO_REGEX.is_match(dependency) {\n                Some(format!(\"https://{GITHUB}/{dependency}\"))\n            } else {\n                alias = Some(dependency.to_string());\n                None\n            }\n        };\n\n        // everything after the last \"@\" should be considered the version if there are no path\n        // segments\n        let (url, name, tag) = if let Some(url_with_version) = url_with_version {\n            // `@`s are actually valid github project name chars but we assume this is unlikely and\n            // treat everything after the last `@` as the version tag there's still the\n            // case that the user tries to use `@<org>/<project>`, so we need to check that the\n            // `tag` does not contain a slash\n            let mut split = url_with_version.rsplit(VERSION_SEPARATOR);\n\n            let mut url = url_with_version.as_str();\n\n            if tag_or_branch.is_none() {\n                let maybe_tag_or_branch = split.next().unwrap();\n                if let Some(actual_url) = split.next()\n                    && !maybe_tag_or_branch.contains('/')\n                {\n                    tag_or_branch = Some(maybe_tag_or_branch.to_string());\n                    url = actual_url;\n                }\n            }\n\n            let url = url.to_string();\n            let name = url\n                .split('/')\n                .next_back()\n                .ok_or_else(|| eyre::eyre!(\"no dependency name found\"))?\n                .to_string();\n\n            (Some(url), Some(name), tag_or_branch)\n        } else {\n            (None, None, None)\n        };\n\n        Ok(Self { name: name.or_else(|| alias.clone()).unwrap(), url, tag, alias })\n    }\n}\n\nimpl Dependency {\n    /// Returns the name of the dependency, prioritizing the alias if it exists.\n    pub fn name(&self) -> &str {\n        self.alias.as_deref().unwrap_or(self.name.as_str())\n    }\n\n    /// Returns the URL of the dependency if it exists, or an error if not.\n    pub fn require_url(&self) -> Result<&str> {\n        self.url.as_deref().ok_or_else(|| eyre::eyre!(\"dependency {} has no url\", self.name()))\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use foundry_compilers::info::ContractInfo;\n\n    #[test]\n    fn parses_dependencies() {\n        [\n            (\"gakonst/lootloose\", \"https://github.com/gakonst/lootloose\", None, None),\n            (\"github.com/gakonst/lootloose\", \"https://github.com/gakonst/lootloose\", None, None),\n            (\n                \"https://github.com/gakonst/lootloose\",\n                \"https://github.com/gakonst/lootloose\",\n                None,\n                None,\n            ),\n            (\n                \"git+https://github.com/gakonst/lootloose\",\n                \"https://github.com/gakonst/lootloose\",\n                None,\n                None,\n            ),\n            (\n                \"git@github.com:gakonst/lootloose@tag=v1\",\n                \"git@github.com:gakonst/lootloose\",\n                Some(\"v1\"),\n                None,\n            ),\n            (\"git@github.com:gakonst/lootloose\", \"git@github.com:gakonst/lootloose\", None, None),\n            (\n                \"https://gitlab.com/gakonst/lootloose\",\n                \"https://gitlab.com/gakonst/lootloose\",\n                None,\n                None,\n            ),\n            (\n                \"https://github.xyz/gakonst/lootloose\",\n                \"https://github.xyz/gakonst/lootloose\",\n                None,\n                None,\n            ),\n            (\n                \"gakonst/lootloose@0.1.0\",\n                \"https://github.com/gakonst/lootloose\",\n                Some(\"0.1.0\"),\n                None,\n            ),\n            (\n                \"gakonst/lootloose@develop\",\n                \"https://github.com/gakonst/lootloose\",\n                Some(\"develop\"),\n                None,\n            ),\n            (\n                \"gakonst/lootloose@98369d0edc900c71d0ec33a01dfba1d92111deed\",\n                \"https://github.com/gakonst/lootloose\",\n                Some(\"98369d0edc900c71d0ec33a01dfba1d92111deed\"),\n                None,\n            ),\n            (\"loot=gakonst/lootloose\", \"https://github.com/gakonst/lootloose\", None, Some(\"loot\")),\n            (\n                \"loot=github.com/gakonst/lootloose\",\n                \"https://github.com/gakonst/lootloose\",\n                None,\n                Some(\"loot\"),\n            ),\n            (\n                \"loot=https://github.com/gakonst/lootloose\",\n                \"https://github.com/gakonst/lootloose\",\n                None,\n                Some(\"loot\"),\n            ),\n            (\n                \"loot=git+https://github.com/gakonst/lootloose\",\n                \"https://github.com/gakonst/lootloose\",\n                None,\n                Some(\"loot\"),\n            ),\n            (\n                \"loot=git@github.com:gakonst/lootloose@tag=v1\",\n                \"git@github.com:gakonst/lootloose\",\n                Some(\"v1\"),\n                Some(\"loot\"),\n            ),\n        ]\n        .iter()\n        .for_each(|(input, expected_path, expected_tag, expected_alias)| {\n            let dep = Dependency::from_str(input).unwrap();\n            assert_eq!(dep.url, Some(expected_path.to_string()));\n            assert_eq!(dep.tag, expected_tag.map(ToString::to_string));\n            assert_eq!(dep.name, \"lootloose\");\n            assert_eq!(dep.alias, expected_alias.map(ToString::to_string));\n        });\n    }\n\n    #[test]\n    fn can_parse_alias_only() {\n        let dep = Dependency::from_str(\"foo\").unwrap();\n        assert_eq!(dep.name, \"foo\");\n        assert_eq!(dep.url, None);\n        assert_eq!(dep.tag, None);\n        assert_eq!(dep.alias, Some(\"foo\".to_string()));\n    }\n\n    #[test]\n    fn test_invalid_github_repo_dependency() {\n        let dep = Dependency::from_str(\"solmate\").unwrap();\n        assert_eq!(dep.url, None);\n    }\n\n    #[test]\n    fn parses_contract_info() {\n        [\n            (\n                \"src/contracts/Contracts.sol:Contract\",\n                Some(\"src/contracts/Contracts.sol\"),\n                \"Contract\",\n            ),\n            (\"Contract\", None, \"Contract\"),\n        ]\n        .iter()\n        .for_each(|(input, expected_path, expected_name)| {\n            let contract = ContractInfo::from_str(input).unwrap();\n            assert_eq!(contract.path, expected_path.map(ToString::to_string));\n            assert_eq!(contract.name, expected_name.to_string());\n        });\n    }\n\n    #[test]\n    fn contract_info_should_reject_without_name() {\n        [\"src/contracts/\", \"src/contracts/Contracts.sol\"].iter().for_each(|input| {\n            let contract = ContractInfo::from_str(input);\n            assert!(contract.is_err())\n        });\n    }\n\n    #[test]\n    fn can_parse_oz_dep() {\n        let dep = Dependency::from_str(\"@openzeppelin/contracts-upgradeable\").unwrap();\n        assert_eq!(dep.name, \"contracts-upgradeable\");\n        assert_eq!(\n            dep.url,\n            Some(\"https://github.com/openzeppelin/contracts-upgradeable\".to_string())\n        );\n        assert_eq!(dep.tag, None);\n        assert_eq!(dep.alias, None);\n    }\n\n    #[test]\n    fn can_parse_oz_dep_tag() {\n        let dep = Dependency::from_str(\"@openzeppelin/contracts-upgradeable@v1\").unwrap();\n        assert_eq!(dep.name, \"contracts-upgradeable\");\n        assert_eq!(\n            dep.url,\n            Some(\"https://github.com/openzeppelin/contracts-upgradeable\".to_string())\n        );\n        assert_eq!(dep.tag, Some(\"v1\".to_string()));\n        assert_eq!(dep.alias, None);\n    }\n\n    #[test]\n    fn can_parse_oz_with_tag() {\n        let dep = Dependency::from_str(\"OpenZeppelin/openzeppelin-contracts@v4.7.0\").unwrap();\n        assert_eq!(dep.name, \"openzeppelin-contracts\");\n        assert_eq!(\n            dep.url,\n            Some(\"https://github.com/OpenZeppelin/openzeppelin-contracts\".to_string())\n        );\n        assert_eq!(dep.tag, Some(\"v4.7.0\".to_string()));\n        assert_eq!(dep.alias, None);\n\n        let dep = Dependency::from_str(\"OpenZeppelin/openzeppelin-contracts@4.7.0\").unwrap();\n        assert_eq!(dep.name, \"openzeppelin-contracts\");\n        assert_eq!(\n            dep.url,\n            Some(\"https://github.com/OpenZeppelin/openzeppelin-contracts\".to_string())\n        );\n        assert_eq!(dep.tag, Some(\"4.7.0\".to_string()));\n        assert_eq!(dep.alias, None);\n    }\n\n    // <https://github.com/foundry-rs/foundry/pull/3130>\n    #[test]\n    fn can_parse_oz_with_alias() {\n        let dep =\n            Dependency::from_str(\"@openzeppelin=OpenZeppelin/openzeppelin-contracts\").unwrap();\n        assert_eq!(dep.name, \"openzeppelin-contracts\");\n        assert_eq!(dep.alias, Some(\"@openzeppelin\".to_string()));\n        assert_eq!(\n            dep.url,\n            Some(\"https://github.com/OpenZeppelin/openzeppelin-contracts\".to_string())\n        );\n    }\n\n    #[test]\n    fn can_parse_aave() {\n        let dep = Dependency::from_str(\"@aave/aave-v3-core\").unwrap();\n        assert_eq!(dep.name, \"aave-v3-core\");\n        assert_eq!(dep.url, Some(\"https://github.com/aave/aave-v3-core\".to_string()));\n    }\n\n    #[test]\n    fn can_parse_aave_with_alias() {\n        let dep = Dependency::from_str(\"@aave=aave/aave-v3-core\").unwrap();\n        assert_eq!(dep.name, \"aave-v3-core\");\n        assert_eq!(dep.alias, Some(\"@aave\".to_string()));\n        assert_eq!(dep.url, Some(\"https://github.com/aave/aave-v3-core\".to_string()));\n    }\n\n    #[test]\n    fn can_parse_org_ssh_url() {\n        let org_url = \"org-git12345678@github.com:my-org/my-repo.git\";\n        assert!(GH_REPO_PREFIX_REGEX.is_match(org_url));\n    }\n\n    #[test]\n    fn can_parse_org_shh_url_dependency() {\n        let dep: Dependency = \"org-git12345678@github.com:my-org/my-repo.git\".parse().unwrap();\n        assert_eq!(dep.url.unwrap(), \"https://github.com/my-org/my-repo\");\n    }\n\n    #[test]\n    fn can_parse_with_explicit_ref_type() {\n        let dep = Dependency::from_str(\"smartcontractkit/ccip@tag=contracts-ccip/v1.2.1\").unwrap();\n        assert_eq!(dep.name, \"ccip\");\n        assert_eq!(dep.url, Some(\"https://github.com/smartcontractkit/ccip\".to_string()));\n        assert_eq!(dep.tag, Some(\"contracts-ccip/v1.2.1\".to_string()));\n        assert_eq!(dep.alias, None);\n\n        let dep =\n            Dependency::from_str(\"smartcontractkit/ccip@branch=contracts-ccip/v1.2.1\").unwrap();\n        assert_eq!(dep.name, \"ccip\");\n        assert_eq!(dep.url, Some(\"https://github.com/smartcontractkit/ccip\".to_string()));\n        assert_eq!(dep.tag, Some(\"contracts-ccip/v1.2.1\".to_string()));\n        assert_eq!(dep.alias, None);\n\n        let dep = Dependency::from_str(\"smartcontractkit/ccip@rev=80eb41b\").unwrap();\n        assert_eq!(dep.name, \"ccip\");\n        assert_eq!(dep.url, Some(\"https://github.com/smartcontractkit/ccip\".to_string()));\n        assert_eq!(dep.tag, Some(\"80eb41b\".to_string()));\n        assert_eq!(dep.alias, None);\n    }\n\n    #[test]\n    fn can_parse_https_with_github_token() {\n        // <https://github.com/foundry-rs/foundry/issues/9717>\n        let dep = Dependency::from_str(\n            \"https://ghp_mytoken@github.com/private-org/precompiles-solidity.git\",\n        )\n        .unwrap();\n        assert_eq!(dep.name, \"precompiles-solidity\");\n        assert_eq!(\n            dep.url,\n            Some(\"https://ghp_mytoken@github.com/private-org/precompiles-solidity\".to_string())\n        );\n    }\n}\n"
  },
  {
    "path": "crates/cli/src/opts/evm.rs",
    "content": "//! CLI arguments for configuring the EVM settings.\n\nuse alloy_primitives::{Address, B256, U256};\nuse clap::Parser;\nuse foundry_config::{\n    Chain, Config,\n    figment::{\n        self, Metadata, Profile, Provider,\n        error::Kind::InvalidType,\n        value::{Dict, Map, Value},\n    },\n};\nuse serde::Serialize;\n\nuse foundry_common::shell;\n\n/// `EvmArgs` and `EnvArgs` take the highest precedence in the Config/Figment hierarchy.\n///\n/// All vars are opt-in, their default values are expected to be set by the\n/// [`foundry_config::Config`], and are always present ([`foundry_config::Config::default`])\n///\n/// Both have corresponding types in the `evm_adapters` crate which have mandatory fields.\n/// The expected workflow is\n///   1. load the [`foundry_config::Config`]\n///   2. merge with `EvmArgs` into a `figment::Figment`\n///   3. extract `evm_adapters::Opts` from the merged `Figment`\n///\n/// # Example\n///\n/// ```ignore\n/// use foundry_config::Config;\n/// use forge::executor::opts::EvmOpts;\n/// use foundry_cli::opts::EvmArgs;\n/// # fn t(args: EvmArgs) {\n/// let figment = Config::figment_with_root(\".\").merge(args);\n/// let opts = figment.extract::<EvmOpts>().unwrap();\n/// # }\n/// ```\n#[derive(Clone, Debug, Default, Serialize, Parser)]\n#[command(next_help_heading = \"EVM options\", about = None, long_about = None)] // override doc\npub struct EvmArgs {\n    /// Fetch state over a remote endpoint instead of starting from an empty state.\n    ///\n    /// If you want to fetch state from a specific block number, see --fork-block-number.\n    #[arg(long, short, visible_alias = \"rpc-url\", value_name = \"URL\")]\n    #[serde(rename = \"eth_rpc_url\", skip_serializing_if = \"Option::is_none\")]\n    pub fork_url: Option<String>,\n\n    /// Fetch state from a specific block number over a remote endpoint.\n    ///\n    /// See --fork-url.\n    #[arg(long, requires = \"fork_url\", value_name = \"BLOCK\")]\n    #[serde(skip_serializing_if = \"Option::is_none\")]\n    pub fork_block_number: Option<u64>,\n\n    /// Number of retries.\n    ///\n    /// See --fork-url.\n    #[arg(long, requires = \"fork_url\", value_name = \"RETRIES\")]\n    #[serde(skip_serializing_if = \"Option::is_none\")]\n    pub fork_retries: Option<u32>,\n\n    /// Initial retry backoff on encountering errors.\n    ///\n    /// See --fork-url.\n    #[arg(long, requires = \"fork_url\", value_name = \"BACKOFF\")]\n    #[serde(skip_serializing_if = \"Option::is_none\")]\n    pub fork_retry_backoff: Option<u64>,\n\n    /// Explicitly disables the use of RPC caching.\n    ///\n    /// All storage slots are read entirely from the endpoint.\n    ///\n    /// This flag overrides the project's configuration file.\n    ///\n    /// See --fork-url.\n    #[arg(long)]\n    #[serde(skip)]\n    pub no_storage_caching: bool,\n\n    /// The initial balance of deployed test contracts.\n    #[arg(long, value_name = \"BALANCE\")]\n    #[serde(skip_serializing_if = \"Option::is_none\")]\n    pub initial_balance: Option<U256>,\n\n    /// The address which will be executing tests/scripts.\n    #[arg(long, value_name = \"ADDRESS\")]\n    #[serde(skip_serializing_if = \"Option::is_none\")]\n    pub sender: Option<Address>,\n\n    /// Enable the FFI cheatcode.\n    #[arg(long)]\n    #[serde(skip)]\n    pub ffi: bool,\n\n    /// Whether to show `console.log` outputs in realtime during script/test execution\n    #[arg(long)]\n    #[serde(skip)]\n    pub live_logs: bool,\n\n    /// Use the create 2 factory in all cases including tests and non-broadcasting scripts.\n    #[arg(long)]\n    #[serde(skip)]\n    pub always_use_create_2_factory: bool,\n\n    /// The CREATE2 deployer address to use, this will override the one in the config.\n    #[arg(long, value_name = \"ADDRESS\")]\n    #[serde(skip_serializing_if = \"Option::is_none\")]\n    pub create2_deployer: Option<Address>,\n\n    /// Sets the number of assumed available compute units per second for this provider\n    ///\n    /// default value: 330\n    ///\n    /// See also --fork-url and <https://docs.alchemy.com/reference/compute-units#what-are-cups-compute-units-per-second>\n    #[arg(long, alias = \"cups\", value_name = \"CUPS\", help_heading = \"Fork config\")]\n    #[serde(skip_serializing_if = \"Option::is_none\")]\n    pub compute_units_per_second: Option<u64>,\n\n    /// Disables rate limiting for this node's provider.\n    ///\n    /// See also --fork-url and <https://docs.alchemy.com/reference/compute-units#what-are-cups-compute-units-per-second>\n    #[arg(\n        long,\n        value_name = \"NO_RATE_LIMITS\",\n        help_heading = \"Fork config\",\n        visible_alias = \"no-rate-limit\"\n    )]\n    #[serde(skip)]\n    pub no_rpc_rate_limit: bool,\n\n    /// All ethereum environment related arguments\n    #[command(flatten)]\n    #[serde(flatten)]\n    pub env: EnvArgs,\n\n    /// Whether to enable isolation of calls.\n    /// In isolation mode all top-level calls are executed as a separate transaction in a separate\n    /// EVM context, enabling more precise gas accounting and transaction state changes.\n    #[arg(long)]\n    #[serde(skip)]\n    pub isolate: bool,\n}\n\n// Make this set of options a `figment::Provider` so that it can be merged into the `Config`\nimpl Provider for EvmArgs {\n    fn metadata(&self) -> Metadata {\n        Metadata::named(\"Evm Opts Provider\")\n    }\n\n    fn data(&self) -> Result<Map<Profile, Dict>, figment::Error> {\n        let value = Value::serialize(self)?;\n        let error = InvalidType(value.to_actual(), \"map\".into());\n        let mut dict = value.into_dict().ok_or(error)?;\n\n        if shell::verbosity() > 0 {\n            // need to merge that manually otherwise `from_occurrences` does not work\n            dict.insert(\"verbosity\".to_string(), shell::verbosity().into());\n        }\n\n        if self.ffi {\n            dict.insert(\"ffi\".to_string(), self.ffi.into());\n        }\n\n        if self.live_logs {\n            dict.insert(\"live_logs\".to_string(), self.live_logs.into());\n        }\n\n        if self.isolate {\n            dict.insert(\"isolate\".to_string(), self.isolate.into());\n        }\n\n        if self.always_use_create_2_factory {\n            dict.insert(\n                \"always_use_create_2_factory\".to_string(),\n                self.always_use_create_2_factory.into(),\n            );\n        }\n\n        if self.no_storage_caching {\n            dict.insert(\"no_storage_caching\".to_string(), self.no_storage_caching.into());\n        }\n\n        if self.no_rpc_rate_limit {\n            dict.insert(\"no_rpc_rate_limit\".to_string(), self.no_rpc_rate_limit.into());\n        }\n\n        Ok(Map::from([(Config::selected_profile(), dict)]))\n    }\n}\n\n/// Configures the executor environment during tests.\n#[derive(Clone, Debug, Default, Serialize, Parser)]\n#[command(next_help_heading = \"Executor environment config\")]\npub struct EnvArgs {\n    /// EIP-170: Contract code size limit in bytes. Useful to increase this because of tests. By\n    /// default, it is 0x6000 (~25kb).\n    #[arg(long, value_name = \"CODE_SIZE\")]\n    #[serde(skip_serializing_if = \"Option::is_none\")]\n    pub code_size_limit: Option<usize>,\n\n    /// The chain name or EIP-155 chain ID.\n    #[arg(long, visible_alias = \"chain-id\", value_name = \"CHAIN\")]\n    #[serde(rename = \"chain_id\", skip_serializing_if = \"Option::is_none\", serialize_with = \"id\")]\n    pub chain: Option<Chain>,\n\n    /// The gas price.\n    #[arg(long, value_name = \"GAS_PRICE\")]\n    #[serde(skip_serializing_if = \"Option::is_none\")]\n    pub gas_price: Option<u64>,\n\n    /// The base fee in a block.\n    #[arg(long, visible_alias = \"base-fee\", value_name = \"FEE\")]\n    #[serde(skip_serializing_if = \"Option::is_none\")]\n    pub block_base_fee_per_gas: Option<u64>,\n\n    /// The transaction origin.\n    #[arg(long, value_name = \"ADDRESS\")]\n    #[serde(skip_serializing_if = \"Option::is_none\")]\n    pub tx_origin: Option<Address>,\n\n    /// The coinbase of the block.\n    #[arg(long, value_name = \"ADDRESS\")]\n    #[serde(skip_serializing_if = \"Option::is_none\")]\n    pub block_coinbase: Option<Address>,\n\n    /// The timestamp of the block.\n    #[arg(long, value_name = \"TIMESTAMP\")]\n    #[serde(skip_serializing_if = \"Option::is_none\")]\n    pub block_timestamp: Option<u64>,\n\n    /// The block number.\n    #[arg(long, value_name = \"BLOCK\")]\n    #[serde(skip_serializing_if = \"Option::is_none\")]\n    pub block_number: Option<u64>,\n\n    /// The block difficulty.\n    #[arg(long, value_name = \"DIFFICULTY\")]\n    #[serde(skip_serializing_if = \"Option::is_none\")]\n    pub block_difficulty: Option<u64>,\n\n    /// The block prevrandao value. NOTE: Before merge this field was mix_hash.\n    #[arg(long, value_name = \"PREVRANDAO\")]\n    #[serde(skip_serializing_if = \"Option::is_none\")]\n    pub block_prevrandao: Option<B256>,\n\n    /// The block gas limit.\n    #[arg(long, visible_alias = \"gas-limit\", value_name = \"BLOCK_GAS_LIMIT\")]\n    #[serde(skip_serializing_if = \"Option::is_none\")]\n    pub block_gas_limit: Option<u64>,\n\n    /// The memory limit per EVM execution in bytes.\n    /// If this limit is exceeded, a `MemoryLimitOOG` result is thrown.\n    ///\n    /// The default is 128MiB.\n    #[arg(long, value_name = \"MEMORY_LIMIT\")]\n    #[serde(skip_serializing_if = \"Option::is_none\")]\n    pub memory_limit: Option<u64>,\n\n    /// Whether to disable the block gas limit checks.\n    #[arg(long, visible_aliases = &[\"no-block-gas-limit\", \"no-gas-limit\"])]\n    #[serde(skip_serializing_if = \"std::ops::Not::not\")]\n    pub disable_block_gas_limit: bool,\n\n    /// Whether to enable tx gas limit checks as imposed by Osaka (EIP-7825).\n    #[arg(long, visible_alias = \"tx-gas-limit\")]\n    #[serde(skip_serializing_if = \"std::ops::Not::not\")]\n    pub enable_tx_gas_limit: bool,\n}\n\n/// We have to serialize chain IDs and not names because when extracting an EVM `Env`, it expects\n/// `chain_id` to be `u64`.\nfn id<S: serde::Serializer>(chain: &Option<Chain>, s: S) -> Result<S::Ok, S::Error> {\n    if let Some(chain) = chain {\n        s.serialize_u64(chain.id())\n    } else {\n        // skip_serializing_if = \"Option::is_none\" should prevent this branch from being taken\n        unreachable!()\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use foundry_config::NamedChain;\n\n    #[test]\n    fn compute_units_per_second_skips_when_none() {\n        let args = EvmArgs::default();\n        let data = args.data().expect(\"provider data\");\n        let dict = data.get(&Config::selected_profile()).expect(\"profile dict\");\n        assert!(\n            !dict.contains_key(\"compute_units_per_second\"),\n            \"compute_units_per_second should be skipped when None\"\n        );\n    }\n\n    #[test]\n    fn compute_units_per_second_present_when_some() {\n        let args = EvmArgs { compute_units_per_second: Some(1000), ..Default::default() };\n        let data = args.data().expect(\"provider data\");\n        let dict = data.get(&Config::selected_profile()).expect(\"profile dict\");\n        let val = dict.get(\"compute_units_per_second\").expect(\"cups present\");\n        assert_eq!(val, &Value::from(1000u64));\n    }\n\n    #[test]\n    fn can_parse_chain_id() {\n        let args = EvmArgs {\n            env: EnvArgs { chain: Some(NamedChain::Mainnet.into()), ..Default::default() },\n            ..Default::default()\n        };\n        let config = Config::from_provider(Config::figment().merge(args)).unwrap();\n        assert_eq!(config.chain, Some(NamedChain::Mainnet.into()));\n\n        let env = EnvArgs::parse_from([\"foundry-cli\", \"--chain-id\", \"goerli\"]);\n        assert_eq!(env.chain, Some(NamedChain::Goerli.into()));\n    }\n\n    #[test]\n    fn test_memory_limit() {\n        let args = EvmArgs {\n            env: EnvArgs { chain: Some(NamedChain::Mainnet.into()), ..Default::default() },\n            ..Default::default()\n        };\n        let config = Config::from_provider(Config::figment().merge(args)).unwrap();\n        assert_eq!(config.memory_limit, Config::default().memory_limit);\n\n        let env = EnvArgs::parse_from([\"foundry-cli\", \"--memory-limit\", \"100\"]);\n        assert_eq!(env.memory_limit, Some(100));\n    }\n\n    #[test]\n    fn test_chain_id() {\n        let env = EnvArgs::parse_from([\"foundry-cli\", \"--chain-id\", \"1\"]);\n        assert_eq!(env.chain, Some(Chain::mainnet()));\n\n        let env = EnvArgs::parse_from([\"foundry-cli\", \"--chain-id\", \"mainnet\"]);\n        assert_eq!(env.chain, Some(Chain::mainnet()));\n        let args = EvmArgs { env, ..Default::default() };\n        let config = Config::from_provider(Config::figment().merge(args)).unwrap();\n        assert_eq!(config.chain, Some(Chain::mainnet()));\n    }\n}\n"
  },
  {
    "path": "crates/cli/src/opts/global.rs",
    "content": "use clap::{ArgAction, Parser};\nuse foundry_common::{\n    shell::{ColorChoice, OutputFormat, OutputMode, Shell, Verbosity},\n    version::{IS_NIGHTLY_VERSION, NIGHTLY_VERSION_WARNING_MESSAGE},\n};\nuse serde::{Deserialize, Serialize};\n\n/// Global arguments for the CLI.\n#[derive(Clone, Debug, Default, Serialize, Deserialize, Parser)]\npub struct GlobalArgs {\n    /// Verbosity level of the log messages.\n    ///\n    /// Pass multiple times to increase the verbosity (e.g. -v, -vv, -vvv).\n    ///\n    /// Depending on the context the verbosity levels have different meanings.\n    ///\n    /// For example, the verbosity levels of the EVM are:\n    /// - 2 (-vv): Print logs for all tests.\n    /// - 3 (-vvv): Print execution traces for failing tests.\n    /// - 4 (-vvvv): Print execution traces for all tests, and setup traces for failing tests.\n    /// - 5 (-vvvvv): Print execution and setup traces for all tests, including storage changes and\n    ///   backtraces with line numbers.\n    #[arg(help_heading = \"Display options\", global = true, short, long, verbatim_doc_comment, conflicts_with = \"quiet\", action = ArgAction::Count)]\n    verbosity: Verbosity,\n\n    /// Do not print log messages.\n    #[arg(help_heading = \"Display options\", global = true, short, long, alias = \"silent\")]\n    quiet: bool,\n\n    /// Format log messages as JSON.\n    #[arg(help_heading = \"Display options\", global = true, long, alias = \"format-json\", conflicts_with_all = &[\"quiet\", \"color\"])]\n    json: bool,\n\n    /// Format log messages as Markdown.\n    #[arg(\n        help_heading = \"Display options\",\n        global = true,\n        long,\n        alias = \"markdown\",\n        conflicts_with = \"json\"\n    )]\n    md: bool,\n\n    /// The color of the log messages.\n    #[arg(help_heading = \"Display options\", global = true, long, value_enum)]\n    color: Option<ColorChoice>,\n\n    /// Number of threads to use. Specifying 0 defaults to the number of logical cores.\n    #[arg(global = true, long, short = 'j', visible_alias = \"jobs\")]\n    threads: Option<usize>,\n}\n\nimpl GlobalArgs {\n    /// Check if `--markdown-help` was passed and print CLI reference as Markdown, then exit.\n    ///\n    /// This must be called **before** parsing arguments, since commands with required\n    /// subcommands would fail parsing before the flag is checked.\n    pub fn check_markdown_help<C: clap::CommandFactory>() {\n        if std::env::args().any(|arg| arg == \"--markdown-help\") {\n            foundry_cli_markdown::print_help_markdown::<C>();\n            std::process::exit(0);\n        }\n    }\n\n    /// Initialize the global options.\n    pub fn init(&self) -> eyre::Result<()> {\n        // Set the global shell.\n        let shell = self.shell();\n        // Argument takes precedence over the env var global color choice.\n        match shell.color_choice() {\n            ColorChoice::Auto => {}\n            ColorChoice::Always => yansi::enable(),\n            ColorChoice::Never => yansi::disable(),\n        }\n        shell.set();\n\n        // Initialize the thread pool only if `threads` was requested to avoid unnecessary overhead.\n        if self.threads.is_some() {\n            self.force_init_thread_pool()?;\n        }\n\n        // Display a warning message if the current version is not stable.\n        if IS_NIGHTLY_VERSION\n            && !self.json\n            && std::env::var_os(\"FOUNDRY_DISABLE_NIGHTLY_WARNING\").is_none()\n        {\n            let _ = sh_warn!(\"{}\", NIGHTLY_VERSION_WARNING_MESSAGE);\n        }\n\n        Ok(())\n    }\n\n    /// Create a new shell instance.\n    pub fn shell(&self) -> Shell {\n        let mode = match self.quiet {\n            true => OutputMode::Quiet,\n            false => OutputMode::Normal,\n        };\n        let color = self.json.then_some(ColorChoice::Never).or(self.color).unwrap_or_default();\n        let format = if self.json {\n            OutputFormat::Json\n        } else if self.md {\n            OutputFormat::Markdown\n        } else {\n            OutputFormat::Text\n        };\n\n        Shell::new_with(format, mode, color, self.verbosity)\n    }\n\n    /// Initialize the global thread pool.\n    pub fn force_init_thread_pool(&self) -> eyre::Result<()> {\n        init_thread_pool(self.threads.unwrap_or(0))\n    }\n\n    /// Creates a new tokio runtime.\n    #[track_caller]\n    pub fn tokio_runtime(&self) -> tokio::runtime::Runtime {\n        let mut builder = tokio::runtime::Builder::new_multi_thread();\n        if let Some(threads) = self.threads\n            && threads > 0\n        {\n            builder.worker_threads(threads);\n        }\n        builder.enable_all().build().expect(\"failed to create tokio runtime\")\n    }\n\n    /// Creates a new tokio runtime and blocks on the future.\n    #[track_caller]\n    pub fn block_on<F: std::future::Future>(&self, future: F) -> F::Output {\n        self.tokio_runtime().block_on(future)\n    }\n}\n\n/// Initialize the global thread pool.\npub fn init_thread_pool(threads: usize) -> eyre::Result<()> {\n    rayon::ThreadPoolBuilder::new()\n        .thread_name(|i| format!(\"foundry-{i}\"))\n        .num_threads(threads)\n        .build_global()?;\n    Ok(())\n}\n"
  },
  {
    "path": "crates/cli/src/opts/mod.rs",
    "content": "mod build;\nmod chain;\nmod dependency;\nmod evm;\nmod global;\nmod network;\nmod rpc;\nmod tempo;\nmod transaction;\n\npub use build::*;\npub use chain::*;\npub use dependency::*;\npub use evm::*;\npub use global::*;\npub use network::*;\npub use rpc::*;\npub use tempo::*;\npub use transaction::*;\n"
  },
  {
    "path": "crates/cli/src/opts/network.rs",
    "content": "/// Network selection, defaulting to Ethereum\n#[derive(Clone, Debug, Default, clap::ValueEnum)]\npub enum NetworkVariant {\n    /// Ethereum (default)\n    #[default]\n    Ethereum,\n    /// Optimism / OP-stack\n    Optimism,\n    /// Tempo\n    Tempo,\n}\n"
  },
  {
    "path": "crates/cli/src/opts/rpc.rs",
    "content": "use crate::opts::ChainValueParser;\nuse alloy_chains::ChainKind;\nuse clap::Parser;\nuse eyre::Result;\nuse foundry_config::{\n    Chain, Config, FigmentProviders,\n    figment::{\n        self, Figment, Metadata, Profile,\n        value::{Dict, Map},\n    },\n    find_project_root, impl_figment_convert_cast,\n};\nuse foundry_wallets::WalletOpts;\nuse serde::Serialize;\nuse std::borrow::Cow;\n\nconst FLASHBOTS_URL: &str = \"https://rpc.flashbots.net/fast\";\n\n#[derive(Clone, Debug, Default, Parser)]\n#[command(next_help_heading = \"Rpc options\")]\npub struct RpcOpts {\n    /// The RPC endpoint, default value is http://localhost:8545.\n    #[arg(short = 'r', long = \"rpc-url\", env = \"ETH_RPC_URL\")]\n    pub url: Option<String>,\n\n    /// Allow insecure RPC connections (accept invalid HTTPS certificates).\n    ///\n    /// When the provider's inner runtime transport variant is HTTP, this configures the reqwest\n    /// client to accept invalid certificates.\n    #[arg(short = 'k', long = \"insecure\", default_value = \"false\")]\n    pub accept_invalid_certs: bool,\n\n    /// Disable automatic proxy detection.\n    ///\n    /// Use this in sandboxed environments (e.g., Cursor IDE sandbox, macOS App Sandbox) where\n    /// system proxy detection causes crashes. When enabled, HTTP_PROXY/HTTPS_PROXY environment\n    /// variables and system proxy settings will be ignored.\n    #[arg(long = \"no-proxy\", alias = \"disable-proxy\", default_value = \"false\")]\n    pub no_proxy: bool,\n\n    /// Use the Flashbots RPC URL with fast mode (<https://rpc.flashbots.net/fast>).\n    ///\n    /// This shares the transaction privately with all registered builders.\n    ///\n    /// See: <https://docs.flashbots.net/flashbots-protect/quick-start#faster-transactions>\n    #[arg(long)]\n    pub flashbots: bool,\n\n    /// JWT Secret for the RPC endpoint.\n    ///\n    /// The JWT secret will be used to create a JWT for a RPC. For example, the following can be\n    /// used to simulate a CL `engine_forkchoiceUpdated` call:\n    ///\n    /// cast rpc --jwt-secret <JWT_SECRET> engine_forkchoiceUpdatedV2\n    /// '[\"0x6bb38c26db65749ab6e472080a3d20a2f35776494e72016d1e339593f21c59bc\",\n    /// \"0x6bb38c26db65749ab6e472080a3d20a2f35776494e72016d1e339593f21c59bc\",\n    /// \"0x6bb38c26db65749ab6e472080a3d20a2f35776494e72016d1e339593f21c59bc\"]'\n    #[arg(long, env = \"ETH_RPC_JWT_SECRET\")]\n    pub jwt_secret: Option<String>,\n\n    /// Timeout for the RPC request in seconds.\n    ///\n    /// The specified timeout will be used to override the default timeout for RPC requests.\n    ///\n    /// Default value: 45\n    #[arg(long, env = \"ETH_RPC_TIMEOUT\")]\n    pub rpc_timeout: Option<u64>,\n\n    /// Specify custom headers for RPC requests.\n    #[arg(long, alias = \"headers\", env = \"ETH_RPC_HEADERS\", value_delimiter(','))]\n    pub rpc_headers: Option<Vec<String>>,\n\n    /// Print the equivalent curl command instead of making the RPC request.\n    #[arg(long)]\n    pub curl: bool,\n}\n\nimpl_figment_convert_cast!(RpcOpts);\n\nimpl figment::Provider for RpcOpts {\n    fn metadata(&self) -> Metadata {\n        Metadata::named(\"RpcOpts\")\n    }\n\n    fn data(&self) -> Result<Map<Profile, Dict>, figment::Error> {\n        Ok(Map::from([(Config::selected_profile(), self.dict())]))\n    }\n}\n\nimpl RpcOpts {\n    /// Returns the RPC endpoint.\n    pub fn url<'a>(&'a self, config: Option<&'a Config>) -> Result<Option<Cow<'a, str>>> {\n        let url = match (self.flashbots, self.url.as_deref(), config) {\n            (true, ..) => Some(Cow::Borrowed(FLASHBOTS_URL)),\n            (false, Some(url), _) => Some(Cow::Borrowed(url)),\n            (false, None, Some(config)) => config.get_rpc_url().transpose()?,\n            (false, None, None) => None,\n        };\n        Ok(url)\n    }\n\n    /// Returns the JWT secret.\n    pub fn jwt<'a>(&'a self, config: Option<&'a Config>) -> Result<Option<Cow<'a, str>>> {\n        let jwt = match (self.jwt_secret.as_deref(), config) {\n            (Some(jwt), _) => Some(Cow::Borrowed(jwt)),\n            (None, Some(config)) => config.get_rpc_jwt_secret()?,\n            (None, None) => None,\n        };\n        Ok(jwt)\n    }\n\n    pub fn dict(&self) -> Dict {\n        let mut dict = Dict::new();\n        if let Ok(Some(url)) = self.url(None) {\n            dict.insert(\"eth_rpc_url\".into(), url.into_owned().into());\n        }\n        if let Ok(Some(jwt)) = self.jwt(None) {\n            dict.insert(\"eth_rpc_jwt\".into(), jwt.into_owned().into());\n        }\n        if let Some(rpc_timeout) = self.rpc_timeout {\n            dict.insert(\"eth_rpc_timeout\".into(), rpc_timeout.into());\n        }\n        if let Some(headers) = &self.rpc_headers {\n            dict.insert(\"eth_rpc_headers\".into(), headers.clone().into());\n        }\n        if self.accept_invalid_certs {\n            dict.insert(\"eth_rpc_accept_invalid_certs\".into(), true.into());\n        }\n        if self.no_proxy {\n            dict.insert(\"eth_rpc_no_proxy\".into(), true.into());\n        }\n        if self.curl {\n            dict.insert(\"eth_rpc_curl\".into(), true.into());\n        }\n        dict\n    }\n\n    pub fn into_figment(self, all: bool) -> Figment {\n        let root = find_project_root(None).expect(\"could not determine project root\");\n        Config::with_root(&root)\n            .to_figment(if all { FigmentProviders::All } else { FigmentProviders::Cast })\n            .merge(self)\n    }\n}\n\n#[derive(Clone, Debug, Default, Serialize, Parser)]\npub struct EtherscanOpts {\n    /// The Etherscan (or equivalent) API key.\n    #[arg(short = 'e', long = \"etherscan-api-key\", alias = \"api-key\", env = \"ETHERSCAN_API_KEY\")]\n    #[serde(rename = \"etherscan_api_key\", skip_serializing_if = \"Option::is_none\")]\n    pub key: Option<String>,\n\n    /// The chain name or EIP-155 chain ID.\n    #[arg(\n        short,\n        long,\n        alias = \"chain-id\",\n        env = \"CHAIN\",\n        value_parser = ChainValueParser::default(),\n    )]\n    #[serde(rename = \"chain_id\", skip_serializing_if = \"Option::is_none\")]\n    pub chain: Option<Chain>,\n}\n\nimpl_figment_convert_cast!(EtherscanOpts);\n\nimpl figment::Provider for EtherscanOpts {\n    fn metadata(&self) -> Metadata {\n        Metadata::named(\"EtherscanOpts\")\n    }\n\n    fn data(&self) -> Result<Map<Profile, Dict>, figment::Error> {\n        Ok(Map::from([(Config::selected_profile(), self.dict())]))\n    }\n}\n\nimpl EtherscanOpts {\n    /// Returns true if the Etherscan API key is set.\n    pub fn has_key(&self) -> bool {\n        self.key.as_ref().filter(|key| !key.trim().is_empty()).is_some()\n    }\n\n    /// Returns the Etherscan API key.\n    pub fn key(&self) -> Option<String> {\n        self.key.as_ref().filter(|key| !key.trim().is_empty()).cloned()\n    }\n\n    pub fn dict(&self) -> Dict {\n        let mut dict = Dict::new();\n        if let Some(key) = self.key() {\n            dict.insert(\"etherscan_api_key\".into(), key.into());\n        }\n\n        if let Some(chain) = self.chain {\n            if let ChainKind::Id(id) = chain.kind() {\n                dict.insert(\"chain_id\".into(), (*id).into());\n            } else {\n                dict.insert(\"chain_id\".into(), chain.to_string().into());\n            }\n        }\n        dict\n    }\n}\n\n#[derive(Clone, Debug, Default, Parser)]\n#[command(next_help_heading = \"Ethereum options\")]\npub struct EthereumOpts {\n    #[command(flatten)]\n    pub rpc: RpcOpts,\n\n    #[command(flatten)]\n    pub etherscan: EtherscanOpts,\n\n    #[command(flatten)]\n    pub wallet: WalletOpts,\n}\n\nimpl_figment_convert_cast!(EthereumOpts);\n\n// Make this args a `Figment` so that it can be merged into the `Config`\nimpl figment::Provider for EthereumOpts {\n    fn metadata(&self) -> Metadata {\n        Metadata::named(\"Ethereum Opts Provider\")\n    }\n\n    fn data(&self) -> Result<Map<Profile, Dict>, figment::Error> {\n        let mut dict = self.etherscan.dict();\n        dict.extend(self.rpc.dict());\n\n        if let Some(from) = self.wallet.from {\n            dict.insert(\"sender\".to_string(), from.to_string().into());\n        }\n\n        Ok(Map::from([(Config::selected_profile(), dict)]))\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn parse_etherscan_opts() {\n        let args: EtherscanOpts =\n            EtherscanOpts::parse_from([\"foundry-cli\", \"--etherscan-api-key\", \"dummykey\"]);\n        assert_eq!(args.key(), Some(\"dummykey\".to_string()));\n\n        let args: EtherscanOpts =\n            EtherscanOpts::parse_from([\"foundry-cli\", \"--etherscan-api-key\", \"\"]);\n        assert!(!args.has_key());\n    }\n}\n"
  },
  {
    "path": "crates/cli/src/opts/tempo.rs",
    "content": "use alloy_network::{Network, TransactionBuilder};\nuse alloy_primitives::{Address, ruint::aliases::U256};\nuse alloy_signer::Signature;\nuse clap::Parser;\nuse foundry_primitives::FoundryTransactionBuilder;\nuse std::str::FromStr;\n\n/// CLI options for Tempo transactions.\n#[derive(Clone, Debug, Default, Parser)]\n#[command(next_help_heading = \"Tempo\")]\npub struct TempoOpts {\n    /// Fee token address for Tempo transactions.\n    ///\n    /// When set, builds a Tempo (type 0x76) transaction that pays gas fees\n    /// in the specified token.\n    ///\n    /// If this is not set, the fee token is chosen according to network rules. See the Tempo docs\n    /// for more information.\n    #[arg(long = \"tempo.fee-token\")]\n    pub fee_token: Option<Address>,\n\n    /// Nonce sequence key for Tempo transactions.\n    ///\n    /// When set, builds a Tempo (type 0x76) transaction with the specified nonce sequence key.\n    ///\n    /// If this is not set, the protocol sequence key (0) will be used.\n    ///\n    /// For more information see <https://docs.tempo.xyz/protocol/transactions/spec-tempo-transaction#parallelizable-nonces>.\n    #[arg(long = \"tempo.seq\")]\n    pub sequence_key: Option<U256>,\n\n    /// Sponsor (fee payer) signature for Tempo sponsored transactions.\n    ///\n    /// The sponsor signs the `fee_payer_signature_hash` to commit to paying gas fees\n    /// on behalf of the sender. Provide as a hex-encoded signature.\n    #[arg(long = \"tempo.sponsor-sig\", value_parser = parse_signature)]\n    pub sponsor_signature: Option<Signature>,\n\n    /// Print the sponsor signature hash and exit.\n    ///\n    /// Computes the `fee_payer_signature_hash` for the transaction so that a sponsor\n    /// knows what hash to sign. The transaction is not sent.\n    #[arg(long = \"tempo.print-sponsor-hash\")]\n    pub print_sponsor_hash: bool,\n\n    /// Access key ID for Tempo Keychain signature transactions.\n    ///\n    /// Used during gas estimation to override the key_id that would normally be\n    /// recovered from the signature.\n    #[arg(long = \"tempo.key-id\")]\n    pub key_id: Option<Address>,\n\n    /// Enable expiring nonce mode for Tempo transactions.\n    ///\n    /// Sets nonce to 0 and nonce_key to U256::MAX, enabling time-bounded transaction\n    /// validity via `--tempo.valid-before` and `--tempo.valid-after`.\n    #[arg(long = \"tempo.expiring-nonce\", requires = \"valid_before\")]\n    pub expiring_nonce: bool,\n\n    /// Upper bound timestamp for Tempo expiring nonce transactions.\n    ///\n    /// The transaction is only valid before this unix timestamp.\n    /// Requires `--tempo.expiring-nonce`.\n    #[arg(long = \"tempo.valid-before\")]\n    pub valid_before: Option<u64>,\n\n    /// Lower bound timestamp for Tempo expiring nonce transactions.\n    ///\n    /// The transaction is only valid after this unix timestamp.\n    /// Requires `--tempo.expiring-nonce`.\n    #[arg(long = \"tempo.valid-after\")]\n    pub valid_after: Option<u64>,\n}\n\nimpl TempoOpts {\n    /// Returns `true` if any Tempo-specific option is set.\n    pub fn is_tempo(&self) -> bool {\n        self.fee_token.is_some()\n            || self.sequence_key.is_some()\n            || self.sponsor_signature.is_some()\n            || self.print_sponsor_hash\n            || self.key_id.is_some()\n            || self.expiring_nonce\n            || self.valid_before.is_some()\n            || self.valid_after.is_some()\n    }\n\n    /// Applies Tempo-specific options to a transaction request.\n    ///\n    /// All setters are no-ops for non-Tempo networks, so this is safe to call unconditionally.\n    pub fn apply<N: Network>(&self, tx: &mut N::TransactionRequest, nonce: Option<u64>)\n    where\n        N::TransactionRequest: FoundryTransactionBuilder<N>,\n    {\n        // Handle expiring nonce mode: sets nonce=0 and nonce_key=U256::MAX\n        if self.expiring_nonce {\n            tx.set_nonce(0);\n            tx.set_nonce_key(U256::MAX);\n        } else {\n            if let Some(nonce) = nonce {\n                tx.set_nonce(nonce);\n            }\n            if let Some(nonce_key) = self.sequence_key {\n                tx.set_nonce_key(nonce_key);\n            }\n        }\n\n        if let Some(fee_token) = self.fee_token {\n            tx.set_fee_token(fee_token);\n        }\n\n        if let Some(valid_before) = self.valid_before {\n            tx.set_valid_before(valid_before);\n        }\n        if let Some(valid_after) = self.valid_after {\n            tx.set_valid_after(valid_after);\n        }\n\n        if let Some(key_id) = self.key_id {\n            tx.set_key_id(key_id);\n        }\n\n        // Force AA tx type if sponsoring or printing sponsor hash.\n        if self.sponsor_signature.is_some() || self.print_sponsor_hash {\n            if tx.nonce_key().is_none() {\n                tx.set_nonce_key(U256::ZERO);\n            }\n            if let Some(sig) = self.sponsor_signature {\n                tx.set_fee_payer_signature(sig);\n            }\n        }\n    }\n}\n\nfn parse_signature(s: &str) -> Result<Signature, String> {\n    Signature::from_str(s).map_err(|e| format!(\"invalid signature: {e}\"))\n}\n"
  },
  {
    "path": "crates/cli/src/opts/transaction.rs",
    "content": "use std::str::FromStr;\n\nuse super::TempoOpts;\nuse crate::utils::{parse_ether_value, parse_json};\nuse alloy_eips::{eip2930::AccessList, eip7702::SignedAuthorization};\nuse alloy_network::{Network, TransactionBuilder};\nuse alloy_primitives::{Address, U64, U256, hex};\nuse alloy_rlp::Decodable;\nuse clap::Parser;\nuse foundry_primitives::FoundryTransactionBuilder;\n\n/// CLI helper to parse a EIP-7702 authorization list.\n/// Can be either a hex-encoded signed authorization or an address.\n#[derive(Clone, Debug)]\npub enum CliAuthorizationList {\n    /// If an address is provided, we sign the authorization delegating to provided address.\n    Address(Address),\n    /// If RLP-encoded authorization is provided, we decode it and attach to transaction.\n    Signed(SignedAuthorization),\n}\n\nimpl FromStr for CliAuthorizationList {\n    type Err = eyre::Error;\n\n    fn from_str(s: &str) -> Result<Self, Self::Err> {\n        if let Ok(addr) = Address::from_str(s) {\n            Ok(Self::Address(addr))\n        } else if let Ok(auth) = SignedAuthorization::decode(&mut hex::decode(s)?.as_ref()) {\n            Ok(Self::Signed(auth))\n        } else {\n            eyre::bail!(\"Failed to decode authorization\")\n        }\n    }\n}\n\n#[derive(Clone, Debug, Parser)]\n#[command(next_help_heading = \"Transaction options\")]\npub struct TransactionOpts {\n    /// Gas limit for the transaction.\n    #[arg(long, env = \"ETH_GAS_LIMIT\")]\n    pub gas_limit: Option<U256>,\n\n    /// Gas price for legacy transactions, or max fee per gas for EIP1559 transactions, either\n    /// specified in wei, or as a string with a unit type.\n    ///\n    /// Examples: 1ether, 10gwei, 0.01ether\n    #[arg(\n        long,\n        env = \"ETH_GAS_PRICE\",\n        value_parser = parse_ether_value,\n        value_name = \"PRICE\"\n    )]\n    pub gas_price: Option<U256>,\n\n    /// Max priority fee per gas for EIP1559 transactions.\n    #[arg(\n        long,\n        env = \"ETH_PRIORITY_GAS_PRICE\",\n        value_parser = parse_ether_value,\n        value_name = \"PRICE\"\n    )]\n    pub priority_gas_price: Option<U256>,\n\n    /// Ether to send in the transaction, either specified in wei, or as a string with a unit type.\n    ///\n    ///\n    ///\n    /// Examples: 1ether, 10gwei, 0.01ether\n    #[arg(long, value_parser = parse_ether_value)]\n    pub value: Option<U256>,\n\n    /// Nonce for the transaction.\n    #[arg(long)]\n    pub nonce: Option<U64>,\n\n    /// Send a legacy transaction instead of an EIP1559 transaction.\n    ///\n    /// This is automatically enabled for common networks without EIP1559.\n    #[arg(long)]\n    pub legacy: bool,\n\n    /// Send a blob transaction using EIP-7594 (PeerDAS) format.\n    ///\n    /// Note: Use with `--eip4844` for the legacy EIP-4844 format.\n    #[arg(long, conflicts_with = \"legacy\")]\n    pub blob: bool,\n\n    /// Send a blob transaction using EIP-4844 (legacy) format instead of EIP-7594. Must be used\n    /// with `--blob`.\n    #[arg(long, conflicts_with = \"legacy\", requires = \"blob\")]\n    pub eip4844: bool,\n\n    /// Gas price for EIP-7594/EIP-4844 blob transaction.\n    #[arg(long, conflicts_with = \"legacy\", value_parser = parse_ether_value, env = \"ETH_BLOB_GAS_PRICE\", value_name = \"BLOB_PRICE\")]\n    pub blob_gas_price: Option<U256>,\n\n    /// EIP-7702 authorization list.\n    ///\n    /// Can be either a hex-encoded signed authorization or an address.\n    #[arg(long, conflicts_with_all = &[\"legacy\", \"blob\"])]\n    pub auth: Vec<CliAuthorizationList>,\n\n    /// EIP-2930 access list.\n    ///\n    /// Accepts either a JSON-encoded access list or an empty value to create the access list\n    /// via an RPC call to `eth_createAccessList`. To retrieve only the access list portion, use\n    /// the `cast access-list` command.\n    #[arg(long, value_parser = parse_json::<AccessList>)]\n    pub access_list: Option<Option<AccessList>>,\n\n    #[command(flatten)]\n    pub tempo: TempoOpts,\n}\n\nimpl TransactionOpts {\n    /// Applies gas, value, fee, and network-specific options to a transaction request.\n    pub fn apply<N: Network>(&self, tx: &mut N::TransactionRequest, legacy: bool)\n    where\n        N::TransactionRequest: FoundryTransactionBuilder<N>,\n    {\n        if let Some(gas_limit) = self.gas_limit {\n            tx.set_gas_limit(gas_limit.to());\n        }\n\n        if let Some(value) = self.value {\n            tx.set_value(value);\n        }\n\n        if let Some(gas_price) = self.gas_price {\n            if legacy {\n                tx.set_gas_price(gas_price.to());\n            } else {\n                tx.set_max_fee_per_gas(gas_price.to());\n            }\n        }\n\n        if !legacy && let Some(priority_fee) = self.priority_gas_price {\n            tx.set_max_priority_fee_per_gas(priority_fee.to());\n        }\n\n        if let Some(max_blob_fee) = self.blob_gas_price {\n            tx.set_max_fee_per_blob_gas(max_blob_fee.to())\n        }\n\n        // set network-specific options\n        self.tempo.apply::<N>(tx, self.nonce.map(|n| n.to()));\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn parse_priority_gas_tx_opts() {\n        let args: TransactionOpts =\n            TransactionOpts::parse_from([\"foundry-cli\", \"--priority-gas-price\", \"100\"]);\n        assert!(args.priority_gas_price.is_some());\n    }\n}\n"
  },
  {
    "path": "crates/cli/src/utils/abi.rs",
    "content": "use alloy_chains::Chain;\nuse alloy_ens::NameOrAddress;\nuse alloy_json_abi::Function;\nuse alloy_primitives::{Address, hex};\nuse alloy_provider::{Network, Provider};\nuse eyre::{OptionExt, Result};\nuse foundry_common::abi::{\n    encode_function_args, encode_function_args_raw, get_func, get_func_etherscan,\n};\nuse futures::future::join_all;\n\nasync fn resolve_name_args<N: Network, P: Provider<N>>(\n    args: &[String],\n    provider: &P,\n) -> Vec<String> {\n    join_all(args.iter().map(|arg| async {\n        if arg.contains('.') {\n            let addr = NameOrAddress::Name(arg.to_string()).resolve(provider).await;\n            match addr {\n                Ok(addr) => addr.to_string(),\n                Err(_) => arg.to_string(),\n            }\n        } else {\n            arg.to_string()\n        }\n    }))\n    .await\n}\n\npub async fn parse_function_args<N: Network, P: Provider<N>>(\n    sig: &str,\n    args: Vec<String>,\n    to: Option<Address>,\n    chain: Chain,\n    provider: &P,\n    etherscan_api_key: Option<&str>,\n) -> Result<(Vec<u8>, Option<Function>)> {\n    if sig.trim().is_empty() {\n        eyre::bail!(\"Function signature or calldata must be provided.\")\n    }\n\n    let args = resolve_name_args(&args, provider).await;\n\n    // Try to decode as hex calldata first, otherwise treat as function signature\n    if let Ok(data) = hex::decode(sig) {\n        return Ok((data, None));\n    } else if sig.starts_with(\"0x\") || sig.starts_with(\"0X\") {\n        let e = hex::decode(sig).unwrap_err();\n        eyre::bail!(\"Invalid hex calldata '{}': {e}\", sig);\n    }\n\n    let func = if sig.contains('(') {\n        // a regular function signature with parentheses\n        get_func(sig)?\n    } else {\n        info!(\n            \"function signature does not contain parentheses, fetching function data from Etherscan\"\n        );\n        let etherscan_api_key = etherscan_api_key.ok_or_eyre(\n            \"Function signature does not contain parentheses. If you wish to fetch function data from Etherscan, please provide an API key.\",\n        )?;\n        let to = to.ok_or_eyre(\"A 'to' address must be provided to fetch function data.\")?;\n        get_func_etherscan(sig, to, &args, chain, etherscan_api_key).await?\n    };\n\n    if to.is_none() {\n        // if this is a CREATE call we must exclude the (constructor) function selector: https://github.com/foundry-rs/foundry/issues/10947\n        Ok((encode_function_args_raw(&func, &args)?, Some(func)))\n    } else {\n        Ok((encode_function_args(&func, &args)?, Some(func)))\n    }\n}\n"
  },
  {
    "path": "crates/cli/src/utils/allocator.rs",
    "content": "//! Abstract global allocator implementation.\n\n#[cfg(feature = \"mimalloc\")]\nuse mimalloc as _;\n#[cfg(all(feature = \"jemalloc\", unix))]\nuse tikv_jemallocator as _;\n\n// If neither jemalloc nor mimalloc are enabled, use explicitly the system allocator.\n// By default jemalloc is enabled on Unix systems.\ncfg_if::cfg_if! {\n    if #[cfg(all(feature = \"jemalloc\", unix))] {\n        type AllocatorInner = tikv_jemallocator::Jemalloc;\n    } else if #[cfg(feature = \"mimalloc\")] {\n        type AllocatorInner = mimalloc::MiMalloc;\n    } else {\n        type AllocatorInner = std::alloc::System;\n    }\n}\n\n// Wrap the allocator if the `tracy-allocator` feature is enabled.\ncfg_if::cfg_if! {\n    if #[cfg(feature = \"tracy-allocator\")] {\n        type AllocatorWrapper = tracing_tracy::client::ProfiledAllocator<AllocatorInner>;\n        const fn new_allocator_wrapper() -> AllocatorWrapper {\n            AllocatorWrapper::new(AllocatorInner {}, 100)\n        }\n    } else {\n        type AllocatorWrapper = AllocatorInner;\n        const fn new_allocator_wrapper() -> AllocatorWrapper {\n            AllocatorInner {}\n        }\n    }\n}\n\npub type Allocator = AllocatorWrapper;\n\n/// Creates a new [allocator][Allocator].\npub const fn new_allocator() -> Allocator {\n    new_allocator_wrapper()\n}\n"
  },
  {
    "path": "crates/cli/src/utils/cmd.rs",
    "content": "use alloy_json_abi::JsonAbi;\nuse eyre::{Result, WrapErr};\nuse foundry_common::{TestFunctionExt, fs, fs::json_files, selectors::SelectorKind, shell};\nuse foundry_compilers::{\n    Artifact, ArtifactId, ProjectCompileOutput, artifacts::CompactBytecode, utils::read_json_file,\n};\nuse foundry_config::{Chain, Config, NamedChain, error::ExtractConfigError, figment::Figment};\nuse foundry_evm::{\n    executors::{DeployResult, EvmError, RawCallResult},\n    opts::EvmOpts,\n    traces::{\n        CallTraceDecoder, TraceKind, Traces, decode_trace_arena, identifier::SignaturesCache,\n        prune_trace_depth, render_trace_arena_inner,\n    },\n};\nuse std::{\n    fmt::Write,\n    path::{Path, PathBuf},\n};\nuse yansi::Paint;\n\n/// Given a `Project`'s output, finds the contract by path and name and returns its\n/// ABI, creation bytecode, and `ArtifactId`.\n#[track_caller]\npub fn find_contract_artifacts(\n    output: ProjectCompileOutput,\n    path: &Path,\n    name: &str,\n) -> Result<(JsonAbi, CompactBytecode, ArtifactId)> {\n    let mut other = Vec::new();\n    let Some((id, contract)) = output.into_artifacts().find_map(|(id, artifact)| {\n        if id.name == name && id.source == path {\n            Some((id, artifact))\n        } else {\n            other.push(id.name);\n            None\n        }\n    }) else {\n        let mut err = format!(\"could not find artifact: `{name}`\");\n        if let Some(suggestion) = super::did_you_mean(name, other).pop()\n            && suggestion != name\n        {\n            err = format!(\n                r#\"{err}\n\n        Did you mean `{suggestion}`?\"#\n            );\n        }\n        eyre::bail!(err)\n    };\n\n    let abi = contract\n        .get_abi()\n        .ok_or_else(|| eyre::eyre!(\"contract {} does not contain abi\", name))?\n        .into_owned();\n\n    let bin = contract\n        .get_bytecode()\n        .ok_or_else(|| eyre::eyre!(\"contract {} does not contain bytecode\", name))?\n        .into_owned();\n\n    Ok((abi, bin, id))\n}\n\n/// Returns error if constructor has arguments.\npub fn ensure_clean_constructor(abi: &JsonAbi) -> Result<()> {\n    if let Some(constructor) = &abi.constructor\n        && !constructor.inputs.is_empty()\n    {\n        eyre::bail!(\n            \"Contract constructor should have no arguments. Add those arguments to  `run(...)` instead, and call it with `--sig run(...)`.\"\n        );\n    }\n    Ok(())\n}\n\npub fn needs_setup(abi: &JsonAbi) -> bool {\n    let setup_fns: Vec<_> = abi.functions().filter(|func| func.name.is_setup()).collect();\n\n    for setup_fn in &setup_fns {\n        if setup_fn.name != \"setUp\" {\n            let _ = sh_warn!(\n                \"Found invalid setup function \\\"{}\\\" did you mean \\\"setUp()\\\"?\",\n                setup_fn.signature()\n            );\n        }\n    }\n\n    setup_fns.len() == 1 && setup_fns[0].name == \"setUp\"\n}\n\npub fn eta_key(state: &indicatif::ProgressState, f: &mut dyn Write) {\n    write!(f, \"{:.1}s\", state.eta().as_secs_f64()).unwrap()\n}\n\npub fn init_progress(len: u64, label: &str) -> indicatif::ProgressBar {\n    let pb = indicatif::ProgressBar::new(len);\n    let mut template =\n        \"{prefix}{spinner:.green} [{elapsed_precise}] [{wide_bar:.cyan/blue}] {pos}/{len} \"\n            .to_string();\n    write!(template, \"{label}\").unwrap();\n    template += \" ({eta})\";\n    pb.set_style(\n        indicatif::ProgressStyle::with_template(&template)\n            .unwrap()\n            .with_key(\"eta\", crate::utils::eta_key)\n            .progress_chars(\"#>-\"),\n    );\n    pb\n}\n\n/// True if the network calculates gas costs differently.\npub fn has_different_gas_calc(chain_id: u64) -> bool {\n    if let Some(chain) = Chain::from(chain_id).named() {\n        return chain.is_arbitrum()\n            || chain.is_elastic()\n            || matches!(\n                chain,\n                NamedChain::Acala\n                    | NamedChain::AcalaMandalaTestnet\n                    | NamedChain::AcalaTestnet\n                    | NamedChain::Etherlink\n                    | NamedChain::EtherlinkShadownet\n                    | NamedChain::Karura\n                    | NamedChain::KaruraTestnet\n                    | NamedChain::Mantle\n                    | NamedChain::MantleSepolia\n                    | NamedChain::Metis\n                    | NamedChain::Monad\n                    | NamedChain::MonadTestnet\n                    | NamedChain::Moonbase\n                    | NamedChain::Moonbeam\n                    | NamedChain::MoonbeamDev\n                    | NamedChain::Moonriver\n                    | NamedChain::PolkadotTestnet\n                    | NamedChain::Kusama\n                    | NamedChain::Polkadot\n            );\n    }\n    false\n}\n\n/// True if it supports broadcasting in batches.\npub fn has_batch_support(chain_id: u64) -> bool {\n    if let Some(chain) = Chain::from(chain_id).named() {\n        return !chain.is_arbitrum();\n    }\n    true\n}\n\n/// Helpers for loading configuration.\n///\n/// This is usually implemented through the macros defined in [`foundry_config`]. See\n/// [`foundry_config::impl_figment_convert`] for more details.\n///\n/// By default each function will emit warnings generated during loading, unless the `_no_warnings`\n/// variant is used.\npub trait LoadConfig {\n    /// Load the [`Config`] based on the options provided in self.\n    fn figment(&self) -> Figment;\n\n    /// Load and sanitize the [`Config`] based on the options provided in self.\n    fn load_config(&self) -> Result<Config, ExtractConfigError> {\n        self.load_config_no_warnings().inspect(emit_warnings)\n    }\n\n    /// Same as [`LoadConfig::load_config`] but does not emit warnings.\n    fn load_config_no_warnings(&self) -> Result<Config, ExtractConfigError> {\n        self.load_config_unsanitized_no_warnings().map(Config::sanitized)\n    }\n\n    /// Load [`Config`] but do not sanitize. See [`Config::sanitized`] for more information.\n    fn load_config_unsanitized(&self) -> Result<Config, ExtractConfigError> {\n        self.load_config_unsanitized_no_warnings().inspect(emit_warnings)\n    }\n\n    /// Same as [`LoadConfig::load_config_unsanitized`] but also emits warnings generated\n    fn load_config_unsanitized_no_warnings(&self) -> Result<Config, ExtractConfigError> {\n        Config::from_provider(self.figment())\n    }\n\n    /// Load and sanitize the [`Config`], as well as extract [`EvmOpts`] from self\n    fn load_config_and_evm_opts(&self) -> Result<(Config, EvmOpts)> {\n        self.load_config_and_evm_opts_no_warnings().inspect(|(config, _)| emit_warnings(config))\n    }\n\n    /// Same as [`LoadConfig::load_config_and_evm_opts`] but also emits warnings generated\n    fn load_config_and_evm_opts_no_warnings(&self) -> Result<(Config, EvmOpts)> {\n        let figment = self.figment();\n\n        let mut evm_opts = figment.extract::<EvmOpts>().map_err(ExtractConfigError::new)?;\n        let config = Config::from_provider(figment)?.sanitized();\n\n        // update the fork url if it was an alias\n        if let Some(fork_url) = config.get_rpc_url() {\n            trace!(target: \"forge::config\", ?fork_url, \"Update EvmOpts fork url\");\n            evm_opts.fork_url = Some(fork_url?.into_owned());\n        }\n\n        Ok((config, evm_opts))\n    }\n}\n\nimpl<T> LoadConfig for T\nwhere\n    for<'a> Figment: From<&'a T>,\n{\n    fn figment(&self) -> Figment {\n        self.into()\n    }\n}\n\nfn emit_warnings(config: &Config) {\n    for warning in &config.warnings {\n        let _ = sh_warn!(\"{warning}\");\n    }\n}\n\n/// Read contract constructor arguments from the given file.\npub fn read_constructor_args_file(constructor_args_path: PathBuf) -> Result<Vec<String>> {\n    if !constructor_args_path.exists() {\n        eyre::bail!(\"Constructor args file \\\"{}\\\" not found\", constructor_args_path.display());\n    }\n    let args = if constructor_args_path.extension() == Some(std::ffi::OsStr::new(\"json\")) {\n        read_json_file(&constructor_args_path).wrap_err(format!(\n            \"Constructor args file \\\"{}\\\" must encode a json array\",\n            constructor_args_path.display(),\n        ))?\n    } else {\n        fs::read_to_string(constructor_args_path)?.split_whitespace().map(str::to_string).collect()\n    };\n    Ok(args)\n}\n\n/// A slimmed down return from the executor used for returning minimal trace + gas metering info\n#[derive(Debug)]\npub struct TraceResult {\n    pub success: bool,\n    pub traces: Option<Traces>,\n    pub gas_used: u64,\n}\n\nimpl TraceResult {\n    /// Create a new [`TraceResult`] from a [`RawCallResult`].\n    pub fn from_raw(raw: RawCallResult, trace_kind: TraceKind) -> Self {\n        let RawCallResult { gas_used, traces, reverted, .. } = raw;\n        Self { success: !reverted, traces: traces.map(|arena| vec![(trace_kind, arena)]), gas_used }\n    }\n}\n\nimpl From<DeployResult> for TraceResult {\n    fn from(result: DeployResult) -> Self {\n        Self::from_raw(result.raw, TraceKind::Deployment)\n    }\n}\n\nimpl TryFrom<Result<DeployResult, EvmError>> for TraceResult {\n    type Error = EvmError;\n\n    fn try_from(value: Result<DeployResult, EvmError>) -> Result<Self, Self::Error> {\n        match value {\n            Ok(result) => Ok(Self::from(result)),\n            Err(EvmError::Execution(err)) => Ok(Self::from_raw(err.raw, TraceKind::Deployment)),\n            Err(err) => Err(err),\n        }\n    }\n}\n\nimpl From<RawCallResult> for TraceResult {\n    fn from(result: RawCallResult) -> Self {\n        Self::from_raw(result, TraceKind::Execution)\n    }\n}\n\nimpl TryFrom<Result<RawCallResult>> for TraceResult {\n    type Error = EvmError;\n\n    fn try_from(value: Result<RawCallResult>) -> Result<Self, Self::Error> {\n        match value {\n            Ok(result) => Ok(Self::from(result)),\n            Err(err) => Err(EvmError::from(err)),\n        }\n    }\n}\n\npub async fn print_traces(\n    result: &mut TraceResult,\n    decoder: &CallTraceDecoder,\n    verbose: bool,\n    state_changes: bool,\n    trace_depth: Option<usize>,\n) -> Result<()> {\n    let traces = result.traces.as_mut().expect(\"No traces found\");\n\n    if !shell::is_json() {\n        sh_println!(\"Traces:\")?;\n    }\n\n    for (_, arena) in traces {\n        decode_trace_arena(arena, decoder).await;\n\n        if let Some(trace_depth) = trace_depth {\n            prune_trace_depth(arena, trace_depth);\n        }\n\n        sh_println!(\"{}\", render_trace_arena_inner(arena, verbose, state_changes))?;\n    }\n\n    if shell::is_json() {\n        return Ok(());\n    }\n\n    sh_println!()?;\n    if result.success {\n        sh_println!(\"{}\", \"Transaction successfully executed.\".green())?;\n    } else {\n        sh_err!(\"Transaction failed.\")?;\n    }\n    sh_println!(\"Gas used: {}\", result.gas_used)?;\n\n    Ok(())\n}\n\n/// Traverse the artifacts in the project to generate local signatures and merge them into the cache\n/// file.\npub fn cache_local_signatures(output: &ProjectCompileOutput) -> Result<()> {\n    let Some(cache_dir) = Config::foundry_cache_dir() else {\n        eyre::bail!(\"Failed to get `cache_dir` to generate local signatures.\");\n    };\n    let path = cache_dir.join(\"signatures\");\n    let mut signatures = SignaturesCache::load(&path);\n    for (_, artifact) in output.artifacts() {\n        if let Some(abi) = &artifact.abi {\n            signatures.extend_from_abi(abi);\n        }\n\n        // External libraries don't have functions included in the ABI, but `methodIdentifiers`.\n        if let Some(method_identifiers) = &artifact.method_identifiers {\n            signatures.extend(method_identifiers.iter().filter_map(|(signature, selector)| {\n                Some((SelectorKind::Function(selector.parse().ok()?), signature.clone()))\n            }));\n        }\n    }\n    signatures.save(&path);\n    Ok(())\n}\n\n/// Traverses all files at `folder_path`, parses any JSON ABI files found,\n/// and caches their function/event/error signatures to the local signatures cache.\npub fn cache_signatures_from_abis(folder_path: impl AsRef<Path>) -> Result<()> {\n    let Some(cache_dir) = Config::foundry_cache_dir() else {\n        eyre::bail!(\"Failed to get `cache_dir` to generate local signatures.\");\n    };\n    let path = cache_dir.join(\"signatures\");\n    let mut signatures = SignaturesCache::load(&path);\n\n    json_files(folder_path.as_ref())\n        .filter_map(|path| std::fs::read_to_string(&path).ok())\n        .filter_map(|content| serde_json::from_str::<JsonAbi>(&content).ok())\n        .for_each(|json_abi| signatures.extend_from_abi(&json_abi));\n\n    signatures.save(&path);\n    Ok(())\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use std::fs;\n    use tempfile::tempdir;\n\n    #[test]\n    fn test_cache_signatures_from_abis() {\n        let temp_dir = tempdir().unwrap();\n        let abi_json = r#\"[\n              {\n                  \"type\": \"function\",\n                  \"name\": \"myCustomFunction\",\n                  \"inputs\": [{\"name\": \"amount\", \"type\": \"uint256\"}],\n                  \"outputs\": [],\n                  \"stateMutability\": \"nonpayable\"\n              },\n              {\n                  \"type\": \"event\",\n                  \"name\": \"MyCustomEvent\",\n                  \"inputs\": [{\"name\": \"value\", \"type\": \"uint256\", \"indexed\": false}],\n                  \"anonymous\": false\n              },\n              {\n                  \"type\": \"error\",\n                  \"name\": \"MyCustomError\",\n                  \"inputs\": [{\"name\": \"code\", \"type\": \"uint256\"}]\n              }\n          ]\"#;\n\n        let abi_path = temp_dir.path().join(\"test.json\");\n        fs::write(&abi_path, abi_json).unwrap();\n\n        cache_signatures_from_abis(temp_dir.path()).unwrap();\n\n        let cache_dir = Config::foundry_cache_dir().unwrap();\n        let cache_path = cache_dir.join(\"signatures\");\n        let cache = SignaturesCache::load(&cache_path);\n\n        let func_selector: alloy_primitives::Selector = \"0x2e2dbaf7\".parse().unwrap();\n        assert!(cache.contains_key(&SelectorKind::Function(func_selector)));\n\n        let event_selector: alloy_primitives::B256 =\n            \"0x8cc20c47f3a2463817352f75dec0dbf43a7a771b5f6817a92bd5724c1f4aa745\".parse().unwrap();\n        assert!(cache.contains_key(&SelectorKind::Event(event_selector)));\n\n        let error_selector: alloy_primitives::Selector = \"0xd35f45de\".parse().unwrap();\n        assert!(cache.contains_key(&SelectorKind::Error(error_selector)));\n    }\n}\n"
  },
  {
    "path": "crates/cli/src/utils/default_directives.txt",
    "content": "[\n    // Low level networking\n    \"hyper=off\",\n    \"hyper_util=off\",\n    \"h2=off\",\n    \"rustls=off\",\n    // Tokio\n    \"mio=off\",\n    // Too verbose\n    \"jsonpath_lib=off\",\n]\n"
  },
  {
    "path": "crates/cli/src/utils/mod.rs",
    "content": "use alloy_json_abi::JsonAbi;\nuse alloy_primitives::{Address, U256, map::HashMap};\nuse alloy_provider::{Network, Provider, RootProvider, network::AnyNetwork};\nuse eyre::{ContextCompat, Result};\nuse foundry_common::{provider::ProviderBuilder, shell};\nuse foundry_config::{Chain, Config};\nuse itertools::Itertools;\nuse path_slash::PathExt;\nuse regex::Regex;\nuse serde::de::DeserializeOwned;\nuse std::{\n    ffi::OsStr,\n    path::{Path, PathBuf},\n    process::{Command, Output, Stdio},\n    str::FromStr,\n    sync::LazyLock,\n    time::{Duration, SystemTime, UNIX_EPOCH},\n};\nuse tracing_subscriber::prelude::*;\n\nmod cmd;\npub use cmd::*;\n\nmod suggestions;\npub use suggestions::*;\n\nmod abi;\npub use abi::*;\n\nmod allocator;\npub use allocator::*;\n\n// reexport all `foundry_config::utils`\n#[doc(hidden)]\npub use foundry_config::utils::*;\n\n/// Deterministic fuzzer seed used for gas snapshots and coverage reports.\n///\n/// The keccak256 hash of \"foundry rulez\"\npub const STATIC_FUZZ_SEED: [u8; 32] = [\n    0x01, 0x00, 0xfa, 0x69, 0xa5, 0xf1, 0x71, 0x0a, 0x95, 0xcd, 0xef, 0x94, 0x88, 0x9b, 0x02, 0x84,\n    0x5d, 0x64, 0x0b, 0x19, 0xad, 0xf0, 0xe3, 0x57, 0xb8, 0xd4, 0xbe, 0x7d, 0x49, 0xee, 0x70, 0xe6,\n];\n\n/// Regex used to parse `.gitmodules` file and capture the submodule path and branch.\npub static SUBMODULE_BRANCH_REGEX: LazyLock<Regex> =\n    LazyLock::new(|| Regex::new(r#\"\\[submodule \"([^\"]+)\"\\](?:[^\\[]*?branch = ([^\\s]+))\"#).unwrap());\n/// Regex used to parse `git submodule status` output.\npub static SUBMODULE_STATUS_REGEX: LazyLock<Regex> =\n    LazyLock::new(|| Regex::new(r\"^[\\s+-]?([a-f0-9]+)\\s+([^\\s]+)(?:\\s+\\([^)]+\\))?$\").unwrap());\n\n/// Useful extensions to [`std::path::Path`].\npub trait FoundryPathExt {\n    /// Returns true if the [`Path`] ends with `.t.sol`\n    fn is_sol_test(&self) -> bool;\n\n    /// Returns true if the  [`Path`] has a `sol` extension\n    fn is_sol(&self) -> bool;\n\n    /// Returns true if the  [`Path`] has a `yul` extension\n    fn is_yul(&self) -> bool;\n}\n\nimpl<T: AsRef<Path>> FoundryPathExt for T {\n    fn is_sol_test(&self) -> bool {\n        self.as_ref()\n            .file_name()\n            .and_then(|s| s.to_str())\n            .map(|s| s.ends_with(\".t.sol\"))\n            .unwrap_or_default()\n    }\n\n    fn is_sol(&self) -> bool {\n        self.as_ref().extension() == Some(std::ffi::OsStr::new(\"sol\"))\n    }\n\n    fn is_yul(&self) -> bool {\n        self.as_ref().extension() == Some(std::ffi::OsStr::new(\"yul\"))\n    }\n}\n\n/// Initializes a tracing Subscriber for logging\npub fn subscriber() {\n    let registry = tracing_subscriber::Registry::default().with(env_filter());\n    #[cfg(feature = \"tracy\")]\n    let registry = registry.with(tracing_tracy::TracyLayer::default());\n    registry.with(tracing_subscriber::fmt::layer().with_writer(std::io::stderr)).init()\n}\n\nfn env_filter() -> tracing_subscriber::EnvFilter {\n    const DEFAULT_DIRECTIVES: &[&str] = &include!(\"./default_directives.txt\");\n    let mut filter = tracing_subscriber::EnvFilter::from_default_env();\n    for &directive in DEFAULT_DIRECTIVES {\n        filter = filter.add_directive(directive.parse().unwrap());\n    }\n    filter\n}\n\n/// Returns a [`RootProvider`] instantiated using [Config]'s RPC settings.\npub fn get_provider(config: &Config) -> Result<RootProvider<AnyNetwork>> {\n    get_provider_builder(config)?.build()\n}\n\n/// Returns a [ProviderBuilder] instantiated using [Config] values.\n///\n/// Defaults to `http://localhost:8545` and `Mainnet`.\npub fn get_provider_builder(config: &Config) -> Result<ProviderBuilder> {\n    ProviderBuilder::from_config(config)\n}\n\npub async fn get_chain<N, P>(chain: Option<Chain>, provider: P) -> Result<Chain>\nwhere\n    N: Network,\n    P: Provider<N>,\n{\n    match chain {\n        Some(chain) => Ok(chain),\n        None => Ok(Chain::from_id(provider.get_chain_id().await?)),\n    }\n}\n\n/// Parses an ether value from a string.\n///\n/// The amount can be tagged with a unit, e.g. \"1ether\".\n///\n/// If the string represents an untagged amount (e.g. \"100\") then\n/// it is interpreted as wei.\npub fn parse_ether_value(value: &str) -> Result<U256> {\n    Ok(if value.starts_with(\"0x\") {\n        U256::from_str_radix(value, 16)?\n    } else {\n        alloy_dyn_abi::DynSolType::coerce_str(&alloy_dyn_abi::DynSolType::Uint(256), value)?\n            .as_uint()\n            .wrap_err(\"Could not parse ether value from string\")?\n            .0\n    })\n}\n\n/// Parses a `T` from a string using [`serde_json::from_str`].\npub fn parse_json<T: DeserializeOwned>(value: &str) -> serde_json::Result<T> {\n    serde_json::from_str(value)\n}\n\n/// Parses a `Duration` from a &str\npub fn parse_delay(delay: &str) -> Result<Duration> {\n    let delay = if delay.ends_with(\"ms\") {\n        let d: u64 = delay.trim_end_matches(\"ms\").parse()?;\n        Duration::from_millis(d)\n    } else {\n        let d: f64 = delay.parse()?;\n        let delay = (d * 1000.0).round();\n        if delay.is_infinite() || delay.is_nan() || delay.is_sign_negative() {\n            eyre::bail!(\"delay must be finite and non-negative\");\n        }\n\n        Duration::from_millis(delay as u64)\n    };\n    Ok(delay)\n}\n\n/// Returns the current time as a [`Duration`] since the Unix epoch.\npub fn now() -> Duration {\n    SystemTime::now().duration_since(UNIX_EPOCH).expect(\"time went backwards\")\n}\n\n/// Common setup for all CLI tools. Does not include [tracing subscriber](subscriber).\npub fn common_setup() {\n    install_crypto_provider();\n    crate::handler::install();\n    load_dotenv();\n    enable_paint();\n}\n\n/// Loads a dotenv file, from the cwd and the project root, ignoring potential failure.\n///\n/// We could use `warn!` here, but that would imply that the dotenv file can't configure\n/// the logging behavior of Foundry.\n///\n/// Similarly, we could just use `eprintln!`, but colors are off limits otherwise dotenv is implied\n/// to not be able to configure the colors. It would also mess up the JSON output.\npub fn load_dotenv() {\n    let load = |p: &Path| {\n        dotenvy::from_path(p.join(\".env\")).ok();\n    };\n\n    // we only want the .env file of the cwd and project root\n    // `find_project_root` calls `current_dir` internally so both paths are either both `Ok` or\n    // both `Err`\n    if let (Ok(cwd), Ok(prj_root)) = (std::env::current_dir(), find_project_root(None)) {\n        load(&prj_root);\n        if cwd != prj_root {\n            // prj root and cwd can be identical\n            load(&cwd);\n        }\n    };\n}\n\n/// Sets the default [`yansi`] color output condition.\npub fn enable_paint() {\n    let enable = yansi::Condition::os_support() && yansi::Condition::tty_and_color_live();\n    yansi::whenever(yansi::Condition::cached(enable));\n}\n\n/// This force installs the default crypto provider.\n///\n/// This is necessary in case there are more than one available backends enabled in rustls (ring,\n/// aws-lc-rs).\n///\n/// This should be called high in the main fn.\n///\n/// See also:\n///   <https://github.com/snapview/tokio-tungstenite/issues/353#issuecomment-2455100010>\n///   <https://github.com/awslabs/aws-sdk-rust/discussions/1257>\npub fn install_crypto_provider() {\n    // https://github.com/snapview/tokio-tungstenite/issues/353\n    rustls::crypto::ring::default_provider()\n        .install_default()\n        .expect(\"Failed to install default rustls crypto provider\");\n}\n\n/// Fetches the ABI of a contract from Etherscan.\npub async fn fetch_abi_from_etherscan(\n    address: Address,\n    config: &foundry_config::Config,\n) -> Result<Vec<(JsonAbi, String)>> {\n    let chain = config.chain.unwrap_or_default();\n    let api_key = config.get_etherscan_api_key(Some(chain)).unwrap_or_default();\n    let client = foundry_block_explorers::Client::new(chain, api_key)?;\n    let source = client.contract_source_code(address).await?;\n    source.items.into_iter().map(|item| Ok((item.abi()?, item.contract_name))).collect()\n}\n\n/// Useful extensions to [`std::process::Command`].\npub trait CommandUtils {\n    /// Returns the command's output if execution is successful, otherwise, throws an error.\n    fn exec(&mut self) -> Result<Output>;\n\n    /// Returns the command's stdout if execution is successful, otherwise, throws an error.\n    fn get_stdout_lossy(&mut self) -> Result<String>;\n}\n\nimpl CommandUtils for Command {\n    #[track_caller]\n    fn exec(&mut self) -> Result<Output> {\n        trace!(command=?self, \"executing\");\n\n        let output = self.output()?;\n\n        trace!(code=?output.status.code(), ?output);\n\n        if output.status.success() {\n            Ok(output)\n        } else {\n            let stdout = String::from_utf8_lossy(&output.stdout);\n            let stdout = stdout.trim();\n            let stderr = String::from_utf8_lossy(&output.stderr);\n            let stderr = stderr.trim();\n            let msg = if stdout.is_empty() {\n                stderr.to_string()\n            } else if stderr.is_empty() {\n                stdout.to_string()\n            } else {\n                format!(\"stdout:\\n{stdout}\\n\\nstderr:\\n{stderr}\")\n            };\n\n            let mut name = self.get_program().to_string_lossy();\n            if let Some(arg) = self.get_args().next() {\n                let arg = arg.to_string_lossy();\n                if !arg.starts_with('-') {\n                    let name = name.to_mut();\n                    name.push(' ');\n                    name.push_str(&arg);\n                }\n            }\n\n            let mut err = match output.status.code() {\n                Some(code) => format!(\"{name} exited with code {code}\"),\n                None => format!(\"{name} terminated by a signal\"),\n            };\n            if !msg.is_empty() {\n                err.push(':');\n                err.push(if msg.lines().count() == 1 { ' ' } else { '\\n' });\n                err.push_str(&msg);\n            }\n            Err(eyre::eyre!(err))\n        }\n    }\n\n    #[track_caller]\n    fn get_stdout_lossy(&mut self) -> Result<String> {\n        let output = self.exec()?;\n        let stdout = String::from_utf8_lossy(&output.stdout);\n        Ok(stdout.trim().into())\n    }\n}\n\n#[derive(Clone, Copy, Debug)]\npub struct Git<'a> {\n    pub root: &'a Path,\n    pub quiet: bool,\n    pub shallow: bool,\n}\n\nimpl<'a> Git<'a> {\n    pub fn new(root: &'a Path) -> Self {\n        Self { root, quiet: shell::is_quiet(), shallow: false }\n    }\n\n    pub fn from_config(config: &'a Config) -> Self {\n        Self::new(config.root.as_path())\n    }\n\n    pub fn root_of(relative_to: &Path) -> Result<PathBuf> {\n        let output = Self::cmd_no_root()\n            .current_dir(relative_to)\n            .args([\"rev-parse\", \"--show-toplevel\"])\n            .get_stdout_lossy()?;\n        Ok(PathBuf::from(output))\n    }\n\n    pub fn clone_with_branch(\n        shallow: bool,\n        from: impl AsRef<OsStr>,\n        branch: impl AsRef<OsStr>,\n        to: Option<impl AsRef<OsStr>>,\n    ) -> Result<()> {\n        Self::cmd_no_root()\n            .stderr(Stdio::inherit())\n            .args([\"clone\", \"--recurse-submodules\"])\n            .args(shallow.then_some(\"--depth=1\"))\n            .args(shallow.then_some(\"--shallow-submodules\"))\n            .arg(\"-b\")\n            .arg(branch)\n            .arg(from)\n            .args(to)\n            .exec()\n            .map(drop)\n    }\n\n    pub fn clone(\n        shallow: bool,\n        from: impl AsRef<OsStr>,\n        to: Option<impl AsRef<OsStr>>,\n    ) -> Result<()> {\n        Self::cmd_no_root()\n            .stderr(Stdio::inherit())\n            .args([\"clone\", \"--recurse-submodules\"])\n            .args(shallow.then_some(\"--depth=1\"))\n            .args(shallow.then_some(\"--shallow-submodules\"))\n            .arg(from)\n            .args(to)\n            .exec()\n            .map(drop)\n    }\n\n    pub fn fetch(\n        self,\n        shallow: bool,\n        remote: impl AsRef<OsStr>,\n        branch: Option<impl AsRef<OsStr>>,\n    ) -> Result<()> {\n        self.cmd()\n            .stderr(Stdio::inherit())\n            .arg(\"fetch\")\n            .args(shallow.then_some(\"--no-tags\"))\n            .args(shallow.then_some(\"--depth=1\"))\n            .arg(remote)\n            .args(branch)\n            .exec()\n            .map(drop)\n    }\n\n    pub fn root(self, root: &Path) -> Git<'_> {\n        Git { root, ..self }\n    }\n\n    pub fn quiet(self, quiet: bool) -> Self {\n        Self { quiet, ..self }\n    }\n\n    /// True to perform shallow clones\n    pub fn shallow(self, shallow: bool) -> Self {\n        Self { shallow, ..self }\n    }\n\n    pub fn checkout(self, recursive: bool, tag: impl AsRef<OsStr>) -> Result<()> {\n        self.cmd()\n            .arg(\"checkout\")\n            .args(recursive.then_some(\"--recurse-submodules\"))\n            .arg(tag)\n            .exec()\n            .map(drop)\n    }\n\n    /// Returns the current HEAD commit hash of the current branch.\n    pub fn head(self) -> Result<String> {\n        self.cmd().args([\"rev-parse\", \"HEAD\"]).get_stdout_lossy()\n    }\n\n    pub fn checkout_at(self, tag: impl AsRef<OsStr>, at: &Path) -> Result<()> {\n        self.cmd_at(at).arg(\"checkout\").arg(tag).exec().map(drop)\n    }\n\n    pub fn init(self) -> Result<()> {\n        self.cmd().arg(\"init\").exec().map(drop)\n    }\n\n    pub fn current_rev_branch(self, at: &Path) -> Result<(String, String)> {\n        let rev = self.cmd_at(at).args([\"rev-parse\", \"HEAD\"]).get_stdout_lossy()?;\n        let branch =\n            self.cmd_at(at).args([\"rev-parse\", \"--abbrev-ref\", \"HEAD\"]).get_stdout_lossy()?;\n        Ok((rev, branch))\n    }\n\n    #[expect(clippy::should_implement_trait)] // this is not std::ops::Add clippy\n    pub fn add<I, S>(self, paths: I) -> Result<()>\n    where\n        I: IntoIterator<Item = S>,\n        S: AsRef<OsStr>,\n    {\n        self.cmd().arg(\"add\").args(paths).exec().map(drop)\n    }\n\n    pub fn reset(self, hard: bool, tree: impl AsRef<OsStr>) -> Result<()> {\n        self.cmd().arg(\"reset\").args(hard.then_some(\"--hard\")).arg(tree).exec().map(drop)\n    }\n\n    pub fn commit_tree(\n        self,\n        tree: impl AsRef<OsStr>,\n        msg: Option<impl AsRef<OsStr>>,\n    ) -> Result<String> {\n        self.cmd()\n            .arg(\"commit-tree\")\n            .arg(tree)\n            .args(msg.as_ref().is_some().then_some(\"-m\"))\n            .args(msg)\n            .get_stdout_lossy()\n    }\n\n    pub fn rm<I, S>(self, force: bool, paths: I) -> Result<()>\n    where\n        I: IntoIterator<Item = S>,\n        S: AsRef<OsStr>,\n    {\n        self.cmd().arg(\"rm\").args(force.then_some(\"--force\")).args(paths).exec().map(drop)\n    }\n\n    pub fn commit(self, msg: &str) -> Result<()> {\n        let output = self\n            .cmd()\n            .args([\"commit\", \"-m\", msg])\n            .args(cfg!(any(test, debug_assertions)).then_some(\"--no-gpg-sign\"))\n            .output()?;\n        if !output.status.success() {\n            let stdout = String::from_utf8_lossy(&output.stdout);\n            let stderr = String::from_utf8_lossy(&output.stderr);\n            // ignore \"nothing to commit\" error\n            let msg = \"nothing to commit, working tree clean\";\n            if !(stdout.contains(msg) || stderr.contains(msg)) {\n                return Err(eyre::eyre!(\n                    \"failed to commit (code={:?}, stdout={:?}, stderr={:?})\",\n                    output.status.code(),\n                    stdout.trim(),\n                    stderr.trim()\n                ));\n            }\n        }\n        Ok(())\n    }\n\n    pub fn is_in_repo(self) -> std::io::Result<bool> {\n        self.cmd().args([\"rev-parse\", \"--is-inside-work-tree\"]).status().map(|s| s.success())\n    }\n\n    pub fn is_repo_root(self) -> Result<bool> {\n        self.cmd().args([\"rev-parse\", \"--show-cdup\"]).get_stdout_lossy().map(|s| s.is_empty())\n    }\n\n    pub fn is_clean(self) -> Result<bool> {\n        self.cmd().args([\"status\", \"--porcelain\"]).exec().map(|out| out.stdout.is_empty())\n    }\n\n    pub fn has_branch(self, branch: impl AsRef<OsStr>, at: &Path) -> Result<bool> {\n        self.cmd_at(at)\n            .args([\"branch\", \"--list\", \"--no-color\"])\n            .arg(branch)\n            .get_stdout_lossy()\n            .map(|stdout| !stdout.is_empty())\n    }\n\n    pub fn has_tag(self, tag: impl AsRef<OsStr>, at: &Path) -> Result<bool> {\n        self.cmd_at(at)\n            .args([\"tag\", \"--list\"])\n            .arg(tag)\n            .get_stdout_lossy()\n            .map(|stdout| !stdout.is_empty())\n    }\n\n    pub fn has_rev(self, rev: impl AsRef<OsStr>, at: &Path) -> Result<bool> {\n        self.cmd_at(at)\n            .args([\"cat-file\", \"-t\"])\n            .arg(rev)\n            .get_stdout_lossy()\n            .map(|stdout| &stdout == \"commit\")\n    }\n\n    pub fn get_rev(self, tag_or_branch: impl AsRef<OsStr>, at: &Path) -> Result<String> {\n        self.cmd_at(at).args([\"rev-list\", \"-n\", \"1\"]).arg(tag_or_branch).get_stdout_lossy()\n    }\n\n    pub fn ensure_clean(self) -> Result<()> {\n        if self.is_clean()? {\n            Ok(())\n        } else {\n            Err(eyre::eyre!(\n                \"\\\nThe target directory is a part of or on its own an already initialized git repository,\nand it requires clean working and staging areas, including no untracked files.\n\nCheck the current git repository's status with `git status`.\nThen, you can track files with `git add ...` and then commit them with `git commit`,\nignore them in the `.gitignore` file.\"\n            ))\n        }\n    }\n\n    pub fn commit_hash(self, short: bool, revision: &str) -> Result<String> {\n        self.cmd()\n            .arg(\"rev-parse\")\n            .args(short.then_some(\"--short\"))\n            .arg(revision)\n            .get_stdout_lossy()\n    }\n\n    pub fn tag(self) -> Result<String> {\n        self.cmd().arg(\"tag\").get_stdout_lossy()\n    }\n\n    /// Returns the tag the commit first appeared in.\n    ///\n    /// E.g Take rev = `abc1234`. This commit can be found in multiple releases (tags).\n    /// Consider releases: `v0.1.0`, `v0.2.0`, `v0.3.0` in chronological order, `rev` first appeared\n    /// in `v0.2.0`.\n    ///\n    /// Hence, `tag_for_commit(\"abc1234\")` will return `v0.2.0`.\n    pub fn tag_for_commit(self, rev: &str, at: &Path) -> Result<Option<String>> {\n        self.cmd_at(at)\n            .args([\"tag\", \"--contains\"])\n            .arg(rev)\n            .get_stdout_lossy()\n            .map(|stdout| stdout.lines().next().map(str::to_string))\n    }\n\n    /// Returns a list of tuples of submodule paths and their respective branches.\n    ///\n    /// This function reads the `.gitmodules` file and returns the paths of all submodules that have\n    /// a branch. The paths are relative to the Git::root_of(git.root) and not lib/ directory.\n    ///\n    /// `at` is the dir in which the `.gitmodules` file is located, this is the git root.\n    /// `lib` is name of the directory where the submodules are located.\n    pub fn read_submodules_with_branch(\n        self,\n        at: &Path,\n        lib: &OsStr,\n    ) -> Result<HashMap<PathBuf, String>> {\n        // Read the .gitmodules file\n        let gitmodules = foundry_common::fs::read_to_string(at.join(\".gitmodules\"))?;\n\n        let paths = SUBMODULE_BRANCH_REGEX\n            .captures_iter(&gitmodules)\n            .map(|cap| {\n                let path_str = cap.get(1).unwrap().as_str();\n                let path = PathBuf::from_str(path_str).unwrap();\n                trace!(path = %path.display(), \"unstripped path\");\n\n                // Keep only the components that come after the lib directory.\n                // This needs to be done because the lockfile uses paths relative foundry project\n                // root whereas .gitmodules use paths relative to the git root which may not be the\n                // project root. e.g monorepo.\n                // Hence, if path is lib/solady, then `lib/solady` is kept. if path is\n                // packages/contract-bedrock/lib/solady, then `lib/solady` is kept.\n                let lib_pos = path.components().find_position(|c| c.as_os_str() == lib);\n                let path = path\n                    .components()\n                    .skip(lib_pos.map(|(i, _)| i).unwrap_or(0))\n                    .collect::<PathBuf>();\n\n                let branch = cap.get(2).unwrap().as_str().to_string();\n                (path, branch)\n            })\n            .collect::<HashMap<_, _>>();\n\n        Ok(paths)\n    }\n\n    pub fn has_missing_dependencies<I, S>(self, paths: I) -> Result<bool>\n    where\n        I: IntoIterator<Item = S>,\n        S: AsRef<OsStr>,\n    {\n        self.cmd()\n            .args([\"submodule\", \"status\"])\n            .args(paths)\n            .get_stdout_lossy()\n            .map(|stdout| stdout.lines().any(|line| line.starts_with('-')))\n    }\n\n    /// Returns true if the given path has submodules by checking `git submodule status`\n    pub fn has_submodules<I, S>(self, paths: I) -> Result<bool>\n    where\n        I: IntoIterator<Item = S>,\n        S: AsRef<OsStr>,\n    {\n        self.cmd()\n            .args([\"submodule\", \"status\"])\n            .args(paths)\n            .get_stdout_lossy()\n            .map(|stdout| stdout.trim().lines().next().is_some())\n    }\n\n    pub fn submodule_add(\n        self,\n        force: bool,\n        url: impl AsRef<OsStr>,\n        path: impl AsRef<OsStr>,\n    ) -> Result<()> {\n        self.cmd()\n            .stderr(self.stderr())\n            .args([\"submodule\", \"add\"])\n            .args(self.shallow.then_some(\"--depth=1\"))\n            .args(force.then_some(\"--force\"))\n            .arg(url)\n            .arg(path)\n            .exec()\n            .map(drop)\n    }\n\n    pub fn submodule_update<I, S>(\n        self,\n        force: bool,\n        remote: bool,\n        no_fetch: bool,\n        recursive: bool,\n        paths: I,\n    ) -> Result<()>\n    where\n        I: IntoIterator<Item = S>,\n        S: AsRef<OsStr>,\n    {\n        self.cmd()\n            .stderr(self.stderr())\n            .args([\"submodule\", \"update\", \"--progress\", \"--init\"])\n            .args(self.shallow.then_some(\"--depth=1\"))\n            .args(force.then_some(\"--force\"))\n            .args(remote.then_some(\"--remote\"))\n            .args(no_fetch.then_some(\"--no-fetch\"))\n            .args(recursive.then_some(\"--recursive\"))\n            .args(paths)\n            .exec()\n            .map(drop)\n    }\n\n    pub fn submodule_foreach(self, recursive: bool, cmd: impl AsRef<OsStr>) -> Result<()> {\n        self.cmd()\n            .stderr(self.stderr())\n            .args([\"submodule\", \"foreach\"])\n            .args(recursive.then_some(\"--recursive\"))\n            .arg(cmd)\n            .exec()\n            .map(drop)\n    }\n\n    /// If the status is prefix with `-`, the submodule is not initialized.\n    ///\n    /// Ref: <https://git-scm.com/docs/git-submodule#Documentation/git-submodule.txt-status--cached--recursive--ltpathgt82308203>\n    pub fn submodules_uninitialized(self) -> Result<bool> {\n        // keep behavior consistent with `has_missing_dependencies`, but avoid duplicating the\n        // \"submodule status has '-' prefix\" logic.\n        self.has_missing_dependencies(std::iter::empty::<&OsStr>())\n    }\n\n    /// Initializes the git submodules.\n    pub fn submodule_init(self) -> Result<()> {\n        self.cmd().stderr(self.stderr()).args([\"submodule\", \"init\"]).exec().map(drop)\n    }\n\n    pub fn submodules(&self) -> Result<Submodules> {\n        self.cmd().args([\"submodule\", \"status\"]).get_stdout_lossy().map(|stdout| stdout.parse())?\n    }\n\n    pub fn submodule_sync(self) -> Result<()> {\n        self.cmd().stderr(self.stderr()).args([\"submodule\", \"sync\"]).exec().map(drop)\n    }\n\n    /// Get the URL of a submodule from git config\n    pub fn submodule_url(self, path: &Path) -> Result<Option<String>> {\n        self.cmd()\n            .args([\"config\", \"--get\", &format!(\"submodule.{}.url\", path.to_slash_lossy())])\n            .get_stdout_lossy()\n            .map(|url| Some(url.trim().to_string()))\n    }\n\n    pub fn cmd(self) -> Command {\n        let mut cmd = Self::cmd_no_root();\n        cmd.current_dir(self.root);\n        cmd\n    }\n\n    pub fn cmd_at(self, path: &Path) -> Command {\n        let mut cmd = Self::cmd_no_root();\n        cmd.current_dir(path);\n        cmd\n    }\n\n    pub fn cmd_no_root() -> Command {\n        let mut cmd = Command::new(\"git\");\n        cmd.stdout(Stdio::piped()).stderr(Stdio::piped());\n        cmd\n    }\n\n    // don't set this in cmd() because it's not wanted for all commands\n    fn stderr(self) -> Stdio {\n        if self.quiet { Stdio::piped() } else { Stdio::inherit() }\n    }\n}\n\n/// Deserialized `git submodule status lib/dep` output.\n#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq, Eq)]\npub struct Submodule {\n    /// Current commit hash the submodule is checked out at.\n    rev: String,\n    /// Relative path to the submodule.\n    path: PathBuf,\n}\n\nimpl Submodule {\n    pub fn new(rev: String, path: PathBuf) -> Self {\n        Self { rev, path }\n    }\n\n    pub fn rev(&self) -> &str {\n        &self.rev\n    }\n\n    pub fn path(&self) -> &PathBuf {\n        &self.path\n    }\n}\n\nimpl FromStr for Submodule {\n    type Err = eyre::Report;\n\n    fn from_str(s: &str) -> Result<Self> {\n        let caps = SUBMODULE_STATUS_REGEX\n            .captures(s)\n            .ok_or_else(|| eyre::eyre!(\"Invalid submodule status format\"))?;\n\n        Ok(Self {\n            rev: caps.get(1).unwrap().as_str().to_string(),\n            path: PathBuf::from(caps.get(2).unwrap().as_str()),\n        })\n    }\n}\n\n/// Deserialized `git submodule status` output.\n#[derive(Debug, Clone, PartialEq, Eq)]\npub struct Submodules(pub Vec<Submodule>);\n\nimpl Submodules {\n    pub fn len(&self) -> usize {\n        self.0.len()\n    }\n\n    pub fn is_empty(&self) -> bool {\n        self.0.is_empty()\n    }\n}\n\nimpl FromStr for Submodules {\n    type Err = eyre::Report;\n\n    fn from_str(s: &str) -> Result<Self> {\n        let subs = s.lines().map(str::parse).collect::<Result<Vec<Submodule>>>()?;\n        Ok(Self(subs))\n    }\n}\n\nimpl<'a> IntoIterator for &'a Submodules {\n    type Item = &'a Submodule;\n    type IntoIter = std::slice::Iter<'a, Submodule>;\n\n    fn into_iter(self) -> Self::IntoIter {\n        self.0.iter()\n    }\n}\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use foundry_common::fs;\n    use std::{env, fs::File, io::Write};\n    use tempfile::tempdir;\n\n    #[test]\n    fn parse_submodule_status() {\n        let s = \"+8829465a08cac423dcf59852f21e448449c1a1a8 lib/openzeppelin-contracts (v4.8.0-791-g8829465a)\";\n        let sub = Submodule::from_str(s).unwrap();\n        assert_eq!(sub.rev(), \"8829465a08cac423dcf59852f21e448449c1a1a8\");\n        assert_eq!(sub.path(), Path::new(\"lib/openzeppelin-contracts\"));\n\n        let s = \"-8829465a08cac423dcf59852f21e448449c1a1a8 lib/openzeppelin-contracts\";\n        let sub = Submodule::from_str(s).unwrap();\n        assert_eq!(sub.rev(), \"8829465a08cac423dcf59852f21e448449c1a1a8\");\n        assert_eq!(sub.path(), Path::new(\"lib/openzeppelin-contracts\"));\n\n        let s = \"8829465a08cac423dcf59852f21e448449c1a1a8 lib/openzeppelin-contracts\";\n        let sub = Submodule::from_str(s).unwrap();\n        assert_eq!(sub.rev(), \"8829465a08cac423dcf59852f21e448449c1a1a8\");\n        assert_eq!(sub.path(), Path::new(\"lib/openzeppelin-contracts\"));\n    }\n\n    #[test]\n    fn parse_multiline_submodule_status() {\n        let s = r#\"+d3db4ef90a72b7d24aa5a2e5c649593eaef7801d lib/forge-std (v1.9.4-6-gd3db4ef)\n+8829465a08cac423dcf59852f21e448449c1a1a8 lib/openzeppelin-contracts (v4.8.0-791-g8829465a)\n\"#;\n        let subs = Submodules::from_str(s).unwrap().0;\n        assert_eq!(subs.len(), 2);\n        assert_eq!(subs[0].rev(), \"d3db4ef90a72b7d24aa5a2e5c649593eaef7801d\");\n        assert_eq!(subs[0].path(), Path::new(\"lib/forge-std\"));\n        assert_eq!(subs[1].rev(), \"8829465a08cac423dcf59852f21e448449c1a1a8\");\n        assert_eq!(subs[1].path(), Path::new(\"lib/openzeppelin-contracts\"));\n    }\n\n    #[test]\n    fn foundry_path_ext_works() {\n        let p = Path::new(\"contracts/MyTest.t.sol\");\n        assert!(p.is_sol_test());\n        assert!(p.is_sol());\n        let p = Path::new(\"contracts/Greeter.sol\");\n        assert!(!p.is_sol_test());\n    }\n\n    // loads .env from cwd and project dir, See [`find_project_root()`]\n    #[test]\n    fn can_load_dotenv() {\n        let temp = tempdir().unwrap();\n        Git::new(temp.path()).init().unwrap();\n        let cwd_env = temp.path().join(\".env\");\n        fs::create_file(temp.path().join(\"foundry.toml\")).unwrap();\n        let nested = temp.path().join(\"nested\");\n        fs::create_dir(&nested).unwrap();\n\n        let mut cwd_file = File::create(cwd_env).unwrap();\n        let mut prj_file = File::create(nested.join(\".env\")).unwrap();\n\n        cwd_file.write_all(\"TESTCWDKEY=cwd_val\".as_bytes()).unwrap();\n        cwd_file.sync_all().unwrap();\n\n        prj_file.write_all(\"TESTPRJKEY=prj_val\".as_bytes()).unwrap();\n        prj_file.sync_all().unwrap();\n\n        let cwd = env::current_dir().unwrap();\n        env::set_current_dir(nested).unwrap();\n        load_dotenv();\n        env::set_current_dir(cwd).unwrap();\n\n        assert_eq!(env::var(\"TESTCWDKEY\").unwrap(), \"cwd_val\");\n        assert_eq!(env::var(\"TESTPRJKEY\").unwrap(), \"prj_val\");\n    }\n\n    #[test]\n    fn test_read_gitmodules_regex() {\n        let gitmodules = r#\"\n        [submodule \"lib/solady\"]\n        path = lib/solady\n        url = \"\"\n        branch = v0.1.0\n        [submodule \"lib/openzeppelin-contracts\"]\n        path = lib/openzeppelin-contracts\n        url = \"\"\n        branch = v4.8.0-791-g8829465a\n        [submodule \"lib/forge-std\"]\n        path = lib/forge-std\n        url = \"\"\n\"#;\n\n        let paths = SUBMODULE_BRANCH_REGEX\n            .captures_iter(gitmodules)\n            .map(|cap| {\n                (\n                    PathBuf::from_str(cap.get(1).unwrap().as_str()).unwrap(),\n                    String::from(cap.get(2).unwrap().as_str()),\n                )\n            })\n            .collect::<HashMap<_, _>>();\n\n        assert_eq!(paths.get(Path::new(\"lib/solady\")).unwrap(), \"v0.1.0\");\n        assert_eq!(\n            paths.get(Path::new(\"lib/openzeppelin-contracts\")).unwrap(),\n            \"v4.8.0-791-g8829465a\"\n        );\n\n        let no_branch_gitmodules = r#\"\n        [submodule \"lib/solady\"]\n        path = lib/solady\n        url = \"\"\n        [submodule \"lib/openzeppelin-contracts\"]\n        path = lib/openzeppelin-contracts\n        url = \"\"\n        [submodule \"lib/forge-std\"]\n        path = lib/forge-std\n        url = \"\"\n\"#;\n        let paths = SUBMODULE_BRANCH_REGEX\n            .captures_iter(no_branch_gitmodules)\n            .map(|cap| {\n                (\n                    PathBuf::from_str(cap.get(1).unwrap().as_str()).unwrap(),\n                    String::from(cap.get(2).unwrap().as_str()),\n                )\n            })\n            .collect::<HashMap<_, _>>();\n\n        assert!(paths.is_empty());\n\n        let branch_in_between = r#\"\n        [submodule \"lib/solady\"]\n        path = lib/solady\n        url = \"\"\n        [submodule \"lib/openzeppelin-contracts\"]\n        path = lib/openzeppelin-contracts\n        url = \"\"\n        branch = v4.8.0-791-g8829465a\n        [submodule \"lib/forge-std\"]\n        path = lib/forge-std\n        url = \"\"\n        \"#;\n\n        let paths = SUBMODULE_BRANCH_REGEX\n            .captures_iter(branch_in_between)\n            .map(|cap| {\n                (\n                    PathBuf::from_str(cap.get(1).unwrap().as_str()).unwrap(),\n                    String::from(cap.get(2).unwrap().as_str()),\n                )\n            })\n            .collect::<HashMap<_, _>>();\n\n        assert_eq!(paths.len(), 1);\n        assert_eq!(\n            paths.get(Path::new(\"lib/openzeppelin-contracts\")).unwrap(),\n            \"v4.8.0-791-g8829465a\"\n        );\n    }\n}\n"
  },
  {
    "path": "crates/cli/src/utils/suggestions.rs",
    "content": "//! Helper functions for suggesting alternative values for a possibly erroneous user input.\n\n/// Filters multiple strings from a given list of possible values which are similar\n/// to the passed in value `v` within a certain confidence by least confidence.\n///\n/// The jaro winkler similarity boosts candidates that have a common prefix, which is often the case\n/// in the event of typos. Thus, in a list of possible values like [\"foo\", \"bar\"], the value \"fop\"\n/// will yield `Some(\"foo\")`, whereas \"blark\" would yield `None`.\npub fn did_you_mean<T, I>(v: &str, candidates: I) -> Vec<String>\nwhere\n    T: AsRef<str>,\n    I: IntoIterator<Item = T>,\n{\n    let mut candidates: Vec<(f64, String)> = candidates\n        .into_iter()\n        .map(|pv| (strsim::jaro_winkler(v, pv.as_ref()), pv.as_ref().to_owned()))\n        .filter(|(similarity, _)| *similarity > 0.8)\n        .collect();\n    candidates.sort_by(|a, b| a.0.total_cmp(&b.0));\n    candidates.into_iter().map(|(_, pv)| pv).collect()\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn possible_artifacts_match() {\n        let candidates = [\"MyContract\", \"Erc20\"];\n        assert_eq!(\n            did_you_mean(\"MyCtrac\", candidates.iter()).pop(),\n            Some(\"MyContract\".to_string())\n        );\n    }\n\n    #[test]\n    fn possible_artifacts_nomatch() {\n        let candidates = [\"MyContract\", \"Erc20\", \"Greeter\"];\n        assert!(did_you_mean(\"Vault\", candidates.iter()).pop().is_none());\n    }\n}\n"
  },
  {
    "path": "crates/cli-markdown/Cargo.toml",
    "content": "[package]\nname = \"foundry-cli-markdown\"\ndescription = \"Generate Markdown documentation for clap CLIs\"\nversion.workspace = true\nedition.workspace = true\nrust-version.workspace = true\nauthors.workspace = true\nlicense.workspace = true\nhomepage.workspace = true\nrepository.workspace = true\n\n[lints]\nworkspace = true\n\n[dependencies]\nclap = { version = \"4\", features = [\"env\"] }\n\n[dev-dependencies]\nclap = { version = \"4\", features = [\"derive\"] }\npretty_assertions = \"1\"\n"
  },
  {
    "path": "crates/cli-markdown/src/lib.rs",
    "content": "//! Generate Markdown documentation for clap command-line tools.\n//!\n//! This is a fork of [`clap-markdown`](https://crates.io/crates/clap-markdown) with the following\n//! enhancements:\n//! - Support for grouped options by help heading ([PR #48](https://github.com/ConnorGray/clap-markdown/pull/48))\n//! - Show environment variable names for arguments ([PR #50](https://github.com/ConnorGray/clap-markdown/pull/50))\n//! - Add version information to generated Markdown ([PR #52](https://github.com/ConnorGray/clap-markdown/pull/52))\n\nuse std::{\n    collections::BTreeMap,\n    fmt::{self, Write},\n};\n\nuse clap::builder::PossibleValue;\n\n/// Options to customize the structure of the output Markdown document.\n#[non_exhaustive]\npub struct MarkdownOptions {\n    title: Option<String>,\n    show_footer: bool,\n    show_table_of_contents: bool,\n    show_aliases: bool,\n}\n\nimpl MarkdownOptions {\n    /// Construct a default instance of `MarkdownOptions`.\n    pub fn new() -> Self {\n        Self { title: None, show_footer: true, show_table_of_contents: true, show_aliases: true }\n    }\n\n    /// Set a custom title to use in the generated document.\n    pub fn title(mut self, title: String) -> Self {\n        self.title = Some(title);\n        self\n    }\n\n    /// Whether to show the default footer advertising `clap-markdown`.\n    pub fn show_footer(mut self, show: bool) -> Self {\n        self.show_footer = show;\n        self\n    }\n\n    /// Whether to show the default table of contents.\n    pub fn show_table_of_contents(mut self, show: bool) -> Self {\n        self.show_table_of_contents = show;\n        self\n    }\n\n    /// Whether to show aliases for arguments and commands.\n    pub fn show_aliases(mut self, show: bool) -> Self {\n        self.show_aliases = show;\n        self\n    }\n}\n\nimpl Default for MarkdownOptions {\n    fn default() -> Self {\n        Self::new()\n    }\n}\n\n/// Format the help information for `command` as Markdown.\npub fn help_markdown<C: clap::CommandFactory>() -> String {\n    let command = C::command();\n    help_markdown_command(&command)\n}\n\n/// Format the help information for `command` as Markdown, with custom options.\npub fn help_markdown_custom<C: clap::CommandFactory>(options: &MarkdownOptions) -> String {\n    let command = C::command();\n    help_markdown_command_custom(&command, options)\n}\n\n/// Format the help information for `command` as Markdown.\npub fn help_markdown_command(command: &clap::Command) -> String {\n    help_markdown_command_custom(command, &Default::default())\n}\n\n/// Format the help information for `command` as Markdown, with custom options.\npub fn help_markdown_command_custom(command: &clap::Command, options: &MarkdownOptions) -> String {\n    let mut buffer = String::with_capacity(100);\n    write_help_markdown(&mut buffer, command, options);\n    buffer\n}\n\n/// Format the help information for `command` as Markdown and print it.\n///\n/// Output is printed to the standard output.\n#[allow(clippy::disallowed_macros)]\npub fn print_help_markdown<C: clap::CommandFactory>() {\n    let command = C::command();\n    let mut buffer = String::with_capacity(100);\n    write_help_markdown(&mut buffer, &command, &Default::default());\n    println!(\"{buffer}\");\n}\n\nfn write_help_markdown(buffer: &mut String, command: &clap::Command, options: &MarkdownOptions) {\n    let title_name = get_canonical_name(command);\n\n    let title = match options.title {\n        Some(ref title) => title.to_owned(),\n        None => format!(\"Command-Line Help for `{title_name}`\"),\n    };\n    writeln!(buffer, \"# {title}\\n\",).unwrap();\n\n    writeln!(\n        buffer,\n        \"This document contains the help content for the `{title_name}` command-line program.\\n\",\n    )\n    .unwrap();\n\n    // Write the version if available (PR #52)\n    if let Some(version) = command.get_version() {\n        let version_str = version.to_string();\n\n        if version_str.contains('\\n') {\n            // Multi-line version: use a code block\n            writeln!(buffer, \"**Version:**\\n\\n```\\n{}\\n```\\n\", version_str.trim()).unwrap();\n        } else {\n            // Single-line version: use inline code\n            writeln!(buffer, \"**Version:** `{version_str}`\\n\").unwrap();\n        }\n    }\n\n    // Write the table of contents\n    if options.show_table_of_contents {\n        writeln!(buffer, \"**Command Overview:**\\n\").unwrap();\n        build_table_of_contents_markdown(buffer, Vec::new(), command, 0).unwrap();\n        writeln!(buffer).unwrap();\n    }\n\n    // Write the commands/subcommands sections\n    build_command_markdown(buffer, Vec::new(), command, 0, options).unwrap();\n\n    // Write the footer\n    if options.show_footer {\n        write!(\n            buffer,\n            r#\"<hr/>\n\n<small><i>\n    This document was generated automatically by\n    <a href=\"https://crates.io/crates/clap-markdown\"><code>clap-markdown</code></a>.\n</i></small>\n\"#\n        )\n        .unwrap();\n    }\n}\n\nfn build_table_of_contents_markdown(\n    buffer: &mut String,\n    parent_command_path: Vec<String>,\n    command: &clap::Command,\n    _depth: usize,\n) -> std::fmt::Result {\n    // Don't document commands marked with `clap(hide = true)`\n    if command.is_hide_set() {\n        return Ok(());\n    }\n\n    let title_name = get_canonical_name(command);\n\n    let command_path = {\n        let mut command_path = parent_command_path;\n        command_path.push(title_name);\n        command_path\n    };\n\n    writeln!(buffer, \"* [`{}`↴](#{})\", command_path.join(\" \"), command_path.join(\"-\"),)?;\n\n    for subcommand in command.get_subcommands() {\n        build_table_of_contents_markdown(buffer, command_path.clone(), subcommand, _depth + 1)?;\n    }\n\n    Ok(())\n}\n\nfn build_command_markdown(\n    buffer: &mut String,\n    parent_command_path: Vec<String>,\n    command: &clap::Command,\n    _depth: usize,\n    options: &MarkdownOptions,\n) -> std::fmt::Result {\n    // Don't document commands marked with `clap(hide = true)`\n    if command.is_hide_set() {\n        return Ok(());\n    }\n\n    let title_name = get_canonical_name(command);\n\n    let command_path = {\n        let mut command_path = parent_command_path.clone();\n        command_path.push(title_name);\n        command_path\n    };\n\n    // Write the markdown heading\n    writeln!(buffer, \"## `{}`\\n\", command_path.join(\" \"))?;\n\n    if let Some(long_about) = command.get_long_about() {\n        writeln!(buffer, \"{long_about}\\n\")?;\n    } else if let Some(about) = command.get_about() {\n        writeln!(buffer, \"{about}\\n\")?;\n    }\n\n    if let Some(help) = command.get_before_long_help() {\n        writeln!(buffer, \"{help}\\n\")?;\n    } else if let Some(help) = command.get_before_help() {\n        writeln!(buffer, \"{help}\\n\")?;\n    }\n\n    writeln!(\n        buffer,\n        \"**Usage:** `{}{}`\\n\",\n        if parent_command_path.is_empty() {\n            String::new()\n        } else {\n            let mut s = parent_command_path.join(\" \");\n            s.push(' ');\n            s\n        },\n        command.clone().render_usage().to_string().replace(\"Usage: \", \"\")\n    )?;\n\n    if options.show_aliases {\n        let aliases = command.get_visible_aliases().collect::<Vec<&str>>();\n        if let Some(aliases_str) = get_alias_string(&aliases) {\n            writeln!(\n                buffer,\n                \"**{}:** {aliases_str}\\n\",\n                pluralize(aliases.len(), \"Command Alias\", \"Command Aliases\")\n            )?;\n        }\n    }\n\n    if let Some(help) = command.get_after_long_help() {\n        writeln!(buffer, \"{help}\\n\")?;\n    } else if let Some(help) = command.get_after_help() {\n        writeln!(buffer, \"{help}\\n\")?;\n    }\n\n    // Subcommands\n    if command.get_subcommands().next().is_some() {\n        writeln!(buffer, \"###### **Subcommands:**\\n\")?;\n\n        for subcommand in command.get_subcommands() {\n            if subcommand.is_hide_set() {\n                continue;\n            }\n\n            let title_name = get_canonical_name(subcommand);\n            let about = match subcommand.get_about() {\n                Some(about) => about.to_string(),\n                None => String::new(),\n            };\n\n            writeln!(buffer, \"* `{title_name}` — {about}\",)?;\n        }\n\n        writeln!(buffer)?;\n    }\n\n    // Arguments (positional)\n    if command.get_positionals().next().is_some() {\n        writeln!(buffer, \"###### **Arguments:**\\n\")?;\n\n        for pos_arg in command.get_positionals() {\n            write_arg_markdown(buffer, pos_arg)?;\n        }\n\n        writeln!(buffer)?;\n    }\n\n    // Options (grouped by help heading) - PR #48\n    let non_pos: Vec<_> =\n        command.get_arguments().filter(|arg| !arg.is_positional() && !arg.is_hide_set()).collect();\n\n    if !non_pos.is_empty() {\n        // Group arguments by help heading\n        let mut grouped_args: BTreeMap<&str, Vec<&clap::Arg>> = BTreeMap::new();\n\n        for arg in non_pos {\n            let heading = arg.get_help_heading().unwrap_or(\"Options\");\n            grouped_args.entry(heading).or_default().push(arg);\n        }\n\n        // Write each group with its heading\n        for (heading, args) in grouped_args {\n            writeln!(buffer, \"###### **{heading}:**\\n\")?;\n\n            for arg in args {\n                write_arg_markdown(buffer, arg)?;\n            }\n\n            writeln!(buffer)?;\n        }\n    }\n\n    // Include extra space between commands\n    write!(buffer, \"\\n\\n\")?;\n\n    for subcommand in command.get_subcommands() {\n        build_command_markdown(buffer, command_path.clone(), subcommand, _depth + 1, options)?;\n    }\n\n    Ok(())\n}\n\nfn write_arg_markdown(buffer: &mut String, arg: &clap::Arg) -> fmt::Result {\n    // Markdown list item\n    write!(buffer, \"* \")?;\n\n    let value_name: String = match arg.get_value_names() {\n        Some([name, ..]) => name.as_str().to_owned(),\n        Some([]) => unreachable!(\"clap Arg::get_value_names() returned Some(..) of empty list\"),\n        None => arg.get_id().to_string().to_ascii_uppercase(),\n    };\n\n    match (arg.get_short(), arg.get_long()) {\n        (Some(short), Some(long)) => {\n            if arg.get_action().takes_values() {\n                write!(buffer, \"`-{short}`, `--{long} <{value_name}>`\")?\n            } else {\n                write!(buffer, \"`-{short}`, `--{long}`\")?\n            }\n        }\n        (Some(short), None) => {\n            if arg.get_action().takes_values() {\n                write!(buffer, \"`-{short} <{value_name}>`\")?\n            } else {\n                write!(buffer, \"`-{short}`\")?\n            }\n        }\n        (None, Some(long)) => {\n            if arg.get_action().takes_values() {\n                write!(buffer, \"`--{long} <{value_name}>`\")?\n            } else {\n                write!(buffer, \"`--{long}`\")?\n            }\n        }\n        (None, None) => {\n            debug_assert!(\n                arg.is_positional(),\n                \"unexpected non-positional Arg with neither short nor long name: {arg:?}\"\n            );\n            write!(buffer, \"`<{value_name}>`\",)?;\n        }\n    }\n\n    if let Some(aliases) = arg.get_visible_aliases().as_deref()\n        && let Some(aliases_str) = get_alias_string(aliases)\n    {\n        write!(buffer, \" [{}: {aliases_str}]\", pluralize(aliases.len(), \"alias\", \"aliases\"))?;\n    }\n\n    if let Some(help) = arg.get_long_help() {\n        buffer.push_str(&indent(&help.to_string(), \" — \", \"   \"))\n    } else if let Some(short_help) = arg.get_help() {\n        writeln!(buffer, \" — {short_help}\")?;\n    } else {\n        writeln!(buffer)?;\n    }\n\n    // Arg default values\n    if !arg.get_default_values().is_empty() {\n        let default_values: String = arg\n            .get_default_values()\n            .iter()\n            .map(|value| format!(\"`{}`\", value.to_string_lossy()))\n            .collect::<Vec<String>>()\n            .join(\", \");\n\n        if arg.get_default_values().len() > 1 {\n            writeln!(buffer, \"\\n  Default values: {default_values}\")?;\n        } else {\n            writeln!(buffer, \"\\n  Default value: {default_values}\")?;\n        }\n    }\n\n    // Arg possible values\n    let possible_values: Vec<PossibleValue> =\n        arg.get_possible_values().into_iter().filter(|pv| !pv.is_hide_set()).collect();\n\n    if !possible_values.is_empty() && !matches!(arg.get_action(), clap::ArgAction::SetTrue) {\n        let any_have_help: bool = possible_values.iter().any(|pv| pv.get_help().is_some());\n\n        if any_have_help {\n            let text: String = possible_values\n                .iter()\n                .map(|pv| match pv.get_help() {\n                    Some(help) => {\n                        format!(\"  - `{}`:\\n    {}\\n\", pv.get_name(), help)\n                    }\n                    None => format!(\"  - `{}`\\n\", pv.get_name()),\n                })\n                .collect::<Vec<String>>()\n                .join(\"\");\n\n            writeln!(buffer, \"\\n  Possible values:\\n{text}\")?;\n        } else {\n            let text: String = possible_values\n                .iter()\n                .map(|pv| format!(\"`{}`\", pv.get_name()))\n                .collect::<Vec<String>>()\n                .join(\", \");\n\n            writeln!(buffer, \"\\n  Possible values: {text}\\n\")?;\n        }\n    }\n\n    // Arg environment variable (PR #50)\n    if !arg.is_hide_env_set()\n        && let Some(env) = arg.get_env()\n    {\n        writeln!(buffer, \"\\n  Environment variable: `{}`\", env.to_string_lossy())?;\n    }\n\n    Ok(())\n}\n\n/// Utility function to get the canonical name of a command.\nfn get_canonical_name(command: &clap::Command) -> String {\n    command\n        .get_display_name()\n        .or_else(|| command.get_bin_name())\n        .map(|name| name.to_owned())\n        .unwrap_or_else(|| command.get_name().to_owned())\n}\n\n/// Indents non-empty lines. The output always ends with a newline.\nfn indent(s: &str, first: &str, rest: &str) -> String {\n    if s.is_empty() {\n        return \"\\n\".to_string();\n    }\n    let mut result = String::new();\n    let mut first_line = true;\n\n    for line in s.lines() {\n        if !line.is_empty() {\n            result.push_str(if first_line { first } else { rest });\n            result.push_str(line);\n            first_line = false;\n        }\n        result.push('\\n');\n    }\n    result\n}\n\nfn get_alias_string(aliases: &[&str]) -> Option<String> {\n    if aliases.is_empty() {\n        return None;\n    }\n\n    Some(aliases.iter().map(|alias| format!(\"`{alias}`\")).collect::<Vec<_>>().join(\", \"))\n}\n\nfn pluralize<'a>(count: usize, singular: &'a str, plural: &'a str) -> &'a str {\n    if count == 1 { singular } else { plural }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use clap::{Arg, Command};\n    use pretty_assertions::assert_eq;\n\n    #[test]\n    fn test_indent() {\n        assert_eq!(&indent(\"Header\\n\\nMore info\", \"___\", \"~~~~\"), \"___Header\\n\\n~~~~More info\\n\");\n        assert_eq!(\n            &indent(\"Header\\n\\nMore info\\n\", \"___\", \"~~~~\"),\n            &indent(\"Header\\n\\nMore info\", \"___\", \"~~~~\"),\n        );\n        assert_eq!(&indent(\"\", \"___\", \"~~~~\"), \"\\n\");\n        assert_eq!(&indent(\"\\n\", \"___\", \"~~~~\"), \"\\n\");\n    }\n\n    #[test]\n    fn test_version_output() {\n        let app = Command::new(\"test-app\").version(\"1.2.3\").about(\"A test application\");\n\n        let markdown =\n            help_markdown_command_custom(&app, &MarkdownOptions::new().show_footer(false));\n\n        assert!(markdown.contains(\"**Version:** `1.2.3`\"), \"Should contain version\");\n    }\n\n    #[test]\n    fn test_multiline_version() {\n        let multi_line_version = \"my-cli 1.2.3 (abc123)\\nmy-lib 2.0.0 (789xyz)\";\n\n        let app = Command::new(\"my-cli\").version(multi_line_version).about(\"Multi-version CLI\");\n\n        let markdown =\n            help_markdown_command_custom(&app, &MarkdownOptions::new().show_footer(false));\n\n        assert!(markdown.contains(\"**Version:**\\n\\n```\"), \"Should use code block for multi-line\");\n    }\n\n    #[test]\n    fn test_env_var_output() {\n        let app = Command::new(\"env-test\").about(\"Test env var output\").arg(\n            Arg::new(\"config\")\n                .short('c')\n                .long(\"config\")\n                .env(\"CONFIG_PATH\")\n                .help(\"Path to config file\"),\n        );\n\n        let markdown =\n            help_markdown_command_custom(&app, &MarkdownOptions::new().show_footer(false));\n\n        assert!(\n            markdown.contains(\"Environment variable: `CONFIG_PATH`\"),\n            \"Should show env var. Output: {markdown}\"\n        );\n    }\n\n    #[test]\n    fn test_grouped_options() {\n        let app = Command::new(\"grouped-app\")\n            .about(\"Test app with grouped options\")\n            .arg(\n                Arg::new(\"verbose\")\n                    .short('v')\n                    .long(\"verbose\")\n                    .help(\"Enable verbose output\")\n                    .help_heading(\"General Options\")\n                    .action(clap::ArgAction::SetTrue),\n            )\n            .arg(\n                Arg::new(\"input\")\n                    .short('i')\n                    .long(\"input\")\n                    .help(\"Input file\")\n                    .help_heading(\"File Options\")\n                    .value_name(\"FILE\"),\n            )\n            .arg(\n                Arg::new(\"format\")\n                    .short('f')\n                    .long(\"format\")\n                    .help(\"Output format\")\n                    .value_name(\"FORMAT\"),\n            );\n\n        let markdown =\n            help_markdown_command_custom(&app, &MarkdownOptions::new().show_footer(false));\n\n        assert!(markdown.contains(\"###### **File Options:**\"), \"Should have File Options heading\");\n        assert!(\n            markdown.contains(\"###### **General Options:**\"),\n            \"Should have General Options heading\"\n        );\n        assert!(markdown.contains(\"###### **Options:**\"), \"Should have default Options heading\");\n    }\n\n    #[test]\n    fn test_no_grouped_options_backward_compatibility() {\n        let app = Command::new(\"simple-app\")\n            .about(\"Test app without grouped options\")\n            .arg(\n                Arg::new(\"verbose\")\n                    .short('v')\n                    .long(\"verbose\")\n                    .help(\"Enable verbose output\")\n                    .action(clap::ArgAction::SetTrue),\n            )\n            .arg(\n                Arg::new(\"output\").short('o').long(\"output\").help(\"Output file\").value_name(\"FILE\"),\n            );\n\n        let markdown =\n            help_markdown_command_custom(&app, &MarkdownOptions::new().show_footer(false));\n\n        assert!(markdown.contains(\"###### **Options:**\"), \"Should have default Options heading\");\n        assert!(markdown.contains(\"`-v`, `--verbose`\"), \"Should have verbose option\");\n        assert!(markdown.contains(\"`-o`, `--output <FILE>`\"), \"Should have output option\");\n    }\n}\n"
  },
  {
    "path": "crates/common/Cargo.toml",
    "content": "[package]\nname = \"foundry-common\"\n\nversion.workspace = true\nedition.workspace = true\nrust-version.workspace = true\nauthors.workspace = true\nlicense.workspace = true\nhomepage.workspace = true\nrepository.workspace = true\n\n[lints]\nworkspace = true\n\n[dependencies]\nfoundry-block-explorers = { workspace = true, features = [\"foundry-compilers\"] }\nfoundry-common-fmt.workspace = true\nfoundry-compilers.workspace = true\nfoundry-config.workspace = true\nfoundry-primitives.workspace = true\n\nalloy-chains.workspace = true\nalloy-dyn-abi = { workspace = true, features = [\"arbitrary\", \"eip712\"] }\nalloy-eips.workspace = true\nalloy-json-abi.workspace = true\nalloy-json-rpc.workspace = true\nalloy-primitives = { workspace = true, features = [\n    \"serde\",\n    \"getrandom\",\n    \"arbitrary\",\n    \"rlp\",\n] }\nalloy-provider.workspace = true\nalloy-pubsub.workspace = true\nalloy-rpc-client.workspace = true\nalloy-rpc-types = { workspace = true, features = [\"eth\", \"engine\"] }\nalloy-sol-types.workspace = true\nalloy-transport-http = { workspace = true, features = [\n    \"reqwest\",\n    \"reqwest-rustls-tls\",\n] }\nalloy-transport-ipc.workspace = true\nalloy-transport-ws.workspace = true\nalloy-transport.workspace = true\nalloy-consensus = { workspace = true, features = [\"k256\"] }\nalloy-network.workspace = true\n\nrevm.workspace = true\n\nsolar.workspace = true\n\ntower.workspace = true\n\nclap = { version = \"4\", features = [\"derive\", \"env\", \"unicode\", \"wrap_help\"] }\ncomfy-table.workspace = true\ndunce.workspace = true\neyre.workspace = true\nitertools.workspace = true\njiff.workspace = true\nnum-format.workspace = true\npath-slash.workspace = true\nregex.workspace = true\nreqwest.workspace = true\nsemver.workspace = true\nserde = { workspace = true, features = [\"derive\"] }\nserde_json.workspace = true\nthiserror.workspace = true\ntokio.workspace = true\ntracing.workspace = true\nurl.workspace = true\nwalkdir.workspace = true\nyansi.workspace = true\n\nanstream.workspace = true\nanstyle.workspace = true\nciborium.workspace = true\n\nflate2.workspace = true\n\n[build-dependencies]\nchrono.workspace = true\nvergen = { workspace = true, features = [\"build\", \"emit_and_set\"] }\n\n[dev-dependencies]\ntokio = { workspace = true, features = [\"rt-multi-thread\", \"macros\"] }\naxum = { workspace = true }\n"
  },
  {
    "path": "crates/common/README.md",
    "content": "Common utilities for building and using foundry's tools.\n"
  },
  {
    "path": "crates/common/build.rs",
    "content": "#![expect(clippy::disallowed_macros)]\n\nuse chrono::DateTime;\nuse std::{error::Error, path::PathBuf};\n\nfn main() -> Result<(), Box<dyn Error>> {\n    println!(\"cargo:rerun-if-changed=build.rs\");\n\n    let build = vergen::Build::builder().build_date(true).build_timestamp(true).build();\n    let git = vergen::Gitcl::builder().describe(false, true, None).sha(false).build();\n\n    vergen::Emitter::new().add_instructions(&build)?.add_instructions(&git)?.emit_and_set()?;\n\n    let sha = env_var(\"VERGEN_GIT_SHA\");\n    let sha_short = &sha[..10];\n\n    let tag_name = try_env_var(\"TAG_NAME\").unwrap_or_else(|| String::from(\"dev\"));\n    let is_nightly = tag_name.contains(\"nightly\");\n    let version_suffix = if is_nightly { \"nightly\" } else { &tag_name };\n\n    if is_nightly {\n        println!(\"cargo:rustc-env=FOUNDRY_IS_NIGHTLY_VERSION=true\");\n    }\n\n    let pkg_version = env_var(\"CARGO_PKG_VERSION\");\n    let version = format!(\"{pkg_version}-{version_suffix}\");\n\n    // `PROFILE` captures only release or debug. Get the actual name from the out directory.\n    let out_dir = PathBuf::from(env_var(\"OUT_DIR\"));\n    let profile = out_dir.components().rev().nth(3).unwrap().as_os_str().to_str().unwrap();\n\n    let build_timestamp = env_var(\"VERGEN_BUILD_TIMESTAMP\");\n    let build_timestamp_unix = DateTime::parse_from_rfc3339(&build_timestamp)?.timestamp();\n\n    // The SemVer compatible version information for Foundry.\n    // - The latest version from Cargo.toml.\n    // - The short SHA of the latest commit.\n    // - The UNIX formatted build timestamp.\n    // - The build profile.\n    // Example: forge 0.3.0-nightly+3cb96bde9b.1737036656.debug\n    println!(\n        \"cargo:rustc-env=FOUNDRY_SEMVER_VERSION={version}+{sha_short}.{build_timestamp_unix}.{profile}\"\n    );\n\n    // The short version information for the Foundry CLI.\n    // - The latest version from Cargo.toml\n    // - The short SHA of the latest commit.\n    // Example: 0.3.0-dev (3cb96bde9b)\n    println!(\"cargo:rustc-env=FOUNDRY_SHORT_VERSION={version} ({sha_short} {build_timestamp})\");\n\n    // The long version information for the Foundry CLI.\n    // - The latest version from Cargo.toml.\n    // - The long SHA of the latest commit.\n    // - The build timestamp in RFC3339 format and UNIX format in seconds.\n    // - The build profile.\n    //\n    // Example:\n    //\n    // ```text\n    // <BIN>\n    // Version: 0.3.0-dev\n    // Commit SHA: 5186142d3bb4d1be7bb4ade548b77c8e2270717e\n    // Build Timestamp: 2025-01-16T15:04:03.522021223Z (1737039843)\n    // Build Profile: debug\n    // ```\n    let long_version = format!(\n        \"\\\nVersion: {version}\nCommit SHA: {sha}\nBuild Timestamp: {build_timestamp} ({build_timestamp_unix})\nBuild Profile: {profile}\"\n    );\n    assert_eq!(long_version.lines().count(), 4);\n    for (i, line) in long_version.lines().enumerate() {\n        println!(\"cargo:rustc-env=FOUNDRY_LONG_VERSION_{i}={line}\");\n    }\n\n    Ok(())\n}\n\nfn env_var(name: &str) -> String {\n    try_env_var(name).unwrap()\n}\n\nfn try_env_var(name: &str) -> Option<String> {\n    println!(\"cargo:rerun-if-env-changed={name}\");\n    std::env::var(name).ok()\n}\n"
  },
  {
    "path": "crates/common/fmt/Cargo.toml",
    "content": "[package]\nname = \"foundry-common-fmt\"\ndescription = \"Common formatting utilities for Foundry\"\n\nversion.workspace = true\nedition.workspace = true\nrust-version.workspace = true\nauthors.workspace = true\nlicense.workspace = true\nhomepage.workspace = true\nrepository.workspace = true\n\n[lints]\nworkspace = true\n\n[dependencies]\nalloy-primitives.workspace = true\nalloy-dyn-abi = { workspace = true, features = [\"eip712\"] }\neyre.workspace = true\n\n# ui\nalloy-consensus.workspace = true\nop-alloy-consensus.workspace = true\nalloy-network.workspace = true\nalloy-rpc-types = { workspace = true, features = [\"eth\"] }\nop-alloy-rpc-types.workspace = true\nalloy-serde.workspace = true\nserde.workspace = true\nserde_json.workspace = true\nchrono.workspace = true\nrevm.workspace = true\nyansi.workspace = true\n\n# foundry primitives\nfoundry-primitives.workspace = true\n\n# Tempo\ntempo-alloy.workspace = true\n\n[dev-dependencies]\nfoundry-macros.workspace = true\nsimilar-asserts.workspace = true\n"
  },
  {
    "path": "crates/common/fmt/src/console.rs",
    "content": "use super::UIfmt;\nuse alloy_primitives::{Address, Bytes, FixedBytes, I256, U256};\nuse std::fmt::{self, Write};\n\n/// A piece is a portion of the format string which represents the next part to emit.\n#[derive(Clone, Debug, PartialEq, Eq)]\npub enum Piece<'a> {\n    /// A literal string which should directly be emitted.\n    String(&'a str),\n    /// A format specifier which should be replaced with the next argument.\n    NextArgument(FormatSpec),\n}\n\n/// A format specifier.\n#[derive(Clone, Debug, Default, PartialEq, Eq)]\npub enum FormatSpec {\n    /// `%s`\n    #[default]\n    String,\n    /// `%d`\n    Number,\n    /// `%i`\n    Integer,\n    /// `%o`\n    Object,\n    /// `%e`, `%18e`\n    Exponential(Option<usize>),\n    /// `%x`\n    Hexadecimal,\n}\n\nimpl fmt::Display for FormatSpec {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.write_str(\"%\")?;\n        match *self {\n            Self::String => f.write_str(\"s\"),\n            Self::Number => f.write_str(\"d\"),\n            Self::Integer => f.write_str(\"i\"),\n            Self::Object => f.write_str(\"o\"),\n            Self::Exponential(Some(n)) => write!(f, \"{n}e\"),\n            Self::Exponential(None) => f.write_str(\"e\"),\n            Self::Hexadecimal => f.write_str(\"x\"),\n        }\n    }\n}\n\nenum ParseArgError {\n    /// Failed to parse the argument.\n    Err,\n    /// Escape `%%`.\n    Skip,\n}\n\n/// Parses a format string into a sequence of [pieces][Piece].\n#[derive(Debug)]\npub struct Parser<'a> {\n    input: &'a str,\n    chars: std::str::CharIndices<'a>,\n}\n\nimpl<'a> Parser<'a> {\n    /// Creates a new parser for the given input.\n    pub fn new(input: &'a str) -> Self {\n        Self { input, chars: input.char_indices() }\n    }\n\n    /// Parses a string until the next format specifier.\n    ///\n    /// `skip` is the number of format specifier characters (`%`) to ignore before returning the\n    /// string.\n    fn string(&mut self, start: usize, mut skip: usize) -> &'a str {\n        while let Some((pos, c)) = self.peek() {\n            if c == '%' {\n                if skip == 0 {\n                    return &self.input[start..pos];\n                }\n                skip -= 1;\n            }\n            self.chars.next();\n        }\n        &self.input[start..]\n    }\n\n    /// Parses a format specifier.\n    ///\n    /// If `Err` is returned, the internal iterator may have been advanced and it may be in an\n    /// invalid state.\n    fn argument(&mut self) -> Result<FormatSpec, ParseArgError> {\n        let (start, ch) = self.peek().ok_or(ParseArgError::Err)?;\n        let simple_spec = match ch {\n            's' => Some(FormatSpec::String),\n            'd' => Some(FormatSpec::Number),\n            'i' => Some(FormatSpec::Integer),\n            'o' => Some(FormatSpec::Object),\n            'e' => Some(FormatSpec::Exponential(None)),\n            'x' => Some(FormatSpec::Hexadecimal),\n            // \"%%\" is a literal '%'.\n            '%' => return Err(ParseArgError::Skip),\n            _ => None,\n        };\n        if let Some(spec) = simple_spec {\n            self.chars.next();\n            return Ok(spec);\n        }\n\n        // %<n>e\n        if ch.is_ascii_digit() {\n            let n = self.integer(start);\n            if let Some((_, 'e')) = self.peek() {\n                self.chars.next();\n                return Ok(FormatSpec::Exponential(n));\n            }\n        }\n\n        Err(ParseArgError::Err)\n    }\n\n    fn integer(&mut self, start: usize) -> Option<usize> {\n        let mut end = start;\n        while let Some((pos, ch)) = self.peek() {\n            if !ch.is_ascii_digit() {\n                end = pos;\n                break;\n            }\n            self.chars.next();\n        }\n        self.input[start..end].parse().ok()\n    }\n\n    fn current_pos(&mut self) -> usize {\n        self.peek().map(|(n, _)| n).unwrap_or(self.input.len())\n    }\n\n    fn peek(&mut self) -> Option<(usize, char)> {\n        self.peek_n(0)\n    }\n\n    fn peek_n(&mut self, n: usize) -> Option<(usize, char)> {\n        self.chars.clone().nth(n)\n    }\n}\n\nimpl<'a> Iterator for Parser<'a> {\n    type Item = Piece<'a>;\n\n    fn next(&mut self) -> Option<Self::Item> {\n        let (mut start, ch) = self.peek()?;\n        let mut skip = 0;\n        if ch == '%' {\n            let prev = self.chars.clone();\n            self.chars.next();\n            match self.argument() {\n                Ok(arg) => {\n                    debug_assert_eq!(arg.to_string(), self.input[start..self.current_pos()]);\n                    return Some(Piece::NextArgument(arg));\n                }\n\n                // Skip the argument if we encountered \"%%\".\n                Err(ParseArgError::Skip) => {\n                    start = self.current_pos();\n                    skip += 1;\n                }\n\n                // Reset the iterator if we failed to parse the argument, and include any\n                // parsed and unparsed specifier in `String`.\n                Err(ParseArgError::Err) => {\n                    self.chars = prev;\n                    skip += 1;\n                }\n            }\n        }\n        Some(Piece::String(self.string(start, skip)))\n    }\n}\n\n/// Formats a value using a [FormatSpec].\npub trait ConsoleFmt {\n    /// Formats a value using a [FormatSpec].\n    fn fmt(&self, spec: FormatSpec) -> String;\n}\n\nimpl ConsoleFmt for String {\n    fn fmt(&self, spec: FormatSpec) -> String {\n        match spec {\n            FormatSpec::String => self.clone(),\n            FormatSpec::Object => format!(\"'{}'\", self.clone()),\n            FormatSpec::Number\n            | FormatSpec::Integer\n            | FormatSpec::Exponential(_)\n            | FormatSpec::Hexadecimal => Self::from(\"NaN\"),\n        }\n    }\n}\n\nimpl ConsoleFmt for bool {\n    fn fmt(&self, spec: FormatSpec) -> String {\n        match spec {\n            FormatSpec::String => self.pretty(),\n            FormatSpec::Object => format!(\"'{}'\", self.pretty()),\n            FormatSpec::Number => (*self as i32).to_string(),\n            FormatSpec::Integer | FormatSpec::Exponential(_) | FormatSpec::Hexadecimal => {\n                String::from(\"NaN\")\n            }\n        }\n    }\n}\n\nimpl ConsoleFmt for U256 {\n    fn fmt(&self, spec: FormatSpec) -> String {\n        match spec {\n            FormatSpec::String | FormatSpec::Object | FormatSpec::Number | FormatSpec::Integer => {\n                self.pretty()\n            }\n            FormatSpec::Hexadecimal => {\n                let hex = format!(\"{self:x}\");\n                format!(\"0x{}\", hex.trim_start_matches('0'))\n            }\n            FormatSpec::Exponential(None) => {\n                let log = self.pretty().len() - 1;\n                let exp10 = Self::from(10).pow(Self::from(log));\n                let amount = *self;\n                let integer = amount / exp10;\n                let decimal = (amount % exp10).to_string();\n                let decimal = format!(\"{decimal:0>log$}\").trim_end_matches('0').to_string();\n                if !decimal.is_empty() {\n                    format!(\"{integer}.{decimal}e{log}\")\n                } else {\n                    format!(\"{integer}e{log}\")\n                }\n            }\n            FormatSpec::Exponential(Some(precision)) => {\n                let exp10 = Self::from(10).pow(Self::from(precision));\n                let amount = *self;\n                let integer = amount / exp10;\n                let decimal = (amount % exp10).to_string();\n                let decimal = format!(\"{decimal:0>precision$}\").trim_end_matches('0').to_string();\n                if !decimal.is_empty() {\n                    format!(\"{integer}.{decimal}\")\n                } else {\n                    format!(\"{integer}\")\n                }\n            }\n        }\n    }\n}\n\nimpl ConsoleFmt for I256 {\n    fn fmt(&self, spec: FormatSpec) -> String {\n        match spec {\n            FormatSpec::String | FormatSpec::Object | FormatSpec::Number | FormatSpec::Integer => {\n                self.pretty()\n            }\n            FormatSpec::Hexadecimal => {\n                let hex = format!(\"{self:x}\");\n                format!(\"0x{}\", hex.trim_start_matches('0'))\n            }\n            FormatSpec::Exponential(None) => {\n                let amount = *self;\n                let sign = if amount.is_negative() { \"-\" } else { \"\" };\n                let log = if amount.is_negative() {\n                    self.pretty().len() - 2\n                } else {\n                    self.pretty().len() - 1\n                };\n                let exp10 = Self::exp10(log);\n                let integer = (amount / exp10).twos_complement();\n                let decimal = (amount % exp10).twos_complement().to_string();\n                let decimal = format!(\"{decimal:0>log$}\").trim_end_matches('0').to_string();\n                if !decimal.is_empty() {\n                    format!(\"{sign}{integer}.{decimal}e{log}\")\n                } else {\n                    format!(\"{sign}{integer}e{log}\")\n                }\n            }\n            FormatSpec::Exponential(Some(precision)) => {\n                let amount = *self;\n                let sign = if amount.is_negative() { \"-\" } else { \"\" };\n                let exp10 = Self::exp10(precision);\n                let integer = (amount / exp10).twos_complement();\n                let decimal = (amount % exp10).twos_complement().to_string();\n                let decimal = format!(\"{decimal:0>precision$}\").trim_end_matches('0').to_string();\n                if !decimal.is_empty() {\n                    format!(\"{sign}{integer}.{decimal}\")\n                } else {\n                    format!(\"{sign}{integer}\")\n                }\n            }\n        }\n    }\n}\n\nimpl ConsoleFmt for Address {\n    fn fmt(&self, spec: FormatSpec) -> String {\n        match spec {\n            FormatSpec::String | FormatSpec::Hexadecimal => self.pretty(),\n            FormatSpec::Object => format!(\"'{}'\", self.pretty()),\n            FormatSpec::Number | FormatSpec::Integer | FormatSpec::Exponential(_) => {\n                String::from(\"NaN\")\n            }\n        }\n    }\n}\n\nimpl ConsoleFmt for Vec<u8> {\n    fn fmt(&self, spec: FormatSpec) -> String {\n        self[..].fmt(spec)\n    }\n}\n\nimpl ConsoleFmt for Bytes {\n    fn fmt(&self, spec: FormatSpec) -> String {\n        self[..].fmt(spec)\n    }\n}\n\nimpl<const N: usize> ConsoleFmt for [u8; N] {\n    fn fmt(&self, spec: FormatSpec) -> String {\n        self[..].fmt(spec)\n    }\n}\n\nimpl<const N: usize> ConsoleFmt for FixedBytes<N> {\n    fn fmt(&self, spec: FormatSpec) -> String {\n        self[..].fmt(spec)\n    }\n}\n\nimpl ConsoleFmt for [u8] {\n    fn fmt(&self, spec: FormatSpec) -> String {\n        match spec {\n            FormatSpec::String | FormatSpec::Hexadecimal => self.pretty(),\n            FormatSpec::Object => format!(\"'{}'\", self.pretty()),\n            FormatSpec::Number | FormatSpec::Integer | FormatSpec::Exponential(_) => {\n                String::from(\"NaN\")\n            }\n        }\n    }\n}\n\n/// Formats a string using the input values.\n///\n/// Formatting rules are the same as Hardhat. The supported format specifiers are as follows:\n/// - %s: Converts the value using its String representation. This is equivalent to applying\n///   [`UIfmt::pretty()`] on the format string.\n/// - %o: Treats the format value as a javascript \"object\" and converts it to its string\n///   representation.\n/// - %d, %i: Converts the value to an integer. If a non-numeric value, such as String or Address,\n///   is passed, then the spec is formatted as `NaN`.\n/// - %x: Converts the value to a hexadecimal string. If a non-numeric value, such as String or\n///   Address, is passed, then the spec is formatted as `NaN`.\n/// - %e: Converts the value to an exponential notation string. If a non-numeric value, such as\n///   String or Address, is passed, then the spec is formatted as `NaN`.\n/// - %%: This is parsed as a single percent sign ('%') without consuming any input value.\n///\n/// Unformatted values are appended to the end of the formatted output using [`UIfmt::pretty()`].\n/// If there are more format specifiers than values, then the remaining unparsed format specifiers\n/// appended to the formatted output as-is.\n///\n/// # Examples\n///\n/// ```ignore (not implemented for integers)\n/// let formatted = foundry_common::fmt::console_format(\"%s has %d characters\", &[&\"foo\", &3]);\n/// assert_eq!(formatted, \"foo has 3 characters\");\n/// ```\npub fn console_format(spec: &str, values: &[&dyn ConsoleFmt]) -> String {\n    let mut values = values.iter().copied();\n    let mut result = String::with_capacity(spec.len());\n\n    // for the first space\n    let mut write_space = if spec.is_empty() {\n        false\n    } else {\n        format_spec(spec, &mut values, &mut result);\n        true\n    };\n\n    // append any remaining values with the standard format\n    for v in values {\n        let fmt = v.fmt(FormatSpec::String);\n        if write_space {\n            result.push(' ');\n        }\n        result.push_str(&fmt);\n        write_space = true;\n    }\n\n    result\n}\n\nfn format_spec<'a>(\n    s: &str,\n    mut values: impl Iterator<Item = &'a dyn ConsoleFmt>,\n    result: &mut String,\n) {\n    for piece in Parser::new(s) {\n        match piece {\n            Piece::String(s) => result.push_str(s),\n            Piece::NextArgument(spec) => {\n                if let Some(value) = values.next() {\n                    result.push_str(&value.fmt(spec));\n                } else {\n                    // Write the format specifier as-is if there are no more values.\n                    write!(result, \"{spec}\").unwrap();\n                }\n            }\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use alloy_primitives::{B256, address};\n    use foundry_macros::ConsoleFmt;\n    use std::str::FromStr;\n\n    macro_rules! logf1 {\n        ($a:ident) => {\n            console_format(&$a.p_0, &[&$a.p_1])\n        };\n    }\n\n    macro_rules! logf2 {\n        ($a:ident) => {\n            console_format(&$a.p_0, &[&$a.p_1, &$a.p_2])\n        };\n    }\n\n    macro_rules! logf3 {\n        ($a:ident) => {\n            console_format(&$a.p_0, &[&$a.p_1, &$a.p_2, &$a.p_3])\n        };\n    }\n\n    #[derive(Clone, Debug, ConsoleFmt)]\n    struct Log1 {\n        p_0: String,\n        p_1: U256,\n    }\n\n    #[derive(Clone, Debug, ConsoleFmt)]\n    struct Log2 {\n        p_0: String,\n        p_1: bool,\n        p_2: U256,\n    }\n\n    #[derive(Clone, Debug, ConsoleFmt)]\n    struct Log3 {\n        p_0: String,\n        p_1: Address,\n        p_2: bool,\n        p_3: U256,\n    }\n\n    #[expect(unused)]\n    #[derive(Clone, Debug, ConsoleFmt)]\n    enum Logs {\n        Log1(Log1),\n        Log2(Log2),\n        Log3(Log3),\n    }\n\n    #[test]\n    fn test_console_log_format_specifiers() {\n        let fmt_1 = |spec: &str, arg: &dyn ConsoleFmt| console_format(spec, &[arg]);\n\n        assert_eq!(\"foo\", fmt_1(\"%s\", &String::from(\"foo\")));\n        assert_eq!(\"NaN\", fmt_1(\"%d\", &String::from(\"foo\")));\n        assert_eq!(\"NaN\", fmt_1(\"%i\", &String::from(\"foo\")));\n        assert_eq!(\"NaN\", fmt_1(\"%e\", &String::from(\"foo\")));\n        assert_eq!(\"NaN\", fmt_1(\"%x\", &String::from(\"foo\")));\n        assert_eq!(\"'foo'\", fmt_1(\"%o\", &String::from(\"foo\")));\n        assert_eq!(\"%s foo\", fmt_1(\"%%s\", &String::from(\"foo\")));\n        assert_eq!(\"% foo\", fmt_1(\"%\", &String::from(\"foo\")));\n        assert_eq!(\"% foo\", fmt_1(\"%%\", &String::from(\"foo\")));\n\n        assert_eq!(\"true\", fmt_1(\"%s\", &true));\n        assert_eq!(\"1\", fmt_1(\"%d\", &true));\n        assert_eq!(\"0\", fmt_1(\"%d\", &false));\n        assert_eq!(\"NaN\", fmt_1(\"%i\", &true));\n        assert_eq!(\"NaN\", fmt_1(\"%e\", &true));\n        assert_eq!(\"NaN\", fmt_1(\"%x\", &true));\n        assert_eq!(\"'true'\", fmt_1(\"%o\", &true));\n\n        let b32 =\n            B256::from_str(\"0xdeadbeef00000000000000000000000000000000000000000000000000000000\")\n                .unwrap();\n        assert_eq!(\n            \"0xdeadbeef00000000000000000000000000000000000000000000000000000000\",\n            fmt_1(\"%s\", &b32)\n        );\n        assert_eq!(\n            \"0xdeadbeef00000000000000000000000000000000000000000000000000000000\",\n            fmt_1(\"%x\", &b32)\n        );\n        assert_eq!(\"NaN\", fmt_1(\"%d\", &b32));\n        assert_eq!(\"NaN\", fmt_1(\"%i\", &b32));\n        assert_eq!(\"NaN\", fmt_1(\"%e\", &b32));\n        assert_eq!(\n            \"'0xdeadbeef00000000000000000000000000000000000000000000000000000000'\",\n            fmt_1(\"%o\", &b32)\n        );\n\n        let addr = address!(\"0xdEADBEeF00000000000000000000000000000000\");\n        assert_eq!(\"0xdEADBEeF00000000000000000000000000000000\", fmt_1(\"%s\", &addr));\n        assert_eq!(\"NaN\", fmt_1(\"%d\", &addr));\n        assert_eq!(\"NaN\", fmt_1(\"%i\", &addr));\n        assert_eq!(\"NaN\", fmt_1(\"%e\", &addr));\n        assert_eq!(\"0xdEADBEeF00000000000000000000000000000000\", fmt_1(\"%x\", &addr));\n        assert_eq!(\"'0xdEADBEeF00000000000000000000000000000000'\", fmt_1(\"%o\", &addr));\n\n        let bytes = Bytes::from_str(\"0xdeadbeef\").unwrap();\n        assert_eq!(\"0xdeadbeef\", fmt_1(\"%s\", &bytes));\n        assert_eq!(\"NaN\", fmt_1(\"%d\", &bytes));\n        assert_eq!(\"NaN\", fmt_1(\"%i\", &bytes));\n        assert_eq!(\"NaN\", fmt_1(\"%e\", &bytes));\n        assert_eq!(\"0xdeadbeef\", fmt_1(\"%x\", &bytes));\n        assert_eq!(\"'0xdeadbeef'\", fmt_1(\"%o\", &bytes));\n\n        assert_eq!(\"100\", fmt_1(\"%s\", &U256::from(100)));\n        assert_eq!(\"100\", fmt_1(\"%d\", &U256::from(100)));\n        assert_eq!(\"100\", fmt_1(\"%i\", &U256::from(100)));\n        assert_eq!(\"1e2\", fmt_1(\"%e\", &U256::from(100)));\n        assert_eq!(\"1.0023e6\", fmt_1(\"%e\", &U256::from(1002300)));\n        assert_eq!(\"1.23e5\", fmt_1(\"%e\", &U256::from(123000)));\n        assert_eq!(\"0x64\", fmt_1(\"%x\", &U256::from(100)));\n        assert_eq!(\"100\", fmt_1(\"%o\", &U256::from(100)));\n\n        assert_eq!(\"100\", fmt_1(\"%s\", &I256::try_from(100).unwrap()));\n        assert_eq!(\"100\", fmt_1(\"%d\", &I256::try_from(100).unwrap()));\n        assert_eq!(\"100\", fmt_1(\"%i\", &I256::try_from(100).unwrap()));\n        assert_eq!(\"1e2\", fmt_1(\"%e\", &I256::try_from(100).unwrap()));\n        assert_eq!(\"-1e2\", fmt_1(\"%e\", &I256::try_from(-100).unwrap()));\n        assert_eq!(\"-1.0023e6\", fmt_1(\"%e\", &I256::try_from(-1002300).unwrap()));\n        assert_eq!(\"-1.23e5\", fmt_1(\"%e\", &I256::try_from(-123000).unwrap()));\n        assert_eq!(\"1.0023e6\", fmt_1(\"%e\", &I256::try_from(1002300).unwrap()));\n        assert_eq!(\"1.23e5\", fmt_1(\"%e\", &I256::try_from(123000).unwrap()));\n\n        // %ne\n        assert_eq!(\"10\", fmt_1(\"%1e\", &I256::try_from(100).unwrap()));\n        assert_eq!(\"-1\", fmt_1(\"%2e\", &I256::try_from(-100).unwrap()));\n        assert_eq!(\"123000\", fmt_1(\"%0e\", &I256::try_from(123000).unwrap()));\n        assert_eq!(\"12300\", fmt_1(\"%1e\", &I256::try_from(123000).unwrap()));\n        assert_eq!(\"0.0123\", fmt_1(\"%7e\", &I256::try_from(123000).unwrap()));\n        assert_eq!(\"-0.0123\", fmt_1(\"%7e\", &I256::try_from(-123000).unwrap()));\n\n        assert_eq!(\"0x64\", fmt_1(\"%x\", &I256::try_from(100).unwrap()));\n        assert_eq!(\n            \"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9c\",\n            fmt_1(\"%x\", &I256::try_from(-100).unwrap())\n        );\n        assert_eq!(\n            \"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffe8b7891800\",\n            fmt_1(\"%x\", &I256::try_from(-100000000000i64).unwrap())\n        );\n        assert_eq!(\"100\", fmt_1(\"%o\", &I256::try_from(100).unwrap()));\n\n        // make sure that %byte values are not consumed when there are no values\n        assert_eq!(\"%333d%3e%5F\", console_format(\"%333d%3e%5F\", &[]));\n        assert_eq!(\n            \"%5d123456.789%2f%3f%e1\",\n            console_format(\"%5d%3e%2f%3f%e1\", &[&U256::from(123456789)])\n        );\n    }\n\n    #[test]\n    fn test_console_log_format() {\n        let mut log1 = Log1 { p_0: \"foo %s\".to_string(), p_1: U256::from(100) };\n        assert_eq!(\"foo 100\", logf1!(log1));\n        log1.p_0 = String::from(\"foo\");\n        assert_eq!(\"foo 100\", logf1!(log1));\n        log1.p_0 = String::from(\"%s foo\");\n        assert_eq!(\"100 foo\", logf1!(log1));\n\n        let mut log2 = Log2 { p_0: \"foo %s %s\".to_string(), p_1: true, p_2: U256::from(100) };\n        assert_eq!(\"foo true 100\", logf2!(log2));\n        log2.p_0 = String::from(\"foo\");\n        assert_eq!(\"foo true 100\", logf2!(log2));\n        log2.p_0 = String::from(\"%s %s foo\");\n        assert_eq!(\"true 100 foo\", logf2!(log2));\n\n        let log3 = Log3 {\n            p_0: String::from(\"foo %s %%s %s and %d foo %%\"),\n            p_1: address!(\"0xdEADBEeF00000000000000000000000000000000\"),\n            p_2: true,\n            p_3: U256::from(21),\n        };\n        assert_eq!(\n            \"foo 0xdEADBEeF00000000000000000000000000000000 %s true and 21 foo %\",\n            logf3!(log3)\n        );\n\n        // %ne\n        let log4 = Log1 { p_0: String::from(\"%5e\"), p_1: U256::from(123456789) };\n        assert_eq!(\"1234.56789\", logf1!(log4));\n\n        let log5 = Log1 { p_0: String::from(\"foo %3e bar\"), p_1: U256::from(123456789) };\n        assert_eq!(\"foo 123456.789 bar\", logf1!(log5));\n\n        let log6 =\n            Log2 { p_0: String::from(\"%e and %12e\"), p_1: false, p_2: U256::from(123456789) };\n        assert_eq!(\"NaN and 0.000123456789\", logf2!(log6));\n    }\n\n    #[test]\n    fn test_derive_format() {\n        let log1 = Log1 { p_0: String::from(\"foo %s bar\"), p_1: U256::from(42) };\n        assert_eq!(log1.fmt(Default::default()), \"foo 42 bar\");\n        let call = Logs::Log1(log1);\n        assert_eq!(call.fmt(Default::default()), \"foo 42 bar\");\n    }\n}\n"
  },
  {
    "path": "crates/common/fmt/src/dynamic.rs",
    "content": "use super::{format_int_exp, format_uint_exp};\nuse alloy_dyn_abi::{DynSolType, DynSolValue};\nuse alloy_primitives::hex;\nuse eyre::Result;\nuse serde_json::{Map, Value};\nuse std::{\n    collections::{BTreeMap, HashMap},\n    fmt,\n};\n\n/// [`DynSolValue`] formatter.\nstruct DynValueFormatter {\n    raw: bool,\n}\n\nimpl DynValueFormatter {\n    /// Recursively formats a [`DynSolValue`].\n    fn value(&self, value: &DynSolValue, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        match value {\n            DynSolValue::Address(inner) => write!(f, \"{inner}\"),\n            DynSolValue::Function(inner) => write!(f, \"{inner}\"),\n            DynSolValue::Bytes(inner) => f.write_str(&hex::encode_prefixed(inner)),\n            DynSolValue::FixedBytes(word, size) => {\n                f.write_str(&hex::encode_prefixed(&word[..*size]))\n            }\n            DynSolValue::Uint(inner, _) => {\n                if self.raw {\n                    write!(f, \"{inner}\")\n                } else {\n                    f.write_str(&format_uint_exp(*inner))\n                }\n            }\n            DynSolValue::Int(inner, _) => {\n                if self.raw {\n                    write!(f, \"{inner}\")\n                } else {\n                    f.write_str(&format_int_exp(*inner))\n                }\n            }\n            DynSolValue::Array(values) | DynSolValue::FixedArray(values) => {\n                f.write_str(\"[\")?;\n                self.list(values, f)?;\n                f.write_str(\"]\")\n            }\n            DynSolValue::Tuple(values) => self.tuple(values, f),\n            DynSolValue::String(inner) => {\n                if self.raw {\n                    write!(f, \"{}\", inner.escape_debug())\n                } else {\n                    write!(f, \"{inner:?}\") // escape strings\n                }\n            }\n            DynSolValue::Bool(inner) => write!(f, \"{inner}\"),\n            DynSolValue::CustomStruct { name, prop_names, tuple } => {\n                if self.raw {\n                    return self.tuple(tuple, f);\n                }\n\n                f.write_str(name)?;\n\n                if prop_names.len() == tuple.len() {\n                    f.write_str(\"({ \")?;\n\n                    for (i, (prop_name, value)) in std::iter::zip(prop_names, tuple).enumerate() {\n                        if i > 0 {\n                            f.write_str(\", \")?;\n                        }\n                        f.write_str(prop_name)?;\n                        f.write_str(\": \")?;\n                        self.value(value, f)?;\n                    }\n\n                    f.write_str(\" })\")\n                } else {\n                    self.tuple(tuple, f)\n                }\n            }\n        }\n    }\n\n    /// Recursively formats a comma-separated list of [`DynSolValue`]s.\n    fn list(&self, values: &[DynSolValue], f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        for (i, value) in values.iter().enumerate() {\n            if i > 0 {\n                f.write_str(\", \")?;\n            }\n            self.value(value, f)?;\n        }\n        Ok(())\n    }\n\n    /// Formats the given values as a tuple.\n    fn tuple(&self, values: &[DynSolValue], f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.write_str(\"(\")?;\n        self.list(values, f)?;\n        f.write_str(\")\")\n    }\n}\n\n/// Wrapper that implements [`Display`](fmt::Display) for a [`DynSolValue`].\nstruct DynValueDisplay<'a> {\n    /// The value to display.\n    value: &'a DynSolValue,\n    /// The formatter.\n    formatter: DynValueFormatter,\n}\n\nimpl<'a> DynValueDisplay<'a> {\n    /// Creates a new [`Display`](fmt::Display) wrapper for the given value.\n    fn new(value: &'a DynSolValue, raw: bool) -> Self {\n        Self { value, formatter: DynValueFormatter { raw } }\n    }\n}\n\nimpl fmt::Display for DynValueDisplay<'_> {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        self.formatter.value(self.value, f)\n    }\n}\n\n/// Parses string input as Token against the expected ParamType\npub fn parse_tokens<'a, I: IntoIterator<Item = (&'a DynSolType, &'a str)>>(\n    params: I,\n) -> alloy_dyn_abi::Result<Vec<DynSolValue>> {\n    params.into_iter().map(|(param, value)| DynSolType::coerce_str(param, value)).collect()\n}\n\n/// Pretty-prints a slice of tokens using [`format_token`].\npub fn format_tokens(tokens: &[DynSolValue]) -> impl Iterator<Item = String> + '_ {\n    tokens.iter().map(format_token)\n}\n\n/// Pretty-prints a slice of tokens using [`format_token_raw`].\npub fn format_tokens_raw(tokens: &[DynSolValue]) -> impl Iterator<Item = String> + '_ {\n    tokens.iter().map(format_token_raw)\n}\n\n/// Pretty-prints the given value into a string suitable for user output.\npub fn format_token(value: &DynSolValue) -> String {\n    DynValueDisplay::new(value, false).to_string()\n}\n\n/// Pretty-prints the given value into a string suitable for re-parsing as values later.\n///\n/// This means:\n/// - integers are not formatted with exponential notation hints\n/// - structs are formatted as tuples, losing the struct and property names\npub fn format_token_raw(value: &DynSolValue) -> String {\n    DynValueDisplay::new(value, true).to_string()\n}\n\n/// Serializes given [DynSolValue] into a [serde_json::Value].\npub fn serialize_value_as_json(\n    value: DynSolValue,\n    defs: Option<&StructDefinitions>,\n) -> Result<Value> {\n    if let Some(defs) = defs {\n        _serialize_value_as_json(value, defs)\n    } else {\n        _serialize_value_as_json(value, &StructDefinitions::default())\n    }\n}\n\nfn _serialize_value_as_json(value: DynSolValue, defs: &StructDefinitions) -> Result<Value> {\n    match value {\n        DynSolValue::Bool(b) => Ok(Value::Bool(b)),\n        DynSolValue::String(s) => {\n            // Strings are allowed to contain stringified JSON objects, so we try to parse it like\n            // one first.\n            if let Ok(map) = serde_json::from_str(&s) {\n                Ok(Value::Object(map))\n            } else {\n                Ok(Value::String(s))\n            }\n        }\n        DynSolValue::Bytes(b) => Ok(Value::String(hex::encode_prefixed(b))),\n        DynSolValue::FixedBytes(b, size) => Ok(Value::String(hex::encode_prefixed(&b[..size]))),\n        DynSolValue::Int(i, _) => {\n            if let Ok(n) = i64::try_from(i) {\n                // Use `serde_json::Number` if the number can be accurately represented.\n                Ok(Value::Number(n.into()))\n            } else {\n                // Otherwise, fallback to its string representation to preserve precision and ensure\n                // compatibility with alloy's `DynSolType` coercion.\n                Ok(Value::String(i.to_string()))\n            }\n        }\n        DynSolValue::Uint(i, _) => {\n            if let Ok(n) = u64::try_from(i) {\n                // Use `serde_json::Number` if the number can be accurately represented.\n                Ok(Value::Number(n.into()))\n            } else {\n                // Otherwise, fallback to its string representation to preserve precision and ensure\n                // compatibility with alloy's `DynSolType` coercion.\n                Ok(Value::String(i.to_string()))\n            }\n        }\n        DynSolValue::Address(a) => Ok(Value::String(a.to_string())),\n        DynSolValue::Array(e) | DynSolValue::FixedArray(e) => Ok(Value::Array(\n            e.into_iter().map(|v| _serialize_value_as_json(v, defs)).collect::<Result<_>>()?,\n        )),\n        DynSolValue::CustomStruct { name, prop_names, tuple } => {\n            let values = tuple\n                .into_iter()\n                .map(|v| _serialize_value_as_json(v, defs))\n                .collect::<Result<Vec<_>>>()?;\n            let mut map: HashMap<String, Value> = prop_names.into_iter().zip(values).collect();\n\n            // If the struct def is known, manually build a `Map` to preserve the order.\n            if let Some(fields) = defs.get(&name)? {\n                let mut ordered_map = Map::with_capacity(fields.len());\n                for (field_name, _) in fields {\n                    if let Some(serialized_value) = map.remove(field_name) {\n                        ordered_map.insert(field_name.clone(), serialized_value);\n                    }\n                }\n                // Explicitly return a `Value::Object` to avoid ambiguity.\n                return Ok(Value::Object(ordered_map));\n            }\n\n            // Otherwise, fall back to alphabetical sorting for deterministic output.\n            Ok(Value::Object(map.into_iter().collect::<Map<String, Value>>()))\n        }\n        DynSolValue::Tuple(values) => Ok(Value::Array(\n            values.into_iter().map(|v| _serialize_value_as_json(v, defs)).collect::<Result<_>>()?,\n        )),\n        DynSolValue::Function(_) => eyre::bail!(\"cannot serialize function pointer\"),\n    }\n}\n\n// -- STRUCT DEFINITIONS -------------------------------------------------------\n\npub type TypeDefMap = BTreeMap<String, Vec<(String, String)>>;\n\n#[derive(Debug, Clone, Default)]\npub struct StructDefinitions(TypeDefMap);\n\nimpl From<TypeDefMap> for StructDefinitions {\n    fn from(map: TypeDefMap) -> Self {\n        Self::new(map)\n    }\n}\n\nimpl StructDefinitions {\n    pub fn new(map: TypeDefMap) -> Self {\n        Self(map)\n    }\n\n    pub fn keys(&self) -> impl Iterator<Item = &String> {\n        self.0.keys()\n    }\n\n    pub fn values(&self) -> impl Iterator<Item = &[(String, String)]> {\n        self.0.values().map(|v| v.as_slice())\n    }\n\n    pub fn get(&self, key: &str) -> eyre::Result<Option<&[(String, String)]>> {\n        if let Some(value) = self.0.get(key) {\n            return Ok(Some(value));\n        }\n\n        let matches: Vec<&[(String, String)]> = self\n            .0\n            .iter()\n            .filter_map(|(k, v)| {\n                if let Some((_, struct_name)) = k.split_once('.')\n                    && struct_name == key\n                {\n                    return Some(v.as_slice());\n                }\n                None\n            })\n            .collect();\n\n        match matches.len() {\n            0 => Ok(None),\n            1 => Ok(Some(matches[0])),\n            _ => eyre::bail!(\n                \"there are several structs with the same name. Use `<contract_name>.{key}` instead.\"\n            ),\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use alloy_primitives::{U256, address};\n\n    #[test]\n    fn parse_hex_uint() {\n        let ty = DynSolType::Uint(256);\n\n        let values = parse_tokens(std::iter::once((&ty, \"100\"))).unwrap();\n        assert_eq!(values, [DynSolValue::Uint(U256::from(100), 256)]);\n\n        let val: U256 = U256::from(100u64);\n        let hex_val = format!(\"0x{val:x}\");\n        let values = parse_tokens(std::iter::once((&ty, hex_val.as_str()))).unwrap();\n        assert_eq!(values, [DynSolValue::Uint(U256::from(100), 256)]);\n    }\n\n    #[test]\n    fn format_addr() {\n        // copied from testcases in https://github.com/ethereum/EIPs/blob/master/EIPS/eip-55.md\n        assert_eq!(\n            format_token(&DynSolValue::Address(address!(\n                \"0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed\"\n            ))),\n            \"0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed\",\n        );\n\n        // copied from testcases in https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1191.md\n        assert_ne!(\n            format_token(&DynSolValue::Address(address!(\n                \"0xFb6916095cA1Df60bb79ce92cE3EA74c37c5d359\"\n            ))),\n            \"0xFb6916095cA1Df60bb79ce92cE3EA74c37c5d359\"\n        );\n    }\n}\n"
  },
  {
    "path": "crates/common/fmt/src/exp.rs",
    "content": "use alloy_primitives::{I256, Sign, U256};\nuse yansi::Paint;\n\n/// Returns the number expressed as a string in exponential notation\n/// with the given precision (number of significant figures),\n/// optionally removing trailing zeros from the mantissa.\n///\n/// Examples:\n///\n/// ```text\n/// precision = 4, trim_end_zeroes = false\n///     1234124124 -> 1.234e9\n///     10000000 -> 1.000e7\n/// precision = 3, trim_end_zeroes = true\n///     1234124124 -> 1.23e9\n///     10000000 -> 1e7\n/// ```\npub fn to_exp_notation(value: U256, precision: usize, trim_end_zeros: bool, sign: Sign) -> String {\n    let stringified = value.to_string();\n    let exponent = stringified.len() - 1;\n    let mut mantissa = stringified.chars().take(precision).collect::<String>();\n\n    // optionally remove trailing zeros\n    if trim_end_zeros {\n        mantissa = mantissa.trim_end_matches('0').to_string();\n    }\n\n    // Place a decimal point only if needed\n    // e.g. 1234 -> 1.234e3 (needed)\n    //      5 -> 5 (not needed)\n    if mantissa.len() > 1 {\n        mantissa.insert(1, '.');\n    }\n\n    format!(\"{sign}{mantissa}e{exponent}\")\n}\n\n/// Formats a U256 number to string, adding an exponential notation _hint_ if it\n/// is larger than `10_000`, with a precision of `4` figures, and trimming the\n/// trailing zeros.\n///\n/// # Examples\n///\n/// ```\n/// use alloy_primitives::U256;\n/// use foundry_common_fmt::format_uint_exp as f;\n///\n/// # yansi::disable();\n/// assert_eq!(f(U256::from(0)), \"0\");\n/// assert_eq!(f(U256::from(1234)), \"1234\");\n/// assert_eq!(f(U256::from(1234567890)), \"1234567890 [1.234e9]\");\n/// assert_eq!(f(U256::from(1000000000000000000_u128)), \"1000000000000000000 [1e18]\");\n/// assert_eq!(f(U256::from(10000000000000000000000_u128)), \"10000000000000000000000 [1e22]\");\n/// ```\npub fn format_uint_exp(num: U256) -> String {\n    if num < U256::from(10_000) {\n        return num.to_string();\n    }\n\n    let exp = to_exp_notation(num, 4, true, Sign::Positive);\n    format!(\"{num} {}\", format!(\"[{exp}]\").dim())\n}\n\n/// Formats a U256 number to string, adding an exponential notation _hint_.\n///\n/// Same as [`format_uint_exp`].\n///\n/// # Examples\n///\n/// ```\n/// use alloy_primitives::I256;\n/// use foundry_common_fmt::format_int_exp as f;\n///\n/// # yansi::disable();\n/// assert_eq!(f(I256::try_from(0).unwrap()), \"0\");\n/// assert_eq!(f(I256::try_from(-1).unwrap()), \"-1\");\n/// assert_eq!(f(I256::try_from(1234).unwrap()), \"1234\");\n/// assert_eq!(f(I256::try_from(1234567890).unwrap()), \"1234567890 [1.234e9]\");\n/// assert_eq!(f(I256::try_from(-1234567890).unwrap()), \"-1234567890 [-1.234e9]\");\n/// assert_eq!(f(I256::try_from(1000000000000000000_u128).unwrap()), \"1000000000000000000 [1e18]\");\n/// assert_eq!(\n///     f(I256::try_from(10000000000000000000000_u128).unwrap()),\n///     \"10000000000000000000000 [1e22]\"\n/// );\n/// assert_eq!(\n///     f(I256::try_from(-10000000000000000000000_i128).unwrap()),\n///     \"-10000000000000000000000 [-1e22]\"\n/// );\n/// ```\npub fn format_int_exp(num: I256) -> String {\n    let (sign, abs) = num.into_sign_and_abs();\n    if abs < U256::from(10_000) {\n        return format!(\"{sign}{abs}\");\n    }\n\n    let exp = to_exp_notation(abs, 4, true, sign);\n    format!(\"{sign}{abs} {}\", format!(\"[{exp}]\").dim())\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_format_to_exponential_notation() {\n        let value = 1234124124u64;\n\n        let formatted = to_exp_notation(U256::from(value), 4, false, Sign::Positive);\n        assert_eq!(formatted, \"1.234e9\");\n\n        let formatted = to_exp_notation(U256::from(value), 3, true, Sign::Positive);\n        assert_eq!(formatted, \"1.23e9\");\n\n        let value = 10000000u64;\n\n        let formatted = to_exp_notation(U256::from(value), 4, false, Sign::Positive);\n        assert_eq!(formatted, \"1.000e7\");\n\n        let formatted = to_exp_notation(U256::from(value), 3, true, Sign::Positive);\n        assert_eq!(formatted, \"1e7\");\n    }\n}\n"
  },
  {
    "path": "crates/common/fmt/src/lib.rs",
    "content": "//! Helpers for formatting Ethereum types.\n\n#![cfg_attr(not(test), warn(unused_crate_dependencies))]\n\nmod console;\npub use console::{ConsoleFmt, FormatSpec, console_format};\n\nmod dynamic;\npub use dynamic::{\n    StructDefinitions, TypeDefMap, format_token, format_token_raw, format_tokens,\n    format_tokens_raw, parse_tokens, serialize_value_as_json,\n};\n\nmod exp;\npub use exp::{format_int_exp, format_uint_exp, to_exp_notation};\n\nmod ui;\npub use ui::{\n    EthValue, UIfmt, UIfmtHeaderExt, UIfmtReceiptExt, UIfmtSignatureExt, get_pretty_block_attr,\n    get_pretty_receipt_attr, get_pretty_tx_attr,\n};\n"
  },
  {
    "path": "crates/common/fmt/src/ui.rs",
    "content": "//! Helper trait and functions to format Ethereum types.\n\nuse alloy_consensus::{\n    BlockHeader, Eip658Value, Receipt, ReceiptWithBloom, Signed, Transaction as TxTrait, TxEip1559,\n    TxEip2930, TxEip4844Variant, TxEip7702, TxEnvelope, TxLegacy, TxReceipt, Typed2718,\n    transaction::TxHashRef,\n};\nuse alloy_network::{\n    AnyReceiptEnvelope, AnyRpcBlock, AnyRpcHeader, AnyRpcTransaction, AnyTransactionReceipt,\n    AnyTxEnvelope, BlockResponse, Network, ReceiptResponse, primitives::HeaderResponse,\n};\nuse alloy_primitives::{\n    Address, Bloom, Bytes, FixedBytes, I256, Signature, U8, U64, U256, Uint, hex,\n};\nuse alloy_rpc_types::{\n    AccessListItem, Block, BlockTransactions, Header, Log, Transaction, TransactionReceipt,\n};\nuse alloy_serde::{OtherFields, WithOtherFields};\nuse foundry_primitives::{FoundryReceiptEnvelope, FoundryTxEnvelope, FoundryTxReceipt};\nuse op_alloy_consensus::{OpTxEnvelope, TxDeposit};\nuse revm::context_interface::transaction::SignedAuthorization;\nuse serde::Deserialize;\nuse tempo_alloy::{\n    primitives::{\n        AASigned, TempoSignature, TempoTransaction, TempoTxEnvelope,\n        transaction::{Call, PrimitiveSignature},\n    },\n    rpc::{TempoHeaderResponse, TempoTransactionReceipt},\n};\n\n/// length of the name column for pretty formatting `{:>20}{value}`\nconst NAME_COLUMN_LEN: usize = 20usize;\n\n/// Helper trait to format Ethereum types.\n///\n/// # Examples\n///\n/// ```\n/// use foundry_common_fmt::UIfmt;\n///\n/// let boolean: bool = true;\n/// let string = boolean.pretty();\n/// ```\npub trait UIfmt {\n    /// Return a prettified string version of the value\n    fn pretty(&self) -> String;\n}\n\nimpl<T: UIfmt> UIfmt for &T {\n    fn pretty(&self) -> String {\n        (*self).pretty()\n    }\n}\n\nimpl<T: UIfmt> UIfmt for Option<T> {\n    fn pretty(&self) -> String {\n        if let Some(inner) = self { inner.pretty() } else { String::new() }\n    }\n}\n\nimpl<T: UIfmt> UIfmt for [T] {\n    fn pretty(&self) -> String {\n        if !self.is_empty() {\n            let mut s = String::with_capacity(self.len() * 64);\n            s.push_str(\"[\\n\");\n            for item in self {\n                for line in item.pretty().lines() {\n                    s.push('\\t');\n                    s.push_str(line);\n                    s.push('\\n');\n                }\n            }\n            s.push(']');\n            s\n        } else {\n            \"[]\".to_string()\n        }\n    }\n}\n\nimpl UIfmt for String {\n    fn pretty(&self) -> String {\n        self.to_string()\n    }\n}\n\nimpl UIfmt for u64 {\n    fn pretty(&self) -> String {\n        self.to_string()\n    }\n}\n\nimpl UIfmt for u128 {\n    fn pretty(&self) -> String {\n        self.to_string()\n    }\n}\n\nimpl UIfmt for bool {\n    fn pretty(&self) -> String {\n        self.to_string()\n    }\n}\n\nimpl<const BITS: usize, const LIMBS: usize> UIfmt for Uint<BITS, LIMBS> {\n    fn pretty(&self) -> String {\n        self.to_string()\n    }\n}\n\nimpl UIfmt for I256 {\n    fn pretty(&self) -> String {\n        self.to_string()\n    }\n}\n\nimpl UIfmt for Address {\n    fn pretty(&self) -> String {\n        self.to_string()\n    }\n}\n\nimpl UIfmt for Bloom {\n    fn pretty(&self) -> String {\n        self.to_string()\n    }\n}\n\nimpl UIfmt for Vec<u8> {\n    fn pretty(&self) -> String {\n        self[..].pretty()\n    }\n}\n\nimpl UIfmt for Bytes {\n    fn pretty(&self) -> String {\n        self[..].pretty()\n    }\n}\n\nimpl<const N: usize> UIfmt for [u8; N] {\n    fn pretty(&self) -> String {\n        self[..].pretty()\n    }\n}\n\nimpl<const N: usize> UIfmt for FixedBytes<N> {\n    fn pretty(&self) -> String {\n        self[..].pretty()\n    }\n}\n\nimpl UIfmt for [u8] {\n    fn pretty(&self) -> String {\n        hex::encode_prefixed(self)\n    }\n}\n\nimpl UIfmt for Eip658Value {\n    fn pretty(&self) -> String {\n        match self {\n            Self::Eip658(status) => if *status { \"1 (success)\" } else { \"0 (failed)\" }.to_string(),\n            Self::PostState(state) => state.pretty(),\n        }\n    }\n}\n\nimpl UIfmt for Signature {\n    fn pretty(&self) -> String {\n        format!(\"[r: {}, s: {}, y_parity: {}]\", self.r(), self.s(), self.v())\n    }\n}\n\nimpl UIfmt for AnyTransactionReceipt {\n    fn pretty(&self) -> String {\n        let Self {\n            inner:\n                TransactionReceipt {\n                    transaction_hash,\n                    transaction_index,\n                    block_hash,\n                    block_number,\n                    from,\n                    to,\n                    gas_used,\n                    contract_address,\n                    effective_gas_price,\n                    inner:\n                        AnyReceiptEnvelope {\n                            r#type: transaction_type,\n                            inner:\n                                ReceiptWithBloom {\n                                    receipt: Receipt { status, cumulative_gas_used, logs },\n                                    logs_bloom,\n                                },\n                        },\n                    blob_gas_price,\n                    blob_gas_used,\n                },\n            other,\n        } = self;\n\n        let mut pretty = format!(\n            \"\nblockHash            {}\nblockNumber          {}\ncontractAddress      {}\ncumulativeGasUsed    {}\neffectiveGasPrice    {}\nfrom                 {}\ngasUsed              {}\nlogs                 {}\nlogsBloom            {}\nroot                 {}\nstatus               {}\ntransactionHash      {}\ntransactionIndex     {}\ntype                 {}\nblobGasPrice         {}\nblobGasUsed          {}\",\n            block_hash.pretty(),\n            block_number.pretty(),\n            contract_address.pretty(),\n            cumulative_gas_used.pretty(),\n            effective_gas_price.pretty(),\n            from.pretty(),\n            gas_used.pretty(),\n            serde_json::to_string(&logs).unwrap(),\n            logs_bloom.pretty(),\n            self.state_root().pretty(),\n            status.pretty(),\n            transaction_hash.pretty(),\n            transaction_index.pretty(),\n            transaction_type,\n            blob_gas_price.pretty(),\n            blob_gas_used.pretty()\n        );\n\n        if let Some(to) = to {\n            pretty.push_str(&format!(\"\\nto                   {}\", to.pretty()));\n        }\n\n        // additional captured fields\n        pretty.push_str(&other.pretty());\n\n        pretty\n    }\n}\n\nimpl UIfmt for Log {\n    fn pretty(&self) -> String {\n        format!(\n            \"\naddress: {}\nblockHash: {}\nblockNumber: {}\ndata: {}\nlogIndex: {}\nremoved: {}\ntopics: {}\ntransactionHash: {}\ntransactionIndex: {}\",\n            self.address().pretty(),\n            self.block_hash.pretty(),\n            self.block_number.pretty(),\n            self.data().data.pretty(),\n            self.log_index.pretty(),\n            self.removed.pretty(),\n            self.topics().pretty(),\n            self.transaction_hash.pretty(),\n            self.transaction_index.pretty(),\n        )\n    }\n}\n\nimpl<T: UIfmt, H: HeaderResponse + UIfmtHeaderExt> UIfmt for Block<T, H> {\n    fn pretty(&self) -> String {\n        format!(\n            \"\n{}\ntransactions:        {}\",\n            pretty_generic_header_response(&self.header),\n            self.transactions.pretty()\n        )\n    }\n}\n\nimpl<T: UIfmt> UIfmt for BlockTransactions<T> {\n    fn pretty(&self) -> String {\n        match self {\n            Self::Hashes(hashes) => hashes.pretty(),\n            Self::Full(transactions) => transactions.pretty(),\n            Self::Uncle => String::new(),\n        }\n    }\n}\n\nimpl UIfmt for OtherFields {\n    fn pretty(&self) -> String {\n        let mut s = String::with_capacity(self.len() * 30);\n        if !self.is_empty() {\n            s.push('\\n');\n        }\n        for (key, value) in self {\n            let val = EthValue::from(value.clone()).pretty();\n            let offset = NAME_COLUMN_LEN.saturating_sub(key.len());\n            s.push_str(key);\n            s.extend(std::iter::repeat_n(' ', offset + 1));\n            s.push_str(&val);\n            s.push('\\n');\n        }\n        s\n    }\n}\n\nimpl UIfmt for AccessListItem {\n    fn pretty(&self) -> String {\n        let mut s = String::with_capacity(42 + self.storage_keys.len() * 66);\n        s.push_str(self.address.pretty().as_str());\n        s.push_str(\" => \");\n        s.push_str(self.storage_keys.pretty().as_str());\n        s\n    }\n}\n\nimpl UIfmt for TxLegacy {\n    fn pretty(&self) -> String {\n        format!(\n            \"\nchainId              {}\nnonce                {}\ngasPrice             {}\ngasLimit             {}\nto                   {}\nvalue                {}\ninput                {}\",\n            self.chain_id.pretty(),\n            self.nonce.pretty(),\n            self.gas_price.pretty(),\n            self.gas_limit.pretty(),\n            self.to().pretty(),\n            self.value.pretty(),\n            self.input.pretty(),\n        )\n    }\n}\n\nimpl UIfmt for TxEip2930 {\n    fn pretty(&self) -> String {\n        format!(\n            \"\nchainId              {}\nnonce                {}\ngasPrice             {}\ngasLimit             {}\nto                   {}\nvalue                {}\naccessList           {}\ninput                {}\",\n            self.chain_id.pretty(),\n            self.nonce.pretty(),\n            self.gas_price.pretty(),\n            self.gas_limit.pretty(),\n            self.to().pretty(),\n            self.value.pretty(),\n            self.access_list.pretty(),\n            self.input.pretty(),\n        )\n    }\n}\n\nimpl UIfmt for TxEip1559 {\n    fn pretty(&self) -> String {\n        format!(\n            \"\nchainId              {}\nnonce                {}\ngasLimit             {}\nmaxFeePerGas         {}\nmaxPriorityFeePerGas {}\nto                   {}\nvalue                {}\naccessList           {}\ninput                {}\",\n            self.chain_id.pretty(),\n            self.nonce.pretty(),\n            self.gas_limit.pretty(),\n            self.max_fee_per_gas.pretty(),\n            self.max_priority_fee_per_gas.pretty(),\n            self.to().pretty(),\n            self.value.pretty(),\n            self.access_list.pretty(),\n            self.input.pretty(),\n        )\n    }\n}\n\nimpl UIfmt for TxEip4844Variant {\n    fn pretty(&self) -> String {\n        use alloy_consensus::TxEip4844;\n        let tx: &TxEip4844 = match self {\n            Self::TxEip4844(tx) => tx,\n            Self::TxEip4844WithSidecar(tx) => tx.tx(),\n        };\n        format!(\n            \"\nchainId              {}\nnonce                {}\ngasLimit             {}\nmaxFeePerGas         {}\nmaxPriorityFeePerGas {}\nto                   {}\nvalue                {}\naccessList           {}\nblobVersionedHashes  {}\nmaxFeePerBlobGas     {}\ninput                {}\",\n            tx.chain_id.pretty(),\n            tx.nonce.pretty(),\n            tx.gas_limit.pretty(),\n            tx.max_fee_per_gas.pretty(),\n            tx.max_priority_fee_per_gas.pretty(),\n            tx.to.pretty(),\n            tx.value.pretty(),\n            tx.access_list.pretty(),\n            tx.blob_versioned_hashes.pretty(),\n            tx.max_fee_per_blob_gas.pretty(),\n            tx.input.pretty(),\n        )\n    }\n}\n\nimpl UIfmt for TxEip7702 {\n    fn pretty(&self) -> String {\n        format!(\n            \"\nchainId              {}\nnonce                {}\ngasLimit             {}\nmaxFeePerGas         {}\nmaxPriorityFeePerGas {}\nto                   {}\nvalue                {}\naccessList           {}\nauthorizationList    {}\ninput                {}\",\n            self.chain_id.pretty(),\n            self.nonce.pretty(),\n            self.gas_limit.pretty(),\n            self.max_fee_per_gas.pretty(),\n            self.max_priority_fee_per_gas.pretty(),\n            self.to.pretty(),\n            self.value.pretty(),\n            self.access_list.pretty(),\n            self.authorization_list.pretty(),\n            self.input.pretty(),\n        )\n    }\n}\n\nimpl UIfmt for TxDeposit {\n    fn pretty(&self) -> String {\n        format!(\n            \"\nsourceHash           {}\nfrom                 {}\nto                   {}\nmint                 {}\nvalue                {}\ngasLimit             {}\nisSystemTransaction  {}\ninput                {}\",\n            self.source_hash.pretty(),\n            self.from.pretty(),\n            self.to().pretty(),\n            self.mint.pretty(),\n            self.value.pretty(),\n            self.gas_limit.pretty(),\n            self.is_system_transaction,\n            self.input.pretty(),\n        )\n    }\n}\n\nimpl UIfmt for Call {\n    fn pretty(&self) -> String {\n        format!(\n            \"to: {}, value: {}, input: {}\",\n            self.to.into_to().pretty(),\n            self.value.pretty(),\n            self.input.pretty(),\n        )\n    }\n}\n\nimpl UIfmt for TempoTransaction {\n    fn pretty(&self) -> String {\n        format!(\n            \"\nchainId              {}\nfeeToken             {}\nmaxPriorityFeePerGas {}\nmaxFeePerGas         {}\ngasLimit             {}\ncalls                {}\naccessList           {}\nnonceKey             {}\nnonce                {}\nfeePayerSignature    {}\nvalidBefore          {}\nvalidAfter           {}\",\n            self.chain_id.pretty(),\n            self.fee_token.pretty(),\n            self.max_priority_fee_per_gas.pretty(),\n            self.max_fee_per_gas.pretty(),\n            self.gas_limit.pretty(),\n            self.calls.pretty(),\n            self.access_list.pretty(),\n            self.nonce_key.pretty(),\n            self.nonce.pretty(),\n            self.fee_payer_signature.pretty(),\n            self.valid_after.pretty(),\n            self.valid_before.pretty(),\n        )\n    }\n}\n\nimpl UIfmt for TempoSignature {\n    fn pretty(&self) -> String {\n        serde_json::to_string(self).unwrap_or_default()\n    }\n}\n\nimpl UIfmt for AASigned {\n    fn pretty(&self) -> String {\n        format!(\n            \"\nhash                 {}\ntype                 {}\n{}\ntempoSignature       {}\",\n            self.hash().pretty(),\n            self.tx().ty(),\n            self.tx().pretty().trim_start(),\n            self.signature().pretty(),\n        )\n    }\n}\n\nimpl<T: UIfmt + Typed2718> UIfmt for Signed<T>\nwhere\n    Self: TxHashRef,\n{\n    fn pretty(&self) -> String {\n        format!(\n            \"\nhash                 {}\ntype                 {}\n{}\nr                    {}\ns                    {}\nyParity              {}\",\n            self.tx_hash().pretty(),\n            self.ty(),\n            self.tx().pretty().trim_start(),\n            FixedBytes::from(self.signature().r()).pretty(),\n            FixedBytes::from(self.signature().s()).pretty(),\n            (if self.signature().v() { 1u64 } else { 0 }).pretty(),\n        )\n    }\n}\n\nimpl UIfmt for TxEnvelope {\n    fn pretty(&self) -> String {\n        match self {\n            Self::Legacy(tx) => tx.pretty(),\n            Self::Eip2930(tx) => tx.pretty(),\n            Self::Eip1559(tx) => tx.pretty(),\n            Self::Eip4844(tx) => tx.pretty(),\n            Self::Eip7702(tx) => tx.pretty(),\n        }\n    }\n}\n\nimpl UIfmt for AnyTxEnvelope {\n    fn pretty(&self) -> String {\n        match self {\n            Self::Ethereum(envelop) => envelop.pretty(),\n            Self::Unknown(tx) => {\n                format!(\n                    \"\nhash                 {}\ntype               {:#x}\n{}\n                    \",\n                    tx.hash.pretty(),\n                    tx.ty(),\n                    tx.inner.fields.pretty().trim_start(),\n                )\n            }\n        }\n    }\n}\n\nimpl UIfmt for OpTxEnvelope {\n    fn pretty(&self) -> String {\n        match self {\n            Self::Legacy(tx) => tx.pretty(),\n            Self::Eip2930(tx) => tx.pretty(),\n            Self::Eip1559(tx) => tx.pretty(),\n            Self::Eip7702(tx) => tx.pretty(),\n            Self::Deposit(tx) => tx.pretty(),\n        }\n    }\n}\n\nimpl UIfmt for TempoTxEnvelope {\n    fn pretty(&self) -> String {\n        match self {\n            Self::Legacy(tx) => tx.pretty(),\n            Self::Eip2930(tx) => tx.pretty(),\n            Self::Eip1559(tx) => tx.pretty(),\n            Self::Eip7702(tx) => tx.pretty(),\n            Self::AA(tx) => tx.pretty(),\n        }\n    }\n}\n\nimpl<T: UIfmt> UIfmt for Transaction<T> {\n    fn pretty(&self) -> String {\n        format!(\n            \"\nblockHash            {}\nblockNumber          {}\nfrom                 {}\ntransactionIndex     {}\neffectiveGasPrice    {}\n{}\",\n            self.block_hash.pretty(),\n            self.block_number.pretty(),\n            self.inner.signer().pretty(),\n            self.transaction_index.pretty(),\n            self.effective_gas_price.pretty(),\n            self.inner.inner().pretty().trim_start(),\n        )\n    }\n}\n\nimpl<T: UIfmt> UIfmt for op_alloy_rpc_types::Transaction<T> {\n    fn pretty(&self) -> String {\n        format!(\n            \"\ndepositNonce         {}\ndepositReceiptVersion {}\n{}\",\n            self.deposit_nonce.pretty(),\n            self.deposit_receipt_version.pretty(),\n            self.inner.pretty().trim_start(),\n        )\n    }\n}\n\nimpl UIfmt for AnyRpcBlock {\n    fn pretty(&self) -> String {\n        self.0.pretty()\n    }\n}\n\nimpl UIfmt for AnyRpcTransaction {\n    fn pretty(&self) -> String {\n        self.0.pretty()\n    }\n}\n\nimpl<T: UIfmt> UIfmt for WithOtherFields<T> {\n    fn pretty(&self) -> String {\n        format!(\"{}{}\", self.inner.pretty(), self.other.pretty())\n    }\n}\n\n/// Various numerical ethereum types used for pretty printing\n#[derive(Clone, Debug, Deserialize)]\n#[serde(untagged)]\n#[expect(missing_docs)]\npub enum EthValue {\n    U64(U64),\n    Address(Address),\n    U256(U256),\n    U64Array(Vec<U64>),\n    U256Array(Vec<U256>),\n    Other(serde_json::Value),\n}\n\nimpl From<serde_json::Value> for EthValue {\n    fn from(val: serde_json::Value) -> Self {\n        serde_json::from_value(val).expect(\"infallible\")\n    }\n}\n\nimpl UIfmt for EthValue {\n    fn pretty(&self) -> String {\n        match self {\n            Self::U64(num) => num.pretty(),\n            Self::U256(num) => num.pretty(),\n            Self::Address(addr) => addr.pretty(),\n            Self::U64Array(arr) => arr.pretty(),\n            Self::U256Array(arr) => arr.pretty(),\n            Self::Other(val) => val.to_string().trim_matches('\"').to_string(),\n        }\n    }\n}\n\nimpl UIfmt for SignedAuthorization {\n    fn pretty(&self) -> String {\n        let signed_authorization = serde_json::to_string(self).unwrap_or(\"<invalid>\".to_string());\n\n        match self.recover_authority() {\n            Ok(authority) => format!(\n                \"{{recoveredAuthority: {authority}, signedAuthority: {signed_authorization}}}\",\n            ),\n            Err(e) => format!(\n                \"{{recoveredAuthority: <error: {e}>, signedAuthority: {signed_authorization}}}\",\n            ),\n        }\n    }\n}\n\nimpl<T> UIfmt for FoundryReceiptEnvelope<T>\nwhere\n    T: UIfmt + Clone + core::fmt::Debug + PartialEq + Eq,\n{\n    fn pretty(&self) -> String {\n        let receipt = self.as_receipt();\n        let deposit_info = match self {\n            Self::Deposit(d) => {\n                format!(\n                    \"\ndepositNonce         {}\ndepositReceiptVersion {}\",\n                    d.receipt.deposit_nonce.pretty(),\n                    d.receipt.deposit_receipt_version.pretty()\n                )\n            }\n            _ => String::new(),\n        };\n\n        format!(\n            \"\nstatus               {}\ncumulativeGasUsed    {}\nlogs                 {}\nlogsBloom            {}\ntype                 {}{}\",\n            receipt.status.pretty(),\n            receipt.cumulative_gas_used.pretty(),\n            receipt.logs.pretty(),\n            self.logs_bloom().pretty(),\n            self.tx_type() as u8,\n            deposit_info\n        )\n    }\n}\n\nimpl UIfmt for FoundryTxReceipt {\n    fn pretty(&self) -> String {\n        let receipt = &self.0.inner;\n        let other = &self.0.other;\n\n        let mut pretty = format!(\n            \"\nblockHash            {}\nblockNumber          {}\ncontractAddress      {}\ncumulativeGasUsed    {}\neffectiveGasPrice    {}\nfrom                 {}\ngasUsed              {}\nlogs                 {}\nlogsBloom            {}\nroot                 {}\nstatus               {}\ntransactionHash      {}\ntransactionIndex     {}\ntype                 {}\nblobGasPrice         {}\nblobGasUsed          {}\",\n            receipt.block_hash().pretty(),\n            receipt.block_number().pretty(),\n            receipt.contract_address().pretty(),\n            receipt.cumulative_gas_used().pretty(),\n            receipt.effective_gas_price().pretty(),\n            receipt.from().pretty(),\n            receipt.gas_used().pretty(),\n            serde_json::to_string(receipt.inner.logs()).unwrap(),\n            receipt.inner.logs_bloom().pretty(),\n            self.state_root().pretty(),\n            receipt.status().pretty(),\n            receipt.transaction_hash().pretty(),\n            receipt.transaction_index().pretty(),\n            receipt.inner.tx_type() as u8,\n            receipt.blob_gas_price().pretty(),\n            receipt.blob_gas_used().pretty()\n        );\n\n        if let Some(to) = receipt.to() {\n            pretty.push_str(&format!(\"\\nto                   {}\", to.pretty()));\n        }\n\n        // additional captured fields\n        pretty.push_str(&other.pretty());\n\n        pretty\n    }\n}\n\npub trait UIfmtHeaderExt {\n    fn size_pretty(&self) -> String;\n}\n\nimpl UIfmtHeaderExt for Header {\n    fn size_pretty(&self) -> String {\n        self.size.pretty()\n    }\n}\n\nimpl UIfmtHeaderExt for AnyRpcHeader {\n    fn size_pretty(&self) -> String {\n        self.size.pretty()\n    }\n}\n\nimpl UIfmtHeaderExt for TempoHeaderResponse {\n    fn size_pretty(&self) -> String {\n        self.inner.size.pretty()\n    }\n}\n\npub trait UIfmtSignatureExt {\n    fn signature_pretty(&self) -> Option<(String, String, String)>;\n}\n\nimpl UIfmtSignatureExt for TxEnvelope {\n    fn signature_pretty(&self) -> Option<(String, String, String)> {\n        let sig = self.signature();\n        Some((\n            FixedBytes::from(sig.r()).pretty(),\n            FixedBytes::from(sig.s()).pretty(),\n            U8::from_le_slice(&sig.as_bytes()[64..]).pretty(),\n        ))\n    }\n}\n\nimpl UIfmtSignatureExt for AnyTxEnvelope {\n    fn signature_pretty(&self) -> Option<(String, String, String)> {\n        self.as_envelope().and_then(|envelope| envelope.signature_pretty())\n    }\n}\n\nimpl UIfmtSignatureExt for OpTxEnvelope {\n    fn signature_pretty(&self) -> Option<(String, String, String)> {\n        self.signature().map(|sig| {\n            (\n                FixedBytes::from(sig.r()).pretty(),\n                FixedBytes::from(sig.s()).pretty(),\n                U8::from_le_slice(&sig.as_bytes()[64..]).pretty(),\n            )\n        })\n    }\n}\n\nimpl UIfmtSignatureExt for FoundryTxEnvelope {\n    fn signature_pretty(&self) -> Option<(String, String, String)> {\n        self.clone().try_into_eth().ok().and_then(|envelope| envelope.signature_pretty())\n    }\n}\n\nimpl UIfmtSignatureExt for TempoTxEnvelope {\n    fn signature_pretty(&self) -> Option<(String, String, String)> {\n        let sig = match self {\n            Self::Legacy(tx) => Some(tx.signature()),\n            Self::Eip2930(tx) => Some(tx.signature()),\n            Self::Eip1559(tx) => Some(tx.signature()),\n            Self::Eip7702(tx) => Some(tx.signature()),\n            Self::AA(tempo_tx) => {\n                if let TempoSignature::Primitive(PrimitiveSignature::Secp256k1(sig)) =\n                    tempo_tx.signature()\n                {\n                    Some(sig)\n                } else {\n                    None\n                }\n            }\n        }?;\n        Some((\n            FixedBytes::from(sig.r()).pretty(),\n            FixedBytes::from(sig.s()).pretty(),\n            U8::from_le_slice(&sig.as_bytes()[64..]).pretty(),\n        ))\n    }\n}\n\npub trait UIfmtReceiptExt {\n    fn logs_pretty(&self) -> String;\n    fn logs_bloom_pretty(&self) -> String;\n    fn tx_type_pretty(&self) -> String;\n}\n\nimpl UIfmtReceiptExt for AnyTransactionReceipt {\n    fn logs_pretty(&self) -> String {\n        serde_json::to_string(&self.inner.inner.inner.receipt.logs).unwrap_or_default()\n    }\n\n    fn logs_bloom_pretty(&self) -> String {\n        self.inner.inner.inner.logs_bloom.pretty()\n    }\n\n    fn tx_type_pretty(&self) -> String {\n        self.inner.inner.r#type.to_string()\n    }\n}\n\nimpl UIfmtReceiptExt for FoundryTxReceipt {\n    fn logs_pretty(&self) -> String {\n        serde_json::to_string(self.0.inner.inner.logs()).unwrap_or_default()\n    }\n\n    fn logs_bloom_pretty(&self) -> String {\n        self.0.inner.inner.logs_bloom().pretty()\n    }\n\n    fn tx_type_pretty(&self) -> String {\n        (self.0.inner.inner.tx_type() as u8).to_string()\n    }\n}\n\nimpl UIfmt for TempoTransactionReceipt {\n    fn pretty(&self) -> String {\n        let receipt = &self.inner;\n\n        let mut pretty = format!(\n            \"\nblockHash            {}\nblockNumber          {}\ncontractAddress      {}\ncumulativeGasUsed    {}\neffectiveGasPrice    {}\nfrom                 {}\ngasUsed              {}\nlogs                 {}\nlogsBloom            {}\nroot                 {}\nstatus               {}\ntransactionHash      {}\ntransactionIndex     {}\ntype                 {}\nfeePayer             {}\nfeeToken             {}\",\n            receipt.block_hash().pretty(),\n            receipt.block_number().pretty(),\n            receipt.contract_address().pretty(),\n            receipt.cumulative_gas_used().pretty(),\n            receipt.effective_gas_price().pretty(),\n            receipt.from().pretty(),\n            receipt.gas_used().pretty(),\n            serde_json::to_string(receipt.inner.logs()).unwrap(),\n            receipt.inner.logs_bloom.pretty(),\n            self.state_root().pretty(),\n            receipt.status().pretty(),\n            receipt.transaction_hash().pretty(),\n            receipt.transaction_index().pretty(),\n            receipt.inner.receipt.tx_type as u8,\n            self.fee_payer.pretty(),\n            self.fee_token.pretty(),\n        );\n\n        if let Some(to) = receipt.to() {\n            pretty.push_str(&format!(\"\\nto                   {}\", to.pretty()));\n        }\n\n        pretty\n    }\n}\n\nimpl UIfmtReceiptExt for TempoTransactionReceipt {\n    fn logs_pretty(&self) -> String {\n        serde_json::to_string(self.inner.inner.logs()).unwrap_or_default()\n    }\n\n    fn logs_bloom_pretty(&self) -> String {\n        self.inner.inner.logs_bloom.pretty()\n    }\n\n    fn tx_type_pretty(&self) -> String {\n        (self.inner.inner.receipt.tx_type as u8).to_string()\n    }\n}\n\n/// Returns the `UiFmt::pretty()` formatted attribute of the transactions\npub fn get_pretty_tx_attr<N>(transaction: &N::TransactionResponse, attr: &str) -> Option<String>\nwhere\n    N: Network,\n    N::TxEnvelope: UIfmtSignatureExt,\n{\n    let (r, s, v) = transaction.as_ref().signature_pretty().unwrap_or_default();\n    match attr {\n        \"blockHash\" | \"block_hash\" => {\n            Some(alloy_network::TransactionResponse::block_hash(transaction).pretty())\n        }\n        \"blockNumber\" | \"block_number\" => {\n            Some(alloy_network::TransactionResponse::block_number(transaction).pretty())\n        }\n        \"from\" => Some(alloy_network::TransactionResponse::from(transaction).pretty()),\n        \"gas\" => Some(TxTrait::gas_limit(transaction).pretty()),\n        \"gasPrice\" | \"gas_price\" => Some(TxTrait::max_fee_per_gas(transaction).pretty()),\n        \"hash\" => Some(alloy_network::TransactionResponse::tx_hash(transaction).pretty()),\n        \"input\" => Some(TxTrait::input(transaction).pretty()),\n        \"nonce\" => Some(TxTrait::nonce(transaction).to_string()),\n        \"s\" => Some(s),\n        \"r\" => Some(r),\n        \"to\" => Some(TxTrait::to(transaction).pretty()),\n        \"transactionIndex\" | \"transaction_index\" => {\n            Some(alloy_network::TransactionResponse::transaction_index(transaction).pretty())\n        }\n        \"v\" => Some(v),\n        \"value\" => Some(TxTrait::value(transaction).pretty()),\n        _ => None,\n    }\n}\n\npub fn get_pretty_block_attr<N>(block: &N::BlockResponse, attr: &str) -> Option<String>\nwhere\n    N: Network,\n    N::BlockResponse: BlockResponse<Header = N::HeaderResponse>,\n    N::HeaderResponse: UIfmtHeaderExt,\n{\n    match attr {\n        \"baseFeePerGas\" | \"base_fee_per_gas\" => Some(block.header().base_fee_per_gas().pretty()),\n        \"difficulty\" => Some(block.header().difficulty().pretty()),\n        \"extraData\" | \"extra_data\" => Some(block.header().extra_data().pretty()),\n        \"gasLimit\" | \"gas_limit\" => Some(block.header().gas_limit().pretty()),\n        \"gasUsed\" | \"gas_used\" => Some(block.header().gas_used().pretty()),\n        \"hash\" => Some(block.header().hash().pretty()),\n        \"logsBloom\" | \"logs_bloom\" => Some(block.header().logs_bloom().pretty()),\n        \"miner\" | \"author\" => Some(block.header().beneficiary().pretty()),\n        \"mixHash\" | \"mix_hash\" => Some(block.header().mix_hash().pretty()),\n        \"nonce\" => Some(block.header().nonce().pretty()),\n        \"number\" => Some(block.header().number().pretty()),\n        \"parentHash\" | \"parent_hash\" => Some(block.header().parent_hash().pretty()),\n        \"transactionsRoot\" | \"transactions_root\" => {\n            Some(block.header().transactions_root().pretty())\n        }\n        \"receiptsRoot\" | \"receipts_root\" => Some(block.header().receipts_root().pretty()),\n        \"sha3Uncles\" | \"sha_3_uncles\" => Some(block.header().ommers_hash().pretty()),\n        \"size\" => Some(block.header().size_pretty()),\n        \"stateRoot\" | \"state_root\" => Some(block.header().state_root().pretty()),\n        \"timestamp\" => Some(block.header().timestamp().pretty()),\n        \"totalDifficulty\" | \"total_difficulty\" => Some(block.header().difficulty().pretty()),\n        \"blobGasUsed\" | \"blob_gas_used\" => Some(block.header().blob_gas_used().pretty()),\n        \"excessBlobGas\" | \"excess_blob_gas\" => Some(block.header().excess_blob_gas().pretty()),\n        \"requestsHash\" | \"requests_hash\" => Some(block.header().requests_hash().pretty()),\n        other => {\n            if let Some(value) = block.other_fields().and_then(|fields| fields.get(other)) {\n                let val = EthValue::from(value.clone());\n                return Some(val.pretty());\n            }\n            None\n        }\n    }\n}\n\npub fn get_pretty_receipt_attr<N>(receipt: &N::ReceiptResponse, attr: &str) -> Option<String>\nwhere\n    N: Network,\n    N::ReceiptResponse: ReceiptResponse + UIfmtReceiptExt,\n{\n    match attr {\n        \"blockHash\" | \"block_hash\" => Some(receipt.block_hash().pretty()),\n        \"blockNumber\" | \"block_number\" => Some(receipt.block_number().pretty()),\n        \"contractAddress\" | \"contract_address\" => Some(receipt.contract_address().pretty()),\n        \"cumulativeGasUsed\" | \"cumulative_gas_used\" => Some(receipt.cumulative_gas_used().pretty()),\n        \"effectiveGasPrice\" | \"effective_gas_price\" => Some(receipt.effective_gas_price().pretty()),\n        \"from\" => Some(receipt.from().pretty()),\n        \"gasUsed\" | \"gas_used\" => Some(receipt.gas_used().pretty()),\n        \"logs\" => Some(receipt.logs_pretty()),\n        \"logsBloom\" | \"logs_bloom\" => Some(receipt.logs_bloom_pretty()),\n        \"root\" | \"stateRoot\" | \"state_root\" => Some(receipt.state_root().pretty()),\n        \"status\" | \"statusCode\" | \"status_code\" => Some(receipt.status().pretty()),\n        \"transactionHash\" | \"transaction_hash\" => Some(receipt.transaction_hash().pretty()),\n        \"transactionIndex\" | \"transaction_index\" => Some(receipt.transaction_index().pretty()),\n        \"to\" => Some(receipt.to().pretty()),\n        \"type\" | \"transaction_type\" => Some(receipt.tx_type_pretty()),\n        \"blobGasPrice\" | \"blob_gas_price\" => Some(receipt.blob_gas_price().pretty()),\n        \"blobGasUsed\" | \"blob_gas_used\" => Some(receipt.blob_gas_used().pretty()),\n        _ => None,\n    }\n}\n\nfn pretty_generic_header_response<H: HeaderResponse + UIfmtHeaderExt>(header: &H) -> String {\n    format!(\n        \"\nbaseFeePerGas        {}\ndifficulty           {}\nextraData            {}\ngasLimit             {}\ngasUsed              {}\nhash                 {}\nlogsBloom            {}\nminer                {}\nmixHash              {}\nnonce                {}\nnumber               {}\nparentHash           {}\nparentBeaconRoot     {}\ntransactionsRoot     {}\nreceiptsRoot         {}\nsha3Uncles           {}\nsize                 {}\nstateRoot            {}\ntimestamp            {} ({})\nwithdrawalsRoot      {}\ntotalDifficulty      {}\nblobGasUsed          {}\nexcessBlobGas        {}\nrequestsHash         {}\",\n        header.base_fee_per_gas().pretty(),\n        header.difficulty().pretty(),\n        header.extra_data().pretty(),\n        header.gas_limit().pretty(),\n        header.gas_used().pretty(),\n        header.hash().pretty(),\n        header.logs_bloom().pretty(),\n        header.beneficiary().pretty(),\n        header.mix_hash().pretty(),\n        header.nonce().pretty(),\n        header.number().pretty(),\n        header.parent_hash().pretty(),\n        header.parent_beacon_block_root().pretty(),\n        header.transactions_root().pretty(),\n        header.receipts_root().pretty(),\n        header.ommers_hash().pretty(),\n        header.size_pretty(),\n        header.state_root().pretty(),\n        header.timestamp().pretty(),\n        fmt_timestamp(header.timestamp()),\n        header.withdrawals_root().pretty(),\n        header.difficulty().pretty(),\n        header.blob_gas_used().pretty(),\n        header.excess_blob_gas().pretty(),\n        header.requests_hash().pretty(),\n    )\n}\n\n/// Formats the timestamp to string\n///\n/// Assumes timestamp is seconds, but handles millis if it is too large\nfn fmt_timestamp(timestamp: u64) -> String {\n    // Tue Jan 19 2038 03:14:07 GMT+0000\n    if timestamp > 2147483647 {\n        // assume this is in millis, incorrectly set to millis by a node\n        chrono::DateTime::from_timestamp_millis(timestamp as i64)\n            .expect(\"block timestamp in range\")\n            .to_rfc3339()\n    } else {\n        // assume this is still in seconds\n        chrono::DateTime::from_timestamp(timestamp as i64, 0)\n            .expect(\"block timestamp in range\")\n            .to_rfc2822()\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use alloy_primitives::B256;\n    use alloy_rpc_types::Authorization;\n    use foundry_primitives::FoundryNetwork;\n    use similar_asserts::assert_eq;\n    use std::str::FromStr;\n\n    #[test]\n    fn format_date_time() {\n        // Fri Aug 29 2025 08:05:38 GMT+0000\n        let timestamp = 1756454738u64;\n\n        let datetime = fmt_timestamp(timestamp);\n        assert_eq!(datetime, \"Fri, 29 Aug 2025 08:05:38 +0000\");\n        let datetime = fmt_timestamp(timestamp * 1000);\n        assert_eq!(datetime, \"2025-08-29T08:05:38+00:00\");\n    }\n\n    #[test]\n    fn can_format_bytes32() {\n        let val = hex::decode(\"7465737400000000000000000000000000000000000000000000000000000000\")\n            .unwrap();\n        let mut b32 = [0u8; 32];\n        b32.copy_from_slice(&val);\n\n        assert_eq!(\n            b32.pretty(),\n            \"0x7465737400000000000000000000000000000000000000000000000000000000\"\n        );\n        let b: Bytes = val.into();\n        assert_eq!(b.pretty(), b32.pretty());\n    }\n\n    #[test]\n    fn can_pretty_print_optimism_tx() {\n        let s = r#\"\n        {\n        \"blockHash\": \"0x02b853cf50bc1c335b70790f93d5a390a35a166bea9c895e685cc866e4961cae\",\n        \"blockNumber\": \"0x1b4\",\n        \"from\": \"0x3b179DcfC5fAa677044c27dCe958e4BC0ad696A6\",\n        \"gas\": \"0x11cbbdc\",\n        \"gasPrice\": \"0x0\",\n        \"hash\": \"0x2642e960d3150244e298d52b5b0f024782253e6d0b2c9a01dd4858f7b4665a3f\",\n        \"input\": \"0xd294f093\",\n        \"nonce\": \"0xa2\",\n        \"to\": \"0x4a16A42407AA491564643E1dfc1fd50af29794eF\",\n        \"transactionIndex\": \"0x0\",\n        \"value\": \"0x0\",\n        \"v\": \"0x38\",\n        \"r\": \"0x6fca94073a0cf3381978662d46cf890602d3e9ccf6a31e4b69e8ecbd995e2bee\",\n        \"s\": \"0xe804161a2b56a37ca1f6f4c4b8bce926587afa0d9b1acc5165e6556c959d583\",\n        \"depositNonce\": \"\",\n        \"depositReceiptVersion\": \"0x1\"\n    }\n        \"#;\n\n        let tx: op_alloy_rpc_types::Transaction<OpTxEnvelope> = serde_json::from_str(s).unwrap();\n        assert_eq!(\n            tx.pretty().trim(),\n            r\"\ndepositNonce         \ndepositReceiptVersion 1\nblockHash            0x02b853cf50bc1c335b70790f93d5a390a35a166bea9c895e685cc866e4961cae\nblockNumber          436\nfrom                 0x3b179DcfC5fAa677044c27dCe958e4BC0ad696A6\ntransactionIndex     0\neffectiveGasPrice    0\nhash                 0x2642e960d3150244e298d52b5b0f024782253e6d0b2c9a01dd4858f7b4665a3f\ntype                 0\nchainId              10\nnonce                162\ngasPrice             0\ngasLimit             18660316\nto                   0x4a16A42407AA491564643E1dfc1fd50af29794eF\nvalue                0\ninput                0xd294f093\nr                    0x6fca94073a0cf3381978662d46cf890602d3e9ccf6a31e4b69e8ecbd995e2bee\ns                    0x0e804161a2b56a37ca1f6f4c4b8bce926587afa0d9b1acc5165e6556c959d583\nyParity              1\n\"\n            .trim()\n        );\n    }\n\n    #[test]\n    fn can_pretty_print_optimism_tx_through_any() {\n        let s = r#\"\n        {\n        \"blockHash\": \"0x02b853cf50bc1c335b70790f93d5a390a35a166bea9c895e685cc866e4961cae\",\n        \"blockNumber\": \"0x1b4\",\n        \"from\": \"0x3b179DcfC5fAa677044c27dCe958e4BC0ad696A6\",\n        \"gas\": \"0x11cbbdc\",\n        \"gasPrice\": \"0x0\",\n        \"hash\": \"0x2642e960d3150244e298d52b5b0f024782253e6d0b2c9a01dd4858f7b4665a3f\",\n        \"input\": \"0xd294f093\",\n        \"nonce\": \"0xa2\",\n        \"to\": \"0x4a16A42407AA491564643E1dfc1fd50af29794eF\",\n        \"transactionIndex\": \"0x0\",\n        \"value\": \"0x0\",\n        \"v\": \"0x38\",\n        \"r\": \"0x6fca94073a0cf3381978662d46cf890602d3e9ccf6a31e4b69e8ecbd995e2bee\",\n        \"s\": \"0xe804161a2b56a37ca1f6f4c4b8bce926587afa0d9b1acc5165e6556c959d583\",\n        \"queueOrigin\": \"sequencer\",\n        \"txType\": \"\",\n        \"l1TxOrigin\": null,\n        \"l1BlockNumber\": \"0xc1a65c\",\n        \"l1Timestamp\": \"0x60d34b60\",\n        \"index\": \"0x1b3\",\n        \"queueIndex\": null,\n        \"rawTransaction\": \"0xf86681a28084011cbbdc944a16a42407aa491564643e1dfc1fd50af29794ef8084d294f09338a06fca94073a0cf3381978662d46cf890602d3e9ccf6a31e4b69e8ecbd995e2beea00e804161a2b56a37ca1f6f4c4b8bce926587afa0d9b1acc5165e6556c959d583\"\n    }\n        \"#;\n\n        let tx: WithOtherFields<Transaction<AnyTxEnvelope>> = serde_json::from_str(s).unwrap();\n        assert_eq!(tx.pretty().trim(),\n                   r\"\nblockHash            0x02b853cf50bc1c335b70790f93d5a390a35a166bea9c895e685cc866e4961cae\nblockNumber          436\nfrom                 0x3b179DcfC5fAa677044c27dCe958e4BC0ad696A6\ntransactionIndex     0\neffectiveGasPrice    0\nhash                 0x2642e960d3150244e298d52b5b0f024782253e6d0b2c9a01dd4858f7b4665a3f\ntype                 0\nchainId              10\nnonce                162\ngasPrice             0\ngasLimit             18660316\nto                   0x4a16A42407AA491564643E1dfc1fd50af29794eF\nvalue                0\ninput                0xd294f093\nr                    0x6fca94073a0cf3381978662d46cf890602d3e9ccf6a31e4b69e8ecbd995e2bee\ns                    0x0e804161a2b56a37ca1f6f4c4b8bce926587afa0d9b1acc5165e6556c959d583\nyParity              1\nindex                435\nl1BlockNumber        12691036\nl1Timestamp          1624460128\nl1TxOrigin           null\nqueueIndex           null\nqueueOrigin          sequencer\nrawTransaction       0xf86681a28084011cbbdc944a16a42407aa491564643e1dfc1fd50af29794ef8084d294f09338a06fca94073a0cf3381978662d46cf890602d3e9ccf6a31e4b69e8ecbd995e2beea00e804161a2b56a37ca1f6f4c4b8bce926587afa0d9b1acc5165e6556c959d583\ntxType               0\n\".trim()\n        );\n    }\n\n    #[test]\n    fn can_pretty_print_eip2930() {\n        let s = r#\"{\n        \"type\": \"0x1\",\n        \"blockHash\": \"0x2b27fe2bbc8ce01ac7ae8bf74f793a197cf7edbe82727588811fa9a2c4776f81\",\n        \"blockNumber\": \"0x12b1d\",\n        \"from\": \"0x2b371c0262ceab27face32fbb5270ddc6aa01ba4\",\n        \"gas\": \"0x6bdf\",\n        \"gasPrice\": \"0x3b9aca00\",\n        \"hash\": \"0xbddbb685774d8a3df036ed9fb920b48f876090a57e9e90ee60921e0510ef7090\",\n        \"input\": \"0x9c0e3f7a0000000000000000000000000000000000000000000000000000000000000078000000000000000000000000000000000000000000000000000000000000002a\",\n        \"nonce\": \"0x1c\",\n        \"to\": \"0x8e730df7c70d33118d9e5f79ab81aed0be6f6635\",\n        \"transactionIndex\": \"0x2\",\n        \"value\": \"0x0\",\n        \"v\": \"0x1\",\n        \"r\": \"0x2a98c51c2782f664d3ce571fef0491b48f5ebbc5845fa513192e6e6b24ecdaa1\",\n        \"s\": \"0x29b8e0c67aa9c11327e16556c591dc84a7aac2f6fc57c7f93901be8ee867aebc\",\n        \"chainId\": \"0x66a\",\n        \"accessList\": [\n            { \"address\": \"0x2b371c0262ceab27face32fbb5270ddc6aa01ba4\", \"storageKeys\": [\"0x1122334455667788990011223344556677889900112233445566778899001122\", \"0x0000000000000000000000000000000000000000000000000000000000000000\"] },\n            { \"address\": \"0x8e730df7c70d33118d9e5f79ab81aed0be6f6635\", \"storageKeys\": [] }\n        ]\n      }\n        \"#;\n        let tx: Transaction = serde_json::from_str(s).unwrap();\n        assert_eq!(tx.pretty().trim(),\n                   r\"\nblockHash            0x2b27fe2bbc8ce01ac7ae8bf74f793a197cf7edbe82727588811fa9a2c4776f81\nblockNumber          76573\nfrom                 0x2b371c0262CEAb27fAcE32FBB5270dDc6Aa01ba4\ntransactionIndex     2\neffectiveGasPrice    1000000000\nhash                 0xbddbb685774d8a3df036ed9fb920b48f876090a57e9e90ee60921e0510ef7090\ntype                 1\nchainId              1642\nnonce                28\ngasPrice             1000000000\ngasLimit             27615\nto                   0x8E730Df7C70D33118D9e5F79ab81aEd0bE6F6635\nvalue                0\naccessList           [\n\t0x2b371c0262CEAb27fAcE32FBB5270dDc6Aa01ba4 => [\n\t\t0x1122334455667788990011223344556677889900112233445566778899001122\n\t\t0x0000000000000000000000000000000000000000000000000000000000000000\n\t]\n\t0x8E730Df7C70D33118D9e5F79ab81aEd0bE6F6635 => []\n]\ninput                0x9c0e3f7a0000000000000000000000000000000000000000000000000000000000000078000000000000000000000000000000000000000000000000000000000000002a\nr                    0x2a98c51c2782f664d3ce571fef0491b48f5ebbc5845fa513192e6e6b24ecdaa1\ns                    0x29b8e0c67aa9c11327e16556c591dc84a7aac2f6fc57c7f93901be8ee867aebc\nyParity              1\n\".trim()\n        );\n    }\n\n    #[test]\n    fn can_pretty_print_eip1559() {\n        let s = r#\"{\n        \"type\": \"0x2\",\n        \"blockHash\": \"0x61abbe5e22738de0462046f5a5d6c4cd6bc1f3a6398e4457d5e293590e721125\",\n        \"blockNumber\": \"0x7647\",\n        \"from\": \"0xbaadf00d42264eeb3fafe6799d0b56cf55df0f00\",\n        \"gas\": \"0x186a0\",\n        \"hash\": \"0xa7231d4da0576fade5d3b9481f4cd52459ec59b9bbdbf4f60d6cd726b2a3a244\",\n        \"input\": \"0x48600055323160015500\",\n        \"nonce\": \"0x12c\",\n        \"to\": null,\n        \"transactionIndex\": \"0x41\",\n        \"value\": \"0x0\",\n        \"v\": \"0x1\",\n        \"yParity\": \"0x1\",\n        \"r\": \"0x396864e5f9132327defdb1449504252e1fa6bce73feb8cd6f348a342b198af34\",\n        \"s\": \"0x44dbba72e6d3304104848277143252ee43627c82f02d1ef8e404e1bf97c70158\",\n        \"gasPrice\": \"0x4a817c800\",\n        \"maxFeePerGas\": \"0x4a817c800\",\n        \"maxPriorityFeePerGas\": \"0x4a817c800\",\n        \"chainId\": \"0x66a\",\n        \"accessList\": [\n          {\n            \"address\": \"0xc141a9a7463e6c4716d9fc0c056c054f46bb2993\",\n            \"storageKeys\": [\n              \"0x0000000000000000000000000000000000000000000000000000000000000000\"\n            ]\n          }\n        ]\n      }\n\"#;\n        let tx: Transaction = serde_json::from_str(s).unwrap();\n        assert_eq!(\n            tx.pretty().trim(),\n            r\"\nblockHash            0x61abbe5e22738de0462046f5a5d6c4cd6bc1f3a6398e4457d5e293590e721125\nblockNumber          30279\nfrom                 0xBaaDF00d42264eEb3FAFe6799d0b56cf55DF0F00\ntransactionIndex     65\neffectiveGasPrice    20000000000\nhash                 0xa7231d4da0576fade5d3b9481f4cd52459ec59b9bbdbf4f60d6cd726b2a3a244\ntype                 2\nchainId              1642\nnonce                300\ngasLimit             100000\nmaxFeePerGas         20000000000\nmaxPriorityFeePerGas 20000000000\nto                   \nvalue                0\naccessList           [\n\t0xC141a9A7463e6C4716d9FC0C056C054F46Bb2993 => [\n\t\t0x0000000000000000000000000000000000000000000000000000000000000000\n\t]\n]\ninput                0x48600055323160015500\nr                    0x396864e5f9132327defdb1449504252e1fa6bce73feb8cd6f348a342b198af34\ns                    0x44dbba72e6d3304104848277143252ee43627c82f02d1ef8e404e1bf97c70158\nyParity              1\n\"\n            .trim()\n        );\n    }\n\n    #[test]\n    fn can_pretty_print_eip4884() {\n        let s = r#\"{\n        \"blockHash\": \"0xfc2715ff196e23ae613ed6f837abd9035329a720a1f4e8dce3b0694c867ba052\",\n        \"blockNumber\": \"0x2a1cb\",\n        \"from\": \"0xad01b55d7c3448b8899862eb335fbb17075d8de2\",\n        \"gas\": \"0x5208\",\n        \"gasPrice\": \"0x1d1a94a201c\",\n        \"maxFeePerGas\": \"0x1d1a94a201c\",\n        \"maxPriorityFeePerGas\": \"0x1d1a94a201c\",\n        \"maxFeePerBlobGas\": \"0x3e8\",\n        \"hash\": \"0x5ceec39b631763ae0b45a8fb55c373f38b8fab308336ca1dc90ecd2b3cf06d00\",\n        \"input\": \"0x\",\n        \"nonce\": \"0x1b483\",\n        \"to\": \"0x000000000000000000000000000000000000f1c1\",\n        \"transactionIndex\": \"0x0\",\n        \"value\": \"0x0\",\n        \"type\": \"0x3\",\n        \"accessList\": [],\n        \"chainId\": \"0x1a1f0ff42\",\n        \"blobVersionedHashes\": [\n          \"0x01a128c46fc61395706686d6284f83c6c86dfc15769b9363171ea9d8566e6e76\"\n        ],\n        \"v\": \"0x0\",\n        \"r\": \"0x343c6239323a81ef61293cb4a4d37b6df47fbf68114adb5dd41581151a077da1\",\n        \"s\": \"0x48c21f6872feaf181d37cc4f9bbb356d3f10b352ceb38d1c3b190d749f95a11b\",\n        \"yParity\": \"0x0\"\n      }\n\"#;\n        let tx: Transaction = serde_json::from_str(s).unwrap();\n        assert_eq!(\n            tx.pretty().trim(),\n            r\"\nblockHash            0xfc2715ff196e23ae613ed6f837abd9035329a720a1f4e8dce3b0694c867ba052\nblockNumber          172491\nfrom                 0xAD01b55d7c3448B8899862eb335FBb17075d8DE2\ntransactionIndex     0\neffectiveGasPrice    2000000000028\nhash                 0x5ceec39b631763ae0b45a8fb55c373f38b8fab308336ca1dc90ecd2b3cf06d00\ntype                 3\nchainId              7011893058\nnonce                111747\ngasLimit             21000\nmaxFeePerGas         2000000000028\nmaxPriorityFeePerGas 2000000000028\nto                   0x000000000000000000000000000000000000f1C1\nvalue                0\naccessList           []\nblobVersionedHashes  [\n\t0x01a128c46fc61395706686d6284f83c6c86dfc15769b9363171ea9d8566e6e76\n]\nmaxFeePerBlobGas     1000\ninput                0x\nr                    0x343c6239323a81ef61293cb4a4d37b6df47fbf68114adb5dd41581151a077da1\ns                    0x48c21f6872feaf181d37cc4f9bbb356d3f10b352ceb38d1c3b190d749f95a11b\nyParity              0\n\"\n            .trim()\n        );\n    }\n\n    #[test]\n    fn print_block_w_txs() {\n        let block = r#\"{\"number\":\"0x3\",\"hash\":\"0xda53da08ef6a3cbde84c33e51c04f68c3853b6a3731f10baa2324968eee63972\",\"parentHash\":\"0x689c70c080ca22bc0e681694fa803c1aba16a69c8b6368fed5311d279eb9de90\",\"mixHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"nonce\":\"0x0000000000000000\",\"sha3Uncles\":\"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347\",\"logsBloom\":\"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\"transactionsRoot\":\"0x7270c1c4440180f2bd5215809ee3d545df042b67329499e1ab97eb759d31610d\",\"stateRoot\":\"0x29f32984517a7d25607da485b23cefabfd443751422ca7e603395e1de9bc8a4b\",\"receiptsRoot\":\"0x056b23fbba480696b65fe5a59b8f2148a1299103c4f57df839233af2cf4ca2d2\",\"miner\":\"0x0000000000000000000000000000000000000000\",\"difficulty\":\"0x0\",\"totalDifficulty\":\"0x0\",\"extraData\":\"0x\",\"size\":\"0x3e8\",\"gasLimit\":\"0x6691b7\",\"gasUsed\":\"0x5208\",\"timestamp\":\"0x5ecedbb9\",\"transactions\":[{\"hash\":\"0xc3c5f700243de37ae986082fd2af88d2a7c2752a0c0f7b9d6ac47c729d45e067\",\"nonce\":\"0x2\",\"blockHash\":\"0xda53da08ef6a3cbde84c33e51c04f68c3853b6a3731f10baa2324968eee63972\",\"blockNumber\":\"0x3\",\"transactionIndex\":\"0x0\",\"from\":\"0xfdcedc3bfca10ecb0890337fbdd1977aba84807a\",\"to\":\"0xdca8ce283150ab773bcbeb8d38289bdb5661de1e\",\"value\":\"0x0\",\"gas\":\"0x15f90\",\"gasPrice\":\"0x4a817c800\",\"input\":\"0x\",\"v\":\"0x25\",\"r\":\"0x19f2694eb9113656dbea0b925e2e7ceb43df83e601c4116aee9c0dd99130be88\",\"s\":\"0x73e5764b324a4f7679d890a198ba658ba1c8cd36983ff9797e10b1b89dbb448e\"}],\"uncles\":[]}\"#;\n        let block: Block = serde_json::from_str(block).unwrap();\n        let output = \"\nblockHash            0xda53da08ef6a3cbde84c33e51c04f68c3853b6a3731f10baa2324968eee63972\nblockNumber          3\nfrom                 0xFdCeDC3bFca10eCb0890337fbdD1977aba84807a\ntransactionIndex     0\neffectiveGasPrice    20000000000\nhash                 0xc3c5f700243de37ae986082fd2af88d2a7c2752a0c0f7b9d6ac47c729d45e067\ntype                 0\nchainId              1\nnonce                2\ngasPrice             20000000000\ngasLimit             90000\nto                   0xdca8ce283150AB773BCbeB8d38289bdB5661dE1e\nvalue                0\ninput                0x\nr                    0x19f2694eb9113656dbea0b925e2e7ceb43df83e601c4116aee9c0dd99130be88\ns                    0x73e5764b324a4f7679d890a198ba658ba1c8cd36983ff9797e10b1b89dbb448e\nyParity              0\"\n            .to_string();\n        let txs = match block.transactions() {\n            BlockTransactions::Full(txs) => txs,\n            _ => panic!(\"not full transactions\"),\n        };\n        let generated = txs[0].pretty();\n        assert_eq!(generated.as_str(), output.as_str());\n    }\n\n    #[test]\n    fn uifmt_option_u64() {\n        assert_eq!(None::<U64>.pretty(), \"\");\n        assert_eq!(U64::from(100).pretty(), \"100\");\n        assert_eq!(Some(U64::from(100)).pretty(), \"100\");\n    }\n\n    #[test]\n    fn uifmt_option_h64() {\n        assert_eq!(None::<B256>.pretty(), \"\");\n        assert_eq!(\n            B256::with_last_byte(100).pretty(),\n            \"0x0000000000000000000000000000000000000000000000000000000000000064\",\n        );\n        assert_eq!(\n            Some(B256::with_last_byte(100)).pretty(),\n            \"0x0000000000000000000000000000000000000000000000000000000000000064\",\n        );\n    }\n\n    #[test]\n    fn uifmt_option_bytes() {\n        assert_eq!(None::<Bytes>.pretty(), \"\");\n        assert_eq!(\n            Bytes::from_str(\"0x0000000000000000000000000000000000000000000000000000000000000064\")\n                .unwrap()\n                .pretty(),\n            \"0x0000000000000000000000000000000000000000000000000000000000000064\",\n        );\n        assert_eq!(\n            Some(\n                Bytes::from_str(\n                    \"0x0000000000000000000000000000000000000000000000000000000000000064\"\n                )\n                .unwrap()\n            )\n            .pretty(),\n            \"0x0000000000000000000000000000000000000000000000000000000000000064\",\n        );\n    }\n\n    #[test]\n    fn test_pretty_tx_attr() {\n        let block = r#\"{\"number\":\"0x3\",\"hash\":\"0xda53da08ef6a3cbde84c33e51c04f68c3853b6a3731f10baa2324968eee63972\",\"parentHash\":\"0x689c70c080ca22bc0e681694fa803c1aba16a69c8b6368fed5311d279eb9de90\",\"mixHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"nonce\":\"0x0000000000000000\",\"sha3Uncles\":\"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347\",\"logsBloom\":\"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\"transactionsRoot\":\"0x7270c1c4440180f2bd5215809ee3d545df042b67329499e1ab97eb759d31610d\",\"stateRoot\":\"0x29f32984517a7d25607da485b23cefabfd443751422ca7e603395e1de9bc8a4b\",\"receiptsRoot\":\"0x056b23fbba480696b65fe5a59b8f2148a1299103c4f57df839233af2cf4ca2d2\",\"miner\":\"0x0000000000000000000000000000000000000000\",\"difficulty\":\"0x0\",\"totalDifficulty\":\"0x0\",\"extraData\":\"0x\",\"size\":\"0x3e8\",\"gasLimit\":\"0x6691b7\",\"gasUsed\":\"0x5208\",\"timestamp\":\"0x5ecedbb9\",\"transactions\":[{\"hash\":\"0xc3c5f700243de37ae986082fd2af88d2a7c2752a0c0f7b9d6ac47c729d45e067\",\"nonce\":\"0x2\",\"blockHash\":\"0xda53da08ef6a3cbde84c33e51c04f68c3853b6a3731f10baa2324968eee63972\",\"blockNumber\":\"0x3\",\"transactionIndex\":\"0x0\",\"from\":\"0xfdcedc3bfca10ecb0890337fbdd1977aba84807a\",\"to\":\"0xdca8ce283150ab773bcbeb8d38289bdb5661de1e\",\"value\":\"0x0\",\"gas\":\"0x15f90\",\"gasPrice\":\"0x4a817c800\",\"input\":\"0x\",\"v\":\"0x25\",\"r\":\"0x19f2694eb9113656dbea0b925e2e7ceb43df83e601c4116aee9c0dd99130be88\",\"s\":\"0x73e5764b324a4f7679d890a198ba658ba1c8cd36983ff9797e10b1b89dbb448e\"}],\"uncles\":[]}\"#;\n        let block: <FoundryNetwork as Network>::BlockResponse =\n            serde_json::from_str(block).unwrap();\n        let txs = match block.transactions() {\n            BlockTransactions::Full(txes) => txes,\n            _ => panic!(\"not full transactions\"),\n        };\n\n        assert_eq!(None, get_pretty_tx_attr::<FoundryNetwork>(&txs[0], \"\"));\n        assert_eq!(\n            Some(\"3\".to_string()),\n            get_pretty_tx_attr::<FoundryNetwork>(&txs[0], \"blockNumber\")\n        );\n        assert_eq!(\n            Some(\"0xFdCeDC3bFca10eCb0890337fbdD1977aba84807a\".to_string()),\n            get_pretty_tx_attr::<FoundryNetwork>(&txs[0], \"from\")\n        );\n        assert_eq!(Some(\"90000\".to_string()), get_pretty_tx_attr::<FoundryNetwork>(&txs[0], \"gas\"));\n        assert_eq!(\n            Some(\"20000000000\".to_string()),\n            get_pretty_tx_attr::<FoundryNetwork>(&txs[0], \"gasPrice\")\n        );\n        assert_eq!(\n            Some(\"0xc3c5f700243de37ae986082fd2af88d2a7c2752a0c0f7b9d6ac47c729d45e067\".to_string()),\n            get_pretty_tx_attr::<FoundryNetwork>(&txs[0], \"hash\")\n        );\n        assert_eq!(Some(\"0x\".to_string()), get_pretty_tx_attr::<FoundryNetwork>(&txs[0], \"input\"));\n        assert_eq!(Some(\"2\".to_string()), get_pretty_tx_attr::<FoundryNetwork>(&txs[0], \"nonce\"));\n        assert_eq!(\n            Some(\"0x19f2694eb9113656dbea0b925e2e7ceb43df83e601c4116aee9c0dd99130be88\".to_string()),\n            get_pretty_tx_attr::<FoundryNetwork>(&txs[0], \"r\")\n        );\n        assert_eq!(\n            Some(\"0x73e5764b324a4f7679d890a198ba658ba1c8cd36983ff9797e10b1b89dbb448e\".to_string()),\n            get_pretty_tx_attr::<FoundryNetwork>(&txs[0], \"s\")\n        );\n        assert_eq!(\n            Some(\"0xdca8ce283150AB773BCbeB8d38289bdB5661dE1e\".into()),\n            get_pretty_tx_attr::<FoundryNetwork>(&txs[0], \"to\")\n        );\n        assert_eq!(\n            Some(\"0\".to_string()),\n            get_pretty_tx_attr::<FoundryNetwork>(&txs[0], \"transactionIndex\")\n        );\n        assert_eq!(Some(\"27\".to_string()), get_pretty_tx_attr::<FoundryNetwork>(&txs[0], \"v\"));\n        assert_eq!(Some(\"0\".to_string()), get_pretty_tx_attr::<FoundryNetwork>(&txs[0], \"value\"));\n    }\n\n    #[test]\n    fn test_pretty_block_attr() {\n        let json = serde_json::json!(\n        {\n            \"baseFeePerGas\": \"0x7\",\n            \"miner\": \"0x0000000000000000000000000000000000000001\",\n            \"number\": \"0x1b4\",\n            \"hash\": \"0x0e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331\",\n            \"parentHash\": \"0x9646252be9520f6e71339a8df9c55e4d7619deeb018d2a3f2d21fc165dde5eb5\",\n            \"mixHash\": \"0x1010101010101010101010101010101010101010101010101010101010101010\",\n            \"nonce\": \"0x0000000000000000\",\n            \"sealFields\": [\n              \"0xe04d296d2460cfb8472af2c5fd05b5a214109c25688d3704aed5484f9a7792f2\",\n              \"0x0000000000000042\"\n            ],\n            \"sha3Uncles\": \"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347\",\n            \"logsBloom\":  \"0x0e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331\",\n            \"transactionsRoot\": \"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\",\n            \"receiptsRoot\": \"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\",\n            \"stateRoot\": \"0xd5855eb08b3387c0af375e9cdb6acfc05eb8f519e419b874b6ff2ffda7ed1dff\",\n            \"difficulty\": \"0x27f07\",\n            \"totalDifficulty\": \"0x27f07\",\n            \"extraData\": \"0x0000000000000000000000000000000000000000000000000000000000000000\",\n            \"size\": \"0x27f07\",\n            \"gasLimit\": \"0x9f759\",\n            \"minGasPrice\": \"0x9f759\",\n            \"gasUsed\": \"0x9f759\",\n            \"timestamp\": \"0x54e34e8e\",\n            \"transactions\": [],\n            \"uncles\": [],\n          }\n        );\n\n        let block: <FoundryNetwork as Network>::BlockResponse =\n            serde_json::from_value(json).unwrap();\n\n        assert_eq!(None, get_pretty_block_attr::<FoundryNetwork>(&block, \"\"));\n        assert_eq!(\n            Some(\"7\".to_string()),\n            get_pretty_block_attr::<FoundryNetwork>(&block, \"baseFeePerGas\")\n        );\n        assert_eq!(\n            Some(\"163591\".to_string()),\n            get_pretty_block_attr::<FoundryNetwork>(&block, \"difficulty\")\n        );\n        assert_eq!(\n            Some(\"0x0000000000000000000000000000000000000000000000000000000000000000\".to_string()),\n            get_pretty_block_attr::<FoundryNetwork>(&block, \"extraData\")\n        );\n        assert_eq!(\n            Some(\"653145\".to_string()),\n            get_pretty_block_attr::<FoundryNetwork>(&block, \"gasLimit\")\n        );\n        assert_eq!(\n            Some(\"653145\".to_string()),\n            get_pretty_block_attr::<FoundryNetwork>(&block, \"gasUsed\")\n        );\n        assert_eq!(\n            Some(\"0x0e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331\".to_string()),\n            get_pretty_block_attr::<FoundryNetwork>(&block, \"hash\")\n        );\n        assert_eq!(Some(\"0x0e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331\".to_string()), get_pretty_block_attr::<FoundryNetwork>(&block, \"logsBloom\"));\n        assert_eq!(\n            Some(\"0x0000000000000000000000000000000000000001\".to_string()),\n            get_pretty_block_attr::<FoundryNetwork>(&block, \"miner\")\n        );\n        assert_eq!(\n            Some(\"0x1010101010101010101010101010101010101010101010101010101010101010\".to_string()),\n            get_pretty_block_attr::<FoundryNetwork>(&block, \"mixHash\")\n        );\n        assert_eq!(\n            Some(\"0x0000000000000000\".to_string()),\n            get_pretty_block_attr::<FoundryNetwork>(&block, \"nonce\")\n        );\n        assert_eq!(\n            Some(\"436\".to_string()),\n            get_pretty_block_attr::<FoundryNetwork>(&block, \"number\")\n        );\n        assert_eq!(\n            Some(\"0x9646252be9520f6e71339a8df9c55e4d7619deeb018d2a3f2d21fc165dde5eb5\".to_string()),\n            get_pretty_block_attr::<FoundryNetwork>(&block, \"parentHash\")\n        );\n        assert_eq!(\n            Some(\"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\".to_string()),\n            get_pretty_block_attr::<FoundryNetwork>(&block, \"transactionsRoot\")\n        );\n        assert_eq!(\n            Some(\"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\".to_string()),\n            get_pretty_block_attr::<FoundryNetwork>(&block, \"receiptsRoot\")\n        );\n        assert_eq!(\n            Some(\"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347\".to_string()),\n            get_pretty_block_attr::<FoundryNetwork>(&block, \"sha3Uncles\")\n        );\n        assert_eq!(\n            Some(\"163591\".to_string()),\n            get_pretty_block_attr::<FoundryNetwork>(&block, \"size\")\n        );\n        assert_eq!(\n            Some(\"0xd5855eb08b3387c0af375e9cdb6acfc05eb8f519e419b874b6ff2ffda7ed1dff\".to_string()),\n            get_pretty_block_attr::<FoundryNetwork>(&block, \"stateRoot\")\n        );\n        assert_eq!(\n            Some(\"1424182926\".to_string()),\n            get_pretty_block_attr::<FoundryNetwork>(&block, \"timestamp\")\n        );\n        assert_eq!(\n            Some(\"163591\".to_string()),\n            get_pretty_block_attr::<FoundryNetwork>(&block, \"totalDifficulty\")\n        );\n    }\n\n    #[test]\n    fn test_receipt_other_fields_alignment() {\n        let receipt_json = serde_json::json!(\n        {\n          \"status\": \"0x1\",\n          \"cumulativeGasUsed\": \"0x74e483\",\n          \"logs\": [],\n          \"logsBloom\": \"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\n          \"type\": \"0x2\",\n          \"transactionHash\": \"0x91181b0dca3b29aa136eeb2f536be5ce7b0aebc949be1c44b5509093c516097d\",\n          \"transactionIndex\": \"0x10\",\n          \"blockHash\": \"0x54bafb12e8cea9bb355fbf03a4ac49e42a2a1a80fa6cf4364b342e2de6432b5d\",\n          \"blockNumber\": \"0x7b1ab93\",\n          \"gasUsed\": \"0xc222\",\n          \"effectiveGasPrice\": \"0x18961\",\n          \"from\": \"0x2d815240a61731c75fa01b2793e1d3ed09f289d0\",\n          \"to\": \"0x4200000000000000000000000000000000000000\",\n          \"contractAddress\": null,\n          \"l1BaseFeeScalar\": \"0x146b\",\n          \"l1BlobBaseFee\": \"0x6a83078\",\n          \"l1BlobBaseFeeScalar\": \"0xf79c5\",\n          \"l1Fee\": \"0x51a9af7fd3\",\n          \"l1GasPrice\": \"0x972fe4acc\",\n          \"l1GasUsed\": \"0x640\"\n        });\n\n        let receipt: AnyTransactionReceipt = serde_json::from_value(receipt_json).unwrap();\n        let formatted = receipt.pretty();\n\n        let expected = r#\"\nblockHash            0x54bafb12e8cea9bb355fbf03a4ac49e42a2a1a80fa6cf4364b342e2de6432b5d\nblockNumber          129084307\ncontractAddress      \ncumulativeGasUsed    7660675\neffectiveGasPrice    100705\nfrom                 0x2D815240A61731c75Fa01b2793E1D3eD09F289d0\ngasUsed              49698\nlogs                 []\nlogsBloom            0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\nroot                 \nstatus               1 (success)\ntransactionHash      0x91181b0dca3b29aa136eeb2f536be5ce7b0aebc949be1c44b5509093c516097d\ntransactionIndex     16\ntype                 2\nblobGasPrice         \nblobGasUsed          \nto                   0x4200000000000000000000000000000000000000\nl1BaseFeeScalar      5227\nl1BlobBaseFee        111685752\nl1BlobBaseFeeScalar  1014213\nl1Fee                350739202003\nl1GasPrice           40583973580\nl1GasUsed            1600\n\"#;\n\n        assert_eq!(formatted.trim(), expected.trim());\n    }\n\n    #[test]\n    fn test_uifmt_for_signed_authorization() {\n        let inner = Authorization {\n            chain_id: U256::from(1),\n            address: \"0x000000000000000000000000000000000000dead\".parse::<Address>().unwrap(),\n            nonce: 42,\n        };\n        let signed_authorization =\n            SignedAuthorization::new_unchecked(inner, 1, U256::from(20), U256::from(30));\n\n        assert_eq!(\n            signed_authorization.pretty(),\n            r#\"{recoveredAuthority: 0xf3eaBD0de6Ca1aE7fC4D81FfD6C9a40e5D5D7e30, signedAuthority: {\"chainId\":\"0x1\",\"address\":\"0x000000000000000000000000000000000000dead\",\"nonce\":\"0x2a\",\"yParity\":\"0x1\",\"r\":\"0x14\",\"s\":\"0x1e\"}}\"#\n        );\n    }\n\n    #[test]\n    fn can_pretty_print_tempo_tx() {\n        let s = r#\"{\n            \"type\":\"0x76\",\n            \"chainId\":\"0xa5bd\",\n            \"feeToken\":\"0x20c0000000000000000000000000000000000001\",\n            \"maxPriorityFeePerGas\":\"0x0\",\n            \"maxFeePerGas\":\"0x2cb417800\",\n            \"gas\":\"0x2d178\",\n            \"calls\":[\n                {\n                    \"data\":null,\n                    \"input\":\"0x095ea7b3000000000000000000000000dec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000989680\",\n                    \"to\":\"0x20c0000000000000000000000000000000000000\",\n                    \"value\":\"0x0\"\n                },\n                {\n                    \"data\":null,\n                    \"input\":\"0xf8856c0f00000000000000000000000020c000000000000000000000000000000000000000000000000000000000000020c00000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000989680000000000000000000000000000000000000000000000000000000000097d330\",\n                    \"to\":\"0xdec0000000000000000000000000000000000000\",\n                    \"value\":\"0x0\"\n                }\n            ],\n            \"accessList\":[],\n            \"nonceKey\":\"0x0\",\n            \"nonce\":\"0x0\",\n            \"feePayerSignature\":null,\n            \"validBefore\":null,\n            \"validAfter\":null,\n            \"keyAuthorization\":null,\n            \"aaAuthorizationList\":[],\n            \"signature\":{\n                \"pubKeyX\":\"0xaacc80b21e45fb11f349424dce3a2f23547f60c0ff2f8bcaede2a247545ce8dd\",\n                \"pubKeyY\":\"0x87abf0dbb7a5c9507efae2e43833356651b45ac576c2e61cec4e9c0f41fcbf6e\",\n                \"r\":\"0xcfd45c3b19745a42f80b134dcb02a8ba099a0e4e7be1984da54734aa81d8f29f\",\n                \"s\":\"0x74bb9170ae6d25bd510c83fe35895ee5712efe13980a5edc8094c534e23af85e\",\n                \"type\":\"webAuthn\",\n                \"webauthnData\":\"0x7b98b7a8e6c68d7eac741a52e6fdae0560ce3c16ef5427ad46d7a54d0ed86dd41d000000007b2274797065223a22776562617574686e2e676574222c226368616c6c656e6765223a2238453071464a7a50585167546e645473643649456659457776323173516e626966374c4741776e4b43626b222c226f726967696e223a2268747470733a2f2f74656d706f2d6465782e76657263656c2e617070222c2263726f73734f726967696e223a66616c73657d\"\n            },\n            \"hash\":\"0x6d6d8c102064e6dee44abad2024a8b1d37959230baab80e70efbf9b0c739c4fd\",\n            \"blockHash\":\"0xc82b23589ceef5341ed307d33554714db6f9eefd4187a9ca8abc910a325b4689\",\n            \"blockNumber\":\"0x321fde\",\n            \"transactionIndex\":\"0x0\",\n            \"from\":\"0x566ff0f4a6114f8072ecdc8a7a8a13d8d0c6b45f\",\n            \"gasPrice\":\"0x2540be400\"\n        }\"#;\n\n        let tx: Transaction<TempoTxEnvelope> = serde_json::from_str(s).unwrap();\n\n        assert_eq!(\n            tx.pretty().trim(),\n            r#\"\nblockHash            0xc82b23589ceef5341ed307d33554714db6f9eefd4187a9ca8abc910a325b4689\nblockNumber          3284958\nfrom                 0x566Ff0f4a6114F8072ecDC8A7A8A13d8d0C6B45F\ntransactionIndex     0\neffectiveGasPrice    10000000000\nhash                 0x6d6d8c102064e6dee44abad2024a8b1d37959230baab80e70efbf9b0c739c4fd\ntype                 118\nchainId              42429\nfeeToken             0x20C0000000000000000000000000000000000001\nmaxPriorityFeePerGas 0\nmaxFeePerGas         12000000000\ngasLimit             184696\ncalls                [\n\tto: 0x20C0000000000000000000000000000000000000, value: 0, input: 0x095ea7b3000000000000000000000000dec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000989680\n\tto: 0xDEc0000000000000000000000000000000000000, value: 0, input: 0xf8856c0f00000000000000000000000020c000000000000000000000000000000000000000000000000000000000000020c00000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000989680000000000000000000000000000000000000000000000000000000000097d330\n]\naccessList           []\nnonceKey             0\nnonce                0\nfeePayerSignature    \nvalidBefore          \nvalidAfter           \ntempoSignature       {\"type\":\"webAuthn\",\"r\":\"0xcfd45c3b19745a42f80b134dcb02a8ba099a0e4e7be1984da54734aa81d8f29f\",\"s\":\"0x74bb9170ae6d25bd510c83fe35895ee5712efe13980a5edc8094c534e23af85e\",\"pubKeyX\":\"0xaacc80b21e45fb11f349424dce3a2f23547f60c0ff2f8bcaede2a247545ce8dd\",\"pubKeyY\":\"0x87abf0dbb7a5c9507efae2e43833356651b45ac576c2e61cec4e9c0f41fcbf6e\",\"webauthnData\":\"0x7b98b7a8e6c68d7eac741a52e6fdae0560ce3c16ef5427ad46d7a54d0ed86dd41d000000007b2274797065223a22776562617574686e2e676574222c226368616c6c656e6765223a2238453071464a7a50585167546e645473643649456659457776323173516e626966374c4741776e4b43626b222c226f726967696e223a2268747470733a2f2f74656d706f2d6465782e76657263656c2e617070222c2263726f73734f726967696e223a66616c73657d\"}\n\"#\n                .trim()\n        );\n    }\n\n    #[test]\n    fn can_pretty_print_tempo_receipt() {\n        let s = r#\"{\"type\":\"0x76\",\"status\":\"0x1\",\"cumulativeGasUsed\":\"0x176d7f4\",\"logs\":[{\"address\":\"0x20c0000000000000000000000000000000000000\",\"topics\":[\"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef\",\"0x000000000000000000000000a70ab0448e66cd77995bfbba5c5b64b41a85f3fd\",\"0x0000000000000000000000000000000000000000000000000000000000000001\"],\"data\":\"0x00000000000000000000000000000000000000000000000000000000000003e8\",\"blockHash\":\"0x860f788b251ece768e63b0d3906d156f652d843848b71c7fe81faacd49139d66\",\"blockNumber\":\"0x69a1d7\",\"blockTimestamp\":\"0x69a5d790\",\"transactionHash\":\"0x04548a0ea27e2cccc1479af3c2ff02da4d4d3ea46af8e8d7edaa49f6ea27073f\",\"transactionIndex\":\"0x63\",\"logIndex\":\"0xb8\",\"removed\":false},{\"address\":\"0x20c0000000000000000000000000000000000003\",\"topics\":[\"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef\",\"0x000000000000000000000000a70ab0448e66cd77995bfbba5c5b64b41a85f3fd\",\"0x000000000000000000000000feec000000000000000000000000000000000000\"],\"data\":\"0x0000000000000000000000000000000000000000000000000000000000000417\",\"blockHash\":\"0x860f788b251ece768e63b0d3906d156f652d843848b71c7fe81faacd49139d66\",\"blockNumber\":\"0x69a1d7\",\"blockTimestamp\":\"0x69a5d790\",\"transactionHash\":\"0x04548a0ea27e2cccc1479af3c2ff02da4d4d3ea46af8e8d7edaa49f6ea27073f\",\"transactionIndex\":\"0x63\",\"logIndex\":\"0xb9\",\"removed\":false}],\"logsBloom\":\"0x00000000000000000000000000000000000000000000010000000000000000000000000000000000000000000100000000000000000000000000000000040008000004200000000000000008000000000000000000040000000000000400000000000002000000000000000000000000000000000000000000000010000000000000000000000000000000000020000000000000800000000000000000000000000020000000000000000000000000000000000400000000000000000000000000000002000000000000000400000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000\",\"transactionHash\":\"0x04548a0ea27e2cccc1479af3c2ff02da4d4d3ea46af8e8d7edaa49f6ea27073f\",\"transactionIndex\":\"0x63\",\"blockHash\":\"0x860f788b251ece768e63b0d3906d156f652d843848b71c7fe81faacd49139d66\",\"blockNumber\":\"0x69a1d7\",\"gasUsed\":\"0xcc6a\",\"effectiveGasPrice\":\"0x4a817c802\",\"from\":\"0xa70ab0448e66cd77995bfbba5c5b64b41a85f3fd\",\"to\":\"0x20c0000000000000000000000000000000000000\",\"contractAddress\":null,\"feeToken\":\"0x20c0000000000000000000000000000000000003\",\"feePayer\":\"0xa70ab0448e66cd77995bfbba5c5b64b41a85f3fd\"}\"#;\n\n        let tx: TempoTransactionReceipt = serde_json::from_str(s).unwrap();\n\n        assert_eq!(\n            tx.pretty().trim(),\n            r#\"\nblockHash            0x860f788b251ece768e63b0d3906d156f652d843848b71c7fe81faacd49139d66\nblockNumber          6922711\ncontractAddress      \ncumulativeGasUsed    24565748\neffectiveGasPrice    20000000002\nfrom                 0xa70ab0448e66cD77995bfBBa5c5b64B41a85F3fd\ngasUsed              52330\nlogs                 [{\"address\":\"0x20c0000000000000000000000000000000000000\",\"topics\":[\"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef\",\"0x000000000000000000000000a70ab0448e66cd77995bfbba5c5b64b41a85f3fd\",\"0x0000000000000000000000000000000000000000000000000000000000000001\"],\"data\":\"0x00000000000000000000000000000000000000000000000000000000000003e8\",\"blockHash\":\"0x860f788b251ece768e63b0d3906d156f652d843848b71c7fe81faacd49139d66\",\"blockNumber\":\"0x69a1d7\",\"blockTimestamp\":\"0x69a5d790\",\"transactionHash\":\"0x04548a0ea27e2cccc1479af3c2ff02da4d4d3ea46af8e8d7edaa49f6ea27073f\",\"transactionIndex\":\"0x63\",\"logIndex\":\"0xb8\",\"removed\":false},{\"address\":\"0x20c0000000000000000000000000000000000003\",\"topics\":[\"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef\",\"0x000000000000000000000000a70ab0448e66cd77995bfbba5c5b64b41a85f3fd\",\"0x000000000000000000000000feec000000000000000000000000000000000000\"],\"data\":\"0x0000000000000000000000000000000000000000000000000000000000000417\",\"blockHash\":\"0x860f788b251ece768e63b0d3906d156f652d843848b71c7fe81faacd49139d66\",\"blockNumber\":\"0x69a1d7\",\"blockTimestamp\":\"0x69a5d790\",\"transactionHash\":\"0x04548a0ea27e2cccc1479af3c2ff02da4d4d3ea46af8e8d7edaa49f6ea27073f\",\"transactionIndex\":\"0x63\",\"logIndex\":\"0xb9\",\"removed\":false}]\nlogsBloom            0x00000000000000000000000000000000000000000000010000000000000000000000000000000000000000000100000000000000000000000000000000040008000004200000000000000008000000000000000000040000000000000400000000000002000000000000000000000000000000000000000000000010000000000000000000000000000000000020000000000000800000000000000000000000000020000000000000000000000000000000000400000000000000000000000000000002000000000000000400000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000\nroot                 \nstatus               true\ntransactionHash      0x04548a0ea27e2cccc1479af3c2ff02da4d4d3ea46af8e8d7edaa49f6ea27073f\ntransactionIndex     99\ntype                 118\nfeePayer             0xa70ab0448e66cD77995bfBBa5c5b64B41a85F3fd\nfeeToken             0x20C0000000000000000000000000000000000003\nto                   0x20C0000000000000000000000000000000000000\n\"#\n                .trim()\n        );\n    }\n\n    #[test]\n    fn test_foundry_tx_receipt_uifmt() {\n        use alloy_network::AnyTransactionReceipt;\n        use foundry_primitives::FoundryTxReceipt;\n\n        // Test UIfmt implementation for FoundryTxReceipt\n        let s = r#\"{\"type\":\"0x2\",\"status\":\"0x1\",\"cumulativeGasUsed\":\"0x5208\",\"logs\":[],\"logsBloom\":\"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\"transactionHash\":\"0x1234567890123456789012345678901234567890123456789012345678901234\",\"transactionIndex\":\"0x0\",\"blockHash\":\"0xabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcd\",\"blockNumber\":\"0x1\",\"gasUsed\":\"0x5208\",\"effectiveGasPrice\":\"0x3b9aca00\",\"from\":\"0x1234567890123456789012345678901234567890\",\"to\":\"0x0987654321098765432109876543210987654321\",\"contractAddress\":null}\"#;\n        let any_receipt: AnyTransactionReceipt = serde_json::from_str(s).unwrap();\n        let foundry_receipt = FoundryTxReceipt::try_from(any_receipt).unwrap();\n\n        let pretty_output = foundry_receipt.pretty();\n\n        // Check that essential fields are present in the output\n        assert!(pretty_output.contains(\"blockHash\"));\n        assert!(pretty_output.contains(\"blockNumber\"));\n        assert!(pretty_output.contains(\"status\"));\n        assert!(pretty_output.contains(\"gasUsed\"));\n        assert!(pretty_output.contains(\"transactionHash\"));\n        assert!(pretty_output.contains(\"type\"));\n\n        // Verify the transaction hash appears in the output\n        assert!(\n            pretty_output\n                .contains(\"0x1234567890123456789012345678901234567890123456789012345678901234\")\n        );\n\n        // Verify status is pretty printed correctly (boolean true for successful transaction)\n        assert!(pretty_output.contains(\"true\"));\n    }\n\n    #[test]\n    fn test_get_pretty_receipt_attr() {\n        let receipt_json = serde_json::json!({\n            \"type\": \"0x2\",\n            \"status\": \"0x1\",\n            \"cumulativeGasUsed\": \"0x5208\",\n            \"logs\": [],\n            \"logsBloom\": \"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\n            \"transactionHash\": \"0x1234567890123456789012345678901234567890123456789012345678901234\",\n            \"transactionIndex\": \"0x0\",\n            \"blockHash\": \"0xabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcd\",\n            \"blockNumber\": \"0x1\",\n            \"gasUsed\": \"0x5208\",\n            \"effectiveGasPrice\": \"0x3b9aca00\",\n            \"from\": \"0x1234567890123456789012345678901234567890\",\n            \"to\": \"0x0987654321098765432109876543210987654321\",\n            \"contractAddress\": null\n        });\n\n        let receipt: <FoundryNetwork as Network>::ReceiptResponse =\n            serde_json::from_value(receipt_json).unwrap();\n\n        // Test basic receipt attributes\n        assert_eq!(\n            Some(\"0xabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcd\".to_string()),\n            get_pretty_receipt_attr::<FoundryNetwork>(&receipt, \"blockHash\")\n        );\n        assert_eq!(\n            Some(\"1\".to_string()),\n            get_pretty_receipt_attr::<FoundryNetwork>(&receipt, \"blockNumber\")\n        );\n        assert_eq!(\n            Some(\"0x1234567890123456789012345678901234567890123456789012345678901234\".to_string()),\n            get_pretty_receipt_attr::<FoundryNetwork>(&receipt, \"transactionHash\")\n        );\n        assert_eq!(\n            Some(\"21000\".to_string()),\n            get_pretty_receipt_attr::<FoundryNetwork>(&receipt, \"gasUsed\")\n        );\n        assert_eq!(\n            Some(\"true\".to_string()),\n            get_pretty_receipt_attr::<FoundryNetwork>(&receipt, \"status\")\n        );\n        assert_eq!(\n            Some(\"2\".to_string()),\n            get_pretty_receipt_attr::<FoundryNetwork>(&receipt, \"type\")\n        );\n        assert_eq!(\n            Some(\"[]\".to_string()),\n            get_pretty_receipt_attr::<FoundryNetwork>(&receipt, \"logs\")\n        );\n        assert!(get_pretty_receipt_attr::<FoundryNetwork>(&receipt, \"logsBloom\").is_some());\n    }\n}\n"
  },
  {
    "path": "crates/common/src/abi.rs",
    "content": "//! ABI related helper functions.\n\nuse alloy_chains::Chain;\nuse alloy_dyn_abi::{DynSolType, DynSolValue, FunctionExt, JsonAbiExt};\nuse alloy_json_abi::{Error, Event, Function, Param};\nuse alloy_primitives::{Address, LogData, hex};\nuse eyre::{Context, ContextCompat, Result};\nuse foundry_block_explorers::{Client, contract::ContractMetadata, errors::EtherscanError};\nuse std::pin::Pin;\n\npub fn encode_args<I, S>(inputs: &[Param], args: I) -> Result<Vec<DynSolValue>>\nwhere\n    I: IntoIterator<Item = S>,\n    S: AsRef<str>,\n{\n    let args: Vec<S> = args.into_iter().collect();\n\n    if inputs.len() != args.len() {\n        eyre::bail!(\"encode length mismatch: expected {} types, got {}\", inputs.len(), args.len())\n    }\n\n    std::iter::zip(inputs, args)\n        .map(|(input, arg)| coerce_value(&input.selector_type(), arg.as_ref()))\n        .collect()\n}\n\n/// Given a function and a vector of string arguments, it proceeds to convert the args to alloy\n/// [DynSolValue]s and then ABI encode them, prefixes the encoded data with the function selector.\npub fn encode_function_args<I, S>(func: &Function, args: I) -> Result<Vec<u8>>\nwhere\n    I: IntoIterator<Item = S>,\n    S: AsRef<str>,\n{\n    Ok(func.abi_encode_input(&encode_args(&func.inputs, args)?)?)\n}\n\n/// Given a function and a vector of string arguments, it proceeds to convert the args to alloy\n/// [DynSolValue]s and then ABI encode them. Doesn't prefix the function selector.\npub fn encode_function_args_raw<I, S>(func: &Function, args: I) -> Result<Vec<u8>>\nwhere\n    I: IntoIterator<Item = S>,\n    S: AsRef<str>,\n{\n    Ok(func.abi_encode_input_raw(&encode_args(&func.inputs, args)?)?)\n}\n\n/// Given a function and a vector of string arguments, it proceeds to convert the args to alloy\n/// [DynSolValue]s and encode them using the packed encoding.\npub fn encode_function_args_packed<I, S>(func: &Function, args: I) -> Result<Vec<u8>>\nwhere\n    I: IntoIterator<Item = S>,\n    S: AsRef<str>,\n{\n    let args: Vec<S> = args.into_iter().collect();\n\n    if func.inputs.len() != args.len() {\n        eyre::bail!(\n            \"encode length mismatch: expected {} types, got {}\",\n            func.inputs.len(),\n            args.len(),\n        );\n    }\n\n    let params: Vec<Vec<u8>> = std::iter::zip(&func.inputs, args)\n        .map(|(input, arg)| coerce_value(&input.selector_type(), arg.as_ref()))\n        .collect::<Result<Vec<_>>>()?\n        .into_iter()\n        .map(|v| v.abi_encode_packed())\n        .collect();\n\n    Ok(params.concat())\n}\n\n/// Decodes the calldata of the function\npub fn abi_decode_calldata(\n    sig: &str,\n    calldata: &str,\n    input: bool,\n    fn_selector: bool,\n) -> Result<Vec<DynSolValue>> {\n    let func = get_func(sig)?;\n    let calldata = hex::decode(calldata)?;\n\n    let mut calldata = calldata.as_slice();\n    // If function selector is prefixed in \"calldata\", remove it (first 4 bytes)\n    if input && fn_selector && calldata.len() >= 4 {\n        calldata = &calldata[4..];\n    }\n\n    let res =\n        if input { func.abi_decode_input(calldata) } else { func.abi_decode_output(calldata) }?;\n\n    // in case the decoding worked but nothing was decoded\n    if res.is_empty() {\n        eyre::bail!(\"no data was decoded\")\n    }\n\n    Ok(res)\n}\n\n/// Given a function signature string, it tries to parse it as a `Function`\npub fn get_func(sig: &str) -> Result<Function> {\n    Function::parse(sig).wrap_err(\"could not parse function signature\")\n}\n\n/// Given an event signature string, it tries to parse it as a `Event`\npub fn get_event(sig: &str) -> Result<Event> {\n    Event::parse(sig).wrap_err(\"could not parse event signature\")\n}\n\n/// Given an error signature string, it tries to parse it as a `Error`\npub fn get_error(sig: &str) -> Result<Error> {\n    Error::parse(sig).wrap_err(\"could not parse error signature\")\n}\n\n/// Given an event without indexed parameters and a rawlog, it tries to return the event with the\n/// proper indexed parameters. Otherwise, it returns the original event.\npub fn get_indexed_event(mut event: Event, raw_log: &LogData) -> Event {\n    if !event.anonymous && raw_log.topics().len() > 1 {\n        let indexed_params = raw_log.topics().len() - 1;\n        let num_inputs = event.inputs.len();\n        let num_address_params = event.inputs.iter().filter(|p| p.ty == \"address\").count();\n\n        event.inputs.iter_mut().enumerate().for_each(|(index, param)| {\n            if param.name.is_empty() {\n                param.name = format!(\"param{index}\");\n            }\n            if num_inputs == indexed_params\n                || (num_address_params == indexed_params && param.ty == \"address\")\n            {\n                param.indexed = true;\n            }\n        })\n    }\n    event\n}\n\n/// Given a function name, address, and args, tries to parse it as a `Function` by fetching the\n/// abi from etherscan. If the address is a proxy, fetches the ABI of the implementation contract.\npub async fn get_func_etherscan(\n    function_name: &str,\n    contract: Address,\n    args: &[String],\n    chain: Chain,\n    etherscan_api_key: &str,\n) -> Result<Function> {\n    let client = Client::new(chain, etherscan_api_key)?;\n    let source = find_source(client, contract).await?;\n    let metadata = source.items.first().wrap_err(\"etherscan returned empty metadata\")?;\n\n    let mut abi = metadata.abi()?;\n    let funcs = abi.functions.remove(function_name).unwrap_or_default();\n\n    for func in funcs {\n        let res = encode_function_args(&func, args);\n        if res.is_ok() {\n            return Ok(func);\n        }\n    }\n\n    Err(eyre::eyre!(\"Function not found in abi\"))\n}\n\n/// If the code at `address` is a proxy, recurse until we find the implementation.\npub fn find_source(\n    client: Client,\n    address: Address,\n) -> Pin<Box<dyn Future<Output = Result<ContractMetadata>>>> {\n    Box::pin(async move {\n        trace!(%address, \"find Etherscan source\");\n        let source = client.contract_source_code(address).await?;\n        let metadata = source.items.first().wrap_err(\"Etherscan returned no data\")?;\n        if metadata.proxy == 0 {\n            Ok(source)\n        } else {\n            let implementation = metadata.implementation.unwrap();\n            sh_println!(\n                \"Contract at {address} is a proxy, trying to fetch source at {implementation}...\"\n            )?;\n            match find_source(client, implementation).await {\n                impl_source @ Ok(_) => impl_source,\n                Err(e) => {\n                    let err = EtherscanError::ContractCodeNotVerified(address).to_string();\n                    if e.to_string() == err {\n                        error!(%err);\n                        Ok(source)\n                    } else {\n                        Err(e)\n                    }\n                }\n            }\n        }\n    })\n}\n\n/// Helper function to coerce a value to a [DynSolValue] given a type string\npub fn coerce_value(ty: &str, arg: &str) -> Result<DynSolValue> {\n    let ty = DynSolType::parse(ty)?;\n    Ok(DynSolType::coerce_str(&ty, arg)?)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use alloy_dyn_abi::EventExt;\n    use alloy_primitives::{B256, U256};\n\n    #[test]\n    fn test_get_func() {\n        let func = get_func(\"function foo(uint256 a, uint256 b) returns (uint256)\");\n        assert!(func.is_ok());\n        let func = func.unwrap();\n        assert_eq!(func.name, \"foo\");\n        assert_eq!(func.inputs.len(), 2);\n        assert_eq!(func.inputs[0].ty, \"uint256\");\n        assert_eq!(func.inputs[1].ty, \"uint256\");\n\n        // Stripped down function, which [Function] can parse.\n        let func = get_func(\"foo(bytes4 a, uint8 b)(bytes4)\");\n        assert!(func.is_ok());\n        let func = func.unwrap();\n        assert_eq!(func.name, \"foo\");\n        assert_eq!(func.inputs.len(), 2);\n        assert_eq!(func.inputs[0].ty, \"bytes4\");\n        assert_eq!(func.inputs[1].ty, \"uint8\");\n        assert_eq!(func.outputs[0].ty, \"bytes4\");\n    }\n\n    #[test]\n    fn test_indexed_only_address() {\n        let event = get_event(\"event Ev(address,uint256,address)\").unwrap();\n\n        let param0 = B256::random();\n        let param1 = vec![3; 32];\n        let param2 = B256::random();\n        let log = LogData::new_unchecked(vec![event.selector(), param0, param2], param1.into());\n        let event = get_indexed_event(event, &log);\n\n        assert_eq!(event.inputs.len(), 3);\n\n        // Only the address fields get indexed since total_params > num_indexed_params\n        let parsed = event.decode_log(&log).unwrap();\n\n        assert_eq!(event.inputs.iter().filter(|param| param.indexed).count(), 2);\n        assert_eq!(parsed.indexed[0], DynSolValue::Address(Address::from_word(param0)));\n        assert_eq!(parsed.body[0], DynSolValue::Uint(U256::from_be_bytes([3; 32]), 256));\n        assert_eq!(parsed.indexed[1], DynSolValue::Address(Address::from_word(param2)));\n    }\n\n    #[test]\n    fn test_indexed_all() {\n        let event = get_event(\"event Ev(address,uint256,address)\").unwrap();\n\n        let param0 = B256::random();\n        let param1 = vec![3; 32];\n        let param2 = B256::random();\n        let log = LogData::new_unchecked(\n            vec![event.selector(), param0, B256::from_slice(&param1), param2],\n            vec![].into(),\n        );\n        let event = get_indexed_event(event, &log);\n\n        assert_eq!(event.inputs.len(), 3);\n\n        // All parameters get indexed since num_indexed_params == total_params\n        assert_eq!(event.inputs.iter().filter(|param| param.indexed).count(), 3);\n        let parsed = event.decode_log(&log).unwrap();\n\n        assert_eq!(parsed.indexed[0], DynSolValue::Address(Address::from_word(param0)));\n        assert_eq!(parsed.indexed[1], DynSolValue::Uint(U256::from_be_bytes([3; 32]), 256));\n        assert_eq!(parsed.indexed[2], DynSolValue::Address(Address::from_word(param2)));\n    }\n\n    #[test]\n    fn test_encode_args_length_validation() {\n        use alloy_json_abi::Param;\n\n        let params = vec![\n            Param {\n                name: \"a\".to_string(),\n                ty: \"uint256\".to_string(),\n                internal_type: None,\n                components: vec![],\n            },\n            Param {\n                name: \"b\".to_string(),\n                ty: \"address\".to_string(),\n                internal_type: None,\n                components: vec![],\n            },\n        ];\n\n        // Less arguments than parameters\n        let args = vec![\"1\"];\n        let res = encode_args(&params, &args);\n        assert!(res.is_err());\n        assert!(format!(\"{}\", res.unwrap_err()).contains(\"encode length mismatch\"));\n\n        // Exact number of arguments and parameters\n        let args = vec![\"1\", \"0x0000000000000000000000000000000000000001\"];\n        let res = encode_args(&params, &args);\n        assert!(res.is_ok());\n        let values = res.unwrap();\n        assert_eq!(values.len(), 2);\n\n        // More arguments than parameters\n        let args = vec![\"1\", \"0x0000000000000000000000000000000000000001\", \"extra\"];\n        let res = encode_args(&params, &args);\n        assert!(res.is_err());\n        assert!(format!(\"{}\", res.unwrap_err()).contains(\"encode length mismatch\"));\n    }\n}\n"
  },
  {
    "path": "crates/common/src/calc.rs",
    "content": "//! Commonly used calculations.\n\n/// Returns the mean of the slice.\npub fn mean(values: &[u64]) -> u64 {\n    if values.is_empty() {\n        return 0;\n    }\n\n    (values.iter().map(|x| *x as u128).sum::<u128>() / values.len() as u128) as u64\n}\n\n/// Returns the median of a _sorted_ slice.\npub fn median_sorted(values: &[u64]) -> u64 {\n    if values.is_empty() {\n        return 0;\n    }\n\n    let len = values.len();\n    let mid = len / 2;\n    if len.is_multiple_of(2) { (values[mid - 1] + values[mid]) / 2 } else { values[mid] }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn calc_mean_empty() {\n        let m = mean(&[]);\n        assert_eq!(m, 0);\n    }\n\n    #[test]\n    fn calc_mean() {\n        let m = mean(&[0, 1, 2, 3, 4, 5, 6]);\n        assert_eq!(m, 3);\n    }\n\n    #[test]\n    fn calc_mean_overflow() {\n        let m = mean(&[0, 1, 2, u32::MAX as u64, 3, u16::MAX as u64, u64::MAX, 6]);\n        assert_eq!(m, 2305843009750573057);\n    }\n\n    #[test]\n    fn calc_median_empty() {\n        let m = median_sorted(&[]);\n        assert_eq!(m, 0);\n    }\n\n    #[test]\n    fn calc_median() {\n        let mut values = vec![29, 30, 31, 40, 59, 61, 71];\n        values.sort();\n        let m = median_sorted(&values);\n        assert_eq!(m, 40);\n    }\n\n    #[test]\n    fn calc_median_even() {\n        let mut values = vec![80, 90, 30, 40, 50, 60, 10, 20];\n        values.sort();\n        let m = median_sorted(&values);\n        assert_eq!(m, 45);\n    }\n}\n"
  },
  {
    "path": "crates/common/src/comments/comment.rs",
    "content": "//! Modified from [`rustc_ast::util::comments`](https://github.com/rust-lang/rust/blob/07d3fd1d9b9c1f07475b96a9d168564bf528db68/compiler/rustc_ast/src/util/comments.rs).\n\nuse solar::parse::{\n    ast::{CommentKind, Span},\n    interface::BytePos,\n};\n\n#[derive(Clone, Copy, PartialEq, Debug)]\npub enum CommentStyle {\n    /// No code on either side of each line of the comment\n    Isolated,\n    /// Code exists to the left of the comment\n    Trailing,\n    /// Code before /* foo */ and after the comment\n    Mixed,\n    /// Just a manual blank line \"\\n\\n\", for layout\n    BlankLine,\n}\n\nimpl CommentStyle {\n    pub fn is_mixed(&self) -> bool {\n        matches!(self, Self::Mixed)\n    }\n    pub fn is_trailing(&self) -> bool {\n        matches!(self, Self::Trailing)\n    }\n    pub fn is_isolated(&self) -> bool {\n        matches!(self, Self::Isolated)\n    }\n    pub fn is_blank(&self) -> bool {\n        matches!(self, Self::BlankLine)\n    }\n}\n\n#[derive(Clone, Debug)]\npub struct Comment {\n    pub lines: Vec<String>,\n    pub span: Span,\n    pub style: CommentStyle,\n    pub is_doc: bool,\n    pub kind: CommentKind,\n}\n\nimpl Comment {\n    pub fn pos(&self) -> BytePos {\n        self.span.lo()\n    }\n\n    pub fn prefix(&self) -> Option<&'static str> {\n        if self.lines.is_empty() {\n            return None;\n        }\n        Some(match (self.kind, self.is_doc) {\n            (CommentKind::Line, false) => \"//\",\n            (CommentKind::Line, true) => \"///\",\n            (CommentKind::Block, false) => \"/*\",\n            (CommentKind::Block, true) => \"/**\",\n        })\n    }\n\n    pub fn suffix(&self) -> Option<&'static str> {\n        if self.lines.is_empty() {\n            return None;\n        }\n        match self.kind {\n            CommentKind::Line => None,\n            CommentKind::Block => Some(\"*/\"),\n        }\n    }\n}\n"
  },
  {
    "path": "crates/common/src/comments/inline_config.rs",
    "content": "use solar::{\n    interface::{BytePos, RelativeBytePos, SourceMap, Span},\n    parse::ast::{self, Visit},\n};\nuse std::{\n    collections::{HashMap, hash_map::Entry},\n    hash::Hash,\n    ops::ControlFlow,\n};\n\n/// A disabled formatting range.\n#[derive(Debug, Clone, Copy)]\nstruct DisabledRange<T = BytePos> {\n    /// Start position, inclusive.\n    lo: T,\n    /// End position, inclusive.\n    hi: T,\n}\n\nimpl DisabledRange<BytePos> {\n    fn includes(&self, span: Span) -> bool {\n        span.lo() >= self.lo && span.hi() <= self.hi\n    }\n}\n\n/// An inline config item\n#[derive(Clone, Debug)]\npub enum InlineConfigItem<I> {\n    /// Disables the next code (AST) item regardless of newlines\n    DisableNextItem(I),\n    /// Disables formatting on the current line\n    DisableLine(I),\n    /// Disables formatting between the next newline and the newline after\n    DisableNextLine(I),\n    /// Disables formatting for any code that follows this and before the next \"disable-end\"\n    DisableStart(I),\n    /// Disables formatting for any code that precedes this and after the previous \"disable-start\"\n    DisableEnd(I),\n}\n\nimpl InlineConfigItem<Vec<String>> {\n    /// Parse an inline config item from a string. Validates IDs against available IDs.\n    pub fn parse(s: &str, available_ids: &[&str]) -> Result<Self, InvalidInlineConfigItem> {\n        let (disable, relevant) = s.split_once('(').unwrap_or((s, \"\"));\n        let ids = if relevant.is_empty() || relevant == \"all)\" {\n            vec![\"all\".to_string()]\n        } else {\n            match relevant.split_once(')') {\n                Some((id_str, _)) => id_str.split(\",\").map(|s| s.trim().to_string()).collect(),\n                None => return Err(InvalidInlineConfigItem::Syntax(s.into())),\n            }\n        };\n\n        // Validate IDs\n        let mut invalid_ids = Vec::new();\n        'ids: for id in &ids {\n            if id == \"all\" {\n                continue;\n            }\n            for available_id in available_ids {\n                if *available_id == id {\n                    continue 'ids;\n                }\n            }\n            invalid_ids.push(id.to_owned());\n        }\n\n        if !invalid_ids.is_empty() {\n            return Err(InvalidInlineConfigItem::Ids(invalid_ids));\n        }\n\n        let res = match disable {\n            \"disable-next-item\" => Self::DisableNextItem(ids),\n            \"disable-line\" => Self::DisableLine(ids),\n            \"disable-next-line\" => Self::DisableNextLine(ids),\n            \"disable-start\" => Self::DisableStart(ids),\n            \"disable-end\" => Self::DisableEnd(ids),\n            s => return Err(InvalidInlineConfigItem::Syntax(s.into())),\n        };\n\n        Ok(res)\n    }\n}\n\nimpl std::str::FromStr for InlineConfigItem<()> {\n    type Err = InvalidInlineConfigItem;\n    fn from_str(s: &str) -> Result<Self, Self::Err> {\n        Ok(match s {\n            \"disable-next-item\" => Self::DisableNextItem(()),\n            \"disable-line\" => Self::DisableLine(()),\n            \"disable-next-line\" => Self::DisableNextLine(()),\n            \"disable-start\" => Self::DisableStart(()),\n            \"disable-end\" => Self::DisableEnd(()),\n            s => return Err(InvalidInlineConfigItem::Syntax(s.into())),\n        })\n    }\n}\n\n#[derive(Debug)]\npub enum InvalidInlineConfigItem {\n    Syntax(String),\n    Ids(Vec<String>),\n}\n\nimpl std::fmt::Display for InvalidInlineConfigItem {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        match self {\n            Self::Syntax(s) => write!(f, \"invalid inline config item: {s}\"),\n            Self::Ids(ids) => {\n                write!(f, \"unknown id: '{}'\", ids.join(\"', '\"))\n            }\n        }\n    }\n}\n\n/// A trait for `InlineConfigItem` types that can be iterated over to produce keys for storage.\npub trait ItemIdIterator {\n    type Item: Eq + Hash + Clone;\n    fn into_iter(self) -> impl IntoIterator<Item = Self::Item>;\n}\n\nimpl ItemIdIterator for () {\n    type Item = ();\n    fn into_iter(self) -> impl IntoIterator<Item = Self::Item> {\n        std::iter::once(())\n    }\n}\n\nimpl ItemIdIterator for Vec<String> {\n    type Item = String;\n    fn into_iter(self) -> impl IntoIterator<Item = Self::Item> {\n        self\n    }\n}\n\n#[derive(Debug, Default)]\npub struct InlineConfig<I: ItemIdIterator> {\n    disabled_ranges: HashMap<I::Item, Vec<DisabledRange>>,\n}\n\nimpl<I: ItemIdIterator> InlineConfig<I> {\n    /// Build a new inline config with an iterator of inline config items and their locations in a\n    /// source file.\n    ///\n    /// # Panics\n    ///\n    /// Panics if `items` is not sorted in ascending order of [`Span`]s.\n    pub fn from_ast<'ast>(\n        items: impl IntoIterator<Item = (Span, InlineConfigItem<I>)>,\n        ast: &'ast ast::SourceUnit<'ast>,\n        source_map: &SourceMap,\n    ) -> Self {\n        Self::build(items, source_map, |offset| NextItemFinder::new(offset).find(ast))\n    }\n\n    fn build(\n        items: impl IntoIterator<Item = (Span, InlineConfigItem<I>)>,\n        source_map: &SourceMap,\n        mut find_next_item: impl FnMut(BytePos) -> Option<Span>,\n    ) -> Self {\n        let mut cfg = Self::new();\n        let mut disabled_blocks = HashMap::new();\n\n        let mut prev_sp = Span::DUMMY;\n        for (sp, item) in items {\n            if cfg!(debug_assertions) {\n                assert!(sp >= prev_sp, \"InlineConfig::new: unsorted items: {sp:?} < {prev_sp:?}\");\n                prev_sp = sp;\n            }\n\n            cfg.disable_item(sp, item, source_map, &mut disabled_blocks, &mut find_next_item);\n        }\n\n        for (id, (_, lo, hi)) in disabled_blocks {\n            cfg.disable(id, DisabledRange { lo, hi });\n        }\n\n        cfg\n    }\n\n    fn new() -> Self {\n        Self { disabled_ranges: HashMap::new() }\n    }\n\n    fn disable_many(&mut self, ids: I, range: DisabledRange) {\n        for id in ids.into_iter() {\n            self.disable(id, range);\n        }\n    }\n\n    fn disable(&mut self, id: I::Item, range: DisabledRange) {\n        self.disabled_ranges.entry(id).or_default().push(range);\n    }\n\n    fn disable_item(\n        &mut self,\n        span: Span,\n        item: InlineConfigItem<I>,\n        source_map: &SourceMap,\n        disabled_blocks: &mut HashMap<I::Item, (usize, BytePos, BytePos)>,\n        find_next_item: &mut dyn FnMut(BytePos) -> Option<Span>,\n    ) {\n        let result = source_map.span_to_source(span).unwrap();\n        let file = result.file;\n        let comment_range = result.data;\n        let src = file.src.as_str();\n\n        #[allow(clippy::collapsible_match)]\n        match item {\n            InlineConfigItem::DisableNextItem(ids) => {\n                if let Some(next_item) = find_next_item(span.hi()) {\n                    self.disable_many(\n                        ids,\n                        DisabledRange { lo: next_item.lo(), hi: next_item.hi() },\n                    );\n                }\n            }\n            InlineConfigItem::DisableLine(ids) => {\n                let start = src[..comment_range.start].rfind('\\n').map_or(0, |i| i);\n                let end = src[comment_range.end..]\n                    .find('\\n')\n                    .map_or(src.len(), |i| comment_range.end + i);\n                self.disable_many(\n                    ids,\n                    DisabledRange {\n                        lo: file.absolute_position(RelativeBytePos::from_usize(start)),\n                        hi: file.absolute_position(RelativeBytePos::from_usize(end)),\n                    },\n                );\n            }\n            InlineConfigItem::DisableNextLine(ids) => {\n                if let Some(offset) = src[comment_range.end..].find('\\n') {\n                    let next_line = comment_range.end + offset + 1;\n                    if next_line < src.len() {\n                        let end = src[next_line..].find('\\n').map_or(src.len(), |i| next_line + i);\n                        self.disable_many(\n                            ids,\n                            DisabledRange {\n                                lo: file.absolute_position(RelativeBytePos::from_usize(\n                                    comment_range.start,\n                                )),\n                                hi: file.absolute_position(RelativeBytePos::from_usize(end)),\n                            },\n                        );\n                    }\n                }\n            }\n\n            InlineConfigItem::DisableStart(ids) => {\n                for id in ids.into_iter() {\n                    disabled_blocks.entry(id).and_modify(|(depth, _, _)| *depth += 1).or_insert((\n                        1,\n                        span.lo(),\n                        // Use file end as fallback for unclosed blocks\n                        file.absolute_position(RelativeBytePos::from_usize(src.len())),\n                    ));\n                }\n            }\n            InlineConfigItem::DisableEnd(ids) => {\n                for id in ids.into_iter() {\n                    if let Entry::Occupied(mut entry) = disabled_blocks.entry(id) {\n                        let (depth, lo, _) = entry.get_mut();\n                        *depth = depth.saturating_sub(1);\n\n                        if *depth == 0 {\n                            let lo = *lo;\n                            let (id, _) = entry.remove_entry();\n\n                            self.disable(id, DisabledRange { lo, hi: span.hi() });\n                        }\n                    }\n                }\n            }\n        }\n    }\n}\n\nimpl InlineConfig<()> {\n    /// Checks if a span is disabled (only applicable when inline config doesn't require an id).\n    pub fn is_disabled(&self, span: Span) -> bool {\n        if let Some(ranges) = self.disabled_ranges.get(&()) {\n            return ranges.iter().any(|range| range.includes(span));\n        }\n        false\n    }\n}\n\nimpl<I: ItemIdIterator> InlineConfig<I>\nwhere\n    I::Item: std::borrow::Borrow<str>,\n{\n    /// Checks if a span is disabled for a specific id. Also checks against \"all\", which disables\n    /// all rules.\n    pub fn is_id_disabled(&self, span: Span, id: &str) -> bool {\n        self.is_id_disabled_inner(span, id)\n            || (id != \"all\" && self.is_id_disabled_inner(span, \"all\"))\n    }\n\n    fn is_id_disabled_inner(&self, span: Span, id: &str) -> bool {\n        if let Some(ranges) = self.disabled_ranges.get(id)\n            && ranges.iter().any(|range| range.includes(span))\n        {\n            return true;\n        }\n\n        false\n    }\n}\n\nmacro_rules! find_next_item {\n    ($self:expr, $x:expr, $span:expr, $walk:ident) => {{\n        let span = $span;\n        // If the item is *entirely* before the offset, skip traversing it.\n        if span.hi() < $self.offset {\n            return ControlFlow::Continue(());\n        }\n        // Check if this item starts after the offset.\n        if span.lo() > $self.offset {\n            return ControlFlow::Break(span);\n        }\n        // Otherwise, continue traversing inside this item.\n        $self.$walk($x)\n    }};\n}\n\n/// An AST visitor that finds the first `Item` that starts after a given offset.\n#[derive(Debug)]\nstruct NextItemFinder {\n    /// The offset to search after.\n    offset: BytePos,\n}\n\nimpl NextItemFinder {\n    fn new(offset: BytePos) -> Self {\n        Self { offset }\n    }\n\n    /// Finds the next AST item or statement which a span that begins after the `offset`.\n    fn find<'ast>(&mut self, ast: &'ast ast::SourceUnit<'ast>) -> Option<Span> {\n        match self.visit_source_unit(ast) {\n            ControlFlow::Break(span) => Some(span),\n            ControlFlow::Continue(()) => None,\n        }\n    }\n}\n\nimpl<'ast> ast::Visit<'ast> for NextItemFinder {\n    type BreakValue = Span;\n\n    fn visit_item(&mut self, item: &'ast ast::Item<'ast>) -> ControlFlow<Self::BreakValue> {\n        find_next_item!(self, item, item.span, walk_item)\n    }\n\n    fn visit_stmt(&mut self, stmt: &'ast ast::Stmt<'ast>) -> ControlFlow<Self::BreakValue> {\n        find_next_item!(self, stmt, stmt.span, walk_stmt)\n    }\n\n    fn visit_yul_stmt(\n        &mut self,\n        stmt: &'ast ast::yul::Stmt<'ast>,\n    ) -> ControlFlow<Self::BreakValue> {\n        find_next_item!(self, stmt, stmt.span, walk_yul_stmt)\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    impl DisabledRange<usize> {\n        fn to_byte_pos(self) -> DisabledRange<BytePos> {\n            DisabledRange::<BytePos> {\n                lo: BytePos::from_usize(self.lo),\n                hi: BytePos::from_usize(self.hi),\n            }\n        }\n\n        fn includes(&self, range: std::ops::Range<usize>) -> bool {\n            self.to_byte_pos().includes(Span::new(\n                BytePos::from_usize(range.start),\n                BytePos::from_usize(range.end),\n            ))\n        }\n    }\n\n    #[test]\n    fn test_disabled_range_includes() {\n        let strict = DisabledRange { lo: 10, hi: 20 };\n        assert!(strict.includes(10..20));\n        assert!(strict.includes(12..18));\n        assert!(!strict.includes(5..15)); // Partial overlap fails\n    }\n\n    #[test]\n    fn test_inline_config_item_from_str() {\n        assert!(matches!(\n            \"disable-next-item\".parse::<InlineConfigItem<()>>().unwrap(),\n            InlineConfigItem::DisableNextItem(())\n        ));\n        assert!(matches!(\n            \"disable-line\".parse::<InlineConfigItem<()>>().unwrap(),\n            InlineConfigItem::DisableLine(())\n        ));\n        assert!(matches!(\n            \"disable-start\".parse::<InlineConfigItem<()>>().unwrap(),\n            InlineConfigItem::DisableStart(())\n        ));\n        assert!(matches!(\n            \"disable-end\".parse::<InlineConfigItem<()>>().unwrap(),\n            InlineConfigItem::DisableEnd(())\n        ));\n        assert!(\"invalid\".parse::<InlineConfigItem<()>>().is_err());\n    }\n\n    #[test]\n    fn test_inline_config_item_parse_with_lints() {\n        let lint_ids = vec![\"lint1\", \"lint2\"];\n\n        // No lints = \"all\"\n        match InlineConfigItem::parse(\"disable-line\", &lint_ids).unwrap() {\n            InlineConfigItem::DisableLine(lints) => assert_eq!(lints, vec![\"all\"]),\n            _ => panic!(\"Wrong type\"),\n        }\n\n        // Valid single lint\n        match InlineConfigItem::parse(\"disable-start(lint1)\", &lint_ids).unwrap() {\n            InlineConfigItem::DisableStart(lints) => assert_eq!(lints, vec![\"lint1\"]),\n            _ => panic!(\"Wrong type\"),\n        }\n\n        // Multiple lints with spaces\n        match InlineConfigItem::parse(\"disable-end(lint1, lint2)\", &lint_ids).unwrap() {\n            InlineConfigItem::DisableEnd(lints) => assert_eq!(lints, vec![\"lint1\", \"lint2\"]),\n            _ => panic!(\"Wrong type\"),\n        }\n\n        // Invalid lint ID\n        assert!(matches!(\n            InlineConfigItem::parse(\"disable-line(unknown)\", &lint_ids),\n            Err(InvalidInlineConfigItem::Ids(_))\n        ));\n\n        // Malformed syntax\n        assert!(matches!(\n            InlineConfigItem::parse(\"disable-line(lint1\", &lint_ids),\n            Err(InvalidInlineConfigItem::Syntax(_))\n        ));\n    }\n}\n"
  },
  {
    "path": "crates/common/src/comments/mod.rs",
    "content": "use crate::iter::IterDelimited;\nuse solar::parse::{\n    ast::{CommentKind, Span},\n    interface::{BytePos, CharPos, SourceMap, source_map::SourceFile},\n    lexer::token::RawTokenKind as TokenKind,\n};\nuse std::fmt;\n\nmod comment;\npub use comment::{Comment, CommentStyle};\n\npub mod inline_config;\n\npub const DISABLE_START: &str = \"forgefmt: disable-start\";\npub const DISABLE_END: &str = \"forgefmt: disable-end\";\n\npub struct Comments {\n    comments: std::collections::VecDeque<Comment>,\n}\n\nimpl fmt::Debug for Comments {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.write_str(\"Comments\")?;\n        f.debug_list().entries(self.iter()).finish()\n    }\n}\n\nimpl Comments {\n    pub fn new(\n        sf: &SourceFile,\n        sm: &SourceMap,\n        normalize_cmnts: bool,\n        group_cmnts: bool,\n        tab_width: Option<usize>,\n    ) -> Self {\n        let gatherer = CommentGatherer::new(sf, sm, normalize_cmnts, tab_width).gather();\n\n        Self {\n            comments: if group_cmnts { gatherer.group().into() } else { gatherer.comments.into() },\n        }\n    }\n\n    pub fn peek(&self) -> Option<&Comment> {\n        self.comments.front()\n    }\n\n    #[allow(clippy::should_implement_trait)]\n    pub fn next(&mut self) -> Option<Comment> {\n        self.comments.pop_front()\n    }\n\n    pub fn iter(&self) -> impl Iterator<Item = &Comment> {\n        self.comments.iter()\n    }\n\n    /// Adds a new comment at the beginning of the list.\n    ///\n    /// Should only be used when comments are gathered scattered, and must be manually sorted.\n    ///\n    /// **WARNING:** This struct works under the assumption that comments are always sorted by\n    /// ascending span position. It is the caller's responsibility to ensure that this premise\n    /// always holds true.\n    pub fn push_front(&mut self, cmnt: Comment) {\n        self.comments.push_front(cmnt)\n    }\n\n    /// Finds the first trailing comment on the same line as `span_pos`, allowing for `Mixed`\n    /// style comments to appear before it.\n    ///\n    /// Returns the comment and its index in the buffer.\n    pub fn peek_trailing(\n        &self,\n        sm: &SourceMap,\n        span_pos: BytePos,\n        next_pos: Option<BytePos>,\n    ) -> Option<(&Comment, usize)> {\n        let span_line = sm.lookup_char_pos(span_pos).line;\n        for (i, cmnt) in self.iter().enumerate() {\n            // If we have moved to the next line, we can stop.\n            let comment_line = sm.lookup_char_pos(cmnt.pos()).line;\n            if comment_line != span_line {\n                break;\n            }\n\n            // The comment must start after the given span position.\n            if cmnt.pos() < span_pos {\n                continue;\n            }\n\n            // The comment must be before the next element.\n            if cmnt.pos() >= next_pos.unwrap_or_else(|| cmnt.pos() + BytePos(1)) {\n                break;\n            }\n\n            // Stop when we find a trailing or a non-mixed comment\n            match cmnt.style {\n                CommentStyle::Mixed => continue,\n                CommentStyle::Trailing => return Some((cmnt, i)),\n                _ => break,\n            }\n        }\n        None\n    }\n}\n\nstruct CommentGatherer<'ast> {\n    sf: &'ast SourceFile,\n    sm: &'ast SourceMap,\n    text: &'ast str,\n    start_bpos: BytePos,\n    pos: usize,\n    comments: Vec<Comment>,\n    code_to_the_left: bool,\n    disabled_block_depth: usize,\n    tab_width: Option<usize>,\n}\n\nimpl<'ast> CommentGatherer<'ast> {\n    fn new(\n        sf: &'ast SourceFile,\n        sm: &'ast SourceMap,\n        normalize_cmnts: bool,\n        tab_width: Option<usize>,\n    ) -> Self {\n        Self {\n            sf,\n            sm,\n            text: sf.src.as_str(),\n            start_bpos: sf.start_pos,\n            pos: 0,\n            comments: Vec::new(),\n            code_to_the_left: false,\n            disabled_block_depth: if normalize_cmnts { 0 } else { 1 },\n            tab_width,\n        }\n    }\n\n    /// Consumes the gatherer and returns the collected comments.\n    fn gather(mut self) -> Self {\n        for token in solar::parse::Cursor::new(&self.text[self.pos..]) {\n            self.process_token(token);\n        }\n        self\n    }\n\n    /// Post-processes a list of comments to group consecutive comments.\n    ///\n    /// Necessary for properly indenting multi-line trailing comments, which would\n    /// otherwise be parsed as a `Trailing` followed by several `Isolated`.\n    fn group(self) -> Vec<Comment> {\n        let mut processed = Vec::new();\n        let mut cursor = self.comments.into_iter().peekable();\n\n        while let Some(mut current) = cursor.next() {\n            if current.kind == CommentKind::Line\n                && (current.style.is_trailing() || current.style.is_isolated())\n            {\n                let mut ref_line = self.sm.lookup_char_pos(current.span.hi()).line;\n                while let Some(next_comment) = cursor.peek() {\n                    if !next_comment.style.is_isolated()\n                        || next_comment.kind != CommentKind::Line\n                        || ref_line + 1 != self.sm.lookup_char_pos(next_comment.span.lo()).line\n                    {\n                        break;\n                    }\n\n                    let next_to_merge = cursor.next().unwrap();\n                    current.lines.extend(next_to_merge.lines);\n                    current.span = current.span.to(next_to_merge.span);\n                    ref_line += 1;\n                }\n            }\n\n            processed.push(current);\n        }\n\n        processed\n    }\n\n    /// Creates a `Span` relative to the source file's start position.\n    fn make_span(&self, range: std::ops::Range<usize>) -> Span {\n        Span::new(self.start_bpos + range.start as u32, self.start_bpos + range.end as u32)\n    }\n\n    /// Processes a single token from the source.\n    fn process_token(&mut self, token: solar::parse::lexer::token::RawToken) {\n        let token_range = self.pos..self.pos + token.len as usize;\n        let span = self.make_span(token_range.clone());\n        let token_text = &self.text[token_range];\n\n        // Keep track of disabled blocks\n        if token_text.trim_start().contains(DISABLE_START) {\n            self.disabled_block_depth += 1;\n        } else if token_text.trim_start().contains(DISABLE_END) {\n            self.disabled_block_depth -= 1;\n        }\n\n        #[allow(clippy::collapsible_match)]\n        match token.kind {\n            TokenKind::Whitespace => {\n                if let Some(mut idx) = token_text.find('\\n') {\n                    self.code_to_the_left = false;\n\n                    while let Some(next_newline) = token_text[idx + 1..].find('\\n') {\n                        idx += 1 + next_newline;\n                        let pos = self.pos + idx;\n                        self.comments.push(Comment {\n                            is_doc: false,\n                            kind: CommentKind::Line,\n                            style: CommentStyle::BlankLine,\n                            lines: vec![],\n                            span: self.make_span(pos..pos),\n                        });\n                        // If not disabled, early-exit as we want only a single blank line.\n                        if self.disabled_block_depth == 0 {\n                            break;\n                        }\n                    }\n                }\n            }\n            TokenKind::BlockComment { is_doc, .. } => {\n                let code_to_the_right = !matches!(\n                    self.text[self.pos + token.len as usize..].chars().next(),\n                    Some('\\r' | '\\n')\n                );\n                let style = match (self.code_to_the_left, code_to_the_right) {\n                    (_, true) => CommentStyle::Mixed,\n                    (false, false) => CommentStyle::Isolated,\n                    (true, false) => CommentStyle::Trailing,\n                };\n                let kind = CommentKind::Block;\n\n                // Count the number of chars since the start of the line by rescanning.\n                let pos_in_file = self.start_bpos + BytePos(self.pos as u32);\n                let line_begin_in_file = line_begin_pos(self.sf, pos_in_file);\n                let line_begin_pos = (line_begin_in_file - self.start_bpos).to_usize();\n                let mut col = CharPos(self.text[line_begin_pos..self.pos].chars().count());\n\n                // To preserve alignment in multi-line non-doc comments, normalize the block based\n                // on its least-indented line.\n                if !is_doc && token_text.contains('\\n') {\n                    col = token_text.lines().skip(1).fold(col, |min, line| {\n                        if line.is_empty() {\n                            return min;\n                        }\n                        std::cmp::min(\n                            CharPos(line.chars().count() - line.trim_start().chars().count()),\n                            min,\n                        )\n                    })\n                };\n\n                let lines = self.split_block_comment_into_lines(token_text, is_doc, col);\n                self.comments.push(Comment { is_doc, kind, style, lines, span })\n            }\n            TokenKind::LineComment { is_doc } => {\n                let line =\n                    if self.disabled_block_depth != 0 { token_text } else { token_text.trim_end() };\n                self.comments.push(Comment {\n                    is_doc,\n                    kind: CommentKind::Line,\n                    style: if self.code_to_the_left {\n                        CommentStyle::Trailing\n                    } else {\n                        CommentStyle::Isolated\n                    },\n                    lines: vec![line.into()],\n                    span,\n                });\n            }\n            _ => {\n                self.code_to_the_left = true;\n            }\n        }\n        self.pos += token.len as usize;\n    }\n\n    /// Splits a block comment into lines, ensuring that each line is properly formatted.\n    fn split_block_comment_into_lines(\n        &self,\n        text: &str,\n        is_doc: bool,\n        col: CharPos,\n    ) -> Vec<String> {\n        // if formatting is disabled, return as is\n        if self.disabled_block_depth != 0 {\n            return vec![text.into()];\n        }\n\n        let mut res: Vec<String> = vec![];\n        let mut lines = text.lines();\n        if let Some(line) = lines.next() {\n            let line = line.trim_end();\n            // Ensure first line of a doc comment only has the `/**` decorator\n            if is_doc && let Some((_, second)) = line.split_once(\"/**\") {\n                res.push(\"/**\".to_string());\n                if !second.trim().is_empty() {\n                    let line = normalize_block_comment_ws(second, col).trim_end();\n                    // Ensure last line of a doc comment only has the `*/` decorator\n                    if let Some((first, _)) = line.split_once(\"*/\") {\n                        if !first.trim().is_empty() {\n                            res.push(format_doc_block_comment(first.trim_end(), self.tab_width));\n                        }\n                        res.push(\" */\".to_string());\n                    } else {\n                        res.push(format_doc_block_comment(line.trim_end(), self.tab_width));\n                    }\n                }\n            } else {\n                res.push(line.to_string());\n            }\n        }\n\n        for (pos, line) in lines.delimited() {\n            let line = normalize_block_comment_ws(line, col).trim_end().to_string();\n            if !is_doc {\n                res.push(line);\n                continue;\n            }\n            if !pos.is_last {\n                res.push(format_doc_block_comment(&line, self.tab_width));\n            } else {\n                // Ensure last line of a doc comment only has the `*/` decorator\n                if let Some((first, _)) = line.split_once(\"*/\")\n                    && !first.trim().is_empty()\n                {\n                    res.push(format_doc_block_comment(first.trim_end(), self.tab_width));\n                }\n                res.push(\" */\".to_string());\n            }\n        }\n        res\n    }\n}\n\n/// Returns `None` if the first `col` chars of `s` contain a non-whitespace char.\n/// Otherwise returns `Some(k)` where `k` is first char offset after that leading\n/// whitespace. Note that `k` may be outside bounds of `s`.\nfn all_whitespace(s: &str, col: CharPos) -> Option<usize> {\n    let mut idx = 0;\n    for (i, ch) in s.char_indices().take(col.to_usize()) {\n        if !ch.is_whitespace() {\n            return None;\n        }\n        idx = i + ch.len_utf8();\n    }\n    Some(idx)\n}\n\n/// Returns `Some(k)` where `k` is the byte offset of the first non-whitespace char. Returns `k = 0`\n/// if `s` starts with a non-whitespace char. If `s` only contains whitespaces, returns `None`.\nfn first_non_whitespace(s: &str) -> Option<usize> {\n    let mut len = 0;\n    for (i, ch) in s.char_indices() {\n        if ch.is_whitespace() {\n            len = ch.len_utf8()\n        } else {\n            return if i == 0 { Some(0) } else { Some(i + 1 - len) };\n        }\n    }\n    None\n}\n\n/// Returns a slice of `s` with a whitespace prefix removed based on `col`. If the first `col` chars\n/// of `s` are all whitespace, returns a slice starting after that prefix.\nfn normalize_block_comment_ws(s: &str, col: CharPos) -> &str {\n    let len = s.len();\n    if let Some(col) = all_whitespace(s, col) {\n        return if col < len { &s[col..] } else { \"\" };\n    }\n    if let Some(col) = first_non_whitespace(s) {\n        return &s[col..];\n    }\n    s\n}\n\n/// Formats a doc block comment line so that they have the ` *` decorator.\nfn format_doc_block_comment(line: &str, tab_width: Option<usize>) -> String {\n    if line.is_empty() {\n        return (\" *\").to_string();\n    }\n\n    if let Some((_, rest_of_line)) = line.split_once(\"*\") {\n        if rest_of_line.is_empty() {\n            (\" *\").to_string()\n        } else if let Some(tab_width) = tab_width {\n            let mut normalized = String::from(\" *\");\n            line_with_tabs(\n                &mut normalized,\n                rest_of_line,\n                tab_width,\n                Some(Consolidation::MinOneTab),\n            );\n            normalized\n        } else {\n            format!(\" *{rest_of_line}\",)\n        }\n    } else if let Some(tab_width) = tab_width {\n        let mut normalized = String::from(\" *\\t\");\n        line_with_tabs(&mut normalized, line, tab_width, Some(Consolidation::WithoutSpaces));\n        normalized\n    } else {\n        format!(\" * {line}\")\n    }\n}\n\npub enum Consolidation {\n    MinOneTab,\n    WithoutSpaces,\n}\n\n/// Normalizes the leading whitespace of a string slice according to a given tab width.\n///\n/// It aggregates and converts leading whitespace (spaces and tabs) into a representation that\n/// maximizes the amount of tabs.\npub fn line_with_tabs(\n    output: &mut String,\n    line: &str,\n    tab_width: usize,\n    strategy: Option<Consolidation>,\n) {\n    // Find the end of the leading whitespace (any sequence of spaces and tabs)\n    let first_non_ws = line.find(|c| c != ' ' && c != '\\t').unwrap_or(line.len());\n    let (leading_ws, rest_of_line) = line.split_at(first_non_ws);\n\n    // Compute its equivalent length and derive the required amount of tabs and spaces\n    let total_width =\n        leading_ws.chars().fold(0, |width, c| width + if c == ' ' { 1 } else { tab_width });\n    let (mut num_tabs, mut num_spaces) = (total_width / tab_width, total_width % tab_width);\n\n    // Adjust based on the desired config\n    match strategy {\n        Some(Consolidation::MinOneTab) => {\n            if num_tabs == 0 && num_spaces != 0 {\n                (num_tabs, num_spaces) = (1, 0);\n            } else if num_spaces != 0 {\n                (num_tabs, num_spaces) = (num_tabs + 1, 0);\n            }\n        }\n        Some(Consolidation::WithoutSpaces) if num_spaces != 0 => {\n            (num_tabs, num_spaces) = (num_tabs + 1, 0);\n        }\n        _ => (),\n    };\n\n    // Append the normalized indentation and the rest of the line to the output\n    output.extend(std::iter::repeat_n('\\t', num_tabs));\n    output.extend(std::iter::repeat_n(' ', num_spaces));\n    output.push_str(rest_of_line);\n}\n\n/// Estimates the display width of a string, accounting for tabs.\npub fn estimate_line_width(line: &str, tab_width: usize) -> usize {\n    line.chars().fold(0, |width, c| width + if c == '\\t' { tab_width } else { 1 })\n}\n\n/// Returns the `BytePos` of the beginning of the current line.\nfn line_begin_pos(sf: &SourceFile, pos: BytePos) -> BytePos {\n    let pos = sf.relative_position(pos);\n    let line_index = sf.lookup_line(pos).unwrap();\n    let line_start_pos = sf.lines()[line_index];\n    sf.absolute_position(line_start_pos)\n}\n"
  },
  {
    "path": "crates/common/src/compile.rs",
    "content": "//! Support for compiling [foundry_compilers::Project]\n\nuse crate::{\n    TestFunctionExt, preprocessor::DynamicTestLinkingPreprocessor, shell, term::SpinnerReporter,\n};\nuse comfy_table::{Cell, Color, Table, modifiers::UTF8_ROUND_CORNERS, presets::ASCII_MARKDOWN};\nuse eyre::Result;\nuse foundry_block_explorers::contract::Metadata;\nuse foundry_compilers::{\n    Artifact, Project, ProjectBuilder, ProjectCompileOutput, ProjectPathsConfig, SolcConfig,\n    artifacts::{BytecodeObject, Contract, Source, remappings::Remapping},\n    compilers::{\n        Compiler,\n        solc::{Solc, SolcCompiler},\n    },\n    info::ContractInfo as CompilerContractInfo,\n    multi::{MultiCompiler, MultiCompilerSettings},\n    project::Preprocessor,\n    report::{BasicStdoutReporter, NoReporter, Report},\n    solc::SolcSettings,\n};\nuse num_format::{Locale, ToFormattedString};\nuse std::{\n    collections::BTreeMap,\n    fmt::Display,\n    io::IsTerminal,\n    path::{Path, PathBuf},\n    str::FromStr,\n    sync::Arc,\n    time::Instant,\n};\n\n/// A Solar compiler instance, to grant syntactic and semantic analysis capabilities.\npub type Analysis = Arc<solar::sema::Compiler>;\n\n/// Builder type to configure how to compile a project.\n///\n/// This is merely a wrapper for [`Project::compile()`] which also prints to stdout depending on its\n/// settings.\n#[must_use = \"ProjectCompiler does nothing unless you call a `compile*` method\"]\npub struct ProjectCompiler {\n    /// The root of the project.\n    project_root: PathBuf,\n\n    /// Whether to also print contract names.\n    print_names: Option<bool>,\n\n    /// Whether to also print contract sizes.\n    print_sizes: Option<bool>,\n\n    /// Whether to print anything at all. Overrides other `print` options.\n    quiet: Option<bool>,\n\n    /// Whether to bail on compiler errors.\n    bail: Option<bool>,\n\n    /// Whether to ignore the contract initcode size limit introduced by EIP-3860.\n    ignore_eip_3860: bool,\n\n    /// Extra files to include, that are not necessarily in the project's source directory.\n    files: Vec<PathBuf>,\n\n    /// Whether to compile with dynamic linking tests and scripts.\n    dynamic_test_linking: bool,\n}\n\nimpl Default for ProjectCompiler {\n    #[inline]\n    fn default() -> Self {\n        Self::new()\n    }\n}\n\nimpl ProjectCompiler {\n    /// Create a new builder with the default settings.\n    #[inline]\n    pub fn new() -> Self {\n        Self {\n            project_root: PathBuf::new(),\n            print_names: None,\n            print_sizes: None,\n            quiet: Some(crate::shell::is_quiet()),\n            bail: None,\n            ignore_eip_3860: false,\n            files: Vec::new(),\n            dynamic_test_linking: false,\n        }\n    }\n\n    /// Sets whether to print contract names.\n    #[inline]\n    pub fn print_names(mut self, yes: bool) -> Self {\n        self.print_names = Some(yes);\n        self\n    }\n\n    /// Sets whether to print contract sizes.\n    #[inline]\n    pub fn print_sizes(mut self, yes: bool) -> Self {\n        self.print_sizes = Some(yes);\n        self\n    }\n\n    /// Sets whether to print anything at all. Overrides other `print` options.\n    #[inline]\n    #[doc(alias = \"silent\")]\n    pub fn quiet(mut self, yes: bool) -> Self {\n        self.quiet = Some(yes);\n        self\n    }\n\n    /// Sets whether to bail on compiler errors.\n    #[inline]\n    pub fn bail(mut self, yes: bool) -> Self {\n        self.bail = Some(yes);\n        self\n    }\n\n    /// Sets whether to ignore EIP-3860 initcode size limits.\n    #[inline]\n    pub fn ignore_eip_3860(mut self, yes: bool) -> Self {\n        self.ignore_eip_3860 = yes;\n        self\n    }\n\n    /// Sets extra files to include, that are not necessarily in the project's source dir.\n    #[inline]\n    pub fn files(mut self, files: impl IntoIterator<Item = PathBuf>) -> Self {\n        self.files.extend(files);\n        self\n    }\n\n    /// Sets if tests should be dynamically linked.\n    #[inline]\n    pub fn dynamic_test_linking(mut self, preprocess: bool) -> Self {\n        self.dynamic_test_linking = preprocess;\n        self\n    }\n\n    /// Compiles the project.\n    #[instrument(target = \"forge::compile\", skip_all)]\n    pub fn compile<C: Compiler<CompilerContract = Contract>>(\n        mut self,\n        project: &Project<C>,\n    ) -> Result<ProjectCompileOutput<C>>\n    where\n        DynamicTestLinkingPreprocessor: Preprocessor<C>,\n    {\n        self.project_root = project.root().to_path_buf();\n\n        // TODO: Avoid using std::process::exit(0).\n        // Replacing this with a return (e.g., Ok(ProjectCompileOutput::default())) would be more\n        // idiomatic, but it currently requires a `Default` bound on `C::Language`, which\n        // breaks compatibility with downstream crates like `foundry-cli`. This would need a\n        // broader refactor across the call chain. Leaving it as-is for now until a larger\n        // refactor is feasible.\n        if !project.paths.has_input_files() && self.files.is_empty() {\n            sh_println!(\"Nothing to compile\")?;\n            std::process::exit(0);\n        }\n\n        // Taking is fine since we don't need these in `compile_with`.\n        let files = std::mem::take(&mut self.files);\n        let preprocess = self.dynamic_test_linking;\n        self.compile_with(|| {\n            let sources = if !files.is_empty() {\n                Source::read_all(files)?\n            } else {\n                project.paths.read_input_files()?\n            };\n\n            let mut compiler =\n                foundry_compilers::project::ProjectCompiler::with_sources(project, sources)?;\n            if preprocess {\n                compiler = compiler.with_preprocessor(DynamicTestLinkingPreprocessor);\n            }\n            compiler.compile().map_err(Into::into)\n        })\n    }\n\n    /// Compiles the project with the given closure\n    fn compile_with<C: Compiler<CompilerContract = Contract>, F>(\n        self,\n        f: F,\n    ) -> Result<ProjectCompileOutput<C>>\n    where\n        F: FnOnce() -> Result<ProjectCompileOutput<C>>,\n    {\n        let quiet = self.quiet.unwrap_or(false);\n        let bail = self.bail.unwrap_or(true);\n\n        let output = with_compilation_reporter(quiet, Some(self.project_root.clone()), || {\n            tracing::debug!(\"compiling project\");\n\n            let timer = Instant::now();\n            let r = f();\n            let elapsed = timer.elapsed();\n\n            tracing::debug!(\"finished compiling in {:.3}s\", elapsed.as_secs_f64());\n            r\n        })?;\n\n        if bail && output.has_compiler_errors() {\n            eyre::bail!(\"{output}\")\n        }\n\n        if !quiet {\n            if !shell::is_json() {\n                if output.is_unchanged() {\n                    sh_println!(\"No files changed, compilation skipped\")?;\n                } else {\n                    // print the compiler output / warnings\n                    sh_println!(\"{output}\")?;\n                }\n            }\n\n            self.handle_output(&output)?;\n        }\n\n        Ok(output)\n    }\n\n    /// If configured, this will print sizes or names\n    fn handle_output<C: Compiler<CompilerContract = Contract>>(\n        &self,\n        output: &ProjectCompileOutput<C>,\n    ) -> Result<()> {\n        let print_names = self.print_names.unwrap_or(false);\n        let print_sizes = self.print_sizes.unwrap_or(false);\n\n        // print any sizes or names\n        if print_names {\n            let mut artifacts: BTreeMap<_, Vec<_>> = BTreeMap::new();\n            for (name, (_, version)) in output.versioned_artifacts() {\n                artifacts.entry(version).or_default().push(name);\n            }\n\n            if shell::is_json() {\n                sh_println!(\"{}\", serde_json::to_string(&artifacts).unwrap())?;\n            } else {\n                for (version, names) in artifacts {\n                    sh_println!(\n                        \"  compiler version: {}.{}.{}\",\n                        version.major,\n                        version.minor,\n                        version.patch\n                    )?;\n                    for name in names {\n                        sh_println!(\"    - {name}\")?;\n                    }\n                }\n            }\n        }\n\n        if print_sizes {\n            // add extra newline if names were already printed\n            if print_names && !shell::is_json() {\n                sh_println!()?;\n            }\n\n            let mut size_report = SizeReport { contracts: BTreeMap::new() };\n\n            let mut artifacts: BTreeMap<String, Vec<_>> = BTreeMap::new();\n            for (id, artifact) in output.artifact_ids().filter(|(id, _)| {\n                // filter out forge-std specific contracts\n                !id.source.to_string_lossy().contains(\"/forge-std/src/\")\n            }) {\n                artifacts.entry(id.name.clone()).or_default().push((id.source.clone(), artifact));\n            }\n\n            for (name, artifact_list) in artifacts {\n                for (path, artifact) in &artifact_list {\n                    let runtime_size = contract_size(*artifact, false).unwrap_or_default();\n                    let init_size = contract_size(*artifact, true).unwrap_or_default();\n\n                    let is_dev_contract = artifact\n                        .abi\n                        .as_ref()\n                        .map(|abi| {\n                            abi.functions().any(|f| {\n                                f.test_function_kind().is_known()\n                                    || matches!(f.name.as_str(), \"IS_TEST\" | \"IS_SCRIPT\")\n                            })\n                        })\n                        .unwrap_or(false);\n\n                    let unique_name = if artifact_list.len() > 1 {\n                        format!(\n                            \"{} ({})\",\n                            name,\n                            path.strip_prefix(&self.project_root).unwrap_or(path).display()\n                        )\n                    } else {\n                        name.clone()\n                    };\n\n                    size_report.contracts.insert(\n                        unique_name,\n                        ContractInfo { runtime_size, init_size, is_dev_contract },\n                    );\n                }\n            }\n\n            sh_println!(\"{size_report}\")?;\n\n            eyre::ensure!(\n                !size_report.exceeds_runtime_size_limit(),\n                \"some contracts exceed the runtime size limit \\\n                 (EIP-170: {CONTRACT_RUNTIME_SIZE_LIMIT} bytes)\"\n            );\n            // Check size limits only if not ignoring EIP-3860\n            eyre::ensure!(\n                self.ignore_eip_3860 || !size_report.exceeds_initcode_size_limit(),\n                \"some contracts exceed the initcode size limit \\\n                 (EIP-3860: {CONTRACT_INITCODE_SIZE_LIMIT} bytes)\"\n            );\n        }\n\n        Ok(())\n    }\n}\n\n// https://eips.ethereum.org/EIPS/eip-170\nconst CONTRACT_RUNTIME_SIZE_LIMIT: usize = 24576;\n\n// https://eips.ethereum.org/EIPS/eip-3860\nconst CONTRACT_INITCODE_SIZE_LIMIT: usize = 49152;\n\n/// Contracts with info about their size\npub struct SizeReport {\n    /// `contract name -> info`\n    pub contracts: BTreeMap<String, ContractInfo>,\n}\n\nimpl SizeReport {\n    /// Returns the maximum runtime code size, excluding dev contracts.\n    pub fn max_runtime_size(&self) -> usize {\n        self.contracts\n            .values()\n            .filter(|c| !c.is_dev_contract)\n            .map(|c| c.runtime_size)\n            .max()\n            .unwrap_or(0)\n    }\n\n    /// Returns the maximum initcode size, excluding dev contracts.\n    pub fn max_init_size(&self) -> usize {\n        self.contracts\n            .values()\n            .filter(|c| !c.is_dev_contract)\n            .map(|c| c.init_size)\n            .max()\n            .unwrap_or(0)\n    }\n\n    /// Returns true if any contract exceeds the runtime size limit, excluding dev contracts.\n    pub fn exceeds_runtime_size_limit(&self) -> bool {\n        self.max_runtime_size() > CONTRACT_RUNTIME_SIZE_LIMIT\n    }\n\n    /// Returns true if any contract exceeds the initcode size limit, excluding dev contracts.\n    pub fn exceeds_initcode_size_limit(&self) -> bool {\n        self.max_init_size() > CONTRACT_INITCODE_SIZE_LIMIT\n    }\n}\n\nimpl Display for SizeReport {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {\n        if shell::is_json() {\n            writeln!(f, \"{}\", self.format_json_output())?;\n        } else {\n            writeln!(f, \"\\n{}\", self.format_table_output())?;\n        }\n        Ok(())\n    }\n}\n\nimpl SizeReport {\n    fn format_json_output(&self) -> String {\n        let contracts = self\n            .contracts\n            .iter()\n            .filter(|(_, c)| !c.is_dev_contract && (c.runtime_size > 0 || c.init_size > 0))\n            .map(|(name, contract)| {\n                (\n                    name.clone(),\n                    serde_json::json!({\n                        \"runtime_size\": contract.runtime_size,\n                        \"init_size\": contract.init_size,\n                        \"runtime_margin\": CONTRACT_RUNTIME_SIZE_LIMIT as isize - contract.runtime_size as isize,\n                        \"init_margin\": CONTRACT_INITCODE_SIZE_LIMIT as isize - contract.init_size as isize,\n                    }),\n                )\n            })\n            .collect::<serde_json::Map<_, _>>();\n\n        serde_json::to_string(&contracts).unwrap()\n    }\n\n    fn format_table_output(&self) -> Table {\n        let mut table = Table::new();\n        if shell::is_markdown() {\n            table.load_preset(ASCII_MARKDOWN);\n        } else {\n            table.apply_modifier(UTF8_ROUND_CORNERS);\n        }\n\n        table.set_header(vec![\n            Cell::new(\"Contract\"),\n            Cell::new(\"Runtime Size (B)\"),\n            Cell::new(\"Initcode Size (B)\"),\n            Cell::new(\"Runtime Margin (B)\"),\n            Cell::new(\"Initcode Margin (B)\"),\n        ]);\n\n        // Filters out dev contracts (Test or Script)\n        let contracts = self\n            .contracts\n            .iter()\n            .filter(|(_, c)| !c.is_dev_contract && (c.runtime_size > 0 || c.init_size > 0));\n        for (name, contract) in contracts {\n            let runtime_margin =\n                CONTRACT_RUNTIME_SIZE_LIMIT as isize - contract.runtime_size as isize;\n            let init_margin = CONTRACT_INITCODE_SIZE_LIMIT as isize - contract.init_size as isize;\n\n            let runtime_color = match contract.runtime_size {\n                ..18_000 => Color::Reset,\n                18_000..=CONTRACT_RUNTIME_SIZE_LIMIT => Color::Yellow,\n                _ => Color::Red,\n            };\n\n            let init_color = match contract.init_size {\n                ..36_000 => Color::Reset,\n                36_000..=CONTRACT_INITCODE_SIZE_LIMIT => Color::Yellow,\n                _ => Color::Red,\n            };\n\n            let locale = &Locale::en;\n            table.add_row([\n                Cell::new(name),\n                Cell::new(contract.runtime_size.to_formatted_string(locale)).fg(runtime_color),\n                Cell::new(contract.init_size.to_formatted_string(locale)).fg(init_color),\n                Cell::new(runtime_margin.to_formatted_string(locale)).fg(runtime_color),\n                Cell::new(init_margin.to_formatted_string(locale)).fg(init_color),\n            ]);\n        }\n\n        table\n    }\n}\n\n/// Returns the deployed or init size of the contract.\nfn contract_size<T: Artifact>(artifact: &T, initcode: bool) -> Option<usize> {\n    let bytecode = if initcode {\n        artifact.get_bytecode_object()?\n    } else {\n        artifact.get_deployed_bytecode_object()?\n    };\n\n    let size = match bytecode.as_ref() {\n        BytecodeObject::Bytecode(bytes) => bytes.len(),\n        BytecodeObject::Unlinked(unlinked) => {\n            // we don't need to account for placeholders here, because library placeholders take up\n            // 40 characters: `__$<library hash>$__` which is the same as a 20byte address in hex.\n            let mut size = unlinked.len();\n            if unlinked.starts_with(\"0x\") {\n                size -= 2;\n            }\n            // hex -> bytes\n            size / 2\n        }\n    };\n\n    Some(size)\n}\n\n/// How big the contract is and whether it is a dev contract where size limits can be neglected\n#[derive(Clone, Copy, Debug)]\npub struct ContractInfo {\n    /// Size of the runtime code in bytes\n    pub runtime_size: usize,\n    /// Size of the initcode in bytes\n    pub init_size: usize,\n    /// A development contract is either a Script or a Test contract.\n    pub is_dev_contract: bool,\n}\n\n/// Compiles target file path.\n///\n/// If `quiet` no solc related output will be emitted to stdout.\n///\n/// **Note:** this expects the `target_path` to be absolute\npub fn compile_target<C: Compiler<CompilerContract = Contract>>(\n    target_path: &Path,\n    project: &Project<C>,\n    quiet: bool,\n) -> Result<ProjectCompileOutput<C>>\nwhere\n    DynamicTestLinkingPreprocessor: Preprocessor<C>,\n{\n    ProjectCompiler::new().quiet(quiet).files([target_path.into()]).compile(project)\n}\n\n/// Creates a [Project] from an Etherscan source.\npub fn etherscan_project(metadata: &Metadata, target_path: &Path) -> Result<Project> {\n    let target_path = dunce::canonicalize(target_path)?;\n    let sources_path = target_path.join(&metadata.contract_name);\n    metadata.source_tree().write_to(&target_path)?;\n\n    let mut settings = metadata.settings()?;\n\n    // make remappings absolute with our root\n    for remapping in &mut settings.remappings {\n        let new_path = sources_path.join(remapping.path.trim_start_matches('/'));\n        remapping.path = new_path.display().to_string();\n    }\n\n    // add missing remappings\n    if !settings.remappings.iter().any(|remapping| remapping.name.starts_with(\"@openzeppelin/\")) {\n        let oz = Remapping {\n            context: None,\n            name: \"@openzeppelin/\".into(),\n            path: sources_path.join(\"@openzeppelin\").display().to_string(),\n        };\n        settings.remappings.push(oz);\n    }\n\n    // root/\n    //   ContractName/\n    //     [source code]\n    let paths = ProjectPathsConfig::builder()\n        .sources(sources_path.clone())\n        .remappings(settings.remappings.clone())\n        .build_with_root(sources_path);\n\n    // TODO: detect vyper\n    let v = metadata.compiler_version()?;\n    let solc = Solc::find_or_install(&v)?;\n\n    let compiler = MultiCompiler { solc: Some(SolcCompiler::Specific(solc)), vyper: None };\n\n    Ok(ProjectBuilder::<MultiCompiler>::default()\n        .settings(MultiCompilerSettings {\n            solc: SolcSettings {\n                settings: SolcConfig::builder().settings(settings).build(),\n                ..Default::default()\n            },\n            ..Default::default()\n        })\n        .paths(paths)\n        .ephemeral()\n        .no_artifacts()\n        .build(compiler)?)\n}\n\n/// Configures the reporter and runs the given closure.\npub fn with_compilation_reporter<O>(\n    quiet: bool,\n    project_root: Option<PathBuf>,\n    f: impl FnOnce() -> O,\n) -> O {\n    #[expect(clippy::collapsible_else_if)]\n    let reporter = if quiet || shell::is_json() {\n        Report::new(NoReporter::default())\n    } else {\n        if std::io::stdout().is_terminal() {\n            Report::new(SpinnerReporter::spawn(project_root))\n        } else {\n            Report::new(BasicStdoutReporter::default())\n        }\n    };\n\n    foundry_compilers::report::with_scoped(&reporter, f)\n}\n\n/// Container type for parsing contract identifiers from CLI.\n///\n/// Passed string can be of the following forms:\n/// - `src/Counter.sol` - path to the contract file, in the case where it only contains one contract\n/// - `src/Counter.sol:Counter` - path to the contract file and the contract name\n/// - `Counter` - contract name only\n#[derive(Clone, PartialEq, Eq)]\npub enum PathOrContractInfo {\n    /// Non-canonicalized path provided via CLI.\n    Path(PathBuf),\n    /// Contract info provided via CLI.\n    ContractInfo(CompilerContractInfo),\n}\n\nimpl PathOrContractInfo {\n    /// Returns the path to the contract file if provided.\n    pub fn path(&self) -> Option<PathBuf> {\n        match self {\n            Self::Path(path) => Some(path.to_path_buf()),\n            Self::ContractInfo(info) => info.path.as_ref().map(PathBuf::from),\n        }\n    }\n\n    /// Returns the contract name if provided.\n    pub fn name(&self) -> Option<&str> {\n        match self {\n            Self::Path(_) => None,\n            Self::ContractInfo(info) => Some(&info.name),\n        }\n    }\n}\n\nimpl FromStr for PathOrContractInfo {\n    type Err = eyre::Error;\n\n    fn from_str(s: &str) -> Result<Self> {\n        if let Ok(contract) = CompilerContractInfo::from_str(s) {\n            return Ok(Self::ContractInfo(contract));\n        }\n        let path = PathBuf::from(s);\n        if path.extension().is_some_and(|ext| ext == \"sol\" || ext == \"vy\") {\n            return Ok(Self::Path(path));\n        }\n        Err(eyre::eyre!(\"Invalid contract identifier, file is not *.sol or *.vy: {}\", s))\n    }\n}\n\nimpl std::fmt::Debug for PathOrContractInfo {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        match self {\n            Self::Path(path) => write!(f, \"Path({})\", path.display()),\n            Self::ContractInfo(info) => {\n                write!(f, \"ContractInfo({info})\")\n            }\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn parse_contract_identifiers() {\n        let t = [\"src/Counter.sol\", \"src/Counter.sol:Counter\", \"Counter\"];\n\n        let i1 = PathOrContractInfo::from_str(t[0]).unwrap();\n        assert_eq!(i1, PathOrContractInfo::Path(PathBuf::from(t[0])));\n\n        let i2 = PathOrContractInfo::from_str(t[1]).unwrap();\n        assert_eq!(\n            i2,\n            PathOrContractInfo::ContractInfo(CompilerContractInfo {\n                path: Some(\"src/Counter.sol\".to_string()),\n                name: \"Counter\".to_string()\n            })\n        );\n\n        let i3 = PathOrContractInfo::from_str(t[2]).unwrap();\n        assert_eq!(\n            i3,\n            PathOrContractInfo::ContractInfo(CompilerContractInfo {\n                path: None,\n                name: \"Counter\".to_string()\n            })\n        );\n    }\n}\n"
  },
  {
    "path": "crates/common/src/constants.rs",
    "content": "//! Commonly used constants.\n\nuse alloy_eips::Typed2718;\nuse alloy_network::AnyTxEnvelope;\nuse alloy_primitives::{Address, B256, Signature, address};\nuse std::time::Duration;\n\n/// The dev chain-id, inherited from hardhat\npub const DEV_CHAIN_ID: u64 = 31337;\n\n/// The first four bytes of the call data for a function call specifies the function to be called.\npub const SELECTOR_LEN: usize = 4;\n\n/// Maximum size in bytes (0x6000) that a contract can have.\npub const CONTRACT_MAX_SIZE: usize = 24576;\n\n/// Default request timeout for http requests\n///\n/// Note: this is only used so that connections, that are discarded on the server side won't stay\n/// open forever. We assume some nodes may have some backoff baked into them and will delay some\n/// responses. This timeout should be a reasonable amount of time to wait for a request.\npub const REQUEST_TIMEOUT: Duration = Duration::from_secs(45);\n\n/// Alchemy free tier cups: <https://docs.alchemy.com/reference/pricing-plans>\npub const ALCHEMY_FREE_TIER_CUPS: u64 = 330;\n\n/// Logged when an error is indicative that the user is trying to fork from a non-archive node.\npub const NON_ARCHIVE_NODE_WARNING: &str = \"\\\nIt looks like you're trying to fork from an older block with a non-archive node which is not \\\nsupported. Please try to change your RPC url to an archive node if the issue persists.\";\n\n/// Arbitrum L1 sender address of the first transaction in every block.\n/// `0x00000000000000000000000000000000000a4b05`\npub const ARBITRUM_SENDER: Address = address!(\"0x00000000000000000000000000000000000a4b05\");\n\n/// The system address, the sender of the first transaction in every block:\n/// `0xdeaddeaddeaddeaddeaddeaddeaddeaddead0001`\n///\n/// See also <https://github.com/ethereum-optimism/optimism/blob/65ec61dde94ffa93342728d324fecf474d228e1f/specs/deposits.md#l1-attributes-deposited-transaction>\npub const OPTIMISM_SYSTEM_ADDRESS: Address = address!(\"0xdeaddeaddeaddeaddeaddeaddeaddeaddead0001\");\n\n/// The system address, the sender of the first transaction in every block:\npub const MONAD_SYSTEM_ADDRESS: Address = address!(\"0x6f49a8F621353f12378d0046E7d7e4b9B249DC9e\");\n\n/// Transaction identifier of System transaction types\npub const SYSTEM_TRANSACTION_TYPE: u8 = 126;\n\n/// Default user agent set as the header for requests that don't specify one.\npub const DEFAULT_USER_AGENT: &str = concat!(\"foundry/\", env!(\"CARGO_PKG_VERSION\"));\n\n/// Prefix for auto-generated type bindings using `forge bind-json`.\npub const TYPE_BINDING_PREFIX: &str = \"string constant schema_\";\n\n/// Returns whether the sender is a known L2 system sender that is the first tx in every block.\n///\n/// Transactions from these senders usually don't have a any fee information OR set absurdly high fees that exceed the gas limit (See: <https://github.com/foundry-rs/foundry/pull/10608>)\n///\n/// See: [ARBITRUM_SENDER], [OPTIMISM_SYSTEM_ADDRESS], [MONAD_SYSTEM_ADDRESS] and [Address::ZERO]\npub fn is_known_system_sender(sender: Address) -> bool {\n    [ARBITRUM_SENDER, OPTIMISM_SYSTEM_ADDRESS, MONAD_SYSTEM_ADDRESS, Address::ZERO]\n        .contains(&sender)\n}\n\npub fn is_impersonated_tx(tx: &AnyTxEnvelope) -> bool {\n    if let AnyTxEnvelope::Ethereum(tx) = tx {\n        return is_impersonated_sig(tx.signature(), tx.ty());\n    }\n    false\n}\n\npub fn is_impersonated_sig(sig: &Signature, ty: u8) -> bool {\n    let impersonated_sig =\n        Signature::from_scalars_and_parity(B256::with_last_byte(1), B256::with_last_byte(1), false);\n    if ty != SYSTEM_TRANSACTION_TYPE\n        && (sig == &impersonated_sig || sig.r() == impersonated_sig.r())\n    {\n        return true;\n    }\n    false\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_constant_sender() {\n        let arb = address!(\"0x00000000000000000000000000000000000a4b05\");\n        assert_eq!(arb, ARBITRUM_SENDER);\n        let base = address!(\"0xdeaddeaddeaddeaddeaddeaddeaddeaddead0001\");\n        assert_eq!(base, OPTIMISM_SYSTEM_ADDRESS);\n    }\n}\n"
  },
  {
    "path": "crates/common/src/contracts.rs",
    "content": "//! Commonly used contract types and functions.\n\nuse crate::{compile::PathOrContractInfo, find_metadata_start, strip_bytecode_placeholders};\nuse alloy_dyn_abi::JsonAbiExt;\nuse alloy_json_abi::{Event, Function, JsonAbi};\nuse alloy_primitives::{Address, B256, Bytes, Selector, hex};\nuse eyre::{OptionExt, Result};\nuse foundry_compilers::{\n    ArtifactId, Project, ProjectCompileOutput,\n    artifacts::{\n        BytecodeObject, CompactBytecode, CompactContractBytecode, CompactContractBytecodeCow,\n        CompactDeployedBytecode, ConfigurableContractArtifact, ContractBytecodeSome, Offsets,\n        StorageLayout,\n    },\n    utils::canonicalized,\n};\nuse std::{\n    collections::BTreeMap,\n    ops::Deref,\n    path::{Path, PathBuf},\n    str::FromStr,\n    sync::Arc,\n};\n\n/// Libraries' runtime code always starts with the following instruction:\n/// `PUSH20 0x0000000000000000000000000000000000000000`\n///\n/// See: <https://docs.soliditylang.org/en/latest/contracts.html#call-protection-for-libraries>\nconst CALL_PROTECTION_BYTECODE_PREFIX: [u8; 21] =\n    hex!(\"730000000000000000000000000000000000000000\");\n\n/// Subset of [CompactBytecode] excluding sourcemaps.\n#[expect(missing_docs)]\n#[derive(Debug, Clone)]\npub struct BytecodeData {\n    pub object: Option<BytecodeObject>,\n    pub link_references: BTreeMap<String, BTreeMap<String, Vec<Offsets>>>,\n    pub immutable_references: BTreeMap<String, Vec<Offsets>>,\n}\n\nimpl BytecodeData {\n    fn bytes(&self) -> Option<&Bytes> {\n        self.object.as_ref().and_then(|b| b.as_bytes())\n    }\n}\n\nimpl From<CompactBytecode> for BytecodeData {\n    fn from(bytecode: CompactBytecode) -> Self {\n        Self {\n            object: Some(bytecode.object),\n            link_references: bytecode.link_references,\n            immutable_references: BTreeMap::new(),\n        }\n    }\n}\n\nimpl From<CompactDeployedBytecode> for BytecodeData {\n    fn from(bytecode: CompactDeployedBytecode) -> Self {\n        let (object, link_references) = if let Some(compact) = bytecode.bytecode {\n            (Some(compact.object), compact.link_references)\n        } else {\n            (None, BTreeMap::new())\n        };\n        Self { object, link_references, immutable_references: bytecode.immutable_references }\n    }\n}\n\n/// Container for commonly used contract data.\n#[derive(Debug)]\npub struct ContractData {\n    /// Contract name.\n    pub name: String,\n    /// Contract ABI.\n    pub abi: JsonAbi,\n    /// Contract creation code.\n    pub bytecode: Option<BytecodeData>,\n    /// Contract runtime code.\n    pub deployed_bytecode: Option<BytecodeData>,\n    /// Contract storage layout, if available.\n    pub storage_layout: Option<Arc<StorageLayout>>,\n}\n\nimpl ContractData {\n    /// Returns reference to bytes of contract creation code, if present.\n    pub fn bytecode(&self) -> Option<&Bytes> {\n        self.bytecode.as_ref()?.bytes().filter(|b| !b.is_empty())\n    }\n\n    /// Returns reference to bytes of contract deployed code, if present.\n    pub fn deployed_bytecode(&self) -> Option<&Bytes> {\n        self.deployed_bytecode.as_ref()?.bytes().filter(|b| !b.is_empty())\n    }\n\n    /// Returns the bytecode without placeholders, if present.\n    pub fn bytecode_without_placeholders(&self) -> Option<Bytes> {\n        strip_bytecode_placeholders(self.bytecode.as_ref()?.object.as_ref()?)\n    }\n\n    /// Returns the deployed bytecode without placeholders, if present.\n    pub fn deployed_bytecode_without_placeholders(&self) -> Option<Bytes> {\n        strip_bytecode_placeholders(self.deployed_bytecode.as_ref()?.object.as_ref()?)\n    }\n}\n\n/// Builder for creating a `ContractsByArtifact` instance, optionally including storage layouts\n/// from project compile output.\npub struct ContractsByArtifactBuilder<'a> {\n    /// All compiled artifact bytecodes (borrowed).\n    artifacts: BTreeMap<ArtifactId, CompactContractBytecodeCow<'a>>,\n    /// Optionally collected storage layouts for matching artifact IDs.\n    storage_layouts: BTreeMap<ArtifactId, StorageLayout>,\n}\n\nimpl<'a> ContractsByArtifactBuilder<'a> {\n    /// Creates a new builder from artifacts with present bytecode iterator.\n    pub fn new(\n        artifacts: impl IntoIterator<Item = (ArtifactId, CompactContractBytecodeCow<'a>)>,\n    ) -> Self {\n        Self { artifacts: artifacts.into_iter().collect(), storage_layouts: BTreeMap::new() }\n    }\n\n    /// Add storage layouts from the given `ProjectCompileOutput` to known artifacts.\n    pub fn with_output(self, output: &ProjectCompileOutput, base: &Path) -> Self {\n        self.with_storage_layouts(output.artifact_ids().filter_map(|(id, artifact)| {\n            artifact\n                .storage_layout\n                .as_ref()\n                .map(|layout| (id.with_stripped_file_prefixes(base), layout.clone()))\n        }))\n    }\n\n    /// Add storage layouts.\n    pub fn with_storage_layouts(\n        mut self,\n        layouts: impl IntoIterator<Item = (ArtifactId, StorageLayout)>,\n    ) -> Self {\n        self.storage_layouts.extend(layouts);\n        self\n    }\n\n    /// Builds `ContractsByArtifact`.\n    pub fn build(self) -> ContractsByArtifact {\n        let map = self\n            .artifacts\n            .into_iter()\n            .filter_map(|(id, artifact)| {\n                let name = id.name.clone();\n                let CompactContractBytecodeCow { abi, bytecode, deployed_bytecode } = artifact;\n\n                Some((\n                    id.clone(),\n                    ContractData {\n                        name,\n                        abi: abi?.into_owned(),\n                        bytecode: bytecode.map(|b| b.into_owned().into()),\n                        deployed_bytecode: deployed_bytecode.map(|b| b.into_owned().into()),\n                        storage_layout: self.storage_layouts.get(&id).map(|l| Arc::new(l.clone())),\n                    },\n                ))\n            })\n            .collect();\n\n        ContractsByArtifact(Arc::new(map))\n    }\n}\n\ntype ArtifactWithContractRef<'a> = (&'a ArtifactId, &'a ContractData);\n\n/// Wrapper type that maps an artifact to a contract ABI and bytecode.\n#[derive(Clone, Default, Debug)]\npub struct ContractsByArtifact(Arc<BTreeMap<ArtifactId, ContractData>>);\n\nimpl ContractsByArtifact {\n    /// Creates a new instance by collecting all artifacts with present bytecode from an iterator.\n    pub fn new(artifacts: impl IntoIterator<Item = (ArtifactId, CompactContractBytecode)>) -> Self {\n        let map = artifacts\n            .into_iter()\n            .filter_map(|(id, artifact)| {\n                let name = id.name.clone();\n                let CompactContractBytecode { abi, bytecode, deployed_bytecode } = artifact;\n                Some((\n                    id,\n                    ContractData {\n                        name,\n                        abi: abi?,\n                        bytecode: bytecode.map(Into::into),\n                        deployed_bytecode: deployed_bytecode.map(Into::into),\n                        storage_layout: None,\n                    },\n                ))\n            })\n            .collect();\n        Self(Arc::new(map))\n    }\n\n    /// Clears all contracts.\n    pub fn clear(&mut self) {\n        *self = Self::default();\n    }\n\n    /// Finds a contract which has a similar bytecode as `code`.\n    pub fn find_by_creation_code(&self, code: &[u8]) -> Option<ArtifactWithContractRef<'_>> {\n        self.find_by_code(code, 0.1, true, ContractData::bytecode)\n    }\n\n    /// Finds a contract which has a similar deployed bytecode as `code`.\n    pub fn find_by_deployed_code(&self, code: &[u8]) -> Option<ArtifactWithContractRef<'_>> {\n        self.find_by_code(code, 0.15, false, ContractData::deployed_bytecode)\n    }\n\n    /// Finds a contract based on provided bytecode and accepted match score.\n    /// If strip constructor args flag is true then removes args from bytecode to compare.\n    fn find_by_code(\n        &self,\n        code: &[u8],\n        accepted_score: f64,\n        strip_ctor_args: bool,\n        get: impl Fn(&ContractData) -> Option<&Bytes>,\n    ) -> Option<ArtifactWithContractRef<'_>> {\n        self.iter()\n            .filter_map(|(id, contract)| {\n                if let Some(deployed_bytecode) = get(contract) {\n                    let mut code = code;\n                    if strip_ctor_args && code.len() > deployed_bytecode.len() {\n                        // Try to decode ctor args with contract abi.\n                        if let Some(constructor) = contract.abi.constructor() {\n                            let constructor_args = &code[deployed_bytecode.len()..];\n                            if constructor.abi_decode_input(constructor_args).is_ok() {\n                                // If we can decode args with current abi then remove args from\n                                // code to compare.\n                                code = &code[..deployed_bytecode.len()]\n                            }\n                        }\n                    };\n\n                    let score = bytecode_diff_score(deployed_bytecode.as_ref(), code);\n                    (score <= accepted_score).then_some((score, (id, contract)))\n                } else {\n                    None\n                }\n            })\n            .min_by(|(score1, _), (score2, _)| score1.total_cmp(score2))\n            .map(|(_, data)| data)\n    }\n\n    /// Finds a contract which deployed bytecode exactly matches the given code. Accounts for link\n    /// references and immutables.\n    pub fn find_by_deployed_code_exact(&self, code: &[u8]) -> Option<ArtifactWithContractRef<'_>> {\n        // Immediately return None if the code is empty.\n        if code.is_empty() {\n            return None;\n        }\n\n        let mut partial_match = None;\n        self.iter()\n            .find(|(id, contract)| {\n                let Some(deployed_bytecode) = &contract.deployed_bytecode else {\n                    return false;\n                };\n                let Some(deployed_code) = &deployed_bytecode.object else {\n                    return false;\n                };\n\n                let len = match deployed_code {\n                    BytecodeObject::Bytecode(bytes) => bytes.len(),\n                    BytecodeObject::Unlinked(bytes) => bytes.len() / 2,\n                };\n\n                if len != code.len() {\n                    return false;\n                }\n\n                // Collect ignored offsets by chaining link and immutable references.\n                let mut ignored = deployed_bytecode\n                    .immutable_references\n                    .values()\n                    .chain(deployed_bytecode.link_references.values().flat_map(|v| v.values()))\n                    .flatten()\n                    .cloned()\n                    .collect::<Vec<_>>();\n\n                // For libraries solidity adds a call protection prefix to the bytecode. We need to\n                // ignore it as it includes library address determined at runtime.\n                // See https://docs.soliditylang.org/en/latest/contracts.html#call-protection-for-libraries and\n                // https://github.com/NomicFoundation/hardhat/blob/af7807cf38842a4f56e7f4b966b806e39631568a/packages/hardhat-verify/src/internal/solc/bytecode.ts#L172\n                let has_call_protection = match deployed_code {\n                    BytecodeObject::Bytecode(bytes) => {\n                        bytes.starts_with(&CALL_PROTECTION_BYTECODE_PREFIX)\n                    }\n                    BytecodeObject::Unlinked(bytes) => {\n                        if let Ok(bytes) =\n                            Bytes::from_str(&bytes[..CALL_PROTECTION_BYTECODE_PREFIX.len() * 2])\n                        {\n                            bytes.starts_with(&CALL_PROTECTION_BYTECODE_PREFIX)\n                        } else {\n                            false\n                        }\n                    }\n                };\n\n                if has_call_protection {\n                    ignored.push(Offsets { start: 1, length: 20 });\n                }\n\n                let metadata_start = find_metadata_start(code);\n\n                if let Some(metadata) = metadata_start {\n                    ignored.push(Offsets {\n                        start: metadata as u32,\n                        length: (code.len() - metadata) as u32,\n                    });\n                }\n\n                ignored.sort_by_key(|o| o.start);\n\n                let mut left = 0;\n                for offset in ignored {\n                    let right = offset.start as usize;\n\n                    let matched = match deployed_code {\n                        BytecodeObject::Bytecode(bytes) => bytes[left..right] == code[left..right],\n                        BytecodeObject::Unlinked(bytes) => {\n                            if let Ok(bytes) = Bytes::from_str(&bytes[left * 2..right * 2]) {\n                                bytes == code[left..right]\n                            } else {\n                                false\n                            }\n                        }\n                    };\n\n                    if !matched {\n                        return false;\n                    }\n\n                    left = right + offset.length as usize;\n                }\n\n                let is_partial = if left < code.len() {\n                    match deployed_code {\n                        BytecodeObject::Bytecode(bytes) => bytes[left..] == code[left..],\n                        BytecodeObject::Unlinked(bytes) => {\n                            if let Ok(bytes) = Bytes::from_str(&bytes[left * 2..]) {\n                                bytes == code[left..]\n                            } else {\n                                false\n                            }\n                        }\n                    }\n                } else {\n                    true\n                };\n\n                if !is_partial {\n                    return false;\n                }\n\n                let Some(metadata) = metadata_start else { return true };\n\n                let exact_match = match deployed_code {\n                    BytecodeObject::Bytecode(bytes) => bytes[metadata..] == code[metadata..],\n                    BytecodeObject::Unlinked(bytes) => {\n                        if let Ok(bytes) = Bytes::from_str(&bytes[metadata * 2..]) {\n                            bytes == code[metadata..]\n                        } else {\n                            false\n                        }\n                    }\n                };\n\n                if exact_match {\n                    true\n                } else {\n                    partial_match = Some((*id, *contract));\n                    false\n                }\n            })\n            .or(partial_match)\n    }\n\n    /// Finds a contract which has the same contract name or identifier as `id`. If more than one is\n    /// found, return error.\n    pub fn find_by_name_or_identifier(\n        &self,\n        id: &str,\n    ) -> Result<Option<ArtifactWithContractRef<'_>>> {\n        let contracts = self\n            .iter()\n            .filter(|(artifact, _)| artifact.name == id || artifact.identifier() == id)\n            .collect::<Vec<_>>();\n\n        if contracts.len() > 1 {\n            eyre::bail!(\"{id} has more than one implementation.\");\n        }\n\n        Ok(contracts.first().copied())\n    }\n\n    /// Finds abi by name or source path\n    ///\n    /// Returns the abi and the contract name.\n    pub fn find_abi_by_name_or_src_path(&self, name_or_path: &str) -> Option<(JsonAbi, String)> {\n        self.iter()\n            .find(|(artifact, _)| {\n                artifact.name == name_or_path || artifact.source == Path::new(name_or_path)\n            })\n            .map(|(_, contract)| (contract.abi.clone(), contract.name.clone()))\n    }\n\n    /// Flattens the contracts into functions, events and errors.\n    pub fn flatten(&self) -> (BTreeMap<Selector, Function>, BTreeMap<B256, Event>, JsonAbi) {\n        let mut funcs = BTreeMap::new();\n        let mut events = BTreeMap::new();\n        let mut errors_abi = JsonAbi::new();\n        for (_name, contract) in self.iter() {\n            for func in contract.abi.functions() {\n                funcs.insert(func.selector(), func.clone());\n            }\n            for event in contract.abi.events() {\n                events.insert(event.selector(), event.clone());\n            }\n            for error in contract.abi.errors() {\n                errors_abi.errors.entry(error.name.clone()).or_default().push(error.clone());\n            }\n        }\n        (funcs, events, errors_abi)\n    }\n}\n\nimpl From<ProjectCompileOutput> for ContractsByArtifact {\n    fn from(value: ProjectCompileOutput) -> Self {\n        Self::new(value.into_artifacts().map(|(id, ar)| {\n            (\n                id,\n                CompactContractBytecode {\n                    abi: ar.abi,\n                    bytecode: ar.bytecode,\n                    deployed_bytecode: ar.deployed_bytecode,\n                },\n            )\n        }))\n    }\n}\n\nimpl Deref for ContractsByArtifact {\n    type Target = BTreeMap<ArtifactId, ContractData>;\n\n    fn deref(&self) -> &Self::Target {\n        &self.0\n    }\n}\n\n/// Wrapper type that maps an address to a contract identifier and contract ABI.\npub type ContractsByAddress = BTreeMap<Address, (String, JsonAbi)>;\n\n/// Very simple fuzzy matching of contract bytecode.\n///\n/// Returns a value between `0.0` (identical) and `1.0` (completely different).\npub fn bytecode_diff_score<'a>(mut a: &'a [u8], mut b: &'a [u8]) -> f64 {\n    // Make sure `a` is the longer one.\n    if a.len() < b.len() {\n        std::mem::swap(&mut a, &mut b);\n    }\n\n    // Account for different lengths.\n    let mut n_different_bytes = a.len() - b.len();\n\n    // If the difference is more than 32 bytes and more than 10% of the total length,\n    // we assume the bytecodes are completely different.\n    // This is a simple heuristic to avoid checking every byte when the lengths are very different.\n    // 32 is chosen to be a reasonable minimum as it's the size of metadata hashes and one EVM word.\n    if n_different_bytes > 32 && n_different_bytes * 10 > a.len() {\n        return 1.0;\n    }\n\n    // Count different bytes.\n    // SAFETY: `a` is longer than `b`.\n    n_different_bytes += unsafe { count_different_bytes(a, b) };\n\n    n_different_bytes as f64 / a.len() as f64\n}\n\n/// Returns the amount of different bytes between two slices.\n///\n/// # Safety\n///\n/// `a` must be at least as long as `b`.\nunsafe fn count_different_bytes(a: &[u8], b: &[u8]) -> usize {\n    // This could've been written as `std::iter::zip(a, b).filter(|(x, y)| x != y).count()`,\n    // however this function is very hot, and has been written to be as primitive as\n    // possible for lower optimization levels.\n\n    let a_ptr = a.as_ptr();\n    let b_ptr = b.as_ptr();\n    let len = b.len();\n\n    let mut sum = 0;\n    let mut i = 0;\n    while i < len {\n        // SAFETY: `a` is at least as long as `b`, and `i` is in bound of `b`.\n        sum += unsafe { *a_ptr.add(i) != *b_ptr.add(i) } as usize;\n        i += 1;\n    }\n    sum\n}\n\n/// Returns contract name for a given contract identifier.\n///\n/// Artifact/Contract identifier can take the following form:\n/// `<artifact file name>:<contract name>`, the `artifact file name` is the name of the json file of\n/// the contract's artifact and the contract name is the name of the solidity contract, like\n/// `SafeTransferLibTest.json:SafeTransferLibTest`\n///\n/// This returns the `contract name` part\n///\n/// # Example\n///\n/// ```\n/// use foundry_common::*;\n/// assert_eq!(\n///     \"SafeTransferLibTest\",\n///     get_contract_name(\"SafeTransferLibTest.json:SafeTransferLibTest\")\n/// );\n/// ```\npub fn get_contract_name(id: &str) -> &str {\n    id.rsplit(':').next().unwrap_or(id)\n}\n\n/// This returns the `file name` part, See [`get_contract_name`]\n///\n/// # Example\n///\n/// ```\n/// use foundry_common::*;\n/// assert_eq!(\n///     \"SafeTransferLibTest.json\",\n///     get_file_name(\"SafeTransferLibTest.json:SafeTransferLibTest\")\n/// );\n/// ```\npub fn get_file_name(id: &str) -> &str {\n    id.split(':').next().unwrap_or(id)\n}\n\n/// Helper function to convert CompactContractBytecode ~> ContractBytecodeSome\npub fn compact_to_contract(contract: CompactContractBytecode) -> Result<ContractBytecodeSome> {\n    Ok(ContractBytecodeSome {\n        abi: contract.abi.ok_or_else(|| eyre::eyre!(\"No contract abi\"))?,\n        bytecode: contract.bytecode.ok_or_else(|| eyre::eyre!(\"No contract bytecode\"))?.into(),\n        deployed_bytecode: contract\n            .deployed_bytecode\n            .ok_or_else(|| eyre::eyre!(\"No contract deployed bytecode\"))?\n            .into(),\n    })\n}\n\n/// Returns the canonicalized target path for the given identifier.\npub fn find_target_path(project: &Project, identifier: &PathOrContractInfo) -> Result<PathBuf> {\n    match identifier {\n        PathOrContractInfo::Path(path) => Ok(canonicalized(project.root().join(path))),\n        PathOrContractInfo::ContractInfo(info) => {\n            if let Some(path) = info.path.as_ref() {\n                let path = canonicalized(project.root().join(path));\n                let sources = project.sources()?;\n                let contract_path = sources\n                    .iter()\n                    .find_map(|(src_path, _)| {\n                        if **src_path == path {\n                            return Some(src_path.clone());\n                        }\n                        None\n                    })\n                    .ok_or_else(|| {\n                        eyre::eyre!(\n                            \"Could not find source file for contract `{}` at {}\",\n                            info.name,\n                            path.strip_prefix(project.root()).unwrap().display()\n                        )\n                    })?;\n                return Ok(contract_path);\n            }\n            // If ContractInfo.path hasn't been provided we try to find the contract using the name.\n            // This will fail if projects have multiple contracts with the same name. In that case,\n            // path must be specified.\n            let path = project.find_contract_path(&info.name)?;\n            Ok(path)\n        }\n    }\n}\n\n/// Returns the target artifact given the path and name.\npub fn find_matching_contract_artifact(\n    output: &mut ProjectCompileOutput,\n    target_path: &Path,\n    target_name: Option<&str>,\n) -> eyre::Result<ConfigurableContractArtifact> {\n    if let Some(name) = target_name {\n        output\n            .remove(target_path, name)\n            .ok_or_eyre(format!(\"Could not find artifact `{name}` in the compiled artifacts\"))\n    } else {\n        let possible_targets = output\n            .artifact_ids()\n            .filter(|(id, _artifact)| id.source == target_path)\n            .collect::<Vec<_>>();\n\n        if possible_targets.is_empty() {\n            eyre::bail!(\n                \"Could not find artifact linked to source `{target_path:?}` in the compiled artifacts\"\n            );\n        }\n\n        let (target_id, target_artifact) = possible_targets[0].clone();\n        if possible_targets.len() == 1 {\n            return Ok(target_artifact.clone());\n        }\n\n        // If all artifact_ids in `possible_targets` have the same name (without \".\", indicates\n        // additional compiler profiles), it means that there are multiple contracts in the\n        // same file.\n        if !target_id.name.contains(\".\")\n            && possible_targets.iter().any(|(id, _)| id.name != target_id.name)\n        {\n            eyre::bail!(\n                \"Multiple contracts found in the same file, please specify the target <path>:<contract> or <contract>\"\n            );\n        }\n\n        // Otherwise, we're dealing with additional compiler profiles wherein `id.source` is the\n        // same but `id.path` is different.\n        let artifact = possible_targets\n            .iter()\n            .find_map(|(id, artifact)| if id.profile == \"default\" { Some(*artifact) } else { None })\n            .unwrap_or(target_artifact);\n\n        Ok(artifact.clone())\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn bytecode_diffing() {\n        assert_eq!(bytecode_diff_score(b\"a\", b\"a\"), 0.0);\n        assert_eq!(bytecode_diff_score(b\"a\", b\"b\"), 1.0);\n\n        let a_100 = &b\"a\".repeat(100)[..];\n        assert_eq!(bytecode_diff_score(a_100, &b\"b\".repeat(100)), 1.0);\n        assert_eq!(bytecode_diff_score(a_100, &b\"b\".repeat(99)), 1.0);\n        assert_eq!(bytecode_diff_score(a_100, &b\"b\".repeat(101)), 1.0);\n        assert_eq!(bytecode_diff_score(a_100, &b\"b\".repeat(120)), 1.0);\n        assert_eq!(bytecode_diff_score(a_100, &b\"b\".repeat(1000)), 1.0);\n\n        let a_99 = &b\"a\".repeat(99)[..];\n        assert!(bytecode_diff_score(a_100, a_99) <= 0.01);\n    }\n\n    #[test]\n    fn find_by_deployed_code_exact_with_empty_deployed() {\n        let contracts = ContractsByArtifact::new(vec![]);\n\n        assert!(contracts.find_by_deployed_code_exact(&[]).is_none());\n    }\n}\n"
  },
  {
    "path": "crates/common/src/errors/fs.rs",
    "content": "use std::{\n    io,\n    path::{Path, PathBuf},\n};\n\n/// Various error variants for `fs` operations that serve as an addition to the io::Error which\n/// does not provide any information about the path.\n#[derive(Debug, thiserror::Error)]\n#[expect(missing_docs)]\npub enum FsPathError {\n    /// Provides additional path context for [`std::fs::write`].\n    #[error(\"failed to write to {path:?}: {source}\")]\n    Write { source: io::Error, path: PathBuf },\n    /// Provides additional path context for [`std::fs::read`].\n    #[error(\"failed to read from {path:?}: {source}\")]\n    Read { source: io::Error, path: PathBuf },\n    /// Provides additional path context for [`std::fs::copy`].\n    #[error(\"failed to copy from {from:?} to {to:?}: {source}\")]\n    Copy { source: io::Error, from: PathBuf, to: PathBuf },\n    /// Provides additional path context for [`std::fs::read_link`].\n    #[error(\"failed to read from {path:?}: {source}\")]\n    ReadLink { source: io::Error, path: PathBuf },\n    /// Provides additional path context for [`std::fs::File::create`].\n    #[error(\"failed to create file {path:?}: {source}\")]\n    CreateFile { source: io::Error, path: PathBuf },\n    /// Provides additional path context for [`std::fs::remove_file`].\n    #[error(\"failed to remove file {path:?}: {source}\")]\n    RemoveFile { source: io::Error, path: PathBuf },\n    /// Provides additional path context for [`std::fs::create_dir`].\n    #[error(\"failed to create dir {path:?}: {source}\")]\n    CreateDir { source: io::Error, path: PathBuf },\n    /// Provides additional path context for [`std::fs::remove_dir`].\n    #[error(\"failed to remove dir {path:?}: {source}\")]\n    RemoveDir { source: io::Error, path: PathBuf },\n    /// Provides additional path context for [`std::fs::File::open`].\n    #[error(\"failed to open file {path:?}: {source}\")]\n    Open { source: io::Error, path: PathBuf },\n    #[error(\"failed to lock file {path:?}: {source}\")]\n    Lock { source: io::Error, path: PathBuf },\n    #[error(\"failed to unlock file {path:?}: {source}\")]\n    Unlock { source: io::Error, path: PathBuf },\n    /// Provides additional path context for the file whose contents should be parsed as JSON.\n    #[error(\"failed to parse json file: {path:?}: {source}\")]\n    ReadJson { source: serde_json::Error, path: PathBuf },\n    /// Provides additional path context for the new JSON file.\n    #[error(\"failed to write to json file: {path:?}: {source}\")]\n    WriteJson { source: serde_json::Error, path: PathBuf },\n}\n\nimpl FsPathError {\n    /// Returns the complementary error variant for [`std::fs::write`].\n    pub fn write(source: io::Error, path: impl Into<PathBuf>) -> Self {\n        Self::Write { source, path: path.into() }\n    }\n\n    /// Returns the complementary error variant for [`std::fs::read`].\n    pub fn read(source: io::Error, path: impl Into<PathBuf>) -> Self {\n        Self::Read { source, path: path.into() }\n    }\n\n    /// Returns the complementary error variant for [`std::fs::copy`].\n    pub fn copy(source: io::Error, from: impl Into<PathBuf>, to: impl Into<PathBuf>) -> Self {\n        Self::Copy { source, from: from.into(), to: to.into() }\n    }\n\n    /// Returns the complementary error variant for [`std::fs::read_link`].\n    pub fn read_link(source: io::Error, path: impl Into<PathBuf>) -> Self {\n        Self::ReadLink { source, path: path.into() }\n    }\n\n    /// Returns the complementary error variant for [`std::fs::File::create`].\n    pub fn create_file(source: io::Error, path: impl Into<PathBuf>) -> Self {\n        Self::CreateFile { source, path: path.into() }\n    }\n\n    /// Returns the complementary error variant for [`std::fs::remove_file`].\n    pub fn remove_file(source: io::Error, path: impl Into<PathBuf>) -> Self {\n        Self::RemoveFile { source, path: path.into() }\n    }\n\n    /// Returns the complementary error variant for [`std::fs::create_dir`].\n    pub fn create_dir(source: io::Error, path: impl Into<PathBuf>) -> Self {\n        Self::CreateDir { source, path: path.into() }\n    }\n\n    /// Returns the complementary error variant for [`std::fs::remove_dir`].\n    pub fn remove_dir(source: io::Error, path: impl Into<PathBuf>) -> Self {\n        Self::RemoveDir { source, path: path.into() }\n    }\n\n    /// Returns the complementary error variant for [`std::fs::File::open`].\n    pub fn open(source: io::Error, path: impl Into<PathBuf>) -> Self {\n        Self::Open { source, path: path.into() }\n    }\n\n    /// Returns the complementary error variant when locking a file.\n    pub fn lock(source: io::Error, path: impl Into<PathBuf>) -> Self {\n        Self::Lock { source, path: path.into() }\n    }\n\n    /// Returns the complementary error variant when unlocking a file.\n    pub fn unlock(source: io::Error, path: impl Into<PathBuf>) -> Self {\n        Self::Unlock { source, path: path.into() }\n    }\n}\n\nimpl AsRef<Path> for FsPathError {\n    fn as_ref(&self) -> &Path {\n        match self {\n            Self::Write { path, .. }\n            | Self::Read { path, .. }\n            | Self::ReadLink { path, .. }\n            | Self::Copy { from: path, .. }\n            | Self::CreateDir { path, .. }\n            | Self::RemoveDir { path, .. }\n            | Self::CreateFile { path, .. }\n            | Self::RemoveFile { path, .. }\n            | Self::Open { path, .. }\n            | Self::Lock { path, .. }\n            | Self::Unlock { path, .. }\n            | Self::ReadJson { path, .. }\n            | Self::WriteJson { path, .. } => path,\n        }\n    }\n}\n\nimpl From<FsPathError> for io::Error {\n    fn from(value: FsPathError) -> Self {\n        match value {\n            FsPathError::Write { source, .. }\n            | FsPathError::Read { source, .. }\n            | FsPathError::ReadLink { source, .. }\n            | FsPathError::Copy { source, .. }\n            | FsPathError::CreateDir { source, .. }\n            | FsPathError::RemoveDir { source, .. }\n            | FsPathError::CreateFile { source, .. }\n            | FsPathError::RemoveFile { source, .. }\n            | FsPathError::Open { source, .. }\n            | FsPathError::Lock { source, .. }\n            | FsPathError::Unlock { source, .. } => source,\n\n            FsPathError::ReadJson { source, .. } | FsPathError::WriteJson { source, .. } => {\n                source.into()\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "crates/common/src/errors/mod.rs",
    "content": "//! Commonly used errors\n\nmod fs;\npub use fs::FsPathError;\n\nmod private {\n    use eyre::Chain;\n    use std::error::Error;\n\n    pub trait ErrorChain {\n        fn chain(&self) -> Chain<'_>;\n    }\n\n    impl ErrorChain for dyn Error + 'static {\n        fn chain(&self) -> Chain<'_> {\n            Chain::new(self)\n        }\n    }\n\n    impl ErrorChain for eyre::Report {\n        fn chain(&self) -> Chain<'_> {\n            self.chain()\n        }\n    }\n}\n\n/// Displays a chain of errors in a single line.\npub fn display_chain<E: private::ErrorChain + ?Sized>(error: &E) -> String {\n    dedup_chain(error).join(\"; \")\n}\n\n/// Deduplicates a chain of errors.\npub fn dedup_chain<E: private::ErrorChain + ?Sized>(error: &E) -> Vec<String> {\n    let mut causes = all_sources(error);\n    // Deduplicate the common pattern `msg1: msg2; msg2` -> `msg1: msg2`.\n    causes.dedup_by(|b, a| a.contains(b.as_str()));\n    causes\n}\n\nfn all_sources<E: private::ErrorChain + ?Sized>(err: &E) -> Vec<String> {\n    err.chain().map(|cause| cause.to_string().trim().to_string()).collect()\n}\n\n/// Converts solar errors to an eyre error.\npub fn convert_solar_errors(dcx: &solar::interface::diagnostics::DiagCtxt) -> eyre::Result<()> {\n    match dcx.emitted_errors() {\n        Some(Ok(())) => Ok(()),\n        Some(Err(e)) if !e.is_empty() => eyre::bail!(\"solar run failed:\\n\\n{e}\"),\n        _ if dcx.has_errors().is_err() => eyre::bail!(\"solar run failed\"),\n        _ => Ok(()),\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn dedups_contained() {\n        #[derive(thiserror::Error, Debug)]\n        #[error(\"my error: {0}\")]\n        struct A(#[from] B);\n\n        #[derive(thiserror::Error, Debug)]\n        #[error(\"{0}\")]\n        struct B(String);\n\n        let ee = eyre::Report::from(A(B(\"hello\".into())));\n        assert_eq!(ee.chain().count(), 2, \"{ee:?}\");\n        let full = all_sources(&ee).join(\"; \");\n        assert_eq!(full, \"my error: hello; hello\");\n        let chained = display_chain(&ee);\n        assert_eq!(chained, \"my error: hello\");\n    }\n}\n"
  },
  {
    "path": "crates/common/src/fs.rs",
    "content": "//! Contains various `std::fs` wrapper functions that also contain the target path in their errors.\n\nuse crate::errors::FsPathError;\nuse flate2::{Compression, read::GzDecoder, write::GzEncoder};\nuse serde::{Serialize, de::DeserializeOwned};\nuse std::{\n    fs::{self, File},\n    io::{BufReader, BufWriter, Read, Seek, SeekFrom, Write},\n    path::{Component, Path, PathBuf},\n};\n\n/// The [`fs`](self) result type.\npub type Result<T> = std::result::Result<T, FsPathError>;\n\n/// Wrapper for [`File::create`].\npub fn create_file(path: impl AsRef<Path>) -> Result<fs::File> {\n    let path = path.as_ref();\n    File::create(path).map_err(|err| FsPathError::create_file(err, path))\n}\n\n/// Wrapper for [`std::fs::remove_file`].\npub fn remove_file(path: impl AsRef<Path>) -> Result<()> {\n    let path = path.as_ref();\n    fs::remove_file(path).map_err(|err| FsPathError::remove_file(err, path))\n}\n\n/// Wrapper for [`std::fs::read`].\npub fn read(path: impl AsRef<Path>) -> Result<Vec<u8>> {\n    let path = path.as_ref();\n    fs::read(path).map_err(|err| FsPathError::read(err, path))\n}\n\n/// Wrapper for [`std::fs::read_link`].\npub fn read_link(path: impl AsRef<Path>) -> Result<PathBuf> {\n    let path = path.as_ref();\n    fs::read_link(path).map_err(|err| FsPathError::read_link(err, path))\n}\n\n/// Wrapper for [`std::fs::read_to_string`].\npub fn read_to_string(path: impl AsRef<Path>) -> Result<String> {\n    let path = path.as_ref();\n    fs::read_to_string(path).map_err(|err| FsPathError::read(err, path))\n}\n\n/// Reads the JSON file and deserialize it into the provided type.\npub fn read_json_file<T: DeserializeOwned>(path: &Path) -> Result<T> {\n    // read the file into a byte array first\n    // https://github.com/serde-rs/json/issues/160\n    let s = read_to_string(path)?;\n    serde_json::from_str(&s).map_err(|source| FsPathError::ReadJson { source, path: path.into() })\n}\n\n/// Reads and decodes the json gzip file, then deserialize it into the provided type.\npub fn read_json_gzip_file<T: DeserializeOwned>(path: &Path) -> Result<T> {\n    let file = open(path)?;\n    let reader = BufReader::new(file);\n    let decoder = GzDecoder::new(reader);\n    serde_json::from_reader(decoder)\n        .map_err(|source| FsPathError::ReadJson { source, path: path.into() })\n}\n\n/// Reads the entire contents of a locked shared file into a string.\npub fn locked_read_to_string(path: impl AsRef<Path>) -> Result<String> {\n    let path = path.as_ref();\n    let contents = locked_read(path)?;\n    String::from_utf8(contents).map_err(|err| FsPathError::read(std::io::Error::other(err), path))\n}\n\n/// Reads the entire contents of a locked shared file into a bytes vector.\npub fn locked_read(path: impl AsRef<Path>) -> Result<Vec<u8>> {\n    let path = path.as_ref();\n    let mut file =\n        fs::OpenOptions::new().read(true).open(path).map_err(|err| FsPathError::open(err, path))?;\n    file.lock_shared().map_err(|err| FsPathError::lock(err, path))?;\n    let contents = read_inner(path, &mut file)?;\n    file.unlock().map_err(|err| FsPathError::unlock(err, path))?;\n    Ok(contents)\n}\n\nfn read_inner(path: &Path, file: &mut File) -> Result<Vec<u8>> {\n    let file_len = file.metadata().map_err(|err| FsPathError::open(err, path))?.len() as usize;\n    let mut buffer = Vec::with_capacity(file_len);\n    file.read_to_end(&mut buffer).map_err(|err| FsPathError::read(err, path))?;\n    Ok(buffer)\n}\n\n/// Writes the object as a JSON object.\npub fn write_json_file<T: Serialize>(path: &Path, obj: &T) -> Result<()> {\n    let file = create_file(path)?;\n    let mut writer = BufWriter::new(file);\n    serde_json::to_writer(&mut writer, obj)\n        .map_err(|source| FsPathError::WriteJson { source, path: path.into() })?;\n    writer.flush().map_err(|e| FsPathError::write(e, path))\n}\n\n/// Writes the object as a pretty JSON object.\npub fn write_pretty_json_file<T: Serialize>(path: &Path, obj: &T) -> Result<()> {\n    let file = create_file(path)?;\n    let mut writer = BufWriter::new(file);\n    serde_json::to_writer_pretty(&mut writer, obj)\n        .map_err(|source| FsPathError::WriteJson { source, path: path.into() })?;\n    writer.flush().map_err(|e| FsPathError::write(e, path))\n}\n\n/// Writes the object as a gzip compressed file.\npub fn write_json_gzip_file<T: Serialize>(path: &Path, obj: &T) -> Result<()> {\n    let file = create_file(path)?;\n    let writer = BufWriter::new(file);\n    let mut encoder = GzEncoder::new(writer, Compression::default());\n    serde_json::to_writer(&mut encoder, obj)\n        .map_err(|source| FsPathError::WriteJson { source, path: path.into() })?;\n    // Ensure we surface any I/O errors on final gzip write and buffer flush.\n    let mut inner_writer = encoder.finish().map_err(|e| FsPathError::write(e, path))?;\n    inner_writer.flush().map_err(|e| FsPathError::write(e, path))?;\n    Ok(())\n}\n\n/// Wrapper for `std::fs::write`\npub fn write(path: impl AsRef<Path>, contents: impl AsRef<[u8]>) -> Result<()> {\n    let path = path.as_ref();\n    fs::write(path, contents).map_err(|err| FsPathError::write(err, path))\n}\n\n/// Writes all content in an exclusive locked file.\npub fn locked_write(path: impl AsRef<Path>, contents: impl AsRef<[u8]>) -> Result<()> {\n    let path = path.as_ref();\n    let mut file = fs::OpenOptions::new()\n        .write(true)\n        .create(true)\n        .truncate(true)\n        .open(path)\n        .map_err(|err| FsPathError::open(err, path))?;\n    file.lock().map_err(|err| FsPathError::lock(err, path))?;\n    file.write_all(contents.as_ref()).map_err(|err| FsPathError::write(err, path))?;\n    file.unlock().map_err(|err| FsPathError::unlock(err, path))\n}\n\n/// Writes a line in an exclusive locked file.\npub fn locked_write_line(path: impl AsRef<Path>, line: &str) -> Result<()> {\n    let path = path.as_ref();\n    if cfg!(windows) {\n        return locked_write_line_windows(path, line);\n    }\n\n    let mut file = std::fs::OpenOptions::new()\n        .append(true)\n        .create(true)\n        .open(path)\n        .map_err(|err| FsPathError::open(err, path))?;\n\n    file.lock().map_err(|err| FsPathError::lock(err, path))?;\n    writeln!(file, \"{line}\").map_err(|err| FsPathError::write(err, path))?;\n    file.unlock().map_err(|err| FsPathError::unlock(err, path))\n}\n\n// Locking fails on Windows if the file is opened in append mode.\nfn locked_write_line_windows(path: &Path, line: &str) -> Result<()> {\n    let mut file = std::fs::OpenOptions::new()\n        .write(true)\n        .truncate(false)\n        .create(true)\n        .open(path)\n        .map_err(|err| FsPathError::open(err, path))?;\n    file.lock().map_err(|err| FsPathError::lock(err, path))?;\n\n    file.seek(SeekFrom::End(0)).map_err(|err| FsPathError::write(err, path))?;\n    writeln!(file, \"{line}\").map_err(|err| FsPathError::write(err, path))?;\n\n    file.unlock().map_err(|err| FsPathError::unlock(err, path))\n}\n\n/// Wrapper for `std::fs::copy`\npub fn copy(from: impl AsRef<Path>, to: impl AsRef<Path>) -> Result<u64> {\n    let from = from.as_ref();\n    let to = to.as_ref();\n    fs::copy(from, to).map_err(|err| FsPathError::copy(err, from, to))\n}\n\n/// Wrapper for `std::fs::create_dir`\npub fn create_dir(path: impl AsRef<Path>) -> Result<()> {\n    let path = path.as_ref();\n    fs::create_dir(path).map_err(|err| FsPathError::create_dir(err, path))\n}\n\n/// Wrapper for `std::fs::create_dir_all`\npub fn create_dir_all(path: impl AsRef<Path>) -> Result<()> {\n    let path = path.as_ref();\n    fs::create_dir_all(path).map_err(|err| FsPathError::create_dir(err, path))\n}\n\n/// Wrapper for `std::fs::remove_dir`\npub fn remove_dir(path: impl AsRef<Path>) -> Result<()> {\n    let path = path.as_ref();\n    fs::remove_dir(path).map_err(|err| FsPathError::remove_dir(err, path))\n}\n\n/// Wrapper for `std::fs::remove_dir_all`\npub fn remove_dir_all(path: impl AsRef<Path>) -> Result<()> {\n    let path = path.as_ref();\n    fs::remove_dir_all(path).map_err(|err| FsPathError::remove_dir(err, path))\n}\n\n/// Wrapper for `std::fs::File::open`\npub fn open(path: impl AsRef<Path>) -> Result<fs::File> {\n    let path = path.as_ref();\n    fs::File::open(path).map_err(|err| FsPathError::open(err, path))\n}\n\n/// Normalize a path, removing things like `.` and `..`.\n///\n/// NOTE: This does not return symlinks and does not touch the filesystem at all (unlike\n/// [`std::fs::canonicalize`])\n///\n/// ref: <https://github.com/rust-lang/cargo/blob/9ded34a558a900563b0acf3730e223c649cf859d/crates/cargo-util/src/paths.rs#L81>\npub fn normalize_path(path: &Path) -> PathBuf {\n    let mut components = path.components().peekable();\n    let mut ret = if let Some(c @ Component::Prefix(..)) = components.peek().copied() {\n        components.next();\n        PathBuf::from(c.as_os_str())\n    } else {\n        PathBuf::new()\n    };\n\n    for component in components {\n        match component {\n            Component::Prefix(..) => unreachable!(),\n            Component::RootDir => {\n                ret.push(component.as_os_str());\n            }\n            Component::CurDir => {}\n            Component::ParentDir => {\n                ret.pop();\n            }\n            Component::Normal(c) => {\n                ret.push(c);\n            }\n        }\n    }\n    ret\n}\n\n/// Returns an iterator over all files with the given extension under the `root` dir.\npub fn files_with_ext<'a>(root: &Path, ext: &'a str) -> impl Iterator<Item = PathBuf> + 'a {\n    walkdir::WalkDir::new(root)\n        .sort_by_file_name()\n        .into_iter()\n        .filter_map(walkdir::Result::ok)\n        .filter(|e| e.file_type().is_file() && e.path().extension() == Some(ext.as_ref()))\n        .map(walkdir::DirEntry::into_path)\n}\n\n/// Returns an iterator over all JSON files under the `root` dir.\npub fn json_files(root: &Path) -> impl Iterator<Item = PathBuf> {\n    files_with_ext(root, \"json\")\n}\n\n/// Canonicalize a path, returning an error if the path does not exist.\n///\n/// Mainly useful to apply canonicalization to paths obtained from project files but still error\n/// properly instead of flattening the errors.\npub fn canonicalize_path(path: impl AsRef<Path>) -> std::io::Result<PathBuf> {\n    dunce::canonicalize(path)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_normalize_path() {\n        let p = Path::new(\"/a/../file.txt\");\n        let normalized = normalize_path(p);\n        assert_eq!(normalized, PathBuf::from(\"/file.txt\"));\n    }\n}\n"
  },
  {
    "path": "crates/common/src/io/macros.rs",
    "content": "/// Prints a message to [`stdout`][std::io::stdout] and reads a line from stdin into a String.\n///\n/// Returns `Result<T>`, so sometimes `T` must be explicitly specified, like in `str::parse`.\n///\n/// # Examples\n///\n/// ```no_run\n/// use foundry_common::prompt;\n///\n/// let response: String = prompt!(\"Would you like to continue? [y/N] \")?;\n/// if !matches!(response.as_str(), \"y\" | \"Y\") {\n///     return Ok(());\n/// }\n/// # Ok::<(), Box<dyn std::error::Error>>(())\n/// ```\n#[macro_export]\nmacro_rules! prompt {\n    () => {\n        $crate::stdin::parse_line()\n    };\n\n    ($($tt:tt)+) => {{\n        let _ = $crate::sh_print!($($tt)+);\n        match ::std::io::Write::flush(&mut ::std::io::stdout()) {\n            ::core::result::Result::Ok(()) => $crate::prompt!(),\n            ::core::result::Result::Err(e) => ::core::result::Result::Err(::eyre::eyre!(\"Could not flush stdout: {e}\"))\n        }\n    }};\n}\n\n/// Prints a formatted error to stderr.\n///\n/// **Note**: will log regardless of the verbosity level.\n#[macro_export]\nmacro_rules! sh_err {\n    ($($args:tt)*) => {\n        $crate::__sh_dispatch!(error $($args)*)\n    };\n}\n\n/// Prints a formatted warning to stderr.\n///\n/// **Note**: if `verbosity` is set to `Quiet`, this is a no-op.\n#[macro_export]\nmacro_rules! sh_warn {\n    ($($args:tt)*) => {\n        $crate::__sh_dispatch!(warn $($args)*)\n    };\n}\n\n/// Prints a raw formatted message to stdout.\n///\n/// **Note**: if `verbosity` is set to `Quiet`, this is a no-op.\n#[macro_export]\nmacro_rules! sh_print {\n    ($($args:tt)*) => {\n        $crate::__sh_dispatch!(print_out $($args)*)\n    };\n\n    ($shell:expr, $($args:tt)*) => {\n        $crate::__sh_dispatch!(print_out $shell, $($args)*)\n    };\n}\n\n/// Prints a raw formatted message to stderr.\n///\n/// **Note**: if `verbosity` is set to `Quiet`, this is a no-op.\n#[macro_export]\nmacro_rules! sh_eprint {\n    ($($args:tt)*) => {\n        $crate::__sh_dispatch!(print_err $($args)*)\n    };\n\n    ($shell:expr, $($args:tt)*) => {\n        $crate::__sh_dispatch!(print_err $shell, $($args)*)\n    };\n}\n\n/// Prints a raw formatted message to stdout, with a trailing newline.\n///\n/// **Note**: if `verbosity` is set to `Quiet`, this is a no-op.\n#[macro_export]\nmacro_rules! sh_println {\n    () => {\n        $crate::sh_print!(\"\\n\")\n    };\n\n    ($fmt:literal $($args:tt)*) => {\n        $crate::sh_print!(\"{}\\n\", ::core::format_args!($fmt $($args)*))\n    };\n\n    ($shell:expr $(,)?) => {\n        $crate::sh_print!($shell, \"\\n\").expect(\"failed to write newline\")\n    };\n\n    ($shell:expr, $($args:tt)*) => {\n        $crate::sh_print!($shell, \"{}\\n\", ::core::format_args!($($args)*))\n    };\n\n    ($($args:tt)*) => {\n        $crate::sh_print!(\"{}\\n\", ::core::format_args!($($args)*))\n    };\n}\n\n/// Prints a raw formatted message to stderr, with a trailing newline.\n///\n/// **Note**: if `verbosity` is set to `Quiet`, this is a no-op.\n#[macro_export]\nmacro_rules! sh_eprintln {\n    () => {\n        $crate::sh_eprint!(\"\\n\")\n    };\n\n    ($fmt:literal $($args:tt)*) => {\n        $crate::sh_eprint!(\"{}\\n\", ::core::format_args!($fmt $($args)*))\n    };\n\n    ($shell:expr $(,)?) => {\n        $crate::sh_eprint!($shell, \"\\n\")\n    };\n\n    ($shell:expr, $($args:tt)*) => {\n        $crate::sh_eprint!($shell, \"{}\\n\", ::core::format_args!($($args)*))\n    };\n\n    ($($args:tt)*) => {\n        $crate::sh_eprint!(\"{}\\n\", ::core::format_args!($($args)*))\n    };\n}\n\n#[doc(hidden)]\n#[macro_export]\nmacro_rules! __sh_dispatch {\n    ($f:ident $fmt:literal $($args:tt)*) => {\n        $crate::__sh_dispatch!(@impl $f &mut *$crate::Shell::get(), $fmt $($args)*)\n    };\n\n    ($f:ident $shell:expr, $($args:tt)*) => {\n        $crate::__sh_dispatch!(@impl $f $shell, $($args)*)\n    };\n\n    ($f:ident $($args:tt)*) => {\n        $crate::__sh_dispatch!(@impl $f &mut *$crate::Shell::get(), $($args)*)\n    };\n\n    // Ensure that the global shell lock is held for as little time as possible.\n    // Also avoids deadlocks in case of nested calls.\n    (@impl $f:ident $shell:expr, $($args:tt)*) => {\n        match format!($($args)*) {\n            fmt => $crate::Shell::$f($shell, fmt),\n        }\n    };\n}\n\n#[cfg(test)]\nmod tests {\n    #[test]\n    fn macros() -> eyre::Result<()> {\n        sh_err!(\"err\")?;\n        sh_err!(\"err {}\", \"arg\")?;\n\n        sh_warn!(\"warn\")?;\n        sh_warn!(\"warn {}\", \"arg\")?;\n\n        sh_print!(\"print -\")?;\n        sh_print!(\"print {} -\", \"arg\")?;\n\n        sh_println!()?;\n        sh_println!(\"println\")?;\n        sh_println!(\"println {}\", \"arg\")?;\n\n        sh_eprint!(\"eprint -\")?;\n        sh_eprint!(\"eprint {} -\", \"arg\")?;\n\n        sh_eprintln!()?;\n        sh_eprintln!(\"eprintln\")?;\n        sh_eprintln!(\"eprintln {}\", \"arg\")?;\n\n        sh_println!(\"{:?}\", {\n            sh_println!(\"hi\")?;\n            solar::data_structures::fmt::from_fn(|f| {\n                let _ = sh_println!(\"even more nested\");\n                write!(f, \"hi 2\")\n            })\n        })?;\n\n        Ok(())\n    }\n\n    #[test]\n    fn macros_with_shell() -> eyre::Result<()> {\n        let shell = &mut crate::Shell::new();\n        sh_eprintln!(shell)?;\n        sh_eprintln!(shell,)?;\n        sh_eprintln!(shell, \"shelled eprintln\")?;\n        sh_eprintln!(shell, \"shelled eprintln {}\", \"arg\")?;\n        sh_eprintln!(&mut crate::Shell::new(), \"shelled eprintln {}\", \"arg\")?;\n\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "crates/common/src/io/mod.rs",
    "content": "//! Utilities for working with standard input, output, and error.\n\n#[macro_use]\nmod macros;\n\npub mod shell;\npub mod stdin;\npub mod style;\n\n#[doc(no_inline)]\npub use shell::Shell;\n"
  },
  {
    "path": "crates/common/src/io/shell.rs",
    "content": "//! Utility functions for writing to [`stdout`](std::io::stdout) and [`stderr`](std::io::stderr).\n//!\n//! Originally from [cargo](https://github.com/rust-lang/cargo/blob/35814255a1dbaeca9219fae81d37a8190050092c/src/cargo/core/shell.rs).\n\nuse super::style::*;\nuse anstream::AutoStream;\nuse anstyle::Style;\nuse clap::ValueEnum;\nuse eyre::Result;\nuse serde::{Deserialize, Serialize};\nuse std::{\n    fmt,\n    io::{IsTerminal, prelude::*},\n    ops::DerefMut,\n    sync::{\n        Mutex, OnceLock, PoisonError,\n        atomic::{AtomicBool, Ordering},\n    },\n};\n\n/// Returns the current color choice.\npub fn color_choice() -> ColorChoice {\n    Shell::get().color_choice()\n}\n\n/// Returns the currently set verbosity level.\npub fn verbosity() -> Verbosity {\n    Shell::get().verbosity()\n}\n\n/// Set the verbosity level.\npub fn set_verbosity(verbosity: Verbosity) {\n    Shell::get().set_verbosity(verbosity);\n}\n\n/// Returns whether the output mode is [`OutputMode::Quiet`].\npub fn is_quiet() -> bool {\n    Shell::get().output_mode().is_quiet()\n}\n\n/// Returns whether the output format is [`OutputFormat::Json`].\npub fn is_json() -> bool {\n    Shell::get().is_json()\n}\n\n/// Returns whether the output format is [`OutputFormat::Markdown`].\npub fn is_markdown() -> bool {\n    Shell::get().is_markdown()\n}\n\n/// The global shell instance.\nstatic GLOBAL_SHELL: OnceLock<Mutex<Shell>> = OnceLock::new();\n\n#[derive(Debug, Default, Clone, Copy, PartialEq)]\n/// The requested output mode.\npub enum OutputMode {\n    /// Default output\n    #[default]\n    Normal,\n    /// No output\n    Quiet,\n}\n\nimpl OutputMode {\n    /// Returns true if the output mode is `Normal`.\n    pub fn is_normal(self) -> bool {\n        self == Self::Normal\n    }\n\n    /// Returns true if the output mode is `Quiet`.\n    pub fn is_quiet(self) -> bool {\n        self == Self::Quiet\n    }\n}\n\n/// The requested output format.\n#[derive(Debug, Default, Clone, Copy, PartialEq)]\npub enum OutputFormat {\n    /// Plain text output.\n    #[default]\n    Text,\n    /// JSON output.\n    Json,\n    /// Plain text with markdown tables.\n    Markdown,\n}\n\nimpl OutputFormat {\n    /// Returns true if the output format is `Text`.\n    pub fn is_text(self) -> bool {\n        self == Self::Text\n    }\n\n    /// Returns true if the output format is `Json`.\n    pub fn is_json(self) -> bool {\n        self == Self::Json\n    }\n\n    /// Returns true if the output format is `Markdown`.\n    pub fn is_markdown(self) -> bool {\n        self == Self::Markdown\n    }\n}\n\n/// The verbosity level.\npub type Verbosity = u8;\n\n/// An abstraction around console output that remembers preferences for output\n/// verbosity and color.\npub struct Shell {\n    /// Wrapper around stdout/stderr. This helps with supporting sending\n    /// output to a memory buffer which is useful for tests.\n    output: ShellOut,\n\n    /// The format to use for message output.\n    output_format: OutputFormat,\n\n    /// The verbosity mode to use for message output.\n    output_mode: OutputMode,\n\n    /// The verbosity level to use for message output.\n    verbosity: Verbosity,\n\n    /// Flag that indicates the current line needs to be cleared before\n    /// printing. Used when a progress bar is currently displayed.\n    needs_clear: AtomicBool,\n}\n\nimpl fmt::Debug for Shell {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        let mut s = f.debug_struct(\"Shell\");\n        s.field(\"output_format\", &self.output_format);\n        s.field(\"output_mode\", &self.output_mode);\n        s.field(\"verbosity\", &self.verbosity);\n        if let ShellOut::Stream { color_choice, .. } = self.output {\n            s.field(\"color_choice\", &color_choice);\n        }\n        s.finish()\n    }\n}\n\n/// A `Write`able object, either with or without color support.\nenum ShellOut {\n    /// Color-enabled stdio, with information on whether color should be used.\n    Stream {\n        stdout: AutoStream<std::io::Stdout>,\n        stderr: AutoStream<std::io::Stderr>,\n        stderr_tty: bool,\n        color_choice: ColorChoice,\n    },\n    /// A write object that ignores all output.\n    Empty(std::io::Empty),\n}\n\n/// Whether messages should use color output.\n#[derive(Debug, Default, PartialEq, Clone, Copy, Serialize, Deserialize, ValueEnum)]\npub enum ColorChoice {\n    /// Intelligently guess whether to use color output (default).\n    #[default]\n    Auto,\n    /// Force color output.\n    Always,\n    /// Force disable color output.\n    Never,\n}\n\nimpl Default for Shell {\n    fn default() -> Self {\n        Self::new()\n    }\n}\n\nimpl Shell {\n    /// Creates a new shell (color choice and verbosity), defaulting to 'auto' color and verbose\n    /// output.\n    pub fn new() -> Self {\n        Self::new_with(\n            OutputFormat::Text,\n            OutputMode::Normal,\n            ColorChoice::Auto,\n            Verbosity::default(),\n        )\n    }\n\n    /// Creates a new shell with the given color choice and verbosity.\n    pub fn new_with(\n        format: OutputFormat,\n        mode: OutputMode,\n        color: ColorChoice,\n        verbosity: Verbosity,\n    ) -> Self {\n        Self {\n            output: ShellOut::Stream {\n                stdout: AutoStream::new(std::io::stdout(), color.to_anstream_color_choice()),\n                stderr: AutoStream::new(std::io::stderr(), color.to_anstream_color_choice()),\n                color_choice: color,\n                stderr_tty: std::io::stderr().is_terminal(),\n            },\n            output_format: format,\n            output_mode: mode,\n            verbosity,\n            needs_clear: AtomicBool::new(false),\n        }\n    }\n\n    /// Creates a shell that ignores all output.\n    pub fn empty() -> Self {\n        Self {\n            output: ShellOut::Empty(std::io::empty()),\n            output_format: OutputFormat::Text,\n            output_mode: OutputMode::Quiet,\n            verbosity: 0,\n            needs_clear: AtomicBool::new(false),\n        }\n    }\n\n    /// Acquire a lock to the global shell.\n    ///\n    /// Initializes it with the default values if it has not been set yet.\n    pub fn get() -> impl DerefMut<Target = Self> + 'static {\n        GLOBAL_SHELL.get_or_init(Default::default).lock().unwrap_or_else(PoisonError::into_inner)\n    }\n\n    /// Set the global shell.\n    ///\n    /// # Panics\n    ///\n    /// Panics if the global shell has already been set.\n    #[track_caller]\n    pub fn set(self) {\n        GLOBAL_SHELL\n            .set(Mutex::new(self))\n            .unwrap_or_else(|_| panic!(\"attempted to set global shell twice\"))\n    }\n\n    /// Sets whether the next print should clear the current line and returns the previous value.\n    pub fn set_needs_clear(&self, needs_clear: bool) -> bool {\n        self.needs_clear.swap(needs_clear, Ordering::Relaxed)\n    }\n\n    /// Returns `true` if the output format is JSON.\n    pub fn is_json(&self) -> bool {\n        self.output_format.is_json()\n    }\n\n    /// Returns `true` if the output format is Markdown.\n    pub fn is_markdown(&self) -> bool {\n        self.output_format.is_markdown()\n    }\n\n    /// Returns `true` if the verbosity level is `Quiet`.\n    pub fn is_quiet(&self) -> bool {\n        self.output_mode.is_quiet()\n    }\n\n    /// Returns `true` if the `needs_clear` flag is set.\n    pub fn needs_clear(&self) -> bool {\n        self.needs_clear.load(Ordering::Relaxed)\n    }\n\n    /// Returns `true` if the `needs_clear` flag is unset.\n    pub fn is_cleared(&self) -> bool {\n        !self.needs_clear()\n    }\n\n    /// Gets the output format of the shell.\n    pub fn output_format(&self) -> OutputFormat {\n        self.output_format\n    }\n\n    /// Gets the output mode of the shell.\n    pub fn output_mode(&self) -> OutputMode {\n        self.output_mode\n    }\n\n    /// Gets the verbosity of the shell when [`OutputMode::Normal`] is set.\n    pub fn verbosity(&self) -> Verbosity {\n        self.verbosity\n    }\n\n    /// Sets the verbosity level.\n    pub fn set_verbosity(&mut self, verbosity: Verbosity) {\n        self.verbosity = verbosity;\n    }\n\n    /// Gets the current color choice.\n    ///\n    /// If we are not using a color stream, this will always return `Never`, even if the color\n    /// choice has been set to something else.\n    pub fn color_choice(&self) -> ColorChoice {\n        match self.output {\n            ShellOut::Stream { color_choice, .. } => color_choice,\n            ShellOut::Empty(_) => ColorChoice::Never,\n        }\n    }\n\n    /// Returns `true` if stderr is a tty.\n    pub fn is_err_tty(&self) -> bool {\n        match self.output {\n            ShellOut::Stream { stderr_tty, .. } => stderr_tty,\n            ShellOut::Empty(_) => false,\n        }\n    }\n\n    /// Whether `stderr` supports color.\n    pub fn err_supports_color(&self) -> bool {\n        match &self.output {\n            ShellOut::Stream { stderr, .. } => supports_color(stderr.current_choice()),\n            ShellOut::Empty(_) => false,\n        }\n    }\n\n    /// Whether `stdout` supports color.\n    pub fn out_supports_color(&self) -> bool {\n        match &self.output {\n            ShellOut::Stream { stdout, .. } => supports_color(stdout.current_choice()),\n            ShellOut::Empty(_) => false,\n        }\n    }\n\n    /// Gets a reference to the underlying stdout writer.\n    pub fn out(&mut self) -> &mut dyn Write {\n        self.maybe_err_erase_line();\n        self.output.stdout()\n    }\n\n    /// Gets a reference to the underlying stderr writer.\n    pub fn err(&mut self) -> &mut dyn Write {\n        self.maybe_err_erase_line();\n        self.output.stderr()\n    }\n\n    /// Erase from cursor to end of line if needed.\n    pub fn maybe_err_erase_line(&mut self) {\n        if self.err_supports_color() && self.set_needs_clear(false) {\n            // This is the \"EL - Erase in Line\" sequence. It clears from the cursor\n            // to the end of line.\n            // https://en.wikipedia.org/wiki/ANSI_escape_code#CSI_sequences\n            let _ = self.output.stderr().write_all(b\"\\x1B[K\");\n        }\n    }\n\n    /// Prints a red 'error' message. Use the [`sh_err!`] macro instead.\n    /// This will render a message in [ERROR] style with a bold `Error: ` prefix.\n    ///\n    /// **Note**: will log regardless of the verbosity level.\n    pub fn error(&mut self, message: impl fmt::Display) -> Result<()> {\n        self.maybe_err_erase_line();\n        self.output.message_stderr(&\"Error\", &ERROR, Some(&message), false)\n    }\n\n    /// Prints an amber 'warning' message. Use the [`sh_warn!`] macro instead.\n    /// This will render a message in [WARN] style with a bold `Warning: `prefix.\n    ///\n    /// **Note**: if `verbosity` is set to `Quiet`, this is a no-op.\n    pub fn warn(&mut self, message: impl fmt::Display) -> Result<()> {\n        match self.output_mode {\n            OutputMode::Quiet => Ok(()),\n            _ => self.print(&\"Warning\", &WARN, Some(&message), false),\n        }\n    }\n\n    /// Write a styled fragment.\n    ///\n    /// Caller is responsible for deciding whether [`Shell::verbosity`] is affects output.\n    pub fn write_stdout(&mut self, fragment: impl fmt::Display, color: &Style) -> Result<()> {\n        self.output.write_stdout(fragment, color)\n    }\n\n    /// Write a styled fragment with the default color. Use the [`sh_print!`] macro instead.\n    ///\n    /// **Note**: if `verbosity` is set to `Quiet`, this is a no-op.\n    pub fn print_out(&mut self, fragment: impl fmt::Display) -> Result<()> {\n        match self.output_mode {\n            OutputMode::Quiet => Ok(()),\n            _ => self.write_stdout(fragment, &Style::new()),\n        }\n    }\n\n    /// Write a styled fragment\n    ///\n    /// Caller is responsible for deciding whether [`Shell::verbosity`] is affects output.\n    pub fn write_stderr(&mut self, fragment: impl fmt::Display, color: &Style) -> Result<()> {\n        self.output.write_stderr(fragment, color)\n    }\n\n    /// Write a styled fragment with the default color. Use the [`sh_eprint!`] macro instead.\n    ///\n    /// **Note**: if `verbosity` is set to `Quiet`, this is a no-op.\n    pub fn print_err(&mut self, fragment: impl fmt::Display) -> Result<()> {\n        match self.output_mode {\n            OutputMode::Quiet => Ok(()),\n            _ => self.write_stderr(fragment, &Style::new()),\n        }\n    }\n\n    /// Prints a message, where the status will have `color` color, and can be justified. The\n    /// messages follows without color.\n    fn print(\n        &mut self,\n        status: &dyn fmt::Display,\n        style: &Style,\n        message: Option<&dyn fmt::Display>,\n        justified: bool,\n    ) -> Result<()> {\n        match self.output_mode {\n            OutputMode::Quiet => Ok(()),\n            _ => {\n                self.maybe_err_erase_line();\n                self.output.message_stderr(status, style, message, justified)\n            }\n        }\n    }\n}\n\nimpl ShellOut {\n    /// Prints out a message with a status to stderr. The status comes first, and is bold plus the\n    /// given color. The status can be justified, in which case the max width that will right\n    /// align is 12 chars.\n    fn message_stderr(\n        &mut self,\n        status: &dyn fmt::Display,\n        style: &Style,\n        message: Option<&dyn fmt::Display>,\n        justified: bool,\n    ) -> Result<()> {\n        let buffer = Self::format_message(status, message, style, justified)?;\n        self.stderr().write_all(&buffer)?;\n        Ok(())\n    }\n\n    /// Write a styled fragment\n    fn write_stdout(&mut self, fragment: impl fmt::Display, style: &Style) -> Result<()> {\n        let mut buffer = Vec::new();\n        write!(buffer, \"{style}{fragment}{style:#}\")?;\n        self.stdout().write_all(&buffer)?;\n        Ok(())\n    }\n\n    /// Write a styled fragment\n    fn write_stderr(&mut self, fragment: impl fmt::Display, style: &Style) -> Result<()> {\n        let mut buffer = Vec::new();\n        write!(buffer, \"{style}{fragment}{style:#}\")?;\n        self.stderr().write_all(&buffer)?;\n        Ok(())\n    }\n\n    /// Gets stdout as a [`io::Write`](Write) trait object.\n    fn stdout(&mut self) -> &mut dyn Write {\n        match self {\n            Self::Stream { stdout, .. } => stdout,\n            Self::Empty(e) => e,\n        }\n    }\n\n    /// Gets stderr as a [`io::Write`](Write) trait object.\n    fn stderr(&mut self) -> &mut dyn Write {\n        match self {\n            Self::Stream { stderr, .. } => stderr,\n            Self::Empty(e) => e,\n        }\n    }\n\n    /// Formats a message with a status and optional message.\n    fn format_message(\n        status: &dyn fmt::Display,\n        message: Option<&dyn fmt::Display>,\n        style: &Style,\n        justified: bool,\n    ) -> Result<Vec<u8>> {\n        let bold = anstyle::Style::new().bold();\n\n        let mut buffer = Vec::new();\n        if justified {\n            write!(buffer, \"{style}{status:>12}{style:#}\")?;\n        } else {\n            write!(buffer, \"{style}{status}{style:#}{bold}:{bold:#}\")?;\n        }\n        match message {\n            Some(message) => {\n                writeln!(buffer, \" {message}\")?;\n            }\n            None => write!(buffer, \" \")?,\n        }\n\n        Ok(buffer)\n    }\n}\n\nimpl ColorChoice {\n    /// Converts our color choice to [`anstream`]'s version.\n    fn to_anstream_color_choice(self) -> anstream::ColorChoice {\n        match self {\n            Self::Always => anstream::ColorChoice::Always,\n            Self::Never => anstream::ColorChoice::Never,\n            Self::Auto => anstream::ColorChoice::Auto,\n        }\n    }\n}\n\nfn supports_color(choice: anstream::ColorChoice) -> bool {\n    match choice {\n        anstream::ColorChoice::Always\n        | anstream::ColorChoice::AlwaysAnsi\n        | anstream::ColorChoice::Auto => true,\n        anstream::ColorChoice::Never => false,\n    }\n}\n"
  },
  {
    "path": "crates/common/src/io/stdin.rs",
    "content": "//! Utility functions for reading from [`stdin`](std::io::stdin).\n\nuse eyre::Result;\nuse std::{\n    error::Error as StdError,\n    io::{self, BufRead, Read},\n    str::FromStr,\n};\n\n/// Unwraps the given `Option<T>` or [reads stdin into a String](read) and parses it as `T`.\npub fn unwrap<T>(value: Option<T>, read_line: bool) -> Result<T>\nwhere\n    T: FromStr,\n    T::Err: StdError + Send + Sync + 'static,\n{\n    match value {\n        Some(value) => Ok(value),\n        None => parse(read_line),\n    }\n}\n\n/// Shortcut for `(unwrap(a), unwrap(b))`.\npub fn unwrap2<A, B>(a: Option<A>, b: Option<B>) -> Result<(A, B)>\nwhere\n    A: FromStr,\n    B: FromStr,\n    A::Err: StdError + Send + Sync + 'static,\n    B::Err: StdError + Send + Sync + 'static,\n{\n    match (a, b) {\n        (Some(a), Some(b)) => Ok((a, b)),\n        (a, b) => Ok((unwrap(a, true)?, unwrap(b, true)?)),\n    }\n}\n\n/// [Reads stdin into a String](read) and parses it as `Vec<T>` using whitespaces as delimiters if\n/// the given `Vec<T>` is empty.\npub fn unwrap_vec<T>(mut value: Vec<T>) -> Result<Vec<T>>\nwhere\n    T: FromStr,\n    T::Err: StdError + Send + Sync + 'static,\n{\n    if value.is_empty() {\n        let s = read(false)?;\n        value = s.split_whitespace().map(FromStr::from_str).collect::<Result<Vec<T>, _>>()?;\n    }\n\n    Ok(value)\n}\n\n/// Short-hand for `unwrap(value, true)`.\npub fn unwrap_line<T>(value: Option<T>) -> Result<T>\nwhere\n    T: FromStr,\n    T::Err: StdError + Send + Sync + 'static,\n{\n    unwrap(value, true)\n}\n\n/// Reads bytes from [`stdin`][io::stdin] into a String.\n///\n/// If `read_line` is true, stop at the first newline (the `0xA` byte).\npub fn parse<T>(read_line: bool) -> Result<T>\nwhere\n    T: FromStr,\n    T::Err: StdError + Send + Sync + 'static,\n{\n    read(read_line).and_then(|s| s.parse().map_err(Into::into))\n}\n\n/// Short-hand for `parse(true)`.\npub fn parse_line<T>() -> Result<T>\nwhere\n    T: FromStr,\n    T::Err: StdError + Send + Sync + 'static,\n{\n    parse(true)\n}\n\n/// Reads bytes from [`stdin`][io::stdin] into a String.\n///\n/// If `read_line` is true, stop at the first newline (the `0xA` byte).\npub fn read(read_line: bool) -> Result<String> {\n    let bytes = read_bytes(read_line)?;\n\n    if read_line {\n        // SAFETY: [BufRead::read_line] appends into a String\n        Ok(unsafe { String::from_utf8_unchecked(bytes) })\n    } else {\n        String::from_utf8(bytes).map_err(Into::into)\n    }\n}\n\n/// Reads bytes from [`stdin`][io::stdin].\n///\n/// If `read_line` is true, read up to the first newline excluded (the `0xA` byte).\npub fn read_bytes(read_line: bool) -> Result<Vec<u8>> {\n    let mut stdin = io::stdin().lock();\n\n    if read_line {\n        let mut buf = String::new();\n        stdin.read_line(&mut buf)?;\n        // remove the trailing newline\n        if let Some(b'\\n') = buf.as_bytes().last() {\n            buf.pop();\n            if let Some(b'\\r') = buf.as_bytes().last() {\n                buf.pop();\n            }\n        }\n        Ok(buf.into_bytes())\n    } else {\n        let mut buf = Vec::new();\n        stdin.read_to_end(&mut buf)?;\n        Ok(buf)\n    }\n}\n"
  },
  {
    "path": "crates/common/src/io/style.rs",
    "content": "#![allow(missing_docs)]\nuse anstyle::*;\n\npub const ERROR: Style = AnsiColor::Red.on_default().effects(Effects::BOLD);\npub const WARN: Style = AnsiColor::Yellow.on_default().effects(Effects::BOLD);\n"
  },
  {
    "path": "crates/common/src/iter.rs",
    "content": "use std::iter::Peekable;\n\npub struct Delimited<I: Iterator> {\n    is_first: bool,\n    iter: Peekable<I>,\n}\n\npub trait IterDelimited: Iterator + Sized {\n    fn delimited(self) -> Delimited<Self> {\n        Delimited { is_first: true, iter: self.peekable() }\n    }\n}\n\nimpl<I: Iterator> IterDelimited for I {}\n\npub struct IteratorPosition {\n    pub is_first: bool,\n    pub is_last: bool,\n}\n\nimpl<I: Iterator> Iterator for Delimited<I> {\n    type Item = (IteratorPosition, I::Item);\n\n    fn next(&mut self) -> Option<Self::Item> {\n        let item = self.iter.next()?;\n        let position =\n            IteratorPosition { is_first: self.is_first, is_last: self.iter.peek().is_none() };\n        self.is_first = false;\n        Some((position, item))\n    }\n}\n"
  },
  {
    "path": "crates/common/src/lib.rs",
    "content": "//! # foundry-common\n//!\n//! Common utilities for building and using foundry's tools.\n\n#![cfg_attr(not(test), warn(unused_crate_dependencies))]\n#![cfg_attr(docsrs, feature(doc_cfg))]\n\n#[expect(unused_extern_crates)] // Used by `ConsoleFmt`.\nextern crate self as foundry_common;\n\n#[macro_use]\nextern crate tracing;\n\n#[macro_use]\npub mod io;\n\npub use foundry_common_fmt as fmt;\n\npub mod abi;\npub mod calc;\npub mod comments;\npub mod compile;\npub mod constants;\npub mod contracts;\npub mod errors;\npub mod fs;\npub mod iter;\npub mod mapping_slots;\nmod preprocessor;\npub mod provider;\npub mod retry;\npub mod selectors;\npub mod serde_helpers;\npub mod slot_identifier;\npub mod term;\npub mod traits;\npub mod transactions;\nmod utils;\npub mod version;\n\npub use compile::Analysis;\npub use constants::*;\npub use contracts::*;\npub use io::{Shell, shell, stdin};\npub use traits::*;\npub use transactions::*;\npub use utils::*;\n"
  },
  {
    "path": "crates/common/src/mapping_slots.rs",
    "content": "use alloy_primitives::{\n    B256, U256, keccak256,\n    map::{AddressHashMap, B256HashMap},\n};\nuse revm::{\n    bytecode::opcode,\n    interpreter::{Interpreter, interpreter_types::Jumps},\n};\n\n/// Recorded mapping slots.\n#[derive(Clone, Debug, Default)]\npub struct MappingSlots {\n    /// Holds mapping parent (slots => slots)\n    pub parent_slots: B256HashMap<B256>,\n\n    /// Holds mapping key (slots => key)\n    pub keys: B256HashMap<B256>,\n\n    /// Holds mapping child (slots => slots[])\n    pub children: B256HashMap<Vec<B256>>,\n\n    /// Holds the last sha3 result `sha3_result => (data_low, data_high)`, this would only record\n    /// when sha3 is called with `size == 0x40`, and the lower 256 bits would be stored in\n    /// `data_low`, higher 256 bits in `data_high`.\n    /// This is needed for mapping_key detect if the slot is for some mapping and record that.\n    pub seen_sha3: B256HashMap<(B256, B256)>,\n}\n\nimpl MappingSlots {\n    /// Tries to insert a mapping slot. Returns true if it was inserted.\n    pub fn insert(&mut self, slot: B256) -> bool {\n        match self.seen_sha3.get(&slot).copied() {\n            Some((key, parent)) => {\n                if self.keys.insert(slot, key).is_some() {\n                    return false;\n                }\n                self.parent_slots.insert(slot, parent);\n                self.children.entry(parent).or_default().push(slot);\n                self.insert(parent);\n                true\n            }\n            None => false,\n        }\n    }\n}\n\n/// Function to be used in Inspector::step to record mapping slots and keys\n#[cold]\npub fn step(mapping_slots: &mut AddressHashMap<MappingSlots>, interpreter: &Interpreter) {\n    #[allow(clippy::collapsible_match)]\n    match interpreter.bytecode.opcode() {\n        opcode::KECCAK256 if interpreter.stack.peek(1) == Ok(U256::from(0x40)) => {\n            let address = interpreter.input.target_address;\n            let offset = interpreter.stack.peek(0).expect(\"stack size > 1\").saturating_to();\n            let data = interpreter.memory.slice_len(offset, 0x40);\n            let low = B256::from_slice(&data[..0x20]);\n            let high = B256::from_slice(&data[0x20..]);\n            let result = keccak256(&*data);\n\n            mapping_slots.entry(address).or_default().seen_sha3.insert(result, (low, high));\n        }\n        opcode::SSTORE => {\n            if let Some(mapping_slots) = mapping_slots.get_mut(&interpreter.input.target_address)\n                && let Ok(slot) = interpreter.stack.peek(0)\n            {\n                mapping_slots.insert(slot.into());\n            }\n        }\n        _ => {}\n    }\n}\n"
  },
  {
    "path": "crates/common/src/preprocessor/data.rs",
    "content": "use super::span_to_range;\nuse foundry_compilers::artifacts::{Source, Sources};\nuse path_slash::PathExt;\nuse solar::sema::{\n    Gcx,\n    hir::{Contract, ContractId},\n    interface::source_map::FileName,\n};\nuse std::{\n    collections::{BTreeMap, HashSet},\n    path::{Path, PathBuf},\n};\n\n/// Keeps data about project contracts definitions referenced from tests and scripts.\n/// Contract id -> Contract data definition mapping.\npub type PreprocessorData = BTreeMap<ContractId, ContractData>;\n\n/// Collects preprocessor data from referenced contracts.\npub(crate) fn collect_preprocessor_data(\n    gcx: Gcx<'_>,\n    referenced_contracts: &HashSet<ContractId>,\n) -> PreprocessorData {\n    let mut data = PreprocessorData::default();\n    for contract_id in referenced_contracts {\n        let contract = gcx.hir.contract(*contract_id);\n        let source = gcx.hir.source(contract.source);\n\n        let FileName::Real(path) = &source.file.name else {\n            continue;\n        };\n\n        let contract_data = ContractData::new(gcx, *contract_id, contract, path, source);\n        data.insert(*contract_id, contract_data);\n    }\n    data\n}\n\n/// Creates helper libraries for contracts with a non-empty constructor.\n///\n/// See [`ContractData::build_helper`] for more details.\npub(crate) fn create_deploy_helpers(data: &BTreeMap<ContractId, ContractData>) -> Sources {\n    let mut deploy_helpers = Sources::new();\n    for (contract_id, contract) in data {\n        if let Some(code) = contract.build_helper() {\n            let path = format!(\"foundry-pp/DeployHelper{}.sol\", contract_id.get());\n            deploy_helpers.insert(path.into(), Source::new(code));\n        }\n    }\n    deploy_helpers\n}\n\n/// Keeps data about a contract constructor.\n#[derive(Debug)]\npub struct ContractConstructorData {\n    /// ABI encoded args.\n    pub abi_encode_args: String,\n    /// Constructor struct fields.\n    pub struct_fields: String,\n}\n\n/// Keeps data about a single contract definition.\n#[derive(Debug)]\npub(crate) struct ContractData {\n    /// HIR Id of the contract.\n    contract_id: ContractId,\n    /// Path of the source file.\n    path: PathBuf,\n    /// Name of the contract\n    name: String,\n    /// Constructor parameters, if any.\n    pub constructor_data: Option<ContractConstructorData>,\n    /// Artifact string to pass into cheatcodes.\n    pub artifact: String,\n}\n\nimpl ContractData {\n    fn new(\n        gcx: Gcx<'_>,\n        contract_id: ContractId,\n        contract: &Contract<'_>,\n        path: &Path,\n        source: &solar::sema::hir::Source<'_>,\n    ) -> Self {\n        let artifact = format!(\"{}:{}\", path.to_slash_lossy(), contract.name);\n\n        // Process data for contracts with constructor and parameters.\n        let constructor_data = contract\n            .ctor\n            .map(|ctor_id| gcx.hir.function(ctor_id))\n            .filter(|ctor| !ctor.parameters.is_empty())\n            .map(|ctor| {\n                let mut abi_encode_args = vec![];\n                let mut struct_fields = vec![];\n                let mut arg_index = 0;\n                for param_id in ctor.parameters {\n                    let src = source.file.src.as_str();\n                    let loc =\n                        span_to_range(gcx.sess.source_map(), gcx.hir.variable(*param_id).span);\n                    let mut new_src = src[loc].replace(\" memory \", \" \").replace(\" calldata \", \" \");\n                    if let Some(ident) = gcx.hir.variable(*param_id).name {\n                        abi_encode_args.push(format!(\"args.{}\", ident.name));\n                    } else {\n                        // Generate an unique name if constructor arg doesn't have one.\n                        arg_index += 1;\n                        abi_encode_args.push(format!(\"args.foundry_pp_ctor_arg{arg_index}\"));\n                        new_src.push_str(&format!(\" foundry_pp_ctor_arg{arg_index}\"));\n                    }\n                    struct_fields.push(new_src);\n                }\n\n                ContractConstructorData {\n                    abi_encode_args: abi_encode_args.join(\", \"),\n                    struct_fields: struct_fields.join(\"; \"),\n                }\n            });\n\n        Self {\n            contract_id,\n            path: path.to_path_buf(),\n            name: contract.name.to_string(),\n            constructor_data,\n            artifact,\n        }\n    }\n\n    /// If contract has a non-empty constructor, generates a helper source file for it containing a\n    /// helper to encode constructor arguments.\n    ///\n    /// This is needed because current preprocessing wraps the arguments, leaving them unchanged.\n    /// This allows us to handle nested new expressions correctly. However, this requires us to have\n    /// a way to wrap both named and unnamed arguments. i.e you can't do abi.encode({arg: val}).\n    ///\n    /// This function produces a helper struct + a helper function to encode the arguments. The\n    /// struct is defined in scope of an abstract contract inheriting the contract containing the\n    /// constructor. This is done as a hack to allow us to inherit the same scope of definitions.\n    ///\n    /// The resulted helper looks like this:\n    /// ```solidity\n    /// import \"lib/openzeppelin-contracts/contracts/token/ERC20.sol\";\n    ///\n    /// abstract contract DeployHelper335 is ERC20 {\n    ///     struct FoundryPpConstructorArgs {\n    ///         string name;\n    ///         string symbol;\n    ///     }\n    /// }\n    ///\n    /// function encodeArgs335(DeployHelper335.FoundryPpConstructorArgs memory args) pure returns (bytes memory) {\n    ///     return abi.encode(args.name, args.symbol);\n    /// }\n    /// ```\n    ///\n    /// Example usage:\n    /// ```solidity\n    /// new ERC20(name, symbol)\n    /// ```\n    /// becomes\n    /// ```solidity\n    /// vm.deployCode(\"artifact path\", encodeArgs335(DeployHelper335.FoundryPpConstructorArgs(name, symbol)))\n    /// ```\n    /// With named arguments:\n    /// ```solidity\n    /// new ERC20({name: name, symbol: symbol})\n    /// ```\n    /// becomes\n    /// ```solidity\n    /// vm.deployCode(\"artifact path\", encodeArgs335(DeployHelper335.FoundryPpConstructorArgs({name: name, symbol: symbol})))\n    /// ```\n    pub fn build_helper(&self) -> Option<String> {\n        let Self { contract_id, path, name, constructor_data, artifact: _ } = self;\n\n        let Some(constructor_details) = constructor_data else { return None };\n        let contract_id = contract_id.get();\n        let struct_fields = &constructor_details.struct_fields;\n        let abi_encode_args = &constructor_details.abi_encode_args;\n\n        let helper = format!(\n            r#\"\n// SPDX-License-Identifier: MIT\npragma solidity >=0.4.0;\n\nimport \"{path}\";\n\nabstract contract DeployHelper{contract_id} is {name} {{\n    struct FoundryPpConstructorArgs {{\n        {struct_fields};\n    }}\n}}\n\nfunction encodeArgs{contract_id}(DeployHelper{contract_id}.FoundryPpConstructorArgs memory args) pure returns (bytes memory) {{\n    return abi.encode({abi_encode_args});\n}}\n        \"#,\n            path = path.to_slash_lossy(),\n        );\n\n        Some(helper)\n    }\n}\n"
  },
  {
    "path": "crates/common/src/preprocessor/deps.rs",
    "content": "use super::{\n    data::{ContractData, PreprocessorData},\n    span_to_range,\n};\nuse foundry_compilers::Updates;\nuse itertools::Itertools;\nuse solar::sema::{\n    Gcx, Hir,\n    hir::{CallArgs, ContractId, Expr, ExprKind, NamedArg, Stmt, StmtKind, TypeKind, Visit},\n    interface::{SourceMap, data_structures::Never, source_map::FileName},\n};\nuse std::{\n    collections::{BTreeMap, BTreeSet, HashSet},\n    ops::{ControlFlow, Range},\n    path::{Path, PathBuf},\n};\n\n/// Holds data about referenced source contracts and bytecode dependencies.\npub(crate) struct PreprocessorDependencies {\n    // Mapping contract id to preprocess -> contract bytecode dependencies.\n    pub preprocessed_contracts: BTreeMap<ContractId, Vec<BytecodeDependency>>,\n    // Referenced contract ids.\n    pub referenced_contracts: HashSet<ContractId>,\n}\n\nimpl PreprocessorDependencies {\n    pub fn new(\n        gcx: Gcx<'_>,\n        paths: &[PathBuf],\n        src_dir: &Path,\n        root_dir: &Path,\n        mocks: &mut HashSet<PathBuf>,\n    ) -> Self {\n        let mut preprocessed_contracts = BTreeMap::new();\n        let mut referenced_contracts = HashSet::new();\n        let mut current_mocks = HashSet::new();\n\n        // Helper closure for iterating candidate contracts to preprocess (tests and scripts).\n        let candidate_contracts = || {\n            gcx.hir.contract_ids().filter_map(|id| {\n                let contract = gcx.hir.contract(id);\n                let source = gcx.hir.source(contract.source);\n                let FileName::Real(path) = &source.file.name else {\n                    return None;\n                };\n\n                if !paths.contains(path) {\n                    trace!(\"{} is not test or script\", path.display());\n                    return None;\n                }\n\n                Some((id, contract, source, path))\n            })\n        };\n\n        // Collect current mocks.\n        for (_, contract, _, path) in candidate_contracts() {\n            if contract.linearized_bases.iter().any(|base_id| {\n                let base = gcx.hir.contract(*base_id);\n                matches!(\n                    &gcx.hir.source(base.source).file.name,\n                    FileName::Real(base_path) if base_path.starts_with(src_dir)\n                )\n            }) {\n                let mock_path = root_dir.join(path);\n                trace!(\"found mock contract {}\", mock_path.display());\n                current_mocks.insert(mock_path);\n            }\n        }\n\n        // Collect dependencies for non-mock test/script contracts.\n        for (contract_id, contract, source, path) in candidate_contracts() {\n            let full_path = root_dir.join(path);\n\n            if current_mocks.contains(&full_path) {\n                trace!(\"{} is a mock, skipping\", path.display());\n                continue;\n            }\n\n            // Make sure current contract is not in list of mocks (could happen when a contract\n            // which used to be a mock is refactored to a non-mock implementation).\n            mocks.remove(&full_path);\n\n            let mut deps_collector =\n                BytecodeDependencyCollector::new(gcx, source.file.src.as_str(), src_dir);\n            // Analyze current contract.\n            let _ = deps_collector.walk_contract(contract);\n            // Ignore empty test contracts declared in source files with other contracts.\n            if !deps_collector.dependencies.is_empty() {\n                preprocessed_contracts.insert(contract_id, deps_collector.dependencies);\n            }\n\n            // Record collected referenced contract ids.\n            referenced_contracts.extend(deps_collector.referenced_contracts);\n        }\n\n        // Add current mocks.\n        mocks.extend(current_mocks);\n\n        Self { preprocessed_contracts, referenced_contracts }\n    }\n}\n\n/// Represents a bytecode dependency kind.\n#[derive(Debug)]\nenum BytecodeDependencyKind {\n    /// `type(Contract).creationCode`\n    CreationCode,\n    /// `new Contract`.\n    New {\n        /// Contract name.\n        name: String,\n        /// Constructor args length.\n        args_length: usize,\n        /// Constructor call args offset.\n        call_args_offset: usize,\n        /// `msg.value` (if any) used when creating contract.\n        value: Option<String>,\n        /// `salt` (if any) used when creating contract.\n        salt: Option<String>,\n        /// Whether it's a try contract creation statement, with custom return.\n        try_stmt: Option<bool>,\n    },\n}\n\n/// Represents a single bytecode dependency.\n#[derive(Debug)]\npub(crate) struct BytecodeDependency {\n    /// Dependency kind.\n    kind: BytecodeDependencyKind,\n    /// Source map location of this dependency.\n    loc: Range<usize>,\n    /// HIR id of referenced contract.\n    referenced_contract: ContractId,\n}\n\n/// Walks over contract HIR and collects [`BytecodeDependency`]s and referenced contracts.\nstruct BytecodeDependencyCollector<'gcx, 'src> {\n    /// Source map, used for determining contract item locations.\n    gcx: Gcx<'gcx>,\n    /// Source content of current contract.\n    src: &'src str,\n    /// Project source dir, used to determine if referenced contract is a source contract.\n    src_dir: &'src Path,\n    /// Dependencies collected for current contract.\n    dependencies: Vec<BytecodeDependency>,\n    /// Unique HIR ids of contracts referenced from current contract.\n    referenced_contracts: HashSet<ContractId>,\n}\n\nimpl<'gcx, 'src> BytecodeDependencyCollector<'gcx, 'src> {\n    fn new(gcx: Gcx<'gcx>, src: &'src str, src_dir: &'src Path) -> Self {\n        Self { gcx, src, src_dir, dependencies: vec![], referenced_contracts: HashSet::default() }\n    }\n\n    /// Collects reference identified as bytecode dependency of analyzed contract.\n    /// Discards any reference that is not in project src directory (e.g. external\n    /// libraries or mock contracts that extend source contracts).\n    fn collect_dependency(&mut self, dependency: BytecodeDependency) {\n        let contract = self.gcx.hir.contract(dependency.referenced_contract);\n        let source = self.gcx.hir.source(contract.source);\n        let FileName::Real(path) = &source.file.name else {\n            return;\n        };\n\n        if !path.starts_with(self.src_dir) {\n            let path = path.display();\n            trace!(\"ignore dependency {path}\");\n            return;\n        }\n\n        self.referenced_contracts.insert(dependency.referenced_contract);\n        self.dependencies.push(dependency);\n    }\n}\n\nimpl<'gcx> Visit<'gcx> for BytecodeDependencyCollector<'gcx, '_> {\n    type BreakValue = Never;\n\n    fn hir(&self) -> &'gcx Hir<'gcx> {\n        &self.gcx.hir\n    }\n\n    fn visit_expr(&mut self, expr: &'gcx Expr<'gcx>) -> ControlFlow<Self::BreakValue> {\n        #[allow(clippy::collapsible_match)]\n        match &expr.kind {\n            ExprKind::Call(call_expr, call_args, named_args) => {\n                if let Some(dependency) = handle_call_expr(\n                    self.src,\n                    self.gcx.sess.source_map(),\n                    expr,\n                    call_expr,\n                    call_args,\n                    named_args,\n                ) {\n                    self.collect_dependency(dependency);\n                }\n            }\n            ExprKind::Member(member_expr, ident) => {\n                if let ExprKind::TypeCall(ty) = &member_expr.kind\n                    && let TypeKind::Custom(contract_id) = &ty.kind\n                    && ident.name.as_str() == \"creationCode\"\n                    && let Some(contract_id) = contract_id.as_contract()\n                {\n                    self.collect_dependency(BytecodeDependency {\n                        kind: BytecodeDependencyKind::CreationCode,\n                        loc: span_to_range(self.gcx.sess.source_map(), expr.span),\n                        referenced_contract: contract_id,\n                    });\n                }\n            }\n            _ => {}\n        }\n        self.walk_expr(expr)\n    }\n\n    fn visit_stmt(&mut self, stmt: &'gcx Stmt<'gcx>) -> ControlFlow<Self::BreakValue> {\n        if let StmtKind::Try(stmt_try) = stmt.kind\n            && let ExprKind::Call(call_expr, call_args, named_args) = &stmt_try.expr.kind\n            && let Some(mut dependency) = handle_call_expr(\n                self.src,\n                self.gcx.sess.source_map(),\n                &stmt_try.expr,\n                call_expr,\n                call_args,\n                named_args,\n            )\n        {\n            let has_custom_return = if let Some(clause) = stmt_try.clauses.first()\n                && clause.args.len() == 1\n                && let Some(ret_var) = clause.args.first()\n                && let TypeKind::Custom(_) = self.hir().variable(*ret_var).ty.kind\n            {\n                true\n            } else {\n                false\n            };\n\n            if let BytecodeDependencyKind::New { try_stmt, .. } = &mut dependency.kind {\n                *try_stmt = Some(has_custom_return);\n            }\n            self.collect_dependency(dependency);\n\n            for clause in stmt_try.clauses {\n                for &var in clause.args {\n                    self.visit_nested_var(var)?;\n                }\n                for stmt in clause.block.stmts {\n                    self.visit_stmt(stmt)?;\n                }\n            }\n            return ControlFlow::Continue(());\n        }\n        self.walk_stmt(stmt)\n    }\n}\n\n/// Helper function to analyze and extract bytecode dependency from a given call expression.\nfn handle_call_expr(\n    src: &str,\n    source_map: &SourceMap,\n    parent_expr: &Expr<'_>,\n    call_expr: &Expr<'_>,\n    call_args: &CallArgs<'_>,\n    named_args: &Option<&[NamedArg<'_>]>,\n) -> Option<BytecodeDependency> {\n    if let ExprKind::New(ty_new) = &call_expr.kind\n        && let TypeKind::Custom(item_id) = ty_new.kind\n        && let Some(contract_id) = item_id.as_contract()\n    {\n        let name_loc = span_to_range(source_map, ty_new.span);\n        let name = &src[name_loc];\n\n        // Calculate offset to remove named args, e.g. for an expression like\n        // `new Counter {value: 333} (  address(this))`\n        // the offset will be used to replace `{value: 333} (  ` with `(`\n        let call_args_offset = if named_args.is_some() && !call_args.is_empty() {\n            (call_args.span.lo() - ty_new.span.hi()).to_usize()\n        } else {\n            0\n        };\n\n        let args_len = parent_expr.span.hi() - ty_new.span.hi();\n        return Some(BytecodeDependency {\n            kind: BytecodeDependencyKind::New {\n                name: name.to_string(),\n                args_length: args_len.to_usize(),\n                call_args_offset,\n                value: named_arg(src, named_args, \"value\", source_map),\n                salt: named_arg(src, named_args, \"salt\", source_map),\n                try_stmt: None,\n            },\n            loc: span_to_range(source_map, call_expr.span),\n            referenced_contract: contract_id,\n        });\n    }\n    None\n}\n\n/// Helper function to extract value of a given named arg.\nfn named_arg(\n    src: &str,\n    named_args: &Option<&[NamedArg<'_>]>,\n    arg: &str,\n    source_map: &SourceMap,\n) -> Option<String> {\n    named_args.unwrap_or_default().iter().find(|named_arg| named_arg.name.as_str() == arg).map(\n        |named_arg| {\n            let named_arg_loc = span_to_range(source_map, named_arg.value.span);\n            src[named_arg_loc].to_string()\n        },\n    )\n}\n\n/// Goes over all test/script files and replaces bytecode dependencies with cheatcode\n/// invocations.\n///\n/// Special handling of try/catch statements with custom returns, where the try statement becomes\n/// ```solidity\n/// try this.addressToCounter() returns (Counter c)\n/// ```\n/// and helper to cast address is appended\n/// ```solidity\n/// function addressToCounter(address addr) returns (Counter) {\n///     return Counter(addr);\n/// }\n/// ```\npub(crate) fn remove_bytecode_dependencies(\n    gcx: Gcx<'_>,\n    deps: &PreprocessorDependencies,\n    data: &PreprocessorData,\n) -> Updates {\n    let mut updates = Updates::default();\n    for (contract_id, deps) in &deps.preprocessed_contracts {\n        let contract = gcx.hir.contract(*contract_id);\n        let source = gcx.hir.source(contract.source);\n        let FileName::Real(path) = &source.file.name else {\n            continue;\n        };\n\n        let updates = updates.entry(path.clone()).or_default();\n        let mut used_helpers = BTreeSet::new();\n\n        let vm_interface_name = format!(\"VmContractHelper{}\", contract_id.get());\n        // `address(uint160(uint256(keccak256(\"hevm cheat code\"))))`\n        let vm = format!(\"{vm_interface_name}(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D)\");\n        let mut try_catch_helpers: HashSet<&str> = HashSet::default();\n\n        for dep in deps {\n            let Some(ContractData { artifact, constructor_data, .. }) =\n                data.get(&dep.referenced_contract)\n            else {\n                continue;\n            };\n\n            match &dep.kind {\n                BytecodeDependencyKind::CreationCode => {\n                    // for creation code we need to just call getCode\n                    updates.insert((\n                        dep.loc.start,\n                        dep.loc.end,\n                        format!(\"{vm}.getCode(\\\"{artifact}\\\")\"),\n                    ));\n                }\n                BytecodeDependencyKind::New {\n                    name,\n                    args_length,\n                    call_args_offset,\n                    value,\n                    salt,\n                    try_stmt,\n                } => {\n                    let (mut update, closing_seq) = if let Some(has_ret) = try_stmt {\n                        if *has_ret {\n                            // try this.addressToCounter1() returns (Counter c)\n                            try_catch_helpers.insert(name);\n                            (format!(\"this.addressTo{name}{id}(\", id = contract_id.get()), \"}))\")\n                        } else {\n                            (String::new(), \"})\")\n                        }\n                    } else {\n                        (format!(\"{name}(payable(\"), \"})))\")\n                    };\n                    update.push_str(&format!(\"{vm}.deployCode({{\"));\n                    update.push_str(&format!(\"_artifact: \\\"{artifact}\\\"\"));\n\n                    if let Some(value) = value {\n                        update.push_str(\", \");\n                        update.push_str(&format!(\"_value: {value}\"));\n                    }\n\n                    if let Some(salt) = salt {\n                        update.push_str(\", \");\n                        update.push_str(&format!(\"_salt: {salt}\"));\n                    }\n\n                    if constructor_data.is_some() {\n                        // Insert our helper\n                        used_helpers.insert(dep.referenced_contract);\n\n                        update.push_str(\", \");\n                        update.push_str(&format!(\n                            \"_args: encodeArgs{id}(DeployHelper{id}.FoundryPpConstructorArgs\",\n                            id = dep.referenced_contract.get()\n                        ));\n                        updates.insert((dep.loc.start, dep.loc.end + call_args_offset, update));\n\n                        updates.insert((\n                            dep.loc.end + args_length,\n                            dep.loc.end + args_length,\n                            format!(\"){closing_seq}\"),\n                        ));\n                    } else {\n                        update.push_str(closing_seq);\n                        updates.insert((dep.loc.start, dep.loc.end + args_length, update));\n                    }\n                }\n            };\n        }\n\n        // Add try catch statements after last function of the test contract.\n        if !try_catch_helpers.is_empty()\n            && let Some(last_fn_id) = contract.functions().last()\n        {\n            let last_fn_range =\n                span_to_range(gcx.sess.source_map(), gcx.hir.function(last_fn_id).span);\n            let to_address_fns = try_catch_helpers\n                .iter()\n                .map(|ty| {\n                    format!(\n                        r#\"\n                            function addressTo{ty}{id}(address addr) public pure returns ({ty}) {{\n                                return {ty}(addr);\n                            }}\n                        \"#,\n                        id = contract_id.get()\n                    )\n                })\n                .collect::<String>();\n\n            updates.insert((last_fn_range.end, last_fn_range.end, to_address_fns));\n        }\n\n        let helper_imports = used_helpers.into_iter().map(|id| {\n            let id = id.get();\n            format!(\n                \"import {{DeployHelper{id}, encodeArgs{id}}} from \\\"foundry-pp/DeployHelper{id}.sol\\\";\",\n            )\n        }).join(\"\\n\");\n        updates.insert((\n            source.file.src.len(),\n            source.file.src.len(),\n            format!(\n                r#\"\n{helper_imports}\n\ninterface {vm_interface_name} {{\n    function deployCode(string memory _artifact) external returns (address);\n    function deployCode(string memory _artifact, bytes32 _salt) external returns (address);\n    function deployCode(string memory _artifact, bytes memory _args) external returns (address);\n    function deployCode(string memory _artifact, bytes memory _args, bytes32 _salt) external returns (address);\n    function deployCode(string memory _artifact, uint256 _value) external returns (address);\n    function deployCode(string memory _artifact, uint256 _value, bytes32 _salt) external returns (address);\n    function deployCode(string memory _artifact, bytes memory _args, uint256 _value) external returns (address);\n    function deployCode(string memory _artifact, bytes memory _args, uint256 _value, bytes32 _salt) external returns (address);\n    function getCode(string memory _artifact) external view returns (bytes memory);\n}}\"#\n            ),\n        ));\n    }\n    updates\n}\n"
  },
  {
    "path": "crates/common/src/preprocessor/mod.rs",
    "content": "use crate::errors::convert_solar_errors;\nuse foundry_compilers::{\n    Compiler, ProjectPathsConfig, SourceParser, apply_updates,\n    artifacts::SolcLanguage,\n    error::Result,\n    multi::{MultiCompiler, MultiCompilerInput, MultiCompilerLanguage},\n    project::Preprocessor,\n    solc::{SolcCompiler, SolcVersionedInput},\n};\nuse solar::parse::{ast::Span, interface::SourceMap};\nuse std::{\n    collections::HashSet,\n    ops::{ControlFlow, Range},\n    path::PathBuf,\n};\n\nmod data;\nuse data::{collect_preprocessor_data, create_deploy_helpers};\n\nmod deps;\nuse deps::{PreprocessorDependencies, remove_bytecode_dependencies};\n\n/// Returns the range of the given span in the source map.\n#[track_caller]\nfn span_to_range(source_map: &SourceMap, span: Span) -> Range<usize> {\n    source_map.span_to_range(span).unwrap()\n}\n\n/// Preprocessor that replaces static bytecode linking in tests and scripts (`new Contract`) with\n/// dynamic linkage through (`Vm.create*`).\n///\n/// This allows for more efficient caching when iterating on tests.\n///\n/// See <https://github.com/foundry-rs/foundry/pull/10010>.\n#[derive(Debug)]\npub struct DynamicTestLinkingPreprocessor;\n\nimpl Preprocessor<SolcCompiler> for DynamicTestLinkingPreprocessor {\n    #[instrument(name = \"DynamicTestLinkingPreprocessor::preprocess\", skip_all)]\n    fn preprocess(\n        &self,\n        _solc: &SolcCompiler,\n        input: &mut SolcVersionedInput,\n        paths: &ProjectPathsConfig<SolcLanguage>,\n        mocks: &mut HashSet<PathBuf>,\n    ) -> Result<()> {\n        // Skip if we are not preprocessing any tests or scripts. Avoids unnecessary AST parsing.\n        if !input.input.sources.iter().any(|(path, _)| paths.is_test_or_script(path)) {\n            trace!(\"no tests or scripts to preprocess\");\n            return Ok(());\n        }\n\n        let mut compiler =\n            foundry_compilers::resolver::parse::SolParser::new(paths.with_language_ref())\n                .into_compiler();\n        let _ = compiler.enter_mut(|compiler| -> solar::interface::Result {\n            let mut pcx = compiler.parse();\n\n            // Add the sources into the context.\n            // Include all sources in the source map so as to not re-load them from disk, but only\n            // parse and preprocess tests and scripts.\n            let mut preprocessed_paths = vec![];\n            let sources = &mut input.input.sources;\n            for (path, source) in sources.iter() {\n                if let Ok(src_file) = compiler\n                    .sess()\n                    .source_map()\n                    .new_source_file(path.clone(), source.content.as_str())\n                    && paths.is_test_or_script(path)\n                {\n                    pcx.add_file(src_file);\n                    preprocessed_paths.push(path.clone());\n                }\n            }\n\n            // Parse and preprocess.\n            pcx.parse();\n            let ControlFlow::Continue(()) = compiler.lower_asts()? else { return Ok(()) };\n            let gcx = compiler.gcx();\n            // Collect tests and scripts dependencies and identify mock contracts.\n            let deps = PreprocessorDependencies::new(\n                gcx,\n                &preprocessed_paths,\n                &paths.paths_relative().sources,\n                &paths.root,\n                mocks,\n            );\n            // Collect data of source contracts referenced in tests and scripts.\n            let data = collect_preprocessor_data(gcx, &deps.referenced_contracts);\n\n            // Extend existing sources with preprocessor deploy helper sources.\n            sources.extend(create_deploy_helpers(&data));\n\n            // Generate and apply preprocessor source updates.\n            apply_updates(sources, remove_bytecode_dependencies(gcx, &deps, &data));\n\n            Ok(())\n        });\n\n        // Warn if any diagnostics emitted during content parsing.\n        if let Err(err) = convert_solar_errors(compiler.dcx()) {\n            warn!(%err, \"failed preprocessing\");\n        }\n\n        Ok(())\n    }\n}\n\nimpl Preprocessor<MultiCompiler> for DynamicTestLinkingPreprocessor {\n    fn preprocess(\n        &self,\n        compiler: &MultiCompiler,\n        input: &mut <MultiCompiler as Compiler>::Input,\n        paths: &ProjectPathsConfig<MultiCompilerLanguage>,\n        mocks: &mut HashSet<PathBuf>,\n    ) -> Result<()> {\n        // Preprocess only Solc compilers.\n        let MultiCompilerInput::Solc(input) = input else { return Ok(()) };\n\n        let Some(solc) = &compiler.solc else { return Ok(()) };\n\n        let paths = paths.clone().with_language::<SolcLanguage>();\n        self.preprocess(solc, input, &paths, mocks)\n    }\n}\n"
  },
  {
    "path": "crates/common/src/provider/curl_transport.rs",
    "content": "//! Transport that outputs equivalent curl commands instead of making RPC requests.\n\nuse alloy_json_rpc::{RequestPacket, ResponsePacket};\nuse alloy_transport::{TransportError, TransportFut};\nuse serde_json::Value;\nuse tower::Service;\nuse url::Url;\n\n/// Escapes a string for use in a single-quoted shell argument.\nfn shell_escape(s: &str) -> String {\n    s.replace('\\'', \"'\\\"'\\\"'\")\n}\n\n/// Generates a curl command for an RPC request.\n///\n/// This is a standalone helper that can be used to generate curl commands\n/// without going through the transport layer.\npub fn generate_curl_command(\n    url: &str,\n    method: &str,\n    params: Value,\n    headers: Option<&[String]>,\n    jwt: Option<&str>,\n) -> String {\n    let payload = serde_json::json!({\n        \"jsonrpc\": \"2.0\",\n        \"method\": method,\n        \"params\": params,\n        \"id\": 1\n    });\n    let payload_str = serde_json::to_string(&payload).unwrap_or_default();\n    let escaped_payload = shell_escape(&payload_str);\n\n    let mut cmd = String::from(\"curl -X POST\");\n    cmd.push_str(\" -H 'Content-Type: application/json'\");\n\n    if let Some(jwt) = jwt {\n        cmd.push_str(&format!(\" -H 'Authorization: Bearer {}'\", shell_escape(jwt)));\n    }\n\n    if let Some(hdrs) = headers {\n        for h in hdrs {\n            cmd.push_str(&format!(\" -H '{}'\", shell_escape(h)));\n        }\n    }\n\n    cmd.push_str(&format!(\" --data-raw '{escaped_payload}'\"));\n    cmd.push_str(&format!(\" '{}'\", shell_escape(url)));\n\n    cmd\n}\n\n/// A transport that prints curl commands instead of executing RPC requests.\n///\n/// When a request is made through this transport, it will print the equivalent\n/// curl command to stderr and return a dummy successful response.\n#[derive(Clone, Debug)]\npub struct CurlTransport {\n    /// The URL to connect to.\n    url: Url,\n    /// The headers to use for requests.\n    headers: Vec<String>,\n    /// The JWT to use for requests.\n    jwt: Option<String>,\n}\n\nimpl CurlTransport {\n    /// Create a new curl transport with the given URL.\n    pub fn new(url: Url) -> Self {\n        Self { url, headers: vec![], jwt: None }\n    }\n\n    /// Set the headers for the transport.\n    pub fn with_headers(mut self, headers: Vec<String>) -> Self {\n        self.headers = headers;\n        self\n    }\n\n    /// Set the JWT for the transport.\n    pub fn with_jwt(mut self, jwt: Option<String>) -> Self {\n        self.jwt = jwt;\n        self\n    }\n\n    /// Generate a curl command for a request.\n    fn generate_curl_command(&self, req: &RequestPacket) -> String {\n        let payload_str = serde_json::to_string(req).unwrap_or_default();\n        let escaped_payload = shell_escape(&payload_str);\n\n        let mut cmd = String::from(\"curl -X POST\");\n        cmd.push_str(\" -H 'Content-Type: application/json'\");\n\n        if let Some(jwt) = &self.jwt {\n            cmd.push_str(&format!(\" -H 'Authorization: Bearer {}'\", shell_escape(jwt)));\n        }\n\n        for h in &self.headers {\n            cmd.push_str(&format!(\" -H '{}'\", shell_escape(h)));\n        }\n\n        cmd.push_str(&format!(\" --data-raw '{escaped_payload}'\"));\n        cmd.push_str(&format!(\" '{}'\", shell_escape(self.url.as_str())));\n\n        cmd\n    }\n\n    /// Handle a request by printing the curl command.\n    pub fn request(&self, req: RequestPacket) -> TransportFut<'static> {\n        let curl_cmd = self.generate_curl_command(&req);\n\n        Box::pin(async move {\n            // Print the curl command to stdout\n            let _ = crate::sh_println!(\"{curl_cmd}\");\n\n            // Exit cleanly after printing the curl command\n            std::process::exit(0);\n        })\n    }\n}\n\nimpl Service<RequestPacket> for CurlTransport {\n    type Response = ResponsePacket;\n    type Error = TransportError;\n    type Future = TransportFut<'static>;\n\n    #[inline]\n    fn poll_ready(\n        &mut self,\n        _cx: &mut std::task::Context<'_>,\n    ) -> std::task::Poll<Result<(), Self::Error>> {\n        std::task::Poll::Ready(Ok(()))\n    }\n\n    #[inline]\n    fn call(&mut self, req: RequestPacket) -> Self::Future {\n        self.request(req)\n    }\n}\n\nimpl Service<RequestPacket> for &CurlTransport {\n    type Response = ResponsePacket;\n    type Error = TransportError;\n    type Future = TransportFut<'static>;\n\n    #[inline]\n    fn poll_ready(\n        &mut self,\n        _cx: &mut std::task::Context<'_>,\n    ) -> std::task::Poll<Result<(), Self::Error>> {\n        std::task::Poll::Ready(Ok(()))\n    }\n\n    #[inline]\n    fn call(&mut self, req: RequestPacket) -> Self::Future {\n        self.request(req)\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use alloy_json_rpc::{Id, Request};\n\n    fn make_test_request() -> RequestPacket {\n        let req: Request<Vec<()>> = Request::new(\"eth_blockNumber\", Id::Number(1), vec![]);\n        let serialized = req.serialize().unwrap();\n        RequestPacket::Single(serialized)\n    }\n\n    #[test]\n    fn test_basic_curl_command() {\n        let transport = CurlTransport::new(\"https://eth.example.com\".parse().unwrap());\n        let req = make_test_request();\n        let cmd = transport.generate_curl_command(&req);\n        assert!(cmd.contains(\"eth_blockNumber\"));\n        assert!(cmd.contains(\"https://eth.example.com\"));\n        assert!(cmd.contains(\"jsonrpc\"));\n    }\n\n    #[test]\n    fn test_curl_with_headers() {\n        let transport = CurlTransport::new(\"https://eth.example.com\".parse().unwrap())\n            .with_headers(vec![\"X-Custom: value\".to_string()]);\n        let req = make_test_request();\n        let cmd = transport.generate_curl_command(&req);\n        assert!(cmd.contains(\"X-Custom: value\"));\n    }\n\n    #[test]\n    fn test_curl_with_jwt() {\n        let transport = CurlTransport::new(\"https://eth.example.com\".parse().unwrap())\n            .with_jwt(Some(\"my-jwt-token\".to_string()));\n        let req = make_test_request();\n        let cmd = transport.generate_curl_command(&req);\n        assert!(cmd.contains(\"Authorization: Bearer my-jwt-token\"));\n    }\n\n    #[test]\n    fn test_shell_escape() {\n        let escaped = shell_escape(\"it's a test\");\n        assert_eq!(escaped, \"it'\\\"'\\\"'s a test\");\n    }\n}\n"
  },
  {
    "path": "crates/common/src/provider/mod.rs",
    "content": "//! Provider-related instantiation and usage utilities.\n\npub mod curl_transport;\npub mod runtime_transport;\n\nuse crate::{\n    ALCHEMY_FREE_TIER_CUPS, REQUEST_TIMEOUT,\n    provider::{curl_transport::CurlTransport, runtime_transport::RuntimeTransportBuilder},\n};\nuse alloy_chains::NamedChain;\nuse alloy_network::{Network, NetworkWallet};\nuse alloy_provider::{\n    Identity, ProviderBuilder as AlloyProviderBuilder, RootProvider,\n    fillers::{FillProvider, JoinFill, RecommendedFillers, WalletFiller},\n    network::{AnyNetwork, EthereumWallet},\n};\nuse alloy_rpc_client::ClientBuilder;\nuse alloy_transport::{layers::RetryBackoffLayer, utils::guess_local_url};\nuse eyre::{Result, WrapErr};\nuse foundry_config::Config;\nuse reqwest::Url;\nuse std::{\n    marker::PhantomData,\n    net::SocketAddr,\n    path::{Path, PathBuf},\n    str::FromStr,\n    time::Duration,\n};\nuse url::ParseError;\n\n/// The assumed block time for unknown chains.\n/// We assume that these are chains have a faster block time.\nconst DEFAULT_UNKNOWN_CHAIN_BLOCK_TIME: Duration = Duration::from_secs(3);\n\n/// The factor to scale the block time by to get the poll interval.\nconst POLL_INTERVAL_BLOCK_TIME_SCALE_FACTOR: f32 = 0.6;\n\n/// Helper type alias for a retry provider\npub type RetryProvider<N = AnyNetwork> = RootProvider<N>;\n\n/// Helper type alias for a retry provider with a signer\npub type RetryProviderWithSigner<N = AnyNetwork, W = EthereumWallet> = FillProvider<\n    JoinFill<JoinFill<Identity, <N as RecommendedFillers>::RecommendedFillers>, WalletFiller<W>>,\n    RootProvider<N>,\n    N,\n>;\n\n/// Constructs a provider with a 100 millisecond interval poll if it's a localhost URL (most likely\n/// an anvil or other dev node) and with the default, or 7 second otherwise.\n///\n/// See [`try_get_http_provider`] for more details.\n///\n/// # Panics\n///\n/// Panics if the URL is invalid.\n///\n/// # Examples\n///\n/// ```\n/// use foundry_common::provider::get_http_provider;\n///\n/// let retry_provider = get_http_provider(\"http://localhost:8545\");\n/// ```\n#[inline]\n#[track_caller]\npub fn get_http_provider(builder: impl AsRef<str>) -> RetryProvider {\n    try_get_http_provider(builder).unwrap()\n}\n\n/// Constructs a provider with a 100 millisecond interval poll if it's a localhost URL (most likely\n/// an anvil or other dev node) and with the default, or 7 second otherwise.\n#[inline]\npub fn try_get_http_provider(builder: impl AsRef<str>) -> Result<RetryProvider> {\n    ProviderBuilder::new(builder.as_ref()).build()\n}\n\n/// Helper type to construct a `RetryProvider`\n///\n/// This builder is generic over the network type `N`, defaulting to `AnyNetwork`.\n#[derive(Debug)]\npub struct ProviderBuilder<N: Network = AnyNetwork> {\n    // Note: this is a result, so we can easily chain builder calls\n    url: Result<Url>,\n    chain: NamedChain,\n    max_retry: u32,\n    initial_backoff: u64,\n    timeout: Duration,\n    /// available CUPS\n    compute_units_per_second: u64,\n    /// JWT Secret\n    jwt: Option<String>,\n    headers: Vec<String>,\n    is_local: bool,\n    /// Whether to accept invalid certificates.\n    accept_invalid_certs: bool,\n    /// Whether to disable automatic proxy detection.\n    no_proxy: bool,\n    /// Whether to output curl commands instead of making requests.\n    curl_mode: bool,\n    /// Phantom data for the network type.\n    _network: PhantomData<N>,\n}\n\nimpl<N: Network> ProviderBuilder<N> {\n    /// Creates a new ProviderBuilder helper instance.\n    pub fn new(url_str: &str) -> Self {\n        // a copy is needed for the next lines to work\n        let mut url_str = url_str;\n\n        // invalid url: non-prefixed URL scheme is not allowed, so we prepend the default http\n        // prefix\n        let storage;\n        if url_str.starts_with(\"localhost:\") {\n            storage = format!(\"http://{url_str}\");\n            url_str = storage.as_str();\n        }\n\n        let url = Url::parse(url_str)\n            .or_else(|err| match err {\n                ParseError::RelativeUrlWithoutBase => {\n                    if SocketAddr::from_str(url_str).is_ok() {\n                        Url::parse(&format!(\"http://{url_str}\"))\n                    } else {\n                        let path = Path::new(url_str);\n\n                        if let Ok(path) = resolve_path(path) {\n                            Url::parse(&format!(\"file://{}\", path.display()))\n                        } else {\n                            Err(err)\n                        }\n                    }\n                }\n                _ => Err(err),\n            })\n            .wrap_err_with(|| format!(\"invalid provider URL: {url_str:?}\"));\n\n        // Use the final URL string to guess if it's a local URL.\n        let is_local = url.as_ref().is_ok_and(|url| guess_local_url(url.as_str()));\n\n        Self {\n            url,\n            chain: NamedChain::Mainnet,\n            max_retry: 8,\n            initial_backoff: 800,\n            timeout: REQUEST_TIMEOUT,\n            // alchemy max cpus <https://docs.alchemy.com/reference/compute-units#what-are-cups-compute-units-per-second>\n            compute_units_per_second: ALCHEMY_FREE_TIER_CUPS,\n            jwt: None,\n            headers: vec![],\n            is_local,\n            accept_invalid_certs: false,\n            no_proxy: false,\n            curl_mode: false,\n            _network: PhantomData,\n        }\n    }\n\n    /// Constructs a [ProviderBuilder] instantiated using [Config] values.\n    ///\n    /// Defaults to `http://localhost:8545` and `Mainnet`.\n    pub fn from_config(config: &Config) -> Result<Self> {\n        let url = config.get_rpc_url_or_localhost_http()?;\n        let mut builder = Self::new(url.as_ref());\n\n        builder = builder.accept_invalid_certs(config.eth_rpc_accept_invalid_certs);\n        builder = builder.curl_mode(config.eth_rpc_curl);\n\n        if let Ok(chain) = config.chain.unwrap_or_default().try_into() {\n            builder = builder.chain(chain);\n        }\n\n        if let Some(jwt) = config.get_rpc_jwt_secret()? {\n            builder = builder.jwt(jwt.as_ref());\n        }\n\n        if let Some(rpc_timeout) = config.eth_rpc_timeout {\n            builder = builder.timeout(Duration::from_secs(rpc_timeout));\n        }\n\n        if let Some(rpc_headers) = config.eth_rpc_headers.clone() {\n            builder = builder.headers(rpc_headers);\n        }\n\n        Ok(builder)\n    }\n\n    /// Enables a request timeout.\n    ///\n    /// The timeout is applied from when the request starts connecting until the\n    /// response body has finished.\n    ///\n    /// Default is no timeout.\n    pub fn timeout(mut self, timeout: Duration) -> Self {\n        self.timeout = timeout;\n        self\n    }\n\n    /// Sets the chain of the node the provider will connect to\n    pub fn chain(mut self, chain: NamedChain) -> Self {\n        self.chain = chain;\n        self\n    }\n\n    /// How often to retry a failed request\n    pub fn max_retry(mut self, max_retry: u32) -> Self {\n        self.max_retry = max_retry;\n        self\n    }\n\n    /// How often to retry a failed request. If `None`, defaults to the already-set value.\n    pub fn maybe_max_retry(mut self, max_retry: Option<u32>) -> Self {\n        self.max_retry = max_retry.unwrap_or(self.max_retry);\n        self\n    }\n\n    /// The starting backoff delay to use after the first failed request. If `None`, defaults to\n    /// the already-set value.\n    pub fn maybe_initial_backoff(mut self, initial_backoff: Option<u64>) -> Self {\n        self.initial_backoff = initial_backoff.unwrap_or(self.initial_backoff);\n        self\n    }\n\n    /// The starting backoff delay to use after the first failed request\n    pub fn initial_backoff(mut self, initial_backoff: u64) -> Self {\n        self.initial_backoff = initial_backoff;\n        self\n    }\n\n    /// Sets the number of assumed available compute units per second\n    ///\n    /// See also, <https://docs.alchemy.com/reference/compute-units#what-are-cups-compute-units-per-second>\n    pub fn compute_units_per_second(mut self, compute_units_per_second: u64) -> Self {\n        self.compute_units_per_second = compute_units_per_second;\n        self\n    }\n\n    /// Sets the number of assumed available compute units per second\n    ///\n    /// See also, <https://docs.alchemy.com/reference/compute-units#what-are-cups-compute-units-per-second>\n    pub fn compute_units_per_second_opt(mut self, compute_units_per_second: Option<u64>) -> Self {\n        if let Some(cups) = compute_units_per_second {\n            self.compute_units_per_second = cups;\n        }\n        self\n    }\n\n    /// Sets the provider to be local.\n    ///\n    /// This is useful for local dev nodes.\n    pub fn local(mut self, is_local: bool) -> Self {\n        self.is_local = is_local;\n        self\n    }\n\n    /// Sets aggressive `max_retry` and `initial_backoff` values\n    ///\n    /// This is only recommend for local dev nodes\n    pub fn aggressive(self) -> Self {\n        self.max_retry(100).initial_backoff(100).local(true)\n    }\n\n    /// Sets the JWT secret\n    pub fn jwt(mut self, jwt: impl Into<String>) -> Self {\n        self.jwt = Some(jwt.into());\n        self\n    }\n\n    /// Sets http headers\n    pub fn headers(mut self, headers: Vec<String>) -> Self {\n        self.headers = headers;\n\n        self\n    }\n\n    /// Sets http headers. If `None`, defaults to the already-set value.\n    pub fn maybe_headers(mut self, headers: Option<Vec<String>>) -> Self {\n        self.headers = headers.unwrap_or(self.headers);\n        self\n    }\n\n    /// Sets whether to accept invalid certificates.\n    pub fn accept_invalid_certs(mut self, accept_invalid_certs: bool) -> Self {\n        self.accept_invalid_certs = accept_invalid_certs;\n        self\n    }\n\n    /// Sets whether to disable automatic proxy detection.\n    ///\n    /// This can help in sandboxed environments (e.g., Cursor IDE sandbox, macOS App Sandbox)\n    /// where system proxy detection via SCDynamicStore causes crashes.\n    pub fn no_proxy(mut self, no_proxy: bool) -> Self {\n        self.no_proxy = no_proxy;\n        self\n    }\n\n    /// Sets whether to output curl commands instead of making requests.\n    ///\n    /// When enabled, the provider will print equivalent curl commands to stdout\n    /// instead of actually executing the RPC requests.\n    pub fn curl_mode(mut self, curl_mode: bool) -> Self {\n        self.curl_mode = curl_mode;\n        self\n    }\n\n    /// Constructs the `RetryProvider` taking all configs into account.\n    pub fn build(self) -> Result<RetryProvider<N>> {\n        let Self {\n            url,\n            chain,\n            max_retry,\n            initial_backoff,\n            timeout,\n            compute_units_per_second,\n            jwt,\n            headers,\n            is_local,\n            accept_invalid_certs,\n            no_proxy,\n            curl_mode,\n            ..\n        } = self;\n        let url = url?;\n\n        let retry_layer =\n            RetryBackoffLayer::new(max_retry, initial_backoff, compute_units_per_second);\n\n        // If curl_mode is enabled, use CurlTransport instead of RuntimeTransport\n        if curl_mode {\n            let transport = CurlTransport::new(url).with_headers(headers).with_jwt(jwt);\n            let client = ClientBuilder::default().layer(retry_layer).transport(transport, is_local);\n\n            let provider = AlloyProviderBuilder::<_, _, N>::default()\n                .connect_provider(RootProvider::new(client));\n\n            return Ok(provider);\n        }\n\n        let transport = RuntimeTransportBuilder::new(url)\n            .with_timeout(timeout)\n            .with_headers(headers)\n            .with_jwt(jwt)\n            .accept_invalid_certs(accept_invalid_certs)\n            .no_proxy(no_proxy)\n            .build();\n        let client = ClientBuilder::default().layer(retry_layer).transport(transport, is_local);\n\n        if !is_local {\n            client.set_poll_interval(\n                chain\n                    .average_blocktime_hint()\n                    // we cap the poll interval because if not provided, chain would default to\n                    // mainnet\n                    .map(|hint| hint.min(DEFAULT_UNKNOWN_CHAIN_BLOCK_TIME))\n                    .unwrap_or(DEFAULT_UNKNOWN_CHAIN_BLOCK_TIME)\n                    .mul_f32(POLL_INTERVAL_BLOCK_TIME_SCALE_FACTOR),\n            );\n        }\n\n        let provider =\n            AlloyProviderBuilder::<_, _, N>::default().connect_provider(RootProvider::new(client));\n\n        Ok(provider)\n    }\n}\n\nimpl<N: Network> ProviderBuilder<N> {\n    /// Constructs the `RetryProvider` with a wallet.\n    pub fn build_with_wallet<W: NetworkWallet<N> + Clone>(\n        self,\n        wallet: W,\n    ) -> Result<RetryProviderWithSigner<N, W>>\n    where\n        N: RecommendedFillers,\n    {\n        let Self {\n            url,\n            chain,\n            max_retry,\n            initial_backoff,\n            timeout,\n            compute_units_per_second,\n            jwt,\n            headers,\n            is_local,\n            accept_invalid_certs,\n            no_proxy,\n            curl_mode,\n            ..\n        } = self;\n        let url = url?;\n\n        let retry_layer =\n            RetryBackoffLayer::new(max_retry, initial_backoff, compute_units_per_second);\n\n        // If curl_mode is enabled, use CurlTransport instead of RuntimeTransport\n        if curl_mode {\n            let transport = CurlTransport::new(url).with_headers(headers).with_jwt(jwt);\n            let client = ClientBuilder::default().layer(retry_layer).transport(transport, is_local);\n\n            let provider = AlloyProviderBuilder::<_, _, N>::default()\n                .with_recommended_fillers()\n                .wallet(wallet)\n                .connect_provider(RootProvider::new(client));\n\n            return Ok(provider);\n        }\n\n        let transport = RuntimeTransportBuilder::new(url)\n            .with_timeout(timeout)\n            .with_headers(headers)\n            .with_jwt(jwt)\n            .accept_invalid_certs(accept_invalid_certs)\n            .no_proxy(no_proxy)\n            .build();\n\n        let client = ClientBuilder::default().layer(retry_layer).transport(transport, is_local);\n\n        if !is_local {\n            client.set_poll_interval(\n                chain\n                    .average_blocktime_hint()\n                    // we cap the poll interval because if not provided, chain would default to\n                    // mainnet\n                    .map(|hint| hint.min(DEFAULT_UNKNOWN_CHAIN_BLOCK_TIME))\n                    .unwrap_or(DEFAULT_UNKNOWN_CHAIN_BLOCK_TIME)\n                    .mul_f32(POLL_INTERVAL_BLOCK_TIME_SCALE_FACTOR),\n            );\n        }\n\n        let provider = AlloyProviderBuilder::<_, _, N>::default()\n            .with_recommended_fillers()\n            .wallet(wallet)\n            .connect_provider(RootProvider::new(client));\n\n        Ok(provider)\n    }\n}\n\n#[cfg(not(windows))]\nfn resolve_path(path: &Path) -> Result<PathBuf, ()> {\n    if path.is_absolute() {\n        Ok(path.to_path_buf())\n    } else {\n        std::env::current_dir().map(|d| d.join(path)).map_err(drop)\n    }\n}\n\n#[cfg(windows)]\nfn resolve_path(path: &Path) -> Result<PathBuf, ()> {\n    if let Some(s) = path.to_str()\n        && s.starts_with(r\"\\\\.\\pipe\\\")\n    {\n        return Ok(path.to_path_buf());\n    }\n    if path.is_absolute() {\n        Ok(path.to_path_buf())\n    } else {\n        std::env::current_dir().map(|d| d.join(path)).map_err(drop)\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn can_auto_correct_missing_prefix() {\n        let builder = ProviderBuilder::<AnyNetwork>::new(\"localhost:8545\");\n        assert!(builder.url.is_ok());\n\n        let url = builder.url.unwrap();\n        assert_eq!(url, Url::parse(\"http://localhost:8545\").unwrap());\n    }\n}\n"
  },
  {
    "path": "crates/common/src/provider/runtime_transport.rs",
    "content": "//! Runtime transport that connects on first request, which can take either of an HTTP,\n//! WebSocket, or IPC transport. Retries are handled by a client layer (e.g.,\n//! `RetryBackoffLayer`) when used.\n\nuse crate::{DEFAULT_USER_AGENT, REQUEST_TIMEOUT};\nuse alloy_json_rpc::{RequestPacket, ResponsePacket};\nuse alloy_pubsub::{PubSubConnect, PubSubFrontend};\nuse alloy_rpc_types::engine::{Claims, JwtSecret};\nuse alloy_transport::{\n    Authorization, BoxTransport, TransportError, TransportErrorKind, TransportFut,\n};\nuse alloy_transport_http::Http;\nuse alloy_transport_ipc::IpcConnect;\nuse alloy_transport_ws::WsConnect;\nuse reqwest::header::{HeaderName, HeaderValue};\nuse std::{fmt, path::PathBuf, str::FromStr, sync::Arc};\nuse thiserror::Error;\nuse tokio::sync::RwLock;\nuse tower::Service;\nuse url::Url;\n\n/// An enum representing the different transports that can be used to connect to a runtime.\n/// Only meant to be used internally by [RuntimeTransport].\n#[derive(Clone, Debug)]\npub enum InnerTransport {\n    /// HTTP transport\n    Http(Http<reqwest::Client>),\n    /// WebSocket transport\n    Ws(PubSubFrontend),\n    /// IPC transport\n    Ipc(PubSubFrontend),\n}\n\n/// Error type for the runtime transport.\n#[derive(Error, Debug)]\npub enum RuntimeTransportError {\n    /// Internal transport error\n    #[error(\"Internal transport error: {0} with {1}\")]\n    TransportError(TransportError, String),\n\n    /// Invalid URL scheme\n    #[error(\"URL scheme is not supported: {0}\")]\n    BadScheme(String),\n\n    /// Invalid HTTP header\n    #[error(\"Invalid HTTP header: {0}\")]\n    BadHeader(String),\n\n    /// Invalid file path\n    #[error(\"Invalid IPC file path: {0}\")]\n    BadPath(String),\n\n    /// Invalid construction of Http provider\n    #[error(transparent)]\n    HttpConstructionError(#[from] reqwest::Error),\n\n    /// Invalid JWT\n    #[error(\"Invalid JWT: {0}\")]\n    InvalidJwt(String),\n}\n\n/// Runtime transport that only connects on first request.\n///\n/// A runtime transport is a custom [`alloy_transport::Transport`] that only connects when the\n/// *first* request is made. When the first request is made, it will connect to the runtime using\n/// either an HTTP WebSocket, or IPC transport depending on the URL used.\n/// Retries for rate-limiting and timeout-related errors are handled by an external\n/// client layer (e.g., `RetryBackoffLayer`) when configured.\n#[derive(Clone, Debug)]\npub struct RuntimeTransport {\n    /// The inner actual transport used.\n    inner: Arc<RwLock<Option<InnerTransport>>>,\n    /// The URL to connect to.\n    url: Url,\n    /// The headers to use for requests.\n    headers: Vec<String>,\n    /// The JWT to use for requests.\n    jwt: Option<String>,\n    /// The timeout for requests.\n    timeout: std::time::Duration,\n    /// Whether to accept invalid certificates.\n    accept_invalid_certs: bool,\n    /// Whether to disable automatic proxy detection.\n    no_proxy: bool,\n}\n\n/// A builder for [RuntimeTransport].\n#[derive(Debug)]\npub struct RuntimeTransportBuilder {\n    url: Url,\n    headers: Vec<String>,\n    jwt: Option<String>,\n    timeout: std::time::Duration,\n    accept_invalid_certs: bool,\n    no_proxy: bool,\n}\n\nimpl RuntimeTransportBuilder {\n    /// Create a new builder with the given URL.\n    pub fn new(url: Url) -> Self {\n        Self {\n            url,\n            headers: vec![],\n            jwt: None,\n            timeout: REQUEST_TIMEOUT,\n            accept_invalid_certs: false,\n            no_proxy: false,\n        }\n    }\n\n    /// Set the URL for the transport.\n    pub fn with_headers(mut self, headers: Vec<String>) -> Self {\n        self.headers = headers;\n        self\n    }\n\n    /// Set the JWT for the transport.\n    pub fn with_jwt(mut self, jwt: Option<String>) -> Self {\n        self.jwt = jwt;\n        self\n    }\n\n    /// Set the timeout for the transport.\n    pub fn with_timeout(mut self, timeout: std::time::Duration) -> Self {\n        self.timeout = timeout;\n        self\n    }\n\n    /// Set whether to accept invalid certificates.\n    pub fn accept_invalid_certs(mut self, accept_invalid_certs: bool) -> Self {\n        self.accept_invalid_certs = accept_invalid_certs;\n        self\n    }\n\n    /// Set whether to disable automatic proxy detection.\n    ///\n    /// This can help in sandboxed environments (e.g., Cursor IDE sandbox, macOS App Sandbox)\n    /// where system proxy detection via SCDynamicStore causes crashes.\n    pub fn no_proxy(mut self, no_proxy: bool) -> Self {\n        self.no_proxy = no_proxy;\n        self\n    }\n\n    /// Builds the [RuntimeTransport] and returns it in a disconnected state.\n    /// The runtime transport will then connect when the first request happens.\n    pub fn build(self) -> RuntimeTransport {\n        RuntimeTransport {\n            inner: Arc::new(RwLock::new(None)),\n            url: self.url,\n            headers: self.headers,\n            jwt: self.jwt,\n            timeout: self.timeout,\n            accept_invalid_certs: self.accept_invalid_certs,\n            no_proxy: self.no_proxy,\n        }\n    }\n}\n\nimpl fmt::Display for RuntimeTransport {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        write!(f, \"RuntimeTransport {}\", self.url)\n    }\n}\n\nimpl RuntimeTransport {\n    /// Connects the underlying transport, depending on the URL scheme.\n    pub async fn connect(&self) -> Result<InnerTransport, RuntimeTransportError> {\n        match self.url.scheme() {\n            \"http\" | \"https\" => self.connect_http(),\n            \"ws\" | \"wss\" => self.connect_ws().await,\n            \"file\" => self.connect_ipc().await,\n            _ => Err(RuntimeTransportError::BadScheme(self.url.scheme().to_string())),\n        }\n    }\n\n    /// Creates a new reqwest client from this transport.\n    pub fn reqwest_client(&self) -> Result<reqwest::Client, RuntimeTransportError> {\n        let mut client_builder = reqwest::Client::builder()\n            .timeout(self.timeout)\n            .danger_accept_invalid_certs(self.accept_invalid_certs);\n\n        // Disable automatic proxy detection if requested. This helps in sandboxed environments\n        // (e.g., Cursor IDE sandbox, macOS App Sandbox) where system proxy detection via\n        // SCDynamicStore causes crashes. See: https://github.com/foundry-rs/foundry/issues/12733\n        if self.no_proxy {\n            client_builder = client_builder.no_proxy();\n        }\n\n        let mut headers = reqwest::header::HeaderMap::new();\n\n        // If there's a JWT, add it to the headers if we can decode it.\n        if let Some(jwt) = self.jwt.clone() {\n            let auth =\n                build_auth(jwt).map_err(|e| RuntimeTransportError::InvalidJwt(e.to_string()))?;\n\n            let mut auth_value: HeaderValue =\n                HeaderValue::from_str(&auth.to_string()).expect(\"Header should be valid string\");\n            auth_value.set_sensitive(true);\n\n            headers.insert(reqwest::header::AUTHORIZATION, auth_value);\n        };\n\n        // Add any custom headers.\n        for header in &self.headers {\n            let make_err = || RuntimeTransportError::BadHeader(header.to_string());\n\n            let (key, val) = header.split_once(':').ok_or_else(make_err)?;\n\n            headers.insert(\n                HeaderName::from_str(key.trim()).map_err(|_| make_err())?,\n                HeaderValue::from_str(val.trim()).map_err(|_| make_err())?,\n            );\n        }\n\n        if !headers.contains_key(reqwest::header::USER_AGENT) {\n            headers.insert(\n                reqwest::header::USER_AGENT,\n                HeaderValue::from_str(DEFAULT_USER_AGENT)\n                    .expect(\"User-Agent should be valid string\"),\n            );\n        }\n\n        client_builder = client_builder.default_headers(headers);\n\n        Ok(client_builder.build()?)\n    }\n\n    /// Connects to an HTTP [alloy_transport_http::Http] transport.\n    fn connect_http(&self) -> Result<InnerTransport, RuntimeTransportError> {\n        let client = self.reqwest_client()?;\n        Ok(InnerTransport::Http(Http::with_client(client, self.url.clone())))\n    }\n\n    /// Connects to a WS transport.\n    async fn connect_ws(&self) -> Result<InnerTransport, RuntimeTransportError> {\n        let auth = self.jwt.as_ref().and_then(|jwt| build_auth(jwt.clone()).ok());\n        let mut ws = WsConnect::new(self.url.to_string());\n        if let Some(auth) = auth {\n            ws = ws.with_auth(auth);\n        };\n        let service = ws\n            .into_service()\n            .await\n            .map_err(|e| RuntimeTransportError::TransportError(e, self.url.to_string()))?;\n        Ok(InnerTransport::Ws(service))\n    }\n\n    /// Connects to an IPC transport.\n    async fn connect_ipc(&self) -> Result<InnerTransport, RuntimeTransportError> {\n        let path = url_to_file_path(&self.url)\n            .map_err(|_| RuntimeTransportError::BadPath(self.url.to_string()))?;\n        let ipc_connector = IpcConnect::new(path.clone());\n        let ipc = ipc_connector.into_service().await.map_err(|e| {\n            RuntimeTransportError::TransportError(e, path.clone().display().to_string())\n        })?;\n        Ok(InnerTransport::Ipc(ipc))\n    }\n\n    /// Sends a request using the underlying transport.\n    /// If this is the first request, it will connect to the appropriate transport depending on the\n    /// URL scheme. Retries are performed by an external client layer (e.g., `RetryBackoffLayer`),\n    /// if such a layer is configured by the caller.\n    /// For sending the actual request, this action is delegated down to the\n    /// underlying transport through Tower's [tower::Service::call]. See tower's [tower::Service]\n    /// trait for more information.\n    pub fn request(&self, req: RequestPacket) -> TransportFut<'static> {\n        let this = self.clone();\n        Box::pin(async move {\n            let mut inner = this.inner.read().await;\n            if inner.is_none() {\n                drop(inner);\n                {\n                    let mut inner_mut = this.inner.write().await;\n                    if inner_mut.is_none() {\n                        *inner_mut =\n                            Some(this.connect().await.map_err(TransportErrorKind::custom)?);\n                    }\n                }\n                inner = this.inner.read().await;\n            }\n\n            // SAFETY: We just checked that the inner transport exists.\n            match inner.clone().expect(\"must've been initialized\") {\n                InnerTransport::Http(mut http) => http.call(req),\n                InnerTransport::Ws(mut ws) => ws.call(req),\n                InnerTransport::Ipc(mut ipc) => ipc.call(req),\n            }\n            .await\n        })\n    }\n\n    /// Convert this transport into a boxed trait object.\n    pub fn boxed(self) -> BoxTransport\n    where\n        Self: Sized + Clone + Send + Sync + 'static,\n    {\n        BoxTransport::new(self)\n    }\n}\n\nimpl tower::Service<RequestPacket> for RuntimeTransport {\n    type Response = ResponsePacket;\n    type Error = TransportError;\n    type Future = TransportFut<'static>;\n\n    #[inline]\n    fn poll_ready(\n        &mut self,\n        _cx: &mut std::task::Context<'_>,\n    ) -> std::task::Poll<Result<(), Self::Error>> {\n        std::task::Poll::Ready(Ok(()))\n    }\n\n    #[inline]\n    fn call(&mut self, req: RequestPacket) -> Self::Future {\n        self.request(req)\n    }\n}\n\nimpl tower::Service<RequestPacket> for &RuntimeTransport {\n    type Response = ResponsePacket;\n    type Error = TransportError;\n    type Future = TransportFut<'static>;\n\n    #[inline]\n    fn poll_ready(\n        &mut self,\n        _cx: &mut std::task::Context<'_>,\n    ) -> std::task::Poll<Result<(), Self::Error>> {\n        std::task::Poll::Ready(Ok(()))\n    }\n\n    #[inline]\n    fn call(&mut self, req: RequestPacket) -> Self::Future {\n        self.request(req)\n    }\n}\n\nfn build_auth(jwt: String) -> eyre::Result<Authorization> {\n    // Decode jwt from hex, then generate claims (iat with current timestamp)\n    let secret = JwtSecret::from_hex(jwt)?;\n    let claims = Claims::default();\n    let token = secret.encode(&claims)?;\n\n    let auth = Authorization::Bearer(token);\n\n    Ok(auth)\n}\n\n#[cfg(windows)]\nfn url_to_file_path(url: &Url) -> Result<PathBuf, ()> {\n    const PREFIX: &str = \"file:///pipe/\";\n\n    let url_str = url.as_str();\n\n    if let Some(pipe_name) = url_str.strip_prefix(PREFIX) {\n        let pipe_path = format!(r\"\\\\.\\pipe\\{pipe_name}\");\n        return Ok(PathBuf::from(pipe_path));\n    }\n\n    url.to_file_path()\n}\n\n#[cfg(not(windows))]\nfn url_to_file_path(url: &Url) -> Result<PathBuf, ()> {\n    url.to_file_path()\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use reqwest::header::HeaderMap;\n\n    #[tokio::test]\n    async fn test_user_agent_header() {\n        let listener = tokio::net::TcpListener::bind(\"127.0.0.1:0\").await.unwrap();\n        let url = Url::parse(&format!(\"http://{}\", listener.local_addr().unwrap())).unwrap();\n\n        let http_handler = axum::routing::get(|actual_headers: HeaderMap| {\n            let user_agent = HeaderName::from_str(\"User-Agent\").unwrap();\n            assert_eq!(actual_headers[user_agent], HeaderValue::from_str(\"test-agent\").unwrap());\n\n            async { \"\" }\n        });\n\n        let server_task = tokio::spawn(async move {\n            axum::serve(listener, http_handler.into_make_service()).await.unwrap()\n        });\n\n        let transport = RuntimeTransportBuilder::new(url.clone())\n            .with_headers(vec![\"User-Agent: test-agent\".to_string()])\n            .build();\n        let inner = transport.connect_http().unwrap();\n\n        match inner {\n            InnerTransport::Http(http) => {\n                let _ = http.client().get(url).send().await.unwrap();\n\n                // assert inside http_handler\n            }\n            _ => unreachable!(),\n        }\n\n        server_task.abort();\n    }\n}\n"
  },
  {
    "path": "crates/common/src/retry.rs",
    "content": "//! Retry utilities.\n\nuse eyre::{Error, Report, Result};\nuse std::time::Duration;\n\n/// Error type for Retry.\n#[derive(Debug, thiserror::Error)]\npub enum RetryError<E = Report> {\n    /// Continues operation without decrementing retries.\n    Continue(E),\n    /// Keeps retrying operation.\n    Retry(E),\n    /// Stops retrying operation immediately.\n    Break(E),\n}\n\n/// A type that keeps track of attempts.\n#[derive(Clone, Debug)]\npub struct Retry {\n    retries: u32,\n    delay: Duration,\n}\n\nimpl Retry {\n    /// Creates a new `Retry` instance.\n    pub fn new(retries: u32, delay: Duration) -> Self {\n        Self { retries, delay }\n    }\n\n    /// Creates a new `Retry` instance with no delay between retries.\n    pub fn new_no_delay(retries: u32) -> Self {\n        Self::new(retries, Duration::ZERO)\n    }\n\n    /// Runs the given closure in a loop, retrying if it fails up to the specified number of times.\n    pub fn run<F: FnMut() -> Result<T>, T>(mut self, mut callback: F) -> Result<T> {\n        loop {\n            match callback() {\n                Err(e) if self.retries > 0 => {\n                    self.handle_err(e);\n                    if !self.delay.is_zero() {\n                        std::thread::sleep(self.delay);\n                    }\n                }\n                res => return res,\n            }\n        }\n    }\n\n    /// Runs the given async closure in a loop, retrying if it fails up to the specified number of\n    /// times.\n    pub async fn run_async<F, Fut, T>(mut self, mut callback: F) -> Result<T>\n    where\n        F: FnMut() -> Fut,\n        Fut: Future<Output = Result<T>>,\n    {\n        loop {\n            match callback().await {\n                Err(e) if self.retries > 0 => {\n                    self.handle_err(e);\n                    if !self.delay.is_zero() {\n                        tokio::time::sleep(self.delay).await;\n                    }\n                }\n                res => return res,\n            };\n        }\n    }\n\n    /// Runs the given async closure in a loop, retrying if it fails up to the specified number of\n    /// times or immediately returning an error if the closure returned [`RetryError::Break`].\n    pub async fn run_async_until_break<F, Fut, T>(mut self, mut callback: F) -> Result<T>\n    where\n        F: FnMut() -> Fut,\n        Fut: Future<Output = Result<T, RetryError>>,\n    {\n        loop {\n            match callback().await {\n                Err(RetryError::Continue(e)) => {\n                    self.log(e, false);\n                    if !self.delay.is_zero() {\n                        tokio::time::sleep(self.delay).await;\n                    }\n                }\n                Err(RetryError::Retry(e)) if self.retries > 0 => {\n                    self.handle_err(e);\n                    if !self.delay.is_zero() {\n                        tokio::time::sleep(self.delay).await;\n                    }\n                }\n                Err(RetryError::Retry(e) | RetryError::Break(e)) => return Err(e),\n                Ok(t) => return Ok(t),\n            };\n        }\n    }\n\n    fn handle_err(&mut self, err: Error) {\n        debug_assert!(self.retries > 0);\n        self.retries -= 1;\n        self.log(err, true);\n    }\n\n    fn log(&self, err: Error, warn: bool) {\n        let msg = format!(\n            \"{err}{delay} ({retries} tries remaining)\",\n            delay = if self.delay.is_zero() {\n                String::new()\n            } else {\n                format!(\"; waiting {} seconds before trying again\", self.delay.as_secs())\n            },\n            retries = self.retries,\n        );\n        if warn {\n            let _ = sh_warn!(\"{msg}\");\n        } else {\n            tracing::info!(\"{msg}\");\n        }\n    }\n}\n"
  },
  {
    "path": "crates/common/src/selectors.rs",
    "content": "//! Support for handling/identifying selectors.\n\n#![allow(missing_docs)]\n\nuse crate::{abi::abi_decode_calldata, provider::runtime_transport::RuntimeTransportBuilder};\nuse alloy_json_abi::JsonAbi;\nuse alloy_primitives::{B256, Selector, map::HashMap};\nuse eyre::Context;\nuse itertools::Itertools;\nuse serde::{Deserialize, Serialize, de::DeserializeOwned};\nuse std::{\n    fmt,\n    sync::{\n        Arc,\n        atomic::{AtomicBool, AtomicUsize, Ordering},\n    },\n    time::Duration,\n};\n\nconst BASE_URL: &str = \"https://api.4byte.sourcify.dev\";\nconst SELECTOR_LOOKUP_URL: &str = \"https://api.4byte.sourcify.dev/signature-database/v1/lookup\";\nconst SELECTOR_IMPORT_URL: &str = \"https://api.4byte.sourcify.dev/signature-database/v1/import\";\n\n/// The standard request timeout for API requests.\nconst REQ_TIMEOUT: Duration = Duration::from_secs(15);\n\n/// How many request can time out before we decide this is a spurious connection.\nconst MAX_TIMEDOUT_REQ: usize = 4usize;\n\n/// List of signatures for a given [`SelectorKind`].\npub type OpenChainSignatures = Vec<String>;\n\n/// A client that can request API data from OpenChain.\n#[derive(Clone, Debug)]\npub struct OpenChainClient {\n    inner: reqwest::Client,\n    /// Whether the connection is spurious, or API is down\n    spurious_connection: Arc<AtomicBool>,\n    /// How many requests timed out\n    timedout_requests: Arc<AtomicUsize>,\n    /// Max allowed request that can time out\n    max_timedout_requests: usize,\n}\n\nimpl OpenChainClient {\n    /// Creates a new client with default settings.\n    pub fn new() -> eyre::Result<Self> {\n        let inner = RuntimeTransportBuilder::new(BASE_URL.parse().unwrap())\n            .with_timeout(REQ_TIMEOUT)\n            .build()\n            .reqwest_client()\n            .wrap_err(\"failed to build OpenChain client\")?;\n        Ok(Self {\n            inner,\n            spurious_connection: Default::default(),\n            timedout_requests: Default::default(),\n            max_timedout_requests: MAX_TIMEDOUT_REQ,\n        })\n    }\n\n    async fn get_text(&self, url: impl reqwest::IntoUrl + fmt::Display) -> reqwest::Result<String> {\n        trace!(%url, \"GET\");\n        self.inner\n            .get(url)\n            .send()\n            .await\n            .inspect_err(|err| self.on_reqwest_err(err))?\n            .text()\n            .await\n            .inspect_err(|err| self.on_reqwest_err(err))\n    }\n\n    /// Sends a new post request\n    async fn post_json<T: Serialize + std::fmt::Debug, R: DeserializeOwned>(\n        &self,\n        url: &str,\n        body: &T,\n    ) -> reqwest::Result<R> {\n        trace!(%url, body=?serde_json::to_string(body), \"POST\");\n        self.inner\n            .post(url)\n            .json(body)\n            .send()\n            .await\n            .inspect_err(|err| self.on_reqwest_err(err))?\n            .json()\n            .await\n            .inspect_err(|err| self.on_reqwest_err(err))\n    }\n\n    fn on_reqwest_err(&self, err: &reqwest::Error) {\n        fn is_connectivity_err(err: &reqwest::Error) -> bool {\n            if err.is_timeout() || err.is_connect() {\n                return true;\n            }\n            // Error HTTP codes (5xx) are considered connectivity issues and will prompt retry\n            if let Some(status) = err.status() {\n                let code = status.as_u16();\n                if (500..600).contains(&code) {\n                    return true;\n                }\n            }\n            false\n        }\n\n        if is_connectivity_err(err) {\n            warn!(\"spurious network detected for OpenChain\");\n            let previous = self.timedout_requests.fetch_add(1, Ordering::SeqCst);\n            if previous + 1 >= self.max_timedout_requests {\n                self.set_spurious();\n            }\n        }\n    }\n\n    /// Returns whether the connection was marked as spurious\n    fn is_spurious(&self) -> bool {\n        self.spurious_connection.load(Ordering::Relaxed)\n    }\n\n    /// Marks the connection as spurious\n    fn set_spurious(&self) {\n        self.spurious_connection.store(true, Ordering::Relaxed)\n    }\n\n    fn ensure_not_spurious(&self) -> eyre::Result<()> {\n        if self.is_spurious() {\n            eyre::bail!(\"Spurious connection detected\")\n        }\n        Ok(())\n    }\n\n    /// Decodes the given function or event selector using OpenChain\n    pub async fn decode_selector(\n        &self,\n        selector: SelectorKind,\n    ) -> eyre::Result<OpenChainSignatures> {\n        Ok(self.decode_selectors(&[selector]).await?.pop().unwrap())\n    }\n\n    /// Decodes the given function, error or event selectors using OpenChain.\n    pub async fn decode_selectors(\n        &self,\n        selectors: &[SelectorKind],\n    ) -> eyre::Result<Vec<OpenChainSignatures>> {\n        if selectors.is_empty() {\n            return Ok(vec![]);\n        }\n\n        if enabled!(tracing::Level::TRACE) {\n            trace!(?selectors, \"decoding selectors\");\n        } else {\n            debug!(len = selectors.len(), \"decoding selectors\");\n        }\n\n        // Exit early if spurious connection.\n        self.ensure_not_spurious()?;\n\n        // Build the URL with the query string.\n        let mut url: url::Url = SELECTOR_LOOKUP_URL.parse().unwrap();\n        {\n            let mut query = url.query_pairs_mut();\n            let functions = selectors.iter().filter_map(SelectorKind::as_function);\n            if functions.clone().next().is_some() {\n                query.append_pair(\"function\", &functions.format(\",\").to_string());\n            }\n            let events = selectors.iter().filter_map(SelectorKind::as_event);\n            if events.clone().next().is_some() {\n                query.append_pair(\"event\", &events.format(\",\").to_string());\n            }\n            let _ = query.finish();\n        }\n\n        let text = self.get_text(url).await?;\n        let SignatureResponse { ok, result } = match serde_json::from_str(&text) {\n            Ok(response) => response,\n            Err(err) => eyre::bail!(\"could not decode response: {err}: {text}\"),\n        };\n        if !ok {\n            eyre::bail!(\"OpenChain returned an error: {text}\");\n        }\n\n        Ok(selectors\n            .iter()\n            .map(|selector| {\n                let signatures = match selector {\n                    SelectorKind::Function(selector) | SelectorKind::Error(selector) => {\n                        result.function.get(selector)\n                    }\n                    SelectorKind::Event(hash) => result.event.get(hash),\n                };\n                signatures\n                    .map(Option::as_deref)\n                    .unwrap_or_default()\n                    .unwrap_or_default()\n                    .iter()\n                    .map(|sig| sig.name.clone())\n                    .collect()\n            })\n            .collect())\n    }\n\n    /// Fetches a function signature given the selector using OpenChain\n    pub async fn decode_function_selector(\n        &self,\n        selector: Selector,\n    ) -> eyre::Result<OpenChainSignatures> {\n        self.decode_selector(SelectorKind::Function(selector)).await\n    }\n\n    /// Fetches all possible signatures and attempts to abi decode the calldata\n    pub async fn decode_calldata(&self, calldata: &str) -> eyre::Result<OpenChainSignatures> {\n        let calldata = calldata.strip_prefix(\"0x\").unwrap_or(calldata);\n        if calldata.len() < 8 {\n            eyre::bail!(\n                \"Calldata too short: expected at least 8 characters (excluding 0x prefix), got {}.\",\n                calldata.len()\n            )\n        }\n\n        let mut sigs = self.decode_function_selector(calldata[..8].parse()?).await?;\n        // Retain only signatures that can be decoded.\n        sigs.retain(|sig| abi_decode_calldata(sig, calldata, true, true).is_ok());\n        Ok(sigs)\n    }\n\n    /// Fetches an event signature given the 32 byte topic using OpenChain.\n    pub async fn decode_event_topic(&self, topic: B256) -> eyre::Result<OpenChainSignatures> {\n        self.decode_selector(SelectorKind::Event(topic)).await\n    }\n\n    /// Pretty print calldata and if available, fetch possible function signatures\n    ///\n    /// ```no_run\n    /// use foundry_common::selectors::OpenChainClient;\n    ///\n    /// # async fn foo() -> eyre::Result<()> {\n    /// let pretty_data = OpenChainClient::new()?\n    ///     .pretty_calldata(\n    ///         \"0x70a08231000000000000000000000000d0074f4e6490ae3f888d1d4f7e3e43326bd3f0f5\"\n    ///             .to_string(),\n    ///         false,\n    ///     )\n    ///     .await?;\n    /// println!(\"{}\", pretty_data);\n    /// # Ok(())\n    /// # }\n    /// ```\n    pub async fn pretty_calldata(\n        &self,\n        calldata: impl AsRef<str>,\n        offline: bool,\n    ) -> eyre::Result<PossibleSigs> {\n        let mut possible_info = PossibleSigs::new();\n        let calldata = calldata.as_ref().trim_start_matches(\"0x\");\n\n        let selector =\n            calldata.get(..8).ok_or_else(|| eyre::eyre!(\"calldata cannot be less that 4 bytes\"))?;\n\n        let sigs = if offline {\n            vec![]\n        } else {\n            let selector = selector.parse()?;\n            self.decode_function_selector(selector).await.unwrap_or_default().into_iter().collect()\n        };\n        let (_, data) = calldata.split_at(8);\n\n        if !data.len().is_multiple_of(64) {\n            eyre::bail!(\"\\nInvalid calldata size\")\n        }\n\n        let row_length = data.len() / 64;\n\n        for row in 0..row_length {\n            possible_info.data.push(data[64 * row..64 * (row + 1)].to_string());\n        }\n        if sigs.is_empty() {\n            possible_info.method = SelectorOrSig::Selector(selector.to_string());\n        } else {\n            possible_info.method = SelectorOrSig::Sig(sigs);\n        }\n        Ok(possible_info)\n    }\n\n    /// uploads selectors to OpenChain using the given data\n    pub async fn import_selectors(\n        &self,\n        data: SelectorImportData,\n    ) -> eyre::Result<SelectorImportResponse> {\n        self.ensure_not_spurious()?;\n\n        let request = match data {\n            SelectorImportData::Abi(abis) => {\n                let functions_and_errors: OpenChainSignatures = abis\n                    .iter()\n                    .flat_map(|abi| {\n                        abi.functions()\n                            .map(|func| func.signature())\n                            .chain(abi.errors().map(|error| error.signature()))\n                            .collect::<Vec<_>>()\n                    })\n                    .collect();\n\n                let events = abis\n                    .iter()\n                    .flat_map(|abi| abi.events().map(|event| event.signature()))\n                    .collect::<Vec<_>>();\n\n                SelectorImportRequest { function: functions_and_errors, event: events }\n            }\n            SelectorImportData::Raw(raw) => {\n                let function_and_error =\n                    raw.function.iter().chain(raw.error.iter()).cloned().collect::<Vec<_>>();\n                SelectorImportRequest { function: function_and_error, event: raw.event }\n            }\n        };\n\n        Ok(self.post_json(SELECTOR_IMPORT_URL, &request).await?)\n    }\n}\n\npub enum SelectorOrSig {\n    Selector(String),\n    Sig(OpenChainSignatures),\n}\n\npub struct PossibleSigs {\n    method: SelectorOrSig,\n    data: OpenChainSignatures,\n}\n\nimpl PossibleSigs {\n    fn new() -> Self {\n        Self { method: SelectorOrSig::Selector(\"0x00000000\".to_string()), data: vec![] }\n    }\n}\n\nimpl fmt::Display for PossibleSigs {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        match &self.method {\n            SelectorOrSig::Selector(selector) => {\n                writeln!(f, \"\\n Method: {selector}\")?;\n            }\n            SelectorOrSig::Sig(sigs) => {\n                writeln!(f, \"\\n Possible methods:\")?;\n                for sig in sigs {\n                    writeln!(f, \" - {sig}\")?;\n                }\n            }\n        }\n\n        writeln!(f, \" ------------\")?;\n        for (i, row) in self.data.iter().enumerate() {\n            let row_label_decimal = i * 32;\n            let row_label_hex = format!(\"{row_label_decimal:03x}\");\n            writeln!(f, \" [{row_label_hex}]: {row}\")?;\n        }\n        Ok(())\n    }\n}\n\n/// The kind of selector to fetch from OpenChain.\n#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]\npub enum SelectorKind {\n    /// A function selector.\n    Function(Selector),\n    /// A custom error selector. Behaves the same as a function selector.\n    Error(Selector),\n    /// An event selector.\n    Event(B256),\n}\n\nimpl SelectorKind {\n    /// Returns the function selector if it is a function OR custom error.\n    pub fn as_function(&self) -> Option<Selector> {\n        match *self {\n            Self::Function(selector) | Self::Error(selector) => Some(selector),\n            _ => None,\n        }\n    }\n\n    /// Returns the event selector if it is an event.\n    pub fn as_event(&self) -> Option<B256> {\n        match *self {\n            Self::Event(hash) => Some(hash),\n            _ => None,\n        }\n    }\n}\n\n/// Decodes the given function or event selector using OpenChain.\npub async fn decode_selector(selector: SelectorKind) -> eyre::Result<OpenChainSignatures> {\n    OpenChainClient::new()?.decode_selector(selector).await\n}\n\n/// Decodes the given function or event selectors using OpenChain.\npub async fn decode_selectors(\n    selectors: &[SelectorKind],\n) -> eyre::Result<Vec<OpenChainSignatures>> {\n    OpenChainClient::new()?.decode_selectors(selectors).await\n}\n\n/// Fetches a function signature given the selector using OpenChain.\npub async fn decode_function_selector(selector: Selector) -> eyre::Result<OpenChainSignatures> {\n    OpenChainClient::new()?.decode_function_selector(selector).await\n}\n\n/// Fetches all possible signatures and attempts to abi decode the calldata using OpenChain.\npub async fn decode_calldata(calldata: &str) -> eyre::Result<OpenChainSignatures> {\n    OpenChainClient::new()?.decode_calldata(calldata).await\n}\n\n/// Fetches an event signature given the 32 byte topic using OpenChain.\npub async fn decode_event_topic(topic: B256) -> eyre::Result<OpenChainSignatures> {\n    OpenChainClient::new()?.decode_event_topic(topic).await\n}\n\n/// Pretty print calldata and if available, fetch possible function signatures.\n///\n/// ```no_run\n/// use foundry_common::selectors::pretty_calldata;\n///\n/// # async fn foo() -> eyre::Result<()> {\n/// let pretty_data = pretty_calldata(\n///     \"0x70a08231000000000000000000000000d0074f4e6490ae3f888d1d4f7e3e43326bd3f0f5\".to_string(),\n///     false,\n/// )\n/// .await?;\n/// println!(\"{}\", pretty_data);\n/// # Ok(())\n/// # }\n/// ```\npub async fn pretty_calldata(\n    calldata: impl AsRef<str>,\n    offline: bool,\n) -> eyre::Result<PossibleSigs> {\n    OpenChainClient::new()?.pretty_calldata(calldata, offline).await\n}\n\n#[derive(Debug, Default, PartialEq, Eq, Serialize)]\npub struct RawSelectorImportData {\n    pub function: OpenChainSignatures,\n    pub event: OpenChainSignatures,\n    pub error: OpenChainSignatures,\n}\n\nimpl RawSelectorImportData {\n    pub fn is_empty(&self) -> bool {\n        self.function.is_empty() && self.event.is_empty() && self.error.is_empty()\n    }\n}\n\n#[derive(Serialize)]\n#[serde(untagged)]\npub enum SelectorImportData {\n    Abi(Vec<JsonAbi>),\n    Raw(RawSelectorImportData),\n}\n\n#[derive(Debug, Default, Serialize)]\nstruct SelectorImportRequest {\n    function: OpenChainSignatures,\n    event: OpenChainSignatures,\n}\n\n#[derive(Debug, Deserialize)]\nstruct SelectorImportEffect {\n    imported: HashMap<String, String>,\n    duplicated: HashMap<String, String>,\n}\n\n#[derive(Debug, Deserialize)]\nstruct SelectorImportResult {\n    function: SelectorImportEffect,\n    event: SelectorImportEffect,\n}\n\n#[derive(Debug, Deserialize)]\npub struct SelectorImportResponse {\n    result: SelectorImportResult,\n}\n\nimpl SelectorImportResponse {\n    /// Print info about the functions which were uploaded or already known\n    pub fn describe(&self) {\n        self.result.function.imported.iter().for_each(|(k, v)| {\n            let _ = sh_println!(\"Imported: Function {k}: {v}\");\n        });\n        self.result.event.imported.iter().for_each(|(k, v)| {\n            let _ = sh_println!(\"Imported: Event {k}: {v}\");\n        });\n        self.result.function.duplicated.iter().for_each(|(k, v)| {\n            let _ = sh_println!(\"Duplicated: Function {k}: {v}\");\n        });\n        self.result.event.duplicated.iter().for_each(|(k, v)| {\n            let _ = sh_println!(\"Duplicated: Event {k}: {v}\");\n        });\n\n        let _ = sh_println!(\"Selectors successfully uploaded to OpenChain\");\n    }\n}\n\n/// uploads selectors to OpenChain using the given data\npub async fn import_selectors(data: SelectorImportData) -> eyre::Result<SelectorImportResponse> {\n    OpenChainClient::new()?.import_selectors(data).await\n}\n\n#[derive(Debug, Default, PartialEq, Eq)]\npub struct ParsedSignatures {\n    pub signatures: RawSelectorImportData,\n    pub abis: Vec<JsonAbi>,\n}\n\n#[derive(Deserialize)]\nstruct Artifact {\n    abi: JsonAbi,\n}\n\n/// Parses a list of tokens into function, event, and error signatures.\n/// Also handles JSON artifact files\n/// Ignores invalid tokens\npub fn parse_signatures(tokens: Vec<String>) -> ParsedSignatures {\n    // if any of the given tokens are json artifact files,\n    // Parse them and read in the ABI from the file\n    let abis = tokens\n        .iter()\n        .filter(|sig| sig.ends_with(\".json\"))\n        .filter_map(|filename| std::fs::read_to_string(filename).ok())\n        .filter_map(|file| serde_json::from_str(file.as_str()).ok())\n        .map(|artifact: Artifact| artifact.abi)\n        .collect();\n\n    // for tokens that are not json artifact files,\n    // try to parse them as raw signatures\n    let signatures = tokens.iter().filter(|sig| !sig.ends_with(\".json\")).fold(\n        RawSelectorImportData::default(),\n        |mut data, signature| {\n            let mut split = signature.split(' ');\n            #[allow(clippy::collapsible_match)]\n            match split.next() {\n                Some(\"function\") => {\n                    if let Some(sig) = split.next() {\n                        data.function.push(sig.to_string())\n                    }\n                }\n                Some(\"event\") => {\n                    if let Some(sig) = split.next() {\n                        data.event.push(sig.to_string())\n                    }\n                }\n                Some(\"error\") => {\n                    if let Some(sig) = split.next() {\n                        data.error.push(sig.to_string())\n                    }\n                }\n                Some(signature) => {\n                    // if no type given, assume function\n                    data.function.push(signature.to_string());\n                }\n                None => {}\n            }\n            data\n        },\n    );\n\n    ParsedSignatures { signatures, abis }\n}\n\n/// [`SELECTOR_LOOKUP_URL`] response.\n#[derive(Deserialize)]\nstruct SignatureResponse {\n    ok: bool,\n    result: SignatureResult,\n}\n\n#[derive(Deserialize)]\nstruct SignatureResult {\n    event: HashMap<B256, Option<Vec<Signature>>>,\n    function: HashMap<Selector, Option<Vec<Signature>>>,\n}\n\n#[derive(Deserialize)]\nstruct Signature {\n    name: String,\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_parse_signatures() {\n        let result = parse_signatures(vec![\"transfer(address,uint256)\".to_string()]);\n        assert_eq!(\n            result,\n            ParsedSignatures {\n                signatures: RawSelectorImportData {\n                    function: vec![\"transfer(address,uint256)\".to_string()],\n                    ..Default::default()\n                },\n                ..Default::default()\n            }\n        );\n\n        let result = parse_signatures(vec![\n            \"transfer(address,uint256)\".to_string(),\n            \"function approve(address,uint256)\".to_string(),\n        ]);\n        assert_eq!(\n            result,\n            ParsedSignatures {\n                signatures: RawSelectorImportData {\n                    function: vec![\n                        \"transfer(address,uint256)\".to_string(),\n                        \"approve(address,uint256)\".to_string()\n                    ],\n                    ..Default::default()\n                },\n                ..Default::default()\n            }\n        );\n\n        let result = parse_signatures(vec![\n            \"transfer(address,uint256)\".to_string(),\n            \"event Approval(address,address,uint256)\".to_string(),\n            \"error ERC20InsufficientBalance(address,uint256,uint256)\".to_string(),\n        ]);\n        assert_eq!(\n            result,\n            ParsedSignatures {\n                signatures: RawSelectorImportData {\n                    function: vec![\"transfer(address,uint256)\".to_string()],\n                    event: vec![\"Approval(address,address,uint256)\".to_string()],\n                    error: vec![\"ERC20InsufficientBalance(address,uint256,uint256)\".to_string()]\n                },\n                ..Default::default()\n            }\n        );\n\n        // skips invalid\n        let result = parse_signatures(vec![\"event\".to_string()]);\n        assert_eq!(\n            result,\n            ParsedSignatures { signatures: Default::default(), ..Default::default() }\n        );\n    }\n\n    #[tokio::test]\n    async fn spurious_marked_on_timeout_threshold() {\n        // Use an unreachable local port to trigger a quick connect error.\n        let client = OpenChainClient::new().expect(\"client must build\");\n        let url = \"http://127.0.0.1:9\"; // Discard port; typically closed and fails fast.\n\n        // After MAX_TIMEDOUT_REQ - 1 failures we should NOT be spurious.\n        for i in 0..(MAX_TIMEDOUT_REQ - 1) {\n            let _ = client.get_text(url).await; // expect an error and internal counter increment\n            assert!(!client.is_spurious(), \"unexpected spurious after {} failed attempts\", i + 1);\n        }\n\n        // The Nth failure (N == MAX_TIMEDOUT_REQ) should flip the spurious flag.\n        let _ = client.get_text(url).await;\n        assert!(client.is_spurious(), \"expected spurious after threshold failures\");\n    }\n}\n"
  },
  {
    "path": "crates/common/src/serde_helpers.rs",
    "content": "//! Misc Serde helpers for foundry crates.\n\nuse alloy_primitives::U256;\nuse serde::{Deserialize, Deserializer, de};\nuse std::str::FromStr;\n\n/// Helper type to parse both `u64` and `U256`\n#[derive(Copy, Clone, Deserialize)]\n#[serde(untagged)]\npub enum Numeric {\n    /// A [U256] value.\n    U256(U256),\n    /// A `u64` value.\n    Num(u64),\n}\n\nimpl From<Numeric> for U256 {\n    fn from(n: Numeric) -> Self {\n        match n {\n            Numeric::U256(n) => n,\n            Numeric::Num(n) => Self::from(n),\n        }\n    }\n}\n\nimpl FromStr for Numeric {\n    type Err = String;\n\n    fn from_str(s: &str) -> Result<Self, Self::Err> {\n        if let Ok(val) = s.parse::<u128>() {\n            Ok(Self::U256(U256::from(val)))\n        } else if s.starts_with(\"0x\") {\n            U256::from_str_radix(s, 16).map(Numeric::U256).map_err(|err| err.to_string())\n        } else {\n            U256::from_str(s).map(Numeric::U256).map_err(|err| err.to_string())\n        }\n    }\n}\n\n/// An enum that represents either a [serde_json::Number] integer, or a hex [U256].\n#[derive(Debug, Deserialize)]\n#[serde(untagged)]\npub enum NumberOrHexU256 {\n    /// An integer\n    Int(serde_json::Number),\n    /// A hex U256\n    Hex(U256),\n}\n\nimpl NumberOrHexU256 {\n    /// Tries to convert this into a [U256]].\n    pub fn try_into_u256<E: de::Error>(self) -> Result<U256, E> {\n        match self {\n            Self::Int(num) => U256::from_str(&num.to_string()).map_err(E::custom),\n            Self::Hex(val) => Ok(val),\n        }\n    }\n}\n\n/// Deserializes the input into a U256, accepting both 0x-prefixed hex and decimal strings with\n/// arbitrary precision, defined by serde_json's [`Number`](serde_json::Number).\npub fn from_int_or_hex<'de, D>(deserializer: D) -> Result<U256, D::Error>\nwhere\n    D: Deserializer<'de>,\n{\n    NumberOrHexU256::deserialize(deserializer)?.try_into_u256()\n}\n\n/// Helper type to deserialize sequence of numbers\n#[derive(Deserialize)]\n#[serde(untagged)]\npub enum NumericSeq {\n    /// Single parameter sequence (e.g `[1]`).\n    Seq([Numeric; 1]),\n    /// `U256`.\n    U256(U256),\n    /// Native `u64`.\n    Num(u64),\n}\n\n/// Deserializes a number from hex or int\npub fn deserialize_number<'de, D>(deserializer: D) -> Result<U256, D::Error>\nwhere\n    D: Deserializer<'de>,\n{\n    Numeric::deserialize(deserializer).map(Into::into)\n}\n\n/// Deserializes a number from hex or int, but optionally\npub fn deserialize_number_opt<'de, D>(deserializer: D) -> Result<Option<U256>, D::Error>\nwhere\n    D: Deserializer<'de>,\n{\n    let num = match Option::<Numeric>::deserialize(deserializer)? {\n        Some(Numeric::U256(n)) => Some(n),\n        Some(Numeric::Num(n)) => Some(U256::from(n)),\n        _ => None,\n    };\n\n    Ok(num)\n}\n\n/// Deserializes single integer params: `1, [1], [\"0x01\"]`\npub fn deserialize_number_seq<'de, D>(deserializer: D) -> Result<U256, D::Error>\nwhere\n    D: Deserializer<'de>,\n{\n    let num = match NumericSeq::deserialize(deserializer)? {\n        NumericSeq::Seq(seq) => seq[0].into(),\n        NumericSeq::U256(n) => n,\n        NumericSeq::Num(n) => U256::from(n),\n    };\n\n    Ok(num)\n}\n\npub mod duration {\n    use serde::{Deserialize, Deserializer};\n    use std::time::Duration;\n\n    pub fn serialize<S>(duration: &Duration, serializer: S) -> Result<S::Ok, S::Error>\n    where\n        S: serde::Serializer,\n    {\n        let d = jiff::SignedDuration::try_from(*duration).map_err(serde::ser::Error::custom)?;\n        serializer.serialize_str(&format!(\"{d:#}\"))\n    }\n\n    pub fn deserialize<'de, D>(deserializer: D) -> Result<Duration, D::Error>\n    where\n        D: Deserializer<'de>,\n    {\n        let s = String::deserialize(deserializer)?;\n        let d = s.parse::<jiff::SignedDuration>().map_err(serde::de::Error::custom)?;\n        d.try_into().map_err(serde::de::Error::custom)\n    }\n}\n"
  },
  {
    "path": "crates/common/src/slot_identifier.rs",
    "content": "//! Storage slot identification and decoding utilities for Solidity storage layouts.\n//!\n//! This module provides functionality to identify and decode storage slots based on\n//! Solidity storage layout information from the compiler.\n\nuse crate::mapping_slots::MappingSlots;\nuse alloy_dyn_abi::{DynSolType, DynSolValue};\nuse alloy_primitives::{B256, U256, hex, keccak256, map::B256Map};\nuse foundry_common_fmt::format_token_raw;\nuse foundry_compilers::artifacts::{Storage, StorageLayout, StorageType};\nuse serde::Serialize;\nuse std::{collections::BTreeMap, str::FromStr, sync::Arc};\nuse tracing::trace;\n\n/// \"inplace\" encoding type for variables that fit in one storage slot i.e 32 bytes\npub const ENCODING_INPLACE: &str = \"inplace\";\n/// \"mapping\" encoding type for Solidity mappings, which use keccak256 hash-based storage\npub const ENCODING_MAPPING: &str = \"mapping\";\n/// \"bytes\" encoding type for bytes and string types, which use either inplace or keccak256\n/// hash-based storage depending on length\npub const ENCODING_BYTES: &str = \"bytes\";\n/// \"dynamic_array\" encoding type for dynamic arrays, which uses keccak256 hash-based storage\npub const ENCODING_DYN_ARRAY: &str = \"dynamic_array\";\n\n/// Information about a storage slot including its label, type, and decoded values.\n#[derive(Serialize, Debug)]\npub struct SlotInfo {\n    /// The variable name from the storage layout.\n    ///\n    /// For top-level variables: just the variable name (e.g., \"myVariable\")\n    /// For struct members: dotted path (e.g., \"myStruct.memberName\")\n    /// For array elements: name with indices (e.g., \"myArray\\[0\\]\", \"matrix\\[1\\]\\[2\\]\")\n    /// For nested structures: full path (e.g., \"outer.inner.field\")\n    /// For mappings: base name with keys (e.g., \"balances\\[0x1234...\\]\")/ex\n    pub label: String,\n    /// The Solidity type information\n    #[serde(rename = \"type\", serialize_with = \"serialize_slot_type\")]\n    pub slot_type: StorageTypeInfo,\n    /// Offset within the storage slot (for packed storage)\n    pub offset: i64,\n    /// The storage slot number as a string\n    pub slot: String,\n    /// For struct members, contains nested SlotInfo for each member\n    ///\n    /// This is populated when a struct's members / fields are packed in a single slot.\n    #[serde(skip_serializing_if = \"Option::is_none\")]\n    pub members: Option<Vec<Self>>,\n    /// Decoded values (if available) - used for struct members\n    #[serde(skip_serializing_if = \"Option::is_none\")]\n    pub decoded: Option<DecodedSlotValues>,\n    /// Decoded mapping keys (serialized as \"key\" for single, \"keys\" for multiple)\n    #[serde(\n        skip_serializing_if = \"Option::is_none\",\n        flatten,\n        serialize_with = \"serialize_mapping_keys\"\n    )]\n    pub keys: Option<Vec<String>>,\n}\n\n/// Wrapper type that holds both the original type label and the parsed DynSolType.\n///\n/// We need both because:\n/// - `label`: Used for serialization to ensure output matches user expectations\n/// - `dyn_sol_type`: The parsed type used for actual value decoding\n#[derive(Debug)]\npub struct StorageTypeInfo {\n    /// The original type label from storage layout (e.g., \"uint256\", \"address\", \"mapping(address\n    /// => uint256)\")\n    pub label: String,\n    /// The parsed dynamic Solidity type used for decoding\n    pub dyn_sol_type: DynSolType,\n}\n\nimpl SlotInfo {\n    /// Decodes a single storage value based on the slot's type information.\n    ///\n    /// Note: For decoding [`DynSolType::Bytes`] or [`DynSolType::String`] that span multiple slots,\n    /// use [`SlotInfo::decode_bytes_or_string`].\n    pub fn decode(&self, value: B256) -> Option<DynSolValue> {\n        // Storage values are always 32 bytes, stored as a single word\n        let mut actual_type = &self.slot_type.dyn_sol_type;\n        // Unwrap nested arrays to get to the base element type.\n        while let DynSolType::FixedArray(elem_type, _) = actual_type {\n            actual_type = elem_type.as_ref();\n        }\n\n        // Special handling for bytes and string types\n        match actual_type {\n            DynSolType::Bytes | DynSolType::String => {\n                // Decode bytes/string from storage\n                // The last byte contains the length * 2 for short strings/bytes\n                // or length * 2 + 1 for long strings/bytes\n                let length_byte = value.0[31];\n\n                if length_byte & 1 == 0 {\n                    // Short string/bytes (less than 32 bytes)\n                    let length = (length_byte >> 1) as usize;\n                    // Extract data\n                    let data = if length == 0 { Vec::new() } else { value.0[0..length].to_vec() };\n\n                    // Create the appropriate value based on type\n                    if matches!(actual_type, DynSolType::String) {\n                        let str_val = if data.is_empty() {\n                            String::new()\n                        } else {\n                            String::from_utf8(data).unwrap_or_default()\n                        };\n                        Some(DynSolValue::String(str_val))\n                    } else {\n                        Some(DynSolValue::Bytes(data))\n                    }\n                } else {\n                    // Long string/bytes (32 bytes or more)\n                    // The actual data is stored at keccak256(slot)\n                    // Return None for long values - they need decode_bytes_or_string()\n                    None\n                }\n            }\n            _ => {\n                // Decode based on the actual type\n                actual_type.abi_decode(&value.0).ok()\n            }\n        }\n    }\n\n    /// Slot is of type [`DynSolType::Bytes`] or [`DynSolType::String`]\n    pub fn is_bytes_or_string(&self) -> bool {\n        matches!(self.slot_type.dyn_sol_type, DynSolType::Bytes | DynSolType::String)\n    }\n\n    /// Decodes a [`DynSolType::Bytes`] or [`DynSolType::String`] value\n    /// that spans across multiple slots.\n    pub fn decode_bytes_or_string(\n        &mut self,\n        base_slot: &B256,\n        storage_values: &B256Map<B256>,\n    ) -> Option<DynSolValue> {\n        // Only process bytes/string types\n        if !self.is_bytes_or_string() {\n            return None;\n        }\n\n        // Try to handle as long bytes/string\n        self.aggregate_bytes_or_strings(base_slot, storage_values).map(|data| {\n            match self.slot_type.dyn_sol_type {\n                DynSolType::String => {\n                    DynSolValue::String(String::from_utf8(data).unwrap_or_default())\n                }\n                DynSolType::Bytes => DynSolValue::Bytes(data),\n                _ => unreachable!(),\n            }\n        })\n    }\n\n    /// Decodes both previous and new [`DynSolType::Bytes`] or [`DynSolType::String`] values\n    /// that span across multiple slots using state diff data.\n    ///\n    /// Accepts a mapping of storage_slot to (previous_value, new_value).\n    pub fn decode_bytes_or_string_values(\n        &mut self,\n        base_slot: &B256,\n        storage_accesses: &BTreeMap<B256, (B256, B256)>,\n    ) {\n        // Only process bytes/string types\n        if !self.is_bytes_or_string() {\n            return;\n        }\n\n        // Get both previous and new values from the storage accesses\n        if let Some((prev_base_value, new_base_value)) = storage_accesses.get(base_slot) {\n            // Reusable closure to decode bytes/string based on length encoding\n            let mut decode_value = |base_value: B256, is_new: bool| {\n                let length_byte = base_value.0[31];\n                if length_byte & 1 == 1 {\n                    // Long bytes/string - aggregate from multiple slots\n                    let value_map = storage_accesses\n                        .iter()\n                        .map(|(slot, (prev, new))| (*slot, if is_new { *new } else { *prev }))\n                        .collect::<B256Map<_>>();\n                    self.decode_bytes_or_string(base_slot, &value_map)\n                } else {\n                    // Short bytes/string - decode directly from base slot\n                    self.decode(base_value)\n                }\n            };\n\n            // Decode previous value\n            let prev_decoded = decode_value(*prev_base_value, false);\n\n            // Decode new value\n            let new_decoded = decode_value(*new_base_value, true);\n\n            // Set decoded values if both were successfully decoded\n            if let (Some(prev), Some(new)) = (prev_decoded, new_decoded) {\n                self.decoded = Some(DecodedSlotValues { previous_value: prev, new_value: new });\n            }\n        }\n    }\n\n    /// Aggregates a [`DynSolType::Bytes`] or [`DynSolType::String`] value that spans across\n    /// multiple slots by looking up the length in the base_slot.\n    ///\n    /// Returns the aggregated raw bytes.\n    fn aggregate_bytes_or_strings(\n        &mut self,\n        base_slot: &B256,\n        storage_values: &B256Map<B256>,\n    ) -> Option<Vec<u8>> {\n        if !self.is_bytes_or_string() {\n            return None;\n        }\n\n        // Check if it's a long bytes/string by looking at the base value\n        if let Some(base_value) = storage_values.get(base_slot) {\n            let length_byte = base_value.0[31];\n\n            // Check if value is long\n            if length_byte & 1 == 1 {\n                // Long bytes/string - populate members\n                let length: U256 = U256::from_be_bytes(base_value.0) >> 1;\n                let num_slots = length.to::<usize>().div_ceil(32).min(256);\n                let data_start = U256::from_be_bytes(keccak256(base_slot.0).0);\n\n                let mut members = Vec::new();\n                let mut full_data = Vec::with_capacity(length.to::<usize>());\n\n                for i in 0..num_slots {\n                    let data_slot = B256::from(data_start + U256::from(i));\n                    let data_slot_u256 = data_start + U256::from(i);\n\n                    // Create member info for this data slot with indexed label\n                    let member_info = Self {\n                        label: format!(\"{}[{}]\", self.label, i),\n                        slot_type: StorageTypeInfo {\n                            label: self.slot_type.label.clone(),\n                            dyn_sol_type: DynSolType::FixedBytes(32),\n                        },\n                        offset: 0,\n                        slot: data_slot_u256.to_string(),\n                        members: None,\n                        decoded: None,\n                        keys: None,\n                    };\n\n                    if let Some(value) = storage_values.get(&data_slot) {\n                        // Collect data\n                        let bytes_to_take =\n                            std::cmp::min(32, length.to::<usize>() - full_data.len());\n                        full_data.extend_from_slice(&value.0[..bytes_to_take]);\n                    }\n\n                    members.push(member_info);\n                }\n\n                // Set the members field\n                if !members.is_empty() {\n                    self.members = Some(members);\n                }\n\n                return Some(full_data);\n            }\n        }\n\n        None\n    }\n\n    /// Decodes storage values (previous and new) and populates the decoded field.\n    /// For structs with members, it decodes each member individually.\n    pub fn decode_values(&mut self, previous_value: B256, new_value: B256) {\n        // If this is a struct with members, decode each member individually\n        if let Some(members) = &mut self.members {\n            for member in members.iter_mut() {\n                let offset = member.offset as usize;\n                let size = match &member.slot_type.dyn_sol_type {\n                    DynSolType::Uint(bits) | DynSolType::Int(bits) => bits / 8,\n                    DynSolType::Address => 20,\n                    DynSolType::Bool => 1,\n                    DynSolType::FixedBytes(size) => *size,\n                    _ => 32, // Default to full word\n                };\n\n                // Extract and decode member values\n                let mut prev_bytes = [0u8; 32];\n                let mut new_bytes = [0u8; 32];\n\n                if offset + size <= 32 {\n                    // In Solidity storage, values are right-aligned\n                    // For offset 0, we want the rightmost bytes\n                    // For offset 16 (for a uint128), we want bytes 0-16\n                    // For packed storage: offset 0 is at the rightmost position\n                    // offset 0, size 16 -> read bytes 16-32 (rightmost)\n                    // offset 16, size 16 -> read bytes 0-16 (leftmost)\n                    let byte_start = 32 - offset - size;\n                    prev_bytes[32 - size..]\n                        .copy_from_slice(&previous_value.0[byte_start..byte_start + size]);\n                    new_bytes[32 - size..]\n                        .copy_from_slice(&new_value.0[byte_start..byte_start + size]);\n                }\n\n                // Decode the member values\n                if let (Ok(prev_val), Ok(new_val)) = (\n                    member.slot_type.dyn_sol_type.abi_decode(&prev_bytes),\n                    member.slot_type.dyn_sol_type.abi_decode(&new_bytes),\n                ) {\n                    member.decoded =\n                        Some(DecodedSlotValues { previous_value: prev_val, new_value: new_val });\n                }\n            }\n            // For structs with members, we don't need a top-level decoded value\n        } else {\n            // For non-struct types, decode directly\n            // Note: decode() returns None for long bytes/strings, which will be handled by\n            // decode_bytes_or_string()\n            if let (Some(prev), Some(new)) = (self.decode(previous_value), self.decode(new_value)) {\n                self.decoded = Some(DecodedSlotValues { previous_value: prev, new_value: new });\n            }\n        }\n    }\n}\n\n/// Custom serializer for StorageTypeInfo that only outputs the label\nfn serialize_slot_type<S>(info: &StorageTypeInfo, serializer: S) -> Result<S::Ok, S::Error>\nwhere\n    S: serde::Serializer,\n{\n    serializer.serialize_str(&info.label)\n}\n\n/// Custom serializer for mapping keys\nfn serialize_mapping_keys<S>(keys: &Option<Vec<String>>, serializer: S) -> Result<S::Ok, S::Error>\nwhere\n    S: serde::Serializer,\n{\n    use serde::ser::SerializeMap;\n\n    if let Some(keys) = keys {\n        let len = if keys.is_empty() { 0 } else { 1 };\n        let mut map = serializer.serialize_map(Some(len))?;\n        if keys.len() == 1 {\n            map.serialize_entry(\"key\", &keys[0])?;\n        } else if keys.len() > 1 {\n            map.serialize_entry(\"keys\", keys)?;\n        }\n        map.end()\n    } else {\n        serializer.serialize_none()\n    }\n}\n\n/// Decoded storage slot values\n#[derive(Debug)]\npub struct DecodedSlotValues {\n    /// Initial decoded storage value\n    pub previous_value: DynSolValue,\n    /// Current decoded storage value\n    pub new_value: DynSolValue,\n}\n\nimpl Serialize for DecodedSlotValues {\n    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>\n    where\n        S: serde::Serializer,\n    {\n        use serde::ser::SerializeStruct;\n\n        let mut state = serializer.serialize_struct(\"DecodedSlotValues\", 2)?;\n        state.serialize_field(\"previousValue\", &format_token_raw(&self.previous_value))?;\n        state.serialize_field(\"newValue\", &format_token_raw(&self.new_value))?;\n        state.end()\n    }\n}\n\n/// Storage slot identifier that uses Solidity [`StorageLayout`] to identify storage slots.\npub struct SlotIdentifier {\n    storage_layout: Arc<StorageLayout>,\n}\n\nimpl SlotIdentifier {\n    /// Creates a new SlotIdentifier with the given storage layout.\n    pub fn new(storage_layout: Arc<StorageLayout>) -> Self {\n        Self { storage_layout }\n    }\n\n    /// Identifies a storage slots type using the [`StorageLayout`].\n    ///\n    /// It can also identify whether a slot belongs to a mapping if provided with [`MappingSlots`].\n    pub fn identify(&self, slot: &B256, mapping_slots: Option<&MappingSlots>) -> Option<SlotInfo> {\n        trace!(?slot, \"identifying slot\");\n        let slot_u256 = U256::from_be_bytes(slot.0);\n        let slot_str = slot_u256.to_string();\n\n        for storage in &self.storage_layout.storage {\n            let storage_type = self.storage_layout.types.get(&storage.storage_type)?;\n            let dyn_type = DynSolType::parse(&storage_type.label).ok();\n\n            // Check if we're able to match on a slot from the layout i.e any of the base slots.\n            // This will always be the case for primitive types that fit in a single slot.\n            if storage.slot == slot_str\n                && let Some(parsed_type) = dyn_type\n            {\n                // Successfully parsed - handle arrays or simple types\n                let label = if let DynSolType::FixedArray(_, _) = &parsed_type {\n                    format!(\"{}{}\", storage.label, get_array_base_indices(&parsed_type))\n                } else {\n                    storage.label.clone()\n                };\n\n                return Some(SlotInfo {\n                    label,\n                    slot_type: StorageTypeInfo {\n                        label: storage_type.label.clone(),\n                        dyn_sol_type: parsed_type,\n                    },\n                    offset: storage.offset,\n                    slot: storage.slot.clone(),\n                    members: None,\n                    decoded: None,\n                    keys: None,\n                });\n            }\n\n            // Encoding types: <https://docs.soliditylang.org/en/latest/internals/layout_in_storage.html#json-output>\n            if storage_type.encoding == ENCODING_INPLACE {\n                // Can be of type FixedArrays or Structs\n                // Handles the case where the accessed `slot` is maybe different from the base slot.\n                let array_start_slot = U256::from_str(&storage.slot).ok()?;\n\n                if let Some(parsed_type) = dyn_type\n                    && let DynSolType::FixedArray(_, _) = parsed_type\n                    && let Some(slot_info) = self.handle_array_slot(\n                        storage,\n                        storage_type,\n                        slot_u256,\n                        array_start_slot,\n                        &slot_str,\n                    )\n                {\n                    return Some(slot_info);\n                }\n\n                // If type parsing fails and the label is a struct\n                if is_struct(&storage_type.label) {\n                    let struct_start_slot = U256::from_str(&storage.slot).ok()?;\n                    if let Some(slot_info) = self.handle_struct(\n                        &storage.label,\n                        storage_type,\n                        slot_u256,\n                        struct_start_slot,\n                        storage.offset,\n                        &slot_str,\n                        0,\n                    ) {\n                        return Some(slot_info);\n                    }\n                }\n            } else if storage_type.encoding == ENCODING_MAPPING\n                && let Some(mapping_slots) = mapping_slots\n                && let Some(info) =\n                    self.handle_mapping(storage, storage_type, slot, &slot_str, mapping_slots)\n            {\n                return Some(info);\n            }\n        }\n\n        None\n    }\n\n    /// Identifies a bytes or string storage slot by checking all bytes/string variables\n    /// in the storage layout and using their base slot values from the provided storage changes.\n    ///\n    /// # Arguments\n    /// * `slot` - The slot being identified\n    /// * `storage_values` - Map of storage slots to their current values\n    pub fn identify_bytes_or_string(\n        &self,\n        slot: &B256,\n        storage_values: &B256Map<B256>,\n    ) -> Option<SlotInfo> {\n        let slot_u256 = U256::from_be_bytes(slot.0);\n        let slot_str = slot_u256.to_string();\n\n        // Search through all bytes/string variables in the storage layout\n        for storage in &self.storage_layout.storage {\n            if let Some(storage_type) = self.storage_layout.types.get(&storage.storage_type)\n                && storage_type.encoding == ENCODING_BYTES\n            {\n                let Some(base_slot) = U256::from_str(&storage.slot).map(B256::from).ok() else {\n                    continue;\n                };\n                // Get the base slot value from storage_values\n                if let Some(base_value) = storage_values.get(&base_slot)\n                    && let Some(info) = self.handle_bytes_string(\n                        storage,\n                        storage_type,\n                        slot_u256,\n                        &slot_str,\n                        base_value,\n                    )\n                {\n                    return Some(info);\n                }\n            }\n        }\n\n        None\n    }\n\n    /// Handles identification of array slots.\n    ///\n    /// # Arguments\n    /// * `storage` - The storage metadata from the layout\n    /// * `storage_type` - Type information for the storage slot\n    /// * `slot` - The target slot being identified\n    /// * `array_start_slot` - The starting slot of the array in storage i.e base_slot\n    /// * `slot_str` - String representation of the slot for output\n    fn handle_array_slot(\n        &self,\n        storage: &Storage,\n        storage_type: &StorageType,\n        slot: U256,\n        array_start_slot: U256,\n        slot_str: &str,\n    ) -> Option<SlotInfo> {\n        // Check if slot is within array bounds\n        let total_bytes = storage_type.number_of_bytes.parse::<u64>().ok()?;\n        let total_slots = total_bytes.div_ceil(32);\n\n        if slot >= array_start_slot && slot < array_start_slot + U256::from(total_slots) {\n            let parsed_type = DynSolType::parse(&storage_type.label).ok()?;\n            let index = (slot - array_start_slot).to::<u64>();\n            // Format the array element label based on array dimensions\n            let label = match &parsed_type {\n                DynSolType::FixedArray(inner, _) => {\n                    if let DynSolType::FixedArray(_, inner_size) = inner.as_ref() {\n                        // 2D array: calculate row and column\n                        let row = index / (*inner_size as u64);\n                        let col = index % (*inner_size as u64);\n                        format!(\"{}[{row}][{col}]\", storage.label)\n                    } else {\n                        // 1D array\n                        format!(\"{}[{index}]\", storage.label)\n                    }\n                }\n                _ => storage.label.clone(),\n            };\n\n            return Some(SlotInfo {\n                label,\n                slot_type: StorageTypeInfo {\n                    label: storage_type.label.clone(),\n                    dyn_sol_type: parsed_type,\n                },\n                offset: 0,\n                slot: slot_str.to_string(),\n                members: None,\n                decoded: None,\n                keys: None,\n            });\n        }\n\n        None\n    }\n\n    /// Handles identification of struct slots.\n    ///\n    /// Recursively resolves struct members to find the exact member corresponding\n    /// to the target slot. Handles both single-slot (packed) and multi-slot structs.\n    ///\n    /// # Arguments\n    /// * `base_label` - The label/name for this struct or member\n    /// * `storage_type` - Type information for the storage\n    /// * `target_slot` - The target slot being identified\n    /// * `struct_start_slot` - The starting slot of this struct\n    /// * `offset` - Offset within the slot (for packed storage)\n    /// * `slot_str` - String representation of the slot for output\n    /// * `depth` - Current recursion depth\n    #[allow(clippy::too_many_arguments)]\n    fn handle_struct(\n        &self,\n        base_label: &str,\n        storage_type: &StorageType,\n        target_slot: U256,\n        struct_start_slot: U256,\n        offset: i64,\n        slot_str: &str,\n        depth: usize,\n    ) -> Option<SlotInfo> {\n        // Limit recursion depth to prevent stack overflow\n        const MAX_DEPTH: usize = 10;\n        if depth > MAX_DEPTH {\n            return None;\n        }\n\n        let members = storage_type\n            .other\n            .get(\"members\")\n            .and_then(|v| serde_json::from_value::<Vec<Storage>>(v.clone()).ok())?;\n\n        // If this is the exact slot we're looking for (struct's base slot)\n        if struct_start_slot == target_slot\n        // Find the member at slot offset 0 (the member that starts at this slot)\n            && let Some(first_member) = members.iter().find(|m| m.slot == \"0\")\n        {\n            let member_type_info = self.storage_layout.types.get(&first_member.storage_type)?;\n\n            // Check if we have a single-slot struct (all members have slot \"0\")\n            let is_single_slot = members.iter().all(|m| m.slot == \"0\");\n\n            if is_single_slot {\n                // Build member info for single-slot struct\n                let mut member_infos = Vec::new();\n                for member in &members {\n                    if let Some(member_type_info) =\n                        self.storage_layout.types.get(&member.storage_type)\n                        && let Some(member_type) = DynSolType::parse(&member_type_info.label).ok()\n                    {\n                        member_infos.push(SlotInfo {\n                            label: member.label.clone(),\n                            slot_type: StorageTypeInfo {\n                                label: member_type_info.label.clone(),\n                                dyn_sol_type: member_type,\n                            },\n                            offset: member.offset,\n                            slot: slot_str.to_string(),\n                            members: None,\n                            decoded: None,\n                            keys: None,\n                        });\n                    }\n                }\n\n                // Build the CustomStruct type\n                let struct_name =\n                    storage_type.label.strip_prefix(\"struct \").unwrap_or(&storage_type.label);\n                let prop_names: Vec<String> = members.iter().map(|m| m.label.clone()).collect();\n                let member_types: Vec<DynSolType> =\n                    member_infos.iter().map(|info| info.slot_type.dyn_sol_type.clone()).collect();\n\n                let parsed_type = DynSolType::CustomStruct {\n                    name: struct_name.to_string(),\n                    prop_names,\n                    tuple: member_types,\n                };\n\n                return Some(SlotInfo {\n                    label: base_label.to_string(),\n                    slot_type: StorageTypeInfo {\n                        label: storage_type.label.clone(),\n                        dyn_sol_type: parsed_type,\n                    },\n                    offset,\n                    slot: slot_str.to_string(),\n                    decoded: None,\n                    members: if member_infos.is_empty() { None } else { Some(member_infos) },\n                    keys: None,\n                });\n            } else {\n                // Multi-slot struct - return the first member.\n                let member_label = format!(\"{}.{}\", base_label, first_member.label);\n\n                // If the first member is itself a struct, recurse\n                if is_struct(&member_type_info.label) {\n                    return self.handle_struct(\n                        &member_label,\n                        member_type_info,\n                        target_slot,\n                        struct_start_slot,\n                        first_member.offset,\n                        slot_str,\n                        depth + 1,\n                    );\n                }\n\n                // Return the first member as a primitive\n                return Some(SlotInfo {\n                    label: member_label,\n                    slot_type: StorageTypeInfo {\n                        label: member_type_info.label.clone(),\n                        dyn_sol_type: DynSolType::parse(&member_type_info.label).ok()?,\n                    },\n                    offset: first_member.offset,\n                    slot: slot_str.to_string(),\n                    decoded: None,\n                    members: None,\n                    keys: None,\n                });\n            }\n        }\n\n        // Not the base slot - search through members\n        for member in &members {\n            let member_slot_offset = U256::from_str(&member.slot).ok()?;\n            let member_slot = struct_start_slot + member_slot_offset;\n            let member_type_info = self.storage_layout.types.get(&member.storage_type)?;\n            let member_label = format!(\"{}.{}\", base_label, member.label);\n\n            // If this member is a struct, recurse into it\n            if is_struct(&member_type_info.label) {\n                let slot_info = self.handle_struct(\n                    &member_label,\n                    member_type_info,\n                    target_slot,\n                    member_slot,\n                    member.offset,\n                    slot_str,\n                    depth + 1,\n                );\n\n                if member_slot == target_slot || slot_info.is_some() {\n                    return slot_info;\n                }\n            }\n\n            if member_slot == target_slot {\n                // Found the exact member slot\n\n                // Regular member\n                let member_type = DynSolType::parse(&member_type_info.label).ok()?;\n                return Some(SlotInfo {\n                    label: member_label,\n                    slot_type: StorageTypeInfo {\n                        label: member_type_info.label.clone(),\n                        dyn_sol_type: member_type,\n                    },\n                    offset: member.offset,\n                    slot: slot_str.to_string(),\n                    members: None,\n                    decoded: None,\n                    keys: None,\n                });\n            }\n        }\n\n        None\n    }\n\n    /// Handles identification of mapping slots.\n    ///\n    /// Identifies mapping entries by walking up the parent chain to find the base slot,\n    /// then decodes the keys and builds the appropriate label.\n    ///\n    /// # Arguments\n    /// * `storage` - The storage metadata from the layout\n    /// * `storage_type` - Type information for the storage\n    /// * `slot` - The accessed slot being identified\n    /// * `slot_str` - String representation of the slot for output\n    /// * `mapping_slots` - Tracked mapping slot accesses for key resolution\n    fn handle_mapping(\n        &self,\n        storage: &Storage,\n        storage_type: &StorageType,\n        slot: &B256,\n        slot_str: &str,\n        mapping_slots: &MappingSlots,\n    ) -> Option<SlotInfo> {\n        trace!(\n            \"handle_mapping: storage.slot={}, slot={:?}, has_keys={}, has_parents={}\",\n            storage.slot,\n            slot,\n            mapping_slots.keys.contains_key(slot),\n            mapping_slots.parent_slots.contains_key(slot)\n        );\n\n        // Verify it's actually a mapping type\n        if storage_type.encoding != ENCODING_MAPPING {\n            return None;\n        }\n\n        // Check if this slot is a known mapping entry\n        if !mapping_slots.keys.contains_key(slot) {\n            return None;\n        }\n\n        // Convert storage.slot to B256 for comparison\n        let storage_slot_b256 = B256::from(U256::from_str(&storage.slot).ok()?);\n\n        // Walk up the parent chain to collect keys and validate the base slot\n        let mut current_slot = *slot;\n        let mut keys_to_decode = Vec::new();\n        let mut found_base = false;\n\n        while let Some((key, parent)) =\n            mapping_slots.keys.get(&current_slot).zip(mapping_slots.parent_slots.get(&current_slot))\n        {\n            keys_to_decode.push(*key);\n\n            // Check if the parent is our base storage slot\n            if *parent == storage_slot_b256 {\n                found_base = true;\n                break;\n            }\n\n            // Move up to the parent for the next iteration\n            current_slot = *parent;\n        }\n\n        if !found_base {\n            trace!(\"Mapping slot {} does not match any parent in chain\", storage.slot);\n            return None;\n        }\n\n        // Resolve the mapping type to get all key types and the final value type\n        let (key_types, value_type_label, full_type_label) =\n            self.resolve_mapping_type(&storage.storage_type)?;\n\n        // Reverse keys to process from outermost to innermost\n        keys_to_decode.reverse();\n\n        // Build the label with decoded keys and collect decoded key values\n        let mut label = storage.label.clone();\n        let mut decoded_keys = Vec::new();\n\n        // Decode each key using the corresponding type\n        for (i, key) in keys_to_decode.iter().enumerate() {\n            if let Some(key_type_label) = key_types.get(i)\n                && let Ok(sol_type) = DynSolType::parse(key_type_label)\n                && let Ok(decoded) = sol_type.abi_decode(&key.0)\n            {\n                let decoded_key_str = format_token_raw(&decoded);\n                decoded_keys.push(decoded_key_str.clone());\n                label = format!(\"{label}[{decoded_key_str}]\");\n            } else {\n                let hex_key = hex::encode_prefixed(key.0);\n                decoded_keys.push(hex_key.clone());\n                label = format!(\"{label}[{hex_key}]\");\n            }\n        }\n\n        // Parse the final value type for decoding\n        let dyn_sol_type = DynSolType::parse(&value_type_label).unwrap_or(DynSolType::Bytes);\n\n        Some(SlotInfo {\n            label,\n            slot_type: StorageTypeInfo { label: full_type_label, dyn_sol_type },\n            offset: storage.offset,\n            slot: slot_str.to_string(),\n            members: None,\n            decoded: None,\n            keys: Some(decoded_keys),\n        })\n    }\n\n    /// Handles identification of bytes/string storage slots.\n    ///\n    /// Bytes and strings in Solidity use a special storage layout:\n    /// - Short values (<32 bytes): stored in the same slot with length * 2\n    /// - Long values (>=32 bytes): length * 2 + 1 in main slot, data at keccak256(slot)\n    ///\n    /// This function checks if the given slot is:\n    /// 1. A main slot for a bytes/string variable\n    /// 2. A data slot for any long bytes/string variable in the storage layout\n    ///\n    /// # Arguments\n    /// * `slot` - The accessed slot being identified\n    /// * `slot_str` - String representation of the slot for output\n    /// * `base_slot_value` - The value at the base slot (used to determine length for long\n    ///   bytes/strings)\n    fn handle_bytes_string(\n        &self,\n        storage: &Storage,\n        storage_type: &StorageType,\n        slot: U256,\n        slot_str: &str,\n        base_slot_value: &B256,\n    ) -> Option<SlotInfo> {\n        // Only handle bytes/string encoded variables for this specific storage entry\n        if storage_type.encoding != ENCODING_BYTES {\n            return None;\n        }\n\n        // Check if this is the main slot for this variable\n        let base_slot = U256::from_str(&storage.slot).ok()?;\n        if slot == base_slot {\n            // Parse the type to get the correct DynSolType\n            let dyn_type = if storage_type.label == \"string\" {\n                DynSolType::String\n            } else if storage_type.label == \"bytes\" {\n                DynSolType::Bytes\n            } else {\n                return None;\n            };\n\n            return Some(SlotInfo {\n                label: storage.label.clone(),\n                slot_type: StorageTypeInfo {\n                    label: storage_type.label.clone(),\n                    dyn_sol_type: dyn_type,\n                },\n                offset: storage.offset,\n                slot: slot_str.to_string(),\n                members: None,\n                decoded: None,\n                keys: None,\n            });\n        }\n\n        // Check if it could be a data slot for this long bytes/string\n        // Calculate where data slots would start for this variable\n        let data_start =\n            U256::from_be_bytes(alloy_primitives::keccak256(base_slot.to_be_bytes::<32>()).0);\n\n        // Get the length from the base slot value to calculate exact number of slots\n        // For long bytes/strings, the length is stored as (length * 2 + 1) in the base slot\n        let length_byte = base_slot_value.0[31];\n        if length_byte & 1 == 1 {\n            // It's a long bytes/string\n            let length = U256::from_be_bytes(base_slot_value.0) >> 1;\n            // Calculate number of slots needed (round up)\n            let num_slots = (length + U256::from(31)) / U256::from(32);\n\n            // Check if our slot is within the data region\n            if slot >= data_start && slot < data_start + num_slots {\n                let slot_index = (slot - data_start).to::<usize>();\n\n                return Some(SlotInfo {\n                    label: format!(\"{}[{}]\", storage.label, slot_index),\n                    slot_type: StorageTypeInfo {\n                        label: storage_type.label.clone(),\n                        // Type is assigned as FixedBytes(32) for data slots\n                        dyn_sol_type: DynSolType::FixedBytes(32),\n                    },\n                    offset: 0,\n                    slot: slot_str.to_string(),\n                    members: None,\n                    decoded: None,\n                    keys: None,\n                });\n            }\n        }\n\n        None\n    }\n\n    fn resolve_mapping_type(&self, type_ref: &str) -> Option<(Vec<String>, String, String)> {\n        let storage_type = self.storage_layout.types.get(type_ref)?;\n\n        if storage_type.encoding != ENCODING_MAPPING {\n            // Not a mapping, return the type as-is\n            return Some((vec![], storage_type.label.clone(), storage_type.label.clone()));\n        }\n\n        // Get key and value type references\n        let key_type_ref = storage_type.key.as_ref()?;\n        let value_type_ref = storage_type.value.as_ref()?;\n\n        // Resolve the key type\n        let key_type = self.storage_layout.types.get(key_type_ref)?;\n        let mut key_types = vec![key_type.label.clone()];\n\n        // Check if the value is another mapping (nested case)\n        if let Some(value_storage_type) = self.storage_layout.types.get(value_type_ref) {\n            if value_storage_type.encoding == ENCODING_MAPPING {\n                // Recursively resolve the nested mapping\n                let (nested_keys, final_value, _) = self.resolve_mapping_type(value_type_ref)?;\n                key_types.extend(nested_keys);\n                return Some((key_types, final_value, storage_type.label.clone()));\n            } else {\n                // Value is not a mapping, we're done\n                return Some((\n                    key_types,\n                    value_storage_type.label.clone(),\n                    storage_type.label.clone(),\n                ));\n            }\n        }\n\n        None\n    }\n}\n\n/// Returns the base indices for array types, e.g. \"\\[0\\]\\[0\\]\" for 2D arrays.\nfn get_array_base_indices(dyn_type: &DynSolType) -> String {\n    match dyn_type {\n        DynSolType::FixedArray(inner, _) => {\n            if let DynSolType::FixedArray(_, _) = inner.as_ref() {\n                // Nested array (2D or higher)\n                format!(\"[0]{}\", get_array_base_indices(inner))\n            } else {\n                // Simple 1D array\n                \"[0]\".to_string()\n            }\n        }\n        _ => String::new(),\n    }\n}\n\n/// Checks if a given type label represents a struct type.\npub fn is_struct(s: &str) -> bool {\n    s.starts_with(\"struct \")\n}\n"
  },
  {
    "path": "crates/common/src/term.rs",
    "content": "//! terminal utils\nuse foundry_compilers::{\n    artifacts::remappings::Remapping,\n    report::{self, Reporter},\n};\nuse itertools::Itertools;\nuse semver::Version;\nuse std::{\n    io,\n    io::{IsTerminal, prelude::*},\n    path::{Path, PathBuf},\n    sync::{\n        LazyLock,\n        mpsc::{self, TryRecvError},\n    },\n    thread,\n    time::Duration,\n};\nuse yansi::Paint;\n\nuse crate::shell;\n\n/// Some spinners\n// https://github.com/gernest/wow/blob/master/spin/spinners.go\npub static SPINNERS: &[&[&str]] = &[\n    &[\"⠃\", \"⠊\", \"⠒\", \"⠢\", \"⠆\", \"⠰\", \"⠔\", \"⠒\", \"⠑\", \"⠘\"],\n    &[\" \", \"⠁\", \"⠉\", \"⠙\", \"⠚\", \"⠖\", \"⠦\", \"⠤\", \"⠠\"],\n    &[\"┤\", \"┘\", \"┴\", \"└\", \"├\", \"┌\", \"┬\", \"┐\"],\n    &[\"▹▹▹▹▹\", \"▸▹▹▹▹\", \"▹▸▹▹▹\", \"▹▹▸▹▹\", \"▹▹▹▸▹\", \"▹▹▹▹▸\"],\n    &[\" \", \"▘\", \"▀\", \"▜\", \"█\", \"▟\", \"▄\", \"▖\"],\n];\n\nstatic TERM_SETTINGS: LazyLock<TermSettings> = LazyLock::new(TermSettings::from_env);\n\n/// Helper type to determine the current tty\npub struct TermSettings {\n    indicate_progress: bool,\n}\n\nimpl TermSettings {\n    /// Returns a new [`TermSettings`], configured from the current environment.\n    pub fn from_env() -> Self {\n        Self { indicate_progress: std::io::stdout().is_terminal() }\n    }\n}\n\n#[expect(missing_docs)]\npub struct Spinner {\n    indicator: &'static [&'static str],\n    no_progress: bool,\n    message: String,\n    idx: usize,\n}\n\n#[expect(missing_docs)]\nimpl Spinner {\n    pub fn new(msg: impl Into<String>) -> Self {\n        Self::with_indicator(SPINNERS[0], msg)\n    }\n\n    pub fn with_indicator(indicator: &'static [&'static str], msg: impl Into<String>) -> Self {\n        Self {\n            indicator,\n            no_progress: !TERM_SETTINGS.indicate_progress,\n            message: msg.into(),\n            idx: 0,\n        }\n    }\n\n    pub fn tick(&mut self) {\n        if self.no_progress {\n            return;\n        }\n\n        let indicator = self.indicator[self.idx % self.indicator.len()].green();\n        let indicator = Paint::new(format!(\"[{indicator}]\")).bold();\n        let _ = sh_print!(\"\\r\\x1B[2K\\r{indicator} {}\", self.message);\n        io::stdout().flush().unwrap();\n\n        self.idx = self.idx.wrapping_add(1);\n    }\n\n    pub fn message(&mut self, msg: impl Into<String>) {\n        self.message = msg.into();\n    }\n}\n\n/// A spinner used as [`report::Reporter`]\n///\n/// This reporter will prefix messages with a spinning cursor\n#[derive(Debug)]\n#[must_use = \"Terminates the spinner on drop\"]\npub struct SpinnerReporter {\n    /// The sender to the spinner thread.\n    sender: mpsc::Sender<SpinnerMsg>,\n    /// The project root path for trimming file paths in verbose output.\n    project_root: Option<PathBuf>,\n}\n\nimpl SpinnerReporter {\n    /// Spawns the [`Spinner`] on a new thread\n    ///\n    /// The spinner's message will be updated via the `reporter` events\n    ///\n    /// On drop the channel will disconnect and the thread will terminate\n    pub fn spawn(project_root: Option<PathBuf>) -> Self {\n        let (sender, rx) = mpsc::channel::<SpinnerMsg>();\n\n        std::thread::Builder::new()\n            .name(\"spinner\".into())\n            .spawn(move || {\n                let mut spinner = Spinner::new(\"Compiling...\");\n                loop {\n                    spinner.tick();\n                    match rx.try_recv() {\n                        Ok(SpinnerMsg::Msg(msg)) => {\n                            spinner.message(msg);\n                            // new line so past messages are not overwritten\n                            let _ = sh_println!();\n                        }\n                        Ok(SpinnerMsg::Shutdown(ack)) => {\n                            // end with a newline\n                            let _ = sh_println!();\n                            let _ = ack.send(());\n                            break;\n                        }\n                        Err(TryRecvError::Disconnected) => break,\n                        Err(TryRecvError::Empty) => thread::sleep(Duration::from_millis(100)),\n                    }\n                }\n            })\n            .expect(\"failed to spawn thread\");\n\n        Self { sender, project_root }\n    }\n\n    fn send_msg(&self, msg: impl Into<String>) {\n        let _ = self.sender.send(SpinnerMsg::Msg(msg.into()));\n    }\n}\n\nenum SpinnerMsg {\n    Msg(String),\n    Shutdown(mpsc::Sender<()>),\n}\n\nimpl Drop for SpinnerReporter {\n    fn drop(&mut self) {\n        let (tx, rx) = mpsc::channel();\n        if self.sender.send(SpinnerMsg::Shutdown(tx)).is_ok() {\n            let _ = rx.recv();\n        }\n    }\n}\n\nimpl Reporter for SpinnerReporter {\n    fn on_compiler_spawn(&self, compiler_name: &str, version: &Version, dirty_files: &[PathBuf]) {\n        // Verbose message with dirty files displays first to avoid being overlapped\n        // by the spinner in .tick() which prints repeatedly over the same line.\n        if shell::verbosity() >= 5 {\n            self.send_msg(format!(\n                \"Files to compile:\\n{}\",\n                dirty_files\n                    .iter()\n                    .map(|path| {\n                        let trimmed_path = if let Some(project_root) = &self.project_root {\n                            path.strip_prefix(project_root).unwrap_or(path)\n                        } else {\n                            path\n                        };\n                        format!(\"- {}\", trimmed_path.display())\n                    })\n                    .sorted()\n                    .format(\"\\n\")\n            ));\n        }\n\n        self.send_msg(format!(\n            \"Compiling {} files with {} {}.{}.{}\",\n            dirty_files.len(),\n            compiler_name,\n            version.major,\n            version.minor,\n            version.patch\n        ));\n    }\n\n    fn on_compiler_success(&self, compiler_name: &str, version: &Version, duration: &Duration) {\n        self.send_msg(format!(\n            \"{} {}.{}.{} finished in {duration:.2?}\",\n            compiler_name, version.major, version.minor, version.patch\n        ));\n    }\n\n    fn on_solc_installation_start(&self, version: &Version) {\n        self.send_msg(format!(\"Installing Solc version {version}\"));\n    }\n\n    fn on_solc_installation_success(&self, version: &Version) {\n        self.send_msg(format!(\"Successfully installed Solc {version}\"));\n    }\n\n    fn on_solc_installation_error(&self, version: &Version, error: &str) {\n        self.send_msg(format!(\"Failed to install Solc {version}: {error}\").red().to_string());\n    }\n\n    fn on_unresolved_imports(&self, imports: &[(&Path, &Path)], remappings: &[Remapping]) {\n        self.send_msg(report::format_unresolved_imports(imports, remappings));\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    #[ignore]\n    fn can_spin() {\n        let mut s = Spinner::new(\"Compiling\".to_string());\n        let ticks = 50;\n        for _ in 0..ticks {\n            std::thread::sleep(std::time::Duration::from_millis(100));\n            s.tick();\n        }\n    }\n\n    #[test]\n    fn can_format_properly() {\n        let r = SpinnerReporter::spawn(None);\n        let remappings: Vec<Remapping> = vec![\n            \"library/=library/src/\".parse().unwrap(),\n            \"weird-erc20/=lib/weird-erc20/src/\".parse().unwrap(),\n            \"ds-test/=lib/ds-test/src/\".parse().unwrap(),\n            \"openzeppelin-contracts/=lib/openzeppelin-contracts/contracts/\".parse().unwrap(),\n        ];\n        let unresolved = vec![(Path::new(\"./src/Import.sol\"), Path::new(\"src/File.col\"))];\n        r.on_unresolved_imports(&unresolved, &remappings);\n        // formats:\n        // [⠒] Unable to resolve imports:\n        //       \"./src/Import.sol\" in \"src/File.col\"\n        // with remappings:\n        //       library/=library/src/\n        //       weird-erc20/=lib/weird-erc20/src/\n        //       ds-test/=lib/ds-test/src/\n        //       openzeppelin-contracts/=lib/openzeppelin-contracts/contracts/\n    }\n}\n"
  },
  {
    "path": "crates/common/src/traits.rs",
    "content": "//! Commonly used traits.\n\nuse alloy_json_abi::Function;\nuse alloy_primitives::Bytes;\nuse alloy_sol_types::SolError;\nuse std::{fmt, path::Path};\n\n/// Test filter.\npub trait TestFilter: Send + Sync {\n    /// Returns whether the test should be included.\n    fn matches_test(&self, test_signature: &str) -> bool;\n\n    /// Returns whether the contract should be included.\n    fn matches_contract(&self, contract_name: &str) -> bool;\n\n    /// Returns a contract with the given path should be included.\n    fn matches_path(&self, path: &Path) -> bool;\n}\n\nimpl<'a> dyn TestFilter + 'a {\n    /// Returns `true` if the function is a test function that matches the given filter.\n    pub fn matches_test_function(&self, func: &Function) -> bool {\n        func.is_any_test() && self.matches_test(&func.signature())\n    }\n}\n\n/// A test filter that filters out nothing.\n#[derive(Clone, Debug, Default)]\npub struct EmptyTestFilter(());\nimpl TestFilter for EmptyTestFilter {\n    fn matches_test(&self, _test_signature: &str) -> bool {\n        true\n    }\n\n    fn matches_contract(&self, _contract_name: &str) -> bool {\n        true\n    }\n\n    fn matches_path(&self, _path: &Path) -> bool {\n        true\n    }\n}\n\n/// Extension trait for `Function`.\npub trait TestFunctionExt {\n    /// Returns the kind of test function.\n    fn test_function_kind(&self) -> TestFunctionKind {\n        TestFunctionKind::classify(self.tfe_as_str(), self.tfe_has_inputs())\n    }\n\n    /// Returns `true` if this function is a `setUp` function.\n    fn is_setup(&self) -> bool {\n        self.test_function_kind().is_setup()\n    }\n\n    /// Returns `true` if this function is a unit, fuzz, or invariant test.\n    fn is_any_test(&self) -> bool {\n        self.test_function_kind().is_any_test()\n    }\n\n    /// Returns `true` if this function is a test that should fail.\n    fn is_any_test_fail(&self) -> bool {\n        self.test_function_kind().is_any_test_fail()\n    }\n\n    /// Returns `true` if this function is a unit test.\n    fn is_unit_test(&self) -> bool {\n        matches!(self.test_function_kind(), TestFunctionKind::UnitTest { .. })\n    }\n\n    /// Returns `true` if this function is a `beforeTestSetup` function.\n    fn is_before_test_setup(&self) -> bool {\n        self.tfe_as_str().eq_ignore_ascii_case(\"beforetestsetup\")\n    }\n\n    /// Returns `true` if this function is a fuzz test.\n    fn is_fuzz_test(&self) -> bool {\n        self.test_function_kind().is_fuzz_test()\n    }\n\n    /// Returns `true` if this function is an invariant test.\n    fn is_invariant_test(&self) -> bool {\n        self.test_function_kind().is_invariant_test()\n    }\n\n    /// Returns `true` if this function is an `afterInvariant` function.\n    fn is_after_invariant(&self) -> bool {\n        self.test_function_kind().is_after_invariant()\n    }\n\n    /// Returns `true` if this function is a `fixture` function.\n    fn is_fixture(&self) -> bool {\n        self.test_function_kind().is_fixture()\n    }\n\n    /// Returns `true` if this function is test reserved function.\n    fn is_reserved(&self) -> bool {\n        self.is_any_test()\n            || self.is_setup()\n            || self.is_before_test_setup()\n            || self.is_after_invariant()\n            || self.is_fixture()\n    }\n\n    #[doc(hidden)]\n    fn tfe_as_str(&self) -> &str;\n    #[doc(hidden)]\n    fn tfe_has_inputs(&self) -> bool;\n}\n\nimpl TestFunctionExt for Function {\n    fn tfe_as_str(&self) -> &str {\n        self.name.as_str()\n    }\n\n    fn tfe_has_inputs(&self) -> bool {\n        !self.inputs.is_empty()\n    }\n}\n\nimpl TestFunctionExt for String {\n    fn tfe_as_str(&self) -> &str {\n        self\n    }\n\n    fn tfe_has_inputs(&self) -> bool {\n        false\n    }\n}\n\nimpl TestFunctionExt for str {\n    fn tfe_as_str(&self) -> &str {\n        self\n    }\n\n    fn tfe_has_inputs(&self) -> bool {\n        false\n    }\n}\n\n/// Test function kind.\n#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]\npub enum TestFunctionKind {\n    /// `setUp`.\n    Setup,\n    /// `test*`. `should_fail` is `true` for `testFail*`.\n    UnitTest { should_fail: bool },\n    /// `test*`, with arguments. `should_fail` is `true` for `testFail*`.\n    FuzzTest { should_fail: bool },\n    /// `invariant*` or `statefulFuzz*`.\n    InvariantTest,\n    /// `table*`, with arguments.\n    TableTest,\n    /// `afterInvariant`.\n    AfterInvariant,\n    /// `fixture*`.\n    Fixture,\n    /// Unknown kind.\n    Unknown,\n}\n\nimpl TestFunctionKind {\n    /// Classify a function.\n    pub fn classify(name: &str, has_inputs: bool) -> Self {\n        match () {\n            _ if name.starts_with(\"test\") => {\n                let should_fail = name.starts_with(\"testFail\");\n                if has_inputs {\n                    Self::FuzzTest { should_fail }\n                } else {\n                    Self::UnitTest { should_fail }\n                }\n            }\n            _ if name.starts_with(\"invariant\") || name.starts_with(\"statefulFuzz\") => {\n                Self::InvariantTest\n            }\n            _ if name.starts_with(\"table\") => Self::TableTest,\n            _ if name.eq_ignore_ascii_case(\"setup\") && !has_inputs => Self::Setup,\n            _ if name.eq_ignore_ascii_case(\"afterinvariant\") => Self::AfterInvariant,\n            _ if name.starts_with(\"fixture\") => Self::Fixture,\n            _ => Self::Unknown,\n        }\n    }\n\n    /// Returns the name of the function kind.\n    pub const fn name(&self) -> &'static str {\n        match self {\n            Self::Setup => \"setUp\",\n            Self::UnitTest { should_fail: false } => \"test\",\n            Self::UnitTest { should_fail: true } => \"testFail\",\n            Self::FuzzTest { should_fail: false } => \"fuzz\",\n            Self::FuzzTest { should_fail: true } => \"fuzz fail\",\n            Self::InvariantTest => \"invariant\",\n            Self::TableTest => \"table\",\n            Self::AfterInvariant => \"afterInvariant\",\n            Self::Fixture => \"fixture\",\n            Self::Unknown => \"unknown\",\n        }\n    }\n\n    /// Returns `true` if this function is a `setUp` function.\n    #[inline]\n    pub const fn is_setup(&self) -> bool {\n        matches!(self, Self::Setup)\n    }\n\n    /// Returns `true` if this function is a unit, fuzz, or invariant test.\n    #[inline]\n    pub const fn is_any_test(&self) -> bool {\n        matches!(\n            self,\n            Self::UnitTest { .. } | Self::FuzzTest { .. } | Self::TableTest | Self::InvariantTest\n        )\n    }\n\n    /// Returns `true` if this function is a test that should fail.\n    #[inline]\n    pub const fn is_any_test_fail(&self) -> bool {\n        matches!(self, Self::UnitTest { should_fail: true } | Self::FuzzTest { should_fail: true })\n    }\n\n    /// Returns `true` if this function is a unit test.\n    #[inline]\n    pub fn is_unit_test(&self) -> bool {\n        matches!(self, Self::UnitTest { .. })\n    }\n\n    /// Returns `true` if this function is a fuzz test.\n    #[inline]\n    pub const fn is_fuzz_test(&self) -> bool {\n        matches!(self, Self::FuzzTest { .. })\n    }\n\n    /// Returns `true` if this function is an invariant test.\n    #[inline]\n    pub const fn is_invariant_test(&self) -> bool {\n        matches!(self, Self::InvariantTest)\n    }\n\n    /// Returns `true` if this function is a table test.\n    #[inline]\n    pub const fn is_table_test(&self) -> bool {\n        matches!(self, Self::TableTest)\n    }\n\n    /// Returns `true` if this function is an `afterInvariant` function.\n    #[inline]\n    pub const fn is_after_invariant(&self) -> bool {\n        matches!(self, Self::AfterInvariant)\n    }\n\n    /// Returns `true` if this function is a `fixture` function.\n    #[inline]\n    pub const fn is_fixture(&self) -> bool {\n        matches!(self, Self::Fixture)\n    }\n\n    /// Returns `true` if this function kind is known.\n    #[inline]\n    pub const fn is_known(&self) -> bool {\n        !matches!(self, Self::Unknown)\n    }\n\n    /// Returns `true` if this function kind is unknown.\n    #[inline]\n    pub const fn is_unknown(&self) -> bool {\n        matches!(self, Self::Unknown)\n    }\n}\n\nimpl fmt::Display for TestFunctionKind {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        self.name().fmt(f)\n    }\n}\n\n/// An extension trait for `std::error::Error` for ABI encoding.\npub trait ErrorExt: std::error::Error {\n    /// ABI-encodes the error using `Revert(string)`.\n    fn abi_encode_revert(&self) -> Bytes;\n}\n\nimpl<T: std::error::Error> ErrorExt for T {\n    fn abi_encode_revert(&self) -> Bytes {\n        alloy_sol_types::Revert::from(self.to_string()).abi_encode().into()\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_setup_classification() {\n        // setUp() with no params should be classified as Setup\n        assert_eq!(TestFunctionKind::classify(\"setUp\", false), TestFunctionKind::Setup);\n\n        // setUp(bytes memory) with params should NOT be classified as Setup\n        // This is common in Gnosis Safe/Zodiac modules\n        assert_eq!(TestFunctionKind::classify(\"setUp\", true), TestFunctionKind::Unknown);\n    }\n}\n"
  },
  {
    "path": "crates/common/src/transactions.rs",
    "content": "//! Wrappers for transactions.\n\nuse alloy_consensus::{Transaction, transaction::SignerRecoverable};\nuse alloy_eips::eip7702::SignedAuthorization;\nuse alloy_network::{AnyTransactionReceipt, Network, TransactionResponse};\nuse alloy_primitives::{Address, Bytes, TxKind, U256};\nuse alloy_provider::{\n    Provider,\n    network::{AnyNetwork, ReceiptResponse, TransactionBuilder},\n};\nuse alloy_rpc_types::BlockId;\nuse eyre::Result;\nuse foundry_common_fmt::{UIfmt, UIfmtReceiptExt, get_pretty_receipt_attr};\nuse foundry_primitives::FoundryTransactionBuilder;\nuse serde::{Deserialize, Serialize};\n\n/// Helper type to carry a transaction along with an optional revert reason\n#[derive(Clone, Debug, Serialize, Deserialize)]\npub struct TransactionReceiptWithRevertReason<N: Network> {\n    /// The underlying transaction receipt\n    #[serde(flatten)]\n    pub receipt: N::ReceiptResponse,\n\n    /// The revert reason string if the transaction status is failed\n    #[serde(skip_serializing_if = \"Option::is_none\", rename = \"revertReason\")]\n    pub revert_reason: Option<String>,\n}\n\nimpl<N: Network> TransactionReceiptWithRevertReason<N>\nwhere\n    N::TxEnvelope: Clone,\n    N::ReceiptResponse: UIfmtReceiptExt,\n{\n    /// Updates the revert reason field using `eth_call` and returns an Err variant if the revert\n    /// reason was not successfully updated\n    pub async fn update_revert_reason(&mut self, provider: &dyn Provider<N>) -> Result<()> {\n        self.revert_reason = self.fetch_revert_reason(provider).await?;\n        Ok(())\n    }\n\n    async fn fetch_revert_reason(&self, provider: &dyn Provider<N>) -> Result<Option<String>> {\n        // If the transaction succeeded, there is no revert reason to fetch\n        if self.receipt.status() {\n            return Ok(None);\n        }\n\n        let transaction = provider\n            .get_transaction_by_hash(self.receipt.transaction_hash())\n            .await\n            .map_err(|err| eyre::eyre!(\"unable to fetch transaction: {err}\"))?\n            .ok_or_else(|| eyre::eyre!(\"transaction not found\"))?;\n\n        if let Some(block_hash) = self.receipt.block_hash() {\n            let mut call_request: N::TransactionRequest = transaction.as_ref().clone().into();\n            call_request.set_from(transaction.from());\n            match provider.call(call_request).block(BlockId::Hash(block_hash.into())).await {\n                Err(e) => return Ok(extract_revert_reason(e.to_string())),\n                Ok(_) => eyre::bail!(\"no revert reason as transaction succeeded\"),\n            }\n        }\n        eyre::bail!(\"unable to fetch block_hash\")\n    }\n}\n\nimpl From<AnyTransactionReceipt> for TransactionReceiptWithRevertReason<AnyNetwork> {\n    fn from(receipt: AnyTransactionReceipt) -> Self {\n        Self { receipt, revert_reason: None }\n    }\n}\n\nimpl From<TransactionReceiptWithRevertReason<AnyNetwork>> for AnyTransactionReceipt {\n    fn from(receipt_with_reason: TransactionReceiptWithRevertReason<AnyNetwork>) -> Self {\n        receipt_with_reason.receipt\n    }\n}\n\nimpl<N: Network> UIfmt for TransactionReceiptWithRevertReason<N>\nwhere\n    N::ReceiptResponse: UIfmt,\n{\n    fn pretty(&self) -> String {\n        if let Some(revert_reason) = &self.revert_reason {\n            format!(\n                \"{}\nrevertReason         {}\",\n                self.receipt.pretty(),\n                revert_reason\n            )\n        } else {\n            self.receipt.pretty()\n        }\n    }\n}\n\nimpl<N: Network> UIfmt for TransactionMaybeSigned<N>\nwhere\n    N::TxEnvelope: UIfmt,\n    N::TransactionRequest: FoundryTransactionBuilder<N>,\n{\n    fn pretty(&self) -> String {\n        match self {\n            Self::Signed { tx, .. } => tx.pretty(),\n            Self::Unsigned(tx) => format!(\n                \"\naccessList           {}\nchainId              {}\ngasLimit             {}\ngasPrice             {}\ninput                {}\nmaxFeePerBlobGas     {}\nmaxFeePerGas         {}\nmaxPriorityFeePerGas {}\nnonce                {}\nto                   {}\ntype                 {}\nvalue                {}\",\n                tx.access_list()\n                    .as_ref()\n                    .map(|a| a.iter().collect::<Vec<_>>())\n                    .unwrap_or_default()\n                    .pretty(),\n                tx.chain_id().pretty(),\n                tx.gas_limit().unwrap_or_default(),\n                tx.gas_price().pretty(),\n                tx.input().pretty(),\n                tx.max_fee_per_blob_gas().pretty(),\n                tx.max_fee_per_gas().pretty(),\n                tx.max_priority_fee_per_gas().pretty(),\n                tx.nonce().pretty(),\n                tx.to().pretty(),\n                tx.output_tx_type(),\n                tx.value().pretty(),\n            ),\n        }\n    }\n}\n\nfn extract_revert_reason<S: AsRef<str>>(error_string: S) -> Option<String> {\n    let message_substr = \"execution reverted: \";\n    error_string\n        .as_ref()\n        .find(message_substr)\n        .map(|index| error_string.as_ref().split_at(index + message_substr.len()).1.to_string())\n}\n\n/// Returns the `UiFmt::pretty()` formatted attribute of the transaction receipt with revert reason\npub fn get_pretty_receipt_w_reason_attr<N>(\n    receipt: &TransactionReceiptWithRevertReason<N>,\n    attr: &str,\n) -> Option<String>\nwhere\n    N: Network,\n    N::ReceiptResponse: UIfmtReceiptExt,\n{\n    // Handle revert reason first, then delegate to the receipt formatting function\n    if matches!(attr, \"revertReason\" | \"revert_reason\") {\n        return Some(receipt.revert_reason.pretty());\n    }\n    get_pretty_receipt_attr::<N>(&receipt.receipt, attr)\n}\n\n/// Used for broadcasting transactions\n/// A transaction can either be a `TransactionRequest` waiting to be signed\n/// or a `TxEnvelope`, already signed\n#[derive(Clone, Debug, Serialize, Deserialize)]\n#[serde(untagged)]\npub enum TransactionMaybeSigned<N: Network> {\n    Signed {\n        #[serde(flatten)]\n        tx: N::TxEnvelope,\n        from: Address,\n    },\n    Unsigned(N::TransactionRequest),\n}\n\nimpl<N: Network> TransactionMaybeSigned<N> {\n    /// Creates a new (unsigned) transaction for broadcast\n    pub fn new(tx: N::TransactionRequest) -> Self {\n        Self::Unsigned(tx)\n    }\n\n    /// Creates a new signed transaction for broadcast.\n    pub fn new_signed(\n        tx: N::TxEnvelope,\n    ) -> core::result::Result<Self, alloy_consensus::crypto::RecoveryError>\n    where\n        N::TxEnvelope: SignerRecoverable,\n    {\n        let from = tx.recover_signer()?;\n        Ok(Self::Signed { tx, from })\n    }\n\n    pub fn is_unsigned(&self) -> bool {\n        matches!(self, Self::Unsigned(_))\n    }\n\n    pub fn as_unsigned_mut(&mut self) -> Option<&mut N::TransactionRequest> {\n        match self {\n            Self::Unsigned(tx) => Some(tx),\n            _ => None,\n        }\n    }\n\n    pub fn from(&self) -> Option<Address> {\n        match self {\n            Self::Signed { from, .. } => Some(*from),\n            Self::Unsigned(tx) => tx.from(),\n        }\n    }\n\n    pub fn input(&self) -> Option<&Bytes> {\n        match self {\n            Self::Signed { tx, .. } => Some(tx.input()),\n            Self::Unsigned(tx) => tx.input(),\n        }\n    }\n\n    pub fn to(&self) -> Option<TxKind> {\n        match self {\n            Self::Signed { tx, .. } => Some(tx.kind()),\n            Self::Unsigned(tx) => tx.kind(),\n        }\n    }\n\n    pub fn value(&self) -> Option<U256> {\n        match self {\n            Self::Signed { tx, .. } => Some(tx.value()),\n            Self::Unsigned(tx) => tx.value(),\n        }\n    }\n\n    pub fn gas(&self) -> Option<u128> {\n        match self {\n            Self::Signed { tx, .. } => Some(tx.gas_limit() as u128),\n            Self::Unsigned(tx) => tx.gas_limit().map(|g| g as u128),\n        }\n    }\n\n    pub fn nonce(&self) -> Option<u64> {\n        match self {\n            Self::Signed { tx, .. } => Some(tx.nonce()),\n            Self::Unsigned(tx) => tx.nonce(),\n        }\n    }\n\n    pub fn authorization_list(&self) -> Option<Vec<SignedAuthorization>>\n    where\n        N::TransactionRequest: FoundryTransactionBuilder<N>,\n    {\n        match self {\n            Self::Signed { tx, .. } => tx.authorization_list().map(|auths| auths.to_vec()),\n            Self::Unsigned(tx) => tx.authorization_list().map(|auths| auths.to_vec()),\n        }\n        .filter(|auths| !auths.is_empty())\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_extract_revert_reason() {\n        let error_string_1 = \"server returned an error response: error code 3: execution reverted: Transaction too old\";\n        let error_string_2 = \"server returned an error response: error code 3: Invalid signature\";\n\n        assert_eq!(extract_revert_reason(error_string_1), Some(\"Transaction too old\".to_string()));\n        assert_eq!(extract_revert_reason(error_string_2), None);\n    }\n}\n"
  },
  {
    "path": "crates/common/src/utils.rs",
    "content": "//! Uncategorised utilities.\n\nuse alloy_primitives::{B256, Bytes, U256, hex, keccak256};\nuse foundry_compilers::{\n    Project,\n    artifacts::{BytecodeObject, SolcLanguage},\n    error::SolcError,\n    flatten::{Flattener, FlattenerError},\n};\nuse regex::Regex;\nuse std::{path::Path, sync::LazyLock};\n\nstatic BYTECODE_PLACEHOLDER_RE: LazyLock<Regex> =\n    LazyLock::new(|| Regex::new(r\"__\\$.{34}\\$__\").expect(\"invalid regex\"));\n\n/// Block on a future using the current tokio runtime on the current thread.\npub fn block_on<F: std::future::Future>(future: F) -> F::Output {\n    block_on_handle(&tokio::runtime::Handle::current(), future)\n}\n\n/// Block on a future using the current tokio runtime on the current thread with the given handle.\npub fn block_on_handle<F: std::future::Future>(\n    handle: &tokio::runtime::Handle,\n    future: F,\n) -> F::Output {\n    tokio::task::block_in_place(|| handle.block_on(future))\n}\n\n/// Computes the storage slot as specified by `ERC-7201`, using the `erc7201` formula ID.\n///\n/// This is defined as:\n///\n/// ```text\n/// erc7201(id: string) = keccak256(keccak256(id) - 1) & ~0xff\n/// ```\n///\n/// # Examples\n///\n/// ```\n/// use alloy_primitives::b256;\n/// use foundry_common::erc7201;\n///\n/// assert_eq!(\n///     erc7201(\"example.main\"),\n///     b256!(\"0x183a6125c38840424c4a85fa12bab2ab606c4b6d0e7cc73c0c06ba5300eab500\"),\n/// );\n/// ```\npub fn erc7201(id: &str) -> B256 {\n    let x = U256::from_be_bytes(keccak256(id).0) - U256::from(1);\n    keccak256(x.to_be_bytes::<32>()) & B256::from(!U256::from(0xff))\n}\n\n/// Utility function to find the start of the metadata in the bytecode.\n/// This assumes that the metadata is at the end of the bytecode.\npub fn find_metadata_start(bytecode: &[u8]) -> Option<usize> {\n    // Get the last two bytes of the bytecode to find the length of CBOR metadata.\n    let (rest, metadata_len_bytes) = bytecode.split_last_chunk()?;\n    let metadata_len = u16::from_be_bytes(*metadata_len_bytes) as usize;\n    if metadata_len > rest.len() {\n        return None;\n    }\n    ciborium::from_reader::<ciborium::Value, _>(&rest[rest.len() - metadata_len..])\n        .is_ok()\n        .then(|| rest.len() - metadata_len)\n}\n\n/// Utility function to ignore metadata hash of the given bytecode.\n/// This assumes that the metadata is at the end of the bytecode.\npub fn ignore_metadata_hash(bytecode: &[u8]) -> &[u8] {\n    if let Some(metadata) = find_metadata_start(bytecode) {\n        &bytecode[..metadata]\n    } else {\n        bytecode\n    }\n}\n\n/// Strips all __$xxx$__ placeholders from the bytecode if it's an unlinked bytecode.\n/// by replacing them with 20 zero bytes.\n/// This is useful for matching bytecodes to a contract source, and for the source map,\n/// in which the actual address of the placeholder isn't important.\npub fn strip_bytecode_placeholders(bytecode: &BytecodeObject) -> Option<Bytes> {\n    match &bytecode {\n        BytecodeObject::Bytecode(bytes) => Some(bytes.clone()),\n        BytecodeObject::Unlinked(s) => {\n            // Replace all __$xxx$__ placeholders with 20 zero bytes (40 hex chars)\n            let s = (*BYTECODE_PLACEHOLDER_RE).replace_all(s, \"00\".repeat(20));\n            let bytes = hex::decode(s.as_bytes());\n            Some(bytes.ok()?.into())\n        }\n    }\n}\n\n/// Flattens the given target of the project. Falls back to the old flattening implementation\n/// if the target cannot be compiled successfully. This would be the case if the target has invalid\n/// syntax. (e.g. Solang)\npub fn flatten(project: Project, target_path: &Path) -> eyre::Result<String> {\n    // Save paths for fallback before Flattener::new takes ownership\n    let paths = project.paths.clone();\n    let flattened = match Flattener::new(project, target_path) {\n        Ok(flattener) => Ok(flattener.flatten()),\n        Err(FlattenerError::Compilation(_)) => {\n            paths.with_language::<SolcLanguage>().flatten(target_path)\n        }\n        Err(FlattenerError::Other(err)) => Err(err),\n    }\n    .map_err(|err: SolcError| eyre::eyre!(\"Failed to flatten: {err}\"))?;\n\n    Ok(flattened)\n}\n"
  },
  {
    "path": "crates/common/src/version.rs",
    "content": "//! Foundry version information.\n\n/// The SemVer compatible version information for Foundry.\npub const SEMVER_VERSION: &str = env!(\"FOUNDRY_SEMVER_VERSION\");\n\n/// The short version message information for the Foundry CLI.\npub const SHORT_VERSION: &str = env!(\"FOUNDRY_SHORT_VERSION\");\n\n/// The long version message information for the Foundry CLI.\npub const LONG_VERSION: &str = concat!(\n    env!(\"FOUNDRY_LONG_VERSION_0\"),\n    \"\\n\",\n    env!(\"FOUNDRY_LONG_VERSION_1\"),\n    \"\\n\",\n    env!(\"FOUNDRY_LONG_VERSION_2\"),\n    \"\\n\",\n    env!(\"FOUNDRY_LONG_VERSION_3\"),\n);\n\n/// Whether the version is a nightly build.\npub const IS_NIGHTLY_VERSION: bool = option_env!(\"FOUNDRY_IS_NIGHTLY_VERSION\").is_some();\n\n/// The warning message for nightly versions.\npub const NIGHTLY_VERSION_WARNING_MESSAGE: &str = \"This is a nightly build of Foundry. It is recommended to use the latest stable version. \\\n    To mute this warning set `FOUNDRY_DISABLE_NIGHTLY_WARNING` in your environment. \\n\";\n"
  },
  {
    "path": "crates/config/Cargo.toml",
    "content": "[package]\nname = \"foundry-config\"\ndescription = \"Foundry configuration\"\n\nversion.workspace = true\nedition.workspace = true\nrust-version.workspace = true\nauthors.workspace = true\nlicense.workspace = true\nhomepage.workspace = true\nrepository.workspace = true\n\n[lints]\nworkspace = true\n\n[dependencies]\nfoundry-block-explorers = { workspace = true, features = [\"foundry-compilers\"] }\nfoundry-compilers = { workspace = true, features = [\"svm-solc\"] }\n\nalloy-chains = { workspace = true, features = [\"serde\"] }\nalloy-primitives = { workspace = true, features = [\"serde\"] }\n\nfoundry-evm-networks.workspace = true\n\nrevm.workspace = true\n\nsolar.workspace = true\n\ndirs.workspace = true\ndunce.workspace = true\neyre.workspace = true\nfigment = { workspace = true, features = [\"toml\", \"env\"] }\nglob = \"0.3\"\nglobset = \"0.4\"\nheck.workspace = true\nitertools.workspace = true\nmesc.workspace = true\nunit-prefix = \"0.5.2\"\nrayon.workspace = true\nregex.workspace = true\nsemver = { workspace = true, features = [\"serde\"] }\nserde_json.workspace = true\nserde.workspace = true\nsoldeer-core.workspace = true\nthiserror.workspace = true\ntoml = { workspace = true, features = [\"preserve_order\"] }\ntoml_edit.workspace = true\ntracing.workspace = true\nwalkdir.workspace = true\nyansi.workspace = true\nclap = { version = \"4\", features = [\"derive\"] }\n\n[target.'cfg(target_os = \"windows\")'.dependencies]\npath-slash = \"0.2\"\n\n[dev-dependencies]\nsnapbox.workspace = true\nsimilar-asserts.workspace = true\nfigment = { workspace = true, features = [\"test\"] }\ntempfile.workspace = true\n\n[features]\nisolate-by-default = []\n"
  },
  {
    "path": "crates/config/README.md",
    "content": "# Configuration\n\nFoundry's configuration system allows you to configure its tools the way _you_ want while also providing with a\nsensible set of defaults.\n\n## Profiles\n\nConfigurations can be arbitrarily namespaced with profiles. Foundry's default config is also named `default`, but you can\narbitrarily name and configure profiles as you like and set the `FOUNDRY_PROFILE` environment variable to the selected\nprofile's name. This results in foundry's tools (forge) preferring the values in the profile with the named that's set\nin `FOUNDRY_PROFILE`. But all custom profiles inherit from the `default` profile.\n\n## foundry.toml\n\nFoundry's tools search for a `foundry.toml` or the filename in a `FOUNDRY_CONFIG` environment variable starting at the\ncurrent working directory. If it is not found, the parent directory, its parent directory, and so on are searched until\nthe file is found or the root is reached. But the typical location for the global `foundry.toml` would\nbe `~/.foundry/foundry.toml`, which is also checked. If the path set in `FOUNDRY_CONFIG` is absolute, no such search\ntakes place and the absolute path is used directly.\n\nIn `foundry.toml` you can define multiple profiles, therefore the file is assumed to be _nested_, so each top-level key\ndeclares a profile and its values configure the profile.\n\nThe following is an example of what such a file might look like. This can also be obtained with `forge config`\n\n```toml\n## defaults for _all_ profiles\n[profile.default]\nsrc = \"src\"\nout = \"out\"\nlibs = [\"lib\"]\nsolc = \"0.8.10\" # to use a specific local solc install set the path as `solc = \"<path to solc>/solc\"`\neth-rpc-url = \"https://mainnet.infura.io\"\n\n## set only when the `hardhat` profile is selected\n[profile.hardhat]\nsrc = \"contracts\"\nout = \"artifacts\"\nlibs = [\"node_modules\"]\n\n## set only when the `spells` profile is selected\n[profile.spells]\n## --snip-- more settings\n```\n\n## Default profile\n\nWhen determining the profile to use, `Config` considers the following sources in ascending priority order to read from\nand merge, at the per-key level:\n\n1. [`Config::default()`], which provides default values for all parameters.\n2. `foundry.toml` _or_ TOML file path in `FOUNDRY_CONFIG` environment variable.\n3. `FOUNDRY_` or `DAPP_` prefixed environment variables.\n\nThe selected profile is the value of the `FOUNDRY_PROFILE` environment variable, or if it is not set, \"default\".\n\n## Configuration Reference\n\nFor a full list of all configuration options, see the [Foundry Book](https://getfoundry.sh/config/reference/overview):\n\n- [Default Configuration](https://getfoundry.sh/config/reference/default-config) - All `[profile.default]` options\n- [Testing Configuration](https://getfoundry.sh/config/reference/testing) - Fuzz and invariant testing options\n- [Formatter Configuration](https://getfoundry.sh/config/reference/formatter) - Code formatting options\n- [Linter Configuration](https://getfoundry.sh/config/reference/linter) - Linting options\n- [Doc Generator Configuration](https://getfoundry.sh/config/reference/doc-generator) - Documentation generation options\n\n## Environment Variables\n\nFoundry's tools read all environment variable names prefixed with `FOUNDRY_` using the string after the `_` as the name\nof a configuration value as the value of the parameter as the value itself. But the\ncorresponding [dapptools](https://github.com/dapphub/dapptools/tree/master/src/dapp#configuration) config vars are also\nsupported, this means that `FOUNDRY_SRC` and `DAPP_SRC` are equivalent.\n\nSome exceptions to the above are [explicitly ignored](https://github.com/foundry-rs/foundry/blob/10440422e63aae660104e079dfccd5b0ae5fd720/config/src/lib.rs#L1539-L15522) due to security concerns.\n\nEnvironment variables take precedence over values in `foundry.toml`. Values are parsed as a loose form of TOML syntax.\n"
  },
  {
    "path": "crates/config/src/bind_json.rs",
    "content": "use crate::filter::GlobMatcher;\nuse serde::{Deserialize, Serialize};\nuse std::path::PathBuf;\n\n/// Contains the config for `forge bind-json`\n#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]\npub struct BindJsonConfig {\n    /// Path for the generated bindings file.\n    pub out: PathBuf,\n    /// Globs to include.\n    ///\n    /// If provided, only the files matching the globs will be included. Otherwise, defaults to\n    /// including all project files.\n    pub include: Vec<GlobMatcher>,\n    /// Globs to ignore\n    pub exclude: Vec<GlobMatcher>,\n}\n\nimpl Default for BindJsonConfig {\n    fn default() -> Self {\n        Self {\n            out: PathBuf::from(\"utils/JsonBindings.sol\"),\n            exclude: Vec::new(),\n            include: Vec::new(),\n        }\n    }\n}\n"
  },
  {
    "path": "crates/config/src/cache.rs",
    "content": "//! Support types for configuring storage caching\n\nuse crate::Chain;\nuse serde::{Deserialize, Deserializer, Serialize, Serializer};\nuse std::{fmt, fmt::Formatter, str::FromStr};\nuse unit_prefix::NumberPrefix;\n\n/// Settings to configure caching of remote.\n#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]\npub struct StorageCachingConfig {\n    /// Chains to cache.\n    pub chains: CachedChains,\n    /// Endpoints to cache.\n    pub endpoints: CachedEndpoints,\n}\n\nimpl StorageCachingConfig {\n    /// Whether caching should be enabled for the endpoint\n    pub fn enable_for_endpoint(&self, endpoint: impl AsRef<str>) -> bool {\n        self.endpoints.is_match(endpoint)\n    }\n\n    /// Whether caching should be enabled for the chain id\n    pub fn enable_for_chain_id(&self, chain_id: u64) -> bool {\n        // ignore dev chains\n        if [99, 1337, 31337].contains(&chain_id) {\n            return false;\n        }\n        self.chains.is_match(chain_id)\n    }\n}\n\n/// What chains to cache\n#[derive(Clone, Debug, Default, PartialEq, Eq)]\npub enum CachedChains {\n    /// Cache all chains\n    #[default]\n    All,\n    /// Don't cache anything\n    None,\n    /// Only cache these chains\n    Chains(Vec<Chain>),\n}\nimpl CachedChains {\n    /// Whether the `endpoint` matches\n    pub fn is_match(&self, chain: u64) -> bool {\n        match self {\n            Self::All => true,\n            Self::None => false,\n            Self::Chains(chains) => chains.iter().any(|c| c.id() == chain),\n        }\n    }\n}\n\nimpl Serialize for CachedChains {\n    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>\n    where\n        S: Serializer,\n    {\n        match self {\n            Self::All => serializer.serialize_str(\"all\"),\n            Self::None => serializer.serialize_str(\"none\"),\n            Self::Chains(chains) => chains.serialize(serializer),\n        }\n    }\n}\n\nimpl<'de> Deserialize<'de> for CachedChains {\n    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>\n    where\n        D: Deserializer<'de>,\n    {\n        #[derive(Deserialize)]\n        #[serde(untagged)]\n        enum Chains {\n            All(String),\n            Chains(Vec<Chain>),\n        }\n\n        match Chains::deserialize(deserializer)? {\n            Chains::All(s) => match s.as_str() {\n                \"all\" => Ok(Self::All),\n                \"none\" => Ok(Self::None),\n                s => Err(serde::de::Error::unknown_variant(s, &[\"all\", \"none\"])),\n            },\n            Chains::Chains(chains) => Ok(Self::Chains(chains)),\n        }\n    }\n}\n\n/// What endpoints to enable caching for\n#[derive(Clone, Debug, Default)]\npub enum CachedEndpoints {\n    /// Cache all endpoints\n    #[default]\n    All,\n    /// Only cache non-local host endpoints\n    Remote,\n    /// Only cache these chains\n    Pattern(regex::Regex),\n}\n\nimpl CachedEndpoints {\n    /// Whether the `endpoint` matches\n    pub fn is_match(&self, endpoint: impl AsRef<str>) -> bool {\n        let endpoint = endpoint.as_ref();\n        match self {\n            Self::All => true,\n            Self::Remote => !endpoint.contains(\"localhost:\") && !endpoint.contains(\"127.0.0.1:\"),\n            Self::Pattern(re) => re.is_match(endpoint),\n        }\n    }\n}\n\nimpl PartialEq for CachedEndpoints {\n    fn eq(&self, other: &Self) -> bool {\n        match (self, other) {\n            (Self::Pattern(a), Self::Pattern(b)) => a.as_str() == b.as_str(),\n            (&Self::All, &Self::All) => true,\n            (&Self::Remote, &Self::Remote) => true,\n            _ => false,\n        }\n    }\n}\n\nimpl Eq for CachedEndpoints {}\n\nimpl fmt::Display for CachedEndpoints {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        match self {\n            Self::All => f.write_str(\"all\"),\n            Self::Remote => f.write_str(\"remote\"),\n            Self::Pattern(s) => s.fmt(f),\n        }\n    }\n}\n\nimpl FromStr for CachedEndpoints {\n    type Err = regex::Error;\n\n    fn from_str(s: &str) -> Result<Self, Self::Err> {\n        match s {\n            \"all\" => Ok(Self::All),\n            \"remote\" => Ok(Self::Remote),\n            _ => Ok(Self::Pattern(s.parse()?)),\n        }\n    }\n}\n\nimpl<'de> Deserialize<'de> for CachedEndpoints {\n    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>\n    where\n        D: Deserializer<'de>,\n    {\n        String::deserialize(deserializer)?.parse().map_err(serde::de::Error::custom)\n    }\n}\n\nimpl Serialize for CachedEndpoints {\n    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>\n    where\n        S: Serializer,\n    {\n        match self {\n            Self::All => serializer.serialize_str(\"all\"),\n            Self::Remote => serializer.serialize_str(\"remote\"),\n            Self::Pattern(pattern) => serializer.serialize_str(pattern.as_str()),\n        }\n    }\n}\n\n/// Content of the foundry cache folder\n#[derive(Debug, Default)]\npub struct Cache {\n    /// The list of chains in the cache\n    pub chains: Vec<ChainCache>,\n}\n\nimpl fmt::Display for Cache {\n    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {\n        for chain in &self.chains {\n            match NumberPrefix::decimal(\n                chain.block_explorer as f32 + chain.blocks.iter().map(|x| x.1).sum::<u64>() as f32,\n            ) {\n                NumberPrefix::Standalone(size) => {\n                    writeln!(f, \"- {} ({size:.1} B)\", chain.name)?;\n                }\n                NumberPrefix::Prefixed(prefix, size) => {\n                    writeln!(f, \"- {} ({size:.1} {prefix}B)\", chain.name)?;\n                }\n            }\n            match NumberPrefix::decimal(chain.block_explorer as f32) {\n                NumberPrefix::Standalone(size) => {\n                    writeln!(f, \"\\t- Block Explorer ({size:.1} B)\\n\")?;\n                }\n                NumberPrefix::Prefixed(prefix, size) => {\n                    writeln!(f, \"\\t- Block Explorer ({size:.1} {prefix}B)\\n\")?;\n                }\n            }\n            for block in &chain.blocks {\n                match NumberPrefix::decimal(block.1 as f32) {\n                    NumberPrefix::Standalone(size) => {\n                        writeln!(f, \"\\t- Block {} ({size:.1} B)\", block.0)?;\n                    }\n                    NumberPrefix::Prefixed(prefix, size) => {\n                        writeln!(f, \"\\t- Block {} ({size:.1} {prefix}B)\", block.0)?;\n                    }\n                }\n            }\n        }\n        Ok(())\n    }\n}\n\n/// A representation of data for a given chain in the foundry cache\n#[derive(Debug)]\npub struct ChainCache {\n    /// The name of the chain\n    pub name: String,\n\n    /// A tuple containing block number and the block directory size in bytes\n    pub blocks: Vec<(String, u64)>,\n\n    /// The size of the block explorer directory in bytes\n    pub block_explorer: u64,\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use similar_asserts::assert_eq;\n\n    #[test]\n    fn can_parse_storage_config() {\n        #[derive(Serialize, Deserialize)]\n        pub struct Wrapper {\n            pub rpc_storage_caching: StorageCachingConfig,\n        }\n\n        let s = r#\"rpc_storage_caching = { chains = \"all\", endpoints = \"remote\"}\"#;\n        let w: Wrapper = toml::from_str(s).unwrap();\n\n        assert_eq!(\n            w.rpc_storage_caching,\n            StorageCachingConfig { chains: CachedChains::All, endpoints: CachedEndpoints::Remote }\n        );\n\n        let s = r#\"rpc_storage_caching = { chains = [1, \"optimism\", 999999], endpoints = \"all\"}\"#;\n        let w: Wrapper = toml::from_str(s).unwrap();\n\n        assert_eq!(\n            w.rpc_storage_caching,\n            StorageCachingConfig {\n                chains: CachedChains::Chains(vec![\n                    Chain::mainnet(),\n                    Chain::optimism_mainnet(),\n                    Chain::from_id(999999)\n                ]),\n                endpoints: CachedEndpoints::All,\n            }\n        )\n    }\n\n    #[test]\n    fn cache_to_string() {\n        let cache = Cache {\n            chains: vec![\n                ChainCache {\n                    name: \"mainnet\".to_string(),\n                    blocks: vec![(\"1\".to_string(), 1), (\"2\".to_string(), 2)],\n                    block_explorer: 500,\n                },\n                ChainCache {\n                    name: \"ropsten\".to_string(),\n                    blocks: vec![(\"1\".to_string(), 1), (\"2\".to_string(), 2)],\n                    block_explorer: 4567,\n                },\n                ChainCache {\n                    name: \"rinkeby\".to_string(),\n                    blocks: vec![(\"1\".to_string(), 1032), (\"2\".to_string(), 2000000)],\n                    block_explorer: 4230000,\n                },\n                ChainCache {\n                    name: \"amoy\".to_string(),\n                    blocks: vec![(\"1\".to_string(), 1), (\"2\".to_string(), 2)],\n                    block_explorer: 0,\n                },\n            ],\n        };\n\n        let expected = \"\\\n            - mainnet (503.0 B)\\n\\t\\\n                - Block Explorer (500.0 B)\\n\\n\\t\\\n                - Block 1 (1.0 B)\\n\\t\\\n                - Block 2 (2.0 B)\\n\\\n            - ropsten (4.6 kB)\\n\\t\\\n                - Block Explorer (4.6 kB)\\n\\n\\t\\\n                - Block 1 (1.0 B)\\n\\t\\\n                - Block 2 (2.0 B)\\n\\\n            - rinkeby (6.2 MB)\\n\\t\\\n                - Block Explorer (4.2 MB)\\n\\n\\t\\\n                - Block 1 (1.0 kB)\\n\\t\\\n                - Block 2 (2.0 MB)\\n\\\n            - amoy (3.0 B)\\n\\t\\\n                - Block Explorer (0.0 B)\\n\\n\\t\\\n                - Block 1 (1.0 B)\\n\\t\\\n                - Block 2 (2.0 B)\\n\";\n        assert_eq!(format!(\"{cache}\"), expected);\n    }\n}\n"
  },
  {
    "path": "crates/config/src/compilation.rs",
    "content": "use crate::{filter::GlobMatcher, serde_helpers};\nuse foundry_compilers::{\n    RestrictionsWithVersion,\n    artifacts::{BytecodeHash, EvmVersion},\n    multi::{MultiCompilerRestrictions, MultiCompilerSettings},\n    settings::VyperRestrictions,\n    solc::{Restriction, SolcRestrictions},\n};\nuse semver::VersionReq;\nuse serde::{Deserialize, Deserializer, Serialize};\n\n/// Keeps possible overrides for default settings which users may configure to construct additional\n/// settings profile.\n#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]\npub struct SettingsOverrides {\n    pub name: String,\n    pub via_ir: Option<bool>,\n    #[serde(default, with = \"serde_helpers::display_from_str_opt\")]\n    pub evm_version: Option<EvmVersion>,\n    pub optimizer: Option<bool>,\n    pub optimizer_runs: Option<usize>,\n    pub bytecode_hash: Option<BytecodeHash>,\n}\n\nimpl SettingsOverrides {\n    /// Applies the overrides to the given settings.\n    pub fn apply(&self, settings: &mut MultiCompilerSettings) {\n        if let Some(via_ir) = self.via_ir {\n            settings.solc.via_ir = Some(via_ir);\n        }\n\n        if let Some(evm_version) = self.evm_version {\n            settings.solc.evm_version = Some(evm_version);\n            settings.vyper.evm_version = Some(evm_version);\n        }\n\n        if let Some(enabled) = self.optimizer {\n            settings.solc.optimizer.enabled = Some(enabled);\n        }\n\n        if let Some(optimizer_runs) = self.optimizer_runs {\n            settings.solc.optimizer.runs = Some(optimizer_runs);\n            // Enable optimizer in optimizer runs set to a higher value than 0.\n            if optimizer_runs > 0 && self.optimizer.is_none() {\n                settings.solc.optimizer.enabled = Some(true);\n            }\n        }\n\n        if let Some(bytecode_hash) = self.bytecode_hash {\n            if let Some(metadata) = settings.solc.metadata.as_mut() {\n                metadata.bytecode_hash = Some(bytecode_hash);\n            } else {\n                settings.solc.metadata = Some(bytecode_hash.into());\n            }\n        }\n    }\n}\n\n#[derive(Debug, thiserror::Error)]\npub enum RestrictionsError {\n    #[error(\"specified both exact and relative restrictions for {0}\")]\n    BothExactAndRelative(&'static str),\n}\n\n/// Restrictions for compilation of given paths.\n///\n/// Only purpose of this type is to accept user input to later construct\n/// `RestrictionsWithVersion<MultiCompilerRestrictions>`.\n#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]\npub struct CompilationRestrictions {\n    pub paths: GlobMatcher,\n    #[serde(default, deserialize_with = \"deserialize_version_req\")]\n    pub version: Option<VersionReq>,\n    pub via_ir: Option<bool>,\n    pub bytecode_hash: Option<BytecodeHash>,\n\n    pub min_optimizer_runs: Option<usize>,\n    pub optimizer_runs: Option<usize>,\n    pub max_optimizer_runs: Option<usize>,\n\n    #[serde(default, with = \"serde_helpers::display_from_str_opt\")]\n    pub min_evm_version: Option<EvmVersion>,\n    #[serde(default, with = \"serde_helpers::display_from_str_opt\")]\n    pub evm_version: Option<EvmVersion>,\n    #[serde(default, with = \"serde_helpers::display_from_str_opt\")]\n    pub max_evm_version: Option<EvmVersion>,\n}\n\n/// Custom deserializer for version field that rejects ambiguous bare version numbers.\nfn deserialize_version_req<'de, D>(deserializer: D) -> Result<Option<VersionReq>, D::Error>\nwhere\n    D: Deserializer<'de>,\n{\n    let opt_string: Option<String> = Option::deserialize(deserializer)?;\n    let Some(opt_string) = opt_string else {\n        return Ok(None);\n    };\n\n    let version = opt_string.trim();\n    // Reject bare versions like \"0.8.11\" that lack an operator prefix\n    if version.chars().next().is_some_and(|c| c.is_ascii_digit()) {\n        return Err(serde::de::Error::custom(format!(\n            \"Invalid version format '{opt_string}' in compilation_restrictions. \\\n             Bare version numbers are ambiguous and default to caret requirements (e.g. '^{version}'). \\\n             Use an explicit constraint such as '={version}' for an exact version or '>={version}' for a minimum version.\"\n        )));\n    }\n\n    let req = VersionReq::parse(&opt_string).map_err(|e| {\n        serde::de::Error::custom(format!(\n            \"Invalid version requirement '{opt_string}': {e}. \\\n             Examples: '=0.8.11' (exact), '>=0.8.11' (minimum), '>=0.8.11 <0.9.0' (range).\"\n        ))\n    })?;\n\n    Ok(Some(req))\n}\n\nimpl TryFrom<CompilationRestrictions> for RestrictionsWithVersion<MultiCompilerRestrictions> {\n    type Error = RestrictionsError;\n\n    fn try_from(value: CompilationRestrictions) -> Result<Self, Self::Error> {\n        let (min_evm, max_evm) =\n            match (value.min_evm_version, value.max_evm_version, value.evm_version) {\n                (None, None, Some(exact)) => (Some(exact), Some(exact)),\n                (min, max, None) => (min, max),\n                _ => return Err(RestrictionsError::BothExactAndRelative(\"evm_version\")),\n            };\n        let (min_opt, max_opt) =\n            match (value.min_optimizer_runs, value.max_optimizer_runs, value.optimizer_runs) {\n                (None, None, Some(exact)) => (Some(exact), Some(exact)),\n                (min, max, None) => (min, max),\n                _ => return Err(RestrictionsError::BothExactAndRelative(\"optimizer_runs\")),\n            };\n        Ok(Self {\n            restrictions: MultiCompilerRestrictions {\n                solc: SolcRestrictions {\n                    evm_version: Restriction { min: min_evm, max: max_evm },\n                    via_ir: value.via_ir,\n                    optimizer_runs: Restriction { min: min_opt, max: max_opt },\n                    bytecode_hash: value.bytecode_hash,\n                },\n                vyper: VyperRestrictions {\n                    evm_version: Restriction { min: min_evm, max: max_evm },\n                },\n            },\n            version: value.version,\n        })\n    }\n}\n"
  },
  {
    "path": "crates/config/src/doc.rs",
    "content": "//! Configuration specific to the `forge doc` command and the `forge_doc` package\n\nuse serde::{Deserialize, Serialize};\nuse std::path::PathBuf;\n\n/// Contains the config for parsing and rendering docs\n#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]\npub struct DocConfig {\n    /// Doc output path.\n    pub out: PathBuf,\n    /// The documentation title.\n    pub title: String,\n    /// Path to user provided `book.toml`.\n    pub book: PathBuf,\n    /// Path to user provided welcome markdown.\n    ///\n    /// If none is provided, it defaults to `README.md`.\n    #[serde(default, skip_serializing_if = \"Option::is_none\")]\n    pub homepage: Option<PathBuf>,\n    /// The repository url.\n    #[serde(default, skip_serializing_if = \"Option::is_none\")]\n    pub repository: Option<String>,\n    /// The path to source code (e.g. `tree/main/packages/contracts`).\n    /// Useful for monorepos or for projects with source code located in specific directories.\n    #[serde(default, skip_serializing_if = \"Option::is_none\")]\n    pub path: Option<String>,\n    /// Globs to ignore\n    pub ignore: Vec<String>,\n}\n\nimpl Default for DocConfig {\n    fn default() -> Self {\n        Self {\n            out: PathBuf::from(\"docs\"),\n            book: PathBuf::from(\"book.toml\"),\n            homepage: Some(PathBuf::from(\"README.md\")),\n            title: String::default(),\n            repository: None,\n            path: None,\n            ignore: Vec::default(),\n        }\n    }\n}\n"
  },
  {
    "path": "crates/config/src/endpoints.rs",
    "content": "//! Support for multiple RPC-endpoints\n\nuse crate::resolve::{RE_PLACEHOLDER, UnresolvedEnvVarError, interpolate};\nuse serde::{Deserialize, Deserializer, Serialize, Serializer, ser::SerializeMap};\nuse std::{\n    collections::BTreeMap,\n    fmt,\n    ops::{Deref, DerefMut},\n};\n\n/// Container type for API endpoints, like various RPC endpoints\n#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]\n#[serde(transparent)]\npub struct RpcEndpoints {\n    endpoints: BTreeMap<String, RpcEndpoint>,\n}\n\nimpl RpcEndpoints {\n    /// Creates a new list of endpoints\n    pub fn new(\n        endpoints: impl IntoIterator<Item = (impl Into<String>, impl Into<RpcEndpointType>)>,\n    ) -> Self {\n        Self {\n            endpoints: endpoints\n                .into_iter()\n                .map(|(name, e)| match e.into() {\n                    RpcEndpointType::String(url) => (name.into(), RpcEndpoint::new(url)),\n                    RpcEndpointType::Config(config) => (name.into(), config),\n                })\n                .collect(),\n        }\n    }\n\n    /// Returns `true` if this type doesn't contain any endpoints\n    pub fn is_empty(&self) -> bool {\n        self.endpoints.is_empty()\n    }\n\n    /// Returns all (alias -> rpc_endpoint) pairs\n    pub fn resolved(self) -> ResolvedRpcEndpoints {\n        ResolvedRpcEndpoints {\n            endpoints: self.endpoints.into_iter().map(|(name, e)| (name, e.resolve())).collect(),\n        }\n    }\n}\n\nimpl Deref for RpcEndpoints {\n    type Target = BTreeMap<String, RpcEndpoint>;\n\n    fn deref(&self) -> &Self::Target {\n        &self.endpoints\n    }\n}\n\n/// RPC endpoint wrapper type\n#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]\n#[serde(untagged)]\npub enum RpcEndpointType {\n    /// Raw Endpoint url string\n    String(RpcEndpointUrl),\n    /// Config object\n    Config(RpcEndpoint),\n}\n\nimpl RpcEndpointType {\n    /// Returns the url or config this type holds\n    ///\n    /// # Error\n    ///\n    /// Returns an error if the type holds a reference to an env var and the env var is not set\n    pub fn resolve(self) -> Result<String, UnresolvedEnvVarError> {\n        match self {\n            Self::String(url) => url.resolve(),\n            Self::Config(config) => config.endpoint.resolve(),\n        }\n    }\n}\n\nimpl fmt::Display for RpcEndpointType {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        match self {\n            Self::String(url) => url.fmt(f),\n            Self::Config(config) => config.fmt(f),\n        }\n    }\n}\n\nimpl TryFrom<RpcEndpointType> for String {\n    type Error = UnresolvedEnvVarError;\n\n    fn try_from(value: RpcEndpointType) -> Result<Self, Self::Error> {\n        match value {\n            RpcEndpointType::String(url) => url.resolve(),\n            RpcEndpointType::Config(config) => config.endpoint.resolve(),\n        }\n    }\n}\n\n/// Represents a single endpoint\n///\n/// This type preserves the value as it's stored in the config. If the value is a reference to an\n/// env var, then the `Endpoint::Env` var will hold the reference (`${MAIN_NET}`) and _not_ the\n/// value of the env var itself.\n/// In other words, this type does not resolve env vars when it's being deserialized\n#[derive(Clone, Debug, PartialEq, Eq)]\npub enum RpcEndpointUrl {\n    /// A raw Url (ws, http)\n    Url(String),\n    /// An endpoint that contains at least one `${ENV_VAR}` placeholder\n    ///\n    /// **Note:** this contains the endpoint as is, like `https://eth-mainnet.alchemyapi.io/v2/${API_KEY}` or `${EPC_ENV_VAR}`\n    Env(String),\n}\n\nimpl RpcEndpointUrl {\n    /// Returns the url variant\n    pub fn as_url(&self) -> Option<&str> {\n        match self {\n            Self::Url(url) => Some(url),\n            Self::Env(_) => None,\n        }\n    }\n\n    /// Returns the url this type holds\n    ///\n    /// # Error\n    ///\n    /// Returns an error if the type holds a reference to an env var and the env var is not set\n    pub fn resolve(self) -> Result<String, UnresolvedEnvVarError> {\n        match self {\n            Self::Url(url) => Ok(url),\n            Self::Env(val) => interpolate(&val),\n        }\n    }\n}\n\nimpl fmt::Display for RpcEndpointUrl {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        match self {\n            Self::Url(url) => url.fmt(f),\n            Self::Env(var) => var.fmt(f),\n        }\n    }\n}\n\nimpl TryFrom<RpcEndpointUrl> for String {\n    type Error = UnresolvedEnvVarError;\n\n    fn try_from(value: RpcEndpointUrl) -> Result<Self, Self::Error> {\n        value.resolve()\n    }\n}\n\nimpl Serialize for RpcEndpointUrl {\n    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>\n    where\n        S: Serializer,\n    {\n        serializer.serialize_str(&self.to_string())\n    }\n}\n\nimpl<'de> Deserialize<'de> for RpcEndpointUrl {\n    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>\n    where\n        D: Deserializer<'de>,\n    {\n        let val = String::deserialize(deserializer)?;\n        let endpoint = if RE_PLACEHOLDER.is_match(&val) { Self::Env(val) } else { Self::Url(val) };\n\n        Ok(endpoint)\n    }\n}\n\nimpl From<RpcEndpointUrl> for RpcEndpointType {\n    fn from(endpoint: RpcEndpointUrl) -> Self {\n        Self::String(endpoint)\n    }\n}\n\nimpl From<RpcEndpointUrl> for RpcEndpoint {\n    fn from(endpoint: RpcEndpointUrl) -> Self {\n        Self { endpoint, ..Default::default() }\n    }\n}\n\n/// The auth token to be used for RPC endpoints\n/// It works in the same way as the `RpcEndpoint` type, where it can be a raw string or a reference\n#[derive(Clone, Debug, PartialEq, Eq)]\npub enum RpcAuth {\n    Raw(String),\n    Env(String),\n}\n\nimpl RpcAuth {\n    /// Returns the auth token this type holds\n    ///\n    /// # Error\n    ///\n    /// Returns an error if the type holds a reference to an env var and the env var is not set\n    pub fn resolve(self) -> Result<String, UnresolvedEnvVarError> {\n        match self {\n            Self::Raw(raw_auth) => Ok(raw_auth),\n            Self::Env(var) => interpolate(&var),\n        }\n    }\n}\n\nimpl fmt::Display for RpcAuth {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        match self {\n            Self::Raw(url) => url.fmt(f),\n            Self::Env(var) => var.fmt(f),\n        }\n    }\n}\n\nimpl Serialize for RpcAuth {\n    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>\n    where\n        S: Serializer,\n    {\n        serializer.serialize_str(&self.to_string())\n    }\n}\n\nimpl<'de> Deserialize<'de> for RpcAuth {\n    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>\n    where\n        D: Deserializer<'de>,\n    {\n        let val = String::deserialize(deserializer)?;\n        let auth = if RE_PLACEHOLDER.is_match(&val) { Self::Env(val) } else { Self::Raw(val) };\n\n        Ok(auth)\n    }\n}\n\n// Rpc endpoint configuration\n#[derive(Debug, Clone, Default, PartialEq, Eq)]\npub struct RpcEndpointConfig {\n    /// The number of retries.\n    pub retries: Option<u32>,\n\n    /// Initial retry backoff.\n    pub retry_backoff: Option<u64>,\n\n    /// The available compute units per second.\n    ///\n    /// See also <https://docs.alchemy.com/reference/compute-units#what-are-cups-compute-units-per-second>\n    pub compute_units_per_second: Option<u64>,\n}\n\nimpl fmt::Display for RpcEndpointConfig {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        let Self { retries, retry_backoff, compute_units_per_second } = self;\n\n        if let Some(retries) = retries {\n            write!(f, \", retries={retries}\")?;\n        }\n\n        if let Some(retry_backoff) = retry_backoff {\n            write!(f, \", retry_backoff={retry_backoff}\")?;\n        }\n\n        if let Some(compute_units_per_second) = compute_units_per_second {\n            write!(f, \", compute_units_per_second={compute_units_per_second}\")?;\n        }\n\n        Ok(())\n    }\n}\n\n/// Rpc endpoint configuration variant\n#[derive(Debug, Clone, PartialEq, Eq)]\npub struct RpcEndpoint {\n    /// endpoint url or env\n    pub endpoint: RpcEndpointUrl,\n\n    /// Token to be used as authentication\n    pub auth: Option<RpcAuth>,\n\n    /// additional configuration\n    pub config: RpcEndpointConfig,\n}\n\nimpl RpcEndpoint {\n    pub fn new(endpoint: RpcEndpointUrl) -> Self {\n        Self { endpoint, ..Default::default() }\n    }\n\n    /// Resolves environment variables in fields into their raw values\n    pub fn resolve(self) -> ResolvedRpcEndpoint {\n        ResolvedRpcEndpoint {\n            endpoint: self.endpoint.resolve(),\n            auth: self.auth.map(|auth| auth.resolve()),\n            config: self.config,\n        }\n    }\n}\n\nimpl fmt::Display for RpcEndpoint {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        let Self { endpoint, auth, config } = self;\n        write!(f, \"{endpoint}\")?;\n        write!(f, \"{config}\")?;\n        if let Some(auth) = auth {\n            write!(f, \", auth={auth}\")?;\n        }\n        Ok(())\n    }\n}\n\nimpl Serialize for RpcEndpoint {\n    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>\n    where\n        S: Serializer,\n    {\n        if self.config.retries.is_none()\n            && self.config.retry_backoff.is_none()\n            && self.config.compute_units_per_second.is_none()\n            && self.auth.is_none()\n        {\n            // serialize as endpoint if there's no additional config\n            self.endpoint.serialize(serializer)\n        } else {\n            let mut map = serializer.serialize_map(Some(5))?;\n            map.serialize_entry(\"endpoint\", &self.endpoint)?;\n            map.serialize_entry(\"retries\", &self.config.retries)?;\n            map.serialize_entry(\"retry_backoff\", &self.config.retry_backoff)?;\n            map.serialize_entry(\"compute_units_per_second\", &self.config.compute_units_per_second)?;\n            map.serialize_entry(\"auth\", &self.auth)?;\n            map.end()\n        }\n    }\n}\n\nimpl<'de> Deserialize<'de> for RpcEndpoint {\n    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>\n    where\n        D: Deserializer<'de>,\n    {\n        let value = serde_json::Value::deserialize(deserializer)?;\n        if value.is_string() {\n            return Ok(Self {\n                endpoint: serde_json::from_value(value).map_err(serde::de::Error::custom)?,\n                ..Default::default()\n            });\n        }\n\n        #[derive(Deserialize)]\n        struct RpcEndpointConfigInner {\n            #[serde(alias = \"url\")]\n            endpoint: RpcEndpointUrl,\n            retries: Option<u32>,\n            retry_backoff: Option<u64>,\n            compute_units_per_second: Option<u64>,\n            auth: Option<RpcAuth>,\n        }\n\n        let RpcEndpointConfigInner {\n            endpoint,\n            retries,\n            retry_backoff,\n            compute_units_per_second,\n            auth,\n        } = serde_json::from_value(value).map_err(serde::de::Error::custom)?;\n\n        Ok(Self {\n            endpoint,\n            auth,\n            config: RpcEndpointConfig { retries, retry_backoff, compute_units_per_second },\n        })\n    }\n}\n\nimpl From<RpcEndpoint> for RpcEndpointType {\n    fn from(config: RpcEndpoint) -> Self {\n        Self::Config(config)\n    }\n}\n\nimpl Default for RpcEndpoint {\n    fn default() -> Self {\n        Self {\n            endpoint: RpcEndpointUrl::Url(\"http://localhost:8545\".to_string()),\n            config: RpcEndpointConfig::default(),\n            auth: None,\n        }\n    }\n}\n\n/// Rpc endpoint with environment variables resolved to values, see [`RpcEndpoint::resolve`].\n#[derive(Clone, Debug, PartialEq, Eq)]\npub struct ResolvedRpcEndpoint {\n    pub endpoint: Result<String, UnresolvedEnvVarError>,\n    pub auth: Option<Result<String, UnresolvedEnvVarError>>,\n    pub config: RpcEndpointConfig,\n}\n\nimpl ResolvedRpcEndpoint {\n    /// Returns the url this type holds, see [`RpcEndpoint::resolve`]\n    pub fn url(&self) -> Result<String, UnresolvedEnvVarError> {\n        self.endpoint.clone()\n    }\n\n    // Returns true if all environment variables are resolved successfully\n    pub fn is_unresolved(&self) -> bool {\n        let endpoint_err = self.endpoint.is_err();\n        let auth_err = self.auth.as_ref().map(|auth| auth.is_err()).unwrap_or(false);\n        endpoint_err || auth_err\n    }\n\n    // Attempts to resolve unresolved environment variables into a new instance\n    pub fn try_resolve(mut self) -> Self {\n        if !self.is_unresolved() {\n            return self;\n        }\n        if let Err(err) = self.endpoint {\n            self.endpoint = err.try_resolve()\n        }\n        if let Some(Err(err)) = self.auth {\n            self.auth = Some(err.try_resolve())\n        }\n        self\n    }\n}\n\n/// Container type for _resolved_ endpoints.\n#[derive(Clone, Debug, Default, PartialEq, Eq)]\npub struct ResolvedRpcEndpoints {\n    endpoints: BTreeMap<String, ResolvedRpcEndpoint>,\n}\n\nimpl ResolvedRpcEndpoints {\n    /// Returns true if there's an endpoint that couldn't be resolved\n    pub fn has_unresolved(&self) -> bool {\n        self.endpoints.values().any(|e| e.is_unresolved())\n    }\n}\n\nimpl Deref for ResolvedRpcEndpoints {\n    type Target = BTreeMap<String, ResolvedRpcEndpoint>;\n\n    fn deref(&self) -> &Self::Target {\n        &self.endpoints\n    }\n}\n\nimpl DerefMut for ResolvedRpcEndpoints {\n    fn deref_mut(&mut self) -> &mut Self::Target {\n        &mut self.endpoints\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn serde_rpc_config() {\n        let s = r#\"{\n            \"endpoint\": \"http://localhost:8545\",\n            \"retries\": 5,\n            \"retry_backoff\": 250,\n            \"compute_units_per_second\": 100,\n            \"auth\": \"Bearer 123\"\n        }\"#;\n        let config: RpcEndpoint = serde_json::from_str(s).unwrap();\n        assert_eq!(\n            config,\n            RpcEndpoint {\n                endpoint: RpcEndpointUrl::Url(\"http://localhost:8545\".to_string()),\n                config: RpcEndpointConfig {\n                    retries: Some(5),\n                    retry_backoff: Some(250),\n                    compute_units_per_second: Some(100),\n                },\n                auth: Some(RpcAuth::Raw(\"Bearer 123\".to_string())),\n            }\n        );\n\n        let s = \"\\\"http://localhost:8545\\\"\";\n        let config: RpcEndpoint = serde_json::from_str(s).unwrap();\n        assert_eq!(\n            config,\n            RpcEndpoint {\n                endpoint: RpcEndpointUrl::Url(\"http://localhost:8545\".to_string()),\n                config: RpcEndpointConfig {\n                    retries: None,\n                    retry_backoff: None,\n                    compute_units_per_second: None,\n                },\n                auth: None,\n            }\n        );\n    }\n}\n"
  },
  {
    "path": "crates/config/src/error.rs",
    "content": "//! error handling and solc error codes\nuse alloy_primitives::map::HashSet;\nuse figment::providers::{Format, Toml};\nuse serde::{Deserialize, Deserializer, Serialize, Serializer};\nuse std::{error::Error, fmt, str::FromStr};\n\n/// Represents a failed attempt to extract `Config` from a `Figment`\n#[derive(Clone, PartialEq)]\npub struct ExtractConfigError {\n    /// error thrown when extracting the `Config`\n    pub(crate) error: figment::Error,\n}\n\nimpl ExtractConfigError {\n    /// Wraps the figment error.\n    pub fn new(error: figment::Error) -> Self {\n        Self { error }\n    }\n}\n\nimpl fmt::Display for ExtractConfigError {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        let mut unique_errors = Vec::with_capacity(self.error.count());\n        let mut unique = HashSet::with_capacity(self.error.count());\n        for err in self.error.clone().into_iter() {\n            let err = if err\n                .metadata\n                .as_ref()\n                .map(|meta| meta.name.contains(Toml::NAME))\n                .unwrap_or_default()\n            {\n                FoundryConfigError::Toml(err)\n            } else {\n                FoundryConfigError::Other(err)\n            };\n\n            if unique.insert(err.to_string()) {\n                unique_errors.push(err);\n            }\n        }\n        writeln!(f, \"failed to extract foundry config:\")?;\n        for err in unique_errors {\n            writeln!(f, \"{err}\")?;\n        }\n        Ok(())\n    }\n}\n\nimpl fmt::Debug for ExtractConfigError {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        fmt::Display::fmt(self, f)\n    }\n}\n\nimpl Error for ExtractConfigError {\n    fn source(&self) -> Option<&(dyn Error + 'static)> {\n        Error::source(&self.error)\n    }\n}\n\n/// Represents an error that can occur when constructing the `Config`\n#[derive(Clone, Debug, PartialEq)]\npub enum FoundryConfigError {\n    /// An error thrown during toml parsing\n    Toml(figment::Error),\n    /// Any other error thrown when constructing the config's figment.\n    Other(figment::Error),\n}\n\nimpl fmt::Display for FoundryConfigError {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        let fmt_err = |err: &figment::Error, f: &mut fmt::Formatter<'_>| {\n            write!(f, \"{err}\")?;\n            if !err.path.is_empty() {\n                // the path will contain the setting value like `[\"etherscan_api_key\"]`\n                write!(f, \" for setting `{}`\", err.path.join(\".\"))?;\n            }\n            Ok(())\n        };\n\n        match self {\n            Self::Toml(err) => {\n                f.write_str(\"foundry.toml error: \")?;\n                fmt_err(err, f)\n            }\n            Self::Other(err) => {\n                f.write_str(\"foundry config error: \")?;\n                fmt_err(err, f)\n            }\n        }\n    }\n}\n\nimpl Error for FoundryConfigError {\n    fn source(&self) -> Option<&(dyn Error + 'static)> {\n        match self {\n            Self::Other(error) | Self::Toml(error) => Error::source(error),\n        }\n    }\n}\n\n/// A non-exhaustive list of solidity error codes\n#[derive(Clone, Copy, Debug, PartialEq, Eq)]\npub enum SolidityErrorCode {\n    /// Warning that SPDX license identifier not provided in source file\n    SpdxLicenseNotProvided,\n    /// Warning: Visibility for constructor is ignored. If you want the contract to be\n    /// non-deployable, making it \"abstract\" is sufficient\n    VisibilityForConstructorIsIgnored,\n    /// Warning that contract code size exceeds 24576 bytes (a limit introduced in Spurious\n    /// Dragon).\n    ContractExceeds24576Bytes,\n    /// Warning after shanghai if init code size exceeds 49152 bytes\n    ContractInitCodeSizeExceeds49152Bytes,\n    /// Warning that Function state mutability can be restricted to view/pure.\n    FunctionStateMutabilityCanBeRestricted,\n    /// Warning: Unused local variable\n    UnusedLocalVariable,\n    /// Warning: Unused function parameter. Remove or comment out the variable name to silence this\n    /// warning.\n    UnusedFunctionParameter,\n    /// Warning: Return value of low-level calls not used.\n    ReturnValueOfCallsNotUsed,\n    ///  Warning: Interface functions are implicitly \"virtual\"\n    InterfacesExplicitlyVirtual,\n    /// Warning: This contract has a payable fallback function, but no receive ether function.\n    /// Consider adding a receive ether function.\n    PayableNoReceiveEther,\n    ///  Warning: This declaration shadows an existing declaration.\n    ShadowsExistingDeclaration,\n    /// This declaration has the same name as another declaration.\n    DeclarationSameNameAsAnother,\n    /// Unnamed return variable can remain unassigned\n    UnnamedReturnVariable,\n    /// Unreachable code\n    Unreachable,\n    /// Missing pragma solidity\n    PragmaSolidity,\n    /// Uses transient opcodes\n    TransientStorageUsed,\n    /// There are more than 256 warnings. Ignoring the rest.\n    TooManyWarnings,\n    /// Warning: 'transfer' is deprecated and scheduled for removal.\n    TransferDeprecated,\n    /// Warning: Natspec memory-safe-assembly special comment for inline assembly is deprecated.\n    NatspecMemorySafeAssemblyDeprecated,\n    /// All other error codes\n    Other(u64),\n}\n\nimpl SolidityErrorCode {\n    /// The textual identifier for this error\n    ///\n    /// Returns `Err(code)` if unknown error\n    pub fn as_str(&self) -> Result<&'static str, u64> {\n        let s = match self {\n            Self::SpdxLicenseNotProvided => \"license\",\n            Self::VisibilityForConstructorIsIgnored => \"constructor-visibility\",\n            Self::ContractExceeds24576Bytes => \"code-size\",\n            Self::ContractInitCodeSizeExceeds49152Bytes => \"init-code-size\",\n            Self::FunctionStateMutabilityCanBeRestricted => \"func-mutability\",\n            Self::UnusedLocalVariable => \"unused-var\",\n            Self::UnusedFunctionParameter => \"unused-param\",\n            Self::ReturnValueOfCallsNotUsed => \"unused-return\",\n            Self::InterfacesExplicitlyVirtual => \"virtual-interfaces\",\n            Self::PayableNoReceiveEther => \"missing-receive-ether\",\n            Self::ShadowsExistingDeclaration => \"shadowing\",\n            Self::DeclarationSameNameAsAnother => \"same-varname\",\n            Self::UnnamedReturnVariable => \"unnamed-return\",\n            Self::Unreachable => \"unreachable\",\n            Self::PragmaSolidity => \"pragma-solidity\",\n            Self::TransientStorageUsed => \"transient-storage\",\n            Self::TooManyWarnings => \"too-many-warnings\",\n            Self::TransferDeprecated => \"transfer-deprecated\",\n            Self::NatspecMemorySafeAssemblyDeprecated => \"natspec-memory-safe-assembly-deprecated\",\n            Self::Other(code) => return Err(*code),\n        };\n        Ok(s)\n    }\n}\n\nimpl From<SolidityErrorCode> for u64 {\n    fn from(code: SolidityErrorCode) -> Self {\n        match code {\n            SolidityErrorCode::SpdxLicenseNotProvided => 1878,\n            SolidityErrorCode::VisibilityForConstructorIsIgnored => 2462,\n            SolidityErrorCode::ContractExceeds24576Bytes => 5574,\n            SolidityErrorCode::ContractInitCodeSizeExceeds49152Bytes => 3860,\n            SolidityErrorCode::FunctionStateMutabilityCanBeRestricted => 2018,\n            SolidityErrorCode::UnusedLocalVariable => 2072,\n            SolidityErrorCode::UnusedFunctionParameter => 5667,\n            SolidityErrorCode::ReturnValueOfCallsNotUsed => 9302,\n            SolidityErrorCode::InterfacesExplicitlyVirtual => 5815,\n            SolidityErrorCode::PayableNoReceiveEther => 3628,\n            SolidityErrorCode::ShadowsExistingDeclaration => 2519,\n            SolidityErrorCode::DeclarationSameNameAsAnother => 8760,\n            SolidityErrorCode::UnnamedReturnVariable => 6321,\n            SolidityErrorCode::Unreachable => 5740,\n            SolidityErrorCode::PragmaSolidity => 3420,\n            SolidityErrorCode::TransientStorageUsed => 2394,\n            SolidityErrorCode::TooManyWarnings => 4591,\n            SolidityErrorCode::TransferDeprecated => 9207,\n            SolidityErrorCode::NatspecMemorySafeAssemblyDeprecated => 2424,\n            SolidityErrorCode::Other(code) => code,\n        }\n    }\n}\n\nimpl fmt::Display for SolidityErrorCode {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        match self.as_str() {\n            Ok(name) => name.fmt(f),\n            Err(code) => code.fmt(f),\n        }\n    }\n}\n\nimpl FromStr for SolidityErrorCode {\n    type Err = String;\n\n    fn from_str(s: &str) -> Result<Self, Self::Err> {\n        let code = match s {\n            \"license\" => Self::SpdxLicenseNotProvided,\n            \"constructor-visibility\" => Self::VisibilityForConstructorIsIgnored,\n            \"code-size\" => Self::ContractExceeds24576Bytes,\n            \"init-code-size\" => Self::ContractInitCodeSizeExceeds49152Bytes,\n            \"func-mutability\" => Self::FunctionStateMutabilityCanBeRestricted,\n            \"unused-var\" => Self::UnusedLocalVariable,\n            \"unused-param\" => Self::UnusedFunctionParameter,\n            \"unused-return\" => Self::ReturnValueOfCallsNotUsed,\n            \"virtual-interfaces\" => Self::InterfacesExplicitlyVirtual,\n            \"missing-receive-ether\" => Self::PayableNoReceiveEther,\n            \"shadowing\" => Self::ShadowsExistingDeclaration,\n            \"same-varname\" => Self::DeclarationSameNameAsAnother,\n            \"unnamed-return\" => Self::UnnamedReturnVariable,\n            \"unreachable\" => Self::Unreachable,\n            \"pragma-solidity\" => Self::PragmaSolidity,\n            \"transient-storage\" => Self::TransientStorageUsed,\n            \"too-many-warnings\" => Self::TooManyWarnings,\n            \"transfer-deprecated\" => Self::TransferDeprecated,\n            \"natspec-memory-safe-assembly-deprecated\" => Self::NatspecMemorySafeAssemblyDeprecated,\n            _ => return Err(format!(\"Unknown variant {s}\")),\n        };\n\n        Ok(code)\n    }\n}\n\nimpl From<u64> for SolidityErrorCode {\n    fn from(code: u64) -> Self {\n        match code {\n            1878 => Self::SpdxLicenseNotProvided,\n            2462 => Self::VisibilityForConstructorIsIgnored,\n            5574 => Self::ContractExceeds24576Bytes,\n            3860 => Self::ContractInitCodeSizeExceeds49152Bytes,\n            2018 => Self::FunctionStateMutabilityCanBeRestricted,\n            2072 => Self::UnusedLocalVariable,\n            5667 => Self::UnusedFunctionParameter,\n            9302 => Self::ReturnValueOfCallsNotUsed,\n            5815 => Self::InterfacesExplicitlyVirtual,\n            3628 => Self::PayableNoReceiveEther,\n            2519 => Self::ShadowsExistingDeclaration,\n            8760 => Self::DeclarationSameNameAsAnother,\n            6321 => Self::UnnamedReturnVariable,\n            5740 => Self::Unreachable,\n            3420 => Self::PragmaSolidity,\n            2394 => Self::TransientStorageUsed,\n            4591 => Self::TooManyWarnings,\n            9207 => Self::TransferDeprecated,\n            2424 => Self::NatspecMemorySafeAssemblyDeprecated,\n            other => Self::Other(other),\n        }\n    }\n}\n\nimpl Serialize for SolidityErrorCode {\n    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>\n    where\n        S: Serializer,\n    {\n        match self.as_str() {\n            Ok(alias) => serializer.serialize_str(alias),\n            Err(code) => serializer.serialize_u64(code),\n        }\n    }\n}\n\nimpl<'de> Deserialize<'de> for SolidityErrorCode {\n    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>\n    where\n        D: Deserializer<'de>,\n    {\n        /// Helper deserializer for error codes as names and codes\n        #[derive(Deserialize)]\n        #[serde(untagged)]\n        enum SolCode {\n            Name(String),\n            Code(u64),\n        }\n\n        match SolCode::deserialize(deserializer)? {\n            SolCode::Code(code) => Ok(code.into()),\n            SolCode::Name(name) => name.parse().map_err(serde::de::Error::custom),\n        }\n    }\n}\n"
  },
  {
    "path": "crates/config/src/etherscan.rs",
    "content": "//! Support for multiple Etherscan keys.\n\nuse crate::{\n    Chain, Config, NamedChain,\n    resolve::{RE_PLACEHOLDER, UnresolvedEnvVarError, interpolate},\n};\nuse figment::{\n    Error, Metadata, Profile, Provider,\n    providers::Env,\n    value::{Dict, Map},\n};\nuse heck::ToKebabCase;\nuse serde::{Deserialize, Deserializer, Serialize, Serializer};\nuse std::{\n    collections::BTreeMap,\n    fmt,\n    ops::{Deref, DerefMut},\n    time::Duration,\n};\n\n/// A [Provider] that provides Etherscan API key from the environment if it's not empty.\n///\n/// This prevents `ETHERSCAN_API_KEY=\"\"` if it's set but empty\n#[derive(Debug, Clone, PartialEq, Eq, Default)]\n#[non_exhaustive]\npub(crate) struct EtherscanEnvProvider;\n\nimpl Provider for EtherscanEnvProvider {\n    fn metadata(&self) -> Metadata {\n        Env::raw().metadata()\n    }\n\n    fn data(&self) -> Result<Map<Profile, Dict>, Error> {\n        let mut dict = Dict::default();\n        let env_provider = Env::raw().only(&[\"ETHERSCAN_API_KEY\"]);\n        if let Some((key, value)) = env_provider.iter().next()\n            && !value.trim().is_empty()\n        {\n            dict.insert(key.as_str().to_string(), value.into());\n        }\n\n        Ok(Map::from([(Config::selected_profile(), dict)]))\n    }\n}\n\n/// Errors that can occur when creating an `EtherscanConfig`\n#[derive(Clone, Debug, PartialEq, Eq, thiserror::Error)]\npub enum EtherscanConfigError {\n    #[error(transparent)]\n    Unresolved(#[from] UnresolvedEnvVarError),\n\n    #[error(\n        \"No known Etherscan API URL for chain `{1}`. To fix this, please:\\n\\\n        1. Specify a `url` {0}\\n\\\n        2. Verify the chain `{1}` is correct\"\n    )]\n    UnknownChain(String, Chain),\n\n    #[error(\"At least one of `url` or `chain` must be present{0}\")]\n    MissingUrlOrChain(String),\n}\n\n/// Container type for Etherscan API keys and URLs.\n#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]\n#[serde(transparent)]\npub struct EtherscanConfigs {\n    configs: BTreeMap<String, EtherscanConfig>,\n}\n\nimpl EtherscanConfigs {\n    /// Creates a new list of etherscan configs\n    pub fn new(configs: impl IntoIterator<Item = (impl Into<String>, EtherscanConfig)>) -> Self {\n        Self { configs: configs.into_iter().map(|(name, config)| (name.into(), config)).collect() }\n    }\n\n    /// Returns `true` if this type doesn't contain any configs\n    pub fn is_empty(&self) -> bool {\n        self.configs.is_empty()\n    }\n\n    /// Returns the first config that matches the chain\n    pub fn find_chain(&self, chain: Chain) -> Option<&EtherscanConfig> {\n        self.configs.values().find(|config| config.chain == Some(chain))\n    }\n\n    /// Returns all (alias -> url) pairs\n    pub fn resolved(self) -> ResolvedEtherscanConfigs {\n        ResolvedEtherscanConfigs {\n            configs: self\n                .configs\n                .into_iter()\n                .map(|(name, e)| {\n                    let resolved = e.resolve(Some(&name));\n                    (name, resolved)\n                })\n                .collect(),\n        }\n    }\n}\n\nimpl Deref for EtherscanConfigs {\n    type Target = BTreeMap<String, EtherscanConfig>;\n\n    fn deref(&self) -> &Self::Target {\n        &self.configs\n    }\n}\n\nimpl DerefMut for EtherscanConfigs {\n    fn deref_mut(&mut self) -> &mut Self::Target {\n        &mut self.configs\n    }\n}\n\n/// Container type for _resolved_ etherscan keys, see [`EtherscanConfigs::resolved`].\n#[derive(Clone, Debug, Default, PartialEq, Eq)]\npub struct ResolvedEtherscanConfigs {\n    /// contains all named `ResolvedEtherscanConfig` or an error if we failed to resolve the env\n    /// var alias\n    configs: BTreeMap<String, Result<ResolvedEtherscanConfig, EtherscanConfigError>>,\n}\n\nimpl ResolvedEtherscanConfigs {\n    /// Creates a new list of resolved etherscan configs\n    pub fn new(\n        configs: impl IntoIterator<Item = (impl Into<String>, ResolvedEtherscanConfig)>,\n    ) -> Self {\n        Self {\n            configs: configs.into_iter().map(|(name, config)| (name.into(), Ok(config))).collect(),\n        }\n    }\n\n    /// Returns the first config that matches the chain\n    pub fn find_chain(\n        self,\n        chain: Chain,\n    ) -> Option<Result<ResolvedEtherscanConfig, EtherscanConfigError>> {\n        for (_, config) in self.configs.into_iter() {\n            match config {\n                Ok(c) if c.chain == Some(chain) => return Some(Ok(c)),\n                Err(e) => return Some(Err(e)),\n                _ => continue,\n            }\n        }\n        None\n    }\n\n    /// Returns true if there's a config that couldn't be resolved\n    pub fn has_unresolved(&self) -> bool {\n        self.configs.values().any(|val| val.is_err())\n    }\n}\n\nimpl Deref for ResolvedEtherscanConfigs {\n    type Target = BTreeMap<String, Result<ResolvedEtherscanConfig, EtherscanConfigError>>;\n\n    fn deref(&self) -> &Self::Target {\n        &self.configs\n    }\n}\n\nimpl DerefMut for ResolvedEtherscanConfigs {\n    fn deref_mut(&mut self) -> &mut Self::Target {\n        &mut self.configs\n    }\n}\n\n/// Represents all info required to create an etherscan client\n#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]\npub struct EtherscanConfig {\n    /// The chain name or EIP-155 chain ID used to derive the API URL.\n    #[serde(default, skip_serializing_if = \"Option::is_none\")]\n    pub chain: Option<Chain>,\n    /// Etherscan API URL\n    #[serde(default, skip_serializing_if = \"Option::is_none\")]\n    pub url: Option<String>,\n    /// The etherscan API KEY that's required to make requests\n    pub key: EtherscanApiKey,\n}\n\nimpl EtherscanConfig {\n    /// Returns the etherscan config required to create a client.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error if the type holds a reference to an env var and the env var is not set or\n    /// no chain or url is configured\n    pub fn resolve(\n        self,\n        alias: Option<&str>,\n    ) -> Result<ResolvedEtherscanConfig, EtherscanConfigError> {\n        let Self { chain, mut url, key } = self;\n\n        if let Some(url) = &mut url {\n            *url = interpolate(url)?;\n        }\n\n        let (chain, alias) = match (chain, alias) {\n            // fill one with the other\n            (Some(chain), None) => (Some(chain), Some(chain.to_string())),\n            (None, Some(alias)) => {\n                // alloy chain is parsed as kebab case\n                (\n                    alias.to_kebab_case().parse().ok().or_else(|| {\n                        // if this didn't work try to parse as json because the deserialize impl\n                        // supports more aliases\n                        serde_json::from_str::<NamedChain>(&format!(\"\\\"{alias}\\\"\"))\n                            .map(Into::into)\n                            .ok()\n                    }),\n                    Some(alias.into()),\n                )\n            }\n            // leave as is\n            (Some(chain), Some(alias)) => (Some(chain), Some(alias.into())),\n            (None, None) => (None, None),\n        };\n        let key = key.resolve()?;\n\n        match (chain, url) {\n            (Some(chain), Some(api_url)) => Ok(ResolvedEtherscanConfig {\n                api_url,\n                browser_url: chain.etherscan_urls().map(|(_, url)| url.to_string()),\n                key,\n                chain: Some(chain),\n            }),\n            (Some(chain), None) => ResolvedEtherscanConfig::create(key, chain).ok_or_else(|| {\n                let msg = alias.map(|a| format!(\"for `{a}`\")).unwrap_or_default();\n                EtherscanConfigError::UnknownChain(msg, chain)\n            }),\n            (None, Some(api_url)) => {\n                Ok(ResolvedEtherscanConfig { api_url, browser_url: None, key, chain: None })\n            }\n            (None, None) => {\n                let msg = alias\n                    .map(|a| format!(\" for Etherscan config with unknown alias `{a}`\"))\n                    .unwrap_or_default();\n                Err(EtherscanConfigError::MissingUrlOrChain(msg))\n            }\n        }\n    }\n}\n\n/// Contains required url + api key to set up an etherscan client\n#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]\npub struct ResolvedEtherscanConfig {\n    /// Etherscan API URL.\n    #[serde(rename = \"url\")]\n    pub api_url: String,\n    /// Optional browser URL.\n    #[serde(default, skip_serializing_if = \"Option::is_none\")]\n    pub browser_url: Option<String>,\n    /// The resolved API key.\n    pub key: String,\n    /// The chain name or EIP-155 chain ID.\n    #[serde(default, skip_serializing_if = \"Option::is_none\")]\n    pub chain: Option<Chain>,\n}\n\nimpl ResolvedEtherscanConfig {\n    /// Creates a new instance using the api key and chain\n    pub fn create(api_key: impl Into<String>, chain: impl Into<Chain>) -> Option<Self> {\n        let chain = chain.into();\n        let (api_url, browser_url) = chain.etherscan_urls()?;\n        Some(Self {\n            api_url: api_url.to_string(),\n            browser_url: Some(browser_url.to_string()),\n            key: api_key.into(),\n            chain: Some(chain),\n        })\n    }\n\n    /// Sets the chain value and consumes the type\n    ///\n    /// This is only used to set derive the appropriate Cache path for the etherscan client\n    pub fn with_chain(mut self, chain: impl Into<Chain>) -> Self {\n        self.set_chain(chain);\n        self\n    }\n\n    /// Sets the chain value\n    pub fn set_chain(&mut self, chain: impl Into<Chain>) -> &mut Self {\n        let chain = chain.into();\n        if let Some((api, browser)) = chain.etherscan_urls() {\n            self.api_url = api.to_string();\n            self.browser_url = Some(browser.to_string());\n        }\n        self.chain = Some(chain);\n        self\n    }\n\n    /// Returns the corresponding `foundry_block_explorers::Client`, configured with the `api_url`,\n    /// `api_key` and cache\n    pub fn into_client(\n        self,\n    ) -> Result<foundry_block_explorers::Client, foundry_block_explorers::errors::EtherscanError>\n    {\n        let Self { api_url, browser_url, key: api_key, chain } = self;\n\n        let chain = chain.unwrap_or_default();\n        let cache = Config::foundry_etherscan_chain_cache_dir(chain);\n\n        if let Some(cache_path) = &cache {\n            // we also create the `sources` sub dir here\n            if let Err(err) = std::fs::create_dir_all(cache_path.join(\"sources\")) {\n                warn!(\"could not create etherscan cache dir: {:?}\", err);\n            }\n        }\n\n        let mut client_builder = foundry_block_explorers::Client::builder()\n            .with_api_key(api_key)\n            .with_cache(cache, Duration::from_secs(24 * 60 * 60));\n        if let Some(ref browser_url) = browser_url {\n            client_builder = client_builder.with_url(browser_url)?;\n        }\n\n        // Use the provided URL (either custom from foundry.toml or chain's default from resolve())\n        client_builder = client_builder.with_api_url(&api_url)?;\n        // Fallback: Use api_url as browser URL if browser_url is not set\n        if browser_url.is_none() {\n            client_builder = client_builder.with_url(&api_url)?;\n        }\n        client_builder.build()\n    }\n}\n\n/// Represents a single etherscan API key\n///\n/// This type preserves the value as it's stored in the config. If the value is a reference to an\n/// env var, then the `EtherscanKey::Key` var will hold the reference (`${MAIN_NET}`) and _not_ the\n/// value of the env var itself.\n/// In other words, this type does not resolve env vars when it's being deserialized\n#[derive(Clone, Debug, PartialEq, Eq)]\npub enum EtherscanApiKey {\n    /// A raw key\n    Key(String),\n    /// An endpoint that contains at least one `${ENV_VAR}` placeholder\n    ///\n    /// **Note:** this contains the key or `${ETHERSCAN_KEY}`\n    Env(String),\n}\n\nimpl EtherscanApiKey {\n    /// Returns the key this type holds\n    ///\n    /// # Error\n    ///\n    /// Returns an error if the type holds a reference to an env var and the env var is not set\n    pub fn resolve(self) -> Result<String, UnresolvedEnvVarError> {\n        match self {\n            Self::Key(key) => Ok(key),\n            Self::Env(val) => interpolate(&val),\n        }\n    }\n}\n\nimpl Serialize for EtherscanApiKey {\n    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>\n    where\n        S: Serializer,\n    {\n        serializer.serialize_str(&self.to_string())\n    }\n}\n\nimpl<'de> Deserialize<'de> for EtherscanApiKey {\n    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>\n    where\n        D: Deserializer<'de>,\n    {\n        let val = String::deserialize(deserializer)?;\n        let endpoint = if RE_PLACEHOLDER.is_match(&val) { Self::Env(val) } else { Self::Key(val) };\n\n        Ok(endpoint)\n    }\n}\n\nimpl fmt::Display for EtherscanApiKey {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        match self {\n            Self::Key(key) => key.fmt(f),\n            Self::Env(var) => var.fmt(f),\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use NamedChain::Mainnet;\n\n    #[test]\n    fn can_create_client_via_chain() {\n        let mut configs = EtherscanConfigs::default();\n        configs.insert(\n            \"mainnet\".to_string(),\n            EtherscanConfig {\n                chain: Some(Mainnet.into()),\n                url: None,\n                key: EtherscanApiKey::Key(\"ABCDEFG\".to_string()),\n            },\n        );\n\n        let mut resolved = configs.resolved();\n        let config = resolved.remove(\"mainnet\").unwrap().unwrap();\n\n        let client = config.into_client().unwrap();\n        assert_eq!(\n            client.etherscan_api_url().as_str(),\n            \"https://api.etherscan.io/v2/api?chainid=1\"\n        );\n    }\n\n    #[test]\n    fn can_create_client_via_url_and_chain() {\n        let mut configs = EtherscanConfigs::default();\n        configs.insert(\n            \"mainnet\".to_string(),\n            EtherscanConfig {\n                chain: Some(Mainnet.into()),\n                url: Some(\"https://api.etherscan.io/api\".to_string()),\n                key: EtherscanApiKey::Key(\"ABCDEFG\".to_string()),\n            },\n        );\n\n        let mut resolved = configs.resolved();\n        let config = resolved.remove(\"mainnet\").unwrap().unwrap();\n        let _ = config.into_client().unwrap();\n    }\n\n    #[test]\n    fn can_create_client_via_url_and_chain_env_var() {\n        let mut configs = EtherscanConfigs::default();\n        let env = \"_CONFIG_ETHERSCAN_API_KEY\";\n        configs.insert(\n            \"mainnet\".to_string(),\n            EtherscanConfig {\n                chain: Some(Mainnet.into()),\n                url: Some(\"https://api.etherscan.io/api\".to_string()),\n                key: EtherscanApiKey::Env(format!(\"${{{env}}}\")),\n            },\n        );\n\n        let mut resolved = configs.clone().resolved();\n        let config = resolved.remove(\"mainnet\").unwrap();\n        assert!(config.is_err());\n\n        unsafe {\n            std::env::set_var(env, \"ABCDEFG\");\n        }\n\n        let mut resolved = configs.resolved();\n        let config = resolved.remove(\"mainnet\").unwrap().unwrap();\n        assert_eq!(config.key, \"ABCDEFG\");\n        let client = config.into_client().unwrap();\n        // Custom URL should be used even when chain has a default URL\n        assert_eq!(client.etherscan_api_url().as_str(), \"https://api.etherscan.io/api\");\n\n        unsafe {\n            std::env::remove_var(env);\n        }\n    }\n\n    #[test]\n    fn resolve_etherscan_alias_config() {\n        let mut configs = EtherscanConfigs::default();\n        configs.insert(\n            \"blast_sepolia\".to_string(),\n            EtherscanConfig {\n                chain: None,\n                url: Some(\"https://api.etherscan.io/api\".to_string()),\n                key: EtherscanApiKey::Key(\"ABCDEFG\".to_string()),\n            },\n        );\n\n        let mut resolved = configs.clone().resolved();\n        let config = resolved.remove(\"blast_sepolia\").unwrap().unwrap();\n        assert_eq!(config.chain, Some(Chain::blast_sepolia()));\n    }\n\n    #[test]\n    fn resolve_etherscan_alias() {\n        let config = EtherscanConfig {\n            chain: None,\n            url: Some(\"https://api.etherscan.io/api\".to_string()),\n            key: EtherscanApiKey::Key(\"ABCDEFG\".to_string()),\n        };\n        let resolved = config.clone().resolve(Some(\"base_sepolia\")).unwrap();\n        assert_eq!(resolved.chain, Some(Chain::base_sepolia()));\n\n        let resolved = config.resolve(Some(\"base-sepolia\")).unwrap();\n        assert_eq!(resolved.chain, Some(Chain::base_sepolia()));\n    }\n\n    #[test]\n    fn can_create_client_with_custom_url_for_chain_without_default_url() {\n        // Chains without default Etherscan URLs (e.g., Dev, AnvilHardhat networks)\n        // should work if a custom URL is provided in foundry.toml.\n        let mut configs = EtherscanConfigs::default();\n        configs.insert(\n            \"dev\".to_string(),\n            EtherscanConfig {\n                chain: Some(Chain::dev()),\n                url: Some(\"https://custom.api.url/verify/etherscan\".to_string()),\n                key: EtherscanApiKey::Key(\"test_key\".to_string()),\n            },\n        );\n\n        let mut resolved = configs.resolved();\n        let config = resolved.remove(\"dev\").unwrap().unwrap();\n        let result = config.into_client();\n        assert!(\n            result.is_ok(),\n            \"Should succeed with custom URL even for chains without default Etherscan URLs\"\n        );\n    }\n\n    #[test]\n    fn fails_without_custom_url_for_chain_without_default_url() {\n        // Chains without default Etherscan URLs (e.g., Dev, AnvilHardhat networks)\n        // should fail if no custom URL is provided in foundry.toml.\n        let mut configs = EtherscanConfigs::default();\n        configs.insert(\n            \"dev\".to_string(),\n            EtherscanConfig {\n                chain: Some(Chain::dev()),\n                url: None,\n                key: EtherscanApiKey::Key(\"test_key\".to_string()),\n            },\n        );\n\n        let mut resolved = configs.resolved();\n        let config = resolved.remove(\"dev\").unwrap();\n\n        assert!(\n            config.is_err(),\n            \"Should fail: chains without default Etherscan URLs require custom URL\"\n        );\n    }\n}\n"
  },
  {
    "path": "crates/config/src/extend.rs",
    "content": "use std::collections::HashMap;\n\nuse serde::{Deserialize, Serialize};\n\n/// Strategy for extending configuration from a base file.\n#[derive(Clone, Copy, Debug, Default, PartialEq, Serialize, Deserialize)]\n#[serde(rename_all = \"kebab-case\")]\npub enum ExtendStrategy {\n    /// Uses `admerge` figment strategy.\n    /// Arrays are concatenated (base elements + local elements).\n    /// Other values are replaced (local values override base values).\n    #[default]\n    ExtendArrays,\n\n    /// Uses `merge` figment strategy.\n    /// Arrays are replaced entirely (local arrays replace base arrays).\n    /// Other values are replaced (local values override base values).\n    ReplaceArrays,\n\n    /// Throws an error if any of the keys in the inherited toml file are also in `foundry.toml`.\n    NoCollision,\n}\n\n/// Configuration for extending from a base file.\n///\n/// Supports two formats:\n/// - String: `extends = \"base.toml\"`\n/// - Object: `extends = { path = \"base.toml\", strategy = \"no-collision\" }`\n#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]\n#[serde(untagged)]\npub enum Extends {\n    /// Simple string path to base file\n    Path(String),\n    /// Detailed configuration with path and strategy\n    Config(ExtendConfig),\n}\n\n#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]\npub struct ExtendConfig {\n    pub path: String,\n    #[serde(default)]\n    pub strategy: Option<ExtendStrategy>,\n}\n\nimpl Extends {\n    /// Get the path to the base file\n    pub fn path(&self) -> &str {\n        match self {\n            Self::Path(path) => path,\n            Self::Config(config) => &config.path,\n        }\n    }\n\n    /// Get the strategy to use for extending\n    pub fn strategy(&self) -> ExtendStrategy {\n        match self {\n            Self::Path(_) => ExtendStrategy::default(),\n            Self::Config(config) => config.strategy.unwrap_or_default(),\n        }\n    }\n}\n\n// -- HELPERS -----------------------------------------------------------------\n\n// Helper structs to only extract the 'extends' field and its strategy from the profiles\n#[derive(Deserialize, Default)]\npub(crate) struct ExtendsPartialConfig {\n    #[serde(default)]\n    pub profile: Option<HashMap<String, ExtendsHelper>>,\n}\n\n#[derive(Deserialize, Default)]\npub(crate) struct ExtendsHelper {\n    #[serde(default)]\n    pub extends: Option<Extends>,\n}\n"
  },
  {
    "path": "crates/config/src/filter.rs",
    "content": "//! Helpers for constructing and using [FileFilter]s.\n\nuse core::fmt;\nuse foundry_compilers::FileFilter;\nuse serde::{Deserialize, Serialize};\nuse std::{\n    convert::Infallible,\n    path::{Path, PathBuf},\n    str::FromStr,\n};\n\n/// Expand globs with a root path.\npub fn expand_globs(\n    root: &Path,\n    patterns: impl IntoIterator<Item = impl AsRef<str>>,\n) -> eyre::Result<Vec<PathBuf>> {\n    let mut expanded = Vec::new();\n    for pattern in patterns {\n        for paths in glob::glob(&root.join(pattern.as_ref()).display().to_string())? {\n            expanded.push(paths?);\n        }\n    }\n    Ok(expanded)\n}\n\n/// A `globset::Glob` that creates its `globset::GlobMatcher` when its created, so it doesn't need\n/// to be compiled when the filter functions `TestFilter` functions are called.\n#[derive(Clone, Debug)]\npub struct GlobMatcher {\n    /// The compiled glob\n    pub matcher: globset::GlobMatcher,\n}\n\nimpl GlobMatcher {\n    /// Creates a new `GlobMatcher` from a `globset::Glob`.\n    pub fn new(glob: globset::Glob) -> Self {\n        Self { matcher: glob.compile_matcher() }\n    }\n\n    /// Tests whether the given path matches this pattern or not.\n    ///\n    /// The glob `./test/*` won't match absolute paths like `test/Contract.sol`, which is common\n    /// format here, so we also handle this case here\n    pub fn is_match(&self, path: &Path) -> bool {\n        if self.matcher.is_match(path) {\n            return true;\n        }\n\n        if let Some(file_name) = path.file_name().and_then(|n| n.to_str())\n            && file_name.contains(self.as_str())\n        {\n            return true;\n        }\n\n        if !path.starts_with(\"./\") && self.as_str().starts_with(\"./\") {\n            return self.matcher.is_match(format!(\"./{}\", path.display()));\n        }\n\n        if path.is_relative() && Path::new(self.glob().glob()).is_absolute() {\n            if let Ok(canonicalized_path) = dunce::canonicalize(path) {\n                return self.matcher.is_match(&canonicalized_path);\n            } else {\n                return false;\n            }\n        }\n\n        false\n    }\n\n    /// Matches file only if the filter does not apply.\n    ///\n    /// This returns the inverse of `self.is_match(file)`.\n    fn is_match_exclude(&self, path: &Path) -> bool {\n        !self.is_match(path)\n    }\n\n    /// Returns the `globset::Glob`.\n    pub fn glob(&self) -> &globset::Glob {\n        self.matcher.glob()\n    }\n\n    /// Returns the `Glob` string used to compile this matcher.\n    pub fn as_str(&self) -> &str {\n        self.glob().glob()\n    }\n}\n\nimpl fmt::Display for GlobMatcher {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        self.glob().fmt(f)\n    }\n}\n\nimpl FromStr for GlobMatcher {\n    type Err = globset::Error;\n\n    fn from_str(s: &str) -> Result<Self, Self::Err> {\n        s.parse::<globset::Glob>().map(Self::new)\n    }\n}\n\nimpl From<globset::Glob> for GlobMatcher {\n    fn from(glob: globset::Glob) -> Self {\n        Self::new(glob)\n    }\n}\n\nimpl Serialize for GlobMatcher {\n    fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {\n        self.glob().glob().serialize(serializer)\n    }\n}\n\nimpl<'de> Deserialize<'de> for GlobMatcher {\n    fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {\n        let s = String::deserialize(deserializer)?;\n        s.parse().map_err(serde::de::Error::custom)\n    }\n}\n\nimpl PartialEq for GlobMatcher {\n    fn eq(&self, other: &Self) -> bool {\n        self.as_str() == other.as_str()\n    }\n}\n\nimpl Eq for GlobMatcher {}\n\n/// Bundles multiple `SkipBuildFilter` into a single `FileFilter`\n#[derive(Clone, Debug)]\npub struct SkipBuildFilters {\n    /// All provided filters.\n    pub matchers: Vec<GlobMatcher>,\n    /// Root of the project.\n    pub project_root: PathBuf,\n}\n\nimpl FileFilter for SkipBuildFilters {\n    /// Only returns a match if _no_  exclusion filter matches\n    fn is_match(&self, file: &Path) -> bool {\n        self.matchers.iter().all(|matcher| {\n            if !matcher.is_match_exclude(file) {\n                false\n            } else {\n                file.strip_prefix(&self.project_root)\n                    .map_or(true, |stripped| matcher.is_match_exclude(stripped))\n            }\n        })\n    }\n}\n\nimpl SkipBuildFilters {\n    /// Creates a new `SkipBuildFilters` from multiple `SkipBuildFilter`.\n    pub fn new<G: Into<GlobMatcher>>(\n        filters: impl IntoIterator<Item = G>,\n        project_root: PathBuf,\n    ) -> Self {\n        let matchers = filters.into_iter().map(|m| m.into()).collect();\n        Self { matchers, project_root }\n    }\n}\n\n/// A filter that excludes matching contracts from the build\n#[derive(Clone, Debug, PartialEq, Eq)]\npub enum SkipBuildFilter {\n    /// Exclude all `.t.sol` contracts\n    Tests,\n    /// Exclude all `.s.sol` contracts\n    Scripts,\n    /// Exclude if the file matches\n    Custom(String),\n}\n\nimpl SkipBuildFilter {\n    fn new(s: &str) -> Self {\n        match s {\n            \"test\" | \"tests\" => Self::Tests,\n            \"script\" | \"scripts\" => Self::Scripts,\n            s => Self::Custom(s.to_string()),\n        }\n    }\n\n    /// Returns the pattern to match against a file\n    pub fn file_pattern(&self) -> &str {\n        match self {\n            Self::Tests => \".t.sol\",\n            Self::Scripts => \".s.sol\",\n            Self::Custom(s) => s.as_str(),\n        }\n    }\n}\n\nimpl FromStr for SkipBuildFilter {\n    type Err = Infallible;\n\n    fn from_str(s: &str) -> Result<Self, Self::Err> {\n        Ok(Self::new(s))\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_build_filter() {\n        let tests = GlobMatcher::from_str(SkipBuildFilter::Tests.file_pattern()).unwrap();\n        let scripts = GlobMatcher::from_str(SkipBuildFilter::Scripts.file_pattern()).unwrap();\n        let custom = |s| GlobMatcher::from_str(s).unwrap();\n\n        let file = Path::new(\"A.t.sol\");\n        assert!(!tests.is_match_exclude(file));\n        assert!(scripts.is_match_exclude(file));\n        assert!(!custom(\"A.t\").is_match_exclude(file));\n\n        let file = Path::new(\"A.s.sol\");\n        assert!(tests.is_match_exclude(file));\n        assert!(!scripts.is_match_exclude(file));\n        assert!(!custom(\"A.s\").is_match_exclude(file));\n\n        let file = Path::new(\"/home/test/Foo.sol\");\n        assert!(!custom(\"*/test/**\").is_match_exclude(file));\n\n        let file = Path::new(\"/home/script/Contract.sol\");\n        assert!(!custom(\"*/script/**\").is_match_exclude(file));\n    }\n\n    #[test]\n    fn can_match_relative_glob_paths() {\n        let matcher: GlobMatcher = \"./test/*\".parse().unwrap();\n\n        // Absolute path that should match the pattern\n        assert!(matcher.is_match(Path::new(\"test/Contract.t.sol\")));\n\n        // Relative path that should match the pattern\n        assert!(matcher.is_match(Path::new(\"./test/Contract.t.sol\")));\n    }\n\n    #[test]\n    fn can_match_absolute_glob_paths() {\n        let matcher: GlobMatcher = \"/home/user/projects/project/test/*\".parse().unwrap();\n\n        // Absolute path that should match the pattern\n        assert!(matcher.is_match(Path::new(\"/home/user/projects/project/test/Contract.t.sol\")));\n\n        // Absolute path that should not match the pattern\n        assert!(!matcher.is_match(Path::new(\"/home/user/other/project/test/Contract.t.sol\")));\n\n        // Relative path that should not match an absolute pattern\n        assert!(!matcher.is_match(Path::new(\"projects/project/test/Contract.t.sol\")));\n    }\n}\n"
  },
  {
    "path": "crates/config/src/fix.rs",
    "content": "//! Helpers to automatically fix configuration warnings.\n\nuse crate::{Config, Warning};\nuse figment::providers::Env;\nuse std::{\n    fs, io,\n    ops::{Deref, DerefMut},\n    path::{Path, PathBuf},\n};\n\n/// A convenience wrapper around a TOML document and the path it was read from\nstruct TomlFile {\n    doc: toml_edit::DocumentMut,\n    path: PathBuf,\n}\n\nimpl TomlFile {\n    fn open(path: impl AsRef<Path>) -> eyre::Result<Self> {\n        let path = path.as_ref().to_owned();\n        let doc = fs::read_to_string(&path)?.parse()?;\n        Ok(Self { doc, path })\n    }\n\n    fn doc(&self) -> &toml_edit::DocumentMut {\n        &self.doc\n    }\n\n    fn doc_mut(&mut self) -> &mut toml_edit::DocumentMut {\n        &mut self.doc\n    }\n\n    fn path(&self) -> &Path {\n        self.path.as_ref()\n    }\n\n    fn save(&self) -> io::Result<()> {\n        fs::write(self.path(), self.doc().to_string())\n    }\n}\n\nimpl Deref for TomlFile {\n    type Target = toml_edit::DocumentMut;\n    fn deref(&self) -> &Self::Target {\n        self.doc()\n    }\n}\n\nimpl DerefMut for TomlFile {\n    fn deref_mut(&mut self) -> &mut Self::Target {\n        self.doc_mut()\n    }\n}\n\n/// The error emitted when failing to insert into a profile.\n#[derive(Debug)]\nstruct InsertProfileError {\n    pub message: String,\n    pub value: toml_edit::Item,\n}\n\nimpl std::fmt::Display for InsertProfileError {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        f.write_str(&self.message)\n    }\n}\n\nimpl std::error::Error for InsertProfileError {}\n\nimpl TomlFile {\n    /// Insert a name as `[profile.name]`. Creating the `[profile]` table where necessary and\n    /// throwing an error if there exists a conflict\n    #[expect(clippy::result_large_err)]\n    fn insert_profile(\n        &mut self,\n        profile_str: &str,\n        value: toml_edit::Item,\n    ) -> Result<(), InsertProfileError> {\n        if !value.is_table_like() {\n            return Err(InsertProfileError {\n                message: format!(\"Expected [{profile_str}] to be a Table\"),\n                value,\n            });\n        }\n        // get or create the profile section\n        let profile_map = if let Some(map) = self.get_mut(Config::PROFILE_SECTION) {\n            map\n        } else {\n            // insert profile section at the beginning of the map\n            let mut profile_section = toml_edit::Table::new();\n            profile_section.set_position(Some(0));\n            profile_section.set_implicit(true);\n            self.insert(Config::PROFILE_SECTION, toml_edit::Item::Table(profile_section));\n            self.get_mut(Config::PROFILE_SECTION).expect(\"exists per above\")\n        };\n        // ensure the profile section is a table\n        let profile_map = if let Some(table) = profile_map.as_table_like_mut() {\n            table\n        } else {\n            return Err(InsertProfileError {\n                message: format!(\"Expected [{}] to be a Table\", Config::PROFILE_SECTION),\n                value,\n            });\n        };\n        // check the profile map for structure and existing keys\n        if let Some(profile) = profile_map.get(profile_str) {\n            if let Some(profile_table) = profile.as_table_like() {\n                if !profile_table.is_empty() {\n                    return Err(InsertProfileError {\n                        message: format!(\n                            \"[{}.{}] already exists\",\n                            Config::PROFILE_SECTION,\n                            profile_str\n                        ),\n                        value,\n                    });\n                }\n            } else {\n                return Err(InsertProfileError {\n                    message: format!(\n                        \"Expected [{}.{}] to be a Table\",\n                        Config::PROFILE_SECTION,\n                        profile_str\n                    ),\n                    value,\n                });\n            }\n        }\n        // insert the profile\n        profile_map.insert(profile_str, value);\n        Ok(())\n    }\n}\n\n/// Making sure any implicit profile `[name]` becomes `[profile.name]` for the given file and\n/// returns the implicit profiles and the result of editing them\nfn fix_toml_non_strict_profiles(\n    toml_file: &mut TomlFile,\n) -> Vec<(String, Result<(), InsertProfileError>)> {\n    let mut results = vec![];\n\n    // get any non root level keys that need to be inserted into [profile]\n    let profiles = toml_file\n        .as_table()\n        .iter()\n        .map(|(k, _)| k.to_string())\n        .filter(|k| !Config::is_standalone_section(k))\n        .collect::<Vec<_>>();\n\n    // remove each profile and insert into [profile] section\n    for profile in profiles {\n        if let Some(value) = toml_file.remove(&profile) {\n            let res = toml_file.insert_profile(&profile, value);\n            if let Err(err) = res.as_ref() {\n                toml_file.insert(&profile, err.value.clone());\n            }\n            results.push((profile, res))\n        }\n    }\n    results\n}\n\n/// Fix foundry.toml files. Making sure any implicit profile `[name]` becomes\n/// `[profile.name]`. Return any warnings\npub fn fix_tomls() -> Vec<Warning> {\n    let mut warnings = vec![];\n\n    let tomls = {\n        let mut tomls = vec![];\n        if let Some(global_toml) = Config::foundry_dir_toml().filter(|p| p.exists()) {\n            tomls.push(global_toml);\n        }\n        let local_toml = PathBuf::from(\n            Env::var(\"FOUNDRY_CONFIG\").unwrap_or_else(|| Config::FILE_NAME.to_string()),\n        );\n        if local_toml.exists() {\n            tomls.push(local_toml);\n        } else {\n            warnings.push(Warning::NoLocalToml(local_toml));\n        }\n        tomls\n    };\n\n    for toml in tomls {\n        let mut toml_file = match TomlFile::open(&toml) {\n            Ok(toml_file) => toml_file,\n            Err(err) => {\n                warnings.push(Warning::CouldNotReadToml { path: toml, err: err.to_string() });\n                continue;\n            }\n        };\n\n        let results = fix_toml_non_strict_profiles(&mut toml_file);\n        let was_edited = results.iter().any(|(_, res)| res.is_ok());\n        for (profile, err) in results\n            .into_iter()\n            .filter_map(|(profile, res)| res.err().map(|err| (profile, err.message)))\n        {\n            warnings.push(Warning::CouldNotFixProfile {\n                path: toml_file.path().into(),\n                profile,\n                err,\n            })\n        }\n\n        if was_edited && let Err(err) = toml_file.save() {\n            warnings.push(Warning::CouldNotWriteToml {\n                path: toml_file.path().into(),\n                err: err.to_string(),\n            });\n        }\n    }\n\n    warnings\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use figment::Jail;\n    use similar_asserts::assert_eq;\n\n    macro_rules! fix_test {\n        ($(#[$attr:meta])* $name:ident, $fun:expr) => {\n            #[test]\n            $(#[$attr])*\n            fn $name() {\n                Jail::expect_with(|jail| {\n                    // setup home directory,\n                    // **Note** this only has an effect on unix, as [`dirs::home_dir()`] on windows uses `FOLDERID_Profile`\n                    jail.set_env(\"HOME\", jail.directory().display().to_string());\n                    std::fs::create_dir(jail.directory().join(\".foundry\")).unwrap();\n\n                    // define function type to allow implicit params / return\n                    let f: Box<dyn FnOnce(&mut Jail) -> Result<(), figment::Error>> = Box::new($fun);\n                    f(jail)?;\n\n                    Ok(())\n                });\n            }\n        };\n    }\n\n    fix_test!(test_implicit_profile_name_changed, |jail| {\n        jail.create_file(\n            \"foundry.toml\",\n            r#\"\n                [default]\n                src = \"src\"\n                # comment\n\n                [other]\n                src = \"other-src\"\n            \"#,\n        )?;\n        fix_tomls();\n        assert_eq!(\n            fs::read_to_string(\"foundry.toml\").unwrap(),\n            r#\"\n                [profile.default]\n                src = \"src\"\n                # comment\n\n                [profile.other]\n                src = \"other-src\"\n            \"#\n        );\n        Ok(())\n    });\n\n    fix_test!(test_leave_standalone_sections_alone, |jail| {\n        jail.create_file(\n            \"foundry.toml\",\n            r#\"\n                [default]\n                src = \"src\"\n\n                [fmt]\n                line_length = 100\n\n                [rpc_endpoints]\n                optimism = \"https://example.com/\"\n            \"#,\n        )?;\n        fix_tomls();\n        assert_eq!(\n            fs::read_to_string(\"foundry.toml\").unwrap(),\n            r#\"\n                [profile.default]\n                src = \"src\"\n\n                [fmt]\n                line_length = 100\n\n                [rpc_endpoints]\n                optimism = \"https://example.com/\"\n            \"#\n        );\n        Ok(())\n    });\n\n    // mocking the `$HOME` has no effect on windows, see [`dirs::home_dir()`]\n    fix_test!(\n        #[cfg(not(windows))]\n        test_global_toml_is_edited,\n        |jail| {\n            jail.create_file(\n                \"foundry.toml\",\n                r#\"\n                [other]\n                src = \"other-src\"\n            \"#,\n            )?;\n            jail.create_file(\n                \".foundry/foundry.toml\",\n                r#\"\n                [default]\n                src = \"src\"\n            \"#,\n            )?;\n            fix_tomls();\n            assert_eq!(\n                fs::read_to_string(\"foundry.toml\").unwrap(),\n                r#\"\n                [profile.other]\n                src = \"other-src\"\n            \"#\n            );\n            assert_eq!(\n                fs::read_to_string(\".foundry/foundry.toml\").unwrap(),\n                r#\"\n                [profile.default]\n                src = \"src\"\n            \"#\n            );\n            Ok(())\n        }\n    );\n}\n"
  },
  {
    "path": "crates/config/src/fmt.rs",
    "content": "//! Configuration specific to the `forge fmt` command and the `forge_fmt` package\n\nuse serde::{Deserialize, Serialize};\n\n/// Contains the config and rule set\n#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]\npub struct FormatterConfig {\n    /// Maximum line length where formatter will try to wrap the line\n    pub line_length: usize,\n    /// Number of spaces per indentation level. Ignored if style is Tab\n    pub tab_width: usize,\n    /// Style of indent\n    pub style: IndentStyle,\n    /// Print spaces between brackets\n    pub bracket_spacing: bool,\n    /// Style of uint/int256 types\n    pub int_types: IntTypes,\n    /// Style of multiline function header in case it doesn't fit\n    pub multiline_func_header: MultilineFuncHeaderStyle,\n    /// Style of quotation marks\n    pub quote_style: QuoteStyle,\n    /// Style of underscores in number literals\n    pub number_underscore: NumberUnderscore,\n    /// Style of underscores in hex literals\n    pub hex_underscore: HexUnderscore,\n    /// Style of single line blocks in statements\n    pub single_line_statement_blocks: SingleLineBlockStyle,\n    /// Print space in state variable, function and modifier `override` attribute\n    pub override_spacing: bool,\n    /// Wrap comments on `line_length` reached\n    pub wrap_comments: bool,\n    /// Style of doc comments\n    pub docs_style: DocCommentStyle,\n    /// Globs to ignore\n    pub ignore: Vec<String>,\n    /// Add new line at start and end of contract declarations\n    pub contract_new_lines: bool,\n    /// Sort import statements alphabetically in groups (a group is separated by a newline).\n    pub sort_imports: bool,\n    /// Choose between `import \"a\" as name` and `import * as name from \"a\"`\n    pub namespace_import_style: NamespaceImportStyle,\n    /// Whether to suppress spaces around the power operator (`**`).\n    pub pow_no_space: bool,\n    /// Style that determines if a broken list, should keep its elements together on their own\n    /// line, before breaking individually.\n    pub prefer_compact: PreferCompact,\n    /// Keep single imports on a single line even if they exceed line length.\n    pub single_line_imports: bool,\n}\n\n/// Style of integer types.\n#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]\n#[serde(rename_all = \"snake_case\")]\npub enum IntTypes {\n    /// Use the type defined in the source code.\n    Preserve,\n    /// Print the full length `uint256` or `int256`.\n    #[default]\n    Long,\n    /// Print the alias `uint` or `int`.\n    Short,\n}\n\n/// Style of underscores in number literals\n#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]\n#[serde(rename_all = \"snake_case\")]\npub enum NumberUnderscore {\n    /// Use the underscores defined in the source code\n    #[default]\n    Preserve,\n    /// Remove all underscores\n    Remove,\n    /// Add an underscore every thousand, if greater than 9999\n    /// e.g. 1000 -> 1000 and 10000 -> 10_000\n    Thousands,\n}\n\nimpl NumberUnderscore {\n    /// Returns true if the option is `Preserve`\n    #[inline]\n    pub fn is_preserve(self) -> bool {\n        matches!(self, Self::Preserve)\n    }\n\n    /// Returns true if the option is `Remove`\n    #[inline]\n    pub fn is_remove(self) -> bool {\n        matches!(self, Self::Remove)\n    }\n\n    /// Returns true if the option is `Remove`\n    #[inline]\n    pub fn is_thousands(self) -> bool {\n        matches!(self, Self::Thousands)\n    }\n}\n\n/// Style of underscores in hex literals\n#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]\n#[serde(rename_all = \"snake_case\")]\npub enum HexUnderscore {\n    /// Use the underscores defined in the source code\n    Preserve,\n    /// Remove all underscores\n    #[default]\n    Remove,\n    /// Add underscore as separator between byte boundaries\n    Bytes,\n}\n\n/// Style of doc comments\n#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]\n#[serde(rename_all = \"snake_case\")]\npub enum DocCommentStyle {\n    /// Preserve the source code style\n    #[default]\n    Preserve,\n    /// Use single-line style (`///`)\n    Line,\n    /// Use block style (`/** .. */`)\n    Block,\n}\n\n/// Style of string quotes\n#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]\n#[serde(rename_all = \"snake_case\")]\npub enum QuoteStyle {\n    /// Use quotation mark defined in the source code.\n    Preserve,\n    /// Use double quotes where possible.\n    #[default]\n    Double,\n    /// Use single quotes where possible.\n    Single,\n}\n\nimpl QuoteStyle {\n    /// Returns the associated quotation mark character.\n    pub const fn quote(self) -> Option<char> {\n        match self {\n            Self::Preserve => None,\n            Self::Double => Some('\"'),\n            Self::Single => Some('\\''),\n        }\n    }\n}\n\n/// Style of single line blocks in statements\n#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]\n#[serde(rename_all = \"snake_case\")]\npub enum SingleLineBlockStyle {\n    /// Preserve the original style\n    #[default]\n    Preserve,\n    /// Prefer single line block when possible\n    Single,\n    /// Always use multiline block\n    Multi,\n}\n\n/// Style of function header in case it doesn't fit\n#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]\n#[serde(rename_all = \"snake_case\")]\npub enum MultilineFuncHeaderStyle {\n    /// Always write function parameters multiline.\n    #[serde(alias = \"params_first\")] // alias for backwards compatibility\n    ParamsAlways,\n    /// Write function parameters multiline first when there is more than one param.\n    ParamsFirstMulti,\n    /// Write function attributes multiline first.\n    #[default]\n    AttributesFirst,\n    /// If function params or attrs are multiline.\n    /// split the rest\n    All,\n    /// Same as `All` but writes function params multiline even when there is a single param.\n    AllParams,\n}\n\nimpl MultilineFuncHeaderStyle {\n    pub fn all(&self) -> bool {\n        matches!(self, Self::All | Self::AllParams)\n    }\n\n    pub fn params_first(&self) -> bool {\n        matches!(self, Self::ParamsAlways | Self::ParamsFirstMulti)\n    }\n\n    pub fn attrib_first(&self) -> bool {\n        matches!(self, Self::AttributesFirst)\n    }\n}\n\n#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]\n#[serde(rename_all = \"snake_case\")]\npub enum NamespaceImportStyle {\n    /// prefer plain imports: `import \"source\" as name;`\n    #[default]\n    PreferPlain,\n    /// prefer glob imports: `import * as name from \"source\";`\n    PreferGlob,\n    /// preserve the original style\n    Preserve,\n}\n\n/// Style that determines if a broken list, should keep its elements together on their own line,\n/// before breaking individually.\n#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]\n#[serde(rename_all = \"snake_case\")]\npub enum PreferCompact {\n    /// All elements are preferred consistent.\n    None,\n    /// Calls are preferred compact. Events and errors break consistently.\n    Calls,\n    /// Events are preferred compact. Calls and errors break consistently.\n    Events,\n    /// Errors are preferred compact. Calls and events break consistently.\n    Errors,\n    /// Events and errors are preferred compact. Calls break consistently.\n    EventsErrors,\n    /// All elements are preferred compact.\n    #[default]\n    All,\n}\n\nimpl PreferCompact {\n    pub fn calls(&self) -> bool {\n        matches!(self, Self::All | Self::Calls)\n    }\n\n    pub fn events(&self) -> bool {\n        matches!(self, Self::All | Self::Events | Self::EventsErrors)\n    }\n\n    pub fn errors(&self) -> bool {\n        matches!(self, Self::All | Self::Errors | Self::EventsErrors)\n    }\n}\n\n/// Style of indent\n#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]\n#[serde(rename_all = \"snake_case\")]\npub enum IndentStyle {\n    #[default]\n    Space,\n    Tab,\n}\n\nimpl Default for FormatterConfig {\n    fn default() -> Self {\n        Self {\n            line_length: 120,\n            tab_width: 4,\n            style: IndentStyle::Space,\n            bracket_spacing: false,\n            int_types: IntTypes::default(),\n            multiline_func_header: MultilineFuncHeaderStyle::default(),\n            quote_style: QuoteStyle::default(),\n            number_underscore: NumberUnderscore::default(),\n            hex_underscore: HexUnderscore::default(),\n            single_line_statement_blocks: SingleLineBlockStyle::default(),\n            override_spacing: false,\n            wrap_comments: false,\n            ignore: vec![],\n            contract_new_lines: false,\n            sort_imports: false,\n            namespace_import_style: NamespaceImportStyle::default(),\n            pow_no_space: false,\n            prefer_compact: PreferCompact::default(),\n            docs_style: DocCommentStyle::default(),\n            single_line_imports: false,\n        }\n    }\n}\n"
  },
  {
    "path": "crates/config/src/fs_permissions.rs",
    "content": "//! Support for controlling fs access\n\nuse serde::{Deserialize, Deserializer, Serialize, Serializer};\nuse std::{\n    fmt,\n    path::{Path, PathBuf},\n    str::FromStr,\n};\n\n/// Configures file system access\n///\n/// E.g. for cheat codes (`vm.writeFile`)\n#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]\n#[serde(transparent)]\npub struct FsPermissions {\n    /// what kind of access is allowed\n    pub permissions: Vec<PathPermission>,\n}\n\nimpl FsPermissions {\n    /// Creates anew instance with the given `permissions`\n    pub fn new(permissions: impl IntoIterator<Item = PathPermission>) -> Self {\n        Self { permissions: permissions.into_iter().collect() }\n    }\n\n    /// Adds a new permission\n    pub fn add(&mut self, permission: PathPermission) {\n        self.permissions.push(permission)\n    }\n\n    /// Returns true if access to the specified path is allowed with the specified.\n    ///\n    /// This first checks permission, and only if it is granted, whether the path is allowed.\n    ///\n    /// We only allow paths that are inside  allowed paths.\n    ///\n    /// Caution: This should be called with normalized paths if the `allowed_paths` are also\n    /// normalized.\n    pub fn is_path_allowed(&self, path: &Path, kind: FsAccessKind) -> bool {\n        self.find_permission(path).is_some_and(|perm| perm.is_granted(kind))\n    }\n\n    /// Returns the permission for the matching path.\n    ///\n    /// This finds the longest matching path with resolved sym links and returns the highest\n    /// privilege permission. The algorithm works as follows:\n    ///\n    /// 1. Find all permissions where the path matches (using longest path match)\n    /// 2. Return the highest privilege permission from those matches\n    ///\n    /// Example scenarios:\n    ///\n    /// ```text\n    /// ./out = read\n    /// ./out/contracts = read-write\n    /// ```\n    /// Checking `./out/contracts/MyContract.sol` returns `read-write` (longest path match)\n    ///\n    /// ```text\n    /// ./out/contracts = read\n    /// ./out/contracts = write\n    /// ```\n    /// Checking `./out/contracts/MyContract.sol` returns `write` (highest privilege, which also\n    /// grants read access)\n    pub fn find_permission(&self, path: &Path) -> Option<FsAccessPermission> {\n        let mut max_path_len = 0;\n        let mut highest_permission = FsAccessPermission::None;\n\n        // Find all matching permissions at the longest matching path\n        for perm in &self.permissions {\n            let permission_path = dunce::canonicalize(&perm.path).unwrap_or(perm.path.clone());\n            if path.starts_with(&permission_path) {\n                let path_len = permission_path.components().count();\n                if path_len > max_path_len {\n                    // Found a longer matching path, reset to this permission\n                    max_path_len = path_len;\n                    highest_permission = perm.access;\n                } else if path_len == max_path_len {\n                    // Same path length, keep the highest privilege\n                    highest_permission = match (highest_permission, perm.access) {\n                        (FsAccessPermission::ReadWrite, _)\n                        | (FsAccessPermission::Read, FsAccessPermission::Write)\n                        | (FsAccessPermission::Write, FsAccessPermission::Read) => {\n                            FsAccessPermission::ReadWrite\n                        }\n                        (FsAccessPermission::None, perm) => perm,\n                        (existing_perm, _) => existing_perm,\n                    }\n                }\n            }\n        }\n\n        if max_path_len > 0 { Some(highest_permission) } else { None }\n    }\n\n    /// Updates all `allowed_paths` and joins ([`Path::join`]) the `root` with all entries\n    pub fn join_all(&mut self, root: &Path) {\n        self.permissions.iter_mut().for_each(|perm| {\n            perm.path = root.join(&perm.path);\n        })\n    }\n\n    /// Same as [`Self::join_all`] but consumes the type\n    pub fn joined(mut self, root: &Path) -> Self {\n        self.join_all(root);\n        self\n    }\n\n    /// Removes all existing permissions for the given path\n    pub fn remove(&mut self, path: &Path) {\n        self.permissions.retain(|permission| permission.path != path)\n    }\n\n    /// Returns true if no permissions are configured\n    pub fn is_empty(&self) -> bool {\n        self.permissions.is_empty()\n    }\n\n    /// Returns the number of configured permissions\n    pub fn len(&self) -> usize {\n        self.permissions.len()\n    }\n}\n\n/// Represents an access permission to a single path\n#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]\npub struct PathPermission {\n    /// Permission level to access the `path`\n    pub access: FsAccessPermission,\n    /// The targeted path guarded by the permission\n    pub path: PathBuf,\n}\n\nimpl PathPermission {\n    /// Returns a new permission for the path and the given access\n    pub fn new(path: impl Into<PathBuf>, access: FsAccessPermission) -> Self {\n        Self { path: path.into(), access }\n    }\n\n    /// Returns a new read-only permission for the path\n    pub fn read(path: impl Into<PathBuf>) -> Self {\n        Self::new(path, FsAccessPermission::Read)\n    }\n\n    /// Returns a new read-write permission for the path\n    pub fn read_write(path: impl Into<PathBuf>) -> Self {\n        Self::new(path, FsAccessPermission::ReadWrite)\n    }\n\n    /// Returns a new write-only permission for the path\n    pub fn write(path: impl Into<PathBuf>) -> Self {\n        Self::new(path, FsAccessPermission::Write)\n    }\n\n    /// Returns a non permission for the path\n    pub fn none(path: impl Into<PathBuf>) -> Self {\n        Self::new(path, FsAccessPermission::None)\n    }\n\n    /// Returns true if the access is allowed\n    pub fn is_granted(&self, kind: FsAccessKind) -> bool {\n        self.access.is_granted(kind)\n    }\n}\n\n/// Represents the operation on the fs\n#[derive(Clone, Copy, Debug, PartialEq, Eq)]\npub enum FsAccessKind {\n    /// read from fs (`vm.readFile`)\n    Read,\n    /// write to fs (`vm.writeFile`)\n    Write,\n}\n\nimpl fmt::Display for FsAccessKind {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        match self {\n            Self::Read => f.write_str(\"read\"),\n            Self::Write => f.write_str(\"write\"),\n        }\n    }\n}\n\n/// Determines the status of file system access\n#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]\npub enum FsAccessPermission {\n    /// FS access is _not_ allowed\n    #[default]\n    None,\n    /// Only reading is allowed\n    Read,\n    /// Only writing is allowed\n    Write,\n    /// FS access is allowed, this includes `read` + `write`\n    ReadWrite,\n}\n\nimpl FsAccessPermission {\n    /// Returns true if the access is allowed\n    pub fn is_granted(&self, kind: FsAccessKind) -> bool {\n        match (self, kind) {\n            (Self::ReadWrite, _) => true,\n            (Self::Write, FsAccessKind::Write) => true,\n            (Self::Read, FsAccessKind::Read) => true,\n            (Self::None, _) => false,\n            _ => false,\n        }\n    }\n}\n\nimpl FromStr for FsAccessPermission {\n    type Err = String;\n\n    fn from_str(s: &str) -> Result<Self, Self::Err> {\n        match s {\n            \"true\" | \"read-write\" | \"readwrite\" => Ok(Self::ReadWrite),\n            \"false\" | \"none\" => Ok(Self::None),\n            \"read\" => Ok(Self::Read),\n            \"write\" => Ok(Self::Write),\n            _ => Err(format!(\"Unknown variant {s}\")),\n        }\n    }\n}\n\nimpl fmt::Display for FsAccessPermission {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        match self {\n            Self::ReadWrite => f.write_str(\"read-write\"),\n            Self::None => f.write_str(\"none\"),\n            Self::Read => f.write_str(\"read\"),\n            Self::Write => f.write_str(\"write\"),\n        }\n    }\n}\n\nimpl Serialize for FsAccessPermission {\n    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>\n    where\n        S: Serializer,\n    {\n        match self {\n            Self::ReadWrite => serializer.serialize_bool(true),\n            Self::None => serializer.serialize_bool(false),\n            Self::Read => serializer.serialize_str(\"read\"),\n            Self::Write => serializer.serialize_str(\"write\"),\n        }\n    }\n}\n\nimpl<'de> Deserialize<'de> for FsAccessPermission {\n    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>\n    where\n        D: Deserializer<'de>,\n    {\n        #[derive(Deserialize)]\n        #[serde(untagged)]\n        enum Status {\n            Bool(bool),\n            String(String),\n        }\n        match Status::deserialize(deserializer)? {\n            Status::Bool(enabled) => {\n                let status = if enabled { Self::ReadWrite } else { Self::None };\n                Ok(status)\n            }\n            Status::String(val) => val.parse().map_err(serde::de::Error::custom),\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn can_parse_permission() {\n        assert_eq!(FsAccessPermission::ReadWrite, \"true\".parse().unwrap());\n        assert_eq!(FsAccessPermission::ReadWrite, \"readwrite\".parse().unwrap());\n        assert_eq!(FsAccessPermission::ReadWrite, \"read-write\".parse().unwrap());\n        assert_eq!(FsAccessPermission::None, \"false\".parse().unwrap());\n        assert_eq!(FsAccessPermission::None, \"none\".parse().unwrap());\n        assert_eq!(FsAccessPermission::Read, \"read\".parse().unwrap());\n        assert_eq!(FsAccessPermission::Write, \"write\".parse().unwrap());\n    }\n\n    #[test]\n    fn nested_permissions() {\n        let permissions = FsPermissions::new(vec![\n            PathPermission::read(\"./\"),\n            PathPermission::write(\"./out\"),\n            PathPermission::read_write(\"./out/contracts\"),\n        ]);\n\n        let permission =\n            permissions.find_permission(Path::new(\"./out/contracts/MyContract.sol\")).unwrap();\n        assert_eq!(FsAccessPermission::ReadWrite, permission);\n        let permission = permissions.find_permission(Path::new(\"./out/MyContract.sol\")).unwrap();\n        assert_eq!(FsAccessPermission::Write, permission);\n    }\n\n    #[test]\n    fn read_write_permission_combination() {\n        // When multiple permissions are defined for the same path, highest privilege wins\n        let permissions = FsPermissions::new(vec![\n            PathPermission::read(\"./out/contracts\"),\n            PathPermission::write(\"./out/contracts\"),\n        ]);\n\n        let permission =\n            permissions.find_permission(Path::new(\"./out/contracts/MyContract.sol\")).unwrap();\n        assert_eq!(FsAccessPermission::ReadWrite, permission);\n    }\n\n    #[test]\n    fn longest_path_takes_precedence() {\n        let permissions = FsPermissions::new(vec![\n            PathPermission::read_write(\"./out\"),\n            PathPermission::read(\"./out/contracts\"),\n        ]);\n\n        // More specific path (./out/contracts) takes precedence even with lower privilege\n        let permission =\n            permissions.find_permission(Path::new(\"./out/contracts/MyContract.sol\")).unwrap();\n        assert_eq!(FsAccessPermission::Read, permission);\n\n        // Broader path still applies to its own files\n        let permission = permissions.find_permission(Path::new(\"./out/other.sol\")).unwrap();\n        assert_eq!(FsAccessPermission::ReadWrite, permission);\n    }\n}\n"
  },
  {
    "path": "crates/config/src/fuzz.rs",
    "content": "//! Configuration for fuzz testing.\n\nuse alloy_primitives::U256;\nuse foundry_compilers::utils::canonicalized;\nuse serde::{Deserialize, Serialize};\nuse std::path::PathBuf;\n\n/// Contains for fuzz testing\n#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]\npub struct FuzzConfig {\n    /// The number of test cases that must execute for each property test\n    pub runs: u32,\n    /// Fails the fuzzed test if a revert occurs.\n    pub fail_on_revert: bool,\n    /// The maximum number of test case rejections allowed,\n    /// encountered during usage of `vm.assume` cheatcode.\n    pub max_test_rejects: u32,\n    /// Optional seed for the fuzzing RNG algorithm\n    pub seed: Option<U256>,\n    /// The fuzz dictionary configuration\n    #[serde(flatten)]\n    pub dictionary: FuzzDictionaryConfig,\n    /// Number of runs to execute and include in the gas report.\n    pub gas_report_samples: u32,\n    /// The fuzz corpus configuration.\n    #[serde(flatten)]\n    pub corpus: FuzzCorpusConfig,\n    /// Path where fuzz failures are recorded and replayed.\n    pub failure_persist_dir: Option<PathBuf>,\n    /// show `console.log` in fuzz test, defaults to `false`\n    pub show_logs: bool,\n    /// Optional timeout (in seconds) for each property test\n    pub timeout: Option<u32>,\n}\n\nimpl Default for FuzzConfig {\n    fn default() -> Self {\n        Self {\n            runs: 256,\n            fail_on_revert: true,\n            max_test_rejects: 65536,\n            seed: None,\n            dictionary: FuzzDictionaryConfig::default(),\n            gas_report_samples: 256,\n            corpus: FuzzCorpusConfig::default(),\n            failure_persist_dir: None,\n            show_logs: false,\n            timeout: None,\n        }\n    }\n}\n\nimpl FuzzConfig {\n    /// Creates fuzz configuration to write failures in `{PROJECT_ROOT}/cache/fuzz` dir.\n    pub fn new(cache_dir: PathBuf) -> Self {\n        Self { failure_persist_dir: Some(cache_dir), ..Default::default() }\n    }\n}\n\n/// Contains for fuzz testing\n#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]\npub struct FuzzDictionaryConfig {\n    /// The weight of the dictionary\n    #[serde(deserialize_with = \"crate::deserialize_stringified_percent\")]\n    pub dictionary_weight: u32,\n    /// The flag indicating whether to include values from storage\n    pub include_storage: bool,\n    /// The flag indicating whether to include push bytes values\n    pub include_push_bytes: bool,\n    /// How many addresses to record at most.\n    /// Once the fuzzer exceeds this limit, it will start evicting random entries\n    ///\n    /// This limit is put in place to prevent memory blowup.\n    #[serde(\n        deserialize_with = \"crate::deserialize_usize_or_max\",\n        serialize_with = \"crate::serialize_usize_or_max\"\n    )]\n    pub max_fuzz_dictionary_addresses: usize,\n    /// How many values to record at most.\n    /// Once the fuzzer exceeds this limit, it will start evicting random entries\n    #[serde(\n        deserialize_with = \"crate::deserialize_usize_or_max\",\n        serialize_with = \"crate::serialize_usize_or_max\"\n    )]\n    pub max_fuzz_dictionary_values: usize,\n    /// How many literal values to seed from the AST, at most.\n    ///\n    /// This value is independent from the max amount of addresses and values.\n    #[serde(\n        deserialize_with = \"crate::deserialize_usize_or_max\",\n        serialize_with = \"crate::serialize_usize_or_max\"\n    )]\n    pub max_fuzz_dictionary_literals: usize,\n}\n\nimpl Default for FuzzDictionaryConfig {\n    fn default() -> Self {\n        const MB: usize = 1024 * 1024;\n\n        Self {\n            dictionary_weight: 40,\n            include_storage: true,\n            include_push_bytes: true,\n            max_fuzz_dictionary_addresses: 300 * MB / 20,\n            max_fuzz_dictionary_values: 300 * MB / 32,\n            max_fuzz_dictionary_literals: 200 * MB / 32,\n        }\n    }\n}\n\n#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]\npub struct FuzzCorpusConfig {\n    // Path to corpus directory, enabled coverage guided fuzzing mode.\n    // If not set then sequences producing new coverage are not persisted and mutated.\n    pub corpus_dir: Option<PathBuf>,\n    // Whether corpus to use gzip file compression and decompression.\n    pub corpus_gzip: bool,\n    // Number of mutations until entry marked as eligible to be flushed from in-memory corpus.\n    // Mutations will be performed at least `corpus_min_mutations` times.\n    pub corpus_min_mutations: usize,\n    // Number of corpus that won't be evicted from memory.\n    pub corpus_min_size: usize,\n    /// Whether to collect and display edge coverage metrics.\n    pub show_edge_coverage: bool,\n}\n\nimpl FuzzCorpusConfig {\n    pub fn with_test(&mut self, contract: &str, test: &str) {\n        if let Some(corpus_dir) = &self.corpus_dir {\n            self.corpus_dir = Some(canonicalized(corpus_dir.join(contract).join(test)));\n        }\n    }\n\n    /// Whether edge coverage should be collected and displayed.\n    pub fn collect_edge_coverage(&self) -> bool {\n        self.corpus_dir.is_some() || self.show_edge_coverage\n    }\n\n    /// Whether coverage guided fuzzing is enabled.\n    pub fn is_coverage_guided(&self) -> bool {\n        self.corpus_dir.is_some()\n    }\n}\n\nimpl Default for FuzzCorpusConfig {\n    fn default() -> Self {\n        Self {\n            corpus_dir: None,\n            corpus_gzip: true,\n            corpus_min_mutations: 5,\n            corpus_min_size: 0,\n            show_edge_coverage: false,\n        }\n    }\n}\n"
  },
  {
    "path": "crates/config/src/inline/mod.rs",
    "content": "use crate::Config;\nuse alloy_primitives::map::HashMap;\nuse figment::{\n    Figment, Profile, Provider,\n    value::{Dict, Map, Value},\n};\nuse foundry_compilers::ProjectCompileOutput;\nuse itertools::Itertools;\n\nmod natspec;\npub use natspec::*;\n\nconst INLINE_CONFIG_PREFIX: &str = \"forge-config:\";\n\ntype DataMap = Map<Profile, Dict>;\n\n/// Errors returned when parsing inline config.\n#[derive(Clone, Debug, PartialEq, Eq, thiserror::Error)]\npub enum InlineConfigErrorKind {\n    /// Failed to parse inline config as TOML.\n    #[error(transparent)]\n    Parse(#[from] toml::de::Error),\n    /// An invalid profile has been provided.\n    #[error(\"invalid profile `{0}`; valid profiles: {1}\")]\n    InvalidProfile(String, String),\n}\n\n/// Wrapper error struct that catches config parsing errors, enriching them with context information\n/// reporting the misconfigured line.\n#[derive(Debug, thiserror::Error)]\n#[error(\"Inline config error at {location}: {kind}\")]\npub struct InlineConfigError {\n    /// The span of the error in the format:\n    /// `dir/TestContract.t.sol:FuzzContract:10:12:111`\n    pub location: String,\n    /// The inner error\n    pub kind: InlineConfigErrorKind,\n}\n\n/// Represents per-test configurations, declared inline\n/// as structured comments in Solidity test files. This allows\n/// to create configs directly bound to a solidity test.\n#[derive(Clone, Debug, Default)]\npub struct InlineConfig {\n    /// Contract-level configuration.\n    contract_level: HashMap<String, DataMap>,\n    /// Function-level configuration.\n    fn_level: HashMap<(String, String), DataMap>,\n}\n\nimpl InlineConfig {\n    /// Creates a new, empty [`InlineConfig`].\n    pub fn new() -> Self {\n        Self::default()\n    }\n\n    /// Tries to create a new instance by detecting inline configurations from the project compile\n    /// output.\n    pub fn new_parsed(output: &ProjectCompileOutput, config: &Config) -> eyre::Result<Self> {\n        let natspecs: Vec<NatSpec> = NatSpec::parse(output, &config.root);\n        let profiles = &config.profiles;\n        let mut inline = Self::new();\n        for natspec in &natspecs {\n            inline.insert(natspec)?;\n            // Validate after parsing as TOML.\n            natspec.validate_profiles(profiles)?;\n        }\n        Ok(inline)\n    }\n\n    /// Inserts a new [`NatSpec`] into the [`InlineConfig`].\n    pub fn insert(&mut self, natspec: &NatSpec) -> Result<(), InlineConfigError> {\n        let map = if let Some(function) = &natspec.function {\n            self.fn_level.entry((natspec.contract.clone(), function.clone())).or_default()\n        } else {\n            self.contract_level.entry(natspec.contract.clone()).or_default()\n        };\n        let joined = natspec\n            .config_values()\n            .map(|s| {\n                // Replace `-` with `_` for backwards compatibility with the old parser.\n                if let Some(idx) = s.find('=') {\n                    s[..idx].replace('-', \"_\") + &s[idx..]\n                } else {\n                    s.to_string()\n                }\n            })\n            .format(\"\\n\")\n            .to_string();\n        let data = toml::from_str::<DataMap>(&joined).map_err(|e| InlineConfigError {\n            location: natspec.location_string(),\n            kind: InlineConfigErrorKind::Parse(e),\n        })?;\n        extend_data_map(map, &data);\n        Ok(())\n    }\n\n    /// Returns a [`figment::Provider`] for this [`InlineConfig`] at the given contract and function\n    /// level.\n    pub fn provide<'a>(&'a self, contract: &'a str, function: &'a str) -> InlineConfigProvider<'a> {\n        InlineConfigProvider { inline: self, contract, function }\n    }\n\n    /// Merges the inline configuration at the given contract and function level with the provided\n    /// base configuration.\n    pub fn merge(&self, contract: &str, function: &str, base: &Config) -> Figment {\n        Figment::from(base).merge(self.provide(contract, function))\n    }\n\n    /// Returns `true` if a configuration is present at the given contract level.\n    pub fn contains_contract(&self, contract: &str) -> bool {\n        self.get_contract(contract).is_some_and(|map| !map.is_empty())\n    }\n\n    /// Returns `true` if a configuration is present at the function level.\n    ///\n    /// Does not include contract-level configurations.\n    pub fn contains_function(&self, contract: &str, function: &str) -> bool {\n        self.get_function(contract, function).is_some_and(|map| !map.is_empty())\n    }\n\n    fn get_contract(&self, contract: &str) -> Option<&DataMap> {\n        self.contract_level.get(contract)\n    }\n\n    fn get_function(&self, contract: &str, function: &str) -> Option<&DataMap> {\n        let key = (contract.to_string(), function.to_string());\n        self.fn_level.get(&key)\n    }\n}\n\n/// [`figment::Provider`] for [`InlineConfig`] at a given contract and function level.\n///\n/// Created by [`InlineConfig::provide`].\n#[derive(Clone, Debug)]\npub struct InlineConfigProvider<'a> {\n    inline: &'a InlineConfig,\n    contract: &'a str,\n    function: &'a str,\n}\n\nimpl Provider for InlineConfigProvider<'_> {\n    fn metadata(&self) -> figment::Metadata {\n        figment::Metadata::named(\"inline config\")\n    }\n\n    fn data(&self) -> figment::Result<DataMap> {\n        let mut map = DataMap::new();\n        if let Some(new) = self.inline.get_contract(self.contract) {\n            extend_data_map(&mut map, new);\n        }\n        if let Some(new) = self.inline.get_function(self.contract, self.function) {\n            extend_data_map(&mut map, new);\n        }\n        Ok(map)\n    }\n}\n\nfn extend_data_map(map: &mut DataMap, new: &DataMap) {\n    for (profile, data) in new {\n        extend_dict(map.entry(profile.clone()).or_default(), data);\n    }\n}\n\nfn extend_dict(dict: &mut Dict, new: &Dict) {\n    for (k, v) in new {\n        match dict.entry(k.clone()) {\n            std::collections::btree_map::Entry::Vacant(entry) => {\n                entry.insert(v.clone());\n            }\n            std::collections::btree_map::Entry::Occupied(entry) => {\n                extend_value(entry.into_mut(), v);\n            }\n        }\n    }\n}\n\nfn extend_value(value: &mut Value, new: &Value) {\n    match (value, new) {\n        (Value::Dict(tag, dict), Value::Dict(new_tag, new_dict)) => {\n            *tag = *new_tag;\n            extend_dict(dict, new_dict);\n        }\n        (value, new) => *value = new.clone(),\n    }\n}\n"
  },
  {
    "path": "crates/config/src/inline/natspec.rs",
    "content": "use super::{INLINE_CONFIG_PREFIX, InlineConfigError, InlineConfigErrorKind};\nuse figment::Profile;\nuse foundry_compilers::{\n    ProjectCompileOutput,\n    artifacts::{Node, ast::NodeType},\n};\nuse itertools::Itertools;\nuse serde_json::Value;\nuse solar::{\n    ast::{self, Span},\n    interface::Session,\n};\nuse std::{collections::BTreeMap, path::Path};\n\n/// Convenient struct to hold in-line per-test configurations\n#[derive(Clone, Debug, PartialEq, Eq)]\npub struct NatSpec {\n    /// The parent contract of the natspec.\n    pub contract: String,\n    /// The function annotated with the natspec. None if the natspec is contract-level.\n    pub function: Option<String>,\n    /// The line the natspec begins, in the form `line:column`, i.e. `10:21`.\n    pub line: String,\n    /// The actual natspec comment, without slashes or block punctuation.\n    pub docs: String,\n}\n\nimpl NatSpec {\n    /// Factory function that extracts a vector of [`NatSpec`] instances from\n    /// a solc compiler output. The root path is to express contract base dirs.\n    /// That is essential to match per-test configs at runtime.\n    #[instrument(name = \"NatSpec::parse\", skip_all)]\n    pub fn parse(output: &ProjectCompileOutput, root: &Path) -> Vec<Self> {\n        let mut natspecs: Vec<Self> = vec![];\n\n        let compiler = output.parser().solc().compiler();\n        let solar = SolarParser::new(compiler.sess());\n        let solc = SolcParser::new();\n        for (id, artifact) in output.artifact_ids() {\n            let path = id.source.as_path();\n            let path = path.strip_prefix(root).unwrap_or(path);\n            let abs_path = &*root.join(path);\n            let contract_name = id.name.split('.').next().unwrap();\n            // `id.identifier` but with the stripped path.\n            let contract = format!(\"{}:{}\", path.display(), id.name);\n\n            let mut used_solar = false;\n            compiler.enter_sequential(|compiler| {\n                if let Some((_, source)) = compiler.gcx().get_ast_source(abs_path)\n                    && let Some(ast) = &source.ast\n                {\n                    solar.parse_ast(&mut natspecs, ast, &contract, contract_name);\n                    used_solar = true;\n                }\n            });\n\n            if !used_solar {\n                warn!(?abs_path, %contract, \"could not parse natspec with solar\");\n            }\n\n            let mut used_solc = false;\n            if !used_solar\n                && let Some(ast) = &artifact.ast\n                && let Some(node) = solc.contract_root_node(&ast.nodes, &contract)\n            {\n                solc.parse(&mut natspecs, &contract, node, true);\n                used_solc = true;\n            }\n\n            if !used_solar && !used_solc {\n                warn!(?abs_path, %contract, \"could not parse natspec\");\n            }\n        }\n\n        natspecs\n    }\n\n    /// Checks if all configuration lines use a valid profile.\n    ///\n    /// i.e. Given available profiles\n    /// ```rust\n    /// let _profiles = vec![\"ci\", \"default\"];\n    /// ```\n    /// A configuration like `forge-config: ciii.invariant.depth = 1` would result\n    /// in an error.\n    pub fn validate_profiles(&self, profiles: &[Profile]) -> eyre::Result<()> {\n        for config in self.config_values() {\n            if !profiles.iter().any(|p| {\n                config\n                    .strip_prefix(p.as_str().as_str())\n                    .is_some_and(|rest| rest.trim_start().starts_with('.'))\n            }) {\n                Err(InlineConfigError {\n                    location: self.location_string(),\n                    kind: InlineConfigErrorKind::InvalidProfile(\n                        config.to_string(),\n                        profiles.iter().format(\", \").to_string(),\n                    ),\n                })?\n            }\n        }\n        Ok(())\n    }\n\n    /// Returns the path of the contract.\n    pub fn path(&self) -> &str {\n        match self.contract.split_once(':') {\n            Some((path, _)) => path,\n            None => self.contract.as_str(),\n        }\n    }\n\n    /// Returns the location of the natspec as a string.\n    pub fn location_string(&self) -> String {\n        format!(\"{}:{}\", self.path(), self.line)\n    }\n\n    /// Returns a list of all the configuration values available in the natspec.\n    pub fn config_values(&self) -> impl Iterator<Item = &str> {\n        self.docs.lines().filter_map(|line| {\n            line.find(INLINE_CONFIG_PREFIX)\n                .map(|idx| line[idx + INLINE_CONFIG_PREFIX.len()..].trim())\n        })\n    }\n}\n\nstruct SolcParser {\n    _private: (),\n}\n\nimpl SolcParser {\n    fn new() -> Self {\n        Self { _private: () }\n    }\n\n    /// Given a list of nodes, find a \"ContractDefinition\" node that matches\n    /// the provided contract_id.\n    fn contract_root_node<'a>(&self, nodes: &'a [Node], contract_id: &str) -> Option<&'a Node> {\n        for n in nodes {\n            if n.node_type == NodeType::ContractDefinition {\n                let contract_data = &n.other;\n                if let Value::String(contract_name) = contract_data.get(\"name\")?\n                    && contract_id.ends_with(contract_name)\n                {\n                    return Some(n);\n                }\n            }\n        }\n        None\n    }\n\n    /// Implements a DFS over a compiler output node and its children.\n    /// If a natspec is found it is added to `natspecs`\n    fn parse(&self, natspecs: &mut Vec<NatSpec>, contract: &str, node: &Node, root: bool) {\n        // If we're at the root contract definition node, try parsing contract-level natspec\n        if root && let Some((docs, line)) = self.get_node_docs(&node.other) {\n            natspecs.push(NatSpec { contract: contract.into(), function: None, docs, line })\n        }\n        for n in &node.nodes {\n            if let Some((function, docs, line)) = self.get_fn_data(n) {\n                natspecs.push(NatSpec {\n                    contract: contract.into(),\n                    function: Some(function),\n                    line,\n                    docs,\n                })\n            }\n            self.parse(natspecs, contract, n, false);\n        }\n    }\n\n    /// Given a compilation output node, if it is a function definition\n    /// that also contains a natspec then return a tuple of:\n    /// - Function name\n    /// - Natspec text\n    /// - Natspec position with format \"row:col:length\"\n    ///\n    /// Return None otherwise.\n    fn get_fn_data(&self, node: &Node) -> Option<(String, String, String)> {\n        if node.node_type == NodeType::FunctionDefinition {\n            let fn_data = &node.other;\n            let fn_name: String = self.get_fn_name(fn_data)?;\n            let (fn_docs, docs_src_line) = self.get_node_docs(fn_data)?;\n            return Some((fn_name, fn_docs, docs_src_line));\n        }\n\n        None\n    }\n\n    /// Given a dictionary of function data returns the name of the function.\n    fn get_fn_name(&self, fn_data: &BTreeMap<String, Value>) -> Option<String> {\n        match fn_data.get(\"name\")? {\n            Value::String(fn_name) => Some(fn_name.into()),\n            _ => None,\n        }\n    }\n\n    /// Inspects Solc compiler output for documentation comments. Returns:\n    /// - `Some((String, String))` in case the function has natspec comments. First item is a\n    ///   textual natspec representation, the second item is the natspec src line, in the form\n    ///   \"raw:col:length\".\n    /// - `None` in case the function has not natspec comments.\n    fn get_node_docs(&self, data: &BTreeMap<String, Value>) -> Option<(String, String)> {\n        if let Value::Object(fn_docs) = data.get(\"documentation\")?\n            && let Value::String(comment) = fn_docs.get(\"text\")?\n            && comment.contains(INLINE_CONFIG_PREFIX)\n        {\n            let mut src_line = fn_docs\n                .get(\"src\")\n                .map(|src| src.to_string())\n                .unwrap_or_else(|| String::from(\"<no-src-line-available>\"));\n\n            src_line.retain(|c| c != '\"');\n            return Some((comment.into(), src_line));\n        }\n        None\n    }\n}\n\nstruct SolarParser<'a> {\n    sess: &'a Session,\n}\n\nimpl<'a> SolarParser<'a> {\n    fn new(sess: &'a Session) -> Self {\n        Self { sess }\n    }\n\n    fn parse_ast(\n        &self,\n        natspecs: &mut Vec<NatSpec>,\n        source_unit: &ast::SourceUnit<'_>,\n        contract_id: &str,\n        contract_name: &str,\n    ) {\n        let mut handle_docs = |item: &ast::Item<'_>| {\n            if item.docs.is_empty() {\n                return;\n            }\n            let mut span = Span::DUMMY;\n            let lines = item\n                .docs\n                .iter()\n                .filter_map(|d| {\n                    let s = d.symbol.as_str();\n                    if !s.contains(INLINE_CONFIG_PREFIX) {\n                        return None;\n                    }\n                    span = if span.is_dummy() { d.span } else { span.to(d.span) };\n                    match d.kind {\n                        ast::CommentKind::Line => Some(s.trim().to_string()),\n                        ast::CommentKind::Block => Some(\n                            s.lines()\n                                .filter(|line| line.contains(INLINE_CONFIG_PREFIX))\n                                .map(|line| line.trim_start().trim_start_matches('*').trim())\n                                .collect::<Vec<_>>()\n                                .join(\"\\n\"),\n                        ),\n                    }\n                })\n                .join(\"\\n\");\n            if lines.is_empty() {\n                return;\n            }\n            natspecs.push(NatSpec {\n                contract: contract_id.to_string(),\n                function: if let ast::ItemKind::Function(f) = &item.kind {\n                    Some(\n                        f.header\n                            .name\n                            .map(|sym| sym.to_string())\n                            .unwrap_or_else(|| f.kind.to_string()),\n                    )\n                } else {\n                    None\n                },\n                line: {\n                    let (_, loc) = self.sess.source_map().span_to_location_info(span);\n                    format!(\"{}:{}\", loc.lo.line, loc.lo.col.0 + 1)\n                },\n                docs: lines,\n            });\n        };\n\n        for item in source_unit.items.iter() {\n            let ast::ItemKind::Contract(c) = &item.kind else { continue };\n            if c.name.as_str() != contract_name {\n                continue;\n            }\n\n            // Handle contract level doc comments.\n            handle_docs(item);\n\n            // Handle function level doc comments.\n            for item in c.body.iter() {\n                let ast::ItemKind::Function(_) = &item.kind else { continue };\n                handle_docs(item);\n            }\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use serde_json::json;\n    use snapbox::{assert_data_eq, str};\n    use solar::parse::{\n        Parser,\n        ast::{Arena, interface},\n    };\n\n    fn parse(natspecs: &mut Vec<NatSpec>, src: &str, contract_id: &str, contract_name: &str) {\n        // Fast path to avoid parsing the file.\n        if !src.contains(INLINE_CONFIG_PREFIX) {\n            return;\n        }\n\n        let sess = Session::builder()\n            .with_silent_emitter(Some(\"Inline config parsing failed\".to_string()))\n            .build();\n        let solar = SolarParser::new(&sess);\n        let _ = sess.enter(|| -> interface::Result<()> {\n            let arena = Arena::new();\n\n            let mut parser = Parser::from_source_code(\n                &sess,\n                &arena,\n                interface::source_map::FileName::Custom(contract_id.to_string()),\n                src.to_string(),\n            )?;\n\n            let source_unit = parser.parse_file().map_err(|e| e.emit())?;\n\n            solar.parse_ast(natspecs, &source_unit, contract_id, contract_name);\n\n            Ok(())\n        });\n    }\n\n    #[test]\n    fn can_reject_invalid_profiles() {\n        let profiles = [\"ci\".into(), \"default\".into()];\n        let natspec = NatSpec {\n            contract: Default::default(),\n            function: Default::default(),\n            line: Default::default(),\n            docs: r\"\n            forge-config: ciii.invariant.depth = 1\n            forge-config: default.invariant.depth = 1\n            \"\n            .into(),\n        };\n\n        let result = natspec.validate_profiles(&profiles);\n        assert!(result.is_err());\n    }\n\n    #[test]\n    fn can_accept_valid_profiles() {\n        let profiles = [\"ci\".into(), \"default\".into()];\n        let natspec = NatSpec {\n            contract: Default::default(),\n            function: Default::default(),\n            line: Default::default(),\n            docs: r\"\n            forge-config: ci.invariant.depth = 1\n            forge-config: default.invariant.depth = 1\n            \"\n            .into(),\n        };\n\n        let result = natspec.validate_profiles(&profiles);\n        assert!(result.is_ok());\n    }\n\n    #[test]\n    fn parse_solar() {\n        let src = \"\ncontract C { /// forge-config: default.fuzz.runs = 600\n\n\\t\\t\\t\\t                                /// forge-config: default.fuzz.runs = 601\n\n    function f1() {}\n       /** forge-config: default.fuzz.runs = 700 */\nfunction f2() {} /** forge-config: default.fuzz.runs = 800 */ function f3() {}\n\n/**\n * forge-config: default.fuzz.runs = 1024\n * forge-config: default.fuzz.max-test-rejects = 500\n */\n    function f4() {}\n}\n\";\n        let mut natspecs = vec![];\n        parse(&mut natspecs, src, \"path.sol:C\", \"C\");\n        assert_data_eq!(\n            format!(\"{natspecs:#?}\"),\n            str![[r#\"\n[\n    NatSpec {\n        contract: \"path.sol:C\",\n        function: Some(\n            \"f1\",\n        ),\n        line: \"2:14\",\n        docs: \"forge-config: default.fuzz.runs = 600/nforge-config: default.fuzz.runs = 601\",\n    },\n    NatSpec {\n        contract: \"path.sol:C\",\n        function: Some(\n            \"f2\",\n        ),\n        line: \"7:8\",\n        docs: \"forge-config: default.fuzz.runs = 700\",\n    },\n    NatSpec {\n        contract: \"path.sol:C\",\n        function: Some(\n            \"f3\",\n        ),\n        line: \"8:18\",\n        docs: \"forge-config: default.fuzz.runs = 800\",\n    },\n    NatSpec {\n        contract: \"path.sol:C\",\n        function: Some(\n            \"f4\",\n        ),\n        line: \"10:1\",\n        docs: \"forge-config: default.fuzz.runs = 1024/nforge-config: default.fuzz.max-test-rejects = 500\",\n    },\n]\n\"#]]\n        );\n    }\n\n    #[test]\n    fn parse_solar_2() {\n        let src = r#\"\n// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity >=0.8.0;\n\nimport \"ds-test/test.sol\";\n\ncontract FuzzInlineConf is DSTest {\n    /**\n     * forge-config: default.fuzz.runs = 1024\n     * forge-config: default.fuzz.max-test-rejects = 500\n     */\n    function testInlineConfFuzz(uint8 x) public {\n        require(true, \"this is not going to revert\");\n    }\n}\n        \"#;\n        let mut natspecs = vec![];\n        parse(&mut natspecs, src, \"inline/FuzzInlineConf.t.sol:FuzzInlineConf\", \"FuzzInlineConf\");\n        assert_data_eq!(\n            format!(\"{natspecs:#?}\"),\n            str![[r#\"\n[\n    NatSpec {\n        contract: \"inline/FuzzInlineConf.t.sol:FuzzInlineConf\",\n        function: Some(\n            \"testInlineConfFuzz\",\n        ),\n        line: \"8:5\",\n        docs: \"forge-config: default.fuzz.runs = 1024/nforge-config: default.fuzz.max-test-rejects = 500\",\n    },\n]\n\"#]]\n        );\n    }\n\n    #[test]\n    fn config_lines() {\n        let natspec = natspec();\n        let config_lines = natspec.config_values();\n        assert_eq!(\n            config_lines.collect::<Vec<_>>(),\n            [\n                \"default.fuzz.runs = 600\".to_string(),\n                \"ci.fuzz.runs = 500\".to_string(),\n                \"default.invariant.runs = 1\".to_string()\n            ]\n        )\n    }\n\n    #[test]\n    fn can_handle_unavailable_src_line_with_fallback() {\n        let mut fn_data: BTreeMap<String, Value> = BTreeMap::new();\n        let doc_without_src_field = json!({ \"text\":  \"forge-config:default.fuzz.runs=600\" });\n        fn_data.insert(\"documentation\".into(), doc_without_src_field);\n        let (_, src_line) = SolcParser::new().get_node_docs(&fn_data).expect(\"Some docs\");\n        assert_eq!(src_line, \"<no-src-line-available>\".to_string());\n    }\n\n    #[test]\n    fn can_handle_available_src_line() {\n        let mut fn_data: BTreeMap<String, Value> = BTreeMap::new();\n        let doc_without_src_field =\n            json!({ \"text\":  \"forge-config:default.fuzz.runs=600\", \"src\": \"73:21:12\" });\n        fn_data.insert(\"documentation\".into(), doc_without_src_field);\n        let (_, src_line) = SolcParser::new().get_node_docs(&fn_data).expect(\"Some docs\");\n        assert_eq!(src_line, \"73:21:12\".to_string());\n    }\n\n    fn natspec() -> NatSpec {\n        let conf = r\"\n        forge-config: default.fuzz.runs = 600\n        forge-config: ci.fuzz.runs = 500\n        ========= SOME NOISY TEXT =============\n         䩹𧀫Jx닧Ʀ̳盅K擷􅟽Ɂw첊}ꏻk86ᖪk-檻ܴ렝[ǲ𐤬oᘓƤ\n        ꣖ۻ%Ƅ㪕ς:(饁΍av/烲ڻ̛߉橞㗡𥺃̹M봓䀖ؿ̄󵼁)𯖛d􂽰񮍃\n        ϊ&»ϿЏ񊈞2򕄬񠪁鞷砕eߥH󶑶J粊񁼯머?槿ᴴጅ𙏑ϖ뀓򨙺򷃅Ӽ츙4󍔹\n        醤㭊r􎜕󷾸𶚏 ܖ̹灱녗V*竅􋹲⒪苏贗񾦼=숽ؓ򗋲бݧ󫥛𛲍ʹ園Ьi\n        =======================================\n        forge-config: default.invariant.runs = 1\n        \";\n\n        NatSpec {\n            contract: \"dir/TestContract.t.sol:FuzzContract\".to_string(),\n            function: Some(\"test_myFunction\".to_string()),\n            line: \"10:12:111\".to_string(),\n            docs: conf.to_string(),\n        }\n    }\n\n    #[test]\n    fn parse_solar_multiple_contracts_from_same_file() {\n        let src = r#\"\n// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity >=0.8.0;\n\nimport \"ds-test/test.sol\";\n\ncontract FuzzInlineConf is DSTest {\n     /// forge-config: default.fuzz.runs = 1\n    function testInlineConfFuzz1() {}\n}\n\ncontract FuzzInlineConf2 is DSTest {\n    /// forge-config: default.fuzz.runs = 2\n    function testInlineConfFuzz2() {}\n}\n        \"#;\n        let mut natspecs = vec![];\n        parse(&mut natspecs, src, \"inline/FuzzInlineConf.t.sol:FuzzInlineConf\", \"FuzzInlineConf\");\n        assert_data_eq!(\n            format!(\"{natspecs:#?}\"),\n            str![[r#\"\n[\n    NatSpec {\n        contract: \"inline/FuzzInlineConf.t.sol:FuzzInlineConf\",\n        function: Some(\n            \"testInlineConfFuzz1\",\n        ),\n        line: \"8:6\",\n        docs: \"forge-config: default.fuzz.runs = 1\",\n    },\n]\n\"#]]\n        );\n\n        let mut natspecs = vec![];\n        parse(\n            &mut natspecs,\n            src,\n            \"inline/FuzzInlineConf2.t.sol:FuzzInlineConf2\",\n            \"FuzzInlineConf2\",\n        );\n        assert_data_eq!(\n            format!(\"{natspecs:#?}\"),\n            str![[r#\"\n[\n    NatSpec {\n        contract: \"inline/FuzzInlineConf2.t.sol:FuzzInlineConf2\",\n        function: Some(\n            \"testInlineConfFuzz2\",\n        ),\n        line: \"13:5\",\n        docs: \"forge-config: default.fuzz.runs = 2\",\n    },\n]\n\"#]]\n        );\n    }\n\n    #[test]\n    fn parse_contract_level_config() {\n        let src = r#\"\n// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity >=0.8.0;\n\nimport \"ds-test/test.sol\";\n\n/// forge-config: default.fuzz.runs = 1\ncontract FuzzInlineConf is DSTest {\n    /// forge-config: default.fuzz.runs = 3\n    function testInlineConfFuzz1() {}\n\n    function testInlineConfFuzz2() {}\n}\"#;\n        let mut natspecs = vec![];\n        parse(&mut natspecs, src, \"inline/FuzzInlineConf.t.sol:FuzzInlineConf\", \"FuzzInlineConf\");\n        assert_data_eq!(\n            format!(\"{natspecs:#?}\"),\n            str![[r#\"\n[\n    NatSpec {\n        contract: \"inline/FuzzInlineConf.t.sol:FuzzInlineConf\",\n        function: None,\n        line: \"7:1\",\n        docs: \"forge-config: default.fuzz.runs = 1\",\n    },\n    NatSpec {\n        contract: \"inline/FuzzInlineConf.t.sol:FuzzInlineConf\",\n        function: Some(\n            \"testInlineConfFuzz1\",\n        ),\n        line: \"9:5\",\n        docs: \"forge-config: default.fuzz.runs = 3\",\n    },\n]\n\"#]]\n        );\n    }\n}\n"
  },
  {
    "path": "crates/config/src/invariant.rs",
    "content": "//! Configuration for invariant testing\n\nuse crate::fuzz::{FuzzCorpusConfig, FuzzDictionaryConfig};\nuse serde::{Deserialize, Serialize};\nuse std::path::PathBuf;\n\n/// Contains for invariant testing\n#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]\npub struct InvariantConfig {\n    /// The number of runs that must execute for each invariant test group.\n    pub runs: u32,\n    /// The number of calls executed to attempt to break invariants in one run.\n    pub depth: u32,\n    /// Fails the invariant fuzzing if a revert occurs\n    pub fail_on_revert: bool,\n    /// Allows overriding an unsafe external call when running invariant tests. eg. reentrancy\n    /// checks\n    pub call_override: bool,\n    /// The fuzz dictionary configuration\n    #[serde(flatten)]\n    pub dictionary: FuzzDictionaryConfig,\n    /// The maximum number of attempts to shrink the sequence\n    pub shrink_run_limit: u32,\n    /// The maximum number of rejects via `vm.assume` which can be encountered during a single\n    /// invariant run.\n    pub max_assume_rejects: u32,\n    /// Number of runs to execute and include in the gas report.\n    pub gas_report_samples: u32,\n    /// The fuzz corpus configuration.\n    #[serde(flatten)]\n    pub corpus: FuzzCorpusConfig,\n    /// Path where invariant failures are recorded and replayed.\n    pub failure_persist_dir: Option<PathBuf>,\n    /// Whether to collect and display fuzzed selectors metrics.\n    pub show_metrics: bool,\n    /// Optional timeout (in seconds) for each invariant test.\n    pub timeout: Option<u32>,\n    /// Display counterexample as solidity calls.\n    pub show_solidity: bool,\n    /// Maximum time (in seconds) between generated txs.\n    pub max_time_delay: Option<u32>,\n    /// Maximum number of blocks elapsed between generated txs.\n    pub max_block_delay: Option<u32>,\n    /// Number of calls to execute between invariant assertions.\n    ///\n    /// - `0`: Only assert on the last call of each run (fastest, but may miss exact breaking call)\n    /// - `1` (default): Assert after every call (current behavior, most precise)\n    /// - `N`: Assert every N calls AND always on the last call\n    ///\n    /// Example: `check_interval = 10` means assert after calls 10, 20, 30, ... and the last call.\n    pub check_interval: u32,\n}\n\nimpl Default for InvariantConfig {\n    fn default() -> Self {\n        Self {\n            runs: 256,\n            depth: 500,\n            fail_on_revert: false,\n            call_override: false,\n            dictionary: FuzzDictionaryConfig { dictionary_weight: 80, ..Default::default() },\n            shrink_run_limit: 5000,\n            max_assume_rejects: 65536,\n            gas_report_samples: 256,\n            corpus: FuzzCorpusConfig::default(),\n            failure_persist_dir: None,\n            show_metrics: true,\n            timeout: None,\n            show_solidity: false,\n            max_time_delay: None,\n            max_block_delay: None,\n            check_interval: 1,\n        }\n    }\n}\n\nimpl InvariantConfig {\n    /// Creates invariant configuration to write failures in `{PROJECT_ROOT}/cache/fuzz` dir.\n    pub fn new(cache_dir: PathBuf) -> Self {\n        Self { failure_persist_dir: Some(cache_dir), ..Default::default() }\n    }\n}\n"
  },
  {
    "path": "crates/config/src/lib.rs",
    "content": "//! # foundry-config\n//!\n//! Foundry configuration.\n\n#![cfg_attr(not(test), warn(unused_crate_dependencies))]\n#![cfg_attr(docsrs, feature(doc_cfg))]\n\n#[macro_use]\nextern crate tracing;\n\nuse crate::cache::StorageCachingConfig;\nuse alloy_primitives::{Address, B256, FixedBytes, U256, address, map::AddressHashMap};\nuse eyre::{ContextCompat, WrapErr};\nuse figment::{\n    Error, Figment, Metadata, Profile, Provider,\n    providers::{Env, Format, Serialized, Toml},\n    value::{Dict, Map, Value},\n};\nuse filter::GlobMatcher;\nuse foundry_compilers::{\n    ArtifactOutput, ConfigurableArtifacts, Graph, Project, ProjectPathsConfig,\n    RestrictionsWithVersion, VyperLanguage,\n    artifacts::{\n        BytecodeHash, DebuggingSettings, EvmVersion, Libraries, ModelCheckerSettings,\n        ModelCheckerTarget, Optimizer, OptimizerDetails, RevertStrings, Settings, SettingsMetadata,\n        Severity,\n        output_selection::{ContractOutputSelection, OutputSelection},\n        remappings::{RelativeRemapping, Remapping},\n        serde_helpers,\n    },\n    cache::SOLIDITY_FILES_CACHE_FILENAME,\n    compilers::{\n        Compiler,\n        multi::{MultiCompiler, MultiCompilerSettings},\n        solc::{Solc, SolcCompiler},\n        vyper::{Vyper, VyperSettings},\n    },\n    error::SolcError,\n    multi::{MultiCompilerParser, MultiCompilerRestrictions},\n    solc::{CliSettings, SolcLanguage, SolcSettings},\n};\nuse regex::Regex;\nuse revm::primitives::hardfork::SpecId;\nuse semver::Version;\nuse serde::{Deserialize, Deserializer, Serialize, Serializer, de};\nuse std::{\n    borrow::Cow,\n    collections::BTreeMap,\n    fs,\n    path::{Path, PathBuf},\n    str::FromStr,\n};\n\nmod macros;\n\npub mod utils;\npub use utils::*;\n\nmod endpoints;\npub use endpoints::{\n    ResolvedRpcEndpoint, ResolvedRpcEndpoints, RpcEndpoint, RpcEndpointUrl, RpcEndpoints,\n};\n\nmod etherscan;\npub use etherscan::EtherscanConfigError;\nuse etherscan::{EtherscanConfigs, EtherscanEnvProvider, ResolvedEtherscanConfig};\n\npub mod resolve;\npub use resolve::UnresolvedEnvVarError;\n\npub mod cache;\nuse cache::{Cache, ChainCache};\n\npub mod fmt;\npub use fmt::FormatterConfig;\n\npub mod lint;\npub use lint::{LinterConfig, Severity as LintSeverity};\n\npub mod fs_permissions;\npub use fs_permissions::FsPermissions;\nuse fs_permissions::PathPermission;\n\npub mod error;\nuse error::ExtractConfigError;\npub use error::SolidityErrorCode;\n\npub mod doc;\npub use doc::DocConfig;\n\npub mod filter;\npub use filter::SkipBuildFilters;\n\nmod warning;\npub use warning::*;\n\npub mod fix;\n\n// reexport so cli types can implement `figment::Provider` to easily merge compiler arguments\npub use alloy_chains::{Chain, NamedChain};\npub use figment;\n\npub mod providers;\npub use providers::Remappings;\nuse providers::*;\n\nmod fuzz;\npub use fuzz::{FuzzConfig, FuzzCorpusConfig, FuzzDictionaryConfig};\n\nmod invariant;\npub use invariant::InvariantConfig;\n\nmod inline;\npub use inline::{InlineConfig, InlineConfigError, NatSpec};\n\npub mod soldeer;\nuse soldeer::{SoldeerConfig, SoldeerDependencyConfig};\n\nmod vyper;\npub use vyper::VyperConfig;\n\nmod bind_json;\nuse bind_json::BindJsonConfig;\n\nmod compilation;\npub use compilation::{CompilationRestrictions, SettingsOverrides};\n\npub mod extend;\nuse extend::Extends;\n\nuse foundry_evm_networks::NetworkConfigs;\npub use semver;\n\n/// Foundry configuration\n///\n/// # Defaults\n///\n/// All configuration values have a default, documented in the [fields](#fields)\n/// section below. [`Config::default()`] returns the default values for\n/// the default profile while [`Config::with_root()`] returns the values based on the given\n/// directory. [`Config::load()`] starts with the default profile and merges various providers into\n/// the config, same for [`Config::load_with_root()`], but there the default values are determined\n/// by [`Config::with_root()`]\n///\n/// # Provider Details\n///\n/// `Config` is a Figment [`Provider`] with the following characteristics:\n///\n///   * **Profile**\n///\n///     The profile is set to the value of the `profile` field.\n///\n///   * **Metadata**\n///\n///     This provider is named `Foundry Config`. It does not specify a\n///     [`Source`](figment::Source) and uses default interpolation.\n///\n///   * **Data**\n///\n///     The data emitted by this provider are the keys and values corresponding\n///     to the fields and values of the structure. The dictionary is emitted to\n///     the \"default\" meta-profile.\n///\n/// Note that these behaviors differ from those of [`Config::figment()`].\n#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]\npub struct Config {\n    /// The selected profile. **(default: _default_ `default`)**\n    ///\n    /// **Note:** This field is never serialized nor deserialized. When a\n    /// `Config` is merged into a `Figment` as a `Provider`, this profile is\n    /// selected on the `Figment`. When a `Config` is extracted, this field is\n    /// set to the extracting Figment's selected `Profile`.\n    #[serde(skip)]\n    pub profile: Profile,\n    /// The list of all profiles defined in the config.\n    ///\n    /// See `profile`.\n    #[serde(skip)]\n    pub profiles: Vec<Profile>,\n\n    /// The root path where the config detection started from, [`Config::with_root`].\n    // We're skipping serialization here, so it won't be included in the [`Config::to_string()`]\n    // representation, but will be deserialized from the `Figment` so that forge commands can\n    // override it.\n    #[serde(default = \"root_default\", skip_serializing)]\n    pub root: PathBuf,\n\n    /// Configuration for extending from another foundry.toml (base) file.\n    ///\n    /// Can be either a string path or an object with path and strategy.\n    /// Base files cannot extend (inherit) other files.\n    #[serde(default, skip_serializing)]\n    pub extends: Option<Extends>,\n\n    /// Path of the sources directory.\n    ///\n    /// Defaults to `src`.\n    pub src: PathBuf,\n    /// Path of the tests directory.\n    pub test: PathBuf,\n    /// Path of the scripts directory.\n    pub script: PathBuf,\n    /// Path to the artifacts directory.\n    pub out: PathBuf,\n    /// Paths to all library folders, such as `lib`, or `node_modules`.\n    pub libs: Vec<PathBuf>,\n    /// Remappings to use for this repo\n    pub remappings: Vec<RelativeRemapping>,\n    /// Whether to autodetect remappings.\n    pub auto_detect_remappings: bool,\n    /// Library addresses to link.\n    pub libraries: Vec<String>,\n    /// Whether to enable the build cache.\n    pub cache: bool,\n    /// The path to the cache store.\n    pub cache_path: PathBuf,\n    /// Whether to dynamically link tests.\n    pub dynamic_test_linking: bool,\n    /// Where the gas snapshots are stored.\n    pub snapshots: PathBuf,\n    /// Whether to check for differences against previously stored gas snapshots.\n    pub gas_snapshot_check: bool,\n    /// Whether to emit gas snapshots to disk.\n    pub gas_snapshot_emit: bool,\n    /// The path to store broadcast logs at.\n    pub broadcast: PathBuf,\n    /// Additional paths passed to `solc --allow-paths`.\n    pub allow_paths: Vec<PathBuf>,\n    /// Additional paths passed to `solc --include-path`.\n    pub include_paths: Vec<PathBuf>,\n    /// Glob patterns for file paths to skip when building and executing contracts.\n    pub skip: Vec<GlobMatcher>,\n    /// Whether to forcefully clean all project artifacts before running commands.\n    pub force: bool,\n    /// The EVM version to use when building contracts.\n    #[serde(with = \"from_str_lowercase\")]\n    pub evm_version: EvmVersion,\n    /// List of contracts to generate gas reports for.\n    pub gas_reports: Vec<String>,\n    /// List of contracts to ignore for gas reports.\n    pub gas_reports_ignore: Vec<String>,\n    /// Whether to include gas reports for tests.\n    pub gas_reports_include_tests: bool,\n    /// The Solc instance to use if any.\n    ///\n    /// This takes precedence over `auto_detect_solc`, if a version is set then this overrides\n    /// auto-detection.\n    ///\n    /// **Note** for backwards compatibility reasons this also accepts solc_version from the toml\n    /// file, see `BackwardsCompatTomlProvider`.\n    ///\n    /// Avoid using this field directly; call the related `solc` methods instead.\n    #[doc(hidden)]\n    pub solc: Option<SolcReq>,\n    /// Whether to autodetect the solc compiler version to use.\n    pub auto_detect_solc: bool,\n    /// Offline mode, if set, network access (downloading solc) is disallowed.\n    ///\n    /// Relationship with `auto_detect_solc`:\n    ///    - if `auto_detect_solc = true` and `offline = true`, the required solc version(s) will\n    ///      be auto detected but if the solc version is not installed, it will _not_ try to\n    ///      install it\n    pub offline: bool,\n    /// Whether to activate optimizer\n    pub optimizer: Option<bool>,\n    /// The number of runs specifies roughly how often each opcode of the deployed code will be\n    /// executed across the life-time of the contract. This means it is a trade-off parameter\n    /// between code size (deploy cost) and code execution cost (cost after deployment).\n    /// An `optimizer_runs` parameter of `1` will produce short but expensive code. In contrast, a\n    /// larger `optimizer_runs` parameter will produce longer but more gas efficient code. The\n    /// maximum value of the parameter is `2**32-1`.\n    ///\n    /// A common misconception is that this parameter specifies the number of iterations of the\n    /// optimizer. This is not true: The optimizer will always run as many times as it can\n    /// still improve the code.\n    pub optimizer_runs: Option<usize>,\n    /// Switch optimizer components on or off in detail.\n    /// The \"enabled\" switch above provides two defaults which can be\n    /// tweaked here. If \"details\" is given, \"enabled\" can be omitted.\n    pub optimizer_details: Option<OptimizerDetails>,\n    /// Model checker settings.\n    pub model_checker: Option<ModelCheckerSettings>,\n    /// verbosity to use\n    pub verbosity: u8,\n    /// url of the rpc server that should be used for any rpc calls\n    pub eth_rpc_url: Option<String>,\n    /// Whether to accept invalid certificates for the rpc server.\n    pub eth_rpc_accept_invalid_certs: bool,\n    /// Whether to disable automatic proxy detection for the rpc server.\n    ///\n    /// This can help in sandboxed environments (e.g., Cursor IDE sandbox, macOS App Sandbox)\n    /// where system proxy detection via SCDynamicStore causes crashes.\n    pub eth_rpc_no_proxy: bool,\n    /// JWT secret that should be used for any rpc calls\n    pub eth_rpc_jwt: Option<String>,\n    /// Timeout that should be used for any rpc calls\n    pub eth_rpc_timeout: Option<u64>,\n    /// Headers that should be used for any rpc calls\n    ///\n    /// # Example\n    ///\n    /// rpc_headers = [\"x-custom-header:value\", \"x-another-header:another-value\"]\n    ///\n    /// You can also the ETH_RPC_HEADERS env variable like so:\n    /// `ETH_RPC_HEADERS=\"x-custom-header:value x-another-header:another-value\"`\n    pub eth_rpc_headers: Option<Vec<String>>,\n    /// Print the equivalent curl command instead of making the RPC request.\n    pub eth_rpc_curl: bool,\n    /// etherscan API key, or alias for an `EtherscanConfig` in `etherscan` table\n    pub etherscan_api_key: Option<String>,\n    /// Multiple etherscan api configs and their aliases\n    #[serde(default, skip_serializing_if = \"EtherscanConfigs::is_empty\")]\n    pub etherscan: EtherscanConfigs,\n    /// List of solidity error codes to always silence in the compiler output.\n    pub ignored_error_codes: Vec<SolidityErrorCode>,\n    /// List of file paths to ignore.\n    #[serde(rename = \"ignored_warnings_from\")]\n    pub ignored_file_paths: Vec<PathBuf>,\n    /// Diagnostic level (minimum) at which the process should finish with a non-zero exit.\n    pub deny: DenyLevel,\n    /// DEPRECATED: use `deny` instead.\n    #[serde(default, skip_serializing)]\n    pub deny_warnings: bool,\n    /// Only run test functions matching the specified regex pattern.\n    #[serde(rename = \"match_test\")]\n    pub test_pattern: Option<RegexWrapper>,\n    /// Only run test functions that do not match the specified regex pattern.\n    #[serde(rename = \"no_match_test\")]\n    pub test_pattern_inverse: Option<RegexWrapper>,\n    /// Only run tests in contracts matching the specified regex pattern.\n    #[serde(rename = \"match_contract\")]\n    pub contract_pattern: Option<RegexWrapper>,\n    /// Only run tests in contracts that do not match the specified regex pattern.\n    #[serde(rename = \"no_match_contract\")]\n    pub contract_pattern_inverse: Option<RegexWrapper>,\n    /// Only run tests in source files matching the specified glob pattern.\n    #[serde(rename = \"match_path\", with = \"from_opt_glob\")]\n    pub path_pattern: Option<globset::Glob>,\n    /// Only run tests in source files that do not match the specified glob pattern.\n    #[serde(rename = \"no_match_path\", with = \"from_opt_glob\")]\n    pub path_pattern_inverse: Option<globset::Glob>,\n    /// Only show coverage for files that do not match the specified regex pattern.\n    #[serde(rename = \"no_match_coverage\")]\n    pub coverage_pattern_inverse: Option<RegexWrapper>,\n    /// Path where last test run failures are recorded.\n    pub test_failures_file: PathBuf,\n    /// Max concurrent threads to use.\n    pub threads: Option<usize>,\n    /// Whether to show test execution progress.\n    pub show_progress: bool,\n    /// Configuration for fuzz testing\n    pub fuzz: FuzzConfig,\n    /// Configuration for invariant testing\n    pub invariant: InvariantConfig,\n    /// Whether to allow ffi cheatcodes in test\n    pub ffi: bool,\n    /// Whether to show `console.log` outputs in realtime during script/test execution\n    pub live_logs: bool,\n    /// Whether to allow `expectRevert` for internal functions.\n    pub allow_internal_expect_revert: bool,\n    /// Use the create 2 factory in all cases including tests and non-broadcasting scripts.\n    pub always_use_create_2_factory: bool,\n    /// Sets a timeout in seconds for vm.prompt cheatcodes\n    pub prompt_timeout: u64,\n    /// The address which will be executing all tests\n    pub sender: Address,\n    /// The tx.origin value during EVM execution\n    pub tx_origin: Address,\n    /// the initial balance of each deployed test contract\n    pub initial_balance: U256,\n    /// the block.number value during EVM execution\n    #[serde(\n        deserialize_with = \"crate::deserialize_u64_to_u256\",\n        serialize_with = \"crate::serialize_u64_or_u256\"\n    )]\n    pub block_number: U256,\n    /// pins the block number for the state fork\n    pub fork_block_number: Option<u64>,\n    /// The chain name or EIP-155 chain ID.\n    #[serde(rename = \"chain_id\", alias = \"chain\")]\n    pub chain: Option<Chain>,\n    /// Block gas limit.\n    pub gas_limit: GasLimit,\n    /// EIP-170: Contract code size limit in bytes. Useful to increase this because of tests.\n    pub code_size_limit: Option<usize>,\n    /// `tx.gasprice` value during EVM execution.\n    ///\n    /// This is an Option, so we can determine in fork mode whether to use the config's gas price\n    /// (if set by user) or the remote client's gas price.\n    pub gas_price: Option<u64>,\n    /// The base fee in a block.\n    pub block_base_fee_per_gas: u64,\n    /// The `block.coinbase` value during EVM execution.\n    pub block_coinbase: Address,\n    /// The `block.timestamp` value during EVM execution.\n    #[serde(\n        deserialize_with = \"crate::deserialize_u64_to_u256\",\n        serialize_with = \"crate::serialize_u64_or_u256\"\n    )]\n    pub block_timestamp: U256,\n    /// The `block.difficulty` value during EVM execution.\n    pub block_difficulty: u64,\n    /// Before merge the `block.max_hash`, after merge it is `block.prevrandao`.\n    pub block_prevrandao: B256,\n    /// The `block.gaslimit` value during EVM execution.\n    pub block_gas_limit: Option<GasLimit>,\n    /// The memory limit per EVM execution in bytes.\n    /// If this limit is exceeded, a `MemoryLimitOOG` result is thrown.\n    ///\n    /// The default is 128MiB.\n    pub memory_limit: u64,\n    /// Additional output selection for all contracts, such as \"ir\", \"devdoc\", \"storageLayout\",\n    /// etc.\n    ///\n    /// See the [Solc Compiler Api](https://docs.soliditylang.org/en/latest/using-the-compiler.html#compiler-api) for more information.\n    ///\n    /// The following values are always set because they're required by `forge`:\n    /// ```json\n    /// {\n    ///   \"*\": [\n    ///       \"abi\",\n    ///       \"evm.bytecode\",\n    ///       \"evm.deployedBytecode\",\n    ///       \"evm.methodIdentifiers\"\n    ///     ]\n    /// }\n    /// ```\n    #[serde(default)]\n    pub extra_output: Vec<ContractOutputSelection>,\n    /// If set, a separate JSON file will be emitted for every contract depending on the\n    /// selection, eg. `extra_output_files = [\"metadata\"]` will create a `metadata.json` for\n    /// each contract in the project.\n    ///\n    /// See [Contract Metadata](https://docs.soliditylang.org/en/latest/metadata.html) for more information.\n    ///\n    /// The difference between `extra_output = [\"metadata\"]` and\n    /// `extra_output_files = [\"metadata\"]` is that the former will include the\n    /// contract's metadata in the contract's json artifact, whereas the latter will emit the\n    /// output selection as separate files.\n    #[serde(default)]\n    pub extra_output_files: Vec<ContractOutputSelection>,\n    /// Whether to print the names of the compiled contracts.\n    pub names: bool,\n    /// Whether to print the sizes of the compiled contracts.\n    pub sizes: bool,\n    /// If set to true, changes compilation pipeline to go through the Yul intermediate\n    /// representation.\n    pub via_ir: bool,\n    /// Whether to include the AST as JSON in the compiler output.\n    pub ast: bool,\n    /// RPC storage caching settings determines what chains and endpoints to cache\n    pub rpc_storage_caching: StorageCachingConfig,\n    /// Disables storage caching entirely. This overrides any settings made in\n    /// `rpc_storage_caching`\n    pub no_storage_caching: bool,\n    /// Disables rate limiting entirely. This overrides any settings made in\n    /// `compute_units_per_second`\n    pub no_rpc_rate_limit: bool,\n    /// Multiple rpc endpoints and their aliases\n    #[serde(default, skip_serializing_if = \"RpcEndpoints::is_empty\")]\n    pub rpc_endpoints: RpcEndpoints,\n    /// Whether to store the referenced sources in the metadata as literal data.\n    pub use_literal_content: bool,\n    /// Whether to include the metadata hash.\n    ///\n    /// The metadata hash is machine dependent. By default, this is set to [BytecodeHash::None] to allow for deterministic code, See: <https://docs.soliditylang.org/en/latest/metadata.html>\n    #[serde(with = \"from_str_lowercase\")]\n    pub bytecode_hash: BytecodeHash,\n    /// Whether to append the metadata hash to the bytecode.\n    ///\n    /// If this is `false` and the `bytecode_hash` option above is not `None` solc will issue a\n    /// warning.\n    pub cbor_metadata: bool,\n    /// How to treat revert (and require) reason strings.\n    #[serde(with = \"serde_helpers::display_from_str_opt\")]\n    pub revert_strings: Option<RevertStrings>,\n    /// Whether to compile in sparse mode\n    ///\n    /// If this option is enabled, only the required contracts/files will be selected to be\n    /// included in solc's output selection, see also [`OutputSelection`].\n    pub sparse_mode: bool,\n    /// Generates additional build info json files for every new build, containing the\n    /// `CompilerInput` and `CompilerOutput`.\n    pub build_info: bool,\n    /// The path to the `build-info` directory that contains the build info json files.\n    pub build_info_path: Option<PathBuf>,\n    /// Configuration for `forge fmt`\n    pub fmt: FormatterConfig,\n    /// Configuration for `forge lint`\n    pub lint: LinterConfig,\n    /// Configuration for `forge doc`\n    pub doc: DocConfig,\n    /// Configuration for `forge bind-json`\n    pub bind_json: BindJsonConfig,\n    /// Configures the permissions of cheat codes that touch the file system.\n    ///\n    /// This includes what operations can be executed (read, write)\n    pub fs_permissions: FsPermissions,\n\n    /// Whether to enable call isolation.\n    ///\n    /// Useful for more correct gas accounting and EVM behavior in general.\n    pub isolate: bool,\n\n    /// Whether to disable the block gas limit checks.\n    pub disable_block_gas_limit: bool,\n\n    /// Whether to enable the tx gas limit checks as imposed by Osaka (EIP-7825).\n    pub enable_tx_gas_limit: bool,\n\n    /// Address labels\n    pub labels: AddressHashMap<String>,\n\n    /// Whether to enable safety checks for `vm.getCode` and `vm.getDeployedCode` invocations.\n    /// If disabled, it is possible to access artifacts which were not recompiled or cached.\n    pub unchecked_cheatcode_artifacts: bool,\n\n    /// CREATE2 salt to use for the library deployment in scripts.\n    pub create2_library_salt: B256,\n\n    /// The CREATE2 deployer address to use.\n    pub create2_deployer: Address,\n\n    /// Configuration for Vyper compiler\n    pub vyper: VyperConfig,\n\n    /// Soldeer dependencies\n    pub dependencies: Option<SoldeerDependencyConfig>,\n\n    /// Soldeer custom configs\n    pub soldeer: Option<SoldeerConfig>,\n\n    /// Whether failed assertions should revert.\n    ///\n    /// Note that this only applies to native (cheatcode) assertions, invoked on Vm contract.\n    pub assertions_revert: bool,\n\n    /// Whether `failed()` should be invoked to check if the test have failed.\n    pub legacy_assertions: bool,\n\n    /// Optional additional CLI arguments to pass to `solc` binary.\n    #[serde(default, skip_serializing_if = \"Vec::is_empty\")]\n    pub extra_args: Vec<String>,\n\n    /// Networks with enabled features.\n    #[serde(flatten)]\n    pub networks: NetworkConfigs,\n\n    /// Timeout for transactions in seconds.\n    pub transaction_timeout: u64,\n\n    /// Warnings gathered when loading the Config. See [`WarningsProvider`] for more information.\n    #[serde(rename = \"__warnings\", default, skip_serializing)]\n    pub warnings: Vec<Warning>,\n\n    /// Additional settings profiles to use when compiling.\n    #[serde(default)]\n    pub additional_compiler_profiles: Vec<SettingsOverrides>,\n\n    /// Restrictions on compilation of certain files.\n    #[serde(default)]\n    pub compilation_restrictions: Vec<CompilationRestrictions>,\n\n    /// Whether to enable script execution protection.\n    pub script_execution_protection: bool,\n\n    /// PRIVATE: This structure may grow, As such, constructing this structure should\n    /// _always_ be done using a public constructor or update syntax:\n    ///\n    /// ```ignore\n    /// use foundry_config::Config;\n    ///\n    /// let config = Config { src: \"other\".into(), ..Default::default() };\n    /// ```\n    #[doc(hidden)]\n    #[serde(skip)]\n    pub _non_exhaustive: (),\n}\n\n/// Diagnostic level (minimum) at which the process should finish with a non-zero exit.\n#[derive(Debug, Clone, Copy, PartialEq, Eq, clap::ValueEnum, Default, Serialize)]\n#[serde(rename_all = \"lowercase\")]\npub enum DenyLevel {\n    /// Always exit with zero code.\n    #[default]\n    Never,\n    /// Exit with a non-zero code if any warnings are found.\n    Warnings,\n    /// Exit with a non-zero code if any notes or warnings are found.\n    Notes,\n}\n\n// Custom deserialization to make `DenyLevel` parsing case-insensitive and backwards compatible with\n// booleans.\nimpl<'de> Deserialize<'de> for DenyLevel {\n    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>\n    where\n        D: Deserializer<'de>,\n    {\n        struct DenyLevelVisitor;\n\n        impl<'de> de::Visitor<'de> for DenyLevelVisitor {\n            type Value = DenyLevel;\n\n            fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n                formatter.write_str(\"one of the following strings: `never`, `warnings`, `notes`\")\n            }\n\n            fn visit_bool<E>(self, value: bool) -> Result<Self::Value, E>\n            where\n                E: de::Error,\n            {\n                Ok(DenyLevel::from(value))\n            }\n\n            fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>\n            where\n                E: de::Error,\n            {\n                DenyLevel::from_str(value).map_err(de::Error::custom)\n            }\n        }\n\n        deserializer.deserialize_any(DenyLevelVisitor)\n    }\n}\n\nimpl FromStr for DenyLevel {\n    type Err = String;\n\n    fn from_str(s: &str) -> Result<Self, Self::Err> {\n        match s.to_lowercase().as_str() {\n            \"warnings\" | \"warning\" | \"w\" => Ok(Self::Warnings),\n            \"notes\" | \"note\" | \"n\" => Ok(Self::Notes),\n            \"never\" | \"false\" | \"f\" => Ok(Self::Never),\n            _ => Err(format!(\n                \"unknown variant: found `{s}`, expected one of `never`, `warnings`, `notes`\"\n            )),\n        }\n    }\n}\n\nimpl From<bool> for DenyLevel {\n    fn from(deny: bool) -> Self {\n        if deny { Self::Warnings } else { Self::Never }\n    }\n}\n\nimpl DenyLevel {\n    /// Returns `true` if the deny level includes warnings.\n    pub fn warnings(&self) -> bool {\n        match self {\n            Self::Never => false,\n            Self::Warnings | Self::Notes => true,\n        }\n    }\n\n    /// Returns `true` if the deny level includes notes.\n    pub fn notes(&self) -> bool {\n        match self {\n            Self::Never | Self::Warnings => false,\n            Self::Notes => true,\n        }\n    }\n\n    /// Returns `true` if the deny level is set to never (only errors).\n    pub fn never(&self) -> bool {\n        match self {\n            Self::Never => true,\n            Self::Warnings | Self::Notes => false,\n        }\n    }\n}\n\n/// Mapping of fallback standalone sections. See [`FallbackProfileProvider`].\npub const STANDALONE_FALLBACK_SECTIONS: &[(&str, &str)] = &[(\"invariant\", \"fuzz\")];\n\n/// Deprecated keys and their replacements.\n///\n/// See [Warning::DeprecatedKey]\npub const DEPRECATIONS: &[(&str, &str)] =\n    &[(\"cancun\", \"evm_version = Cancun\"), (\"deny_warnings\", \"deny = warnings\")];\n\nimpl Config {\n    /// The default profile: \"default\"\n    pub const DEFAULT_PROFILE: Profile = Profile::Default;\n\n    /// The hardhat profile: \"hardhat\"\n    pub const HARDHAT_PROFILE: Profile = Profile::const_new(\"hardhat\");\n\n    /// TOML section for profiles\n    pub const PROFILE_SECTION: &'static str = \"profile\";\n\n    /// External config sections, ignored from warnings.\n    pub const EXTERNAL_SECTION: &'static str = \"external\";\n\n    /// Standalone sections in the config which get integrated into the selected profile\n    pub const STANDALONE_SECTIONS: &'static [&'static str] = &[\n        \"rpc_endpoints\",\n        \"etherscan\",\n        \"fmt\",\n        \"lint\",\n        \"doc\",\n        \"fuzz\",\n        \"invariant\",\n        \"labels\",\n        \"dependencies\",\n        \"soldeer\",\n        \"vyper\",\n        \"bind_json\",\n    ];\n\n    pub(crate) fn is_standalone_section<T: ?Sized + PartialEq<str>>(section: &T) -> bool {\n        section == Self::PROFILE_SECTION\n            || section == Self::EXTERNAL_SECTION\n            || Self::STANDALONE_SECTIONS.iter().any(|s| section == *s)\n    }\n\n    /// File name of config toml file\n    pub const FILE_NAME: &'static str = \"foundry.toml\";\n\n    /// The name of the directory foundry reserves for itself under the user's home directory: `~`\n    pub const FOUNDRY_DIR_NAME: &'static str = \".foundry\";\n\n    /// Default address for tx.origin\n    ///\n    /// `0x1804c8AB1F12E6bbf3894d4083f33e07309d1f38`\n    pub const DEFAULT_SENDER: Address = address!(\"0x1804c8AB1F12E6bbf3894d4083f33e07309d1f38\");\n\n    /// Default salt for create2 library deployments\n    pub const DEFAULT_CREATE2_LIBRARY_SALT: FixedBytes<32> = FixedBytes::<32>::ZERO;\n\n    /// Default create2 deployer\n    pub const DEFAULT_CREATE2_DEPLOYER: Address =\n        address!(\"0x4e59b44847b379578588920ca78fbf26c0b4956c\");\n\n    /// Loads the `Config` from the current directory.\n    ///\n    /// See [`figment`](Self::figment) for more details.\n    pub fn load() -> Result<Self, ExtractConfigError> {\n        Self::from_provider(Self::figment())\n    }\n\n    /// Loads the `Config` with the given `providers` preset.\n    ///\n    /// See [`figment`](Self::figment) for more details.\n    pub fn load_with_providers(providers: FigmentProviders) -> Result<Self, ExtractConfigError> {\n        Self::from_provider(Self::default().to_figment(providers))\n    }\n\n    /// Loads the `Config` from the given root directory.\n    ///\n    /// See [`figment_with_root`](Self::figment_with_root) for more details.\n    #[track_caller]\n    pub fn load_with_root(root: impl AsRef<Path>) -> Result<Self, ExtractConfigError> {\n        Self::from_provider(Self::figment_with_root(root.as_ref()))\n    }\n\n    /// Loads the `Config` from the given root directory, allowing profile fallback.\n    ///\n    /// Unlike [`load_with_root`](Self::load_with_root), if the selected profile (via\n    /// `FOUNDRY_PROFILE`) does not exist in the config, this falls back to the default profile\n    /// instead of returning an error. This is useful for loading nested lib/dependency configs\n    /// that may not define all profiles the main project uses.\n    #[track_caller]\n    pub fn load_with_root_and_fallback(root: impl AsRef<Path>) -> Result<Self, ExtractConfigError> {\n        let figment = Self::figment_with_root(root.as_ref());\n        Self::from_figment_fallback(Figment::from(figment))\n    }\n\n    /// Attempts to extract a `Config` from `provider`, returning the result.\n    ///\n    /// # Example\n    ///\n    /// ```rust\n    /// use figment::providers::{Env, Format, Toml};\n    /// use foundry_config::Config;\n    ///\n    /// // Use foundry's default `Figment`, but allow values from `other.toml`\n    /// // to supersede its values.\n    /// let figment = Config::figment().merge(Toml::file(\"other.toml\").nested());\n    ///\n    /// let config = Config::from_provider(figment);\n    /// ```\n    #[doc(alias = \"try_from\")]\n    pub fn from_provider<T: Provider>(provider: T) -> Result<Self, ExtractConfigError> {\n        trace!(\"load config with provider: {:?}\", provider.metadata());\n        Self::from_figment(Figment::from(provider))\n    }\n\n    #[doc(hidden)]\n    #[deprecated(note = \"use `Config::from_provider` instead\")]\n    pub fn try_from<T: Provider>(provider: T) -> Result<Self, ExtractConfigError> {\n        Self::from_provider(provider)\n    }\n\n    fn from_figment(figment: Figment) -> Result<Self, ExtractConfigError> {\n        Self::from_figment_inner(figment, true)\n    }\n\n    /// Same as `from_figment` but allows unknown profiles, falling back to default profile.\n    /// Used when loading nested lib configs that may not define all profiles.\n    fn from_figment_fallback(figment: Figment) -> Result<Self, ExtractConfigError> {\n        Self::from_figment_inner(figment, false)\n    }\n\n    fn from_figment_inner(\n        figment: Figment,\n        strict_profile: bool,\n    ) -> Result<Self, ExtractConfigError> {\n        let mut config = figment.extract::<Self>().map_err(ExtractConfigError::new)?;\n        let selected_profile = figment.profile().clone();\n\n        // The `\"profile\"` profile contains all the profiles as keys.\n        fn add_profile(profiles: &mut Vec<Profile>, profile: &Profile) {\n            if !profiles.contains(profile) {\n                profiles.push(profile.clone());\n            }\n        }\n        let figment = figment.select(Self::PROFILE_SECTION);\n        if let Ok(data) = figment.data()\n            && let Some(profiles) = data.get(&Profile::new(Self::PROFILE_SECTION))\n        {\n            for profile in profiles.keys() {\n                add_profile(&mut config.profiles, &Profile::new(profile));\n            }\n        }\n        add_profile(&mut config.profiles, &Self::DEFAULT_PROFILE);\n\n        // Check if the selected profile exists.\n        if config.profiles.contains(&selected_profile) {\n            config.profile = selected_profile;\n        } else if strict_profile {\n            return Err(ExtractConfigError::new(Error::from(format!(\n                \"selected profile `{selected_profile}` does not exist\"\n            ))));\n        } else {\n            // Fall back to default profile for nested lib configs.\n            config.profile = Self::DEFAULT_PROFILE;\n        }\n\n        config.normalize_optimizer_settings();\n\n        Ok(config)\n    }\n\n    /// Returns the populated [Figment] using the requested [FigmentProviders] preset.\n    ///\n    /// This will merge various providers, such as env,toml,remappings into the figment if\n    /// requested.\n    pub fn to_figment(&self, providers: FigmentProviders) -> Figment {\n        // Note that `Figment::from` here is a method on `Figment` rather than the `From` impl below\n\n        if providers.is_none() {\n            return Figment::from(self);\n        }\n\n        let root = self.root.as_path();\n        let profile = Self::selected_profile();\n        let mut figment = Figment::default().merge(DappHardhatDirProvider(root));\n\n        // merge global foundry.toml file\n        if let Some(global_toml) = Self::foundry_dir_toml().filter(|p| p.exists()) {\n            figment = Self::merge_toml_provider(\n                figment,\n                TomlFileProvider::new(None, global_toml),\n                profile.clone(),\n            );\n        }\n        // merge local foundry.toml file\n        figment = Self::merge_toml_provider(\n            figment,\n            TomlFileProvider::new(Some(\"FOUNDRY_CONFIG\"), root.join(Self::FILE_NAME)),\n            profile.clone(),\n        );\n\n        // merge environment variables\n        figment = figment\n            .merge(\n                Env::prefixed(\"DAPP_\")\n                    .ignore(&[\"REMAPPINGS\", \"LIBRARIES\", \"FFI\", \"FS_PERMISSIONS\"])\n                    .global(),\n            )\n            .merge(\n                Env::prefixed(\"DAPP_TEST_\")\n                    .ignore(&[\"CACHE\", \"FUZZ_RUNS\", \"DEPTH\", \"FFI\", \"FS_PERMISSIONS\"])\n                    .global(),\n            )\n            .merge(DappEnvCompatProvider)\n            .merge(EtherscanEnvProvider::default())\n            .merge(\n                Env::prefixed(\"FOUNDRY_\")\n                    .ignore(&[\"PROFILE\", \"REMAPPINGS\", \"LIBRARIES\", \"FFI\", \"FS_PERMISSIONS\"])\n                    .map(|key| {\n                        let key = key.as_str();\n                        if Self::STANDALONE_SECTIONS.iter().any(|section| {\n                            key.starts_with(&format!(\"{}_\", section.to_ascii_uppercase()))\n                        }) {\n                            key.replacen('_', \".\", 1).into()\n                        } else {\n                            key.into()\n                        }\n                    })\n                    .global(),\n            )\n            .select(profile.clone());\n\n        // only resolve remappings if all providers are requested\n        if providers.is_all() {\n            // we try to merge remappings after we've merged all other providers, this prevents\n            // redundant fs lookups to determine the default remappings that are eventually updated\n            // by other providers, like the toml file\n            let remappings = RemappingsProvider {\n                auto_detect_remappings: figment\n                    .extract_inner::<bool>(\"auto_detect_remappings\")\n                    .unwrap_or(true),\n                lib_paths: figment\n                    .extract_inner::<Vec<PathBuf>>(\"libs\")\n                    .map(Cow::Owned)\n                    .unwrap_or_else(|_| Cow::Borrowed(&self.libs)),\n                root,\n                remappings: figment.extract_inner::<Vec<Remapping>>(\"remappings\"),\n            };\n            figment = figment.merge(remappings);\n        }\n\n        // normalize defaults\n        figment = self.normalize_defaults(figment);\n\n        Figment::from(self).merge(figment).select(profile)\n    }\n\n    /// The config supports relative paths and tracks the root path separately see\n    /// `Config::with_root`\n    ///\n    /// This joins all relative paths with the current root and attempts to make them canonic\n    #[must_use]\n    pub fn canonic(self) -> Self {\n        let root = self.root.clone();\n        self.canonic_at(root)\n    }\n\n    /// Joins all relative paths with the given root so that paths that are defined as:\n    ///\n    /// ```toml\n    /// [profile.default]\n    /// src = \"src\"\n    /// out = \"./out\"\n    /// libs = [\"lib\", \"/var/lib\"]\n    /// ```\n    ///\n    /// Will be made canonic with the given root:\n    ///\n    /// ```toml\n    /// [profile.default]\n    /// src = \"<root>/src\"\n    /// out = \"<root>/out\"\n    /// libs = [\"<root>/lib\", \"/var/lib\"]\n    /// ```\n    #[must_use]\n    pub fn canonic_at(mut self, root: impl Into<PathBuf>) -> Self {\n        let root = canonic(root);\n\n        fn p(root: &Path, rem: &Path) -> PathBuf {\n            canonic(root.join(rem))\n        }\n\n        self.src = p(&root, &self.src);\n        self.test = p(&root, &self.test);\n        self.script = p(&root, &self.script);\n        self.out = p(&root, &self.out);\n        self.broadcast = p(&root, &self.broadcast);\n        self.cache_path = p(&root, &self.cache_path);\n        self.snapshots = p(&root, &self.snapshots);\n        self.test_failures_file = p(&root, &self.test_failures_file);\n\n        if let Some(build_info_path) = self.build_info_path {\n            self.build_info_path = Some(p(&root, &build_info_path));\n        }\n\n        self.libs = self.libs.into_iter().map(|lib| p(&root, &lib)).collect();\n\n        self.remappings =\n            self.remappings.into_iter().map(|r| RelativeRemapping::new(r.into(), &root)).collect();\n\n        self.allow_paths = self.allow_paths.into_iter().map(|allow| p(&root, &allow)).collect();\n\n        self.include_paths = self.include_paths.into_iter().map(|allow| p(&root, &allow)).collect();\n\n        self.fs_permissions.join_all(&root);\n\n        if let Some(model_checker) = &mut self.model_checker {\n            model_checker.contracts = std::mem::take(&mut model_checker.contracts)\n                .into_iter()\n                .map(|(path, contracts)| {\n                    (format!(\"{}\", p(&root, path.as_ref()).display()), contracts)\n                })\n                .collect();\n        }\n\n        self\n    }\n\n    /// Normalizes the evm version if a [SolcReq] is set\n    pub fn normalized_evm_version(mut self) -> Self {\n        self.normalize_evm_version();\n        self\n    }\n\n    /// Normalizes optimizer settings.\n    /// See <https://github.com/foundry-rs/foundry/issues/9665>\n    pub fn normalized_optimizer_settings(mut self) -> Self {\n        self.normalize_optimizer_settings();\n        self\n    }\n\n    /// Normalizes the evm version if a [SolcReq] is set to a valid version.\n    pub fn normalize_evm_version(&mut self) {\n        self.evm_version = self.get_normalized_evm_version();\n    }\n\n    /// Normalizes optimizer settings:\n    /// - with default settings, optimizer is set to false and optimizer runs to 200\n    /// - if optimizer is set and optimizer runs not specified, then optimizer runs is set to 200\n    /// - enable optimizer if not explicitly set and optimizer runs set to a value greater than 0\n    pub fn normalize_optimizer_settings(&mut self) {\n        match (self.optimizer, self.optimizer_runs) {\n            // Default: set the optimizer to false and optimizer runs to 200.\n            (None, None) => {\n                self.optimizer = Some(false);\n                self.optimizer_runs = Some(200);\n            }\n            // Set the optimizer runs to 200 if the `optimizer` config set.\n            (Some(_), None) => self.optimizer_runs = Some(200),\n            // Enables optimizer if the `optimizer_runs` has been set with a value greater than 0.\n            (None, Some(runs)) => self.optimizer = Some(runs > 0),\n            _ => {}\n        }\n    }\n\n    /// Returns the normalized [EvmVersion] for the current solc version, or the configured one.\n    pub fn get_normalized_evm_version(&self) -> EvmVersion {\n        if let Some(version) = self.solc_version()\n            && let Some(evm_version) = self.evm_version.normalize_version_solc(&version)\n        {\n            return evm_version;\n        }\n        self.evm_version\n    }\n\n    /// Returns a sanitized version of the Config where are paths are set correctly and potential\n    /// duplicates are resolved\n    ///\n    /// See [`Self::canonic`]\n    #[must_use]\n    pub fn sanitized(self) -> Self {\n        let mut config = self.canonic();\n\n        config.sanitize_remappings();\n\n        config.libs.sort_unstable();\n        config.libs.dedup();\n\n        config\n    }\n\n    /// Cleans up any duplicate `Remapping` and sorts them\n    ///\n    /// On windows this will convert any `\\` in the remapping path into a `/`\n    pub fn sanitize_remappings(&mut self) {\n        #[cfg(target_os = \"windows\")]\n        {\n            // force `/` in remappings on windows\n            use path_slash::PathBufExt;\n            self.remappings.iter_mut().for_each(|r| {\n                r.path.path = r.path.path.to_slash_lossy().into_owned().into();\n            });\n        }\n    }\n\n    /// Returns the directory in which dependencies should be installed\n    ///\n    /// Returns the first dir from `libs` that is not `node_modules` or `lib` if `libs` is empty\n    pub fn install_lib_dir(&self) -> &Path {\n        self.libs\n            .iter()\n            .find(|p| !p.ends_with(\"node_modules\"))\n            .map(|p| p.as_path())\n            .unwrap_or_else(|| Path::new(\"lib\"))\n    }\n\n    /// Serves as the entrypoint for obtaining the project.\n    ///\n    /// Returns the `Project` configured with all `solc` and path related values.\n    ///\n    /// *Note*: this also _cleans_ [`Project::cleanup`] the workspace if `force` is set to true.\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// use foundry_config::Config;\n    /// let config = Config::load_with_root(\".\")?.sanitized();\n    /// let project = config.project()?;\n    /// # Ok::<_, eyre::Error>(())\n    /// ```\n    pub fn project(&self) -> Result<Project<MultiCompiler>, SolcError> {\n        self.create_project(self.cache, false)\n    }\n\n    /// Same as [`Self::project()`] but sets configures the project to not emit artifacts and ignore\n    /// cache.\n    pub fn ephemeral_project(&self) -> Result<Project<MultiCompiler>, SolcError> {\n        self.create_project(false, true)\n    }\n\n    /// A cached, in-memory project that does not request any artifacts.\n    ///\n    /// Use this when you just want the source graph or the Solar compiler context.\n    pub fn solar_project(&self) -> Result<Project<MultiCompiler>, SolcError> {\n        let ui_testing = std::env::var_os(\"FOUNDRY_LINT_UI_TESTING\").is_some();\n        let mut project = self.create_project(self.cache && !ui_testing, false)?;\n        project.update_output_selection(|selection| {\n            // We have to request something to populate `contracts` in the output and thus\n            // artifacts.\n            *selection = OutputSelection::common_output_selection([\"abi\".into()]);\n        });\n        Ok(project)\n    }\n\n    /// Builds mapping with additional settings profiles.\n    fn additional_settings(\n        &self,\n        base: &MultiCompilerSettings,\n    ) -> BTreeMap<String, MultiCompilerSettings> {\n        let mut map = BTreeMap::new();\n\n        for profile in &self.additional_compiler_profiles {\n            let mut settings = base.clone();\n            profile.apply(&mut settings);\n            map.insert(profile.name.clone(), settings);\n        }\n\n        map\n    }\n\n    /// Resolves globs and builds a mapping from individual source files to their restrictions\n    #[expect(clippy::disallowed_macros)]\n    fn restrictions(\n        &self,\n        paths: &ProjectPathsConfig,\n    ) -> Result<BTreeMap<PathBuf, RestrictionsWithVersion<MultiCompilerRestrictions>>, SolcError>\n    {\n        let mut map = BTreeMap::new();\n        if self.compilation_restrictions.is_empty() {\n            return Ok(BTreeMap::new());\n        }\n\n        let graph = Graph::<MultiCompilerParser>::resolve(paths)?;\n        let (sources, _) = graph.into_sources();\n\n        for res in &self.compilation_restrictions {\n            for source in sources.keys().filter(|path| {\n                if res.paths.is_match(path) {\n                    true\n                } else if let Ok(path) = path.strip_prefix(&paths.root) {\n                    res.paths.is_match(path)\n                } else {\n                    false\n                }\n            }) {\n                let res: RestrictionsWithVersion<_> =\n                    res.clone().try_into().map_err(SolcError::msg)?;\n                if !map.contains_key(source) {\n                    map.insert(source.clone(), res);\n                } else {\n                    let value = map.remove(source.as_path()).unwrap();\n                    if let Some(merged) = value.clone().merge(res) {\n                        map.insert(source.clone(), merged);\n                    } else {\n                        // `sh_warn!` is a circular dependency, preventing us from using it here.\n                        eprintln!(\n                            \"{}\",\n                            yansi::Paint::yellow(&format!(\n                                \"Failed to merge compilation restrictions for {}\",\n                                source.display()\n                            ))\n                        );\n                        map.insert(source.clone(), value);\n                    }\n                }\n            }\n        }\n\n        Ok(map)\n    }\n\n    /// Creates a [`Project`] with the given `cached` and `no_artifacts` flags.\n    ///\n    /// Prefer using [`Self::project`] or [`Self::ephemeral_project`] instead.\n    pub fn create_project(&self, cached: bool, no_artifacts: bool) -> Result<Project, SolcError> {\n        let settings = self.compiler_settings()?;\n        let paths = self.project_paths();\n        let mut builder = Project::builder()\n            .artifacts(self.configured_artifacts_handler())\n            .additional_settings(self.additional_settings(&settings))\n            .restrictions(self.restrictions(&paths)?)\n            .settings(settings)\n            .paths(paths)\n            .ignore_error_codes(self.ignored_error_codes.iter().copied().map(Into::into))\n            .ignore_paths(\n                self.ignored_file_paths\n                    .iter()\n                    .map(|path| {\n                        // Strip \"./\" prefix for consistent path matching\n                        path.strip_prefix(\"./\").unwrap_or(path).to_path_buf()\n                    })\n                    .collect::<Vec<_>>(),\n            )\n            .set_compiler_severity_filter(if self.deny.warnings() {\n                Severity::Warning\n            } else {\n                Severity::Error\n            })\n            .set_offline(self.offline)\n            .set_cached(cached)\n            .set_build_info(!no_artifacts && self.build_info)\n            .set_no_artifacts(no_artifacts);\n\n        if !self.skip.is_empty() {\n            let filter = SkipBuildFilters::new(self.skip.clone(), self.root.clone());\n            builder = builder.sparse_output(filter);\n        }\n\n        let project = builder.build(self.compiler()?)?;\n\n        if self.force {\n            self.cleanup(&project)?;\n        }\n\n        Ok(project)\n    }\n\n    /// Disables optimizations and enables viaIR with minimum optimization if `ir_minimum` is true.\n    pub fn disable_optimizations(&self, project: &mut Project, ir_minimum: bool) {\n        if ir_minimum {\n            // Enable viaIR with minimum optimization: https://github.com/ethereum/solidity/issues/12533#issuecomment-1013073350\n            // And also in new releases of Solidity: https://github.com/ethereum/solidity/issues/13972#issuecomment-1628632202\n            project.settings.solc.settings = std::mem::take(&mut project.settings.solc.settings)\n                .with_via_ir_minimum_optimization();\n\n            // Sanitize settings for solc 0.8.4 if version cannot be detected: https://github.com/foundry-rs/foundry/issues/9322\n            // But keep the EVM version: https://github.com/ethereum/solidity/issues/15775\n            let evm_version = project.settings.solc.evm_version;\n            let version = self.solc_version().unwrap_or_else(|| Version::new(0, 8, 4));\n            project.settings.solc.settings.sanitize(&version, SolcLanguage::Solidity);\n            project.settings.solc.evm_version = evm_version;\n        } else {\n            project.settings.solc.optimizer.disable();\n            project.settings.solc.optimizer.runs = None;\n            project.settings.solc.optimizer.details = None;\n            project.settings.solc.via_ir = None;\n        }\n    }\n\n    /// Cleans the project.\n    pub fn cleanup<C: Compiler, T: ArtifactOutput<CompilerContract = C::CompilerContract>>(\n        &self,\n        project: &Project<C, T>,\n    ) -> Result<(), SolcError> {\n        project.cleanup()?;\n\n        // Remove last test run failures file.\n        let _ = fs::remove_file(&self.test_failures_file);\n\n        // Remove fuzz and invariant cache directories.\n        let remove_test_dir = |test_dir: &Option<PathBuf>| {\n            if let Some(test_dir) = test_dir {\n                let path = project.root().join(test_dir);\n                if path.exists() {\n                    let _ = fs::remove_dir_all(&path);\n                }\n            }\n        };\n        remove_test_dir(&self.fuzz.failure_persist_dir);\n        remove_test_dir(&self.fuzz.corpus.corpus_dir);\n        remove_test_dir(&self.invariant.corpus.corpus_dir);\n        remove_test_dir(&self.invariant.failure_persist_dir);\n\n        Ok(())\n    }\n\n    /// Ensures that the configured version is installed if explicitly set\n    ///\n    /// If `solc` is [`SolcReq::Version`] then this will download and install the solc version if\n    /// it's missing, unless the `offline` flag is enabled, in which case an error is thrown.\n    ///\n    /// If `solc` is [`SolcReq::Local`] then this will ensure that the path exists.\n    fn ensure_solc(&self) -> Result<Option<Solc>, SolcError> {\n        if let Some(solc) = &self.solc {\n            let solc = match solc {\n                SolcReq::Version(version) => {\n                    if let Some(solc) = Solc::find_svm_installed_version(version)? {\n                        solc\n                    } else {\n                        if self.offline {\n                            return Err(SolcError::msg(format!(\n                                \"can't install missing solc {version} in offline mode\"\n                            )));\n                        }\n                        Solc::blocking_install(version)?\n                    }\n                }\n                SolcReq::Local(solc) => {\n                    if !solc.is_file() {\n                        return Err(SolcError::msg(format!(\n                            \"`solc` {} does not exist\",\n                            solc.display()\n                        )));\n                    }\n                    Solc::new(solc)?\n                }\n            };\n            return Ok(Some(solc));\n        }\n\n        Ok(None)\n    }\n\n    /// Returns the [SpecId] derived from the configured [EvmVersion]\n    pub fn evm_spec_id(&self) -> SpecId {\n        evm_spec_id(self.evm_version)\n    }\n\n    /// Returns whether the compiler version should be auto-detected\n    ///\n    /// Returns `false` if `solc_version` is explicitly set, otherwise returns the value of\n    /// `auto_detect_solc`\n    pub fn is_auto_detect(&self) -> bool {\n        if self.solc.is_some() {\n            return false;\n        }\n        self.auto_detect_solc\n    }\n\n    /// Whether caching should be enabled for the given chain id\n    pub fn enable_caching(&self, endpoint: &str, chain_id: impl Into<u64>) -> bool {\n        !self.no_storage_caching\n            && self.rpc_storage_caching.enable_for_chain_id(chain_id.into())\n            && self.rpc_storage_caching.enable_for_endpoint(endpoint)\n    }\n\n    /// Returns the `ProjectPathsConfig` sub set of the config.\n    ///\n    /// **NOTE**: this uses the paths as they are and does __not__ modify them, see\n    /// `[Self::sanitized]`\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// use foundry_compilers::solc::Solc;\n    /// use foundry_config::Config;\n    /// let config = Config::load_with_root(\".\")?.sanitized();\n    /// let paths = config.project_paths::<Solc>();\n    /// # Ok::<_, eyre::Error>(())\n    /// ```\n    pub fn project_paths<L>(&self) -> ProjectPathsConfig<L> {\n        let mut builder = ProjectPathsConfig::builder()\n            .cache(self.cache_path.join(SOLIDITY_FILES_CACHE_FILENAME))\n            .sources(&self.src)\n            .tests(&self.test)\n            .scripts(&self.script)\n            .artifacts(&self.out)\n            .libs(self.libs.iter())\n            .remappings(self.get_all_remappings())\n            .allowed_path(&self.root)\n            .allowed_paths(&self.libs)\n            .allowed_paths(&self.allow_paths)\n            .include_paths(&self.include_paths);\n\n        if let Some(build_info_path) = &self.build_info_path {\n            builder = builder.build_infos(build_info_path);\n        }\n\n        builder.build_with_root(&self.root)\n    }\n\n    /// Returns configuration for a compiler to use when setting up a [Project].\n    pub fn solc_compiler(&self) -> Result<SolcCompiler, SolcError> {\n        if let Some(solc) = self.ensure_solc()? {\n            Ok(SolcCompiler::Specific(solc))\n        } else {\n            Ok(SolcCompiler::AutoDetect)\n        }\n    }\n\n    /// Returns the solc version, if any.\n    pub fn solc_version(&self) -> Option<Version> {\n        self.solc.as_ref().and_then(|solc| solc.try_version().ok())\n    }\n\n    /// Returns configured [Vyper] compiler.\n    pub fn vyper_compiler(&self) -> Result<Option<Vyper>, SolcError> {\n        // Only instantiate Vyper if there are any Vyper files in the project.\n        if !self.project_paths::<VyperLanguage>().has_input_files() {\n            return Ok(None);\n        }\n        let vyper = if let Some(path) = &self.vyper.path {\n            Some(Vyper::new(path)?)\n        } else {\n            Vyper::new(\"vyper\").ok()\n        };\n        Ok(vyper)\n    }\n\n    /// Returns configuration for a compiler to use when setting up a [Project].\n    pub fn compiler(&self) -> Result<MultiCompiler, SolcError> {\n        Ok(MultiCompiler { solc: Some(self.solc_compiler()?), vyper: self.vyper_compiler()? })\n    }\n\n    /// Returns configured [MultiCompilerSettings].\n    pub fn compiler_settings(&self) -> Result<MultiCompilerSettings, SolcError> {\n        Ok(MultiCompilerSettings { solc: self.solc_settings()?, vyper: self.vyper_settings()? })\n    }\n\n    /// Returns all configured remappings.\n    pub fn get_all_remappings(&self) -> impl Iterator<Item = Remapping> + '_ {\n        self.remappings.iter().map(|m| m.clone().into())\n    }\n\n    /// Returns the configured rpc jwt secret\n    ///\n    /// Returns:\n    ///    - The jwt secret, if configured\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// use foundry_config::Config;\n    /// # fn t() {\n    /// let config = Config::with_root(\"./\");\n    /// let rpc_jwt = config.get_rpc_jwt_secret().unwrap().unwrap();\n    /// # }\n    /// ```\n    pub fn get_rpc_jwt_secret(&self) -> Result<Option<Cow<'_, str>>, UnresolvedEnvVarError> {\n        Ok(self.eth_rpc_jwt.as_ref().map(|jwt| Cow::Borrowed(jwt.as_str())))\n    }\n\n    /// Returns the configured rpc url\n    ///\n    /// Returns:\n    ///    - the matching, resolved url of  `rpc_endpoints` if `eth_rpc_url` is an alias\n    ///    - the `eth_rpc_url` as-is if it isn't an alias\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// use foundry_config::Config;\n    /// # fn t() {\n    /// let config = Config::with_root(\"./\");\n    /// let rpc_url = config.get_rpc_url().unwrap().unwrap();\n    /// # }\n    /// ```\n    pub fn get_rpc_url(&self) -> Option<Result<Cow<'_, str>, UnresolvedEnvVarError>> {\n        let maybe_alias = self.eth_rpc_url.as_deref()?;\n        if let Some(alias) = self.get_rpc_url_with_alias(maybe_alias) {\n            Some(alias)\n        } else {\n            Some(Ok(Cow::Borrowed(self.eth_rpc_url.as_deref()?)))\n        }\n    }\n\n    /// Resolves the given alias to a matching rpc url\n    ///\n    /// # Returns\n    ///\n    /// In order of resolution:\n    ///\n    /// - the matching, resolved url of `rpc_endpoints` if `maybe_alias` is an alias\n    /// - a mesc resolved url if `maybe_alias` is a known alias in mesc\n    /// - `None` otherwise\n    ///\n    /// # Note on mesc\n    ///\n    /// The endpoint is queried for in mesc under the `foundry` profile, allowing users to customize\n    /// endpoints for Foundry specifically.\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// use foundry_config::Config;\n    /// # fn t() {\n    /// let config = Config::with_root(\"./\");\n    /// let rpc_url = config.get_rpc_url_with_alias(\"mainnet\").unwrap().unwrap();\n    /// # }\n    /// ```\n    pub fn get_rpc_url_with_alias(\n        &self,\n        maybe_alias: &str,\n    ) -> Option<Result<Cow<'_, str>, UnresolvedEnvVarError>> {\n        let mut endpoints = self.rpc_endpoints.clone().resolved();\n        if let Some(endpoint) = endpoints.remove(maybe_alias) {\n            return Some(endpoint.url().map(Cow::Owned));\n        }\n\n        if let Some(mesc_url) = self.get_rpc_url_from_mesc(maybe_alias) {\n            return Some(Ok(Cow::Owned(mesc_url)));\n        }\n\n        None\n    }\n\n    /// Attempts to resolve the URL for the given alias from [`mesc`](https://github.com/paradigmxyz/mesc)\n    pub fn get_rpc_url_from_mesc(&self, maybe_alias: &str) -> Option<String> {\n        // Note: mesc requires a MESC_PATH in the env, which the user can configure and is expected\n        // to be part of the shell profile, default is ~/mesc.json\n        let mesc_config = mesc::load::load_config_data()\n            .inspect_err(|err| debug!(%err, \"failed to load mesc config\"))\n            .ok()?;\n\n        if let Ok(Some(endpoint)) =\n            mesc::query::get_endpoint_by_query(&mesc_config, maybe_alias, Some(\"foundry\"))\n        {\n            return Some(endpoint.url);\n        }\n\n        if maybe_alias.chars().all(|c| c.is_numeric()) {\n            // try to lookup the mesc network by chain id if alias is numeric\n            // This only succeeds if the chain id has a default:\n            // \"network_defaults\": {\n            //    \"50104\": \"sophon_50104\"\n            // }\n            if let Ok(Some(endpoint)) =\n                mesc::query::get_endpoint_by_network(&mesc_config, maybe_alias, Some(\"foundry\"))\n            {\n                return Some(endpoint.url);\n            }\n        }\n\n        None\n    }\n\n    /// Returns the configured rpc, or the fallback url\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// use foundry_config::Config;\n    /// # fn t() {\n    /// let config = Config::with_root(\"./\");\n    /// let rpc_url = config.get_rpc_url_or(\"http://localhost:8545\").unwrap();\n    /// # }\n    /// ```\n    pub fn get_rpc_url_or<'a>(\n        &'a self,\n        fallback: impl Into<Cow<'a, str>>,\n    ) -> Result<Cow<'a, str>, UnresolvedEnvVarError> {\n        if let Some(url) = self.get_rpc_url() { url } else { Ok(fallback.into()) }\n    }\n\n    /// Returns the configured rpc or `\"http://localhost:8545\"` if no `eth_rpc_url` is set\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// use foundry_config::Config;\n    /// # fn t() {\n    /// let config = Config::with_root(\"./\");\n    /// let rpc_url = config.get_rpc_url_or_localhost_http().unwrap();\n    /// # }\n    /// ```\n    pub fn get_rpc_url_or_localhost_http(&self) -> Result<Cow<'_, str>, UnresolvedEnvVarError> {\n        self.get_rpc_url_or(\"http://localhost:8545\")\n    }\n\n    /// Returns the `EtherscanConfig` to use, if any\n    ///\n    /// Returns\n    ///  - the matching `ResolvedEtherscanConfig` of the `etherscan` table if `etherscan_api_key` is\n    ///    an alias\n    ///  - the matching `ResolvedEtherscanConfig` of the `etherscan` table if a `chain` is\n    ///    configured. an alias\n    ///  - the Mainnet  `ResolvedEtherscanConfig` if `etherscan_api_key` is set, `None` otherwise\n    ///\n    /// # Example\n    ///\n    /// ```\n    /// use foundry_config::Config;\n    /// # fn t() {\n    /// let config = Config::with_root(\"./\");\n    /// let etherscan_config = config.get_etherscan_config().unwrap().unwrap();\n    /// let client = etherscan_config.into_client().unwrap();\n    /// # }\n    /// ```\n    pub fn get_etherscan_config(\n        &self,\n    ) -> Option<Result<ResolvedEtherscanConfig, EtherscanConfigError>> {\n        self.get_etherscan_config_with_chain(None).transpose()\n    }\n\n    /// Same as [`Self::get_etherscan_config()`] but optionally updates the config with the given\n    /// `chain`, and `etherscan_api_key`\n    ///\n    /// If not matching alias was found, then this will try to find the first entry in the table\n    /// with a matching chain id. If an etherscan_api_key is already set it will take precedence\n    /// over the chain's entry in the table.\n    pub fn get_etherscan_config_with_chain(\n        &self,\n        chain: Option<Chain>,\n    ) -> Result<Option<ResolvedEtherscanConfig>, EtherscanConfigError> {\n        if let Some(maybe_alias) = self.etherscan_api_key.as_ref().or(self.eth_rpc_url.as_ref())\n            && self.etherscan.contains_key(maybe_alias)\n        {\n            return self.etherscan.clone().resolved().remove(maybe_alias).transpose();\n        }\n\n        // try to find by comparing chain IDs after resolving\n        if let Some(res) = chain\n            .or(self.chain)\n            .and_then(|chain| self.etherscan.clone().resolved().find_chain(chain))\n        {\n            match (res, self.etherscan_api_key.as_ref()) {\n                (Ok(mut config), Some(key)) => {\n                    // we update the key, because if an etherscan_api_key is set, it should take\n                    // precedence over the entry, since this is usually set via env var or CLI args.\n                    config.key.clone_from(key);\n                    return Ok(Some(config));\n                }\n                (Ok(config), None) => return Ok(Some(config)),\n                (Err(err), None) => return Err(err),\n                (Err(_), Some(_)) => {\n                    // use the etherscan key as fallback\n                }\n            }\n        }\n\n        // etherscan fallback via API key\n        if let Some(key) = self.etherscan_api_key.as_ref() {\n            return Ok(ResolvedEtherscanConfig::create(\n                key,\n                chain.or(self.chain).unwrap_or_default(),\n            ));\n        }\n        Ok(None)\n    }\n\n    /// Helper function to just get the API key\n    ///\n    /// Optionally updates the config with the given `chain`.\n    ///\n    /// See also [Self::get_etherscan_config_with_chain]\n    #[expect(clippy::disallowed_macros)]\n    pub fn get_etherscan_api_key(&self, chain: Option<Chain>) -> Option<String> {\n        self.get_etherscan_config_with_chain(chain)\n            .map_err(|e| {\n                // `sh_warn!` is a circular dependency, preventing us from using it here.\n                eprintln!(\n                    \"{}: failed getting etherscan config: {e}\",\n                    yansi::Paint::yellow(\"Warning\"),\n                );\n            })\n            .ok()\n            .flatten()\n            .map(|c| c.key)\n    }\n\n    /// Returns the remapping for the project's _src_ directory\n    ///\n    /// **Note:** this will add an additional `<src>/=<src path>` remapping here so imports that\n    /// look like `import {Foo} from \"src/Foo.sol\";` are properly resolved.\n    ///\n    /// This is due the fact that `solc`'s VFS resolves [direct imports](https://docs.soliditylang.org/en/develop/path-resolution.html#direct-imports) that start with the source directory's name.\n    pub fn get_source_dir_remapping(&self) -> Option<Remapping> {\n        get_dir_remapping(&self.src)\n    }\n\n    /// Returns the remapping for the project's _test_ directory, but only if it exists\n    pub fn get_test_dir_remapping(&self) -> Option<Remapping> {\n        if self.root.join(&self.test).exists() { get_dir_remapping(&self.test) } else { None }\n    }\n\n    /// Returns the remapping for the project's _script_ directory, but only if it exists\n    pub fn get_script_dir_remapping(&self) -> Option<Remapping> {\n        if self.root.join(&self.script).exists() { get_dir_remapping(&self.script) } else { None }\n    }\n\n    /// Returns the `Optimizer` based on the configured settings\n    ///\n    /// Note: optimizer details can be set independently of `enabled`\n    /// See also: <https://github.com/foundry-rs/foundry/issues/7689>\n    /// and  <https://github.com/ethereum/solidity/blob/bbb7f58be026fdc51b0b4694a6f25c22a1425586/docs/using-the-compiler.rst?plain=1#L293-L294>\n    pub fn optimizer(&self) -> Optimizer {\n        Optimizer {\n            enabled: self.optimizer,\n            runs: self.optimizer_runs,\n            // we always set the details because `enabled` is effectively a specific details profile\n            // that can still be modified\n            details: self.optimizer_details.clone(),\n        }\n    }\n\n    /// returns the [`foundry_compilers::ConfigurableArtifacts`] for this config, that includes the\n    /// `extra_output` fields\n    pub fn configured_artifacts_handler(&self) -> ConfigurableArtifacts {\n        let mut extra_output = self.extra_output.clone();\n\n        // Sourcify verification requires solc metadata output. Since, it doesn't\n        // affect the UX & performance of the compiler, output the metadata files\n        // by default.\n        // For more info see: <https://github.com/foundry-rs/foundry/issues/2795>\n        // Metadata is not emitted as separate file because this breaks typechain support: <https://github.com/foundry-rs/foundry/issues/2969>\n        if !extra_output.contains(&ContractOutputSelection::Metadata) {\n            extra_output.push(ContractOutputSelection::Metadata);\n        }\n\n        ConfigurableArtifacts::new(extra_output, self.extra_output_files.iter().copied())\n    }\n\n    /// Parses all libraries in the form of\n    /// `<file>:<lib>:<addr>`\n    pub fn parsed_libraries(&self) -> Result<Libraries, SolcError> {\n        Libraries::parse(&self.libraries)\n    }\n\n    /// Returns all libraries with applied remappings. Same as `self.solc_settings()?.libraries`.\n    pub fn libraries_with_remappings(&self) -> Result<Libraries, SolcError> {\n        let paths: ProjectPathsConfig = self.project_paths();\n        Ok(self.parsed_libraries()?.apply(|libs| paths.apply_lib_remappings(libs)))\n    }\n\n    /// Returns the configured `solc` `Settings` that includes:\n    /// - all libraries\n    /// - the optimizer (including details, if configured)\n    /// - evm version\n    pub fn solc_settings(&self) -> Result<SolcSettings, SolcError> {\n        // By default if no targets are specifically selected the model checker uses all targets.\n        // This might be too much here, so only enable assertion checks.\n        // If users wish to enable all options they need to do so explicitly.\n        let mut model_checker = self.model_checker.clone();\n        if let Some(model_checker_settings) = &mut model_checker\n            && model_checker_settings.targets.is_none()\n        {\n            model_checker_settings.targets = Some(vec![ModelCheckerTarget::Assert]);\n        }\n\n        let mut settings = Settings {\n            libraries: self.libraries_with_remappings()?,\n            optimizer: self.optimizer(),\n            evm_version: Some(self.evm_version),\n            metadata: Some(SettingsMetadata {\n                use_literal_content: Some(self.use_literal_content),\n                bytecode_hash: Some(self.bytecode_hash),\n                cbor_metadata: Some(self.cbor_metadata),\n            }),\n            debug: self.revert_strings.map(|revert_strings| DebuggingSettings {\n                revert_strings: Some(revert_strings),\n                // Not used.\n                debug_info: Vec::new(),\n            }),\n            model_checker,\n            via_ir: Some(self.via_ir),\n            // Not used.\n            stop_after: None,\n            // Set in project paths.\n            remappings: Vec::new(),\n            // Set with `with_extra_output` below.\n            output_selection: Default::default(),\n        }\n        .with_extra_output(self.configured_artifacts_handler().output_selection());\n\n        // We're keeping AST in `--build-info` for backwards compatibility with HardHat.\n        if self.ast || self.build_info {\n            settings = settings.with_ast();\n        }\n\n        let cli_settings =\n            CliSettings { extra_args: self.extra_args.clone(), ..Default::default() };\n\n        Ok(SolcSettings { settings, cli_settings })\n    }\n\n    /// Returns the configured [VyperSettings] that includes:\n    /// - evm version\n    pub fn vyper_settings(&self) -> Result<VyperSettings, SolcError> {\n        Ok(VyperSettings {\n            evm_version: Some(self.evm_version),\n            optimize: self.vyper.optimize,\n            bytecode_metadata: None,\n            // TODO: We don't yet have a way to deserialize other outputs correctly, so request only\n            // those for now. It should be enough to run tests and deploy contracts.\n            output_selection: OutputSelection::common_output_selection([\n                \"abi\".to_string(),\n                \"evm.bytecode\".to_string(),\n                \"evm.deployedBytecode\".to_string(),\n            ]),\n            search_paths: None,\n            experimental_codegen: self.vyper.experimental_codegen,\n        })\n    }\n\n    /// Returns the default figment\n    ///\n    /// The default figment reads from the following sources, in ascending\n    /// priority order:\n    ///\n    ///   1. [`Config::default()`] (see [defaults](#defaults))\n    ///   2. `foundry.toml` _or_ filename in `FOUNDRY_CONFIG` environment variable\n    ///   3. `FOUNDRY_` prefixed environment variables\n    ///\n    /// The profile selected is the value set in the `FOUNDRY_PROFILE`\n    /// environment variable. If it is not set, it defaults to `default`.\n    ///\n    /// # Example\n    ///\n    /// ```rust\n    /// use foundry_config::Config;\n    /// use serde::Deserialize;\n    ///\n    /// let my_config = Config::figment().extract::<Config>();\n    /// ```\n    pub fn figment() -> Figment {\n        Self::default().into()\n    }\n\n    /// Returns the default figment enhanced with additional context extracted from the provided\n    /// root, like remappings and directories.\n    ///\n    /// # Example\n    ///\n    /// ```rust\n    /// use foundry_config::Config;\n    /// use serde::Deserialize;\n    ///\n    /// let my_config = Config::figment_with_root(\".\").extract::<Config>();\n    /// ```\n    pub fn figment_with_root(root: impl AsRef<Path>) -> Figment {\n        Self::with_root(root.as_ref()).into()\n    }\n\n    #[doc(hidden)]\n    #[track_caller]\n    pub fn figment_with_root_opt(root: Option<&Path>) -> Figment {\n        let root = match root {\n            Some(root) => root,\n            None => &find_project_root(None).expect(\"could not determine project root\"),\n        };\n        Self::figment_with_root(root)\n    }\n\n    /// Creates a new Config that adds additional context extracted from the provided root.\n    ///\n    /// # Example\n    ///\n    /// ```rust\n    /// use foundry_config::Config;\n    /// let my_config = Config::with_root(\".\");\n    /// ```\n    pub fn with_root(root: impl AsRef<Path>) -> Self {\n        Self::_with_root(root.as_ref())\n    }\n\n    fn _with_root(root: &Path) -> Self {\n        // autodetect paths\n        let paths = ProjectPathsConfig::builder().build_with_root::<()>(root);\n        let artifacts: PathBuf = paths.artifacts.file_name().unwrap().into();\n        Self {\n            root: paths.root,\n            src: paths.sources.file_name().unwrap().into(),\n            out: artifacts.clone(),\n            libs: paths.libraries.into_iter().map(|lib| lib.file_name().unwrap().into()).collect(),\n            fs_permissions: FsPermissions::new([PathPermission::read(artifacts)]),\n            ..Self::default()\n        }\n    }\n\n    /// Returns the default config but with hardhat paths\n    pub fn hardhat() -> Self {\n        Self {\n            src: \"contracts\".into(),\n            out: \"artifacts\".into(),\n            libs: vec![\"node_modules\".into()],\n            ..Self::default()\n        }\n    }\n\n    /// Extracts a basic subset of the config, used for initialisations.\n    ///\n    /// # Example\n    ///\n    /// ```rust\n    /// use foundry_config::Config;\n    /// let my_config = Config::with_root(\".\").into_basic();\n    /// ```\n    pub fn into_basic(self) -> BasicConfig {\n        BasicConfig {\n            profile: self.profile,\n            src: self.src,\n            out: self.out,\n            libs: self.libs,\n            remappings: self.remappings,\n        }\n    }\n\n    /// Updates the `foundry.toml` file for the given `root` based on the provided closure.\n    ///\n    /// **Note:** the closure will only be invoked if the `foundry.toml` file exists, See\n    /// [Self::get_config_path()] and if the closure returns `true`.\n    pub fn update_at<F>(root: &Path, f: F) -> eyre::Result<()>\n    where\n        F: FnOnce(&Self, &mut toml_edit::DocumentMut) -> bool,\n    {\n        let config = Self::load_with_root(root)?.sanitized();\n        config.update(|doc| f(&config, doc))\n    }\n\n    /// Updates the `foundry.toml` file this `Config` ias based on with the provided closure.\n    ///\n    /// **Note:** the closure will only be invoked if the `foundry.toml` file exists, See\n    /// [Self::get_config_path()] and if the closure returns `true`\n    pub fn update<F>(&self, f: F) -> eyre::Result<()>\n    where\n        F: FnOnce(&mut toml_edit::DocumentMut) -> bool,\n    {\n        let file_path = self.get_config_path();\n        if !file_path.exists() {\n            return Ok(());\n        }\n        let contents = fs::read_to_string(&file_path)?;\n        let mut doc = contents.parse::<toml_edit::DocumentMut>()?;\n        if f(&mut doc) {\n            fs::write(file_path, doc.to_string())?;\n        }\n        Ok(())\n    }\n\n    /// Sets the `libs` entry inside a `foundry.toml` file but only if it exists\n    ///\n    /// # Errors\n    ///\n    /// An error if the `foundry.toml` could not be parsed.\n    pub fn update_libs(&self) -> eyre::Result<()> {\n        self.update(|doc| {\n            let profile = self.profile.as_str().as_str();\n            let root = &self.root;\n            let libs: toml_edit::Value = self\n                .libs\n                .iter()\n                .map(|path| {\n                    let path =\n                        if let Ok(relative) = path.strip_prefix(root) { relative } else { path };\n                    toml_edit::Value::from(&*path.to_string_lossy())\n                })\n                .collect();\n            let libs = toml_edit::value(libs);\n            doc[Self::PROFILE_SECTION][profile][\"libs\"] = libs;\n            true\n        })\n    }\n\n    /// Serialize the config type as a String of TOML.\n    ///\n    /// This serializes to a table with the name of the profile\n    ///\n    /// ```toml\n    /// [profile.default]\n    /// src = \"src\"\n    /// out = \"out\"\n    /// libs = [\"lib\"]\n    /// # ...\n    /// ```\n    pub fn to_string_pretty(&self) -> Result<String, toml::ser::Error> {\n        // serializing to value first to prevent `ValueAfterTable` errors\n        let mut value = toml::Value::try_from(self)?;\n        // Config map always gets serialized as a table\n        let value_table = value.as_table_mut().unwrap();\n        // remove standalone sections from inner table\n        let standalone_sections = Self::STANDALONE_SECTIONS\n            .iter()\n            .filter_map(|section| {\n                let section = section.to_string();\n                value_table.remove(&section).map(|value| (section, value))\n            })\n            .collect::<Vec<_>>();\n        // wrap inner table in [profile.<profile>]\n        let mut wrapping_table = [(\n            Self::PROFILE_SECTION.into(),\n            toml::Value::Table([(self.profile.to_string(), value)].into_iter().collect()),\n        )]\n        .into_iter()\n        .collect::<toml::map::Map<_, _>>();\n        // insert standalone sections\n        for (section, value) in standalone_sections {\n            wrapping_table.insert(section, value);\n        }\n        // stringify\n        toml::to_string_pretty(&toml::Value::Table(wrapping_table))\n    }\n\n    /// Returns the path to the `foundry.toml` of this `Config`.\n    pub fn get_config_path(&self) -> PathBuf {\n        self.root.join(Self::FILE_NAME)\n    }\n\n    /// Returns the selected profile.\n    ///\n    /// If the `FOUNDRY_PROFILE` env variable is not set, this returns the `DEFAULT_PROFILE`.\n    pub fn selected_profile() -> Profile {\n        // Can't cache in tests because the env var can change.\n        #[cfg(test)]\n        {\n            Self::force_selected_profile()\n        }\n        #[cfg(not(test))]\n        {\n            static CACHE: std::sync::OnceLock<Profile> = std::sync::OnceLock::new();\n            CACHE.get_or_init(Self::force_selected_profile).clone()\n        }\n    }\n\n    fn force_selected_profile() -> Profile {\n        Profile::from_env_or(\"FOUNDRY_PROFILE\", Self::DEFAULT_PROFILE)\n    }\n\n    /// Returns the path to foundry's global TOML file: `~/.foundry/foundry.toml`.\n    pub fn foundry_dir_toml() -> Option<PathBuf> {\n        Self::foundry_dir().map(|p| p.join(Self::FILE_NAME))\n    }\n\n    /// Returns the path to foundry's config dir: `~/.foundry/`.\n    pub fn foundry_dir() -> Option<PathBuf> {\n        dirs::home_dir().map(|p| p.join(Self::FOUNDRY_DIR_NAME))\n    }\n\n    /// Returns the path to foundry's cache dir: `~/.foundry/cache`.\n    pub fn foundry_cache_dir() -> Option<PathBuf> {\n        Self::foundry_dir().map(|p| p.join(\"cache\"))\n    }\n\n    /// Returns the path to foundry rpc cache dir: `~/.foundry/cache/rpc`.\n    pub fn foundry_rpc_cache_dir() -> Option<PathBuf> {\n        Some(Self::foundry_cache_dir()?.join(\"rpc\"))\n    }\n    /// Returns the path to foundry chain's cache dir: `~/.foundry/cache/rpc/<chain>`\n    pub fn foundry_chain_cache_dir(chain_id: impl Into<Chain>) -> Option<PathBuf> {\n        Some(Self::foundry_rpc_cache_dir()?.join(chain_id.into().to_string()))\n    }\n\n    /// Returns the path to foundry's etherscan cache dir: `~/.foundry/cache/etherscan`.\n    pub fn foundry_etherscan_cache_dir() -> Option<PathBuf> {\n        Some(Self::foundry_cache_dir()?.join(\"etherscan\"))\n    }\n\n    /// Returns the path to foundry's keystores dir: `~/.foundry/keystores`.\n    pub fn foundry_keystores_dir() -> Option<PathBuf> {\n        Some(Self::foundry_dir()?.join(\"keystores\"))\n    }\n\n    /// Returns the path to foundry's etherscan cache dir for `chain_id`:\n    /// `~/.foundry/cache/etherscan/<chain>`\n    pub fn foundry_etherscan_chain_cache_dir(chain_id: impl Into<Chain>) -> Option<PathBuf> {\n        Some(Self::foundry_etherscan_cache_dir()?.join(chain_id.into().to_string()))\n    }\n\n    /// Returns the path to the cache dir of the `block` on the `chain`:\n    /// `~/.foundry/cache/rpc/<chain>/<block>`\n    pub fn foundry_block_cache_dir(chain_id: impl Into<Chain>, block: u64) -> Option<PathBuf> {\n        Some(Self::foundry_chain_cache_dir(chain_id)?.join(format!(\"{block}\")))\n    }\n\n    /// Returns the path to the cache file of the `block` on the `chain`:\n    /// `~/.foundry/cache/rpc/<chain>/<block>/storage.json`\n    pub fn foundry_block_cache_file(chain_id: impl Into<Chain>, block: u64) -> Option<PathBuf> {\n        Some(Self::foundry_block_cache_dir(chain_id, block)?.join(\"storage.json\"))\n    }\n\n    /// Returns the path to `foundry`'s data directory inside the user's data directory.\n    ///\n    /// | Platform | Value                                         | Example                                          |\n    /// | -------  | --------------------------------------------- | ------------------------------------------------ |\n    /// | Linux    | `$XDG_CONFIG_HOME` or `$HOME`/.config/foundry | /home/alice/.config/foundry                      |\n    /// | macOS    | `$HOME`/Library/Application Support/foundry   | /Users/Alice/Library/Application Support/foundry |\n    /// | Windows  | `{FOLDERID_RoamingAppData}/foundry`           | C:\\Users\\Alice\\AppData\\Roaming/foundry           |\n    pub fn data_dir() -> eyre::Result<PathBuf> {\n        let path = dirs::data_dir().wrap_err(\"Failed to find data directory\")?.join(\"foundry\");\n        std::fs::create_dir_all(&path).wrap_err(\"Failed to create module directory\")?;\n        Ok(path)\n    }\n\n    /// Returns the path to the `foundry.toml` file, the file is searched for in\n    /// the current working directory and all parent directories until the root,\n    /// and the first hit is used.\n    ///\n    /// If this search comes up empty, then it checks if a global `foundry.toml` exists at\n    /// `~/.foundry/foundry.toml`, see [`Self::foundry_dir_toml`].\n    pub fn find_config_file() -> Option<PathBuf> {\n        fn find(path: &Path) -> Option<PathBuf> {\n            if path.is_absolute() {\n                return match path.is_file() {\n                    true => Some(path.to_path_buf()),\n                    false => None,\n                };\n            }\n            let cwd = std::env::current_dir().ok()?;\n            let mut cwd = cwd.as_path();\n            loop {\n                let file_path = cwd.join(path);\n                if file_path.is_file() {\n                    return Some(file_path);\n                }\n                cwd = cwd.parent()?;\n            }\n        }\n        find(Env::var_or(\"FOUNDRY_CONFIG\", Self::FILE_NAME).as_ref())\n            .or_else(|| Self::foundry_dir_toml().filter(|p| p.exists()))\n    }\n\n    /// Clears the foundry cache.\n    pub fn clean_foundry_cache() -> eyre::Result<()> {\n        if let Some(cache_dir) = Self::foundry_cache_dir() {\n            let path = cache_dir.as_path();\n            let _ = fs::remove_dir_all(path);\n        } else {\n            eyre::bail!(\"failed to get foundry_cache_dir\");\n        }\n\n        Ok(())\n    }\n\n    /// Clears the foundry cache for `chain`.\n    pub fn clean_foundry_chain_cache(chain: Chain) -> eyre::Result<()> {\n        if let Some(cache_dir) = Self::foundry_chain_cache_dir(chain) {\n            let path = cache_dir.as_path();\n            let _ = fs::remove_dir_all(path);\n        } else {\n            eyre::bail!(\"failed to get foundry_chain_cache_dir\");\n        }\n\n        Ok(())\n    }\n\n    /// Clears the foundry cache for `chain` and `block`.\n    pub fn clean_foundry_block_cache(chain: Chain, block: u64) -> eyre::Result<()> {\n        if let Some(cache_dir) = Self::foundry_block_cache_dir(chain, block) {\n            let path = cache_dir.as_path();\n            let _ = fs::remove_dir_all(path);\n        } else {\n            eyre::bail!(\"failed to get foundry_block_cache_dir\");\n        }\n\n        Ok(())\n    }\n\n    /// Clears the foundry etherscan cache.\n    pub fn clean_foundry_etherscan_cache() -> eyre::Result<()> {\n        if let Some(cache_dir) = Self::foundry_etherscan_cache_dir() {\n            let path = cache_dir.as_path();\n            let _ = fs::remove_dir_all(path);\n        } else {\n            eyre::bail!(\"failed to get foundry_etherscan_cache_dir\");\n        }\n\n        Ok(())\n    }\n\n    /// Clears the foundry etherscan cache for `chain`.\n    pub fn clean_foundry_etherscan_chain_cache(chain: Chain) -> eyre::Result<()> {\n        if let Some(cache_dir) = Self::foundry_etherscan_chain_cache_dir(chain) {\n            let path = cache_dir.as_path();\n            let _ = fs::remove_dir_all(path);\n        } else {\n            eyre::bail!(\"failed to get foundry_etherscan_cache_dir for chain: {}\", chain);\n        }\n\n        Ok(())\n    }\n\n    /// List the data in the foundry cache.\n    pub fn list_foundry_cache() -> eyre::Result<Cache> {\n        if let Some(cache_dir) = Self::foundry_rpc_cache_dir() {\n            let mut cache = Cache { chains: vec![] };\n            if !cache_dir.exists() {\n                return Ok(cache);\n            }\n            if let Ok(entries) = cache_dir.as_path().read_dir() {\n                for entry in entries.flatten().filter(|x| x.path().is_dir()) {\n                    match Chain::from_str(&entry.file_name().to_string_lossy()) {\n                        Ok(chain) => cache.chains.push(Self::list_foundry_chain_cache(chain)?),\n                        Err(_) => continue,\n                    }\n                }\n                Ok(cache)\n            } else {\n                eyre::bail!(\"failed to access foundry_cache_dir\");\n            }\n        } else {\n            eyre::bail!(\"failed to get foundry_cache_dir\");\n        }\n    }\n\n    /// List the cached data for `chain`.\n    pub fn list_foundry_chain_cache(chain: Chain) -> eyre::Result<ChainCache> {\n        let block_explorer_data_size = match Self::foundry_etherscan_chain_cache_dir(chain) {\n            Some(cache_dir) => Self::get_cached_block_explorer_data(&cache_dir)?,\n            None => {\n                warn!(\"failed to access foundry_etherscan_chain_cache_dir\");\n                0\n            }\n        };\n\n        if let Some(cache_dir) = Self::foundry_chain_cache_dir(chain) {\n            let blocks = Self::get_cached_blocks(&cache_dir)?;\n            Ok(ChainCache {\n                name: chain.to_string(),\n                blocks,\n                block_explorer: block_explorer_data_size,\n            })\n        } else {\n            eyre::bail!(\"failed to get foundry_chain_cache_dir\");\n        }\n    }\n\n    /// The path provided to this function should point to a cached chain folder.\n    fn get_cached_blocks(chain_path: &Path) -> eyre::Result<Vec<(String, u64)>> {\n        let mut blocks = vec![];\n        if !chain_path.exists() {\n            return Ok(blocks);\n        }\n        for block in chain_path.read_dir()?.flatten() {\n            let file_type = block.file_type()?;\n            let file_name = block.file_name();\n            let filepath = if file_type.is_dir() {\n                block.path().join(\"storage.json\")\n            } else if file_type.is_file()\n                && file_name.to_string_lossy().chars().all(char::is_numeric)\n            {\n                block.path()\n            } else {\n                continue;\n            };\n            blocks.push((file_name.to_string_lossy().into_owned(), fs::metadata(filepath)?.len()));\n        }\n        Ok(blocks)\n    }\n\n    /// The path provided to this function should point to the etherscan cache for a chain.\n    fn get_cached_block_explorer_data(chain_path: &Path) -> eyre::Result<u64> {\n        if !chain_path.exists() {\n            return Ok(0);\n        }\n\n        fn dir_size_recursive(mut dir: fs::ReadDir) -> eyre::Result<u64> {\n            dir.try_fold(0, |acc, file| {\n                let file = file?;\n                let size = match file.metadata()? {\n                    data if data.is_dir() => dir_size_recursive(fs::read_dir(file.path())?)?,\n                    data => data.len(),\n                };\n                Ok(acc + size)\n            })\n        }\n\n        dir_size_recursive(fs::read_dir(chain_path)?)\n    }\n\n    fn merge_toml_provider(\n        mut figment: Figment,\n        toml_provider: impl Provider,\n        profile: Profile,\n    ) -> Figment {\n        figment = figment.select(profile.clone());\n\n        // add warnings\n        figment = {\n            let warnings = WarningsProvider::for_figment(&toml_provider, &figment);\n            figment.merge(warnings)\n        };\n\n        // use [profile.<profile>] as [<profile>]\n        let mut profiles = vec![Self::DEFAULT_PROFILE];\n        if profile != Self::DEFAULT_PROFILE {\n            profiles.push(profile.clone());\n        }\n        let provider = toml_provider.strict_select(profiles);\n\n        // apply any key fixes\n        let provider = &BackwardsCompatTomlProvider(ForcedSnakeCaseData(provider));\n\n        // merge the default profile as a base\n        if profile != Self::DEFAULT_PROFILE {\n            figment = figment.merge(provider.rename(Self::DEFAULT_PROFILE, profile.clone()));\n        }\n        // merge special keys into config\n        for standalone_key in Self::STANDALONE_SECTIONS {\n            if let Some((_, fallback)) =\n                STANDALONE_FALLBACK_SECTIONS.iter().find(|(key, _)| standalone_key == key)\n            {\n                figment = figment.merge(\n                    provider\n                        .fallback(standalone_key, fallback)\n                        .wrap(profile.clone(), standalone_key),\n                );\n            } else {\n                figment = figment.merge(provider.wrap(profile.clone(), standalone_key));\n            }\n        }\n        // merge the profile\n        figment = figment.merge(provider);\n        figment\n    }\n\n    /// Check if any defaults need to be normalized.\n    ///\n    /// This normalizes the default `evm_version` if a `solc` was provided in the config.\n    ///\n    /// See also <https://github.com/foundry-rs/foundry/issues/7014>\n    fn normalize_defaults(&self, mut figment: Figment) -> Figment {\n        if figment.contains(\"evm_version\") {\n            return figment;\n        }\n\n        // Normalize `evm_version` based on the provided solc version.\n        if let Ok(solc) = figment.extract_inner::<SolcReq>(\"solc\")\n            && let Some(version) = solc\n                .try_version()\n                .ok()\n                .and_then(|version| self.evm_version.normalize_version_solc(&version))\n        {\n            figment = figment.merge((\"evm_version\", version));\n        }\n\n        // Normalize `deny` based on the provided `deny_warnings` value.\n        if figment.extract_inner::<bool>(\"deny_warnings\").unwrap_or(false)\n            && let Ok(DenyLevel::Never) = figment.extract_inner(\"deny\")\n        {\n            figment = figment.merge((\"deny\", DenyLevel::Warnings));\n        }\n\n        figment\n    }\n}\n\nimpl From<Config> for Figment {\n    fn from(c: Config) -> Self {\n        (&c).into()\n    }\n}\nimpl From<&Config> for Figment {\n    fn from(c: &Config) -> Self {\n        c.to_figment(FigmentProviders::All)\n    }\n}\n\n/// Determines what providers should be used when loading the [`Figment`] for a [`Config`].\n#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]\npub enum FigmentProviders {\n    /// Include all providers.\n    #[default]\n    All,\n    /// Only include necessary providers that are useful for cast commands.\n    ///\n    /// This will exclude more expensive providers such as remappings.\n    Cast,\n    /// Only include necessary providers that are useful for anvil.\n    ///\n    /// This will exclude more expensive providers such as remappings.\n    Anvil,\n    /// Don't include any providers.\n    None,\n}\n\nimpl FigmentProviders {\n    /// Returns true if all providers should be included.\n    pub const fn is_all(&self) -> bool {\n        matches!(self, Self::All)\n    }\n\n    /// Returns true if this is the cast preset.\n    pub const fn is_cast(&self) -> bool {\n        matches!(self, Self::Cast)\n    }\n\n    /// Returns true if this is the anvil preset.\n    pub const fn is_anvil(&self) -> bool {\n        matches!(self, Self::Anvil)\n    }\n\n    /// Returns true if no providers should be included.\n    pub const fn is_none(&self) -> bool {\n        matches!(self, Self::None)\n    }\n}\n\n/// Wrapper type for [`regex::Regex`] that implements [`PartialEq`] and [`serde`] traits.\n#[derive(Clone, Debug, Serialize, Deserialize)]\n#[serde(transparent)]\npub struct RegexWrapper {\n    #[serde(with = \"serde_regex\")]\n    inner: regex::Regex,\n}\n\nimpl std::ops::Deref for RegexWrapper {\n    type Target = regex::Regex;\n\n    fn deref(&self) -> &Self::Target {\n        &self.inner\n    }\n}\n\nimpl std::cmp::PartialEq for RegexWrapper {\n    fn eq(&self, other: &Self) -> bool {\n        self.as_str() == other.as_str()\n    }\n}\n\nimpl Eq for RegexWrapper {}\n\nimpl From<RegexWrapper> for regex::Regex {\n    fn from(wrapper: RegexWrapper) -> Self {\n        wrapper.inner\n    }\n}\n\nimpl From<regex::Regex> for RegexWrapper {\n    fn from(re: Regex) -> Self {\n        Self { inner: re }\n    }\n}\n\nmod serde_regex {\n    use regex::Regex;\n    use serde::{Deserialize, Deserializer, Serializer};\n\n    pub(crate) fn serialize<S>(value: &Regex, serializer: S) -> Result<S::Ok, S::Error>\n    where\n        S: Serializer,\n    {\n        serializer.serialize_str(value.as_str())\n    }\n\n    pub(crate) fn deserialize<'de, D>(deserializer: D) -> Result<Regex, D::Error>\n    where\n        D: Deserializer<'de>,\n    {\n        let s = String::deserialize(deserializer)?;\n        Regex::new(&s).map_err(serde::de::Error::custom)\n    }\n}\n\n/// Ser/de `globset::Glob` explicitly to handle `Option<Glob>` properly\npub(crate) mod from_opt_glob {\n    use serde::{Deserialize, Deserializer, Serializer};\n\n    pub fn serialize<S>(value: &Option<globset::Glob>, serializer: S) -> Result<S::Ok, S::Error>\n    where\n        S: Serializer,\n    {\n        match value {\n            Some(glob) => serializer.serialize_str(glob.glob()),\n            None => serializer.serialize_none(),\n        }\n    }\n\n    pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<globset::Glob>, D::Error>\n    where\n        D: Deserializer<'de>,\n    {\n        let s: Option<String> = Option::deserialize(deserializer)?;\n        if let Some(s) = s {\n            return Ok(Some(globset::Glob::new(&s).map_err(serde::de::Error::custom)?));\n        }\n        Ok(None)\n    }\n}\n\n/// Parses a config profile\n///\n/// All `Profile` date is ignored by serde, however the `Config::to_string_pretty` includes it and\n/// returns a toml table like\n///\n/// ```toml\n/// #[profile.default]\n/// src = \"...\"\n/// ```\n/// This ignores the `#[profile.default]` part in the toml\npub fn parse_with_profile<T: serde::de::DeserializeOwned>(\n    s: &str,\n) -> Result<Option<(Profile, T)>, Error> {\n    let figment = Config::merge_toml_provider(\n        Figment::new(),\n        Toml::string(s).nested(),\n        Config::DEFAULT_PROFILE,\n    );\n    if figment.profiles().any(|p| p == Config::DEFAULT_PROFILE) {\n        Ok(Some((Config::DEFAULT_PROFILE, figment.select(Config::DEFAULT_PROFILE).extract()?)))\n    } else {\n        Ok(None)\n    }\n}\n\nimpl Provider for Config {\n    fn metadata(&self) -> Metadata {\n        Metadata::named(\"Foundry Config\")\n    }\n\n    #[track_caller]\n    fn data(&self) -> Result<Map<Profile, Dict>, figment::Error> {\n        let mut data = Serialized::defaults(self).data()?;\n        if let Some(entry) = data.get_mut(&self.profile) {\n            entry.insert(\"root\".to_string(), Value::serialize(self.root.clone())?);\n        }\n        Ok(data)\n    }\n\n    fn profile(&self) -> Option<Profile> {\n        Some(self.profile.clone())\n    }\n}\n\nimpl Default for Config {\n    fn default() -> Self {\n        Self {\n            profile: Self::DEFAULT_PROFILE,\n            profiles: vec![Self::DEFAULT_PROFILE],\n            fs_permissions: FsPermissions::new([PathPermission::read(\"out\")]),\n            isolate: cfg!(feature = \"isolate-by-default\"),\n            root: root_default(),\n            extends: None,\n            src: \"src\".into(),\n            test: \"test\".into(),\n            script: \"script\".into(),\n            out: \"out\".into(),\n            libs: vec![\"lib\".into()],\n            cache: true,\n            dynamic_test_linking: false,\n            cache_path: \"cache\".into(),\n            broadcast: \"broadcast\".into(),\n            snapshots: \"snapshots\".into(),\n            gas_snapshot_check: false,\n            gas_snapshot_emit: true,\n            allow_paths: vec![],\n            include_paths: vec![],\n            force: false,\n            evm_version: EvmVersion::Osaka,\n            gas_reports: vec![\"*\".to_string()],\n            gas_reports_ignore: vec![],\n            gas_reports_include_tests: false,\n            solc: None,\n            vyper: Default::default(),\n            auto_detect_solc: true,\n            offline: false,\n            optimizer: None,\n            optimizer_runs: None,\n            optimizer_details: None,\n            model_checker: None,\n            extra_output: Default::default(),\n            extra_output_files: Default::default(),\n            names: false,\n            sizes: false,\n            test_pattern: None,\n            test_pattern_inverse: None,\n            contract_pattern: None,\n            contract_pattern_inverse: None,\n            path_pattern: None,\n            path_pattern_inverse: None,\n            coverage_pattern_inverse: None,\n            test_failures_file: \"cache/test-failures\".into(),\n            threads: None,\n            show_progress: false,\n            fuzz: FuzzConfig::new(\"cache/fuzz\".into()),\n            invariant: InvariantConfig::new(\"cache/invariant\".into()),\n            always_use_create_2_factory: false,\n            ffi: false,\n            live_logs: false,\n            allow_internal_expect_revert: false,\n            prompt_timeout: 120,\n            sender: Self::DEFAULT_SENDER,\n            tx_origin: Self::DEFAULT_SENDER,\n            initial_balance: U256::from((1u128 << 96) - 1),\n            block_number: U256::from(1),\n            fork_block_number: None,\n            chain: None,\n            gas_limit: (1u64 << 30).into(), // ~1B\n            code_size_limit: None,\n            gas_price: None,\n            block_base_fee_per_gas: 0,\n            block_coinbase: Address::ZERO,\n            block_timestamp: U256::from(1),\n            block_difficulty: 0,\n            block_prevrandao: Default::default(),\n            block_gas_limit: None,\n            disable_block_gas_limit: false,\n            enable_tx_gas_limit: false,\n            memory_limit: 1 << 27, // 2**27 = 128MiB = 134_217_728 bytes\n            eth_rpc_url: None,\n            eth_rpc_accept_invalid_certs: false,\n            eth_rpc_no_proxy: false,\n            eth_rpc_jwt: None,\n            eth_rpc_timeout: None,\n            eth_rpc_headers: None,\n            eth_rpc_curl: false,\n            etherscan_api_key: None,\n            verbosity: 0,\n            remappings: vec![],\n            auto_detect_remappings: true,\n            libraries: vec![],\n            ignored_error_codes: vec![\n                SolidityErrorCode::SpdxLicenseNotProvided,\n                SolidityErrorCode::ContractExceeds24576Bytes,\n                SolidityErrorCode::ContractInitCodeSizeExceeds49152Bytes,\n                SolidityErrorCode::TransientStorageUsed,\n                SolidityErrorCode::TransferDeprecated,\n                SolidityErrorCode::NatspecMemorySafeAssemblyDeprecated,\n            ],\n            ignored_file_paths: vec![],\n            deny: DenyLevel::Never,\n            deny_warnings: false,\n            via_ir: false,\n            ast: false,\n            rpc_storage_caching: Default::default(),\n            rpc_endpoints: Default::default(),\n            etherscan: Default::default(),\n            no_storage_caching: false,\n            no_rpc_rate_limit: false,\n            use_literal_content: false,\n            bytecode_hash: BytecodeHash::Ipfs,\n            cbor_metadata: true,\n            revert_strings: None,\n            sparse_mode: false,\n            build_info: false,\n            build_info_path: None,\n            fmt: Default::default(),\n            lint: Default::default(),\n            doc: Default::default(),\n            bind_json: Default::default(),\n            labels: Default::default(),\n            unchecked_cheatcode_artifacts: false,\n            create2_library_salt: Self::DEFAULT_CREATE2_LIBRARY_SALT,\n            create2_deployer: Self::DEFAULT_CREATE2_DEPLOYER,\n            skip: vec![],\n            dependencies: Default::default(),\n            soldeer: Default::default(),\n            assertions_revert: true,\n            legacy_assertions: false,\n            warnings: vec![],\n            extra_args: vec![],\n            networks: Default::default(),\n            transaction_timeout: 120,\n            additional_compiler_profiles: Default::default(),\n            compilation_restrictions: Default::default(),\n            script_execution_protection: true,\n            _non_exhaustive: (),\n        }\n    }\n}\n\n/// Wrapper for the config's `gas_limit` value necessary because toml-rs can't handle larger number\n/// because integers are stored signed: <https://github.com/alexcrichton/toml-rs/issues/256>\n///\n/// Due to this limitation this type will be serialized/deserialized as String if it's larger than\n/// `i64`\n#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Deserialize)]\npub struct GasLimit(#[serde(deserialize_with = \"crate::deserialize_u64_or_max\")] pub u64);\n\nimpl From<u64> for GasLimit {\n    fn from(gas: u64) -> Self {\n        Self(gas)\n    }\n}\n\nimpl From<GasLimit> for u64 {\n    fn from(gas: GasLimit) -> Self {\n        gas.0\n    }\n}\n\nimpl Serialize for GasLimit {\n    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>\n    where\n        S: Serializer,\n    {\n        if self.0 == u64::MAX {\n            serializer.serialize_str(\"max\")\n        } else if self.0 > i64::MAX as u64 {\n            serializer.serialize_str(&self.0.to_string())\n        } else {\n            serializer.serialize_u64(self.0)\n        }\n    }\n}\n\n/// Variants for selecting the [`Solc`] instance\n#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]\n#[serde(untagged)]\npub enum SolcReq {\n    /// Requires a specific solc version, that's either already installed (via `svm`) or will be\n    /// auto installed (via `svm`)\n    Version(Version),\n    /// Path to an existing local solc installation\n    Local(PathBuf),\n}\n\nimpl SolcReq {\n    /// Tries to get the solc version from the `SolcReq`\n    ///\n    /// If the `SolcReq` is a `Version` it will return the version, if it's a path to a binary it\n    /// will try to get the version from the binary.\n    fn try_version(&self) -> Result<Version, SolcError> {\n        match self {\n            Self::Version(version) => Ok(version.clone()),\n            Self::Local(path) => Solc::new(path).map(|solc| solc.version),\n        }\n    }\n}\n\nimpl<T: AsRef<str>> From<T> for SolcReq {\n    fn from(s: T) -> Self {\n        let s = s.as_ref();\n        if let Ok(v) = Version::from_str(s) { Self::Version(v) } else { Self::Local(s.into()) }\n    }\n}\n\n/// A subset of the foundry `Config`\n/// used to initialize a `foundry.toml` file\n///\n/// # Example\n///\n/// ```rust\n/// use foundry_config::{BasicConfig, Config};\n/// use serde::Deserialize;\n///\n/// let my_config = Config::figment().extract::<BasicConfig>();\n/// ```\n#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]\npub struct BasicConfig {\n    /// the profile tag: `[profile.default]`\n    #[serde(skip)]\n    pub profile: Profile,\n    /// path of the source contracts dir, like `src` or `contracts`\n    pub src: PathBuf,\n    /// path to where artifacts shut be written to\n    pub out: PathBuf,\n    /// all library folders to include, `lib`, `node_modules`\n    pub libs: Vec<PathBuf>,\n    /// `Remappings` to use for this repo\n    #[serde(default, skip_serializing_if = \"Vec::is_empty\")]\n    pub remappings: Vec<RelativeRemapping>,\n}\n\nimpl BasicConfig {\n    /// Serialize the config as a String of TOML.\n    ///\n    /// This serializes to a table with the name of the profile\n    pub fn to_string_pretty(&self) -> Result<String, toml::ser::Error> {\n        let s = toml::to_string_pretty(self)?;\n        Ok(format!(\n            \"\\\n[profile.{}]\n{s}\n# See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options\\n\",\n            self.profile\n        ))\n    }\n}\n\npub(crate) mod from_str_lowercase {\n    use serde::{Deserialize, Deserializer, Serializer};\n    use std::str::FromStr;\n\n    pub fn serialize<T, S>(value: &T, serializer: S) -> Result<S::Ok, S::Error>\n    where\n        T: std::fmt::Display,\n        S: Serializer,\n    {\n        serializer.collect_str(&value.to_string().to_lowercase())\n    }\n\n    pub fn deserialize<'de, T, D>(deserializer: D) -> Result<T, D::Error>\n    where\n        D: Deserializer<'de>,\n        T: FromStr,\n        T::Err: std::fmt::Display,\n    {\n        String::deserialize(deserializer)?.to_lowercase().parse().map_err(serde::de::Error::custom)\n    }\n}\n\nfn canonic(path: impl Into<PathBuf>) -> PathBuf {\n    let path = path.into();\n    foundry_compilers::utils::canonicalize(&path).unwrap_or(path)\n}\n\nfn root_default() -> PathBuf {\n    \".\".into()\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use crate::{\n        cache::{CachedChains, CachedEndpoints},\n        endpoints::RpcEndpointType,\n        etherscan::ResolvedEtherscanConfigs,\n        fmt::IndentStyle,\n    };\n    use NamedChain::Moonbeam;\n    use endpoints::{RpcAuth, RpcEndpointConfig};\n    use figment::error::Kind::InvalidType;\n    use foundry_compilers::artifacts::{\n        ModelCheckerEngine, YulDetails, vyper::VyperOptimizationMode,\n    };\n    use similar_asserts::assert_eq;\n    use soldeer_core::remappings::RemappingsLocation;\n    use std::{fs::File, io::Write};\n    use tempfile::tempdir;\n\n    // Helper function to clear `__warnings` in config, since it will be populated during loading\n    // from file, causing testing problem when comparing to those created from `default()`, etc.\n    fn clear_warning(config: &mut Config) {\n        config.warnings = vec![];\n    }\n\n    #[test]\n    fn default_sender() {\n        assert_eq!(Config::DEFAULT_SENDER, address!(\"0x1804c8AB1F12E6bbf3894d4083f33e07309d1f38\"));\n    }\n\n    #[test]\n    fn test_caching() {\n        let mut config = Config::default();\n        let chain_id = NamedChain::Mainnet;\n        let url = \"https://eth-mainnet.alchemyapi\";\n        assert!(config.enable_caching(url, chain_id));\n\n        config.no_storage_caching = true;\n        assert!(!config.enable_caching(url, chain_id));\n\n        config.no_storage_caching = false;\n        assert!(!config.enable_caching(url, NamedChain::Dev));\n    }\n\n    #[test]\n    fn test_install_dir() {\n        figment::Jail::expect_with(|jail| {\n            let config = Config::load().unwrap();\n            assert_eq!(config.install_lib_dir(), PathBuf::from(\"lib\"));\n            jail.create_file(\n                \"foundry.toml\",\n                r\"\n                [profile.default]\n                libs = ['node_modules', 'lib']\n            \",\n            )?;\n            let config = Config::load().unwrap();\n            assert_eq!(config.install_lib_dir(), PathBuf::from(\"lib\"));\n\n            jail.create_file(\n                \"foundry.toml\",\n                r\"\n                [profile.default]\n                libs = ['custom', 'node_modules', 'lib']\n            \",\n            )?;\n            let config = Config::load().unwrap();\n            assert_eq!(config.install_lib_dir(), PathBuf::from(\"custom\"));\n\n            Ok(())\n        });\n    }\n\n    #[test]\n    fn test_figment_is_default() {\n        figment::Jail::expect_with(|_| {\n            let mut default: Config = Config::figment().extract()?;\n            let default2 = Config::default();\n            default.profile = default2.profile.clone();\n            default.profiles = default2.profiles.clone();\n            assert_eq!(default, default2);\n            Ok(())\n        });\n    }\n\n    #[test]\n    fn figment_profiles() {\n        figment::Jail::expect_with(|jail| {\n            jail.create_file(\n                \"foundry.toml\",\n                r\"\n                [foo.baz]\n                libs = ['node_modules', 'lib']\n\n                [profile.default]\n                libs = ['node_modules', 'lib']\n\n                [profile.ci]\n                libs = ['node_modules', 'lib']\n\n                [profile.local]\n                libs = ['node_modules', 'lib']\n            \",\n            )?;\n\n            let config = crate::Config::load().unwrap();\n            let expected: &[figment::Profile] = &[\"ci\".into(), \"default\".into(), \"local\".into()];\n            assert_eq!(config.profiles, expected);\n\n            Ok(())\n        });\n    }\n\n    #[test]\n    fn test_default_round_trip() {\n        figment::Jail::expect_with(|_| {\n            let original = Config::figment();\n            let roundtrip = Figment::from(Config::from_provider(&original).unwrap());\n            for figment in &[original, roundtrip] {\n                let config = Config::from_provider(figment).unwrap();\n                assert_eq!(config, Config::default().normalized_optimizer_settings());\n            }\n            Ok(())\n        });\n    }\n\n    #[test]\n    fn ffi_env_disallowed() {\n        figment::Jail::expect_with(|jail| {\n            jail.set_env(\"FOUNDRY_FFI\", \"true\");\n            jail.set_env(\"FFI\", \"true\");\n            jail.set_env(\"DAPP_FFI\", \"true\");\n            let config = Config::load().unwrap();\n            assert!(!config.ffi);\n\n            Ok(())\n        });\n    }\n\n    #[test]\n    fn test_profile_env() {\n        figment::Jail::expect_with(|jail| {\n            jail.set_env(\"FOUNDRY_PROFILE\", \"default\");\n            let figment = Config::figment();\n            assert_eq!(figment.profile(), \"default\");\n\n            jail.set_env(\"FOUNDRY_PROFILE\", \"hardhat\");\n            let figment: Figment = Config::hardhat().into();\n            assert_eq!(figment.profile(), \"hardhat\");\n\n            jail.create_file(\n                \"foundry.toml\",\n                r\"\n                [profile.default]\n                libs = ['lib']\n                [profile.local]\n                libs = ['modules']\n            \",\n            )?;\n            jail.set_env(\"FOUNDRY_PROFILE\", \"local\");\n            let config = Config::load().unwrap();\n            assert_eq!(config.libs, vec![PathBuf::from(\"modules\")]);\n\n            Ok(())\n        });\n    }\n\n    #[test]\n    fn test_default_test_path() {\n        figment::Jail::expect_with(|_| {\n            let config = Config::default();\n            let paths_config = config.project_paths::<Solc>();\n            assert_eq!(paths_config.tests, PathBuf::from(r\"test\"));\n            Ok(())\n        });\n    }\n\n    #[test]\n    fn test_default_libs() {\n        figment::Jail::expect_with(|jail| {\n            let config = Config::load().unwrap();\n            assert_eq!(config.libs, vec![PathBuf::from(\"lib\")]);\n\n            fs::create_dir_all(jail.directory().join(\"node_modules\")).unwrap();\n            let config = Config::load().unwrap();\n            assert_eq!(config.libs, vec![PathBuf::from(\"node_modules\")]);\n\n            fs::create_dir_all(jail.directory().join(\"lib\")).unwrap();\n            let config = Config::load().unwrap();\n            assert_eq!(config.libs, vec![PathBuf::from(\"lib\"), PathBuf::from(\"node_modules\")]);\n\n            Ok(())\n        });\n    }\n\n    #[test]\n    fn test_inheritance_from_default_test_path() {\n        figment::Jail::expect_with(|jail| {\n            jail.create_file(\n                \"foundry.toml\",\n                r#\"\n                [profile.default]\n                test = \"defaulttest\"\n                src  = \"defaultsrc\"\n                libs = ['lib', 'node_modules']\n\n                [profile.custom]\n                src = \"customsrc\"\n            \"#,\n            )?;\n\n            let config = Config::load().unwrap();\n            assert_eq!(config.src, PathBuf::from(\"defaultsrc\"));\n            assert_eq!(config.libs, vec![PathBuf::from(\"lib\"), PathBuf::from(\"node_modules\")]);\n\n            jail.set_env(\"FOUNDRY_PROFILE\", \"custom\");\n            let config = Config::load().unwrap();\n            assert_eq!(config.src, PathBuf::from(\"customsrc\"));\n            assert_eq!(config.test, PathBuf::from(\"defaulttest\"));\n            assert_eq!(config.libs, vec![PathBuf::from(\"lib\"), PathBuf::from(\"node_modules\")]);\n\n            Ok(())\n        });\n    }\n\n    #[test]\n    fn test_custom_test_path() {\n        figment::Jail::expect_with(|jail| {\n            jail.create_file(\n                \"foundry.toml\",\n                r#\"\n                [profile.default]\n                test = \"mytest\"\n            \"#,\n            )?;\n\n            let config = Config::load().unwrap();\n            let paths_config = config.project_paths::<Solc>();\n            assert_eq!(paths_config.tests, PathBuf::from(r\"mytest\"));\n            Ok(())\n        });\n    }\n\n    #[test]\n    fn test_remappings() {\n        figment::Jail::expect_with(|jail| {\n            jail.create_file(\n                \"foundry.toml\",\n                r#\"\n                [profile.default]\n                src = \"some-source\"\n                out = \"some-out\"\n                cache = true\n            \"#,\n            )?;\n            let config = Config::load().unwrap();\n            assert!(config.remappings.is_empty());\n\n            jail.create_file(\n                \"remappings.txt\",\n                r\"\n                file-ds-test/=lib/ds-test/\n                file-other/=lib/other/\n            \",\n            )?;\n\n            let config = Config::load().unwrap();\n            assert_eq!(\n                config.remappings,\n                vec![\n                    Remapping::from_str(\"file-ds-test/=lib/ds-test/\").unwrap().into(),\n                    Remapping::from_str(\"file-other/=lib/other/\").unwrap().into(),\n                ],\n            );\n\n            jail.set_env(\"DAPP_REMAPPINGS\", \"ds-test=lib/ds-test/\\nother/=lib/other/\");\n            let config = Config::load().unwrap();\n\n            assert_eq!(\n                config.remappings,\n                vec![\n                    // From environment (should have precedence over remapping.txt)\n                    Remapping::from_str(\"ds-test=lib/ds-test/\").unwrap().into(),\n                    Remapping::from_str(\"other/=lib/other/\").unwrap().into(),\n                    // From remapping.txt (should have less precedence than remapping.txt)\n                    Remapping::from_str(\"file-ds-test/=lib/ds-test/\").unwrap().into(),\n                    Remapping::from_str(\"file-other/=lib/other/\").unwrap().into(),\n                ],\n            );\n\n            Ok(())\n        });\n    }\n\n    #[test]\n    fn test_remappings_override() {\n        figment::Jail::expect_with(|jail| {\n            jail.create_file(\n                \"foundry.toml\",\n                r#\"\n                [profile.default]\n                src = \"some-source\"\n                out = \"some-out\"\n                cache = true\n            \"#,\n            )?;\n            let config = Config::load().unwrap();\n            assert!(config.remappings.is_empty());\n\n            jail.create_file(\n                \"remappings.txt\",\n                r\"\n                ds-test/=lib/ds-test/\n                other/=lib/other/\n            \",\n            )?;\n\n            let config = Config::load().unwrap();\n            assert_eq!(\n                config.remappings,\n                vec![\n                    Remapping::from_str(\"ds-test/=lib/ds-test/\").unwrap().into(),\n                    Remapping::from_str(\"other/=lib/other/\").unwrap().into(),\n                ],\n            );\n\n            jail.set_env(\"DAPP_REMAPPINGS\", \"ds-test/=lib/ds-test/src/\\nenv-lib/=lib/env-lib/\");\n            let config = Config::load().unwrap();\n\n            // Remappings should now be:\n            // - ds-test from environment (lib/ds-test/src/)\n            // - other from remappings.txt (lib/other/)\n            // - env-lib from environment (lib/env-lib/)\n            assert_eq!(\n                config.remappings,\n                vec![\n                    Remapping::from_str(\"ds-test/=lib/ds-test/src/\").unwrap().into(),\n                    Remapping::from_str(\"env-lib/=lib/env-lib/\").unwrap().into(),\n                    Remapping::from_str(\"other/=lib/other/\").unwrap().into(),\n                ],\n            );\n\n            // contains additional remapping to the source dir\n            assert_eq!(\n                config.get_all_remappings().collect::<Vec<_>>(),\n                vec![\n                    Remapping::from_str(\"ds-test/=lib/ds-test/src/\").unwrap(),\n                    Remapping::from_str(\"env-lib/=lib/env-lib/\").unwrap(),\n                    Remapping::from_str(\"other/=lib/other/\").unwrap(),\n                ],\n            );\n\n            Ok(())\n        });\n    }\n\n    #[test]\n    fn test_can_update_libs() {\n        figment::Jail::expect_with(|jail| {\n            jail.create_file(\n                \"foundry.toml\",\n                r#\"\n                [profile.default]\n                libs = [\"node_modules\"]\n            \"#,\n            )?;\n\n            let mut config = Config::load().unwrap();\n            config.libs.push(\"libs\".into());\n            config.update_libs().unwrap();\n\n            let config = Config::load().unwrap();\n            assert_eq!(config.libs, vec![PathBuf::from(\"node_modules\"), PathBuf::from(\"libs\"),]);\n            Ok(())\n        });\n    }\n\n    #[test]\n    fn test_large_gas_limit() {\n        figment::Jail::expect_with(|jail| {\n            let gas = u64::MAX;\n            jail.create_file(\n                \"foundry.toml\",\n                &format!(\n                    r#\"\n                [profile.default]\n                gas_limit = \"{gas}\"\n            \"#\n                ),\n            )?;\n\n            let config = Config::load().unwrap();\n            assert_eq!(\n                config,\n                Config {\n                    gas_limit: gas.into(),\n                    ..Config::default().normalized_optimizer_settings()\n                }\n            );\n\n            Ok(())\n        });\n    }\n\n    #[test]\n    #[should_panic]\n    fn test_toml_file_parse_failure() {\n        figment::Jail::expect_with(|jail| {\n            jail.create_file(\n                \"foundry.toml\",\n                r#\"\n                [profile.default]\n                eth_rpc_url = \"https://example.com/\n            \"#,\n            )?;\n\n            let _config = Config::load().unwrap();\n\n            Ok(())\n        });\n    }\n\n    #[test]\n    #[should_panic]\n    fn test_toml_file_non_existing_config_var_failure() {\n        figment::Jail::expect_with(|jail| {\n            jail.set_env(\"FOUNDRY_CONFIG\", \"this config does not exist\");\n\n            let _config = Config::load().unwrap();\n\n            Ok(())\n        });\n    }\n\n    #[test]\n    fn test_resolve_etherscan_with_chain() {\n        figment::Jail::expect_with(|jail| {\n            let env_key = \"__BSC_ETHERSCAN_API_KEY\";\n            let env_value = \"env value\";\n            jail.create_file(\n                \"foundry.toml\",\n                r#\"\n                [profile.default]\n\n                [etherscan]\n                bsc = { key = \"${__BSC_ETHERSCAN_API_KEY}\", url = \"https://api.bscscan.com/api\" }\n            \"#,\n            )?;\n\n            let config = Config::load().unwrap();\n            assert!(\n                config\n                    .get_etherscan_config_with_chain(Some(NamedChain::BinanceSmartChain.into()))\n                    .is_err()\n            );\n\n            unsafe {\n                std::env::set_var(env_key, env_value);\n            }\n\n            assert_eq!(\n                config\n                    .get_etherscan_config_with_chain(Some(NamedChain::BinanceSmartChain.into()))\n                    .unwrap()\n                    .unwrap()\n                    .key,\n                env_value\n            );\n\n            let mut with_key = config;\n            with_key.etherscan_api_key = Some(\"via etherscan_api_key\".to_string());\n\n            assert_eq!(\n                with_key\n                    .get_etherscan_config_with_chain(Some(NamedChain::BinanceSmartChain.into()))\n                    .unwrap()\n                    .unwrap()\n                    .key,\n                \"via etherscan_api_key\"\n            );\n\n            unsafe {\n                std::env::remove_var(env_key);\n            }\n            Ok(())\n        });\n    }\n\n    #[test]\n    fn test_resolve_etherscan() {\n        figment::Jail::expect_with(|jail| {\n            jail.create_file(\n                \"foundry.toml\",\n                r#\"\n                [profile.default]\n\n                [etherscan]\n                mainnet = { key = \"FX42Z3BBJJEWXWGYV2X1CIPRSCN\" }\n                moonbeam = { key = \"${_CONFIG_ETHERSCAN_MOONBEAM}\" }\n            \"#,\n            )?;\n\n            let config = Config::load().unwrap();\n\n            assert!(config.etherscan.clone().resolved().has_unresolved());\n\n            jail.set_env(\"_CONFIG_ETHERSCAN_MOONBEAM\", \"123456789\");\n\n            let configs = config.etherscan.resolved();\n            assert!(!configs.has_unresolved());\n\n            let mb_urls = Moonbeam.etherscan_urls().unwrap();\n            let mainnet_urls = NamedChain::Mainnet.etherscan_urls().unwrap();\n            assert_eq!(\n                configs,\n                ResolvedEtherscanConfigs::new([\n                    (\n                        \"mainnet\",\n                        ResolvedEtherscanConfig {\n                            api_url: mainnet_urls.0.to_string(),\n                            chain: Some(NamedChain::Mainnet.into()),\n                            browser_url: Some(mainnet_urls.1.to_string()),\n                            key: \"FX42Z3BBJJEWXWGYV2X1CIPRSCN\".to_string(),\n                        }\n                    ),\n                    (\n                        \"moonbeam\",\n                        ResolvedEtherscanConfig {\n                            api_url: mb_urls.0.to_string(),\n                            chain: Some(Moonbeam.into()),\n                            browser_url: Some(mb_urls.1.to_string()),\n                            key: \"123456789\".to_string(),\n                        }\n                    ),\n                ])\n            );\n\n            Ok(())\n        });\n    }\n\n    #[test]\n    fn test_resolve_etherscan_with_versions() {\n        figment::Jail::expect_with(|jail| {\n            jail.create_file(\n                \"foundry.toml\",\n                r#\"\n                [profile.default]\n\n                [etherscan]\n                mainnet = { key = \"FX42Z3BBJJEWXWGYV2X1CIPRSCN\", api_version = \"v2\" }\n                moonbeam = { key = \"${_CONFIG_ETHERSCAN_MOONBEAM}\", api_version = \"v1\" }\n            \"#,\n            )?;\n\n            let config = Config::load().unwrap();\n\n            assert!(config.etherscan.clone().resolved().has_unresolved());\n\n            jail.set_env(\"_CONFIG_ETHERSCAN_MOONBEAM\", \"123456789\");\n\n            let configs = config.etherscan.resolved();\n            assert!(!configs.has_unresolved());\n\n            let mb_urls = Moonbeam.etherscan_urls().unwrap();\n            let mainnet_urls = NamedChain::Mainnet.etherscan_urls().unwrap();\n            assert_eq!(\n                configs,\n                ResolvedEtherscanConfigs::new([\n                    (\n                        \"mainnet\",\n                        ResolvedEtherscanConfig {\n                            api_url: mainnet_urls.0.to_string(),\n                            chain: Some(NamedChain::Mainnet.into()),\n                            browser_url: Some(mainnet_urls.1.to_string()),\n                            key: \"FX42Z3BBJJEWXWGYV2X1CIPRSCN\".to_string(),\n                        }\n                    ),\n                    (\n                        \"moonbeam\",\n                        ResolvedEtherscanConfig {\n                            api_url: mb_urls.0.to_string(),\n                            chain: Some(Moonbeam.into()),\n                            browser_url: Some(mb_urls.1.to_string()),\n                            key: \"123456789\".to_string(),\n                        }\n                    ),\n                ])\n            );\n\n            Ok(())\n        });\n    }\n\n    #[test]\n    fn test_resolve_etherscan_chain_id() {\n        figment::Jail::expect_with(|jail| {\n            jail.create_file(\n                \"foundry.toml\",\n                r#\"\n                [profile.default]\n                chain_id = \"sepolia\"\n\n                [etherscan]\n                sepolia = { key = \"FX42Z3BBJJEWXWGYV2X1CIPRSCN\" }\n            \"#,\n            )?;\n\n            let config = Config::load().unwrap();\n            let etherscan = config.get_etherscan_config().unwrap().unwrap();\n            assert_eq!(etherscan.chain, Some(NamedChain::Sepolia.into()));\n            assert_eq!(etherscan.key, \"FX42Z3BBJJEWXWGYV2X1CIPRSCN\");\n\n            Ok(())\n        });\n    }\n\n    // any invalid entry invalidates whole [etherscan] sections\n    #[test]\n    fn test_resolve_etherscan_with_invalid_name() {\n        figment::Jail::expect_with(|jail| {\n            jail.create_file(\n                \"foundry.toml\",\n                r#\"\n                [etherscan]\n                mainnet = { key = \"FX42Z3BBJJEWXWGYV2X1CIPRSCN\" }\n                an_invalid_name = { key = \"FX42Z3BBJJEWXWGYV2X1CIPRSCN\" }\n            \"#,\n            )?;\n\n            let config = Config::load().unwrap();\n            let etherscan_config = config.get_etherscan_config();\n            assert!(etherscan_config.is_none());\n\n            Ok(())\n        });\n    }\n\n    #[test]\n    fn test_resolve_rpc_url() {\n        figment::Jail::expect_with(|jail| {\n            jail.create_file(\n                \"foundry.toml\",\n                r#\"\n                [profile.default]\n                [rpc_endpoints]\n                optimism = \"https://example.com/\"\n                mainnet = \"${_CONFIG_MAINNET}\"\n            \"#,\n            )?;\n            jail.set_env(\"_CONFIG_MAINNET\", \"https://eth-mainnet.alchemyapi.io/v2/123455\");\n\n            let mut config = Config::load().unwrap();\n            assert_eq!(\"http://localhost:8545\", config.get_rpc_url_or_localhost_http().unwrap());\n\n            config.eth_rpc_url = Some(\"mainnet\".to_string());\n            assert_eq!(\n                \"https://eth-mainnet.alchemyapi.io/v2/123455\",\n                config.get_rpc_url_or_localhost_http().unwrap()\n            );\n\n            config.eth_rpc_url = Some(\"optimism\".to_string());\n            assert_eq!(\"https://example.com/\", config.get_rpc_url_or_localhost_http().unwrap());\n\n            Ok(())\n        })\n    }\n\n    #[test]\n    fn test_resolve_rpc_url_if_etherscan_set() {\n        figment::Jail::expect_with(|jail| {\n            jail.create_file(\n                \"foundry.toml\",\n                r#\"\n                [profile.default]\n                etherscan_api_key = \"dummy\"\n                [rpc_endpoints]\n                optimism = \"https://example.com/\"\n            \"#,\n            )?;\n\n            let config = Config::load().unwrap();\n            assert_eq!(\"http://localhost:8545\", config.get_rpc_url_or_localhost_http().unwrap());\n\n            Ok(())\n        })\n    }\n\n    #[test]\n    fn test_resolve_rpc_url_alias() {\n        figment::Jail::expect_with(|jail| {\n            jail.create_file(\n                \"foundry.toml\",\n                r#\"\n                [profile.default]\n                [rpc_endpoints]\n                polygonAmoy = \"https://polygon-amoy.g.alchemy.com/v2/${_RESOLVE_RPC_ALIAS}\"\n            \"#,\n            )?;\n            let mut config = Config::load().unwrap();\n            config.eth_rpc_url = Some(\"polygonAmoy\".to_string());\n            assert!(config.get_rpc_url().unwrap().is_err());\n\n            jail.set_env(\"_RESOLVE_RPC_ALIAS\", \"123455\");\n\n            let mut config = Config::load().unwrap();\n            config.eth_rpc_url = Some(\"polygonAmoy\".to_string());\n            assert_eq!(\n                \"https://polygon-amoy.g.alchemy.com/v2/123455\",\n                config.get_rpc_url().unwrap().unwrap()\n            );\n\n            Ok(())\n        })\n    }\n\n    #[test]\n    fn test_resolve_rpc_aliases() {\n        figment::Jail::expect_with(|jail| {\n            jail.create_file(\n                \"foundry.toml\",\n                r#\"\n               [profile.default]\n               [etherscan]\n               arbitrum_alias = { key = \"${TEST_RESOLVE_RPC_ALIAS_ARBISCAN}\" }\n               [rpc_endpoints]\n               arbitrum_alias = \"https://arb-mainnet.g.alchemy.com/v2/${TEST_RESOLVE_RPC_ALIAS_ARB_ONE}\"\n            \"#,\n            )?;\n\n            jail.set_env(\"TEST_RESOLVE_RPC_ALIAS_ARB_ONE\", \"123455\");\n            jail.set_env(\"TEST_RESOLVE_RPC_ALIAS_ARBISCAN\", \"123455\");\n\n            let config = Config::load().unwrap();\n\n            let config = config.get_etherscan_config_with_chain(Some(NamedChain::Arbitrum.into()));\n            assert!(config.is_err());\n            assert_eq!(\n                config.unwrap_err().to_string(),\n                \"At least one of `url` or `chain` must be present for Etherscan config with unknown alias `arbitrum_alias`\"\n            );\n\n            Ok(())\n        });\n    }\n\n    #[test]\n    fn test_resolve_rpc_config() {\n        figment::Jail::expect_with(|jail| {\n            jail.create_file(\n                \"foundry.toml\",\n                r#\"\n                [rpc_endpoints]\n                optimism = \"https://example.com/\"\n                mainnet = { endpoint = \"${_CONFIG_MAINNET}\", retries = 3, retry_backoff = 1000, compute_units_per_second = 1000 }\n            \"#,\n            )?;\n            jail.set_env(\"_CONFIG_MAINNET\", \"https://eth-mainnet.alchemyapi.io/v2/123455\");\n\n            let config = Config::load().unwrap();\n            assert_eq!(\n                RpcEndpoints::new([\n                    (\n                        \"optimism\",\n                        RpcEndpointType::String(RpcEndpointUrl::Url(\n                            \"https://example.com/\".to_string()\n                        ))\n                    ),\n                    (\n                        \"mainnet\",\n                        RpcEndpointType::Config(RpcEndpoint {\n                            endpoint: RpcEndpointUrl::Env(\"${_CONFIG_MAINNET}\".to_string()),\n                            config: RpcEndpointConfig {\n                                retries: Some(3),\n                                retry_backoff: Some(1000),\n                                compute_units_per_second: Some(1000),\n                            },\n                            auth: None,\n                        })\n                    ),\n                ]),\n                config.rpc_endpoints\n            );\n\n            let resolved = config.rpc_endpoints.resolved();\n            assert_eq!(\n                RpcEndpoints::new([\n                    (\n                        \"optimism\",\n                        RpcEndpointType::String(RpcEndpointUrl::Url(\n                            \"https://example.com/\".to_string()\n                        ))\n                    ),\n                    (\n                        \"mainnet\",\n                        RpcEndpointType::Config(RpcEndpoint {\n                            endpoint: RpcEndpointUrl::Env(\"${_CONFIG_MAINNET}\".to_string()),\n                            config: RpcEndpointConfig {\n                                retries: Some(3),\n                                retry_backoff: Some(1000),\n                                compute_units_per_second: Some(1000),\n                            },\n                            auth: None,\n                        })\n                    ),\n                ])\n                .resolved(),\n                resolved\n            );\n            Ok(())\n        })\n    }\n\n    #[test]\n    fn test_resolve_auth() {\n        figment::Jail::expect_with(|jail| {\n            jail.create_file(\n                \"foundry.toml\",\n                r#\"\n                [profile.default]\n                eth_rpc_url = \"optimism\"\n                [rpc_endpoints]\n                optimism = \"https://example.com/\"\n                mainnet = { endpoint = \"${_CONFIG_MAINNET}\", retries = 3, retry_backoff = 1000, compute_units_per_second = 1000, auth = \"Bearer ${_CONFIG_AUTH}\" }\n            \"#,\n            )?;\n\n            let config = Config::load().unwrap();\n\n            jail.set_env(\"_CONFIG_AUTH\", \"123456\");\n            jail.set_env(\"_CONFIG_MAINNET\", \"https://eth-mainnet.alchemyapi.io/v2/123455\");\n\n            assert_eq!(\n                RpcEndpoints::new([\n                    (\n                        \"optimism\",\n                        RpcEndpointType::String(RpcEndpointUrl::Url(\n                            \"https://example.com/\".to_string()\n                        ))\n                    ),\n                    (\n                        \"mainnet\",\n                        RpcEndpointType::Config(RpcEndpoint {\n                            endpoint: RpcEndpointUrl::Env(\"${_CONFIG_MAINNET}\".to_string()),\n                            config: RpcEndpointConfig {\n                                retries: Some(3),\n                                retry_backoff: Some(1000),\n                                compute_units_per_second: Some(1000)\n                            },\n                            auth: Some(RpcAuth::Env(\"Bearer ${_CONFIG_AUTH}\".to_string())),\n                        })\n                    ),\n                ]),\n                config.rpc_endpoints\n            );\n            let resolved = config.rpc_endpoints.resolved();\n            assert_eq!(\n                RpcEndpoints::new([\n                    (\n                        \"optimism\",\n                        RpcEndpointType::String(RpcEndpointUrl::Url(\n                            \"https://example.com/\".to_string()\n                        ))\n                    ),\n                    (\n                        \"mainnet\",\n                        RpcEndpointType::Config(RpcEndpoint {\n                            endpoint: RpcEndpointUrl::Url(\n                                \"https://eth-mainnet.alchemyapi.io/v2/123455\".to_string()\n                            ),\n                            config: RpcEndpointConfig {\n                                retries: Some(3),\n                                retry_backoff: Some(1000),\n                                compute_units_per_second: Some(1000)\n                            },\n                            auth: Some(RpcAuth::Raw(\"Bearer 123456\".to_string())),\n                        })\n                    ),\n                ])\n                .resolved(),\n                resolved\n            );\n\n            Ok(())\n        });\n    }\n\n    #[test]\n    fn test_resolve_endpoints() {\n        figment::Jail::expect_with(|jail| {\n            jail.create_file(\n                \"foundry.toml\",\n                r#\"\n                [profile.default]\n                eth_rpc_url = \"optimism\"\n                [rpc_endpoints]\n                optimism = \"https://example.com/\"\n                mainnet = \"${_CONFIG_MAINNET}\"\n                mainnet_2 = \"https://eth-mainnet.alchemyapi.io/v2/${_CONFIG_API_KEY1}\"\n                mainnet_3 = \"https://eth-mainnet.alchemyapi.io/v2/${_CONFIG_API_KEY1}/${_CONFIG_API_KEY2}\"\n            \"#,\n            )?;\n\n            let config = Config::load().unwrap();\n\n            assert_eq!(config.get_rpc_url().unwrap().unwrap(), \"https://example.com/\");\n\n            assert!(config.rpc_endpoints.clone().resolved().has_unresolved());\n\n            jail.set_env(\"_CONFIG_MAINNET\", \"https://eth-mainnet.alchemyapi.io/v2/123455\");\n            jail.set_env(\"_CONFIG_API_KEY1\", \"123456\");\n            jail.set_env(\"_CONFIG_API_KEY2\", \"98765\");\n\n            let endpoints = config.rpc_endpoints.resolved();\n\n            assert!(!endpoints.has_unresolved());\n\n            assert_eq!(\n                endpoints,\n                RpcEndpoints::new([\n                    (\"optimism\", RpcEndpointUrl::Url(\"https://example.com/\".to_string())),\n                    (\n                        \"mainnet\",\n                        RpcEndpointUrl::Url(\n                            \"https://eth-mainnet.alchemyapi.io/v2/123455\".to_string()\n                        )\n                    ),\n                    (\n                        \"mainnet_2\",\n                        RpcEndpointUrl::Url(\n                            \"https://eth-mainnet.alchemyapi.io/v2/123456\".to_string()\n                        )\n                    ),\n                    (\n                        \"mainnet_3\",\n                        RpcEndpointUrl::Url(\n                            \"https://eth-mainnet.alchemyapi.io/v2/123456/98765\".to_string()\n                        )\n                    ),\n                ])\n                .resolved()\n            );\n\n            Ok(())\n        });\n    }\n\n    #[test]\n    fn test_extract_etherscan_config() {\n        figment::Jail::expect_with(|jail| {\n            jail.create_file(\n                \"foundry.toml\",\n                r#\"\n                [profile.default]\n                etherscan_api_key = \"optimism\"\n\n                [etherscan]\n                optimism = { key = \"https://etherscan-optimism.com/\" }\n                amoy = { key = \"https://etherscan-amoy.com/\" }\n            \"#,\n            )?;\n\n            let mut config = Config::load().unwrap();\n\n            let optimism = config.get_etherscan_api_key(Some(NamedChain::Optimism.into()));\n            assert_eq!(optimism, Some(\"https://etherscan-optimism.com/\".to_string()));\n\n            config.etherscan_api_key = Some(\"amoy\".to_string());\n\n            let amoy = config.get_etherscan_api_key(Some(NamedChain::PolygonAmoy.into()));\n            assert_eq!(amoy, Some(\"https://etherscan-amoy.com/\".to_string()));\n\n            Ok(())\n        });\n    }\n\n    #[test]\n    fn test_extract_etherscan_config_by_chain() {\n        figment::Jail::expect_with(|jail| {\n            jail.create_file(\n                \"foundry.toml\",\n                r#\"\n                [profile.default]\n\n                [etherscan]\n                amoy = { key = \"https://etherscan-amoy.com/\", chain = 80002 }\n            \"#,\n            )?;\n\n            let config = Config::load().unwrap();\n\n            let amoy = config\n                .get_etherscan_config_with_chain(Some(NamedChain::PolygonAmoy.into()))\n                .unwrap()\n                .unwrap();\n            assert_eq!(amoy.key, \"https://etherscan-amoy.com/\".to_string());\n\n            Ok(())\n        });\n    }\n\n    #[test]\n    fn test_extract_etherscan_config_by_chain_with_url() {\n        figment::Jail::expect_with(|jail| {\n            jail.create_file(\n                \"foundry.toml\",\n                r#\"\n                [profile.default]\n\n                [etherscan]\n                amoy = { key = \"https://etherscan-amoy.com/\", chain = 80002 , url =  \"https://verifier-url.com/\"}\n            \"#,\n            )?;\n\n            let config = Config::load().unwrap();\n\n            let amoy = config\n                .get_etherscan_config_with_chain(Some(NamedChain::PolygonAmoy.into()))\n                .unwrap()\n                .unwrap();\n            assert_eq!(amoy.key, \"https://etherscan-amoy.com/\".to_string());\n            assert_eq!(amoy.api_url, \"https://verifier-url.com/\".to_string());\n\n            Ok(())\n        });\n    }\n\n    #[test]\n    fn test_extract_etherscan_config_by_chain_and_alias() {\n        figment::Jail::expect_with(|jail| {\n            jail.create_file(\n                \"foundry.toml\",\n                r#\"\n                [profile.default]\n                eth_rpc_url = \"amoy\"\n\n                [etherscan]\n                amoy = { key = \"https://etherscan-amoy.com/\" }\n\n                [rpc_endpoints]\n                amoy = \"https://polygon-amoy.g.alchemy.com/v2/amoy\"\n            \"#,\n            )?;\n\n            let config = Config::load().unwrap();\n\n            let amoy = config.get_etherscan_config_with_chain(None).unwrap().unwrap();\n            assert_eq!(amoy.key, \"https://etherscan-amoy.com/\".to_string());\n\n            let amoy_rpc = config.get_rpc_url().unwrap().unwrap();\n            assert_eq!(amoy_rpc, \"https://polygon-amoy.g.alchemy.com/v2/amoy\");\n            Ok(())\n        });\n    }\n\n    #[test]\n    fn test_toml_file() {\n        figment::Jail::expect_with(|jail| {\n            jail.create_file(\n                \"foundry.toml\",\n                r#\"\n                [profile.default]\n                src = \"some-source\"\n                out = \"some-out\"\n                cache = true\n                eth_rpc_url = \"https://example.com/\"\n                verbosity = 3\n                remappings = [\"ds-test=lib/ds-test/\"]\n                via_ir = true\n                rpc_storage_caching = { chains = [1, \"optimism\", 999999], endpoints = \"all\"}\n                use_literal_content = false\n                bytecode_hash = \"ipfs\"\n                cbor_metadata = true\n                revert_strings = \"strip\"\n                allow_paths = [\"allow\", \"paths\"]\n                build_info_path = \"build-info\"\n                always_use_create_2_factory = true\n\n                [rpc_endpoints]\n                optimism = \"https://example.com/\"\n                mainnet = \"${RPC_MAINNET}\"\n                mainnet_2 = \"https://eth-mainnet.alchemyapi.io/v2/${API_KEY}\"\n                mainnet_3 = \"https://eth-mainnet.alchemyapi.io/v2/${API_KEY}/${ANOTHER_KEY}\"\n            \"#,\n            )?;\n\n            let config = Config::load().unwrap();\n            assert_eq!(\n                config,\n                Config {\n                    src: \"some-source\".into(),\n                    out: \"some-out\".into(),\n                    cache: true,\n                    eth_rpc_url: Some(\"https://example.com/\".to_string()),\n                    remappings: vec![Remapping::from_str(\"ds-test=lib/ds-test/\").unwrap().into()],\n                    verbosity: 3,\n                    via_ir: true,\n                    rpc_storage_caching: StorageCachingConfig {\n                        chains: CachedChains::Chains(vec![\n                            Chain::mainnet(),\n                            Chain::optimism_mainnet(),\n                            Chain::from_id(999999)\n                        ]),\n                        endpoints: CachedEndpoints::All,\n                    },\n                    use_literal_content: false,\n                    bytecode_hash: BytecodeHash::Ipfs,\n                    cbor_metadata: true,\n                    revert_strings: Some(RevertStrings::Strip),\n                    allow_paths: vec![PathBuf::from(\"allow\"), PathBuf::from(\"paths\")],\n                    rpc_endpoints: RpcEndpoints::new([\n                        (\"optimism\", RpcEndpointUrl::Url(\"https://example.com/\".to_string())),\n                        (\"mainnet\", RpcEndpointUrl::Env(\"${RPC_MAINNET}\".to_string())),\n                        (\n                            \"mainnet_2\",\n                            RpcEndpointUrl::Env(\n                                \"https://eth-mainnet.alchemyapi.io/v2/${API_KEY}\".to_string()\n                            )\n                        ),\n                        (\n                            \"mainnet_3\",\n                            RpcEndpointUrl::Env(\n                                \"https://eth-mainnet.alchemyapi.io/v2/${API_KEY}/${ANOTHER_KEY}\"\n                                    .to_string()\n                            )\n                        ),\n                    ]),\n                    build_info_path: Some(\"build-info\".into()),\n                    always_use_create_2_factory: true,\n                    ..Config::default().normalized_optimizer_settings()\n                }\n            );\n\n            Ok(())\n        });\n    }\n\n    #[test]\n    fn test_load_remappings() {\n        figment::Jail::expect_with(|jail| {\n            jail.create_file(\n                \"foundry.toml\",\n                r\"\n                [profile.default]\n                remappings = ['nested/=lib/nested/']\n            \",\n            )?;\n\n            let config = Config::load_with_root(jail.directory()).unwrap();\n            assert_eq!(\n                config.remappings,\n                vec![Remapping::from_str(\"nested/=lib/nested/\").unwrap().into()]\n            );\n\n            Ok(())\n        });\n    }\n\n    #[test]\n    fn test_load_full_toml() {\n        figment::Jail::expect_with(|jail| {\n            jail.create_file(\n                \"foundry.toml\",\n                r#\"\n                [profile.default]\n                auto_detect_solc = true\n                block_base_fee_per_gas = 0\n                block_coinbase = '0x0000000000000000000000000000000000000000'\n                block_difficulty = 0\n                block_prevrandao = '0x0000000000000000000000000000000000000000000000000000000000000000'\n                block_number = 1\n                block_timestamp = 1\n                use_literal_content = false\n                bytecode_hash = 'ipfs'\n                cbor_metadata = true\n                cache = true\n                cache_path = 'cache'\n                evm_version = 'london'\n                extra_output = []\n                extra_output_files = []\n                always_use_create_2_factory = false\n                ffi = false\n                force = false\n                gas_limit = 9223372036854775807\n                gas_price = 0\n                gas_reports = ['*']\n                ignored_error_codes = [1878]\n                ignored_warnings_from = [\"something\"]\n                deny = \"never\"\n                initial_balance = '0xffffffffffffffffffffffff'\n                libraries = []\n                libs = ['lib']\n                memory_limit = 134217728\n                names = false\n                no_storage_caching = false\n                no_rpc_rate_limit = false\n                offline = false\n                optimizer = true\n                optimizer_runs = 200\n                out = 'out'\n                remappings = ['nested/=lib/nested/']\n                sender = '0x1804c8AB1F12E6bbf3894d4083f33e07309d1f38'\n                sizes = false\n                sparse_mode = false\n                src = 'src'\n                test = 'test'\n                tx_origin = '0x1804c8AB1F12E6bbf3894d4083f33e07309d1f38'\n                verbosity = 0\n                via_ir = false\n\n                [profile.default.rpc_storage_caching]\n                chains = 'all'\n                endpoints = 'all'\n\n                [rpc_endpoints]\n                optimism = \"https://example.com/\"\n                mainnet = \"${RPC_MAINNET}\"\n                mainnet_2 = \"https://eth-mainnet.alchemyapi.io/v2/${API_KEY}\"\n\n                [fuzz]\n                runs = 256\n                seed = '0x3e8'\n                max_test_rejects = 65536\n\n                [invariant]\n                runs = 256\n                depth = 500\n                fail_on_revert = false\n                call_override = false\n                shrink_run_limit = 5000\n            \"#,\n            )?;\n\n            let config = Config::load_with_root(jail.directory()).unwrap();\n\n            assert_eq!(config.ignored_file_paths, vec![PathBuf::from(\"something\")]);\n            assert_eq!(config.fuzz.seed, Some(U256::from(1000)));\n            assert_eq!(\n                config.remappings,\n                vec![Remapping::from_str(\"nested/=lib/nested/\").unwrap().into()]\n            );\n\n            assert_eq!(\n                config.rpc_endpoints,\n                RpcEndpoints::new([\n                    (\"optimism\", RpcEndpointUrl::Url(\"https://example.com/\".to_string())),\n                    (\"mainnet\", RpcEndpointUrl::Env(\"${RPC_MAINNET}\".to_string())),\n                    (\n                        \"mainnet_2\",\n                        RpcEndpointUrl::Env(\n                            \"https://eth-mainnet.alchemyapi.io/v2/${API_KEY}\".to_string()\n                        )\n                    ),\n                ]),\n            );\n\n            Ok(())\n        });\n    }\n\n    #[test]\n    fn test_solc_req() {\n        figment::Jail::expect_with(|jail| {\n            jail.create_file(\n                \"foundry.toml\",\n                r#\"\n                [profile.default]\n                solc_version = \"0.8.12\"\n            \"#,\n            )?;\n\n            let config = Config::load().unwrap();\n            assert_eq!(config.solc, Some(SolcReq::Version(Version::new(0, 8, 12))));\n\n            jail.create_file(\n                \"foundry.toml\",\n                r#\"\n                [profile.default]\n                solc = \"0.8.12\"\n            \"#,\n            )?;\n\n            let config = Config::load().unwrap();\n            assert_eq!(config.solc, Some(SolcReq::Version(Version::new(0, 8, 12))));\n\n            jail.create_file(\n                \"foundry.toml\",\n                r#\"\n                [profile.default]\n                solc = \"path/to/local/solc\"\n            \"#,\n            )?;\n\n            let config = Config::load().unwrap();\n            assert_eq!(config.solc, Some(SolcReq::Local(\"path/to/local/solc\".into())));\n\n            jail.set_env(\"FOUNDRY_SOLC_VERSION\", \"0.6.6\");\n            let config = Config::load().unwrap();\n            assert_eq!(config.solc, Some(SolcReq::Version(Version::new(0, 6, 6))));\n            Ok(())\n        });\n    }\n\n    // ensures the newer `solc` takes precedence over `solc_version`\n    #[test]\n    fn test_backwards_solc_version() {\n        figment::Jail::expect_with(|jail| {\n            jail.create_file(\n                \"foundry.toml\",\n                r#\"\n                [default]\n                solc = \"0.8.12\"\n                solc_version = \"0.8.20\"\n            \"#,\n            )?;\n\n            let config = Config::load().unwrap();\n            assert_eq!(config.solc, Some(SolcReq::Version(Version::new(0, 8, 12))));\n\n            Ok(())\n        });\n\n        figment::Jail::expect_with(|jail| {\n            jail.create_file(\n                \"foundry.toml\",\n                r#\"\n                [default]\n                solc_version = \"0.8.20\"\n            \"#,\n            )?;\n\n            let config = Config::load().unwrap();\n            assert_eq!(config.solc, Some(SolcReq::Version(Version::new(0, 8, 20))));\n\n            Ok(())\n        });\n    }\n\n    #[test]\n    fn test_toml_casing_file() {\n        figment::Jail::expect_with(|jail| {\n            jail.create_file(\n                \"foundry.toml\",\n                r#\"\n                [profile.default]\n                src = \"some-source\"\n                out = \"some-out\"\n                cache = true\n                eth-rpc-url = \"https://example.com/\"\n                evm-version = \"berlin\"\n                auto-detect-solc = false\n            \"#,\n            )?;\n\n            let config = Config::load().unwrap();\n            assert_eq!(\n                config,\n                Config {\n                    src: \"some-source\".into(),\n                    out: \"some-out\".into(),\n                    cache: true,\n                    eth_rpc_url: Some(\"https://example.com/\".to_string()),\n                    auto_detect_solc: false,\n                    evm_version: EvmVersion::Berlin,\n                    ..Config::default().normalized_optimizer_settings()\n                }\n            );\n\n            Ok(())\n        });\n    }\n\n    #[test]\n    fn test_output_selection() {\n        figment::Jail::expect_with(|jail| {\n            jail.create_file(\n                \"foundry.toml\",\n                r#\"\n                [profile.default]\n                extra_output = [\"metadata\", \"ir-optimized\"]\n                extra_output_files = [\"metadata\"]\n            \"#,\n            )?;\n\n            let config = Config::load().unwrap();\n\n            assert_eq!(\n                config.extra_output,\n                vec![ContractOutputSelection::Metadata, ContractOutputSelection::IrOptimized]\n            );\n            assert_eq!(config.extra_output_files, vec![ContractOutputSelection::Metadata]);\n\n            Ok(())\n        });\n    }\n\n    #[test]\n    fn test_precedence() {\n        figment::Jail::expect_with(|jail| {\n            jail.create_file(\n                \"foundry.toml\",\n                r#\"\n                [profile.default]\n                src = \"mysrc\"\n                out = \"myout\"\n                verbosity = 3\n            \"#,\n            )?;\n\n            let config = Config::load().unwrap();\n            assert_eq!(\n                config,\n                Config {\n                    src: \"mysrc\".into(),\n                    out: \"myout\".into(),\n                    verbosity: 3,\n                    ..Config::default().normalized_optimizer_settings()\n                }\n            );\n\n            jail.set_env(\"FOUNDRY_SRC\", r\"other-src\");\n            let config = Config::load().unwrap();\n            assert_eq!(\n                config,\n                Config {\n                    src: \"other-src\".into(),\n                    out: \"myout\".into(),\n                    verbosity: 3,\n                    ..Config::default().normalized_optimizer_settings()\n                }\n            );\n\n            jail.set_env(\"FOUNDRY_PROFILE\", \"foo\");\n            let val: Result<String, _> = Config::figment().extract_inner(\"profile\");\n            assert!(val.is_err());\n\n            Ok(())\n        });\n    }\n\n    #[test]\n    fn test_extract_basic() {\n        figment::Jail::expect_with(|jail| {\n            jail.create_file(\n                \"foundry.toml\",\n                r#\"\n                [profile.default]\n                src = \"mysrc\"\n                out = \"myout\"\n                verbosity = 3\n                evm_version = 'berlin'\n\n                [profile.other]\n                src = \"other-src\"\n            \"#,\n            )?;\n            let loaded = Config::load().unwrap();\n            assert_eq!(loaded.evm_version, EvmVersion::Berlin);\n            let base = loaded.into_basic();\n            let default = Config::default();\n            assert_eq!(\n                base,\n                BasicConfig {\n                    profile: Config::DEFAULT_PROFILE,\n                    src: \"mysrc\".into(),\n                    out: \"myout\".into(),\n                    libs: default.libs.clone(),\n                    remappings: default.remappings.clone(),\n                }\n            );\n            jail.set_env(\"FOUNDRY_PROFILE\", r\"other\");\n            let base = Config::figment().extract::<BasicConfig>().unwrap();\n            assert_eq!(\n                base,\n                BasicConfig {\n                    profile: Config::DEFAULT_PROFILE,\n                    src: \"other-src\".into(),\n                    out: \"myout\".into(),\n                    libs: default.libs.clone(),\n                    remappings: default.remappings,\n                }\n            );\n            Ok(())\n        });\n    }\n\n    #[test]\n    #[should_panic]\n    fn test_parse_invalid_fuzz_weight() {\n        figment::Jail::expect_with(|jail| {\n            jail.create_file(\n                \"foundry.toml\",\n                r\"\n                [fuzz]\n                dictionary_weight = 101\n            \",\n            )?;\n            let _config = Config::load().unwrap();\n            Ok(())\n        });\n    }\n\n    #[test]\n    fn test_fallback_provider() {\n        figment::Jail::expect_with(|jail| {\n            jail.create_file(\n                \"foundry.toml\",\n                r\"\n                [fuzz]\n                runs = 1\n                include_storage = false\n                dictionary_weight = 99\n\n                [invariant]\n                runs = 420\n\n                [profile.ci.fuzz]\n                dictionary_weight = 5\n\n                [profile.ci.invariant]\n                runs = 400\n            \",\n            )?;\n\n            let invariant_default = InvariantConfig::default();\n            let config = Config::load().unwrap();\n\n            assert_ne!(config.invariant.runs, config.fuzz.runs);\n            assert_eq!(config.invariant.runs, 420);\n\n            assert_ne!(\n                config.fuzz.dictionary.include_storage,\n                invariant_default.dictionary.include_storage\n            );\n            assert_eq!(\n                config.invariant.dictionary.include_storage,\n                config.fuzz.dictionary.include_storage\n            );\n\n            assert_ne!(\n                config.fuzz.dictionary.dictionary_weight,\n                invariant_default.dictionary.dictionary_weight\n            );\n            assert_eq!(\n                config.invariant.dictionary.dictionary_weight,\n                config.fuzz.dictionary.dictionary_weight\n            );\n\n            jail.set_env(\"FOUNDRY_PROFILE\", \"ci\");\n            let ci_config = Config::load().unwrap();\n            assert_eq!(ci_config.fuzz.runs, 1);\n            assert_eq!(ci_config.invariant.runs, 400);\n            assert_eq!(ci_config.fuzz.dictionary.dictionary_weight, 5);\n            assert_eq!(\n                ci_config.invariant.dictionary.dictionary_weight,\n                config.fuzz.dictionary.dictionary_weight\n            );\n\n            Ok(())\n        })\n    }\n\n    #[test]\n    fn test_standalone_profile_sections() {\n        figment::Jail::expect_with(|jail| {\n            jail.create_file(\n                \"foundry.toml\",\n                r\"\n                [fuzz]\n                runs = 100\n\n                [invariant]\n                runs = 120\n\n                [profile.ci.fuzz]\n                runs = 420\n\n                [profile.ci.invariant]\n                runs = 500\n            \",\n            )?;\n\n            let config = Config::load().unwrap();\n            assert_eq!(config.fuzz.runs, 100);\n            assert_eq!(config.invariant.runs, 120);\n\n            jail.set_env(\"FOUNDRY_PROFILE\", \"ci\");\n            let config = Config::load().unwrap();\n            assert_eq!(config.fuzz.runs, 420);\n            assert_eq!(config.invariant.runs, 500);\n\n            Ok(())\n        });\n    }\n\n    #[test]\n    fn can_handle_deviating_dapp_aliases() {\n        figment::Jail::expect_with(|jail| {\n            let addr = Address::ZERO;\n            jail.set_env(\"DAPP_TEST_NUMBER\", 1337);\n            jail.set_env(\"DAPP_TEST_ADDRESS\", format!(\"{addr:?}\"));\n            jail.set_env(\"DAPP_TEST_FUZZ_RUNS\", 420);\n            jail.set_env(\"DAPP_TEST_DEPTH\", 20);\n            jail.set_env(\"DAPP_FORK_BLOCK\", 100);\n            jail.set_env(\"DAPP_BUILD_OPTIMIZE_RUNS\", 999);\n            jail.set_env(\"DAPP_BUILD_OPTIMIZE\", 0);\n\n            let config = Config::load().unwrap();\n\n            assert_eq!(config.block_number, U256::from(1337));\n            assert_eq!(config.sender, addr);\n            assert_eq!(config.fuzz.runs, 420);\n            assert_eq!(config.invariant.depth, 20);\n            assert_eq!(config.fork_block_number, Some(100));\n            assert_eq!(config.optimizer_runs, Some(999));\n            assert!(!config.optimizer.unwrap());\n\n            Ok(())\n        });\n    }\n\n    #[test]\n    fn can_parse_libraries() {\n        figment::Jail::expect_with(|jail| {\n            jail.set_env(\n                \"DAPP_LIBRARIES\",\n                \"[src/DssSpell.sol:DssExecLib:0x8De6DDbCd5053d32292AAA0D2105A32d108484a6]\",\n            );\n            let config = Config::load().unwrap();\n            assert_eq!(\n                config.libraries,\n                vec![\n                    \"src/DssSpell.sol:DssExecLib:0x8De6DDbCd5053d32292AAA0D2105A32d108484a6\"\n                        .to_string()\n                ]\n            );\n\n            jail.set_env(\n                \"DAPP_LIBRARIES\",\n                \"src/DssSpell.sol:DssExecLib:0x8De6DDbCd5053d32292AAA0D2105A32d108484a6\",\n            );\n            let config = Config::load().unwrap();\n            assert_eq!(\n                config.libraries,\n                vec![\n                    \"src/DssSpell.sol:DssExecLib:0x8De6DDbCd5053d32292AAA0D2105A32d108484a6\"\n                        .to_string(),\n                ]\n            );\n\n            jail.set_env(\n                \"DAPP_LIBRARIES\",\n                \"src/DssSpell.sol:DssExecLib:0x8De6DDbCd5053d32292AAA0D2105A32d108484a6,src/DssSpell.sol:DssExecLib:0x8De6DDbCd5053d32292AAA0D2105A32d108484a6\",\n            );\n            let config = Config::load().unwrap();\n            assert_eq!(\n                config.libraries,\n                vec![\n                    \"src/DssSpell.sol:DssExecLib:0x8De6DDbCd5053d32292AAA0D2105A32d108484a6\"\n                        .to_string(),\n                    \"src/DssSpell.sol:DssExecLib:0x8De6DDbCd5053d32292AAA0D2105A32d108484a6\"\n                        .to_string()\n                ]\n            );\n\n            Ok(())\n        });\n    }\n\n    #[test]\n    fn test_parse_many_libraries() {\n        figment::Jail::expect_with(|jail| {\n            jail.create_file(\n                \"foundry.toml\",\n                r\"\n                [profile.default]\n               libraries= [\n                        './src/SizeAuctionDiscount.sol:Chainlink:0xffedba5e171c4f15abaaabc86e8bd01f9b54dae5',\n                        './src/SizeAuction.sol:ChainlinkTWAP:0xffedba5e171c4f15abaaabc86e8bd01f9b54dae5',\n                        './src/SizeAuction.sol:Math:0x902f6cf364b8d9470d5793a9b2b2e86bddd21e0c',\n                        './src/test/ChainlinkTWAP.t.sol:ChainlinkTWAP:0xffedba5e171c4f15abaaabc86e8bd01f9b54dae5',\n                        './src/SizeAuctionDiscount.sol:Math:0x902f6cf364b8d9470d5793a9b2b2e86bddd21e0c',\n                    ]\n            \",\n            )?;\n            let config = Config::load().unwrap();\n\n            let libs = config.parsed_libraries().unwrap().libs;\n\n            similar_asserts::assert_eq!(\n                libs,\n                BTreeMap::from([\n                    (\n                        PathBuf::from(\"./src/SizeAuctionDiscount.sol\"),\n                        BTreeMap::from([\n                            (\n                                \"Chainlink\".to_string(),\n                                \"0xffedba5e171c4f15abaaabc86e8bd01f9b54dae5\".to_string()\n                            ),\n                            (\n                                \"Math\".to_string(),\n                                \"0x902f6cf364b8d9470d5793a9b2b2e86bddd21e0c\".to_string()\n                            )\n                        ])\n                    ),\n                    (\n                        PathBuf::from(\"./src/SizeAuction.sol\"),\n                        BTreeMap::from([\n                            (\n                                \"ChainlinkTWAP\".to_string(),\n                                \"0xffedba5e171c4f15abaaabc86e8bd01f9b54dae5\".to_string()\n                            ),\n                            (\n                                \"Math\".to_string(),\n                                \"0x902f6cf364b8d9470d5793a9b2b2e86bddd21e0c\".to_string()\n                            )\n                        ])\n                    ),\n                    (\n                        PathBuf::from(\"./src/test/ChainlinkTWAP.t.sol\"),\n                        BTreeMap::from([(\n                            \"ChainlinkTWAP\".to_string(),\n                            \"0xffedba5e171c4f15abaaabc86e8bd01f9b54dae5\".to_string()\n                        )])\n                    ),\n                ])\n            );\n\n            Ok(())\n        });\n    }\n\n    #[test]\n    fn config_roundtrip() {\n        figment::Jail::expect_with(|jail| {\n            let default = Config::default().normalized_optimizer_settings();\n            let basic = default.clone().into_basic();\n            jail.create_file(\"foundry.toml\", &basic.to_string_pretty().unwrap())?;\n\n            let mut other = Config::load().unwrap();\n            clear_warning(&mut other);\n            assert_eq!(default, other);\n\n            let other = other.into_basic();\n            assert_eq!(basic, other);\n\n            jail.create_file(\"foundry.toml\", &default.to_string_pretty().unwrap())?;\n            let mut other = Config::load().unwrap();\n            clear_warning(&mut other);\n            assert_eq!(default, other);\n\n            Ok(())\n        });\n    }\n\n    #[test]\n    fn test_fs_permissions() {\n        figment::Jail::expect_with(|jail| {\n            jail.create_file(\n                \"foundry.toml\",\n                r#\"\n                [profile.default]\n                fs_permissions = [{ access = \"read-write\", path = \"./\"}]\n            \"#,\n            )?;\n            let loaded = Config::load().unwrap();\n\n            assert_eq!(\n                loaded.fs_permissions,\n                FsPermissions::new(vec![PathPermission::read_write(\"./\")])\n            );\n\n            jail.create_file(\n                \"foundry.toml\",\n                r#\"\n                [profile.default]\n                fs_permissions = [{ access = \"none\", path = \"./\"}]\n            \"#,\n            )?;\n            let loaded = Config::load().unwrap();\n            assert_eq!(loaded.fs_permissions, FsPermissions::new(vec![PathPermission::none(\"./\")]));\n\n            Ok(())\n        });\n    }\n\n    #[test]\n    fn test_optimizer_settings_basic() {\n        figment::Jail::expect_with(|jail| {\n            jail.create_file(\n                \"foundry.toml\",\n                r\"\n                [profile.default]\n                optimizer = true\n\n                [profile.default.optimizer_details]\n                yul = false\n\n                [profile.default.optimizer_details.yulDetails]\n                stackAllocation = true\n            \",\n            )?;\n            let mut loaded = Config::load().unwrap();\n            clear_warning(&mut loaded);\n            assert_eq!(\n                loaded.optimizer_details,\n                Some(OptimizerDetails {\n                    yul: Some(false),\n                    yul_details: Some(YulDetails {\n                        stack_allocation: Some(true),\n                        ..Default::default()\n                    }),\n                    ..Default::default()\n                })\n            );\n\n            let s = loaded.to_string_pretty().unwrap();\n            jail.create_file(\"foundry.toml\", &s)?;\n\n            let mut reloaded = Config::load().unwrap();\n            clear_warning(&mut reloaded);\n            assert_eq!(loaded, reloaded);\n\n            Ok(())\n        });\n    }\n\n    #[test]\n    fn test_model_checker_settings_basic() {\n        figment::Jail::expect_with(|jail| {\n            jail.create_file(\n                \"foundry.toml\",\n                r\"\n                [profile.default]\n\n                [profile.default.model_checker]\n                contracts = { 'a.sol' = [ 'A1', 'A2' ], 'b.sol' = [ 'B1', 'B2' ] }\n                engine = 'chc'\n                targets = [ 'assert', 'outOfBounds' ]\n                timeout = 10000\n            \",\n            )?;\n            let mut loaded = Config::load().unwrap();\n            clear_warning(&mut loaded);\n            assert_eq!(\n                loaded.model_checker,\n                Some(ModelCheckerSettings {\n                    contracts: BTreeMap::from([\n                        (\"a.sol\".to_string(), vec![\"A1\".to_string(), \"A2\".to_string()]),\n                        (\"b.sol\".to_string(), vec![\"B1\".to_string(), \"B2\".to_string()]),\n                    ]),\n                    engine: Some(ModelCheckerEngine::CHC),\n                    targets: Some(vec![\n                        ModelCheckerTarget::Assert,\n                        ModelCheckerTarget::OutOfBounds\n                    ]),\n                    timeout: Some(10000),\n                    invariants: None,\n                    show_unproved: None,\n                    div_mod_with_slacks: None,\n                    solvers: None,\n                    show_unsupported: None,\n                    show_proved_safe: None,\n                })\n            );\n\n            let s = loaded.to_string_pretty().unwrap();\n            jail.create_file(\"foundry.toml\", &s)?;\n\n            let mut reloaded = Config::load().unwrap();\n            clear_warning(&mut reloaded);\n            assert_eq!(loaded, reloaded);\n\n            Ok(())\n        });\n    }\n\n    #[test]\n    fn test_model_checker_settings_with_bool_flags() {\n        figment::Jail::expect_with(|jail| {\n            jail.create_file(\n                \"foundry.toml\",\n                r\"\n                [profile.default]\n\n                [profile.default.model_checker]\n                engine = 'chc'\n                show_unproved = true\n                show_unsupported = true\n                show_proved_safe = false\n                div_mod_with_slacks = true\n            \",\n            )?;\n            let mut loaded = Config::load().unwrap();\n            clear_warning(&mut loaded);\n\n            let mc = loaded.model_checker.as_ref().unwrap();\n            assert_eq!(mc.show_unproved, Some(true));\n            assert_eq!(mc.show_unsupported, Some(true));\n            assert_eq!(mc.show_proved_safe, Some(false));\n            assert_eq!(mc.div_mod_with_slacks, Some(true));\n\n            // Test round-trip: serialize and reload\n            let s = loaded.to_string_pretty().unwrap();\n            jail.create_file(\"foundry.toml\", &s)?;\n\n            let mut reloaded = Config::load().unwrap();\n            clear_warning(&mut reloaded);\n\n            let mc_reloaded = reloaded.model_checker.as_ref().unwrap();\n            assert_eq!(mc_reloaded.show_unproved, Some(true));\n            assert_eq!(mc_reloaded.show_unsupported, Some(true));\n            assert_eq!(mc_reloaded.show_proved_safe, Some(false));\n            assert_eq!(mc_reloaded.div_mod_with_slacks, Some(true));\n\n            Ok(())\n        });\n    }\n\n    #[test]\n    fn test_model_checker_settings_relative_paths() {\n        figment::Jail::expect_with(|jail| {\n            jail.create_file(\n                \"foundry.toml\",\n                r\"\n                [profile.default]\n\n                [profile.default.model_checker]\n                contracts = { 'a.sol' = [ 'A1', 'A2' ], 'b.sol' = [ 'B1', 'B2' ] }\n                engine = 'chc'\n                targets = [ 'assert', 'outOfBounds' ]\n                timeout = 10000\n            \",\n            )?;\n            let loaded = Config::load().unwrap().sanitized();\n\n            // NOTE(onbjerg): We have to canonicalize the path here using dunce because figment will\n            // canonicalize the jail path using the standard library. The standard library *always*\n            // transforms Windows paths to some weird extended format, which none of our code base\n            // does.\n            let dir = foundry_compilers::utils::canonicalize(jail.directory())\n                .expect(\"Could not canonicalize jail path\");\n            assert_eq!(\n                loaded.model_checker,\n                Some(ModelCheckerSettings {\n                    contracts: BTreeMap::from([\n                        (\n                            format!(\"{}\", dir.join(\"a.sol\").display()),\n                            vec![\"A1\".to_string(), \"A2\".to_string()]\n                        ),\n                        (\n                            format!(\"{}\", dir.join(\"b.sol\").display()),\n                            vec![\"B1\".to_string(), \"B2\".to_string()]\n                        ),\n                    ]),\n                    engine: Some(ModelCheckerEngine::CHC),\n                    targets: Some(vec![\n                        ModelCheckerTarget::Assert,\n                        ModelCheckerTarget::OutOfBounds\n                    ]),\n                    timeout: Some(10000),\n                    invariants: None,\n                    show_unproved: None,\n                    div_mod_with_slacks: None,\n                    solvers: None,\n                    show_unsupported: None,\n                    show_proved_safe: None,\n                })\n            );\n\n            Ok(())\n        });\n    }\n\n    #[test]\n    fn test_fmt_config() {\n        figment::Jail::expect_with(|jail| {\n            jail.create_file(\n                \"foundry.toml\",\n                r#\"\n                [fmt]\n                line_length = 100\n                tab_width = 2\n                bracket_spacing = true\n                style = \"space\"\n            \"#,\n            )?;\n            let loaded = Config::load().unwrap().sanitized();\n            assert_eq!(\n                loaded.fmt,\n                FormatterConfig {\n                    line_length: 100,\n                    tab_width: 2,\n                    bracket_spacing: true,\n                    style: IndentStyle::Space,\n                    ..Default::default()\n                }\n            );\n\n            Ok(())\n        });\n    }\n\n    #[test]\n    fn test_lint_config() {\n        figment::Jail::expect_with(|jail| {\n            jail.create_file(\n                \"foundry.toml\",\n                r\"\n                [lint]\n                severity = ['high', 'medium']\n                exclude_lints = ['incorrect-shift']\n                \",\n            )?;\n            let loaded = Config::load().unwrap().sanitized();\n            assert_eq!(\n                loaded.lint,\n                LinterConfig {\n                    severity: vec![LintSeverity::High, LintSeverity::Med],\n                    exclude_lints: vec![\"incorrect-shift\".into()],\n                    ..Default::default()\n                }\n            );\n\n            Ok(())\n        });\n    }\n\n    #[test]\n    fn test_invariant_config() {\n        figment::Jail::expect_with(|jail| {\n            jail.create_file(\n                \"foundry.toml\",\n                r\"\n                [invariant]\n                runs = 512\n                depth = 10\n            \",\n            )?;\n\n            let loaded = Config::load().unwrap().sanitized();\n            assert_eq!(\n                loaded.invariant,\n                InvariantConfig {\n                    runs: 512,\n                    depth: 10,\n                    failure_persist_dir: Some(PathBuf::from(\"cache/invariant\")),\n                    ..Default::default()\n                }\n            );\n\n            Ok(())\n        });\n    }\n\n    #[test]\n    fn test_standalone_sections_env() {\n        figment::Jail::expect_with(|jail| {\n            jail.create_file(\n                \"foundry.toml\",\n                r\"\n                [fuzz]\n                runs = 100\n\n                [invariant]\n                depth = 1\n            \",\n            )?;\n\n            jail.set_env(\"FOUNDRY_FMT_LINE_LENGTH\", \"95\");\n            jail.set_env(\"FOUNDRY_FUZZ_DICTIONARY_WEIGHT\", \"99\");\n            jail.set_env(\"FOUNDRY_INVARIANT_DEPTH\", \"5\");\n\n            let config = Config::load().unwrap();\n            assert_eq!(config.fmt.line_length, 95);\n            assert_eq!(config.fuzz.dictionary.dictionary_weight, 99);\n            assert_eq!(config.invariant.depth, 5);\n\n            Ok(())\n        });\n    }\n\n    #[test]\n    fn test_parse_with_profile() {\n        let foundry_str = r\"\n            [profile.default]\n            src = 'src'\n            out = 'out'\n            libs = ['lib']\n\n            # See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options\n        \";\n        assert_eq!(\n            parse_with_profile::<BasicConfig>(foundry_str).unwrap().unwrap(),\n            (\n                Config::DEFAULT_PROFILE,\n                BasicConfig {\n                    profile: Config::DEFAULT_PROFILE,\n                    src: \"src\".into(),\n                    out: \"out\".into(),\n                    libs: vec![\"lib\".into()],\n                    remappings: vec![]\n                }\n            )\n        );\n    }\n\n    #[test]\n    fn test_implicit_profile_loads() {\n        figment::Jail::expect_with(|jail| {\n            jail.create_file(\n                \"foundry.toml\",\n                r\"\n                [default]\n                src = 'my-src'\n                out = 'my-out'\n            \",\n            )?;\n            let loaded = Config::load().unwrap().sanitized();\n            assert_eq!(loaded.src.file_name().unwrap(), \"my-src\");\n            assert_eq!(loaded.out.file_name().unwrap(), \"my-out\");\n            assert_eq!(\n                loaded.warnings,\n                vec![Warning::UnknownSection {\n                    unknown_section: Profile::new(\"default\"),\n                    source: Some(\"foundry.toml\".into())\n                }]\n            );\n\n            Ok(())\n        });\n    }\n\n    #[test]\n    fn test_etherscan_api_key() {\n        figment::Jail::expect_with(|jail| {\n            jail.create_file(\n                \"foundry.toml\",\n                r\"\n                [default]\n            \",\n            )?;\n            jail.set_env(\"ETHERSCAN_API_KEY\", \"\");\n            let loaded = Config::load().unwrap().sanitized();\n            assert!(loaded.etherscan_api_key.is_none());\n\n            jail.set_env(\"ETHERSCAN_API_KEY\", \"DUMMY\");\n            let loaded = Config::load().unwrap().sanitized();\n            assert_eq!(loaded.etherscan_api_key, Some(\"DUMMY\".into()));\n\n            Ok(())\n        });\n    }\n\n    #[test]\n    fn test_etherscan_api_key_figment() {\n        figment::Jail::expect_with(|jail| {\n            jail.create_file(\n                \"foundry.toml\",\n                r\"\n                [default]\n                etherscan_api_key = 'DUMMY'\n            \",\n            )?;\n            jail.set_env(\"ETHERSCAN_API_KEY\", \"ETHER\");\n\n            let figment = Config::figment_with_root(jail.directory())\n                .merge((\"etherscan_api_key\", \"USER_KEY\"));\n\n            let loaded = Config::from_provider(figment).unwrap();\n            assert_eq!(loaded.etherscan_api_key, Some(\"USER_KEY\".into()));\n\n            Ok(())\n        });\n    }\n\n    #[test]\n    fn test_normalize_defaults() {\n        figment::Jail::expect_with(|jail| {\n            jail.create_file(\n                \"foundry.toml\",\n                r\"\n                [default]\n                solc = '0.8.13'\n            \",\n            )?;\n\n            let loaded = Config::load().unwrap().sanitized();\n            assert_eq!(loaded.evm_version, EvmVersion::London);\n            Ok(())\n        });\n    }\n\n    // a test to print the config, mainly used to update the example config in the README\n    #[expect(clippy::disallowed_macros)]\n    #[test]\n    #[ignore]\n    fn print_config() {\n        let config = Config {\n            optimizer_details: Some(OptimizerDetails {\n                peephole: None,\n                inliner: None,\n                jumpdest_remover: None,\n                order_literals: None,\n                deduplicate: None,\n                cse: None,\n                constant_optimizer: Some(true),\n                yul: Some(true),\n                yul_details: Some(YulDetails {\n                    stack_allocation: None,\n                    optimizer_steps: Some(\"dhfoDgvulfnTUtnIf\".to_string()),\n                }),\n                simple_counter_for_loop_unchecked_increment: None,\n            }),\n            ..Default::default()\n        };\n        println!(\"{}\", config.to_string_pretty().unwrap());\n    }\n\n    #[test]\n    fn can_use_impl_figment_macro() {\n        #[derive(Default, Serialize)]\n        struct MyArgs {\n            #[serde(skip_serializing_if = \"Option::is_none\")]\n            root: Option<PathBuf>,\n        }\n        impl_figment_convert!(MyArgs);\n\n        impl Provider for MyArgs {\n            fn metadata(&self) -> Metadata {\n                Metadata::default()\n            }\n\n            fn data(&self) -> Result<Map<Profile, Dict>, Error> {\n                let value = Value::serialize(self)?;\n                let error = InvalidType(value.to_actual(), \"map\".into());\n                let dict = value.into_dict().ok_or(error)?;\n                Ok(Map::from([(Config::selected_profile(), dict)]))\n            }\n        }\n\n        let _figment: Figment = From::from(&MyArgs::default());\n\n        #[derive(Default)]\n        struct Outer {\n            start: MyArgs,\n            other: MyArgs,\n            another: MyArgs,\n        }\n        impl_figment_convert!(Outer, start, other, another);\n\n        let _figment: Figment = From::from(&Outer::default());\n    }\n\n    #[test]\n    fn list_cached_blocks() -> eyre::Result<()> {\n        fn fake_block_cache(chain_path: &Path, block_number: &str, size_bytes: usize) {\n            let block_path = chain_path.join(block_number);\n            fs::create_dir(block_path.as_path()).unwrap();\n            let file_path = block_path.join(\"storage.json\");\n            let mut file = File::create(file_path).unwrap();\n            writeln!(file, \"{}\", vec![' '; size_bytes - 1].iter().collect::<String>()).unwrap();\n        }\n\n        fn fake_block_cache_block_path_as_file(\n            chain_path: &Path,\n            block_number: &str,\n            size_bytes: usize,\n        ) {\n            let block_path = chain_path.join(block_number);\n            let mut file = File::create(block_path).unwrap();\n            writeln!(file, \"{}\", vec![' '; size_bytes - 1].iter().collect::<String>()).unwrap();\n        }\n\n        let chain_dir = tempdir()?;\n\n        fake_block_cache(chain_dir.path(), \"1\", 100);\n        fake_block_cache(chain_dir.path(), \"2\", 500);\n        fake_block_cache_block_path_as_file(chain_dir.path(), \"3\", 900);\n        // Pollution file that should not show up in the cached block\n        let mut pol_file = File::create(chain_dir.path().join(\"pol.txt\")).unwrap();\n        writeln!(pol_file, \"{}\", [' '; 10].iter().collect::<String>()).unwrap();\n\n        let result = Config::get_cached_blocks(chain_dir.path())?;\n\n        assert_eq!(result.len(), 3);\n        let block1 = &result.iter().find(|x| x.0 == \"1\").unwrap();\n        let block2 = &result.iter().find(|x| x.0 == \"2\").unwrap();\n        let block3 = &result.iter().find(|x| x.0 == \"3\").unwrap();\n\n        assert_eq!(block1.0, \"1\");\n        assert_eq!(block1.1, 100);\n        assert_eq!(block2.0, \"2\");\n        assert_eq!(block2.1, 500);\n        assert_eq!(block3.0, \"3\");\n        assert_eq!(block3.1, 900);\n\n        chain_dir.close()?;\n        Ok(())\n    }\n\n    #[test]\n    fn list_etherscan_cache() -> eyre::Result<()> {\n        fn fake_etherscan_cache(chain_path: &Path, address: &str, size_bytes: usize) {\n            let metadata_path = chain_path.join(\"sources\");\n            let abi_path = chain_path.join(\"abi\");\n            let _ = fs::create_dir(metadata_path.as_path());\n            let _ = fs::create_dir(abi_path.as_path());\n\n            let metadata_file_path = metadata_path.join(address);\n            let mut metadata_file = File::create(metadata_file_path).unwrap();\n            writeln!(metadata_file, \"{}\", vec![' '; size_bytes / 2 - 1].iter().collect::<String>())\n                .unwrap();\n\n            let abi_file_path = abi_path.join(address);\n            let mut abi_file = File::create(abi_file_path).unwrap();\n            writeln!(abi_file, \"{}\", vec![' '; size_bytes / 2 - 1].iter().collect::<String>())\n                .unwrap();\n        }\n\n        let chain_dir = tempdir()?;\n\n        fake_etherscan_cache(chain_dir.path(), \"1\", 100);\n        fake_etherscan_cache(chain_dir.path(), \"2\", 500);\n\n        let result = Config::get_cached_block_explorer_data(chain_dir.path())?;\n\n        assert_eq!(result, 600);\n\n        chain_dir.close()?;\n        Ok(())\n    }\n\n    #[test]\n    fn test_parse_error_codes() {\n        figment::Jail::expect_with(|jail| {\n            jail.create_file(\n                \"foundry.toml\",\n                r#\"\n                [default]\n                ignored_error_codes = [\"license\", \"unreachable\", 1337]\n            \"#,\n            )?;\n\n            let config = Config::load().unwrap();\n            assert_eq!(\n                config.ignored_error_codes,\n                vec![\n                    SolidityErrorCode::SpdxLicenseNotProvided,\n                    SolidityErrorCode::Unreachable,\n                    SolidityErrorCode::Other(1337)\n                ]\n            );\n\n            Ok(())\n        });\n    }\n\n    #[test]\n    fn test_parse_file_paths() {\n        figment::Jail::expect_with(|jail| {\n            jail.create_file(\n                \"foundry.toml\",\n                r#\"\n                [default]\n                ignored_warnings_from = [\"something\"]\n            \"#,\n            )?;\n\n            let config = Config::load().unwrap();\n            assert_eq!(config.ignored_file_paths, vec![Path::new(\"something\").to_path_buf()]);\n\n            Ok(())\n        });\n    }\n\n    #[test]\n    fn test_parse_optimizer_settings() {\n        figment::Jail::expect_with(|jail| {\n            jail.create_file(\n                \"foundry.toml\",\n                r\"\n                [default]\n                [profile.default.optimizer_details]\n            \",\n            )?;\n\n            let config = Config::load().unwrap();\n            assert_eq!(config.optimizer_details, Some(OptimizerDetails::default()));\n\n            Ok(())\n        });\n    }\n\n    #[test]\n    fn test_parse_labels() {\n        figment::Jail::expect_with(|jail| {\n            jail.create_file(\n                \"foundry.toml\",\n                r#\"\n                [labels]\n                0x1F98431c8aD98523631AE4a59f267346ea31F984 = \"Uniswap V3: Factory\"\n                0xC36442b4a4522E871399CD717aBDD847Ab11FE88 = \"Uniswap V3: Positions NFT\"\n            \"#,\n            )?;\n\n            let config = Config::load().unwrap();\n            assert_eq!(\n                config.labels,\n                AddressHashMap::from_iter(vec![\n                    (\n                        address!(\"0x1F98431c8aD98523631AE4a59f267346ea31F984\"),\n                        \"Uniswap V3: Factory\".to_string()\n                    ),\n                    (\n                        address!(\"0xC36442b4a4522E871399CD717aBDD847Ab11FE88\"),\n                        \"Uniswap V3: Positions NFT\".to_string()\n                    ),\n                ])\n            );\n\n            Ok(())\n        });\n    }\n\n    #[test]\n    fn test_parse_vyper() {\n        figment::Jail::expect_with(|jail| {\n            jail.create_file(\n                \"foundry.toml\",\n                r#\"\n                [vyper]\n                optimize = \"codesize\"\n                path = \"/path/to/vyper\"\n                experimental_codegen = true\n            \"#,\n            )?;\n\n            let config = Config::load().unwrap();\n            assert_eq!(\n                config.vyper,\n                VyperConfig {\n                    optimize: Some(VyperOptimizationMode::Codesize),\n                    path: Some(\"/path/to/vyper\".into()),\n                    experimental_codegen: Some(true),\n                }\n            );\n\n            Ok(())\n        });\n    }\n\n    #[test]\n    fn test_parse_soldeer() {\n        figment::Jail::expect_with(|jail| {\n            jail.create_file(\n                \"foundry.toml\",\n                r#\"\n                [soldeer]\n                remappings_generate = true\n                remappings_regenerate = false\n                remappings_version = true\n                remappings_prefix = \"@\"\n                remappings_location = \"txt\"\n                recursive_deps = true\n            \"#,\n            )?;\n\n            let config = Config::load().unwrap();\n\n            assert_eq!(\n                config.soldeer,\n                Some(SoldeerConfig {\n                    remappings_generate: true,\n                    remappings_regenerate: false,\n                    remappings_version: true,\n                    remappings_prefix: \"@\".to_string(),\n                    remappings_location: RemappingsLocation::Txt,\n                    recursive_deps: true,\n                })\n            );\n\n            Ok(())\n        });\n    }\n\n    // <https://github.com/foundry-rs/foundry/issues/10926>\n    #[test]\n    fn test_resolve_mesc_by_chain_id() {\n        let s = r#\"{\n    \"mesc_version\": \"0.2.1\",\n    \"default_endpoint\": null,\n    \"endpoints\": {\n        \"sophon_50104\": {\n            \"name\": \"sophon_50104\",\n            \"url\": \"https://rpc.sophon.xyz\",\n            \"chain_id\": \"50104\",\n            \"endpoint_metadata\": {}\n        }\n    },\n    \"network_defaults\": {\n    },\n    \"network_names\": {},\n    \"profiles\": {\n        \"foundry\": {\n            \"name\": \"foundry\",\n            \"default_endpoint\": \"local_ethereum\",\n            \"network_defaults\": {\n                \"50104\": \"sophon_50104\"\n            },\n            \"profile_metadata\": {},\n            \"use_mesc\": true\n        }\n    },\n    \"global_metadata\": {}\n}\"#;\n\n        let config = serde_json::from_str(s).unwrap();\n        let endpoint = mesc::query::get_endpoint_by_network(&config, \"50104\", Some(\"foundry\"))\n            .unwrap()\n            .unwrap();\n        assert_eq!(endpoint.url, \"https://rpc.sophon.xyz\");\n\n        let s = r#\"{\n    \"mesc_version\": \"0.2.1\",\n    \"default_endpoint\": null,\n    \"endpoints\": {\n        \"sophon_50104\": {\n            \"name\": \"sophon_50104\",\n            \"url\": \"https://rpc.sophon.xyz\",\n            \"chain_id\": \"50104\",\n            \"endpoint_metadata\": {}\n        }\n    },\n    \"network_defaults\": {\n        \"50104\": \"sophon_50104\"\n    },\n    \"network_names\": {},\n    \"profiles\": {},\n    \"global_metadata\": {}\n}\"#;\n\n        let config = serde_json::from_str(s).unwrap();\n        let endpoint = mesc::query::get_endpoint_by_network(&config, \"50104\", Some(\"foundry\"))\n            .unwrap()\n            .unwrap();\n        assert_eq!(endpoint.url, \"https://rpc.sophon.xyz\");\n    }\n\n    #[test]\n    fn test_get_etherscan_config_with_unknown_chain() {\n        figment::Jail::expect_with(|jail| {\n            jail.create_file(\n                \"foundry.toml\",\n                r#\"\n                [etherscan]\n                mainnet = { chain = 3658348, key = \"api-key\"}\n            \"#,\n            )?;\n            let config = Config::load().unwrap();\n            let unknown_chain = Chain::from_id(3658348);\n            let result = config.get_etherscan_config_with_chain(Some(unknown_chain));\n            assert!(result.is_err());\n            let error_msg = result.unwrap_err().to_string();\n            assert!(error_msg.contains(\"No known Etherscan API URL for chain `3658348`\"));\n            assert!(error_msg.contains(\"Specify a `url`\"));\n            assert!(error_msg.contains(\"Verify the chain `3658348` is correct\"));\n\n            Ok(())\n        });\n    }\n\n    #[test]\n    fn test_get_etherscan_config_with_existing_chain_and_url() {\n        figment::Jail::expect_with(|jail| {\n            jail.create_file(\n                \"foundry.toml\",\n                r#\"\n                [etherscan]\n                mainnet = { chain = 1, key = \"api-key\" }\n            \"#,\n            )?;\n            let config = Config::load().unwrap();\n            let unknown_chain = Chain::from_id(1);\n            let result = config.get_etherscan_config_with_chain(Some(unknown_chain));\n            assert!(result.is_ok());\n            Ok(())\n        });\n    }\n\n    #[test]\n    fn test_can_inherit_a_base_toml() {\n        figment::Jail::expect_with(|jail| {\n            // Create base config file with optimizer_runs = 800\n            jail.create_file(\n                \"base-config.toml\",\n                r#\"\n                    [profile.default]\n                    optimizer_runs = 800\n\n                    [invariant]\n                    runs = 1000\n\n                    [rpc_endpoints]\n                    mainnet = \"https://example.com\"\n                    optimism = \"https://example-2.com/\"\n                    \"#,\n            )?;\n\n            // Create local config that inherits from base-config.toml\n            jail.create_file(\n                \"foundry.toml\",\n                r#\"\n                    [profile.default]\n                    extends = \"base-config.toml\"\n\n                    [invariant]\n                    runs = 333\n                    depth = 15\n\n                    [rpc_endpoints]\n                    mainnet = \"https://test.xyz/rpc\"\n                    \"#,\n            )?;\n\n            let config = Config::load().unwrap();\n            assert_eq!(config.extends, Some(Extends::Path(\"base-config.toml\".to_string())));\n\n            // optimizer_runs should be inherited from base-config.toml\n            assert_eq!(config.optimizer_runs, Some(800));\n\n            // invariant settings should be overridden by local config\n            assert_eq!(config.invariant.runs, 333);\n            assert_eq!(config.invariant.depth, 15);\n\n            // rpc_endpoints.mainnet should be overridden by local config\n            // optimism should be inherited from base config\n            let endpoints = config.rpc_endpoints.resolved();\n            assert!(\n                endpoints.get(\"mainnet\").unwrap().url().unwrap().contains(\"https://test.xyz/rpc\")\n            );\n            assert!(endpoints.get(\"optimism\").unwrap().url().unwrap().contains(\"example-2.com\"));\n\n            Ok(())\n        });\n    }\n\n    #[test]\n    fn test_inheritance_validation() {\n        figment::Jail::expect_with(|jail| {\n            // Test 1: Base file with 'extends' should fail\n            jail.create_file(\n                \"base-with-inherit.toml\",\n                r#\"\n                    [profile.default]\n                    extends = \"another.toml\"\n                    optimizer_runs = 800\n                    \"#,\n            )?;\n\n            jail.create_file(\n                \"foundry.toml\",\n                r#\"\n                    [profile.default]\n                    extends = \"base-with-inherit.toml\"\n                    \"#,\n            )?;\n\n            // Should fail because base file has 'extends'\n            let result = Config::load();\n            assert!(result.is_err());\n            assert!(result.unwrap_err().to_string().contains(\"Nested inheritance is not allowed\"));\n\n            // Test 2: Circular reference should fail\n            jail.create_file(\n                \"foundry.toml\",\n                r#\"\n                    [profile.default]\n                    extends = \"foundry.toml\"\n                    \"#,\n            )?;\n\n            let result = Config::load();\n            assert!(result.is_err());\n            assert!(result.unwrap_err().to_string().contains(\"cannot inherit from itself\"));\n\n            // Test 3: Non-existent base file should fail\n            jail.create_file(\n                \"foundry.toml\",\n                r#\"\n                    [profile.default]\n                    extends = \"non-existent.toml\"\n                    \"#,\n            )?;\n\n            let result = Config::load();\n            assert!(result.is_err());\n            let err_msg = result.unwrap_err().to_string();\n            assert!(\n                err_msg.contains(\"does not exist\")\n                    || err_msg.contains(\"Failed to resolve inherited config path\"),\n                \"Error message: {err_msg}\"\n            );\n\n            Ok(())\n        });\n    }\n\n    #[test]\n    fn test_complex_inheritance_merging() {\n        figment::Jail::expect_with(|jail| {\n            // Create a comprehensive base config\n            jail.create_file(\n                \"base.toml\",\n                r#\"\n                    [profile.default]\n                    optimizer = true\n                    optimizer_runs = 1000\n                    via_ir = false\n                    solc = \"0.8.19\"\n\n                    [invariant]\n                    runs = 500\n                    depth = 100\n\n                    [fuzz]\n                    runs = 256\n                    seed = \"0x123\"\n\n                    [rpc_endpoints]\n                    mainnet = \"https://base-mainnet.com\"\n                    optimism = \"https://base-optimism.com\"\n                    arbitrum = \"https://base-arbitrum.com\"\n                    \"#,\n            )?;\n\n            // Create local config that overrides some values\n            jail.create_file(\n                \"foundry.toml\",\n                r#\"\n                    [profile.default]\n                    extends = \"base.toml\"\n                    optimizer_runs = 200  # Override\n                    via_ir = true        # Override\n                    # optimizer and solc are inherited\n\n                    [invariant]\n                    runs = 333  # Override\n                    # depth is inherited\n\n                    # fuzz section is fully inherited\n\n                    [rpc_endpoints]\n                    mainnet = \"https://local-mainnet.com\"  # Override\n                    # optimism and arbitrum are inherited\n                    polygon = \"https://local-polygon.com\"  # New\n                    \"#,\n            )?;\n\n            let config = Config::load().unwrap();\n\n            // Check profile.default values\n            assert_eq!(config.optimizer, Some(true));\n            assert_eq!(config.optimizer_runs, Some(200));\n            assert_eq!(config.via_ir, true);\n            assert_eq!(config.solc, Some(SolcReq::Version(Version::new(0, 8, 19))));\n\n            // Check invariant section\n            assert_eq!(config.invariant.runs, 333);\n            assert_eq!(config.invariant.depth, 100);\n\n            // Check fuzz section (fully inherited)\n            assert_eq!(config.fuzz.runs, 256);\n            assert_eq!(config.fuzz.seed, Some(U256::from(0x123)));\n\n            // Check rpc_endpoints\n            let endpoints = config.rpc_endpoints.resolved();\n            assert!(endpoints.get(\"mainnet\").unwrap().url().unwrap().contains(\"local-mainnet\"));\n            assert!(endpoints.get(\"optimism\").unwrap().url().unwrap().contains(\"base-optimism\"));\n            assert!(endpoints.get(\"arbitrum\").unwrap().url().unwrap().contains(\"base-arbitrum\"));\n            assert!(endpoints.get(\"polygon\").unwrap().url().unwrap().contains(\"local-polygon\"));\n\n            Ok(())\n        });\n    }\n\n    #[test]\n    fn test_inheritance_with_different_profiles() {\n        figment::Jail::expect_with(|jail| {\n            // Create base config with multiple profiles\n            jail.create_file(\n                \"base.toml\",\n                r#\"\n                    [profile.default]\n                    optimizer = true\n                    optimizer_runs = 200\n\n                    [profile.ci]\n                    optimizer = true\n                    optimizer_runs = 10000\n                    via_ir = true\n\n                    [profile.dev]\n                    optimizer = false\n                    \"#,\n            )?;\n\n            // Local config inherits from base - only for default profile\n            jail.create_file(\n                \"foundry.toml\",\n                r#\"\n                    [profile.default]\n                    extends = \"base.toml\"\n                    verbosity = 3\n\n                    [profile.ci]\n                    optimizer_runs = 5000  # This doesn't inherit from base.toml's ci profile\n                    \"#,\n            )?;\n\n            // Test default profile\n            let config = Config::load().unwrap();\n            assert_eq!(config.optimizer, Some(true));\n            assert_eq!(config.optimizer_runs, Some(200));\n            assert_eq!(config.verbosity, 3);\n\n            // Test CI profile (NO 'extends', so doesn't inherit from base)\n            jail.set_env(\"FOUNDRY_PROFILE\", \"ci\");\n            let config = Config::load().unwrap();\n            assert_eq!(config.optimizer_runs, Some(5000));\n            assert_eq!(config.optimizer, Some(true));\n            // via_ir is not set in local ci profile and there's no 'extends', so default\n            assert_eq!(config.via_ir, false);\n\n            Ok(())\n        });\n    }\n\n    #[test]\n    fn test_inheritance_with_env_vars() {\n        figment::Jail::expect_with(|jail| {\n            jail.create_file(\n                \"base.toml\",\n                r#\"\n                    [profile.default]\n                    optimizer_runs = 500\n                    sender = \"0x0000000000000000000000000000000000000001\"\n                    verbosity = 1\n                    \"#,\n            )?;\n\n            jail.create_file(\n                \"foundry.toml\",\n                r#\"\n                    [profile.default]\n                    extends = \"base.toml\"\n                    verbosity = 2\n                    \"#,\n            )?;\n\n            // Environment variables should override both base and local values\n            jail.set_env(\"FOUNDRY_OPTIMIZER_RUNS\", \"999\");\n            jail.set_env(\"FOUNDRY_VERBOSITY\", \"4\");\n\n            let config = Config::load().unwrap();\n            assert_eq!(config.optimizer_runs, Some(999));\n            assert_eq!(config.verbosity, 4);\n            assert_eq!(\n                config.sender,\n                \"0x0000000000000000000000000000000000000001\"\n                    .parse::<alloy_primitives::Address>()\n                    .unwrap()\n            );\n\n            Ok(())\n        });\n    }\n\n    #[test]\n    fn test_inheritance_with_subdirectories() {\n        figment::Jail::expect_with(|jail| {\n            // Create base config in a subdirectory\n            jail.create_dir(\"configs\")?;\n            jail.create_file(\n                \"configs/base.toml\",\n                r#\"\n                    [profile.default]\n                    optimizer_runs = 800\n                    src = \"contracts\"\n                    \"#,\n            )?;\n\n            // Reference it with relative path\n            jail.create_file(\n                \"foundry.toml\",\n                r#\"\n                    [profile.default]\n                    extends = \"configs/base.toml\"\n                    test = \"tests\"\n                    \"#,\n            )?;\n\n            let config = Config::load().unwrap();\n            assert_eq!(config.optimizer_runs, Some(800));\n            assert_eq!(config.src, PathBuf::from(\"contracts\"));\n            assert_eq!(config.test, PathBuf::from(\"tests\"));\n\n            // Test with parent directory reference\n            jail.create_dir(\"project\")?;\n            jail.create_file(\n                \"shared-base.toml\",\n                r#\"\n                    [profile.default]\n                    optimizer_runs = 1500\n                    \"#,\n            )?;\n\n            jail.create_file(\n                \"project/foundry.toml\",\n                r#\"\n                    [profile.default]\n                    extends = \"../shared-base.toml\"\n                    \"#,\n            )?;\n\n            std::env::set_current_dir(jail.directory().join(\"project\")).unwrap();\n            let config = Config::load().unwrap();\n            assert_eq!(config.optimizer_runs, Some(1500));\n\n            Ok(())\n        });\n    }\n\n    #[test]\n    fn test_inheritance_with_empty_files() {\n        figment::Jail::expect_with(|jail| {\n            // Empty base file\n            jail.create_file(\n                \"base.toml\",\n                r#\"\n                    [profile.default]\n                    \"#,\n            )?;\n\n            jail.create_file(\n                \"foundry.toml\",\n                r#\"\n                    [profile.default]\n                    extends = \"base.toml\"\n                    optimizer_runs = 300\n                    \"#,\n            )?;\n\n            let config = Config::load().unwrap();\n            assert_eq!(config.optimizer_runs, Some(300));\n\n            // Empty local file (only 'extends')\n            jail.create_file(\n                \"base2.toml\",\n                r#\"\n                    [profile.default]\n                    optimizer_runs = 400\n                    via_ir = true\n                    \"#,\n            )?;\n\n            jail.create_file(\n                \"foundry.toml\",\n                r#\"\n                    [profile.default]\n                    extends = \"base2.toml\"\n                    \"#,\n            )?;\n\n            let config = Config::load().unwrap();\n            assert_eq!(config.optimizer_runs, Some(400));\n            assert!(config.via_ir);\n\n            Ok(())\n        });\n    }\n\n    #[test]\n    fn test_inheritance_array_and_table_merging() {\n        figment::Jail::expect_with(|jail| {\n            jail.create_file(\n                \"base.toml\",\n                r#\"\n                    [profile.default]\n                    libs = [\"lib\", \"node_modules\"]\n                    ignored_error_codes = [5667, 1878]\n                    extra_output = [\"metadata\", \"ir\"]\n\n                    [profile.default.model_checker]\n                    engine = \"chc\"\n                    timeout = 10000\n                    targets = [\"assert\"]\n\n                    [profile.default.optimizer_details]\n                    peephole = true\n                    inliner = true\n                    \"#,\n            )?;\n\n            jail.create_file(\n                \"foundry.toml\",\n                r#\"\n                    [profile.default]\n                    extends = \"base.toml\"\n                    libs = [\"custom-lib\"]  # Concatenates with base array\n                    ignored_error_codes = [2018]  # Concatenates with base array\n\n                    [profile.default.model_checker]\n                    timeout = 5000  # Overrides base value\n                    # engine and targets are inherited\n\n                    [profile.default.optimizer_details]\n                    jumpdest_remover = true  # Adds new field\n                    # peephole and inliner are inherited\n                    \"#,\n            )?;\n\n            let config = Config::load().unwrap();\n\n            // Arrays are now concatenated with admerge (base + local)\n            assert_eq!(\n                config.libs,\n                vec![\n                    PathBuf::from(\"lib\"),\n                    PathBuf::from(\"node_modules\"),\n                    PathBuf::from(\"custom-lib\")\n                ]\n            );\n            assert_eq!(\n                config.ignored_error_codes,\n                vec![\n                    SolidityErrorCode::UnusedFunctionParameter, // 5667 from base.toml\n                    SolidityErrorCode::SpdxLicenseNotProvided,  // 1878 from base.toml\n                    SolidityErrorCode::FunctionStateMutabilityCanBeRestricted  // 2018 from local\n                ]\n            );\n\n            // Tables are deep-merged\n            assert_eq!(config.model_checker.as_ref().unwrap().timeout, Some(5000));\n            assert_eq!(\n                config.model_checker.as_ref().unwrap().engine,\n                Some(ModelCheckerEngine::CHC)\n            );\n            assert_eq!(\n                config.model_checker.as_ref().unwrap().targets,\n                Some(vec![ModelCheckerTarget::Assert])\n            );\n\n            // optimizer_details table is actually merged, not replaced\n            assert_eq!(config.optimizer_details.as_ref().unwrap().peephole, Some(true));\n            assert_eq!(config.optimizer_details.as_ref().unwrap().inliner, Some(true));\n            assert_eq!(config.optimizer_details.as_ref().unwrap().jumpdest_remover, None);\n\n            Ok(())\n        });\n    }\n\n    #[test]\n    fn test_inheritance_with_special_sections() {\n        figment::Jail::expect_with(|jail| {\n            jail.create_file(\n                \"base.toml\",\n                r#\"\n                    [profile.default]\n                    # Base file should not have 'extends' to avoid nested inheritance\n\n                    [labels]\n                    \"0x0000000000000000000000000000000000000001\" = \"Alice\"\n                    \"0x0000000000000000000000000000000000000002\" = \"Bob\"\n\n                    [[profile.default.fs_permissions]]\n                    access = \"read\"\n                    path = \"./src\"\n\n                    [[profile.default.fs_permissions]]\n                    access = \"read-write\"\n                    path = \"./cache\"\n                    \"#,\n            )?;\n\n            jail.create_file(\n                \"foundry.toml\",\n                r#\"\n                    [profile.default]\n                    extends = \"base.toml\"\n\n                    [labels]\n                    \"0x0000000000000000000000000000000000000002\" = \"Bob Updated\"\n                    \"0x0000000000000000000000000000000000000003\" = \"Charlie\"\n\n                    [[profile.default.fs_permissions]]\n                    access = \"read\"\n                    path = \"./test\"\n                    \"#,\n            )?;\n\n            let config = Config::load().unwrap();\n\n            // Labels should be merged\n            assert_eq!(\n                config.labels.get(\n                    &\"0x0000000000000000000000000000000000000001\"\n                        .parse::<alloy_primitives::Address>()\n                        .unwrap()\n                ),\n                Some(&\"Alice\".to_string())\n            );\n            assert_eq!(\n                config.labels.get(\n                    &\"0x0000000000000000000000000000000000000002\"\n                        .parse::<alloy_primitives::Address>()\n                        .unwrap()\n                ),\n                Some(&\"Bob Updated\".to_string())\n            );\n            assert_eq!(\n                config.labels.get(\n                    &\"0x0000000000000000000000000000000000000003\"\n                        .parse::<alloy_primitives::Address>()\n                        .unwrap()\n                ),\n                Some(&\"Charlie\".to_string())\n            );\n\n            // fs_permissions array is now concatenated with addmerge (base + local)\n            assert_eq!(config.fs_permissions.permissions.len(), 3); // 2 from base + 1 from local\n            // Check that all permissions are present\n            assert!(\n                config\n                    .fs_permissions\n                    .permissions\n                    .iter()\n                    .any(|p| p.path.to_str().unwrap() == \"./src\")\n            );\n            assert!(\n                config\n                    .fs_permissions\n                    .permissions\n                    .iter()\n                    .any(|p| p.path.to_str().unwrap() == \"./cache\")\n            );\n            assert!(\n                config\n                    .fs_permissions\n                    .permissions\n                    .iter()\n                    .any(|p| p.path.to_str().unwrap() == \"./test\")\n            );\n\n            Ok(())\n        });\n    }\n\n    #[test]\n    fn test_inheritance_with_compilation_settings() {\n        figment::Jail::expect_with(|jail| {\n            jail.create_file(\n                \"base.toml\",\n                r#\"\n                    [profile.default]\n                    solc = \"0.8.19\"\n                    evm_version = \"paris\"\n                    via_ir = false\n                    optimizer = true\n                    optimizer_runs = 200\n\n                    [profile.default.optimizer_details]\n                    peephole = true\n                    inliner = false\n                    jumpdest_remover = true\n                    order_literals = false\n                    deduplicate = true\n                    cse = true\n                    constant_optimizer = true\n                    yul = true\n\n                    [profile.default.optimizer_details.yul_details]\n                    stack_allocation = true\n                    optimizer_steps = \"dhfoDgvulfnTUtnIf\"\n                    \"#,\n            )?;\n\n            jail.create_file(\n                \"foundry.toml\",\n                r#\"\n                    [profile.default]\n                    extends = \"base.toml\"\n                    evm_version = \"shanghai\"  # Override\n                    optimizer_runs = 1000  # Override\n\n                    [profile.default.optimizer_details]\n                    inliner = true  # Override\n                    # Rest inherited\n                    \"#,\n            )?;\n\n            let config = Config::load().unwrap();\n\n            // Check compilation settings\n            assert_eq!(config.solc, Some(SolcReq::Version(Version::new(0, 8, 19))));\n            assert_eq!(config.evm_version, EvmVersion::Shanghai);\n            assert_eq!(config.via_ir, false);\n            assert_eq!(config.optimizer, Some(true));\n            assert_eq!(config.optimizer_runs, Some(1000));\n\n            // Check optimizer details - the table is actually merged\n            let details = config.optimizer_details.as_ref().unwrap();\n            assert_eq!(details.peephole, Some(true));\n            assert_eq!(details.inliner, Some(true));\n            assert_eq!(details.jumpdest_remover, None);\n            assert_eq!(details.order_literals, None);\n            assert_eq!(details.deduplicate, Some(true));\n            assert_eq!(details.cse, Some(true));\n            assert_eq!(details.constant_optimizer, None);\n            assert_eq!(details.yul, Some(true));\n\n            // Check yul details - inherited from base\n            if let Some(yul_details) = details.yul_details.as_ref() {\n                assert_eq!(yul_details.stack_allocation, Some(true));\n                assert_eq!(yul_details.optimizer_steps, Some(\"dhfoDgvulfnTUtnIf\".to_string()));\n            }\n\n            Ok(())\n        });\n    }\n\n    #[test]\n    fn test_inheritance_with_remappings() {\n        figment::Jail::expect_with(|jail| {\n            jail.create_file(\n                \"base.toml\",\n                r#\"\n                    [profile.default]\n                    remappings = [\n                        \"forge-std/=lib/forge-std/src/\",\n                        \"@openzeppelin/=lib/openzeppelin-contracts/\",\n                        \"ds-test/=lib/ds-test/src/\"\n                    ]\n                    auto_detect_remappings = false\n                    \"#,\n            )?;\n\n            jail.create_file(\n                \"foundry.toml\",\n                r#\"\n                    [profile.default]\n                    extends = \"base.toml\"\n                    remappings = [\n                        \"@custom/=lib/custom/\",\n                        \"ds-test/=lib/forge-std/lib/ds-test/src/\"  # Note: This will be added alongside base remappings\n                    ]\n                    \"#,\n            )?;\n\n            let config = Config::load().unwrap();\n\n            // Remappings array is now concatenated with admerge (base + local)\n            assert!(config.remappings.iter().any(|r| r.to_string().contains(\"@custom/\")));\n            assert!(config.remappings.iter().any(|r| r.to_string().contains(\"ds-test/\")));\n            assert!(config.remappings.iter().any(|r| r.to_string().contains(\"forge-std/\")));\n            assert!(config.remappings.iter().any(|r| r.to_string().contains(\"@openzeppelin/\")));\n\n            // auto_detect_remappings should be inherited\n            assert!(!config.auto_detect_remappings);\n\n            Ok(())\n        });\n    }\n\n    #[test]\n    fn test_inheritance_with_multiple_profiles_and_single_file() {\n        figment::Jail::expect_with(|jail| {\n            // Create base config with prod and test profiles\n            jail.create_file(\n                \"base.toml\",\n                r#\"\n                    [profile.prod]\n                    optimizer = true\n                    optimizer_runs = 10000\n                    via_ir = true\n\n                    [profile.test]\n                    optimizer = false\n\n                    [profile.test.fuzz]\n                    runs = 100\n                    \"#,\n            )?;\n\n            // Local config inherits from base for prod profile\n            jail.create_file(\n                \"foundry.toml\",\n                r#\"\n                    [profile.prod]\n                    extends = \"base.toml\"\n                    evm_version = \"shanghai\"  # Additional setting\n\n                    [profile.test]\n                    extends = \"base.toml\"\n\n                    [profile.test.fuzz]\n                    runs = 500  # Override\n                    \"#,\n            )?;\n\n            // Test prod profile\n            jail.set_env(\"FOUNDRY_PROFILE\", \"prod\");\n            let config = Config::load().unwrap();\n            assert_eq!(config.optimizer, Some(true));\n            assert_eq!(config.optimizer_runs, Some(10000));\n            assert_eq!(config.via_ir, true);\n            assert_eq!(config.evm_version, EvmVersion::Shanghai);\n\n            // Test test profile\n            jail.set_env(\"FOUNDRY_PROFILE\", \"test\");\n            let config = Config::load().unwrap();\n            assert_eq!(config.optimizer, Some(false));\n            assert_eq!(config.fuzz.runs, 500);\n\n            Ok(())\n        });\n    }\n\n    #[test]\n    fn test_inheritance_with_multiple_profiles_and_files() {\n        figment::Jail::expect_with(|jail| {\n            jail.create_file(\n                \"prod.toml\",\n                r#\"\n                    [profile.prod]\n                    optimizer = true\n                    optimizer_runs = 20000\n                    gas_limit = 50000000\n                    \"#,\n            )?;\n            jail.create_file(\n                \"dev.toml\",\n                r#\"\n                    [profile.dev]\n                    optimizer = true\n                    optimizer_runs = 333\n                    gas_limit = 555555\n                    \"#,\n            )?;\n\n            // Local config with only both profiles\n            jail.create_file(\n                \"foundry.toml\",\n                r#\"\n                    [profile.dev]\n                    extends = \"dev.toml\"\n                    sender = \"0x0000000000000000000000000000000000000001\"\n\n                    [profile.prod]\n                    extends = \"prod.toml\"\n                    sender = \"0x0000000000000000000000000000000000000002\"\n                    \"#,\n            )?;\n\n            // Test that prod profile correctly inherits even without a default profile\n            jail.set_env(\"FOUNDRY_PROFILE\", \"dev\");\n            let config = Config::load().unwrap();\n            assert_eq!(config.optimizer, Some(true));\n            assert_eq!(config.optimizer_runs, Some(333));\n            assert_eq!(config.gas_limit, 555555.into());\n            assert_eq!(\n                config.sender,\n                \"0x0000000000000000000000000000000000000001\"\n                    .parse::<alloy_primitives::Address>()\n                    .unwrap()\n            );\n\n            // Test that prod profile correctly inherits even without a default profile\n            jail.set_env(\"FOUNDRY_PROFILE\", \"prod\");\n            let config = Config::load().unwrap();\n            assert_eq!(config.optimizer, Some(true));\n            assert_eq!(config.optimizer_runs, Some(20000));\n            assert_eq!(config.gas_limit, 50000000.into());\n            assert_eq!(\n                config.sender,\n                \"0x0000000000000000000000000000000000000002\"\n                    .parse::<alloy_primitives::Address>()\n                    .unwrap()\n            );\n\n            Ok(())\n        });\n    }\n\n    #[test]\n    fn test_extends_strategy_extend_arrays() {\n        figment::Jail::expect_with(|jail| {\n            // Create base config with arrays\n            jail.create_file(\n                \"base.toml\",\n                r#\"\n                    [profile.default]\n                    libs = [\"lib\", \"node_modules\"]\n                    ignored_error_codes = [5667, 1878]\n                    optimizer_runs = 200\n                    \"#,\n            )?;\n\n            // Local config extends with extend-arrays strategy (concatenates arrays)\n            jail.create_file(\n                \"foundry.toml\",\n                r#\"\n                    [profile.default]\n                    extends = \"base.toml\"\n                    libs = [\"mylib\", \"customlib\"]\n                    ignored_error_codes = [1234]\n                    optimizer_runs = 500\n                    \"#,\n            )?;\n\n            let config = Config::load().unwrap();\n\n            // Arrays should be concatenated (base + local)\n            assert_eq!(config.libs.len(), 4);\n            assert!(config.libs.iter().any(|l| l.to_str() == Some(\"lib\")));\n            assert!(config.libs.iter().any(|l| l.to_str() == Some(\"node_modules\")));\n            assert!(config.libs.iter().any(|l| l.to_str() == Some(\"mylib\")));\n            assert!(config.libs.iter().any(|l| l.to_str() == Some(\"customlib\")));\n\n            assert_eq!(config.ignored_error_codes.len(), 3);\n            assert!(\n                config.ignored_error_codes.contains(&SolidityErrorCode::UnusedFunctionParameter)\n            ); // 5667\n            assert!(\n                config.ignored_error_codes.contains(&SolidityErrorCode::SpdxLicenseNotProvided)\n            ); // 1878\n            assert!(config.ignored_error_codes.contains(&SolidityErrorCode::from(1234u64))); // 1234 - generic\n\n            // Non-array values should be replaced\n            assert_eq!(config.optimizer_runs, Some(500));\n\n            Ok(())\n        });\n    }\n\n    #[test]\n    fn test_extends_strategy_replace_arrays() {\n        figment::Jail::expect_with(|jail| {\n            // Create base config with arrays\n            jail.create_file(\n                \"base.toml\",\n                r#\"\n                    [profile.default]\n                    libs = [\"lib\", \"node_modules\"]\n                    ignored_error_codes = [5667, 1878]\n                    optimizer_runs = 200\n                    \"#,\n            )?;\n\n            // Local config extends with replace-arrays strategy (replaces arrays entirely)\n            jail.create_file(\n                \"foundry.toml\",\n                r#\"\n                    [profile.default]\n                    extends = { path = \"base.toml\", strategy = \"replace-arrays\" }\n                    libs = [\"mylib\", \"customlib\"]\n                    ignored_error_codes = [1234]\n                    optimizer_runs = 500\n                    \"#,\n            )?;\n\n            let config = Config::load().unwrap();\n\n            // Arrays should be replaced entirely (only local values)\n            assert_eq!(config.libs.len(), 2);\n            assert!(config.libs.iter().any(|l| l.to_str() == Some(\"mylib\")));\n            assert!(config.libs.iter().any(|l| l.to_str() == Some(\"customlib\")));\n            assert!(!config.libs.iter().any(|l| l.to_str() == Some(\"lib\")));\n            assert!(!config.libs.iter().any(|l| l.to_str() == Some(\"node_modules\")));\n\n            assert_eq!(config.ignored_error_codes.len(), 1);\n            assert!(config.ignored_error_codes.contains(&SolidityErrorCode::from(1234u64))); // 1234\n            assert!(\n                !config.ignored_error_codes.contains(&SolidityErrorCode::UnusedFunctionParameter)\n            ); // 5667\n\n            // Non-array values should be replaced\n            assert_eq!(config.optimizer_runs, Some(500));\n\n            Ok(())\n        });\n    }\n\n    #[test]\n    fn test_extends_strategy_no_collision_success() {\n        figment::Jail::expect_with(|jail| {\n            // Create base config\n            jail.create_file(\n                \"base.toml\",\n                r#\"\n                    [profile.default]\n                    optimizer = true\n                    optimizer_runs = 200\n                    src = \"src\"\n                    \"#,\n            )?;\n\n            // Local config extends with no-collision strategy and no conflicts\n            jail.create_file(\n                \"foundry.toml\",\n                r#\"\n                    [profile.default]\n                    extends = { path = \"base.toml\", strategy = \"no-collision\" }\n                    test = \"tests\"\n                    libs = [\"lib\"]\n                    \"#,\n            )?;\n\n            let config = Config::load().unwrap();\n\n            // Values from base should be present\n            assert_eq!(config.optimizer, Some(true));\n            assert_eq!(config.optimizer_runs, Some(200));\n            assert_eq!(config.src, PathBuf::from(\"src\"));\n\n            // Values from local should be present\n            assert_eq!(config.test, PathBuf::from(\"tests\"));\n            assert_eq!(config.libs.len(), 1);\n            assert!(config.libs.iter().any(|l| l.to_str() == Some(\"lib\")));\n\n            Ok(())\n        });\n    }\n\n    #[test]\n    fn test_extends_strategy_no_collision_error() {\n        figment::Jail::expect_with(|jail| {\n            // Create base config\n            jail.create_file(\n                \"base.toml\",\n                r#\"\n                    [profile.default]\n                    optimizer = true\n                    optimizer_runs = 200\n                    libs = [\"lib\", \"node_modules\"]\n                    \"#,\n            )?;\n\n            // Local config extends with no-collision strategy but has conflicts\n            jail.create_file(\n                \"foundry.toml\",\n                r#\"\n                    [profile.default]\n                    extends = { path = \"base.toml\", strategy = \"no-collision\" }\n                    optimizer_runs = 500\n                    libs = [\"mylib\"]\n                    \"#,\n            )?;\n\n            // Loading should fail due to key collision\n            let result = Config::load();\n\n            if let Ok(config) = result {\n                panic!(\n                    \"Expected error but got config with optimizer_runs: {:?}, libs: {:?}\",\n                    config.optimizer_runs, config.libs\n                );\n            }\n\n            let err = result.unwrap_err();\n            let err_str = err.to_string();\n            assert!(\n                err_str.contains(\"Key collision detected\") || err_str.contains(\"collision\"),\n                \"Error message doesn't mention collision: {err_str}\"\n            );\n\n            Ok(())\n        });\n    }\n\n    #[test]\n    fn test_extends_both_syntaxes() {\n        figment::Jail::expect_with(|jail| {\n            // Create base config\n            jail.create_file(\n                \"base.toml\",\n                r#\"\n                    [profile.default]\n                    libs = [\"lib\"]\n                    optimizer = true\n                    \"#,\n            )?;\n\n            // Test 1: Simple string syntax (should use default extend-arrays)\n            jail.create_file(\n                \"foundry_string.toml\",\n                r#\"\n                    [profile.default]\n                    extends = \"base.toml\"\n                    libs = [\"custom\"]\n                    \"#,\n            )?;\n\n            // Test 2: Object syntax with explicit strategy\n            jail.create_file(\n                \"foundry_object.toml\",\n                r#\"\n                    [profile.default]\n                    extends = { path = \"base.toml\", strategy = \"replace-arrays\" }\n                    libs = [\"custom\"]\n                    \"#,\n            )?;\n\n            // Test string syntax (default extend-arrays)\n            jail.set_env(\"FOUNDRY_CONFIG\", \"foundry_string.toml\");\n            let config = Config::load().unwrap();\n            assert_eq!(config.libs.len(), 2); // Should concatenate\n            assert!(config.libs.iter().any(|l| l.to_str() == Some(\"lib\")));\n            assert!(config.libs.iter().any(|l| l.to_str() == Some(\"custom\")));\n\n            // Test object syntax (replace-arrays)\n            jail.set_env(\"FOUNDRY_CONFIG\", \"foundry_object.toml\");\n            let config = Config::load().unwrap();\n            assert_eq!(config.libs.len(), 1); // Should replace\n            assert!(config.libs.iter().any(|l| l.to_str() == Some(\"custom\")));\n            assert!(!config.libs.iter().any(|l| l.to_str() == Some(\"lib\")));\n\n            Ok(())\n        });\n    }\n\n    #[test]\n    fn test_extends_strategy_default_is_extend_arrays() {\n        figment::Jail::expect_with(|jail| {\n            // Create base config\n            jail.create_file(\n                \"base.toml\",\n                r#\"\n                    [profile.default]\n                    libs = [\"lib\", \"node_modules\"]\n                    optimizer = true\n                    \"#,\n            )?;\n\n            // Local config extends without specifying strategy (should default to extend-arrays)\n            jail.create_file(\n                \"foundry.toml\",\n                r#\"\n                    [profile.default]\n                    extends = \"base.toml\"\n                    libs = [\"custom\"]\n                    optimizer = false\n                    \"#,\n            )?;\n\n            // Should work with default extend-arrays strategy\n            let config = Config::load().unwrap();\n\n            // Arrays should be concatenated by default\n            assert_eq!(config.libs.len(), 3);\n            assert!(config.libs.iter().any(|l| l.to_str() == Some(\"lib\")));\n            assert!(config.libs.iter().any(|l| l.to_str() == Some(\"node_modules\")));\n            assert!(config.libs.iter().any(|l| l.to_str() == Some(\"custom\")));\n\n            // Non-array values should be replaced\n            assert_eq!(config.optimizer, Some(false));\n\n            Ok(())\n        });\n    }\n\n    #[test]\n    fn test_deprecated_deny_warnings_is_handled() {\n        figment::Jail::expect_with(|jail| {\n            jail.create_file(\n                \"foundry.toml\",\n                r#\"\n                [profile.default]\n                deny_warnings = true\n                \"#,\n            )?;\n            let config = Config::load().unwrap();\n\n            // Assert that the deprecated flag is correctly interpreted\n            assert_eq!(config.deny, DenyLevel::Warnings);\n            Ok(())\n        });\n    }\n\n    #[test]\n    fn warns_on_unknown_keys_in_profile() {\n        figment::Jail::expect_with(|jail| {\n            jail.create_file(\n                \"foundry.toml\",\n                r#\"\n                [profile.default]\n                unknown_key_xyz = 123\n                \"#,\n            )?;\n\n            let cfg = Config::load().unwrap();\n            assert!(cfg.warnings.iter().any(\n                |w| matches!(w, crate::Warning::UnknownKey { key, .. } if key == \"unknown_key_xyz\")\n            ));\n            Ok(())\n        });\n    }\n\n    #[test]\n    fn fails_on_ambiguous_version_in_compilation_restrictions() {\n        figment::Jail::expect_with(|jail| {\n            jail.create_file(\n                \"foundry.toml\",\n                r#\"\n                [profile.default]\n                src = \"src\"\n\n                [[profile.default.compilation_restrictions]]\n                paths = \"src/*.sol\"\n                version = \"0.8.11\"\n                \"#,\n            )?;\n\n            let err = Config::load().expect_err(\"expected bare version to fail\");\n            let err_msg = err.to_string();\n            assert!(\n                err_msg.contains(\"Invalid version format '0.8.11'\")\n                    && err_msg.contains(\"Bare version numbers are ambiguous\"),\n                \"Expected error about ambiguous version, got: {err_msg}\"\n            );\n\n            Ok(())\n        });\n    }\n\n    #[test]\n    fn accepts_explicit_version_requirements() {\n        figment::Jail::expect_with(|jail| {\n            jail.create_file(\n                \"foundry.toml\",\n                r#\"\n                [profile.default]\n                src = \"src\"\n\n                [[profile.default.compilation_restrictions]]\n                paths = \"src/*.sol\"\n                version = \"=0.8.11\"\n\n                [[profile.default.compilation_restrictions]]\n                paths = \"test/*.sol\"\n                version = \">=0.8.11\"\n                \"#,\n            )?;\n\n            let config = Config::load().expect(\"should accept explicit version requirements\");\n            assert_eq!(config.compilation_restrictions.len(), 2);\n\n            Ok(())\n        });\n    }\n\n    #[test]\n    fn warns_on_unknown_keys_in_all_config_sections() {\n        figment::Jail::expect_with(|jail| {\n            jail.create_file(\n                \"foundry.toml\",\n                r#\"\n                [profile.default]\n                src = \"src\"\n                unknown_profile_key = \"should_warn\"\n\n                # Standalone sections with unknown keys\n                [fmt]\n                line_length = 120\n                unknown_fmt_key = \"should_warn\"\n\n                [lint]\n                severity = [\"high\"]\n                unknown_lint_key = \"should_warn\"\n\n                [doc]\n                out = \"docs\"\n                unknown_doc_key = \"should_warn\"\n\n                [fuzz]\n                runs = 256\n                unknown_fuzz_key = \"should_warn\"\n\n                [invariant]\n                runs = 256\n                unknown_invariant_key = \"should_warn\"\n\n                [vyper]\n                unknown_vyper_key = \"should_warn\"\n\n                [bind_json]\n                out = \"bindings.sol\"\n                unknown_bind_json_key = \"should_warn\"\n\n                # Nested profile sections with unknown keys\n                [profile.default.fmt]\n                line_length = 100\n                unknown_nested_fmt_key = \"should_warn\"\n\n                [profile.default.lint]\n                severity = [\"low\"]\n                unknown_nested_lint_key = \"should_warn\"\n\n                [profile.default.doc]\n                out = \"documentation\"\n                unknown_nested_doc_key = \"should_warn\"\n\n                [profile.default.fuzz]\n                runs = 512\n                unknown_nested_fuzz_key = \"should_warn\"\n\n                [profile.default.invariant]\n                runs = 512\n                unknown_nested_invariant_key = \"should_warn\"\n\n                [profile.default.vyper]\n                unknown_nested_vyper_key = \"should_warn\"\n\n                [profile.default.bind_json]\n                out = \"nested_bindings.sol\"\n                unknown_nested_bind_json_key = \"should_warn\"\n\n                # Array sections with unknown keys\n                [[profile.default.compilation_restrictions]]\n                paths = \"src/*.sol\"\n                unknown_compilation_key = \"should_warn\"\n\n                [[profile.default.additional_compiler_profiles]]\n                name = \"via-ir\"\n                via_ir = true\n                unknown_compiler_profile_key = \"should_warn\"\n                \"#,\n            )?;\n\n            let cfg = Config::load().unwrap();\n\n            // Expected warnings for profile-level unknown key\n            assert!(\n                cfg.warnings.iter().any(|w| matches!(\n                    w,\n                    crate::Warning::UnknownKey { key, .. } if key == \"unknown_profile_key\"\n                )),\n                \"Expected warning for 'unknown_profile_key' in profile, got: {:?}\",\n                cfg.warnings\n            );\n\n            // Expected warnings for standalone sections\n            let standalone_expected = [\n                (\"unknown_fmt_key\", \"fmt\"),\n                (\"unknown_lint_key\", \"lint\"),\n                (\"unknown_doc_key\", \"doc\"),\n                (\"unknown_fuzz_key\", \"fuzz\"),\n                (\"unknown_invariant_key\", \"invariant\"),\n                (\"unknown_vyper_key\", \"vyper\"),\n                (\"unknown_bind_json_key\", \"bind_json\"),\n            ];\n\n            for (expected_key, expected_section) in standalone_expected {\n                assert!(\n                    cfg.warnings.iter().any(|w| matches!(\n                        w,\n                        crate::Warning::UnknownSectionKey { key, section, .. }\n                        if key == expected_key && section == expected_section\n                    )),\n                    \"Expected warning for '{}' in standalone section '{}', got: {:?}\",\n                    expected_key,\n                    expected_section,\n                    cfg.warnings\n                );\n            }\n\n            // Expected warnings for nested profile sections\n            let nested_expected = [\n                (\"unknown_nested_fmt_key\", \"fmt\"),\n                (\"unknown_nested_lint_key\", \"lint\"),\n                (\"unknown_nested_doc_key\", \"doc\"),\n                (\"unknown_nested_fuzz_key\", \"fuzz\"),\n                (\"unknown_nested_invariant_key\", \"invariant\"),\n                (\"unknown_nested_vyper_key\", \"vyper\"),\n                (\"unknown_nested_bind_json_key\", \"bind_json\"),\n            ];\n\n            for (expected_key, expected_section) in nested_expected {\n                assert!(\n                    cfg.warnings.iter().any(|w| matches!(\n                        w,\n                        crate::Warning::UnknownSectionKey { key, section, .. }\n                        if key == expected_key && section == expected_section\n                    )),\n                    \"Expected warning for '{}' in nested section '{}', got: {:?}\",\n                    expected_key,\n                    expected_section,\n                    cfg.warnings\n                );\n            }\n\n            // Expected warnings for array item sections\n            let array_expected = [\n                (\"unknown_compilation_key\", \"compilation_restrictions\"),\n                (\"unknown_compiler_profile_key\", \"additional_compiler_profiles\"),\n            ];\n\n            for (expected_key, expected_section) in array_expected {\n                assert!(\n                    cfg.warnings.iter().any(|w| matches!(\n                        w,\n                        crate::Warning::UnknownSectionKey { key, section, .. }\n                        if key == expected_key && section == expected_section\n                    )),\n                    \"Expected warning for '{}' in array section '{}', got: {:?}\",\n                    expected_key,\n                    expected_section,\n                    cfg.warnings\n                );\n            }\n\n            // Verify total count of unknown key warnings\n            let unknown_key_warnings: Vec<_> = cfg\n                .warnings\n                .iter()\n                .filter(|w| {\n                    matches!(w, crate::Warning::UnknownKey { .. })\n                        || matches!(w, crate::Warning::UnknownSectionKey { .. })\n                })\n                .collect();\n\n            // 1 profile key + 7 standalone + 7 nested + 2 array = 17 total\n            assert_eq!(\n                unknown_key_warnings.len(),\n                17,\n                \"Expected 17 unknown key warnings (1 profile + 7 standalone + 7 nested + 2 array), got {}: {:?}\",\n                unknown_key_warnings.len(),\n                unknown_key_warnings\n            );\n\n            Ok(())\n        });\n    }\n\n    #[test]\n    fn warns_on_unknown_keys_in_extended_config() {\n        figment::Jail::expect_with(|jail| {\n            // Create base config with unknown keys\n            jail.create_file(\n                \"base.toml\",\n                r#\"\n                [profile.default]\n                optimizer_runs = 800\n                unknown_base_profile_key = \"should_warn\"\n\n                [lint]\n                severity = [\"high\"]\n                unknown_base_lint_key = \"should_warn\"\n\n                [fmt]\n                line_length = 100\n                unknown_base_fmt_key = \"should_warn\"\n                \"#,\n            )?;\n\n            // Create local config that extends base with its own unknown keys\n            jail.create_file(\n                \"foundry.toml\",\n                r#\"\n                [profile.default]\n                extends = \"base.toml\"\n                src = \"src\"\n                unknown_local_profile_key = \"should_warn\"\n\n                [lint]\n                unknown_local_lint_key = \"should_warn\"\n\n                [fuzz]\n                runs = 512\n                unknown_local_fuzz_key = \"should_warn\"\n\n                [[profile.default.compilation_restrictions]]\n                paths = \"src/*.sol\"\n                unknown_local_restriction_key = \"should_warn\"\n                \"#,\n            )?;\n\n            let cfg = Config::load().unwrap();\n\n            // Verify base config values are inherited\n            assert_eq!(cfg.optimizer_runs, Some(800));\n\n            // Unknown keys from both base and local configs should be detected.\n            // Note: Due to how figment merges configs before validation, the source\n            // will show the local config file for all warnings. This is a known\n            // limitation - proper source attribution for extended configs would\n            // require validating each file before the merge.\n\n            // Verify all expected unknown keys are detected\n            let expected_unknown_keys = [\"unknown_base_profile_key\", \"unknown_local_profile_key\"];\n            for expected_key in expected_unknown_keys {\n                assert!(\n                    cfg.warnings.iter().any(|w| matches!(\n                        w,\n                        crate::Warning::UnknownKey { key, .. } if key == expected_key\n                    )),\n                    \"Expected warning for '{}', got: {:?}\",\n                    expected_key,\n                    cfg.warnings\n                );\n            }\n\n            let expected_section_keys = [\n                (\"unknown_base_lint_key\", \"lint\"),\n                (\"unknown_base_fmt_key\", \"fmt\"),\n                (\"unknown_local_lint_key\", \"lint\"),\n                (\"unknown_local_fuzz_key\", \"fuzz\"),\n                (\"unknown_local_restriction_key\", \"compilation_restrictions\"),\n            ];\n            for (expected_key, expected_section) in expected_section_keys {\n                assert!(\n                    cfg.warnings.iter().any(|w| matches!(\n                        w,\n                        crate::Warning::UnknownSectionKey { key, section, .. }\n                        if key == expected_key && section == expected_section\n                    )),\n                    \"Expected warning for '{}' in section '{}', got: {:?}\",\n                    expected_key,\n                    expected_section,\n                    cfg.warnings\n                );\n            }\n\n            // Verify total: 2 profile keys + 5 section keys = 7 warnings\n            let unknown_warnings: Vec<_> = cfg\n                .warnings\n                .iter()\n                .filter(|w| {\n                    matches!(w, crate::Warning::UnknownKey { .. })\n                        || matches!(w, crate::Warning::UnknownSectionKey { .. })\n                })\n                .collect();\n            assert_eq!(\n                unknown_warnings.len(),\n                7,\n                \"Expected 7 unknown key warnings, got {}: {:?}\",\n                unknown_warnings.len(),\n                unknown_warnings\n            );\n\n            Ok(())\n        });\n    }\n\n    // Test for issue #12844: FOUNDRY_PROFILE=nonexistent should fail\n    #[test]\n    fn fails_on_unknown_profile() {\n        figment::Jail::expect_with(|jail| {\n            jail.create_file(\n                \"foundry.toml\",\n                r#\"\n                [profile.default]\n                src = \"src\"\n                \"#,\n            )?;\n\n            jail.set_env(\"FOUNDRY_PROFILE\", \"nonexistent\");\n            let err = Config::load().expect_err(\"expected unknown profile to fail\");\n            let err_msg = err.to_string();\n            assert!(\n                err_msg.contains(\"selected profile `nonexistent` does not exist\"),\n                \"Expected error about nonexistent profile, got: {err_msg}\"\n            );\n\n            Ok(())\n        });\n    }\n\n    // Test for issue #13316: vyper config keys should not trigger unknown key warnings\n    #[test]\n    fn no_false_warnings_for_vyper_config_keys() {\n        figment::Jail::expect_with(|jail| {\n            jail.create_file(\n                \"foundry.toml\",\n                r#\"\n                [profile.default]\n                src = \"src\"\n\n                [vyper]\n                optimize = \"gas\"\n                path = \"/usr/bin/vyper\"\n                experimental_codegen = true\n                \"#,\n            )?;\n\n            let cfg = Config::load().unwrap();\n            // None of the valid vyper keys should trigger warnings\n            let vyper_warnings: Vec<_> = cfg\n                .warnings\n                .iter()\n                .filter(|w| {\n                    matches!(\n                        w,\n                        crate::Warning::UnknownSectionKey { section, .. } if section == \"vyper\"\n                    )\n                })\n                .collect();\n\n            assert!(\n                vyper_warnings.is_empty(),\n                \"Valid vyper keys should not trigger warnings, got: {vyper_warnings:?}\"\n            );\n\n            Ok(())\n        });\n    }\n\n    // Test for issue #13316: vyper config in profile should not trigger false warnings\n    #[test]\n    fn no_false_warnings_for_nested_vyper_config_keys() {\n        figment::Jail::expect_with(|jail| {\n            jail.create_file(\n                \"foundry.toml\",\n                r#\"\n                [profile.default]\n                src = \"src\"\n\n                [profile.default.vyper]\n                optimize = \"codesize\"\n                path = \"/opt/vyper/bin/vyper\"\n                experimental_codegen = false\n                \"#,\n            )?;\n\n            let cfg = Config::load().unwrap();\n            // None of the valid vyper keys should trigger warnings\n            let vyper_warnings: Vec<_> = cfg\n                .warnings\n                .iter()\n                .filter(|w| {\n                    matches!(\n                        w,\n                        crate::Warning::UnknownSectionKey { section, .. } if section == \"vyper\"\n                    )\n                })\n                .collect();\n\n            assert!(\n                vyper_warnings.is_empty(),\n                \"Valid nested vyper keys should not trigger warnings, got: {vyper_warnings:?}\"\n            );\n\n            Ok(())\n        });\n    }\n\n    // Test for issue #13316: inline vyper config format should not trigger false warnings\n    // This matches the exact format used in https://github.com/pcaversaccio/snekmate\n    #[test]\n    fn no_false_warnings_for_inline_vyper_config() {\n        figment::Jail::expect_with(|jail| {\n            jail.create_file(\n                \"foundry.toml\",\n                r#\"\n                [profile.default]\n                src = \"src\"\n                vyper = { optimize = \"gas\" }\n\n                [profile.default-venom]\n                vyper = { experimental_codegen = true }\n\n                [profile.ci-venom]\n                vyper = { experimental_codegen = true }\n                \"#,\n            )?;\n\n            let cfg = Config::load().unwrap();\n            let vyper_warnings: Vec<_> = cfg\n                .warnings\n                .iter()\n                .filter(|w| {\n                    matches!(\n                        w,\n                        crate::Warning::UnknownSectionKey { section, .. } if section == \"vyper\"\n                    )\n                })\n                .collect();\n\n            assert!(\n                vyper_warnings.is_empty(),\n                \"Valid inline vyper config should not trigger warnings, got: {vyper_warnings:?}\"\n            );\n\n            Ok(())\n        });\n    }\n\n    // Test for issue #13316: unknown vyper keys should still warn\n    #[test]\n    fn warns_on_unknown_vyper_keys() {\n        figment::Jail::expect_with(|jail| {\n            jail.create_file(\n                \"foundry.toml\",\n                r#\"\n                [profile.default]\n                src = \"src\"\n\n                [vyper]\n                optimize = \"gas\"\n                unknown_vyper_option = true\n                \"#,\n            )?;\n\n            let cfg = Config::load().unwrap();\n            assert!(\n                cfg.warnings.iter().any(|w| matches!(\n                    w,\n                    crate::Warning::UnknownSectionKey { key, section, .. }\n                    if key == \"unknown_vyper_option\" && section == \"vyper\"\n                )),\n                \"Unknown vyper key should trigger warning, got: {:?}\",\n                cfg.warnings\n            );\n\n            Ok(())\n        });\n    }\n\n    // Test for issue #12844: known profile should work\n    #[test]\n    fn succeeds_on_known_profile() {\n        figment::Jail::expect_with(|jail| {\n            jail.create_file(\n                \"foundry.toml\",\n                r#\"\n                [profile.default]\n                src = \"src\"\n\n                [profile.ci]\n                src = \"src\"\n                fuzz = { runs = 10000 }\n                \"#,\n            )?;\n\n            jail.set_env(\"FOUNDRY_PROFILE\", \"ci\");\n            let config = Config::load().expect(\"known profile should work\");\n            assert_eq!(config.profile.as_str(), \"ci\");\n            assert_eq!(config.fuzz.runs, 10000);\n\n            Ok(())\n        });\n    }\n\n    // Test for issue #12963: nested lib configs should fallback to default profile\n    // when they don't define the requested profile\n    #[test]\n    fn nested_lib_config_falls_back_to_default_profile() {\n        figment::Jail::expect_with(|jail| {\n            // Create a lib directory with only default profile\n            let lib_path = jail.directory().join(\"lib/mylib\");\n            std::fs::create_dir_all(&lib_path).unwrap();\n            jail.create_file(\n                \"lib/mylib/foundry.toml\",\n                r#\"\n                [profile.default]\n                src = \"contracts\"\n                \"#,\n            )?;\n\n            // Set a profile that doesn't exist in the lib\n            jail.set_env(\"FOUNDRY_PROFILE\", \"ci\");\n\n            // load_with_root_and_fallback should succeed and fall back to default\n            let config = Config::load_with_root_and_fallback(&lib_path)\n                .expect(\"lib config should load with fallback\");\n            assert_eq!(config.profile, Config::DEFAULT_PROFILE);\n            assert_eq!(config.src.as_os_str(), \"contracts\");\n\n            Ok(())\n        });\n    }\n\n    // Test for issue #12963: nested lib configs should use requested profile if it exists\n    #[test]\n    fn nested_lib_config_uses_profile_if_exists() {\n        figment::Jail::expect_with(|jail| {\n            // Create a lib directory with both default and ci profiles\n            let lib_path = jail.directory().join(\"lib/mylib\");\n            std::fs::create_dir_all(&lib_path).unwrap();\n            jail.create_file(\n                \"lib/mylib/foundry.toml\",\n                r#\"\n                [profile.default]\n                src = \"contracts\"\n\n                [profile.ci]\n                src = \"contracts\"\n                fuzz = { runs = 5000 }\n                \"#,\n            )?;\n\n            // Set a profile that exists in the lib\n            jail.set_env(\"FOUNDRY_PROFILE\", \"ci\");\n\n            // load_with_root_and_fallback should use the ci profile\n            let config = Config::load_with_root_and_fallback(&lib_path)\n                .expect(\"lib config should load with profile\");\n            assert_eq!(config.profile.as_str(), \"ci\");\n            assert_eq!(config.fuzz.runs, 5000);\n\n            Ok(())\n        });\n    }\n\n    // Test for issue #13170: profile names with hyphens should work correctly\n    #[test]\n    fn succeeds_on_hyphenated_profile_name() {\n        figment::Jail::expect_with(|jail| {\n            jail.create_file(\n                \"foundry.toml\",\n                r#\"\n                [profile.default]\n                src = \"src\"\n\n                [profile.ci-venom]\n                src = \"src\"\n                fuzz = { runs = 7500 }\n\n                [profile.default-venom]\n                src = \"src\"\n                fuzz = { runs = 8000 }\n                \"#,\n            )?;\n\n            // Test ci-venom profile\n            jail.set_env(\"FOUNDRY_PROFILE\", \"ci-venom\");\n            let config = Config::load().expect(\"hyphenated profile should work\");\n            assert_eq!(config.profile.as_str(), \"ci-venom\");\n            assert_eq!(config.fuzz.runs, 7500);\n\n            // Test default-venom profile\n            jail.set_env(\"FOUNDRY_PROFILE\", \"default-venom\");\n            let config = Config::load().expect(\"hyphenated profile should work\");\n            assert_eq!(config.profile.as_str(), \"default-venom\");\n            assert_eq!(config.fuzz.runs, 8000);\n\n            // Verify the profiles list contains hyphenated names\n            assert!(\n                config.profiles.iter().any(|p| p.as_str() == \"ci-venom\"),\n                \"profiles should contain 'ci-venom', got: {:?}\",\n                config.profiles\n            );\n            assert!(\n                config.profiles.iter().any(|p| p.as_str() == \"default-venom\"),\n                \"profiles should contain 'default-venom', got: {:?}\",\n                config.profiles\n            );\n\n            Ok(())\n        });\n    }\n\n    // Test for issue #13170: hyphenated profile with nested config keys\n    #[test]\n    fn hyphenated_profile_with_nested_sections() {\n        figment::Jail::expect_with(|jail| {\n            jail.create_file(\n                \"foundry.toml\",\n                r#\"\n                [profile.default]\n                src = \"src\"\n\n                [profile.ci-venom]\n                src = \"src\"\n                optimizer_runs = 500\n\n                [profile.ci-venom.fuzz]\n                runs = 10000\n                max_test_rejects = 350000\n\n                [profile.ci-venom.invariant]\n                runs = 375\n                depth = 500\n                \"#,\n            )?;\n\n            jail.set_env(\"FOUNDRY_PROFILE\", \"ci-venom\");\n            let config =\n                Config::load().expect(\"hyphenated profile with nested sections should work\");\n            assert_eq!(config.profile.as_str(), \"ci-venom\");\n            assert_eq!(config.optimizer_runs, Some(500));\n            assert_eq!(config.fuzz.runs, 10000);\n            assert_eq!(config.fuzz.max_test_rejects, 350000);\n            assert_eq!(config.invariant.runs, 375);\n            assert_eq!(config.invariant.depth, 500);\n\n            Ok(())\n        });\n    }\n}\n"
  },
  {
    "path": "crates/config/src/lint.rs",
    "content": "//! Configuration specific to the `forge lint` command and the `forge_lint` package\n\nuse clap::ValueEnum;\nuse core::fmt;\nuse serde::{Deserialize, Deserializer, Serialize};\nuse solar::{\n    ast::{self as ast},\n    interface::diagnostics::Level,\n};\nuse std::str::FromStr;\nuse yansi::Paint;\n\n/// Contains the config and rule set.\n#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]\npub struct LinterConfig {\n    /// Specifies which lints to run based on severity.\n    ///\n    /// If uninformed, all severities are checked.\n    pub severity: Vec<Severity>,\n\n    /// Deny specific lints based on their ID (e.g. \"mixed-case-function\").\n    pub exclude_lints: Vec<String>,\n\n    /// Globs to ignore.\n    pub ignore: Vec<String>,\n\n    /// Whether to run linting during `forge build`.\n    ///\n    /// Defaults to true. Set to false to disable automatic linting during builds.\n    pub lint_on_build: bool,\n\n    /// Configuration specific to individual lints.\n    pub lint_specific: LintSpecificConfig,\n}\n\nimpl Default for LinterConfig {\n    fn default() -> Self {\n        Self {\n            lint_on_build: true,\n            severity: vec![Severity::High, Severity::Med, Severity::Low],\n            exclude_lints: Vec::new(),\n            ignore: Vec::new(),\n            lint_specific: LintSpecificConfig::default(),\n        }\n    }\n}\n\n/// Contract types that can be exempted from the multi-contract-file lint.\n#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]\n#[serde(rename_all = \"snake_case\")]\npub enum ContractException {\n    Interface,\n    Library,\n    AbstractContract,\n}\n\n/// Configuration specific to individual lints.\n#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]\n#[serde(default)]\npub struct LintSpecificConfig {\n    /// Configurable patterns that should be excluded when performing `mixedCase` lint checks.\n    ///\n    /// Defaults to [\"ERC\", \"URI\"] to allow common names like `rescueERC20`, `ERC721TokenReceiver`\n    /// or `tokenURI`.\n    pub mixed_case_exceptions: Vec<String>,\n\n    /// Contract types that are allowed to appear multiple times in the same file.\n    ///\n    /// Valid values: \"interface\", \"library\", \"abstract_contract\"\n    ///\n    /// Defaults to an empty array (all contract types are flagged when multiple exist).\n    /// Note: Regular contracts cannot be exempted and will always be flagged when multiple exist.\n    pub multi_contract_file_exceptions: Vec<ContractException>,\n}\n\nimpl Default for LintSpecificConfig {\n    fn default() -> Self {\n        Self {\n            mixed_case_exceptions: vec![\n                \"ERC\".to_string(),\n                \"URI\".to_string(),\n                \"ID\".to_string(),\n                \"URL\".to_string(),\n                \"API\".to_string(),\n                \"JSON\".to_string(),\n                \"XML\".to_string(),\n                \"HTML\".to_string(),\n                \"HTTP\".to_string(),\n                \"HTTPS\".to_string(),\n            ],\n            multi_contract_file_exceptions: Vec::new(),\n        }\n    }\n}\n\nimpl LintSpecificConfig {\n    /// Checks if a given contract kind is included in the list of exceptions\n    pub fn is_exempted(&self, contract_kind: &ast::ContractKind) -> bool {\n        let exception_to_check = match contract_kind {\n            ast::ContractKind::Interface => ContractException::Interface,\n            ast::ContractKind::Library => ContractException::Library,\n            ast::ContractKind::AbstractContract => ContractException::AbstractContract,\n            // Regular contracts are always linted\n            ast::ContractKind::Contract => return false,\n        };\n\n        self.multi_contract_file_exceptions.contains(&exception_to_check)\n    }\n}\n\n/// Severity of a lint.\n#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]\npub enum Severity {\n    High,\n    Med,\n    Low,\n    Info,\n    Gas,\n    CodeSize,\n}\n\nimpl Severity {\n    fn to_str(self) -> &'static str {\n        match self {\n            Self::High => \"High\",\n            Self::Med => \"Med\",\n            Self::Low => \"Low\",\n            Self::Info => \"Info\",\n            Self::Gas => \"Gas\",\n            Self::CodeSize => \"CodeSize\",\n        }\n    }\n\n    fn to_str_kebab(self) -> &'static str {\n        match self {\n            Self::High => \"high\",\n            Self::Med => \"medium\",\n            Self::Low => \"low\",\n            Self::Info => \"info\",\n            Self::Gas => \"gas\",\n            Self::CodeSize => \"code-size\",\n        }\n    }\n\n    pub fn color(&self, message: &str) -> String {\n        match self {\n            Self::High => Paint::red(message).bold().to_string(),\n            Self::Med => Paint::rgb(message, 255, 135, 61).bold().to_string(),\n            Self::Low => Paint::yellow(message).bold().to_string(),\n            Self::Info => Paint::cyan(message).bold().to_string(),\n            Self::Gas => Paint::green(message).bold().to_string(),\n            Self::CodeSize => Paint::green(message).bold().to_string(),\n        }\n    }\n}\n\nimpl From<Severity> for Level {\n    fn from(severity: Severity) -> Self {\n        match severity {\n            Severity::High | Severity::Med | Severity::Low => Self::Warning,\n            Severity::Info | Severity::Gas | Severity::CodeSize => Self::Note,\n        }\n    }\n}\n\nimpl fmt::Display for Severity {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        write!(f, \"{}\", self.color(self.to_str()))\n    }\n}\n\nimpl Serialize for Severity {\n    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>\n    where\n        S: serde::Serializer,\n    {\n        self.to_str_kebab().serialize(serializer)\n    }\n}\n\n// Custom deserialization to make `Severity` parsing case-insensitive\nimpl<'de> Deserialize<'de> for Severity {\n    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>\n    where\n        D: Deserializer<'de>,\n    {\n        let s = String::deserialize(deserializer)?;\n        FromStr::from_str(&s).map_err(serde::de::Error::custom)\n    }\n}\n\nimpl FromStr for Severity {\n    type Err = String;\n\n    fn from_str(s: &str) -> Result<Self, Self::Err> {\n        match s.to_lowercase().as_str() {\n            \"high\" => Ok(Self::High),\n            \"med\" | \"medium\" => Ok(Self::Med),\n            \"low\" => Ok(Self::Low),\n            \"info\" => Ok(Self::Info),\n            \"gas\" => Ok(Self::Gas),\n            \"size\" | \"codesize\" | \"code-size\" => Ok(Self::CodeSize),\n            _ => Err(format!(\n                \"unknown variant: found `{s}`, expected `one of `High`, `Med`, `Low`, `Info`, `Gas`, `CodeSize`\"\n            )),\n        }\n    }\n}\n"
  },
  {
    "path": "crates/config/src/macros.rs",
    "content": "/// A macro to implement converters from a type to [`Config`](crate::Config) and\n/// [`figment::Figment`].\n///\n/// This can be used to remove some boilerplate code that's necessary to add additional layer(s) to\n/// the `Config`'s default `Figment`.\n///\n/// `impl_figment` takes the default `Config` and merges additional `Provider`, therefore the\n/// targeted type, requires an implementation of `figment::Profile`.\n///\n/// # Example\n///\n/// Use `impl_figment` on a type with a `root: Option<PathBuf>` field, which will be used for\n/// [`Config::figment_with_root()`](crate::Config::figment_with_root).\n///\n/// ```rust\n/// use std::path::PathBuf;\n/// use serde::Serialize;\n/// use foundry_config::{Config, impl_figment_convert};\n/// use foundry_config::figment::*;\n/// use foundry_config::figment::error::Kind::InvalidType;\n/// use foundry_config::figment::value::*;\n/// #[derive(Default, Serialize)]\n/// struct MyArgs {\n///     #[serde(skip_serializing_if = \"Option::is_none\")]\n///     root: Option<PathBuf>,\n/// }\n/// impl_figment_convert!(MyArgs);\n///\n/// impl Provider for MyArgs {\n///     fn metadata(&self) -> Metadata {\n///         Metadata::default()\n///     }\n///\n///     fn data(&self) -> std::result::Result<Map<Profile, Dict>, Error> {\n///         let value = Value::serialize(self)?;\n///         let error = InvalidType(value.to_actual(), \"map\".into());\n///         let mut dict = value.into_dict().ok_or(error)?;\n///         Ok(Map::from([(Config::selected_profile(), dict)]))\n///     }\n/// }\n///\n/// let figment: Figment = From::from(&MyArgs::default());\n///\n///  // Use `impl_figment` on a type that has several nested `Provider` as fields but is _not_ a `Provider` itself\n///\n/// #[derive(Default)]\n/// struct Outer {\n///     start: MyArgs,\n///     second: MyArgs,\n///     third: MyArgs,\n/// }\n/// impl_figment_convert!(Outer, start, second, third);\n///\n/// let figment: Figment = From::from(&Outer::default());\n/// ```\n#[macro_export]\nmacro_rules! impl_figment_convert {\n    ($name:ty) => {\n        impl<'a> From<&'a $name> for $crate::figment::Figment {\n            fn from(args: &'a $name) -> Self {\n                $crate::Config::figment_with_root_opt(args.root.as_deref()).merge(args)\n            }\n        }\n    };\n    ($name:ty, $start:ident $(, $more:ident)*) => {\n        impl<'a> From<&'a $name> for $crate::figment::Figment {\n            fn from(args: &'a $name) -> Self {\n                let mut figment: $crate::figment::Figment = From::from(&args.$start);\n                $(\n                    figment = figment.merge(&args.$more);\n                )*\n                figment\n            }\n        }\n    };\n    ($name:ty, self, $start:ident $(, $more:ident)*) => {\n        impl<'a> From<&'a $name> for $crate::figment::Figment {\n            fn from(args: &'a $name) -> Self {\n                let mut figment: $crate::figment::Figment = From::from(&args.$start);\n                $(\n                    figment = figment.merge(&args.$more);\n                )*\n                figment = figment.merge(args);\n                figment\n            }\n        }\n    };\n}\n\n/// Same as `impl_figment_convert` but also merges the type itself into the figment\n///\n/// # Example\n///\n/// Merge several nested `Provider` together with the type itself\n///\n/// ```rust\n/// use foundry_config::{\n///     Config,\n///     figment::{value::*, *},\n///     impl_figment_convert, merge_impl_figment_convert,\n/// };\n/// use std::path::PathBuf;\n///\n/// #[derive(Default)]\n/// struct MyArgs {\n///     root: Option<PathBuf>,\n/// }\n///\n/// impl Provider for MyArgs {\n///     fn metadata(&self) -> Metadata {\n///         Metadata::default()\n///     }\n///\n///     fn data(&self) -> std::result::Result<Map<Profile, Dict>, Error> {\n///         todo!()\n///     }\n/// }\n///\n/// impl_figment_convert!(MyArgs);\n///\n/// #[derive(Default)]\n/// struct OuterArgs {\n///     value: u64,\n///     inner: MyArgs,\n/// }\n///\n/// impl Provider for OuterArgs {\n///     fn metadata(&self) -> Metadata {\n///         Metadata::default()\n///     }\n///\n///     fn data(&self) -> std::result::Result<Map<Profile, Dict>, Error> {\n///         todo!()\n///     }\n/// }\n///\n/// merge_impl_figment_convert!(OuterArgs, inner);\n/// ```\n#[macro_export]\nmacro_rules! merge_impl_figment_convert {\n    ($name:ty, $start:ident $(, $more:ident)*) => {\n        impl<'a> From<&'a $name> for $crate::figment::Figment {\n            fn from(args: &'a $name) -> Self {\n                let mut figment: $crate::figment::Figment = From::from(&args.$start);\n                $ (\n                  figment =  figment.merge(&args.$more);\n                )*\n                figment = figment.merge(args);\n                figment\n            }\n        }\n    };\n}\n\n/// A macro to implement converters from a type to [`Config`](crate::Config) and\n/// [`figment::Figment`].\n///\n/// Via [Config::to_figment](crate::Config::to_figment) and the\n/// [Cast](crate::FigmentProviders::Cast) profile.\n#[macro_export]\nmacro_rules! impl_figment_convert_cast {\n    ($name:ty) => {\n        impl<'a> From<&'a $name> for $crate::figment::Figment {\n            fn from(args: &'a $name) -> Self {\n                let root =\n                    $crate::find_project_root(None).expect(\"could not determine project root\");\n                $crate::Config::with_root(&root)\n                    .to_figment($crate::FigmentProviders::Cast)\n                    .merge(args)\n            }\n        }\n    };\n}\n\n/// Same as `impl_figment_convert` but also implies `Provider` for the given `Serialize` type for\n/// convenience. The `Provider` only provides the \"root\" value for the current profile\n#[macro_export]\nmacro_rules! impl_figment_convert_basic {\n    ($name:ty) => {\n        $crate::impl_figment_convert!($name);\n\n        impl $crate::figment::Provider for $name {\n            fn metadata(&self) -> $crate::figment::Metadata {\n                $crate::figment::Metadata::named(stringify!($name))\n            }\n\n            fn data(\n                &self,\n            ) -> Result<\n                $crate::figment::value::Map<$crate::figment::Profile, $crate::figment::value::Dict>,\n                $crate::figment::Error,\n            > {\n                let mut dict = $crate::figment::value::Dict::new();\n                if let Some(root) = self.root.as_ref() {\n                    dict.insert(\n                        \"root\".to_string(),\n                        $crate::figment::value::Value::serialize(root)?,\n                    );\n                }\n                Ok($crate::figment::value::Map::from([($crate::Config::selected_profile(), dict)]))\n            }\n        }\n    };\n}\n"
  },
  {
    "path": "crates/config/src/providers/ext.rs",
    "content": "use crate::{Config, extend, utils};\nuse figment::{\n    Error, Figment, Metadata, Profile, Provider,\n    providers::{Env, Format, Toml},\n    value::{Dict, Map, Value},\n};\nuse foundry_compilers::ProjectPathsConfig;\nuse heck::ToSnakeCase;\nuse std::{\n    cell::OnceCell,\n    path::{Path, PathBuf},\n};\n\npub(crate) trait ProviderExt: Provider + Sized {\n    fn rename(\n        self,\n        from: impl Into<Profile>,\n        to: impl Into<Profile>,\n    ) -> RenameProfileProvider<Self> {\n        RenameProfileProvider::new(self, from, to)\n    }\n\n    fn wrap(\n        self,\n        wrapping_key: impl Into<Profile>,\n        profile: impl Into<Profile>,\n    ) -> WrapProfileProvider<Self> {\n        WrapProfileProvider::new(self, wrapping_key, profile)\n    }\n\n    fn strict_select(\n        self,\n        profiles: impl IntoIterator<Item = impl Into<Profile>>,\n    ) -> OptionalStrictProfileProvider<Self> {\n        OptionalStrictProfileProvider::new(self, profiles)\n    }\n\n    fn fallback(\n        self,\n        profile: impl Into<Profile>,\n        fallback: impl Into<Profile>,\n    ) -> FallbackProfileProvider<Self> {\n        FallbackProfileProvider::new(self, profile, fallback)\n    }\n}\n\nimpl<P: Provider> ProviderExt for P {}\n\n/// A convenience provider to retrieve a toml file.\n/// This will return an error if the env var is set but the file does not exist\npub(crate) struct TomlFileProvider {\n    env_var: Option<&'static str>,\n    env_val: OnceCell<Option<String>>,\n    default: PathBuf,\n    cache: OnceCell<Result<Map<Profile, Dict>, Error>>,\n}\n\nimpl TomlFileProvider {\n    pub(crate) fn new(env_var: Option<&'static str>, default: PathBuf) -> Self {\n        Self { env_var, env_val: OnceCell::new(), default, cache: OnceCell::new() }\n    }\n\n    fn env_val(&self) -> Option<&str> {\n        self.env_val.get_or_init(|| self.env_var.and_then(Env::var)).as_deref()\n    }\n\n    fn file(&self) -> PathBuf {\n        self.env_val().map(PathBuf::from).unwrap_or_else(|| self.default.clone())\n    }\n\n    fn is_missing(&self) -> bool {\n        if let Some(file) = self.env_val() {\n            let path = Path::new(&file);\n            if !path.exists() {\n                return true;\n            }\n        }\n        false\n    }\n\n    /// Reads and processes the TOML configuration file, handling inheritance if configured.\n    fn read(&self) -> Result<Map<Profile, Dict>, Error> {\n        use serde::de::Error as _;\n\n        // Get the config file path and validate it exists\n        let local_path = self.file();\n        if !local_path.exists() {\n            if let Some(file) = self.env_val() {\n                return Err(Error::custom(format!(\n                    \"Config file `{}` set in env var `{}` does not exist\",\n                    file,\n                    self.env_var.unwrap()\n                )));\n            }\n            return Ok(Map::new());\n        }\n\n        // Create a provider for the local config file\n        let local_provider = Toml::file(local_path.clone()).nested();\n\n        // Parse the local config to check for extends field\n        let local_path_str = local_path.to_string_lossy();\n        let local_content = std::fs::read_to_string(&local_path)\n            .map_err(|e| Error::custom(e.to_string()).with_path(&local_path_str))?;\n        let partial_config: extend::ExtendsPartialConfig = toml::from_str(&local_content)\n            .map_err(|e| Error::custom(e.to_string()).with_path(&local_path_str))?;\n\n        // Check if the currently active profile has an 'extends' field\n        let selected_profile = Config::selected_profile();\n        let extends_config = partial_config.profile.as_ref().and_then(|profiles| {\n            let profile_str = selected_profile.to_string();\n            profiles.get(&profile_str).and_then(|cfg| cfg.extends.as_ref())\n        });\n\n        // If inheritance is configured, load and merge the base config\n        if let Some(extends_config) = extends_config {\n            let extends_path = extends_config.path();\n            let extends_strategy = extends_config.strategy();\n            let relative_base_path = PathBuf::from(extends_path);\n            let local_dir = local_path.parent().ok_or_else(|| {\n                Error::custom(format!(\n                    \"Could not determine parent directory of config file: {}\",\n                    local_path.display()\n                ))\n            })?;\n\n            let base_path =\n                foundry_compilers::utils::canonicalize(local_dir.join(&relative_base_path))\n                    .map_err(|e| {\n                        Error::custom(format!(\n                            \"Failed to resolve inherited config path: {}: {e}\",\n                            relative_base_path.display()\n                        ))\n                    })?;\n\n            // Validate the base config file exists\n            if !base_path.is_file() {\n                return Err(Error::custom(format!(\n                    \"Inherited config file does not exist or is not a file: {}\",\n                    base_path.display()\n                )));\n            }\n\n            // Prevent self-inheritance which would cause infinite recursion\n            if foundry_compilers::utils::canonicalize(&local_path).ok().as_ref() == Some(&base_path)\n            {\n                return Err(Error::custom(format!(\n                    \"Config file {} cannot inherit from itself.\",\n                    local_path.display()\n                )));\n            }\n\n            // Parse the base config to check for nested inheritance\n            let base_path_str = base_path.to_string_lossy();\n            let base_content = std::fs::read_to_string(&base_path)\n                .map_err(|e| Error::custom(e.to_string()).with_path(&base_path_str))?;\n            let base_partial: extend::ExtendsPartialConfig = toml::from_str(&base_content)\n                .map_err(|e| Error::custom(e.to_string()).with_path(&base_path_str))?;\n\n            // Check if the base file's same profile also has extends (nested inheritance)\n            let base_extends = base_partial\n                .profile\n                .as_ref()\n                .and_then(|profiles| {\n                    let profile_str = selected_profile.to_string();\n                    profiles.get(&profile_str)\n                })\n                .and_then(|profile| profile.extends.as_ref());\n\n            // Prevent nested inheritance to avoid complexity and potential cycles\n            if base_extends.is_some() {\n                return Err(Error::custom(format!(\n                    \"Nested inheritance is not allowed. Base file '{}' cannot have an 'extends' field in profile '{selected_profile}'.\",\n                    base_path.display()\n                )));\n            }\n\n            // Load base configuration as a Figment provider\n            let base_provider = Toml::file(base_path).nested();\n\n            // Apply the selected merge strategy\n            match extends_strategy {\n                extend::ExtendStrategy::ExtendArrays => {\n                    // Using 'admerge' strategy:\n                    // - Arrays are concatenated (base elements + local elements)\n                    // - Other values are replaced (local values override base values)\n                    // - The extends field is preserved in the final configuration\n                    Figment::new().merge(base_provider).admerge(local_provider).data()\n                }\n                extend::ExtendStrategy::ReplaceArrays => {\n                    // Using 'merge' strategy:\n                    // - Arrays are replaced entirely (local arrays replace base arrays)\n                    // - Other values are replaced (local values override base values)\n                    Figment::new().merge(base_provider).merge(local_provider).data()\n                }\n                extend::ExtendStrategy::NoCollision => {\n                    // Check for key collisions between base and local configs\n                    let base_data = base_provider.data()?;\n                    let local_data = local_provider.data()?;\n\n                    let profile_key = Profile::new(\"profile\");\n                    if let (Some(local_profiles), Some(base_profiles)) =\n                        (local_data.get(&profile_key), base_data.get(&profile_key))\n                    {\n                        // Extract dicts for the selected profile\n                        let profile_str = selected_profile.to_string();\n                        let base_dict = base_profiles.get(&profile_str).and_then(|v| v.as_dict());\n                        let local_dict = local_profiles.get(&profile_str).and_then(|v| v.as_dict());\n\n                        // Find colliding keys\n                        if let (Some(local_dict), Some(base_dict)) = (local_dict, base_dict) {\n                            let collisions: Vec<&String> = local_dict\n                                .keys()\n                                .filter(|key| {\n                                    // Ignore the \"extends\" key as it's expected\n                                    *key != \"extends\" && base_dict.contains_key(*key)\n                                })\n                                .collect();\n\n                            if !collisions.is_empty() {\n                                return Err(Error::custom(format!(\n                                    \"Key collision detected in profile '{profile_str}' when extending '{extends_path}'. \\\n                                    Conflicting keys: {collisions:?}. Use 'extends.strategy' or 'extends_strategy' to specify how to handle conflicts.\"\n                                )));\n                            }\n                        }\n                    }\n\n                    // Safe to merge the configs without collisions\n                    Figment::new().merge(base_provider).merge(local_provider).data()\n                }\n            }\n        } else {\n            // No inheritance - return the local config as-is\n            local_provider.data()\n        }\n    }\n}\n\nimpl Provider for TomlFileProvider {\n    fn metadata(&self) -> Metadata {\n        if self.is_missing() {\n            Metadata::named(\"TOML file provider\")\n        } else {\n            Toml::file(self.file()).nested().metadata()\n        }\n    }\n\n    fn data(&self) -> Result<Map<Profile, Dict>, Error> {\n        self.cache.get_or_init(|| self.read()).clone()\n    }\n}\n\n/// A Provider that ensures all keys are snake case if they're not standalone sections, See\n/// `Config::STANDALONE_SECTIONS`\n///\n/// For the `[profile]` section, profile names (like `ci-venom`) are preserved as-is,\n/// but the config keys within each profile are still converted to snake_case.\npub(crate) struct ForcedSnakeCaseData<P>(pub(crate) P);\n\nimpl<P: Provider> Provider for ForcedSnakeCaseData<P> {\n    fn metadata(&self) -> Metadata {\n        self.0.metadata()\n    }\n\n    fn data(&self) -> Result<Map<Profile, Dict>, Error> {\n        let mut map = self.0.data()?;\n        for (profile, dict) in &mut map {\n            if Config::STANDALONE_SECTIONS.contains(&profile.as_ref()) {\n                // don't force snake case for keys in standalone sections\n                continue;\n            }\n\n            if profile.as_str().as_str() == Config::PROFILE_SECTION {\n                // For the `[profile]` section, we need to preserve profile names (the keys)\n                // but snake_case the config keys within each profile's dict.\n                let dict2 = std::mem::take(dict);\n                *dict = dict2\n                    .into_iter()\n                    .map(|(profile_name, v)| {\n                        // Keep the profile name exactly as-is (e.g., \"ci-venom\" stays \"ci-venom\")\n                        let v = snake_case_value_keys(v);\n                        (profile_name, v)\n                    })\n                    .collect();\n                continue;\n            }\n\n            let dict2 = std::mem::take(dict);\n            *dict = dict2.into_iter().map(|(k, v)| (k.to_snake_case(), v)).collect();\n        }\n        Ok(map)\n    }\n\n    fn profile(&self) -> Option<Profile> {\n        self.0.profile()\n    }\n}\n\n/// Recursively converts all keys in a Value (if it's a Dict) to snake_case.\nfn snake_case_value_keys(value: Value) -> Value {\n    match value {\n        Value::Dict(tag, dict) => {\n            let new_dict = dict\n                .into_iter()\n                .map(|(k, v)| (k.to_snake_case(), snake_case_value_keys(v)))\n                .collect();\n            Value::Dict(tag, new_dict)\n        }\n        Value::Array(tag, arr) => {\n            let new_arr = arr.into_iter().map(snake_case_value_keys).collect();\n            Value::Array(tag, new_arr)\n        }\n        other => other,\n    }\n}\n\n/// A Provider that handles breaking changes in toml files\npub(crate) struct BackwardsCompatTomlProvider<P>(pub(crate) P);\n\nimpl<P: Provider> Provider for BackwardsCompatTomlProvider<P> {\n    fn metadata(&self) -> Metadata {\n        self.0.metadata()\n    }\n\n    fn data(&self) -> Result<Map<Profile, Dict>, Error> {\n        let mut map = Map::new();\n        let solc_env = std::env::var(\"FOUNDRY_SOLC_VERSION\")\n            .or_else(|_| std::env::var(\"DAPP_SOLC_VERSION\"))\n            .map(Value::from)\n            .ok();\n        for (profile, mut dict) in self.0.data()? {\n            if let Some(v) = solc_env.clone() {\n                // ENV var takes precedence over config file\n                dict.insert(\"solc\".to_string(), v);\n            } else if let Some(v) = dict.remove(\"solc_version\") {\n                // only insert older variant if not already included\n                if !dict.contains_key(\"solc\") {\n                    dict.insert(\"solc\".to_string(), v);\n                }\n            }\n            if let Some(v) = dict.remove(\"deny_warnings\")\n                && !dict.contains_key(\"deny\")\n            {\n                dict.insert(\"deny\".to_string(), v);\n            }\n\n            map.insert(profile, dict);\n        }\n        Ok(map)\n    }\n\n    fn profile(&self) -> Option<Profile> {\n        self.0.profile()\n    }\n}\n\n/// A provider that sets the `src` and `output` path depending on their existence.\npub(crate) struct DappHardhatDirProvider<'a>(pub(crate) &'a Path);\n\nimpl Provider for DappHardhatDirProvider<'_> {\n    fn metadata(&self) -> Metadata {\n        Metadata::named(\"Dapp Hardhat dir compat\")\n    }\n\n    fn data(&self) -> Result<Map<Profile, Dict>, Error> {\n        let mut dict = Dict::new();\n        dict.insert(\n            \"src\".to_string(),\n            ProjectPathsConfig::find_source_dir(self.0)\n                .file_name()\n                .unwrap()\n                .to_string_lossy()\n                .to_string()\n                .into(),\n        );\n        dict.insert(\n            \"out\".to_string(),\n            ProjectPathsConfig::find_artifacts_dir(self.0)\n                .file_name()\n                .unwrap()\n                .to_string_lossy()\n                .to_string()\n                .into(),\n        );\n\n        // detect libs folders:\n        //   if `lib` _and_ `node_modules` exists: include both\n        //   if only `node_modules` exists: include `node_modules`\n        //   include `lib` otherwise\n        let mut libs = vec![];\n        let node_modules = self.0.join(\"node_modules\");\n        let lib = self.0.join(\"lib\");\n        if node_modules.exists() {\n            if lib.exists() {\n                libs.push(lib.file_name().unwrap().to_string_lossy().to_string());\n            }\n            libs.push(node_modules.file_name().unwrap().to_string_lossy().to_string());\n        } else {\n            libs.push(lib.file_name().unwrap().to_string_lossy().to_string());\n        }\n\n        dict.insert(\"libs\".to_string(), libs.into());\n\n        Ok(Map::from([(Config::selected_profile(), dict)]))\n    }\n}\n\n/// A provider that checks for DAPP_ env vars that are named differently than FOUNDRY_\npub(crate) struct DappEnvCompatProvider;\n\nimpl Provider for DappEnvCompatProvider {\n    fn metadata(&self) -> Metadata {\n        Metadata::named(\"Dapp env compat\")\n    }\n\n    fn data(&self) -> Result<Map<Profile, Dict>, Error> {\n        use serde::de::Error as _;\n        use std::env;\n\n        let mut dict = Dict::new();\n        if let Ok(val) = env::var(\"DAPP_TEST_NUMBER\") {\n            dict.insert(\n                \"block_number\".to_string(),\n                val.parse::<u64>().map_err(figment::Error::custom)?.into(),\n            );\n        }\n        if let Ok(val) = env::var(\"DAPP_TEST_ADDRESS\") {\n            dict.insert(\"sender\".to_string(), val.into());\n        }\n        if let Ok(val) = env::var(\"DAPP_FORK_BLOCK\") {\n            dict.insert(\n                \"fork_block_number\".to_string(),\n                val.parse::<u64>().map_err(figment::Error::custom)?.into(),\n            );\n        } else if let Ok(val) = env::var(\"DAPP_TEST_NUMBER\") {\n            dict.insert(\n                \"fork_block_number\".to_string(),\n                val.parse::<u64>().map_err(figment::Error::custom)?.into(),\n            );\n        }\n        if let Ok(val) = env::var(\"DAPP_TEST_TIMESTAMP\") {\n            dict.insert(\n                \"block_timestamp\".to_string(),\n                val.parse::<u64>().map_err(figment::Error::custom)?.into(),\n            );\n        }\n        if let Ok(val) = env::var(\"DAPP_BUILD_OPTIMIZE_RUNS\") {\n            dict.insert(\n                \"optimizer_runs\".to_string(),\n                val.parse::<u64>().map_err(figment::Error::custom)?.into(),\n            );\n        }\n        if let Ok(val) = env::var(\"DAPP_BUILD_OPTIMIZE\") {\n            // Activate Solidity optimizer (0 or 1)\n            let val = val.parse::<u8>().map_err(figment::Error::custom)?;\n            if val > 1 {\n                return Err(\n                    format!(\"Invalid $DAPP_BUILD_OPTIMIZE value `{val}`, expected 0 or 1\").into()\n                );\n            }\n            dict.insert(\"optimizer\".to_string(), (val == 1).into());\n        }\n\n        // libraries in env vars either as `[..]` or single string separated by comma\n        if let Ok(val) = env::var(\"DAPP_LIBRARIES\").or_else(|_| env::var(\"FOUNDRY_LIBRARIES\")) {\n            dict.insert(\"libraries\".to_string(), utils::to_array_value(&val)?);\n        }\n\n        let mut fuzz_dict = Dict::new();\n        if let Ok(val) = env::var(\"DAPP_TEST_FUZZ_RUNS\") {\n            fuzz_dict.insert(\n                \"runs\".to_string(),\n                val.parse::<u32>().map_err(figment::Error::custom)?.into(),\n            );\n        }\n        dict.insert(\"fuzz\".to_string(), fuzz_dict.into());\n\n        let mut invariant_dict = Dict::new();\n        if let Ok(val) = env::var(\"DAPP_TEST_DEPTH\") {\n            invariant_dict.insert(\n                \"depth\".to_string(),\n                val.parse::<u32>().map_err(figment::Error::custom)?.into(),\n            );\n        }\n        dict.insert(\"invariant\".to_string(), invariant_dict.into());\n\n        Ok(Map::from([(Config::selected_profile(), dict)]))\n    }\n}\n\n/// Renames a profile from `from` to `to`.\n///\n/// For example given:\n///\n/// ```toml\n/// [from]\n/// key = \"value\"\n/// ```\n///\n/// RenameProfileProvider will output\n///\n/// ```toml\n/// [to]\n/// key = \"value\"\n/// ```\npub(crate) struct RenameProfileProvider<P> {\n    provider: P,\n    from: Profile,\n    to: Profile,\n}\n\nimpl<P> RenameProfileProvider<P> {\n    pub(crate) fn new(provider: P, from: impl Into<Profile>, to: impl Into<Profile>) -> Self {\n        Self { provider, from: from.into(), to: to.into() }\n    }\n}\n\nimpl<P: Provider> Provider for RenameProfileProvider<P> {\n    fn metadata(&self) -> Metadata {\n        self.provider.metadata()\n    }\n\n    fn data(&self) -> Result<Map<Profile, Dict>, Error> {\n        let mut data = self.provider.data()?;\n        if let Some(data) = data.remove(&self.from) {\n            return Ok(Map::from([(self.to.clone(), data)]));\n        }\n        Ok(Default::default())\n    }\n\n    fn profile(&self) -> Option<Profile> {\n        Some(self.to.clone())\n    }\n}\n\n/// Unwraps a profile reducing the key depth\n///\n/// For example given:\n///\n/// ```toml\n/// [wrapping_key.profile]\n/// key = \"value\"\n/// ```\n///\n/// UnwrapProfileProvider will output:\n///\n/// ```toml\n/// [profile]\n/// key = \"value\"\n/// ```\nstruct UnwrapProfileProvider<P> {\n    provider: P,\n    wrapping_key: Profile,\n    profile: Profile,\n}\n\nimpl<P> UnwrapProfileProvider<P> {\n    pub fn new(provider: P, wrapping_key: impl Into<Profile>, profile: impl Into<Profile>) -> Self {\n        Self { provider, wrapping_key: wrapping_key.into(), profile: profile.into() }\n    }\n}\n\nimpl<P: Provider> Provider for UnwrapProfileProvider<P> {\n    fn metadata(&self) -> Metadata {\n        self.provider.metadata()\n    }\n\n    fn data(&self) -> Result<Map<Profile, Dict>, Error> {\n        let mut data = self.provider.data()?;\n        if let Some(profiles) = data.remove(&self.wrapping_key) {\n            for (profile_str, profile_val) in profiles {\n                let profile = Profile::new(&profile_str);\n                if profile != self.profile {\n                    continue;\n                }\n                match profile_val {\n                    Value::Dict(_, dict) => return Ok(profile.collect(dict)),\n                    bad_val => {\n                        let mut err = Error::from(figment::error::Kind::InvalidType(\n                            bad_val.to_actual(),\n                            \"dict\".into(),\n                        ));\n                        err.metadata = Some(self.provider.metadata());\n                        err.profile = Some(self.profile.clone());\n                        return Err(err);\n                    }\n                }\n            }\n        }\n        Ok(Default::default())\n    }\n\n    fn profile(&self) -> Option<Profile> {\n        Some(self.profile.clone())\n    }\n}\n\n/// Wraps a profile in another profile\n///\n/// For example given:\n///\n/// ```toml\n/// [profile]\n/// key = \"value\"\n/// ```\n///\n/// WrapProfileProvider will output:\n///\n/// ```toml\n/// [wrapping_key.profile]\n/// key = \"value\"\n/// ```\npub(crate) struct WrapProfileProvider<P> {\n    provider: P,\n    wrapping_key: Profile,\n    profile: Profile,\n}\n\nimpl<P> WrapProfileProvider<P> {\n    pub fn new(provider: P, wrapping_key: impl Into<Profile>, profile: impl Into<Profile>) -> Self {\n        Self { provider, wrapping_key: wrapping_key.into(), profile: profile.into() }\n    }\n}\n\nimpl<P: Provider> Provider for WrapProfileProvider<P> {\n    fn metadata(&self) -> Metadata {\n        self.provider.metadata()\n    }\n\n    fn data(&self) -> Result<Map<Profile, Dict>, Error> {\n        if let Some(inner) = self.provider.data()?.remove(&self.profile) {\n            let value = Value::from(inner);\n            let mut dict = Dict::new();\n            dict.insert(self.profile.as_str().as_str().to_snake_case(), value);\n            Ok(self.wrapping_key.collect(dict))\n        } else {\n            Ok(Default::default())\n        }\n    }\n\n    fn profile(&self) -> Option<Profile> {\n        Some(self.profile.clone())\n    }\n}\n\n/// Extracts the profile from the `profile` key and using the original key as backup, merging\n/// values where necessary\n///\n/// For example given:\n///\n/// ```toml\n/// [profile.cool]\n/// key = \"value\"\n///\n/// [cool]\n/// key2 = \"value2\"\n/// ```\n///\n/// OptionalStrictProfileProvider will output:\n///\n/// ```toml\n/// [cool]\n/// key = \"value\"\n/// key2 = \"value2\"\n/// ```\n///\n/// And emit a deprecation warning\npub(crate) struct OptionalStrictProfileProvider<P> {\n    provider: P,\n    profiles: Vec<Profile>,\n}\n\nimpl<P> OptionalStrictProfileProvider<P> {\n    pub const PROFILE_PROFILE: Profile = Profile::const_new(\"profile\");\n\n    pub fn new(provider: P, profiles: impl IntoIterator<Item = impl Into<Profile>>) -> Self {\n        Self { provider, profiles: profiles.into_iter().map(|profile| profile.into()).collect() }\n    }\n}\n\nimpl<P: Provider> Provider for OptionalStrictProfileProvider<P> {\n    fn metadata(&self) -> Metadata {\n        self.provider.metadata()\n    }\n\n    fn data(&self) -> Result<Map<Profile, Dict>, Error> {\n        let mut figment = Figment::from(&self.provider);\n        for profile in &self.profiles {\n            figment = figment.merge(UnwrapProfileProvider::new(\n                &self.provider,\n                Self::PROFILE_PROFILE,\n                profile.clone(),\n            ));\n        }\n        figment.data().map_err(|err| {\n            // figment does tag metadata and tries to map metadata to an error, since we use a new\n            // figment in this provider this new figment does not know about the metadata of the\n            // provider and can't map the metadata to the error. Therefore we return the root error\n            // if this error originated in the provider's data.\n            if let Err(root_err) = self.provider.data() {\n                return root_err;\n            }\n            err\n        })\n    }\n\n    fn profile(&self) -> Option<Profile> {\n        self.profiles.last().cloned()\n    }\n}\n\n/// Extracts the profile from the `profile` key and sets unset values according to the fallback\n/// provider\npub struct FallbackProfileProvider<P> {\n    provider: P,\n    profile: Profile,\n    fallback: Profile,\n}\n\nimpl<P> FallbackProfileProvider<P> {\n    /// Creates a new fallback profile provider.\n    pub fn new(provider: P, profile: impl Into<Profile>, fallback: impl Into<Profile>) -> Self {\n        Self { provider, profile: profile.into(), fallback: fallback.into() }\n    }\n}\n\nimpl<P: Provider> Provider for FallbackProfileProvider<P> {\n    fn metadata(&self) -> Metadata {\n        self.provider.metadata()\n    }\n\n    fn data(&self) -> Result<Map<Profile, Dict>, Error> {\n        let mut data = self.provider.data()?;\n        if let Some(fallback) = data.remove(&self.fallback) {\n            let mut inner = data.remove(&self.profile).unwrap_or_default();\n            for (k, v) in fallback {\n                inner.entry(k).or_insert(v);\n            }\n            Ok(self.profile.collect(inner))\n        } else {\n            Ok(data)\n        }\n    }\n\n    fn profile(&self) -> Option<Profile> {\n        Some(self.profile.clone())\n    }\n}\n"
  },
  {
    "path": "crates/config/src/providers/mod.rs",
    "content": "//! Config providers.\n\nmod ext;\npub use ext::*;\n\nmod remappings;\npub use remappings::*;\n\nmod warnings;\npub use warnings::*;\n"
  },
  {
    "path": "crates/config/src/providers/remappings.rs",
    "content": "use crate::{Config, foundry_toml_dirs, remappings_from_env_var, remappings_from_newline};\nuse figment::{\n    Error, Figment, Metadata, Profile, Provider,\n    value::{Dict, Map},\n};\nuse foundry_compilers::artifacts::remappings::{RelativeRemapping, Remapping};\nuse rayon::prelude::*;\nuse std::{\n    borrow::Cow,\n    collections::{BTreeMap, HashSet, btree_map::Entry},\n    fs,\n    path::{Path, PathBuf},\n};\n\n/// Wrapper types over a `Vec<Remapping>` that only appends unique remappings.\n#[derive(Clone, Debug, Default)]\npub struct Remappings {\n    /// Remappings.\n    remappings: Vec<Remapping>,\n    /// Source, test and script configured project dirs.\n    /// Remappings of these dirs from libs are ignored.\n    project_paths: Vec<Remapping>,\n}\n\nimpl Remappings {\n    /// Create a new `Remappings` wrapper with an empty vector.\n    pub fn new() -> Self {\n        Self { remappings: Vec::new(), project_paths: Vec::new() }\n    }\n\n    /// Create a new `Remappings` wrapper with a vector of remappings.\n    pub fn new_with_remappings(remappings: Vec<Remapping>) -> Self {\n        Self { remappings, project_paths: Vec::new() }\n    }\n\n    /// Extract project paths that cannot be remapped by dependencies.\n    pub fn with_figment(mut self, figment: &Figment) -> Self {\n        let mut add_project_remapping = |path: &str| {\n            if let Ok(path) = figment.find_value(path)\n                && let Some(path) = path.into_string()\n            {\n                let remapping =\n                    Remapping { context: None, name: format!(\"{path}/\"), path: format!(\"{path}/\") };\n                self.project_paths.push(remapping);\n            }\n        };\n        add_project_remapping(\"src\");\n        add_project_remapping(\"test\");\n        add_project_remapping(\"script\");\n        self\n    }\n\n    /// Filters the remappings vector by name and context.\n    fn filter_key(r: &Remapping) -> String {\n        match &r.context {\n            Some(str) => str.clone() + &r.name.clone(),\n            None => r.name.clone(),\n        }\n    }\n\n    /// Consumes the wrapper and returns the inner remappings vector.\n    pub fn into_inner(self) -> Vec<Remapping> {\n        let mut seen = HashSet::new();\n        self.remappings.iter().filter(|r| seen.insert(Self::filter_key(r))).cloned().collect()\n    }\n\n    /// Push an element to the remappings vector, but only if it's not already present.\n    fn push(&mut self, remapping: Remapping) {\n        // Special handling for .sol file remappings, only allow one remapping per source file.\n        if remapping.name.ends_with(\".sol\") && !remapping.path.ends_with(\".sol\") {\n            return;\n        }\n\n        if self.remappings.iter().any(|existing| {\n            if remapping.name.ends_with(\".sol\") {\n                // For .sol files, only prevent duplicate source names in the same context\n                return existing.name == remapping.name\n                    && existing.context == remapping.context\n                    && existing.path == remapping.path;\n            }\n\n            // What we're doing here is filtering for ambiguous paths. For example, if we have\n            // @prb/math/=node_modules/@prb/math/src/ as existing, and\n            // @prb/=node_modules/@prb/ as the one being checked,\n            // we want to keep the already existing one, which is the first one. This way we avoid\n            // having to deal with ambiguous paths which is unwanted when autodetecting remappings.\n            // Remappings are added from root of the project down to libraries, so\n            // we also want to exclude any conflicting remappings added from libraries. For example,\n            // if we have `@utils/=src/` added in project remappings and `@utils/libraries/=src/`\n            // added in a dependency, we don't want to add the new one as it conflicts with project\n            // existing remapping.\n            let mut existing_name_path = existing.name.clone();\n            if !existing_name_path.ends_with('/') {\n                existing_name_path.push('/')\n            }\n            let is_conflicting = remapping.name.starts_with(&existing_name_path)\n                || existing.name.starts_with(&remapping.name);\n            is_conflicting && existing.context == remapping.context\n        }) {\n            return;\n        };\n\n        // Ignore remappings of root project src, test or script dir.\n        // See <https://github.com/foundry-rs/foundry/issues/3440>.\n        if self\n            .project_paths\n            .iter()\n            .any(|project_path| remapping.name.eq_ignore_ascii_case(&project_path.name))\n        {\n            return;\n        };\n\n        self.remappings.push(remapping);\n    }\n\n    /// Extend the remappings vector, leaving out the remappings that are already present.\n    pub fn extend(&mut self, remappings: Vec<Remapping>) {\n        for remapping in remappings {\n            self.push(remapping);\n        }\n    }\n}\n\n/// A figment provider that checks if the remappings were previously set and if they're unset looks\n/// up the fs via\n///   - `DAPP_REMAPPINGS` || `FOUNDRY_REMAPPINGS` env var\n///   - `<root>/remappings.txt` file\n///   - `Remapping::find_many`.\npub struct RemappingsProvider<'a> {\n    /// Whether to auto detect remappings from the `lib_paths`\n    pub auto_detect_remappings: bool,\n    /// The lib/dependency directories to scan for remappings\n    pub lib_paths: Cow<'a, Vec<PathBuf>>,\n    /// the root path used to turn an absolute `Remapping`, as we're getting it from\n    /// `Remapping::find_many` into a relative one.\n    pub root: &'a Path,\n    /// This contains either:\n    ///   - previously set remappings\n    ///   - a `MissingField` error, which means previous provider didn't set the \"remappings\" field\n    ///   - other error, like formatting\n    pub remappings: Result<Vec<Remapping>, Error>,\n}\n\nimpl RemappingsProvider<'_> {\n    /// Find and parse remappings for the projects\n    ///\n    /// **Order**\n    ///\n    /// Remappings are built in this order (last item takes precedence)\n    /// - Autogenerated remappings\n    /// - toml remappings\n    /// - `remappings.txt`\n    /// - Environment variables\n    /// - CLI parameters\n    fn get_remappings(&self, remappings: Vec<Remapping>) -> Result<Vec<Remapping>, Error> {\n        trace!(\"get all remappings from {:?}\", self.root);\n        /// prioritizes remappings that are closer: shorter `path`\n        ///   - (\"a\", \"1/2\") over (\"a\", \"1/2/3\")\n        ///\n        /// grouped by remapping context\n        fn insert_closest(\n            mappings: &mut BTreeMap<Option<String>, BTreeMap<String, PathBuf>>,\n            context: Option<String>,\n            key: String,\n            path: PathBuf,\n        ) {\n            let context_mappings = mappings.entry(context).or_default();\n            match context_mappings.entry(key) {\n                Entry::Occupied(mut e)\n                    if e.get().components().count() > path.components().count() =>\n                {\n                    e.insert(path);\n                }\n                Entry::Vacant(e) => {\n                    e.insert(path);\n                }\n                _ => {}\n            }\n        }\n\n        // Let's first just extend the remappings with the ones that were passed in,\n        // without any filtering.\n        let mut user_remappings = Vec::new();\n\n        // check env vars\n        if let Some(env_remappings) = remappings_from_env_var(\"DAPP_REMAPPINGS\")\n            .or_else(|| remappings_from_env_var(\"FOUNDRY_REMAPPINGS\"))\n        {\n            user_remappings\n                .extend(env_remappings.map_err::<Error, _>(|err| err.to_string().into())?);\n        }\n\n        // check remappings.txt file\n        let remappings_file = self.root.join(\"remappings.txt\");\n        if remappings_file.is_file() {\n            let content = fs::read_to_string(remappings_file).map_err(|err| err.to_string())?;\n            let remappings_from_file: Result<Vec<_>, _> =\n                remappings_from_newline(&content).collect();\n            user_remappings\n                .extend(remappings_from_file.map_err::<Error, _>(|err| err.to_string().into())?);\n        }\n\n        user_remappings.extend(remappings);\n        // Let's now use the wrapper to conditionally extend the remappings with the autodetected\n        // ones. We want to avoid duplicates, and the wrapper will handle this for us.\n        let mut all_remappings = Remappings::new_with_remappings(user_remappings);\n\n        // scan all library dirs and autodetect remappings\n        // TODO: if a lib specifies contexts for remappings manually, we need to figure out how to\n        // resolve that\n        if self.auto_detect_remappings {\n            let (nested_foundry_remappings, auto_detected_remappings) = rayon::join(\n                || self.find_nested_foundry_remappings(),\n                || self.auto_detect_remappings(),\n            );\n\n            let mut lib_remappings = BTreeMap::new();\n            for r in nested_foundry_remappings {\n                insert_closest(&mut lib_remappings, r.context, r.name, r.path.into());\n            }\n            for r in auto_detected_remappings {\n                // this is an additional safety check for weird auto-detected remappings\n                if [\"lib/\", \"src/\", \"contracts/\"].contains(&r.name.as_str()) {\n                    trace!(target: \"forge\", \"- skipping the remapping\");\n                    continue;\n                }\n                insert_closest(&mut lib_remappings, r.context, r.name, r.path.into());\n            }\n\n            all_remappings.extend(\n                lib_remappings\n                    .into_iter()\n                    .flat_map(|(context, remappings)| {\n                        remappings.into_iter().map(move |(name, path)| Remapping {\n                            context: context.clone(),\n                            name,\n                            path: path.to_string_lossy().into(),\n                        })\n                    })\n                    .collect(),\n            );\n        }\n\n        Ok(all_remappings.into_inner())\n    }\n\n    /// Returns all remappings declared in foundry.toml files of libraries\n    fn find_nested_foundry_remappings(&self) -> impl Iterator<Item = Remapping> + '_ {\n        self.lib_paths\n            .par_iter()\n            .map(|p| if p.is_absolute() { self.root.join(\"lib\") } else { self.root.join(p) })\n            .flat_map(foundry_toml_dirs)\n            .flat_map_iter(|lib| {\n                trace!(?lib, \"find all remappings of nested foundry.toml\");\n                self.nested_foundry_remappings(&lib)\n            })\n            .collect::<Vec<_>>()\n            .into_iter()\n    }\n\n    fn nested_foundry_remappings(&self, lib: &Path) -> Vec<Remapping> {\n        // load config of the nested lib if it exists, using fallback mode since libs may not\n        // define all profiles the main project uses\n        let Ok(config) = Config::load_with_root_and_fallback(lib) else { return vec![] };\n        let config = config.sanitized();\n\n        // if the configured _src_ directory is set to something that\n        // `Remapping::find_many` doesn't classify as a src directory (src, contracts,\n        // lib), then we need to manually add a remapping here\n        let mut src_remapping = None;\n        if ![Path::new(\"src\"), Path::new(\"contracts\"), Path::new(\"lib\")]\n            .contains(&config.src.as_path())\n            && let Some(name) = lib.file_name().and_then(|s| s.to_str())\n        {\n            let mut r = Remapping {\n                context: None,\n                name: format!(\"{name}/\"),\n                path: format!(\"{}\", lib.join(&config.src).display()),\n            };\n            if !r.path.ends_with('/') {\n                r.path.push('/')\n            }\n            src_remapping = Some(r);\n        }\n\n        // Eventually, we could set context for remappings at this location,\n        // taking into account the OS platform. We'll need to be able to handle nested\n        // contexts depending on dependencies for this to work.\n        // For now, we just leave the default context (none).\n        let mut remappings =\n            config.remappings.into_iter().map(Remapping::from).collect::<Vec<Remapping>>();\n\n        if let Some(r) = src_remapping {\n            remappings.push(r);\n        }\n        remappings\n    }\n\n    /// Auto detect remappings from the lib paths\n    fn auto_detect_remappings(&self) -> impl Iterator<Item = Remapping> + '_ {\n        self.lib_paths\n            .par_iter()\n            .flat_map_iter(|lib| {\n                let lib = self.root.join(lib);\n                trace!(?lib, \"find all remappings\");\n                Remapping::find_many(&lib)\n            })\n            .collect::<Vec<_>>()\n            .into_iter()\n    }\n}\n\nimpl Provider for RemappingsProvider<'_> {\n    fn metadata(&self) -> Metadata {\n        Metadata::named(\"Remapping Provider\")\n    }\n\n    fn data(&self) -> Result<Map<Profile, Dict>, Error> {\n        let remappings = match &self.remappings {\n            Ok(remappings) => self.get_remappings(remappings.clone()),\n            Err(err) => {\n                if let figment::error::Kind::MissingField(_) = err.kind {\n                    self.get_remappings(vec![])\n                } else {\n                    return Err(err.clone());\n                }\n            }\n        }?;\n\n        // turn the absolute remapping into a relative one by stripping the `root`\n        let remappings = remappings\n            .into_iter()\n            .map(|r| RelativeRemapping::new(r, self.root).to_string())\n            .collect::<Vec<_>>();\n\n        Ok(Map::from([(\n            Config::selected_profile(),\n            Dict::from([(\"remappings\".to_string(), figment::value::Value::from(remappings))]),\n        )]))\n    }\n\n    fn profile(&self) -> Option<Profile> {\n        Some(Config::selected_profile())\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_sol_file_remappings() {\n        let mut remappings = Remappings::new();\n\n        // First valid remapping\n        remappings.push(Remapping {\n            context: None,\n            name: \"MyContract.sol\".to_string(),\n            path: \"implementations/Contract1.sol\".to_string(),\n        });\n\n        // Same source to different target (should be rejected)\n        remappings.push(Remapping {\n            context: None,\n            name: \"MyContract.sol\".to_string(),\n            path: \"implementations/Contract2.sol\".to_string(),\n        });\n\n        // Different source to same target (should be allowed)\n        remappings.push(Remapping {\n            context: None,\n            name: \"OtherContract.sol\".to_string(),\n            path: \"implementations/Contract1.sol\".to_string(),\n        });\n\n        // Exact duplicate (should be silently ignored)\n        remappings.push(Remapping {\n            context: None,\n            name: \"MyContract.sol\".to_string(),\n            path: \"implementations/Contract1.sol\".to_string(),\n        });\n\n        // Invalid .sol remapping (target not .sol)\n        remappings.push(Remapping {\n            context: None,\n            name: \"Invalid.sol\".to_string(),\n            path: \"implementations/Contract1.txt\".to_string(),\n        });\n\n        let result = remappings.into_inner();\n        assert_eq!(result.len(), 2, \"Should only have 2 valid remappings\");\n\n        // Verify the correct remappings exist\n        assert!(\n            result\n                .iter()\n                .any(|r| r.name == \"MyContract.sol\" && r.path == \"implementations/Contract1.sol\"),\n            \"Should keep first mapping of MyContract.sol\"\n        );\n        assert!(\n            !result\n                .iter()\n                .any(|r| r.name == \"MyContract.sol\" && r.path == \"implementations/Contract2.sol\"),\n            \"Should keep first mapping of MyContract.sol\"\n        );\n        assert!(result.iter().any(|r| r.name == \"OtherContract.sol\" && r.path == \"implementations/Contract1.sol\"),\n            \"Should allow different source to same target\");\n\n        // Verify the rejected remapping doesn't exist\n        assert!(\n            !result\n                .iter()\n                .any(|r| r.name == \"MyContract.sol\" && r.path == \"implementations/Contract2.sol\"),\n            \"Should reject same source to different target\"\n        );\n    }\n\n    #[test]\n    fn test_mixed_remappings() {\n        let mut remappings = Remappings::new();\n\n        remappings.push(Remapping {\n            context: None,\n            name: \"@openzeppelin-contracts/\".to_string(),\n            path: \"lib/openzeppelin-contracts/\".to_string(),\n        });\n        remappings.push(Remapping {\n            context: None,\n            name: \"@openzeppelin/contracts/\".to_string(),\n            path: \"lib/openzeppelin/contracts/\".to_string(),\n        });\n\n        remappings.push(Remapping {\n            context: None,\n            name: \"MyContract.sol\".to_string(),\n            path: \"os/Contract.sol\".to_string(),\n        });\n\n        let result = remappings.into_inner();\n        assert_eq!(result.len(), 3, \"Should have 3 remappings\");\n        assert_eq!(result.first().unwrap().name, \"@openzeppelin-contracts/\");\n        assert_eq!(result.first().unwrap().path, \"lib/openzeppelin-contracts/\");\n        assert_eq!(result.get(1).unwrap().name, \"@openzeppelin/contracts/\");\n        assert_eq!(result.get(1).unwrap().path, \"lib/openzeppelin/contracts/\");\n        assert_eq!(result.get(2).unwrap().name, \"MyContract.sol\");\n        assert_eq!(result.get(2).unwrap().path, \"os/Contract.sol\");\n    }\n\n    #[test]\n    fn test_remappings_with_context() {\n        let mut remappings = Remappings::new();\n\n        // Same name but different contexts\n        remappings.push(Remapping {\n            context: Some(\"test/\".to_string()),\n            name: \"MyContract.sol\".to_string(),\n            path: \"test/Contract.sol\".to_string(),\n        });\n        remappings.push(Remapping {\n            context: Some(\"prod/\".to_string()),\n            name: \"MyContract.sol\".to_string(),\n            path: \"prod/Contract.sol\".to_string(),\n        });\n\n        let result = remappings.into_inner();\n        assert_eq!(result.len(), 2, \"Should allow same name with different contexts\");\n        assert!(\n            result\n                .iter()\n                .any(|r| r.context == Some(\"test/\".to_string()) && r.path == \"test/Contract.sol\")\n        );\n        assert!(\n            result\n                .iter()\n                .any(|r| r.context == Some(\"prod/\".to_string()) && r.path == \"prod/Contract.sol\")\n        );\n    }\n}\n"
  },
  {
    "path": "crates/config/src/providers/warnings.rs",
    "content": "use crate::{Config, DEPRECATIONS, Warning};\nuse figment::{\n    Error, Figment, Metadata, Profile, Provider,\n    value::{Dict, Map, Value},\n};\nuse heck::ToSnakeCase;\nuse std::collections::{BTreeMap, BTreeSet};\n\n/// Allowed keys for CompilationRestrictions.\nconst COMPILATION_RESTRICTIONS_KEYS: &[&str] = &[\n    \"paths\",\n    \"version\",\n    \"via_ir\",\n    \"bytecode_hash\",\n    \"min_optimizer_runs\",\n    \"optimizer_runs\",\n    \"max_optimizer_runs\",\n    \"min_evm_version\",\n    \"evm_version\",\n    \"max_evm_version\",\n];\n\n/// Allowed keys for SettingsOverrides.\nconst SETTINGS_OVERRIDES_KEYS: &[&str] =\n    &[\"name\", \"via_ir\", \"evm_version\", \"optimizer\", \"optimizer_runs\", \"bytecode_hash\"];\n\n/// Allowed keys for VyperConfig.\n/// Required because VyperConfig uses `skip_serializing_if = \"Option::is_none\"` on all fields,\n/// causing the default serialization to produce an empty dict.\nconst VYPER_KEYS: &[&str] = &[\"optimize\", \"path\", \"experimental_codegen\"];\n\n/// Allowed keys for DocConfig.\n/// Required because DocConfig uses `skip_serializing_if = \"Option::is_none\"` on some fields\n/// (`repository`, `path`), whose defaults are `None` and thus excluded from serialization.\nconst DOC_KEYS: &[&str] = &[\"out\", \"title\", \"book\", \"homepage\", \"repository\", \"path\", \"ignore\"];\n\n/// Reserved keys that should not trigger unknown key warnings.\nconst RESERVED_KEYS: &[&str] = &[\"extends\"];\n\n/// Keys kept for backward compatibility that should not trigger unknown key warnings.\nconst BACKWARD_COMPATIBLE_KEYS: &[&str] = &[\"solc_version\"];\n\n/// Generate warnings for unknown sections and deprecated keys\npub struct WarningsProvider<P> {\n    provider: P,\n    profile: Profile,\n    old_warnings: Result<Vec<Warning>, Error>,\n}\n\nimpl<P: Provider> WarningsProvider<P> {\n    const WARNINGS_KEY: &'static str = \"__warnings\";\n\n    /// Creates a new warnings provider.\n    pub fn new(\n        provider: P,\n        profile: impl Into<Profile>,\n        old_warnings: Result<Vec<Warning>, Error>,\n    ) -> Self {\n        Self { provider, profile: profile.into(), old_warnings }\n    }\n\n    /// Creates a new figment warnings provider.\n    pub fn for_figment(provider: P, figment: &Figment) -> Self {\n        let old_warnings = {\n            let warnings_res = figment.extract_inner(Self::WARNINGS_KEY);\n            if warnings_res.as_ref().err().map(|err| err.missing()).unwrap_or(false) {\n                Ok(vec![])\n            } else {\n                warnings_res\n            }\n        };\n        Self::new(provider, figment.profile().clone(), old_warnings)\n    }\n\n    /// Collects all warnings.\n    pub fn collect_warnings(&self) -> Result<Vec<Warning>, Error> {\n        let data = self.provider.data().unwrap_or_default();\n\n        let mut out = self.old_warnings.clone()?;\n\n        // Add warning for unknown sections.\n        out.extend(data.keys().filter(|k| !Config::is_standalone_section(k.as_str())).map(\n            |unknown_section| {\n                let source = self.provider.metadata().source.map(|s| s.to_string());\n                Warning::UnknownSection { unknown_section: unknown_section.clone(), source }\n            },\n        ));\n\n        // Add warning for deprecated keys.\n        let deprecated_key_warning = |key| {\n            DEPRECATIONS.iter().find_map(|(deprecated_key, new_value)| {\n                if key == *deprecated_key {\n                    Some(Warning::DeprecatedKey {\n                        old: deprecated_key.to_string(),\n                        new: new_value.to_string(),\n                    })\n                } else {\n                    None\n                }\n            })\n        };\n        let profiles = data\n            .iter()\n            .filter(|(profile, _)| **profile == Config::PROFILE_SECTION)\n            .map(|(_, dict)| dict);\n\n        out.extend(profiles.clone().flat_map(BTreeMap::keys).filter_map(deprecated_key_warning));\n        out.extend(\n            profiles\n                .clone()\n                .filter_map(|dict| dict.get(self.profile.as_str().as_str()))\n                .filter_map(Value::as_dict)\n                .flat_map(BTreeMap::keys)\n                .filter_map(deprecated_key_warning),\n        );\n\n        // Add warning for unknown keys within profiles (root keys only here).\n        if let Ok(default_map) = figment::providers::Serialized::defaults(&Config::default()).data()\n            && let Some(default_dict) = default_map.get(&Config::DEFAULT_PROFILE)\n        {\n            let allowed_keys: BTreeSet<String> = default_dict.keys().cloned().collect();\n            for profile_map in profiles.clone() {\n                for (profile, value) in profile_map {\n                    let Some(profile_dict) = value.as_dict() else {\n                        continue;\n                    };\n\n                    let source = self\n                        .provider\n                        .metadata()\n                        .source\n                        .map(|s| s.to_string())\n                        .unwrap_or(Config::FILE_NAME.to_string());\n                    for key in profile_dict.keys() {\n                        let is_not_deprecated =\n                            !DEPRECATIONS.iter().any(|(deprecated_key, _)| *deprecated_key == key);\n                        let is_not_allowed = !allowed_keys.contains(key)\n                            && !allowed_keys.contains(&key.to_snake_case());\n                        let is_not_reserved =\n                            !RESERVED_KEYS.contains(&key.as_str()) && key != Self::WARNINGS_KEY;\n                        let is_not_backward_compatible =\n                            !BACKWARD_COMPATIBLE_KEYS.contains(&key.as_str());\n\n                        if is_not_deprecated\n                            && is_not_allowed\n                            && is_not_reserved\n                            && is_not_backward_compatible\n                        {\n                            out.push(Warning::UnknownKey {\n                                key: key.clone(),\n                                profile: profile.clone(),\n                                source: source.clone(),\n                            });\n                        }\n                    }\n\n                    // Add warning for unknown keys in nested sections within profiles.\n                    self.collect_nested_section_warnings(\n                        profile_dict,\n                        default_dict,\n                        &source,\n                        &mut out,\n                    );\n                }\n            }\n\n            // Add warning for unknown keys in standalone sections.\n            self.collect_standalone_section_warnings(&data, default_dict, &mut out);\n        }\n\n        Ok(out)\n    }\n\n    /// Collects warnings for unknown keys in standalone sections like `[lint]`, `[fmt]`, etc.\n    fn collect_standalone_section_warnings(\n        &self,\n        data: &Map<Profile, Dict>,\n        default_dict: &Dict,\n        out: &mut Vec<Warning>,\n    ) {\n        let source = self\n            .provider\n            .metadata()\n            .source\n            .map(|s| s.to_string())\n            .unwrap_or(Config::FILE_NAME.to_string());\n\n        for section_name in Config::STANDALONE_SECTIONS {\n            // Get the section from the parsed data\n            let section_profile = Profile::new(section_name);\n            let Some(section_dict) = data.get(&section_profile) else {\n                continue;\n            };\n\n            // Get allowed keys for this section from the default config\n            // Special case for vyper: VyperConfig uses skip_serializing_if on all Option fields,\n            // so the default serialization produces an empty dict. Use explicit keys instead.\n            let allowed_keys: BTreeSet<String> = if *section_name == \"vyper\" {\n                VYPER_KEYS.iter().map(|s| s.to_string()).collect()\n            } else if *section_name == \"doc\" {\n                DOC_KEYS.iter().map(|s| s.to_string()).collect()\n            } else {\n                let Some(default_section_value) = default_dict.get(*section_name) else {\n                    continue;\n                };\n                let Some(default_section_dict) = default_section_value.as_dict() else {\n                    continue;\n                };\n                default_section_dict.keys().cloned().collect()\n            };\n\n            for key in section_dict.keys() {\n                let is_not_allowed =\n                    !allowed_keys.contains(key) && !allowed_keys.contains(&key.to_snake_case());\n                if is_not_allowed {\n                    out.push(Warning::UnknownSectionKey {\n                        key: key.clone(),\n                        section: section_name.to_string(),\n                        source: source.clone(),\n                    });\n                }\n            }\n        }\n    }\n\n    /// Collects warnings for unknown keys in nested sections within profiles,\n    /// like `compilation_restrictions`.\n    fn collect_nested_section_warnings(\n        &self,\n        profile_dict: &Dict,\n        default_dict: &Dict,\n        source: &str,\n        out: &mut Vec<Warning>,\n    ) {\n        // Check nested sections that are dicts (like `lint`, `fmt` when defined in profile)\n        for (key, value) in profile_dict {\n            let Some(nested_dict) = value.as_dict() else {\n                // Also check arrays of dicts (like `compilation_restrictions`)\n                if let Some(arr) = value.as_array() {\n                    // Get allowed keys for known array item types\n                    let allowed_keys = Self::get_array_item_allowed_keys(key);\n\n                    if allowed_keys.is_empty() {\n                        continue;\n                    }\n\n                    for item in arr {\n                        let Some(item_dict) = item.as_dict() else {\n                            continue;\n                        };\n                        for item_key in item_dict.keys() {\n                            let is_not_allowed = !allowed_keys.contains(item_key)\n                                && !allowed_keys.contains(&item_key.to_snake_case());\n                            if is_not_allowed {\n                                out.push(Warning::UnknownSectionKey {\n                                    key: item_key.clone(),\n                                    section: key.clone(),\n                                    source: source.to_string(),\n                                });\n                            }\n                        }\n                    }\n                }\n                continue;\n            };\n\n            // Get allowed keys from the default config for this nested section\n            // Special case for vyper: VyperConfig uses skip_serializing_if on all Option fields,\n            // so the default serialization produces an empty dict. Use explicit keys instead.\n            let allowed_keys: BTreeSet<String> = if key == \"vyper\" {\n                VYPER_KEYS.iter().map(|s| s.to_string()).collect()\n            } else if key == \"doc\" {\n                DOC_KEYS.iter().map(|s| s.to_string()).collect()\n            } else {\n                let Some(default_value) = default_dict.get(key) else {\n                    continue;\n                };\n                let Some(default_nested_dict) = default_value.as_dict() else {\n                    continue;\n                };\n                default_nested_dict.keys().cloned().collect()\n            };\n\n            for nested_key in nested_dict.keys() {\n                let is_not_allowed = !allowed_keys.contains(nested_key)\n                    && !allowed_keys.contains(&nested_key.to_snake_case());\n                if is_not_allowed {\n                    out.push(Warning::UnknownSectionKey {\n                        key: nested_key.clone(),\n                        section: key.clone(),\n                        source: source.to_string(),\n                    });\n                }\n            }\n        }\n    }\n\n    /// Returns the allowed keys for array item types based on the section name.\n    fn get_array_item_allowed_keys(section_name: &str) -> BTreeSet<String> {\n        match section_name {\n            \"compilation_restrictions\" => {\n                COMPILATION_RESTRICTIONS_KEYS.iter().map(|s| s.to_string()).collect()\n            }\n            \"additional_compiler_profiles\" => {\n                SETTINGS_OVERRIDES_KEYS.iter().map(|s| s.to_string()).collect()\n            }\n            _ => BTreeSet::new(),\n        }\n    }\n}\n\nimpl<P: Provider> Provider for WarningsProvider<P> {\n    fn metadata(&self) -> Metadata {\n        if let Some(source) = self.provider.metadata().source {\n            Metadata::from(\"Warnings\", source)\n        } else {\n            Metadata::named(\"Warnings\")\n        }\n    }\n\n    fn data(&self) -> Result<Map<Profile, Dict>, Error> {\n        let warnings = self.collect_warnings()?;\n        Ok(Map::from([(\n            self.profile.clone(),\n            Dict::from([(Self::WARNINGS_KEY.to_string(), Value::serialize(warnings)?)]),\n        )]))\n    }\n\n    fn profile(&self) -> Option<Profile> {\n        Some(self.profile.clone())\n    }\n}\n"
  },
  {
    "path": "crates/config/src/resolve.rs",
    "content": "//! Helper for resolving env vars\n\nuse regex::Regex;\nuse std::{env, env::VarError, fmt, sync::LazyLock};\n\n/// A regex that matches `${val}` placeholders\npub static RE_PLACEHOLDER: LazyLock<Regex> =\n    LazyLock::new(|| Regex::new(r\"(?m)(?P<outer>\\$\\{\\s*(?P<inner>.*?)\\s*})\").unwrap());\n\n/// Error when we failed to resolve an env var\n#[derive(Clone, Debug, PartialEq, Eq)]\npub struct UnresolvedEnvVarError {\n    /// The unresolved input string\n    pub unresolved: String,\n    /// Var that couldn't be resolved\n    pub var: String,\n    /// the `env::var` error\n    pub source: VarError,\n}\n\nimpl UnresolvedEnvVarError {\n    /// Tries to resolve a value\n    pub fn try_resolve(&self) -> Result<String, Self> {\n        interpolate(&self.unresolved)\n    }\n\n    fn is_simple(&self) -> bool {\n        RE_PLACEHOLDER.captures_iter(&self.unresolved).count() <= 1\n    }\n}\n\nimpl fmt::Display for UnresolvedEnvVarError {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        write!(f, \"environment variable `{}` \", self.var)?;\n        f.write_str(match self.source {\n            VarError::NotPresent => \"not found\",\n            VarError::NotUnicode(_) => \"is not valid unicode\",\n        })?;\n        if !self.is_simple() {\n            write!(f, \" in `{}`\", self.unresolved)?;\n        }\n        Ok(())\n    }\n}\n\nimpl std::error::Error for UnresolvedEnvVarError {\n    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {\n        Some(&self.source)\n    }\n}\n\n/// Replaces all Env var placeholders in the input string with the values they hold\npub fn interpolate(input: &str) -> Result<String, UnresolvedEnvVarError> {\n    let mut res = input.to_string();\n\n    // loop over all placeholders in the input and replace them one by one\n    for caps in RE_PLACEHOLDER.captures_iter(input) {\n        let var = &caps[\"inner\"];\n        let value = env::var(var).map_err(|source| UnresolvedEnvVarError {\n            unresolved: input.to_string(),\n            var: var.to_string(),\n            source,\n        })?;\n\n        res = res.replacen(&caps[\"outer\"], &value, 1);\n    }\n    Ok(res)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn can_find_placeholder() {\n        let val = \"https://eth-mainnet.alchemyapi.io/v2/346273846238426342\";\n        assert!(!RE_PLACEHOLDER.is_match(val));\n\n        let val = \"${RPC_ENV}\";\n        assert!(RE_PLACEHOLDER.is_match(val));\n\n        let val = \"https://eth-mainnet.alchemyapi.io/v2/${API_KEY}\";\n        assert!(RE_PLACEHOLDER.is_match(val));\n\n        let cap = RE_PLACEHOLDER.captures(val).unwrap();\n        assert_eq!(cap.name(\"outer\").unwrap().as_str(), \"${API_KEY}\");\n        assert_eq!(cap.name(\"inner\").unwrap().as_str(), \"API_KEY\");\n    }\n}\n"
  },
  {
    "path": "crates/config/src/soldeer.rs",
    "content": "//! Configuration specific to the `forge soldeer` command and the `forge_soldeer` package\nuse serde::{Deserialize, Serialize};\npub use soldeer_core::config::SoldeerConfig;\nuse std::collections::BTreeMap;\n\n/// Soldeer dependencies config structure when it's defined as a map\n#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]\npub struct MapDependency {\n    /// The version of the dependency\n    pub version: String,\n\n    /// The url from where the dependency was retrieved\n    #[serde(default, skip_serializing_if = \"Option::is_none\")]\n    pub url: Option<String>,\n\n    /// The git URL for the source repo\n    #[serde(default, skip_serializing_if = \"Option::is_none\")]\n    pub git: Option<String>,\n\n    /// The commit in case git is used as dependency source\n    #[serde(default, skip_serializing_if = \"Option::is_none\")]\n    pub rev: Option<String>,\n\n    /// The branch in case git is used as dependency source\n    #[serde(default, skip_serializing_if = \"Option::is_none\")]\n    pub branch: Option<String>,\n\n    /// The git tag in case git is used as dependency source\n    #[serde(default, skip_serializing_if = \"Option::is_none\")]\n    pub tag: Option<String>,\n\n    /// An optional relative path to the project's root within the repository\n    #[serde(default, skip_serializing_if = \"Option::is_none\")]\n    pub project_root: Option<String>,\n}\n\n/// Type for Soldeer configs, under dependencies tag in the foundry.toml\n#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]\npub struct SoldeerDependencyConfig(pub BTreeMap<String, SoldeerDependencyValue>);\n\nimpl AsRef<Self> for SoldeerDependencyConfig {\n    fn as_ref(&self) -> &Self {\n        self\n    }\n}\n\n/// Enum to cover both available formats for defining a dependency\n/// `dep = { version = \"1.1\", url = \"https://my-dependency\" }`\n/// or\n/// `dep = \"1.1\"`\n#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]\n#[serde(untagged)]\npub enum SoldeerDependencyValue {\n    Map(MapDependency),\n    Str(String),\n}\n"
  },
  {
    "path": "crates/config/src/utils.rs",
    "content": "//! Utility functions\n\nuse crate::Config;\nuse alloy_primitives::U256;\nuse figment::value::Value;\nuse foundry_compilers::artifacts::{\n    EvmVersion,\n    remappings::{Remapping, RemappingError},\n};\nuse revm::primitives::hardfork::SpecId;\nuse serde::{Deserialize, Deserializer, Serializer, de::Error};\nuse std::{\n    io,\n    path::{Path, PathBuf},\n    str::FromStr,\n};\n\n// TODO: Why do these exist separately from `Config::load`?\n\n/// Loads the config for the current project workspace.\npub fn load_config() -> eyre::Result<Config> {\n    load_config_with_root(None)\n}\n\n/// Loads the config for the current project workspace or the provided root path.\npub fn load_config_with_root(root: Option<&Path>) -> eyre::Result<Config> {\n    let root = match root {\n        Some(root) => root,\n        None => &find_project_root(None)?,\n    };\n    Ok(Config::load_with_root(root)?.sanitized())\n}\n\n/// Returns the path of the top-level directory of the working git tree.\npub fn find_git_root(relative_to: &Path) -> io::Result<Option<PathBuf>> {\n    let root =\n        if relative_to.is_absolute() { relative_to } else { &dunce::canonicalize(relative_to)? };\n    Ok(root.ancestors().find(|p| p.join(\".git\").exists()).map(Path::to_path_buf))\n}\n\n/// Returns the root path to set for the project root.\n///\n/// Traverse the dir tree up and look for a `foundry.toml` file starting at the given path or cwd,\n/// but only until the root dir of the current repo so that:\n///\n/// ```text\n/// -- foundry.toml\n///\n/// -- repo\n///   |__ .git\n///   |__sub\n///      |__ [given_path | cwd]\n/// ```\n///\n/// will still detect `repo` as root.\n///\n/// Returns `repo` or `cwd` if no `foundry.toml` is found in the tree.\n///\n/// Returns an error if:\n/// - `cwd` is `Some` and is not a valid directory;\n/// - `cwd` is `None` and the [`std::env::current_dir`] call fails.\npub fn find_project_root(cwd: Option<&Path>) -> io::Result<PathBuf> {\n    let cwd = match cwd {\n        Some(path) => path,\n        None => &std::env::current_dir()?,\n    };\n    let boundary = find_git_root(cwd)?;\n    let found = cwd\n        .ancestors()\n        // Don't look outside of the git repo if it exists.\n        .take_while(|p| if let Some(boundary) = &boundary { p.starts_with(boundary) } else { true })\n        .find(|p| p.join(Config::FILE_NAME).is_file())\n        .map(Path::to_path_buf);\n    Ok(found.or(boundary).unwrap_or_else(|| cwd.to_path_buf()))\n}\n\n/// Returns all [`Remapping`]s contained in the `remappings` str separated by newlines\n///\n/// # Example\n///\n/// ```\n/// use foundry_config::remappings_from_newline;\n/// let remappings: Result<Vec<_>, _> = remappings_from_newline(\n///     r#\"\n///              file-ds-test/=lib/ds-test/\n///              file-other/=lib/other/\n///          \"#,\n/// )\n/// .collect();\n/// ```\npub fn remappings_from_newline(\n    remappings: &str,\n) -> impl Iterator<Item = Result<Remapping, RemappingError>> + '_ {\n    remappings.lines().map(|x| x.trim()).filter(|x| !x.is_empty()).map(Remapping::from_str)\n}\n\n/// Returns the remappings from the given var\n///\n/// Returns `None` if the env var is not set, otherwise all Remappings, See\n/// `remappings_from_newline`\npub fn remappings_from_env_var(env_var: &str) -> Option<Result<Vec<Remapping>, RemappingError>> {\n    let val = std::env::var(env_var).ok()?;\n    Some(remappings_from_newline(&val).collect())\n}\n\n/// Converts the `val` into a `figment::Value::Array`\n///\n/// The values should be separated by commas, surrounding brackets are also supported `[a,b,c]`\npub fn to_array_value(val: &str) -> Result<Value, figment::Error> {\n    let value: Value = match Value::from(val) {\n        Value::String(_, val) => val\n            .trim_start_matches('[')\n            .trim_end_matches(']')\n            .split(',')\n            .map(|s| s.to_string())\n            .collect::<Vec<_>>()\n            .into(),\n        Value::Empty(_, _) => Vec::<Value>::new().into(),\n        val @ Value::Array(_, _) => val,\n        _ => return Err(format!(\"Invalid value `{val}`, expected an array\").into()),\n    };\n    Ok(value)\n}\n\n/// Returns a list of _unique_ paths to all folders under `root` that contain a `foundry.toml` file\n///\n/// This will also resolve symlinks\n///\n/// # Example\n///\n/// ```no_run\n/// use foundry_config::utils;\n/// let dirs = utils::foundry_toml_dirs(\"./lib\");\n/// ```\n///\n/// for following layout this will return\n/// `[\"lib/dep1\", \"lib/dep2\"]`\n///\n/// ```text\n/// lib\n/// └── dep1\n/// │   ├── foundry.toml\n/// └── dep2\n///     ├── foundry.toml\n/// ```\npub fn foundry_toml_dirs(root: impl AsRef<Path>) -> Vec<PathBuf> {\n    walkdir::WalkDir::new(root)\n        .max_depth(1)\n        .into_iter()\n        .filter_map(Result::ok)\n        .filter(|e| e.file_type().is_dir())\n        .filter_map(|e| dunce::canonicalize(e.path()).ok())\n        .filter(|p| p.join(Config::FILE_NAME).exists())\n        .collect()\n}\n\n/// Returns a remapping for the given dir\npub(crate) fn get_dir_remapping(dir: impl AsRef<Path>) -> Option<Remapping> {\n    let dir = dir.as_ref();\n    if let Some(dir_name) = dir.file_name().and_then(|s| s.to_str()).filter(|s| !s.is_empty()) {\n        let mut r = Remapping {\n            context: None,\n            name: format!(\"{dir_name}/\"),\n            path: format!(\"{}\", dir.display()),\n        };\n        if !r.path.ends_with('/') {\n            r.path.push('/')\n        }\n        Some(r)\n    } else {\n        None\n    }\n}\n\n/// Deserialize stringified percent. The value must be between 0 and 100 inclusive.\npub(crate) fn deserialize_stringified_percent<'de, D>(deserializer: D) -> Result<u32, D::Error>\nwhere\n    D: Deserializer<'de>,\n{\n    let num: U256 = Numeric::deserialize(deserializer)?.into();\n    let num: u64 = num.try_into().map_err(serde::de::Error::custom)?;\n    if num <= 100 {\n        num.try_into().map_err(serde::de::Error::custom)\n    } else {\n        Err(serde::de::Error::custom(\"percent must be lte 100\"))\n    }\n}\n\n/// Deserialize a `u64` or \"max\" for `u64::MAX`.\npub(crate) fn deserialize_u64_or_max<'de, D>(deserializer: D) -> Result<u64, D::Error>\nwhere\n    D: Deserializer<'de>,\n{\n    #[derive(Deserialize)]\n    #[serde(untagged)]\n    enum Val {\n        Number(u64),\n        String(String),\n    }\n\n    match Val::deserialize(deserializer)? {\n        Val::Number(num) => Ok(num),\n        Val::String(s) if s.eq_ignore_ascii_case(\"max\") => Ok(u64::MAX),\n        Val::String(s) => s.parse::<u64>().map_err(D::Error::custom),\n    }\n}\n\n/// Deserialize a `usize` or \"max\" for `usize::MAX`.\npub(crate) fn deserialize_usize_or_max<'de, D>(deserializer: D) -> Result<usize, D::Error>\nwhere\n    D: Deserializer<'de>,\n{\n    deserialize_u64_or_max(deserializer)?.try_into().map_err(D::Error::custom)\n}\n\n/// Serialize a `usize` as `\"max\"` if it equals `usize::MAX`, as a string if it exceeds\n/// `i64::MAX` (TOML integer limit), or as a plain number otherwise.\npub(crate) fn serialize_usize_or_max<S>(value: &usize, serializer: S) -> Result<S::Ok, S::Error>\nwhere\n    S: Serializer,\n{\n    if *value == usize::MAX {\n        serializer.serialize_str(\"max\")\n    } else if *value > i64::MAX as usize {\n        serializer.serialize_str(&value.to_string())\n    } else {\n        serializer.serialize_u64(*value as u64)\n    }\n}\n\n/// Deserialize into `U256` from either a `u64`, a `U256` hex string, or a decimal string.\npub fn deserialize_u64_to_u256<'de, D>(deserializer: D) -> Result<U256, D::Error>\nwhere\n    D: Deserializer<'de>,\n{\n    #[derive(Deserialize)]\n    #[serde(untagged)]\n    enum NumericValue {\n        U256(U256),\n        U64(u64),\n        String(String),\n    }\n\n    match NumericValue::deserialize(deserializer)? {\n        NumericValue::U64(n) => Ok(U256::from(n)),\n        NumericValue::U256(n) => Ok(n),\n        NumericValue::String(s) => {\n            // Handle decimal strings (e.g., \"18446744073709551615\")\n            U256::from_str(&s).map_err(D::Error::custom)\n        }\n    }\n}\n\n/// Serialize `U256` as `u64` if it fits, otherwise as a hex string.\n/// If the number fits into a i64, serialize it as number without quotation marks.\n/// If the number fits into a u64, serialize it as a stringified number with quotation marks.\n/// Otherwise, serialize it as a hex string with quotation marks.\npub fn serialize_u64_or_u256<S>(n: &U256, serializer: S) -> Result<S::Ok, S::Error>\nwhere\n    S: Serializer,\n{\n    // The TOML specification handles integers as i64 so the number representation is limited to\n    // i64. If the number is larger than `i64::MAX` and up to `u64::MAX`, we serialize it as a\n    // string to avoid losing precision.\n    if let Ok(n_i64) = i64::try_from(*n) {\n        serializer.serialize_i64(n_i64)\n    } else if let Ok(n_u64) = u64::try_from(*n) {\n        serializer.serialize_str(&n_u64.to_string())\n    } else {\n        serializer.serialize_str(&format!(\"{n:#x}\"))\n    }\n}\n\n/// Helper type to parse both `u64` and `U256`\n#[derive(Clone, Copy, Deserialize)]\n#[serde(untagged)]\npub enum Numeric {\n    /// A [U256] value.\n    U256(U256),\n    /// A `u64` value.\n    Num(u64),\n}\n\nimpl From<Numeric> for U256 {\n    fn from(n: Numeric) -> Self {\n        match n {\n            Numeric::U256(n) => n,\n            Numeric::Num(n) => Self::from(n),\n        }\n    }\n}\n\nimpl FromStr for Numeric {\n    type Err = String;\n\n    fn from_str(s: &str) -> Result<Self, Self::Err> {\n        if s.starts_with(\"0x\") {\n            U256::from_str_radix(s, 16).map(Numeric::U256).map_err(|err| err.to_string())\n        } else {\n            U256::from_str(s).map(Numeric::U256).map_err(|err| err.to_string())\n        }\n    }\n}\n\n/// Returns the [SpecId] derived from [EvmVersion]\npub fn evm_spec_id(evm_version: EvmVersion) -> SpecId {\n    match evm_version {\n        EvmVersion::Homestead => SpecId::HOMESTEAD,\n        EvmVersion::TangerineWhistle => SpecId::TANGERINE,\n        EvmVersion::SpuriousDragon => SpecId::SPURIOUS_DRAGON,\n        EvmVersion::Byzantium => SpecId::BYZANTIUM,\n        EvmVersion::Constantinople => SpecId::CONSTANTINOPLE,\n        EvmVersion::Petersburg => SpecId::PETERSBURG,\n        EvmVersion::Istanbul => SpecId::ISTANBUL,\n        EvmVersion::Berlin => SpecId::BERLIN,\n        EvmVersion::London => SpecId::LONDON,\n        EvmVersion::Paris => SpecId::MERGE,\n        EvmVersion::Shanghai => SpecId::SHANGHAI,\n        EvmVersion::Cancun => SpecId::CANCUN,\n        EvmVersion::Prague => SpecId::PRAGUE,\n        EvmVersion::Osaka => SpecId::OSAKA,\n    }\n}\n"
  },
  {
    "path": "crates/config/src/vyper.rs",
    "content": "//! Vyper specific configuration types.\n\nuse foundry_compilers::artifacts::vyper::VyperOptimizationMode;\nuse serde::{Deserialize, Serialize};\nuse std::path::PathBuf;\n\n#[derive(Default, Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]\npub struct VyperConfig {\n    /// Vyper optimization mode. \"gas\", \"none\" or \"codesize\"\n    #[serde(default, skip_serializing_if = \"Option::is_none\")]\n    pub optimize: Option<VyperOptimizationMode>,\n    /// The Vyper instance to use if any.\n    #[serde(default, skip_serializing_if = \"Option::is_none\")]\n    pub path: Option<PathBuf>,\n    /// Optionally enables experimental Venom pipeline\n    #[serde(default, skip_serializing_if = \"Option::is_none\")]\n    pub experimental_codegen: Option<bool>,\n}\n"
  },
  {
    "path": "crates/config/src/warning.rs",
    "content": "use figment::Profile;\nuse serde::{Deserialize, Serialize};\nuse std::{fmt, path::PathBuf};\n\n/// Warnings emitted during loading or managing Configuration\n#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]\n#[serde(tag = \"type\")]\npub enum Warning {\n    /// An unknown section was encountered in a TOML file\n    UnknownSection {\n        /// The unknown key\n        unknown_section: Profile,\n        /// The source where the key was found\n        source: Option<String>,\n    },\n    /// No local TOML file found, with location tried\n    NoLocalToml(PathBuf),\n    /// Could not read TOML\n    CouldNotReadToml {\n        /// The path of the TOML file\n        path: PathBuf,\n        /// The error message that occurred\n        err: String,\n    },\n    /// Could not write TOML\n    CouldNotWriteToml {\n        /// The path of the TOML file\n        path: PathBuf,\n        /// The error message that occurred\n        err: String,\n    },\n    /// Invalid profile. Profile should be a table\n    CouldNotFixProfile {\n        /// The path of the TOML file\n        path: PathBuf,\n        /// The profile to be fixed\n        profile: String,\n        /// The error message that occurred\n        err: String,\n    },\n    /// Deprecated key.\n    DeprecatedKey {\n        /// The key being deprecated\n        old: String,\n        /// The new key replacing the deprecated one if not empty, otherwise, meaning the old one\n        /// is being removed completely without replacement\n        new: String,\n    },\n    /// An unknown key was encountered in a profile in a TOML file\n    UnknownKey {\n        /// The unknown key name\n        key: String,\n        /// The profile where the key was found, if applicable\n        profile: String,\n        /// The config file where the key was found\n        source: String,\n    },\n    /// An unknown key was encountered in a section in a TOML file\n    UnknownSectionKey {\n        /// The unknown key name\n        key: String,\n        /// The section where the key was found\n        section: String,\n        /// The config file where the key was found\n        source: String,\n    },\n}\n\nimpl fmt::Display for Warning {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        match self {\n            Self::UnknownSection { unknown_section, source } => {\n                let source = source.as_ref().map(|src| format!(\" in {src}\")).unwrap_or_default();\n                write!(\n                    f,\n                    \"Found unknown config section{source}: [{unknown_section}]\\n\\\n                     This notation for profiles has been deprecated and may result in the profile \\\n                     not being registered in future versions.\\n\\\n                     Please use [profile.{unknown_section}] instead or run `forge config --fix`.\"\n                )\n            }\n            Self::NoLocalToml(path) => write!(\n                f,\n                \"No local TOML found to fix at {}.\\n\\\n                 Change the current directory to a project path or set the foundry.toml path with \\\n                 the `FOUNDRY_CONFIG` environment variable\",\n                path.display()\n            ),\n\n            Self::CouldNotReadToml { path, err } => {\n                write!(f, \"Could not read TOML at {}: {err}\", path.display())\n            }\n            Self::CouldNotWriteToml { path, err } => {\n                write!(f, \"Could not write TOML to {}: {err}\", path.display())\n            }\n            Self::CouldNotFixProfile { path, profile, err } => {\n                write!(f, \"Could not fix [{profile}] in TOML at {}: {err}\", path.display())\n            }\n            Self::DeprecatedKey { old, new } if new.is_empty() => {\n                write!(f, \"Key `{old}` is being deprecated and will be removed in future versions.\")\n            }\n            Self::DeprecatedKey { old, new } => {\n                write!(\n                    f,\n                    \"Key `{old}` is being deprecated in favor of `{new}`. It will be removed in future versions.\"\n                )\n            }\n            Self::UnknownKey { key, profile, source } => {\n                write!(\n                    f,\n                    \"Found unknown `{key}` config for profile `{profile}` defined in {source}.\"\n                )\n            }\n            Self::UnknownSectionKey { key, section, source } => {\n                write!(\n                    f,\n                    \"Found unknown `{key}` config key in section `{section}` defined in {source}.\"\n                )\n            }\n        }\n    }\n}\n\nimpl std::error::Error for Warning {}\n"
  },
  {
    "path": "crates/debugger/Cargo.toml",
    "content": "[package]\nname = \"foundry-debugger\"\n\nversion.workspace = true\nedition.workspace = true\nrust-version.workspace = true\nauthors.workspace = true\nlicense.workspace = true\nhomepage.workspace = true\nrepository.workspace = true\n\n[lints]\nworkspace = true\n\n[dependencies]\nfoundry-common.workspace = true\nfoundry-compilers.workspace = true\nfoundry-evm-traces.workspace = true\nfoundry-evm-core.workspace = true\nrevm-inspectors.workspace = true\n\nalloy-primitives.workspace = true\n\ncrossterm = \"0.29\"\neyre.workspace = true\nratatui = { version = \"0.30\", default-features = false, features = [\n    \"crossterm\",\n] }\nrevm.workspace = true\ntracing.workspace = true\nserde.workspace = true\n"
  },
  {
    "path": "crates/debugger/src/builder.rs",
    "content": "//! Debugger builder.\n\nuse crate::{DebugNode, Debugger, node::flatten_call_trace};\nuse alloy_primitives::{Address, map::AddressHashMap};\nuse foundry_common::get_contract_name;\nuse foundry_evm_core::Breakpoints;\nuse foundry_evm_traces::{CallTraceArena, CallTraceDecoder, Traces, debug::ContractSources};\n\n/// Debugger builder.\n#[derive(Debug, Default)]\n#[must_use = \"builders do nothing unless you call `build` on them\"]\npub struct DebuggerBuilder {\n    /// Debug traces returned from the EVM execution.\n    debug_arena: Vec<DebugNode>,\n    /// Identified contracts.\n    identified_contracts: AddressHashMap<String>,\n    /// Map of source files.\n    sources: ContractSources,\n    /// Map of the debugger breakpoints.\n    breakpoints: Breakpoints,\n}\n\nimpl DebuggerBuilder {\n    /// Creates a new debugger builder.\n    #[inline]\n    pub fn new() -> Self {\n        Self::default()\n    }\n\n    /// Extends the debug arena.\n    #[inline]\n    pub fn traces(mut self, traces: Traces) -> Self {\n        for (_, arena) in traces {\n            self = self.trace_arena(arena.arena);\n        }\n        self\n    }\n\n    /// Extends the debug arena.\n    #[inline]\n    pub fn trace_arena(mut self, arena: CallTraceArena) -> Self {\n        flatten_call_trace(arena, &mut self.debug_arena);\n        self\n    }\n\n    /// Extends the identified contracts from multiple decoders.\n    #[inline]\n    pub fn decoders(mut self, decoders: &[CallTraceDecoder]) -> Self {\n        for decoder in decoders {\n            self = self.decoder(decoder);\n        }\n        self\n    }\n\n    /// Extends the identified contracts from a decoder.\n    #[inline]\n    pub fn decoder(self, decoder: &CallTraceDecoder) -> Self {\n        let c = decoder.contracts.iter().map(|(k, v)| (*k, get_contract_name(v).to_string()));\n        self.identified_contracts(c)\n    }\n\n    /// Extends the identified contracts.\n    #[inline]\n    pub fn identified_contracts(\n        mut self,\n        identified_contracts: impl IntoIterator<Item = (Address, String)>,\n    ) -> Self {\n        self.identified_contracts.extend(identified_contracts);\n        self\n    }\n\n    /// Sets the sources for the debugger.\n    #[inline]\n    pub fn sources(mut self, sources: ContractSources) -> Self {\n        self.sources = sources;\n        self\n    }\n\n    /// Sets the breakpoints for the debugger.\n    #[inline]\n    pub fn breakpoints(mut self, breakpoints: Breakpoints) -> Self {\n        self.breakpoints = breakpoints;\n        self\n    }\n\n    /// Builds the debugger.\n    #[inline]\n    pub fn build(self) -> Debugger {\n        let Self { debug_arena, identified_contracts, sources, breakpoints } = self;\n        Debugger::new(debug_arena, identified_contracts, sources, breakpoints)\n    }\n}\n"
  },
  {
    "path": "crates/debugger/src/debugger.rs",
    "content": "//! Debugger implementation.\n\nuse crate::{DebugNode, DebuggerBuilder, ExitReason, tui::TUI};\nuse alloy_primitives::map::AddressHashMap;\nuse eyre::Result;\nuse foundry_evm_core::Breakpoints;\nuse foundry_evm_traces::debug::ContractSources;\nuse std::path::Path;\n\npub struct DebuggerContext {\n    pub debug_arena: Vec<DebugNode>,\n    pub identified_contracts: AddressHashMap<String>,\n    /// Source map of contract sources\n    pub contracts_sources: ContractSources,\n    pub breakpoints: Breakpoints,\n}\n\npub struct Debugger {\n    context: DebuggerContext,\n}\n\nimpl Debugger {\n    /// Creates a new debugger builder.\n    #[inline]\n    pub fn builder() -> DebuggerBuilder {\n        DebuggerBuilder::new()\n    }\n\n    /// Creates a new debugger.\n    pub fn new(\n        debug_arena: Vec<DebugNode>,\n        identified_contracts: AddressHashMap<String>,\n        contracts_sources: ContractSources,\n        breakpoints: Breakpoints,\n    ) -> Self {\n        Self {\n            context: DebuggerContext {\n                debug_arena,\n                identified_contracts,\n                contracts_sources,\n                breakpoints,\n            },\n        }\n    }\n\n    /// Starts the debugger TUI. Terminates the current process on failure or user exit.\n    pub fn run_tui_exit(mut self) -> ! {\n        let code = match self.try_run_tui() {\n            Ok(ExitReason::CharExit) => 0,\n            Err(e) => {\n                let _ = sh_eprintln!(\"{e}\");\n                1\n            }\n        };\n        std::process::exit(code)\n    }\n\n    /// Starts the debugger TUI.\n    pub fn try_run_tui(&mut self) -> Result<ExitReason> {\n        eyre::ensure!(!self.context.debug_arena.is_empty(), \"debug arena is empty\");\n\n        let mut tui = TUI::new(&mut self.context);\n        tui.try_run()\n    }\n\n    /// Dumps debugger data to file.\n    pub fn dump_to_file(&mut self, path: &Path) -> Result<()> {\n        eyre::ensure!(!self.context.debug_arena.is_empty(), \"debug arena is empty\");\n        crate::dump::dump(path, &self.context)\n    }\n}\n"
  },
  {
    "path": "crates/debugger/src/dump.rs",
    "content": "use crate::{DebugNode, debugger::DebuggerContext};\nuse alloy_primitives::map::AddressMap;\nuse foundry_common::fs::write_json_file;\nuse foundry_compilers::{\n    artifacts::sourcemap::{Jump, SourceElement},\n    multi::MultiCompilerLanguage,\n};\nuse foundry_evm_core::ic::PcIcMap;\nuse foundry_evm_traces::debug::{ArtifactData, ContractSources, SourceData};\nuse serde::Serialize;\nuse std::{collections::HashMap, path::Path};\n\n/// Dumps debugger data to a JSON file.\npub(crate) fn dump(path: &Path, context: &DebuggerContext) -> eyre::Result<()> {\n    write_json_file(path, &DebuggerDump::new(context))?;\n    Ok(())\n}\n\n/// Holds info of debugger dump.\n#[derive(Serialize)]\nstruct DebuggerDump<'a> {\n    contracts: ContractsDump<'a>,\n    debug_arena: &'a [DebugNode],\n}\n\nimpl<'a> DebuggerDump<'a> {\n    fn new(debugger_context: &'a DebuggerContext) -> Self {\n        Self {\n            contracts: ContractsDump::new(debugger_context),\n            debug_arena: &debugger_context.debug_arena,\n        }\n    }\n}\n\n#[derive(Serialize)]\nstruct SourceElementDump {\n    offset: u32,\n    length: u32,\n    index: i32,\n    jump: u32,\n    modifier_depth: u32,\n}\n\nimpl SourceElementDump {\n    fn new(v: &SourceElement) -> Self {\n        Self {\n            offset: v.offset(),\n            length: v.length(),\n            index: v.index_i32(),\n            jump: match v.jump() {\n                Jump::In => 0,\n                Jump::Out => 1,\n                Jump::Regular => 2,\n            },\n            modifier_depth: v.modifier_depth(),\n        }\n    }\n}\n\n#[derive(Serialize)]\nstruct ContractsDump<'a> {\n    identified_contracts: &'a AddressMap<String>,\n    sources: ContractsSourcesDump<'a>,\n}\n\nimpl<'a> ContractsDump<'a> {\n    fn new(debugger_context: &'a DebuggerContext) -> Self {\n        Self {\n            identified_contracts: &debugger_context.identified_contracts,\n            sources: ContractsSourcesDump::new(&debugger_context.contracts_sources),\n        }\n    }\n}\n\n#[derive(Serialize)]\nstruct ContractsSourcesDump<'a> {\n    sources_by_id: HashMap<&'a str, HashMap<u32, SourceDataDump<'a>>>,\n    artifacts_by_name: HashMap<&'a str, Vec<ArtifactDataDump<'a>>>,\n}\n\nimpl<'a> ContractsSourcesDump<'a> {\n    fn new(contracts_sources: &'a ContractSources) -> Self {\n        Self {\n            sources_by_id: contracts_sources\n                .sources_by_id\n                .iter()\n                .map(|(name, inner_map)| {\n                    (\n                        name.as_str(),\n                        inner_map\n                            .iter()\n                            .map(|(id, source_data)| (*id, SourceDataDump::new(source_data)))\n                            .collect(),\n                    )\n                })\n                .collect(),\n            artifacts_by_name: contracts_sources\n                .artifacts_by_name\n                .iter()\n                .map(|(name, data)| {\n                    (name.as_str(), data.iter().map(ArtifactDataDump::new).collect())\n                })\n                .collect(),\n        }\n    }\n}\n\n#[derive(Serialize)]\nstruct SourceDataDump<'a> {\n    source: &'a str,\n    language: MultiCompilerLanguage,\n    path: &'a Path,\n}\n\nimpl<'a> SourceDataDump<'a> {\n    fn new(v: &'a SourceData) -> Self {\n        Self { source: &v.source, language: v.language, path: &v.path }\n    }\n}\n\n#[derive(Serialize)]\nstruct ArtifactDataDump<'a> {\n    source_map: Option<Vec<SourceElementDump>>,\n    source_map_runtime: Option<Vec<SourceElementDump>>,\n    pc_ic_map: Option<&'a PcIcMap>,\n    pc_ic_map_runtime: Option<&'a PcIcMap>,\n    build_id: &'a str,\n    file_id: u32,\n}\n\nimpl<'a> ArtifactDataDump<'a> {\n    fn new(v: &'a ArtifactData) -> Self {\n        Self {\n            source_map: v\n                .source_map\n                .as_ref()\n                .map(|source_map| source_map.iter().map(SourceElementDump::new).collect()),\n            source_map_runtime: v\n                .source_map_runtime\n                .as_ref()\n                .map(|source_map| source_map.iter().map(SourceElementDump::new).collect()),\n            pc_ic_map: v.pc_ic_map.as_ref(),\n            pc_ic_map_runtime: v.pc_ic_map_runtime.as_ref(),\n            build_id: &v.build_id,\n            file_id: v.file_id,\n        }\n    }\n}\n"
  },
  {
    "path": "crates/debugger/src/lib.rs",
    "content": "//! # foundry-debugger\n//!\n//! Interactive Solidity TUI debugger and debugger data file dumper\n\n#![cfg_attr(not(test), warn(unused_crate_dependencies))]\n#![cfg_attr(docsrs, feature(doc_cfg))]\n\n#[macro_use]\nextern crate foundry_common;\n\n#[macro_use]\nextern crate tracing;\n\nmod op;\n\nmod builder;\nmod debugger;\nmod dump;\nmod tui;\n\nmod node;\n\npub use node::DebugNode;\n\npub use builder::DebuggerBuilder;\npub use debugger::Debugger;\npub use tui::{ExitReason, TUI};\n"
  },
  {
    "path": "crates/debugger/src/node.rs",
    "content": "use alloy_primitives::{Address, Bytes};\nuse foundry_evm_traces::{CallKind, CallTraceArena};\nuse revm_inspectors::tracing::types::{CallTraceStep, TraceMemberOrder};\nuse serde::{Deserialize, Serialize};\n\n/// Represents a part of the execution frame before the next call or end of the execution.\n#[derive(Clone, Debug, Default, Serialize, Deserialize)]\npub struct DebugNode {\n    /// Execution context.\n    ///\n    /// Note that this is the address of the *code*, not necessarily the address of the storage.\n    pub address: Address,\n    /// The kind of call this is.\n    pub kind: CallKind,\n    /// Calldata of the call.\n    pub calldata: Bytes,\n    /// The gas limit of the call.\n    pub gas_limit: u64,\n    /// The debug steps.\n    pub steps: Vec<CallTraceStep>,\n}\n\nimpl DebugNode {\n    /// Creates a new debug node.\n    pub fn new(\n        address: Address,\n        kind: CallKind,\n        steps: Vec<CallTraceStep>,\n        calldata: Bytes,\n        gas_limit: u64,\n    ) -> Self {\n        Self { address, kind, steps, calldata, gas_limit }\n    }\n}\n\n/// Flattens given [CallTraceArena] into a list of [DebugNode]s.\n///\n/// This is done by recursively traversing the call tree and collecting the steps in-between the\n/// calls.\npub fn flatten_call_trace(arena: CallTraceArena, out: &mut Vec<DebugNode>) {\n    #[derive(Debug, Clone, Copy)]\n    struct PendingNode {\n        node_idx: usize,\n        steps_count: usize,\n    }\n\n    fn inner(arena: &CallTraceArena, node_idx: usize, out: &mut Vec<PendingNode>) {\n        let mut pending = PendingNode { node_idx, steps_count: 0 };\n        let node = &arena.nodes()[node_idx];\n        for order in &node.ordering {\n            match order {\n                TraceMemberOrder::Call(idx) => {\n                    out.push(pending);\n                    pending.steps_count = 0;\n                    inner(arena, node.children[*idx], out);\n                }\n                TraceMemberOrder::Step(_) => {\n                    pending.steps_count += 1;\n                }\n                _ => {}\n            }\n        }\n        out.push(pending);\n    }\n    let mut nodes = Vec::new();\n    inner(&arena, 0, &mut nodes);\n\n    let mut arena_nodes = arena.into_nodes();\n\n    for pending in nodes {\n        let steps = {\n            let other_steps =\n                arena_nodes[pending.node_idx].trace.steps.split_off(pending.steps_count);\n            std::mem::replace(&mut arena_nodes[pending.node_idx].trace.steps, other_steps)\n        };\n\n        // Skip nodes with empty steps as there's nothing to display for them.\n        if steps.is_empty() {\n            continue;\n        }\n\n        let call = &arena_nodes[pending.node_idx].trace;\n        let calldata = if call.kind.is_any_create() { Bytes::new() } else { call.data.clone() };\n        let node = DebugNode::new(call.address, call.kind, steps, calldata, call.gas_limit);\n\n        out.push(node);\n    }\n}\n"
  },
  {
    "path": "crates/debugger/src/op.rs",
    "content": "/// Named parameter of an EVM opcode.\n#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]\npub(crate) struct OpcodeParam {\n    /// The name of the parameter.\n    pub(crate) name: &'static str,\n    /// The index of the parameter on the stack. This is relative to the top of the stack.\n    pub(crate) index: usize,\n}\n\nimpl OpcodeParam {\n    /// Returns the list of named parameters for the given opcode, accounts for special opcodes\n    /// requiring immediate bytes to determine stack items.\n    #[inline]\n    pub(crate) fn of(op: u8) -> &'static [Self] {\n        MAP[op as usize]\n    }\n}\n\nstatic MAP: [&[OpcodeParam]; 256] = {\n    let mut table = [[].as_slice(); 256];\n    let mut i = 0;\n    while i < 256 {\n        table[i] = map_opcode(i as u8);\n        i += 1;\n    }\n    table\n};\n\nconst fn map_opcode(op: u8) -> &'static [OpcodeParam] {\n    macro_rules! map {\n        ($($op:literal($($idx:literal : $name:literal),* $(,)?)),* $(,)?) => {\n            match op {\n                $($op => &[\n                    $(OpcodeParam {\n                        name: $name,\n                        index: $idx,\n                    }),*\n                ]),*\n            }\n        };\n    }\n\n    // https://www.evm.codes\n    // https://raw.githubusercontent.com/duneanalytics/evm.codes/refs/heads/main/opcodes.json\n    //\n    // jq -r '\n    //   def mkargs(input):\n    //     input\n    //     | split(\" | \")\n    //     | to_entries\n    //     | map(\"\\(.key): \\\"\\(.value)\\\"\")\n    //     | join(\", \");\n    //   to_entries[]\n    //   | \"0x\\(.key)(\\(mkargs(.value.input))),\"\n    // ' opcodes.json\n    //\n    // NOTE: the labels generated for `DUPN` and `SWAPN` have incorrect indices and have been\n    // manually adjusted in the `map!` macro below.\n    map! {\n        0x00(),\n        0x01(0: \"a\", 1: \"b\"),\n        0x02(0: \"a\", 1: \"b\"),\n        0x03(0: \"a\", 1: \"b\"),\n        0x04(0: \"a\", 1: \"b\"),\n        0x05(0: \"a\", 1: \"b\"),\n        0x06(0: \"a\", 1: \"b\"),\n        0x07(0: \"a\", 1: \"b\"),\n        0x08(0: \"a\", 1: \"b\", 2: \"N\"),\n        0x09(0: \"a\", 1: \"b\", 2: \"N\"),\n        0x0a(0: \"a\", 1: \"exponent\"),\n        0x0b(0: \"b\", 1: \"x\"),\n        0x0c(),\n        0x0d(),\n        0x0e(),\n        0x0f(),\n        0x10(0: \"a\", 1: \"b\"),\n        0x11(0: \"a\", 1: \"b\"),\n        0x12(0: \"a\", 1: \"b\"),\n        0x13(0: \"a\", 1: \"b\"),\n        0x14(0: \"a\", 1: \"b\"),\n        0x15(0: \"a\"),\n        0x16(0: \"a\", 1: \"b\"),\n        0x17(0: \"a\", 1: \"b\"),\n        0x18(0: \"a\", 1: \"b\"),\n        0x19(0: \"a\"),\n        0x1a(0: \"i\", 1: \"x\"),\n        0x1b(0: \"shift\", 1: \"value\"),\n        0x1c(0: \"shift\", 1: \"value\"),\n        0x1d(0: \"shift\", 1: \"value\"),\n        0x1e(),\n        0x1f(),\n        0x20(0: \"offset\", 1: \"size\"),\n        0x21(),\n        0x22(),\n        0x23(),\n        0x24(),\n        0x25(),\n        0x26(),\n        0x27(),\n        0x28(),\n        0x29(),\n        0x2a(),\n        0x2b(),\n        0x2c(),\n        0x2d(),\n        0x2e(),\n        0x2f(),\n        0x30(),\n        0x31(0: \"address\"),\n        0x32(),\n        0x33(),\n        0x34(),\n        0x35(0: \"i\"),\n        0x36(),\n        0x37(0: \"destOffset\", 1: \"offset\", 2: \"size\"),\n        0x38(),\n        0x39(0: \"destOffset\", 1: \"offset\", 2: \"size\"),\n        0x3a(),\n        0x3b(0: \"address\"),\n        0x3c(0: \"address\", 1: \"destOffset\", 2: \"offset\", 3: \"size\"),\n        0x3d(),\n        0x3e(0: \"destOffset\", 1: \"offset\", 2: \"size\"),\n        0x3f(0: \"address\"),\n        0x40(0: \"blockNumber\"),\n        0x41(),\n        0x42(),\n        0x43(),\n        0x44(),\n        0x45(),\n        0x46(),\n        0x47(),\n        0x48(),\n        0x49(0: \"index\"),\n        0x4a(),\n        0x4b(),\n        0x4c(),\n        0x4d(),\n        0x4e(),\n        0x4f(),\n        0x50(0: \"y\"),\n        0x51(0: \"offset\"),\n        0x52(0: \"offset\", 1: \"value\"),\n        0x53(0: \"offset\", 1: \"value\"),\n        0x54(0: \"key\"),\n        0x55(0: \"key\", 1: \"value\"),\n        0x56(0: \"counter\"),\n        0x57(0: \"counter\", 1: \"b\"),\n        0x58(),\n        0x59(),\n        0x5a(),\n        0x5b(),\n        0x5c(0: \"key\"),\n        0x5d(0: \"key\", 1: \"value\"),\n        0x5e(0: \"destOffset\", 1: \"offset\", 2: \"size\"),\n        0x5f(),\n        0x60(),\n        0x61(),\n        0x62(),\n        0x63(),\n        0x64(),\n        0x65(),\n        0x66(),\n        0x67(),\n        0x68(),\n        0x69(),\n        0x6a(),\n        0x6b(),\n        0x6c(),\n        0x6d(),\n        0x6e(),\n        0x6f(),\n        0x70(),\n        0x71(),\n        0x72(),\n        0x73(),\n        0x74(),\n        0x75(),\n        0x76(),\n        0x77(),\n        0x78(),\n        0x79(),\n        0x7a(),\n        0x7b(),\n        0x7c(),\n        0x7d(),\n        0x7e(),\n        0x7f(),\n\n        // DUPN\n        0x80(0x00: \"dup_value\"),\n        0x81(0x01: \"dup_value\"),\n        0x82(0x02: \"dup_value\"),\n        0x83(0x03: \"dup_value\"),\n        0x84(0x04: \"dup_value\"),\n        0x85(0x05: \"dup_value\"),\n        0x86(0x06: \"dup_value\"),\n        0x87(0x07: \"dup_value\"),\n        0x88(0x08: \"dup_value\"),\n        0x89(0x09: \"dup_value\"),\n        0x8a(0x0a: \"dup_value\"),\n        0x8b(0x0b: \"dup_value\"),\n        0x8c(0x0c: \"dup_value\"),\n        0x8d(0x0d: \"dup_value\"),\n        0x8e(0x0e: \"dup_value\"),\n        0x8f(0x0f: \"dup_value\"),\n\n        // SWAPN\n        0x90(0: \"a\", 0x01: \"swap_value\"),\n        0x91(0: \"a\", 0x02: \"swap_value\"),\n        0x92(0: \"a\", 0x03: \"swap_value\"),\n        0x93(0: \"a\", 0x04: \"swap_value\"),\n        0x94(0: \"a\", 0x05: \"swap_value\"),\n        0x95(0: \"a\", 0x06: \"swap_value\"),\n        0x96(0: \"a\", 0x07: \"swap_value\"),\n        0x97(0: \"a\", 0x08: \"swap_value\"),\n        0x98(0: \"a\", 0x09: \"swap_value\"),\n        0x99(0: \"a\", 0x0a: \"swap_value\"),\n        0x9a(0: \"a\", 0x0b: \"swap_value\"),\n        0x9b(0: \"a\", 0x0c: \"swap_value\"),\n        0x9c(0: \"a\", 0x0d: \"swap_value\"),\n        0x9d(0: \"a\", 0x0e: \"swap_value\"),\n        0x9e(0: \"a\", 0x0f: \"swap_value\"),\n        0x9f(0: \"a\", 0x10: \"swap_value\"),\n\n        0xa0(0: \"offset\", 1: \"size\"),\n        0xa1(0: \"offset\", 1: \"size\", 2: \"topic\"),\n        0xa2(0: \"offset\", 1: \"size\", 2: \"topic1\", 3: \"topic2\"),\n        0xa3(0: \"offset\", 1: \"size\", 2: \"topic1\", 3: \"topic2\", 4: \"topic3\"),\n        0xa4(0: \"offset\", 1: \"size\", 2: \"topic1\", 3: \"topic2\", 4: \"topic3\", 5: \"topic4\"),\n        0xa5(),\n        0xa6(),\n        0xa7(),\n        0xa8(),\n        0xa9(),\n        0xaa(),\n        0xab(),\n        0xac(),\n        0xad(),\n        0xae(),\n        0xaf(),\n        0xb0(),\n        0xb1(),\n        0xb2(),\n        0xb3(),\n        0xb4(),\n        0xb5(),\n        0xb6(),\n        0xb7(),\n        0xb8(),\n        0xb9(),\n        0xba(),\n        0xbb(),\n        0xbc(),\n        0xbd(),\n        0xbe(),\n        0xbf(),\n        0xc0(),\n        0xc1(),\n        0xc2(),\n        0xc3(),\n        0xc4(),\n        0xc5(),\n        0xc6(),\n        0xc7(),\n        0xc8(),\n        0xc9(),\n        0xca(),\n        0xcb(),\n        0xcc(),\n        0xcd(),\n        0xce(),\n        0xcf(),\n        0xd0(0: \"offset\"),\n        0xd1(),\n        0xd2(),\n        0xd3(0: \"mem_offset\", 1: \"offset\", 2: \"size\"),\n        0xd4(),\n        0xd5(),\n        0xd6(),\n        0xd7(),\n        0xd8(),\n        0xd9(),\n        0xda(),\n        0xdb(),\n        0xdc(),\n        0xdd(),\n        0xde(),\n        0xdf(),\n        0xe0(),\n        0xe1(0: \"condition\"),\n        0xe2(0: \"case\"),\n        0xe3(),\n        0xe4(),\n        0xe5(),\n        0xe6(),\n        0xe7(),\n        0xe8(),\n        0xe9(),\n        0xea(),\n        0xeb(),\n        0xec(0: \"value\", 1: \"salt\", 2: \"input_offset\", 3: \"input_size\"),\n        0xed(),\n        0xee(0: \"aux_data_offset\", 1: \"aux_data_size\"),\n        0xef(),\n        0xf0(0: \"value\", 1: \"offset\", 2: \"size\"),\n        0xf1(0: \"gas\", 1: \"address\", 2: \"value\", 3: \"argsOffset\", 4: \"argsSize\", 5: \"retOffset\", 6: \"retSize\"),\n        0xf2(0: \"gas\", 1: \"address\", 2: \"value\", 3: \"argsOffset\", 4: \"argsSize\", 5: \"retOffset\", 6: \"retSize\"),\n        0xf3(0: \"offset\", 1: \"size\"),\n        0xf4(0: \"gas\", 1: \"address\", 2: \"argsOffset\", 3: \"argsSize\", 4: \"retOffset\", 5: \"retSize\"),\n        0xf5(0: \"value\", 1: \"offset\", 2: \"size\", 3: \"salt\"),\n        0xf6(),\n        0xf7(0: \"offset\"),\n        0xf8(0: \"target_address\", 1: \"input_offset\", 2: \"input_size\", 3: \"value\"),\n        0xf9(0: \"target_address\", 1: \"input_offset\", 2: \"input_size\"),\n        0xfa(0: \"gas\", 1: \"address\", 2: \"argsOffset\", 3: \"argsSize\", 4: \"retOffset\", 5: \"retSize\"),\n        0xfb(0: \"target_address\", 1: \"input_offset\", 2: \"input_size\"),\n        0xfc(),\n        0xfd(0: \"offset\", 1: \"size\"),\n        0xfe(),\n        0xff(0: \"address\"),\n    }\n}\n"
  },
  {
    "path": "crates/debugger/src/tui/context.rs",
    "content": "//! Debugger context and event handler implementation.\n\nuse crate::{DebugNode, ExitReason, debugger::DebuggerContext};\nuse alloy_primitives::{Address, hex};\nuse crossterm::event::{Event, KeyCode, KeyEvent, KeyModifiers, MouseEvent, MouseEventKind};\nuse foundry_evm_core::buffer::BufferKind;\nuse revm::bytecode::opcode::OpCode;\nuse revm_inspectors::tracing::types::{CallKind, CallTraceStep};\nuse std::ops::ControlFlow;\n\n/// This is currently used to remember last scroll position so screen doesn't wiggle as much.\n#[derive(Default)]\npub(crate) struct DrawMemory {\n    pub(crate) inner_call_index: usize,\n    pub(crate) current_buf_startline: usize,\n    pub(crate) current_stack_startline: usize,\n}\n\npub(crate) struct TUIContext<'a> {\n    pub(crate) debugger_context: &'a mut DebuggerContext,\n\n    /// Buffer for keys prior to execution, i.e. '10' + 'k' => move up 10 operations.\n    pub(crate) key_buffer: String,\n    /// Current step in the debug steps.\n    pub(crate) current_step: usize,\n    pub(crate) draw_memory: DrawMemory,\n    pub(crate) opcode_list: Vec<String>,\n    pub(crate) last_index: usize,\n\n    pub(crate) stack_labels: bool,\n    /// Whether to decode active buffer as utf8 or not.\n    pub(crate) buf_utf: bool,\n    pub(crate) show_shortcuts: bool,\n    /// The currently active buffer (memory, calldata, returndata) to be drawn.\n    pub(crate) active_buffer: BufferKind,\n}\n\nimpl<'a> TUIContext<'a> {\n    pub(crate) fn new(debugger_context: &'a mut DebuggerContext) -> Self {\n        TUIContext {\n            debugger_context,\n\n            key_buffer: String::with_capacity(64),\n            current_step: 0,\n            draw_memory: DrawMemory::default(),\n            opcode_list: Vec::new(),\n            last_index: 0,\n\n            stack_labels: false,\n            buf_utf: false,\n            show_shortcuts: true,\n            active_buffer: BufferKind::Memory,\n        }\n    }\n\n    pub(crate) fn init(&mut self) {\n        self.gen_opcode_list();\n    }\n\n    pub(crate) fn debug_arena(&self) -> &[DebugNode] {\n        &self.debugger_context.debug_arena\n    }\n\n    pub(crate) fn debug_call(&self) -> &DebugNode {\n        &self.debug_arena()[self.draw_memory.inner_call_index]\n    }\n\n    /// Returns the current call address.\n    pub(crate) fn address(&self) -> &Address {\n        &self.debug_call().address\n    }\n\n    /// Returns the current call kind.\n    pub(crate) fn call_kind(&self) -> CallKind {\n        self.debug_call().kind\n    }\n\n    /// Returns the current debug steps.\n    pub(crate) fn debug_steps(&self) -> &[CallTraceStep] {\n        &self.debug_call().steps\n    }\n\n    /// Returns the current debug step.\n    pub(crate) fn current_step(&self) -> &CallTraceStep {\n        &self.debug_steps()[self.current_step]\n    }\n\n    fn gen_opcode_list(&mut self) {\n        self.opcode_list.clear();\n        let debug_steps =\n            &self.debugger_context.debug_arena[self.draw_memory.inner_call_index].steps;\n        for step in debug_steps {\n            self.opcode_list.push(pretty_opcode(step));\n        }\n    }\n\n    fn gen_opcode_list_if_necessary(&mut self) {\n        if self.last_index != self.draw_memory.inner_call_index {\n            self.gen_opcode_list();\n            self.last_index = self.draw_memory.inner_call_index;\n        }\n    }\n\n    fn active_buffer(&self) -> &[u8] {\n        match self.active_buffer {\n            BufferKind::Memory => self.current_step().memory.as_ref().unwrap().as_bytes(),\n            BufferKind::Calldata => &self.debug_call().calldata,\n            BufferKind::Returndata => &self.current_step().returndata,\n        }\n    }\n}\n\nimpl TUIContext<'_> {\n    pub(crate) fn handle_event(&mut self, event: Event) -> ControlFlow<ExitReason> {\n        let ret = match event {\n            Event::Key(event) => self.handle_key_event(event),\n            Event::Mouse(event) => self.handle_mouse_event(event),\n            _ => ControlFlow::Continue(()),\n        };\n        // Generate the list after the event has been handled.\n        self.gen_opcode_list_if_necessary();\n        ret\n    }\n\n    fn handle_key_event(&mut self, event: KeyEvent) -> ControlFlow<ExitReason> {\n        // Breakpoints\n        if let KeyCode::Char(c) = event.code\n            && c.is_alphabetic()\n            && self.key_buffer.starts_with('\\'')\n        {\n            self.handle_breakpoint(c);\n            return ControlFlow::Continue(());\n        }\n\n        let control = event.modifiers.contains(KeyModifiers::CONTROL);\n\n        match event.code {\n            // Exit\n            KeyCode::Char('q') => return ControlFlow::Break(ExitReason::CharExit),\n\n            // Scroll up the memory buffer\n            KeyCode::Char('k') | KeyCode::Up if control => self.repeat(|this| {\n                this.draw_memory.current_buf_startline =\n                    this.draw_memory.current_buf_startline.saturating_sub(1);\n            }),\n            // Scroll down the memory buffer\n            KeyCode::Char('j') | KeyCode::Down if control => self.repeat(|this| {\n                let max_buf = (this.active_buffer().len() / 32).saturating_sub(1);\n                if this.draw_memory.current_buf_startline < max_buf {\n                    this.draw_memory.current_buf_startline += 1;\n                }\n            }),\n\n            // Move up\n            KeyCode::Char('k') | KeyCode::Up => self.repeat(Self::step_back),\n            // Move down\n            KeyCode::Char('j') | KeyCode::Down => self.repeat(Self::step),\n\n            // Scroll up the stack\n            KeyCode::Char('K') => self.repeat(|this| {\n                this.draw_memory.current_stack_startline =\n                    this.draw_memory.current_stack_startline.saturating_sub(1);\n            }),\n            // Scroll down the stack\n            KeyCode::Char('J') => self.repeat(|this| {\n                let max_stack =\n                    this.current_step().stack.as_ref().map_or(0, |s| s.len()).saturating_sub(1);\n                if this.draw_memory.current_stack_startline < max_stack {\n                    this.draw_memory.current_stack_startline += 1;\n                }\n            }),\n\n            // Cycle buffers\n            KeyCode::Char('b') => {\n                self.active_buffer = self.active_buffer.next();\n                self.draw_memory.current_buf_startline = 0;\n            }\n\n            // Go to top of file\n            KeyCode::Char('g') => {\n                self.draw_memory.inner_call_index = 0;\n                self.current_step = 0;\n            }\n\n            // Go to bottom of file\n            KeyCode::Char('G') => {\n                self.draw_memory.inner_call_index = self.debug_arena().len() - 1;\n                self.current_step = self.n_steps() - 1;\n            }\n\n            // Go to previous call\n            KeyCode::Char('c') => {\n                self.draw_memory.inner_call_index =\n                    self.draw_memory.inner_call_index.saturating_sub(1);\n                self.current_step = self.n_steps() - 1;\n            }\n\n            // Go to next call\n            KeyCode::Char('C')\n                if self.debug_arena().len() > self.draw_memory.inner_call_index + 1 =>\n            {\n                self.draw_memory.inner_call_index += 1;\n                self.current_step = 0;\n            }\n\n            // Step forward\n            KeyCode::Char('s') => self.repeat(|this| {\n                let remaining_steps = &this.debug_steps()[this.current_step..];\n                if let Some((i, _)) =\n                    remaining_steps.iter().enumerate().skip(1).find(|(i, step)| {\n                        let prev = &remaining_steps[*i - 1];\n                        is_jump(step, prev)\n                    })\n                {\n                    this.current_step += i\n                }\n            }),\n\n            // Step backwards\n            KeyCode::Char('a') => self.repeat(|this| {\n                let ops = &this.debug_steps()[..this.current_step];\n                this.current_step = ops\n                    .iter()\n                    .enumerate()\n                    .skip(1)\n                    .rev()\n                    .find(|&(i, op)| {\n                        let prev = &ops[i - 1];\n                        is_jump(op, prev)\n                    })\n                    .map(|(i, _)| i)\n                    .unwrap_or_default();\n            }),\n\n            // Toggle stack labels\n            KeyCode::Char('t') => self.stack_labels = !self.stack_labels,\n\n            // Toggle memory UTF-8 decoding\n            KeyCode::Char('m') => self.buf_utf = !self.buf_utf,\n\n            // Toggle help notice\n            KeyCode::Char('h') => self.show_shortcuts = !self.show_shortcuts,\n\n            // Numbers for repeating commands or breakpoints\n            KeyCode::Char(\n                other @ ('0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | '\\''),\n            ) => {\n                // Early return to not clear the buffer.\n                self.key_buffer.push(other);\n                return ControlFlow::Continue(());\n            }\n\n            // Unknown/unhandled key code\n            _ => {}\n        };\n\n        self.key_buffer.clear();\n        ControlFlow::Continue(())\n    }\n\n    fn handle_breakpoint(&mut self, c: char) {\n        // Find the location of the called breakpoint in the whole debug arena (at this address with\n        // this pc)\n        if let Some((caller, pc)) = self.debugger_context.breakpoints.get(&c) {\n            for (i, node) in self.debug_arena().iter().enumerate() {\n                if node.address == *caller\n                    && let Some(step) = node.steps.iter().position(|step| step.pc == *pc)\n                {\n                    self.draw_memory.inner_call_index = i;\n                    self.current_step = step;\n                    break;\n                }\n            }\n        }\n        self.key_buffer.clear();\n    }\n\n    fn handle_mouse_event(&mut self, event: MouseEvent) -> ControlFlow<ExitReason> {\n        match event.kind {\n            MouseEventKind::ScrollUp => self.step_back(),\n            MouseEventKind::ScrollDown => self.step(),\n            _ => {}\n        }\n\n        ControlFlow::Continue(())\n    }\n\n    fn step_back(&mut self) {\n        if self.current_step > 0 {\n            self.current_step -= 1;\n        } else if self.draw_memory.inner_call_index > 0 {\n            self.draw_memory.inner_call_index -= 1;\n            self.current_step = self.n_steps() - 1;\n        }\n    }\n\n    fn step(&mut self) {\n        if self.current_step < self.n_steps() - 1 {\n            self.current_step += 1;\n        } else if self.draw_memory.inner_call_index < self.debug_arena().len() - 1 {\n            self.draw_memory.inner_call_index += 1;\n            self.current_step = 0;\n        }\n    }\n\n    /// Calls a closure `f` the number of times specified in the key buffer, and at least once.\n    fn repeat(&mut self, mut f: impl FnMut(&mut Self)) {\n        for _ in 0..buffer_as_number(&self.key_buffer) {\n            f(self);\n        }\n    }\n\n    fn n_steps(&self) -> usize {\n        self.debug_steps().len()\n    }\n}\n\n/// Grab number from buffer. Used for something like '10k' to move up 10 operations\nfn buffer_as_number(s: &str) -> usize {\n    const MIN: usize = 1;\n    const MAX: usize = 100_000;\n    s.parse().unwrap_or(MIN).clamp(MIN, MAX)\n}\n\nfn pretty_opcode(step: &CallTraceStep) -> String {\n    if let Some(immediate) = step.immediate_bytes.as_ref().filter(|b| !b.is_empty()) {\n        format!(\"{}(0x{})\", step.op, hex::encode(immediate))\n    } else {\n        step.op.to_string()\n    }\n}\n\nfn is_jump(step: &CallTraceStep, prev: &CallTraceStep) -> bool {\n    if !matches!(prev.op, OpCode::JUMP | OpCode::JUMPI) {\n        return false;\n    }\n\n    let immediate_len = prev.immediate_bytes.as_ref().map_or(0, |b| b.len());\n\n    step.pc != prev.pc + 1 + immediate_len\n}\n"
  },
  {
    "path": "crates/debugger/src/tui/draw.rs",
    "content": "//! TUI draw implementation.\n\nuse super::context::TUIContext;\nuse crate::op::OpcodeParam;\nuse foundry_compilers::artifacts::sourcemap::SourceElement;\nuse foundry_evm_core::buffer::{BufferKind, get_buffer_accesses};\nuse foundry_evm_traces::debug::SourceData;\nuse ratatui::{\n    Frame,\n    layout::{Alignment, Constraint, Direction, Layout, Rect},\n    style::{Color, Modifier, Style},\n    text::{Line, Span, Text},\n    widgets::{Block, Borders, List, ListItem, ListState, Paragraph, Wrap},\n};\nuse revm_inspectors::tracing::types::CallKind;\nuse std::{collections::VecDeque, fmt::Write, io};\n\nimpl TUIContext<'_> {\n    /// Draws the TUI layout and subcomponents to the given terminal.\n    pub(crate) fn draw(&self, terminal: &mut super::DebuggerTerminal) -> io::Result<()> {\n        terminal.draw(|f| self.draw_layout(f)).map(drop)\n    }\n\n    fn draw_layout(&self, f: &mut Frame<'_>) {\n        // We need 100 columns to display a 32 byte word in the memory and stack panes.\n        let area = f.area();\n        let min_width = 100;\n        let min_height = 16;\n        if area.width < min_width || area.height < min_height {\n            self.size_too_small(f, min_width, min_height);\n            return;\n        }\n\n        // The horizontal layout draws these panes at 50% width.\n        let min_column_width_for_horizontal = 200;\n        if area.width >= min_column_width_for_horizontal {\n            self.horizontal_layout(f);\n        } else {\n            self.vertical_layout(f);\n        }\n    }\n\n    fn size_too_small(&self, f: &mut Frame<'_>, min_width: u16, min_height: u16) {\n        let mut lines = Vec::with_capacity(4);\n\n        let l1 = \"Terminal size too small:\";\n        lines.push(Line::from(l1));\n\n        let area = f.area();\n        let width_color = if area.width >= min_width { Color::Green } else { Color::Red };\n        let height_color = if area.height >= min_height { Color::Green } else { Color::Red };\n        let l2 = vec![\n            Span::raw(\"Width = \"),\n            Span::styled(area.width.to_string(), Style::new().fg(width_color)),\n            Span::raw(\" Height = \"),\n            Span::styled(area.height.to_string(), Style::new().fg(height_color)),\n        ];\n        lines.push(Line::from(l2));\n\n        let l3 = \"Needed for current config:\";\n        lines.push(Line::from(l3));\n        let l4 = format!(\"Width = {min_width} Height = {min_height}\");\n        lines.push(Line::from(l4));\n\n        let paragraph =\n            Paragraph::new(lines).alignment(Alignment::Center).wrap(Wrap { trim: true });\n        f.render_widget(paragraph, area)\n    }\n\n    /// Draws the layout in vertical mode.\n    ///\n    /// ```text\n    /// |-----------------------------|\n    /// |             op              |\n    /// |-----------------------------|\n    /// |            stack            |\n    /// |-----------------------------|\n    /// |             buf             |\n    /// |-----------------------------|\n    /// |                             |\n    /// |             src             |\n    /// |                             |\n    /// |-----------------------------|\n    /// ```\n    fn vertical_layout(&self, f: &mut Frame<'_>) {\n        let area = f.area();\n        let h_height = if self.show_shortcuts { 4 } else { 0 };\n\n        // NOTE: `Layout::split` always returns a slice of the same length as the number of\n        // constraints, so the `else` branch is unreachable.\n\n        // Split off footer.\n        let [app, footer] = Layout::new(\n            Direction::Vertical,\n            [Constraint::Ratio(100 - h_height, 100), Constraint::Ratio(h_height, 100)],\n        )\n        .split(area)[..] else {\n            unreachable!()\n        };\n\n        // Split the app in 4 vertically to construct all the panes.\n        let [op_pane, stack_pane, memory_pane, src_pane] = Layout::new(\n            Direction::Vertical,\n            [\n                Constraint::Ratio(1, 6),\n                Constraint::Ratio(1, 6),\n                Constraint::Ratio(1, 6),\n                Constraint::Ratio(3, 6),\n            ],\n        )\n        .split(app)[..] else {\n            unreachable!()\n        };\n\n        if self.show_shortcuts {\n            self.draw_footer(f, footer);\n        }\n        self.draw_src(f, src_pane);\n        self.draw_op_list(f, op_pane);\n        self.draw_stack(f, stack_pane);\n        self.draw_buffer(f, memory_pane);\n    }\n\n    /// Draws the layout in horizontal mode.\n    ///\n    /// ```text\n    /// |-----------------|-----------|\n    /// |        op       |   stack   |\n    /// |-----------------|-----------|\n    /// |                 |           |\n    /// |       src       |    buf    |\n    /// |                 |           |\n    /// |-----------------|-----------|\n    /// ```\n    fn horizontal_layout(&self, f: &mut Frame<'_>) {\n        let area = f.area();\n        let h_height = if self.show_shortcuts { 4 } else { 0 };\n\n        // Split off footer.\n        let [app, footer] = Layout::new(\n            Direction::Vertical,\n            [Constraint::Ratio(100 - h_height, 100), Constraint::Ratio(h_height, 100)],\n        )\n        .split(area)[..] else {\n            unreachable!()\n        };\n\n        // Split app in 2 horizontally.\n        let [app_left, app_right] =\n            Layout::new(Direction::Horizontal, [Constraint::Ratio(1, 2), Constraint::Ratio(1, 2)])\n                .split(app)[..]\n        else {\n            unreachable!()\n        };\n\n        // Split left pane in 2 vertically to opcode list and source.\n        let [op_pane, src_pane] =\n            Layout::new(Direction::Vertical, [Constraint::Ratio(1, 4), Constraint::Ratio(3, 4)])\n                .split(app_left)[..]\n        else {\n            unreachable!()\n        };\n\n        // Split right pane horizontally to construct stack and memory.\n        let [stack_pane, memory_pane] =\n            Layout::new(Direction::Vertical, [Constraint::Ratio(1, 4), Constraint::Ratio(3, 4)])\n                .split(app_right)[..]\n        else {\n            unreachable!()\n        };\n\n        if self.show_shortcuts {\n            self.draw_footer(f, footer);\n        }\n        self.draw_src(f, src_pane);\n        self.draw_op_list(f, op_pane);\n        self.draw_stack(f, stack_pane);\n        self.draw_buffer(f, memory_pane);\n    }\n\n    fn draw_footer(&self, f: &mut Frame<'_>, area: Rect) {\n        let l1 = \"[q]: quit | [k/j]: prev/next op | [a/s]: prev/next jump | [c/C]: prev/next call | [g/G]: start/end | [b]: cycle memory/calldata/returndata buffers\";\n        let l2 = \"[t]: stack labels | [m]: buffer decoding | [shift + j/k]: scroll stack | [ctrl + j/k]: scroll buffer | ['<char>]: goto breakpoint | [h] toggle help\";\n        let dimmed = Style::new().add_modifier(Modifier::DIM);\n        let lines =\n            vec![Line::from(Span::styled(l1, dimmed)), Line::from(Span::styled(l2, dimmed))];\n        let paragraph =\n            Paragraph::new(lines).alignment(Alignment::Center).wrap(Wrap { trim: false });\n        f.render_widget(paragraph, area);\n    }\n\n    fn draw_src(&self, f: &mut Frame<'_>, area: Rect) {\n        let (text_output, source_name) = self.src_text(area);\n        let call_kind_text = match self.call_kind() {\n            CallKind::Create | CallKind::Create2 => \"Contract creation\",\n            CallKind::Call => \"Contract call\",\n            CallKind::StaticCall => \"Contract staticcall\",\n            CallKind::CallCode => \"Contract callcode\",\n            CallKind::DelegateCall => \"Contract delegatecall\",\n            CallKind::AuthCall => \"Contract authcall\",\n        };\n        let title = format!(\n            \"{} {} \",\n            call_kind_text,\n            source_name.map(|s| format!(\"| {s}\")).unwrap_or_default()\n        );\n        let block = Block::default().title(title).borders(Borders::ALL);\n        let paragraph = Paragraph::new(text_output).block(block).wrap(Wrap { trim: false });\n        f.render_widget(paragraph, area);\n    }\n\n    fn src_text(&self, area: Rect) -> (Text<'_>, Option<&str>) {\n        let (source_element, source) = match self.src_map() {\n            Ok(r) => r,\n            Err(e) => return (Text::from(e), None),\n        };\n\n        // We are handed a vector of SourceElements that give us a span of sourcecode that is\n        // currently being executed. This includes an offset and length.\n        // This vector is in instruction pointer order, meaning the location of the instruction\n        // minus `sum(push_bytes[..pc])`.\n        let offset = source_element.offset() as usize;\n        let len = source_element.length() as usize;\n        let max = source.source.len();\n\n        // Split source into before, relevant, and after chunks, split by line, for formatting.\n        let actual_start = offset.min(max);\n        let actual_end = (offset + len).min(max);\n\n        let mut before: Vec<_> = source.source[..actual_start].split_inclusive('\\n').collect();\n        let actual: Vec<_> =\n            source.source[actual_start..actual_end].split_inclusive('\\n').collect();\n        let mut after: VecDeque<_> = source.source[actual_end..].split_inclusive('\\n').collect();\n\n        let num_lines = before.len() + actual.len() + after.len();\n        let height = area.height as usize;\n        let needed_highlight = actual.len();\n        let mid_len = before.len() + actual.len();\n\n        // adjust what text we show of the source code\n        let (start_line, end_line) = if needed_highlight > height {\n            // highlighted section is more lines than we have available\n            let start_line = before.len().saturating_sub(1);\n            (start_line, before.len() + needed_highlight)\n        } else if height > num_lines {\n            // we can fit entire source\n            (0, num_lines)\n        } else {\n            let remaining = height - needed_highlight;\n            let mut above = remaining / 2;\n            let mut below = remaining / 2;\n            if below > after.len() {\n                // unused space below the highlight\n                above += below - after.len();\n            } else if above > before.len() {\n                // we have unused space above the highlight\n                below += above - before.len();\n            } else {\n                // no unused space\n            }\n\n            // since above is subtracted from before.len(), and the resulting\n            // start_line is used to index into before, above must be at least\n            // 1 to avoid out-of-range accesses.\n            if above == 0 {\n                above = 1;\n            }\n            (before.len().saturating_sub(above), mid_len + below)\n        };\n\n        // Unhighlighted line number: gray.\n        let u_num = Style::new().fg(Color::Gray);\n        // Unhighlighted text: default, dimmed.\n        let u_text = Style::new().add_modifier(Modifier::DIM);\n        // Highlighted line number: cyan.\n        let h_num = Style::new().fg(Color::Cyan);\n        // Highlighted text: cyan, bold.\n        let h_text = Style::new().fg(Color::Cyan).add_modifier(Modifier::BOLD);\n\n        let mut lines = SourceLines::new(start_line, end_line);\n\n        // We check if there is other text on the same line before the highlight starts.\n        if let Some(last) = before.pop() {\n            let last_has_nl = last.ends_with('\\n');\n\n            if last_has_nl {\n                before.push(last);\n            }\n            for line in &before[start_line..] {\n                lines.push(u_num, line, u_text);\n            }\n\n            let first = if !last_has_nl {\n                lines.push_raw(h_num, &[Span::raw(last), Span::styled(actual[0], h_text)]);\n                1\n            } else {\n                0\n            };\n\n            // Skip the first line if it has already been handled above.\n            for line in &actual[first..] {\n                lines.push(h_num, line, h_text);\n            }\n        } else {\n            // No text before the current line.\n            for line in &actual {\n                lines.push(h_num, line, h_text);\n            }\n        }\n\n        // Fill in the rest of the line as unhighlighted.\n        if let Some(last) = actual.last()\n            && !last.ends_with('\\n')\n            && let Some(post) = after.pop_front()\n            && let Some(last) = lines.lines.last_mut()\n        {\n            last.spans.push(Span::raw(post));\n        }\n\n        // Add after highlighted text.\n        while mid_len + after.len() > end_line {\n            after.pop_back();\n        }\n        for line in after {\n            lines.push(u_num, line, u_text);\n        }\n\n        // pad with empty to each line to ensure the previous text is cleared\n        for line in &mut lines.lines {\n            // note that the \\n is not included in the line length\n            if area.width as usize > line.width() + 1 {\n                line.push_span(Span::raw(\" \".repeat(area.width as usize - line.width() - 1)));\n            }\n        }\n\n        (Text::from(lines.lines), source.path.to_str())\n    }\n\n    /// Returns source map, source code and source name of the current line.\n    fn src_map(&self) -> Result<(SourceElement, &SourceData), String> {\n        let address = self.address();\n        let Some(contract_name) = self.debugger_context.identified_contracts.get(address) else {\n            return Err(format!(\"Unknown contract at address {address}\"));\n        };\n\n        self.debugger_context\n            .contracts_sources\n            .find_source_mapping(\n                contract_name,\n                self.current_step().pc as u32,\n                self.debug_call().kind.is_any_create(),\n            )\n            .ok_or_else(|| format!(\"No source map for contract {contract_name}\"))\n    }\n\n    fn draw_op_list(&self, f: &mut Frame<'_>, area: Rect) {\n        let debug_steps = self.debug_steps();\n        let max_pc = debug_steps.iter().map(|step| step.pc).max().unwrap_or(0);\n        let max_pc_len = hex_digits(max_pc);\n\n        let items = debug_steps\n            .iter()\n            .enumerate()\n            .map(|(i, step)| {\n                let mut content = String::with_capacity(64);\n                write!(content, \"{:0>max_pc_len$x}|\", step.pc).unwrap();\n                if let Some(op) = self.opcode_list.get(i) {\n                    content.push_str(op);\n                }\n                ListItem::new(Span::styled(content, Style::new().fg(Color::White)))\n            })\n            .collect::<Vec<_>>();\n\n        let title = format!(\n            \"Address: {} | PC: {} | Gas used: {} | Gas refund: {}\",\n            self.address(),\n            self.current_step().pc,\n            self.debug_call().gas_limit - self.current_step().gas_remaining,\n            self.current_step().gas_refund_counter\n        );\n        let block = Block::default().title(title).borders(Borders::ALL);\n        let list = List::new(items)\n            .block(block)\n            .highlight_symbol(\"▶\")\n            .highlight_style(Style::new().fg(Color::White).bg(Color::DarkGray))\n            .scroll_padding(1);\n        let mut state = ListState::default().with_selected(Some(self.current_step));\n        f.render_stateful_widget(list, area, &mut state);\n    }\n\n    fn draw_stack(&self, f: &mut Frame<'_>, area: Rect) {\n        let step = self.current_step();\n        let stack = step.stack.as_ref();\n        let stack_len = stack.map_or(0, |s| s.len());\n\n        let min_len = decimal_digits(stack_len).max(2);\n\n        let params = OpcodeParam::of(step.op.get());\n\n        let text: Vec<Line<'_>> = stack\n            .map(|stack| {\n                stack\n                    .iter()\n                    .rev()\n                    .enumerate()\n                    .skip(self.draw_memory.current_stack_startline)\n                    .map(|(i, stack_item)| {\n                        let param = params.iter().find(|param| param.index == i);\n                        let mut spans = Vec::with_capacity(1 + 32 * 2 + 3);\n\n                        // Stack index.\n                        spans.push(Span::styled(\n                            format!(\"{i:0min_len$}| \"),\n                            Style::new().fg(Color::White),\n                        ));\n\n                        // Item hex bytes.\n                        hex_bytes_spans(&stack_item.to_be_bytes::<32>(), &mut spans, |_, _| {\n                            if param.is_some() {\n                                Style::new().fg(Color::Cyan)\n                            } else {\n                                Style::new().fg(Color::White)\n                            }\n                        });\n\n                        if self.stack_labels\n                            && let Some(param) = param\n                        {\n                            spans.push(Span::raw(\"| \"));\n                            spans.push(Span::raw(param.name));\n                        }\n\n                        spans.push(Span::raw(\"\\n\"));\n\n                        Line::from(spans)\n                    })\n                    .collect()\n            })\n            .unwrap_or_default();\n\n        let title = format!(\"Stack: {stack_len}\");\n        let block = Block::default().title(title).borders(Borders::ALL);\n        let paragraph = Paragraph::new(text).block(block).wrap(Wrap { trim: true });\n        f.render_widget(paragraph, area);\n    }\n\n    fn draw_buffer(&self, f: &mut Frame<'_>, area: Rect) {\n        let call = self.debug_call();\n        let step = self.current_step();\n        let buf = match self.active_buffer {\n            BufferKind::Memory => step.memory.as_ref().unwrap().as_ref(),\n            BufferKind::Calldata => call.calldata.as_ref(),\n            BufferKind::Returndata => step.returndata.as_ref(),\n        };\n\n        let min_len = hex_digits(buf.len());\n\n        // Color memory region based on read/write.\n        let mut offset = None;\n        let mut len = None;\n        let mut write_offset = None;\n        let mut write_size = None;\n        let mut color = None;\n        let stack_len = step.stack.as_ref().map_or(0, |s| s.len());\n        if stack_len > 0\n            && let Some(stack) = step.stack.as_ref()\n            && let Some(accesses) = get_buffer_accesses(step.op.get(), stack)\n        {\n            if let Some(read_access) = accesses.read {\n                offset = Some(read_access.1.offset);\n                len = Some(read_access.1.len);\n                color = Some(Color::Cyan);\n            }\n            if let Some(write_access) = accesses.write\n                && self.active_buffer == BufferKind::Memory\n            {\n                write_offset = Some(write_access.offset);\n                write_size = Some(write_access.len);\n            }\n        }\n\n        // color word on previous write op\n        // TODO: technically it's possible for this to conflict with the current op, ie, with\n        // subsequent MCOPYs, but solc can't seem to generate that code even with high optimizer\n        // settings\n        if self.current_step > 0 {\n            let prev_step = self.current_step - 1;\n            let prev_step = &self.debug_steps()[prev_step];\n            if let Some(stack) = prev_step.stack.as_ref()\n                && let Some(write_access) =\n                    get_buffer_accesses(prev_step.op.get(), stack).and_then(|a| a.write)\n                && self.active_buffer == BufferKind::Memory\n            {\n                offset = Some(write_access.offset);\n                len = Some(write_access.len);\n                color = Some(Color::Green);\n            }\n        }\n\n        let height = area.height as usize;\n        let end_line = self.draw_memory.current_buf_startline + height;\n\n        let text: Vec<Line<'_>> = buf\n            .chunks(32)\n            .enumerate()\n            .skip(self.draw_memory.current_buf_startline)\n            .take_while(|(i, _)| *i < end_line)\n            .map(|(i, buf_word)| {\n                let mut spans = Vec::with_capacity(1 + 32 * 2 + 1 + 32 / 4 + 1);\n\n                // Buffer index.\n                spans.push(Span::styled(\n                    format!(\"{:0min_len$x}| \", i * 32),\n                    Style::new().fg(Color::White),\n                ));\n\n                // Word hex bytes.\n                hex_bytes_spans(buf_word, &mut spans, |j, _| {\n                    let mut byte_color = Color::White;\n                    let mut end = None;\n                    let idx = i * 32 + j;\n                    if let (Some(offset), Some(len), Some(color)) = (offset, len, color) {\n                        end = Some(offset + len);\n                        if (offset..offset + len).contains(&idx) {\n                            // [offset, offset + len] is the memory region to be colored.\n                            // If a byte at row i and column j in the memory panel\n                            // falls in this region, set the color.\n                            byte_color = color;\n                        }\n                    }\n                    if let (Some(write_offset), Some(write_size)) = (write_offset, write_size) {\n                        // check for overlap with read region\n                        let write_end = write_offset + write_size;\n                        if let Some(read_end) = end {\n                            let read_start = offset.unwrap();\n                            if (write_offset..write_end).contains(&read_end) {\n                                // if it contains end, start from write_start up to read_end\n                                if (write_offset..read_end).contains(&idx) {\n                                    return Style::new().fg(Color::Yellow);\n                                }\n                            } else if (write_offset..write_end).contains(&read_start) {\n                                // otherwise if it contains read start, start from read_start up to\n                                // write_end\n                                if (read_start..write_end).contains(&idx) {\n                                    return Style::new().fg(Color::Yellow);\n                                }\n                            }\n                        }\n                        if (write_offset..write_end).contains(&idx) {\n                            byte_color = Color::Red;\n                        }\n                    }\n\n                    Style::new().fg(byte_color)\n                });\n\n                if self.buf_utf {\n                    spans.push(Span::raw(\"|\"));\n                    for utf in buf_word.chunks(4) {\n                        if let Ok(utf_str) = std::str::from_utf8(utf) {\n                            spans.push(Span::raw(utf_str.replace('\\0', \".\")));\n                        } else {\n                            spans.push(Span::raw(\".\"));\n                        }\n                    }\n                }\n\n                spans.push(Span::raw(\"\\n\"));\n\n                Line::from(spans)\n            })\n            .collect();\n\n        let title = self.active_buffer.title(buf.len());\n        let block = Block::default().title(title).borders(Borders::ALL);\n        let paragraph = Paragraph::new(text).block(block).wrap(Wrap { trim: true });\n        f.render_widget(paragraph, area);\n    }\n}\n\n/// Wrapper around a list of [`Line`]s that prepends the line number on each new line.\nstruct SourceLines<'a> {\n    lines: Vec<Line<'a>>,\n    start_line: usize,\n    max_line_num: usize,\n}\n\nimpl<'a> SourceLines<'a> {\n    fn new(start_line: usize, end_line: usize) -> Self {\n        Self { lines: Vec::new(), start_line, max_line_num: decimal_digits(end_line) }\n    }\n\n    fn push(&mut self, line_number_style: Style, line: &'a str, line_style: Style) {\n        self.push_raw(line_number_style, &[Span::styled(line, line_style)]);\n    }\n\n    fn push_raw(&mut self, line_number_style: Style, spans: &[Span<'a>]) {\n        let mut line_spans = Vec::with_capacity(4);\n\n        let line_number = format!(\n            \"{number: >width$} \",\n            number = self.start_line + self.lines.len() + 1,\n            width = self.max_line_num\n        );\n        line_spans.push(Span::styled(line_number, line_number_style));\n\n        // Space between line number and line text.\n        line_spans.push(Span::raw(\"  \"));\n\n        line_spans.extend_from_slice(spans);\n\n        self.lines.push(Line::from(line_spans));\n    }\n}\n\nfn hex_bytes_spans(bytes: &[u8], spans: &mut Vec<Span<'_>>, f: impl Fn(usize, u8) -> Style) {\n    for (i, &byte) in bytes.iter().enumerate() {\n        if i > 0 {\n            spans.push(Span::raw(\" \"));\n        }\n        spans.push(Span::styled(alloy_primitives::hex::encode([byte]), f(i, byte)));\n    }\n}\n\n/// Returns the number of decimal digits in the given number.\n///\n/// This is the same as `n.to_string().len()`.\nfn decimal_digits(n: usize) -> usize {\n    n.checked_ilog10().unwrap_or(0) as usize + 1\n}\n\n/// Returns the number of hexadecimal digits in the given number.\n///\n/// This is the same as `format!(\"{n:x}\").len()`.\nfn hex_digits(n: usize) -> usize {\n    n.checked_ilog(16).unwrap_or(0) as usize + 1\n}\n\n#[cfg(test)]\nmod tests {\n    #[test]\n    fn decimal_digits() {\n        assert_eq!(super::decimal_digits(0), 1);\n        assert_eq!(super::decimal_digits(1), 1);\n        assert_eq!(super::decimal_digits(2), 1);\n        assert_eq!(super::decimal_digits(9), 1);\n        assert_eq!(super::decimal_digits(10), 2);\n        assert_eq!(super::decimal_digits(11), 2);\n        assert_eq!(super::decimal_digits(50), 2);\n        assert_eq!(super::decimal_digits(99), 2);\n        assert_eq!(super::decimal_digits(100), 3);\n        assert_eq!(super::decimal_digits(101), 3);\n        assert_eq!(super::decimal_digits(201), 3);\n        assert_eq!(super::decimal_digits(999), 3);\n        assert_eq!(super::decimal_digits(1000), 4);\n        assert_eq!(super::decimal_digits(1001), 4);\n    }\n\n    #[test]\n    fn hex_digits() {\n        assert_eq!(super::hex_digits(0), 1);\n        assert_eq!(super::hex_digits(1), 1);\n        assert_eq!(super::hex_digits(2), 1);\n        assert_eq!(super::hex_digits(9), 1);\n        assert_eq!(super::hex_digits(10), 1);\n        assert_eq!(super::hex_digits(11), 1);\n        assert_eq!(super::hex_digits(15), 1);\n        assert_eq!(super::hex_digits(16), 2);\n        assert_eq!(super::hex_digits(17), 2);\n        assert_eq!(super::hex_digits(0xff), 2);\n        assert_eq!(super::hex_digits(0x100), 3);\n        assert_eq!(super::hex_digits(0x101), 3);\n    }\n}\n"
  },
  {
    "path": "crates/debugger/src/tui/mod.rs",
    "content": "//! The debugger TUI.\n\nuse crossterm::{\n    event::{self, DisableMouseCapture, EnableMouseCapture},\n    execute,\n    terminal::{EnterAlternateScreen, LeaveAlternateScreen, disable_raw_mode, enable_raw_mode},\n};\nuse eyre::Result;\nuse ratatui::{\n    Terminal,\n    backend::{Backend, CrosstermBackend},\n};\nuse std::{io, ops::ControlFlow, sync::Arc};\n\nmod context;\nuse crate::debugger::DebuggerContext;\nuse context::TUIContext;\n\nmod draw;\n\ntype DebuggerTerminal = Terminal<CrosstermBackend<io::Stdout>>;\n\n/// Debugger exit reason.\n#[derive(Debug)]\npub enum ExitReason {\n    /// Exit using 'q'.\n    CharExit,\n}\n\n/// The debugger TUI.\npub struct TUI<'a> {\n    debugger_context: &'a mut DebuggerContext,\n}\n\nimpl<'a> TUI<'a> {\n    /// Creates a new debugger.\n    pub fn new(debugger_context: &'a mut DebuggerContext) -> Self {\n        Self { debugger_context }\n    }\n\n    /// Starts the debugger TUI.\n    pub fn try_run(&mut self) -> Result<ExitReason> {\n        let backend = CrosstermBackend::new(io::stdout());\n        let terminal = Terminal::new(backend)?;\n        TerminalGuard::with(terminal, |terminal| self.run_inner(terminal))\n    }\n\n    #[instrument(target = \"debugger\", name = \"run\", skip_all, ret)]\n    fn run_inner(&mut self, terminal: &mut DebuggerTerminal) -> Result<ExitReason> {\n        let mut cx = TUIContext::new(self.debugger_context);\n        cx.init();\n        loop {\n            cx.draw(terminal)?;\n            match cx.handle_event(event::read()?) {\n                ControlFlow::Continue(()) => {}\n                ControlFlow::Break(reason) => return Ok(reason),\n            }\n        }\n    }\n}\n\ntype PanicHandler = Box<dyn Fn(&std::panic::PanicHookInfo<'_>) + 'static + Sync + Send>;\n\n/// Handles terminal state.\n#[must_use]\nstruct TerminalGuard<B: Backend + io::Write> {\n    terminal: Terminal<B>,\n    hook: Option<Arc<PanicHandler>>,\n}\n\nimpl<B: Backend + io::Write> TerminalGuard<B> {\n    fn with<T>(terminal: Terminal<B>, mut f: impl FnMut(&mut Terminal<B>) -> T) -> T {\n        let mut guard = Self { terminal, hook: None };\n        guard.setup();\n        f(&mut guard.terminal)\n    }\n\n    fn setup(&mut self) {\n        let previous = Arc::new(std::panic::take_hook());\n        self.hook = Some(previous.clone());\n        // We need to restore the terminal state before displaying the panic message.\n        // TODO: Use `std::panic::update_hook` when it's stable\n        std::panic::set_hook(Box::new(move |info| {\n            Self::half_restore(&mut std::io::stdout());\n            (previous)(info)\n        }));\n\n        let _ = enable_raw_mode();\n        let _ = execute!(*self.terminal.backend_mut(), EnterAlternateScreen, EnableMouseCapture);\n        let _ = self.terminal.hide_cursor();\n        let _ = self.terminal.clear();\n    }\n\n    fn restore(&mut self) {\n        if !std::thread::panicking() {\n            // Drop the current hook to guarantee that `self.hook` is the only reference to it.\n            let _ = std::panic::take_hook();\n            // Restore the previous panic hook.\n            let prev = self.hook.take().unwrap();\n            let prev = match Arc::try_unwrap(prev) {\n                Ok(prev) => prev,\n                Err(_) => unreachable!(\"`self.hook` is not the only reference to the panic hook\"),\n            };\n            std::panic::set_hook(prev);\n\n            // NOTE: Our panic handler calls this function, so we only have to call it here if we're\n            // not panicking.\n            Self::half_restore(self.terminal.backend_mut());\n        }\n\n        let _ = self.terminal.show_cursor();\n    }\n\n    fn half_restore(w: &mut impl io::Write) {\n        let _ = disable_raw_mode();\n        let _ = execute!(*w, LeaveAlternateScreen, DisableMouseCapture);\n    }\n}\n\nimpl<B: Backend + io::Write> Drop for TerminalGuard<B> {\n    #[inline]\n    fn drop(&mut self) {\n        self.restore();\n    }\n}\n"
  },
  {
    "path": "crates/doc/Cargo.toml",
    "content": "[package]\nname = \"forge-doc\"\ndescription = \"Solidity documentation generator\"\n\nversion.workspace = true\nedition.workspace = true\nrust-version.workspace = true\nauthors.workspace = true\nlicense.workspace = true\nhomepage.workspace = true\nrepository.workspace = true\n\n[lints]\nworkspace = true\n\n[dependencies]\nforge-fmt.workspace = true\nfoundry-common.workspace = true\nfoundry-compilers.workspace = true\nfoundry-config.workspace = true\n\nsolar.workspace = true\nalloy-primitives.workspace = true\n\nderive_more.workspace = true\neyre.workspace = true\nitertools.workspace = true\nmdbook-driver = { version = \"0.5\", default-features = false, features = [\"search\"] }\nrayon.workspace = true\nserde_json.workspace = true\nserde.workspace = true\nsolang-parser.workspace = true\nthiserror.workspace = true\ntoml.workspace = true\ntracing.workspace = true\nregex.workspace = true\n"
  },
  {
    "path": "crates/doc/README.md",
    "content": "# Documentation (`doc`)\n\nSolidity documentation generator. It parses the source code and generates an mdbook\nbased on the parse tree and [NatSpec comments](https://docs.soliditylang.org/en/v0.8.17/natspec-format.html).\n\n## Architecture\n\nThe entrypoint for the documentation module is the `DocBuilder`.\nThe `DocBuilder` generates the mdbook in 3 phases:\n\n1. Parse\n\nIn this phase, builder invokes 2 parsers: [solang parser](https://github.com/hyperledger-labs/solang) and internal `Parser`. The solang parser produces the parse tree based on the source code. Afterwards, the internal parser walks the parse tree by implementing the `Visitor` trait from the `fmt` crate and saves important information about the parsed nodes, doc comments.\n\nThen, builder takes the output of the internal `Parser` and creates documents with additional information: the path of the original item, display identity, the target path where this document will be written.\n\n2. Preprocess\n\nThe builder accepts an array of preprocessors which can be applied to documents produced in the `Parse` phase. The preprocessors can rearrange and/or change the array as well as modify the separate documents.\n\nAt the end of this phase, the builder maintains a possibly modified collection of documents.\n\n3. Write\n\nAt this point, builder has all necessary information to generate documentation for the source code. It takes every document, formats the source file contents and writes/copies additional files that are required for building documentation.\n"
  },
  {
    "path": "crates/doc/src/builder.rs",
    "content": "use crate::{\n    AsDoc, BufWriter, Document, ParseItem, ParseSource, Parser, Preprocessor,\n    document::DocumentContent, helpers::merge_toml_table, solang_ext::Visitable,\n};\nuse alloy_primitives::map::HashMap;\nuse eyre::{Context, Result};\nuse foundry_compilers::{compilers::solc::SOLC_EXTENSIONS, utils::source_files_iter};\nuse foundry_config::{DocConfig, FormatterConfig, filter::expand_globs};\nuse itertools::Itertools;\nuse mdbook_driver::MDBook;\nuse rayon::prelude::*;\nuse std::{\n    cmp::Ordering,\n    fs,\n    path::{Path, PathBuf},\n};\nuse toml::value;\n\n/// Build Solidity documentation for a project from natspec comments.\n/// The builder parses the source files using [Parser],\n/// then formats and writes the elements as the output.\n#[derive(Debug)]\npub struct DocBuilder {\n    /// The project root\n    root: PathBuf,\n    /// Path to Solidity source files.\n    sources: PathBuf,\n    /// Paths to external libraries.\n    libraries: Vec<PathBuf>,\n    /// Flag whether to build mdbook.\n    should_build: bool,\n    /// Documentation configuration.\n    config: DocConfig,\n    /// The array of preprocessors to apply.\n    preprocessors: Vec<Box<dyn Preprocessor>>,\n    /// The formatter config.\n    fmt: FormatterConfig,\n    /// Whether to include libraries to the output.\n    include_libraries: bool,\n}\n\nimpl DocBuilder {\n    pub(crate) const SRC: &'static str = \"src\";\n    const SOL_EXT: &'static str = \"sol\";\n    const README: &'static str = \"README.md\";\n    const SUMMARY: &'static str = \"SUMMARY.md\";\n\n    /// Create new instance of builder.\n    pub fn new(\n        root: PathBuf,\n        sources: PathBuf,\n        libraries: Vec<PathBuf>,\n        include_libraries: bool,\n    ) -> Self {\n        Self {\n            root,\n            sources,\n            libraries,\n            include_libraries,\n            should_build: false,\n            config: DocConfig::default(),\n            preprocessors: Default::default(),\n            fmt: Default::default(),\n        }\n    }\n\n    /// Set `should_build` flag on the builder\n    pub fn with_should_build(mut self, should_build: bool) -> Self {\n        self.should_build = should_build;\n        self\n    }\n\n    /// Set config on the builder.\n    pub fn with_config(mut self, config: DocConfig) -> Self {\n        self.config = config;\n        self\n    }\n\n    /// Set formatter config on the builder.\n    pub fn with_fmt(mut self, fmt: FormatterConfig) -> Self {\n        self.fmt = fmt;\n        self\n    }\n\n    /// Set preprocessors on the builder.\n    pub fn with_preprocessor<P: Preprocessor + 'static>(mut self, preprocessor: P) -> Self {\n        self.preprocessors.push(Box::new(preprocessor) as Box<dyn Preprocessor>);\n        self\n    }\n\n    /// Get the output directory\n    pub fn out_dir(&self) -> Result<PathBuf> {\n        Ok(self.root.join(&self.config.out).canonicalize()?)\n    }\n\n    /// Parse the sources and build the documentation.\n    pub fn build(self, compiler: &mut solar::sema::Compiler) -> eyre::Result<()> {\n        fs::create_dir_all(self.root.join(&self.config.out))\n            .wrap_err(\"failed to create output directory\")?;\n\n        // Expand ignore globs\n        let ignored = expand_globs(&self.root, self.config.ignore.iter())?;\n\n        // Collect and parse source files\n        let sources = source_files_iter(&self.sources, SOLC_EXTENSIONS)\n            .filter(|file| !ignored.contains(file))\n            .collect::<Vec<_>>();\n\n        if sources.is_empty() {\n            sh_println!(\"No sources detected at {}\", self.sources.display())?;\n            return Ok(());\n        }\n\n        let library_sources = self\n            .libraries\n            .iter()\n            .flat_map(|lib| source_files_iter(lib, SOLC_EXTENSIONS))\n            .collect::<Vec<_>>();\n\n        let combined_sources = sources\n            .iter()\n            .map(|path| (path, false))\n            .chain(library_sources.iter().map(|path| (path, true)))\n            .collect::<Vec<_>>();\n\n        let out_dir = self.out_dir()?;\n        let out_target_dir = out_dir.clone();\n        let documents = compiler.enter_mut(|compiler| -> eyre::Result<Vec<Vec<Document>>> {\n            let gcx = compiler.gcx();\n            let documents = combined_sources\n                .par_iter()\n                .enumerate()\n                .map(|(i, (path, from_library))| {\n                    let path = *path;\n                    let from_library = *from_library;\n                    let mut files = vec![];\n\n                    // Read and parse source file\n                    if let Some((_, ast)) = gcx.get_ast_source(path)\n                        && let Some(source) =\n                            forge_fmt::format_ast(gcx, ast, self.fmt.clone().into())\n                    {\n                        let (mut source_unit, comments) = match solang_parser::parse(&source, i) {\n                            Ok(res) => res,\n                            Err(err) => {\n                                if from_library {\n                                    // Ignore failures for library files\n                                    return Ok(files);\n                                } else {\n                                    return Err(eyre::eyre!(\n                                        \"Failed to parse Solidity code for {}\\nDebug info: {:?}\",\n                                        path.display(),\n                                        err\n                                    ));\n                                }\n                            }\n                        };\n\n                        // Visit the parse tree\n                        let mut doc = Parser::new(comments, source, self.fmt.tab_width);\n                        source_unit\n                            .visit(&mut doc)\n                            .map_err(|err| eyre::eyre!(\"Failed to parse source: {err}\"))?;\n\n                        // Split the parsed items on top-level constants and rest.\n                        let (items, consts): (Vec<ParseItem>, Vec<ParseItem>) = doc\n                            .items()\n                            .into_iter()\n                            .partition(|item| !matches!(item.source, ParseSource::Variable(_)));\n\n                        // Attempt to group overloaded top-level functions\n                        let mut remaining = Vec::with_capacity(items.len());\n                        let mut funcs: HashMap<String, Vec<ParseItem>> = HashMap::default();\n                        for item in items {\n                            if matches!(item.source, ParseSource::Function(_)) {\n                                funcs.entry(item.source.ident()).or_default().push(item);\n                            } else {\n                                // Put the item back\n                                remaining.push(item);\n                            }\n                        }\n                        let (items, overloaded): (\n                            HashMap<String, Vec<ParseItem>>,\n                            HashMap<String, Vec<ParseItem>>,\n                        ) = funcs.into_iter().partition(|(_, v)| v.len() == 1);\n                        remaining.extend(items.into_values().flatten());\n\n                        // Each regular item will be written into its own file.\n                        files = remaining\n                            .into_iter()\n                            .map(|item| {\n                                let relative_path =\n                                    path.strip_prefix(&self.root)?.join(item.filename());\n\n                                let target_path = out_dir.join(Self::SRC).join(relative_path);\n                                let ident = item.source.ident();\n                                Ok(Document::new(\n                                    path.clone(),\n                                    target_path,\n                                    from_library,\n                                    out_target_dir.clone(),\n                                )\n                                .with_content(DocumentContent::Single(item), ident))\n                            })\n                            .collect::<eyre::Result<Vec<_>>>()?;\n\n                        // If top-level constants exist, they will be written to the same file.\n                        if !consts.is_empty() {\n                            let filestem = path.file_stem().and_then(|stem| stem.to_str());\n\n                            let filename = {\n                                let mut name = \"constants\".to_owned();\n                                if let Some(stem) = filestem {\n                                    name.push_str(&format!(\".{stem}\"));\n                                }\n                                name.push_str(\".md\");\n                                name\n                            };\n                            let relative_path = path.strip_prefix(&self.root)?.join(filename);\n                            let target_path = out_dir.join(Self::SRC).join(relative_path);\n\n                            let identity = match filestem {\n                                Some(stem) if stem.to_lowercase().contains(\"constants\") => {\n                                    stem.to_owned()\n                                }\n                                Some(stem) => format!(\"{stem} constants\"),\n                                None => \"constants\".to_owned(),\n                            };\n\n                            files.push(\n                                Document::new(\n                                    path.clone(),\n                                    target_path,\n                                    from_library,\n                                    out_target_dir.clone(),\n                                )\n                                .with_content(DocumentContent::Constants(consts), identity),\n                            )\n                        }\n\n                        // If overloaded functions exist, they will be written to the same file\n                        if !overloaded.is_empty() {\n                            for (ident, funcs) in overloaded {\n                                let filename =\n                                    funcs.first().expect(\"no overloaded functions\").filename();\n                                let relative_path = path.strip_prefix(&self.root)?.join(filename);\n\n                                let target_path = out_dir.join(Self::SRC).join(relative_path);\n                                files.push(\n                                    Document::new(\n                                        path.clone(),\n                                        target_path,\n                                        from_library,\n                                        out_target_dir.clone(),\n                                    )\n                                    .with_content(\n                                        DocumentContent::OverloadedFunctions(funcs),\n                                        ident,\n                                    ),\n                                );\n                            }\n                        }\n                    };\n\n                    Ok(files)\n                })\n                .collect::<eyre::Result<Vec<_>>>()?;\n\n            Ok(documents)\n        })?;\n\n        // Flatten results and apply preprocessors to files\n        let documents = self\n            .preprocessors\n            .iter()\n            .try_fold(documents.into_iter().flatten().collect_vec(), |docs, p| {\n                p.preprocess(docs)\n            })?;\n\n        // Sort the results and filter libraries.\n        let documents = documents\n            .into_iter()\n            .sorted_by(|doc1, doc2| {\n                doc1.item_path.display().to_string().cmp(&doc2.item_path.display().to_string())\n            })\n            .filter(|d| !d.from_library || self.include_libraries)\n            .collect_vec();\n\n        // Write mdbook related files\n        self.write_mdbook(documents)?;\n\n        // Build the book if requested\n        if self.should_build {\n            MDBook::load(self.out_dir().wrap_err(\"failed to construct output directory\")?)\n                .and_then(|book| book.build())\n                .map_err(|err| eyre::eyre!(\"failed to build book: {err:?}\"))?;\n        }\n\n        Ok(())\n    }\n\n    fn write_mdbook(&self, documents: Vec<Document>) -> eyre::Result<()> {\n        let out_dir = self.out_dir().wrap_err(\"failed to construct output directory\")?;\n        let out_dir_src = out_dir.join(Self::SRC);\n        fs::create_dir_all(&out_dir_src)?;\n\n        // Write readme content if any\n        let homepage_content = {\n            // Default to the homepage README if it's available.\n            // If not, use the src README as a fallback.\n            let homepage_or_src_readme = self\n                .config\n                .homepage\n                .as_ref()\n                .map(|homepage| self.root.join(homepage))\n                .unwrap_or_else(|| self.sources.join(Self::README));\n            // Grab the root readme.\n            let root_readme = self.root.join(Self::README);\n\n            // Check to see if there is a 'homepage' option specified in config.\n            // If not, fall back to src and root readme files, in that order.\n            if homepage_or_src_readme.exists() {\n                fs::read_to_string(homepage_or_src_readme)?\n            } else if root_readme.exists() {\n                fs::read_to_string(root_readme)?\n            } else {\n                String::new()\n            }\n        };\n\n        let readme_path = out_dir_src.join(Self::README);\n        fs::write(readme_path, homepage_content)?;\n\n        // Write summary and section readmes\n        let mut summary = BufWriter::default();\n        summary.write_title(\"Summary\")?;\n        summary.write_link_list_item(\"Home\", Self::README, 0)?;\n        self.write_summary_section(&mut summary, &documents.iter().collect::<Vec<_>>(), None, 0)?;\n        fs::write(out_dir_src.join(Self::SUMMARY), summary.finish())?;\n\n        // Write solidity syntax highlighting\n        fs::write(out_dir.join(\"solidity.min.js\"), include_str!(\"../static/solidity.min.js\"))?;\n\n        // Write css files\n        fs::write(out_dir.join(\"book.css\"), include_str!(\"../static/book.css\"))?;\n\n        // Write book config\n        fs::write(out_dir.join(\"book.toml\"), self.book_config()?)?;\n\n        // Write .gitignore\n        let gitignore = \"book/\";\n        fs::write(out_dir.join(\".gitignore\"), gitignore)?;\n\n        // Write doc files\n        for document in documents {\n            fs::create_dir_all(\n                document\n                    .target_path\n                    .parent()\n                    .ok_or_else(|| eyre::format_err!(\"empty target path; noop\"))?,\n            )?;\n            fs::write(&document.target_path, document.as_doc()?)?;\n        }\n\n        Ok(())\n    }\n\n    fn book_config(&self) -> eyre::Result<String> {\n        // Read the default book first\n        let mut book: value::Table = toml::from_str(include_str!(\"../static/book.toml\"))?;\n        book[\"book\"]\n            .as_table_mut()\n            .unwrap()\n            .insert(String::from(\"title\"), self.config.title.clone().into());\n        if let Some(ref repo) = self.config.repository {\n            // Create the full repository URL.\n            let git_repo_url = if let Some(path) = &self.config.path {\n                // If path is specified, append it to the repository URL.\n                format!(\"{}/{}\", repo.trim_end_matches('/'), path.trim_start_matches('/'))\n            } else {\n                // If no path specified, use repository URL as-is.\n                repo.clone()\n            };\n\n            book[\"output\"].as_table_mut().unwrap()[\"html\"]\n                .as_table_mut()\n                .unwrap()\n                .insert(String::from(\"git-repository-url\"), git_repo_url.into());\n        }\n\n        // Attempt to find the user provided book path\n        let book_path = {\n            if self.config.book.is_file() {\n                Some(self.config.book.clone())\n            } else {\n                let book_path = self.config.book.join(\"book.toml\");\n                if book_path.is_file() { Some(book_path) } else { None }\n            }\n        };\n\n        // Merge two book configs\n        if let Some(book_path) = book_path {\n            merge_toml_table(&mut book, toml::from_str(&fs::read_to_string(book_path)?)?);\n        }\n\n        Ok(toml::to_string_pretty(&book)?)\n    }\n\n    fn write_summary_section(\n        &self,\n        summary: &mut BufWriter,\n        files: &[&Document],\n        base_path: Option<&Path>,\n        depth: usize,\n    ) -> eyre::Result<()> {\n        if files.is_empty() {\n            return Ok(());\n        }\n\n        if let Some(path) = base_path {\n            let title = path.iter().next_back().unwrap().to_string_lossy();\n            if depth == 1 {\n                summary.write_title(&title)?;\n            } else {\n                let summary_path = path.join(Self::README);\n                summary.write_link_list_item(\n                    &format!(\"❱ {title}\"),\n                    &summary_path.display().to_string(),\n                    depth - 1,\n                )?;\n            }\n        }\n\n        // Group entries by path depth\n        let mut grouped = HashMap::new();\n        for file in files {\n            let path = file.item_path.strip_prefix(&self.root)?;\n            let key = path.iter().take(depth + 1).collect::<PathBuf>();\n            grouped.entry(key).or_insert_with(Vec::new).push(*file);\n        }\n        // Sort entries by path depth\n        let grouped = grouped.into_iter().sorted_by(|(lhs, _), (rhs, _)| {\n            let lhs_at_end = lhs.extension().map(|ext| ext == Self::SOL_EXT).unwrap_or_default();\n            let rhs_at_end = rhs.extension().map(|ext| ext == Self::SOL_EXT).unwrap_or_default();\n            if lhs_at_end == rhs_at_end {\n                lhs.cmp(rhs)\n            } else if lhs_at_end {\n                Ordering::Greater\n            } else {\n                Ordering::Less\n            }\n        });\n\n        let out_dir = self.out_dir().wrap_err(\"failed to construct output directory\")?;\n        let mut readme = BufWriter::new(\"\\n\\n# Contents\\n\");\n        for (path, files) in grouped {\n            if path.extension().map(|ext| ext == Self::SOL_EXT).unwrap_or_default() {\n                for file in files {\n                    let ident = &file.identity;\n\n                    let summary_path = &file.target_path.strip_prefix(out_dir.join(Self::SRC))?;\n                    summary.write_link_list_item(\n                        ident,\n                        &summary_path.display().to_string(),\n                        depth,\n                    )?;\n\n                    let readme_path = base_path\n                        .map(|path| summary_path.strip_prefix(path))\n                        .transpose()?\n                        .unwrap_or(summary_path);\n                    readme.write_link_list_item(ident, &readme_path.display().to_string(), 0)?;\n                }\n            } else {\n                let name = path.iter().next_back().unwrap().to_string_lossy();\n                let readme_path = Path::new(\"/\").join(&path).display().to_string();\n                readme.write_link_list_item(&name, &readme_path, 0)?;\n                self.write_summary_section(summary, &files, Some(&path), depth + 1)?;\n            }\n        }\n        if !readme.is_empty()\n            && let Some(path) = base_path\n        {\n            let path = out_dir.join(Self::SRC).join(path);\n            fs::create_dir_all(&path)?;\n            fs::write(path.join(Self::README), readme.finish())?;\n        }\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "crates/doc/src/document.rs",
    "content": "use crate::{DocBuilder, ParseItem, PreprocessorId, PreprocessorOutput};\nuse alloy_primitives::map::HashMap;\nuse std::{\n    path::{Path, PathBuf},\n    slice::IterMut,\n    sync::Mutex,\n};\n\n/// The wrapper around the [ParseItem] containing additional\n/// information the original item and extra context for outputting it.\n#[derive(Debug)]\npub struct Document {\n    /// The underlying parsed items.\n    pub content: DocumentContent,\n    /// The original item path.\n    pub item_path: PathBuf,\n    /// The original item file content.\n    pub item_content: String,\n    /// The target path where the document will be written.\n    pub target_path: PathBuf,\n    /// The document display identity.\n    pub identity: String,\n    /// The preprocessors results.\n    context: Mutex<HashMap<PreprocessorId, PreprocessorOutput>>,\n    /// Whether the document is from external library.\n    pub from_library: bool,\n    /// The target directory for the doc output.\n    pub out_target_dir: PathBuf,\n}\n\nimpl Document {\n    /// Create new instance of [Document].\n    pub fn new(\n        item_path: PathBuf,\n        target_path: PathBuf,\n        from_library: bool,\n        out_target_dir: PathBuf,\n    ) -> Self {\n        Self {\n            item_path,\n            target_path,\n            from_library,\n            item_content: String::default(),\n            identity: String::default(),\n            content: DocumentContent::Empty,\n            out_target_dir,\n            context: Mutex::new(HashMap::default()),\n        }\n    }\n\n    /// Set content and identity on the [Document].\n    #[must_use]\n    pub fn with_content(mut self, content: DocumentContent, identity: String) -> Self {\n        self.content = content;\n        self.identity = identity;\n        self\n    }\n\n    /// Add a preprocessor result to inner document context.\n    pub fn add_context(&self, id: PreprocessorId, output: PreprocessorOutput) {\n        let mut context = self.context.lock().expect(\"failed to lock context\");\n        context.insert(id, output);\n    }\n\n    /// Read preprocessor result from context\n    pub fn get_from_context(&self, id: PreprocessorId) -> Option<PreprocessorOutput> {\n        let context = self.context.lock().expect(\"failed to lock context\");\n        context.get(&id).cloned()\n    }\n\n    fn try_relative_output_path(&self) -> Option<&Path> {\n        self.target_path.strip_prefix(&self.out_target_dir).ok()?.strip_prefix(DocBuilder::SRC).ok()\n    }\n\n    /// Returns the relative path of the document output.\n    pub fn relative_output_path(&self) -> &Path {\n        self.try_relative_output_path().unwrap_or(self.target_path.as_path())\n    }\n}\n\n/// The content of the document.\n#[derive(Debug)]\n#[allow(clippy::large_enum_variant)]\npub enum DocumentContent {\n    Empty,\n    Single(ParseItem),\n    Constants(Vec<ParseItem>),\n    OverloadedFunctions(Vec<ParseItem>),\n}\n\nimpl DocumentContent {\n    pub(crate) fn len(&self) -> usize {\n        match self {\n            Self::Empty => 0,\n            Self::Single(_) => 1,\n            Self::Constants(items) => items.len(),\n            Self::OverloadedFunctions(items) => items.len(),\n        }\n    }\n\n    pub(crate) fn get_mut(&mut self, index: usize) -> Option<&mut ParseItem> {\n        match self {\n            Self::Empty => None,\n            Self::Single(item) => {\n                if index == 0 {\n                    Some(item)\n                } else {\n                    None\n                }\n            }\n            Self::Constants(items) => items.get_mut(index),\n            Self::OverloadedFunctions(items) => items.get_mut(index),\n        }\n    }\n\n    pub fn iter_items(&self) -> ParseItemIter<'_> {\n        match self {\n            Self::Empty => ParseItemIter { next: None, other: None },\n            Self::Single(item) => ParseItemIter { next: Some(item), other: None },\n            Self::Constants(items) => ParseItemIter { next: None, other: Some(items.iter()) },\n            Self::OverloadedFunctions(items) => {\n                ParseItemIter { next: None, other: Some(items.iter()) }\n            }\n        }\n    }\n\n    pub fn iter_items_mut(&mut self) -> ParseItemIterMut<'_> {\n        match self {\n            Self::Empty => ParseItemIterMut { next: None, other: None },\n            Self::Single(item) => ParseItemIterMut { next: Some(item), other: None },\n            Self::Constants(items) => {\n                ParseItemIterMut { next: None, other: Some(items.iter_mut()) }\n            }\n            Self::OverloadedFunctions(items) => {\n                ParseItemIterMut { next: None, other: Some(items.iter_mut()) }\n            }\n        }\n    }\n}\n\n#[derive(Debug)]\npub struct ParseItemIter<'a> {\n    next: Option<&'a ParseItem>,\n    other: Option<std::slice::Iter<'a, ParseItem>>,\n}\n\nimpl<'a> Iterator for ParseItemIter<'a> {\n    type Item = &'a ParseItem;\n\n    fn next(&mut self) -> Option<Self::Item> {\n        if let Some(next) = self.next.take() {\n            return Some(next);\n        }\n        if let Some(other) = self.other.as_mut() {\n            return other.next();\n        }\n\n        None\n    }\n}\n\n#[derive(Debug)]\npub struct ParseItemIterMut<'a> {\n    next: Option<&'a mut ParseItem>,\n    other: Option<IterMut<'a, ParseItem>>,\n}\n\nimpl<'a> Iterator for ParseItemIterMut<'a> {\n    type Item = &'a mut ParseItem;\n\n    fn next(&mut self) -> Option<Self::Item> {\n        if let Some(next) = self.next.take() {\n            return Some(next);\n        }\n        if let Some(other) = self.other.as_mut() {\n            return other.next();\n        }\n\n        None\n    }\n}\n\n/// Read the preprocessor output variant from document context.\n/// Returns [None] if there is no output.\nmacro_rules! read_context {\n    ($doc:expr, $id:expr, $variant:ident) => {\n        $doc.get_from_context($id).and_then(|out| match out {\n            // Only a single variant is matched. Otherwise the code is invalid.\n            PreprocessorOutput::$variant(inner) => Some(inner),\n            _ => None,\n        })\n    };\n}\n\npub(crate) use read_context;\n"
  },
  {
    "path": "crates/doc/src/helpers.rs",
    "content": "use itertools::Itertools;\nuse solang_parser::pt::FunctionDefinition;\nuse toml::{Value, value::Table};\n\n/// Generates a function signature with parameter types (e.g., \"functionName(type1,type2)\").\n/// Returns the function name without parameters if the function has no parameters.\npub fn function_signature(func: &FunctionDefinition) -> String {\n    let func_name = func.name.as_ref().map_or(func.ty.to_string(), |n| n.name.to_owned());\n    if func.params.is_empty() {\n        return func_name;\n    }\n\n    format!(\n        \"{}({})\",\n        func_name,\n        func.params\n            .iter()\n            .map(|p| p.1.as_ref().map(|p| p.ty.to_string()).unwrap_or_default())\n            .join(\",\")\n    )\n}\n\n/// Merge original toml table with the override.\npub(crate) fn merge_toml_table(table: &mut Table, override_table: Table) {\n    for (key, override_value) in override_table {\n        match table.get_mut(&key) {\n            Some(Value::Table(inner_table)) => {\n                // Override value must be a table, otherwise discard\n                if let Value::Table(inner_override) = override_value {\n                    merge_toml_table(inner_table, inner_override);\n                }\n            }\n            Some(Value::Array(inner_array)) => {\n                // Override value must be an array, otherwise discard\n                if let Value::Array(inner_override) = override_value {\n                    for entry in inner_override {\n                        if !inner_array.contains(&entry) {\n                            inner_array.push(entry);\n                        }\n                    }\n                }\n            }\n            _ => {\n                table.insert(key, override_value);\n            }\n        };\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use solang_parser::{\n        parse,\n        pt::{ContractPart, SourceUnit, SourceUnitPart},\n    };\n\n    #[test]\n    fn test_function_signature_no_params() {\n        let (source_unit, _) = parse(\n            r#\"\n            contract Test {\n                function foo() public {}\n            }\n            \"#,\n            0,\n        )\n        .unwrap();\n\n        let func = extract_function(&source_unit);\n        assert_eq!(function_signature(func), \"foo\");\n    }\n\n    #[test]\n    fn test_function_signature_with_params() {\n        let (source_unit, _) = parse(\n            r#\"\n            contract Test {\n                function transfer(address to, uint256 amount) public {}\n            }\n            \"#,\n            0,\n        )\n        .unwrap();\n\n        let func = extract_function(&source_unit);\n        assert_eq!(function_signature(func), \"transfer(address,uint256)\");\n    }\n\n    #[test]\n    fn test_function_signature_constructor() {\n        let (source_unit, _) = parse(\n            r#\"\n            contract Test {\n                constructor(address owner) {}\n            }\n            \"#,\n            0,\n        )\n        .unwrap();\n\n        let func = extract_function(&source_unit);\n        assert_eq!(function_signature(func), \"constructor(address)\");\n    }\n\n    /// Helper to extract the first function from a parsed source unit\n    fn extract_function(source_unit: &SourceUnit) -> &FunctionDefinition {\n        for part in &source_unit.0 {\n            if let SourceUnitPart::ContractDefinition(contract) = part {\n                for part in &contract.parts {\n                    if let ContractPart::FunctionDefinition(func) = part {\n                        return func;\n                    }\n                }\n            }\n        }\n        panic!(\"No function found in source unit\");\n    }\n}\n"
  },
  {
    "path": "crates/doc/src/lib.rs",
    "content": "//! The module for generating Solidity documentation.\n//!\n//! See [`DocBuilder`].\n\n#![cfg_attr(not(test), warn(unused_crate_dependencies))]\n#![cfg_attr(docsrs, feature(doc_cfg))]\n\n#[macro_use]\nextern crate foundry_common;\n\n#[macro_use]\nextern crate tracing;\n\nmod builder;\npub use builder::DocBuilder;\n\nmod document;\npub use document::Document;\n\nmod helpers;\n\nmod parser;\npub use parser::{\n    Comment, CommentTag, Comments, CommentsRef, ParseItem, ParseSource, Parser, error,\n};\n\nmod preprocessor;\npub use preprocessor::*;\n\nmod writer;\npub use writer::{AsDoc, AsDocResult, BufWriter, Markdown};\n\npub use mdbook_driver;\n\n// old formatter dependencies\npub mod solang_ext;\n"
  },
  {
    "path": "crates/doc/src/parser/comment.rs",
    "content": "use alloy_primitives::map::HashMap;\nuse derive_more::{Deref, DerefMut, derive::Display};\nuse solang_parser::doccomment::DocCommentTag;\n\n/// The natspec comment tag explaining the purpose of the comment.\n/// See: <https://docs.soliditylang.org/en/v0.8.17/natspec-format.html#tags>.\n#[derive(Clone, Debug, Display, PartialEq, Eq)]\npub enum CommentTag {\n    /// A title that should describe the contract/interface\n    Title,\n    /// The name of the author\n    Author,\n    /// Explain to an end user what this does\n    Notice,\n    /// Explain to a developer any extra details\n    Dev,\n    /// Documents a parameter just like in Doxygen (must be followed by parameter name)\n    Param,\n    /// Documents the return variables of a contract’s function\n    Return,\n    /// Copies all missing tags from the base function (must be followed by the contract name)\n    Inheritdoc,\n    /// Custom tag, semantics is application-defined\n    Custom(String),\n}\n\nimpl CommentTag {\n    fn from_str(s: &str) -> Option<Self> {\n        let trimmed = s.trim();\n        let tag = match trimmed {\n            \"title\" => Self::Title,\n            \"author\" => Self::Author,\n            \"notice\" => Self::Notice,\n            \"dev\" => Self::Dev,\n            \"param\" => Self::Param,\n            \"return\" => Self::Return,\n            \"inheritdoc\" => Self::Inheritdoc,\n            _ if trimmed.starts_with(\"custom:\") => {\n                // `@custom:param` tag will be parsed as `CommentTag::Param` due to a limitation\n                // on specifying parameter docs for unnamed function arguments.\n                let custom_tag = trimmed.trim_start_matches(\"custom:\").trim();\n                match custom_tag {\n                    \"param\" => Self::Param,\n                    _ => Self::Custom(custom_tag.to_owned()),\n                }\n            }\n            _ => {\n                warn!(target: \"forge::doc\", tag=trimmed, \"unknown comment tag. custom tags must be preceded by `custom:`\");\n                return None;\n            }\n        };\n        Some(tag)\n    }\n}\n\n/// The natspec documentation comment.\n///\n/// Ref: <https://docs.soliditylang.org/en/v0.8.17/natspec-format.html>\n#[derive(Clone, Debug, PartialEq, Eq)]\npub struct Comment {\n    /// The doc comment tag.\n    pub tag: CommentTag,\n    /// The doc comment value.\n    pub value: String,\n}\n\nimpl Comment {\n    /// Create new instance of [Comment].\n    pub fn new(tag: CommentTag, value: String) -> Self {\n        Self { tag, value }\n    }\n\n    /// Create new instance of [Comment] from [DocCommentTag]\n    /// if it has a valid natspec tag.\n    pub fn from_doc_comment(value: DocCommentTag) -> Option<Self> {\n        CommentTag::from_str(&value.tag).map(|tag| Self { tag, value: value.value })\n    }\n\n    /// Split the comment at first word.\n    /// Useful for [CommentTag::Param] and [CommentTag::Return] comments.\n    pub fn split_first_word(&self) -> Option<(&str, &str)> {\n        self.value.trim_start().split_once(' ')\n    }\n\n    /// Match the first word of the comment with the expected.\n    /// Returns [None] if the word doesn't match.\n    /// Useful for [CommentTag::Param] and [CommentTag::Return] comments.\n    pub fn match_first_word(&self, expected: &str) -> Option<&str> {\n        self.split_first_word().and_then(\n            |(word, rest)| {\n                if word == expected { Some(rest) } else { None }\n            },\n        )\n    }\n\n    /// Check if this comment is a custom tag.\n    pub fn is_custom(&self) -> bool {\n        matches!(self.tag, CommentTag::Custom(_))\n    }\n}\n\n/// The collection of natspec [Comment] items.\n#[derive(Clone, Debug, Default, PartialEq, Deref, DerefMut)]\npub struct Comments(Vec<Comment>);\n\n/// Forward the [Comments] function implementation to the [CommentsRef]\n/// reference type.\nmacro_rules! ref_fn {\n    ($vis:vis fn $name:ident(&self$(, )?$($arg_name:ident: $arg:ty),*) -> $ret:ty) => {\n        /// Forward the function implementation to [CommentsRef] reference type.\n        $vis fn $name(&self, $($arg_name: $arg),*) -> $ret {\n            CommentsRef::from(self).$name($($arg_name),*)\n        }\n    };\n}\n\nimpl Comments {\n    ref_fn!(pub fn include_tag(&self, tag: CommentTag) -> CommentsRef<'_>);\n    ref_fn!(pub fn include_tags(&self, tags: &[CommentTag]) -> CommentsRef<'_>);\n    ref_fn!(pub fn exclude_tags(&self, tags: &[CommentTag]) -> CommentsRef<'_>);\n    ref_fn!(pub fn contains_tag(&self, tag: &Comment) -> bool);\n    ref_fn!(pub fn find_inheritdoc_base(&self) -> Option<&'_ str>);\n\n    /// Attempts to lookup inherited comments and merge them with the current collection.\n    ///\n    /// Looks up comments in `inheritdocs` using the key `{base}.{ident}` where `base` is\n    /// extracted from an `@inheritdoc` tag. Merges the found comments by inserting\n    /// [CommentTag] from the inherited collection into the current one unless they are\n    /// already present.\n    pub fn merge_inheritdoc(\n        &self,\n        ident: &str,\n        inheritdocs: Option<HashMap<String, Self>>,\n    ) -> Self {\n        let mut result = self.clone();\n\n        if let (Some(inheritdocs), Some(base)) = (inheritdocs, self.find_inheritdoc_base()) {\n            let key = format!(\"{base}.{ident}\");\n            if let Some(other) = inheritdocs.get(&key) {\n                for comment in other.iter() {\n                    if !result.contains_tag(comment) {\n                        result.push(comment.clone());\n                    }\n                }\n            }\n        }\n\n        result\n    }\n}\n\nimpl From<Vec<DocCommentTag>> for Comments {\n    fn from(value: Vec<DocCommentTag>) -> Self {\n        Self(value.into_iter().flat_map(Comment::from_doc_comment).collect())\n    }\n}\n\n/// The collection of references to natspec [Comment] items.\n#[derive(Debug, Default, PartialEq, Deref)]\npub struct CommentsRef<'a>(Vec<&'a Comment>);\n\nimpl<'a> CommentsRef<'a> {\n    /// Filter a collection of comments and return only those that match a provided tag.\n    pub fn include_tag(&self, tag: CommentTag) -> Self {\n        self.include_tags(&[tag])\n    }\n\n    /// Filter a collection of comments and return only those that match provided tags.\n    pub fn include_tags(&self, tags: &[CommentTag]) -> Self {\n        // Cloning only references here\n        CommentsRef(self.iter().copied().filter(|c| tags.contains(&c.tag)).collect())\n    }\n\n    /// Filter a collection of comments and return only those that do not match provided tags.\n    pub fn exclude_tags(&self, tags: &[CommentTag]) -> Self {\n        // Cloning only references here\n        CommentsRef(self.iter().copied().filter(|c| !tags.contains(&c.tag)).collect())\n    }\n\n    /// Check if the collection contains a target comment.\n    pub fn contains_tag(&self, target: &Comment) -> bool {\n        self.iter().any(|c| match (&c.tag, &target.tag) {\n            (CommentTag::Inheritdoc, CommentTag::Inheritdoc) => c.value == target.value,\n            (CommentTag::Param, CommentTag::Param) | (CommentTag::Return, CommentTag::Return) => {\n                c.split_first_word().map(|(name, _)| name)\n                    == target.split_first_word().map(|(name, _)| name)\n            }\n            (tag1, tag2) => tag1 == tag2,\n        })\n    }\n\n    /// Find an [CommentTag::Inheritdoc] comment and extract the base.\n    fn find_inheritdoc_base(&self) -> Option<&'a str> {\n        self.iter()\n            .find(|c| matches!(c.tag, CommentTag::Inheritdoc))\n            .and_then(|c| c.value.split_whitespace().next())\n    }\n\n    /// Filter a collection of comments and only return the custom tags.\n    pub fn get_custom_tags(&self) -> Self {\n        CommentsRef(self.iter().copied().filter(|c| c.is_custom()).collect())\n    }\n}\n\nimpl<'a> From<&'a Comments> for CommentsRef<'a> {\n    fn from(value: &'a Comments) -> Self {\n        Self(value.iter().collect())\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn parse_comment_tag() {\n        assert_eq!(CommentTag::from_str(\"title\"), Some(CommentTag::Title));\n        assert_eq!(CommentTag::from_str(\" title  \"), Some(CommentTag::Title));\n        assert_eq!(CommentTag::from_str(\"author\"), Some(CommentTag::Author));\n        assert_eq!(CommentTag::from_str(\"notice\"), Some(CommentTag::Notice));\n        assert_eq!(CommentTag::from_str(\"dev\"), Some(CommentTag::Dev));\n        assert_eq!(CommentTag::from_str(\"param\"), Some(CommentTag::Param));\n        assert_eq!(CommentTag::from_str(\"return\"), Some(CommentTag::Return));\n        assert_eq!(CommentTag::from_str(\"inheritdoc\"), Some(CommentTag::Inheritdoc));\n        assert_eq!(CommentTag::from_str(\"custom:\"), Some(CommentTag::Custom(String::new())));\n        assert_eq!(\n            CommentTag::from_str(\"custom:some\"),\n            Some(CommentTag::Custom(\"some\".to_owned()))\n        );\n        assert_eq!(\n            CommentTag::from_str(\"  custom:   some   \"),\n            Some(CommentTag::Custom(\"some\".to_owned()))\n        );\n\n        assert_eq!(CommentTag::from_str(\"\"), None);\n        assert_eq!(CommentTag::from_str(\"custom\"), None);\n        assert_eq!(CommentTag::from_str(\"sometag\"), None);\n    }\n\n    #[test]\n    fn test_is_custom() {\n        // Test custom tag.\n        let custom_comment = Comment::new(\n            CommentTag::from_str(\"custom:test\").unwrap(),\n            \"dummy custom tag\".to_owned(),\n        );\n        assert!(custom_comment.is_custom(), \"Custom tag should return true for is_custom\");\n\n        // Test non-custom tags.\n        let non_custom_tags = [\n            CommentTag::Title,\n            CommentTag::Author,\n            CommentTag::Notice,\n            CommentTag::Dev,\n            CommentTag::Param,\n            CommentTag::Return,\n            CommentTag::Inheritdoc,\n        ];\n        for tag in non_custom_tags {\n            let comment = Comment::new(tag.clone(), \"Non-custom comment\".to_string());\n            assert!(\n                !comment.is_custom(),\n                \"Non-custom tag {tag:?} should return false for is_custom\"\n            );\n        }\n    }\n}\n"
  },
  {
    "path": "crates/doc/src/parser/error.rs",
    "content": "use solar::interface::diagnostics::EmittedDiagnostics;\nuse thiserror::Error;\n\n/// The parser error.\n#[derive(Debug, Error)]\n#[error(transparent)]\npub enum ParserError {\n    /// Formatter error.\n    #[error(transparent)]\n    Formatter(EmittedDiagnostics),\n    /// Internal parser error.\n    #[error(transparent)]\n    Internal(#[from] eyre::Error),\n}\n\n/// The parser result.\npub type ParserResult<T, E = ParserError> = std::result::Result<T, E>;\n"
  },
  {
    "path": "crates/doc/src/parser/item.rs",
    "content": "use crate::{Comments, helpers::function_signature, solang_ext::SafeUnwrap};\nuse solang_parser::pt::{\n    ContractDefinition, ContractTy, EnumDefinition, ErrorDefinition, EventDefinition,\n    FunctionDefinition, StructDefinition, TypeDefinition, VariableDefinition,\n};\nuse std::ops::Range;\n\n/// The parsed item.\n#[derive(Debug, PartialEq)]\npub struct ParseItem {\n    /// The parse tree source.\n    pub source: ParseSource,\n    /// Item comments.\n    pub comments: Comments,\n    /// Children items.\n    pub children: Vec<Self>,\n    /// Formatted code string.\n    pub code: String,\n}\n\n/// Defines a method that filters [ParseItem]'s children and returns the source pt token of the\n/// children matching the target variant as well as its comments.\n/// Returns [Option::None] if no children matching the variant are found.\nmacro_rules! filter_children_fn {\n    ($vis:vis fn $name:ident(&self, $variant:ident) -> $ret:ty) => {\n        /// Filter children items for [ParseSource::$variant] variants.\n        $vis fn $name(&self) -> Option<Vec<(&$ret, &Comments, &String)>> {\n            let items = self.children.iter().filter_map(|item| match item.source {\n                ParseSource::$variant(ref inner) => Some((inner, &item.comments, &item.code)),\n                _ => None,\n            });\n            let items = items.collect::<Vec<_>>();\n            if !items.is_empty() {\n                Some(items)\n            } else {\n                None\n            }\n        }\n    };\n}\n\n/// Defines a method that returns [ParseSource] inner element if it matches\n/// the variant\nmacro_rules! as_inner_source {\n    ($vis:vis fn $name:ident(&self, $variant:ident) -> $ret:ty) => {\n        /// Return inner element if it matches $variant.\n        /// If the element doesn't match, returns [None]\n        $vis fn $name(&self) -> Option<&$ret> {\n            match self.source {\n                ParseSource::$variant(ref inner) => Some(inner),\n                _ => None\n            }\n        }\n    };\n}\n\nimpl ParseItem {\n    /// Create new instance of [ParseItem].\n    pub fn new(source: ParseSource) -> Self {\n        Self {\n            source,\n            comments: Default::default(),\n            children: Default::default(),\n            code: Default::default(),\n        }\n    }\n\n    /// Set comments on the [ParseItem].\n    pub fn with_comments(mut self, comments: Comments) -> Self {\n        self.comments = comments;\n        self\n    }\n\n    /// Set children on the [ParseItem].\n    pub fn with_children(mut self, children: Vec<Self>) -> Self {\n        self.children = children;\n        self\n    }\n\n    /// Set the source code of this [ParseItem].\n    ///\n    /// The parameter should be the full source file where this parse item originated from.\n    pub fn with_code(mut self, source: &str, tab_width: usize) -> Self {\n        let mut code = source[self.source.range()].to_string();\n\n        // Special function case, add `;` at the end of definition.\n        if let ParseSource::Function(_) | ParseSource::Error(_) | ParseSource::Event(_) =\n            self.source\n        {\n            code.push(';');\n        }\n\n        // Remove extra indent from source lines.\n        let prefix = &\" \".repeat(tab_width);\n        self.code = code\n            .lines()\n            .map(|line| line.strip_prefix(prefix).unwrap_or(line))\n            .collect::<Vec<_>>()\n            .join(\"\\n\");\n        self\n    }\n\n    /// Format the item's filename.\n    pub fn filename(&self) -> String {\n        let prefix = match self.source {\n            ParseSource::Contract(ref c) => match c.ty {\n                ContractTy::Contract(_) => \"contract\",\n                ContractTy::Abstract(_) => \"abstract\",\n                ContractTy::Interface(_) => \"interface\",\n                ContractTy::Library(_) => \"library\",\n            },\n            ParseSource::Function(_) => \"function\",\n            ParseSource::Variable(_) => \"variable\",\n            ParseSource::Event(_) => \"event\",\n            ParseSource::Error(_) => \"error\",\n            ParseSource::Struct(_) => \"struct\",\n            ParseSource::Enum(_) => \"enum\",\n            ParseSource::Type(_) => \"type\",\n        };\n        let ident = self.source.ident();\n        format!(\"{prefix}.{ident}.md\")\n    }\n\n    filter_children_fn!(pub fn variables(&self, Variable) -> VariableDefinition);\n    filter_children_fn!(pub fn functions(&self, Function) -> FunctionDefinition);\n    filter_children_fn!(pub fn events(&self, Event) -> EventDefinition);\n    filter_children_fn!(pub fn errors(&self, Error) -> ErrorDefinition);\n    filter_children_fn!(pub fn structs(&self, Struct) -> StructDefinition);\n    filter_children_fn!(pub fn enums(&self, Enum) -> EnumDefinition);\n\n    as_inner_source!(pub fn as_contract(&self, Contract) -> ContractDefinition);\n    as_inner_source!(pub fn as_variable(&self, Variable) -> VariableDefinition);\n    as_inner_source!(pub fn as_function(&self, Function) -> FunctionDefinition);\n}\n\n/// A wrapper type around pt token.\n#[derive(Clone, Debug, PartialEq, Eq)]\n#[allow(clippy::large_enum_variant)]\npub enum ParseSource {\n    /// Source contract definition.\n    Contract(Box<ContractDefinition>),\n    /// Source function definition.\n    Function(FunctionDefinition),\n    /// Source variable definition.\n    Variable(VariableDefinition),\n    /// Source event definition.\n    Event(EventDefinition),\n    /// Source error definition.\n    Error(ErrorDefinition),\n    /// Source struct definition.\n    Struct(StructDefinition),\n    /// Source enum definition.\n    Enum(EnumDefinition),\n    /// Source type definition.\n    Type(TypeDefinition),\n}\n\nimpl ParseSource {\n    /// Get the identity of the source\n    pub fn ident(&self) -> String {\n        match self {\n            Self::Contract(contract) => contract.name.safe_unwrap().name.to_owned(),\n            Self::Variable(var) => var.name.safe_unwrap().name.to_owned(),\n            Self::Event(event) => event.name.safe_unwrap().name.to_owned(),\n            Self::Error(error) => error.name.safe_unwrap().name.to_owned(),\n            Self::Struct(structure) => structure.name.safe_unwrap().name.to_owned(),\n            Self::Enum(enumerable) => enumerable.name.safe_unwrap().name.to_owned(),\n            Self::Function(func) => {\n                func.name.as_ref().map_or(func.ty.to_string(), |n| n.name.to_owned())\n            }\n            Self::Type(ty) => ty.name.name.to_owned(),\n        }\n    }\n\n    /// Get the signature of the source (for functions, includes parameter types)\n    pub fn signature(&self) -> String {\n        match self {\n            Self::Function(func) => function_signature(func),\n            _ => self.ident(),\n        }\n    }\n\n    /// Get the range of this item in the source file.\n    pub fn range(&self) -> Range<usize> {\n        match self {\n            Self::Contract(contract) => contract.loc,\n            Self::Variable(var) => var.loc,\n            Self::Event(event) => event.loc,\n            Self::Error(error) => error.loc,\n            Self::Struct(structure) => structure.loc,\n            Self::Enum(enumerable) => enumerable.loc,\n            Self::Function(func) => func.loc_prototype,\n            Self::Type(ty) => ty.loc,\n        }\n        .range()\n    }\n}\n"
  },
  {
    "path": "crates/doc/src/parser/mod.rs",
    "content": "//! The parser module.\n\nuse crate::solang_ext::{Visitable, Visitor};\nuse itertools::Itertools;\nuse solang_parser::{\n    doccomment::{DocComment, parse_doccomments},\n    pt::{\n        Comment as SolangComment, EnumDefinition, ErrorDefinition, EventDefinition,\n        FunctionDefinition, Identifier, Loc, SourceUnit, SourceUnitPart, StructDefinition,\n        TypeDefinition, VariableDefinition,\n    },\n};\n\n/// Parser error.\npub mod error;\nuse error::{ParserError, ParserResult};\n\n/// Parser item.\nmod item;\npub use item::{ParseItem, ParseSource};\n\n/// Doc comment.\nmod comment;\npub use comment::{Comment, CommentTag, Comments, CommentsRef};\n\n/// The documentation parser. This type implements a [Visitor] trait.\n///\n/// While walking the parse tree, [Parser] will collect relevant source items and corresponding\n/// doc comments. The resulting [ParseItem]s can be accessed by calling [Parser::items].\n#[derive(Debug, Default)]\npub struct Parser {\n    /// Initial comments from solang parser.\n    comments: Vec<SolangComment>,\n    /// Parser context.\n    context: ParserContext,\n    /// Parsed results.\n    items: Vec<ParseItem>,\n    /// Source file.\n    source: String,\n    /// Tab width used to format code.\n    tab_width: usize,\n}\n\n/// [Parser] context.\n#[derive(Debug, Default)]\nstruct ParserContext {\n    /// Current visited parent.\n    parent: Option<ParseItem>,\n    /// Current start pointer for parsing doc comments.\n    doc_start_loc: usize,\n}\n\nimpl Parser {\n    /// Create a new instance of [Parser].\n    pub fn new(comments: Vec<SolangComment>, source: String, tab_width: usize) -> Self {\n        Self { comments, source, tab_width, ..Default::default() }\n    }\n\n    /// Return the parsed items. Consumes the parser.\n    pub fn items(self) -> Vec<ParseItem> {\n        self.items\n    }\n\n    /// Visit the children elements with parent context.\n    /// This function memoizes the previous parent, sets the context\n    /// to a new one and invokes a visit function. The context will be reset\n    /// to the previous parent at the end of the function.\n    fn with_parent(\n        &mut self,\n        mut parent: ParseItem,\n        mut visit: impl FnMut(&mut Self) -> ParserResult<()>,\n    ) -> ParserResult<ParseItem> {\n        let curr = self.context.parent.take();\n        self.context.parent = Some(parent);\n        visit(self)?;\n        parent = self.context.parent.take().unwrap();\n        self.context.parent = curr;\n        Ok(parent)\n    }\n\n    /// Adds a child element to the parent item if it exists.\n    /// Otherwise the element will be added to a top-level items collection.\n    /// Moves the doc comment pointer to the end location of the child element.\n    fn add_element_to_parent(&mut self, source: ParseSource, loc: Loc) -> ParserResult<()> {\n        let child = self.new_item(source, loc.start())?;\n        if let Some(parent) = self.context.parent.as_mut() {\n            parent.children.push(child);\n        } else {\n            self.items.push(child);\n        }\n        self.context.doc_start_loc = loc.end();\n        Ok(())\n    }\n\n    /// Create new [ParseItem] with comments and formatted code.\n    fn new_item(&mut self, source: ParseSource, loc_start: usize) -> ParserResult<ParseItem> {\n        let docs = self.parse_docs(loc_start)?;\n        Ok(ParseItem::new(source).with_comments(docs).with_code(&self.source, self.tab_width))\n    }\n\n    /// Parse the doc comments from the current start location.\n    fn parse_docs(&mut self, end: usize) -> ParserResult<Comments> {\n        self.parse_docs_range(self.context.doc_start_loc, end)\n    }\n\n    /// Parse doc comments from the within specified range.\n    fn parse_docs_range(&mut self, start: usize, end: usize) -> ParserResult<Comments> {\n        let mut res = vec![];\n        for comment in parse_doccomments(&self.comments, start, end) {\n            match comment {\n                DocComment::Line { comment } => res.push(comment),\n                DocComment::Block { comments } => res.extend(comments),\n            }\n        }\n\n        // Filter out `@solidity` and empty tags\n        // See https://docs.soliditylang.org/en/v0.8.17/assembly.html#memory-safety\n        let res = res\n            .into_iter()\n            .filter(|c| c.tag.trim() != \"solidity\" && !c.tag.trim().is_empty())\n            .collect_vec();\n        Ok(res.into())\n    }\n}\n\nimpl Visitor for Parser {\n    type Error = ParserError;\n\n    fn visit_source_unit(&mut self, source_unit: &mut SourceUnit) -> ParserResult<()> {\n        for source in &mut source_unit.0 {\n            match source {\n                SourceUnitPart::ContractDefinition(def) => {\n                    // Create new contract parse item.\n                    let contract =\n                        self.new_item(ParseSource::Contract(def.clone()), def.loc.start())?;\n\n                    // Move the doc pointer to the contract location start.\n                    self.context.doc_start_loc = def.loc.start();\n\n                    // Parse child elements with current contract as parent\n                    let contract = self.with_parent(contract, |doc| {\n                        def.parts\n                            .iter_mut()\n                            .map(|d| d.visit(doc))\n                            .collect::<ParserResult<Vec<_>>>()?;\n                        Ok(())\n                    })?;\n\n                    // Move the doc pointer to the contract location end.\n                    self.context.doc_start_loc = def.loc.end();\n\n                    // Add contract to the parsed items.\n                    self.items.push(contract);\n                }\n                SourceUnitPart::FunctionDefinition(func) => self.visit_function(func)?,\n                SourceUnitPart::EventDefinition(event) => self.visit_event(event)?,\n                SourceUnitPart::ErrorDefinition(error) => self.visit_error(error)?,\n                SourceUnitPart::StructDefinition(structure) => self.visit_struct(structure)?,\n                SourceUnitPart::EnumDefinition(enumerable) => self.visit_enum(enumerable)?,\n                SourceUnitPart::VariableDefinition(var) => self.visit_var_definition(var)?,\n                SourceUnitPart::TypeDefinition(ty) => self.visit_type_definition(ty)?,\n                _ => {}\n            };\n        }\n\n        Ok(())\n    }\n\n    fn visit_enum(&mut self, enumerable: &mut EnumDefinition) -> ParserResult<()> {\n        self.add_element_to_parent(ParseSource::Enum(enumerable.clone()), enumerable.loc)\n    }\n\n    fn visit_var_definition(&mut self, var: &mut VariableDefinition) -> ParserResult<()> {\n        self.add_element_to_parent(ParseSource::Variable(var.clone()), var.loc)\n    }\n\n    fn visit_function(&mut self, func: &mut FunctionDefinition) -> ParserResult<()> {\n        // If the function parameter doesn't have a name, try to set it with\n        // `@custom:name` tag if any was provided\n        let mut start_loc = func.loc.start();\n        for (loc, param) in &mut func.params {\n            if let Some(param) = param\n                && param.name.is_none()\n            {\n                let docs = self.parse_docs_range(start_loc, loc.end())?;\n                let name_tag = docs.iter().find(|c| c.tag == CommentTag::Custom(\"name\".to_owned()));\n                if let Some(name_tag) = name_tag\n                    && let Some(name) = name_tag.value.trim().split(' ').next()\n                {\n                    param.name = Some(Identifier { loc: Loc::Implicit, name: name.to_owned() })\n                }\n            }\n            start_loc = loc.end();\n        }\n\n        self.add_element_to_parent(ParseSource::Function(func.clone()), func.loc)\n    }\n\n    fn visit_struct(&mut self, structure: &mut StructDefinition) -> ParserResult<()> {\n        self.add_element_to_parent(ParseSource::Struct(structure.clone()), structure.loc)\n    }\n\n    fn visit_event(&mut self, event: &mut EventDefinition) -> ParserResult<()> {\n        self.add_element_to_parent(ParseSource::Event(event.clone()), event.loc)\n    }\n\n    fn visit_error(&mut self, error: &mut ErrorDefinition) -> ParserResult<()> {\n        self.add_element_to_parent(ParseSource::Error(error.clone()), error.loc)\n    }\n\n    fn visit_type_definition(&mut self, def: &mut TypeDefinition) -> ParserResult<()> {\n        self.add_element_to_parent(ParseSource::Type(def.clone()), def.loc)\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use solang_parser::parse;\n\n    fn parse_source(src: &str) -> Vec<ParseItem> {\n        let (mut source, comments) = parse(src, 0).expect(\"failed to parse source\");\n        let mut doc = Parser::new(comments, src.to_owned(), 4);\n        source.visit(&mut doc).expect(\"failed to visit source\");\n        doc.items()\n    }\n\n    macro_rules! test_single_unit {\n        ($test:ident, $src:expr, $variant:ident $identity:expr) => {\n            #[test]\n            fn $test() {\n                let items = parse_source($src);\n                assert_eq!(items.len(), 1);\n                let item = items.first().unwrap();\n                assert!(item.comments.is_empty());\n                assert!(item.children.is_empty());\n                assert_eq!(item.source.ident(), $identity);\n                assert!(matches!(item.source, ParseSource::$variant(_)));\n            }\n        };\n    }\n\n    #[test]\n    fn empty_source() {\n        assert_eq!(parse_source(\"\"), vec![]);\n    }\n\n    test_single_unit!(single_function, \"function someFn() { }\", Function \"someFn\");\n    test_single_unit!(single_variable, \"uint256 constant VALUE = 0;\", Variable \"VALUE\");\n    test_single_unit!(single_event, \"event SomeEvent();\", Event \"SomeEvent\");\n    test_single_unit!(single_error, \"error SomeError();\", Error \"SomeError\");\n    test_single_unit!(single_struct, \"struct SomeStruct { }\", Struct \"SomeStruct\");\n    test_single_unit!(single_enum, \"enum SomeEnum { SOME, OTHER }\", Enum \"SomeEnum\");\n    test_single_unit!(single_contract, \"contract Contract { }\", Contract \"Contract\");\n\n    #[test]\n    fn multiple_shallow_contracts() {\n        let items = parse_source(\n            r\"\n            contract A { }\n            contract B { }\n            contract C { }\n        \",\n        );\n        assert_eq!(items.len(), 3);\n\n        let first_item = items.first().unwrap();\n        assert!(matches!(first_item.source, ParseSource::Contract(_)));\n        assert_eq!(first_item.source.ident(), \"A\");\n\n        let first_item = items.get(1).unwrap();\n        assert!(matches!(first_item.source, ParseSource::Contract(_)));\n        assert_eq!(first_item.source.ident(), \"B\");\n\n        let first_item = items.get(2).unwrap();\n        assert!(matches!(first_item.source, ParseSource::Contract(_)));\n        assert_eq!(first_item.source.ident(), \"C\");\n    }\n\n    #[test]\n    fn contract_with_children_items() {\n        let items = parse_source(\n            r\"\n            event TopLevelEvent();\n\n            contract Contract {\n                event ContractEvent();\n                error ContractError();\n                struct ContractStruct { }\n                enum ContractEnum { }\n\n                uint256 constant CONTRACT_CONSTANT = 0;\n                bool contractVar;\n\n                function contractFunction(uint256) external returns (uint256) {\n                    bool localVar; // must be ignored\n                }\n            }\n        \",\n        );\n\n        assert_eq!(items.len(), 2);\n\n        let event = items.first().unwrap();\n        assert!(event.comments.is_empty());\n        assert!(event.children.is_empty());\n        assert_eq!(event.source.ident(), \"TopLevelEvent\");\n        assert!(matches!(event.source, ParseSource::Event(_)));\n\n        let contract = items.get(1).unwrap();\n        assert!(contract.comments.is_empty());\n        assert_eq!(contract.children.len(), 7);\n        assert_eq!(contract.source.ident(), \"Contract\");\n        assert!(matches!(contract.source, ParseSource::Contract(_)));\n        assert!(contract.children.iter().all(|ch| ch.children.is_empty()));\n        assert!(contract.children.iter().all(|ch| ch.comments.is_empty()));\n    }\n\n    #[test]\n    fn contract_with_fallback() {\n        let items = parse_source(\n            r\"\n            contract Contract {\n                fallback() external payable {}\n            }\n        \",\n        );\n\n        assert_eq!(items.len(), 1);\n\n        let contract = items.first().unwrap();\n        assert!(contract.comments.is_empty());\n        assert_eq!(contract.children.len(), 1);\n        assert_eq!(contract.source.ident(), \"Contract\");\n        assert!(matches!(contract.source, ParseSource::Contract(_)));\n\n        let fallback = contract.children.first().unwrap();\n        assert_eq!(fallback.source.ident(), \"fallback\");\n        assert!(matches!(fallback.source, ParseSource::Function(_)));\n    }\n\n    #[test]\n    fn contract_with_doc_comments() {\n        let items = parse_source(\n            r\"\n            pragma solidity ^0.8.19;\n            /// @name Test\n            ///  no tag\n            ///@notice    Cool contract\n            ///   @  dev     This is not a dev tag\n            /**\n             * @dev line one\n             *    line 2\n             */\n            contract Test {\n                /** my function\n                      i like whitespace\n            */\n                function test() {}\n            }\n        \",\n        );\n\n        assert_eq!(items.len(), 1);\n\n        let contract = items.first().unwrap();\n        assert_eq!(contract.comments.len(), 2);\n        assert_eq!(\n            *contract.comments.first().unwrap(),\n            Comment::new(CommentTag::Notice, \"Cool contract\".to_owned())\n        );\n        assert_eq!(\n            *contract.comments.get(1).unwrap(),\n            Comment::new(CommentTag::Dev, \"line one\\nline 2\".to_owned())\n        );\n\n        let function = contract.children.first().unwrap();\n        assert_eq!(\n            *function.comments.first().unwrap(),\n            Comment::new(CommentTag::Notice, \"my function\\ni like whitespace\".to_owned())\n        );\n    }\n}\n"
  },
  {
    "path": "crates/doc/src/preprocessor/contract_inheritance.rs",
    "content": "use super::{Preprocessor, PreprocessorId};\nuse crate::{\n    Document, ParseSource, PreprocessorOutput, document::DocumentContent, solang_ext::SafeUnwrap,\n};\nuse alloy_primitives::map::HashMap;\nuse std::path::PathBuf;\n\n/// [ContractInheritance] preprocessor id.\npub const CONTRACT_INHERITANCE_ID: PreprocessorId = PreprocessorId(\"contract_inheritance\");\n\n/// The contract inheritance preprocessor.\n///\n/// It matches the documents with inner [`ParseSource::Contract`](crate::ParseSource) elements,\n/// iterates over their [Base](solang_parser::pt::Base)s and attempts\n/// to link them with the paths of the other contract documents.\n///\n/// This preprocessor writes to [Document]'s context.\n#[derive(Debug, Default)]\npub struct ContractInheritance {\n    /// Whether to capture inherited contracts from libraries.\n    pub include_libraries: bool,\n}\n\nimpl Preprocessor for ContractInheritance {\n    fn id(&self) -> PreprocessorId {\n        CONTRACT_INHERITANCE_ID\n    }\n\n    fn preprocess(&self, documents: Vec<Document>) -> Result<Vec<Document>, eyre::Error> {\n        for document in &documents {\n            if let DocumentContent::Single(ref item) = document.content\n                && let ParseSource::Contract(ref contract) = item.source\n            {\n                let mut links = HashMap::default();\n\n                // Attempt to match bases to other contracts\n                for base in &contract.base {\n                    let base_ident = base.name.identifiers.last().unwrap().name.clone();\n                    if let Some(linked) = self.try_link_base(&base_ident, &documents) {\n                        links.insert(base_ident, linked);\n                    }\n                }\n\n                if !links.is_empty() {\n                    // Write to context\n                    document.add_context(self.id(), PreprocessorOutput::ContractInheritance(links));\n                }\n            }\n        }\n\n        Ok(documents)\n    }\n}\n\nimpl ContractInheritance {\n    fn try_link_base(&self, base: &str, documents: &Vec<Document>) -> Option<PathBuf> {\n        for candidate in documents {\n            if candidate.from_library && !self.include_libraries {\n                continue;\n            }\n            if let DocumentContent::Single(ref item) = candidate.content\n                && let ParseSource::Contract(ref contract) = item.source\n                && base == contract.name.safe_unwrap().name\n            {\n                return Some(candidate.relative_output_path().to_path_buf());\n            }\n        }\n        None\n    }\n}\n"
  },
  {
    "path": "crates/doc/src/preprocessor/deployments.rs",
    "content": "use super::{Preprocessor, PreprocessorId};\nuse crate::{Document, PreprocessorOutput};\nuse alloy_primitives::Address;\nuse std::{\n    fs,\n    path::{Path, PathBuf},\n};\n\n/// [Deployments] preprocessor id.\npub const DEPLOYMENTS_ID: PreprocessorId = PreprocessorId(\"deployments\");\n\n/// The deployments preprocessor.\n///\n/// This preprocessor writes to [Document]'s context.\n#[derive(Debug)]\npub struct Deployments {\n    /// The project root.\n    pub root: PathBuf,\n    /// The deployments directory.\n    pub deployments: Option<PathBuf>,\n}\n\n/// A contract deployment.\n#[derive(Clone, Debug, serde::Deserialize)]\npub struct Deployment {\n    /// The contract address\n    pub address: Address,\n    /// The network name\n    pub network: Option<String>,\n}\n\nimpl Preprocessor for Deployments {\n    fn id(&self) -> PreprocessorId {\n        DEPLOYMENTS_ID\n    }\n\n    fn preprocess(&self, documents: Vec<Document>) -> Result<Vec<Document>, eyre::Error> {\n        let deployments_dir =\n            self.root.join(self.deployments.as_deref().unwrap_or(Path::new(\"deployments\")));\n\n        // Gather all networks from the deployments directory.\n        let networks = fs::read_dir(&deployments_dir)?\n            .map(|entry| {\n                let entry = entry?;\n                let path = entry.path();\n                if entry.file_type()?.is_dir() {\n                    entry\n                        .file_name()\n                        .into_string()\n                        .map_err(|e| eyre::eyre!(\"failed to extract directory name: {e:?}\"))\n                } else {\n                    eyre::bail!(\"not a directory: {}\", path.display())\n                }\n            })\n            .collect::<Result<Vec<_>, _>>()?;\n\n        // Iterate over all documents to find any deployments.\n        for document in &documents {\n            let mut deployments = Vec::default();\n\n            // Iterate over all networks and check if there is a deployment for the given contract.\n            for network in &networks {\n                // Clone the item path of the document and change it from \".sol\" -> \".json\"\n                let mut item_path_clone = document.item_path.clone();\n                item_path_clone.set_extension(\"json\");\n\n                // Determine the path of the deployment artifact relative to the root directory.\n                let deployment_path =\n                    deployments_dir.join(network).join(item_path_clone.file_name().ok_or_else(\n                        || eyre::eyre!(\"Failed to extract file name from item path\"),\n                    )?);\n\n                // If the deployment file for the given contract is found, add the deployment\n                // address to the document context.\n                let mut deployment: Deployment =\n                    serde_json::from_str(&fs::read_to_string(deployment_path)?)?;\n                deployment.network = Some(network.clone());\n                deployments.push(deployment);\n            }\n\n            // If there are any deployments for the given contract, add them to the document\n            // context.\n            if !deployments.is_empty() {\n                document.add_context(self.id(), PreprocessorOutput::Deployments(deployments));\n            }\n        }\n\n        Ok(documents)\n    }\n}\n"
  },
  {
    "path": "crates/doc/src/preprocessor/git_source.rs",
    "content": "use super::{Preprocessor, PreprocessorId};\nuse crate::{Document, PreprocessorOutput};\nuse std::path::PathBuf;\n\n/// [GitSource] preprocessor id.\npub const GIT_SOURCE_ID: PreprocessorId = PreprocessorId(\"git_source\");\n\n/// The git source preprocessor.\n///\n/// This preprocessor writes to [Document]'s context.\n#[derive(Debug)]\npub struct GitSource {\n    /// The project root.\n    pub root: PathBuf,\n    /// The current commit hash.\n    pub commit: Option<String>,\n    /// The repository url.\n    pub repository: Option<String>,\n}\n\nimpl Preprocessor for GitSource {\n    fn id(&self) -> PreprocessorId {\n        GIT_SOURCE_ID\n    }\n\n    fn preprocess(&self, documents: Vec<Document>) -> Result<Vec<Document>, eyre::Error> {\n        if let Some(ref repo) = self.repository {\n            let repo = repo.trim_end_matches('/');\n            let commit = self.commit.as_deref().unwrap_or(\"master\");\n            for document in &documents {\n                if document.from_library {\n                    continue;\n                }\n                let git_url = format!(\n                    \"{repo}/blob/{commit}/{}\",\n                    document.item_path.strip_prefix(&self.root)?.display()\n                );\n                document.add_context(self.id(), PreprocessorOutput::GitSource(git_url));\n            }\n        }\n\n        Ok(documents)\n    }\n}\n"
  },
  {
    "path": "crates/doc/src/preprocessor/infer_hyperlinks.rs",
    "content": "use super::{Preprocessor, PreprocessorId};\nuse crate::{Comments, Document, ParseItem, ParseSource, solang_ext::SafeUnwrap};\nuse regex::{Captures, Match, Regex};\nuse std::{\n    borrow::Cow,\n    path::{Path, PathBuf},\n    sync::LazyLock,\n};\n\n/// A regex that matches `{identifier-part}` placeholders\n///\n/// Overloaded functions are referenced by including the exact function arguments in the `part`\n/// section of the placeholder.\nstatic RE_INLINE_LINK: LazyLock<Regex> = LazyLock::new(|| {\n    Regex::new(r\"(?m)(\\{(?P<xref>xref-)?(?P<identifier>[a-zA-Z_][0-9a-zA-Z_]*)(-(?P<part>[a-zA-Z_][0-9a-zA-Z_-]*))?}(\\[(?P<link>(.*?))\\])?)\").unwrap()\n});\n\n/// [InferInlineHyperlinks] preprocessor id.\npub const INFER_INLINE_HYPERLINKS_ID: PreprocessorId = PreprocessorId(\"infer inline hyperlinks\");\n\n/// The infer hyperlinks preprocessor tries to map @dev tags to referenced items\n/// Traverses the documents and attempts to find referenced items\n/// comments for dev comment tags.\n///\n/// This preprocessor replaces inline links in comments with the links to the referenced items.\n#[derive(Debug, Default)]\n#[non_exhaustive]\npub struct InferInlineHyperlinks;\n\nimpl Preprocessor for InferInlineHyperlinks {\n    fn id(&self) -> PreprocessorId {\n        INFER_INLINE_HYPERLINKS_ID\n    }\n\n    fn preprocess(&self, mut documents: Vec<Document>) -> Result<Vec<Document>, eyre::Error> {\n        // traverse all comments and try to match inline links and replace with inline links for\n        // markdown\n        let mut docs = Vec::with_capacity(documents.len());\n        while !documents.is_empty() {\n            let mut document = documents.remove(0);\n            let target_path = document.relative_output_path().to_path_buf();\n            for idx in 0..document.content.len() {\n                let (mut comments, item_children_len) = {\n                    let item = document.content.get_mut(idx).unwrap();\n                    let comments = std::mem::take(&mut item.comments);\n                    let children = item.children.len();\n                    (comments, children)\n                };\n                Self::inline_doc_links(&documents, &target_path, &mut comments, &document);\n                document.content.get_mut(idx).unwrap().comments = comments;\n\n                // we also need to iterate over all child items\n                // This is a bit horrible but we need to traverse all items in all documents\n                for child_idx in 0..item_children_len {\n                    let mut comments = {\n                        let item = document.content.get_mut(idx).unwrap();\n\n                        std::mem::take(&mut item.children[child_idx].comments)\n                    };\n                    Self::inline_doc_links(&documents, &target_path, &mut comments, &document);\n                    document.content.get_mut(idx).unwrap().children[child_idx].comments = comments;\n                }\n            }\n\n            docs.push(document);\n        }\n\n        Ok(docs)\n    }\n}\n\nimpl InferInlineHyperlinks {\n    /// Finds the first match for the given link.\n    ///\n    /// All items get their own section in the markdown file.\n    /// This section uses the identifier of the item: `#functionname`\n    ///\n    /// Note: the target path is the relative path to the markdown file.\n    fn find_match<'a>(\n        link: &InlineLink<'a>,\n        target_path: &Path,\n        items: impl Iterator<Item = &'a ParseItem>,\n    ) -> Option<InlineLinkTarget<'a>> {\n        for item in items {\n            match &item.source {\n                ParseSource::Contract(contract) => {\n                    let name = &contract.name.safe_unwrap().name;\n                    if name == link.identifier {\n                        if link.part.is_none() {\n                            return Some(InlineLinkTarget::borrowed(\n                                name,\n                                target_path.to_path_buf(),\n                            ));\n                        }\n                        // try to find the referenced item in the contract's children\n                        return Self::find_match(link, target_path, item.children.iter());\n                    }\n                }\n                ParseSource::Function(fun) => {\n                    // TODO: handle overloaded functions\n                    // functions can be overloaded so we need to keep track of how many matches we\n                    // have so we can match the correct one\n                    if let Some(id) = &fun.name {\n                        // Note: constructors don't have a name\n                        if id.name == link.ref_name() {\n                            return Some(InlineLinkTarget::borrowed(\n                                &id.name,\n                                target_path.to_path_buf(),\n                            ));\n                        }\n                    } else if link.ref_name() == \"constructor\" {\n                        return Some(InlineLinkTarget::borrowed(\n                            \"constructor\",\n                            target_path.to_path_buf(),\n                        ));\n                    }\n                }\n                ParseSource::Variable(_) => {}\n                ParseSource::Event(ev) => {\n                    let ev_name = &ev.name.safe_unwrap().name;\n                    if ev_name == link.ref_name() {\n                        return Some(InlineLinkTarget::borrowed(\n                            ev_name,\n                            target_path.to_path_buf(),\n                        ));\n                    }\n                }\n                ParseSource::Error(err) => {\n                    let err_name = &err.name.safe_unwrap().name;\n                    if err_name == link.ref_name() {\n                        return Some(InlineLinkTarget::borrowed(\n                            err_name,\n                            target_path.to_path_buf(),\n                        ));\n                    }\n                }\n                ParseSource::Struct(structdef) => {\n                    let struct_name = &structdef.name.safe_unwrap().name;\n                    if struct_name == link.ref_name() {\n                        return Some(InlineLinkTarget::borrowed(\n                            struct_name,\n                            target_path.to_path_buf(),\n                        ));\n                    }\n                }\n                ParseSource::Enum(_) => {}\n                ParseSource::Type(_) => {}\n            }\n        }\n\n        None\n    }\n\n    /// Attempts to convert inline links to markdown links.\n    fn inline_doc_links(\n        documents: &[Document],\n        target_path: &Path,\n        comments: &mut Comments,\n        parent: &Document,\n    ) {\n        // loop over all comments in the item\n        for comment in comments.iter_mut() {\n            let val = comment.value.clone();\n            // replace all links with inline markdown links\n            for link in InlineLink::captures(val.as_str()) {\n                let target = if link.is_external() {\n                    // find in all documents\n                    documents.iter().find_map(|doc| {\n                        Self::find_match(\n                            &link,\n                            doc.relative_output_path(),\n                            doc.content.iter_items().flat_map(|item| {\n                                Some(item).into_iter().chain(item.children.iter())\n                            }),\n                        )\n                    })\n                } else {\n                    // find matches in the document\n                    Self::find_match(\n                        &link,\n                        target_path,\n                        parent\n                            .content\n                            .iter_items()\n                            .flat_map(|item| Some(item).into_iter().chain(item.children.iter())),\n                    )\n                };\n                if let Some(target) = target {\n                    let display_value = link.markdown_link_display_value();\n                    let markdown_link = format!(\"[{display_value}]({target})\");\n                    // replace the link with the markdown link\n                    comment.value =\n                        comment.value.as_str().replacen(link.as_str(), markdown_link.as_str(), 1);\n                }\n            }\n        }\n    }\n}\n\nstruct InlineLinkTarget<'a> {\n    section: Cow<'a, str>,\n    target_path: PathBuf,\n}\n\nimpl<'a> InlineLinkTarget<'a> {\n    fn borrowed(section: &'a str, target_path: PathBuf) -> Self {\n        Self { section: Cow::Borrowed(section), target_path }\n    }\n}\n\nimpl std::fmt::Display for InlineLinkTarget<'_> {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        // NOTE: the url should be absolute for markdown and section names are lowercase\n        write!(f, \"/{}#{}\", self.target_path.display(), self.section.to_lowercase())\n    }\n}\n\n/// A parsed link to an item.\n#[derive(Debug)]\nstruct InlineLink<'a> {\n    outer: Match<'a>,\n    identifier: &'a str,\n    part: Option<&'a str>,\n    link: Option<&'a str>,\n}\n\nimpl<'a> InlineLink<'a> {\n    fn from_capture(cap: Captures<'a>) -> Option<Self> {\n        Some(Self {\n            outer: cap.get(1)?,\n            identifier: cap.name(\"identifier\")?.as_str(),\n            part: cap.name(\"part\").map(|m| m.as_str()),\n            link: cap.name(\"link\").map(|m| m.as_str()),\n        })\n    }\n\n    fn captures(s: &'a str) -> impl Iterator<Item = Self> + 'a {\n        RE_INLINE_LINK.captures_iter(s).filter_map(Self::from_capture)\n    }\n\n    /// Parses the first inline link.\n    #[allow(unused)]\n    fn capture(s: &'a str) -> Option<Self> {\n        let cap = RE_INLINE_LINK.captures(s)?;\n        Self::from_capture(cap)\n    }\n\n    /// Returns the name of the link\n    fn markdown_link_display_value(&self) -> Cow<'_, str> {\n        if let Some(link) = self.link {\n            Cow::Borrowed(link)\n        } else if let Some(part) = self.part {\n            Cow::Owned(format!(\"{}-{}\", self.identifier, part))\n        } else {\n            Cow::Borrowed(self.identifier)\n        }\n    }\n\n    /// Returns the name of the referenced item.\n    fn ref_name(&self) -> &str {\n        self.exact_identifier().split('-').next().unwrap()\n    }\n\n    fn exact_identifier(&self) -> &str {\n        let mut name = self.identifier;\n        if let Some(part) = self.part {\n            name = part;\n        }\n        name\n    }\n\n    /// Returns the content of the matched link.\n    fn as_str(&self) -> &str {\n        self.outer.as_str()\n    }\n\n    /// Returns true if the link is external.\n    fn is_external(&self) -> bool {\n        self.part.is_some()\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn parse_inline_links() {\n        let s = \"    {IERC165-supportsInterface}   \";\n        let cap = RE_INLINE_LINK.captures(s).unwrap();\n\n        let identifier = cap.name(\"identifier\").unwrap().as_str();\n        assert_eq!(identifier, \"IERC165\");\n        let part = cap.name(\"part\").unwrap().as_str();\n        assert_eq!(part, \"supportsInterface\");\n\n        let s = \"    {supportsInterface}   \";\n        let cap = RE_INLINE_LINK.captures(s).unwrap();\n\n        let identifier = cap.name(\"identifier\").unwrap().as_str();\n        assert_eq!(identifier, \"supportsInterface\");\n\n        let s = \"{xref-ERC721-_safeMint-address-uint256-}\";\n        let cap = RE_INLINE_LINK.captures(s).unwrap();\n\n        let identifier = cap.name(\"identifier\").unwrap().as_str();\n        assert_eq!(identifier, \"ERC721\");\n        let identifier = cap.name(\"xref\").unwrap().as_str();\n        assert_eq!(identifier, \"xref-\");\n        let identifier = cap.name(\"part\").unwrap().as_str();\n        assert_eq!(identifier, \"_safeMint-address-uint256-\");\n\n        let link = InlineLink::capture(s).unwrap();\n        assert_eq!(link.ref_name(), \"_safeMint\");\n        assert_eq!(link.as_str(), \"{xref-ERC721-_safeMint-address-uint256-}\");\n\n        let s = \"{xref-ERC721-_safeMint-address-uint256-}[`Named link`]\";\n        let link = InlineLink::capture(s).unwrap();\n        assert_eq!(link.link, Some(\"`Named link`\"));\n        assert_eq!(link.markdown_link_display_value(), \"`Named link`\");\n    }\n}\n"
  },
  {
    "path": "crates/doc/src/preprocessor/inheritdoc.rs",
    "content": "use super::{Preprocessor, PreprocessorId};\nuse crate::{\n    Comments, Document, ParseItem, ParseSource, PreprocessorOutput, document::DocumentContent,\n    solang_ext::SafeUnwrap,\n};\nuse alloy_primitives::map::HashMap;\n\n/// [`Inheritdoc`] preprocessor ID.\npub const INHERITDOC_ID: PreprocessorId = PreprocessorId(\"inheritdoc\");\n\n/// The inheritdoc preprocessor.\n/// Traverses the documents and attempts to find inherited\n/// comments for inheritdoc comment tags.\n///\n/// This preprocessor writes to [Document]'s context.\n#[derive(Debug, Default)]\n#[non_exhaustive]\npub struct Inheritdoc;\n\nimpl Preprocessor for Inheritdoc {\n    fn id(&self) -> PreprocessorId {\n        INHERITDOC_ID\n    }\n\n    fn preprocess(&self, documents: Vec<Document>) -> Result<Vec<Document>, eyre::Error> {\n        for document in &documents {\n            if let DocumentContent::Single(ref item) = document.content {\n                let context = self.visit_item(item, &documents);\n                if !context.is_empty() {\n                    document.add_context(self.id(), PreprocessorOutput::Inheritdoc(context));\n                }\n            }\n        }\n\n        Ok(documents)\n    }\n}\n\nimpl Inheritdoc {\n    fn visit_item(&self, item: &ParseItem, documents: &Vec<Document>) -> HashMap<String, Comments> {\n        let mut context = HashMap::default();\n\n        // Match for the item first.\n        let matched = item\n            .comments\n            .find_inheritdoc_base()\n            .and_then(|base| self.try_match_inheritdoc(base, &item.source, documents));\n        if let Some((key, comments)) = matched {\n            context.insert(key, comments);\n        }\n\n        // Match item's children.\n        for ch in &item.children {\n            let matched = ch\n                .comments\n                .find_inheritdoc_base()\n                .and_then(|base| self.try_match_inheritdoc(base, &ch.source, documents));\n            if let Some((key, comments)) = matched {\n                context.insert(key, comments);\n            }\n        }\n\n        context\n    }\n\n    fn try_match_inheritdoc(\n        &self,\n        base: &str,\n        source: &ParseSource,\n        documents: &Vec<Document>,\n    ) -> Option<(String, Comments)> {\n        for candidate in documents {\n            if let DocumentContent::Single(ref item) = candidate.content\n                && let ParseSource::Contract(ref contract) = item.source\n                && base == contract.name.safe_unwrap().name\n            {\n                // Not matched for the contract because it's a noop\n                // https://docs.soliditylang.org/en/v0.8.17/natspec-format.html#tags\n\n                for children in &item.children {\n                    // Match using signature for functions (includes parameter types for overloads)\n                    if source.signature() == children.source.signature() {\n                        let key = format!(\"{}.{}\", base, source.signature());\n                        return Some((key, children.comments.clone()));\n                    }\n                }\n            }\n        }\n        None\n    }\n}\n"
  },
  {
    "path": "crates/doc/src/preprocessor/mod.rs",
    "content": "//! Module containing documentation preprocessors.\n\nuse crate::{Comments, Document};\nuse alloy_primitives::map::HashMap;\nuse std::{fmt::Debug, path::PathBuf};\n\nmod contract_inheritance;\npub use contract_inheritance::{CONTRACT_INHERITANCE_ID, ContractInheritance};\n\nmod inheritdoc;\npub use inheritdoc::{INHERITDOC_ID, Inheritdoc};\n\nmod infer_hyperlinks;\npub use infer_hyperlinks::{INFER_INLINE_HYPERLINKS_ID, InferInlineHyperlinks};\n\nmod git_source;\npub use git_source::{GIT_SOURCE_ID, GitSource};\n\nmod deployments;\npub use deployments::{DEPLOYMENTS_ID, Deployment, Deployments};\n\n/// The preprocessor id.\n#[derive(Debug, PartialEq, Eq, Hash)]\npub struct PreprocessorId(&'static str);\n\n/// Preprocessor output.\n/// Wraps all existing preprocessor outputs\n/// in a single abstraction.\n#[derive(Clone, Debug)]\npub enum PreprocessorOutput {\n    /// The contract inheritance output.\n    /// The map of contract base idents to the path of the base contract.\n    ContractInheritance(HashMap<String, PathBuf>),\n    /// The inheritdoc output.\n    /// The map of inherited item keys to their comments.\n    Inheritdoc(HashMap<String, Comments>),\n    /// The git source output.\n    /// The git url of the item path.\n    GitSource(String),\n    /// The deployments output.\n    /// The deployment address of the item path.\n    Deployments(Vec<Deployment>),\n}\n\n/// Trait for preprocessing and/or modifying existing documents\n/// before writing the to disk.\npub trait Preprocessor: Debug {\n    /// The id of the preprocessor.\n    /// Used to write data to document context.\n    fn id(&self) -> PreprocessorId;\n\n    /// Preprocess the collection of documents\n    fn preprocess(&self, documents: Vec<Document>) -> Result<Vec<Document>, eyre::Error>;\n}\n"
  },
  {
    "path": "crates/doc/src/solang_ext/ast_eq.rs",
    "content": "use alloy_primitives::{Address, I256, U256};\nuse solang_parser::pt::*;\nuse std::str::FromStr;\n\n/// Helper to convert a string number into a comparable one\nfn to_num(string: &str) -> I256 {\n    if string.is_empty() {\n        return I256::ZERO;\n    }\n    string.replace('_', \"\").trim().parse().unwrap()\n}\n\n/// Helper to convert the fractional part of a number into a comparable one.\n/// This will reverse the number so that 0's can be ignored\nfn to_num_reversed(string: &str) -> U256 {\n    if string.is_empty() {\n        return U256::from(0);\n    }\n    string.replace('_', \"\").trim().chars().rev().collect::<String>().parse().unwrap()\n}\n\n/// Helper to filter [ParameterList] to omit empty\n/// parameters\nfn filter_params(list: &ParameterList) -> ParameterList {\n    list.iter().filter(|(_, param)| param.is_some()).cloned().collect::<Vec<_>>()\n}\n\n/// Check if two ParseTrees are equal ignoring location information or ordering if ordering does\n/// not matter\npub trait AstEq {\n    fn ast_eq(&self, other: &Self) -> bool;\n}\n\nimpl AstEq for Loc {\n    fn ast_eq(&self, _other: &Self) -> bool {\n        true\n    }\n}\n\nimpl AstEq for IdentifierPath {\n    fn ast_eq(&self, other: &Self) -> bool {\n        self.identifiers.ast_eq(&other.identifiers)\n    }\n}\n\nimpl AstEq for SourceUnit {\n    fn ast_eq(&self, other: &Self) -> bool {\n        self.0.ast_eq(&other.0)\n    }\n}\n\nimpl AstEq for VariableDefinition {\n    fn ast_eq(&self, other: &Self) -> bool {\n        let sorted_attrs = |def: &Self| {\n            let mut attrs = def.attrs.clone();\n            attrs.sort();\n            attrs\n        };\n        self.ty.ast_eq(&other.ty)\n            && self.name.ast_eq(&other.name)\n            && self.initializer.ast_eq(&other.initializer)\n            && sorted_attrs(self).ast_eq(&sorted_attrs(other))\n    }\n}\n\nimpl AstEq for FunctionDefinition {\n    fn ast_eq(&self, other: &Self) -> bool {\n        // attributes\n        let sorted_attrs = |def: &Self| {\n            let mut attrs = def.attributes.clone();\n            attrs.sort();\n            attrs\n        };\n\n        // params\n        let left_params = filter_params(&self.params);\n        let right_params = filter_params(&other.params);\n        let left_returns = filter_params(&self.returns);\n        let right_returns = filter_params(&other.returns);\n\n        self.ty.ast_eq(&other.ty)\n            && self.name.ast_eq(&other.name)\n            && left_params.ast_eq(&right_params)\n            && self.return_not_returns.ast_eq(&other.return_not_returns)\n            && left_returns.ast_eq(&right_returns)\n            && self.body.ast_eq(&other.body)\n            && sorted_attrs(self).ast_eq(&sorted_attrs(other))\n    }\n}\n\nimpl AstEq for Base {\n    fn ast_eq(&self, other: &Self) -> bool {\n        self.name.ast_eq(&other.name)\n            && self.args.clone().unwrap_or_default().ast_eq(&other.args.clone().unwrap_or_default())\n    }\n}\n\nimpl<T> AstEq for Vec<T>\nwhere\n    T: AstEq,\n{\n    fn ast_eq(&self, other: &Self) -> bool {\n        if self.len() != other.len() {\n            false\n        } else {\n            self.iter().zip(other.iter()).all(|(left, right)| left.ast_eq(right))\n        }\n    }\n}\n\nimpl<T> AstEq for Option<T>\nwhere\n    T: AstEq,\n{\n    fn ast_eq(&self, other: &Self) -> bool {\n        match (self, other) {\n            (Some(left), Some(right)) => left.ast_eq(right),\n            (None, None) => true,\n            _ => false,\n        }\n    }\n}\n\nimpl<T> AstEq for Box<T>\nwhere\n    T: AstEq,\n{\n    fn ast_eq(&self, other: &Self) -> bool {\n        T::ast_eq(self, other)\n    }\n}\n\nimpl AstEq for () {\n    fn ast_eq(&self, _other: &Self) -> bool {\n        true\n    }\n}\n\nimpl<T> AstEq for &T\nwhere\n    T: AstEq,\n{\n    fn ast_eq(&self, other: &Self) -> bool {\n        T::ast_eq(self, other)\n    }\n}\n\nimpl AstEq for String {\n    fn ast_eq(&self, other: &Self) -> bool {\n        match (Address::from_str(self), Address::from_str(other)) {\n            (Ok(left), Ok(right)) => left == right,\n            _ => self == other,\n        }\n    }\n}\n\nmacro_rules! ast_eq_field {\n    (#[ast_eq_use($convert_func:ident)] $field:ident) => {\n        $convert_func($field)\n    };\n    ($field:ident) => {\n        $field\n    };\n}\n\nmacro_rules! gen_ast_eq_enum {\n    ($self:expr, $other:expr, $name:ident {\n        $($unit_variant:ident),* $(,)?\n        _\n        $($tuple_variant:ident ( $($(#[ast_eq_use($tuple_convert_func:ident)])? $tuple_field:ident),* $(,)? )),*  $(,)?\n        _\n        $($struct_variant:ident { $($(#[ast_eq_use($struct_convert_func:ident)])? $struct_field:ident),* $(,)? }),*  $(,)?\n    }) => {\n        match $self {\n            $($name::$unit_variant => gen_ast_eq_enum!($other, $name, $unit_variant),)*\n            $($name::$tuple_variant($($tuple_field),*) =>\n                gen_ast_eq_enum!($other, $name, $tuple_variant ($($(#[ast_eq_use($tuple_convert_func)])? $tuple_field),*)),)*\n            $($name::$struct_variant { $($struct_field),* } =>\n                gen_ast_eq_enum!($other, $name, $struct_variant {$($(#[ast_eq_use($struct_convert_func)])? $struct_field),*}),)*\n        }\n    };\n    ($other:expr, $name:ident, $unit_variant:ident) => {\n        {\n            matches!($other, $name::$unit_variant)\n        }\n    };\n    ($other:expr, $name:ident, $tuple_variant:ident ( $($(#[ast_eq_use($tuple_convert_func:ident)])? $tuple_field:ident),* $(,)? ) ) => {\n        {\n            let left = ($(ast_eq_field!($(#[ast_eq_use($tuple_convert_func)])? $tuple_field)),*);\n            if let $name::$tuple_variant($($tuple_field),*) = $other {\n                let right = ($(ast_eq_field!($(#[ast_eq_use($tuple_convert_func)])? $tuple_field)),*);\n                left.ast_eq(&right)\n            } else {\n                false\n            }\n        }\n    };\n    ($other:expr, $name:ident, $struct_variant:ident { $($(#[ast_eq_use($struct_convert_func:ident)])? $struct_field:ident),* $(,)? } ) => {\n        {\n            let left = ($(ast_eq_field!($(#[ast_eq_use($struct_convert_func)])? $struct_field)),*);\n            if let $name::$struct_variant { $($struct_field),* } = $other {\n                let right = ($(ast_eq_field!($(#[ast_eq_use($struct_convert_func)])? $struct_field)),*);\n                left.ast_eq(&right)\n            } else {\n                false\n            }\n        }\n    };\n}\n\nmacro_rules! wrap_in_box {\n    ($stmt:expr, $loc:expr) => {\n        if !matches!(**$stmt, Statement::Block { .. }) {\n            Box::new(Statement::Block {\n                loc: $loc,\n                unchecked: false,\n                statements: vec![*$stmt.clone()],\n            })\n        } else {\n            $stmt.clone()\n        }\n    };\n}\n\nimpl AstEq for Statement {\n    fn ast_eq(&self, other: &Self) -> bool {\n        match self {\n            Self::If(loc, expr, stmt1, stmt2) => {\n                #[expect(clippy::borrowed_box)]\n                let wrap_if = |stmt1: &Box<Self>, stmt2: &Option<Box<Self>>| {\n                    (\n                        wrap_in_box!(stmt1, *loc),\n                        stmt2.as_ref().map(|stmt2| {\n                            if matches!(**stmt2, Self::If(..)) {\n                                stmt2.clone()\n                            } else {\n                                wrap_in_box!(stmt2, *loc)\n                            }\n                        }),\n                    )\n                };\n                let (stmt1, stmt2) = wrap_if(stmt1, stmt2);\n                let left = (loc, expr, &stmt1, &stmt2);\n                if let Self::If(loc, expr, stmt1, stmt2) = other {\n                    let (stmt1, stmt2) = wrap_if(stmt1, stmt2);\n                    let right = (loc, expr, &stmt1, &stmt2);\n                    left.ast_eq(&right)\n                } else {\n                    false\n                }\n            }\n            Self::While(loc, expr, stmt1) => {\n                let stmt1 = wrap_in_box!(stmt1, *loc);\n                let left = (loc, expr, &stmt1);\n                if let Self::While(loc, expr, stmt1) = other {\n                    let stmt1 = wrap_in_box!(stmt1, *loc);\n                    let right = (loc, expr, &stmt1);\n                    left.ast_eq(&right)\n                } else {\n                    false\n                }\n            }\n            Self::DoWhile(loc, stmt1, expr) => {\n                let stmt1 = wrap_in_box!(stmt1, *loc);\n                let left = (loc, &stmt1, expr);\n                if let Self::DoWhile(loc, stmt1, expr) = other {\n                    let stmt1 = wrap_in_box!(stmt1, *loc);\n                    let right = (loc, &stmt1, expr);\n                    left.ast_eq(&right)\n                } else {\n                    false\n                }\n            }\n            Self::For(loc, stmt1, expr, stmt2, stmt3) => {\n                let stmt3 = stmt3.as_ref().map(|stmt3| wrap_in_box!(stmt3, *loc));\n                let left = (loc, stmt1, expr, stmt2, &stmt3);\n                if let Self::For(loc, stmt1, expr, stmt2, stmt3) = other {\n                    let stmt3 = stmt3.as_ref().map(|stmt3| wrap_in_box!(stmt3, *loc));\n                    let right = (loc, stmt1, expr, stmt2, &stmt3);\n                    left.ast_eq(&right)\n                } else {\n                    false\n                }\n            }\n            Self::Try(loc, expr, returns, catch) => {\n                let left_returns =\n                    returns.as_ref().map(|(params, stmt)| (filter_params(params), stmt));\n                let left = (loc, expr, left_returns, catch);\n                if let Self::Try(loc, expr, returns, catch) = other {\n                    let right_returns =\n                        returns.as_ref().map(|(params, stmt)| (filter_params(params), stmt));\n                    let right = (loc, expr, right_returns, catch);\n                    left.ast_eq(&right)\n                } else {\n                    false\n                }\n            }\n            _ => gen_ast_eq_enum!(self, other, Statement {\n                _\n                Args(loc, args),\n                Expression(loc, expr),\n                VariableDefinition(loc, decl, expr),\n                Continue(loc, ),\n                Break(loc, ),\n                Return(loc, expr),\n                Revert(loc, expr, expr2),\n                RevertNamedArgs(loc, expr, args),\n                Emit(loc, expr),\n                // provide overridden variants regardless\n                If(loc, expr, stmt1, stmt2),\n                While(loc, expr, stmt1),\n                DoWhile(loc, stmt1, expr),\n                For(loc, stmt1, expr, stmt2, stmt3),\n                Try(loc, expr, params, clause),\n                Error(loc)\n                _\n                Block {\n                    loc,\n                    unchecked,\n                    statements,\n                },\n                Assembly {\n                    loc,\n                    dialect,\n                    block,\n                    flags,\n                },\n            }),\n        }\n    }\n}\n\nmacro_rules! derive_ast_eq {\n    ($name:ident) => {\n        impl AstEq for $name {\n            fn ast_eq(&self, other: &Self) -> bool {\n                self == other\n            }\n        }\n    };\n    (($($index:tt $gen:tt),*)) => {\n        impl < $( $gen ),* > AstEq for ($($gen,)*) where $($gen: AstEq),* {\n            fn ast_eq(&self, other: &Self) -> bool {\n                $(\n                if !self.$index.ast_eq(&other.$index) {\n                    return false\n                }\n                )*\n                true\n            }\n        }\n    };\n    (struct $name:ident { $($field:ident),* $(,)? }) => {\n        impl AstEq for $name {\n            fn ast_eq(&self, other: &Self) -> bool {\n                let $name { $($field),* } = self;\n                let left = ($($field),*);\n                let $name { $($field),* } = other;\n                let right = ($($field),*);\n                left.ast_eq(&right)\n            }\n        }\n    };\n    (enum $name:ident {\n        $($unit_variant:ident),* $(,)?\n        _\n        $($tuple_variant:ident ( $($(#[ast_eq_use($tuple_convert_func:ident)])? $tuple_field:ident),* $(,)? )),*  $(,)?\n        _\n        $($struct_variant:ident { $($(#[ast_eq_use($struct_convert_func:ident)])? $struct_field:ident),* $(,)? }),*  $(,)?\n    }) => {\n        impl AstEq for $name {\n            fn ast_eq(&self, other: &Self) -> bool {\n                gen_ast_eq_enum!(self, other, $name {\n                    $($unit_variant),*\n                    _\n                    $($tuple_variant ( $($(#[ast_eq_use($tuple_convert_func)])? $tuple_field),* )),*\n                    _\n                    $($struct_variant { $($(#[ast_eq_use($struct_convert_func)])? $struct_field),* }),*\n                })\n            }\n        }\n    }\n}\n\nderive_ast_eq! { (0 A) }\nderive_ast_eq! { (0 A, 1 B) }\nderive_ast_eq! { (0 A, 1 B, 2 C) }\nderive_ast_eq! { (0 A, 1 B, 2 C, 3 D) }\nderive_ast_eq! { (0 A, 1 B, 2 C, 3 D, 4 E) }\nderive_ast_eq! { (0 A, 1 B, 2 C, 3 D, 4 E, 5 F) }\nderive_ast_eq! { (0 A, 1 B, 2 C, 3 D, 4 E, 5 F, 6 G) }\nderive_ast_eq! { bool }\nderive_ast_eq! { u8 }\nderive_ast_eq! { u16 }\nderive_ast_eq! { I256 }\nderive_ast_eq! { U256 }\nderive_ast_eq! { struct Identifier { loc, name } }\nderive_ast_eq! { struct HexLiteral { loc, hex } }\nderive_ast_eq! { struct StringLiteral { loc, unicode, string } }\nderive_ast_eq! { struct Parameter { loc, annotation, ty, storage, name } }\nderive_ast_eq! { struct NamedArgument { loc, name, expr } }\nderive_ast_eq! { struct YulBlock { loc, statements } }\nderive_ast_eq! { struct YulFunctionCall { loc, id, arguments } }\nderive_ast_eq! { struct YulFunctionDefinition { loc, id, params, returns, body } }\nderive_ast_eq! { struct YulSwitch { loc, condition, cases, default } }\nderive_ast_eq! { struct YulFor {\n    loc,\n    init_block,\n    condition,\n    post_block,\n    execution_block,\n}}\nderive_ast_eq! { struct YulTypedIdentifier { loc, id, ty } }\nderive_ast_eq! { struct VariableDeclaration { loc, ty, storage, name } }\nderive_ast_eq! { struct Using { loc, list, ty, global } }\nderive_ast_eq! { struct UsingFunction { loc, path, oper } }\nderive_ast_eq! { struct TypeDefinition { loc, name, ty } }\nderive_ast_eq! { struct ContractDefinition { loc, ty, name, base, layout, parts } }\nderive_ast_eq! { struct EventParameter { loc, ty, indexed, name } }\nderive_ast_eq! { struct ErrorParameter { loc, ty, name } }\nderive_ast_eq! { struct EventDefinition { loc, name, fields, anonymous } }\nderive_ast_eq! { struct ErrorDefinition { loc, keyword, name, fields } }\nderive_ast_eq! { struct StructDefinition { loc, name, fields } }\nderive_ast_eq! { struct EnumDefinition { loc, name, values } }\nderive_ast_eq! { struct Annotation { loc, id, value } }\nderive_ast_eq! { enum PragmaDirective {\n    _\n    Identifier(loc, id1, id2),\n    StringLiteral(loc, id, lit),\n    Version(loc, id, version),\n    _\n}}\nderive_ast_eq! { enum UsingList {\n    Error,\n    _\n    Library(expr),\n    Functions(exprs),\n    _\n}}\nderive_ast_eq! { enum UserDefinedOperator {\n    BitwiseAnd,\n    BitwiseNot,\n    Negate,\n    BitwiseOr,\n    BitwiseXor,\n    Add,\n    Divide,\n    Modulo,\n    Multiply,\n    Subtract,\n    Equal,\n    More,\n    MoreEqual,\n    Less,\n    LessEqual,\n    NotEqual,\n    _\n    _\n}}\nderive_ast_eq! { enum Visibility {\n    _\n    External(loc),\n    Public(loc),\n    Internal(loc),\n    Private(loc),\n    _\n}}\nderive_ast_eq! { enum Mutability {\n    _\n    Pure(loc),\n    View(loc),\n    Constant(loc),\n    Payable(loc),\n    _\n}}\nderive_ast_eq! { enum FunctionAttribute {\n    _\n    Mutability(muta),\n    Visibility(visi),\n    Virtual(loc),\n    Immutable(loc),\n    Override(loc, idents),\n    BaseOrModifier(loc, base),\n    Error(loc),\n    _\n}}\nderive_ast_eq! { enum StorageLocation {\n    _\n    Memory(loc),\n    Storage(loc),\n    Calldata(loc),\n    Transient(loc),\n    _\n}}\nderive_ast_eq! { enum Type {\n    Address,\n    AddressPayable,\n    Payable,\n    Bool,\n    Rational,\n    DynamicBytes,\n    String,\n    _\n    Int(int),\n    Uint(int),\n    Bytes(int),\n    _\n    Mapping{ loc, key, key_name, value, value_name },\n    Function { params, attributes, returns },\n}}\nderive_ast_eq! { enum Expression {\n    _\n    PostIncrement(loc, expr1),\n    PostDecrement(loc, expr1),\n    New(loc, expr1),\n    ArraySubscript(loc, expr1, expr2),\n    ArraySlice(\n        loc,\n        expr1,\n        expr2,\n        expr3,\n    ),\n    MemberAccess(loc, expr1, ident1),\n    FunctionCall(loc, expr1, exprs1),\n    FunctionCallBlock(loc, expr1, stmt),\n    NamedFunctionCall(loc, expr1, args),\n    Not(loc, expr1),\n    BitwiseNot(loc, expr1),\n    Delete(loc, expr1),\n    PreIncrement(loc, expr1),\n    PreDecrement(loc, expr1),\n    UnaryPlus(loc, expr1),\n    Negate(loc, expr1),\n    Power(loc, expr1, expr2),\n    Multiply(loc, expr1, expr2),\n    Divide(loc, expr1, expr2),\n    Modulo(loc, expr1, expr2),\n    Add(loc, expr1, expr2),\n    Subtract(loc, expr1, expr2),\n    ShiftLeft(loc, expr1, expr2),\n    ShiftRight(loc, expr1, expr2),\n    BitwiseAnd(loc, expr1, expr2),\n    BitwiseXor(loc, expr1, expr2),\n    BitwiseOr(loc, expr1, expr2),\n    Less(loc, expr1, expr2),\n    More(loc, expr1, expr2),\n    LessEqual(loc, expr1, expr2),\n    MoreEqual(loc, expr1, expr2),\n    Equal(loc, expr1, expr2),\n    NotEqual(loc, expr1, expr2),\n    And(loc, expr1, expr2),\n    Or(loc, expr1, expr2),\n    ConditionalOperator(loc, expr1, expr2, expr3),\n    Assign(loc, expr1, expr2),\n    AssignOr(loc, expr1, expr2),\n    AssignAnd(loc, expr1, expr2),\n    AssignXor(loc, expr1, expr2),\n    AssignShiftLeft(loc, expr1, expr2),\n    AssignShiftRight(loc, expr1, expr2),\n    AssignAdd(loc, expr1, expr2),\n    AssignSubtract(loc, expr1, expr2),\n    AssignMultiply(loc, expr1, expr2),\n    AssignDivide(loc, expr1, expr2),\n    AssignModulo(loc, expr1, expr2),\n    BoolLiteral(loc, bool1),\n    NumberLiteral(loc, #[ast_eq_use(to_num)] str1, #[ast_eq_use(to_num)] str2, unit),\n    RationalNumberLiteral(\n        loc,\n        #[ast_eq_use(to_num)] str1,\n        #[ast_eq_use(to_num_reversed)] str2,\n        #[ast_eq_use(to_num)] str3,\n        unit\n    ),\n    HexNumberLiteral(loc, str1, unit),\n    StringLiteral(strs1),\n    Type(loc, ty1),\n    HexLiteral(hexs1),\n    AddressLiteral(loc, str1),\n    Variable(ident1),\n    List(loc, params1),\n    ArrayLiteral(loc, exprs1),\n    Parenthesis(loc, expr)\n    _\n}}\nderive_ast_eq! { enum CatchClause {\n    _\n    Simple(param, ident, stmt),\n    Named(loc, ident, param, stmt),\n    _\n}}\nderive_ast_eq! { enum YulStatement {\n    _\n    Assign(loc, exprs, expr),\n    VariableDeclaration(loc, idents, expr),\n    If(loc, expr, block),\n    For(yul_for),\n    Switch(switch),\n    Leave(loc),\n    Break(loc),\n    Continue(loc),\n    Block(block),\n    FunctionDefinition(def),\n    FunctionCall(func),\n    Error(loc),\n    _\n}}\nderive_ast_eq! { enum YulExpression {\n    _\n    BoolLiteral(loc, boo, ident),\n    NumberLiteral(loc, string1, string2, ident),\n    HexNumberLiteral(loc, string, ident),\n    HexStringLiteral(hex, ident),\n    StringLiteral(string, ident),\n    Variable(ident),\n    FunctionCall(func),\n    SuffixAccess(loc, expr, ident),\n    _\n}}\nderive_ast_eq! { enum YulSwitchOptions {\n    _\n    Case(loc, expr, block),\n    Default(loc, block),\n    _\n}}\nderive_ast_eq! { enum SourceUnitPart {\n    _\n    ContractDefinition(def),\n    PragmaDirective(pragma),\n    ImportDirective(import),\n    EnumDefinition(def),\n    StructDefinition(def),\n    EventDefinition(def),\n    ErrorDefinition(def),\n    FunctionDefinition(def),\n    VariableDefinition(def),\n    TypeDefinition(def),\n    Using(using),\n    StraySemicolon(loc),\n    Annotation(annotation),\n    _\n}}\nderive_ast_eq! { enum ImportPath {\n    _\n    Filename(lit),\n    Path(path),\n    _\n}}\nderive_ast_eq! { enum Import {\n    _\n    Plain(string, loc),\n    GlobalSymbol(string, ident, loc),\n    Rename(string, idents, loc),\n    _\n}}\nderive_ast_eq! { enum FunctionTy {\n    Constructor,\n    Function,\n    Fallback,\n    Receive,\n    Modifier,\n    _\n    _\n}}\nderive_ast_eq! { enum ContractPart {\n    _\n    StructDefinition(def),\n    EventDefinition(def),\n    EnumDefinition(def),\n    ErrorDefinition(def),\n    VariableDefinition(def),\n    FunctionDefinition(def),\n    TypeDefinition(def),\n    StraySemicolon(loc),\n    Using(using),\n    Annotation(annotation),\n    _\n}}\nderive_ast_eq! { enum ContractTy {\n    _\n    Abstract(loc),\n    Contract(loc),\n    Interface(loc),\n    Library(loc),\n    _\n}}\nderive_ast_eq! { enum VariableAttribute {\n    _\n    Visibility(visi),\n    Constant(loc),\n    Immutable(loc),\n    Override(loc, idents),\n    StorageType(st),\n    StorageLocation(st),\n    _\n}}\n\n// Who cares\nimpl AstEq for StorageType {\n    fn ast_eq(&self, _other: &Self) -> bool {\n        true\n    }\n}\n\nimpl AstEq for VersionComparator {\n    fn ast_eq(&self, _other: &Self) -> bool {\n        true\n    }\n}\n"
  },
  {
    "path": "crates/doc/src/solang_ext/loc.rs",
    "content": "use solang_parser::pt;\nuse std::{borrow::Cow, rc::Rc, sync::Arc};\n\n/// Returns the code location.\n///\n/// Patched version of [`pt::CodeLocation`]: includes the block of a [`pt::FunctionDefinition`] in\n/// its `loc`.\npub trait CodeLocationExt {\n    /// Returns the code location of `self`.\n    fn loc(&self) -> pt::Loc;\n}\n\nimpl<T: ?Sized + CodeLocationExt> CodeLocationExt for &T {\n    fn loc(&self) -> pt::Loc {\n        (**self).loc()\n    }\n}\n\nimpl<T: ?Sized + CodeLocationExt> CodeLocationExt for &mut T {\n    fn loc(&self) -> pt::Loc {\n        (**self).loc()\n    }\n}\n\nimpl<T: ?Sized + ToOwned + CodeLocationExt> CodeLocationExt for Cow<'_, T> {\n    fn loc(&self) -> pt::Loc {\n        (**self).loc()\n    }\n}\n\nimpl<T: ?Sized + CodeLocationExt> CodeLocationExt for Box<T> {\n    fn loc(&self) -> pt::Loc {\n        (**self).loc()\n    }\n}\n\nimpl<T: ?Sized + CodeLocationExt> CodeLocationExt for Rc<T> {\n    fn loc(&self) -> pt::Loc {\n        (**self).loc()\n    }\n}\n\nimpl<T: ?Sized + CodeLocationExt> CodeLocationExt for Arc<T> {\n    fn loc(&self) -> pt::Loc {\n        (**self).loc()\n    }\n}\n\n// FunctionDefinition patch\nimpl CodeLocationExt for pt::FunctionDefinition {\n    #[inline]\n    #[track_caller]\n    fn loc(&self) -> pt::Loc {\n        let mut loc = self.loc;\n        if let Some(ref body) = self.body {\n            loc.use_end_from(&pt::CodeLocation::loc(body));\n        }\n        loc\n    }\n}\n\nimpl CodeLocationExt for pt::ContractPart {\n    #[inline]\n    #[track_caller]\n    fn loc(&self) -> pt::Loc {\n        match self {\n            Self::FunctionDefinition(f) => f.loc(),\n            _ => pt::CodeLocation::loc(self),\n        }\n    }\n}\n\nimpl CodeLocationExt for pt::SourceUnitPart {\n    #[inline]\n    #[track_caller]\n    fn loc(&self) -> pt::Loc {\n        match self {\n            Self::FunctionDefinition(f) => f.loc(),\n            _ => pt::CodeLocation::loc(self),\n        }\n    }\n}\n\nimpl CodeLocationExt for pt::ImportPath {\n    fn loc(&self) -> pt::Loc {\n        match self {\n            Self::Filename(s) => s.loc(),\n            Self::Path(i) => i.loc(),\n        }\n    }\n}\n\nimpl CodeLocationExt for pt::VersionComparator {\n    fn loc(&self) -> pt::Loc {\n        match self {\n            Self::Plain { loc, .. }\n            | Self::Operator { loc, .. }\n            | Self::Or { loc, .. }\n            | Self::Range { loc, .. } => *loc,\n        }\n    }\n}\n\nmacro_rules! impl_delegate {\n    ($($t:ty),+ $(,)?) => {$(\n        impl CodeLocationExt for $t {\n            #[inline]\n            #[track_caller]\n            fn loc(&self) -> pt::Loc {\n                pt::CodeLocation::loc(self)\n            }\n        }\n    )+};\n}\n\nimpl_delegate! {\n    pt::Annotation,\n    pt::Base,\n    pt::ContractDefinition,\n    pt::EnumDefinition,\n    pt::ErrorDefinition,\n    pt::ErrorParameter,\n    pt::EventDefinition,\n    pt::EventParameter,\n    pt::PragmaDirective,\n    // pt::FunctionDefinition,\n    pt::HexLiteral,\n    pt::Identifier,\n    pt::IdentifierPath,\n    pt::NamedArgument,\n    pt::Parameter,\n    // pt::SourceUnit,\n    pt::StringLiteral,\n    pt::StructDefinition,\n    pt::TypeDefinition,\n    pt::Using,\n    pt::UsingFunction,\n    pt::VariableDeclaration,\n    pt::VariableDefinition,\n    pt::YulBlock,\n    pt::YulFor,\n    pt::YulFunctionCall,\n    pt::YulFunctionDefinition,\n    pt::YulSwitch,\n    pt::YulTypedIdentifier,\n\n    pt::CatchClause,\n    pt::Comment,\n    // pt::ContractPart,\n    pt::ContractTy,\n    pt::Expression,\n    pt::FunctionAttribute,\n    // pt::FunctionTy,\n    pt::Import,\n    pt::Loc,\n    pt::Mutability,\n    // pt::SourceUnitPart,\n    pt::Statement,\n    pt::StorageLocation,\n    // pt::Type,\n    // pt::UserDefinedOperator,\n    pt::UsingList,\n    pt::VariableAttribute,\n    // pt::Visibility,\n    pt::YulExpression,\n    pt::YulStatement,\n    pt::YulSwitchOptions,\n}\n"
  },
  {
    "path": "crates/doc/src/solang_ext/mod.rs",
    "content": "//! Extension traits and modules to the [`solang_parser`] crate.\n\n/// Same as [`solang_parser::pt`], but with the patched `CodeLocation`.\npub mod pt {\n    #[doc(no_inline)]\n    pub use super::loc::CodeLocationExt as CodeLocation;\n\n    #[doc(no_inline)]\n    pub use solang_parser::pt::{\n        Annotation, Base, CatchClause, Comment, ContractDefinition, ContractPart, ContractTy,\n        EnumDefinition, ErrorDefinition, ErrorParameter, EventDefinition, EventParameter,\n        Expression, FunctionAttribute, FunctionDefinition, FunctionTy, HexLiteral, Identifier,\n        IdentifierPath, Import, ImportPath, Loc, Mutability, NamedArgument, OptionalCodeLocation,\n        Parameter, ParameterList, PragmaDirective, SourceUnit, SourceUnitPart, Statement,\n        StorageLocation, StringLiteral, StructDefinition, Type, TypeDefinition,\n        UserDefinedOperator, Using, UsingFunction, UsingList, VariableAttribute,\n        VariableDeclaration, VariableDefinition, Visibility, YulBlock, YulExpression, YulFor,\n        YulFunctionCall, YulFunctionDefinition, YulStatement, YulSwitch, YulSwitchOptions,\n        YulTypedIdentifier,\n    };\n}\n\nmod ast_eq;\nmod loc;\nmod safe_unwrap;\nmod visit;\n\npub use ast_eq::AstEq;\npub use loc::CodeLocationExt;\npub use safe_unwrap::SafeUnwrap;\npub use visit::{Visitable, Visitor};\n"
  },
  {
    "path": "crates/doc/src/solang_ext/safe_unwrap.rs",
    "content": "use solang_parser::pt;\n\n/// Trait implemented to unwrap optional parse tree items initially introduced in\n/// [hyperledger/solang#1068].\n///\n/// Note that the methods of this trait should only be used on parse tree items' fields, like\n/// [pt::VariableDefinition] or [pt::EventDefinition], where the `name` field is `None` only when an\n/// error occurred during parsing.\n///\n/// [hyperledger/solang#1068]: https://github.com/hyperledger/solang/pull/1068\npub trait SafeUnwrap<T> {\n    /// See [SafeUnwrap].\n    fn safe_unwrap(&self) -> &T;\n\n    /// See [SafeUnwrap].\n    fn safe_unwrap_mut(&mut self) -> &mut T;\n}\n\n#[inline(never)]\n#[cold]\n#[track_caller]\nfn invalid() -> ! {\n    panic!(\"invalid parse tree\")\n}\n\nmacro_rules! impl_ {\n    ($($t:ty),+ $(,)?) => {\n        $(\n            impl SafeUnwrap<$t> for Option<$t> {\n                #[inline]\n                #[track_caller]\n                fn safe_unwrap(&self) -> &$t {\n                    match *self {\n                        Some(ref x) => x,\n                        None => invalid(),\n                    }\n                }\n\n                #[inline]\n                #[track_caller]\n                fn safe_unwrap_mut(&mut self) -> &mut $t {\n                    match *self {\n                        Some(ref mut x) => x,\n                        None => invalid(),\n                    }\n                }\n            }\n        )+\n    };\n}\n\nimpl_!(pt::Identifier, pt::StringLiteral);\n"
  },
  {
    "path": "crates/doc/src/solang_ext/visit.rs",
    "content": "//! Visitor helpers to traverse the [solang Solidity Parse Tree](solang_parser::pt).\n\nuse crate::solang_ext::{CodeLocationExt, pt::*};\n\n/// A trait that is invoked while traversing the Solidity Parse Tree.\n/// Each method of the [Visitor] trait is a hook that can be potentially overridden.\n///\n/// Currently the main implementer of this trait is the [`Formatter`](crate::Formatter<'_>) struct.\npub trait Visitor {\n    type Error: std::error::Error;\n\n    fn visit_source(&mut self, _loc: Loc) -> Result<(), Self::Error> {\n        Ok(())\n    }\n\n    fn visit_source_unit(&mut self, _source_unit: &mut SourceUnit) -> Result<(), Self::Error> {\n        Ok(())\n    }\n\n    fn visit_contract(&mut self, _contract: &mut ContractDefinition) -> Result<(), Self::Error> {\n        Ok(())\n    }\n\n    fn visit_annotation(&mut self, annotation: &mut Annotation) -> Result<(), Self::Error> {\n        self.visit_source(annotation.loc)\n    }\n\n    fn visit_pragma(&mut self, pragma: &mut PragmaDirective) -> Result<(), Self::Error> {\n        self.visit_source(pragma.loc())\n    }\n\n    fn visit_import_plain(\n        &mut self,\n        _loc: Loc,\n        _import: &mut ImportPath,\n    ) -> Result<(), Self::Error> {\n        Ok(())\n    }\n\n    fn visit_import_global(\n        &mut self,\n        _loc: Loc,\n        _global: &mut ImportPath,\n        _alias: &mut Identifier,\n    ) -> Result<(), Self::Error> {\n        Ok(())\n    }\n\n    fn visit_import_renames(\n        &mut self,\n        _loc: Loc,\n        _imports: &mut [(Identifier, Option<Identifier>)],\n        _from: &mut ImportPath,\n    ) -> Result<(), Self::Error> {\n        Ok(())\n    }\n\n    fn visit_enum(&mut self, _enum: &mut EnumDefinition) -> Result<(), Self::Error> {\n        Ok(())\n    }\n\n    fn visit_assembly(\n        &mut self,\n        loc: Loc,\n        _dialect: &mut Option<StringLiteral>,\n        _block: &mut YulBlock,\n        _flags: &mut Option<Vec<StringLiteral>>,\n    ) -> Result<(), Self::Error> {\n        self.visit_source(loc)\n    }\n\n    fn visit_block(\n        &mut self,\n        loc: Loc,\n        _unchecked: bool,\n        _statements: &mut Vec<Statement>,\n    ) -> Result<(), Self::Error> {\n        self.visit_source(loc)\n    }\n\n    fn visit_args(&mut self, loc: Loc, _args: &mut Vec<NamedArgument>) -> Result<(), Self::Error> {\n        self.visit_source(loc)\n    }\n\n    /// Don't write semicolon at the end because expressions can appear as both\n    /// part of other node and a statement in the function body\n    fn visit_expr(&mut self, loc: Loc, _expr: &mut Expression) -> Result<(), Self::Error> {\n        self.visit_source(loc)\n    }\n\n    fn visit_ident(&mut self, loc: Loc, _ident: &mut Identifier) -> Result<(), Self::Error> {\n        self.visit_source(loc)\n    }\n\n    fn visit_ident_path(&mut self, idents: &mut IdentifierPath) -> Result<(), Self::Error> {\n        self.visit_source(idents.loc)\n    }\n\n    fn visit_emit(&mut self, loc: Loc, _event: &mut Expression) -> Result<(), Self::Error> {\n        self.visit_source(loc)?;\n        self.visit_stray_semicolon()?;\n\n        Ok(())\n    }\n\n    fn visit_var_definition(&mut self, var: &mut VariableDefinition) -> Result<(), Self::Error> {\n        self.visit_source(var.loc)?;\n        self.visit_stray_semicolon()?;\n\n        Ok(())\n    }\n\n    fn visit_var_definition_stmt(\n        &mut self,\n        loc: Loc,\n        _declaration: &mut VariableDeclaration,\n        _expr: &mut Option<Expression>,\n    ) -> Result<(), Self::Error> {\n        self.visit_source(loc)?;\n        self.visit_stray_semicolon()\n    }\n\n    fn visit_var_declaration(&mut self, var: &mut VariableDeclaration) -> Result<(), Self::Error> {\n        self.visit_source(var.loc)\n    }\n\n    fn visit_return(\n        &mut self,\n        loc: Loc,\n        _expr: &mut Option<Expression>,\n    ) -> Result<(), Self::Error> {\n        self.visit_source(loc)?;\n        self.visit_stray_semicolon()?;\n\n        Ok(())\n    }\n\n    fn visit_revert(\n        &mut self,\n        loc: Loc,\n        _error: &mut Option<IdentifierPath>,\n        _args: &mut Vec<Expression>,\n    ) -> Result<(), Self::Error> {\n        self.visit_source(loc)?;\n        self.visit_stray_semicolon()?;\n\n        Ok(())\n    }\n\n    fn visit_revert_named_args(\n        &mut self,\n        loc: Loc,\n        _error: &mut Option<IdentifierPath>,\n        _args: &mut Vec<NamedArgument>,\n    ) -> Result<(), Self::Error> {\n        self.visit_source(loc)?;\n        self.visit_stray_semicolon()?;\n\n        Ok(())\n    }\n\n    fn visit_break(&mut self, loc: Loc, _semicolon: bool) -> Result<(), Self::Error> {\n        self.visit_source(loc)\n    }\n\n    fn visit_continue(&mut self, loc: Loc, _semicolon: bool) -> Result<(), Self::Error> {\n        self.visit_source(loc)\n    }\n\n    #[expect(clippy::type_complexity)]\n    fn visit_try(\n        &mut self,\n        loc: Loc,\n        _expr: &mut Expression,\n        _returns: &mut Option<(Vec<(Loc, Option<Parameter>)>, Box<Statement>)>,\n        _clauses: &mut Vec<CatchClause>,\n    ) -> Result<(), Self::Error> {\n        self.visit_source(loc)\n    }\n\n    fn visit_if(\n        &mut self,\n        loc: Loc,\n        _cond: &mut Expression,\n        _if_branch: &mut Box<Statement>,\n        _else_branch: &mut Option<Box<Statement>>,\n        _is_first_stmt: bool,\n    ) -> Result<(), Self::Error> {\n        self.visit_source(loc)\n    }\n\n    fn visit_do_while(\n        &mut self,\n        loc: Loc,\n        _body: &mut Statement,\n        _cond: &mut Expression,\n    ) -> Result<(), Self::Error> {\n        self.visit_source(loc)\n    }\n\n    fn visit_while(\n        &mut self,\n        loc: Loc,\n        _cond: &mut Expression,\n        _body: &mut Statement,\n    ) -> Result<(), Self::Error> {\n        self.visit_source(loc)\n    }\n\n    fn visit_for(\n        &mut self,\n        loc: Loc,\n        _init: &mut Option<Box<Statement>>,\n        _cond: &mut Option<Box<Expression>>,\n        _update: &mut Option<Box<Expression>>,\n        _body: &mut Option<Box<Statement>>,\n    ) -> Result<(), Self::Error> {\n        self.visit_source(loc)\n    }\n\n    fn visit_function(&mut self, func: &mut FunctionDefinition) -> Result<(), Self::Error> {\n        self.visit_source(func.loc())?;\n        if func.body.is_none() {\n            self.visit_stray_semicolon()?;\n        }\n\n        Ok(())\n    }\n\n    fn visit_function_attribute(\n        &mut self,\n        attribute: &mut FunctionAttribute,\n    ) -> Result<(), Self::Error> {\n        self.visit_source(attribute.loc())?;\n        Ok(())\n    }\n\n    fn visit_var_attribute(\n        &mut self,\n        attribute: &mut VariableAttribute,\n    ) -> Result<(), Self::Error> {\n        self.visit_source(attribute.loc())?;\n        Ok(())\n    }\n\n    fn visit_base(&mut self, base: &mut Base) -> Result<(), Self::Error> {\n        self.visit_source(base.loc)\n    }\n\n    fn visit_parameter(&mut self, parameter: &mut Parameter) -> Result<(), Self::Error> {\n        self.visit_source(parameter.loc)\n    }\n\n    fn visit_struct(&mut self, structure: &mut StructDefinition) -> Result<(), Self::Error> {\n        self.visit_source(structure.loc)?;\n\n        Ok(())\n    }\n\n    fn visit_event(&mut self, event: &mut EventDefinition) -> Result<(), Self::Error> {\n        self.visit_source(event.loc)?;\n        self.visit_stray_semicolon()?;\n\n        Ok(())\n    }\n\n    fn visit_event_parameter(&mut self, param: &mut EventParameter) -> Result<(), Self::Error> {\n        self.visit_source(param.loc)\n    }\n\n    fn visit_error(&mut self, error: &mut ErrorDefinition) -> Result<(), Self::Error> {\n        self.visit_source(error.loc)?;\n        self.visit_stray_semicolon()?;\n\n        Ok(())\n    }\n\n    fn visit_error_parameter(&mut self, param: &mut ErrorParameter) -> Result<(), Self::Error> {\n        self.visit_source(param.loc)\n    }\n\n    fn visit_type_definition(&mut self, def: &mut TypeDefinition) -> Result<(), Self::Error> {\n        self.visit_source(def.loc)\n    }\n\n    fn visit_stray_semicolon(&mut self) -> Result<(), Self::Error> {\n        Ok(())\n    }\n\n    fn visit_using(&mut self, using: &mut Using) -> Result<(), Self::Error> {\n        self.visit_source(using.loc)?;\n        self.visit_stray_semicolon()?;\n\n        Ok(())\n    }\n\n    fn visit_yul_block(\n        &mut self,\n        loc: Loc,\n        _stmts: &mut Vec<YulStatement>,\n        _attempt_single_line: bool,\n    ) -> Result<(), Self::Error> {\n        self.visit_source(loc)\n    }\n\n    fn visit_yul_expr(&mut self, expr: &mut YulExpression) -> Result<(), Self::Error> {\n        self.visit_source(expr.loc())\n    }\n\n    fn visit_yul_assignment<T>(\n        &mut self,\n        loc: Loc,\n        _exprs: &mut Vec<T>,\n        _expr: &mut Option<&mut YulExpression>,\n    ) -> Result<(), Self::Error>\n    where\n        T: Visitable + CodeLocationExt,\n    {\n        self.visit_source(loc)\n    }\n\n    fn visit_yul_for(&mut self, stmt: &mut YulFor) -> Result<(), Self::Error> {\n        self.visit_source(stmt.loc)\n    }\n\n    fn visit_yul_function_call(&mut self, stmt: &mut YulFunctionCall) -> Result<(), Self::Error> {\n        self.visit_source(stmt.loc)\n    }\n\n    fn visit_yul_fun_def(&mut self, stmt: &mut YulFunctionDefinition) -> Result<(), Self::Error> {\n        self.visit_source(stmt.loc)\n    }\n\n    fn visit_yul_if(\n        &mut self,\n        loc: Loc,\n        _expr: &mut YulExpression,\n        _block: &mut YulBlock,\n    ) -> Result<(), Self::Error> {\n        self.visit_source(loc)\n    }\n\n    fn visit_yul_leave(&mut self, loc: Loc) -> Result<(), Self::Error> {\n        self.visit_source(loc)\n    }\n\n    fn visit_yul_switch(&mut self, stmt: &mut YulSwitch) -> Result<(), Self::Error> {\n        self.visit_source(stmt.loc)\n    }\n\n    fn visit_yul_var_declaration(\n        &mut self,\n        loc: Loc,\n        _idents: &mut Vec<YulTypedIdentifier>,\n        _expr: &mut Option<YulExpression>,\n    ) -> Result<(), Self::Error> {\n        self.visit_source(loc)\n    }\n\n    fn visit_yul_typed_ident(&mut self, ident: &mut YulTypedIdentifier) -> Result<(), Self::Error> {\n        self.visit_source(ident.loc)\n    }\n\n    fn visit_parser_error(&mut self, loc: Loc) -> Result<(), Self::Error> {\n        self.visit_source(loc)\n    }\n}\n\n/// Visitable trait for [`solang_parser::pt`] types.\n///\n/// All [`solang_parser::pt`] types, such as [Statement], should implement the [Visitable] trait\n/// that accepts a trait [Visitor] implementation, which has various callback handles for Solidity\n/// Parse Tree nodes.\n///\n/// We want to take a `&mut self` to be able to implement some advanced features in the future such\n/// as modifying the Parse Tree before formatting it.\npub trait Visitable {\n    fn visit<V>(&mut self, v: &mut V) -> Result<(), V::Error>\n    where\n        V: Visitor;\n}\n\nimpl<T> Visitable for &mut T\nwhere\n    T: Visitable,\n{\n    fn visit<V>(&mut self, v: &mut V) -> Result<(), V::Error>\n    where\n        V: Visitor,\n    {\n        T::visit(self, v)\n    }\n}\n\nimpl<T> Visitable for Option<T>\nwhere\n    T: Visitable,\n{\n    fn visit<V>(&mut self, v: &mut V) -> Result<(), V::Error>\n    where\n        V: Visitor,\n    {\n        if let Some(inner) = self.as_mut() { inner.visit(v) } else { Ok(()) }\n    }\n}\n\nimpl<T> Visitable for Box<T>\nwhere\n    T: Visitable,\n{\n    fn visit<V>(&mut self, v: &mut V) -> Result<(), V::Error>\n    where\n        V: Visitor,\n    {\n        T::visit(self, v)\n    }\n}\n\nimpl<T> Visitable for Vec<T>\nwhere\n    T: Visitable,\n{\n    fn visit<V>(&mut self, v: &mut V) -> Result<(), V::Error>\n    where\n        V: Visitor,\n    {\n        for item in self.iter_mut() {\n            item.visit(v)?;\n        }\n        Ok(())\n    }\n}\n\nimpl Visitable for SourceUnitPart {\n    fn visit<V>(&mut self, v: &mut V) -> Result<(), V::Error>\n    where\n        V: Visitor,\n    {\n        match self {\n            Self::ContractDefinition(contract) => v.visit_contract(contract),\n            Self::PragmaDirective(pragma) => v.visit_pragma(pragma),\n            Self::ImportDirective(import) => import.visit(v),\n            Self::EnumDefinition(enumeration) => v.visit_enum(enumeration),\n            Self::StructDefinition(structure) => v.visit_struct(structure),\n            Self::EventDefinition(event) => v.visit_event(event),\n            Self::ErrorDefinition(error) => v.visit_error(error),\n            Self::FunctionDefinition(function) => v.visit_function(function),\n            Self::VariableDefinition(variable) => v.visit_var_definition(variable),\n            Self::TypeDefinition(def) => v.visit_type_definition(def),\n            Self::StraySemicolon(_) => v.visit_stray_semicolon(),\n            Self::Using(using) => v.visit_using(using),\n            Self::Annotation(annotation) => v.visit_annotation(annotation),\n        }\n    }\n}\n\nimpl Visitable for Import {\n    fn visit<V>(&mut self, v: &mut V) -> Result<(), V::Error>\n    where\n        V: Visitor,\n    {\n        match self {\n            Self::Plain(import, loc) => v.visit_import_plain(*loc, import),\n            Self::GlobalSymbol(global, import_as, loc) => {\n                v.visit_import_global(*loc, global, import_as)\n            }\n            Self::Rename(from, imports, loc) => v.visit_import_renames(*loc, imports, from),\n        }\n    }\n}\n\nimpl Visitable for ContractPart {\n    fn visit<V>(&mut self, v: &mut V) -> Result<(), V::Error>\n    where\n        V: Visitor,\n    {\n        match self {\n            Self::StructDefinition(structure) => v.visit_struct(structure),\n            Self::EventDefinition(event) => v.visit_event(event),\n            Self::ErrorDefinition(error) => v.visit_error(error),\n            Self::EnumDefinition(enumeration) => v.visit_enum(enumeration),\n            Self::VariableDefinition(variable) => v.visit_var_definition(variable),\n            Self::FunctionDefinition(function) => v.visit_function(function),\n            Self::TypeDefinition(def) => v.visit_type_definition(def),\n            Self::StraySemicolon(_) => v.visit_stray_semicolon(),\n            Self::Using(using) => v.visit_using(using),\n            Self::Annotation(annotation) => v.visit_annotation(annotation),\n        }\n    }\n}\n\nimpl Visitable for Statement {\n    fn visit<V>(&mut self, v: &mut V) -> Result<(), V::Error>\n    where\n        V: Visitor,\n    {\n        match self {\n            Self::Block { loc, unchecked, statements } => {\n                v.visit_block(*loc, *unchecked, statements)\n            }\n            Self::Assembly { loc, dialect, block, flags } => {\n                v.visit_assembly(*loc, dialect, block, flags)\n            }\n            Self::Args(loc, args) => v.visit_args(*loc, args),\n            Self::If(loc, cond, if_branch, else_branch) => {\n                v.visit_if(*loc, cond, if_branch, else_branch, true)\n            }\n            Self::While(loc, cond, body) => v.visit_while(*loc, cond, body),\n            Self::Expression(loc, expr) => {\n                v.visit_expr(*loc, expr)?;\n                v.visit_stray_semicolon()\n            }\n            Self::VariableDefinition(loc, declaration, expr) => {\n                v.visit_var_definition_stmt(*loc, declaration, expr)\n            }\n            Self::For(loc, init, cond, update, body) => v.visit_for(*loc, init, cond, update, body),\n            Self::DoWhile(loc, body, cond) => v.visit_do_while(*loc, body, cond),\n            Self::Continue(loc) => v.visit_continue(*loc, true),\n            Self::Break(loc) => v.visit_break(*loc, true),\n            Self::Return(loc, expr) => v.visit_return(*loc, expr),\n            Self::Revert(loc, error, args) => v.visit_revert(*loc, error, args),\n            Self::RevertNamedArgs(loc, error, args) => v.visit_revert_named_args(*loc, error, args),\n            Self::Emit(loc, event) => v.visit_emit(*loc, event),\n            Self::Try(loc, expr, returns, clauses) => v.visit_try(*loc, expr, returns, clauses),\n            Self::Error(loc) => v.visit_parser_error(*loc),\n        }\n    }\n}\n\nimpl Visitable for Loc {\n    fn visit<V>(&mut self, v: &mut V) -> Result<(), V::Error>\n    where\n        V: Visitor,\n    {\n        v.visit_source(*self)\n    }\n}\n\nimpl Visitable for Expression {\n    fn visit<V>(&mut self, v: &mut V) -> Result<(), V::Error>\n    where\n        V: Visitor,\n    {\n        v.visit_expr(self.loc(), self)\n    }\n}\n\nimpl Visitable for Identifier {\n    fn visit<V>(&mut self, v: &mut V) -> Result<(), V::Error>\n    where\n        V: Visitor,\n    {\n        v.visit_ident(self.loc, self)\n    }\n}\n\nimpl Visitable for VariableDeclaration {\n    fn visit<V>(&mut self, v: &mut V) -> Result<(), V::Error>\n    where\n        V: Visitor,\n    {\n        v.visit_var_declaration(self)\n    }\n}\n\nimpl Visitable for YulBlock {\n    fn visit<V>(&mut self, v: &mut V) -> Result<(), V::Error>\n    where\n        V: Visitor,\n    {\n        v.visit_yul_block(self.loc, self.statements.as_mut(), false)\n    }\n}\n\nimpl Visitable for YulStatement {\n    fn visit<V>(&mut self, v: &mut V) -> Result<(), V::Error>\n    where\n        V: Visitor,\n    {\n        match self {\n            Self::Assign(loc, exprs, expr) => v.visit_yul_assignment(*loc, exprs, &mut Some(expr)),\n            Self::Block(block) => v.visit_yul_block(block.loc, block.statements.as_mut(), false),\n            Self::Break(loc) => v.visit_break(*loc, false),\n            Self::Continue(loc) => v.visit_continue(*loc, false),\n            Self::For(stmt) => v.visit_yul_for(stmt),\n            Self::FunctionCall(stmt) => v.visit_yul_function_call(stmt),\n            Self::FunctionDefinition(stmt) => v.visit_yul_fun_def(stmt),\n            Self::If(loc, expr, block) => v.visit_yul_if(*loc, expr, block),\n            Self::Leave(loc) => v.visit_yul_leave(*loc),\n            Self::Switch(stmt) => v.visit_yul_switch(stmt),\n            Self::VariableDeclaration(loc, idents, expr) => {\n                v.visit_yul_var_declaration(*loc, idents, expr)\n            }\n            Self::Error(loc) => v.visit_parser_error(*loc),\n        }\n    }\n}\n\nmacro_rules! impl_visitable {\n    ($type:ty, $func:ident) => {\n        impl Visitable for $type {\n            fn visit<V>(&mut self, v: &mut V) -> Result<(), V::Error>\n            where\n                V: Visitor,\n            {\n                v.$func(self)\n            }\n        }\n    };\n}\n\nimpl_visitable!(SourceUnit, visit_source_unit);\nimpl_visitable!(FunctionAttribute, visit_function_attribute);\nimpl_visitable!(VariableAttribute, visit_var_attribute);\nimpl_visitable!(Parameter, visit_parameter);\nimpl_visitable!(Base, visit_base);\nimpl_visitable!(EventParameter, visit_event_parameter);\nimpl_visitable!(ErrorParameter, visit_error_parameter);\nimpl_visitable!(IdentifierPath, visit_ident_path);\nimpl_visitable!(YulExpression, visit_yul_expr);\nimpl_visitable!(YulTypedIdentifier, visit_yul_typed_ident);\n"
  },
  {
    "path": "crates/doc/src/writer/as_doc.rs",
    "content": "use crate::{\n    CONTRACT_INHERITANCE_ID, CommentTag, Comments, CommentsRef, DEPLOYMENTS_ID, Document,\n    GIT_SOURCE_ID, INHERITDOC_ID, Markdown, PreprocessorOutput,\n    document::{DocumentContent, read_context},\n    helpers::function_signature,\n    parser::ParseSource,\n    solang_ext::SafeUnwrap,\n    writer::BufWriter,\n};\nuse itertools::Itertools;\nuse solang_parser::pt::{Base, FunctionDefinition, VariableAttribute};\nuse std::path::Path;\n\n/// The result of [`AsDoc::as_doc`].\npub type AsDocResult = Result<String, std::fmt::Error>;\n\n/// A trait for formatting a parse unit as documentation.\npub trait AsDoc {\n    /// Formats a parse tree item into a doc string.\n    fn as_doc(&self) -> AsDocResult;\n}\n\nimpl AsDoc for String {\n    fn as_doc(&self) -> AsDocResult {\n        Ok(self.to_owned())\n    }\n}\n\nimpl AsDoc for Comments {\n    fn as_doc(&self) -> AsDocResult {\n        CommentsRef::from(self).as_doc()\n    }\n}\n\nimpl AsDoc for CommentsRef<'_> {\n    // TODO: support other tags\n    fn as_doc(&self) -> AsDocResult {\n        let mut writer = BufWriter::default();\n\n        // Write title tag(s)\n        let titles = self.include_tag(CommentTag::Title);\n        if !titles.is_empty() {\n            writer.write_bold(&format!(\"Title{}:\", if titles.len() == 1 { \"\" } else { \"s\" }))?;\n            writer.writeln_raw(titles.iter().map(|t| &t.value).join(\", \"))?;\n            writer.writeln()?;\n        }\n\n        // Write author tag(s)\n        let authors = self.include_tag(CommentTag::Author);\n        if !authors.is_empty() {\n            writer.write_bold(&format!(\"Author{}:\", if authors.len() == 1 { \"\" } else { \"s\" }))?;\n            writer.writeln_raw(authors.iter().map(|a| &a.value).join(\", \"))?;\n            writer.writeln()?;\n        }\n\n        // Write notice tags\n        let notices = self.include_tag(CommentTag::Notice);\n        for n in notices.iter() {\n            writer.writeln_raw(&n.value)?;\n            writer.writeln()?;\n        }\n\n        // Write dev tags\n        let devs = self.include_tag(CommentTag::Dev);\n        for d in devs.iter() {\n            writer.write_dev_content(&d.value)?;\n            writer.writeln()?;\n        }\n\n        // Write custom tags\n        let customs = self.get_custom_tags();\n        if !customs.is_empty() {\n            writer.write_bold(&format!(\"Note{}:\", if customs.len() == 1 { \"\" } else { \"s\" }))?;\n            for c in customs.iter() {\n                writer.writeln_raw(format!(\n                    \"{}{}: {}\",\n                    if customs.len() == 1 { \"\" } else { \"- \" },\n                    &c.tag,\n                    &c.value\n                ))?;\n                writer.writeln()?;\n            }\n        }\n\n        Ok(writer.finish())\n    }\n}\n\nimpl AsDoc for Base {\n    fn as_doc(&self) -> AsDocResult {\n        Ok(self.name.identifiers.iter().map(|ident| ident.name.to_owned()).join(\".\"))\n    }\n}\n\nimpl AsDoc for Document {\n    fn as_doc(&self) -> AsDocResult {\n        let mut writer = BufWriter::default();\n\n        match &self.content {\n            DocumentContent::OverloadedFunctions(items) => {\n                writer\n                    .write_title(&format!(\"function {}\", items.first().unwrap().source.ident()))?;\n                if let Some(git_source) = read_context!(self, GIT_SOURCE_ID, GitSource) {\n                    writer.write_link(\"Git Source\", &git_source)?;\n                    writer.writeln()?;\n                }\n\n                for item in items {\n                    let func = item.as_function().unwrap();\n                    let heading = function_signature(func).replace(',', \", \");\n                    writer.write_heading(&heading)?;\n                    writer.write_section(&item.comments, &item.code)?;\n                }\n            }\n            DocumentContent::Constants(items) => {\n                writer.write_title(\"Constants\")?;\n                if let Some(git_source) = read_context!(self, GIT_SOURCE_ID, GitSource) {\n                    writer.write_link(\"Git Source\", &git_source)?;\n                    writer.writeln()?;\n                }\n\n                for item in items {\n                    let var = item.as_variable().unwrap();\n                    writer.write_heading(&var.name.safe_unwrap().name)?;\n                    writer.write_section(&item.comments, &item.code)?;\n                }\n            }\n            DocumentContent::Single(item) => {\n                writer.write_title(&item.source.ident())?;\n                if let Some(git_source) = read_context!(self, GIT_SOURCE_ID, GitSource) {\n                    writer.write_link(\"Git Source\", &git_source)?;\n                    writer.writeln()?;\n                }\n\n                if let Some(deployments) = read_context!(self, DEPLOYMENTS_ID, Deployments) {\n                    writer.write_deployments_table(deployments)?;\n                }\n\n                match &item.source {\n                    ParseSource::Contract(contract) => {\n                        if !contract.base.is_empty() {\n                            writer.write_bold(\"Inherits:\")?;\n\n                            let mut bases = vec![];\n                            let linked =\n                                read_context!(self, CONTRACT_INHERITANCE_ID, ContractInheritance);\n                            for base in &contract.base {\n                                let base_doc = base.as_doc()?;\n                                let base_ident = &base.name.identifiers.last().unwrap().name;\n\n                                let link = linked\n                                    .as_ref()\n                                    .and_then(|link| {\n                                        link.get(base_ident).map(|path| {\n                                            let path = if cfg!(windows) {\n                                                Path::new(\"\\\\\").join(path)\n                                            } else {\n                                                Path::new(\"/\").join(path)\n                                            };\n                                            Markdown::Link(&base_doc, &path.display().to_string())\n                                                .as_doc()\n                                        })\n                                    })\n                                    .transpose()?\n                                    .unwrap_or(base_doc);\n\n                                bases.push(link);\n                            }\n\n                            writer.writeln_raw(bases.join(\", \"))?;\n                            writer.writeln()?;\n                        }\n\n                        writer.writeln_doc(&item.comments)?;\n\n                        if let Some(all_vars) = item.variables() {\n                            let (constants, state_vars): (Vec<_>, Vec<_>) =\n                                all_vars.into_iter().partition(|(item, _, _)| {\n                                    item.attrs.iter().any(|attr| {\n                                        matches!(\n                                            attr,\n                                            VariableAttribute::Constant(_)\n                                                | VariableAttribute::Immutable(_)\n                                        )\n                                    })\n                                });\n\n                            if !constants.is_empty() {\n                                writer.write_subtitle(\"Constants\")?;\n                                constants.into_iter().try_for_each(|(item, comments, code)| {\n                                    let comments = comments.merge_inheritdoc(\n                                        &item.name.safe_unwrap().name,\n                                        read_context!(self, INHERITDOC_ID, Inheritdoc),\n                                    );\n\n                                    writer.write_heading(&item.name.safe_unwrap().name)?;\n                                    writer.write_section(&comments, code)?;\n                                    writer.writeln()\n                                })?;\n                            }\n\n                            if !state_vars.is_empty() {\n                                writer.write_subtitle(\"State Variables\")?;\n                                state_vars.into_iter().try_for_each(|(item, comments, code)| {\n                                    let comments = comments.merge_inheritdoc(\n                                        &item.name.safe_unwrap().name,\n                                        read_context!(self, INHERITDOC_ID, Inheritdoc),\n                                    );\n\n                                    writer.write_heading(&item.name.safe_unwrap().name)?;\n                                    writer.write_section(&comments, code)?;\n                                    writer.writeln()\n                                })?;\n                            }\n                        }\n\n                        if let Some(funcs) = item.functions() {\n                            writer.write_subtitle(\"Functions\")?;\n\n                            for (func, comments, code) in &funcs {\n                                self.write_function(&mut writer, func, comments, code)?;\n                            }\n                        }\n\n                        if let Some(events) = item.events() {\n                            writer.write_subtitle(\"Events\")?;\n                            events.into_iter().try_for_each(|(item, comments, code)| {\n                                writer.write_heading(&item.name.safe_unwrap().name)?;\n                                writer.write_section(comments, code)?;\n                                writer.try_write_events_table(&item.fields, comments)\n                            })?;\n                        }\n\n                        if let Some(errors) = item.errors() {\n                            writer.write_subtitle(\"Errors\")?;\n                            errors.into_iter().try_for_each(|(item, comments, code)| {\n                                writer.write_heading(&item.name.safe_unwrap().name)?;\n                                writer.write_section(comments, code)?;\n                                writer.try_write_errors_table(&item.fields, comments)\n                            })?;\n                        }\n\n                        if let Some(structs) = item.structs() {\n                            writer.write_subtitle(\"Structs\")?;\n                            structs.into_iter().try_for_each(|(item, comments, code)| {\n                                writer.write_heading(&item.name.safe_unwrap().name)?;\n                                writer.write_section(comments, code)?;\n                                writer.try_write_properties_table(&item.fields, comments)\n                            })?;\n                        }\n\n                        if let Some(enums) = item.enums() {\n                            writer.write_subtitle(\"Enums\")?;\n                            enums.into_iter().try_for_each(|(item, comments, code)| {\n                                writer.write_heading(&item.name.safe_unwrap().name)?;\n                                writer.write_section(comments, code)?;\n                                writer.try_write_variant_table(item, comments)\n                            })?;\n                        }\n                    }\n\n                    ParseSource::Function(func) => {\n                        // TODO: cleanup\n                        // Write function docs\n                        writer.writeln_doc(\n                            &item.comments.exclude_tags(&[CommentTag::Param, CommentTag::Return]),\n                        )?;\n\n                        // Write function header\n                        writer.write_code(&item.code)?;\n\n                        // Write function parameter comments in a table\n                        let params =\n                            func.params.iter().filter_map(|p| p.1.as_ref()).collect::<Vec<_>>();\n                        writer.try_write_param_table(CommentTag::Param, &params, &item.comments)?;\n\n                        // Write function return parameter comments in a table\n                        let returns =\n                            func.returns.iter().filter_map(|p| p.1.as_ref()).collect::<Vec<_>>();\n                        writer.try_write_param_table(\n                            CommentTag::Return,\n                            &returns,\n                            &item.comments,\n                        )?;\n\n                        writer.writeln()?;\n                    }\n\n                    ParseSource::Struct(ty) => {\n                        writer.write_section(&item.comments, &item.code)?;\n                        writer.try_write_properties_table(&ty.fields, &item.comments)?;\n                    }\n                    ParseSource::Event(ev) => {\n                        writer.write_section(&item.comments, &item.code)?;\n                        writer.try_write_events_table(&ev.fields, &item.comments)?;\n                    }\n                    ParseSource::Error(err) => {\n                        writer.write_section(&item.comments, &item.code)?;\n                        writer.try_write_errors_table(&err.fields, &item.comments)?;\n                    }\n                    ParseSource::Variable(_) | ParseSource::Enum(_) | ParseSource::Type(_) => {\n                        writer.write_section(&item.comments, &item.code)?;\n                    }\n                }\n            }\n            DocumentContent::Empty => (),\n        };\n\n        Ok(writer.finish())\n    }\n}\n\nimpl Document {\n    /// Writes a function to the buffer.\n    fn write_function(\n        &self,\n        writer: &mut BufWriter,\n        func: &FunctionDefinition,\n        comments: &Comments,\n        code: &str,\n    ) -> Result<(), std::fmt::Error> {\n        let func_sign = function_signature(func);\n        let func_name = func.name.as_ref().map_or(func.ty.to_string(), |n| n.name.to_owned());\n        let comments =\n            comments.merge_inheritdoc(&func_sign, read_context!(self, INHERITDOC_ID, Inheritdoc));\n\n        // Write function name\n        writer.write_heading(&func_name)?;\n\n        writer.writeln()?;\n\n        // Write function docs\n        writer.writeln_doc(&comments.exclude_tags(&[CommentTag::Param, CommentTag::Return]))?;\n\n        // Write function header\n        writer.write_code(code)?;\n\n        // Write function parameter comments in a table\n        let params = func.params.iter().filter_map(|p| p.1.as_ref()).collect::<Vec<_>>();\n        writer.try_write_param_table(CommentTag::Param, &params, &comments)?;\n\n        // Write function return parameter comments in a table\n        let returns = func.returns.iter().filter_map(|p| p.1.as_ref()).collect::<Vec<_>>();\n        writer.try_write_param_table(CommentTag::Return, &returns, &comments)?;\n\n        writer.writeln()?;\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "crates/doc/src/writer/buf_writer.rs",
    "content": "use crate::{AsDoc, CommentTag, Comments, Deployment, Markdown, writer::traits::ParamLike};\nuse itertools::Itertools;\nuse solang_parser::pt::{\n    EnumDefinition, ErrorParameter, EventParameter, Parameter, VariableDeclaration,\n};\nuse std::{\n    fmt::{self, Display, Write},\n    sync::LazyLock,\n};\n\n/// Solidity language name.\nconst SOLIDITY: &str = \"solidity\";\n\n/// Headers and separator for rendering parameter table.\nconst PARAM_TABLE_HEADERS: &[&str] = &[\"Name\", \"Type\", \"Description\"];\nstatic PARAM_TABLE_SEPARATOR: LazyLock<String> =\n    LazyLock::new(|| PARAM_TABLE_HEADERS.iter().map(|h| \"-\".repeat(h.len())).join(\"|\"));\n\n/// Headers and separator for rendering the deployments table.\nconst DEPLOYMENTS_TABLE_HEADERS: &[&str] = &[\"Network\", \"Address\"];\nstatic DEPLOYMENTS_TABLE_SEPARATOR: LazyLock<String> =\n    LazyLock::new(|| DEPLOYMENTS_TABLE_HEADERS.iter().map(|h| \"-\".repeat(h.len())).join(\"|\"));\n\n/// Headers and separator for rendering the variants table.\nconst VARIANTS_TABLE_HEADERS: &[&str] = &[\"Name\", \"Description\"];\nstatic VARIANTS_TABLE_SEPARATOR: LazyLock<String> =\n    LazyLock::new(|| VARIANTS_TABLE_HEADERS.iter().map(|h| \"-\".repeat(h.len())).join(\"|\"));\n\n/// The buffered writer.\n/// Writes various display items into the internal buffer.\n#[derive(Debug, Default)]\npub struct BufWriter {\n    buf: String,\n}\n\nimpl BufWriter {\n    /// Create new instance of [BufWriter] from [ToString].\n    pub fn new(content: impl ToString) -> Self {\n        Self { buf: content.to_string() }\n    }\n\n    /// Returns true if the buffer is empty.\n    pub fn is_empty(&self) -> bool {\n        self.buf.is_empty()\n    }\n\n    /// Write [AsDoc] implementation to the buffer.\n    pub fn write_doc<T: AsDoc>(&mut self, doc: &T) -> fmt::Result {\n        write!(self.buf, \"{}\", doc.as_doc()?)\n    }\n\n    /// Write [AsDoc] implementation to the buffer with newline.\n    pub fn writeln_doc<T: AsDoc>(&mut self, doc: &T) -> fmt::Result {\n        writeln!(self.buf, \"{}\", doc.as_doc()?)\n    }\n\n    /// Writes raw content to the buffer.\n    pub fn write_raw<T: Display>(&mut self, content: T) -> fmt::Result {\n        write!(self.buf, \"{content}\")\n    }\n\n    /// Writes raw content to the buffer with newline.\n    pub fn writeln_raw<T: Display>(&mut self, content: T) -> fmt::Result {\n        writeln!(self.buf, \"{content}\")\n    }\n\n    /// Writes newline to the buffer.\n    pub fn writeln(&mut self) -> fmt::Result {\n        writeln!(self.buf)\n    }\n\n    /// Writes a title to the buffer formatted as [Markdown::H1].\n    pub fn write_title(&mut self, title: &str) -> fmt::Result {\n        writeln!(self.buf, \"{}\", Markdown::H1(title))\n    }\n\n    /// Writes a subtitle to the bugger formatted as [Markdown::H2].\n    pub fn write_subtitle(&mut self, subtitle: &str) -> fmt::Result {\n        writeln!(self.buf, \"{}\", Markdown::H2(subtitle))\n    }\n\n    /// Writes heading to the buffer formatted as [Markdown::H3].\n    pub fn write_heading(&mut self, heading: &str) -> fmt::Result {\n        writeln!(self.buf, \"{}\", Markdown::H3(heading))\n    }\n\n    /// Writes text in italics to the buffer formatted as [Markdown::Italic].\n    pub fn write_italic(&mut self, text: &str) -> fmt::Result {\n        writeln!(self.buf, \"{}\", Markdown::Italic(text))\n    }\n\n    /// Writes dev content to the buffer, handling markdown lists properly.\n    /// If the content contains markdown lists, it formats them correctly.\n    /// Otherwise, it writes the content in italics.\n    pub fn write_dev_content(&mut self, text: &str) -> fmt::Result {\n        for line in text.lines() {\n            writeln!(self.buf, \"{line}\")?;\n        }\n\n        Ok(())\n    }\n\n    /// Writes bold text to the buffer formatted as [Markdown::Bold].\n    pub fn write_bold(&mut self, text: &str) -> fmt::Result {\n        writeln!(self.buf, \"{}\", Markdown::Bold(text))\n    }\n\n    /// Writes link to the buffer formatted as [Markdown::Link].\n    pub fn write_link(&mut self, name: &str, path: &str) -> fmt::Result {\n        writeln!(self.buf, \"{}\", Markdown::Link(name, path))\n    }\n\n    /// Writes a list item to the buffer indented by specified depth.\n    pub fn write_list_item(&mut self, item: &str, depth: usize) -> fmt::Result {\n        let indent = \" \".repeat(depth * 2);\n        writeln!(self.buf, \"{indent}- {item}\")\n    }\n\n    /// Writes a link to the buffer as a list item.\n    pub fn write_link_list_item(&mut self, name: &str, path: &str, depth: usize) -> fmt::Result {\n        let link = Markdown::Link(name, path);\n        self.write_list_item(&link.as_doc()?, depth)\n    }\n\n    /// Writes a solidity code block to the buffer.\n    pub fn write_code(&mut self, code: &str) -> fmt::Result {\n        writeln!(self.buf, \"{}\", Markdown::CodeBlock(SOLIDITY, code))\n    }\n\n    /// Write an item section to the buffer. First write comments, the item itself as code.\n    pub fn write_section(&mut self, comments: &Comments, code: &str) -> fmt::Result {\n        self.writeln_raw(comments.as_doc()?)?;\n        self.write_code(code)?;\n        self.writeln()\n    }\n\n    /// Tries to write the table to the buffer.\n    /// Doesn't write anything if either params or comments are empty.\n    fn try_write_table<T>(\n        &mut self,\n        tag: CommentTag,\n        params: &[T],\n        comments: &Comments,\n        heading: &str,\n    ) -> fmt::Result\n    where\n        T: ParamLike,\n    {\n        let comments = comments.include_tag(tag.clone());\n\n        // There is nothing to write.\n        if params.is_empty() || comments.is_empty() {\n            return Ok(());\n        }\n\n        self.write_bold(heading)?;\n        self.writeln()?;\n\n        self.write_piped(&PARAM_TABLE_HEADERS.join(\"|\"))?;\n        self.write_piped(&PARAM_TABLE_SEPARATOR)?;\n\n        for (index, param) in params.iter().enumerate() {\n            let param_name = param.name();\n\n            let mut comment = param_name.as_ref().and_then(|name| {\n                comments.iter().find_map(|comment| comment.match_first_word(name))\n            });\n\n            // If it's a return tag and couldn't match by first word,\n            // lookup the doc by index.\n            if comment.is_none() && matches!(tag, CommentTag::Return) {\n                comment = comments.get(index).map(|c| &*c.value);\n            }\n\n            let row = [\n                Markdown::Code(param_name.unwrap_or(\"<none>\")).as_doc()?,\n                Markdown::Code(&param.type_name()).as_doc()?,\n                comment.unwrap_or_default().replace('\\n', \" \"),\n            ];\n            self.write_piped(&row.join(\"|\"))?;\n        }\n\n        self.writeln()?;\n\n        Ok(())\n    }\n\n    /// Tries to write the properties table to the buffer.\n    /// Doesn't write anything if either params or comments are empty.\n    pub fn try_write_properties_table(\n        &mut self,\n        params: &[VariableDeclaration],\n        comments: &Comments,\n    ) -> fmt::Result {\n        self.try_write_table(CommentTag::Param, params, comments, \"Properties\")\n    }\n\n    /// Tries to write the variant table to the buffer.\n    /// Doesn't write anything if either params or comments are empty.\n    pub fn try_write_variant_table(\n        &mut self,\n        params: &EnumDefinition,\n        comments: &Comments,\n    ) -> fmt::Result {\n        let comments = comments.include_tags(&[CommentTag::Param]);\n\n        // There is nothing to write.\n        if comments.is_empty() {\n            return Ok(());\n        }\n\n        self.write_bold(\"Variants\")?;\n        self.writeln()?;\n\n        self.write_piped(&VARIANTS_TABLE_HEADERS.join(\"|\"))?;\n        self.write_piped(&VARIANTS_TABLE_SEPARATOR)?;\n\n        for value in &params.values {\n            let param_name = value.as_ref().map(|v| v.name.clone());\n\n            let comment = param_name.as_ref().and_then(|name| {\n                comments.iter().find_map(|comment| comment.match_first_word(name))\n            });\n\n            let row = [\n                Markdown::Code(&param_name.unwrap_or(\"<none>\".to_string())).as_doc()?,\n                comment.unwrap_or_default().replace('\\n', \" \"),\n            ];\n            self.write_piped(&row.join(\"|\"))?;\n        }\n\n        self.writeln()?;\n\n        Ok(())\n    }\n\n    /// Tries to write the parameters table to the buffer.\n    /// Doesn't write anything if either params or comments are empty.\n    pub fn try_write_events_table(\n        &mut self,\n        params: &[EventParameter],\n        comments: &Comments,\n    ) -> fmt::Result {\n        self.try_write_table(CommentTag::Param, params, comments, \"Parameters\")\n    }\n\n    /// Tries to write the parameters table to the buffer.\n    /// Doesn't write anything if either params or comments are empty.\n    pub fn try_write_errors_table(\n        &mut self,\n        params: &[ErrorParameter],\n        comments: &Comments,\n    ) -> fmt::Result {\n        self.try_write_table(CommentTag::Param, params, comments, \"Parameters\")\n    }\n\n    /// Tries to write the parameters table to the buffer.\n    /// Doesn't write anything if either params or comments are empty.\n    pub fn try_write_param_table(\n        &mut self,\n        tag: CommentTag,\n        params: &[&Parameter],\n        comments: &Comments,\n    ) -> fmt::Result {\n        let heading = match &tag {\n            CommentTag::Param => \"Parameters\",\n            CommentTag::Return => \"Returns\",\n            _ => return Err(fmt::Error),\n        };\n\n        self.try_write_table(tag, params, comments, heading)\n    }\n\n    /// Writes the deployment table to the buffer.\n    pub fn write_deployments_table(&mut self, deployments: Vec<Deployment>) -> fmt::Result {\n        self.write_bold(\"Deployments\")?;\n        self.writeln()?;\n\n        self.write_piped(&DEPLOYMENTS_TABLE_HEADERS.join(\"|\"))?;\n        self.write_piped(&DEPLOYMENTS_TABLE_SEPARATOR)?;\n\n        for deployment in deployments {\n            let mut network = deployment.network.ok_or(fmt::Error)?;\n            network[0..1].make_ascii_uppercase();\n\n            let row = [\n                Markdown::Bold(&network).as_doc()?,\n                Markdown::Code(&format!(\"{:?}\", deployment.address)).as_doc()?,\n            ];\n            self.write_piped(&row.join(\"|\"))?;\n        }\n\n        self.writeln()?;\n\n        Ok(())\n    }\n\n    /// Write content to the buffer surrounded by pipes.\n    pub fn write_piped(&mut self, content: &str) -> fmt::Result {\n        self.write_raw(\"|\")?;\n        self.write_raw(content)?;\n        self.writeln_raw(\"|\")\n    }\n\n    /// Finish and return underlying buffer.\n    pub fn finish(self) -> String {\n        self.buf\n    }\n}\n"
  },
  {
    "path": "crates/doc/src/writer/markdown.rs",
    "content": "use crate::{AsDoc, AsDocResult};\n\n/// The markdown format.\n#[derive(Debug)]\npub enum Markdown<'a> {\n    /// H1 heading item.\n    H1(&'a str),\n    /// H2 heading item.\n    H2(&'a str),\n    /// H3 heading item.\n    H3(&'a str),\n    /// Italic item.\n    Italic(&'a str),\n    /// Bold item.\n    Bold(&'a str),\n    /// Link item.\n    Link(&'a str, &'a str),\n    /// Code item.\n    Code(&'a str),\n    /// Code block item.\n    CodeBlock(&'a str, &'a str),\n}\n\nimpl AsDoc for Markdown<'_> {\n    fn as_doc(&self) -> AsDocResult {\n        let doc = match self {\n            Self::H1(val) => format!(\"# {val}\"),\n            Self::H2(val) => format!(\"## {val}\"),\n            Self::H3(val) => format!(\"### {val}\"),\n            Self::Italic(val) => format!(\"*{val}*\"),\n            Self::Bold(val) => format!(\"**{val}**\"),\n            Self::Link(val, link) => format!(\"[{val}]({link})\"),\n            Self::Code(val) => format!(\"`{val}`\"),\n            Self::CodeBlock(lang, val) => format!(\"```{lang}\\n{val}\\n```\"),\n        };\n        Ok(doc)\n    }\n}\n\nimpl std::fmt::Display for Markdown<'_> {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        f.write_fmt(format_args!(\"{}\", self.as_doc()?))\n    }\n}\n"
  },
  {
    "path": "crates/doc/src/writer/mod.rs",
    "content": "//! The module for writing and formatting various parse tree items.\n\nmod as_doc;\nmod buf_writer;\nmod markdown;\n\npub use as_doc::{AsDoc, AsDocResult};\npub use buf_writer::BufWriter;\npub use markdown::Markdown;\n\nmod traits;\n"
  },
  {
    "path": "crates/doc/src/writer/traits.rs",
    "content": "//! Helper traits for writing documentation.\n\nuse solang_parser::pt::Expression;\n\n/// Helper trait to abstract over a solang type that can be documented as parameter\npub(crate) trait ParamLike {\n    /// Returns the type of the parameter.\n    fn ty(&self) -> &Expression;\n\n    /// Returns the type as a string.\n    fn type_name(&self) -> String {\n        self.ty().to_string()\n    }\n\n    /// Returns the identifier of the parameter.\n    fn name(&self) -> Option<&str>;\n}\n\nimpl ParamLike for solang_parser::pt::Parameter {\n    fn ty(&self) -> &Expression {\n        &self.ty\n    }\n\n    fn name(&self) -> Option<&str> {\n        self.name.as_ref().map(|id| id.name.as_str())\n    }\n}\n\nimpl ParamLike for solang_parser::pt::VariableDeclaration {\n    fn ty(&self) -> &Expression {\n        &self.ty\n    }\n\n    fn name(&self) -> Option<&str> {\n        self.name.as_ref().map(|id| id.name.as_str())\n    }\n}\n\nimpl ParamLike for solang_parser::pt::EventParameter {\n    fn ty(&self) -> &Expression {\n        &self.ty\n    }\n\n    fn name(&self) -> Option<&str> {\n        self.name.as_ref().map(|id| id.name.as_str())\n    }\n}\n\nimpl ParamLike for solang_parser::pt::ErrorParameter {\n    fn ty(&self) -> &Expression {\n        &self.ty\n    }\n\n    fn name(&self) -> Option<&str> {\n        self.name.as_ref().map(|id| id.name.as_str())\n    }\n}\n\nimpl<T> ParamLike for &T\nwhere\n    T: ParamLike,\n{\n    fn ty(&self) -> &Expression {\n        T::ty(*self)\n    }\n\n    fn name(&self) -> Option<&str> {\n        T::name(*self)\n    }\n}\n"
  },
  {
    "path": "crates/doc/static/book.css",
    "content": "table {\n    margin: 0 auto;\n    border-collapse: collapse;\n    width: 100%;\n}\n\ntable td:first-child {\n    width: 15%;\n}\n  \ntable td:nth-child(2) {\n    width: 25%;\n}"
  },
  {
    "path": "crates/doc/static/book.toml",
    "content": "# For more configuration see https://rust-lang.github.io/mdBook/format/configuration/index.html\n[book]\nsrc = \"src\"\n\n[output.html]\nno-section-label = true\nadditional-js = [\"solidity.min.js\"]\nadditional-css = [\"book.css\"]\nmathjax-support = true\n\n[output.html.fold]\nenable = true\n"
  },
  {
    "path": "crates/evm/abi/Cargo.toml",
    "content": "[package]\nname = \"foundry-evm-abi\"\ndescription = \"Solidity ABI-related utilities and `sol!` definitions\"\n\nversion.workspace = true\nedition.workspace = true\nrust-version.workspace = true\nauthors.workspace = true\nlicense.workspace = true\nhomepage.workspace = true\nrepository.workspace = true\n\n[lints]\nworkspace = true\n\n[dependencies]\nfoundry-common-fmt.workspace = true\nfoundry-macros.workspace = true\n\nalloy-primitives.workspace = true\nalloy-sol-types = { workspace = true, features = [\"json\"] }\n\nderive_more.workspace = true\nitertools.workspace = true"
  },
  {
    "path": "crates/evm/abi/src/Console.json",
    "content": "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes10\",\"name\":\"\",\"type\":\"bytes10\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes11\",\"name\":\"\",\"type\":\"bytes11\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes25\",\"name\":\"\",\"type\":\"bytes25\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"int256\",\"name\":\"\",\"type\":\"int256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes3\",\"name\":\"\",\"type\":\"bytes3\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes17\",\"name\":\"\",\"type\":\"bytes17\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes27\",\"name\":\"\",\"type\":\"bytes27\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"int256\",\"name\":\"\",\"type\":\"int256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes29\",\"name\":\"\",\"type\":\"bytes29\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes7\",\"name\":\"\",\"type\":\"bytes7\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes8\",\"name\":\"\",\"type\":\"bytes8\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes20\",\"name\":\"\",\"type\":\"bytes20\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes19\",\"name\":\"\",\"type\":\"bytes19\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes16\",\"name\":\"\",\"type\":\"bytes16\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes1\",\"name\":\"\",\"type\":\"bytes1\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes12\",\"name\":\"\",\"type\":\"bytes12\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes9\",\"name\":\"\",\"type\":\"bytes9\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes14\",\"name\":\"\",\"type\":\"bytes14\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes13\",\"name\":\"\",\"type\":\"bytes13\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes5\",\"name\":\"\",\"type\":\"bytes5\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes23\",\"name\":\"\",\"type\":\"bytes23\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes6\",\"name\":\"\",\"type\":\"bytes6\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes31\",\"name\":\"\",\"type\":\"bytes31\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes18\",\"name\":\"\",\"type\":\"bytes18\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes28\",\"name\":\"\",\"type\":\"bytes28\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes22\",\"name\":\"\",\"type\":\"bytes22\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes15\",\"name\":\"\",\"type\":\"bytes15\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"\",\"type\":\"bytes4\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes2\",\"name\":\"\",\"type\":\"bytes2\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes21\",\"name\":\"\",\"type\":\"bytes21\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes30\",\"name\":\"\",\"type\":\"bytes30\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes24\",\"name\":\"\",\"type\":\"bytes24\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes26\",\"name\":\"\",\"type\":\"bytes26\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"log\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"}]"
  },
  {
    "path": "crates/evm/abi/src/console/ds.rs",
    "content": "//! DSTest log interface.\n\nuse super::{format_units_int, format_units_uint};\nuse alloy_primitives::hex;\nuse alloy_sol_types::sol;\nuse derive_more::Display;\nuse foundry_common_fmt::UIfmt;\nuse itertools::Itertools;\n\n// Using UIfmt for consistent and user-friendly formatting\n\nsol! {\n#[sol(abi)]\n#[derive(Display)]\ninterface Console {\n    #[display(\"{}\", val.pretty())]\n    event log(string val);\n\n    #[display(\"{}\", hex::encode_prefixed(val))]\n    event logs(bytes val);\n\n    #[display(\"{}\", val.pretty())]\n    event log_address(address val);\n\n    #[display(\"{}\", val.pretty())]\n    event log_bytes32(bytes32 val);\n\n    #[display(\"{}\", val.pretty())]\n    event log_int(int val);\n\n    #[display(\"{}\", val.pretty())]\n    event log_uint(uint val);\n\n    #[display(\"{}\", hex::encode_prefixed(val))]\n    event log_bytes(bytes val);\n\n    #[display(\"{}\", val.pretty())]\n    event log_string(string val);\n\n    #[display(\"[{}]\", val.iter().map(|v| v.pretty()).format(\", \"))]\n    event log_array(uint256[] val);\n\n    #[display(\"[{}]\", val.iter().map(|v| v.pretty()).format(\", \"))]\n    event log_array(int256[] val);\n\n    #[display(\"[{}]\", val.iter().map(|v| v.pretty()).format(\", \"))]\n    event log_array(address[] val);\n\n    #[display(\"{}: {}\", key.pretty(), val.pretty())]\n    event log_named_address(string key, address val);\n\n    #[display(\"{}: {}\", key.pretty(), val.pretty())]\n    event log_named_bytes32(string key, bytes32 val);\n\n    #[display(\"{}: {}\", key.pretty(), format_units_int(val, decimals))]\n    event log_named_decimal_int(string key, int val, uint decimals);\n\n    #[display(\"{}: {}\", key.pretty(), format_units_uint(val, decimals))]\n    event log_named_decimal_uint(string key, uint val, uint decimals);\n\n    #[display(\"{}: {}\", key.pretty(), val.pretty())]\n    event log_named_int(string key, int val);\n\n    #[display(\"{}: {}\", key.pretty(), val.pretty())]\n    event log_named_uint(string key, uint val);\n\n    #[display(\"{}: {}\", key.pretty(), hex::encode_prefixed(val))]\n    event log_named_bytes(string key, bytes val);\n\n    #[display(\"{}: {}\", key.pretty(), val.pretty())]\n    event log_named_string(string key, string val);\n\n    #[display(\"{}: [{}]\", key.pretty(), val.iter().map(|v| v.pretty()).format(\", \"))]\n    event log_named_array(string key, uint256[] val);\n\n    #[display(\"{}: [{}]\", key.pretty(), val.iter().map(|v| v.pretty()).format(\", \"))]\n    event log_named_array(string key, int256[] val);\n\n    #[display(\"{}: [{}]\", key.pretty(), val.iter().map(|v| v.pretty()).format(\", \"))]\n    event log_named_array(string key, address[] val);\n}\n}\n\npub use Console::*;\n"
  },
  {
    "path": "crates/evm/abi/src/console/hh.rs",
    "content": "//! Hardhat `console.sol` interface.\n\nuse alloy_sol_types::sol;\nuse foundry_common_fmt::*;\nuse foundry_macros::ConsoleFmt;\n\nsol!(\n    #[sol(abi)]\n    #[derive(ConsoleFmt)]\n    Console,\n    \"src/Console.json\"\n);\n\npub use Console::*;\n"
  },
  {
    "path": "crates/evm/abi/src/console/mod.rs",
    "content": "use alloy_primitives::{I256, U256};\n\npub mod ds;\npub mod hh;\n\npub fn format_units_int(x: &I256, decimals: &U256) -> String {\n    let (sign, x) = x.into_sign_and_abs();\n    format!(\"{sign}{}\", format_units_uint(&x, decimals))\n}\n\npub fn format_units_uint(x: &U256, decimals: &U256) -> String {\n    match alloy_primitives::utils::Unit::new(decimals.saturating_to::<u8>()) {\n        Some(units) => alloy_primitives::utils::ParseUnits::U256(*x).format_units(units),\n        None => x.to_string(),\n    }\n}\n"
  },
  {
    "path": "crates/evm/abi/src/console.py",
    "content": "#!/usr/bin/env python3\n# Generates the JSON ABI for console.sol.\n\nimport json\nimport re\nimport subprocess\nimport sys\n\n\ndef main():\n    if len(sys.argv) != 3:\n        print(f\"Usage: {sys.argv[0]} <console.sol> <Console.json>\")\n        sys.exit(1)\n    [console_file, abi_file] = sys.argv[1:3]\n\n    # Parse signatures from `console.sol`'s string literals\n    console_sol = open(console_file).read()\n    sig_strings = re.findall(\n        r'\"(log.*?)\"',\n        console_sol,\n    )\n    raw_sigs = [s.strip().strip('\"') for s in sig_strings]\n    sigs = [\n        s.replace(\"string\", \"string memory\").replace(\"bytes)\", \"bytes memory)\")\n        for s in raw_sigs\n    ]\n    sigs = list(set(sigs))\n\n    # Get HardhatConsole ABI\n    s = \"interface HardhatConsole{\\n\"\n    for sig in sigs:\n        s += f\"function {sig} external pure;\\n\"\n    s += \"\\n}\"\n    r = subprocess.run(\n        [\"solc\", \"-\", \"--combined-json\", \"abi\"],\n        input=s.encode(\"utf8\"),\n        capture_output=True,\n    )\n    combined = json.loads(r.stdout.strip())\n    abi = combined[\"contracts\"][\"<stdin>:HardhatConsole\"][\"abi\"]\n    open(abi_file, \"w\").write(json.dumps(abi, separators=(\",\", \":\"), indent=None))\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "crates/evm/abi/src/lib.rs",
    "content": "//! Solidity ABI-related utilities and [`sol!`](alloy_sol_types::sol) definitions.\n\n#![cfg_attr(not(test), warn(unused_crate_dependencies))]\n#![cfg_attr(docsrs, feature(doc_cfg))]\n\npub mod console;\n"
  },
  {
    "path": "crates/evm/core/Cargo.toml",
    "content": "[package]\nname = \"foundry-evm-core\"\ndescription = \"Core EVM abstractions\"\n\nversion.workspace = true\nedition.workspace = true\nrust-version.workspace = true\nauthors.workspace = true\nlicense.workspace = true\nhomepage.workspace = true\nrepository.workspace = true\n\n[lints]\nworkspace = true\n\n[dependencies]\nfoundry-cheatcodes-spec.workspace = true\nfoundry-common.workspace = true\nfoundry-config.workspace = true\nfoundry-evm-abi.workspace = true\nfoundry-evm-networks.workspace = true\n\nalloy-chains.workspace = true\nalloy-dyn-abi = { workspace = true, features = [\"arbitrary\", \"eip712\"] }\nalloy-evm = { workspace = true, features = [\"rpc\"] }\nalloy-genesis.workspace = true\nalloy-hardforks.workspace = true\nalloy-op-hardforks.workspace = true\nalloy-json-abi.workspace = true\nalloy-primitives = { workspace = true, features = [\n    \"serde\",\n    \"getrandom\",\n    \"arbitrary\",\n    \"rlp\",\n] }\nalloy-provider.workspace = true\nalloy-network.workspace = true\nalloy-consensus.workspace = true\nalloy-rpc-types.workspace = true\nalloy-sol-types.workspace = true\nfoundry-fork-db.workspace = true\n\nrevm = { workspace = true, features = [\n    \"std\",\n    \"serde\",\n    \"memory_limit\",\n    \"optional_eip3607\",\n    \"optional_block_gas_limit\",\n    \"optional_no_base_fee\",\n    \"arbitrary\",\n    \"c-kzg\",\n    \"blst\",\n] }\nrevm-inspectors.workspace = true\nop-revm.workspace = true\nalloy-op-evm.workspace = true\n\nauto_impl.workspace = true\neyre.workspace = true\nfutures.workspace = true\nitertools.workspace = true\nparking_lot.workspace = true\nserde.workspace = true\nserde_json.workspace = true\nthiserror.workspace = true\ntokio = { workspace = true, features = [\"time\", \"macros\"] }\ntracing.workspace = true\nurl.workspace = true\n\n[dev-dependencies]\nfoundry-test-utils.workspace = true\n"
  },
  {
    "path": "crates/evm/core/src/backend/cow.rs",
    "content": "//! A wrapper around `Backend` that is clone-on-write used for fuzzing.\n\nuse super::BackendError;\nuse crate::{\n    EthInspectorExt,\n    backend::{\n        Backend, DatabaseExt, JournaledState, LocalForkId, RevertStateSnapshotAction,\n        diagnostic::RevertDiagnostic,\n    },\n    fork::{CreateFork, ForkId},\n};\nuse alloy_evm::{Evm, EvmEnv};\nuse alloy_genesis::GenesisAccount;\nuse alloy_primitives::{Address, B256, TxKind, U256};\nuse eyre::WrapErr;\nuse foundry_fork_db::DatabaseError;\nuse revm::{\n    Database, DatabaseCommit,\n    bytecode::Bytecode,\n    context::TxEnv,\n    context_interface::result::ResultAndState,\n    database::DatabaseRef,\n    primitives::{HashMap as Map, hardfork::SpecId},\n    state::{Account, AccountInfo, EvmState},\n};\nuse std::{borrow::Cow, collections::BTreeMap};\n\n/// A wrapper around `Backend` that ensures only `revm::DatabaseRef` functions are called.\n///\n/// Any changes made during its existence that affect the caching layer of the underlying Database\n/// will result in a clone of the initial Database. Therefore, this backend type is basically\n/// a clone-on-write `Backend`, where cloning is only necessary if cheatcodes will modify the\n/// `Backend`\n///\n/// Entire purpose of this type is for fuzzing. A test function fuzzer will repeatedly execute the\n/// function via immutable raw (no state changes) calls.\n///\n/// **N.B.**: we're assuming cheatcodes that alter the state (like multi fork swapping) are niche.\n/// If they executed, it will require a clone of the initial input database.\n/// This way we can support these cheatcodes cheaply without adding overhead for tests that\n/// don't make use of them. Alternatively each test case would require its own `Backend` clone,\n/// which would add significant overhead for large fuzz sets even if the Database is not big after\n/// setup.\n#[derive(Clone, Debug)]\npub struct CowBackend<'a> {\n    /// The underlying `Backend`.\n    ///\n    /// No calls on the `CowBackend` will ever persistently modify the `backend`'s state.\n    pub backend: Cow<'a, Backend>,\n    /// Pending initialization params for the backend on first mutable access.\n    /// `None` means the backend has already been initialized for the current call.\n    pending_init: Option<(SpecId, Address, TxKind)>,\n}\n\nimpl<'a> CowBackend<'a> {\n    /// Creates a new `CowBackend` with the given `Backend`.\n    pub fn new_borrowed(backend: &'a Backend) -> Self {\n        Self { backend: Cow::Borrowed(backend), pending_init: None }\n    }\n\n    /// Executes the configured transaction of the `env` without committing state changes\n    ///\n    /// Note: in case there are any cheatcodes executed that modify the environment, this will\n    /// update the given `env` with the new values.\n    #[instrument(name = \"inspect\", level = \"debug\", skip_all)]\n    pub fn inspect<I: EthInspectorExt>(\n        &mut self,\n        evm_env: &mut EvmEnv,\n        tx_env: &mut TxEnv,\n        inspector: I,\n    ) -> eyre::Result<ResultAndState> {\n        // this is a new call to inspect with a new env, so even if we've cloned the backend\n        // already, we reset the initialized state\n        self.pending_init = Some((evm_env.cfg_env.spec, tx_env.caller, tx_env.kind));\n\n        let mut evm = crate::evm::new_eth_evm_with_inspector(\n            self,\n            evm_env.clone(),\n            tx_env.clone(),\n            inspector,\n        );\n\n        let res = evm.transact(tx_env.clone()).wrap_err(\"EVM error\")?;\n\n        *evm_env = EvmEnv::new(evm.cfg.clone(), evm.block.clone());\n        *tx_env = evm.tx.clone();\n\n        Ok(res)\n    }\n\n    /// Returns whether there was a state snapshot failure in the backend.\n    ///\n    /// This is bubbled up from the underlying Copy-On-Write backend when a revert occurs.\n    pub fn has_state_snapshot_failure(&self) -> bool {\n        self.backend.has_state_snapshot_failure()\n    }\n\n    /// Returns a mutable instance of the Backend.\n    ///\n    /// If this is the first time this is called, the backed is cloned and initialized.\n    fn backend_mut(&mut self) -> &mut Backend {\n        if let Some((spec_id, caller, tx_kind)) = self.pending_init.take() {\n            let backend = self.backend.to_mut();\n            backend.initialize(spec_id, caller, tx_kind);\n            return backend;\n        }\n        self.backend.to_mut()\n    }\n\n    /// Returns a mutable instance of the Backend if it is initialized.\n    fn initialized_backend_mut(&mut self) -> Option<&mut Backend> {\n        if self.pending_init.is_none() {\n            return Some(self.backend.to_mut());\n        }\n        None\n    }\n}\n\nimpl DatabaseExt for CowBackend<'_> {\n    fn snapshot_state(&mut self, journaled_state: &JournaledState, evm_env: &EvmEnv) -> U256 {\n        self.backend_mut().snapshot_state(journaled_state, evm_env)\n    }\n\n    fn revert_state(\n        &mut self,\n        id: U256,\n        journaled_state: &JournaledState,\n        evm_env: &mut EvmEnv,\n        tx_env: &mut TxEnv,\n        action: RevertStateSnapshotAction,\n    ) -> Option<JournaledState> {\n        self.backend_mut().revert_state(id, journaled_state, evm_env, tx_env, action)\n    }\n\n    fn delete_state_snapshot(&mut self, id: U256) -> bool {\n        // delete state snapshot requires a previous snapshot to be initialized\n        if let Some(backend) = self.initialized_backend_mut() {\n            return backend.delete_state_snapshot(id);\n        }\n        false\n    }\n\n    fn delete_state_snapshots(&mut self) {\n        if let Some(backend) = self.initialized_backend_mut() {\n            backend.delete_state_snapshots()\n        }\n    }\n\n    fn create_fork(&mut self, fork: CreateFork) -> eyre::Result<LocalForkId> {\n        self.backend.to_mut().create_fork(fork)\n    }\n\n    fn create_fork_at_transaction(\n        &mut self,\n        fork: CreateFork,\n        transaction: B256,\n    ) -> eyre::Result<LocalForkId> {\n        self.backend.to_mut().create_fork_at_transaction(fork, transaction)\n    }\n\n    fn select_fork(\n        &mut self,\n        id: LocalForkId,\n        evm_env: &mut EvmEnv,\n        tx_env: &mut TxEnv,\n        journaled_state: &mut JournaledState,\n    ) -> eyre::Result<()> {\n        self.backend_mut().select_fork(id, evm_env, tx_env, journaled_state)\n    }\n\n    fn roll_fork(\n        &mut self,\n        id: Option<LocalForkId>,\n        block_number: u64,\n        evm_env: &mut EvmEnv,\n        tx_env: &mut TxEnv,\n        journaled_state: &mut JournaledState,\n    ) -> eyre::Result<()> {\n        self.backend_mut().roll_fork(id, block_number, evm_env, tx_env, journaled_state)\n    }\n\n    fn roll_fork_to_transaction(\n        &mut self,\n        id: Option<LocalForkId>,\n        transaction: B256,\n        evm_env: &mut EvmEnv,\n        tx_env: &mut TxEnv,\n        journaled_state: &mut JournaledState,\n    ) -> eyre::Result<()> {\n        self.backend_mut().roll_fork_to_transaction(\n            id,\n            transaction,\n            evm_env,\n            tx_env,\n            journaled_state,\n        )\n    }\n\n    fn transact(\n        &mut self,\n        id: Option<LocalForkId>,\n        transaction: B256,\n        evm_env: EvmEnv,\n        tx_env: TxEnv,\n        journaled_state: &mut JournaledState,\n        inspector: &mut dyn EthInspectorExt,\n    ) -> eyre::Result<()> {\n        self.backend_mut().transact(id, transaction, evm_env, tx_env, journaled_state, inspector)\n    }\n\n    fn transact_from_tx(\n        &mut self,\n        tx_env: &TxEnv,\n        evm_env: EvmEnv,\n        journaled_state: &mut JournaledState,\n        inspector: &mut dyn EthInspectorExt,\n    ) -> eyre::Result<()> {\n        self.backend_mut().transact_from_tx(tx_env, evm_env, journaled_state, inspector)\n    }\n\n    fn active_fork_id(&self) -> Option<LocalForkId> {\n        self.backend.active_fork_id()\n    }\n\n    fn active_fork_url(&self) -> Option<String> {\n        self.backend.active_fork_url()\n    }\n\n    fn ensure_fork(&self, id: Option<LocalForkId>) -> eyre::Result<LocalForkId> {\n        self.backend.ensure_fork(id)\n    }\n\n    fn ensure_fork_id(&self, id: LocalForkId) -> eyre::Result<&ForkId> {\n        self.backend.ensure_fork_id(id)\n    }\n\n    fn diagnose_revert(&self, callee: Address, evm_state: &EvmState) -> Option<RevertDiagnostic> {\n        self.backend.diagnose_revert(callee, evm_state)\n    }\n\n    fn load_allocs(\n        &mut self,\n        allocs: &BTreeMap<Address, GenesisAccount>,\n        journaled_state: &mut JournaledState,\n    ) -> Result<(), BackendError> {\n        self.backend.to_mut().load_allocs(allocs, journaled_state)\n    }\n\n    fn clone_account(\n        &mut self,\n        source: &GenesisAccount,\n        target: &Address,\n        journaled_state: &mut JournaledState,\n    ) -> Result<(), BackendError> {\n        self.backend.to_mut().clone_account(source, target, journaled_state)\n    }\n\n    fn is_persistent(&self, acc: &Address) -> bool {\n        self.backend.is_persistent(acc)\n    }\n\n    fn remove_persistent_account(&mut self, account: &Address) -> bool {\n        self.backend.to_mut().remove_persistent_account(account)\n    }\n\n    fn add_persistent_account(&mut self, account: Address) -> bool {\n        self.backend.to_mut().add_persistent_account(account)\n    }\n\n    fn allow_cheatcode_access(&mut self, account: Address) -> bool {\n        self.backend.to_mut().allow_cheatcode_access(account)\n    }\n\n    fn revoke_cheatcode_access(&mut self, account: &Address) -> bool {\n        self.backend.to_mut().revoke_cheatcode_access(account)\n    }\n\n    fn has_cheatcode_access(&self, account: &Address) -> bool {\n        self.backend.has_cheatcode_access(account)\n    }\n\n    fn set_blockhash(&mut self, block_number: U256, block_hash: B256) {\n        self.backend.to_mut().set_blockhash(block_number, block_hash);\n    }\n}\n\nimpl DatabaseRef for CowBackend<'_> {\n    type Error = DatabaseError;\n\n    fn basic_ref(&self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {\n        DatabaseRef::basic_ref(self.backend.as_ref(), address)\n    }\n\n    fn code_by_hash_ref(&self, code_hash: B256) -> Result<Bytecode, Self::Error> {\n        DatabaseRef::code_by_hash_ref(self.backend.as_ref(), code_hash)\n    }\n\n    fn storage_ref(&self, address: Address, index: U256) -> Result<U256, Self::Error> {\n        DatabaseRef::storage_ref(self.backend.as_ref(), address, index)\n    }\n\n    fn block_hash_ref(&self, number: u64) -> Result<B256, Self::Error> {\n        DatabaseRef::block_hash_ref(self.backend.as_ref(), number)\n    }\n}\n\nimpl Database for CowBackend<'_> {\n    type Error = DatabaseError;\n\n    fn basic(&mut self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {\n        DatabaseRef::basic_ref(self, address)\n    }\n\n    fn code_by_hash(&mut self, code_hash: B256) -> Result<Bytecode, Self::Error> {\n        DatabaseRef::code_by_hash_ref(self, code_hash)\n    }\n\n    fn storage(&mut self, address: Address, index: U256) -> Result<U256, Self::Error> {\n        DatabaseRef::storage_ref(self, address, index)\n    }\n\n    fn block_hash(&mut self, number: u64) -> Result<B256, Self::Error> {\n        DatabaseRef::block_hash_ref(self, number)\n    }\n}\n\nimpl DatabaseCommit for CowBackend<'_> {\n    fn commit(&mut self, changes: Map<Address, Account>) {\n        self.backend.to_mut().commit(changes)\n    }\n}\n"
  },
  {
    "path": "crates/evm/core/src/backend/diagnostic.rs",
    "content": "use crate::backend::LocalForkId;\nuse alloy_primitives::{Address, map::AddressHashMap};\nuse itertools::Itertools;\n\n/// Represents possible diagnostic cases on revert\n#[derive(Clone, Debug)]\npub enum RevertDiagnostic {\n    /// The `contract` does not exist on the `active` fork but exist on other fork(s)\n    ContractExistsOnOtherForks {\n        contract: Address,\n        active: LocalForkId,\n        available_on: Vec<LocalForkId>,\n    },\n    ContractDoesNotExist {\n        contract: Address,\n        active: LocalForkId,\n        persistent: bool,\n    },\n}\n\nimpl RevertDiagnostic {\n    /// Converts the diagnostic to a readable error message\n    pub fn to_error_msg(&self, labels: &AddressHashMap<String>) -> String {\n        let get_label =\n            |addr: &Address| labels.get(addr).cloned().unwrap_or_else(|| addr.to_string());\n\n        match self {\n            Self::ContractExistsOnOtherForks { contract, active, available_on } => {\n                let contract_label = get_label(contract);\n\n                format!(\n                    r#\"Contract {} does not exist on active fork with id `{}`\n        But exists on non active forks: `[{}]`\"#,\n                    contract_label,\n                    active,\n                    available_on.iter().format(\", \")\n                )\n            }\n            Self::ContractDoesNotExist { contract, persistent, .. } => {\n                let contract_label = get_label(contract);\n                if *persistent {\n                    format!(\"Contract {contract_label} does not exist\")\n                } else {\n                    format!(\n                        \"Contract {contract_label} does not exist and is not marked as persistent, see `vm.makePersistent()`\"\n                    )\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "crates/evm/core/src/backend/error.rs",
    "content": "use alloy_primitives::Address;\npub use foundry_fork_db::{DatabaseError, DatabaseResult};\nuse revm::context_interface::result::EVMError;\nuse std::convert::Infallible;\n\npub type BackendResult<T> = Result<T, BackendError>;\n\n/// Errors that can happen when working with [`revm::Database`]\n#[derive(Debug, thiserror::Error)]\n#[expect(missing_docs)]\npub enum BackendError {\n    #[error(\"{0}\")]\n    Message(String),\n    #[error(\"cheatcodes are not enabled for {0}; see `vm.allowCheatcodes(address)`\")]\n    NoCheats(Address),\n    #[error(transparent)]\n    Database(#[from] DatabaseError),\n    #[error(\"failed to fetch account info for {0}\")]\n    MissingAccount(Address),\n    #[error(\n        \"CREATE2 Deployer (0x4e59b44847b379578588920ca78fbf26c0b4956c) not present on this chain.\\n\\\n         For a production environment, you can deploy it using the pre-signed transaction from \\\n         https://github.com/Arachnid/deterministic-deployment-proxy.\\n\\\n         For a test environment, you can use `etch` to place the required bytecode at that address.\"\n    )]\n    MissingCreate2Deployer,\n}\n\nimpl BackendError {\n    /// Create a new error with a message\n    pub fn msg(msg: impl Into<String>) -> Self {\n        Self::Message(msg.into())\n    }\n\n    /// Create a new error with a message\n    pub fn display(msg: impl std::fmt::Display) -> Self {\n        Self::Message(msg.to_string())\n    }\n}\n\nimpl From<tokio::task::JoinError> for BackendError {\n    fn from(value: tokio::task::JoinError) -> Self {\n        Self::display(value)\n    }\n}\n\nimpl From<Infallible> for BackendError {\n    fn from(value: Infallible) -> Self {\n        match value {}\n    }\n}\n\n// Note: this is mostly necessary to use some revm internals that return an [EVMError]\nimpl<T: Into<Self>> From<EVMError<T>> for BackendError {\n    fn from(err: EVMError<T>) -> Self {\n        match err {\n            EVMError::Database(err) => err.into(),\n            EVMError::Custom(err) => Self::msg(err),\n            EVMError::Header(err) => Self::msg(err.to_string()),\n            EVMError::Transaction(err) => Self::msg(err.to_string()),\n        }\n    }\n}\n"
  },
  {
    "path": "crates/evm/core/src/backend/in_memory_db.rs",
    "content": "//! In-memory database.\n\nuse crate::state_snapshot::StateSnapshots;\nuse alloy_primitives::{Address, B256, U256};\nuse foundry_fork_db::DatabaseError;\nuse revm::{\n    Database, DatabaseCommit,\n    bytecode::Bytecode,\n    database::{CacheDB, DatabaseRef, EmptyDB},\n    primitives::HashMap as Map,\n    state::{Account, AccountInfo},\n};\n\n/// Type alias for an in-memory database.\n///\n/// See [`EmptyDBWrapper`].\npub type FoundryEvmInMemoryDB = CacheDB<EmptyDBWrapper>;\n\n/// In-memory [`Database`] for Anvil.\n///\n/// This acts like a wrapper type for [`FoundryEvmInMemoryDB`] but is capable of applying snapshots.\n#[derive(Debug)]\npub struct MemDb {\n    pub inner: FoundryEvmInMemoryDB,\n    pub state_snapshots: StateSnapshots<FoundryEvmInMemoryDB>,\n}\n\nimpl Default for MemDb {\n    fn default() -> Self {\n        Self { inner: CacheDB::new(Default::default()), state_snapshots: Default::default() }\n    }\n}\n\nimpl DatabaseRef for MemDb {\n    type Error = DatabaseError;\n\n    fn basic_ref(&self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {\n        DatabaseRef::basic_ref(&self.inner, address)\n    }\n\n    fn code_by_hash_ref(&self, code_hash: B256) -> Result<Bytecode, Self::Error> {\n        DatabaseRef::code_by_hash_ref(&self.inner, code_hash)\n    }\n\n    fn storage_ref(&self, address: Address, index: U256) -> Result<U256, Self::Error> {\n        DatabaseRef::storage_ref(&self.inner, address, index)\n    }\n\n    fn block_hash_ref(&self, number: u64) -> Result<B256, Self::Error> {\n        DatabaseRef::block_hash_ref(&self.inner, number)\n    }\n}\n\nimpl Database for MemDb {\n    type Error = DatabaseError;\n\n    fn basic(&mut self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {\n        // Note: this will always return `Some(AccountInfo)`, See `EmptyDBWrapper`\n        Database::basic(&mut self.inner, address)\n    }\n\n    fn code_by_hash(&mut self, code_hash: B256) -> Result<Bytecode, Self::Error> {\n        Database::code_by_hash(&mut self.inner, code_hash)\n    }\n\n    fn storage(&mut self, address: Address, index: U256) -> Result<U256, Self::Error> {\n        Database::storage(&mut self.inner, address, index)\n    }\n\n    fn block_hash(&mut self, number: u64) -> Result<B256, Self::Error> {\n        Database::block_hash(&mut self.inner, number)\n    }\n}\n\nimpl DatabaseCommit for MemDb {\n    fn commit(&mut self, changes: Map<Address, Account>) {\n        DatabaseCommit::commit(&mut self.inner, changes)\n    }\n}\n\n/// An empty database that always returns default values when queried.\n///\n/// This is just a simple wrapper for `revm::EmptyDB` but implements `DatabaseError` instead, this\n/// way we can unify all different `Database` impls\n///\n/// This will also _always_ return `Some(AccountInfo)`:\n///\n/// The [`Database`] implementation for `CacheDB` manages an `AccountState` for the\n/// `DbAccount`, this will be set to `AccountState::NotExisting` if the account does not exist yet.\n/// This is because there's a distinction between \"non-existing\" and \"empty\",\n/// see <https://github.com/bluealloy/revm/blob/8f4348dc93022cffb3730d9db5d3ab1aad77676a/crates/revm/src/db/in_memory_db.rs#L81-L83>.\n/// If an account is `NotExisting`, `Database::basic_ref` will always return `None` for the\n/// requested `AccountInfo`.\n///\n/// To prevent this, we ensure that a missing account is never marked as `NotExisting` by always\n/// returning `Some` with this type, which will then insert a default [`AccountInfo`] instead\n/// of one marked as `AccountState::NotExisting`.\n#[derive(Clone, Debug, Default)]\npub struct EmptyDBWrapper(EmptyDB);\n\nimpl DatabaseRef for EmptyDBWrapper {\n    type Error = DatabaseError;\n\n    fn basic_ref(&self, _address: Address) -> Result<Option<AccountInfo>, Self::Error> {\n        // Note: this will always return `Some(AccountInfo)`, for the reason explained above\n        Ok(Some(AccountInfo::default()))\n    }\n\n    fn code_by_hash_ref(&self, code_hash: B256) -> Result<Bytecode, Self::Error> {\n        Ok(self.0.code_by_hash_ref(code_hash)?)\n    }\n    fn storage_ref(&self, address: Address, index: U256) -> Result<U256, Self::Error> {\n        Ok(self.0.storage_ref(address, index)?)\n    }\n\n    fn block_hash_ref(&self, number: u64) -> Result<B256, Self::Error> {\n        Ok(self.0.block_hash_ref(number)?)\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use alloy_primitives::b256;\n\n    /// Ensures the `Database(Ref)` implementation for `revm::CacheDB` works as expected\n    ///\n    /// Demonstrates how calling `Database::basic` works if an account does not exist\n    #[test]\n    fn cache_db_insert_basic_non_existing() {\n        let mut db = CacheDB::new(EmptyDB::default());\n        let address = Address::random();\n        // call `basic` on a non-existing account\n        let info = Database::basic(&mut db, address).unwrap();\n        assert!(info.is_none());\n\n        let mut info = info.unwrap_or_default();\n        info.balance = U256::from(500u64);\n\n        // insert the modified account info\n        db.insert_account_info(address, info);\n\n        // now we can call `basic` again and it should return the inserted account info\n        let info = Database::basic(&mut db, address).unwrap();\n        assert!(info.is_some());\n    }\n\n    /// Demonstrates how to insert a new account but not mark it as non-existing\n    #[test]\n    fn cache_db_insert_basic_default() {\n        let mut db = CacheDB::new(EmptyDB::default());\n        let address = Address::random();\n\n        // We use `basic_ref` here to ensure that the account is not marked as `NotExisting`.\n        let info = DatabaseRef::basic_ref(&db, address).unwrap();\n        assert!(info.is_none());\n        let mut info = info.unwrap_or_default();\n        info.balance = U256::from(500u64);\n\n        // insert the modified account info\n        db.insert_account_info(address, info.clone());\n\n        let loaded = Database::basic(&mut db, address).unwrap();\n        assert!(loaded.is_some());\n        assert_eq!(loaded.unwrap(), info)\n    }\n\n    /// Demonstrates that `Database::basic` for `MemDb` will always return the `AccountInfo`\n    #[test]\n    fn mem_db_insert_basic_default() {\n        let mut db = MemDb::default();\n        let address = Address::from_word(b256!(\n            \"0x000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa96045\"\n        ));\n\n        let info = Database::basic(&mut db, address).unwrap();\n        // We know info exists, as MemDb always returns `Some(AccountInfo)` due to the\n        // `EmptyDbWrapper`.\n        assert!(info.is_some());\n        let mut info = info.unwrap();\n        info.balance = U256::from(500u64);\n\n        // insert the modified account info\n        db.inner.insert_account_info(address, info.clone());\n\n        let loaded = Database::basic(&mut db, address).unwrap();\n        assert!(loaded.is_some());\n        assert_eq!(loaded.unwrap(), info)\n    }\n}\n"
  },
  {
    "path": "crates/evm/core/src/backend/mod.rs",
    "content": "//! Foundry's main executor backend abstraction and implementation.\n\nuse crate::{\n    EthInspectorExt, FoundryBlock, FoundryTransaction,\n    constants::{CALLER, CHEATCODE_ADDRESS, DEFAULT_CREATE2_DEPLOYER, TEST_CONTRACT_ADDRESS},\n    evm::new_eth_evm_with_inspector,\n    fork::{CreateFork, ForkId, MultiFork},\n    state_snapshot::StateSnapshots,\n    utils::get_blob_base_fee_update_fraction,\n};\nuse alloy_consensus::{BlockHeader, Typed2718};\nuse alloy_evm::{Evm, EvmEnv, FromRecoveredTx};\nuse alloy_genesis::GenesisAccount;\nuse alloy_network::{\n    AnyNetwork, AnyRpcBlock, AnyRpcTransaction, AnyTxEnvelope, BlockResponse, TransactionResponse,\n};\nuse alloy_primitives::{Address, B256, TxKind, U256, keccak256, uint};\nuse alloy_rpc_types::{BlockNumberOrTag, Transaction};\nuse eyre::Context;\nuse foundry_common::{SYSTEM_TRANSACTION_TYPE, is_known_system_sender};\npub use foundry_fork_db::{BlockchainDb, SharedBackend, cache::BlockchainDbMeta};\nuse revm::{\n    Database, DatabaseCommit, JournalEntry,\n    bytecode::Bytecode,\n    context::{BlockEnv, JournalInner, TxEnv},\n    context_interface::{journaled_state::account::JournaledAccountTr, result::ResultAndState},\n    database::{CacheDB, DatabaseRef},\n    inspector::NoOpInspector,\n    precompile::{PrecompileSpecId, Precompiles},\n    primitives::{HashMap as Map, KECCAK_EMPTY, Log, hardfork::SpecId},\n    state::{Account, AccountInfo, EvmState, EvmStorageSlot},\n};\nuse std::{\n    collections::{BTreeMap, HashMap, HashSet},\n    fmt::Debug,\n    time::Instant,\n};\n\nmod diagnostic;\npub use diagnostic::RevertDiagnostic;\n\nmod error;\npub use error::{BackendError, BackendResult, DatabaseError, DatabaseResult};\n\nmod cow;\npub use cow::CowBackend;\n\nmod in_memory_db;\npub use in_memory_db::{EmptyDBWrapper, FoundryEvmInMemoryDB, MemDb};\n\nmod snapshot;\npub use snapshot::{BackendStateSnapshot, RevertStateSnapshotAction, StateSnapshot};\n\n// A `revm::Database` that is used in forking mode\ntype ForkDB = CacheDB<SharedBackend>;\n\n/// Represents a numeric `ForkId` valid only for the existence of the `Backend`.\n///\n/// The difference between `ForkId` and `LocalForkId` is that `ForkId` tracks pairs of `endpoint +\n/// block` which can be reused by multiple tests, whereas the `LocalForkId` is unique within a test\npub type LocalForkId = U256;\n\n/// Represents the index of a fork in the created forks vector\n/// This is used for fast lookup\ntype ForkLookupIndex = usize;\n\n/// All accounts that will have persistent storage across fork swaps.\nconst DEFAULT_PERSISTENT_ACCOUNTS: [Address; 3] =\n    [CHEATCODE_ADDRESS, DEFAULT_CREATE2_DEPLOYER, CALLER];\n\n/// `bytes32(\"failed\")`, as a storage slot key into [`CHEATCODE_ADDRESS`].\n///\n/// Used by all `forge-std` test contracts and newer `DSTest` test contracts as a global marker for\n/// a failed test.\npub const GLOBAL_FAIL_SLOT: U256 =\n    uint!(0x6661696c65640000000000000000000000000000000000000000000000000000_U256);\n\npub type JournaledState = JournalInner<JournalEntry>;\n\n/// An extension trait that allows us to easily extend the `revm::Inspector` capabilities\n#[auto_impl::auto_impl(&mut)]\npub trait DatabaseExt<BLOCK = BlockEnv, TX = TxEnv, SPEC = SpecId>:\n    Database<Error = DatabaseError> + DatabaseCommit + Debug\n{\n    /// Creates a new state snapshot at the current point of execution.\n    ///\n    /// A state snapshot is associated with a new unique id that's created for the snapshot.\n    /// State snapshots can be reverted: [DatabaseExt::revert_state], however, depending on the\n    /// [RevertStateSnapshotAction], it will keep the snapshot alive or delete it.\n    fn snapshot_state(\n        &mut self,\n        journaled_state: &JournaledState,\n        evm_env: &EvmEnv<SPEC, BLOCK>,\n    ) -> U256;\n\n    /// Reverts the snapshot if it exists\n    ///\n    /// Returns `true` if the snapshot was successfully reverted, `false` if no snapshot for that id\n    /// exists.\n    ///\n    /// **N.B.** While this reverts the state of the evm to the snapshot, it keeps new logs made\n    /// since the snapshots was created. This way we can show logs that were emitted between\n    /// snapshot and its revert.\n    /// This will also revert any changes in the `EvmEnv` and `TxEnv` and replace them with the\n    /// captured values from `Self::snapshot_state`.\n    ///\n    /// Depending on [RevertStateSnapshotAction] it will keep the snapshot alive or delete it.\n    fn revert_state(\n        &mut self,\n        id: U256,\n        journaled_state: &JournaledState,\n        evm_env: &mut EvmEnv<SPEC, BLOCK>,\n        tx_env: &mut TX,\n        action: RevertStateSnapshotAction,\n    ) -> Option<JournaledState>;\n\n    /// Deletes the state snapshot with the given `id`\n    ///\n    /// Returns `true` if the snapshot was successfully deleted, `false` if no snapshot for that id\n    /// exists.\n    fn delete_state_snapshot(&mut self, id: U256) -> bool;\n\n    /// Deletes all state snapshots.\n    fn delete_state_snapshots(&mut self);\n\n    /// Creates and also selects a new fork\n    ///\n    /// This is basically `create_fork` + `select_fork`\n    fn create_select_fork(\n        &mut self,\n        fork: CreateFork,\n        evm_env: &mut EvmEnv<SPEC, BLOCK>,\n        tx_env: &mut TX,\n        journaled_state: &mut JournaledState,\n    ) -> eyre::Result<LocalForkId> {\n        let id = self.create_fork(fork)?;\n        self.select_fork(id, evm_env, tx_env, journaled_state)?;\n        Ok(id)\n    }\n\n    /// Creates and also selects a new fork\n    ///\n    /// This is basically `create_fork` + `select_fork`\n    fn create_select_fork_at_transaction(\n        &mut self,\n        fork: CreateFork,\n        evm_env: &mut EvmEnv<SPEC, BLOCK>,\n        tx_env: &mut TX,\n        journaled_state: &mut JournaledState,\n        transaction: B256,\n    ) -> eyre::Result<LocalForkId> {\n        let id = self.create_fork_at_transaction(fork, transaction)?;\n        self.select_fork(id, evm_env, tx_env, journaled_state)?;\n        Ok(id)\n    }\n\n    /// Creates a new fork but does _not_ select it\n    fn create_fork(&mut self, fork: CreateFork) -> eyre::Result<LocalForkId>;\n\n    /// Creates a new fork but does _not_ select it\n    fn create_fork_at_transaction(\n        &mut self,\n        fork: CreateFork,\n        transaction: B256,\n    ) -> eyre::Result<LocalForkId>;\n\n    /// Selects the fork's state\n    ///\n    /// This will also modify the current `EvmEnv` and `TxEnv`.\n    ///\n    /// **Note**: this does not change the local state, but swaps the remote state\n    ///\n    /// # Errors\n    ///\n    /// Returns an error if no fork with the given `id` exists\n    fn select_fork(\n        &mut self,\n        id: LocalForkId,\n        evm_env: &mut EvmEnv<SPEC, BLOCK>,\n        tx_env: &mut TX,\n        journaled_state: &mut JournaledState,\n    ) -> eyre::Result<()>;\n\n    /// Updates the fork to given block number.\n    ///\n    /// This will essentially create a new fork at the given block height.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error if not matching fork was found.\n    fn roll_fork(\n        &mut self,\n        id: Option<LocalForkId>,\n        block_number: u64,\n        evm_env: &mut EvmEnv<SPEC, BLOCK>,\n        tx_env: &mut TX,\n        journaled_state: &mut JournaledState,\n    ) -> eyre::Result<()>;\n\n    /// Updates the fork to given transaction hash\n    ///\n    /// This will essentially create a new fork at the block this transaction was mined and replays\n    /// all transactions up until the given transaction.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error if not matching fork was found.\n    fn roll_fork_to_transaction(\n        &mut self,\n        id: Option<LocalForkId>,\n        transaction: B256,\n        evm_env: &mut EvmEnv<SPEC, BLOCK>,\n        tx_env: &mut TX,\n        journaled_state: &mut JournaledState,\n    ) -> eyre::Result<()>;\n\n    /// Fetches the given transaction for the fork and executes it, committing the state in the DB\n    fn transact(\n        &mut self,\n        id: Option<LocalForkId>,\n        transaction: B256,\n        evm_env: EvmEnv<SPEC, BLOCK>,\n        tx_env: TX,\n        journaled_state: &mut JournaledState,\n        inspector: &mut dyn EthInspectorExt<BLOCK, TX, SPEC>,\n    ) -> eyre::Result<()>;\n\n    /// Executes a given TransactionRequest, commits the new state to the DB\n    fn transact_from_tx(\n        &mut self,\n        tx_env: &TX,\n        evm_env: EvmEnv<SPEC, BLOCK>,\n        journaled_state: &mut JournaledState,\n        inspector: &mut dyn EthInspectorExt<BLOCK, TX, SPEC>,\n    ) -> eyre::Result<()>;\n\n    /// Returns the `ForkId` that's currently used in the database, if fork mode is on\n    fn active_fork_id(&self) -> Option<LocalForkId>;\n\n    /// Returns the Fork url that's currently used in the database, if fork mode is on\n    fn active_fork_url(&self) -> Option<String>;\n\n    /// Whether the database is currently in forked mode.\n    fn is_forked_mode(&self) -> bool {\n        self.active_fork_id().is_some()\n    }\n\n    /// Ensures that an appropriate fork exists\n    ///\n    /// If `id` contains a requested `Fork` this will ensure it exists.\n    /// Otherwise, this returns the currently active fork.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error if the given `id` does not match any forks\n    ///\n    /// Returns an error if no fork exists\n    fn ensure_fork(&self, id: Option<LocalForkId>) -> eyre::Result<LocalForkId>;\n\n    /// Ensures that a corresponding `ForkId` exists for the given local `id`\n    fn ensure_fork_id(&self, id: LocalForkId) -> eyre::Result<&ForkId>;\n\n    /// Handling multiple accounts/new contracts in a multifork environment can be challenging since\n    /// every fork has its own standalone storage section. So this can be a common error to run\n    /// into:\n    ///\n    /// ```solidity\n    /// function testCanDeploy() public {\n    ///    vm.selectFork(mainnetFork);\n    ///    // contract created while on `mainnetFork`\n    ///    DummyContract dummy = new DummyContract();\n    ///    // this will succeed\n    ///    dummy.hello();\n    ///\n    ///    vm.selectFork(optimismFork);\n    ///\n    ///    vm.expectRevert();\n    ///    // this will revert since `dummy` contract only exists on `mainnetFork`\n    ///    dummy.hello();\n    /// }\n    /// ```\n    ///\n    /// If this happens (`dummy.hello()`), or more general, a call on an address that's not a\n    /// contract, revm will revert without useful context. This call will check in this context if\n    /// `address(dummy)` belongs to an existing contract and if not will check all other forks if\n    /// the contract is deployed there.\n    ///\n    /// Returns a more useful error message if that's the case\n    fn diagnose_revert(&self, callee: Address, evm_state: &EvmState) -> Option<RevertDiagnostic>;\n\n    /// Loads the account allocs from the given `allocs` map into the passed [JournaledState].\n    ///\n    /// Returns [Ok] if all accounts were successfully inserted into the journal, [Err] otherwise.\n    fn load_allocs(\n        &mut self,\n        allocs: &BTreeMap<Address, GenesisAccount>,\n        journaled_state: &mut JournaledState,\n    ) -> Result<(), BackendError>;\n\n    /// Copies bytecode, storage, nonce and balance from the given genesis account to the target\n    /// address.\n    ///\n    /// Returns [Ok] if data was successfully inserted into the journal, [Err] otherwise.\n    fn clone_account(\n        &mut self,\n        source: &GenesisAccount,\n        target: &Address,\n        journaled_state: &mut JournaledState,\n    ) -> Result<(), BackendError>;\n\n    /// Returns true if the given account is currently marked as persistent.\n    fn is_persistent(&self, acc: &Address) -> bool;\n\n    /// Revokes persistent status from the given account.\n    fn remove_persistent_account(&mut self, account: &Address) -> bool;\n\n    /// Marks the given account as persistent.\n    fn add_persistent_account(&mut self, account: Address) -> bool;\n\n    /// Removes persistent status from all given accounts.\n    #[auto_impl(keep_default_for(&, &mut, Rc, Arc, Box))]\n    fn remove_persistent_accounts(&mut self, accounts: impl IntoIterator<Item = Address>)\n    where\n        Self: Sized,\n    {\n        for acc in accounts {\n            self.remove_persistent_account(&acc);\n        }\n    }\n\n    /// Extends the persistent accounts with the accounts the iterator yields.\n    #[auto_impl(keep_default_for(&, &mut, Rc, Arc, Box))]\n    fn extend_persistent_accounts(&mut self, accounts: impl IntoIterator<Item = Address>)\n    where\n        Self: Sized,\n    {\n        for acc in accounts {\n            self.add_persistent_account(acc);\n        }\n    }\n\n    /// Grants cheatcode access for the given `account`\n    ///\n    /// Returns true if the `account` already has access\n    fn allow_cheatcode_access(&mut self, account: Address) -> bool;\n\n    /// Revokes cheatcode access for the given account\n    ///\n    /// Returns true if the `account` was previously allowed cheatcode access\n    fn revoke_cheatcode_access(&mut self, account: &Address) -> bool;\n\n    /// Returns `true` if the given account is allowed to execute cheatcodes\n    fn has_cheatcode_access(&self, account: &Address) -> bool;\n\n    /// Ensures that `account` is allowed to execute cheatcodes\n    ///\n    /// Returns an error if [`Self::has_cheatcode_access`] returns `false`\n    fn ensure_cheatcode_access(&self, account: &Address) -> Result<(), BackendError> {\n        if !self.has_cheatcode_access(account) {\n            return Err(BackendError::NoCheats(*account));\n        }\n        Ok(())\n    }\n\n    /// Same as [`Self::ensure_cheatcode_access()`] but only enforces it if the backend is currently\n    /// in forking mode\n    fn ensure_cheatcode_access_forking_mode(&self, account: &Address) -> Result<(), BackendError> {\n        if self.is_forked_mode() {\n            return self.ensure_cheatcode_access(account);\n        }\n        Ok(())\n    }\n\n    /// Set the blockhash for a given block number.\n    ///\n    /// # Arguments\n    ///\n    /// * `number` - The block number to set the blockhash for\n    /// * `hash` - The blockhash to set\n    ///\n    /// # Note\n    ///\n    /// This function mimics the EVM limits of the `blockhash` operation:\n    /// - It sets the blockhash for blocks where `block.number - 256 <= number < block.number`\n    /// - Setting a blockhash for the current block (number == block.number) has no effect\n    /// - Setting a blockhash for future blocks (number > block.number) has no effect\n    /// - Setting a blockhash for blocks older than `block.number - 256` has no effect\n    fn set_blockhash(&mut self, block_number: U256, block_hash: B256);\n}\n\nstruct _ObjectSafe(dyn DatabaseExt);\n\n/// Provides the underlying `revm::Database` implementation.\n///\n/// A `Backend` can be initialised in two forms:\n///\n/// # 1. Empty in-memory Database\n/// This is the default variant: an empty `revm::Database`\n///\n/// # 2. Forked Database\n/// A `revm::Database` that forks off a remote client\n///\n///\n/// In addition to that we support forking manually on the fly.\n/// Additional forks can be created. Each unique fork is identified by its unique `ForkId`. We treat\n/// forks as unique if they have the same `(endpoint, block number)` pair.\n///\n/// When it comes to testing, it's intended that each contract will use its own `Backend`\n/// (`Backend::clone`). This way each contract uses its own encapsulated evm state. For in-memory\n/// testing, the database is just an owned `revm::InMemoryDB`.\n///\n/// Each `Fork`, identified by a unique id, uses completely separate storage, write operations are\n/// performed only in the fork's own database, `ForkDB`.\n///\n/// A `ForkDB` consists of 2 halves:\n///   - everything fetched from the remote is readonly\n///   - all local changes (instructed by the contract) are written to the backend's `db` and don't\n///     alter the state of the remote client.\n///\n/// # Fork swapping\n///\n/// Multiple \"forks\" can be created `Backend::create_fork()`, however only 1 can be used by the\n/// `db`. However, their state can be hot-swapped by swapping the read half of `db` from one fork to\n/// another.\n/// When swapping forks (`Backend::select_fork()`) we also update the current `EvmEnv` of the `EVM`\n/// accordingly, so that all `block.*` config values match\n///\n/// When another for is selected [`DatabaseExt::select_fork()`] the entire storage, including\n/// `JournaledState` is swapped, but the storage of the caller's and the test contract account is\n/// _always_ cloned. This way a fork has entirely separate storage but data can still be shared\n/// across fork boundaries via stack and contract variables.\n///\n/// # Snapshotting\n///\n/// A snapshot of the current overall state can be taken at any point in time. A snapshot is\n/// identified by a unique id that's returned when a snapshot is created. A snapshot can only be\n/// reverted _once_. After a successful revert, the same snapshot id cannot be used again. Reverting\n/// a snapshot replaces the current active state with the snapshot state, the snapshot is deleted\n/// afterwards, as well as any snapshots taken after the reverted snapshot, (e.g.: reverting to id\n/// 0x1 will delete snapshots with ids 0x1, 0x2, etc.)\n///\n/// **Note:** State snapshots work across fork-swaps, e.g. if fork `A` is currently active, then a\n/// snapshot is created before fork `B` is selected, then fork `A` will be the active fork again\n/// after reverting the snapshot.\n#[derive(Clone, Debug)]\n#[must_use]\npub struct Backend {\n    /// The access point for managing forks\n    forks: MultiFork<AnyNetwork>,\n    // The default in memory db\n    mem_db: FoundryEvmInMemoryDB,\n    /// The journaled_state to use to initialize new forks with\n    ///\n    /// The way [`JournaledState`] works is, that it holds the \"hot\" accounts loaded from the\n    /// underlying `Database` that feeds the Account and State data to the journaled_state so it\n    /// can apply changes to the state while the EVM executes.\n    ///\n    /// In a way the `JournaledState` is something like a cache that\n    /// 1. check if account is already loaded (hot)\n    /// 2. if not load from the `Database` (this will then retrieve the account via RPC in forking\n    ///    mode)\n    ///\n    /// To properly initialize we store the `JournaledState` before the first fork is selected\n    /// ([`DatabaseExt::select_fork`]).\n    ///\n    /// This will be an empty `JournaledState`, which will be populated with persistent accounts,\n    /// See [`Self::update_fork_db()`].\n    fork_init_journaled_state: JournaledState,\n    /// The currently active fork database\n    ///\n    /// If this is set, then the Backend is currently in forking mode\n    active_fork_ids: Option<(LocalForkId, ForkLookupIndex)>,\n    /// holds additional Backend data\n    inner: BackendInner,\n}\n\nimpl Backend {\n    /// Creates a new Backend with a spawned multi fork thread.\n    ///\n    /// If `fork` is `Some` this will use a `fork` database, otherwise with an in-memory\n    /// database.\n    pub fn spawn(fork: Option<CreateFork>) -> eyre::Result<Self> {\n        Self::new(MultiFork::spawn(), fork)\n    }\n\n    /// Creates a new instance of `Backend`\n    ///\n    /// If `fork` is `Some` this will use a `fork` database, otherwise with an in-memory\n    /// database.\n    ///\n    /// Prefer using [`spawn`](Self::spawn) instead.\n    pub fn new(forks: MultiFork<AnyNetwork>, fork: Option<CreateFork>) -> eyre::Result<Self> {\n        trace!(target: \"backend\", forking_mode=?fork.is_some(), \"creating executor backend\");\n        // Note: this will take of registering the `fork`\n        let inner = BackendInner {\n            persistent_accounts: HashSet::from(DEFAULT_PERSISTENT_ACCOUNTS),\n            ..Default::default()\n        };\n\n        let mut backend = Self {\n            forks,\n            mem_db: CacheDB::new(Default::default()),\n            fork_init_journaled_state: inner.new_journaled_state(),\n            active_fork_ids: None,\n            inner,\n        };\n\n        if let Some(fork) = fork {\n            let (fork_id, fork, _) = backend.forks.create_fork(fork)?;\n            let fork_db = ForkDB::new(fork);\n            let fork_ids = backend.inner.insert_new_fork(\n                fork_id.clone(),\n                fork_db,\n                backend.inner.new_journaled_state(),\n            );\n            backend.inner.launched_with_fork = Some((fork_id, fork_ids.0, fork_ids.1));\n            backend.active_fork_ids = Some(fork_ids);\n        }\n\n        trace!(target: \"backend\", forking_mode=? backend.active_fork_ids.is_some(), \"created executor backend\");\n\n        Ok(backend)\n    }\n\n    /// Creates a new instance of `Backend` with fork added to the fork database and sets the fork\n    /// as active\n    pub(crate) fn new_with_fork(\n        id: &ForkId,\n        fork: Fork,\n        journaled_state: JournaledState,\n    ) -> eyre::Result<Self> {\n        let mut backend = Self::spawn(None)?;\n        let fork_ids = backend.inner.insert_new_fork(id.clone(), fork.db, journaled_state);\n        backend.inner.launched_with_fork = Some((id.clone(), fork_ids.0, fork_ids.1));\n        backend.active_fork_ids = Some(fork_ids);\n        Ok(backend)\n    }\n\n    /// Creates a new instance with a `BackendDatabase::InMemory` cache layer for the `CacheDB`\n    pub fn clone_empty(&self) -> Self {\n        Self {\n            forks: self.forks.clone(),\n            mem_db: CacheDB::new(Default::default()),\n            fork_init_journaled_state: self.inner.new_journaled_state(),\n            active_fork_ids: None,\n            inner: Default::default(),\n        }\n    }\n\n    pub fn insert_account_info(&mut self, address: Address, account: AccountInfo) {\n        if let Some(db) = self.active_fork_db_mut() {\n            db.insert_account_info(address, account)\n        } else {\n            self.mem_db.insert_account_info(address, account)\n        }\n    }\n\n    /// Inserts a value on an account's storage without overriding account info\n    pub fn insert_account_storage(\n        &mut self,\n        address: Address,\n        slot: U256,\n        value: U256,\n    ) -> Result<(), DatabaseError> {\n        if let Some(db) = self.active_fork_db_mut() {\n            db.insert_account_storage(address, slot, value)\n        } else {\n            self.mem_db.insert_account_storage(address, slot, value)\n        }\n    }\n\n    /// Completely replace an account's storage without overriding account info.\n    ///\n    /// When forking, this causes the backend to assume a `0` value for all\n    /// unset storage slots instead of trying to fetch it.\n    pub fn replace_account_storage(\n        &mut self,\n        address: Address,\n        storage: Map<U256, U256>,\n    ) -> Result<(), DatabaseError> {\n        if let Some(db) = self.active_fork_db_mut() {\n            db.replace_account_storage(address, storage)\n        } else {\n            self.mem_db.replace_account_storage(address, storage)\n        }\n    }\n\n    /// Returns all snapshots created in this backend\n    pub fn state_snapshots(\n        &self,\n    ) -> &StateSnapshots<BackendStateSnapshot<BackendDatabaseSnapshot>> {\n        &self.inner.state_snapshots\n    }\n\n    /// Sets the address of the `DSTest` contract that is being executed\n    ///\n    /// This will also mark the caller as persistent and remove the persistent status from the\n    /// previous test contract address\n    ///\n    /// This will also grant cheatcode access to the test account\n    pub fn set_test_contract(&mut self, acc: Address) -> &mut Self {\n        trace!(?acc, \"setting test account\");\n        self.add_persistent_account(acc);\n        self.allow_cheatcode_access(acc);\n        self\n    }\n\n    /// Sets the caller address\n    pub fn set_caller(&mut self, acc: Address) -> &mut Self {\n        trace!(?acc, \"setting caller account\");\n        self.inner.caller = Some(acc);\n        self.allow_cheatcode_access(acc);\n        self\n    }\n\n    /// Sets the current spec id\n    pub fn set_spec_id(&mut self, spec_id: SpecId) -> &mut Self {\n        trace!(?spec_id, \"setting spec ID\");\n        self.inner.spec_id = spec_id;\n        self\n    }\n\n    /// Returns the set caller address\n    pub fn caller_address(&self) -> Option<Address> {\n        self.inner.caller\n    }\n\n    /// Failures occurred in state snapshots are tracked when the state snapshot is reverted.\n    ///\n    /// If an error occurs in a restored state snapshot, the test is considered failed.\n    ///\n    /// This returns whether there was a reverted state snapshot that recorded an error.\n    pub fn has_state_snapshot_failure(&self) -> bool {\n        self.inner.has_state_snapshot_failure\n    }\n\n    /// Sets the state snapshot failure flag.\n    pub fn set_state_snapshot_failure(&mut self, has_state_snapshot_failure: bool) {\n        self.inner.has_state_snapshot_failure = has_state_snapshot_failure\n    }\n\n    /// When creating or switching forks, we update the AccountInfo of the contract\n    pub(crate) fn update_fork_db(\n        &self,\n        active_journaled_state: &mut JournaledState,\n        target_fork: &mut Fork,\n    ) {\n        self.update_fork_db_contracts(\n            self.inner.persistent_accounts.iter().copied(),\n            active_journaled_state,\n            target_fork,\n        )\n    }\n\n    /// Merges the state of all `accounts` from the currently active db into the given `fork`\n    pub(crate) fn update_fork_db_contracts(\n        &self,\n        accounts: impl IntoIterator<Item = Address>,\n        active_journaled_state: &mut JournaledState,\n        target_fork: &mut Fork,\n    ) {\n        if let Some(db) = self.active_fork_db() {\n            merge_account_data(accounts, db, active_journaled_state, target_fork)\n        } else {\n            merge_account_data(accounts, &self.mem_db, active_journaled_state, target_fork)\n        }\n    }\n\n    /// Returns the memory db used if not in forking mode\n    pub fn mem_db(&self) -> &FoundryEvmInMemoryDB {\n        &self.mem_db\n    }\n\n    /// Returns true if the `id` is currently active\n    pub fn is_active_fork(&self, id: LocalForkId) -> bool {\n        self.active_fork_ids.map(|(i, _)| i == id).unwrap_or_default()\n    }\n\n    /// Returns `true` if the `Backend` is currently in forking mode\n    pub fn is_in_forking_mode(&self) -> bool {\n        self.active_fork().is_some()\n    }\n\n    /// Returns the currently active `Fork`, if any\n    pub fn active_fork(&self) -> Option<&Fork> {\n        self.active_fork_ids.map(|(_, idx)| self.inner.get_fork(idx))\n    }\n\n    /// Returns the currently active `Fork`, if any\n    pub fn active_fork_mut(&mut self) -> Option<&mut Fork> {\n        self.active_fork_ids.map(|(_, idx)| self.inner.get_fork_mut(idx))\n    }\n\n    /// Returns the currently active `ForkDB`, if any\n    pub fn active_fork_db(&self) -> Option<&ForkDB> {\n        self.active_fork().map(|f| &f.db)\n    }\n\n    /// Returns the currently active `ForkDB`, if any\n    pub fn active_fork_db_mut(&mut self) -> Option<&mut ForkDB> {\n        self.active_fork_mut().map(|f| &mut f.db)\n    }\n\n    /// Returns the current database implementation as a `&dyn` value.\n    pub fn db(&self) -> &dyn Database<Error = DatabaseError> {\n        match self.active_fork_db() {\n            Some(fork_db) => fork_db,\n            None => &self.mem_db,\n        }\n    }\n\n    /// Returns the current database implementation as a `&mut dyn` value.\n    pub fn db_mut(&mut self) -> &mut dyn Database<Error = DatabaseError> {\n        match self.active_fork_ids.map(|(_, idx)| &mut self.inner.get_fork_mut(idx).db) {\n            Some(fork_db) => fork_db,\n            None => &mut self.mem_db,\n        }\n    }\n\n    /// Creates a snapshot of the currently active database\n    pub(crate) fn create_db_snapshot(&self) -> BackendDatabaseSnapshot {\n        if let Some((id, idx)) = self.active_fork_ids {\n            let fork = self.inner.get_fork(idx).clone();\n            let fork_id = self.inner.ensure_fork_id(id).cloned().expect(\"Exists; qed\");\n            BackendDatabaseSnapshot::Forked(id, fork_id, idx, Box::new(fork))\n        } else {\n            BackendDatabaseSnapshot::InMemory(self.mem_db.clone())\n        }\n    }\n\n    /// Since each `Fork` tracks logs separately, we need to merge them to get _all_ of them\n    pub fn merged_logs(&self, mut logs: Vec<Log>) -> Vec<Log> {\n        if let Some((_, active)) = self.active_fork_ids {\n            let mut all_logs = Vec::with_capacity(logs.len());\n\n            self.inner\n                .forks\n                .iter()\n                .enumerate()\n                .filter_map(|(idx, f)| f.as_ref().map(|f| (idx, f)))\n                .for_each(|(idx, f)| {\n                    if idx == active {\n                        all_logs.append(&mut logs);\n                    } else {\n                        all_logs.extend(f.journaled_state.logs.clone())\n                    }\n                });\n            return all_logs;\n        }\n\n        logs\n    }\n\n    /// Initializes settings we need to keep track of.\n    ///\n    /// We need to track these mainly to prevent issues when switching between different evms\n    pub(crate) fn initialize(&mut self, spec_id: SpecId, caller: Address, tx_kind: TxKind) {\n        self.set_caller(caller);\n        self.set_spec_id(spec_id);\n\n        let test_contract = match tx_kind {\n            TxKind::Call(to) => to,\n            TxKind::Create => {\n                let nonce =\n                    self.basic_ref(caller).map(|b| b.unwrap_or_default().nonce).unwrap_or_default();\n                caller.create(nonce)\n            }\n        };\n        self.set_test_contract(test_contract);\n    }\n\n    /// Executes the configured test call of the `env` without committing state changes.\n    ///\n    /// Note: in case there are any cheatcodes executed that modify the environment, this will\n    /// update the given `env` with the new values.\n    #[instrument(name = \"inspect\", level = \"debug\", skip_all)]\n    pub fn inspect<I: EthInspectorExt>(\n        &mut self,\n        evm_env: &mut EvmEnv,\n        tx_env: &mut TxEnv,\n        inspector: I,\n    ) -> eyre::Result<ResultAndState> {\n        self.initialize(evm_env.cfg_env.spec, tx_env.caller, tx_env.kind);\n        let mut evm = crate::evm::new_eth_evm_with_inspector(\n            self,\n            evm_env.to_owned(),\n            tx_env.to_owned(),\n            inspector,\n        );\n\n        let res = evm.transact(tx_env.clone()).wrap_err(\"EVM error\")?;\n\n        *evm_env = EvmEnv::new(evm.cfg.clone(), evm.block.clone());\n        *tx_env = evm.tx.clone();\n\n        Ok(res)\n    }\n\n    /// Returns true if the address is a precompile\n    pub fn is_existing_precompile(&self, addr: &Address) -> bool {\n        self.inner.precompiles().contains(addr)\n    }\n\n    /// Sets the initial journaled state to use when initializing forks\n    #[inline]\n    fn set_init_journaled_state(&mut self, journaled_state: JournaledState) {\n        trace!(\"recording fork init journaled_state\");\n        self.fork_init_journaled_state = journaled_state;\n    }\n\n    /// Cleans up already loaded accounts that would be initialized without the correct data from\n    /// the fork.\n    ///\n    /// It can happen that an account is loaded before the first fork is selected, like\n    /// `getNonce(addr)`, which will load an empty account by default.\n    ///\n    /// This account data then would not match the account data of a fork if it exists.\n    /// So when the first fork is initialized we replace these accounts with the actual account as\n    /// it exists on the fork.\n    fn prepare_init_journal_state(&mut self) -> Result<(), BackendError> {\n        let loaded_accounts = self\n            .fork_init_journaled_state\n            .state\n            .iter()\n            .filter(|(addr, _)| !self.is_existing_precompile(addr) && !self.is_persistent(addr))\n            .map(|(addr, _)| addr)\n            .copied()\n            .collect::<Vec<_>>();\n\n        for fork in self.inner.forks_iter_mut() {\n            let mut journaled_state = self.fork_init_journaled_state.clone();\n            for loaded_account in loaded_accounts.iter().copied() {\n                trace!(?loaded_account, \"replacing account on init\");\n                let init_account =\n                    journaled_state.state.get_mut(&loaded_account).expect(\"exists; qed\");\n\n                // here's an edge case where we need to check if this account has been created, in\n                // which case we don't need to replace it with the account from the fork because the\n                // created account takes precedence: for example contract creation in setups\n                if init_account.is_created() {\n                    trace!(?loaded_account, \"skipping created account\");\n                    continue;\n                }\n\n                // otherwise we need to replace the account's info with the one from the fork's\n                // database\n                let fork_account = Database::basic(&mut fork.db, loaded_account)?\n                    .ok_or(BackendError::MissingAccount(loaded_account))?;\n                init_account.info = fork_account;\n            }\n            fork.journaled_state = journaled_state;\n        }\n        Ok(())\n    }\n\n    /// Returns the block numbers required for replaying a transaction\n    fn get_block_number_and_block_for_transaction(\n        &self,\n        id: LocalForkId,\n        transaction: B256,\n    ) -> eyre::Result<(u64, AnyRpcBlock)> {\n        let fork = self.inner.get_fork_by_id(id)?;\n        let tx = fork.backend().get_transaction(transaction)?;\n\n        // get the block number we need to fork\n        if let Some(tx_block) = tx.block_number {\n            let block = fork.backend().get_full_block(tx_block)?;\n\n            // we need to subtract 1 here because we want the state before the transaction\n            // was mined\n            let fork_block = tx_block - 1;\n            Ok((fork_block, block))\n        } else {\n            let block = fork.backend().get_full_block(BlockNumberOrTag::Latest)?;\n\n            let number = block.header.number();\n\n            Ok((number, block))\n        }\n    }\n\n    /// Replays all the transactions at the forks current block that were mined before the `tx`\n    ///\n    /// Returns the _unmined_ transaction that corresponds to the given `tx_hash`\n    pub fn replay_until(\n        &mut self,\n        id: LocalForkId,\n        mut evm_env: EvmEnv,\n        mut tx_env: TxEnv,\n        tx_hash: B256,\n        journaled_state: &mut JournaledState,\n    ) -> eyre::Result<Option<Transaction<AnyTxEnvelope>>> {\n        trace!(?id, ?tx_hash, \"replay until transaction\");\n\n        let persistent_accounts = self.inner.persistent_accounts.clone();\n        let fork_id = self.ensure_fork_id(id)?.clone();\n\n        let fork = self.inner.get_fork_by_id_mut(id)?;\n        let full_block =\n            fork.backend().get_full_block(evm_env.block_env.number.saturating_to::<u64>())?;\n\n        for tx in full_block.inner.transactions.txns() {\n            // System transactions such as on L2s don't contain any pricing info so we skip them\n            // otherwise this would cause reverts\n            if is_known_system_sender(tx.inner().inner.signer())\n                || tx.ty() == SYSTEM_TRANSACTION_TYPE\n            {\n                trace!(tx=?tx.tx_hash(), \"skipping system transaction\");\n                continue;\n            }\n\n            if tx.tx_hash() == tx_hash {\n                // found the target transaction\n                return Ok(Some(tx.inner.clone()));\n            }\n            trace!(tx=?tx.tx_hash(), \"committing transaction\");\n\n            commit_transaction(\n                tx,\n                &mut evm_env,\n                &mut tx_env,\n                journaled_state,\n                fork,\n                &fork_id,\n                &persistent_accounts,\n                &mut NoOpInspector,\n            )?;\n        }\n\n        Ok(None)\n    }\n}\n\nimpl DatabaseExt for Backend {\n    fn snapshot_state(&mut self, journaled_state: &JournaledState, evm_env: &EvmEnv) -> U256 {\n        trace!(\"create snapshot\");\n        let id = self.inner.state_snapshots.insert(BackendStateSnapshot::new(\n            self.create_db_snapshot(),\n            journaled_state.clone(),\n            evm_env.clone(),\n        ));\n        trace!(target: \"backend\", \"Created new snapshot {}\", id);\n        id\n    }\n\n    fn revert_state(\n        &mut self,\n        id: U256,\n        current_state: &JournaledState,\n        evm_env: &mut EvmEnv,\n        tx_env: &mut TxEnv,\n        action: RevertStateSnapshotAction,\n    ) -> Option<JournaledState> {\n        trace!(?id, \"revert snapshot\");\n        if let Some(mut snapshot) = self.inner.state_snapshots.remove_at(id) {\n            // Re-insert snapshot to persist it\n            if action.is_keep() {\n                self.inner.state_snapshots.insert_at(snapshot.clone(), id);\n            }\n\n            // https://github.com/foundry-rs/foundry/issues/3055\n            // Check if an error occurred either during or before the snapshot.\n            // DSTest contracts don't have snapshot functionality, so this slot is enough to check\n            // for failure here.\n            if let Some(account) = current_state.state.get(&CHEATCODE_ADDRESS)\n                && let Some(slot) = account.storage.get(&GLOBAL_FAIL_SLOT)\n                && !slot.present_value.is_zero()\n            {\n                self.set_state_snapshot_failure(true);\n            }\n\n            // merge additional logs\n            snapshot.merge(current_state);\n            let BackendStateSnapshot { db, mut journaled_state, snap_evm_env } = snapshot;\n            match db {\n                BackendDatabaseSnapshot::InMemory(mem_db) => {\n                    self.mem_db = mem_db;\n                }\n                BackendDatabaseSnapshot::Forked(id, fork_id, idx, mut fork) => {\n                    // there might be the case where the snapshot was created during `setUp` with\n                    // another caller, so we need to ensure the caller account is present in the\n                    // journaled state and database\n                    let caller = tx_env.caller;\n                    journaled_state.state.entry(caller).or_insert_with(|| {\n                        let caller_account = current_state\n                            .state\n                            .get(&caller)\n                            .map(|acc| acc.info.clone())\n                            .unwrap_or_default();\n\n                        if !fork.db.cache.accounts.contains_key(&caller) {\n                            // update the caller account which is required by the evm\n                            fork.db.insert_account_info(caller, caller_account.clone());\n                        }\n                        caller_account.into()\n                    });\n                    self.inner.revert_state_snapshot(id, fork_id, idx, *fork);\n                    self.active_fork_ids = Some((id, idx))\n                }\n            }\n\n            update_current_env_with_fork_env(evm_env, tx_env, snap_evm_env);\n            trace!(target: \"backend\", \"Reverted snapshot {}\", id);\n\n            Some(journaled_state)\n        } else {\n            warn!(target: \"backend\", \"No snapshot to revert for {}\", id);\n            None\n        }\n    }\n\n    fn delete_state_snapshot(&mut self, id: U256) -> bool {\n        self.inner.state_snapshots.remove_at(id).is_some()\n    }\n\n    fn delete_state_snapshots(&mut self) {\n        self.inner.state_snapshots.clear()\n    }\n\n    fn create_fork(&mut self, create_fork: CreateFork) -> eyre::Result<LocalForkId> {\n        trace!(\"create fork\");\n        let (fork_id, fork, _) = self.forks.create_fork(create_fork)?;\n\n        let fork_db = ForkDB::new(fork);\n        let (id, _) =\n            self.inner.insert_new_fork(fork_id, fork_db, self.fork_init_journaled_state.clone());\n        Ok(id)\n    }\n\n    fn create_fork_at_transaction(\n        &mut self,\n        fork: CreateFork,\n        transaction: B256,\n    ) -> eyre::Result<LocalForkId> {\n        trace!(?transaction, \"create fork at transaction\");\n        let id = self.create_fork(fork)?;\n        let fork_id = self.ensure_fork_id(id).cloned()?;\n        let mut evm_env = self\n            .forks\n            .get_evm_env(fork_id)?\n            .ok_or_else(|| eyre::eyre!(\"Requested fork `{}` does not exist\", id))?;\n\n        // we still need to roll to the transaction, but we only need an empty dummy state since we\n        // don't need to update the active journaled state yet\n        self.roll_fork_to_transaction(\n            Some(id),\n            transaction,\n            &mut evm_env,\n            &mut TxEnv::default(),\n            &mut self.inner.new_journaled_state(),\n        )?;\n\n        Ok(id)\n    }\n\n    /// Select an existing fork by id.\n    /// When switching forks we copy the shared state\n    fn select_fork(\n        &mut self,\n        id: LocalForkId,\n        evm_env: &mut EvmEnv,\n        tx_env: &mut TxEnv,\n        active_journaled_state: &mut JournaledState,\n    ) -> eyre::Result<()> {\n        trace!(?id, \"select fork\");\n        if self.is_active_fork(id) {\n            // nothing to do\n            return Ok(());\n        }\n\n        // Update block number and timestamp of active fork (if any) with current env values,\n        // in order to preserve values changed by using `roll` and `warp` cheatcodes.\n        if let Some(active_fork_id) = self.active_fork_id() {\n            self.forks.update_block(\n                self.ensure_fork_id(active_fork_id).cloned()?,\n                evm_env.block_env.number,\n                evm_env.block_env.timestamp,\n            )?;\n        }\n\n        let fork_id = self.ensure_fork_id(id).cloned()?;\n        let idx = self.inner.ensure_fork_index(&fork_id)?;\n        let fork_evm_env = self\n            .forks\n            .get_evm_env(fork_id)?\n            .ok_or_else(|| eyre::eyre!(\"Requested fork `{}` does not exist\", id))?;\n\n        // If we're currently in forking mode we need to update the journaled_state to this point,\n        // this ensures the changes performed while the fork was active are recorded\n        if let Some(active) = self.active_fork_mut() {\n            active.journaled_state = active_journaled_state.clone();\n\n            let caller = tx_env.caller;\n            let caller_account = active.journaled_state.state.get(&tx_env.caller).cloned();\n            let target_fork = self.inner.get_fork_mut(idx);\n\n            // depth 0 will be the default value when the fork was created\n            if target_fork.journaled_state.depth == 0 {\n                // Initialize caller with its fork info\n                if let Some(mut acc) = caller_account {\n                    let fork_account = Database::basic(&mut target_fork.db, caller)?\n                        .ok_or(BackendError::MissingAccount(caller))?;\n\n                    acc.info = fork_account;\n                    target_fork.journaled_state.state.insert(caller, acc);\n                }\n            }\n        } else {\n            // this is the first time a fork is selected. This means up to this point all changes\n            // are made in a single `JournaledState`, for example after a `setup` that only created\n            // different forks. Since the `JournaledState` is valid for all forks until the\n            // first fork is selected, we need to update it for all forks and use it as init state\n            // for all future forks\n\n            self.set_init_journaled_state(active_journaled_state.clone());\n            self.prepare_init_journal_state()?;\n\n            // Make sure that the next created fork has a depth of 0.\n            self.fork_init_journaled_state.depth = 0;\n        }\n\n        {\n            // update the shared state and track\n            let mut fork = self.inner.take_fork(idx);\n\n            // Make sure all persistent accounts on the newly selected fork reflect same state as\n            // the active db / previous fork.\n            // This can get out of sync when multiple forks are created on test `setUp`, then a\n            // fork is selected and persistent contract is changed. If first action in test is to\n            // select a different fork, then the persistent contract state won't reflect changes\n            // done in `setUp` for the other fork.\n            // See <https://github.com/foundry-rs/foundry/issues/10296> and <https://github.com/foundry-rs/foundry/issues/10552>.\n            let persistent_accounts = self.inner.persistent_accounts.clone();\n            if let Some(db) = self.active_fork_db_mut() {\n                for addr in persistent_accounts {\n                    let Ok(db_account) = db.load_account(addr) else { continue };\n\n                    let Some(fork_account) = fork.journaled_state.state.get_mut(&addr) else {\n                        continue;\n                    };\n\n                    for (key, val) in &db_account.storage {\n                        if let Some(fork_storage) = fork_account.storage.get_mut(key) {\n                            fork_storage.present_value = *val;\n                        }\n                    }\n                }\n            }\n\n            // since all forks handle their state separately, the depth can drift\n            // this is a handover where the target fork starts at the same depth where it was\n            // selected. This ensures that there are no gaps in depth which would\n            // otherwise cause issues with the tracer\n            fork.journaled_state.depth = active_journaled_state.depth;\n\n            // another edge case where a fork is created and selected during setup with not\n            // necessarily the same caller as for the test, however we must always\n            // ensure that fork's state contains the current sender\n            let caller = tx_env.caller;\n            fork.journaled_state.state.entry(caller).or_insert_with(|| {\n                let caller_account = active_journaled_state\n                    .state\n                    .get(&tx_env.caller)\n                    .map(|acc| acc.info.clone())\n                    .unwrap_or_default();\n\n                if !fork.db.cache.accounts.contains_key(&caller) {\n                    // update the caller account which is required by the evm\n                    fork.db.insert_account_info(caller, caller_account.clone());\n                }\n                caller_account.into()\n            });\n\n            self.update_fork_db(active_journaled_state, &mut fork);\n\n            // insert the fork back\n            self.inner.set_fork(idx, fork);\n        }\n\n        self.active_fork_ids = Some((id, idx));\n        // Update current environment with environment of newly selected fork.\n        update_current_env_with_fork_env(evm_env, tx_env, fork_evm_env);\n\n        Ok(())\n    }\n\n    /// This is effectively the same as [`Self::create_select_fork()`] but updating an existing\n    /// [ForkId] that is mapped to the [LocalForkId]\n    fn roll_fork(\n        &mut self,\n        id: Option<LocalForkId>,\n        block_number: u64,\n        evm_env: &mut EvmEnv,\n        tx_env: &mut TxEnv,\n        journaled_state: &mut JournaledState,\n    ) -> eyre::Result<()> {\n        trace!(?id, ?block_number, \"roll fork\");\n        let id = self.ensure_fork(id)?;\n        let (fork_id, backend, fork_env) =\n            self.forks.roll_fork(self.inner.ensure_fork_id(id).cloned()?, block_number)?;\n        // this will update the local mapping\n        self.inner.roll_fork(id, fork_id, backend)?;\n\n        if let Some((active_id, active_idx)) = self.active_fork_ids {\n            // the currently active fork is the targeted fork of this call\n            if active_id == id {\n                // need to update the block's env settings right away, which is otherwise set when\n                // forks are selected `select_fork`\n                update_current_env_with_fork_env(evm_env, tx_env, fork_env);\n\n                // we also need to update the journaled_state right away, this has essentially the\n                // same effect as selecting (`select_fork`) by discarding\n                // non-persistent storage from the journaled_state. This which will\n                // reset cached state from the previous block\n                let mut persistent_addrs = self.inner.persistent_accounts.clone();\n                // we also want to copy the caller state here\n                persistent_addrs.extend(self.caller_address());\n\n                let active = self.inner.get_fork_mut(active_idx);\n                active.journaled_state = self.fork_init_journaled_state.clone();\n                active.journaled_state.depth = journaled_state.depth;\n\n                for addr in persistent_addrs {\n                    merge_journaled_state_data(addr, journaled_state, &mut active.journaled_state);\n                }\n\n                // Ensure all previously loaded accounts are present in the journaled state to\n                // prevent issues in the new journalstate, e.g. assumptions that accounts are loaded\n                // if the account is not touched, we reload it, if it's touched we clone it.\n                //\n                // Special case for accounts that are not created: we don't merge their state but\n                // load it in order to reflect their state at the new block (they should explicitly\n                // be marked as persistent if it is desired to keep state between fork rolls).\n                for (addr, acc) in &journaled_state.state {\n                    if acc.is_created() {\n                        if acc.is_touched() {\n                            merge_journaled_state_data(\n                                *addr,\n                                journaled_state,\n                                &mut active.journaled_state,\n                            );\n                        }\n                    } else {\n                        let _ = active.journaled_state.load_account(&mut active.db, *addr);\n                    }\n                }\n\n                *journaled_state = active.journaled_state.clone();\n            }\n        }\n        Ok(())\n    }\n\n    fn roll_fork_to_transaction(\n        &mut self,\n        id: Option<LocalForkId>,\n        transaction: B256,\n        evm_env: &mut EvmEnv,\n        tx_env: &mut TxEnv,\n        journaled_state: &mut JournaledState,\n    ) -> eyre::Result<()> {\n        trace!(?id, ?transaction, \"roll fork to transaction\");\n        let id = self.ensure_fork(id)?;\n\n        let (fork_block, block) =\n            self.get_block_number_and_block_for_transaction(id, transaction)?;\n\n        // roll the fork to the transaction's parent block or latest if it's pending, because we\n        // need to fork off the parent block's state for tx level forking and then replay the txs\n        // before the tx in that block to get the state at the tx\n        self.roll_fork(Some(id), fork_block, evm_env, tx_env, journaled_state)?;\n\n        // we need to update the env to the block\n        update_env_block(evm_env, block.header());\n\n        // after we forked at the fork block we need to properly update the block env to the block\n        // env of the tx's block\n        let _ = self\n            .forks\n            .update_block_env(self.inner.ensure_fork_id(id).cloned()?, evm_env.block_env.clone());\n\n        // replay all transactions that came before\n        self.replay_until(id, evm_env.clone(), tx_env.clone(), transaction, journaled_state)?;\n\n        Ok(())\n    }\n\n    fn transact(\n        &mut self,\n        maybe_id: Option<LocalForkId>,\n        transaction: B256,\n        mut evm_env: EvmEnv,\n        mut tx_env: TxEnv,\n        journaled_state: &mut JournaledState,\n        inspector: &mut dyn EthInspectorExt,\n    ) -> eyre::Result<()> {\n        trace!(?maybe_id, ?transaction, \"execute transaction\");\n        let persistent_accounts = self.inner.persistent_accounts.clone();\n        let id = self.ensure_fork(maybe_id)?;\n        let fork_id = self.ensure_fork_id(id).cloned()?;\n\n        let tx = {\n            let fork = self.inner.get_fork_by_id_mut(id)?;\n            fork.backend().get_transaction(transaction)?\n        };\n\n        // This is a bit ambiguous because the user wants to transact an arbitrary transaction in\n        // the current context, but we're assuming the user wants to transact the transaction as it\n        // was mined. Usually this is used in a combination of a fork at the transaction's parent\n        // transaction in the block and then the transaction is transacted:\n        // <https://github.com/foundry-rs/foundry/issues/6538>\n        // So we modify the env to match the transaction's block.\n        let (_fork_block, block) =\n            self.get_block_number_and_block_for_transaction(id, transaction)?;\n        update_env_block(&mut evm_env, block.header());\n\n        let fork = self.inner.get_fork_by_id_mut(id)?;\n        commit_transaction(\n            &tx,\n            &mut evm_env,\n            &mut tx_env,\n            journaled_state,\n            fork,\n            &fork_id,\n            &persistent_accounts,\n            inspector,\n        )\n    }\n\n    fn transact_from_tx(\n        &mut self,\n        tx_env: &TxEnv,\n        evm_env: EvmEnv,\n        journaled_state: &mut JournaledState,\n        inspector: &mut dyn EthInspectorExt,\n    ) -> eyre::Result<()> {\n        trace!(?tx_env, \"execute signed transaction\");\n\n        self.commit(journaled_state.state.clone());\n\n        let res = {\n            let mut db = self.clone();\n            let mut evm =\n                new_eth_evm_with_inspector(&mut db, evm_env, tx_env.to_owned(), inspector);\n            evm.journaled_state.depth = journaled_state.depth + 1;\n            evm.transact_raw(tx_env.to_owned())?\n        };\n\n        self.commit(res.state);\n        update_state(&mut journaled_state.state, self, None)?;\n\n        Ok(())\n    }\n\n    fn active_fork_id(&self) -> Option<LocalForkId> {\n        self.active_fork_ids.map(|(id, _)| id)\n    }\n\n    fn active_fork_url(&self) -> Option<String> {\n        let fork = self.inner.issued_local_fork_ids.get(&self.active_fork_id()?)?;\n        self.forks.get_fork_url(fork.clone()).ok()?\n    }\n\n    fn ensure_fork(&self, id: Option<LocalForkId>) -> eyre::Result<LocalForkId> {\n        if let Some(id) = id {\n            if self.inner.issued_local_fork_ids.contains_key(&id) {\n                return Ok(id);\n            }\n            eyre::bail!(\"Requested fork `{}` does not exist\", id)\n        }\n        if let Some(id) = self.active_fork_id() { Ok(id) } else { eyre::bail!(\"No fork active\") }\n    }\n\n    fn ensure_fork_id(&self, id: LocalForkId) -> eyre::Result<&ForkId> {\n        self.inner.ensure_fork_id(id)\n    }\n\n    fn diagnose_revert(&self, callee: Address, evm_state: &EvmState) -> Option<RevertDiagnostic> {\n        let active_id = self.active_fork_id()?;\n        let active_fork = self.active_fork()?;\n\n        if self.inner.forks.len() == 1 {\n            // we only want to provide additional diagnostics here when in multifork mode with > 1\n            // forks\n            return None;\n        }\n\n        if !active_fork.is_contract(callee) && !is_contract_in_state(evm_state, callee) {\n            // no contract for `callee` available on current fork, check if available on other forks\n            let mut available_on = Vec::new();\n            for (id, fork) in self.inner.forks_iter().filter(|(id, _)| *id != active_id) {\n                trace!(?id, address=?callee, \"checking if account exists\");\n                if fork.is_contract(callee) {\n                    available_on.push(id);\n                }\n            }\n\n            return if available_on.is_empty() {\n                Some(RevertDiagnostic::ContractDoesNotExist {\n                    contract: callee,\n                    active: active_id,\n                    persistent: self.is_persistent(&callee),\n                })\n            } else {\n                // likely user error: called a contract that's not available on active fork but is\n                // present other forks\n                Some(RevertDiagnostic::ContractExistsOnOtherForks {\n                    contract: callee,\n                    active: active_id,\n                    available_on,\n                })\n            };\n        }\n        None\n    }\n\n    /// Loads the account allocs from the given `allocs` map into the passed [JournaledState].\n    ///\n    /// Returns [Ok] if all accounts were successfully inserted into the journal, [Err] otherwise.\n    fn load_allocs(\n        &mut self,\n        allocs: &BTreeMap<Address, GenesisAccount>,\n        journaled_state: &mut JournaledState,\n    ) -> Result<(), BackendError> {\n        // Loop through all of the allocs defined in the map and commit them to the journal.\n        for (addr, acc) in allocs {\n            self.clone_account(acc, addr, journaled_state)?;\n        }\n\n        Ok(())\n    }\n\n    /// Copies bytecode, storage, nonce and balance from the given genesis account to the target\n    /// address.\n    ///\n    /// Returns [Ok] if data was successfully inserted into the journal, [Err] otherwise.\n    fn clone_account(\n        &mut self,\n        source: &GenesisAccount,\n        target: &Address,\n        journaled_state: &mut JournaledState,\n    ) -> Result<(), BackendError> {\n        // Fetch the account from the journaled state. Will create a new account if it does\n        // not already exist.\n        let mut state_acc = journaled_state.load_account_mut(self, *target)?;\n\n        // Set the account's bytecode and code hash, if the `bytecode` field is present.\n        if let Some(bytecode) = source.code.as_ref() {\n            let bytecode_hash = keccak256(bytecode);\n            let bytecode = Bytecode::new_raw(bytecode.0.clone().into());\n            state_acc.set_code(bytecode_hash, bytecode);\n        }\n\n        // Set the account's balance.\n        state_acc.set_balance(source.balance);\n\n        // Set the account's storage, if the `storage` field is present.\n        if let Some(acc) = journaled_state.state.get_mut(target) {\n            if let Some(storage) = source.storage.as_ref() {\n                for (slot, value) in storage {\n                    let slot = U256::from_be_bytes(slot.0);\n                    acc.storage.insert(\n                        slot,\n                        EvmStorageSlot::new_changed(\n                            acc.storage.get(&slot).map(|s| s.present_value).unwrap_or_default(),\n                            U256::from_be_bytes(value.0),\n                            0,\n                        ),\n                    );\n                }\n            }\n\n            // Set the account's nonce.\n            acc.info.nonce = source.nonce.unwrap_or_default();\n        };\n\n        // Touch the account to ensure the loaded information persists if called in `setUp`.\n        journaled_state.touch(*target);\n\n        Ok(())\n    }\n\n    fn add_persistent_account(&mut self, account: Address) -> bool {\n        trace!(?account, \"add persistent account\");\n        self.inner.persistent_accounts.insert(account)\n    }\n\n    fn remove_persistent_account(&mut self, account: &Address) -> bool {\n        trace!(?account, \"remove persistent account\");\n        self.inner.persistent_accounts.remove(account)\n    }\n\n    fn is_persistent(&self, acc: &Address) -> bool {\n        self.inner.persistent_accounts.contains(acc)\n    }\n\n    fn allow_cheatcode_access(&mut self, account: Address) -> bool {\n        trace!(?account, \"allow cheatcode access\");\n        self.inner.cheatcode_access_accounts.insert(account)\n    }\n\n    fn revoke_cheatcode_access(&mut self, account: &Address) -> bool {\n        trace!(?account, \"revoke cheatcode access\");\n        self.inner.cheatcode_access_accounts.remove(account)\n    }\n\n    fn has_cheatcode_access(&self, account: &Address) -> bool {\n        self.inner.cheatcode_access_accounts.contains(account)\n    }\n\n    fn set_blockhash(&mut self, block_number: U256, block_hash: B256) {\n        if let Some(db) = self.active_fork_db_mut() {\n            db.cache.block_hashes.insert(block_number.saturating_to(), block_hash);\n        } else {\n            self.mem_db.cache.block_hashes.insert(block_number.saturating_to(), block_hash);\n        }\n    }\n}\n\nimpl DatabaseRef for Backend {\n    type Error = DatabaseError;\n\n    fn basic_ref(&self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {\n        if let Some(db) = self.active_fork_db() {\n            db.basic_ref(address)\n        } else {\n            Ok(self.mem_db.basic_ref(address)?)\n        }\n    }\n\n    fn code_by_hash_ref(&self, code_hash: B256) -> Result<Bytecode, Self::Error> {\n        if let Some(db) = self.active_fork_db() {\n            db.code_by_hash_ref(code_hash)\n        } else {\n            Ok(self.mem_db.code_by_hash_ref(code_hash)?)\n        }\n    }\n\n    fn storage_ref(&self, address: Address, index: U256) -> Result<U256, Self::Error> {\n        if let Some(db) = self.active_fork_db() {\n            DatabaseRef::storage_ref(db, address, index)\n        } else {\n            Ok(DatabaseRef::storage_ref(&self.mem_db, address, index)?)\n        }\n    }\n\n    fn block_hash_ref(&self, number: u64) -> Result<B256, Self::Error> {\n        if let Some(db) = self.active_fork_db() {\n            db.block_hash_ref(number)\n        } else {\n            Ok(self.mem_db.block_hash_ref(number)?)\n        }\n    }\n}\n\nimpl DatabaseCommit for Backend {\n    fn commit(&mut self, changes: Map<Address, Account>) {\n        if let Some(db) = self.active_fork_db_mut() {\n            db.commit(changes)\n        } else {\n            self.mem_db.commit(changes)\n        }\n    }\n}\n\nimpl Database for Backend {\n    type Error = DatabaseError;\n    fn basic(&mut self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {\n        if let Some(db) = self.active_fork_db_mut() {\n            Ok(db.basic(address)?)\n        } else {\n            Ok(self.mem_db.basic(address)?)\n        }\n    }\n\n    fn code_by_hash(&mut self, code_hash: B256) -> Result<Bytecode, Self::Error> {\n        if let Some(db) = self.active_fork_db_mut() {\n            Ok(db.code_by_hash(code_hash)?)\n        } else {\n            Ok(self.mem_db.code_by_hash(code_hash)?)\n        }\n    }\n\n    fn storage(&mut self, address: Address, index: U256) -> Result<U256, Self::Error> {\n        if let Some(db) = self.active_fork_db_mut() {\n            Ok(Database::storage(db, address, index)?)\n        } else {\n            Ok(Database::storage(&mut self.mem_db, address, index)?)\n        }\n    }\n\n    fn block_hash(&mut self, number: u64) -> Result<B256, Self::Error> {\n        if let Some(db) = self.active_fork_db_mut() {\n            Ok(db.block_hash(number)?)\n        } else {\n            Ok(self.mem_db.block_hash(number)?)\n        }\n    }\n}\n\n/// Variants of a [revm::Database]\n#[derive(Clone, Debug)]\npub enum BackendDatabaseSnapshot {\n    /// Simple in-memory [revm::Database]\n    InMemory(FoundryEvmInMemoryDB),\n    /// Contains the entire forking mode database\n    Forked(LocalForkId, ForkId, ForkLookupIndex, Box<Fork>),\n}\n\n/// Represents a fork\n#[derive(Clone, Debug)]\npub struct Fork {\n    db: ForkDB,\n    journaled_state: JournaledState,\n}\n\nimpl Fork {\n    /// Returns a reference to the underlying [`SharedBackend`].\n    pub fn backend(&self) -> &SharedBackend {\n        &self.db.db\n    }\n\n    /// Returns true if the account is a contract\n    pub fn is_contract(&self, acc: Address) -> bool {\n        if let Ok(Some(acc)) = self.db.basic_ref(acc)\n            && acc.code_hash != KECCAK_EMPTY\n        {\n            return true;\n        }\n        is_contract_in_state(&self.journaled_state.state, acc)\n    }\n}\n\n/// Container type for various Backend related data\n#[derive(Clone, Debug)]\npub struct BackendInner {\n    /// Stores the `ForkId` of the fork the `Backend` launched with from the start.\n    ///\n    /// In other words if [`Backend::spawn()`] was called with a `CreateFork` command, to launch\n    /// directly in fork mode, this holds the corresponding fork identifier of this fork.\n    pub launched_with_fork: Option<(ForkId, LocalForkId, ForkLookupIndex)>,\n    /// This tracks numeric fork ids and the `ForkId` used by the handler.\n    ///\n    /// This is necessary, because there can be multiple `Backends` associated with a single\n    /// `ForkId` which is only a pair of endpoint + block. Since an existing fork can be\n    /// modified (e.g. `roll_fork`), but this should only affect the fork that's unique for the\n    /// test and not the `ForkId`\n    ///\n    /// This ensures we can treat forks as unique from the context of a test, so rolling to another\n    /// is basically creating(or reusing) another `ForkId` that's then mapped to the previous\n    /// issued _local_ numeric identifier, that remains constant, even if the underlying fork\n    /// backend changes.\n    pub issued_local_fork_ids: HashMap<LocalForkId, ForkId>,\n    /// tracks all the created forks\n    /// Contains the index of the corresponding `ForkDB` in the `forks` vec\n    pub created_forks: HashMap<ForkId, ForkLookupIndex>,\n    /// Holds all created fork databases\n    // Note: data is stored in an `Option` so we can remove it without reshuffling\n    pub forks: Vec<Option<Fork>>,\n    /// Contains state snapshots made at a certain point\n    pub state_snapshots: StateSnapshots<BackendStateSnapshot<BackendDatabaseSnapshot>>,\n    /// Tracks whether there was a failure in a snapshot that was reverted\n    ///\n    /// The Test contract contains a bool variable that is set to true when an `assert` function\n    /// failed. When a snapshot is reverted, it reverts the state of the evm, but we still want\n    /// to know if there was an `assert` that failed after the snapshot was taken so that we can\n    /// check if the test function passed all asserts even across snapshots. When a snapshot is\n    /// reverted we get the _current_ `revm::JournaledState` which contains the state that we can\n    /// check if the `_failed` variable is set,\n    /// additionally\n    pub has_state_snapshot_failure: bool,\n    /// Tracks the caller of the test function\n    pub caller: Option<Address>,\n    /// Tracks numeric identifiers for forks\n    pub next_fork_id: LocalForkId,\n    /// All accounts that should be kept persistent when switching forks.\n    /// This means all accounts stored here _don't_ use a separate storage section on each fork\n    /// instead the use only one that's persistent across fork swaps.\n    pub persistent_accounts: HashSet<Address>,\n    /// The configured spec id\n    pub spec_id: SpecId,\n    /// All accounts that are allowed to execute cheatcodes\n    pub cheatcode_access_accounts: HashSet<Address>,\n}\n\nimpl BackendInner {\n    pub fn ensure_fork_id(&self, id: LocalForkId) -> eyre::Result<&ForkId> {\n        self.issued_local_fork_ids\n            .get(&id)\n            .ok_or_else(|| eyre::eyre!(\"No matching fork found for {}\", id))\n    }\n\n    pub fn ensure_fork_index(&self, id: &ForkId) -> eyre::Result<ForkLookupIndex> {\n        self.created_forks\n            .get(id)\n            .copied()\n            .ok_or_else(|| eyre::eyre!(\"No matching fork found for {}\", id))\n    }\n\n    pub fn ensure_fork_index_by_local_id(&self, id: LocalForkId) -> eyre::Result<ForkLookupIndex> {\n        self.ensure_fork_index(self.ensure_fork_id(id)?)\n    }\n\n    /// Returns the underlying fork mapped to the index\n    #[track_caller]\n    fn get_fork(&self, idx: ForkLookupIndex) -> &Fork {\n        debug_assert!(idx < self.forks.len(), \"fork lookup index must exist\");\n        self.forks[idx].as_ref().unwrap()\n    }\n\n    /// Returns the underlying fork mapped to the index\n    #[track_caller]\n    fn get_fork_mut(&mut self, idx: ForkLookupIndex) -> &mut Fork {\n        debug_assert!(idx < self.forks.len(), \"fork lookup index must exist\");\n        self.forks[idx].as_mut().unwrap()\n    }\n\n    /// Returns the underlying fork corresponding to the id\n    #[track_caller]\n    fn get_fork_by_id_mut(&mut self, id: LocalForkId) -> eyre::Result<&mut Fork> {\n        let idx = self.ensure_fork_index_by_local_id(id)?;\n        Ok(self.get_fork_mut(idx))\n    }\n\n    /// Returns the underlying fork corresponding to the id\n    #[track_caller]\n    fn get_fork_by_id(&self, id: LocalForkId) -> eyre::Result<&Fork> {\n        let idx = self.ensure_fork_index_by_local_id(id)?;\n        Ok(self.get_fork(idx))\n    }\n\n    /// Removes the fork\n    fn take_fork(&mut self, idx: ForkLookupIndex) -> Fork {\n        debug_assert!(idx < self.forks.len(), \"fork lookup index must exist\");\n        self.forks[idx].take().unwrap()\n    }\n\n    fn set_fork(&mut self, idx: ForkLookupIndex, fork: Fork) {\n        self.forks[idx] = Some(fork)\n    }\n\n    /// Returns an iterator over Forks\n    pub fn forks_iter(&self) -> impl Iterator<Item = (LocalForkId, &Fork)> + '_ {\n        self.issued_local_fork_ids\n            .iter()\n            .map(|(id, fork_id)| (*id, self.get_fork(self.created_forks[fork_id])))\n    }\n\n    /// Returns a mutable iterator over all Forks\n    pub fn forks_iter_mut(&mut self) -> impl Iterator<Item = &mut Fork> + '_ {\n        self.forks.iter_mut().filter_map(|f| f.as_mut())\n    }\n\n    /// Reverts the entire fork database\n    pub fn revert_state_snapshot(\n        &mut self,\n        id: LocalForkId,\n        fork_id: ForkId,\n        idx: ForkLookupIndex,\n        fork: Fork,\n    ) {\n        self.created_forks.insert(fork_id.clone(), idx);\n        self.issued_local_fork_ids.insert(id, fork_id);\n        self.set_fork(idx, fork)\n    }\n\n    /// Updates the fork and the local mapping and returns the new index for the `fork_db`\n    pub fn update_fork_mapping(\n        &mut self,\n        id: LocalForkId,\n        fork_id: ForkId,\n        db: ForkDB,\n        journaled_state: JournaledState,\n    ) -> ForkLookupIndex {\n        let idx = self.forks.len();\n        self.issued_local_fork_ids.insert(id, fork_id.clone());\n        self.created_forks.insert(fork_id, idx);\n\n        let fork = Fork { db, journaled_state };\n        self.forks.push(Some(fork));\n        idx\n    }\n\n    pub fn roll_fork(\n        &mut self,\n        id: LocalForkId,\n        new_fork_id: ForkId,\n        backend: SharedBackend,\n    ) -> eyre::Result<ForkLookupIndex> {\n        let fork_id = self.ensure_fork_id(id)?;\n        let idx = self.ensure_fork_index(fork_id)?;\n\n        if let Some(active) = self.forks[idx].as_mut() {\n            // we initialize a _new_ `ForkDB` but keep the state of persistent accounts\n            let mut new_db = ForkDB::new(backend);\n            for addr in self.persistent_accounts.iter().copied() {\n                merge_db_account_data(addr, &active.db, &mut new_db);\n            }\n            active.db = new_db;\n        }\n        // update mappings\n        self.issued_local_fork_ids.insert(id, new_fork_id.clone());\n        self.created_forks.insert(new_fork_id, idx);\n        Ok(idx)\n    }\n\n    /// Inserts a _new_ `ForkDB` and issues a new local fork identifier\n    ///\n    /// Also returns the index where the `ForDB` is stored\n    pub fn insert_new_fork(\n        &mut self,\n        fork_id: ForkId,\n        db: ForkDB,\n        journaled_state: JournaledState,\n    ) -> (LocalForkId, ForkLookupIndex) {\n        let idx = self.forks.len();\n        self.created_forks.insert(fork_id.clone(), idx);\n        let id = self.next_id();\n        self.issued_local_fork_ids.insert(id, fork_id);\n        let fork = Fork { db, journaled_state };\n        self.forks.push(Some(fork));\n        (id, idx)\n    }\n\n    fn next_id(&mut self) -> U256 {\n        let id = self.next_fork_id;\n        self.next_fork_id += U256::from(1);\n        id\n    }\n\n    /// Returns the number of issued ids\n    pub fn len(&self) -> usize {\n        self.issued_local_fork_ids.len()\n    }\n\n    /// Returns true if no forks are issued\n    pub fn is_empty(&self) -> bool {\n        self.issued_local_fork_ids.is_empty()\n    }\n\n    pub fn precompiles(&self) -> &'static Precompiles {\n        Precompiles::new(PrecompileSpecId::from_spec_id(self.spec_id))\n    }\n\n    /// Returns a new, empty, `JournaledState` with set precompiles\n    pub fn new_journaled_state(&self) -> JournaledState {\n        let mut journal = {\n            let mut journal_inner = JournalInner::new();\n            journal_inner.set_spec_id(self.spec_id);\n            journal_inner\n        };\n        journal\n            .warm_addresses\n            .set_precompile_addresses(self.precompiles().addresses().copied().collect());\n        journal\n    }\n}\n\nimpl Default for BackendInner {\n    fn default() -> Self {\n        Self {\n            launched_with_fork: None,\n            issued_local_fork_ids: Default::default(),\n            created_forks: Default::default(),\n            forks: vec![],\n            state_snapshots: Default::default(),\n            has_state_snapshot_failure: false,\n            caller: None,\n            next_fork_id: Default::default(),\n            persistent_accounts: Default::default(),\n            spec_id: SpecId::default(),\n            // grant the cheatcode,default test and caller address access to execute cheatcodes\n            // itself\n            cheatcode_access_accounts: HashSet::from([\n                CHEATCODE_ADDRESS,\n                TEST_CONTRACT_ADDRESS,\n                CALLER,\n            ]),\n        }\n    }\n}\n\n/// This updates the currently used env with the fork's environment\npub(crate) fn update_current_env_with_fork_env<\n    SPEC,\n    BLOCK: FoundryBlock,\n    TX: FoundryTransaction,\n>(\n    evm_env: &mut EvmEnv<SPEC, BLOCK>,\n    tx_env: &mut TX,\n    fork_evm_env: EvmEnv<SPEC, BLOCK>,\n) {\n    tx_env.set_chain_id(Some(fork_evm_env.cfg_env.chain_id));\n    *evm_env = fork_evm_env;\n}\n\n/// Clones the data of the given `accounts` from the `active` database into the `fork_db`\n/// This includes the data held in storage (`CacheDB`) and kept in the `JournaledState`.\npub(crate) fn merge_account_data<ExtDB: DatabaseRef>(\n    accounts: impl IntoIterator<Item = Address>,\n    active: &CacheDB<ExtDB>,\n    active_journaled_state: &mut JournaledState,\n    target_fork: &mut Fork,\n) {\n    for addr in accounts.into_iter() {\n        merge_db_account_data(addr, active, &mut target_fork.db);\n        merge_journaled_state_data(addr, active_journaled_state, &mut target_fork.journaled_state);\n    }\n\n    *active_journaled_state = target_fork.journaled_state.clone();\n}\n\n/// Clones the account data from the `active_journaled_state`  into the `fork_journaled_state`\nfn merge_journaled_state_data(\n    addr: Address,\n    active_journaled_state: &JournaledState,\n    fork_journaled_state: &mut JournaledState,\n) {\n    if let Some(mut acc) = active_journaled_state.state.get(&addr).cloned() {\n        trace!(?addr, \"updating journaled_state account data\");\n        if let Some(fork_account) = fork_journaled_state.state.get_mut(&addr) {\n            // This will merge the fork's tracked storage with active storage and update values\n            fork_account.storage.extend(std::mem::take(&mut acc.storage));\n            // swap them so we can insert the account as whole in the next step\n            std::mem::swap(&mut fork_account.storage, &mut acc.storage);\n        }\n        fork_journaled_state.state.insert(addr, acc);\n    }\n}\n\n/// Clones the account data from the `active` db into the `ForkDB`\nfn merge_db_account_data<ExtDB: DatabaseRef>(\n    addr: Address,\n    active: &CacheDB<ExtDB>,\n    fork_db: &mut ForkDB,\n) {\n    trace!(?addr, \"merging database data\");\n\n    let Some(acc) = active.cache.accounts.get(&addr) else { return };\n\n    // port contract cache over\n    if let Some(code) = active.cache.contracts.get(&acc.info.code_hash) {\n        trace!(\"merging contract cache\");\n        fork_db.cache.contracts.insert(acc.info.code_hash, code.clone());\n    }\n\n    // port account storage over\n    use std::collections::hash_map::Entry;\n    match fork_db.cache.accounts.entry(addr) {\n        Entry::Vacant(vacant) => {\n            trace!(\"target account not present - inserting from active\");\n            // if the fork_db doesn't have the target account\n            // insert the entire thing\n            vacant.insert(acc.clone());\n        }\n        Entry::Occupied(mut occupied) => {\n            trace!(\"target account present - merging storage slots\");\n            // if the fork_db does have the system,\n            // extend the existing storage (overriding)\n            let fork_account = occupied.get_mut();\n            fork_account.storage.extend(&acc.storage);\n        }\n    }\n}\n\n/// Returns true of the address is a contract\nfn is_contract_in_state(evm_state: &EvmState, acc: Address) -> bool {\n    evm_state.get(&acc).map(|acc| acc.info.code_hash != KECCAK_EMPTY).unwrap_or_default()\n}\n\n/// Updates the evm env's block with the block's data\nfn update_env_block<SPEC, BLOCK: FoundryBlock>(\n    evm_env: &mut EvmEnv<SPEC, BLOCK>,\n    header: &impl BlockHeader,\n) {\n    let block_env = &mut evm_env.block_env;\n    block_env.set_timestamp(U256::from(header.timestamp()));\n    block_env.set_beneficiary(header.beneficiary());\n    block_env.set_difficulty(header.difficulty());\n    block_env.set_prevrandao(header.mix_hash());\n    block_env.set_basefee(header.base_fee_per_gas().unwrap_or_default());\n    block_env.set_gas_limit(header.gas_limit());\n    block_env.set_number(U256::from(header.number()));\n\n    if let Some(excess_blob_gas) = header.excess_blob_gas() {\n        evm_env.block_env.set_blob_excess_gas_and_price(\n            excess_blob_gas,\n            get_blob_base_fee_update_fraction(evm_env.cfg_env.chain_id, header.timestamp()),\n        );\n    }\n}\n\n/// Executes the given transaction and commits state changes to the database _and_ the journaled\n/// state, with an inspector.\n#[allow(clippy::too_many_arguments)]\nfn commit_transaction(\n    tx: &AnyRpcTransaction,\n    evm_env: &mut EvmEnv,\n    tx_env: &mut TxEnv,\n    journaled_state: &mut JournaledState,\n    fork: &mut Fork,\n    fork_id: &ForkId,\n    persistent_accounts: &HashSet<Address>,\n    inspector: &mut dyn EthInspectorExt,\n) -> eyre::Result<()> {\n    if let Some(tx_envelope) = tx.as_envelope() {\n        *tx_env = TxEnv::from_recovered_tx(tx_envelope, tx.from());\n    }\n\n    let now = Instant::now();\n    let res = {\n        let fork = fork.clone();\n        let journaled_state = journaled_state.clone();\n        let depth = journaled_state.depth;\n        let mut db = Backend::new_with_fork(fork_id, fork, journaled_state)?;\n\n        let mut evm = crate::evm::new_eth_evm_with_inspector(\n            &mut db as _,\n            evm_env.to_owned(),\n            tx_env.to_owned(),\n            inspector,\n        );\n        // Adjust inner EVM depth to ensure that inspectors receive accurate data.\n        evm.journaled_state.depth = depth + 1;\n        evm.transact(tx_env.clone()).wrap_err(\"backend: failed committing transaction\")?\n    };\n    trace!(elapsed = ?now.elapsed(), \"transacted transaction\");\n\n    apply_state_changeset(res.state, journaled_state, fork, persistent_accounts)?;\n    Ok(())\n}\n\n/// Helper method which updates data in the state with the data from the database.\n/// Does not change state for persistent accounts (for roll fork to transaction and transact).\npub fn update_state<DB: Database>(\n    state: &mut EvmState,\n    db: &mut DB,\n    persistent_accounts: Option<&HashSet<Address>>,\n) -> Result<(), DB::Error> {\n    for (addr, acc) in state.iter_mut() {\n        if !persistent_accounts.is_some_and(|accounts| accounts.contains(addr)) {\n            acc.info = db.basic(*addr)?.unwrap_or_default();\n            for (key, val) in &mut acc.storage {\n                val.present_value = db.storage(*addr, *key)?;\n            }\n        }\n    }\n\n    Ok(())\n}\n\n/// Applies the changeset of a transaction to the active journaled state and also commits it in the\n/// forked db\nfn apply_state_changeset(\n    state: Map<revm::primitives::Address, Account>,\n    journaled_state: &mut JournaledState,\n    fork: &mut Fork,\n    persistent_accounts: &HashSet<Address>,\n) -> Result<(), BackendError> {\n    // commit the state and update the loaded accounts\n    fork.db.commit(state);\n\n    update_state(&mut journaled_state.state, &mut fork.db, Some(persistent_accounts))?;\n    update_state(&mut fork.journaled_state.state, &mut fork.db, Some(persistent_accounts))?;\n\n    Ok(())\n}\n\n#[cfg(test)]\nmod tests {\n    use crate::{backend::Backend, opts::EvmOpts};\n    use alloy_primitives::{U256, address};\n    use alloy_provider::Provider;\n    use foundry_common::provider::get_http_provider;\n    use foundry_config::{Config, NamedChain};\n    use foundry_fork_db::cache::{BlockchainDb, BlockchainDbMeta};\n    use revm::database::DatabaseRef;\n\n    #[tokio::test(flavor = \"multi_thread\")]\n    async fn can_read_write_cache() {\n        let endpoint = &*foundry_test_utils::rpc::next_http_rpc_endpoint();\n        let provider = get_http_provider(endpoint);\n\n        let block_num = provider.get_block_number().await.unwrap();\n\n        let mut evm_opts = Config::figment().extract::<EvmOpts>().unwrap();\n        evm_opts.fork_url = Some(endpoint.to_string());\n        evm_opts.fork_block_number = Some(block_num);\n\n        let (evm_env, _) = evm_opts.env().await.unwrap();\n\n        let fork = evm_opts.get_fork(&Config::default(), evm_env.clone()).unwrap();\n\n        let backend = Backend::spawn(Some(fork)).unwrap();\n\n        // some rng contract from etherscan\n        let address = address!(\"0x63091244180ae240c87d1f528f5f269134cb07b3\");\n\n        let num_slots = 5;\n        let _account = backend.basic_ref(address);\n        for idx in 0..num_slots {\n            let _ = backend.storage_ref(address, U256::from(idx));\n        }\n        drop(backend);\n\n        let meta = BlockchainDbMeta {\n            chain: None,\n            block_env: evm_env.block_env,\n            hosts: Default::default(),\n        };\n\n        let db = BlockchainDb::new(\n            meta,\n            Some(Config::foundry_block_cache_dir(NamedChain::Mainnet, block_num).unwrap()),\n        );\n        assert!(db.accounts().read().contains_key(&address));\n        assert!(db.storage().read().contains_key(&address));\n        assert_eq!(db.storage().read().get(&address).unwrap().len(), num_slots as usize);\n    }\n}\n"
  },
  {
    "path": "crates/evm/core/src/backend/snapshot.rs",
    "content": "use super::JournaledState;\nuse alloy_evm::EvmEnv;\nuse alloy_primitives::{\n    B256, U256,\n    map::{AddressHashMap, HashMap},\n};\nuse revm::state::AccountInfo;\nuse serde::{Deserialize, Serialize};\n\n/// A minimal abstraction of a state at a certain point in time\n#[derive(Clone, Debug, Default, Serialize, Deserialize)]\npub struct StateSnapshot {\n    pub accounts: AddressHashMap<AccountInfo>,\n    pub storage: AddressHashMap<HashMap<U256, U256>>,\n    pub block_hashes: HashMap<U256, B256>,\n}\n\n/// Represents a state snapshot taken during evm execution\n#[derive(Clone, Debug)]\npub struct BackendStateSnapshot<T> {\n    pub db: T,\n    /// The journaled_state state at a specific point\n    pub journaled_state: JournaledState,\n    /// Contains the evm env at the time of the snapshot\n    pub snap_evm_env: EvmEnv,\n}\n\nimpl<T> BackendStateSnapshot<T> {\n    /// Takes a new state snapshot.\n    pub fn new(db: T, journaled_state: JournaledState, evm_env: EvmEnv) -> Self {\n        Self { db, journaled_state, snap_evm_env: evm_env }\n    }\n\n    /// Called when this state snapshot is reverted.\n    ///\n    /// Since we want to keep all additional logs that were emitted since the snapshot was taken\n    /// we'll merge additional logs into the snapshot's `revm::JournaledState`. Additional logs are\n    /// those logs that are missing in the snapshot's journaled_state, since the current\n    /// journaled_state includes the same logs, we can simply replace use that See also\n    /// `DatabaseExt::revert`.\n    pub fn merge(&mut self, current: &JournaledState) {\n        self.journaled_state.logs.clone_from(&current.logs);\n    }\n}\n\n/// What to do when reverting a state snapshot.\n///\n/// Whether to remove the state snapshot or keep it.\n#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]\npub enum RevertStateSnapshotAction {\n    /// Remove the state snapshot after reverting.\n    #[default]\n    RevertRemove,\n    /// Keep the state snapshot after reverting.\n    RevertKeep,\n}\n\nimpl RevertStateSnapshotAction {\n    /// Returns `true` if the action is to keep the state snapshot.\n    pub fn is_keep(&self) -> bool {\n        matches!(self, Self::RevertKeep)\n    }\n}\n"
  },
  {
    "path": "crates/evm/core/src/buffer.rs",
    "content": "use alloy_primitives::U256;\nuse revm::bytecode::opcode;\n\n/// Used to keep track of which buffer is currently active to be drawn by the debugger.\n#[derive(Debug, PartialEq)]\npub enum BufferKind {\n    Memory,\n    Calldata,\n    Returndata,\n}\n\nimpl BufferKind {\n    /// Helper to cycle through the active buffers.\n    pub fn next(&self) -> Self {\n        match self {\n            Self::Memory => Self::Calldata,\n            Self::Calldata => Self::Returndata,\n            Self::Returndata => Self::Memory,\n        }\n    }\n\n    /// Helper to format the title of the active buffer pane\n    pub fn title(&self, size: usize) -> String {\n        match self {\n            Self::Memory => format!(\"Memory (max expansion: {size} bytes)\"),\n            Self::Calldata => format!(\"Calldata (size: {size} bytes)\"),\n            Self::Returndata => format!(\"Returndata (size: {size} bytes)\"),\n        }\n    }\n}\n\n/// Container for buffer access information.\npub struct BufferAccess {\n    pub offset: usize,\n    pub len: usize,\n}\n\n/// Container for read and write buffer access information.\npub struct BufferAccesses {\n    /// The read buffer kind and access information.\n    pub read: Option<(BufferKind, BufferAccess)>,\n    /// The only mutable buffer is the memory buffer, so don't store the buffer kind.\n    pub write: Option<BufferAccess>,\n}\n\n/// A utility function to get the buffer access.\n///\n/// The memory_access variable stores the index on the stack that indicates the buffer\n/// offset/len accessed by the given opcode:\n///    (read buffer, buffer read offset, buffer read len, write memory offset, write memory len)\n///    \\>= 1: the stack index\n///    0: no memory access\n///    -1: a fixed len of 32 bytes\n///    -2: a fixed len of 1 byte\n///\n/// The return value is a tuple about accessed buffer region by the given opcode:\n///    (read buffer, buffer read offset, buffer read len, write memory offset, write memory len)\npub fn get_buffer_accesses(op: u8, stack: &[U256]) -> Option<BufferAccesses> {\n    let buffer_access = match op {\n        opcode::KECCAK256 | opcode::RETURN | opcode::REVERT => {\n            (Some((BufferKind::Memory, 1, 2)), None)\n        }\n        opcode::CALLDATACOPY => (Some((BufferKind::Calldata, 2, 3)), Some((1, 3))),\n        opcode::RETURNDATACOPY => (Some((BufferKind::Returndata, 2, 3)), Some((1, 3))),\n        opcode::CALLDATALOAD => (Some((BufferKind::Calldata, 1, -1)), None),\n        opcode::CODECOPY => (None, Some((1, 3))),\n        opcode::EXTCODECOPY => (None, Some((2, 4))),\n        opcode::MLOAD => (Some((BufferKind::Memory, 1, -1)), None),\n        opcode::MSTORE => (None, Some((1, -1))),\n        opcode::MSTORE8 => (None, Some((1, -2))),\n        opcode::LOG0 | opcode::LOG1 | opcode::LOG2 | opcode::LOG3 | opcode::LOG4 => {\n            (Some((BufferKind::Memory, 1, 2)), None)\n        }\n        opcode::CREATE | opcode::CREATE2 => (Some((BufferKind::Memory, 2, 3)), None),\n        opcode::CALL | opcode::CALLCODE => (Some((BufferKind::Memory, 4, 5)), None),\n        opcode::DELEGATECALL | opcode::STATICCALL => (Some((BufferKind::Memory, 3, 4)), None),\n        opcode::MCOPY => (Some((BufferKind::Memory, 2, 3)), Some((1, 3))),\n        _ => Default::default(),\n    };\n\n    let stack_len = stack.len();\n    let get_size = |stack_index| match stack_index {\n        -2 => Some(1),\n        -1 => Some(32),\n        0 => None,\n        1.. => {\n            if (stack_index as usize) <= stack_len {\n                Some(stack[stack_len - stack_index as usize].saturating_to())\n            } else {\n                None\n            }\n        }\n        _ => panic!(\"invalid stack index\"),\n    };\n\n    if buffer_access.0.is_some() || buffer_access.1.is_some() {\n        let (read, write) = buffer_access;\n        let read_access = read.and_then(|b| {\n            let (buffer, offset, len) = b;\n            Some((buffer, BufferAccess { offset: get_size(offset)?, len: get_size(len)? }))\n        });\n        let write_access = write.and_then(|b| {\n            let (offset, len) = b;\n            Some(BufferAccess { offset: get_size(offset)?, len: get_size(len)? })\n        });\n        Some(BufferAccesses { read: read_access, write: write_access })\n    } else {\n        None\n    }\n}\n"
  },
  {
    "path": "crates/evm/core/src/bytecode.rs",
    "content": "use revm::bytecode::{OpCode, opcode};\nuse std::{fmt, slice};\n\n/// An iterator that yields opcodes and their immediate data.\n///\n/// If the bytecode is not well-formed, the iterator will still yield opcodes, but the immediate\n/// data may be incorrect. For example, if the bytecode is `PUSH2 0x69`, the iterator will yield\n/// `PUSH2, &[]`.\n#[derive(Clone, Debug)]\npub struct InstIter<'a> {\n    iter: slice::Iter<'a, u8>,\n}\n\nimpl fmt::Display for InstIter<'_> {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        for (i, op) in self.clone().enumerate() {\n            if i > 0 {\n                f.write_str(\" \")?;\n            }\n            write!(f, \"{op}\")?;\n        }\n        Ok(())\n    }\n}\n\nimpl<'a> InstIter<'a> {\n    /// Create a new iterator over the given bytecode slice.\n    #[inline]\n    pub fn new(slice: &'a [u8]) -> Self {\n        Self { iter: slice.iter() }\n    }\n\n    /// Returns a new iterator that also yields the program counter alongside the opcode and\n    /// immediate data.\n    #[inline]\n    pub fn with_pc(self) -> InstIterWithPc<'a> {\n        InstIterWithPc { iter: self, pc: 0 }\n    }\n\n    /// Returns the inner iterator.\n    #[inline]\n    pub fn inner(&self) -> &slice::Iter<'a, u8> {\n        &self.iter\n    }\n\n    /// Returns the inner iterator.\n    #[inline]\n    pub fn inner_mut(&mut self) -> &mut slice::Iter<'a, u8> {\n        &mut self.iter\n    }\n\n    /// Returns the inner iterator.\n    #[inline]\n    pub fn into_inner(self) -> slice::Iter<'a, u8> {\n        self.iter\n    }\n}\n\nimpl<'a> Iterator for InstIter<'a> {\n    type Item = Inst<'a>;\n\n    #[inline]\n    fn next(&mut self) -> Option<Self::Item> {\n        self.iter.next().map(|&opcode| {\n            let opcode = unsafe { OpCode::new_unchecked(opcode) };\n            let len = imm_len(opcode.get()) as usize;\n            let (immediate, rest) = self.iter.as_slice().split_at_checked(len).unwrap_or_default();\n            self.iter = rest.iter();\n            Inst { opcode, immediate }\n        })\n    }\n\n    #[inline]\n    fn size_hint(&self) -> (usize, Option<usize>) {\n        let len = self.iter.len();\n        ((len != 0) as usize, Some(len))\n    }\n}\n\nimpl std::iter::FusedIterator for InstIter<'_> {}\n\n/// A bytecode iterator that yields opcodes and their immediate data, alongside the program counter.\n///\n/// Created by calling [`InstIter::with_pc`].\n#[derive(Debug)]\npub struct InstIterWithPc<'a> {\n    iter: InstIter<'a>,\n    pc: usize,\n}\n\nimpl<'a> Iterator for InstIterWithPc<'a> {\n    type Item = (usize, Inst<'a>);\n\n    #[inline]\n    fn next(&mut self) -> Option<Self::Item> {\n        self.iter.next().map(|inst| {\n            let pc = self.pc;\n            self.pc += 1 + inst.immediate.len();\n            (pc, inst)\n        })\n    }\n\n    #[inline]\n    fn size_hint(&self) -> (usize, Option<usize>) {\n        self.iter.size_hint()\n    }\n}\n\nimpl std::iter::FusedIterator for InstIterWithPc<'_> {}\n\n/// An opcode and its immediate data. Returned by [`InstIter`].\n#[derive(Clone, Copy, PartialEq, Eq)]\npub struct Inst<'a> {\n    /// The opcode.\n    pub opcode: OpCode,\n    /// The immediate data, if any.\n    ///\n    /// If an opcode is missing immediate data, e.g. malformed or bytecode hash, this will be an\n    /// empty slice.\n    pub immediate: &'a [u8],\n}\n\nimpl fmt::Debug for Inst<'_> {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        fmt::Display::fmt(self, f)\n    }\n}\n\nimpl fmt::Display for Inst<'_> {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        write!(f, \"{}\", self.opcode)?;\n        match self.immediate {\n            [] => Ok(()),\n            imm => write!(f, \" {:#x}\", alloy_primitives::hex::display(imm)),\n        }\n    }\n}\n\n/// Returns the length of the immediate data for the given opcode, or `0` if none.\n#[inline]\nconst fn imm_len(op: u8) -> u8 {\n    match op {\n        opcode::PUSH1..=opcode::PUSH32 => op - opcode::PUSH0,\n        _ => 0,\n    }\n}\n\n/// Returns a string representation of the given bytecode.\npub fn format_bytecode(bytecode: &[u8]) -> String {\n    let mut w = String::new();\n    format_bytecode_to(bytecode, &mut w).unwrap();\n    w\n}\n\n/// Formats an EVM bytecode to the given writer.\npub fn format_bytecode_to<W: fmt::Write + ?Sized>(bytecode: &[u8], w: &mut W) -> fmt::Result {\n    write!(w, \"{}\", InstIter::new(bytecode))\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use revm::bytecode::opcode as op;\n\n    fn o(op: u8) -> OpCode {\n        unsafe { OpCode::new_unchecked(op) }\n    }\n\n    #[test]\n    fn iter_basic() {\n        let bytecode = [0x01, 0x02, 0x03, 0x04, 0x05];\n        let mut iter = InstIter::new(&bytecode);\n\n        assert_eq!(iter.next(), Some(Inst { opcode: o(0x01), immediate: &[] }));\n        assert_eq!(iter.next(), Some(Inst { opcode: o(0x02), immediate: &[] }));\n        assert_eq!(iter.next(), Some(Inst { opcode: o(0x03), immediate: &[] }));\n        assert_eq!(iter.next(), Some(Inst { opcode: o(0x04), immediate: &[] }));\n        assert_eq!(iter.next(), Some(Inst { opcode: o(0x05), immediate: &[] }));\n        assert_eq!(iter.next(), None);\n    }\n\n    #[test]\n    fn iter_with_imm() {\n        let bytecode = [op::PUSH0, op::PUSH1, 0x69, op::PUSH2, 0x01, 0x02];\n        let mut iter = InstIter::new(&bytecode);\n\n        assert_eq!(iter.next(), Some(Inst { opcode: o(op::PUSH0), immediate: &[] }));\n        assert_eq!(iter.next(), Some(Inst { opcode: o(op::PUSH1), immediate: &[0x69] }));\n        assert_eq!(iter.next(), Some(Inst { opcode: o(op::PUSH2), immediate: &[0x01, 0x02] }));\n        assert_eq!(iter.next(), None);\n    }\n\n    #[test]\n    fn iter_with_imm_too_short() {\n        let bytecode = [op::PUSH2, 0x69];\n        let mut iter = InstIter::new(&bytecode);\n\n        assert_eq!(iter.next(), Some(Inst { opcode: o(op::PUSH2), immediate: &[] }));\n        assert_eq!(iter.next(), None);\n    }\n\n    #[test]\n    fn display() {\n        let bytecode = [op::PUSH0, op::PUSH1, 0x69, op::PUSH2, 0x01, 0x02];\n        let s = format_bytecode(&bytecode);\n        assert_eq!(s, \"PUSH0 PUSH1 0x69 PUSH2 0x0102\");\n    }\n\n    #[test]\n    fn decode_push2_and_stop() {\n        // 0x61 0xAA 0xBB = PUSH2 0xAABB\n        // 0x00           = STOP\n        let code = vec![0x61, 0xAA, 0xBB, 0x00];\n        let insns = InstIter::new(&code).with_pc().collect::<Vec<_>>();\n\n        // PUSH2 then STOP\n        assert_eq!(insns.len(), 2);\n\n        // PUSH2 at pc = 0\n        let i0 = &insns[0];\n        assert_eq!(i0.0, 0);\n        assert_eq!(i0.1.opcode, op::PUSH2);\n        assert_eq!(i0.1.immediate, &[0xAA, 0xBB]);\n\n        // STOP at pc = 3\n        let i1 = &insns[1];\n        assert_eq!(i1.0, 3);\n        assert_eq!(i1.1.opcode, op::STOP);\n        assert!(i1.1.immediate.is_empty());\n    }\n\n    #[test]\n    fn decode_arithmetic_ops() {\n        // 0x01 = ADD, 0x02 = MUL, 0x03 = SUB, 0x04 = DIV\n        let code = vec![0x01, 0x02, 0x03, 0x04];\n        let insns = InstIter::new(&code).with_pc().collect::<Vec<_>>();\n\n        assert_eq!(insns.len(), 4);\n\n        let expected = [(0, op::ADD), (1, op::MUL), (2, op::SUB), (3, op::DIV)];\n        for ((pc, want_op), insn) in expected.iter().zip(insns.iter()) {\n            assert_eq!(insn.0, *pc);\n            assert_eq!(insn.1.opcode, *want_op);\n            assert!(insn.1.immediate.is_empty());\n        }\n    }\n}\n"
  },
  {
    "path": "crates/evm/core/src/constants.rs",
    "content": "use alloy_primitives::{Address, B256, address, b256, hex};\n\n/// The cheatcode handler address.\n///\n/// This is the same address as the one used in DappTools's HEVM.\n///\n/// This is calculated as:\n/// `address(bytes20(uint160(uint256(keccak256('hevm cheat code')))))`\npub const CHEATCODE_ADDRESS: Address = address!(\"0x7109709ECfa91a80626fF3989D68f67F5b1DD12D\");\n\n/// The contract hash at [`CHEATCODE_ADDRESS`].\n///\n/// This is calculated as:\n/// `keccak256(abi.encodePacked(CHEATCODE_ADDRESS))`.\npub const CHEATCODE_CONTRACT_HASH: B256 =\n    b256!(\"0xb0450508e5a2349057c3b4c9c84524d62be4bb17e565dbe2df34725a26872291\");\n\n/// The Hardhat console address.\n///\n/// See: <https://github.com/NomicFoundation/hardhat/blob/main/v-next/hardhat/console.sol>\npub const HARDHAT_CONSOLE_ADDRESS: Address = address!(\"0x000000000000000000636F6e736F6c652e6c6f67\");\n\n/// Stores the caller address to be used as *sender* account for:\n/// - deploying Test contracts\n/// - deploying Script contracts\n///\n/// Derived from `address(uint160(uint256(keccak256(\"foundry default caller\"))))`,\n/// which is equal to `0x1804c8AB1F12E6bbf3894d4083f33e07309d1f38`.\npub const CALLER: Address = address!(\"0x1804c8AB1F12E6bbf3894d4083f33e07309d1f38\");\n\n/// The default test contract address.\n///\n/// Derived from `CALLER.create(1)`.\npub const TEST_CONTRACT_ADDRESS: Address = address!(\"0x7FA9385bE102ac3EAc297483Dd6233D62b3e1496\");\n\n/// Magic return value returned by the `assume` cheatcode.\npub const MAGIC_ASSUME: &[u8] = b\"FOUNDRY::ASSUME\";\n\n/// Magic return value returned by the `skip` cheatcode. Optionally appended with a reason.\npub const MAGIC_SKIP: &[u8] = b\"FOUNDRY::SKIP\";\n\n/// The address that deploys the default CREATE2 deployer contract.\npub const DEFAULT_CREATE2_DEPLOYER_DEPLOYER: Address =\n    address!(\"0x3fAB184622Dc19b6109349B94811493BF2a45362\");\n/// The default CREATE2 deployer.\npub const DEFAULT_CREATE2_DEPLOYER: Address =\n    address!(\"0x4e59b44847b379578588920ca78fbf26c0b4956c\");\n/// The initcode of the default CREATE2 deployer.\npub const DEFAULT_CREATE2_DEPLOYER_CODE: &[u8] = &hex!(\n    \"604580600e600039806000f350fe7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf3\"\n);\n/// The runtime code of the default CREATE2 deployer.\npub const DEFAULT_CREATE2_DEPLOYER_RUNTIME_CODE: &[u8] = &hex!(\n    \"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf3\"\n);\n/// The hash of the default CREATE2 deployer code.\n///\n/// This is calculated as `keccak256([`DEFAULT_CREATE2_DEPLOYER_RUNTIME_CODE`])`.\npub const DEFAULT_CREATE2_DEPLOYER_CODEHASH: B256 =\n    b256!(\"0x2fa86add0aed31f33a762c9d88e807c475bd51d0f52bd0955754b2608f7e4989\");\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn create2_deployer() {\n        assert_eq!(DEFAULT_CREATE2_DEPLOYER_DEPLOYER.create(0), DEFAULT_CREATE2_DEPLOYER);\n    }\n}\n"
  },
  {
    "path": "crates/evm/core/src/decode.rs",
    "content": "//! Various utilities to decode test results.\n\nuse crate::abi::{Vm, console};\nuse alloy_dyn_abi::JsonAbiExt;\nuse alloy_json_abi::{Error, JsonAbi};\nuse alloy_primitives::{Log, Selector, hex, map::HashMap};\nuse alloy_sol_types::{\n    ContractError::Revert, RevertReason, RevertReason::ContractError, SolEventInterface,\n    SolInterface, SolValue,\n};\nuse foundry_common::SELECTOR_LEN;\nuse itertools::Itertools;\nuse revm::interpreter::InstructionResult;\nuse std::{fmt, sync::OnceLock};\n\n/// A skip reason.\n#[derive(Clone, Debug, PartialEq, Eq)]\npub struct SkipReason(pub Option<String>);\n\nimpl SkipReason {\n    /// Decodes a skip reason, if any.\n    pub fn decode(raw_result: &[u8]) -> Option<Self> {\n        raw_result.strip_prefix(crate::constants::MAGIC_SKIP).map(|reason| {\n            let reason = String::from_utf8_lossy(reason).into_owned();\n            Self((!reason.is_empty()).then_some(reason))\n        })\n    }\n\n    /// Decodes a skip reason from a string that was obtained by formatting `Self`.\n    ///\n    /// This is a hack to support re-decoding a skip reason in proptest.\n    pub fn decode_self(s: &str) -> Option<Self> {\n        s.strip_prefix(\"skipped\").map(|rest| Self(rest.strip_prefix(\": \").map(ToString::to_string)))\n    }\n}\n\nimpl fmt::Display for SkipReason {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.write_str(\"skipped\")?;\n        if let Some(reason) = &self.0 {\n            f.write_str(\": \")?;\n            f.write_str(reason)?;\n        }\n        Ok(())\n    }\n}\n\n/// Decode a set of logs, only returning logs from DSTest logging events and Hardhat's `console.log`\npub fn decode_console_logs(logs: &[Log]) -> Vec<String> {\n    logs.iter().filter_map(decode_console_log).collect()\n}\n\n/// Decode a single log.\n///\n/// This function returns [None] if it is not a DSTest log or the result of a Hardhat\n/// `console.log`.\npub fn decode_console_log(log: &Log) -> Option<String> {\n    console::ds::ConsoleEvents::decode_log(log).ok().map(|decoded| decoded.to_string())\n}\n\n/// Decodes revert data.\n#[derive(Clone, Debug, Default)]\npub struct RevertDecoder {\n    /// The custom errors to use for decoding.\n    errors: HashMap<Selector, Vec<Error>>,\n}\n\nimpl Default for &RevertDecoder {\n    fn default() -> Self {\n        static EMPTY: OnceLock<RevertDecoder> = OnceLock::new();\n        EMPTY.get_or_init(RevertDecoder::new)\n    }\n}\n\nimpl RevertDecoder {\n    /// Creates a new, empty revert decoder.\n    pub fn new() -> Self {\n        Self::default()\n    }\n\n    /// Sets the ABIs to use for error decoding.\n    ///\n    /// Note that this is decently expensive as it will hash all errors for faster indexing.\n    pub fn with_abis<'a>(mut self, abi: impl IntoIterator<Item = &'a JsonAbi>) -> Self {\n        self.extend_from_abis(abi);\n        self\n    }\n\n    /// Sets the ABI to use for error decoding.\n    ///\n    /// Note that this is decently expensive as it will hash all errors for faster indexing.\n    pub fn with_abi(mut self, abi: &JsonAbi) -> Self {\n        self.extend_from_abi(abi);\n        self\n    }\n\n    /// Extends the decoder with the given ABI's custom errors.\n    fn extend_from_abis<'a>(&mut self, abi: impl IntoIterator<Item = &'a JsonAbi>) {\n        for abi in abi {\n            self.extend_from_abi(abi);\n        }\n    }\n\n    /// Extends the decoder with the given ABI's custom errors.\n    fn extend_from_abi(&mut self, abi: &JsonAbi) {\n        for error in abi.errors() {\n            self.push_error(error.clone());\n        }\n    }\n\n    /// Adds a custom error to use for decoding.\n    pub fn push_error(&mut self, error: Error) {\n        self.errors.entry(error.selector()).or_default().push(error);\n    }\n\n    /// Tries to decode an error message from the given revert bytes.\n    ///\n    /// Note that this is just a best-effort guess, and should not be relied upon for anything other\n    /// than user output.\n    pub fn decode(&self, err: &[u8], status: Option<InstructionResult>) -> String {\n        self.maybe_decode(err, status).unwrap_or_else(|| {\n            if err.is_empty() { \"<empty revert data>\".to_string() } else { trimmed_hex(err) }\n        })\n    }\n\n    /// Tries to decode an error message from the given revert bytes.\n    ///\n    /// See [`decode`](Self::decode) for more information.\n    pub fn maybe_decode(&self, err: &[u8], status: Option<InstructionResult>) -> Option<String> {\n        if let Some(reason) = SkipReason::decode(err) {\n            return Some(reason.to_string());\n        }\n\n        // Solidity's `Error(string)` (handled separately in order to strip revert: prefix)\n        if let Some(ContractError(Revert(revert))) = RevertReason::decode(err) {\n            return Some(revert.reason);\n        }\n\n        // Solidity's `Panic(uint256)` and `Vm`'s custom errors.\n        if let Ok(e) = alloy_sol_types::ContractError::<Vm::VmErrors>::abi_decode(err) {\n            return Some(e.to_string());\n        }\n\n        let string_decoded = decode_as_non_empty_string(err);\n\n        if let Some((selector, data)) = err.split_first_chunk::<SELECTOR_LEN>() {\n            // Custom errors.\n            if let Some(errors) = self.errors.get(selector) {\n                for error in errors {\n                    // If we don't decode, don't return an error, try to decode as a string\n                    // later.\n                    if let Ok(decoded) = error.abi_decode_input(data) {\n                        return Some(format!(\n                            \"{}({})\",\n                            error.name,\n                            decoded.iter().map(foundry_common::fmt::format_token).format(\", \")\n                        ));\n                    }\n                }\n            }\n\n            if string_decoded.is_some() {\n                return string_decoded;\n            }\n\n            // Generic custom error.\n            return Some({\n                let mut s = format!(\"custom error {}\", hex::encode_prefixed(selector));\n                if !data.is_empty() {\n                    s.push_str(\": \");\n                    match std::str::from_utf8(data) {\n                        Ok(data) => s.push_str(data),\n                        Err(_) => s.push_str(&hex::encode(data)),\n                    }\n                }\n                s\n            });\n        }\n\n        if string_decoded.is_some() {\n            return string_decoded;\n        }\n\n        if let Some(status) = status\n            && !status.is_ok()\n        {\n            return Some(format!(\"EvmError: {status:?}\"));\n        }\n        if err.is_empty() {\n            None\n        } else {\n            Some(format!(\"custom error bytes {}\", hex::encode_prefixed(err)))\n        }\n    }\n}\n\n/// Helper function that decodes provided error as an ABI encoded or an ASCII string (if not empty).\nfn decode_as_non_empty_string(err: &[u8]) -> Option<String> {\n    // ABI-encoded `string`.\n    if let Ok(s) = String::abi_decode(err)\n        && !s.is_empty()\n    {\n        return Some(s);\n    }\n\n    // ASCII string.\n    if err.is_ascii() {\n        let msg = std::str::from_utf8(err).unwrap().to_string();\n        if !msg.is_empty() {\n            return Some(msg);\n        }\n    }\n\n    None\n}\n\nfn trimmed_hex(s: &[u8]) -> String {\n    let n = 32;\n    if s.len() <= n {\n        hex::encode(s)\n    } else {\n        format!(\n            \"{}…{} ({} bytes)\",\n            &hex::encode(&s[..n / 2]),\n            &hex::encode(&s[s.len() - n / 2..]),\n            s.len(),\n        )\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_trimmed_hex() {\n        assert_eq!(trimmed_hex(&hex::decode(\"1234567890\").unwrap()), \"1234567890\");\n        assert_eq!(\n            trimmed_hex(&hex::decode(\"492077697368207275737420737570706F72746564206869676865722D6B696E646564207479706573\").unwrap()),\n            \"49207769736820727573742073757070…6865722d6b696e646564207479706573 (41 bytes)\"\n        );\n    }\n\n    // https://github.com/foundry-rs/foundry/issues/10162\n    #[test]\n    fn partial_decode() {\n        /*\n        error ValidationFailed(bytes);\n        error InvalidNonce();\n        */\n        let mut decoder = RevertDecoder::default();\n        decoder.push_error(\"ValidationFailed(bytes)\".parse().unwrap());\n\n        /*\n        abi.encodeWithSelector(ValidationFailed.selector, InvalidNonce.selector)\n        */\n        let data = &hex!(\n            \"0xe17594de\"\n            \"756688fe00000000000000000000000000000000000000000000000000000000\"\n        );\n        assert_eq!(\n            decoder.decode(data, None),\n            \"custom error 0xe17594de: 756688fe00000000000000000000000000000000000000000000000000000000\"\n        );\n\n        /*\n        abi.encodeWithSelector(ValidationFailed.selector, abi.encodeWithSelector(InvalidNonce.selector))\n        */\n        let data = &hex!(\n            \"0xe17594de\"\n            \"0000000000000000000000000000000000000000000000000000000000000020\"\n            \"0000000000000000000000000000000000000000000000000000000000000004\"\n            \"756688fe00000000000000000000000000000000000000000000000000000000\"\n        );\n        assert_eq!(decoder.decode(data, None), \"ValidationFailed(0x756688fe)\");\n    }\n}\n"
  },
  {
    "path": "crates/evm/core/src/either_evm.rs",
    "content": "use alloy_evm::{Database, EthEvm, Evm, EvmEnv, eth::EthEvmContext};\nuse alloy_op_evm::OpEvm;\nuse alloy_primitives::{Address, Bytes};\nuse op_revm::{OpContext, OpHaltReason, OpSpecId, OpTransaction, OpTransactionError};\nuse revm::{\n    DatabaseCommit, Inspector,\n    context::{\n        BlockEnv, TxEnv,\n        result::{EVMError, ExecResultAndState, ExecutionResult, ResultAndState},\n    },\n    handler::PrecompileProvider,\n    interpreter::InterpreterResult,\n    primitives::hardfork::SpecId,\n};\n\n/// Alias for result type returned by [`Evm::transact`] methods.\ntype EitherEvmResult<DBError, HaltReason, TxError> =\n    Result<ResultAndState<HaltReason>, EVMError<DBError, TxError>>;\n\n/// Alias for result type returned by [`Evm::transact_commit`] methods.\ntype EitherExecResult<DBError, HaltReason, TxError> =\n    Result<ExecutionResult<HaltReason>, EVMError<DBError, TxError>>;\n\n/// [`EitherEvm`] delegates its calls to one of the two evm implementations; either [`EthEvm`] or\n/// [`OpEvm`].\n///\n/// Calls are delegated to [`OpEvm`] only if optimism is enabled.\n///\n/// The call delegation is handled via its own implementation of the [`Evm`] trait.\n///\n/// The [`Evm::transact`] and other such calls work over the [`OpTransaction<TxEnv>`] type.\n///\n/// However, the [`Evm::HaltReason`] and [`Evm::Error`] leverage the optimism [`OpHaltReason`] and\n/// [`OpTransactionError`] as these are supersets of the eth types. This makes it easier to map eth\n/// types to op types and also prevents ignoring of any error that maybe thrown by [`OpEvm`].\n#[allow(clippy::large_enum_variant)]\npub enum EitherEvm<DB, I, P>\nwhere\n    DB: Database,\n{\n    /// [`EthEvm`] implementation.\n    Eth(EthEvm<DB, I, P>),\n    /// [`OpEvm`] implementation.\n    Op(OpEvm<DB, I, P>),\n}\n\nimpl<DB, I, P> EitherEvm<DB, I, P>\nwhere\n    DB: Database,\n    I: Inspector<EthEvmContext<DB>> + Inspector<OpContext<DB>>,\n    P: PrecompileProvider<EthEvmContext<DB>, Output = InterpreterResult>\n        + PrecompileProvider<OpContext<DB>, Output = InterpreterResult>,\n{\n    /// Converts the [`EthEvm::transact`] result to [`EitherEvmResult`].\n    fn map_eth_result(\n        &self,\n        result: Result<ExecResultAndState<ExecutionResult>, EVMError<DB::Error>>,\n    ) -> EitherEvmResult<DB::Error, OpHaltReason, OpTransactionError> {\n        match result {\n            Ok(result) => Ok(ResultAndState {\n                result: result.result.map_haltreason(OpHaltReason::Base),\n                state: result.state,\n            }),\n            Err(e) => Err(self.map_eth_err(e)),\n        }\n    }\n\n    /// Converts the [`EthEvm::transact_commit`] result to [`EitherExecResult`].\n    fn map_exec_result(\n        &self,\n        result: Result<ExecutionResult, EVMError<DB::Error>>,\n    ) -> EitherExecResult<DB::Error, OpHaltReason, OpTransactionError> {\n        match result {\n            Ok(result) => {\n                // Map the halt reason\n                Ok(result.map_haltreason(OpHaltReason::Base))\n            }\n            Err(e) => Err(self.map_eth_err(e)),\n        }\n    }\n\n    /// Maps [`EVMError<DBError>`] to [`EVMError<DBError, OpTransactionError>`].\n    fn map_eth_err(&self, err: EVMError<DB::Error>) -> EVMError<DB::Error, OpTransactionError> {\n        match err {\n            EVMError::Transaction(invalid_tx) => {\n                EVMError::Transaction(OpTransactionError::Base(invalid_tx))\n            }\n            EVMError::Database(e) => EVMError::Database(e),\n            EVMError::Header(e) => EVMError::Header(e),\n            EVMError::Custom(e) => EVMError::Custom(e),\n        }\n    }\n}\n\nimpl<DB, I, P> Evm for EitherEvm<DB, I, P>\nwhere\n    DB: Database,\n    I: Inspector<EthEvmContext<DB>> + Inspector<OpContext<DB>>,\n    P: PrecompileProvider<EthEvmContext<DB>, Output = InterpreterResult>\n        + PrecompileProvider<OpContext<DB>, Output = InterpreterResult>,\n{\n    type DB = DB;\n    type Error = EVMError<DB::Error, OpTransactionError>;\n    type HaltReason = OpHaltReason;\n    type Tx = OpTransaction<TxEnv>;\n    type Inspector = I;\n    type Precompiles = P;\n    type Spec = SpecId;\n    type BlockEnv = BlockEnv;\n\n    fn block(&self) -> &BlockEnv {\n        match self {\n            Self::Eth(evm) => evm.block(),\n            Self::Op(evm) => evm.block(),\n        }\n    }\n\n    fn chain_id(&self) -> u64 {\n        match self {\n            Self::Eth(evm) => evm.chain_id(),\n            Self::Op(evm) => evm.chain_id(),\n        }\n    }\n\n    fn components(&self) -> (&Self::DB, &Self::Inspector, &Self::Precompiles) {\n        match self {\n            Self::Eth(evm) => evm.components(),\n            Self::Op(evm) => evm.components(),\n        }\n    }\n\n    fn components_mut(&mut self) -> (&mut Self::DB, &mut Self::Inspector, &mut Self::Precompiles) {\n        match self {\n            Self::Eth(evm) => evm.components_mut(),\n            Self::Op(evm) => evm.components_mut(),\n        }\n    }\n\n    fn db_mut(&mut self) -> &mut Self::DB {\n        match self {\n            Self::Eth(evm) => evm.db_mut(),\n            Self::Op(evm) => evm.db_mut(),\n        }\n    }\n\n    fn into_db(self) -> Self::DB\n    where\n        Self: Sized,\n    {\n        match self {\n            Self::Eth(evm) => evm.into_db(),\n            Self::Op(evm) => evm.into_db(),\n        }\n    }\n\n    fn finish(self) -> (Self::DB, EvmEnv<Self::Spec>)\n    where\n        Self: Sized,\n    {\n        match self {\n            Self::Eth(evm) => evm.finish(),\n            Self::Op(evm) => {\n                let (db, env) = evm.finish();\n                (db, map_env(env))\n            }\n        }\n    }\n\n    fn precompiles(&self) -> &Self::Precompiles {\n        match self {\n            Self::Eth(evm) => evm.precompiles(),\n            Self::Op(evm) => evm.precompiles(),\n        }\n    }\n\n    fn precompiles_mut(&mut self) -> &mut Self::Precompiles {\n        match self {\n            Self::Eth(evm) => evm.precompiles_mut(),\n            Self::Op(evm) => evm.precompiles_mut(),\n        }\n    }\n\n    fn inspector(&self) -> &Self::Inspector {\n        match self {\n            Self::Eth(evm) => evm.inspector(),\n            Self::Op(evm) => evm.inspector(),\n        }\n    }\n\n    fn inspector_mut(&mut self) -> &mut Self::Inspector {\n        match self {\n            Self::Eth(evm) => evm.inspector_mut(),\n            Self::Op(evm) => evm.inspector_mut(),\n        }\n    }\n\n    fn enable_inspector(&mut self) {\n        match self {\n            Self::Eth(evm) => evm.enable_inspector(),\n            Self::Op(evm) => evm.enable_inspector(),\n        }\n    }\n\n    fn disable_inspector(&mut self) {\n        match self {\n            Self::Eth(evm) => evm.disable_inspector(),\n            Self::Op(evm) => evm.disable_inspector(),\n        }\n    }\n\n    fn set_inspector_enabled(&mut self, enabled: bool) {\n        match self {\n            Self::Eth(evm) => evm.set_inspector_enabled(enabled),\n            Self::Op(evm) => evm.set_inspector_enabled(enabled),\n        }\n    }\n\n    fn into_env(self) -> EvmEnv<Self::Spec>\n    where\n        Self: Sized,\n    {\n        match self {\n            Self::Eth(evm) => evm.into_env(),\n            Self::Op(evm) => map_env(evm.into_env()),\n        }\n    }\n\n    fn transact(\n        &mut self,\n        tx: impl alloy_evm::IntoTxEnv<Self::Tx>,\n    ) -> Result<ResultAndState<Self::HaltReason>, Self::Error> {\n        match self {\n            Self::Eth(evm) => {\n                let eth = evm.transact(tx.into_tx_env().base);\n                self.map_eth_result(eth)\n            }\n            Self::Op(evm) => evm.transact(tx),\n        }\n    }\n\n    fn transact_commit(\n        &mut self,\n        tx: impl alloy_evm::IntoTxEnv<Self::Tx>,\n    ) -> Result<ExecutionResult<Self::HaltReason>, Self::Error>\n    where\n        Self::DB: DatabaseCommit,\n    {\n        match self {\n            Self::Eth(evm) => {\n                let eth = evm.transact_commit(tx.into_tx_env().base);\n                self.map_exec_result(eth)\n            }\n            Self::Op(evm) => evm.transact_commit(tx),\n        }\n    }\n\n    fn transact_raw(\n        &mut self,\n        tx: Self::Tx,\n    ) -> Result<ResultAndState<Self::HaltReason>, Self::Error> {\n        match self {\n            Self::Eth(evm) => {\n                let res = evm.transact_raw(tx.base);\n                self.map_eth_result(res)\n            }\n            Self::Op(evm) => evm.transact_raw(tx),\n        }\n    }\n\n    fn transact_system_call(\n        &mut self,\n        caller: Address,\n        contract: Address,\n        data: Bytes,\n    ) -> Result<ResultAndState<Self::HaltReason>, Self::Error> {\n        match self {\n            Self::Eth(evm) => {\n                let eth = evm.transact_system_call(caller, contract, data);\n                self.map_eth_result(eth)\n            }\n            Self::Op(evm) => evm.transact_system_call(caller, contract, data),\n        }\n    }\n}\n\n/// Maps [`EvmEnv<OpSpecId>`] to [`EvmEnv`].\nfn map_env(env: EvmEnv<OpSpecId>) -> EvmEnv {\n    let eth_spec_id = env.spec_id().into_eth_spec();\n    let cfg = env.cfg_env.with_spec_and_mainnet_gas_params(eth_spec_id);\n    EvmEnv { cfg_env: cfg, block_env: env.block_env }\n}\n"
  },
  {
    "path": "crates/evm/core/src/env.rs",
    "content": "use std::fmt::Debug;\n\npub use alloy_evm::EvmEnv;\nuse alloy_primitives::{Address, B256, Bytes, U256};\nuse revm::{\n    Context, Database,\n    context::{Block, BlockEnv, Cfg, CfgEnv, Transaction, TxEnv},\n    context_interface::{ContextTr, transaction::AccessList},\n    inspector::JournalExt,\n    primitives::{TxKind, hardfork::SpecId},\n};\n\nuse crate::backend::{DatabaseExt, JournaledState};\n\n/// Extension of [`Block`] with mutable setters, allowing EVM-agnostic mutation of block fields.\npub trait FoundryBlock: Block {\n    /// Sets the block number.\n    fn set_number(&mut self, number: U256);\n\n    /// Sets the beneficiary (coinbase) address.\n    fn set_beneficiary(&mut self, beneficiary: Address);\n\n    /// Sets the block timestamp.\n    fn set_timestamp(&mut self, timestamp: U256);\n\n    /// Sets the gas limit.\n    fn set_gas_limit(&mut self, gas_limit: u64);\n\n    /// Sets the base fee per gas.\n    fn set_basefee(&mut self, basefee: u64);\n\n    /// Sets the block difficulty.\n    fn set_difficulty(&mut self, difficulty: U256);\n\n    /// Sets the prevrandao value.\n    fn set_prevrandao(&mut self, prevrandao: Option<B256>);\n\n    /// Sets the excess blob gas and blob gasprice.\n    fn set_blob_excess_gas_and_price(\n        &mut self,\n        _excess_blob_gas: u64,\n        _base_fee_update_fraction: u64,\n    );\n}\n\nimpl FoundryBlock for BlockEnv {\n    fn set_number(&mut self, number: U256) {\n        self.number = number;\n    }\n\n    fn set_beneficiary(&mut self, beneficiary: Address) {\n        self.beneficiary = beneficiary;\n    }\n\n    fn set_timestamp(&mut self, timestamp: U256) {\n        self.timestamp = timestamp;\n    }\n\n    fn set_gas_limit(&mut self, gas_limit: u64) {\n        self.gas_limit = gas_limit;\n    }\n\n    fn set_basefee(&mut self, basefee: u64) {\n        self.basefee = basefee;\n    }\n\n    fn set_difficulty(&mut self, difficulty: U256) {\n        self.difficulty = difficulty;\n    }\n\n    fn set_prevrandao(&mut self, prevrandao: Option<B256>) {\n        self.prevrandao = prevrandao;\n    }\n\n    fn set_blob_excess_gas_and_price(\n        &mut self,\n        excess_blob_gas: u64,\n        base_fee_update_fraction: u64,\n    ) {\n        self.set_blob_excess_gas_and_price(excess_blob_gas, base_fee_update_fraction);\n    }\n}\n\n/// Extension of [`Transaction`] with mutable setters, allowing EVM-agnostic mutation of transaction\n/// fields.\npub trait FoundryTransaction: Transaction {\n    /// Sets the transaction type.\n    fn set_tx_type(&mut self, tx_type: u8);\n\n    /// Sets the caller (sender) address.\n    fn set_caller(&mut self, caller: Address);\n\n    /// Sets the gas limit.\n    fn set_gas_limit(&mut self, gas_limit: u64);\n\n    /// Sets the gas price (or max fee per gas for EIP-1559).\n    fn set_gas_price(&mut self, gas_price: u128);\n\n    /// Sets the transaction kind (call or create).\n    fn set_kind(&mut self, kind: TxKind);\n\n    /// Sets the value sent with the transaction.\n    fn set_value(&mut self, value: U256);\n\n    /// Sets the transaction input data.\n    fn set_data(&mut self, data: Bytes);\n\n    /// Sets the nonce.\n    fn set_nonce(&mut self, nonce: u64);\n\n    /// Sets the chain ID.\n    fn set_chain_id(&mut self, chain_id: Option<u64>);\n\n    /// Sets the access list.\n    fn set_access_list(&mut self, access_list: AccessList);\n\n    /// Sets the max priority fee per gas.\n    fn set_gas_priority_fee(&mut self, gas_priority_fee: Option<u128>);\n\n    /// Sets the blob versioned hashes.\n    fn set_blob_hashes(&mut self, blob_hashes: Vec<B256>);\n\n    /// Sets the max fee per blob gas.\n    fn set_max_fee_per_blob_gas(&mut self, max_fee_per_blob_gas: u128);\n}\n\nimpl FoundryTransaction for TxEnv {\n    fn set_tx_type(&mut self, tx_type: u8) {\n        self.tx_type = tx_type;\n    }\n\n    fn set_caller(&mut self, caller: Address) {\n        self.caller = caller;\n    }\n\n    fn set_gas_limit(&mut self, gas_limit: u64) {\n        self.gas_limit = gas_limit;\n    }\n\n    fn set_gas_price(&mut self, gas_price: u128) {\n        self.gas_price = gas_price;\n    }\n\n    fn set_kind(&mut self, kind: TxKind) {\n        self.kind = kind;\n    }\n\n    fn set_value(&mut self, value: U256) {\n        self.value = value;\n    }\n\n    fn set_data(&mut self, data: Bytes) {\n        self.data = data;\n    }\n\n    fn set_nonce(&mut self, nonce: u64) {\n        self.nonce = nonce;\n    }\n\n    fn set_chain_id(&mut self, chain_id: Option<u64>) {\n        self.chain_id = chain_id;\n    }\n\n    fn set_access_list(&mut self, access_list: AccessList) {\n        self.access_list = access_list;\n    }\n\n    fn set_gas_priority_fee(&mut self, gas_priority_fee: Option<u128>) {\n        self.gas_priority_fee = gas_priority_fee;\n    }\n\n    fn set_blob_hashes(&mut self, blob_hashes: Vec<B256>) {\n        self.blob_hashes = blob_hashes;\n    }\n\n    fn set_max_fee_per_blob_gas(&mut self, max_fee_per_blob_gas: u128) {\n        self.max_fee_per_blob_gas = max_fee_per_blob_gas;\n    }\n}\n\n/// Marker trait for Foundry's [`CfgEnv`] type, abstracting `Spec` type.\npub trait FoundryCfg: Cfg + Clone + Debug {\n    type Spec: Into<SpecId> + Clone + Debug;\n}\n\nimpl<SPEC: Into<SpecId> + Clone + Debug> FoundryCfg for CfgEnv<SPEC> {\n    type Spec = SPEC;\n}\n\n/// Extension trait providing mutable field access to block, tx, and cfg environments.\n///\n/// [`ContextTr`] only exposes immutable references for block, tx, and cfg.\n/// Cheatcodes like `vm.warp()`, `vm.roll()`, `vm.chainId()` need to mutate these fields.\npub trait FoundryContextExt:\n    ContextTr<\n        Block: FoundryBlock + Clone,\n        Tx: FoundryTransaction + Clone,\n        Cfg: FoundryCfg,\n        Journal: JournalExt,\n    >\n{\n    /// Mutable reference to the block environment.\n    fn block_mut(&mut self) -> &mut Self::Block;\n    /// Mutable reference to the transaction environment.\n    fn tx_mut(&mut self) -> &mut Self::Tx;\n    /// Mutable reference to the configuration environment.\n    fn cfg_mut(&mut self) -> &mut Self::Cfg;\n    /// Mutable reference to the db and the journal inner.\n    fn db_journal_inner_mut(&mut self) -> (&mut Self::Db, &mut JournaledState);\n    /// Sets block environment.\n    fn set_block(&mut self, block: Self::Block) {\n        *self.block_mut() = block;\n    }\n    /// Sets transaction environment.\n    fn set_tx(&mut self, tx: Self::Tx) {\n        *self.tx_mut() = tx;\n    }\n    /// Sets configuration environment.\n    fn set_cfg(&mut self, cfg: Self::Cfg) {\n        *self.cfg_mut() = cfg;\n    }\n    /// Sets journal inner.\n    fn set_journal_inner(&mut self, journal_inner: JournaledState) {\n        *self.db_journal_inner_mut().1 = journal_inner;\n    }\n    /// Sets EVM environment.\n    fn set_evm(&mut self, evm_env: EvmEnv<<Self::Cfg as FoundryCfg>::Spec, Self::Block>)\n    where\n        Self::Cfg: From<CfgEnv<<Self::Cfg as FoundryCfg>::Spec>>,\n    {\n        *self.cfg_mut() = evm_env.cfg_env.into();\n        *self.block_mut() = evm_env.block_env;\n    }\n    /// Cloned transaction environment.\n    fn tx_clone(&self) -> Self::Tx {\n        self.tx().clone()\n    }\n    /// Cloned EVM environment (Cfg + Block).\n    fn evm_clone(&self) -> EvmEnv<<Self::Cfg as FoundryCfg>::Spec, Self::Block>\n    where\n        Self::Cfg: Into<CfgEnv<<Self::Cfg as FoundryCfg>::Spec>>,\n    {\n        EvmEnv::new(self.cfg().clone().into(), self.block().clone())\n    }\n}\n\nimpl<BLOCK: FoundryBlock + Clone, TX: FoundryTransaction + Clone, CFG: FoundryCfg, DB: Database>\n    FoundryContextExt for Context<BLOCK, TX, CFG, DB>\n{\n    fn block_mut(&mut self) -> &mut Self::Block {\n        &mut self.block\n    }\n    fn tx_mut(&mut self) -> &mut Self::Tx {\n        &mut self.tx\n    }\n    fn cfg_mut(&mut self) -> &mut Self::Cfg {\n        &mut self.cfg\n    }\n    fn db_journal_inner_mut(&mut self) -> (&mut Self::Db, &mut JournaledState) {\n        (&mut self.journaled_state.database, &mut self.journaled_state.inner)\n    }\n}\n\n/// Temporary bound alias used during the transition to a fully generic foundry-evm and\n/// foundry-cheatcodes.\n///\n/// Pins the EVM context to Ethereum-specific environment types (`BlockEnv`, `TxEnv`, `CfgEnv`)\n/// so that cheatcode implementations don't need to repeat the full where-clause everywhere.\n/// Once cheatcodes are fully generic over network/environment types this alias will be removed.\npub trait EthCheatCtx:\n    FoundryContextExt<\n        Block = BlockEnv,\n        Tx = TxEnv,\n        Cfg = CfgEnv,\n        Db: DatabaseExt<Self::Block, Self::Tx, <Self::Cfg as FoundryCfg>::Spec>,\n    >\n{\n}\nimpl<CTX> EthCheatCtx for CTX where\n    CTX: FoundryContextExt<\n            Block = BlockEnv,\n            Tx = TxEnv,\n            Cfg = CfgEnv,\n            Db: DatabaseExt<Self::Block, Self::Tx, <Self::Cfg as FoundryCfg>::Spec>,\n        >\n{\n}\n"
  },
  {
    "path": "crates/evm/core/src/evm.rs",
    "content": "use std::{\n    marker::PhantomData,\n    ops::{Deref, DerefMut},\n};\n\nuse crate::{\n    EthCheatCtx, EthInspectorExt,\n    backend::{DatabaseExt, JournaledState},\n    constants::DEFAULT_CREATE2_DEPLOYER_CODEHASH,\n};\nuse alloy_consensus::constants::KECCAK_EMPTY;\nuse alloy_evm::{Evm, EvmEnv, EvmFactory, eth::EthEvmContext, precompiles::PrecompilesMap};\nuse alloy_primitives::{Address, Bytes, U256};\nuse foundry_fork_db::DatabaseError;\nuse revm::{\n    Context,\n    context::{\n        BlockEnv, Cfg, CfgEnv, ContextTr, CreateScheme, Evm as RevmEvm, JournalTr, LocalContextTr,\n        TxEnv,\n        result::{EVMError, ExecResultAndState, ExecutionResult, HaltReason, ResultAndState},\n    },\n    handler::{\n        EthFrame, EvmTr, FrameResult, FrameTr, Handler, ItemOrResult, instructions::EthInstructions,\n    },\n    inspector::{InspectorEvmTr, InspectorHandler},\n    interpreter::{\n        CallInput, CallInputs, CallOutcome, CallScheme, CallValue, CreateInputs, CreateOutcome,\n        FrameInput, Gas, InstructionResult, InterpreterResult, SharedMemory,\n        interpreter::EthInterpreter, interpreter_action::FrameInit, return_ok,\n    },\n    primitives::hardfork::SpecId,\n};\n\npub fn new_eth_evm_with_inspector<'db, I: EthInspectorExt>(\n    db: &'db mut dyn DatabaseExt,\n    evm_env: EvmEnv,\n    tx_env: TxEnv,\n    inspector: I,\n) -> FoundryEvm<'db, I> {\n    let eth_evm =\n        alloy_evm::EthEvmFactory::default().create_evm_with_inspector(db, evm_env, inspector);\n    let mut inner = eth_evm.into_inner();\n    inner.ctx.cfg.tx_chain_id_check = true;\n    inner.ctx.tx = tx_env;\n\n    let mut evm = FoundryEvm { inner };\n    evm.inspector().get_networks().inject_precompiles(evm.precompiles_mut());\n    evm\n}\n\n/// Get the call inputs for the CREATE2 factory.\nfn get_create2_factory_call_inputs(\n    salt: U256,\n    inputs: &CreateInputs,\n    deployer: Address,\n) -> CallInputs {\n    let calldata = [&salt.to_be_bytes::<32>()[..], &inputs.init_code()[..]].concat();\n    CallInputs {\n        caller: inputs.caller(),\n        bytecode_address: deployer,\n        known_bytecode: None,\n        target_address: deployer,\n        scheme: CallScheme::Call,\n        value: CallValue::Transfer(inputs.value()),\n        input: CallInput::Bytes(calldata.into()),\n        gas_limit: inputs.gas_limit(),\n        is_static: false,\n        return_memory_offset: 0..0,\n    }\n}\n\npub struct FoundryEvm<'db, I: EthInspectorExt> {\n    #[allow(clippy::type_complexity)]\n    inner: RevmEvm<\n        EthEvmContext<&'db mut dyn DatabaseExt>,\n        I,\n        EthInstructions<EthInterpreter, EthEvmContext<&'db mut dyn DatabaseExt>>,\n        PrecompilesMap,\n        EthFrame<EthInterpreter>,\n    >,\n}\n\nimpl<'db, I: EthInspectorExt> Evm for FoundryEvm<'db, I> {\n    type Precompiles = PrecompilesMap;\n    type Inspector = I;\n    type DB = &'db mut dyn DatabaseExt;\n    type Error = EVMError<DatabaseError>;\n    type HaltReason = HaltReason;\n    type Spec = SpecId;\n    type Tx = TxEnv;\n    type BlockEnv = BlockEnv;\n\n    fn block(&self) -> &BlockEnv {\n        &self.inner.block\n    }\n\n    fn chain_id(&self) -> u64 {\n        self.inner.ctx.cfg.chain_id\n    }\n\n    fn components(&self) -> (&Self::DB, &Self::Inspector, &Self::Precompiles) {\n        (&self.inner.ctx.journaled_state.database, &self.inner.inspector, &self.inner.precompiles)\n    }\n\n    fn components_mut(&mut self) -> (&mut Self::DB, &mut Self::Inspector, &mut Self::Precompiles) {\n        (\n            &mut self.inner.ctx.journaled_state.database,\n            &mut self.inner.inspector,\n            &mut self.inner.precompiles,\n        )\n    }\n\n    fn set_inspector_enabled(&mut self, _enabled: bool) {\n        unimplemented!(\"FoundryEvm is always inspecting\")\n    }\n\n    fn transact_raw(\n        &mut self,\n        tx: Self::Tx,\n    ) -> Result<ResultAndState<Self::HaltReason>, Self::Error> {\n        self.inner.ctx.tx = tx;\n\n        let mut handler = FoundryHandler::<I>::default();\n        let result = handler.inspect_run(&mut self.inner)?;\n\n        Ok(ResultAndState::new(result, self.inner.ctx.journaled_state.inner.state.clone()))\n    }\n\n    fn transact_system_call(\n        &mut self,\n        _caller: Address,\n        _contract: Address,\n        _data: Bytes,\n    ) -> Result<ExecResultAndState<ExecutionResult>, Self::Error> {\n        unimplemented!()\n    }\n\n    fn finish(self) -> (Self::DB, EvmEnv<Self::Spec>)\n    where\n        Self: Sized,\n    {\n        let Context { block: block_env, cfg: cfg_env, journaled_state, .. } = self.inner.ctx;\n\n        (journaled_state.database, EvmEnv { block_env, cfg_env })\n    }\n}\n\nimpl<'db, I: EthInspectorExt> Deref for FoundryEvm<'db, I> {\n    type Target = Context<BlockEnv, TxEnv, CfgEnv, &'db mut dyn DatabaseExt>;\n\n    fn deref(&self) -> &Self::Target {\n        &self.inner.ctx\n    }\n}\n\nimpl<I: EthInspectorExt> DerefMut for FoundryEvm<'_, I> {\n    fn deref_mut(&mut self) -> &mut Self::Target {\n        &mut self.inner.ctx\n    }\n}\n\n/// Object-safe trait exposing the operations that cheatcode nested EVM closures need.\n///\n/// This abstracts over the concrete EVM type (`FoundryEvm`, future `TempoEvm`, etc.)\n/// so that cheatcode impls can build and run nested EVMs without knowing the concrete type.\npub trait NestedEvm {\n    /// The transaction environment type.\n    type Tx;\n    /// The block environment type.\n    type Block;\n    /// The EVM spec (hardfork) type.\n    type Spec;\n\n    /// Returns a mutable reference to the journal inner state (`JournaledState`).\n    fn journal_inner_mut(&mut self) -> &mut JournaledState;\n\n    /// Runs a single execution frame (create or call) through the EVM handler loop.\n    fn run_execution(&mut self, frame: FrameInput) -> Result<FrameResult, EVMError<DatabaseError>>;\n\n    /// Executes a full transaction with the given tx env.\n    fn transact(\n        &mut self,\n        tx: Self::Tx,\n    ) -> Result<ResultAndState<HaltReason>, EVMError<DatabaseError>>;\n\n    /// Returns a snapshot of the current EVM environment (cfg + block).\n    fn to_evm_env(&self) -> EvmEnv<Self::Spec, Self::Block>;\n}\n\nimpl<I: EthInspectorExt> NestedEvm for FoundryEvm<'_, I> {\n    type Tx = TxEnv;\n    type Block = BlockEnv;\n    type Spec = SpecId;\n\n    fn journal_inner_mut(&mut self) -> &mut JournaledState {\n        &mut self.inner.ctx.journaled_state.inner\n    }\n\n    fn run_execution(&mut self, frame: FrameInput) -> Result<FrameResult, EVMError<DatabaseError>> {\n        let mut handler = FoundryHandler::<I>::default();\n\n        // Create first frame\n        let memory =\n            SharedMemory::new_with_buffer(self.inner.ctx().local().shared_memory_buffer().clone());\n        let first_frame_input = FrameInit { depth: 0, memory, frame_input: frame };\n\n        // Run execution loop\n        let mut frame_result = handler.inspect_run_exec_loop(&mut self.inner, first_frame_input)?;\n\n        // Handle last frame result\n        handler.last_frame_result(&mut self.inner, &mut frame_result)?;\n\n        Ok(frame_result)\n    }\n\n    fn transact(\n        &mut self,\n        tx: TxEnv,\n    ) -> Result<ResultAndState<HaltReason>, EVMError<DatabaseError>> {\n        Evm::transact_raw(self, tx)\n    }\n\n    fn to_evm_env(&self) -> EvmEnv {\n        EvmEnv { cfg_env: self.inner.ctx.cfg.clone(), block_env: self.inner.ctx.block.clone() }\n    }\n}\n\n/// Closure type used by `CheatcodesExecutor` methods that run nested EVM operations.\npub type NestedEvmClosure<'a, Block, Tx, Spec> =\n    &'a mut dyn FnMut(\n        &mut dyn NestedEvm<Block = Block, Tx = Tx, Spec = Spec>,\n    ) -> Result<(), EVMError<DatabaseError>>;\n\n/// Clones the current context (env + journal), passes the database, cloned env,\n/// and cloned journal inner to the callback. The callback builds whatever EVM it\n/// needs, runs its operations, and returns `(result, modified_env, modified_journal)`.\n/// Modified state is written back after the callback returns.\npub fn with_cloned_context<CTX: EthCheatCtx>(\n    ecx: &mut CTX,\n    f: impl FnOnce(\n        &mut dyn DatabaseExt<CTX::Block, CTX::Tx, <CTX::Cfg as Cfg>::Spec>,\n        EvmEnv<<CTX::Cfg as Cfg>::Spec, CTX::Block>,\n        CTX::Tx,\n        JournaledState,\n    ) -> Result<\n        (EvmEnv<<CTX::Cfg as Cfg>::Spec, CTX::Block>, JournaledState),\n        EVMError<DatabaseError>,\n    >,\n) -> Result<(), EVMError<DatabaseError>> {\n    let evm_env = ecx.evm_clone();\n    let tx_env = ecx.tx_clone();\n\n    let (db, journal_inner) = ecx.db_journal_inner_mut();\n    let journal_inner_clone = journal_inner.clone();\n\n    let (sub_evm_env, sub_inner) = f(db, evm_env, tx_env, journal_inner_clone)?;\n\n    // Write back modified state. The db borrow was released when f returned.\n    ecx.set_journal_inner(sub_inner);\n    ecx.set_evm(sub_evm_env);\n\n    Ok(())\n}\n\npub struct FoundryHandler<'db, I: EthInspectorExt> {\n    create2_overrides: Vec<(usize, CallInputs)>,\n    _phantom: PhantomData<(&'db mut dyn DatabaseExt, I)>,\n}\n\nimpl<I: EthInspectorExt> Default for FoundryHandler<'_, I> {\n    fn default() -> Self {\n        Self { create2_overrides: Vec::new(), _phantom: PhantomData }\n    }\n}\n\n// Blanket Handler implementation for FoundryHandler, needed for implementing the InspectorHandler\n// trait.\nimpl<'db, I: EthInspectorExt> Handler for FoundryHandler<'db, I> {\n    type Evm = RevmEvm<\n        EthEvmContext<&'db mut dyn DatabaseExt>,\n        I,\n        EthInstructions<EthInterpreter, EthEvmContext<&'db mut dyn DatabaseExt>>,\n        PrecompilesMap,\n        EthFrame<EthInterpreter>,\n    >;\n    type Error = EVMError<DatabaseError>;\n    type HaltReason = HaltReason;\n}\n\nimpl<'db, I: EthInspectorExt> FoundryHandler<'db, I> {\n    /// Handles CREATE2 frame initialization, potentially transforming it to use the CREATE2\n    /// factory.\n    fn handle_create_frame(\n        &mut self,\n        evm: &mut <Self as Handler>::Evm,\n        init: &mut FrameInit,\n    ) -> Result<Option<FrameResult>, <Self as Handler>::Error> {\n        if let FrameInput::Create(inputs) = &init.frame_input\n            && let CreateScheme::Create2 { salt } = inputs.scheme()\n        {\n            let (ctx, inspector) = evm.ctx_inspector();\n\n            if inspector.should_use_create2_factory(ctx.journal().depth(), inputs) {\n                let gas_limit = inputs.gas_limit();\n\n                // Get CREATE2 deployer.\n                let create2_deployer = evm.inspector().create2_deployer();\n\n                // Generate call inputs for CREATE2 factory.\n                let call_inputs = get_create2_factory_call_inputs(salt, inputs, create2_deployer);\n\n                // Push data about current override to the stack.\n                self.create2_overrides.push((evm.journal().depth(), call_inputs.clone()));\n\n                // Sanity check that CREATE2 deployer exists.\n                let code_hash = evm.journal_mut().load_account(create2_deployer)?.info.code_hash;\n                if code_hash == KECCAK_EMPTY {\n                    return Ok(Some(FrameResult::Call(CallOutcome {\n                        result: InterpreterResult {\n                            result: InstructionResult::Revert,\n                            output: Bytes::from(\n                                format!(\"missing CREATE2 deployer: {create2_deployer}\")\n                                    .into_bytes(),\n                            ),\n                            gas: Gas::new(gas_limit),\n                        },\n                        memory_offset: 0..0,\n                        was_precompile_called: false,\n                        precompile_call_logs: vec![],\n                    })));\n                } else if code_hash != DEFAULT_CREATE2_DEPLOYER_CODEHASH {\n                    return Ok(Some(FrameResult::Call(CallOutcome {\n                        result: InterpreterResult {\n                            result: InstructionResult::Revert,\n                            output: \"invalid CREATE2 deployer bytecode\".into(),\n                            gas: Gas::new(gas_limit),\n                        },\n                        memory_offset: 0..0,\n                        was_precompile_called: false,\n                        precompile_call_logs: vec![],\n                    })));\n                }\n\n                // Rewrite the frame init\n                init.frame_input = FrameInput::Call(Box::new(call_inputs));\n            }\n        }\n        Ok(None)\n    }\n\n    /// Transforms CREATE2 factory call results back into CREATE outcomes.\n    fn handle_create2_override(\n        &mut self,\n        evm: &mut <Self as Handler>::Evm,\n        result: FrameResult,\n    ) -> FrameResult {\n        if self.create2_overrides.last().is_some_and(|(depth, _)| *depth == evm.journal().depth()) {\n            let (_, call_inputs) = self.create2_overrides.pop().unwrap();\n            let FrameResult::Call(mut call) = result else {\n                unreachable!(\"create2 override should be a call frame\");\n            };\n\n            // Decode address from output.\n            let address = match call.instruction_result() {\n                return_ok!() => Address::try_from(call.output().as_ref())\n                    .map_err(|_| {\n                        call.result = InterpreterResult {\n                            result: InstructionResult::Revert,\n                            output: \"invalid CREATE2 factory output\".into(),\n                            gas: Gas::new(call_inputs.gas_limit),\n                        };\n                    })\n                    .ok(),\n                _ => None,\n            };\n\n            FrameResult::Create(CreateOutcome { result: call.result, address })\n        } else {\n            result\n        }\n    }\n}\n\nimpl<I: EthInspectorExt> InspectorHandler for FoundryHandler<'_, I> {\n    type IT = EthInterpreter;\n\n    fn inspect_run_exec_loop(\n        &mut self,\n        evm: &mut Self::Evm,\n        first_frame_input: <<Self::Evm as EvmTr>::Frame as FrameTr>::FrameInit,\n    ) -> Result<FrameResult, Self::Error> {\n        let res = evm.inspect_frame_init(first_frame_input)?;\n\n        if let ItemOrResult::Result(frame_result) = res {\n            return Ok(frame_result);\n        }\n\n        loop {\n            let call_or_result = evm.inspect_frame_run()?;\n\n            let result = match call_or_result {\n                ItemOrResult::Item(mut init) => {\n                    // Handle CREATE/CREATE2 frame initialization\n                    if let Some(frame_result) = self.handle_create_frame(evm, &mut init)? {\n                        return Ok(frame_result);\n                    }\n\n                    match evm.inspect_frame_init(init)? {\n                        ItemOrResult::Item(_) => continue,\n                        ItemOrResult::Result(result) => result,\n                    }\n                }\n                ItemOrResult::Result(result) => result,\n            };\n\n            // Handle CREATE2 override transformation if needed\n            let result = self.handle_create2_override(evm, result);\n\n            if let Some(result) = evm.frame_return_result(result)? {\n                return Ok(result);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "crates/evm/core/src/fork/database.rs",
    "content": "//! A revm database that forks off a remote client\n\nuse crate::{\n    backend::{RevertStateSnapshotAction, StateSnapshot},\n    state_snapshot::StateSnapshots,\n};\nuse alloy_network::Network;\nuse alloy_primitives::{Address, B256, U256, map::HashMap};\nuse alloy_rpc_types::BlockId;\nuse foundry_fork_db::{BlockchainDb, DatabaseError, SharedBackend};\nuse parking_lot::Mutex;\nuse revm::{\n    Database, DatabaseCommit,\n    bytecode::Bytecode,\n    database::{CacheDB, DatabaseRef},\n    state::{Account, AccountInfo},\n};\nuse std::sync::Arc;\n\n/// a [revm::Database] that's forked off another client\n///\n/// The `backend` is used to retrieve (missing) data, which is then fetched from the remote\n/// endpoint. The inner in-memory database holds this storage and will be used for write operations.\n/// This database uses the `backend` for read and the `db` for write operations. But note the\n/// `backend` will also write (missing) data to the `db` in the background\n#[derive(Clone, Debug)]\npub struct ForkedDatabase<N: Network> {\n    /// Responsible for fetching missing data.\n    ///\n    /// This is responsible for getting data.\n    backend: SharedBackend<N>,\n    /// Cached Database layer, ensures that changes are not written to the database that\n    /// exclusively stores the state of the remote client.\n    ///\n    /// This separates Read/Write operations\n    ///   - reads from the `SharedBackend as DatabaseRef` writes to the internal cache storage.\n    cache_db: CacheDB<SharedBackend<N>>,\n    /// Contains all the data already fetched.\n    ///\n    /// This exclusively stores the _unchanged_ remote client state.\n    db: BlockchainDb,\n    /// Holds the state snapshots of a blockchain.\n    state_snapshots: Arc<Mutex<StateSnapshots<ForkDbStateSnapshot<N>>>>,\n}\n\nimpl<N: Network> ForkedDatabase<N> {\n    /// Creates a new instance of this DB\n    pub fn new(backend: SharedBackend<N>, db: BlockchainDb) -> Self {\n        Self {\n            cache_db: CacheDB::new(backend.clone()),\n            backend,\n            db,\n            state_snapshots: Arc::new(Mutex::new(Default::default())),\n        }\n    }\n\n    pub fn database(&self) -> &CacheDB<SharedBackend<N>> {\n        &self.cache_db\n    }\n\n    pub fn database_mut(&mut self) -> &mut CacheDB<SharedBackend<N>> {\n        &mut self.cache_db\n    }\n\n    pub fn state_snapshots(&self) -> &Arc<Mutex<StateSnapshots<ForkDbStateSnapshot<N>>>> {\n        &self.state_snapshots\n    }\n\n    /// Reset the fork to a fresh forked state, and optionally update the fork config\n    pub fn reset(\n        &mut self,\n        _url: Option<String>,\n        block_number: impl Into<BlockId>,\n    ) -> Result<(), String> {\n        self.backend.set_pinned_block(block_number).map_err(|err| err.to_string())?;\n\n        // TODO need to find a way to update generic provider via url\n\n        // wipe the storage retrieved from remote\n        self.inner().db().clear();\n        // create a fresh `CacheDB`, effectively wiping modified state\n        self.cache_db = CacheDB::new(self.backend.clone());\n        trace!(target: \"backend::forkdb\", \"Cleared database\");\n        Ok(())\n    }\n\n    /// Flushes the cache to disk if configured\n    pub fn flush_cache(&self) {\n        self.db.cache().flush()\n    }\n\n    /// Returns the database that holds the remote state\n    pub fn inner(&self) -> &BlockchainDb {\n        &self.db\n    }\n\n    pub fn create_state_snapshot(&self) -> ForkDbStateSnapshot<N> {\n        let db = self.db.db();\n        let state_snapshot = StateSnapshot {\n            accounts: db.accounts.read().clone(),\n            storage: db.storage.read().clone(),\n            block_hashes: db.block_hashes.read().clone(),\n        };\n        ForkDbStateSnapshot { local: self.cache_db.clone(), state_snapshot }\n    }\n\n    pub fn insert_state_snapshot(&self) -> U256 {\n        let state_snapshot = self.create_state_snapshot();\n        let mut state_snapshots = self.state_snapshots().lock();\n        let id = state_snapshots.insert(state_snapshot);\n        trace!(target: \"backend::forkdb\", \"Created new snapshot {}\", id);\n        id\n    }\n\n    /// Removes the snapshot from the tracked snapshot and sets it as the current state\n    pub fn revert_state_snapshot(&mut self, id: U256, action: RevertStateSnapshotAction) -> bool {\n        let state_snapshot = { self.state_snapshots().lock().remove_at(id) };\n        if let Some(state_snapshot) = state_snapshot {\n            if action.is_keep() {\n                self.state_snapshots().lock().insert_at(state_snapshot.clone(), id);\n            }\n            let ForkDbStateSnapshot {\n                local,\n                state_snapshot: StateSnapshot { accounts, storage, block_hashes },\n            } = state_snapshot;\n            let db = self.inner().db();\n            {\n                let mut accounts_lock = db.accounts.write();\n                accounts_lock.clear();\n                accounts_lock.extend(accounts);\n            }\n            {\n                let mut storage_lock = db.storage.write();\n                storage_lock.clear();\n                storage_lock.extend(storage);\n            }\n            {\n                let mut block_hashes_lock = db.block_hashes.write();\n                block_hashes_lock.clear();\n                block_hashes_lock.extend(block_hashes);\n            }\n\n            self.cache_db = local;\n\n            trace!(target: \"backend::forkdb\", \"Reverted snapshot {}\", id);\n            true\n        } else {\n            warn!(target: \"backend::forkdb\", \"No snapshot to revert for {}\", id);\n            false\n        }\n    }\n}\n\nimpl<N: Network> Database for ForkedDatabase<N> {\n    type Error = DatabaseError;\n\n    fn basic(&mut self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {\n        // Note: this will always return Some, since the `SharedBackend` will always load the\n        // account, this differs from `<CacheDB as Database>::basic`, See also\n        // [MemDb::ensure_loaded](crate::backend::MemDb::ensure_loaded)\n        Database::basic(&mut self.cache_db, address)\n    }\n\n    fn code_by_hash(&mut self, code_hash: B256) -> Result<Bytecode, Self::Error> {\n        Database::code_by_hash(&mut self.cache_db, code_hash)\n    }\n\n    fn storage(&mut self, address: Address, index: U256) -> Result<U256, Self::Error> {\n        Database::storage(&mut self.cache_db, address, index)\n    }\n\n    fn block_hash(&mut self, number: u64) -> Result<B256, Self::Error> {\n        Database::block_hash(&mut self.cache_db, number)\n    }\n}\n\nimpl<N: Network> DatabaseRef for ForkedDatabase<N> {\n    type Error = DatabaseError;\n\n    fn basic_ref(&self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {\n        self.cache_db.basic_ref(address)\n    }\n\n    fn code_by_hash_ref(&self, code_hash: B256) -> Result<Bytecode, Self::Error> {\n        self.cache_db.code_by_hash_ref(code_hash)\n    }\n\n    fn storage_ref(&self, address: Address, index: U256) -> Result<U256, Self::Error> {\n        DatabaseRef::storage_ref(&self.cache_db, address, index)\n    }\n\n    fn block_hash_ref(&self, number: u64) -> Result<B256, Self::Error> {\n        self.cache_db.block_hash_ref(number)\n    }\n}\n\nimpl<N: Network> DatabaseCommit for ForkedDatabase<N> {\n    fn commit(&mut self, changes: HashMap<Address, Account>) {\n        self.database_mut().commit(changes)\n    }\n}\n\n/// Represents a snapshot of the database\n///\n/// This mimics `revm::CacheDB`\n#[derive(Clone, Debug)]\npub struct ForkDbStateSnapshot<N: Network> {\n    pub local: CacheDB<SharedBackend<N>>,\n    pub state_snapshot: StateSnapshot,\n}\n\nimpl<N: Network> ForkDbStateSnapshot<N> {\n    fn get_storage(&self, address: Address, index: U256) -> Option<U256> {\n        self.local\n            .cache\n            .accounts\n            .get(&address)\n            .and_then(|account| account.storage.get(&index))\n            .copied()\n    }\n}\n\n// This `DatabaseRef` implementation works similar to `CacheDB` which prioritizes modified elements,\n// and uses another db as fallback\n// We prioritize stored changed accounts/storage\nimpl<N: Network> DatabaseRef for ForkDbStateSnapshot<N> {\n    type Error = DatabaseError;\n\n    fn basic_ref(&self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {\n        match self.local.cache.accounts.get(&address) {\n            Some(account) => Ok(Some(account.info.clone())),\n            None => {\n                let mut acc = self.state_snapshot.accounts.get(&address).cloned();\n\n                if acc.is_none() {\n                    acc = self.local.basic_ref(address)?;\n                }\n                Ok(acc)\n            }\n        }\n    }\n\n    fn code_by_hash_ref(&self, code_hash: B256) -> Result<Bytecode, Self::Error> {\n        self.local.code_by_hash_ref(code_hash)\n    }\n\n    fn storage_ref(&self, address: Address, index: U256) -> Result<U256, Self::Error> {\n        match self.local.cache.accounts.get(&address) {\n            Some(account) => match account.storage.get(&index) {\n                Some(entry) => Ok(*entry),\n                None => match self.get_storage(address, index) {\n                    None => DatabaseRef::storage_ref(&self.local, address, index),\n                    Some(storage) => Ok(storage),\n                },\n            },\n            None => match self.get_storage(address, index) {\n                None => DatabaseRef::storage_ref(&self.local, address, index),\n                Some(storage) => Ok(storage),\n            },\n        }\n    }\n\n    fn block_hash_ref(&self, number: u64) -> Result<B256, Self::Error> {\n        match self.state_snapshot.block_hashes.get(&U256::from(number)).copied() {\n            None => self.local.block_hash_ref(number),\n            Some(block_hash) => Ok(block_hash),\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use crate::backend::BlockchainDbMeta;\n    use foundry_common::provider::get_http_provider;\n\n    /// Demonstrates that `Database::basic` for `ForkedDatabase` will always return the\n    /// `AccountInfo`\n    #[tokio::test(flavor = \"multi_thread\")]\n    async fn fork_db_insert_basic_default() {\n        let rpc = foundry_test_utils::rpc::next_http_rpc_endpoint();\n        let provider = get_http_provider(rpc.clone());\n        let meta = BlockchainDbMeta::new(Default::default(), rpc);\n\n        let db = BlockchainDb::new(meta, None);\n\n        let backend = SharedBackend::spawn_backend(Arc::new(provider), db.clone(), None).await;\n\n        let mut db = ForkedDatabase::new(backend, db);\n        let address = Address::random();\n\n        let info = Database::basic(&mut db, address).unwrap();\n        assert!(info.is_some());\n        let mut info = info.unwrap();\n        info.balance = U256::from(500u64);\n\n        // insert the modified account info\n        db.database_mut().insert_account_info(address, info.clone());\n\n        let loaded = Database::basic(&mut db, address).unwrap();\n        assert!(loaded.is_some());\n        assert_eq!(loaded.unwrap(), info);\n    }\n}\n"
  },
  {
    "path": "crates/evm/core/src/fork/mod.rs",
    "content": "use super::opts::EvmOpts;\nuse alloy_evm::EvmEnv;\n\npub mod database;\n\nmod multi;\npub use multi::{ForkId, MultiFork, MultiForkHandler};\n\n/// Represents a _fork_ of a remote chain whose data is available only via the `url` endpoint.\n#[derive(Clone, Debug)]\npub struct CreateFork {\n    /// Whether to enable rpc storage caching for this fork\n    pub enable_caching: bool,\n    /// The URL to a node for fetching remote state\n    pub url: String,\n    /// The EVM environment for this fork (main purpose is to provide some block and cfg metadata).\n    pub evm_env: EvmEnv,\n    /// All env settings as configured by the user\n    pub evm_opts: EvmOpts,\n}\n"
  },
  {
    "path": "crates/evm/core/src/fork/multi.rs",
    "content": "//! Support for running multiple fork backends.\n//!\n//! The design is similar to the single `SharedBackend`, `BackendHandler` but supports multiple\n//! concurrently active pairs at once.\n\nuse super::CreateFork;\nuse alloy_evm::EvmEnv;\nuse alloy_network::Network;\nuse alloy_primitives::{U256, map::HashMap};\nuse foundry_config::Config;\nuse foundry_fork_db::{BackendHandler, BlockchainDb, SharedBackend, cache::BlockchainDbMeta};\nuse futures::{\n    FutureExt, StreamExt,\n    channel::mpsc::{Receiver, Sender, channel},\n    stream::Fuse,\n    task::{Context, Poll},\n};\nuse revm::context::BlockEnv;\nuse std::{\n    fmt::{self, Write},\n    pin::Pin,\n    sync::{\n        Arc,\n        atomic::AtomicUsize,\n        mpsc::{Sender as OneshotSender, channel as oneshot_channel},\n    },\n    time::Duration,\n};\n\n/// The _unique_ identifier for a specific fork, this could be the name of the network a custom\n/// descriptive name.\n#[derive(Clone, Debug, PartialEq, Eq, Hash)]\npub struct ForkId(pub String);\n\nimpl ForkId {\n    /// Returns the identifier for a Fork from a URL and block number.\n    pub fn new(url: &str, num: Option<u64>) -> Self {\n        let mut id = url.to_string();\n        id.push('@');\n        match num {\n            Some(n) => write!(id, \"{n:#x}\").unwrap(),\n            None => id.push_str(\"latest\"),\n        }\n        Self(id)\n    }\n\n    /// Returns the identifier of the fork.\n    pub fn as_str(&self) -> &str {\n        &self.0\n    }\n}\n\nimpl fmt::Display for ForkId {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        self.0.fmt(f)\n    }\n}\n\nimpl<T: Into<String>> From<T> for ForkId {\n    fn from(id: T) -> Self {\n        Self(id.into())\n    }\n}\n\n/// The Sender half of multi fork pair.\n/// Can send requests to the `MultiForkHandler` to create forks.\n#[derive(Clone, Debug)]\n#[must_use]\npub struct MultiFork<N: Network> {\n    /// Channel to send `Request`s to the handler.\n    handler: Sender<Request<N>>,\n    /// Ensures that all rpc resources get flushed properly.\n    _shutdown: Arc<ShutDownMultiFork<N>>,\n}\n\nimpl<N: Network> MultiFork<N> {\n    /// Creates a new pair and spawns the `MultiForkHandler` on a background thread.\n    pub fn spawn() -> Self {\n        trace!(target: \"fork::multi\", \"spawning multifork\");\n\n        let (fork, mut handler) = Self::new();\n\n        // Spawn a light-weight thread just for sending and receiving data from the remote\n        // client(s).\n        let fut = async move {\n            // Flush cache every 60s, this ensures that long-running fork tests get their\n            // cache flushed from time to time.\n            // NOTE: we install the interval here because the `tokio::timer::Interval`\n            // requires a rt.\n            handler.set_flush_cache_interval(Duration::from_secs(60));\n            handler.await\n        };\n        match tokio::runtime::Handle::try_current() {\n            Ok(rt) => _ = rt.spawn(fut),\n            Err(_) => {\n                trace!(target: \"fork::multi\", \"spawning multifork backend thread\");\n                _ = std::thread::Builder::new()\n                    .name(\"multi-fork-backend\".into())\n                    .spawn(move || {\n                        tokio::runtime::Builder::new_current_thread()\n                            .enable_all()\n                            .build()\n                            .expect(\"failed to build tokio runtime\")\n                            .block_on(fut)\n                    })\n                    .expect(\"failed to spawn thread\")\n            }\n        }\n\n        trace!(target: \"fork::multi\", \"spawned MultiForkHandler thread\");\n        fork\n    }\n\n    /// Creates a new pair multi fork pair.\n    ///\n    /// Use [`spawn`](Self::spawn) instead.\n    #[doc(hidden)]\n    pub fn new() -> (Self, MultiForkHandler<N>) {\n        let (handler, handler_rx) = channel(1);\n        let _shutdown = Arc::new(ShutDownMultiFork { handler: Some(handler.clone()) });\n        (Self { handler, _shutdown }, MultiForkHandler::new(handler_rx))\n    }\n\n    /// Returns a fork backend.\n    ///\n    /// If no matching fork backend exists it will be created.\n    pub fn create_fork(\n        &self,\n        fork: CreateFork,\n    ) -> eyre::Result<(ForkId, SharedBackend<N>, EvmEnv)> {\n        trace!(\"Creating new fork, url={}, block={:?}\", fork.url, fork.evm_opts.fork_block_number);\n        let (sender, rx) = oneshot_channel();\n        let req = Request::CreateFork(Box::new(fork), sender);\n        self.handler.clone().try_send(req).map_err(|e| eyre::eyre!(\"{:?}\", e))?;\n        rx.recv()?\n    }\n\n    /// Rolls the block of the fork.\n    ///\n    /// If no matching fork backend exists it will be created.\n    pub fn roll_fork(\n        &self,\n        fork: ForkId,\n        block: u64,\n    ) -> eyre::Result<(ForkId, SharedBackend<N>, EvmEnv)> {\n        trace!(?fork, ?block, \"rolling fork\");\n        let (sender, rx) = oneshot_channel();\n        let req = Request::RollFork(fork, block, sender);\n        self.handler.clone().try_send(req).map_err(|e| eyre::eyre!(\"{:?}\", e))?;\n        rx.recv()?\n    }\n\n    /// Returns the `EvmEnv` of the given fork, if any.\n    pub fn get_evm_env(&self, fork: ForkId) -> eyre::Result<Option<EvmEnv>> {\n        trace!(?fork, \"getting env config\");\n        let (sender, rx) = oneshot_channel();\n        let req = Request::GetEvmEnv(fork, sender);\n        self.handler.clone().try_send(req).map_err(|e| eyre::eyre!(\"{:?}\", e))?;\n        Ok(rx.recv()?)\n    }\n\n    /// Updates block number and timestamp of given fork with new values.\n    pub fn update_block(&self, fork: ForkId, number: U256, timestamp: U256) -> eyre::Result<()> {\n        trace!(?fork, ?number, ?timestamp, \"update fork block\");\n        self.handler\n            .clone()\n            .try_send(Request::UpdateBlock(fork, number, timestamp))\n            .map_err(|e| eyre::eyre!(\"{:?}\", e))\n    }\n\n    /// Updates the fork's entire env\n    ///\n    /// This is required for tx level forking where we need to fork off the `block - 1` state but\n    /// still need use env settings for `env`.\n    pub fn update_block_env(&self, fork: ForkId, env: BlockEnv) -> eyre::Result<()> {\n        trace!(?fork, ?env, \"update fork block\");\n        self.handler\n            .clone()\n            .try_send(Request::UpdateEnv(fork, env))\n            .map_err(|e| eyre::eyre!(\"{:?}\", e))\n    }\n\n    /// Returns the corresponding fork if it exists.\n    ///\n    /// Returns `None` if no matching fork backend is available.\n    pub fn get_fork(&self, id: impl Into<ForkId>) -> eyre::Result<Option<SharedBackend<N>>> {\n        let id = id.into();\n        trace!(?id, \"get fork backend\");\n        let (sender, rx) = oneshot_channel();\n        let req = Request::GetFork(id, sender);\n        self.handler.clone().try_send(req).map_err(|e| eyre::eyre!(\"{:?}\", e))?;\n        Ok(rx.recv()?)\n    }\n\n    /// Returns the corresponding fork url if it exists.\n    ///\n    /// Returns `None` if no matching fork is available.\n    pub fn get_fork_url(&self, id: impl Into<ForkId>) -> eyre::Result<Option<String>> {\n        let (sender, rx) = oneshot_channel();\n        let req = Request::GetForkUrl(id.into(), sender);\n        self.handler.clone().try_send(req).map_err(|e| eyre::eyre!(\"{:?}\", e))?;\n        Ok(rx.recv()?)\n    }\n}\n\ntype CreateFuture<N> =\n    Pin<Box<dyn Future<Output = eyre::Result<(ForkId, CreatedFork<N>, BackendHandler<N>)>> + Send>>;\ntype CreateSender<N> = OneshotSender<eyre::Result<(ForkId, SharedBackend<N>, EvmEnv)>>;\ntype GetEvmEnvSender = OneshotSender<Option<EvmEnv>>;\n\n/// Request that's send to the handler.\n#[derive(Debug)]\nenum Request<N: Network> {\n    /// Creates a new ForkBackend.\n    CreateFork(Box<CreateFork>, CreateSender<N>),\n    /// Returns the Fork backend for the `ForkId` if it exists.\n    GetFork(ForkId, OneshotSender<Option<SharedBackend<N>>>),\n    /// Adjusts the block that's being forked, by creating a new fork at the new block.\n    RollFork(ForkId, u64, CreateSender<N>),\n    /// Returns the environment of the fork.\n    GetEvmEnv(ForkId, GetEvmEnvSender),\n    /// Updates the block number and timestamp of the fork.\n    UpdateBlock(ForkId, U256, U256),\n    /// Updates the block the entire block env,\n    UpdateEnv(ForkId, BlockEnv),\n    /// Shutdowns the entire `MultiForkHandler`, see `ShutDownMultiFork`\n    ShutDown(OneshotSender<()>),\n    /// Returns the Fork Url for the `ForkId` if it exists.\n    GetForkUrl(ForkId, OneshotSender<Option<String>>),\n}\n\nenum ForkTask<N: Network> {\n    /// Contains the future that will establish a new fork.\n    Create(CreateFuture<N>, ForkId, CreateSender<N>, Vec<CreateSender<N>>),\n}\n\n/// The type that manages connections in the background.\n#[must_use = \"futures do nothing unless polled\"]\npub struct MultiForkHandler<N: Network> {\n    /// Incoming requests from the `MultiFork`.\n    incoming: Fuse<Receiver<Request<N>>>,\n\n    /// All active handlers.\n    ///\n    /// It's expected that this list will be rather small (<10).\n    handlers: Vec<(ForkId, BackendHandler<N>)>,\n\n    // tasks currently in progress\n    pending_tasks: Vec<ForkTask<N>>,\n\n    /// All _unique_ forkids mapped to their corresponding backend.\n    ///\n    /// Note: The backend can be shared by multiple ForkIds if the target the same provider and\n    /// block number.\n    forks: HashMap<ForkId, CreatedFork<N>>,\n\n    /// Optional periodic interval to flush rpc cache.\n    flush_cache_interval: Option<tokio::time::Interval>,\n}\n\nimpl<N: Network> MultiForkHandler<N> {\n    fn new(incoming: Receiver<Request<N>>) -> Self {\n        Self {\n            incoming: incoming.fuse(),\n            handlers: Default::default(),\n            pending_tasks: Default::default(),\n            forks: Default::default(),\n            flush_cache_interval: None,\n        }\n    }\n\n    /// Sets the interval after which all rpc caches should be flushed periodically.\n    pub fn set_flush_cache_interval(&mut self, period: Duration) -> &mut Self {\n        self.flush_cache_interval =\n            Some(tokio::time::interval_at(tokio::time::Instant::now() + period, period));\n        self\n    }\n\n    /// Returns the list of additional senders of a matching task for the given id, if any.\n    fn find_in_progress_task(&mut self, id: &ForkId) -> Option<&mut Vec<CreateSender<N>>> {\n        for ForkTask::Create(_, in_progress, _, additional) in &mut self.pending_tasks {\n            if in_progress == id {\n                return Some(additional);\n            }\n        }\n        None\n    }\n\n    fn create_fork(&mut self, fork: CreateFork, sender: CreateSender<N>) {\n        let fork_id = ForkId::new(&fork.url, fork.evm_opts.fork_block_number);\n        trace!(?fork_id, \"created new forkId\");\n\n        // There could already be a task for the requested fork in progress.\n        if let Some(in_progress) = self.find_in_progress_task(&fork_id) {\n            in_progress.push(sender);\n            return;\n        }\n\n        // Need to create a new fork.\n        let task = Box::pin(create_fork(fork));\n        self.pending_tasks.push(ForkTask::Create(task, fork_id, sender, Vec::new()));\n    }\n\n    fn insert_new_fork(\n        &mut self,\n        fork_id: ForkId,\n        fork: CreatedFork<N>,\n        sender: CreateSender<N>,\n        additional_senders: Vec<CreateSender<N>>,\n    ) {\n        self.forks.insert(fork_id.clone(), fork.clone());\n        let _ = sender.send(Ok((fork_id.clone(), fork.backend.clone(), fork.opts.evm_env.clone())));\n\n        // Notify all additional senders and track unique forkIds.\n        for sender in additional_senders {\n            let next_fork_id = fork.inc_senders(fork_id.clone());\n            self.forks.insert(next_fork_id.clone(), fork.clone());\n            let _ =\n                sender.send(Ok((next_fork_id, fork.backend.clone(), fork.opts.evm_env.clone())));\n        }\n    }\n\n    /// Update the fork's block entire env\n    fn update_env(&mut self, fork_id: ForkId, env: BlockEnv) {\n        if let Some(fork) = self.forks.get_mut(&fork_id) {\n            fork.opts.evm_env.block_env = env;\n        }\n    }\n    /// Update fork block number and timestamp. Used to preserve values set by `roll` and `warp`\n    /// cheatcodes when new fork selected.\n    fn update_block(&mut self, fork_id: ForkId, block_number: U256, block_timestamp: U256) {\n        if let Some(fork) = self.forks.get_mut(&fork_id) {\n            fork.opts.evm_env.block_env.number = block_number;\n            fork.opts.evm_env.block_env.timestamp = block_timestamp;\n        }\n    }\n\n    fn on_request(&mut self, req: Request<N>) {\n        match req {\n            Request::CreateFork(fork, sender) => self.create_fork(*fork, sender),\n            Request::GetFork(fork_id, sender) => {\n                let fork = self.forks.get(&fork_id).map(|f| f.backend.clone());\n                let _ = sender.send(fork);\n            }\n            Request::RollFork(fork_id, block, sender) => {\n                if let Some(fork) = self.forks.get(&fork_id) {\n                    trace!(target: \"fork::multi\", \"rolling {} to {}\", fork_id, block);\n                    let mut opts = fork.opts.clone();\n                    opts.evm_opts.fork_block_number = Some(block);\n                    self.create_fork(opts, sender)\n                } else {\n                    let _ =\n                        sender.send(Err(eyre::eyre!(\"No matching fork exists for {}\", fork_id)));\n                }\n            }\n            Request::GetEvmEnv(fork_id, sender) => {\n                let _ = sender.send(self.forks.get(&fork_id).map(|fork| fork.opts.evm_env.clone()));\n            }\n            Request::UpdateBlock(fork_id, block_number, block_timestamp) => {\n                self.update_block(fork_id, block_number, block_timestamp);\n            }\n            Request::UpdateEnv(fork_id, block_env) => {\n                self.update_env(fork_id, block_env);\n            }\n            Request::ShutDown(sender) => {\n                trace!(target: \"fork::multi\", \"received shutdown signal\");\n                // We're emptying all fork backends, this way we ensure all caches get flushed.\n                self.forks.clear();\n                self.handlers.clear();\n                let _ = sender.send(());\n            }\n            Request::GetForkUrl(fork_id, sender) => {\n                let fork = self.forks.get(&fork_id).map(|f| f.opts.url.clone());\n                let _ = sender.send(fork);\n            }\n        }\n    }\n}\n\n// Drives all handler to completion.\n// This future will finish once all underlying BackendHandler are completed.\nimpl<N: Network> Future for MultiForkHandler<N> {\n    type Output = ();\n\n    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {\n        let this = self.get_mut();\n\n        // Receive new requests.\n        loop {\n            match this.incoming.poll_next_unpin(cx) {\n                Poll::Ready(Some(req)) => this.on_request(req),\n                Poll::Ready(None) => {\n                    // Channel closed, but we still need to drive the fork handlers to completion.\n                    trace!(target: \"fork::multi\", \"request channel closed\");\n                    break;\n                }\n                Poll::Pending => break,\n            }\n        }\n\n        // Advance all tasks.\n        for n in (0..this.pending_tasks.len()).rev() {\n            let task = this.pending_tasks.swap_remove(n);\n            match task {\n                ForkTask::Create(mut fut, id, sender, additional_senders) => {\n                    if let Poll::Ready(resp) = fut.poll_unpin(cx) {\n                        match resp {\n                            Ok((fork_id, fork, handler)) => {\n                                if let Some(fork) = this.forks.get(&fork_id).cloned() {\n                                    this.insert_new_fork(\n                                        fork.inc_senders(fork_id),\n                                        fork,\n                                        sender,\n                                        additional_senders,\n                                    );\n                                } else {\n                                    this.handlers.push((fork_id.clone(), handler));\n                                    this.insert_new_fork(fork_id, fork, sender, additional_senders);\n                                }\n                            }\n                            Err(err) => {\n                                let _ = sender.send(Err(eyre::eyre!(\"{err}\")));\n                                for sender in additional_senders {\n                                    let _ = sender.send(Err(eyre::eyre!(\"{err}\")));\n                                }\n                            }\n                        }\n                    } else {\n                        this.pending_tasks.push(ForkTask::Create(\n                            fut,\n                            id,\n                            sender,\n                            additional_senders,\n                        ));\n                    }\n                }\n            }\n        }\n\n        // Advance all handlers.\n        for n in (0..this.handlers.len()).rev() {\n            let (id, mut handler) = this.handlers.swap_remove(n);\n            match handler.poll_unpin(cx) {\n                Poll::Ready(_) => {\n                    trace!(target: \"fork::multi\", \"fork {:?} completed\", id);\n                }\n                Poll::Pending => {\n                    this.handlers.push((id, handler));\n                }\n            }\n        }\n\n        if this.handlers.is_empty() && this.incoming.is_done() {\n            trace!(target: \"fork::multi\", \"completed\");\n            return Poll::Ready(());\n        }\n\n        // Periodically flush cached RPC state.\n        if this\n            .flush_cache_interval\n            .as_mut()\n            .map(|interval| interval.poll_tick(cx).is_ready())\n            .unwrap_or_default()\n            && !this.forks.is_empty()\n        {\n            trace!(target: \"fork::multi\", \"tick flushing caches\");\n            let forks = this.forks.values().map(|f| f.backend.clone()).collect::<Vec<_>>();\n            // Flush this on new thread to not block here.\n            std::thread::Builder::new()\n                .name(\"flusher\".into())\n                .spawn(move || {\n                    forks.into_iter().for_each(|fork| fork.flush_cache());\n                })\n                .expect(\"failed to spawn thread\");\n        }\n\n        Poll::Pending\n    }\n}\n\n/// Tracks the created Fork\n#[derive(Debug, Clone)]\nstruct CreatedFork<N: Network> {\n    /// How the fork was initially created.\n    opts: CreateFork,\n    /// Copy of the sender.\n    backend: SharedBackend<N>,\n    /// How many consumers there are, since a `SharedBacked` can be used by multiple\n    /// consumers.\n    num_senders: Arc<AtomicUsize>,\n}\n\nimpl<N: Network> CreatedFork<N> {\n    pub fn new(opts: CreateFork, backend: SharedBackend<N>) -> Self {\n        Self { opts, backend, num_senders: Arc::new(AtomicUsize::new(1)) }\n    }\n\n    /// Increment senders and return unique identifier of the fork.\n    fn inc_senders(&self, fork_id: ForkId) -> ForkId {\n        format!(\n            \"{}-{}\",\n            fork_id.as_str(),\n            self.num_senders.fetch_add(1, std::sync::atomic::Ordering::Relaxed)\n        )\n        .into()\n    }\n}\n\n/// A type that's used to signaling the `MultiForkHandler` when it's time to shut down.\n///\n/// This is essentially a sync on drop, so that the `MultiForkHandler` can flush all rpc cashes.\n///\n/// This type intentionally does not implement `Clone` since it's intended that there's only once\n/// instance.\n#[derive(Debug)]\nstruct ShutDownMultiFork<N: Network> {\n    handler: Option<Sender<Request<N>>>,\n}\n\nimpl<N: Network> Drop for ShutDownMultiFork<N> {\n    fn drop(&mut self) {\n        trace!(target: \"fork::multi\", \"initiating shutdown\");\n        let (sender, rx) = oneshot_channel();\n        let req = Request::ShutDown(sender);\n        if let Some(mut handler) = self.handler.take()\n            && handler.try_send(req).is_ok()\n        {\n            let _ = rx.recv();\n            trace!(target: \"fork::cache\", \"multifork backend shutdown\");\n        }\n    }\n}\n\n/// Creates a new fork.\n///\n/// This will establish a new `Provider` to the endpoint and return the Fork Backend.\nasync fn create_fork<N: Network>(\n    mut fork: CreateFork,\n) -> eyre::Result<(ForkId, CreatedFork<N>, BackendHandler<N>)> {\n    // Ensure evm_opts reflects the fork URL (may differ from the resolved CreateFork url when\n    // created via cheatcodes, where evm_opts is cloned from the base config).\n    fork.evm_opts.fork_url = Some(fork.url.clone());\n\n    let provider = fork.evm_opts.fork_provider_with_url::<N>(&fork.url)?;\n\n    // Initialise the fork environment.\n    let (evm_env, number) = fork.evm_opts.fork_evm_env(&provider).await?;\n    fork.evm_env = evm_env;\n    let meta = BlockchainDbMeta::new(fork.evm_env.block_env.clone(), fork.url.clone());\n\n    // Determine the cache path if caching is enabled.\n    let cache_path = if fork.enable_caching {\n        Config::foundry_block_cache_dir(fork.evm_env.cfg_env.chain_id, number)\n    } else {\n        None\n    };\n\n    let db = BlockchainDb::new(meta, cache_path);\n    let (backend, handler) = SharedBackend::new(provider, db, Some(number.into()));\n    let fork = CreatedFork::new(fork, backend);\n    let fork_id = ForkId::new(&fork.opts.url, Some(number));\n\n    Ok((fork_id, fork, handler))\n}\n"
  },
  {
    "path": "crates/evm/core/src/hardfork.rs",
    "content": "use alloy_rpc_types::BlockNumberOrTag;\nuse op_revm::OpSpecId;\nuse revm::primitives::hardfork::SpecId;\n\npub use alloy_hardforks::EthereumHardfork;\npub use alloy_op_hardforks::OpHardfork;\n\n#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]\npub enum FoundryHardfork {\n    Ethereum(EthereumHardfork),\n    Optimism(OpHardfork),\n}\n\nimpl FoundryHardfork {\n    pub fn ethereum(h: EthereumHardfork) -> Self {\n        Self::Ethereum(h)\n    }\n\n    pub fn optimism(h: OpHardfork) -> Self {\n        Self::Optimism(h)\n    }\n}\n\nimpl From<EthereumHardfork> for FoundryHardfork {\n    fn from(value: EthereumHardfork) -> Self {\n        Self::Ethereum(value)\n    }\n}\n\nimpl From<OpHardfork> for FoundryHardfork {\n    fn from(value: OpHardfork) -> Self {\n        Self::Optimism(value)\n    }\n}\n\nimpl From<FoundryHardfork> for SpecId {\n    fn from(fork: FoundryHardfork) -> Self {\n        match fork {\n            FoundryHardfork::Ethereum(hardfork) => spec_id_from_ethereum_hardfork(hardfork),\n            FoundryHardfork::Optimism(hardfork) => spec_id_from_optimism_hardfork(hardfork).into(),\n        }\n    }\n}\n\n/// Map an EthereumHardfork enum into its corresponding SpecId.\npub fn spec_id_from_ethereum_hardfork(hardfork: EthereumHardfork) -> SpecId {\n    match hardfork {\n        EthereumHardfork::Frontier => SpecId::FRONTIER,\n        EthereumHardfork::Homestead => SpecId::HOMESTEAD,\n        EthereumHardfork::Dao => SpecId::DAO_FORK,\n        EthereumHardfork::Tangerine => SpecId::TANGERINE,\n        EthereumHardfork::SpuriousDragon => SpecId::SPURIOUS_DRAGON,\n        EthereumHardfork::Byzantium => SpecId::BYZANTIUM,\n        EthereumHardfork::Constantinople => SpecId::CONSTANTINOPLE,\n        EthereumHardfork::Petersburg => SpecId::PETERSBURG,\n        EthereumHardfork::Istanbul => SpecId::ISTANBUL,\n        EthereumHardfork::MuirGlacier => SpecId::MUIR_GLACIER,\n        EthereumHardfork::Berlin => SpecId::BERLIN,\n        EthereumHardfork::London => SpecId::LONDON,\n        EthereumHardfork::ArrowGlacier => SpecId::ARROW_GLACIER,\n        EthereumHardfork::GrayGlacier => SpecId::GRAY_GLACIER,\n        EthereumHardfork::Paris => SpecId::MERGE,\n        EthereumHardfork::Shanghai => SpecId::SHANGHAI,\n        EthereumHardfork::Cancun => SpecId::CANCUN,\n        EthereumHardfork::Prague => SpecId::PRAGUE,\n        EthereumHardfork::Osaka => SpecId::OSAKA,\n        EthereumHardfork::Bpo1 | EthereumHardfork::Bpo2 => SpecId::OSAKA,\n        EthereumHardfork::Bpo3 | EthereumHardfork::Bpo4 | EthereumHardfork::Bpo5 => {\n            unimplemented!()\n        }\n        f => unreachable!(\"unimplemented {}\", f),\n    }\n}\n\n/// Map an OptimismHardfork enum into its corresponding OpSpecId.\npub fn spec_id_from_optimism_hardfork(hardfork: OpHardfork) -> OpSpecId {\n    match hardfork {\n        OpHardfork::Bedrock => OpSpecId::BEDROCK,\n        OpHardfork::Regolith => OpSpecId::REGOLITH,\n        OpHardfork::Canyon => OpSpecId::CANYON,\n        OpHardfork::Ecotone => OpSpecId::ECOTONE,\n        OpHardfork::Fjord => OpSpecId::FJORD,\n        OpHardfork::Granite => OpSpecId::GRANITE,\n        OpHardfork::Holocene => OpSpecId::HOLOCENE,\n        OpHardfork::Isthmus => OpSpecId::ISTHMUS,\n        OpHardfork::Interop => OpSpecId::INTEROP,\n        OpHardfork::Jovian => OpSpecId::JOVIAN,\n        f => unreachable!(\"unimplemented {}\", f),\n    }\n}\n\n/// Convert a `BlockNumberOrTag` into an `EthereumHardfork`.\npub fn ethereum_hardfork_from_block_tag(block: impl Into<BlockNumberOrTag>) -> EthereumHardfork {\n    let num = match block.into() {\n        BlockNumberOrTag::Earliest => 0,\n        BlockNumberOrTag::Number(num) => num,\n        _ => u64::MAX,\n    };\n\n    EthereumHardfork::from_mainnet_block_number(num)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use alloy_hardforks::ethereum::mainnet::*;\n\n    #[test]\n    fn test_ethereum_spec_id_mapping() {\n        assert_eq!(spec_id_from_ethereum_hardfork(EthereumHardfork::Frontier), SpecId::FRONTIER);\n        assert_eq!(spec_id_from_ethereum_hardfork(EthereumHardfork::Homestead), SpecId::HOMESTEAD);\n\n        // Test latest hardforks\n        assert_eq!(spec_id_from_ethereum_hardfork(EthereumHardfork::Cancun), SpecId::CANCUN);\n        assert_eq!(spec_id_from_ethereum_hardfork(EthereumHardfork::Prague), SpecId::PRAGUE);\n        assert_eq!(spec_id_from_ethereum_hardfork(EthereumHardfork::Osaka), SpecId::OSAKA);\n    }\n\n    #[test]\n    fn test_optimism_spec_id_mapping() {\n        assert_eq!(spec_id_from_optimism_hardfork(OpHardfork::Bedrock), OpSpecId::BEDROCK);\n        assert_eq!(spec_id_from_optimism_hardfork(OpHardfork::Regolith), OpSpecId::REGOLITH);\n\n        // Test latest hardforks\n        assert_eq!(spec_id_from_optimism_hardfork(OpHardfork::Holocene), OpSpecId::HOLOCENE);\n        assert_eq!(spec_id_from_optimism_hardfork(OpHardfork::Interop), OpSpecId::INTEROP);\n    }\n\n    #[test]\n    fn test_hardfork_from_block_tag_numbers() {\n        assert_eq!(\n            ethereum_hardfork_from_block_tag(MAINNET_HOMESTEAD_BLOCK - 1),\n            EthereumHardfork::Frontier\n        );\n        assert_eq!(\n            ethereum_hardfork_from_block_tag(MAINNET_LONDON_BLOCK + 1),\n            EthereumHardfork::London\n        );\n    }\n}\n"
  },
  {
    "path": "crates/evm/core/src/ic.rs",
    "content": "use crate::bytecode::InstIter;\nuse alloy_primitives::map::rustc_hash::FxHashMap;\nuse serde::Serialize;\n\n/// Maps from program counter to instruction counter.\n///\n/// Inverse of [`IcPcMap`].\n#[derive(Debug, Clone, Serialize)]\n#[serde(transparent)]\npub struct PcIcMap {\n    inner: FxHashMap<u32, u32>,\n}\n\nimpl PcIcMap {\n    /// Creates a new `PcIcMap` for the given code.\n    pub fn new(code: &[u8]) -> Self {\n        Self { inner: make_map::<true>(code) }\n    }\n\n    /// Returns the length of the map.\n    pub fn len(&self) -> usize {\n        self.inner.len()\n    }\n\n    /// Returns `true` if the map is empty.\n    pub fn is_empty(&self) -> bool {\n        self.inner.is_empty()\n    }\n\n    /// Returns the instruction counter for the given program counter.\n    pub fn get(&self, pc: u32) -> Option<u32> {\n        self.inner.get(&pc).copied()\n    }\n}\n\n/// Map from instruction counter to program counter.\n///\n/// Inverse of [`PcIcMap`].\npub struct IcPcMap {\n    inner: FxHashMap<u32, u32>,\n}\n\nimpl IcPcMap {\n    /// Creates a new `IcPcMap` for the given code.\n    pub fn new(code: &[u8]) -> Self {\n        Self { inner: make_map::<false>(code) }\n    }\n\n    /// Returns the length of the map.\n    pub fn len(&self) -> usize {\n        self.inner.len()\n    }\n\n    /// Returns `true` if the map is empty.\n    pub fn is_empty(&self) -> bool {\n        self.inner.is_empty()\n    }\n\n    /// Returns the program counter for the given instruction counter.\n    pub fn get(&self, ic: u32) -> Option<u32> {\n        self.inner.get(&ic).copied()\n    }\n\n    /// Iterate over the IC-PC pairs.\n    pub fn iter(&self) -> impl Iterator<Item = (&u32, &u32)> {\n        self.inner.iter()\n    }\n}\n\nfn make_map<const PC_FIRST: bool>(code: &[u8]) -> FxHashMap<u32, u32> {\n    assert!(code.len() <= u32::MAX as usize, \"bytecode is too big\");\n    let mut map = FxHashMap::with_capacity_and_hasher(code.len(), Default::default());\n    for (ic, (pc, _)) in InstIter::new(code).with_pc().enumerate() {\n        if PC_FIRST {\n            map.insert(pc as u32, ic as u32);\n        } else {\n            map.insert(ic as u32, pc as u32);\n        }\n    }\n    map.shrink_to_fit();\n    map\n}\n"
  },
  {
    "path": "crates/evm/core/src/lib.rs",
    "content": "//! # foundry-evm-core\n//!\n//! Core EVM abstractions.\n\n#![cfg_attr(not(test), warn(unused_crate_dependencies))]\n#![cfg_attr(docsrs, feature(doc_cfg))]\n\nuse crate::constants::DEFAULT_CREATE2_DEPLOYER;\nuse alloy_primitives::{Address, map::HashMap};\nuse auto_impl::auto_impl;\nuse backend::DatabaseExt;\nuse revm::{\n    Context, Inspector,\n    context::{BlockEnv, CfgEnv, TxEnv},\n    inspector::NoOpInspector,\n    interpreter::CreateInputs,\n    primitives::hardfork::SpecId,\n};\nuse revm_inspectors::access_list::AccessListInspector;\n\n/// Map keyed by breakpoints char to their location (contract address, pc)\npub type Breakpoints = HashMap<char, (Address, usize)>;\n\n#[macro_use]\nextern crate tracing;\n\npub mod abi {\n    pub use foundry_cheatcodes_spec::Vm;\n    pub use foundry_evm_abi::*;\n}\n\npub mod env;\npub use env::*;\nuse foundry_evm_networks::NetworkConfigs;\n\npub mod backend;\npub mod buffer;\npub mod bytecode;\npub mod constants;\npub mod decode;\npub mod either_evm;\npub mod evm;\npub mod fork;\npub mod hardfork;\npub mod ic;\npub mod opts;\npub mod precompiles;\npub mod state_snapshot;\npub mod utils;\n\n/// Foundry-specific inspector methods, decoupled from any particular EVM context type.\n///\n/// This trait holds Foundry-specific extensions (create2 factory, console logging,\n/// network config, deployer address). It has no `Inspector<CTX>` supertrait so it can\n/// be used in generic code with `I: FoundryInspectorExt + Inspector<CTX>`.\n#[auto_impl(&mut, Box)]\npub trait FoundryInspectorExt {\n    /// Determines whether the `DEFAULT_CREATE2_DEPLOYER` should be used for a CREATE2 frame.\n    ///\n    /// If this function returns true, we'll replace CREATE2 frame with a CALL frame to CREATE2\n    /// factory.\n    fn should_use_create2_factory(&mut self, _depth: usize, _inputs: &CreateInputs) -> bool {\n        false\n    }\n\n    /// Simulates `console.log` invocation.\n    fn console_log(&mut self, msg: &str) {\n        let _ = msg;\n    }\n\n    /// Returns configured networks.\n    fn get_networks(&self) -> NetworkConfigs {\n        NetworkConfigs::default()\n    }\n\n    /// Returns the CREATE2 deployer address.\n    fn create2_deployer(&self) -> Address {\n        DEFAULT_CREATE2_DEPLOYER\n    }\n}\n\n/// Combined trait: `Inspector<Context<...>>` + [`FoundryInspectorExt`].\n///\n/// For generic multi-network code, use `I: FoundryInspectorExt + Inspector<CTX>` instead.\npub trait EthInspectorExt<BLOCK = BlockEnv, TX = TxEnv, SPEC = SpecId>:\n    for<'a> Inspector<Context<BLOCK, TX, CfgEnv<SPEC>, &'a mut dyn DatabaseExt>> + FoundryInspectorExt\n{\n}\n\nimpl<BLOCK, TX, SPEC, T> EthInspectorExt<BLOCK, TX, SPEC> for T where\n    T: for<'a> Inspector<Context<BLOCK, TX, CfgEnv<SPEC>, &'a mut dyn DatabaseExt>>\n        + FoundryInspectorExt\n{\n}\n\nimpl FoundryInspectorExt for NoOpInspector {}\n\nimpl FoundryInspectorExt for AccessListInspector {}\n"
  },
  {
    "path": "crates/evm/core/src/opts.rs",
    "content": "use crate::{\n    EvmEnv,\n    constants::DEFAULT_CREATE2_DEPLOYER,\n    fork::CreateFork,\n    utils::{apply_chain_and_block_specific_env_changes, block_env_from_header},\n};\nuse alloy_consensus::BlockHeader;\nuse alloy_network::{AnyNetwork, BlockResponse, Network};\nuse alloy_primitives::{Address, B256, BlockNumber, ChainId, U256};\nuse alloy_provider::{Provider, RootProvider};\nuse alloy_rpc_types::BlockNumberOrTag;\nuse eyre::WrapErr;\nuse foundry_common::{ALCHEMY_FREE_TIER_CUPS, NON_ARCHIVE_NODE_WARNING, provider::ProviderBuilder};\nuse foundry_config::{Chain, Config, GasLimit};\nuse foundry_evm_networks::NetworkConfigs;\nuse revm::context::{BlockEnv, CfgEnv, TxEnv};\nuse serde::{Deserialize, Serialize};\nuse std::fmt::Write;\nuse url::Url;\n\n#[derive(Clone, Debug, Serialize, Deserialize)]\npub struct EvmOpts {\n    /// The EVM environment configuration.\n    #[serde(flatten)]\n    pub env: Env,\n\n    /// Fetch state over a remote instead of starting from empty state.\n    #[serde(rename = \"eth_rpc_url\")]\n    pub fork_url: Option<String>,\n\n    /// Pins the block number for the state fork.\n    pub fork_block_number: Option<u64>,\n\n    /// The number of retries.\n    pub fork_retries: Option<u32>,\n\n    /// Initial retry backoff.\n    pub fork_retry_backoff: Option<u64>,\n\n    /// Headers to use with `fork_url`\n    pub fork_headers: Option<Vec<String>>,\n\n    /// The available compute units per second.\n    ///\n    /// See also <https://docs.alchemy.com/reference/compute-units#what-are-cups-compute-units-per-second>\n    pub compute_units_per_second: Option<u64>,\n\n    /// Disables RPC rate limiting entirely.\n    pub no_rpc_rate_limit: bool,\n\n    /// Disables storage caching entirely.\n    pub no_storage_caching: bool,\n\n    /// The initial balance of each deployed test contract.\n    pub initial_balance: U256,\n\n    /// The address which will be executing all tests.\n    pub sender: Address,\n\n    /// Enables the FFI cheatcode.\n    pub ffi: bool,\n\n    /// Use the create 2 factory in all cases including tests and non-broadcasting scripts.\n    pub always_use_create_2_factory: bool,\n\n    /// Verbosity mode of EVM output as number of occurrences.\n    pub verbosity: u8,\n\n    /// The memory limit per EVM execution in bytes.\n    /// If this limit is exceeded, a `MemoryLimitOOG` result is thrown.\n    pub memory_limit: u64,\n\n    /// Whether to enable isolation of calls.\n    pub isolate: bool,\n\n    /// Whether to disable block gas limit checks.\n    pub disable_block_gas_limit: bool,\n\n    /// Whether to enable tx gas limit checks as imposed by Osaka (EIP-7825).\n    pub enable_tx_gas_limit: bool,\n\n    #[serde(flatten)]\n    /// Networks with enabled features.\n    pub networks: NetworkConfigs,\n\n    /// The CREATE2 deployer's address.\n    pub create2_deployer: Address,\n}\n\nimpl Default for EvmOpts {\n    fn default() -> Self {\n        Self {\n            env: Env::default(),\n            fork_url: None,\n            fork_block_number: None,\n            fork_retries: None,\n            fork_retry_backoff: None,\n            fork_headers: None,\n            compute_units_per_second: None,\n            no_rpc_rate_limit: false,\n            no_storage_caching: false,\n            initial_balance: U256::default(),\n            sender: Address::default(),\n            ffi: false,\n            always_use_create_2_factory: false,\n            verbosity: 0,\n            memory_limit: 0,\n            isolate: false,\n            disable_block_gas_limit: false,\n            enable_tx_gas_limit: false,\n            networks: NetworkConfigs::default(),\n            create2_deployer: DEFAULT_CREATE2_DEPLOYER,\n        }\n    }\n}\n\nimpl EvmOpts {\n    /// Returns a `RootProvider` for the given fork URL configured with options in `self` and\n    /// annotated `Network` type.\n    pub fn fork_provider_with_url<N: Network>(\n        &self,\n        fork_url: &str,\n    ) -> eyre::Result<RootProvider<N>> {\n        ProviderBuilder::new(fork_url)\n            .maybe_max_retry(self.fork_retries)\n            .maybe_initial_backoff(self.fork_retry_backoff)\n            .maybe_headers(self.fork_headers.clone())\n            .compute_units_per_second(self.get_compute_units_per_second())\n            .build()\n    }\n\n    /// Returns a tuple with [`EvmEnv`] and [`TxEnv`]\n    ///\n    /// If a `fork_url` is set, creates a provider and passes it to both `EvmOpts::fork_evm_env`\n    /// and `EvmOpts::fork_tx_env`. Falls back to local settings when no fork URL is configured.\n    pub async fn env(&self) -> eyre::Result<(EvmEnv, TxEnv)> {\n        if let Some(ref fork_url) = self.fork_url {\n            let provider = self.fork_provider_with_url::<AnyNetwork>(fork_url)?;\n            let ((evm_env, _block), tx) =\n                tokio::try_join!(self.fork_evm_env(&provider), self.fork_tx_env(&provider))?;\n            Ok((evm_env, tx))\n        } else {\n            Ok((self.local_evm_env(), self.local_tx_env()))\n        }\n    }\n\n    /// Returns the [`EvmEnv`] (cfg + block) and [`BlockNumber`] fetched from the fork endpoint via\n    /// provider\n    pub async fn fork_evm_env<N: Network, P: Provider<N>>(\n        &self,\n        provider: &P,\n    ) -> eyre::Result<(EvmEnv, BlockNumber)> {\n        trace!(\n            memory_limit = %self.memory_limit,\n            override_chain_id = ?self.env.chain_id,\n            pin_block = ?self.fork_block_number,\n            origin = %self.sender,\n            disable_block_gas_limit = %self.disable_block_gas_limit,\n            enable_tx_gas_limit = %self.enable_tx_gas_limit,\n            configs = ?self.networks,\n            \"creating fork environment\"\n        );\n\n        let bn = match self.fork_block_number {\n            Some(bn) => BlockNumberOrTag::Number(bn),\n            None => BlockNumberOrTag::Latest,\n        };\n\n        let (chain_id, block) = tokio::try_join!(\n            option_try_or_else(self.env.chain_id, async || provider.get_chain_id().await),\n            provider.get_block_by_number(bn)\n        )\n        .wrap_err_with(|| {\n            let mut msg = \"could not instantiate forked environment\".to_string();\n            if let Some(fork_url) = self.fork_url.as_deref()\n                && let Ok(url) = Url::parse(fork_url)\n                && let Some(host) = url.host()\n            {\n                write!(msg, \" with provider {host}\").unwrap();\n            }\n            msg\n        })?;\n\n        let Some(block) = block else {\n            let bn_msg = match bn {\n                BlockNumberOrTag::Number(bn) => format!(\"block number: {bn}\"),\n                bn => format!(\"{bn} block\"),\n            };\n            let latest_msg = if let Ok(latest_block) = provider.get_block_number().await {\n                if let Some(block_number) = self.fork_block_number\n                    && block_number <= latest_block\n                {\n                    error!(\"{NON_ARCHIVE_NODE_WARNING}\");\n                }\n                format!(\"; latest block number: {latest_block}\")\n            } else {\n                Default::default()\n            };\n            eyre::bail!(\"failed to get {bn_msg}{latest_msg}\");\n        };\n\n        let block_number = block.header().number();\n        let mut evm_env = EvmEnv {\n            cfg_env: self.cfg_env(chain_id),\n            block_env: block_env_from_header(block.header()),\n        };\n\n        apply_chain_and_block_specific_env_changes::<N>(&mut evm_env, &block, self.networks);\n\n        Ok((evm_env, block_number))\n    }\n\n    /// Returns the [`EvmEnv`] configured with only local settings.\n    fn local_evm_env(&self) -> EvmEnv {\n        let gas_limit = self.gas_limit();\n        EvmEnv {\n            cfg_env: self.cfg_env(self.env.chain_id.unwrap_or(foundry_common::DEV_CHAIN_ID)),\n            block_env: BlockEnv {\n                number: self.env.block_number,\n                beneficiary: self.env.block_coinbase,\n                timestamp: self.env.block_timestamp,\n                difficulty: U256::from(self.env.block_difficulty),\n                prevrandao: Some(self.env.block_prevrandao),\n                basefee: self.env.block_base_fee_per_gas,\n                gas_limit,\n                ..Default::default()\n            },\n        }\n    }\n\n    /// Returns the [`TxEnv`] with gas price and chain id resolved from provider.\n    async fn fork_tx_env<N: Network, P: Provider<N>>(&self, provider: &P) -> eyre::Result<TxEnv> {\n        let (gas_price, chain_id) = tokio::try_join!(\n            option_try_or_else(self.env.gas_price.map(|v| v as u128), async || {\n                provider.get_gas_price().await\n            }),\n            option_try_or_else(self.env.chain_id, async || provider.get_chain_id().await),\n        )?;\n        Ok(TxEnv {\n            caller: self.sender,\n            gas_price,\n            chain_id: Some(chain_id),\n            gas_limit: self.gas_limit(),\n            ..Default::default()\n        })\n    }\n\n    /// Returns the [`TxEnv`] configured from local settings only.\n    fn local_tx_env(&self) -> TxEnv {\n        TxEnv {\n            caller: self.sender,\n            gas_price: self.env.gas_price.unwrap_or_default().into(),\n            gas_limit: self.gas_limit(),\n            ..Default::default()\n        }\n    }\n\n    /// Builds a [`CfgEnv`] from the options, using the provided [`ChainId`].\n    fn cfg_env(&self, chain_id: ChainId) -> CfgEnv {\n        let mut cfg = CfgEnv::default();\n        cfg.chain_id = chain_id;\n        cfg.memory_limit = self.memory_limit;\n        cfg.limit_contract_code_size = Some(usize::MAX);\n        // EIP-3607 rejects transactions from senders with deployed code.\n        // If EIP-3607 is enabled it can cause issues during fuzz/invariant tests if the caller\n        // is a contract. So we disable the check by default.\n        cfg.disable_eip3607 = true;\n        cfg.disable_block_gas_limit = self.disable_block_gas_limit;\n        cfg.disable_nonce_check = true;\n        // By default do not enforce transaction gas limits imposed by Osaka (EIP-7825).\n        // Users can opt-in to enable these limits by setting `enable_tx_gas_limit` to true.\n        if !self.enable_tx_gas_limit {\n            cfg.tx_gas_limit_cap = Some(u64::MAX);\n        }\n        cfg\n    }\n\n    /// Helper function that returns the [CreateFork] to use, if any.\n    ///\n    /// storage caching for the [CreateFork] will be enabled if\n    ///   - `fork_url` is present\n    ///   - `fork_block_number` is present\n    ///   - `StorageCachingConfig` allows the `fork_url` + chain ID pair\n    ///   - storage is allowed (`no_storage_caching = false`)\n    ///\n    /// If all these criteria are met, then storage caching is enabled and storage info will be\n    /// written to `<Config::foundry_cache_dir()>/<str(chainid)>/<block>/storage.json`.\n    ///\n    /// for `mainnet` and `--fork-block-number 14435000` on mac the corresponding storage cache will\n    /// be at `~/.foundry/cache/mainnet/14435000/storage.json`.\n    pub fn get_fork(&self, config: &Config, evm_env: EvmEnv) -> Option<CreateFork> {\n        let url = self.fork_url.clone()?;\n        let enable_caching = config.enable_caching(&url, evm_env.cfg_env.chain_id);\n\n        // Pin fork_block_number to the block that was already fetched in env, so subsequent\n        // fork operations use the same block. This prevents inconsistencies when forking at\n        // \"latest\" where the chain could advance between calls.\n        let mut evm_opts = self.clone();\n        if evm_opts.fork_block_number.is_none() {\n            evm_opts.fork_block_number = Some(evm_env.block_env.number.to());\n        }\n\n        Some(CreateFork { url, enable_caching, evm_env, evm_opts })\n    }\n\n    /// Returns the gas limit to use\n    pub fn gas_limit(&self) -> u64 {\n        self.env.block_gas_limit.unwrap_or(self.env.gas_limit).0\n    }\n\n    /// Returns the available compute units per second, which will be\n    /// - u64::MAX, if `no_rpc_rate_limit` if set (as rate limiting is disabled)\n    /// - the assigned compute units, if `compute_units_per_second` is set\n    /// - ALCHEMY_FREE_TIER_CUPS (330) otherwise\n    fn get_compute_units_per_second(&self) -> u64 {\n        if self.no_rpc_rate_limit {\n            u64::MAX\n        } else if let Some(cups) = self.compute_units_per_second {\n            cups\n        } else {\n            ALCHEMY_FREE_TIER_CUPS\n        }\n    }\n\n    /// Returns the chain ID from the RPC, if any.\n    pub async fn get_remote_chain_id(&self) -> Option<Chain> {\n        if let Some(url) = &self.fork_url\n            && let Ok(provider) = self.fork_provider_with_url::<AnyNetwork>(url)\n        {\n            trace!(?url, \"retrieving chain via eth_chainId\");\n\n            if let Ok(id) = provider.get_chain_id().await {\n                return Some(Chain::from(id));\n            }\n\n            // Provider URLs could be of the format `{CHAIN_IDENTIFIER}-mainnet`\n            // (e.g. Alchemy `opt-mainnet`, `arb-mainnet`), fallback to this method only\n            // if we're not able to retrieve chain id from `RetryProvider`.\n            if url.contains(\"mainnet\") {\n                trace!(?url, \"auto detected mainnet chain\");\n                return Some(Chain::mainnet());\n            }\n        }\n\n        None\n    }\n}\n\n#[derive(Clone, Debug, Default, Serialize, Deserialize)]\npub struct Env {\n    /// The block gas limit.\n    pub gas_limit: GasLimit,\n\n    /// The `CHAINID` opcode value.\n    pub chain_id: Option<u64>,\n\n    /// the tx.gasprice value during EVM execution\n    ///\n    /// This is an Option, so we can determine in fork mode whether to use the config's gas price\n    /// (if set by user) or the remote client's gas price.\n    #[serde(default, skip_serializing_if = \"Option::is_none\")]\n    pub gas_price: Option<u64>,\n\n    /// the base fee in a block\n    pub block_base_fee_per_gas: u64,\n\n    /// the tx.origin value during EVM execution\n    pub tx_origin: Address,\n\n    /// the block.coinbase value during EVM execution\n    pub block_coinbase: Address,\n\n    /// the block.timestamp value during EVM execution\n    #[serde(\n        deserialize_with = \"foundry_config::deserialize_u64_to_u256\",\n        serialize_with = \"foundry_config::serialize_u64_or_u256\"\n    )]\n    pub block_timestamp: U256,\n\n    /// the block.number value during EVM execution\"\n    #[serde(\n        deserialize_with = \"foundry_config::deserialize_u64_to_u256\",\n        serialize_with = \"foundry_config::serialize_u64_or_u256\"\n    )]\n    pub block_number: U256,\n\n    /// the block.difficulty value during EVM execution\n    pub block_difficulty: u64,\n\n    /// Previous block beacon chain random value. Before merge this field is used for mix_hash\n    pub block_prevrandao: B256,\n\n    /// the block.gaslimit value during EVM execution\n    #[serde(default, skip_serializing_if = \"Option::is_none\")]\n    pub block_gas_limit: Option<GasLimit>,\n\n    /// EIP-170: Contract code size limit in bytes. Useful to increase this because of tests.\n    #[serde(default, skip_serializing_if = \"Option::is_none\")]\n    pub code_size_limit: Option<usize>,\n}\n\nasync fn option_try_or_else<T, E>(\n    option: Option<T>,\n    f: impl AsyncFnOnce() -> Result<T, E>,\n) -> Result<T, E> {\n    if let Some(value) = option { Ok(value) } else { f().await }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[tokio::test(flavor = \"multi_thread\")]\n    async fn get_fork_pins_block_number_from_env() {\n        let endpoint = foundry_test_utils::rpc::next_http_rpc_endpoint();\n\n        let config = Config::figment();\n        let mut evm_opts = config.extract::<EvmOpts>().unwrap();\n        evm_opts.fork_url = Some(endpoint.clone());\n        // Explicitly leave fork_block_number as None to simulate --fork-url without --block-number\n        assert!(evm_opts.fork_block_number.is_none());\n\n        // Fetch the environment (this resolves \"latest\" to an actual block number)\n        let (evm_env, _) = evm_opts.env().await.unwrap();\n        let resolved_block = evm_env.block_env.number;\n        assert!(resolved_block > U256::ZERO, \"should have resolved to a real block number\");\n\n        // Create the fork - this should pin the block number\n        let fork = evm_opts.get_fork(&Config::default(), evm_env).unwrap();\n\n        // The fork's evm_opts should now have fork_block_number set to the resolved block\n        assert_eq!(\n            fork.evm_opts.fork_block_number,\n            Some(resolved_block.to::<u64>()),\n            \"get_fork should pin fork_block_number to the block from env\"\n        );\n    }\n\n    #[tokio::test(flavor = \"multi_thread\")]\n    async fn get_fork_preserves_explicit_block_number() {\n        let endpoint = foundry_test_utils::rpc::next_http_rpc_endpoint();\n\n        let config = Config::figment();\n        let mut evm_opts = config.extract::<EvmOpts>().unwrap();\n        evm_opts.fork_url = Some(endpoint.clone());\n        // Set an explicit block number\n        evm_opts.fork_block_number = Some(12345678);\n\n        let (evm_env, _) = evm_opts.env().await.unwrap();\n\n        let fork = evm_opts.get_fork(&Config::default(), evm_env).unwrap();\n\n        // Should preserve the explicit block number, not override it\n        assert_eq!(\n            fork.evm_opts.fork_block_number,\n            Some(12345678),\n            \"get_fork should preserve explicitly set fork_block_number\"\n        );\n    }\n}\n"
  },
  {
    "path": "crates/evm/core/src/precompiles.rs",
    "content": "use alloy_primitives::{Address, address};\n\n/// The ECRecover precompile address.\npub const EC_RECOVER: Address = address!(\"0x0000000000000000000000000000000000000001\");\n\n/// The SHA-256 precompile address.\npub const SHA_256: Address = address!(\"0x0000000000000000000000000000000000000002\");\n\n/// The RIPEMD-160 precompile address.\npub const RIPEMD_160: Address = address!(\"0x0000000000000000000000000000000000000003\");\n\n/// The Identity precompile address.\npub const IDENTITY: Address = address!(\"0x0000000000000000000000000000000000000004\");\n\n/// The ModExp precompile address.\npub const MOD_EXP: Address = address!(\"0x0000000000000000000000000000000000000005\");\n\n/// The ECAdd precompile address.\npub const EC_ADD: Address = address!(\"0x0000000000000000000000000000000000000006\");\n\n/// The ECMul precompile address.\npub const EC_MUL: Address = address!(\"0x0000000000000000000000000000000000000007\");\n\n/// The ECPairing precompile address.\npub const EC_PAIRING: Address = address!(\"0x0000000000000000000000000000000000000008\");\n\n/// The Blake2F precompile address.\npub const BLAKE_2F: Address = address!(\"0x0000000000000000000000000000000000000009\");\n\n/// The PointEvaluation precompile address.\npub const POINT_EVALUATION: Address = address!(\"0x000000000000000000000000000000000000000a\");\n\n/// The BLS12-381 G1ADD precompile address.\npub const BLS12_G1ADD: Address = address!(\"0x000000000000000000000000000000000000000b\");\n\n/// The BLS12-381 G1MSM precompile address.\npub const BLS12_G1MSM: Address = address!(\"0x000000000000000000000000000000000000000c\");\n\n/// The BLS12-381 G2ADD precompile address.\npub const BLS12_G2ADD: Address = address!(\"0x000000000000000000000000000000000000000d\");\n\n/// The BLS12-381 G2MSM precompile address.\npub const BLS12_G2MSM: Address = address!(\"0x000000000000000000000000000000000000000e\");\n\n/// The BLS12-381 pairing check precompile address.\npub const BLS12_PAIRING_CHECK: Address = address!(\"0x000000000000000000000000000000000000000f\");\n\n/// The BLS12-381 map Fp to G1 precompile address.\npub const BLS12_MAP_FP_TO_G1: Address = address!(\"0x0000000000000000000000000000000000000010\");\n\n/// The BLS12-381 map Fp2 to G2 precompile address.\npub const BLS12_MAP_FP2_TO_G2: Address = address!(\"0x0000000000000000000000000000000000000011\");\n\n/// The P256VERIFY precompile address.\npub const P256_VERIFY: Address = address!(\"0x0000000000000000000000000000000000000100\");\n\n/// Precompile addresses.\npub const PRECOMPILES: &[Address] = &[\n    EC_RECOVER,\n    SHA_256,\n    RIPEMD_160,\n    IDENTITY,\n    MOD_EXP,\n    EC_ADD,\n    EC_MUL,\n    EC_PAIRING,\n    BLAKE_2F,\n    POINT_EVALUATION,\n    BLS12_G1ADD,\n    BLS12_G1MSM,\n    BLS12_G2ADD,\n    BLS12_G2MSM,\n    BLS12_PAIRING_CHECK,\n    BLS12_MAP_FP_TO_G1,\n    BLS12_MAP_FP2_TO_G2,\n    P256_VERIFY,\n];\n"
  },
  {
    "path": "crates/evm/core/src/state_snapshot.rs",
    "content": "//! Support for snapshotting different states\n\nuse alloy_primitives::{U256, map::HashMap};\n\n/// Represents all state snapshots\n#[derive(Clone, Debug)]\npub struct StateSnapshots<T> {\n    id: U256,\n    state_snapshots: HashMap<U256, T>,\n}\n\nimpl<T> StateSnapshots<T> {\n    fn next_id(&mut self) -> U256 {\n        let id = self.id;\n        self.id = id.saturating_add(U256::from(1));\n        id\n    }\n\n    /// Returns the state snapshot with the given id `id`\n    pub fn get(&self, id: U256) -> Option<&T> {\n        self.state_snapshots.get(&id)\n    }\n\n    /// Removes the state snapshot with the given `id`.\n    ///\n    /// This will also remove any state snapshots taken after the state snapshot with the `id`.\n    /// e.g.: reverting to id 1 will delete snapshots with ids 1, 2, 3, etc.)\n    pub fn remove(&mut self, id: U256) -> Option<T> {\n        let snapshot_state = self.state_snapshots.remove(&id);\n\n        // Revert all state snapshots taken after the state snapshot with the `id`\n        let mut to_revert = id + U256::from(1);\n        while to_revert < self.id {\n            self.state_snapshots.remove(&to_revert);\n            to_revert += U256::from(1);\n        }\n\n        snapshot_state\n    }\n\n    /// Removes all state snapshots.\n    pub fn clear(&mut self) {\n        self.state_snapshots.clear();\n    }\n\n    /// Removes the state snapshot with the given `id`.\n    ///\n    /// Does not remove state snapshots after it.\n    pub fn remove_at(&mut self, id: U256) -> Option<T> {\n        self.state_snapshots.remove(&id)\n    }\n\n    /// Inserts the new state snapshot and returns the id.\n    pub fn insert(&mut self, state_snapshot: T) -> U256 {\n        let id = self.next_id();\n        self.state_snapshots.insert(id, state_snapshot);\n        id\n    }\n\n    /// Inserts the new state snapshot at the given `id`.\n    ///\n    ///  Does not auto-increment the next `id`.\n    pub fn insert_at(&mut self, state_snapshot: T, id: U256) {\n        self.state_snapshots.insert(id, state_snapshot);\n    }\n}\n\nimpl<T> Default for StateSnapshots<T> {\n    fn default() -> Self {\n        Self { id: U256::ZERO, state_snapshots: HashMap::default() }\n    }\n}\n"
  },
  {
    "path": "crates/evm/core/src/utils.rs",
    "content": "use crate::EvmEnv;\nuse alloy_chains::Chain;\nuse alloy_consensus::{BlockHeader, private::alloy_eips::eip7840::BlobParams};\nuse alloy_hardforks::EthereumHardfork;\nuse alloy_json_abi::{Function, JsonAbi};\nuse alloy_primitives::{B256, ChainId, Selector, U256};\nuse alloy_provider::{Network, network::BlockResponse};\nuse foundry_config::NamedChain;\nuse foundry_evm_networks::NetworkConfigs;\npub use revm::state::EvmState as StateChangeset;\nuse revm::{\n    context::BlockEnv,\n    primitives::{\n        eip4844::{BLOB_BASE_FEE_UPDATE_FRACTION_CANCUN, BLOB_BASE_FEE_UPDATE_FRACTION_PRAGUE},\n        hardfork::SpecId,\n    },\n};\n\n/// Hints to the compiler that this is a cold path, i.e. unlikely to be taken.\n#[cold]\n#[inline(always)]\npub fn cold_path() {\n    // TODO: remove `#[cold]` and call `std::hint::cold_path` once stable.\n}\n\n/// Constructs a [`BlockEnv`] from a block header.\npub fn block_env_from_header(header: &impl BlockHeader) -> BlockEnv {\n    BlockEnv {\n        number: U256::from(header.number()),\n        beneficiary: header.beneficiary(),\n        timestamp: U256::from(header.timestamp()),\n        difficulty: header.difficulty(),\n        prevrandao: header.mix_hash(),\n        basefee: header.base_fee_per_gas().unwrap_or_default(),\n        gas_limit: header.gas_limit(),\n        ..Default::default()\n    }\n}\n\n/// Depending on the configured chain id and block number this should apply any specific changes\n///\n/// - checks for prevrandao mixhash after merge\n/// - applies chain specifics: on Arbitrum `block.number` is the L1 block\n///\n/// Should be called with proper chain id (retrieved from provider if not provided).\npub fn apply_chain_and_block_specific_env_changes<N: Network>(\n    evm_env: &mut EvmEnv,\n    block: &N::BlockResponse,\n    configs: NetworkConfigs,\n) {\n    use NamedChain::*;\n\n    if let Ok(chain) = NamedChain::try_from(evm_env.cfg_env.chain_id) {\n        let block_number = block.header().number();\n\n        match chain {\n            Mainnet => {\n                // after merge difficulty is supplanted with prevrandao EIP-4399\n                if block_number >= 15_537_351u64 {\n                    evm_env.block_env.difficulty =\n                        evm_env.block_env.prevrandao.unwrap_or_default().into();\n                }\n\n                return;\n            }\n            BinanceSmartChain | BinanceSmartChainTestnet => {\n                // https://github.com/foundry-rs/foundry/issues/9942\n                // As far as observed from the source code of bnb-chain/bsc, the `difficulty` field\n                // is still in use and returned by the corresponding opcode but `prevrandao`\n                // (`mixHash`) is always zero, even though bsc adopts the newer EVM\n                // specification. This will confuse revm and causes emulation\n                // failure.\n                evm_env.block_env.prevrandao = Some(evm_env.block_env.difficulty.into());\n                return;\n            }\n            c if c.is_arbitrum() => {\n                // on arbitrum `block.number` is the L1 block which is included in the\n                // `l1BlockNumber` field\n                if let Some(l1_block_number) = block\n                    .other_fields()\n                    .and_then(|other| other.get(\"l1BlockNumber\").cloned())\n                    .and_then(|l1_block_number| {\n                        serde_json::from_value::<U256>(l1_block_number).ok()\n                    })\n                {\n                    evm_env.block_env.number = l1_block_number.to();\n                }\n            }\n            _ => {}\n        }\n    }\n\n    if configs.bypass_prevrandao(evm_env.cfg_env.chain_id) && evm_env.block_env.prevrandao.is_none()\n    {\n        // <https://github.com/foundry-rs/foundry/issues/4232>\n        evm_env.block_env.prevrandao = Some(B256::random());\n    }\n\n    // if difficulty is `0` we assume it's past merge\n    if block.header().difficulty().is_zero() {\n        evm_env.block_env.difficulty = evm_env.block_env.prevrandao.unwrap_or_default().into();\n    }\n}\n\n/// Derives the active [`BlobParams`] based on the given timestamp.\n///\n/// This falls back to regular ethereum blob params if no hardforks for the given chain id are\n/// detected.\npub fn get_blob_params(chain_id: ChainId, timestamp: u64) -> BlobParams {\n    let hardfork = EthereumHardfork::from_chain_and_timestamp(Chain::from_id(chain_id), timestamp)\n        .unwrap_or_default();\n\n    match hardfork {\n        EthereumHardfork::Prague => BlobParams::prague(),\n        EthereumHardfork::Osaka => BlobParams::osaka(),\n        EthereumHardfork::Bpo1 => BlobParams::bpo1(),\n        EthereumHardfork::Bpo2 => BlobParams::bpo2(),\n\n        // future hardforks/unknown settings: update once decided\n        EthereumHardfork::Bpo3 => BlobParams::bpo2(),\n        EthereumHardfork::Bpo4 => BlobParams::bpo2(),\n        EthereumHardfork::Bpo5 => BlobParams::bpo2(),\n        EthereumHardfork::Amsterdam => BlobParams::bpo2(),\n\n        // fallback\n        _ => BlobParams::cancun(),\n    }\n}\n\n/// Derive the blob base fee update fraction based on the chain and timestamp by checking the\n/// hardfork.\npub fn get_blob_base_fee_update_fraction(chain_id: ChainId, timestamp: u64) -> u64 {\n    get_blob_params(chain_id, timestamp).update_fraction as u64\n}\n\n/// Returns the blob base fee update fraction based on the spec id.\npub fn get_blob_base_fee_update_fraction_by_spec_id(spec: SpecId) -> u64 {\n    if spec >= SpecId::PRAGUE {\n        BLOB_BASE_FEE_UPDATE_FRACTION_PRAGUE\n    } else {\n        BLOB_BASE_FEE_UPDATE_FRACTION_CANCUN\n    }\n}\n\n/// Given an ABI and selector, it tries to find the respective function.\npub fn get_function<'a>(\n    contract_name: &str,\n    selector: Selector,\n    abi: &'a JsonAbi,\n) -> eyre::Result<&'a Function> {\n    abi.functions()\n        .find(|func| func.selector() == selector)\n        .ok_or_else(|| eyre::eyre!(\"{contract_name} does not have the selector {selector}\"))\n}\n"
  },
  {
    "path": "crates/evm/core/test-data/storage.json",
    "content": "{\"meta\":{\"cfg_env\":{\"chain_id\":1,\"spec_id\":\"LATEST\",\"perf_all_precompiles_have_balance\":false,\"memory_limit\":4294967295,\"perf_analyse_created_bytecodes\":\"Analyse\",\"limit_contract_code_size\":24576,\"disable_coinbase_tip\":false},\"block_env\":{\"number\":\"0xdc42b8\",\"coinbase\":\"0x0000000000000000000000000000000000000000\",\"timestamp\":\"0x1\",\"difficulty\":\"0x0\",\"basefee\":\"0x0\",\"gas_limit\":\"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\"},\"hosts\":[\"mainnet.infura.io\"]},\"accounts\":{\"0x63091244180ae240c87d1f528f5f269134cb07b3\":{\"balance\":\"0x0\",\"code_hash\":\"0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470\",\"code\":null,\"nonce\":0}},\"storage\":{\"0x63091244180ae240c87d1f528f5f269134cb07b3\":{\"0x0\":\"0x0\",\"0x1\":\"0x0\",\"0x2\":\"0x0\",\"0x3\":\"0x0\",\"0x4\":\"0x0\",\"0x5\":\"0x0\",\"0x6\":\"0x0\",\"0x7\":\"0x0\",\"0x8\":\"0x0\",\"0x9\":\"0x0\"}},\"block_hashes\":{}}"
  },
  {
    "path": "crates/evm/coverage/Cargo.toml",
    "content": "[package]\nname = \"foundry-evm-coverage\"\ndescription = \"EVM bytecode coverage analysis\"\n\nversion.workspace = true\nedition.workspace = true\nrust-version.workspace = true\nauthors.workspace = true\nlicense.workspace = true\nhomepage.workspace = true\nrepository.workspace = true\n\n[lints]\nworkspace = true\n\n[dependencies]\nfoundry-common.workspace = true\nfoundry-compilers.workspace = true\nfoundry-evm-core.workspace = true\n\nalloy-primitives.workspace = true\neyre.workspace = true\nrevm.workspace = true\nsemver.workspace = true\ntracing.workspace = true\nrayon.workspace = true\nsolar.workspace = true\n"
  },
  {
    "path": "crates/evm/coverage/src/analysis.rs",
    "content": "use super::{CoverageItem, CoverageItemKind, SourceLocation};\nuse alloy_primitives::map::HashMap;\nuse foundry_common::TestFunctionExt;\nuse foundry_compilers::ProjectCompileOutput;\nuse rayon::prelude::*;\nuse solar::{\n    ast::{self, ExprKind, ItemKind, StmtKind, yul},\n    data_structures::{Never, map::FxHashSet},\n    interface::{BytePos, Span},\n    sema::{Gcx, hir},\n};\nuse std::{\n    ops::{ControlFlow, Range},\n    path::PathBuf,\n    sync::Arc,\n};\n\n/// A visitor that walks the AST of a single contract and finds coverage items.\n#[derive(Clone)]\nstruct SourceVisitor<'gcx> {\n    /// The source ID of the contract.\n    source_id: u32,\n    /// The solar session for span resolution.\n    gcx: Gcx<'gcx>,\n\n    /// The name of the contract being walked.\n    contract_name: Arc<str>,\n\n    /// The current branch ID\n    branch_id: u32,\n\n    /// Coverage items\n    items: Vec<CoverageItem>,\n\n    all_lines: Vec<u32>,\n    function_calls: Vec<Span>,\n    function_calls_set: FxHashSet<Span>,\n}\n\nstruct SourceVisitorCheckpoint {\n    items: usize,\n    all_lines: usize,\n    function_calls: usize,\n}\n\nimpl<'gcx> SourceVisitor<'gcx> {\n    fn new(source_id: u32, gcx: Gcx<'gcx>) -> Self {\n        Self {\n            source_id,\n            gcx,\n            contract_name: Arc::default(),\n            branch_id: 0,\n            all_lines: Default::default(),\n            function_calls: Default::default(),\n            function_calls_set: Default::default(),\n            items: Default::default(),\n        }\n    }\n\n    fn checkpoint(&self) -> SourceVisitorCheckpoint {\n        SourceVisitorCheckpoint {\n            items: self.items.len(),\n            all_lines: self.all_lines.len(),\n            function_calls: self.function_calls.len(),\n        }\n    }\n\n    fn restore_checkpoint(&mut self, checkpoint: SourceVisitorCheckpoint) {\n        let SourceVisitorCheckpoint { items, all_lines, function_calls } = checkpoint;\n        self.items.truncate(items);\n        self.all_lines.truncate(all_lines);\n        self.function_calls.truncate(function_calls);\n    }\n\n    fn visit_contract<'ast>(&mut self, contract: &'ast ast::ItemContract<'ast>) {\n        let _ = ast::Visit::visit_item_contract(self, contract);\n    }\n\n    /// Returns `true` if the contract has any test functions.\n    fn has_tests(&self, checkpoint: &SourceVisitorCheckpoint) -> bool {\n        self.items[checkpoint.items..].iter().any(|item| {\n            if let CoverageItemKind::Function { name } = &item.kind {\n                name.is_any_test()\n            } else {\n                false\n            }\n        })\n    }\n\n    /// Disambiguate functions with the same name in the same contract.\n    fn disambiguate_functions(&mut self) {\n        let mut dups = HashMap::<_, Vec<usize>>::default();\n        for (i, item) in self.items.iter().enumerate() {\n            if let CoverageItemKind::Function { name } = &item.kind {\n                dups.entry(name.clone()).or_default().push(i);\n            }\n        }\n        for dups in dups.values() {\n            if dups.len() > 1 {\n                for (i, &dup) in dups.iter().enumerate() {\n                    let item = &mut self.items[dup];\n                    if let CoverageItemKind::Function { name } = &item.kind {\n                        item.kind =\n                            CoverageItemKind::Function { name: format!(\"{name}.{i}\").into() };\n                    }\n                }\n            }\n        }\n    }\n\n    fn resolve_function_calls(&mut self, hir_source_id: hir::SourceId) {\n        self.function_calls_set = self.function_calls.iter().copied().collect();\n        let _ = hir::Visit::visit_nested_source(self, hir_source_id);\n    }\n\n    fn sort(&mut self) {\n        self.items.sort();\n    }\n\n    fn push_lines(&mut self) {\n        self.all_lines.sort_unstable();\n        self.all_lines.dedup();\n        let mut lines = Vec::new();\n        for &line in &self.all_lines {\n            if let Some(reference_item) =\n                self.items.iter().find(|item| item.loc.lines.start == line)\n            {\n                lines.push(CoverageItem {\n                    kind: CoverageItemKind::Line,\n                    loc: reference_item.loc.clone(),\n                    hits: 0,\n                });\n            }\n        }\n        self.items.extend(lines);\n    }\n\n    fn push_stmt(&mut self, span: Span) {\n        self.push_item_kind(CoverageItemKind::Statement, span);\n    }\n\n    /// Creates a coverage item for a given kind and source location. Pushes item to the internal\n    /// collection (plus additional coverage line if item is a statement).\n    fn push_item_kind(&mut self, kind: CoverageItemKind, span: Span) {\n        let item = CoverageItem { kind, loc: self.source_location_for(span), hits: 0 };\n\n        debug_assert!(!matches!(item.kind, CoverageItemKind::Line));\n        self.all_lines.push(item.loc.lines.start);\n\n        self.items.push(item);\n    }\n\n    fn source_location_for(&self, mut span: Span) -> SourceLocation {\n        // Statements' ranges in the solc source map do not include the semicolon.\n        if let Ok(snippet) = self.gcx.sess.source_map().span_to_snippet(span)\n            && let Some(stripped) = snippet.strip_suffix(';')\n        {\n            let stripped = stripped.trim_end();\n            let skipped = snippet.len() - stripped.len();\n            span = span.with_hi(span.hi() - BytePos::from_usize(skipped));\n        }\n\n        SourceLocation {\n            source_id: self.source_id as usize,\n            contract_name: self.contract_name.clone(),\n            bytes: self.byte_range(span),\n            lines: self.line_range(span),\n        }\n    }\n\n    fn byte_range(&self, span: Span) -> Range<u32> {\n        let bytes_usize = self.gcx.sess.source_map().span_to_source(span).unwrap().data;\n        bytes_usize.start as u32..bytes_usize.end as u32\n    }\n\n    fn line_range(&self, span: Span) -> Range<u32> {\n        let lines = self.gcx.sess.source_map().span_to_lines(span).unwrap().data;\n        assert!(!lines.is_empty());\n        let first = lines.first().unwrap();\n        let last = lines.last().unwrap();\n        first.line_index as u32 + 1..last.line_index as u32 + 2\n    }\n\n    fn next_branch_id(&mut self) -> u32 {\n        let id = self.branch_id;\n        self.branch_id = id + 1;\n        id\n    }\n}\n\nimpl<'ast> ast::Visit<'ast> for SourceVisitor<'_> {\n    type BreakValue = Never;\n\n    fn visit_item_contract(\n        &mut self,\n        contract: &'ast ast::ItemContract<'ast>,\n    ) -> ControlFlow<Self::BreakValue> {\n        self.contract_name = contract.name.as_str().into();\n        self.walk_item_contract(contract)\n    }\n\n    #[expect(clippy::single_match)]\n    fn visit_item(&mut self, item: &'ast ast::Item<'ast>) -> ControlFlow<Self::BreakValue> {\n        match &item.kind {\n            ItemKind::Function(func) => {\n                // TODO: We currently can only detect empty bodies in normal functions, not any of\n                // the other kinds: https://github.com/foundry-rs/foundry/issues/9458\n                if func.kind != ast::FunctionKind::Function && !has_statements(func.body.as_ref()) {\n                    return ControlFlow::Continue(());\n                }\n\n                let name = func.header.name.as_ref().map(|n| n.as_str()).unwrap_or_else(|| {\n                    match func.kind {\n                        ast::FunctionKind::Constructor => \"constructor\",\n                        ast::FunctionKind::Receive => \"receive\",\n                        ast::FunctionKind::Fallback => \"fallback\",\n                        ast::FunctionKind::Function | ast::FunctionKind::Modifier => unreachable!(),\n                    }\n                });\n\n                // Exclude function from coverage report if it is virtual without implementation.\n                let exclude_func = func.header.virtual_() && !func.is_implemented();\n                if !exclude_func {\n                    self.push_item_kind(\n                        CoverageItemKind::Function { name: name.into() },\n                        item.span,\n                    );\n                }\n\n                self.walk_item(item)?;\n            }\n            _ => {}\n        }\n        // Only walk functions.\n        ControlFlow::Continue(())\n    }\n\n    fn visit_stmt(&mut self, stmt: &'ast ast::Stmt<'ast>) -> ControlFlow<Self::BreakValue> {\n        match &stmt.kind {\n            StmtKind::Break | StmtKind::Continue | StmtKind::Emit(..) | StmtKind::Revert(..) => {\n                self.push_stmt(stmt.span);\n                // TODO(dani): these probably shouldn't be excluded.\n                return ControlFlow::Continue(());\n            }\n            StmtKind::Return(_) | StmtKind::DeclSingle(_) | StmtKind::DeclMulti(..) => {\n                self.push_stmt(stmt.span);\n            }\n\n            StmtKind::If(_cond, then_stmt, else_stmt) => {\n                let branch_id = self.next_branch_id();\n\n                // Add branch coverage items only if one of true/branch bodies contains statements.\n                if stmt_has_statements(then_stmt)\n                    || else_stmt.as_ref().is_some_and(|s| stmt_has_statements(s))\n                {\n                    // The branch instruction is mapped to the first opcode within the true\n                    // body source range.\n                    self.push_item_kind(\n                        CoverageItemKind::Branch { branch_id, path_id: 0, is_first_opcode: true },\n                        then_stmt.span,\n                    );\n                    if else_stmt.is_some() {\n                        // We use `stmt.span`, which includes `else_stmt.span`, since we need to\n                        // include the condition so that this can be marked as covered.\n                        // Initially implemented in https://github.com/foundry-rs/foundry/pull/3094.\n                        self.push_item_kind(\n                            CoverageItemKind::Branch {\n                                branch_id,\n                                path_id: 1,\n                                is_first_opcode: false,\n                            },\n                            stmt.span,\n                        );\n                    }\n                }\n            }\n\n            StmtKind::Try(ast::StmtTry { expr: _, clauses }) => {\n                let branch_id = self.next_branch_id();\n\n                let mut path_id = 0;\n                for catch in clauses.iter() {\n                    let ast::TryCatchClause { span, name: _, args, block } = catch;\n                    let span = if path_id == 0 { stmt.span.to(*span) } else { *span };\n                    if path_id == 0 || has_statements(Some(block)) {\n                        self.push_item_kind(\n                            CoverageItemKind::Branch { branch_id, path_id, is_first_opcode: true },\n                            span,\n                        );\n                        path_id += 1;\n                    } else if !args.is_empty() {\n                        // Add coverage for clause with parameters and empty statements.\n                        // (`catch (bytes memory reason) {}`).\n                        // Catch all clause without statements is ignored (`catch {}`).\n                        self.push_stmt(span);\n                    }\n                }\n            }\n\n            // Skip placeholder statements as they are never referenced in source maps.\n            StmtKind::Assembly(_)\n            | StmtKind::Block(_)\n            | StmtKind::UncheckedBlock(_)\n            | StmtKind::Placeholder\n            | StmtKind::Expr(_)\n            | StmtKind::While(..)\n            | StmtKind::DoWhile(..)\n            | StmtKind::For { .. } => {}\n        }\n        self.walk_stmt(stmt)\n    }\n\n    fn visit_expr(&mut self, expr: &'ast ast::Expr<'ast>) -> ControlFlow<Self::BreakValue> {\n        match &expr.kind {\n            ExprKind::Assign(..)\n            | ExprKind::Unary(..)\n            | ExprKind::Binary(..)\n            | ExprKind::Ternary(..) => {\n                self.push_stmt(expr.span);\n                if matches!(expr.kind, ExprKind::Binary(..)) {\n                    return self.walk_expr(expr);\n                }\n            }\n            ExprKind::Call(callee, _args) => {\n                // Resolve later.\n                self.function_calls.push(expr.span);\n\n                if let ExprKind::Ident(ident) = &callee.kind {\n                    // Might be a require call, add branch coverage.\n                    // Asserts should not be considered branches: <https://github.com/foundry-rs/foundry/issues/9460>.\n                    if ident.as_str() == \"require\" {\n                        let branch_id = self.next_branch_id();\n                        self.push_item_kind(\n                            CoverageItemKind::Branch {\n                                branch_id,\n                                path_id: 0,\n                                is_first_opcode: false,\n                            },\n                            expr.span,\n                        );\n                        self.push_item_kind(\n                            CoverageItemKind::Branch {\n                                branch_id,\n                                path_id: 1,\n                                is_first_opcode: false,\n                            },\n                            expr.span,\n                        );\n                    }\n                }\n            }\n            _ => {}\n        }\n        // Intentionally do not walk all expressions.\n        ControlFlow::Continue(())\n    }\n\n    fn visit_yul_stmt(&mut self, stmt: &'ast yul::Stmt<'ast>) -> ControlFlow<Self::BreakValue> {\n        use yul::StmtKind;\n        match &stmt.kind {\n            StmtKind::VarDecl(..)\n            | StmtKind::AssignSingle(..)\n            | StmtKind::AssignMulti(..)\n            | StmtKind::Leave\n            | StmtKind::Break\n            | StmtKind::Continue => {\n                self.push_stmt(stmt.span);\n                // Don't walk assignments.\n                return ControlFlow::Continue(());\n            }\n            StmtKind::If(..) => {\n                let branch_id = self.next_branch_id();\n                self.push_item_kind(\n                    CoverageItemKind::Branch { branch_id, path_id: 0, is_first_opcode: false },\n                    stmt.span,\n                );\n            }\n            StmtKind::For(yul::StmtFor { body, .. }) => {\n                self.push_stmt(body.span);\n            }\n            StmtKind::Switch(switch) => {\n                for case in switch.cases.iter() {\n                    self.push_stmt(case.span);\n                    self.push_stmt(case.body.span);\n                }\n            }\n            StmtKind::FunctionDef(func) => {\n                let name = func.name.as_str();\n                self.push_item_kind(CoverageItemKind::Function { name: name.into() }, stmt.span);\n            }\n            // TODO(dani): merge with Block below on next solar release: https://github.com/paradigmxyz/solar/pull/496\n            StmtKind::Expr(_) => {\n                self.push_stmt(stmt.span);\n                return ControlFlow::Continue(());\n            }\n            StmtKind::Block(_) => {}\n        }\n        self.walk_yul_stmt(stmt)\n    }\n\n    fn visit_yul_expr(&mut self, expr: &'ast yul::Expr<'ast>) -> ControlFlow<Self::BreakValue> {\n        use yul::ExprKind;\n        match &expr.kind {\n            ExprKind::Path(_) | ExprKind::Lit(_) => {}\n            ExprKind::Call(_) => self.push_stmt(expr.span),\n        }\n        // Intentionally do not walk all expressions.\n        ControlFlow::Continue(())\n    }\n}\n\nimpl<'gcx> hir::Visit<'gcx> for SourceVisitor<'gcx> {\n    type BreakValue = Never;\n\n    fn hir(&self) -> &'gcx hir::Hir<'gcx> {\n        &self.gcx.hir\n    }\n\n    fn visit_expr(&mut self, expr: &'gcx hir::Expr<'gcx>) -> ControlFlow<Self::BreakValue> {\n        if let hir::ExprKind::Call(lhs, ..) = &expr.kind\n            && self.function_calls_set.contains(&expr.span)\n            && is_regular_call(lhs)\n        {\n            self.push_stmt(expr.span);\n        }\n        self.walk_expr(expr)\n    }\n}\n\n// https://github.com/argotorg/solidity/blob/965166317bbc2b02067eb87f222a2dce9d24e289/libsolidity/ast/ASTAnnotations.h#L336-L341\n// https://github.com/argotorg/solidity/blob/965166317bbc2b02067eb87f222a2dce9d24e289/libsolidity/analysis/TypeChecker.cpp#L2720\nfn is_regular_call(lhs: &hir::Expr<'_>) -> bool {\n    match lhs.peel_parens().kind {\n        // StructConstructorCall\n        hir::ExprKind::Ident([hir::Res::Item(hir::ItemId::Struct(_))]) => false,\n        // TypeConversion\n        hir::ExprKind::Type(_) => false,\n        _ => true,\n    }\n}\n\nfn has_statements(block: Option<&ast::Block<'_>>) -> bool {\n    block.is_some_and(|block| !block.is_empty())\n}\n\nfn stmt_has_statements(stmt: &ast::Stmt<'_>) -> bool {\n    match &stmt.kind {\n        StmtKind::Assembly(a) => !a.block.is_empty(),\n        StmtKind::Block(b) | StmtKind::UncheckedBlock(b) => has_statements(Some(b)),\n        _ => true,\n    }\n}\n\n/// Coverage source analysis.\n#[derive(Clone, Debug, Default)]\npub struct SourceAnalysis {\n    /// All the coverage items.\n    all_items: Vec<CoverageItem>,\n    /// Source ID to `(offset, len)` into `all_items`.\n    map: Vec<(u32, u32)>,\n}\n\nimpl SourceAnalysis {\n    /// Analyzes contracts in the sources held by the source analyzer.\n    ///\n    /// Coverage items are found by:\n    /// - Walking the AST of each contract (except interfaces)\n    /// - Recording the items of each contract\n    ///\n    /// Each coverage item contains relevant information to find opcodes corresponding to them: the\n    /// source ID the item is in, the source code range of the item, and the contract name the item\n    /// is in.\n    ///\n    /// Note: Source IDs are only unique per compilation job; that is, a code base compiled with\n    /// two different solc versions will produce overlapping source IDs if the compiler version is\n    /// not taken into account.\n    #[instrument(name = \"SourceAnalysis::new\", skip_all)]\n    pub fn new(data: &SourceFiles, output: &ProjectCompileOutput) -> eyre::Result<Self> {\n        let mut sourced_items = output.parser().solc().compiler().enter(|compiler| {\n            data.sources\n                .par_iter()\n                .map(|(&source_id, path)| {\n                    let _guard = debug_span!(\"SourceAnalysis::new::visit\", ?path).entered();\n\n                    let (_, source) = compiler.gcx().get_ast_source(path).unwrap();\n                    let ast = source.ast.as_ref().unwrap();\n                    let (hir_source_id, _) = compiler.gcx().get_hir_source(path).unwrap();\n\n                    let mut visitor = SourceVisitor::new(source_id, compiler.gcx());\n                    for item in ast.items.iter() {\n                        // Visit only top-level contracts.\n                        let ItemKind::Contract(contract) = &item.kind else { continue };\n\n                        // Skip interfaces which have no function implementations.\n                        if contract.kind.is_interface() {\n                            continue;\n                        }\n\n                        let checkpoint = visitor.checkpoint();\n                        visitor.visit_contract(contract);\n                        if visitor.has_tests(&checkpoint) {\n                            visitor.restore_checkpoint(checkpoint);\n                        }\n                    }\n\n                    if !visitor.function_calls.is_empty() {\n                        visitor.resolve_function_calls(hir_source_id);\n                    }\n\n                    if !visitor.items.is_empty() {\n                        visitor.disambiguate_functions();\n                        visitor.sort();\n                        visitor.push_lines();\n                        visitor.sort();\n                    }\n                    (source_id, visitor.items)\n                })\n                .collect::<Vec<(u32, Vec<CoverageItem>)>>()\n        });\n\n        // Create mapping and merge items.\n        sourced_items.sort_by_key(|(id, items)| (*id, items.first().map(|i| i.loc.bytes.start)));\n        let Some(&(max_idx, _)) = sourced_items.last() else { return Ok(Self::default()) };\n        let len = max_idx + 1;\n        let mut all_items = Vec::new();\n        let mut map = vec![(u32::MAX, 0); len as usize];\n        for (idx, items) in sourced_items {\n            // Assumes that all `idx` items are consecutive, guaranteed by the sort above.\n            let idx = idx as usize;\n            if map[idx].0 == u32::MAX {\n                map[idx].0 = all_items.len() as u32;\n            }\n            map[idx].1 += items.len() as u32;\n            all_items.extend(items);\n        }\n\n        Ok(Self { all_items, map })\n    }\n\n    /// Returns all the coverage items.\n    pub fn all_items(&self) -> &[CoverageItem] {\n        &self.all_items\n    }\n\n    /// Returns all the mutable coverage items.\n    pub fn all_items_mut(&mut self) -> &mut Vec<CoverageItem> {\n        &mut self.all_items\n    }\n\n    /// Returns an iterator over the coverage items and their IDs for the given source.\n    pub fn items_for_source_enumerated(\n        &self,\n        source_id: u32,\n    ) -> impl Iterator<Item = (u32, &CoverageItem)> {\n        let (base_id, items) = self.items_for_source(source_id);\n        items.iter().enumerate().map(move |(idx, item)| (base_id + idx as u32, item))\n    }\n\n    /// Returns the base item ID and all the coverage items for the given source.\n    pub fn items_for_source(&self, source_id: u32) -> (u32, &[CoverageItem]) {\n        let (mut offset, len) = self.map.get(source_id as usize).copied().unwrap_or_default();\n        if offset == u32::MAX {\n            offset = 0;\n        }\n        (offset, &self.all_items[offset as usize..][..len as usize])\n    }\n\n    /// Returns the coverage item for the given item ID.\n    #[inline]\n    pub fn get(&self, item_id: u32) -> Option<&CoverageItem> {\n        self.all_items.get(item_id as usize)\n    }\n}\n\n/// A list of versioned sources and their ASTs.\n#[derive(Default)]\npub struct SourceFiles {\n    /// The versioned sources.\n    pub sources: HashMap<u32, PathBuf>,\n}\n"
  },
  {
    "path": "crates/evm/coverage/src/anchors.rs",
    "content": "use super::{CoverageItemKind, ItemAnchor, SourceLocation};\nuse crate::analysis::SourceAnalysis;\nuse alloy_primitives::map::rustc_hash::FxHashSet;\nuse eyre::ensure;\nuse foundry_compilers::artifacts::sourcemap::{SourceElement, SourceMap};\nuse foundry_evm_core::{bytecode::InstIter, ic::IcPcMap};\nuse revm::bytecode::opcode;\n\n/// Attempts to find anchors for the given items using the given source map and bytecode.\npub fn find_anchors(\n    bytecode: &[u8],\n    source_map: &SourceMap,\n    ic_pc_map: &IcPcMap,\n    analysis: &SourceAnalysis,\n) -> Vec<ItemAnchor> {\n    let mut seen_sources = FxHashSet::default();\n    source_map\n        .iter()\n        .filter_map(|element| element.index())\n        .filter(|&source| seen_sources.insert(source))\n        .flat_map(|source| analysis.items_for_source_enumerated(source))\n        .filter_map(|(item_id, item)| {\n            match item.kind {\n                CoverageItemKind::Branch { path_id, is_first_opcode: false, .. } => {\n                    find_anchor_branch(bytecode, source_map, item_id, &item.loc).map(|anchors| {\n                        match path_id {\n                            0 => anchors.0,\n                            1 => anchors.1,\n                            _ => panic!(\"too many path IDs for branch\"),\n                        }\n                    })\n                }\n                _ => find_anchor_simple(source_map, ic_pc_map, item_id, &item.loc),\n            }\n            .inspect_err(|err| warn!(%item, %err, \"could not find anchor\"))\n            .ok()\n        })\n        .collect()\n}\n\n/// Find an anchor representing the first opcode within the given source range.\npub fn find_anchor_simple(\n    source_map: &SourceMap,\n    ic_pc_map: &IcPcMap,\n    item_id: u32,\n    loc: &SourceLocation,\n) -> eyre::Result<ItemAnchor> {\n    let instruction =\n        source_map.iter().position(|element| is_in_source_range(element, loc)).ok_or_else(\n            || eyre::eyre!(\"Could not find anchor: No matching instruction in range {loc}\"),\n        )?;\n\n    Ok(ItemAnchor {\n        instruction: ic_pc_map.get(instruction as u32).ok_or_else(|| {\n            eyre::eyre!(\"We found an anchor, but we can't translate it to a program counter\")\n        })?,\n        item_id,\n    })\n}\n\n/// Finds the anchor corresponding to a branch item.\n///\n/// This finds the relevant anchors for a branch coverage item. These anchors\n/// are found using the bytecode of the contract in the range of the branching node.\n///\n/// For `IfStatement` nodes, the template is generally:\n/// ```text\n/// <condition>\n/// PUSH <ic if false>\n/// JUMPI\n/// <true branch>\n/// <...>\n/// <false branch>\n/// ```\n///\n/// For `assert` and `require`, the template is generally:\n///\n/// ```text\n/// PUSH <ic if true>\n/// JUMPI\n/// <revert>\n/// <...>\n/// <true branch>\n/// ```\n///\n/// This function will look for the last JUMPI instruction, backtrack to find the program\n/// counter of the first branch, and return an item for that program counter, and the\n/// program counter immediately after the JUMPI instruction.\npub fn find_anchor_branch(\n    bytecode: &[u8],\n    source_map: &SourceMap,\n    item_id: u32,\n    loc: &SourceLocation,\n) -> eyre::Result<(ItemAnchor, ItemAnchor)> {\n    let mut anchors: Option<(ItemAnchor, ItemAnchor)> = None;\n    for (ic, (pc, inst)) in InstIter::new(bytecode).with_pc().enumerate() {\n        // We found a push, so we do some PC -> IC translation accounting, but we also check if\n        // this push is coupled with the JUMPI we are interested in.\n\n        // Check if Opcode is PUSH\n        if (opcode::PUSH1..=opcode::PUSH32).contains(&inst.opcode.get()) {\n            let Some(element) = source_map.get(ic) else {\n                // NOTE(onbjerg): For some reason the last few bytes of the bytecode do not have\n                // a source map associated, so at that point we just stop searching\n                break;\n            };\n\n            // Check if we are in the source range we are interested in, and if the next opcode\n            // is a JUMPI\n            let next_pc = pc + inst.immediate.len() + 1;\n            let push_size = inst.immediate.len();\n            if bytecode.get(next_pc).copied() == Some(opcode::JUMPI)\n                && is_in_source_range(element, loc)\n            {\n                // We do not support program counters bigger than u32.\n                ensure!(push_size <= 4, \"jump destination overflow\");\n\n                // Convert the push bytes for the second branch's PC to a u32.\n                let mut pc_bytes = [0u8; 4];\n                pc_bytes[4 - push_size..].copy_from_slice(inst.immediate);\n                let pc_jump = u32::from_be_bytes(pc_bytes);\n                anchors = Some((\n                    ItemAnchor {\n                        item_id,\n                        // The first branch is the opcode directly after JUMPI\n                        instruction: (next_pc + 1) as u32,\n                    },\n                    ItemAnchor { item_id, instruction: pc_jump },\n                ));\n            }\n        }\n    }\n\n    anchors.ok_or_else(|| eyre::eyre!(\"Could not detect branches in source: {}\", loc))\n}\n\n/// Calculates whether `element` is within the range of the target `location`.\nfn is_in_source_range(element: &SourceElement, location: &SourceLocation) -> bool {\n    // Source IDs must match.\n    let source_ids_match = element.index_i32() == location.source_id as i32;\n    if !source_ids_match {\n        return false;\n    }\n\n    // Needed because some source ranges in the source map mark the entire contract...\n    let is_within_start = element.offset() >= location.bytes.start;\n    if !is_within_start {\n        return false;\n    }\n\n    let start_of_ranges = location.bytes.start.max(element.offset());\n    let end_of_ranges =\n        (location.bytes.start + location.len()).min(element.offset() + element.length());\n    let within_ranges = start_of_ranges <= end_of_ranges;\n    if !within_ranges {\n        return false;\n    }\n\n    true\n}\n"
  },
  {
    "path": "crates/evm/coverage/src/inspector.rs",
    "content": "use crate::{HitMap, HitMaps};\nuse alloy_primitives::B256;\nuse revm::{\n    Inspector,\n    context::ContextTr,\n    inspector::JournalExt,\n    interpreter::{Interpreter, interpreter_types::Jumps},\n};\nuse std::ptr::NonNull;\n\n/// Inspector implementation for collecting coverage information.\n#[derive(Clone, Debug)]\npub struct LineCoverageCollector {\n    // NOTE: `current_map` is always a valid reference into `maps`.\n    // It is accessed only through `get_or_insert_map` which guarantees that it's valid.\n    // Both of these fields are unsafe to access directly outside of `*insert_map`.\n    current_map: NonNull<HitMap>,\n    current_hash: B256,\n\n    maps: HitMaps,\n}\n\n// SAFETY: See comments on `current_map`.\nunsafe impl Send for LineCoverageCollector {}\nunsafe impl Sync for LineCoverageCollector {}\n\nimpl Default for LineCoverageCollector {\n    fn default() -> Self {\n        Self {\n            current_map: NonNull::dangling(),\n            current_hash: B256::ZERO,\n            maps: Default::default(),\n        }\n    }\n}\n\nimpl<CTX> Inspector<CTX> for LineCoverageCollector\nwhere\n    CTX: ContextTr<Journal: JournalExt>,\n{\n    fn initialize_interp(&mut self, interpreter: &mut Interpreter, _context: &mut CTX) {\n        let map = self.get_or_insert_map(interpreter);\n        // Reserve some space early to avoid reallocating too often.\n        map.reserve(8192.min(interpreter.bytecode.len()));\n    }\n\n    fn step(&mut self, interpreter: &mut Interpreter, _context: &mut CTX) {\n        let map = self.get_or_insert_map(interpreter);\n        map.hit(interpreter.bytecode.pc() as u32);\n    }\n}\n\nimpl LineCoverageCollector {\n    /// Finish collecting coverage information and return the [`HitMaps`].\n    pub fn finish(self) -> HitMaps {\n        self.maps\n    }\n\n    /// Gets the hit map for the current contract, or inserts a new one if it doesn't exist.\n    ///\n    /// The map is stored in `current_map` and returned as a mutable reference.\n    /// See comments on `current_map` for more details.\n    #[inline]\n    fn get_or_insert_map(&mut self, interpreter: &mut Interpreter) -> &mut HitMap {\n        let hash = interpreter.bytecode.get_or_calculate_hash();\n        if self.current_hash != *hash {\n            self.insert_map(interpreter);\n        }\n        // SAFETY: See comments on `current_map`.\n        unsafe { self.current_map.as_mut() }\n    }\n\n    #[cold]\n    #[inline(never)]\n    fn insert_map(&mut self, interpreter: &mut Interpreter) {\n        let hash = interpreter.bytecode.hash().unwrap();\n        self.current_hash = hash;\n        // Converts the mutable reference to a `NonNull` pointer.\n        self.current_map = self\n            .maps\n            .entry(hash)\n            .or_insert_with(|| HitMap::new(interpreter.bytecode.original_bytes()))\n            .into();\n    }\n}\n"
  },
  {
    "path": "crates/evm/coverage/src/lib.rs",
    "content": "//! # foundry-evm-coverage\n//!\n//! EVM bytecode coverage analysis.\n\n#![cfg_attr(not(test), warn(unused_crate_dependencies))]\n#![cfg_attr(docsrs, feature(doc_cfg))]\n\n#[macro_use]\nextern crate tracing;\n\nuse alloy_primitives::{\n    Bytes,\n    map::{B256HashMap, HashMap, rustc_hash::FxHashMap},\n};\nuse analysis::SourceAnalysis;\nuse eyre::Result;\nuse foundry_compilers::artifacts::sourcemap::SourceMap;\nuse semver::Version;\nuse std::{\n    collections::BTreeMap,\n    fmt,\n    num::NonZeroU32,\n    ops::{Deref, DerefMut, Range},\n    path::{Path, PathBuf},\n    sync::Arc,\n};\n\npub mod analysis;\npub mod anchors;\n\nmod inspector;\npub use inspector::LineCoverageCollector;\n\n/// A coverage report.\n///\n/// A coverage report contains coverage items and opcodes corresponding to those items (called\n/// \"anchors\"). A single coverage item may be referred to by multiple anchors.\n#[derive(Clone, Debug, Default)]\npub struct CoverageReport {\n    /// A map of source IDs to the source path.\n    pub source_paths: HashMap<(Version, usize), PathBuf>,\n    /// A map of source paths to source IDs.\n    pub source_paths_to_ids: HashMap<(Version, PathBuf), usize>,\n    /// All coverage items for the codebase, keyed by the compiler version.\n    pub analyses: HashMap<Version, SourceAnalysis>,\n    /// All item anchors for the codebase, keyed by their contract ID.\n    ///\n    /// `(id, (creation, runtime))`\n    pub anchors: HashMap<ContractId, (Vec<ItemAnchor>, Vec<ItemAnchor>)>,\n    /// All the bytecode hits for the codebase.\n    pub bytecode_hits: HashMap<ContractId, HitMap>,\n    /// The bytecode -> source mappings.\n    pub source_maps: HashMap<ContractId, (SourceMap, SourceMap)>,\n}\n\nimpl CoverageReport {\n    /// Add a source file path.\n    pub fn add_source(&mut self, version: Version, source_id: usize, path: PathBuf) {\n        self.source_paths.insert((version.clone(), source_id), path.clone());\n        self.source_paths_to_ids.insert((version, path), source_id);\n    }\n\n    /// Get the source ID for a specific source file path.\n    pub fn get_source_id(&self, version: Version, path: PathBuf) -> Option<usize> {\n        self.source_paths_to_ids.get(&(version, path)).copied()\n    }\n\n    /// Add the source maps.\n    pub fn add_source_maps(\n        &mut self,\n        source_maps: impl IntoIterator<Item = (ContractId, (SourceMap, SourceMap))>,\n    ) {\n        self.source_maps.extend(source_maps);\n    }\n\n    /// Add a [`SourceAnalysis`] to this report.\n    pub fn add_analysis(&mut self, version: Version, analysis: SourceAnalysis) {\n        self.analyses.insert(version, analysis);\n    }\n\n    /// Add anchors to this report.\n    ///\n    /// `(id, (creation, runtime))`\n    pub fn add_anchors(\n        &mut self,\n        anchors: impl IntoIterator<Item = (ContractId, (Vec<ItemAnchor>, Vec<ItemAnchor>))>,\n    ) {\n        self.anchors.extend(anchors);\n    }\n\n    /// Returns an iterator over coverage summaries by source file path.\n    pub fn summary_by_file(&self) -> impl Iterator<Item = (&Path, CoverageSummary)> {\n        self.by_file(|summary: &mut CoverageSummary, item| summary.add_item(item))\n    }\n\n    /// Returns an iterator over coverage items by source file path.\n    pub fn items_by_file(&self) -> impl Iterator<Item = (&Path, Vec<&CoverageItem>)> {\n        self.by_file(|list: &mut Vec<_>, item| list.push(item))\n    }\n\n    fn by_file<'a, T: Default>(\n        &'a self,\n        mut f: impl FnMut(&mut T, &'a CoverageItem),\n    ) -> impl Iterator<Item = (&'a Path, T)> {\n        let mut by_file: BTreeMap<&Path, T> = BTreeMap::new();\n        for (version, items) in &self.analyses {\n            for item in items.all_items() {\n                let key = (version.clone(), item.loc.source_id);\n                let Some(path) = self.source_paths.get(&key) else { continue };\n                f(by_file.entry(path).or_default(), item);\n            }\n        }\n        by_file.into_iter()\n    }\n\n    /// Processes data from a [`HitMap`] and sets hit counts for coverage items in this coverage\n    /// map.\n    ///\n    /// This function should only be called *after* all the relevant sources have been processed and\n    /// added to the map (see [`add_source`](Self::add_source)).\n    pub fn add_hit_map(\n        &mut self,\n        contract_id: &ContractId,\n        hit_map: &HitMap,\n        is_deployed_code: bool,\n    ) -> Result<()> {\n        // Add bytecode level hits.\n        self.bytecode_hits\n            .entry(contract_id.clone())\n            .and_modify(|m| m.merge(hit_map))\n            .or_insert_with(|| hit_map.clone());\n\n        // Add source level hits.\n        if let Some(anchors) = self.anchors.get(contract_id) {\n            let anchors = if is_deployed_code { &anchors.1 } else { &anchors.0 };\n            for anchor in anchors {\n                if let Some(hits) = hit_map.get(anchor.instruction) {\n                    self.analyses\n                        .get_mut(&contract_id.version)\n                        .and_then(|items| items.all_items_mut().get_mut(anchor.item_id as usize))\n                        .expect(\"Anchor refers to non-existent coverage item\")\n                        .hits += hits.get();\n                }\n            }\n        }\n\n        Ok(())\n    }\n\n    /// Retains all the coverage items specified by `predicate`.\n    ///\n    /// This function should only be called after all the sources were used, otherwise, the output\n    /// will be missing the ones that are dependent on them.\n    pub fn retain_sources(&mut self, mut predicate: impl FnMut(&Path) -> bool) {\n        self.analyses.retain(|version, analysis| {\n            analysis.all_items_mut().retain(|item| {\n                self.source_paths\n                    .get(&(version.clone(), item.loc.source_id))\n                    .map(|path| predicate(path))\n                    .unwrap_or(false)\n            });\n            !analysis.all_items().is_empty()\n        });\n    }\n}\n\n/// A collection of [`HitMap`]s.\n#[derive(Clone, Debug, Default)]\npub struct HitMaps(pub B256HashMap<HitMap>);\n\nimpl HitMaps {\n    /// Merges two `Option<HitMaps>`.\n    pub fn merge_opt(a: &mut Option<Self>, b: Option<Self>) {\n        match (a, b) {\n            (_, None) => {}\n            (a @ None, Some(b)) => *a = Some(b),\n            (Some(a), Some(b)) => a.merge(b),\n        }\n    }\n\n    /// Merges two `HitMaps`.\n    pub fn merge(&mut self, other: Self) {\n        self.reserve(other.len());\n        for (code_hash, other) in other.0 {\n            self.entry(code_hash).and_modify(|e| e.merge(&other)).or_insert(other);\n        }\n    }\n\n    /// Merges two `HitMaps`.\n    pub fn merged(mut self, other: Self) -> Self {\n        self.merge(other);\n        self\n    }\n}\n\nimpl Deref for HitMaps {\n    type Target = B256HashMap<HitMap>;\n\n    fn deref(&self) -> &Self::Target {\n        &self.0\n    }\n}\n\nimpl DerefMut for HitMaps {\n    fn deref_mut(&mut self) -> &mut Self::Target {\n        &mut self.0\n    }\n}\n\n/// Hit data for an address.\n///\n/// Contains low-level data about hit counters for the instructions in the bytecode of a contract.\n#[derive(Clone, Debug)]\npub struct HitMap {\n    hits: FxHashMap<u32, u32>,\n    bytecode: Bytes,\n}\n\nimpl HitMap {\n    /// Create a new hitmap with the given bytecode.\n    #[inline]\n    pub fn new(bytecode: Bytes) -> Self {\n        Self { bytecode, hits: HashMap::with_capacity_and_hasher(1024, Default::default()) }\n    }\n\n    /// Returns the bytecode.\n    #[inline]\n    pub fn bytecode(&self) -> &Bytes {\n        &self.bytecode\n    }\n\n    /// Returns the number of hits for the given program counter.\n    #[inline]\n    pub fn get(&self, pc: u32) -> Option<NonZeroU32> {\n        NonZeroU32::new(self.hits.get(&pc).copied().unwrap_or(0))\n    }\n\n    /// Increase the hit counter by 1 for the given program counter.\n    #[inline]\n    pub fn hit(&mut self, pc: u32) {\n        self.hits(pc, 1)\n    }\n\n    /// Increase the hit counter by `hits` for the given program counter.\n    #[inline]\n    pub fn hits(&mut self, pc: u32, hits: u32) {\n        *self.hits.entry(pc).or_default() += hits;\n    }\n\n    /// Reserve space for additional hits.\n    #[inline]\n    pub fn reserve(&mut self, additional: usize) {\n        self.hits.reserve(additional);\n    }\n\n    /// Merge another hitmap into this, assuming the bytecode is consistent\n    pub fn merge(&mut self, other: &Self) {\n        self.reserve(other.len());\n        for (pc, hits) in other.iter() {\n            self.hits(pc, hits);\n        }\n    }\n\n    /// Returns an iterator over all the program counters and their hit counts.\n    #[inline]\n    pub fn iter(&self) -> impl Iterator<Item = (u32, u32)> + '_ {\n        self.hits.iter().map(|(&pc, &hits)| (pc, hits))\n    }\n\n    /// Returns the number of program counters hit in the hitmap.\n    #[inline]\n    pub fn len(&self) -> usize {\n        self.hits.len()\n    }\n\n    /// Returns `true` if the hitmap is empty.\n    #[inline]\n    pub fn is_empty(&self) -> bool {\n        self.hits.is_empty()\n    }\n}\n\n/// A unique identifier for a contract\n#[derive(Clone, Debug, PartialEq, Eq, Hash)]\npub struct ContractId {\n    pub version: Version,\n    pub source_id: usize,\n    pub contract_name: Arc<str>,\n}\n\nimpl fmt::Display for ContractId {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        write!(\n            f,\n            \"Contract \\\"{}\\\" (solc {}, source ID {})\",\n            self.contract_name, self.version, self.source_id\n        )\n    }\n}\n\n/// An item anchor describes what instruction marks a [CoverageItem] as covered.\n#[derive(Clone, Debug)]\npub struct ItemAnchor {\n    /// The program counter for the opcode of this anchor.\n    pub instruction: u32,\n    /// The item ID this anchor points to.\n    pub item_id: u32,\n}\n\nimpl fmt::Display for ItemAnchor {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        write!(f, \"IC {} -> Item {}\", self.instruction, self.item_id)\n    }\n}\n\n#[derive(Clone, Debug)]\npub enum CoverageItemKind {\n    /// An executable line in the code.\n    Line,\n    /// A statement in the code.\n    Statement,\n    /// A branch in the code.\n    Branch {\n        /// The ID that identifies the branch.\n        ///\n        /// There may be multiple items with the same branch ID - they belong to the same branch,\n        /// but represent different paths.\n        branch_id: u32,\n        /// The path ID for this branch.\n        ///\n        /// The first path has ID 0, the next ID 1, and so on.\n        path_id: u32,\n        /// If true, then the branch anchor is the first opcode within the branch source range.\n        is_first_opcode: bool,\n    },\n    /// A function in the code.\n    Function {\n        /// The name of the function.\n        name: Box<str>,\n    },\n}\n\nimpl PartialEq for CoverageItemKind {\n    fn eq(&self, other: &Self) -> bool {\n        self.ord_key() == other.ord_key()\n    }\n}\n\nimpl Eq for CoverageItemKind {}\n\nimpl PartialOrd for CoverageItemKind {\n    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {\n        Some(self.cmp(other))\n    }\n}\n\nimpl Ord for CoverageItemKind {\n    fn cmp(&self, other: &Self) -> std::cmp::Ordering {\n        self.ord_key().cmp(&other.ord_key())\n    }\n}\n\nimpl CoverageItemKind {\n    fn ord_key(&self) -> impl Ord + use<> {\n        match *self {\n            Self::Line => 0,\n            Self::Statement => 1,\n            Self::Branch { .. } => 2,\n            Self::Function { .. } => 3,\n        }\n    }\n}\n\n#[derive(Clone, Debug)]\npub struct CoverageItem {\n    /// The coverage item kind.\n    pub kind: CoverageItemKind,\n    /// The location of the item in the source code.\n    pub loc: SourceLocation,\n    /// The number of times this item was hit.\n    pub hits: u32,\n}\n\nimpl PartialEq for CoverageItem {\n    fn eq(&self, other: &Self) -> bool {\n        self.ord_key() == other.ord_key()\n    }\n}\n\nimpl Eq for CoverageItem {}\n\nimpl PartialOrd for CoverageItem {\n    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {\n        Some(self.cmp(other))\n    }\n}\n\nimpl Ord for CoverageItem {\n    fn cmp(&self, other: &Self) -> std::cmp::Ordering {\n        self.ord_key().cmp(&other.ord_key())\n    }\n}\n\nimpl fmt::Display for CoverageItem {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        self.fmt_with_source(None).fmt(f)\n    }\n}\n\nimpl CoverageItem {\n    fn ord_key(&self) -> impl Ord + use<> {\n        (\n            self.loc.source_id,\n            self.loc.lines.start,\n            self.loc.lines.end,\n            self.kind.ord_key(),\n            self.loc.bytes.start,\n            self.loc.bytes.end,\n        )\n    }\n\n    pub fn fmt_with_source(&self, src: Option<&str>) -> impl fmt::Display {\n        solar::data_structures::fmt::from_fn(move |f| {\n            match &self.kind {\n                CoverageItemKind::Line => {\n                    write!(f, \"Line\")?;\n                }\n                CoverageItemKind::Statement => {\n                    write!(f, \"Statement\")?;\n                }\n                CoverageItemKind::Branch { branch_id, path_id, .. } => {\n                    write!(f, \"Branch (branch: {branch_id}, path: {path_id})\")?;\n                }\n                CoverageItemKind::Function { name } => {\n                    write!(f, r#\"Function \"{name}\"\"#)?;\n                }\n            }\n            write!(f, \" (location: ({}), hits: {})\", self.loc, self.hits)?;\n\n            if let Some(src) = src\n                && let Some(src) = src.get(self.loc.bytes())\n            {\n                write!(f, \" -> \")?;\n\n                let max_len = 64;\n                let max_half = max_len / 2;\n\n                if src.len() > max_len {\n                    write!(f, \"\\\"{}\", src[..max_half].escape_debug())?;\n                    write!(f, \"...\")?;\n                    write!(f, \"{}\\\"\", src[src.len() - max_half..].escape_debug())?;\n                } else {\n                    write!(f, \"{src:?}\")?;\n                }\n            }\n\n            Ok(())\n        })\n    }\n}\n\n/// A source location.\n#[derive(Clone, Debug)]\npub struct SourceLocation {\n    /// The source ID.\n    pub source_id: usize,\n    /// The contract this source range is in.\n    pub contract_name: Arc<str>,\n    /// Byte range.\n    pub bytes: Range<u32>,\n    /// Line range. Indices are 1-based.\n    pub lines: Range<u32>,\n}\n\nimpl fmt::Display for SourceLocation {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        write!(f, \"source ID: {}, lines: {:?}, bytes: {:?}\", self.source_id, self.lines, self.bytes)\n    }\n}\n\nimpl SourceLocation {\n    /// Returns the byte range as usize.\n    pub fn bytes(&self) -> Range<usize> {\n        self.bytes.start as usize..self.bytes.end as usize\n    }\n\n    /// Returns the length of the byte range.\n    pub fn len(&self) -> u32 {\n        self.bytes.len() as u32\n    }\n\n    /// Returns true if the byte range is empty.\n    pub fn is_empty(&self) -> bool {\n        self.len() == 0\n    }\n}\n\n/// Coverage summary for a source file.\n#[derive(Clone, Debug, Default)]\npub struct CoverageSummary {\n    /// The number of executable lines in the source file.\n    pub line_count: usize,\n    /// The number of lines that were hit.\n    pub line_hits: usize,\n    /// The number of statements in the source file.\n    pub statement_count: usize,\n    /// The number of statements that were hit.\n    pub statement_hits: usize,\n    /// The number of branches in the source file.\n    pub branch_count: usize,\n    /// The number of branches that were hit.\n    pub branch_hits: usize,\n    /// The number of functions in the source file.\n    pub function_count: usize,\n    /// The number of functions hit.\n    pub function_hits: usize,\n}\n\nimpl CoverageSummary {\n    /// Creates a new, empty coverage summary.\n    pub fn new() -> Self {\n        Self::default()\n    }\n\n    /// Creates a coverage summary from a collection of coverage items.\n    pub fn from_items<'a>(items: impl IntoIterator<Item = &'a CoverageItem>) -> Self {\n        let mut summary = Self::default();\n        summary.add_items(items);\n        summary\n    }\n\n    /// Adds another coverage summary to this one.\n    pub fn merge(&mut self, other: &Self) {\n        let Self {\n            line_count,\n            line_hits,\n            statement_count,\n            statement_hits,\n            branch_count,\n            branch_hits,\n            function_count,\n            function_hits,\n        } = self;\n        *line_count += other.line_count;\n        *line_hits += other.line_hits;\n        *statement_count += other.statement_count;\n        *statement_hits += other.statement_hits;\n        *branch_count += other.branch_count;\n        *branch_hits += other.branch_hits;\n        *function_count += other.function_count;\n        *function_hits += other.function_hits;\n    }\n\n    /// Adds a coverage item to this summary.\n    pub fn add_item(&mut self, item: &CoverageItem) {\n        match item.kind {\n            CoverageItemKind::Line => {\n                self.line_count += 1;\n                if item.hits > 0 {\n                    self.line_hits += 1;\n                }\n            }\n            CoverageItemKind::Statement => {\n                self.statement_count += 1;\n                if item.hits > 0 {\n                    self.statement_hits += 1;\n                }\n            }\n            CoverageItemKind::Branch { .. } => {\n                self.branch_count += 1;\n                if item.hits > 0 {\n                    self.branch_hits += 1;\n                }\n            }\n            CoverageItemKind::Function { .. } => {\n                self.function_count += 1;\n                if item.hits > 0 {\n                    self.function_hits += 1;\n                }\n            }\n        }\n    }\n\n    /// Adds multiple coverage items to this summary.\n    pub fn add_items<'a>(&mut self, items: impl IntoIterator<Item = &'a CoverageItem>) {\n        for item in items {\n            self.add_item(item);\n        }\n    }\n}\n"
  },
  {
    "path": "crates/evm/evm/Cargo.toml",
    "content": "[package]\nname = \"foundry-evm\"\ndescription = \"Main Foundry EVM backend abstractions\"\n\nversion.workspace = true\nedition.workspace = true\nrust-version.workspace = true\nauthors.workspace = true\nlicense.workspace = true\nhomepage.workspace = true\nrepository.workspace = true\n\n[lints]\nworkspace = true\n\n[dependencies]\nfoundry-cheatcodes.workspace = true\nfoundry-common.workspace = true\nfoundry-compilers.workspace = true\nfoundry-config.workspace = true\nfoundry-evm-core.workspace = true\nfoundry-evm-coverage.workspace = true\nfoundry-evm-fuzz.workspace = true\nfoundry-evm-networks.workspace = true\nfoundry-evm-traces.workspace = true\n\nalloy-dyn-abi = { workspace = true, features = [\"arbitrary\", \"eip712\"] }\nalloy-evm.workspace = true\nalloy-json-abi.workspace = true\nalloy-primitives = { workspace = true, features = [\n    \"serde\",\n    \"getrandom\",\n    \"arbitrary\",\n    \"rlp\",\n] }\nalloy-rpc-types.workspace = true\nalloy-sol-types.workspace = true\nrevm = { workspace = true, default-features = false, features = [\n    \"std\",\n    \"serde\",\n    \"memory_limit\",\n    \"optional_eip3607\",\n    \"optional_block_gas_limit\",\n    \"optional_no_base_fee\",\n    \"arbitrary\",\n    \"c-kzg\",\n] }\nrevm-inspectors.workspace = true\n\neyre.workspace = true\nparking_lot.workspace = true\nproptest.workspace = true\nthiserror.workspace = true\ntracing.workspace = true\nindicatif.workspace = true\nserde_json.workspace = true\nserde.workspace = true\nuuid.workspace = true\nrayon.workspace = true\ntokio.workspace = true\n"
  },
  {
    "path": "crates/evm/evm/src/executors/builder.rs",
    "content": "use crate::{executors::Executor, inspectors::InspectorStackBuilder};\nuse foundry_evm_core::{EvmEnv, backend::Backend};\nuse revm::{context::TxEnv, primitives::hardfork::SpecId};\n\n/// The builder that allows to configure an evm [`Executor`] which a stack of optional\n/// [`revm::Inspector`]s, such as [`Cheatcodes`].\n///\n/// By default, the [`Executor`] will be configured with an empty [`InspectorStack`].\n///\n/// [`Cheatcodes`]: super::Cheatcodes\n/// [`InspectorStack`]: super::InspectorStack\n#[derive(Debug, Clone)]\n#[must_use = \"builders do nothing unless you call `build` on them\"]\npub struct ExecutorBuilder {\n    /// The configuration used to build an `InspectorStack`.\n    stack: InspectorStackBuilder,\n    /// The gas limit.\n    gas_limit: Option<u64>,\n    /// The spec ID.\n    spec_id: SpecId,\n    legacy_assertions: bool,\n}\n\nimpl Default for ExecutorBuilder {\n    #[inline]\n    fn default() -> Self {\n        Self {\n            stack: InspectorStackBuilder::new(),\n            gas_limit: None,\n            spec_id: SpecId::default(),\n            legacy_assertions: false,\n        }\n    }\n}\n\nimpl ExecutorBuilder {\n    /// Create a new executor builder.\n    #[inline]\n    pub fn new() -> Self {\n        Self::default()\n    }\n\n    /// Modify the inspector stack.\n    #[inline]\n    pub fn inspectors(\n        mut self,\n        f: impl FnOnce(InspectorStackBuilder) -> InspectorStackBuilder,\n    ) -> Self {\n        self.stack = f(self.stack);\n        self\n    }\n\n    /// Sets the EVM spec to use.\n    #[inline]\n    pub fn spec_id(mut self, spec: SpecId) -> Self {\n        self.spec_id = spec;\n        self\n    }\n\n    /// Sets the executor gas limit.\n    #[inline]\n    pub fn gas_limit(mut self, gas_limit: u64) -> Self {\n        self.gas_limit = Some(gas_limit);\n        self\n    }\n\n    /// Sets the `legacy_assertions` flag.\n    #[inline]\n    pub fn legacy_assertions(mut self, legacy_assertions: bool) -> Self {\n        self.legacy_assertions = legacy_assertions;\n        self\n    }\n\n    /// Builds the executor as configured.\n    #[inline]\n    pub fn build(self, mut evm_env: EvmEnv, tx_env: TxEnv, db: Backend) -> Executor {\n        let Self { mut stack, gas_limit, spec_id, legacy_assertions } = self;\n        if stack.block.is_none() {\n            stack.block = Some(evm_env.block_env.clone());\n        }\n        if stack.gas_price.is_none() {\n            stack.gas_price = Some(tx_env.gas_price);\n        }\n        let gas_limit = gas_limit.unwrap_or(evm_env.block_env.gas_limit);\n        evm_env.cfg_env.set_spec(spec_id);\n        Executor::new(db, evm_env, tx_env, stack.build(), gas_limit, legacy_assertions)\n    }\n}\n"
  },
  {
    "path": "crates/evm/evm/src/executors/corpus.rs",
    "content": "//! Corpus management for parallel fuzzing with coverage-guided mutation.\n//!\n//! This module implements a corpus-based fuzzing system that stores, mutates, and shares\n//! transaction sequences across multiple fuzzing workers. Each corpus entry represents a\n//! sequence of transactions that has produced interesting coverage, and can be mutated to\n//! discover new execution paths.\n//!\n//! ## File System Structure\n//!\n//! The corpus is organized on disk as follows:\n//!\n//! ```text\n//! <corpus_dir>/\n//! ├── worker0/                  # Master (worker 0) directory\n//! │   ├── corpus/               # Master's corpus entries\n//! │   │   ├── <uuid>-<timestamp>.json          # Corpus entry (if small)\n//! │   │   ├── <uuid>-<timestamp>.json.gz       # Corpus entry (if large, compressed)\n//! │   └── sync/                 # Directory where other workers export new findings\n//! │       └── <uuid>-<timestamp>.json          # New entries from other workers\n//! └── workerN/                  # Worker N's directory\n//!     ├── corpus/               # Worker N's local corpus\n//!     │   └── ...\n//!     └── sync/                 # Worker 2's sync directory\n//!         └── ...\n//! ```\n//!\n//! ## Workflow\n//!\n//! - Each worker maintains its own local corpus with entries stored as JSON files\n//! - Workers export new interesting entries to the master's sync directory via hard links\n//! - The master (worker0) imports new entries from its sync directory and exports them to all the\n//!   other workers\n//! - Workers sync with the master to receive new corpus entries from other workers\n//! - This all happens periodically, there is no clear order in which workers export or import\n//!   entries since it doesn't matter as long as the corpus eventually syncs across all workers\n\nuse crate::executors::{Executor, RawCallResult, invariant::execute_tx};\nuse alloy_dyn_abi::JsonAbiExt;\nuse alloy_json_abi::Function;\nuse alloy_primitives::Bytes;\nuse eyre::{Result, eyre};\nuse foundry_config::FuzzCorpusConfig;\nuse foundry_evm_fuzz::{\n    BasicTxDetails,\n    invariant::FuzzRunIdentifiedContracts,\n    strategies::{EvmFuzzState, mutate_param_value},\n};\nuse proptest::{\n    prelude::{Just, Rng, Strategy},\n    prop_oneof,\n    strategy::{BoxedStrategy, ValueTree},\n    test_runner::TestRunner,\n};\nuse serde::Serialize;\nuse std::{\n    fmt,\n    path::{Path, PathBuf},\n    sync::{\n        Arc,\n        atomic::{AtomicUsize, Ordering},\n    },\n    time::{SystemTime, UNIX_EPOCH},\n};\nuse uuid::Uuid;\n\nconst WORKER: &str = \"worker\";\nconst CORPUS_DIR: &str = \"corpus\";\nconst SYNC_DIR: &str = \"sync\";\n\nconst FAVORABILITY_THRESHOLD: f64 = 0.3;\nconst COVERAGE_MAP_SIZE: usize = 65536;\n\n/// Threshold for compressing corpus entries.\n/// 4KiB is usually the minimum file size on popular file systems.\nconst GZIP_THRESHOLD: usize = 4 * 1024;\n\n/// Possible mutation strategies to apply on a call sequence.\n#[derive(Debug, Clone)]\nenum MutationType {\n    /// Splice original call sequence.\n    Splice,\n    /// Repeat selected call several times.\n    Repeat,\n    /// Interleave calls from two random call sequences.\n    Interleave,\n    /// Replace prefix of the original call sequence with new calls.\n    Prefix,\n    /// Replace suffix of the original call sequence with new calls.\n    Suffix,\n    /// ABI mutate random args of selected call in sequence.\n    Abi,\n}\n\n/// Holds Corpus information.\n#[derive(Clone, Serialize)]\nstruct CorpusEntry {\n    // Unique corpus identifier.\n    uuid: Uuid,\n    // Total mutations of corpus as primary source.\n    total_mutations: usize,\n    // New coverage found as a result of mutating this corpus.\n    new_finds_produced: usize,\n    // Corpus call sequence.\n    #[serde(skip_serializing)]\n    tx_seq: Vec<BasicTxDetails>,\n    // Whether this corpus is favored, i.e. producing new finds more often than\n    // `FAVORABILITY_THRESHOLD`.\n    is_favored: bool,\n    /// Timestamp of when this entry was written to disk in seconds.\n    #[serde(skip_serializing)]\n    timestamp: u64,\n}\n\nimpl CorpusEntry {\n    /// Creates a corpus entry with a new UUID.\n    pub fn new(tx_seq: Vec<BasicTxDetails>) -> Self {\n        Self::new_with(tx_seq, Uuid::new_v4())\n    }\n\n    /// Creates a corpus entry with a path.\n    /// The UUID is parsed from the file name, otherwise a new UUID is generated.\n    pub fn new_existing(tx_seq: Vec<BasicTxDetails>, path: PathBuf) -> Result<Self> {\n        let Some(name) = path.file_name().and_then(|s| s.to_str()) else {\n            eyre::bail!(\"invalid corpus file path: {path:?}\");\n        };\n        let uuid = parse_corpus_filename(name)?.0;\n        Ok(Self::new_with(tx_seq, uuid))\n    }\n\n    /// Creates a corpus entry with the given UUID.\n    pub fn new_with(tx_seq: Vec<BasicTxDetails>, uuid: Uuid) -> Self {\n        Self {\n            uuid,\n            total_mutations: 0,\n            new_finds_produced: 0,\n            tx_seq,\n            is_favored: false,\n            timestamp: SystemTime::now()\n                .duration_since(UNIX_EPOCH)\n                .expect(\"time went backwards\")\n                .as_secs(),\n        }\n    }\n\n    fn write_to_disk_in(&self, dir: &Path, can_gzip: bool) -> foundry_common::fs::Result<()> {\n        let file_name = self.file_name(can_gzip);\n        let path = dir.join(file_name);\n        if self.should_gzip(can_gzip) {\n            foundry_common::fs::write_json_gzip_file(&path, &self.tx_seq)\n        } else {\n            foundry_common::fs::write_json_file(&path, &self.tx_seq)\n        }\n    }\n\n    fn file_name(&self, can_gzip: bool) -> String {\n        let ext = if self.should_gzip(can_gzip) { \".json.gz\" } else { \".json\" };\n        format!(\"{}-{}{ext}\", self.uuid, self.timestamp)\n    }\n\n    fn should_gzip(&self, can_gzip: bool) -> bool {\n        if !can_gzip {\n            return false;\n        }\n        let size: usize = self.tx_seq.iter().map(|tx| tx.estimate_serialized_size()).sum();\n        size > GZIP_THRESHOLD\n    }\n}\n\n#[derive(Default)]\npub(crate) struct GlobalCorpusMetrics {\n    // Number of edges seen during the invariant run.\n    cumulative_edges_seen: AtomicUsize,\n    // Number of features (new hitcount bin of previously hit edge) seen during the invariant run.\n    cumulative_features_seen: AtomicUsize,\n    // Number of corpus entries.\n    corpus_count: AtomicUsize,\n    // Number of corpus entries that are favored.\n    favored_items: AtomicUsize,\n}\n\nimpl fmt::Display for GlobalCorpusMetrics {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        self.load().fmt(f)\n    }\n}\n\nimpl GlobalCorpusMetrics {\n    pub(crate) fn load(&self) -> CorpusMetrics {\n        CorpusMetrics {\n            cumulative_edges_seen: self.cumulative_edges_seen.load(Ordering::Relaxed),\n            cumulative_features_seen: self.cumulative_features_seen.load(Ordering::Relaxed),\n            corpus_count: self.corpus_count.load(Ordering::Relaxed),\n            favored_items: self.favored_items.load(Ordering::Relaxed),\n        }\n    }\n}\n\n#[derive(Serialize, Default, Clone)]\npub(crate) struct CorpusMetrics {\n    // Number of edges seen during the invariant run.\n    cumulative_edges_seen: usize,\n    // Number of features (new hitcount bin of previously hit edge) seen during the invariant run.\n    cumulative_features_seen: usize,\n    // Number of corpus entries.\n    corpus_count: usize,\n    // Number of corpus entries that are favored.\n    favored_items: usize,\n}\n\nimpl fmt::Display for CorpusMetrics {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        writeln!(f)?;\n        writeln!(f, \"        - cumulative edges seen: {}\", self.cumulative_edges_seen)?;\n        writeln!(f, \"        - cumulative features seen: {}\", self.cumulative_features_seen)?;\n        writeln!(f, \"        - corpus count: {}\", self.corpus_count)?;\n        write!(f, \"        - favored items: {}\", self.favored_items)?;\n        Ok(())\n    }\n}\n\nimpl CorpusMetrics {\n    /// Records number of new edges or features explored during the campaign.\n    pub fn update_seen(&mut self, is_edge: bool) {\n        if is_edge {\n            self.cumulative_edges_seen += 1;\n        } else {\n            self.cumulative_features_seen += 1;\n        }\n    }\n\n    /// Updates campaign favored items.\n    pub fn update_favored(&mut self, is_favored: bool, corpus_favored: bool) {\n        if is_favored && !corpus_favored {\n            self.favored_items += 1;\n        } else if !is_favored && corpus_favored {\n            self.favored_items -= 1;\n        }\n    }\n}\n\n/// Per-worker corpus manager.\npub struct WorkerCorpus {\n    /// Worker Id\n    id: usize,\n    /// In-memory corpus entries populated from the persisted files and\n    /// runs administered by this worker.\n    in_memory_corpus: Vec<CorpusEntry>,\n    /// History of binned hitcount of edges seen during fuzzing\n    history_map: Vec<u8>,\n    /// Number of failed replays from initial corpus\n    pub(crate) failed_replays: usize,\n    /// Worker Metrics\n    pub(crate) metrics: CorpusMetrics,\n    /// Fuzzed calls generator.\n    tx_generator: BoxedStrategy<BasicTxDetails>,\n    /// Call sequence mutation strategy type generator used by stateful fuzzing.\n    mutation_generator: BoxedStrategy<MutationType>,\n    /// Identifier of current mutated entry for this worker.\n    current_mutated: Option<Uuid>,\n    /// Config\n    config: Arc<FuzzCorpusConfig>,\n    /// Indices of new entries added to [`WorkerCorpus::in_memory_corpus`] since last sync.\n    new_entry_indices: Vec<usize>,\n    /// Last sync timestamp in seconds.\n    last_sync_timestamp: u64,\n    /// Worker Dir\n    /// corpus_dir/worker1/\n    worker_dir: Option<PathBuf>,\n    /// Metrics at last sync - used to calculate deltas while syncing with global metrics\n    last_sync_metrics: CorpusMetrics,\n}\n\nimpl WorkerCorpus {\n    pub fn new(\n        id: usize,\n        config: FuzzCorpusConfig,\n        tx_generator: BoxedStrategy<BasicTxDetails>,\n        // Only required by master worker (id = 0) to replay existing corpus.\n        executor: Option<&Executor>,\n        fuzzed_function: Option<&Function>,\n        fuzzed_contracts: Option<&FuzzRunIdentifiedContracts>,\n    ) -> Result<Self> {\n        let mutation_generator = prop_oneof![\n            Just(MutationType::Splice),\n            Just(MutationType::Repeat),\n            Just(MutationType::Interleave),\n            Just(MutationType::Prefix),\n            Just(MutationType::Suffix),\n            Just(MutationType::Abi),\n        ]\n        .boxed();\n\n        let worker_dir = config.corpus_dir.as_ref().map(|corpus_dir| {\n            let worker_dir = corpus_dir.join(format!(\"{WORKER}{id}\"));\n            let worker_corpus = worker_dir.join(CORPUS_DIR);\n            let sync_dir = worker_dir.join(SYNC_DIR);\n\n            // Create the necessary directories for the worker.\n            let _ = foundry_common::fs::create_dir_all(&worker_corpus);\n            let _ = foundry_common::fs::create_dir_all(&sync_dir);\n\n            worker_dir\n        });\n\n        let mut in_memory_corpus = vec![];\n        let mut history_map = vec![0u8; COVERAGE_MAP_SIZE];\n        let mut metrics = CorpusMetrics::default();\n        let mut failed_replays = 0;\n\n        if id == 0\n            && let Some(corpus_dir) = &config.corpus_dir\n        {\n            // Master worker loads the initial corpus, if it exists.\n            // Then, [distribute]s it to workers.\n            let executor = executor.expect(\"Executor required for master worker\");\n            'corpus_replay: for entry in read_corpus_dir(corpus_dir) {\n                let tx_seq = entry.read_tx_seq()?;\n                if tx_seq.is_empty() {\n                    continue;\n                }\n                // Warm up history map from loaded sequences.\n                let mut executor = executor.clone();\n                for tx in &tx_seq {\n                    if Self::can_replay_tx(tx, fuzzed_function, fuzzed_contracts) {\n                        let mut call_result = execute_tx(&mut executor, tx)?;\n                        let (new_coverage, is_edge) =\n                            call_result.merge_edge_coverage(&mut history_map);\n                        if new_coverage {\n                            metrics.update_seen(is_edge);\n                        }\n\n                        // Commit only when running invariant / stateful tests.\n                        if fuzzed_contracts.is_some() {\n                            executor.commit(&mut call_result);\n                        }\n                    } else {\n                        failed_replays += 1;\n\n                        // If the only input for fuzzed function cannot be replied, then move to\n                        // next one without adding it in memory.\n                        if fuzzed_function.is_some() {\n                            continue 'corpus_replay;\n                        }\n                    }\n                }\n\n                metrics.corpus_count += 1;\n\n                debug!(\n                    target: \"corpus\",\n                    \"load sequence with len {} from corpus file {}\",\n                    tx_seq.len(),\n                    entry.path.display()\n                );\n\n                // Populate in memory corpus with the sequence from corpus file.\n                in_memory_corpus.push(CorpusEntry::new_with(tx_seq, entry.uuid));\n            }\n        }\n\n        Ok(Self {\n            id,\n            in_memory_corpus,\n            history_map,\n            failed_replays,\n            metrics,\n            tx_generator,\n            mutation_generator,\n            current_mutated: None,\n            config: config.into(),\n            new_entry_indices: Default::default(),\n            last_sync_timestamp: 0,\n            worker_dir,\n            last_sync_metrics: Default::default(),\n        })\n    }\n\n    /// Updates stats for the given call sequence, if new coverage produced.\n    /// Persists the call sequence (if corpus directory is configured and new coverage) and updates\n    /// in-memory corpus.\n    #[instrument(skip_all)]\n    pub fn process_inputs(&mut self, inputs: &[BasicTxDetails], new_coverage: bool) {\n        let Some(worker_corpus) = &self.worker_dir else {\n            return;\n        };\n        let worker_corpus = worker_corpus.join(CORPUS_DIR);\n\n        // Update stats of current mutated primary corpus.\n        if let Some(uuid) = &self.current_mutated {\n            if let Some(corpus) =\n                self.in_memory_corpus.iter_mut().find(|corpus| corpus.uuid == *uuid)\n            {\n                corpus.total_mutations += 1;\n                if new_coverage {\n                    corpus.new_finds_produced += 1\n                }\n                let is_favored = (corpus.new_finds_produced as f64 / corpus.total_mutations as f64)\n                    > FAVORABILITY_THRESHOLD;\n                self.metrics.update_favored(is_favored, corpus.is_favored);\n                corpus.is_favored = is_favored;\n\n                trace!(\n                    target: \"corpus\",\n                    \"updated corpus {}, total mutations: {}, new finds: {}\",\n                    corpus.uuid, corpus.total_mutations, corpus.new_finds_produced\n                );\n            }\n\n            self.current_mutated = None;\n        }\n\n        // Collect inputs only if current run produced new coverage.\n        if !new_coverage {\n            return;\n        }\n\n        assert!(!inputs.is_empty());\n        let corpus = CorpusEntry::new(inputs.to_vec());\n\n        // Persist to disk.\n        let write_result = corpus.write_to_disk_in(&worker_corpus, self.config.corpus_gzip);\n        if let Err(err) = write_result {\n            debug!(target: \"corpus\", %err, \"failed to record call sequence {:?}\", corpus.tx_seq);\n        } else {\n            trace!(\n                target: \"corpus\",\n                \"persisted {} inputs for new coverage for {} corpus\",\n                corpus.tx_seq.len(),\n                corpus.uuid,\n            );\n        }\n\n        // Track in-memory corpus changes to update MasterWorker on sync.\n        let new_index = self.in_memory_corpus.len();\n        self.new_entry_indices.push(new_index);\n\n        // This includes reverting txs in the corpus and `can_continue` removes\n        // them. We want this as it is new coverage and may help reach the other branch.\n        self.metrics.corpus_count += 1;\n        self.in_memory_corpus.push(corpus);\n    }\n\n    /// Collects coverage from call result and updates metrics.\n    pub fn merge_edge_coverage(&mut self, call_result: &mut RawCallResult) -> bool {\n        if !self.config.collect_edge_coverage() {\n            return false;\n        }\n\n        let (new_coverage, is_edge) = call_result.merge_edge_coverage(&mut self.history_map);\n        if new_coverage {\n            self.metrics.update_seen(is_edge);\n        }\n        new_coverage\n    }\n\n    /// Generates new call sequence from in memory corpus. Evicts oldest corpus mutated more than\n    /// configured max mutations value. Used by invariant test campaigns.\n    #[instrument(skip_all)]\n    pub fn new_inputs(\n        &mut self,\n        test_runner: &mut TestRunner,\n        fuzz_state: &EvmFuzzState,\n        targeted_contracts: &FuzzRunIdentifiedContracts,\n    ) -> Result<Vec<BasicTxDetails>> {\n        let mut new_seq = vec![];\n\n        // Early return with first_input only if corpus dir / coverage guided fuzzing not\n        // configured.\n        if !self.config.is_coverage_guided() {\n            new_seq.push(self.new_tx(test_runner)?);\n            return Ok(new_seq);\n        };\n\n        if !self.in_memory_corpus.is_empty() {\n            self.evict_oldest_corpus()?;\n\n            let mutation_type = self\n                .mutation_generator\n                .new_tree(test_runner)\n                .map_err(|err| eyre!(\"Could not generate mutation type {err}\"))?\n                .current();\n\n            let rng = test_runner.rng();\n            let corpus_len = self.in_memory_corpus.len();\n            let primary = &self.in_memory_corpus[rng.random_range(0..corpus_len)];\n            let secondary = &self.in_memory_corpus[rng.random_range(0..corpus_len)];\n\n            match mutation_type {\n                MutationType::Splice => {\n                    trace!(target: \"corpus\", \"splice {} and {}\", primary.uuid, secondary.uuid);\n\n                    self.current_mutated = Some(primary.uuid);\n\n                    let start1 = rng.random_range(0..primary.tx_seq.len());\n                    let end1 = rng.random_range(start1..primary.tx_seq.len());\n\n                    let start2 = rng.random_range(0..secondary.tx_seq.len());\n                    let end2 = rng.random_range(start2..secondary.tx_seq.len());\n\n                    for tx in primary.tx_seq.iter().take(end1).skip(start1) {\n                        new_seq.push(tx.clone());\n                    }\n                    for tx in secondary.tx_seq.iter().take(end2).skip(start2) {\n                        new_seq.push(tx.clone());\n                    }\n                }\n                MutationType::Repeat => {\n                    let corpus = if rng.random::<bool>() { primary } else { secondary };\n                    trace!(target: \"corpus\", \"repeat {}\", corpus.uuid);\n\n                    self.current_mutated = Some(corpus.uuid);\n\n                    new_seq = corpus.tx_seq.clone();\n                    let start = rng.random_range(0..corpus.tx_seq.len());\n                    let end = rng.random_range(start..corpus.tx_seq.len());\n                    let item_idx = rng.random_range(0..corpus.tx_seq.len());\n                    let repeated = vec![new_seq[item_idx].clone(); end - start];\n                    new_seq.splice(start..end, repeated);\n                }\n                MutationType::Interleave => {\n                    trace!(target: \"corpus\", \"interleave {} with {}\", primary.uuid, secondary.uuid);\n\n                    self.current_mutated = Some(primary.uuid);\n\n                    for (tx1, tx2) in primary.tx_seq.iter().zip(secondary.tx_seq.iter()) {\n                        // TODO: chunks?\n                        let tx = if rng.random::<bool>() { tx1.clone() } else { tx2.clone() };\n                        new_seq.push(tx);\n                    }\n                }\n                MutationType::Prefix => {\n                    let corpus = if rng.random::<bool>() { primary } else { secondary };\n                    trace!(target: \"corpus\", \"overwrite prefix of {}\", corpus.uuid);\n\n                    self.current_mutated = Some(corpus.uuid);\n\n                    new_seq = corpus.tx_seq.clone();\n                    for i in 0..rng.random_range(0..=new_seq.len()) {\n                        new_seq[i] = self.new_tx(test_runner)?;\n                    }\n                }\n                MutationType::Suffix => {\n                    let corpus = if rng.random::<bool>() { primary } else { secondary };\n                    trace!(target: \"corpus\", \"overwrite suffix of {}\", corpus.uuid);\n\n                    self.current_mutated = Some(corpus.uuid);\n\n                    new_seq = corpus.tx_seq.clone();\n                    for i in new_seq.len() - rng.random_range(0..new_seq.len())..corpus.tx_seq.len()\n                    {\n                        new_seq[i] = self.new_tx(test_runner)?;\n                    }\n                }\n                MutationType::Abi => {\n                    let targets = targeted_contracts.targets.lock();\n                    let corpus = if rng.random::<bool>() { primary } else { secondary };\n                    trace!(target: \"corpus\", \"ABI mutate args of {}\", corpus.uuid);\n\n                    self.current_mutated = Some(corpus.uuid);\n\n                    new_seq = corpus.tx_seq.clone();\n\n                    let idx = rng.random_range(0..new_seq.len());\n                    let tx = new_seq.get_mut(idx).unwrap();\n                    if let (_, Some(function)) = targets.fuzzed_artifacts(tx) {\n                        // TODO: add call_value to call details and mutate it as well as sender some\n                        // of the time.\n                        if !function.inputs.is_empty() {\n                            self.abi_mutate(tx, function, test_runner, fuzz_state)?;\n                        }\n                    }\n                }\n            }\n        }\n\n        // Make sure the new sequence contains at least one tx to start fuzzing from.\n        if new_seq.is_empty() {\n            new_seq.push(self.new_tx(test_runner)?);\n        }\n        trace!(target: \"corpus\", \"new sequence of {} calls generated\", new_seq.len());\n\n        Ok(new_seq)\n    }\n\n    /// Generates a new input from the shared in memory corpus.  Evicts oldest corpus mutated more\n    /// than configured max mutations value. Used by fuzz (stateless) test campaigns.\n    #[instrument(skip_all)]\n    pub fn new_input(\n        &mut self,\n        test_runner: &mut TestRunner,\n        fuzz_state: &EvmFuzzState,\n        function: &Function,\n    ) -> Result<Bytes> {\n        // Early return if not running with coverage guided fuzzing.\n        if !self.config.is_coverage_guided() {\n            return Ok(self.new_tx(test_runner)?.call_details.calldata);\n        }\n\n        self.evict_oldest_corpus()?;\n\n        let tx = if !self.in_memory_corpus.is_empty() {\n            let corpus = &self.in_memory_corpus\n                [test_runner.rng().random_range(0..self.in_memory_corpus.len())];\n            self.current_mutated = Some(corpus.uuid);\n            let mut tx = corpus.tx_seq.first().unwrap().clone();\n            self.abi_mutate(&mut tx, function, test_runner, fuzz_state)?;\n            tx\n        } else {\n            self.new_tx(test_runner)?\n        };\n\n        Ok(tx.call_details.calldata)\n    }\n\n    /// Generates single call from corpus strategy.\n    pub fn new_tx(&self, test_runner: &mut TestRunner) -> Result<BasicTxDetails> {\n        Ok(self\n            .tx_generator\n            .new_tree(test_runner)\n            .map_err(|_| eyre!(\"Could not generate case\"))?\n            .current())\n    }\n\n    /// Returns the next call to be used in call sequence.\n    /// If coverage guided fuzzing is not configured or if previous input was discarded then this is\n    /// a new tx from strategy.\n    /// If running with coverage guided fuzzing it returns a new call only when sequence\n    /// does not have enough entries, or randomly. Otherwise, returns the next call from initial\n    /// sequence.\n    pub fn generate_next_input(\n        &mut self,\n        test_runner: &mut TestRunner,\n        sequence: &[BasicTxDetails],\n        discarded: bool,\n        depth: usize,\n    ) -> Result<BasicTxDetails> {\n        // Early return with new input if corpus dir / coverage guided fuzzing not configured or if\n        // call was discarded.\n        if self.config.corpus_dir.is_none() || discarded {\n            return self.new_tx(test_runner);\n        }\n\n        // When running with coverage guided fuzzing enabled then generate new sequence if initial\n        // sequence's length is less than depth or randomly, to occasionally intermix new txs.\n        if depth > sequence.len().saturating_sub(1) || test_runner.rng().random_ratio(1, 10) {\n            return self.new_tx(test_runner);\n        }\n\n        // Continue with the next call initial sequence.\n        Ok(sequence[depth].clone())\n    }\n\n    /// Flush the oldest corpus mutated more than configured max mutations unless they are\n    /// favored.\n    fn evict_oldest_corpus(&mut self) -> Result<()> {\n        if self.in_memory_corpus.len() > self.config.corpus_min_size.max(1)\n            && let Some(index) = self.in_memory_corpus.iter().position(|corpus| {\n                corpus.total_mutations > self.config.corpus_min_mutations && !corpus.is_favored\n            })\n        {\n            let corpus = &self.in_memory_corpus[index];\n\n            trace!(target: \"corpus\", corpus=%serde_json::to_string(&corpus).unwrap(), \"evict corpus\");\n\n            // Remove corpus from memory.\n            self.in_memory_corpus.remove(index);\n\n            // Adjust the tracked indices.\n            self.new_entry_indices.retain_mut(|i| {\n                if *i > index {\n                    *i -= 1; // Shift indices down.\n                    true // Keep this index.\n                } else {\n                    *i != index // Remove if it's the deleted index, keep otherwise.\n                }\n            });\n        }\n        Ok(())\n    }\n\n    /// Mutates calldata of provided tx by abi decoding current values and randomly selecting the\n    /// inputs to change.\n    fn abi_mutate(\n        &self,\n        tx: &mut BasicTxDetails,\n        function: &Function,\n        test_runner: &mut TestRunner,\n        fuzz_state: &EvmFuzzState,\n    ) -> Result<()> {\n        // let rng = test_runner.rng();\n        let mut arg_mutation_rounds =\n            test_runner.rng().random_range(0..=function.inputs.len()).max(1);\n        let round_arg_idx: Vec<usize> = if function.inputs.len() <= 1 {\n            vec![0]\n        } else {\n            (0..arg_mutation_rounds)\n                .map(|_| test_runner.rng().random_range(0..function.inputs.len()))\n                .collect()\n        };\n        let mut prev_inputs = function\n            .abi_decode_input(&tx.call_details.calldata[4..])\n            .map_err(|err| eyre!(\"failed to load previous inputs: {err}\"))?;\n\n        while arg_mutation_rounds > 0 {\n            let idx = round_arg_idx[arg_mutation_rounds - 1];\n            prev_inputs[idx] = mutate_param_value(\n                &function\n                    .inputs\n                    .get(idx)\n                    .expect(\"Could not get input to mutate\")\n                    .selector_type()\n                    .parse()?,\n                prev_inputs[idx].clone(),\n                test_runner,\n                fuzz_state,\n            );\n            arg_mutation_rounds -= 1;\n        }\n\n        tx.call_details.calldata =\n            function.abi_encode_input(&prev_inputs).map_err(|e| eyre!(e.to_string()))?.into();\n        Ok(())\n    }\n\n    // Sync Methods.\n\n    /// Imports the new corpus entries from the `sync` directory.\n    /// These contain tx sequences which are replayed and used to update the history map.\n    fn load_sync_corpus(&self) -> Result<Vec<(CorpusDirEntry, Vec<BasicTxDetails>)>> {\n        let Some(worker_dir) = &self.worker_dir else {\n            return Ok(vec![]);\n        };\n\n        let sync_dir = worker_dir.join(SYNC_DIR);\n        if !sync_dir.is_dir() {\n            return Ok(vec![]);\n        }\n\n        let mut imports = vec![];\n        for entry in read_corpus_dir(&sync_dir) {\n            if entry.timestamp <= self.last_sync_timestamp {\n                continue;\n            }\n            let tx_seq = entry.read_tx_seq()?;\n            if tx_seq.is_empty() {\n                warn!(target: \"corpus\", \"skipping empty corpus entry: {}\", entry.path.display());\n                continue;\n            }\n            imports.push((entry, tx_seq));\n        }\n\n        if !imports.is_empty() {\n            debug!(target: \"corpus\", \"imported {} new corpus entries\", imports.len());\n        }\n\n        Ok(imports)\n    }\n\n    /// Syncs and calibrates the in memory corpus and updates the history_map if new coverage is\n    /// found from the corpus findings of other workers.\n    #[instrument(skip_all)]\n    fn calibrate(\n        &mut self,\n        executor: &Executor,\n        fuzzed_function: Option<&Function>,\n        fuzzed_contracts: Option<&FuzzRunIdentifiedContracts>,\n    ) -> Result<()> {\n        let Some(worker_dir) = &self.worker_dir else {\n            return Ok(());\n        };\n        let corpus_dir = worker_dir.join(CORPUS_DIR);\n\n        let mut executor = executor.clone();\n        for (entry, tx_seq) in self.load_sync_corpus()? {\n            let mut new_coverage_on_sync = false;\n            for tx in &tx_seq {\n                if !Self::can_replay_tx(tx, fuzzed_function, fuzzed_contracts) {\n                    continue;\n                }\n\n                let mut call_result = execute_tx(&mut executor, tx)?;\n\n                // Check if this provides new coverage.\n                let (new_coverage, is_edge) =\n                    call_result.merge_edge_coverage(&mut self.history_map);\n\n                if new_coverage {\n                    self.metrics.update_seen(is_edge);\n                    new_coverage_on_sync = true;\n                }\n\n                // Commit only for stateful tests.\n                if fuzzed_contracts.is_some() {\n                    executor.commit(&mut call_result);\n                }\n\n                trace!(\n                    target: \"corpus\",\n                    %new_coverage,\n                    ?tx,\n                    \"replayed tx for syncing\",\n                );\n            }\n\n            let sync_path = &entry.path;\n            if new_coverage_on_sync {\n                // Move file from sync/ to corpus/ directory.\n                let corpus_path = corpus_dir.join(sync_path.components().next_back().unwrap());\n                if let Err(err) = std::fs::rename(sync_path, &corpus_path) {\n                    debug!(target: \"corpus\", %err, \"failed to move synced corpus from {sync_path:?} to {corpus_path:?} dir\");\n                    continue;\n                }\n\n                debug!(\n                    target: \"corpus\",\n                    name=%entry.name(),\n                    \"moved synced corpus to corpus dir\",\n                );\n\n                let corpus_entry = CorpusEntry::new_existing(tx_seq.to_vec(), entry.path.clone())?;\n                self.in_memory_corpus.push(corpus_entry);\n            } else {\n                // Remove the file as it did not generate new coverage.\n                if let Err(err) = std::fs::remove_file(&entry.path) {\n                    debug!(target: \"corpus\", %err, \"failed to remove synced corpus from {sync_path:?}\");\n                    continue;\n                }\n                trace!(target: \"corpus\", \"removed synced corpus from {sync_path:?}\");\n            }\n        }\n\n        Ok(())\n    }\n\n    /// Exports the new corpus entries to the master worker's sync dir.\n    #[instrument(skip_all)]\n    fn export_to_master(&self) -> Result<()> {\n        // Master doesn't export (it only receives from others).\n        assert_ne!(self.id, 0, \"non-master only\");\n\n        // Early return if no new entries or corpus dir not configured.\n        if self.new_entry_indices.is_empty() || self.worker_dir.is_none() {\n            return Ok(());\n        }\n\n        let worker_dir = self.worker_dir.as_ref().unwrap();\n        let Some(master_sync_dir) = self\n            .config\n            .corpus_dir\n            .as_ref()\n            .map(|dir| dir.join(format!(\"{WORKER}0\")).join(SYNC_DIR))\n        else {\n            return Ok(());\n        };\n\n        let mut exported = 0;\n        let corpus_dir = worker_dir.join(CORPUS_DIR);\n\n        for &index in &self.new_entry_indices {\n            let Some(corpus) = self.in_memory_corpus.get(index) else { continue };\n            let file_name = corpus.file_name(self.config.corpus_gzip);\n            let file_path = corpus_dir.join(&file_name);\n            let sync_path = master_sync_dir.join(&file_name);\n            if let Err(err) = std::fs::hard_link(&file_path, &sync_path) {\n                debug!(target: \"corpus\", %err, \"failed to export corpus {}\", corpus.uuid);\n                continue;\n            }\n            exported += 1;\n        }\n\n        debug!(target: \"corpus\", \"exported {exported} new corpus entries\");\n\n        Ok(())\n    }\n\n    /// Exports the global corpus to the `sync/` directories of all the non-master workers.\n    #[instrument(skip_all)]\n    fn export_to_workers(&mut self, num_workers: usize) -> Result<()> {\n        assert_eq!(self.id, 0, \"master worker only\");\n        if self.worker_dir.is_none() {\n            return Ok(());\n        }\n\n        let worker_dir = self.worker_dir.as_ref().unwrap();\n        let master_corpus_dir = worker_dir.join(CORPUS_DIR);\n        let filtered_master_corpus = read_corpus_dir(&master_corpus_dir)\n            .filter(|entry| entry.timestamp > self.last_sync_timestamp)\n            .collect::<Vec<_>>();\n        let mut any_distributed = false;\n        for target_worker in 1..num_workers {\n            let target_dir = self\n                .config\n                .corpus_dir\n                .as_ref()\n                .unwrap()\n                .join(format!(\"{WORKER}{target_worker}\"))\n                .join(SYNC_DIR);\n\n            if !target_dir.is_dir() {\n                foundry_common::fs::create_dir_all(&target_dir)?;\n            }\n\n            for entry in &filtered_master_corpus {\n                let name = entry.name();\n                let sync_path = target_dir.join(name);\n                if let Err(err) = std::fs::hard_link(&entry.path, &sync_path) {\n                    debug!(target: \"corpus\", %err, from=?entry.path, to=?sync_path, \"failed to distribute corpus\");\n                    continue;\n                }\n                any_distributed = true;\n                trace!(target: \"corpus\", %name, ?target_dir, \"distributed corpus\");\n            }\n        }\n\n        debug!(target: \"corpus\", %any_distributed, \"distributed master corpus to all workers\");\n\n        Ok(())\n    }\n\n    // TODO(dani): currently only master syncs metrics?\n    /// Syncs local metrics with global corpus metrics by calculating and applying deltas.\n    pub(crate) fn sync_metrics(&mut self, global_corpus_metrics: &GlobalCorpusMetrics) {\n        // Calculate delta metrics since last sync.\n        let edges_delta = self\n            .metrics\n            .cumulative_edges_seen\n            .saturating_sub(self.last_sync_metrics.cumulative_edges_seen);\n        let features_delta = self\n            .metrics\n            .cumulative_features_seen\n            .saturating_sub(self.last_sync_metrics.cumulative_features_seen);\n        // For corpus count and favored items, calculate deltas.\n        let corpus_count_delta =\n            self.metrics.corpus_count as isize - self.last_sync_metrics.corpus_count as isize;\n        let favored_delta =\n            self.metrics.favored_items as isize - self.last_sync_metrics.favored_items as isize;\n\n        // Add delta values to global metrics.\n\n        if edges_delta > 0 {\n            global_corpus_metrics.cumulative_edges_seen.fetch_add(edges_delta, Ordering::Relaxed);\n        }\n        if features_delta > 0 {\n            global_corpus_metrics\n                .cumulative_features_seen\n                .fetch_add(features_delta, Ordering::Relaxed);\n        }\n\n        if corpus_count_delta > 0 {\n            global_corpus_metrics\n                .corpus_count\n                .fetch_add(corpus_count_delta as usize, Ordering::Relaxed);\n        } else if corpus_count_delta < 0 {\n            global_corpus_metrics\n                .corpus_count\n                .fetch_sub((-corpus_count_delta) as usize, Ordering::Relaxed);\n        }\n\n        if favored_delta > 0 {\n            global_corpus_metrics\n                .favored_items\n                .fetch_add(favored_delta as usize, Ordering::Relaxed);\n        } else if favored_delta < 0 {\n            global_corpus_metrics\n                .favored_items\n                .fetch_sub((-favored_delta) as usize, Ordering::Relaxed);\n        }\n\n        // Store current metrics as last sync metrics for next delta calculation.\n        self.last_sync_metrics = self.metrics.clone();\n    }\n\n    /// Syncs the workers in_memory_corpus and history_map with the findings from other workers.\n    #[instrument(skip_all)]\n    pub fn sync(\n        &mut self,\n        num_workers: usize,\n        executor: &Executor,\n        fuzzed_function: Option<&Function>,\n        fuzzed_contracts: Option<&FuzzRunIdentifiedContracts>,\n        global_corpus_metrics: &GlobalCorpusMetrics,\n    ) -> Result<()> {\n        trace!(target: \"corpus\", \"syncing\");\n\n        self.sync_metrics(global_corpus_metrics);\n\n        self.calibrate(executor, fuzzed_function, fuzzed_contracts)?;\n        if self.id == 0 {\n            self.export_to_workers(num_workers)?;\n        } else {\n            self.export_to_master()?;\n        }\n\n        let last_sync = SystemTime::now().duration_since(UNIX_EPOCH)?.as_secs();\n        self.last_sync_timestamp = last_sync;\n\n        self.new_entry_indices.clear();\n\n        debug!(target: \"corpus\", last_sync, \"synced\");\n\n        Ok(())\n    }\n\n    /// Helper to check if a tx can be replayed.\n    fn can_replay_tx(\n        tx: &BasicTxDetails,\n        fuzzed_function: Option<&Function>,\n        fuzzed_contracts: Option<&FuzzRunIdentifiedContracts>,\n    ) -> bool {\n        fuzzed_contracts.is_some_and(|contracts| contracts.targets.lock().can_replay(tx))\n            || fuzzed_function.is_some_and(|function| {\n                tx.call_details\n                    .calldata\n                    .get(..4)\n                    .is_some_and(|selector| function.selector() == selector)\n            })\n    }\n}\n\nfn read_corpus_dir(path: &Path) -> impl Iterator<Item = CorpusDirEntry> {\n    let dir = match std::fs::read_dir(path) {\n        Ok(dir) => dir,\n        Err(err) => {\n            debug!(%err, ?path, \"failed to read corpus directory\");\n            return vec![].into_iter();\n        }\n    };\n    dir.filter_map(|res| match res {\n        Ok(entry) => {\n            let path = entry.path();\n            if !path.is_file() {\n                return None;\n            }\n            let name = if path.is_file()\n                && let Some(name) = path.file_name()\n                && let Some(name) = name.to_str()\n            {\n                name\n            } else {\n                return None;\n            };\n\n            if let Ok((uuid, timestamp)) = parse_corpus_filename(name) {\n                Some(CorpusDirEntry { path, uuid, timestamp })\n            } else {\n                debug!(target: \"corpus\", ?path, \"failed to parse corpus filename\");\n                None\n            }\n        }\n        Err(err) => {\n            debug!(%err, \"failed to read corpus directory entry\");\n            None\n        }\n    })\n    .collect::<Vec<_>>()\n    .into_iter()\n}\n\nstruct CorpusDirEntry {\n    path: PathBuf,\n    uuid: Uuid,\n    timestamp: u64,\n}\n\nimpl CorpusDirEntry {\n    fn name(&self) -> &str {\n        self.path.file_name().unwrap().to_str().unwrap()\n    }\n\n    fn read_tx_seq(&self) -> foundry_common::fs::Result<Vec<BasicTxDetails>> {\n        let path = &self.path;\n        if path.extension() == Some(\"gz\".as_ref()) {\n            foundry_common::fs::read_json_gzip_file(path)\n        } else {\n            foundry_common::fs::read_json_file(path)\n        }\n    }\n}\n\n/// Parses the corpus filename and returns the uuid and timestamp associated with it.\nfn parse_corpus_filename(name: &str) -> Result<(Uuid, u64)> {\n    let name = name.trim_end_matches(\".gz\").trim_end_matches(\".json\");\n\n    let (uuid_str, timestamp_str) =\n        name.rsplit_once('-').ok_or_else(|| eyre!(\"invalid corpus filename format: {name}\"))?;\n\n    let uuid = Uuid::parse_str(uuid_str)?;\n    let timestamp = timestamp_str.parse()?;\n\n    Ok((uuid, timestamp))\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use alloy_primitives::Address;\n    use std::fs;\n\n    fn basic_tx() -> BasicTxDetails {\n        BasicTxDetails {\n            warp: None,\n            roll: None,\n            sender: Address::ZERO,\n            call_details: foundry_evm_fuzz::CallDetails {\n                target: Address::ZERO,\n                calldata: Bytes::new(),\n            },\n        }\n    }\n\n    fn temp_corpus_dir() -> PathBuf {\n        let dir = std::env::temp_dir().join(format!(\"foundry-corpus-tests-{}\", Uuid::new_v4()));\n        let _ = fs::create_dir_all(&dir);\n        dir\n    }\n\n    fn new_manager_with_single_corpus() -> (WorkerCorpus, Uuid) {\n        let tx_gen = Just(basic_tx()).boxed();\n        let config = FuzzCorpusConfig {\n            corpus_dir: Some(temp_corpus_dir()),\n            corpus_gzip: false,\n            corpus_min_mutations: 0,\n            corpus_min_size: 0,\n            ..Default::default()\n        };\n\n        let tx_seq = vec![basic_tx()];\n        let corpus = CorpusEntry::new(tx_seq);\n        let seed_uuid = corpus.uuid;\n\n        // Create corpus root dir and worker subdirectory.\n        let corpus_root = config.corpus_dir.clone().unwrap();\n        let worker_subdir = corpus_root.join(\"worker0\");\n        let _ = fs::create_dir_all(&worker_subdir);\n\n        let manager = WorkerCorpus {\n            id: 0,\n            tx_generator: tx_gen,\n            mutation_generator: Just(MutationType::Repeat).boxed(),\n            config: config.into(),\n            in_memory_corpus: vec![corpus],\n            current_mutated: Some(seed_uuid),\n            failed_replays: 0,\n            history_map: vec![0u8; COVERAGE_MAP_SIZE],\n            metrics: CorpusMetrics::default(),\n            new_entry_indices: Default::default(),\n            last_sync_timestamp: 0,\n            worker_dir: Some(corpus_root),\n            last_sync_metrics: CorpusMetrics::default(),\n        };\n\n        (manager, seed_uuid)\n    }\n\n    #[test]\n    fn favored_sets_true_and_metrics_increment_when_ratio_gt_threshold() {\n        let (mut manager, uuid) = new_manager_with_single_corpus();\n        let corpus = manager.in_memory_corpus.iter_mut().find(|c| c.uuid == uuid).unwrap();\n        corpus.total_mutations = 4;\n        corpus.new_finds_produced = 2; // ratio currently 0.5 if both increment → 3/5 = 0.6 > 0.3.\n        corpus.is_favored = false;\n\n        // Ensure metrics start at 0.\n        assert_eq!(manager.metrics.favored_items, 0);\n\n        // Mark this as the currently mutated corpus and process a run with new coverage.\n        manager.current_mutated = Some(uuid);\n        manager.process_inputs(&[basic_tx()], true);\n\n        let corpus = manager.in_memory_corpus.iter().find(|c| c.uuid == uuid).unwrap();\n        assert!(corpus.is_favored, \"expected favored to be true when ratio > threshold\");\n        assert_eq!(\n            manager.metrics.favored_items, 1,\n            \"favored_items should increment on false→true\"\n        );\n    }\n\n    #[test]\n    fn favored_sets_false_and_metrics_decrement_when_ratio_lt_threshold() {\n        let (mut manager, uuid) = new_manager_with_single_corpus();\n        let corpus = manager.in_memory_corpus.iter_mut().find(|c| c.uuid == uuid).unwrap();\n        corpus.total_mutations = 9;\n        corpus.new_finds_produced = 3; // 3/9 = 0.333.. > 0.3; after +1: 3/10 = 0.3 => not favored.\n        corpus.is_favored = true; // Start as favored.\n\n        manager.metrics.favored_items = 1;\n\n        // Next run does NOT produce coverage → only total_mutations increments, ratio drops.\n        manager.current_mutated = Some(uuid);\n        manager.process_inputs(&[basic_tx()], false);\n\n        let corpus = manager.in_memory_corpus.iter().find(|c| c.uuid == uuid).unwrap();\n        assert!(!corpus.is_favored, \"expected favored to be false when ratio < threshold\");\n        assert_eq!(\n            manager.metrics.favored_items, 0,\n            \"favored_items should decrement on true→false\"\n        );\n    }\n\n    #[test]\n    fn favored_is_false_on_ratio_equal_threshold() {\n        let (mut manager, uuid) = new_manager_with_single_corpus();\n        let corpus = manager.in_memory_corpus.iter_mut().find(|c| c.uuid == uuid).unwrap();\n        // After this call with new_coverage=true, totals become 10 and 3 → 0.3.\n        corpus.total_mutations = 9;\n        corpus.new_finds_produced = 2;\n        corpus.is_favored = false;\n\n        manager.current_mutated = Some(uuid);\n        manager.process_inputs(&[basic_tx()], true);\n\n        let corpus = manager.in_memory_corpus.iter().find(|c| c.uuid == uuid).unwrap();\n        assert!(\n            !(corpus.is_favored),\n            \"with strict '>' comparison, favored must be false when ratio == threshold\"\n        );\n    }\n\n    #[test]\n    fn eviction_skips_favored_and_evicts_non_favored() {\n        // Manager with two corpora.\n        let tx_gen = Just(basic_tx()).boxed();\n        let config = FuzzCorpusConfig {\n            corpus_dir: Some(temp_corpus_dir()),\n            corpus_min_mutations: 0,\n            corpus_min_size: 0,\n            ..Default::default()\n        };\n\n        let mut favored = CorpusEntry::new(vec![basic_tx()]);\n        favored.total_mutations = 2;\n        favored.is_favored = true;\n\n        let mut non_favored = CorpusEntry::new(vec![basic_tx()]);\n        non_favored.total_mutations = 2;\n        non_favored.is_favored = false;\n        let non_favored_uuid = non_favored.uuid;\n\n        let corpus_root = temp_corpus_dir();\n        let worker_subdir = corpus_root.join(\"worker0\");\n        fs::create_dir_all(&worker_subdir).unwrap();\n\n        let mut manager = WorkerCorpus {\n            id: 0,\n            tx_generator: tx_gen,\n            mutation_generator: Just(MutationType::Repeat).boxed(),\n            config: config.into(),\n            in_memory_corpus: vec![favored, non_favored],\n            current_mutated: None,\n            failed_replays: 0,\n            history_map: vec![0u8; COVERAGE_MAP_SIZE],\n            metrics: CorpusMetrics::default(),\n            new_entry_indices: Default::default(),\n            last_sync_timestamp: 0,\n            worker_dir: Some(corpus_root),\n            last_sync_metrics: CorpusMetrics::default(),\n        };\n\n        // First eviction should remove the non-favored one.\n        manager.evict_oldest_corpus().unwrap();\n        assert_eq!(manager.in_memory_corpus.len(), 1);\n        assert!(manager.in_memory_corpus.iter().all(|c| c.is_favored));\n\n        // Attempt eviction again: only favored remains → should not remove.\n        manager.evict_oldest_corpus().unwrap();\n        assert_eq!(manager.in_memory_corpus.len(), 1, \"favored corpus must not be evicted\");\n\n        // Ensure the evicted one was the non-favored uuid.\n        assert!(manager.in_memory_corpus.iter().all(|c| c.uuid != non_favored_uuid));\n    }\n}\n"
  },
  {
    "path": "crates/evm/evm/src/executors/fuzz/mod.rs",
    "content": "use crate::executors::{\n    DURATION_BETWEEN_METRICS_REPORT, EarlyExit, Executor, FuzzTestTimer, RawCallResult,\n    corpus::{GlobalCorpusMetrics, WorkerCorpus},\n};\nuse alloy_dyn_abi::JsonAbiExt;\nuse alloy_json_abi::Function;\nuse alloy_primitives::{Address, Bytes, Log, U256, keccak256, map::HashMap};\nuse eyre::Result;\nuse foundry_common::sh_println;\nuse foundry_config::FuzzConfig;\nuse foundry_evm_core::{\n    Breakpoints,\n    constants::{CHEATCODE_ADDRESS, MAGIC_ASSUME},\n    decode::{RevertDecoder, SkipReason},\n};\nuse foundry_evm_coverage::HitMaps;\nuse foundry_evm_fuzz::{\n    BaseCounterExample, BasicTxDetails, CallDetails, CounterExample, FuzzCase, FuzzError,\n    FuzzFixtures, FuzzTestResult,\n    strategies::{EvmFuzzState, fuzz_calldata, fuzz_calldata_from_state},\n};\nuse foundry_evm_traces::SparsedTraceArena;\nuse indicatif::ProgressBar;\nuse proptest::{\n    strategy::Strategy,\n    test_runner::{RngAlgorithm, TestCaseError, TestRng, TestRunner},\n};\nuse rayon::iter::{IntoParallelIterator, ParallelIterator};\nuse serde_json::json;\nuse std::{\n    sync::{\n        Arc, OnceLock,\n        atomic::{AtomicU32, Ordering},\n    },\n    time::{Instant, SystemTime, UNIX_EPOCH},\n};\n\nmod types;\npub use types::{CaseOutcome, CounterExampleOutcome, FuzzOutcome};\n\n/// Corpus syncs across workers every `SYNC_INTERVAL` runs.\nconst SYNC_INTERVAL: u32 = 1000;\n\n/// Minimum number of runs per worker.\n/// This is mainly to reduce the overall number of rayon jobs.\nconst MIN_RUNS_PER_WORKER: u32 = 64;\n\n#[derive(Default)]\nstruct WorkerState {\n    /// Worker identifier\n    id: usize,\n    /// First fuzz case this worker encountered (with global run number)\n    first_case: Option<(u32, FuzzCase)>,\n    /// Gas usage for all cases this worker ran\n    gas_by_case: Vec<(u64, u64)>,\n    /// Counterexample if this worker found one\n    counterexample: (Bytes, RawCallResult),\n    /// Traces collected by this worker\n    ///\n    /// Stores up to `max_traces_to_collect` which is `config.gas_report_samples / num_workers`\n    traces: Vec<SparsedTraceArena>,\n    /// Last breakpoints from this worker\n    breakpoints: Option<Breakpoints>,\n    /// Coverage collected by this worker\n    coverage: Option<HitMaps>,\n    /// Logs from all cases this worker ran\n    logs: Vec<Log>,\n    /// Deprecated cheatcodes seen by this worker\n    deprecated_cheatcodes: HashMap<&'static str, Option<&'static str>>,\n    /// Number of runs this worker completed\n    runs: u32,\n    /// Failure reason if this worker failed\n    failure: Option<TestCaseError>,\n    /// Last run timestamp in milliseconds\n    ///\n    /// Used to identify which worker ran last and collect its traces and call breakpoints\n    last_run_timestamp: u128,\n    /// Failed corpus replays\n    failed_corpus_replays: usize,\n}\n\nimpl WorkerState {\n    fn new(worker_id: usize) -> Self {\n        Self { id: worker_id, ..Default::default() }\n    }\n}\n\n/// Shared state for coordinating parallel fuzz workers\nstruct SharedFuzzState {\n    state: EvmFuzzState,\n    /// Total runs across workers\n    total_runs: Arc<AtomicU32>,\n    /// Found failure\n    ///\n    /// The worker that found the failure sets it's ID.\n    ///\n    /// This ID is then used to correctly extract the failure reason and counterexample.\n    failed_worker_id: OnceLock<usize>,\n    /// Total rejects across workers\n    total_rejects: Arc<AtomicU32>,\n    /// Fuzz timer\n    timer: FuzzTestTimer,\n    /// Global corpus metrics\n    global_corpus_metrics: GlobalCorpusMetrics,\n\n    /// Global test suite early exit.\n    global_early_exit: EarlyExit,\n    /// Local fuzz early exit.\n    local_early_exit: EarlyExit,\n}\n\nimpl SharedFuzzState {\n    fn new(state: EvmFuzzState, timeout: Option<u32>, early_exit: EarlyExit) -> Self {\n        Self {\n            state,\n            total_runs: Arc::new(AtomicU32::new(0)),\n            failed_worker_id: OnceLock::new(),\n            total_rejects: Arc::new(AtomicU32::new(0)),\n            timer: FuzzTestTimer::new(timeout),\n            global_corpus_metrics: GlobalCorpusMetrics::default(),\n            global_early_exit: early_exit,\n            local_early_exit: EarlyExit::new(true),\n        }\n    }\n\n    /// Increments the number of runs and returns the new value.\n    fn increment_runs(&self) -> u32 {\n        self.total_runs.fetch_add(1, Ordering::Relaxed) + 1\n    }\n\n    /// Increments and returns the new value of the number of rejected tests.\n    fn increment_rejects(&self) -> u32 {\n        self.total_rejects.fetch_add(1, Ordering::Relaxed) + 1\n    }\n\n    /// Returns `true` if the worker should continue running.\n    fn should_continue(&self) -> bool {\n        !(self.global_early_exit.should_stop()\n            || self.local_early_exit.should_stop()\n            || self.timer.is_timed_out())\n    }\n\n    /// Returns true if the worker was able to claim the failure, false if failure was set by\n    /// another worker\n    fn try_claim_failure(&self, worker_id: usize) -> bool {\n        let mut claimed = false;\n        let _ = self.failed_worker_id.get_or_init(|| {\n            claimed = true;\n            self.local_early_exit.record_failure();\n            worker_id\n        });\n        claimed\n    }\n}\n\n/// Wrapper around an [`Executor`] which provides fuzzing support using [`proptest`].\n///\n/// After instantiation, calling `fuzz` will proceed to hammer the deployed smart contract with\n/// inputs, until it finds a counterexample. The provided [`TestRunner`] contains all the\n/// configuration which can be overridden via [environment variables](proptest::test_runner::Config)\npub struct FuzzedExecutor {\n    /// The EVM executor.\n    executor_f: Executor,\n    /// The fuzzer\n    runner: TestRunner,\n    /// The account that calls tests.\n    sender: Address,\n    /// The fuzz configuration.\n    config: FuzzConfig,\n    /// The persisted counterexample to be replayed, if any.\n    persisted_failure: Option<BaseCounterExample>,\n    /// The number of parallel workers.\n    num_workers: usize,\n}\n\nimpl FuzzedExecutor {\n    /// Instantiates a fuzzed executor given a testrunner\n    pub fn new(\n        executor: Executor,\n        runner: TestRunner,\n        sender: Address,\n        config: FuzzConfig,\n        persisted_failure: Option<BaseCounterExample>,\n    ) -> Self {\n        let mut max_workers = Ord::max(1, config.runs / MIN_RUNS_PER_WORKER);\n        if config.runs == 0 {\n            max_workers = 0;\n        }\n        let num_workers = Ord::min(rayon::current_num_threads(), max_workers as usize);\n        Self { executor_f: executor, runner, sender, config, persisted_failure, num_workers }\n    }\n\n    /// Fuzzes the provided function, assuming it is available at the contract at `address`\n    /// If `should_fail` is set to `true`, then it will stop only when there's a success\n    /// test case.\n    ///\n    /// Returns a list of all the consumed gas and calldata of every fuzz case.\n    #[allow(clippy::too_many_arguments)]\n    pub fn fuzz(\n        &mut self,\n        func: &Function,\n        fuzz_fixtures: &FuzzFixtures,\n        state: EvmFuzzState,\n        address: Address,\n        rd: &RevertDecoder,\n        progress: Option<&ProgressBar>,\n        early_exit: &EarlyExit,\n        tokio_handle: &tokio::runtime::Handle,\n    ) -> Result<FuzzTestResult> {\n        let shared_state = SharedFuzzState::new(state, self.config.timeout, early_exit.clone());\n\n        debug!(n = self.num_workers, \"spawning workers\");\n        let workers = (0..self.num_workers)\n            .into_par_iter()\n            .map(|worker_id| {\n                let _guard = tokio_handle.enter();\n                let _guard = info_span!(\"fuzz_worker\", id = worker_id).entered();\n                let timer = Instant::now();\n                let r = self.run_worker(\n                    worker_id,\n                    func,\n                    fuzz_fixtures,\n                    address,\n                    rd,\n                    &shared_state,\n                    progress,\n                );\n                debug!(\"finished in {:?}\", timer.elapsed());\n                r\n            })\n            .collect::<Result<Vec<_>>>()?;\n\n        Ok(self.aggregate_results(workers, func, &shared_state))\n    }\n\n    /// Granular and single-step function that runs only one fuzz and returns either a `CaseOutcome`\n    /// or a `CounterExampleOutcome`\n    fn single_fuzz(\n        &self,\n        executor: &Executor,\n        address: Address,\n        calldata: Bytes,\n        coverage_metrics: &mut WorkerCorpus,\n    ) -> Result<FuzzOutcome, TestCaseError> {\n        let mut call = executor\n            .call_raw(self.sender, address, calldata.clone(), U256::ZERO)\n            .map_err(|e| TestCaseError::fail(e.to_string()))?;\n        let new_coverage = coverage_metrics.merge_edge_coverage(&mut call);\n        coverage_metrics.process_inputs(\n            &[BasicTxDetails {\n                warp: None,\n                roll: None,\n                sender: self.sender,\n                call_details: CallDetails { target: address, calldata: calldata.clone() },\n            }],\n            new_coverage,\n        );\n\n        // Handle `vm.assume`.\n        if call.result.as_ref() == MAGIC_ASSUME {\n            return Err(TestCaseError::reject(FuzzError::AssumeReject));\n        }\n\n        let (breakpoints, deprecated_cheatcodes) =\n            call.cheatcodes.as_ref().map_or_else(Default::default, |cheats| {\n                (cheats.breakpoints.clone(), cheats.deprecated.clone())\n            });\n\n        // Consider call success if test should not fail on reverts and reverter is not the\n        // cheatcode or test address.\n        let success = if !self.config.fail_on_revert\n            && call\n                .reverter\n                .is_some_and(|reverter| reverter != address && reverter != CHEATCODE_ADDRESS)\n        {\n            true\n        } else {\n            executor.is_raw_call_mut_success(address, &mut call, false)\n        };\n\n        if success {\n            Ok(FuzzOutcome::Case(CaseOutcome {\n                case: FuzzCase { gas: call.gas_used, stipend: call.stipend },\n                traces: call.traces,\n                coverage: call.line_coverage,\n                breakpoints,\n                logs: call.logs,\n                deprecated_cheatcodes,\n            }))\n        } else {\n            Ok(FuzzOutcome::CounterExample(CounterExampleOutcome {\n                exit_reason: call.exit_reason,\n                counterexample: (calldata, call),\n                breakpoints,\n            }))\n        }\n    }\n\n    /// Aggregates the results from all workers\n    fn aggregate_results(\n        &self,\n        mut workers: Vec<WorkerState>,\n        func: &Function,\n        shared_state: &SharedFuzzState,\n    ) -> FuzzTestResult {\n        let mut result = FuzzTestResult::default();\n        if workers.is_empty() {\n            result.success = true;\n            return result;\n        }\n\n        // Find first case and last run worker. Set `failed_corpus_replays`.\n        let mut first_case_candidate = None;\n        let mut last_run_worker = None;\n        for (i, worker) in workers.iter().enumerate() {\n            if let Some((run, ref case)) = worker.first_case\n                && first_case_candidate.as_ref().is_none_or(|&(r, _)| run < r)\n            {\n                first_case_candidate = Some((run, case.clone()));\n            }\n\n            if last_run_worker.is_none_or(|(t, _)| worker.last_run_timestamp > t) {\n                last_run_worker = Some((worker.last_run_timestamp, i));\n            }\n\n            // Only set replays from master which is responsible for replaying persisted corpus.\n            if worker.id == 0 {\n                result.failed_corpus_replays = worker.failed_corpus_replays;\n            }\n        }\n        result.first_case = first_case_candidate.map(|(_, case)| case).unwrap_or_default();\n        let (_, last_run_worker_idx) = last_run_worker.expect(\"at least one worker\");\n\n        if let Some(&failed_worker_id) = shared_state.failed_worker_id.get() {\n            result.success = false;\n\n            let failed_worker_idx = workers.iter().position(|w| w.id == failed_worker_id).unwrap();\n            let failed_worker = &mut workers[failed_worker_idx];\n\n            let (calldata, call) = std::mem::take(&mut failed_worker.counterexample);\n            result.labels = call.labels;\n            result.traces = call.traces.clone();\n            result.breakpoints = call.cheatcodes.map(|c| c.breakpoints);\n\n            match &failed_worker.failure {\n                Some(TestCaseError::Fail(reason)) => {\n                    let reason = reason.to_string();\n                    result.reason = (!reason.is_empty()).then_some(reason);\n                    let args = if let Some(data) = calldata.get(4..) {\n                        func.abi_decode_input(data).unwrap_or_default()\n                    } else {\n                        vec![]\n                    };\n                    result.counterexample = Some(CounterExample::Single(\n                        BaseCounterExample::from_fuzz_call(calldata, args, call.traces),\n                    ));\n                }\n                Some(TestCaseError::Reject(reason)) => {\n                    let reason = reason.to_string();\n                    result.reason = (!reason.is_empty()).then_some(reason);\n                }\n                None => {}\n            }\n        } else {\n            let last_run_worker = &workers[last_run_worker_idx];\n            result.success = true;\n            result.traces = last_run_worker.traces.last().cloned();\n            result.breakpoints = last_run_worker.breakpoints.clone();\n        }\n\n        if !self.config.show_logs {\n            result.logs = workers[last_run_worker_idx].logs.clone();\n        }\n\n        for mut worker in workers {\n            result.gas_by_case.append(&mut worker.gas_by_case);\n            if self.config.show_logs {\n                result.logs.append(&mut worker.logs);\n            }\n            result.gas_report_traces.extend(worker.traces.into_iter().map(|t| t.arena));\n            HitMaps::merge_opt(&mut result.line_coverage, worker.coverage);\n            result.deprecated_cheatcodes.extend(worker.deprecated_cheatcodes);\n        }\n\n        if let Some(reason) = &result.reason\n            && let Some(reason) = SkipReason::decode_self(reason)\n        {\n            result.skipped = true;\n            result.reason = reason.0;\n        }\n\n        result\n    }\n\n    /// Runs a single fuzz worker\n    #[allow(clippy::too_many_arguments)]\n    fn run_worker(\n        &self,\n        worker_id: usize,\n        func: &Function,\n        fuzz_fixtures: &FuzzFixtures,\n        address: Address,\n        rd: &RevertDecoder,\n        shared_state: &SharedFuzzState,\n        progress: Option<&ProgressBar>,\n    ) -> Result<WorkerState> {\n        // Prepare\n        let dictionary_weight = self.config.dictionary.dictionary_weight.min(100);\n        let strategy = proptest::prop_oneof![\n            100 - dictionary_weight => fuzz_calldata(func.clone(), fuzz_fixtures),\n            dictionary_weight => fuzz_calldata_from_state(func.clone(), &shared_state.state),\n        ]\n        .prop_map(move |calldata| BasicTxDetails {\n            warp: None,\n            roll: None,\n            sender: Default::default(),\n            call_details: CallDetails { target: Default::default(), calldata },\n        });\n\n        let mut corpus = WorkerCorpus::new(\n            worker_id,\n            self.config.corpus.clone(),\n            strategy.boxed(),\n            // Master worker replays the persisted corpus using the executor\n            if worker_id == 0 { Some(&self.executor_f) } else { None },\n            Some(func),\n            None, // fuzzed_contracts for invariant tests\n        )?;\n        let mut executor = self.executor_f.clone();\n\n        let mut worker = WorkerState::new(worker_id);\n        // We want to collect at least one trace which will be displayed to user.\n        let max_traces_to_collect =\n            std::cmp::max(1, self.config.gas_report_samples / self.num_workers as u32);\n\n        let worker_runs = self.runs_per_worker(worker_id);\n        debug!(worker_runs);\n\n        let mut runner_config = self.runner.config().clone();\n        runner_config.cases = worker_runs;\n\n        let mut runner = if let Some(seed) = self.config.seed {\n            // For deterministic parallel fuzzing, derive a unique seed for each worker\n            let worker_seed = if worker_id == 0 {\n                // Master worker uses the provided seed as is.\n                seed\n            } else {\n                // Derive a worker-specific seed using keccak256(seed || worker_id)\n                let seed_data =\n                    [&seed.to_be_bytes::<32>()[..], &worker_id.to_be_bytes()[..]].concat();\n                U256::from_be_bytes(keccak256(seed_data).0)\n            };\n            trace!(target: \"forge::test\", ?worker_seed, \"deterministic seed for worker {worker_id}\");\n            let rng = TestRng::from_seed(RngAlgorithm::ChaCha, &worker_seed.to_be_bytes::<32>());\n            TestRunner::new_with_rng(runner_config, rng)\n        } else {\n            TestRunner::new(runner_config)\n        };\n\n        let mut persisted_failure = self.persisted_failure.as_ref().filter(|_| worker_id == 0);\n\n        // Offset to stagger corpus syncs across workers; so that workers don't sync at the same\n        // time.\n        let sync_offset = worker_id as u32 * 100;\n        let sync_threshold = SYNC_INTERVAL + sync_offset;\n        let mut runs_since_sync = sync_threshold; // Always sync at the start.\n        let mut last_metrics_report = Instant::now();\n        // Continue while:\n        // 1. Global state allows (not timed out, not at global limit, no failure found)\n        // 2. Worker hasn't reached its specific run limit\n        'stop: while shared_state.should_continue() && worker.runs < worker_runs {\n            // If counterexample recorded, replay it first, without incrementing runs.\n            let input = if worker_id == 0\n                && let Some(failure) = persisted_failure.take()\n                && failure.calldata.get(..4).is_some_and(|selector| func.selector() == selector)\n            {\n                failure.calldata.clone()\n            } else {\n                runs_since_sync += 1;\n                if runs_since_sync >= sync_threshold {\n                    let timer = Instant::now();\n                    corpus.sync(\n                        self.num_workers,\n                        &executor,\n                        Some(func),\n                        None,\n                        &shared_state.global_corpus_metrics,\n                    )?;\n                    trace!(\"finished corpus sync in {:?}\", timer.elapsed());\n                    runs_since_sync = 0;\n                }\n\n                if let Some(cheats) = executor.inspector_mut().cheatcodes.as_mut()\n                    && let Some(seed) = self.config.seed\n                {\n                    cheats.set_seed(seed.wrapping_add(U256::from(worker.runs)));\n                }\n\n                match corpus.new_input(&mut runner, &shared_state.state, func) {\n                    Ok(input) => input,\n                    Err(err) => {\n                        worker.failure = Some(TestCaseError::fail(format!(\n                            \"failed to generate fuzzed input in worker {}: {err}\",\n                            worker.id\n                        )));\n                        shared_state.try_claim_failure(worker_id);\n                        break 'stop;\n                    }\n                }\n            };\n\n            let mut inc_runs = || {\n                let total_runs = shared_state.increment_runs();\n                debug_assert!(\n                    shared_state.timer.is_enabled() || total_runs <= self.config.runs,\n                    \"worker runs were not distributed correctly\"\n                );\n                worker.runs += 1;\n                if let Some(progress) = progress {\n                    progress.inc(1);\n                }\n                total_runs\n            };\n\n            worker.last_run_timestamp = SystemTime::now().duration_since(UNIX_EPOCH)?.as_millis();\n            match self.single_fuzz(&executor, address, input, &mut corpus) {\n                Ok(fuzz_outcome) => match fuzz_outcome {\n                    FuzzOutcome::Case(case) => {\n                        let total_runs = inc_runs();\n\n                        if worker_id == 0 && self.config.corpus.collect_edge_coverage() {\n                            if let Some(progress) = progress {\n                                corpus.sync_metrics(&shared_state.global_corpus_metrics);\n                                progress\n                                    .set_message(format!(\"{}\", shared_state.global_corpus_metrics));\n                            } else if last_metrics_report.elapsed()\n                                > DURATION_BETWEEN_METRICS_REPORT\n                            {\n                                corpus.sync_metrics(&shared_state.global_corpus_metrics);\n                                // Display metrics inline.\n                                let metrics = json!({\n                                    \"timestamp\": SystemTime::now()\n                                        .duration_since(UNIX_EPOCH)?\n                                        .as_secs(),\n                                    \"test\": func.name,\n                                    \"metrics\": shared_state.global_corpus_metrics.load(),\n                                });\n                                let _ = sh_println!(\"{metrics}\");\n                                last_metrics_report = Instant::now();\n                            }\n                        }\n\n                        worker.gas_by_case.push((case.case.gas, case.case.stipend));\n\n                        if worker.first_case.is_none() {\n                            worker.first_case = Some((total_runs, case.case));\n                        }\n\n                        if let Some(call_traces) = case.traces {\n                            if worker.traces.len() == max_traces_to_collect as usize {\n                                worker.traces.pop();\n                            }\n                            worker.traces.push(call_traces);\n                            worker.breakpoints = Some(case.breakpoints);\n                        }\n\n                        // Always store logs from the last run in test_data.logs for display at\n                        // verbosity >= 2. When show_logs is true,\n                        // accumulate all logs. When false, only keep the last run's logs.\n                        if self.config.show_logs {\n                            worker.logs.extend(case.logs);\n                        } else {\n                            worker.logs = case.logs;\n                        }\n\n                        HitMaps::merge_opt(&mut worker.coverage, case.coverage);\n                        worker.deprecated_cheatcodes = case.deprecated_cheatcodes;\n                    }\n                    FuzzOutcome::CounterExample(CounterExampleOutcome {\n                        exit_reason: status,\n                        counterexample: outcome,\n                        ..\n                    }) => {\n                        inc_runs();\n\n                        let reason = rd.maybe_decode(&outcome.1.result, status);\n                        worker.logs.extend(outcome.1.logs.clone());\n                        worker.counterexample = outcome;\n                        worker.failure = Some(TestCaseError::fail(reason.unwrap_or_default()));\n                        shared_state.try_claim_failure(worker_id);\n                        break 'stop;\n                    }\n                },\n                Err(err) => match err {\n                    TestCaseError::Fail(_) => {\n                        worker.failure = Some(err);\n                        shared_state.try_claim_failure(worker_id);\n                        break 'stop;\n                    }\n                    TestCaseError::Reject(_) => {\n                        let max = self.config.max_test_rejects;\n\n                        let total = shared_state.increment_rejects();\n\n                        // Update progress bar to reflect rejected runs.\n                        // TODO(dani): (pre-existing) conflicts with corpus metrics `set_message`\n                        if !self.config.corpus.collect_edge_coverage()\n                            && let Some(progress) = progress\n                        {\n                            progress.set_message(format!(\"([{total}] rejected)\"));\n                        }\n\n                        if max > 0 && total > max {\n                            worker.failure =\n                                Some(TestCaseError::reject(FuzzError::TooManyRejects(max)));\n                            shared_state.try_claim_failure(worker_id);\n                            break 'stop;\n                        }\n                    }\n                },\n            }\n        }\n\n        if worker_id == 0 {\n            worker.failed_corpus_replays = corpus.failed_replays;\n        }\n\n        // Logs stats\n        trace!(\"worker {worker_id} fuzz stats\");\n        shared_state.state.log_stats();\n\n        Ok(worker)\n    }\n\n    /// Determines the number of runs per worker.\n    fn runs_per_worker(&self, worker_id: usize) -> u32 {\n        let worker_id = worker_id as u32;\n        let total_runs = self.config.runs;\n        let n = self.num_workers as u32;\n        let runs = total_runs / n;\n        let remainder = total_runs % n;\n        // Distribute the remainder evenly among the first `remainder` workers,\n        // assuming `worker_id` is in `0..n`.\n        if worker_id < remainder { runs + 1 } else { runs }\n    }\n}\n"
  },
  {
    "path": "crates/evm/evm/src/executors/fuzz/types.rs",
    "content": "use crate::executors::RawCallResult;\nuse alloy_primitives::{Bytes, Log, map::HashMap};\nuse foundry_evm_core::Breakpoints;\nuse foundry_evm_coverage::HitMaps;\nuse foundry_evm_fuzz::FuzzCase;\nuse foundry_evm_traces::SparsedTraceArena;\nuse revm::interpreter::InstructionResult;\n\n/// Returned by a single fuzz in the case of a successful run\n#[derive(Debug)]\npub struct CaseOutcome {\n    /// Data of a single fuzz test case.\n    pub case: FuzzCase,\n    /// The traces of the call.\n    pub traces: Option<SparsedTraceArena>,\n    /// The coverage info collected during the call.\n    pub coverage: Option<HitMaps>,\n    /// Breakpoints char pc map.\n    pub breakpoints: Breakpoints,\n    /// logs of a single fuzz test case.\n    pub logs: Vec<Log>,\n    // Deprecated cheatcodes mapped to their replacements.\n    pub deprecated_cheatcodes: HashMap<&'static str, Option<&'static str>>,\n}\n\n/// Returned by a single fuzz when a counterexample has been discovered\n#[derive(Debug)]\npub struct CounterExampleOutcome {\n    /// Minimal reproduction test case for failing test.\n    pub counterexample: (Bytes, RawCallResult),\n    /// The status of the call.\n    pub exit_reason: Option<InstructionResult>,\n    /// Breakpoints char pc map.\n    pub breakpoints: Breakpoints,\n}\n\n/// Outcome of a single fuzz\n#[derive(Debug)]\n#[expect(clippy::large_enum_variant)]\npub enum FuzzOutcome {\n    Case(CaseOutcome),\n    CounterExample(CounterExampleOutcome),\n}\n"
  },
  {
    "path": "crates/evm/evm/src/executors/invariant/error.rs",
    "content": "use super::InvariantContract;\nuse crate::executors::RawCallResult;\nuse alloy_primitives::{Address, Bytes};\nuse foundry_config::InvariantConfig;\nuse foundry_evm_core::decode::RevertDecoder;\nuse foundry_evm_fuzz::{BasicTxDetails, Reason, invariant::FuzzRunIdentifiedContracts};\nuse proptest::test_runner::TestError;\n\n/// Stores information about failures and reverts of the invariant tests.\n#[derive(Clone, Default)]\npub struct InvariantFailures {\n    /// Total number of reverts.\n    pub reverts: usize,\n    /// The latest revert reason of a run.\n    pub revert_reason: Option<String>,\n    /// Maps a broken invariant to its specific error.\n    pub error: Option<InvariantFuzzError>,\n}\n\nimpl InvariantFailures {\n    pub fn new() -> Self {\n        Self::default()\n    }\n\n    pub fn into_inner(self) -> (usize, Option<InvariantFuzzError>) {\n        (self.reverts, self.error)\n    }\n}\n\n#[derive(Clone, Debug)]\npub enum InvariantFuzzError {\n    Revert(FailedInvariantCaseData),\n    BrokenInvariant(FailedInvariantCaseData),\n    MaxAssumeRejects(u32),\n}\n\nimpl InvariantFuzzError {\n    pub fn revert_reason(&self) -> Option<String> {\n        match self {\n            Self::BrokenInvariant(case_data) | Self::Revert(case_data) => {\n                (!case_data.revert_reason.is_empty()).then(|| case_data.revert_reason.clone())\n            }\n            Self::MaxAssumeRejects(allowed) => {\n                Some(format!(\"`vm.assume` rejected too many inputs ({allowed} allowed)\"))\n            }\n        }\n    }\n}\n\n#[derive(Clone, Debug)]\npub struct FailedInvariantCaseData {\n    /// The proptest error occurred as a result of a test case.\n    pub test_error: TestError<Vec<BasicTxDetails>>,\n    /// The return reason of the offending call.\n    pub return_reason: Reason,\n    /// The revert string of the offending call.\n    pub revert_reason: String,\n    /// Address of the invariant asserter.\n    pub addr: Address,\n    /// Function calldata for invariant check.\n    pub calldata: Bytes,\n    /// Inner fuzzing Sequence coming from overriding calls.\n    pub inner_sequence: Vec<Option<BasicTxDetails>>,\n    /// Shrink run limit\n    pub shrink_run_limit: u32,\n    /// Fail on revert, used to check sequence when shrinking.\n    pub fail_on_revert: bool,\n}\n\nimpl FailedInvariantCaseData {\n    pub fn new(\n        invariant_contract: &InvariantContract<'_>,\n        invariant_config: &InvariantConfig,\n        targeted_contracts: &FuzzRunIdentifiedContracts,\n        calldata: &[BasicTxDetails],\n        call_result: RawCallResult,\n        inner_sequence: &[Option<BasicTxDetails>],\n    ) -> Self {\n        // Collect abis of fuzzed and invariant contracts to decode custom error.\n        let revert_reason = RevertDecoder::new()\n            .with_abis(targeted_contracts.targets.lock().values().map(|c| &c.abi))\n            .with_abi(invariant_contract.abi)\n            .decode(call_result.result.as_ref(), call_result.exit_reason);\n\n        let func = invariant_contract.invariant_function;\n        debug_assert!(func.inputs.is_empty());\n        let origin = func.name.as_str();\n        Self {\n            test_error: TestError::Fail(\n                format!(\"{origin}, reason: {revert_reason}\").into(),\n                calldata.to_vec(),\n            ),\n            return_reason: \"\".into(),\n            revert_reason,\n            addr: invariant_contract.address,\n            calldata: func.selector().to_vec().into(),\n            inner_sequence: inner_sequence.to_vec(),\n            shrink_run_limit: invariant_config.shrink_run_limit,\n            fail_on_revert: invariant_config.fail_on_revert,\n        }\n    }\n}\n"
  },
  {
    "path": "crates/evm/evm/src/executors/invariant/mod.rs",
    "content": "use crate::{\n    executors::{\n        DURATION_BETWEEN_METRICS_REPORT, EarlyExit, EvmError, Executor, FuzzTestTimer,\n        RawCallResult, corpus::WorkerCorpus,\n    },\n    inspectors::Fuzzer,\n};\nuse alloy_primitives::{\n    Address, Bytes, FixedBytes, I256, Selector, U256,\n    map::{AddressMap, HashMap},\n};\nuse alloy_sol_types::{SolCall, sol};\nuse eyre::{ContextCompat, Result, eyre};\nuse foundry_common::{\n    TestFunctionExt,\n    contracts::{ContractsByAddress, ContractsByArtifact},\n    sh_println,\n};\nuse foundry_config::InvariantConfig;\nuse foundry_evm_core::{\n    constants::{\n        CALLER, CHEATCODE_ADDRESS, DEFAULT_CREATE2_DEPLOYER, HARDHAT_CONSOLE_ADDRESS, MAGIC_ASSUME,\n    },\n    precompiles::PRECOMPILES,\n};\nuse foundry_evm_fuzz::{\n    BasicTxDetails, FuzzCase, FuzzFixtures, FuzzedCases,\n    invariant::{\n        ArtifactFilters, FuzzRunIdentifiedContracts, InvariantContract, RandomCallGenerator,\n        SenderFilters, TargetedContract, TargetedContracts,\n    },\n    strategies::{EvmFuzzState, invariant_strat, override_call_strat},\n};\nuse foundry_evm_traces::{CallTraceArena, SparsedTraceArena};\nuse indicatif::ProgressBar;\nuse parking_lot::RwLock;\nuse proptest::{strategy::Strategy, test_runner::TestRunner};\nuse result::{assert_after_invariant, assert_invariants, can_continue};\nuse revm::state::Account;\nuse serde::{Deserialize, Serialize};\nuse serde_json::json;\nuse std::{\n    collections::{HashMap as Map, btree_map::Entry},\n    sync::Arc,\n    time::{Instant, SystemTime, UNIX_EPOCH},\n};\n\nmod error;\npub use error::{InvariantFailures, InvariantFuzzError};\nuse foundry_evm_coverage::HitMaps;\n\nmod replay;\npub use replay::{replay_error, replay_run};\n\nmod result;\npub use result::InvariantFuzzTestResult;\n\nmod shrink;\npub use shrink::{check_sequence, check_sequence_value};\n\nsol! {\n    interface IInvariantTest {\n        #[derive(Default)]\n        struct FuzzSelector {\n            address addr;\n            bytes4[] selectors;\n        }\n\n        #[derive(Default)]\n        struct FuzzArtifactSelector {\n            string artifact;\n            bytes4[] selectors;\n        }\n\n        #[derive(Default)]\n        struct FuzzInterface {\n            address addr;\n            string[] artifacts;\n        }\n\n        function afterInvariant() external;\n\n        #[derive(Default)]\n        function excludeArtifacts() public view returns (string[] memory excludedArtifacts);\n\n        #[derive(Default)]\n        function excludeContracts() public view returns (address[] memory excludedContracts);\n\n        #[derive(Default)]\n        function excludeSelectors() public view returns (FuzzSelector[] memory excludedSelectors);\n\n        #[derive(Default)]\n        function excludeSenders() public view returns (address[] memory excludedSenders);\n\n        #[derive(Default)]\n        function targetArtifacts() public view returns (string[] memory targetedArtifacts);\n\n        #[derive(Default)]\n        function targetArtifactSelectors() public view returns (FuzzArtifactSelector[] memory targetedArtifactSelectors);\n\n        #[derive(Default)]\n        function targetContracts() public view returns (address[] memory targetedContracts);\n\n        #[derive(Default)]\n        function targetSelectors() public view returns (FuzzSelector[] memory targetedSelectors);\n\n        #[derive(Default)]\n        function targetSenders() public view returns (address[] memory targetedSenders);\n\n        #[derive(Default)]\n        function targetInterfaces() public view returns (FuzzInterface[] memory targetedInterfaces);\n    }\n}\n\n/// Contains invariant metrics for a single fuzzed selector.\n#[derive(Default, Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]\npub struct InvariantMetrics {\n    // Count of fuzzed selector calls.\n    pub calls: usize,\n    // Count of fuzzed selector reverts.\n    pub reverts: usize,\n    // Count of fuzzed selector discards (through assume cheatcodes).\n    pub discards: usize,\n}\n\n/// Contains data collected during invariant test runs.\nstruct InvariantTestData {\n    // Consumed gas and calldata of every successful fuzz call.\n    fuzz_cases: Vec<FuzzedCases>,\n    // Data related to reverts or failed assertions of the test.\n    failures: InvariantFailures,\n    // Calldata in the last invariant run.\n    last_run_inputs: Vec<BasicTxDetails>,\n    // Additional traces for gas report.\n    gas_report_traces: Vec<Vec<CallTraceArena>>,\n    // Last call results of the invariant test.\n    last_call_results: Option<RawCallResult>,\n    // Line coverage information collected from all fuzzed calls.\n    line_coverage: Option<HitMaps>,\n    // Metrics for each fuzzed selector.\n    metrics: Map<String, InvariantMetrics>,\n\n    // Proptest runner to query for random values.\n    // The strategy only comes with the first `input`. We fill the rest of the `inputs`\n    // until the desired `depth` so we can use the evolving fuzz dictionary\n    // during the run.\n    branch_runner: TestRunner,\n\n    // Optimization mode state: tracks the best (maximum) value and the sequence that produced it.\n    // Only used when invariant function returns int256.\n    optimization_best_value: Option<I256>,\n    optimization_best_sequence: Vec<BasicTxDetails>,\n}\n\n/// Contains invariant test data.\nstruct InvariantTest {\n    // Fuzz state of invariant test.\n    fuzz_state: EvmFuzzState,\n    // Contracts fuzzed by the invariant test.\n    targeted_contracts: FuzzRunIdentifiedContracts,\n    // Data collected during invariant runs.\n    test_data: InvariantTestData,\n}\n\nimpl InvariantTest {\n    /// Instantiates an invariant test.\n    fn new(\n        fuzz_state: EvmFuzzState,\n        targeted_contracts: FuzzRunIdentifiedContracts,\n        failures: InvariantFailures,\n        last_call_results: Option<RawCallResult>,\n        branch_runner: TestRunner,\n    ) -> Self {\n        let mut fuzz_cases = vec![];\n        if last_call_results.is_none() {\n            fuzz_cases.push(FuzzedCases::new(vec![]));\n        }\n        let test_data = InvariantTestData {\n            fuzz_cases,\n            failures,\n            last_run_inputs: vec![],\n            gas_report_traces: vec![],\n            last_call_results,\n            line_coverage: None,\n            metrics: Map::default(),\n            branch_runner,\n            optimization_best_value: None,\n            optimization_best_sequence: vec![],\n        };\n        Self { fuzz_state, targeted_contracts, test_data }\n    }\n\n    /// Returns number of invariant test reverts.\n    fn reverts(&self) -> usize {\n        self.test_data.failures.reverts\n    }\n\n    /// Whether invariant test has errors or not.\n    fn has_errors(&self) -> bool {\n        self.test_data.failures.error.is_some()\n    }\n\n    /// Set invariant test error.\n    fn set_error(&mut self, error: InvariantFuzzError) {\n        self.test_data.failures.error = Some(error);\n    }\n\n    /// Set last invariant test call results.\n    fn set_last_call_results(&mut self, call_result: Option<RawCallResult>) {\n        self.test_data.last_call_results = call_result;\n    }\n\n    /// Set last invariant run call sequence.\n    fn set_last_run_inputs(&mut self, inputs: &Vec<BasicTxDetails>) {\n        self.test_data.last_run_inputs.clone_from(inputs);\n    }\n\n    /// Merge current collected line coverage with the new coverage from last fuzzed call.\n    fn merge_line_coverage(&mut self, new_coverage: Option<HitMaps>) {\n        HitMaps::merge_opt(&mut self.test_data.line_coverage, new_coverage);\n    }\n\n    /// Update metrics for a fuzzed selector, extracted from tx details.\n    /// Always increments number of calls; discarded runs (through assume cheatcodes) are tracked\n    /// separated from reverts.\n    fn record_metrics(&mut self, tx_details: &BasicTxDetails, reverted: bool, discarded: bool) {\n        if let Some(metric_key) =\n            self.targeted_contracts.targets.lock().fuzzed_metric_key(tx_details)\n        {\n            let test_metrics = &mut self.test_data.metrics;\n            let invariant_metrics = test_metrics.entry(metric_key).or_default();\n            invariant_metrics.calls += 1;\n            if discarded {\n                invariant_metrics.discards += 1;\n            } else if reverted {\n                invariant_metrics.reverts += 1;\n            }\n        }\n    }\n\n    /// End invariant test run by collecting results, cleaning collected artifacts and reverting\n    /// created fuzz state.\n    fn end_run(&mut self, run: InvariantTestRun, gas_samples: usize) {\n        // We clear all the targeted contracts created during this run.\n        self.targeted_contracts.clear_created_contracts(run.created_contracts);\n\n        if self.test_data.gas_report_traces.len() < gas_samples {\n            self.test_data\n                .gas_report_traces\n                .push(run.run_traces.into_iter().map(|arena| arena.arena).collect());\n        }\n        self.test_data.fuzz_cases.push(FuzzedCases::new(run.fuzz_runs));\n\n        // Revert state to not persist values between runs.\n        self.fuzz_state.revert();\n    }\n\n    /// Updates the optimization state if the new value is better (higher) than the current best.\n    fn update_optimization_value(&mut self, value: I256, sequence: &[BasicTxDetails]) {\n        if self.test_data.optimization_best_value.is_none_or(|best| value > best) {\n            self.test_data.optimization_best_value = Some(value);\n            self.test_data.optimization_best_sequence = sequence.to_vec();\n        }\n    }\n}\n\n/// Contains data for an invariant test run.\nstruct InvariantTestRun {\n    // Invariant run call sequence.\n    inputs: Vec<BasicTxDetails>,\n    // Current invariant run executor.\n    executor: Executor,\n    // Invariant run stat reports (eg. gas usage).\n    fuzz_runs: Vec<FuzzCase>,\n    // Contracts created during current invariant run.\n    created_contracts: Vec<Address>,\n    // Traces of each call of the invariant run call sequence.\n    run_traces: Vec<SparsedTraceArena>,\n    // Current depth of invariant run.\n    depth: u32,\n    // Current assume rejects of the invariant run.\n    rejects: u32,\n    // Whether new coverage was discovered during this run.\n    new_coverage: bool,\n}\n\nimpl InvariantTestRun {\n    /// Instantiates an invariant test run.\n    fn new(first_input: BasicTxDetails, executor: Executor, depth: usize) -> Self {\n        Self {\n            inputs: vec![first_input],\n            executor,\n            fuzz_runs: Vec::with_capacity(depth),\n            created_contracts: vec![],\n            run_traces: vec![],\n            depth: 0,\n            rejects: 0,\n            new_coverage: false,\n        }\n    }\n}\n\n/// Wrapper around any [`Executor`] implementer which provides fuzzing support using [`proptest`].\n///\n/// After instantiation, calling `invariant_fuzz` will proceed to hammer the deployed smart\n/// contracts with inputs, until it finds a counterexample sequence. The provided [`TestRunner`]\n/// contains all the configuration which can be overridden via [environment\n/// variables](proptest::test_runner::Config)\npub struct InvariantExecutor<'a> {\n    pub executor: Executor,\n    /// Proptest runner.\n    runner: TestRunner,\n    /// The invariant configuration\n    config: InvariantConfig,\n    /// Contracts deployed with `setUp()`\n    setup_contracts: &'a ContractsByAddress,\n    /// Contracts that are part of the project but have not been deployed yet. We need the bytecode\n    /// to identify them from the stateset changes.\n    project_contracts: &'a ContractsByArtifact,\n    /// Filters contracts to be fuzzed through their artifact identifiers.\n    artifact_filters: ArtifactFilters,\n}\n\nimpl<'a> InvariantExecutor<'a> {\n    /// Instantiates a fuzzed executor EVM given a testrunner\n    pub fn new(\n        executor: Executor,\n        runner: TestRunner,\n        config: InvariantConfig,\n        setup_contracts: &'a ContractsByAddress,\n        project_contracts: &'a ContractsByArtifact,\n    ) -> Self {\n        Self {\n            executor,\n            runner,\n            config,\n            setup_contracts,\n            project_contracts,\n            artifact_filters: ArtifactFilters::default(),\n        }\n    }\n\n    pub fn config(self) -> InvariantConfig {\n        self.config\n    }\n\n    /// Fuzzes any deployed contract and checks any broken invariant at `invariant_address`.\n    pub fn invariant_fuzz(\n        &mut self,\n        invariant_contract: InvariantContract<'_>,\n        fuzz_fixtures: &FuzzFixtures,\n        fuzz_state: EvmFuzzState,\n        progress: Option<&ProgressBar>,\n        early_exit: &EarlyExit,\n    ) -> Result<InvariantFuzzTestResult> {\n        // Throw an error to abort test run if the invariant function accepts input params\n        if !invariant_contract.invariant_function.inputs.is_empty() {\n            return Err(eyre!(\"Invariant test function should have no inputs\"));\n        }\n\n        let (mut invariant_test, mut corpus_manager) =\n            self.prepare_test(&invariant_contract, fuzz_fixtures, fuzz_state)?;\n\n        // Start timer for this invariant test.\n        let mut runs = 0;\n        let timer = FuzzTestTimer::new(self.config.timeout);\n        let mut last_metrics_report = Instant::now();\n        let continue_campaign = |runs: u32| {\n            if early_exit.should_stop() {\n                return false;\n            }\n\n            if timer.is_enabled() { !timer.is_timed_out() } else { runs < self.config.runs }\n        };\n\n        // Invariant runs with edge coverage if corpus dir is set or showing edge coverage.\n        let edge_coverage_enabled = self.config.corpus.collect_edge_coverage();\n\n        'stop: while continue_campaign(runs) {\n            let initial_seq = corpus_manager.new_inputs(\n                &mut invariant_test.test_data.branch_runner,\n                &invariant_test.fuzz_state,\n                &invariant_test.targeted_contracts,\n            )?;\n\n            // Create current invariant run data.\n            let mut current_run = InvariantTestRun::new(\n                initial_seq[0].clone(),\n                // Before each run, we must reset the backend state.\n                self.executor.clone(),\n                self.config.depth as usize,\n            );\n\n            // We stop the run immediately if we have reverted, and `fail_on_revert` is set.\n            if self.config.fail_on_revert && invariant_test.reverts() > 0 {\n                return Err(eyre!(\"call reverted\"));\n            }\n\n            while current_run.depth < self.config.depth {\n                // Check if the timeout has been reached.\n                if timer.is_timed_out() {\n                    // Since we never record a revert here the test is still considered\n                    // successful even though it timed out. We *want*\n                    // this behavior for now, so that's ok, but\n                    // future developers should be aware of this.\n                    break 'stop;\n                }\n\n                let tx = current_run\n                    .inputs\n                    .last()\n                    .ok_or_else(|| eyre!(\"no input generated to call fuzzed target.\"))?;\n\n                // Execute call from the randomly generated sequence without committing state.\n                // State is committed only if call is not a magic assume.\n                let mut call_result = execute_tx(&mut current_run.executor, tx)?;\n                let discarded = call_result.result.as_ref() == MAGIC_ASSUME;\n                if self.config.show_metrics {\n                    invariant_test.record_metrics(tx, call_result.reverted, discarded);\n                }\n\n                // Collect line coverage from last fuzzed call.\n                invariant_test.merge_line_coverage(call_result.line_coverage.clone());\n                // Collect edge coverage and set the flag in the current run.\n                if corpus_manager.merge_edge_coverage(&mut call_result) {\n                    current_run.new_coverage = true;\n                }\n\n                if discarded {\n                    current_run.inputs.pop();\n                    current_run.rejects += 1;\n                    if current_run.rejects > self.config.max_assume_rejects {\n                        invariant_test.set_error(InvariantFuzzError::MaxAssumeRejects(\n                            self.config.max_assume_rejects,\n                        ));\n                        break 'stop;\n                    }\n                } else {\n                    // Commit executed call result.\n                    current_run.executor.commit(&mut call_result);\n\n                    // Collect data for fuzzing from the state changeset.\n                    // This step updates the state dictionary and therefore invalidates the\n                    // ValueTree in use by the current run. This manifestsitself in proptest\n                    // observing a different input case than what it was called with, and creates\n                    // inconsistencies whenever proptest tries to use the input case after test\n                    // execution.\n                    // See <https://github.com/foundry-rs/foundry/issues/9764>.\n                    let mut state_changeset = std::mem::take(&mut call_result.state_changeset);\n                    if !call_result.reverted {\n                        collect_data(\n                            &invariant_test,\n                            &mut state_changeset,\n                            tx,\n                            &call_result,\n                            self.config.depth,\n                        );\n                    }\n\n                    // Collect created contracts and add to fuzz targets only if targeted contracts\n                    // are updatable.\n                    if let Err(error) =\n                        &invariant_test.targeted_contracts.collect_created_contracts(\n                            &state_changeset,\n                            self.project_contracts,\n                            self.setup_contracts,\n                            &self.artifact_filters,\n                            &mut current_run.created_contracts,\n                        )\n                    {\n                        warn!(target: \"forge::test\", \"{error}\");\n                    }\n                    current_run\n                        .fuzz_runs\n                        .push(FuzzCase { gas: call_result.gas_used, stipend: call_result.stipend });\n\n                    // Determine if test can continue or should exit.\n                    // Check invariants based on check_interval to improve deep run performance.\n                    // - check_interval=0: only assert on the last call\n                    // - check_interval=1 (default): assert after every call\n                    // - check_interval=N: assert every N calls AND always on the last call\n                    let is_last_call = current_run.depth == self.config.depth - 1;\n                    let should_check_invariant = if self.config.check_interval == 0 {\n                        is_last_call\n                    } else {\n                        self.config.check_interval == 1\n                            || (current_run.depth + 1).is_multiple_of(self.config.check_interval)\n                            || is_last_call\n                    };\n\n                    let result = if should_check_invariant {\n                        can_continue(\n                            &invariant_contract,\n                            &mut invariant_test,\n                            &mut current_run,\n                            &self.config,\n                            call_result,\n                            &state_changeset,\n                        )\n                        .map_err(|e| eyre!(e.to_string()))?\n                    } else {\n                        // Skip invariant check but still track reverts\n                        if call_result.reverted {\n                            invariant_test.test_data.failures.reverts += 1;\n                            if self.config.fail_on_revert {\n                                let case_data = error::FailedInvariantCaseData::new(\n                                    &invariant_contract,\n                                    &self.config,\n                                    &invariant_test.targeted_contracts,\n                                    &current_run.inputs,\n                                    call_result,\n                                    &[],\n                                );\n                                invariant_test.test_data.failures.revert_reason =\n                                    Some(case_data.revert_reason.clone());\n                                invariant_test.test_data.failures.error =\n                                    Some(InvariantFuzzError::Revert(case_data));\n                                result::RichInvariantResults::new(false, None)\n                            } else if !invariant_contract.is_optimization() {\n                                // In optimization mode, keep reverted calls to preserve\n                                // warp/roll values for correct replay during shrinking.\n                                current_run.inputs.pop();\n                                result::RichInvariantResults::new(true, None)\n                            } else {\n                                result::RichInvariantResults::new(true, None)\n                            }\n                        } else {\n                            result::RichInvariantResults::new(true, None)\n                        }\n                    };\n\n                    if !result.can_continue || current_run.depth == self.config.depth - 1 {\n                        invariant_test.set_last_run_inputs(&current_run.inputs);\n                    }\n                    // If test cannot continue then stop current run and exit test suite.\n                    if !result.can_continue {\n                        break 'stop;\n                    }\n\n                    invariant_test.set_last_call_results(result.call_result);\n                    current_run.depth += 1;\n                }\n\n                current_run.inputs.push(corpus_manager.generate_next_input(\n                    &mut invariant_test.test_data.branch_runner,\n                    &initial_seq,\n                    discarded,\n                    current_run.depth as usize,\n                )?);\n            }\n\n            // Extend corpus with current run data.\n            corpus_manager.process_inputs(&current_run.inputs, current_run.new_coverage);\n\n            // Call `afterInvariant` only if it is declared and test didn't fail already.\n            if invariant_contract.call_after_invariant && !invariant_test.has_errors() {\n                assert_after_invariant(\n                    &invariant_contract,\n                    &mut invariant_test,\n                    &current_run,\n                    &self.config,\n                )\n                .map_err(|_| eyre!(\"Failed to call afterInvariant\"))?;\n            }\n\n            // End current invariant test run.\n            invariant_test.end_run(current_run, self.config.gas_report_samples as usize);\n            if let Some(progress) = progress {\n                // If running with progress then increment completed runs.\n                progress.inc(1);\n                // Display metrics in progress bar.\n                if edge_coverage_enabled {\n                    progress.set_message(format!(\"{}\", &corpus_manager.metrics));\n                }\n            } else if edge_coverage_enabled\n                && last_metrics_report.elapsed() > DURATION_BETWEEN_METRICS_REPORT\n            {\n                // Display metrics inline if corpus dir set.\n                let metrics = json!({\n                    \"timestamp\": SystemTime::now()\n                        .duration_since(UNIX_EPOCH)?\n                        .as_secs(),\n                    \"invariant\": invariant_contract.invariant_function.name,\n                    \"metrics\": &corpus_manager.metrics,\n                });\n                let _ = sh_println!(\"{}\", serde_json::to_string(&metrics)?);\n                last_metrics_report = Instant::now();\n            }\n\n            runs += 1;\n        }\n\n        trace!(?fuzz_fixtures);\n        invariant_test.fuzz_state.log_stats();\n\n        let result = invariant_test.test_data;\n        Ok(InvariantFuzzTestResult {\n            error: result.failures.error,\n            cases: result.fuzz_cases,\n            reverts: result.failures.reverts,\n            last_run_inputs: result.last_run_inputs,\n            gas_report_traces: result.gas_report_traces,\n            line_coverage: result.line_coverage,\n            metrics: result.metrics,\n            failed_corpus_replays: corpus_manager.failed_replays,\n            optimization_best_value: result.optimization_best_value,\n            optimization_best_sequence: result.optimization_best_sequence,\n        })\n    }\n\n    /// Prepares certain structures to execute the invariant tests:\n    /// * Invariant Fuzz Test.\n    /// * Invariant Corpus Manager.\n    fn prepare_test(\n        &mut self,\n        invariant_contract: &InvariantContract<'_>,\n        fuzz_fixtures: &FuzzFixtures,\n        fuzz_state: EvmFuzzState,\n    ) -> Result<(InvariantTest, WorkerCorpus)> {\n        // Finds out the chosen deployed contracts and/or senders.\n        self.select_contract_artifacts(invariant_contract.address)?;\n        let (targeted_senders, targeted_contracts) =\n            self.select_contracts_and_senders(invariant_contract.address)?;\n\n        // Creates the invariant strategy.\n        let strategy = invariant_strat(\n            fuzz_state.clone(),\n            targeted_senders,\n            targeted_contracts.clone(),\n            self.config.clone(),\n            fuzz_fixtures.clone(),\n        )\n        .no_shrink();\n\n        // If any of the targeted contracts have the storage layout enabled then we can sample\n        // mapping values. To accomplish, we need to record the mapping storage slots and keys.\n        let fuzz_state =\n            if targeted_contracts.targets.lock().iter().any(|(_, t)| t.storage_layout.is_some()) {\n                fuzz_state.with_mapping_slots(AddressMap::default())\n            } else {\n                fuzz_state\n            };\n\n        // Set up fuzzer WITHOUT call_generator initially.\n        // We defer call_override until after the initial invariant check to avoid\n        // injecting random calls during setup which would break the invariant assertion.\n        self.executor.inspector_mut().set_fuzzer(Fuzzer {\n            call_generator: None,\n            fuzz_state: fuzz_state.clone(),\n            collect: true,\n        });\n\n        // Let's make sure the invariant is sound before actually starting the run:\n        // We'll assert the invariant in its initial state, and if it fails, we'll\n        // already know if we can early exit the invariant run.\n        // This does not count as a fuzz run. It will just register the revert.\n        let mut failures = InvariantFailures::new();\n        let last_call_results = assert_invariants(\n            invariant_contract,\n            &self.config,\n            &targeted_contracts,\n            &self.executor,\n            &[],\n            &mut failures,\n        )?;\n        if let Some(error) = failures.error {\n            return Err(eyre!(error.revert_reason().unwrap_or_default()));\n        }\n\n        // NOW enable call_override after the initial invariant check has passed.\n        // This allows `override_call_strat` to inject calls during actual fuzz runs\n        // for reentrancy vulnerability detection.\n        if self.config.call_override {\n            let target_contract_ref = Arc::new(RwLock::new(Address::ZERO));\n\n            // Collect handler addresses - these are the contracts we want to inject\n            // reentrancy into (simulating malicious receive() functions).\n            let handler_addresses: std::collections::HashSet<Address> =\n                targeted_contracts.targets.lock().keys().copied().collect();\n\n            let call_generator = RandomCallGenerator::new(\n                invariant_contract.address,\n                handler_addresses,\n                self.runner.clone(),\n                override_call_strat(\n                    fuzz_state.clone(),\n                    targeted_contracts.clone(),\n                    target_contract_ref.clone(),\n                    fuzz_fixtures.clone(),\n                ),\n                target_contract_ref,\n            );\n\n            if let Some(fuzzer) = self.executor.inspector_mut().fuzzer.as_mut() {\n                fuzzer.call_generator = Some(call_generator);\n            }\n        }\n\n        let worker = WorkerCorpus::new(\n            0,\n            self.config.corpus.clone(),\n            strategy.boxed(),\n            Some(&self.executor),\n            None,\n            Some(&targeted_contracts),\n        )?;\n\n        let invariant_test = InvariantTest::new(\n            fuzz_state,\n            targeted_contracts,\n            failures,\n            last_call_results,\n            self.runner.clone(),\n        );\n\n        Ok((invariant_test, worker))\n    }\n\n    /// Fills the `InvariantExecutor` with the artifact identifier filters (in `path:name` string\n    /// format). They will be used to filter contracts after the `setUp`, and more importantly,\n    /// during the runs.\n    ///\n    /// Also excludes any contract without any mutable functions.\n    ///\n    /// Priority:\n    ///\n    /// targetArtifactSelectors > excludeArtifacts > targetArtifacts\n    pub fn select_contract_artifacts(&mut self, invariant_address: Address) -> Result<()> {\n        let targeted_artifact_selectors = self\n            .executor\n            .call_sol_default(invariant_address, &IInvariantTest::targetArtifactSelectorsCall {});\n\n        // Insert them into the executor `targeted_abi`.\n        for IInvariantTest::FuzzArtifactSelector { artifact, selectors } in\n            targeted_artifact_selectors\n        {\n            let identifier = self.validate_selected_contract(artifact, &selectors)?;\n            self.artifact_filters.targeted.entry(identifier).or_default().extend(selectors);\n        }\n\n        let targeted_artifacts = self\n            .executor\n            .call_sol_default(invariant_address, &IInvariantTest::targetArtifactsCall {});\n        let excluded_artifacts = self\n            .executor\n            .call_sol_default(invariant_address, &IInvariantTest::excludeArtifactsCall {});\n\n        // Insert `excludeArtifacts` into the executor `excluded_abi`.\n        for contract in excluded_artifacts {\n            let identifier = self.validate_selected_contract(contract, &[])?;\n\n            if !self.artifact_filters.excluded.contains(&identifier) {\n                self.artifact_filters.excluded.push(identifier);\n            }\n        }\n\n        // Exclude any artifact without mutable functions.\n        for (artifact, contract) in self.project_contracts.iter() {\n            if contract\n                .abi\n                .functions()\n                .filter(|func| {\n                    !matches!(\n                        func.state_mutability,\n                        alloy_json_abi::StateMutability::Pure\n                            | alloy_json_abi::StateMutability::View\n                    )\n                })\n                .count()\n                == 0\n                && !self.artifact_filters.excluded.contains(&artifact.identifier())\n            {\n                self.artifact_filters.excluded.push(artifact.identifier());\n            }\n        }\n\n        // Insert `targetArtifacts` into the executor `targeted_abi`, if they have not been seen\n        // before.\n        for contract in targeted_artifacts {\n            let identifier = self.validate_selected_contract(contract, &[])?;\n\n            if !self.artifact_filters.targeted.contains_key(&identifier)\n                && !self.artifact_filters.excluded.contains(&identifier)\n            {\n                self.artifact_filters.targeted.insert(identifier, vec![]);\n            }\n        }\n        Ok(())\n    }\n\n    /// Makes sure that the contract exists in the project. If so, it returns its artifact\n    /// identifier.\n    fn validate_selected_contract(\n        &mut self,\n        contract: String,\n        selectors: &[FixedBytes<4>],\n    ) -> Result<String> {\n        if let Some((artifact, contract_data)) =\n            self.project_contracts.find_by_name_or_identifier(&contract)?\n        {\n            // Check that the selectors really exist for this contract.\n            for selector in selectors {\n                contract_data\n                    .abi\n                    .functions()\n                    .find(|func| func.selector().as_slice() == selector.as_slice())\n                    .wrap_err(format!(\"{contract} does not have the selector {selector:?}\"))?;\n            }\n\n            return Ok(artifact.identifier());\n        }\n        eyre::bail!(\n            \"{contract} not found in the project. Allowed format: `contract_name` or `contract_path:contract_name`.\"\n        );\n    }\n\n    /// Selects senders and contracts based on the contract methods `targetSenders() -> address[]`,\n    /// `targetContracts() -> address[]` and `excludeContracts() -> address[]`.\n    pub fn select_contracts_and_senders(\n        &self,\n        to: Address,\n    ) -> Result<(SenderFilters, FuzzRunIdentifiedContracts)> {\n        let targeted_senders =\n            self.executor.call_sol_default(to, &IInvariantTest::targetSendersCall {});\n        let mut excluded_senders =\n            self.executor.call_sol_default(to, &IInvariantTest::excludeSendersCall {});\n        // Extend with default excluded addresses - https://github.com/foundry-rs/foundry/issues/4163\n        excluded_senders.extend([\n            CHEATCODE_ADDRESS,\n            HARDHAT_CONSOLE_ADDRESS,\n            DEFAULT_CREATE2_DEPLOYER,\n        ]);\n        // Extend with precompiles - https://github.com/foundry-rs/foundry/issues/4287\n        excluded_senders.extend(PRECOMPILES);\n        let sender_filters = SenderFilters::new(targeted_senders, excluded_senders);\n\n        let selected = self.executor.call_sol_default(to, &IInvariantTest::targetContractsCall {});\n        let excluded = self.executor.call_sol_default(to, &IInvariantTest::excludeContractsCall {});\n\n        let contracts = self\n            .setup_contracts\n            .iter()\n            .filter(|&(addr, (identifier, _))| {\n                // Include to address if explicitly set as target.\n                if *addr == to && selected.contains(&to) {\n                    return true;\n                }\n\n                *addr != to\n                    && *addr != CHEATCODE_ADDRESS\n                    && *addr != HARDHAT_CONSOLE_ADDRESS\n                    && (selected.is_empty() || selected.contains(addr))\n                    && (excluded.is_empty() || !excluded.contains(addr))\n                    && self.artifact_filters.matches(identifier)\n            })\n            .map(|(addr, (identifier, abi))| {\n                (\n                    *addr,\n                    TargetedContract::new(identifier.clone(), abi.clone())\n                        .with_project_contracts(self.project_contracts),\n                )\n            })\n            .collect();\n        let mut contracts = TargetedContracts { inner: contracts };\n\n        self.target_interfaces(to, &mut contracts)?;\n\n        self.select_selectors(to, &mut contracts)?;\n\n        // There should be at least one contract identified as target for fuzz runs.\n        if contracts.is_empty() {\n            eyre::bail!(\"No contracts to fuzz.\");\n        }\n\n        Ok((sender_filters, FuzzRunIdentifiedContracts::new(contracts, selected.is_empty())))\n    }\n\n    /// Extends the contracts and selectors to fuzz with the addresses and ABIs specified in\n    /// `targetInterfaces() -> (address, string[])[]`. Enables targeting of addresses that are\n    /// not deployed during `setUp` such as when fuzzing in a forked environment. Also enables\n    /// targeting of delegate proxies and contracts deployed with `create` or `create2`.\n    pub fn target_interfaces(\n        &self,\n        invariant_address: Address,\n        targeted_contracts: &mut TargetedContracts,\n    ) -> Result<()> {\n        let interfaces = self\n            .executor\n            .call_sol_default(invariant_address, &IInvariantTest::targetInterfacesCall {});\n\n        // Since `targetInterfaces` returns a tuple array there is no guarantee\n        // that the addresses are unique this map is used to merge functions of\n        // the specified interfaces for the same address. For example:\n        // `[(addr1, [\"IERC20\", \"IOwnable\"])]` and `[(addr1, [\"IERC20\"]), (addr1, (\"IOwnable\"))]`\n        // should be equivalent.\n        let mut combined = TargetedContracts::new();\n\n        // Loop through each address and its associated artifact identifiers.\n        // We're borrowing here to avoid taking full ownership.\n        for IInvariantTest::FuzzInterface { addr, artifacts } in &interfaces {\n            // Identifiers are specified as an array, so we loop through them.\n            for identifier in artifacts {\n                // Try to find the contract by name or identifier in the project's contracts.\n                if let Some((_, contract_data)) =\n                    self.project_contracts.iter().find(|(artifact, _)| {\n                        &artifact.name == identifier || &artifact.identifier() == identifier\n                    })\n                {\n                    let abi = &contract_data.abi;\n                    combined\n                        // Check if there's an entry for the given key in the 'combined' map.\n                        .entry(*addr)\n                        // If the entry exists, extends its ABI with the function list.\n                        .and_modify(|entry| {\n                            // Extend the ABI's function list with the new functions.\n                            entry.abi.functions.extend(abi.functions.clone());\n                        })\n                        // Otherwise insert it into the map.\n                        .or_insert_with(|| {\n                            let mut contract =\n                                TargetedContract::new(identifier.to_string(), abi.clone());\n                            contract.storage_layout =\n                                contract_data.storage_layout.as_ref().map(Arc::clone);\n                            contract\n                        });\n                }\n            }\n        }\n\n        targeted_contracts.extend(combined.inner);\n\n        Ok(())\n    }\n\n    /// Selects the functions to fuzz based on the contract method `targetSelectors()` and\n    /// `targetArtifactSelectors()`.\n    pub fn select_selectors(\n        &self,\n        address: Address,\n        targeted_contracts: &mut TargetedContracts,\n    ) -> Result<()> {\n        for (address, (identifier, _)) in self.setup_contracts {\n            if let Some(selectors) = self.artifact_filters.targeted.get(identifier) {\n                self.add_address_with_functions(*address, selectors, false, targeted_contracts)?;\n            }\n        }\n\n        let mut target_test_selectors = vec![];\n        let mut excluded_test_selectors = vec![];\n\n        // Collect contract functions marked as target for fuzzing campaign.\n        let selectors =\n            self.executor.call_sol_default(address, &IInvariantTest::targetSelectorsCall {});\n        for IInvariantTest::FuzzSelector { addr, selectors } in selectors {\n            if addr == address {\n                target_test_selectors = selectors.clone();\n            }\n            self.add_address_with_functions(addr, &selectors, false, targeted_contracts)?;\n        }\n\n        // Collect contract functions excluded from fuzzing campaign.\n        let excluded_selectors =\n            self.executor.call_sol_default(address, &IInvariantTest::excludeSelectorsCall {});\n        for IInvariantTest::FuzzSelector { addr, selectors } in excluded_selectors {\n            if addr == address {\n                // If fuzz selector address is the test contract, then record selectors to be\n                // later excluded if needed.\n                excluded_test_selectors = selectors.clone();\n            }\n            self.add_address_with_functions(addr, &selectors, true, targeted_contracts)?;\n        }\n\n        if target_test_selectors.is_empty()\n            && let Some(target) = targeted_contracts.get(&address)\n        {\n            // If test contract is marked as a target and no target selector explicitly set, then\n            // include only state-changing functions that are not reserved and selectors that are\n            // not explicitly excluded.\n            let selectors: Vec<_> = target\n                .abi\n                .functions()\n                .filter_map(|func| {\n                    if matches!(\n                        func.state_mutability,\n                        alloy_json_abi::StateMutability::Pure\n                            | alloy_json_abi::StateMutability::View\n                    ) || func.is_reserved()\n                        || excluded_test_selectors.contains(&func.selector())\n                    {\n                        None\n                    } else {\n                        Some(func.selector())\n                    }\n                })\n                .collect();\n            self.add_address_with_functions(address, &selectors, false, targeted_contracts)?;\n        }\n\n        Ok(())\n    }\n\n    /// Adds the address and fuzzed or excluded functions to `TargetedContracts`.\n    fn add_address_with_functions(\n        &self,\n        address: Address,\n        selectors: &[Selector],\n        should_exclude: bool,\n        targeted_contracts: &mut TargetedContracts,\n    ) -> eyre::Result<()> {\n        // Do not add address in target contracts if no function selected.\n        if selectors.is_empty() {\n            return Ok(());\n        }\n\n        let contract = match targeted_contracts.entry(address) {\n            Entry::Occupied(entry) => entry.into_mut(),\n            Entry::Vacant(entry) => {\n                let (identifier, abi) = self.setup_contracts.get(&address).ok_or_else(|| {\n                    eyre::eyre!(\n                        \"[{}] address does not have an associated contract: {}\",\n                        if should_exclude { \"excludeSelectors\" } else { \"targetSelectors\" },\n                        address\n                    )\n                })?;\n                entry.insert(\n                    TargetedContract::new(identifier.clone(), abi.clone())\n                        .with_project_contracts(self.project_contracts),\n                )\n            }\n        };\n        contract.add_selectors(selectors.iter().copied(), should_exclude)?;\n        Ok(())\n    }\n}\n\n/// Collects data from call for fuzzing. However, it first verifies that the sender is not an EOA\n/// before inserting it into the dictionary. Otherwise, we flood the dictionary with\n/// randomly generated addresses.\nfn collect_data(\n    invariant_test: &InvariantTest,\n    state_changeset: &mut HashMap<Address, Account>,\n    tx: &BasicTxDetails,\n    call_result: &RawCallResult,\n    run_depth: u32,\n) {\n    // Verify it has no code.\n    let mut has_code = false;\n    if let Some(Some(code)) =\n        state_changeset.get(&tx.sender).map(|account| account.info.code.as_ref())\n    {\n        has_code = !code.is_empty();\n    }\n\n    // We keep the nonce changes to apply later.\n    let mut sender_changeset = None;\n    if !has_code {\n        sender_changeset = state_changeset.remove(&tx.sender);\n    }\n\n    // Collect values from fuzzed call result and add them to fuzz dictionary.\n    invariant_test.fuzz_state.collect_values_from_call(\n        &invariant_test.targeted_contracts,\n        tx,\n        &call_result.result,\n        &call_result.logs,\n        &*state_changeset,\n        run_depth,\n    );\n\n    // Re-add changes\n    if let Some(changed) = sender_changeset {\n        state_changeset.insert(tx.sender, changed);\n    }\n}\n\n/// Calls the `afterInvariant()` function on a contract.\n/// Returns call result and if call succeeded.\n/// The state after the call is not persisted.\npub(crate) fn call_after_invariant_function(\n    executor: &Executor,\n    to: Address,\n) -> Result<(RawCallResult, bool), EvmError> {\n    let calldata = Bytes::from_static(&IInvariantTest::afterInvariantCall::SELECTOR);\n    let mut call_result = executor.call_raw(CALLER, to, calldata, U256::ZERO)?;\n    let success = executor.is_raw_call_mut_success(to, &mut call_result, false);\n    Ok((call_result, success))\n}\n\n/// Calls the invariant function and returns call result and if succeeded.\npub(crate) fn call_invariant_function(\n    executor: &Executor,\n    address: Address,\n    calldata: Bytes,\n) -> Result<(RawCallResult, bool)> {\n    let mut call_result = executor.call_raw(CALLER, address, calldata, U256::ZERO)?;\n    let success = executor.is_raw_call_mut_success(address, &mut call_result, false);\n    Ok((call_result, success))\n}\n\n/// Executes a fuzz call and returns the result.\n/// Applies any block timestamp (warp) and block number (roll) adjustments before the call.\npub(crate) fn execute_tx(executor: &mut Executor, tx: &BasicTxDetails) -> Result<RawCallResult> {\n    let warp = tx.warp.unwrap_or_default();\n    let roll = tx.roll.unwrap_or_default();\n\n    if warp > 0 || roll > 0 {\n        // Apply pre-call block adjustments to the executor's env.\n        executor.evm_env_mut().block_env.timestamp += warp;\n        executor.evm_env_mut().block_env.number += roll;\n\n        // Also update the inspector's cheatcodes.block if set.\n        // The inspector's block may override the env during interpreter initialization,\n        // so we need to add our warp/roll on top of any existing cheatcode-set values.\n        let block_env = executor.evm_env().block_env.clone();\n        if let Some(cheatcodes) = executor.inspector_mut().cheatcodes.as_mut() {\n            if let Some(block) = cheatcodes.block.as_mut() {\n                block.timestamp += warp;\n                block.number += roll;\n            } else {\n                cheatcodes.block = Some(block_env);\n            }\n        }\n    }\n\n    executor\n        .call_raw(tx.sender, tx.call_details.target, tx.call_details.calldata.clone(), U256::ZERO)\n        .map_err(|e| eyre!(format!(\"Could not make raw evm call: {e}\")))\n}\n"
  },
  {
    "path": "crates/evm/evm/src/executors/invariant/replay.rs",
    "content": "use super::{call_after_invariant_function, call_invariant_function, execute_tx};\nuse crate::executors::{\n    EarlyExit, Executor,\n    invariant::shrink::{shrink_sequence, shrink_sequence_value},\n};\nuse alloy_dyn_abi::JsonAbiExt;\nuse alloy_primitives::{I256, Log, map::HashMap};\nuse eyre::Result;\nuse foundry_common::{ContractsByAddress, ContractsByArtifact};\nuse foundry_config::InvariantConfig;\nuse foundry_evm_coverage::HitMaps;\nuse foundry_evm_fuzz::{BaseCounterExample, BasicTxDetails, invariant::InvariantContract};\nuse foundry_evm_traces::{TraceKind, TraceMode, Traces, load_contracts};\nuse indicatif::ProgressBar;\nuse parking_lot::RwLock;\nuse std::sync::Arc;\n\n/// Replays a call sequence for collecting logs and traces.\n/// Returns counterexample to be used when the call sequence is a failed scenario.\n#[expect(clippy::too_many_arguments)]\npub fn replay_run(\n    invariant_contract: &InvariantContract<'_>,\n    mut executor: Executor,\n    known_contracts: &ContractsByArtifact,\n    mut ided_contracts: ContractsByAddress,\n    logs: &mut Vec<Log>,\n    traces: &mut Traces,\n    line_coverage: &mut Option<HitMaps>,\n    deprecated_cheatcodes: &mut HashMap<&'static str, Option<&'static str>>,\n    inputs: &[BasicTxDetails],\n    show_solidity: bool,\n) -> Result<Vec<BaseCounterExample>> {\n    // We want traces for a failed case.\n    if executor.inspector().tracer.is_none() {\n        executor.set_tracing(TraceMode::Call);\n    }\n\n    let mut counterexample_sequence = vec![];\n\n    // Replay each call from the sequence, collect logs, traces and coverage.\n    for tx in inputs {\n        let mut call_result = execute_tx(&mut executor, tx)?;\n        logs.extend(call_result.logs.clone());\n        traces.push((TraceKind::Execution, call_result.traces.clone().unwrap()));\n        HitMaps::merge_opt(line_coverage, call_result.line_coverage.clone());\n\n        // Commit state changes to persist across calls in the sequence.\n        executor.commit(&mut call_result);\n\n        // Identify newly generated contracts, if they exist.\n        ided_contracts\n            .extend(load_contracts(call_result.traces.iter().map(|a| &a.arena), known_contracts));\n\n        // Create counter example to be used in failed case.\n        counterexample_sequence.push(BaseCounterExample::from_invariant_call(\n            tx,\n            &ided_contracts,\n            call_result.traces,\n            show_solidity,\n        ));\n    }\n\n    // Replay invariant to collect logs and traces.\n    // We do this only once at the end of the replayed sequence.\n    // Checking after each call doesn't add valuable info for passing scenario\n    // (invariant call result is always success) nor for failed scenarios\n    // (invariant call result is always success until the last call that breaks it).\n    let (invariant_result, invariant_success) = call_invariant_function(\n        &executor,\n        invariant_contract.address,\n        invariant_contract.invariant_function.abi_encode_input(&[])?.into(),\n    )?;\n    traces.push((TraceKind::Execution, invariant_result.traces.clone().unwrap()));\n    logs.extend(invariant_result.logs);\n    deprecated_cheatcodes.extend(\n        invariant_result\n            .cheatcodes\n            .as_ref()\n            .map_or_else(Default::default, |cheats| cheats.deprecated.clone()),\n    );\n\n    // Collect after invariant logs and traces.\n    if invariant_contract.call_after_invariant && invariant_success {\n        let (after_invariant_result, _) =\n            call_after_invariant_function(&executor, invariant_contract.address)?;\n        traces.push((TraceKind::Execution, after_invariant_result.traces.clone().unwrap()));\n        logs.extend(after_invariant_result.logs);\n    }\n\n    Ok(counterexample_sequence)\n}\n\n/// Replays and shrinks a call sequence, collecting logs and traces.\n///\n/// For check mode (target_value=None): shrinks to find shortest failing sequence.\n/// For optimization mode (target_value=Some): shrinks to find shortest sequence producing target.\n#[expect(clippy::too_many_arguments)]\npub fn replay_error(\n    config: InvariantConfig,\n    mut executor: Executor,\n    calls: &[BasicTxDetails],\n    inner_sequence: Option<Vec<Option<BasicTxDetails>>>,\n    target_value: Option<I256>,\n    invariant_contract: &InvariantContract<'_>,\n    known_contracts: &ContractsByArtifact,\n    ided_contracts: ContractsByAddress,\n    logs: &mut Vec<Log>,\n    traces: &mut Traces,\n    line_coverage: &mut Option<HitMaps>,\n    deprecated_cheatcodes: &mut HashMap<&'static str, Option<&'static str>>,\n    progress: Option<&ProgressBar>,\n    early_exit: &EarlyExit,\n) -> Result<Vec<BaseCounterExample>> {\n    let calls = if let Some(target) = target_value {\n        shrink_sequence_value(\n            &config,\n            invariant_contract,\n            calls,\n            &executor,\n            target,\n            progress,\n            early_exit,\n        )?\n    } else {\n        shrink_sequence(&config, invariant_contract, calls, &executor, progress, early_exit)?\n    };\n\n    if let Some(sequence) = inner_sequence {\n        set_up_inner_replay(&mut executor, &sequence);\n    }\n\n    replay_run(\n        invariant_contract,\n        executor,\n        known_contracts,\n        ided_contracts,\n        logs,\n        traces,\n        line_coverage,\n        deprecated_cheatcodes,\n        &calls,\n        config.show_solidity,\n    )\n}\n\n/// Sets up the calls generated by the internal fuzzer, if they exist.\nfn set_up_inner_replay(executor: &mut Executor, inner_sequence: &[Option<BasicTxDetails>]) {\n    if let Some(fuzzer) = &mut executor.inspector_mut().fuzzer\n        && let Some(call_generator) = &mut fuzzer.call_generator\n    {\n        call_generator.last_sequence = Arc::new(RwLock::new(inner_sequence.to_owned()));\n        call_generator.set_replay(true);\n    }\n}\n"
  },
  {
    "path": "crates/evm/evm/src/executors/invariant/result.rs",
    "content": "use super::{\n    InvariantFailures, InvariantFuzzError, InvariantMetrics, InvariantTest, InvariantTestRun,\n    call_after_invariant_function, call_invariant_function, error::FailedInvariantCaseData,\n};\nuse crate::executors::{Executor, RawCallResult};\nuse alloy_dyn_abi::JsonAbiExt;\nuse alloy_primitives::I256;\nuse eyre::Result;\nuse foundry_config::InvariantConfig;\nuse foundry_evm_core::utils::StateChangeset;\nuse foundry_evm_coverage::HitMaps;\nuse foundry_evm_fuzz::{\n    BasicTxDetails, FuzzedCases,\n    invariant::{FuzzRunIdentifiedContracts, InvariantContract},\n};\nuse revm_inspectors::tracing::CallTraceArena;\nuse std::{borrow::Cow, collections::HashMap};\n\n/// The outcome of an invariant fuzz test\n#[derive(Debug)]\npub struct InvariantFuzzTestResult {\n    pub error: Option<InvariantFuzzError>,\n    /// Every successful fuzz test case\n    pub cases: Vec<FuzzedCases>,\n    /// Number of reverted fuzz calls\n    pub reverts: usize,\n    /// The entire inputs of the last run of the invariant campaign, used for\n    /// replaying the run for collecting traces.\n    pub last_run_inputs: Vec<BasicTxDetails>,\n    /// Additional traces used for gas report construction.\n    pub gas_report_traces: Vec<Vec<CallTraceArena>>,\n    /// The coverage info collected during the invariant test runs.\n    pub line_coverage: Option<HitMaps>,\n    /// Fuzzed selectors metrics collected during the invariant test runs.\n    pub metrics: HashMap<String, InvariantMetrics>,\n    /// Number of failed replays from persisted corpus.\n    pub failed_corpus_replays: usize,\n    /// For optimization mode (int256 return): the best (maximum) value achieved.\n    /// None means standard invariant check mode.\n    pub optimization_best_value: Option<I256>,\n    /// For optimization mode: the call sequence that produced the best value.\n    pub optimization_best_sequence: Vec<BasicTxDetails>,\n}\n\n/// Enriched results of an invariant run check.\n///\n/// Contains the success condition and call results of the last run\npub(crate) struct RichInvariantResults {\n    pub(crate) can_continue: bool,\n    pub(crate) call_result: Option<RawCallResult>,\n}\n\nimpl RichInvariantResults {\n    pub(crate) fn new(can_continue: bool, call_result: Option<RawCallResult>) -> Self {\n        Self { can_continue, call_result }\n    }\n}\n\n/// Given the executor state, asserts that no invariant has been broken. Otherwise, it fills the\n/// external `invariant_failures.failed_invariant` map and returns a generic error.\n/// Either returns the call result if successful, or nothing if there was an error.\npub(crate) fn assert_invariants(\n    invariant_contract: &InvariantContract<'_>,\n    invariant_config: &InvariantConfig,\n    targeted_contracts: &FuzzRunIdentifiedContracts,\n    executor: &Executor,\n    calldata: &[BasicTxDetails],\n    invariant_failures: &mut InvariantFailures,\n) -> Result<Option<RawCallResult>> {\n    let mut inner_sequence = vec![];\n\n    if let Some(fuzzer) = &executor.inspector().fuzzer\n        && let Some(call_generator) = &fuzzer.call_generator\n    {\n        inner_sequence.extend(call_generator.last_sequence.read().iter().cloned());\n    }\n\n    let (call_result, success) = call_invariant_function(\n        executor,\n        invariant_contract.address,\n        invariant_contract.invariant_function.abi_encode_input(&[])?.into(),\n    )?;\n    if !success {\n        // We only care about invariants which we haven't broken yet.\n        if invariant_failures.error.is_none() {\n            let case_data = FailedInvariantCaseData::new(\n                invariant_contract,\n                invariant_config,\n                targeted_contracts,\n                calldata,\n                call_result,\n                &inner_sequence,\n            );\n            invariant_failures.error = Some(InvariantFuzzError::BrokenInvariant(case_data));\n            return Ok(None);\n        }\n    }\n\n    Ok(Some(call_result))\n}\n\n/// Returns if invariant test can continue and last successful call result of the invariant test\n/// function (if it can continue).\n///\n/// For optimization mode (int256 return), tracks the max value but never fails on invariant.\n/// For check mode, asserts the invariant and fails if broken.\npub(crate) fn can_continue(\n    invariant_contract: &InvariantContract<'_>,\n    invariant_test: &mut InvariantTest,\n    invariant_run: &mut InvariantTestRun,\n    invariant_config: &InvariantConfig,\n    call_result: RawCallResult,\n    state_changeset: &StateChangeset,\n) -> Result<RichInvariantResults> {\n    let mut call_results = None;\n    let is_optimization = invariant_contract.is_optimization();\n\n    let handlers_succeeded = || {\n        invariant_test.targeted_contracts.targets.lock().keys().all(|address| {\n            invariant_run.executor.is_success(\n                *address,\n                false,\n                Cow::Borrowed(state_changeset),\n                false,\n            )\n        })\n    };\n\n    if !call_result.reverted && handlers_succeeded() {\n        if let Some(traces) = call_result.traces {\n            invariant_run.run_traces.push(traces);\n        }\n\n        if is_optimization {\n            // Optimization mode: call invariant and track max value, never fail.\n            let (inv_result, success) = call_invariant_function(\n                &invariant_run.executor,\n                invariant_contract.address,\n                invariant_contract.invariant_function.abi_encode_input(&[])?.into(),\n            )?;\n            if success\n                && inv_result.result.len() >= 32\n                && let Some(value) = I256::try_from_be_slice(&inv_result.result[..32])\n            {\n                invariant_test.update_optimization_value(value, &invariant_run.inputs);\n            }\n            call_results = Some(inv_result);\n        } else {\n            // Check mode: assert invariants and fail if broken.\n            call_results = assert_invariants(\n                invariant_contract,\n                invariant_config,\n                &invariant_test.targeted_contracts,\n                &invariant_run.executor,\n                &invariant_run.inputs,\n                &mut invariant_test.test_data.failures,\n            )?;\n            if call_results.is_none() {\n                return Ok(RichInvariantResults::new(false, None));\n            }\n        }\n    } else {\n        // Increase the amount of reverts.\n        let invariant_data = &mut invariant_test.test_data;\n        invariant_data.failures.reverts += 1;\n        // If fail on revert is set, we must return immediately.\n        if invariant_config.fail_on_revert {\n            let case_data = FailedInvariantCaseData::new(\n                invariant_contract,\n                invariant_config,\n                &invariant_test.targeted_contracts,\n                &invariant_run.inputs,\n                call_result,\n                &[],\n            );\n            invariant_data.failures.revert_reason = Some(case_data.revert_reason.clone());\n            invariant_data.failures.error = Some(InvariantFuzzError::Revert(case_data));\n\n            return Ok(RichInvariantResults::new(false, None));\n        } else if call_result.reverted && !is_optimization {\n            // If we don't fail test on revert then remove last reverted call from inputs.\n            // In optimization mode, we keep reverted calls to preserve warp/roll values\n            // for correct replay during shrinking.\n            invariant_run.inputs.pop();\n        }\n    }\n    Ok(RichInvariantResults::new(true, call_results))\n}\n\n/// Given the executor state, asserts conditions within `afterInvariant` function.\n/// If call fails then the invariant test is considered failed.\npub(crate) fn assert_after_invariant(\n    invariant_contract: &InvariantContract<'_>,\n    invariant_test: &mut InvariantTest,\n    invariant_run: &InvariantTestRun,\n    invariant_config: &InvariantConfig,\n) -> Result<bool> {\n    let (call_result, success) =\n        call_after_invariant_function(&invariant_run.executor, invariant_contract.address)?;\n    // Fail the test case if `afterInvariant` doesn't succeed.\n    if !success {\n        let case_data = FailedInvariantCaseData::new(\n            invariant_contract,\n            invariant_config,\n            &invariant_test.targeted_contracts,\n            &invariant_run.inputs,\n            call_result,\n            &[],\n        );\n        invariant_test.set_error(InvariantFuzzError::BrokenInvariant(case_data));\n    }\n    Ok(success)\n}\n"
  },
  {
    "path": "crates/evm/evm/src/executors/invariant/shrink.rs",
    "content": "use crate::executors::{\n    EarlyExit, Executor,\n    invariant::{call_after_invariant_function, call_invariant_function, execute_tx},\n};\nuse alloy_primitives::{Address, Bytes, I256, U256};\nuse foundry_config::InvariantConfig;\nuse foundry_evm_core::constants::MAGIC_ASSUME;\nuse foundry_evm_fuzz::{BasicTxDetails, invariant::InvariantContract};\nuse indicatif::ProgressBar;\nuse proptest::bits::{BitSetLike, VarBitSet};\n\n/// Shrinker for a call sequence failure.\n/// Iterates sequence call sequence top down and removes calls one by one.\n/// If the failure is still reproducible with removed call then moves to the next one.\n/// If the failure is not reproducible then restore removed call and moves to next one.\n#[derive(Debug)]\nstruct CallSequenceShrinker {\n    /// Length of call sequence to be shrunk.\n    call_sequence_len: usize,\n    /// Call ids contained in current shrunk sequence.\n    included_calls: VarBitSet,\n}\n\nimpl CallSequenceShrinker {\n    fn new(call_sequence_len: usize) -> Self {\n        Self { call_sequence_len, included_calls: VarBitSet::saturated(call_sequence_len) }\n    }\n\n    /// Return candidate shrink sequence to be tested, by removing ids from original sequence.\n    fn current(&self) -> impl Iterator<Item = usize> + '_ {\n        (0..self.call_sequence_len).filter(|&call_id| self.included_calls.test(call_id))\n    }\n\n    /// Advance to the next call index, wrapping around to 0 at the end.\n    fn next_index(&self, call_idx: usize) -> usize {\n        if call_idx + 1 == self.call_sequence_len { 0 } else { call_idx + 1 }\n    }\n}\n\n/// Resets the progress bar for shrinking.\nfn reset_shrink_progress(config: &InvariantConfig, progress: Option<&ProgressBar>) {\n    if let Some(progress) = progress {\n        progress.set_length(config.shrink_run_limit as u64);\n        progress.reset();\n        progress.set_message(\" Shrink\");\n    }\n}\n\n/// Applies accumulated warp/roll to a call, returning a modified copy.\nfn apply_warp_roll(call: &BasicTxDetails, warp: U256, roll: U256) -> BasicTxDetails {\n    let mut result = call.clone();\n    if warp > U256::ZERO {\n        result.warp = Some(warp);\n    }\n    if roll > U256::ZERO {\n        result.roll = Some(roll);\n    }\n    result\n}\n\n/// Applies warp/roll adjustments directly to the executor's environment.\nfn apply_warp_roll_to_env(executor: &mut Executor, warp: U256, roll: U256) {\n    if warp > U256::ZERO || roll > U256::ZERO {\n        executor.evm_env_mut().block_env.timestamp += warp;\n        executor.evm_env_mut().block_env.number += roll;\n\n        let block_env = executor.evm_env().block_env.clone();\n        if let Some(cheatcodes) = executor.inspector_mut().cheatcodes.as_mut() {\n            if let Some(block) = cheatcodes.block.as_mut() {\n                block.timestamp += warp;\n                block.number += roll;\n            } else {\n                cheatcodes.block = Some(block_env);\n            }\n        }\n    }\n}\n\npub(crate) fn shrink_sequence(\n    config: &InvariantConfig,\n    invariant_contract: &InvariantContract<'_>,\n    calls: &[BasicTxDetails],\n    executor: &Executor,\n    progress: Option<&ProgressBar>,\n    early_exit: &EarlyExit,\n) -> eyre::Result<Vec<BasicTxDetails>> {\n    trace!(target: \"forge::test\", \"Shrinking sequence of {} calls.\", calls.len());\n\n    reset_shrink_progress(config, progress);\n\n    let target_address = invariant_contract.address;\n    let calldata: Bytes = invariant_contract.invariant_function.selector().to_vec().into();\n    // Special case test: the invariant is *unsatisfiable* - it took 0 calls to\n    // break the invariant -- consider emitting a warning.\n    let (_, success) = call_invariant_function(executor, target_address, calldata.clone())?;\n    if !success {\n        return Ok(vec![]);\n    }\n\n    let mut call_idx = 0;\n    let mut shrinker = CallSequenceShrinker::new(calls.len());\n\n    for _ in 0..config.shrink_run_limit {\n        if early_exit.should_stop() {\n            break;\n        }\n\n        shrinker.included_calls.clear(call_idx);\n\n        match check_sequence(\n            executor.clone(),\n            calls,\n            shrinker.current().collect(),\n            target_address,\n            calldata.clone(),\n            config.fail_on_revert,\n            invariant_contract.call_after_invariant,\n        ) {\n            // If candidate sequence still fails, shrink until shortest possible.\n            Ok((false, _)) if shrinker.included_calls.count() == 1 => break,\n            // Restore last removed call as it caused sequence to pass invariant.\n            Ok((true, _)) => shrinker.included_calls.set(call_idx),\n            _ => {}\n        }\n\n        if let Some(progress) = progress {\n            progress.inc(1);\n        }\n\n        call_idx = shrinker.next_index(call_idx);\n    }\n\n    Ok(shrinker.current().map(|idx| &calls[idx]).cloned().collect())\n}\n\n/// Checks if the given call sequence breaks the invariant.\n///\n/// Used in shrinking phase for checking candidate sequences and in replay failures phase to test\n/// persisted failures.\n/// Returns the result of invariant check (and afterInvariant call if needed) and if sequence was\n/// entirely applied.\npub fn check_sequence(\n    mut executor: Executor,\n    calls: &[BasicTxDetails],\n    sequence: Vec<usize>,\n    test_address: Address,\n    calldata: Bytes,\n    fail_on_revert: bool,\n    call_after_invariant: bool,\n) -> eyre::Result<(bool, bool)> {\n    // Apply the call sequence.\n    for call_index in sequence {\n        let tx = &calls[call_index];\n        let mut call_result = execute_tx(&mut executor, tx)?;\n        executor.commit(&mut call_result);\n        // Ignore calls reverted with `MAGIC_ASSUME`. This is needed to handle failed scenarios that\n        // are replayed with a modified version of test driver (that use new `vm.assume`\n        // cheatcodes).\n        if call_result.reverted && fail_on_revert && call_result.result.as_ref() != MAGIC_ASSUME {\n            // Candidate sequence fails test.\n            // We don't have to apply remaining calls to check sequence.\n            return Ok((false, false));\n        }\n    }\n\n    // Check the invariant for call sequence.\n    let (_, mut success) = call_invariant_function(&executor, test_address, calldata)?;\n    // Check after invariant result if invariant is success and `afterInvariant` function is\n    // declared.\n    if success && call_after_invariant {\n        (_, success) = call_after_invariant_function(&executor, test_address)?;\n    }\n\n    Ok((success, true))\n}\n\n/// Shrinks a call sequence to the shortest sequence that still produces the target optimization\n/// value. This is specifically for optimization mode where we want to find the minimal sequence\n/// that achieves the maximum value.\n///\n/// Unlike `shrink_sequence` (for check mode), this function:\n/// - Accumulates warp/roll values from removed calls into the next kept call\n/// - Checks for target value equality rather than invariant failure\npub(crate) fn shrink_sequence_value(\n    config: &InvariantConfig,\n    invariant_contract: &InvariantContract<'_>,\n    calls: &[BasicTxDetails],\n    executor: &Executor,\n    target_value: I256,\n    progress: Option<&ProgressBar>,\n    early_exit: &EarlyExit,\n) -> eyre::Result<Vec<BasicTxDetails>> {\n    trace!(target: \"forge::test\", \"Shrinking optimization sequence of {} calls for target value {}.\", calls.len(), target_value);\n\n    reset_shrink_progress(config, progress);\n\n    let target_address = invariant_contract.address;\n    let calldata: Bytes = invariant_contract.invariant_function.selector().to_vec().into();\n\n    // Special case: check if target value is achieved with 0 calls.\n    if check_sequence_value(executor.clone(), calls, vec![], target_address, calldata.clone())?\n        == Some(target_value)\n    {\n        return Ok(vec![]);\n    }\n\n    let mut call_idx = 0;\n    let mut shrinker = CallSequenceShrinker::new(calls.len());\n\n    for _ in 0..config.shrink_run_limit {\n        if early_exit.should_stop() {\n            break;\n        }\n\n        shrinker.included_calls.clear(call_idx);\n\n        let keeps_target = check_sequence_value(\n            executor.clone(),\n            calls,\n            shrinker.current().collect(),\n            target_address,\n            calldata.clone(),\n        )? == Some(target_value);\n\n        if keeps_target {\n            if shrinker.included_calls.count() == 1 {\n                break;\n            }\n        } else {\n            shrinker.included_calls.set(call_idx);\n        }\n\n        if let Some(progress) = progress {\n            progress.inc(1);\n        }\n\n        call_idx = shrinker.next_index(call_idx);\n    }\n\n    // Build the final shrunk sequence, accumulating warp/roll from removed calls.\n    let mut result = Vec::new();\n    let mut accumulated_warp = U256::ZERO;\n    let mut accumulated_roll = U256::ZERO;\n\n    for (idx, call) in calls.iter().enumerate() {\n        accumulated_warp += call.warp.unwrap_or(U256::ZERO);\n        accumulated_roll += call.roll.unwrap_or(U256::ZERO);\n\n        if shrinker.included_calls.test(idx) {\n            result.push(apply_warp_roll(call, accumulated_warp, accumulated_roll));\n            accumulated_warp = U256::ZERO;\n            accumulated_roll = U256::ZERO;\n        }\n    }\n\n    Ok(result)\n}\n\n/// Executes a call sequence and returns the optimization value (int256) from the invariant\n/// function. Used during shrinking for optimization mode.\n///\n/// Returns `None` if the invariant call fails or doesn't return a valid int256.\n/// Unlike `check_sequence`, this applies warp/roll from ALL calls (including removed ones).\npub fn check_sequence_value(\n    mut executor: Executor,\n    calls: &[BasicTxDetails],\n    sequence: Vec<usize>,\n    test_address: Address,\n    calldata: Bytes,\n) -> eyre::Result<Option<I256>> {\n    let mut accumulated_warp = U256::ZERO;\n    let mut accumulated_roll = U256::ZERO;\n    let mut seq_iter = sequence.iter().peekable();\n\n    for (idx, tx) in calls.iter().enumerate() {\n        accumulated_warp += tx.warp.unwrap_or(U256::ZERO);\n        accumulated_roll += tx.roll.unwrap_or(U256::ZERO);\n\n        if seq_iter.peek() == Some(&&idx) {\n            seq_iter.next();\n\n            let tx_with_accumulated = apply_warp_roll(tx, accumulated_warp, accumulated_roll);\n            let mut call_result = execute_tx(&mut executor, &tx_with_accumulated)?;\n\n            if !call_result.reverted {\n                executor.commit(&mut call_result);\n            }\n\n            accumulated_warp = U256::ZERO;\n            accumulated_roll = U256::ZERO;\n        }\n    }\n\n    // Apply any remaining accumulated warp/roll before calling invariant.\n    apply_warp_roll_to_env(&mut executor, accumulated_warp, accumulated_roll);\n\n    let (inv_result, success) = call_invariant_function(&executor, test_address, calldata)?;\n\n    if success\n        && inv_result.result.len() >= 32\n        && let Some(value) = I256::try_from_be_slice(&inv_result.result[..32])\n    {\n        return Ok(Some(value));\n    }\n\n    Ok(None)\n}\n"
  },
  {
    "path": "crates/evm/evm/src/executors/mod.rs",
    "content": "//! EVM executor abstractions, which can execute calls.\n//!\n//! Used for running tests, scripts, and interacting with the inner backend which holds the state.\n\n// TODO: The individual executors in this module should be moved into the respective crates, and the\n// `Executor` struct should be accessed using a trait defined in `foundry-evm-core` instead of\n// the concrete `Executor` type.\n\nuse crate::inspectors::{\n    Cheatcodes, InspectorData, InspectorStack, cheatcodes::BroadcastableTransactions,\n};\nuse alloy_dyn_abi::{DynSolValue, FunctionExt, JsonAbiExt};\nuse alloy_json_abi::Function;\nuse alloy_primitives::{\n    Address, Bytes, Log, TxKind, U256, keccak256,\n    map::{AddressHashMap, HashMap},\n};\nuse alloy_sol_types::{SolCall, sol};\nuse foundry_evm_core::{\n    EvmEnv,\n    backend::{Backend, BackendError, BackendResult, CowBackend, DatabaseExt, GLOBAL_FAIL_SLOT},\n    constants::{\n        CALLER, CHEATCODE_ADDRESS, CHEATCODE_CONTRACT_HASH, DEFAULT_CREATE2_DEPLOYER,\n        DEFAULT_CREATE2_DEPLOYER_CODE, DEFAULT_CREATE2_DEPLOYER_DEPLOYER,\n    },\n    decode::{RevertDecoder, SkipReason},\n    utils::StateChangeset,\n};\nuse foundry_evm_coverage::HitMaps;\nuse foundry_evm_traces::{SparsedTraceArena, TraceMode};\nuse revm::{\n    bytecode::Bytecode,\n    context::{BlockEnv, TxEnv},\n    context_interface::{\n        result::{ExecutionResult, Output, ResultAndState},\n        transaction::SignedAuthorization,\n    },\n    database::{DatabaseCommit, DatabaseRef},\n    interpreter::{InstructionResult, return_ok},\n    primitives::hardfork::SpecId,\n};\nuse std::{\n    borrow::Cow,\n    sync::{\n        Arc,\n        atomic::{AtomicBool, Ordering},\n    },\n    time::{Duration, Instant},\n};\n\nmod builder;\npub use builder::ExecutorBuilder;\n\npub mod fuzz;\npub use fuzz::FuzzedExecutor;\n\npub mod invariant;\npub use invariant::InvariantExecutor;\n\nmod corpus;\nmod trace;\n\npub use trace::TracingExecutor;\n\nconst DURATION_BETWEEN_METRICS_REPORT: Duration = Duration::from_secs(5);\n\nsol! {\n    interface ITest {\n        function setUp() external;\n        function failed() external view returns (bool failed);\n\n        #[derive(Default)]\n        function beforeTestSetup(bytes4 testSelector) public view returns (bytes[] memory beforeTestCalldata);\n    }\n}\n\n/// EVM executor.\n///\n/// The executor can be configured with various `revm::Inspector`s, like `Cheatcodes`.\n///\n/// There are multiple ways of interacting the EVM:\n/// - `call`: executes a transaction, but does not persist any state changes; similar to `eth_call`,\n///   where the EVM state is unchanged after the call.\n/// - `transact`: executes a transaction and persists the state changes\n/// - `deploy`: a special case of `transact`, specialized for persisting the state of a contract\n///   deployment\n/// - `setup`: a special case of `transact`, used to set up the environment for a test\n#[derive(Clone, Debug)]\npub struct Executor {\n    /// The underlying `revm::Database` that contains the EVM storage.\n    ///\n    /// Wrapped in `Arc` for efficient cloning during parallel fuzzing. Use [`Arc::make_mut`]\n    /// for copy-on-write semantics when mutation is needed.\n    // Note: We do not store an EVM here, since we are really\n    // only interested in the database. REVM's `EVM` is a thin\n    // wrapper around spawning a new EVM on every call anyway,\n    // so the performance difference should be negligible.\n    backend: Arc<Backend>,\n    /// The EVM environment (block and cfg).\n    evm_env: EvmEnv,\n    /// The transaction environment.\n    tx_env: TxEnv,\n    /// The Revm inspector stack.\n    inspector: InspectorStack,\n    /// The gas limit for calls and deployments.\n    gas_limit: u64,\n    /// Whether `failed()` should be called on the test contract to determine if the test failed.\n    legacy_assertions: bool,\n}\n\nimpl Executor {\n    /// Creates a new `Executor` with the given arguments.\n    #[inline]\n    pub fn new(\n        mut backend: Backend,\n        evm_env: EvmEnv,\n        tx_env: TxEnv,\n        inspector: InspectorStack,\n        gas_limit: u64,\n        legacy_assertions: bool,\n    ) -> Self {\n        // Need to create a non-empty contract on the cheatcodes address so `extcodesize` checks\n        // do not fail.\n        backend.insert_account_info(\n            CHEATCODE_ADDRESS,\n            revm::state::AccountInfo {\n                code: Some(Bytecode::new_raw(Bytes::from_static(&[0]))),\n                // Also set the code hash manually so that it's not computed later.\n                // The code hash value does not matter, as long as it's not zero or `KECCAK_EMPTY`.\n                code_hash: CHEATCODE_CONTRACT_HASH,\n                ..Default::default()\n            },\n        );\n\n        Self {\n            backend: Arc::new(backend),\n            evm_env,\n            tx_env,\n            inspector,\n            gas_limit,\n            legacy_assertions,\n        }\n    }\n\n    fn clone_with_backend(&self, backend: Backend) -> Self {\n        let mut evm_env = self.evm_env.clone();\n        evm_env.cfg_env.spec = self.spec_id();\n        Self {\n            backend: Arc::new(backend),\n            evm_env,\n            tx_env: self.tx_env.clone(),\n            inspector: self.inspector().clone(),\n            gas_limit: self.gas_limit,\n            legacy_assertions: self.legacy_assertions,\n        }\n    }\n\n    /// Returns a reference to the EVM backend.\n    pub fn backend(&self) -> &Backend {\n        &self.backend\n    }\n\n    /// Returns a mutable reference to the EVM backend.\n    ///\n    /// Uses copy-on-write semantics: if other clones of this executor share the backend,\n    /// this will clone the backend first.\n    pub fn backend_mut(&mut self) -> &mut Backend {\n        Arc::make_mut(&mut self.backend)\n    }\n\n    /// Returns a reference to the EVM environment (block and cfg).\n    pub fn evm_env(&self) -> &EvmEnv {\n        &self.evm_env\n    }\n\n    /// Returns a mutable reference to the EVM environment (block and cfg).\n    pub fn evm_env_mut(&mut self) -> &mut EvmEnv {\n        &mut self.evm_env\n    }\n\n    /// Returns a reference to the transaction environment.\n    pub fn tx_env(&self) -> &TxEnv {\n        &self.tx_env\n    }\n\n    /// Returns a mutable reference to the transaction environment.\n    pub fn tx_env_mut(&mut self) -> &mut TxEnv {\n        &mut self.tx_env\n    }\n\n    /// Returns a reference to the EVM inspector.\n    pub fn inspector(&self) -> &InspectorStack {\n        &self.inspector\n    }\n\n    /// Returns a mutable reference to the EVM inspector.\n    pub fn inspector_mut(&mut self) -> &mut InspectorStack {\n        &mut self.inspector\n    }\n\n    /// Returns the EVM spec ID.\n    pub fn spec_id(&self) -> SpecId {\n        self.evm_env.cfg_env.spec\n    }\n\n    /// Sets the EVM spec ID.\n    pub fn set_spec_id(&mut self, spec_id: SpecId) {\n        self.evm_env.cfg_env.spec = spec_id;\n    }\n\n    /// Returns the gas limit for calls and deployments.\n    ///\n    /// This is different from the gas limit imposed by the passed in environment, as those limits\n    /// are used by the EVM for certain opcodes like `gaslimit`.\n    pub fn gas_limit(&self) -> u64 {\n        self.gas_limit\n    }\n\n    /// Sets the gas limit for calls and deployments.\n    pub fn set_gas_limit(&mut self, gas_limit: u64) {\n        self.gas_limit = gas_limit;\n    }\n\n    /// Returns whether `failed()` should be called on the test contract to determine if the test\n    /// failed.\n    pub fn legacy_assertions(&self) -> bool {\n        self.legacy_assertions\n    }\n\n    /// Sets whether `failed()` should be called on the test contract to determine if the test\n    /// failed.\n    pub fn set_legacy_assertions(&mut self, legacy_assertions: bool) {\n        self.legacy_assertions = legacy_assertions;\n    }\n\n    /// Creates the default CREATE2 Contract Deployer for local tests and scripts.\n    pub fn deploy_create2_deployer(&mut self) -> eyre::Result<()> {\n        trace!(\"deploying local create2 deployer\");\n        let create2_deployer_account = self\n            .backend()\n            .basic_ref(DEFAULT_CREATE2_DEPLOYER)?\n            .ok_or_else(|| BackendError::MissingAccount(DEFAULT_CREATE2_DEPLOYER))?;\n\n        // If the deployer is not currently deployed, deploy the default one.\n        if create2_deployer_account.code.is_none_or(|code| code.is_empty()) {\n            let creator = DEFAULT_CREATE2_DEPLOYER_DEPLOYER;\n\n            // Probably 0, but just in case.\n            let initial_balance = self.get_balance(creator)?;\n            self.set_balance(creator, U256::MAX)?;\n\n            let res =\n                self.deploy(creator, DEFAULT_CREATE2_DEPLOYER_CODE.into(), U256::ZERO, None)?;\n            trace!(create2=?res.address, \"deployed local create2 deployer\");\n\n            self.set_balance(creator, initial_balance)?;\n        }\n        Ok(())\n    }\n\n    /// Set the balance of an account.\n    pub fn set_balance(&mut self, address: Address, amount: U256) -> BackendResult<()> {\n        trace!(?address, ?amount, \"setting account balance\");\n        let mut account = self.backend().basic_ref(address)?.unwrap_or_default();\n        account.balance = amount;\n        self.backend_mut().insert_account_info(address, account);\n        Ok(())\n    }\n\n    /// Gets the balance of an account\n    pub fn get_balance(&self, address: Address) -> BackendResult<U256> {\n        Ok(self.backend().basic_ref(address)?.map(|acc| acc.balance).unwrap_or_default())\n    }\n\n    /// Set the nonce of an account.\n    pub fn set_nonce(&mut self, address: Address, nonce: u64) -> BackendResult<()> {\n        let mut account = self.backend().basic_ref(address)?.unwrap_or_default();\n        account.nonce = nonce;\n        self.backend_mut().insert_account_info(address, account);\n        self.tx_env_mut().nonce = nonce;\n        Ok(())\n    }\n\n    /// Returns the nonce of an account.\n    pub fn get_nonce(&self, address: Address) -> BackendResult<u64> {\n        Ok(self.backend().basic_ref(address)?.map(|acc| acc.nonce).unwrap_or_default())\n    }\n\n    /// Set the code of an account.\n    pub fn set_code(&mut self, address: Address, code: Bytecode) -> BackendResult<()> {\n        let mut account = self.backend().basic_ref(address)?.unwrap_or_default();\n        account.code_hash = keccak256(code.original_byte_slice());\n        account.code = Some(code);\n        self.backend_mut().insert_account_info(address, account);\n        Ok(())\n    }\n\n    /// Set the storage of an account.\n    pub fn set_storage(\n        &mut self,\n        address: Address,\n        storage: HashMap<U256, U256>,\n    ) -> BackendResult<()> {\n        self.backend_mut().replace_account_storage(address, storage)?;\n        Ok(())\n    }\n\n    /// Set a storage slot of an account.\n    pub fn set_storage_slot(\n        &mut self,\n        address: Address,\n        slot: U256,\n        value: U256,\n    ) -> BackendResult<()> {\n        self.backend_mut().insert_account_storage(address, slot, value)?;\n        Ok(())\n    }\n\n    /// Returns `true` if the account has no code.\n    pub fn is_empty_code(&self, address: Address) -> BackendResult<bool> {\n        Ok(self.backend().basic_ref(address)?.map(|acc| acc.is_empty_code_hash()).unwrap_or(true))\n    }\n\n    #[inline]\n    pub fn set_tracing(&mut self, mode: TraceMode) -> &mut Self {\n        self.inspector_mut().tracing(mode);\n        self\n    }\n\n    #[inline]\n    pub fn set_script_execution(&mut self, script_address: Address) {\n        self.inspector_mut().script(script_address);\n    }\n\n    #[inline]\n    pub fn set_trace_printer(&mut self, trace_printer: bool) -> &mut Self {\n        self.inspector_mut().print(trace_printer);\n        self\n    }\n\n    #[inline]\n    pub fn create2_deployer(&self) -> Address {\n        self.inspector().create2_deployer\n    }\n\n    /// Deploys a contract and commits the new state to the underlying database.\n    ///\n    /// Executes a CREATE transaction with the contract `code` and persistent database state\n    /// modifications.\n    pub fn deploy(\n        &mut self,\n        from: Address,\n        code: Bytes,\n        value: U256,\n        rd: Option<&RevertDecoder>,\n    ) -> Result<DeployResult, EvmError> {\n        let (evm_env, tx_env) = self.build_test_env(from, TxKind::Create, code, value);\n        self.deploy_with_env(evm_env, tx_env, rd)\n    }\n\n    /// Deploys a contract using the given `env` and commits the new state to the underlying\n    /// database.\n    ///\n    /// # Panics\n    ///\n    /// Panics if `tx_env.kind` is not `TxKind::Create(_)`.\n    #[instrument(name = \"deploy\", level = \"debug\", skip_all)]\n    pub fn deploy_with_env(\n        &mut self,\n        evm_env: EvmEnv,\n        tx_env: TxEnv,\n        rd: Option<&RevertDecoder>,\n    ) -> Result<DeployResult, EvmError> {\n        assert!(\n            matches!(tx_env.kind, TxKind::Create),\n            \"Expected create transaction, got {:?}\",\n            tx_env.kind\n        );\n        trace!(sender=%tx_env.caller, \"deploying contract\");\n\n        let mut result = self.transact_with_env(evm_env, tx_env)?;\n        result = result.into_result(rd)?;\n        let Some(Output::Create(_, Some(address))) = result.out else {\n            panic!(\"Deployment succeeded, but no address was returned: {result:#?}\");\n        };\n\n        // also mark this library as persistent, this will ensure that the state of the library is\n        // persistent across fork swaps in forking mode\n        self.backend_mut().add_persistent_account(address);\n\n        trace!(%address, \"deployed contract\");\n\n        Ok(DeployResult { raw: result, address })\n    }\n\n    /// Calls the `setUp()` function on a contract.\n    ///\n    /// This will commit any state changes to the underlying database.\n    ///\n    /// Ayn changes made during the setup call to env's block environment are persistent, for\n    /// example `vm.chainId()` will change the `block.chainId` for all subsequent test calls.\n    #[instrument(name = \"setup\", level = \"debug\", skip_all)]\n    pub fn setup(\n        &mut self,\n        from: Option<Address>,\n        to: Address,\n        rd: Option<&RevertDecoder>,\n    ) -> Result<RawCallResult, EvmError> {\n        trace!(?from, ?to, \"setting up contract\");\n\n        let from = from.unwrap_or(CALLER);\n        self.backend_mut().set_test_contract(to).set_caller(from);\n        let calldata = Bytes::from_static(&ITest::setUpCall::SELECTOR);\n        let mut res = self.transact_raw(from, to, calldata, U256::ZERO)?;\n        res = res.into_result(rd)?;\n\n        // record any changes made to the block's environment during setup\n        self.evm_env_mut().block_env = res.evm_env.block_env.clone();\n        // and also the chainid, which can be set manually\n        self.evm_env_mut().cfg_env.chain_id = res.evm_env.cfg_env.chain_id;\n\n        let success =\n            self.is_raw_call_success(to, Cow::Borrowed(&res.state_changeset), &res, false);\n        if !success {\n            return Err(res.into_execution_error(\"execution error\".to_string()).into());\n        }\n\n        Ok(res)\n    }\n\n    /// Performs a call to an account on the current state of the VM.\n    pub fn call(\n        &self,\n        from: Address,\n        to: Address,\n        func: &Function,\n        args: &[DynSolValue],\n        value: U256,\n        rd: Option<&RevertDecoder>,\n    ) -> Result<CallResult, EvmError> {\n        let calldata = Bytes::from(func.abi_encode_input(args)?);\n        let result = self.call_raw(from, to, calldata, value)?;\n        result.into_decoded_result(func, rd)\n    }\n\n    /// Performs a call to an account on the current state of the VM.\n    pub fn call_sol<C: SolCall>(\n        &self,\n        from: Address,\n        to: Address,\n        args: &C,\n        value: U256,\n        rd: Option<&RevertDecoder>,\n    ) -> Result<CallResult<C::Return>, EvmError> {\n        let calldata = Bytes::from(args.abi_encode());\n        let mut raw = self.call_raw(from, to, calldata, value)?;\n        raw = raw.into_result(rd)?;\n        Ok(CallResult { decoded_result: C::abi_decode_returns(&raw.result)?, raw })\n    }\n\n    /// Performs a call to an account on the current state of the VM.\n    pub fn transact(\n        &mut self,\n        from: Address,\n        to: Address,\n        func: &Function,\n        args: &[DynSolValue],\n        value: U256,\n        rd: Option<&RevertDecoder>,\n    ) -> Result<CallResult, EvmError> {\n        let calldata = Bytes::from(func.abi_encode_input(args)?);\n        let result = self.transact_raw(from, to, calldata, value)?;\n        result.into_decoded_result(func, rd)\n    }\n\n    /// Performs a raw call to an account on the current state of the VM.\n    pub fn call_raw(\n        &self,\n        from: Address,\n        to: Address,\n        calldata: Bytes,\n        value: U256,\n    ) -> eyre::Result<RawCallResult> {\n        let (evm_env, tx_env) = self.build_test_env(from, TxKind::Call(to), calldata, value);\n        self.call_with_env(evm_env, tx_env)\n    }\n\n    /// Performs a raw call to an account on the current state of the VM with an EIP-7702\n    /// authorization list.\n    pub fn call_raw_with_authorization(\n        &mut self,\n        from: Address,\n        to: Address,\n        calldata: Bytes,\n        value: U256,\n        authorization_list: Vec<SignedAuthorization>,\n    ) -> eyre::Result<RawCallResult> {\n        let (evm_env, mut tx_env) = self.build_test_env(from, to.into(), calldata, value);\n        tx_env.set_signed_authorization(authorization_list);\n        tx_env.tx_type = 4;\n        self.call_with_env(evm_env, tx_env)\n    }\n\n    /// Performs a raw call to an account on the current state of the VM.\n    pub fn transact_raw(\n        &mut self,\n        from: Address,\n        to: Address,\n        calldata: Bytes,\n        value: U256,\n    ) -> eyre::Result<RawCallResult> {\n        let (evm_env, tx_env) = self.build_test_env(from, TxKind::Call(to), calldata, value);\n        self.transact_with_env(evm_env, tx_env)\n    }\n\n    /// Performs a raw call to an account on the current state of the VM with an EIP-7702\n    /// authorization last.\n    pub fn transact_raw_with_authorization(\n        &mut self,\n        from: Address,\n        to: Address,\n        calldata: Bytes,\n        value: U256,\n        authorization_list: Vec<SignedAuthorization>,\n    ) -> eyre::Result<RawCallResult> {\n        let (evm_env, mut tx_env) = self.build_test_env(from, TxKind::Call(to), calldata, value);\n        tx_env.set_signed_authorization(authorization_list);\n        tx_env.tx_type = 4;\n        self.transact_with_env(evm_env, tx_env)\n    }\n\n    /// Execute the transaction configured in `tx_env`.\n    ///\n    /// The state after the call is **not** persisted.\n    #[instrument(name = \"call\", level = \"debug\", skip_all)]\n    pub fn call_with_env(\n        &self,\n        mut evm_env: EvmEnv,\n        mut tx_env: TxEnv,\n    ) -> eyre::Result<RawCallResult> {\n        let mut stack = self.inspector().clone();\n        let mut backend = CowBackend::new_borrowed(self.backend());\n        let result = backend.inspect(&mut evm_env, &mut tx_env, &mut stack)?;\n        convert_executed_result(\n            evm_env,\n            tx_env,\n            stack,\n            result,\n            backend.has_state_snapshot_failure(),\n        )\n    }\n\n    /// Execute the transaction configured in `tx_env`.\n    #[instrument(name = \"transact\", level = \"debug\", skip_all)]\n    pub fn transact_with_env(\n        &mut self,\n        mut evm_env: EvmEnv,\n        mut tx_env: TxEnv,\n    ) -> eyre::Result<RawCallResult> {\n        let mut stack = self.inspector().clone();\n        let backend = self.backend_mut();\n        let result: revm::context::result::ExecResultAndState<ExecutionResult> =\n            backend.inspect(&mut evm_env, &mut tx_env, &mut stack)?;\n        let mut result = convert_executed_result(\n            evm_env,\n            tx_env,\n            stack,\n            result,\n            backend.has_state_snapshot_failure(),\n        )?;\n        self.commit(&mut result);\n        Ok(result)\n    }\n\n    /// Commit the changeset to the database and adjust `self.inspector_config` values according to\n    /// the executed call result.\n    ///\n    /// This should not be exposed to the user, as it should be called only by `transact*`.\n    #[instrument(name = \"commit\", level = \"debug\", skip_all)]\n    fn commit(&mut self, result: &mut RawCallResult) {\n        // Persist changes to db.\n        self.backend_mut().commit(result.state_changeset.clone());\n\n        // Persist cheatcode state.\n        self.inspector_mut().cheatcodes = result.cheatcodes.take();\n        if let Some(cheats) = self.inspector_mut().cheatcodes.as_mut() {\n            // Clear broadcastable transactions\n            cheats.broadcastable_transactions.clear();\n            cheats.ignored_traces.ignored.clear();\n\n            // if tracing was paused but never unpaused, we should begin next frame with tracing\n            // still paused\n            if let Some(last_pause_call) = cheats.ignored_traces.last_pause_call.as_mut() {\n                *last_pause_call = (0, 0);\n            }\n        }\n\n        // Persist the changed environment.\n        self.inspector_mut().set_env(&result.evm_env, &result.tx_env);\n    }\n\n    /// Returns `true` if a test can be considered successful.\n    ///\n    /// This is the same as [`Self::is_success`], but will consume the `state_changeset` map to use\n    /// internally when calling `failed()`.\n    pub fn is_raw_call_mut_success(\n        &self,\n        address: Address,\n        call_result: &mut RawCallResult,\n        should_fail: bool,\n    ) -> bool {\n        self.is_raw_call_success(\n            address,\n            Cow::Owned(std::mem::take(&mut call_result.state_changeset)),\n            call_result,\n            should_fail,\n        )\n    }\n\n    /// Returns `true` if a test can be considered successful.\n    ///\n    /// This is the same as [`Self::is_success`], but intended for outcomes of [`Self::call_raw`].\n    pub fn is_raw_call_success(\n        &self,\n        address: Address,\n        state_changeset: Cow<'_, StateChangeset>,\n        call_result: &RawCallResult,\n        should_fail: bool,\n    ) -> bool {\n        if call_result.has_state_snapshot_failure {\n            // a failure occurred in a reverted snapshot, which is considered a failed test\n            return should_fail;\n        }\n        self.is_success(address, call_result.reverted, state_changeset, should_fail)\n    }\n\n    /// Returns `true` if a test can be considered successful.\n    ///\n    /// If the call succeeded, we also have to check the global and local failure flags.\n    ///\n    /// These are set by the test contract itself when an assertion fails, using the internal `fail`\n    /// function. The global flag is located in [`CHEATCODE_ADDRESS`] at slot [`GLOBAL_FAIL_SLOT`],\n    /// and the local flag is located in the test contract at an unspecified slot.\n    ///\n    /// This behavior is inherited from Dapptools, where initially only a public\n    /// `failed` variable was used to track test failures, and later, a global failure flag was\n    /// introduced to track failures across multiple contracts in\n    /// [ds-test#30](https://github.com/dapphub/ds-test/pull/30).\n    ///\n    /// The assumption is that the test runner calls `failed` on the test contract to determine if\n    /// it failed. However, we want to avoid this as much as possible, as it is relatively\n    /// expensive to set up an EVM call just for checking a single boolean flag.\n    ///\n    /// See:\n    /// - Newer DSTest: <https://github.com/dapphub/ds-test/blob/e282159d5170298eb2455a6c05280ab5a73a4ef0/src/test.sol#L47-L63>\n    /// - Older DSTest: <https://github.com/dapphub/ds-test/blob/9ca4ecd48862b40d7b0197b600713f64d337af12/src/test.sol#L38-L49>\n    /// - forge-std: <https://github.com/foundry-rs/forge-std/blob/19891e6a0b5474b9ea6827ddb90bb9388f7acfc0/src/StdAssertions.sol#L38-L44>\n    pub fn is_success(\n        &self,\n        address: Address,\n        reverted: bool,\n        state_changeset: Cow<'_, StateChangeset>,\n        should_fail: bool,\n    ) -> bool {\n        let success = self.is_success_raw(address, reverted, state_changeset);\n        should_fail ^ success\n    }\n\n    #[instrument(name = \"is_success\", level = \"debug\", skip_all)]\n    fn is_success_raw(\n        &self,\n        address: Address,\n        reverted: bool,\n        state_changeset: Cow<'_, StateChangeset>,\n    ) -> bool {\n        // The call reverted.\n        if reverted {\n            return false;\n        }\n\n        // A failure occurred in a reverted snapshot, which is considered a failed test.\n        if self.backend().has_state_snapshot_failure() {\n            return false;\n        }\n\n        // Check the global failure slot.\n        if let Some(acc) = state_changeset.get(&CHEATCODE_ADDRESS)\n            && let Some(failed_slot) = acc.storage.get(&GLOBAL_FAIL_SLOT)\n            && !failed_slot.present_value().is_zero()\n        {\n            return false;\n        }\n        if let Ok(failed_slot) = self.backend().storage_ref(CHEATCODE_ADDRESS, GLOBAL_FAIL_SLOT)\n            && !failed_slot.is_zero()\n        {\n            return false;\n        }\n\n        if !self.legacy_assertions {\n            return true;\n        }\n\n        // Finally, resort to calling `DSTest::failed`.\n        {\n            // Construct a new bare-bones backend to evaluate success.\n            let mut backend = self.backend().clone_empty();\n\n            // We only clone the test contract and cheatcode accounts,\n            // that's all we need to evaluate success.\n            for address in [address, CHEATCODE_ADDRESS] {\n                let Ok(acc) = self.backend().basic_ref(address) else { return false };\n                backend.insert_account_info(address, acc.unwrap_or_default());\n            }\n\n            // If this test failed any asserts, then this changeset will contain changes\n            // `false -> true` for the contract's `failed` variable and the `globalFailure` flag\n            // in the state of the cheatcode address,\n            // which are both read when we call `\"failed()(bool)\"` in the next step.\n            backend.commit(state_changeset.into_owned());\n\n            // Check if a DSTest assertion failed\n            let executor = self.clone_with_backend(backend);\n            let call = executor.call_sol(CALLER, address, &ITest::failedCall {}, U256::ZERO, None);\n            match call {\n                Ok(CallResult { raw: _, decoded_result: failed }) => {\n                    trace!(failed, \"DSTest::failed()\");\n                    !failed\n                }\n                Err(err) => {\n                    trace!(%err, \"failed to call DSTest::failed()\");\n                    true\n                }\n            }\n        }\n    }\n\n    /// Creates the environment to use when executing a transaction in a test context\n    ///\n    /// If using a backend with cheatcodes, `tx.gas_price` and `block.number` will be overwritten by\n    /// the cheatcode state in between calls.\n    fn build_test_env(\n        &self,\n        caller: Address,\n        kind: TxKind,\n        data: Bytes,\n        value: U256,\n    ) -> (EvmEnv, TxEnv) {\n        let evm_env = EvmEnv {\n            cfg_env: {\n                let mut cfg = self.evm_env.cfg_env.clone();\n                cfg.spec = self.spec_id();\n                cfg\n            },\n            // We always set the gas price to 0 so we can execute the transaction regardless of\n            // network conditions - the actual gas price is kept in `self.block` and is applied\n            // by the cheatcode handler if it is enabled\n            block_env: BlockEnv {\n                basefee: 0,\n                gas_limit: self.gas_limit,\n                ..self.evm_env.block_env.clone()\n            },\n        };\n        let tx_env = TxEnv {\n            caller,\n            kind,\n            data,\n            value,\n            // As above, we set the gas price to 0.\n            gas_price: 0,\n            gas_priority_fee: None,\n            gas_limit: self.gas_limit,\n            chain_id: Some(self.evm_env.cfg_env.chain_id),\n            ..self.tx_env.clone()\n        };\n        (evm_env, tx_env)\n    }\n\n    pub fn call_sol_default<C: SolCall>(&self, to: Address, args: &C) -> C::Return\n    where\n        C::Return: Default,\n    {\n        self.call_sol(CALLER, to, args, U256::ZERO, None)\n            .map(|c| c.decoded_result)\n            .inspect_err(|e| warn!(target: \"forge::test\", \"failed calling {:?}: {e}\", C::SIGNATURE))\n            .unwrap_or_default()\n    }\n}\n\n/// Represents the context after an execution error occurred.\n#[derive(Debug, thiserror::Error)]\n#[error(\"execution reverted: {reason} (gas: {})\", raw.gas_used)]\npub struct ExecutionErr {\n    /// The raw result of the call.\n    pub raw: RawCallResult,\n    /// The revert reason.\n    pub reason: String,\n}\n\nimpl std::ops::Deref for ExecutionErr {\n    type Target = RawCallResult;\n\n    #[inline]\n    fn deref(&self) -> &Self::Target {\n        &self.raw\n    }\n}\n\nimpl std::ops::DerefMut for ExecutionErr {\n    #[inline]\n    fn deref_mut(&mut self) -> &mut Self::Target {\n        &mut self.raw\n    }\n}\n\n#[derive(Debug, thiserror::Error)]\npub enum EvmError {\n    /// Error which occurred during execution of a transaction.\n    #[error(transparent)]\n    Execution(#[from] Box<ExecutionErr>),\n    /// Error which occurred during ABI encoding/decoding.\n    #[error(transparent)]\n    Abi(#[from] alloy_dyn_abi::Error),\n    /// Error caused which occurred due to calling the `skip` cheatcode.\n    #[error(\"{0}\")]\n    Skip(SkipReason),\n    /// Any other error.\n    #[error(\"{0}\")]\n    Eyre(\n        #[from]\n        #[source]\n        eyre::Report,\n    ),\n}\n\nimpl From<ExecutionErr> for EvmError {\n    fn from(err: ExecutionErr) -> Self {\n        Self::Execution(Box::new(err))\n    }\n}\n\nimpl From<alloy_sol_types::Error> for EvmError {\n    fn from(err: alloy_sol_types::Error) -> Self {\n        Self::Abi(err.into())\n    }\n}\n\n/// The result of a deployment.\n#[derive(Debug)]\npub struct DeployResult {\n    /// The raw result of the deployment.\n    pub raw: RawCallResult,\n    /// The address of the deployed contract\n    pub address: Address,\n}\n\nimpl std::ops::Deref for DeployResult {\n    type Target = RawCallResult;\n\n    #[inline]\n    fn deref(&self) -> &Self::Target {\n        &self.raw\n    }\n}\n\nimpl std::ops::DerefMut for DeployResult {\n    #[inline]\n    fn deref_mut(&mut self) -> &mut Self::Target {\n        &mut self.raw\n    }\n}\n\nimpl From<DeployResult> for RawCallResult {\n    fn from(d: DeployResult) -> Self {\n        d.raw\n    }\n}\n\n/// The result of a raw call.\n#[derive(Debug)]\npub struct RawCallResult {\n    /// The status of the call\n    pub exit_reason: Option<InstructionResult>,\n    /// Whether the call reverted or not\n    pub reverted: bool,\n    /// Whether the call includes a snapshot failure\n    ///\n    /// This is tracked separately from revert because a snapshot failure can occur without a\n    /// revert, since assert failures are stored in a global variable (ds-test legacy)\n    pub has_state_snapshot_failure: bool,\n    /// The raw result of the call.\n    pub result: Bytes,\n    /// The gas used for the call\n    pub gas_used: u64,\n    /// Refunded gas\n    pub gas_refunded: u64,\n    /// The initial gas stipend for the transaction\n    pub stipend: u64,\n    /// The logs emitted during the call\n    pub logs: Vec<Log>,\n    /// The labels assigned to addresses during the call\n    pub labels: AddressHashMap<String>,\n    /// The traces of the call\n    pub traces: Option<SparsedTraceArena>,\n    /// The line coverage info collected during the call\n    pub line_coverage: Option<HitMaps>,\n    /// The edge coverage info collected during the call\n    pub edge_coverage: Option<Vec<u8>>,\n    /// Scripted transactions generated from this call\n    pub transactions: Option<BroadcastableTransactions>,\n    /// The changeset of the state.\n    pub state_changeset: StateChangeset,\n    /// The `EvmEnv` after the call\n    pub evm_env: EvmEnv,\n    /// The `TxEnv` after the call\n    pub tx_env: TxEnv,\n    /// The cheatcode states after execution\n    pub cheatcodes: Option<Box<Cheatcodes>>,\n    /// The raw output of the execution\n    pub out: Option<Output>,\n    /// The chisel state\n    pub chisel_state: Option<(Vec<U256>, Vec<u8>)>,\n    pub reverter: Option<Address>,\n}\n\nimpl Default for RawCallResult {\n    fn default() -> Self {\n        Self {\n            exit_reason: None,\n            reverted: false,\n            has_state_snapshot_failure: false,\n            result: Bytes::new(),\n            gas_used: 0,\n            gas_refunded: 0,\n            stipend: 0,\n            logs: Vec::new(),\n            labels: HashMap::default(),\n            traces: None,\n            line_coverage: None,\n            edge_coverage: None,\n            transactions: None,\n            state_changeset: HashMap::default(),\n            evm_env: EvmEnv::default(),\n            tx_env: TxEnv::default(),\n            cheatcodes: Default::default(),\n            out: None,\n            chisel_state: None,\n            reverter: None,\n        }\n    }\n}\n\nimpl RawCallResult {\n    /// Unpacks an EVM result.\n    pub fn from_evm_result(r: Result<Self, EvmError>) -> eyre::Result<(Self, Option<String>)> {\n        match r {\n            Ok(r) => Ok((r, None)),\n            Err(EvmError::Execution(e)) => Ok((e.raw, Some(e.reason))),\n            Err(e) => Err(e.into()),\n        }\n    }\n\n    /// Converts the result of the call into an `EvmError`.\n    pub fn into_evm_error(self, rd: Option<&RevertDecoder>) -> EvmError {\n        if let Some(reason) = SkipReason::decode(&self.result) {\n            return EvmError::Skip(reason);\n        }\n        let reason = rd.unwrap_or_default().decode(&self.result, self.exit_reason);\n        EvmError::Execution(Box::new(self.into_execution_error(reason)))\n    }\n\n    /// Converts the result of the call into an `ExecutionErr`.\n    pub fn into_execution_error(self, reason: String) -> ExecutionErr {\n        ExecutionErr { raw: self, reason }\n    }\n\n    /// Returns an `EvmError` if the call failed, otherwise returns `self`.\n    pub fn into_result(self, rd: Option<&RevertDecoder>) -> Result<Self, EvmError> {\n        if let Some(reason) = self.exit_reason\n            && reason.is_ok()\n        {\n            Ok(self)\n        } else {\n            Err(self.into_evm_error(rd))\n        }\n    }\n\n    /// Decodes the result of the call with the given function.\n    pub fn into_decoded_result(\n        mut self,\n        func: &Function,\n        rd: Option<&RevertDecoder>,\n    ) -> Result<CallResult, EvmError> {\n        self = self.into_result(rd)?;\n        let mut result = func.abi_decode_output(&self.result)?;\n        let decoded_result = if result.len() == 1 {\n            result.pop().unwrap()\n        } else {\n            // combine results into a tuple\n            DynSolValue::Tuple(result)\n        };\n        Ok(CallResult { raw: self, decoded_result })\n    }\n\n    /// Returns the transactions generated from this call.\n    pub fn transactions(&self) -> Option<&BroadcastableTransactions> {\n        self.cheatcodes.as_ref().map(|c| &c.broadcastable_transactions)\n    }\n\n    /// Update provided history map with edge coverage info collected during this call.\n    /// Uses AFL binning algo <https://github.com/h0mbre/Lucid/blob/3026e7323c52b30b3cf12563954ac1eaa9c6981e/src/coverage.rs#L57-L85>\n    pub fn merge_edge_coverage(&mut self, history_map: &mut [u8]) -> (bool, bool) {\n        let mut new_coverage = false;\n        let mut is_edge = false;\n        if let Some(x) = &mut self.edge_coverage {\n            // Iterate over the current map and the history map together and update\n            // the history map, if we discover some new coverage, report true\n            for (curr, hist) in std::iter::zip(x, history_map) {\n                // If we got a hitcount of at least 1\n                if *curr > 0 {\n                    // Convert hitcount into bucket count\n                    let bucket = match *curr {\n                        0 => 0,\n                        1 => 1,\n                        2 => 2,\n                        3 => 4,\n                        4..=7 => 8,\n                        8..=15 => 16,\n                        16..=31 => 32,\n                        32..=127 => 64,\n                        128..=255 => 128,\n                    };\n\n                    // If the old record for this edge pair is lower, update\n                    if *hist < bucket {\n                        if *hist == 0 {\n                            // Counts as an edge the first time we see it, otherwise it's a feature.\n                            is_edge = true;\n                        }\n                        *hist = bucket;\n                        new_coverage = true;\n                    }\n\n                    // Zero out the current map for next iteration.\n                    *curr = 0;\n                }\n            }\n        }\n        (new_coverage, is_edge)\n    }\n}\n\n/// The result of a call.\npub struct CallResult<T = DynSolValue> {\n    /// The raw result of the call.\n    pub raw: RawCallResult,\n    /// The decoded result of the call.\n    pub decoded_result: T,\n}\n\nimpl std::ops::Deref for CallResult {\n    type Target = RawCallResult;\n\n    #[inline]\n    fn deref(&self) -> &Self::Target {\n        &self.raw\n    }\n}\n\nimpl std::ops::DerefMut for CallResult {\n    #[inline]\n    fn deref_mut(&mut self) -> &mut Self::Target {\n        &mut self.raw\n    }\n}\n\n/// Converts the data aggregated in the `inspector` and `call` to a `RawCallResult`\nfn convert_executed_result(\n    evm_env: EvmEnv,\n    tx_env: TxEnv,\n    inspector: InspectorStack,\n    ResultAndState { result, state: state_changeset }: ResultAndState,\n    has_state_snapshot_failure: bool,\n) -> eyre::Result<RawCallResult> {\n    let (exit_reason, gas_refunded, gas_used, out, exec_logs) = match result {\n        ExecutionResult::Success { reason, gas_used, gas_refunded, output, logs, .. } => {\n            (reason.into(), gas_refunded, gas_used, Some(output), logs)\n        }\n        ExecutionResult::Revert { gas_used, output } => {\n            // Need to fetch the unused gas\n            (InstructionResult::Revert, 0_u64, gas_used, Some(Output::Call(output)), vec![])\n        }\n        ExecutionResult::Halt { reason, gas_used } => {\n            (reason.into(), 0_u64, gas_used, None, vec![])\n        }\n    };\n    let gas = revm::interpreter::gas::calculate_initial_tx_gas(\n        evm_env.cfg_env.spec,\n        &tx_env.data,\n        tx_env.kind.is_create(),\n        tx_env.access_list.len().try_into()?,\n        0,\n        0,\n    );\n\n    let result = match &out {\n        Some(Output::Call(data)) => data.clone(),\n        _ => Bytes::new(),\n    };\n\n    let InspectorData {\n        mut logs,\n        labels,\n        traces,\n        line_coverage,\n        edge_coverage,\n        cheatcodes,\n        chisel_state,\n        reverter,\n    } = inspector.collect();\n\n    if logs.is_empty() {\n        logs = exec_logs;\n    }\n\n    let transactions = cheatcodes\n        .as_ref()\n        .map(|c| c.broadcastable_transactions.clone())\n        .filter(|txs| !txs.is_empty());\n\n    Ok(RawCallResult {\n        exit_reason: Some(exit_reason),\n        reverted: !matches!(exit_reason, return_ok!()),\n        has_state_snapshot_failure,\n        result,\n        gas_used,\n        gas_refunded,\n        stipend: gas.initial_gas,\n        logs,\n        labels,\n        traces,\n        line_coverage,\n        edge_coverage,\n        transactions,\n        state_changeset,\n        evm_env,\n        tx_env,\n        cheatcodes,\n        out,\n        chisel_state,\n        reverter,\n    })\n}\n\n/// Timer for a fuzz test.\npub struct FuzzTestTimer {\n    /// Inner fuzz test timer - (test start time, test duration).\n    inner: Option<(Instant, Duration)>,\n}\n\nimpl FuzzTestTimer {\n    pub fn new(timeout: Option<u32>) -> Self {\n        Self { inner: timeout.map(|timeout| (Instant::now(), Duration::from_secs(timeout.into()))) }\n    }\n\n    /// Whether the fuzz test timer is enabled.\n    pub fn is_enabled(&self) -> bool {\n        self.inner.is_some()\n    }\n\n    /// Whether the current fuzz test timed out and should be stopped.\n    pub fn is_timed_out(&self) -> bool {\n        self.inner.is_some_and(|(start, duration)| start.elapsed() > duration)\n    }\n}\n\n/// Helper struct to enable early exit behavior: when one test fails or run is interrupted,\n/// all other tests stop early.\n#[derive(Clone, Debug)]\npub struct EarlyExit {\n    /// Shared atomic flag set to `true` when a failure occurs or ctrl-c received.\n    inner: Arc<AtomicBool>,\n    /// Whether to exit early on test failure (fail-fast mode).\n    fail_fast: bool,\n}\n\nimpl EarlyExit {\n    pub fn new(fail_fast: bool) -> Self {\n        Self { inner: Arc::new(AtomicBool::new(false)), fail_fast }\n    }\n\n    /// Records a test failure. Only triggers early exit if fail-fast mode is enabled.\n    pub fn record_failure(&self) {\n        if self.fail_fast {\n            self.inner.store(true, Ordering::Relaxed);\n        }\n    }\n\n    /// Records a Ctrl-C interrupt. Always triggers early exit.\n    pub fn record_ctrl_c(&self) {\n        self.inner.store(true, Ordering::Relaxed);\n    }\n\n    /// Whether tests should stop and exit early.\n    pub fn should_stop(&self) -> bool {\n        self.inner.load(Ordering::Relaxed)\n    }\n}\n"
  },
  {
    "path": "crates/evm/evm/src/executors/trace.rs",
    "content": "use crate::executors::{Executor, ExecutorBuilder};\nuse alloy_evm::EvmEnv;\nuse alloy_primitives::{Address, U256, map::HashMap};\nuse alloy_rpc_types::state::StateOverride;\nuse eyre::Context;\nuse foundry_compilers::artifacts::EvmVersion;\nuse foundry_config::{Chain, Config, utils::evm_spec_id};\nuse foundry_evm_core::{backend::Backend, fork::CreateFork, opts::EvmOpts};\nuse foundry_evm_networks::NetworkConfigs;\nuse foundry_evm_traces::TraceMode;\nuse revm::{context::TxEnv, primitives::hardfork::SpecId, state::Bytecode};\nuse std::ops::{Deref, DerefMut};\n\n/// A default executor with tracing enabled\npub struct TracingExecutor {\n    executor: Executor,\n}\n\nimpl TracingExecutor {\n    pub fn new(\n        env: (EvmEnv, TxEnv),\n        fork: CreateFork,\n        version: Option<EvmVersion>,\n        trace_mode: TraceMode,\n        networks: NetworkConfigs,\n        create2_deployer: Address,\n        state_overrides: Option<StateOverride>,\n    ) -> eyre::Result<Self> {\n        let db = Backend::spawn(Some(fork))?;\n        // configures a bare version of the evm executor: no cheatcode and log_collector inspector\n        // is enabled, tracing will be enabled only for the targeted transaction\n        let mut executor = ExecutorBuilder::new()\n            .inspectors(|stack| {\n                stack.trace_mode(trace_mode).networks(networks).create2_deployer(create2_deployer)\n            })\n            .spec_id(evm_spec_id(version.unwrap_or_default()))\n            .build(env.0, env.1, db);\n\n        // Apply the state overrides.\n        if let Some(state_overrides) = state_overrides {\n            for (address, overrides) in state_overrides {\n                if let Some(balance) = overrides.balance {\n                    executor.set_balance(address, balance)?;\n                }\n                if let Some(nonce) = overrides.nonce {\n                    executor.set_nonce(address, nonce)?;\n                }\n                if let Some(code) = overrides.code {\n                    let bytecode = Bytecode::new_raw_checked(code)\n                        .wrap_err(\"invalid bytecode in state override\")?;\n                    executor.set_code(address, bytecode)?;\n                }\n                if let Some(state) = overrides.state {\n                    let state: HashMap<U256, U256> = state\n                        .into_iter()\n                        .map(|(slot, value)| (slot.into(), value.into()))\n                        .collect();\n                    executor.set_storage(address, state)?;\n                }\n                if let Some(state_diff) = overrides.state_diff {\n                    for (slot, value) in state_diff {\n                        executor.set_storage_slot(address, slot.into(), value.into())?;\n                    }\n                }\n            }\n        }\n\n        Ok(Self { executor })\n    }\n\n    /// Returns the spec id of the executor\n    pub fn spec_id(&self) -> SpecId {\n        self.executor.spec_id()\n    }\n\n    /// uses the fork block number from the config\n    pub async fn get_fork_material(\n        config: &mut Config,\n        mut evm_opts: EvmOpts,\n    ) -> eyre::Result<(EvmEnv, TxEnv, CreateFork, Chain, NetworkConfigs)> {\n        evm_opts.fork_url = Some(config.get_rpc_url_or_localhost_http()?.into_owned());\n        evm_opts.fork_block_number = config.fork_block_number;\n\n        let (evm_env, tx_env) = evm_opts.env().await?;\n\n        let fork = evm_opts.get_fork(config, evm_env.clone()).unwrap();\n        let networks = evm_opts.networks.with_chain_id(evm_env.cfg_env.chain_id);\n        config.labels.extend(networks.precompiles_label());\n\n        let chain = tx_env.chain_id.unwrap().into();\n        Ok((evm_env, tx_env, fork, chain, networks))\n    }\n}\n\nimpl Deref for TracingExecutor {\n    type Target = Executor;\n\n    fn deref(&self) -> &Self::Target {\n        &self.executor\n    }\n}\n\nimpl DerefMut for TracingExecutor {\n    fn deref_mut(&mut self) -> &mut Self::Target {\n        &mut self.executor\n    }\n}\n"
  },
  {
    "path": "crates/evm/evm/src/inspectors/chisel_state.rs",
    "content": "use alloy_primitives::U256;\nuse foundry_evm_core::backend::DatabaseError;\nuse revm::{\n    Database, Inspector,\n    context::ContextTr,\n    inspector::JournalExt,\n    interpreter::{Interpreter, interpreter::EthInterpreter, interpreter_types::Jumps},\n};\n\n/// An inspector for Chisel\n#[derive(Clone, Debug, Default)]\npub struct ChiselState {\n    /// The PC of the final instruction\n    pub final_pc: usize,\n    /// The final state of the REPL contract call\n    pub state: Option<(Vec<U256>, Vec<u8>)>,\n}\n\nimpl ChiselState {\n    /// Create a new Chisel state inspector.\n    #[inline]\n    pub fn new(final_pc: usize) -> Self {\n        Self { final_pc, state: None }\n    }\n}\n\nimpl<CTX, D> Inspector<CTX, EthInterpreter> for ChiselState\nwhere\n    D: Database<Error = DatabaseError>,\n    CTX: ContextTr<Db = D>,\n    CTX::Journal: JournalExt,\n{\n    #[cold]\n    fn step_end(&mut self, interpreter: &mut Interpreter, _context: &mut CTX) {\n        // If we are at the final pc of the REPL contract execution, set the state.\n        // Subtraction can't overflow because `pc` is always at least 1 in `step_end`.\n        if self.final_pc == interpreter.bytecode.pc() - 1 {\n            self.state = Some((\n                interpreter.stack.data().clone(),\n                interpreter.memory.context_memory().to_vec(),\n            ))\n        }\n    }\n}\n"
  },
  {
    "path": "crates/evm/evm/src/inspectors/custom_printer.rs",
    "content": "//! Custom print inspector, it has step level information of execution.\n//! It is a great tool if some debugging is needed.\n\nuse foundry_common::sh_println;\nuse foundry_evm_core::backend::DatabaseError;\nuse revm::{\n    Database, Inspector,\n    bytecode::opcode::OpCode,\n    context::{ContextTr, JournalTr},\n    inspector::{JournalExt, inspectors::GasInspector},\n    interpreter::{\n        CallInputs, CallOutcome, CreateInputs, CreateOutcome, Interpreter,\n        interpreter::EthInterpreter,\n        interpreter_types::{Jumps, MemoryTr},\n    },\n    primitives::{Address, U256},\n};\n\n/// Custom print [Inspector], it has step level information of execution.\n///\n/// It is a great tool if some debugging is needed.\n#[derive(Clone, Debug, Default)]\npub struct CustomPrintTracer {\n    gas_inspector: GasInspector,\n}\n\nimpl<CTX, D> Inspector<CTX, EthInterpreter> for CustomPrintTracer\nwhere\n    D: Database<Error = DatabaseError>,\n    CTX: ContextTr<Db = D>,\n    CTX::Journal: JournalExt,\n{\n    fn initialize_interp(&mut self, interp: &mut Interpreter, _context: &mut CTX) {\n        self.gas_inspector.initialize_interp(&interp.gas);\n    }\n\n    // get opcode by calling `interp.contract.opcode(interp.program_counter())`.\n    // all other information can be obtained from interp.\n    fn step(&mut self, interp: &mut Interpreter, context: &mut CTX) {\n        let opcode = interp.bytecode.opcode();\n        let name = OpCode::name_by_op(opcode);\n\n        let gas_remaining = self.gas_inspector.gas_remaining();\n\n        let memory_size = interp.memory.size();\n\n        let _ = sh_println!(\n            \"depth:{}, PC:{}, gas:{:#x}({}), OPCODE: {:?}({:?})  refund:{:#x}({}) Stack:{:?}, Data size:{}\",\n            context.journal().depth(),\n            interp.bytecode.pc(),\n            gas_remaining,\n            gas_remaining,\n            name,\n            opcode,\n            interp.gas.refunded(),\n            interp.gas.refunded(),\n            interp.stack.data(),\n            memory_size,\n        );\n\n        self.gas_inspector.step(&interp.gas);\n    }\n\n    fn step_end(&mut self, interpreter: &mut Interpreter, _context: &mut CTX) {\n        self.gas_inspector.step_end(&interpreter.gas);\n    }\n\n    fn call_end(&mut self, _context: &mut CTX, _inputs: &CallInputs, outcome: &mut CallOutcome) {\n        self.gas_inspector.call_end(outcome)\n    }\n\n    fn create_end(\n        &mut self,\n        _context: &mut CTX,\n        _inputs: &CreateInputs,\n        outcome: &mut CreateOutcome,\n    ) {\n        self.gas_inspector.create_end(outcome)\n    }\n\n    fn call(&mut self, _context: &mut CTX, inputs: &mut CallInputs) -> Option<CallOutcome> {\n        let _ = sh_println!(\n            \"SM Address: {:?}, caller:{:?},target:{:?} is_static:{:?}, transfer:{:?}, input_size:{:?}\",\n            inputs.bytecode_address,\n            inputs.caller,\n            inputs.target_address,\n            inputs.is_static,\n            inputs.value,\n            inputs.input.len(),\n        );\n        None\n    }\n\n    fn create(&mut self, _context: &mut CTX, inputs: &mut CreateInputs) -> Option<CreateOutcome> {\n        let _ = sh_println!(\n            \"CREATE CALL: caller:{:?}, scheme:{:?}, value:{:?}, init_code:{:?}, gas:{:?}\",\n            inputs.caller(),\n            inputs.scheme(),\n            inputs.value(),\n            inputs.init_code(),\n            inputs.gas_limit()\n        );\n        None\n    }\n\n    fn selfdestruct(&mut self, contract: Address, target: Address, value: U256) {\n        let _ = sh_println!(\n            \"SELFDESTRUCT: contract: {:?}, refund target: {:?}, value {:?}\",\n            contract,\n            target,\n            value\n        );\n    }\n}\n"
  },
  {
    "path": "crates/evm/evm/src/inspectors/logs.rs",
    "content": "use alloy_primitives::Log;\nuse alloy_sol_types::{SolEvent, SolInterface, SolValue};\nuse foundry_common::{ErrorExt, fmt::ConsoleFmt, sh_println};\nuse foundry_evm_core::{\n    FoundryInspectorExt, abi::console, constants::HARDHAT_CONSOLE_ADDRESS,\n    decode::decode_console_log,\n};\nuse revm::{\n    Inspector,\n    context::ContextTr,\n    interpreter::{\n        CallInputs, CallOutcome, Gas, InstructionResult, InterpreterResult,\n        interpreter::EthInterpreter,\n    },\n};\n\n/// An inspector that collects logs during execution.\n///\n/// The inspector collects logs from the `LOG` opcodes as well as Hardhat-style `console.sol` logs.\n#[derive(Clone, Debug)]\npub enum LogCollector {\n    /// The collected logs. Includes both `LOG` opcodes and Hardhat-style `console.sol` logs.\n    Capture { logs: Vec<Log> },\n    /// Print logs directly to stdout.\n    LiveLogs,\n}\n\nimpl LogCollector {\n    pub fn into_captured_logs(self) -> Option<Vec<Log>> {\n        match self {\n            Self::Capture { logs } => Some(logs),\n            Self::LiveLogs => None,\n        }\n    }\n\n    #[cold]\n    fn do_hardhat_log<CTX>(&mut self, context: &mut CTX, inputs: &CallInputs) -> Option<CallOutcome>\n    where\n        CTX: ContextTr,\n    {\n        if let Err(err) = self.hardhat_log(&inputs.input.bytes(context)) {\n            let result = InstructionResult::Revert;\n            let output = err.abi_encode_revert();\n            return Some(CallOutcome {\n                result: InterpreterResult { result, output, gas: Gas::new(inputs.gas_limit) },\n                memory_offset: inputs.return_memory_offset.clone(),\n                was_precompile_called: true,\n                precompile_call_logs: vec![],\n            });\n        }\n        None\n    }\n\n    fn hardhat_log(&mut self, data: &[u8]) -> alloy_sol_types::Result<()> {\n        let decoded = console::hh::ConsoleCalls::abi_decode(data)?;\n        self.push_msg(&decoded.fmt(Default::default()));\n        Ok(())\n    }\n\n    fn push_raw_log(&mut self, log: Log) {\n        match self {\n            Self::Capture { logs } => logs.push(log),\n            Self::LiveLogs => {\n                if let Some(msg) = decode_console_log(&log) {\n                    sh_println!(\"{msg}\").expect(\"fail printing to stdout\");\n                } else {\n                    // This case should not happen if the users call through forge-std.\n                    // We print the log data for the user nonetheless.\n                    sh_println!(\"console.log({:?}, {})\", log.data.topics(), log.data.data)\n                        .expect(\"fail printing to stdout\");\n                }\n            }\n        }\n    }\n\n    fn push_msg(&mut self, msg: &str) {\n        match self {\n            Self::Capture { logs } => logs.push(new_console_log(msg)),\n            Self::LiveLogs => sh_println!(\"{msg}\").expect(\"fail printing to stdout\"),\n        }\n    }\n}\n\nimpl<CTX> Inspector<CTX, EthInterpreter> for LogCollector\nwhere\n    CTX: ContextTr,\n{\n    fn log(&mut self, _context: &mut CTX, log: Log) {\n        self.push_raw_log(log);\n    }\n\n    fn call(&mut self, context: &mut CTX, inputs: &mut CallInputs) -> Option<CallOutcome> {\n        if inputs.target_address == HARDHAT_CONSOLE_ADDRESS {\n            return self.do_hardhat_log(context, inputs);\n        }\n        None\n    }\n}\n\nimpl FoundryInspectorExt for LogCollector {\n    fn console_log(&mut self, msg: &str) {\n        self.push_msg(msg);\n    }\n}\n\n/// Creates a `console.log(string)` event.\nfn new_console_log(msg: &str) -> Log {\n    Log::new_unchecked(\n        HARDHAT_CONSOLE_ADDRESS,\n        vec![console::ds::log::SIGNATURE_HASH],\n        msg.abi_encode().into(),\n    )\n}\n"
  },
  {
    "path": "crates/evm/evm/src/inspectors/mod.rs",
    "content": "//! EVM inspectors.\n\npub use foundry_cheatcodes::{self as cheatcodes, Cheatcodes, CheatsConfig};\npub use foundry_evm_coverage::LineCoverageCollector;\npub use foundry_evm_fuzz::Fuzzer;\npub use foundry_evm_traces::{StackSnapshotType, TracingInspector, TracingInspectorConfig};\n\npub use revm_inspectors::access_list::AccessListInspector;\n\nmod custom_printer;\npub use custom_printer::CustomPrintTracer;\n\nmod chisel_state;\npub use chisel_state::ChiselState;\n\nmod logs;\npub use logs::LogCollector;\n\nmod script;\npub use script::ScriptExecutionInspector;\n\nmod stack;\npub use stack::{InspectorData, InspectorStack, InspectorStackBuilder};\n\nmod revert_diagnostic;\npub use revert_diagnostic::RevertDiagnostic;\n"
  },
  {
    "path": "crates/evm/evm/src/inspectors/revert_diagnostic.rs",
    "content": "use alloy_primitives::{Address, U256};\nuse alloy_sol_types::SolValue;\nuse foundry_evm_core::{\n    backend::DatabaseError,\n    constants::{CHEATCODE_ADDRESS, HARDHAT_CONSOLE_ADDRESS},\n};\nuse revm::{\n    Database, Inspector,\n    bytecode::opcode,\n    context::{ContextTr, JournalTr},\n    inspector::JournalExt,\n    interpreter::{\n        CallInputs, CallOutcome, CallScheme, InstructionResult, Interpreter, InterpreterAction,\n        interpreter::EthInterpreter,\n        interpreter_types::{Jumps, LoopControl},\n    },\n};\nuse std::fmt;\n\nconst IGNORE: [Address; 2] = [HARDHAT_CONSOLE_ADDRESS, CHEATCODE_ADDRESS];\n\n/// Checks if the call scheme corresponds to any sort of delegate call\npub fn is_delegatecall(scheme: CallScheme) -> bool {\n    matches!(scheme, CallScheme::DelegateCall | CallScheme::CallCode)\n}\n\n#[derive(Debug, Clone, Copy)]\npub enum DetailedRevertReason {\n    CallToNonContract(Address),\n    DelegateCallToNonContract(Address),\n}\n\nimpl fmt::Display for DetailedRevertReason {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        match self {\n            Self::CallToNonContract(addr) => {\n                write!(f, \"call to non-contract address {addr}\")\n            }\n            Self::DelegateCallToNonContract(addr) => write!(\n                f,\n                \"delegatecall to non-contract address {addr} (usually an unliked library)\"\n            ),\n        }\n    }\n}\n\n/// An inspector that tracks call context to enhances revert diagnostics.\n/// Useful for understanding reverts that are not linked to custom errors or revert strings.\n///\n/// Supported diagnostics:\n///  1. **Non-void call to non-contract address:** the soldity compiler adds some validation to the\n///     return data of the call, so despite the call succeeds, as doesn't return data, the\n///     validation causes a revert.\n///\n///     Identified when: a call with non-empty calldata is made to an address without bytecode,\n///     followed by an empty revert at the same depth.\n///\n///  2. **Void call to non-contract address:** in this case the solidity compiler adds some checks\n///     before doing the call, so it never takes place.\n///\n///     Identified when: extcodesize for the target address returns 0 + empty revert at the same\n///     depth.\n#[derive(Clone, Debug, Default)]\npub struct RevertDiagnostic {\n    /// Tracks calls with calldata that target an address without executable code.\n    non_contract_call: Option<(Address, CallScheme, usize)>,\n    /// Tracks EXTCODESIZE checks that target an address without executable code.\n    non_contract_size_check: Option<(Address, usize)>,\n    /// Whether the step opcode is EXTCODESIZE or not.\n    is_extcodesize_step: bool,\n}\n\nimpl RevertDiagnostic {\n    /// Returns the effective target address whose code would be executed.\n    /// For delegate calls, this is the `bytecode_address`. Otherwise, it's the `target_address`.\n    fn code_target_address(&self, inputs: &mut CallInputs) -> Address {\n        if is_delegatecall(inputs.scheme) { inputs.bytecode_address } else { inputs.target_address }\n    }\n\n    /// Derives the revert reason based on the cached data. Should only be called after a revert.\n    fn reason(&self) -> Option<DetailedRevertReason> {\n        if let Some((addr, scheme, _)) = self.non_contract_call {\n            let reason = if is_delegatecall(scheme) {\n                DetailedRevertReason::DelegateCallToNonContract(addr)\n            } else {\n                DetailedRevertReason::CallToNonContract(addr)\n            };\n\n            return Some(reason);\n        }\n\n        if let Some((addr, _)) = self.non_contract_size_check {\n            // unknown schema as the call never took place --> output most generic reason\n            return Some(DetailedRevertReason::CallToNonContract(addr));\n        }\n\n        None\n    }\n\n    /// Injects the revert diagnostic into the debug traces. Should only be called after a revert.\n    fn broadcast_diagnostic(&self, interpreter: &mut Interpreter) {\n        if let Some(reason) = self.reason() {\n            interpreter.bytecode.set_action(InterpreterAction::new_return(\n                InstructionResult::Revert,\n                reason.to_string().abi_encode().into(),\n                interpreter.gas,\n            ));\n        }\n    }\n\n    /// When a `REVERT` opcode with zero data size occurs:\n    ///  - if `non_contract_call` was set at the current depth, `broadcast_diagnostic` is called.\n    ///    Otherwise, it is cleared.\n    ///  - if `non_contract_size_check` was set at the current depth, `broadcast_diagnostic` is\n    ///    called. Otherwise, it is cleared.\n    #[cold]\n    fn handle_revert<CTX, D>(&mut self, interp: &mut Interpreter, ctx: &mut CTX)\n    where\n        D: Database<Error = DatabaseError>,\n        CTX: ContextTr<Db = D>,\n        CTX::Journal: JournalExt,\n    {\n        // REVERT (offset, size)\n        if let Ok(size) = interp.stack.peek(1)\n            && size.is_zero()\n        {\n            // Check empty revert with same depth as a non-contract call\n            if let Some((_, _, depth)) = self.non_contract_call {\n                if ctx.journal_ref().depth() == depth {\n                    self.broadcast_diagnostic(interp);\n                } else {\n                    self.non_contract_call = None;\n                }\n                return;\n            }\n\n            // Check empty revert with same depth as a non-contract size check\n            if let Some((_, depth)) = self.non_contract_size_check {\n                if depth == ctx.journal_ref().depth() {\n                    self.broadcast_diagnostic(interp);\n                } else {\n                    self.non_contract_size_check = None;\n                }\n            }\n        }\n    }\n\n    /// When an `EXTCODESIZE` opcode occurs:\n    ///  - Optimistically caches the target address and current depth in `non_contract_size_check`,\n    ///    pending later validation.\n    #[cold]\n    fn handle_extcodesize<CTX, D>(&mut self, interp: &mut Interpreter, ctx: &mut CTX)\n    where\n        D: Database<Error = DatabaseError>,\n        CTX: ContextTr<Db = D>,\n        CTX::Journal: JournalExt,\n    {\n        // EXTCODESIZE (address)\n        if let Ok(word) = interp.stack.peek(0) {\n            let addr = Address::from_word(word.into());\n            if IGNORE.contains(&addr) || ctx.journal_ref().precompile_addresses().contains(&addr) {\n                return;\n            }\n\n            // Optimistically cache --> validated and cleared (if necessary) at `fn\n            // step_end()`\n            self.non_contract_size_check = Some((addr, ctx.journal_ref().depth()));\n            self.is_extcodesize_step = true;\n        }\n    }\n\n    /// Tracks `EXTCODESIZE` output. If the bytecode size is NOT 0, clears the cache.\n    #[cold]\n    fn handle_extcodesize_output(&mut self, interp: &mut Interpreter) {\n        if let Ok(size) = interp.stack.peek(0)\n            && size != U256::ZERO\n        {\n            self.non_contract_size_check = None;\n        }\n\n        self.is_extcodesize_step = false;\n    }\n}\n\nimpl<CTX, D> Inspector<CTX, EthInterpreter> for RevertDiagnostic\nwhere\n    D: Database<Error = DatabaseError>,\n    CTX: ContextTr<Db = D>,\n    CTX::Journal: JournalExt,\n{\n    /// Tracks the first call with non-zero calldata that targets a non-contract address. Excludes\n    /// precompiles and test addresses.\n    fn call(&mut self, ctx: &mut CTX, inputs: &mut CallInputs) -> Option<CallOutcome> {\n        let target = self.code_target_address(inputs);\n\n        if IGNORE.contains(&target) || ctx.journal_ref().precompile_addresses().contains(&target) {\n            return None;\n        }\n\n        if let Ok(state) = ctx.journal_mut().code(target)\n            && state.is_empty()\n            && !inputs.input.is_empty()\n        {\n            self.non_contract_call = Some((target, inputs.scheme, ctx.journal_ref().depth()));\n        }\n        None\n    }\n\n    /// Handles `REVERT` and `EXTCODESIZE` opcodes for diagnostics.\n    fn step(&mut self, interp: &mut Interpreter, ctx: &mut CTX) {\n        match interp.bytecode.opcode() {\n            opcode::REVERT => self.handle_revert(interp, ctx),\n            opcode::EXTCODESIZE => self.handle_extcodesize(interp, ctx),\n            _ => {}\n        }\n    }\n\n    fn step_end(&mut self, interp: &mut Interpreter, _ctx: &mut CTX) {\n        if self.is_extcodesize_step {\n            self.handle_extcodesize_output(interp);\n        }\n    }\n}\n"
  },
  {
    "path": "crates/evm/evm/src/inspectors/script.rs",
    "content": "use alloy_evm::Database;\nuse alloy_primitives::{Address, Bytes};\nuse foundry_evm_core::backend::DatabaseError;\nuse revm::{\n    Inspector,\n    bytecode::opcode::ADDRESS,\n    context::ContextTr,\n    inspector::JournalExt,\n    interpreter::{\n        InstructionResult, Interpreter, InterpreterAction,\n        interpreter::EthInterpreter,\n        interpreter_types::{Jumps, LoopControl},\n    },\n};\n\n/// An inspector that enforces certain rules during script execution.\n///\n/// Currently, it only warns if the `ADDRESS` opcode is used within the script's main contract.\n#[derive(Clone, Debug, Default)]\npub struct ScriptExecutionInspector {\n    /// The address of the script contract being executed.\n    pub script_address: Address,\n}\n\nimpl<CTX, D> Inspector<CTX, EthInterpreter> for ScriptExecutionInspector\nwhere\n    D: Database<Error = DatabaseError>,\n    CTX: ContextTr<Db = D>,\n    CTX::Journal: JournalExt,\n{\n    fn step(&mut self, interpreter: &mut Interpreter, _ecx: &mut CTX) {\n        // Check if both target and bytecode address are the same as script contract address\n        // (allow calling external libraries when bytecode address is different).\n        if interpreter.bytecode.opcode() == ADDRESS\n            && interpreter.input.target_address == self.script_address\n            && interpreter.input.bytecode_address == Some(self.script_address)\n        {\n            interpreter.bytecode.set_action(InterpreterAction::new_return(\n                InstructionResult::Revert,\n                Bytes::from(\"Usage of `address(this)` detected in script contract. Script contracts are ephemeral and their addresses should not be relied upon.\"),\n                interpreter.gas,\n            ));\n        }\n    }\n}\n"
  },
  {
    "path": "crates/evm/evm/src/inspectors/stack.rs",
    "content": "use super::{\n    Cheatcodes, CheatsConfig, ChiselState, CustomPrintTracer, Fuzzer, LineCoverageCollector,\n    LogCollector, RevertDiagnostic, ScriptExecutionInspector, TracingInspector,\n};\nuse alloy_evm::EvmEnv;\nuse alloy_primitives::{\n    Address, B256, Bytes, Log, TxKind, U256,\n    map::{AddressHashMap, HashMap},\n};\nuse foundry_cheatcodes::{\n    CheatcodeAnalysis, CheatcodesExecutor, EthCheatCtx, NestedEvmClosure, Wallets,\n};\nuse foundry_common::compile::Analysis;\nuse foundry_compilers::ProjectPathsConfig;\nuse foundry_evm_core::{\n    FoundryBlock, FoundryInspectorExt, FoundryTransaction,\n    backend::{DatabaseError, DatabaseExt, JournaledState},\n    env::FoundryContextExt,\n    evm::{NestedEvm, new_eth_evm_with_inspector, with_cloned_context},\n};\nuse foundry_evm_coverage::HitMaps;\nuse foundry_evm_networks::NetworkConfigs;\nuse foundry_evm_traces::{SparsedTraceArena, TraceMode};\nuse revm::{\n    Inspector,\n    context::{\n        Block, BlockEnv, Cfg, ContextTr, JournalTr, Transaction, TxEnv,\n        result::{EVMError, ExecutionResult, Output},\n    },\n    context_interface::CreateScheme,\n    inspector::JournalExt,\n    interpreter::{\n        CallInputs, CallOutcome, CallScheme, CreateInputs, CreateOutcome, Gas, InstructionResult,\n        Interpreter, InterpreterResult,\n    },\n    state::{Account, AccountStatus},\n};\nuse revm_inspectors::edge_cov::EdgeCovInspector;\nuse std::{\n    ops::{Deref, DerefMut},\n    sync::Arc,\n};\n\n#[derive(Clone, Debug, Default)]\n#[must_use = \"builders do nothing unless you call `build` on them\"]\npub struct InspectorStackBuilder {\n    /// Solar compiler instance, to grant syntactic and semantic analysis capabilities.\n    pub analysis: Option<Analysis>,\n    /// The block environment.\n    ///\n    /// Used in the cheatcode handler to overwrite the block environment separately from the\n    /// execution block environment.\n    pub block: Option<BlockEnv>,\n    /// The gas price.\n    ///\n    /// Used in the cheatcode handler to overwrite the gas price separately from the gas price\n    /// in the execution environment.\n    pub gas_price: Option<u128>,\n    /// The cheatcodes config.\n    pub cheatcodes: Option<Arc<CheatsConfig>>,\n    /// The fuzzer inspector and its state, if it exists.\n    pub fuzzer: Option<Fuzzer>,\n    /// Whether to enable tracing and revert diagnostics.\n    pub trace_mode: TraceMode,\n    /// Whether logs should be collected.\n    /// - None for no log collection.\n    /// - Some(true) for realtime console.log-ing.\n    /// - Some(false) for log collection.\n    pub logs: Option<bool>,\n    /// Whether line coverage info should be collected.\n    pub line_coverage: Option<bool>,\n    /// Whether to print all opcode traces into the console. Useful for debugging the EVM.\n    pub print: Option<bool>,\n    /// The chisel state inspector.\n    pub chisel_state: Option<usize>,\n    /// Whether to enable call isolation.\n    /// In isolation mode all top-level calls are executed as a separate transaction in a separate\n    /// EVM context, enabling more precise gas accounting and transaction state changes.\n    pub enable_isolation: bool,\n    /// Networks with enabled features.\n    pub networks: NetworkConfigs,\n    /// The wallets to set in the cheatcodes context.\n    pub wallets: Option<Wallets>,\n    /// The CREATE2 deployer address.\n    pub create2_deployer: Address,\n}\n\nimpl InspectorStackBuilder {\n    /// Create a new inspector stack builder.\n    #[inline]\n    pub fn new() -> Self {\n        Self::default()\n    }\n\n    /// Set the solar compiler instance that grants syntactic and semantic analysis capabilities\n    #[inline]\n    pub fn set_analysis(mut self, analysis: Analysis) -> Self {\n        self.analysis = Some(analysis);\n        self\n    }\n\n    /// Set the block environment.\n    #[inline]\n    pub fn block(mut self, block: BlockEnv) -> Self {\n        self.block = Some(block);\n        self\n    }\n\n    /// Set the gas price.\n    #[inline]\n    pub fn gas_price(mut self, gas_price: u128) -> Self {\n        self.gas_price = Some(gas_price);\n        self\n    }\n\n    /// Enable cheatcodes with the given config.\n    #[inline]\n    pub fn cheatcodes(mut self, config: Arc<CheatsConfig>) -> Self {\n        self.cheatcodes = Some(config);\n        self\n    }\n\n    /// Set the wallets.\n    #[inline]\n    pub fn wallets(mut self, wallets: Wallets) -> Self {\n        self.wallets = Some(wallets);\n        self\n    }\n\n    /// Set the fuzzer inspector.\n    #[inline]\n    pub fn fuzzer(mut self, fuzzer: Fuzzer) -> Self {\n        self.fuzzer = Some(fuzzer);\n        self\n    }\n\n    /// Set the Chisel inspector.\n    #[inline]\n    pub fn chisel_state(mut self, final_pc: usize) -> Self {\n        self.chisel_state = Some(final_pc);\n        self\n    }\n\n    /// Set the log collector, and whether to print the logs directly to stdout.\n    #[inline]\n    pub fn logs(mut self, live_logs: bool) -> Self {\n        self.logs = Some(live_logs);\n        self\n    }\n\n    /// Set whether to collect line coverage information.\n    #[inline]\n    pub fn line_coverage(mut self, yes: bool) -> Self {\n        self.line_coverage = Some(yes);\n        self\n    }\n\n    /// Set whether to enable the trace printer.\n    #[inline]\n    pub fn print(mut self, yes: bool) -> Self {\n        self.print = Some(yes);\n        self\n    }\n\n    /// Set whether to enable the tracer.\n    /// Revert diagnostic inspector is activated when `mode != TraceMode::None`\n    #[inline]\n    pub fn trace_mode(mut self, mode: TraceMode) -> Self {\n        if self.trace_mode < mode {\n            self.trace_mode = mode\n        }\n        self\n    }\n\n    /// Set whether to enable the call isolation.\n    /// For description of call isolation, see [`InspectorStack::enable_isolation`].\n    #[inline]\n    pub fn enable_isolation(mut self, yes: bool) -> Self {\n        self.enable_isolation = yes;\n        self\n    }\n\n    /// Set networks with enabled features.\n    #[inline]\n    pub fn networks(mut self, networks: NetworkConfigs) -> Self {\n        self.networks = networks;\n        self\n    }\n\n    #[inline]\n    pub fn create2_deployer(mut self, create2_deployer: Address) -> Self {\n        self.create2_deployer = create2_deployer;\n        self\n    }\n\n    /// Builds the stack of inspectors to use when transacting/committing on the EVM.\n    pub fn build(self) -> InspectorStack {\n        let Self {\n            analysis,\n            block,\n            gas_price,\n            cheatcodes,\n            fuzzer,\n            trace_mode,\n            logs,\n            line_coverage,\n            print,\n            chisel_state,\n            enable_isolation,\n            networks,\n            wallets,\n            create2_deployer,\n        } = self;\n        let mut stack = InspectorStack::new();\n\n        // inspectors\n        if let Some(config) = cheatcodes {\n            let mut cheatcodes = Cheatcodes::new(config);\n            // Set analysis capabilities if they are provided\n            if let Some(analysis) = analysis {\n                stack.set_analysis(analysis.clone());\n                cheatcodes.set_analysis(CheatcodeAnalysis::new(analysis));\n            }\n            // Set wallets if they are provided\n            if let Some(wallets) = wallets {\n                cheatcodes.set_wallets(wallets);\n            }\n            stack.set_cheatcodes(cheatcodes);\n        }\n\n        if let Some(fuzzer) = fuzzer {\n            stack.set_fuzzer(fuzzer);\n        }\n        if let Some(chisel_state) = chisel_state {\n            stack.set_chisel(chisel_state);\n        }\n        stack.collect_line_coverage(line_coverage.unwrap_or(false));\n        stack.collect_logs(logs);\n        stack.print(print.unwrap_or(false));\n        stack.tracing(trace_mode);\n\n        stack.enable_isolation(enable_isolation);\n        stack.networks(networks);\n        stack.set_create2_deployer(create2_deployer);\n\n        // environment, must come after all of the inspectors\n        if let Some(block) = block {\n            stack.set_block(&block);\n        }\n        if let Some(gas_price) = gas_price {\n            stack.set_gas_price(gas_price);\n        }\n\n        stack\n    }\n}\n\n/// Helper macro to call the same method on multiple inspectors without resorting to dynamic\n/// dispatch.\n#[macro_export]\nmacro_rules! call_inspectors {\n    ([$($inspector:expr),+ $(,)?], |$id:ident $(,)?| $body:expr $(,)?) => {\n        $(\n            if let Some($id) = $inspector {\n                $crate::utils::cold_path();\n                $body;\n            }\n        )+\n    };\n    (#[ret] [$($inspector:expr),+ $(,)?], |$id:ident $(,)?| $body:expr $(,)?) => {{\n        $(\n            if let Some($id) = $inspector {\n                $crate::utils::cold_path();\n                if let Some(result) = $body {\n                    return result;\n                }\n            }\n        )+\n    }};\n}\n\n/// The collected results of [`InspectorStack`].\npub struct InspectorData {\n    pub logs: Vec<Log>,\n    pub labels: AddressHashMap<String>,\n    pub traces: Option<SparsedTraceArena>,\n    pub line_coverage: Option<HitMaps>,\n    pub edge_coverage: Option<Vec<u8>>,\n    pub cheatcodes: Option<Box<Cheatcodes>>,\n    pub chisel_state: Option<(Vec<U256>, Vec<u8>)>,\n    pub reverter: Option<Address>,\n}\n\n/// Contains data about the state of outer/main EVM which created and invoked the inner EVM context.\n/// Used to adjust EVM state while in inner context.\n///\n/// We need this to avoid breaking changes due to EVM behavior differences in isolated vs\n/// non-isolated mode. For descriptions and workarounds for those changes see: <https://github.com/foundry-rs/foundry/pull/7186#issuecomment-1959102195>\n#[derive(Debug, Clone)]\npub struct InnerContextData {\n    /// Origin of the transaction in the outer EVM context.\n    original_origin: Address,\n}\n\n/// An inspector that calls multiple inspectors in sequence.\n///\n/// If a call to an inspector returns a value (indicating a stop or revert) the remaining inspectors\n/// are not called.\n///\n/// Stack is divided into [Cheatcodes] and `InspectorStackInner`. This is done to allow assembling\n/// `InspectorStackRefMut` inside [Cheatcodes] to allow usage of it as [revm::Inspector]. This gives\n/// us ability to create and execute separate EVM frames from inside cheatcodes while still having\n/// access to entire stack of inspectors and correctly handling traces, logs, debugging info\n/// collection, etc.\n#[derive(Clone, Debug, Default)]\npub struct InspectorStack {\n    pub cheatcodes: Option<Box<Cheatcodes>>,\n    pub inner: InspectorStackInner,\n}\n\nimpl InspectorStack {\n    pub fn paths_config(&self) -> Option<&ProjectPathsConfig> {\n        self.cheatcodes.as_ref().map(|c| &c.config.paths)\n    }\n}\n\n/// All used inpectors besides [Cheatcodes].\n///\n/// See [`InspectorStack`].\n#[derive(Default, Clone, Debug)]\npub struct InspectorStackInner {\n    /// Solar compiler instance, to grant syntactic and semantic analysis capabilities.\n    pub analysis: Option<Analysis>,\n\n    // Inspectors.\n    // These are boxed to reduce the size of the struct and slightly improve performance of the\n    // `if let Some` checks.\n    pub chisel_state: Option<Box<ChiselState>>,\n    pub edge_coverage: Option<Box<EdgeCovInspector>>,\n    pub fuzzer: Option<Box<Fuzzer>>,\n    pub line_coverage: Option<Box<LineCoverageCollector>>,\n    pub log_collector: Option<Box<LogCollector>>,\n    pub printer: Option<Box<CustomPrintTracer>>,\n    pub revert_diag: Option<Box<RevertDiagnostic>>,\n    pub script_execution_inspector: Option<Box<ScriptExecutionInspector>>,\n    pub tracer: Option<Box<TracingInspector>>,\n\n    // EthInspectorExt and other internal data.\n    pub enable_isolation: bool,\n    pub networks: NetworkConfigs,\n    pub create2_deployer: Address,\n    /// Flag marking if we are in the inner EVM context.\n    pub in_inner_context: bool,\n    pub inner_context_data: Option<InnerContextData>,\n    pub top_frame_journal: HashMap<Address, Account>,\n    /// Address that reverted the call, if any.\n    pub reverter: Option<Address>,\n}\n\n/// Struct keeping mutable references to both parts of [InspectorStack] and implementing\n/// [revm::Inspector]. This struct can be obtained via [InspectorStack::as_mut].\npub struct InspectorStackRefMut<'a> {\n    pub cheatcodes: Option<&'a mut Cheatcodes>,\n    pub inner: &'a mut InspectorStackInner,\n}\n\nimpl<CTX: EthCheatCtx> CheatcodesExecutor<CTX> for InspectorStackInner {\n    fn with_nested_evm(\n        &mut self,\n        cheats: &mut Cheatcodes,\n        ecx: &mut CTX,\n        f: NestedEvmClosure<'_, CTX::Block, CTX::Tx, <CTX::Cfg as Cfg>::Spec>,\n    ) -> Result<(), EVMError<DatabaseError>> {\n        let mut inspector = InspectorStackRefMut { cheatcodes: Some(cheats), inner: self };\n        with_cloned_context(ecx, |db, evm_env, tx_env, journal_inner| {\n            let mut evm = new_eth_evm_with_inspector(db, evm_env, tx_env, &mut inspector);\n            *evm.journal_inner_mut() = journal_inner;\n            f(&mut evm)?;\n            let sub_evm_env = evm.to_evm_env();\n            let sub_inner = evm.journaled_state.inner.clone();\n            Ok((sub_evm_env, sub_inner))\n        })\n    }\n\n    fn with_fresh_nested_evm(\n        &mut self,\n        cheats: &mut Cheatcodes,\n        db: &mut dyn DatabaseExt<CTX::Block, CTX::Tx, <CTX::Cfg as Cfg>::Spec>,\n        evm_env: EvmEnv<<CTX::Cfg as Cfg>::Spec, CTX::Block>,\n        tx_env: CTX::Tx,\n        f: NestedEvmClosure<'_, CTX::Block, CTX::Tx, <CTX::Cfg as Cfg>::Spec>,\n    ) -> Result<(), EVMError<DatabaseError>> {\n        let mut inspector = InspectorStackRefMut { cheatcodes: Some(cheats), inner: self };\n        let mut evm = new_eth_evm_with_inspector(db, evm_env, tx_env, &mut inspector);\n        f(&mut evm)\n    }\n\n    fn transact_on_db(\n        &mut self,\n        cheats: &mut Cheatcodes,\n        ecx: &mut CTX,\n        fork_id: Option<U256>,\n        transaction: B256,\n    ) -> eyre::Result<()> {\n        let evm_env = ecx.evm_clone();\n        let tx_env = ecx.tx_clone();\n        let mut inspector = InspectorStackRefMut { cheatcodes: Some(cheats), inner: self };\n        let (db, inner) = ecx.db_journal_inner_mut();\n        db.transact(fork_id, transaction, evm_env, tx_env, inner, &mut inspector)\n    }\n\n    fn transact_from_tx_on_db(\n        &mut self,\n        cheats: &mut Cheatcodes,\n        ecx: &mut CTX,\n        tx_env: &CTX::Tx,\n    ) -> eyre::Result<()> {\n        let evm_env = ecx.evm_clone();\n        let mut inspector = InspectorStackRefMut { cheatcodes: Some(cheats), inner: self };\n        let (db, inner) = ecx.db_journal_inner_mut();\n        db.transact_from_tx(tx_env, evm_env, inner, &mut inspector)\n    }\n\n    fn console_log(&mut self, _cheats: &mut Cheatcodes, msg: &str) {\n        if let Some(ref mut collector) = self.log_collector {\n            FoundryInspectorExt::console_log(&mut **collector, msg);\n        }\n    }\n\n    fn tracing_inspector(&mut self) -> Option<&mut TracingInspector> {\n        self.tracer.as_deref_mut()\n    }\n\n    fn set_in_inner_context(&mut self, enabled: bool, original_origin: Option<Address>) {\n        self.in_inner_context = enabled;\n        self.inner_context_data = if enabled {\n            Some(InnerContextData {\n                original_origin: original_origin.expect(\"origin required when enabling inner ctx\"),\n            })\n        } else {\n            None\n        };\n    }\n}\n\nimpl InspectorStack {\n    /// Creates a new inspector stack.\n    ///\n    /// Note that the stack is empty by default, and you must add inspectors to it.\n    /// This is done by calling the `set_*` methods on the stack directly, or by building the stack\n    /// with [`InspectorStack`].\n    #[inline]\n    pub fn new() -> Self {\n        Self::default()\n    }\n\n    /// Logs the status of the inspectors.\n    pub fn log_status(&self) {\n        trace!(enabled=%{\n            let mut enabled = Vec::with_capacity(16);\n            macro_rules! push {\n                ($($id:ident),* $(,)?) => {\n                    $(\n                        if self.$id.is_some() {\n                            enabled.push(stringify!($id));\n                        }\n                    )*\n                };\n            }\n            push!(cheatcodes, chisel_state, line_coverage, fuzzer, log_collector, printer, tracer);\n            if self.enable_isolation {\n                enabled.push(\"isolation\");\n            }\n            format!(\"[{}]\", enabled.join(\", \"))\n        });\n    }\n\n    /// Set the solar compiler instance.\n    #[inline]\n    pub fn set_analysis(&mut self, analysis: Analysis) {\n        self.analysis = Some(analysis);\n    }\n\n    /// Set variables from an environment for the relevant inspectors.\n    #[inline]\n    pub fn set_env(&mut self, evm_env: &EvmEnv, tx_env: &TxEnv) {\n        self.set_block(&evm_env.block_env);\n        self.set_gas_price(tx_env.gas_price);\n    }\n\n    /// Sets the block for the relevant inspectors.\n    #[inline]\n    pub fn set_block(&mut self, block: &BlockEnv) {\n        if let Some(cheatcodes) = &mut self.cheatcodes {\n            cheatcodes.block = Some(block.clone());\n        }\n    }\n\n    /// Sets the gas price for the relevant inspectors.\n    #[inline]\n    pub fn set_gas_price(&mut self, gas_price: u128) {\n        if let Some(cheatcodes) = &mut self.cheatcodes {\n            cheatcodes.gas_price = Some(gas_price);\n        }\n    }\n\n    /// Set the cheatcodes inspector.\n    #[inline]\n    pub fn set_cheatcodes(&mut self, cheatcodes: Cheatcodes) {\n        self.cheatcodes = Some(cheatcodes.into());\n    }\n\n    /// Set the fuzzer inspector.\n    #[inline]\n    pub fn set_fuzzer(&mut self, fuzzer: Fuzzer) {\n        self.fuzzer = Some(fuzzer.into());\n    }\n\n    /// Set the Chisel inspector.\n    #[inline]\n    pub fn set_chisel(&mut self, final_pc: usize) {\n        self.chisel_state = Some(ChiselState::new(final_pc).into());\n    }\n\n    /// Set whether to enable the line coverage collector.\n    #[inline]\n    pub fn collect_line_coverage(&mut self, yes: bool) {\n        self.line_coverage = yes.then(Default::default);\n    }\n\n    /// Set whether to enable the edge coverage collector.\n    #[inline]\n    pub fn collect_edge_coverage(&mut self, yes: bool) {\n        // TODO: configurable edge size?\n        self.edge_coverage = yes.then(EdgeCovInspector::new).map(Into::into);\n    }\n\n    /// Set whether to enable call isolation.\n    #[inline]\n    pub fn enable_isolation(&mut self, yes: bool) {\n        self.enable_isolation = yes;\n    }\n\n    /// Set networks with enabled features.\n    #[inline]\n    pub fn networks(&mut self, networks: NetworkConfigs) {\n        self.networks = networks;\n    }\n\n    /// Set the CREATE2 deployer address.\n    #[inline]\n    pub fn set_create2_deployer(&mut self, deployer: Address) {\n        self.create2_deployer = deployer;\n    }\n\n    /// Set whether to enable the log collector.\n    /// - None for no log collection.\n    /// - Some(true) for realtime console.log-ing.\n    /// - Some(false) for log collection.\n    #[inline]\n    pub fn collect_logs(&mut self, live_logs: Option<bool>) {\n        self.log_collector = live_logs.map(|live_logs| {\n            Box::new(if live_logs {\n                LogCollector::LiveLogs\n            } else {\n                LogCollector::Capture { logs: Vec::new() }\n            })\n        });\n    }\n\n    /// Set whether to enable the trace printer.\n    #[inline]\n    pub fn print(&mut self, yes: bool) {\n        self.printer = yes.then(Default::default);\n    }\n\n    /// Set whether to enable the tracer.\n    /// Revert diagnostic inspector is activated when `mode != TraceMode::None`\n    #[inline]\n    pub fn tracing(&mut self, mode: TraceMode) {\n        self.revert_diag = (!mode.is_none()).then(RevertDiagnostic::default).map(Into::into);\n\n        if let Some(config) = mode.into_config() {\n            *self.tracer.get_or_insert_with(Default::default).config_mut() = config;\n        } else {\n            self.tracer = None;\n        }\n    }\n\n    /// Set whether to enable script execution inspector.\n    #[inline]\n    pub fn script(&mut self, script_address: Address) {\n        self.script_execution_inspector.get_or_insert_with(Default::default).script_address =\n            script_address;\n    }\n\n    #[inline(always)]\n    fn as_mut(&mut self) -> InspectorStackRefMut<'_> {\n        InspectorStackRefMut { cheatcodes: self.cheatcodes.as_deref_mut(), inner: &mut self.inner }\n    }\n\n    /// Collects all the data gathered during inspection into a single struct.\n    pub fn collect(self) -> InspectorData {\n        let Self {\n            mut cheatcodes,\n            inner:\n                InspectorStackInner {\n                    chisel_state,\n                    line_coverage,\n                    edge_coverage,\n                    log_collector,\n                    tracer,\n                    reverter,\n                    ..\n                },\n        } = self;\n\n        let traces = tracer.map(|tracer| tracer.into_traces()).map(|arena| {\n            let ignored = cheatcodes\n                .as_mut()\n                .map(|cheatcodes| {\n                    let mut ignored = std::mem::take(&mut cheatcodes.ignored_traces.ignored);\n\n                    // If the last pause call was not resumed, ignore the rest of the trace\n                    if let Some(last_pause_call) = cheatcodes.ignored_traces.last_pause_call {\n                        ignored.insert(last_pause_call, (arena.nodes().len(), 0));\n                    }\n\n                    ignored\n                })\n                .unwrap_or_default();\n\n            SparsedTraceArena { arena, ignored }\n        });\n\n        InspectorData {\n            logs: log_collector.and_then(|logs| logs.into_captured_logs()).unwrap_or_default(),\n            labels: cheatcodes\n                .as_ref()\n                .map(|cheatcodes| cheatcodes.labels.clone())\n                .unwrap_or_default(),\n            traces,\n            line_coverage: line_coverage.map(|line_coverage| line_coverage.finish()),\n            edge_coverage: edge_coverage.map(|edge_coverage| edge_coverage.into_hitcount()),\n            cheatcodes,\n            chisel_state: chisel_state.and_then(|state| state.state),\n            reverter,\n        }\n    }\n}\n\nimpl InspectorStackRefMut<'_> {\n    /// Adjusts the EVM data for the inner EVM context.\n    /// Should be called on the top-level call of inner context (depth == 0 &&\n    /// self.in_inner_context) Decreases sender nonce for CALLs to keep backwards compatibility\n    /// Updates tx.origin to the value before entering inner context\n    fn adjust_evm_data_for_inner_context<CTX: FoundryContextExt>(&mut self, ecx: &mut CTX) {\n        let inner_context_data =\n            self.inner_context_data.as_ref().expect(\"should be called in inner context\");\n        ecx.tx_mut().set_caller(inner_context_data.original_origin);\n    }\n\n    fn do_call_end<CTX: EthCheatCtx>(\n        &mut self,\n        ecx: &mut CTX,\n        inputs: &CallInputs,\n        outcome: &mut CallOutcome,\n    ) -> CallOutcome {\n        let result = outcome.result.result;\n        call_inspectors!(\n            #[ret]\n            [\n                &mut self.fuzzer,\n                &mut self.tracer,\n                &mut self.cheatcodes,\n                &mut self.printer,\n                &mut self.revert_diag\n            ],\n            |inspector| {\n                let previous_outcome = outcome.clone();\n                inspector.call_end(ecx, inputs, outcome);\n\n                // If the inspector returns a different status or a revert with a non-empty message,\n                // we assume it wants to tell us something\n                let different = outcome.result.result != result\n                    || (outcome.result.result == InstructionResult::Revert\n                        && outcome.output() != previous_outcome.output());\n                different.then_some(outcome.clone())\n            },\n        );\n\n        // Record first address that reverted the call.\n        if result.is_revert() && self.reverter.is_none() {\n            self.reverter = Some(inputs.target_address);\n        }\n\n        outcome.clone()\n    }\n\n    fn do_create_end<CTX: EthCheatCtx>(\n        &mut self,\n        ecx: &mut CTX,\n        call: &CreateInputs,\n        outcome: &mut CreateOutcome,\n    ) -> CreateOutcome {\n        let result = outcome.result.result;\n        call_inspectors!(\n            #[ret]\n            [&mut self.tracer, &mut self.cheatcodes, &mut self.printer],\n            |inspector| {\n                let previous_outcome = outcome.clone();\n                inspector.create_end(ecx, call, outcome);\n\n                // If the inspector returns a different status or a revert with a non-empty message,\n                // we assume it wants to tell us something\n                let different = outcome.result.result != result\n                    || (outcome.result.result == InstructionResult::Revert\n                        && outcome.output() != previous_outcome.output());\n                different.then_some(outcome.clone())\n            },\n        );\n\n        outcome.clone()\n    }\n\n    fn transact_inner<CTX: EthCheatCtx>(\n        &mut self,\n        ecx: &mut CTX,\n        kind: TxKind,\n        caller: Address,\n        input: Bytes,\n        gas_limit: u64,\n        value: U256,\n    ) -> (InterpreterResult, Option<Address>) {\n        let cached_evm_env = ecx.evm_clone();\n        let cached_tx_env = ecx.tx_clone();\n\n        ecx.block_mut().set_basefee(0);\n\n        let chain_id = ecx.cfg().chain_id();\n        ecx.tx_mut().set_chain_id(Some(chain_id));\n        ecx.tx_mut().set_caller(caller);\n        ecx.tx_mut().set_kind(kind);\n        ecx.tx_mut().set_data(input);\n        ecx.tx_mut().set_value(value);\n        // Add 21000 to the gas limit to account for the base cost of transaction.\n        ecx.tx_mut().set_gas_limit(gas_limit + 21000);\n\n        // If we haven't disabled gas limit checks, ensure that transaction gas limit will not\n        // exceed block gas limit.\n        if !ecx.cfg().is_block_gas_limit_disabled() {\n            let gas_limit = std::cmp::min(ecx.tx().gas_limit(), ecx.block().gas_limit());\n            ecx.tx_mut().set_gas_limit(gas_limit);\n        }\n        ecx.tx_mut().set_gas_price(0);\n\n        self.inner_context_data = Some(InnerContextData { original_origin: cached_tx_env.caller });\n        self.in_inner_context = true;\n\n        let evm_env = ecx.evm_clone();\n        let tx_env = ecx.tx_clone();\n\n        let res = self.with_inspector(|mut inspector| {\n            let (res, nested_env) = {\n                let (db, journal) = ecx.db_journal_inner_mut();\n                let mut evm =\n                    new_eth_evm_with_inspector(db, evm_env, tx_env.clone(), &mut inspector);\n\n                evm.journal_inner_mut().state = {\n                    let mut state = journal.state.clone();\n\n                    for (addr, acc_mut) in &mut state {\n                        // mark all accounts cold, besides preloaded addresses\n                        if journal.warm_addresses.is_cold(addr) {\n                            acc_mut.mark_cold();\n                        }\n\n                        // mark all slots cold\n                        for slot_mut in acc_mut.storage.values_mut() {\n                            slot_mut.is_cold = true;\n                            slot_mut.original_value = slot_mut.present_value;\n                        }\n                    }\n\n                    state\n                };\n\n                // set depth to 1 to make sure traces are collected correctly\n                evm.journal_inner_mut().depth = 1;\n\n                let res = evm.transact(tx_env);\n                let nested_evm_env = evm.to_evm_env();\n                (res, nested_evm_env)\n            };\n\n            // Restore env, preserving cheatcode cfg/block changes from the nested EVM\n            // but restoring the original tx and basefee (which we zeroed for the nested call).\n            let mut restored_evm_env = nested_env;\n            restored_evm_env.block_env.basefee = cached_evm_env.block_env.basefee;\n            ecx.set_evm(restored_evm_env);\n            ecx.set_tx(cached_tx_env);\n\n            res\n        });\n\n        self.in_inner_context = false;\n        self.inner_context_data = None;\n\n        let mut gas = Gas::new(gas_limit);\n\n        let Ok(res) = res else {\n            // Should we match, encode and propagate error as a revert reason?\n            let result =\n                InterpreterResult { result: InstructionResult::Revert, output: Bytes::new(), gas };\n            return (result, None);\n        };\n\n        for (addr, mut acc) in res.state {\n            let Some(acc_mut) = ecx.journal_mut().evm_state_mut().get_mut(&addr) else {\n                ecx.journal_mut().evm_state_mut().insert(addr, acc);\n                continue;\n            };\n\n            // make sure accounts that were warmed earlier do not become cold\n            if acc.status.contains(AccountStatus::Cold)\n                && !acc_mut.status.contains(AccountStatus::Cold)\n            {\n                acc.status -= AccountStatus::Cold;\n            }\n            acc_mut.info = acc.info;\n            acc_mut.status |= acc.status;\n\n            for (key, val) in acc.storage {\n                let Some(slot_mut) = acc_mut.storage.get_mut(&key) else {\n                    acc_mut.storage.insert(key, val);\n                    continue;\n                };\n                slot_mut.present_value = val.present_value;\n                slot_mut.is_cold &= val.is_cold;\n            }\n        }\n\n        let (result, address, output) = match res.result {\n            ExecutionResult::Success { reason, gas_used, gas_refunded, logs: _, output } => {\n                gas.set_refund(gas_refunded as i64);\n                let _ = gas.record_cost(gas_used);\n                let address = match output {\n                    Output::Create(_, address) => address,\n                    Output::Call(_) => None,\n                };\n                (reason.into(), address, output.into_data())\n            }\n            ExecutionResult::Halt { reason, gas_used } => {\n                let _ = gas.record_cost(gas_used);\n                (reason.into(), None, Bytes::new())\n            }\n            ExecutionResult::Revert { gas_used, output } => {\n                let _ = gas.record_cost(gas_used);\n                (InstructionResult::Revert, None, output)\n            }\n        };\n        (InterpreterResult { result, output, gas }, address)\n    }\n\n    /// Moves out of references, constructs a new [`InspectorStackRefMut`] and runs the given\n    /// closure with it.\n    fn with_inspector<O>(&mut self, f: impl FnOnce(InspectorStackRefMut<'_>) -> O) -> O {\n        let mut cheatcodes = self\n            .cheatcodes\n            .as_deref_mut()\n            .map(|cheats| core::mem::replace(cheats, Cheatcodes::new(cheats.config.clone())));\n        let mut inner = std::mem::take(self.inner);\n\n        let out = f(InspectorStackRefMut { cheatcodes: cheatcodes.as_mut(), inner: &mut inner });\n\n        if let Some(cheats) = self.cheatcodes.as_deref_mut() {\n            *cheats = cheatcodes.unwrap();\n        }\n\n        *self.inner = inner;\n\n        out\n    }\n\n    /// Invoked at the beginning of a new top-level (0 depth) frame.\n    fn top_level_frame_start<CTX: ContextTr<Journal: JournalExt>>(&mut self, ecx: &mut CTX) {\n        if self.enable_isolation {\n            // If we're in isolation mode, we need to keep track of the state at the beginning of\n            // the frame to be able to roll back on revert\n            self.top_frame_journal.clone_from(ecx.journal().evm_state());\n        }\n    }\n\n    /// Invoked at the end of root frame.\n    fn top_level_frame_end<CTX: ContextTr<Journal: JournalExt>>(\n        &mut self,\n        ecx: &mut CTX,\n        result: InstructionResult,\n    ) {\n        if !result.is_revert() {\n            return;\n        }\n        // Encountered a revert, since cheatcodes may have altered the evm state in such a way\n        // that violates some constraints, e.g. `deal`, we need to manually roll back on revert\n        // before revm reverts the state itself\n        if let Some(cheats) = self.cheatcodes.as_mut() {\n            cheats.on_revert(ecx);\n        }\n\n        // If we're in isolation mode, we need to rollback to state before the root frame was\n        // created We can't rely on revm's journal because it doesn't account for changes\n        // made by isolated calls\n        if self.enable_isolation {\n            *ecx.journal_mut().evm_state_mut() = std::mem::take(&mut self.top_frame_journal);\n        }\n    }\n\n    // We take extra care in optimizing `step` and `step_end`, as they're are likely the most\n    // hot functions in all of Foundry.\n    // We want to `#[inline(always)]` these functions so that `InspectorStack` does not\n    // delegate to `InspectorStackRefMut` in this case.\n\n    #[inline(always)]\n    fn step_inlined<CTX: EthCheatCtx>(&mut self, interpreter: &mut Interpreter, ecx: &mut CTX) {\n        call_inspectors!(\n            [\n                // These are sorted in definition order.\n                &mut self.edge_coverage,\n                &mut self.fuzzer,\n                &mut self.line_coverage,\n                &mut self.printer,\n                &mut self.revert_diag,\n                &mut self.script_execution_inspector,\n                &mut self.tracer,\n                // Keep `cheatcodes` last to make use of the tail call.\n                &mut self.cheatcodes,\n            ],\n            |inspector| (**inspector).step(interpreter, ecx),\n        );\n    }\n\n    #[inline(always)]\n    fn step_end_inlined<CTX: EthCheatCtx>(&mut self, interpreter: &mut Interpreter, ecx: &mut CTX) {\n        call_inspectors!(\n            [\n                // These are sorted in definition order.\n                &mut self.chisel_state,\n                &mut self.printer,\n                &mut self.revert_diag,\n                &mut self.tracer,\n                // Keep `cheatcodes` last to make use of the tail call.\n                &mut self.cheatcodes,\n            ],\n            |inspector| (**inspector).step_end(interpreter, ecx),\n        );\n    }\n}\n\nimpl<CTX: EthCheatCtx> Inspector<CTX> for InspectorStackRefMut<'_> {\n    fn initialize_interp(&mut self, interpreter: &mut Interpreter, ecx: &mut CTX) {\n        call_inspectors!(\n            [\n                &mut self.line_coverage,\n                &mut self.tracer,\n                &mut self.cheatcodes,\n                &mut self.script_execution_inspector,\n                &mut self.printer\n            ],\n            |inspector| inspector.initialize_interp(interpreter, ecx),\n        );\n    }\n\n    fn step(&mut self, interpreter: &mut Interpreter, ecx: &mut CTX) {\n        self.step_inlined(interpreter, ecx);\n    }\n\n    fn step_end(&mut self, interpreter: &mut Interpreter, ecx: &mut CTX) {\n        self.step_end_inlined(interpreter, ecx);\n    }\n\n    #[allow(clippy::redundant_clone)]\n    fn log(&mut self, ecx: &mut CTX, log: Log) {\n        call_inspectors!(\n            [&mut self.tracer, &mut self.log_collector, &mut self.cheatcodes, &mut self.printer],\n            |inspector| inspector.log(ecx, log.clone()),\n        );\n    }\n\n    #[allow(clippy::redundant_clone)]\n    fn log_full(&mut self, interpreter: &mut Interpreter, ecx: &mut CTX, log: Log) {\n        call_inspectors!(\n            [&mut self.tracer, &mut self.log_collector, &mut self.cheatcodes, &mut self.printer],\n            |inspector| inspector.log_full(interpreter, ecx, log.clone()),\n        );\n    }\n\n    fn call(&mut self, ecx: &mut CTX, call: &mut CallInputs) -> Option<CallOutcome> {\n        if self.in_inner_context && ecx.journal().depth() == 1 {\n            self.adjust_evm_data_for_inner_context(ecx);\n            return None;\n        }\n\n        if ecx.journal().depth() == 0 {\n            self.top_level_frame_start(ecx);\n        }\n\n        call_inspectors!(\n            #[ret]\n            [\n                &mut self.fuzzer,\n                &mut self.tracer,\n                &mut self.log_collector,\n                &mut self.printer,\n                &mut self.revert_diag\n            ],\n            |inspector| {\n                let mut out = None;\n                if let Some(output) = inspector.call(ecx, call) {\n                    out = Some(Some(output));\n                }\n                out\n            },\n        );\n\n        if let Some(cheatcodes) = self.cheatcodes.as_deref_mut() {\n            // Handle mocked functions, replace bytecode address with mock if matched.\n            if let Some(mocks) = cheatcodes.mocked_functions.get(&call.bytecode_address) {\n                let input_bytes = call.input.bytes(ecx);\n                // Check if any mock function set for call data or if catch-all mock function set\n                // for selector.\n                if let Some(target) = mocks\n                    .get(&input_bytes)\n                    .or_else(|| input_bytes.get(..4).and_then(|selector| mocks.get(selector)))\n                {\n                    call.bytecode_address = *target;\n                    call.known_bytecode = None;\n                }\n            }\n\n            if let Some(output) = cheatcodes.call_with_executor(ecx, call, self.inner) {\n                return Some(output);\n            }\n        }\n\n        if self.enable_isolation && !self.in_inner_context && ecx.journal().depth() == 1 {\n            match call.scheme {\n                // Isolate CALLs\n                CallScheme::Call => {\n                    let input = call.input.bytes(ecx);\n                    let (result, _) = self.transact_inner(\n                        ecx,\n                        TxKind::Call(call.target_address),\n                        call.caller,\n                        input,\n                        call.gas_limit,\n                        call.value.get(),\n                    );\n                    return Some(CallOutcome {\n                        result,\n                        memory_offset: call.return_memory_offset.clone(),\n                        was_precompile_called: true,\n                        precompile_call_logs: vec![],\n                    });\n                }\n                // Mark accounts and storage cold before STATICCALLs\n                CallScheme::StaticCall => {\n                    let (_, journal_inner) = ecx.db_journal_inner_mut();\n                    let JournaledState { state, warm_addresses, .. } = journal_inner;\n                    for (addr, acc_mut) in state {\n                        // Do not mark accounts and storage cold accounts with arbitrary storage.\n                        if let Some(cheatcodes) = &self.cheatcodes\n                            && cheatcodes.has_arbitrary_storage(addr)\n                        {\n                            continue;\n                        }\n\n                        if warm_addresses.is_cold(addr) {\n                            acc_mut.mark_cold();\n                        }\n\n                        for slot_mut in acc_mut.storage.values_mut() {\n                            slot_mut.is_cold = true;\n                        }\n                    }\n                }\n                // Process other variants as usual\n                CallScheme::CallCode | CallScheme::DelegateCall => {}\n            }\n        }\n\n        None\n    }\n\n    fn call_end(&mut self, ecx: &mut CTX, inputs: &CallInputs, outcome: &mut CallOutcome) {\n        // We are processing inner context outputs in the outer context, so need to avoid processing\n        // twice.\n        if self.in_inner_context && ecx.journal().depth() == 1 {\n            return;\n        }\n\n        self.do_call_end(ecx, inputs, outcome);\n\n        if ecx.journal().depth() == 0 {\n            self.top_level_frame_end(ecx, outcome.result.result);\n        }\n    }\n\n    fn create(&mut self, ecx: &mut CTX, create: &mut CreateInputs) -> Option<CreateOutcome> {\n        if self.in_inner_context && ecx.journal().depth() == 1 {\n            self.adjust_evm_data_for_inner_context(ecx);\n            return None;\n        }\n\n        if ecx.journal().depth() == 0 {\n            self.top_level_frame_start(ecx);\n        }\n\n        call_inspectors!(\n            #[ret]\n            [&mut self.tracer, &mut self.line_coverage, &mut self.cheatcodes],\n            |inspector| inspector.create(ecx, create).map(Some),\n        );\n\n        if !matches!(create.scheme(), CreateScheme::Create2 { .. })\n            && self.enable_isolation\n            && !self.in_inner_context\n            && ecx.journal().depth() == 1\n        {\n            let (result, address) = self.transact_inner(\n                ecx,\n                TxKind::Create,\n                create.caller(),\n                create.init_code().clone(),\n                create.gas_limit(),\n                create.value(),\n            );\n            return Some(CreateOutcome { result, address });\n        }\n\n        None\n    }\n\n    fn create_end(&mut self, ecx: &mut CTX, call: &CreateInputs, outcome: &mut CreateOutcome) {\n        // We are processing inner context outputs in the outer context, so need to avoid processing\n        // twice.\n        if self.in_inner_context && ecx.journal().depth() == 1 {\n            return;\n        }\n\n        self.do_create_end(ecx, call, outcome);\n\n        if ecx.journal().depth() == 0 {\n            self.top_level_frame_end(ecx, outcome.result.result);\n        }\n    }\n\n    fn selfdestruct(&mut self, contract: Address, target: Address, value: U256) {\n        call_inspectors!([&mut self.printer], |inspector| Inspector::<CTX>::selfdestruct(\n            inspector, contract, target, value,\n        ));\n    }\n}\n\nimpl FoundryInspectorExt for InspectorStackRefMut<'_> {\n    fn should_use_create2_factory(&mut self, depth: usize, inputs: &CreateInputs) -> bool {\n        call_inspectors!(\n            #[ret]\n            [&mut self.cheatcodes],\n            |inspector| { inspector.should_use_create2_factory(depth, inputs).then_some(true) },\n        );\n\n        false\n    }\n\n    fn console_log(&mut self, msg: &str) {\n        call_inspectors!([&mut self.log_collector], |inspector| FoundryInspectorExt::console_log(\n            inspector, msg\n        ));\n    }\n\n    fn get_networks(&self) -> NetworkConfigs {\n        self.inner.networks\n    }\n\n    fn create2_deployer(&self) -> Address {\n        self.inner.create2_deployer\n    }\n}\n\nimpl<CTX: EthCheatCtx> Inspector<CTX> for InspectorStack {\n    fn step(&mut self, interpreter: &mut Interpreter, ecx: &mut CTX) {\n        self.as_mut().step_inlined(interpreter, ecx)\n    }\n\n    fn step_end(&mut self, interpreter: &mut Interpreter, ecx: &mut CTX) {\n        self.as_mut().step_end_inlined(interpreter, ecx)\n    }\n\n    fn call(&mut self, context: &mut CTX, inputs: &mut CallInputs) -> Option<CallOutcome> {\n        self.as_mut().call(context, inputs)\n    }\n\n    fn call_end(&mut self, context: &mut CTX, inputs: &CallInputs, outcome: &mut CallOutcome) {\n        self.as_mut().call_end(context, inputs, outcome)\n    }\n\n    fn create(&mut self, context: &mut CTX, create: &mut CreateInputs) -> Option<CreateOutcome> {\n        self.as_mut().create(context, create)\n    }\n\n    fn create_end(&mut self, context: &mut CTX, call: &CreateInputs, outcome: &mut CreateOutcome) {\n        self.as_mut().create_end(context, call, outcome)\n    }\n\n    fn initialize_interp(&mut self, interpreter: &mut Interpreter, ecx: &mut CTX) {\n        self.as_mut().initialize_interp(interpreter, ecx)\n    }\n\n    fn log(&mut self, ecx: &mut CTX, log: Log) {\n        self.as_mut().log(ecx, log)\n    }\n\n    fn log_full(&mut self, interpreter: &mut Interpreter, ecx: &mut CTX, log: Log) {\n        self.as_mut().log_full(interpreter, ecx, log)\n    }\n\n    fn selfdestruct(&mut self, contract: Address, target: Address, value: U256) {\n        call_inspectors!([&mut self.inner.printer], |inspector| Inspector::<CTX>::selfdestruct(\n            inspector, contract, target, value,\n        ));\n    }\n}\n\nimpl FoundryInspectorExt for InspectorStack {\n    fn should_use_create2_factory(&mut self, depth: usize, inputs: &CreateInputs) -> bool {\n        self.as_mut().should_use_create2_factory(depth, inputs)\n    }\n\n    fn get_networks(&self) -> NetworkConfigs {\n        self.networks\n    }\n\n    fn create2_deployer(&self) -> Address {\n        self.create2_deployer\n    }\n}\n\nimpl<'a> Deref for InspectorStackRefMut<'a> {\n    type Target = &'a mut InspectorStackInner;\n\n    fn deref(&self) -> &Self::Target {\n        &self.inner\n    }\n}\n\nimpl DerefMut for InspectorStackRefMut<'_> {\n    fn deref_mut(&mut self) -> &mut Self::Target {\n        &mut self.inner\n    }\n}\n\nimpl Deref for InspectorStack {\n    type Target = InspectorStackInner;\n\n    fn deref(&self) -> &Self::Target {\n        &self.inner\n    }\n}\n\nimpl DerefMut for InspectorStack {\n    fn deref_mut(&mut self) -> &mut Self::Target {\n        &mut self.inner\n    }\n}\n"
  },
  {
    "path": "crates/evm/evm/src/lib.rs",
    "content": "//! # foundry-evm\n//!\n//! Main Foundry EVM backend abstractions.\n\n#![cfg_attr(not(test), warn(unused_crate_dependencies))]\n#![cfg_attr(docsrs, feature(doc_cfg))]\n\n#[macro_use]\nextern crate tracing;\n\npub mod executors;\npub mod inspectors;\n\npub use foundry_evm_core as core;\npub use foundry_evm_core::{\n    EthInspectorExt, EvmEnv, FoundryInspectorExt, backend, constants, decode, fork, hardfork, opts,\n    utils,\n};\npub use foundry_evm_coverage as coverage;\npub use foundry_evm_fuzz as fuzz;\npub use foundry_evm_traces as traces;\n\n// TODO: We should probably remove these, but it's a pretty big breaking change.\n#[doc(hidden)]\npub use revm;\n"
  },
  {
    "path": "crates/evm/fuzz/Cargo.toml",
    "content": "[package]\nname = \"foundry-evm-fuzz\"\ndescription = \"EVM fuzzing implementation using `proptest`\"\n\nversion.workspace = true\nedition.workspace = true\nrust-version.workspace = true\nauthors.workspace = true\nlicense.workspace = true\nhomepage.workspace = true\nrepository.workspace = true\n\n[lints]\nworkspace = true\n\n[dependencies]\nfoundry-common.workspace = true\nfoundry-compilers.workspace = true\nfoundry-config.workspace = true\nfoundry-evm-core.workspace = true\nfoundry-evm-coverage.workspace = true\nfoundry-evm-traces.workspace = true\n\nsolar.workspace = true\n\nalloy-dyn-abi = { workspace = true, features = [\"arbitrary\", \"eip712\"] }\nalloy-json-abi.workspace = true\nalloy-primitives = { workspace = true, features = [\n    \"serde\",\n    \"getrandom\",\n    \"arbitrary\",\n    \"rlp\",\n    \"map-indexmap\",\n] }\nrevm = { workspace = true, features = [\n    \"std\",\n    \"serde\",\n    \"memory_limit\",\n    \"optional_eip3607\",\n    \"optional_block_gas_limit\",\n    \"optional_no_base_fee\",\n    \"arbitrary\",\n] }\n\neyre.workspace = true\nitertools.workspace = true\nparking_lot.workspace = true\nproptest.workspace = true\nrand.workspace = true\nserde.workspace = true\nthiserror.workspace = true\ntracing.workspace = true\n"
  },
  {
    "path": "crates/evm/fuzz/src/error.rs",
    "content": "//! Errors related to fuzz tests.\n\nuse proptest::test_runner::Reason;\n\n/// Possible errors when running fuzz tests\n#[derive(Debug, thiserror::Error)]\npub enum FuzzError {\n    #[error(\"`vm.assume` reject\")]\n    AssumeReject,\n    #[error(\"`vm.assume` rejected too many inputs ({0} allowed)\")]\n    TooManyRejects(u32),\n}\n\nimpl From<FuzzError> for Reason {\n    fn from(error: FuzzError) -> Self {\n        error.to_string().into()\n    }\n}\n"
  },
  {
    "path": "crates/evm/fuzz/src/inspector.rs",
    "content": "use crate::{invariant::RandomCallGenerator, strategies::EvmFuzzState};\nuse foundry_common::mapping_slots::step as mapping_step;\nuse foundry_evm_core::constants::CHEATCODE_ADDRESS;\nuse revm::{\n    Inspector,\n    context::{ContextTr, JournalTr, Transaction},\n    inspector::JournalExt,\n    interpreter::{CallInput, CallInputs, CallOutcome, CallScheme, CallValue, Interpreter},\n};\n\n/// An inspector that can fuzz and collect data for that effect.\n#[derive(Clone, Debug)]\npub struct Fuzzer {\n    /// If set, it collects `stack` and `memory` values for fuzzing purposes.\n    pub collect: bool,\n    /// Given a strategy, it generates a random call.\n    pub call_generator: Option<RandomCallGenerator>,\n    /// If `collect` is set, we store the collected values in this fuzz dictionary.\n    pub fuzz_state: EvmFuzzState,\n}\n\nimpl<CTX> Inspector<CTX> for Fuzzer\nwhere\n    CTX: ContextTr<Journal: JournalExt>,\n{\n    #[inline]\n    fn step(&mut self, interp: &mut Interpreter, _context: &mut CTX) {\n        // We only collect `stack` and `memory` data before and after calls.\n        if self.collect {\n            self.collect_data(interp);\n            if let Some(mapping_slots) = &mut self.fuzz_state.mapping_slots {\n                mapping_step(mapping_slots, interp);\n            }\n        }\n    }\n\n    fn call(&mut self, ecx: &mut CTX, inputs: &mut CallInputs) -> Option<CallOutcome> {\n        // We don't want to override the very first call made to the test contract.\n        if self.call_generator.is_some() && ecx.tx().caller() != inputs.caller {\n            self.override_call(ecx, inputs);\n        }\n\n        // We only collect `stack` and `memory` data before and after calls.\n        // this will be turned off on the next `step`\n        self.collect = true;\n\n        None\n    }\n\n    fn call_end(&mut self, _context: &mut CTX, _inputs: &CallInputs, _outcome: &mut CallOutcome) {\n        if let Some(ref mut call_generator) = self.call_generator {\n            // Decrement depth when any call ends while inside an override\n            if call_generator.override_depth > 0 {\n                call_generator.override_depth -= 1;\n            }\n        }\n\n        // We only collect `stack` and `memory` data before and after calls.\n        // this will be turned off on the next `step`\n        self.collect = true;\n    }\n}\n\nimpl Fuzzer {\n    /// Collects `stack` and `memory` values into the fuzz dictionary.\n    #[cold]\n    fn collect_data(&mut self, interpreter: &Interpreter) {\n        self.fuzz_state.collect_values(interpreter.stack.data().iter().copied().map(Into::into));\n\n        // TODO: disabled for now since it's flooding the dictionary\n        // for index in 0..interpreter.shared_memory.len() / 32 {\n        //     let mut slot = [0u8; 32];\n        //     slot.clone_from_slice(interpreter.shared_memory.get_slice(index * 32, 32));\n\n        //     state.insert(slot);\n        // }\n\n        self.collect = false;\n    }\n\n    /// Overrides an external call to simulate reentrancy attacks.\n    ///\n    /// This function detects reentrancy vulnerabilities by replacing external calls\n    /// with callbacks that reenter the caller contract.\n    ///\n    /// For calls with value (ETH transfers):\n    /// 1. Performs the ETH transfer via the journal first\n    /// 2. Replaces the call with a reentrant callback (value = 0)\n    ///\n    /// For calls without value:\n    /// - Replaces the call entirely with a reentrant callback\n    ///\n    /// This simulates malicious contracts that immediately reenter when called.\n    fn override_call<CTX>(&mut self, ecx: &mut CTX, call: &mut CallInputs)\n    where\n        CTX: ContextTr<Journal: JournalExt>,\n    {\n        let Some(ref mut call_generator) = self.call_generator else {\n            return;\n        };\n\n        // Skip if:\n        // - Caller is test contract (don't override the initial calls from the test)\n        // - Not a CALL scheme (only override CALLs, not STATICCALLs, DELEGATECALLs, etc.)\n        // - Inside an override (prevent recursive overrides)\n        // - Target is cheatcode address\n        // - Neither caller nor target is a handler contract\n        //\n        // We override calls when either the caller OR target is a handler. This covers:\n        // 1. EtherStore pattern: handler sends ETH out, attacker reenters handler\n        // 2. Rari pattern: external protocol sends ETH to handler, handler reenters protocol\n        let caller_is_handler = call_generator.is_handler(call.caller);\n        let target_is_handler = call_generator.is_handler(call.target_address);\n        if call.caller == call_generator.test_address\n            || call.scheme != CallScheme::Call\n            || call_generator.override_depth > 0\n            || call.target_address == CHEATCODE_ADDRESS\n            || (!caller_is_handler && !target_is_handler)\n        {\n            return;\n        }\n\n        // There's only a ~27% chance that an override happens (90% * 30% from strategy).\n        let Some(tx) = call_generator.next(call.caller, call.target_address) else {\n            return;\n        };\n\n        // For value transfers, perform the ETH transfer before injecting the callback.\n        // This simulates a malicious receive() that gets the ETH and then reenters.\n        let value = call.transfer_value().unwrap_or_default();\n        let has_value = !value.is_zero() && call.gas_limit > 2300;\n        if has_value && ecx.journal_mut().transfer(call.caller, call.target_address, value).is_err()\n        {\n            return;\n        }\n\n        // Replace the call with a reentrant callback\n        call.input = CallInput::Bytes(tx.call_details.calldata.0.into());\n        call.caller = tx.sender;\n        call.target_address = tx.call_details.target;\n        call.bytecode_address = tx.call_details.target;\n        // Clear known_bytecode to force REVM to load bytecode from the new target.\n        // Without this, REVM uses cached bytecode from the original target (e.g., empty\n        // bytecode for EOA), causing the call to short-circuit before executing any code.\n        call.known_bytecode = None;\n        // Clear value since ETH was already transferred above\n        call.value = CallValue::Transfer(alloy_primitives::U256::ZERO);\n\n        // Track that we're inside an overridden call to avoid recursive overrides\n        call_generator.override_depth = 1;\n    }\n}\n"
  },
  {
    "path": "crates/evm/fuzz/src/invariant/call_override.rs",
    "content": "use crate::{BasicTxDetails, CallDetails};\nuse alloy_primitives::Address;\nuse parking_lot::{Mutex, RwLock};\nuse proptest::{\n    option::weighted,\n    strategy::{SBoxedStrategy, Strategy, ValueTree},\n    test_runner::TestRunner,\n};\nuse std::{collections::HashSet, sync::Arc};\n\n/// Given a TestRunner and a strategy, it generates calls. Used inside the Fuzzer inspector to\n/// override external calls to test for potential reentrancy vulnerabilities.\n///\n/// The key insight is that we only override calls TO handler contracts (targeted contracts).\n/// This simulates a malicious contract that reenters when receiving ETH via its receive() function.\n#[derive(Clone, Debug)]\npub struct RandomCallGenerator {\n    /// Address of the test contract.\n    pub test_address: Address,\n    /// Addresses of handler contracts that can be reentered.\n    /// We only inject callbacks when the call target is one of these.\n    pub handler_addresses: Arc<RwLock<HashSet<Address>>>,\n    /// Runner that will generate the call from the strategy.\n    pub runner: Arc<Mutex<TestRunner>>,\n    /// Strategy to be used to generate calls from `target_reference`.\n    pub strategy: SBoxedStrategy<Option<CallDetails>>,\n    /// Reference to which contract we want a fuzzed calldata from.\n    pub target_reference: Arc<RwLock<Address>>,\n    /// Tracks the call depth when an override is active. When > 0, we're inside an overridden\n    /// call and should not override nested calls. Incremented when we override a call,\n    /// decremented when any call ends while inside an override.\n    pub override_depth: usize,\n    /// If set to `true`, consumes the next call from `last_sequence`, otherwise queries it from\n    /// the strategy.\n    pub replay: bool,\n    /// Saves the sequence of generated calls that can be replayed later on.\n    pub last_sequence: Arc<RwLock<Vec<Option<BasicTxDetails>>>>,\n}\n\nimpl RandomCallGenerator {\n    pub fn new(\n        test_address: Address,\n        handler_addresses: HashSet<Address>,\n        runner: TestRunner,\n        strategy: impl Strategy<Value = CallDetails> + Send + Sync + 'static,\n        target_reference: Arc<RwLock<Address>>,\n    ) -> Self {\n        Self {\n            test_address,\n            handler_addresses: Arc::new(RwLock::new(handler_addresses)),\n            runner: Arc::new(Mutex::new(runner)),\n            strategy: weighted(0.9, strategy).sboxed(),\n            target_reference,\n            last_sequence: Arc::default(),\n            replay: false,\n            override_depth: 0,\n        }\n    }\n\n    /// Check if the given address is a handler that can be reentered.\n    pub fn is_handler(&self, address: Address) -> bool {\n        self.handler_addresses.read().contains(&address)\n    }\n\n    /// All `self.next()` calls will now pop `self.last_sequence`. Used to replay an invariant\n    /// failure.\n    pub fn set_replay(&mut self, status: bool) {\n        self.replay = status;\n        if status {\n            // So it can later be popped.\n            self.last_sequence.write().reverse();\n        }\n    }\n\n    /// Gets the next call. Random if replay is not set. Otherwise, it pops from `last_sequence`.\n    pub fn next(\n        &mut self,\n        original_caller: Address,\n        original_target: Address,\n    ) -> Option<BasicTxDetails> {\n        if self.replay {\n            self.last_sequence.write().pop().expect(\n                \"to have same size as the number of (unsafe) external calls of the sequence.\",\n            )\n        } else {\n            // TODO: Do we want it to be 80% chance only too ?\n            let sender = original_target;\n\n            // Set which contract we mostly (80% chance) want to generate calldata from.\n            *self.target_reference.write() = original_caller;\n\n            // `original_caller` has a 80% chance of being the `new_target`.\n            let choice = self.strategy.new_tree(&mut self.runner.lock()).unwrap().current().map(\n                |call_details| BasicTxDetails { warp: None, roll: None, sender, call_details },\n            );\n\n            self.last_sequence.write().push(choice.clone());\n            choice\n        }\n    }\n}\n"
  },
  {
    "path": "crates/evm/fuzz/src/invariant/filters.rs",
    "content": "use alloy_json_abi::{Function, JsonAbi};\nuse alloy_primitives::{Address, Selector};\nuse foundry_compilers::ArtifactId;\nuse foundry_evm_core::utils::get_function;\nuse std::collections::BTreeMap;\n\n/// Contains which contracts are to be targeted or excluded on an invariant test through their\n/// artifact identifiers.\n#[derive(Default)]\npub struct ArtifactFilters {\n    /// List of `contract_path:contract_name` along with selectors, which are to be targeted. If\n    /// list of functions is not empty, target only those.\n    pub targeted: BTreeMap<String, Vec<Selector>>,\n    /// List of `contract_path:contract_name` which are to be excluded.\n    pub excluded: Vec<String>,\n}\n\nimpl ArtifactFilters {\n    /// Returns `true` if the given identifier matches this filter.\n    pub fn matches(&self, identifier: &str) -> bool {\n        (self.targeted.is_empty() || self.targeted.contains_key(identifier))\n            && (self.excluded.is_empty() || !self.excluded.iter().any(|id| id == identifier))\n    }\n\n    /// Gets all the targeted functions from `artifact`. Returns error, if selectors do not match\n    /// the `artifact`.\n    ///\n    /// An empty vector means that it targets any mutable function.\n    pub fn get_targeted_functions(\n        &self,\n        artifact: &ArtifactId,\n        abi: &JsonAbi,\n    ) -> eyre::Result<Option<Vec<Function>>> {\n        if let Some(selectors) = self.targeted.get(&artifact.identifier()) {\n            let functions = selectors\n                .iter()\n                .map(|selector| get_function(&artifact.name, *selector, abi).cloned())\n                .collect::<eyre::Result<Vec<_>>>()?;\n            // targetArtifactSelectors > excludeArtifacts > targetArtifacts\n            if functions.is_empty() && self.excluded.contains(&artifact.identifier()) {\n                return Ok(None);\n            }\n            return Ok(Some(functions));\n        }\n        // If no contract is specifically targeted, and this contract is not excluded, then accept\n        // all functions.\n        if self.targeted.is_empty() && !self.excluded.contains(&artifact.identifier()) {\n            return Ok(Some(vec![]));\n        }\n        Ok(None)\n    }\n}\n\n/// Filter for acceptable senders to use for invariant testing. Exclusion takes priority if\n/// clashing.\n///\n/// `address(0)` is excluded by default.\n#[derive(Default)]\npub struct SenderFilters {\n    pub targeted: Vec<Address>,\n    pub excluded: Vec<Address>,\n}\n\nimpl SenderFilters {\n    pub fn new(mut targeted: Vec<Address>, mut excluded: Vec<Address>) -> Self {\n        let addr_0 = Address::ZERO;\n        if !excluded.contains(&addr_0) {\n            excluded.push(addr_0);\n        }\n        targeted.retain(|addr| !excluded.contains(addr));\n        Self { targeted, excluded }\n    }\n}\n"
  },
  {
    "path": "crates/evm/fuzz/src/invariant/mod.rs",
    "content": "use alloy_json_abi::{Function, JsonAbi};\nuse alloy_primitives::{Address, Selector, map::HashMap};\nuse foundry_compilers::artifacts::StorageLayout;\nuse itertools::Either;\nuse parking_lot::Mutex;\nuse std::{collections::BTreeMap, sync::Arc};\n\nmod call_override;\npub use call_override::RandomCallGenerator;\n\nmod filters;\nuse crate::BasicTxDetails;\npub use filters::{ArtifactFilters, SenderFilters};\nuse foundry_common::{ContractsByAddress, ContractsByArtifact};\nuse foundry_evm_core::utils::{StateChangeset, get_function};\n\n/// Returns true if the function returns `int256`, indicating optimization mode.\n/// In optimization mode, the fuzzer maximizes the return value instead of checking invariants.\npub fn is_optimization_invariant(func: &Function) -> bool {\n    func.outputs.len() == 1 && func.outputs[0].ty == \"int256\"\n}\n\n/// Contracts identified as targets during a fuzz run.\n///\n/// During execution, any newly created contract is added as target and used through the rest of\n/// the fuzz run if the collection is updatable (no `targetContract` specified in `setUp`).\n#[derive(Clone, Debug)]\npub struct FuzzRunIdentifiedContracts {\n    /// Contracts identified as targets during a fuzz run.\n    pub targets: Arc<Mutex<TargetedContracts>>,\n    /// Whether target contracts are updatable or not.\n    pub is_updatable: bool,\n}\n\nimpl FuzzRunIdentifiedContracts {\n    /// Creates a new `FuzzRunIdentifiedContracts` instance.\n    pub fn new(targets: TargetedContracts, is_updatable: bool) -> Self {\n        Self { targets: Arc::new(Mutex::new(targets)), is_updatable }\n    }\n\n    /// If targets are updatable, collect all contracts created during an invariant run (which\n    /// haven't been discovered yet).\n    pub fn collect_created_contracts(\n        &self,\n        state_changeset: &StateChangeset,\n        project_contracts: &ContractsByArtifact,\n        setup_contracts: &ContractsByAddress,\n        artifact_filters: &ArtifactFilters,\n        created_contracts: &mut Vec<Address>,\n    ) -> eyre::Result<()> {\n        if !self.is_updatable {\n            return Ok(());\n        }\n\n        let mut targets = self.targets.lock();\n        for (address, account) in state_changeset {\n            if setup_contracts.contains_key(address) {\n                continue;\n            }\n            if !account.is_touched() {\n                continue;\n            }\n            let Some(code) = &account.info.code else {\n                continue;\n            };\n            if code.is_empty() {\n                continue;\n            }\n            let Some((artifact, contract)) =\n                project_contracts.find_by_deployed_code(code.original_byte_slice())\n            else {\n                continue;\n            };\n            let Some(functions) =\n                artifact_filters.get_targeted_functions(artifact, &contract.abi)?\n            else {\n                continue;\n            };\n            created_contracts.push(*address);\n            let contract = TargetedContract {\n                identifier: artifact.name.clone(),\n                abi: contract.abi.clone(),\n                targeted_functions: functions,\n                excluded_functions: Vec::new(),\n                storage_layout: contract.storage_layout.as_ref().map(Arc::clone),\n            };\n            targets.insert(*address, contract);\n        }\n        Ok(())\n    }\n\n    /// Clears targeted contracts created during an invariant run.\n    pub fn clear_created_contracts(&self, created_contracts: Vec<Address>) {\n        if !created_contracts.is_empty() {\n            let mut targets = self.targets.lock();\n            for addr in &created_contracts {\n                targets.remove(addr);\n            }\n        }\n    }\n}\n\n/// A collection of contracts identified as targets for invariant testing.\n#[derive(Clone, Debug, Default)]\npub struct TargetedContracts {\n    /// The inner map of targeted contracts.\n    pub inner: BTreeMap<Address, TargetedContract>,\n}\n\nimpl TargetedContracts {\n    /// Returns a new `TargetedContracts` instance.\n    pub fn new() -> Self {\n        Self::default()\n    }\n\n    /// Returns fuzzed contract abi and fuzzed function from address and provided calldata.\n    ///\n    /// Used to decode return values and logs in order to add values into fuzz dictionary.\n    pub fn fuzzed_artifacts(&self, tx: &BasicTxDetails) -> (Option<&JsonAbi>, Option<&Function>) {\n        match self.inner.get(&tx.call_details.target) {\n            Some(c) => (\n                Some(&c.abi),\n                c.abi.functions().find(|f| f.selector() == tx.call_details.calldata[..4]),\n            ),\n            None => (None, None),\n        }\n    }\n\n    /// Returns flatten target contract address and functions to be fuzzed.\n    /// Includes contract targeted functions if specified, else all mutable contract functions.\n    pub fn fuzzed_functions(&self) -> impl Iterator<Item = (&Address, &Function)> {\n        self.inner\n            .iter()\n            .filter(|(_, c)| !c.abi.functions.is_empty())\n            .flat_map(|(contract, c)| c.abi_fuzzed_functions().map(move |f| (contract, f)))\n    }\n\n    /// Returns whether the given transaction can be replayed or not with known contracts.\n    pub fn can_replay(&self, tx: &BasicTxDetails) -> bool {\n        match self.inner.get(&tx.call_details.target) {\n            Some(c) => c.abi.functions().any(|f| f.selector() == tx.call_details.calldata[..4]),\n            None => false,\n        }\n    }\n\n    /// Identifies fuzzed contract and function based on given tx details and returns unique metric\n    /// key composed from contract identifier and function name.\n    pub fn fuzzed_metric_key(&self, tx: &BasicTxDetails) -> Option<String> {\n        self.inner.get(&tx.call_details.target).and_then(|contract| {\n            contract\n                .abi\n                .functions()\n                .find(|f| f.selector() == tx.call_details.calldata[..4])\n                .map(|function| format!(\"{}.{}\", contract.identifier.clone(), function.name))\n        })\n    }\n\n    /// Returns a map of contract addresses to their storage layouts.\n    pub fn get_storage_layouts(&self) -> HashMap<Address, Arc<StorageLayout>> {\n        self.inner\n            .iter()\n            .filter_map(|(addr, c)| {\n                c.storage_layout.as_ref().map(|layout| (*addr, Arc::clone(layout)))\n            })\n            .collect()\n    }\n}\n\nimpl std::ops::Deref for TargetedContracts {\n    type Target = BTreeMap<Address, TargetedContract>;\n\n    fn deref(&self) -> &Self::Target {\n        &self.inner\n    }\n}\n\nimpl std::ops::DerefMut for TargetedContracts {\n    fn deref_mut(&mut self) -> &mut Self::Target {\n        &mut self.inner\n    }\n}\n\n/// A contract identified as target for invariant testing.\n#[derive(Clone, Debug)]\npub struct TargetedContract {\n    /// The contract identifier. This is only used in error messages.\n    pub identifier: String,\n    /// The contract's ABI.\n    pub abi: JsonAbi,\n    /// The targeted functions of the contract.\n    pub targeted_functions: Vec<Function>,\n    /// The excluded functions of the contract.\n    pub excluded_functions: Vec<Function>,\n    /// The contract's storage layout, if available.\n    pub storage_layout: Option<Arc<StorageLayout>>,\n}\n\nimpl TargetedContract {\n    /// Returns a new `TargetedContract` instance.\n    pub fn new(identifier: String, abi: JsonAbi) -> Self {\n        Self {\n            identifier,\n            abi,\n            targeted_functions: Vec::new(),\n            excluded_functions: Vec::new(),\n            storage_layout: None,\n        }\n    }\n\n    /// Determines contract storage layout from project contracts. Needs `storageLayout` to be\n    /// enabled as extra output in project configuration.\n    pub fn with_project_contracts(mut self, project_contracts: &ContractsByArtifact) -> Self {\n        if let Some((src, name)) = self.identifier.split_once(':')\n            && let Some((_, contract_data)) = project_contracts.iter().find(|(artifact, _)| {\n                artifact.name == name && artifact.source.as_path().ends_with(src)\n            })\n        {\n            self.storage_layout = contract_data.storage_layout.as_ref().map(Arc::clone);\n        }\n        self\n    }\n\n    /// Helper to retrieve functions to fuzz for specified abi.\n    /// Returns specified targeted functions if any, else mutable abi functions that are not\n    /// marked as excluded.\n    pub fn abi_fuzzed_functions(&self) -> impl Iterator<Item = &Function> {\n        if !self.targeted_functions.is_empty() {\n            Either::Left(self.targeted_functions.iter())\n        } else {\n            Either::Right(self.abi.functions().filter(|&func| {\n                !matches!(\n                    func.state_mutability,\n                    alloy_json_abi::StateMutability::Pure | alloy_json_abi::StateMutability::View\n                ) && !self.excluded_functions.contains(func)\n            }))\n        }\n    }\n\n    /// Returns the function for the given selector.\n    pub fn get_function(&self, selector: Selector) -> eyre::Result<&Function> {\n        get_function(&self.identifier, selector, &self.abi)\n    }\n\n    /// Adds the specified selectors to the targeted functions.\n    pub fn add_selectors(\n        &mut self,\n        selectors: impl IntoIterator<Item = Selector>,\n        should_exclude: bool,\n    ) -> eyre::Result<()> {\n        for selector in selectors {\n            if should_exclude {\n                self.excluded_functions.push(self.get_function(selector)?.clone());\n            } else {\n                self.targeted_functions.push(self.get_function(selector)?.clone());\n            }\n        }\n        Ok(())\n    }\n}\n\n/// Test contract which is testing its invariants.\n#[derive(Clone, Debug)]\npub struct InvariantContract<'a> {\n    /// Address of the test contract.\n    pub address: Address,\n    /// Invariant function present in the test contract.\n    pub invariant_function: &'a Function,\n    /// If true, `afterInvariant` function is called after each invariant run.\n    pub call_after_invariant: bool,\n    /// ABI of the test contract.\n    pub abi: &'a JsonAbi,\n}\n\nimpl<'a> InvariantContract<'a> {\n    /// Creates a new invariant contract.\n    pub fn new(\n        address: Address,\n        invariant_function: &'a Function,\n        call_after_invariant: bool,\n        abi: &'a JsonAbi,\n    ) -> Self {\n        Self { address, invariant_function, call_after_invariant, abi }\n    }\n\n    /// Returns true if this is an optimization mode invariant (returns int256).\n    pub fn is_optimization(&self) -> bool {\n        is_optimization_invariant(self.invariant_function)\n    }\n}\n"
  },
  {
    "path": "crates/evm/fuzz/src/lib.rs",
    "content": "//! # foundry-evm-fuzz\n//!\n//! EVM fuzzing implementation using [`proptest`].\n\n#![cfg_attr(not(test), warn(unused_crate_dependencies))]\n#![cfg_attr(docsrs, feature(doc_cfg))]\n\n#[macro_use]\nextern crate tracing;\n\nuse alloy_dyn_abi::{DynSolValue, JsonAbiExt};\nuse alloy_primitives::{\n    Address, Bytes, Log, U256,\n    map::{AddressHashMap, HashMap},\n};\nuse foundry_common::{calc, contracts::ContractsByAddress};\nuse foundry_evm_core::Breakpoints;\nuse foundry_evm_coverage::HitMaps;\nuse foundry_evm_traces::{CallTraceArena, SparsedTraceArena};\nuse itertools::Itertools;\nuse serde::{Deserialize, Serialize};\nuse std::{fmt, sync::Arc};\n\npub use proptest::test_runner::{Config as FuzzConfig, Reason};\n\nmod error;\npub use error::FuzzError;\n\npub mod invariant;\npub mod strategies;\npub use strategies::LiteralMaps;\n\nmod inspector;\npub use inspector::Fuzzer;\n\n/// Details of a transaction generated by fuzz strategy for fuzzing a target.\n#[derive(Clone, Debug, Serialize, Deserialize)]\npub struct BasicTxDetails {\n    /// Time (in seconds) to increase block timestamp before executing the tx.\n    #[serde(default, skip_serializing_if = \"Option::is_none\")]\n    pub warp: Option<U256>,\n    /// Number to increase block number before executing the tx.\n    #[serde(default, skip_serializing_if = \"Option::is_none\")]\n    pub roll: Option<U256>,\n    /// Transaction sender address.\n    pub sender: Address,\n    /// Transaction call details.\n    #[serde(flatten)]\n    pub call_details: CallDetails,\n}\n\n/// Call details of a transaction generated to fuzz.\n#[derive(Clone, Debug, Serialize, Deserialize)]\npub struct CallDetails {\n    /// Address of target contract.\n    pub target: Address,\n    /// The data of the transaction.\n    pub calldata: Bytes,\n}\n\nimpl BasicTxDetails {\n    /// Returns an estimate of the serialized (JSON) size in bytes.\n    pub fn estimate_serialized_size(&self) -> usize {\n        size_of::<Self>() + self.call_details.calldata.len() * 2\n    }\n}\n\n#[derive(Clone, Debug, Serialize, Deserialize)]\n#[expect(clippy::large_enum_variant)]\npub enum CounterExample {\n    /// Call used as a counter example for fuzz tests.\n    Single(BaseCounterExample),\n    /// Original sequence size and sequence of calls used as a counter example for invariant tests.\n    Sequence(usize, Vec<BaseCounterExample>),\n}\n\n#[derive(Clone, Debug, Serialize, Deserialize)]\npub struct BaseCounterExample {\n    // Amount to increase block timestamp.\n    pub warp: Option<U256>,\n    // Amount to increase block number.\n    pub roll: Option<U256>,\n    /// Address which makes the call.\n    pub sender: Option<Address>,\n    /// Address to which to call to.\n    pub addr: Option<Address>,\n    /// The data to provide.\n    pub calldata: Bytes,\n    /// Contract name if it exists.\n    pub contract_name: Option<String>,\n    /// Function name if it exists.\n    pub func_name: Option<String>,\n    /// Function signature if it exists.\n    pub signature: Option<String>,\n    /// Pretty formatted args used to call the function.\n    pub args: Option<String>,\n    /// Unformatted args used to call the function.\n    pub raw_args: Option<String>,\n    /// Counter example traces.\n    #[serde(skip)]\n    pub traces: Option<SparsedTraceArena>,\n    /// Whether to display sequence as solidity.\n    #[serde(skip)]\n    pub show_solidity: bool,\n}\n\nimpl BaseCounterExample {\n    /// Creates counter example representing a step from invariant call sequence.\n    pub fn from_invariant_call(\n        tx: &BasicTxDetails,\n        contracts: &ContractsByAddress,\n        traces: Option<SparsedTraceArena>,\n        show_solidity: bool,\n    ) -> Self {\n        let sender = tx.sender;\n        let target = tx.call_details.target;\n        let bytes = &tx.call_details.calldata;\n        let warp = tx.warp;\n        let roll = tx.roll;\n        if let Some((name, abi)) = &contracts.get(&target)\n            && let Some(func) = abi.functions().find(|f| f.selector() == bytes[..4])\n        {\n            // skip the function selector when decoding\n            if let Ok(args) = func.abi_decode_input(&bytes[4..]) {\n                return Self {\n                    warp,\n                    roll,\n                    sender: Some(sender),\n                    addr: Some(target),\n                    calldata: bytes.clone(),\n                    contract_name: Some(name.clone()),\n                    func_name: Some(func.name.clone()),\n                    signature: Some(func.signature()),\n                    args: Some(foundry_common::fmt::format_tokens(&args).format(\", \").to_string()),\n                    raw_args: Some(\n                        foundry_common::fmt::format_tokens_raw(&args).format(\", \").to_string(),\n                    ),\n                    traces,\n                    show_solidity,\n                };\n            }\n        }\n\n        Self {\n            warp,\n            roll,\n            sender: Some(sender),\n            addr: Some(target),\n            calldata: bytes.clone(),\n            contract_name: None,\n            func_name: None,\n            signature: None,\n            args: None,\n            raw_args: None,\n            traces,\n            show_solidity: false,\n        }\n    }\n\n    /// Creates counter example for a fuzz test failure.\n    pub fn from_fuzz_call(\n        bytes: Bytes,\n        args: Vec<DynSolValue>,\n        traces: Option<SparsedTraceArena>,\n    ) -> Self {\n        Self {\n            warp: None,\n            roll: None,\n            sender: None,\n            addr: None,\n            calldata: bytes,\n            contract_name: None,\n            func_name: None,\n            signature: None,\n            args: Some(foundry_common::fmt::format_tokens(&args).format(\", \").to_string()),\n            raw_args: Some(foundry_common::fmt::format_tokens_raw(&args).format(\", \").to_string()),\n            traces,\n            show_solidity: false,\n        }\n    }\n}\n\nimpl fmt::Display for BaseCounterExample {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        // Display counterexample as solidity.\n        if self.show_solidity\n            && let (Some(sender), Some(contract), Some(address), Some(func_name), Some(args)) =\n                (&self.sender, &self.contract_name, &self.addr, &self.func_name, &self.raw_args)\n        {\n            if let Some(warp) = &self.warp {\n                writeln!(f, \"\\t\\tvm.warp(block.timestamp + {warp});\")?;\n            }\n            if let Some(roll) = &self.roll {\n                writeln!(f, \"\\t\\tvm.roll(block.number + {roll});\")?;\n            }\n            writeln!(f, \"\\t\\tvm.prank({sender});\")?;\n            write!(\n                f,\n                \"\\t\\t{}({}).{}({});\",\n                contract.split_once(':').map_or(contract.as_str(), |(_, contract)| contract),\n                address,\n                func_name,\n                args\n            )?;\n\n            return Ok(());\n        }\n\n        // Regular counterexample display.\n        if let Some(sender) = self.sender {\n            write!(f, \"\\t\\tsender={sender} addr=\")?\n        }\n\n        if let Some(name) = &self.contract_name {\n            write!(f, \"[{name}]\")?\n        }\n\n        if let Some(addr) = &self.addr {\n            write!(f, \"{addr} \")?\n        }\n\n        if let Some(warp) = &self.warp {\n            write!(f, \"warp={warp} \")?;\n        }\n        if let Some(roll) = &self.roll {\n            write!(f, \"roll={roll} \")?;\n        }\n\n        if let Some(sig) = &self.signature {\n            write!(f, \"calldata={sig}\")?\n        } else {\n            write!(f, \"calldata={}\", &self.calldata)?\n        }\n\n        if let Some(args) = &self.args {\n            write!(f, \" args=[{args}]\")\n        } else {\n            write!(f, \" args=[]\")\n        }\n    }\n}\n\n/// The outcome of a fuzz test\n#[derive(Debug, Default)]\npub struct FuzzTestResult {\n    /// we keep this for the debugger\n    pub first_case: FuzzCase,\n    /// Gas usage (gas_used, call_stipend) per cases\n    pub gas_by_case: Vec<(u64, u64)>,\n    /// Whether the test case was successful. This means that the transaction executed\n    /// properly, or that there was a revert and that the test was expected to fail\n    /// (prefixed with `testFail`)\n    pub success: bool,\n    /// Whether the test case was skipped. `reason` will contain the skip reason, if any.\n    pub skipped: bool,\n\n    /// If there was a revert, this field will be populated. Note that the test can\n    /// still be successful (i.e self.success == true) when it's expected to fail.\n    pub reason: Option<String>,\n\n    /// Minimal reproduction test case for failing fuzz tests\n    pub counterexample: Option<CounterExample>,\n\n    /// Any captured & parsed as strings logs along the test's execution which should\n    /// be printed to the user.\n    pub logs: Vec<Log>,\n\n    /// Labeled addresses\n    pub labels: AddressHashMap<String>,\n\n    /// Exemplary traces for a fuzz run of the test function\n    ///\n    /// **Note** We only store a single trace of a successful fuzz call, otherwise we would get\n    /// `num(fuzz_cases)` traces, one for each run, which is neither helpful nor performant.\n    pub traces: Option<SparsedTraceArena>,\n\n    /// Additional traces used for gas report construction.\n    /// Those traces should not be displayed.\n    pub gas_report_traces: Vec<CallTraceArena>,\n\n    /// Raw line coverage info\n    pub line_coverage: Option<HitMaps>,\n\n    /// Breakpoints for debugger. Correspond to the same fuzz case as `traces`.\n    pub breakpoints: Option<Breakpoints>,\n\n    // Deprecated cheatcodes mapped to their replacements.\n    pub deprecated_cheatcodes: HashMap<&'static str, Option<&'static str>>,\n\n    /// Number of failed replays from persisted corpus.\n    pub failed_corpus_replays: usize,\n}\n\nimpl FuzzTestResult {\n    /// Returns the median gas of all test cases\n    pub fn median_gas(&self, with_stipend: bool) -> u64 {\n        let mut values = self.gas_values(with_stipend);\n        values.sort_unstable();\n        calc::median_sorted(&values)\n    }\n\n    /// Returns the average gas use of all test cases\n    pub fn mean_gas(&self, with_stipend: bool) -> u64 {\n        let mut values = self.gas_values(with_stipend);\n        values.sort_unstable();\n        calc::mean(&values)\n    }\n\n    fn gas_values(&self, with_stipend: bool) -> Vec<u64> {\n        self.gas_by_case\n            .iter()\n            .map(|gas| if with_stipend { gas.0 } else { gas.0.saturating_sub(gas.1) })\n            .collect()\n    }\n}\n\n/// Data of a single fuzz test case\n#[derive(Clone, Debug, Default, Serialize, Deserialize)]\npub struct FuzzCase {\n    /// Consumed gas\n    pub gas: u64,\n    /// The initial gas stipend for the transaction\n    pub stipend: u64,\n}\n\n/// Container type for all successful test cases\n#[derive(Clone, Debug, Serialize, Deserialize)]\n#[serde(transparent)]\npub struct FuzzedCases {\n    cases: Vec<FuzzCase>,\n}\n\nimpl FuzzedCases {\n    pub fn new(mut cases: Vec<FuzzCase>) -> Self {\n        cases.sort_by_key(|c| c.gas);\n        Self { cases }\n    }\n\n    pub fn cases(&self) -> &[FuzzCase] {\n        &self.cases\n    }\n\n    pub fn into_cases(self) -> Vec<FuzzCase> {\n        self.cases\n    }\n\n    /// Get the last [FuzzCase]\n    pub fn last(&self) -> Option<&FuzzCase> {\n        self.cases.last()\n    }\n\n    /// Returns the median gas of all test cases\n    pub fn median_gas(&self, with_stipend: bool) -> u64 {\n        let mut values = self.gas_values(with_stipend);\n        values.sort_unstable();\n        calc::median_sorted(&values)\n    }\n\n    /// Returns the average gas use of all test cases\n    pub fn mean_gas(&self, with_stipend: bool) -> u64 {\n        let mut values = self.gas_values(with_stipend);\n        values.sort_unstable();\n        calc::mean(&values)\n    }\n\n    fn gas_values(&self, with_stipend: bool) -> Vec<u64> {\n        self.cases\n            .iter()\n            .map(|c| if with_stipend { c.gas } else { c.gas.saturating_sub(c.stipend) })\n            .collect()\n    }\n\n    /// Returns the case with the highest gas usage\n    pub fn highest(&self) -> Option<&FuzzCase> {\n        self.cases.last()\n    }\n\n    /// Returns the case with the lowest gas usage\n    pub fn lowest(&self) -> Option<&FuzzCase> {\n        self.cases.first()\n    }\n\n    /// Returns the highest amount of gas spent on a fuzz case\n    pub fn highest_gas(&self, with_stipend: bool) -> u64 {\n        self.highest()\n            .map(|c| if with_stipend { c.gas } else { c.gas - c.stipend })\n            .unwrap_or_default()\n    }\n\n    /// Returns the lowest amount of gas spent on a fuzz case\n    pub fn lowest_gas(&self) -> u64 {\n        self.lowest().map(|c| c.gas).unwrap_or_default()\n    }\n}\n\n/// Fixtures to be used for fuzz tests.\n///\n/// The key represents name of the fuzzed parameter, value holds possible fuzzed values.\n/// For example, for a fixture function declared as\n/// `function fixture_sender() external returns (address[] memory senders)`\n/// the fuzz fixtures will contain `sender` key with `senders` array as value\n#[derive(Clone, Default, Debug)]\npub struct FuzzFixtures {\n    inner: Arc<HashMap<String, DynSolValue>>,\n}\n\nimpl FuzzFixtures {\n    pub fn new(fixtures: HashMap<String, DynSolValue>) -> Self {\n        Self { inner: Arc::new(fixtures) }\n    }\n\n    /// Returns configured fixtures for `param_name` fuzzed parameter.\n    pub fn param_fixtures(&self, param_name: &str) -> Option<&[DynSolValue]> {\n        if let Some(param_fixtures) = self.inner.get(&normalize_fixture(param_name)) {\n            param_fixtures.as_fixed_array().or_else(|| param_fixtures.as_array())\n        } else {\n            None\n        }\n    }\n}\n\n/// Extracts fixture name from a function name.\n/// For example: fixtures defined in `fixture_Owner` function will be applied for `owner` parameter.\npub fn fixture_name(function_name: String) -> String {\n    normalize_fixture(function_name.strip_prefix(\"fixture\").unwrap())\n}\n\n/// Normalize fixture parameter name, for example `_Owner` to `owner`.\nfn normalize_fixture(param_name: &str) -> String {\n    param_name.trim_matches('_').to_ascii_lowercase()\n}\n"
  },
  {
    "path": "crates/evm/fuzz/src/strategies/calldata.rs",
    "content": "use crate::{\n    FuzzFixtures,\n    strategies::{EvmFuzzState, fuzz_param_from_state, fuzz_param_with_fixtures},\n};\nuse alloy_dyn_abi::JsonAbiExt;\nuse alloy_json_abi::Function;\nuse alloy_primitives::Bytes;\nuse proptest::prelude::Strategy;\n\n/// Given a function, it returns a strategy which generates valid calldata\n/// for that function's input types, following declared test fixtures.\npub fn fuzz_calldata(\n    func: Function,\n    fuzz_fixtures: &FuzzFixtures,\n) -> impl Strategy<Value = Bytes> + use<> {\n    // We need to compose all the strategies generated for each parameter in all\n    // possible combinations, accounting any parameter declared fixture\n    let strats = func\n        .inputs\n        .iter()\n        .map(|input| {\n            fuzz_param_with_fixtures(\n                &input.selector_type().parse().unwrap(),\n                fuzz_fixtures.param_fixtures(&input.name),\n                &input.name,\n            )\n        })\n        .collect::<Vec<_>>();\n    strats.prop_map(move |values| {\n        func.abi_encode_input(&values)\n            .unwrap_or_else(|_| {\n                panic!(\n                    \"Fuzzer generated invalid arguments for function `{}` with inputs {:?}: {:?}\",\n                    func.name, func.inputs, values\n                )\n            })\n            .into()\n    })\n}\n\n/// Given a function and some state, it returns a strategy which generated valid calldata for the\n/// given function's input types, based on state taken from the EVM.\npub fn fuzz_calldata_from_state(\n    func: Function,\n    state: &EvmFuzzState,\n) -> impl Strategy<Value = Bytes> + use<> {\n    let strats = func\n        .inputs\n        .iter()\n        .map(|input| fuzz_param_from_state(&input.selector_type().parse().unwrap(), state))\n        .collect::<Vec<_>>();\n    strats\n        .prop_map(move |values| {\n            func.abi_encode_input(&values)\n                .unwrap_or_else(|_| {\n                    panic!(\n                        \"Fuzzer generated invalid arguments for function `{}` with inputs {:?}: {:?}\",\n                        func.name, func.inputs, values\n                    )\n                })\n                .into()\n        })\n        .no_shrink()\n}\n\n#[cfg(test)]\nmod tests {\n    use crate::{FuzzFixtures, strategies::fuzz_calldata};\n    use alloy_dyn_abi::{DynSolValue, JsonAbiExt};\n    use alloy_json_abi::Function;\n    use alloy_primitives::{Address, map::HashMap};\n    use proptest::prelude::Strategy;\n\n    #[test]\n    fn can_fuzz_with_fixtures() {\n        let function = Function::parse(\"test_fuzzed_address(address addressFixture)\").unwrap();\n\n        let address_fixture = DynSolValue::Address(Address::random());\n        let mut fixtures = HashMap::default();\n        fixtures.insert(\n            \"addressFixture\".to_string(),\n            DynSolValue::Array(vec![address_fixture.clone()]),\n        );\n\n        let expected = function.abi_encode_input(&[address_fixture]).unwrap();\n        let strategy = fuzz_calldata(function, &FuzzFixtures::new(fixtures));\n        let _ = strategy.prop_map(move |fuzzed| {\n            assert_eq!(expected, fuzzed);\n        });\n    }\n}\n"
  },
  {
    "path": "crates/evm/fuzz/src/strategies/int.rs",
    "content": "use alloy_dyn_abi::{DynSolType, DynSolValue};\nuse alloy_primitives::{I256, Sign, U256};\nuse proptest::{\n    prelude::Rng,\n    strategy::{NewTree, Strategy, ValueTree},\n    test_runner::TestRunner,\n};\n\n/// Value tree for signed ints (up to int256).\npub struct IntValueTree {\n    /// Lower base (by absolute value)\n    lo: I256,\n    /// Current value\n    curr: I256,\n    /// Higher base (by absolute value)\n    hi: I256,\n    /// If true cannot be simplified or complexified\n    fixed: bool,\n}\n\nimpl IntValueTree {\n    /// Create a new tree\n    /// # Arguments\n    /// * `start` - Starting value for the tree\n    /// * `fixed` - If `true` the tree would only contain one element and won't be simplified.\n    fn new(start: I256, fixed: bool) -> Self {\n        Self { lo: I256::ZERO, curr: start, hi: start, fixed }\n    }\n\n    fn reposition(&mut self) -> bool {\n        let interval = self.hi - self.lo;\n        let new_mid = self.lo + interval / I256::from_raw(U256::from(2));\n\n        if new_mid == self.curr {\n            false\n        } else {\n            self.curr = new_mid;\n            true\n        }\n    }\n\n    fn magnitude_greater(lhs: I256, rhs: I256) -> bool {\n        if lhs.is_zero() {\n            return false;\n        }\n        (lhs > rhs) ^ (lhs.is_negative())\n    }\n}\n\nimpl ValueTree for IntValueTree {\n    type Value = I256;\n\n    fn current(&self) -> Self::Value {\n        self.curr\n    }\n\n    fn simplify(&mut self) -> bool {\n        if self.fixed || !Self::magnitude_greater(self.hi, self.lo) {\n            return false;\n        }\n        self.hi = self.curr;\n        self.reposition()\n    }\n\n    fn complicate(&mut self) -> bool {\n        if self.fixed || !Self::magnitude_greater(self.hi, self.lo) {\n            return false;\n        }\n\n        self.lo = if self.curr != I256::MIN && self.curr != I256::MAX {\n            self.curr + if self.hi.is_negative() { I256::MINUS_ONE } else { I256::ONE }\n        } else {\n            self.curr\n        };\n\n        self.reposition()\n    }\n}\n\n/// Value tree for signed ints (up to int256).\n/// The strategy combines 3 different strategies, each assigned a specific weight:\n/// 1. Generate purely random value in a range. This will first choose bit size uniformly (up `bits`\n///    param). Then generate a value for this bit size.\n/// 2. Generate a random value around the edges (+/- 3 around min, 0 and max possible value)\n/// 3. Generate a value from a predefined fixtures set\n///\n/// To define int fixtures:\n/// - return an array of possible values for a parameter named `amount` declare a function `function\n///   fixture_amount() public returns (int32[] memory)`.\n/// - use `amount` named parameter in fuzzed test in order to include fixtures in fuzzed values\n///   `function testFuzz_int32(int32 amount)`.\n///\n/// If fixture is not a valid int type then error is raised and random value generated.\n#[derive(Debug)]\npub struct IntStrategy {\n    /// Bit size of int (e.g. 256)\n    bits: usize,\n    /// A set of fixtures to be generated\n    fixtures: Vec<DynSolValue>,\n    /// The weight for edge cases (+/- 3 around 0 and max possible value)\n    edge_weight: usize,\n    /// The weight for fixtures\n    fixtures_weight: usize,\n    /// The weight for purely random values\n    random_weight: usize,\n}\n\nimpl IntStrategy {\n    /// Create a new strategy.\n    /// #Arguments\n    /// * `bits` - Size of uint in bits\n    /// * `fixtures` - A set of fixed values to be generated (according to fixtures weight)\n    pub fn new(bits: usize, fixtures: Option<&[DynSolValue]>) -> Self {\n        Self {\n            bits,\n            fixtures: Vec::from(fixtures.unwrap_or_default()),\n            edge_weight: 10usize,\n            fixtures_weight: 40usize,\n            random_weight: 50usize,\n        }\n    }\n\n    fn generate_edge_tree(&self, runner: &mut TestRunner) -> NewTree<Self> {\n        let rng = runner.rng();\n\n        let offset = I256::from_raw(U256::from(rng.random_range(0..4)));\n        let umax: U256 = (U256::from(1) << (self.bits - 1)) - U256::from(1);\n        // Choose if we want values around min, -0, +0, or max\n        let kind = rng.random_range(0..4);\n        let start = match kind {\n            0 => {\n                I256::overflowing_from_sign_and_abs(Sign::Negative, umax + U256::from(1)).0 + offset\n            }\n            1 => -offset - I256::ONE,\n            2 => offset,\n            3 => I256::overflowing_from_sign_and_abs(Sign::Positive, umax).0 - offset,\n            _ => unreachable!(),\n        };\n        Ok(IntValueTree::new(start, false))\n    }\n\n    fn generate_fixtures_tree(&self, runner: &mut TestRunner) -> NewTree<Self> {\n        // generate random cases if there's no fixtures\n        if self.fixtures.is_empty() {\n            return self.generate_random_tree(runner);\n        }\n\n        // Generate value tree from fixture.\n        let fixture = &self.fixtures[runner.rng().random_range(0..self.fixtures.len())];\n        if let Some(int_fixture) = fixture.as_int()\n            && int_fixture.1 == self.bits\n        {\n            return Ok(IntValueTree::new(int_fixture.0, false));\n        }\n\n        // If fixture is not a valid type, raise error and generate random value.\n        error!(\"{:?} is not a valid {} fixture\", fixture, DynSolType::Int(self.bits));\n        self.generate_random_tree(runner)\n    }\n\n    fn generate_random_tree(&self, runner: &mut TestRunner) -> NewTree<Self> {\n        let rng = runner.rng();\n\n        // generate random number of bits uniformly\n        let bits = rng.random_range(0..=self.bits);\n\n        if bits == 0 {\n            return Ok(IntValueTree::new(I256::ZERO, false));\n        }\n\n        // init 2 128-bit randoms\n        let mut higher: u128 = rng.random_range(0..=u128::MAX);\n        let mut lower: u128 = rng.random_range(0..=u128::MAX);\n\n        // cut 2 randoms according to bits size\n        match bits - 1 {\n            x if x < 128 => {\n                lower &= (1u128 << x) - 1;\n                higher = 0;\n            }\n            x if (128..256).contains(&x) => higher &= (1u128 << (x - 128)) - 1,\n            _ => {}\n        };\n\n        // init I256 from 2 randoms\n        let mut inner: [u64; 4] = [0; 4];\n        inner[0] = lower as u64;\n        inner[1] = (lower >> 64) as u64;\n        inner[2] = higher as u64;\n        inner[3] = (higher >> 64) as u64;\n\n        // we have a small bias here, i.e. intN::min will never be generated\n        // but it's ok since it's generated in `fn generate_edge_tree(...)`\n        let sign = if rng.random::<bool>() { Sign::Positive } else { Sign::Negative };\n        let (start, _) = I256::overflowing_from_sign_and_abs(sign, U256::from_limbs(inner));\n\n        Ok(IntValueTree::new(start, false))\n    }\n}\n\nimpl Strategy for IntStrategy {\n    type Tree = IntValueTree;\n    type Value = I256;\n\n    fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> {\n        let total_weight = self.random_weight + self.fixtures_weight + self.edge_weight;\n        let bias = runner.rng().random_range(0..total_weight);\n        // randomly select one of 3 strategies\n        match bias {\n            x if x < self.edge_weight => self.generate_edge_tree(runner),\n            x if x < self.edge_weight + self.fixtures_weight => self.generate_fixtures_tree(runner),\n            _ => self.generate_random_tree(runner),\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use crate::strategies::int::IntValueTree;\n    use alloy_primitives::I256;\n    use proptest::strategy::ValueTree;\n\n    #[test]\n    fn test_int_tree_complicate_should_not_overflow() {\n        let mut int_tree = IntValueTree::new(I256::MAX, false);\n        assert_eq!(int_tree.hi, I256::MAX);\n        assert_eq!(int_tree.curr, I256::MAX);\n        int_tree.complicate();\n        assert_eq!(int_tree.lo, I256::MAX);\n\n        let mut int_tree = IntValueTree::new(I256::MIN, false);\n        assert_eq!(int_tree.hi, I256::MIN);\n        assert_eq!(int_tree.curr, I256::MIN);\n        int_tree.complicate();\n        assert_eq!(int_tree.lo, I256::MIN);\n    }\n}\n"
  },
  {
    "path": "crates/evm/fuzz/src/strategies/invariants.rs",
    "content": "use super::{fuzz_calldata, fuzz_param_from_state};\nuse crate::{\n    BasicTxDetails, CallDetails, FuzzFixtures,\n    invariant::{FuzzRunIdentifiedContracts, SenderFilters},\n    strategies::{EvmFuzzState, fuzz_calldata_from_state, fuzz_param},\n};\nuse alloy_json_abi::Function;\nuse alloy_primitives::{Address, U256};\nuse foundry_config::InvariantConfig;\nuse parking_lot::RwLock;\nuse proptest::prelude::*;\nuse rand::seq::IteratorRandom;\nuse std::{rc::Rc, sync::Arc};\n\n/// Given a target address, we generate random calldata.\npub fn override_call_strat(\n    fuzz_state: EvmFuzzState,\n    contracts: FuzzRunIdentifiedContracts,\n    target: Arc<RwLock<Address>>,\n    fuzz_fixtures: FuzzFixtures,\n) -> impl Strategy<Value = CallDetails> + Send + Sync + 'static {\n    let contracts_ref = contracts.targets.clone();\n    proptest::prop_oneof![\n        80 => proptest::strategy::LazyJust::new(move || *target.read()),\n        20 => any::<prop::sample::Selector>()\n            .prop_map(move |selector| *selector.select(contracts_ref.lock().keys())),\n    ]\n    .prop_flat_map(move |target_address| {\n        let fuzz_state = fuzz_state.clone();\n        let fuzz_fixtures = fuzz_fixtures.clone();\n\n        let (actual_target, func) = {\n            let contracts = contracts.targets.lock();\n            // If the target address is in the contracts map, use it directly.\n            // Otherwise, fall back to a random contract from the targeted contracts.\n            // This can happen when call_override sets target_reference to a contract\n            // that is not in targetContracts (e.g., the protocol contract during reentrancy).\n            let (actual_target, contract) =\n                contracts.get(&target_address).map(|c| (target_address, c)).unwrap_or_else(|| {\n                    let entry = contracts\n                        .iter()\n                        .choose(&mut rand::rng())\n                        .expect(\"at least one target contract\");\n                    (*entry.0, entry.1)\n                });\n            let fuzzed_functions: Vec<_> = contract.abi_fuzzed_functions().cloned().collect();\n            (\n                actual_target,\n                any::<prop::sample::Index>()\n                    .prop_map(move |index| index.get(&fuzzed_functions).clone()),\n            )\n        };\n\n        func.prop_flat_map(move |func| {\n            fuzz_contract_with_calldata(&fuzz_state, &fuzz_fixtures, actual_target, func)\n        })\n    })\n}\n\n/// Creates the invariant strategy.\n///\n/// Given the known and future contracts, it generates the next call by fuzzing the `caller`,\n/// `calldata` and `target`. The generated data is evaluated lazily for every single call to fully\n/// leverage the evolving fuzz dictionary.\n///\n/// The fuzzed parameters can be filtered through different methods implemented in the test\n/// contract:\n///\n/// `targetContracts()`, `targetSenders()`, `excludeContracts()`, `targetSelectors()`\npub fn invariant_strat(\n    fuzz_state: EvmFuzzState,\n    senders: SenderFilters,\n    contracts: FuzzRunIdentifiedContracts,\n    config: InvariantConfig,\n    fuzz_fixtures: FuzzFixtures,\n) -> impl Strategy<Value = BasicTxDetails> {\n    let senders = Rc::new(senders);\n    let dictionary_weight = config.dictionary.dictionary_weight;\n\n    // Strategy to generate values for tx warp and roll.\n    let warp_roll_strat = |cond: bool| {\n        if cond { any::<U256>().prop_map(Some).boxed() } else { Just(None).boxed() }\n    };\n\n    any::<prop::sample::Selector>()\n        .prop_flat_map(move |selector| {\n            let contracts = contracts.targets.lock();\n            let functions = contracts.fuzzed_functions();\n            let (target_address, target_function) = selector.select(functions);\n\n            let sender = select_random_sender(&fuzz_state, senders.clone(), dictionary_weight);\n\n            let call_details = fuzz_contract_with_calldata(\n                &fuzz_state,\n                &fuzz_fixtures,\n                *target_address,\n                target_function.clone(),\n            );\n\n            let warp = warp_roll_strat(config.max_time_delay.is_some());\n            let roll = warp_roll_strat(config.max_block_delay.is_some());\n\n            (warp, roll, sender, call_details)\n        })\n        .prop_map(move |(warp, roll, sender, call_details)| {\n            let warp =\n                warp.map(|time| time % U256::from(config.max_time_delay.unwrap_or_default()));\n            let roll =\n                roll.map(|block| block % U256::from(config.max_block_delay.unwrap_or_default()));\n            BasicTxDetails { warp, roll, sender, call_details }\n        })\n}\n\n/// Strategy to select a sender address:\n/// * If `senders` is empty, then it's either a random address (10%) or from the dictionary (90%).\n/// * If `senders` is not empty, a random address is chosen from the list of senders.\nfn select_random_sender(\n    fuzz_state: &EvmFuzzState,\n    senders: Rc<SenderFilters>,\n    dictionary_weight: u32,\n) -> impl Strategy<Value = Address> + use<> {\n    if !senders.targeted.is_empty() {\n        any::<prop::sample::Index>().prop_map(move |index| *index.get(&senders.targeted)).boxed()\n    } else {\n        assert!(dictionary_weight <= 100, \"dictionary_weight must be <= 100\");\n        proptest::prop_oneof![\n            100 - dictionary_weight => fuzz_param(&alloy_dyn_abi::DynSolType::Address),\n            dictionary_weight => fuzz_param_from_state(&alloy_dyn_abi::DynSolType::Address, fuzz_state),\n        ]\n        .prop_map(move |addr| {\n            let mut addr = addr.as_address().unwrap();\n            // Make sure the selected address is not in the list of excluded senders.\n            // We don't use proptest's filter to avoid reaching the `PROPTEST_MAX_LOCAL_REJECTS`\n            // max rejects and exiting test before all runs completes.\n            // See <https://github.com/foundry-rs/foundry/issues/11369>.\n            loop {\n                if !senders.excluded.contains(&addr) {\n                    break;\n                }\n                addr = Address::random();\n            }\n            addr\n        })\n        .boxed()\n    }\n}\n\n/// Given a function, it returns a proptest strategy which generates valid abi-encoded calldata\n/// for that function's input types.\npub fn fuzz_contract_with_calldata(\n    fuzz_state: &EvmFuzzState,\n    fuzz_fixtures: &FuzzFixtures,\n    target: Address,\n    func: Function,\n) -> impl Strategy<Value = CallDetails> + use<> {\n    // We need to compose all the strategies generated for each parameter in all possible\n    // combinations.\n    // `prop_oneof!` / `TupleUnion` `Arc`s for cheap cloning.\n    prop_oneof![\n        60 => fuzz_calldata(func.clone(), fuzz_fixtures),\n        40 => fuzz_calldata_from_state(func, fuzz_state),\n    ]\n    .prop_map(move |calldata| {\n        trace!(input=?calldata);\n        CallDetails { target, calldata }\n    })\n}\n"
  },
  {
    "path": "crates/evm/fuzz/src/strategies/literals.rs",
    "content": "use alloy_dyn_abi::DynSolType;\nuse alloy_primitives::{\n    B256, Bytes, I256, U256, keccak256,\n    map::{B256IndexSet, HashMap, IndexSet},\n};\nuse foundry_common::Analysis;\nuse foundry_compilers::ProjectPathsConfig;\nuse solar::{\n    ast::{self, Visit},\n    interface::source_map::FileName,\n};\nuse std::{\n    ops::ControlFlow,\n    sync::{Arc, OnceLock},\n};\n\n#[derive(Clone, Debug)]\npub struct LiteralsDictionary {\n    maps: Arc<OnceLock<LiteralMaps>>,\n}\n\nimpl Default for LiteralsDictionary {\n    fn default() -> Self {\n        Self::new(None, None, usize::MAX)\n    }\n}\n\nimpl LiteralsDictionary {\n    pub fn new(\n        analysis: Option<Analysis>,\n        paths_config: Option<ProjectPathsConfig>,\n        max_values: usize,\n    ) -> Self {\n        let maps = Arc::new(OnceLock::<LiteralMaps>::new());\n        if let Some(analysis) = analysis\n            && max_values > 0\n        {\n            let maps = maps.clone();\n            // This can't be done in a rayon task (including inside of `get`) because it can cause a\n            // deadlock, since internally `solar` also uses rayon.\n            let _ = std::thread::Builder::new().name(\"literal-collector\".into()).spawn(move || {\n                let _ = maps.get_or_init(|| {\n                    let literals =\n                        LiteralsCollector::process(&analysis, paths_config.as_ref(), max_values);\n                    debug!(\n                        words = literals.words.values().map(|set| set.len()).sum::<usize>(),\n                        strings = literals.strings.len(),\n                        bytes = literals.bytes.len(),\n                        \"collected source code literals for fuzz dictionary\"\n                    );\n                    literals\n                });\n            });\n        } else {\n            maps.set(Default::default()).unwrap();\n        }\n        Self { maps }\n    }\n\n    /// Returns a reference to the `LiteralMaps`.\n    pub fn get(&self) -> &LiteralMaps {\n        self.maps.wait()\n    }\n\n    /// Test-only helper to seed the dictionary with literal values.\n    #[cfg(test)]\n    pub(crate) fn set(&mut self, map: super::LiteralMaps) {\n        self.maps = Arc::new(OnceLock::new());\n        self.maps.set(map).unwrap();\n    }\n}\n\n#[derive(Debug, Default)]\npub struct LiteralMaps {\n    pub words: HashMap<DynSolType, B256IndexSet>,\n    pub strings: IndexSet<String>,\n    pub bytes: IndexSet<Bytes>,\n}\n\n#[derive(Debug, Default)]\npub struct LiteralsCollector {\n    max_values: usize,\n    total_values: usize,\n    output: LiteralMaps,\n}\n\nimpl LiteralsCollector {\n    fn new(max_values: usize) -> Self {\n        Self { max_values, ..Default::default() }\n    }\n\n    pub fn process(\n        analysis: &Analysis,\n        paths_config: Option<&ProjectPathsConfig>,\n        max_values: usize,\n    ) -> LiteralMaps {\n        analysis.enter(|compiler| {\n            let mut literals_collector = Self::new(max_values);\n            for source in compiler.sources().iter() {\n                // Ignore scripts, and libs\n                if let Some(paths) = paths_config\n                    && let FileName::Real(source_path) = &source.file.name\n                    && !(source_path.starts_with(&paths.sources) || paths.is_test(source_path))\n                {\n                    continue;\n                }\n\n                if let Some(ast) = &source.ast\n                    && literals_collector.visit_source_unit(ast).is_break()\n                {\n                    break;\n                }\n            }\n\n            literals_collector.output\n        })\n    }\n}\n\nimpl<'ast> ast::Visit<'ast> for LiteralsCollector {\n    type BreakValue = ();\n\n    fn visit_expr(&mut self, expr: &'ast ast::Expr<'ast>) -> ControlFlow<()> {\n        // Stop early if we've hit the limit\n        if self.total_values >= self.max_values {\n            return ControlFlow::Break(());\n        }\n\n        // Handle unary negation of number literals\n        if let ast::ExprKind::Unary(un_op, inner_expr) = &expr.kind\n            && un_op.kind == ast::UnOpKind::Neg\n            && let ast::ExprKind::Lit(lit, _) = &inner_expr.kind\n            && let ast::LitKind::Number(n) = &lit.kind\n        {\n            // Compute the negative I256 value\n            if let Ok(pos_i256) = I256::try_from(*n) {\n                let neg_value = -pos_i256;\n                let neg_b256 = B256::from(neg_value.into_raw());\n\n                // Store under all intN sizes that can represent this value\n                for bits in [16, 32, 64, 128, 256] {\n                    if can_fit_int(neg_value, bits)\n                        && self\n                            .output\n                            .words\n                            .entry(DynSolType::Int(bits))\n                            .or_default()\n                            .insert(neg_b256)\n                    {\n                        self.total_values += 1;\n                    }\n                }\n            }\n\n            // Continue walking the expression\n            return self.walk_expr(expr);\n        }\n\n        // Handle literals\n        if let ast::ExprKind::Lit(lit, _) = &expr.kind {\n            let is_new = match &lit.kind {\n                ast::LitKind::Number(n) => {\n                    let pos_value = U256::from(*n);\n                    let pos_b256 = B256::from(pos_value);\n\n                    // Store under all uintN sizes that can represent this value\n                    for bits in [8, 16, 32, 64, 128, 256] {\n                        if can_fit_uint(pos_value, bits)\n                            && self\n                                .output\n                                .words\n                                .entry(DynSolType::Uint(bits))\n                                .or_default()\n                                .insert(pos_b256)\n                        {\n                            self.total_values += 1;\n                        }\n                    }\n                    false // already handled inserts individually\n                }\n                ast::LitKind::Address(addr) => self\n                    .output\n                    .words\n                    .entry(DynSolType::Address)\n                    .or_default()\n                    .insert(addr.into_word()),\n                ast::LitKind::Str(ast::StrKind::Hex, sym, _) => {\n                    self.output.bytes.insert(Bytes::copy_from_slice(sym.as_byte_str()))\n                }\n                ast::LitKind::Str(_, sym, _) => {\n                    let s = String::from_utf8_lossy(sym.as_byte_str()).into_owned();\n                    // For strings, also store the hashed version\n                    let hash = keccak256(s.as_bytes());\n                    if self.output.words.entry(DynSolType::FixedBytes(32)).or_default().insert(hash)\n                    {\n                        self.total_values += 1;\n                    }\n                    // And the right-padded version if it fits.\n                    if s.len() <= 32 {\n                        let padded = B256::right_padding_from(s.as_bytes());\n                        if self\n                            .output\n                            .words\n                            .entry(DynSolType::FixedBytes(32))\n                            .or_default()\n                            .insert(padded)\n                        {\n                            self.total_values += 1;\n                        }\n                    }\n                    self.output.strings.insert(s)\n                }\n                ast::LitKind::Bool(..) | ast::LitKind::Rational(..) | ast::LitKind::Err(..) => {\n                    false // ignore\n                }\n            };\n\n            if is_new {\n                self.total_values += 1;\n            }\n        }\n\n        self.walk_expr(expr)\n    }\n}\n\n/// Checks if a signed integer value can fit in intN type.\nfn can_fit_int(value: I256, bits: usize) -> bool {\n    // Calculate the maximum positive value for intN: 2^(N-1) - 1\n    let max_val = I256::try_from((U256::from(1) << (bits - 1)) - U256::from(1))\n        .expect(\"max value should fit in I256\");\n    // Calculate the minimum negative value for intN: -2^(N-1)\n    let min_val = -max_val - I256::ONE;\n\n    value >= min_val && value <= max_val\n}\n\n/// Checks if an unsigned integer value can fit in uintN type.\nfn can_fit_uint(value: U256, bits: usize) -> bool {\n    if bits == 256 {\n        return true;\n    }\n    // Calculate the maximum value for uintN: 2^N - 1\n    let max_val = (U256::from(1) << bits) - U256::from(1);\n    value <= max_val\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use alloy_primitives::address;\n    use solar::interface::{Session, source_map};\n\n    const SOURCE: &str = r#\"\n    contract Magic {\n        // plain literals\n        address constant DAI = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\n        uint64 constant MAGIC_NUMBER = 1122334455;\n        int32 constant MAGIC_INT = -777;\n        bytes32 constant MAGIC_WORD = \"abcd1234\";\n        bytes constant MAGIC_BYTES = hex\"deadbeef\";\n        string constant MAGIC_STRING = \"xyzzy\";\n\n        // constant exprs with folding\n        uint256 constant NEG_FOLDING = uint(-2);\n        uint256 constant BIN_FOLDING = 2 * 2 ether;\n        bytes32 constant IMPLEMENTATION_SLOT = bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1);\n    }\"#;\n\n    #[test]\n    fn test_literals_collector_coverage() {\n        let map = process_source_literals(SOURCE);\n\n        // Expected values from the SOURCE contract\n        let addr = address!(\"0x6B175474E89094C44Da98b954EedeAC495271d0F\").into_word();\n        let num = B256::from(U256::from(1122334455u64));\n        let int = B256::from(I256::try_from(-777i32).unwrap().into_raw());\n        let word = B256::right_padding_from(b\"abcd1234\");\n        let dyn_bytes = Bytes::from_static(&[0xde, 0xad, 0xbe, 0xef]);\n\n        assert_word(&map, DynSolType::Address, addr, \"Expected DAI in address set\");\n        assert_word(&map, DynSolType::Uint(64), num, \"Expected MAGIC_NUMBER in uint64 set\");\n        assert_word(&map, DynSolType::Int(32), int, \"Expected MAGIC_INT in int32 set\");\n        assert_word(&map, DynSolType::FixedBytes(32), word, \"Expected MAGIC_WORD in bytes32 set\");\n        assert!(map.strings.contains(\"xyzzy\"), \"Expected MAGIC_STRING to be collected\");\n        assert!(\n            map.strings.contains(\"eip1967.proxy.implementation\"),\n            \"Expected IMPLEMENTATION_SLOT in string set\"\n        );\n        assert!(map.bytes.contains(&dyn_bytes), \"Expected MAGIC_BYTES in bytes set\");\n    }\n\n    #[test]\n    fn test_literals_collector_size() {\n        let literals = process_source_literals(SOURCE);\n\n        // Helper to get count for a type, returns 0 if not present\n        let count = |ty: DynSolType| literals.words.get(&ty).map_or(0, |set| set.len());\n\n        assert_eq!(count(DynSolType::Address), 1, \"Address literal count mismatch\");\n        assert_eq!(literals.strings.len(), 3, \"String literals count mismatch\");\n        assert_eq!(literals.bytes.len(), 1, \"Byte literals count mismatch\");\n\n        // Unsigned integers - MAGIC_NUMBER (1122334455) appears in multiple sizes\n        assert_eq!(count(DynSolType::Uint(8)), 2, \"Uint(8) count mismatch\");\n        assert_eq!(count(DynSolType::Uint(16)), 3, \"Uint(16) count mismatch\");\n        assert_eq!(count(DynSolType::Uint(32)), 4, \"Uint(32) count mismatch\");\n        assert_eq!(count(DynSolType::Uint(64)), 5, \"Uint(64) count mismatch\");\n        assert_eq!(count(DynSolType::Uint(128)), 5, \"Uint(128) count mismatch\");\n        assert_eq!(count(DynSolType::Uint(256)), 5, \"Uint(256) count mismatch\");\n\n        // Signed integers - MAGIC_INT (-777) appears in multiple sizes\n        assert_eq!(count(DynSolType::Int(16)), 2, \"Int(16) count mismatch\");\n        assert_eq!(count(DynSolType::Int(32)), 2, \"Int(32) count mismatch\");\n        assert_eq!(count(DynSolType::Int(64)), 2, \"Int(64) count mismatch\");\n        assert_eq!(count(DynSolType::Int(128)), 2, \"Int(128) count mismatch\");\n        assert_eq!(count(DynSolType::Int(256)), 2, \"Int(256) count mismatch\");\n\n        // FixedBytes(32) includes:\n        // - MAGIC_WORD\n        // - String literals (hashed and right-padded versions)\n        assert_eq!(count(DynSolType::FixedBytes(32)), 6, \"FixedBytes(32) count mismatch\");\n\n        // Total count check\n        assert_eq!(\n            literals.words.values().map(|set| set.len()).sum::<usize>(),\n            41,\n            \"Total word values count mismatch\"\n        );\n    }\n\n    // -- TEST HELPERS ---------------------------------------------------------\n\n    fn process_source_literals(source: &str) -> LiteralMaps {\n        let mut compiler =\n            solar::sema::Compiler::new(Session::builder().with_stderr_emitter().build());\n        compiler\n            .enter_mut(|c| -> std::io::Result<()> {\n                let mut pcx = c.parse();\n                pcx.set_resolve_imports(false);\n\n                pcx.add_file(\n                    c.sess().source_map().new_source_file(source_map::FileName::Stdin, source)?,\n                );\n                pcx.parse();\n                let _ = c.lower_asts();\n                Ok(())\n            })\n            .expect(\"Failed to compile test source\");\n\n        LiteralsCollector::process(&std::sync::Arc::new(compiler), None, usize::MAX)\n    }\n\n    fn assert_word(literals: &LiteralMaps, ty: DynSolType, value: B256, msg: &str) {\n        assert!(literals.words.get(&ty).is_some_and(|set| set.contains(&value)), \"{}\", msg);\n    }\n}\n"
  },
  {
    "path": "crates/evm/fuzz/src/strategies/mod.rs",
    "content": "mod int;\npub use int::IntStrategy;\n\nmod uint;\npub use uint::UintStrategy;\n\nmod param;\npub use param::{\n    fuzz_param, fuzz_param_from_state, fuzz_param_with_fixtures, mutate_param_value,\n    mutate_param_value_with_senders,\n};\n\nmod calldata;\npub use calldata::{fuzz_calldata, fuzz_calldata_from_state};\n\nmod state;\npub use state::EvmFuzzState;\n\nmod invariants;\npub use invariants::{fuzz_contract_with_calldata, invariant_strat, override_call_strat};\n\nmod mutators;\npub use mutators::BoundMutator;\n\nmod literals;\npub use literals::{LiteralMaps, LiteralsCollector, LiteralsDictionary};\n"
  },
  {
    "path": "crates/evm/fuzz/src/strategies/mutators.rs",
    "content": "use alloy_dyn_abi::Word;\nuse alloy_primitives::{Address, I256, Sign, U256};\nuse proptest::{prelude::*, test_runner::TestRunner};\nuse rand::seq::IndexedRandom;\nuse std::fmt::Debug;\n\n// Interesting 8-bit values to inject.\nstatic INTERESTING_8: &[i8] = &[-128, -1, 0, 1, 16, 32, 64, 100, 127];\n\n/// Interesting 16-bit values to inject.\nstatic INTERESTING_16: &[i16] = &[\n    -128, -1, 0, 1, 16, 32, 64, 100, 127, -32768, -129, 128, 255, 256, 512, 1000, 1024, 4096, 32767,\n];\n\n/// Interesting 32-bit values to inject.\nstatic INTERESTING_32: &[i32] = &[\n    -128,\n    -1,\n    0,\n    1,\n    16,\n    32,\n    64,\n    100,\n    127,\n    -32768,\n    -129,\n    128,\n    255,\n    256,\n    512,\n    1000,\n    1024,\n    4096,\n    32767,\n    -2147483648,\n    -100663046,\n    -32769,\n    32768,\n    65535,\n    65536,\n    100663045,\n    2147483647,\n];\n\n/// Multipliers used to define the 3 standard deviation range of a Gaussian-like curve.\n/// For example, a multiplier of 0.25 means the +/-3 standard deviation bounds are +/-25% of the\n/// original value.\nstatic THREE_SIGMA_MULTIPLIERS: &[f64] = &[0.1, 0.25, 0.5, 1.0, 2.0, 5.0, 10.0];\n\n/// Mutator that randomly increments or decrements an uint or int.\npub(crate) trait IncrementDecrementMutator: Sized + Copy + Debug {\n    fn validate(old: Self, new: Self, size: usize) -> Option<Self>;\n\n    #[instrument(\n        name = \"mutator::increment_decrement\",\n        level = \"trace\",\n        skip(size, test_runner),\n        ret\n    )]\n    fn increment_decrement(self, size: usize, test_runner: &mut TestRunner) -> Option<Self> {\n        let mutated = if test_runner.rng().random::<bool>() {\n            self.wrapping_add(Self::ONE)\n        } else {\n            self.wrapping_sub(Self::ONE)\n        };\n        Self::validate(self, mutated, size)\n    }\n\n    fn wrapping_add(self, rhs: Self) -> Self;\n    fn wrapping_sub(self, rhs: Self) -> Self;\n    const ONE: Self;\n}\n\nmacro_rules! impl_increment_decrement_mutator {\n    ($ty:ty, $validate_fn:path) => {\n        impl IncrementDecrementMutator for $ty {\n            fn validate(old: Self, new: Self, size: usize) -> Option<Self> {\n                $validate_fn(old, new, size)\n            }\n\n            fn wrapping_add(self, rhs: Self) -> Self {\n                Self::wrapping_add(self, rhs)\n            }\n\n            fn wrapping_sub(self, rhs: Self) -> Self {\n                Self::wrapping_sub(self, rhs)\n            }\n\n            const ONE: Self = Self::ONE;\n        }\n    };\n}\n\nimpl_increment_decrement_mutator!(U256, validate_uint_mutation);\nimpl_increment_decrement_mutator!(I256, validate_int_mutation);\n\n/// Mutator that changes the current value of an uint or int by applying gaussian noise.\npub(crate) trait GaussianNoiseMutator: Sized + Copy + Debug {\n    fn mutate_with_gaussian_noise(self, size: usize, test_runner: &mut TestRunner) -> Option<Self>;\n}\n\nimpl GaussianNoiseMutator for U256 {\n    #[instrument(\n        name = \"U256::mutate_with_gaussian_noise\",\n        level = \"trace\",\n        skip(size, test_runner),\n        ret\n    )]\n    fn mutate_with_gaussian_noise(self, size: usize, test_runner: &mut TestRunner) -> Option<Self> {\n        let scale_factor = sample_gaussian_scale(&mut test_runner.rng())?;\n        let mut bytes: [u8; 32] = self.to_be_bytes();\n        apply_scale_to_bytes(&mut bytes[32 - size / 8..], scale_factor)?;\n        validate_uint_mutation(self, Self::from_be_bytes(bytes), size)\n    }\n}\n\nimpl GaussianNoiseMutator for I256 {\n    #[instrument(\n        name = \"I256::mutate_with_gaussian_noise\",\n        level = \"trace\",\n        skip(size, test_runner),\n        ret\n    )]\n    fn mutate_with_gaussian_noise(self, size: usize, test_runner: &mut TestRunner) -> Option<Self> {\n        let scale_factor = sample_gaussian_scale(&mut test_runner.rng())?;\n        let mut bytes: [u8; 32] = self.to_be_bytes();\n        apply_scale_to_bytes(&mut bytes[32 - size / 8..], scale_factor)?;\n        validate_int_mutation(self, Self::from_be_bytes(bytes), size)\n    }\n}\n\n/// Mutator that bounds the current value of an uint or int in the given range.\n/// The mutated value is always different from the current value.\npub trait BoundMutator: Sized + Copy + Debug {\n    fn bound(self, min: Self, max: Self, test_runner: &mut TestRunner) -> Option<Self>;\n}\n\nimpl BoundMutator for U256 {\n    #[instrument(name = \"U256::bound\", level = \"trace\", skip(test_runner), ret)]\n    fn bound(self, min: Self, max: Self, test_runner: &mut TestRunner) -> Option<Self> {\n        if min > max || self < min || self > max || min == max {\n            return None;\n        }\n\n        let rng = test_runner.rng();\n\n        loop {\n            let bits = rng.random_range(8..=256);\n            let mask = (Self::ONE << bits) - Self::ONE;\n            let candidate = Self::from(rng.random::<u128>()) & mask;\n\n            // Map to range.\n            let candidate = min + (candidate % ((max - min).saturating_add(Self::ONE)));\n\n            if candidate != self {\n                return Some(candidate);\n            }\n        }\n    }\n}\n\nimpl BoundMutator for I256 {\n    #[instrument(name = \"I256::bound\", level = \"trace\", skip(test_runner), ret)]\n    fn bound(self, min: Self, max: Self, test_runner: &mut TestRunner) -> Option<Self> {\n        if min > max || self < min || self > max || min == max {\n            return None;\n        }\n\n        let rng = test_runner.rng();\n\n        loop {\n            let bits = rng.random_range(8..=255);\n            let mask = (U256::ONE << bits) - U256::ONE;\n            let rand_u = U256::from(rng.next_u64()) | (U256::from(rng.next_u64()) << 64);\n            let unsigned_candidate = rand_u & mask;\n\n            let signed_candidate = {\n                let midpoint = U256::ONE << (bits - 1);\n                if unsigned_candidate < midpoint {\n                    Self::from_raw(unsigned_candidate)\n                } else {\n                    Self::from_raw(unsigned_candidate) - Self::from_raw(U256::ONE << bits)\n                }\n            };\n\n            // Map to range.\n            let range = max.saturating_sub(min).saturating_add(Self::ONE).unsigned_abs();\n            let wrapped = Self::from_raw(U256::from(signed_candidate.unsigned_abs()) % range);\n            let candidate =\n                if signed_candidate.is_negative() { max - wrapped } else { min + wrapped };\n\n            if candidate != self {\n                return Some(candidate);\n            }\n        }\n    }\n}\n\n/// Mutator that changes the current value by flipping a random bit.\npub(crate) trait BitMutator: Sized + Copy + Debug {\n    fn flip_random_bit(self, size: usize, test_runner: &mut TestRunner) -> Option<Self>;\n}\n\nimpl BitMutator for U256 {\n    #[instrument(name = \"U256::flip_random_bit\", level = \"trace\", skip(size, test_runner), ret)]\n    fn flip_random_bit(self, size: usize, test_runner: &mut TestRunner) -> Option<Self> {\n        let mut bytes: [u8; 32] = self.to_be_bytes();\n        flip_random_bit_in_slice(&mut bytes[32 - size / 8..], test_runner)?;\n        validate_uint_mutation(self, Self::from_be_bytes(bytes), size)\n    }\n}\n\nimpl BitMutator for I256 {\n    #[instrument(name = \"I256::flip_random_bit\", level = \"trace\", skip(size, test_runner), ret)]\n    fn flip_random_bit(self, size: usize, test_runner: &mut TestRunner) -> Option<Self> {\n        let mut bytes: [u8; 32] = self.to_be_bytes();\n        flip_random_bit_in_slice(&mut bytes[32 - size / 8..], test_runner)?;\n        validate_int_mutation(self, Self::from_be_bytes(bytes), size)\n    }\n}\n\nimpl BitMutator for Address {\n    #[instrument(name = \"Address::flip_random_bit\", level = \"trace\", skip(_size, test_runner), ret)]\n    fn flip_random_bit(self, _size: usize, test_runner: &mut TestRunner) -> Option<Self> {\n        let mut mutated = self;\n        flip_random_bit_in_slice(mutated.as_mut_slice(), test_runner)?;\n        (self != mutated).then_some(mutated)\n    }\n}\n\nimpl BitMutator for Word {\n    #[instrument(name = \"Word::flip_random_bit\", level = \"trace\", skip(size, test_runner), ret)]\n    fn flip_random_bit(self, size: usize, test_runner: &mut TestRunner) -> Option<Self> {\n        let mut bytes = self;\n        let slice = &mut bytes[..size];\n        flip_random_bit_in_slice(slice, test_runner)?;\n        (self != bytes).then_some(bytes)\n    }\n}\n\n/// Mutator that changes the current value by randomly injecting interesting words (for uint, int,\n/// address and fixed bytes) - see <https://github.com/AFLplusplus/LibAFL/blob/90cb9a2919faf386e0678870e52784070cdac4b6/crates/libafl/src/mutators/mutations.rs#L88-L123>.\npub(crate) trait InterestingWordMutator: Sized + Copy + Debug {\n    fn mutate_interesting_byte(self, size: usize, test_runner: &mut TestRunner) -> Option<Self>;\n    fn mutate_interesting_word(self, size: usize, test_runner: &mut TestRunner) -> Option<Self>;\n    fn mutate_interesting_dword(self, size: usize, test_runner: &mut TestRunner) -> Option<Self>;\n}\n\nimpl InterestingWordMutator for U256 {\n    #[instrument(\n        name = \"U256::mutate_interesting_byte\",\n        level = \"trace\",\n        skip(size, test_runner),\n        ret\n    )]\n    fn mutate_interesting_byte(self, size: usize, test_runner: &mut TestRunner) -> Option<Self> {\n        let mut bytes: [u8; 32] = self.to_be_bytes();\n        mutate_interesting_byte_slice(&mut bytes[32 - size / 8..], test_runner)?;\n        validate_uint_mutation(self, Self::from_be_bytes(bytes), size)\n    }\n\n    #[instrument(\n        name = \"U256::mutate_interesting_word\",\n        level = \"trace\",\n        skip(size, test_runner),\n        ret\n    )]\n    fn mutate_interesting_word(self, size: usize, test_runner: &mut TestRunner) -> Option<Self> {\n        let mut bytes: [u8; 32] = self.to_be_bytes();\n        mutate_interesting_word_slice(&mut bytes[32 - size / 8..], test_runner)?;\n        validate_uint_mutation(self, Self::from_be_bytes(bytes), size)\n    }\n\n    #[instrument(\n        name = \"U256::mutate_interesting_dword\",\n        level = \"trace\",\n        skip(size, test_runner),\n        ret\n    )]\n    fn mutate_interesting_dword(self, size: usize, test_runner: &mut TestRunner) -> Option<Self> {\n        let mut bytes: [u8; 32] = self.to_be_bytes();\n        mutate_interesting_dword_slice(&mut bytes[32 - size / 8..], test_runner)?;\n        validate_uint_mutation(self, Self::from_be_bytes(bytes), size)\n    }\n}\n\nimpl InterestingWordMutator for I256 {\n    #[instrument(\n        name = \"I256::mutate_interesting_byte\",\n        level = \"trace\",\n        skip(size, test_runner),\n        ret\n    )]\n    fn mutate_interesting_byte(self, size: usize, test_runner: &mut TestRunner) -> Option<Self> {\n        let mut bytes: [u8; 32] = self.to_be_bytes();\n        mutate_interesting_byte_slice(&mut bytes[32 - size / 8..], test_runner)?;\n        validate_int_mutation(self, Self::from_be_bytes(bytes), size)\n    }\n\n    #[instrument(\n        name = \"I256::mutate_interesting_word\",\n        level = \"trace\",\n        skip(size, test_runner),\n        ret\n    )]\n    fn mutate_interesting_word(self, size: usize, test_runner: &mut TestRunner) -> Option<Self> {\n        let mut bytes: [u8; 32] = self.to_be_bytes();\n        mutate_interesting_word_slice(&mut bytes[32 - size / 8..], test_runner)?;\n        validate_int_mutation(self, Self::from_be_bytes(bytes), size)\n    }\n\n    #[instrument(\n        name = \"I256::mutate_interesting_dword\",\n        level = \"trace\",\n        skip(size, test_runner),\n        ret\n    )]\n    fn mutate_interesting_dword(self, size: usize, test_runner: &mut TestRunner) -> Option<Self> {\n        let mut bytes: [u8; 32] = self.to_be_bytes();\n        mutate_interesting_dword_slice(&mut bytes[32 - size / 8..], test_runner)?;\n        validate_int_mutation(self, Self::from_be_bytes(bytes), size)\n    }\n}\n\nimpl InterestingWordMutator for Address {\n    #[instrument(\n        name = \"Address::mutate_interesting_byte\",\n        level = \"trace\",\n        skip(_size, test_runner),\n        ret\n    )]\n    fn mutate_interesting_byte(self, _size: usize, test_runner: &mut TestRunner) -> Option<Self> {\n        let mut mutated = self;\n        mutate_interesting_byte_slice(mutated.as_mut_slice(), test_runner)?;\n        (self != mutated).then_some(mutated)\n    }\n\n    #[instrument(\n        name = \"Address::mutate_interesting_word\",\n        level = \"trace\",\n        skip(_size, test_runner),\n        ret\n    )]\n    fn mutate_interesting_word(self, _size: usize, test_runner: &mut TestRunner) -> Option<Self> {\n        let mut mutated = self;\n        mutate_interesting_word_slice(mutated.as_mut_slice(), test_runner)?;\n        (self != mutated).then_some(mutated)\n    }\n\n    #[instrument(\n        name = \"Address::mutate_interesting_dword\",\n        level = \"trace\",\n        skip(_size, test_runner),\n        ret\n    )]\n    fn mutate_interesting_dword(self, _size: usize, test_runner: &mut TestRunner) -> Option<Self> {\n        let mut mutated = self;\n        mutate_interesting_dword_slice(mutated.as_mut_slice(), test_runner)?;\n        (self != mutated).then_some(mutated)\n    }\n}\n\nimpl InterestingWordMutator for Word {\n    #[instrument(\n        name = \"Word::mutate_interesting_byte\",\n        level = \"trace\",\n        skip(size, test_runner),\n        ret\n    )]\n    fn mutate_interesting_byte(self, size: usize, test_runner: &mut TestRunner) -> Option<Self> {\n        let mut bytes = self;\n        let slice = &mut bytes[..size];\n        mutate_interesting_byte_slice(slice, test_runner)?;\n        (self != bytes).then_some(bytes)\n    }\n\n    #[instrument(\n        name = \"Word::mutate_interesting_word\",\n        level = \"trace\",\n        skip(size, test_runner),\n        ret\n    )]\n    fn mutate_interesting_word(self, size: usize, test_runner: &mut TestRunner) -> Option<Self> {\n        let mut bytes = self;\n        let slice = &mut bytes[..size];\n        mutate_interesting_word_slice(slice, test_runner)?;\n        (self != bytes).then_some(bytes)\n    }\n\n    #[instrument(\n        name = \"Word::mutate_interesting_dword\",\n        level = \"trace\",\n        skip(size, test_runner),\n        ret\n    )]\n    fn mutate_interesting_dword(self, size: usize, test_runner: &mut TestRunner) -> Option<Self> {\n        let mut bytes = self;\n        let slice = &mut bytes[..size];\n        mutate_interesting_dword_slice(slice, test_runner)?;\n        (self != bytes).then_some(bytes)\n    }\n}\n\n/// Flips a random bit in the given mutable byte slice.\nfn flip_random_bit_in_slice(bytes: &mut [u8], test_runner: &mut TestRunner) -> Option<()> {\n    if bytes.is_empty() {\n        return None;\n    }\n    let bit_index = test_runner.rng().random_range(0..(bytes.len() * 8));\n    bytes[bit_index / 8] ^= 1 << (bit_index % 8);\n    Some(())\n}\n\n/// Mutates a random byte in the given byte slice by replacing it with a randomly chosen\n/// interesting 8-bit value.\nfn mutate_interesting_byte_slice(bytes: &mut [u8], test_runner: &mut TestRunner) -> Option<()> {\n    let index = test_runner.rng().random_range(0..bytes.len());\n    let val = *INTERESTING_8.choose(&mut test_runner.rng())? as u8;\n    bytes[index] = val;\n    Some(())\n}\n\n/// Mutates a random 2-byte (16-bit) region in the byte slice with a randomly chosen interesting\n/// 16-bit value.\nfn mutate_interesting_word_slice(bytes: &mut [u8], test_runner: &mut TestRunner) -> Option<()> {\n    if bytes.len() < 2 {\n        return None;\n    }\n    let index = test_runner.rng().random_range(0..=bytes.len() - 2);\n    let val = *INTERESTING_16.choose(&mut test_runner.rng())? as u16;\n    bytes[index..index + 2].copy_from_slice(&val.to_be_bytes());\n    Some(())\n}\n\n/// Mutates a random 4-byte (32-bit) region in the byte slice with a randomly chosen interesting\n/// 32-bit value.\nfn mutate_interesting_dword_slice(bytes: &mut [u8], test_runner: &mut TestRunner) -> Option<()> {\n    if bytes.len() < 4 {\n        return None;\n    }\n    let index = test_runner.rng().random_range(0..=bytes.len() - 4);\n    let val = *INTERESTING_32.choose(&mut test_runner.rng())? as u32;\n    bytes[index..index + 4].copy_from_slice(&val.to_be_bytes());\n    Some(())\n}\n\n/// Samples a scale factor from a pseudo-Gaussian distribution centered around 1.0.\n///\n/// - Select a random standard deviation multiplier from a predefined set.\n/// - Approximates a standard normal distribution using the Irwin-Hall method (sum of uniform\n///   samples).\n/// - Scales the normal value by the chosen standard deviation multiplier, divided by 3 to get\n///   standard deviation.\n/// - Adds 1.0 to center the scale factor around 1.0 (no mutation).\n///\n/// Returns a scale factor that, when applied to a number, mimics Gaussian noise.\nfn sample_gaussian_scale<R: Rng>(rng: &mut R) -> Option<f64> {\n    let num_samples = 8;\n    let chosen_3rd_sigma = *THREE_SIGMA_MULTIPLIERS.choose(rng).unwrap_or(&1.0);\n\n    let mut sum = 0.0;\n    for _ in 0..num_samples {\n        sum += rng.random::<f64>();\n    }\n\n    let standard_normal = sum - (num_samples as f64 / 2.0);\n    let mut scale_factor = (chosen_3rd_sigma / 3.0) * standard_normal;\n    scale_factor += 1.0;\n\n    if scale_factor < 0.0 || (scale_factor - 1.0).abs() < f64::EPSILON {\n        None\n    } else {\n        Some(scale_factor)\n    }\n}\n\n/// Applies a floating-point scale factor to a byte slice representing an unsigned or signed\n/// integer.\nfn apply_scale_to_bytes(bytes: &mut [u8], scale_factor: f64) -> Option<()> {\n    let mut carry_down = 0.0;\n\n    for i in (0..bytes.len()).rev() {\n        let byte_val = bytes[i] as f64;\n        let scaled = (byte_val + carry_down * 256.0) * scale_factor;\n\n        if i == 0 && scaled >= 256.0 {\n            bytes.iter_mut().for_each(|b| *b = 0xFF);\n            return Some(());\n        }\n\n        bytes[i] = (scaled % 256.0).floor() as u8;\n\n        let mut carry_up = (scaled / 256.0).floor();\n        carry_down = (scaled % 1.0) / scale_factor;\n\n        let mut j = i;\n        // Propagate carry_up until it is zero or no more bytes left\n        while carry_up > 0.0 && j > 0 {\n            j -= 1;\n            let new_val = bytes[j] as f64 + carry_up;\n            if j == 0 && new_val >= 256.0 {\n                bytes.iter_mut().for_each(|b| *b = 0xFF);\n                return Some(());\n            }\n            bytes[j] = (new_val % 256.0).floor() as u8;\n            carry_up = (new_val / 256.0).floor();\n        }\n    }\n\n    Some(())\n}\n\n/// Returns mutated uint value if different from the original value and if it fits in the given\n/// size, otherwise None.\nfn validate_uint_mutation(original: U256, mutated: U256, size: usize) -> Option<U256> {\n    // Early return if mutated value is the same as original value.\n    if mutated == original {\n        return None;\n    }\n\n    // Check if mutated value fits the given size.\n    let max = if size < 256 { (U256::from(1) << size) - U256::from(1) } else { U256::MAX };\n    (mutated < max).then_some(mutated)\n}\n\n/// Returns mutated int value if different from the original value and if it fits in the given size,\n/// otherwise None.\nfn validate_int_mutation(original: I256, mutated: I256, size: usize) -> Option<I256> {\n    // Early return if mutated value is the same as original value.\n    if mutated == original {\n        return None;\n    }\n\n    // Check if mutated value fits the given size.\n    let max_abs = (U256::from(1) << (size - 1)) - U256::from(1);\n    match mutated.sign() {\n        Sign::Positive => mutated < I256::overflowing_from_sign_and_abs(Sign::Positive, max_abs).0,\n        Sign::Negative => mutated > I256::overflowing_from_sign_and_abs(Sign::Negative, max_abs).0,\n    }\n    .then_some(mutated)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use proptest::test_runner::Config;\n\n    #[test]\n    fn test_mutate_uint() {\n        let mut runner = TestRunner::new(Config::default());\n        let size = 32;\n\n        let test_values =\n            vec![U256::ZERO, U256::ONE, U256::from(12345u64), U256::from(255), U256::MAX];\n\n        #[track_caller]\n        fn validate_mutation(value: U256, mutated: Option<U256>) {\n            assert!(\n                mutated.is_none() || mutated.is_some_and(|m| m != value),\n                \"Mutation failed: value = {value:?}, mutated = {mutated:?}\"\n            );\n        }\n\n        for value in test_values {\n            for _ in 0..100 {\n                validate_mutation(value, U256::increment_decrement(value, size, &mut runner));\n                validate_mutation(value, U256::flip_random_bit(value, size, &mut runner));\n                validate_mutation(value, U256::mutate_interesting_byte(value, size, &mut runner));\n                validate_mutation(value, U256::mutate_interesting_word(value, size, &mut runner));\n                validate_mutation(value, U256::mutate_interesting_dword(value, size, &mut runner));\n            }\n        }\n    }\n\n    #[test]\n    fn test_mutate_int() {\n        let mut runner = TestRunner::new(Config::default());\n        let size = 32;\n\n        let test_values = vec![\n            I256::ZERO,\n            I256::ONE,\n            I256::MINUS_ONE,\n            I256::from_dec_str(\"12345\").unwrap(),\n            I256::from_dec_str(\"-54321\").unwrap(),\n            I256::from_dec_str(\"340282366920938463463374607431768211455\").unwrap(),\n            I256::from_dec_str(\"-340282366920938463463374607431768211455\").unwrap(),\n        ];\n\n        #[track_caller]\n        fn validate_mutation(value: I256, mutated: Option<I256>) {\n            assert!(\n                mutated.is_none() || mutated.is_some_and(|m| m != value),\n                \"Mutation failed: value = {value:?}, mutated = {mutated:?}\"\n            );\n        }\n\n        for value in test_values {\n            for _ in 0..100 {\n                validate_mutation(value, I256::increment_decrement(value, size, &mut runner));\n                validate_mutation(value, I256::flip_random_bit(value, size, &mut runner));\n                validate_mutation(value, I256::mutate_interesting_byte(value, size, &mut runner));\n                validate_mutation(value, I256::mutate_interesting_word(value, size, &mut runner));\n                validate_mutation(value, I256::mutate_interesting_dword(value, size, &mut runner));\n            }\n        }\n    }\n\n    #[test]\n    fn test_mutate_address() {\n        let mut runner = TestRunner::new(Config::default());\n        let value = Address::random();\n\n        #[track_caller]\n        fn validate_mutation(value: Address, mutated: Option<Address>) {\n            assert!(\n                mutated.is_none() || mutated.is_some_and(|mutated| mutated != value),\n                \"Mutation failed for value: {value:?}, result: {mutated:?}\"\n            );\n        }\n\n        for _ in 0..100 {\n            validate_mutation(value, Address::flip_random_bit(value, 20, &mut runner));\n            validate_mutation(value, Address::mutate_interesting_byte(value, 20, &mut runner));\n            validate_mutation(value, Address::mutate_interesting_word(value, 20, &mut runner));\n            validate_mutation(value, Address::mutate_interesting_dword(value, 20, &mut runner));\n        }\n    }\n\n    #[test]\n    fn test_mutate_word() {\n        let mut runner = TestRunner::new(Config::default());\n        let value = Word::random();\n\n        #[track_caller]\n        fn validate_mutation(value: Word, mutated: Option<Word>) {\n            assert!(\n                mutated.is_none() || mutated.is_some_and(|mutated| mutated != value),\n                \"Mutation failed for value: {value:?}, result: {mutated:?}\"\n            );\n        }\n\n        for _ in 0..100 {\n            validate_mutation(value, Word::flip_random_bit(value, 32, &mut runner));\n            validate_mutation(value, Word::mutate_interesting_byte(value, 32, &mut runner));\n            validate_mutation(value, Word::mutate_interesting_word(value, 32, &mut runner));\n            validate_mutation(value, Word::mutate_interesting_dword(value, 32, &mut runner));\n        }\n    }\n\n    #[test]\n    fn test_mutate_interesting_word_too_small_returns_none() {\n        let mut runner = TestRunner::new(Config::default());\n        let value = U256::from(123);\n        assert!(U256::mutate_interesting_word(value, 8, &mut runner).is_none());\n    }\n\n    #[test]\n    fn test_mutate_interesting_dword_too_small_returns_none() {\n        let mut runner = TestRunner::new(Config::default());\n        let value = I256::from_dec_str(\"123\").unwrap();\n        assert!(I256::mutate_interesting_dword(value, 16, &mut runner).is_none());\n    }\n\n    #[test]\n    fn test_u256_bound() {\n        let mut runner = TestRunner::new(Config::default());\n        let min = U256::from(0u64);\n        let max = U256::from(200u64);\n        let original = U256::from(100u64);\n\n        for _ in 0..50 {\n            let result = original.bound(min, max, &mut runner);\n            assert!(result.is_some(), \"Mutation should occur\");\n\n            let mutated = result.unwrap();\n            assert!(mutated >= min, \"Mutated value >= min\");\n            assert!(mutated <= max, \"Mutated value <= max\");\n            assert_ne!(mutated, original, \"mutated value should differ from original\");\n        }\n\n        // Test bound in [min, max] range.\n        let result = original.bound(U256::MIN, U256::MAX, &mut runner);\n        assert!(result.is_some(), \"Mutation should occur\");\n    }\n\n    #[test]\n    fn test_i256_bound() {\n        let mut runner = TestRunner::new(Config::default());\n        let min = I256::from_dec_str(\"-100\").unwrap();\n        let max = I256::from_dec_str(\"100\").unwrap();\n        let original = I256::from_dec_str(\"10\").unwrap();\n\n        for _ in 0..50 {\n            let result = original.bound(min, max, &mut runner);\n            assert!(result.is_some(), \"Mutation should occur\");\n\n            let mutated = result.unwrap();\n            assert!(mutated >= min, \"Mutated value >= min\");\n            assert!(mutated <= max, \"Mutated value <= max\");\n            assert_ne!(mutated, original, \"Mutated value should not equal current\");\n        }\n\n        // Test bound in [min, max] range.\n        let result = original.bound(I256::MIN, I256::MAX, &mut runner);\n        assert!(result.is_some(), \"Mutation should occur\");\n    }\n}\n"
  },
  {
    "path": "crates/evm/fuzz/src/strategies/param.rs",
    "content": "use super::state::EvmFuzzState;\nuse crate::{\n    invariant::SenderFilters,\n    strategies::mutators::{\n        BitMutator, GaussianNoiseMutator, IncrementDecrementMutator, InterestingWordMutator,\n    },\n};\nuse alloy_dyn_abi::{DynSolType, DynSolValue, Word};\nuse alloy_primitives::{Address, B256, I256, U256};\nuse proptest::{prelude::*, test_runner::TestRunner};\nuse rand::{SeedableRng, prelude::IndexedMutRandom, rngs::StdRng};\nuse std::mem::replace;\n\n/// The max length of arrays we fuzz for is 256.\nconst MAX_ARRAY_LEN: usize = 256;\n\n/// Given a parameter type, returns a strategy for generating values for that type.\n///\n/// See [`fuzz_param_with_fixtures`] for more information.\npub fn fuzz_param(param: &DynSolType) -> BoxedStrategy<DynSolValue> {\n    fuzz_param_inner(param, None)\n}\n\n/// Given a parameter type and configured fixtures for param name, returns a strategy for generating\n/// values for that type.\n///\n/// Fixtures can be currently generated for uint, int, address, bytes and\n/// string types and are defined for parameter name.\n/// For example, fixtures for parameter `owner` of type `address` can be defined in a function with\n/// a `function fixture_owner() public returns (address[] memory)` signature.\n///\n/// Fixtures are matched on parameter name, hence fixtures defined in\n/// `fixture_owner` function can be used in a fuzzed test function with a signature like\n/// `function testFuzz_ownerAddress(address owner, uint amount)`.\n///\n/// Raises an error if all the fixture types are not of the same type as the input parameter.\n///\n/// Works with ABI Encoder v2 tuples.\npub fn fuzz_param_with_fixtures(\n    param: &DynSolType,\n    fixtures: Option<&[DynSolValue]>,\n    name: &str,\n) -> BoxedStrategy<DynSolValue> {\n    fuzz_param_inner(param, fixtures.map(|f| (f, name)))\n}\n\nfn fuzz_param_inner(\n    param: &DynSolType,\n    mut fuzz_fixtures: Option<(&[DynSolValue], &str)>,\n) -> BoxedStrategy<DynSolValue> {\n    if let Some((fixtures, name)) = fuzz_fixtures\n        && !fixtures.iter().all(|f| f.matches(param))\n    {\n        error!(\"fixtures for {name:?} do not match type {param}\");\n        fuzz_fixtures = None;\n    }\n    let fuzz_fixtures = fuzz_fixtures.map(|(f, _)| f);\n\n    let value = || {\n        let default_strategy = DynSolValue::type_strategy(param);\n        if let Some(fixtures) = fuzz_fixtures {\n            proptest::prop_oneof![\n                50 => {\n                    let fixtures = fixtures.to_vec();\n                    any::<prop::sample::Index>()\n                        .prop_map(move |index| index.get(&fixtures).clone())\n                },\n                50 => default_strategy,\n            ]\n            .boxed()\n        } else {\n            default_strategy.boxed()\n        }\n    };\n\n    match *param {\n        DynSolType::Address => value(),\n        DynSolType::Int(n @ 8..=256) => super::IntStrategy::new(n, fuzz_fixtures)\n            .prop_map(move |x| DynSolValue::Int(x, n))\n            .boxed(),\n        DynSolType::Uint(n @ 8..=256) => super::UintStrategy::new(n, fuzz_fixtures)\n            .prop_map(move |x| DynSolValue::Uint(x, n))\n            .boxed(),\n        DynSolType::Function | DynSolType::Bool => DynSolValue::type_strategy(param).boxed(),\n        DynSolType::Bytes => value(),\n        DynSolType::FixedBytes(_size @ 1..=32) => value(),\n        DynSolType::String => value()\n            .prop_map(move |value| {\n                DynSolValue::String(\n                    value.as_str().unwrap().trim().trim_end_matches('\\0').to_string(),\n                )\n            })\n            .boxed(),\n        DynSolType::Tuple(ref params) => params\n            .iter()\n            .map(|param| fuzz_param_inner(param, None))\n            .collect::<Vec<_>>()\n            .prop_map(DynSolValue::Tuple)\n            .boxed(),\n        DynSolType::FixedArray(ref param, size) => {\n            proptest::collection::vec(fuzz_param_inner(param, None), size)\n                .prop_map(DynSolValue::FixedArray)\n                .boxed()\n        }\n        DynSolType::Array(ref param) => {\n            proptest::collection::vec(fuzz_param_inner(param, None), 0..MAX_ARRAY_LEN)\n                .prop_map(DynSolValue::Array)\n                .boxed()\n        }\n        _ => panic!(\"unsupported fuzz param type: {param}\"),\n    }\n}\n\n/// Given a parameter type, returns a strategy for generating values for that type, given some EVM\n/// fuzz state.\n///\n/// Works with ABI Encoder v2 tuples.\npub fn fuzz_param_from_state(\n    param: &DynSolType,\n    state: &EvmFuzzState,\n) -> BoxedStrategy<DynSolValue> {\n    // Value strategy that uses the state.\n    let value = || {\n        let state = state.clone();\n        let param = param.clone();\n        // Generate a bias and use it to pick samples or non-persistent values (50 / 50).\n        // Use `Index` instead of `Selector` when selecting a value to avoid iterating over the\n        // entire dictionary.\n        any::<(bool, prop::sample::Index)>().prop_map(move |(bias, index)| {\n            let state = state.dictionary_read();\n            let values = if bias { state.samples(&param) } else { None }\n                .unwrap_or_else(|| state.values())\n                .as_slice();\n            values[index.index(values.len())]\n        })\n    };\n\n    // Convert the value based on the parameter type\n    match *param {\n        DynSolType::Address => {\n            let deployed_libs = state.deployed_libs.clone();\n            value()\n                .prop_map(move |value| {\n                    let mut fuzzed_addr = Address::from_word(value);\n                    if deployed_libs.contains(&fuzzed_addr) {\n                        let mut rng = StdRng::seed_from_u64(0x1337); // use deterministic rng\n\n                        // Do not use addresses of deployed libraries as fuzz input, instead return\n                        // a deterministically random address. We cannot filter out this value (via\n                        // `prop_filter_map`) as proptest can invoke this closure after test\n                        // execution, and returning a `None` will cause it to panic.\n                        // See <https://github.com/foundry-rs/foundry/issues/9764> and <https://github.com/foundry-rs/foundry/issues/8639>.\n                        loop {\n                            fuzzed_addr.randomize_with(&mut rng);\n                            if !deployed_libs.contains(&fuzzed_addr) {\n                                break;\n                            }\n                        }\n                    }\n                    DynSolValue::Address(fuzzed_addr)\n                })\n                .boxed()\n        }\n        DynSolType::Function => value()\n            .prop_map(move |value| {\n                DynSolValue::Function(alloy_primitives::Function::from_word(value))\n            })\n            .boxed(),\n        DynSolType::FixedBytes(size @ 1..=32) => value()\n            .prop_map(move |mut v| {\n                v[size..].fill(0);\n                DynSolValue::FixedBytes(B256::from(v), size)\n            })\n            .boxed(),\n        DynSolType::Bool => DynSolValue::type_strategy(param).boxed(),\n        DynSolType::String => {\n            let state = state.clone();\n            (proptest::bool::weighted(0.3), any::<prop::sample::Index>())\n                .prop_flat_map(move |(use_ast, select_index)| {\n                    let dict = state.dictionary_read();\n\n                    // AST string literals available: 30% probability\n                    let ast_strings = dict.ast_strings();\n                    if use_ast && !ast_strings.is_empty() {\n                        let s = &ast_strings.as_slice()[select_index.index(ast_strings.len())];\n                        return Just(DynSolValue::String(s.clone())).boxed();\n                    }\n\n                    // Fallback to random string generation\n                    DynSolValue::type_strategy(&DynSolType::String)\n                        .prop_map(|value| {\n                            DynSolValue::String(\n                                value.as_str().unwrap().trim().trim_end_matches('\\0').to_string(),\n                            )\n                        })\n                        .boxed()\n                })\n                .boxed()\n        }\n        DynSolType::Bytes => {\n            let state_clone = state.clone();\n            (\n                value(),\n                proptest::bool::weighted(0.1),\n                proptest::bool::weighted(0.2),\n                any::<prop::sample::Index>(),\n            )\n                .prop_map(move |(word, use_ast_string, use_ast_bytes, select_index)| {\n                    let dict = state_clone.dictionary_read();\n\n                    // Try string literals as bytes: 10% chance\n                    let ast_strings = dict.ast_strings();\n                    if use_ast_string && !ast_strings.is_empty() {\n                        let s = &ast_strings.as_slice()[select_index.index(ast_strings.len())];\n                        return DynSolValue::Bytes(s.as_bytes().to_vec());\n                    }\n\n                    // Try hex literals: 20% chance\n                    let ast_bytes = dict.ast_bytes();\n                    if use_ast_bytes && !ast_bytes.is_empty() {\n                        let bytes = &ast_bytes.as_slice()[select_index.index(ast_bytes.len())];\n                        return DynSolValue::Bytes(bytes.to_vec());\n                    }\n\n                    // Fallback to the generated word from the dictionary: 70% chance\n                    DynSolValue::Bytes(word.0.into())\n                })\n                .boxed()\n        }\n        DynSolType::Int(n @ 8..=256) => match n / 8 {\n            32 => value()\n                .prop_map(move |value| DynSolValue::Int(I256::from_raw(value.into()), 256))\n                .boxed(),\n            1..=31 => value()\n                .prop_map(move |value| {\n                    // Extract lower N bits\n                    let uint_n = U256::from_be_bytes(value.0) % U256::from(1).wrapping_shl(n);\n                    // Interpret as signed int (two's complement) --> check sign bit (bit N-1).\n                    let sign_bit = U256::from(1) << (n - 1);\n                    let num = if uint_n >= sign_bit {\n                        // Negative number in two's complement\n                        let modulus = U256::from(1) << n;\n                        I256::from_raw(uint_n.wrapping_sub(modulus))\n                    } else {\n                        // Positive number\n                        I256::from_raw(uint_n)\n                    };\n\n                    DynSolValue::Int(num, n)\n                })\n                .boxed(),\n            _ => unreachable!(),\n        },\n        DynSolType::Uint(n @ 8..=256) => match n / 8 {\n            32 => value()\n                .prop_map(move |value| DynSolValue::Uint(U256::from_be_bytes(value.0), 256))\n                .boxed(),\n            1..=31 => value()\n                .prop_map(move |value| {\n                    let uint = U256::from_be_bytes(value.0) % U256::from(1).wrapping_shl(n);\n                    DynSolValue::Uint(uint, n)\n                })\n                .boxed(),\n            _ => unreachable!(),\n        },\n        DynSolType::Tuple(ref params) => params\n            .iter()\n            .map(|p| fuzz_param_from_state(p, state))\n            .collect::<Vec<_>>()\n            .prop_map(DynSolValue::Tuple)\n            .boxed(),\n        DynSolType::FixedArray(ref param, size) => {\n            proptest::collection::vec(fuzz_param_from_state(param, state), size)\n                .prop_map(DynSolValue::FixedArray)\n                .boxed()\n        }\n        DynSolType::Array(ref param) => {\n            proptest::collection::vec(fuzz_param_from_state(param, state), 0..MAX_ARRAY_LEN)\n                .prop_map(DynSolValue::Array)\n                .boxed()\n        }\n        _ => panic!(\"unsupported fuzz param type: {param}\"),\n    }\n}\n\n/// Selects a random address for mutation, respecting sender filters if provided.\n///\n/// Priority:\n/// 1. If `senders` has targeted addresses, pick randomly from those\n/// 2. Otherwise, pick from the dictionary state values (excluding any in `senders.excluded`)\n/// 3. Returns `None` if no suitable address is found or if the selected address equals `current`\nfn select_random_address(\n    current: Address,\n    test_runner: &mut TestRunner,\n    state: &EvmFuzzState,\n    senders: Option<&SenderFilters>,\n) -> Option<Address> {\n    if let Some(senders) = senders {\n        if !senders.targeted.is_empty() {\n            // Pick from targeted senders\n            let index = test_runner.rng().random_range(0..senders.targeted.len());\n            let addr = senders.targeted[index];\n            return (addr != current).then_some(addr);\n        }\n\n        // Pick from dictionary state values, excluding addresses in the exclusion list\n        let dict = state.dictionary_read();\n        let values = dict.values();\n        if values.is_empty() {\n            return None;\n        }\n\n        // Try a few times to find a non-excluded address\n        for _ in 0..10 {\n            let index = test_runner.rng().random_range(0..values.len());\n            let addr = Address::from_word(values[index]);\n            if addr != current && !senders.excluded.contains(&addr) {\n                return Some(addr);\n            }\n        }\n        None\n    } else {\n        // No sender filters, just pick from dictionary state values\n        let dict = state.dictionary_read();\n        let values = dict.values();\n        if values.is_empty() {\n            None\n        } else {\n            let index = test_runner.rng().random_range(0..values.len());\n            let addr = Address::from_word(values[index]);\n            (addr != current).then_some(addr)\n        }\n    }\n}\n\n/// Mutates the current value of the given parameter type and value.\npub fn mutate_param_value(\n    param: &DynSolType,\n    value: DynSolValue,\n    test_runner: &mut TestRunner,\n    state: &EvmFuzzState,\n) -> DynSolValue {\n    mutate_param_value_inner(param, value, test_runner, state, None)\n}\n\n/// Mutates the current value of the given parameter type and value, with optional sender filters.\n///\n/// When `senders` is provided and has targeted addresses, address mutations will prefer\n/// selecting from those targeted addresses (similar to `select_random_sender` behavior).\npub fn mutate_param_value_with_senders(\n    param: &DynSolType,\n    value: DynSolValue,\n    test_runner: &mut TestRunner,\n    state: &EvmFuzzState,\n    senders: &SenderFilters,\n) -> DynSolValue {\n    mutate_param_value_inner(param, value, test_runner, state, Some(senders))\n}\n\nfn mutate_param_value_inner(\n    param: &DynSolType,\n    value: DynSolValue,\n    test_runner: &mut TestRunner,\n    state: &EvmFuzzState,\n    senders: Option<&SenderFilters>,\n) -> DynSolValue {\n    let new_value = |param: &DynSolType, test_runner: &mut TestRunner| {\n        fuzz_param_from_state(param, state)\n            .new_tree(test_runner)\n            .expect(\"Could not generate case\")\n            .current()\n    };\n\n    match value {\n        DynSolValue::Bool(val) => {\n            // flip boolean value\n            trace!(target: \"mutator\", \"Bool flip {val}\");\n            Some(DynSolValue::Bool(!val))\n        }\n        DynSolValue::Uint(val, size) => match test_runner.rng().random_range(0..=6) {\n            0 => U256::increment_decrement(val, size, test_runner),\n            1 => U256::flip_random_bit(val, size, test_runner),\n            2 => U256::mutate_interesting_byte(val, size, test_runner),\n            3 => U256::mutate_interesting_word(val, size, test_runner),\n            4 => U256::mutate_interesting_dword(val, size, test_runner),\n            5 => U256::mutate_with_gaussian_noise(val, size, test_runner),\n            6 => None,\n            _ => unreachable!(),\n        }\n        .map(|v| DynSolValue::Uint(v, size)),\n        DynSolValue::Int(val, size) => match test_runner.rng().random_range(0..=6) {\n            0 => I256::increment_decrement(val, size, test_runner),\n            1 => I256::flip_random_bit(val, size, test_runner),\n            2 => I256::mutate_interesting_byte(val, size, test_runner),\n            3 => I256::mutate_interesting_word(val, size, test_runner),\n            4 => I256::mutate_interesting_dword(val, size, test_runner),\n            5 => I256::mutate_with_gaussian_noise(val, size, test_runner),\n            6 => None,\n            _ => unreachable!(),\n        }\n        .map(|v| DynSolValue::Int(v, size)),\n        DynSolValue::Address(val) => match test_runner.rng().random_range(0..=5) {\n            0 => Address::flip_random_bit(val, 20, test_runner),\n            1 => Address::mutate_interesting_byte(val, 20, test_runner),\n            2 => Address::mutate_interesting_word(val, 20, test_runner),\n            3 => Address::mutate_interesting_dword(val, 20, test_runner),\n            // Replace with a random address from targeted senders or dictionary.\n            4 => select_random_address(val, test_runner, state, senders),\n            5 => None,\n            _ => unreachable!(),\n        }\n        .map(DynSolValue::Address),\n        DynSolValue::Array(mut values) => {\n            if let DynSolType::Array(param_type) = param\n                && !values.is_empty()\n            {\n                match test_runner.rng().random_range(0..=2) {\n                    // Decrease array size by removing a random element.\n                    0 => {\n                        values.remove(test_runner.rng().random_range(0..values.len()));\n                    }\n                    // Increase array size.\n                    1 => values.push(new_value(param_type, test_runner)),\n                    // Mutate random array element.\n                    2 => mutate_random_array_value(\n                        &mut values,\n                        param_type,\n                        test_runner,\n                        state,\n                        senders,\n                    ),\n                    _ => unreachable!(),\n                }\n                Some(DynSolValue::Array(values))\n            } else {\n                None\n            }\n        }\n        DynSolValue::FixedArray(mut values) => {\n            if let DynSolType::FixedArray(param_type, _size) = param\n                && !values.is_empty()\n            {\n                mutate_random_array_value(&mut values, param_type, test_runner, state, senders);\n                Some(DynSolValue::FixedArray(values))\n            } else {\n                None\n            }\n        }\n        DynSolValue::FixedBytes(word, size) => match test_runner.rng().random_range(0..=4) {\n            0 => Word::flip_random_bit(word, size, test_runner),\n            1 => Word::mutate_interesting_byte(word, size, test_runner),\n            2 => Word::mutate_interesting_word(word, size, test_runner),\n            3 => Word::mutate_interesting_dword(word, size, test_runner),\n            4 => None,\n            _ => unreachable!(),\n        }\n        .map(|word| DynSolValue::FixedBytes(word, size)),\n        DynSolValue::CustomStruct { name, prop_names, tuple: mut values } => {\n            if let DynSolType::CustomStruct { name: _, prop_names: _, tuple: tuple_types }\n            | DynSolType::Tuple(tuple_types) = param\n                && !values.is_empty()\n            {\n                // Mutate random struct element.\n                mutate_random_tuple_value(&mut values, tuple_types, test_runner, state, senders);\n                Some(DynSolValue::CustomStruct { name, prop_names, tuple: values })\n            } else {\n                None\n            }\n        }\n        DynSolValue::Tuple(mut values) => {\n            if let DynSolType::Tuple(tuple_types) = param\n                && !values.is_empty()\n            {\n                // Mutate random tuple element.\n                mutate_random_tuple_value(&mut values, tuple_types, test_runner, state, senders);\n                Some(DynSolValue::Tuple(values))\n            } else {\n                None\n            }\n        }\n        _ => None,\n    }\n    .unwrap_or_else(|| new_value(param, test_runner))\n}\n\n/// Mutates random value from given tuples.\nfn mutate_random_tuple_value(\n    tuple_values: &mut [DynSolValue],\n    tuple_types: &[DynSolType],\n    test_runner: &mut TestRunner,\n    state: &EvmFuzzState,\n    senders: Option<&SenderFilters>,\n) {\n    let id = test_runner.rng().random_range(0..tuple_values.len());\n    let param_type = &tuple_types[id];\n    let old_val = replace(&mut tuple_values[id], DynSolValue::Bool(false));\n    let new_val = mutate_param_value_inner(param_type, old_val, test_runner, state, senders);\n    tuple_values[id] = new_val;\n}\n\n/// Mutates random value from given array.\nfn mutate_random_array_value(\n    array_values: &mut [DynSolValue],\n    element_type: &DynSolType,\n    test_runner: &mut TestRunner,\n    state: &EvmFuzzState,\n    senders: Option<&SenderFilters>,\n) {\n    let elem = array_values.choose_mut(&mut test_runner.rng()).unwrap();\n    let old_val = replace(elem, DynSolValue::Bool(false));\n    let new_val = mutate_param_value_inner(element_type, old_val, test_runner, state, senders);\n    *elem = new_val;\n}\n\n#[cfg(test)]\nmod tests {\n    use crate::{\n        FuzzFixtures,\n        strategies::{EvmFuzzState, fuzz_calldata, fuzz_calldata_from_state},\n    };\n    use alloy_primitives::B256;\n    use foundry_common::abi::get_func;\n    use std::collections::HashSet;\n\n    #[test]\n    fn can_fuzz_array() {\n        let f = \"testArray(uint64[2] calldata values)\";\n        let func = get_func(f).unwrap();\n        let state = EvmFuzzState::test();\n        let strategy = proptest::prop_oneof![\n            60 => fuzz_calldata(func.clone(), &FuzzFixtures::default()),\n            40 => fuzz_calldata_from_state(func, &state),\n        ];\n        let cfg = proptest::test_runner::Config { failure_persistence: None, ..Default::default() };\n        let mut runner = proptest::test_runner::TestRunner::new(cfg);\n        let _ = runner.run(&strategy, |_| Ok(()));\n    }\n\n    #[test]\n    fn can_fuzz_string_and_bytes_with_ast_literals_and_hashes() {\n        use super::fuzz_param_from_state;\n        use crate::strategies::LiteralMaps;\n        use alloy_dyn_abi::DynSolType;\n        use alloy_primitives::keccak256;\n        use proptest::strategy::Strategy;\n\n        // Seed dict with string values and their hashes --> mimic `CheatcodeAnalysis` behavior.\n        let mut literals = LiteralMaps::default();\n        literals.strings.insert(\"hello\".to_string());\n        literals.strings.insert(\"world\".to_string());\n        literals.words.entry(DynSolType::FixedBytes(32)).or_default().insert(keccak256(\"hello\"));\n        literals.words.entry(DynSolType::FixedBytes(32)).or_default().insert(keccak256(\"world\"));\n\n        let state = EvmFuzzState::test();\n        state.seed_literals(literals);\n\n        let cfg = proptest::test_runner::Config { failure_persistence: None, ..Default::default() };\n        let mut runner = proptest::test_runner::TestRunner::new(cfg);\n\n        // Verify strategies generates the seeded AST literals\n        let mut generated_bytes = HashSet::new();\n        let mut generated_hashes = HashSet::new();\n        let mut generated_strings = HashSet::new();\n        let bytes_strategy = fuzz_param_from_state(&DynSolType::Bytes, &state);\n        let string_strategy = fuzz_param_from_state(&DynSolType::String, &state);\n        let bytes32_strategy = fuzz_param_from_state(&DynSolType::FixedBytes(32), &state);\n\n        for _ in 0..256 {\n            let tree = bytes_strategy.new_tree(&mut runner).unwrap();\n            if let Some(bytes) = tree.current().as_bytes()\n                && let Ok(s) = std::str::from_utf8(bytes)\n            {\n                generated_bytes.insert(s.to_string());\n            }\n\n            let tree = string_strategy.new_tree(&mut runner).unwrap();\n            if let Some(s) = tree.current().as_str() {\n                generated_strings.insert(s.to_string());\n            }\n\n            let tree = bytes32_strategy.new_tree(&mut runner).unwrap();\n            if let Some((bytes, size)) = tree.current().as_fixed_bytes()\n                && size == 32\n            {\n                generated_hashes.insert(B256::from_slice(bytes));\n            }\n        }\n\n        assert!(generated_bytes.contains(\"hello\"));\n        assert!(generated_bytes.contains(\"world\"));\n        assert!(generated_strings.contains(\"hello\"));\n        assert!(generated_strings.contains(\"world\"));\n        assert!(generated_hashes.contains(&keccak256(\"hello\")));\n        assert!(generated_hashes.contains(&keccak256(\"world\")));\n    }\n\n    #[test]\n    fn mutate_address_can_select_from_dictionary() {\n        use super::mutate_param_value;\n        use alloy_dyn_abi::{DynSolType, DynSolValue};\n        use alloy_primitives::Address;\n\n        let state = EvmFuzzState::test();\n\n        // Add addresses to dictionary via state values.\n        let addr1 = Address::repeat_byte(0x11);\n        let addr2 = Address::repeat_byte(0x22);\n        let addr3 = Address::repeat_byte(0x33);\n        state.collect_values([addr1.into_word(), addr2.into_word(), addr3.into_word()]);\n\n        let cfg = proptest::test_runner::Config { failure_persistence: None, ..Default::default() };\n        let mut runner = proptest::test_runner::TestRunner::new(cfg);\n\n        // Mutate an address many times and verify we can get addresses from the dictionary.\n        let original = Address::repeat_byte(0xff);\n        let mut got_addr1 = false;\n        let mut got_addr2 = false;\n        let mut got_addr3 = false;\n\n        for _ in 0..1000 {\n            let mutated = mutate_param_value(\n                &DynSolType::Address,\n                DynSolValue::Address(original),\n                &mut runner,\n                &state,\n            );\n            if let DynSolValue::Address(addr) = mutated {\n                if addr == addr1 {\n                    got_addr1 = true;\n                }\n                if addr == addr2 {\n                    got_addr2 = true;\n                }\n                if addr == addr3 {\n                    got_addr3 = true;\n                }\n            }\n            if got_addr1 && got_addr2 && got_addr3 {\n                break;\n            }\n        }\n\n        // We should have seen at least one dictionary address in 1000 iterations.\n        assert!(\n            got_addr1 || got_addr2 || got_addr3,\n            \"Address mutation should select addresses from dictionary\"\n        );\n    }\n\n    #[test]\n    fn mutate_address_prefers_targeted_senders() {\n        use super::select_random_address;\n        use crate::invariant::SenderFilters;\n        use alloy_primitives::Address;\n\n        let state = EvmFuzzState::test();\n\n        // Add addresses to dictionary (these should NOT be selected when targeted is set).\n        let dict_addr = Address::repeat_byte(0xdd);\n        state.collect_values([dict_addr.into_word()]);\n\n        // Set up targeted senders.\n        let targeted1 = Address::repeat_byte(0x11);\n        let targeted2 = Address::repeat_byte(0x22);\n        let senders = SenderFilters::new(vec![targeted1, targeted2], vec![]);\n\n        let cfg = proptest::test_runner::Config { failure_persistence: None, ..Default::default() };\n        let mut runner = proptest::test_runner::TestRunner::new(cfg);\n\n        // Call select_random_address directly to verify it uses targeted senders.\n        let original = Address::repeat_byte(0xff);\n        let mut got_targeted1 = false;\n        let mut got_targeted2 = false;\n        let mut got_dict = false;\n\n        for _ in 0..100 {\n            if let Some(addr) = select_random_address(original, &mut runner, &state, Some(&senders))\n            {\n                if addr == targeted1 {\n                    got_targeted1 = true;\n                }\n                if addr == targeted2 {\n                    got_targeted2 = true;\n                }\n                if addr == dict_addr {\n                    got_dict = true;\n                }\n            }\n        }\n\n        // Should see targeted addresses, never dictionary address.\n        assert!(\n            got_targeted1 || got_targeted2,\n            \"select_random_address should select from targeted senders\"\n        );\n        assert!(\n            !got_dict,\n            \"select_random_address should not select from dictionary when targeted senders are set\"\n        );\n    }\n\n    #[test]\n    fn mutate_address_respects_excluded_senders() {\n        use super::select_random_address;\n        use crate::invariant::SenderFilters;\n        use alloy_primitives::Address;\n\n        let state = EvmFuzzState::test();\n\n        // Add addresses to dictionary.\n        let addr1 = Address::repeat_byte(0x11);\n        let addr2 = Address::repeat_byte(0x22);\n        let excluded_addr = Address::repeat_byte(0xee);\n        state.collect_values([addr1.into_word(), addr2.into_word(), excluded_addr.into_word()]);\n\n        // Exclude one address.\n        let senders = SenderFilters::new(vec![], vec![excluded_addr]);\n\n        let cfg = proptest::test_runner::Config { failure_persistence: None, ..Default::default() };\n        let mut runner = proptest::test_runner::TestRunner::new(cfg);\n\n        // Call select_random_address directly to verify it respects excluded senders.\n        let original = Address::repeat_byte(0xff);\n        let mut got_excluded = false;\n        let mut got_valid = false;\n\n        for _ in 0..100 {\n            if let Some(addr) = select_random_address(original, &mut runner, &state, Some(&senders))\n            {\n                if addr == excluded_addr {\n                    got_excluded = true;\n                    break;\n                }\n                if addr == addr1 || addr == addr2 {\n                    got_valid = true;\n                }\n            }\n        }\n\n        assert!(!got_excluded, \"select_random_address should not select excluded addresses\");\n        assert!(got_valid, \"select_random_address should select valid (non-excluded) addresses\");\n    }\n}\n"
  },
  {
    "path": "crates/evm/fuzz/src/strategies/state.rs",
    "content": "use crate::{\n    BasicTxDetails, invariant::FuzzRunIdentifiedContracts, strategies::literals::LiteralsDictionary,\n};\nuse alloy_dyn_abi::{DynSolType, DynSolValue, EventExt, FunctionExt};\nuse alloy_json_abi::{Function, JsonAbi};\nuse alloy_primitives::{\n    Address, B256, Bytes, Log, U256,\n    map::{AddressIndexSet, AddressMap, B256IndexSet, HashMap, IndexSet},\n};\nuse foundry_common::{\n    ignore_metadata_hash, mapping_slots::MappingSlots, slot_identifier::SlotIdentifier,\n};\nuse foundry_compilers::artifacts::StorageLayout;\nuse foundry_config::FuzzDictionaryConfig;\nuse foundry_evm_core::{bytecode::InstIter, utils::StateChangeset};\nuse parking_lot::{RawRwLock, RwLock, lock_api::RwLockReadGuard};\nuse revm::{\n    database::{CacheDB, DatabaseRef, DbAccount},\n    state::AccountInfo,\n};\nuse std::{collections::BTreeMap, fmt, sync::Arc};\n\n/// The maximum number of bytes we will look at in bytecodes to find push bytes (24 KiB).\n///\n/// This is to limit the performance impact of fuzz tests that might deploy arbitrarily sized\n/// bytecode (as is the case with Solmate).\nconst PUSH_BYTE_ANALYSIS_LIMIT: usize = 24 * 1024;\n\n/// A set of arbitrary 32 byte data from the VM used to generate values for the strategy.\n///\n/// Wrapped in a shareable container.\n#[derive(Clone, Debug)]\npub struct EvmFuzzState {\n    inner: Arc<RwLock<FuzzDictionary>>,\n    /// Addresses of external libraries deployed in test setup, excluded from fuzz test inputs.\n    pub deployed_libs: Vec<Address>,\n    /// Records mapping accesses. Used to identify storage slots belonging to mappings and sampling\n    /// the values in the [`FuzzDictionary`].\n    ///\n    /// Only needed when [`StorageLayout`] is available.\n    pub(crate) mapping_slots: Option<AddressMap<MappingSlots>>,\n}\n\nimpl EvmFuzzState {\n    #[cfg(test)]\n    pub(crate) fn test() -> Self {\n        Self::new(\n            &[],\n            &CacheDB::<revm::database::EmptyDB>::default(),\n            FuzzDictionaryConfig::default(),\n            None,\n        )\n    }\n\n    pub fn new<DB: DatabaseRef>(\n        deployed_libs: &[Address],\n        db: &CacheDB<DB>,\n        config: FuzzDictionaryConfig,\n        literals: Option<&LiteralsDictionary>,\n    ) -> Self {\n        // Sort accounts to ensure deterministic dictionary generation from the same setUp state.\n        let mut accs = db.cache.accounts.iter().collect::<Vec<_>>();\n        accs.sort_by_key(|(address, _)| *address);\n\n        // Create fuzz dictionary and insert values from db state.\n        let mut dictionary = FuzzDictionary::new(config);\n        dictionary.insert_db_values(accs);\n        if let Some(literals) = literals {\n            dictionary.literal_values = literals.clone();\n        }\n\n        Self {\n            inner: Arc::new(RwLock::new(dictionary)),\n            deployed_libs: deployed_libs.to_vec(),\n            mapping_slots: None,\n        }\n    }\n\n    pub fn with_mapping_slots(mut self, mapping_slots: AddressMap<MappingSlots>) -> Self {\n        self.mapping_slots = Some(mapping_slots);\n        self\n    }\n\n    pub fn collect_values(&self, values: impl IntoIterator<Item = B256>) {\n        let mut dict = self.inner.write();\n        for value in values {\n            dict.insert_value(value);\n        }\n    }\n\n    /// Collects state changes from a [StateChangeset] and logs into an [EvmFuzzState] according to\n    /// the given [FuzzDictionaryConfig].\n    pub fn collect_values_from_call(\n        &self,\n        fuzzed_contracts: &FuzzRunIdentifiedContracts,\n        tx: &BasicTxDetails,\n        result: &Bytes,\n        logs: &[Log],\n        state_changeset: &StateChangeset,\n        run_depth: u32,\n    ) {\n        let mut dict = self.inner.write();\n        {\n            let targets = fuzzed_contracts.targets.lock();\n            let (target_abi, target_function) = targets.fuzzed_artifacts(tx);\n            dict.insert_logs_values(target_abi, logs, run_depth);\n            dict.insert_result_values(target_function, result, run_depth);\n            // Get storage layouts for contracts in the state changeset\n            let storage_layouts = targets.get_storage_layouts();\n            dict.insert_new_state_values(\n                state_changeset,\n                &storage_layouts,\n                self.mapping_slots.as_ref(),\n            );\n        }\n    }\n\n    /// Removes all newly added entries from the dictionary.\n    ///\n    /// Should be called between fuzz/invariant runs to avoid accumulating data derived from fuzz\n    /// inputs.\n    pub fn revert(&self) {\n        self.inner.write().revert();\n    }\n\n    pub fn dictionary_read(&self) -> RwLockReadGuard<'_, RawRwLock, FuzzDictionary> {\n        self.inner.read()\n    }\n\n    /// Logs stats about the current state.\n    pub fn log_stats(&self) {\n        self.inner.read().log_stats();\n    }\n\n    /// Test-only helper to seed the dictionary with literal values.\n    #[cfg(test)]\n    pub(crate) fn seed_literals(&self, map: super::LiteralMaps) {\n        self.inner.write().seed_literals(map);\n    }\n}\n\n// We're using `IndexSet` to have a stable element order when restoring persisted state, as well as\n// for performance when iterating over the sets.\npub struct FuzzDictionary {\n    /// Collected state values.\n    state_values: B256IndexSet,\n    /// Addresses that already had their PUSH bytes collected.\n    addresses: AddressIndexSet,\n    /// Configuration for the dictionary.\n    config: FuzzDictionaryConfig,\n    /// Number of state values initially collected from db.\n    /// Used to revert new collected values at the end of each run.\n    db_state_values: usize,\n    /// Number of address values initially collected from db.\n    /// Used to revert new collected addresses at the end of each run.\n    db_addresses: usize,\n    /// Typed runtime sample values persisted across invariant runs.\n    /// Initially seeded with literal values collected from the source code.\n    sample_values: HashMap<DynSolType, B256IndexSet>,\n    /// Lazily initialized dictionary of literal values collected from the source code.\n    literal_values: LiteralsDictionary,\n    /// Tracks whether literals from `literal_values` have been merged into `sample_values`.\n    ///\n    /// Set to `true` on first call to `seed_samples()`. Before seeding, `samples()` checks both\n    /// maps separately. After seeding, literals are merged in, so only `sample_values` is checked.\n    samples_seeded: bool,\n\n    misses: usize,\n    hits: usize,\n}\n\nimpl fmt::Debug for FuzzDictionary {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.debug_struct(\"FuzzDictionary\")\n            .field(\"state_values\", &self.state_values.len())\n            .field(\"addresses\", &self.addresses)\n            .finish()\n    }\n}\n\nimpl Default for FuzzDictionary {\n    fn default() -> Self {\n        Self::new(Default::default())\n    }\n}\n\nimpl FuzzDictionary {\n    pub fn new(config: FuzzDictionaryConfig) -> Self {\n        let mut dictionary = Self {\n            config,\n            samples_seeded: false,\n\n            state_values: Default::default(),\n            addresses: Default::default(),\n            db_state_values: Default::default(),\n            db_addresses: Default::default(),\n            sample_values: Default::default(),\n            literal_values: Default::default(),\n            misses: Default::default(),\n            hits: Default::default(),\n        };\n        dictionary.prefill();\n        dictionary\n    }\n\n    /// Insert common values into the dictionary at initialization.\n    fn prefill(&mut self) {\n        self.insert_value(B256::ZERO);\n    }\n\n    /// Seeds `sample_values` with all words from the [`LiteralsDictionary`].\n    /// Should only be called once per dictionary lifetime.\n    #[cold]\n    fn seed_samples(&mut self) {\n        trace!(\"seeding `sample_values` from literal dictionary\");\n        self.sample_values\n            .extend(self.literal_values.get().words.iter().map(|(k, v)| (k.clone(), v.clone())));\n        self.samples_seeded = true;\n    }\n\n    /// Insert values from initial db state into fuzz dictionary.\n    /// These values are persisted across invariant runs.\n    fn insert_db_values(&mut self, db_state: Vec<(&Address, &DbAccount)>) {\n        for (address, account) in db_state {\n            // Insert basic account information\n            self.insert_value(address.into_word());\n            // Insert push bytes\n            self.insert_push_bytes_values(address, &account.info);\n            // Insert storage values.\n            if self.config.include_storage {\n                // Sort storage values before inserting to ensure deterministic dictionary.\n                let values = account.storage.iter().collect::<BTreeMap<_, _>>();\n                for (slot, value) in values {\n                    self.insert_storage_value(slot, value, None, None);\n                }\n            }\n        }\n\n        // We need at least some state data if DB is empty,\n        // otherwise we can't select random data for state fuzzing.\n        if self.values().is_empty() {\n            // Prefill with a random address.\n            self.insert_value(Address::random().into_word());\n        }\n\n        // Record number of values and addresses inserted from db to be used for reverting at the\n        // end of each run.\n        self.db_state_values = self.state_values.len();\n        self.db_addresses = self.addresses.len();\n    }\n\n    /// Insert values collected from call result into fuzz dictionary.\n    fn insert_result_values(\n        &mut self,\n        function: Option<&Function>,\n        result: &Bytes,\n        run_depth: u32,\n    ) {\n        if let Some(function) = function\n            && !function.outputs.is_empty()\n        {\n            // Decode result and collect samples to be used in subsequent fuzz runs.\n            if let Ok(decoded_result) = function.abi_decode_output(result) {\n                self.insert_sample_values(decoded_result, run_depth);\n            }\n        }\n    }\n\n    /// Insert values from call log topics and data into fuzz dictionary.\n    fn insert_logs_values(&mut self, abi: Option<&JsonAbi>, logs: &[Log], run_depth: u32) {\n        let mut samples = Vec::new();\n        // Decode logs with known events and collect samples from indexed fields and event body.\n        for log in logs {\n            let mut log_decoded = false;\n            // Try to decode log with events from contract abi.\n            if let Some(abi) = abi {\n                for event in abi.events() {\n                    if let Ok(decoded_event) = event.decode_log(log) {\n                        samples.extend(decoded_event.indexed);\n                        samples.extend(decoded_event.body);\n                        log_decoded = true;\n                        break;\n                    }\n                }\n            }\n\n            // If we weren't able to decode event then we insert raw data in fuzz dictionary.\n            if !log_decoded {\n                for &topic in log.topics() {\n                    self.insert_value(topic);\n                }\n                let chunks = log.data.data.chunks_exact(32);\n                let rem = chunks.remainder();\n                for chunk in chunks {\n                    self.insert_value(chunk.try_into().unwrap());\n                }\n                if !rem.is_empty() {\n                    self.insert_value(B256::right_padding_from(rem));\n                }\n            }\n        }\n\n        // Insert samples collected from current call in fuzz dictionary.\n        self.insert_sample_values(samples, run_depth);\n    }\n\n    /// Insert values from call state changeset into fuzz dictionary.\n    /// These values are removed at the end of current run.\n    fn insert_new_state_values(\n        &mut self,\n        state_changeset: &StateChangeset,\n        storage_layouts: &HashMap<Address, Arc<StorageLayout>>,\n        mapping_slots: Option<&AddressMap<MappingSlots>>,\n    ) {\n        for (address, account) in state_changeset {\n            // Insert basic account information.\n            self.insert_value(address.into_word());\n            // Insert push bytes.\n            self.insert_push_bytes_values(address, &account.info);\n            // Insert storage values.\n            if self.config.include_storage {\n                let slot_identifier =\n                    storage_layouts.get(address).map(|layout| SlotIdentifier::new(layout.clone()));\n                trace!(\n                    \"{address:?} has mapping_slots {}\",\n                    mapping_slots.is_some_and(|m| m.contains_key(address))\n                );\n                let mapping_slots = mapping_slots.and_then(|m| m.get(address));\n                for (slot, value) in &account.storage {\n                    self.insert_storage_value(\n                        slot,\n                        &value.present_value,\n                        slot_identifier.as_ref(),\n                        mapping_slots,\n                    );\n                }\n            }\n        }\n    }\n\n    /// Insert values from push bytes into fuzz dictionary.\n    /// Values are collected only once for a given address.\n    /// If values are newly collected then they are removed at the end of current run.\n    fn insert_push_bytes_values(&mut self, address: &Address, account_info: &AccountInfo) {\n        if self.config.include_push_bytes\n            && !self.addresses.contains(address)\n            && let Some(code) = &account_info.code\n        {\n            self.insert_address(*address);\n            if !self.values_full() {\n                self.collect_push_bytes(ignore_metadata_hash(code.original_byte_slice()));\n            }\n        }\n    }\n\n    fn collect_push_bytes(&mut self, code: &[u8]) {\n        let len = code.len().min(PUSH_BYTE_ANALYSIS_LIMIT);\n        let code = &code[..len];\n        for inst in InstIter::new(code) {\n            // Don't add 0 to the dictionary as it's already present.\n            if !inst.immediate.is_empty()\n                && let Some(push_value) = U256::try_from_be_slice(inst.immediate)\n                && push_value != U256::ZERO\n            {\n                self.insert_value_u256(push_value);\n            }\n        }\n    }\n\n    /// Insert values from single storage slot and storage value into fuzz dictionary.\n    /// Uses [`SlotIdentifier`] to identify storage slots types.\n    fn insert_storage_value(\n        &mut self,\n        slot: &U256,\n        value: &U256,\n        slot_identifier: Option<&SlotIdentifier>,\n        mapping_slots: Option<&MappingSlots>,\n    ) {\n        let slot = B256::from(*slot);\n        let value = B256::from(*value);\n\n        // Always insert the slot itself\n        self.insert_value(slot);\n\n        // If we have a storage layout, use SlotIdentifier for better type identification.\n        if let Some(slot_identifier) = slot_identifier\n            // Identify slot type.\n            && let Some(slot_info) = slot_identifier.identify(&slot, mapping_slots)\n            && slot_info.decode(value).is_some()\n        {\n            trace!(?slot_info, \"inserting typed storage value\");\n            if !self.samples_seeded {\n                self.seed_samples();\n            }\n            self.sample_values.entry(slot_info.slot_type.dyn_sol_type).or_default().insert(value);\n        } else {\n            self.insert_value_u256(value.into());\n        }\n    }\n\n    /// Insert address into fuzz dictionary.\n    /// If address is newly collected then it is removed by index at the end of current run.\n    fn insert_address(&mut self, address: Address) {\n        if self.addresses.len() < self.config.max_fuzz_dictionary_addresses {\n            self.addresses.insert(address);\n        }\n    }\n\n    /// Insert raw value into fuzz dictionary.\n    ///\n    /// If value is newly collected then it is removed by index at the end of current run.\n    ///\n    /// Returns true if the value was inserted.\n    fn insert_value(&mut self, value: B256) -> bool {\n        let insert = !self.values_full();\n        if insert {\n            let new_value = self.state_values.insert(value);\n            let counter = if new_value { &mut self.misses } else { &mut self.hits };\n            *counter += 1;\n        }\n        insert\n    }\n\n    fn insert_value_u256(&mut self, value: U256) -> bool {\n        // Also add the value below and above the push value to the dictionary.\n        let one = U256::from(1);\n        self.insert_value(value.into())\n            | self.insert_value((value.wrapping_sub(one)).into())\n            | self.insert_value((value.wrapping_add(one)).into())\n    }\n\n    fn values_full(&self) -> bool {\n        self.state_values.len() >= self.config.max_fuzz_dictionary_values\n    }\n\n    /// Insert sample values that are reused across multiple runs.\n    /// The number of samples is limited to invariant run depth.\n    /// If collected samples limit is reached then values are inserted as regular values.\n    pub fn insert_sample_values(\n        &mut self,\n        sample_values: impl IntoIterator<Item = DynSolValue>,\n        limit: u32,\n    ) {\n        if !self.samples_seeded {\n            self.seed_samples();\n        }\n        for sample in sample_values {\n            if let (Some(sample_type), Some(sample_value)) = (sample.as_type(), sample.as_word()) {\n                if let Some(values) = self.sample_values.get_mut(&sample_type) {\n                    if values.len() < limit as usize {\n                        values.insert(sample_value);\n                    } else {\n                        // Insert as state value (will be removed at the end of the run).\n                        self.insert_value(sample_value);\n                    }\n                } else {\n                    self.sample_values.entry(sample_type).or_default().insert(sample_value);\n                }\n            }\n        }\n    }\n\n    pub fn values(&self) -> &B256IndexSet {\n        &self.state_values\n    }\n\n    pub fn len(&self) -> usize {\n        self.state_values.len()\n    }\n\n    pub fn is_empty(&self) -> bool {\n        self.state_values.is_empty()\n    }\n\n    /// Returns sample values for a given type, checking both runtime samples and literals.\n    ///\n    /// Before `seed_samples()` is called, checks both `literal_values` and `sample_values`\n    /// separately. After seeding, all literal values are merged into `sample_values`.\n    #[inline]\n    pub fn samples(&self, param_type: &DynSolType) -> Option<&B256IndexSet> {\n        // If not seeded yet, return literals\n        if !self.samples_seeded {\n            return self.literal_values.get().words.get(param_type);\n        }\n\n        self.sample_values.get(param_type)\n    }\n\n    /// Returns the collected literal strings, triggering initialization if needed.\n    #[inline]\n    pub fn ast_strings(&self) -> &IndexSet<String> {\n        &self.literal_values.get().strings\n    }\n\n    /// Returns the collected literal bytes (hex strings), triggering initialization if needed.\n    #[inline]\n    pub fn ast_bytes(&self) -> &IndexSet<Bytes> {\n        &self.literal_values.get().bytes\n    }\n\n    #[inline]\n    pub fn addresses(&self) -> &AddressIndexSet {\n        &self.addresses\n    }\n\n    /// Revert values and addresses collected during the run by truncating to initial db len.\n    pub fn revert(&mut self) {\n        self.state_values.truncate(self.db_state_values);\n        self.addresses.truncate(self.db_addresses);\n    }\n\n    pub fn log_stats(&self) {\n        trace!(\n            addresses.len = self.addresses.len(),\n            sample.len = self.sample_values.len(),\n            state.len = self.state_values.len(),\n            state.misses = self.misses,\n            state.hits = self.hits,\n            \"FuzzDictionary stats\",\n        );\n    }\n\n    #[cfg(test)]\n    /// Test-only helper to seed the dictionary with literal values.\n    pub(crate) fn seed_literals(&mut self, map: super::LiteralMaps) {\n        self.literal_values.set(map);\n    }\n}\n"
  },
  {
    "path": "crates/evm/fuzz/src/strategies/uint.rs",
    "content": "use alloy_dyn_abi::{DynSolType, DynSolValue};\nuse alloy_primitives::U256;\nuse proptest::{\n    prelude::Rng,\n    strategy::{NewTree, Strategy, ValueTree},\n    test_runner::TestRunner,\n};\n\n/// Value tree for unsigned ints (up to uint256).\npub struct UintValueTree {\n    /// Lower base\n    lo: U256,\n    /// Current value\n    curr: U256,\n    /// Higher base\n    hi: U256,\n    /// If true cannot be simplified or complexified\n    fixed: bool,\n}\n\nimpl UintValueTree {\n    /// Create a new tree\n    /// # Arguments\n    /// * `start` - Starting value for the tree\n    /// * `fixed` - If `true` the tree would only contain one element and won't be simplified.\n    fn new(start: U256, fixed: bool) -> Self {\n        Self { lo: U256::ZERO, curr: start, hi: start, fixed }\n    }\n\n    fn reposition(&mut self) -> bool {\n        let interval = self.hi - self.lo;\n        let new_mid = self.lo + interval / U256::from(2);\n\n        if new_mid == self.curr {\n            false\n        } else {\n            self.curr = new_mid;\n            true\n        }\n    }\n}\n\nimpl ValueTree for UintValueTree {\n    type Value = U256;\n\n    fn current(&self) -> Self::Value {\n        self.curr\n    }\n\n    fn simplify(&mut self) -> bool {\n        if self.fixed || (self.hi <= self.lo) {\n            return false;\n        }\n        self.hi = self.curr;\n        self.reposition()\n    }\n\n    fn complicate(&mut self) -> bool {\n        if self.fixed || (self.hi <= self.lo) {\n            return false;\n        }\n\n        self.lo = self.curr + U256::from(1);\n        self.reposition()\n    }\n}\n\n/// Value tree for unsigned ints (up to uint256).\n/// The strategy combines 3 different strategies, each assigned a specific weight:\n/// 1. Generate purely random value in a range. This will first choose bit size uniformly (up `bits`\n///    param). Then generate a value for this bit size.\n/// 2. Generate a random value around the edges (+/- 3 around 0 and max possible value)\n/// 3. Generate a value from a predefined fixtures set\n///\n/// To define uint fixtures:\n/// - return an array of possible values for a parameter named `amount` declare a function `function\n///   fixture_amount() public returns (uint32[] memory)`.\n/// - use `amount` named parameter in fuzzed test in order to include fixtures in fuzzed values\n///   `function testFuzz_uint32(uint32 amount)`.\n///\n/// If fixture is not a valid uint type then error is raised and random value generated.\n#[derive(Debug)]\npub struct UintStrategy {\n    /// Bit size of uint (e.g. 256)\n    bits: usize,\n    /// A set of fixtures to be generated\n    fixtures: Vec<DynSolValue>,\n    /// The weight for edge cases (+/- 3 around 0 and max possible value)\n    edge_weight: usize,\n    /// The weight for fixtures\n    fixtures_weight: usize,\n    /// The weight for purely random values\n    random_weight: usize,\n}\n\nimpl UintStrategy {\n    /// Create a new strategy.\n    /// #Arguments\n    /// * `bits` - Size of uint in bits\n    /// * `fixtures` - A set of fixed values to be generated (according to fixtures weight)\n    pub fn new(bits: usize, fixtures: Option<&[DynSolValue]>) -> Self {\n        Self {\n            bits,\n            fixtures: Vec::from(fixtures.unwrap_or_default()),\n            edge_weight: 10usize,\n            fixtures_weight: 40usize,\n            random_weight: 50usize,\n        }\n    }\n\n    fn generate_edge_tree(&self, runner: &mut TestRunner) -> NewTree<Self> {\n        let rng = runner.rng();\n        // Choose if we want values around 0 or max\n        let is_min = rng.random::<bool>();\n        let offset = U256::from(rng.random_range(0..4));\n        let start = if is_min { offset } else { self.type_max().saturating_sub(offset) };\n        Ok(UintValueTree::new(start, false))\n    }\n\n    fn generate_fixtures_tree(&self, runner: &mut TestRunner) -> NewTree<Self> {\n        // generate random cases if there's no fixtures\n        if self.fixtures.is_empty() {\n            return self.generate_random_tree(runner);\n        }\n\n        // Generate value tree from fixture.\n        let fixture = &self.fixtures[runner.rng().random_range(0..self.fixtures.len())];\n        if let Some(uint_fixture) = fixture.as_uint()\n            && uint_fixture.1 == self.bits\n        {\n            return Ok(UintValueTree::new(uint_fixture.0, false));\n        }\n\n        // If fixture is not a valid type, raise error and generate random value.\n        error!(\"{:?} is not a valid {} fixture\", fixture, DynSolType::Uint(self.bits));\n        self.generate_random_tree(runner)\n    }\n\n    fn generate_random_tree(&self, runner: &mut TestRunner) -> NewTree<Self> {\n        let rng = runner.rng();\n\n        // generate random number of bits uniformly\n        let bits = rng.random_range(0..=self.bits);\n\n        // init 2 128-bit randoms\n        let mut higher: u128 = rng.random_range(0..=u128::MAX);\n        let mut lower: u128 = rng.random_range(0..=u128::MAX);\n\n        // cut 2 randoms according to bits size\n        match bits {\n            x if x < 128 => {\n                lower &= (1u128 << x) - 1;\n                higher = 0;\n            }\n            x if (128..256).contains(&x) => higher &= (1u128 << (x - 128)) - 1,\n            _ => {}\n        };\n\n        // init U256 from 2 randoms\n        let mut inner: [u64; 4] = [0; 4];\n        inner[0] = lower as u64;\n        inner[1] = (lower >> 64) as u64;\n        inner[2] = higher as u64;\n        inner[3] = (higher >> 64) as u64;\n        let start: U256 = U256::from_limbs(inner);\n\n        Ok(UintValueTree::new(start, false))\n    }\n\n    fn type_max(&self) -> U256 {\n        if self.bits < 256 { (U256::from(1) << self.bits) - U256::from(1) } else { U256::MAX }\n    }\n}\n\nimpl Strategy for UintStrategy {\n    type Tree = UintValueTree;\n    type Value = U256;\n    fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> {\n        let total_weight = self.random_weight + self.fixtures_weight + self.edge_weight;\n        let bias = runner.rng().random_range(0..total_weight);\n        // randomly select one of 3 strategies\n        match bias {\n            x if x < self.edge_weight => self.generate_edge_tree(runner),\n            x if x < self.edge_weight + self.fixtures_weight => self.generate_fixtures_tree(runner),\n            _ => self.generate_random_tree(runner),\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use crate::strategies::uint::UintValueTree;\n    use alloy_primitives::U256;\n    use proptest::strategy::ValueTree;\n\n    #[test]\n    fn test_uint_tree_complicate_max() {\n        let mut uint_tree = UintValueTree::new(U256::MAX, false);\n        assert_eq!(uint_tree.hi, U256::MAX);\n        assert_eq!(uint_tree.curr, U256::MAX);\n        uint_tree.complicate();\n        assert_eq!(uint_tree.lo, U256::MIN);\n    }\n}\n"
  },
  {
    "path": "crates/evm/networks/Cargo.toml",
    "content": "[package]\nname = \"foundry-evm-networks\"\ndescription = \"Custom network features, like precompiles and custom tx types\"\n\nversion.workspace = true\nedition.workspace = true\nrust-version.workspace = true\nauthors.workspace = true\nlicense.workspace = true\nhomepage.workspace = true\nrepository.workspace = true\n\n[lints]\nworkspace = true\n\n[dependencies]\nalloy-chains.workspace = true\nalloy-eips.workspace = true\nalloy-evm.workspace = true\nalloy-op-hardforks.workspace = true\nalloy-primitives = { workspace = true, features = [\n    \"serde\",\n    \"getrandom\",\n    \"arbitrary\",\n    \"rlp\",\n] }\n\nrevm = { workspace = true, features = [\n    \"std\",\n    \"serde\",\n    \"memory_limit\",\n    \"optional_eip3607\",\n    \"optional_block_gas_limit\",\n    \"optional_no_base_fee\",\n    \"arbitrary\",\n    \"c-kzg\",\n    \"blst\",\n] }\n\nclap = { version = \"4\", features = [\"derive\", \"env\", \"unicode\", \"wrap_help\"] }\nserde.workspace = true"
  },
  {
    "path": "crates/evm/networks/README.md",
    "content": "# Custom EVM Networks\n\nThe evm-networks crate defines custom network features that are shared across Foundry's tooling (`anvil`, `forge` and \n`cast`). Currently, it supports custom precompiles, with planned support for custom transaction types.\n\n## Adding a Custom Network\nTo add configuration support for a custom network (e.g. `my_network`), add a new field to the `NetworkConfigs` struct:\n\n```rust\n    /// Enable my custom network features.\n    #[arg(help_heading = \"Networks\", long)]\n    #[serde(default)]\n    pub my_network: bool,\n```\n\nThis automatically enables:\n- `my_network = true` in foundry.toml\n- `--my-network` anvil CLI flag\n```\nNetworks:\n      --my-network\n          Enable my custom network features\n\n```\n\nIf you'd like network features to be enabled automatically based on the chain ID, update `NetworkConfigs::with_chain_id`:\n\n```rust\nimpl NetworkConfigs {\n    pub fn with_chain_id(chain_id: u64) -> Self {\n        // Enable custom network features here\n    }\n}\n```\n\n## Adding a custom precompile\n\n- Create a module for your network-specific logic, e.g., `my_network/transfer`.\n- Implement the precompile logic as a function that accepts a `PrecompileInput` containing execution context and hooks for \ninteracting with EVM state, and returns a `PrecompileResult`:\n\n```rust\npub fn custom_precompile(\n  input: alloy_evm::precompiles::PrecompileInput<'_>\n) -> revm::precompile::PrecompileResult {\n  // Your logic here\n}\n```\n\n- Enable the precompile in the `NetworkConfigs` implementation by conditionally applying it to an address:\n\n```rust\nif self.my_network {\n    precompiles.apply_precompile(&MY_NETWORK_TRANSFER_ADDRESS, move |_| {\n        Some(my_network::transfer::custom_precompile())\n    });\n}\n```"
  },
  {
    "path": "crates/evm/networks/src/celo/mod.rs",
    "content": "pub mod transfer;\n"
  },
  {
    "path": "crates/evm/networks/src/celo/transfer.rs",
    "content": "//! Celo precompile implementation for token transfers.\n//!\n//! This module implements the Celo transfer precompile that enables native token transfers from an\n//! EVM contract. The precompile is part of Celo's token duality system, allowing transfer of\n//! native tokens via ERC20.\n//!\n//! For more details, see: <https://specs.celo.org/token_duality.html#the-transfer-precompile>\n//!\n//! The transfer precompile is deployed at address 0xfd and accepts 96 bytes of input:\n//! - from address (32 bytes, left-padded)\n//! - to address (32 bytes, left-padded)\n//! - value (32 bytes, big-endian U256)\n\nuse std::borrow::Cow;\n\nuse alloy_evm::precompiles::{DynPrecompile, PrecompileInput};\nuse alloy_primitives::{Address, U256, address};\nuse revm::precompile::{PrecompileError, PrecompileId, PrecompileOutput, PrecompileResult};\n\n/// Label of the Celo transfer precompile to display in traces.\npub const CELO_TRANSFER_LABEL: &str = \"CELO_TRANSFER_PRECOMPILE\";\n\n/// Address of the Celo transfer precompile.\npub const CELO_TRANSFER_ADDRESS: Address = address!(\"0x00000000000000000000000000000000000000fd\");\n\n/// ID for the [Celo transfer precompile](CELO_TRANSFER_ADDRESS).\npub static PRECOMPILE_ID_CELO_TRANSFER: PrecompileId =\n    PrecompileId::Custom(Cow::Borrowed(\"celo transfer\"));\n\n/// Gas cost for Celo transfer precompile.\nconst CELO_TRANSFER_GAS_COST: u64 = 9000;\n\n/// Returns the Celo native transfer.\npub fn precompile() -> DynPrecompile {\n    DynPrecompile::new_stateful(PRECOMPILE_ID_CELO_TRANSFER.clone(), celo_transfer_precompile)\n}\n\n/// Celo transfer precompile implementation.\n///\n/// Uses load_account to modify balances directly, making it compatible with PrecompilesMap.\npub fn celo_transfer_precompile(mut input: PrecompileInput<'_>) -> PrecompileResult {\n    // Check minimum gas requirement\n    if input.gas < CELO_TRANSFER_GAS_COST {\n        return Err(PrecompileError::OutOfGas);\n    }\n\n    // Validate input length (must be exactly 96 bytes: 32 + 32 + 32)\n    if input.data.len() != 96 {\n        return Err(PrecompileError::Other(\n            format!(\n                \"Invalid input length for Celo transfer precompile: expected 96 bytes, got {}\",\n                input.data.len()\n            )\n            .into(),\n        ));\n    }\n\n    // Parse input: from (bytes 12-32), to (bytes 44-64), value (bytes 64-96)\n    let from_bytes = &input.data[12..32];\n    let to_bytes = &input.data[44..64];\n    let value_bytes = &input.data[64..96];\n\n    let from_address = Address::from_slice(from_bytes);\n    let to_address = Address::from_slice(to_bytes);\n    let value = U256::from_be_slice(value_bytes);\n\n    // Perform the transfer using load_account to modify balances directly\n    let internals = input.internals_mut();\n\n    // Load and check the from account balance first\n\n    let from_account = match internals.load_account(from_address) {\n        Ok(account) => account,\n        Err(e) => {\n            return Err(PrecompileError::Other(\n                format!(\"Failed to load sender account: {e:?}\").into(),\n            ));\n        }\n    };\n\n    // Check if from account has sufficient balance\n    if from_account.data.info.balance < value {\n        return Err(PrecompileError::Other(\"Insufficient balance\".into()));\n    }\n\n    let to_account = match internals.load_account(to_address) {\n        Ok(account) => account,\n        Err(e) => {\n            return Err(PrecompileError::Other(\n                format!(\"Failed to load recipient account: {e:?}\").into(),\n            ));\n        }\n    };\n\n    // Check for overflow in to account\n    if to_account.data.info.balance.checked_add(value).is_none() {\n        return Err(PrecompileError::Other(\"Balance overflow in to account\".into()));\n    }\n\n    // Transfer the value between accounts\n    internals\n        .transfer(from_address, to_address, value)\n        .map_err(|e| PrecompileError::Other(format!(\"Failed to perform transfer: {e:?}\").into()))?;\n\n    // No output data for successful transfer\n    Ok(PrecompileOutput::new(CELO_TRANSFER_GAS_COST, alloy_primitives::Bytes::new()))\n}\n"
  },
  {
    "path": "crates/evm/networks/src/lib.rs",
    "content": "//! # foundry-evm-networks\n//!\n//! Foundry EVM network configuration.\n\nuse crate::celo::transfer::{\n    CELO_TRANSFER_ADDRESS, CELO_TRANSFER_LABEL, PRECOMPILE_ID_CELO_TRANSFER,\n};\nuse alloy_chains::{\n    NamedChain,\n    NamedChain::{Chiado, Gnosis, Moonbase, Moonbeam, MoonbeamDev, Moonriver, Rsk, RskTestnet},\n};\nuse alloy_eips::eip1559::BaseFeeParams;\nuse alloy_evm::precompiles::PrecompilesMap;\nuse alloy_op_hardforks::{OpChainHardforks, OpHardforks};\nuse alloy_primitives::{Address, map::AddressHashMap};\nuse clap::Parser;\nuse serde::{Deserialize, Serialize};\nuse std::collections::BTreeMap;\n\npub mod celo;\n\n#[derive(Clone, Debug, Default, Parser, Copy, Serialize, Deserialize, PartialEq)]\npub struct NetworkConfigs {\n    /// Enable Optimism network features.\n    #[arg(help_heading = \"Networks\", long, conflicts_with = \"celo\")]\n    // Skipped from configs (forge) as there is no feature to be added yet.\n    #[serde(skip)]\n    optimism: bool,\n    /// Enable Celo network features.\n    #[arg(help_heading = \"Networks\", long, conflicts_with = \"optimism\")]\n    #[serde(default)]\n    celo: bool,\n    /// Whether to bypass prevrandao.\n    #[arg(skip)]\n    #[serde(default)]\n    bypass_prevrandao: bool,\n}\n\nimpl NetworkConfigs {\n    pub fn with_optimism() -> Self {\n        Self { optimism: true, ..Default::default() }\n    }\n\n    pub fn with_celo() -> Self {\n        Self { celo: true, ..Default::default() }\n    }\n\n    pub fn is_optimism(&self) -> bool {\n        self.optimism\n    }\n\n    /// Returns the base fee parameters for the configured network.\n    ///\n    /// For Optimism networks, returns Canyon parameters if the Canyon hardfork is active\n    /// at the given timestamp, otherwise returns pre-Canyon parameters.\n    pub fn base_fee_params(&self, timestamp: u64) -> BaseFeeParams {\n        if self.is_optimism() {\n            let op_hardforks = OpChainHardforks::op_mainnet();\n            if op_hardforks.is_canyon_active_at_timestamp(timestamp) {\n                BaseFeeParams::optimism_canyon()\n            } else {\n                BaseFeeParams::optimism()\n            }\n        } else {\n            BaseFeeParams::ethereum()\n        }\n    }\n\n    pub fn bypass_prevrandao(&self, chain_id: u64) -> bool {\n        if let Ok(\n            Moonbeam | Moonbase | Moonriver | MoonbeamDev | Rsk | RskTestnet | Gnosis | Chiado,\n        ) = NamedChain::try_from(chain_id)\n        {\n            return true;\n        }\n        self.bypass_prevrandao\n    }\n\n    pub fn is_celo(&self) -> bool {\n        self.celo\n    }\n\n    pub fn with_chain_id(mut self, chain_id: u64) -> Self {\n        if let Ok(NamedChain::Celo | NamedChain::CeloSepolia) = NamedChain::try_from(chain_id) {\n            self.celo = true;\n        }\n        self\n    }\n\n    /// Inject precompiles for configured networks.\n    pub fn inject_precompiles(self, precompiles: &mut PrecompilesMap) {\n        if self.celo {\n            precompiles.apply_precompile(&CELO_TRANSFER_ADDRESS, move |_| {\n                Some(celo::transfer::precompile())\n            });\n        }\n    }\n\n    /// Returns precompiles label for configured networks, to be used in traces.\n    pub fn precompiles_label(self) -> AddressHashMap<String> {\n        let mut labels = AddressHashMap::default();\n        if self.celo {\n            labels.insert(CELO_TRANSFER_ADDRESS, CELO_TRANSFER_LABEL.to_string());\n        }\n        labels\n    }\n\n    /// Returns precompiles for configured networks.\n    pub fn precompiles(self) -> BTreeMap<String, Address> {\n        let mut precompiles = BTreeMap::new();\n        if self.celo {\n            precompiles\n                .insert(PRECOMPILE_ID_CELO_TRANSFER.name().to_string(), CELO_TRANSFER_ADDRESS);\n        }\n        precompiles\n    }\n}\n"
  },
  {
    "path": "crates/evm/test-data/solc-obj.json",
    "content": "{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_feeToSetter\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token0\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token1\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"pair\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"PairCreated\",\"type\":\"event\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"allPairs\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"allPairsLength\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"tokenA\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"tokenB\",\"type\":\"address\"}],\"name\":\"createPair\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"pair\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"feeTo\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"feeToSetter\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"getPair\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"_feeTo\",\"type\":\"address\"}],\"name\":\"setFeeTo\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"_feeToSetter\",\"type\":\"address\"}],\"name\":\"setFeeToSetter\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"evm\":{\"bytecode\":{\"linkReferences\":{},\"object\":\"608060405234801561001057600080fd5b506040516136863803806136868339818101604052602081101561003357600080fd5b5051600180546001600160a01b0319166001600160a01b03909216919091179055613623806100636000396000f3fe608060405234801561001057600080fd5b50600436106100885760003560e01c8063a2e74af61161005b578063a2e74af6146100fd578063c9c6539614610132578063e6a439051461016d578063f46901ed146101a857610088565b8063017e7e581461008d578063094b7415146100be5780631e3dd18b146100c6578063574f2ba3146100e3575b600080fd5b6100956101db565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b6100956101f7565b610095600480360360208110156100dc57600080fd5b5035610213565b6100eb610247565b60408051918252519081900360200190f35b6101306004803603602081101561011357600080fd5b503573ffffffffffffffffffffffffffffffffffffffff1661024d565b005b6100956004803603604081101561014857600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135811691602001351661031a565b6100956004803603604081101561018357600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135811691602001351661076d565b610130600480360360208110156101be57600080fd5b503573ffffffffffffffffffffffffffffffffffffffff166107a0565b60005473ffffffffffffffffffffffffffffffffffffffff1681565b60015473ffffffffffffffffffffffffffffffffffffffff1681565b6003818154811061022057fe5b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff16905081565b60035490565b60015473ffffffffffffffffffffffffffffffffffffffff1633146102d357604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f556e697377617056323a20464f5242494444454e000000000000000000000000604482015290519081900360640190fd5b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60008173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614156103b757604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f556e697377617056323a204944454e544943414c5f4144445245535345530000604482015290519081900360640190fd5b6000808373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16106103f45783856103f7565b84845b909250905073ffffffffffffffffffffffffffffffffffffffff821661047e57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f556e697377617056323a205a45524f5f41444452455353000000000000000000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff82811660009081526002602090815260408083208585168452909152902054161561051f57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f556e697377617056323a20504149525f45584953545300000000000000000000604482015290519081900360640190fd5b6060604051806020016105319061086d565b6020820181038252601f19601f82011660405250905060008383604051602001808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660601b81526014018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660601b815260140192505050604051602081830303815290604052805190602001209050808251602084016000f5604080517f485cc95500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8781166004830152868116602483015291519297509087169163485cc9559160448082019260009290919082900301818387803b15801561065e57600080fd5b505af1158015610672573d6000803e3d6000fd5b5050505073ffffffffffffffffffffffffffffffffffffffff84811660008181526002602081815260408084208987168086529083528185208054978d167fffffffffffffffffffffffff000000000000000000000000000000000000000098891681179091559383528185208686528352818520805488168517905560038054600181018255958190527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b90950180549097168417909655925483519283529082015281517f0d3648bd0f6ba80134a33ba9275ac585d9d315f0ad8355cddefde31afa28d0e9929181900390910190a35050505092915050565b600260209081526000928352604080842090915290825290205473ffffffffffffffffffffffffffffffffffffffff1681565b60015473ffffffffffffffffffffffffffffffffffffffff16331461082657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f556e697377617056323a20464f5242494444454e000000000000000000000000604482015290519081900360640190fd5b600080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b612d748061087b8339019056fe60806040526001600c5534801561001557600080fd5b506040514690806052612d228239604080519182900360520182208282018252600a8352692ab734b9bbb0b8102b1960b11b6020938401528151808301835260018152603160f81b908401528151808401919091527fbfcc8ef98ffbf7b6c3fec7bf5185b566b9863e35a9d83acd49ad6824b5969738818301527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6606082015260808101949094523060a0808601919091528151808603909101815260c09094019052825192019190912060035550600580546001600160a01b03191633179055612c1d806101056000396000f3fe608060405234801561001057600080fd5b50600436106101b95760003560e01c80636a627842116100f9578063ba9a7a5611610097578063d21220a711610071578063d21220a7146105da578063d505accf146105e2578063dd62ed3e14610640578063fff6cae91461067b576101b9565b8063ba9a7a5614610597578063bc25cf771461059f578063c45a0155146105d2576101b9565b80637ecebe00116100d35780637ecebe00146104d757806389afcb441461050a57806395d89b4114610556578063a9059cbb1461055e576101b9565b80636a6278421461046957806370a082311461049c5780637464fc3d146104cf576101b9565b806323b872dd116101665780633644e515116101405780633644e51514610416578063485cc9551461041e5780635909c0d5146104595780635a3d549314610461576101b9565b806323b872dd146103ad57806330adf81f146103f0578063313ce567146103f8576101b9565b8063095ea7b311610197578063095ea7b3146103155780630dfe16811461036257806318160ddd14610393576101b9565b8063022c0d9f146101be57806306fdde03146102595780630902f1ac146102d6575b600080fd5b610257600480360360808110156101d457600080fd5b81359160208101359173ffffffffffffffffffffffffffffffffffffffff604083013516919081019060808101606082013564010000000081111561021857600080fd5b82018360208201111561022a57600080fd5b8035906020019184600183028401116401000000008311171561024c57600080fd5b509092509050610683565b005b610261610d57565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561029b578181015183820152602001610283565b50505050905090810190601f1680156102c85780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6102de610d90565b604080516dffffffffffffffffffffffffffff948516815292909316602083015263ffffffff168183015290519081900360600190f35b61034e6004803603604081101561032b57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135169060200135610de5565b604080519115158252519081900360200190f35b61036a610dfc565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b61039b610e18565b60408051918252519081900360200190f35b61034e600480360360608110156103c357600080fd5b5073ffffffffffffffffffffffffffffffffffffffff813581169160208101359091169060400135610e1e565b61039b610efd565b610400610f21565b6040805160ff9092168252519081900360200190f35b61039b610f26565b6102576004803603604081101561043457600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81358116916020013516610f2c565b61039b611005565b61039b61100b565b61039b6004803603602081101561047f57600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16611011565b61039b600480360360208110156104b257600080fd5b503573ffffffffffffffffffffffffffffffffffffffff166113cb565b61039b6113dd565b61039b600480360360208110156104ed57600080fd5b503573ffffffffffffffffffffffffffffffffffffffff166113e3565b61053d6004803603602081101561052057600080fd5b503573ffffffffffffffffffffffffffffffffffffffff166113f5565b6040805192835260208301919091528051918290030190f35b610261611892565b61034e6004803603604081101561057457600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81351690602001356118cb565b61039b6118d8565b610257600480360360208110156105b557600080fd5b503573ffffffffffffffffffffffffffffffffffffffff166118de565b61036a611ad4565b61036a611af0565b610257600480360360e08110156105f857600080fd5b5073ffffffffffffffffffffffffffffffffffffffff813581169160208101359091169060408101359060608101359060ff6080820135169060a08101359060c00135611b0c565b61039b6004803603604081101561065657600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81358116916020013516611dd8565b610257611df5565b600c546001146106f457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f556e697377617056323a204c4f434b4544000000000000000000000000000000604482015290519081900360640190fd5b6000600c55841515806107075750600084115b61075c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526025815260200180612b2f6025913960400191505060405180910390fd5b600080610767610d90565b5091509150816dffffffffffffffffffffffffffff168710801561079a5750806dffffffffffffffffffffffffffff1686105b6107ef576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526021815260200180612b786021913960400191505060405180910390fd5b600654600754600091829173ffffffffffffffffffffffffffffffffffffffff91821691908116908916821480159061085457508073ffffffffffffffffffffffffffffffffffffffff168973ffffffffffffffffffffffffffffffffffffffff1614155b6108bf57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f556e697377617056323a20494e56414c49445f544f0000000000000000000000604482015290519081900360640190fd5b8a156108d0576108d0828a8d611fdb565b89156108e1576108e1818a8c611fdb565b86156109c3578873ffffffffffffffffffffffffffffffffffffffff166310d1e85c338d8d8c8c6040518663ffffffff1660e01b8152600401808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001858152602001848152602001806020018281038252848482818152602001925080828437600081840152601f19601f8201169050808301925050509650505050505050600060405180830381600087803b1580156109aa57600080fd5b505af11580156109be573d6000803e3d6000fd5b505050505b604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905173ffffffffffffffffffffffffffffffffffffffff8416916370a08231916024808301926020929190829003018186803b158015610a2f57600080fd5b505afa158015610a43573d6000803e3d6000fd5b505050506040513d6020811015610a5957600080fd5b5051604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905191955073ffffffffffffffffffffffffffffffffffffffff8316916370a0823191602480820192602092909190829003018186803b158015610acb57600080fd5b505afa158015610adf573d6000803e3d6000fd5b505050506040513d6020811015610af557600080fd5b5051925060009150506dffffffffffffffffffffffffffff85168a90038311610b1f576000610b35565b89856dffffffffffffffffffffffffffff160383035b9050600089856dffffffffffffffffffffffffffff16038311610b59576000610b6f565b89856dffffffffffffffffffffffffffff160383035b90506000821180610b805750600081115b610bd5576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526024815260200180612b546024913960400191505060405180910390fd5b6000610c09610beb84600363ffffffff6121e816565b610bfd876103e863ffffffff6121e816565b9063ffffffff61226e16565b90506000610c21610beb84600363ffffffff6121e816565b9050610c59620f4240610c4d6dffffffffffffffffffffffffffff8b8116908b1663ffffffff6121e816565b9063ffffffff6121e816565b610c69838363ffffffff6121e816565b1015610cd657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f556e697377617056323a204b0000000000000000000000000000000000000000604482015290519081900360640190fd5b5050610ce4848488886122e0565b60408051838152602081018390528082018d9052606081018c9052905173ffffffffffffffffffffffffffffffffffffffff8b169133917fd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d8229181900360800190a350506001600c55505050505050505050565b6040518060400160405280600a81526020017f556e69737761702056320000000000000000000000000000000000000000000081525081565b6008546dffffffffffffffffffffffffffff808216926e0100000000000000000000000000008304909116917c0100000000000000000000000000000000000000000000000000000000900463ffffffff1690565b6000610df233848461259c565b5060015b92915050565b60065473ffffffffffffffffffffffffffffffffffffffff1681565b60005481565b73ffffffffffffffffffffffffffffffffffffffff831660009081526002602090815260408083203384529091528120547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff14610ee85773ffffffffffffffffffffffffffffffffffffffff84166000908152600260209081526040808320338452909152902054610eb6908363ffffffff61226e16565b73ffffffffffffffffffffffffffffffffffffffff851660009081526002602090815260408083203384529091529020555b610ef384848461260b565b5060019392505050565b7f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c981565b601281565b60035481565b60055473ffffffffffffffffffffffffffffffffffffffff163314610fb257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f556e697377617056323a20464f5242494444454e000000000000000000000000604482015290519081900360640190fd5b6006805473ffffffffffffffffffffffffffffffffffffffff9384167fffffffffffffffffffffffff00000000000000000000000000000000000000009182161790915560078054929093169116179055565b60095481565b600a5481565b6000600c5460011461108457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f556e697377617056323a204c4f434b4544000000000000000000000000000000604482015290519081900360640190fd5b6000600c81905580611094610d90565b50600654604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905193955091935060009273ffffffffffffffffffffffffffffffffffffffff909116916370a08231916024808301926020929190829003018186803b15801561110e57600080fd5b505afa158015611122573d6000803e3d6000fd5b505050506040513d602081101561113857600080fd5b5051600754604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905192935060009273ffffffffffffffffffffffffffffffffffffffff909216916370a0823191602480820192602092909190829003018186803b1580156111b157600080fd5b505afa1580156111c5573d6000803e3d6000fd5b505050506040513d60208110156111db57600080fd5b505190506000611201836dffffffffffffffffffffffffffff871663ffffffff61226e16565b90506000611225836dffffffffffffffffffffffffffff871663ffffffff61226e16565b9050600061123387876126ec565b600054909150806112705761125c6103e8610bfd611257878763ffffffff6121e816565b612878565b985061126b60006103e86128ca565b6112cd565b6112ca6dffffffffffffffffffffffffffff8916611294868463ffffffff6121e816565b8161129b57fe5b046dffffffffffffffffffffffffffff89166112bd868563ffffffff6121e816565b816112c457fe5b0461297a565b98505b60008911611326576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526028815260200180612bc16028913960400191505060405180910390fd5b6113308a8a6128ca565b61133c86868a8a6122e0565b811561137e5760085461137a906dffffffffffffffffffffffffffff808216916e01000000000000000000000000000090041663ffffffff6121e816565b600b555b6040805185815260208101859052815133927f4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f928290030190a250506001600c5550949695505050505050565b60016020526000908152604090205481565b600b5481565b60046020526000908152604090205481565b600080600c5460011461146957604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f556e697377617056323a204c4f434b4544000000000000000000000000000000604482015290519081900360640190fd5b6000600c81905580611479610d90565b50600654600754604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905194965092945073ffffffffffffffffffffffffffffffffffffffff9182169391169160009184916370a08231916024808301926020929190829003018186803b1580156114fb57600080fd5b505afa15801561150f573d6000803e3d6000fd5b505050506040513d602081101561152557600080fd5b5051604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905191925060009173ffffffffffffffffffffffffffffffffffffffff8516916370a08231916024808301926020929190829003018186803b15801561159957600080fd5b505afa1580156115ad573d6000803e3d6000fd5b505050506040513d60208110156115c357600080fd5b5051306000908152600160205260408120549192506115e288886126ec565b600054909150806115f9848763ffffffff6121e816565b8161160057fe5b049a5080611614848663ffffffff6121e816565b8161161b57fe5b04995060008b11801561162e575060008a115b611683576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526028815260200180612b996028913960400191505060405180910390fd5b61168d3084612992565b611698878d8d611fdb565b6116a3868d8c611fdb565b604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905173ffffffffffffffffffffffffffffffffffffffff8916916370a08231916024808301926020929190829003018186803b15801561170f57600080fd5b505afa158015611723573d6000803e3d6000fd5b505050506040513d602081101561173957600080fd5b5051604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905191965073ffffffffffffffffffffffffffffffffffffffff8816916370a0823191602480820192602092909190829003018186803b1580156117ab57600080fd5b505afa1580156117bf573d6000803e3d6000fd5b505050506040513d60208110156117d557600080fd5b505193506117e585858b8b6122e0565b811561182757600854611823906dffffffffffffffffffffffffffff808216916e01000000000000000000000000000090041663ffffffff6121e816565b600b555b604080518c8152602081018c9052815173ffffffffffffffffffffffffffffffffffffffff8f169233927fdccd412f0b1252819cb1fd330b93224ca42612892bb3f4f789976e6d81936496929081900390910190a35050505050505050506001600c81905550915091565b6040518060400160405280600681526020017f554e492d5632000000000000000000000000000000000000000000000000000081525081565b6000610df233848461260b565b6103e881565b600c5460011461194f57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f556e697377617056323a204c4f434b4544000000000000000000000000000000604482015290519081900360640190fd5b6000600c55600654600754600854604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905173ffffffffffffffffffffffffffffffffffffffff9485169490931692611a2b9285928792611a26926dffffffffffffffffffffffffffff169185916370a0823191602480820192602092909190829003018186803b1580156119ee57600080fd5b505afa158015611a02573d6000803e3d6000fd5b505050506040513d6020811015611a1857600080fd5b50519063ffffffff61226e16565b611fdb565b600854604080517f70a082310000000000000000000000000000000000000000000000000000000081523060048201529051611aca9284928792611a26926e01000000000000000000000000000090046dffffffffffffffffffffffffffff169173ffffffffffffffffffffffffffffffffffffffff8616916370a0823191602480820192602092909190829003018186803b1580156119ee57600080fd5b50506001600c5550565b60055473ffffffffffffffffffffffffffffffffffffffff1681565b60075473ffffffffffffffffffffffffffffffffffffffff1681565b42841015611b7b57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f556e697377617056323a20455850495245440000000000000000000000000000604482015290519081900360640190fd5b60035473ffffffffffffffffffffffffffffffffffffffff80891660008181526004602090815260408083208054600180820190925582517f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98186015280840196909652958d166060860152608085018c905260a085019590955260c08085018b90528151808603909101815260e0850182528051908301207f19010000000000000000000000000000000000000000000000000000000000006101008601526101028501969096526101228085019690965280518085039096018652610142840180825286519683019690962095839052610162840180825286905260ff89166101828501526101a284018890526101c28401879052519193926101e2808201937fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081019281900390910190855afa158015611cdc573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff811615801590611d5757508873ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16145b611dc257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f556e697377617056323a20494e56414c49445f5349474e415455524500000000604482015290519081900360640190fd5b611dcd89898961259c565b505050505050505050565b600260209081526000928352604080842090915290825290205481565b600c54600114611e6657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f556e697377617056323a204c4f434b4544000000000000000000000000000000604482015290519081900360640190fd5b6000600c55600654604080517f70a082310000000000000000000000000000000000000000000000000000000081523060048201529051611fd49273ffffffffffffffffffffffffffffffffffffffff16916370a08231916024808301926020929190829003018186803b158015611edd57600080fd5b505afa158015611ef1573d6000803e3d6000fd5b505050506040513d6020811015611f0757600080fd5b5051600754604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905173ffffffffffffffffffffffffffffffffffffffff909216916370a0823191602480820192602092909190829003018186803b158015611f7a57600080fd5b505afa158015611f8e573d6000803e3d6000fd5b505050506040513d6020811015611fa457600080fd5b50516008546dffffffffffffffffffffffffffff808216916e0100000000000000000000000000009004166122e0565b6001600c55565b604080518082018252601981527f7472616e7366657228616464726573732c75696e743235362900000000000000602091820152815173ffffffffffffffffffffffffffffffffffffffff85811660248301526044808301869052845180840390910181526064909201845291810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001781529251815160009460609489169392918291908083835b602083106120e157805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016120a4565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114612143576040519150601f19603f3d011682016040523d82523d6000602084013e612148565b606091505b5091509150818015612176575080511580612176575080806020019051602081101561217357600080fd5b50515b6121e157604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f556e697377617056323a205452414e534645525f4641494c4544000000000000604482015290519081900360640190fd5b5050505050565b60008115806122035750508082028282828161220057fe5b04145b610df657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f64732d6d6174682d6d756c2d6f766572666c6f77000000000000000000000000604482015290519081900360640190fd5b80820382811115610df657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f64732d6d6174682d7375622d756e646572666c6f770000000000000000000000604482015290519081900360640190fd5b6dffffffffffffffffffffffffffff841180159061230c57506dffffffffffffffffffffffffffff8311155b61237757604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f556e697377617056323a204f564552464c4f5700000000000000000000000000604482015290519081900360640190fd5b60085463ffffffff428116917c0100000000000000000000000000000000000000000000000000000000900481168203908116158015906123c757506dffffffffffffffffffffffffffff841615155b80156123e257506dffffffffffffffffffffffffffff831615155b15612492578063ffffffff16612425856123fb86612a57565b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff169063ffffffff612a7b16565b600980547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff929092169290920201905563ffffffff8116612465846123fb87612a57565b600a80547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff92909216929092020190555b600880547fffffffffffffffffffffffffffffffffffff0000000000000000000000000000166dffffffffffffffffffffffffffff888116919091177fffffffff0000000000000000000000000000ffffffffffffffffffffffffffff166e0100000000000000000000000000008883168102919091177bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167c010000000000000000000000000000000000000000000000000000000063ffffffff871602179283905560408051848416815291909304909116602082015281517f1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1929181900390910190a1505050505050565b73ffffffffffffffffffffffffffffffffffffffff808416600081815260026020908152604080832094871680845294825291829020859055815185815291517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259281900390910190a3505050565b73ffffffffffffffffffffffffffffffffffffffff8316600090815260016020526040902054612641908263ffffffff61226e16565b73ffffffffffffffffffffffffffffffffffffffff8085166000908152600160205260408082209390935590841681522054612683908263ffffffff612abc16565b73ffffffffffffffffffffffffffffffffffffffff80841660008181526001602090815260409182902094909455805185815290519193928716927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92918290030190a3505050565b600080600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663017e7e586040518163ffffffff1660e01b815260040160206040518083038186803b15801561275757600080fd5b505afa15801561276b573d6000803e3d6000fd5b505050506040513d602081101561278157600080fd5b5051600b5473ffffffffffffffffffffffffffffffffffffffff821615801594509192509061286457801561285f5760006127d86112576dffffffffffffffffffffffffffff88811690881663ffffffff6121e816565b905060006127e583612878565b90508082111561285c576000612813612804848463ffffffff61226e16565b6000549063ffffffff6121e816565b905060006128388361282c86600563ffffffff6121e816565b9063ffffffff612abc16565b9050600081838161284557fe5b04905080156128585761285887826128ca565b5050505b50505b612870565b8015612870576000600b555b505092915050565b600060038211156128bb575080600160028204015b818110156128b5578091506002818285816128a457fe5b0401816128ad57fe5b04905061288d565b506128c5565b81156128c5575060015b919050565b6000546128dd908263ffffffff612abc16565b600090815573ffffffffffffffffffffffffffffffffffffffff8316815260016020526040902054612915908263ffffffff612abc16565b73ffffffffffffffffffffffffffffffffffffffff831660008181526001602090815260408083209490945583518581529351929391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a35050565b6000818310612989578161298b565b825b9392505050565b73ffffffffffffffffffffffffffffffffffffffff82166000908152600160205260409020546129c8908263ffffffff61226e16565b73ffffffffffffffffffffffffffffffffffffffff831660009081526001602052604081209190915554612a02908263ffffffff61226e16565b600090815560408051838152905173ffffffffffffffffffffffffffffffffffffffff8516917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef919081900360200190a35050565b6dffffffffffffffffffffffffffff166e0100000000000000000000000000000290565b60006dffffffffffffffffffffffffffff82167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff841681612ab457fe5b049392505050565b80820182811015610df657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f64732d6d6174682d6164642d6f766572666c6f77000000000000000000000000604482015290519081900360640190fdfe556e697377617056323a20494e53554646494349454e545f4f55545055545f414d4f554e54556e697377617056323a20494e53554646494349454e545f494e5055545f414d4f554e54556e697377617056323a20494e53554646494349454e545f4c4951554944495459556e697377617056323a20494e53554646494349454e545f4c49515549444954595f4255524e4544556e697377617056323a20494e53554646494349454e545f4c49515549444954595f4d494e544544a265627a7a723158207dca18479e58487606bf70c79e44d8dee62353c9ee6d01f9a9d70885b8765f2264736f6c63430005100032454950373132446f6d61696e28737472696e67206e616d652c737472696e672076657273696f6e2c75696e7432353620636861696e49642c6164647265737320766572696679696e67436f6e747261637429a265627a7a723158202760f92d7fa1db6f5aa16307bad65df4ebcc8550c4b1f03755ab8dfd830c178f64736f6c63430005100032\",\"opcodes\":\"PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x40 MLOAD PUSH2 0x3686 CODESIZE SUB DUP1 PUSH2 0x3686 DUP4 CODECOPY DUP2 DUP2 ADD PUSH1 0x40 MSTORE PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x33 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP MLOAD PUSH1 0x1 DUP1 SLOAD PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB NOT AND PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB SWAP1 SWAP3 AND SWAP2 SWAP1 SWAP2 OR SWAP1 SSTORE PUSH2 0x3623 DUP1 PUSH2 0x63 PUSH1 0x0 CODECOPY PUSH1 0x0 RETURN INVALID PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x4 CALLDATASIZE LT PUSH2 0x88 JUMPI PUSH1 0x0 CALLDATALOAD PUSH1 0xE0 SHR DUP1 PUSH4 0xA2E74AF6 GT PUSH2 0x5B JUMPI DUP1 PUSH4 0xA2E74AF6 EQ PUSH2 0xFD JUMPI DUP1 PUSH4 0xC9C65396 EQ PUSH2 0x132 JUMPI DUP1 PUSH4 0xE6A43905 EQ PUSH2 0x16D JUMPI DUP1 PUSH4 0xF46901ED EQ PUSH2 0x1A8 JUMPI PUSH2 0x88 JUMP JUMPDEST DUP1 PUSH4 0x17E7E58 EQ PUSH2 0x8D JUMPI DUP1 PUSH4 0x94B7415 EQ PUSH2 0xBE JUMPI DUP1 PUSH4 0x1E3DD18B EQ PUSH2 0xC6 JUMPI DUP1 PUSH4 0x574F2BA3 EQ PUSH2 0xE3 JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x95 PUSH2 0x1DB JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP1 SWAP3 AND DUP3 MSTORE MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x20 ADD SWAP1 RETURN JUMPDEST PUSH2 0x95 PUSH2 0x1F7 JUMP JUMPDEST PUSH2 0x95 PUSH1 0x4 DUP1 CALLDATASIZE SUB PUSH1 0x20 DUP2 LT ISZERO PUSH2 0xDC JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP CALLDATALOAD PUSH2 0x213 JUMP JUMPDEST PUSH2 0xEB PUSH2 0x247 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD SWAP2 DUP3 MSTORE MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x20 ADD SWAP1 RETURN JUMPDEST PUSH2 0x130 PUSH1 0x4 DUP1 CALLDATASIZE SUB PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x113 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP CALLDATALOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH2 0x24D JUMP JUMPDEST STOP JUMPDEST PUSH2 0x95 PUSH1 0x4 DUP1 CALLDATASIZE SUB PUSH1 0x40 DUP2 LT ISZERO PUSH2 0x148 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP2 CALLDATALOAD DUP2 AND SWAP2 PUSH1 0x20 ADD CALLDATALOAD AND PUSH2 0x31A JUMP JUMPDEST PUSH2 0x95 PUSH1 0x4 DUP1 CALLDATASIZE SUB PUSH1 0x40 DUP2 LT ISZERO PUSH2 0x183 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP2 CALLDATALOAD DUP2 AND SWAP2 PUSH1 0x20 ADD CALLDATALOAD AND PUSH2 0x76D JUMP JUMPDEST PUSH2 0x130 PUSH1 0x4 DUP1 CALLDATASIZE SUB PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x1BE JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP CALLDATALOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH2 0x7A0 JUMP JUMPDEST PUSH1 0x0 SLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 JUMP JUMPDEST PUSH1 0x1 SLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 JUMP JUMPDEST PUSH1 0x3 DUP2 DUP2 SLOAD DUP2 LT PUSH2 0x220 JUMPI INVALID JUMPDEST PUSH1 0x0 SWAP2 DUP3 MSTORE PUSH1 0x20 SWAP1 SWAP2 KECCAK256 ADD SLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND SWAP1 POP DUP2 JUMP JUMPDEST PUSH1 0x3 SLOAD SWAP1 JUMP JUMPDEST PUSH1 0x1 SLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND CALLER EQ PUSH2 0x2D3 JUMPI PUSH1 0x40 DUP1 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x20 PUSH1 0x4 DUP3 ADD MSTORE PUSH1 0x14 PUSH1 0x24 DUP3 ADD MSTORE PUSH32 0x556E697377617056323A20464F5242494444454E000000000000000000000000 PUSH1 0x44 DUP3 ADD MSTORE SWAP1 MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x64 ADD SWAP1 REVERT JUMPDEST PUSH1 0x1 DUP1 SLOAD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFF0000000000000000000000000000000000000000 AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP3 SWAP1 SWAP3 AND SWAP2 SWAP1 SWAP2 OR SWAP1 SSTORE JUMP JUMPDEST PUSH1 0x0 DUP2 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP4 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND EQ ISZERO PUSH2 0x3B7 JUMPI PUSH1 0x40 DUP1 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x20 PUSH1 0x4 DUP3 ADD MSTORE PUSH1 0x1E PUSH1 0x24 DUP3 ADD MSTORE PUSH32 0x556E697377617056323A204944454E544943414C5F4144445245535345530000 PUSH1 0x44 DUP3 ADD MSTORE SWAP1 MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x64 ADD SWAP1 REVERT JUMPDEST PUSH1 0x0 DUP1 DUP4 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP6 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND LT PUSH2 0x3F4 JUMPI DUP4 DUP6 PUSH2 0x3F7 JUMP JUMPDEST DUP5 DUP5 JUMPDEST SWAP1 SWAP3 POP SWAP1 POP PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP3 AND PUSH2 0x47E JUMPI PUSH1 0x40 DUP1 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x20 PUSH1 0x4 DUP3 ADD MSTORE PUSH1 0x17 PUSH1 0x24 DUP3 ADD MSTORE PUSH32 0x556E697377617056323A205A45524F5F41444452455353000000000000000000 PUSH1 0x44 DUP3 ADD MSTORE SWAP1 MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x64 ADD SWAP1 REVERT JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP3 DUP2 AND PUSH1 0x0 SWAP1 DUP2 MSTORE PUSH1 0x2 PUSH1 0x20 SWAP1 DUP2 MSTORE PUSH1 0x40 DUP1 DUP4 KECCAK256 DUP6 DUP6 AND DUP5 MSTORE SWAP1 SWAP2 MSTORE SWAP1 KECCAK256 SLOAD AND ISZERO PUSH2 0x51F JUMPI PUSH1 0x40 DUP1 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x20 PUSH1 0x4 DUP3 ADD MSTORE PUSH1 0x16 PUSH1 0x24 DUP3 ADD MSTORE PUSH32 0x556E697377617056323A20504149525F45584953545300000000000000000000 PUSH1 0x44 DUP3 ADD MSTORE SWAP1 MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x64 ADD SWAP1 REVERT JUMPDEST PUSH1 0x60 PUSH1 0x40 MLOAD DUP1 PUSH1 0x20 ADD PUSH2 0x531 SWAP1 PUSH2 0x86D JUMP JUMPDEST PUSH1 0x20 DUP3 ADD DUP2 SUB DUP3 MSTORE PUSH1 0x1F NOT PUSH1 0x1F DUP3 ADD AND PUSH1 0x40 MSTORE POP SWAP1 POP PUSH1 0x0 DUP4 DUP4 PUSH1 0x40 MLOAD PUSH1 0x20 ADD DUP1 DUP4 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH1 0x60 SHL DUP2 MSTORE PUSH1 0x14 ADD DUP3 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH1 0x60 SHL DUP2 MSTORE PUSH1 0x14 ADD SWAP3 POP POP POP PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE DUP1 MLOAD SWAP1 PUSH1 0x20 ADD KECCAK256 SWAP1 POP DUP1 DUP3 MLOAD PUSH1 0x20 DUP5 ADD PUSH1 0x0 CREATE2 PUSH1 0x40 DUP1 MLOAD PUSH32 0x485CC95500000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP8 DUP2 AND PUSH1 0x4 DUP4 ADD MSTORE DUP7 DUP2 AND PUSH1 0x24 DUP4 ADD MSTORE SWAP2 MLOAD SWAP3 SWAP8 POP SWAP1 DUP8 AND SWAP2 PUSH4 0x485CC955 SWAP2 PUSH1 0x44 DUP1 DUP3 ADD SWAP3 PUSH1 0x0 SWAP3 SWAP1 SWAP2 SWAP1 DUP3 SWAP1 SUB ADD DUP2 DUP4 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x65E JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0x672 JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP5 DUP2 AND PUSH1 0x0 DUP2 DUP2 MSTORE PUSH1 0x2 PUSH1 0x20 DUP2 DUP2 MSTORE PUSH1 0x40 DUP1 DUP5 KECCAK256 DUP10 DUP8 AND DUP1 DUP7 MSTORE SWAP1 DUP4 MSTORE DUP2 DUP6 KECCAK256 DUP1 SLOAD SWAP8 DUP14 AND PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFF0000000000000000000000000000000000000000 SWAP9 DUP10 AND DUP2 OR SWAP1 SWAP2 SSTORE SWAP4 DUP4 MSTORE DUP2 DUP6 KECCAK256 DUP7 DUP7 MSTORE DUP4 MSTORE DUP2 DUP6 KECCAK256 DUP1 SLOAD DUP9 AND DUP6 OR SWAP1 SSTORE PUSH1 0x3 DUP1 SLOAD PUSH1 0x1 DUP2 ADD DUP3 SSTORE SWAP6 DUP2 SWAP1 MSTORE PUSH32 0xC2575A0E9E593C00F959F8C92F12DB2869C3395A3B0502D05E2516446F71F85B SWAP1 SWAP6 ADD DUP1 SLOAD SWAP1 SWAP8 AND DUP5 OR SWAP1 SWAP7 SSTORE SWAP3 SLOAD DUP4 MLOAD SWAP3 DUP4 MSTORE SWAP1 DUP3 ADD MSTORE DUP2 MLOAD PUSH32 0xD3648BD0F6BA80134A33BA9275AC585D9D315F0AD8355CDDEFDE31AFA28D0E9 SWAP3 SWAP2 DUP2 SWAP1 SUB SWAP1 SWAP2 ADD SWAP1 LOG3 POP POP POP POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x2 PUSH1 0x20 SWAP1 DUP2 MSTORE PUSH1 0x0 SWAP3 DUP4 MSTORE PUSH1 0x40 DUP1 DUP5 KECCAK256 SWAP1 SWAP2 MSTORE SWAP1 DUP3 MSTORE SWAP1 KECCAK256 SLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 JUMP JUMPDEST PUSH1 0x1 SLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND CALLER EQ PUSH2 0x826 JUMPI PUSH1 0x40 DUP1 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x20 PUSH1 0x4 DUP3 ADD MSTORE PUSH1 0x14 PUSH1 0x24 DUP3 ADD MSTORE PUSH32 0x556E697377617056323A20464F5242494444454E000000000000000000000000 PUSH1 0x44 DUP3 ADD MSTORE SWAP1 MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x64 ADD SWAP1 REVERT JUMPDEST PUSH1 0x0 DUP1 SLOAD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFF0000000000000000000000000000000000000000 AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP3 SWAP1 SWAP3 AND SWAP2 SWAP1 SWAP2 OR SWAP1 SSTORE JUMP JUMPDEST PUSH2 0x2D74 DUP1 PUSH2 0x87B DUP4 CODECOPY ADD SWAP1 JUMP INVALID PUSH1 0x80 PUSH1 0x40 MSTORE PUSH1 0x1 PUSH1 0xC SSTORE CALLVALUE DUP1 ISZERO PUSH2 0x15 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x40 MLOAD CHAINID SWAP1 DUP1 PUSH1 0x52 PUSH2 0x2D22 DUP3 CODECOPY PUSH1 0x40 DUP1 MLOAD SWAP2 DUP3 SWAP1 SUB PUSH1 0x52 ADD DUP3 KECCAK256 DUP3 DUP3 ADD DUP3 MSTORE PUSH1 0xA DUP4 MSTORE PUSH10 0x2AB734B9BBB0B8102B19 PUSH1 0xB1 SHL PUSH1 0x20 SWAP4 DUP5 ADD MSTORE DUP2 MLOAD DUP1 DUP4 ADD DUP4 MSTORE PUSH1 0x1 DUP2 MSTORE PUSH1 0x31 PUSH1 0xF8 SHL SWAP1 DUP5 ADD MSTORE DUP2 MLOAD DUP1 DUP5 ADD SWAP2 SWAP1 SWAP2 MSTORE PUSH32 0xBFCC8EF98FFBF7B6C3FEC7BF5185B566B9863E35A9D83ACD49AD6824B5969738 DUP2 DUP4 ADD MSTORE PUSH32 0xC89EFDAA54C0F20C7ADF612882DF0950F5A951637E0307CDCB4C672F298B8BC6 PUSH1 0x60 DUP3 ADD MSTORE PUSH1 0x80 DUP2 ADD SWAP5 SWAP1 SWAP5 MSTORE ADDRESS PUSH1 0xA0 DUP1 DUP7 ADD SWAP2 SWAP1 SWAP2 MSTORE DUP2 MLOAD DUP1 DUP7 SUB SWAP1 SWAP2 ADD DUP2 MSTORE PUSH1 0xC0 SWAP1 SWAP5 ADD SWAP1 MSTORE DUP3 MLOAD SWAP3 ADD SWAP2 SWAP1 SWAP2 KECCAK256 PUSH1 0x3 SSTORE POP PUSH1 0x5 DUP1 SLOAD PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB NOT AND CALLER OR SWAP1 SSTORE PUSH2 0x2C1D DUP1 PUSH2 0x105 PUSH1 0x0 CODECOPY PUSH1 0x0 RETURN INVALID PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x4 CALLDATASIZE LT PUSH2 0x1B9 JUMPI PUSH1 0x0 CALLDATALOAD PUSH1 0xE0 SHR DUP1 PUSH4 0x6A627842 GT PUSH2 0xF9 JUMPI DUP1 PUSH4 0xBA9A7A56 GT PUSH2 0x97 JUMPI DUP1 PUSH4 0xD21220A7 GT PUSH2 0x71 JUMPI DUP1 PUSH4 0xD21220A7 EQ PUSH2 0x5DA JUMPI DUP1 PUSH4 0xD505ACCF EQ PUSH2 0x5E2 JUMPI DUP1 PUSH4 0xDD62ED3E EQ PUSH2 0x640 JUMPI DUP1 PUSH4 0xFFF6CAE9 EQ PUSH2 0x67B JUMPI PUSH2 0x1B9 JUMP JUMPDEST DUP1 PUSH4 0xBA9A7A56 EQ PUSH2 0x597 JUMPI DUP1 PUSH4 0xBC25CF77 EQ PUSH2 0x59F JUMPI DUP1 PUSH4 0xC45A0155 EQ PUSH2 0x5D2 JUMPI PUSH2 0x1B9 JUMP JUMPDEST DUP1 PUSH4 0x7ECEBE00 GT PUSH2 0xD3 JUMPI DUP1 PUSH4 0x7ECEBE00 EQ PUSH2 0x4D7 JUMPI DUP1 PUSH4 0x89AFCB44 EQ PUSH2 0x50A JUMPI DUP1 PUSH4 0x95D89B41 EQ PUSH2 0x556 JUMPI DUP1 PUSH4 0xA9059CBB EQ PUSH2 0x55E JUMPI PUSH2 0x1B9 JUMP JUMPDEST DUP1 PUSH4 0x6A627842 EQ PUSH2 0x469 JUMPI DUP1 PUSH4 0x70A08231 EQ PUSH2 0x49C JUMPI DUP1 PUSH4 0x7464FC3D EQ PUSH2 0x4CF JUMPI PUSH2 0x1B9 JUMP JUMPDEST DUP1 PUSH4 0x23B872DD GT PUSH2 0x166 JUMPI DUP1 PUSH4 0x3644E515 GT PUSH2 0x140 JUMPI DUP1 PUSH4 0x3644E515 EQ PUSH2 0x416 JUMPI DUP1 PUSH4 0x485CC955 EQ PUSH2 0x41E JUMPI DUP1 PUSH4 0x5909C0D5 EQ PUSH2 0x459 JUMPI DUP1 PUSH4 0x5A3D5493 EQ PUSH2 0x461 JUMPI PUSH2 0x1B9 JUMP JUMPDEST DUP1 PUSH4 0x23B872DD EQ PUSH2 0x3AD JUMPI DUP1 PUSH4 0x30ADF81F EQ PUSH2 0x3F0 JUMPI DUP1 PUSH4 0x313CE567 EQ PUSH2 0x3F8 JUMPI PUSH2 0x1B9 JUMP JUMPDEST DUP1 PUSH4 0x95EA7B3 GT PUSH2 0x197 JUMPI DUP1 PUSH4 0x95EA7B3 EQ PUSH2 0x315 JUMPI DUP1 PUSH4 0xDFE1681 EQ PUSH2 0x362 JUMPI DUP1 PUSH4 0x18160DDD EQ PUSH2 0x393 JUMPI PUSH2 0x1B9 JUMP JUMPDEST DUP1 PUSH4 0x22C0D9F EQ PUSH2 0x1BE JUMPI DUP1 PUSH4 0x6FDDE03 EQ PUSH2 0x259 JUMPI DUP1 PUSH4 0x902F1AC EQ PUSH2 0x2D6 JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x257 PUSH1 0x4 DUP1 CALLDATASIZE SUB PUSH1 0x80 DUP2 LT ISZERO PUSH2 0x1D4 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 CALLDATALOAD SWAP2 PUSH1 0x20 DUP2 ADD CALLDATALOAD SWAP2 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF PUSH1 0x40 DUP4 ADD CALLDATALOAD AND SWAP2 SWAP1 DUP2 ADD SWAP1 PUSH1 0x80 DUP2 ADD PUSH1 0x60 DUP3 ADD CALLDATALOAD PUSH5 0x100000000 DUP2 GT ISZERO PUSH2 0x218 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP3 ADD DUP4 PUSH1 0x20 DUP3 ADD GT ISZERO PUSH2 0x22A JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP1 CALLDATALOAD SWAP1 PUSH1 0x20 ADD SWAP2 DUP5 PUSH1 0x1 DUP4 MUL DUP5 ADD GT PUSH5 0x100000000 DUP4 GT OR ISZERO PUSH2 0x24C JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP SWAP1 SWAP3 POP SWAP1 POP PUSH2 0x683 JUMP JUMPDEST STOP JUMPDEST PUSH2 0x261 PUSH2 0xD57 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH1 0x20 DUP1 DUP3 MSTORE DUP4 MLOAD DUP2 DUP4 ADD MSTORE DUP4 MLOAD SWAP2 SWAP3 DUP4 SWAP3 SWAP1 DUP4 ADD SWAP2 DUP6 ADD SWAP1 DUP1 DUP4 DUP4 PUSH1 0x0 JUMPDEST DUP4 DUP2 LT ISZERO PUSH2 0x29B JUMPI DUP2 DUP2 ADD MLOAD DUP4 DUP3 ADD MSTORE PUSH1 0x20 ADD PUSH2 0x283 JUMP JUMPDEST POP POP POP POP SWAP1 POP SWAP1 DUP2 ADD SWAP1 PUSH1 0x1F AND DUP1 ISZERO PUSH2 0x2C8 JUMPI DUP1 DUP3 SUB DUP1 MLOAD PUSH1 0x1 DUP4 PUSH1 0x20 SUB PUSH2 0x100 EXP SUB NOT AND DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP JUMPDEST POP SWAP3 POP POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH2 0x2DE PUSH2 0xD90 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH14 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP5 DUP6 AND DUP2 MSTORE SWAP3 SWAP1 SWAP4 AND PUSH1 0x20 DUP4 ADD MSTORE PUSH4 0xFFFFFFFF AND DUP2 DUP4 ADD MSTORE SWAP1 MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x60 ADD SWAP1 RETURN JUMPDEST PUSH2 0x34E PUSH1 0x4 DUP1 CALLDATASIZE SUB PUSH1 0x40 DUP2 LT ISZERO PUSH2 0x32B JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP2 CALLDATALOAD AND SWAP1 PUSH1 0x20 ADD CALLDATALOAD PUSH2 0xDE5 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD SWAP2 ISZERO ISZERO DUP3 MSTORE MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x20 ADD SWAP1 RETURN JUMPDEST PUSH2 0x36A PUSH2 0xDFC JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP1 SWAP3 AND DUP3 MSTORE MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x20 ADD SWAP1 RETURN JUMPDEST PUSH2 0x39B PUSH2 0xE18 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD SWAP2 DUP3 MSTORE MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x20 ADD SWAP1 RETURN JUMPDEST PUSH2 0x34E PUSH1 0x4 DUP1 CALLDATASIZE SUB PUSH1 0x60 DUP2 LT ISZERO PUSH2 0x3C3 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP2 CALLDATALOAD DUP2 AND SWAP2 PUSH1 0x20 DUP2 ADD CALLDATALOAD SWAP1 SWAP2 AND SWAP1 PUSH1 0x40 ADD CALLDATALOAD PUSH2 0xE1E JUMP JUMPDEST PUSH2 0x39B PUSH2 0xEFD JUMP JUMPDEST PUSH2 0x400 PUSH2 0xF21 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH1 0xFF SWAP1 SWAP3 AND DUP3 MSTORE MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x20 ADD SWAP1 RETURN JUMPDEST PUSH2 0x39B PUSH2 0xF26 JUMP JUMPDEST PUSH2 0x257 PUSH1 0x4 DUP1 CALLDATASIZE SUB PUSH1 0x40 DUP2 LT ISZERO PUSH2 0x434 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP2 CALLDATALOAD DUP2 AND SWAP2 PUSH1 0x20 ADD CALLDATALOAD AND PUSH2 0xF2C JUMP JUMPDEST PUSH2 0x39B PUSH2 0x1005 JUMP JUMPDEST PUSH2 0x39B PUSH2 0x100B JUMP JUMPDEST PUSH2 0x39B PUSH1 0x4 DUP1 CALLDATASIZE SUB PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x47F JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP CALLDATALOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH2 0x1011 JUMP JUMPDEST PUSH2 0x39B PUSH1 0x4 DUP1 CALLDATASIZE SUB PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x4B2 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP CALLDATALOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH2 0x13CB JUMP JUMPDEST PUSH2 0x39B PUSH2 0x13DD JUMP JUMPDEST PUSH2 0x39B PUSH1 0x4 DUP1 CALLDATASIZE SUB PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x4ED JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP CALLDATALOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH2 0x13E3 JUMP JUMPDEST PUSH2 0x53D PUSH1 0x4 DUP1 CALLDATASIZE SUB PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x520 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP CALLDATALOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH2 0x13F5 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD SWAP3 DUP4 MSTORE PUSH1 0x20 DUP4 ADD SWAP2 SWAP1 SWAP2 MSTORE DUP1 MLOAD SWAP2 DUP3 SWAP1 SUB ADD SWAP1 RETURN JUMPDEST PUSH2 0x261 PUSH2 0x1892 JUMP JUMPDEST PUSH2 0x34E PUSH1 0x4 DUP1 CALLDATASIZE SUB PUSH1 0x40 DUP2 LT ISZERO PUSH2 0x574 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP2 CALLDATALOAD AND SWAP1 PUSH1 0x20 ADD CALLDATALOAD PUSH2 0x18CB JUMP JUMPDEST PUSH2 0x39B PUSH2 0x18D8 JUMP JUMPDEST PUSH2 0x257 PUSH1 0x4 DUP1 CALLDATASIZE SUB PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x5B5 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP CALLDATALOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH2 0x18DE JUMP JUMPDEST PUSH2 0x36A PUSH2 0x1AD4 JUMP JUMPDEST PUSH2 0x36A PUSH2 0x1AF0 JUMP JUMPDEST PUSH2 0x257 PUSH1 0x4 DUP1 CALLDATASIZE SUB PUSH1 0xE0 DUP2 LT ISZERO PUSH2 0x5F8 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP2 CALLDATALOAD DUP2 AND SWAP2 PUSH1 0x20 DUP2 ADD CALLDATALOAD SWAP1 SWAP2 AND SWAP1 PUSH1 0x40 DUP2 ADD CALLDATALOAD SWAP1 PUSH1 0x60 DUP2 ADD CALLDATALOAD SWAP1 PUSH1 0xFF PUSH1 0x80 DUP3 ADD CALLDATALOAD AND SWAP1 PUSH1 0xA0 DUP2 ADD CALLDATALOAD SWAP1 PUSH1 0xC0 ADD CALLDATALOAD PUSH2 0x1B0C JUMP JUMPDEST PUSH2 0x39B PUSH1 0x4 DUP1 CALLDATASIZE SUB PUSH1 0x40 DUP2 LT ISZERO PUSH2 0x656 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP2 CALLDATALOAD DUP2 AND SWAP2 PUSH1 0x20 ADD CALLDATALOAD AND PUSH2 0x1DD8 JUMP JUMPDEST PUSH2 0x257 PUSH2 0x1DF5 JUMP JUMPDEST PUSH1 0xC SLOAD PUSH1 0x1 EQ PUSH2 0x6F4 JUMPI PUSH1 0x40 DUP1 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x20 PUSH1 0x4 DUP3 ADD MSTORE PUSH1 0x11 PUSH1 0x24 DUP3 ADD MSTORE PUSH32 0x556E697377617056323A204C4F434B4544000000000000000000000000000000 PUSH1 0x44 DUP3 ADD MSTORE SWAP1 MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x64 ADD SWAP1 REVERT JUMPDEST PUSH1 0x0 PUSH1 0xC SSTORE DUP5 ISZERO ISZERO DUP1 PUSH2 0x707 JUMPI POP PUSH1 0x0 DUP5 GT JUMPDEST PUSH2 0x75C JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD DUP1 DUP1 PUSH1 0x20 ADD DUP3 DUP2 SUB DUP3 MSTORE PUSH1 0x25 DUP2 MSTORE PUSH1 0x20 ADD DUP1 PUSH2 0x2B2F PUSH1 0x25 SWAP2 CODECOPY PUSH1 0x40 ADD SWAP2 POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 REVERT JUMPDEST PUSH1 0x0 DUP1 PUSH2 0x767 PUSH2 0xD90 JUMP JUMPDEST POP SWAP2 POP SWAP2 POP DUP2 PUSH14 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP8 LT DUP1 ISZERO PUSH2 0x79A JUMPI POP DUP1 PUSH14 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP7 LT JUMPDEST PUSH2 0x7EF JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD DUP1 DUP1 PUSH1 0x20 ADD DUP3 DUP2 SUB DUP3 MSTORE PUSH1 0x21 DUP2 MSTORE PUSH1 0x20 ADD DUP1 PUSH2 0x2B78 PUSH1 0x21 SWAP2 CODECOPY PUSH1 0x40 ADD SWAP2 POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 REVERT JUMPDEST PUSH1 0x6 SLOAD PUSH1 0x7 SLOAD PUSH1 0x0 SWAP2 DUP3 SWAP2 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP2 DUP3 AND SWAP2 SWAP1 DUP2 AND SWAP1 DUP10 AND DUP3 EQ DUP1 ISZERO SWAP1 PUSH2 0x854 JUMPI POP DUP1 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP10 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND EQ ISZERO JUMPDEST PUSH2 0x8BF JUMPI PUSH1 0x40 DUP1 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x20 PUSH1 0x4 DUP3 ADD MSTORE PUSH1 0x15 PUSH1 0x24 DUP3 ADD MSTORE PUSH32 0x556E697377617056323A20494E56414C49445F544F0000000000000000000000 PUSH1 0x44 DUP3 ADD MSTORE SWAP1 MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x64 ADD SWAP1 REVERT JUMPDEST DUP11 ISZERO PUSH2 0x8D0 JUMPI PUSH2 0x8D0 DUP3 DUP11 DUP14 PUSH2 0x1FDB JUMP JUMPDEST DUP10 ISZERO PUSH2 0x8E1 JUMPI PUSH2 0x8E1 DUP2 DUP11 DUP13 PUSH2 0x1FDB JUMP JUMPDEST DUP7 ISZERO PUSH2 0x9C3 JUMPI DUP9 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH4 0x10D1E85C CALLER DUP14 DUP14 DUP13 DUP13 PUSH1 0x40 MLOAD DUP7 PUSH4 0xFFFFFFFF AND PUSH1 0xE0 SHL DUP2 MSTORE PUSH1 0x4 ADD DUP1 DUP7 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD DUP6 DUP2 MSTORE PUSH1 0x20 ADD DUP5 DUP2 MSTORE PUSH1 0x20 ADD DUP1 PUSH1 0x20 ADD DUP3 DUP2 SUB DUP3 MSTORE DUP5 DUP5 DUP3 DUP2 DUP2 MSTORE PUSH1 0x20 ADD SWAP3 POP DUP1 DUP3 DUP5 CALLDATACOPY PUSH1 0x0 DUP2 DUP5 ADD MSTORE PUSH1 0x1F NOT PUSH1 0x1F DUP3 ADD AND SWAP1 POP DUP1 DUP4 ADD SWAP3 POP POP POP SWAP7 POP POP POP POP POP POP POP PUSH1 0x0 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 PUSH1 0x0 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x9AA JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0x9BE JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH32 0x70A0823100000000000000000000000000000000000000000000000000000000 DUP2 MSTORE ADDRESS PUSH1 0x4 DUP3 ADD MSTORE SWAP1 MLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP5 AND SWAP2 PUSH4 0x70A08231 SWAP2 PUSH1 0x24 DUP1 DUP4 ADD SWAP3 PUSH1 0x20 SWAP3 SWAP2 SWAP1 DUP3 SWAP1 SUB ADD DUP2 DUP7 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0xA2F JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS STATICCALL ISZERO DUP1 ISZERO PUSH2 0xA43 JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH1 0x40 MLOAD RETURNDATASIZE PUSH1 0x20 DUP2 LT ISZERO PUSH2 0xA59 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP MLOAD PUSH1 0x40 DUP1 MLOAD PUSH32 0x70A0823100000000000000000000000000000000000000000000000000000000 DUP2 MSTORE ADDRESS PUSH1 0x4 DUP3 ADD MSTORE SWAP1 MLOAD SWAP2 SWAP6 POP PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP4 AND SWAP2 PUSH4 0x70A08231 SWAP2 PUSH1 0x24 DUP1 DUP3 ADD SWAP3 PUSH1 0x20 SWAP3 SWAP1 SWAP2 SWAP1 DUP3 SWAP1 SUB ADD DUP2 DUP7 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0xACB JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS STATICCALL ISZERO DUP1 ISZERO PUSH2 0xADF JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH1 0x40 MLOAD RETURNDATASIZE PUSH1 0x20 DUP2 LT ISZERO PUSH2 0xAF5 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP MLOAD SWAP3 POP PUSH1 0x0 SWAP2 POP POP PUSH14 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP6 AND DUP11 SWAP1 SUB DUP4 GT PUSH2 0xB1F JUMPI PUSH1 0x0 PUSH2 0xB35 JUMP JUMPDEST DUP10 DUP6 PUSH14 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND SUB DUP4 SUB JUMPDEST SWAP1 POP PUSH1 0x0 DUP10 DUP6 PUSH14 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND SUB DUP4 GT PUSH2 0xB59 JUMPI PUSH1 0x0 PUSH2 0xB6F JUMP JUMPDEST DUP10 DUP6 PUSH14 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND SUB DUP4 SUB JUMPDEST SWAP1 POP PUSH1 0x0 DUP3 GT DUP1 PUSH2 0xB80 JUMPI POP PUSH1 0x0 DUP2 GT JUMPDEST PUSH2 0xBD5 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD DUP1 DUP1 PUSH1 0x20 ADD DUP3 DUP2 SUB DUP3 MSTORE PUSH1 0x24 DUP2 MSTORE PUSH1 0x20 ADD DUP1 PUSH2 0x2B54 PUSH1 0x24 SWAP2 CODECOPY PUSH1 0x40 ADD SWAP2 POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 REVERT JUMPDEST PUSH1 0x0 PUSH2 0xC09 PUSH2 0xBEB DUP5 PUSH1 0x3 PUSH4 0xFFFFFFFF PUSH2 0x21E8 AND JUMP JUMPDEST PUSH2 0xBFD DUP8 PUSH2 0x3E8 PUSH4 0xFFFFFFFF PUSH2 0x21E8 AND JUMP JUMPDEST SWAP1 PUSH4 0xFFFFFFFF PUSH2 0x226E AND JUMP JUMPDEST SWAP1 POP PUSH1 0x0 PUSH2 0xC21 PUSH2 0xBEB DUP5 PUSH1 0x3 PUSH4 0xFFFFFFFF PUSH2 0x21E8 AND JUMP JUMPDEST SWAP1 POP PUSH2 0xC59 PUSH3 0xF4240 PUSH2 0xC4D PUSH14 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP12 DUP2 AND SWAP1 DUP12 AND PUSH4 0xFFFFFFFF PUSH2 0x21E8 AND JUMP JUMPDEST SWAP1 PUSH4 0xFFFFFFFF PUSH2 0x21E8 AND JUMP JUMPDEST PUSH2 0xC69 DUP4 DUP4 PUSH4 0xFFFFFFFF PUSH2 0x21E8 AND JUMP JUMPDEST LT ISZERO PUSH2 0xCD6 JUMPI PUSH1 0x40 DUP1 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x20 PUSH1 0x4 DUP3 ADD MSTORE PUSH1 0xC PUSH1 0x24 DUP3 ADD MSTORE PUSH32 0x556E697377617056323A204B0000000000000000000000000000000000000000 PUSH1 0x44 DUP3 ADD MSTORE SWAP1 MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x64 ADD SWAP1 REVERT JUMPDEST POP POP PUSH2 0xCE4 DUP5 DUP5 DUP9 DUP9 PUSH2 0x22E0 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD DUP4 DUP2 MSTORE PUSH1 0x20 DUP2 ADD DUP4 SWAP1 MSTORE DUP1 DUP3 ADD DUP14 SWAP1 MSTORE PUSH1 0x60 DUP2 ADD DUP13 SWAP1 MSTORE SWAP1 MLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP12 AND SWAP2 CALLER SWAP2 PUSH32 0xD78AD95FA46C994B6551D0DA85FC275FE613CE37657FB8D5E3D130840159D822 SWAP2 DUP2 SWAP1 SUB PUSH1 0x80 ADD SWAP1 LOG3 POP POP PUSH1 0x1 PUSH1 0xC SSTORE POP POP POP POP POP POP POP POP POP JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 PUSH1 0x40 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0xA DUP2 MSTORE PUSH1 0x20 ADD PUSH32 0x556E697377617020563200000000000000000000000000000000000000000000 DUP2 MSTORE POP DUP2 JUMP JUMPDEST PUSH1 0x8 SLOAD PUSH14 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP1 DUP3 AND SWAP3 PUSH15 0x10000000000000000000000000000 DUP4 DIV SWAP1 SWAP2 AND SWAP2 PUSH29 0x100000000000000000000000000000000000000000000000000000000 SWAP1 DIV PUSH4 0xFFFFFFFF AND SWAP1 JUMP JUMPDEST PUSH1 0x0 PUSH2 0xDF2 CALLER DUP5 DUP5 PUSH2 0x259C JUMP JUMPDEST POP PUSH1 0x1 JUMPDEST SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x6 SLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 JUMP JUMPDEST PUSH1 0x0 SLOAD DUP2 JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP4 AND PUSH1 0x0 SWAP1 DUP2 MSTORE PUSH1 0x2 PUSH1 0x20 SWAP1 DUP2 MSTORE PUSH1 0x40 DUP1 DUP4 KECCAK256 CALLER DUP5 MSTORE SWAP1 SWAP2 MSTORE DUP2 KECCAK256 SLOAD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF EQ PUSH2 0xEE8 JUMPI PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP5 AND PUSH1 0x0 SWAP1 DUP2 MSTORE PUSH1 0x2 PUSH1 0x20 SWAP1 DUP2 MSTORE PUSH1 0x40 DUP1 DUP4 KECCAK256 CALLER DUP5 MSTORE SWAP1 SWAP2 MSTORE SWAP1 KECCAK256 SLOAD PUSH2 0xEB6 SWAP1 DUP4 PUSH4 0xFFFFFFFF PUSH2 0x226E AND JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP6 AND PUSH1 0x0 SWAP1 DUP2 MSTORE PUSH1 0x2 PUSH1 0x20 SWAP1 DUP2 MSTORE PUSH1 0x40 DUP1 DUP4 KECCAK256 CALLER DUP5 MSTORE SWAP1 SWAP2 MSTORE SWAP1 KECCAK256 SSTORE JUMPDEST PUSH2 0xEF3 DUP5 DUP5 DUP5 PUSH2 0x260B JUMP JUMPDEST POP PUSH1 0x1 SWAP4 SWAP3 POP POP POP JUMP JUMPDEST PUSH32 0x6E71EDAE12B1B97F4D1F60370FEF10105FA2FAAE0126114A169C64845D6126C9 DUP2 JUMP JUMPDEST PUSH1 0x12 DUP2 JUMP JUMPDEST PUSH1 0x3 SLOAD DUP2 JUMP JUMPDEST PUSH1 0x5 SLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND CALLER EQ PUSH2 0xFB2 JUMPI PUSH1 0x40 DUP1 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x20 PUSH1 0x4 DUP3 ADD MSTORE PUSH1 0x14 PUSH1 0x24 DUP3 ADD MSTORE PUSH32 0x556E697377617056323A20464F5242494444454E000000000000000000000000 PUSH1 0x44 DUP3 ADD MSTORE SWAP1 MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x64 ADD SWAP1 REVERT JUMPDEST PUSH1 0x6 DUP1 SLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP4 DUP5 AND PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFF0000000000000000000000000000000000000000 SWAP2 DUP3 AND OR SWAP1 SWAP2 SSTORE PUSH1 0x7 DUP1 SLOAD SWAP3 SWAP1 SWAP4 AND SWAP2 AND OR SWAP1 SSTORE JUMP JUMPDEST PUSH1 0x9 SLOAD DUP2 JUMP JUMPDEST PUSH1 0xA SLOAD DUP2 JUMP JUMPDEST PUSH1 0x0 PUSH1 0xC SLOAD PUSH1 0x1 EQ PUSH2 0x1084 JUMPI PUSH1 0x40 DUP1 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x20 PUSH1 0x4 DUP3 ADD MSTORE PUSH1 0x11 PUSH1 0x24 DUP3 ADD MSTORE PUSH32 0x556E697377617056323A204C4F434B4544000000000000000000000000000000 PUSH1 0x44 DUP3 ADD MSTORE SWAP1 MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x64 ADD SWAP1 REVERT JUMPDEST PUSH1 0x0 PUSH1 0xC DUP2 SWAP1 SSTORE DUP1 PUSH2 0x1094 PUSH2 0xD90 JUMP JUMPDEST POP PUSH1 0x6 SLOAD PUSH1 0x40 DUP1 MLOAD PUSH32 0x70A0823100000000000000000000000000000000000000000000000000000000 DUP2 MSTORE ADDRESS PUSH1 0x4 DUP3 ADD MSTORE SWAP1 MLOAD SWAP4 SWAP6 POP SWAP2 SWAP4 POP PUSH1 0x0 SWAP3 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP1 SWAP2 AND SWAP2 PUSH4 0x70A08231 SWAP2 PUSH1 0x24 DUP1 DUP4 ADD SWAP3 PUSH1 0x20 SWAP3 SWAP2 SWAP1 DUP3 SWAP1 SUB ADD DUP2 DUP7 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x110E JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS STATICCALL ISZERO DUP1 ISZERO PUSH2 0x1122 JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH1 0x40 MLOAD RETURNDATASIZE PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x1138 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP MLOAD PUSH1 0x7 SLOAD PUSH1 0x40 DUP1 MLOAD PUSH32 0x70A0823100000000000000000000000000000000000000000000000000000000 DUP2 MSTORE ADDRESS PUSH1 0x4 DUP3 ADD MSTORE SWAP1 MLOAD SWAP3 SWAP4 POP PUSH1 0x0 SWAP3 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP1 SWAP3 AND SWAP2 PUSH4 0x70A08231 SWAP2 PUSH1 0x24 DUP1 DUP3 ADD SWAP3 PUSH1 0x20 SWAP3 SWAP1 SWAP2 SWAP1 DUP3 SWAP1 SUB ADD DUP2 DUP7 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x11B1 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS STATICCALL ISZERO DUP1 ISZERO PUSH2 0x11C5 JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH1 0x40 MLOAD RETURNDATASIZE PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x11DB JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP MLOAD SWAP1 POP PUSH1 0x0 PUSH2 0x1201 DUP4 PUSH14 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP8 AND PUSH4 0xFFFFFFFF PUSH2 0x226E AND JUMP JUMPDEST SWAP1 POP PUSH1 0x0 PUSH2 0x1225 DUP4 PUSH14 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP8 AND PUSH4 0xFFFFFFFF PUSH2 0x226E AND JUMP JUMPDEST SWAP1 POP PUSH1 0x0 PUSH2 0x1233 DUP8 DUP8 PUSH2 0x26EC JUMP JUMPDEST PUSH1 0x0 SLOAD SWAP1 SWAP2 POP DUP1 PUSH2 0x1270 JUMPI PUSH2 0x125C PUSH2 0x3E8 PUSH2 0xBFD PUSH2 0x1257 DUP8 DUP8 PUSH4 0xFFFFFFFF PUSH2 0x21E8 AND JUMP JUMPDEST PUSH2 0x2878 JUMP JUMPDEST SWAP9 POP PUSH2 0x126B PUSH1 0x0 PUSH2 0x3E8 PUSH2 0x28CA JUMP JUMPDEST PUSH2 0x12CD JUMP JUMPDEST PUSH2 0x12CA PUSH14 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP10 AND PUSH2 0x1294 DUP7 DUP5 PUSH4 0xFFFFFFFF PUSH2 0x21E8 AND JUMP JUMPDEST DUP2 PUSH2 0x129B JUMPI INVALID JUMPDEST DIV PUSH14 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP10 AND PUSH2 0x12BD DUP7 DUP6 PUSH4 0xFFFFFFFF PUSH2 0x21E8 AND JUMP JUMPDEST DUP2 PUSH2 0x12C4 JUMPI INVALID JUMPDEST DIV PUSH2 0x297A JUMP JUMPDEST SWAP9 POP JUMPDEST PUSH1 0x0 DUP10 GT PUSH2 0x1326 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD DUP1 DUP1 PUSH1 0x20 ADD DUP3 DUP2 SUB DUP3 MSTORE PUSH1 0x28 DUP2 MSTORE PUSH1 0x20 ADD DUP1 PUSH2 0x2BC1 PUSH1 0x28 SWAP2 CODECOPY PUSH1 0x40 ADD SWAP2 POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 REVERT JUMPDEST PUSH2 0x1330 DUP11 DUP11 PUSH2 0x28CA JUMP JUMPDEST PUSH2 0x133C DUP7 DUP7 DUP11 DUP11 PUSH2 0x22E0 JUMP JUMPDEST DUP2 ISZERO PUSH2 0x137E JUMPI PUSH1 0x8 SLOAD PUSH2 0x137A SWAP1 PUSH14 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP1 DUP3 AND SWAP2 PUSH15 0x10000000000000000000000000000 SWAP1 DIV AND PUSH4 0xFFFFFFFF PUSH2 0x21E8 AND JUMP JUMPDEST PUSH1 0xB SSTORE JUMPDEST PUSH1 0x40 DUP1 MLOAD DUP6 DUP2 MSTORE PUSH1 0x20 DUP2 ADD DUP6 SWAP1 MSTORE DUP2 MLOAD CALLER SWAP3 PUSH32 0x4C209B5FC8AD50758F13E2E1088BA56A560DFF690A1C6FEF26394F4C03821C4F SWAP3 DUP3 SWAP1 SUB ADD SWAP1 LOG2 POP POP PUSH1 0x1 PUSH1 0xC SSTORE POP SWAP5 SWAP7 SWAP6 POP POP POP POP POP POP JUMP JUMPDEST PUSH1 0x1 PUSH1 0x20 MSTORE PUSH1 0x0 SWAP1 DUP2 MSTORE PUSH1 0x40 SWAP1 KECCAK256 SLOAD DUP2 JUMP JUMPDEST PUSH1 0xB SLOAD DUP2 JUMP JUMPDEST PUSH1 0x4 PUSH1 0x20 MSTORE PUSH1 0x0 SWAP1 DUP2 MSTORE PUSH1 0x40 SWAP1 KECCAK256 SLOAD DUP2 JUMP JUMPDEST PUSH1 0x0 DUP1 PUSH1 0xC SLOAD PUSH1 0x1 EQ PUSH2 0x1469 JUMPI PUSH1 0x40 DUP1 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x20 PUSH1 0x4 DUP3 ADD MSTORE PUSH1 0x11 PUSH1 0x24 DUP3 ADD MSTORE PUSH32 0x556E697377617056323A204C4F434B4544000000000000000000000000000000 PUSH1 0x44 DUP3 ADD MSTORE SWAP1 MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x64 ADD SWAP1 REVERT JUMPDEST PUSH1 0x0 PUSH1 0xC DUP2 SWAP1 SSTORE DUP1 PUSH2 0x1479 PUSH2 0xD90 JUMP JUMPDEST POP PUSH1 0x6 SLOAD PUSH1 0x7 SLOAD PUSH1 0x40 DUP1 MLOAD PUSH32 0x70A0823100000000000000000000000000000000000000000000000000000000 DUP2 MSTORE ADDRESS PUSH1 0x4 DUP3 ADD MSTORE SWAP1 MLOAD SWAP5 SWAP7 POP SWAP3 SWAP5 POP PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP2 DUP3 AND SWAP4 SWAP2 AND SWAP2 PUSH1 0x0 SWAP2 DUP5 SWAP2 PUSH4 0x70A08231 SWAP2 PUSH1 0x24 DUP1 DUP4 ADD SWAP3 PUSH1 0x20 SWAP3 SWAP2 SWAP1 DUP3 SWAP1 SUB ADD DUP2 DUP7 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x14FB JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS STATICCALL ISZERO DUP1 ISZERO PUSH2 0x150F JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH1 0x40 MLOAD RETURNDATASIZE PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x1525 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP MLOAD PUSH1 0x40 DUP1 MLOAD PUSH32 0x70A0823100000000000000000000000000000000000000000000000000000000 DUP2 MSTORE ADDRESS PUSH1 0x4 DUP3 ADD MSTORE SWAP1 MLOAD SWAP2 SWAP3 POP PUSH1 0x0 SWAP2 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP6 AND SWAP2 PUSH4 0x70A08231 SWAP2 PUSH1 0x24 DUP1 DUP4 ADD SWAP3 PUSH1 0x20 SWAP3 SWAP2 SWAP1 DUP3 SWAP1 SUB ADD DUP2 DUP7 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x1599 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS STATICCALL ISZERO DUP1 ISZERO PUSH2 0x15AD JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH1 0x40 MLOAD RETURNDATASIZE PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x15C3 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP MLOAD ADDRESS PUSH1 0x0 SWAP1 DUP2 MSTORE PUSH1 0x1 PUSH1 0x20 MSTORE PUSH1 0x40 DUP2 KECCAK256 SLOAD SWAP2 SWAP3 POP PUSH2 0x15E2 DUP9 DUP9 PUSH2 0x26EC JUMP JUMPDEST PUSH1 0x0 SLOAD SWAP1 SWAP2 POP DUP1 PUSH2 0x15F9 DUP5 DUP8 PUSH4 0xFFFFFFFF PUSH2 0x21E8 AND JUMP JUMPDEST DUP2 PUSH2 0x1600 JUMPI INVALID JUMPDEST DIV SWAP11 POP DUP1 PUSH2 0x1614 DUP5 DUP7 PUSH4 0xFFFFFFFF PUSH2 0x21E8 AND JUMP JUMPDEST DUP2 PUSH2 0x161B JUMPI INVALID JUMPDEST DIV SWAP10 POP PUSH1 0x0 DUP12 GT DUP1 ISZERO PUSH2 0x162E JUMPI POP PUSH1 0x0 DUP11 GT JUMPDEST PUSH2 0x1683 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD DUP1 DUP1 PUSH1 0x20 ADD DUP3 DUP2 SUB DUP3 MSTORE PUSH1 0x28 DUP2 MSTORE PUSH1 0x20 ADD DUP1 PUSH2 0x2B99 PUSH1 0x28 SWAP2 CODECOPY PUSH1 0x40 ADD SWAP2 POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 REVERT JUMPDEST PUSH2 0x168D ADDRESS DUP5 PUSH2 0x2992 JUMP JUMPDEST PUSH2 0x1698 DUP8 DUP14 DUP14 PUSH2 0x1FDB JUMP JUMPDEST PUSH2 0x16A3 DUP7 DUP14 DUP13 PUSH2 0x1FDB JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH32 0x70A0823100000000000000000000000000000000000000000000000000000000 DUP2 MSTORE ADDRESS PUSH1 0x4 DUP3 ADD MSTORE SWAP1 MLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP10 AND SWAP2 PUSH4 0x70A08231 SWAP2 PUSH1 0x24 DUP1 DUP4 ADD SWAP3 PUSH1 0x20 SWAP3 SWAP2 SWAP1 DUP3 SWAP1 SUB ADD DUP2 DUP7 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x170F JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS STATICCALL ISZERO DUP1 ISZERO PUSH2 0x1723 JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH1 0x40 MLOAD RETURNDATASIZE PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x1739 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP MLOAD PUSH1 0x40 DUP1 MLOAD PUSH32 0x70A0823100000000000000000000000000000000000000000000000000000000 DUP2 MSTORE ADDRESS PUSH1 0x4 DUP3 ADD MSTORE SWAP1 MLOAD SWAP2 SWAP7 POP PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP9 AND SWAP2 PUSH4 0x70A08231 SWAP2 PUSH1 0x24 DUP1 DUP3 ADD SWAP3 PUSH1 0x20 SWAP3 SWAP1 SWAP2 SWAP1 DUP3 SWAP1 SUB ADD DUP2 DUP7 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x17AB JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS STATICCALL ISZERO DUP1 ISZERO PUSH2 0x17BF JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH1 0x40 MLOAD RETURNDATASIZE PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x17D5 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP MLOAD SWAP4 POP PUSH2 0x17E5 DUP6 DUP6 DUP12 DUP12 PUSH2 0x22E0 JUMP JUMPDEST DUP2 ISZERO PUSH2 0x1827 JUMPI PUSH1 0x8 SLOAD PUSH2 0x1823 SWAP1 PUSH14 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP1 DUP3 AND SWAP2 PUSH15 0x10000000000000000000000000000 SWAP1 DIV AND PUSH4 0xFFFFFFFF PUSH2 0x21E8 AND JUMP JUMPDEST PUSH1 0xB SSTORE JUMPDEST PUSH1 0x40 DUP1 MLOAD DUP13 DUP2 MSTORE PUSH1 0x20 DUP2 ADD DUP13 SWAP1 MSTORE DUP2 MLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP16 AND SWAP3 CALLER SWAP3 PUSH32 0xDCCD412F0B1252819CB1FD330B93224CA42612892BB3F4F789976E6D81936496 SWAP3 SWAP1 DUP2 SWAP1 SUB SWAP1 SWAP2 ADD SWAP1 LOG3 POP POP POP POP POP POP POP POP POP PUSH1 0x1 PUSH1 0xC DUP2 SWAP1 SSTORE POP SWAP2 POP SWAP2 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 PUSH1 0x40 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x6 DUP2 MSTORE PUSH1 0x20 ADD PUSH32 0x554E492D56320000000000000000000000000000000000000000000000000000 DUP2 MSTORE POP DUP2 JUMP JUMPDEST PUSH1 0x0 PUSH2 0xDF2 CALLER DUP5 DUP5 PUSH2 0x260B JUMP JUMPDEST PUSH2 0x3E8 DUP2 JUMP JUMPDEST PUSH1 0xC SLOAD PUSH1 0x1 EQ PUSH2 0x194F JUMPI PUSH1 0x40 DUP1 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x20 PUSH1 0x4 DUP3 ADD MSTORE PUSH1 0x11 PUSH1 0x24 DUP3 ADD MSTORE PUSH32 0x556E697377617056323A204C4F434B4544000000000000000000000000000000 PUSH1 0x44 DUP3 ADD MSTORE SWAP1 MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x64 ADD SWAP1 REVERT JUMPDEST PUSH1 0x0 PUSH1 0xC SSTORE PUSH1 0x6 SLOAD PUSH1 0x7 SLOAD PUSH1 0x8 SLOAD PUSH1 0x40 DUP1 MLOAD PUSH32 0x70A0823100000000000000000000000000000000000000000000000000000000 DUP2 MSTORE ADDRESS PUSH1 0x4 DUP3 ADD MSTORE SWAP1 MLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP5 DUP6 AND SWAP5 SWAP1 SWAP4 AND SWAP3 PUSH2 0x1A2B SWAP3 DUP6 SWAP3 DUP8 SWAP3 PUSH2 0x1A26 SWAP3 PUSH14 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND SWAP2 DUP6 SWAP2 PUSH4 0x70A08231 SWAP2 PUSH1 0x24 DUP1 DUP3 ADD SWAP3 PUSH1 0x20 SWAP3 SWAP1 SWAP2 SWAP1 DUP3 SWAP1 SUB ADD DUP2 DUP7 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x19EE JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS STATICCALL ISZERO DUP1 ISZERO PUSH2 0x1A02 JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH1 0x40 MLOAD RETURNDATASIZE PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x1A18 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP MLOAD SWAP1 PUSH4 0xFFFFFFFF PUSH2 0x226E AND JUMP JUMPDEST PUSH2 0x1FDB JUMP JUMPDEST PUSH1 0x8 SLOAD PUSH1 0x40 DUP1 MLOAD PUSH32 0x70A0823100000000000000000000000000000000000000000000000000000000 DUP2 MSTORE ADDRESS PUSH1 0x4 DUP3 ADD MSTORE SWAP1 MLOAD PUSH2 0x1ACA SWAP3 DUP5 SWAP3 DUP8 SWAP3 PUSH2 0x1A26 SWAP3 PUSH15 0x10000000000000000000000000000 SWAP1 DIV PUSH14 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND SWAP2 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP7 AND SWAP2 PUSH4 0x70A08231 SWAP2 PUSH1 0x24 DUP1 DUP3 ADD SWAP3 PUSH1 0x20 SWAP3 SWAP1 SWAP2 SWAP1 DUP3 SWAP1 SUB ADD DUP2 DUP7 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x19EE JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP POP PUSH1 0x1 PUSH1 0xC SSTORE POP JUMP JUMPDEST PUSH1 0x5 SLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 JUMP JUMPDEST PUSH1 0x7 SLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 JUMP JUMPDEST TIMESTAMP DUP5 LT ISZERO PUSH2 0x1B7B JUMPI PUSH1 0x40 DUP1 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x20 PUSH1 0x4 DUP3 ADD MSTORE PUSH1 0x12 PUSH1 0x24 DUP3 ADD MSTORE PUSH32 0x556E697377617056323A20455850495245440000000000000000000000000000 PUSH1 0x44 DUP3 ADD MSTORE SWAP1 MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x64 ADD SWAP1 REVERT JUMPDEST PUSH1 0x3 SLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP1 DUP10 AND PUSH1 0x0 DUP2 DUP2 MSTORE PUSH1 0x4 PUSH1 0x20 SWAP1 DUP2 MSTORE PUSH1 0x40 DUP1 DUP4 KECCAK256 DUP1 SLOAD PUSH1 0x1 DUP1 DUP3 ADD SWAP1 SWAP3 SSTORE DUP3 MLOAD PUSH32 0x6E71EDAE12B1B97F4D1F60370FEF10105FA2FAAE0126114A169C64845D6126C9 DUP2 DUP7 ADD MSTORE DUP1 DUP5 ADD SWAP7 SWAP1 SWAP7 MSTORE SWAP6 DUP14 AND PUSH1 0x60 DUP7 ADD MSTORE PUSH1 0x80 DUP6 ADD DUP13 SWAP1 MSTORE PUSH1 0xA0 DUP6 ADD SWAP6 SWAP1 SWAP6 MSTORE PUSH1 0xC0 DUP1 DUP6 ADD DUP12 SWAP1 MSTORE DUP2 MLOAD DUP1 DUP7 SUB SWAP1 SWAP2 ADD DUP2 MSTORE PUSH1 0xE0 DUP6 ADD DUP3 MSTORE DUP1 MLOAD SWAP1 DUP4 ADD KECCAK256 PUSH32 0x1901000000000000000000000000000000000000000000000000000000000000 PUSH2 0x100 DUP7 ADD MSTORE PUSH2 0x102 DUP6 ADD SWAP7 SWAP1 SWAP7 MSTORE PUSH2 0x122 DUP1 DUP6 ADD SWAP7 SWAP1 SWAP7 MSTORE DUP1 MLOAD DUP1 DUP6 SUB SWAP1 SWAP7 ADD DUP7 MSTORE PUSH2 0x142 DUP5 ADD DUP1 DUP3 MSTORE DUP7 MLOAD SWAP7 DUP4 ADD SWAP7 SWAP1 SWAP7 KECCAK256 SWAP6 DUP4 SWAP1 MSTORE PUSH2 0x162 DUP5 ADD DUP1 DUP3 MSTORE DUP7 SWAP1 MSTORE PUSH1 0xFF DUP10 AND PUSH2 0x182 DUP6 ADD MSTORE PUSH2 0x1A2 DUP5 ADD DUP9 SWAP1 MSTORE PUSH2 0x1C2 DUP5 ADD DUP8 SWAP1 MSTORE MLOAD SWAP2 SWAP4 SWAP3 PUSH2 0x1E2 DUP1 DUP3 ADD SWAP4 PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 DUP2 ADD SWAP3 DUP2 SWAP1 SUB SWAP1 SWAP2 ADD SWAP1 DUP6 GAS STATICCALL ISZERO DUP1 ISZERO PUSH2 0x1CDC JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP PUSH1 0x40 MLOAD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 ADD MLOAD SWAP2 POP POP PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP2 AND ISZERO DUP1 ISZERO SWAP1 PUSH2 0x1D57 JUMPI POP DUP9 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND EQ JUMPDEST PUSH2 0x1DC2 JUMPI PUSH1 0x40 DUP1 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x20 PUSH1 0x4 DUP3 ADD MSTORE PUSH1 0x1C PUSH1 0x24 DUP3 ADD MSTORE PUSH32 0x556E697377617056323A20494E56414C49445F5349474E415455524500000000 PUSH1 0x44 DUP3 ADD MSTORE SWAP1 MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x64 ADD SWAP1 REVERT JUMPDEST PUSH2 0x1DCD DUP10 DUP10 DUP10 PUSH2 0x259C JUMP JUMPDEST POP POP POP POP POP POP POP POP POP JUMP JUMPDEST PUSH1 0x2 PUSH1 0x20 SWAP1 DUP2 MSTORE PUSH1 0x0 SWAP3 DUP4 MSTORE PUSH1 0x40 DUP1 DUP5 KECCAK256 SWAP1 SWAP2 MSTORE SWAP1 DUP3 MSTORE SWAP1 KECCAK256 SLOAD DUP2 JUMP JUMPDEST PUSH1 0xC SLOAD PUSH1 0x1 EQ PUSH2 0x1E66 JUMPI PUSH1 0x40 DUP1 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x20 PUSH1 0x4 DUP3 ADD MSTORE PUSH1 0x11 PUSH1 0x24 DUP3 ADD MSTORE PUSH32 0x556E697377617056323A204C4F434B4544000000000000000000000000000000 PUSH1 0x44 DUP3 ADD MSTORE SWAP1 MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x64 ADD SWAP1 REVERT JUMPDEST PUSH1 0x0 PUSH1 0xC SSTORE PUSH1 0x6 SLOAD PUSH1 0x40 DUP1 MLOAD PUSH32 0x70A0823100000000000000000000000000000000000000000000000000000000 DUP2 MSTORE ADDRESS PUSH1 0x4 DUP3 ADD MSTORE SWAP1 MLOAD PUSH2 0x1FD4 SWAP3 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND SWAP2 PUSH4 0x70A08231 SWAP2 PUSH1 0x24 DUP1 DUP4 ADD SWAP3 PUSH1 0x20 SWAP3 SWAP2 SWAP1 DUP3 SWAP1 SUB ADD DUP2 DUP7 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x1EDD JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS STATICCALL ISZERO DUP1 ISZERO PUSH2 0x1EF1 JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH1 0x40 MLOAD RETURNDATASIZE PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x1F07 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP MLOAD PUSH1 0x7 SLOAD PUSH1 0x40 DUP1 MLOAD PUSH32 0x70A0823100000000000000000000000000000000000000000000000000000000 DUP2 MSTORE ADDRESS PUSH1 0x4 DUP3 ADD MSTORE SWAP1 MLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP1 SWAP3 AND SWAP2 PUSH4 0x70A08231 SWAP2 PUSH1 0x24 DUP1 DUP3 ADD SWAP3 PUSH1 0x20 SWAP3 SWAP1 SWAP2 SWAP1 DUP3 SWAP1 SUB ADD DUP2 DUP7 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x1F7A JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS STATICCALL ISZERO DUP1 ISZERO PUSH2 0x1F8E JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH1 0x40 MLOAD RETURNDATASIZE PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x1FA4 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP MLOAD PUSH1 0x8 SLOAD PUSH14 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP1 DUP3 AND SWAP2 PUSH15 0x10000000000000000000000000000 SWAP1 DIV AND PUSH2 0x22E0 JUMP JUMPDEST PUSH1 0x1 PUSH1 0xC SSTORE JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD DUP1 DUP3 ADD DUP3 MSTORE PUSH1 0x19 DUP2 MSTORE PUSH32 0x7472616E7366657228616464726573732C75696E743235362900000000000000 PUSH1 0x20 SWAP2 DUP3 ADD MSTORE DUP2 MLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP6 DUP2 AND PUSH1 0x24 DUP4 ADD MSTORE PUSH1 0x44 DUP1 DUP4 ADD DUP7 SWAP1 MSTORE DUP5 MLOAD DUP1 DUP5 SUB SWAP1 SWAP2 ADD DUP2 MSTORE PUSH1 0x64 SWAP1 SWAP3 ADD DUP5 MSTORE SWAP2 DUP2 ADD DUP1 MLOAD PUSH28 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH32 0xA9059CBB00000000000000000000000000000000000000000000000000000000 OR DUP2 MSTORE SWAP3 MLOAD DUP2 MLOAD PUSH1 0x0 SWAP5 PUSH1 0x60 SWAP5 DUP10 AND SWAP4 SWAP3 SWAP2 DUP3 SWAP2 SWAP1 DUP1 DUP4 DUP4 JUMPDEST PUSH1 0x20 DUP4 LT PUSH2 0x20E1 JUMPI DUP1 MLOAD DUP3 MSTORE PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 SWAP1 SWAP3 ADD SWAP2 PUSH1 0x20 SWAP2 DUP3 ADD SWAP2 ADD PUSH2 0x20A4 JUMP JUMPDEST PUSH1 0x1 DUP4 PUSH1 0x20 SUB PUSH2 0x100 EXP SUB DUP1 NOT DUP3 MLOAD AND DUP2 DUP5 MLOAD AND DUP1 DUP3 OR DUP6 MSTORE POP POP POP POP POP POP SWAP1 POP ADD SWAP2 POP POP PUSH1 0x0 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 PUSH1 0x0 DUP7 GAS CALL SWAP2 POP POP RETURNDATASIZE DUP1 PUSH1 0x0 DUP2 EQ PUSH2 0x2143 JUMPI PUSH1 0x40 MLOAD SWAP2 POP PUSH1 0x1F NOT PUSH1 0x3F RETURNDATASIZE ADD AND DUP3 ADD PUSH1 0x40 MSTORE RETURNDATASIZE DUP3 MSTORE RETURNDATASIZE PUSH1 0x0 PUSH1 0x20 DUP5 ADD RETURNDATACOPY PUSH2 0x2148 JUMP JUMPDEST PUSH1 0x60 SWAP2 POP JUMPDEST POP SWAP2 POP SWAP2 POP DUP2 DUP1 ISZERO PUSH2 0x2176 JUMPI POP DUP1 MLOAD ISZERO DUP1 PUSH2 0x2176 JUMPI POP DUP1 DUP1 PUSH1 0x20 ADD SWAP1 MLOAD PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x2173 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP MLOAD JUMPDEST PUSH2 0x21E1 JUMPI PUSH1 0x40 DUP1 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x20 PUSH1 0x4 DUP3 ADD MSTORE PUSH1 0x1A PUSH1 0x24 DUP3 ADD MSTORE PUSH32 0x556E697377617056323A205452414E534645525F4641494C4544000000000000 PUSH1 0x44 DUP3 ADD MSTORE SWAP1 MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x64 ADD SWAP1 REVERT JUMPDEST POP POP POP POP POP JUMP JUMPDEST PUSH1 0x0 DUP2 ISZERO DUP1 PUSH2 0x2203 JUMPI POP POP DUP1 DUP3 MUL DUP3 DUP3 DUP3 DUP2 PUSH2 0x2200 JUMPI INVALID JUMPDEST DIV EQ JUMPDEST PUSH2 0xDF6 JUMPI PUSH1 0x40 DUP1 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x20 PUSH1 0x4 DUP3 ADD MSTORE PUSH1 0x14 PUSH1 0x24 DUP3 ADD MSTORE PUSH32 0x64732D6D6174682D6D756C2D6F766572666C6F77000000000000000000000000 PUSH1 0x44 DUP3 ADD MSTORE SWAP1 MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x64 ADD SWAP1 REVERT JUMPDEST DUP1 DUP3 SUB DUP3 DUP2 GT ISZERO PUSH2 0xDF6 JUMPI PUSH1 0x40 DUP1 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x20 PUSH1 0x4 DUP3 ADD MSTORE PUSH1 0x15 PUSH1 0x24 DUP3 ADD MSTORE PUSH32 0x64732D6D6174682D7375622D756E646572666C6F770000000000000000000000 PUSH1 0x44 DUP3 ADD MSTORE SWAP1 MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x64 ADD SWAP1 REVERT JUMPDEST PUSH14 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP5 GT DUP1 ISZERO SWAP1 PUSH2 0x230C JUMPI POP PUSH14 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP4 GT ISZERO JUMPDEST PUSH2 0x2377 JUMPI PUSH1 0x40 DUP1 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x20 PUSH1 0x4 DUP3 ADD MSTORE PUSH1 0x13 PUSH1 0x24 DUP3 ADD MSTORE PUSH32 0x556E697377617056323A204F564552464C4F5700000000000000000000000000 PUSH1 0x44 DUP3 ADD MSTORE SWAP1 MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x64 ADD SWAP1 REVERT JUMPDEST PUSH1 0x8 SLOAD PUSH4 0xFFFFFFFF TIMESTAMP DUP2 AND SWAP2 PUSH29 0x100000000000000000000000000000000000000000000000000000000 SWAP1 DIV DUP2 AND DUP3 SUB SWAP1 DUP2 AND ISZERO DUP1 ISZERO SWAP1 PUSH2 0x23C7 JUMPI POP PUSH14 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP5 AND ISZERO ISZERO JUMPDEST DUP1 ISZERO PUSH2 0x23E2 JUMPI POP PUSH14 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP4 AND ISZERO ISZERO JUMPDEST ISZERO PUSH2 0x2492 JUMPI DUP1 PUSH4 0xFFFFFFFF AND PUSH2 0x2425 DUP6 PUSH2 0x23FB DUP7 PUSH2 0x2A57 JUMP JUMPDEST PUSH28 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND SWAP1 PUSH4 0xFFFFFFFF PUSH2 0x2A7B AND JUMP JUMPDEST PUSH1 0x9 DUP1 SLOAD PUSH28 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP3 SWAP1 SWAP3 AND SWAP3 SWAP1 SWAP3 MUL ADD SWAP1 SSTORE PUSH4 0xFFFFFFFF DUP2 AND PUSH2 0x2465 DUP5 PUSH2 0x23FB DUP8 PUSH2 0x2A57 JUMP JUMPDEST PUSH1 0xA DUP1 SLOAD PUSH28 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP3 SWAP1 SWAP3 AND SWAP3 SWAP1 SWAP3 MUL ADD SWAP1 SSTORE JUMPDEST PUSH1 0x8 DUP1 SLOAD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000000000000000000000000000 AND PUSH14 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP9 DUP2 AND SWAP2 SWAP1 SWAP2 OR PUSH32 0xFFFFFFFF0000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH15 0x10000000000000000000000000000 DUP9 DUP4 AND DUP2 MUL SWAP2 SWAP1 SWAP2 OR PUSH28 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH29 0x100000000000000000000000000000000000000000000000000000000 PUSH4 0xFFFFFFFF DUP8 AND MUL OR SWAP3 DUP4 SWAP1 SSTORE PUSH1 0x40 DUP1 MLOAD DUP5 DUP5 AND DUP2 MSTORE SWAP2 SWAP1 SWAP4 DIV SWAP1 SWAP2 AND PUSH1 0x20 DUP3 ADD MSTORE DUP2 MLOAD PUSH32 0x1C411E9A96E071241C2F21F7726B17AE89E3CAB4C78BE50E062B03A9FFFBBAD1 SWAP3 SWAP2 DUP2 SWAP1 SUB SWAP1 SWAP2 ADD SWAP1 LOG1 POP POP POP POP POP POP JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP1 DUP5 AND PUSH1 0x0 DUP2 DUP2 MSTORE PUSH1 0x2 PUSH1 0x20 SWAP1 DUP2 MSTORE PUSH1 0x40 DUP1 DUP4 KECCAK256 SWAP5 DUP8 AND DUP1 DUP5 MSTORE SWAP5 DUP3 MSTORE SWAP2 DUP3 SWAP1 KECCAK256 DUP6 SWAP1 SSTORE DUP2 MLOAD DUP6 DUP2 MSTORE SWAP2 MLOAD PUSH32 0x8C5BE1E5EBEC7D5BD14F71427D1E84F3DD0314C0F7B2291E5B200AC8C7C3B925 SWAP3 DUP2 SWAP1 SUB SWAP1 SWAP2 ADD SWAP1 LOG3 POP POP POP JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP4 AND PUSH1 0x0 SWAP1 DUP2 MSTORE PUSH1 0x1 PUSH1 0x20 MSTORE PUSH1 0x40 SWAP1 KECCAK256 SLOAD PUSH2 0x2641 SWAP1 DUP3 PUSH4 0xFFFFFFFF PUSH2 0x226E AND JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP1 DUP6 AND PUSH1 0x0 SWAP1 DUP2 MSTORE PUSH1 0x1 PUSH1 0x20 MSTORE PUSH1 0x40 DUP1 DUP3 KECCAK256 SWAP4 SWAP1 SWAP4 SSTORE SWAP1 DUP5 AND DUP2 MSTORE KECCAK256 SLOAD PUSH2 0x2683 SWAP1 DUP3 PUSH4 0xFFFFFFFF PUSH2 0x2ABC AND JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP1 DUP5 AND PUSH1 0x0 DUP2 DUP2 MSTORE PUSH1 0x1 PUSH1 0x20 SWAP1 DUP2 MSTORE PUSH1 0x40 SWAP2 DUP3 SWAP1 KECCAK256 SWAP5 SWAP1 SWAP5 SSTORE DUP1 MLOAD DUP6 DUP2 MSTORE SWAP1 MLOAD SWAP2 SWAP4 SWAP3 DUP8 AND SWAP3 PUSH32 0xDDF252AD1BE2C89B69C2B068FC378DAA952BA7F163C4A11628F55A4DF523B3EF SWAP3 SWAP2 DUP3 SWAP1 SUB ADD SWAP1 LOG3 POP POP POP JUMP JUMPDEST PUSH1 0x0 DUP1 PUSH1 0x5 PUSH1 0x0 SWAP1 SLOAD SWAP1 PUSH2 0x100 EXP SWAP1 DIV PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH4 0x17E7E58 PUSH1 0x40 MLOAD DUP2 PUSH4 0xFFFFFFFF AND PUSH1 0xE0 SHL DUP2 MSTORE PUSH1 0x4 ADD PUSH1 0x20 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 DUP7 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x2757 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS STATICCALL ISZERO DUP1 ISZERO PUSH2 0x276B JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH1 0x40 MLOAD RETURNDATASIZE PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x2781 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP MLOAD PUSH1 0xB SLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP3 AND ISZERO DUP1 ISZERO SWAP5 POP SWAP2 SWAP3 POP SWAP1 PUSH2 0x2864 JUMPI DUP1 ISZERO PUSH2 0x285F JUMPI PUSH1 0x0 PUSH2 0x27D8 PUSH2 0x1257 PUSH14 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP9 DUP2 AND SWAP1 DUP9 AND PUSH4 0xFFFFFFFF PUSH2 0x21E8 AND JUMP JUMPDEST SWAP1 POP PUSH1 0x0 PUSH2 0x27E5 DUP4 PUSH2 0x2878 JUMP JUMPDEST SWAP1 POP DUP1 DUP3 GT ISZERO PUSH2 0x285C JUMPI PUSH1 0x0 PUSH2 0x2813 PUSH2 0x2804 DUP5 DUP5 PUSH4 0xFFFFFFFF PUSH2 0x226E AND JUMP JUMPDEST PUSH1 0x0 SLOAD SWAP1 PUSH4 0xFFFFFFFF PUSH2 0x21E8 AND JUMP JUMPDEST SWAP1 POP PUSH1 0x0 PUSH2 0x2838 DUP4 PUSH2 0x282C DUP7 PUSH1 0x5 PUSH4 0xFFFFFFFF PUSH2 0x21E8 AND JUMP JUMPDEST SWAP1 PUSH4 0xFFFFFFFF PUSH2 0x2ABC AND JUMP JUMPDEST SWAP1 POP PUSH1 0x0 DUP2 DUP4 DUP2 PUSH2 0x2845 JUMPI INVALID JUMPDEST DIV SWAP1 POP DUP1 ISZERO PUSH2 0x2858 JUMPI PUSH2 0x2858 DUP8 DUP3 PUSH2 0x28CA JUMP JUMPDEST POP POP POP JUMPDEST POP POP JUMPDEST PUSH2 0x2870 JUMP JUMPDEST DUP1 ISZERO PUSH2 0x2870 JUMPI PUSH1 0x0 PUSH1 0xB SSTORE JUMPDEST POP POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x3 DUP3 GT ISZERO PUSH2 0x28BB JUMPI POP DUP1 PUSH1 0x1 PUSH1 0x2 DUP3 DIV ADD JUMPDEST DUP2 DUP2 LT ISZERO PUSH2 0x28B5 JUMPI DUP1 SWAP2 POP PUSH1 0x2 DUP2 DUP3 DUP6 DUP2 PUSH2 0x28A4 JUMPI INVALID JUMPDEST DIV ADD DUP2 PUSH2 0x28AD JUMPI INVALID JUMPDEST DIV SWAP1 POP PUSH2 0x288D JUMP JUMPDEST POP PUSH2 0x28C5 JUMP JUMPDEST DUP2 ISZERO PUSH2 0x28C5 JUMPI POP PUSH1 0x1 JUMPDEST SWAP2 SWAP1 POP JUMP JUMPDEST PUSH1 0x0 SLOAD PUSH2 0x28DD SWAP1 DUP3 PUSH4 0xFFFFFFFF PUSH2 0x2ABC AND JUMP JUMPDEST PUSH1 0x0 SWAP1 DUP2 SSTORE PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP4 AND DUP2 MSTORE PUSH1 0x1 PUSH1 0x20 MSTORE PUSH1 0x40 SWAP1 KECCAK256 SLOAD PUSH2 0x2915 SWAP1 DUP3 PUSH4 0xFFFFFFFF PUSH2 0x2ABC AND JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP4 AND PUSH1 0x0 DUP2 DUP2 MSTORE PUSH1 0x1 PUSH1 0x20 SWAP1 DUP2 MSTORE PUSH1 0x40 DUP1 DUP4 KECCAK256 SWAP5 SWAP1 SWAP5 SSTORE DUP4 MLOAD DUP6 DUP2 MSTORE SWAP4 MLOAD SWAP3 SWAP4 SWAP2 SWAP3 PUSH32 0xDDF252AD1BE2C89B69C2B068FC378DAA952BA7F163C4A11628F55A4DF523B3EF SWAP3 DUP2 SWAP1 SUB SWAP1 SWAP2 ADD SWAP1 LOG3 POP POP JUMP JUMPDEST PUSH1 0x0 DUP2 DUP4 LT PUSH2 0x2989 JUMPI DUP2 PUSH2 0x298B JUMP JUMPDEST DUP3 JUMPDEST SWAP4 SWAP3 POP POP POP JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP3 AND PUSH1 0x0 SWAP1 DUP2 MSTORE PUSH1 0x1 PUSH1 0x20 MSTORE PUSH1 0x40 SWAP1 KECCAK256 SLOAD PUSH2 0x29C8 SWAP1 DUP3 PUSH4 0xFFFFFFFF PUSH2 0x226E AND JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP4 AND PUSH1 0x0 SWAP1 DUP2 MSTORE PUSH1 0x1 PUSH1 0x20 MSTORE PUSH1 0x40 DUP2 KECCAK256 SWAP2 SWAP1 SWAP2 SSTORE SLOAD PUSH2 0x2A02 SWAP1 DUP3 PUSH4 0xFFFFFFFF PUSH2 0x226E AND JUMP JUMPDEST PUSH1 0x0 SWAP1 DUP2 SSTORE PUSH1 0x40 DUP1 MLOAD DUP4 DUP2 MSTORE SWAP1 MLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP6 AND SWAP2 PUSH32 0xDDF252AD1BE2C89B69C2B068FC378DAA952BA7F163C4A11628F55A4DF523B3EF SWAP2 SWAP1 DUP2 SWAP1 SUB PUSH1 0x20 ADD SWAP1 LOG3 POP POP JUMP JUMPDEST PUSH14 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH15 0x10000000000000000000000000000 MUL SWAP1 JUMP JUMPDEST PUSH1 0x0 PUSH14 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP3 AND PUSH28 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP5 AND DUP2 PUSH2 0x2AB4 JUMPI INVALID JUMPDEST DIV SWAP4 SWAP3 POP POP POP JUMP JUMPDEST DUP1 DUP3 ADD DUP3 DUP2 LT ISZERO PUSH2 0xDF6 JUMPI PUSH1 0x40 DUP1 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x20 PUSH1 0x4 DUP3 ADD MSTORE PUSH1 0x14 PUSH1 0x24 DUP3 ADD MSTORE PUSH32 0x64732D6D6174682D6164642D6F766572666C6F77000000000000000000000000 PUSH1 0x44 DUP3 ADD MSTORE SWAP1 MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x64 ADD SWAP1 REVERT INVALID SSTORE PUSH15 0x697377617056323A20494E53554646 0x49 NUMBER 0x49 GASLIMIT 0x4E SLOAD 0x5F 0x4F SSTORE SLOAD POP SSTORE SLOAD 0x5F COINBASE 0x4D 0x4F SSTORE 0x4E SLOAD SSTORE PUSH15 0x697377617056323A20494E53554646 0x49 NUMBER 0x49 GASLIMIT 0x4E SLOAD 0x5F 0x49 0x4E POP SSTORE SLOAD 0x5F COINBASE 0x4D 0x4F SSTORE 0x4E SLOAD SSTORE PUSH15 0x697377617056323A20494E53554646 0x49 NUMBER 0x49 GASLIMIT 0x4E SLOAD 0x5F 0x4C 0x49 MLOAD SSTORE 0x49 DIFFICULTY 0x49 SLOAD MSIZE SSTORE PUSH15 0x697377617056323A20494E53554646 0x49 NUMBER 0x49 GASLIMIT 0x4E SLOAD 0x5F 0x4C 0x49 MLOAD SSTORE 0x49 DIFFICULTY 0x49 SLOAD MSIZE 0x5F TIMESTAMP SSTORE MSTORE 0x4E GASLIMIT DIFFICULTY SSTORE PUSH15 0x697377617056323A20494E53554646 0x49 NUMBER 0x49 GASLIMIT 0x4E SLOAD 0x5F 0x4C 0x49 MLOAD SSTORE 0x49 DIFFICULTY 0x49 SLOAD MSIZE 0x5F 0x4D 0x49 0x4E SLOAD GASLIMIT DIFFICULTY LOG2 PUSH6 0x627A7A723158 KECCAK256 PUSH30 0xCA18479E58487606BF70C79E44D8DEE62353C9EE6D01F9A9D70885B8765F 0x22 PUSH5 0x736F6C6343 STOP SDIV LT STOP ORIGIN GASLIMIT 0x49 POP CALLDATACOPY BALANCE ORIGIN DIFFICULTY PUSH16 0x6D61696E28737472696E67206E616D65 0x2C PUSH20 0x7472696E672076657273696F6E2C75696E743235 CALLDATASIZE KECCAK256 PUSH4 0x6861696E 0x49 PUSH5 0x2C61646472 PUSH6 0x737320766572 PUSH10 0x6679696E67436F6E7472 PUSH2 0x6374 0x29 LOG2 PUSH6 0x627A7A723158 KECCAK256 0x27 PUSH1 0xF9 0x2D PUSH32 0xA1DB6F5AA16307BAD65DF4EBCC8550C4B1F03755AB8DFD830C178F64736F6C63 NUMBER STOP SDIV LT STOP ORIGIN \",\"sourceMap\":\"102:1764:1:-;;;406:84;8:9:-1;5:2;;;30:1;27;20:12;5:2;406:84:1;;;;;;;;;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;406:84:1;457:11;:26;;-1:-1:-1;;;;;;457:26:1;-1:-1:-1;;;;;457:26:1;;;;;;;;;102:1764;;;-1:-1:-1;102:1764:1;;\"},\"deployedBytecode\":{\"linkReferences\":{},\"object\":\"608060405234801561001057600080fd5b50600436106100885760003560e01c8063a2e74af61161005b578063a2e74af6146100fd578063c9c6539614610132578063e6a439051461016d578063f46901ed146101a857610088565b8063017e7e581461008d578063094b7415146100be5780631e3dd18b146100c6578063574f2ba3146100e3575b600080fd5b6100956101db565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b6100956101f7565b610095600480360360208110156100dc57600080fd5b5035610213565b6100eb610247565b60408051918252519081900360200190f35b6101306004803603602081101561011357600080fd5b503573ffffffffffffffffffffffffffffffffffffffff1661024d565b005b6100956004803603604081101561014857600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135811691602001351661031a565b6100956004803603604081101561018357600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135811691602001351661076d565b610130600480360360208110156101be57600080fd5b503573ffffffffffffffffffffffffffffffffffffffff166107a0565b60005473ffffffffffffffffffffffffffffffffffffffff1681565b60015473ffffffffffffffffffffffffffffffffffffffff1681565b6003818154811061022057fe5b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff16905081565b60035490565b60015473ffffffffffffffffffffffffffffffffffffffff1633146102d357604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f556e697377617056323a20464f5242494444454e000000000000000000000000604482015290519081900360640190fd5b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60008173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614156103b757604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f556e697377617056323a204944454e544943414c5f4144445245535345530000604482015290519081900360640190fd5b6000808373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16106103f45783856103f7565b84845b909250905073ffffffffffffffffffffffffffffffffffffffff821661047e57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f556e697377617056323a205a45524f5f41444452455353000000000000000000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff82811660009081526002602090815260408083208585168452909152902054161561051f57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f556e697377617056323a20504149525f45584953545300000000000000000000604482015290519081900360640190fd5b6060604051806020016105319061086d565b6020820181038252601f19601f82011660405250905060008383604051602001808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660601b81526014018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660601b815260140192505050604051602081830303815290604052805190602001209050808251602084016000f5604080517f485cc95500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8781166004830152868116602483015291519297509087169163485cc9559160448082019260009290919082900301818387803b15801561065e57600080fd5b505af1158015610672573d6000803e3d6000fd5b5050505073ffffffffffffffffffffffffffffffffffffffff84811660008181526002602081815260408084208987168086529083528185208054978d167fffffffffffffffffffffffff000000000000000000000000000000000000000098891681179091559383528185208686528352818520805488168517905560038054600181018255958190527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b90950180549097168417909655925483519283529082015281517f0d3648bd0f6ba80134a33ba9275ac585d9d315f0ad8355cddefde31afa28d0e9929181900390910190a35050505092915050565b600260209081526000928352604080842090915290825290205473ffffffffffffffffffffffffffffffffffffffff1681565b60015473ffffffffffffffffffffffffffffffffffffffff16331461082657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f556e697377617056323a20464f5242494444454e000000000000000000000000604482015290519081900360640190fd5b600080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b612d748061087b8339019056fe60806040526001600c5534801561001557600080fd5b506040514690806052612d228239604080519182900360520182208282018252600a8352692ab734b9bbb0b8102b1960b11b6020938401528151808301835260018152603160f81b908401528151808401919091527fbfcc8ef98ffbf7b6c3fec7bf5185b566b9863e35a9d83acd49ad6824b5969738818301527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6606082015260808101949094523060a0808601919091528151808603909101815260c09094019052825192019190912060035550600580546001600160a01b03191633179055612c1d806101056000396000f3fe608060405234801561001057600080fd5b50600436106101b95760003560e01c80636a627842116100f9578063ba9a7a5611610097578063d21220a711610071578063d21220a7146105da578063d505accf146105e2578063dd62ed3e14610640578063fff6cae91461067b576101b9565b8063ba9a7a5614610597578063bc25cf771461059f578063c45a0155146105d2576101b9565b80637ecebe00116100d35780637ecebe00146104d757806389afcb441461050a57806395d89b4114610556578063a9059cbb1461055e576101b9565b80636a6278421461046957806370a082311461049c5780637464fc3d146104cf576101b9565b806323b872dd116101665780633644e515116101405780633644e51514610416578063485cc9551461041e5780635909c0d5146104595780635a3d549314610461576101b9565b806323b872dd146103ad57806330adf81f146103f0578063313ce567146103f8576101b9565b8063095ea7b311610197578063095ea7b3146103155780630dfe16811461036257806318160ddd14610393576101b9565b8063022c0d9f146101be57806306fdde03146102595780630902f1ac146102d6575b600080fd5b610257600480360360808110156101d457600080fd5b81359160208101359173ffffffffffffffffffffffffffffffffffffffff604083013516919081019060808101606082013564010000000081111561021857600080fd5b82018360208201111561022a57600080fd5b8035906020019184600183028401116401000000008311171561024c57600080fd5b509092509050610683565b005b610261610d57565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561029b578181015183820152602001610283565b50505050905090810190601f1680156102c85780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6102de610d90565b604080516dffffffffffffffffffffffffffff948516815292909316602083015263ffffffff168183015290519081900360600190f35b61034e6004803603604081101561032b57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135169060200135610de5565b604080519115158252519081900360200190f35b61036a610dfc565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b61039b610e18565b60408051918252519081900360200190f35b61034e600480360360608110156103c357600080fd5b5073ffffffffffffffffffffffffffffffffffffffff813581169160208101359091169060400135610e1e565b61039b610efd565b610400610f21565b6040805160ff9092168252519081900360200190f35b61039b610f26565b6102576004803603604081101561043457600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81358116916020013516610f2c565b61039b611005565b61039b61100b565b61039b6004803603602081101561047f57600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16611011565b61039b600480360360208110156104b257600080fd5b503573ffffffffffffffffffffffffffffffffffffffff166113cb565b61039b6113dd565b61039b600480360360208110156104ed57600080fd5b503573ffffffffffffffffffffffffffffffffffffffff166113e3565b61053d6004803603602081101561052057600080fd5b503573ffffffffffffffffffffffffffffffffffffffff166113f5565b6040805192835260208301919091528051918290030190f35b610261611892565b61034e6004803603604081101561057457600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81351690602001356118cb565b61039b6118d8565b610257600480360360208110156105b557600080fd5b503573ffffffffffffffffffffffffffffffffffffffff166118de565b61036a611ad4565b61036a611af0565b610257600480360360e08110156105f857600080fd5b5073ffffffffffffffffffffffffffffffffffffffff813581169160208101359091169060408101359060608101359060ff6080820135169060a08101359060c00135611b0c565b61039b6004803603604081101561065657600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81358116916020013516611dd8565b610257611df5565b600c546001146106f457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f556e697377617056323a204c4f434b4544000000000000000000000000000000604482015290519081900360640190fd5b6000600c55841515806107075750600084115b61075c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526025815260200180612b2f6025913960400191505060405180910390fd5b600080610767610d90565b5091509150816dffffffffffffffffffffffffffff168710801561079a5750806dffffffffffffffffffffffffffff1686105b6107ef576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526021815260200180612b786021913960400191505060405180910390fd5b600654600754600091829173ffffffffffffffffffffffffffffffffffffffff91821691908116908916821480159061085457508073ffffffffffffffffffffffffffffffffffffffff168973ffffffffffffffffffffffffffffffffffffffff1614155b6108bf57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f556e697377617056323a20494e56414c49445f544f0000000000000000000000604482015290519081900360640190fd5b8a156108d0576108d0828a8d611fdb565b89156108e1576108e1818a8c611fdb565b86156109c3578873ffffffffffffffffffffffffffffffffffffffff166310d1e85c338d8d8c8c6040518663ffffffff1660e01b8152600401808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001858152602001848152602001806020018281038252848482818152602001925080828437600081840152601f19601f8201169050808301925050509650505050505050600060405180830381600087803b1580156109aa57600080fd5b505af11580156109be573d6000803e3d6000fd5b505050505b604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905173ffffffffffffffffffffffffffffffffffffffff8416916370a08231916024808301926020929190829003018186803b158015610a2f57600080fd5b505afa158015610a43573d6000803e3d6000fd5b505050506040513d6020811015610a5957600080fd5b5051604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905191955073ffffffffffffffffffffffffffffffffffffffff8316916370a0823191602480820192602092909190829003018186803b158015610acb57600080fd5b505afa158015610adf573d6000803e3d6000fd5b505050506040513d6020811015610af557600080fd5b5051925060009150506dffffffffffffffffffffffffffff85168a90038311610b1f576000610b35565b89856dffffffffffffffffffffffffffff160383035b9050600089856dffffffffffffffffffffffffffff16038311610b59576000610b6f565b89856dffffffffffffffffffffffffffff160383035b90506000821180610b805750600081115b610bd5576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526024815260200180612b546024913960400191505060405180910390fd5b6000610c09610beb84600363ffffffff6121e816565b610bfd876103e863ffffffff6121e816565b9063ffffffff61226e16565b90506000610c21610beb84600363ffffffff6121e816565b9050610c59620f4240610c4d6dffffffffffffffffffffffffffff8b8116908b1663ffffffff6121e816565b9063ffffffff6121e816565b610c69838363ffffffff6121e816565b1015610cd657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f556e697377617056323a204b0000000000000000000000000000000000000000604482015290519081900360640190fd5b5050610ce4848488886122e0565b60408051838152602081018390528082018d9052606081018c9052905173ffffffffffffffffffffffffffffffffffffffff8b169133917fd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d8229181900360800190a350506001600c55505050505050505050565b6040518060400160405280600a81526020017f556e69737761702056320000000000000000000000000000000000000000000081525081565b6008546dffffffffffffffffffffffffffff808216926e0100000000000000000000000000008304909116917c0100000000000000000000000000000000000000000000000000000000900463ffffffff1690565b6000610df233848461259c565b5060015b92915050565b60065473ffffffffffffffffffffffffffffffffffffffff1681565b60005481565b73ffffffffffffffffffffffffffffffffffffffff831660009081526002602090815260408083203384529091528120547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff14610ee85773ffffffffffffffffffffffffffffffffffffffff84166000908152600260209081526040808320338452909152902054610eb6908363ffffffff61226e16565b73ffffffffffffffffffffffffffffffffffffffff851660009081526002602090815260408083203384529091529020555b610ef384848461260b565b5060019392505050565b7f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c981565b601281565b60035481565b60055473ffffffffffffffffffffffffffffffffffffffff163314610fb257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f556e697377617056323a20464f5242494444454e000000000000000000000000604482015290519081900360640190fd5b6006805473ffffffffffffffffffffffffffffffffffffffff9384167fffffffffffffffffffffffff00000000000000000000000000000000000000009182161790915560078054929093169116179055565b60095481565b600a5481565b6000600c5460011461108457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f556e697377617056323a204c4f434b4544000000000000000000000000000000604482015290519081900360640190fd5b6000600c81905580611094610d90565b50600654604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905193955091935060009273ffffffffffffffffffffffffffffffffffffffff909116916370a08231916024808301926020929190829003018186803b15801561110e57600080fd5b505afa158015611122573d6000803e3d6000fd5b505050506040513d602081101561113857600080fd5b5051600754604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905192935060009273ffffffffffffffffffffffffffffffffffffffff909216916370a0823191602480820192602092909190829003018186803b1580156111b157600080fd5b505afa1580156111c5573d6000803e3d6000fd5b505050506040513d60208110156111db57600080fd5b505190506000611201836dffffffffffffffffffffffffffff871663ffffffff61226e16565b90506000611225836dffffffffffffffffffffffffffff871663ffffffff61226e16565b9050600061123387876126ec565b600054909150806112705761125c6103e8610bfd611257878763ffffffff6121e816565b612878565b985061126b60006103e86128ca565b6112cd565b6112ca6dffffffffffffffffffffffffffff8916611294868463ffffffff6121e816565b8161129b57fe5b046dffffffffffffffffffffffffffff89166112bd868563ffffffff6121e816565b816112c457fe5b0461297a565b98505b60008911611326576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526028815260200180612bc16028913960400191505060405180910390fd5b6113308a8a6128ca565b61133c86868a8a6122e0565b811561137e5760085461137a906dffffffffffffffffffffffffffff808216916e01000000000000000000000000000090041663ffffffff6121e816565b600b555b6040805185815260208101859052815133927f4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f928290030190a250506001600c5550949695505050505050565b60016020526000908152604090205481565b600b5481565b60046020526000908152604090205481565b600080600c5460011461146957604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f556e697377617056323a204c4f434b4544000000000000000000000000000000604482015290519081900360640190fd5b6000600c81905580611479610d90565b50600654600754604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905194965092945073ffffffffffffffffffffffffffffffffffffffff9182169391169160009184916370a08231916024808301926020929190829003018186803b1580156114fb57600080fd5b505afa15801561150f573d6000803e3d6000fd5b505050506040513d602081101561152557600080fd5b5051604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905191925060009173ffffffffffffffffffffffffffffffffffffffff8516916370a08231916024808301926020929190829003018186803b15801561159957600080fd5b505afa1580156115ad573d6000803e3d6000fd5b505050506040513d60208110156115c357600080fd5b5051306000908152600160205260408120549192506115e288886126ec565b600054909150806115f9848763ffffffff6121e816565b8161160057fe5b049a5080611614848663ffffffff6121e816565b8161161b57fe5b04995060008b11801561162e575060008a115b611683576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526028815260200180612b996028913960400191505060405180910390fd5b61168d3084612992565b611698878d8d611fdb565b6116a3868d8c611fdb565b604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905173ffffffffffffffffffffffffffffffffffffffff8916916370a08231916024808301926020929190829003018186803b15801561170f57600080fd5b505afa158015611723573d6000803e3d6000fd5b505050506040513d602081101561173957600080fd5b5051604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905191965073ffffffffffffffffffffffffffffffffffffffff8816916370a0823191602480820192602092909190829003018186803b1580156117ab57600080fd5b505afa1580156117bf573d6000803e3d6000fd5b505050506040513d60208110156117d557600080fd5b505193506117e585858b8b6122e0565b811561182757600854611823906dffffffffffffffffffffffffffff808216916e01000000000000000000000000000090041663ffffffff6121e816565b600b555b604080518c8152602081018c9052815173ffffffffffffffffffffffffffffffffffffffff8f169233927fdccd412f0b1252819cb1fd330b93224ca42612892bb3f4f789976e6d81936496929081900390910190a35050505050505050506001600c81905550915091565b6040518060400160405280600681526020017f554e492d5632000000000000000000000000000000000000000000000000000081525081565b6000610df233848461260b565b6103e881565b600c5460011461194f57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f556e697377617056323a204c4f434b4544000000000000000000000000000000604482015290519081900360640190fd5b6000600c55600654600754600854604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905173ffffffffffffffffffffffffffffffffffffffff9485169490931692611a2b9285928792611a26926dffffffffffffffffffffffffffff169185916370a0823191602480820192602092909190829003018186803b1580156119ee57600080fd5b505afa158015611a02573d6000803e3d6000fd5b505050506040513d6020811015611a1857600080fd5b50519063ffffffff61226e16565b611fdb565b600854604080517f70a082310000000000000000000000000000000000000000000000000000000081523060048201529051611aca9284928792611a26926e01000000000000000000000000000090046dffffffffffffffffffffffffffff169173ffffffffffffffffffffffffffffffffffffffff8616916370a0823191602480820192602092909190829003018186803b1580156119ee57600080fd5b50506001600c5550565b60055473ffffffffffffffffffffffffffffffffffffffff1681565b60075473ffffffffffffffffffffffffffffffffffffffff1681565b42841015611b7b57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f556e697377617056323a20455850495245440000000000000000000000000000604482015290519081900360640190fd5b60035473ffffffffffffffffffffffffffffffffffffffff80891660008181526004602090815260408083208054600180820190925582517f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98186015280840196909652958d166060860152608085018c905260a085019590955260c08085018b90528151808603909101815260e0850182528051908301207f19010000000000000000000000000000000000000000000000000000000000006101008601526101028501969096526101228085019690965280518085039096018652610142840180825286519683019690962095839052610162840180825286905260ff89166101828501526101a284018890526101c28401879052519193926101e2808201937fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081019281900390910190855afa158015611cdc573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff811615801590611d5757508873ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16145b611dc257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f556e697377617056323a20494e56414c49445f5349474e415455524500000000604482015290519081900360640190fd5b611dcd89898961259c565b505050505050505050565b600260209081526000928352604080842090915290825290205481565b600c54600114611e6657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f556e697377617056323a204c4f434b4544000000000000000000000000000000604482015290519081900360640190fd5b6000600c55600654604080517f70a082310000000000000000000000000000000000000000000000000000000081523060048201529051611fd49273ffffffffffffffffffffffffffffffffffffffff16916370a08231916024808301926020929190829003018186803b158015611edd57600080fd5b505afa158015611ef1573d6000803e3d6000fd5b505050506040513d6020811015611f0757600080fd5b5051600754604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905173ffffffffffffffffffffffffffffffffffffffff909216916370a0823191602480820192602092909190829003018186803b158015611f7a57600080fd5b505afa158015611f8e573d6000803e3d6000fd5b505050506040513d6020811015611fa457600080fd5b50516008546dffffffffffffffffffffffffffff808216916e0100000000000000000000000000009004166122e0565b6001600c55565b604080518082018252601981527f7472616e7366657228616464726573732c75696e743235362900000000000000602091820152815173ffffffffffffffffffffffffffffffffffffffff85811660248301526044808301869052845180840390910181526064909201845291810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001781529251815160009460609489169392918291908083835b602083106120e157805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016120a4565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114612143576040519150601f19603f3d011682016040523d82523d6000602084013e612148565b606091505b5091509150818015612176575080511580612176575080806020019051602081101561217357600080fd5b50515b6121e157604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f556e697377617056323a205452414e534645525f4641494c4544000000000000604482015290519081900360640190fd5b5050505050565b60008115806122035750508082028282828161220057fe5b04145b610df657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f64732d6d6174682d6d756c2d6f766572666c6f77000000000000000000000000604482015290519081900360640190fd5b80820382811115610df657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f64732d6d6174682d7375622d756e646572666c6f770000000000000000000000604482015290519081900360640190fd5b6dffffffffffffffffffffffffffff841180159061230c57506dffffffffffffffffffffffffffff8311155b61237757604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f556e697377617056323a204f564552464c4f5700000000000000000000000000604482015290519081900360640190fd5b60085463ffffffff428116917c0100000000000000000000000000000000000000000000000000000000900481168203908116158015906123c757506dffffffffffffffffffffffffffff841615155b80156123e257506dffffffffffffffffffffffffffff831615155b15612492578063ffffffff16612425856123fb86612a57565b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff169063ffffffff612a7b16565b600980547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff929092169290920201905563ffffffff8116612465846123fb87612a57565b600a80547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff92909216929092020190555b600880547fffffffffffffffffffffffffffffffffffff0000000000000000000000000000166dffffffffffffffffffffffffffff888116919091177fffffffff0000000000000000000000000000ffffffffffffffffffffffffffff166e0100000000000000000000000000008883168102919091177bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167c010000000000000000000000000000000000000000000000000000000063ffffffff871602179283905560408051848416815291909304909116602082015281517f1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1929181900390910190a1505050505050565b73ffffffffffffffffffffffffffffffffffffffff808416600081815260026020908152604080832094871680845294825291829020859055815185815291517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259281900390910190a3505050565b73ffffffffffffffffffffffffffffffffffffffff8316600090815260016020526040902054612641908263ffffffff61226e16565b73ffffffffffffffffffffffffffffffffffffffff8085166000908152600160205260408082209390935590841681522054612683908263ffffffff612abc16565b73ffffffffffffffffffffffffffffffffffffffff80841660008181526001602090815260409182902094909455805185815290519193928716927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92918290030190a3505050565b600080600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663017e7e586040518163ffffffff1660e01b815260040160206040518083038186803b15801561275757600080fd5b505afa15801561276b573d6000803e3d6000fd5b505050506040513d602081101561278157600080fd5b5051600b5473ffffffffffffffffffffffffffffffffffffffff821615801594509192509061286457801561285f5760006127d86112576dffffffffffffffffffffffffffff88811690881663ffffffff6121e816565b905060006127e583612878565b90508082111561285c576000612813612804848463ffffffff61226e16565b6000549063ffffffff6121e816565b905060006128388361282c86600563ffffffff6121e816565b9063ffffffff612abc16565b9050600081838161284557fe5b04905080156128585761285887826128ca565b5050505b50505b612870565b8015612870576000600b555b505092915050565b600060038211156128bb575080600160028204015b818110156128b5578091506002818285816128a457fe5b0401816128ad57fe5b04905061288d565b506128c5565b81156128c5575060015b919050565b6000546128dd908263ffffffff612abc16565b600090815573ffffffffffffffffffffffffffffffffffffffff8316815260016020526040902054612915908263ffffffff612abc16565b73ffffffffffffffffffffffffffffffffffffffff831660008181526001602090815260408083209490945583518581529351929391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a35050565b6000818310612989578161298b565b825b9392505050565b73ffffffffffffffffffffffffffffffffffffffff82166000908152600160205260409020546129c8908263ffffffff61226e16565b73ffffffffffffffffffffffffffffffffffffffff831660009081526001602052604081209190915554612a02908263ffffffff61226e16565b600090815560408051838152905173ffffffffffffffffffffffffffffffffffffffff8516917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef919081900360200190a35050565b6dffffffffffffffffffffffffffff166e0100000000000000000000000000000290565b60006dffffffffffffffffffffffffffff82167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff841681612ab457fe5b049392505050565b80820182811015610df657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f64732d6d6174682d6164642d6f766572666c6f77000000000000000000000000604482015290519081900360640190fdfe556e697377617056323a20494e53554646494349454e545f4f55545055545f414d4f554e54556e697377617056323a20494e53554646494349454e545f494e5055545f414d4f554e54556e697377617056323a20494e53554646494349454e545f4c4951554944495459556e697377617056323a20494e53554646494349454e545f4c49515549444954595f4255524e4544556e697377617056323a20494e53554646494349454e545f4c49515549444954595f4d494e544544a265627a7a723158207dca18479e58487606bf70c79e44d8dee62353c9ee6d01f9a9d70885b8765f2264736f6c63430005100032454950373132446f6d61696e28737472696e67206e616d652c737472696e672076657273696f6e2c75696e7432353620636861696e49642c6164647265737320766572696679696e67436f6e747261637429a265627a7a723158202760f92d7fa1db6f5aa16307bad65df4ebcc8550c4b1f03755ab8dfd830c178f64736f6c63430005100032\",\"opcodes\":\"PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x4 CALLDATASIZE LT PUSH2 0x88 JUMPI PUSH1 0x0 CALLDATALOAD PUSH1 0xE0 SHR DUP1 PUSH4 0xA2E74AF6 GT PUSH2 0x5B JUMPI DUP1 PUSH4 0xA2E74AF6 EQ PUSH2 0xFD JUMPI DUP1 PUSH4 0xC9C65396 EQ PUSH2 0x132 JUMPI DUP1 PUSH4 0xE6A43905 EQ PUSH2 0x16D JUMPI DUP1 PUSH4 0xF46901ED EQ PUSH2 0x1A8 JUMPI PUSH2 0x88 JUMP JUMPDEST DUP1 PUSH4 0x17E7E58 EQ PUSH2 0x8D JUMPI DUP1 PUSH4 0x94B7415 EQ PUSH2 0xBE JUMPI DUP1 PUSH4 0x1E3DD18B EQ PUSH2 0xC6 JUMPI DUP1 PUSH4 0x574F2BA3 EQ PUSH2 0xE3 JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x95 PUSH2 0x1DB JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP1 SWAP3 AND DUP3 MSTORE MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x20 ADD SWAP1 RETURN JUMPDEST PUSH2 0x95 PUSH2 0x1F7 JUMP JUMPDEST PUSH2 0x95 PUSH1 0x4 DUP1 CALLDATASIZE SUB PUSH1 0x20 DUP2 LT ISZERO PUSH2 0xDC JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP CALLDATALOAD PUSH2 0x213 JUMP JUMPDEST PUSH2 0xEB PUSH2 0x247 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD SWAP2 DUP3 MSTORE MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x20 ADD SWAP1 RETURN JUMPDEST PUSH2 0x130 PUSH1 0x4 DUP1 CALLDATASIZE SUB PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x113 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP CALLDATALOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH2 0x24D JUMP JUMPDEST STOP JUMPDEST PUSH2 0x95 PUSH1 0x4 DUP1 CALLDATASIZE SUB PUSH1 0x40 DUP2 LT ISZERO PUSH2 0x148 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP2 CALLDATALOAD DUP2 AND SWAP2 PUSH1 0x20 ADD CALLDATALOAD AND PUSH2 0x31A JUMP JUMPDEST PUSH2 0x95 PUSH1 0x4 DUP1 CALLDATASIZE SUB PUSH1 0x40 DUP2 LT ISZERO PUSH2 0x183 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP2 CALLDATALOAD DUP2 AND SWAP2 PUSH1 0x20 ADD CALLDATALOAD AND PUSH2 0x76D JUMP JUMPDEST PUSH2 0x130 PUSH1 0x4 DUP1 CALLDATASIZE SUB PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x1BE JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP CALLDATALOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH2 0x7A0 JUMP JUMPDEST PUSH1 0x0 SLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 JUMP JUMPDEST PUSH1 0x1 SLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 JUMP JUMPDEST PUSH1 0x3 DUP2 DUP2 SLOAD DUP2 LT PUSH2 0x220 JUMPI INVALID JUMPDEST PUSH1 0x0 SWAP2 DUP3 MSTORE PUSH1 0x20 SWAP1 SWAP2 KECCAK256 ADD SLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND SWAP1 POP DUP2 JUMP JUMPDEST PUSH1 0x3 SLOAD SWAP1 JUMP JUMPDEST PUSH1 0x1 SLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND CALLER EQ PUSH2 0x2D3 JUMPI PUSH1 0x40 DUP1 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x20 PUSH1 0x4 DUP3 ADD MSTORE PUSH1 0x14 PUSH1 0x24 DUP3 ADD MSTORE PUSH32 0x556E697377617056323A20464F5242494444454E000000000000000000000000 PUSH1 0x44 DUP3 ADD MSTORE SWAP1 MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x64 ADD SWAP1 REVERT JUMPDEST PUSH1 0x1 DUP1 SLOAD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFF0000000000000000000000000000000000000000 AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP3 SWAP1 SWAP3 AND SWAP2 SWAP1 SWAP2 OR SWAP1 SSTORE JUMP JUMPDEST PUSH1 0x0 DUP2 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP4 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND EQ ISZERO PUSH2 0x3B7 JUMPI PUSH1 0x40 DUP1 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x20 PUSH1 0x4 DUP3 ADD MSTORE PUSH1 0x1E PUSH1 0x24 DUP3 ADD MSTORE PUSH32 0x556E697377617056323A204944454E544943414C5F4144445245535345530000 PUSH1 0x44 DUP3 ADD MSTORE SWAP1 MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x64 ADD SWAP1 REVERT JUMPDEST PUSH1 0x0 DUP1 DUP4 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP6 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND LT PUSH2 0x3F4 JUMPI DUP4 DUP6 PUSH2 0x3F7 JUMP JUMPDEST DUP5 DUP5 JUMPDEST SWAP1 SWAP3 POP SWAP1 POP PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP3 AND PUSH2 0x47E JUMPI PUSH1 0x40 DUP1 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x20 PUSH1 0x4 DUP3 ADD MSTORE PUSH1 0x17 PUSH1 0x24 DUP3 ADD MSTORE PUSH32 0x556E697377617056323A205A45524F5F41444452455353000000000000000000 PUSH1 0x44 DUP3 ADD MSTORE SWAP1 MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x64 ADD SWAP1 REVERT JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP3 DUP2 AND PUSH1 0x0 SWAP1 DUP2 MSTORE PUSH1 0x2 PUSH1 0x20 SWAP1 DUP2 MSTORE PUSH1 0x40 DUP1 DUP4 KECCAK256 DUP6 DUP6 AND DUP5 MSTORE SWAP1 SWAP2 MSTORE SWAP1 KECCAK256 SLOAD AND ISZERO PUSH2 0x51F JUMPI PUSH1 0x40 DUP1 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x20 PUSH1 0x4 DUP3 ADD MSTORE PUSH1 0x16 PUSH1 0x24 DUP3 ADD MSTORE PUSH32 0x556E697377617056323A20504149525F45584953545300000000000000000000 PUSH1 0x44 DUP3 ADD MSTORE SWAP1 MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x64 ADD SWAP1 REVERT JUMPDEST PUSH1 0x60 PUSH1 0x40 MLOAD DUP1 PUSH1 0x20 ADD PUSH2 0x531 SWAP1 PUSH2 0x86D JUMP JUMPDEST PUSH1 0x20 DUP3 ADD DUP2 SUB DUP3 MSTORE PUSH1 0x1F NOT PUSH1 0x1F DUP3 ADD AND PUSH1 0x40 MSTORE POP SWAP1 POP PUSH1 0x0 DUP4 DUP4 PUSH1 0x40 MLOAD PUSH1 0x20 ADD DUP1 DUP4 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH1 0x60 SHL DUP2 MSTORE PUSH1 0x14 ADD DUP3 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH1 0x60 SHL DUP2 MSTORE PUSH1 0x14 ADD SWAP3 POP POP POP PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE DUP1 MLOAD SWAP1 PUSH1 0x20 ADD KECCAK256 SWAP1 POP DUP1 DUP3 MLOAD PUSH1 0x20 DUP5 ADD PUSH1 0x0 CREATE2 PUSH1 0x40 DUP1 MLOAD PUSH32 0x485CC95500000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP8 DUP2 AND PUSH1 0x4 DUP4 ADD MSTORE DUP7 DUP2 AND PUSH1 0x24 DUP4 ADD MSTORE SWAP2 MLOAD SWAP3 SWAP8 POP SWAP1 DUP8 AND SWAP2 PUSH4 0x485CC955 SWAP2 PUSH1 0x44 DUP1 DUP3 ADD SWAP3 PUSH1 0x0 SWAP3 SWAP1 SWAP2 SWAP1 DUP3 SWAP1 SUB ADD DUP2 DUP4 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x65E JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0x672 JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP5 DUP2 AND PUSH1 0x0 DUP2 DUP2 MSTORE PUSH1 0x2 PUSH1 0x20 DUP2 DUP2 MSTORE PUSH1 0x40 DUP1 DUP5 KECCAK256 DUP10 DUP8 AND DUP1 DUP7 MSTORE SWAP1 DUP4 MSTORE DUP2 DUP6 KECCAK256 DUP1 SLOAD SWAP8 DUP14 AND PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFF0000000000000000000000000000000000000000 SWAP9 DUP10 AND DUP2 OR SWAP1 SWAP2 SSTORE SWAP4 DUP4 MSTORE DUP2 DUP6 KECCAK256 DUP7 DUP7 MSTORE DUP4 MSTORE DUP2 DUP6 KECCAK256 DUP1 SLOAD DUP9 AND DUP6 OR SWAP1 SSTORE PUSH1 0x3 DUP1 SLOAD PUSH1 0x1 DUP2 ADD DUP3 SSTORE SWAP6 DUP2 SWAP1 MSTORE PUSH32 0xC2575A0E9E593C00F959F8C92F12DB2869C3395A3B0502D05E2516446F71F85B SWAP1 SWAP6 ADD DUP1 SLOAD SWAP1 SWAP8 AND DUP5 OR SWAP1 SWAP7 SSTORE SWAP3 SLOAD DUP4 MLOAD SWAP3 DUP4 MSTORE SWAP1 DUP3 ADD MSTORE DUP2 MLOAD PUSH32 0xD3648BD0F6BA80134A33BA9275AC585D9D315F0AD8355CDDEFDE31AFA28D0E9 SWAP3 SWAP2 DUP2 SWAP1 SUB SWAP1 SWAP2 ADD SWAP1 LOG3 POP POP POP POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x2 PUSH1 0x20 SWAP1 DUP2 MSTORE PUSH1 0x0 SWAP3 DUP4 MSTORE PUSH1 0x40 DUP1 DUP5 KECCAK256 SWAP1 SWAP2 MSTORE SWAP1 DUP3 MSTORE SWAP1 KECCAK256 SLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 JUMP JUMPDEST PUSH1 0x1 SLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND CALLER EQ PUSH2 0x826 JUMPI PUSH1 0x40 DUP1 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x20 PUSH1 0x4 DUP3 ADD MSTORE PUSH1 0x14 PUSH1 0x24 DUP3 ADD MSTORE PUSH32 0x556E697377617056323A20464F5242494444454E000000000000000000000000 PUSH1 0x44 DUP3 ADD MSTORE SWAP1 MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x64 ADD SWAP1 REVERT JUMPDEST PUSH1 0x0 DUP1 SLOAD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFF0000000000000000000000000000000000000000 AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP3 SWAP1 SWAP3 AND SWAP2 SWAP1 SWAP2 OR SWAP1 SSTORE JUMP JUMPDEST PUSH2 0x2D74 DUP1 PUSH2 0x87B DUP4 CODECOPY ADD SWAP1 JUMP INVALID PUSH1 0x80 PUSH1 0x40 MSTORE PUSH1 0x1 PUSH1 0xC SSTORE CALLVALUE DUP1 ISZERO PUSH2 0x15 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x40 MLOAD CHAINID SWAP1 DUP1 PUSH1 0x52 PUSH2 0x2D22 DUP3 CODECOPY PUSH1 0x40 DUP1 MLOAD SWAP2 DUP3 SWAP1 SUB PUSH1 0x52 ADD DUP3 KECCAK256 DUP3 DUP3 ADD DUP3 MSTORE PUSH1 0xA DUP4 MSTORE PUSH10 0x2AB734B9BBB0B8102B19 PUSH1 0xB1 SHL PUSH1 0x20 SWAP4 DUP5 ADD MSTORE DUP2 MLOAD DUP1 DUP4 ADD DUP4 MSTORE PUSH1 0x1 DUP2 MSTORE PUSH1 0x31 PUSH1 0xF8 SHL SWAP1 DUP5 ADD MSTORE DUP2 MLOAD DUP1 DUP5 ADD SWAP2 SWAP1 SWAP2 MSTORE PUSH32 0xBFCC8EF98FFBF7B6C3FEC7BF5185B566B9863E35A9D83ACD49AD6824B5969738 DUP2 DUP4 ADD MSTORE PUSH32 0xC89EFDAA54C0F20C7ADF612882DF0950F5A951637E0307CDCB4C672F298B8BC6 PUSH1 0x60 DUP3 ADD MSTORE PUSH1 0x80 DUP2 ADD SWAP5 SWAP1 SWAP5 MSTORE ADDRESS PUSH1 0xA0 DUP1 DUP7 ADD SWAP2 SWAP1 SWAP2 MSTORE DUP2 MLOAD DUP1 DUP7 SUB SWAP1 SWAP2 ADD DUP2 MSTORE PUSH1 0xC0 SWAP1 SWAP5 ADD SWAP1 MSTORE DUP3 MLOAD SWAP3 ADD SWAP2 SWAP1 SWAP2 KECCAK256 PUSH1 0x3 SSTORE POP PUSH1 0x5 DUP1 SLOAD PUSH1 0x1 PUSH1 0x1 PUSH1 0xA0 SHL SUB NOT AND CALLER OR SWAP1 SSTORE PUSH2 0x2C1D DUP1 PUSH2 0x105 PUSH1 0x0 CODECOPY PUSH1 0x0 RETURN INVALID PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x4 CALLDATASIZE LT PUSH2 0x1B9 JUMPI PUSH1 0x0 CALLDATALOAD PUSH1 0xE0 SHR DUP1 PUSH4 0x6A627842 GT PUSH2 0xF9 JUMPI DUP1 PUSH4 0xBA9A7A56 GT PUSH2 0x97 JUMPI DUP1 PUSH4 0xD21220A7 GT PUSH2 0x71 JUMPI DUP1 PUSH4 0xD21220A7 EQ PUSH2 0x5DA JUMPI DUP1 PUSH4 0xD505ACCF EQ PUSH2 0x5E2 JUMPI DUP1 PUSH4 0xDD62ED3E EQ PUSH2 0x640 JUMPI DUP1 PUSH4 0xFFF6CAE9 EQ PUSH2 0x67B JUMPI PUSH2 0x1B9 JUMP JUMPDEST DUP1 PUSH4 0xBA9A7A56 EQ PUSH2 0x597 JUMPI DUP1 PUSH4 0xBC25CF77 EQ PUSH2 0x59F JUMPI DUP1 PUSH4 0xC45A0155 EQ PUSH2 0x5D2 JUMPI PUSH2 0x1B9 JUMP JUMPDEST DUP1 PUSH4 0x7ECEBE00 GT PUSH2 0xD3 JUMPI DUP1 PUSH4 0x7ECEBE00 EQ PUSH2 0x4D7 JUMPI DUP1 PUSH4 0x89AFCB44 EQ PUSH2 0x50A JUMPI DUP1 PUSH4 0x95D89B41 EQ PUSH2 0x556 JUMPI DUP1 PUSH4 0xA9059CBB EQ PUSH2 0x55E JUMPI PUSH2 0x1B9 JUMP JUMPDEST DUP1 PUSH4 0x6A627842 EQ PUSH2 0x469 JUMPI DUP1 PUSH4 0x70A08231 EQ PUSH2 0x49C JUMPI DUP1 PUSH4 0x7464FC3D EQ PUSH2 0x4CF JUMPI PUSH2 0x1B9 JUMP JUMPDEST DUP1 PUSH4 0x23B872DD GT PUSH2 0x166 JUMPI DUP1 PUSH4 0x3644E515 GT PUSH2 0x140 JUMPI DUP1 PUSH4 0x3644E515 EQ PUSH2 0x416 JUMPI DUP1 PUSH4 0x485CC955 EQ PUSH2 0x41E JUMPI DUP1 PUSH4 0x5909C0D5 EQ PUSH2 0x459 JUMPI DUP1 PUSH4 0x5A3D5493 EQ PUSH2 0x461 JUMPI PUSH2 0x1B9 JUMP JUMPDEST DUP1 PUSH4 0x23B872DD EQ PUSH2 0x3AD JUMPI DUP1 PUSH4 0x30ADF81F EQ PUSH2 0x3F0 JUMPI DUP1 PUSH4 0x313CE567 EQ PUSH2 0x3F8 JUMPI PUSH2 0x1B9 JUMP JUMPDEST DUP1 PUSH4 0x95EA7B3 GT PUSH2 0x197 JUMPI DUP1 PUSH4 0x95EA7B3 EQ PUSH2 0x315 JUMPI DUP1 PUSH4 0xDFE1681 EQ PUSH2 0x362 JUMPI DUP1 PUSH4 0x18160DDD EQ PUSH2 0x393 JUMPI PUSH2 0x1B9 JUMP JUMPDEST DUP1 PUSH4 0x22C0D9F EQ PUSH2 0x1BE JUMPI DUP1 PUSH4 0x6FDDE03 EQ PUSH2 0x259 JUMPI DUP1 PUSH4 0x902F1AC EQ PUSH2 0x2D6 JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x257 PUSH1 0x4 DUP1 CALLDATASIZE SUB PUSH1 0x80 DUP2 LT ISZERO PUSH2 0x1D4 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 CALLDATALOAD SWAP2 PUSH1 0x20 DUP2 ADD CALLDATALOAD SWAP2 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF PUSH1 0x40 DUP4 ADD CALLDATALOAD AND SWAP2 SWAP1 DUP2 ADD SWAP1 PUSH1 0x80 DUP2 ADD PUSH1 0x60 DUP3 ADD CALLDATALOAD PUSH5 0x100000000 DUP2 GT ISZERO PUSH2 0x218 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP3 ADD DUP4 PUSH1 0x20 DUP3 ADD GT ISZERO PUSH2 0x22A JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP1 CALLDATALOAD SWAP1 PUSH1 0x20 ADD SWAP2 DUP5 PUSH1 0x1 DUP4 MUL DUP5 ADD GT PUSH5 0x100000000 DUP4 GT OR ISZERO PUSH2 0x24C JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP SWAP1 SWAP3 POP SWAP1 POP PUSH2 0x683 JUMP JUMPDEST STOP JUMPDEST PUSH2 0x261 PUSH2 0xD57 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH1 0x20 DUP1 DUP3 MSTORE DUP4 MLOAD DUP2 DUP4 ADD MSTORE DUP4 MLOAD SWAP2 SWAP3 DUP4 SWAP3 SWAP1 DUP4 ADD SWAP2 DUP6 ADD SWAP1 DUP1 DUP4 DUP4 PUSH1 0x0 JUMPDEST DUP4 DUP2 LT ISZERO PUSH2 0x29B JUMPI DUP2 DUP2 ADD MLOAD DUP4 DUP3 ADD MSTORE PUSH1 0x20 ADD PUSH2 0x283 JUMP JUMPDEST POP POP POP POP SWAP1 POP SWAP1 DUP2 ADD SWAP1 PUSH1 0x1F AND DUP1 ISZERO PUSH2 0x2C8 JUMPI DUP1 DUP3 SUB DUP1 MLOAD PUSH1 0x1 DUP4 PUSH1 0x20 SUB PUSH2 0x100 EXP SUB NOT AND DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP JUMPDEST POP SWAP3 POP POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH2 0x2DE PUSH2 0xD90 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH14 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP5 DUP6 AND DUP2 MSTORE SWAP3 SWAP1 SWAP4 AND PUSH1 0x20 DUP4 ADD MSTORE PUSH4 0xFFFFFFFF AND DUP2 DUP4 ADD MSTORE SWAP1 MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x60 ADD SWAP1 RETURN JUMPDEST PUSH2 0x34E PUSH1 0x4 DUP1 CALLDATASIZE SUB PUSH1 0x40 DUP2 LT ISZERO PUSH2 0x32B JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP2 CALLDATALOAD AND SWAP1 PUSH1 0x20 ADD CALLDATALOAD PUSH2 0xDE5 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD SWAP2 ISZERO ISZERO DUP3 MSTORE MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x20 ADD SWAP1 RETURN JUMPDEST PUSH2 0x36A PUSH2 0xDFC JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP1 SWAP3 AND DUP3 MSTORE MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x20 ADD SWAP1 RETURN JUMPDEST PUSH2 0x39B PUSH2 0xE18 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD SWAP2 DUP3 MSTORE MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x20 ADD SWAP1 RETURN JUMPDEST PUSH2 0x34E PUSH1 0x4 DUP1 CALLDATASIZE SUB PUSH1 0x60 DUP2 LT ISZERO PUSH2 0x3C3 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP2 CALLDATALOAD DUP2 AND SWAP2 PUSH1 0x20 DUP2 ADD CALLDATALOAD SWAP1 SWAP2 AND SWAP1 PUSH1 0x40 ADD CALLDATALOAD PUSH2 0xE1E JUMP JUMPDEST PUSH2 0x39B PUSH2 0xEFD JUMP JUMPDEST PUSH2 0x400 PUSH2 0xF21 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH1 0xFF SWAP1 SWAP3 AND DUP3 MSTORE MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x20 ADD SWAP1 RETURN JUMPDEST PUSH2 0x39B PUSH2 0xF26 JUMP JUMPDEST PUSH2 0x257 PUSH1 0x4 DUP1 CALLDATASIZE SUB PUSH1 0x40 DUP2 LT ISZERO PUSH2 0x434 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP2 CALLDATALOAD DUP2 AND SWAP2 PUSH1 0x20 ADD CALLDATALOAD AND PUSH2 0xF2C JUMP JUMPDEST PUSH2 0x39B PUSH2 0x1005 JUMP JUMPDEST PUSH2 0x39B PUSH2 0x100B JUMP JUMPDEST PUSH2 0x39B PUSH1 0x4 DUP1 CALLDATASIZE SUB PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x47F JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP CALLDATALOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH2 0x1011 JUMP JUMPDEST PUSH2 0x39B PUSH1 0x4 DUP1 CALLDATASIZE SUB PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x4B2 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP CALLDATALOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH2 0x13CB JUMP JUMPDEST PUSH2 0x39B PUSH2 0x13DD JUMP JUMPDEST PUSH2 0x39B PUSH1 0x4 DUP1 CALLDATASIZE SUB PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x4ED JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP CALLDATALOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH2 0x13E3 JUMP JUMPDEST PUSH2 0x53D PUSH1 0x4 DUP1 CALLDATASIZE SUB PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x520 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP CALLDATALOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH2 0x13F5 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD SWAP3 DUP4 MSTORE PUSH1 0x20 DUP4 ADD SWAP2 SWAP1 SWAP2 MSTORE DUP1 MLOAD SWAP2 DUP3 SWAP1 SUB ADD SWAP1 RETURN JUMPDEST PUSH2 0x261 PUSH2 0x1892 JUMP JUMPDEST PUSH2 0x34E PUSH1 0x4 DUP1 CALLDATASIZE SUB PUSH1 0x40 DUP2 LT ISZERO PUSH2 0x574 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP2 CALLDATALOAD AND SWAP1 PUSH1 0x20 ADD CALLDATALOAD PUSH2 0x18CB JUMP JUMPDEST PUSH2 0x39B PUSH2 0x18D8 JUMP JUMPDEST PUSH2 0x257 PUSH1 0x4 DUP1 CALLDATASIZE SUB PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x5B5 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP CALLDATALOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH2 0x18DE JUMP JUMPDEST PUSH2 0x36A PUSH2 0x1AD4 JUMP JUMPDEST PUSH2 0x36A PUSH2 0x1AF0 JUMP JUMPDEST PUSH2 0x257 PUSH1 0x4 DUP1 CALLDATASIZE SUB PUSH1 0xE0 DUP2 LT ISZERO PUSH2 0x5F8 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP2 CALLDATALOAD DUP2 AND SWAP2 PUSH1 0x20 DUP2 ADD CALLDATALOAD SWAP1 SWAP2 AND SWAP1 PUSH1 0x40 DUP2 ADD CALLDATALOAD SWAP1 PUSH1 0x60 DUP2 ADD CALLDATALOAD SWAP1 PUSH1 0xFF PUSH1 0x80 DUP3 ADD CALLDATALOAD AND SWAP1 PUSH1 0xA0 DUP2 ADD CALLDATALOAD SWAP1 PUSH1 0xC0 ADD CALLDATALOAD PUSH2 0x1B0C JUMP JUMPDEST PUSH2 0x39B PUSH1 0x4 DUP1 CALLDATASIZE SUB PUSH1 0x40 DUP2 LT ISZERO PUSH2 0x656 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP2 CALLDATALOAD DUP2 AND SWAP2 PUSH1 0x20 ADD CALLDATALOAD AND PUSH2 0x1DD8 JUMP JUMPDEST PUSH2 0x257 PUSH2 0x1DF5 JUMP JUMPDEST PUSH1 0xC SLOAD PUSH1 0x1 EQ PUSH2 0x6F4 JUMPI PUSH1 0x40 DUP1 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x20 PUSH1 0x4 DUP3 ADD MSTORE PUSH1 0x11 PUSH1 0x24 DUP3 ADD MSTORE PUSH32 0x556E697377617056323A204C4F434B4544000000000000000000000000000000 PUSH1 0x44 DUP3 ADD MSTORE SWAP1 MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x64 ADD SWAP1 REVERT JUMPDEST PUSH1 0x0 PUSH1 0xC SSTORE DUP5 ISZERO ISZERO DUP1 PUSH2 0x707 JUMPI POP PUSH1 0x0 DUP5 GT JUMPDEST PUSH2 0x75C JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD DUP1 DUP1 PUSH1 0x20 ADD DUP3 DUP2 SUB DUP3 MSTORE PUSH1 0x25 DUP2 MSTORE PUSH1 0x20 ADD DUP1 PUSH2 0x2B2F PUSH1 0x25 SWAP2 CODECOPY PUSH1 0x40 ADD SWAP2 POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 REVERT JUMPDEST PUSH1 0x0 DUP1 PUSH2 0x767 PUSH2 0xD90 JUMP JUMPDEST POP SWAP2 POP SWAP2 POP DUP2 PUSH14 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP8 LT DUP1 ISZERO PUSH2 0x79A JUMPI POP DUP1 PUSH14 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP7 LT JUMPDEST PUSH2 0x7EF JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD DUP1 DUP1 PUSH1 0x20 ADD DUP3 DUP2 SUB DUP3 MSTORE PUSH1 0x21 DUP2 MSTORE PUSH1 0x20 ADD DUP1 PUSH2 0x2B78 PUSH1 0x21 SWAP2 CODECOPY PUSH1 0x40 ADD SWAP2 POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 REVERT JUMPDEST PUSH1 0x6 SLOAD PUSH1 0x7 SLOAD PUSH1 0x0 SWAP2 DUP3 SWAP2 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP2 DUP3 AND SWAP2 SWAP1 DUP2 AND SWAP1 DUP10 AND DUP3 EQ DUP1 ISZERO SWAP1 PUSH2 0x854 JUMPI POP DUP1 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP10 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND EQ ISZERO JUMPDEST PUSH2 0x8BF JUMPI PUSH1 0x40 DUP1 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x20 PUSH1 0x4 DUP3 ADD MSTORE PUSH1 0x15 PUSH1 0x24 DUP3 ADD MSTORE PUSH32 0x556E697377617056323A20494E56414C49445F544F0000000000000000000000 PUSH1 0x44 DUP3 ADD MSTORE SWAP1 MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x64 ADD SWAP1 REVERT JUMPDEST DUP11 ISZERO PUSH2 0x8D0 JUMPI PUSH2 0x8D0 DUP3 DUP11 DUP14 PUSH2 0x1FDB JUMP JUMPDEST DUP10 ISZERO PUSH2 0x8E1 JUMPI PUSH2 0x8E1 DUP2 DUP11 DUP13 PUSH2 0x1FDB JUMP JUMPDEST DUP7 ISZERO PUSH2 0x9C3 JUMPI DUP9 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH4 0x10D1E85C CALLER DUP14 DUP14 DUP13 DUP13 PUSH1 0x40 MLOAD DUP7 PUSH4 0xFFFFFFFF AND PUSH1 0xE0 SHL DUP2 MSTORE PUSH1 0x4 ADD DUP1 DUP7 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD DUP6 DUP2 MSTORE PUSH1 0x20 ADD DUP5 DUP2 MSTORE PUSH1 0x20 ADD DUP1 PUSH1 0x20 ADD DUP3 DUP2 SUB DUP3 MSTORE DUP5 DUP5 DUP3 DUP2 DUP2 MSTORE PUSH1 0x20 ADD SWAP3 POP DUP1 DUP3 DUP5 CALLDATACOPY PUSH1 0x0 DUP2 DUP5 ADD MSTORE PUSH1 0x1F NOT PUSH1 0x1F DUP3 ADD AND SWAP1 POP DUP1 DUP4 ADD SWAP3 POP POP POP SWAP7 POP POP POP POP POP POP POP PUSH1 0x0 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 PUSH1 0x0 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x9AA JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0x9BE JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH32 0x70A0823100000000000000000000000000000000000000000000000000000000 DUP2 MSTORE ADDRESS PUSH1 0x4 DUP3 ADD MSTORE SWAP1 MLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP5 AND SWAP2 PUSH4 0x70A08231 SWAP2 PUSH1 0x24 DUP1 DUP4 ADD SWAP3 PUSH1 0x20 SWAP3 SWAP2 SWAP1 DUP3 SWAP1 SUB ADD DUP2 DUP7 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0xA2F JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS STATICCALL ISZERO DUP1 ISZERO PUSH2 0xA43 JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH1 0x40 MLOAD RETURNDATASIZE PUSH1 0x20 DUP2 LT ISZERO PUSH2 0xA59 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP MLOAD PUSH1 0x40 DUP1 MLOAD PUSH32 0x70A0823100000000000000000000000000000000000000000000000000000000 DUP2 MSTORE ADDRESS PUSH1 0x4 DUP3 ADD MSTORE SWAP1 MLOAD SWAP2 SWAP6 POP PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP4 AND SWAP2 PUSH4 0x70A08231 SWAP2 PUSH1 0x24 DUP1 DUP3 ADD SWAP3 PUSH1 0x20 SWAP3 SWAP1 SWAP2 SWAP1 DUP3 SWAP1 SUB ADD DUP2 DUP7 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0xACB JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS STATICCALL ISZERO DUP1 ISZERO PUSH2 0xADF JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH1 0x40 MLOAD RETURNDATASIZE PUSH1 0x20 DUP2 LT ISZERO PUSH2 0xAF5 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP MLOAD SWAP3 POP PUSH1 0x0 SWAP2 POP POP PUSH14 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP6 AND DUP11 SWAP1 SUB DUP4 GT PUSH2 0xB1F JUMPI PUSH1 0x0 PUSH2 0xB35 JUMP JUMPDEST DUP10 DUP6 PUSH14 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND SUB DUP4 SUB JUMPDEST SWAP1 POP PUSH1 0x0 DUP10 DUP6 PUSH14 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND SUB DUP4 GT PUSH2 0xB59 JUMPI PUSH1 0x0 PUSH2 0xB6F JUMP JUMPDEST DUP10 DUP6 PUSH14 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND SUB DUP4 SUB JUMPDEST SWAP1 POP PUSH1 0x0 DUP3 GT DUP1 PUSH2 0xB80 JUMPI POP PUSH1 0x0 DUP2 GT JUMPDEST PUSH2 0xBD5 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD DUP1 DUP1 PUSH1 0x20 ADD DUP3 DUP2 SUB DUP3 MSTORE PUSH1 0x24 DUP2 MSTORE PUSH1 0x20 ADD DUP1 PUSH2 0x2B54 PUSH1 0x24 SWAP2 CODECOPY PUSH1 0x40 ADD SWAP2 POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 REVERT JUMPDEST PUSH1 0x0 PUSH2 0xC09 PUSH2 0xBEB DUP5 PUSH1 0x3 PUSH4 0xFFFFFFFF PUSH2 0x21E8 AND JUMP JUMPDEST PUSH2 0xBFD DUP8 PUSH2 0x3E8 PUSH4 0xFFFFFFFF PUSH2 0x21E8 AND JUMP JUMPDEST SWAP1 PUSH4 0xFFFFFFFF PUSH2 0x226E AND JUMP JUMPDEST SWAP1 POP PUSH1 0x0 PUSH2 0xC21 PUSH2 0xBEB DUP5 PUSH1 0x3 PUSH4 0xFFFFFFFF PUSH2 0x21E8 AND JUMP JUMPDEST SWAP1 POP PUSH2 0xC59 PUSH3 0xF4240 PUSH2 0xC4D PUSH14 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP12 DUP2 AND SWAP1 DUP12 AND PUSH4 0xFFFFFFFF PUSH2 0x21E8 AND JUMP JUMPDEST SWAP1 PUSH4 0xFFFFFFFF PUSH2 0x21E8 AND JUMP JUMPDEST PUSH2 0xC69 DUP4 DUP4 PUSH4 0xFFFFFFFF PUSH2 0x21E8 AND JUMP JUMPDEST LT ISZERO PUSH2 0xCD6 JUMPI PUSH1 0x40 DUP1 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x20 PUSH1 0x4 DUP3 ADD MSTORE PUSH1 0xC PUSH1 0x24 DUP3 ADD MSTORE PUSH32 0x556E697377617056323A204B0000000000000000000000000000000000000000 PUSH1 0x44 DUP3 ADD MSTORE SWAP1 MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x64 ADD SWAP1 REVERT JUMPDEST POP POP PUSH2 0xCE4 DUP5 DUP5 DUP9 DUP9 PUSH2 0x22E0 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD DUP4 DUP2 MSTORE PUSH1 0x20 DUP2 ADD DUP4 SWAP1 MSTORE DUP1 DUP3 ADD DUP14 SWAP1 MSTORE PUSH1 0x60 DUP2 ADD DUP13 SWAP1 MSTORE SWAP1 MLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP12 AND SWAP2 CALLER SWAP2 PUSH32 0xD78AD95FA46C994B6551D0DA85FC275FE613CE37657FB8D5E3D130840159D822 SWAP2 DUP2 SWAP1 SUB PUSH1 0x80 ADD SWAP1 LOG3 POP POP PUSH1 0x1 PUSH1 0xC SSTORE POP POP POP POP POP POP POP POP POP JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 PUSH1 0x40 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0xA DUP2 MSTORE PUSH1 0x20 ADD PUSH32 0x556E697377617020563200000000000000000000000000000000000000000000 DUP2 MSTORE POP DUP2 JUMP JUMPDEST PUSH1 0x8 SLOAD PUSH14 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP1 DUP3 AND SWAP3 PUSH15 0x10000000000000000000000000000 DUP4 DIV SWAP1 SWAP2 AND SWAP2 PUSH29 0x100000000000000000000000000000000000000000000000000000000 SWAP1 DIV PUSH4 0xFFFFFFFF AND SWAP1 JUMP JUMPDEST PUSH1 0x0 PUSH2 0xDF2 CALLER DUP5 DUP5 PUSH2 0x259C JUMP JUMPDEST POP PUSH1 0x1 JUMPDEST SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x6 SLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 JUMP JUMPDEST PUSH1 0x0 SLOAD DUP2 JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP4 AND PUSH1 0x0 SWAP1 DUP2 MSTORE PUSH1 0x2 PUSH1 0x20 SWAP1 DUP2 MSTORE PUSH1 0x40 DUP1 DUP4 KECCAK256 CALLER DUP5 MSTORE SWAP1 SWAP2 MSTORE DUP2 KECCAK256 SLOAD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF EQ PUSH2 0xEE8 JUMPI PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP5 AND PUSH1 0x0 SWAP1 DUP2 MSTORE PUSH1 0x2 PUSH1 0x20 SWAP1 DUP2 MSTORE PUSH1 0x40 DUP1 DUP4 KECCAK256 CALLER DUP5 MSTORE SWAP1 SWAP2 MSTORE SWAP1 KECCAK256 SLOAD PUSH2 0xEB6 SWAP1 DUP4 PUSH4 0xFFFFFFFF PUSH2 0x226E AND JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP6 AND PUSH1 0x0 SWAP1 DUP2 MSTORE PUSH1 0x2 PUSH1 0x20 SWAP1 DUP2 MSTORE PUSH1 0x40 DUP1 DUP4 KECCAK256 CALLER DUP5 MSTORE SWAP1 SWAP2 MSTORE SWAP1 KECCAK256 SSTORE JUMPDEST PUSH2 0xEF3 DUP5 DUP5 DUP5 PUSH2 0x260B JUMP JUMPDEST POP PUSH1 0x1 SWAP4 SWAP3 POP POP POP JUMP JUMPDEST PUSH32 0x6E71EDAE12B1B97F4D1F60370FEF10105FA2FAAE0126114A169C64845D6126C9 DUP2 JUMP JUMPDEST PUSH1 0x12 DUP2 JUMP JUMPDEST PUSH1 0x3 SLOAD DUP2 JUMP JUMPDEST PUSH1 0x5 SLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND CALLER EQ PUSH2 0xFB2 JUMPI PUSH1 0x40 DUP1 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x20 PUSH1 0x4 DUP3 ADD MSTORE PUSH1 0x14 PUSH1 0x24 DUP3 ADD MSTORE PUSH32 0x556E697377617056323A20464F5242494444454E000000000000000000000000 PUSH1 0x44 DUP3 ADD MSTORE SWAP1 MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x64 ADD SWAP1 REVERT JUMPDEST PUSH1 0x6 DUP1 SLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP4 DUP5 AND PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFF0000000000000000000000000000000000000000 SWAP2 DUP3 AND OR SWAP1 SWAP2 SSTORE PUSH1 0x7 DUP1 SLOAD SWAP3 SWAP1 SWAP4 AND SWAP2 AND OR SWAP1 SSTORE JUMP JUMPDEST PUSH1 0x9 SLOAD DUP2 JUMP JUMPDEST PUSH1 0xA SLOAD DUP2 JUMP JUMPDEST PUSH1 0x0 PUSH1 0xC SLOAD PUSH1 0x1 EQ PUSH2 0x1084 JUMPI PUSH1 0x40 DUP1 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x20 PUSH1 0x4 DUP3 ADD MSTORE PUSH1 0x11 PUSH1 0x24 DUP3 ADD MSTORE PUSH32 0x556E697377617056323A204C4F434B4544000000000000000000000000000000 PUSH1 0x44 DUP3 ADD MSTORE SWAP1 MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x64 ADD SWAP1 REVERT JUMPDEST PUSH1 0x0 PUSH1 0xC DUP2 SWAP1 SSTORE DUP1 PUSH2 0x1094 PUSH2 0xD90 JUMP JUMPDEST POP PUSH1 0x6 SLOAD PUSH1 0x40 DUP1 MLOAD PUSH32 0x70A0823100000000000000000000000000000000000000000000000000000000 DUP2 MSTORE ADDRESS PUSH1 0x4 DUP3 ADD MSTORE SWAP1 MLOAD SWAP4 SWAP6 POP SWAP2 SWAP4 POP PUSH1 0x0 SWAP3 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP1 SWAP2 AND SWAP2 PUSH4 0x70A08231 SWAP2 PUSH1 0x24 DUP1 DUP4 ADD SWAP3 PUSH1 0x20 SWAP3 SWAP2 SWAP1 DUP3 SWAP1 SUB ADD DUP2 DUP7 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x110E JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS STATICCALL ISZERO DUP1 ISZERO PUSH2 0x1122 JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH1 0x40 MLOAD RETURNDATASIZE PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x1138 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP MLOAD PUSH1 0x7 SLOAD PUSH1 0x40 DUP1 MLOAD PUSH32 0x70A0823100000000000000000000000000000000000000000000000000000000 DUP2 MSTORE ADDRESS PUSH1 0x4 DUP3 ADD MSTORE SWAP1 MLOAD SWAP3 SWAP4 POP PUSH1 0x0 SWAP3 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP1 SWAP3 AND SWAP2 PUSH4 0x70A08231 SWAP2 PUSH1 0x24 DUP1 DUP3 ADD SWAP3 PUSH1 0x20 SWAP3 SWAP1 SWAP2 SWAP1 DUP3 SWAP1 SUB ADD DUP2 DUP7 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x11B1 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS STATICCALL ISZERO DUP1 ISZERO PUSH2 0x11C5 JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH1 0x40 MLOAD RETURNDATASIZE PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x11DB JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP MLOAD SWAP1 POP PUSH1 0x0 PUSH2 0x1201 DUP4 PUSH14 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP8 AND PUSH4 0xFFFFFFFF PUSH2 0x226E AND JUMP JUMPDEST SWAP1 POP PUSH1 0x0 PUSH2 0x1225 DUP4 PUSH14 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP8 AND PUSH4 0xFFFFFFFF PUSH2 0x226E AND JUMP JUMPDEST SWAP1 POP PUSH1 0x0 PUSH2 0x1233 DUP8 DUP8 PUSH2 0x26EC JUMP JUMPDEST PUSH1 0x0 SLOAD SWAP1 SWAP2 POP DUP1 PUSH2 0x1270 JUMPI PUSH2 0x125C PUSH2 0x3E8 PUSH2 0xBFD PUSH2 0x1257 DUP8 DUP8 PUSH4 0xFFFFFFFF PUSH2 0x21E8 AND JUMP JUMPDEST PUSH2 0x2878 JUMP JUMPDEST SWAP9 POP PUSH2 0x126B PUSH1 0x0 PUSH2 0x3E8 PUSH2 0x28CA JUMP JUMPDEST PUSH2 0x12CD JUMP JUMPDEST PUSH2 0x12CA PUSH14 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP10 AND PUSH2 0x1294 DUP7 DUP5 PUSH4 0xFFFFFFFF PUSH2 0x21E8 AND JUMP JUMPDEST DUP2 PUSH2 0x129B JUMPI INVALID JUMPDEST DIV PUSH14 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP10 AND PUSH2 0x12BD DUP7 DUP6 PUSH4 0xFFFFFFFF PUSH2 0x21E8 AND JUMP JUMPDEST DUP2 PUSH2 0x12C4 JUMPI INVALID JUMPDEST DIV PUSH2 0x297A JUMP JUMPDEST SWAP9 POP JUMPDEST PUSH1 0x0 DUP10 GT PUSH2 0x1326 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD DUP1 DUP1 PUSH1 0x20 ADD DUP3 DUP2 SUB DUP3 MSTORE PUSH1 0x28 DUP2 MSTORE PUSH1 0x20 ADD DUP1 PUSH2 0x2BC1 PUSH1 0x28 SWAP2 CODECOPY PUSH1 0x40 ADD SWAP2 POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 REVERT JUMPDEST PUSH2 0x1330 DUP11 DUP11 PUSH2 0x28CA JUMP JUMPDEST PUSH2 0x133C DUP7 DUP7 DUP11 DUP11 PUSH2 0x22E0 JUMP JUMPDEST DUP2 ISZERO PUSH2 0x137E JUMPI PUSH1 0x8 SLOAD PUSH2 0x137A SWAP1 PUSH14 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP1 DUP3 AND SWAP2 PUSH15 0x10000000000000000000000000000 SWAP1 DIV AND PUSH4 0xFFFFFFFF PUSH2 0x21E8 AND JUMP JUMPDEST PUSH1 0xB SSTORE JUMPDEST PUSH1 0x40 DUP1 MLOAD DUP6 DUP2 MSTORE PUSH1 0x20 DUP2 ADD DUP6 SWAP1 MSTORE DUP2 MLOAD CALLER SWAP3 PUSH32 0x4C209B5FC8AD50758F13E2E1088BA56A560DFF690A1C6FEF26394F4C03821C4F SWAP3 DUP3 SWAP1 SUB ADD SWAP1 LOG2 POP POP PUSH1 0x1 PUSH1 0xC SSTORE POP SWAP5 SWAP7 SWAP6 POP POP POP POP POP POP JUMP JUMPDEST PUSH1 0x1 PUSH1 0x20 MSTORE PUSH1 0x0 SWAP1 DUP2 MSTORE PUSH1 0x40 SWAP1 KECCAK256 SLOAD DUP2 JUMP JUMPDEST PUSH1 0xB SLOAD DUP2 JUMP JUMPDEST PUSH1 0x4 PUSH1 0x20 MSTORE PUSH1 0x0 SWAP1 DUP2 MSTORE PUSH1 0x40 SWAP1 KECCAK256 SLOAD DUP2 JUMP JUMPDEST PUSH1 0x0 DUP1 PUSH1 0xC SLOAD PUSH1 0x1 EQ PUSH2 0x1469 JUMPI PUSH1 0x40 DUP1 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x20 PUSH1 0x4 DUP3 ADD MSTORE PUSH1 0x11 PUSH1 0x24 DUP3 ADD MSTORE PUSH32 0x556E697377617056323A204C4F434B4544000000000000000000000000000000 PUSH1 0x44 DUP3 ADD MSTORE SWAP1 MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x64 ADD SWAP1 REVERT JUMPDEST PUSH1 0x0 PUSH1 0xC DUP2 SWAP1 SSTORE DUP1 PUSH2 0x1479 PUSH2 0xD90 JUMP JUMPDEST POP PUSH1 0x6 SLOAD PUSH1 0x7 SLOAD PUSH1 0x40 DUP1 MLOAD PUSH32 0x70A0823100000000000000000000000000000000000000000000000000000000 DUP2 MSTORE ADDRESS PUSH1 0x4 DUP3 ADD MSTORE SWAP1 MLOAD SWAP5 SWAP7 POP SWAP3 SWAP5 POP PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP2 DUP3 AND SWAP4 SWAP2 AND SWAP2 PUSH1 0x0 SWAP2 DUP5 SWAP2 PUSH4 0x70A08231 SWAP2 PUSH1 0x24 DUP1 DUP4 ADD SWAP3 PUSH1 0x20 SWAP3 SWAP2 SWAP1 DUP3 SWAP1 SUB ADD DUP2 DUP7 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x14FB JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS STATICCALL ISZERO DUP1 ISZERO PUSH2 0x150F JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH1 0x40 MLOAD RETURNDATASIZE PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x1525 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP MLOAD PUSH1 0x40 DUP1 MLOAD PUSH32 0x70A0823100000000000000000000000000000000000000000000000000000000 DUP2 MSTORE ADDRESS PUSH1 0x4 DUP3 ADD MSTORE SWAP1 MLOAD SWAP2 SWAP3 POP PUSH1 0x0 SWAP2 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP6 AND SWAP2 PUSH4 0x70A08231 SWAP2 PUSH1 0x24 DUP1 DUP4 ADD SWAP3 PUSH1 0x20 SWAP3 SWAP2 SWAP1 DUP3 SWAP1 SUB ADD DUP2 DUP7 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x1599 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS STATICCALL ISZERO DUP1 ISZERO PUSH2 0x15AD JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH1 0x40 MLOAD RETURNDATASIZE PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x15C3 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP MLOAD ADDRESS PUSH1 0x0 SWAP1 DUP2 MSTORE PUSH1 0x1 PUSH1 0x20 MSTORE PUSH1 0x40 DUP2 KECCAK256 SLOAD SWAP2 SWAP3 POP PUSH2 0x15E2 DUP9 DUP9 PUSH2 0x26EC JUMP JUMPDEST PUSH1 0x0 SLOAD SWAP1 SWAP2 POP DUP1 PUSH2 0x15F9 DUP5 DUP8 PUSH4 0xFFFFFFFF PUSH2 0x21E8 AND JUMP JUMPDEST DUP2 PUSH2 0x1600 JUMPI INVALID JUMPDEST DIV SWAP11 POP DUP1 PUSH2 0x1614 DUP5 DUP7 PUSH4 0xFFFFFFFF PUSH2 0x21E8 AND JUMP JUMPDEST DUP2 PUSH2 0x161B JUMPI INVALID JUMPDEST DIV SWAP10 POP PUSH1 0x0 DUP12 GT DUP1 ISZERO PUSH2 0x162E JUMPI POP PUSH1 0x0 DUP11 GT JUMPDEST PUSH2 0x1683 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD DUP1 DUP1 PUSH1 0x20 ADD DUP3 DUP2 SUB DUP3 MSTORE PUSH1 0x28 DUP2 MSTORE PUSH1 0x20 ADD DUP1 PUSH2 0x2B99 PUSH1 0x28 SWAP2 CODECOPY PUSH1 0x40 ADD SWAP2 POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 REVERT JUMPDEST PUSH2 0x168D ADDRESS DUP5 PUSH2 0x2992 JUMP JUMPDEST PUSH2 0x1698 DUP8 DUP14 DUP14 PUSH2 0x1FDB JUMP JUMPDEST PUSH2 0x16A3 DUP7 DUP14 DUP13 PUSH2 0x1FDB JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH32 0x70A0823100000000000000000000000000000000000000000000000000000000 DUP2 MSTORE ADDRESS PUSH1 0x4 DUP3 ADD MSTORE SWAP1 MLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP10 AND SWAP2 PUSH4 0x70A08231 SWAP2 PUSH1 0x24 DUP1 DUP4 ADD SWAP3 PUSH1 0x20 SWAP3 SWAP2 SWAP1 DUP3 SWAP1 SUB ADD DUP2 DUP7 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x170F JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS STATICCALL ISZERO DUP1 ISZERO PUSH2 0x1723 JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH1 0x40 MLOAD RETURNDATASIZE PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x1739 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP MLOAD PUSH1 0x40 DUP1 MLOAD PUSH32 0x70A0823100000000000000000000000000000000000000000000000000000000 DUP2 MSTORE ADDRESS PUSH1 0x4 DUP3 ADD MSTORE SWAP1 MLOAD SWAP2 SWAP7 POP PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP9 AND SWAP2 PUSH4 0x70A08231 SWAP2 PUSH1 0x24 DUP1 DUP3 ADD SWAP3 PUSH1 0x20 SWAP3 SWAP1 SWAP2 SWAP1 DUP3 SWAP1 SUB ADD DUP2 DUP7 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x17AB JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS STATICCALL ISZERO DUP1 ISZERO PUSH2 0x17BF JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH1 0x40 MLOAD RETURNDATASIZE PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x17D5 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP MLOAD SWAP4 POP PUSH2 0x17E5 DUP6 DUP6 DUP12 DUP12 PUSH2 0x22E0 JUMP JUMPDEST DUP2 ISZERO PUSH2 0x1827 JUMPI PUSH1 0x8 SLOAD PUSH2 0x1823 SWAP1 PUSH14 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP1 DUP3 AND SWAP2 PUSH15 0x10000000000000000000000000000 SWAP1 DIV AND PUSH4 0xFFFFFFFF PUSH2 0x21E8 AND JUMP JUMPDEST PUSH1 0xB SSTORE JUMPDEST PUSH1 0x40 DUP1 MLOAD DUP13 DUP2 MSTORE PUSH1 0x20 DUP2 ADD DUP13 SWAP1 MSTORE DUP2 MLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP16 AND SWAP3 CALLER SWAP3 PUSH32 0xDCCD412F0B1252819CB1FD330B93224CA42612892BB3F4F789976E6D81936496 SWAP3 SWAP1 DUP2 SWAP1 SUB SWAP1 SWAP2 ADD SWAP1 LOG3 POP POP POP POP POP POP POP POP POP PUSH1 0x1 PUSH1 0xC DUP2 SWAP1 SSTORE POP SWAP2 POP SWAP2 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 PUSH1 0x40 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x6 DUP2 MSTORE PUSH1 0x20 ADD PUSH32 0x554E492D56320000000000000000000000000000000000000000000000000000 DUP2 MSTORE POP DUP2 JUMP JUMPDEST PUSH1 0x0 PUSH2 0xDF2 CALLER DUP5 DUP5 PUSH2 0x260B JUMP JUMPDEST PUSH2 0x3E8 DUP2 JUMP JUMPDEST PUSH1 0xC SLOAD PUSH1 0x1 EQ PUSH2 0x194F JUMPI PUSH1 0x40 DUP1 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x20 PUSH1 0x4 DUP3 ADD MSTORE PUSH1 0x11 PUSH1 0x24 DUP3 ADD MSTORE PUSH32 0x556E697377617056323A204C4F434B4544000000000000000000000000000000 PUSH1 0x44 DUP3 ADD MSTORE SWAP1 MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x64 ADD SWAP1 REVERT JUMPDEST PUSH1 0x0 PUSH1 0xC SSTORE PUSH1 0x6 SLOAD PUSH1 0x7 SLOAD PUSH1 0x8 SLOAD PUSH1 0x40 DUP1 MLOAD PUSH32 0x70A0823100000000000000000000000000000000000000000000000000000000 DUP2 MSTORE ADDRESS PUSH1 0x4 DUP3 ADD MSTORE SWAP1 MLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP5 DUP6 AND SWAP5 SWAP1 SWAP4 AND SWAP3 PUSH2 0x1A2B SWAP3 DUP6 SWAP3 DUP8 SWAP3 PUSH2 0x1A26 SWAP3 PUSH14 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND SWAP2 DUP6 SWAP2 PUSH4 0x70A08231 SWAP2 PUSH1 0x24 DUP1 DUP3 ADD SWAP3 PUSH1 0x20 SWAP3 SWAP1 SWAP2 SWAP1 DUP3 SWAP1 SUB ADD DUP2 DUP7 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x19EE JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS STATICCALL ISZERO DUP1 ISZERO PUSH2 0x1A02 JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH1 0x40 MLOAD RETURNDATASIZE PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x1A18 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP MLOAD SWAP1 PUSH4 0xFFFFFFFF PUSH2 0x226E AND JUMP JUMPDEST PUSH2 0x1FDB JUMP JUMPDEST PUSH1 0x8 SLOAD PUSH1 0x40 DUP1 MLOAD PUSH32 0x70A0823100000000000000000000000000000000000000000000000000000000 DUP2 MSTORE ADDRESS PUSH1 0x4 DUP3 ADD MSTORE SWAP1 MLOAD PUSH2 0x1ACA SWAP3 DUP5 SWAP3 DUP8 SWAP3 PUSH2 0x1A26 SWAP3 PUSH15 0x10000000000000000000000000000 SWAP1 DIV PUSH14 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND SWAP2 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP7 AND SWAP2 PUSH4 0x70A08231 SWAP2 PUSH1 0x24 DUP1 DUP3 ADD SWAP3 PUSH1 0x20 SWAP3 SWAP1 SWAP2 SWAP1 DUP3 SWAP1 SUB ADD DUP2 DUP7 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x19EE JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP POP PUSH1 0x1 PUSH1 0xC SSTORE POP JUMP JUMPDEST PUSH1 0x5 SLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 JUMP JUMPDEST PUSH1 0x7 SLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 JUMP JUMPDEST TIMESTAMP DUP5 LT ISZERO PUSH2 0x1B7B JUMPI PUSH1 0x40 DUP1 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x20 PUSH1 0x4 DUP3 ADD MSTORE PUSH1 0x12 PUSH1 0x24 DUP3 ADD MSTORE PUSH32 0x556E697377617056323A20455850495245440000000000000000000000000000 PUSH1 0x44 DUP3 ADD MSTORE SWAP1 MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x64 ADD SWAP1 REVERT JUMPDEST PUSH1 0x3 SLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP1 DUP10 AND PUSH1 0x0 DUP2 DUP2 MSTORE PUSH1 0x4 PUSH1 0x20 SWAP1 DUP2 MSTORE PUSH1 0x40 DUP1 DUP4 KECCAK256 DUP1 SLOAD PUSH1 0x1 DUP1 DUP3 ADD SWAP1 SWAP3 SSTORE DUP3 MLOAD PUSH32 0x6E71EDAE12B1B97F4D1F60370FEF10105FA2FAAE0126114A169C64845D6126C9 DUP2 DUP7 ADD MSTORE DUP1 DUP5 ADD SWAP7 SWAP1 SWAP7 MSTORE SWAP6 DUP14 AND PUSH1 0x60 DUP7 ADD MSTORE PUSH1 0x80 DUP6 ADD DUP13 SWAP1 MSTORE PUSH1 0xA0 DUP6 ADD SWAP6 SWAP1 SWAP6 MSTORE PUSH1 0xC0 DUP1 DUP6 ADD DUP12 SWAP1 MSTORE DUP2 MLOAD DUP1 DUP7 SUB SWAP1 SWAP2 ADD DUP2 MSTORE PUSH1 0xE0 DUP6 ADD DUP3 MSTORE DUP1 MLOAD SWAP1 DUP4 ADD KECCAK256 PUSH32 0x1901000000000000000000000000000000000000000000000000000000000000 PUSH2 0x100 DUP7 ADD MSTORE PUSH2 0x102 DUP6 ADD SWAP7 SWAP1 SWAP7 MSTORE PUSH2 0x122 DUP1 DUP6 ADD SWAP7 SWAP1 SWAP7 MSTORE DUP1 MLOAD DUP1 DUP6 SUB SWAP1 SWAP7 ADD DUP7 MSTORE PUSH2 0x142 DUP5 ADD DUP1 DUP3 MSTORE DUP7 MLOAD SWAP7 DUP4 ADD SWAP7 SWAP1 SWAP7 KECCAK256 SWAP6 DUP4 SWAP1 MSTORE PUSH2 0x162 DUP5 ADD DUP1 DUP3 MSTORE DUP7 SWAP1 MSTORE PUSH1 0xFF DUP10 AND PUSH2 0x182 DUP6 ADD MSTORE PUSH2 0x1A2 DUP5 ADD DUP9 SWAP1 MSTORE PUSH2 0x1C2 DUP5 ADD DUP8 SWAP1 MSTORE MLOAD SWAP2 SWAP4 SWAP3 PUSH2 0x1E2 DUP1 DUP3 ADD SWAP4 PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 DUP2 ADD SWAP3 DUP2 SWAP1 SUB SWAP1 SWAP2 ADD SWAP1 DUP6 GAS STATICCALL ISZERO DUP1 ISZERO PUSH2 0x1CDC JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP PUSH1 0x40 MLOAD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 ADD MLOAD SWAP2 POP POP PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP2 AND ISZERO DUP1 ISZERO SWAP1 PUSH2 0x1D57 JUMPI POP DUP9 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND EQ JUMPDEST PUSH2 0x1DC2 JUMPI PUSH1 0x40 DUP1 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x20 PUSH1 0x4 DUP3 ADD MSTORE PUSH1 0x1C PUSH1 0x24 DUP3 ADD MSTORE PUSH32 0x556E697377617056323A20494E56414C49445F5349474E415455524500000000 PUSH1 0x44 DUP3 ADD MSTORE SWAP1 MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x64 ADD SWAP1 REVERT JUMPDEST PUSH2 0x1DCD DUP10 DUP10 DUP10 PUSH2 0x259C JUMP JUMPDEST POP POP POP POP POP POP POP POP POP JUMP JUMPDEST PUSH1 0x2 PUSH1 0x20 SWAP1 DUP2 MSTORE PUSH1 0x0 SWAP3 DUP4 MSTORE PUSH1 0x40 DUP1 DUP5 KECCAK256 SWAP1 SWAP2 MSTORE SWAP1 DUP3 MSTORE SWAP1 KECCAK256 SLOAD DUP2 JUMP JUMPDEST PUSH1 0xC SLOAD PUSH1 0x1 EQ PUSH2 0x1E66 JUMPI PUSH1 0x40 DUP1 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x20 PUSH1 0x4 DUP3 ADD MSTORE PUSH1 0x11 PUSH1 0x24 DUP3 ADD MSTORE PUSH32 0x556E697377617056323A204C4F434B4544000000000000000000000000000000 PUSH1 0x44 DUP3 ADD MSTORE SWAP1 MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x64 ADD SWAP1 REVERT JUMPDEST PUSH1 0x0 PUSH1 0xC SSTORE PUSH1 0x6 SLOAD PUSH1 0x40 DUP1 MLOAD PUSH32 0x70A0823100000000000000000000000000000000000000000000000000000000 DUP2 MSTORE ADDRESS PUSH1 0x4 DUP3 ADD MSTORE SWAP1 MLOAD PUSH2 0x1FD4 SWAP3 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND SWAP2 PUSH4 0x70A08231 SWAP2 PUSH1 0x24 DUP1 DUP4 ADD SWAP3 PUSH1 0x20 SWAP3 SWAP2 SWAP1 DUP3 SWAP1 SUB ADD DUP2 DUP7 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x1EDD JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS STATICCALL ISZERO DUP1 ISZERO PUSH2 0x1EF1 JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH1 0x40 MLOAD RETURNDATASIZE PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x1F07 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP MLOAD PUSH1 0x7 SLOAD PUSH1 0x40 DUP1 MLOAD PUSH32 0x70A0823100000000000000000000000000000000000000000000000000000000 DUP2 MSTORE ADDRESS PUSH1 0x4 DUP3 ADD MSTORE SWAP1 MLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP1 SWAP3 AND SWAP2 PUSH4 0x70A08231 SWAP2 PUSH1 0x24 DUP1 DUP3 ADD SWAP3 PUSH1 0x20 SWAP3 SWAP1 SWAP2 SWAP1 DUP3 SWAP1 SUB ADD DUP2 DUP7 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x1F7A JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS STATICCALL ISZERO DUP1 ISZERO PUSH2 0x1F8E JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH1 0x40 MLOAD RETURNDATASIZE PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x1FA4 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP MLOAD PUSH1 0x8 SLOAD PUSH14 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP1 DUP3 AND SWAP2 PUSH15 0x10000000000000000000000000000 SWAP1 DIV AND PUSH2 0x22E0 JUMP JUMPDEST PUSH1 0x1 PUSH1 0xC SSTORE JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD DUP1 DUP3 ADD DUP3 MSTORE PUSH1 0x19 DUP2 MSTORE PUSH32 0x7472616E7366657228616464726573732C75696E743235362900000000000000 PUSH1 0x20 SWAP2 DUP3 ADD MSTORE DUP2 MLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP6 DUP2 AND PUSH1 0x24 DUP4 ADD MSTORE PUSH1 0x44 DUP1 DUP4 ADD DUP7 SWAP1 MSTORE DUP5 MLOAD DUP1 DUP5 SUB SWAP1 SWAP2 ADD DUP2 MSTORE PUSH1 0x64 SWAP1 SWAP3 ADD DUP5 MSTORE SWAP2 DUP2 ADD DUP1 MLOAD PUSH28 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH32 0xA9059CBB00000000000000000000000000000000000000000000000000000000 OR DUP2 MSTORE SWAP3 MLOAD DUP2 MLOAD PUSH1 0x0 SWAP5 PUSH1 0x60 SWAP5 DUP10 AND SWAP4 SWAP3 SWAP2 DUP3 SWAP2 SWAP1 DUP1 DUP4 DUP4 JUMPDEST PUSH1 0x20 DUP4 LT PUSH2 0x20E1 JUMPI DUP1 MLOAD DUP3 MSTORE PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 SWAP1 SWAP3 ADD SWAP2 PUSH1 0x20 SWAP2 DUP3 ADD SWAP2 ADD PUSH2 0x20A4 JUMP JUMPDEST PUSH1 0x1 DUP4 PUSH1 0x20 SUB PUSH2 0x100 EXP SUB DUP1 NOT DUP3 MLOAD AND DUP2 DUP5 MLOAD AND DUP1 DUP3 OR DUP6 MSTORE POP POP POP POP POP POP SWAP1 POP ADD SWAP2 POP POP PUSH1 0x0 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 PUSH1 0x0 DUP7 GAS CALL SWAP2 POP POP RETURNDATASIZE DUP1 PUSH1 0x0 DUP2 EQ PUSH2 0x2143 JUMPI PUSH1 0x40 MLOAD SWAP2 POP PUSH1 0x1F NOT PUSH1 0x3F RETURNDATASIZE ADD AND DUP3 ADD PUSH1 0x40 MSTORE RETURNDATASIZE DUP3 MSTORE RETURNDATASIZE PUSH1 0x0 PUSH1 0x20 DUP5 ADD RETURNDATACOPY PUSH2 0x2148 JUMP JUMPDEST PUSH1 0x60 SWAP2 POP JUMPDEST POP SWAP2 POP SWAP2 POP DUP2 DUP1 ISZERO PUSH2 0x2176 JUMPI POP DUP1 MLOAD ISZERO DUP1 PUSH2 0x2176 JUMPI POP DUP1 DUP1 PUSH1 0x20 ADD SWAP1 MLOAD PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x2173 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP MLOAD JUMPDEST PUSH2 0x21E1 JUMPI PUSH1 0x40 DUP1 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x20 PUSH1 0x4 DUP3 ADD MSTORE PUSH1 0x1A PUSH1 0x24 DUP3 ADD MSTORE PUSH32 0x556E697377617056323A205452414E534645525F4641494C4544000000000000 PUSH1 0x44 DUP3 ADD MSTORE SWAP1 MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x64 ADD SWAP1 REVERT JUMPDEST POP POP POP POP POP JUMP JUMPDEST PUSH1 0x0 DUP2 ISZERO DUP1 PUSH2 0x2203 JUMPI POP POP DUP1 DUP3 MUL DUP3 DUP3 DUP3 DUP2 PUSH2 0x2200 JUMPI INVALID JUMPDEST DIV EQ JUMPDEST PUSH2 0xDF6 JUMPI PUSH1 0x40 DUP1 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x20 PUSH1 0x4 DUP3 ADD MSTORE PUSH1 0x14 PUSH1 0x24 DUP3 ADD MSTORE PUSH32 0x64732D6D6174682D6D756C2D6F766572666C6F77000000000000000000000000 PUSH1 0x44 DUP3 ADD MSTORE SWAP1 MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x64 ADD SWAP1 REVERT JUMPDEST DUP1 DUP3 SUB DUP3 DUP2 GT ISZERO PUSH2 0xDF6 JUMPI PUSH1 0x40 DUP1 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x20 PUSH1 0x4 DUP3 ADD MSTORE PUSH1 0x15 PUSH1 0x24 DUP3 ADD MSTORE PUSH32 0x64732D6D6174682D7375622D756E646572666C6F770000000000000000000000 PUSH1 0x44 DUP3 ADD MSTORE SWAP1 MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x64 ADD SWAP1 REVERT JUMPDEST PUSH14 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP5 GT DUP1 ISZERO SWAP1 PUSH2 0x230C JUMPI POP PUSH14 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP4 GT ISZERO JUMPDEST PUSH2 0x2377 JUMPI PUSH1 0x40 DUP1 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x20 PUSH1 0x4 DUP3 ADD MSTORE PUSH1 0x13 PUSH1 0x24 DUP3 ADD MSTORE PUSH32 0x556E697377617056323A204F564552464C4F5700000000000000000000000000 PUSH1 0x44 DUP3 ADD MSTORE SWAP1 MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x64 ADD SWAP1 REVERT JUMPDEST PUSH1 0x8 SLOAD PUSH4 0xFFFFFFFF TIMESTAMP DUP2 AND SWAP2 PUSH29 0x100000000000000000000000000000000000000000000000000000000 SWAP1 DIV DUP2 AND DUP3 SUB SWAP1 DUP2 AND ISZERO DUP1 ISZERO SWAP1 PUSH2 0x23C7 JUMPI POP PUSH14 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP5 AND ISZERO ISZERO JUMPDEST DUP1 ISZERO PUSH2 0x23E2 JUMPI POP PUSH14 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP4 AND ISZERO ISZERO JUMPDEST ISZERO PUSH2 0x2492 JUMPI DUP1 PUSH4 0xFFFFFFFF AND PUSH2 0x2425 DUP6 PUSH2 0x23FB DUP7 PUSH2 0x2A57 JUMP JUMPDEST PUSH28 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND SWAP1 PUSH4 0xFFFFFFFF PUSH2 0x2A7B AND JUMP JUMPDEST PUSH1 0x9 DUP1 SLOAD PUSH28 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP3 SWAP1 SWAP3 AND SWAP3 SWAP1 SWAP3 MUL ADD SWAP1 SSTORE PUSH4 0xFFFFFFFF DUP2 AND PUSH2 0x2465 DUP5 PUSH2 0x23FB DUP8 PUSH2 0x2A57 JUMP JUMPDEST PUSH1 0xA DUP1 SLOAD PUSH28 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP3 SWAP1 SWAP3 AND SWAP3 SWAP1 SWAP3 MUL ADD SWAP1 SSTORE JUMPDEST PUSH1 0x8 DUP1 SLOAD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000000000000000000000000000 AND PUSH14 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP9 DUP2 AND SWAP2 SWAP1 SWAP2 OR PUSH32 0xFFFFFFFF0000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH15 0x10000000000000000000000000000 DUP9 DUP4 AND DUP2 MUL SWAP2 SWAP1 SWAP2 OR PUSH28 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH29 0x100000000000000000000000000000000000000000000000000000000 PUSH4 0xFFFFFFFF DUP8 AND MUL OR SWAP3 DUP4 SWAP1 SSTORE PUSH1 0x40 DUP1 MLOAD DUP5 DUP5 AND DUP2 MSTORE SWAP2 SWAP1 SWAP4 DIV SWAP1 SWAP2 AND PUSH1 0x20 DUP3 ADD MSTORE DUP2 MLOAD PUSH32 0x1C411E9A96E071241C2F21F7726B17AE89E3CAB4C78BE50E062B03A9FFFBBAD1 SWAP3 SWAP2 DUP2 SWAP1 SUB SWAP1 SWAP2 ADD SWAP1 LOG1 POP POP POP POP POP POP JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP1 DUP5 AND PUSH1 0x0 DUP2 DUP2 MSTORE PUSH1 0x2 PUSH1 0x20 SWAP1 DUP2 MSTORE PUSH1 0x40 DUP1 DUP4 KECCAK256 SWAP5 DUP8 AND DUP1 DUP5 MSTORE SWAP5 DUP3 MSTORE SWAP2 DUP3 SWAP1 KECCAK256 DUP6 SWAP1 SSTORE DUP2 MLOAD DUP6 DUP2 MSTORE SWAP2 MLOAD PUSH32 0x8C5BE1E5EBEC7D5BD14F71427D1E84F3DD0314C0F7B2291E5B200AC8C7C3B925 SWAP3 DUP2 SWAP1 SUB SWAP1 SWAP2 ADD SWAP1 LOG3 POP POP POP JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP4 AND PUSH1 0x0 SWAP1 DUP2 MSTORE PUSH1 0x1 PUSH1 0x20 MSTORE PUSH1 0x40 SWAP1 KECCAK256 SLOAD PUSH2 0x2641 SWAP1 DUP3 PUSH4 0xFFFFFFFF PUSH2 0x226E AND JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP1 DUP6 AND PUSH1 0x0 SWAP1 DUP2 MSTORE PUSH1 0x1 PUSH1 0x20 MSTORE PUSH1 0x40 DUP1 DUP3 KECCAK256 SWAP4 SWAP1 SWAP4 SSTORE SWAP1 DUP5 AND DUP2 MSTORE KECCAK256 SLOAD PUSH2 0x2683 SWAP1 DUP3 PUSH4 0xFFFFFFFF PUSH2 0x2ABC AND JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP1 DUP5 AND PUSH1 0x0 DUP2 DUP2 MSTORE PUSH1 0x1 PUSH1 0x20 SWAP1 DUP2 MSTORE PUSH1 0x40 SWAP2 DUP3 SWAP1 KECCAK256 SWAP5 SWAP1 SWAP5 SSTORE DUP1 MLOAD DUP6 DUP2 MSTORE SWAP1 MLOAD SWAP2 SWAP4 SWAP3 DUP8 AND SWAP3 PUSH32 0xDDF252AD1BE2C89B69C2B068FC378DAA952BA7F163C4A11628F55A4DF523B3EF SWAP3 SWAP2 DUP3 SWAP1 SUB ADD SWAP1 LOG3 POP POP POP JUMP JUMPDEST PUSH1 0x0 DUP1 PUSH1 0x5 PUSH1 0x0 SWAP1 SLOAD SWAP1 PUSH2 0x100 EXP SWAP1 DIV PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH4 0x17E7E58 PUSH1 0x40 MLOAD DUP2 PUSH4 0xFFFFFFFF AND PUSH1 0xE0 SHL DUP2 MSTORE PUSH1 0x4 ADD PUSH1 0x20 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 DUP7 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0x2757 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS STATICCALL ISZERO DUP1 ISZERO PUSH2 0x276B JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH1 0x40 MLOAD RETURNDATASIZE PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x2781 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP MLOAD PUSH1 0xB SLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP3 AND ISZERO DUP1 ISZERO SWAP5 POP SWAP2 SWAP3 POP SWAP1 PUSH2 0x2864 JUMPI DUP1 ISZERO PUSH2 0x285F JUMPI PUSH1 0x0 PUSH2 0x27D8 PUSH2 0x1257 PUSH14 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP9 DUP2 AND SWAP1 DUP9 AND PUSH4 0xFFFFFFFF PUSH2 0x21E8 AND JUMP JUMPDEST SWAP1 POP PUSH1 0x0 PUSH2 0x27E5 DUP4 PUSH2 0x2878 JUMP JUMPDEST SWAP1 POP DUP1 DUP3 GT ISZERO PUSH2 0x285C JUMPI PUSH1 0x0 PUSH2 0x2813 PUSH2 0x2804 DUP5 DUP5 PUSH4 0xFFFFFFFF PUSH2 0x226E AND JUMP JUMPDEST PUSH1 0x0 SLOAD SWAP1 PUSH4 0xFFFFFFFF PUSH2 0x21E8 AND JUMP JUMPDEST SWAP1 POP PUSH1 0x0 PUSH2 0x2838 DUP4 PUSH2 0x282C DUP7 PUSH1 0x5 PUSH4 0xFFFFFFFF PUSH2 0x21E8 AND JUMP JUMPDEST SWAP1 PUSH4 0xFFFFFFFF PUSH2 0x2ABC AND JUMP JUMPDEST SWAP1 POP PUSH1 0x0 DUP2 DUP4 DUP2 PUSH2 0x2845 JUMPI INVALID JUMPDEST DIV SWAP1 POP DUP1 ISZERO PUSH2 0x2858 JUMPI PUSH2 0x2858 DUP8 DUP3 PUSH2 0x28CA JUMP JUMPDEST POP POP POP JUMPDEST POP POP JUMPDEST PUSH2 0x2870 JUMP JUMPDEST DUP1 ISZERO PUSH2 0x2870 JUMPI PUSH1 0x0 PUSH1 0xB SSTORE JUMPDEST POP POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x3 DUP3 GT ISZERO PUSH2 0x28BB JUMPI POP DUP1 PUSH1 0x1 PUSH1 0x2 DUP3 DIV ADD JUMPDEST DUP2 DUP2 LT ISZERO PUSH2 0x28B5 JUMPI DUP1 SWAP2 POP PUSH1 0x2 DUP2 DUP3 DUP6 DUP2 PUSH2 0x28A4 JUMPI INVALID JUMPDEST DIV ADD DUP2 PUSH2 0x28AD JUMPI INVALID JUMPDEST DIV SWAP1 POP PUSH2 0x288D JUMP JUMPDEST POP PUSH2 0x28C5 JUMP JUMPDEST DUP2 ISZERO PUSH2 0x28C5 JUMPI POP PUSH1 0x1 JUMPDEST SWAP2 SWAP1 POP JUMP JUMPDEST PUSH1 0x0 SLOAD PUSH2 0x28DD SWAP1 DUP3 PUSH4 0xFFFFFFFF PUSH2 0x2ABC AND JUMP JUMPDEST PUSH1 0x0 SWAP1 DUP2 SSTORE PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP4 AND DUP2 MSTORE PUSH1 0x1 PUSH1 0x20 MSTORE PUSH1 0x40 SWAP1 KECCAK256 SLOAD PUSH2 0x2915 SWAP1 DUP3 PUSH4 0xFFFFFFFF PUSH2 0x2ABC AND JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP4 AND PUSH1 0x0 DUP2 DUP2 MSTORE PUSH1 0x1 PUSH1 0x20 SWAP1 DUP2 MSTORE PUSH1 0x40 DUP1 DUP4 KECCAK256 SWAP5 SWAP1 SWAP5 SSTORE DUP4 MLOAD DUP6 DUP2 MSTORE SWAP4 MLOAD SWAP3 SWAP4 SWAP2 SWAP3 PUSH32 0xDDF252AD1BE2C89B69C2B068FC378DAA952BA7F163C4A11628F55A4DF523B3EF SWAP3 DUP2 SWAP1 SUB SWAP1 SWAP2 ADD SWAP1 LOG3 POP POP JUMP JUMPDEST PUSH1 0x0 DUP2 DUP4 LT PUSH2 0x2989 JUMPI DUP2 PUSH2 0x298B JUMP JUMPDEST DUP3 JUMPDEST SWAP4 SWAP3 POP POP POP JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP3 AND PUSH1 0x0 SWAP1 DUP2 MSTORE PUSH1 0x1 PUSH1 0x20 MSTORE PUSH1 0x40 SWAP1 KECCAK256 SLOAD PUSH2 0x29C8 SWAP1 DUP3 PUSH4 0xFFFFFFFF PUSH2 0x226E AND JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP4 AND PUSH1 0x0 SWAP1 DUP2 MSTORE PUSH1 0x1 PUSH1 0x20 MSTORE PUSH1 0x40 DUP2 KECCAK256 SWAP2 SWAP1 SWAP2 SSTORE SLOAD PUSH2 0x2A02 SWAP1 DUP3 PUSH4 0xFFFFFFFF PUSH2 0x226E AND JUMP JUMPDEST PUSH1 0x0 SWAP1 DUP2 SSTORE PUSH1 0x40 DUP1 MLOAD DUP4 DUP2 MSTORE SWAP1 MLOAD PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP6 AND SWAP2 PUSH32 0xDDF252AD1BE2C89B69C2B068FC378DAA952BA7F163C4A11628F55A4DF523B3EF SWAP2 SWAP1 DUP2 SWAP1 SUB PUSH1 0x20 ADD SWAP1 LOG3 POP POP JUMP JUMPDEST PUSH14 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH15 0x10000000000000000000000000000 MUL SWAP1 JUMP JUMPDEST PUSH1 0x0 PUSH14 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP3 AND PUSH28 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP5 AND DUP2 PUSH2 0x2AB4 JUMPI INVALID JUMPDEST DIV SWAP4 SWAP3 POP POP POP JUMP JUMPDEST DUP1 DUP3 ADD DUP3 DUP2 LT ISZERO PUSH2 0xDF6 JUMPI PUSH1 0x40 DUP1 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x20 PUSH1 0x4 DUP3 ADD MSTORE PUSH1 0x14 PUSH1 0x24 DUP3 ADD MSTORE PUSH32 0x64732D6D6174682D6164642D6F766572666C6F77000000000000000000000000 PUSH1 0x44 DUP3 ADD MSTORE SWAP1 MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x64 ADD SWAP1 REVERT INVALID SSTORE PUSH15 0x697377617056323A20494E53554646 0x49 NUMBER 0x49 GASLIMIT 0x4E SLOAD 0x5F 0x4F SSTORE SLOAD POP SSTORE SLOAD 0x5F COINBASE 0x4D 0x4F SSTORE 0x4E SLOAD SSTORE PUSH15 0x697377617056323A20494E53554646 0x49 NUMBER 0x49 GASLIMIT 0x4E SLOAD 0x5F 0x49 0x4E POP SSTORE SLOAD 0x5F COINBASE 0x4D 0x4F SSTORE 0x4E SLOAD SSTORE PUSH15 0x697377617056323A20494E53554646 0x49 NUMBER 0x49 GASLIMIT 0x4E SLOAD 0x5F 0x4C 0x49 MLOAD SSTORE 0x49 DIFFICULTY 0x49 SLOAD MSIZE SSTORE PUSH15 0x697377617056323A20494E53554646 0x49 NUMBER 0x49 GASLIMIT 0x4E SLOAD 0x5F 0x4C 0x49 MLOAD SSTORE 0x49 DIFFICULTY 0x49 SLOAD MSIZE 0x5F TIMESTAMP SSTORE MSTORE 0x4E GASLIMIT DIFFICULTY SSTORE PUSH15 0x697377617056323A20494E53554646 0x49 NUMBER 0x49 GASLIMIT 0x4E SLOAD 0x5F 0x4C 0x49 MLOAD SSTORE 0x49 DIFFICULTY 0x49 SLOAD MSIZE 0x5F 0x4D 0x49 0x4E SLOAD GASLIMIT DIFFICULTY LOG2 PUSH6 0x627A7A723158 KECCAK256 PUSH30 0xCA18479E58487606BF70C79E44D8DEE62353C9EE6D01F9A9D70885B8765F 0x22 PUSH5 0x736F6C6343 STOP SDIV LT STOP ORIGIN GASLIMIT 0x49 POP CALLDATACOPY BALANCE ORIGIN DIFFICULTY PUSH16 0x6D61696E28737472696E67206E616D65 0x2C PUSH20 0x7472696E672076657273696F6E2C75696E743235 CALLDATASIZE KECCAK256 PUSH4 0x6861696E 0x49 PUSH5 0x2C61646472 PUSH6 0x737320766572 PUSH10 0x6679696E67436F6E7472 PUSH2 0x6374 0x29 LOG2 PUSH6 0x627A7A723158 KECCAK256 0x27 PUSH1 0xF9 0x2D PUSH32 0xA1DB6F5AA16307BAD65DF4EBCC8550C4B1F03755AB8DFD830C178F64736F6C63 NUMBER STOP SDIV LT STOP ORIGIN \",\"sourceMap\":\"102:1764:1:-;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;102:1764:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;155:20;;;:::i;:::-;;;;;;;;;;;;;;;;;;;181:26;;;:::i;282:25::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;282:25:1;;:::i;496:94::-;;;:::i;:::-;;;;;;;;;;;;;;;;1698:166;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;1698:166:1;;;;:::i;:::-;;596:948;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;596:948:1;;;;;;;;;;;:::i;214:62::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;214:62:1;;;;;;;;;;;:::i;1550:142::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;1550:142:1;;;;:::i;155:20::-;;;;;;:::o;181:26::-;;;;;;:::o;282:25::-;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;282:25:1;:::o;496:94::-;568:8;:15;496:94;:::o;1698:166::-;1785:11;;;;1771:10;:25;1763:58;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1831:11;:26;;;;;;;;;;;;;;;1698:166::o;596:948::-;666:12;708:6;698:16;;:6;:16;;;;690:59;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;760:14;776;803:6;794:15;;:6;:15;;;:53;;832:6;840;794:53;;;813:6;821;794:53;759:88;;-1:-1:-1;759:88:1;-1:-1:-1;865:20:1;;;857:56;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;931:37;:15;;;966:1;931:15;;;:7;:15;;;;;;;;:23;;;;;;;;;;;;:37;923:72;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1035:21;1059:32;;;;;;;;:::i;:::-;41:4:-1;34:5;30:16;25:3;21:26;14:5;7:41;87:2;83:7;78:2;73:3;69:12;65:26;61:2;54:38;1059:32:1;1035:56;;1101:12;1143:6;1151;1126:32;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;49:4:-1;39:7;30;26:21;22:32;13:7;6:49;1126:32:1;;;1116:43;;;;;;1101:58;;1247:4;1236:8;1230:15;1225:2;1215:8;1211:17;1208:1;1200:52;1271:47;;;;;;:31;:47;;;;;;;;;;;;;;;;1192:60;;-1:-1:-1;1271:31:1;;;;;;:47;;;;;-1:-1:-1;;1271:47:1;;;;;;;;-1:-1:-1;1271:31:1;:47;;;5:2:-1;;;;30:1;27;20:12;5:2;1271:47:1;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;-1:-1;;;;1328:15:1;;;;;;;;:7;:15;;;;;;;;:23;;;;;;;;;;;;:30;;;;;;;;;;;;;;1368:15;;;;;;:23;;;;;;;;:30;;;;;;;;1453:8;27:10:-1;;-1:-1;23:18;;45:23;;1453:19:1;;;;;;;;;;;;;;;;;;1521:15;;1487:50;;;;;;;;;;;;;;;;;;;;;;596:948;;;;;;;;:::o;214:62::-;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;1550:142::-;1625:11;;;;1611:10;:25;1603:58;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1671:5;:14;;;;;;;;;;;;;;;1550:142::o;102:1764::-;;;;;;;;:::o\"}},\"interface\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_feeToSetter\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token0\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token1\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"pair\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"PairCreated\",\"type\":\"event\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"allPairs\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"allPairsLength\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"tokenA\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"tokenB\",\"type\":\"address\"}],\"name\":\"createPair\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"pair\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"feeTo\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"feeToSetter\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"getPair\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"_feeTo\",\"type\":\"address\"}],\"name\":\"setFeeTo\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"_feeToSetter\",\"type\":\"address\"}],\"name\":\"setFeeToSetter\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]}"
  },
  {
    "path": "crates/evm/traces/Cargo.toml",
    "content": "[package]\nname = \"foundry-evm-traces\"\ndescription = \"EVM trace identifying and decoding\"\n\nversion.workspace = true\nedition.workspace = true\nrust-version.workspace = true\nauthors.workspace = true\nlicense.workspace = true\nhomepage.workspace = true\nrepository.workspace = true\n\n[lints]\nworkspace = true\n\n[dependencies]\nfoundry-block-explorers.workspace = true\nfoundry-common.workspace = true\nfoundry-compilers.workspace = true\nfoundry-linking.workspace = true\nfoundry-config.workspace = true\nfoundry-evm-core.workspace = true\n\nalloy-dyn-abi = { workspace = true, features = [\"arbitrary\", \"eip712\"] }\nalloy-json-abi.workspace = true\nalloy-primitives = { workspace = true, features = [\n    \"serde\",\n    \"getrandom\",\n    \"arbitrary\",\n    \"rlp\",\n] }\nalloy-sol-types.workspace = true\nrevm-inspectors.workspace = true\n\nasync-trait.workspace = true\neyre.workspace = true\nfutures.workspace = true\nitertools.workspace = true\nmemchr.workspace = true\nrayon.workspace = true\nreqwest.workspace = true\nrevm.workspace = true\nserde_json = { workspace = true, features = [\"raw_value\"] }\nserde.workspace = true\nsolar.workspace = true\ntempfile.workspace = true\ntokio = { workspace = true, features = [\"time\", \"macros\"] }\ntracing.workspace = true\nyansi.workspace = true\n"
  },
  {
    "path": "crates/evm/traces/src/backtrace/mod.rs",
    "content": "//! Solidity stack trace support for test failures.\n\nuse crate::{CallTrace, SparsedTraceArena};\nuse alloy_primitives::{Address, Bytes, map::HashMap};\nuse foundry_compilers::{\n    Artifact, ArtifactId, ProjectCompileOutput,\n    artifacts::{ConfigurableContractArtifact, Libraries, sourcemap::SourceMap},\n};\nuse std::{fmt, path::PathBuf};\nuse yansi::Paint;\n\nmod source_map;\nuse source_map::load_build_sources;\npub use source_map::{PcSourceMapper, SourceData};\n\n/// Linked library information for backtrace resolution.\n///\n/// Contains the path, name, and deployed address of a linked library\n/// to enable proper frame resolution in backtraces.\n#[derive(Debug, Clone)]\nstruct LinkedLib {\n    /// The source file path of the library\n    path: PathBuf,\n    /// The name of the library contract\n    name: String,\n    /// The deployed address of the library\n    address: Address,\n}\n\n/// Holds a reference to [`ProjectCompileOutput`] to fetch artifacts and sources for backtrace\n/// generation.\npub struct BacktraceBuilder<'a> {\n    /// Linked libraries from configuration\n    linked_libraries: Vec<LinkedLib>,\n    /// Reference to project output for on-demand source loading\n    output: &'a ProjectCompileOutput,\n    /// Project root\n    root: PathBuf,\n    /// Disable source locations\n    ///\n    /// Source locations will be inaccurately reported if the files have been compiled with via-ir\n    disable_source_locs: bool,\n    /// Sources grouped by [`ArtifactId::build_id`] to avoid re-reading files for artifacts from\n    /// the same build\n    ///\n    /// The source [`Vec`] is indexed by the compiler source ID, and contains the source path and\n    /// source content.\n    build_sources_cache: HashMap<String, Vec<(PathBuf, String)>>,\n}\n\nimpl<'a> BacktraceBuilder<'a> {\n    /// Instantiates a backtrace builder from a [`ProjectCompileOutput`].\n    pub fn new(\n        output: &'a ProjectCompileOutput,\n        root: PathBuf,\n        linked_libraries: Option<Libraries>,\n        disable_source_locs: bool,\n    ) -> Self {\n        let linked_libs = linked_libraries\n            .map(|libs| {\n                libs.libs\n                    .iter()\n                    .flat_map(|(path, libs_map)| {\n                        libs_map.iter().map(move |(name, addr_str)| (path, name, addr_str))\n                    })\n                    .filter_map(|(path, name, addr_str)| {\n                        addr_str.parse().ok().map(|address| LinkedLib {\n                            path: path.clone(),\n                            name: name.clone(),\n                            address,\n                        })\n                    })\n                    .collect()\n            })\n            .unwrap_or_default();\n\n        Self {\n            linked_libraries: linked_libs,\n            output,\n            root,\n            disable_source_locs,\n            build_sources_cache: HashMap::default(),\n        }\n    }\n\n    /// Generates a backtrace from a [`SparsedTraceArena`].\n    pub fn from_traces(&mut self, arena: &SparsedTraceArena) -> Backtrace<'_> {\n        // Resolve addresses to artifacts using trace labels and linked libraries\n        let artifacts_by_address = self.resolve_addresses(arena);\n        for (artifact_id, _) in artifacts_by_address.values() {\n            let build_id = &artifact_id.build_id;\n            if !self.build_sources_cache.contains_key(build_id)\n                && let Some(sources) = load_build_sources(build_id, self.output, &self.root)\n            {\n                self.build_sources_cache.insert(build_id.clone(), sources);\n            }\n        }\n\n        Backtrace::new(\n            artifacts_by_address,\n            &self.build_sources_cache,\n            self.linked_libraries.clone(),\n            self.disable_source_locs,\n            arena,\n        )\n    }\n\n    /// Resolves contract addresses to [`ArtifactId`] and their [`SourceData`] from trace labels and\n    /// linked libraries.\n    fn resolve_addresses(\n        &self,\n        arena: &SparsedTraceArena,\n    ) -> HashMap<Address, (ArtifactId, SourceData)> {\n        let mut artifacts_by_address = HashMap::default();\n\n        // Collect all labels from traces first\n        let label_to_address = arena\n            .nodes()\n            .iter()\n            .filter_map(|node| {\n                if let Some(decoded) = &node.trace.decoded\n                    && let Some(label) = &decoded.label\n                {\n                    return Some((label.as_str(), node.trace.address));\n                }\n                None\n            })\n            .collect::<HashMap<_, _>>();\n\n        // Build linked library target IDs\n        let linked_lib_targets = self\n            .linked_libraries\n            .iter()\n            .map(|lib| (format!(\"{}:{}\", lib.path.display(), lib.name), lib.address))\n            .collect::<HashMap<_, _>>();\n\n        let get_source = |artifact: &ConfigurableContractArtifact| -> Option<(SourceMap, Bytes)> {\n            let source_map = artifact.get_source_map_deployed()?.ok()?;\n            let deployed_bytecode = artifact.get_deployed_bytecode_bytes()?.into_owned();\n\n            if deployed_bytecode.is_empty() {\n                return None;\n            }\n\n            Some((source_map, deployed_bytecode))\n        };\n\n        for (artifact_id, artifact) in self.output.artifact_ids() {\n            // Match and insert artifacts using trace labels\n            if let Some(address) = label_to_address.get(artifact_id.name.as_str())\n                && let Some((source_map, bytecode)) = get_source(artifact)\n            {\n                // Match and insert artifacts using trace labels\n                artifacts_by_address\n                    .insert(*address, (artifact_id.clone(), SourceData { source_map, bytecode }));\n            } else if let Some(&lib_address) =\n                // Match and insert the linked library artifacts\n                linked_lib_targets.get(&artifact_id.identifier()).or_else(|| {\n                        let id = artifact_id\n                            .clone()\n                            .with_stripped_file_prefixes(&self.root)\n                            .identifier();\n                        linked_lib_targets.get(&id)\n                    })\n                && let Some((source_map, bytecode)) = get_source(artifact)\n            {\n                // Insert linked libraries\n                artifacts_by_address\n                    .insert(lib_address, (artifact_id, SourceData { source_map, bytecode }));\n            }\n        }\n\n        artifacts_by_address\n    }\n}\n\n/// A Solidity stack trace for a test failure.\n///\n/// Generates a backtrace from a [`SparsedTraceArena`] by leveraging source maps and bytecode.\n///\n/// It uses the program counter (PC) from the traces to map to a specific source location for the\n/// call.\n///\n/// Each step/call in the backtrace is classified as a BacktraceFrame\n#[non_exhaustive]\npub struct Backtrace<'a> {\n    /// The frames of the backtrace, from innermost (where the revert happened) to outermost.\n    frames: Vec<BacktraceFrame>,\n    /// Map from address to PcSourceMapper\n    pc_mappers: HashMap<Address, PcSourceMapper<'a>>,\n    /// Linked libraries from configuration\n    linked_libraries: Vec<LinkedLib>,\n    /// Disable pinpointing source locations in files\n    ///\n    /// Should be disabled when via-ir is enabled\n    disable_source_locs: bool,\n}\n\nimpl<'a> Backtrace<'a> {\n    /// Creates a backtrace from collected artifacts and sources.\n    fn new(\n        artifacts_by_address: HashMap<Address, (ArtifactId, SourceData)>,\n        build_sources: &'a HashMap<String, Vec<(PathBuf, String)>>,\n        linked_libraries: Vec<LinkedLib>,\n        disable_source_locs: bool,\n        arena: &SparsedTraceArena,\n    ) -> Self {\n        let mut pc_mappers = HashMap::default();\n\n        // Build PC source mappers for each contract\n        if !disable_source_locs {\n            for (addr, (artifact_id, source_data)) in artifacts_by_address {\n                if let Some(sources) = build_sources.get(&artifact_id.build_id) {\n                    let mapper = PcSourceMapper::new(source_data, sources);\n                    pc_mappers.insert(addr, mapper);\n                }\n            }\n        }\n\n        let mut backtrace =\n            Self { frames: Vec::new(), pc_mappers, linked_libraries, disable_source_locs };\n\n        backtrace.extract_frames(arena);\n\n        backtrace\n    }\n\n    /// Extracts backtrace frames from a trace arena.\n    fn extract_frames(&mut self, arena: &SparsedTraceArena) {\n        let resolved_arena = &arena.arena;\n\n        if resolved_arena.nodes().is_empty() {\n            return;\n        }\n\n        // Find the deepest failed node (where the actual revert happened)\n        let mut current_idx = None;\n        let mut max_depth = 0;\n\n        for (idx, node) in resolved_arena.nodes().iter().enumerate() {\n            if !node.trace.success && node.trace.depth >= max_depth {\n                max_depth = node.trace.depth;\n                current_idx = Some(idx);\n            }\n        }\n\n        if current_idx.is_none() {\n            return;\n        }\n\n        // Build the call stack by walking from the deepest node back to root\n        while let Some(idx) = current_idx {\n            let node = &resolved_arena.nodes()[idx];\n            let trace = &node.trace;\n\n            if let Some(frame) = self.create_frame(trace) {\n                self.frames.push(frame);\n            }\n\n            current_idx = node.parent;\n        }\n    }\n\n    /// Creates a frame from a call trace.\n    fn create_frame(&self, trace: &CallTrace) -> Option<BacktraceFrame> {\n        let contract_address = trace.address;\n        let mut frame = BacktraceFrame::new(contract_address);\n\n        // Try to get source location from PC mapper\n        if !self.disable_source_locs\n            && let Some(source_location) = trace.steps.last().and_then(|last_step| {\n                self.pc_mappers.get(&contract_address).and_then(|m| m.map_pc(last_step.pc))\n            })\n        {\n            frame = frame\n                .with_source_location(\n                    source_location.file,\n                    source_location.line,\n                    source_location.column,\n                )\n                .with_byte_offset(source_location.offset);\n        }\n\n        if let Some(decoded) = &trace.decoded {\n            if let Some(label) = &decoded.label {\n                frame = frame.with_contract_name(label.clone());\n            } else if let Some(lib) =\n                self.linked_libraries.iter().find(|l| l.address == contract_address)\n            {\n                frame = frame.with_contract_name(lib.name.clone());\n            }\n\n            if let Some(call_data) = &decoded.call_data {\n                let sig = &call_data.signature;\n                let func_name =\n                    if let Some(paren_pos) = sig.find('(') { &sig[..paren_pos] } else { sig };\n                frame = frame.with_function_name(func_name.to_string());\n            }\n        }\n\n        Some(frame)\n    }\n\n    /// Returns true if the backtrace is empty.\n    pub fn is_empty(&self) -> bool {\n        self.frames.is_empty()\n    }\n}\n\nimpl fmt::Display for Backtrace<'_> {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        if self.frames.is_empty() {\n            return Ok(());\n        }\n\n        writeln!(f, \"{}\", Paint::yellow(\"Backtrace:\"))?;\n\n        for frame in &self.frames {\n            write!(f, \"  \")?;\n            write!(f, \"at \")?;\n            writeln!(f, \"{frame}\")?;\n        }\n\n        Ok(())\n    }\n}\n\n/// A single frame in a backtrace.\n#[derive(Debug, Clone)]\nstruct BacktraceFrame {\n    /// The contract address where this frame is executing.\n    pub contract_address: Address,\n    /// The contract name, if known.\n    pub contract_name: Option<String>,\n    /// The function name, if known.\n    pub function_name: Option<String>,\n    /// The source file path.\n    pub file: Option<PathBuf>,\n    /// The line number in the source file.\n    pub line: Option<usize>,\n    /// The column number in the source file.\n    pub column: Option<usize>,\n    /// The byte offset in the source file.\n    pub byte_offset: Option<usize>,\n}\n\nimpl BacktraceFrame {\n    /// Creates a new backtrace frame.\n    fn new(contract_address: Address) -> Self {\n        Self {\n            contract_address,\n            contract_name: None,\n            function_name: None,\n            file: None,\n            line: None,\n            column: None,\n            byte_offset: None,\n        }\n    }\n\n    /// Sets the contract name.\n    fn with_contract_name(mut self, name: String) -> Self {\n        self.contract_name = Some(name);\n        self\n    }\n\n    /// Sets the function name.\n    fn with_function_name(mut self, name: String) -> Self {\n        self.function_name = Some(name);\n        self\n    }\n\n    /// Sets the source location.\n    fn with_source_location(mut self, file: PathBuf, line: usize, column: usize) -> Self {\n        self.file = Some(file);\n        self.line = Some(line);\n        self.column = Some(column);\n        self\n    }\n\n    /// Sets the byte offset.\n    fn with_byte_offset(mut self, offset: usize) -> Self {\n        self.byte_offset = Some(offset);\n        self\n    }\n}\n\n// Format: <CONTRACT_NAME>.<FUNCTION_NAME> (FILE:LINE:COL)\nimpl fmt::Display for BacktraceFrame {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        let mut result = String::new();\n\n        // No contract name, show address\n        result.push_str(self.contract_name.as_ref().unwrap_or(&self.contract_address.to_string()));\n\n        // Add function name if available\n        result.push_str(&self.function_name.as_ref().map_or(String::new(), |f| format!(\".{f}\")));\n\n        if let Some(file) = &self.file {\n            result.push_str(\" (\");\n            result.push_str(&file.display().to_string());\n        }\n\n        if let Some(line) = self.line {\n            result.push(':');\n            result.push_str(&line.to_string());\n\n            result.push(':');\n            result.push_str(&self.column.as_ref().map_or(\"0\".to_string(), |c| c.to_string()));\n        }\n\n        // Add location in parentheses if available\n        if self.file.is_some() || self.line.is_some() {\n            result.push(')');\n        }\n\n        write!(f, \"{result}\")\n    }\n}\n"
  },
  {
    "path": "crates/evm/traces/src/backtrace/source_map.rs",
    "content": "//! Source map decoding and PC mapping utilities.\n\nuse alloy_primitives::Bytes;\nuse foundry_compilers::{ProjectCompileOutput, artifacts::sourcemap::SourceMap};\nuse foundry_evm_core::ic::IcPcMap;\nuse std::path::{Path, PathBuf};\n\n/// Source data for a single contract.\n#[derive(Debug, Clone)]\npub struct SourceData {\n    /// Runtime source map for the contract\n    pub source_map: SourceMap,\n    /// Deployed bytecode for accurate PC mapping\n    pub bytecode: Bytes,\n}\n\n/// Maps program counters to source locations.\npub struct PcSourceMapper<'a> {\n    /// Mapping from instruction counter to program counter.\n    ic_pc_map: IcPcMap,\n    /// Source data consists of the source_map and the deployed bytecode\n    source_data: SourceData,\n    /// Source files i.e source path and content (indexed by source_id)\n    sources: &'a [(PathBuf, String)],\n    /// Cached line offset mappings for each source file.\n    line_offsets: Vec<Vec<usize>>,\n}\n\nimpl<'a> PcSourceMapper<'a> {\n    /// Creates a new PC to source mapper.\n    pub fn new(source_data: SourceData, sources: &'a [(PathBuf, String)]) -> Self {\n        // Build instruction counter to program counter mapping\n        let ic_pc_map = IcPcMap::new(source_data.bytecode.as_ref());\n\n        // Pre-calculate line offsets for each source file\n        let line_offsets =\n            sources.iter().map(|(_, content)| compute_line_offsets(content)).collect();\n\n        Self { ic_pc_map, source_data, sources, line_offsets }\n    }\n\n    /// Maps a program counter to source location.\n    pub fn map_pc(&self, pc: usize) -> Option<SourceLocation> {\n        // Find the instruction counter for this PC\n        let ic = self.find_instruction_counter(pc)?;\n\n        // Get the source element for this instruction\n        let element = self.source_data.source_map.get(ic)?;\n\n        // Get the source file index - returns None if index is -1\n        let source_idx_opt = element.index();\n\n        let source_idx = source_idx_opt? as usize;\n        if source_idx >= self.sources.len() {\n            return None;\n        }\n\n        // Get the source file info\n        let (file_path, content) = &self.sources[source_idx];\n\n        // Convert byte offset to line and column\n        let offset = element.offset() as usize;\n\n        // Check if offset is valid for this source file\n        if offset >= content.len() {\n            return None;\n        }\n\n        let (line, column) = self.offset_to_line_column(source_idx, offset)?;\n\n        trace!(\n            file = ?file_path,\n            line = line,\n            column = column,\n            offset = offset,\n            \"Mapped PC to source location\"\n        );\n\n        Some(SourceLocation {\n            file: file_path.clone(),\n            line,\n            column,\n            length: element.length() as usize,\n            offset,\n        })\n    }\n\n    /// Finds the instruction counter for a given program counter.\n    fn find_instruction_counter(&self, pc: usize) -> Option<usize> {\n        // The IcPcMap maps IC -> PC, we need the reverse\n        // We find the highest IC that has a PC <= our target PC\n        let mut best_ic = None;\n        let mut best_pc = 0;\n\n        for (ic, mapped_pc) in self.ic_pc_map.iter() {\n            let mapped_pc = *mapped_pc as usize;\n            if mapped_pc <= pc && mapped_pc >= best_pc {\n                best_pc = mapped_pc;\n                best_ic = Some(*ic as usize);\n            }\n        }\n\n        best_ic\n    }\n\n    /// Converts a byte offset to line and column numbers.\n    ///\n    /// Returned lines and column numbers are 1-indexed.\n    fn offset_to_line_column(&self, source_idx: usize, offset: usize) -> Option<(usize, usize)> {\n        let line_offsets = self.line_offsets.get(source_idx)?;\n\n        // Find the line containing this offset\n        let line = line_offsets.binary_search(&offset).unwrap_or_else(|i| i.saturating_sub(1));\n\n        // Calculate column within the line\n        let line_start = if line == 0 { 0 } else { line_offsets[line - 1] + 1 };\n        let column = offset.saturating_sub(line_start);\n\n        // Lines and columns are 1-indexed\n        Some((line + 1, column + 1))\n    }\n}\n/// Represents a location in source code.\n#[derive(Debug, Clone)]\npub struct SourceLocation {\n    pub file: PathBuf,\n    pub line: usize,\n    pub column: usize,\n    pub length: usize,\n    /// Byte offset in the source file\n    /// This specifically useful when one source file contains multiple contracts / libraries.\n    pub offset: usize,\n}\n\n/// Computes line offset positions in source content.\nfn compute_line_offsets(content: &str) -> Vec<usize> {\n    let mut offsets = vec![0];\n    offsets.extend(memchr::memchr_iter(b'\\n', content.as_bytes()));\n    offsets\n}\n\n/// Loads sources for a specific ArtifactId.build_id\npub fn load_build_sources(\n    build_id: &str,\n    output: &ProjectCompileOutput,\n    root: &Path,\n) -> Option<Vec<(PathBuf, String)>> {\n    let build_ctx = output.builds().find(|(bid, _)| *bid == build_id).map(|(_, ctx)| ctx)?;\n\n    // Determine the size needed for sources vector\n    // Highest source_id\n    let max_source_id = build_ctx.source_id_to_path.keys().max().map_or(0, |id| *id) as usize;\n\n    // Vec of source path and it's content\n    let mut sources = vec![(PathBuf::new(), String::new()); max_source_id + 1];\n\n    // Populate sources at their correct indices\n    for (source_id, source_path) in &build_ctx.source_id_to_path {\n        let idx = *source_id as usize;\n\n        let full_path =\n            if source_path.is_absolute() { source_path.clone() } else { root.join(source_path) };\n        let mut source_content = foundry_common::fs::read_to_string(&full_path).unwrap_or_default();\n\n        // Normalize line endings for windows\n        if source_content.contains('\\r') {\n            source_content = source_content.replace(\"\\r\\n\", \"\\n\");\n        }\n\n        // Convert path to relative PathBuf\n        let path_buf = source_path.strip_prefix(root).unwrap_or(source_path).to_path_buf();\n\n        sources[idx] = (path_buf, source_content);\n    }\n\n    Some(sources)\n}\n"
  },
  {
    "path": "crates/evm/traces/src/debug/mod.rs",
    "content": "mod sources;\nuse crate::CallTraceNode;\nuse alloy_dyn_abi::{\n    DynSolType, DynSolValue, Specifier,\n    parser::{Parameters, Storage},\n};\nuse alloy_primitives::U256;\nuse foundry_common::fmt::format_token;\nuse foundry_compilers::artifacts::sourcemap::{Jump, SourceElement};\nuse revm::bytecode::opcode::OpCode;\nuse revm_inspectors::tracing::types::{CallTraceStep, DecodedInternalCall, DecodedTraceStep};\npub use sources::{ArtifactData, ContractSources, SourceData};\n\n#[derive(Clone, Debug)]\npub struct DebugTraceIdentifier {\n    /// Source map of contract sources\n    contracts_sources: ContractSources,\n}\n\nimpl DebugTraceIdentifier {\n    pub fn new(contracts_sources: ContractSources) -> Self {\n        Self { contracts_sources }\n    }\n\n    /// Identifies internal function invocations in a given [CallTraceNode].\n    ///\n    /// Accepts the node itself and identified name of the contract which node corresponds to.\n    pub fn identify_node_steps(&self, node: &mut CallTraceNode, contract_name: &str) {\n        DebugStepsWalker::new(node, &self.contracts_sources, contract_name).walk();\n    }\n}\n\n/// Walks through the [CallTraceStep]s attempting to match JUMPs to internal functions.\n///\n/// This is done by looking up jump kinds in the source maps. The structure of internal function\n/// call always looks like this:\n///     - JUMP\n///     - JUMPDEST\n///     ... function steps ...\n///     - JUMP\n///     - JUMPDEST\n///\n/// The assumption we rely on is that first JUMP into function will be marked as [Jump::In] in\n/// source map, and second JUMP out of the function will be marked as [Jump::Out].\n///\n/// Also, we rely on JUMPDEST after first JUMP pointing to the source location of the body of\n/// function which was entered. We pass this source part to [parse_function_from_loc] to extract the\n/// function name.\n///\n/// When we find a [Jump::In] and identify the function name, we push it to the stack.\n///\n/// When we find a [Jump::Out] we try to find a matching [Jump::In] in the stack. A match is found\n/// when source location of the JUMP-in matches the source location of final JUMPDEST (this would be\n/// the location of the function invocation), or when source location of first JUMODEST matches the\n/// source location of the JUMP-out (this would be the location of function body).\n///\n/// When a match is found, all items which were pushed after the matched function are removed. There\n/// is a lot of such items due to source maps getting malformed during optimization.\nstruct DebugStepsWalker<'a> {\n    node: &'a mut CallTraceNode,\n    current_step: usize,\n    stack: Vec<(String, usize)>,\n    sources: &'a ContractSources,\n    contract_name: &'a str,\n}\n\nimpl<'a> DebugStepsWalker<'a> {\n    pub fn new(\n        node: &'a mut CallTraceNode,\n        sources: &'a ContractSources,\n        contract_name: &'a str,\n    ) -> Self {\n        Self { node, current_step: 0, stack: Vec::new(), sources, contract_name }\n    }\n\n    fn current_step(&self) -> &CallTraceStep {\n        &self.node.trace.steps[self.current_step]\n    }\n\n    fn src_map(&self, step: usize) -> Option<(SourceElement, &SourceData)> {\n        self.sources.find_source_mapping(\n            self.contract_name,\n            self.node.trace.steps[step].pc as u32,\n            self.node.trace.kind.is_any_create(),\n        )\n    }\n\n    fn prev_src_map(&self) -> Option<(SourceElement, &SourceData)> {\n        if self.current_step == 0 {\n            return None;\n        }\n\n        self.src_map(self.current_step - 1)\n    }\n\n    fn current_src_map(&self) -> Option<(SourceElement, &SourceData)> {\n        self.src_map(self.current_step)\n    }\n\n    fn is_same_loc(&self, step: usize, other: usize) -> bool {\n        let Some((loc, _)) = self.src_map(step) else {\n            return false;\n        };\n        let Some((other_loc, _)) = self.src_map(other) else {\n            return false;\n        };\n\n        loc.offset() == other_loc.offset()\n            && loc.length() == other_loc.length()\n            && loc.index() == other_loc.index()\n    }\n\n    /// Invoked when current step is a JUMPDEST preceded by a JUMP marked as [Jump::In].\n    fn jump_in(&mut self) {\n        // This usually means that this is a jump into the external function which is an\n        // entrypoint for the current frame. We don't want to include this to avoid\n        // duplicating traces.\n        if self.is_same_loc(self.current_step, self.current_step - 1) {\n            return;\n        }\n\n        let Some((source_element, source)) = self.current_src_map() else {\n            return;\n        };\n\n        if let Some(name) = parse_function_from_loc(source, &source_element) {\n            self.stack.push((name, self.current_step - 1));\n        }\n    }\n\n    /// Invoked when current step is a JUMPDEST preceded by a JUMP marked as [Jump::Out].\n    fn jump_out(&mut self) {\n        let Some((i, _)) = self.stack.iter().enumerate().rfind(|(_, (_, step_idx))| {\n            self.is_same_loc(*step_idx, self.current_step)\n                || self.is_same_loc(step_idx + 1, self.current_step - 1)\n        }) else {\n            return;\n        };\n        // We've found a match, remove all records between start and end, those\n        // are considered invalid.\n        let (func_name, start_idx) = self.stack.split_off(i).swap_remove(0);\n\n        // Try to decode function inputs and outputs from the stack and memory.\n        let (inputs, outputs) = self\n            .src_map(start_idx + 1)\n            .map(|(source_element, source)| {\n                let start = source_element.offset() as usize;\n                let end = start + source_element.length() as usize;\n                let fn_definition = source.source[start..end].replace('\\n', \"\");\n                let (inputs, outputs) = parse_types(&fn_definition);\n\n                (\n                    inputs.and_then(|t| {\n                        try_decode_args_from_step(&t, &self.node.trace.steps[start_idx + 1])\n                    }),\n                    outputs.and_then(|t| try_decode_args_from_step(&t, self.current_step())),\n                )\n            })\n            .unwrap_or_default();\n\n        self.node.trace.steps[start_idx].decoded = Some(Box::new(DecodedTraceStep::InternalCall(\n            DecodedInternalCall { func_name, args: inputs, return_data: outputs },\n            self.current_step,\n        )));\n    }\n\n    fn process(&mut self) {\n        // We are only interested in JUMPs.\n        if self.current_step().op != OpCode::JUMP && self.current_step().op != OpCode::JUMPDEST {\n            return;\n        }\n\n        let Some((prev_source_element, _)) = self.prev_src_map() else {\n            return;\n        };\n\n        match prev_source_element.jump() {\n            Jump::In => self.jump_in(),\n            Jump::Out => self.jump_out(),\n            _ => {}\n        };\n    }\n\n    fn step(&mut self) {\n        self.process();\n        self.current_step += 1;\n    }\n\n    pub fn walk(mut self) {\n        while self.current_step < self.node.trace.steps.len() {\n            self.step();\n        }\n    }\n}\n\n/// Tries to parse the function name from the source code and detect the contract name which\n/// contains the given function.\n///\n/// Returns string in the format `Contract::function`.\nfn parse_function_from_loc(source: &SourceData, loc: &SourceElement) -> Option<String> {\n    let start = loc.offset() as usize;\n    let end = start + loc.length() as usize;\n    let src_len = source.source.len();\n\n    // Handle special case of preprocessed test sources.\n    if start > src_len || end > src_len {\n        return None;\n    }\n\n    let source_part = &source.source[start..end];\n    if !source_part.starts_with(\"function\") {\n        return None;\n    }\n    let function_name = source_part.split_once(\"function\")?.1.split('(').next()?.trim();\n    let contract_name = source.find_contract_name(start, end)?;\n\n    Some(format!(\"{contract_name}::{function_name}\"))\n}\n\n/// Parses function input and output types into [Parameters].\nfn parse_types(source: &str) -> (Option<Parameters<'_>>, Option<Parameters<'_>>) {\n    let inputs = source.find('(').and_then(|params_start| {\n        let params_end = params_start + source[params_start..].find(')')?;\n        Parameters::parse(&source[params_start..params_end + 1]).ok()\n    });\n    let outputs = source.find(\"returns\").and_then(|returns_start| {\n        let return_params_start = returns_start + source[returns_start..].find('(')?;\n        let return_params_end = return_params_start + source[return_params_start..].find(')')?;\n        Parameters::parse(&source[return_params_start..return_params_end + 1]).ok()\n    });\n\n    (inputs, outputs)\n}\n\n/// Given [Parameters] and [CallTraceStep], tries to decode parameters by using stack and memory.\nfn try_decode_args_from_step(args: &Parameters<'_>, step: &CallTraceStep) -> Option<Vec<String>> {\n    let params = &args.params;\n\n    if params.is_empty() {\n        return Some(vec![]);\n    }\n\n    let types = params.iter().map(|p| p.resolve().ok().map(|t| (t, p.storage))).collect::<Vec<_>>();\n\n    let stack = step.stack.as_ref()?;\n\n    if stack.len() < types.len() {\n        return None;\n    }\n\n    let inputs = &stack[stack.len() - types.len()..];\n\n    let decoded = inputs\n        .iter()\n        .zip(types.iter())\n        .map(|(input, type_and_storage)| {\n            type_and_storage\n                .as_ref()\n                .and_then(|(type_, storage)| {\n                    match (type_, storage) {\n                        // HACK: alloy parser treats user-defined types as uint8: https://github.com/alloy-rs/core/pull/386\n                        //\n                        // filter out `uint8` params which are marked as storage or memory as this\n                        // is not possible in Solidity and means that type is user-defined\n                        (DynSolType::Uint(8), Some(Storage::Memory | Storage::Storage)) => None,\n                        (_, Some(Storage::Memory)) => decode_from_memory(\n                            type_,\n                            step.memory.as_ref()?.as_bytes(),\n                            input.try_into().ok()?,\n                        ),\n                        // Read other types from stack\n                        _ => type_.abi_decode(&input.to_be_bytes::<32>()).ok(),\n                    }\n                })\n                .as_ref()\n                .map(format_token)\n                .unwrap_or_else(|| \"<unknown>\".to_string())\n        })\n        .collect();\n\n    Some(decoded)\n}\n\n/// Decodes given [DynSolType] from memory.\nfn decode_from_memory(ty: &DynSolType, memory: &[u8], location: usize) -> Option<DynSolValue> {\n    let first_word = memory.get(location..location + 32)?;\n\n    match ty {\n        // For `string` and `bytes` layout is a word with length followed by the data\n        DynSolType::String | DynSolType::Bytes => {\n            let length: usize = U256::from_be_slice(first_word).try_into().ok()?;\n            let data = memory.get(location + 32..location + 32 + length)?;\n\n            match ty {\n                DynSolType::Bytes => Some(DynSolValue::Bytes(data.to_vec())),\n                DynSolType::String => {\n                    Some(DynSolValue::String(String::from_utf8_lossy(data).to_string()))\n                }\n                _ => unreachable!(),\n            }\n        }\n        // Dynamic arrays are encoded as a word with length followed by words with elements\n        // Fixed arrays are encoded as words with elements\n        DynSolType::Array(inner) | DynSolType::FixedArray(inner, _) => {\n            let (length, start) = match ty {\n                DynSolType::FixedArray(_, length) => (*length, location),\n                DynSolType::Array(_) => {\n                    (U256::from_be_slice(first_word).try_into().ok()?, location + 32)\n                }\n                _ => unreachable!(),\n            };\n            let mut decoded = Vec::with_capacity(length);\n\n            for i in 0..length {\n                let offset = start + i * 32;\n                let location = match inner.as_ref() {\n                    // Arrays of variable length types are arrays of pointers to the values\n                    DynSolType::String | DynSolType::Bytes | DynSolType::Array(_) => {\n                        U256::from_be_slice(memory.get(offset..offset + 32)?).try_into().ok()?\n                    }\n                    _ => offset,\n                };\n\n                decoded.push(decode_from_memory(inner, memory, location)?);\n            }\n\n            Some(DynSolValue::Array(decoded))\n        }\n        _ => ty.abi_decode(first_word).ok(),\n    }\n}\n"
  },
  {
    "path": "crates/evm/traces/src/debug/sources.rs",
    "content": "use eyre::{Context, Result};\nuse foundry_common::{compact_to_contract, strip_bytecode_placeholders};\nuse foundry_compilers::{\n    Artifact, ProjectCompileOutput,\n    artifacts::{\n        Bytecode, ContractBytecodeSome, Libraries, Source,\n        sourcemap::{SourceElement, SourceMap},\n    },\n    multi::MultiCompilerLanguage,\n};\nuse foundry_evm_core::ic::PcIcMap;\nuse foundry_linking::Linker;\nuse rayon::prelude::*;\nuse std::{\n    collections::{BTreeMap, HashMap, HashSet},\n    fmt::Write,\n    ops::Range,\n    path::{Path, PathBuf},\n    sync::Arc,\n};\n\n#[derive(Clone, Debug)]\npub struct SourceData {\n    pub source: Arc<String>,\n    pub language: MultiCompilerLanguage,\n    pub path: PathBuf,\n    /// Maps contract name to (start, end) of the contract definition in the source code.\n    /// This is useful for determining which contract contains given function definition.\n    pub contract_definitions: Vec<(String, Range<usize>)>,\n}\n\nimpl SourceData {\n    pub fn new(\n        output: &ProjectCompileOutput,\n        source: Arc<String>,\n        language: MultiCompilerLanguage,\n        path: PathBuf,\n        root: &Path,\n    ) -> Self {\n        let mut contract_definitions = Vec::new();\n\n        match language {\n            MultiCompilerLanguage::Vyper(_) => {\n                // Vyper contracts have the same name as the file name.\n                if let Some(name) = path.file_stem().map(|s| s.to_string_lossy().to_string()) {\n                    contract_definitions.push((name, 0..source.len()));\n                }\n            }\n            MultiCompilerLanguage::Solc(_) => {\n                let r = output.parser().solc().compiler().enter(|compiler| -> Option<()> {\n                    let (_, source) = compiler.gcx().get_ast_source(root.join(&path))?;\n                    for item in source.ast.as_ref()?.items.iter() {\n                        if let solar::ast::ItemKind::Contract(contract) = &item.kind {\n                            contract_definitions.push((\n                                contract.name.to_string(),\n                                compiler.sess().source_map().span_to_range(item.span).unwrap(),\n                            ));\n                        }\n                    }\n                    Some(())\n                });\n                if r.is_none() {\n                    warn!(\"failed to parse contract definitions for {}\", path.display());\n                }\n            }\n        }\n\n        Self { source, language, path, contract_definitions }\n    }\n\n    /// Finds name of contract that contains given loc.\n    pub fn find_contract_name(&self, start: usize, end: usize) -> Option<&str> {\n        self.contract_definitions\n            .iter()\n            .find(|(_, r)| start >= r.start && end <= r.end)\n            .map(|(name, _)| name.as_str())\n    }\n}\n\n#[derive(Clone, Debug)]\npub struct ArtifactData {\n    pub source_map: Option<SourceMap>,\n    pub source_map_runtime: Option<SourceMap>,\n    pub pc_ic_map: Option<PcIcMap>,\n    pub pc_ic_map_runtime: Option<PcIcMap>,\n    pub build_id: String,\n    pub file_id: u32,\n}\n\nimpl ArtifactData {\n    fn new(bytecode: ContractBytecodeSome, build_id: String, file_id: u32) -> Result<Self> {\n        let parse = |b: &Bytecode, name: &str| {\n            // Only parse source map if it's not empty.\n            let source_map = if b.source_map.as_ref().is_none_or(|s| s.is_empty()) {\n                Ok(None)\n            } else {\n                b.source_map().transpose().wrap_err_with(|| {\n                    format!(\"failed to parse {name} source map of file {file_id} in {build_id}\")\n                })\n            };\n\n            // Only parse bytecode if it's not empty, stripping placeholders if necessary.\n            let pc_ic_map = if let Some(bytes) = strip_bytecode_placeholders(&b.object) {\n                (!bytes.is_empty()).then(|| PcIcMap::new(bytes.as_ref()))\n            } else {\n                None\n            };\n\n            source_map.map(|source_map| (source_map, pc_ic_map))\n        };\n        let (source_map, pc_ic_map) = parse(&bytecode.bytecode, \"creation\")?;\n        let (source_map_runtime, pc_ic_map_runtime) = bytecode\n            .deployed_bytecode\n            .bytecode\n            .map(|b| parse(&b, \"runtime\"))\n            .unwrap_or_else(|| Ok((None, None)))?;\n\n        Ok(Self { source_map, source_map_runtime, pc_ic_map, pc_ic_map_runtime, build_id, file_id })\n    }\n}\n\n/// Container with artifacts data useful for identifying individual execution steps.\n#[derive(Clone, Debug, Default)]\npub struct ContractSources {\n    /// Map over build_id -> file_id -> (source code, language)\n    pub sources_by_id: HashMap<String, HashMap<u32, Arc<SourceData>>>,\n    /// Map over contract name -> Vec<(bytecode, build_id, file_id)>\n    pub artifacts_by_name: HashMap<String, Vec<ArtifactData>>,\n}\n\nimpl ContractSources {\n    /// Collects the contract sources and artifacts from the project compile output.\n    pub fn from_project_output(\n        output: &ProjectCompileOutput,\n        root: &Path,\n        libraries: Option<&Libraries>,\n    ) -> Result<Self> {\n        let mut sources = Self::default();\n        sources.insert(output, root, libraries)?;\n        Ok(sources)\n    }\n\n    pub fn insert(\n        &mut self,\n        output: &ProjectCompileOutput,\n        root: &Path,\n        libraries: Option<&Libraries>,\n    ) -> Result<()> {\n        let link_data = libraries.map(|libraries| {\n            let linker = Linker::new(root, output.artifact_ids().collect());\n            (linker, libraries)\n        });\n\n        let artifacts: Vec<_> = output\n            .artifact_ids()\n            .collect::<Vec<_>>()\n            .par_iter()\n            .map(|(id, artifact)| {\n                let mut new_artifact = None;\n                if let Some(file_id) = artifact.id {\n                    let artifact = if let Some((linker, libraries)) = link_data.as_ref() {\n                        linker.link(id, libraries)?\n                    } else {\n                        artifact.get_contract_bytecode()\n                    };\n                    let bytecode = compact_to_contract(artifact.into_contract_bytecode())?;\n\n                    new_artifact = Some((\n                        id.name.clone(),\n                        ArtifactData::new(bytecode, id.build_id.clone(), file_id)?,\n                    ));\n                } else {\n                    warn!(id = id.identifier(), \"source not found\");\n                };\n\n                Ok(new_artifact)\n            })\n            .collect::<Result<Vec<_>>>()?;\n\n        for (name, artifact) in artifacts.into_iter().flatten() {\n            self.artifacts_by_name.entry(name).or_default().push(artifact);\n        }\n\n        // Not all source files produce artifacts, so we are populating sources by using build\n        // infos.\n        let mut files: BTreeMap<PathBuf, Arc<SourceData>> = BTreeMap::new();\n        let mut removed_files = HashSet::new();\n        for (build_id, build) in output.builds() {\n            for (source_id, path) in &build.source_id_to_path {\n                if !path.exists() {\n                    removed_files.insert(path);\n                    continue;\n                }\n\n                let source_data = match files.entry(path.clone()) {\n                    std::collections::btree_map::Entry::Vacant(entry) => {\n                        let source = Source::read(path).wrap_err_with(|| {\n                            format!(\"failed to read artifact source file for `{}`\", path.display())\n                        })?;\n                        let stripped = path.strip_prefix(root).unwrap_or(path).to_path_buf();\n                        let source_data = Arc::new(SourceData::new(\n                            output,\n                            source.content.clone(),\n                            build.language,\n                            stripped,\n                            root,\n                        ));\n                        entry.insert(source_data.clone());\n                        source_data\n                    }\n                    std::collections::btree_map::Entry::Occupied(entry) => entry.get().clone(),\n                };\n                self.sources_by_id\n                    .entry(build_id.clone())\n                    .or_default()\n                    .insert(*source_id, source_data);\n            }\n        }\n\n        if !removed_files.is_empty() {\n            let mut warning = \"Detected artifacts built from source files that no longer exist. \\\n                Run `forge clean` to make sure builds are in sync with project files.\"\n                .to_string();\n            for file in removed_files {\n                write!(warning, \"\\n - {}\", file.display())?;\n            }\n            let _ = sh_warn!(\"{}\", warning);\n        }\n\n        Ok(())\n    }\n\n    /// Merges given contract sources.\n    pub fn merge(&mut self, sources: Self) {\n        self.sources_by_id.extend(sources.sources_by_id);\n        for (name, artifacts) in sources.artifacts_by_name {\n            self.artifacts_by_name.entry(name).or_default().extend(artifacts);\n        }\n    }\n\n    /// Returns all sources for a contract by name.\n    pub fn get_sources(\n        &self,\n        name: &str,\n    ) -> Option<impl Iterator<Item = (&ArtifactData, &SourceData)>> {\n        self.artifacts_by_name.get(name).map(|artifacts| {\n            artifacts.iter().filter_map(|artifact| {\n                let source =\n                    self.sources_by_id.get(artifact.build_id.as_str())?.get(&artifact.file_id)?;\n                Some((artifact, source.as_ref()))\n            })\n        })\n    }\n\n    /// Returns all (name, bytecode, source) sets.\n    pub fn entries(&self) -> impl Iterator<Item = (&str, &ArtifactData, &SourceData)> {\n        self.artifacts_by_name.iter().flat_map(|(name, artifacts)| {\n            artifacts.iter().filter_map(|artifact| {\n                let source =\n                    self.sources_by_id.get(artifact.build_id.as_str())?.get(&artifact.file_id)?;\n                Some((name.as_str(), artifact, source.as_ref()))\n            })\n        })\n    }\n\n    pub fn find_source_mapping(\n        &self,\n        contract_name: &str,\n        pc: u32,\n        init_code: bool,\n    ) -> Option<(SourceElement, &SourceData)> {\n        self.get_sources(contract_name)?.find_map(|(artifact, source)| {\n            let source_map = if init_code {\n                artifact.source_map.as_ref()\n            } else {\n                artifact.source_map_runtime.as_ref()\n            }?;\n\n            // Solc indexes source maps by instruction counter, but Vyper indexes by program\n            // counter.\n            let source_element = if matches!(source.language, MultiCompilerLanguage::Solc(_)) {\n                let pc_ic_map = if init_code {\n                    artifact.pc_ic_map.as_ref()\n                } else {\n                    artifact.pc_ic_map_runtime.as_ref()\n                }?;\n                let ic = pc_ic_map.get(pc)?;\n\n                source_map.get(ic as usize)\n            } else {\n                source_map.get(pc as usize)\n            }?;\n            // if the source element has an index, find the sourcemap for that index\n            source_element\n                .index()\n                // if index matches current file_id, return current source code\n                .and_then(|index| {\n                    (index == artifact.file_id).then(|| (source_element.clone(), source))\n                })\n                .or_else(|| {\n                    // otherwise find the source code for the element's index\n                    self.sources_by_id\n                        .get(&artifact.build_id)?\n                        .get(&source_element.index()?)\n                        .map(|source| (source_element.clone(), source.as_ref()))\n                })\n        })\n    }\n}\n"
  },
  {
    "path": "crates/evm/traces/src/decoder/mod.rs",
    "content": "use crate::{\n    CallTrace, CallTraceArena, CallTraceNode, DecodedCallData,\n    debug::DebugTraceIdentifier,\n    identifier::{IdentifiedAddress, LocalTraceIdentifier, SignaturesIdentifier, TraceIdentifier},\n};\nuse alloy_dyn_abi::{DecodedEvent, DynSolValue, EventExt, FunctionExt, JsonAbiExt};\nuse alloy_json_abi::{Error, Event, Function, JsonAbi};\nuse alloy_primitives::{\n    Address, B256, LogData, Selector,\n    map::{HashMap, HashSet, hash_map::Entry},\n};\nuse foundry_common::{\n    ContractsByArtifact, SELECTOR_LEN, abi::get_indexed_event, fmt::format_token,\n    get_contract_name, selectors::SelectorKind,\n};\nuse foundry_evm_core::{\n    abi::{Vm, console},\n    constants::{CALLER, CHEATCODE_ADDRESS, DEFAULT_CREATE2_DEPLOYER, HARDHAT_CONSOLE_ADDRESS},\n    decode::RevertDecoder,\n    precompiles::{\n        BLAKE_2F, BLS12_G1ADD, BLS12_G1MSM, BLS12_G2ADD, BLS12_G2MSM, BLS12_MAP_FP_TO_G1,\n        BLS12_MAP_FP2_TO_G2, BLS12_PAIRING_CHECK, EC_ADD, EC_MUL, EC_PAIRING, EC_RECOVER, IDENTITY,\n        MOD_EXP, P256_VERIFY, POINT_EVALUATION, RIPEMD_160, SHA_256,\n    },\n};\nuse itertools::Itertools;\nuse revm_inspectors::tracing::types::{DecodedCallLog, DecodedCallTrace};\nuse std::{collections::BTreeMap, sync::OnceLock};\n\nmod precompiles;\n\n/// Build a new [CallTraceDecoder].\n#[derive(Default)]\n#[must_use = \"builders do nothing unless you call `build` on them\"]\npub struct CallTraceDecoderBuilder {\n    decoder: CallTraceDecoder,\n}\n\nimpl CallTraceDecoderBuilder {\n    /// Create a new builder.\n    #[inline]\n    pub fn new() -> Self {\n        Self { decoder: CallTraceDecoder::new().clone() }\n    }\n\n    /// Add known labels to the decoder.\n    #[inline]\n    pub fn with_labels(mut self, labels: impl IntoIterator<Item = (Address, String)>) -> Self {\n        self.decoder.labels.extend(labels);\n        self\n    }\n\n    /// Add known errors to the decoder.\n    #[inline]\n    pub fn with_abi(mut self, abi: &JsonAbi) -> Self {\n        self.decoder.collect_abi(abi, None);\n        self\n    }\n\n    /// Add known contracts to the decoder.\n    #[inline]\n    pub fn with_known_contracts(mut self, contracts: &ContractsByArtifact) -> Self {\n        trace!(target: \"evm::traces\", len=contracts.len(), \"collecting known contract ABIs\");\n        for contract in contracts.values() {\n            self.decoder.collect_abi(&contract.abi, None);\n        }\n        self\n    }\n\n    /// Add known contracts to the decoder from a `LocalTraceIdentifier`.\n    #[inline]\n    pub fn with_local_identifier_abis(self, identifier: &LocalTraceIdentifier<'_>) -> Self {\n        self.with_known_contracts(identifier.contracts())\n    }\n\n    /// Sets the verbosity level of the decoder.\n    #[inline]\n    pub fn with_verbosity(mut self, level: u8) -> Self {\n        self.decoder.verbosity = level;\n        self\n    }\n\n    /// Sets the signature identifier for events and functions.\n    #[inline]\n    pub fn with_signature_identifier(mut self, identifier: SignaturesIdentifier) -> Self {\n        self.decoder.signature_identifier = Some(identifier);\n        self\n    }\n\n    /// Sets the signature identifier for events and functions.\n    #[inline]\n    pub fn with_label_disabled(mut self, disable_alias: bool) -> Self {\n        self.decoder.disable_labels = disable_alias;\n        self\n    }\n\n    /// Sets the debug identifier for the decoder.\n    #[inline]\n    pub fn with_debug_identifier(mut self, identifier: DebugTraceIdentifier) -> Self {\n        self.decoder.debug_identifier = Some(identifier);\n        self\n    }\n\n    /// Build the decoder.\n    #[inline]\n    pub fn build(self) -> CallTraceDecoder {\n        self.decoder\n    }\n}\n\n/// The call trace decoder.\n///\n/// The decoder collects address labels and ABIs from any number of [TraceIdentifier]s, which it\n/// then uses to decode the call trace.\n///\n/// Note that a call trace decoder is required for each new set of traces, since addresses in\n/// different sets might overlap.\n#[derive(Clone, Debug, Default)]\npub struct CallTraceDecoder {\n    /// Addresses identified to be a specific contract.\n    ///\n    /// The values are in the form `\"<artifact>:<contract>\"`.\n    pub contracts: HashMap<Address, String>,\n    /// Address labels.\n    pub labels: HashMap<Address, String>,\n    /// Contract addresses that have a receive function.\n    pub receive_contracts: HashSet<Address>,\n    /// Contract addresses that have fallback functions, mapped to function selectors of that\n    /// contract.\n    pub fallback_contracts: HashMap<Address, HashSet<Selector>>,\n    /// Contract addresses that have do NOT have fallback functions, mapped to function selectors\n    /// of that contract.\n    pub non_fallback_contracts: HashMap<Address, HashSet<Selector>>,\n\n    /// All known functions.\n    pub functions: HashMap<Selector, Vec<Function>>,\n    /// All known events.\n    ///\n    /// Key is: `(topics[0], topics.len() - 1)`.\n    pub events: BTreeMap<(B256, usize), Vec<Event>>,\n    /// Revert decoder. Contains all known custom errors.\n    pub revert_decoder: RevertDecoder,\n\n    /// A signature identifier for events and functions.\n    pub signature_identifier: Option<SignaturesIdentifier>,\n    /// Verbosity level\n    pub verbosity: u8,\n\n    /// Optional identifier of individual trace steps.\n    pub debug_identifier: Option<DebugTraceIdentifier>,\n\n    /// Disable showing of labels.\n    pub disable_labels: bool,\n}\n\nimpl CallTraceDecoder {\n    /// Creates a new call trace decoder.\n    ///\n    /// The call trace decoder always knows how to decode calls to the cheatcode address, as well\n    /// as DSTest-style logs.\n    pub fn new() -> &'static Self {\n        // If you want to take arguments in this function, assign them to the fields of the cloned\n        // lazy instead of removing it\n        static INIT: OnceLock<CallTraceDecoder> = OnceLock::new();\n        INIT.get_or_init(Self::init)\n    }\n\n    #[instrument(name = \"CallTraceDecoder::init\", level = \"debug\")]\n    fn init() -> Self {\n        Self {\n            contracts: Default::default(),\n            labels: HashMap::from_iter([\n                (CHEATCODE_ADDRESS, \"VM\".to_string()),\n                (HARDHAT_CONSOLE_ADDRESS, \"console\".to_string()),\n                (DEFAULT_CREATE2_DEPLOYER, \"Create2Deployer\".to_string()),\n                (CALLER, \"DefaultSender\".to_string()),\n                (EC_RECOVER, \"ECRecover\".to_string()),\n                (SHA_256, \"SHA-256\".to_string()),\n                (RIPEMD_160, \"RIPEMD-160\".to_string()),\n                (IDENTITY, \"Identity\".to_string()),\n                (MOD_EXP, \"ModExp\".to_string()),\n                (EC_ADD, \"ECAdd\".to_string()),\n                (EC_MUL, \"ECMul\".to_string()),\n                (EC_PAIRING, \"ECPairing\".to_string()),\n                (BLAKE_2F, \"Blake2F\".to_string()),\n                (POINT_EVALUATION, \"PointEvaluation\".to_string()),\n                (BLS12_G1ADD, \"BLS12_G1ADD\".to_string()),\n                (BLS12_G1MSM, \"BLS12_G1MSM\".to_string()),\n                (BLS12_G2ADD, \"BLS12_G2ADD\".to_string()),\n                (BLS12_G2MSM, \"BLS12_G2MSM\".to_string()),\n                (BLS12_PAIRING_CHECK, \"BLS12_PAIRING_CHECK\".to_string()),\n                (BLS12_MAP_FP_TO_G1, \"BLS12_MAP_FP_TO_G1\".to_string()),\n                (BLS12_MAP_FP2_TO_G2, \"BLS12_MAP_FP2_TO_G2\".to_string()),\n                (P256_VERIFY, \"P256VERIFY\".to_string()),\n            ]),\n            receive_contracts: Default::default(),\n            fallback_contracts: Default::default(),\n            non_fallback_contracts: Default::default(),\n\n            functions: console::hh::abi::functions()\n                .into_values()\n                .chain(Vm::abi::functions().into_values())\n                .flatten()\n                .map(|func| (func.selector(), vec![func]))\n                .collect(),\n            events: console::ds::abi::events()\n                .into_values()\n                .flatten()\n                .map(|event| ((event.selector(), indexed_inputs(&event)), vec![event]))\n                .collect(),\n            revert_decoder: Default::default(),\n\n            signature_identifier: None,\n            verbosity: 0,\n\n            debug_identifier: None,\n\n            disable_labels: false,\n        }\n    }\n\n    /// Clears all known addresses.\n    pub fn clear_addresses(&mut self) {\n        self.contracts.clear();\n\n        let default_labels = &Self::new().labels;\n        if self.labels.len() > default_labels.len() {\n            self.labels.clone_from(default_labels);\n        }\n\n        self.receive_contracts.clear();\n        self.fallback_contracts.clear();\n        self.non_fallback_contracts.clear();\n    }\n\n    /// Identify unknown addresses in the specified call trace using the specified identifier.\n    ///\n    /// Unknown contracts are contracts that either lack a label or an ABI.\n    pub fn identify(&mut self, arena: &CallTraceArena, identifier: &mut impl TraceIdentifier) {\n        self.collect_identified_addresses(self.identify_addresses(arena, identifier));\n    }\n\n    /// Identify unknown addresses in the specified call trace using the specified identifier.\n    ///\n    /// Unknown contracts are contracts that either lack a label or an ABI.\n    pub fn identify_addresses<'a>(\n        &self,\n        arena: &CallTraceArena,\n        identifier: &'a mut impl TraceIdentifier,\n    ) -> Vec<IdentifiedAddress<'a>> {\n        let nodes = arena.nodes().iter().filter(|node| {\n            let address = &node.trace.address;\n            !self.labels.contains_key(address) || !self.contracts.contains_key(address)\n        });\n        identifier.identify_addresses(&nodes.collect::<Vec<_>>())\n    }\n\n    /// Adds a single event to the decoder.\n    pub fn push_event(&mut self, event: Event) {\n        self.events.entry((event.selector(), indexed_inputs(&event))).or_default().push(event);\n    }\n\n    /// Adds a single function to the decoder.\n    pub fn push_function(&mut self, function: Function) {\n        match self.functions.entry(function.selector()) {\n            Entry::Occupied(entry) => {\n                // This shouldn't happen that often.\n                if entry.get().contains(&function) {\n                    return;\n                }\n                trace!(target: \"evm::traces\", selector=%entry.key(), new=%function.signature(), \"duplicate function selector\");\n                entry.into_mut().push(function);\n            }\n            Entry::Vacant(entry) => {\n                entry.insert(vec![function]);\n            }\n        }\n    }\n\n    /// Selects the appropriate function from a list of functions with the same selector\n    /// by checking which one belongs to the contract being called, this avoids collisions\n    /// where multiple different functions across different contracts have the same selector.\n    fn select_contract_function<'a>(\n        &self,\n        functions: &'a [Function],\n        trace: &CallTrace,\n    ) -> &'a [Function] {\n        // When there are selector collisions, try to decode the calldata with each function\n        // to determine which one is actually being called. The correct function should\n        // decode successfully while the wrong ones will fail due to parameter type mismatches.\n        if functions.len() > 1 {\n            for (i, func) in functions.iter().enumerate() {\n                if trace.data.len() >= SELECTOR_LEN\n                    && func.abi_decode_input(&trace.data[SELECTOR_LEN..]).is_ok()\n                {\n                    return &functions[i..i + 1];\n                }\n            }\n        }\n        functions\n    }\n\n    /// Adds a single error to the decoder.\n    pub fn push_error(&mut self, error: Error) {\n        self.revert_decoder.push_error(error);\n    }\n\n    pub fn without_label(&mut self, disable: bool) {\n        self.disable_labels = disable;\n    }\n\n    fn collect_identified_addresses(&mut self, mut addrs: Vec<IdentifiedAddress<'_>>) {\n        addrs.sort_by_key(|identity| identity.address);\n        addrs.dedup_by_key(|identity| identity.address);\n        if addrs.is_empty() {\n            return;\n        }\n\n        trace!(target: \"evm::traces\", len=addrs.len(), \"collecting address identities\");\n        for IdentifiedAddress { address, label, contract, abi, artifact_id: _ } in addrs {\n            let _span = trace_span!(target: \"evm::traces\", \"identity\", ?contract, ?label).entered();\n\n            if let Some(contract) = contract {\n                self.contracts.entry(address).or_insert(contract);\n            }\n\n            if let Some(label) = label.filter(|s| !s.is_empty()) {\n                self.labels.entry(address).or_insert(label);\n            }\n\n            if let Some(abi) = abi {\n                self.collect_abi(&abi, Some(address));\n            }\n        }\n    }\n\n    fn collect_abi(&mut self, abi: &JsonAbi, address: Option<Address>) {\n        let len = abi.len();\n        if len == 0 {\n            return;\n        }\n        trace!(target: \"evm::traces\", len, ?address, \"collecting ABI\");\n        for function in abi.functions() {\n            self.push_function(function.clone());\n        }\n        for event in abi.events() {\n            self.push_event(event.clone());\n        }\n        for error in abi.errors() {\n            self.push_error(error.clone());\n        }\n        if let Some(address) = address {\n            if abi.receive.is_some() {\n                self.receive_contracts.insert(address);\n            }\n\n            if abi.fallback.is_some() {\n                self.fallback_contracts\n                    .insert(address, abi.functions().map(|f| f.selector()).collect());\n            } else {\n                self.non_fallback_contracts\n                    .insert(address, abi.functions().map(|f| f.selector()).collect());\n            }\n        }\n    }\n\n    /// Populates the traces with decoded data by mutating the\n    /// [CallTrace] in place. See [CallTraceDecoder::decode_function] and\n    /// [CallTraceDecoder::decode_event] for more details.\n    pub async fn populate_traces(&self, traces: &mut Vec<CallTraceNode>) {\n        for node in traces {\n            node.trace.decoded = Some(Box::new(self.decode_function(&node.trace).await));\n            for log in &mut node.logs {\n                log.decoded = Some(Box::new(self.decode_event(&log.raw_log).await));\n            }\n\n            if let Some(debug) = self.debug_identifier.as_ref()\n                && let Some(identified) = self.contracts.get(&node.trace.address)\n            {\n                debug.identify_node_steps(node, get_contract_name(identified))\n            }\n        }\n    }\n\n    /// Decodes a call trace.\n    pub async fn decode_function(&self, trace: &CallTrace) -> DecodedCallTrace {\n        let label =\n            if self.disable_labels { None } else { self.labels.get(&trace.address).cloned() };\n\n        if trace.kind.is_any_create() {\n            return DecodedCallTrace { label, ..Default::default() };\n        }\n\n        if let Some(trace) = precompiles::decode(trace, 1) {\n            return trace;\n        }\n\n        let cdata = &trace.data;\n        if trace.address == DEFAULT_CREATE2_DEPLOYER {\n            return DecodedCallTrace {\n                label,\n                call_data: Some(DecodedCallData { signature: \"create2\".to_string(), args: vec![] }),\n                return_data: self.default_return_data(trace),\n            };\n        }\n\n        if is_abi_call_data(cdata) {\n            let selector = Selector::try_from(&cdata[..SELECTOR_LEN]).unwrap();\n            let mut functions = Vec::new();\n            let functions = match self.functions.get(&selector) {\n                Some(fs) => fs,\n                None => {\n                    if let Some(identifier) = &self.signature_identifier\n                        && let Some(function) = identifier.identify_function(selector).await\n                    {\n                        functions.push(function);\n                    }\n                    &functions\n                }\n            };\n\n            // Check if unsupported fn selector: calldata dooes NOT point to one of its selectors +\n            // non-fallback contract + no receive\n            if let Some(contract_selectors) = self.non_fallback_contracts.get(&trace.address)\n                && !contract_selectors.contains(&selector)\n                && (!cdata.is_empty() || !self.receive_contracts.contains(&trace.address))\n            {\n                let return_data = if !trace.success {\n                    let revert_msg = self.revert_decoder.decode(&trace.output, trace.status);\n\n                    if trace.output.is_empty() || revert_msg.contains(\"EvmError: Revert\") {\n                        Some(format!(\n                            \"unrecognized function selector {} for contract {}, which has no fallback function.\",\n                            selector, trace.address\n                        ))\n                    } else {\n                        Some(revert_msg)\n                    }\n                } else {\n                    None\n                };\n\n                return if let Some(func) = functions.first() {\n                    DecodedCallTrace {\n                        label,\n                        call_data: Some(self.decode_function_input(trace, func)),\n                        return_data,\n                    }\n                } else {\n                    DecodedCallTrace {\n                        label,\n                        call_data: self.fallback_call_data(trace),\n                        return_data,\n                    }\n                };\n            }\n\n            let contract_functions = self.select_contract_function(functions, trace);\n            let [func, ..] = contract_functions else {\n                return DecodedCallTrace {\n                    label,\n                    call_data: self.fallback_call_data(trace),\n                    return_data: self.default_return_data(trace),\n                };\n            };\n\n            // If traced contract is a fallback contract, check if it has the decoded function.\n            // If not, then replace call data signature with `fallback`.\n            let mut call_data = self.decode_function_input(trace, func);\n            if let Some(fallback_functions) = self.fallback_contracts.get(&trace.address)\n                && !fallback_functions.contains(&selector)\n                && let Some(cd) = self.fallback_call_data(trace)\n            {\n                call_data.signature = cd.signature;\n            }\n\n            DecodedCallTrace {\n                label,\n                call_data: Some(call_data),\n                return_data: self.decode_function_output(trace, contract_functions),\n            }\n        } else {\n            DecodedCallTrace {\n                label,\n                call_data: self.fallback_call_data(trace),\n                return_data: self.default_return_data(trace),\n            }\n        }\n    }\n\n    /// Decodes a function's input into the given trace.\n    fn decode_function_input(&self, trace: &CallTrace, func: &Function) -> DecodedCallData {\n        let mut args = None;\n        if trace.data.len() >= SELECTOR_LEN {\n            if trace.address == CHEATCODE_ADDRESS {\n                // Try to decode cheatcode inputs in a more custom way\n                if let Some(v) = self.decode_cheatcode_inputs(func, &trace.data) {\n                    args = Some(v);\n                }\n            }\n\n            if args.is_none()\n                && let Ok(v) = func.abi_decode_input(&trace.data[SELECTOR_LEN..])\n            {\n                args = Some(v.iter().map(|value| self.format_value(value)).collect());\n            }\n        }\n\n        DecodedCallData { signature: func.signature(), args: args.unwrap_or_default() }\n    }\n\n    /// Custom decoding for cheatcode inputs.\n    fn decode_cheatcode_inputs(&self, func: &Function, data: &[u8]) -> Option<Vec<String>> {\n        match func.name.as_str() {\n            \"expectRevert\" => Some(vec![self.revert_decoder.decode(data, None)]),\n            \"addr\" | \"createWallet\" | \"deriveKey\" | \"rememberKey\" => {\n                // Redact private key in all cases\n                Some(vec![\"<pk>\".to_string()])\n            }\n            \"broadcast\" | \"startBroadcast\" => {\n                // Redact private key if defined\n                // broadcast(uint256) / startBroadcast(uint256)\n                if !func.inputs.is_empty() && func.inputs[0].ty == \"uint256\" {\n                    Some(vec![\"<pk>\".to_string()])\n                } else {\n                    None\n                }\n            }\n            \"getNonce\" => {\n                // Redact private key if defined\n                // getNonce(Wallet)\n                if !func.inputs.is_empty() && func.inputs[0].ty == \"tuple\" {\n                    Some(vec![\"<pk>\".to_string()])\n                } else {\n                    None\n                }\n            }\n            \"sign\" | \"signP256\" => {\n                let mut decoded = func.abi_decode_input(&data[SELECTOR_LEN..]).ok()?;\n\n                // Redact private key and replace in trace\n                // sign(uint256,bytes32) / signP256(uint256,bytes32) / sign(Wallet,bytes32)\n                if !decoded.is_empty() &&\n                    (func.inputs[0].ty == \"uint256\" || func.inputs[0].ty == \"tuple\")\n                {\n                    decoded[0] = DynSolValue::String(\"<pk>\".to_string());\n                }\n\n                Some(decoded.iter().map(format_token).collect())\n            }\n            \"signDelegation\" | \"signAndAttachDelegation\" => {\n                let mut decoded = func.abi_decode_input(&data[SELECTOR_LEN..]).ok()?;\n                // Redact private key and replace in trace for\n                // signAndAttachDelegation(address implementation, uint256 privateKey)\n                // signDelegation(address implementation, uint256 privateKey)\n                decoded[1] = DynSolValue::String(\"<pk>\".to_string());\n                Some(decoded.iter().map(format_token).collect())\n            }\n            \"parseJson\" |\n            \"parseJsonUint\" |\n            \"parseJsonUintArray\" |\n            \"parseJsonInt\" |\n            \"parseJsonIntArray\" |\n            \"parseJsonString\" |\n            \"parseJsonStringArray\" |\n            \"parseJsonAddress\" |\n            \"parseJsonAddressArray\" |\n            \"parseJsonBool\" |\n            \"parseJsonBoolArray\" |\n            \"parseJsonBytes\" |\n            \"parseJsonBytesArray\" |\n            \"parseJsonBytes32\" |\n            \"parseJsonBytes32Array\" |\n            \"writeJson\" |\n            // `keyExists` is being deprecated in favor of `keyExistsJson`. It will be removed in future versions.\n            \"keyExists\" |\n            \"keyExistsJson\" |\n            \"serializeBool\" |\n            \"serializeUint\" |\n            \"serializeUintToHex\" |\n            \"serializeInt\" |\n            \"serializeAddress\" |\n            \"serializeBytes32\" |\n            \"serializeString\" |\n            \"serializeBytes\" => {\n                if self.verbosity >= 5 {\n                    None\n                } else {\n                    let mut decoded = func.abi_decode_input(&data[SELECTOR_LEN..]).ok()?;\n                    let token = if func.name.as_str() == \"parseJson\" ||\n                        // `keyExists` is being deprecated in favor of `keyExistsJson`. It will be removed in future versions.\n                        func.name.as_str() == \"keyExists\" ||\n                        func.name.as_str() == \"keyExistsJson\"\n                    {\n                        \"<JSON file>\"\n                    } else {\n                        \"<stringified JSON>\"\n                    };\n                    decoded[0] = DynSolValue::String(token.to_string());\n                    Some(decoded.iter().map(format_token).collect())\n                }\n            }\n            s if s.contains(\"Toml\") => {\n                if self.verbosity >= 5 {\n                    None\n                } else {\n                    let mut decoded = func.abi_decode_input(&data[SELECTOR_LEN..]).ok()?;\n                    let token = if func.name.as_str() == \"parseToml\" ||\n                        func.name.as_str() == \"keyExistsToml\"\n                    {\n                        \"<TOML file>\"\n                    } else {\n                        \"<stringified TOML>\"\n                    };\n                    decoded[0] = DynSolValue::String(token.to_string());\n                    Some(decoded.iter().map(format_token).collect())\n                }\n            }\n            \"createFork\" |\n            \"createSelectFork\" |\n            \"rpc\" => {\n                let mut decoded = func.abi_decode_input(&data[SELECTOR_LEN..]).ok()?;\n\n                // Redact RPC URL except if referenced by an alias\n                if !decoded.is_empty() && func.inputs[0].ty == \"string\" {\n                    let url_or_alias = decoded[0].as_str().unwrap_or_default();\n\n                    if url_or_alias.starts_with(\"http\") || url_or_alias.starts_with(\"ws\") {\n                        decoded[0] = DynSolValue::String(\"<rpc url>\".to_string());\n                    }\n                } else {\n                    return None;\n                }\n\n                Some(decoded.iter().map(format_token).collect())\n            }\n            _ => None,\n        }\n    }\n\n    /// Decodes a function's output into the given trace.\n    fn decode_function_output(&self, trace: &CallTrace, funcs: &[Function]) -> Option<String> {\n        if !trace.success {\n            return self.default_return_data(trace);\n        }\n\n        if trace.address == CHEATCODE_ADDRESS\n            && let Some(decoded) = funcs.iter().find_map(|func| self.decode_cheatcode_outputs(func))\n        {\n            return Some(decoded);\n        }\n\n        if let Some(values) =\n            funcs.iter().find_map(|func| func.abi_decode_output(&trace.output).ok())\n        {\n            // Functions coming from an external database do not have any outputs specified,\n            // and will lead to returning an empty list of values.\n            if values.is_empty() {\n                return None;\n            }\n\n            return Some(\n                values.iter().map(|value| self.format_value(value)).format(\", \").to_string(),\n            );\n        }\n\n        None\n    }\n\n    /// Custom decoding for cheatcode outputs.\n    fn decode_cheatcode_outputs(&self, func: &Function) -> Option<String> {\n        match func.name.as_str() {\n            s if s.starts_with(\"env\") => Some(\"<env var value>\"),\n            \"createWallet\" | \"deriveKey\" => Some(\"<pk>\"),\n            \"promptSecret\" | \"promptSecretUint\" => Some(\"<secret>\"),\n            \"parseJson\" if self.verbosity < 5 => Some(\"<encoded JSON value>\"),\n            \"readFile\" if self.verbosity < 5 => Some(\"<file>\"),\n            \"rpcUrl\" | \"rpcUrls\" | \"rpcUrlStructs\" => Some(\"<rpc url>\"),\n            _ => None,\n        }\n        .map(Into::into)\n    }\n\n    #[track_caller]\n    fn fallback_call_data(&self, trace: &CallTrace) -> Option<DecodedCallData> {\n        let cdata = &trace.data;\n        let signature = if cdata.is_empty() && self.receive_contracts.contains(&trace.address) {\n            \"receive()\"\n        } else if self.fallback_contracts.contains_key(&trace.address) {\n            \"fallback()\"\n        } else {\n            return None;\n        }\n        .to_string();\n        let args = if cdata.is_empty() { Vec::new() } else { vec![cdata.to_string()] };\n        Some(DecodedCallData { signature, args })\n    }\n\n    /// The default decoded return data for a trace.\n    fn default_return_data(&self, trace: &CallTrace) -> Option<String> {\n        // For calls with status None or successful status, don't decode revert data\n        // This is due to trace.status is derived from the revm_interpreter::InstructionResult in\n        // revm-inspectors status will `None` post revm 27, as `InstructionResult::Continue` does\n        // not exists anymore.\n        if trace.status.is_none() || trace.status.is_some_and(|s| s.is_ok()) {\n            return None;\n        }\n        (!trace.success).then(|| self.revert_decoder.decode(&trace.output, trace.status))\n    }\n\n    /// Decodes an event.\n    pub async fn decode_event(&self, log: &LogData) -> DecodedCallLog {\n        let &[t0, ..] = log.topics() else { return DecodedCallLog { name: None, params: None } };\n\n        let mut events = Vec::new();\n        let events = match self.events.get(&(t0, log.topics().len() - 1)) {\n            Some(es) => es,\n            None => {\n                if let Some(identifier) = &self.signature_identifier\n                    && let Some(event) = identifier.identify_event(t0).await\n                {\n                    events.push(get_indexed_event(event, log));\n                }\n                &events\n            }\n        };\n        for event in events {\n            if let Ok(decoded) = event.decode_log(log) {\n                let params = reconstruct_params(event, &decoded);\n                return DecodedCallLog {\n                    name: Some(event.name.clone()),\n                    params: Some(\n                        params\n                            .into_iter()\n                            .zip(event.inputs.iter())\n                            .map(|(param, input)| {\n                                // undo patched names\n                                let name = input.name.clone();\n                                (name, self.format_value(&param))\n                            })\n                            .collect(),\n                    ),\n                };\n            }\n        }\n\n        DecodedCallLog { name: None, params: None }\n    }\n\n    /// Prefetches function and event signatures into the identifier cache\n    pub async fn prefetch_signatures(&self, nodes: &[CallTraceNode]) {\n        let Some(identifier) = &self.signature_identifier else { return };\n        let events = nodes\n            .iter()\n            .flat_map(|node| {\n                node.logs\n                    .iter()\n                    .map(|log| log.raw_log.topics())\n                    .filter(|&topics| {\n                        if let Some(&first) = topics.first()\n                            && self.events.contains_key(&(first, topics.len() - 1))\n                        {\n                            return false;\n                        }\n                        true\n                    })\n                    .filter_map(|topics| topics.first())\n            })\n            .copied();\n        let functions = nodes\n            .iter()\n            .filter(|&n| {\n                // Ignore known addresses.\n                if n.trace.address == DEFAULT_CREATE2_DEPLOYER\n                    || n.is_precompile()\n                    || precompiles::is_known_precompile(n.trace.address, 1)\n                {\n                    return false;\n                }\n                // Ignore non-ABI calldata.\n                if n.trace.kind.is_any_create() || !is_abi_call_data(&n.trace.data) {\n                    return false;\n                }\n                true\n            })\n            .filter_map(|n| n.trace.data.first_chunk().map(Selector::from))\n            .filter(|selector| !self.functions.contains_key(selector));\n        let selectors = events\n            .map(SelectorKind::Event)\n            .chain(functions.map(SelectorKind::Function))\n            .unique()\n            .collect::<Vec<_>>();\n        let _ = identifier.identify(&selectors).await;\n    }\n\n    /// Pretty-prints a value.\n    fn format_value(&self, value: &DynSolValue) -> String {\n        if let DynSolValue::Address(addr) = value\n            && let Some(label) = self.labels.get(addr)\n        {\n            return format!(\"{label}: [{addr}]\");\n        }\n        format_token(value)\n    }\n}\n\n/// Returns `true` if the given function calldata (including function selector) is ABI-encoded.\n///\n/// This is a simple heuristic to avoid fetching non ABI-encoded selectors.\nfn is_abi_call_data(data: &[u8]) -> bool {\n    match data.len().cmp(&SELECTOR_LEN) {\n        std::cmp::Ordering::Less => false,\n        std::cmp::Ordering::Equal => true,\n        std::cmp::Ordering::Greater => is_abi_data(&data[SELECTOR_LEN..]),\n    }\n}\n\n/// Returns `true` if the given data is ABI-encoded.\n///\n/// See [`is_abi_call_data`] for more details.\nfn is_abi_data(data: &[u8]) -> bool {\n    let rem = data.len() % 32;\n    if rem == 0 || data.is_empty() {\n        return true;\n    }\n    // If the length is not a multiple of 32, also accept when the last remainder bytes are all 0.\n    data[data.len() - rem..].iter().all(|byte| *byte == 0)\n}\n\n/// Restore the order of the params of a decoded event,\n/// as Alloy returns the indexed and unindexed params separately.\nfn reconstruct_params(event: &Event, decoded: &DecodedEvent) -> Vec<DynSolValue> {\n    let mut indexed = 0;\n    let mut unindexed = 0;\n    let mut inputs = vec![];\n    for input in &event.inputs {\n        // Prevent panic of event `Transfer(from, to)` decoded with a signature\n        // `Transfer(address indexed from, address indexed to, uint256 indexed tokenId)` by making\n        // sure the event inputs is not higher than decoded indexed / un-indexed values.\n        if input.indexed && indexed < decoded.indexed.len() {\n            inputs.push(decoded.indexed[indexed].clone());\n            indexed += 1;\n        } else if unindexed < decoded.body.len() {\n            inputs.push(decoded.body[unindexed].clone());\n            unindexed += 1;\n        }\n    }\n\n    inputs\n}\n\nfn indexed_inputs(event: &Event) -> usize {\n    event.inputs.iter().filter(|param| param.indexed).count()\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use alloy_primitives::hex;\n\n    #[test]\n    fn test_selector_collision_resolution() {\n        use alloy_json_abi::Function;\n        use alloy_primitives::Address;\n\n        // Create two functions with the same selector but different signatures\n        let func1 = Function::parse(\"transferFrom(address,address,uint256)\").unwrap();\n        let func2 = Function::parse(\"gasprice_bit_ether(int128)\").unwrap();\n\n        // Verify they have the same selector (this is the collision)\n        assert_eq!(func1.selector(), func2.selector());\n\n        let functions = vec![func1, func2];\n\n        // Create a mock trace with calldata that matches func1\n        let trace = CallTrace {\n            address: Address::from([0x12; 20]),\n            data: hex!(\"23b872dd000000000000000000000000000000000000000000000000000000000000012300000000000000000000000000000000000000000000000000000000000004560000000000000000000000000000000000000000000000000000000000000064\").to_vec().into(),\n            ..Default::default()\n        };\n\n        let decoder = CallTraceDecoder::new();\n        let result = decoder.select_contract_function(&functions, &trace);\n\n        // Should return only the function that can decode the calldata (func1)\n        assert_eq!(result.len(), 1);\n        assert_eq!(result[0].signature(), \"transferFrom(address,address,uint256)\");\n    }\n\n    #[test]\n    fn test_selector_collision_resolution_second_function() {\n        use alloy_json_abi::Function;\n        use alloy_primitives::Address;\n\n        // Create two functions with the same selector but different signatures\n        let func1 = Function::parse(\"transferFrom(address,address,uint256)\").unwrap();\n        let func2 = Function::parse(\"gasprice_bit_ether(int128)\").unwrap();\n\n        let functions = vec![func1, func2];\n\n        // Create a mock trace with calldata that matches func2\n        let trace = CallTrace {\n            address: Address::from([0x12; 20]),\n            data: hex!(\"23b872dd0000000000000000000000000000000000000000000000000000000000000064\")\n                .to_vec()\n                .into(),\n            ..Default::default()\n        };\n\n        let decoder = CallTraceDecoder::new();\n        let result = decoder.select_contract_function(&functions, &trace);\n\n        // Should return only the function that can decode the calldata (func2)\n        assert_eq!(result.len(), 1);\n        assert_eq!(result[0].signature(), \"gasprice_bit_ether(int128)\");\n    }\n\n    #[test]\n    fn test_should_redact() {\n        let decoder = CallTraceDecoder::new();\n\n        // [function_signature, data, expected]\n        let cheatcode_input_test_cases = vec![\n            // Should redact private key from traces in all cases:\n            (\"addr(uint256)\", vec![], Some(vec![\"<pk>\".to_string()])),\n            (\"createWallet(string)\", vec![], Some(vec![\"<pk>\".to_string()])),\n            (\"createWallet(uint256)\", vec![], Some(vec![\"<pk>\".to_string()])),\n            (\"deriveKey(string,uint32)\", vec![], Some(vec![\"<pk>\".to_string()])),\n            (\"deriveKey(string,string,uint32)\", vec![], Some(vec![\"<pk>\".to_string()])),\n            (\"deriveKey(string,uint32,string)\", vec![], Some(vec![\"<pk>\".to_string()])),\n            (\"deriveKey(string,string,uint32,string)\", vec![], Some(vec![\"<pk>\".to_string()])),\n            (\"rememberKey(uint256)\", vec![], Some(vec![\"<pk>\".to_string()])),\n            //\n            // Should redact private key from traces in specific cases with exceptions:\n            (\"broadcast(uint256)\", vec![], Some(vec![\"<pk>\".to_string()])),\n            (\"broadcast()\", vec![], None), // Ignore: `private key` is not passed.\n            (\"startBroadcast(uint256)\", vec![], Some(vec![\"<pk>\".to_string()])),\n            (\"startBroadcast()\", vec![], None), // Ignore: `private key` is not passed.\n            (\"getNonce((address,uint256,uint256,uint256))\", vec![], Some(vec![\"<pk>\".to_string()])),\n            (\"getNonce(address)\", vec![], None), // Ignore: `address` is public.\n            //\n            // Should redact private key and replace in trace in cases:\n            (\n                \"sign(uint256,bytes32)\",\n                hex!(\n                    \"\n                    e341eaa4\n                    7c852118294e51e653712a81e05800f419141751be58f605c371e15141b007a6\n                    0000000000000000000000000000000000000000000000000000000000000000\n                \"\n                )\n                .to_vec(),\n                Some(vec![\n                    \"\\\"<pk>\\\"\".to_string(),\n                    \"0x0000000000000000000000000000000000000000000000000000000000000000\"\n                        .to_string(),\n                ]),\n            ),\n            (\n                \"signP256(uint256,bytes32)\",\n                hex!(\n                    \"\n                    83211b40\n                    7c852118294e51e653712a81e05800f419141751be58f605c371e15141b007a6\n                    0000000000000000000000000000000000000000000000000000000000000000\n                \"\n                )\n                .to_vec(),\n                Some(vec![\n                    \"\\\"<pk>\\\"\".to_string(),\n                    \"0x0000000000000000000000000000000000000000000000000000000000000000\"\n                        .to_string(),\n                ]),\n            ),\n            (\n                // cast calldata \"createFork(string)\" \"https://eth-mainnet.g.alchemy.com/v2/api_key\"\n                \"createFork(string)\",\n                hex!(\n                    \"\n                    31ba3498\n                    0000000000000000000000000000000000000000000000000000000000000020\n                    000000000000000000000000000000000000000000000000000000000000002c\n                    68747470733a2f2f6574682d6d61696e6e65742e672e616c6368656d792e636f\n                    6d2f76322f6170695f6b65790000000000000000000000000000000000000000\n                    \"\n                )\n                .to_vec(),\n                Some(vec![\"\\\"<rpc url>\\\"\".to_string()]),\n            ),\n            (\n                // cast calldata \"createFork(string)\" \"wss://eth-mainnet.g.alchemy.com/v2/api_key\"\n                \"createFork(string)\",\n                hex!(\n                    \"\n                    31ba3498\n                    0000000000000000000000000000000000000000000000000000000000000020\n                    000000000000000000000000000000000000000000000000000000000000002a\n                    7773733a2f2f6574682d6d61696e6e65742e672e616c6368656d792e636f6d2f\n                    76322f6170695f6b657900000000000000000000000000000000000000000000\n                    \"\n                )\n                .to_vec(),\n                Some(vec![\"\\\"<rpc url>\\\"\".to_string()]),\n            ),\n            (\n                // cast calldata \"createFork(string)\" \"mainnet\"\n                \"createFork(string)\",\n                hex!(\n                    \"\n                    31ba3498\n                    0000000000000000000000000000000000000000000000000000000000000020\n                    0000000000000000000000000000000000000000000000000000000000000007\n                    6d61696e6e657400000000000000000000000000000000000000000000000000\n                    \"\n                )\n                .to_vec(),\n                Some(vec![\"\\\"mainnet\\\"\".to_string()]),\n            ),\n            (\n                // cast calldata \"createFork(string,uint256)\" \"https://eth-mainnet.g.alchemy.com/v2/api_key\" 1\n                \"createFork(string,uint256)\",\n                hex!(\n                    \"\n                    6ba3ba2b\n                    0000000000000000000000000000000000000000000000000000000000000040\n                    0000000000000000000000000000000000000000000000000000000000000001\n                    000000000000000000000000000000000000000000000000000000000000002c\n                    68747470733a2f2f6574682d6d61696e6e65742e672e616c6368656d792e636f\n                    6d2f76322f6170695f6b65790000000000000000000000000000000000000000\n                \"\n                )\n                .to_vec(),\n                Some(vec![\"\\\"<rpc url>\\\"\".to_string(), \"1\".to_string()]),\n            ),\n            (\n                // cast calldata \"createFork(string,uint256)\" \"mainnet\" 1\n                \"createFork(string,uint256)\",\n                hex!(\n                    \"\n                    6ba3ba2b\n                    0000000000000000000000000000000000000000000000000000000000000040\n                    0000000000000000000000000000000000000000000000000000000000000001\n                    0000000000000000000000000000000000000000000000000000000000000007\n                    6d61696e6e657400000000000000000000000000000000000000000000000000\n                \"\n                )\n                .to_vec(),\n                Some(vec![\"\\\"mainnet\\\"\".to_string(), \"1\".to_string()]),\n            ),\n            (\n                // cast calldata \"createFork(string,bytes32)\" \"https://eth-mainnet.g.alchemy.com/v2/api_key\" 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\n                \"createFork(string,bytes32)\",\n                hex!(\n                    \"\n                    7ca29682\n                    0000000000000000000000000000000000000000000000000000000000000040\n                    ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\n                    000000000000000000000000000000000000000000000000000000000000002c\n                    68747470733a2f2f6574682d6d61696e6e65742e672e616c6368656d792e636f\n                    6d2f76322f6170695f6b65790000000000000000000000000000000000000000\n                \"\n                )\n                .to_vec(),\n                Some(vec![\n                    \"\\\"<rpc url>\\\"\".to_string(),\n                    \"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\"\n                        .to_string(),\n                ]),\n            ),\n            (\n                // cast calldata \"createFork(string,bytes32)\" \"mainnet\"\n                // 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\n                \"createFork(string,bytes32)\",\n                hex!(\n                    \"\n                    7ca29682\n                    0000000000000000000000000000000000000000000000000000000000000040\n                    ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\n                    0000000000000000000000000000000000000000000000000000000000000007\n                    6d61696e6e657400000000000000000000000000000000000000000000000000\n                \"\n                )\n                .to_vec(),\n                Some(vec![\n                    \"\\\"mainnet\\\"\".to_string(),\n                    \"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\"\n                        .to_string(),\n                ]),\n            ),\n            (\n                // cast calldata \"createSelectFork(string)\" \"https://eth-mainnet.g.alchemy.com/v2/api_key\"\n                \"createSelectFork(string)\",\n                hex!(\n                    \"\n                    98680034\n                    0000000000000000000000000000000000000000000000000000000000000020\n                    000000000000000000000000000000000000000000000000000000000000002c\n                    68747470733a2f2f6574682d6d61696e6e65742e672e616c6368656d792e636f\n                    6d2f76322f6170695f6b65790000000000000000000000000000000000000000\n                    \"\n                )\n                .to_vec(),\n                Some(vec![\"\\\"<rpc url>\\\"\".to_string()]),\n            ),\n            (\n                // cast calldata \"createSelectFork(string)\" \"mainnet\"\n                \"createSelectFork(string)\",\n                hex!(\n                    \"\n                    98680034\n                    0000000000000000000000000000000000000000000000000000000000000020\n                    0000000000000000000000000000000000000000000000000000000000000007\n                    6d61696e6e657400000000000000000000000000000000000000000000000000\n                    \"\n                )\n                .to_vec(),\n                Some(vec![\"\\\"mainnet\\\"\".to_string()]),\n            ),\n            (\n                // cast calldata \"createSelectFork(string,uint256)\" \"https://eth-mainnet.g.alchemy.com/v2/api_key\" 1\n                \"createSelectFork(string,uint256)\",\n                hex!(\n                    \"\n                    71ee464d\n                    0000000000000000000000000000000000000000000000000000000000000040\n                    0000000000000000000000000000000000000000000000000000000000000001\n                    000000000000000000000000000000000000000000000000000000000000002c\n                    68747470733a2f2f6574682d6d61696e6e65742e672e616c6368656d792e636f\n                    6d2f76322f6170695f6b65790000000000000000000000000000000000000000\n                \"\n                )\n                .to_vec(),\n                Some(vec![\"\\\"<rpc url>\\\"\".to_string(), \"1\".to_string()]),\n            ),\n            (\n                // cast calldata \"createSelectFork(string,uint256)\" \"mainnet\" 1\n                \"createSelectFork(string,uint256)\",\n                hex!(\n                    \"\n                    71ee464d\n                    0000000000000000000000000000000000000000000000000000000000000040\n                    0000000000000000000000000000000000000000000000000000000000000001\n                    0000000000000000000000000000000000000000000000000000000000000007\n                    6d61696e6e657400000000000000000000000000000000000000000000000000\n                \"\n                )\n                .to_vec(),\n                Some(vec![\"\\\"mainnet\\\"\".to_string(), \"1\".to_string()]),\n            ),\n            (\n                // cast calldata \"createSelectFork(string,bytes32)\" \"https://eth-mainnet.g.alchemy.com/v2/api_key\" 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\n                \"createSelectFork(string,bytes32)\",\n                hex!(\n                    \"\n                    84d52b7a\n                    0000000000000000000000000000000000000000000000000000000000000040\n                    ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\n                    000000000000000000000000000000000000000000000000000000000000002c\n                    68747470733a2f2f6574682d6d61696e6e65742e672e616c6368656d792e636f\n                    6d2f76322f6170695f6b65790000000000000000000000000000000000000000\n                \"\n                )\n                .to_vec(),\n                Some(vec![\n                    \"\\\"<rpc url>\\\"\".to_string(),\n                    \"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\"\n                        .to_string(),\n                ]),\n            ),\n            (\n                // cast calldata \"createSelectFork(string,bytes32)\" \"mainnet\"\n                // 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\n                \"createSelectFork(string,bytes32)\",\n                hex!(\n                    \"\n                    84d52b7a\n                    0000000000000000000000000000000000000000000000000000000000000040\n                    ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\n                    0000000000000000000000000000000000000000000000000000000000000007\n                    6d61696e6e657400000000000000000000000000000000000000000000000000\n                \"\n                )\n                .to_vec(),\n                Some(vec![\n                    \"\\\"mainnet\\\"\".to_string(),\n                    \"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\"\n                        .to_string(),\n                ]),\n            ),\n            (\n                // cast calldata \"rpc(string,string,string)\" \"https://eth-mainnet.g.alchemy.com/v2/api_key\" \"eth_getBalance\" \"[\\\"0x551e7784778ef8e048e495df49f2614f84a4f1dc\\\",\\\"0x0\\\"]\"\n                \"rpc(string,string,string)\",\n                hex!(\n                    \"\n                    0199a220\n                    0000000000000000000000000000000000000000000000000000000000000060\n                    00000000000000000000000000000000000000000000000000000000000000c0\n                    0000000000000000000000000000000000000000000000000000000000000100\n                    000000000000000000000000000000000000000000000000000000000000002c\n                    68747470733a2f2f6574682d6d61696e6e65742e672e616c6368656d792e636f\n                    6d2f76322f6170695f6b65790000000000000000000000000000000000000000\n                    000000000000000000000000000000000000000000000000000000000000000e\n                    6574685f67657442616c616e6365000000000000000000000000000000000000\n                    0000000000000000000000000000000000000000000000000000000000000034\n                    5b22307835353165373738343737386566386530343865343935646634396632\n                    363134663834613466316463222c22307830225d000000000000000000000000\n                \"\n                )\n                .to_vec(),\n                Some(vec![\n                    \"\\\"<rpc url>\\\"\".to_string(),\n                    \"\\\"eth_getBalance\\\"\".to_string(),\n                    \"\\\"[\\\\\\\"0x551e7784778ef8e048e495df49f2614f84a4f1dc\\\\\\\",\\\\\\\"0x0\\\\\\\"]\\\"\"\n                        .to_string(),\n                ]),\n            ),\n            (\n                // cast calldata \"rpc(string,string,string)\" \"mainnet\" \"eth_getBalance\"\n                // \"[\\\"0x551e7784778ef8e048e495df49f2614f84a4f1dc\\\",\\\"0x0\\\"]\"\n                \"rpc(string,string,string)\",\n                hex!(\n                    \"\n                    0199a220\n                    0000000000000000000000000000000000000000000000000000000000000060\n                    00000000000000000000000000000000000000000000000000000000000000a0\n                    00000000000000000000000000000000000000000000000000000000000000e0\n                    0000000000000000000000000000000000000000000000000000000000000007\n                    6d61696e6e657400000000000000000000000000000000000000000000000000\n                    000000000000000000000000000000000000000000000000000000000000000e\n                    6574685f67657442616c616e6365000000000000000000000000000000000000\n                    0000000000000000000000000000000000000000000000000000000000000034\n                    5b22307835353165373738343737386566386530343865343935646634396632\n                    363134663834613466316463222c22307830225d000000000000000000000000\n                \"\n                )\n                .to_vec(),\n                Some(vec![\n                    \"\\\"mainnet\\\"\".to_string(),\n                    \"\\\"eth_getBalance\\\"\".to_string(),\n                    \"\\\"[\\\\\\\"0x551e7784778ef8e048e495df49f2614f84a4f1dc\\\\\\\",\\\\\\\"0x0\\\\\\\"]\\\"\"\n                        .to_string(),\n                ]),\n            ),\n        ];\n\n        // [function_signature, expected]\n        let cheatcode_output_test_cases = vec![\n            // Should redact private key on output in all cases:\n            (\"createWallet(string)\", Some(\"<pk>\".to_string())),\n            (\"deriveKey(string,uint32)\", Some(\"<pk>\".to_string())),\n            // Should redact RPC URL if defined, except if referenced by an alias:\n            (\"rpcUrl(string)\", Some(\"<rpc url>\".to_string())),\n            (\"rpcUrls()\", Some(\"<rpc url>\".to_string())),\n            (\"rpcUrlStructs()\", Some(\"<rpc url>\".to_string())),\n        ];\n\n        for (function_signature, data, expected) in cheatcode_input_test_cases {\n            let function = Function::parse(function_signature).unwrap();\n            let result = decoder.decode_cheatcode_inputs(&function, &data);\n            assert_eq!(result, expected, \"Input case failed for: {function_signature}\");\n        }\n\n        for (function_signature, expected) in cheatcode_output_test_cases {\n            let function = Function::parse(function_signature).unwrap();\n            let result = Some(decoder.decode_cheatcode_outputs(&function).unwrap_or_default());\n            assert_eq!(result, expected, \"Output case failed for: {function_signature}\");\n        }\n    }\n}\n"
  },
  {
    "path": "crates/evm/traces/src/decoder/precompiles.rs",
    "content": "use crate::{CallTrace, DecodedCallData};\nuse alloy_primitives::{Address, B256, U256, hex};\nuse alloy_sol_types::{SolCall, abi, sol};\nuse foundry_evm_core::precompiles::{\n    BLAKE_2F, BLS12_G1ADD, BLS12_G1MSM, BLS12_G2ADD, BLS12_G2MSM, BLS12_MAP_FP_TO_G1,\n    BLS12_MAP_FP2_TO_G2, BLS12_PAIRING_CHECK, EC_ADD, EC_MUL, EC_PAIRING, EC_RECOVER, IDENTITY,\n    MOD_EXP, P256_VERIFY, POINT_EVALUATION, RIPEMD_160, SHA_256,\n};\nuse itertools::Itertools;\nuse revm_inspectors::tracing::types::DecodedCallTrace;\n\nsol! {\n/// EVM precompiles interface. For illustration purposes only, as precompiles don't follow the\n/// Solidity ABI codec.\n///\n/// Parameter names and types are taken from [evm.codes](https://www.evm.codes/precompiled).\ninterface Precompiles {\n    struct EcPairingInput {\n        uint256 x1;\n        uint256 y1;\n        uint256 x2;\n        uint256 y2;\n        uint256 x3;\n        uint256 y3;\n    }\n\n    /* 0x01 */ function ecrecover(bytes32 hash, uint8 v, uint256 r, uint256 s) returns (address publicAddress);\n    /* 0x02 */ function sha256(bytes data) returns (bytes32 hash);\n    /* 0x03 */ function ripemd(bytes data) returns (bytes20 hash);\n    /* 0x04 */ function identity(bytes data) returns (bytes data);\n    /* 0x05 */ function modexp(uint256 Bsize, uint256 Esize, uint256 Msize, bytes B, bytes E, bytes M) returns (bytes value);\n    /* 0x06 */ function ecadd(uint256 x1, uint256 y1, uint256 x2, uint256 y2) returns (uint256 x, uint256 y);\n    /* 0x07 */ function ecmul(uint256 x1, uint256 y1, uint256 s) returns (uint256 x, uint256 y);\n    /* 0x08 */ function ecpairing(EcPairingInput[] input) returns (bool success);\n    /* 0x09 */ function blake2f(uint32 rounds, uint64[8] h, uint64[16] m, uint64[2] t, bool f) returns (uint64[8] h);\n    /* 0x0a */ function pointEvaluation(bytes32 versionedHash, bytes32 z, bytes32 y, bytes1[48] commitment, bytes1[48] proof) returns (bytes value);\n\n    // Prague BLS12-381 precompiles (EIP-2537)\n    /* 0x0b */ function bls12G1Add(bytes p1, bytes p2) returns (bytes result);\n    /* 0x0c */ function bls12G1Msm(bytes[] scalarsAndPoints) returns (bytes result);\n    /* 0x0d */ function bls12G2Add(bytes p1, bytes p2) returns (bytes result);\n    /* 0x0e */ function bls12G2Msm(bytes[] scalarsAndPoints) returns (bytes result);\n    /* 0x0f */ function bls12PairingCheck(bytes[] pairs) returns (bool success);\n    /* 0x10 */ function bls12MapFpToG1(bytes fp) returns (bytes result);\n    /* 0x11 */ function bls12MapFp2ToG2(bytes fp2) returns (bytes result);\n\n    // Osaka precompiles (EIP-7212)\n    /* 0x100 */ function p256Verify(bytes32 hash, uint256 r, uint256 s, uint256 qx, uint256 qy) returns (bool success);\n}\n}\nuse Precompiles::*;\n\npub(super) fn is_known_precompile(address: Address, _chain_id: u64) -> bool {\n    address[..19].iter().all(|&x| x == 0)\n        && matches!(\n            address,\n            EC_RECOVER\n                | SHA_256\n                | RIPEMD_160\n                | IDENTITY\n                | MOD_EXP\n                | EC_ADD\n                | EC_MUL\n                | EC_PAIRING\n                | BLAKE_2F\n                | POINT_EVALUATION\n                | BLS12_G1ADD\n                | BLS12_G1MSM\n                | BLS12_G2ADD\n                | BLS12_G2MSM\n                | BLS12_PAIRING_CHECK\n                | BLS12_MAP_FP_TO_G1\n                | BLS12_MAP_FP2_TO_G2\n                | P256_VERIFY\n        )\n}\n\n/// Tries to decode a precompile call. Returns `Some` if successful.\npub(super) fn decode(trace: &CallTrace, _chain_id: u64) -> Option<DecodedCallTrace> {\n    if !is_known_precompile(trace.address, _chain_id) {\n        return None;\n    }\n\n    for &precompile in PRECOMPILES {\n        if trace.address == precompile.address() {\n            let signature = precompile.signature(&trace.data);\n\n            let args = precompile\n                .decode_call(&trace.data)\n                .unwrap_or_else(|_| vec![trace.data.to_string()]);\n\n            let return_data = precompile\n                .decode_return(&trace.output)\n                .unwrap_or_else(|_| vec![trace.output.to_string()]);\n            let return_data = if return_data.len() == 1 {\n                return_data.into_iter().next().unwrap()\n            } else {\n                format!(\"({})\", return_data.join(\", \"))\n            };\n\n            return Some(DecodedCallTrace {\n                label: Some(\"PRECOMPILES\".to_string()),\n                call_data: Some(DecodedCallData { signature: signature.to_string(), args }),\n                return_data: Some(return_data),\n            });\n        }\n    }\n\n    None\n}\n\npub(super) trait Precompile {\n    fn address(&self) -> Address;\n    fn signature(&self, data: &[u8]) -> &'static str;\n\n    fn decode_call(&self, data: &[u8]) -> alloy_sol_types::Result<Vec<String>> {\n        Ok(vec![hex::encode_prefixed(data)])\n    }\n\n    fn decode_return(&self, data: &[u8]) -> alloy_sol_types::Result<Vec<String>> {\n        Ok(vec![hex::encode_prefixed(data)])\n    }\n}\n\n// Note: we use the ABI decoder, but this is not necessarily ABI-encoded data. It's just a\n// convenient way to decode the data.\n\nconst PRECOMPILES: &[&dyn Precompile] = &[\n    &Ecrecover,\n    &Sha256,\n    &Ripemd160,\n    &Identity,\n    &ModExp,\n    &EcAdd,\n    &Ecmul,\n    &Ecpairing,\n    &Blake2f,\n    &PointEvaluation,\n    &Bls12G1Add,\n    &Bls12G1Msm,\n    &Bls12G2Add,\n    &Bls12G2Msm,\n    &Bls12PairingCheck,\n    &Bls12MapFpToG1,\n    &Bls12MapFp2ToG2,\n    &P256Verify,\n];\n\nstruct Ecrecover;\nimpl Precompile for Ecrecover {\n    fn address(&self) -> Address {\n        EC_RECOVER\n    }\n\n    fn signature(&self, _: &[u8]) -> &'static str {\n        ecrecoverCall::SIGNATURE\n    }\n\n    fn decode_call(&self, data: &[u8]) -> alloy_sol_types::Result<Vec<String>> {\n        let ecrecoverCall { hash, v, r, s } = ecrecoverCall::abi_decode_raw(data)?;\n        Ok(vec![hash.to_string(), v.to_string(), r.to_string(), s.to_string()])\n    }\n\n    fn decode_return(&self, data: &[u8]) -> alloy_sol_types::Result<Vec<String>> {\n        let ret = ecrecoverCall::abi_decode_returns(data)?;\n        Ok(vec![ret.to_string()])\n    }\n}\n\nstruct Sha256;\nimpl Precompile for Sha256 {\n    fn address(&self) -> Address {\n        SHA_256\n    }\n\n    fn signature(&self, _: &[u8]) -> &'static str {\n        sha256Call::SIGNATURE\n    }\n\n    fn decode_return(&self, data: &[u8]) -> alloy_sol_types::Result<Vec<String>> {\n        let ret = sha256Call::abi_decode_returns(data)?;\n        Ok(vec![ret.to_string()])\n    }\n}\n\nstruct Ripemd160;\nimpl Precompile for Ripemd160 {\n    fn address(&self) -> Address {\n        RIPEMD_160\n    }\n\n    fn signature(&self, _: &[u8]) -> &'static str {\n        ripemdCall::SIGNATURE\n    }\n\n    fn decode_return(&self, data: &[u8]) -> alloy_sol_types::Result<Vec<String>> {\n        let ret = ripemdCall::abi_decode_returns(data)?;\n        Ok(vec![ret.to_string()])\n    }\n}\n\nstruct Identity;\nimpl Precompile for Identity {\n    fn address(&self) -> Address {\n        IDENTITY\n    }\n\n    fn signature(&self, _: &[u8]) -> &'static str {\n        identityCall::SIGNATURE\n    }\n}\n\nstruct ModExp;\nimpl Precompile for ModExp {\n    fn address(&self) -> Address {\n        MOD_EXP\n    }\n\n    fn signature(&self, _: &[u8]) -> &'static str {\n        modexpCall::SIGNATURE\n    }\n\n    fn decode_call(&self, data: &[u8]) -> alloy_sol_types::Result<Vec<String>> {\n        let mut decoder = abi::Decoder::new(data);\n        let b_size = decoder.take_offset()?;\n        let e_size = decoder.take_offset()?;\n        let m_size = decoder.take_offset()?;\n        let b = decoder.take_slice(b_size)?;\n        let e = decoder.take_slice(e_size)?;\n        let m = decoder.take_slice(m_size)?;\n        Ok(vec![\n            b_size.to_string(),\n            e_size.to_string(),\n            m_size.to_string(),\n            hex::encode_prefixed(b),\n            hex::encode_prefixed(e),\n            hex::encode_prefixed(m),\n        ])\n    }\n}\n\nstruct EcAdd;\nimpl Precompile for EcAdd {\n    fn address(&self) -> Address {\n        EC_ADD\n    }\n\n    fn signature(&self, _: &[u8]) -> &'static str {\n        ecaddCall::SIGNATURE\n    }\n\n    fn decode_call(&self, data: &[u8]) -> alloy_sol_types::Result<Vec<String>> {\n        let ecaddCall { x1, y1, x2, y2 } = ecaddCall::abi_decode_raw(data)?;\n        Ok(vec![x1.to_string(), y1.to_string(), x2.to_string(), y2.to_string()])\n    }\n\n    fn decode_return(&self, data: &[u8]) -> alloy_sol_types::Result<Vec<String>> {\n        let ecaddReturn { x, y } = ecaddCall::abi_decode_returns(data)?;\n        Ok(vec![x.to_string(), y.to_string()])\n    }\n}\n\nstruct Ecmul;\nimpl Precompile for Ecmul {\n    fn address(&self) -> Address {\n        EC_MUL\n    }\n\n    fn signature(&self, _: &[u8]) -> &'static str {\n        ecmulCall::SIGNATURE\n    }\n\n    fn decode_call(&self, data: &[u8]) -> alloy_sol_types::Result<Vec<String>> {\n        let ecmulCall { x1, y1, s } = ecmulCall::abi_decode_raw(data)?;\n        Ok(vec![x1.to_string(), y1.to_string(), s.to_string()])\n    }\n\n    fn decode_return(&self, data: &[u8]) -> alloy_sol_types::Result<Vec<String>> {\n        let ecmulReturn { x, y } = ecmulCall::abi_decode_returns(data)?;\n        Ok(vec![x.to_string(), y.to_string()])\n    }\n}\n\nstruct Ecpairing;\nimpl Precompile for Ecpairing {\n    fn address(&self) -> Address {\n        EC_PAIRING\n    }\n\n    fn signature(&self, _: &[u8]) -> &'static str {\n        ecpairingCall::SIGNATURE\n    }\n\n    fn decode_call(&self, data: &[u8]) -> alloy_sol_types::Result<Vec<String>> {\n        let mut decoder = abi::Decoder::new(data);\n        let mut values = Vec::new();\n        // input must be either empty or a multiple of 6 32-byte values\n        let mut tmp = <[&B256; 6]>::default();\n        while !decoder.is_empty() {\n            for tmp in &mut tmp {\n                *tmp = decoder.take_word()?;\n            }\n            values.push(iter_to_string(tmp.iter().map(|x| U256::from_be_bytes(x.0))));\n        }\n        Ok(values)\n    }\n\n    fn decode_return(&self, data: &[u8]) -> alloy_sol_types::Result<Vec<String>> {\n        let ret = ecpairingCall::abi_decode_returns(data)?;\n        Ok(vec![ret.to_string()])\n    }\n}\n\nstruct Blake2f;\nimpl Precompile for Blake2f {\n    fn address(&self) -> Address {\n        BLAKE_2F\n    }\n\n    fn signature(&self, _: &[u8]) -> &'static str {\n        blake2fCall::SIGNATURE\n    }\n\n    fn decode_call(&self, data: &[u8]) -> alloy_sol_types::Result<Vec<String>> {\n        decode_blake2f(data)\n    }\n}\n\nfn decode_blake2f<'a>(data: &'a [u8]) -> alloy_sol_types::Result<Vec<String>> {\n    let mut decoder = abi::Decoder::new(data);\n    let rounds = u32::from_be_bytes(decoder.take_slice(4)?.try_into().unwrap());\n    let u64_le_list =\n        |x: &'a [u8]| x.chunks_exact(8).map(|x| u64::from_le_bytes(x.try_into().unwrap()));\n    let h = u64_le_list(decoder.take_slice(64)?);\n    let m = u64_le_list(decoder.take_slice(128)?);\n    let t = u64_le_list(decoder.take_slice(16)?);\n    let f = decoder.take_slice(1)?[0];\n    Ok(vec![\n        rounds.to_string(),\n        iter_to_string(h),\n        iter_to_string(m),\n        iter_to_string(t),\n        f.to_string(),\n    ])\n}\n\nstruct PointEvaluation;\nimpl Precompile for PointEvaluation {\n    fn address(&self) -> Address {\n        POINT_EVALUATION\n    }\n\n    fn signature(&self, _: &[u8]) -> &'static str {\n        pointEvaluationCall::SIGNATURE\n    }\n\n    fn decode_call(&self, data: &[u8]) -> alloy_sol_types::Result<Vec<String>> {\n        let mut decoder = abi::Decoder::new(data);\n        let versioned_hash = decoder.take_word()?;\n        let z = decoder.take_word()?;\n        let y = decoder.take_word()?;\n        let commitment = decoder.take_slice(48)?;\n        let proof = decoder.take_slice(48)?;\n        Ok(vec![\n            versioned_hash.to_string(),\n            z.to_string(),\n            y.to_string(),\n            hex::encode_prefixed(commitment),\n            hex::encode_prefixed(proof),\n        ])\n    }\n}\n\nfn iter_to_string<I: Iterator<Item = T>, T: std::fmt::Display>(iter: I) -> String {\n    format!(\"[{}]\", iter.format(\", \"))\n}\n\nconst G1_POINT_SIZE: usize = 128;\nconst G2_POINT_SIZE: usize = 256;\nconst SCALAR_SIZE: usize = 32;\nconst FP_SIZE: usize = 64;\n\nstruct Bls12G1Add;\nimpl Precompile for Bls12G1Add {\n    fn address(&self) -> Address {\n        BLS12_G1ADD\n    }\n\n    fn signature(&self, _: &[u8]) -> &'static str {\n        bls12G1AddCall::SIGNATURE\n    }\n\n    fn decode_call(&self, data: &[u8]) -> alloy_sol_types::Result<Vec<String>> {\n        let (p1, rest) = take_at_most(data, G1_POINT_SIZE);\n        let (p2, _) = take_at_most(rest, G1_POINT_SIZE);\n        Ok(vec![hex::encode_prefixed(p1), hex::encode_prefixed(p2)])\n    }\n}\n\nstruct Bls12G1Msm;\nimpl Precompile for Bls12G1Msm {\n    fn address(&self) -> Address {\n        BLS12_G1MSM\n    }\n\n    fn signature(&self, _: &[u8]) -> &'static str {\n        bls12G1MsmCall::SIGNATURE\n    }\n\n    fn decode_call(&self, data: &[u8]) -> alloy_sol_types::Result<Vec<String>> {\n        let pair_size = G1_POINT_SIZE + SCALAR_SIZE;\n        Ok(data.chunks(pair_size).map(hex::encode_prefixed).collect())\n    }\n}\n\nstruct Bls12G2Add;\nimpl Precompile for Bls12G2Add {\n    fn address(&self) -> Address {\n        BLS12_G2ADD\n    }\n\n    fn signature(&self, _: &[u8]) -> &'static str {\n        bls12G2AddCall::SIGNATURE\n    }\n\n    fn decode_call(&self, data: &[u8]) -> alloy_sol_types::Result<Vec<String>> {\n        let (p1, rest) = take_at_most(data, G2_POINT_SIZE);\n        let (p2, _) = take_at_most(rest, G2_POINT_SIZE);\n        Ok(vec![hex::encode_prefixed(p1), hex::encode_prefixed(p2)])\n    }\n}\n\nstruct Bls12G2Msm;\nimpl Precompile for Bls12G2Msm {\n    fn address(&self) -> Address {\n        BLS12_G2MSM\n    }\n\n    fn signature(&self, _: &[u8]) -> &'static str {\n        bls12G2MsmCall::SIGNATURE\n    }\n\n    fn decode_call(&self, data: &[u8]) -> alloy_sol_types::Result<Vec<String>> {\n        let pair_size = G2_POINT_SIZE + SCALAR_SIZE;\n        Ok(data.chunks(pair_size).map(hex::encode_prefixed).collect())\n    }\n}\n\nstruct Bls12PairingCheck;\nimpl Precompile for Bls12PairingCheck {\n    fn address(&self) -> Address {\n        BLS12_PAIRING_CHECK\n    }\n\n    fn signature(&self, _: &[u8]) -> &'static str {\n        bls12PairingCheckCall::SIGNATURE\n    }\n\n    fn decode_call(&self, data: &[u8]) -> alloy_sol_types::Result<Vec<String>> {\n        let pair_size = G1_POINT_SIZE + G2_POINT_SIZE;\n        Ok(data.chunks(pair_size).map(hex::encode_prefixed).collect())\n    }\n\n    fn decode_return(&self, data: &[u8]) -> alloy_sol_types::Result<Vec<String>> {\n        let ret = bls12PairingCheckCall::abi_decode_returns(data)?;\n        Ok(vec![ret.to_string()])\n    }\n}\n\nstruct Bls12MapFpToG1;\nimpl Precompile for Bls12MapFpToG1 {\n    fn address(&self) -> Address {\n        BLS12_MAP_FP_TO_G1\n    }\n\n    fn signature(&self, _: &[u8]) -> &'static str {\n        bls12MapFpToG1Call::SIGNATURE\n    }\n\n    fn decode_call(&self, data: &[u8]) -> alloy_sol_types::Result<Vec<String>> {\n        let (fp, _) = take_at_most(data, FP_SIZE);\n        Ok(vec![hex::encode_prefixed(fp)])\n    }\n}\n\nstruct Bls12MapFp2ToG2;\nimpl Precompile for Bls12MapFp2ToG2 {\n    fn address(&self) -> Address {\n        BLS12_MAP_FP2_TO_G2\n    }\n\n    fn signature(&self, _: &[u8]) -> &'static str {\n        bls12MapFp2ToG2Call::SIGNATURE\n    }\n\n    fn decode_call(&self, data: &[u8]) -> alloy_sol_types::Result<Vec<String>> {\n        let (fp2, _) = take_at_most(data, G1_POINT_SIZE);\n        Ok(vec![hex::encode_prefixed(fp2)])\n    }\n}\n\nstruct P256Verify;\nimpl Precompile for P256Verify {\n    fn address(&self) -> Address {\n        P256_VERIFY\n    }\n\n    fn signature(&self, _: &[u8]) -> &'static str {\n        p256VerifyCall::SIGNATURE\n    }\n\n    fn decode_call(&self, data: &[u8]) -> alloy_sol_types::Result<Vec<String>> {\n        let p256VerifyCall { hash, r, s, qx, qy } = p256VerifyCall::abi_decode_raw(data)?;\n        Ok(vec![hash.to_string(), r.to_string(), s.to_string(), qx.to_string(), qy.to_string()])\n    }\n\n    fn decode_return(&self, data: &[u8]) -> alloy_sol_types::Result<Vec<String>> {\n        let ret = p256VerifyCall::abi_decode_returns(data)?;\n        Ok(vec![ret.to_string()])\n    }\n}\n\nfn take_at_most(data: &[u8], n: usize) -> (&[u8], &[u8]) {\n    let n = n.min(data.len());\n    data.split_at(n)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use alloy_primitives::hex;\n\n    #[test]\n    fn ecpairing() {\n        // https://github.com/foundry-rs/foundry/issues/5337#issuecomment-1627384480\n        let data = hex!(\n            \"\n            26bbb723f965460ca7282cd75f0e3e7c67b15817f7cee60856b394936ed02917\n            0fbe873ac672168143a91535450bab6c412dce8dc8b66a88f2da6e245f9282df\n            13cd4f0451538ece5014fe6688b197aefcc611a5c6a7c319f834f2188ba04b08\n            126ff07e81490a1b6ae92b2d9e700c8e23e9d5c7f6ab857027213819a6c9ae7d\n            04183624c9858a56c54deb237c26cb4355bc2551312004e65fc5b299440b15a3\n            2e4b11aa549ad6c667057b18be4f4437fda92f018a59430ebb992fa3462c9ca1\n            2d4d9aa7e302d9df41749d5507949d05dbea33fbb16c643b22f599a2be6df2e2\n            14bedd503c37ceb061d8ec60209fe345ce89830a19230301f076caff004d1926\n            0967032fcbf776d1afc985f88877f182d38480a653f2decaa9794cbc3bf3060c\n            0e187847ad4c798374d0d6732bf501847dd68bc0e071241e0213bc7fc13db7ab\n            304cfbd1e08a704a99f5e847d93f8c3caafddec46b7a0d379da69a4d112346a7\n            1739c1b1a457a8c7313123d24d2f9192f896b7c63eea05a9d57f06547ad0cec8\n            001d6fedb032f70e377635238e0563f131670001f6abf439adb3a9d5d52073c6\n            1889afe91e4e367f898a7fcd6464e5ca4e822fe169bccb624f6aeb87e4d060bc\n            198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2\n            1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed\n            090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b\n            12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa\n            2dde6d7baf0bfa09329ec8d44c38282f5bf7f9ead1914edd7dcaebb498c84519\n            0c359f868a85c6e6c1ea819cfab4a867501a3688324d74df1fe76556558b1937\n            29f41c6e0e30802e2749bfb0729810876f3423e6f24829ad3e30adb1934f1c8a\n            030e7a5f70bb5daa6e18d80d6d447e772efb0bb7fb9d0ffcd54fc5a48af1286d\n            0ea726b117e48cda8bce2349405f006a84cdd3dcfba12efc990df25970a27b6d\n            30364cd4f8a293b1a04f0153548d3e01baad091c69097ca4e9f26be63e4095b5\n        \"\n        );\n        let decoded = Ecpairing.decode_call(&data).unwrap();\n        // 4 arrays of 6 32-byte values\n        assert_eq!(decoded.len(), 4);\n    }\n}\n"
  },
  {
    "path": "crates/evm/traces/src/folded_stack_trace.rs",
    "content": "use alloy_primitives::hex::ToHexExt;\nuse revm_inspectors::tracing::{\n    CallTraceArena,\n    types::{CallTraceNode, CallTraceStep, DecodedTraceStep, TraceMemberOrder},\n};\n\n/// Builds a folded stack trace from a call trace arena.\npub fn build(arena: &CallTraceArena, isolate: bool) -> Vec<String> {\n    let mut fst = EvmFoldedStackTraceBuilder::new(isolate);\n    fst.process_call_node(arena.nodes(), 0);\n    fst.build()\n}\n\n/// Wrapper for building a folded stack trace using EVM call trace node.\npub struct EvmFoldedStackTraceBuilder {\n    /// Trace produced in isolate mode, meaning refund needs to be reversed at the depth=1\n    /// frame for consistent gas values.\n    isolate: bool,\n    /// Raw folded stack trace builder.\n    fst: FoldedStackTraceBuilder,\n}\n\nimpl EvmFoldedStackTraceBuilder {\n    pub fn new(isolate: bool) -> Self {\n        Self { isolate, fst: FoldedStackTraceBuilder::default() }\n    }\n\n    /// Returns the folded stack trace.\n    pub fn build(self) -> Vec<String> {\n        self.fst.build()\n    }\n\n    /// Creates an entry for a EVM CALL in the folded stack trace. This method recursively processes\n    /// all the children nodes of the call node and at the end it exits.\n    pub fn process_call_node(&mut self, nodes: &[CallTraceNode], idx: usize) {\n        let node = &nodes[idx];\n\n        let func_name = if node.trace.kind.is_any_create() {\n            let contract_name = node\n                .trace\n                .decoded\n                .as_ref()\n                .and_then(|dc| dc.label.as_deref())\n                .unwrap_or(\"Contract\");\n            format!(\"new {contract_name}\")\n        } else {\n            let selector = node\n                .selector()\n                .map(|selector| selector.encode_hex_with_prefix())\n                .unwrap_or_else(|| \"fallback\".to_string());\n            let signature = node\n                .trace\n                .decoded\n                .as_ref()\n                .and_then(|dc| dc.call_data.as_ref())\n                .map(|dc| &dc.signature)\n                .unwrap_or(&selector);\n\n            if let Some(label) = node.trace.decoded.as_ref().and_then(|dc| dc.label.as_ref()) {\n                format!(\"{label}.{signature}\")\n            } else {\n                signature.clone()\n            }\n        };\n\n        let mut gas_used = node.trace.gas_used;\n        let max_refund_adjust_depth = if self.isolate { 1 } else { 0 };\n        if node.trace.depth <= max_refund_adjust_depth {\n            gas_used += node.trace.gas_refund_counter;\n        }\n\n        self.fst.enter(func_name, gas_used);\n\n        // Track internal function step exits to do in this call context.\n        let mut step_exits = vec![];\n\n        // Process children nodes.\n        for order in &node.ordering {\n            match order {\n                TraceMemberOrder::Call(child_idx) => {\n                    let child_node_idx = node.children[*child_idx];\n                    self.process_call_node(nodes, child_node_idx);\n                }\n                TraceMemberOrder::Step(step_idx) => {\n                    self.exit_previous_steps(&mut step_exits, *step_idx);\n                    self.process_step(&node.trace.steps, *step_idx, &mut step_exits)\n                }\n                TraceMemberOrder::Log(_) => {}\n            }\n        }\n\n        // Exit pending internal function calls if any.\n        for _ in 0..step_exits.len() {\n            self.fst.exit();\n        }\n\n        // Exit from this call context in the folded stack trace.\n        self.fst.exit();\n    }\n\n    /// Creates an entry for an internal function call in the folded stack trace. This method only\n    /// enters the function in the folded stack trace, we cannot exit since we need to exit at a\n    /// future step. Hence, we keep track of the step end index in the `step_exits`.\n    fn process_step(\n        &mut self,\n        steps: &[CallTraceStep],\n        step_idx: usize,\n        step_exits: &mut Vec<usize>,\n    ) {\n        let step = &steps[step_idx];\n        if let Some(decoded_step) = &step.decoded {\n            match decoded_step.as_ref() {\n                DecodedTraceStep::InternalCall(decoded_internal_call, step_end_idx) => {\n                    let gas_used = step.gas_remaining - steps[*step_end_idx].gas_remaining;\n                    self.fst.enter(decoded_internal_call.func_name.clone(), gas_used);\n                    step_exits.push(*step_end_idx);\n                }\n                DecodedTraceStep::Line(_) => {}\n            }\n        }\n    }\n\n    /// Exits all the previous internal calls that should end before starting step_idx.\n    fn exit_previous_steps(&mut self, step_exits: &mut Vec<usize>, step_idx: usize) {\n        let initial_length = step_exits.len();\n        step_exits.retain(|&number| number > step_idx);\n\n        let num_exits = initial_length - step_exits.len();\n        for _ in 0..num_exits {\n            self.fst.exit();\n        }\n    }\n}\n\n/// Helps to translate a function enter-exit flow into a folded stack trace.\n///\n/// Example:\n/// ```solidity\n/// function top() { child_a(); child_b() } // consumes 500 gas\n/// function child_a() {} // consumes 100 gas\n/// function child_b() {} // consumes 200 gas\n/// ```\n///\n/// For execution of the `top` function looks like:\n/// 1. enter `top`\n/// 2. enter `child_a`\n/// 3. exit `child_a`\n/// 4. enter `child_b`\n/// 5. exit `child_b`\n/// 6. exit `top`\n///\n/// The translated folded stack trace lines look like:\n/// 1. top\n/// 2. top;child_a\n/// 3. top;child_b\n///\n/// Including the gas consumed by the function by itself.\n/// 1. top 200 // 500 - 100 - 200\n/// 2. top;child_a 100\n/// 3. top;child_b 200\n#[derive(Debug, Default)]\npub struct FoldedStackTraceBuilder {\n    /// Trace entries.\n    traces: Vec<TraceEntry>,\n    /// Number of exits to be done before entering a new function.\n    exits: usize,\n}\n\n#[derive(Debug, Default)]\nstruct TraceEntry {\n    /// Names of all functions in the call stack of this trace.\n    names: Vec<String>,\n    /// Gas consumed by this function, not including refunds.\n    gas: u64,\n}\n\nimpl FoldedStackTraceBuilder {\n    /// Enter execution of a function call that consumes `gas`.\n    pub fn enter(&mut self, label: String, gas: u64) {\n        let mut names = self.traces.last().map(|entry| entry.names.clone()).unwrap_or_default();\n\n        while self.exits > 0 {\n            names.pop();\n            self.exits -= 1;\n        }\n\n        names.push(label);\n        self.traces.push(TraceEntry { names, gas });\n    }\n\n    /// Exit execution of a function call.\n    pub fn exit(&mut self) {\n        self.exits += 1;\n    }\n\n    /// Returns folded stack trace.\n    pub fn build(mut self) -> Vec<String> {\n        self.subtract_children();\n        self.build_without_subtraction()\n    }\n\n    /// Internal method to build the folded stack trace without subtracting gas consumed by\n    /// the children function calls.\n    pub fn build_without_subtraction(&mut self) -> Vec<String> {\n        let mut lines = Vec::new();\n        for TraceEntry { names, gas } in &self.traces {\n            lines.push(format!(\"{} {}\", names.join(\";\"), gas));\n        }\n        lines\n    }\n\n    /// Subtracts gas consumed by the children function calls from the parent function calls.\n    fn subtract_children(&mut self) {\n        // Iterate over each trace to find the children and subtract their values from the parents.\n        for i in 0..self.traces.len() {\n            let (left, right) = self.traces.split_at_mut(i);\n            let TraceEntry { names, gas } = &right[0];\n            if names.len() > 1 {\n                let parent_trace_to_match = &names[..names.len() - 1];\n                for parent in left.iter_mut().rev() {\n                    if parent.names == parent_trace_to_match {\n                        parent.gas -= gas;\n                        break;\n                    }\n                }\n            }\n        }\n    }\n}\n\nmod tests {\n    #[test]\n    fn test_fst_1() {\n        let mut trace = super::FoldedStackTraceBuilder::default();\n        trace.enter(\"top\".to_string(), 500);\n        trace.enter(\"child_a\".to_string(), 100);\n        trace.exit();\n        trace.enter(\"child_b\".to_string(), 200);\n\n        assert_eq!(\n            trace.build_without_subtraction(),\n            vec![\n                \"top 500\", //\n                \"top;child_a 100\",\n                \"top;child_b 200\",\n            ]\n        );\n        assert_eq!(\n            trace.build(),\n            vec![\n                \"top 200\", // 500 - 100 - 200\n                \"top;child_a 100\",\n                \"top;child_b 200\",\n            ]\n        );\n    }\n\n    #[test]\n    fn test_fst_2() {\n        let mut trace = super::FoldedStackTraceBuilder::default();\n        trace.enter(\"top\".to_string(), 500);\n        trace.enter(\"child_a\".to_string(), 300);\n        trace.enter(\"child_b\".to_string(), 100);\n        trace.exit();\n        trace.exit();\n        trace.enter(\"child_c\".to_string(), 100);\n\n        assert_eq!(\n            trace.build_without_subtraction(),\n            vec![\n                \"top 500\", //\n                \"top;child_a 300\",\n                \"top;child_a;child_b 100\",\n                \"top;child_c 100\",\n            ]\n        );\n\n        assert_eq!(\n            trace.build(),\n            vec![\n                \"top 100\",         // 500 - 300 - 100\n                \"top;child_a 200\", // 300 - 100\n                \"top;child_a;child_b 100\",\n                \"top;child_c 100\",\n            ]\n        );\n    }\n\n    #[test]\n    fn test_fst_3() {\n        let mut trace = super::FoldedStackTraceBuilder::default();\n        trace.enter(\"top\".to_string(), 1700);\n        trace.enter(\"child_a\".to_string(), 500);\n        trace.exit();\n        trace.enter(\"child_b\".to_string(), 500);\n        trace.enter(\"child_c\".to_string(), 500);\n        trace.exit();\n        trace.exit();\n        trace.exit();\n        trace.enter(\"top2\".to_string(), 1700);\n\n        assert_eq!(\n            trace.build_without_subtraction(),\n            vec![\n                \"top 1700\", //\n                \"top;child_a 500\",\n                \"top;child_b 500\",\n                \"top;child_b;child_c 500\",\n                \"top2 1700\",\n            ]\n        );\n\n        assert_eq!(\n            trace.build(),\n            vec![\n                \"top 700\", //\n                \"top;child_a 500\",\n                \"top;child_b 0\",\n                \"top;child_b;child_c 500\",\n                \"top2 1700\",\n            ]\n        );\n    }\n}\n"
  },
  {
    "path": "crates/evm/traces/src/identifier/external.rs",
    "content": "use super::{IdentifiedAddress, TraceIdentifier};\nuse crate::debug::ContractSources;\nuse alloy_primitives::{\n    Address,\n    map::{Entry, HashMap, HashSet},\n};\nuse eyre::WrapErr;\nuse foundry_block_explorers::{contract::Metadata, errors::EtherscanError};\nuse foundry_common::compile::etherscan_project;\nuse foundry_config::{Chain, Config};\nuse futures::{\n    future::join_all,\n    stream::{FuturesUnordered, Stream, StreamExt},\n    task::{Context, Poll},\n};\nuse revm_inspectors::tracing::types::CallTraceNode;\nuse serde::Deserialize;\nuse std::{\n    borrow::Cow,\n    pin::Pin,\n    sync::{\n        Arc,\n        atomic::{AtomicBool, Ordering},\n    },\n};\nuse tokio::time::{Duration, Interval};\n\n/// A trace identifier that tries to identify addresses using Etherscan.\npub struct ExternalIdentifier {\n    fetchers: Vec<Arc<dyn ExternalFetcherT>>,\n    /// Cached contracts.\n    contracts: HashMap<Address, (FetcherKind, Option<Metadata>)>,\n}\n\nimpl ExternalIdentifier {\n    /// Creates a new external identifier with the given client\n    pub fn new(config: &Config, mut chain: Option<Chain>) -> eyre::Result<Option<Self>> {\n        if config.offline {\n            return Ok(None);\n        }\n\n        let config = match config.get_etherscan_config_with_chain(chain) {\n            Ok(Some(config)) => {\n                chain = config.chain;\n                Some(config)\n            }\n            Ok(None) => {\n                warn!(target: \"evm::traces::external\", \"etherscan config not found\");\n                None\n            }\n            Err(err) => {\n                warn!(target: \"evm::traces::external\", ?err, \"failed to get etherscan config\");\n                None\n            }\n        };\n\n        let mut fetchers = Vec::<Arc<dyn ExternalFetcherT>>::new();\n        if let Some(chain) = chain {\n            debug!(target: \"evm::traces::external\", ?chain, \"using sourcify identifier\");\n            fetchers.push(Arc::new(SourcifyFetcher::new(chain)));\n        }\n        if let Some(config) = config {\n            debug!(target: \"evm::traces::external\", chain=?config.chain, url=?config.api_url, \"using etherscan identifier\");\n            match config.into_client() {\n                Ok(client) => {\n                    fetchers.push(Arc::new(EtherscanFetcher::new(client)));\n                }\n                Err(err) => {\n                    warn!(target: \"evm::traces::external\", ?err, \"failed to create etherscan client\");\n                }\n            }\n        }\n        if fetchers.is_empty() {\n            debug!(target: \"evm::traces::external\", \"no fetchers enabled\");\n            return Ok(None);\n        }\n\n        Ok(Some(Self { fetchers, contracts: Default::default() }))\n    }\n\n    /// Goes over the list of contracts we have pulled from the traces, clones their source from\n    /// Etherscan and compiles them locally, for usage in the debugger.\n    pub async fn get_compiled_contracts(&self) -> eyre::Result<ContractSources> {\n        // Collect contract info upfront so we can reference it in error messages\n        let contracts_info: Vec<_> = self\n            .contracts\n            .iter()\n            // filter out vyper files and contracts without metadata\n            .filter_map(|(addr, (_, metadata))| {\n                if let Some(metadata) = metadata.as_ref()\n                    && !metadata.is_vyper()\n                {\n                    Some((*addr, metadata))\n                } else {\n                    None\n                }\n            })\n            .collect();\n\n        let outputs_fut = contracts_info\n            .iter()\n            .map(|(addr, metadata)| async move {\n                sh_println!(\"Compiling: {} {addr}\", metadata.contract_name)?;\n                let root = tempfile::tempdir()?;\n                let root_path = root.path();\n                let project = etherscan_project(metadata, root_path)?;\n                let output = project.compile()?;\n                if output.has_compiler_errors() {\n                    eyre::bail!(\"{output}\")\n                }\n\n                Ok((project, output, root))\n            })\n            .collect::<Vec<_>>();\n\n        // poll all the futures concurrently\n        let outputs = join_all(outputs_fut).await;\n\n        let mut sources: ContractSources = Default::default();\n\n        // construct the map\n        for (idx, res) in outputs.into_iter().enumerate() {\n            let (addr, metadata) = &contracts_info[idx];\n            let name = &metadata.contract_name;\n            let (project, output, _) =\n                res.wrap_err_with(|| format!(\"Failed to compile contract {name} at {addr}\"))?;\n            sources\n                .insert(&output, project.root(), None)\n                .wrap_err_with(|| format!(\"Failed to insert contract {name} at {addr}\"))?;\n        }\n\n        Ok(sources)\n    }\n\n    fn identify_from_metadata(\n        &self,\n        address: Address,\n        metadata: &Metadata,\n    ) -> IdentifiedAddress<'static> {\n        let label = metadata.contract_name.clone();\n        let abi = metadata.abi().ok().map(Cow::Owned);\n        IdentifiedAddress {\n            address,\n            label: Some(label.clone()),\n            contract: Some(label),\n            abi,\n            artifact_id: None,\n        }\n    }\n}\n\nimpl TraceIdentifier for ExternalIdentifier {\n    fn identify_addresses(&mut self, nodes: &[&CallTraceNode]) -> Vec<IdentifiedAddress<'_>> {\n        if nodes.is_empty() {\n            return Vec::new();\n        }\n\n        trace!(target: \"evm::traces::external\", \"identify {} addresses\", nodes.len());\n\n        let mut identities = Vec::new();\n        let mut to_fetch = HashSet::new();\n\n        // Check cache first.\n        for &node in nodes {\n            let address = node.trace.address;\n            if let Some((_, metadata)) = self.contracts.get(&address) {\n                if let Some(metadata) = metadata {\n                    identities.push(self.identify_from_metadata(address, metadata));\n                } else {\n                    // Do nothing. We know that this contract was not verified.\n                }\n            } else {\n                to_fetch.insert(address);\n            }\n        }\n\n        if to_fetch.is_empty() {\n            return identities;\n        }\n        trace!(target: \"evm::traces::external\", \"fetching {} addresses\", to_fetch.len());\n\n        let to_fetch = to_fetch.into_iter().collect::<Vec<_>>();\n        let fetchers =\n            self.fetchers.iter().map(|fetcher| ExternalFetcher::new(fetcher.clone(), &to_fetch));\n        let fetched_identities = foundry_common::block_on(\n            futures::stream::select_all(fetchers)\n                .filter_map(|(address, value)| {\n                    let addr = value\n                        .1\n                        .as_ref()\n                        .map(|metadata| self.identify_from_metadata(address, metadata));\n                    match self.contracts.entry(address) {\n                        Entry::Occupied(mut occupied_entry) => {\n                            // Override if:\n                            // - new is from Etherscan and old is not\n                            // - new is Some and old is None, meaning verified only in one source\n                            if !matches!(occupied_entry.get().0, FetcherKind::Etherscan)\n                                || value.1.is_none()\n                            {\n                                occupied_entry.insert(value);\n                            }\n                        }\n                        Entry::Vacant(vacant_entry) => {\n                            vacant_entry.insert(value);\n                        }\n                    }\n                    async move { addr }\n                })\n                .collect::<Vec<IdentifiedAddress<'_>>>(),\n        );\n        trace!(target: \"evm::traces::external\", \"fetched {} addresses: {fetched_identities:#?}\", fetched_identities.len());\n\n        identities.extend(fetched_identities);\n        identities\n    }\n}\n\ntype FetchFuture =\n    Pin<Box<dyn Future<Output = (Address, Result<Option<Metadata>, EtherscanError>)>>>;\n\n/// A rate limit aware fetcher.\n///\n/// Fetches information about multiple addresses concurrently, while respecting rate limits.\nstruct ExternalFetcher {\n    /// The fetcher\n    fetcher: Arc<dyn ExternalFetcherT>,\n    /// The time we wait if we hit the rate limit\n    timeout: Duration,\n    /// The interval we are currently waiting for before making a new request\n    backoff: Option<Interval>,\n    /// The maximum amount of requests to send concurrently\n    concurrency: usize,\n    /// The addresses we have yet to make requests for\n    queue: Vec<Address>,\n    /// The in progress requests\n    in_progress: FuturesUnordered<FetchFuture>,\n}\n\nimpl ExternalFetcher {\n    fn new(fetcher: Arc<dyn ExternalFetcherT>, to_fetch: &[Address]) -> Self {\n        Self {\n            timeout: fetcher.timeout(),\n            backoff: None,\n            concurrency: fetcher.concurrency(),\n            fetcher,\n            queue: to_fetch.to_vec(),\n            in_progress: FuturesUnordered::new(),\n        }\n    }\n\n    fn queue_next_reqs(&mut self) {\n        while self.in_progress.len() < self.concurrency {\n            let Some(addr) = self.queue.pop() else { break };\n            let fetcher = Arc::clone(&self.fetcher);\n            self.in_progress.push(Box::pin(async move {\n                trace!(target: \"evm::traces::external\", ?addr, \"fetching info\");\n                let res = fetcher.fetch(addr).await;\n                (addr, res)\n            }));\n        }\n    }\n}\n\nimpl Stream for ExternalFetcher {\n    type Item = (Address, (FetcherKind, Option<Metadata>));\n\n    fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {\n        let pin = self.get_mut();\n\n        let _guard =\n            info_span!(\"evm::traces::external\", kind=?pin.fetcher.kind(), \"ExternalFetcher\")\n                .entered();\n\n        if pin.fetcher.invalid_api_key().load(Ordering::Relaxed) {\n            return Poll::Ready(None);\n        }\n\n        loop {\n            if let Some(mut backoff) = pin.backoff.take()\n                && backoff.poll_tick(cx).is_pending()\n            {\n                pin.backoff = Some(backoff);\n                return Poll::Pending;\n            }\n\n            pin.queue_next_reqs();\n\n            let mut made_progress_this_iter = false;\n            match pin.in_progress.poll_next_unpin(cx) {\n                Poll::Pending => {}\n                Poll::Ready(None) => return Poll::Ready(None),\n                Poll::Ready(Some((addr, res))) => {\n                    made_progress_this_iter = true;\n                    match res {\n                        Ok(metadata) => {\n                            return Poll::Ready(Some((addr, (pin.fetcher.kind(), metadata))));\n                        }\n                        Err(EtherscanError::ContractCodeNotVerified(_)) => {\n                            return Poll::Ready(Some((addr, (pin.fetcher.kind(), None))));\n                        }\n                        Err(EtherscanError::RateLimitExceeded) => {\n                            warn!(target: \"evm::traces::external\", \"rate limit exceeded on attempt\");\n                            pin.backoff = Some(tokio::time::interval(pin.timeout));\n                            pin.queue.push(addr);\n                        }\n                        Err(EtherscanError::InvalidApiKey) => {\n                            warn!(target: \"evm::traces::external\", \"invalid api key\");\n                            // mark key as invalid\n                            pin.fetcher.invalid_api_key().store(true, Ordering::Relaxed);\n                            return Poll::Ready(None);\n                        }\n                        Err(EtherscanError::BlockedByCloudflare) => {\n                            warn!(target: \"evm::traces::external\", \"blocked by cloudflare\");\n                            // mark key as invalid\n                            pin.fetcher.invalid_api_key().store(true, Ordering::Relaxed);\n                            return Poll::Ready(None);\n                        }\n                        Err(err) => {\n                            warn!(target: \"evm::traces::external\", ?err, \"could not get info\");\n                        }\n                    }\n                }\n            }\n\n            if !made_progress_this_iter {\n                return Poll::Pending;\n            }\n        }\n    }\n}\n\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\nenum FetcherKind {\n    Etherscan,\n    Sourcify,\n}\n\n#[async_trait::async_trait]\ntrait ExternalFetcherT: Send + Sync {\n    fn kind(&self) -> FetcherKind;\n    fn timeout(&self) -> Duration;\n    fn concurrency(&self) -> usize;\n    fn invalid_api_key(&self) -> &AtomicBool;\n    async fn fetch(&self, address: Address) -> Result<Option<Metadata>, EtherscanError>;\n}\n\nstruct EtherscanFetcher {\n    client: foundry_block_explorers::Client,\n    invalid_api_key: AtomicBool,\n}\n\nimpl EtherscanFetcher {\n    fn new(client: foundry_block_explorers::Client) -> Self {\n        Self { client, invalid_api_key: AtomicBool::new(false) }\n    }\n}\n\n#[async_trait::async_trait]\nimpl ExternalFetcherT for EtherscanFetcher {\n    fn kind(&self) -> FetcherKind {\n        FetcherKind::Etherscan\n    }\n\n    fn timeout(&self) -> Duration {\n        Duration::from_secs(1)\n    }\n\n    fn concurrency(&self) -> usize {\n        5\n    }\n\n    fn invalid_api_key(&self) -> &AtomicBool {\n        &self.invalid_api_key\n    }\n\n    async fn fetch(&self, address: Address) -> Result<Option<Metadata>, EtherscanError> {\n        self.client.contract_source_code(address).await.map(|mut metadata| metadata.items.pop())\n    }\n}\n\nstruct SourcifyFetcher {\n    client: reqwest::Client,\n    url: String,\n    invalid_api_key: AtomicBool,\n}\n\nimpl SourcifyFetcher {\n    fn new(chain: Chain) -> Self {\n        Self {\n            client: reqwest::Client::new(),\n            url: format!(\"https://sourcify.dev/server/v2/contract/{}\", chain.id()),\n            invalid_api_key: AtomicBool::new(false),\n        }\n    }\n}\n\n#[async_trait::async_trait]\nimpl ExternalFetcherT for SourcifyFetcher {\n    fn kind(&self) -> FetcherKind {\n        FetcherKind::Sourcify\n    }\n\n    fn timeout(&self) -> Duration {\n        Duration::from_secs(1)\n    }\n\n    fn concurrency(&self) -> usize {\n        5\n    }\n\n    fn invalid_api_key(&self) -> &AtomicBool {\n        &self.invalid_api_key\n    }\n\n    async fn fetch(&self, address: Address) -> Result<Option<Metadata>, EtherscanError> {\n        let url = format!(\"{url}/{address}?fields=abi,compilation\", url = self.url);\n        let response = self\n            .client\n            .get(url)\n            .send()\n            .await\n            .map_err(|e| EtherscanError::Unknown(e.to_string()))?;\n        let code = response.status();\n        match code.as_u16() {\n            // Not verified.\n            404 => return Err(EtherscanError::ContractCodeNotVerified(address)),\n            // Too many requests.\n            429 => return Err(EtherscanError::RateLimitExceeded),\n            _ => {}\n        }\n        let response: SourcifyResponse =\n            response.json().await.map_err(|e| EtherscanError::Unknown(e.to_string()))?;\n        trace!(target: \"evm::traces::external\", \"Sourcify response for {address}: {response:#?}\");\n        match response {\n            SourcifyResponse::Success(metadata) => Ok(Some(metadata.into())),\n            SourcifyResponse::Error(error) => Err(EtherscanError::Unknown(format!(\"{error:#?}\"))),\n        }\n    }\n}\n\n/// Sourcify API response for `/v2/contract/{chainId}/{address}`.\n#[derive(Debug, Clone, Deserialize)]\n#[serde(untagged)]\nenum SourcifyResponse {\n    Success(SourcifyMetadata),\n    Error(SourcifyError),\n}\n\n#[derive(Debug, Clone, Deserialize)]\n#[serde(rename_all = \"camelCase\")]\n#[expect(dead_code)] // Used in Debug.\nstruct SourcifyError {\n    custom_code: String,\n    message: String,\n    error_id: String,\n}\n\n#[derive(Debug, Clone, Deserialize)]\n#[serde(rename_all = \"camelCase\")]\nstruct SourcifyMetadata {\n    #[serde(default)]\n    abi: Option<Box<serde_json::value::RawValue>>,\n    #[serde(default)]\n    compilation: Option<Compilation>,\n}\n\n#[derive(Debug, Clone, Deserialize)]\n#[serde(rename_all = \"camelCase\")]\nstruct Compilation {\n    #[serde(default)]\n    compiler_version: String,\n    #[serde(default)]\n    name: String,\n}\n\nimpl From<SourcifyMetadata> for Metadata {\n    fn from(metadata: SourcifyMetadata) -> Self {\n        let SourcifyMetadata { abi, compilation } = metadata;\n        let (contract_name, compiler_version) = compilation\n            .map(|c| (c.name, c.compiler_version))\n            .unwrap_or_else(|| (String::new(), String::new()));\n        // Defaulted fields may be fetched from sourcify but we don't make use of them.\n        Self {\n            source_code: foundry_block_explorers::contract::SourceCodeMetadata::Sources(\n                Default::default(),\n            ),\n            abi: Box::<str>::from(abi.unwrap_or_default()).into(),\n            contract_name,\n            compiler_version,\n            optimization_used: 0,\n            runs: 0,\n            constructor_arguments: Default::default(),\n            evm_version: String::new(),\n            library: String::new(),\n            license_type: String::new(),\n            proxy: 0,\n            implementation: None,\n            swarm_source: String::new(),\n        }\n    }\n}\n"
  },
  {
    "path": "crates/evm/traces/src/identifier/local.rs",
    "content": "use super::{IdentifiedAddress, TraceIdentifier};\nuse alloy_dyn_abi::JsonAbiExt;\nuse alloy_json_abi::JsonAbi;\nuse alloy_primitives::{Address, Bytes, map::HashMap};\nuse foundry_common::contracts::{ContractsByArtifact, bytecode_diff_score};\nuse foundry_compilers::ArtifactId;\nuse revm_inspectors::tracing::types::CallTraceNode;\nuse std::borrow::Cow;\n\n/// A trace identifier that tries to identify addresses using local contracts.\npub struct LocalTraceIdentifier<'a> {\n    /// Known contracts to search through.\n    known_contracts: &'a ContractsByArtifact,\n    /// Vector of pairs of artifact ID and the runtime code length of the given artifact.\n    ordered_ids: Vec<(&'a ArtifactId, usize)>,\n    /// The contracts bytecode.\n    contracts_bytecode: Option<&'a HashMap<Address, Bytes>>,\n}\n\nimpl<'a> LocalTraceIdentifier<'a> {\n    /// Creates a new local trace identifier.\n    pub fn new(known_contracts: &'a ContractsByArtifact) -> Self {\n        let mut ordered_ids = known_contracts\n            .iter()\n            .filter_map(|(id, contract)| Some((id, contract.deployed_bytecode()?)))\n            .map(|(id, bytecode)| (id, bytecode.len()))\n            .collect::<Vec<_>>();\n        ordered_ids.sort_by_key(|(_, len)| *len);\n        Self { known_contracts, ordered_ids, contracts_bytecode: None }\n    }\n\n    pub fn with_bytecodes(mut self, contracts_bytecode: &'a HashMap<Address, Bytes>) -> Self {\n        self.contracts_bytecode = Some(contracts_bytecode);\n        self\n    }\n\n    /// Returns the known contracts.\n    #[inline]\n    pub fn contracts(&self) -> &'a ContractsByArtifact {\n        self.known_contracts\n    }\n\n    /// Identifies the artifact based on score computed for both creation and deployed bytecodes.\n    pub fn identify_code(\n        &self,\n        runtime_code: &[u8],\n        creation_code: &[u8],\n    ) -> Option<(&'a ArtifactId, &'a JsonAbi)> {\n        let len = runtime_code.len();\n\n        let mut min_score = f64::MAX;\n        let mut min_score_id = None;\n\n        let mut check = |id, is_creation, min_score: &mut f64| {\n            let contract = self.known_contracts.get(id)?;\n            // Select bytecodes to compare based on `is_creation` flag.\n            let (contract_bytecode, current_bytecode) = if is_creation {\n                (contract.bytecode_without_placeholders(), creation_code)\n            } else {\n                (contract.deployed_bytecode_without_placeholders(), runtime_code)\n            };\n\n            if let Some(bytecode) = contract_bytecode {\n                let mut current_bytecode = current_bytecode;\n                if is_creation && current_bytecode.len() > bytecode.len() {\n                    // Try to decode ctor args with contract abi.\n                    if let Some(constructor) = contract.abi.constructor() {\n                        let constructor_args = &current_bytecode[bytecode.len()..];\n                        if constructor.abi_decode_input(constructor_args).is_ok() {\n                            // If we can decode args with current abi then remove args from\n                            // code to compare.\n                            current_bytecode = &current_bytecode[..bytecode.len()]\n                        }\n                    }\n                }\n\n                let score = bytecode_diff_score(&bytecode, current_bytecode);\n                if score == 0.0 {\n                    trace!(target: \"evm::traces::local\", \"found exact match\");\n                    return Some((id, &contract.abi));\n                }\n                if score < *min_score {\n                    *min_score = score;\n                    min_score_id = Some((id, &contract.abi));\n                }\n            }\n            None\n        };\n\n        // Check `[len * 0.9, ..., len * 1.1]`.\n        let max_len = (len * 11) / 10;\n\n        // Start at artifacts with the same code length: `len..len*1.1`.\n        let same_length_idx = self.find_index(len);\n        for idx in same_length_idx..self.ordered_ids.len() {\n            let (id, len) = self.ordered_ids[idx];\n            if len > max_len {\n                break;\n            }\n            if let found @ Some(_) = check(id, true, &mut min_score) {\n                return found;\n            }\n        }\n\n        // Iterate over the remaining artifacts with less code length: `len*0.9..len`.\n        let min_len = (len * 9) / 10;\n        let idx = self.find_index(min_len);\n        for i in idx..same_length_idx {\n            let (id, _) = self.ordered_ids[i];\n            if let found @ Some(_) = check(id, true, &mut min_score) {\n                return found;\n            }\n        }\n\n        // Fallback to comparing deployed code if min score greater than threshold.\n        if min_score >= 0.85 {\n            for (artifact, _) in &self.ordered_ids {\n                if let found @ Some(_) = check(artifact, false, &mut min_score) {\n                    return found;\n                }\n            }\n        }\n\n        trace!(target: \"evm::traces::local\", %min_score, \"no exact match found\");\n\n        // Note: the diff score can be inaccurate for small contracts so we're using a relatively\n        // high threshold here to avoid filtering out too many contracts.\n        if min_score < 0.85 { min_score_id } else { None }\n    }\n\n    /// Returns the index of the artifact with the given code length, or the index of the first\n    /// artifact with a greater code length if the exact code length is not found.\n    fn find_index(&self, len: usize) -> usize {\n        let (Ok(mut idx) | Err(mut idx)) =\n            self.ordered_ids.binary_search_by_key(&len, |(_, probe)| *probe);\n\n        // In case of multiple artifacts with the same code length, we need to find the first one.\n        while idx > 0 && self.ordered_ids[idx - 1].1 == len {\n            idx -= 1;\n        }\n\n        idx\n    }\n}\n\nimpl TraceIdentifier for LocalTraceIdentifier<'_> {\n    fn identify_addresses(&mut self, nodes: &[&CallTraceNode]) -> Vec<IdentifiedAddress<'_>> {\n        if nodes.is_empty() {\n            return Vec::new();\n        }\n\n        trace!(target: \"evm::traces::local\", \"identify {} addresses\", nodes.len());\n\n        nodes\n            .iter()\n            .map(|&node| {\n                (\n                    node.trace.address,\n                    node.trace.kind.is_any_create().then_some(&node.trace.output[..]),\n                    node.trace.kind.is_any_create().then_some(&node.trace.data[..]),\n                )\n            })\n            .filter_map(|(address, runtime_code, creation_code)| {\n                let _span =\n                    trace_span!(target: \"evm::traces::local\", \"identify\", %address).entered();\n\n                // In order to identify the addresses, we need at least the runtime code. It can be\n                // obtained from the trace itself (if it's a CREATE* call), or from the fetched\n                // bytecodes.\n                let (runtime_code, creation_code) = match (runtime_code, creation_code) {\n                    (Some(runtime_code), Some(creation_code)) => (runtime_code, creation_code),\n                    (Some(runtime_code), _) => (runtime_code, &[] as &[u8]),\n                    _ => {\n                        let code = self.contracts_bytecode?.get(&address)?;\n                        (code.as_ref(), &[] as &[u8])\n                    }\n                };\n                let (id, abi) = self.identify_code(runtime_code, creation_code)?;\n                trace!(target: \"evm::traces::local\", id=%id.identifier(), \"identified\");\n\n                Some(IdentifiedAddress {\n                    address,\n                    contract: Some(id.identifier()),\n                    label: Some(id.name.clone()),\n                    abi: Some(Cow::Borrowed(abi)),\n                    artifact_id: Some(id.clone()),\n                })\n            })\n            .collect()\n    }\n}\n"
  },
  {
    "path": "crates/evm/traces/src/identifier/mod.rs",
    "content": "use alloy_json_abi::JsonAbi;\nuse alloy_primitives::{Address, Bytes, map::HashMap};\nuse foundry_common::ContractsByArtifact;\nuse foundry_compilers::ArtifactId;\nuse foundry_config::{Chain, Config};\nuse revm_inspectors::tracing::types::CallTraceNode;\nuse std::borrow::Cow;\n\nmod local;\npub use local::LocalTraceIdentifier;\n\nmod external;\npub use external::ExternalIdentifier;\n\nmod signatures;\npub use signatures::{SignaturesCache, SignaturesIdentifier};\n\n/// An address identified by a [`TraceIdentifier`].\n#[derive(Debug)]\npub struct IdentifiedAddress<'a> {\n    /// The address.\n    pub address: Address,\n    /// The label for the address.\n    pub label: Option<String>,\n    /// The contract this address represents.\n    ///\n    /// Note: This may be in the format `\"<artifact>:<contract>\"`.\n    pub contract: Option<String>,\n    /// The ABI of the contract at this address.\n    pub abi: Option<Cow<'a, JsonAbi>>,\n    /// The artifact ID of the contract, if any.\n    pub artifact_id: Option<ArtifactId>,\n}\n\n/// Trace identifiers figure out what ABIs and labels belong to all the addresses of the trace.\npub trait TraceIdentifier {\n    /// Attempts to identify an address in one or more call traces.\n    fn identify_addresses(&mut self, nodes: &[&CallTraceNode]) -> Vec<IdentifiedAddress<'_>>;\n}\n\n/// A collection of trace identifiers.\npub struct TraceIdentifiers<'a> {\n    /// The local trace identifier.\n    pub local: Option<LocalTraceIdentifier<'a>>,\n    /// The optional external trace identifier.\n    pub external: Option<ExternalIdentifier>,\n}\n\nimpl Default for TraceIdentifiers<'_> {\n    fn default() -> Self {\n        Self::new()\n    }\n}\n\nimpl TraceIdentifier for TraceIdentifiers<'_> {\n    fn identify_addresses(&mut self, nodes: &[&CallTraceNode]) -> Vec<IdentifiedAddress<'_>> {\n        if nodes.is_empty() {\n            return Vec::new();\n        }\n\n        let mut identities = Vec::with_capacity(nodes.len());\n        if let Some(local) = &mut self.local {\n            identities.extend(local.identify_addresses(nodes));\n            if identities.len() >= nodes.len() {\n                return identities;\n            }\n        }\n        if let Some(external) = &mut self.external {\n            identities.extend(external.identify_addresses(nodes));\n        }\n        identities\n    }\n}\n\nimpl<'a> TraceIdentifiers<'a> {\n    /// Creates a new, empty instance.\n    pub const fn new() -> Self {\n        Self { local: None, external: None }\n    }\n\n    /// Sets the local identifier.\n    pub fn with_local(mut self, known_contracts: &'a ContractsByArtifact) -> Self {\n        self.local = Some(LocalTraceIdentifier::new(known_contracts));\n        self\n    }\n\n    /// Sets the local identifier.\n    pub fn with_local_and_bytecodes(\n        mut self,\n        known_contracts: &'a ContractsByArtifact,\n        contracts_bytecode: &'a HashMap<Address, Bytes>,\n    ) -> Self {\n        self.local =\n            Some(LocalTraceIdentifier::new(known_contracts).with_bytecodes(contracts_bytecode));\n        self\n    }\n\n    /// Sets the external identifier.\n    pub fn with_external(mut self, config: &Config, chain: Option<Chain>) -> eyre::Result<Self> {\n        self.external = ExternalIdentifier::new(config, chain)?;\n        Ok(self)\n    }\n\n    /// Returns `true` if there are no set identifiers.\n    pub fn is_empty(&self) -> bool {\n        self.local.is_none() && self.external.is_none()\n    }\n}\n"
  },
  {
    "path": "crates/evm/traces/src/identifier/signatures.rs",
    "content": "use alloy_json_abi::{Error, Event, Function, JsonAbi};\nuse alloy_primitives::{B256, Selector, map::HashMap};\nuse eyre::Result;\nuse foundry_common::{\n    abi::{get_error, get_event, get_func},\n    fs,\n    selectors::{OpenChainClient, SelectorKind},\n};\nuse foundry_config::Config;\nuse serde::{Deserialize, Serialize};\nuse std::{\n    collections::BTreeMap,\n    path::{Path, PathBuf},\n    sync::Arc,\n};\nuse tokio::sync::RwLock;\n\n/// Cache for function, event and error signatures. Used by [`SignaturesIdentifier`].\n#[derive(Debug, Default, Deserialize)]\n#[serde(try_from = \"SignaturesDiskCache\")]\npub struct SignaturesCache {\n    signatures: HashMap<SelectorKind, Option<String>>,\n}\n\n/// Disk representation of the signatures cache.\n#[derive(Serialize, Deserialize)]\nstruct SignaturesDiskCache {\n    functions: BTreeMap<Selector, String>,\n    errors: BTreeMap<Selector, String>,\n    events: BTreeMap<B256, String>,\n}\n\nimpl From<SignaturesDiskCache> for SignaturesCache {\n    fn from(value: SignaturesDiskCache) -> Self {\n        let functions = value\n            .functions\n            .into_iter()\n            .map(|(selector, signature)| (SelectorKind::Function(selector), signature));\n        let errors = value\n            .errors\n            .into_iter()\n            .map(|(selector, signature)| (SelectorKind::Error(selector), signature));\n        let events = value\n            .events\n            .into_iter()\n            .map(|(selector, signature)| (SelectorKind::Event(selector), signature));\n        Self {\n            signatures: functions\n                .chain(errors)\n                .chain(events)\n                .map(|(sel, sig)| (sel, (!sig.is_empty()).then_some(sig)))\n                .collect(),\n        }\n    }\n}\n\nimpl From<&SignaturesCache> for SignaturesDiskCache {\n    fn from(value: &SignaturesCache) -> Self {\n        let (functions, errors, events) = value.signatures.iter().fold(\n            (BTreeMap::new(), BTreeMap::new(), BTreeMap::new()),\n            |mut acc, (kind, signature)| {\n                let value = signature.clone().unwrap_or_default();\n                match *kind {\n                    SelectorKind::Function(selector) => _ = acc.0.insert(selector, value),\n                    SelectorKind::Error(selector) => _ = acc.1.insert(selector, value),\n                    SelectorKind::Event(selector) => _ = acc.2.insert(selector, value),\n                }\n                acc\n            },\n        );\n        Self { functions, errors, events }\n    }\n}\n\nimpl Serialize for SignaturesCache {\n    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>\n    where\n        S: serde::Serializer,\n    {\n        SignaturesDiskCache::from(self).serialize(serializer)\n    }\n}\n\nimpl SignaturesCache {\n    /// Loads the cache from a file.\n    #[instrument(target = \"evm::traces\", name = \"SignaturesCache::load\")]\n    pub fn load(path: &Path) -> Self {\n        trace!(target: \"evm::traces\", ?path, \"reading signature cache\");\n        fs::read_json_file(path)\n            .inspect_err(\n                |err| warn!(target: \"evm::traces\", ?path, ?err, \"failed to read cache file\"),\n            )\n            .unwrap_or_default()\n    }\n\n    /// Saves the cache to a file.\n    #[instrument(target = \"evm::traces\", name = \"SignaturesCache::save\", skip(self))]\n    pub fn save(&self, path: &Path) {\n        if let Some(parent) = path.parent()\n            && let Err(err) = std::fs::create_dir_all(parent)\n        {\n            warn!(target: \"evm::traces\", ?parent, %err, \"failed to create cache\");\n        }\n        if let Err(err) = fs::write_json_file(path, self) {\n            warn!(target: \"evm::traces\", %err, \"failed to flush signature cache\");\n        } else {\n            trace!(target: \"evm::traces\", \"flushed signature cache\")\n        }\n    }\n\n    /// Updates the cache from an ABI.\n    pub fn extend_from_abi(&mut self, abi: &JsonAbi) {\n        self.extend(abi.items().filter_map(|item| match item {\n            alloy_json_abi::AbiItem::Function(f) => {\n                Some((SelectorKind::Function(f.selector()), f.signature()))\n            }\n            alloy_json_abi::AbiItem::Error(e) => {\n                Some((SelectorKind::Error(e.selector()), e.signature()))\n            }\n            alloy_json_abi::AbiItem::Event(e) => {\n                Some((SelectorKind::Event(e.selector()), e.full_signature()))\n            }\n            _ => None,\n        }));\n    }\n\n    /// Inserts a single signature into the cache.\n    pub fn insert(&mut self, key: SelectorKind, value: String) {\n        self.extend(std::iter::once((key, value)));\n    }\n\n    /// Extends the cache with multiple signatures.\n    pub fn extend(&mut self, signatures: impl IntoIterator<Item = (SelectorKind, String)>) {\n        self.signatures\n            .extend(signatures.into_iter().map(|(k, v)| (k, (!v.is_empty()).then_some(v))));\n    }\n\n    /// Gets a signature from the cache.\n    pub fn get(&self, key: &SelectorKind) -> Option<Option<String>> {\n        self.signatures.get(key).cloned()\n    }\n\n    /// Returns true if the cache contains a signature.\n    pub fn contains_key(&self, key: &SelectorKind) -> bool {\n        self.signatures.contains_key(key)\n    }\n}\n\n/// An identifier that tries to identify functions and events using signatures found at\n/// `https://openchain.xyz` or a local cache.\n#[derive(Clone, Debug)]\npub struct SignaturesIdentifier(Arc<SignaturesIdentifierInner>);\n\n#[derive(Debug)]\nstruct SignaturesIdentifierInner {\n    /// Cached selectors for functions, events and custom errors.\n    cache: RwLock<SignaturesCache>,\n    /// Location where to save the signature cache.\n    cache_path: Option<PathBuf>,\n    /// The OpenChain client to fetch signatures from. `None` if disabled on construction.\n    client: Option<OpenChainClient>,\n}\n\nimpl SignaturesIdentifier {\n    /// Creates a new `SignaturesIdentifier` with the default cache directory.\n    pub fn new(offline: bool) -> Result<Self> {\n        Self::new_with(Config::foundry_cache_dir().as_deref(), offline)\n    }\n\n    /// Creates a new `SignaturesIdentifier` from the global configuration.\n    pub fn from_config(config: &Config) -> Result<Self> {\n        Self::new(config.offline)\n    }\n\n    /// Creates a new `SignaturesIdentifier`.\n    ///\n    /// - `cache_dir` is the cache directory to store the signatures.\n    /// - `offline` disables the OpenChain client.\n    pub fn new_with(cache_dir: Option<&Path>, offline: bool) -> Result<Self> {\n        let client = if !offline { Some(OpenChainClient::new()?) } else { None };\n        let (cache, cache_path) = if let Some(cache_dir) = cache_dir {\n            let path = cache_dir.join(\"signatures\");\n            let cache = SignaturesCache::load(&path);\n            (cache, Some(path))\n        } else {\n            Default::default()\n        };\n        Ok(Self(Arc::new(SignaturesIdentifierInner {\n            cache: RwLock::new(cache),\n            cache_path,\n            client,\n        })))\n    }\n\n    /// Saves the cache to the file system.\n    pub fn save(&self) {\n        self.0.save();\n    }\n\n    /// Identifies `Function`s.\n    pub async fn identify_functions(\n        &self,\n        identifiers: impl IntoIterator<Item = Selector>,\n    ) -> Vec<Option<Function>> {\n        self.identify_map(identifiers.into_iter().map(SelectorKind::Function), get_func).await\n    }\n\n    /// Identifies a `Function`.\n    pub async fn identify_function(&self, identifier: Selector) -> Option<Function> {\n        self.identify_functions([identifier]).await.pop().unwrap()\n    }\n\n    /// Identifies `Event`s.\n    pub async fn identify_events(\n        &self,\n        identifiers: impl IntoIterator<Item = B256>,\n    ) -> Vec<Option<Event>> {\n        self.identify_map(identifiers.into_iter().map(SelectorKind::Event), get_event).await\n    }\n\n    /// Identifies an `Event`.\n    pub async fn identify_event(&self, identifier: B256) -> Option<Event> {\n        self.identify_events([identifier]).await.pop().unwrap()\n    }\n\n    /// Identifies `Error`s.\n    pub async fn identify_errors(\n        &self,\n        identifiers: impl IntoIterator<Item = Selector>,\n    ) -> Vec<Option<Error>> {\n        self.identify_map(identifiers.into_iter().map(SelectorKind::Error), get_error).await\n    }\n\n    /// Identifies an `Error`.\n    pub async fn identify_error(&self, identifier: Selector) -> Option<Error> {\n        self.identify_errors([identifier]).await.pop().unwrap()\n    }\n\n    /// Identifies a list of selectors.\n    pub async fn identify(&self, selectors: &[SelectorKind]) -> Vec<Option<String>> {\n        if selectors.is_empty() {\n            return vec![];\n        }\n        trace!(target: \"evm::traces\", ?selectors, \"identifying selectors\");\n\n        let mut cache_r = self.0.cache.read().await;\n        if let Some(client) = &self.0.client {\n            let query =\n                selectors.iter().copied().filter(|v| !cache_r.contains_key(v)).collect::<Vec<_>>();\n            if !query.is_empty() {\n                drop(cache_r);\n                let mut cache_w = self.0.cache.write().await;\n                if let Ok(res) = client.decode_selectors(&query).await {\n                    for (selector, signatures) in std::iter::zip(query, res) {\n                        cache_w.signatures.insert(selector, signatures.into_iter().next());\n                    }\n                }\n                drop(cache_w);\n                cache_r = self.0.cache.read().await;\n            }\n        }\n        selectors.iter().map(|selector| cache_r.get(selector).unwrap_or_default()).collect()\n    }\n\n    async fn identify_map<T>(\n        &self,\n        selectors: impl IntoIterator<Item = SelectorKind>,\n        get_type: impl Fn(&str) -> Result<T>,\n    ) -> Vec<Option<T>> {\n        let results = self.identify(&Vec::from_iter(selectors)).await;\n        results.into_iter().map(|r| r.and_then(|r| get_type(&r).ok())).collect()\n    }\n}\n\nimpl SignaturesIdentifierInner {\n    fn save(&self) {\n        // We only identify new signatures if the client is enabled.\n        if let Some(path) = &self.cache_path\n            && self.client.is_some()\n        {\n            self.cache\n                .try_read()\n                .expect(\"SignaturesIdentifier cache is locked while attempting to save\")\n                .save(path);\n        }\n    }\n}\n\nimpl Drop for SignaturesIdentifierInner {\n    fn drop(&mut self) {\n        self.save();\n    }\n}\n"
  },
  {
    "path": "crates/evm/traces/src/lib.rs",
    "content": "//! # foundry-evm-traces\n//!\n//! EVM trace identifying and decoding.\n\n#![cfg_attr(not(test), warn(unused_crate_dependencies))]\n#![cfg_attr(docsrs, feature(doc_cfg))]\n\n#[macro_use]\nextern crate foundry_common;\n\n#[macro_use]\nextern crate tracing;\n\nuse foundry_common::{\n    contracts::{ContractsByAddress, ContractsByArtifact},\n    shell,\n};\nuse revm::bytecode::opcode::OpCode;\nuse revm_inspectors::tracing::{\n    OpcodeFilter,\n    types::{DecodedTraceStep, TraceMemberOrder},\n};\nuse serde::{Deserialize, Serialize};\nuse std::{\n    borrow::Cow,\n    collections::BTreeSet,\n    ops::{Deref, DerefMut},\n};\n\nuse alloy_primitives::map::HashMap;\n\npub use revm_inspectors::tracing::{\n    CallTraceArena, FourByteInspector, GethTraceBuilder, ParityTraceBuilder, StackSnapshotType,\n    TraceWriter, TracingInspector, TracingInspectorConfig,\n    types::{\n        CallKind, CallLog, CallTrace, CallTraceNode, DecodedCallData, DecodedCallLog,\n        DecodedCallTrace,\n    },\n};\n\n/// Call trace address identifiers.\n///\n/// Identifiers figure out what ABIs and labels belong to all the addresses of the trace.\npub mod identifier;\nuse identifier::LocalTraceIdentifier;\n\nmod decoder;\npub use decoder::{CallTraceDecoder, CallTraceDecoderBuilder};\n\npub mod debug;\npub use debug::DebugTraceIdentifier;\n\npub mod folded_stack_trace;\n\npub mod backtrace;\n\npub type Traces = Vec<(TraceKind, SparsedTraceArena)>;\n\n/// Trace arena keeping track of ignored trace items.\n#[derive(Debug, Clone, Serialize, Deserialize)]\npub struct SparsedTraceArena {\n    /// Full trace arena.\n    #[serde(flatten)]\n    pub arena: CallTraceArena,\n    /// Ranges of trace steps to ignore in format (start_node, start_step) -> (end_node, end_step).\n    /// See `foundry_cheatcodes::utils::IgnoredTraces` for more information.\n    #[serde(default, skip_serializing_if = \"HashMap::is_empty\")]\n    pub ignored: HashMap<(usize, usize), (usize, usize)>,\n}\n\nimpl SparsedTraceArena {\n    /// Goes over entire trace arena and removes ignored trace items.\n    fn resolve_arena(&self) -> Cow<'_, CallTraceArena> {\n        if self.ignored.is_empty() {\n            Cow::Borrowed(&self.arena)\n        } else {\n            let mut arena = self.arena.clone();\n\n            fn clear_node(\n                nodes: &mut [CallTraceNode],\n                node_idx: usize,\n                ignored: &HashMap<(usize, usize), (usize, usize)>,\n                cur_ignore_end: &mut Option<(usize, usize)>,\n            ) {\n                // Prepend an additional None item to the ordering to handle the beginning of the\n                // trace.\n                let items = std::iter::once(None)\n                    .chain(nodes[node_idx].ordering.clone().into_iter().map(Some))\n                    .enumerate();\n\n                let mut internal_calls = Vec::new();\n                let mut items_to_remove = BTreeSet::new();\n                for (item_idx, item) in items {\n                    if let Some(end_node) = ignored.get(&(node_idx, item_idx)) {\n                        *cur_ignore_end = Some(*end_node);\n                    }\n\n                    let mut remove = cur_ignore_end.is_some() & item.is_some();\n\n                    match item {\n                        // we only remove calls if they did not start/pause tracing\n                        Some(TraceMemberOrder::Call(child_idx)) => {\n                            clear_node(\n                                nodes,\n                                nodes[node_idx].children[child_idx],\n                                ignored,\n                                cur_ignore_end,\n                            );\n                            remove &= cur_ignore_end.is_some();\n                        }\n                        // we only remove decoded internal calls if they did not start/pause tracing\n                        Some(TraceMemberOrder::Step(step_idx)) => {\n                            // If this is an internal call beginning, track it in `internal_calls`\n                            if let Some(decoded) = &nodes[node_idx].trace.steps[step_idx].decoded\n                                && let DecodedTraceStep::InternalCall(_, end_step_idx) = &**decoded\n                            {\n                                internal_calls.push((item_idx, remove, *end_step_idx));\n                                // we decide if we should remove it later\n                                remove = false;\n                            }\n                            // Handle ends of internal calls\n                            internal_calls.retain(|(start_item_idx, remove_start, end_idx)| {\n                                if *end_idx != step_idx {\n                                    return true;\n                                }\n                                // only remove start if end should be removed as well\n                                if *remove_start && remove {\n                                    items_to_remove.insert(*start_item_idx);\n                                } else {\n                                    remove = false;\n                                }\n\n                                false\n                            });\n                        }\n                        _ => {}\n                    }\n\n                    if remove {\n                        items_to_remove.insert(item_idx);\n                    }\n\n                    if let Some((end_node, end_step_idx)) = cur_ignore_end\n                        && node_idx == *end_node\n                        && item_idx == *end_step_idx\n                    {\n                        *cur_ignore_end = None;\n                    }\n                }\n\n                for (offset, item_idx) in items_to_remove.into_iter().enumerate() {\n                    nodes[node_idx].ordering.remove(item_idx - offset - 1);\n                }\n            }\n\n            clear_node(arena.nodes_mut(), 0, &self.ignored, &mut None);\n\n            Cow::Owned(arena)\n        }\n    }\n}\n\nimpl Deref for SparsedTraceArena {\n    type Target = CallTraceArena;\n\n    fn deref(&self) -> &Self::Target {\n        &self.arena\n    }\n}\n\nimpl DerefMut for SparsedTraceArena {\n    fn deref_mut(&mut self) -> &mut Self::Target {\n        &mut self.arena\n    }\n}\n\n/// Decode a collection of call traces.\n///\n/// The traces will be decoded using the given decoder, if possible.\npub async fn decode_trace_arena(arena: &mut CallTraceArena, decoder: &CallTraceDecoder) {\n    decoder.prefetch_signatures(arena.nodes()).await;\n    decoder.populate_traces(arena.nodes_mut()).await;\n}\n\n/// Render a collection of call traces to a string.\npub fn render_trace_arena(arena: &SparsedTraceArena) -> String {\n    render_trace_arena_inner(arena, false, false)\n}\n\n/// Prunes trace depth if depth is provided as an argument\npub fn prune_trace_depth(arena: &mut CallTraceArena, depth: usize) {\n    for node in arena.nodes_mut() {\n        if node.trace.depth >= depth {\n            node.ordering.clear();\n        }\n    }\n}\n\n/// Render a collection of call traces to a string optionally including contract creation bytecodes\n/// and in JSON format.\npub fn render_trace_arena_inner(\n    arena: &SparsedTraceArena,\n    with_bytecodes: bool,\n    with_storage_changes: bool,\n) -> String {\n    if shell::is_json() {\n        return serde_json::to_string(&arena.resolve_arena()).expect(\"Failed to serialize traces\");\n    }\n\n    let mut w = TraceWriter::new(Vec::<u8>::new())\n        .color_cheatcodes(true)\n        .use_colors(convert_color_choice(shell::color_choice()))\n        .write_bytecodes(with_bytecodes)\n        .with_storage_changes(with_storage_changes);\n    w.write_arena(&arena.resolve_arena()).expect(\"Failed to write traces\");\n    String::from_utf8(w.into_writer()).expect(\"trace writer wrote invalid UTF-8\")\n}\n\nfn convert_color_choice(choice: shell::ColorChoice) -> revm_inspectors::ColorChoice {\n    match choice {\n        shell::ColorChoice::Auto => revm_inspectors::ColorChoice::Auto,\n        shell::ColorChoice::Always => revm_inspectors::ColorChoice::Always,\n        shell::ColorChoice::Never => revm_inspectors::ColorChoice::Never,\n    }\n}\n\n/// Specifies the kind of trace.\n#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]\npub enum TraceKind {\n    Deployment,\n    Setup,\n    Execution,\n}\n\nimpl TraceKind {\n    /// Returns `true` if the trace kind is [`Deployment`].\n    ///\n    /// [`Deployment`]: TraceKind::Deployment\n    #[must_use]\n    pub fn is_deployment(self) -> bool {\n        matches!(self, Self::Deployment)\n    }\n\n    /// Returns `true` if the trace kind is [`Setup`].\n    ///\n    /// [`Setup`]: TraceKind::Setup\n    #[must_use]\n    pub fn is_setup(self) -> bool {\n        matches!(self, Self::Setup)\n    }\n\n    /// Returns `true` if the trace kind is [`Execution`].\n    ///\n    /// [`Execution`]: TraceKind::Execution\n    #[must_use]\n    pub fn is_execution(self) -> bool {\n        matches!(self, Self::Execution)\n    }\n}\n\n/// Given a list of traces and artifacts, it returns a map connecting address to abi\npub fn load_contracts<'a>(\n    traces: impl IntoIterator<Item = &'a CallTraceArena>,\n    known_contracts: &ContractsByArtifact,\n) -> ContractsByAddress {\n    let mut local_identifier = LocalTraceIdentifier::new(known_contracts);\n    let decoder = CallTraceDecoder::new();\n    let mut contracts = ContractsByAddress::new();\n    for trace in traces {\n        for address in decoder.identify_addresses(trace, &mut local_identifier) {\n            if let (Some(contract), Some(abi)) = (address.contract, address.abi) {\n                contracts.insert(address.address, (contract, abi.into_owned()));\n            }\n        }\n    }\n    contracts\n}\n\n/// Different kinds of internal functions tracing.\n#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default)]\npub enum InternalTraceMode {\n    #[default]\n    None,\n    /// Traces internal functions without decoding inputs/outputs from memory.\n    Simple,\n    /// Same as `Simple`, but also tracks memory snapshots.\n    Full,\n}\n\nimpl From<InternalTraceMode> for TraceMode {\n    fn from(mode: InternalTraceMode) -> Self {\n        match mode {\n            InternalTraceMode::None => Self::None,\n            InternalTraceMode::Simple => Self::JumpSimple,\n            InternalTraceMode::Full => Self::Jump,\n        }\n    }\n}\n\n// Different kinds of traces used by different foundry components.\n#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default)]\npub enum TraceMode {\n    /// Disabled tracing.\n    #[default]\n    None,\n    /// Simple call trace, no steps tracing required.\n    Call,\n    /// Call trace with steps tracing for JUMP and JUMPDEST opcodes.\n    ///\n    /// Does not enable tracking memory or stack snapshots.\n    Steps,\n    /// Call trace with tracing for JUMP and JUMPDEST opcode steps.\n    ///\n    /// Used for internal functions identification. Does not track memory snapshots.\n    JumpSimple,\n    /// Call trace with tracing for JUMP and JUMPDEST opcode steps.\n    ///\n    /// Same as `JumpSimple`, but tracks memory snapshots as well.\n    Jump,\n    /// Call trace with complete steps tracing.\n    ///\n    /// Used by debugger.\n    Debug,\n    /// Step trace with storage change recording.\n    ///\n    /// Records JUMP/JUMPDEST steps (like `Steps`) plus storage diffs on SLOAD/SSTORE.\n    /// Does not enable memory/stack snapshots or unfiltered opcode recording.\n    RecordStateDiff,\n}\n\nimpl TraceMode {\n    pub const fn is_none(self) -> bool {\n        matches!(self, Self::None)\n    }\n\n    pub const fn is_call(self) -> bool {\n        matches!(self, Self::Call)\n    }\n\n    pub const fn is_steps(self) -> bool {\n        matches!(self, Self::Steps)\n    }\n\n    pub const fn is_jump_simple(self) -> bool {\n        matches!(self, Self::JumpSimple)\n    }\n\n    pub const fn is_jump(self) -> bool {\n        matches!(self, Self::Jump)\n    }\n\n    pub const fn record_state_diff(self) -> bool {\n        matches!(self, Self::RecordStateDiff)\n    }\n\n    pub const fn is_debug(self) -> bool {\n        matches!(self, Self::Debug)\n    }\n\n    pub fn with_debug(self, yes: bool) -> Self {\n        if yes { std::cmp::max(self, Self::Debug) } else { self }\n    }\n\n    pub fn with_decode_internal(self, mode: InternalTraceMode) -> Self {\n        std::cmp::max(self, mode.into())\n    }\n\n    pub fn with_state_changes(self, yes: bool) -> Self {\n        if yes { std::cmp::max(self, Self::RecordStateDiff) } else { self }\n    }\n\n    pub fn with_verbosity(self, verbosity: u8) -> Self {\n        match verbosity {\n            0..3 => self,\n            3..=4 => std::cmp::max(self, Self::Call),\n            // Enable step recording and state diff recording when verbosity is 5 or higher.\n            // This includes backtraces (JUMP/JUMPDEST steps) and storage changes.\n            _ => std::cmp::max(self, Self::RecordStateDiff),\n        }\n    }\n\n    pub fn into_config(self) -> Option<TracingInspectorConfig> {\n        if self.is_none() {\n            None\n        } else {\n            // RecordStateDiff is Steps + state diff recording, not Debug + state diff.\n            // It should not enable memory/stack snapshots.\n            // State diff recording requires all opcodes (no filter) since it needs\n            // SLOAD/SSTORE steps, not just JUMP/JUMPDEST.\n            let effective = if self.record_state_diff() { Self::Steps } else { self };\n            TracingInspectorConfig {\n                record_steps: self >= Self::Steps,\n                record_memory_snapshots: effective >= Self::Jump,\n                record_stack_snapshots: if effective > Self::Steps {\n                    StackSnapshotType::Full\n                } else {\n                    StackSnapshotType::None\n                },\n                record_logs: true,\n                record_state_diff: self.record_state_diff(),\n                record_returndata_snapshots: effective.is_debug(),\n                // State diff needs all opcodes recorded to capture SLOAD/SSTORE.\n                record_opcodes_filter: if self.record_state_diff() {\n                    None\n                } else {\n                    (effective.is_steps() || effective.is_jump() || effective.is_jump_simple())\n                        .then(|| {\n                            OpcodeFilter::new().enabled(OpCode::JUMP).enabled(OpCode::JUMPDEST)\n                        })\n                },\n                exclude_precompile_calls: false,\n                record_immediate_bytes: effective.is_debug(),\n            }\n            .into()\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    // -- TraceMode::with_verbosity level tests --\n\n    #[test]\n    fn verbosity_0_through_2_is_noop() {\n        for v in 0..=2 {\n            assert_eq!(TraceMode::None.with_verbosity(v), TraceMode::None, \"v={v}\");\n            assert_eq!(TraceMode::Call.with_verbosity(v), TraceMode::Call, \"v={v}\");\n            assert_eq!(TraceMode::Debug.with_verbosity(v), TraceMode::Debug, \"v={v}\");\n        }\n    }\n\n    #[test]\n    fn verbosity_3_and_4_raises_to_call() {\n        for v in 3..=4 {\n            assert_eq!(TraceMode::None.with_verbosity(v), TraceMode::Call, \"v={v}\");\n            // Already above Call — must not downgrade.\n            assert_eq!(TraceMode::Debug.with_verbosity(v), TraceMode::Debug, \"v={v}\");\n            assert_eq!(\n                TraceMode::RecordStateDiff.with_verbosity(v),\n                TraceMode::RecordStateDiff,\n                \"v={v}\"\n            );\n        }\n    }\n\n    #[test]\n    fn verbosity_5_raises_to_record_state_diff() {\n        assert_eq!(TraceMode::None.with_verbosity(5), TraceMode::RecordStateDiff);\n        assert_eq!(TraceMode::Call.with_verbosity(5), TraceMode::RecordStateDiff);\n        assert_eq!(TraceMode::Steps.with_verbosity(5), TraceMode::RecordStateDiff);\n        assert_eq!(TraceMode::Debug.with_verbosity(5), TraceMode::RecordStateDiff);\n        // Already at the top — stays the same.\n        assert_eq!(TraceMode::RecordStateDiff.with_verbosity(5), TraceMode::RecordStateDiff);\n    }\n\n    // -- into_config at each verbosity level --\n\n    #[test]\n    fn config_at_verbosity_0_is_none() {\n        let mode = TraceMode::None.with_verbosity(0);\n        assert!(mode.into_config().is_none());\n    }\n\n    #[test]\n    fn config_at_verbosity_3_records_calls_only() {\n        let cfg = TraceMode::None.with_verbosity(3).into_config().unwrap();\n        assert!(!cfg.record_steps, \"verbosity 3 should not record steps\");\n        assert!(!cfg.record_state_diff, \"verbosity 3 should not record state diff\");\n        assert!(cfg.record_logs, \"verbosity 3 should record logs\");\n    }\n\n    #[test]\n    fn config_at_verbosity_5_records_steps_and_state_diff() {\n        let cfg = TraceMode::None.with_verbosity(5).into_config().unwrap();\n        assert!(cfg.record_steps, \"verbosity 5 must record steps for backtraces\");\n        assert!(cfg.record_state_diff, \"verbosity 5 must record state diff\");\n        assert!(cfg.record_logs, \"verbosity 5 must record logs\");\n        // RecordStateDiff should NOT enable expensive debug-level features.\n        assert!(!cfg.record_memory_snapshots, \"verbosity 5 should not record memory snapshots\");\n        assert_eq!(\n            cfg.record_stack_snapshots,\n            StackSnapshotType::None,\n            \"verbosity 5 should not record stack snapshots\"\n        );\n        // State diff requires all opcodes to capture SLOAD/SSTORE, so no filter.\n        assert!(\n            cfg.record_opcodes_filter.is_none(),\n            \"verbosity 5 needs unfiltered opcodes for state diff\"\n        );\n    }\n\n    #[test]\n    fn config_debug_mode_unchanged() {\n        // Debug mode must still enable full recording for the debugger.\n        let cfg = TraceMode::Debug.into_config().unwrap();\n        assert!(cfg.record_steps);\n        assert!(cfg.record_memory_snapshots, \"Debug must record memory snapshots\");\n        assert_eq!(\n            cfg.record_stack_snapshots,\n            StackSnapshotType::Full,\n            \"Debug must record full stack snapshots\"\n        );\n        assert!(cfg.record_returndata_snapshots, \"Debug must record returndata\");\n        assert!(cfg.record_immediate_bytes, \"Debug must record immediate bytes\");\n        assert!(cfg.record_opcodes_filter.is_none(), \"Debug must record all opcodes (no filter)\");\n        assert!(!cfg.record_state_diff, \"Debug alone should not record state diff\");\n    }\n}\n"
  },
  {
    "path": "crates/fmt/Cargo.toml",
    "content": "[package]\nname = \"forge-fmt\"\n\nversion.workspace = true\nedition.workspace = true\nrust-version.workspace = true\nauthors.workspace = true\nlicense.workspace = true\nhomepage.workspace = true\nrepository.workspace = true\n\n[lints]\nworkspace = true\n\n[dependencies]\nfoundry-config.workspace = true\nfoundry-common.workspace = true\n\nsolar.workspace = true\n\nitertools.workspace = true\nsimilar = { version = \"2\", features = [\"inline\"] }\n\n[dev-dependencies]\nfoundry-test-utils.workspace = true\n\ntoml.workspace = true\nsnapbox.workspace = true\n"
  },
  {
    "path": "crates/fmt/README.md",
    "content": "# Formatter (`fmt`)\n\nSolidity formatter that respects (some parts of)\nthe [Style Guide](https://docs.soliditylang.org/en/latest/style-guide.html) and\nis tested on the [Prettier Solidity Plugin](https://github.com/prettier-solidity/prettier-plugin-solidity) cases.\n\n## Architecture\n\nThe formatter is built on top of [Solar](https://github.com/paradigmxyz/solar), and the architecture is based on a Wadler-style pretty-printing engine. The formatting process consists of two main steps:\n\n1.  **Parsing**: The Solidity source code is parsed using **`solar`** into an **Abstract Syntax Tree (AST)**. The AST is a tree representation of the code's syntactic structure.\n2.  **Printing**: The AST is traversed by a visitor, which generates a stream of abstract tokens that are then processed by a pretty-printing engine to produce the final formatted code.\n\n### The Pretty Printer (`pp`)\n\nThe core of the formatter is a pretty-printing engine inspired by Philip Wadler's algorithm, and adapted from the implementations in `rustc_ast_pretty` and `prettyplease`. Its goal is to produce an optimal and readable layout by making intelligent decisions about line breaks.\n\nThe process works like this:\n\n1.  **AST to Abstract Tokens**: The formatter's `State` object walks the `solar` AST. Instead of directly writing strings, it translates the AST nodes into a stream of abstract formatting \"commands\" called `Token`s. This decouples the code's structure from the final text output. The primary tokens are:\n    *   **`String`**: An atomic, unbreakable piece of text, like a keyword (`function`), an identifier (`myVar`), or a literal (`42`).\n    *   **`Break`**: A potential line break. This is the core of the engine's flexibility. The `Printer` later decides whether to render a `Break` as a single space or as a newline with appropriate indentation.\n    *   **`Begin`/`End`**: These tokens define a logical group of tokens that should be formatted as a single unit. This allows the printer to decide how to format the entire group at once.\n\n2.  **Grouping and Breaking Strategy**: The `Begin` and `End` tokens create formatting \"boxes\" that guide the breaking strategy. There are two main types of boxes:\n    *   **Consistent Box (`cbox`)**: If *any* `Break` inside this box becomes a newline, then *all* `Break`s inside it must also become newlines. This is ideal for lists like function parameters or struct fields, ensuring they are either all on one line or neatly arranged with one item per line.\n    *   **Inconsistent Box (`ibox`)**: `Break`s within this box are independent. The printer can wrap a long line at any `Break` point without forcing other breaks in the same box to become newlines. This is useful for formatting long expressions or comments.\n\n3.  **The `Printer` Engine**: The `Printer` consumes this stream of tokens and makes the final decisions:\n    *   It maintains a buffer of tokens and tracks the remaining space on the current line based on the configured `line_length`.\n    *   When it encounters a `Begin` token for a group, it calculates whether the entire group could fit on the current line if all its `Break`s were spaces.\n    *   **If it fits**, all `Break`s in that group are rendered as spaces.\n    *   **If it doesn't fit**, `Break`s are rendered as newlines, and the indentation level is adjusted accordingly based on the box's rules (consistent or inconsistent).\n\nCrucially, this entire process is deterministic. Because the formatter completely rebuilds the code from the AST, it discards all original whitespace, line breaks, and other stylistic variations. This means that for a given AST and configuration, the output will always be identical. No matter how inconsistently the input code is formatted, the result is a single, canonical representation, ensuring predictability and consistency across any codebase.\n\n> **Debug Mode**: To visualize the debug output, and understand how the pretty-printer makes its decisions about boxes and breaks, see the [Debug](#debug) section in Testing.\n\n### Comments\n\nComment handling is a critical aspect of the formatter, designed to preserve developer intent while restructuring the code.\n\n1.  **Categorization**: Comments are parsed and categorized by their position and style: `Isolated` (on its own line), `Mixed` (on a line with code), and `Trailing` (at the end of a line).\n\n2.  **Blank Line Handling**: Blank lines in the source code are treated as a special `BlankLine` comment type, allowing the formatter to preserve vertical spacing that separates logical blocks of code. However, to maintain a clean and consistent vertical rhythm, any sequence of multiple blank lines is collapsed into a single blank line. This prevents excessive empty space in the formatted output.\n\n3.  **Integration with Printing**: During the AST traversal, the formatter queries for comments that appear before the current code element. These comments, including blank lines, are then strategically inserted into the `Printer`'s token stream. The formatter inserts `Break` tokens around comments to ensure they are correctly spaced from the surrounding code, and emits one or two `hardbreak`s for blank lines to maintain the original vertical rhythm.\n\nThis approach allows the formatter to respect both the syntactic structure of the code and the developer's textual annotations and spacing, producing a clean, readable, and intentional layout.\n\n### Example\n\n**Source Code**\n```solidity\npragma   solidity ^0.8.10 ;\ncontract  HelloWorld {\n    string   public message;\n    constructor(  string memory initMessage) { message = initMessage;}\n}\n\n\n\nevent    Greet( string  indexed  name) ;\n```\n\n**Abstract Syntax Tree (AST) (simplified)**\n```text\nSourceUnit\n ├─ PragmaDirective(\"solidity\", \"^0.8.10\")\n ├─ ItemContract(\"HelloWorld\")\n │   ├─ VariableDefinition { name: \"message\", ty: \"string\", visibility: \"public\" }\n │   └─ ItemFunction {\n │         kind: Constructor,\n │         header: FunctionHeader {\n │            parameters: [\n │               VariableDefinition { name: \"initMessage\", ty: \"string\", data_location: \"memory\" }\n │            ]\n │         },\n │         body: Block {\n │            stmts: [\n │               Stmt { kind: Expr(Assign {lhs: Ident(\"message\"), rhs: Ident(\"initMessage\")}) }\n │            ]\n │         }\n │      }\n └─ ItemEvent { name: \"Greet\", parameters: [\n       VariableDefinition { name: \"name\", ty: \"string\", indexed: true }\n    ] }\n```\n\n\n**Formatted Source Code**\nThe code is reconstructed from the AST using the pretty-printer.\n```solidity\npragma solidity ^0.8.10;\n\ncontract HelloWorld {\n    string public message;\n\n    constructor(string memory initMessage) {\n        message = initMessage;\n    }\n}\n\nevent Greet(string indexed name);\n```\n\n### Configuration\n\nThe formatter supports multiple configuration options defined in `foundry.toml`.\n\n| Option | Default | Description |\n| :--- | :--- | :--- |\n| `line_length` | `120` | Maximum line length where the formatter will try to wrap the line. |\n| `tab_width` | `4` | Number of spaces per indentation level. Ignored if `style` is `tab`. |\n| `style` | `space` | The style of indentation. Options: `space`, `tab`. |\n| `bracket_spacing` | `false` | Print spaces between brackets. |\n| `int_types` | `long` | Style for `uint256`/`int256` types. Options: `long`, `short`, `preserve`. |\n| `multiline_func_header` | `attributes_first` | The style of multiline function headers. Options: `attributes_first`, `params_always`, `params_first_multi`, `all`, `all_params`. |\n| `prefer_compact` | `all` | Style that determines if a broken list, should keep its elements together on their own line, before breaking individually. Options: `none`, `calls`, `events`, `errors`, `events_errors`, `all`. |\n| `quote_style` | `double` | The style of quotation marks. Options: `double`, `single`, `preserve`. |\n| `number_underscore` | `preserve` | The style of underscores in number literals. Options: `preserve`, `remove`, `thousands`. |\n| `hex_underscore` | `remove` | The style of underscores in hex literals. Options: `preserve`, `remove`, `bytes`. |\n| `single_line_statement_blocks` | `preserve` | The style of single-line blocks in statements. Options: `preserve`, `single`, `multi`. |\n| `override_spacing` | `false` | Print a space in the `override` attribute. |\n| `wrap_comments` | `false` | Wrap comments when `line_length` is reached. |\n| `docs_style` | `preserve` | Enforces the style of doc (natspec) comments. Options: `preserve`, `line`, `block`. |\n| `ignore` | `[]` | Globs to ignore. |\n| `contract_new_lines` | `false` | Add a new line at the start and end of contract declarations. |\n| `sort_imports` | `false` | Sort import statements alphabetically in groups. A group is a set of imports separated by a newline. |\n| `namespace_import_style` | `prefer_plain` | Style for namespace imports. Options: `prefer_plain` (`import \"foo\" as foo;`), `prefer_glob` (`import * as foo from \"foo\";`), `preserve`. |\n| `pow_no_space` | `false` | Suppress spaces around the power operator (`**`). |\n| `single_line_imports` | `false` | Keep single imports on a single line, even if they exceed the line length limit. |\n\n> Check [`FormatterConfig`](../config/src/fmt.rs) for a more detailed explanation.\n\n### Inline Configuration\n\nThe formatter can be instructed to skip specific sections of code using inline comments. While the tool supports fine-grained control, it is generally more robust and efficient to disable formatting for entire AST items or statements.\n\nThis approach is preferred because it allows the formatter to treat the entire disabled item as a single, opaque unit. It can simply copy the original source text for that item's span instead of partially formatting a line, switching to copy mode, and then resuming formatting. This leads to more predictable output and avoids potential edge cases with complex, partially-disabled statements.\n\n#### Disable Line\n\nThese directives are best used when they apply to a complete, self-contained AST statement, as shown below. In this case, `uint x = 100;` is a full statement, making it a good candidate for a line-based disable.\n\nTo disable the next line:\n```solidity\n// forgefmt: disable-next-line\nuint x = 100;\n```\n\nTo disable the current line:\n```solidity\nuint x = 100; // forgefmt: disable-line\n```\n#### Disable Block\n\nThis is the recommended approach for complex, multi-line constructs where you want to preserve specific formatting. In the example below, the entire `function` definition is disabled. This is preferable to trying to disable individual lines within the signature, because lines like `uint256 b /* a comment that goes inside the comma */,` do not correspond to a complete AST item or statement on their own. Disabling the whole item is cleaner and more aligned with the code's structure.\n\n```solidity\n// forgefmt: disable-start\nfunction fnWithManyArguments(\n    uint a,\n    uint256 b /* a comment that goes inside the comma */,\n    uint256      c\n) external returns (bool) {\n// forgefmt: disable-end\n```\n\n## Contributing\n\nCheck out the [foundry contribution guide](https://github.com/foundry-rs/foundry/blob/master/CONTRIBUTING.md).\n\nGuidelines for contributing to `forge fmt`:\n\n### Opening an issue\n\n1.  Create a short, concise title describing the issue.\n    *   **Bad**: `Forge fmt does not work`\n    *   **Good**: `bug(forge-fmt): misplaces postfix comment on if-statement`\n2.  Fill in the issue template fields, including Foundry version, platform, and component info.\n3.  Provide code snippets showing the current and expected behaviors.\n4.  If it's a feature request, explain why the feature is needed.\n5.  Add the `C-forge` and `Cmd-forge-fmt` labels.\n\n### Fixing a Bug or Developing a Feature\n\n1.  Specify the issue being addressed in the PR description.\n2.  Add a note on your solution in the PR description.\n3.  Ensure the PR includes comprehensive acceptance tests under `fmt/testdata/`, covering:\n    *   The specific case being fixed/added.\n    *   Behavior with different kinds of comments (isolated, mixed, trailing).\n    *   If it's a new config value, tests covering all available options.\n\n### Testing\n\nTests are located in the `fmt/testdata` folder. Each test consists of an `original.sol` file and one or more expected output files, named `*.fmt.sol`.\n\nThe default configuration can be overridden from within an expected output file by adding a comment in the format `// config: {config_key} = {config_value}`. For example:\n```solidity\n// config: line_length = 160\n```\n\nThe testing process for each test suite is as follows:\n1.  Read `original.sol` and the corresponding `*.fmt.sol` expected output.\n2.  Parse any `// config:` comments from the expected file to create a test-specific configuration.\n3.  Format `original.sol` and assert that the output matches the content of `*.fmt.sol`.\n4.  To ensure **idempotency**, format the content of `*.fmt.sol` again and assert that the output does not change.\n\n### Debug\n\nThe formatter includes a debug mode that provides visual insight into the pretty-printer's decision-making process. This is invaluable for troubleshooting complex formatting issues and understanding how the boxes and breaks described in [The Pretty Printer](#the-pretty-printer-pp) section work.\n\nTo enable it, run the formatter with the `FMT_DEBUG` environment variable set:\n```sh\nFMT_DEBUG=1 cargo test -p forge-fmt --test formatter Repros\n```\n\nWhen enabled, the output will be annotated with special characters representing the printer's internal state:\n\n*   **Boxes**:\n    *   `«` and `»`: Mark the start and end of a **consistent** box (`cbox`).\n    *   `‹` and `›`: Mark the start and end of an **inconsistent** box (`ibox`).\n\n*   **Breaks**:\n    *   `·`: Represents a `Break` token, which could be a space or a newline.\n\nFor example, running debug mode on the `HelloWorld` contract from earlier would produce an output like this:\n\n```text\npragma solidity ^0.8.10;·\n·\n«‹«contract HelloWorld »{›·\n‹‹    string· public· message››;·\n·\n«    constructor«(«‹‹string memory initMessage››»)» {»·\n«‹        message = ·initMessage›·;·\n»    }·\n»}·\n·\nevent Greet(««‹‹string indexed name››»»);·\n```\n\nThis annotated output allows you to see exactly how the printer is grouping tokens and where it considers inserting a space or a newline. This makes it much easier to diagnose why a certain layout is being produced.\n"
  },
  {
    "path": "crates/fmt/src/lib.rs",
    "content": "#![doc = include_str!(\"../README.md\")]\n#![cfg_attr(not(test), warn(unused_crate_dependencies))]\n#![cfg_attr(docsrs, feature(doc_cfg))]\n\nconst DEBUG: bool = false || option_env!(\"FMT_DEBUG\").is_some();\nconst DEBUG_INDENT: bool = false || option_env!(\"FMT_DEBUG\").is_some();\n\nuse foundry_common::comments::{\n    Comment, Comments,\n    inline_config::{InlineConfig, InlineConfigItem},\n};\n\nmod state;\n\nmod pp;\n\nuse solar::{\n    parse::{\n        ast::{SourceUnit, Span},\n        interface::{Session, diagnostics::EmittedDiagnostics, source_map::SourceFile},\n    },\n    sema::{Compiler, Gcx, Source},\n};\n\nuse std::{path::Path, sync::Arc};\n\npub use foundry_config::fmt::*;\n\n/// The result of the formatter.\npub type FormatterResult = DiagnosticsResult<String, EmittedDiagnostics>;\n\n/// The result of the formatter.\n#[derive(Debug)]\npub enum DiagnosticsResult<T, E> {\n    /// Everything went well.\n    Ok(T),\n    /// No errors encountered, but warnings or other non-error diagnostics were emitted.\n    OkWithDiagnostics(T, E),\n    /// Errors encountered, but a result was produced anyway.\n    ErrRecovered(T, E),\n    /// Fatal errors encountered.\n    Err(E),\n}\n\nimpl<T, E> DiagnosticsResult<T, E> {\n    /// Converts the formatter result into a standard result.\n    ///\n    /// This ignores any non-error diagnostics if `Ok`, and any valid result if `Err`.\n    pub fn into_result(self) -> Result<T, E> {\n        match self {\n            Self::Ok(s) | Self::OkWithDiagnostics(s, _) => Ok(s),\n            Self::ErrRecovered(_, d) | Self::Err(d) => Err(d),\n        }\n    }\n\n    /// Returns the result, even if it was produced with errors.\n    pub fn into_ok(self) -> Result<T, E> {\n        match self {\n            Self::Ok(s) | Self::OkWithDiagnostics(s, _) | Self::ErrRecovered(s, _) => Ok(s),\n            Self::Err(e) => Err(e),\n        }\n    }\n\n    /// Returns any result produced.\n    pub fn ok_ref(&self) -> Option<&T> {\n        match self {\n            Self::Ok(s) | Self::OkWithDiagnostics(s, _) | Self::ErrRecovered(s, _) => Some(s),\n            Self::Err(_) => None,\n        }\n    }\n\n    /// Returns any diagnostics emitted.\n    pub fn err_ref(&self) -> Option<&E> {\n        match self {\n            Self::Ok(_) => None,\n            Self::OkWithDiagnostics(_, d) | Self::ErrRecovered(_, d) | Self::Err(d) => Some(d),\n        }\n    }\n\n    /// Returns `true` if the result is `Ok`.\n    pub fn is_ok(&self) -> bool {\n        matches!(self, Self::Ok(_) | Self::OkWithDiagnostics(_, _))\n    }\n\n    /// Returns `true` if the result is `Err`.\n    pub fn is_err(&self) -> bool {\n        !self.is_ok()\n    }\n}\n\npub fn format_file(\n    path: &Path,\n    config: Arc<FormatterConfig>,\n    compiler: &mut Compiler,\n) -> FormatterResult {\n    format_inner(config, compiler, &|sess| {\n        sess.source_map().load_file(path).map_err(|e| sess.dcx.err(e.to_string()).emit())\n    })\n}\n\npub fn format_source(\n    source: &str,\n    path: Option<&Path>,\n    config: Arc<FormatterConfig>,\n    compiler: &mut Compiler,\n) -> FormatterResult {\n    format_inner(config, compiler, &|sess| {\n        let name = match path {\n            Some(path) => solar::parse::interface::source_map::FileName::Real(path.to_path_buf()),\n            None => solar::parse::interface::source_map::FileName::Stdin,\n        };\n        sess.source_map()\n            .new_source_file(name, source)\n            .map_err(|e| sess.dcx.err(e.to_string()).emit())\n    })\n}\n\n/// Format a string input with the default compiler.\npub fn format(source: &str, config: FormatterConfig) -> FormatterResult {\n    let mut compiler = Compiler::new(\n        solar::interface::Session::builder().with_buffer_emitter(Default::default()).build(),\n    );\n\n    format_source(source, None, Arc::new(config), &mut compiler)\n}\n\nfn format_inner(\n    config: Arc<FormatterConfig>,\n    compiler: &mut Compiler,\n    mk_file: &(dyn Fn(&Session) -> solar::parse::interface::Result<Arc<SourceFile>> + Sync + Send),\n) -> FormatterResult {\n    // First pass formatting\n    let first_result = format_once(config.clone(), compiler, mk_file);\n\n    // If first pass was not successful, return the result\n    if first_result.is_err() {\n        return first_result;\n    }\n    let Some(first_formatted) = first_result.ok_ref() else { return first_result };\n\n    // Second pass formatting\n    let second_result = format_once(config, compiler, &|sess| {\n        // Need a new name since we can't overwrite the original file.\n        let prev_sf = mk_file(sess)?;\n        let new_name = match &prev_sf.name {\n            solar::interface::source_map::FileName::Real(path) => {\n                path.with_extension(\"again.sol\").into()\n            }\n            solar::interface::source_map::FileName::Stdin => {\n                solar::interface::source_map::FileName::Custom(\"stdin-again\".to_string())\n            }\n            solar::interface::source_map::FileName::Custom(name) => {\n                solar::interface::source_map::FileName::Custom(format!(\"{name}-again\"))\n            }\n        };\n        sess.source_map()\n            .new_source_file(new_name, first_formatted)\n            .map_err(|e| sess.dcx.err(e.to_string()).emit())\n    });\n\n    // Check if the two passes produce the same output (idempotency)\n    match (first_result.ok_ref(), second_result.ok_ref()) {\n        (Some(first), Some(second)) if first != second => {\n            panic!(\"formatter is not idempotent:\\n{}\", diff(first, second));\n        }\n        _ => {}\n    }\n\n    if first_result.is_ok() && second_result.is_err() && !DEBUG {\n        panic!(\n            \"failed to format a second time:\\nfirst_result={first_result:#?}\\nsecond_result={second_result:#?}\"\n        );\n        // second_result\n    } else {\n        first_result\n    }\n}\n\nfn diff(first: &str, second: &str) -> impl std::fmt::Display {\n    use std::fmt::Write;\n    let diff = similar::TextDiff::from_lines(first, second);\n    let mut s = String::new();\n    for change in diff.iter_all_changes() {\n        let tag = match change.tag() {\n            similar::ChangeTag::Delete => \"-\",\n            similar::ChangeTag::Insert => \"+\",\n            similar::ChangeTag::Equal => \" \",\n        };\n        write!(s, \"{tag}{change}\").unwrap();\n    }\n    s\n}\n\nfn format_once(\n    config: Arc<FormatterConfig>,\n    compiler: &mut Compiler,\n    mk_file: &(\n         dyn Fn(&solar::interface::Session) -> solar::interface::Result<Arc<SourceFile>>\n             + Send\n             + Sync\n     ),\n) -> FormatterResult {\n    let res = compiler.enter_mut(|c| -> solar::interface::Result<String> {\n        let mut pcx = c.parse();\n        pcx.set_resolve_imports(false);\n        let file = mk_file(c.sess())?;\n        pcx.add_file(file.clone());\n        pcx.parse();\n        c.dcx().has_errors()?;\n\n        let gcx = c.gcx();\n        let (_, source) = gcx.get_ast_source(&file.name).unwrap();\n        Ok(format_ast(gcx, source, config).expect(\"unable to format AST\"))\n    });\n\n    let diagnostics = compiler.sess().dcx.emitted_diagnostics().unwrap();\n    match (res, compiler.sess().dcx.has_errors()) {\n        (Ok(s), Ok(())) if diagnostics.is_empty() => FormatterResult::Ok(s),\n        (Ok(s), Ok(())) => FormatterResult::OkWithDiagnostics(s, diagnostics),\n        (Ok(s), Err(_)) => FormatterResult::ErrRecovered(s, diagnostics),\n        (Err(_), Ok(_)) => unreachable!(),\n        (Err(_), Err(_)) => FormatterResult::Err(diagnostics),\n    }\n}\n\n// A parallel-safe \"worker\" function.\npub fn format_ast<'ast>(\n    gcx: Gcx<'ast>,\n    source: &'ast Source<'ast>,\n    config: Arc<FormatterConfig>,\n) -> Option<String> {\n    let comments = Comments::new(\n        &source.file,\n        gcx.sess.source_map(),\n        true,\n        config.wrap_comments,\n        if matches!(config.style, IndentStyle::Tab) { Some(config.tab_width) } else { None },\n    );\n    let ast = source.ast.as_ref()?;\n    let inline_config = parse_inline_config(gcx.sess, &comments, ast);\n\n    let mut state = state::State::new(gcx.sess.source_map(), config, inline_config, comments);\n    state.print_source_unit(ast);\n    Some(state.s.eof())\n}\n\nfn parse_inline_config<'ast>(\n    sess: &Session,\n    comments: &Comments,\n    ast: &'ast SourceUnit<'ast>,\n) -> InlineConfig<()> {\n    let parse_item = |mut item: &str, cmnt: &Comment| -> Option<(Span, InlineConfigItem<()>)> {\n        if let Some(prefix) = cmnt.prefix() {\n            item = item.strip_prefix(prefix).unwrap_or(item);\n        }\n        if let Some(suffix) = cmnt.suffix() {\n            item = item.strip_suffix(suffix).unwrap_or(item);\n        }\n        let item = item.trim_start().strip_prefix(\"forgefmt:\")?.trim();\n        match item.parse::<InlineConfigItem<()>>() {\n            Ok(item) => Some((cmnt.span, item)),\n            Err(e) => {\n                sess.dcx.warn(e.to_string()).span(cmnt.span).emit();\n                None\n            }\n        }\n    };\n\n    let items = comments.iter().flat_map(|cmnt| {\n        let mut found_items = Vec::with_capacity(2);\n        // Always process the first line.\n        if let Some(line) = cmnt.lines.first()\n            && let Some(item) = parse_item(line, cmnt)\n        {\n            found_items.push(item);\n        }\n        // If the comment has more than one line, process the last line.\n        if cmnt.lines.len() > 1\n            && let Some(line) = cmnt.lines.last()\n            && let Some(item) = parse_item(line, cmnt)\n        {\n            found_items.push(item);\n        }\n        found_items\n    });\n\n    InlineConfig::from_ast(items, ast, sess.source_map())\n}\n"
  },
  {
    "path": "crates/fmt/src/pp/convenience.rs",
    "content": "use super::{BeginToken, BreakToken, Breaks, IndentStyle, Printer, SIZE_INFINITY, Token};\nuse std::borrow::Cow;\n\nimpl Printer {\n    /// \"raw box\"\n    pub fn rbox(&mut self, indent: isize, breaks: Breaks) {\n        self.scan_begin(BeginToken { indent: IndentStyle::Block { offset: indent }, breaks });\n    }\n\n    /// Inconsistent breaking box\n    pub fn ibox(&mut self, indent: isize) {\n        self.rbox(indent, Breaks::Inconsistent);\n    }\n\n    /// Consistent breaking box\n    pub fn cbox(&mut self, indent: isize) {\n        self.rbox(indent, Breaks::Consistent);\n    }\n\n    pub fn visual_align(&mut self) {\n        self.scan_begin(BeginToken { indent: IndentStyle::Visual, breaks: Breaks::Consistent });\n    }\n\n    pub fn break_offset(&mut self, n: usize, off: isize) {\n        self.scan_break(BreakToken { offset: off, blank_space: n, ..BreakToken::default() });\n    }\n\n    pub fn end(&mut self) {\n        self.scan_end();\n    }\n\n    pub fn eof(mut self) -> String {\n        self.scan_eof();\n        self.out\n    }\n\n    pub fn word(&mut self, w: impl Into<Cow<'static, str>>) {\n        self.scan_string(w.into());\n    }\n\n    fn spaces(&mut self, n: usize) {\n        self.break_offset(n, 0);\n    }\n\n    pub fn zerobreak(&mut self) {\n        self.spaces(0);\n    }\n\n    pub fn space(&mut self) {\n        self.spaces(1);\n    }\n\n    pub fn hardbreak(&mut self) {\n        self.spaces(SIZE_INFINITY as usize);\n    }\n\n    pub fn last_token_is_neverbreak(&self) -> bool {\n        if let Some(token) = self.last_token() {\n            return token.is_neverbreak();\n        }\n\n        false\n    }\n\n    pub fn last_token_is_break(&self) -> bool {\n        if let Some(token) = self.last_token() {\n            return matches!(token, Token::Break(_));\n        }\n        false\n    }\n\n    pub fn last_token_is_space(&self) -> bool {\n        if let Some(token) = self.last_token()\n            && token.is_space()\n        {\n            return true;\n        }\n\n        self.out.ends_with(\" \")\n    }\n\n    pub fn is_beginning_of_line(&self) -> bool {\n        match self.last_token() {\n            Some(last_token) => last_token.is_hardbreak(),\n            None => self.out.is_empty() || self.out.ends_with('\\n'),\n        }\n    }\n\n    /// Attempts to identify whether the current position is:\n    ///   1. the beginning of a line (empty)\n    ///   2. a line with only indentation (just whitespaces)\n    ///\n    /// NOTE: this is still an educated guess, based on a heuristic.\n    pub fn is_bol_or_only_ind(&self) -> bool {\n        for i in self.buf.index_range().rev() {\n            let token = &self.buf[i].token;\n            if token.is_hardbreak() {\n                return true;\n            }\n            if Self::token_has_non_whitespace_content(token) {\n                return false;\n            }\n        }\n\n        let last_line =\n            if let Some(pos) = self.out.rfind('\\n') { &self.out[pos + 1..] } else { &self.out[..] };\n\n        last_line.trim().is_empty()\n    }\n\n    fn token_has_non_whitespace_content(token: &Token) -> bool {\n        match token {\n            Token::String(s) => !s.trim().is_empty(),\n            Token::Break(BreakToken { pre_break: Some(s), .. }) => !s.trim().is_empty(),\n            _ => false,\n        }\n    }\n\n    pub(crate) fn hardbreak_tok_offset(offset: isize) -> Token {\n        Token::Break(BreakToken {\n            offset,\n            blank_space: SIZE_INFINITY as usize,\n            ..BreakToken::default()\n        })\n    }\n\n    pub fn hardbreak_if_nonempty(&mut self) {\n        self.scan_break(BreakToken {\n            blank_space: SIZE_INFINITY as usize,\n            if_nonempty: true,\n            ..BreakToken::default()\n        });\n    }\n\n    pub fn neverbreak(&mut self) {\n        self.scan_break(BreakToken { never_break: true, ..BreakToken::default() });\n    }\n}\n\nimpl Token {\n    pub(crate) fn is_neverbreak(&self) -> bool {\n        if let Self::Break(BreakToken { never_break, .. }) = *self {\n            return never_break;\n        }\n        false\n    }\n\n    pub(crate) fn is_hardbreak(&self) -> bool {\n        if let Self::Break(BreakToken { blank_space, never_break, .. }) = *self {\n            return blank_space == SIZE_INFINITY as usize && !never_break;\n        }\n        false\n    }\n\n    pub(crate) fn is_space(&self) -> bool {\n        match self {\n            Self::Break(BreakToken { offset, blank_space, .. }) => {\n                *offset == 0 && *blank_space == 1\n            }\n            Self::String(s) => s.ends_with(' '),\n            _ => false,\n        }\n    }\n}\n"
  },
  {
    "path": "crates/fmt/src/pp/helpers.rs",
    "content": "use super::{Printer, Token};\nuse std::borrow::Cow;\n\nimpl Printer {\n    pub fn word_space(&mut self, w: impl Into<Cow<'static, str>>) {\n        self.word(w);\n        self.space();\n    }\n\n    /// Adds a new hardbreak if not at the beginning of the line.\n    /// If there was a buffered break token, replaces it (ensures hardbreak) keeping the offset.\n    pub fn hardbreak_if_not_bol(&mut self) {\n        if !self.is_bol_or_only_ind() {\n            if let Some(Token::Break(last)) = self.last_token_still_buffered()\n                && last.offset != 0\n            {\n                self.replace_last_token_still_buffered(Self::hardbreak_tok_offset(last.offset));\n                return;\n            }\n            self.hardbreak();\n        }\n    }\n\n    pub fn space_if_not_bol(&mut self) {\n        if !self.is_bol_or_only_ind() {\n            self.space();\n        }\n    }\n\n    pub fn nbsp(&mut self) {\n        self.word(\" \");\n    }\n\n    pub fn space_or_nbsp(&mut self, breaks: bool) {\n        if breaks {\n            self.space();\n        } else {\n            self.nbsp();\n        }\n    }\n\n    pub fn word_nbsp(&mut self, w: impl Into<Cow<'static, str>>) {\n        self.word(w);\n        self.nbsp();\n    }\n}\n"
  },
  {
    "path": "crates/fmt/src/pp/mod.rs",
    "content": "//! Adapted from [`rustc_ast_pretty`](https://github.com/rust-lang/rust/blob/07d3fd1d9b9c1f07475b96a9d168564bf528db68/compiler/rustc_ast_pretty/src/pp.rs)\n//! and [`prettyplease`](https://github.com/dtolnay/prettyplease/blob/8eb8c14649aea32e810732bd4d64fe519e6b752a/src/algorithm.rs).\n\nuse crate::{DEBUG, DEBUG_INDENT};\nuse ring::RingBuffer;\nuse std::{borrow::Cow, cmp, collections::VecDeque, iter};\n\nmod convenience;\nmod helpers;\nmod ring;\n\n// Every line is allowed at least this much space, even if highly indented.\nconst MIN_SPACE: isize = 40;\n\n/// How to break. Described in more detail in the module docs.\n#[derive(Clone, Copy, Debug, PartialEq, Eq)]\npub enum Breaks {\n    Consistent,\n    Inconsistent,\n}\n\n#[derive(Clone, Copy, Debug, PartialEq, Eq)]\nenum IndentStyle {\n    /// Vertically aligned under whatever column this block begins at.\n    /// ```ignore\n    /// fn demo(arg1: usize,\n    ///         arg2: usize) {}\n    /// ```\n    Visual,\n    /// Indented relative to the indentation level of the previous line.\n    /// ```ignore\n    /// fn demo(\n    ///     arg1: usize,\n    ///     arg2: usize,\n    /// ) {}\n    /// ```\n    Block { offset: isize },\n}\n\n#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]\npub(crate) struct BreakToken {\n    pub(crate) offset: isize,\n    pub(crate) blank_space: usize,\n    pub(crate) pre_break: Option<&'static str>,\n    pub(crate) post_break: Option<&'static str>,\n    pub(crate) if_nonempty: bool,\n    pub(crate) never_break: bool,\n}\n\n#[derive(Clone, Copy, Debug, PartialEq, Eq)]\npub(crate) struct BeginToken {\n    indent: IndentStyle,\n    breaks: Breaks,\n}\n\n#[derive(Debug, PartialEq, Eq)]\npub(crate) enum Token {\n    // In practice a string token contains either a `&'static str` or a\n    // `String`. `Cow` is overkill for this because we never modify the data,\n    // but it's more convenient than rolling our own more specialized type.\n    String(Cow<'static, str>),\n    Break(BreakToken),\n    Begin(BeginToken),\n    End,\n}\n\n#[derive(Copy, Clone, Debug)]\nenum PrintFrame {\n    Fits(Breaks),\n    Broken(usize, Breaks),\n}\n\npub(crate) const SIZE_INFINITY: isize = 0xffff;\n\n#[derive(Debug)]\npub struct Printer {\n    out: String,\n    /// Number of spaces left on line.\n    space: isize,\n    /// Ring-buffer of tokens and calculated sizes.\n    buf: RingBuffer<BufEntry>,\n    /// Running size of stream \"...left\".\n    left_total: isize,\n    /// Running size of stream \"...right\".\n    right_total: isize,\n    /// Pseudo-stack, really a ring too. Holds the\n    /// primary-ring-buffers index of the Begin that started the\n    /// current block, possibly with the most recent Break after that\n    /// Begin (if there is any) on top of it. Stuff is flushed off the\n    /// bottom as it becomes irrelevant due to the primary ring-buffer\n    /// advancing.\n    scan_stack: VecDeque<usize>,\n    /// Stack of blocks-in-progress being flushed by print.\n    print_stack: Vec<PrintFrame>,\n    /// Level of indentation of current line.\n    indent: usize,\n    /// Buffered indentation to avoid writing trailing whitespace.\n    pending_indentation: usize,\n    /// The token most recently popped from the left boundary of the\n    /// ring-buffer for printing.\n    last_printed: Option<Token>,\n\n    /// Target line width.\n    margin: isize,\n    /// If `Some(tab_width)` the printer will use tabs for indentation.\n    indent_config: Option<usize>,\n}\n\n#[derive(Debug)]\npub struct BufEntry {\n    token: Token,\n    size: isize,\n}\n\nimpl Printer {\n    pub fn new(margin: usize, use_tab_with_size: Option<usize>) -> Self {\n        let margin = (margin as isize).clamp(MIN_SPACE, SIZE_INFINITY - 1);\n        Self {\n            out: String::new(),\n            space: margin,\n            buf: RingBuffer::new(),\n            left_total: 0,\n            right_total: 0,\n            scan_stack: VecDeque::new(),\n            print_stack: Vec::new(),\n            indent: 0,\n            pending_indentation: 0,\n            last_printed: None,\n\n            margin,\n            indent_config: use_tab_with_size,\n        }\n    }\n\n    /// Predicts available space on the current or next line based on pending breaks.\n    ///\n    /// This function provides a heuristic for estimating available space by checking if\n    /// an unconditional hard break is pending in the buffer. The printer's internal\n    /// `self.space` value may not accurately reflect pending formatting decisions.\n    ///\n    /// # Returns\n    ///\n    /// - The full `margin` if an unconditional hard break is pending, signaling that a new line\n    ///   will be created. Callers should apply their own indentation logic as they have more\n    ///   semantic context about the code structure.\n    /// - The current space left (`self.space`) if no hard break is found, which can be trusted when\n    ///   no line breaks are imminent.\n    ///\n    /// # Trade-offs\n    ///\n    /// This heuristic may overestimate available space,\n    /// but provides a reliable signal for hard breaks while keeping the implementation\n    /// simple.\n    pub(crate) fn space_left(&self) -> usize {\n        // Scan backwards through the buffer for the last unconditional hard break.\n        for i in self.buf.index_range().rev() {\n            let token = &self.buf[i].token;\n\n            if let Token::Break(break_token) = token\n                && break_token.blank_space as isize >= SIZE_INFINITY\n                && !break_token.never_break\n            {\n                return self.margin as usize;\n            }\n\n            // Stop at first non-end token.\n            if !matches!(token, Token::End) {\n                break;\n            }\n        }\n\n        // If no hard break pending, return actual space on current line or the full margin if space\n        // is negative.\n        (if self.space < 0 { self.margin } else { self.space }) as usize\n    }\n\n    pub(crate) fn last_token(&self) -> Option<&Token> {\n        self.last_token_still_buffered().or(self.last_printed.as_ref())\n    }\n\n    pub(crate) fn last_token_still_buffered(&self) -> Option<&Token> {\n        if self.buf.is_empty() {\n            return None;\n        }\n        Some(&self.buf.last().token)\n    }\n\n    /// Be very careful with this!\n    pub(crate) fn replace_last_token_still_buffered(&mut self, token: Token) {\n        self.buf.last_mut().token = token;\n    }\n\n    /// WARNING: Be very careful with this!\n    ///\n    /// Searches backwards through the buffer to find and replace the last token\n    /// that satisfies a predicate. This is a specialized and sensitive operation.\n    ///\n    /// This function's traversal logic is specifically designed to handle cases\n    /// where formatting boxes have been closed (e.g., after a multi-line\n    /// comment). It will automatically skip over any trailing `Token::End`\n    /// tokens to find the substantive token before them.\n    ///\n    /// The search stops as soon as it encounters any token other than `End`\n    /// (i.e., a `String`, `Break`, or `Begin`). The provided predicate is then\n    /// called on that token. If the predicate returns `true`, the token is\n    /// replaced.\n    ///\n    /// This function will only ever evaluate the predicate on **one** token.\n    pub(crate) fn find_and_replace_last_token_still_buffered<F>(\n        &mut self,\n        new_token: Token,\n        predicate: F,\n    ) where\n        F: FnOnce(&Token) -> bool,\n    {\n        for i in self.buf.index_range().rev() {\n            let token = &self.buf[i].token;\n            if let Token::End = token {\n                // It's safe to skip the end of a box.\n                continue;\n            }\n\n            // Apply the predicate and return after the first non-end token.\n            if predicate(token) {\n                self.buf[i].token = new_token;\n            }\n            break;\n        }\n    }\n\n    fn scan_eof(&mut self) {\n        if !self.scan_stack.is_empty() {\n            self.check_stack(0);\n            self.advance_left();\n        }\n    }\n\n    fn scan_begin(&mut self, token: BeginToken) {\n        if self.scan_stack.is_empty() {\n            self.left_total = 1;\n            self.right_total = 1;\n            self.buf.clear();\n        }\n        let right = self.buf.push(BufEntry { token: Token::Begin(token), size: -self.right_total });\n        self.scan_stack.push_back(right);\n    }\n\n    fn scan_end(&mut self) {\n        if self.scan_stack.is_empty() {\n            self.print_end();\n        } else {\n            if !self.buf.is_empty()\n                && let Token::Break(break_token) = self.buf.last().token\n            {\n                if self.buf.len() >= 2\n                    && let Token::Begin(_) = self.buf.second_last().token\n                {\n                    self.buf.pop_last();\n                    self.buf.pop_last();\n                    self.scan_stack.pop_back();\n                    self.scan_stack.pop_back();\n                    self.right_total -= break_token.blank_space as isize;\n                    return;\n                }\n                if break_token.if_nonempty {\n                    self.buf.pop_last();\n                    self.scan_stack.pop_back();\n                    self.right_total -= break_token.blank_space as isize;\n                }\n            }\n            let right = self.buf.push(BufEntry { token: Token::End, size: -1 });\n            self.scan_stack.push_back(right);\n        }\n    }\n\n    pub(crate) fn scan_break(&mut self, token: BreakToken) {\n        if self.scan_stack.is_empty() {\n            self.left_total = 1;\n            self.right_total = 1;\n            self.buf.clear();\n        } else {\n            self.check_stack(0);\n        }\n        let right = self.buf.push(BufEntry { token: Token::Break(token), size: -self.right_total });\n        self.scan_stack.push_back(right);\n        self.right_total += token.blank_space as isize;\n    }\n\n    fn scan_string(&mut self, string: Cow<'static, str>) {\n        if self.scan_stack.is_empty() {\n            self.print_string(&string);\n        } else {\n            let len = string.len() as isize;\n            self.buf.push(BufEntry { token: Token::String(string), size: len });\n            self.right_total += len;\n            self.check_stream();\n        }\n    }\n\n    #[track_caller]\n    pub(crate) fn offset(&mut self, offset: isize) {\n        match &mut self.buf.last_mut().token {\n            Token::Break(token) => token.offset += offset,\n            Token::Begin(_) => {}\n            Token::String(_) | Token::End => unreachable!(),\n        }\n    }\n\n    pub(crate) fn ends_with(&self, ch: char) -> bool {\n        for i in self.buf.index_range().rev() {\n            if let Token::String(token) = &self.buf[i].token {\n                return token.ends_with(ch);\n            }\n        }\n        self.out.ends_with(ch)\n    }\n\n    fn check_stream(&mut self) {\n        while self.right_total - self.left_total > self.space {\n            if *self.scan_stack.front().unwrap() == self.buf.index_range().start {\n                self.scan_stack.pop_front().unwrap();\n                self.buf.first_mut().size = SIZE_INFINITY;\n            }\n\n            self.advance_left();\n\n            if self.buf.is_empty() {\n                break;\n            }\n        }\n    }\n\n    fn advance_left(&mut self) {\n        while self.buf.first().size >= 0 {\n            let left = self.buf.pop_first();\n\n            match &left.token {\n                Token::String(string) => {\n                    self.left_total += left.size;\n                    self.print_string(string);\n                }\n                Token::Break(token) => {\n                    self.left_total += token.blank_space as isize;\n                    self.print_break(*token, left.size);\n                }\n                Token::Begin(token) => self.print_begin(*token, left.size),\n                Token::End => self.print_end(),\n            }\n\n            self.last_printed = Some(left.token);\n\n            if self.buf.is_empty() {\n                break;\n            }\n        }\n    }\n\n    fn check_stack(&mut self, mut depth: usize) {\n        while let Some(&index) = self.scan_stack.back() {\n            let entry = &mut self.buf[index];\n            match entry.token {\n                Token::Begin(_) => {\n                    if depth == 0 {\n                        break;\n                    }\n                    self.scan_stack.pop_back().unwrap();\n                    entry.size += self.right_total;\n                    depth -= 1;\n                }\n                Token::End => {\n                    // paper says + not =, but that makes no sense.\n                    self.scan_stack.pop_back().unwrap();\n                    entry.size = 1;\n                    depth += 1;\n                }\n                _ => {\n                    self.scan_stack.pop_back().unwrap();\n                    entry.size += self.right_total;\n                    if depth == 0 {\n                        break;\n                    }\n                }\n            }\n        }\n    }\n\n    fn get_top(&self) -> PrintFrame {\n        self.print_stack.last().copied().unwrap_or(PrintFrame::Broken(0, Breaks::Inconsistent))\n    }\n\n    fn print_begin(&mut self, token: BeginToken, size: isize) {\n        if DEBUG {\n            self.out.push(match token.breaks {\n                Breaks::Consistent => '«',\n                Breaks::Inconsistent => '‹',\n            });\n            if DEBUG_INDENT && let IndentStyle::Block { offset } = token.indent {\n                self.out.extend(offset.to_string().chars().map(|ch| match ch {\n                    '0'..='9' => ['₀', '₁', '₂', '₃', '₄', '₅', '₆', '₇', '₈', '₉']\n                        [(ch as u8 - b'0') as usize],\n                    '-' => '₋',\n                    _ => unreachable!(),\n                }));\n            }\n        }\n\n        if size > self.space {\n            self.print_stack.push(PrintFrame::Broken(self.indent, token.breaks));\n            self.indent = match token.indent {\n                IndentStyle::Block { offset } => {\n                    usize::try_from(self.indent as isize + offset).unwrap()\n                }\n                IndentStyle::Visual => (self.margin - self.space) as usize,\n            };\n        } else {\n            self.print_stack.push(PrintFrame::Fits(token.breaks));\n        }\n    }\n\n    fn print_end(&mut self) {\n        let breaks = match self.print_stack.pop().unwrap() {\n            PrintFrame::Broken(indent, breaks) => {\n                self.indent = indent;\n                breaks\n            }\n            PrintFrame::Fits(breaks) => breaks,\n        };\n        if DEBUG {\n            self.out.push(match breaks {\n                Breaks::Consistent => '»',\n                Breaks::Inconsistent => '›',\n            });\n        }\n    }\n\n    fn print_break(&mut self, token: BreakToken, size: isize) {\n        let fits = token.never_break\n            || match self.get_top() {\n                PrintFrame::Fits(..) => true,\n                PrintFrame::Broken(.., Breaks::Consistent) => false,\n                PrintFrame::Broken(.., Breaks::Inconsistent) => size <= self.space,\n            };\n        if fits {\n            self.pending_indentation += token.blank_space;\n            self.space -= token.blank_space as isize;\n            if DEBUG {\n                self.out.push('·');\n            }\n        } else {\n            if let Some(pre_break) = token.pre_break {\n                self.print_indent();\n                self.out.push_str(pre_break);\n            }\n            if DEBUG {\n                self.out.push('·');\n            }\n            self.out.push('\\n');\n            let indent = self.indent as isize + token.offset;\n            self.pending_indentation = usize::try_from(indent).expect(\"negative indentation\");\n            self.space = cmp::max(self.margin - indent, MIN_SPACE);\n            if let Some(post_break) = token.post_break {\n                self.print_indent();\n                self.out.push_str(post_break);\n                self.space -= post_break.len() as isize;\n            }\n        }\n    }\n\n    fn print_string(&mut self, string: &str) {\n        self.print_indent();\n        self.out.push_str(string);\n        self.space -= string.len() as isize;\n    }\n\n    fn print_indent(&mut self) {\n        self.out.reserve(self.pending_indentation);\n        if let Some(tab_width) = self.indent_config {\n            let num_tabs = self.pending_indentation / tab_width;\n            self.out.extend(iter::repeat_n('\\t', num_tabs));\n\n            let remainder = self.pending_indentation % tab_width;\n            self.out.extend(iter::repeat_n(' ', remainder));\n        } else {\n            self.out.extend(iter::repeat_n(' ', self.pending_indentation));\n        }\n        self.pending_indentation = 0;\n    }\n}\n"
  },
  {
    "path": "crates/fmt/src/pp/ring.rs",
    "content": "use std::{\n    collections::VecDeque,\n    ops::{Index, IndexMut, Range},\n};\n\n#[derive(Debug)]\npub(crate) struct RingBuffer<T> {\n    data: VecDeque<T>,\n    // Abstract index of data[0] in the infinitely sized queue.\n    offset: usize,\n}\n\nimpl<T> RingBuffer<T> {\n    pub(crate) fn new() -> Self {\n        Self { data: VecDeque::new(), offset: 0 }\n    }\n\n    pub(crate) fn is_empty(&self) -> bool {\n        self.data.is_empty()\n    }\n\n    pub(crate) fn len(&self) -> usize {\n        self.data.len()\n    }\n\n    pub(crate) fn push(&mut self, value: T) -> usize {\n        let index = self.offset + self.data.len();\n        self.data.push_back(value);\n        index\n    }\n\n    pub(crate) fn clear(&mut self) {\n        self.data.clear();\n    }\n\n    pub(crate) fn index_range(&self) -> Range<usize> {\n        self.offset..self.offset + self.data.len()\n    }\n\n    #[inline]\n    #[track_caller]\n    pub(crate) fn first(&self) -> &T {\n        &self.data[0]\n    }\n\n    #[inline]\n    #[track_caller]\n    pub(crate) fn first_mut(&mut self) -> &mut T {\n        &mut self.data[0]\n    }\n\n    #[inline]\n    #[track_caller]\n    pub(crate) fn pop_first(&mut self) -> T {\n        self.offset += 1;\n        self.data.pop_front().unwrap()\n    }\n\n    #[inline]\n    #[track_caller]\n    pub(crate) fn last(&self) -> &T {\n        self.data.back().unwrap()\n    }\n\n    #[inline]\n    #[track_caller]\n    pub(crate) fn last_mut(&mut self) -> &mut T {\n        self.data.back_mut().unwrap()\n    }\n\n    #[inline]\n    #[track_caller]\n    pub(crate) fn second_last(&self) -> &T {\n        &self.data[self.data.len() - 2]\n    }\n\n    #[inline]\n    #[track_caller]\n    pub(crate) fn pop_last(&mut self) {\n        self.data.pop_back().unwrap();\n    }\n}\n\nimpl<T> Index<usize> for RingBuffer<T> {\n    type Output = T;\n    fn index(&self, index: usize) -> &Self::Output {\n        &self.data[index.checked_sub(self.offset).unwrap()]\n    }\n}\n\nimpl<T> IndexMut<usize> for RingBuffer<T> {\n    fn index_mut(&mut self, index: usize) -> &mut Self::Output {\n        &mut self.data[index.checked_sub(self.offset).unwrap()]\n    }\n}\n"
  },
  {
    "path": "crates/fmt/src/state/common.rs",
    "content": "use super::{CommentConfig, Separator, State};\nuse crate::pp::{BreakToken, Printer, SIZE_INFINITY};\nuse foundry_common::iter::IterDelimited;\nuse foundry_config::fmt as config;\nuse itertools::{Either, Itertools};\nuse solar::parse::{\n    Cursor,\n    ast::{self, Span},\n    interface::BytePos,\n};\nuse std::{borrow::Cow, fmt::Debug};\n\npub(crate) trait LitExt<'ast> {\n    fn is_str_concatenation(&self) -> bool;\n}\n\nimpl<'ast> LitExt<'ast> for ast::Lit<'ast> {\n    /// Checks if a the input literal is a string literal with multiple parts.\n    fn is_str_concatenation(&self) -> bool {\n        if let ast::LitKind::Str(_, _, parts) = &self.kind { !parts.is_empty() } else { false }\n    }\n}\n\n/// Language-specific pretty printing. Common for both: Solidity + Yul.\nimpl<'ast> State<'_, 'ast> {\n    pub(super) fn print_lit_inner(&mut self, lit: &'ast ast::Lit<'ast>, is_yul: bool) {\n        let ast::Lit { span, symbol, ref kind } = *lit;\n        if self.handle_span(span, false) {\n            return;\n        }\n\n        match *kind {\n            ast::LitKind::Str(kind, ..) => {\n                self.s.ibox(0);\n                for (pos, (span, symbol)) in lit.literals().delimited() {\n                    if !self.handle_span(span, false) {\n                        let quote_pos = span.lo() + kind.prefix().len() as u32;\n                        self.print_str_lit(kind, quote_pos, symbol.as_str());\n                    }\n                    if !pos.is_last {\n                        if !self.print_trailing_comment(span.hi(), None) {\n                            self.space_if_not_bol();\n                        }\n                    } else {\n                        self.neverbreak();\n                    }\n                }\n                self.end();\n            }\n            ast::LitKind::Number(_) | ast::LitKind::Rational(_) => {\n                self.print_num_literal(symbol.as_str(), is_yul);\n            }\n            ast::LitKind::Address(value) => self.word(value.to_string()),\n            ast::LitKind::Bool(value) => self.word(if value { \"true\" } else { \"false\" }),\n            ast::LitKind::Err(_) => self.word(symbol.to_string()),\n        }\n    }\n\n    fn print_num_literal(&mut self, source: &str, is_yul: bool) {\n        fn strip_underscores_if(b: bool, s: &str) -> Cow<'_, str> {\n            if b && s.contains('_') { Cow::Owned(s.replace('_', \"\")) } else { Cow::Borrowed(s) }\n        }\n\n        fn add_underscores(\n            out: &mut String,\n            config: config::NumberUnderscore,\n            string: &str,\n            is_dec: bool,\n            is_yul: bool,\n            reversed: bool,\n        ) {\n            // The underscore thousand separator is only valid in Solidity decimal numbers.\n            // It is not supported by hex numbers, nor Yul literals.\n            // https://github.com/foundry-rs/foundry/issues/12111\n            if !config.is_thousands() || !is_dec || is_yul || string.len() < 5 {\n                out.push_str(string);\n                return;\n            }\n\n            let chunks = if reversed {\n                Either::Left(string.as_bytes().chunks(3))\n            } else {\n                Either::Right(string.as_bytes().rchunks(3).rev())\n            }\n            .map(|chunk| std::str::from_utf8(chunk).unwrap());\n            for chunk in Itertools::intersperse(chunks, \"_\") {\n                out.push_str(chunk);\n            }\n        }\n\n        debug_assert!(source.is_ascii(), \"{source:?}\");\n\n        let config = self.config.number_underscore;\n        let is_dec = ![\"0x\", \"0b\", \"0o\"].iter().any(|prefix| source.starts_with(prefix));\n\n        let (val, exp) = if !is_dec {\n            (source, \"\")\n        } else {\n            source.split_once(['e', 'E']).unwrap_or((source, \"\"))\n        };\n        let (val, fract) = val.split_once('.').unwrap_or((val, \"\"));\n\n        let strip_underscores = !config.is_preserve() || is_yul;\n        let mut val = &strip_underscores_if(strip_underscores, val)[..];\n        let mut exp = &strip_underscores_if(strip_underscores, exp)[..];\n        let mut fract = &strip_underscores_if(strip_underscores, fract)[..];\n\n        // strip any padded 0's\n        let mut exp_sign = \"\";\n        if is_dec {\n            val = val.trim_start_matches('0');\n            fract = fract.trim_end_matches('0');\n            (exp_sign, exp) =\n                if let Some(exp) = exp.strip_prefix('-') { (\"-\", exp) } else { (\"\", exp) };\n            exp = exp.trim_start_matches('0');\n        }\n\n        let mut out = String::with_capacity(source.len() * 2);\n        if val.is_empty() {\n            out.push('0');\n        } else {\n            add_underscores(&mut out, config, val, is_dec, is_yul, false);\n        }\n        if source.contains('.') {\n            out.push('.');\n            match (fract.is_empty(), exp.is_empty()) {\n                // `X.YeZ`: keep as is\n                (false, false) => out.push_str(fract),\n                // `X.Y`\n                (false, true) => add_underscores(&mut out, config, fract, is_dec, is_yul, true),\n                // `X.` -> `X.0`\n                (true, _) => out.push('0'),\n            };\n        }\n        if !exp.is_empty() {\n            out.push('e');\n            out.push_str(exp_sign);\n            add_underscores(&mut out, config, exp, is_dec, is_yul, false);\n        }\n\n        self.word(out);\n    }\n\n    /// `s` should be the *unescaped contents of the string literal*.\n    pub(super) fn print_str_lit(&mut self, kind: ast::StrKind, quote_pos: BytePos, s: &str) {\n        self.print_comments(quote_pos, CommentConfig::default());\n        let s = self.str_lit_to_string(kind, quote_pos, s);\n        self.word(s);\n    }\n\n    /// `s` should be the *unescaped contents of the string literal*.\n    fn str_lit_to_string(&self, kind: ast::StrKind, quote_pos: BytePos, s: &str) -> String {\n        let prefix = kind.prefix();\n        let quote = match self.config.quote_style {\n            config::QuoteStyle::Double => '\\\"',\n            config::QuoteStyle::Single => '\\'',\n            config::QuoteStyle::Preserve => self.char_at(quote_pos).unwrap_or_default(),\n        };\n        debug_assert!(matches!(quote, '\\\"' | '\\''), \"{quote:?}\");\n        let s = solar::parse::interface::data_structures::fmt::from_fn(move |f| {\n            if matches!(kind, ast::StrKind::Hex) {\n                match self.config.hex_underscore {\n                    config::HexUnderscore::Preserve => {}\n                    config::HexUnderscore::Remove | config::HexUnderscore::Bytes => {\n                        let mut clean = s.to_string().replace('_', \"\");\n                        if matches!(self.config.hex_underscore, config::HexUnderscore::Bytes) {\n                            clean =\n                                clean.chars().chunks(2).into_iter().map(|c| c.format(\"\")).join(\"_\");\n                        }\n                        return f.write_str(&clean);\n                    }\n                };\n            }\n            f.write_str(s)\n        });\n        let mut s = format!(\"{prefix}{quote}{s}{quote}\");\n\n        // If the output is not a single token then revert to the original quote.\n        #[allow(unstable_name_collisions)]\n        if Cursor::new(&s).exactly_one().is_err() {\n            let other_quote = if quote == '\\\"' { '\\'' } else { '\\\"' };\n            {\n                let s = unsafe { s.as_bytes_mut() };\n                s[prefix.len()] = other_quote as u8;\n                s[s.len() - 1] = other_quote as u8;\n            }\n            debug_assert!(Cursor::new(&s).exactly_one().map(|_| true).unwrap());\n        }\n\n        s\n    }\n\n    pub(super) fn print_tuple_empty(&mut self, pos_lo: BytePos, pos_hi: BytePos) {\n        if self.handle_span(Span::new(pos_lo, pos_hi), true) {\n            return;\n        }\n\n        self.print_inside_parens(|state| {\n            state.s.cbox(state.ind);\n            if let Some(cmnt) =\n                state.print_comments(pos_hi, CommentConfig::skip_ws().mixed_prev_space())\n            {\n                if cmnt.is_mixed() {\n                    state.s.offset(-state.ind);\n                } else {\n                    state.break_offset_if_not_bol(0, -state.ind, false);\n                }\n            }\n            state.end();\n        });\n    }\n\n    pub(super) fn print_tuple<'a, T, P, S>(\n        &mut self,\n        values: &'a [T],\n        pos_lo: BytePos,\n        pos_hi: BytePos,\n        mut print: P,\n        mut get_span: S,\n        format: ListFormat,\n    ) where\n        P: FnMut(&mut Self, &'a T),\n        S: FnMut(&T) -> Span,\n    {\n        if self.handle_span(Span::new(pos_lo, pos_hi), true) {\n            return;\n        }\n\n        if values.is_empty() {\n            self.print_tuple_empty(pos_lo, pos_hi);\n            return;\n        }\n\n        if !(values.len() == 1 && format.is_inline()) {\n            // Use commasep\n            self.print_inside_parens(|state| {\n                state.commasep(values, pos_lo, pos_hi, print, get_span, format)\n            });\n            return;\n        }\n\n        // Format single-item inline lists directly without boxes\n        self.print_inside_parens(|state| {\n            let span = get_span(&values[0]);\n            state.s.cbox(state.ind);\n            let mut skip_break = true;\n            if state.peek_comment_before(span.hi()).is_some() {\n                state.hardbreak();\n                skip_break = false;\n            }\n\n            state.print_comments(span.lo(), CommentConfig::skip_ws().mixed_prev_space());\n            print(state, &values[0]);\n\n            if !state.print_trailing_comment(span.hi(), None) && skip_break {\n                state.neverbreak();\n            } else {\n                state.break_offset_if_not_bol(0, -state.ind, false);\n            }\n            state.end();\n        });\n    }\n\n    pub(super) fn print_array<'a, T, P, S>(\n        &mut self,\n        values: &'a [T],\n        span: Span,\n        print: P,\n        get_span: S,\n    ) where\n        P: FnMut(&mut Self, &'a T),\n        S: FnMut(&T) -> Span,\n    {\n        if self.handle_span(span, false) {\n            return;\n        }\n\n        self.print_word(\"[\");\n        self.commasep(values, span.lo(), span.hi(), print, get_span, ListFormat::compact());\n        self.print_word(\"]\");\n    }\n\n    pub(super) fn commasep_opening_logic<T, S>(\n        &mut self,\n        values: &[T],\n        mut get_span: S,\n        format: ListFormat,\n        manual_opening: bool,\n    ) -> bool\n    where\n        S: FnMut(&T) -> Span,\n    {\n        let Some(span) = values.first().map(&mut get_span) else {\n            return false;\n        };\n\n        // If first item is uninformed (just a comma), and it has its own comment, skip it.\n        // It will be dealt with when printing the item in the main loop of `commasep`.\n        if span.is_dummy()\n            && let Some(next_pos) = values.get(1).map(|v| get_span(v).lo())\n            && self.peek_comment_before(next_pos).is_some()\n        {\n            return true;\n        }\n\n        // Check for comments before the first item.\n        if let Some((cmnt_span, cmnt_style)) =\n            self.peek_comment_before(span.lo()).map(|c| (c.span, c.style))\n        {\n            let cmnt_disabled = self.inline_config.is_disabled(cmnt_span);\n            // Handle special formatting for disabled code with isolated comments.\n            if self.cursor.enabled && cmnt_disabled && cmnt_style.is_isolated() {\n                self.print_sep(Separator::Hardbreak);\n                if !format.with_delimiters {\n                    self.s.offset(self.ind);\n                }\n            };\n\n            // If manual opening flag is passed, we simply force the break, and skip the comment.\n            // It will be dealt with when printing the item in the main loop of `commasep`.\n            if manual_opening {\n                self.hardbreak();\n                self.s.offset(self.ind);\n                return true;\n            }\n\n            let cmnt_config = if format.with_delimiters {\n                CommentConfig::skip_ws().mixed_no_break().mixed_prev_space()\n            } else {\n                CommentConfig::skip_ws().no_breaks().mixed_prev_space().offset(self.ind)\n            };\n            // Apply spacing based on comment styles.\n            if let Some(last_style) = self.print_comments(span.lo(), cmnt_config) {\n                match (cmnt_style.is_mixed(), last_style.is_mixed()) {\n                    (true, true) => {\n                        if format.breaks_cmnts {\n                            self.hardbreak();\n                        } else {\n                            self.space();\n                        }\n                        if !format.with_delimiters && !cmnt_disabled {\n                            self.s.offset(self.ind);\n                        }\n                    }\n                    (false, true) => {\n                        self.nbsp();\n                    }\n                    (false, false) if !format.with_delimiters && !cmnt_disabled => {\n                        self.hardbreak();\n                        self.s.offset(self.ind);\n                    }\n                    _ => {}\n                }\n            }\n            if self.cursor.enabled {\n                self.cursor.advance_to(span.lo(), true);\n            }\n            return true;\n        }\n\n        if self.cursor.enabled {\n            self.cursor.advance_to(span.lo(), true);\n        }\n\n        if !values.is_empty() && !format.with_delimiters {\n            format.print_break(true, values.len(), &mut self.s);\n            self.s.offset(self.ind);\n            return true;\n        }\n\n        false\n    }\n\n    pub(super) fn commasep<'a, T, P, S>(\n        &mut self,\n        values: &'a [T],\n        _pos_lo: BytePos,\n        pos_hi: BytePos,\n        mut print: P,\n        mut get_span: S,\n        format: ListFormat,\n    ) where\n        P: FnMut(&mut Self, &'a T),\n        S: FnMut(&T) -> Span,\n    {\n        if values.is_empty() {\n            return;\n        }\n\n        // We can't simply check `peek_comment_before(pos_hi)` cause we would also account for\n        // comments in the child expression, and those don't matter.\n        let has_comments =\n            // check for comments before the first element\n            self.peek_comment_before(get_span(&values[0]).lo()).is_some() ||\n            // check for comments between elements\n            values.windows(2).any(|w| self.peek_comment_between(get_span(&w[0]).hi(), get_span(&w[1]).lo()).is_some()) ||\n            // check for comments after the last element\n            self.peek_comment_between(get_span(values.last().unwrap()).hi(), pos_hi).is_some();\n\n        // For calls with opts and args, which should break consistently, we need to skip the\n        // wrapping cbox to prioritize call args breaking before the call opts. Because of that, we\n        // must manually offset the breaks between args, so that they are properly indented.\n        let manual_opening =\n            format.is_consistent() && !format.with_delimiters && self.call_with_opts_and_args;\n        // When there are comments, we can preserve the cbox, as they will make it break\n        let manual_offset = !has_comments && manual_opening;\n\n        let is_single_without_cmnts = values.len() == 1 && !format.break_single && !has_comments;\n        let skip_first_break = if format.with_delimiters || format.is_inline() {\n            self.s.cbox(if format.no_ind { 0 } else { self.ind });\n            if is_single_without_cmnts {\n                true\n            } else {\n                self.commasep_opening_logic(values, &mut get_span, format, manual_opening)\n            }\n        } else {\n            let res = self.commasep_opening_logic(values, &mut get_span, format, manual_opening);\n            if !manual_offset {\n                self.s.cbox(if format.no_ind { 0 } else { self.ind });\n            }\n            res\n        };\n\n        if let Some(sym) = format.prev_symbol() {\n            self.word_space(sym);\n        } else if is_single_without_cmnts && format.with_space {\n            self.nbsp();\n        } else if !skip_first_break && !format.is_inline() {\n            format.print_break(true, values.len(), &mut self.s);\n            if manual_offset {\n                self.s.offset(self.ind);\n            }\n        }\n\n        if format.is_compact() && !(format.breaks_with_comments() && has_comments) {\n            self.s.cbox(0);\n        }\n\n        let mut last_delimiter_break = !format.with_delimiters;\n        let mut skip_last_break =\n            is_single_without_cmnts || !format.with_delimiters || format.is_inline();\n        for (i, value) in values.iter().enumerate() {\n            let is_last = i == values.len() - 1;\n            if self\n                .print_comments(get_span(value).lo(), CommentConfig::skip_ws().mixed_prev_space())\n                .is_some_and(|cmnt| cmnt.is_mixed())\n                && format.breaks_cmnts\n            {\n                self.hardbreak(); // trailing and isolated comments already hardbreak\n            }\n\n            // Avoid printing the last uninformed item, so that we can handle line breaks.\n            if !(is_last && get_span(value).is_dummy()) {\n                print(self, value);\n            }\n\n            let next_span = if is_last { None } else { Some(get_span(&values[i + 1])) };\n            let next_pos = next_span.map(Span::lo).unwrap_or(pos_hi);\n            let cmnt_before_next =\n                self.peek_comment_before(next_pos).map(|cmnt| (cmnt.span, cmnt.style));\n\n            if !is_last {\n                // Handle disabled lines with comments after the value, but before the comma.\n                if cmnt_before_next.is_some_and(|(cmnt_span, _)| {\n                    let span = self.cursor.span(cmnt_span.lo());\n                    self.inline_config.is_disabled(span)\n                        // NOTE: necessary workaround to patch this edgecase due to lack of spans for the commas.\n                        && self.sm.span_to_snippet(span).is_ok_and(|snip| !snip.contains(','))\n                }) {\n                    self.print_comments(\n                        next_pos,\n                        CommentConfig::skip_ws().mixed_no_break().mixed_prev_space(),\n                    );\n                }\n                self.print_word(\",\");\n            }\n\n            if !is_last\n                && format.breaks_cmnts\n                && cmnt_before_next.is_some_and(|(cmnt_span, cmnt_style)| {\n                    let disabled = self.inline_config.is_disabled(cmnt_span);\n                    (cmnt_style.is_mixed() && !disabled) || (cmnt_style.is_isolated() && disabled)\n                })\n            {\n                self.hardbreak(); // trailing and isolated comments already hardbreak\n            }\n\n            // Print trailing comments.\n            let comment_config = if !is_last || format.with_delimiters {\n                CommentConfig::skip_ws().mixed_no_break().mixed_prev_space()\n            } else {\n                CommentConfig::skip_ws().no_breaks().mixed_prev_space()\n            };\n            let with_trailing = self.print_comments(next_pos, comment_config).is_some();\n\n            if is_last && with_trailing {\n                if self.is_bol_or_only_ind() {\n                    // if a trailing comment is printed at the very end, we have to manually adjust\n                    // the offset to avoid having a double break.\n                    self.break_offset_if_not_bol(0, -self.ind, false);\n                } else {\n                    self.s.break_offset(SIZE_INFINITY as usize, -self.ind);\n                }\n                skip_last_break = true;\n                last_delimiter_break = false;\n            }\n\n            // Final break if needed before the next value.\n            if let Some(next_span) = next_span\n                && !self.is_bol_or_only_ind()\n                && !self.inline_config.is_disabled(next_span)\n                && !next_span.is_dummy()\n            {\n                format.print_break(false, values.len(), &mut self.s);\n                if manual_offset {\n                    self.s.offset(self.ind);\n                }\n            }\n        }\n\n        if format.is_compact() && !(format.breaks_with_comments() && has_comments) {\n            self.end();\n        }\n        if !skip_last_break {\n            if let Some(sym) = format.post_symbol() {\n                format.print_break(false, values.len(), &mut self.s);\n                self.s.offset(-self.ind);\n                self.word(sym);\n            } else {\n                format.print_break(true, values.len(), &mut self.s);\n                self.s.offset(-self.ind);\n            }\n        } else if is_single_without_cmnts && format.with_space {\n            self.nbsp();\n        } else if let Some(sym) = format.post_symbol() {\n            self.nbsp();\n            self.word(sym);\n        }\n\n        if !manual_offset {\n            self.end();\n        }\n        self.cursor.advance_to(pos_hi, true);\n\n        if last_delimiter_break {\n            format.print_break(true, values.len(), &mut self.s);\n        }\n    }\n\n    pub(super) fn print_path(&mut self, path: &'ast ast::PathSlice, consistent_break: bool) {\n        if consistent_break {\n            self.s.cbox(self.ind);\n        } else {\n            self.s.ibox(self.ind);\n        }\n        for (pos, ident) in path.segments().iter().delimited() {\n            self.print_ident(ident);\n            if !pos.is_last {\n                if !self.emit_or_revert {\n                    self.zerobreak();\n                }\n                self.word(\".\");\n            }\n        }\n        self.end();\n    }\n\n    pub(super) fn print_block_inner<T: Debug>(\n        &mut self,\n        block: &'ast [T],\n        block_format: BlockFormat,\n        mut print: impl FnMut(&mut Self, &'ast T),\n        mut get_block_span: impl FnMut(&'ast T) -> Span,\n        pos_hi: BytePos,\n    ) {\n        // Attempt to print in a single line.\n        if block_format.attempt_single_line() && block.len() == 1 {\n            self.print_single_line_block(block, block_format, print, get_block_span);\n            return;\n        }\n\n        // Empty blocks with comments require special attention.\n        if block.is_empty() {\n            self.print_empty_block(block_format, pos_hi);\n            return;\n        }\n\n        // update block depth\n        self.block_depth += 1;\n\n        // Print multiline block comments.\n        let block_lo = get_block_span(&block[0]).lo();\n        match block_format {\n            BlockFormat::NoBraces(None) => {\n                if !self.handle_span(self.cursor.span(block_lo), false) {\n                    self.print_comments(block_lo, CommentConfig::default());\n                }\n                self.s.cbox(0);\n            }\n            BlockFormat::NoBraces(Some(offset)) => {\n                let enabled =\n                    !self.inline_config.is_disabled(Span::new(block_lo, block_lo + BytePos(1)))\n                        && !self.handle_span(self.cursor.span(block_lo), true);\n                match self.peek_comment().and_then(|cmnt| {\n                    if cmnt.span.hi() < block_lo { Some((cmnt.span, cmnt.style)) } else { None }\n                }) {\n                    Some((span, style)) => {\n                        if enabled {\n                            // Inline config is not disabled and span not handled\n                            if !self.inline_config.is_disabled(span) || style.is_isolated() {\n                                self.cursor.advance_to(span.lo(), true);\n                                self.break_offset(SIZE_INFINITY as usize, offset);\n                            }\n                            if let Some(cmnt) = self.print_comments(\n                                block_lo,\n                                CommentConfig::skip_leading_ws(false).offset(offset),\n                            ) && !cmnt.is_mixed()\n                                && !cmnt.is_blank()\n                            {\n                                self.s.offset(offset);\n                            }\n                        } else if style.is_isolated() {\n                            self.print_sep_unhandled(Separator::Hardbreak);\n                            self.s.offset(offset);\n                        }\n                    }\n                    None => {\n                        if enabled {\n                            self.zerobreak();\n                            self.s.offset(offset);\n                        } else if self.cursor.enabled {\n                            self.print_sep_unhandled(Separator::Space);\n                            self.s.offset(offset);\n                            self.cursor.advance_to(block_lo, true);\n                        }\n                    }\n                }\n                self.s.cbox(self.ind);\n            }\n            _ => {\n                self.print_word(\"{\");\n                self.s.cbox(self.ind);\n                if !self.handle_span(self.cursor.span(block_lo), false)\n                    && self\n                        .print_comments(block_lo, CommentConfig::default())\n                        .is_none_or(|cmnt| cmnt.is_mixed())\n                {\n                    self.hardbreak_if_nonempty();\n                }\n            }\n        }\n\n        // Print multiline block statements.\n        for (i, stmt) in block.iter().enumerate() {\n            let is_last = i == block.len() - 1;\n            print(self, stmt);\n\n            let is_disabled = self.inline_config.is_disabled(get_block_span(stmt));\n            let mut next_enabled = false;\n            let mut next_lo = None;\n            if !is_last {\n                let next_span = get_block_span(&block[i + 1]);\n                next_enabled = !self.inline_config.is_disabled(next_span);\n                next_lo =\n                    self.peek_comment_before(next_span.lo()).is_none().then_some(next_span.lo());\n            }\n\n            // when this stmt and the next one are enabled, break normally (except if last stmt)\n            if !is_disabled\n                && next_enabled\n                && (!is_last\n                    || self.peek_comment_before(pos_hi).is_some_and(|cmnt| cmnt.style.is_mixed()))\n            {\n                self.hardbreak_if_not_bol();\n                continue;\n            }\n            // when this stmt is disabled and the next one is enabled, break if there is no\n            // enabled preceding comment. Otherwise the breakpoint is handled by the comment.\n            if is_disabled\n                && next_enabled\n                && let Some(next_lo) = next_lo\n                && self\n                    .peek_comment_before(next_lo)\n                    .is_none_or(|cmnt| self.inline_config.is_disabled(cmnt.span))\n            {\n                self.hardbreak_if_not_bol()\n            }\n        }\n\n        self.print_comments(\n            pos_hi,\n            CommentConfig::skip_trailing_ws().mixed_no_break().mixed_prev_space(),\n        );\n        if !block_format.breaks() {\n            if !self.last_token_is_break() {\n                self.hardbreak();\n            }\n            self.s.offset(-self.ind);\n        }\n        self.end();\n        if block_format.with_braces() {\n            self.print_word(\"}\");\n        }\n\n        // restore block depth\n        self.block_depth -= 1;\n    }\n\n    fn print_single_line_block<T: Debug>(\n        &mut self,\n        block: &'ast [T],\n        block_format: BlockFormat,\n        mut print: impl FnMut(&mut Self, &'ast T),\n        mut get_block_span: impl FnMut(&'ast T) -> Span,\n    ) {\n        self.s.cbox(self.ind);\n\n        match block_format {\n            BlockFormat::Compact(true) => {\n                self.scan_break(BreakToken { pre_break: Some(\"{\"), ..Default::default() });\n                print(self, &block[0]);\n                self.print_comments(get_block_span(&block[0]).hi(), CommentConfig::default());\n                self.s.scan_break(BreakToken { post_break: Some(\"}\"), ..Default::default() });\n                self.s.offset(-self.ind);\n            }\n            _ => {\n                self.word(\"{\");\n                self.space();\n                print(self, &block[0]);\n                self.print_comments(get_block_span(&block[0]).hi(), CommentConfig::default());\n                self.space_if_not_bol();\n                self.s.offset(-self.ind);\n                self.word(\"}\");\n            }\n        }\n\n        self.end();\n    }\n\n    fn print_empty_block(&mut self, block_format: BlockFormat, pos_hi: BytePos) {\n        let has_braces = block_format.with_braces();\n\n        // Trailing comments are printed after the block\n        if self.peek_comment_before(pos_hi).is_none_or(|c| c.style.is_trailing()) {\n            if self.config.bracket_spacing {\n                if has_braces {\n                    self.word(\"{ }\");\n                } else {\n                    self.nbsp();\n                }\n            } else if has_braces {\n                self.word(\"{}\");\n            }\n            self.print_comments(pos_hi, CommentConfig::skip_ws());\n            return;\n        }\n\n        // Non-trailing or mixed comments - print inside block\n        if has_braces {\n            self.word(\"{\");\n        }\n        let mut offset = 0;\n        if let BlockFormat::NoBraces(Some(off)) = block_format {\n            offset = off;\n        }\n        self.print_comments(\n            pos_hi,\n            self.cmnt_config().offset(offset).mixed_no_break().mixed_prev_space().mixed_post_nbsp(),\n        );\n        self.print_comments(\n            pos_hi,\n            CommentConfig::default().mixed_no_break().mixed_prev_space().mixed_post_nbsp(),\n        );\n        if has_braces {\n            self.word(\"}\");\n        }\n    }\n}\n\n/// Formatting style for comma-separated lists.\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\npub(crate) struct ListFormat {\n    /// The core formatting strategy.\n    kind: ListFormatKind,\n    /// If `true`, it means that the list already carries indentation.\n    no_ind: bool,\n    /// If `true`, a single-element list may break.\n    break_single: bool,\n    /// If `true`, a comment within the list forces a break.\n    breaks_cmnts: bool,\n    /// If `true`, a space is added after the opening delimiter and before the closing one.\n    with_space: bool,\n    /// If `true`, the list is enclosed in delimiters.\n    with_delimiters: bool,\n}\n\n/// The kind of formatting style for a list.\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\npub(crate) enum ListFormatKind {\n    /// Always breaks for multiple elements.\n    AlwaysBreak,\n    /// Breaks all elements if any break.\n    Consistent,\n    /// Attempts to fit all elements in one line, before breaking consistently.\n    Compact,\n    /// The list is printed inline, without breaks.\n    Inline,\n    /// Special formatting for Yul return values.\n    Yul { sym_prev: Option<&'static str>, sym_post: Option<&'static str> },\n}\n\nimpl Default for ListFormat {\n    fn default() -> Self {\n        Self {\n            kind: ListFormatKind::Consistent,\n            no_ind: false,\n            break_single: false,\n            breaks_cmnts: false,\n            with_space: false,\n            with_delimiters: true,\n        }\n    }\n}\n\nimpl ListFormat {\n    // -- GETTER METHODS -------------------------------------------------------\n    pub(crate) fn prev_symbol(&self) -> Option<&'static str> {\n        if let ListFormatKind::Yul { sym_prev, .. } = self.kind { sym_prev } else { None }\n    }\n\n    pub(crate) fn post_symbol(&self) -> Option<&'static str> {\n        if let ListFormatKind::Yul { sym_post, .. } = self.kind { sym_post } else { None }\n    }\n\n    pub(crate) fn is_consistent(&self) -> bool {\n        matches!(self.kind, ListFormatKind::Consistent)\n    }\n\n    pub(crate) fn is_compact(&self) -> bool {\n        matches!(self.kind, ListFormatKind::Compact)\n    }\n\n    pub(crate) fn is_inline(&self) -> bool {\n        matches!(self.kind, ListFormatKind::Inline)\n    }\n\n    pub(crate) fn breaks_with_comments(&self) -> bool {\n        self.breaks_cmnts\n    }\n\n    // -- BUILDER METHODS ------------------------------------------------------\n    pub(crate) fn inline() -> Self {\n        Self { kind: ListFormatKind::Inline, ..Default::default() }\n    }\n\n    pub(crate) fn consistent() -> Self {\n        Self { kind: ListFormatKind::Consistent, ..Default::default() }\n    }\n\n    pub(crate) fn compact() -> Self {\n        Self { kind: ListFormatKind::Compact, ..Default::default() }\n    }\n\n    pub(crate) fn always_break() -> Self {\n        Self {\n            kind: ListFormatKind::AlwaysBreak,\n            breaks_cmnts: true,\n            break_single: true,\n            with_delimiters: true,\n            ..Default::default()\n        }\n    }\n\n    pub(crate) fn yul(sym_prev: Option<&'static str>, sym_post: Option<&'static str>) -> Self {\n        Self {\n            kind: ListFormatKind::Yul { sym_prev, sym_post },\n            breaks_cmnts: true,\n            with_delimiters: true,\n            ..Default::default()\n        }\n    }\n\n    pub(crate) fn without_ind(mut self, without: bool) -> Self {\n        if !matches!(self.kind, ListFormatKind::Inline) {\n            self.no_ind = without;\n        }\n        self\n    }\n\n    pub(crate) fn break_single(mut self, value: bool) -> Self {\n        if !matches!(self.kind, ListFormatKind::Inline) {\n            self.break_single = value;\n        }\n        self\n    }\n\n    pub(crate) fn break_cmnts(mut self) -> Self {\n        if !matches!(self.kind, ListFormatKind::Inline) {\n            self.breaks_cmnts = true;\n        }\n        self\n    }\n\n    pub(crate) fn with_space(mut self) -> Self {\n        if !matches!(self.kind, ListFormatKind::Inline) {\n            self.with_space = true;\n        }\n        self\n    }\n\n    pub(crate) fn with_delimiters(mut self, with: bool) -> Self {\n        if matches!(self.kind, ListFormatKind::Compact | ListFormatKind::Consistent) {\n            self.with_delimiters = with;\n        }\n        self\n    }\n\n    // -- PRINTER METHODS ------------------------------------------------------\n    pub(crate) fn print_break(&self, soft: bool, elems: usize, p: &mut Printer) {\n        match self.kind {\n            ListFormatKind::Inline => p.nbsp(), // CAREFUL: we can't use `pp.offset()` afterwards\n            ListFormatKind::AlwaysBreak if elems > 1 || (self.break_single && elems == 1) => {\n                p.hardbreak()\n            }\n            _ => {\n                if soft && !self.with_space {\n                    p.zerobreak();\n                } else {\n                    p.space();\n                }\n            }\n        }\n    }\n}\n\n/// Formatting style for code blocks\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\n#[expect(dead_code)]\npub(crate) enum BlockFormat {\n    Regular,\n    /// Attempts to fit all elements in one line, before breaking consistently. Flags whether to\n    /// use braces or not.\n    Compact(bool),\n    /// Doesn't print braces. Flags the offset that should be applied before opening the block box.\n    /// Useful when the caller needs to manually handle the braces.\n    NoBraces(Option<isize>),\n}\n\nimpl BlockFormat {\n    pub(crate) fn with_braces(&self) -> bool {\n        !matches!(self, Self::NoBraces(_))\n    }\n    pub(crate) fn breaks(&self) -> bool {\n        matches!(self, Self::NoBraces(None))\n    }\n\n    pub(crate) fn attempt_single_line(&self) -> bool {\n        matches!(self, Self::Compact(_))\n    }\n}\n"
  },
  {
    "path": "crates/fmt/src/state/mod.rs",
    "content": "#![allow(clippy::too_many_arguments)]\nuse crate::{\n    FormatterConfig, InlineConfig,\n    pp::{self, BreakToken, SIZE_INFINITY, Token},\n    state::sol::BinOpGroup,\n};\nuse foundry_common::{\n    comments::{Comment, CommentStyle, Comments, estimate_line_width, line_with_tabs},\n    iter::IterDelimited,\n};\nuse foundry_config::fmt::{DocCommentStyle, IndentStyle};\nuse solar::parse::{\n    ast::{self, Span},\n    interface::{BytePos, SourceMap},\n    token,\n};\nuse std::{borrow::Cow, ops::Deref, sync::Arc};\n\nmod common;\nmod sol;\nmod yul;\n\n/// Specifies the nature of a complex call.\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\npub(super) enum CallContextKind {\n    /// A chained method call, `a().b()`.\n    Chained,\n\n    /// A nested function call, `a(b())`.\n    Nested,\n}\n\n/// Formatting context for a call expression.\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\npub(super) struct CallContext {\n    /// The kind call.\n    pub(super) kind: CallContextKind,\n\n    /// The size of the callee's head, excluding its arguments.\n    pub(super) size: usize,\n\n    /// Whether this chain context added its own indentation box.\n    pub(super) has_indent: bool,\n}\n\nimpl CallContext {\n    pub(super) fn nested(size: usize) -> Self {\n        Self { kind: CallContextKind::Nested, size, has_indent: false }\n    }\n\n    pub(super) fn chained(size: usize, has_indent: bool) -> Self {\n        Self { kind: CallContextKind::Chained, size, has_indent }\n    }\n\n    pub(super) fn is_nested(&self) -> bool {\n        matches!(self.kind, CallContextKind::Nested)\n    }\n\n    pub(super) fn is_chained(&self) -> bool {\n        matches!(self.kind, CallContextKind::Chained)\n    }\n}\n\n#[derive(Debug, Default)]\npub(super) struct CallStack {\n    stack: Vec<CallContext>,\n}\n\nimpl Deref for CallStack {\n    type Target = [CallContext];\n    fn deref(&self) -> &Self::Target {\n        &self.stack\n    }\n}\n\nimpl CallStack {\n    pub(crate) fn push(&mut self, call: CallContext) {\n        self.stack.push(call);\n    }\n\n    pub(crate) fn pop(&mut self) -> Option<CallContext> {\n        self.stack.pop()\n    }\n\n    pub(crate) fn is_nested(&self) -> bool {\n        self.last().is_some_and(|call| call.is_nested())\n    }\n\n    /// Returns true if any chained call in the stack has its own indentation.\n    /// Used to determine if commasep should skip its own indentation (to avoid double indent).\n    pub(crate) fn has_chain_with_indent(&self) -> bool {\n        self.stack.iter().any(|call| call.is_chained() && call.has_indent)\n    }\n}\n\npub(super) struct State<'sess, 'ast> {\n    // CORE COMPONENTS\n    pub(super) s: pp::Printer,\n    ind: isize,\n\n    sm: &'sess SourceMap,\n    pub(super) comments: Comments,\n    config: Arc<FormatterConfig>,\n    inline_config: InlineConfig<()>,\n    cursor: SourcePos,\n\n    // FORMATTING CONTEXT:\n    // Whether the source file uses CRLF (`\\r\\n`) line endings.\n    has_crlf: bool,\n    // The current contract being formatted, if inside a contract definition.\n    contract: Option<&'ast ast::ItemContract<'ast>>,\n    // Current block nesting depth (incremented for each `{...}` block entered).\n    block_depth: usize,\n    // Stack tracking nested and chained function calls.\n    call_stack: CallStack,\n\n    // Whether the current statement should be formatted as a single line, or not.\n    single_line_stmt: Option<bool>,\n    // The current binary expression chain context, if inside one.\n    binary_expr: Option<BinOpGroup>,\n    // Whether inside a `return` statement that contains a binary expression, or not.\n    return_bin_expr: bool,\n    // Whether inside a call with call options and at least one argument.\n    call_with_opts_and_args: bool,\n    // Whether to skip the index soft breaks because the callee fits inline.\n    skip_index_break: bool,\n    // Whether inside an `emit` or `revert` call with a qualified path, or not.\n    emit_or_revert: bool,\n    // Whether inside a variable initialization expression, or not.\n    var_init: bool,\n}\n\nimpl std::ops::Deref for State<'_, '_> {\n    type Target = pp::Printer;\n\n    #[inline(always)]\n    fn deref(&self) -> &Self::Target {\n        &self.s\n    }\n}\n\nimpl std::ops::DerefMut for State<'_, '_> {\n    #[inline(always)]\n    fn deref_mut(&mut self) -> &mut Self::Target {\n        &mut self.s\n    }\n}\n\nstruct SourcePos {\n    pos: BytePos,\n    enabled: bool,\n}\n\nimpl SourcePos {\n    pub(super) fn advance(&mut self, bytes: u32) {\n        self.pos += BytePos(bytes);\n    }\n\n    pub(super) fn advance_to(&mut self, pos: BytePos, enabled: bool) {\n        self.pos = std::cmp::max(pos, self.pos);\n        self.enabled = enabled;\n    }\n\n    pub(super) fn next_line(&mut self, is_at_crlf: bool) {\n        self.pos += if is_at_crlf { 2 } else { 1 };\n    }\n\n    pub(super) fn span(&self, to: BytePos) -> Span {\n        Span::new(self.pos, to)\n    }\n}\n\npub(super) enum Separator {\n    Nbsp,\n    Space,\n    Hardbreak,\n    SpaceOrNbsp(bool),\n}\n\nimpl Separator {\n    fn print(&self, p: &mut pp::Printer, cursor: &mut SourcePos, is_at_crlf: bool) {\n        match self {\n            Self::Nbsp => p.nbsp(),\n            Self::Space => p.space(),\n            Self::Hardbreak => p.hardbreak(),\n            Self::SpaceOrNbsp(breaks) => p.space_or_nbsp(*breaks),\n        }\n\n        cursor.next_line(is_at_crlf);\n    }\n}\n\n/// Generic methods\nimpl<'sess> State<'sess, '_> {\n    pub(super) fn new(\n        sm: &'sess SourceMap,\n        config: Arc<FormatterConfig>,\n        inline_config: InlineConfig<()>,\n        comments: Comments,\n    ) -> Self {\n        Self {\n            s: pp::Printer::new(\n                config.line_length,\n                if matches!(config.style, IndentStyle::Tab) {\n                    Some(config.tab_width)\n                } else {\n                    None\n                },\n            ),\n            ind: config.tab_width as isize,\n            sm,\n            comments,\n            config,\n            inline_config,\n            cursor: SourcePos { pos: BytePos::from_u32(0), enabled: true },\n            has_crlf: false,\n            contract: None,\n            single_line_stmt: None,\n            call_with_opts_and_args: false,\n            skip_index_break: false,\n            binary_expr: None,\n            return_bin_expr: false,\n            emit_or_revert: false,\n            var_init: false,\n            block_depth: 0,\n            call_stack: CallStack::default(),\n        }\n    }\n\n    /// Checks a span of the source for a carriage return (`\\r`) to determine if the file\n    /// uses CRLF line endings.\n    ///\n    /// If a `\\r` is found, `self.has_crlf` is set to `true`. This is intended to be\n    /// called once at the beginning of the formatting process for efficiency.\n    fn check_crlf(&mut self, span: Span) {\n        if let Ok(snip) = self.sm.span_to_snippet(span)\n            && snip.contains('\\r')\n        {\n            self.has_crlf = true;\n        }\n    }\n\n    /// Checks if the cursor is currently positioned at the start of a CRLF sequence (`\\r\\n`).\n    /// The check is only meaningful if `self.has_crlf` is true.\n    fn is_at_crlf(&self) -> bool {\n        self.has_crlf && self.char_at(self.cursor.pos) == Some('\\r')\n    }\n\n    /// Computes the space left, bounded by the max space left.\n    fn space_left(&self) -> usize {\n        std::cmp::min(self.s.space_left(), self.max_space_left(0))\n    }\n\n    /// Computes the maximum space left given the context information available:\n    /// `block_depth`, `tab_width`, and a user-defined unavailable size `prefix_len`.\n    fn max_space_left(&self, prefix_len: usize) -> usize {\n        self.config\n            .line_length\n            .saturating_sub(self.block_depth * self.config.tab_width + prefix_len)\n    }\n\n    fn break_offset_if_not_bol(&mut self, n: usize, off: isize, search: bool) {\n        // When searching, the break token is expected to be inside a closed box. Thus, we will\n        // traverse the buffer and evaluate the first non-end token.\n        if search {\n            // We do something pretty sketchy here: tuck the nonzero offset-adjustment we\n            // were going to deposit along with the break into the previous hardbreak.\n            self.find_and_replace_last_token_still_buffered(\n                pp::Printer::hardbreak_tok_offset(off),\n                |token| token.is_hardbreak(),\n            );\n            return;\n        }\n\n        // When not explicitly searching, the break token is expected to be the last token.\n        if !self.is_beginning_of_line() {\n            self.break_offset(n, off)\n        } else if off != 0\n            && let Some(last_token) = self.last_token_still_buffered()\n            && last_token.is_hardbreak()\n        {\n            // We do something pretty sketchy here: tuck the nonzero offset-adjustment we\n            // were going to deposit along with the break into the previous hardbreak.\n            self.replace_last_token_still_buffered(pp::Printer::hardbreak_tok_offset(off));\n        }\n    }\n\n    fn braces_break(&mut self) {\n        if self.config.bracket_spacing {\n            self.space();\n        } else {\n            self.zerobreak();\n        }\n    }\n}\n\n/// Span to source.\nimpl State<'_, '_> {\n    fn char_at(&self, pos: BytePos) -> Option<char> {\n        let res = self.sm.lookup_byte_offset(pos);\n        res.sf.src.get(res.pos.to_usize()..)?.chars().next()\n    }\n\n    fn print_span(&mut self, span: Span) {\n        match self.sm.span_to_snippet(span) {\n            Ok(s) => self.s.word(if matches!(self.config.style, IndentStyle::Tab) {\n                snippet_with_tabs(s, self.config.tab_width)\n            } else {\n                s\n            }),\n            Err(e) => panic!(\"failed to print {span:?}: {e:#?}\"),\n        }\n        // Drop comments that are included in the span.\n        while let Some(cmnt) = self.peek_comment() {\n            if cmnt.pos() >= span.hi() {\n                break;\n            }\n            let _ = self.next_comment().unwrap();\n        }\n        // Update cursor\n        self.cursor.advance_to(span.hi(), false);\n    }\n\n    /// Returns `true` if the span is disabled and has been printed as-is.\n    #[must_use]\n    fn handle_span(&mut self, span: Span, skip_prev_cmnts: bool) -> bool {\n        if !skip_prev_cmnts {\n            self.print_comments(span.lo(), CommentConfig::default());\n        }\n        self.print_span_if_disabled(span)\n    }\n\n    /// Returns `true` if the span is disabled and has been printed as-is.\n    #[inline]\n    #[must_use]\n    fn print_span_if_disabled(&mut self, span: Span) -> bool {\n        let cursor_span = self.cursor.span(span.hi());\n        if self.inline_config.is_disabled(cursor_span) {\n            self.print_span_cold(cursor_span);\n            return true;\n        }\n        if self.inline_config.is_disabled(span) {\n            self.print_span_cold(span);\n            return true;\n        }\n        false\n    }\n\n    #[cold]\n    fn print_span_cold(&mut self, span: Span) {\n        self.print_span(span);\n    }\n\n    fn print_tokens(&mut self, tokens: &[token::Token]) {\n        // Leave unchanged.\n        let span = Span::join_first_last(tokens.iter().map(|t| t.span));\n        self.print_span(span);\n    }\n\n    fn print_word(&mut self, w: impl Into<Cow<'static, str>>) {\n        let cow = w.into();\n        self.cursor.advance(cow.len() as u32);\n        self.word(cow);\n    }\n\n    fn print_sep(&mut self, sep: Separator) {\n        if self.handle_span(\n            self.cursor.span(self.cursor.pos + if self.is_at_crlf() { 2 } else { 1 }),\n            true,\n        ) {\n            return;\n        }\n\n        self.print_sep_unhandled(sep);\n    }\n\n    fn print_sep_unhandled(&mut self, sep: Separator) {\n        let is_at_crlf = self.is_at_crlf();\n        sep.print(&mut self.s, &mut self.cursor, is_at_crlf);\n    }\n\n    fn print_ident(&mut self, ident: &ast::Ident) {\n        if self.handle_span(ident.span, true) {\n            return;\n        }\n\n        self.print_comments(ident.span.lo(), CommentConfig::skip_ws());\n        self.word(ident.to_string());\n    }\n\n    fn print_inside_parens<F>(&mut self, f: F)\n    where\n        F: FnOnce(&mut Self),\n    {\n        self.print_word(\"(\");\n        f(self);\n        self.print_word(\")\");\n    }\n\n    fn estimate_size(&self, span: Span) -> usize {\n        if let Ok(snip) = self.sm.span_to_snippet(span) {\n            let (mut size, mut first, mut prev_needs_space) = (0, true, false);\n\n            for line in snip.lines() {\n                let line = line.trim();\n\n                if prev_needs_space {\n                    size += 1;\n                } else if !first && let Some(char) = line.chars().next() {\n                    // A line break or a space are required if this line:\n                    // - starts with an operator.\n                    // - starts with one of the ternary operators\n                    // - starts with a bracket and fmt config forces bracket spacing.\n                    match char {\n                        '&' | '|' | '=' | '>' | '<' | '+' | '-' | '*' | '/' | '%' | '^' | '?'\n                        | ':' => size += 1,\n                        '}' | ')' | ']' if self.config.bracket_spacing => size += 1,\n                        _ => (),\n                    }\n                }\n                first = false;\n\n                // trim spaces before and after mixed comments\n                let mut search = line;\n                loop {\n                    if let Some((lhs, comment)) = search.split_once(r#\"/*\"#) {\n                        size += lhs.trim_end().len() + 2;\n                        search = comment;\n                    } else if let Some((comment, rhs)) = search.split_once(r#\"*/\"#) {\n                        size += comment.len() + 2;\n                        search = rhs;\n                    } else {\n                        size += search.trim().len();\n                        break;\n                    }\n                }\n\n                // Next line requires a line break if this one:\n                // - ends with a bracket and fmt config forces bracket spacing.\n                // - ends with ',' a line break or a space are required.\n                // - ends with ';' a line break is required.\n                prev_needs_space = match line.chars().next_back() {\n                    Some('[') | Some('(') | Some('{') => self.config.bracket_spacing,\n                    Some(',') | Some(';') => true,\n                    _ => false,\n                };\n            }\n            return size;\n        }\n\n        span.to_range().len()\n    }\n\n    fn same_source_line(&self, a: BytePos, b: BytePos) -> bool {\n        self.sm.lookup_char_pos(a).line == self.sm.lookup_char_pos(b).line\n    }\n}\n\n/// Comment-related methods.\nimpl<'sess> State<'sess, '_> {\n    /// Returns `None` if the span is disabled and has been printed as-is.\n    #[must_use]\n    fn handle_comment(&mut self, cmnt: Comment, skip_break: bool) -> Option<Comment> {\n        if self.cursor.enabled {\n            if self.inline_config.is_disabled(cmnt.span) {\n                if cmnt.style.is_trailing() && !self.last_token_is_space() {\n                    self.nbsp();\n                }\n                self.print_span_cold(cmnt.span);\n                if !skip_break && (cmnt.style.is_isolated() || cmnt.style.is_trailing()) {\n                    self.print_sep(Separator::Hardbreak);\n                }\n                return None;\n            }\n        } else if self.print_span_if_disabled(cmnt.span) {\n            if !skip_break && (cmnt.style.is_isolated() || cmnt.style.is_trailing()) {\n                self.print_sep(Separator::Hardbreak);\n            }\n            return None;\n        }\n        Some(cmnt)\n    }\n\n    fn cmnt_config(&self) -> CommentConfig {\n        CommentConfig { ..Default::default() }\n    }\n\n    fn print_docs(&mut self, docs: &'_ ast::DocComments<'_>) {\n        // Intetionally no-op. Handled with `self.comments`.\n        let _ = docs;\n    }\n\n    /// Prints comments that are before the given position.\n    ///\n    /// Returns `Some` with the style of the last comment printed, or `None` if no comment was\n    /// printed.\n    fn print_comments(&mut self, pos: BytePos, mut config: CommentConfig) -> Option<CommentStyle> {\n        let mut last_style: Option<CommentStyle> = None;\n        let mut is_leading = true;\n        let config_cache = config;\n        let mut buffered_blank = None;\n        while self.peek_comment().is_some_and(|c| c.pos() < pos) {\n            let mut cmnt = self.next_comment().unwrap();\n            let style_cache = cmnt.style;\n\n            // Merge consecutive line doc comments when converting to block style\n            if self.config.docs_style == foundry_config::fmt::DocCommentStyle::Block\n                && cmnt.is_doc\n                && cmnt.kind == ast::CommentKind::Line\n            {\n                let mut ref_line = self.sm.lookup_char_pos(cmnt.span.hi()).line;\n                while let Some(next_cmnt) = self.peek_comment() {\n                    if !next_cmnt.is_doc\n                        || next_cmnt.kind != ast::CommentKind::Line\n                        || ref_line + 1 != self.sm.lookup_char_pos(next_cmnt.span.lo()).line\n                    {\n                        break;\n                    }\n\n                    let next_to_merge = self.next_comment().unwrap();\n                    cmnt.lines.extend(next_to_merge.lines);\n                    cmnt.span = cmnt.span.to(next_to_merge.span);\n                    ref_line += 1;\n                }\n            }\n\n            // Ensure breaks are never skipped when there are multiple comments\n            if self.peek_comment_before(pos).is_some() {\n                config.iso_no_break = false;\n                config.trailing_no_break = false;\n            }\n\n            // Handle disabled comments\n            let Some(cmnt) = self.handle_comment(\n                cmnt,\n                if style_cache.is_isolated() {\n                    config.iso_no_break\n                } else {\n                    config.trailing_no_break\n                },\n            ) else {\n                last_style = Some(style_cache);\n                continue;\n            };\n\n            if cmnt.style.is_blank() {\n                match config.skip_blanks {\n                    Some(Skip::All) => continue,\n                    Some(Skip::Leading { resettable: true }) if is_leading => continue,\n                    Some(Skip::Leading { resettable: false }) if last_style.is_none() => continue,\n                    Some(Skip::Trailing) => {\n                        buffered_blank = Some(cmnt);\n                        continue;\n                    }\n                    _ => (),\n                }\n            // Never print blank lines after docs comments\n            } else if !cmnt.is_doc {\n                is_leading = false;\n            }\n\n            if let Some(blank) = buffered_blank.take() {\n                self.print_comment(blank, config);\n            }\n\n            // Handle mixed with follow-up comment\n            if cmnt.style.is_mixed() {\n                if let Some(cmnt) = self.peek_comment_before(pos) {\n                    config.mixed_no_break_prev = true;\n                    config.mixed_no_break_post = true;\n                    config.mixed_post_nbsp = cmnt.style.is_mixed();\n                }\n\n                // Ensure consecutive mixed comments don't have a double-space\n                if last_style.is_some_and(|s| s.is_mixed()) {\n                    config.mixed_no_break_prev = true;\n                    config.mixed_no_break_post = true;\n                    config.mixed_prev_space = false;\n                }\n            } else if config.offset != 0\n                && cmnt.style.is_isolated()\n                && last_style.is_some_and(|s| s.is_isolated())\n            {\n                self.offset(config.offset);\n            }\n\n            last_style = Some(cmnt.style);\n            self.print_comment(cmnt, config);\n            config = config_cache;\n        }\n        last_style\n    }\n\n    /// Prints a line, wrapping it if it starts with the given prefix.\n    fn print_wrapped_line(\n        &mut self,\n        line: &str,\n        prefix: &'static str,\n        break_offset: isize,\n        is_doc: bool,\n    ) {\n        if !line.starts_with(prefix) {\n            self.word(line.to_owned());\n            return;\n        }\n\n        fn post_break_prefix(prefix: &'static str, has_content: bool) -> &'static str {\n            if !has_content {\n                return prefix;\n            }\n            match prefix {\n                \"///\" => \"/// \",\n                \"//\" => \"// \",\n                \"/*\" => \"/* \",\n                \" *\" => \" * \",\n                _ => prefix,\n            }\n        }\n\n        self.ibox(0);\n        self.word(prefix);\n\n        let content = &line[prefix.len()..];\n        let content = if is_doc {\n            // Doc comments preserve leading whitespaces (right after the prefix) as nbps.\n            let ws_len = content\n                .char_indices()\n                .take_while(|(_, c)| c.is_whitespace())\n                .last()\n                .map_or(0, |(idx, c)| idx + c.len_utf8());\n            let (leading_ws, rest) = content.split_at(ws_len);\n            if !leading_ws.is_empty() {\n                self.word(leading_ws.to_owned());\n            }\n            rest\n        } else {\n            // Non-doc comments: replace first whitespace with nbsp, rest of content continues\n            if let Some(first_char) = content.chars().next() {\n                if first_char.is_whitespace() {\n                    self.nbsp();\n                    &content[first_char.len_utf8()..]\n                } else {\n                    content\n                }\n            } else {\n                \"\"\n            }\n        };\n\n        let post_break = post_break_prefix(prefix, !content.is_empty());\n\n        // Process content character by character to preserve consecutive whitespaces\n        let (mut chars, mut current_word) = (content.chars().peekable(), String::new());\n        while let Some(ch) = chars.next() {\n            if ch.is_whitespace() {\n                // Print current word\n                if !current_word.is_empty() {\n                    self.word(std::mem::take(&mut current_word));\n                }\n\n                // Preserve multiple spaces while adding a single break\n                let mut ws_count = 1;\n                while chars.peek().is_some_and(|c| c.is_whitespace()) {\n                    ws_count += 1;\n                    chars.next();\n                }\n                self.s.scan_break(BreakToken {\n                    offset: break_offset,\n                    blank_space: ws_count,\n                    post_break: if post_break.starts_with(\"/*\") { None } else { Some(post_break) },\n                    ..Default::default()\n                });\n                continue;\n            }\n\n            current_word.push(ch);\n        }\n\n        // Print final word\n        if !current_word.is_empty() {\n            self.word(current_word);\n        }\n\n        self.end();\n    }\n\n    /// Merges consecutive line comments to avoid orphan words.\n    fn merge_comment_lines(&self, lines: &[String], prefix: &str) -> Vec<String> {\n        // Do not apply smart merging to block comments\n        if lines.is_empty() || lines.len() < 2 || !prefix.starts_with(\"//\") {\n            return lines.to_vec();\n        }\n\n        let mut result = Vec::new();\n        let mut i = 0;\n\n        while i < lines.len() {\n            let current_line = &lines[i];\n\n            // Keep empty lines, and non-prefixed lines, untouched\n            if current_line.trim().is_empty() || !current_line.starts_with(prefix) {\n                result.push(current_line.clone());\n                i += 1;\n                continue;\n            }\n\n            if i + 1 < lines.len() {\n                let next_line = &lines[i + 1];\n\n                // Check if next line is has the same prefix and is not empty\n                if next_line.starts_with(prefix) && !next_line.trim().is_empty() {\n                    // Only merge if the current line doesn't fit within available width\n                    if estimate_line_width(current_line, self.config.tab_width) > self.space_left()\n                    {\n                        // Merge the lines and let the wrapper handle breaking if needed\n                        let merged_line = format!(\n                            \"{current_line} {next_content}\",\n                            next_content = &next_line[prefix.len()..].trim_start()\n                        );\n                        result.push(merged_line);\n\n                        // Skip both lines since they are merged\n                        i += 2;\n                        continue;\n                    }\n                }\n            }\n\n            // No merge possible, keep the line as-is\n            result.push(current_line.clone());\n            i += 1;\n        }\n\n        result\n    }\n\n    fn print_comment(&mut self, mut cmnt: Comment, mut config: CommentConfig) {\n        self.cursor.advance_to(cmnt.span.hi(), true);\n\n        if cmnt.is_doc {\n            cmnt = style_doc_comment(self.config.docs_style, cmnt);\n        }\n\n        match cmnt.style {\n            CommentStyle::Mixed => {\n                let Some(prefix) = cmnt.prefix() else { return };\n                let never_break = self.last_token_is_neverbreak();\n                if !self.is_bol_or_only_ind() {\n                    match (never_break || config.mixed_no_break_prev, config.mixed_prev_space) {\n                        (false, true) => config.space(&mut self.s),\n                        (false, false) => config.zerobreak(&mut self.s),\n                        (true, true) => self.nbsp(),\n                        (true, false) => (),\n                    };\n                }\n                if self.config.wrap_comments {\n                    // Merge and wrap comments\n                    let merged_lines = self.merge_comment_lines(&cmnt.lines, prefix);\n                    for (pos, line) in merged_lines.into_iter().delimited() {\n                        self.print_wrapped_line(&line, prefix, 0, cmnt.is_doc);\n                        if !pos.is_last {\n                            self.hardbreak();\n                        }\n                    }\n                } else {\n                    // No wrapping, print as-is\n                    for (pos, line) in cmnt.lines.into_iter().delimited() {\n                        self.word(line);\n                        if !pos.is_last {\n                            self.hardbreak();\n                        }\n                    }\n                }\n                if config.mixed_post_nbsp {\n                    config.nbsp_or_space(self.config.wrap_comments, &mut self.s);\n                    self.cursor.advance(1);\n                } else if !config.mixed_no_break_post {\n                    config.space(&mut self.s);\n                    self.cursor.advance(1);\n                }\n            }\n            CommentStyle::Isolated => {\n                let Some(mut prefix) = cmnt.prefix() else { return };\n                if !config.iso_no_break {\n                    config.hardbreak_if_not_bol(self.is_bol_or_only_ind(), &mut self.s);\n                }\n\n                if self.config.wrap_comments {\n                    // Merge and wrap comments\n                    let merged_lines = self.merge_comment_lines(&cmnt.lines, prefix);\n                    for (pos, line) in merged_lines.into_iter().delimited() {\n                        let hb = |this: &mut Self| {\n                            this.hardbreak();\n                            if pos.is_last {\n                                this.cursor.next_line(this.is_at_crlf());\n                            }\n                        };\n                        if line.is_empty() {\n                            hb(self);\n                            continue;\n                        }\n                        if pos.is_first {\n                            self.ibox(config.offset);\n                            if cmnt.is_doc && matches!(prefix, \"/**\") {\n                                self.word(prefix);\n                                hb(self);\n                                prefix = \" * \";\n                                continue;\n                            }\n                        }\n\n                        self.print_wrapped_line(&line, prefix, 0, cmnt.is_doc);\n\n                        if pos.is_last {\n                            self.end();\n                            if !config.iso_no_break {\n                                hb(self);\n                            }\n                        } else {\n                            hb(self);\n                        }\n                    }\n                } else {\n                    // No wrapping, print as-is\n                    for (pos, line) in cmnt.lines.into_iter().delimited() {\n                        let hb = |this: &mut Self| {\n                            this.hardbreak();\n                            if pos.is_last {\n                                this.cursor.next_line(this.is_at_crlf());\n                            }\n                        };\n                        if line.is_empty() {\n                            hb(self);\n                            continue;\n                        }\n                        if pos.is_first {\n                            self.ibox(config.offset);\n                            if cmnt.is_doc && matches!(prefix, \"/**\") {\n                                self.word(prefix);\n                                hb(self);\n                                prefix = \" * \";\n                                continue;\n                            }\n                        }\n\n                        self.word(line);\n\n                        if pos.is_last {\n                            self.end();\n                            if !config.iso_no_break {\n                                hb(self);\n                            }\n                        } else {\n                            hb(self);\n                        }\n                    }\n                }\n            }\n            CommentStyle::Trailing => {\n                let Some(prefix) = cmnt.prefix() else { return };\n                self.neverbreak();\n                if !self.is_bol_or_only_ind() {\n                    self.nbsp();\n                }\n\n                if !self.config.wrap_comments && cmnt.lines.len() == 1 {\n                    self.word(cmnt.lines.pop().unwrap());\n                } else if self.config.wrap_comments {\n                    if cmnt.is_doc || matches!(cmnt.kind, ast::CommentKind::Line) {\n                        config.offset = 0;\n                    } else {\n                        config.offset = self.ind;\n                    }\n                    for (lpos, line) in cmnt.lines.into_iter().delimited() {\n                        if !line.is_empty() {\n                            self.print_wrapped_line(&line, prefix, config.offset, cmnt.is_doc);\n                        }\n                        if !lpos.is_last {\n                            config.hardbreak(&mut self.s);\n                        }\n                    }\n                } else {\n                    self.visual_align();\n                    for (pos, line) in cmnt.lines.into_iter().delimited() {\n                        if !line.is_empty() {\n                            self.word(line);\n                            if !pos.is_last {\n                                self.hardbreak();\n                            }\n                        }\n                    }\n                    self.end();\n                }\n\n                if !config.trailing_no_break {\n                    self.print_sep(Separator::Hardbreak);\n                }\n            }\n\n            CommentStyle::BlankLine => {\n                // Pre-requisite: ensure that blank links are printed at the beginning of new line.\n                if !self.last_token_is_break() && !self.is_bol_or_only_ind() {\n                    config.hardbreak(&mut self.s);\n                    self.cursor.next_line(self.is_at_crlf());\n                }\n\n                // We need to do at least one, possibly two hardbreaks.\n                let twice = match self.last_token() {\n                    Some(Token::String(s)) => \";\" == s,\n                    Some(Token::Begin(_)) => true,\n                    Some(Token::End) => true,\n                    _ => false,\n                };\n                if twice {\n                    config.hardbreak(&mut self.s);\n                    self.cursor.next_line(self.is_at_crlf());\n                }\n                config.hardbreak(&mut self.s);\n                self.cursor.next_line(self.is_at_crlf());\n            }\n        }\n    }\n\n    fn peek_comment<'b>(&'b self) -> Option<&'b Comment>\n    where\n        'sess: 'b,\n    {\n        self.comments.peek()\n    }\n\n    fn peek_comment_before<'b>(&'b self, pos: BytePos) -> Option<&'b Comment>\n    where\n        'sess: 'b,\n    {\n        self.comments.iter().take_while(|c| c.pos() < pos).find(|c| !c.style.is_blank())\n    }\n\n    fn has_comment_before_with<F>(&self, pos: BytePos, f: F) -> bool\n    where\n        F: FnMut(&Comment) -> bool,\n    {\n        self.comments.iter().take_while(|c| c.pos() < pos).any(f)\n    }\n\n    fn peek_comment_between<'b>(&'b self, pos_lo: BytePos, pos_hi: BytePos) -> Option<&'b Comment>\n    where\n        'sess: 'b,\n    {\n        self.comments\n            .iter()\n            .take_while(|c| pos_lo < c.pos() && c.pos() < pos_hi)\n            .find(|c| !c.style.is_blank())\n    }\n\n    fn has_comment_between(&self, start_pos: BytePos, end_pos: BytePos) -> bool {\n        self.comments.iter().filter(|c| c.pos() > start_pos && c.pos() < end_pos).any(|_| true)\n    }\n\n    pub(crate) fn next_comment(&mut self) -> Option<Comment> {\n        self.comments.next()\n    }\n\n    fn peek_trailing_comment<'b>(\n        &'b self,\n        span_pos: BytePos,\n        next_pos: Option<BytePos>,\n    ) -> Option<&'b Comment>\n    where\n        'sess: 'b,\n    {\n        self.comments.peek_trailing(self.sm, span_pos, next_pos).map(|(cmnt, _)| cmnt)\n    }\n\n    fn print_trailing_comment_inner(\n        &mut self,\n        span_pos: BytePos,\n        next_pos: Option<BytePos>,\n        config: Option<CommentConfig>,\n    ) -> bool {\n        let mut printed = 0;\n        if let Some((_, n)) = self.comments.peek_trailing(self.sm, span_pos, next_pos) {\n            let config =\n                config.unwrap_or(CommentConfig::skip_ws().mixed_no_break().mixed_prev_space());\n            while printed <= n {\n                let cmnt = self.comments.next().unwrap();\n                if let Some(cmnt) = self.handle_comment(cmnt, config.trailing_no_break) {\n                    self.print_comment(cmnt, config);\n                };\n                printed += 1;\n            }\n        }\n        printed != 0\n    }\n\n    fn print_trailing_comment(&mut self, span_pos: BytePos, next_pos: Option<BytePos>) -> bool {\n        self.print_trailing_comment_inner(span_pos, next_pos, None)\n    }\n\n    fn print_trailing_comment_no_break(&mut self, span_pos: BytePos, next_pos: Option<BytePos>) {\n        self.print_trailing_comment_inner(\n            span_pos,\n            next_pos,\n            Some(CommentConfig::skip_ws().trailing_no_break().mixed_no_break().mixed_prev_space()),\n        );\n    }\n\n    fn print_remaining_comments(&mut self, skip_leading_ws: bool) {\n        // If there aren't any remaining comments, then we need to manually\n        // make sure there is a line break at the end.\n        if self.peek_comment().is_none() && !self.is_bol_or_only_ind() {\n            self.hardbreak();\n            return;\n        }\n\n        let mut is_leading = true;\n        while let Some(cmnt) = self.next_comment() {\n            if cmnt.style.is_blank() && skip_leading_ws && is_leading {\n                continue;\n            }\n\n            is_leading = false;\n            if let Some(cmnt) = self.handle_comment(cmnt, false) {\n                self.print_comment(cmnt, CommentConfig::default());\n            } else if self.peek_comment().is_none() && !self.is_bol_or_only_ind() {\n                self.hardbreak();\n            }\n        }\n    }\n}\n\n#[derive(Clone, Copy)]\nenum Skip {\n    All,\n    Leading { resettable: bool },\n    Trailing,\n}\n\n#[derive(Default, Clone, Copy)]\npub(crate) struct CommentConfig {\n    // Config: all\n    skip_blanks: Option<Skip>,\n    offset: isize,\n\n    // Config: isolated comments\n    iso_no_break: bool,\n    // Config: trailing comments\n    trailing_no_break: bool,\n    // Config: mixed comments\n    mixed_prev_space: bool,\n    mixed_post_nbsp: bool,\n    mixed_no_break_prev: bool,\n    mixed_no_break_post: bool,\n}\n\nimpl CommentConfig {\n    pub(crate) fn skip_ws() -> Self {\n        Self { skip_blanks: Some(Skip::All), ..Default::default() }\n    }\n\n    pub(crate) fn skip_leading_ws(resettable: bool) -> Self {\n        Self { skip_blanks: Some(Skip::Leading { resettable }), ..Default::default() }\n    }\n\n    pub(crate) fn skip_trailing_ws() -> Self {\n        Self { skip_blanks: Some(Skip::Trailing), ..Default::default() }\n    }\n\n    pub(crate) fn offset(mut self, off: isize) -> Self {\n        self.offset = off;\n        self\n    }\n\n    pub(crate) fn no_breaks(mut self) -> Self {\n        self.iso_no_break = true;\n        self.trailing_no_break = true;\n        self.mixed_no_break_prev = true;\n        self.mixed_no_break_post = true;\n        self\n    }\n\n    pub(crate) fn trailing_no_break(mut self) -> Self {\n        self.trailing_no_break = true;\n        self\n    }\n\n    pub(crate) fn mixed_no_break(mut self) -> Self {\n        self.mixed_no_break_prev = true;\n        self.mixed_no_break_post = true;\n        self\n    }\n\n    pub(crate) fn mixed_no_break_post(mut self) -> Self {\n        self.mixed_no_break_post = true;\n        self\n    }\n\n    pub(crate) fn mixed_prev_space(mut self) -> Self {\n        self.mixed_prev_space = true;\n        self\n    }\n\n    pub(crate) fn mixed_post_nbsp(mut self) -> Self {\n        self.mixed_post_nbsp = true;\n        self\n    }\n\n    pub(crate) fn hardbreak_if_not_bol(&self, is_bol: bool, p: &mut pp::Printer) {\n        if self.offset != 0 && !is_bol {\n            self.hardbreak(p);\n        } else {\n            p.hardbreak_if_not_bol();\n        }\n    }\n\n    pub(crate) fn hardbreak(&self, p: &mut pp::Printer) {\n        p.break_offset(SIZE_INFINITY as usize, self.offset);\n    }\n\n    pub(crate) fn space(&self, p: &mut pp::Printer) {\n        p.break_offset(1, self.offset);\n    }\n\n    pub(crate) fn nbsp_or_space(&self, breaks: bool, p: &mut pp::Printer) {\n        if breaks {\n            self.space(p);\n        } else {\n            p.nbsp();\n        }\n    }\n\n    pub(crate) fn zerobreak(&self, p: &mut pp::Printer) {\n        p.break_offset(0, self.offset);\n    }\n}\n\nfn snippet_with_tabs(s: String, tab_width: usize) -> String {\n    // process leading breaks\n    let trimmed = s.trim_start_matches('\\n');\n    let num_breaks = s.len() - trimmed.len();\n    let mut formatted = std::iter::repeat_n('\\n', num_breaks).collect::<String>();\n\n    // process lines\n    for (pos, line) in trimmed.lines().delimited() {\n        line_with_tabs(&mut formatted, line, tab_width, None);\n        if !pos.is_last {\n            formatted.push('\\n');\n        }\n    }\n\n    formatted\n}\n\n/// Formats a doc comment with the requested style.\n///\n/// NOTE: assumes comments have already been normalized.\nfn style_doc_comment(style: DocCommentStyle, mut cmnt: Comment) -> Comment {\n    match style {\n        DocCommentStyle::Line if cmnt.kind == ast::CommentKind::Block => {\n            let mut new_lines = Vec::new();\n            for (pos, line) in cmnt.lines.iter().delimited() {\n                if pos.is_first || pos.is_last {\n                    // Skip the opening '/**' and closing '*/' lines\n                    continue;\n                }\n\n                // Convert ' * {content}' to '/// {content}'\n                let trimmed = line.trim_start();\n                if let Some(content) = trimmed.strip_prefix('*') {\n                    new_lines.push(format!(\"///{content}\"));\n                } else if !trimmed.is_empty() {\n                    new_lines.push(format!(\"/// {trimmed}\"));\n                }\n            }\n\n            cmnt.lines = new_lines;\n            cmnt.kind = ast::CommentKind::Line;\n            cmnt\n        }\n        DocCommentStyle::Block if cmnt.kind == ast::CommentKind::Line => {\n            let mut new_lines = vec![\"/**\".to_string()];\n\n            for line in &cmnt.lines {\n                // Convert '/// {content}' to ' * {content}'\n                new_lines.push(format!(\" *{content}\", content = &line[3..]))\n            }\n\n            new_lines.push(\" */\".to_string());\n            cmnt.lines = new_lines;\n            cmnt.kind = ast::CommentKind::Block;\n            cmnt\n        }\n        // Otherwise, no conversion needed.\n        _ => cmnt,\n    }\n}\n"
  },
  {
    "path": "crates/fmt/src/state/sol.rs",
    "content": "#![allow(clippy::too_many_arguments)]\n\nuse super::{\n    CommentConfig, Separator, State,\n    common::{BlockFormat, ListFormat},\n};\nuse crate::{\n    pp::SIZE_INFINITY,\n    state::{CallContext, common::LitExt},\n};\nuse foundry_common::{comments::Comment, iter::IterDelimited};\nuse foundry_config::fmt::{self as config, MultilineFuncHeaderStyle};\nuse solar::{\n    ast::BoxSlice,\n    interface::SpannedOption,\n    parse::{\n        ast::{self, Span},\n        interface::BytePos,\n    },\n};\nuse std::{collections::HashMap, fmt::Debug};\n\n#[rustfmt::skip]\nmacro_rules! get_span {\n    () => { |value| value.span };\n    (()) => { |value| value.span() };\n}\n\n/// Language-specific pretty printing: Solidity.\nimpl<'ast> State<'_, 'ast> {\n    pub(crate) fn print_source_unit(&mut self, source_unit: &'ast ast::SourceUnit<'ast>) {\n        // Figure out if the cursor needs to check for CR (`\\r`).\n        if let Some(item) = source_unit.items.first() {\n            self.check_crlf(item.span.to(source_unit.items.last().unwrap().span));\n        }\n\n        let mut items = source_unit.items.iter().peekable();\n        let mut is_first = true;\n        while let Some(item) = items.next() {\n            // If imports shouldn't be sorted, or if the item is not an import, print it directly.\n            if !self.config.sort_imports || !matches!(item.kind, ast::ItemKind::Import(_)) {\n                self.print_item(item, is_first);\n                is_first = false;\n                if let Some(next_item) = items.peek() {\n                    self.separate_items(next_item, false);\n                }\n                continue;\n            }\n\n            // Otherwise, collect a group of consecutive imports and sort them before printing.\n            let mut import_group = vec![item];\n            while let Some(next_item) = items.peek() {\n                // Groups end when the next item is not an import or when there is a blank line.\n                if !matches!(next_item.kind, ast::ItemKind::Import(_))\n                    || self.has_comment_between(item.span.hi(), next_item.span.lo())\n                {\n                    break;\n                }\n                import_group.push(items.next().unwrap());\n            }\n\n            import_group.sort_by_key(|item| {\n                if let ast::ItemKind::Import(import) = &item.kind {\n                    import.path.value.as_str()\n                } else {\n                    unreachable!(\"Expected an import item\")\n                }\n            });\n\n            for (pos, group_item) in import_group.iter().delimited() {\n                self.print_item(group_item, is_first);\n                is_first = false;\n\n                if !pos.is_last {\n                    self.hardbreak_if_not_bol();\n                }\n            }\n            if let Some(next_item) = items.peek() {\n                self.separate_items(next_item, false);\n            }\n        }\n\n        self.print_remaining_comments(is_first);\n    }\n\n    /// Prints a hardbreak if the item needs an isolated line break.\n    fn separate_items(&mut self, next_item: &'ast ast::Item<'ast>, advance: bool) {\n        if !item_needs_iso(&next_item.kind) {\n            return;\n        }\n        let span = next_item.span;\n\n        let cmnts = self\n            .comments\n            .iter()\n            .filter_map(|c| if c.pos() < span.lo() { Some(c.style) } else { None })\n            .collect::<Vec<_>>();\n\n        if let Some(first) = cmnts.first()\n            && let Some(last) = cmnts.last()\n        {\n            if !(first.is_blank() || last.is_blank()) {\n                self.hardbreak();\n                return;\n            }\n            if advance {\n                if self.peek_comment_before(span.lo()).is_some() {\n                    self.print_comments(span.lo(), CommentConfig::default());\n                } else if self.inline_config.is_disabled(span.shrink_to_lo()) {\n                    self.hardbreak();\n                    self.cursor.advance_to(span.lo(), true);\n                }\n            }\n        } else {\n            self.hardbreak();\n        }\n    }\n\n    fn print_item(&mut self, item: &'ast ast::Item<'ast>, skip_ws: bool) {\n        let ast::Item { ref docs, span, ref kind } = *item;\n        self.print_docs(docs);\n\n        if self.handle_span(item.span, skip_ws) {\n            if !self.print_trailing_comment(span.hi(), None) {\n                self.print_sep(Separator::Hardbreak);\n            }\n            return;\n        }\n\n        if self\n            .print_comments(\n                span.lo(),\n                if skip_ws {\n                    CommentConfig::skip_leading_ws(false)\n                } else {\n                    CommentConfig::default()\n                },\n            )\n            .is_some_and(|cmnt| cmnt.is_mixed())\n        {\n            self.zerobreak();\n        }\n\n        match kind {\n            ast::ItemKind::Pragma(pragma) => self.print_pragma(pragma),\n            ast::ItemKind::Import(import) => self.print_import(import),\n            ast::ItemKind::Using(using) => self.print_using(using),\n            ast::ItemKind::Contract(contract) => self.print_contract(contract, span),\n            ast::ItemKind::Function(func) => self.print_function(func),\n            ast::ItemKind::Variable(var) => self.print_var_def(var),\n            ast::ItemKind::Struct(strukt) => self.print_struct(strukt, span),\n            ast::ItemKind::Enum(enm) => self.print_enum(enm, span),\n            ast::ItemKind::Udvt(udvt) => self.print_udvt(udvt),\n            ast::ItemKind::Error(err) => self.print_error(err),\n            ast::ItemKind::Event(event) => self.print_event(event),\n        }\n\n        self.cursor.advance_to(span.hi(), true);\n        self.print_comments(span.hi(), CommentConfig::default());\n        self.print_trailing_comment(span.hi(), None);\n        self.hardbreak_if_not_bol();\n        self.cursor.next_line(self.is_at_crlf());\n    }\n\n    fn print_pragma(&mut self, pragma: &'ast ast::PragmaDirective<'ast>) {\n        self.word(\"pragma \");\n        match &pragma.tokens {\n            ast::PragmaTokens::Version(ident, semver_req) => {\n                self.print_ident(ident);\n                self.nbsp();\n                self.word(semver_req.to_string());\n            }\n            ast::PragmaTokens::Custom(a, b) => {\n                self.print_ident_or_strlit(a);\n                if let Some(b) = b {\n                    self.nbsp();\n                    self.print_ident_or_strlit(b);\n                }\n            }\n            ast::PragmaTokens::Verbatim(tokens) => {\n                self.print_tokens(tokens);\n            }\n        }\n        self.word(\";\");\n    }\n\n    fn print_commasep_aliases<'a, I>(&mut self, aliases: I)\n    where\n        I: Iterator<Item = &'a (ast::Ident, Option<ast::Ident>)>,\n        'ast: 'a,\n    {\n        for (pos, (ident, alias)) in aliases.delimited() {\n            self.print_ident(ident);\n            if let Some(alias) = alias {\n                self.word(\" as \");\n                self.print_ident(alias);\n            }\n            if !pos.is_last {\n                self.word(\",\");\n                self.space();\n            }\n        }\n    }\n\n    fn print_import(&mut self, import: &'ast ast::ImportDirective<'ast>) {\n        let ast::ImportDirective { path, items } = import;\n        self.word(\"import \");\n\n        use ast::ImportItems;\n        use config::NamespaceImportStyle as NIStyle;\n\n        match (items, self.config.namespace_import_style) {\n            (ImportItems::Plain(None), _) => {\n                self.print_ast_str_lit(path);\n            }\n\n            (ImportItems::Plain(Some(source_alias)), NIStyle::Preserve | NIStyle::PreferPlain)\n            | (ImportItems::Glob(source_alias), NIStyle::PreferPlain) => {\n                self.print_ast_str_lit(path);\n                self.word(\" as \");\n                self.print_ident(source_alias);\n            }\n\n            (ImportItems::Glob(source_alias), NIStyle::Preserve | NIStyle::PreferGlob)\n            | (ImportItems::Plain(Some(source_alias)), NIStyle::PreferGlob) => {\n                self.word(\"*\");\n                self.word(\" as \");\n                self.print_ident(source_alias);\n                self.word(\" from \");\n                self.print_ast_str_lit(path);\n            }\n\n            (ImportItems::Aliases(aliases), _) => {\n                // Check if we should keep single imports on one line\n                let use_single_line = self.config.single_line_imports && aliases.len() == 1;\n\n                if use_single_line {\n                    self.word(\"{\");\n                    if self.config.bracket_spacing {\n                        self.nbsp();\n                    }\n                } else {\n                    self.s.cbox(self.ind);\n                    self.word(\"{\");\n                    self.braces_break();\n                }\n\n                if self.config.sort_imports {\n                    let mut sorted: Vec<_> = aliases.iter().collect();\n                    sorted.sort_by_key(|(ident, _alias)| ident.name.as_str());\n                    self.print_commasep_aliases(sorted.into_iter());\n                } else {\n                    self.print_commasep_aliases(aliases.iter());\n                };\n\n                if use_single_line {\n                    if self.config.bracket_spacing {\n                        self.nbsp();\n                    }\n                    self.word(\"}\");\n                } else {\n                    self.braces_break();\n                    self.s.offset(-self.ind);\n                    self.word(\"}\");\n                    self.end();\n                }\n                self.word(\" from \");\n                self.print_ast_str_lit(path);\n            }\n        }\n        self.word(\";\");\n    }\n\n    fn print_using(&mut self, using: &'ast ast::UsingDirective<'ast>) {\n        let ast::UsingDirective { list, ty, global } = using;\n        self.word(\"using \");\n        match list {\n            ast::UsingList::Single(path) => self.print_path(path, true),\n            ast::UsingList::Multiple(items) => {\n                self.s.cbox(self.ind);\n                self.word(\"{\");\n                self.braces_break();\n                for (pos, (path, op)) in items.iter().delimited() {\n                    self.print_path(path, true);\n                    if let Some(op) = op {\n                        self.word(\" as \");\n                        self.word(op.to_str());\n                    }\n                    if !pos.is_last {\n                        self.word(\",\");\n                        self.space();\n                    }\n                }\n                self.braces_break();\n                self.s.offset(-self.ind);\n                self.word(\"}\");\n                self.end();\n            }\n        }\n        self.word(\" for \");\n        if let Some(ty) = ty {\n            self.print_ty(ty);\n        } else {\n            self.word(\"*\");\n        }\n        if *global {\n            self.word(\" global\");\n        }\n        self.word(\";\");\n    }\n\n    fn print_contract(&mut self, c: &'ast ast::ItemContract<'ast>, span: Span) {\n        let ast::ItemContract { kind, name, layout, bases, body } = c;\n        self.contract = Some(c);\n        self.cursor.advance_to(span.lo(), true);\n\n        self.s.cbox(self.ind);\n        self.ibox(0);\n        self.cbox(0);\n        self.word_nbsp(kind.to_str());\n        self.print_ident(name);\n        self.nbsp();\n\n        if let Some(layout) = layout\n            && !self.handle_span(layout.span, false)\n        {\n            self.word(\"layout at \");\n            self.print_expr(layout.slot);\n            self.print_sep(Separator::Space);\n        }\n\n        if let Some(first) = bases.first().map(|base| base.span())\n            && let Some(last) = bases.last().map(|base| base.span())\n            && self.inline_config.is_disabled(first.to(last))\n        {\n            _ = self.handle_span(first.until(last), false);\n        } else if !bases.is_empty() {\n            self.word(\"is\");\n            self.space();\n            let last = bases.len() - 1;\n            for (i, base) in bases.iter().enumerate() {\n                if !self.handle_span(base.span(), false) {\n                    self.print_modifier_call(base, false);\n                    if i != last {\n                        self.word(\",\");\n                        if self\n                            .print_comments(\n                                bases[i + 1].span().lo(),\n                                CommentConfig::skip_ws().mixed_prev_space().mixed_post_nbsp(),\n                            )\n                            .is_none()\n                        {\n                            self.space();\n                        }\n                    }\n                }\n            }\n            if !self.print_trailing_comment(bases.last().unwrap().span().hi(), None) {\n                self.space();\n            }\n            self.s.offset(-self.ind);\n        }\n        self.end();\n\n        self.print_word(\"{\");\n        self.end();\n        if !body.is_empty() {\n            // update block depth\n            self.block_depth += 1;\n\n            self.print_sep(Separator::Hardbreak);\n            if self.config.contract_new_lines {\n                self.hardbreak();\n            }\n            let body_lo = body[0].span.lo();\n            if self.peek_comment_before(body_lo).is_some() {\n                self.print_comments(body_lo, CommentConfig::skip_leading_ws(true));\n            }\n\n            let mut is_first = true;\n            let mut items = body.iter().peekable();\n            while let Some(item) = items.next() {\n                self.print_item(item, is_first);\n                is_first = false;\n                if let Some(next_item) = items.peek() {\n                    if self.inline_config.is_disabled(next_item.span) {\n                        _ = self.handle_span(next_item.span, false);\n                    } else {\n                        self.separate_items(next_item, true);\n                    }\n                }\n            }\n\n            if let Some(cmnt) = self.print_comments(span.hi(), CommentConfig::skip_trailing_ws())\n                && self.config.contract_new_lines\n                && !cmnt.is_blank()\n            {\n                self.print_sep(Separator::Hardbreak);\n            }\n            self.s.offset(-self.ind);\n            self.end();\n            if self.config.contract_new_lines {\n                self.hardbreak_if_nonempty();\n            }\n\n            // restore block depth\n            self.block_depth -= 1;\n        } else {\n            if self.print_comments(span.hi(), CommentConfig::skip_ws()).is_some() {\n                // Adjust the offset of the trailing break from comment printing\n                // so the closing brace is not indented\n                self.s.offset(-self.ind);\n            } else if self.config.bracket_spacing {\n                self.nbsp();\n            };\n            self.end();\n        }\n        self.print_word(\"}\");\n\n        self.cursor.advance_to(span.hi(), true);\n        self.contract = None;\n    }\n\n    fn print_struct(&mut self, strukt: &'ast ast::ItemStruct<'ast>, span: Span) {\n        let ast::ItemStruct { name, fields } = strukt;\n        let ind = if self.estimate_size(name.span) + 8 >= self.space_left() { self.ind } else { 0 };\n        self.s.ibox(self.ind);\n        self.word(\"struct\");\n        self.space();\n        self.print_ident(name);\n        self.word(\" {\");\n        if !fields.is_empty() {\n            self.break_offset(SIZE_INFINITY as usize, ind);\n        }\n        self.s.ibox(0);\n        for var in fields.iter() {\n            self.print_var_def(var);\n            if !self.print_trailing_comment(var.span.hi(), None) {\n                self.hardbreak();\n            }\n        }\n        self.print_comments(span.hi(), CommentConfig::skip_ws());\n        if ind == 0 {\n            self.s.offset(-self.ind);\n        }\n        self.end();\n        self.end();\n        self.word(\"}\");\n    }\n\n    fn print_enum(&mut self, enm: &'ast ast::ItemEnum<'ast>, span: Span) {\n        let ast::ItemEnum { name, variants } = enm;\n        self.s.cbox(self.ind);\n        self.word(\"enum \");\n        self.print_ident(name);\n        self.word(\" {\");\n        self.hardbreak_if_nonempty();\n        for (pos, ident) in variants.iter().delimited() {\n            self.print_comments(ident.span.lo(), CommentConfig::default());\n            self.print_ident(ident);\n            if !pos.is_last {\n                self.word(\",\");\n            }\n            if !self.print_trailing_comment(ident.span.hi(), None) {\n                self.hardbreak();\n            }\n        }\n        self.print_comments(span.hi(), CommentConfig::skip_ws());\n        self.s.offset(-self.ind);\n        self.end();\n        self.word(\"}\");\n    }\n\n    fn print_udvt(&mut self, udvt: &'ast ast::ItemUdvt<'ast>) {\n        let ast::ItemUdvt { name, ty } = udvt;\n        self.word(\"type \");\n        self.print_ident(name);\n        self.word(\" is \");\n        self.print_ty(ty);\n        self.word(\";\");\n    }\n\n    // NOTE(rusowsky): Functions are the only source unit item that handle inline (disabled) format\n    fn print_function(&mut self, func: &'ast ast::ItemFunction<'ast>) {\n        let ast::ItemFunction { kind, ref header, ref body, body_span } = *func;\n        let ast::FunctionHeader {\n            name,\n            ref parameters,\n            visibility,\n            state_mutability: sm,\n            virtual_,\n            ref override_,\n            ref returns,\n            ..\n        } = *header;\n\n        self.s.cbox(self.ind);\n\n        // Print fn name and params\n        _ = self.handle_span(self.cursor.span(header.span.lo()), false);\n        self.print_word(kind.to_str());\n        if let Some(name) = name {\n            self.print_sep(Separator::Nbsp);\n            self.print_ident(&name);\n            self.cursor.advance_to(name.span.hi(), true);\n        }\n        self.s.cbox(-self.ind);\n        let header_style = self.config.multiline_func_header;\n        let params_format = match header_style {\n            MultilineFuncHeaderStyle::ParamsAlways => ListFormat::always_break(),\n            MultilineFuncHeaderStyle::All\n                if header.parameters.len() > 1 && !self.can_header_be_inlined(func) =>\n            {\n                ListFormat::always_break()\n            }\n            MultilineFuncHeaderStyle::AllParams\n                if !header.parameters.is_empty() && !self.can_header_be_inlined(func) =>\n            {\n                ListFormat::always_break()\n            }\n            _ => ListFormat::consistent().break_cmnts().break_single(\n                // ensure fn params are always breakable when there is a single `Contract.Struct`\n                parameters.len() == 1\n                    && matches!(\n                        &parameters[0].ty,\n                        ast::Type { kind: ast::TypeKind::Custom(ty), .. } if ty.segments().len() > 1\n                    ),\n            ),\n        };\n        self.print_parameter_list(parameters, parameters.span, params_format);\n        self.end();\n\n        // Map attributes to their corresponding comments\n        let (mut map, attributes, first_attrib_pos) =\n            AttributeCommentMapper::new(returns.as_ref(), body_span.lo()).build(self, header);\n\n        let mut handle_pre_cmnts = |this: &mut Self, span: Span| -> bool {\n            if this.inline_config.is_disabled(span)\n                // Note: `map` is still captured from the outer scope, which is fine.\n                && let Some((pre_cmnts, ..)) = map.remove(&span.lo())\n            {\n                for (pos, cmnt) in pre_cmnts.into_iter().delimited() {\n                    if pos.is_first && cmnt.style.is_isolated() && !this.is_bol_or_only_ind() {\n                        this.print_sep(Separator::Hardbreak);\n                    }\n                    if let Some(cmnt) = this.handle_comment(cmnt, false) {\n                        this.print_comment(cmnt, CommentConfig::skip_ws().mixed_post_nbsp());\n                    }\n                    if pos.is_last {\n                        return true;\n                    }\n                }\n            }\n            false\n        };\n\n        let skip_attribs = returns.as_ref().is_some_and(|ret| {\n            let attrib_span = Span::new(first_attrib_pos, ret.span.lo());\n            handle_pre_cmnts(self, attrib_span);\n            self.handle_span(attrib_span, false)\n        });\n        let skip_returns = {\n            let pos = if skip_attribs { self.cursor.pos } else { first_attrib_pos };\n            let ret_span = Span::new(pos, body_span.lo());\n            handle_pre_cmnts(self, ret_span);\n            self.handle_span(ret_span, false)\n        };\n\n        let attrib_box = self.config.multiline_func_header.params_first()\n            || (self.config.multiline_func_header.attrib_first()\n                && !self.can_header_params_be_inlined(func));\n        if attrib_box {\n            self.s.cbox(0);\n        }\n        if !(skip_attribs || skip_returns) {\n            // Print fn attributes in correct order\n            if let Some(v) = visibility {\n                self.print_fn_attribute(v.span, &mut map, &mut |s| s.word(v.to_str()));\n            }\n            if let Some(sm) = sm\n                && !matches!(*sm, ast::StateMutability::NonPayable)\n            {\n                self.print_fn_attribute(sm.span, &mut map, &mut |s| s.word(sm.to_str()));\n            }\n            if let Some(v) = virtual_ {\n                self.print_fn_attribute(v, &mut map, &mut |s| s.word(\"virtual\"));\n            }\n            if let Some(o) = override_ {\n                self.print_fn_attribute(o.span, &mut map, &mut |s| s.print_override(o));\n            }\n            for m in attributes.iter().filter(|a| matches!(a.kind, AttributeKind::Modifier(_))) {\n                if let AttributeKind::Modifier(modifier) = m.kind {\n                    let is_base = self.is_modifier_a_base_contract(kind, modifier);\n                    self.print_fn_attribute(m.span, &mut map, &mut |s| {\n                        s.print_modifier_call(modifier, is_base)\n                    });\n                }\n            }\n        }\n        if !skip_returns\n            && let Some(ret) = returns\n            && !ret.is_empty()\n        {\n            if !self.handle_span(self.cursor.span(ret.span.lo()), false) {\n                if !self.is_bol_or_only_ind() && !self.last_token_is_space() {\n                    self.print_sep(Separator::Space);\n                }\n                self.cursor.advance_to(ret.span.lo(), true);\n                self.print_word(\"returns \");\n            }\n            self.print_parameter_list(\n                ret,\n                ret.span,\n                ListFormat::consistent(), // .with_cmnts_break(false),\n            );\n        }\n\n        // Print fn body\n        if let Some(body) = body {\n            if self.handle_span(self.cursor.span(body_span.lo()), false) {\n                // Print spacing if necessary. Updates cursor.\n            } else {\n                if let Some(cmnt) = self.peek_comment_before(body_span.lo()) {\n                    if cmnt.style.is_mixed() {\n                        // These shouldn't update the cursor, as we've already dealt with it above\n                        self.space();\n                        self.s.offset(-self.ind);\n                        self.print_comments(body_span.lo(), CommentConfig::skip_ws());\n                    } else {\n                        self.zerobreak();\n                        self.s.offset(-self.ind);\n                        self.print_comments(body_span.lo(), CommentConfig::skip_ws());\n                        self.s.offset(-self.ind);\n                    }\n                } else {\n                    // If there are no modifiers, overrides, nor returns never break\n                    if header.modifiers.is_empty()\n                        && header.override_.is_none()\n                        && returns.as_ref().is_none_or(|r| r.is_empty())\n                        && (header.visibility().is_none() || body.is_empty())\n                    {\n                        self.nbsp();\n                    } else {\n                        self.space();\n                        self.s.offset(-self.ind);\n                    }\n                }\n                self.cursor.advance_to(body_span.lo(), true);\n            }\n            self.print_word(\"{\");\n            self.end();\n            if attrib_box {\n                self.end();\n            }\n\n            self.print_block_without_braces(body, body_span.hi(), Some(self.ind));\n            if self.cursor.enabled || self.cursor.pos < body_span.hi() {\n                self.print_word(\"}\");\n                self.cursor.advance_to(body_span.hi(), true);\n            }\n        } else {\n            self.print_comments(body_span.lo(), CommentConfig::skip_ws().mixed_prev_space());\n            self.end();\n            if attrib_box {\n                self.end();\n            }\n            self.neverbreak();\n            self.print_word(\";\");\n        }\n\n        if let Some(cmnt) = self.peek_trailing_comment(body_span.hi(), None) {\n            if cmnt.is_doc {\n                // trailing doc comments after the fn body are isolated\n                // these shouldn't update the cursor, as this is our own formatting\n                self.hardbreak();\n                self.hardbreak();\n            }\n            self.print_trailing_comment(body_span.hi(), None);\n        }\n    }\n\n    fn print_fn_attribute(\n        &mut self,\n        span: Span,\n        map: &mut AttributeCommentMap,\n        print_fn: &mut dyn FnMut(&mut Self),\n    ) {\n        match map.remove(&span.lo()) {\n            Some((pre_cmnts, inner_cmnts, post_cmnts)) => {\n                // Print preceding comments.\n                for cmnt in pre_cmnts {\n                    let Some(cmnt) = self.handle_comment(cmnt, false) else {\n                        continue;\n                    };\n                    self.print_comment(cmnt, CommentConfig::default());\n                }\n                // Push the inner comments back to the queue, so that they are printed in their\n                // intended place.\n                for cmnt in inner_cmnts.into_iter().rev() {\n                    self.comments.push_front(cmnt);\n                }\n                let mut enabled = false;\n                if !self.handle_span(span, false) {\n                    if !self.is_bol_or_only_ind() {\n                        self.space();\n                    }\n                    self.ibox(0);\n                    print_fn(self);\n                    self.cursor.advance_to(span.hi(), true);\n                    enabled = true;\n                }\n                // Print subsequent comments.\n                for cmnt in post_cmnts {\n                    let Some(cmnt) = self.handle_comment(cmnt, false) else {\n                        continue;\n                    };\n                    self.print_comment(cmnt, CommentConfig::default().mixed_prev_space());\n                }\n                if enabled {\n                    self.end();\n                }\n            }\n            // Fallback for attributes not in the map (should never happen)\n            None => {\n                if !self.is_bol_or_only_ind() {\n                    self.space();\n                }\n                print_fn(self);\n                self.cursor.advance_to(span.hi(), true);\n            }\n        }\n    }\n\n    fn is_modifier_a_base_contract(\n        &self,\n        kind: ast::FunctionKind,\n        modifier: &'ast ast::Modifier<'ast>,\n    ) -> bool {\n        // Add `()` in functions when the modifier is a base contract.\n        // HACK: heuristics:\n        // 1. exactly matches the name of a base contract as declared in the `contract is`;\n        // this does not account for inheritance;\n        let is_contract_base = self.contract.is_some_and(|contract| {\n            contract\n                .bases\n                .iter()\n                .any(|contract_base| contract_base.name.to_string() == modifier.name.to_string())\n        });\n        // 2. assume that title case names in constructors are bases.\n        // LEGACY: constructors used to also be `function NameOfContract...`; not checked.\n        let is_constructor = matches!(kind, ast::FunctionKind::Constructor);\n        // LEGACY: we are checking the beginning of the path, not the last segment.\n        is_contract_base\n            || (is_constructor\n                && modifier.name.first().name.as_str().starts_with(char::is_uppercase))\n    }\n\n    fn print_error(&mut self, err: &'ast ast::ItemError<'ast>) {\n        let ast::ItemError { name, parameters } = err;\n        self.word(\"error \");\n        self.print_ident(name);\n        self.print_parameter_list(\n            parameters,\n            parameters.span,\n            if self.config.prefer_compact.errors() {\n                ListFormat::compact()\n            } else {\n                ListFormat::consistent()\n            },\n        );\n        self.word(\";\");\n    }\n\n    fn print_event(&mut self, event: &'ast ast::ItemEvent<'ast>) {\n        let ast::ItemEvent { name, parameters, anonymous } = event;\n        self.word(\"event \");\n        self.print_ident(name);\n        self.print_parameter_list(\n            parameters,\n            parameters.span,\n            if self.config.prefer_compact.events() {\n                ListFormat::compact().break_cmnts()\n            } else {\n                ListFormat::consistent().break_cmnts()\n            },\n        );\n        if *anonymous {\n            self.word(\" anonymous\");\n        }\n        self.word(\";\");\n    }\n\n    fn print_var_def(&mut self, var: &'ast ast::VariableDefinition<'ast>) {\n        self.print_var(var, true);\n        self.word(\";\");\n    }\n\n    /// Prints the RHS of an assignment or variable initializer.\n    fn print_assign_rhs(\n        &mut self,\n        rhs: &'ast ast::Expr<'ast>,\n        lhs_size: usize,\n        space_left: usize,\n        ty: Option<&ast::TypeKind<'ast>>,\n        cache: bool,\n    ) {\n        // Check if the total expression overflows but the RHS would fit alone on a new line.\n        // This helps keep the RHS together on a single line when possible.\n        let rhs_size = self.estimate_size(rhs.span);\n        let overflows = lhs_size + rhs_size >= space_left;\n        let fits_alone = rhs_size + self.config.tab_width < space_left;\n        let fits_alone_no_cmnts =\n            fits_alone && !self.has_comment_between(rhs.span.lo(), rhs.span.hi());\n        let force_break = overflows && fits_alone_no_cmnts;\n\n        if lhs_size <= space_left {\n            self.neverbreak();\n        }\n\n        // Handle comments before the RHS expression\n        if let Some(cmnt) = self.peek_comment_before(rhs.span.lo())\n            && self.inline_config.is_disabled(cmnt.span)\n        {\n            self.print_sep(Separator::Nbsp);\n        }\n        if self\n            .print_comments(\n                rhs.span.lo(),\n                CommentConfig::skip_ws().mixed_no_break().mixed_prev_space(),\n            )\n            .is_some_and(|cmnt| cmnt.is_trailing())\n        {\n            self.break_offset_if_not_bol(SIZE_INFINITY as usize, self.ind, false);\n        }\n\n        // Match on expression kind to determine formatting strategy\n        match &rhs.kind {\n            ast::ExprKind::Lit(lit, ..) if lit.is_str_concatenation() => {\n                // String concatenations stay on the same line with nbsp\n                self.print_sep(Separator::Nbsp);\n                self.neverbreak();\n                self.s.ibox(self.ind);\n                self.print_expr(rhs);\n                self.end();\n            }\n            ast::ExprKind::Lit(..) if ty.is_none() && !fits_alone => {\n                // Long string in assign expr goes on its own line\n                self.print_sep(Separator::Space);\n                self.s.offset(self.ind);\n                self.print_expr(rhs);\n            }\n            ast::ExprKind::Binary(lhs, op, _) => {\n                let print_inline = |this: &mut Self| {\n                    this.print_sep(Separator::Nbsp);\n                    this.neverbreak();\n                    this.print_expr(rhs);\n                };\n                let print_with_break = |this: &mut Self, force_break: bool| {\n                    if !this.is_bol_or_only_ind() {\n                        if force_break {\n                            this.print_sep(Separator::Hardbreak);\n                        } else {\n                            this.print_sep(Separator::Space);\n                        }\n                    }\n                    this.s.offset(this.ind);\n                    this.s.ibox(this.ind);\n                    this.print_expr(rhs);\n                    this.end();\n                };\n\n                // Binary expressions: check if we need to break and indent\n                if force_break {\n                    print_with_break(self, true);\n                } else if self.estimate_lhs_size(rhs, op) + lhs_size > space_left {\n                    if has_complex_successor(&rhs.kind, true)\n                        && get_callee_head_size(lhs) + lhs_size <= space_left\n                    {\n                        // Keep complex exprs (where callee fits) inline, as they will have breaks\n                        if matches!(lhs.kind, ast::ExprKind::Call(..)) {\n                            self.s.ibox(-self.ind);\n                            print_inline(self);\n                            self.end();\n                        } else {\n                            print_inline(self);\n                        }\n                    } else {\n                        print_with_break(self, false);\n                    }\n                }\n                // Otherwise, if expr fits, ensure no breaks\n                else {\n                    print_inline(self);\n                }\n            }\n            _ => {\n                // General case: handle calls, complex successors, and other expressions\n                let callee_doesnt_fit = if let ast::ExprKind::Call(call_expr, ..) = &rhs.kind {\n                    let callee_size = get_callee_head_size(call_expr);\n                    callee_size + lhs_size > space_left\n                        && callee_size + self.config.tab_width < space_left\n                } else {\n                    false\n                };\n\n                if (lhs_size + 1 >= space_left && !is_call_chain(&rhs.kind, false))\n                    || callee_doesnt_fit\n                {\n                    self.s.ibox(self.ind);\n                } else {\n                    self.s.ibox(0);\n                };\n\n                if has_complex_successor(&rhs.kind, true)\n                    && !matches!(&rhs.kind, ast::ExprKind::Member(..))\n                {\n                    // delegate breakpoints to `self.commasep(..)` for complex successors\n                    if !self.is_bol_or_only_ind() {\n                        let needs_offset = !callee_doesnt_fit\n                            && rhs_size + lhs_size + 1 >= space_left\n                            && fits_alone_no_cmnts;\n                        let separator = if callee_doesnt_fit || needs_offset {\n                            Separator::Space\n                        } else {\n                            Separator::Nbsp\n                        };\n                        self.print_sep(separator);\n                        if needs_offset {\n                            self.s.offset(self.ind);\n                        }\n                    }\n                } else {\n                    if !self.is_bol_or_only_ind() {\n                        self.print_sep_unhandled(Separator::Space);\n                    }\n                    // apply type-dependent indentation if type info is available\n                    if let Some(ty) = ty\n                        && matches!(ty, ast::TypeKind::Elementary(..) | ast::TypeKind::Mapping(..))\n                    {\n                        self.s.offset(self.ind);\n                    }\n                }\n                self.print_expr(rhs);\n                self.end();\n            }\n        }\n\n        self.var_init = cache;\n    }\n\n    fn print_var(&mut self, var: &'ast ast::VariableDefinition<'ast>, is_var_def: bool) {\n        let ast::VariableDefinition {\n            span,\n            ty,\n            visibility,\n            mutability,\n            data_location,\n            override_,\n            indexed,\n            name,\n            initializer,\n        } = var;\n\n        if self.handle_span(*span, false) {\n            return;\n        }\n\n        // NOTE(rusowsky): this is hacky but necessary to properly estimate if we figure out if we\n        // have double breaks (which should have double indentation) or not.\n        // Alternatively, we could achieve the same behavior with a new box group that supports\n        // \"continuation\" which would only increase indentation if its parent box broke.\n        let init_space_left = self.space_left();\n        let mut pre_init_size = self.estimate_size(ty.span);\n\n        // Non-elementary types use commasep which has its own padding.\n        self.s.ibox(0);\n        if override_.is_some() {\n            self.s.cbox(self.ind);\n        } else {\n            self.s.ibox(self.ind);\n        }\n        self.print_ty(ty);\n\n        self.print_attribute(visibility.map(|v| v.to_str()), is_var_def, &mut pre_init_size);\n        self.print_attribute(mutability.map(|m| m.to_str()), is_var_def, &mut pre_init_size);\n        self.print_attribute(data_location.map(|d| d.to_str()), is_var_def, &mut pre_init_size);\n\n        if let Some(override_) = override_ {\n            if self\n                .print_comments(override_.span.lo(), CommentConfig::skip_ws().mixed_prev_space())\n                .is_none()\n            {\n                self.print_sep(Separator::SpaceOrNbsp(is_var_def));\n            }\n            self.ibox(0);\n            self.print_override(override_);\n            pre_init_size += self.estimate_size(override_.span) + 1;\n        }\n\n        if *indexed {\n            self.print_attribute(indexed.then_some(\"indexed\"), is_var_def, &mut pre_init_size);\n        }\n\n        if let Some(ident) = name {\n            self.print_sep(Separator::SpaceOrNbsp(is_var_def && override_.is_none()));\n            self.print_comments(\n                ident.span.lo(),\n                CommentConfig::skip_ws().mixed_no_break().mixed_post_nbsp(),\n            );\n            self.print_ident(ident);\n            pre_init_size += self.estimate_size(ident.span) + 1;\n        }\n        if let Some(init) = initializer {\n            let cache = self.var_init;\n            self.var_init = true;\n\n            pre_init_size += 2;\n            self.print_word(\" =\");\n            if override_.is_some() {\n                self.end();\n            }\n            self.end();\n\n            self.print_assign_rhs(init, pre_init_size, init_space_left, Some(&ty.kind), cache);\n        } else {\n            self.end();\n        }\n        self.end();\n    }\n\n    fn print_attribute(\n        &mut self,\n        attribute: Option<&'static str>,\n        is_var_def: bool,\n        size: &mut usize,\n    ) {\n        if let Some(s) = attribute {\n            self.print_sep(Separator::SpaceOrNbsp(is_var_def));\n            self.print_word(s);\n            *size += s.len() + 1;\n        }\n    }\n\n    fn print_parameter_list(\n        &mut self,\n        parameters: &'ast [ast::VariableDefinition<'ast>],\n        span: Span,\n        format: ListFormat,\n    ) {\n        if self.handle_span(span, false) {\n            return;\n        }\n\n        self.print_tuple(\n            parameters,\n            span.lo(),\n            span.hi(),\n            |fmt, var| fmt.print_var(var, false),\n            get_span!(),\n            format,\n        );\n    }\n\n    fn print_ident_or_strlit(&mut self, value: &'ast ast::IdentOrStrLit) {\n        match value {\n            ast::IdentOrStrLit::Ident(ident) => self.print_ident(ident),\n            ast::IdentOrStrLit::StrLit(strlit) => self.print_ast_str_lit(strlit),\n        }\n    }\n\n    /// Prints a raw AST string literal, which is unescaped.\n    fn print_ast_str_lit(&mut self, strlit: &'ast ast::StrLit) {\n        self.print_str_lit(ast::StrKind::Str, strlit.span.lo(), strlit.value.as_str());\n    }\n\n    fn print_lit(&mut self, lit: &'ast ast::Lit<'ast>) {\n        self.print_lit_inner(lit, false);\n    }\n\n    fn print_ty(&mut self, ty: &'ast ast::Type<'ast>) {\n        if self.handle_span(ty.span, false) {\n            return;\n        }\n\n        match &ty.kind {\n            &ast::TypeKind::Elementary(ty) => 'b: {\n                match ty {\n                    // `address payable` is normalized to `address`.\n                    ast::ElementaryType::Address(true) => {\n                        self.word(\"address payable\");\n                        break 'b;\n                    }\n                    // Integers are normalized to long form.\n                    ast::ElementaryType::Int(size) | ast::ElementaryType::UInt(size) => {\n                        match (self.config.int_types, size.bits_raw()) {\n                            (config::IntTypes::Short, 0 | 256)\n                            | (config::IntTypes::Preserve, 0) => {\n                                let short = match ty {\n                                    ast::ElementaryType::Int(_) => \"int\",\n                                    ast::ElementaryType::UInt(_) => \"uint\",\n                                    _ => unreachable!(),\n                                };\n                                self.word(short);\n                                break 'b;\n                            }\n                            _ => {}\n                        }\n                    }\n                    _ => {}\n                }\n                self.word(ty.to_abi_str());\n            }\n            ast::TypeKind::Array(ast::TypeArray { element, size }) => {\n                self.print_ty(element);\n                if let Some(size) = size {\n                    self.word(\"[\");\n                    self.print_expr(size);\n                    self.word(\"]\");\n                } else {\n                    self.word(\"[]\");\n                }\n            }\n            ast::TypeKind::Function(ast::TypeFunction {\n                parameters,\n                visibility,\n                state_mutability,\n                returns,\n            }) => {\n                self.cbox(0);\n                self.word(\"function\");\n                self.print_parameter_list(parameters, parameters.span, ListFormat::inline());\n\n                if let Some(v) = visibility {\n                    self.space();\n                    self.word(v.to_str());\n                }\n                if let Some(sm) = state_mutability\n                    && !matches!(**sm, ast::StateMutability::NonPayable)\n                {\n                    self.space();\n                    self.word(sm.to_str());\n                }\n                if let Some(ret) = returns\n                    && !ret.is_empty()\n                {\n                    self.nbsp();\n                    self.word(\"returns\");\n                    self.nbsp();\n                    self.print_parameter_list(\n                        ret,\n                        ret.span,\n                        ListFormat::consistent(), // .with_cmnts_break(false),\n                    );\n                }\n                self.end();\n            }\n            ast::TypeKind::Mapping(ast::TypeMapping { key, key_name, value, value_name }) => {\n                self.word(\"mapping(\");\n                self.s.cbox(0);\n                if let Some(cmnt) = self.peek_comment_before(key.span.lo()) {\n                    if cmnt.style.is_mixed() {\n                        self.print_comments(\n                            key.span.lo(),\n                            CommentConfig::skip_ws().mixed_no_break().mixed_prev_space(),\n                        );\n                        self.break_offset_if_not_bol(SIZE_INFINITY as usize, 0, false);\n                    } else {\n                        self.print_comments(key.span.lo(), CommentConfig::skip_ws());\n                    }\n                }\n                // Fitting a mapping in one line takes, at least, 16 chars (one-char var name):\n                // 'mapping(' + {key} + ' => ' {value} ') ' + {name} + ';'\n                // To be more conservative, we use 18 to decide whether to force a break or not.\n                else if 18\n                    + self.estimate_size(key.span)\n                    + key_name.map(|k| self.estimate_size(k.span)).unwrap_or(0)\n                    + self.estimate_size(value.span)\n                    + value_name.map(|v| self.estimate_size(v.span)).unwrap_or(0)\n                    >= self.space_left()\n                {\n                    self.hardbreak();\n                } else {\n                    self.zerobreak();\n                }\n                self.s.cbox(0);\n                self.print_ty(key);\n                if let Some(ident) = key_name {\n                    if self\n                        .print_comments(\n                            ident.span.lo(),\n                            CommentConfig::skip_ws()\n                                .mixed_no_break()\n                                .mixed_prev_space()\n                                .mixed_post_nbsp(),\n                        )\n                        .is_none()\n                    {\n                        self.nbsp();\n                    }\n                    self.print_ident(ident);\n                }\n                // NOTE(rusowsky): unless we add more spans to solar, using `value.span.lo()`\n                // consumes \"comment6\" of which should be printed after the `=>`\n                self.print_comments(\n                    value.span.lo(),\n                    CommentConfig::skip_ws()\n                        .trailing_no_break()\n                        .mixed_no_break()\n                        .mixed_prev_space(),\n                );\n                self.space();\n                self.s.offset(self.ind);\n                self.word(\"=> \");\n                self.s.ibox(self.ind);\n                self.print_ty(value);\n                if let Some(ident) = value_name {\n                    self.neverbreak();\n                    if self\n                        .print_comments(\n                            ident.span.lo(),\n                            CommentConfig::skip_ws()\n                                .mixed_no_break()\n                                .mixed_prev_space()\n                                .mixed_post_nbsp(),\n                        )\n                        .is_none()\n                    {\n                        self.nbsp();\n                    }\n                    self.print_ident(ident);\n                    if self\n                        .peek_comment_before(ty.span.hi())\n                        .is_some_and(|cmnt| cmnt.style.is_mixed())\n                    {\n                        self.neverbreak();\n                        self.print_comments(\n                            value.span.lo(),\n                            CommentConfig::skip_ws().mixed_no_break(),\n                        );\n                    }\n                }\n                self.end();\n                self.end();\n                if self\n                    .print_comments(\n                        ty.span.hi(),\n                        CommentConfig::skip_ws().mixed_no_break().mixed_prev_space(),\n                    )\n                    .is_some_and(|cmnt| !cmnt.is_mixed())\n                {\n                    self.break_offset_if_not_bol(0, -self.ind, false);\n                } else {\n                    self.zerobreak();\n                    self.s.offset(-self.ind);\n                }\n                self.end();\n                self.word(\")\");\n            }\n            ast::TypeKind::Custom(path) => self.print_path(path, false),\n        }\n    }\n\n    fn print_override(&mut self, override_: &'ast ast::Override<'ast>) {\n        let ast::Override { span, paths } = override_;\n        if self.handle_span(*span, false) {\n            return;\n        }\n        self.word(\"override\");\n        if !paths.is_empty() {\n            if self.config.override_spacing {\n                self.nbsp();\n            }\n            self.print_tuple(\n                paths,\n                span.lo(),\n                span.hi(),\n                |this, path| this.print_path(path, false),\n                get_span!(()),\n                ListFormat::consistent(), // .with_cmnts_break(false),\n            );\n        }\n    }\n\n    /* --- Expressions --- */\n    /// Prints an expression by matching on its variant and delegating to the appropriate\n    /// printer method, handling all Solidity expression kinds.\n    fn print_expr(&mut self, expr: &'ast ast::Expr<'ast>) {\n        let ast::Expr { span, ref kind } = *expr;\n        if self.handle_span(span, false) {\n            return;\n        }\n\n        match kind {\n            ast::ExprKind::Array(exprs) => {\n                self.print_array(exprs, expr.span, |this, e| this.print_expr(e), get_span!())\n            }\n            ast::ExprKind::Assign(lhs, None, rhs) => self.print_assign_expr(lhs, rhs),\n            ast::ExprKind::Assign(lhs, Some(op), rhs) => self.print_bin_expr(lhs, op, rhs, true),\n            ast::ExprKind::Binary(lhs, op, rhs) => self.print_bin_expr(lhs, op, rhs, false),\n            ast::ExprKind::Call(call_expr, call_args) => {\n                let cache = self.call_with_opts_and_args;\n                self.call_with_opts_and_args = is_call_with_opts_and_args(&expr.kind);\n                self.print_member_or_call_chain(\n                    call_expr,\n                    MemberOrCallArgs::CallArgs(\n                        self.estimate_size(call_args.span),\n                        self.has_comments_between_elements(call_args.span, call_args.exprs()),\n                    ),\n                    |s| {\n                        s.print_call_args(\n                            call_args,\n                            ListFormat::compact()\n                                .break_cmnts()\n                                .break_single(true)\n                                .without_ind(s.return_bin_expr)\n                                .with_delimiters(!s.call_with_opts_and_args),\n                            get_callee_head_size(call_expr),\n                        );\n                    },\n                );\n                self.call_with_opts_and_args = cache;\n            }\n            ast::ExprKind::CallOptions(expr, named_args) => {\n                // the flag is only meant to be used to format the call args\n                let cache = self.call_with_opts_and_args;\n                self.call_with_opts_and_args = false;\n\n                self.print_expr(expr);\n                self.print_named_args(named_args, span.hi());\n\n                // restore cached value\n                self.call_with_opts_and_args = cache;\n            }\n            ast::ExprKind::Delete(expr) => {\n                self.word(\"delete \");\n                self.print_expr(expr);\n            }\n            ast::ExprKind::Ident(ident) => self.print_ident(ident),\n            ast::ExprKind::Index(expr, kind) => self.print_index_expr(span, expr, kind),\n            ast::ExprKind::Lit(lit, unit) => {\n                self.print_lit(lit);\n                if let Some(unit) = unit {\n                    self.nbsp();\n                    self.word(unit.to_str());\n                }\n            }\n            ast::ExprKind::Member(member_expr, ident) => {\n                self.print_member_or_call_chain(\n                    member_expr,\n                    MemberOrCallArgs::Member(self.estimate_size(ident.span)),\n                    |s| {\n                        s.print_trailing_comment(member_expr.span.hi(), Some(ident.span.lo()));\n                        match member_expr.kind {\n                            ast::ExprKind::Ident(_) | ast::ExprKind::Type(_) => (),\n                            ast::ExprKind::Index(..) if s.skip_index_break => (),\n                            // Don't add break when accessing a field after a call with named args.\n                            // e.g., `_lzSend({_dstEid: x, ...}).guid` should keep `.guid`\n                            // on the same line as the closing `})`.\n                            // See: https://github.com/foundry-rs/foundry/issues/12399\n                            _ if is_call_with_named_args(&member_expr.kind) => (),\n                            _ => s.zerobreak(),\n                        }\n                        s.word(\".\");\n                        s.print_ident(ident);\n                    },\n                );\n            }\n            ast::ExprKind::New(ty) => {\n                self.word(\"new \");\n                self.print_ty(ty);\n            }\n            ast::ExprKind::Payable(args) => {\n                self.word(\"payable\");\n                self.print_call_args(args, ListFormat::compact().break_cmnts(), 7);\n            }\n            ast::ExprKind::Ternary(cond, then, els) => self.print_ternary_expr(cond, then, els),\n            ast::ExprKind::Tuple(exprs) => self.print_tuple(\n                exprs,\n                span.lo(),\n                span.hi(),\n                |this, expr| match expr.as_ref() {\n                    SpannedOption::Some(expr) => this.print_expr(expr),\n                    SpannedOption::None(span) => {\n                        this.print_comments(span.hi(), CommentConfig::skip_ws().no_breaks());\n                    }\n                },\n                |expr| match expr.as_ref() {\n                    SpannedOption::Some(expr) => expr.span,\n                    // Manually handled by printing the comment when `None`\n                    SpannedOption::None(..) => Span::DUMMY,\n                },\n                ListFormat::compact().break_single(is_binary_expr(&expr.kind)),\n            ),\n            ast::ExprKind::TypeCall(ty) => {\n                self.word(\"type\");\n                self.print_tuple(\n                    std::slice::from_ref(ty),\n                    span.lo(),\n                    span.hi(),\n                    Self::print_ty,\n                    get_span!(),\n                    ListFormat::consistent(),\n                );\n            }\n            ast::ExprKind::Type(ty) => self.print_ty(ty),\n            ast::ExprKind::Unary(un_op, expr) => {\n                let prefix = un_op.kind.is_prefix();\n                let op = un_op.kind.to_str();\n                if prefix {\n                    self.word(op);\n                }\n                self.print_expr(expr);\n                if !prefix {\n                    debug_assert!(un_op.kind.is_postfix());\n                    self.word(op);\n                }\n            }\n        }\n        self.cursor.advance_to(span.hi(), true);\n    }\n\n    /// Prints a simple assignment expression of the form `lhs = rhs`.\n    fn print_assign_expr(&mut self, lhs: &'ast ast::Expr<'ast>, rhs: &'ast ast::Expr<'ast>) {\n        let cache = self.var_init;\n        self.var_init = true;\n\n        let space_left = self.space_left();\n        let lhs_size = self.estimate_size(lhs.span);\n        self.print_expr(lhs);\n        self.word(\" =\");\n        self.print_assign_rhs(rhs, lhs_size + 2, space_left, None, cache);\n    }\n\n    /// Prints a binary operator expression. Handles operator chains and formatting.\n    fn print_bin_expr(\n        &mut self,\n        lhs: &'ast ast::Expr<'ast>,\n        bin_op: &ast::BinOp,\n        rhs: &'ast ast::Expr<'ast>,\n        is_assign: bool,\n    ) {\n        let prev_chain = self.binary_expr;\n        let is_chain = prev_chain.is_some_and(|prev| prev == bin_op.kind.group());\n\n        // Opening box if starting a new operator chain.\n        if !is_chain {\n            self.binary_expr = Some(bin_op.kind.group());\n\n            let indent = if (is_assign && has_complex_successor(&rhs.kind, true))\n                || self.call_stack.is_nested()\n                    && is_call_chain(&lhs.kind, false)\n                    && self.estimate_size(lhs.span) >= self.space_left()\n            {\n                0\n            } else {\n                self.ind\n            };\n            self.s.ibox(indent);\n        }\n\n        // Print LHS.\n        self.print_expr(lhs);\n\n        // Handle assignment (`+=`, etc.) vs binary ops (`+`, `*`, etc.).\n        let no_trailing_comment = !self.print_trailing_comment(lhs.span.hi(), Some(rhs.span.lo()));\n        if is_assign {\n            if no_trailing_comment {\n                self.nbsp();\n            }\n            self.word(bin_op.kind.to_str());\n            self.word(\"= \");\n        } else {\n            if no_trailing_comment\n                && self\n                    .print_comments(\n                        bin_op.span.lo(),\n                        CommentConfig::skip_ws().mixed_no_break().mixed_prev_space(),\n                    )\n                    .is_none_or(|cmnt| cmnt.is_mixed())\n            {\n                if !self.config.pow_no_space || !matches!(bin_op.kind, ast::BinOpKind::Pow) {\n                    self.space_if_not_bol();\n                } else if !self.is_bol_or_only_ind() && !self.last_token_is_break() {\n                    self.zerobreak();\n                }\n            }\n\n            self.word(bin_op.kind.to_str());\n\n            if !self.config.pow_no_space || !matches!(bin_op.kind, ast::BinOpKind::Pow) {\n                self.nbsp();\n            }\n        }\n\n        // Print RHS with optional ibox if mixed comment precedes.\n        let rhs_has_mixed_comment =\n            self.peek_comment_before(rhs.span.lo()).is_some_and(|cmnt| cmnt.style.is_mixed());\n        if rhs_has_mixed_comment {\n            self.ibox(0);\n            self.print_expr(rhs);\n            self.end();\n        } else {\n            self.print_expr(rhs);\n        }\n\n        // End current box if this was top-level in the chain.\n        if !is_chain {\n            self.binary_expr = prev_chain;\n            self.end();\n        }\n    }\n\n    /// Prints an indexing expression.\n    fn print_index_expr(\n        &mut self,\n        span: Span,\n        expr: &'ast ast::Expr<'ast>,\n        kind: &'ast ast::IndexKind<'ast>,\n    ) {\n        self.print_expr(expr);\n        self.word(\"[\");\n        self.s.cbox(self.ind);\n\n        let mut skip_break = false;\n        let mut zerobreak = |this: &mut Self| {\n            if this.skip_index_break {\n                skip_break = true;\n            } else {\n                this.zerobreak();\n            }\n        };\n        match kind {\n            ast::IndexKind::Index(Some(inner_expr)) => {\n                zerobreak(self);\n                self.print_expr(inner_expr);\n            }\n            ast::IndexKind::Index(None) => {}\n            ast::IndexKind::Range(start, end) => {\n                if let Some(start_expr) = start {\n                    if self\n                        .print_comments(start_expr.span.lo(), CommentConfig::skip_ws())\n                        .is_none_or(|s| s.is_mixed())\n                    {\n                        zerobreak(self);\n                    }\n                    self.print_expr(start_expr);\n                } else {\n                    zerobreak(self);\n                }\n\n                self.word(\":\");\n\n                if let Some(end_expr) = end {\n                    self.s.ibox(self.ind);\n                    if start.is_some() {\n                        zerobreak(self);\n                    }\n                    self.print_comments(\n                        end_expr.span.lo(),\n                        CommentConfig::skip_ws()\n                            .mixed_prev_space()\n                            .mixed_no_break()\n                            .mixed_post_nbsp(),\n                    );\n                    self.print_expr(end_expr);\n                }\n\n                // Trailing comment handling.\n                let mut is_trailing = false;\n                if let Some(style) = self.print_comments(\n                    span.hi(),\n                    CommentConfig::skip_ws().mixed_no_break().mixed_prev_space(),\n                ) {\n                    skip_break = true;\n                    is_trailing = style.is_trailing();\n                }\n\n                // Adjust indentation and line breaks.\n                match (skip_break, end.is_some()) {\n                    (true, true) => {\n                        self.break_offset_if_not_bol(0, -2 * self.ind, false);\n                        self.end();\n                        if !is_trailing {\n                            self.break_offset_if_not_bol(0, -self.ind, false);\n                        }\n                    }\n                    (true, false) => {\n                        self.break_offset_if_not_bol(0, -self.ind, false);\n                    }\n                    (false, true) => {\n                        self.end();\n                    }\n                    _ => {}\n                }\n            }\n        }\n\n        if !skip_break {\n            self.zerobreak();\n            self.s.offset(-self.ind);\n        }\n\n        self.end();\n        self.word(\"]\");\n    }\n\n    /// Prints a ternary expression of the form `cond ? then : else`.\n    fn print_ternary_expr(\n        &mut self,\n        cond: &'ast ast::Expr<'ast>,\n        then: &'ast ast::Expr<'ast>,\n        els: &'ast ast::Expr<'ast>,\n    ) {\n        self.s.cbox(self.ind);\n        self.s.ibox(0);\n\n        let print_sub_expr = |this: &mut Self, span_lo, prefix, expr: &'ast ast::Expr<'ast>| {\n            match prefix {\n                Some(prefix) => {\n                    if this.peek_comment_before(span_lo).is_some() {\n                        this.space();\n                    }\n                    this.print_comments(span_lo, CommentConfig::skip_ws());\n                    this.end();\n                    if !this.is_bol_or_only_ind() {\n                        this.space();\n                    }\n                    this.s.ibox(0);\n                    this.word(prefix);\n                }\n                None => {\n                    this.print_comments(expr.span.lo(), CommentConfig::skip_ws());\n                }\n            };\n            this.print_expr(expr);\n        };\n\n        // conditional expression\n        self.s.ibox(-self.ind);\n        print_sub_expr(self, then.span.lo(), None, cond);\n        self.end();\n        // then expression\n        print_sub_expr(self, then.span.lo(), Some(\"? \"), then);\n        // else expression\n        print_sub_expr(self, els.span.lo(), Some(\": \"), els);\n\n        self.end();\n        self.neverbreak();\n        self.s.offset(-self.ind);\n        self.end();\n    }\n\n    // If `add_parens_if_empty` is true, then add parentheses `()` even if there are no arguments.\n    fn print_modifier_call(\n        &mut self,\n        modifier: &'ast ast::Modifier<'ast>,\n        add_parens_if_empty: bool,\n    ) {\n        let ast::Modifier { name, arguments } = modifier;\n        self.print_path(name, false);\n        if !arguments.is_empty() || add_parens_if_empty {\n            self.print_call_args(\n                arguments,\n                ListFormat::compact().break_cmnts(),\n                name.to_string().len(),\n            );\n        }\n    }\n\n    fn print_member_or_call_chain<F>(\n        &mut self,\n        child_expr: &'ast ast::Expr<'ast>,\n        member_or_args: MemberOrCallArgs,\n        print_suffix: F,\n    ) where\n        F: FnOnce(&mut Self),\n    {\n        fn member_depth(depth: usize, expr: &ast::Expr<'_>) -> usize {\n            if let ast::ExprKind::Member(child, ..) = &expr.kind {\n                member_depth(depth + 1, child)\n            } else {\n                depth\n            }\n        }\n\n        let (mut extra_box, skip_cache) = (false, self.skip_index_break);\n        let parent_is_chain = self.call_stack.last().copied().is_some_and(|call| call.is_chained());\n        if !parent_is_chain {\n            // Estimate sizes of callee and optional member\n            let callee_size = get_callee_head_size(child_expr) + member_or_args.member_size();\n            let expr_size = self.estimate_size(child_expr.span);\n\n            let callee_fits_line = self.space_left() > callee_size + 1;\n            let total_fits_line = self.space_left() > expr_size + member_or_args.size() + 2;\n            let no_cmnt_or_mixed =\n                self.peek_comment_before(child_expr.span.hi()).is_none_or(|c| c.style.is_mixed());\n\n            // If call with options, add an extra box to prioritize breaking the call args\n            if self.call_with_opts_and_args {\n                self.cbox(0);\n                extra_box = true;\n            }\n\n            // Determine if this chain will add its own indentation\n            let chain_has_indent = is_call_chain(&child_expr.kind, true)\n                || !(no_cmnt_or_mixed\n                    || matches!(&child_expr.kind, ast::ExprKind::CallOptions(..)))\n                || !callee_fits_line\n                || (member_depth(0, child_expr) >= 2\n                    && (!total_fits_line || member_or_args.has_comments()));\n\n            // Start a new chain if needed\n            if is_call_chain(&child_expr.kind, false) {\n                self.call_stack.push(CallContext::chained(callee_size, chain_has_indent));\n            }\n\n            if !chain_has_indent {\n                self.skip_index_break = true;\n                self.cbox(0);\n            } else {\n                self.s.ibox(self.ind);\n            }\n        }\n\n        // Recursively print the child/prefix expression.\n        self.print_expr(child_expr);\n\n        // If an extra box was opened, close it\n        if extra_box {\n            self.end();\n        }\n\n        // Call the closure to print the suffix for the current link, with the calculated position.\n        print_suffix(self);\n\n        // If a chain was started, clean up the state and end the box.\n        if !parent_is_chain {\n            if is_call_chain(&child_expr.kind, false) {\n                self.call_stack.pop();\n            }\n            self.end();\n        }\n\n        // Restore cache\n        if self.skip_index_break {\n            self.skip_index_break = skip_cache;\n        }\n    }\n\n    fn print_call_args(\n        &mut self,\n        args: &'ast ast::CallArgs<'ast>,\n        format: ListFormat,\n        callee_size: usize,\n    ) {\n        let ast::CallArgs { span, ref kind } = *args;\n        if self.handle_span(span, true) {\n            return;\n        }\n\n        self.call_stack.push(CallContext::nested(callee_size));\n\n        // Clear the binary expression cache before the call.\n        let cache = self.binary_expr.take();\n\n        match kind {\n            ast::CallArgsKind::Unnamed(exprs) => {\n                self.print_tuple(\n                    exprs,\n                    span.lo(),\n                    span.hi(),\n                    |this, e| this.print_expr(e),\n                    get_span!(),\n                    format,\n                );\n            }\n            ast::CallArgsKind::Named(named_args) => {\n                self.print_inside_parens(|state| state.print_named_args(named_args, span.hi()));\n            }\n        }\n\n        // Restore the cache to continue with the current chain.\n        self.binary_expr = cache;\n        self.call_stack.pop();\n    }\n\n    fn print_named_args(&mut self, args: &'ast [ast::NamedArg<'ast>], pos_hi: BytePos) {\n        let list_format = match (self.config.bracket_spacing, self.config.prefer_compact.calls()) {\n            (false, true) => ListFormat::compact(),\n            (false, false) => ListFormat::consistent(),\n            (true, true) => ListFormat::compact().with_space(),\n            (true, false) => ListFormat::consistent().with_space(),\n        };\n\n        self.word(\"{\");\n        // Use the start position of the first argument's name for comment processing.\n        if let Some(first_arg) = args.first() {\n            let list_lo = first_arg.name.span.lo();\n            self.commasep(\n                args,\n                list_lo,\n                pos_hi,\n                // Closure to print a single named argument (`name: value`)\n                |s, arg| {\n                    s.cbox(0);\n                    s.print_ident(&arg.name);\n                    s.word(\":\");\n                    if s.same_source_line(arg.name.span.hi(), arg.value.span.hi())\n                        || !s.print_trailing_comment(arg.name.span.hi(), None)\n                    {\n                        s.nbsp();\n                    }\n                    s.print_comments(\n                        arg.value.span.lo(),\n                        CommentConfig::skip_ws().mixed_no_break().mixed_post_nbsp(),\n                    );\n                    s.print_expr(arg.value);\n                    s.end();\n                },\n                |arg| arg.name.span.until(arg.value.span),\n                list_format\n                    .break_cmnts()\n                    .break_single(true)\n                    .without_ind(self.call_stack.has_chain_with_indent())\n                    .with_delimiters(!self.call_with_opts_and_args),\n            );\n        } else if self.config.bracket_spacing {\n            self.nbsp();\n        }\n        self.word(\"}\");\n    }\n\n    /* --- Statements --- */\n    /// Prints the given statement in the source code, handling formatting, inline documentation,\n    /// trailing comments and layout logic for various statement kinds.\n    fn print_stmt(&mut self, stmt: &'ast ast::Stmt<'ast>) {\n        let ast::Stmt { ref docs, span, ref kind } = *stmt;\n        self.print_docs(docs);\n\n        // Handle disabled statements.\n        if self.handle_span(span, false) {\n            self.print_trailing_comment_no_break(stmt.span.hi(), None);\n            return;\n        }\n\n        // return statements can't have a preceding comment in the same line.\n        let force_break = matches!(kind, ast::StmtKind::Return(..))\n            && self.peek_comment_before(span.lo()).is_some_and(|cmnt| cmnt.style.is_mixed());\n\n        match kind {\n            ast::StmtKind::Assembly(ast::StmtAssembly { dialect, flags, block }) => {\n                self.print_assembly_stmt(span, dialect, flags, block)\n            }\n            ast::StmtKind::DeclSingle(var) => self.print_var(var, true),\n            ast::StmtKind::DeclMulti(vars, init_expr) => {\n                self.print_multi_decl_stmt(span, vars, init_expr)\n            }\n            ast::StmtKind::Block(stmts) => self.print_block(stmts, span),\n            ast::StmtKind::Break => self.word(\"break\"),\n            ast::StmtKind::Continue => self.word(\"continue\"),\n            ast::StmtKind::DoWhile(stmt, cond) => {\n                self.word(\"do \");\n                self.print_stmt_as_block(stmt, cond.span.lo(), false);\n                self.nbsp();\n                self.print_if_cond(\"while\", cond, cond.span.hi());\n            }\n            ast::StmtKind::Emit(path, args) => self.print_emit_or_revert(\"emit\", path, args),\n            ast::StmtKind::Expr(expr) => self.print_expr(expr),\n            ast::StmtKind::For { init, cond, next, body } => {\n                self.print_for_stmt(span, init, cond, next, body)\n            }\n            ast::StmtKind::If(cond, then, els_opt) => self.print_if_stmt(span, cond, then, els_opt),\n            ast::StmtKind::Return(expr) => self.print_return_stmt(force_break, expr),\n            ast::StmtKind::Revert(path, args) => self.print_emit_or_revert(\"revert\", path, args),\n            ast::StmtKind::Try(ast::StmtTry { expr, clauses }) => {\n                self.print_try_stmt(expr, clauses)\n            }\n            ast::StmtKind::UncheckedBlock(block) => {\n                self.word(\"unchecked \");\n                self.print_block(block, stmt.span);\n            }\n            ast::StmtKind::While(cond, stmt) => {\n                // Check if blocks should be inlined and update cache if necessary\n                let inline = self.is_single_line_block(cond, stmt, None);\n                if !inline.is_cached && self.single_line_stmt.is_none() {\n                    self.single_line_stmt = Some(inline.outcome);\n                }\n\n                // Print while cond and its statement\n                self.print_if_cond(\"while\", cond, stmt.span.lo());\n                self.nbsp();\n                self.print_stmt_as_block(stmt, stmt.span.hi(), inline.outcome);\n\n                // Clear cache if necessary\n                if !inline.is_cached && self.single_line_stmt.is_some() {\n                    self.single_line_stmt = None;\n                }\n            }\n            ast::StmtKind::Placeholder => self.word(\"_\"),\n        }\n        if stmt_needs_semi(kind) {\n            self.neverbreak(); // semicolon shouldn't account for linebreaks\n            self.word(\";\");\n            self.cursor.advance_to(span.hi(), true);\n        }\n        // print comments without breaks, as those are handled by the caller.\n        self.print_comments(\n            stmt.span.hi(),\n            CommentConfig::default().trailing_no_break().mixed_no_break().mixed_prev_space(),\n        );\n        self.print_trailing_comment_no_break(stmt.span.hi(), None);\n    }\n\n    /// Prints an `assembly` statement, including optional dialect and flags,\n    /// followed by its Yul block.\n    fn print_assembly_stmt(\n        &mut self,\n        span: Span,\n        dialect: &'ast Option<ast::StrLit>,\n        flags: &'ast [ast::StrLit],\n        block: &'ast ast::yul::Block<'ast>,\n    ) {\n        _ = self.handle_span(self.cursor.span(span.lo()), false);\n        if !self.handle_span(span.until(block.span), false) {\n            self.cursor.advance_to(span.lo(), true);\n            self.print_word(\"assembly \"); // 9 chars\n            if let Some(dialect) = dialect {\n                self.print_ast_str_lit(dialect);\n                self.print_sep(Separator::Nbsp);\n            }\n            if !flags.is_empty() {\n                self.print_tuple(\n                    flags,\n                    span.lo(),\n                    block.span.lo(),\n                    Self::print_ast_str_lit,\n                    get_span!(),\n                    ListFormat::consistent(),\n                );\n                self.print_sep(Separator::Nbsp);\n            }\n        }\n        self.print_yul_block(block, block.span, false, 9);\n    }\n\n    /// Prints a multiple-variable declaration with a single initializer expression,\n    /// formatted as a tuple-style assignment (e.g., `(a, b) = foo();`).\n    fn print_multi_decl_stmt(\n        &mut self,\n        span: Span,\n        vars: &'ast BoxSlice<'ast, SpannedOption<ast::VariableDefinition<'ast>>>,\n        init_expr: &'ast ast::Expr<'ast>,\n    ) {\n        let space_left = self.space_left();\n\n        self.s.ibox(self.ind);\n        self.s.ibox(-self.ind);\n        self.print_tuple(\n            vars,\n            span.lo(),\n            init_expr.span.lo(),\n            |this, var| match var {\n                SpannedOption::Some(var) => this.print_var(var, true),\n                SpannedOption::None(span) => {\n                    this.print_comments(span.hi(), CommentConfig::skip_ws().mixed_no_break_post());\n                }\n            },\n            |var| match var {\n                SpannedOption::Some(var) => var.span,\n                // Manually handled by printing the comment when `None`\n                SpannedOption::None(..) => Span::DUMMY,\n            },\n            ListFormat::consistent(),\n        );\n        self.end();\n        self.word(\" =\");\n\n        if self.estimate_size(init_expr.span) + self.config.tab_width\n            <= std::cmp::max(space_left, self.space_left())\n        {\n            self.print_sep(Separator::Space);\n            self.ibox(0);\n        } else {\n            self.print_sep(Separator::Nbsp);\n            self.neverbreak();\n            self.s.ibox(-self.ind);\n        }\n        self.print_expr(init_expr);\n        self.end();\n        self.end();\n    }\n\n    /// Prints a `for` loop statement, including its initializer, condition,\n    /// increment expression, and loop body, with formatting and spacing.\n    fn print_for_stmt(\n        &mut self,\n        span: Span,\n        init: &'ast Option<&mut ast::Stmt<'ast>>,\n        cond: &'ast Option<&mut ast::Expr<'ast>>,\n        next: &'ast Option<&mut ast::Expr<'ast>>,\n        body: &'ast ast::Stmt<'ast>,\n    ) {\n        self.cbox(0);\n        self.s.ibox(self.ind);\n        self.print_word(\"for (\");\n        self.zerobreak();\n\n        // Print init.\n        self.s.cbox(0);\n        match init {\n            Some(init_stmt) => self.print_stmt(init_stmt),\n            None => self.print_word(\";\"),\n        }\n\n        // Print condition.\n        match cond {\n            Some(cond_expr) => {\n                self.print_sep(Separator::Space);\n                self.print_expr(cond_expr);\n            }\n            None => self.zerobreak(),\n        }\n        self.print_word(\";\");\n\n        // Print next clause.\n        match next {\n            Some(next_expr) => {\n                self.space();\n                self.print_expr(next_expr);\n            }\n            None => self.zerobreak(),\n        }\n\n        // Close head.\n        self.break_offset_if_not_bol(0, -self.ind, false);\n        self.end();\n        self.print_word(\") \");\n        self.neverbreak();\n        self.end();\n\n        // Print comments and body.\n        self.print_comments(body.span.lo(), CommentConfig::skip_ws());\n        self.print_stmt_as_block(body, span.hi(), false);\n        self.end();\n    }\n\n    /// Prints an `if` statement, including its condition, `then` block, and any chained\n    /// `else` or `else if` branches, handling inline formatting decisions and comments.\n    fn print_if_stmt(\n        &mut self,\n        span: Span,\n        cond: &'ast ast::Expr<'ast>,\n        then: &'ast ast::Stmt<'ast>,\n        els_opt: &'ast Option<&mut ast::Stmt<'ast>>,\n    ) {\n        // Check if blocks should be inlined and update cache if necessary\n        let inline = self.is_single_line_block(cond, then, els_opt.as_ref());\n        let set_inline_cache = !inline.is_cached && self.single_line_stmt.is_none();\n        if set_inline_cache {\n            self.single_line_stmt = Some(inline.outcome);\n        }\n\n        self.cbox(0);\n        self.ibox(0);\n        // Print if stmt\n        self.print_if_no_else(cond, then, inline.outcome);\n\n        // Print else (if) stmts, if any\n        let mut current_else = els_opt.as_deref();\n        while let Some(els) = current_else {\n            if self.ends_with('}') {\n                // If there are comments with line breaks, don't add spaces to mixed comments\n                if self.has_comment_before_with(els.span.lo(), |cmnt| !cmnt.style.is_mixed()) {\n                    // If last comment is miced, ensure line break\n                    if self\n                        .print_comments(els.span.lo(), CommentConfig::skip_ws().mixed_no_break())\n                        .is_some_and(|cmnt| cmnt.is_mixed())\n                    {\n                        self.hardbreak();\n                    }\n                }\n                // Otherwise, ensure a non-breaking space is added\n                else if self\n                    .print_comments(\n                        els.span.lo(),\n                        CommentConfig::skip_ws()\n                            .mixed_no_break()\n                            .mixed_prev_space()\n                            .mixed_post_nbsp(),\n                    )\n                    .is_none()\n                {\n                    self.nbsp();\n                }\n            } else {\n                self.hardbreak_if_not_bol();\n                if self\n                    .print_comments(els.span.lo(), CommentConfig::skip_ws())\n                    .is_some_and(|cmnt| cmnt.is_mixed())\n                {\n                    self.hardbreak();\n                };\n            }\n\n            self.ibox(0);\n            self.print_word(\"else \");\n            match &els.kind {\n                ast::StmtKind::If(cond, then, next_else) => {\n                    self.print_if_no_else(cond, then, inline.outcome);\n                    current_else = next_else.as_deref();\n                }\n                _ => {\n                    self.print_stmt_as_block(els, span.hi(), inline.outcome);\n                    self.end(); // end ibox for final else\n                    break;\n                }\n            }\n        }\n        self.end();\n\n        // Clear inline cache if we set it earlier.\n        if set_inline_cache {\n            self.single_line_stmt = None;\n        }\n    }\n\n    /// Prints a `return` statement, optionally including a return expression.\n    /// Handles spacing, line breaking, and formatting.\n    fn print_return_stmt(&mut self, force_break: bool, expr: &'ast Option<&mut ast::Expr<'ast>>) {\n        if force_break {\n            self.hardbreak_if_not_bol();\n        }\n\n        let space_left = self.space_left();\n        let expr_size = expr.as_ref().map_or(0, |expr| self.estimate_size(expr.span));\n\n        // `return ' + expr + ';'\n        let overflows = space_left < 8 + expr_size;\n        let fits_alone = space_left > expr_size;\n\n        if let Some(expr) = expr {\n            let is_simple = matches!(expr.kind, ast::ExprKind::Lit(..) | ast::ExprKind::Ident(..));\n            let allow_break = overflows && fits_alone;\n\n            self.return_bin_expr = matches!(expr.kind, ast::ExprKind::Binary(..));\n            self.s.ibox(if is_simple || allow_break { self.ind } else { 0 });\n\n            self.print_word(\"return\");\n\n            match self.print_comments(\n                expr.span.lo(),\n                CommentConfig::skip_ws().mixed_no_break().mixed_prev_space().mixed_post_nbsp(),\n            ) {\n                Some(cmnt) if cmnt.is_trailing() && !is_simple => self.s.offset(self.ind),\n                None => self.print_sep(Separator::SpaceOrNbsp(allow_break)),\n                _ => {}\n            }\n\n            self.print_expr(expr);\n            self.end();\n            self.return_bin_expr = false;\n        } else {\n            self.print_word(\"return\");\n        }\n    }\n\n    /// Prints a `try` statement along with its associated `catch` clauses,\n    /// following Solidity's `try ... returns (...) { ... } catch (...) { ... }` syntax.\n    fn print_try_stmt(\n        &mut self,\n        expr: &'ast ast::Expr<'ast>,\n        clauses: &'ast [ast::TryCatchClause<'ast>],\n    ) {\n        self.cbox(0);\n        if let Some((first, other)) = clauses.split_first() {\n            // Print the 'try' clause\n            let ast::TryCatchClause { args, block, span: try_span, .. } = first;\n            self.cbox(0);\n            self.ibox(0);\n            self.print_word(\"try \");\n            self.print_comments(expr.span.lo(), CommentConfig::skip_ws());\n            self.print_expr(expr);\n\n            // Print comments.\n            self.print_comments(\n                args.first().map(|p| p.span.lo()).unwrap_or_else(|| expr.span.lo()),\n                CommentConfig::skip_ws(),\n            );\n            if !self.is_beginning_of_line() {\n                self.nbsp();\n            }\n\n            if !args.is_empty() {\n                self.print_word(\"returns \");\n                self.print_word(\"(\");\n                self.zerobreak();\n                self.end();\n                let span = args.span.with_hi(block.span.lo());\n                self.commasep(\n                    args,\n                    span.lo(),\n                    span.hi(),\n                    |fmt, var| fmt.print_var(var, false),\n                    get_span!(),\n                    ListFormat::compact().with_delimiters(false),\n                );\n                self.print_word(\")\");\n                self.nbsp();\n            } else {\n                self.end();\n            }\n            if block.is_empty() {\n                self.print_block(block, *try_span);\n                self.end();\n            } else {\n                self.print_word(\"{\");\n                self.end();\n                self.neverbreak();\n                self.print_trailing_comment_no_break(try_span.lo(), None);\n                self.print_block_without_braces(block, try_span.hi(), Some(self.ind));\n                if self.cursor.enabled || self.cursor.pos < try_span.hi() {\n                    self.print_word(\"}\");\n                    self.cursor.advance_to(try_span.hi(), true);\n                }\n            }\n\n            let mut skip_ind = false;\n            if self.print_trailing_comment(try_span.hi(), other.first().map(|c| c.span.lo())) {\n                // if a trailing comment is printed at the very end, we have to manually\n                // adjust the offset to avoid having a double break.\n                self.break_offset_if_not_bol(0, self.ind, false);\n                skip_ind = true;\n            };\n\n            let mut prev_block_multiline = self.is_multiline_block(block, false);\n\n            // Handle 'catch' clauses\n            for (pos, ast::TryCatchClause { name, args, block, span: catch_span }) in\n                other.iter().delimited()\n            {\n                let current_block_multiline = self.is_multiline_block(block, false);\n                if !pos.is_first || !skip_ind {\n                    if prev_block_multiline && (current_block_multiline || pos.is_last) {\n                        self.nbsp();\n                    } else {\n                        self.space();\n                        if !current_block_multiline {\n                            self.s.offset(self.ind);\n                        }\n                    }\n                }\n                self.s.ibox(self.ind);\n                self.print_comments(\n                    catch_span.lo(),\n                    CommentConfig::skip_ws().mixed_no_break().mixed_post_nbsp(),\n                );\n\n                self.print_word(\"catch \");\n                if !args.is_empty() {\n                    self.print_comments(\n                        args[0].span.lo(),\n                        CommentConfig::skip_ws().mixed_no_break().mixed_post_nbsp(),\n                    );\n                    if let Some(name) = name {\n                        self.print_ident(name);\n                    }\n                    self.print_parameter_list(\n                        args,\n                        args.span.with_hi(block.span.lo()),\n                        ListFormat::inline(),\n                    );\n                    self.nbsp();\n                }\n                self.print_word(\"{\");\n                self.end();\n                if !block.is_empty() {\n                    self.print_trailing_comment_no_break(catch_span.lo(), None);\n                }\n                self.print_block_without_braces(block, catch_span.hi(), Some(self.ind));\n                if self.cursor.enabled || self.cursor.pos < try_span.hi() {\n                    self.print_word(\"}\");\n                    self.cursor.advance_to(catch_span.hi(), true);\n                }\n\n                prev_block_multiline = current_block_multiline;\n            }\n        }\n        self.end();\n    }\n\n    fn print_if_no_else(\n        &mut self,\n        cond: &'ast ast::Expr<'ast>,\n        then: &'ast ast::Stmt<'ast>,\n        inline: bool,\n    ) {\n        if !self.handle_span(cond.span.until(then.span), true) {\n            self.print_if_cond(\"if\", cond, then.span.lo());\n            // if empty block without comments, ensure braces are inlined\n            if let ast::StmtKind::Block(block) = &then.kind\n                && block.is_empty()\n                && self.peek_comment_before(then.span.hi()).is_none()\n            {\n                self.neverbreak();\n                self.print_sep(Separator::Nbsp);\n            } else {\n                self.print_sep(Separator::Space);\n            }\n        }\n        self.end();\n        self.print_stmt_as_block(then, then.span.hi(), inline);\n        self.cursor.advance_to(then.span.hi(), true);\n    }\n\n    fn print_if_cond(&mut self, kw: &'static str, cond: &'ast ast::Expr<'ast>, pos_hi: BytePos) {\n        self.print_word(kw);\n        self.print_sep_unhandled(Separator::Nbsp);\n        self.print_tuple(\n            std::slice::from_ref(cond),\n            cond.span.lo(),\n            pos_hi,\n            Self::print_expr,\n            get_span!(),\n            ListFormat::compact().break_cmnts().break_single(is_binary_expr(&cond.kind)),\n        );\n    }\n\n    fn print_emit_or_revert(\n        &mut self,\n        kw: &'static str,\n        path: &'ast ast::PathSlice,\n        args: &'ast ast::CallArgs<'ast>,\n    ) {\n        self.word(kw);\n        if self\n            .print_comments(\n                path.span().lo(),\n                CommentConfig::skip_ws().mixed_no_break().mixed_prev_space().mixed_post_nbsp(),\n            )\n            .is_none()\n        {\n            self.nbsp();\n        };\n        self.s.cbox(0);\n        self.emit_or_revert = path.segments().len() > 1;\n        self.print_path(path, false);\n        let format = if self.config.prefer_compact.calls() {\n            ListFormat::compact()\n        } else {\n            ListFormat::consistent()\n        };\n        self.print_call_args(args, format.break_cmnts(), path.to_string().len());\n        self.emit_or_revert = false;\n        self.end();\n    }\n\n    fn print_block(&mut self, block: &'ast [ast::Stmt<'ast>], span: Span) {\n        self.print_block_inner(\n            block,\n            BlockFormat::Regular,\n            Self::print_stmt,\n            |b| b.span,\n            span.hi(),\n        );\n    }\n\n    fn print_block_without_braces(\n        &mut self,\n        block: &'ast [ast::Stmt<'ast>],\n        pos_hi: BytePos,\n        offset: Option<isize>,\n    ) {\n        self.print_block_inner(\n            block,\n            BlockFormat::NoBraces(offset),\n            Self::print_stmt,\n            |b| b.span,\n            pos_hi,\n        );\n    }\n\n    // Body of a if/loop.\n    fn print_stmt_as_block(&mut self, stmt: &'ast ast::Stmt<'ast>, pos_hi: BytePos, inline: bool) {\n        if self.handle_span(stmt.span, false) {\n            return;\n        }\n\n        let stmts = if let ast::StmtKind::Block(stmts) = &stmt.kind {\n            stmts\n        } else {\n            std::slice::from_ref(stmt)\n        };\n\n        if inline && !stmts.is_empty() {\n            self.neverbreak();\n            self.print_block_without_braces(stmts, pos_hi, None);\n        } else {\n            // Reset cache for nested (child) stmts within this (parent) block.\n            let inline_parent = self.single_line_stmt.take();\n\n            self.print_word(\"{\");\n            self.print_block_without_braces(stmts, pos_hi, Some(self.ind));\n            self.print_word(\"}\");\n\n            // Restore cache for the rest of stmts within the same height.\n            self.single_line_stmt = inline_parent;\n        }\n    }\n\n    /// Determines if an `if/else` block should be inlined.\n    /// Also returns if the value was cached, so that it can be cleaned afterwards.\n    ///\n    /// # Returns\n    ///\n    /// A tuple `(should_inline, was_cached)`. The second boolean is `true` if the\n    /// decision was retrieved from the cache or is a final decision based on config,\n    /// preventing the caller from clearing a cache value that was never set.\n    fn is_single_line_block(\n        &mut self,\n        cond: &'ast ast::Expr<'ast>,\n        then: &'ast ast::Stmt<'ast>,\n        els_opt: Option<&'ast &'ast mut ast::Stmt<'ast>>,\n    ) -> Decision {\n        // If a decision is already cached from a parent, use it directly.\n        if let Some(cached_decision) = self.single_line_stmt {\n            return Decision { outcome: cached_decision, is_cached: true };\n        }\n\n        // Empty statements are always printed as blocks.\n        if std::slice::from_ref(then).is_empty() {\n            return Decision { outcome: false, is_cached: false };\n        }\n\n        // If possible, take an early decision based on the block style configuration.\n        match self.config.single_line_statement_blocks {\n            config::SingleLineBlockStyle::Preserve\n                if self.is_stmt_in_new_line(cond, then)\n                    || self.is_multiline_block_stmt(then, true) =>\n            {\n                return Decision { outcome: false, is_cached: false };\n            }\n            config::SingleLineBlockStyle::Single if self.is_multiline_block_stmt(then, true) => {\n                return Decision { outcome: false, is_cached: false };\n            }\n            config::SingleLineBlockStyle::Multi => {\n                return Decision { outcome: false, is_cached: false };\n            }\n            _ => {}\n        };\n\n        // If no decision was made, estimate the length to be formatted.\n        // NOTE: conservative check -> worst-case scenario is formatting as multi-line block.\n        if !self.can_stmts_be_inlined(cond, then, els_opt) {\n            return Decision { outcome: false, is_cached: false };\n        }\n\n        // If the parent would fit, check all of its children.\n        if let Some(stmt) = els_opt {\n            if let ast::StmtKind::If(child_cond, child_then, child_els_opt) = &stmt.kind {\n                return self.is_single_line_block(child_cond, child_then, child_els_opt.as_ref());\n            } else if self.is_multiline_block_stmt(stmt, true) {\n                return Decision { outcome: false, is_cached: false };\n            }\n        }\n\n        // If all children can also fit, allow single-line block.\n        Decision { outcome: true, is_cached: false }\n    }\n\n    fn is_inline_stmt(&self, stmt: &'ast ast::Stmt<'ast>, cond_len: usize) -> bool {\n        if let ast::StmtKind::If(cond, then, els_opt) = &stmt.kind {\n            let if_span = cond.span.to(then.span);\n            if self.sm.is_multiline(if_span)\n                && matches!(\n                    self.config.single_line_statement_blocks,\n                    config::SingleLineBlockStyle::Preserve\n                )\n            {\n                return false;\n            }\n            if cond_len + self.estimate_size(if_span) >= self.space_left() {\n                return false;\n            }\n            if let Some(els) = els_opt\n                && !self.is_inline_stmt(els, 6)\n            {\n                return false;\n            }\n        } else {\n            if matches!(\n                self.config.single_line_statement_blocks,\n                config::SingleLineBlockStyle::Preserve\n            ) && self.sm.is_multiline(stmt.span)\n            {\n                return false;\n            }\n            if cond_len + self.estimate_size(stmt.span) >= self.space_left() {\n                return false;\n            }\n        }\n        true\n    }\n\n    /// Checks if a statement was explicitly written in a new line.\n    fn is_stmt_in_new_line(\n        &self,\n        cond: &'ast ast::Expr<'ast>,\n        then: &'ast ast::Stmt<'ast>,\n    ) -> bool {\n        let span_between = cond.span.between(then.span);\n        if let Ok(snip) = self.sm.span_to_snippet(span_between) {\n            // Check for newlines after the closing parenthesis of the `if (...)`.\n            if let Some((_, after_paren)) = snip.split_once(')') {\n                return after_paren.lines().count() > 1;\n            }\n        }\n        false\n    }\n\n    /// Checks if a block statement `{ ... }` contains more than one line of actual code.\n    fn is_multiline_block_stmt(\n        &self,\n        stmt: &'ast ast::Stmt<'ast>,\n        empty_as_multiline: bool,\n    ) -> bool {\n        if let ast::StmtKind::Block(block) = &stmt.kind {\n            return self.is_multiline_block(block, empty_as_multiline);\n        }\n        false\n    }\n\n    /// Checks if a block statement `{ ... }` should be treated as multiline,\n    /// either because it spans multiple lines or contains multiple statements.\n    fn is_multiline_block(&self, block: &'ast ast::Block<'ast>, empty_as_multiline: bool) -> bool {\n        if block.stmts.is_empty() {\n            return empty_as_multiline;\n        }\n        // A block with multiple statements should never be inlined, regardless of\n        // whether it was written on a single line in the source.\n        if block.stmts.len() > 1 {\n            return true;\n        }\n        if self.sm.is_multiline(block.span)\n            && let Ok(snip) = self.sm.span_to_snippet(block.span)\n        {\n            let code_lines = snip.lines().filter(|line| {\n                let trimmed = line.trim();\n                // Ignore empty lines and lines with only '{' or '}'\n                if empty_as_multiline {\n                    !trimmed.is_empty() && trimmed != \"{\" && trimmed != \"}\"\n                } else {\n                    !trimmed.is_empty()\n                }\n            });\n            return code_lines.count() > 1;\n        }\n        false\n    }\n\n    /// Performs a size estimation to see if the if/else can fit on one line.\n    fn can_stmts_be_inlined(\n        &mut self,\n        cond: &'ast ast::Expr<'ast>,\n        then: &'ast ast::Stmt<'ast>,\n        els_opt: Option<&'ast &'ast mut ast::Stmt<'ast>>,\n    ) -> bool {\n        let cond_len = self.estimate_size(cond.span);\n\n        // If the condition fits in one line, 6 chars: 'if (' + {cond} + ') ' + {then}\n        // Otherwise chars: ') ' + {then}\n        let then_margin = if 6 + cond_len < self.space_left() { 6 + cond_len } else { 2 };\n\n        if !self.is_inline_stmt(then, then_margin) {\n            return false;\n        }\n\n        // Always 6 chars for the else: 'else '\n        els_opt.is_none_or(|els| self.is_inline_stmt(els, 6))\n    }\n\n    fn can_header_be_inlined(&mut self, func: &ast::ItemFunction<'_>) -> bool {\n        self.estimate_header_size(func) <= self.space_left()\n    }\n\n    fn can_header_params_be_inlined(&mut self, func: &ast::ItemFunction<'_>) -> bool {\n        self.estimate_header_params_size(func) <= self.space_left()\n    }\n\n    fn estimate_header_size(&mut self, func: &ast::ItemFunction<'_>) -> usize {\n        let ast::ItemFunction { kind: _, ref header, ref body, body_span: _ } = *func;\n\n        // ' ' + visibility\n        let visibility = header.visibility.map_or(0, |v| self.estimate_size(v.span) + 1);\n        // ' ' + state mutability\n        let mutability = header.state_mutability.map_or(0, |sm| self.estimate_size(sm.span) + 1);\n        // ' ' + modifier + (' ' + modifier)\n        let m = header.modifiers.iter().fold(0, |len, m| len + self.estimate_size(m.span()));\n        let modifiers = if m != 0 { m + 1 } else { 0 };\n        // ' ' + override\n        let override_ = header.override_.as_ref().map_or(0, |o| self.estimate_size(o.span) + 1);\n        // ' ' + virtual\n        let virtual_ = if header.virtual_.is_none() { 0 } else { 8 };\n        // ' returns(' + var + (', ' + var) + ')'\n        let returns = header.returns.as_ref().map_or(0, |ret| {\n            ret.vars\n                .iter()\n                .fold(0, |len, p| if len != 0 { len + 2 } else { 10 } + self.estimate_size(p.span))\n        });\n        // ' {' or ';'\n        let end = if body.is_some() { 2 } else { 1 };\n\n        self.estimate_header_params_size(func)\n            + visibility\n            + mutability\n            + modifiers\n            + override_\n            + virtual_\n            + returns\n            + end\n    }\n\n    fn estimate_header_params_size(&mut self, func: &ast::ItemFunction<'_>) -> usize {\n        let ast::ItemFunction { kind, ref header, body: _, body_span: _ } = *func;\n\n        let kw = match kind {\n            ast::FunctionKind::Constructor => 11, // 'constructor'\n            ast::FunctionKind::Function => 9,     // 'function '\n            ast::FunctionKind::Modifier => 9,     // 'modifier '\n            ast::FunctionKind::Fallback => 8,     // 'fallback'\n            ast::FunctionKind::Receive => 7,      // 'receive'\n        };\n\n        // '(' + param + (', ' + param) + ')'\n        let params = header\n            .parameters\n            .vars\n            .iter()\n            .fold(0, |len, p| if len != 0 { len + 2 } else { 2 } + self.estimate_size(p.span));\n\n        kw + header.name.map_or(0, |name| self.estimate_size(name.span)) + std::cmp::max(2, params)\n    }\n\n    fn estimate_lhs_size(&self, expr: &ast::Expr<'_>, parent_op: &ast::BinOp) -> usize {\n        match &expr.kind {\n            ast::ExprKind::Binary(lhs, op, _) if op.kind.group() == parent_op.kind.group() => {\n                self.estimate_lhs_size(lhs, op)\n            }\n            _ => self.estimate_size(expr.span),\n        }\n    }\n\n    fn has_comments_between_elements<I>(&self, limits: Span, elements: I) -> bool\n    where\n        I: IntoIterator<Item = &'ast ast::Expr<'ast>>,\n    {\n        let mut last_span_end = limits.lo();\n        for expr in elements {\n            if self.has_comment_between(last_span_end, expr.span.lo()) {\n                return true;\n            }\n            last_span_end = expr.span.hi();\n        }\n\n        if self.has_comment_between(last_span_end, limits.hi()) {\n            return true;\n        }\n\n        false\n    }\n}\n\n// -- HELPERS (language-specific) ----------------------------------------------\n\n#[derive(Debug)]\nenum MemberOrCallArgs {\n    Member(usize),\n    CallArgs(usize, bool),\n}\n\nimpl MemberOrCallArgs {\n    fn size(&self) -> usize {\n        match self {\n            Self::CallArgs(size, ..) | Self::Member(size) => *size,\n        }\n    }\n\n    fn member_size(&self) -> usize {\n        match self {\n            Self::CallArgs(..) => 0,\n            Self::Member(size) => *size,\n        }\n    }\n\n    fn has_comments(&self) -> bool {\n        matches!(self, Self::CallArgs(.., true))\n    }\n}\n\n#[derive(Debug, Clone)]\n#[expect(dead_code)]\nenum AttributeKind<'ast> {\n    Visibility(ast::Visibility),\n    StateMutability(ast::StateMutability),\n    Virtual,\n    Override(&'ast ast::Override<'ast>),\n    Modifier(&'ast ast::Modifier<'ast>),\n}\n\ntype AttributeCommentMap = HashMap<BytePos, (Vec<Comment>, Vec<Comment>, Vec<Comment>)>;\n\n#[derive(Debug, Clone)]\nstruct AttributeInfo<'ast> {\n    kind: AttributeKind<'ast>,\n    span: Span,\n}\n\n/// Helper struct to map attributes to their associated comments in function headers.\nstruct AttributeCommentMapper<'ast> {\n    limit_pos: BytePos,\n    comments: Vec<Comment>,\n    attributes: Vec<AttributeInfo<'ast>>,\n}\n\nimpl<'ast> AttributeCommentMapper<'ast> {\n    fn new(returns: Option<&'ast ast::ParameterList<'ast>>, body_pos: BytePos) -> Self {\n        Self {\n            comments: Vec::new(),\n            attributes: Vec::new(),\n            limit_pos: returns.as_ref().map_or(body_pos, |ret| ret.span.lo()),\n        }\n    }\n\n    #[allow(clippy::type_complexity)]\n    fn build(\n        mut self,\n        state: &mut State<'_, 'ast>,\n        header: &'ast ast::FunctionHeader<'ast>,\n    ) -> (AttributeCommentMap, Vec<AttributeInfo<'ast>>, BytePos) {\n        let first_attr = self.collect_attributes(header);\n        self.cache_comments(state);\n        (self.map(), self.attributes, first_attr)\n    }\n\n    fn map(&mut self) -> AttributeCommentMap {\n        let mut map = HashMap::new();\n        for a in 0..self.attributes.len() {\n            let is_last = a == self.attributes.len() - 1;\n            let (mut before, mut inner, mut after) = (Vec::new(), Vec::new(), Vec::new());\n\n            let before_limit = self.attributes[a].span.lo();\n            let inner_limit = self.attributes[a].span.hi();\n            let after_limit =\n                if !is_last { self.attributes[a + 1].span.lo() } else { self.limit_pos };\n\n            let mut c = 0;\n            while c < self.comments.len() {\n                if self.comments[c].pos() <= before_limit {\n                    before.push(self.comments.remove(c));\n                } else if self.comments[c].pos() <= inner_limit {\n                    inner.push(self.comments.remove(c));\n                } else if (after.is_empty() || is_last) && self.comments[c].pos() <= after_limit {\n                    after.push(self.comments.remove(c));\n                } else {\n                    c += 1;\n                }\n            }\n            map.insert(before_limit, (before, inner, after));\n        }\n        map\n    }\n\n    fn collect_attributes(&mut self, header: &'ast ast::FunctionHeader<'ast>) -> BytePos {\n        let mut first_pos = BytePos(u32::MAX);\n        if let Some(v) = header.visibility {\n            if v.span.lo() < first_pos {\n                first_pos = v.span.lo()\n            }\n            self.attributes\n                .push(AttributeInfo { kind: AttributeKind::Visibility(*v), span: v.span });\n        }\n        if let Some(sm) = header.state_mutability {\n            if sm.span.lo() < first_pos {\n                first_pos = sm.span.lo()\n            }\n            self.attributes\n                .push(AttributeInfo { kind: AttributeKind::StateMutability(*sm), span: sm.span });\n        }\n        if let Some(span) = header.virtual_ {\n            if span.lo() < first_pos {\n                first_pos = span.lo()\n            }\n            self.attributes.push(AttributeInfo { kind: AttributeKind::Virtual, span });\n        }\n        if let Some(ref o) = header.override_ {\n            if o.span.lo() < first_pos {\n                first_pos = o.span.lo()\n            }\n            self.attributes.push(AttributeInfo { kind: AttributeKind::Override(o), span: o.span });\n        }\n        for m in header.modifiers.iter() {\n            if m.span().lo() < first_pos {\n                first_pos = m.span().lo()\n            }\n            self.attributes\n                .push(AttributeInfo { kind: AttributeKind::Modifier(m), span: m.span() });\n        }\n        self.attributes.sort_by_key(|attr| attr.span.lo());\n        first_pos\n    }\n\n    fn cache_comments(&mut self, state: &mut State<'_, 'ast>) {\n        let mut pending = None;\n        for cmnt in state.comments.iter() {\n            if cmnt.pos() >= self.limit_pos {\n                break;\n            }\n            match pending {\n                Some(ref p) => pending = Some(p + 1),\n                None => pending = Some(0),\n            }\n        }\n        while let Some(p) = pending {\n            if p == 0 {\n                pending = None;\n            } else {\n                pending = Some(p - 1);\n            }\n            let cmnt = state.next_comment().unwrap();\n            if cmnt.style.is_blank() {\n                continue;\n            }\n            self.comments.push(cmnt);\n        }\n    }\n}\n\nfn stmt_needs_semi(stmt: &ast::StmtKind<'_>) -> bool {\n    match stmt {\n        ast::StmtKind::Assembly { .. }\n        | ast::StmtKind::Block { .. }\n        | ast::StmtKind::For { .. }\n        | ast::StmtKind::If { .. }\n        | ast::StmtKind::Try { .. }\n        | ast::StmtKind::UncheckedBlock { .. }\n        | ast::StmtKind::While { .. } => false,\n\n        ast::StmtKind::DeclSingle { .. }\n        | ast::StmtKind::DeclMulti { .. }\n        | ast::StmtKind::Break { .. }\n        | ast::StmtKind::Continue { .. }\n        | ast::StmtKind::DoWhile { .. }\n        | ast::StmtKind::Emit { .. }\n        | ast::StmtKind::Expr { .. }\n        | ast::StmtKind::Return { .. }\n        | ast::StmtKind::Revert { .. }\n        | ast::StmtKind::Placeholder { .. } => true,\n    }\n}\n\n/// Returns `true` if the item needs an isolated line break.\nfn item_needs_iso(item: &ast::ItemKind<'_>) -> bool {\n    match item {\n        ast::ItemKind::Pragma(..)\n        | ast::ItemKind::Import(..)\n        | ast::ItemKind::Using(..)\n        | ast::ItemKind::Variable(..)\n        | ast::ItemKind::Udvt(..)\n        | ast::ItemKind::Enum(..)\n        | ast::ItemKind::Error(..)\n        | ast::ItemKind::Event(..) => false,\n\n        ast::ItemKind::Contract(..) => true,\n\n        ast::ItemKind::Struct(strukt) => !strukt.fields.is_empty(),\n        ast::ItemKind::Function(func) => {\n            func.body.as_ref().is_some_and(|b| !b.is_empty())\n                && !matches!(func.kind, ast::FunctionKind::Modifier)\n        }\n    }\n}\n\nfn is_binary_expr(expr_kind: &ast::ExprKind<'_>) -> bool {\n    matches!(expr_kind, ast::ExprKind::Binary(..))\n}\n\nfn has_complex_successor(expr_kind: &ast::ExprKind<'_>, left: bool) -> bool {\n    match expr_kind {\n        ast::ExprKind::Binary(lhs, _, rhs) => {\n            if left {\n                has_complex_successor(&lhs.kind, left)\n            } else {\n                has_complex_successor(&rhs.kind, left)\n            }\n        }\n        ast::ExprKind::Unary(_, expr) => has_complex_successor(&expr.kind, left),\n        ast::ExprKind::Lit(..) | ast::ExprKind::Ident(_) => false,\n        ast::ExprKind::Tuple(..) => false,\n        _ => true,\n    }\n}\n\nfn is_call(expr_kind: &ast::ExprKind<'_>) -> bool {\n    matches!(expr_kind, ast::ExprKind::Call(..))\n}\n\n/// Returns true if this is a call with named arguments (struct-style syntax).\n/// Used to determine if `.field` after such a call should avoid breaking.\n/// E.g., `_lzSend({_dstEid: x, ...}).guid` → true (named args call)\n/// E.g., `someFunc(a, b).field` → false (positional args)\nfn is_call_with_named_args(expr_kind: &ast::ExprKind<'_>) -> bool {\n    if let ast::ExprKind::Call(_, args) = expr_kind {\n        matches!(args.kind, ast::CallArgsKind::Named(_))\n    } else {\n        false\n    }\n}\n\nfn is_call_chain(expr_kind: &ast::ExprKind<'_>, must_have_child: bool) -> bool {\n    if let ast::ExprKind::Member(child, ..) = expr_kind {\n        is_call_chain(&child.kind, false)\n    } else {\n        !must_have_child && is_call(expr_kind)\n    }\n}\n\nfn is_call_with_opts_and_args(expr_kind: &ast::ExprKind<'_>) -> bool {\n    if let ast::ExprKind::Call(call_expr, call_args) = expr_kind {\n        matches!(call_expr.kind, ast::ExprKind::CallOptions(..)) && !call_args.is_empty()\n    } else {\n        false\n    }\n}\n\n#[derive(Debug)]\nstruct Decision {\n    outcome: bool,\n    is_cached: bool,\n}\n\n#[derive(Clone, Copy, PartialEq, Eq)]\npub(crate) enum BinOpGroup {\n    Arithmetic,\n    Bitwise,\n    Comparison,\n    Logical,\n}\n\ntrait BinOpExt {\n    fn group(&self) -> BinOpGroup;\n}\n\nimpl BinOpExt for ast::BinOpKind {\n    fn group(&self) -> BinOpGroup {\n        match self {\n            Self::Or | Self::And => BinOpGroup::Logical,\n            Self::Eq | Self::Ne | Self::Lt | Self::Le | Self::Gt | Self::Ge => {\n                BinOpGroup::Comparison\n            }\n            Self::BitOr | Self::BitXor | Self::BitAnd | Self::Shl | Self::Shr | Self::Sar => {\n                BinOpGroup::Bitwise\n            }\n            Self::Add | Self::Sub | Self::Mul | Self::Div | Self::Rem | Self::Pow => {\n                BinOpGroup::Arithmetic\n            }\n        }\n    }\n}\n\n/// Calculates the size the callee's \"head,\" excluding its arguments.\n///\n/// # Examples\n///\n/// - `myFunction(..)`: 8 (length of `myFunction`)\n/// - `uint256(..)`: 7 (length of `uint256`)\n/// - `abi.encode(..)`: 10 (length of `abi.encode`)\n/// - `foo(..).bar(..)`: 3 (length of `foo`)\npub(super) fn get_callee_head_size(callee: &ast::Expr<'_>) -> usize {\n    match &callee.kind {\n        ast::ExprKind::Ident(id) => id.as_str().len(),\n        ast::ExprKind::Type(ast::Type { kind: ast::TypeKind::Elementary(ty), .. }) => {\n            ty.to_abi_str().len()\n        }\n        ast::ExprKind::Index(base, idx) => {\n            let idx_len = match idx {\n                ast::IndexKind::Index(expr) => expr.as_ref().map_or(0, |e| get_callee_head_size(e)),\n                ast::IndexKind::Range(e1, e2) => {\n                    1 + e1.as_ref().map_or(0, |e| get_callee_head_size(e))\n                        + e2.as_ref().map_or(0, |e| get_callee_head_size(e))\n                }\n            };\n            get_callee_head_size(base) + 2 + idx_len\n        }\n        ast::ExprKind::Member(base, member_ident) => {\n            match &base.kind {\n                ast::ExprKind::Ident(..) | ast::ExprKind::Type(..) => {\n                    get_callee_head_size(base) + 1 + member_ident.as_str().len()\n                }\n\n                // Chainned calls are not traversed, and instead just the member identifier is used\n                ast::ExprKind::Member(child, ..)\n                    if !matches!(&child.kind, ast::ExprKind::Call(..)) =>\n                {\n                    get_callee_head_size(base) + 1 + member_ident.as_str().len()\n                }\n                _ => member_ident.as_str().len(),\n            }\n        }\n        ast::ExprKind::Binary(lhs, _, _) => get_callee_head_size(lhs),\n\n        // If the callee is not an identifier or member access, it has no \"head\"\n        _ => 0,\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use crate::{FormatterConfig, InlineConfig};\n    use foundry_common::comments::Comments;\n    use solar::{\n        interface::{Session, source_map::FileName},\n        sema::Compiler,\n    };\n    use std::sync::Arc;\n\n    /// This helper extracts function headers from the AST and passes them to the test function.\n    fn parse_and_test<F>(source: &str, test_fn: F)\n    where\n        F: FnOnce(&mut State<'_, '_>, &ast::ItemFunction<'_>) + Send,\n    {\n        let session = Session::builder().with_buffer_emitter(Default::default()).build();\n        let mut compiler = Compiler::new(session);\n\n        compiler\n            .enter_mut(|c| -> solar::interface::Result<()> {\n                let mut pcx = c.parse();\n                pcx.set_resolve_imports(false);\n\n                // Create a source file using stdin as the filename\n                let file = c\n                    .sess()\n                    .source_map()\n                    .new_source_file(FileName::Stdin, source)\n                    .map_err(|e| c.sess().dcx.err(e.to_string()).emit())?;\n\n                pcx.add_file(file.clone());\n                pcx.parse();\n                c.dcx().has_errors()?;\n\n                // Get AST from parsed source and setup the formatter\n                let gcx = c.gcx();\n                let (_, source_obj) = gcx.get_ast_source(&file.name).expect(\"Failed to get AST\");\n                let ast = source_obj.ast.as_ref().expect(\"No AST found\");\n                let comments =\n                    Comments::new(&source_obj.file, gcx.sess.source_map(), true, false, None);\n                let config = Arc::new(FormatterConfig::default());\n                let inline_config = InlineConfig::default();\n                let mut state = State::new(gcx.sess.source_map(), config, inline_config, comments);\n\n                // Extract the first function header (either top-level or inside a contract)\n                let func = ast\n                    .items\n                    .iter()\n                    .find_map(|item| match &item.kind {\n                        ast::ItemKind::Function(func) => Some(func),\n                        ast::ItemKind::Contract(contract) => {\n                            contract.body.iter().find_map(|contract_item| {\n                                match &contract_item.kind {\n                                    ast::ItemKind::Function(func) => Some(func),\n                                    _ => None,\n                                }\n                            })\n                        }\n                        _ => None,\n                    })\n                    .expect(\"No function found in source\");\n\n                // Run the closure\n                test_fn(&mut state, func);\n\n                Ok(())\n            })\n            .expect(\"Test failed\");\n    }\n\n    #[test]\n    fn test_estimate_header_sizes() {\n        let test_cases = [\n            (\"function foo();\", 14, 15),\n            (\"function foo() {}\", 14, 16),\n            (\"function foo() public {}\", 14, 23),\n            (\"function foo(uint256 a) public {}\", 23, 32),\n            (\"function foo(uint256 a, address b, bool c) public {}\", 42, 51),\n            (\"function foo() public pure {}\", 14, 28),\n            (\"function foo() public virtual {}\", 14, 31),\n            (\"function foo() public override {}\", 14, 32),\n            (\"function foo() public onlyOwner {}\", 14, 33),\n            (\"function foo() public returns(uint256) {}\", 14, 40),\n            (\"function foo() public returns(uint256, address) {}\", 14, 49),\n            (\"function foo(uint256 a) public virtual override returns(uint256) {}\", 23, 66),\n            (\"function foo() external payable {}\", 14, 33),\n            // other function types\n            (\"contract C { constructor() {} }\", 13, 15),\n            (\"contract C { constructor(uint256 a) {} }\", 22, 24),\n            (\"contract C { modifier onlyOwner() {} }\", 20, 22),\n            (\"contract C { modifier onlyRole(bytes32 role) {} }\", 31, 33),\n            (\"contract C { fallback() external payable {} }\", 10, 29),\n            (\"contract C { receive() external payable {} }\", 9, 28),\n        ];\n\n        for (source, expected_params, expected_header) in &test_cases {\n            parse_and_test(source, |state, func| {\n                let params_size = state.estimate_header_params_size(func);\n                assert_eq!(\n                    params_size, *expected_params,\n                    \"Failed params size: expected {expected_params}, got {params_size} for source: {source}\",\n                );\n\n                let header_size = state.estimate_header_size(func);\n                assert_eq!(\n                    header_size, *expected_header,\n                    \"Failed header size: expected {expected_header}, got {header_size} for source: {source}\",\n                );\n            });\n        }\n    }\n}\n"
  },
  {
    "path": "crates/fmt/src/state/yul.rs",
    "content": "#![allow(clippy::too_many_arguments)]\n\nuse super::{\n    CommentConfig, State,\n    common::{BlockFormat, ListFormat},\n};\nuse solar::parse::ast::{self, Span, yul};\n\n#[rustfmt::skip]\nmacro_rules! get_span {\n    () => { |value| value.span };\n    (()) => { |value| value.span() };\n}\n\n/// Language-specific pretty printing: Yul.\nimpl<'ast> State<'_, 'ast> {\n    fn print_lit_yul(&mut self, lit: &'ast ast::Lit<'ast>) {\n        self.print_lit_inner(lit, true);\n    }\n\n    pub(crate) fn print_yul_stmt(&mut self, stmt: &'ast yul::Stmt<'ast>) {\n        let yul::Stmt { ref docs, span, ref kind } = *stmt;\n        self.print_docs(docs);\n        if self.handle_span(span, false) {\n            return;\n        }\n\n        match kind {\n            yul::StmtKind::Block(stmts) => self.print_yul_block(stmts, span, false, 0),\n            yul::StmtKind::AssignSingle(path, expr) => {\n                self.print_path(path, false);\n                self.word(\" := \");\n                self.neverbreak();\n                self.cursor.advance_to(expr.span.lo(), self.cursor.enabled);\n                self.print_yul_expr(expr);\n            }\n            yul::StmtKind::AssignMulti(paths, expr_call) => {\n                self.ibox(0);\n                self.commasep(\n                    paths,\n                    stmt.span.lo(),\n                    stmt.span.hi(),\n                    |this, path| this.print_path(path, false),\n                    get_span!(()),\n                    ListFormat::consistent(),\n                );\n                self.word(\" :=\");\n                self.space();\n                self.s.offset(self.ind);\n                self.ibox(0);\n                self.print_yul_expr(expr_call);\n                self.end();\n                self.end();\n            }\n            yul::StmtKind::Expr(expr_call) => self.print_yul_expr(expr_call),\n            yul::StmtKind::If(expr, stmts) => {\n                self.print_word(\"if \"); // 3 chars\n                self.print_yul_expr(expr);\n                self.nbsp(); // 1 char\n                self.print_yul_block(stmts, span, false, 4 + self.estimate_size(expr.span));\n            }\n            yul::StmtKind::For(yul::StmtFor { init, cond, step, body }) => {\n                self.ibox(0);\n\n                self.print_word(\"for \"); // 4 chars\n                self.print_yul_block(init, init.span, false, 4);\n\n                self.space();\n                self.print_yul_expr(cond);\n\n                self.space();\n                self.print_yul_block(step, step.span, false, 0);\n\n                self.space();\n                self.print_yul_block(body, body.span, false, 0);\n\n                self.end();\n            }\n            yul::StmtKind::Switch(yul::StmtSwitch { selector, cases }) => {\n                self.print_word(\"switch \");\n                self.print_yul_expr(selector);\n\n                self.print_trailing_comment(selector.span.hi(), None);\n\n                for yul::StmtSwitchCase { constant, body, span } in cases.iter() {\n                    self.hardbreak_if_not_bol();\n                    if let Some(constant) = constant {\n                        self.print_comments(\n                            constant.span.lo(),\n                            CommentConfig::default().mixed_prev_space(),\n                        );\n                        self.print_word(\"case \");\n                        self.print_lit_yul(constant);\n                        self.nbsp();\n                    } else {\n                        self.print_comments(\n                            body.span.lo(),\n                            CommentConfig::default().mixed_prev_space(),\n                        );\n                        self.print_word(\"default \");\n                    }\n                    self.print_yul_block(body, *span, false, 0);\n\n                    self.print_trailing_comment(selector.span.hi(), None);\n                }\n            }\n            yul::StmtKind::Leave => self.print_word(\"leave\"),\n            yul::StmtKind::Break => self.print_word(\"break\"),\n            yul::StmtKind::Continue => self.print_word(\"continue\"),\n            yul::StmtKind::FunctionDef(func) => {\n                let yul::Function { name, parameters, returns, body } = func;\n                let params_hi = parameters\n                    .last()\n                    .map_or(returns.first().map_or(body.span.lo(), |r| r.span.lo()), |p| {\n                        p.span.hi()\n                    });\n\n                self.cbox(0);\n                self.s.ibox(0);\n                self.print_word(\"function \");\n                self.print_ident(name);\n                self.print_tuple(\n                    parameters,\n                    span.lo(),\n                    params_hi,\n                    Self::print_ident,\n                    get_span!(),\n                    ListFormat::consistent(),\n                );\n                self.nbsp();\n                let has_returns = !returns.is_empty();\n                let skip_opening_brace = has_returns;\n                if self.can_yul_header_params_be_inlined(func) {\n                    self.neverbreak();\n                }\n                if has_returns {\n                    self.commasep(\n                        returns,\n                        returns.first().map_or(params_hi, |ret| ret.span.lo()),\n                        returns.last().map_or(body.span.lo(), |ret| ret.span.hi()),\n                        Self::print_ident,\n                        get_span!(),\n                        ListFormat::yul(Some(\"->\"), Some(\"{\")),\n                    );\n                }\n                self.end();\n                self.print_yul_block(body, span, skip_opening_brace, 0);\n                self.end();\n            }\n            yul::StmtKind::VarDecl(idents, expr) => {\n                self.s.ibox(self.ind);\n                self.print_word(\"let \");\n                self.commasep(\n                    idents,\n                    stmt.span.lo(),\n                    idents.last().map_or(stmt.span.lo(), |i| i.span.hi()),\n                    Self::print_ident,\n                    get_span!(),\n                    ListFormat::consistent(),\n                );\n                if let Some(expr) = expr {\n                    self.print_word(\" :=\");\n                    self.space();\n                    self.print_yul_expr(expr);\n                }\n                self.end();\n            }\n        }\n    }\n\n    fn print_yul_expr(&mut self, expr: &'ast yul::Expr<'ast>) {\n        let yul::Expr { span, ref kind } = *expr;\n        if self.handle_span(span, false) {\n            return;\n        }\n\n        match kind {\n            yul::ExprKind::Path(path) => self.print_path(path, false),\n            yul::ExprKind::Call(yul::ExprCall { name, arguments }) => {\n                self.print_ident(name);\n                self.print_tuple(\n                    arguments,\n                    span.lo(),\n                    span.hi(),\n                    |s, arg| s.print_yul_expr(arg),\n                    get_span!(),\n                    ListFormat::consistent().break_single(true),\n                );\n            }\n            yul::ExprKind::Lit(lit) => {\n                if matches!(&lit.kind, ast::LitKind::Address(_)) {\n                    self.print_span_cold(lit.span);\n                } else {\n                    self.print_lit_yul(lit);\n                }\n            }\n        }\n    }\n\n    pub(super) fn print_yul_block(\n        &mut self,\n        block: &'ast yul::Block<'ast>,\n        span: Span,\n        skip_opening_brace: bool,\n        prefix_len: usize,\n    ) {\n        if self.handle_span(span, false) {\n            return;\n        }\n\n        if !skip_opening_brace {\n            self.print_word(\"{\");\n        }\n\n        let can_inline_block = if block.len() <= 1 && !self.is_multiline_yul_block(block) {\n            if self.max_space_left(prefix_len) == 0 {\n                self.estimate_size(block.span) + self.config.tab_width < self.space_left()\n            } else {\n                self.estimate_size(block.span) + prefix_len < self.space_left()\n            }\n        } else {\n            false\n        };\n        if can_inline_block {\n            self.neverbreak();\n            self.print_block_inner(\n                block,\n                BlockFormat::NoBraces(None),\n                |s, stmt| {\n                    s.nbsp();\n                    s.print_yul_stmt(stmt);\n                    if s.peek_comment_before(stmt.span.hi()).is_none()\n                        && s.peek_trailing_comment(stmt.span.hi(), None).is_none()\n                    {\n                        s.nbsp();\n                    }\n                    s.print_comments(\n                        stmt.span.hi(),\n                        CommentConfig::skip_ws().mixed_no_break().mixed_post_nbsp(),\n                    );\n                    if !s.last_token_is_space() {\n                        s.nbsp();\n                    }\n                },\n                |b| b.span,\n                span.hi(),\n            );\n        } else {\n            let (mut i, n_args) = (0, block.len().saturating_sub(1));\n            self.print_block_inner(\n                block,\n                BlockFormat::NoBraces(Some(self.ind)),\n                |s, stmt| {\n                    s.print_yul_stmt(stmt);\n                    s.print_comments(stmt.span.hi(), CommentConfig::default());\n                    if i != n_args {\n                        let next_span = block[i + 1].span;\n                        s.print_trailing_comment(stmt.span.hi(), Some(next_span.lo()));\n                        if !s.is_bol_or_only_ind() && !s.inline_config.is_disabled(stmt.span) {\n                            // when disabling a single line, manually add a nonbreaking line jump so\n                            // that the indentation of the disabled line is maintained.\n                            if s.inline_config.is_disabled(next_span)\n                                && s.peek_comment_before(next_span.lo())\n                                    .is_none_or(|cmnt| !cmnt.style.is_isolated())\n                            {\n                                s.word(\"\\n\");\n                            // otherwise, use a regular hardbreak\n                            } else {\n                                s.hardbreak_if_not_bol();\n                            }\n                        }\n                        i += 1;\n                    } else {\n                        s.print_trailing_comment(stmt.span.hi(), Some(span.hi()));\n                    }\n                },\n                |b| b.span,\n                span.hi(),\n            );\n        }\n        self.print_word(\"}\");\n        self.print_trailing_comment(span.hi(), None);\n    }\n\n    /// Checks if a block statement `{ ... }` contains more than one line of actual code.\n    fn is_multiline_yul_block(&self, block: &'ast yul::Block<'ast>) -> bool {\n        if block.stmts.is_empty() {\n            return false;\n        }\n        if self.sm.is_multiline(block.span)\n            && let Ok(snip) = self.sm.span_to_snippet(block.span)\n        {\n            let code_lines = snip.lines().filter(|line| {\n                let trimmed = line.trim();\n                // Ignore empty lines and lines with only '{' or '}'\n                !trimmed.is_empty()\n            });\n            return code_lines.count() > 1;\n        }\n        false\n    }\n\n    fn estimate_yul_header_params_size(&mut self, func: &yul::Function<'_>) -> usize {\n        // '(' + param + (', ' + param) + ')'\n        let params = func\n            .parameters\n            .iter()\n            .fold(0, |len, p| if len != 0 { len + 2 } else { 2 } + self.estimate_size(p.span));\n\n        // 'function ' + name + ' ' + params + ' ->'\n        9 + self.estimate_size(func.name.span) + 1 + params + 3\n    }\n\n    fn can_yul_header_params_be_inlined(&mut self, func: &yul::Function<'_>) -> bool {\n        self.estimate_yul_header_params_size(func) <= self.space_left()\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/Annotation/fmt.sol",
    "content": "// Support for Solana/Substrate annotations\ncontract A {\n    @selector([1, 2, 3, 4])\n    function foo() public {}\n\n    @selector(\"another one\")\n    function bar() public {}\n\n    @first(\"\")\n    @second(\"\")\n    function foobar() public {}\n}\n\n@topselector(2)\ncontract B {}\n"
  },
  {
    "path": "crates/fmt/testdata/Annotation/original.sol",
    "content": "// Support for Solana/Substrate annotations\ncontract A {\n    @selector([1,2,3,4])\n    function foo() public {}\n\n        @selector(\"another one\")\n    function bar() public {}\n\n    @first(\"\")\n    @second(\"\")\n    function foobar() public {}\n}\n\n@topselector(2)\ncontract B {}\n"
  },
  {
    "path": "crates/fmt/testdata/ArrayExpressions/fmt.sol",
    "content": "contract ArrayExpressions {\n    function test() external {\n        /* ARRAY SUBSCRIPT */\n        uint256[10] memory sample;\n\n        uint256 length = 10;\n        uint256[] memory sample2 = new uint256[](length);\n\n        uint256[] memory /* comment1 */ /* comment2 */ sample3; // comment3\n\n        /* ARRAY SLICE */\n        msg.data[4:];\n        msg.data[:msg.data.length];\n        msg.data[4:msg.data.length];\n\n        msg.data[\n            // comment1\n            4:\n        ];\n        msg.data[\n            : /* comment2 */ msg.data.length // comment3\n        ];\n        msg.data[\n            // comment4\n            4: // comment5\n                msg.data.length /* comment6 */\n        ];\n\n        uint256\n            someVeryVeryVeryLongVariableNameThatDenotesTheStartOfTheMessageDataSlice =\n                4;\n        uint256\n            someVeryVeryVeryLongVariableNameThatDenotesTheEndOfTheMessageDataSlice =\n                msg.data.length;\n        msg.data[\n            someVeryVeryVeryLongVariableNameThatDenotesTheStartOfTheMessageDataSlice:\n        ];\n        msg.data[\n            :someVeryVeryVeryLongVariableNameThatDenotesTheEndOfTheMessageDataSlice\n        ];\n        msg.data[\n            someVeryVeryVeryLongVariableNameThatDenotesTheStartOfTheMessageDataSlice:\n                someVeryVeryVeryLongVariableNameThatDenotesTheEndOfTheMessageDataSlice\n        ];\n\n        /* ARRAY LITERAL */\n        [1, 2, 3];\n\n        uint256 someVeryVeryLongVariableName = 0;\n        [\n            someVeryVeryLongVariableName,\n            someVeryVeryLongVariableName,\n            someVeryVeryLongVariableName\n        ];\n        uint256[3] memory literal = [\n            someVeryVeryLongVariableName,\n            someVeryVeryLongVariableName,\n            someVeryVeryLongVariableName\n        ];\n\n        uint8[3] memory literal2 = /* comment7 */ [ // comment8\n            1,\n            2, /* comment9 */\n            3 // comment10\n        ];\n        uint256[1] memory literal3 = [ /* comment11 */\n            someVeryVeryLongVariableName /* comment13 */\n        ];\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/ArrayExpressions/original.sol",
    "content": "contract ArrayExpressions {\n    function test() external {\n        /* ARRAY SUBSCRIPT */\n        uint[10] memory sample;\n\n        uint256 length = 10;\n        uint[] memory sample2 = new  uint[](\n            length);\n\n        uint /* comment1 */ [] memory /* comment2 */ sample3 // comment3\n        ;\n\n        /* ARRAY SLICE */\n        msg.data[4:];\n        msg.data[:msg.data.length];\n        msg.data[4:msg.data.length];\n\n        msg.data[\n            // comment1\n            4:];\n        msg.data[\n            : /* comment2 */ msg.data.length // comment3\n            ];\n        msg.data[\n        // comment4 \n        4 // comment5\n        :msg.data.length /* comment6 */];\n\n        uint256 someVeryVeryVeryLongVariableNameThatDenotesTheStartOfTheMessageDataSlice = 4;\n        uint256 someVeryVeryVeryLongVariableNameThatDenotesTheEndOfTheMessageDataSlice = msg.data.length;\n        msg.data[someVeryVeryVeryLongVariableNameThatDenotesTheStartOfTheMessageDataSlice:];\n        msg.data[:someVeryVeryVeryLongVariableNameThatDenotesTheEndOfTheMessageDataSlice];\n        msg.data[someVeryVeryVeryLongVariableNameThatDenotesTheStartOfTheMessageDataSlice:someVeryVeryVeryLongVariableNameThatDenotesTheEndOfTheMessageDataSlice];\n\n        /* ARRAY LITERAL */\n        [1, 2, 3];\n\n        uint256 someVeryVeryLongVariableName = 0;\n        [someVeryVeryLongVariableName, someVeryVeryLongVariableName, someVeryVeryLongVariableName];\n        uint256[3] memory literal = [someVeryVeryLongVariableName,someVeryVeryLongVariableName,someVeryVeryLongVariableName];\n        \n        uint8[3] memory literal2 = /* comment7 */ [ // comment8 \n        1, 2, /* comment9 */ 3 // comment10\n        ];\n        uint256[1] memory literal3 = [ /* comment11 */ someVeryVeryLongVariableName /* comment13 */]; \n    }\n}"
  },
  {
    "path": "crates/fmt/testdata/BlockComments/fmt.sol",
    "content": "contract CounterTest is Test {\n    /**\n     * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection.\n     */\n    constructor(string memory name_, string memory symbol_) {\n        _name = name_;\n        _symbol = symbol_;\n    }\n\n    /**\n     * @dev See {IERC721-balanceOf}.\n     */\n    function test_Increment() public {\n        counter.increment();\n        assertEq(counter.number(), 1);\n    }\n\n    /**\n     * @dev See {IERC165-supportsInterface}.\n     */\n    function test_Increment() public {\n        counter.increment();\n        assertEq(counter.number(), 1);\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/BlockComments/original.sol",
    "content": "contract CounterTest is Test {\n    /**\n     * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection.\n     */\n\n    constructor(string memory name_, string memory symbol_) {\n                _name = name_;\n        _symbol = symbol_;\n    }\n\n        /**\n     * @dev See {IERC721-balanceOf}.\n     */\n    function test_Increment() public {\n            counter.increment();\n        assertEq(counter.number(), 1);\n    }\n\n    /**\n * @dev See {IERC165-supportsInterface}.\n     */    function test_Increment() public {\n    counter.increment();\n    assertEq(counter.number(), 1);\n}\n\n}"
  },
  {
    "path": "crates/fmt/testdata/BlockComments/tab.fmt.sol",
    "content": "// config: style = \"tab\"\ncontract CounterTest is Test {\n\t/**\n\t *\t@dev Initializes the contract by setting a `name` and a `symbol` to the token collection.\n\t */\n\tconstructor(string memory name_, string memory symbol_) {\n\t\t_name = name_;\n\t\t_symbol = symbol_;\n\t}\n\n\t/**\n\t *\t@dev See {IERC721-balanceOf}.\n\t */\n\tfunction test_Increment() public {\n\t\tcounter.increment();\n\t\tassertEq(counter.number(), 1);\n\t}\n\n\t/**\n\t *\t@dev See {IERC165-supportsInterface}.\n\t */\n\tfunction test_Increment() public {\n\t\tcounter.increment();\n\t\tassertEq(counter.number(), 1);\n\t}\n}\n"
  },
  {
    "path": "crates/fmt/testdata/BlockCommentsFunction/fmt.sol",
    "content": "contract A {\n    Counter public counter;\n    /**\n     *  TODO: this fuzz use too much time to execute\n     * function testGetFuzz(bytes[2][] memory kvs) public {\n     *     for (uint256 i = 0; i < kvs.length; i++) {\n     *         bytes32 root = trie.update(kvs[i][0], kvs[i][1]);\n     *         console.logBytes32(root);\n     *     }\n     *\n     *     for (uint256 i = 0; i < kvs.length; i++) {\n     *         (bool exist, bytes memory value) = trie.get(kvs[i][0]);\n     *         console.logBool(exist);\n     *         console.logBytes(value);\n     *         require(exist);\n     *         require(BytesSlice.equal(value, trie.getRaw(kvs[i][0])));\n     *     }\n     * }\n     */\n}\n"
  },
  {
    "path": "crates/fmt/testdata/BlockCommentsFunction/original.sol",
    "content": "contract A {\n    Counter public counter;\n    /**\n     *  TODO: this fuzz use too much time to execute\n    function testGetFuzz(bytes[2][] memory kvs) public {\n        for (uint256 i = 0; i < kvs.length; i++) {\n            bytes32 root = trie.update(kvs[i][0], kvs[i][1]);\n            console.logBytes32(root);\n        }\n\n        for (uint256 i = 0; i < kvs.length; i++) {\n            (bool exist, bytes memory value) = trie.get(kvs[i][0]);\n            console.logBool(exist);\n            console.logBytes(value);\n            require(exist);\n            require(BytesSlice.equal(value, trie.getRaw(kvs[i][0])));\n        }\n    }\n    */\n}"
  },
  {
    "path": "crates/fmt/testdata/BlockCommentsFunction/tab.fmt.sol",
    "content": "// config: style = \"tab\"\ncontract A {\n\tCounter public counter;\n\t/**\n\t *\tTODO: this fuzz use too much time to execute\n\t *\tfunction testGetFuzz(bytes[2][] memory kvs) public {\n\t *\t\tfor (uint256 i = 0; i < kvs.length; i++) {\n\t *\t\t\tbytes32 root = trie.update(kvs[i][0], kvs[i][1]);\n\t *\t\t\tconsole.logBytes32(root);\n\t *\t\t}\n\t *\n\t *\t\tfor (uint256 i = 0; i < kvs.length; i++) {\n\t *\t\t\t(bool exist, bytes memory value) = trie.get(kvs[i][0]);\n\t *\t\t\tconsole.logBool(exist);\n\t *\t\t\tconsole.logBytes(value);\n\t *\t\t\trequire(exist);\n\t *\t\t\trequire(BytesSlice.equal(value, trie.getRaw(kvs[i][0])));\n\t *\t\t}\n\t *\t}\n\t */\n}\n"
  },
  {
    "path": "crates/fmt/testdata/CommentEmptyLine/fmt.sol",
    "content": "pragma solidity ^0.8.0;\n\ncontract ProofOfConcept {\n    // some comment\n}\n"
  },
  {
    "path": "crates/fmt/testdata/CommentEmptyLine/original.sol",
    "content": "pragma solidity ^0.8.0;\n\ncontract ProofOfConcept {\n    // some comment\n\n}\n"
  },
  {
    "path": "crates/fmt/testdata/ConditionalOperatorExpression/fmt.sol",
    "content": "contract TernaryExpression {\n    function test() external {\n        bool condition;\n        bool someVeryVeryLongConditionUsedInTheTernaryExpression;\n\n        condition ? 0 : 1;\n\n        someVeryVeryLongConditionUsedInTheTernaryExpression\n            ? 1234567890\n            : 987654321;\n\n        condition /* comment1 */ /* comment2 */\n            ? 1001 /* comment3 */ /* comment4 */\n            : 2002;\n\n        // comment5\n        someVeryVeryLongConditionUsedInTheTernaryExpression\n            ? 1\n            // comment6\n            // comment7\n            : 0; // comment8\n\n        uint256 amount = msg.value > 0\n            ? msg.value\n            : parseAmount(IERC20(asset).balanceOf(msg.sender), msg.data);\n\n        uint256 amount = msg.value > 0\n            ? msg.value\n            // comment9\n            : parseAmount(IERC20(asset).balanceOf(msg.sender), msg.data);\n\n        uint256 amount = msg.value > 0\n            // comment10\n            ? msg.value\n            : parseAmount(IERC20(asset).balanceOf(msg.sender), msg.data);\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/ConditionalOperatorExpression/original.sol",
    "content": "contract TernaryExpression {\n    function test() external {\n        bool condition;\n        bool someVeryVeryLongConditionUsedInTheTernaryExpression;\n\n        condition ? 0 : 1;\n\n        someVeryVeryLongConditionUsedInTheTernaryExpression ? 1234567890 : 987654321;\n\n        condition /* comment1 */ ? /* comment2 */ 1001 /* comment3 */ : /* comment4 */ 2002;\n\n        // comment5\n        someVeryVeryLongConditionUsedInTheTernaryExpression ? 1\n        // comment6\n        :\n        // comment7\n        0; // comment8\n\n        uint256 amount = msg.value > 0\n            ? msg.value\n            : parseAmount(IERC20(asset).balanceOf(msg.sender), msg.data);\n\n        uint256 amount = msg.value > 0\n            ? msg.value\n            // comment9\n            : parseAmount(IERC20(asset).balanceOf(msg.sender), msg.data);\n\n        uint amount = msg.value > 0\n            // comment10\n            ? msg.value\n            : parseAmount(IERC20(asset).balanceOf(msg.sender), msg.data);\n    }\n}"
  },
  {
    "path": "crates/fmt/testdata/ConstructorDefinition/fmt.sol",
    "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.5.2;\n\n// comment block starts here\n// comment block continues\n//\n\n// comment block 2 starts here\n// comment block 2 continues\n\ncontract Constructors is Ownable, Changeable {\n    function Constructors(variable1)\n        public\n        Changeable(variable1)\n        Ownable()\n        onlyOwner\n    {}\n\n    constructor(\n        variable1,\n        variable2,\n        variable3,\n        variable4,\n        variable5,\n        variable6,\n        variable7\n    )\n        public\n        Changeable(\n            variable1,\n            variable2,\n            variable3,\n            variable4,\n            variable5,\n            variable6,\n            variable7\n        )\n        Ownable()\n        onlyOwner\n    {}\n}\n"
  },
  {
    "path": "crates/fmt/testdata/ConstructorDefinition/original.sol",
    "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.5.2;\n\n// comment block starts here\n// comment block continues\n//\n\n// comment block 2 starts here\n// comment block 2 continues\n\ncontract Constructors is Ownable, Changeable {\n    function Constructors(variable1) public Changeable(variable1) Ownable() onlyOwner {\n    }\n\n    constructor(variable1, variable2, variable3, variable4, variable5, variable6, variable7) public Changeable(variable1, variable2, variable3, variable4, variable5, variable6, variable7) Ownable() onlyOwner {}\n}\n"
  },
  {
    "path": "crates/fmt/testdata/ConstructorModifierStyle/fmt.sol",
    "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.5.2;\n\nimport {Ownable} from \"@openzeppelin/contracts/access/Ownable.sol\";\nimport {ERC1155} from \"solmate/tokens/ERC1155.sol\";\n\nimport {IAchievements} from \"./interfaces/IAchievements.sol\";\nimport {SoulBound1155} from \"./abstracts/SoulBound1155.sol\";\n\ncontract Achievements is IAchievements, SoulBound1155, Ownable {\n    constructor(address owner) my_modifier Ownable() ERC1155() {}\n\n    function f() my_modifier MyModifier my_modifier MyModifier {}\n}\n"
  },
  {
    "path": "crates/fmt/testdata/ConstructorModifierStyle/original.sol",
    "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.5.2;\n\nimport {Ownable} from \"@openzeppelin/contracts/access/Ownable.sol\";\nimport {ERC1155} from \"solmate/tokens/ERC1155.sol\";\n\nimport {IAchievements} from \"./interfaces/IAchievements.sol\";\nimport {SoulBound1155} from \"./abstracts/SoulBound1155.sol\";\n\ncontract Achievements is IAchievements, SoulBound1155, Ownable {\n    constructor(address owner) my_modifier Ownable() ERC1155() {}\n\n    function f() my_modifier MyModifier() my_modifier() MyModifier {}\n}\n"
  },
  {
    "path": "crates/fmt/testdata/ContractDefinition/bracket-spacing.fmt.sol",
    "content": "// config: line_length = 160\n// config: bracket_spacing = true\ncontract ContractDefinition is Contract1, Contract2, Contract3, Contract4, Contract5 { }\n\n// comment 7\ncontract SampleContract {\n    // spaced comment 1\n\n    // spaced comment 2\n    // that spans multiple lines\n\n    // comment 8\n    constructor() { /* comment 9 */ } // comment 10\n\n    // comment 11\n    function max( /* comment 13 */\n        uint256 arg1,\n        uint256 /* comment 14 */ arg2,\n        uint256 /* comment 15 */\n    )\n        // comment 16\n        external /* comment 17 */\n        pure\n        returns (uint256)\n    // comment 18\n    {\n        // comment 19\n        return arg1 > arg2 ? arg1 : arg2;\n    }\n}\n\n// comment 20\ncontract /* comment 21 */ ExampleContract is /* comment 22 */ SampleContract { }\n\ncontract ERC20DecimalsMock is ERC20 {\n    uint8 private immutable _decimals;\n\n    constructor(string memory name_, string memory symbol_, uint8 decimals_) ERC20(name_, symbol_) {\n        _decimals = decimals_;\n    }\n}\n\ncontract SomeContract is\n    ERC165Upgradeable, // 1 inherited component\n    ISomeContract // 4 inherited components\n{ }\n\ncontract AnotherContract is\n    Adminable, /* 1 inherited components */\n    UUPSUpgradeable /* 1 inherited component */\n{ }\n\ncontract WithLayoutAndBase layout at 69 is Base { }\n"
  },
  {
    "path": "crates/fmt/testdata/ContractDefinition/contract-new-lines.fmt.sol",
    "content": "// config: contract_new_lines = true\ncontract ContractDefinition is\n    Contract1,\n    Contract2,\n    Contract3,\n    Contract4,\n    Contract5\n{}\n\n// comment 7\ncontract SampleContract {\n\n    // spaced comment 1\n\n    // spaced comment 2\n    // that spans multiple lines\n\n    // comment 8\n    constructor() { /* comment 9 */ } // comment 10\n\n    // comment 11\n    function max( /* comment 13 */\n        uint256 arg1,\n        uint256 /* comment 14 */ arg2,\n        uint256 /* comment 15 */\n    )\n        // comment 16\n        external /* comment 17 */\n        pure\n        returns (uint256)\n    // comment 18\n    {\n        // comment 19\n        return arg1 > arg2 ? arg1 : arg2;\n    }\n\n}\n\n// comment 20\ncontract /* comment 21 */ ExampleContract is /* comment 22 */ SampleContract {}\n\ncontract ERC20DecimalsMock is ERC20 {\n\n    uint8 private immutable _decimals;\n\n    constructor(string memory name_, string memory symbol_, uint8 decimals_)\n        ERC20(name_, symbol_)\n    {\n        _decimals = decimals_;\n    }\n\n}\n\ncontract SomeContract is\n    ERC165Upgradeable, // 1 inherited component\n    ISomeContract // 4 inherited components\n{}\n\ncontract AnotherContract is\n    Adminable, /* 1 inherited components */\n    UUPSUpgradeable /* 1 inherited component */\n{}\n\ncontract WithLayoutAndBase layout at 69 is Base {}\n"
  },
  {
    "path": "crates/fmt/testdata/ContractDefinition/fmt.sol",
    "content": "contract ContractDefinition is\n    Contract1,\n    Contract2,\n    Contract3,\n    Contract4,\n    Contract5\n{}\n\n// comment 7\ncontract SampleContract {\n    // spaced comment 1\n\n    // spaced comment 2\n    // that spans multiple lines\n\n    // comment 8\n    constructor() { /* comment 9 */ } // comment 10\n\n    // comment 11\n    function max( /* comment 13 */\n        uint256 arg1,\n        uint256 /* comment 14 */ arg2,\n        uint256 /* comment 15 */\n    )\n        // comment 16\n        external /* comment 17 */\n        pure\n        returns (uint256)\n    // comment 18\n    {\n        // comment 19\n        return arg1 > arg2 ? arg1 : arg2;\n    }\n}\n\n// comment 20\ncontract /* comment 21 */ ExampleContract is /* comment 22 */ SampleContract {}\n\ncontract ERC20DecimalsMock is ERC20 {\n    uint8 private immutable _decimals;\n\n    constructor(string memory name_, string memory symbol_, uint8 decimals_)\n        ERC20(name_, symbol_)\n    {\n        _decimals = decimals_;\n    }\n}\n\ncontract SomeContract is\n    ERC165Upgradeable, // 1 inherited component\n    ISomeContract // 4 inherited components\n{}\n\ncontract AnotherContract is\n    Adminable, /* 1 inherited components */\n    UUPSUpgradeable /* 1 inherited component */\n{}\n\ncontract WithLayoutAndBase layout at 69 is Base {}\n"
  },
  {
    "path": "crates/fmt/testdata/ContractDefinition/original.sol",
    "content": "contract ContractDefinition is Contract1, Contract2, Contract3, Contract4, Contract5 {\n}\n\n// comment 7\ncontract SampleContract {\n\n    // spaced comment 1\n\n    // spaced comment 2\n    // that spans multiple lines\n\n    // comment 8\n    constructor() { /* comment 9 */ } // comment 10\n\n    // comment 11\n    function max(/* comment 13 */ uint256 arg1, uint256 /* comment 14 */ arg2, uint256 /* comment 15 */)\n    // comment 16\n    external /* comment 17 */\n    pure\n    returns(uint256)\n    // comment 18\n    { // comment 19\n        return arg1 > arg2 ? arg1 : arg2;\n    }\n}\n\n// comment 20\ncontract /* comment 21 */ ExampleContract /* comment 22 */ is SampleContract {}\n\ncontract ERC20DecimalsMock is ERC20 {\n    uint8 private immutable _decimals;\n\n    constructor(\n        string memory name_,\n        string memory symbol_,\n        uint8 decimals_\n    ) ERC20(name_, symbol_) {\n        _decimals = decimals_;\n    }\n}\n\ncontract SomeContract is\n    ERC165Upgradeable, // 1 inherited component\n    ISomeContract // 4 inherited components\n{ }\n\ncontract AnotherContract is\n    Adminable, /* 1 inherited components */\n    UUPSUpgradeable /* 1 inherited component */\n{ }\n\ncontract WithLayoutAndBase layout at 69 is Base {}\n"
  },
  {
    "path": "crates/fmt/testdata/DoWhileStatement/fmt.sol",
    "content": "pragma solidity ^0.8.8;\n\ncontract DoWhileStatement {\n    function test() external {\n        uint256 i;\n        do {\n            \"test\";\n        } while (i != 0);\n\n        do {} while (i != 0);\n\n        bool someVeryVeryLongCondition;\n        do {\n            \"test\";\n        } while (\n            someVeryVeryLongCondition && !someVeryVeryLongCondition\n                && !someVeryVeryLongCondition && someVeryVeryLongCondition\n        );\n\n        do {\n            i++;\n        } while (i < 10);\n\n        do {\n            do {\n                i++;\n            } while (i < 30);\n        } while (i < 20);\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/DoWhileStatement/original.sol",
    "content": "pragma solidity ^0.8.8;\n\n contract DoWhileStatement {\n    function test() external {\n        uint256 i;\n        do { \"test\"; } while (i != 0);\n\n        do \n        {}\n        while\n        (\n    i != 0);\n\n        bool someVeryVeryLongCondition;\n        do { \"test\"; } while(\n            someVeryVeryLongCondition && !someVeryVeryLongCondition && \n!someVeryVeryLongCondition &&\n    someVeryVeryLongCondition); \n\n     do i++; while(i < 10);\n\n        do do i++; while (i < 30); while(i < 20);\n    }\n}"
  },
  {
    "path": "crates/fmt/testdata/DocComments/block.fmt.sol",
    "content": "// config: docs_style = \"block\"\npragma solidity ^0.8.13;\n\n/**\n * @title A Hello world example\n */\ncontract HelloWorld {\n    /**\n     * Some example struct\n     */\n    struct Person {\n        uint256 age;\n        address wallet;\n    }\n\n    /**\n     * Here's a more double asterix comment\n     */\n    Person public theDude;\n\n    /**\n     * Will this long comment be wrapped leaving\n     * orphan words?\n     */\n    Person public anotherDude;\n\n    /**\n     * Constructs the dude\n     * @param age The dude's age\n     */\n    constructor(uint256 age) {\n        theDude = Person({age: age, wallet: msg.sender});\n    }\n\n    /**\n     * @dev does nothing\n     */\n    function example() public {\n        /**\n         * Does this add a whitespace error?\n         *\n         * Let's find out.\n         */\n    }\n\n    /**\n     * @dev Calculates a rectangle's surface and perimeter.\n     * @param w Width of the rectangle.\n     * @param h Height of the rectangle.\n     * @return s The calculated surface.\n     * @return p The calculated perimeter.\n     */\n    function rectangle(uint256 w, uint256 h)\n        public\n        pure\n        returns (uint256 s, uint256 p)\n    {\n        s = w * h;\n        p = 2 * (w + h);\n    }\n\n    /**\n     * A long doc line comment that will be wrapped\n     */\n    function docLineOverflow() external {}\n\n    function docLinePostfixOverflow() external {}\n\n    /**\n     * A long doc line comment that will be wrapped\n     */\n\n    /**\n     * @notice Here is my comment\n     *       - item 1\n     *       - item 2\n     * Some equations:\n     *     y = mx + b\n     */\n    function anotherExample() external {}\n\n    /**\n     * contract A {\n     *     function foo() public {\n     *         // does nothing.\n     *     }\n     * }\n     */\n    function multilineIndent() external {}\n\n    /**\n     * contract A {\n     * function foo() public {\n     *             // does nothing.\n     *   }\n     * }\n     */\n    function multilineMalformedIndent() external {}\n\n    /**\n     * contract A {\n     * function withALongNameThatWillCauseCommentWrap() public {\n     *             // does nothing.\n     *   }\n     * }\n     */\n    function malformedIndentOverflow() external {}\n}\n\n/**\n * contract A {\n *     function foo() public {\n *         // does nothing.\n *     }\n * }\n */\nfunction freeFloatingMultilineIndent() {}\n"
  },
  {
    "path": "crates/fmt/testdata/DocComments/fmt.sol",
    "content": "pragma solidity ^0.8.13;\n\n/// @title A Hello world example\ncontract HelloWorld {\n    /// Some example struct\n    struct Person {\n        uint256 age;\n        address wallet;\n    }\n\n    /**\n     * Here's a more double asterix comment\n     */\n    Person public theDude;\n\n    /// Will this long comment be wrapped leaving\n    /// orphan words?\n    Person public anotherDude;\n\n    /// Constructs the dude\n    /// @param age The dude's age\n    constructor(uint256 age) {\n        theDude = Person({age: age, wallet: msg.sender});\n    }\n\n    /**\n     * @dev does nothing\n     */\n    function example() public {\n        /**\n         * Does this add a whitespace error?\n         *\n         * Let's find out.\n         */\n    }\n\n    /**\n     * @dev Calculates a rectangle's surface and perimeter.\n     * @param w Width of the rectangle.\n     * @param h Height of the rectangle.\n     * @return s The calculated surface.\n     * @return p The calculated perimeter.\n     */\n    function rectangle(uint256 w, uint256 h)\n        public\n        pure\n        returns (uint256 s, uint256 p)\n    {\n        s = w * h;\n        p = 2 * (w + h);\n    }\n\n    /// A long doc line comment that will be wrapped\n    function docLineOverflow() external {}\n\n    function docLinePostfixOverflow() external {}\n\n    /// A long doc line comment that will be wrapped\n\n    /**\n     * @notice Here is my comment\n     *       - item 1\n     *       - item 2\n     * Some equations:\n     *     y = mx + b\n     */\n    function anotherExample() external {}\n\n    /**\n     * contract A {\n     *     function foo() public {\n     *         // does nothing.\n     *     }\n     * }\n     */\n    function multilineIndent() external {}\n\n    /**\n     * contract A {\n     * function foo() public {\n     *             // does nothing.\n     *   }\n     * }\n     */\n    function multilineMalformedIndent() external {}\n\n    /**\n     * contract A {\n     * function withALongNameThatWillCauseCommentWrap() public {\n     *             // does nothing.\n     *   }\n     * }\n     */\n    function malformedIndentOverflow() external {}\n}\n\n/**\n * contract A {\n *     function foo() public {\n *         // does nothing.\n *     }\n * }\n */\nfunction freeFloatingMultilineIndent() {}\n"
  },
  {
    "path": "crates/fmt/testdata/DocComments/line.fmt.sol",
    "content": "// config: docs_style = \"line\"\npragma solidity ^0.8.13;\n\n/// @title A Hello world example\ncontract HelloWorld {\n    /// Some example struct\n    struct Person {\n        uint256 age;\n        address wallet;\n    }\n\n    /// Here's a more double asterix comment\n    Person public theDude;\n\n    /// Will this long comment be wrapped leaving\n    /// orphan words?\n    Person public anotherDude;\n\n    /// Constructs the dude\n    /// @param age The dude's age\n    constructor(uint256 age) {\n        theDude = Person({age: age, wallet: msg.sender});\n    }\n\n    /// @dev does nothing\n    function example() public {\n        /// Does this add a whitespace error?\n        ///\n        /// Let's find out.\n    }\n\n    /// @dev Calculates a rectangle's surface and perimeter.\n    /// @param w Width of the rectangle.\n    /// @param h Height of the rectangle.\n    /// @return s The calculated surface.\n    /// @return p The calculated perimeter.\n    function rectangle(uint256 w, uint256 h)\n        public\n        pure\n        returns (uint256 s, uint256 p)\n    {\n        s = w * h;\n        p = 2 * (w + h);\n    }\n\n    /// A long doc line comment that will be wrapped\n    function docLineOverflow() external {}\n\n    function docLinePostfixOverflow() external {}\n\n    /// A long doc line comment that will be wrapped\n\n    /// @notice Here is my comment\n    ///       - item 1\n    ///       - item 2\n    /// Some equations:\n    ///     y = mx + b\n    function anotherExample() external {}\n\n    /// contract A {\n    ///     function foo() public {\n    ///         // does nothing.\n    ///     }\n    /// }\n    function multilineIndent() external {}\n\n    /// contract A {\n    /// function foo() public {\n    ///             // does nothing.\n    ///   }\n    /// }\n    function multilineMalformedIndent() external {}\n\n    /// contract A {\n    /// function withALongNameThatWillCauseCommentWrap() public {\n    ///             // does nothing.\n    ///   }\n    /// }\n    function malformedIndentOverflow() external {}\n}\n\n/// contract A {\n///     function foo() public {\n///         // does nothing.\n///     }\n/// }\nfunction freeFloatingMultilineIndent() {}\n"
  },
  {
    "path": "crates/fmt/testdata/DocComments/original.sol",
    "content": "pragma solidity ^0.8.13;\n\n/// @title A Hello world example\ncontract HelloWorld {\n\n        /// Some example struct\n    struct Person {\n        uint age;\n        address wallet;\n    }\n\n            /**\n        Here's a more double asterix comment\n    */\n    Person public theDude;\n\n    /// Will this long comment be wrapped leaving\n    /// orphan words?\n    Person public anotherDude;\n\n    /// Constructs the dude\n        /// @param age The dude's age\n    constructor(uint256 age) {\n        theDude = Person({\n            age: age,\n            wallet: msg.sender\n        });\n    }\n\n    /** @dev does nothing */\n    function example() public {\n          /**\n     * Does this add a whitespace error?\n    *\n     * Let's find out.\n     */\n    }\n\n    /** @dev Calculates a rectangle's surface and perimeter.\n      * @param w Width of the rectangle.\n        * @param h Height of the rectangle.\n                * @return s The calculated surface.\n* @return p The calculated perimeter.\n      */\n    function rectangle(uint256 w, uint256 h) public pure returns (uint256 s, uint256 p) {\n        s = w * h;\n        p = 2 * (w + h);\n    }\n\n    /// A long doc line comment that will be wrapped\n    function docLineOverflow() external {}\n\n    function docLinePostfixOverflow() external {} /// A long doc line comment that will be wrapped\n\n    /**\n     * @notice Here is my comment\n     *       - item 1\n     *       - item 2\n     * Some equations:\n     *     y = mx + b\n     */\n    function anotherExample() external {}\n\n    /**\n    contract A {\n        function foo() public {\n            // does nothing.\n        }\n    }\n    */\n    function multilineIndent() external {}\n\n    /**\n    contract A {\nfunction foo() public {\n                // does nothing.\n      }\n    }\n    */\n    function multilineMalformedIndent() external {}\n\n    /**\n    contract A {\nfunction withALongNameThatWillCauseCommentWrap() public {\n                // does nothing.\n      }\n    }\n    */\n    function malformedIndentOverflow() external {}\n}\n\n/**\ncontract A {\n    function foo() public {\n        // does nothing.\n    }\n}\n*/\nfunction freeFloatingMultilineIndent() {}\n"
  },
  {
    "path": "crates/fmt/testdata/DocComments/tab.fmt.sol",
    "content": "// config: style = \"tab\"\npragma solidity ^0.8.13;\n\n/// @title A Hello world example\ncontract HelloWorld {\n\t/// Some example struct\n\tstruct Person {\n\t\tuint256 age;\n\t\taddress wallet;\n\t}\n\n\t/**\n\t *\tHere's a more double asterix comment\n\t */\n\tPerson public theDude;\n\n\t/// Will this long comment be wrapped leaving\n\t/// orphan words?\n\tPerson public anotherDude;\n\n\t/// Constructs the dude\n\t/// @param age The dude's age\n\tconstructor(uint256 age) {\n\t\ttheDude = Person({age: age, wallet: msg.sender});\n\t}\n\n\t/**\n\t *\t@dev does nothing\n\t */\n\tfunction example() public {\n\t\t/**\n\t\t *\tDoes this add a whitespace error?\n\t\t *\n\t\t *\tLet's find out.\n\t\t */\n\t}\n\n\t/**\n\t *\t@dev Calculates a rectangle's surface and perimeter.\n\t *\t@param w Width of the rectangle.\n\t *\t@param h Height of the rectangle.\n\t *\t@return s The calculated surface.\n\t *\t@return p The calculated perimeter.\n\t */\n\tfunction rectangle(uint256 w, uint256 h)\n\t\tpublic\n\t\tpure\n\t\treturns (uint256 s, uint256 p)\n\t{\n\t\ts = w * h;\n\t\tp = 2 * (w + h);\n\t}\n\n\t/// A long doc line comment that will be wrapped\n\tfunction docLineOverflow() external {}\n\n\tfunction docLinePostfixOverflow() external {}\n\n\t/// A long doc line comment that will be wrapped\n\n\t/**\n\t *\t@notice Here is my comment\n\t *\t\t- item 1\n\t *\t\t- item 2\n\t *\tSome equations:\n\t *\t\ty = mx + b\n\t */\n\tfunction anotherExample() external {}\n\n\t/**\n\t *\tcontract A {\n\t *\t\tfunction foo() public {\n\t *\t\t\t// does nothing.\n\t *\t\t}\n\t *\t}\n\t */\n\tfunction multilineIndent() external {}\n\n\t/**\n\t *\tcontract A {\n\t *\tfunction foo() public {\n\t *\t\t\t\t// does nothing.\n\t *\t\t}\n\t *\t}\n\t */\n\tfunction multilineMalformedIndent() external {}\n\n\t/**\n\t *\tcontract A {\n\t *\tfunction withALongNameThatWillCauseCommentWrap() public {\n\t *\t\t\t\t// does nothing.\n\t *\t\t}\n\t *\t}\n\t */\n\tfunction malformedIndentOverflow() external {}\n}\n\n/**\n *\tcontract A {\n *\t\tfunction foo() public {\n *\t\t\t// does nothing.\n *\t\t}\n *\t}\n */\nfunction freeFloatingMultilineIndent() {}\n"
  },
  {
    "path": "crates/fmt/testdata/DocComments/wrap-comments.fmt.sol",
    "content": "// config: line_length = 40\n// config: wrap_comments = true\npragma solidity ^0.8.13;\n\n/// @title A Hello world example\ncontract HelloWorld {\n    /// Some example struct\n    struct Person {\n        uint256 age;\n        address wallet;\n    }\n\n    /**\n     * Here's a more double asterix comment\n     */\n    Person public theDude;\n\n    /// Will this long comment be wrapped\n    /// leaving orphan words?\n    Person public anotherDude;\n\n    /// Constructs the dude\n    /// @param age The dude's age\n    constructor(uint256 age) {\n        theDude = Person({\n            age: age, wallet: msg.sender\n        });\n    }\n\n    /**\n     * @dev does nothing\n     */\n    function example() public {\n        /**\n         * Does this add a whitespace error?\n         *\n         * Let's find out.\n         */\n    }\n\n    /**\n     * @dev Calculates a rectangle's surface\n     * and perimeter.\n     * @param w Width of the rectangle.\n     * @param h Height of the rectangle.\n     * @return s The calculated surface.\n     * @return p The calculated perimeter.\n     */\n    function rectangle(\n        uint256 w,\n        uint256 h\n    )\n        public\n        pure\n        returns (uint256 s, uint256 p)\n    {\n        s = w * h;\n        p = 2 * (w + h);\n    }\n\n    /// A long doc line comment that will be\n    /// wrapped\n    function docLineOverflow() external {}\n\n    function docLinePostfixOverflow()\n        external {}\n\n    /// A long doc line comment that will be\n    /// wrapped\n\n    /**\n     * @notice Here is my comment\n     *       - item 1\n     *       - item 2\n     * Some equations:\n     *     y = mx + b\n     */\n    function anotherExample() external {}\n\n    /**\n     * contract A {\n     *     function foo() public {\n     *         // does nothing.\n     *     }\n     * }\n     */\n    function multilineIndent() external {}\n\n    /**\n     * contract A {\n     * function foo() public {\n     *             // does nothing.\n     *   }\n     * }\n     */\n    function multilineMalformedIndent()\n        external {}\n\n    /**\n     * contract A {\n     * function\n     * withALongNameThatWillCauseCommentWrap()\n     * public {\n     *             // does nothing.\n     *   }\n     * }\n     */\n    function malformedIndentOverflow()\n        external {}\n}\n\n/**\n * contract A {\n *     function foo() public {\n *         // does nothing.\n *     }\n * }\n */\nfunction freeFloatingMultilineIndent() {}\n"
  },
  {
    "path": "crates/fmt/testdata/EmitStatement/120.compact.fmt.sol",
    "content": "// config: line_length = 120\nevent NewEvent(address beneficiary, uint256 index, uint64 timestamp, uint64 endTimestamp);\n\nfunction emitEvent() {\n    emit NewEvent(beneficiary, _vestingBeneficiaries.length - 1, uint64(block.timestamp), endTimestamp);\n\n    emit NewEvent( /* beneficiary */\n        beneficiary,\n        /* index */\n        _vestingBeneficiaries.length - 1,\n        /* timestamp */\n        uint64(block.timestamp),\n        /* end timestamp */\n        endTimestamp\n    );\n\n    emit NewEvent(\n        beneficiary, // beneficiary\n        _vestingBeneficiaries.length - 1, // index\n        uint64(block.timestamp), // timestamp\n        endTimestamp // end timestamp\n    );\n\n    // https://github.com/foundry-rs/foundry/issues/12029\n    emit OperatorSharesDecreased(\n        defaultOperator,\n        address(0),\n        strategyMock,\n        depositAmount / 6 // 1 withdrawal not queued so decreased\n    );\n\n    // https://github.com/foundry-rs/foundry/issues/12146\n    emit ISablierComptroller.DisableCustomFeeUSD(\n        protocol_protocol, caller_caller, user_users.sender, previousMinFeeUSD_0, newMinFeeUSD_feeUSD\n    );\n    emit ISablierComptroller.DisableCustomFeeUSD({\n        protocol: protocol, caller: caller, user: users.sender, previousMinFeeUSD: 0, newMinFeeUSD: feeUSD\n    });\n\n    emit ISablierLockupLinear.CreateLockupLinearStream({\n        streamId: streamId,\n        commonParams: Lockup.CreateEventCommon({\n            funder: msg.sender, sender: sender, recipient: recipient, depositAmount: depositAmount\n        }),\n        cliffTime: cliffTime,\n        unlockAmounts: unlockAmounts\n    });\n}\n"
  },
  {
    "path": "crates/fmt/testdata/EmitStatement/120.fmt.sol",
    "content": "// config: line_length = 120\n// config: prefer_compact = \"none\"\nevent NewEvent(address beneficiary, uint256 index, uint64 timestamp, uint64 endTimestamp);\n\nfunction emitEvent() {\n    emit NewEvent(beneficiary, _vestingBeneficiaries.length - 1, uint64(block.timestamp), endTimestamp);\n\n    emit NewEvent( /* beneficiary */\n        beneficiary,\n        /* index */\n        _vestingBeneficiaries.length - 1,\n        /* timestamp */\n        uint64(block.timestamp),\n        /* end timestamp */\n        endTimestamp\n    );\n\n    emit NewEvent(\n        beneficiary, // beneficiary\n        _vestingBeneficiaries.length - 1, // index\n        uint64(block.timestamp), // timestamp\n        endTimestamp // end timestamp\n    );\n\n    // https://github.com/foundry-rs/foundry/issues/12029\n    emit OperatorSharesDecreased(\n        defaultOperator,\n        address(0),\n        strategyMock,\n        depositAmount / 6 // 1 withdrawal not queued so decreased\n    );\n\n    // https://github.com/foundry-rs/foundry/issues/12146\n    emit ISablierComptroller.DisableCustomFeeUSD(\n        protocol_protocol,\n        caller_caller,\n        user_users.sender,\n        previousMinFeeUSD_0,\n        newMinFeeUSD_feeUSD\n    );\n    emit ISablierComptroller.DisableCustomFeeUSD({\n        protocol: protocol,\n        caller: caller,\n        user: users.sender,\n        previousMinFeeUSD: 0,\n        newMinFeeUSD: feeUSD\n    });\n\n    emit ISablierLockupLinear.CreateLockupLinearStream({\n        streamId: streamId,\n        commonParams: Lockup.CreateEventCommon({\n            funder: msg.sender,\n            sender: sender,\n            recipient: recipient,\n            depositAmount: depositAmount\n        }),\n        cliffTime: cliffTime,\n        unlockAmounts: unlockAmounts\n    });\n}\n"
  },
  {
    "path": "crates/fmt/testdata/EmitStatement/fmt.sol",
    "content": "// config: line_length = 80\nevent NewEvent(\n    address beneficiary, uint256 index, uint64 timestamp, uint64 endTimestamp\n);\n\nfunction emitEvent() {\n    emit NewEvent(\n        beneficiary,\n        _vestingBeneficiaries.length - 1,\n        uint64(block.timestamp),\n        endTimestamp\n    );\n\n    emit NewEvent( /* beneficiary */\n        beneficiary,\n        /* index */\n        _vestingBeneficiaries.length - 1,\n        /* timestamp */\n        uint64(block.timestamp),\n        /* end timestamp */\n        endTimestamp\n    );\n\n    emit NewEvent(\n        beneficiary, // beneficiary\n        _vestingBeneficiaries.length - 1, // index\n        uint64(block.timestamp), // timestamp\n        endTimestamp // end timestamp\n    );\n\n    // https://github.com/foundry-rs/foundry/issues/12029\n    emit OperatorSharesDecreased(\n        defaultOperator,\n        address(0),\n        strategyMock,\n        depositAmount / 6 // 1 withdrawal not queued so decreased\n    );\n\n    // https://github.com/foundry-rs/foundry/issues/12146\n    emit ISablierComptroller.DisableCustomFeeUSD(\n        protocol_protocol,\n        caller_caller,\n        user_users.sender,\n        previousMinFeeUSD_0,\n        newMinFeeUSD_feeUSD\n    );\n    emit ISablierComptroller.DisableCustomFeeUSD({\n        protocol: protocol,\n        caller: caller,\n        user: users.sender,\n        previousMinFeeUSD: 0,\n        newMinFeeUSD: feeUSD\n    });\n\n    emit ISablierLockupLinear.CreateLockupLinearStream({\n        streamId: streamId,\n        commonParams: Lockup.CreateEventCommon({\n            funder: msg.sender,\n            sender: sender,\n            recipient: recipient,\n            depositAmount: depositAmount\n        }),\n        cliffTime: cliffTime,\n        unlockAmounts: unlockAmounts\n    });\n}\n"
  },
  {
    "path": "crates/fmt/testdata/EmitStatement/original.sol",
    "content": "event NewEvent(address beneficiary, uint256 index, uint64 timestamp, uint64 endTimestamp);\n\nfunction emitEvent() {\n    emit NewEvent(\n            beneficiary,\n            _vestingBeneficiaries.length - 1,\n            uint64(block.timestamp),\n            endTimestamp\n            );\n\n    emit\n        NewEvent(\n            /* beneficiary */ beneficiary,\n            /* index */ _vestingBeneficiaries.length - 1,\n        /* timestamp */   uint64(block.timestamp),\n    /* end timestamp */ endTimestamp);\n\n    emit NewEvent(\n        beneficiary, // beneficiary\n      _vestingBeneficiaries.length - 1, // index\n   uint64(block.timestamp), // timestamp\n     endTimestamp // end timestamp\n    );\n\n    // https://github.com/foundry-rs/foundry/issues/12029\n    emit OperatorSharesDecreased(\n        defaultOperator,\n        address(0),\n        strategyMock,\n        depositAmount / 6 // 1 withdrawal not queued so decreased\n    );\n\n    // https://github.com/foundry-rs/foundry/issues/12146\n    emit ISablierComptroller.DisableCustomFeeUSD(protocol_protocol, caller_caller, user_users.sender, previousMinFeeUSD_0, newMinFeeUSD_feeUSD);\n    emit ISablierComptroller.DisableCustomFeeUSD({ protocol: protocol, caller: caller, user: users.sender, previousMinFeeUSD: 0, newMinFeeUSD: feeUSD });\n\n    emit ISablierLockupLinear.CreateLockupLinearStream({\n        streamId: streamId,\n        commonParams: Lockup.CreateEventCommon({\n            funder: msg.sender,\n            sender: sender,\n            recipient: recipient,\n            depositAmount: depositAmount\n        }),\n        cliffTime: cliffTime,\n        unlockAmounts: unlockAmounts\n    });\n}\n"
  },
  {
    "path": "crates/fmt/testdata/EnumDefinition/bracket-spacing.fmt.sol",
    "content": "// config: bracket_spacing = true\ncontract EnumDefinitions {\n    enum Empty {}\n    enum ActionChoices {\n        GoLeft,\n        GoRight,\n        GoStraight,\n        SitStill\n    }\n    enum States {\n        State1,\n        State2,\n        State3,\n        State4,\n        State5,\n        State6,\n        State7,\n        State8,\n        State9\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/EnumDefinition/fmt.sol",
    "content": "contract EnumDefinitions {\n    enum Empty {}\n    enum ActionChoices {\n        GoLeft,\n        GoRight,\n        GoStraight,\n        SitStill\n    }\n    enum States {\n        State1,\n        State2,\n        State3,\n        State4,\n        State5,\n        State6,\n        State7,\n        State8,\n        State9\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/EnumDefinition/original.sol",
    "content": "contract EnumDefinitions {\n    enum Empty {\n\n    }\n    enum ActionChoices { GoLeft, GoRight, GoStraight, SitStill }\n    enum States { State1, State2, State3, State4, State5, State6, State7, State8, State9 }\n}"
  },
  {
    "path": "crates/fmt/testdata/EnumVariants/fmt.sol",
    "content": "interface I {\n    enum Empty {}\n\n    /// A modification applied to either `msg.sender` or `tx.origin`. Returned by `readCallers`.\n    enum CallerMode {\n        /// No caller modification is currently active.\n        None\n    }\n\n    /// A modification applied to either `msg.sender` or `tx.origin`. Returned by `readCallers`.\n    enum CallerMode2 {\n        /// No caller modification is currently active.\n        None, /// No caller modification is currently active2.\n\n        Some\n    }\n\n    function bar() public {}\n}\n"
  },
  {
    "path": "crates/fmt/testdata/EnumVariants/original.sol",
    "content": "interface I {\n    enum Empty {\n\n    }\n\n    /// A modification applied to either `msg.sender` or `tx.origin`. Returned by `readCallers`.\n    enum CallerMode\n    {/// No caller modification is currently active.\n        None\n    }\n\n    /// A modification applied to either `msg.sender` or `tx.origin`. Returned by `readCallers`.\n    enum CallerMode2\n    {/// No caller modification is currently active.\n        None,/// No caller modification is currently active2.\n\n        Some\n    }\n\n    function bar() public {\n\n    }\n}"
  },
  {
    "path": "crates/fmt/testdata/ErrorDefinition/fmt.sol",
    "content": "pragma solidity ^0.8.4;\n\nerror TopLevelCustomError();\nerror TopLevelCustomErrorWithArg(uint256 x);\nerror TopLevelCustomErrorArgWithoutName(string);\nerror Error1(\n    uint256, uint256, uint256, uint256, uint256, uint256, uint256, uint256\n);\n\ncontract Errors {\n    error ContractCustomError();\n    error ContractCustomErrorWithArg(uint256 x);\n    error ContractCustomErrorArgWithoutName(string);\n}\n"
  },
  {
    "path": "crates/fmt/testdata/ErrorDefinition/original.sol",
    "content": "pragma solidity ^0.8.4;\n\nerror\n  TopLevelCustomError();\n  error TopLevelCustomErrorWithArg(uint    x)  ;\nerror TopLevelCustomErrorArgWithoutName  (string);\nerror Error1(uint256, uint256, uint256, uint256, uint256, uint256, uint256, uint256);\n\ncontract Errors {\n  error\n    ContractCustomError();\n    error ContractCustomErrorWithArg(uint    x)  ;\n  error ContractCustomErrorArgWithoutName  (string);\n}"
  },
  {
    "path": "crates/fmt/testdata/EventDefinition/fmt.sol",
    "content": "pragma solidity ^0.5.2;\n\ncontract Events {\n    event Event1();\n    event Event1() anonymous;\n\n    event Event1(uint256);\n    event Event1(uint256) anonymous;\n\n    event Event1(uint256 a);\n    event Event1(uint256 a) anonymous;\n\n    event Event1(uint256 indexed);\n    event Event1(uint256 indexed) anonymous;\n\n    event Event1(uint256 indexed a);\n    event Event1(uint256 indexed a) anonymous;\n\n    event Event1(uint256, uint256, uint256, uint256, uint256, uint256, uint256);\n    event Event1(\n        uint256, uint256, uint256, uint256, uint256, uint256, uint256\n    ) anonymous;\n\n    event Event1(\n        uint256, uint256, uint256, uint256, uint256, uint256, uint256, uint256\n    );\n    event Event1(\n        uint256, uint256, uint256, uint256, uint256, uint256, uint256, uint256\n    ) anonymous;\n\n    event Event1(\n        uint256,\n        uint256,\n        uint256,\n        uint256,\n        uint256,\n        uint256,\n        uint256,\n        uint256,\n        uint256,\n        uint256,\n        uint256,\n        uint256,\n        uint256,\n        uint256,\n        uint256\n    );\n    event Event1(\n        uint256,\n        uint256,\n        uint256,\n        uint256,\n        uint256,\n        uint256,\n        uint256,\n        uint256,\n        uint256,\n        uint256,\n        uint256,\n        uint256,\n        uint256,\n        uint256,\n        uint256\n    ) anonymous;\n\n    event Event1(\n        uint256 a,\n        uint256 a,\n        uint256 a,\n        uint256 a,\n        uint256 a,\n        uint256 a,\n        uint256 a,\n        uint256 a,\n        uint256 a,\n        uint256 a,\n        uint256 a,\n        uint256 a,\n        uint256 a\n    );\n    event Event1(\n        uint256 a,\n        uint256 a,\n        uint256 a,\n        uint256 a,\n        uint256 a,\n        uint256 a,\n        uint256 a,\n        uint256 a,\n        uint256 a,\n        uint256 a,\n        uint256 a,\n        uint256 a,\n        uint256 a\n    ) anonymous;\n\n    event Event1(\n        uint256 indexed,\n        uint256 indexed,\n        uint256 indexed,\n        uint256 indexed,\n        uint256 indexed,\n        uint256 indexed,\n        uint256 indexed,\n        uint256 indexed,\n        uint256 indexed\n    );\n    event Event1(\n        uint256 indexed,\n        uint256 indexed,\n        uint256 indexed,\n        uint256 indexed,\n        uint256 indexed,\n        uint256 indexed,\n        uint256 indexed,\n        uint256 indexed,\n        uint256 indexed\n    ) anonymous;\n\n    event Event1(\n        uint256 indexed a,\n        uint256 indexed a,\n        uint256 indexed a,\n        uint256 indexed a,\n        uint256 indexed a,\n        uint256 indexed a,\n        uint256 indexed a,\n        uint256 indexed a,\n        uint256 indexed a,\n        uint256 indexed a\n    );\n    event Event1(\n        uint256 indexed a,\n        uint256 indexed a,\n        uint256 indexed a,\n        uint256 indexed a,\n        uint256 indexed a,\n        uint256 indexed a,\n        uint256 indexed a,\n        uint256 indexed a,\n        uint256 indexed a,\n        uint256 indexed a\n    ) anonymous;\n}\n"
  },
  {
    "path": "crates/fmt/testdata/EventDefinition/original.sol",
    "content": "pragma solidity ^0.5.2;\n\ncontract Events {\n    event Event1();\n    event Event1() anonymous;\n\n    event Event1(uint256);\n    event Event1(uint256) anonymous;\n\n    event Event1(uint256 a);\n    event Event1(uint256 a) anonymous;\n\n    event Event1(uint256 indexed);\n    event Event1(uint256 indexed) anonymous;\n\n    event Event1(uint256 indexed a);\n    event Event1(uint256 indexed a) anonymous;\n\n    event Event1(uint256, uint256, uint256, uint256, uint256, uint256, uint256);\n    event Event1(uint256, uint256, uint256, uint256, uint256, uint256, uint256) anonymous;\n\n    event Event1(uint256, uint256, uint256, uint256, uint256, uint256, uint256, uint256);\n    event Event1(uint256, uint256, uint256, uint256, uint256, uint256, uint256, uint256) anonymous;\n\n    event Event1(uint256, uint256, uint256, uint256, uint256, uint256, uint256, uint256, uint256, uint256, uint256, uint256, uint256, uint256, uint256);\n    event Event1(uint256, uint256, uint256, uint256, uint256, uint256, uint256, uint256, uint256, uint256, uint256, uint256, uint256, uint256, uint256) anonymous;\n\n    event Event1(uint256 a, uint256 a, uint256 a, uint256 a, uint256 a, uint256 a, uint256 a, uint256 a, uint256 a, uint256 a, uint256 a, uint256 a, uint256 a);\n    event Event1(uint256 a, uint256 a, uint256 a, uint256 a, uint256 a, uint256 a, uint256 a, uint256 a, uint256 a, uint256 a, uint256 a, uint256 a, uint256 a) anonymous;\n\n    event Event1(uint256 indexed, uint256 indexed, uint256 indexed, uint256 indexed, uint256 indexed, uint256 indexed, uint256 indexed, uint256 indexed, uint256 indexed);\n    event Event1(uint256 indexed, uint256 indexed, uint256 indexed, uint256 indexed, uint256 indexed, uint256 indexed, uint256 indexed, uint256 indexed, uint256 indexed) anonymous;\n\n    event Event1(uint256 indexed a, uint256 indexed a, uint256 indexed a, uint256 indexed a, uint256 indexed a, uint256 indexed a, uint256 indexed a, uint256 indexed a, uint256 indexed a, uint256 indexed a);\n    event Event1(uint256 indexed a, uint256 indexed a, uint256 indexed a, uint256 indexed a, uint256 indexed a, uint256 indexed a, uint256 indexed a, uint256 indexed a, uint256 indexed a, uint256 indexed a) anonymous;\n}\n"
  },
  {
    "path": "crates/fmt/testdata/ForStatement/fmt.sol",
    "content": "pragma solidity ^0.8.8;\n\ncontract ForStatement {\n    function test() external {\n        for (uint256 i1; i1 < 10; i1++) {\n            i1++;\n        }\n\n        uint256 i2;\n        for (++i2; i2 < 10; i2++) {}\n\n        uint256 veryLongVariableName = 1000;\n        for (\n            uint256 i3;\n            i3 < 10 && veryLongVariableName > 999\n                && veryLongVariableName < 1001;\n            i3++\n        ) {\n            i3++;\n        }\n\n        for (\n            uint256 i3;\n            i3 < 10 && veryLongVariableName > 900 && veryLongVariableName < 999;\n            i3++\n        ) {\n            i3++;\n        }\n\n        for (type(uint256).min;;) {}\n\n        for (;;) {\n            \"test\";\n        }\n\n        for (uint256 i4; i4 < 10; i4++) {\n            i4++;\n        }\n\n        for (uint256 i5;;) {\n            for (uint256 i6 = 10; i6 > i5; i6--) {\n                i5++;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/ForStatement/original.sol",
    "content": "pragma solidity ^0.8.8;\n\ncontract ForStatement {\n    function test() external {\n        for\n    (uint256 i1\n        ; i1 < 10;      i1++)\n    {\n             i1++;\n            }\n\n        uint256 i2;\n        for(++i2;i2<10;i2++)\n\n        {}\n\n        uint256 veryLongVariableName = 1000;\n        for ( uint256 i3; i3 < 10\n        && veryLongVariableName>999 &&      veryLongVariableName< 1001\n        ; i3++)\n        { i3 ++ ; }\n\n        for ( uint256 i3; i3 < 10\n        && veryLongVariableName>900 &&      veryLongVariableName< 999\n        ; i3++)\n        { i3 ++ ; }\n\n\n        for (type(uint256).min;;) {}\n\n        for (;;) { \"test\" ; }\n\n        for (uint256 i4; i4< 10; i4++) i4++;\n\n        for (uint256 i5; ;)\n            for (uint256 i6 = 10; i6 > i5; i6--)\n                i5++;\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/FunctionCall/bracket-spacing.fmt.sol",
    "content": "// config: line_length = 120\n// config: bracket_spacing = true\ncontract FunctionCall {\n    function foo() public pure {\n        bar(1111111111111111111111111111111111111111111111111111, 111111111111111111111111111111111111111111111111111);\n        bar(1111111111111111111111111111111111111111111111111112, 1111111111111111111111111111111111111111111111111112);\n        bar(1111111111111111111111111111111111111111111111111113, 11111111111111111111111111111111111111111111111111113); // the semicolon is not considered when determining line break\n        bar(\n            1111111111111111111111111111111111111111111111111114, 111111111111111111111111111111111111111111111111111114\n        );\n        bar(\n            111111111111111111111111111111111115,\n            11111111111111111111111111111111115,\n            11111111111111111111111111111111115\n        );\n        bar(\n            111111111111111111111111111111111111111111111111111116,\n            111111111111111111111111111111111111111111111111111116\n        );\n        bar(\n            111111111111111111111111111111111111111111111111111117,\n            1111111111111111111111111111111111111111111111111111117\n        );\n    }\n\n    function bar(uint256, uint256) private pure {\n        return;\n    }\n}\n\nfunction a(uint256 foo) {\n    foo;\n    MyContract c = new MyContract(address(0), hex\"beef\");\n}\n\nfunction b() {\n    a({ foo: 5 });\n}\n\ncontract MyContract {\n    constructor(address arg, bytes memory data) { }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/FunctionCall/fmt.sol",
    "content": "// config: line_length = 120\ncontract FunctionCall {\n    function foo() public pure {\n        bar(1111111111111111111111111111111111111111111111111111, 111111111111111111111111111111111111111111111111111);\n        bar(1111111111111111111111111111111111111111111111111112, 1111111111111111111111111111111111111111111111111112);\n        bar(1111111111111111111111111111111111111111111111111113, 11111111111111111111111111111111111111111111111111113); // the semicolon is not considered when determining line break\n        bar(\n            1111111111111111111111111111111111111111111111111114, 111111111111111111111111111111111111111111111111111114\n        );\n        bar(\n            111111111111111111111111111111111115,\n            11111111111111111111111111111111115,\n            11111111111111111111111111111111115\n        );\n        bar(\n            111111111111111111111111111111111111111111111111111116,\n            111111111111111111111111111111111111111111111111111116\n        );\n        bar(\n            111111111111111111111111111111111111111111111111111117,\n            1111111111111111111111111111111111111111111111111111117\n        );\n    }\n\n    function bar(uint256, uint256) private pure {\n        return;\n    }\n}\n\nfunction a(uint256 foo) {\n    foo;\n    MyContract c = new MyContract(address(0), hex\"beef\");\n}\n\nfunction b() {\n    a({foo: 5});\n}\n\ncontract MyContract {\n    constructor(address arg, bytes memory data) {}\n}\n"
  },
  {
    "path": "crates/fmt/testdata/FunctionCall/original.sol",
    "content": "contract FunctionCall {\n    function foo() public pure {\n        bar(1111111111111111111111111111111111111111111111111111, 111111111111111111111111111111111111111111111111111);\n        bar(1111111111111111111111111111111111111111111111111112, 1111111111111111111111111111111111111111111111111112);\n        bar(1111111111111111111111111111111111111111111111111113, 11111111111111111111111111111111111111111111111111113);  // the semicolon is not considered when determining line break\n        bar(1111111111111111111111111111111111111111111111111114, 111111111111111111111111111111111111111111111111111114);\n        bar(\n            111111111111111111111111111111111115, 11111111111111111111111111111111115, 11111111111111111111111111111111115\n        );\n        bar(\n            111111111111111111111111111111111111111111111111111116, 111111111111111111111111111111111111111111111111111116\n        );\n        bar(\n            111111111111111111111111111111111111111111111111111117, 1111111111111111111111111111111111111111111111111111117\n        );\n    }\n\n    function bar(uint256, uint256) private pure {\n        return;\n    }\n}\n\nfunction a(uint256 foo) {\n    foo;\n    MyContract c = new  MyContract(address( 0),hex\"beef\");\n}\n\nfunction b() {\n    a( {foo: 5} );\n}\n\ncontract MyContract {\n    constructor(address arg, bytes memory data) {}\n}\n"
  },
  {
    "path": "crates/fmt/testdata/FunctionCallArgsStatement/bracket-spacing.fmt.sol",
    "content": "// config: line_length = 120\n// config: bracket_spacing = true\ninterface ITarget {\n    function run() external payable;\n    function veryAndVeryLongNameOfSomeRunFunction() external payable;\n}\n\ncontract FunctionCallArgsStatement {\n    ITarget public target;\n\n    function estimate() public returns (uint256 gas) {\n        gas = 1 gwei;\n    }\n\n    function veryAndVeryLongNameOfSomeGasEstimateFunction() public returns (uint256) {\n        return gasleft();\n    }\n\n    function value(uint256 val) public returns (uint256) {\n        return val;\n    }\n\n    function test() external {\n        target.run{ gas: gasleft(), value: 1 wei };\n\n        target.run{ gas: 1, value: 0x00 }();\n\n        target.run{ gas: 1000, value: 1 ether }();\n\n        target.run{ gas: estimate(), value: value(1) }();\n\n        target.run{ value: value(1 ether), gas: veryAndVeryLongNameOfSomeGasEstimateFunction() }();\n\n        target.run{ /* comment 1 */\n            value: /* comment2 */ 1\n        };\n\n        target.run{ /* comment3 */\n            value: 1, // comment4\n            gas: gasleft()\n        };\n\n        target.run{\n            // comment5\n            value: 1,\n            // comment6\n            gas: gasleft()\n        };\n\n        vm.expectEmit({ checkTopic1: false, checkTopic2: false });\n\n        lockup.withdraw{ value: LOCKUP_MIN_FEE_WEI }({\n            streamId: streamId, to: users.recipient, amount: withdrawAmount\n        });\n        portal.xcall{ value: msg.value }(id, ConfLevel.Finalized, Predeploys.NominaBridgeNative, xcalldata);\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/FunctionCallArgsStatement/fmt.sol",
    "content": "interface ITarget {\n    function run() external payable;\n    function veryAndVeryLongNameOfSomeRunFunction() external payable;\n}\n\ncontract FunctionCallArgsStatement {\n    ITarget public target;\n\n    function estimate() public returns (uint256 gas) {\n        gas = 1 gwei;\n    }\n\n    function veryAndVeryLongNameOfSomeGasEstimateFunction()\n        public\n        returns (uint256)\n    {\n        return gasleft();\n    }\n\n    function value(uint256 val) public returns (uint256) {\n        return val;\n    }\n\n    function test() external {\n        target.run{gas: gasleft(), value: 1 wei};\n\n        target.run{gas: 1, value: 0x00}();\n\n        target.run{gas: 1000, value: 1 ether}();\n\n        target.run{gas: estimate(), value: value(1)}();\n\n        target.run{\n            value: value(1 ether),\n            gas: veryAndVeryLongNameOfSomeGasEstimateFunction()\n        }();\n\n        target.run{ /* comment 1 */\n            value: /* comment2 */ 1\n        };\n\n        target.run{ /* comment3 */\n            value: 1, // comment4\n            gas: gasleft()\n        };\n\n        target.run{\n            // comment5\n            value: 1,\n            // comment6\n            gas: gasleft()\n        };\n\n        vm.expectEmit({checkTopic1: false, checkTopic2: false});\n\n        lockup.withdraw{value: LOCKUP_MIN_FEE_WEI}({\n            streamId: streamId, to: users.recipient, amount: withdrawAmount\n        });\n        portal.xcall{value: msg.value}(\n            id, ConfLevel.Finalized, Predeploys.NominaBridgeNative, xcalldata\n        );\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/FunctionCallArgsStatement/original.sol",
    "content": "interface ITarget {\n    function run() external payable;\n    function veryAndVeryLongNameOfSomeRunFunction() external payable;\n}\n\ncontract FunctionCallArgsStatement {\n    ITarget public target;\n\n    function estimate() public returns (uint256 gas) {\n        gas = 1 gwei;\n    }\n\n    function veryAndVeryLongNameOfSomeGasEstimateFunction() public returns (uint256) {\n        return gasleft();\n    }\n\n    function value(uint256 val) public returns (uint256) {\n        return val;\n    }\n\n    function test() external {\n        target.run{ gas: gasleft(), value: 1 wei };\n\n        target.run{gas:1,value:0x00}();\n\n        target.run{\n                gas : 1000,\n        value: 1 ether\n        } ();\n\n        target.run{  gas: estimate(),\n    value: value(1) }();\n\n        target.run { value:\n        value(1 ether), gas: veryAndVeryLongNameOfSomeGasEstimateFunction() } ();\n\n        target.run /* comment 1 */ { value: /* comment2 */ 1 };\n\n        target.run { /* comment3 */ value: 1, // comment4\n        gas: gasleft()};\n\n        target.run {\n            // comment5\n            value: 1,\n            // comment6\n            gas: gasleft()};\n\n        vm.expectEmit({ checkTopic1: false, checkTopic2: false    });\n\n        lockup.withdraw{ value: LOCKUP_MIN_FEE_WEI }({ streamId: streamId, to: users.recipient, amount: withdrawAmount });\n        portal.xcall{ value: msg.value }(id, ConfLevel.Finalized, Predeploys.NominaBridgeNative, xcalldata);\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/FunctionDefinition/all-params.fmt.sol",
    "content": "// config: line_length = 60\n// config: multiline_func_header = \"all_params\"\ninterface FunctionInterfaces {\n    function noParamsNoModifiersNoReturns();\n\n    function oneParam(uint256 x);\n\n    function oneModifier() modifier1;\n\n    function oneReturn() returns (uint256 y1);\n\n    // function prefix\n    function withComments( // function name postfix\n        // x1 prefix\n        uint256 x1, // x1 postfix\n        // x2 prefix\n        uint256 x2, // x2 postfix\n        // x2 postfix2\n        /*\n            multi-line x3 prefix\n        */\n        uint256 x3 // x3 postfix\n    )\n        // public prefix\n        public // public postfix\n        // pure prefix\n        pure // pure postfix\n        // modifier1 prefix\n        modifier1 // modifier1 postfix\n        // modifier2 prefix\n        modifier2 /*\n                    mutliline modifier2 postfix\n                    */\n        // modifier3 prefix\n        modifier3 // modifier3 postfix\n        returns (\n            // y1 prefix\n            uint256 y1, // y1 postfix\n            // y2 prefix\n            uint256 y2, // y2 postfix\n            // y3 prefix\n            uint256 y3 // y3 postfix\n        ); // function postfix\n\n    /*//////////////////////////////////////////////////////////////////////////\n                                    TEST\n    //////////////////////////////////////////////////////////////////////////*/\n    function manyParams(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3,\n        uint256 x4,\n        uint256 x5,\n        uint256 x6,\n        uint256 x7,\n        uint256 x8,\n        uint256 x9,\n        uint256 x10\n    );\n\n    function manyModifiers()\n        modifier1\n        modifier2\n        modifier3\n        modifier4\n        modifier5\n        modifier6\n        modifier7\n        modifier8\n        modifier9\n        modifier10;\n\n    function manyReturns()\n        returns (\n            uint256 y1,\n            uint256 y2,\n            uint256 y3,\n            uint256 y4,\n            uint256 y5,\n            uint256 y6,\n            uint256 y7,\n            uint256 y8,\n            uint256 y9,\n            uint256 y10\n        );\n\n    function someParamsSomeModifiers(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3\n    )\n        modifier1\n        modifier2\n        modifier3;\n\n    function someParamsSomeReturns(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3\n    )\n        returns (uint256 y1, uint256 y2, uint256 y3);\n\n    function someModifiersSomeReturns()\n        modifier1\n        modifier2\n        modifier3\n        returns (uint256 y1, uint256 y2, uint256 y3);\n\n    function someParamSomeModifiersSomeReturns(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3\n    )\n        modifier1\n        modifier2\n        modifier3\n        returns (uint256 y1, uint256 y2, uint256 y3);\n\n    function someParamsManyModifiers(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3\n    )\n        modifier1\n        modifier2\n        modifier3\n        modifier4\n        modifier5\n        modifier6\n        modifier7\n        modifier8\n        modifier9\n        modifier10;\n\n    function someParamsManyReturns(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3\n    )\n        returns (\n            uint256 y1,\n            uint256 y2,\n            uint256 y3,\n            uint256 y4,\n            uint256 y5,\n            uint256 y6,\n            uint256 y7,\n            uint256 y8,\n            uint256 y9,\n            uint256 y10\n        );\n\n    function manyParamsSomeModifiers(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3,\n        uint256 x4,\n        uint256 x5,\n        uint256 x6,\n        uint256 x7,\n        uint256 x8,\n        uint256 x9,\n        uint256 x10\n    )\n        modifier1\n        modifier2\n        modifier3;\n\n    function manyParamsSomeReturns(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3,\n        uint256 x4,\n        uint256 x5,\n        uint256 x6,\n        uint256 x7,\n        uint256 x8,\n        uint256 x9,\n        uint256 x10\n    )\n        returns (uint256 y1, uint256 y2, uint256 y3);\n\n    function manyParamsManyModifiers(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3,\n        uint256 x4,\n        uint256 x5,\n        uint256 x6,\n        uint256 x7,\n        uint256 x8,\n        uint256 x9,\n        uint256 x10\n    )\n        modifier1\n        modifier2\n        modifier3\n        modifier4\n        modifier5\n        modifier6\n        modifier7\n        modifier8\n        modifier9\n        modifier10;\n\n    function manyParamsManyReturns(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3,\n        uint256 x4,\n        uint256 x5,\n        uint256 x6,\n        uint256 x7,\n        uint256 x8,\n        uint256 x9,\n        uint256 x10\n    )\n        returns (\n            uint256 y1,\n            uint256 y2,\n            uint256 y3,\n            uint256 y4,\n            uint256 y5,\n            uint256 y6,\n            uint256 y7,\n            uint256 y8,\n            uint256 y9,\n            uint256 y10\n        );\n\n    function manyParamsManyModifiersManyReturns(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3,\n        uint256 x4,\n        uint256 x5,\n        uint256 x6,\n        uint256 x7,\n        uint256 x8,\n        uint256 x9,\n        uint256 x10\n    )\n        modifier1\n        modifier2\n        modifier3\n        modifier4\n        modifier5\n        modifier6\n        modifier7\n        modifier8\n        modifier9\n        modifier10\n        returns (\n            uint256 y1,\n            uint256 y2,\n            uint256 y3,\n            uint256 y4,\n            uint256 y5,\n            uint256 y6,\n            uint256 y7,\n            uint256 y8,\n            uint256 y9,\n            uint256 y10\n        );\n\n    function modifierOrderCorrect01()\n        public\n        view\n        virtual\n        override\n        modifier1\n        modifier2\n        returns (uint256);\n\n    function modifierOrderCorrect02()\n        private\n        pure\n        virtual\n        modifier1\n        modifier2\n        returns (string);\n\n    function modifierOrderCorrect03()\n        external\n        payable\n        override\n        modifier1\n        modifier2\n        returns (address);\n\n    function modifierOrderCorrect04()\n        internal\n        virtual\n        override\n        modifier1\n        modifier2\n        returns (uint256);\n\n    function modifierOrderIncorrect01()\n        public\n        view\n        virtual\n        override\n        modifier1\n        modifier2\n        returns (uint256);\n\n    function modifierOrderIncorrect02()\n        external\n        virtual\n        override\n        modifier1\n        modifier2\n        returns (uint256);\n\n    function modifierOrderIncorrect03()\n        internal\n        pure\n        virtual\n        modifier1\n        modifier2\n        returns (uint256);\n\n    function modifierOrderIncorrect04()\n        external\n        payable\n        override\n        modifier1\n        modifier2\n        returns (uint256);\n}\n\ncontract FunctionDefinitions {\n    function f() external {}\n    fallback() external {}\n\n    function f() external payable {}\n    fallback() external payable {}\n    receive() external payable {}\n\n    function noParamsNoModifiersNoReturns() {\n        a = 1;\n    }\n\n    function oneParam(uint256 x) {\n        a = 1;\n    }\n\n    function oneModifier() modifier1 {\n        a = 1;\n    }\n\n    function oneReturn() returns (uint256 y1) {\n        a = 1;\n    }\n\n    function manyParams(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3,\n        uint256 x4,\n        uint256 x5,\n        uint256 x6,\n        uint256 x7,\n        uint256 x8,\n        uint256 x9,\n        uint256 x10\n    ) {\n        a = 1;\n    }\n\n    function manyModifiers()\n        modifier1\n        modifier2\n        modifier3\n        modifier4\n        modifier5\n        modifier6\n        modifier7\n        modifier8\n        modifier9\n        modifier10\n    {\n        a = 1;\n    }\n\n    function manyReturns()\n        returns (\n            uint256 y1,\n            uint256 y2,\n            uint256 y3,\n            uint256 y4,\n            uint256 y5,\n            uint256 y6,\n            uint256 y7,\n            uint256 y8,\n            uint256 y9,\n            uint256 y10\n        )\n    {\n        a = 1;\n    }\n\n    function someParamsSomeModifiers(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3\n    )\n        modifier1\n        modifier2\n        modifier3\n    {\n        a = 1;\n    }\n\n    function someParamsSomeReturns(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3\n    )\n        returns (uint256 y1, uint256 y2, uint256 y3)\n    {\n        a = 1;\n    }\n\n    function someModifiersSomeReturns()\n        modifier1\n        modifier2\n        modifier3\n        returns (uint256 y1, uint256 y2, uint256 y3)\n    {\n        a = 1;\n    }\n\n    function someParamSomeModifiersSomeReturns(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3\n    )\n        modifier1\n        modifier2\n        modifier3\n        returns (uint256 y1, uint256 y2, uint256 y3)\n    {\n        a = 1;\n    }\n\n    function someParamsManyModifiers(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3\n    )\n        modifier1\n        modifier2\n        modifier3\n        modifier4\n        modifier5\n        modifier6\n        modifier7\n        modifier8\n        modifier9\n        modifier10\n    {\n        a = 1;\n    }\n\n    function someParamsManyReturns(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3\n    )\n        returns (\n            uint256 y1,\n            uint256 y2,\n            uint256 y3,\n            uint256 y4,\n            uint256 y5,\n            uint256 y6,\n            uint256 y7,\n            uint256 y8,\n            uint256 y9,\n            uint256 y10\n        )\n    {\n        a = 1;\n    }\n\n    function manyParamsSomeModifiers(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3,\n        uint256 x4,\n        uint256 x5,\n        uint256 x6,\n        uint256 x7,\n        uint256 x8,\n        uint256 x9,\n        uint256 x10\n    )\n        modifier1\n        modifier2\n        modifier3\n    {\n        a = 1;\n    }\n\n    function manyParamsSomeReturns(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3,\n        uint256 x4,\n        uint256 x5,\n        uint256 x6,\n        uint256 x7,\n        uint256 x8,\n        uint256 x9,\n        uint256 x10\n    )\n        returns (uint256 y1, uint256 y2, uint256 y3)\n    {\n        a = 1;\n    }\n\n    function manyParamsManyModifiers(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3,\n        uint256 x4,\n        uint256 x5,\n        uint256 x6,\n        uint256 x7,\n        uint256 x8,\n        uint256 x9,\n        uint256 x10\n    )\n        public\n        modifier1\n        modifier2\n        modifier3\n        modifier4\n        modifier5\n        modifier6\n        modifier7\n        modifier8\n        modifier9\n        modifier10\n    {\n        a = 1;\n    }\n\n    function manyParamsManyReturns(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3,\n        uint256 x4,\n        uint256 x5,\n        uint256 x6,\n        uint256 x7,\n        uint256 x8,\n        uint256 x9,\n        uint256 x10\n    )\n        returns (\n            uint256 y1,\n            uint256 y2,\n            uint256 y3,\n            uint256 y4,\n            uint256 y5,\n            uint256 y6,\n            uint256 y7,\n            uint256 y8,\n            uint256 y9,\n            uint256 y10\n        )\n    {\n        a = 1;\n    }\n\n    function manyParamsManyModifiersManyReturns(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3,\n        uint256 x4,\n        uint256 x5,\n        uint256 x6,\n        uint256 x7,\n        uint256 x8,\n        uint256 x9,\n        uint256 x10\n    )\n        modifier1\n        modifier2\n        modifier3\n        modifier4\n        modifier5\n        modifier6\n        modifier7\n        modifier8\n        modifier9\n        modifier10\n        returns (\n            uint256 y1,\n            uint256 y2,\n            uint256 y3,\n            uint256 y4,\n            uint256 y5,\n            uint256 y6,\n            uint256 y7,\n            uint256 y8,\n            uint256 y9,\n            uint256 y10\n        )\n    {\n        a = 1;\n    }\n\n    function modifierOrderCorrect01()\n        public\n        view\n        virtual\n        override\n        modifier1\n        modifier2\n        returns (uint256)\n    {\n        a = 1;\n    }\n\n    function modifierOrderCorrect02()\n        private\n        pure\n        virtual\n        modifier1\n        modifier2\n        returns (string)\n    {\n        a = 1;\n    }\n\n    function modifierOrderCorrect03()\n        external\n        payable\n        override\n        modifier1\n        modifier2\n        returns (address)\n    {\n        a = 1;\n    }\n\n    function modifierOrderCorrect04()\n        internal\n        virtual\n        override\n        modifier1\n        modifier2\n        returns (uint256)\n    {\n        a = 1;\n    }\n\n    function modifierOrderIncorrect01()\n        public\n        view\n        virtual\n        override\n        modifier1\n        modifier2\n        returns (uint256)\n    {\n        a = 1;\n    }\n\n    function modifierOrderIncorrect02()\n        external\n        virtual\n        override\n        modifier1\n        modifier2\n        returns (uint256)\n    {\n        a = 1;\n    }\n\n    function modifierOrderIncorrect03()\n        internal\n        pure\n        virtual\n        modifier1\n        modifier2\n        returns (uint256)\n    {\n        a = 1;\n    }\n\n    function modifierOrderIncorrect04()\n        external\n        payable\n        override\n        modifier1\n        modifier2\n        returns (uint256)\n    {\n        a = 1;\n    }\n\n    fallback() external payable virtual {}\n    receive() external payable virtual {}\n}\n\ncontract FunctionOverrides is\n    FunctionInterfaces,\n    FunctionDefinitions\n{\n    function noParamsNoModifiersNoReturns() override {\n        a = 1;\n    }\n\n    function oneParam(\n        uint256 x\n    )\n        override(\n            FunctionInterfaces,\n            FunctionDefinitions,\n            SomeOtherFunctionContract,\n            SomeImport.AndAnotherFunctionContract\n        )\n    {\n        a = 1;\n    }\n\n    function simple(\n        address _target,\n        bytes memory _payload\n    )\n        internal\n    {\n        a = 1;\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/FunctionDefinition/all.fmt.sol",
    "content": "// config: line_length = 60\n// config: multiline_func_header = \"all\"\ninterface FunctionInterfaces {\n    function noParamsNoModifiersNoReturns();\n\n    function oneParam(uint256 x);\n\n    function oneModifier() modifier1;\n\n    function oneReturn() returns (uint256 y1);\n\n    // function prefix\n    function withComments( // function name postfix\n        // x1 prefix\n        uint256 x1, // x1 postfix\n        // x2 prefix\n        uint256 x2, // x2 postfix\n        // x2 postfix2\n        /*\n            multi-line x3 prefix\n        */\n        uint256 x3 // x3 postfix\n    )\n        // public prefix\n        public // public postfix\n        // pure prefix\n        pure // pure postfix\n        // modifier1 prefix\n        modifier1 // modifier1 postfix\n        // modifier2 prefix\n        modifier2 /*\n                    mutliline modifier2 postfix\n                    */\n        // modifier3 prefix\n        modifier3 // modifier3 postfix\n        returns (\n            // y1 prefix\n            uint256 y1, // y1 postfix\n            // y2 prefix\n            uint256 y2, // y2 postfix\n            // y3 prefix\n            uint256 y3 // y3 postfix\n        ); // function postfix\n\n    /*//////////////////////////////////////////////////////////////////////////\n                                    TEST\n    //////////////////////////////////////////////////////////////////////////*/\n    function manyParams(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3,\n        uint256 x4,\n        uint256 x5,\n        uint256 x6,\n        uint256 x7,\n        uint256 x8,\n        uint256 x9,\n        uint256 x10\n    );\n\n    function manyModifiers()\n        modifier1\n        modifier2\n        modifier3\n        modifier4\n        modifier5\n        modifier6\n        modifier7\n        modifier8\n        modifier9\n        modifier10;\n\n    function manyReturns()\n        returns (\n            uint256 y1,\n            uint256 y2,\n            uint256 y3,\n            uint256 y4,\n            uint256 y5,\n            uint256 y6,\n            uint256 y7,\n            uint256 y8,\n            uint256 y9,\n            uint256 y10\n        );\n\n    function someParamsSomeModifiers(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3\n    )\n        modifier1\n        modifier2\n        modifier3;\n\n    function someParamsSomeReturns(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3\n    )\n        returns (uint256 y1, uint256 y2, uint256 y3);\n\n    function someModifiersSomeReturns()\n        modifier1\n        modifier2\n        modifier3\n        returns (uint256 y1, uint256 y2, uint256 y3);\n\n    function someParamSomeModifiersSomeReturns(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3\n    )\n        modifier1\n        modifier2\n        modifier3\n        returns (uint256 y1, uint256 y2, uint256 y3);\n\n    function someParamsManyModifiers(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3\n    )\n        modifier1\n        modifier2\n        modifier3\n        modifier4\n        modifier5\n        modifier6\n        modifier7\n        modifier8\n        modifier9\n        modifier10;\n\n    function someParamsManyReturns(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3\n    )\n        returns (\n            uint256 y1,\n            uint256 y2,\n            uint256 y3,\n            uint256 y4,\n            uint256 y5,\n            uint256 y6,\n            uint256 y7,\n            uint256 y8,\n            uint256 y9,\n            uint256 y10\n        );\n\n    function manyParamsSomeModifiers(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3,\n        uint256 x4,\n        uint256 x5,\n        uint256 x6,\n        uint256 x7,\n        uint256 x8,\n        uint256 x9,\n        uint256 x10\n    )\n        modifier1\n        modifier2\n        modifier3;\n\n    function manyParamsSomeReturns(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3,\n        uint256 x4,\n        uint256 x5,\n        uint256 x6,\n        uint256 x7,\n        uint256 x8,\n        uint256 x9,\n        uint256 x10\n    )\n        returns (uint256 y1, uint256 y2, uint256 y3);\n\n    function manyParamsManyModifiers(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3,\n        uint256 x4,\n        uint256 x5,\n        uint256 x6,\n        uint256 x7,\n        uint256 x8,\n        uint256 x9,\n        uint256 x10\n    )\n        modifier1\n        modifier2\n        modifier3\n        modifier4\n        modifier5\n        modifier6\n        modifier7\n        modifier8\n        modifier9\n        modifier10;\n\n    function manyParamsManyReturns(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3,\n        uint256 x4,\n        uint256 x5,\n        uint256 x6,\n        uint256 x7,\n        uint256 x8,\n        uint256 x9,\n        uint256 x10\n    )\n        returns (\n            uint256 y1,\n            uint256 y2,\n            uint256 y3,\n            uint256 y4,\n            uint256 y5,\n            uint256 y6,\n            uint256 y7,\n            uint256 y8,\n            uint256 y9,\n            uint256 y10\n        );\n\n    function manyParamsManyModifiersManyReturns(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3,\n        uint256 x4,\n        uint256 x5,\n        uint256 x6,\n        uint256 x7,\n        uint256 x8,\n        uint256 x9,\n        uint256 x10\n    )\n        modifier1\n        modifier2\n        modifier3\n        modifier4\n        modifier5\n        modifier6\n        modifier7\n        modifier8\n        modifier9\n        modifier10\n        returns (\n            uint256 y1,\n            uint256 y2,\n            uint256 y3,\n            uint256 y4,\n            uint256 y5,\n            uint256 y6,\n            uint256 y7,\n            uint256 y8,\n            uint256 y9,\n            uint256 y10\n        );\n\n    function modifierOrderCorrect01()\n        public\n        view\n        virtual\n        override\n        modifier1\n        modifier2\n        returns (uint256);\n\n    function modifierOrderCorrect02()\n        private\n        pure\n        virtual\n        modifier1\n        modifier2\n        returns (string);\n\n    function modifierOrderCorrect03()\n        external\n        payable\n        override\n        modifier1\n        modifier2\n        returns (address);\n\n    function modifierOrderCorrect04()\n        internal\n        virtual\n        override\n        modifier1\n        modifier2\n        returns (uint256);\n\n    function modifierOrderIncorrect01()\n        public\n        view\n        virtual\n        override\n        modifier1\n        modifier2\n        returns (uint256);\n\n    function modifierOrderIncorrect02()\n        external\n        virtual\n        override\n        modifier1\n        modifier2\n        returns (uint256);\n\n    function modifierOrderIncorrect03()\n        internal\n        pure\n        virtual\n        modifier1\n        modifier2\n        returns (uint256);\n\n    function modifierOrderIncorrect04()\n        external\n        payable\n        override\n        modifier1\n        modifier2\n        returns (uint256);\n}\n\ncontract FunctionDefinitions {\n    function f() external {}\n    fallback() external {}\n\n    function f() external payable {}\n    fallback() external payable {}\n    receive() external payable {}\n\n    function noParamsNoModifiersNoReturns() {\n        a = 1;\n    }\n\n    function oneParam(uint256 x) {\n        a = 1;\n    }\n\n    function oneModifier() modifier1 {\n        a = 1;\n    }\n\n    function oneReturn() returns (uint256 y1) {\n        a = 1;\n    }\n\n    function manyParams(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3,\n        uint256 x4,\n        uint256 x5,\n        uint256 x6,\n        uint256 x7,\n        uint256 x8,\n        uint256 x9,\n        uint256 x10\n    ) {\n        a = 1;\n    }\n\n    function manyModifiers()\n        modifier1\n        modifier2\n        modifier3\n        modifier4\n        modifier5\n        modifier6\n        modifier7\n        modifier8\n        modifier9\n        modifier10\n    {\n        a = 1;\n    }\n\n    function manyReturns()\n        returns (\n            uint256 y1,\n            uint256 y2,\n            uint256 y3,\n            uint256 y4,\n            uint256 y5,\n            uint256 y6,\n            uint256 y7,\n            uint256 y8,\n            uint256 y9,\n            uint256 y10\n        )\n    {\n        a = 1;\n    }\n\n    function someParamsSomeModifiers(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3\n    )\n        modifier1\n        modifier2\n        modifier3\n    {\n        a = 1;\n    }\n\n    function someParamsSomeReturns(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3\n    )\n        returns (uint256 y1, uint256 y2, uint256 y3)\n    {\n        a = 1;\n    }\n\n    function someModifiersSomeReturns()\n        modifier1\n        modifier2\n        modifier3\n        returns (uint256 y1, uint256 y2, uint256 y3)\n    {\n        a = 1;\n    }\n\n    function someParamSomeModifiersSomeReturns(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3\n    )\n        modifier1\n        modifier2\n        modifier3\n        returns (uint256 y1, uint256 y2, uint256 y3)\n    {\n        a = 1;\n    }\n\n    function someParamsManyModifiers(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3\n    )\n        modifier1\n        modifier2\n        modifier3\n        modifier4\n        modifier5\n        modifier6\n        modifier7\n        modifier8\n        modifier9\n        modifier10\n    {\n        a = 1;\n    }\n\n    function someParamsManyReturns(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3\n    )\n        returns (\n            uint256 y1,\n            uint256 y2,\n            uint256 y3,\n            uint256 y4,\n            uint256 y5,\n            uint256 y6,\n            uint256 y7,\n            uint256 y8,\n            uint256 y9,\n            uint256 y10\n        )\n    {\n        a = 1;\n    }\n\n    function manyParamsSomeModifiers(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3,\n        uint256 x4,\n        uint256 x5,\n        uint256 x6,\n        uint256 x7,\n        uint256 x8,\n        uint256 x9,\n        uint256 x10\n    )\n        modifier1\n        modifier2\n        modifier3\n    {\n        a = 1;\n    }\n\n    function manyParamsSomeReturns(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3,\n        uint256 x4,\n        uint256 x5,\n        uint256 x6,\n        uint256 x7,\n        uint256 x8,\n        uint256 x9,\n        uint256 x10\n    )\n        returns (uint256 y1, uint256 y2, uint256 y3)\n    {\n        a = 1;\n    }\n\n    function manyParamsManyModifiers(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3,\n        uint256 x4,\n        uint256 x5,\n        uint256 x6,\n        uint256 x7,\n        uint256 x8,\n        uint256 x9,\n        uint256 x10\n    )\n        public\n        modifier1\n        modifier2\n        modifier3\n        modifier4\n        modifier5\n        modifier6\n        modifier7\n        modifier8\n        modifier9\n        modifier10\n    {\n        a = 1;\n    }\n\n    function manyParamsManyReturns(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3,\n        uint256 x4,\n        uint256 x5,\n        uint256 x6,\n        uint256 x7,\n        uint256 x8,\n        uint256 x9,\n        uint256 x10\n    )\n        returns (\n            uint256 y1,\n            uint256 y2,\n            uint256 y3,\n            uint256 y4,\n            uint256 y5,\n            uint256 y6,\n            uint256 y7,\n            uint256 y8,\n            uint256 y9,\n            uint256 y10\n        )\n    {\n        a = 1;\n    }\n\n    function manyParamsManyModifiersManyReturns(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3,\n        uint256 x4,\n        uint256 x5,\n        uint256 x6,\n        uint256 x7,\n        uint256 x8,\n        uint256 x9,\n        uint256 x10\n    )\n        modifier1\n        modifier2\n        modifier3\n        modifier4\n        modifier5\n        modifier6\n        modifier7\n        modifier8\n        modifier9\n        modifier10\n        returns (\n            uint256 y1,\n            uint256 y2,\n            uint256 y3,\n            uint256 y4,\n            uint256 y5,\n            uint256 y6,\n            uint256 y7,\n            uint256 y8,\n            uint256 y9,\n            uint256 y10\n        )\n    {\n        a = 1;\n    }\n\n    function modifierOrderCorrect01()\n        public\n        view\n        virtual\n        override\n        modifier1\n        modifier2\n        returns (uint256)\n    {\n        a = 1;\n    }\n\n    function modifierOrderCorrect02()\n        private\n        pure\n        virtual\n        modifier1\n        modifier2\n        returns (string)\n    {\n        a = 1;\n    }\n\n    function modifierOrderCorrect03()\n        external\n        payable\n        override\n        modifier1\n        modifier2\n        returns (address)\n    {\n        a = 1;\n    }\n\n    function modifierOrderCorrect04()\n        internal\n        virtual\n        override\n        modifier1\n        modifier2\n        returns (uint256)\n    {\n        a = 1;\n    }\n\n    function modifierOrderIncorrect01()\n        public\n        view\n        virtual\n        override\n        modifier1\n        modifier2\n        returns (uint256)\n    {\n        a = 1;\n    }\n\n    function modifierOrderIncorrect02()\n        external\n        virtual\n        override\n        modifier1\n        modifier2\n        returns (uint256)\n    {\n        a = 1;\n    }\n\n    function modifierOrderIncorrect03()\n        internal\n        pure\n        virtual\n        modifier1\n        modifier2\n        returns (uint256)\n    {\n        a = 1;\n    }\n\n    function modifierOrderIncorrect04()\n        external\n        payable\n        override\n        modifier1\n        modifier2\n        returns (uint256)\n    {\n        a = 1;\n    }\n\n    fallback() external payable virtual {}\n    receive() external payable virtual {}\n}\n\ncontract FunctionOverrides is\n    FunctionInterfaces,\n    FunctionDefinitions\n{\n    function noParamsNoModifiersNoReturns() override {\n        a = 1;\n    }\n\n    function oneParam(uint256 x)\n        override(\n            FunctionInterfaces,\n            FunctionDefinitions,\n            SomeOtherFunctionContract,\n            SomeImport.AndAnotherFunctionContract\n        )\n    {\n        a = 1;\n    }\n\n    function simple(\n        address _target,\n        bytes memory _payload\n    )\n        internal\n    {\n        a = 1;\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/FunctionDefinition/fmt.sol",
    "content": "// config: line_length = 60\ninterface FunctionInterfaces {\n    function noParamsNoModifiersNoReturns();\n\n    function oneParam(uint256 x);\n\n    function oneModifier() modifier1;\n\n    function oneReturn() returns (uint256 y1);\n\n    // function prefix\n    function withComments( // function name postfix\n        // x1 prefix\n        uint256 x1, // x1 postfix\n        // x2 prefix\n        uint256 x2, // x2 postfix\n        // x2 postfix2\n        /*\n            multi-line x3 prefix\n        */\n        uint256 x3 // x3 postfix\n    )\n        // public prefix\n        public // public postfix\n        // pure prefix\n        pure // pure postfix\n        // modifier1 prefix\n        modifier1 // modifier1 postfix\n        // modifier2 prefix\n        modifier2 /*\n                    mutliline modifier2 postfix\n                    */\n        // modifier3 prefix\n        modifier3 // modifier3 postfix\n        returns (\n            // y1 prefix\n            uint256 y1, // y1 postfix\n            // y2 prefix\n            uint256 y2, // y2 postfix\n            // y3 prefix\n            uint256 y3 // y3 postfix\n        ); // function postfix\n\n    /*//////////////////////////////////////////////////////////////////////////\n                                    TEST\n    //////////////////////////////////////////////////////////////////////////*/\n    function manyParams(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3,\n        uint256 x4,\n        uint256 x5,\n        uint256 x6,\n        uint256 x7,\n        uint256 x8,\n        uint256 x9,\n        uint256 x10\n    );\n\n    function manyModifiers()\n        modifier1\n        modifier2\n        modifier3\n        modifier4\n        modifier5\n        modifier6\n        modifier7\n        modifier8\n        modifier9\n        modifier10;\n\n    function manyReturns()\n        returns (\n            uint256 y1,\n            uint256 y2,\n            uint256 y3,\n            uint256 y4,\n            uint256 y5,\n            uint256 y6,\n            uint256 y7,\n            uint256 y8,\n            uint256 y9,\n            uint256 y10\n        );\n\n    function someParamsSomeModifiers(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3\n    ) modifier1 modifier2 modifier3;\n\n    function someParamsSomeReturns(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3\n    ) returns (uint256 y1, uint256 y2, uint256 y3);\n\n    function someModifiersSomeReturns()\n        modifier1\n        modifier2\n        modifier3\n        returns (uint256 y1, uint256 y2, uint256 y3);\n\n    function someParamSomeModifiersSomeReturns(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3\n    )\n        modifier1\n        modifier2\n        modifier3\n        returns (uint256 y1, uint256 y2, uint256 y3);\n\n    function someParamsManyModifiers(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3\n    )\n        modifier1\n        modifier2\n        modifier3\n        modifier4\n        modifier5\n        modifier6\n        modifier7\n        modifier8\n        modifier9\n        modifier10;\n\n    function someParamsManyReturns(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3\n    )\n        returns (\n            uint256 y1,\n            uint256 y2,\n            uint256 y3,\n            uint256 y4,\n            uint256 y5,\n            uint256 y6,\n            uint256 y7,\n            uint256 y8,\n            uint256 y9,\n            uint256 y10\n        );\n\n    function manyParamsSomeModifiers(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3,\n        uint256 x4,\n        uint256 x5,\n        uint256 x6,\n        uint256 x7,\n        uint256 x8,\n        uint256 x9,\n        uint256 x10\n    ) modifier1 modifier2 modifier3;\n\n    function manyParamsSomeReturns(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3,\n        uint256 x4,\n        uint256 x5,\n        uint256 x6,\n        uint256 x7,\n        uint256 x8,\n        uint256 x9,\n        uint256 x10\n    ) returns (uint256 y1, uint256 y2, uint256 y3);\n\n    function manyParamsManyModifiers(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3,\n        uint256 x4,\n        uint256 x5,\n        uint256 x6,\n        uint256 x7,\n        uint256 x8,\n        uint256 x9,\n        uint256 x10\n    )\n        modifier1\n        modifier2\n        modifier3\n        modifier4\n        modifier5\n        modifier6\n        modifier7\n        modifier8\n        modifier9\n        modifier10;\n\n    function manyParamsManyReturns(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3,\n        uint256 x4,\n        uint256 x5,\n        uint256 x6,\n        uint256 x7,\n        uint256 x8,\n        uint256 x9,\n        uint256 x10\n    )\n        returns (\n            uint256 y1,\n            uint256 y2,\n            uint256 y3,\n            uint256 y4,\n            uint256 y5,\n            uint256 y6,\n            uint256 y7,\n            uint256 y8,\n            uint256 y9,\n            uint256 y10\n        );\n\n    function manyParamsManyModifiersManyReturns(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3,\n        uint256 x4,\n        uint256 x5,\n        uint256 x6,\n        uint256 x7,\n        uint256 x8,\n        uint256 x9,\n        uint256 x10\n    )\n        modifier1\n        modifier2\n        modifier3\n        modifier4\n        modifier5\n        modifier6\n        modifier7\n        modifier8\n        modifier9\n        modifier10\n        returns (\n            uint256 y1,\n            uint256 y2,\n            uint256 y3,\n            uint256 y4,\n            uint256 y5,\n            uint256 y6,\n            uint256 y7,\n            uint256 y8,\n            uint256 y9,\n            uint256 y10\n        );\n\n    function modifierOrderCorrect01()\n        public\n        view\n        virtual\n        override\n        modifier1\n        modifier2\n        returns (uint256);\n\n    function modifierOrderCorrect02()\n        private\n        pure\n        virtual\n        modifier1\n        modifier2\n        returns (string);\n\n    function modifierOrderCorrect03()\n        external\n        payable\n        override\n        modifier1\n        modifier2\n        returns (address);\n\n    function modifierOrderCorrect04()\n        internal\n        virtual\n        override\n        modifier1\n        modifier2\n        returns (uint256);\n\n    function modifierOrderIncorrect01()\n        public\n        view\n        virtual\n        override\n        modifier1\n        modifier2\n        returns (uint256);\n\n    function modifierOrderIncorrect02()\n        external\n        virtual\n        override\n        modifier1\n        modifier2\n        returns (uint256);\n\n    function modifierOrderIncorrect03()\n        internal\n        pure\n        virtual\n        modifier1\n        modifier2\n        returns (uint256);\n\n    function modifierOrderIncorrect04()\n        external\n        payable\n        override\n        modifier1\n        modifier2\n        returns (uint256);\n}\n\ncontract FunctionDefinitions {\n    function f() external {}\n    fallback() external {}\n\n    function f() external payable {}\n    fallback() external payable {}\n    receive() external payable {}\n\n    function noParamsNoModifiersNoReturns() {\n        a = 1;\n    }\n\n    function oneParam(uint256 x) {\n        a = 1;\n    }\n\n    function oneModifier() modifier1 {\n        a = 1;\n    }\n\n    function oneReturn() returns (uint256 y1) {\n        a = 1;\n    }\n\n    function manyParams(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3,\n        uint256 x4,\n        uint256 x5,\n        uint256 x6,\n        uint256 x7,\n        uint256 x8,\n        uint256 x9,\n        uint256 x10\n    ) {\n        a = 1;\n    }\n\n    function manyModifiers()\n        modifier1\n        modifier2\n        modifier3\n        modifier4\n        modifier5\n        modifier6\n        modifier7\n        modifier8\n        modifier9\n        modifier10\n    {\n        a = 1;\n    }\n\n    function manyReturns()\n        returns (\n            uint256 y1,\n            uint256 y2,\n            uint256 y3,\n            uint256 y4,\n            uint256 y5,\n            uint256 y6,\n            uint256 y7,\n            uint256 y8,\n            uint256 y9,\n            uint256 y10\n        )\n    {\n        a = 1;\n    }\n\n    function someParamsSomeModifiers(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3\n    ) modifier1 modifier2 modifier3 {\n        a = 1;\n    }\n\n    function someParamsSomeReturns(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3\n    ) returns (uint256 y1, uint256 y2, uint256 y3) {\n        a = 1;\n    }\n\n    function someModifiersSomeReturns()\n        modifier1\n        modifier2\n        modifier3\n        returns (uint256 y1, uint256 y2, uint256 y3)\n    {\n        a = 1;\n    }\n\n    function someParamSomeModifiersSomeReturns(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3\n    )\n        modifier1\n        modifier2\n        modifier3\n        returns (uint256 y1, uint256 y2, uint256 y3)\n    {\n        a = 1;\n    }\n\n    function someParamsManyModifiers(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3\n    )\n        modifier1\n        modifier2\n        modifier3\n        modifier4\n        modifier5\n        modifier6\n        modifier7\n        modifier8\n        modifier9\n        modifier10\n    {\n        a = 1;\n    }\n\n    function someParamsManyReturns(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3\n    )\n        returns (\n            uint256 y1,\n            uint256 y2,\n            uint256 y3,\n            uint256 y4,\n            uint256 y5,\n            uint256 y6,\n            uint256 y7,\n            uint256 y8,\n            uint256 y9,\n            uint256 y10\n        )\n    {\n        a = 1;\n    }\n\n    function manyParamsSomeModifiers(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3,\n        uint256 x4,\n        uint256 x5,\n        uint256 x6,\n        uint256 x7,\n        uint256 x8,\n        uint256 x9,\n        uint256 x10\n    ) modifier1 modifier2 modifier3 {\n        a = 1;\n    }\n\n    function manyParamsSomeReturns(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3,\n        uint256 x4,\n        uint256 x5,\n        uint256 x6,\n        uint256 x7,\n        uint256 x8,\n        uint256 x9,\n        uint256 x10\n    ) returns (uint256 y1, uint256 y2, uint256 y3) {\n        a = 1;\n    }\n\n    function manyParamsManyModifiers(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3,\n        uint256 x4,\n        uint256 x5,\n        uint256 x6,\n        uint256 x7,\n        uint256 x8,\n        uint256 x9,\n        uint256 x10\n    )\n        public\n        modifier1\n        modifier2\n        modifier3\n        modifier4\n        modifier5\n        modifier6\n        modifier7\n        modifier8\n        modifier9\n        modifier10\n    {\n        a = 1;\n    }\n\n    function manyParamsManyReturns(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3,\n        uint256 x4,\n        uint256 x5,\n        uint256 x6,\n        uint256 x7,\n        uint256 x8,\n        uint256 x9,\n        uint256 x10\n    )\n        returns (\n            uint256 y1,\n            uint256 y2,\n            uint256 y3,\n            uint256 y4,\n            uint256 y5,\n            uint256 y6,\n            uint256 y7,\n            uint256 y8,\n            uint256 y9,\n            uint256 y10\n        )\n    {\n        a = 1;\n    }\n\n    function manyParamsManyModifiersManyReturns(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3,\n        uint256 x4,\n        uint256 x5,\n        uint256 x6,\n        uint256 x7,\n        uint256 x8,\n        uint256 x9,\n        uint256 x10\n    )\n        modifier1\n        modifier2\n        modifier3\n        modifier4\n        modifier5\n        modifier6\n        modifier7\n        modifier8\n        modifier9\n        modifier10\n        returns (\n            uint256 y1,\n            uint256 y2,\n            uint256 y3,\n            uint256 y4,\n            uint256 y5,\n            uint256 y6,\n            uint256 y7,\n            uint256 y8,\n            uint256 y9,\n            uint256 y10\n        )\n    {\n        a = 1;\n    }\n\n    function modifierOrderCorrect01()\n        public\n        view\n        virtual\n        override\n        modifier1\n        modifier2\n        returns (uint256)\n    {\n        a = 1;\n    }\n\n    function modifierOrderCorrect02()\n        private\n        pure\n        virtual\n        modifier1\n        modifier2\n        returns (string)\n    {\n        a = 1;\n    }\n\n    function modifierOrderCorrect03()\n        external\n        payable\n        override\n        modifier1\n        modifier2\n        returns (address)\n    {\n        a = 1;\n    }\n\n    function modifierOrderCorrect04()\n        internal\n        virtual\n        override\n        modifier1\n        modifier2\n        returns (uint256)\n    {\n        a = 1;\n    }\n\n    function modifierOrderIncorrect01()\n        public\n        view\n        virtual\n        override\n        modifier1\n        modifier2\n        returns (uint256)\n    {\n        a = 1;\n    }\n\n    function modifierOrderIncorrect02()\n        external\n        virtual\n        override\n        modifier1\n        modifier2\n        returns (uint256)\n    {\n        a = 1;\n    }\n\n    function modifierOrderIncorrect03()\n        internal\n        pure\n        virtual\n        modifier1\n        modifier2\n        returns (uint256)\n    {\n        a = 1;\n    }\n\n    function modifierOrderIncorrect04()\n        external\n        payable\n        override\n        modifier1\n        modifier2\n        returns (uint256)\n    {\n        a = 1;\n    }\n\n    fallback() external payable virtual {}\n    receive() external payable virtual {}\n}\n\ncontract FunctionOverrides is\n    FunctionInterfaces,\n    FunctionDefinitions\n{\n    function noParamsNoModifiersNoReturns() override {\n        a = 1;\n    }\n\n    function oneParam(uint256 x)\n        override(\n            FunctionInterfaces,\n            FunctionDefinitions,\n            SomeOtherFunctionContract,\n            SomeImport.AndAnotherFunctionContract\n        )\n    {\n        a = 1;\n    }\n\n    function simple(address _target, bytes memory _payload)\n        internal\n    {\n        a = 1;\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/FunctionDefinition/original.sol",
    "content": "interface FunctionInterfaces {\n    function noParamsNoModifiersNoReturns();\n\n    function oneParam(uint x);\n\n    function oneModifier() modifier1;\n\n    function oneReturn() returns(uint y1);\n\n    // function prefix\n    function withComments( // function name postfix\n    // x1 prefix\n    uint256 x1, // x1 postfix\n\n        // x2 prefix\n            uint256 x2, // x2 postfix\n                // x2 postfix2\n        /*\n            multi-line x3 prefix\n        */\n        uint256 x3 // x3 postfix\n\n    )\n            // pure prefix\n                pure // pure postfix\n        // modifier1 prefix\n        modifier1 // modifier1 postfix\n    // public prefix\n    public // public postfix\n        // modifier2 prefix\n        modifier2 /*\n                    mutliline modifier2 postfix\n                    */\n            // modifier3 prefix\n            modifier3 // modifier3 postfix\n        returns (\n            // y1 prefix\n            uint256 y1, // y1 postfix\n            // y2 prefix\n            uint256 y2, // y2 postfix\n            // y3 prefix\n            uint256 y3 // y3 postfix\n        ); // function postfix\n\n    /*//////////////////////////////////////////////////////////////////////////\n                                    TEST\n    //////////////////////////////////////////////////////////////////////////*/\n    function manyParams(uint x1, uint x2, uint x3, uint x4, uint x5, uint x6, uint x7, uint x8, uint x9, uint x10);\n\n    function manyModifiers() modifier1() modifier2() modifier3 modifier4 modifier5 modifier6 modifier7 modifier8 modifier9 modifier10;\n\n    function manyReturns() returns(uint y1, uint y2, uint y3, uint y4, uint y5, uint y6, uint y7, uint y8, uint y9, uint y10);\n\n    function someParamsSomeModifiers(uint x1, uint x2, uint x3) modifier1() modifier2 modifier3;\n\n    function someParamsSomeReturns(uint x1, uint x2, uint x3) returns(uint y1, uint y2, uint y3);\n\n    function someModifiersSomeReturns() modifier1 modifier2 modifier3 returns(uint y1, uint y2, uint y3);\n\n    function someParamSomeModifiersSomeReturns(uint x1, uint x2, uint x3) modifier1 modifier2 modifier3 returns(uint y1, uint y2, uint y3);\n\n    function someParamsManyModifiers(uint x1, uint x2, uint x3) modifier1 modifier2 modifier3 modifier4 modifier5 modifier6 modifier7 modifier8 modifier9 modifier10;\n\n    function someParamsManyReturns(uint x1, uint x2, uint x3) returns(uint y1, uint y2, uint y3, uint y4, uint y5, uint y6, uint y7, uint y8, uint y9, uint y10);\n\n    function manyParamsSomeModifiers(uint x1, uint x2, uint x3, uint x4, uint x5, uint x6, uint x7, uint x8, uint x9, uint x10) modifier1 modifier2 modifier3;\n\n    function manyParamsSomeReturns(uint x1, uint x2, uint x3, uint x4, uint x5, uint x6, uint x7, uint x8, uint x9, uint x10) returns(uint y1, uint y2, uint y3);\n\n    function manyParamsManyModifiers(uint x1, uint x2, uint x3, uint x4, uint x5, uint x6, uint x7, uint x8, uint x9, uint x10) modifier1 modifier2 modifier3 modifier4 modifier5 modifier6 modifier7 modifier8 modifier9 modifier10;\n\n    function manyParamsManyReturns(uint x1, uint x2, uint x3, uint x4, uint x5, uint x6, uint x7, uint x8, uint x9, uint x10) returns(uint y1, uint y2, uint y3, uint y4, uint y5, uint y6, uint y7, uint y8, uint y9, uint y10);\n\n    function manyParamsManyModifiersManyReturns(uint x1, uint x2, uint x3, uint x4, uint x5, uint x6, uint x7, uint x8, uint x9, uint x10) modifier1 modifier2 modifier3 modifier4 modifier5 modifier6 modifier7 modifier8 modifier9 modifier10 returns(uint y1, uint y2, uint y3, uint y4, uint y5, uint y6, uint y7, uint y8, uint y9, uint y10);\n\n    function modifierOrderCorrect01() public view virtual override modifier1 modifier2 returns(uint);\n\n    function modifierOrderCorrect02() private pure virtual modifier1 modifier2 returns(string);\n\n    function modifierOrderCorrect03() external payable override modifier1 modifier2 returns(address);\n\n    function modifierOrderCorrect04() internal virtual override modifier1 modifier2 returns(uint);\n\n    function modifierOrderIncorrect01() public modifier1 modifier2 override virtual view returns(uint);\n\n    function modifierOrderIncorrect02() virtual modifier1 external modifier2 override returns(uint);\n\n    function modifierOrderIncorrect03() modifier1 pure internal virtual modifier2 returns(uint);\n\n    function modifierOrderIncorrect04() override modifier1 payable external modifier2 returns(uint);\n}\n\ncontract FunctionDefinitions {\n    function f() external {}\n    fallback () external {}\n\n    function f() external payable {}\n    fallback () external payable {}\n    receive () external payable {}\n\n    function noParamsNoModifiersNoReturns() {\n        a = 1;\n    }\n\n    function oneParam(uint x) {\n        a = 1;\n    }\n\n    function oneModifier() modifier1 {\n        a = 1;\n    }\n\n    function oneReturn() returns(uint y1) {\n        a = 1;\n    }\n\n    function manyParams(uint x1, uint x2, uint x3, uint x4, uint x5, uint x6, uint x7, uint x8, uint x9, uint x10) {\n        a = 1;\n    }\n\n    function manyModifiers() modifier1 modifier2 modifier3 modifier4 modifier5 modifier6 modifier7 modifier8 modifier9 modifier10 {\n        a = 1;\n    }\n\n    function manyReturns() returns(uint y1, uint y2, uint y3, uint y4, uint y5, uint y6, uint y7, uint y8, uint y9, uint y10) {\n        a = 1;\n    }\n\n    function someParamsSomeModifiers(uint x1, uint x2, uint x3) modifier1 modifier2 modifier3 {\n        a = 1;\n    }\n\n    function someParamsSomeReturns(uint x1, uint x2, uint x3) returns(uint y1, uint y2, uint y3) {\n        a = 1;\n    }\n\n    function someModifiersSomeReturns() modifier1 modifier2 modifier3 returns(uint y1, uint y2, uint y3) {\n        a = 1;\n    }\n\n    function someParamSomeModifiersSomeReturns(uint x1, uint x2, uint x3) modifier1 modifier2 modifier3 returns(uint y1, uint y2, uint y3) {\n        a = 1;\n    }\n\n    function someParamsManyModifiers(uint x1, uint x2, uint x3) modifier1 modifier2 modifier3 modifier4 modifier5 modifier6 modifier7 modifier8 modifier9 modifier10 {\n        a = 1;\n    }\n\n    function someParamsManyReturns(uint x1, uint x2, uint x3) returns(uint y1, uint y2, uint y3, uint y4, uint y5, uint y6, uint y7, uint y8, uint y9, uint y10) {\n        a = 1;\n    }\n\n    function manyParamsSomeModifiers(uint x1, uint x2, uint x3, uint x4, uint x5, uint x6, uint x7, uint x8, uint x9, uint x10) modifier1 modifier2 modifier3 {\n        a = 1;\n    }\n\n    function manyParamsSomeReturns(uint x1, uint x2, uint x3, uint x4, uint x5, uint x6, uint x7, uint x8, uint x9, uint x10) returns(uint y1, uint y2, uint y3) {\n        a = 1;\n    }\n\n    function manyParamsManyModifiers(uint x1, uint x2, uint x3, uint x4, uint x5, uint x6, uint x7, uint x8, uint x9, uint x10) modifier1 modifier2 modifier3 modifier4 modifier5 modifier6 modifier7 modifier8 modifier9 modifier10 public {\n        a = 1;\n    }\n\n    function manyParamsManyReturns(uint x1, uint x2, uint x3, uint x4, uint x5, uint x6, uint x7, uint x8, uint x9, uint x10) returns(uint y1, uint y2, uint y3, uint y4, uint y5, uint y6, uint y7, uint y8, uint y9, uint y10) {\n        a = 1;\n    }\n\n    function manyParamsManyModifiersManyReturns(uint x1, uint x2, uint x3, uint x4, uint x5, uint x6, uint x7, uint x8, uint x9, uint x10) modifier1 modifier2 modifier3 modifier4 modifier5 modifier6 modifier7 modifier8 modifier9 modifier10 returns(uint y1, uint y2, uint y3, uint y4, uint y5, uint y6, uint y7, uint y8, uint y9, uint y10) {\n        a = 1;\n    }\n\n    function modifierOrderCorrect01() public view virtual override modifier1 modifier2 returns(uint) {\n        a = 1;\n    }\n\n    function modifierOrderCorrect02() private pure virtual modifier1 modifier2 returns(string) {\n        a = 1;\n    }\n\n    function modifierOrderCorrect03() external payable override modifier1 modifier2 returns(address) {\n        a = 1;\n    }\n\n    function modifierOrderCorrect04() internal virtual override modifier1 modifier2 returns(uint) {\n        a = 1;\n    }\n\n    function modifierOrderIncorrect01() public modifier1 modifier2 override virtual view returns(uint) {\n        a = 1;\n    }\n\n    function modifierOrderIncorrect02() virtual modifier1 external modifier2 override returns(uint) {\n        a = 1;\n    }\n\n    function modifierOrderIncorrect03() modifier1 pure internal virtual modifier2 returns(uint) {\n        a = 1;\n    }\n\n    function modifierOrderIncorrect04() override modifier1 payable external modifier2 returns(uint) {\n        a = 1;\n    }\n\n    fallback() external payable virtual {}\n    receive() external payable virtual {}\n}\n\ncontract FunctionOverrides is FunctionInterfaces, FunctionDefinitions {\n    function noParamsNoModifiersNoReturns() override {\n        a = 1;\n    }\n\n    function oneParam(uint256 x) override(FunctionInterfaces, FunctionDefinitions, SomeOtherFunctionContract, SomeImport.AndAnotherFunctionContract) {\n        a = 1;\n    }\n\n    function simple(address _target, bytes memory _payload)\n        internal\n    {\n        a = 1;\n    }\n\n}\n"
  },
  {
    "path": "crates/fmt/testdata/FunctionDefinition/override-spacing.fmt.sol",
    "content": "// config: line_length = 60\n// config: override_spacing = true\ninterface FunctionInterfaces {\n    function noParamsNoModifiersNoReturns();\n\n    function oneParam(uint256 x);\n\n    function oneModifier() modifier1;\n\n    function oneReturn() returns (uint256 y1);\n\n    // function prefix\n    function withComments( // function name postfix\n        // x1 prefix\n        uint256 x1, // x1 postfix\n        // x2 prefix\n        uint256 x2, // x2 postfix\n        // x2 postfix2\n        /*\n            multi-line x3 prefix\n        */\n        uint256 x3 // x3 postfix\n    )\n        // public prefix\n        public // public postfix\n        // pure prefix\n        pure // pure postfix\n        // modifier1 prefix\n        modifier1 // modifier1 postfix\n        // modifier2 prefix\n        modifier2 /*\n                    mutliline modifier2 postfix\n                    */\n        // modifier3 prefix\n        modifier3 // modifier3 postfix\n        returns (\n            // y1 prefix\n            uint256 y1, // y1 postfix\n            // y2 prefix\n            uint256 y2, // y2 postfix\n            // y3 prefix\n            uint256 y3 // y3 postfix\n        ); // function postfix\n\n    /*//////////////////////////////////////////////////////////////////////////\n                                    TEST\n    //////////////////////////////////////////////////////////////////////////*/\n    function manyParams(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3,\n        uint256 x4,\n        uint256 x5,\n        uint256 x6,\n        uint256 x7,\n        uint256 x8,\n        uint256 x9,\n        uint256 x10\n    );\n\n    function manyModifiers()\n        modifier1\n        modifier2\n        modifier3\n        modifier4\n        modifier5\n        modifier6\n        modifier7\n        modifier8\n        modifier9\n        modifier10;\n\n    function manyReturns()\n        returns (\n            uint256 y1,\n            uint256 y2,\n            uint256 y3,\n            uint256 y4,\n            uint256 y5,\n            uint256 y6,\n            uint256 y7,\n            uint256 y8,\n            uint256 y9,\n            uint256 y10\n        );\n\n    function someParamsSomeModifiers(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3\n    ) modifier1 modifier2 modifier3;\n\n    function someParamsSomeReturns(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3\n    ) returns (uint256 y1, uint256 y2, uint256 y3);\n\n    function someModifiersSomeReturns()\n        modifier1\n        modifier2\n        modifier3\n        returns (uint256 y1, uint256 y2, uint256 y3);\n\n    function someParamSomeModifiersSomeReturns(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3\n    )\n        modifier1\n        modifier2\n        modifier3\n        returns (uint256 y1, uint256 y2, uint256 y3);\n\n    function someParamsManyModifiers(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3\n    )\n        modifier1\n        modifier2\n        modifier3\n        modifier4\n        modifier5\n        modifier6\n        modifier7\n        modifier8\n        modifier9\n        modifier10;\n\n    function someParamsManyReturns(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3\n    )\n        returns (\n            uint256 y1,\n            uint256 y2,\n            uint256 y3,\n            uint256 y4,\n            uint256 y5,\n            uint256 y6,\n            uint256 y7,\n            uint256 y8,\n            uint256 y9,\n            uint256 y10\n        );\n\n    function manyParamsSomeModifiers(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3,\n        uint256 x4,\n        uint256 x5,\n        uint256 x6,\n        uint256 x7,\n        uint256 x8,\n        uint256 x9,\n        uint256 x10\n    ) modifier1 modifier2 modifier3;\n\n    function manyParamsSomeReturns(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3,\n        uint256 x4,\n        uint256 x5,\n        uint256 x6,\n        uint256 x7,\n        uint256 x8,\n        uint256 x9,\n        uint256 x10\n    ) returns (uint256 y1, uint256 y2, uint256 y3);\n\n    function manyParamsManyModifiers(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3,\n        uint256 x4,\n        uint256 x5,\n        uint256 x6,\n        uint256 x7,\n        uint256 x8,\n        uint256 x9,\n        uint256 x10\n    )\n        modifier1\n        modifier2\n        modifier3\n        modifier4\n        modifier5\n        modifier6\n        modifier7\n        modifier8\n        modifier9\n        modifier10;\n\n    function manyParamsManyReturns(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3,\n        uint256 x4,\n        uint256 x5,\n        uint256 x6,\n        uint256 x7,\n        uint256 x8,\n        uint256 x9,\n        uint256 x10\n    )\n        returns (\n            uint256 y1,\n            uint256 y2,\n            uint256 y3,\n            uint256 y4,\n            uint256 y5,\n            uint256 y6,\n            uint256 y7,\n            uint256 y8,\n            uint256 y9,\n            uint256 y10\n        );\n\n    function manyParamsManyModifiersManyReturns(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3,\n        uint256 x4,\n        uint256 x5,\n        uint256 x6,\n        uint256 x7,\n        uint256 x8,\n        uint256 x9,\n        uint256 x10\n    )\n        modifier1\n        modifier2\n        modifier3\n        modifier4\n        modifier5\n        modifier6\n        modifier7\n        modifier8\n        modifier9\n        modifier10\n        returns (\n            uint256 y1,\n            uint256 y2,\n            uint256 y3,\n            uint256 y4,\n            uint256 y5,\n            uint256 y6,\n            uint256 y7,\n            uint256 y8,\n            uint256 y9,\n            uint256 y10\n        );\n\n    function modifierOrderCorrect01()\n        public\n        view\n        virtual\n        override\n        modifier1\n        modifier2\n        returns (uint256);\n\n    function modifierOrderCorrect02()\n        private\n        pure\n        virtual\n        modifier1\n        modifier2\n        returns (string);\n\n    function modifierOrderCorrect03()\n        external\n        payable\n        override\n        modifier1\n        modifier2\n        returns (address);\n\n    function modifierOrderCorrect04()\n        internal\n        virtual\n        override\n        modifier1\n        modifier2\n        returns (uint256);\n\n    function modifierOrderIncorrect01()\n        public\n        view\n        virtual\n        override\n        modifier1\n        modifier2\n        returns (uint256);\n\n    function modifierOrderIncorrect02()\n        external\n        virtual\n        override\n        modifier1\n        modifier2\n        returns (uint256);\n\n    function modifierOrderIncorrect03()\n        internal\n        pure\n        virtual\n        modifier1\n        modifier2\n        returns (uint256);\n\n    function modifierOrderIncorrect04()\n        external\n        payable\n        override\n        modifier1\n        modifier2\n        returns (uint256);\n}\n\ncontract FunctionDefinitions {\n    function f() external {}\n    fallback() external {}\n\n    function f() external payable {}\n    fallback() external payable {}\n    receive() external payable {}\n\n    function noParamsNoModifiersNoReturns() {\n        a = 1;\n    }\n\n    function oneParam(uint256 x) {\n        a = 1;\n    }\n\n    function oneModifier() modifier1 {\n        a = 1;\n    }\n\n    function oneReturn() returns (uint256 y1) {\n        a = 1;\n    }\n\n    function manyParams(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3,\n        uint256 x4,\n        uint256 x5,\n        uint256 x6,\n        uint256 x7,\n        uint256 x8,\n        uint256 x9,\n        uint256 x10\n    ) {\n        a = 1;\n    }\n\n    function manyModifiers()\n        modifier1\n        modifier2\n        modifier3\n        modifier4\n        modifier5\n        modifier6\n        modifier7\n        modifier8\n        modifier9\n        modifier10\n    {\n        a = 1;\n    }\n\n    function manyReturns()\n        returns (\n            uint256 y1,\n            uint256 y2,\n            uint256 y3,\n            uint256 y4,\n            uint256 y5,\n            uint256 y6,\n            uint256 y7,\n            uint256 y8,\n            uint256 y9,\n            uint256 y10\n        )\n    {\n        a = 1;\n    }\n\n    function someParamsSomeModifiers(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3\n    ) modifier1 modifier2 modifier3 {\n        a = 1;\n    }\n\n    function someParamsSomeReturns(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3\n    ) returns (uint256 y1, uint256 y2, uint256 y3) {\n        a = 1;\n    }\n\n    function someModifiersSomeReturns()\n        modifier1\n        modifier2\n        modifier3\n        returns (uint256 y1, uint256 y2, uint256 y3)\n    {\n        a = 1;\n    }\n\n    function someParamSomeModifiersSomeReturns(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3\n    )\n        modifier1\n        modifier2\n        modifier3\n        returns (uint256 y1, uint256 y2, uint256 y3)\n    {\n        a = 1;\n    }\n\n    function someParamsManyModifiers(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3\n    )\n        modifier1\n        modifier2\n        modifier3\n        modifier4\n        modifier5\n        modifier6\n        modifier7\n        modifier8\n        modifier9\n        modifier10\n    {\n        a = 1;\n    }\n\n    function someParamsManyReturns(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3\n    )\n        returns (\n            uint256 y1,\n            uint256 y2,\n            uint256 y3,\n            uint256 y4,\n            uint256 y5,\n            uint256 y6,\n            uint256 y7,\n            uint256 y8,\n            uint256 y9,\n            uint256 y10\n        )\n    {\n        a = 1;\n    }\n\n    function manyParamsSomeModifiers(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3,\n        uint256 x4,\n        uint256 x5,\n        uint256 x6,\n        uint256 x7,\n        uint256 x8,\n        uint256 x9,\n        uint256 x10\n    ) modifier1 modifier2 modifier3 {\n        a = 1;\n    }\n\n    function manyParamsSomeReturns(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3,\n        uint256 x4,\n        uint256 x5,\n        uint256 x6,\n        uint256 x7,\n        uint256 x8,\n        uint256 x9,\n        uint256 x10\n    ) returns (uint256 y1, uint256 y2, uint256 y3) {\n        a = 1;\n    }\n\n    function manyParamsManyModifiers(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3,\n        uint256 x4,\n        uint256 x5,\n        uint256 x6,\n        uint256 x7,\n        uint256 x8,\n        uint256 x9,\n        uint256 x10\n    )\n        public\n        modifier1\n        modifier2\n        modifier3\n        modifier4\n        modifier5\n        modifier6\n        modifier7\n        modifier8\n        modifier9\n        modifier10\n    {\n        a = 1;\n    }\n\n    function manyParamsManyReturns(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3,\n        uint256 x4,\n        uint256 x5,\n        uint256 x6,\n        uint256 x7,\n        uint256 x8,\n        uint256 x9,\n        uint256 x10\n    )\n        returns (\n            uint256 y1,\n            uint256 y2,\n            uint256 y3,\n            uint256 y4,\n            uint256 y5,\n            uint256 y6,\n            uint256 y7,\n            uint256 y8,\n            uint256 y9,\n            uint256 y10\n        )\n    {\n        a = 1;\n    }\n\n    function manyParamsManyModifiersManyReturns(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3,\n        uint256 x4,\n        uint256 x5,\n        uint256 x6,\n        uint256 x7,\n        uint256 x8,\n        uint256 x9,\n        uint256 x10\n    )\n        modifier1\n        modifier2\n        modifier3\n        modifier4\n        modifier5\n        modifier6\n        modifier7\n        modifier8\n        modifier9\n        modifier10\n        returns (\n            uint256 y1,\n            uint256 y2,\n            uint256 y3,\n            uint256 y4,\n            uint256 y5,\n            uint256 y6,\n            uint256 y7,\n            uint256 y8,\n            uint256 y9,\n            uint256 y10\n        )\n    {\n        a = 1;\n    }\n\n    function modifierOrderCorrect01()\n        public\n        view\n        virtual\n        override\n        modifier1\n        modifier2\n        returns (uint256)\n    {\n        a = 1;\n    }\n\n    function modifierOrderCorrect02()\n        private\n        pure\n        virtual\n        modifier1\n        modifier2\n        returns (string)\n    {\n        a = 1;\n    }\n\n    function modifierOrderCorrect03()\n        external\n        payable\n        override\n        modifier1\n        modifier2\n        returns (address)\n    {\n        a = 1;\n    }\n\n    function modifierOrderCorrect04()\n        internal\n        virtual\n        override\n        modifier1\n        modifier2\n        returns (uint256)\n    {\n        a = 1;\n    }\n\n    function modifierOrderIncorrect01()\n        public\n        view\n        virtual\n        override\n        modifier1\n        modifier2\n        returns (uint256)\n    {\n        a = 1;\n    }\n\n    function modifierOrderIncorrect02()\n        external\n        virtual\n        override\n        modifier1\n        modifier2\n        returns (uint256)\n    {\n        a = 1;\n    }\n\n    function modifierOrderIncorrect03()\n        internal\n        pure\n        virtual\n        modifier1\n        modifier2\n        returns (uint256)\n    {\n        a = 1;\n    }\n\n    function modifierOrderIncorrect04()\n        external\n        payable\n        override\n        modifier1\n        modifier2\n        returns (uint256)\n    {\n        a = 1;\n    }\n\n    fallback() external payable virtual {}\n    receive() external payable virtual {}\n}\n\ncontract FunctionOverrides is\n    FunctionInterfaces,\n    FunctionDefinitions\n{\n    function noParamsNoModifiersNoReturns() override {\n        a = 1;\n    }\n\n    function oneParam(uint256 x)\n        override (\n            FunctionInterfaces,\n            FunctionDefinitions,\n            SomeOtherFunctionContract,\n            SomeImport.AndAnotherFunctionContract\n        )\n    {\n        a = 1;\n    }\n\n    function simple(address _target, bytes memory _payload)\n        internal\n    {\n        a = 1;\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/FunctionDefinition/params-always.fmt.sol",
    "content": "// config: line_length = 60\n// config: multiline_func_header = \"params_always\"\ninterface FunctionInterfaces {\n    function noParamsNoModifiersNoReturns();\n\n    function oneParam(\n        uint256 x\n    );\n\n    function oneModifier() modifier1;\n\n    function oneReturn() returns (uint256 y1);\n\n    // function prefix\n    function withComments( // function name postfix\n        // x1 prefix\n        uint256 x1, // x1 postfix\n        // x2 prefix\n        uint256 x2, // x2 postfix\n        // x2 postfix2\n        /*\n            multi-line x3 prefix\n        */\n        uint256 x3 // x3 postfix\n    )\n        // public prefix\n        public // public postfix\n        // pure prefix\n        pure // pure postfix\n        // modifier1 prefix\n        modifier1 // modifier1 postfix\n        // modifier2 prefix\n        modifier2 /*\n                    mutliline modifier2 postfix\n                    */\n        // modifier3 prefix\n        modifier3 // modifier3 postfix\n        returns (\n            // y1 prefix\n            uint256 y1, // y1 postfix\n            // y2 prefix\n            uint256 y2, // y2 postfix\n            // y3 prefix\n            uint256 y3 // y3 postfix\n        ); // function postfix\n\n    /*//////////////////////////////////////////////////////////////////////////\n                                    TEST\n    //////////////////////////////////////////////////////////////////////////*/\n    function manyParams(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3,\n        uint256 x4,\n        uint256 x5,\n        uint256 x6,\n        uint256 x7,\n        uint256 x8,\n        uint256 x9,\n        uint256 x10\n    );\n\n    function manyModifiers()\n        modifier1\n        modifier2\n        modifier3\n        modifier4\n        modifier5\n        modifier6\n        modifier7\n        modifier8\n        modifier9\n        modifier10;\n\n    function manyReturns()\n        returns (\n            uint256 y1,\n            uint256 y2,\n            uint256 y3,\n            uint256 y4,\n            uint256 y5,\n            uint256 y6,\n            uint256 y7,\n            uint256 y8,\n            uint256 y9,\n            uint256 y10\n        );\n\n    function someParamsSomeModifiers(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3\n    ) modifier1 modifier2 modifier3;\n\n    function someParamsSomeReturns(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3\n    ) returns (uint256 y1, uint256 y2, uint256 y3);\n\n    function someModifiersSomeReturns()\n        modifier1\n        modifier2\n        modifier3\n        returns (uint256 y1, uint256 y2, uint256 y3);\n\n    function someParamSomeModifiersSomeReturns(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3\n    )\n        modifier1\n        modifier2\n        modifier3\n        returns (uint256 y1, uint256 y2, uint256 y3);\n\n    function someParamsManyModifiers(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3\n    )\n        modifier1\n        modifier2\n        modifier3\n        modifier4\n        modifier5\n        modifier6\n        modifier7\n        modifier8\n        modifier9\n        modifier10;\n\n    function someParamsManyReturns(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3\n    )\n        returns (\n            uint256 y1,\n            uint256 y2,\n            uint256 y3,\n            uint256 y4,\n            uint256 y5,\n            uint256 y6,\n            uint256 y7,\n            uint256 y8,\n            uint256 y9,\n            uint256 y10\n        );\n\n    function manyParamsSomeModifiers(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3,\n        uint256 x4,\n        uint256 x5,\n        uint256 x6,\n        uint256 x7,\n        uint256 x8,\n        uint256 x9,\n        uint256 x10\n    ) modifier1 modifier2 modifier3;\n\n    function manyParamsSomeReturns(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3,\n        uint256 x4,\n        uint256 x5,\n        uint256 x6,\n        uint256 x7,\n        uint256 x8,\n        uint256 x9,\n        uint256 x10\n    ) returns (uint256 y1, uint256 y2, uint256 y3);\n\n    function manyParamsManyModifiers(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3,\n        uint256 x4,\n        uint256 x5,\n        uint256 x6,\n        uint256 x7,\n        uint256 x8,\n        uint256 x9,\n        uint256 x10\n    )\n        modifier1\n        modifier2\n        modifier3\n        modifier4\n        modifier5\n        modifier6\n        modifier7\n        modifier8\n        modifier9\n        modifier10;\n\n    function manyParamsManyReturns(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3,\n        uint256 x4,\n        uint256 x5,\n        uint256 x6,\n        uint256 x7,\n        uint256 x8,\n        uint256 x9,\n        uint256 x10\n    )\n        returns (\n            uint256 y1,\n            uint256 y2,\n            uint256 y3,\n            uint256 y4,\n            uint256 y5,\n            uint256 y6,\n            uint256 y7,\n            uint256 y8,\n            uint256 y9,\n            uint256 y10\n        );\n\n    function manyParamsManyModifiersManyReturns(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3,\n        uint256 x4,\n        uint256 x5,\n        uint256 x6,\n        uint256 x7,\n        uint256 x8,\n        uint256 x9,\n        uint256 x10\n    )\n        modifier1\n        modifier2\n        modifier3\n        modifier4\n        modifier5\n        modifier6\n        modifier7\n        modifier8\n        modifier9\n        modifier10\n        returns (\n            uint256 y1,\n            uint256 y2,\n            uint256 y3,\n            uint256 y4,\n            uint256 y5,\n            uint256 y6,\n            uint256 y7,\n            uint256 y8,\n            uint256 y9,\n            uint256 y10\n        );\n\n    function modifierOrderCorrect01()\n        public\n        view\n        virtual\n        override\n        modifier1\n        modifier2\n        returns (uint256);\n\n    function modifierOrderCorrect02()\n        private\n        pure\n        virtual\n        modifier1\n        modifier2\n        returns (string);\n\n    function modifierOrderCorrect03()\n        external\n        payable\n        override\n        modifier1\n        modifier2\n        returns (address);\n\n    function modifierOrderCorrect04()\n        internal\n        virtual\n        override\n        modifier1\n        modifier2\n        returns (uint256);\n\n    function modifierOrderIncorrect01()\n        public\n        view\n        virtual\n        override\n        modifier1\n        modifier2\n        returns (uint256);\n\n    function modifierOrderIncorrect02()\n        external\n        virtual\n        override\n        modifier1\n        modifier2\n        returns (uint256);\n\n    function modifierOrderIncorrect03()\n        internal\n        pure\n        virtual\n        modifier1\n        modifier2\n        returns (uint256);\n\n    function modifierOrderIncorrect04()\n        external\n        payable\n        override\n        modifier1\n        modifier2\n        returns (uint256);\n}\n\ncontract FunctionDefinitions {\n    function f() external {}\n    fallback() external {}\n\n    function f() external payable {}\n    fallback() external payable {}\n    receive() external payable {}\n\n    function noParamsNoModifiersNoReturns() {\n        a = 1;\n    }\n\n    function oneParam(\n        uint256 x\n    ) {\n        a = 1;\n    }\n\n    function oneModifier() modifier1 {\n        a = 1;\n    }\n\n    function oneReturn() returns (uint256 y1) {\n        a = 1;\n    }\n\n    function manyParams(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3,\n        uint256 x4,\n        uint256 x5,\n        uint256 x6,\n        uint256 x7,\n        uint256 x8,\n        uint256 x9,\n        uint256 x10\n    ) {\n        a = 1;\n    }\n\n    function manyModifiers()\n        modifier1\n        modifier2\n        modifier3\n        modifier4\n        modifier5\n        modifier6\n        modifier7\n        modifier8\n        modifier9\n        modifier10\n    {\n        a = 1;\n    }\n\n    function manyReturns()\n        returns (\n            uint256 y1,\n            uint256 y2,\n            uint256 y3,\n            uint256 y4,\n            uint256 y5,\n            uint256 y6,\n            uint256 y7,\n            uint256 y8,\n            uint256 y9,\n            uint256 y10\n        )\n    {\n        a = 1;\n    }\n\n    function someParamsSomeModifiers(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3\n    ) modifier1 modifier2 modifier3 {\n        a = 1;\n    }\n\n    function someParamsSomeReturns(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3\n    ) returns (uint256 y1, uint256 y2, uint256 y3) {\n        a = 1;\n    }\n\n    function someModifiersSomeReturns()\n        modifier1\n        modifier2\n        modifier3\n        returns (uint256 y1, uint256 y2, uint256 y3)\n    {\n        a = 1;\n    }\n\n    function someParamSomeModifiersSomeReturns(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3\n    )\n        modifier1\n        modifier2\n        modifier3\n        returns (uint256 y1, uint256 y2, uint256 y3)\n    {\n        a = 1;\n    }\n\n    function someParamsManyModifiers(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3\n    )\n        modifier1\n        modifier2\n        modifier3\n        modifier4\n        modifier5\n        modifier6\n        modifier7\n        modifier8\n        modifier9\n        modifier10\n    {\n        a = 1;\n    }\n\n    function someParamsManyReturns(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3\n    )\n        returns (\n            uint256 y1,\n            uint256 y2,\n            uint256 y3,\n            uint256 y4,\n            uint256 y5,\n            uint256 y6,\n            uint256 y7,\n            uint256 y8,\n            uint256 y9,\n            uint256 y10\n        )\n    {\n        a = 1;\n    }\n\n    function manyParamsSomeModifiers(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3,\n        uint256 x4,\n        uint256 x5,\n        uint256 x6,\n        uint256 x7,\n        uint256 x8,\n        uint256 x9,\n        uint256 x10\n    ) modifier1 modifier2 modifier3 {\n        a = 1;\n    }\n\n    function manyParamsSomeReturns(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3,\n        uint256 x4,\n        uint256 x5,\n        uint256 x6,\n        uint256 x7,\n        uint256 x8,\n        uint256 x9,\n        uint256 x10\n    ) returns (uint256 y1, uint256 y2, uint256 y3) {\n        a = 1;\n    }\n\n    function manyParamsManyModifiers(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3,\n        uint256 x4,\n        uint256 x5,\n        uint256 x6,\n        uint256 x7,\n        uint256 x8,\n        uint256 x9,\n        uint256 x10\n    )\n        public\n        modifier1\n        modifier2\n        modifier3\n        modifier4\n        modifier5\n        modifier6\n        modifier7\n        modifier8\n        modifier9\n        modifier10\n    {\n        a = 1;\n    }\n\n    function manyParamsManyReturns(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3,\n        uint256 x4,\n        uint256 x5,\n        uint256 x6,\n        uint256 x7,\n        uint256 x8,\n        uint256 x9,\n        uint256 x10\n    )\n        returns (\n            uint256 y1,\n            uint256 y2,\n            uint256 y3,\n            uint256 y4,\n            uint256 y5,\n            uint256 y6,\n            uint256 y7,\n            uint256 y8,\n            uint256 y9,\n            uint256 y10\n        )\n    {\n        a = 1;\n    }\n\n    function manyParamsManyModifiersManyReturns(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3,\n        uint256 x4,\n        uint256 x5,\n        uint256 x6,\n        uint256 x7,\n        uint256 x8,\n        uint256 x9,\n        uint256 x10\n    )\n        modifier1\n        modifier2\n        modifier3\n        modifier4\n        modifier5\n        modifier6\n        modifier7\n        modifier8\n        modifier9\n        modifier10\n        returns (\n            uint256 y1,\n            uint256 y2,\n            uint256 y3,\n            uint256 y4,\n            uint256 y5,\n            uint256 y6,\n            uint256 y7,\n            uint256 y8,\n            uint256 y9,\n            uint256 y10\n        )\n    {\n        a = 1;\n    }\n\n    function modifierOrderCorrect01()\n        public\n        view\n        virtual\n        override\n        modifier1\n        modifier2\n        returns (uint256)\n    {\n        a = 1;\n    }\n\n    function modifierOrderCorrect02()\n        private\n        pure\n        virtual\n        modifier1\n        modifier2\n        returns (string)\n    {\n        a = 1;\n    }\n\n    function modifierOrderCorrect03()\n        external\n        payable\n        override\n        modifier1\n        modifier2\n        returns (address)\n    {\n        a = 1;\n    }\n\n    function modifierOrderCorrect04()\n        internal\n        virtual\n        override\n        modifier1\n        modifier2\n        returns (uint256)\n    {\n        a = 1;\n    }\n\n    function modifierOrderIncorrect01()\n        public\n        view\n        virtual\n        override\n        modifier1\n        modifier2\n        returns (uint256)\n    {\n        a = 1;\n    }\n\n    function modifierOrderIncorrect02()\n        external\n        virtual\n        override\n        modifier1\n        modifier2\n        returns (uint256)\n    {\n        a = 1;\n    }\n\n    function modifierOrderIncorrect03()\n        internal\n        pure\n        virtual\n        modifier1\n        modifier2\n        returns (uint256)\n    {\n        a = 1;\n    }\n\n    function modifierOrderIncorrect04()\n        external\n        payable\n        override\n        modifier1\n        modifier2\n        returns (uint256)\n    {\n        a = 1;\n    }\n\n    fallback() external payable virtual {}\n    receive() external payable virtual {}\n}\n\ncontract FunctionOverrides is\n    FunctionInterfaces,\n    FunctionDefinitions\n{\n    function noParamsNoModifiersNoReturns() override {\n        a = 1;\n    }\n\n    function oneParam(\n        uint256 x\n    )\n        override(\n            FunctionInterfaces,\n            FunctionDefinitions,\n            SomeOtherFunctionContract,\n            SomeImport.AndAnotherFunctionContract\n        )\n    {\n        a = 1;\n    }\n\n    function simple(\n        address _target,\n        bytes memory _payload\n    ) internal {\n        a = 1;\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/FunctionDefinition/params-multi.fmt.sol",
    "content": "// config: line_length = 60\n// config: multiline_func_header = \"params_first_multi\"\ninterface FunctionInterfaces {\n    function noParamsNoModifiersNoReturns();\n\n    function oneParam(uint256 x);\n\n    function oneModifier() modifier1;\n\n    function oneReturn() returns (uint256 y1);\n\n    // function prefix\n    function withComments( // function name postfix\n        // x1 prefix\n        uint256 x1, // x1 postfix\n        // x2 prefix\n        uint256 x2, // x2 postfix\n        // x2 postfix2\n        /*\n            multi-line x3 prefix\n        */\n        uint256 x3 // x3 postfix\n    )\n        // public prefix\n        public // public postfix\n        // pure prefix\n        pure // pure postfix\n        // modifier1 prefix\n        modifier1 // modifier1 postfix\n        // modifier2 prefix\n        modifier2 /*\n                    mutliline modifier2 postfix\n                    */\n        // modifier3 prefix\n        modifier3 // modifier3 postfix\n        returns (\n            // y1 prefix\n            uint256 y1, // y1 postfix\n            // y2 prefix\n            uint256 y2, // y2 postfix\n            // y3 prefix\n            uint256 y3 // y3 postfix\n        ); // function postfix\n\n    /*//////////////////////////////////////////////////////////////////////////\n                                    TEST\n    //////////////////////////////////////////////////////////////////////////*/\n    function manyParams(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3,\n        uint256 x4,\n        uint256 x5,\n        uint256 x6,\n        uint256 x7,\n        uint256 x8,\n        uint256 x9,\n        uint256 x10\n    );\n\n    function manyModifiers()\n        modifier1\n        modifier2\n        modifier3\n        modifier4\n        modifier5\n        modifier6\n        modifier7\n        modifier8\n        modifier9\n        modifier10;\n\n    function manyReturns()\n        returns (\n            uint256 y1,\n            uint256 y2,\n            uint256 y3,\n            uint256 y4,\n            uint256 y5,\n            uint256 y6,\n            uint256 y7,\n            uint256 y8,\n            uint256 y9,\n            uint256 y10\n        );\n\n    function someParamsSomeModifiers(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3\n    ) modifier1 modifier2 modifier3;\n\n    function someParamsSomeReturns(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3\n    ) returns (uint256 y1, uint256 y2, uint256 y3);\n\n    function someModifiersSomeReturns()\n        modifier1\n        modifier2\n        modifier3\n        returns (uint256 y1, uint256 y2, uint256 y3);\n\n    function someParamSomeModifiersSomeReturns(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3\n    )\n        modifier1\n        modifier2\n        modifier3\n        returns (uint256 y1, uint256 y2, uint256 y3);\n\n    function someParamsManyModifiers(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3\n    )\n        modifier1\n        modifier2\n        modifier3\n        modifier4\n        modifier5\n        modifier6\n        modifier7\n        modifier8\n        modifier9\n        modifier10;\n\n    function someParamsManyReturns(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3\n    )\n        returns (\n            uint256 y1,\n            uint256 y2,\n            uint256 y3,\n            uint256 y4,\n            uint256 y5,\n            uint256 y6,\n            uint256 y7,\n            uint256 y8,\n            uint256 y9,\n            uint256 y10\n        );\n\n    function manyParamsSomeModifiers(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3,\n        uint256 x4,\n        uint256 x5,\n        uint256 x6,\n        uint256 x7,\n        uint256 x8,\n        uint256 x9,\n        uint256 x10\n    ) modifier1 modifier2 modifier3;\n\n    function manyParamsSomeReturns(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3,\n        uint256 x4,\n        uint256 x5,\n        uint256 x6,\n        uint256 x7,\n        uint256 x8,\n        uint256 x9,\n        uint256 x10\n    ) returns (uint256 y1, uint256 y2, uint256 y3);\n\n    function manyParamsManyModifiers(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3,\n        uint256 x4,\n        uint256 x5,\n        uint256 x6,\n        uint256 x7,\n        uint256 x8,\n        uint256 x9,\n        uint256 x10\n    )\n        modifier1\n        modifier2\n        modifier3\n        modifier4\n        modifier5\n        modifier6\n        modifier7\n        modifier8\n        modifier9\n        modifier10;\n\n    function manyParamsManyReturns(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3,\n        uint256 x4,\n        uint256 x5,\n        uint256 x6,\n        uint256 x7,\n        uint256 x8,\n        uint256 x9,\n        uint256 x10\n    )\n        returns (\n            uint256 y1,\n            uint256 y2,\n            uint256 y3,\n            uint256 y4,\n            uint256 y5,\n            uint256 y6,\n            uint256 y7,\n            uint256 y8,\n            uint256 y9,\n            uint256 y10\n        );\n\n    function manyParamsManyModifiersManyReturns(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3,\n        uint256 x4,\n        uint256 x5,\n        uint256 x6,\n        uint256 x7,\n        uint256 x8,\n        uint256 x9,\n        uint256 x10\n    )\n        modifier1\n        modifier2\n        modifier3\n        modifier4\n        modifier5\n        modifier6\n        modifier7\n        modifier8\n        modifier9\n        modifier10\n        returns (\n            uint256 y1,\n            uint256 y2,\n            uint256 y3,\n            uint256 y4,\n            uint256 y5,\n            uint256 y6,\n            uint256 y7,\n            uint256 y8,\n            uint256 y9,\n            uint256 y10\n        );\n\n    function modifierOrderCorrect01()\n        public\n        view\n        virtual\n        override\n        modifier1\n        modifier2\n        returns (uint256);\n\n    function modifierOrderCorrect02()\n        private\n        pure\n        virtual\n        modifier1\n        modifier2\n        returns (string);\n\n    function modifierOrderCorrect03()\n        external\n        payable\n        override\n        modifier1\n        modifier2\n        returns (address);\n\n    function modifierOrderCorrect04()\n        internal\n        virtual\n        override\n        modifier1\n        modifier2\n        returns (uint256);\n\n    function modifierOrderIncorrect01()\n        public\n        view\n        virtual\n        override\n        modifier1\n        modifier2\n        returns (uint256);\n\n    function modifierOrderIncorrect02()\n        external\n        virtual\n        override\n        modifier1\n        modifier2\n        returns (uint256);\n\n    function modifierOrderIncorrect03()\n        internal\n        pure\n        virtual\n        modifier1\n        modifier2\n        returns (uint256);\n\n    function modifierOrderIncorrect04()\n        external\n        payable\n        override\n        modifier1\n        modifier2\n        returns (uint256);\n}\n\ncontract FunctionDefinitions {\n    function f() external {}\n    fallback() external {}\n\n    function f() external payable {}\n    fallback() external payable {}\n    receive() external payable {}\n\n    function noParamsNoModifiersNoReturns() {\n        a = 1;\n    }\n\n    function oneParam(uint256 x) {\n        a = 1;\n    }\n\n    function oneModifier() modifier1 {\n        a = 1;\n    }\n\n    function oneReturn() returns (uint256 y1) {\n        a = 1;\n    }\n\n    function manyParams(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3,\n        uint256 x4,\n        uint256 x5,\n        uint256 x6,\n        uint256 x7,\n        uint256 x8,\n        uint256 x9,\n        uint256 x10\n    ) {\n        a = 1;\n    }\n\n    function manyModifiers()\n        modifier1\n        modifier2\n        modifier3\n        modifier4\n        modifier5\n        modifier6\n        modifier7\n        modifier8\n        modifier9\n        modifier10\n    {\n        a = 1;\n    }\n\n    function manyReturns()\n        returns (\n            uint256 y1,\n            uint256 y2,\n            uint256 y3,\n            uint256 y4,\n            uint256 y5,\n            uint256 y6,\n            uint256 y7,\n            uint256 y8,\n            uint256 y9,\n            uint256 y10\n        )\n    {\n        a = 1;\n    }\n\n    function someParamsSomeModifiers(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3\n    ) modifier1 modifier2 modifier3 {\n        a = 1;\n    }\n\n    function someParamsSomeReturns(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3\n    ) returns (uint256 y1, uint256 y2, uint256 y3) {\n        a = 1;\n    }\n\n    function someModifiersSomeReturns()\n        modifier1\n        modifier2\n        modifier3\n        returns (uint256 y1, uint256 y2, uint256 y3)\n    {\n        a = 1;\n    }\n\n    function someParamSomeModifiersSomeReturns(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3\n    )\n        modifier1\n        modifier2\n        modifier3\n        returns (uint256 y1, uint256 y2, uint256 y3)\n    {\n        a = 1;\n    }\n\n    function someParamsManyModifiers(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3\n    )\n        modifier1\n        modifier2\n        modifier3\n        modifier4\n        modifier5\n        modifier6\n        modifier7\n        modifier8\n        modifier9\n        modifier10\n    {\n        a = 1;\n    }\n\n    function someParamsManyReturns(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3\n    )\n        returns (\n            uint256 y1,\n            uint256 y2,\n            uint256 y3,\n            uint256 y4,\n            uint256 y5,\n            uint256 y6,\n            uint256 y7,\n            uint256 y8,\n            uint256 y9,\n            uint256 y10\n        )\n    {\n        a = 1;\n    }\n\n    function manyParamsSomeModifiers(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3,\n        uint256 x4,\n        uint256 x5,\n        uint256 x6,\n        uint256 x7,\n        uint256 x8,\n        uint256 x9,\n        uint256 x10\n    ) modifier1 modifier2 modifier3 {\n        a = 1;\n    }\n\n    function manyParamsSomeReturns(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3,\n        uint256 x4,\n        uint256 x5,\n        uint256 x6,\n        uint256 x7,\n        uint256 x8,\n        uint256 x9,\n        uint256 x10\n    ) returns (uint256 y1, uint256 y2, uint256 y3) {\n        a = 1;\n    }\n\n    function manyParamsManyModifiers(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3,\n        uint256 x4,\n        uint256 x5,\n        uint256 x6,\n        uint256 x7,\n        uint256 x8,\n        uint256 x9,\n        uint256 x10\n    )\n        public\n        modifier1\n        modifier2\n        modifier3\n        modifier4\n        modifier5\n        modifier6\n        modifier7\n        modifier8\n        modifier9\n        modifier10\n    {\n        a = 1;\n    }\n\n    function manyParamsManyReturns(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3,\n        uint256 x4,\n        uint256 x5,\n        uint256 x6,\n        uint256 x7,\n        uint256 x8,\n        uint256 x9,\n        uint256 x10\n    )\n        returns (\n            uint256 y1,\n            uint256 y2,\n            uint256 y3,\n            uint256 y4,\n            uint256 y5,\n            uint256 y6,\n            uint256 y7,\n            uint256 y8,\n            uint256 y9,\n            uint256 y10\n        )\n    {\n        a = 1;\n    }\n\n    function manyParamsManyModifiersManyReturns(\n        uint256 x1,\n        uint256 x2,\n        uint256 x3,\n        uint256 x4,\n        uint256 x5,\n        uint256 x6,\n        uint256 x7,\n        uint256 x8,\n        uint256 x9,\n        uint256 x10\n    )\n        modifier1\n        modifier2\n        modifier3\n        modifier4\n        modifier5\n        modifier6\n        modifier7\n        modifier8\n        modifier9\n        modifier10\n        returns (\n            uint256 y1,\n            uint256 y2,\n            uint256 y3,\n            uint256 y4,\n            uint256 y5,\n            uint256 y6,\n            uint256 y7,\n            uint256 y8,\n            uint256 y9,\n            uint256 y10\n        )\n    {\n        a = 1;\n    }\n\n    function modifierOrderCorrect01()\n        public\n        view\n        virtual\n        override\n        modifier1\n        modifier2\n        returns (uint256)\n    {\n        a = 1;\n    }\n\n    function modifierOrderCorrect02()\n        private\n        pure\n        virtual\n        modifier1\n        modifier2\n        returns (string)\n    {\n        a = 1;\n    }\n\n    function modifierOrderCorrect03()\n        external\n        payable\n        override\n        modifier1\n        modifier2\n        returns (address)\n    {\n        a = 1;\n    }\n\n    function modifierOrderCorrect04()\n        internal\n        virtual\n        override\n        modifier1\n        modifier2\n        returns (uint256)\n    {\n        a = 1;\n    }\n\n    function modifierOrderIncorrect01()\n        public\n        view\n        virtual\n        override\n        modifier1\n        modifier2\n        returns (uint256)\n    {\n        a = 1;\n    }\n\n    function modifierOrderIncorrect02()\n        external\n        virtual\n        override\n        modifier1\n        modifier2\n        returns (uint256)\n    {\n        a = 1;\n    }\n\n    function modifierOrderIncorrect03()\n        internal\n        pure\n        virtual\n        modifier1\n        modifier2\n        returns (uint256)\n    {\n        a = 1;\n    }\n\n    function modifierOrderIncorrect04()\n        external\n        payable\n        override\n        modifier1\n        modifier2\n        returns (uint256)\n    {\n        a = 1;\n    }\n\n    fallback() external payable virtual {}\n    receive() external payable virtual {}\n}\n\ncontract FunctionOverrides is\n    FunctionInterfaces,\n    FunctionDefinitions\n{\n    function noParamsNoModifiersNoReturns() override {\n        a = 1;\n    }\n\n    function oneParam(uint256 x)\n        override(\n            FunctionInterfaces,\n            FunctionDefinitions,\n            SomeOtherFunctionContract,\n            SomeImport.AndAnotherFunctionContract\n        )\n    {\n        a = 1;\n    }\n\n    function simple(\n        address _target,\n        bytes memory _payload\n    ) internal {\n        a = 1;\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/FunctionDefinitionWithFunctionReturns/fmt.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.17;\n\ncontract ReturnFnFormat {\n    function returnsFunction()\n        internal\n        pure\n        returns (function() internal pure returns (uint256))\n    {}\n}\n\n// https://github.com/foundry-rs/foundry/issues/7920\ncontract ReturnFnDisableFormat {\n    // forgefmt: disable-next-line\n    function disableFnFormat() external returns (uint256) {\n        return 0;\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/FunctionDefinitionWithFunctionReturns/original.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.17;\n\ncontract ReturnFnFormat {\n    function returnsFunction()\n    internal\n    pure\n    returns (\n        function()\n        internal pure returns (uint256)\n    )\n    {}\n}\n\n// https://github.com/foundry-rs/foundry/issues/7920\ncontract ReturnFnDisableFormat {\n    // forgefmt: disable-next-line\n    function disableFnFormat() external returns (uint256) {\n        return 0;\n    }\n}"
  },
  {
    "path": "crates/fmt/testdata/FunctionType/fmt.sol",
    "content": "// config: line_length = 100\nlibrary ArrayUtils {\n    function map(uint256[] memory self, function(uint256) pure returns (uint256) f)\n        internal\n        pure\n        returns (uint256[] memory r)\n    {\n        r = new uint256[](self.length);\n        for (uint256 i = 0; i < self.length; i++) {\n            r[i] = f(self[i]);\n        }\n    }\n\n    function reduce(uint256[] memory self, function(uint256, uint256) pure returns (uint256) f)\n        internal\n        pure\n        returns (uint256 r)\n    {\n        r = self[0];\n        for (uint256 i = 1; i < self.length; i++) {\n            r = f(r, self[i]);\n        }\n    }\n\n    function range(uint256 length) internal pure returns (uint256[] memory r) {\n        r = new uint256[](length);\n        for (uint256 i = 0; i < r.length; i++) {\n            r[i] = i;\n        }\n    }\n\n    function _castToPure(function(bytes memory) internal view fnIn)\n        returns (function(bytes memory) pure fnOut)\n    {\n        assembly {\n            fnOut := fnIn\n        }\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/FunctionType/original.sol",
    "content": "library ArrayUtils {\n    function map(uint[] memory self, function (uint) pure returns (uint) f)\n        internal\n        pure\n        returns (\n            uint[] memory r\n        )\n    {\n        r = new uint[]( self.length);\n        for (uint i = 0; i < self.length; i++) {\n            r[i] = f(self[i]);\n        }\n    }\n\n    function reduce(\n        uint[] memory self,\n        function (uint, uint) pure returns (uint) f\n    ) internal pure returns (uint256 r) {\n        r = self[0];\n        for (uint i = 1; i < self.length; i++) {\n            r = f(r, self[i]);\n        }\n    }\n\n    function range(uint256 length) internal pure returns (uint[] memory r) {\n        r = new uint256[](length );\n        for (uint i = 0; i < r.length; i++) {\n            r[i] = i;\n        }\n    }\n\n    function _castToPure(function(bytes memory) internal view fnIn)\nreturns (function(bytes memory) pure fnOut)\n   {\n       assembly {\n           fnOut := fnIn\n           }\n        }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/HexUnderscore/bytes.fmt.sol",
    "content": "// config: hex_underscore = \"bytes\"\ncontract HexLiteral {\n    function test() external {\n        hex\"01_23_00_00\";\n        hex\"01_23_00_00\";\n        hex\"01_23_00_00\";\n        hex\"\";\n        hex\"60_01_60_02_53\";\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/HexUnderscore/fmt.sol",
    "content": "contract HexLiteral {\n    function test() external {\n        hex\"01230000\";\n        hex\"01230000\";\n        hex\"01230000\";\n        hex\"\";\n        hex\"6001600253\";\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/HexUnderscore/original.sol",
    "content": "contract HexLiteral {\n    function test() external {\n       hex\"0123_0000\";\n       hex\"01230000\";\n       hex\"0123_00_00\";\n       hex\"\";\n       hex\"6001_6002_53\";\n    }\n}"
  },
  {
    "path": "crates/fmt/testdata/HexUnderscore/preserve.fmt.sol",
    "content": "// config: hex_underscore = \"preserve\"\ncontract HexLiteral {\n    function test() external {\n        hex\"0123_0000\";\n        hex\"01230000\";\n        hex\"0123_00_00\";\n        hex\"\";\n        hex\"6001_6002_53\";\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/HexUnderscore/remove.fmt.sol",
    "content": "// config: hex_underscore = \"remove\"\ncontract HexLiteral {\n    function test() external {\n        hex\"01230000\";\n        hex\"01230000\";\n        hex\"01230000\";\n        hex\"\";\n        hex\"6001600253\";\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/IfStatement/block-multi.fmt.sol",
    "content": "// config: single_line_statement_blocks = \"multi\"\nfunction execute() returns (bool) {\n    if (true) {\n        // always returns true\n        return true;\n    }\n    return false;\n}\n\nfunction executeElse() {}\n\nfunction executeWithMultipleParameters(bool parameter1, bool parameter2) {}\n\nfunction executeWithVeryVeryVeryLongNameAndSomeParameter(bool parameter) {}\n\ncontract IfStatement {\n    function test() external {\n        if (true) {\n            execute();\n        }\n\n        bool condition;\n        bool anotherLongCondition;\n        bool andAnotherVeryVeryLongCondition;\n        if (\n            condition && anotherLongCondition || andAnotherVeryVeryLongCondition\n        ) {\n            execute();\n        }\n\n        // comment\n        if (condition) {\n            execute();\n        } else if (anotherLongCondition) {\n            execute(); // differently\n        }\n\n        /* comment1 */\n        if ( /* comment2 */ /* comment3 */\n            condition // comment4\n        ) {\n            // comment5\n            execute();\n        } // comment6\n\n        if (condition) {\n            execute();\n        } // comment7\n        /* comment8 */\n        /* comment9 */\n        else if ( /* comment10 */\n            anotherLongCondition // comment11\n            /* comment12 */\n        ) {\n            execute();\n        } // comment13\n        /* comment14 */\n        else {} // comment15\n\n        if (\n            // comment16\n            condition /* comment17 */\n        ) {\n            execute();\n        }\n\n        if (condition) {\n            execute();\n        } else {\n            executeElse();\n        }\n\n        if (condition) {\n            if (anotherLongCondition) {\n                execute();\n            }\n        }\n\n        if (condition) {\n            execute();\n        }\n\n        if (\n            condition && anotherLongCondition || andAnotherVeryVeryLongCondition\n        ) {\n            execute();\n        }\n\n        if (condition) {\n            if (anotherLongCondition) {\n                execute();\n            }\n        }\n\n        if (condition) {\n            execute(); // comment18\n        }\n\n        if (condition) {\n            executeWithMultipleParameters(condition, anotherLongCondition);\n        }\n\n        if (condition) {\n            executeWithVeryVeryVeryLongNameAndSomeParameter(condition);\n        }\n\n        if (condition) {\n            execute();\n        } else {\n            execute();\n        }\n\n        if (condition) {}\n\n        if (condition) {\n            executeWithMultipleParameters(condition, anotherLongCondition);\n        } else if (anotherLongCondition) {\n            execute();\n        }\n\n        if (condition && ((condition || anotherLongCondition))) {\n            execute();\n        }\n\n        // if statement\n        if (condition) {\n            execute();\n        }\n        // else statement\n        else {\n            execute();\n        }\n\n        // if statement\n        if (condition) {\n            execute();\n        }\n        // else statement\n        else {\n            executeWithMultipleParameters(\n                anotherLongCondition, andAnotherVeryVeryLongCondition\n            );\n        }\n\n        if (condition) {\n            execute();\n        } else if (condition) {\n            execute();\n        } else if (condition) {\n            execute();\n        } else if (condition) {\n            execute();\n        } else if (condition) {\n            execute();\n        }\n\n        if (condition) {\n            execute();\n        } else if (condition) {\n            execute();\n        } else if (condition) {\n            execute();\n        } else if (condition) {\n            execute();\n        } else if (condition) {\n            execute();\n        } else {\n            executeElse();\n        }\n    }\n\n    function test_nestedBkocks() public {\n        if (accesses[i].account == address(simpleStorage)) {\n            for (uint256 j = 0; j < accesses[i].storageAccesses.length; j++) {\n                bytes32 slot = accesses[i].storageAccesses[j].slot;\n                if (slot == bytes32(uint256(0))) {\n                    foundValueSlot = true;\n                }\n                if (slot == bytes32(uint256(1))) {\n                    foundOwnerSlot = true;\n                }\n                if (slot == bytes32(uint256(2))) {\n                    foundValuesSlot0 = true;\n                }\n                if (slot == bytes32(uint256(3))) {\n                    foundValuesSlot1 = true;\n                }\n                if (slot == bytes32(uint256(4))) {\n                    foundValuesSlot2 = true;\n                }\n            }\n        }\n    }\n\n    function test_emptyIfBlock() external {\n        if (block.number < 10) {} else {\n            revert();\n        }\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/IfStatement/block-single.fmt.sol",
    "content": "// config: single_line_statement_blocks = \"single\"\nfunction execute() returns (bool) {\n    if (true) {\n        // always returns true\n        return true;\n    }\n    return false;\n}\n\nfunction executeElse() {}\n\nfunction executeWithMultipleParameters(bool parameter1, bool parameter2) {}\n\nfunction executeWithVeryVeryVeryLongNameAndSomeParameter(bool parameter) {}\n\ncontract IfStatement {\n    function test() external {\n        if (true) execute();\n\n        bool condition;\n        bool anotherLongCondition;\n        bool andAnotherVeryVeryLongCondition;\n        if (\n            condition && anotherLongCondition || andAnotherVeryVeryLongCondition\n        ) execute();\n\n        // comment\n        if (condition) execute();\n        else if (anotherLongCondition) execute(); // differently\n\n        /* comment1 */\n        if ( /* comment2 */ /* comment3 */\n            condition // comment4\n        ) {\n            // comment5\n            execute();\n        } // comment6\n\n        if (condition) {\n            execute();\n        } // comment7\n        /* comment8 */\n        /* comment9 */\n        else if ( /* comment10 */\n            anotherLongCondition // comment11\n            /* comment12 */\n        ) {\n            execute();\n        } // comment13\n        /* comment14 */\n        else {} // comment15\n\n        if (\n            // comment16\n            condition /* comment17 */\n        ) execute();\n\n        if (condition) execute();\n        else executeElse();\n\n        if (condition) if (anotherLongCondition) execute();\n\n        if (condition) execute();\n\n        if (\n            condition && anotherLongCondition || andAnotherVeryVeryLongCondition\n        ) execute();\n\n        if (condition) if (anotherLongCondition) execute();\n\n        if (condition) execute(); // comment18\n\n        if (condition) {\n            executeWithMultipleParameters(condition, anotherLongCondition);\n        }\n\n        if (condition) {\n            executeWithVeryVeryVeryLongNameAndSomeParameter(condition);\n        }\n\n        if (condition) execute();\n        else execute();\n\n        if (condition) {}\n\n        if (condition) {\n            executeWithMultipleParameters(condition, anotherLongCondition);\n        } else if (anotherLongCondition) {\n            execute();\n        }\n\n        if (condition && ((condition || anotherLongCondition))) execute();\n\n        // if statement\n        if (condition) execute();\n        // else statement\n        else execute();\n\n        // if statement\n        if (condition) {\n            execute();\n        }\n        // else statement\n        else {\n            executeWithMultipleParameters(\n                anotherLongCondition, andAnotherVeryVeryLongCondition\n            );\n        }\n\n        if (condition) execute();\n        else if (condition) execute();\n        else if (condition) execute();\n        else if (condition) execute();\n        else if (condition) execute();\n\n        if (condition) execute();\n        else if (condition) execute();\n        else if (condition) execute();\n        else if (condition) execute();\n        else if (condition) execute();\n        else executeElse();\n    }\n\n    function test_nestedBkocks() public {\n        if (accesses[i].account == address(simpleStorage)) {\n            for (uint256 j = 0; j < accesses[i].storageAccesses.length; j++) {\n                bytes32 slot = accesses[i].storageAccesses[j].slot;\n                if (slot == bytes32(uint256(0))) foundValueSlot = true;\n                if (slot == bytes32(uint256(1))) foundOwnerSlot = true;\n                if (slot == bytes32(uint256(2))) foundValuesSlot0 = true;\n                if (slot == bytes32(uint256(3))) foundValuesSlot1 = true;\n                if (slot == bytes32(uint256(4))) foundValuesSlot2 = true;\n            }\n        }\n    }\n\n    function test_emptyIfBlock() external {\n        if (block.number < 10) {} else {\n            revert();\n        }\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/IfStatement/fmt.sol",
    "content": "function execute() returns (bool) {\n    if (true) {\n        // always returns true\n        return true;\n    }\n    return false;\n}\n\nfunction executeElse() {}\n\nfunction executeWithMultipleParameters(bool parameter1, bool parameter2) {}\n\nfunction executeWithVeryVeryVeryLongNameAndSomeParameter(bool parameter) {}\n\ncontract IfStatement {\n    function test() external {\n        if (true) {\n            execute();\n        }\n\n        bool condition;\n        bool anotherLongCondition;\n        bool andAnotherVeryVeryLongCondition;\n        if (\n            condition && anotherLongCondition || andAnotherVeryVeryLongCondition\n        ) {\n            execute();\n        }\n\n        // comment\n        if (condition) {\n            execute();\n        } else if (anotherLongCondition) {\n            execute(); // differently\n        }\n\n        /* comment1 */\n        if ( /* comment2 */ /* comment3 */\n            condition // comment4\n        ) {\n            // comment5\n            execute();\n        } // comment6\n\n        if (condition) {\n            execute();\n        } // comment7\n        /* comment8 */\n        /* comment9 */\n        else if ( /* comment10 */\n            anotherLongCondition // comment11\n            /* comment12 */\n        ) {\n            execute();\n        } // comment13\n        /* comment14 */\n        else {} // comment15\n\n        if (\n            // comment16\n            condition /* comment17 */\n        ) {\n            execute();\n        }\n\n        if (condition) {\n            execute();\n        } else {\n            executeElse();\n        }\n\n        if (condition) {\n            if (anotherLongCondition) {\n                execute();\n            }\n        }\n\n        if (condition) execute();\n\n        if (\n            condition && anotherLongCondition || andAnotherVeryVeryLongCondition\n        ) execute();\n\n        if (condition) if (anotherLongCondition) execute();\n\n        if (condition) execute(); // comment18\n\n        if (condition) {\n            executeWithMultipleParameters(condition, anotherLongCondition);\n        }\n\n        if (condition) {\n            executeWithVeryVeryVeryLongNameAndSomeParameter(condition);\n        }\n\n        if (condition) execute();\n        else execute();\n\n        if (condition) {}\n\n        if (condition) {\n            executeWithMultipleParameters(condition, anotherLongCondition);\n        } else if (anotherLongCondition) {\n            execute();\n        }\n\n        if (condition && ((condition || anotherLongCondition))) execute();\n\n        // if statement\n        if (condition) execute();\n        // else statement\n        else execute();\n\n        // if statement\n        if (condition) {\n            execute();\n        }\n        // else statement\n        else {\n            executeWithMultipleParameters(\n                anotherLongCondition, andAnotherVeryVeryLongCondition\n            );\n        }\n\n        if (condition) execute();\n        else if (condition) execute();\n        else if (condition) execute();\n        else if (condition) execute();\n        else if (condition) execute();\n\n        if (condition) {\n            execute();\n        } else if (condition) {\n            execute();\n        } else if (condition) {\n            execute();\n        } else if (condition) {\n            execute();\n        } else if (condition) {\n            execute();\n        } else {\n            executeElse();\n        }\n    }\n\n    function test_nestedBkocks() public {\n        if (accesses[i].account == address(simpleStorage)) {\n            for (uint256 j = 0; j < accesses[i].storageAccesses.length; j++) {\n                bytes32 slot = accesses[i].storageAccesses[j].slot;\n                if (slot == bytes32(uint256(0))) foundValueSlot = true;\n                if (slot == bytes32(uint256(1))) foundOwnerSlot = true;\n                if (slot == bytes32(uint256(2))) foundValuesSlot0 = true;\n                if (slot == bytes32(uint256(3))) foundValuesSlot1 = true;\n                if (slot == bytes32(uint256(4))) foundValuesSlot2 = true;\n            }\n        }\n    }\n\n    function test_emptyIfBlock() external {\n        if (block.number < 10) {} else {\n            revert();\n        }\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/IfStatement/original.sol",
    "content": "function execute() returns (bool) {\n    if (true) {\n        // always returns true\n        return true;\n    }\n    return false;\n}\n\nfunction executeElse() {}\n\nfunction executeWithMultipleParameters(bool parameter1, bool parameter2) {}\n\nfunction executeWithVeryVeryVeryLongNameAndSomeParameter(bool parameter) {}\n\ncontract IfStatement {\n\n    function test() external {\n        if(  true)\n    {\n            execute() ;\n        }\n\n    bool condition; bool anotherLongCondition; bool andAnotherVeryVeryLongCondition ;\n    if\n        ( condition && anotherLongCondition ||\n    andAnotherVeryVeryLongCondition\n        )\n        { execute(); }\n\n            // comment\n        if (condition) { execute(); }\n        else\n        if (anotherLongCondition) {\n            execute(); // differently\n        }\n\n          /* comment1 */  if /* comment2 */ ( /* comment3 */ condition ) // comment4\n            {\n            // comment5\n            execute();\n        } // comment6\n\n          if (condition ) {\n              execute();\n          } // comment7\n          /* comment8 */\n          /* comment9 */ else if /* comment10 */ (anotherLongCondition) // comment11\n          /* comment12 */ {\n            execute() ;\n          } // comment13\n          /* comment14 */ else { } // comment15\n\n          if (\n            // comment16\n            condition       /* comment17 */\n        )\n        {\n            execute();\n        }\n\n          if (condition)\n            execute();\n        else\n            executeElse();\n\n        if (condition)\n            if (anotherLongCondition)\n                execute();\n\n        if (condition) execute();\n\n        if (condition && anotherLongCondition ||\n    andAnotherVeryVeryLongCondition ) execute();\n\n        if (condition) if (anotherLongCondition) execute();\n\n        if (condition) execute(); // comment18\n\n        if (condition) executeWithMultipleParameters(condition, anotherLongCondition);\n\n        if (condition) executeWithVeryVeryVeryLongNameAndSomeParameter(condition);\n\n        if (condition) execute(); else execute();\n\n        if (condition) {}\n\n        if (condition) executeWithMultipleParameters(condition, anotherLongCondition); else if (anotherLongCondition) execute();\n\n        if (condition && ((condition || anotherLongCondition)\n        )\n        ) execute();\n\n        // if statement\n        if (condition) execute();\n        // else statement\n        else execute();\n\n        // if statement\n        if (condition) execute();\n        // else statement\n        else executeWithMultipleParameters(anotherLongCondition, andAnotherVeryVeryLongCondition);\n\n        if (condition) execute();\n        else if (condition) execute();\n        else if (condition) execute();\n        else if (condition) execute();\n        else if (condition) execute();\n\n        if (condition) execute();\n        else if (condition)\n            execute();\n        else if (condition) execute();\n        else if (condition)\n            execute();\n        else if (condition) execute();\n        else\n            executeElse();\n    }\n\n    function test_nestedBkocks() public {\n        if (accesses[i].account == address(simpleStorage)) {\n            for (uint256 j = 0; j < accesses[i].storageAccesses.length; j++) {\n                bytes32 slot = accesses[i].storageAccesses[j].slot;\n                if (slot == bytes32(uint256(0))) foundValueSlot = true;\n                if (slot == bytes32(uint256(1))) foundOwnerSlot = true;\n                if (slot == bytes32(uint256(2))) foundValuesSlot0 = true;\n                if (slot == bytes32(uint256(3))) foundValuesSlot1 = true;\n                if (slot == bytes32(uint256(4))) foundValuesSlot2 = true;\n            }\n        }\n    }\n\n    function test_emptyIfBlock() external {\n        if (block.number < 10) {} else {\n            revert();\n        }\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/IfStatement2/120.fmt.sol",
    "content": "// config: line_length = 120\ncontract IfStatement {\n    function test() external {\n        bool anotherLongCondition;\n\n        if (condition && ((condition || anotherLongCondition))) execute();\n    }\n\n    // https://github.com/foundry-rs/foundry/issues/12102\n    function repro() external {\n        for (uint256 i; i < len; ++i) {\n            proportions[i] = totalDepositedTvl == 0\n                ? 0\n                : Math.mulDiv(vaultUsdValue[i], 1e18, totalDepositedTvl, Math.Rounding.Floor);\n            proportions[i] = totalDepositedTvl == 0\n                ? 0\n                : Math.mulDiv(vaultUsdValue[i], 1e18, totalDepositedTvl, Math.Rounding.Floor);\n        }\n    }\n\n    // https://github.com/foundry-rs/foundry/issues/12315\n    function repro_longComplexExpr() {\n        vars.expectedSnapshotTime = withdrawAmount\n            <= getDescaledAmount(flow.getSnapshotDebtScaled(streamId), flow.getTokenDecimals(streamId))\n            ? flow.getSnapshotTime(streamId)\n            : getBlockTimestamp();\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/IfStatement2/fmt.sol",
    "content": "contract IfStatement {\n    function test() external {\n        bool anotherLongCondition;\n\n        if (condition && ((condition || anotherLongCondition))) execute();\n    }\n\n    // https://github.com/foundry-rs/foundry/issues/12102\n    function repro() external {\n        for (uint256 i; i < len; ++i) {\n            proportions[i] = totalDepositedTvl == 0\n                ? 0\n                : Math.mulDiv(\n                    vaultUsdValue[i],\n                    1e18,\n                    totalDepositedTvl,\n                    Math.Rounding.Floor\n                );\n            proportions[i] = totalDepositedTvl == 0\n                ? 0\n                : Math.mulDiv(\n                    vaultUsdValue[i],\n                    1e18,\n                    totalDepositedTvl,\n                    Math.Rounding.Floor\n                );\n        }\n    }\n\n    // https://github.com/foundry-rs/foundry/issues/12315\n    function repro_longComplexExpr() {\n        vars.expectedSnapshotTime = withdrawAmount\n            <= getDescaledAmount(\n                flow.getSnapshotDebtScaled(streamId),\n                flow.getTokenDecimals(streamId)\n            )\n            ? flow.getSnapshotTime(streamId)\n            : getBlockTimestamp();\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/IfStatement2/original.sol",
    "content": "contract IfStatement {\n\n    function test() external {\n        bool anotherLongCondition;\n\n        if (condition && ((condition || anotherLongCondition)\n        )\n        ) execute();\n    }\n\n    // https://github.com/foundry-rs/foundry/issues/12102\n    function repro() external {\n        for (uint i; i < len; ++i) {\n            proportions[i] =\n                totalDepositedTvl == 0 ? 0 : Math.mulDiv(vaultUsdValue[i], 1e18, totalDepositedTvl, Math.Rounding.Floor);\n            proportions[i] = totalDepositedTvl == 0\n                ? 0\n                : Math.mulDiv(vaultUsdValue[i], 1e18, totalDepositedTvl, Math.Rounding.Floor);\n        }\n    }\n\n    // https://github.com/foundry-rs/foundry/issues/12315\n    function repro_longComplexExpr() {\n        vars. expectedSnapshotTime = withdrawAmount\n            <= getDescaledAmount(flow.getSnapshotDebtScaled (streamId), flow.getTokenDecimals(streamId))\n            ? flow.getSnapshotTime(streamId)\n            : getBlockTimestamp ();\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/ImportDirective/bracket-spacing.fmt.sol",
    "content": "// config: bracket_spacing = true\nimport \"SomeFile.sol\";\nimport \"SomeFile.sol\";\nimport \"SomeFile.sol\" as SomeOtherFile;\nimport \"SomeFile.sol\" as SomeOtherFile;\nimport \"AnotherFile.sol\" as SomeSymbol;\nimport \"AnotherFile.sol\" as SomeSymbol;\nimport { symbol1 as alias0, symbol2 } from \"File.sol\";\nimport { symbol1 as alias0, symbol2 } from \"File.sol\";\nimport {\n    symbol1 as alias1,\n    symbol2 as alias2,\n    symbol3 as alias3,\n    symbol4\n} from \"File2.sol\";\nimport {\n    symbol1 as alias1,\n    symbol2 as alias2,\n    symbol3 as alias3,\n    symbol4\n} from \"File2.sol\";\n\n// Single import that exceeds line length (121 chars)\nimport {\n    ITransparentUpgradeableProxy\n} from \"@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol\";\n"
  },
  {
    "path": "crates/fmt/testdata/ImportDirective/fmt.sol",
    "content": "import \"SomeFile.sol\";\nimport \"SomeFile.sol\";\nimport \"SomeFile.sol\" as SomeOtherFile;\nimport \"SomeFile.sol\" as SomeOtherFile;\nimport \"AnotherFile.sol\" as SomeSymbol;\nimport \"AnotherFile.sol\" as SomeSymbol;\nimport {symbol1 as alias0, symbol2} from \"File.sol\";\nimport {symbol1 as alias0, symbol2} from \"File.sol\";\nimport {\n    symbol1 as alias1,\n    symbol2 as alias2,\n    symbol3 as alias3,\n    symbol4\n} from \"File2.sol\";\nimport {\n    symbol1 as alias1,\n    symbol2 as alias2,\n    symbol3 as alias3,\n    symbol4\n} from \"File2.sol\";\n\n// Single import that exceeds line length (121 chars)\nimport {\n    ITransparentUpgradeableProxy\n} from \"@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol\";\n"
  },
  {
    "path": "crates/fmt/testdata/ImportDirective/namespace-import-prefer-glob.fmt.sol",
    "content": "// config: namespace_import_style = \"prefer_glob\"\nimport \"SomeFile.sol\";\nimport \"SomeFile.sol\";\nimport * as SomeOtherFile from \"SomeFile.sol\";\nimport * as SomeOtherFile from \"SomeFile.sol\";\nimport * as SomeSymbol from \"AnotherFile.sol\";\nimport * as SomeSymbol from \"AnotherFile.sol\";\nimport {symbol1 as alias0, symbol2} from \"File.sol\";\nimport {symbol1 as alias0, symbol2} from \"File.sol\";\nimport {\n    symbol1 as alias1,\n    symbol2 as alias2,\n    symbol3 as alias3,\n    symbol4\n} from \"File2.sol\";\nimport {\n    symbol1 as alias1,\n    symbol2 as alias2,\n    symbol3 as alias3,\n    symbol4\n} from \"File2.sol\";\n\n// Single import that exceeds line length (121 chars)\nimport {\n    ITransparentUpgradeableProxy\n} from \"@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol\";\n"
  },
  {
    "path": "crates/fmt/testdata/ImportDirective/namespace-import-prefer-plain.fmt.sol",
    "content": "// config: namespace_import_style = \"prefer_plain\"\nimport \"SomeFile.sol\";\nimport \"SomeFile.sol\";\nimport \"SomeFile.sol\" as SomeOtherFile;\nimport \"SomeFile.sol\" as SomeOtherFile;\nimport \"AnotherFile.sol\" as SomeSymbol;\nimport \"AnotherFile.sol\" as SomeSymbol;\nimport {symbol1 as alias0, symbol2} from \"File.sol\";\nimport {symbol1 as alias0, symbol2} from \"File.sol\";\nimport {\n    symbol1 as alias1,\n    symbol2 as alias2,\n    symbol3 as alias3,\n    symbol4\n} from \"File2.sol\";\nimport {\n    symbol1 as alias1,\n    symbol2 as alias2,\n    symbol3 as alias3,\n    symbol4\n} from \"File2.sol\";\n\n// Single import that exceeds line length (121 chars)\nimport {\n    ITransparentUpgradeableProxy\n} from \"@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol\";\n"
  },
  {
    "path": "crates/fmt/testdata/ImportDirective/namespace-import-preserve.fmt.sol",
    "content": "// config: namespace_import_style = \"preserve\"\nimport \"SomeFile.sol\";\nimport \"SomeFile.sol\";\nimport \"SomeFile.sol\" as SomeOtherFile;\nimport \"SomeFile.sol\" as SomeOtherFile;\nimport * as SomeSymbol from \"AnotherFile.sol\";\nimport * as SomeSymbol from \"AnotherFile.sol\";\nimport {symbol1 as alias0, symbol2} from \"File.sol\";\nimport {symbol1 as alias0, symbol2} from \"File.sol\";\nimport {\n    symbol1 as alias1,\n    symbol2 as alias2,\n    symbol3 as alias3,\n    symbol4\n} from \"File2.sol\";\nimport {\n    symbol1 as alias1,\n    symbol2 as alias2,\n    symbol3 as alias3,\n    symbol4\n} from \"File2.sol\";\n\n// Single import that exceeds line length (121 chars)\nimport {\n    ITransparentUpgradeableProxy\n} from \"@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol\";\n"
  },
  {
    "path": "crates/fmt/testdata/ImportDirective/original.sol",
    "content": "import \"SomeFile.sol\";\nimport 'SomeFile.sol';\nimport \"SomeFile.sol\" as SomeOtherFile;\nimport 'SomeFile.sol' as SomeOtherFile;\nimport * as SomeSymbol from \"AnotherFile.sol\";\nimport * as SomeSymbol from 'AnotherFile.sol';\nimport {symbol1 as alias0, symbol2} from \"File.sol\";\nimport {symbol1 as alias0, symbol2} from 'File.sol';\nimport {symbol1 as alias1, symbol2 as alias2, symbol3 as alias3, symbol4} from \"File2.sol\";\nimport {symbol1 as alias1, symbol2 as alias2, symbol3 as alias3, symbol4} from 'File2.sol';\n\n// Single import that exceeds line length (121 chars)\nimport { ITransparentUpgradeableProxy } from \"@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol\";\n"
  },
  {
    "path": "crates/fmt/testdata/ImportDirective/preserve-quote.fmt.sol",
    "content": "// config: quote_style = \"preserve\"\nimport \"SomeFile.sol\";\nimport 'SomeFile.sol';\nimport \"SomeFile.sol\" as SomeOtherFile;\nimport 'SomeFile.sol' as SomeOtherFile;\nimport \"AnotherFile.sol\" as SomeSymbol;\nimport 'AnotherFile.sol' as SomeSymbol;\nimport {symbol1 as alias0, symbol2} from \"File.sol\";\nimport {symbol1 as alias0, symbol2} from 'File.sol';\nimport {\n    symbol1 as alias1,\n    symbol2 as alias2,\n    symbol3 as alias3,\n    symbol4\n} from \"File2.sol\";\nimport {\n    symbol1 as alias1,\n    symbol2 as alias2,\n    symbol3 as alias3,\n    symbol4\n} from 'File2.sol';\n\n// Single import that exceeds line length (121 chars)\nimport {\n    ITransparentUpgradeableProxy\n} from \"@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol\";\n"
  },
  {
    "path": "crates/fmt/testdata/ImportDirective/single-quote.fmt.sol",
    "content": "// config: quote_style = \"single\"\nimport 'SomeFile.sol';\nimport 'SomeFile.sol';\nimport 'SomeFile.sol' as SomeOtherFile;\nimport 'SomeFile.sol' as SomeOtherFile;\nimport 'AnotherFile.sol' as SomeSymbol;\nimport 'AnotherFile.sol' as SomeSymbol;\nimport {symbol1 as alias0, symbol2} from 'File.sol';\nimport {symbol1 as alias0, symbol2} from 'File.sol';\nimport {\n    symbol1 as alias1,\n    symbol2 as alias2,\n    symbol3 as alias3,\n    symbol4\n} from 'File2.sol';\nimport {\n    symbol1 as alias1,\n    symbol2 as alias2,\n    symbol3 as alias3,\n    symbol4\n} from 'File2.sol';\n\n// Single import that exceeds line length (121 chars)\nimport {\n    ITransparentUpgradeableProxy\n} from '@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol';\n"
  },
  {
    "path": "crates/fmt/testdata/ImportDirective/single_line_import.fmt.sol",
    "content": "// config: single_line_imports = true\nimport \"SomeFile.sol\";\nimport \"SomeFile.sol\";\nimport \"SomeFile.sol\" as SomeOtherFile;\nimport \"SomeFile.sol\" as SomeOtherFile;\nimport \"AnotherFile.sol\" as SomeSymbol;\nimport \"AnotherFile.sol\" as SomeSymbol;\nimport {symbol1 as alias0, symbol2} from \"File.sol\";\nimport {symbol1 as alias0, symbol2} from \"File.sol\";\nimport {\n    symbol1 as alias1,\n    symbol2 as alias2,\n    symbol3 as alias3,\n    symbol4\n} from \"File2.sol\";\nimport {\n    symbol1 as alias1,\n    symbol2 as alias2,\n    symbol3 as alias3,\n    symbol4\n} from \"File2.sol\";\n\n// Single import that exceeds line length (121 chars)\nimport {ITransparentUpgradeableProxy} from \"@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol\";\n"
  },
  {
    "path": "crates/fmt/testdata/InlineDisable/fmt.sol",
    "content": "pragma solidity ^0.5.2;\n\n// forgefmt: disable-next-line\npragma    solidity     ^0.5.2;\n\nimport {\n    symbol1 as alias1,\n    symbol2 as alias2,\n    symbol3 as alias3,\n    symbol4\n} from \"File2.sol\";\n\n// forgefmt: disable-next-line\nimport {symbol1 as alias1, symbol2 as alias2, symbol3 as alias3, symbol4} from 'File2.sol';\n\nenum States {\n    State1,\n    State2,\n    State3,\n    State4,\n    State5,\n    State6,\n    State7,\n    State8,\n    State9\n}\n\n// forgefmt: disable-next-line\nenum States { State1, State2, State3, State4, State5, State6, State7, State8, State9 }\n\n// forgefmt: disable-next-line\nbytes32 constant BYTES = 0x035aff83d86937d35b32e04f0ddc6ff469290eef2f1b692d8a815c89404d4749;\n\n// forgefmt: disable-start\n\n// comment1\n\n\n// comment2\n/* comment 3 */ /*\n    comment4\n     */ // comment 5\n\n\n/// Doccomment 1\n    /// Doccomment 2\n\n/**\n     * docccoment 3\n  */\n\n\n// forgefmt: disable-end\n\n// forgefmt: disable-start\n\nfunction test1() {}\n\nfunction test2() {}\n\n// forgefmt: disable-end\n\ncontract Constructors is Ownable, Changeable {\n    //forgefmt: disable-next-item\n    function Constructors(variable1) public Changeable(variable1) Ownable() onlyOwner {\n    }\n\n    //forgefmt: disable-next-item\n    constructor(variable1, variable2, variable3, variable4, variable5, variable6, variable7) public Changeable(variable1, variable2, variable3, variable4, variable5, variable6, variable7) Ownable() onlyOwner {}\n}\n\nfunction test() {\n    uint256 pi_approx = 666 / 212;\n    uint256 pi_approx = /* forgefmt: disable-start */ 666    /    212; /* forgefmt: disable-end */\n\n    // forgefmt: disable-next-item\n    uint256 pi_approx = 666 /\n        212;\n\n    uint256 test_postfix = 1; // forgefmt: disable-start\n                              // comment1\n                              // comment2\n                              // comment3\n                              // forgefmt: disable-end\n}\n\n// forgefmt: disable-next-item\nfunction testFunc(uint256   num, bytes32 data  ,    address receiver)\n    public payable    attr1   Cool( \"hello\"   ) {}\n\nfunction testAttrs(uint256 num, bytes32 data, address receiver)\n    // forgefmt: disable-next-line\n    public payable    attr1   Cool( \"hello\"   ) {}\n\n// forgefmt: disable-next-line\nfunction testParams(uint256   num, bytes32 data  ,    address receiver)\n    public\n    payable\n    attr1\n    Cool(\"hello\")\n{}\n\nfunction testDoWhile() external {\n    //forgefmt: disable-start\n    uint256 i;\n    do { \"test\"; } while (i != 0);\n\n    do\n    {}\n    while\n    (\ni != 0);\n\n    bool someVeryVeryLongCondition;\n    do { \"test\"; } while(\n        someVeryVeryLongCondition && !someVeryVeryLongCondition &&\n!someVeryVeryLongCondition &&\nsomeVeryVeryLongCondition);\n\n    do i++; while(i < 10);\n\n    do do i++; while (i < 30); while(i < 20);\n    //forgefmt: disable-end\n}\n\nfunction forStatement() {\n    //forgefmt: disable-start\n        for\n    (uint256 i1\n        ; i1 < 10;      i1++)\n    {\n             i1++;\n            }\n\n        uint256 i2;\n        for(++i2;i2<10;i2++)\n\n        {}\n\n        uint256 veryLongVariableName = 1000;\n        for ( uint256 i3; i3 < 10\n        && veryLongVariableName>999 &&      veryLongVariableName< 1001\n        ; i3++)\n        { i3 ++ ; }\n\n        for (type(uint256).min;;) {}\n\n        for (;;) { \"test\" ; }\n\n        for (uint256 i4; i4< 10; i4++) i4++;\n\n        for (uint256 i5; ;)\n            for (uint256 i6 = 10; i6 > i5; i6--)\n                i5++;\n    //forgefmt: disable-end\n}\n\nfunction callArgTest() {\n    //forgefmt: disable-start\n        target.run{ gas: gasleft(), value: 1 wei };\n\n        target.run{gas:1,value:0x00}();\n\n        target.run{\n                gas : 1000,\n        value: 1 ether\n        } ();\n\n        target.run{  gas: estimate(),\n    value: value(1) }();\n\n        target.run { value:\n        value(1 ether), gas: veryAndVeryLongNameOfSomeGasEstimateFunction() } ();\n\n        target.run /* comment 1 */ { value: /* comment2 */ 1 };\n\n        target.run { /* comment3 */ value: 1, // comment4\n        gas: gasleft()};\n\n        target.run {\n            // comment5\n            value: 1,\n            // comment6\n            gas: gasleft()};\n    //forgefmt: disable-end\n}\n\nfunction ifTest() {\n    // forgefmt: disable-start\n    if (condition)\n            execute();\n        else\n            executeElse();\n    // forgefmt: disable-end\n\n    /* forgefmt: disable-next-line */\n    if (condition   &&   anotherLongCondition ) {\n        execute();\n    }\n}\n\nfunction yulTest() {\n    // forgefmt: disable-start\n        assembly {\n            let payloadSize := sub(calldatasize(), 4)\n            calldatacopy(0, 4, payloadSize)\n            mstore(payloadSize, shl(96, caller()))\n\n            let result :=\n                delegatecall(gas(), moduleImpl, 0, add(payloadSize, 20), 0, 0)\n\n            returndatacopy(0, 0, returndatasize())\n\n            switch result\n            case 0 { revert(0, returndatasize()) }\n            default { return(0, returndatasize()) }\n        }\n    // forgefmt: disable-end\n}\n\nfunction literalTest() {\n    // forgefmt: disable-start\n\n        true;\n            0x123_456;\n        .1;\n    \"foobar\";\n            hex\"001122FF\";\n        0xc02aaa39b223Fe8D0A0e5C4F27ead9083c756Cc2;\n    // forgefmt: disable-end\n\n    // forgefmt: disable-next-line\n    bytes memory bytecode = hex\"ff\";\n}\n\nfunction returnTest() {\n    // forgefmt: disable-start\n        if (val == 0) {\n        return // return single 1\n        0x00;\n        }\n\n        if (val == 1) { return\n        1; }\n\n        if (val == 2) {\n                return 3\n                -\n                    1;\n        }\n\n        if (val == 4) {\n            /* return single 2 */ return 2** // return single 3\n            3 // return single 4\n            ;\n        }\n\n        return  value(); // return single 5\n            return  ;\n            return /* return mul 4 */\n            (\n                987654321, 1234567890,/* return mul 5 */ false);\n    // forgefmt: disable-end\n}\n\nfunction namedFuncCall() {\n    // forgefmt: disable-start\n        SimpleStruct memory simple = SimpleStruct({ val: 0 });\n\n        ComplexStruct memory complex = ComplexStruct({ val: 1, anotherVal: 2, flag: true, timestamp: block.timestamp });\n\n        StructWithAVeryLongNameThatExceedsMaximumLengthThatIsAllowedForFormatting memory long = StructWithAVeryLongNameThatExceedsMaximumLengthThatIsAllowedForFormatting({ whyNameSoLong: \"dunno\" });\n\n        SimpleStruct memory simple2 = SimpleStruct(\n    { // comment1\n        /* comment2 */ val : /* comment3 */ 0\n\n    }\n        );\n    // forgefmt: disable-end\n}\n\nfunction revertTest() {\n    // forgefmt: disable-start\n        revert ({ });\n\n        revert EmptyError({});\n\n        revert SimpleError({ val: 0 });\n\n        revert ComplexError(\n            {\n                val: 0,\n                    ts: block.timestamp,\n                        message: \"some reason\"\n            });\n\n        revert SomeVeryVeryVeryLongErrorNameWithNamedArgumentsThatExceedsMaximumLength({ val: 0, ts: 0x00, message: \"something unpredictable happened that caused execution to revert\"});\n\n        revert // comment1\n        ({});\n    // forgefmt: disable-end\n}\n\nfunction testTernary() {\n    // forgefmt: disable-start\n        bool condition;\n        bool someVeryVeryLongConditionUsedInTheTernaryExpression;\n\n        condition ? 0 : 1;\n\n        someVeryVeryLongConditionUsedInTheTernaryExpression ? 1234567890 : 987654321;\n\n        condition /* comment1 */ ? /* comment2 */ 1001 /* comment3 */ : /* comment4 */ 2002;\n\n        // comment5\n        someVeryVeryLongConditionUsedInTheTernaryExpression ? 1\n        // comment6\n        :\n        // comment7\n        0; // comment8\n    // forgefmt: disable-end\n}\n\nfunction thisTest() {\n    // forgefmt: disable-start\n        this.someFunc();\n        this.someVeryVeryVeryLongVariableNameThatWillBeAccessedByThisKeyword();\n        this // comment1\n            .someVeryVeryVeryLongVariableNameThatWillBeAccessedByThisKeyword();\n        address(this).balance;\n\n        address thisAddress = address(\n            // comment2\n             /* comment3 */ this // comment 4\n        );\n    // forgefmt: disable-end\n}\n\nfunction tryTest() {\n    // forgefmt: disable-start\n        try unknown.empty() {} catch {}\n\n        try unknown.lookup() returns (uint256) {} catch Error(string memory) {}\n\n        try unknown.lookup() returns (uint256) {} catch Error(string memory) {} catch (bytes memory) {}\n\n    try unknown\n        .lookup() returns   (uint256\n                ) {\n                } catch ( bytes  memory ){}\n\n        try unknown.empty() {\n            unknown.doSomething();\n        } catch {\n            unknown.handleError();\n        }\n\n        try unknown.empty() {\n            unknown.doSomething();\n        } catch Error(string memory) {}\n        catch Panic(uint) {}\n        catch {\n            unknown.handleError();\n        }\n\n        try unknown.lookupMultipleValues() returns (uint256, uint256, uint256, uint256, uint256) {} catch Error(string memory) {} catch {}\n\n        try unknown.lookupMultipleValues() returns (uint256, uint256, uint256, uint256, uint256) {\n            unknown.doSomething();\n        }\n        catch Error(string memory) {\n             unknown.handleError();\n        }\n        catch {}\n    // forgefmt: disable-end\n}\n\nfunction testArray() {\n    // forgefmt: disable-start\n        msg.data[\n            // comment1\n            4:];\n        msg.data[\n            : /* comment2 */ msg.data.length // comment3\n            ];\n        msg.data[\n        // comment4\n        4 // comment5\n        :msg.data.length /* comment6 */];\n    // forgefmt: disable-end\n}\n\nfunction testUnit() {\n    // forgefmt: disable-start\n        uint256 timestamp;\n        timestamp = 1 seconds;\n        timestamp = 1 minutes;\n        timestamp = 1 hours;\n        timestamp = 1 days;\n        timestamp = 1 weeks;\n\n        uint256 value;\n        value = 1 wei;\n        value = 1 gwei;\n        value = 1 ether;\n\n        uint256 someVeryVeryVeryLongVariableNameForTheMultiplierForEtherValue;\n\n        value =  someVeryVeryVeryLongVariableNameForTheMultiplierForEtherValue * 1 /* comment1 */ ether; // comment2\n\n        value = 1 // comment3\n        // comment4\n        ether; // comment5\n    // forgefmt: disable-end\n}\n\ncontract UsingExampleContract {\n    // forgefmt: disable-start\n    using  UsingExampleLibrary      for   *  ;\n        using UsingExampleLibrary for uint;\n    using Example.UsingExampleLibrary  for  uint;\n            using { M.g, M.f} for uint;\n    using UsingExampleLibrary for   uint  global;\n    using { These, Are, MultipleLibraries, ThatNeedToBePut, OnSeparateLines } for uint;\n    using { This.isareally.longmember.access.expression.that.needs.to.besplit.into.lines } for uint;\n    // forgefmt: disable-end\n}\n\nfunction testAssignment() {\n    // forgefmt: disable-start\n        (, uint256 second) = (1, 2);\n        (uint256 listItem001) = 1;\n        (uint256 listItem002, uint256 listItem003) = (10, 20);\n        (uint256 listItem004, uint256 listItem005, uint256 listItem006) =\n            (10, 20, 30);\n    // forgefmt: disable-end\n}\n\nfunction testWhile() {\n    // forgefmt: disable-start\n        uint256 i1;\n            while (  i1 <  10 ) {\n            i1++;\n        }\n\n        while (i1<10) i1++;\n\n        while (i1<10)\n            while (i1<10)\n                i1++;\n\n         uint256 i2;\n        while ( i2   < 10) { i2++; }\n\n        uint256 i3; while (\n            i3 < 10\n        ) { i3++; }\n\n        uint256 i4; while (i4 < 10)\n\n        { i4 ++ ;}\n\n        uint256 someLongVariableName;\n        while (\n            someLongVariableName < 10 && someLongVariableName < 11 && someLongVariableName < 12\n        ) { someLongVariableName ++; } someLongVariableName++;\n    // forgefmt: disable-end\n}\n\nfunction testLine() {}\nfunction   /* forgefmt: disable-line */ testLine(   ) { }\nfunction testLine() {}\nfunction   testLine(   ) { }  // forgefmt: disable-line\n\n// forgefmt: disable-start\n\n    type Hello is uint256;\n\nerror\n  TopLevelCustomError();\n  error TopLevelCustomErrorWithArg(uint    x)  ;\nerror TopLevelCustomErrorArgWithoutName  (string);\n\n    event Event1(uint256 indexed a, uint256 indexed a, uint256 indexed a, uint256 indexed a, uint256 indexed a, uint256 indexed a, uint256 indexed a, uint256 indexed a, uint256 indexed a, uint256 indexed a);\n\n// forgefmt: disable-end\n\nfunction setNumber(uint256 newNumber /* param1 */, uint256 sjdfasdfasdfasdfasfsdfsadfasdfasdfasdfsadjfkhasdfljkahsdfkjasdkfhsaf /* param2 */) public view returns (bool,bool) { /* inline*/ number1 = newNumber1; // forgefmt: disable-line\n    number = newNumber;\n    return (true, true);\n}\n\nfunction setNumber1(uint256 newNumber /* param1 */, uint256 sjdfasdfasdfasdfasfsdfsadfasdfasdfasdfsadjfkhasdfljkahsdfkjasdkfhsaf /* param2 */) public view returns (bool,bool) { /* inline*/ number1 = newNumber1; // forgefmt: disable-line\n}\n\n// forgefmt: disable-next-line\nfunction setNumber1(uint256 newNumber , uint256 sjdfasdfasdfasdfasfsdfsadfasdfasdfasdfsadjfkhasdfljkahsdfkjasdkfhsaf) public view returns (bool,bool) { number1 = newNumber1;\n}\n\nfunction setNumber(uint256 newNumber, uint256 sjdfasdfasdfasdfasfsdfsadfasdfasdfasdfsadjfkhasdfljkahsdfkjasdkfhsaf) public { // forgefmt: disable-line\n    number = newNumber;\n    number1 =   newNumber1; // forgefmt: disable-line\n}\n"
  },
  {
    "path": "crates/fmt/testdata/InlineDisable/original.sol",
    "content": "pragma    solidity     ^0.5.2;\n\n// forgefmt: disable-next-line\npragma    solidity     ^0.5.2;\n\nimport {symbol1 as alias1, symbol2 as alias2, symbol3 as alias3, symbol4} from 'File2.sol';\n\n// forgefmt: disable-next-line\nimport {symbol1 as alias1, symbol2 as alias2, symbol3 as alias3, symbol4} from 'File2.sol';\n\nenum States { State1, State2, State3, State4, State5, State6, State7, State8, State9 }\n\n// forgefmt: disable-next-line\nenum States { State1, State2, State3, State4, State5, State6, State7, State8, State9 }\n\n// forgefmt: disable-next-line\nbytes32 constant BYTES = 0x035aff83d86937d35b32e04f0ddc6ff469290eef2f1b692d8a815c89404d4749;\n\n// forgefmt: disable-start\n\n// comment1\n\n\n// comment2\n/* comment 3 */ /*\n    comment4\n     */ // comment 5\n\n\n/// Doccomment 1\n    /// Doccomment 2\n\n/**\n     * docccoment 3\n  */\n\n\n// forgefmt: disable-end\n\n// forgefmt: disable-start\n\nfunction test1() {}\n\nfunction test2() {}\n\n// forgefmt: disable-end\n\ncontract Constructors is Ownable, Changeable {\n    //forgefmt: disable-next-item\n    function Constructors(variable1) public Changeable(variable1) Ownable() onlyOwner {\n    }\n\n    //forgefmt: disable-next-item\n    constructor(variable1, variable2, variable3, variable4, variable5, variable6, variable7) public Changeable(variable1, variable2, variable3, variable4, variable5, variable6, variable7) Ownable() onlyOwner {}\n}\n\nfunction test() {\n    uint256 pi_approx = 666    /    212;\n    uint256 pi_approx = /* forgefmt: disable-start */ 666    /    212; /* forgefmt: disable-end */\n\n    // forgefmt: disable-next-item\n    uint256 pi_approx = 666 /\n        212;\n\n    uint256 test_postfix = 1; // forgefmt: disable-start\n                              // comment1\n                              // comment2\n                              // comment3\n                              // forgefmt: disable-end\n}\n\n// forgefmt: disable-next-item\nfunction testFunc(uint256   num, bytes32 data  ,    address receiver)\n    public payable    attr1   Cool( \"hello\"   ) {}\n\nfunction testAttrs(uint256   num, bytes32 data  ,    address receiver)\n    // forgefmt: disable-next-line\n    public payable    attr1   Cool( \"hello\"   ) {}\n\n// forgefmt: disable-next-line\nfunction testParams(uint256   num, bytes32 data  ,    address receiver)\n    public payable    attr1   Cool( \"hello\"   ) {}\n\n\nfunction testDoWhile() external {\n    //forgefmt: disable-start\n    uint256 i;\n    do { \"test\"; } while (i != 0);\n\n    do\n    {}\n    while\n    (\ni != 0);\n\n    bool someVeryVeryLongCondition;\n    do { \"test\"; } while(\n        someVeryVeryLongCondition && !someVeryVeryLongCondition &&\n!someVeryVeryLongCondition &&\nsomeVeryVeryLongCondition);\n\n    do i++; while(i < 10);\n\n    do do i++; while (i < 30); while(i < 20);\n    //forgefmt: disable-end\n}\n\nfunction forStatement() {\n    //forgefmt: disable-start\n        for\n    (uint256 i1\n        ; i1 < 10;      i1++)\n    {\n             i1++;\n            }\n\n        uint256 i2;\n        for(++i2;i2<10;i2++)\n\n        {}\n\n        uint256 veryLongVariableName = 1000;\n        for ( uint256 i3; i3 < 10\n        && veryLongVariableName>999 &&      veryLongVariableName< 1001\n        ; i3++)\n        { i3 ++ ; }\n\n        for (type(uint256).min;;) {}\n\n        for (;;) { \"test\" ; }\n\n        for (uint256 i4; i4< 10; i4++) i4++;\n\n        for (uint256 i5; ;)\n            for (uint256 i6 = 10; i6 > i5; i6--)\n                i5++;\n    //forgefmt: disable-end\n}\n\nfunction callArgTest() {\n    //forgefmt: disable-start\n        target.run{ gas: gasleft(), value: 1 wei };\n\n        target.run{gas:1,value:0x00}();\n\n        target.run{\n                gas : 1000,\n        value: 1 ether\n        } ();\n\n        target.run{  gas: estimate(),\n    value: value(1) }();\n\n        target.run { value:\n        value(1 ether), gas: veryAndVeryLongNameOfSomeGasEstimateFunction() } ();\n\n        target.run /* comment 1 */ { value: /* comment2 */ 1 };\n\n        target.run { /* comment3 */ value: 1, // comment4\n        gas: gasleft()};\n\n        target.run {\n            // comment5\n            value: 1,\n            // comment6\n            gas: gasleft()};\n    //forgefmt: disable-end\n}\n\nfunction ifTest() {\n    // forgefmt: disable-start\n    if (condition)\n            execute();\n        else\n            executeElse();\n    // forgefmt: disable-end\n\n    /* forgefmt: disable-next-line */\n    if (condition   &&   anotherLongCondition ) {\n            execute(); }\n}\n\nfunction yulTest() {\n    // forgefmt: disable-start\n        assembly {\n            let payloadSize := sub(calldatasize(), 4)\n            calldatacopy(0, 4, payloadSize)\n            mstore(payloadSize, shl(96, caller()))\n\n            let result :=\n                delegatecall(gas(), moduleImpl, 0, add(payloadSize, 20), 0, 0)\n\n            returndatacopy(0, 0, returndatasize())\n\n            switch result\n            case 0 { revert(0, returndatasize()) }\n            default { return(0, returndatasize()) }\n        }\n    // forgefmt: disable-end\n}\n\nfunction literalTest() {\n    // forgefmt: disable-start\n\n        true;\n            0x123_456;\n        .1;\n    \"foobar\";\n            hex\"001122FF\";\n        0xc02aaa39b223Fe8D0A0e5C4F27ead9083c756Cc2;\n    // forgefmt: disable-end\n\n    // forgefmt: disable-next-line\n    bytes memory bytecode =\n        hex\"ff\";\n}\n\nfunction returnTest() {\n    // forgefmt: disable-start\n        if (val == 0) {\n        return // return single 1\n        0x00;\n        }\n\n        if (val == 1) { return\n        1; }\n\n        if (val == 2) {\n                return 3\n                -\n                    1;\n        }\n\n        if (val == 4) {\n            /* return single 2 */ return 2** // return single 3\n            3 // return single 4\n            ;\n        }\n\n        return  value(); // return single 5\n            return  ;\n            return /* return mul 4 */\n            (\n                987654321, 1234567890,/* return mul 5 */ false);\n    // forgefmt: disable-end\n}\n\nfunction namedFuncCall() {\n    // forgefmt: disable-start\n        SimpleStruct memory simple = SimpleStruct({ val: 0 });\n\n        ComplexStruct memory complex = ComplexStruct({ val: 1, anotherVal: 2, flag: true, timestamp: block.timestamp });\n\n        StructWithAVeryLongNameThatExceedsMaximumLengthThatIsAllowedForFormatting memory long = StructWithAVeryLongNameThatExceedsMaximumLengthThatIsAllowedForFormatting({ whyNameSoLong: \"dunno\" });\n\n        SimpleStruct memory simple2 = SimpleStruct(\n    { // comment1\n        /* comment2 */ val : /* comment3 */ 0\n\n    }\n        );\n    // forgefmt: disable-end\n}\n\nfunction revertTest() {\n    // forgefmt: disable-start\n        revert ({ });\n\n        revert EmptyError({});\n\n        revert SimpleError({ val: 0 });\n\n        revert ComplexError(\n            {\n                val: 0,\n                    ts: block.timestamp,\n                        message: \"some reason\"\n            });\n\n        revert SomeVeryVeryVeryLongErrorNameWithNamedArgumentsThatExceedsMaximumLength({ val: 0, ts: 0x00, message: \"something unpredictable happened that caused execution to revert\"});\n\n        revert // comment1\n        ({});\n    // forgefmt: disable-end\n}\n\nfunction testTernary() {\n    // forgefmt: disable-start\n        bool condition;\n        bool someVeryVeryLongConditionUsedInTheTernaryExpression;\n\n        condition ? 0 : 1;\n\n        someVeryVeryLongConditionUsedInTheTernaryExpression ? 1234567890 : 987654321;\n\n        condition /* comment1 */ ? /* comment2 */ 1001 /* comment3 */ : /* comment4 */ 2002;\n\n        // comment5\n        someVeryVeryLongConditionUsedInTheTernaryExpression ? 1\n        // comment6\n        :\n        // comment7\n        0; // comment8\n    // forgefmt: disable-end\n}\n\nfunction thisTest() {\n    // forgefmt: disable-start\n        this.someFunc();\n        this.someVeryVeryVeryLongVariableNameThatWillBeAccessedByThisKeyword();\n        this // comment1\n            .someVeryVeryVeryLongVariableNameThatWillBeAccessedByThisKeyword();\n        address(this).balance;\n\n        address thisAddress = address(\n            // comment2\n             /* comment3 */ this // comment 4\n        );\n    // forgefmt: disable-end\n}\n\nfunction tryTest() {\n    // forgefmt: disable-start\n        try unknown.empty() {} catch {}\n\n        try unknown.lookup() returns (uint256) {} catch Error(string memory) {}\n\n        try unknown.lookup() returns (uint256) {} catch Error(string memory) {} catch (bytes memory) {}\n\n    try unknown\n        .lookup() returns   (uint256\n                ) {\n                } catch ( bytes  memory ){}\n\n        try unknown.empty() {\n            unknown.doSomething();\n        } catch {\n            unknown.handleError();\n        }\n\n        try unknown.empty() {\n            unknown.doSomething();\n        } catch Error(string memory) {}\n        catch Panic(uint) {}\n        catch {\n            unknown.handleError();\n        }\n\n        try unknown.lookupMultipleValues() returns (uint256, uint256, uint256, uint256, uint256) {} catch Error(string memory) {} catch {}\n\n        try unknown.lookupMultipleValues() returns (uint256, uint256, uint256, uint256, uint256) {\n            unknown.doSomething();\n        }\n        catch Error(string memory) {\n             unknown.handleError();\n        }\n        catch {}\n    // forgefmt: disable-end\n}\n\nfunction testArray() {\n    // forgefmt: disable-start\n        msg.data[\n            // comment1\n            4:];\n        msg.data[\n            : /* comment2 */ msg.data.length // comment3\n            ];\n        msg.data[\n        // comment4\n        4 // comment5\n        :msg.data.length /* comment6 */];\n    // forgefmt: disable-end\n}\n\nfunction testUnit() {\n    // forgefmt: disable-start\n        uint256 timestamp;\n        timestamp = 1 seconds;\n        timestamp = 1 minutes;\n        timestamp = 1 hours;\n        timestamp = 1 days;\n        timestamp = 1 weeks;\n\n        uint256 value;\n        value = 1 wei;\n        value = 1 gwei;\n        value = 1 ether;\n\n        uint256 someVeryVeryVeryLongVariableNameForTheMultiplierForEtherValue;\n\n        value =  someVeryVeryVeryLongVariableNameForTheMultiplierForEtherValue * 1 /* comment1 */ ether; // comment2\n\n        value = 1 // comment3\n        // comment4\n        ether; // comment5\n    // forgefmt: disable-end\n}\n\ncontract UsingExampleContract {\n    // forgefmt: disable-start\n    using  UsingExampleLibrary      for   *  ;\n        using UsingExampleLibrary for uint;\n    using Example.UsingExampleLibrary  for  uint;\n            using { M.g, M.f} for uint;\n    using UsingExampleLibrary for   uint  global;\n    using { These, Are, MultipleLibraries, ThatNeedToBePut, OnSeparateLines } for uint;\n    using { This.isareally.longmember.access.expression.that.needs.to.besplit.into.lines } for uint;\n    // forgefmt: disable-end\n}\n\nfunction testAssignment() {\n    // forgefmt: disable-start\n        (, uint256 second) = (1, 2);\n        (uint256 listItem001) = 1;\n        (uint256 listItem002, uint256 listItem003) = (10, 20);\n        (uint256 listItem004, uint256 listItem005, uint256 listItem006) =\n            (10, 20, 30);\n    // forgefmt: disable-end\n}\n\nfunction testWhile() {\n    // forgefmt: disable-start\n        uint256 i1;\n            while (  i1 <  10 ) {\n            i1++;\n        }\n\n        while (i1<10) i1++;\n\n        while (i1<10)\n            while (i1<10)\n                i1++;\n\n         uint256 i2;\n        while ( i2   < 10) { i2++; }\n\n        uint256 i3; while (\n            i3 < 10\n        ) { i3++; }\n\n        uint256 i4; while (i4 < 10)\n\n        { i4 ++ ;}\n\n        uint256 someLongVariableName;\n        while (\n            someLongVariableName < 10 && someLongVariableName < 11 && someLongVariableName < 12\n        ) { someLongVariableName ++; } someLongVariableName++;\n    // forgefmt: disable-end\n}\n\nfunction   testLine(   ) { }\nfunction   /* forgefmt: disable-line */ testLine(   ) { }\nfunction   testLine(   ) { }\nfunction   testLine(   ) { }  // forgefmt: disable-line\n\n// forgefmt: disable-start\n\n    type Hello is uint256;\n\nerror\n  TopLevelCustomError();\n  error TopLevelCustomErrorWithArg(uint    x)  ;\nerror TopLevelCustomErrorArgWithoutName  (string);\n\n    event Event1(uint256 indexed a, uint256 indexed a, uint256 indexed a, uint256 indexed a, uint256 indexed a, uint256 indexed a, uint256 indexed a, uint256 indexed a, uint256 indexed a, uint256 indexed a);\n\n// forgefmt: disable-end\n\nfunction setNumber(uint256 newNumber /* param1 */, uint256 sjdfasdfasdfasdfasfsdfsadfasdfasdfasdfsadjfkhasdfljkahsdfkjasdkfhsaf /* param2 */) public view returns (bool,bool) { /* inline*/ number1 = newNumber1; // forgefmt: disable-line\n    number = newNumber;\n    return (true, true);\n}\n\nfunction setNumber1(uint256 newNumber /* param1 */, uint256 sjdfasdfasdfasdfasfsdfsadfasdfasdfasdfsadjfkhasdfljkahsdfkjasdkfhsaf /* param2 */) public view returns (bool,bool) { /* inline*/ number1 = newNumber1; // forgefmt: disable-line\n}\n\n// forgefmt: disable-next-line\nfunction setNumber1(uint256 newNumber , uint256 sjdfasdfasdfasdfasfsdfsadfasdfasdfasdfsadjfkhasdfljkahsdfkjasdkfhsaf) public view returns (bool,bool) { number1 = newNumber1;\n}\n\nfunction setNumber(uint256 newNumber, uint256 sjdfasdfasdfasdfasfsdfsadfasdfasdfasdfsadjfkhasdfljkahsdfkjasdkfhsaf) public { // forgefmt: disable-line\n    number = newNumber;\n    number1 =   newNumber1; // forgefmt: disable-line\n}\n"
  },
  {
    "path": "crates/fmt/testdata/IntTypes/fmt.sol",
    "content": "contract Contract {\n    uint256 constant UINT256_IMPL = 0;\n    uint8 constant UINT8 = 1;\n    uint128 constant UINT128 = 2;\n    uint256 constant UINT256_EXPL = 3;\n\n    int256 constant INT256_IMPL = 4;\n    int8 constant INT8 = 5;\n    int128 constant INT128 = 6;\n    int256 constant INT256_EXPL = 7;\n\n    function test(\n        uint256 uint256_impl,\n        uint8 uint8_var,\n        uint128 uint128_var,\n        uint256 uint256_expl,\n        int256 int256_impl,\n        int8 int8_var,\n        int128 int128_var,\n        int256 int256_expl\n    ) public {\n        // do something\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/IntTypes/original.sol",
    "content": "contract Contract {\n    uint constant UINT256_IMPL = 0;\n    uint8 constant UINT8 = 1;\n    uint128 constant UINT128 = 2;\n    uint256 constant UINT256_EXPL = 3;\n\n    int constant INT256_IMPL = 4;\n    int8 constant INT8 = 5;\n    int128 constant INT128 = 6;\n    int256 constant INT256_EXPL = 7;\n\n    function test(\n        uint uint256_impl,\n        uint8 uint8_var,\n        uint128 uint128_var,\n        uint256 uint256_expl,\n        int int256_impl,\n        int8 int8_var,\n        int128 int128_var,\n        int256 int256_expl\n    ) public {\n        // do something\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/IntTypes/preserve.fmt.sol",
    "content": "// config: int_types = \"preserve\"\ncontract Contract {\n    uint constant UINT256_IMPL = 0;\n    uint8 constant UINT8 = 1;\n    uint128 constant UINT128 = 2;\n    uint256 constant UINT256_EXPL = 3;\n\n    int constant INT256_IMPL = 4;\n    int8 constant INT8 = 5;\n    int128 constant INT128 = 6;\n    int256 constant INT256_EXPL = 7;\n\n    function test(\n        uint uint256_impl,\n        uint8 uint8_var,\n        uint128 uint128_var,\n        uint256 uint256_expl,\n        int int256_impl,\n        int8 int8_var,\n        int128 int128_var,\n        int256 int256_expl\n    ) public {\n        // do something\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/IntTypes/short.fmt.sol",
    "content": "// config: int_types = \"short\"\ncontract Contract {\n    uint constant UINT256_IMPL = 0;\n    uint8 constant UINT8 = 1;\n    uint128 constant UINT128 = 2;\n    uint constant UINT256_EXPL = 3;\n\n    int constant INT256_IMPL = 4;\n    int8 constant INT8 = 5;\n    int128 constant INT128 = 6;\n    int constant INT256_EXPL = 7;\n\n    function test(\n        uint uint256_impl,\n        uint8 uint8_var,\n        uint128 uint128_var,\n        uint uint256_expl,\n        int int256_impl,\n        int8 int8_var,\n        int128 int128_var,\n        int int256_expl\n    ) public {\n        // do something\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/LiteralExpression/fmt.sol",
    "content": "contract LiteralExpressions {\n    function test() external {\n        // bool literals\n        true;\n        false;\n        /* comment1 */\n        true; /* comment2 */\n        // comment3\n        false; // comment4\n\n        // number literals\n        1;\n        123_000;\n        // 1_2e345_678;\n        -1;\n        2e-10;\n        // comment5\n        /* comment6 */\n        -1; /* comment7 */\n\n        // hex number literals\n        0x00;\n        0x123_456;\n        0x2eff_abde;\n        address(0xCAFE);\n        address(0xBEEF);\n\n        // rational number literals\n        0.1;\n        1.3;\n        2.5e1;\n\n        // string literals\n        \"\";\n        \"foobar\";\n        \"foo\" // comment8\n        \" bar\";\n        // comment9\n        \"\\\nsome words\"; /* comment10 */\n        unicode\"Hello 😃\";\n\n        // quoted strings\n        'hello \"world\"';\n        \"hello 'world'\";\n        \"hello \\'world\\'\";\n        \"hello \\\"world\\\"\";\n        \"hello \\\"world\\\"\";\n        \"hello \\'world\\'\";\n\n        // hex literals\n        hex\"001122FF\";\n        hex\"001122FF\";\n        hex\"00112233\" hex\"44556677\";\n\n        // address literals\n        0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;\n        // non checksummed address\n        0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/LiteralExpression/original.sol",
    "content": "contract LiteralExpressions {\n    function test() external {\n        // bool literals\n        true;\n        false;\n        /* comment1 */ true /* comment2 */;\n        // comment3\n        false; // comment4\n\n        // number literals\n        1;\n        123_000;\n        // 1_2e345_678;\n        -1;\n        2e-10;\n        // comment5\n        /* comment6 */ -1 /* comment7 */;\n\n        // hex number literals\n        0x00;\n        0x123_456;\n        0x2eff_abde;\n        address(0xCAFE);\n        address(0xBEEF);\n\n        // rational number literals\n        .1;\n        1.3;\n        2.5e1;\n\n        // string literals\n        \"\";\n        \"foobar\";\n        \"foo\" // comment8\n            \" bar\";\n        // comment9\n        \"\\\nsome words\" /* comment10 */;\n        unicode\"Hello 😃\";\n\n        // quoted strings\n        'hello \"world\"';\n        \"hello 'world'\";\n        'hello \\'world\\'';\n        \"hello \\\"world\\\"\";\n        'hello \\\"world\\\"';\n        \"hello \\'world\\'\";\n\n\n        // hex literals\n        hex\"001122FF\";\n        hex'0011_22_FF';\n        hex\"00112233\" hex\"44556677\";\n\n        // address literals\n        0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;\n        // non checksummed address\n        0xc02aaa39b223Fe8D0A0e5C4F27ead9083c756Cc2;\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/LiteralExpression/preserve-quote.fmt.sol",
    "content": "// config: quote_style = \"preserve\"\ncontract LiteralExpressions {\n    function test() external {\n        // bool literals\n        true;\n        false;\n        /* comment1 */\n        true; /* comment2 */\n        // comment3\n        false; // comment4\n\n        // number literals\n        1;\n        123_000;\n        // 1_2e345_678;\n        -1;\n        2e-10;\n        // comment5\n        /* comment6 */\n        -1; /* comment7 */\n\n        // hex number literals\n        0x00;\n        0x123_456;\n        0x2eff_abde;\n        address(0xCAFE);\n        address(0xBEEF);\n\n        // rational number literals\n        0.1;\n        1.3;\n        2.5e1;\n\n        // string literals\n        \"\";\n        \"foobar\";\n        \"foo\" // comment8\n        \" bar\";\n        // comment9\n        \"\\\nsome words\"; /* comment10 */\n        unicode\"Hello 😃\";\n\n        // quoted strings\n        'hello \"world\"';\n        \"hello 'world'\";\n        'hello \\'world\\'';\n        \"hello \\\"world\\\"\";\n        'hello \\\"world\\\"';\n        \"hello \\'world\\'\";\n\n        // hex literals\n        hex\"001122FF\";\n        hex'001122FF';\n        hex\"00112233\" hex\"44556677\";\n\n        // address literals\n        0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;\n        // non checksummed address\n        0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/LiteralExpression/single-quote.fmt.sol",
    "content": "// config: quote_style = \"single\"\ncontract LiteralExpressions {\n    function test() external {\n        // bool literals\n        true;\n        false;\n        /* comment1 */\n        true; /* comment2 */\n        // comment3\n        false; // comment4\n\n        // number literals\n        1;\n        123_000;\n        // 1_2e345_678;\n        -1;\n        2e-10;\n        // comment5\n        /* comment6 */\n        -1; /* comment7 */\n\n        // hex number literals\n        0x00;\n        0x123_456;\n        0x2eff_abde;\n        address(0xCAFE);\n        address(0xBEEF);\n\n        // rational number literals\n        0.1;\n        1.3;\n        2.5e1;\n\n        // string literals\n        '';\n        'foobar';\n        'foo' // comment8\n        ' bar';\n        // comment9\n        '\\\nsome words'; /* comment10 */\n        unicode'Hello 😃';\n\n        // quoted strings\n        'hello \"world\"';\n        \"hello 'world'\";\n        'hello \\'world\\'';\n        'hello \\\"world\\\"';\n        'hello \\\"world\\\"';\n        'hello \\'world\\'';\n\n        // hex literals\n        hex'001122FF';\n        hex'001122FF';\n        hex'00112233' hex'44556677';\n\n        // address literals\n        0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;\n        // non checksummed address\n        0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/MappingType/fmt.sol",
    "content": "// config: line_length = 40\ncontract X {\n    type Y is bytes32;\n}\n\ntype SomeVeryLongTypeName is uint256;\n\ncontract Mapping {\n    mapping(uint256 => X.Y) mapping1;\n    mapping(\n        uint256 key => uint256 value\n    ) mapping2;\n    mapping(\n        uint256 veryLongKeyName\n            => uint256 veryLongValueName\n    ) mapping3;\n    mapping(\n        string anotherVeryLongKeyName\n            => uint256 anotherVeryLongValueName\n    ) mapping4;\n    mapping(\n        SomeVeryLongTypeName anotherVeryLongKeyName\n            => uint256 anotherVeryLongValueName\n    ) mapping5;\n\n    mapping(\n        // comment1\n        uint256 key => uint256 value\n        // comment2\n    ) mapping6;\n    mapping( /* comment3 */\n        uint256 /* comment4 */ key /* comment5 */ /* comment6 */\n            => uint256 /* comment7 */ value /* comment8 */ /* comment9 */\n    ) /* comment10 */ mapping7;\n}\n"
  },
  {
    "path": "crates/fmt/testdata/MappingType/original.sol",
    "content": "contract X {\n    type Y is bytes32;\n}\n\ntype SomeVeryLongTypeName is uint256;\n\ncontract Mapping {\n    mapping(uint256 => X.Y) mapping1;\n    mapping(uint256 key => uint256 value) mapping2;\n    mapping(uint256 veryLongKeyName => uint256 veryLongValueName) mapping3;\n    mapping(string anotherVeryLongKeyName => uint256 anotherVeryLongValueName) mapping4;\n    mapping(SomeVeryLongTypeName anotherVeryLongKeyName => uint256 anotherVeryLongValueName) mapping5;\n\n    mapping(\n            \n            // comment1\n    uint256 key => uint256 value\n// comment2\n    ) mapping6;\n    mapping( /* comment3 */\n        uint256 /* comment4 */ key /* comment5 */ => /* comment6 */ uint256 /* comment7 */ value /* comment8 */ /* comment9 */\n    )  /* comment10 */ mapping7;\n}"
  },
  {
    "path": "crates/fmt/testdata/ModifierDefinition/fmt.sol",
    "content": "// config: line_length = 60\ncontract ModifierDefinitions {\n    modifier noParams() {}\n    modifier oneParam(uint256 a) {}\n    modifier twoParams(uint256 a, uint256 b) {}\n    modifier threeParams(uint256 a, uint256 b, uint256 c) {}\n    modifier fourParams(\n        uint256 a,\n        uint256 b,\n        uint256 c,\n        uint256 d\n    ) {}\n    modifier overridden() override(Base1, Base2) {}\n}\n"
  },
  {
    "path": "crates/fmt/testdata/ModifierDefinition/original.sol",
    "content": "contract ModifierDefinitions {\n    modifier noParams() {}\n    modifier oneParam(uint a) {}\n    modifier twoParams(uint a,uint b) {}\n    modifier threeParams(uint a,uint b   ,uint c) {}\n    modifier fourParams(uint a,uint b   ,uint c, uint d) {}\n    modifier overridden (\n    ) override ( Base1 , Base2) {}\n}\n"
  },
  {
    "path": "crates/fmt/testdata/ModifierDefinition/override-spacing.fmt.sol",
    "content": "// config: line_length = 60\n// config: override_spacing = true\ncontract ModifierDefinitions {\n    modifier noParams() {}\n    modifier oneParam(uint256 a) {}\n    modifier twoParams(uint256 a, uint256 b) {}\n    modifier threeParams(uint256 a, uint256 b, uint256 c) {}\n    modifier fourParams(\n        uint256 a,\n        uint256 b,\n        uint256 c,\n        uint256 d\n    ) {}\n    modifier overridden() override (Base1, Base2) {}\n}\n"
  },
  {
    "path": "crates/fmt/testdata/NamedFunctionCallExpression/fmt.sol",
    "content": "// config: prefer_compact = \"events_errors\"\ncontract NamedFunctionCallExpression {\n    struct SimpleStruct {\n        uint256 val;\n    }\n\n    struct ComplexStruct {\n        uint256 val;\n        uint256 anotherVal;\n        bool flag;\n        uint256 timestamp;\n    }\n\n    struct\n        StructWithAVeryLongNameThatExceedsMaximumLengthThatIsAllowedForFormatting {\n            string whyNameSoLong;\n        }\n\n    function test() external {\n        SimpleStruct memory simple = SimpleStruct({val: 0});\n\n        ComplexStruct memory complex = ComplexStruct({\n            val: 1,\n            anotherVal: 2,\n            flag: true,\n            timestamp: block.timestamp\n        });\n\n        StructWithAVeryLongNameThatExceedsMaximumLengthThatIsAllowedForFormatting\n            memory\n            long = StructWithAVeryLongNameThatExceedsMaximumLengthThatIsAllowedForFormatting({\n                whyNameSoLong: \"dunno\"\n            });\n\n        SimpleStruct memory simple2 = SimpleStruct({ // comment1\n            /* comment2 */ val: /* comment3 */ 0\n        });\n\n        SimpleStruct memory simple3 = SimpleStruct({ /* comment4 */\n            // comment5\n            val: // comment6\n            0 // comment7\n            // comment8\n        });\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/NamedFunctionCallExpression/original.sol",
    "content": "contract NamedFunctionCallExpression {\n    struct SimpleStruct { uint256 val; }\n    struct ComplexStruct { uint256 val; uint256 anotherVal; bool flag; uint256 timestamp; }\n    struct StructWithAVeryLongNameThatExceedsMaximumLengthThatIsAllowedForFormatting { string whyNameSoLong; }\n\n    function test() external {\n        SimpleStruct memory simple = SimpleStruct({ val: 0 });\n\n        ComplexStruct memory complex = ComplexStruct({ val: 1, anotherVal: 2, flag: true, timestamp: block.timestamp });\n\n        StructWithAVeryLongNameThatExceedsMaximumLengthThatIsAllowedForFormatting memory long = StructWithAVeryLongNameThatExceedsMaximumLengthThatIsAllowedForFormatting({ whyNameSoLong: \"dunno\" });\n\n        SimpleStruct memory simple2 = SimpleStruct(\n    { // comment1\n        /* comment2 */ val : /* comment3 */ 0\n\n    }\n        );\n\n        SimpleStruct memory simple3 = SimpleStruct(\n            /* comment4 */  {\n                // comment5\n                val: // comment6\n                    0 // comment7\n                    // comment8\n        });\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/NonKeywords/fmt.sol",
    "content": "struct S {\n    uint256 error;\n    uint256 layout;\n    uint256 at;\n    // uint256 transient;\n}\n\nfunction f() {\n    uint256 error = 0;\n    uint256 layout = 0;\n    uint256 at = 0;\n    // uint256 transient = 0;\n\n    error = 0;\n    // layout = 0;\n    at = 0;\n    // transient = 0;\n\n    S memory x = S({\n        // format\n        error: 0,\n        layout: 0,\n        at: 0\n        // transient: 0\n    });\n\n    x.error = 0;\n    x.layout = 0;\n    x.at = 0;\n    // x.transient = 0;\n\n    assembly {\n        let error := 0\n        let layout := 0\n        let at := 0\n        // let transient := 0\n\n        error := 0\n        layout := 0\n        at := 0\n        // transient := 0\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/NonKeywords/original.sol",
    "content": "struct S {\n    uint256 error;\n    uint256 layout;\n    uint256 at;\n    // uint256 transient;\n}\n\nfunction f() {\n    uint256 error = 0;\n    uint256 layout = 0;\n    uint256 at = 0;\n    // uint256 transient = 0;\n\n    error = 0;\n    // layout = 0;\n    at = 0;\n    // transient = 0;\n\n    S memory x = S({\n        // format\n        error: 0,\n        layout: 0,\n        at: 0\n        // transient: 0\n    });\n\n    x.error = 0;\n    x.layout = 0;\n    x.at = 0;\n    // x.transient = 0;\n\n    assembly {\n        let error := 0\n        let layout := 0\n        let at := 0\n        // let transient := 0\n\n        error := 0\n        layout := 0\n        at := 0\n        // transient := 0\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/NumberLiteralUnderscore/fmt.sol",
    "content": "contract NumberLiteral {\n    bytes4 internal constant HEX_NUM = 0x01ffc9a7;\n\n    function test() external {\n        1;\n        123_000;\n        // 1_2e345_678; // solar error: exponent too large\n        -1;\n        2e-10;\n        0.1;\n        1.3;\n        2.5e1;\n        1.23454;\n        // 1.2e34_5_678; // solar error: exponent too large\n        // 134411.2e34_5_678; // solar error: exponent too large\n        // 13431.134112e34_135_678; // solar error: exponent too large\n        13431.0134112;\n        // 13431.134112e-139_3141340; // solar error: exponent too large\n        // 00134411.200e0034_5_6780; // solar error: leading zeros are not allowed in integers\n        // 013431.13411200e34_135_6780; // solar error: leading zeros are not allowed in integers\n        // 00.1341120000; // solar error: leading zeros are not allowed in integers\n        1.0;\n        // 0013431.13411200e-00139_3141340; // solar error: leading zeros are not allowed in integers\n        10_234e56;\n        1234e56;\n        10000;\n        1_000;\n        5_267.8268764263694426e18;\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/NumberLiteralUnderscore/original.sol",
    "content": "contract NumberLiteral {\n    bytes4 internal constant HEX_NUM = 0x01ffc9a7;\n\n    function test() external {\n        1;\n        123_000;\n        // 1_2e345_678; // solar error: exponent too large\n        -1;\n        2e-10;\n        .1;\n        1.3;\n        2.5e1;\n        1.23454e0;\n        // 1.2e34_5_678; // solar error: exponent too large\n        // 134411.2e34_5_678; // solar error: exponent too large\n        // 13431.134112e34_135_678; // solar error: exponent too large\n        13431.0134112;\n        // 13431.134112e-139_3141340; // solar error: exponent too large\n        // 00134411.200e0034_5_6780; // solar error: leading zeros are not allowed in integers\n        // 013431.13411200e34_135_6780; // solar error: leading zeros are not allowed in integers\n        // 00.1341120000; // solar error: leading zeros are not allowed in integers\n        1.0000;\n        // 0013431.13411200e-00139_3141340; // solar error: leading zeros are not allowed in integers\n        10_234E56;\n        1234E56;\n        10000;\n        1_000;\n        5_267.8268764263694426e18;\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/NumberLiteralUnderscore/preserve.fmt.sol",
    "content": "// config: number_underscore = \"preserve\"\ncontract NumberLiteral {\n    bytes4 internal constant HEX_NUM = 0x01ffc9a7;\n\n    function test() external {\n        1;\n        123_000;\n        // 1_2e345_678; // solar error: exponent too large\n        -1;\n        2e-10;\n        0.1;\n        1.3;\n        2.5e1;\n        1.23454;\n        // 1.2e34_5_678; // solar error: exponent too large\n        // 134411.2e34_5_678; // solar error: exponent too large\n        // 13431.134112e34_135_678; // solar error: exponent too large\n        13431.0134112;\n        // 13431.134112e-139_3141340; // solar error: exponent too large\n        // 00134411.200e0034_5_6780; // solar error: leading zeros are not allowed in integers\n        // 013431.13411200e34_135_6780; // solar error: leading zeros are not allowed in integers\n        // 00.1341120000; // solar error: leading zeros are not allowed in integers\n        1.0;\n        // 0013431.13411200e-00139_3141340; // solar error: leading zeros are not allowed in integers\n        10_234e56;\n        1234e56;\n        10000;\n        1_000;\n        5_267.8268764263694426e18;\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/NumberLiteralUnderscore/remove.fmt.sol",
    "content": "// config: number_underscore = \"remove\"\ncontract NumberLiteral {\n    bytes4 internal constant HEX_NUM = 0x01ffc9a7;\n\n    function test() external {\n        1;\n        123000;\n        // 1_2e345_678; // solar error: exponent too large\n        -1;\n        2e-10;\n        0.1;\n        1.3;\n        2.5e1;\n        1.23454;\n        // 1.2e34_5_678; // solar error: exponent too large\n        // 134411.2e34_5_678; // solar error: exponent too large\n        // 13431.134112e34_135_678; // solar error: exponent too large\n        13431.0134112;\n        // 13431.134112e-139_3141340; // solar error: exponent too large\n        // 00134411.200e0034_5_6780; // solar error: leading zeros are not allowed in integers\n        // 013431.13411200e34_135_6780; // solar error: leading zeros are not allowed in integers\n        // 00.1341120000; // solar error: leading zeros are not allowed in integers\n        1.0;\n        // 0013431.13411200e-00139_3141340; // solar error: leading zeros are not allowed in integers\n        10234e56;\n        1234e56;\n        10000;\n        1000;\n        5267.8268764263694426e18;\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/NumberLiteralUnderscore/thousands.fmt.sol",
    "content": "// config: number_underscore = \"thousands\"\ncontract NumberLiteral {\n    bytes4 internal constant HEX_NUM = 0x01ffc9a7;\n\n    function test() external {\n        1;\n        123_000;\n        // 1_2e345_678; // solar error: exponent too large\n        -1;\n        2e-10;\n        0.1;\n        1.3;\n        2.5e1;\n        1.234_54;\n        // 1.2e34_5_678; // solar error: exponent too large\n        // 134411.2e34_5_678; // solar error: exponent too large\n        // 13431.134112e34_135_678; // solar error: exponent too large\n        13_431.013_411_2;\n        // 13431.134112e-139_3141340; // solar error: exponent too large\n        // 00134411.200e0034_5_6780; // solar error: leading zeros are not allowed in integers\n        // 013431.13411200e34_135_6780; // solar error: leading zeros are not allowed in integers\n        // 00.1341120000; // solar error: leading zeros are not allowed in integers\n        1.0;\n        // 0013431.13411200e-00139_3141340; // solar error: leading zeros are not allowed in integers\n        10_234e56;\n        1234e56;\n        10_000;\n        1000;\n        5267.8268764263694426e18;\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/OperatorExpressions/120.fmt.sol",
    "content": "// config: line_length = 120\nfunction test() {\n    uint256 expr001 = (1 + 2) + 3;\n    uint256 expr002 = 1 + (2 + 3);\n    uint256 expr003 = 1 * 2 + 3;\n    uint256 expr004 = (1 * 2) + 3;\n    uint256 expr005 = 1 * (2 + 3);\n    uint256 expr006 = 1 + 2 * 3;\n    uint256 expr007 = (1 + 2) * 3;\n    uint256 expr008 = 1 + (2 * 3);\n    uint256 expr009 = 1 ** 2 ** 3;\n    uint256 expr010 = 1 ** (2 ** 3);\n    uint256 expr011 = (1 ** 2) ** 3;\n    uint256 expr012 = ++expr011 + 1;\n    bool expr013 = ++expr012 == expr011 - 1;\n    bool expr014 = ++(++expr013)--;\n    if (++batch.movesPerformed == drivers.length) createNewBatch();\n    sum += getPrice(\n        ACCELERATE_STARTING_PRICE,\n        ACCELERATE_PER_PERIOD_DECREASE,\n        idleTicks,\n        actionsSold[ActionType.ACCELERATE] + i,\n        ACCELERATE_SELL_PER_TICK\n    ) / 1e18;\n    other += 1e18\n        / getPrice(\n            ACCELERATE_STARTING_PRICE,\n            ACCELERATE_PER_PERIOD_DECREASE,\n            idleTicks,\n            actionsSold[ActionType.ACCELERATE] + i,\n            ACCELERATE_SELL_PER_TICK\n        );\n    if (\n        op == 0x54 // SLOAD\n            || op == 0x55 // SSTORE\n            || op == 0xF0 // CREATE\n            || op == 0xF1 // CALL\n            || op == 0xF2 // CALLCODE\n            || op == 0xF4 // DELEGATECALL\n            || op == 0xF5 // CREATE2\n            || op == 0xFA // STATICCALL\n            || op == 0xFF // SELFDESTRUCT\n    ) return false;\n}\n\nfunction test_nested() {\n    require(\n        keccak256(abi.encodePacked(\"some long string\")) == keccak256(abi.encodePacked(\"some other long string\")),\n        \"string mismatch\"\n    );\n\n    state.zeroForOne =\n        IERC20(Currency.unwrap(state.poolKey1.currency0)) == IERC20(Currency.unwrap(state.poolKey0.curerncy1));\n\n    coreAddresses.evc == address(0) && coreAddresses.protocolConfig == address(0)\n        && coreAddresses.sequenceRegistry == address(0) && coreAddresses.balanceTracker == address(0)\n        && coreAddresses.permit2 == address(0);\n\n    return spender == ownerOf(tokenId) || getApproved[tokenId] == spender || isApprovedForAll[ownerOf(tokenId)][spender];\n}\n\nfunction new_y(uint256 x, uint256 dx, uint256 x_basis, uint256 y, uint256 y_basis) external pure returns (uint256) {\n    return _get_y(\n        x * _VELODROME_TOKEN_BASIS / x_basis,\n        dx * _VELODROME_TOKEN_BASIS / x_basis,\n        y * _VELODROME_TOKEN_BASIS / y_basis\n    ) * y_basis / _VELODROME_TOKEN_BASIS * aReallyLongIdentifierThatMakesTheOperatorExpressionBreak;\n}\n\ncontract Repro {\n    bytes4 public constant MINIMAL_INTERFACE_ID = this.calculateMinFeeWeiFor.selector ^ this.convertUSDFeeToWei.selector\n        ^ this.execute.selector ^ this.getMinFeeUSDFor.selector;\n    bool isTestnet = chainId == ARBITRUM_SEPOLIA || chainId == BASE_SEPOLIA || chainId == MODE_SEPOLIA\n        || chainId == OPTIMISM_SEPOLIA || chainId == SEPOLIA;\n\n    function test() {\n        assign = this.calculateMinFeeWeiFor.selector ^ this.convertUSDFeeToWei.selector ^ this.execute.selector\n            ^ this.getMinFeeUSDFor.selector;\n        isMainnet = chainId == ABSTRACT || chainId == ARBITRUM || chainId == AVALANCHE || chainId == BASE\n            || chainId == BERACHAIN || chainId == BLAST || chainId == BSC || chainId == CHILIZ || chainId == COREDAO\n            || chainId == ETHEREUM || chainId == GNOSIS || chainId == HYPEREVM || chainId == LIGHTLINK\n            || chainId == LINEA || chainId == MODE || chainId == MORPH || chainId == OPTIMISM || chainId == POLYGON\n            || chainId == SCROLL || chainId == SEI || chainId == SOPHON || chainId == SUPERSEED || chainId == SONIC\n            || chainId == UNICHAIN || chainId == XDC || chainId == ZKSYNC;\n\n        callsGas += (3 * FixedPointMathLib.divUp(paramsLength, 32))\n            + FixedPointMathLib.mulDivUp(paramsLength, paramsLength, 524_288);\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/OperatorExpressions/fmt.sol",
    "content": "function test() {\n    uint256 expr001 = (1 + 2) + 3;\n    uint256 expr002 = 1 + (2 + 3);\n    uint256 expr003 = 1 * 2 + 3;\n    uint256 expr004 = (1 * 2) + 3;\n    uint256 expr005 = 1 * (2 + 3);\n    uint256 expr006 = 1 + 2 * 3;\n    uint256 expr007 = (1 + 2) * 3;\n    uint256 expr008 = 1 + (2 * 3);\n    uint256 expr009 = 1 ** 2 ** 3;\n    uint256 expr010 = 1 ** (2 ** 3);\n    uint256 expr011 = (1 ** 2) ** 3;\n    uint256 expr012 = ++expr011 + 1;\n    bool expr013 = ++expr012 == expr011 - 1;\n    bool expr014 = ++(++expr013)--;\n    if (++batch.movesPerformed == drivers.length) createNewBatch();\n    sum += getPrice(\n        ACCELERATE_STARTING_PRICE,\n        ACCELERATE_PER_PERIOD_DECREASE,\n        idleTicks,\n        actionsSold[ActionType.ACCELERATE] + i,\n        ACCELERATE_SELL_PER_TICK\n    ) / 1e18;\n    other += 1e18\n        / getPrice(\n            ACCELERATE_STARTING_PRICE,\n            ACCELERATE_PER_PERIOD_DECREASE,\n            idleTicks,\n            actionsSold[ActionType.ACCELERATE] + i,\n            ACCELERATE_SELL_PER_TICK\n        );\n    if (\n        op == 0x54 // SLOAD\n            || op == 0x55 // SSTORE\n            || op == 0xF0 // CREATE\n            || op == 0xF1 // CALL\n            || op == 0xF2 // CALLCODE\n            || op == 0xF4 // DELEGATECALL\n            || op == 0xF5 // CREATE2\n            || op == 0xFA // STATICCALL\n            || op == 0xFF // SELFDESTRUCT\n    ) return false;\n}\n\nfunction test_nested() {\n    require(\n        keccak256(abi.encodePacked(\"some long string\"))\n            == keccak256(abi.encodePacked(\"some other long string\")),\n        \"string mismatch\"\n    );\n\n    state.zeroForOne = IERC20(Currency.unwrap(state.poolKey1.currency0))\n        == IERC20(Currency.unwrap(state.poolKey0.curerncy1));\n\n    coreAddresses.evc == address(0)\n        && coreAddresses.protocolConfig == address(0)\n        && coreAddresses.sequenceRegistry == address(0)\n        && coreAddresses.balanceTracker == address(0)\n        && coreAddresses.permit2 == address(0);\n\n    return spender == ownerOf(tokenId) || getApproved[tokenId] == spender\n        || isApprovedForAll[ownerOf(tokenId)][spender];\n}\n\nfunction new_y(\n    uint256 x,\n    uint256 dx,\n    uint256 x_basis,\n    uint256 y,\n    uint256 y_basis\n) external pure returns (uint256) {\n    return _get_y(\n        x * _VELODROME_TOKEN_BASIS / x_basis,\n        dx * _VELODROME_TOKEN_BASIS / x_basis,\n        y * _VELODROME_TOKEN_BASIS / y_basis\n    ) * y_basis / _VELODROME_TOKEN_BASIS\n        * aReallyLongIdentifierThatMakesTheOperatorExpressionBreak;\n}\n\ncontract Repro {\n    bytes4 public constant MINIMAL_INTERFACE_ID =\n        this.calculateMinFeeWeiFor.selector ^ this.convertUSDFeeToWei.selector\n            ^ this.execute.selector ^ this.getMinFeeUSDFor.selector;\n    bool isTestnet = chainId == ARBITRUM_SEPOLIA || chainId == BASE_SEPOLIA\n        || chainId == MODE_SEPOLIA || chainId == OPTIMISM_SEPOLIA\n        || chainId == SEPOLIA;\n\n    function test() {\n        assign = this.calculateMinFeeWeiFor.selector\n            ^ this.convertUSDFeeToWei.selector ^ this.execute.selector\n            ^ this.getMinFeeUSDFor.selector;\n        isMainnet = chainId == ABSTRACT || chainId == ARBITRUM\n            || chainId == AVALANCHE || chainId == BASE || chainId == BERACHAIN\n            || chainId == BLAST || chainId == BSC || chainId == CHILIZ\n            || chainId == COREDAO || chainId == ETHEREUM || chainId == GNOSIS\n            || chainId == HYPEREVM || chainId == LIGHTLINK || chainId == LINEA\n            || chainId == MODE || chainId == MORPH || chainId == OPTIMISM\n            || chainId == POLYGON || chainId == SCROLL || chainId == SEI\n            || chainId == SOPHON || chainId == SUPERSEED || chainId == SONIC\n            || chainId == UNICHAIN || chainId == XDC || chainId == ZKSYNC;\n\n        callsGas += (3 * FixedPointMathLib.divUp(paramsLength, 32))\n            + FixedPointMathLib.mulDivUp(paramsLength, paramsLength, 524_288);\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/OperatorExpressions/original.sol",
    "content": "function test() {\n    uint256 expr001 = (1 + 2) + 3;\n    uint256 expr002 = 1 + (2 + 3);\n    uint256 expr003 = 1 * 2 + 3;\n    uint256 expr004 = (1 * 2) + 3;\n    uint256 expr005 = 1 * (2 + 3);\n    uint256 expr006 = 1 + 2 * 3;\n    uint256 expr007 = (1 + 2) * 3;\n    uint256 expr008 = 1 + (2 * 3);\n    uint256 expr009 = 1**2 ** 3;\n    uint256 expr010 = 1**(2 ** 3);\n    uint256 expr011 = (1**2) ** 3;\n    uint256 expr012 = ++expr011 + 1;\n    bool expr013 = ++expr012 == expr011 - 1;\n    bool expr014 = ++(++expr013)--;\n    if (++batch.movesPerformed == drivers.length) createNewBatch();\n    sum += getPrice(ACCELERATE_STARTING_PRICE, ACCELERATE_PER_PERIOD_DECREASE, idleTicks, actionsSold[ActionType.ACCELERATE] + i, ACCELERATE_SELL_PER_TICK) / 1e18;\n    other += 1e18 / getPrice(ACCELERATE_STARTING_PRICE, ACCELERATE_PER_PERIOD_DECREASE, idleTicks, actionsSold[ActionType.ACCELERATE] + i, ACCELERATE_SELL_PER_TICK);\n        if (\n        op == 0x54 // SLOAD\n        || op == 0x55 // SSTORE\n        || op == 0xF0 // CREATE\n        || op == 0xF1 // CALL\n        || op == 0xF2 // CALLCODE\n        || op == 0xF4 // DELEGATECALL\n        || op == 0xF5 // CREATE2\n        || op == 0xFA // STATICCALL\n        || op == 0xFF // SELFDESTRUCT\n    ) return false;\n}\n\nfunction test_nested() {\n    require(\n        keccak256(abi.encodePacked(\"some long string\"))\n            == keccak256(abi.encodePacked(\"some other long string\")),\n        \"string mismatch\"\n    );\n\n    state.zeroForOne = IERC20(Currency.unwrap(state.poolKey1.currency0))\n        == IERC20(Currency.unwrap(state.poolKey0.curerncy1));\n\n    coreAddresses.evc == address(0) && coreAddresses.protocolConfig == address(0)\n        && coreAddresses.sequenceRegistry == address(0) && coreAddresses.balanceTracker == address(0)\n        && coreAddresses.permit2 == address(0);\n\n    return spender == ownerOf(tokenId) || getApproved[tokenId] == spender\n        || isApprovedForAll[ownerOf(tokenId)][spender];\n}\n\nfunction new_y(uint256 x, uint256 dx, uint256 x_basis, uint256 y, uint256 y_basis)\n    external\n    pure\n    returns (uint256)\n{\n    return _get_y(\n        x * _VELODROME_TOKEN_BASIS / x_basis,\n        dx * _VELODROME_TOKEN_BASIS / x_basis,\n        y * _VELODROME_TOKEN_BASIS / y_basis\n    ) * y_basis / _VELODROME_TOKEN_BASIS * aReallyLongIdentifierThatMakesTheOperatorExpressionBreak;\n}\n\ncontract Repro {\n    bytes4 public constant MINIMAL_INTERFACE_ID = this.calculateMinFeeWeiFor.selector ^ this.convertUSDFeeToWei.selector ^ this.execute.selector ^ this.getMinFeeUSDFor.selector;\n    bool isTestnet = chainId == ARBITRUM_SEPOLIA || chainId == BASE_SEPOLIA || chainId == MODE_SEPOLIA || chainId == OPTIMISM_SEPOLIA || chainId == SEPOLIA;\n\n    function test() {\n        assign = this.calculateMinFeeWeiFor.selector ^ this.convertUSDFeeToWei.selector ^ this.execute.selector ^ this.getMinFeeUSDFor.selector;\n        isMainnet = chainId == ABSTRACT || chainId == ARBITRUM || chainId == AVALANCHE || chainId == BASE\n            || chainId == BERACHAIN || chainId == BLAST || chainId == BSC || chainId == CHILIZ || chainId == COREDAO\n            || chainId == ETHEREUM || chainId == GNOSIS || chainId == HYPEREVM || chainId == LIGHTLINK || chainId == LINEA\n            || chainId == MODE || chainId == MORPH || chainId == OPTIMISM || chainId == POLYGON || chainId == SCROLL\n            || chainId == SEI || chainId == SOPHON || chainId == SUPERSEED || chainId == SONIC || chainId == UNICHAIN\n            || chainId == XDC || chainId == ZKSYNC;\n\n        callsGas += (3 * FixedPointMathLib.divUp(paramsLength, 32)) + FixedPointMathLib.mulDivUp(paramsLength, paramsLength, 524_288);\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/OperatorExpressions/pow-no-space.fmt.sol",
    "content": "// config: pow_no_space = true\nfunction test() {\n    uint256 expr001 = (1 + 2) + 3;\n    uint256 expr002 = 1 + (2 + 3);\n    uint256 expr003 = 1 * 2 + 3;\n    uint256 expr004 = (1 * 2) + 3;\n    uint256 expr005 = 1 * (2 + 3);\n    uint256 expr006 = 1 + 2 * 3;\n    uint256 expr007 = (1 + 2) * 3;\n    uint256 expr008 = 1 + (2 * 3);\n    uint256 expr009 = 1**2**3;\n    uint256 expr010 = 1**(2**3);\n    uint256 expr011 = (1**2)**3;\n    uint256 expr012 = ++expr011 + 1;\n    bool expr013 = ++expr012 == expr011 - 1;\n    bool expr014 = ++(++expr013)--;\n    if (++batch.movesPerformed == drivers.length) createNewBatch();\n    sum += getPrice(\n        ACCELERATE_STARTING_PRICE,\n        ACCELERATE_PER_PERIOD_DECREASE,\n        idleTicks,\n        actionsSold[ActionType.ACCELERATE] + i,\n        ACCELERATE_SELL_PER_TICK\n    ) / 1e18;\n    other += 1e18\n        / getPrice(\n            ACCELERATE_STARTING_PRICE,\n            ACCELERATE_PER_PERIOD_DECREASE,\n            idleTicks,\n            actionsSold[ActionType.ACCELERATE] + i,\n            ACCELERATE_SELL_PER_TICK\n        );\n    if (\n        op == 0x54 // SLOAD\n            || op == 0x55 // SSTORE\n            || op == 0xF0 // CREATE\n            || op == 0xF1 // CALL\n            || op == 0xF2 // CALLCODE\n            || op == 0xF4 // DELEGATECALL\n            || op == 0xF5 // CREATE2\n            || op == 0xFA // STATICCALL\n            || op == 0xFF // SELFDESTRUCT\n    ) return false;\n}\n\nfunction test_nested() {\n    require(\n        keccak256(abi.encodePacked(\"some long string\"))\n            == keccak256(abi.encodePacked(\"some other long string\")),\n        \"string mismatch\"\n    );\n\n    state.zeroForOne = IERC20(Currency.unwrap(state.poolKey1.currency0))\n        == IERC20(Currency.unwrap(state.poolKey0.curerncy1));\n\n    coreAddresses.evc == address(0)\n        && coreAddresses.protocolConfig == address(0)\n        && coreAddresses.sequenceRegistry == address(0)\n        && coreAddresses.balanceTracker == address(0)\n        && coreAddresses.permit2 == address(0);\n\n    return spender == ownerOf(tokenId) || getApproved[tokenId] == spender\n        || isApprovedForAll[ownerOf(tokenId)][spender];\n}\n\nfunction new_y(\n    uint256 x,\n    uint256 dx,\n    uint256 x_basis,\n    uint256 y,\n    uint256 y_basis\n) external pure returns (uint256) {\n    return _get_y(\n        x * _VELODROME_TOKEN_BASIS / x_basis,\n        dx * _VELODROME_TOKEN_BASIS / x_basis,\n        y * _VELODROME_TOKEN_BASIS / y_basis\n    ) * y_basis / _VELODROME_TOKEN_BASIS\n        * aReallyLongIdentifierThatMakesTheOperatorExpressionBreak;\n}\n\ncontract Repro {\n    bytes4 public constant MINIMAL_INTERFACE_ID =\n        this.calculateMinFeeWeiFor.selector ^ this.convertUSDFeeToWei.selector\n            ^ this.execute.selector ^ this.getMinFeeUSDFor.selector;\n    bool isTestnet = chainId == ARBITRUM_SEPOLIA || chainId == BASE_SEPOLIA\n        || chainId == MODE_SEPOLIA || chainId == OPTIMISM_SEPOLIA\n        || chainId == SEPOLIA;\n\n    function test() {\n        assign = this.calculateMinFeeWeiFor.selector\n            ^ this.convertUSDFeeToWei.selector ^ this.execute.selector\n            ^ this.getMinFeeUSDFor.selector;\n        isMainnet = chainId == ABSTRACT || chainId == ARBITRUM\n            || chainId == AVALANCHE || chainId == BASE || chainId == BERACHAIN\n            || chainId == BLAST || chainId == BSC || chainId == CHILIZ\n            || chainId == COREDAO || chainId == ETHEREUM || chainId == GNOSIS\n            || chainId == HYPEREVM || chainId == LIGHTLINK || chainId == LINEA\n            || chainId == MODE || chainId == MORPH || chainId == OPTIMISM\n            || chainId == POLYGON || chainId == SCROLL || chainId == SEI\n            || chainId == SOPHON || chainId == SUPERSEED || chainId == SONIC\n            || chainId == UNICHAIN || chainId == XDC || chainId == ZKSYNC;\n\n        callsGas += (3 * FixedPointMathLib.divUp(paramsLength, 32))\n            + FixedPointMathLib.mulDivUp(paramsLength, paramsLength, 524_288);\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/PragmaDirective/fmt.sol",
    "content": "pragma solidity 0.8.17;\npragma experimental ABIEncoderV2;\n\ncontract Contract {}\n\n// preserves lines\npragma solidity 0.8.17;\n\npragma experimental ABIEncoderV2;\n"
  },
  {
    "path": "crates/fmt/testdata/PragmaDirective/original.sol",
    "content": "pragma solidity 0.8.17;\npragma experimental ABIEncoderV2;\n\ncontract Contract {}\n\n// preserves lines\npragma solidity 0.8.17;\n\npragma experimental ABIEncoderV2;"
  },
  {
    "path": "crates/fmt/testdata/Repros/fmt.sol",
    "content": "// Repros of fmt issues\n\n// https://github.com/foundry-rs/foundry/issues/7944\nimport {ERC20} from \"@contracts/token/ERC20/ERC20.sol\";\nimport {ERC20Permit} from \"@contracts/token/ERC20/ext/ERC20Permit.sol\";\nimport {ERC20Burnable} from \"@contracts/token/ERC20/ext/ERC20Burnable.sol\";\nimport {IERC20} from \"@contracts/token/ERC20/IERC20.sol\";\nimport {IERC20Permit} from \"@contracts/token/ERC20/ext/ERC20Permit.sol\";\nimport {AccessControl} from \"@contracts/access/AccessControl.sol\";\n\n// https://github.com/foundry-rs/foundry/issues/4403\nfunction errorIdentifier() {\n    bytes memory error = bytes(\"\");\n    if (error.length > 0) {}\n}\n\n// https://github.com/foundry-rs/foundry/issues/7549\nfunction one() external {\n    this.other({\n        data: abi.encodeCall(\n            this.other,\n            (\"bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla\")\n        )\n    });\n}\n\n// https://github.com/foundry-rs/foundry/issues/3979\ncontract Format {\n    bool public test;\n\n    function testing(uint256 amount) public payable {\n        if (\n            // This is a comment\n            msg.value == amount\n        ) {\n            test = true;\n        } else {\n            test = false;\n        }\n\n        if (\n            // Another one\n            block.timestamp >= amount\n        ) {}\n    }\n}\n\n// https://github.com/foundry-rs/foundry/issues/3830\ncontract TestContract {\n    function test(uint256 a) public {\n        if (a > 1) {\n            a = 2;\n        } // forgefmt: disable-line\n    }\n\n    function test1() public {\n        assembly { sstore(   1,    1) /* inline comment*/ // forgefmt: disable-line\n            sstore(2, 2)\n        }\n    }\n\n    function test2() public {\n        assembly { sstore(   1,    1) // forgefmt: disable-line\n            sstore(2, 2)\n            sstore(3,    3) // forgefmt: disable-line\n            sstore(4, 4)\n        }\n    }\n\n    function test3() public {\n        // forgefmt: disable-next-line\n        assembly{ sstore(   1,    1)\n            sstore(2, 2)\n            sstore(3,    3) // forgefmt: disable-line\n            sstore(4, 4)\n        } // forgefmt: disable-line\n    }\n\n    function test4() public {\n        // forgefmt: disable-next-line\n                  assembly {\n            sstore(1, 1)\n            sstore(2, 2)\n            sstore(3,    3) // forgefmt: disable-line\n            sstore(4, 4)\n        } // forgefmt: disable-line\n        if (condition) execute(); // comment7\n    }\n\n    function test5() public {\n        assembly { sstore(0, 0) }// forgefmt: disable-line\n    }\n\n    function test6() returns (bool) { // forgefmt: disable-line\n        if (  true  ) {  // forgefmt: disable-line\n        }\n        return true ;  }  // forgefmt: disable-line\n\n    function test7() returns (bool) { // forgefmt: disable-line\n        if (true) {  // forgefmt: disable-line\n            uint256 a     =     1; // forgefmt: disable-line\n        }\n        return true;\n    }\n\n    function test8() returns (bool) { // forgefmt: disable-line\n        if (  true  ) {    // forgefmt: disable-line\n            uint256 a = 1;\n        } else {\n            uint256 b     =     1; // forgefmt: disable-line\n        }\n        return true;\n    }\n}\n\n// https://github.com/foundry-rs/foundry/issues/5825\nlibrary MyLib {\n    bytes32 private constant TYPE_HASH = keccak256(\n        // forgefmt: disable-start\n        \"MyStruct(\"\n            \"uint8 myEnum,\"\n                \"address myAddress\"\n                    \")\"\n        // forgefmt: disable-end\n    );\n\n    bytes32 private constant TYPE_HASH_1 = keccak256(\n        \"MyStruct(\"    \"uint8 myEnum,\"    \"address myAddress\"    \")\" // forgefmt: disable-line\n    );\n\n    // forgefmt: disable-start\n    bytes32 private constant TYPE_HASH_2 = keccak256(\n        \"MyStruct(\"\n            \"uint8 myEnum,\"\n            \"address myAddress\"\n        \")\"\n    );\n    // forgefmt: disable-end\n}\n\ncontract IfElseTest {\n    function setNumber(uint256 newNumber) public {\n        number = newNumber;\n        if (newNumber = 1) {\n            number = 1;\n        } else if (newNumber = 2) {\n            //            number = 2;\n        } else {\n            newNumber = 3;\n        }\n    }\n}\n\ncontract DbgFmtTest is Test {\n    function test_argsList() public {\n        uint256 result1 = internalNoArgs({});\n        result2 = add({a: 1, b: 2});\n    }\n\n    function add(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a + b;\n    }\n\n    function internalNoArgs() internal pure returns (uint256) {\n        return 0;\n    }\n}\n\n// https://github.com/foundry-rs/foundry/issues/8557\n// https://github.com/foundry-rs/foundry/issues/11249\nfunction argListRepro(address tokenIn, uint256 amountIn, bool data) {\n    maverickV2SwapCallback(\n        tokenIn,\n        amountIn, // forgefmt: disable-line\n        // forgefmt: disable-next-line\n        0 /* we didn't bother loading `amountOut` because we don't use it */,\n        data\n    );\n}\n\n// https://github.com/foundry-rs/foundry/issues/11905\nfunction noBlanksLinesBeforeIdentifiers() public {\n    timelockController.grantRole(keccak256(\"EXECUTOR_ROLE\"), address(0));\n}\n\n// https://github.com/foundry-rs/foundry/issues/11913\nfunction rustfmtBlankLinesInStmtBlocks() public {\n    if (someCondition) {\n        bar = true;\n\n        emit Foo(bar);\n    }\n}\n\ncontract NestedCallsTest is Test {\n    string constant errMsg = \"User provided message\";\n    uint256 constant maxDecimals = 77;\n\n    Vm constant vm = Vm(HEVM_ADDRESS);\n\n    function test_nestedCalls() public {\n        vm._expectCheatcodeRevert(\n            bytes(string.concat(errMsg, \": \", left, \" != \", right))\n        );\n    }\n\n    function test_assemblyFnComments() public {\n        assembly {\n            function setJPoint(i, x, y, z) {\n                // We will multiply by `0x80` (i.e. `shl(7, i)`) instead\n                // since the memory expansion costs are cheaper than doing `mul(0x60, i)`.\n                // Also help combine the lookup expression for `u1` and `u2` in `jMultShamir`.\n                i := shl(7, i)\n                mstore(i, x)\n                mstore(add(i, returndatasize()), y)\n                mstore(add(i, 0x40), z)\n            }\n        }\n    }\n\n    function test_binOpsInsideNestedBlocks() public {\n        for (uint256 i = 0; i < steps.length; i++) {\n            if (\n                step.opcode == 0x52\n                    && /*MSTORE*/ step.stack[0] == testContract.memPtr() // MSTORE offset\n                    && step.stack[1] == testContract.expectedValueInMemory() // MSTORE val\n            ) {\n                mstoreCalled = true;\n            }\n        }\n    }\n}\n\ncontract ERC1967Factory {\n    /// @dev Returns a pointer to the initialization code of a proxy created via this factory.\n    function _initCode() internal view returns (bytes32 m) {\n        assembly {\n            /**\n             * -------------------------------------------------------------------------------------+\n             * CREATION (9 bytes)                                                                   |\n             * -------------------------------------------------------------------------------------|\n             * Opcode     | Mnemonic        | Stack               | Memory                          |\n             * -------------------------------------------------------------------------------------|\n             * 60 runSize | PUSH1 runSize   | r                   |                                 |\n             * 3d         | RETURNDATASIZE  | 0 r                 |                                 |\n             * 81         | DUP2            | r 0 r               |                                 |\n             * 60 offset  | PUSH1 offset    | o r 0 r             |                                 |\n             * 3d         | RETURNDATASIZE  | 0 o r 0 r           |                                 |\n             * 39         | CODECOPY        | 0 r                 | [0..runSize): runtime code      |\n             * f3         | RETURN          |                     | [0..runSize): runtime code      |\n             * -------------------------------------------------------------------------------------|\n             * RUNTIME (127 bytes)                                                                  |\n             * -------------------------------------------------------------------------------------|\n             * Opcode      | Mnemonic       | Stack               | Memory                          |\n             * -------------------------------------------------------------------------------------|\n             *                                                                                      |\n             * ::: keep some values in stack :::::::::::::::::::::::::::::::::::::::::::::::::::::: |\n             * 3d          | RETURNDATASIZE | 0                   |                                 |\n             * 3d          | RETURNDATASIZE | 0 0                 |                                 |\n             *                                                                                      |\n             * ::: check if caller is factory ::::::::::::::::::::::::::::::::::::::::::::::::::::: |\n             * 33          | CALLER         | c 0 0               |                                 |\n             * 73 factory  | PUSH20 factory | f c 0 0             |                                 |\n             * 14          | EQ             | isf 0 0             |                                 |\n             * 60 0x57     | PUSH1 0x57     | dest isf 0 0        |                                 |\n             * 57          | JUMPI          | 0 0                 |                                 |\n             *                                                                                      |\n             * ::: copy calldata to memory :::::::::::::::::::::::::::::::::::::::::::::::::::::::: |\n             * 36          | CALLDATASIZE   | cds 0 0             |                                 |\n             * 3d          | RETURNDATASIZE | 0 cds 0 0           |                                 |\n             * 3d          | RETURNDATASIZE | 0 0 cds 0 0         |                                 |\n             * 37          | CALLDATACOPY   | 0 0                 | [0..calldatasize): calldata     |\n             *                                                                                      |\n             * ::: delegatecall to implementation ::::::::::::::::::::::::::::::::::::::::::::::::: |\n             * 36          | CALLDATASIZE   | cds 0 0             | [0..calldatasize): calldata     |\n             * 3d          | RETURNDATASIZE | 0 cds 0 0           | [0..calldatasize): calldata     |\n             * 7f slot     | PUSH32 slot    | s 0 cds 0 0         | [0..calldatasize): calldata     |\n             * 54          | SLOAD          | i 0 cds 0 0         | [0..calldatasize): calldata     |\n             * 5a          | GAS            | g i 0 cds 0 0       | [0..calldatasize): calldata     |\n             * f4          | DELEGATECALL   | succ                | [0..calldatasize): calldata     |\n             *                                                                                      |\n             * ::: copy returndata to memory :::::::::::::::::::::::::::::::::::::::::::::::::::::: |\n             * 3d          | RETURNDATASIZE | rds succ            | [0..calldatasize): calldata     |\n             * 60 0x00     | PUSH1 0x00     | 0 rds succ          | [0..calldatasize): calldata     |\n             * 80          | DUP1           | 0 0 rds succ        | [0..calldatasize): calldata     |\n             * 3e          | RETURNDATACOPY | succ                | [0..returndatasize): returndata |\n             *                                                                                      |\n             * ::: branch on delegatecall status :::::::::::::::::::::::::::::::::::::::::::::::::: |\n             * 60 0x52     | PUSH1 0x52     | dest succ           | [0..returndatasize): returndata |\n             * 57          | JUMPI          |                     | [0..returndatasize): returndata |\n             *                                                                                      |\n             * ::: delegatecall failed, revert :::::::::::::::::::::::::::::::::::::::::::::::::::: |\n             * 3d          | RETURNDATASIZE | rds                 | [0..returndatasize): returndata |\n             * 60 0x00     | PUSH1 0x00     | 0 rds               | [0..returndatasize): returndata |\n             * fd          | REVERT         |                     | [0..returndatasize): returndata |\n             *                                                                                      |\n             * ::: delegatecall succeeded, return ::::::::::::::::::::::::::::::::::::::::::::::::: |\n             * 5b          | JUMPDEST       |                     | [0..returndatasize): returndata |\n             * 3d          | RETURNDATASIZE | rds                 | [0..returndatasize): returndata |\n             * 60 0x00     | PUSH1 0x00     | 0 rds               | [0..returndatasize): returndata |\n             * f3          | RETURN         |                     | [0..returndatasize): returndata |\n             *                                                                                      |\n             * ::: set new implementation (caller is factory) ::::::::::::::::::::::::::::::::::::: |\n             * 5b          | JUMPDEST       | 0 0                 |                                 |\n             * 3d          | RETURNDATASIZE | 0 0 0               |                                 |\n             * 35          | CALLDATALOAD   | impl 0 0            |                                 |\n             * 60 0x20     | PUSH1 0x20     | w impl 0 0          |                                 |\n             * 35          | CALLDATALOAD   | slot impl 0 0       |                                 |\n             * 55          | SSTORE         | 0 0                 |                                 |\n             *                                                                                      |\n             * ::: no extra calldata, return :::::::::::::::::::::::::::::::::::::::::::::::::::::: |\n             * 60 0x40     | PUSH1 0x40     | 2w 0 0              |                                 |\n             * 80          | DUP1           | 2w 2w 0 0           |                                 |\n             * 36          | CALLDATASIZE   | cds 2w 2w 0 0       |                                 |\n             * 11          | GT             | gt 2w 0 0           |                                 |\n             * 15          | ISZERO         | lte 2w 0 0          |                                 |\n             * 60 0x52     | PUSH1 0x52     | dest lte 2w 0 0     |                                 |\n             * 57          | JUMPI          | 2w 0 0              |                                 |\n             *                                                                                      |\n             * ::: copy extra calldata to memory :::::::::::::::::::::::::::::::::::::::::::::::::: |\n             * 36          | CALLDATASIZE   | cds 2w 0 0          |                                 |\n             * 03          | SUB            | t 0 0               |                                 |\n             * 80          | DUP1           | t t 0 0             |                                 |\n             * 60 0x40     | PUSH1 0x40     | 2w t t 0 0          |                                 |\n             * 3d          | RETURNDATASIZE | 0 2w t t 0 0        |                                 |\n             * 37          | CALLDATACOPY   | t 0 0               | [0..t): extra calldata          |\n             *                                                                                      |\n             * ::: delegatecall to implementation ::::::::::::::::::::::::::::::::::::::::::::::::: |\n             * 3d          | RETURNDATASIZE | 0 t 0 0             | [0..t): extra calldata          |\n             * 3d          | RETURNDATASIZE | 0 0 t 0 0           | [0..t): extra calldata          |\n             * 35          | CALLDATALOAD   | i 0 t 0 0           | [0..t): extra calldata          |\n             * 5a          | GAS            | g i 0 t 0 0         | [0..t): extra calldata          |\n             * f4          | DELEGATECALL   | succ                | [0..t): extra calldata          |\n             *                                                                                      |\n             * ::: copy returndata to memory :::::::::::::::::::::::::::::::::::::::::::::::::::::: |\n             * 3d          | RETURNDATASIZE | rds succ            | [0..t): extra calldata          |\n             * 60 0x00     | PUSH1 0x00     | 0 rds succ          | [0..t): extra calldata          |\n             * 80          | DUP1           | 0 0 rds succ        | [0..t): extra calldata          |\n             * 3e          | RETURNDATACOPY | succ                | [0..returndatasize): returndata |\n             *                                                                                      |\n             * ::: branch on delegatecall status :::::::::::::::::::::::::::::::::::::::::::::::::: |\n             * 60 0x52     | PUSH1 0x52     | dest succ           | [0..returndatasize): returndata |\n             * 57          | JUMPI          |                     | [0..returndatasize): returndata |\n             *                                                                                      |\n             * ::: delegatecall failed, revert :::::::::::::::::::::::::::::::::::::::::::::::::::: |\n             * 3d          | RETURNDATASIZE | rds                 | [0..returndatasize): returndata |\n             * 60 0x00     | PUSH1 0x00     | 0 rds               | [0..returndatasize): returndata |\n             * fd          | REVERT         |                     | [0..returndatasize): returndata |\n             * -------------------------------------------------------------------------------------+\n             */\n            m := mload(0x40)\n            // forgefmt: disable-start\n            switch shr(112, address())\n            case 0 {\n                // If the factory's address has six or more leading zero bytes.\n                mstore(add(m, 0x75), 0x604c573d6000fd) // 7\n                mstore(add(m, 0x6e), 0x3d3560203555604080361115604c5736038060403d373d3d355af43d6000803e) // 32\n                mstore(add(m, 0x4e), 0x3735a920a3ca505d382bbc545af43d6000803e604c573d6000fd5b3d6000f35b) // 32\n                mstore(add(m, 0x2e), 0x14605157363d3d37363d7f360894a13ba1a3210667c828492db98dca3e2076cc) // 32\n                mstore(add(m, 0x0e), address()) // 14\n                mstore(m, 0x60793d8160093d39f33d3d336d) // 9 + 4\n            }\n            default {\n                mstore(add(m, 0x7b), 0x6052573d6000fd) // 7\n                mstore(add(m, 0x74), 0x3d356020355560408036111560525736038060403d373d3d355af43d6000803e) // 32\n                mstore(add(m, 0x54), 0x3735a920a3ca505d382bbc545af43d6000803e6052573d6000fd5b3d6000f35b) // 32\n                mstore(add(m, 0x34), 0x14605757363d3d37363d7f360894a13ba1a3210667c828492db98dca3e2076cc) // 32\n                mstore(add(m, 0x14), address()) // 20\n                mstore(m, 0x607f3d8160093d39f33d3d3373) // 9 + 4\n            }\n            // forgefmt: disable-end\n        }\n    }\n}\n\n/// @title Wrapped Ether Hook\n/// @notice Hook for wrapping/unwrapping ETH in Uniswap V4 pools\n/// @dev Implements 1:1 wrapping/unwrapping of ETH to WETH\ncontract WETHHook is BaseTokenWrapperHook {\n    /// @notice The WETH9 contract\n    WETH public immutable weth;\n\n    /// @notice Creates a new WETH wrapper hook\n    /// @param _manager The Uniswap V4 pool manager\n    /// @param _weth The WETH9 contract address\n    constructor(IPoolManager _manager, address payable _weth)\n        BaseTokenWrapperHook(\n            _manager,\n            Currency.wrap(_weth), // wrapper token is WETH\n            CurrencyLibrary.ADDRESS_ZERO // underlying token is ETH (address(0))\n        )\n    {\n        weth = WETH(payable(_weth));\n    }\n}\n\n// https://github.com/foundry-rs/foundry/issues/12529\nlibrary TransferMessageLib {\n    struct TransferMessage {\n        bytes32 sender;\n        address receiver;\n        address token;\n        uint256 amount;\n    }\n\n    function pack(TransferMessage memory m)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return \"\";\n    }\n}\n\ncontract ChainedStructCall {\n    using TransferMessageLib for TransferMessageLib.TransferMessage;\n    bytes32 someBytes32Value;\n    address someAddressValue;\n    uint256 someUint256Value;\n\n    function test_chainedStructIndentation() public {\n        bytes memory payload = TransferMessageLib.TransferMessage({\n            sender: someBytes32Value,\n            receiver: someAddressValue,\n            token: someAddressValue,\n            amount: someUint256Value\n        }).pack();\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/Repros/original.sol",
    "content": "// Repros of fmt issues\n\n// https://github.com/foundry-rs/foundry/issues/7944\nimport { ERC20 } from \"@contracts/token/ERC20/ERC20.sol\";\nimport { ERC20Permit } from \"@contracts/token/ERC20/ext/ERC20Permit.sol\";\nimport { ERC20Burnable } from \"@contracts/token/ERC20/ext/ERC20Burnable.sol\";\nimport { IERC20 } from \"@contracts/token/ERC20/IERC20.sol\";\nimport { IERC20Permit } from \"@contracts/token/ERC20/ext/ERC20Permit.sol\";\nimport { AccessControl } from \"@contracts/access/AccessControl.sol\";\n\n// https://github.com/foundry-rs/foundry/issues/4403\nfunction errorIdentifier() {\n    bytes memory error = bytes(\"\");\n    if (error.length > 0) {}\n}\n\n// https://github.com/foundry-rs/foundry/issues/7549\nfunction one() external {\n    this.other({\n        data: abi.encodeCall(\n            this.other,\n            (\n                \"bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla\"\n            )\n            )\n    });\n}\n\n// https://github.com/foundry-rs/foundry/issues/3979\ncontract Format {\n    bool public test;\n\n    function testing(uint256 amount) public payable {\n        if (\n            // This is a comment\n            msg.value == amount\n        ) {\n            test = true;\n        } else {\n            test = false;\n        }\n\n        if (\n            // Another one\n            block.timestamp >= amount\n        ) {}\n    }\n}\n\n// https://github.com/foundry-rs/foundry/issues/3830\ncontract TestContract {\n    function test(uint256 a) public {\n        if (a > 1) {\n            a = 2;\n        } // forgefmt: disable-line\n    }\n\n    function test1() public {\n        assembly { sstore(   1,    1) /* inline comment*/ // forgefmt: disable-line\n            sstore(2,    2)\n        }\n    }\n\n    function test2() public {\n        assembly { sstore(   1,    1) // forgefmt: disable-line\n            sstore(2,    2)\n            sstore(3,    3) // forgefmt: disable-line\n            sstore(4,    4)\n        }\n    }\n\n    function test3() public {\n        // forgefmt: disable-next-line\n        assembly{ sstore(   1,    1)\n            sstore(2,    2)\n            sstore(3,    3) // forgefmt: disable-line\n            sstore(4,    4)\n        }// forgefmt: disable-line\n    }\n\n    function test4() public {\n        // forgefmt: disable-next-line\n                  assembly {\n            sstore(   1,    1)\n            sstore(2,    2)\n            sstore(3,    3) // forgefmt: disable-line\n            sstore(4,    4)\n        }// forgefmt: disable-line\n        if (condition) execute(); // comment7\n    }\n\n    function test5() public {\n         assembly { sstore(0, 0) }// forgefmt: disable-line\n    }\n\n    function test6() returns (bool) { // forgefmt: disable-line\n        if (  true  ) {  // forgefmt: disable-line\n        }\n        return true ;  }  // forgefmt: disable-line\n\n    function test7() returns (bool) { // forgefmt: disable-line\n        if (true) {  // forgefmt: disable-line\n            uint256 a     =     1; // forgefmt: disable-line\n        }\n        return true ;  }\n\n    function test8() returns (bool) { // forgefmt: disable-line\n        if (  true  ) {    // forgefmt: disable-line\n            uint256 a = 1;\n        } else {\n            uint256 b     =     1; // forgefmt: disable-line\n        }\n        return true ;  }\n}\n\n// https://github.com/foundry-rs/foundry/issues/5825\nlibrary MyLib {\n    bytes32 private constant TYPE_HASH = keccak256(\n        // forgefmt: disable-start\n        \"MyStruct(\"\n            \"uint8 myEnum,\"\n                \"address myAddress\"\n                    \")\"\n        // forgefmt: disable-end\n    );\n\n    bytes32 private constant TYPE_HASH_1 = keccak256(\n        \"MyStruct(\"    \"uint8 myEnum,\"    \"address myAddress\"    \")\" // forgefmt: disable-line\n    );\n\n    // forgefmt: disable-start\n    bytes32 private constant TYPE_HASH_2 = keccak256(\n        \"MyStruct(\"\n            \"uint8 myEnum,\"\n            \"address myAddress\"\n        \")\"\n    );\n    // forgefmt: disable-end\n}\n\ncontract IfElseTest {\n     function setNumber(uint256 newNumber) public {\n         number = newNumber;\n         if (newNumber = 1) {\n             number = 1;\n         } else if (newNumber = 2) {\n         //            number = 2;\n         }\n         else {\n             newNumber = 3;\n         }\n     }\n}\n\ncontract DbgFmtTest is Test {\n    function test_argsList() public {\n        uint256 result1 = internalNoArgs({});\n        result2 = add({a: 1, b: 2});\n    }\n\n    function add(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a + b;\n    }\n\n    function internalNoArgs() internal pure returns (uint256) {\n        return 0;\n    }\n}\n\n// https://github.com/foundry-rs/foundry/issues/8557\n// https://github.com/foundry-rs/foundry/issues/11249\nfunction argListRepro(address tokenIn, uint256 amountIn, bool data) {\n    maverickV2SwapCallback(\n        tokenIn,\n        amountIn, // forgefmt: disable-line\n        // forgefmt: disable-next-line\n        0 /* we didn't bother loading `amountOut` because we don't use it */,\n        data\n    );\n}\n\n// https://github.com/foundry-rs/foundry/issues/11905\nfunction noBlanksLinesBeforeIdentifiers() public {\n            timelockController\n\n\n\n        .grantRole(keccak256(\"EXECUTOR_ROLE\"), address(0));\n}\n\n// https://github.com/foundry-rs/foundry/issues/11913\nfunction rustfmtBlankLinesInStmtBlocks() public {\n        if (someCondition) {\n\n\n\n    bar = true;\n\n\n\n            emit Foo(bar);\n\n\n            }\n}\n\ncontract NestedCallsTest is Test {\n    string constant errMsg = \"User provided message\";\n    uint256 constant maxDecimals = 77;\n\n    Vm constant vm = Vm(HEVM_ADDRESS);\n\n    function test_nestedCalls() public {\n        vm._expectCheatcodeRevert(\n            bytes(string.concat(errMsg, \": \", left, \" != \", right))\n        );\n    }\n\n    function test_assemblyFnComments() public {\n        assembly {\n            function setJPoint(i, x, y, z) {\n                // We will multiply by `0x80` (i.e. `shl(7, i)`) instead\n                // since the memory expansion costs are cheaper than doing `mul(0x60, i)`.\n                // Also help combine the lookup expression for `u1` and `u2` in `jMultShamir`.\n                i := shl(7, i)\n                mstore(i, x)\n                mstore(add(i, returndatasize()), y)\n                mstore(add(i, 0x40), z)\n            }\n        }\n    }\n\n    function test_binOpsInsideNestedBlocks() public {\n        for (uint256 i = 0; i < steps.length; i++) {\n            if (\n                step.opcode == 0x52\n                    && /*MSTORE*/ step.stack[0] == testContract.memPtr() // MSTORE offset\n                && step.stack[1] == testContract.expectedValueInMemory() // MSTORE val\n            ) {\n                mstoreCalled = true;\n            }\n        }\n    }\n}\n\ncontract ERC1967Factory {\n    /// @dev Returns a pointer to the initialization code of a proxy created via this factory.\n    function _initCode() internal view returns (bytes32 m) {\n        assembly {\n            /**\n             * -------------------------------------------------------------------------------------+\n             * CREATION (9 bytes)                                                                   |\n             * -------------------------------------------------------------------------------------|\n             * Opcode     | Mnemonic        | Stack               | Memory                          |\n             * -------------------------------------------------------------------------------------|\n             * 60 runSize | PUSH1 runSize   | r                   |                                 |\n             * 3d         | RETURNDATASIZE  | 0 r                 |                                 |\n             * 81         | DUP2            | r 0 r               |                                 |\n             * 60 offset  | PUSH1 offset    | o r 0 r             |                                 |\n             * 3d         | RETURNDATASIZE  | 0 o r 0 r           |                                 |\n             * 39         | CODECOPY        | 0 r                 | [0..runSize): runtime code      |\n             * f3         | RETURN          |                     | [0..runSize): runtime code      |\n             * -------------------------------------------------------------------------------------|\n             * RUNTIME (127 bytes)                                                                  |\n             * -------------------------------------------------------------------------------------|\n             * Opcode      | Mnemonic       | Stack               | Memory                          |\n             * -------------------------------------------------------------------------------------|\n             *                                                                                      |\n             * ::: keep some values in stack :::::::::::::::::::::::::::::::::::::::::::::::::::::: |\n             * 3d          | RETURNDATASIZE | 0                   |                                 |\n             * 3d          | RETURNDATASIZE | 0 0                 |                                 |\n             *                                                                                      |\n             * ::: check if caller is factory ::::::::::::::::::::::::::::::::::::::::::::::::::::: |\n             * 33          | CALLER         | c 0 0               |                                 |\n             * 73 factory  | PUSH20 factory | f c 0 0             |                                 |\n             * 14          | EQ             | isf 0 0             |                                 |\n             * 60 0x57     | PUSH1 0x57     | dest isf 0 0        |                                 |\n             * 57          | JUMPI          | 0 0                 |                                 |\n             *                                                                                      |\n             * ::: copy calldata to memory :::::::::::::::::::::::::::::::::::::::::::::::::::::::: |\n             * 36          | CALLDATASIZE   | cds 0 0             |                                 |\n             * 3d          | RETURNDATASIZE | 0 cds 0 0           |                                 |\n             * 3d          | RETURNDATASIZE | 0 0 cds 0 0         |                                 |\n             * 37          | CALLDATACOPY   | 0 0                 | [0..calldatasize): calldata     |\n             *                                                                                      |\n             * ::: delegatecall to implementation ::::::::::::::::::::::::::::::::::::::::::::::::: |\n             * 36          | CALLDATASIZE   | cds 0 0             | [0..calldatasize): calldata     |\n             * 3d          | RETURNDATASIZE | 0 cds 0 0           | [0..calldatasize): calldata     |\n             * 7f slot     | PUSH32 slot    | s 0 cds 0 0         | [0..calldatasize): calldata     |\n             * 54          | SLOAD          | i 0 cds 0 0         | [0..calldatasize): calldata     |\n             * 5a          | GAS            | g i 0 cds 0 0       | [0..calldatasize): calldata     |\n             * f4          | DELEGATECALL   | succ                | [0..calldatasize): calldata     |\n             *                                                                                      |\n             * ::: copy returndata to memory :::::::::::::::::::::::::::::::::::::::::::::::::::::: |\n             * 3d          | RETURNDATASIZE | rds succ            | [0..calldatasize): calldata     |\n             * 60 0x00     | PUSH1 0x00     | 0 rds succ          | [0..calldatasize): calldata     |\n             * 80          | DUP1           | 0 0 rds succ        | [0..calldatasize): calldata     |\n             * 3e          | RETURNDATACOPY | succ                | [0..returndatasize): returndata |\n             *                                                                                      |\n             * ::: branch on delegatecall status :::::::::::::::::::::::::::::::::::::::::::::::::: |\n             * 60 0x52     | PUSH1 0x52     | dest succ           | [0..returndatasize): returndata |\n             * 57          | JUMPI          |                     | [0..returndatasize): returndata |\n             *                                                                                      |\n             * ::: delegatecall failed, revert :::::::::::::::::::::::::::::::::::::::::::::::::::: |\n             * 3d          | RETURNDATASIZE | rds                 | [0..returndatasize): returndata |\n             * 60 0x00     | PUSH1 0x00     | 0 rds               | [0..returndatasize): returndata |\n             * fd          | REVERT         |                     | [0..returndatasize): returndata |\n             *                                                                                      |\n             * ::: delegatecall succeeded, return ::::::::::::::::::::::::::::::::::::::::::::::::: |\n             * 5b          | JUMPDEST       |                     | [0..returndatasize): returndata |\n             * 3d          | RETURNDATASIZE | rds                 | [0..returndatasize): returndata |\n             * 60 0x00     | PUSH1 0x00     | 0 rds               | [0..returndatasize): returndata |\n             * f3          | RETURN         |                     | [0..returndatasize): returndata |\n             *                                                                                      |\n             * ::: set new implementation (caller is factory) ::::::::::::::::::::::::::::::::::::: |\n             * 5b          | JUMPDEST       | 0 0                 |                                 |\n             * 3d          | RETURNDATASIZE | 0 0 0               |                                 |\n             * 35          | CALLDATALOAD   | impl 0 0            |                                 |\n             * 60 0x20     | PUSH1 0x20     | w impl 0 0          |                                 |\n             * 35          | CALLDATALOAD   | slot impl 0 0       |                                 |\n             * 55          | SSTORE         | 0 0                 |                                 |\n             *                                                                                      |\n             * ::: no extra calldata, return :::::::::::::::::::::::::::::::::::::::::::::::::::::: |\n             * 60 0x40     | PUSH1 0x40     | 2w 0 0              |                                 |\n             * 80          | DUP1           | 2w 2w 0 0           |                                 |\n             * 36          | CALLDATASIZE   | cds 2w 2w 0 0       |                                 |\n             * 11          | GT             | gt 2w 0 0           |                                 |\n             * 15          | ISZERO         | lte 2w 0 0          |                                 |\n             * 60 0x52     | PUSH1 0x52     | dest lte 2w 0 0     |                                 |\n             * 57          | JUMPI          | 2w 0 0              |                                 |\n             *                                                                                      |\n             * ::: copy extra calldata to memory :::::::::::::::::::::::::::::::::::::::::::::::::: |\n             * 36          | CALLDATASIZE   | cds 2w 0 0          |                                 |\n             * 03          | SUB            | t 0 0               |                                 |\n             * 80          | DUP1           | t t 0 0             |                                 |\n             * 60 0x40     | PUSH1 0x40     | 2w t t 0 0          |                                 |\n             * 3d          | RETURNDATASIZE | 0 2w t t 0 0        |                                 |\n             * 37          | CALLDATACOPY   | t 0 0               | [0..t): extra calldata          |\n             *                                                                                      |\n             * ::: delegatecall to implementation ::::::::::::::::::::::::::::::::::::::::::::::::: |\n             * 3d          | RETURNDATASIZE | 0 t 0 0             | [0..t): extra calldata          |\n             * 3d          | RETURNDATASIZE | 0 0 t 0 0           | [0..t): extra calldata          |\n             * 35          | CALLDATALOAD   | i 0 t 0 0           | [0..t): extra calldata          |\n             * 5a          | GAS            | g i 0 t 0 0         | [0..t): extra calldata          |\n             * f4          | DELEGATECALL   | succ                | [0..t): extra calldata          |\n             *                                                                                      |\n             * ::: copy returndata to memory :::::::::::::::::::::::::::::::::::::::::::::::::::::: |\n             * 3d          | RETURNDATASIZE | rds succ            | [0..t): extra calldata          |\n             * 60 0x00     | PUSH1 0x00     | 0 rds succ          | [0..t): extra calldata          |\n             * 80          | DUP1           | 0 0 rds succ        | [0..t): extra calldata          |\n             * 3e          | RETURNDATACOPY | succ                | [0..returndatasize): returndata |\n             *                                                                                      |\n             * ::: branch on delegatecall status :::::::::::::::::::::::::::::::::::::::::::::::::: |\n             * 60 0x52     | PUSH1 0x52     | dest succ           | [0..returndatasize): returndata |\n             * 57          | JUMPI          |                     | [0..returndatasize): returndata |\n             *                                                                                      |\n             * ::: delegatecall failed, revert :::::::::::::::::::::::::::::::::::::::::::::::::::: |\n             * 3d          | RETURNDATASIZE | rds                 | [0..returndatasize): returndata |\n             * 60 0x00     | PUSH1 0x00     | 0 rds               | [0..returndatasize): returndata |\n             * fd          | REVERT         |                     | [0..returndatasize): returndata |\n             * -------------------------------------------------------------------------------------+\n             */\n            m := mload(0x40)\n            // forgefmt: disable-start\n            switch shr(112, address())\n            case 0 {\n                // If the factory's address has six or more leading zero bytes.\n                mstore(add(m, 0x75), 0x604c573d6000fd) // 7\n                mstore(add(m, 0x6e), 0x3d3560203555604080361115604c5736038060403d373d3d355af43d6000803e) // 32\n                mstore(add(m, 0x4e), 0x3735a920a3ca505d382bbc545af43d6000803e604c573d6000fd5b3d6000f35b) // 32\n                mstore(add(m, 0x2e), 0x14605157363d3d37363d7f360894a13ba1a3210667c828492db98dca3e2076cc) // 32\n                mstore(add(m, 0x0e), address()) // 14\n                mstore(m, 0x60793d8160093d39f33d3d336d) // 9 + 4\n            }\n            default {\n                mstore(add(m, 0x7b), 0x6052573d6000fd) // 7\n                mstore(add(m, 0x74), 0x3d356020355560408036111560525736038060403d373d3d355af43d6000803e) // 32\n                mstore(add(m, 0x54), 0x3735a920a3ca505d382bbc545af43d6000803e6052573d6000fd5b3d6000f35b) // 32\n                mstore(add(m, 0x34), 0x14605757363d3d37363d7f360894a13ba1a3210667c828492db98dca3e2076cc) // 32\n                mstore(add(m, 0x14), address()) // 20\n                mstore(m, 0x607f3d8160093d39f33d3d3373) // 9 + 4\n            }\n            // forgefmt: disable-end\n        }\n    }\n}\n\n/// @title Wrapped Ether Hook\n/// @notice Hook for wrapping/unwrapping ETH in Uniswap V4 pools\n/// @dev Implements 1:1 wrapping/unwrapping of ETH to WETH\ncontract WETHHook is BaseTokenWrapperHook {\n    /// @notice The WETH9 contract\n    WETH public immutable weth;\n\n    /// @notice Creates a new WETH wrapper hook\n    /// @param _manager The Uniswap V4 pool manager\n    /// @param _weth The WETH9 contract address\n    constructor(IPoolManager _manager, address payable _weth)\n        BaseTokenWrapperHook(\n            _manager,\n            Currency.wrap(_weth), // wrapper token is WETH\n            CurrencyLibrary.ADDRESS_ZERO // underlying token is ETH (address(0))\n        )\n    {\n        weth = WETH(payable(_weth));\n    }\n}\n\n// https://github.com/foundry-rs/foundry/issues/12529\nlibrary TransferMessageLib {\n    struct TransferMessage { bytes32 sender; address receiver; address token; uint256 amount; }\n    function pack(TransferMessage memory m) internal pure returns (bytes memory) { return \"\"; }\n}\n\ncontract ChainedStructCall {\n    using TransferMessageLib for TransferMessageLib.TransferMessage;\n    bytes32 someBytes32Value;\n    address someAddressValue;\n    uint256 someUint256Value;\n\n    function test_chainedStructIndentation() public {\n        bytes memory payload = TransferMessageLib.TransferMessage({\n                sender: someBytes32Value, receiver: someAddressValue, token: someAddressValue, amount: someUint256Value\n            }).pack();\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/Repros/sorted.fmt.sol",
    "content": "// config: sort_imports = true\n// Repros of fmt issues\n\n// https://github.com/foundry-rs/foundry/issues/7944\nimport {AccessControl} from \"@contracts/access/AccessControl.sol\";\nimport {ERC20} from \"@contracts/token/ERC20/ERC20.sol\";\nimport {IERC20} from \"@contracts/token/ERC20/IERC20.sol\";\nimport {ERC20Burnable} from \"@contracts/token/ERC20/ext/ERC20Burnable.sol\";\nimport {ERC20Permit} from \"@contracts/token/ERC20/ext/ERC20Permit.sol\";\nimport {IERC20Permit} from \"@contracts/token/ERC20/ext/ERC20Permit.sol\";\n\n// https://github.com/foundry-rs/foundry/issues/4403\nfunction errorIdentifier() {\n    bytes memory error = bytes(\"\");\n    if (error.length > 0) {}\n}\n\n// https://github.com/foundry-rs/foundry/issues/7549\nfunction one() external {\n    this.other({\n        data: abi.encodeCall(\n            this.other,\n            (\"bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla\")\n        )\n    });\n}\n\n// https://github.com/foundry-rs/foundry/issues/3979\ncontract Format {\n    bool public test;\n\n    function testing(uint256 amount) public payable {\n        if (\n            // This is a comment\n            msg.value == amount\n        ) {\n            test = true;\n        } else {\n            test = false;\n        }\n\n        if (\n            // Another one\n            block.timestamp >= amount\n        ) {}\n    }\n}\n\n// https://github.com/foundry-rs/foundry/issues/3830\ncontract TestContract {\n    function test(uint256 a) public {\n        if (a > 1) {\n            a = 2;\n        } // forgefmt: disable-line\n    }\n\n    function test1() public {\n        assembly { sstore(   1,    1) /* inline comment*/ // forgefmt: disable-line\n            sstore(2, 2)\n        }\n    }\n\n    function test2() public {\n        assembly { sstore(   1,    1) // forgefmt: disable-line\n            sstore(2, 2)\n            sstore(3,    3) // forgefmt: disable-line\n            sstore(4, 4)\n        }\n    }\n\n    function test3() public {\n        // forgefmt: disable-next-line\n        assembly{ sstore(   1,    1)\n            sstore(2, 2)\n            sstore(3,    3) // forgefmt: disable-line\n            sstore(4, 4)\n        } // forgefmt: disable-line\n    }\n\n    function test4() public {\n        // forgefmt: disable-next-line\n                  assembly {\n            sstore(1, 1)\n            sstore(2, 2)\n            sstore(3,    3) // forgefmt: disable-line\n            sstore(4, 4)\n        } // forgefmt: disable-line\n        if (condition) execute(); // comment7\n    }\n\n    function test5() public {\n        assembly { sstore(0, 0) }// forgefmt: disable-line\n    }\n\n    function test6() returns (bool) { // forgefmt: disable-line\n        if (  true  ) {  // forgefmt: disable-line\n        }\n        return true ;  }  // forgefmt: disable-line\n\n    function test7() returns (bool) { // forgefmt: disable-line\n        if (true) {  // forgefmt: disable-line\n            uint256 a     =     1; // forgefmt: disable-line\n        }\n        return true;\n    }\n\n    function test8() returns (bool) { // forgefmt: disable-line\n        if (  true  ) {    // forgefmt: disable-line\n            uint256 a = 1;\n        } else {\n            uint256 b     =     1; // forgefmt: disable-line\n        }\n        return true;\n    }\n}\n\n// https://github.com/foundry-rs/foundry/issues/5825\nlibrary MyLib {\n    bytes32 private constant TYPE_HASH = keccak256(\n        // forgefmt: disable-start\n        \"MyStruct(\"\n            \"uint8 myEnum,\"\n                \"address myAddress\"\n                    \")\"\n        // forgefmt: disable-end\n    );\n\n    bytes32 private constant TYPE_HASH_1 = keccak256(\n        \"MyStruct(\"    \"uint8 myEnum,\"    \"address myAddress\"    \")\" // forgefmt: disable-line\n    );\n\n    // forgefmt: disable-start\n    bytes32 private constant TYPE_HASH_2 = keccak256(\n        \"MyStruct(\"\n            \"uint8 myEnum,\"\n            \"address myAddress\"\n        \")\"\n    );\n    // forgefmt: disable-end\n}\n\ncontract IfElseTest {\n    function setNumber(uint256 newNumber) public {\n        number = newNumber;\n        if (newNumber = 1) {\n            number = 1;\n        } else if (newNumber = 2) {\n            //            number = 2;\n        } else {\n            newNumber = 3;\n        }\n    }\n}\n\ncontract DbgFmtTest is Test {\n    function test_argsList() public {\n        uint256 result1 = internalNoArgs({});\n        result2 = add({a: 1, b: 2});\n    }\n\n    function add(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a + b;\n    }\n\n    function internalNoArgs() internal pure returns (uint256) {\n        return 0;\n    }\n}\n\n// https://github.com/foundry-rs/foundry/issues/8557\n// https://github.com/foundry-rs/foundry/issues/11249\nfunction argListRepro(address tokenIn, uint256 amountIn, bool data) {\n    maverickV2SwapCallback(\n        tokenIn,\n        amountIn, // forgefmt: disable-line\n        // forgefmt: disable-next-line\n        0 /* we didn't bother loading `amountOut` because we don't use it */,\n        data\n    );\n}\n\n// https://github.com/foundry-rs/foundry/issues/11905\nfunction noBlanksLinesBeforeIdentifiers() public {\n    timelockController.grantRole(keccak256(\"EXECUTOR_ROLE\"), address(0));\n}\n\n// https://github.com/foundry-rs/foundry/issues/11913\nfunction rustfmtBlankLinesInStmtBlocks() public {\n    if (someCondition) {\n        bar = true;\n\n        emit Foo(bar);\n    }\n}\n\ncontract NestedCallsTest is Test {\n    string constant errMsg = \"User provided message\";\n    uint256 constant maxDecimals = 77;\n\n    Vm constant vm = Vm(HEVM_ADDRESS);\n\n    function test_nestedCalls() public {\n        vm._expectCheatcodeRevert(\n            bytes(string.concat(errMsg, \": \", left, \" != \", right))\n        );\n    }\n\n    function test_assemblyFnComments() public {\n        assembly {\n            function setJPoint(i, x, y, z) {\n                // We will multiply by `0x80` (i.e. `shl(7, i)`) instead\n                // since the memory expansion costs are cheaper than doing `mul(0x60, i)`.\n                // Also help combine the lookup expression for `u1` and `u2` in `jMultShamir`.\n                i := shl(7, i)\n                mstore(i, x)\n                mstore(add(i, returndatasize()), y)\n                mstore(add(i, 0x40), z)\n            }\n        }\n    }\n\n    function test_binOpsInsideNestedBlocks() public {\n        for (uint256 i = 0; i < steps.length; i++) {\n            if (\n                step.opcode == 0x52\n                    && /*MSTORE*/ step.stack[0] == testContract.memPtr() // MSTORE offset\n                    && step.stack[1] == testContract.expectedValueInMemory() // MSTORE val\n            ) {\n                mstoreCalled = true;\n            }\n        }\n    }\n}\n\ncontract ERC1967Factory {\n    /// @dev Returns a pointer to the initialization code of a proxy created via this factory.\n    function _initCode() internal view returns (bytes32 m) {\n        assembly {\n            /**\n             * -------------------------------------------------------------------------------------+\n             * CREATION (9 bytes)                                                                   |\n             * -------------------------------------------------------------------------------------|\n             * Opcode     | Mnemonic        | Stack               | Memory                          |\n             * -------------------------------------------------------------------------------------|\n             * 60 runSize | PUSH1 runSize   | r                   |                                 |\n             * 3d         | RETURNDATASIZE  | 0 r                 |                                 |\n             * 81         | DUP2            | r 0 r               |                                 |\n             * 60 offset  | PUSH1 offset    | o r 0 r             |                                 |\n             * 3d         | RETURNDATASIZE  | 0 o r 0 r           |                                 |\n             * 39         | CODECOPY        | 0 r                 | [0..runSize): runtime code      |\n             * f3         | RETURN          |                     | [0..runSize): runtime code      |\n             * -------------------------------------------------------------------------------------|\n             * RUNTIME (127 bytes)                                                                  |\n             * -------------------------------------------------------------------------------------|\n             * Opcode      | Mnemonic       | Stack               | Memory                          |\n             * -------------------------------------------------------------------------------------|\n             *                                                                                      |\n             * ::: keep some values in stack :::::::::::::::::::::::::::::::::::::::::::::::::::::: |\n             * 3d          | RETURNDATASIZE | 0                   |                                 |\n             * 3d          | RETURNDATASIZE | 0 0                 |                                 |\n             *                                                                                      |\n             * ::: check if caller is factory ::::::::::::::::::::::::::::::::::::::::::::::::::::: |\n             * 33          | CALLER         | c 0 0               |                                 |\n             * 73 factory  | PUSH20 factory | f c 0 0             |                                 |\n             * 14          | EQ             | isf 0 0             |                                 |\n             * 60 0x57     | PUSH1 0x57     | dest isf 0 0        |                                 |\n             * 57          | JUMPI          | 0 0                 |                                 |\n             *                                                                                      |\n             * ::: copy calldata to memory :::::::::::::::::::::::::::::::::::::::::::::::::::::::: |\n             * 36          | CALLDATASIZE   | cds 0 0             |                                 |\n             * 3d          | RETURNDATASIZE | 0 cds 0 0           |                                 |\n             * 3d          | RETURNDATASIZE | 0 0 cds 0 0         |                                 |\n             * 37          | CALLDATACOPY   | 0 0                 | [0..calldatasize): calldata     |\n             *                                                                                      |\n             * ::: delegatecall to implementation ::::::::::::::::::::::::::::::::::::::::::::::::: |\n             * 36          | CALLDATASIZE   | cds 0 0             | [0..calldatasize): calldata     |\n             * 3d          | RETURNDATASIZE | 0 cds 0 0           | [0..calldatasize): calldata     |\n             * 7f slot     | PUSH32 slot    | s 0 cds 0 0         | [0..calldatasize): calldata     |\n             * 54          | SLOAD          | i 0 cds 0 0         | [0..calldatasize): calldata     |\n             * 5a          | GAS            | g i 0 cds 0 0       | [0..calldatasize): calldata     |\n             * f4          | DELEGATECALL   | succ                | [0..calldatasize): calldata     |\n             *                                                                                      |\n             * ::: copy returndata to memory :::::::::::::::::::::::::::::::::::::::::::::::::::::: |\n             * 3d          | RETURNDATASIZE | rds succ            | [0..calldatasize): calldata     |\n             * 60 0x00     | PUSH1 0x00     | 0 rds succ          | [0..calldatasize): calldata     |\n             * 80          | DUP1           | 0 0 rds succ        | [0..calldatasize): calldata     |\n             * 3e          | RETURNDATACOPY | succ                | [0..returndatasize): returndata |\n             *                                                                                      |\n             * ::: branch on delegatecall status :::::::::::::::::::::::::::::::::::::::::::::::::: |\n             * 60 0x52     | PUSH1 0x52     | dest succ           | [0..returndatasize): returndata |\n             * 57          | JUMPI          |                     | [0..returndatasize): returndata |\n             *                                                                                      |\n             * ::: delegatecall failed, revert :::::::::::::::::::::::::::::::::::::::::::::::::::: |\n             * 3d          | RETURNDATASIZE | rds                 | [0..returndatasize): returndata |\n             * 60 0x00     | PUSH1 0x00     | 0 rds               | [0..returndatasize): returndata |\n             * fd          | REVERT         |                     | [0..returndatasize): returndata |\n             *                                                                                      |\n             * ::: delegatecall succeeded, return ::::::::::::::::::::::::::::::::::::::::::::::::: |\n             * 5b          | JUMPDEST       |                     | [0..returndatasize): returndata |\n             * 3d          | RETURNDATASIZE | rds                 | [0..returndatasize): returndata |\n             * 60 0x00     | PUSH1 0x00     | 0 rds               | [0..returndatasize): returndata |\n             * f3          | RETURN         |                     | [0..returndatasize): returndata |\n             *                                                                                      |\n             * ::: set new implementation (caller is factory) ::::::::::::::::::::::::::::::::::::: |\n             * 5b          | JUMPDEST       | 0 0                 |                                 |\n             * 3d          | RETURNDATASIZE | 0 0 0               |                                 |\n             * 35          | CALLDATALOAD   | impl 0 0            |                                 |\n             * 60 0x20     | PUSH1 0x20     | w impl 0 0          |                                 |\n             * 35          | CALLDATALOAD   | slot impl 0 0       |                                 |\n             * 55          | SSTORE         | 0 0                 |                                 |\n             *                                                                                      |\n             * ::: no extra calldata, return :::::::::::::::::::::::::::::::::::::::::::::::::::::: |\n             * 60 0x40     | PUSH1 0x40     | 2w 0 0              |                                 |\n             * 80          | DUP1           | 2w 2w 0 0           |                                 |\n             * 36          | CALLDATASIZE   | cds 2w 2w 0 0       |                                 |\n             * 11          | GT             | gt 2w 0 0           |                                 |\n             * 15          | ISZERO         | lte 2w 0 0          |                                 |\n             * 60 0x52     | PUSH1 0x52     | dest lte 2w 0 0     |                                 |\n             * 57          | JUMPI          | 2w 0 0              |                                 |\n             *                                                                                      |\n             * ::: copy extra calldata to memory :::::::::::::::::::::::::::::::::::::::::::::::::: |\n             * 36          | CALLDATASIZE   | cds 2w 0 0          |                                 |\n             * 03          | SUB            | t 0 0               |                                 |\n             * 80          | DUP1           | t t 0 0             |                                 |\n             * 60 0x40     | PUSH1 0x40     | 2w t t 0 0          |                                 |\n             * 3d          | RETURNDATASIZE | 0 2w t t 0 0        |                                 |\n             * 37          | CALLDATACOPY   | t 0 0               | [0..t): extra calldata          |\n             *                                                                                      |\n             * ::: delegatecall to implementation ::::::::::::::::::::::::::::::::::::::::::::::::: |\n             * 3d          | RETURNDATASIZE | 0 t 0 0             | [0..t): extra calldata          |\n             * 3d          | RETURNDATASIZE | 0 0 t 0 0           | [0..t): extra calldata          |\n             * 35          | CALLDATALOAD   | i 0 t 0 0           | [0..t): extra calldata          |\n             * 5a          | GAS            | g i 0 t 0 0         | [0..t): extra calldata          |\n             * f4          | DELEGATECALL   | succ                | [0..t): extra calldata          |\n             *                                                                                      |\n             * ::: copy returndata to memory :::::::::::::::::::::::::::::::::::::::::::::::::::::: |\n             * 3d          | RETURNDATASIZE | rds succ            | [0..t): extra calldata          |\n             * 60 0x00     | PUSH1 0x00     | 0 rds succ          | [0..t): extra calldata          |\n             * 80          | DUP1           | 0 0 rds succ        | [0..t): extra calldata          |\n             * 3e          | RETURNDATACOPY | succ                | [0..returndatasize): returndata |\n             *                                                                                      |\n             * ::: branch on delegatecall status :::::::::::::::::::::::::::::::::::::::::::::::::: |\n             * 60 0x52     | PUSH1 0x52     | dest succ           | [0..returndatasize): returndata |\n             * 57          | JUMPI          |                     | [0..returndatasize): returndata |\n             *                                                                                      |\n             * ::: delegatecall failed, revert :::::::::::::::::::::::::::::::::::::::::::::::::::: |\n             * 3d          | RETURNDATASIZE | rds                 | [0..returndatasize): returndata |\n             * 60 0x00     | PUSH1 0x00     | 0 rds               | [0..returndatasize): returndata |\n             * fd          | REVERT         |                     | [0..returndatasize): returndata |\n             * -------------------------------------------------------------------------------------+\n             */\n            m := mload(0x40)\n            // forgefmt: disable-start\n            switch shr(112, address())\n            case 0 {\n                // If the factory's address has six or more leading zero bytes.\n                mstore(add(m, 0x75), 0x604c573d6000fd) // 7\n                mstore(add(m, 0x6e), 0x3d3560203555604080361115604c5736038060403d373d3d355af43d6000803e) // 32\n                mstore(add(m, 0x4e), 0x3735a920a3ca505d382bbc545af43d6000803e604c573d6000fd5b3d6000f35b) // 32\n                mstore(add(m, 0x2e), 0x14605157363d3d37363d7f360894a13ba1a3210667c828492db98dca3e2076cc) // 32\n                mstore(add(m, 0x0e), address()) // 14\n                mstore(m, 0x60793d8160093d39f33d3d336d) // 9 + 4\n            }\n            default {\n                mstore(add(m, 0x7b), 0x6052573d6000fd) // 7\n                mstore(add(m, 0x74), 0x3d356020355560408036111560525736038060403d373d3d355af43d6000803e) // 32\n                mstore(add(m, 0x54), 0x3735a920a3ca505d382bbc545af43d6000803e6052573d6000fd5b3d6000f35b) // 32\n                mstore(add(m, 0x34), 0x14605757363d3d37363d7f360894a13ba1a3210667c828492db98dca3e2076cc) // 32\n                mstore(add(m, 0x14), address()) // 20\n                mstore(m, 0x607f3d8160093d39f33d3d3373) // 9 + 4\n            }\n            // forgefmt: disable-end\n        }\n    }\n}\n\n/// @title Wrapped Ether Hook\n/// @notice Hook for wrapping/unwrapping ETH in Uniswap V4 pools\n/// @dev Implements 1:1 wrapping/unwrapping of ETH to WETH\ncontract WETHHook is BaseTokenWrapperHook {\n    /// @notice The WETH9 contract\n    WETH public immutable weth;\n\n    /// @notice Creates a new WETH wrapper hook\n    /// @param _manager The Uniswap V4 pool manager\n    /// @param _weth The WETH9 contract address\n    constructor(IPoolManager _manager, address payable _weth)\n        BaseTokenWrapperHook(\n            _manager,\n            Currency.wrap(_weth), // wrapper token is WETH\n            CurrencyLibrary.ADDRESS_ZERO // underlying token is ETH (address(0))\n        )\n    {\n        weth = WETH(payable(_weth));\n    }\n}\n\n// https://github.com/foundry-rs/foundry/issues/12529\nlibrary TransferMessageLib {\n    struct TransferMessage {\n        bytes32 sender;\n        address receiver;\n        address token;\n        uint256 amount;\n    }\n\n    function pack(TransferMessage memory m)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        return \"\";\n    }\n}\n\ncontract ChainedStructCall {\n    using TransferMessageLib for TransferMessageLib.TransferMessage;\n    bytes32 someBytes32Value;\n    address someAddressValue;\n    uint256 someUint256Value;\n\n    function test_chainedStructIndentation() public {\n        bytes memory payload = TransferMessageLib.TransferMessage({\n            sender: someBytes32Value,\n            receiver: someAddressValue,\n            token: someAddressValue,\n            amount: someUint256Value\n        }).pack();\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/Repros/tab.fmt.sol",
    "content": "// config: style = \"tab\"\n// Repros of fmt issues\n\n// https://github.com/foundry-rs/foundry/issues/7944\nimport {ERC20} from \"@contracts/token/ERC20/ERC20.sol\";\nimport {ERC20Permit} from \"@contracts/token/ERC20/ext/ERC20Permit.sol\";\nimport {ERC20Burnable} from \"@contracts/token/ERC20/ext/ERC20Burnable.sol\";\nimport {IERC20} from \"@contracts/token/ERC20/IERC20.sol\";\nimport {IERC20Permit} from \"@contracts/token/ERC20/ext/ERC20Permit.sol\";\nimport {AccessControl} from \"@contracts/access/AccessControl.sol\";\n\n// https://github.com/foundry-rs/foundry/issues/4403\nfunction errorIdentifier() {\n\tbytes memory error = bytes(\"\");\n\tif (error.length > 0) {}\n}\n\n// https://github.com/foundry-rs/foundry/issues/7549\nfunction one() external {\n\tthis.other({\n\t\tdata: abi.encodeCall(\n\t\t\tthis.other,\n\t\t\t(\"bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla\")\n\t\t)\n\t});\n}\n\n// https://github.com/foundry-rs/foundry/issues/3979\ncontract Format {\n\tbool public test;\n\n\tfunction testing(uint256 amount) public payable {\n\t\tif (\n\t\t\t// This is a comment\n\t\t\tmsg.value == amount\n\t\t) {\n\t\t\ttest = true;\n\t\t} else {\n\t\t\ttest = false;\n\t\t}\n\n\t\tif (\n\t\t\t// Another one\n\t\t\tblock.timestamp >= amount\n\t\t) {}\n\t}\n}\n\n// https://github.com/foundry-rs/foundry/issues/3830\ncontract TestContract {\n\tfunction test(uint256 a) public {\n\t\tif (a > 1) {\n\t\t\ta = 2;\n\t\t} // forgefmt: disable-line\n\t}\n\n\tfunction test1() public {\n\t\tassembly { sstore(   1,    1) /* inline comment*/ // forgefmt: disable-line\n\t\t\tsstore(2, 2)\n\t\t}\n\t}\n\n\tfunction test2() public {\n\t\tassembly { sstore(   1,    1) // forgefmt: disable-line\n\t\t\tsstore(2, 2)\n\t\t\tsstore(3,    3) // forgefmt: disable-line\n\t\t\tsstore(4, 4)\n\t\t}\n\t}\n\n\tfunction test3() public {\n\t\t// forgefmt: disable-next-line\n\t\tassembly{ sstore(   1,    1)\n\t\t\tsstore(2, 2)\n\t\t\tsstore(3,    3) // forgefmt: disable-line\n\t\t\tsstore(4, 4)\n\t\t} // forgefmt: disable-line\n\t}\n\n\tfunction test4() public {\n\t\t// forgefmt: disable-next-line\n\t\t\t\t  assembly {\n\t\t\tsstore(1, 1)\n\t\t\tsstore(2, 2)\n\t\t\tsstore(3,    3) // forgefmt: disable-line\n\t\t\tsstore(4, 4)\n\t\t} // forgefmt: disable-line\n\t\tif (condition) execute(); // comment7\n\t}\n\n\tfunction test5() public {\n\t\tassembly { sstore(0, 0) }// forgefmt: disable-line\n\t}\n\n\tfunction test6() returns (bool) { // forgefmt: disable-line\n\t\tif (  true  ) {  // forgefmt: disable-line\n\t\t}\n\t\treturn true ;  }  // forgefmt: disable-line\n\n\tfunction test7() returns (bool) { // forgefmt: disable-line\n\t\tif (true) {  // forgefmt: disable-line\n\t\t\tuint256 a     =     1; // forgefmt: disable-line\n\t\t}\n\t\treturn true;\n\t}\n\n\tfunction test8() returns (bool) { // forgefmt: disable-line\n\t\tif (  true  ) {\t// forgefmt: disable-line\n\t\t\tuint256 a = 1;\n\t\t} else {\n\t\t\tuint256 b     =     1; // forgefmt: disable-line\n\t\t}\n\t\treturn true;\n\t}\n}\n\n// https://github.com/foundry-rs/foundry/issues/5825\nlibrary MyLib {\n\tbytes32 private constant TYPE_HASH = keccak256(\n\t\t// forgefmt: disable-start\n\t\t\"MyStruct(\"\n\t\t\t\"uint8 myEnum,\"\n\t\t\t\t\"address myAddress\"\n\t\t\t\t\t\")\"\n\t\t// forgefmt: disable-end\n\t);\n\n\tbytes32 private constant TYPE_HASH_1 = keccak256(\n\t\t\"MyStruct(\"    \"uint8 myEnum,\"    \"address myAddress\"    \")\" // forgefmt: disable-line\n\t);\n\n\t// forgefmt: disable-start\n\tbytes32 private constant TYPE_HASH_2 = keccak256(\n\t\t\"MyStruct(\"\n\t\t\t\"uint8 myEnum,\"\n\t\t\t\"address myAddress\"\n\t\t\")\"\n\t);\n\t// forgefmt: disable-end\n}\n\ncontract IfElseTest {\n\tfunction setNumber(uint256 newNumber) public {\n\t\tnumber = newNumber;\n\t\tif (newNumber = 1) {\n\t\t\tnumber = 1;\n\t\t} else if (newNumber = 2) {\n\t\t\t//            number = 2;\n\t\t} else {\n\t\t\tnewNumber = 3;\n\t\t}\n\t}\n}\n\ncontract DbgFmtTest is Test {\n\tfunction test_argsList() public {\n\t\tuint256 result1 = internalNoArgs({});\n\t\tresult2 = add({a: 1, b: 2});\n\t}\n\n\tfunction add(uint256 a, uint256 b) internal pure returns (uint256) {\n\t\treturn a + b;\n\t}\n\n\tfunction internalNoArgs() internal pure returns (uint256) {\n\t\treturn 0;\n\t}\n}\n\n// https://github.com/foundry-rs/foundry/issues/8557\n// https://github.com/foundry-rs/foundry/issues/11249\nfunction argListRepro(address tokenIn, uint256 amountIn, bool data) {\n\tmaverickV2SwapCallback(\n\t\ttokenIn,\n\t\tamountIn, // forgefmt: disable-line\n\t\t// forgefmt: disable-next-line\n\t\t0 /* we didn't bother loading `amountOut` because we don't use it */,\n\t\tdata\n\t);\n}\n\n// https://github.com/foundry-rs/foundry/issues/11905\nfunction noBlanksLinesBeforeIdentifiers() public {\n\ttimelockController.grantRole(keccak256(\"EXECUTOR_ROLE\"), address(0));\n}\n\n// https://github.com/foundry-rs/foundry/issues/11913\nfunction rustfmtBlankLinesInStmtBlocks() public {\n\tif (someCondition) {\n\t\tbar = true;\n\n\t\temit Foo(bar);\n\t}\n}\n\ncontract NestedCallsTest is Test {\n\tstring constant errMsg = \"User provided message\";\n\tuint256 constant maxDecimals = 77;\n\n\tVm constant vm = Vm(HEVM_ADDRESS);\n\n\tfunction test_nestedCalls() public {\n\t\tvm._expectCheatcodeRevert(\n\t\t\tbytes(string.concat(errMsg, \": \", left, \" != \", right))\n\t\t);\n\t}\n\n\tfunction test_assemblyFnComments() public {\n\t\tassembly {\n\t\t\tfunction setJPoint(i, x, y, z) {\n\t\t\t\t// We will multiply by `0x80` (i.e. `shl(7, i)`) instead\n\t\t\t\t// since the memory expansion costs are cheaper than doing `mul(0x60, i)`.\n\t\t\t\t// Also help combine the lookup expression for `u1` and `u2` in `jMultShamir`.\n\t\t\t\ti := shl(7, i)\n\t\t\t\tmstore(i, x)\n\t\t\t\tmstore(add(i, returndatasize()), y)\n\t\t\t\tmstore(add(i, 0x40), z)\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction test_binOpsInsideNestedBlocks() public {\n\t\tfor (uint256 i = 0; i < steps.length; i++) {\n\t\t\tif (\n\t\t\t\tstep.opcode == 0x52\n\t\t\t\t\t&& /*MSTORE*/ step.stack[0] == testContract.memPtr() // MSTORE offset\n\t\t\t\t\t&& step.stack[1] == testContract.expectedValueInMemory() // MSTORE val\n\t\t\t) {\n\t\t\t\tmstoreCalled = true;\n\t\t\t}\n\t\t}\n\t}\n}\n\ncontract ERC1967Factory {\n\t/// @dev Returns a pointer to the initialization code of a proxy created via this factory.\n\tfunction _initCode() internal view returns (bytes32 m) {\n\t\tassembly {\n\t\t\t/**\n\t\t\t *\t-------------------------------------------------------------------------------------+\n\t\t\t *\tCREATION (9 bytes)                                                                   |\n\t\t\t *\t-------------------------------------------------------------------------------------|\n\t\t\t *\tOpcode     | Mnemonic        | Stack               | Memory                          |\n\t\t\t *\t-------------------------------------------------------------------------------------|\n\t\t\t *\t60 runSize | PUSH1 runSize   | r                   |                                 |\n\t\t\t *\t3d         | RETURNDATASIZE  | 0 r                 |                                 |\n\t\t\t *\t81         | DUP2            | r 0 r               |                                 |\n\t\t\t *\t60 offset  | PUSH1 offset    | o r 0 r             |                                 |\n\t\t\t *\t3d         | RETURNDATASIZE  | 0 o r 0 r           |                                 |\n\t\t\t *\t39         | CODECOPY        | 0 r                 | [0..runSize): runtime code      |\n\t\t\t *\tf3         | RETURN          |                     | [0..runSize): runtime code      |\n\t\t\t *\t-------------------------------------------------------------------------------------|\n\t\t\t *\tRUNTIME (127 bytes)                                                                  |\n\t\t\t *\t-------------------------------------------------------------------------------------|\n\t\t\t *\tOpcode      | Mnemonic       | Stack               | Memory                          |\n\t\t\t *\t-------------------------------------------------------------------------------------|\n\t\t\t *\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t|\n\t\t\t *\t::: keep some values in stack :::::::::::::::::::::::::::::::::::::::::::::::::::::: |\n\t\t\t *\t3d          | RETURNDATASIZE | 0                   |                                 |\n\t\t\t *\t3d          | RETURNDATASIZE | 0 0                 |                                 |\n\t\t\t *\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t|\n\t\t\t *\t::: check if caller is factory ::::::::::::::::::::::::::::::::::::::::::::::::::::: |\n\t\t\t *\t33          | CALLER         | c 0 0               |                                 |\n\t\t\t *\t73 factory  | PUSH20 factory | f c 0 0             |                                 |\n\t\t\t *\t14          | EQ             | isf 0 0             |                                 |\n\t\t\t *\t60 0x57     | PUSH1 0x57     | dest isf 0 0        |                                 |\n\t\t\t *\t57          | JUMPI          | 0 0                 |                                 |\n\t\t\t *\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t|\n\t\t\t *\t::: copy calldata to memory :::::::::::::::::::::::::::::::::::::::::::::::::::::::: |\n\t\t\t *\t36          | CALLDATASIZE   | cds 0 0             |                                 |\n\t\t\t *\t3d          | RETURNDATASIZE | 0 cds 0 0           |                                 |\n\t\t\t *\t3d          | RETURNDATASIZE | 0 0 cds 0 0         |                                 |\n\t\t\t *\t37          | CALLDATACOPY   | 0 0                 | [0..calldatasize): calldata     |\n\t\t\t *\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t|\n\t\t\t *\t::: delegatecall to implementation ::::::::::::::::::::::::::::::::::::::::::::::::: |\n\t\t\t *\t36          | CALLDATASIZE   | cds 0 0             | [0..calldatasize): calldata     |\n\t\t\t *\t3d          | RETURNDATASIZE | 0 cds 0 0           | [0..calldatasize): calldata     |\n\t\t\t *\t7f slot     | PUSH32 slot    | s 0 cds 0 0         | [0..calldatasize): calldata     |\n\t\t\t *\t54          | SLOAD          | i 0 cds 0 0         | [0..calldatasize): calldata     |\n\t\t\t *\t5a          | GAS            | g i 0 cds 0 0       | [0..calldatasize): calldata     |\n\t\t\t *\tf4          | DELEGATECALL   | succ                | [0..calldatasize): calldata     |\n\t\t\t *\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t|\n\t\t\t *\t::: copy returndata to memory :::::::::::::::::::::::::::::::::::::::::::::::::::::: |\n\t\t\t *\t3d          | RETURNDATASIZE | rds succ            | [0..calldatasize): calldata     |\n\t\t\t *\t60 0x00     | PUSH1 0x00     | 0 rds succ          | [0..calldatasize): calldata     |\n\t\t\t *\t80          | DUP1           | 0 0 rds succ        | [0..calldatasize): calldata     |\n\t\t\t *\t3e          | RETURNDATACOPY | succ                | [0..returndatasize): returndata |\n\t\t\t *\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t|\n\t\t\t *\t::: branch on delegatecall status :::::::::::::::::::::::::::::::::::::::::::::::::: |\n\t\t\t *\t60 0x52     | PUSH1 0x52     | dest succ           | [0..returndatasize): returndata |\n\t\t\t *\t57          | JUMPI          |                     | [0..returndatasize): returndata |\n\t\t\t *\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t|\n\t\t\t *\t::: delegatecall failed, revert :::::::::::::::::::::::::::::::::::::::::::::::::::: |\n\t\t\t *\t3d          | RETURNDATASIZE | rds                 | [0..returndatasize): returndata |\n\t\t\t *\t60 0x00     | PUSH1 0x00     | 0 rds               | [0..returndatasize): returndata |\n\t\t\t *\tfd          | REVERT         |                     | [0..returndatasize): returndata |\n\t\t\t *\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t|\n\t\t\t *\t::: delegatecall succeeded, return ::::::::::::::::::::::::::::::::::::::::::::::::: |\n\t\t\t *\t5b          | JUMPDEST       |                     | [0..returndatasize): returndata |\n\t\t\t *\t3d          | RETURNDATASIZE | rds                 | [0..returndatasize): returndata |\n\t\t\t *\t60 0x00     | PUSH1 0x00     | 0 rds               | [0..returndatasize): returndata |\n\t\t\t *\tf3          | RETURN         |                     | [0..returndatasize): returndata |\n\t\t\t *\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t|\n\t\t\t *\t::: set new implementation (caller is factory) ::::::::::::::::::::::::::::::::::::: |\n\t\t\t *\t5b          | JUMPDEST       | 0 0                 |                                 |\n\t\t\t *\t3d          | RETURNDATASIZE | 0 0 0               |                                 |\n\t\t\t *\t35          | CALLDATALOAD   | impl 0 0            |                                 |\n\t\t\t *\t60 0x20     | PUSH1 0x20     | w impl 0 0          |                                 |\n\t\t\t *\t35          | CALLDATALOAD   | slot impl 0 0       |                                 |\n\t\t\t *\t55          | SSTORE         | 0 0                 |                                 |\n\t\t\t *\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t|\n\t\t\t *\t::: no extra calldata, return :::::::::::::::::::::::::::::::::::::::::::::::::::::: |\n\t\t\t *\t60 0x40     | PUSH1 0x40     | 2w 0 0              |                                 |\n\t\t\t *\t80          | DUP1           | 2w 2w 0 0           |                                 |\n\t\t\t *\t36          | CALLDATASIZE   | cds 2w 2w 0 0       |                                 |\n\t\t\t *\t11          | GT             | gt 2w 0 0           |                                 |\n\t\t\t *\t15          | ISZERO         | lte 2w 0 0          |                                 |\n\t\t\t *\t60 0x52     | PUSH1 0x52     | dest lte 2w 0 0     |                                 |\n\t\t\t *\t57          | JUMPI          | 2w 0 0              |                                 |\n\t\t\t *\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t|\n\t\t\t *\t::: copy extra calldata to memory :::::::::::::::::::::::::::::::::::::::::::::::::: |\n\t\t\t *\t36          | CALLDATASIZE   | cds 2w 0 0          |                                 |\n\t\t\t *\t03          | SUB            | t 0 0               |                                 |\n\t\t\t *\t80          | DUP1           | t t 0 0             |                                 |\n\t\t\t *\t60 0x40     | PUSH1 0x40     | 2w t t 0 0          |                                 |\n\t\t\t *\t3d          | RETURNDATASIZE | 0 2w t t 0 0        |                                 |\n\t\t\t *\t37          | CALLDATACOPY   | t 0 0               | [0..t): extra calldata          |\n\t\t\t *\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t|\n\t\t\t *\t::: delegatecall to implementation ::::::::::::::::::::::::::::::::::::::::::::::::: |\n\t\t\t *\t3d          | RETURNDATASIZE | 0 t 0 0             | [0..t): extra calldata          |\n\t\t\t *\t3d          | RETURNDATASIZE | 0 0 t 0 0           | [0..t): extra calldata          |\n\t\t\t *\t35          | CALLDATALOAD   | i 0 t 0 0           | [0..t): extra calldata          |\n\t\t\t *\t5a          | GAS            | g i 0 t 0 0         | [0..t): extra calldata          |\n\t\t\t *\tf4          | DELEGATECALL   | succ                | [0..t): extra calldata          |\n\t\t\t *\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t|\n\t\t\t *\t::: copy returndata to memory :::::::::::::::::::::::::::::::::::::::::::::::::::::: |\n\t\t\t *\t3d          | RETURNDATASIZE | rds succ            | [0..t): extra calldata          |\n\t\t\t *\t60 0x00     | PUSH1 0x00     | 0 rds succ          | [0..t): extra calldata          |\n\t\t\t *\t80          | DUP1           | 0 0 rds succ        | [0..t): extra calldata          |\n\t\t\t *\t3e          | RETURNDATACOPY | succ                | [0..returndatasize): returndata |\n\t\t\t *\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t|\n\t\t\t *\t::: branch on delegatecall status :::::::::::::::::::::::::::::::::::::::::::::::::: |\n\t\t\t *\t60 0x52     | PUSH1 0x52     | dest succ           | [0..returndatasize): returndata |\n\t\t\t *\t57          | JUMPI          |                     | [0..returndatasize): returndata |\n\t\t\t *\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t|\n\t\t\t *\t::: delegatecall failed, revert :::::::::::::::::::::::::::::::::::::::::::::::::::: |\n\t\t\t *\t3d          | RETURNDATASIZE | rds                 | [0..returndatasize): returndata |\n\t\t\t *\t60 0x00     | PUSH1 0x00     | 0 rds               | [0..returndatasize): returndata |\n\t\t\t *\tfd          | REVERT         |                     | [0..returndatasize): returndata |\n\t\t\t *\t-------------------------------------------------------------------------------------+\n\t\t\t */\n\t\t\tm := mload(0x40)\n\t\t\t// forgefmt: disable-start\n\t\t\tswitch shr(112, address())\n\t\t\tcase 0 {\n\t\t\t\t// If the factory's address has six or more leading zero bytes.\n\t\t\t\tmstore(add(m, 0x75), 0x604c573d6000fd) // 7\n\t\t\t\tmstore(add(m, 0x6e), 0x3d3560203555604080361115604c5736038060403d373d3d355af43d6000803e) // 32\n\t\t\t\tmstore(add(m, 0x4e), 0x3735a920a3ca505d382bbc545af43d6000803e604c573d6000fd5b3d6000f35b) // 32\n\t\t\t\tmstore(add(m, 0x2e), 0x14605157363d3d37363d7f360894a13ba1a3210667c828492db98dca3e2076cc) // 32\n\t\t\t\tmstore(add(m, 0x0e), address()) // 14\n\t\t\t\tmstore(m, 0x60793d8160093d39f33d3d336d) // 9 + 4\n\t\t\t}\n\t\t\tdefault {\n\t\t\t\tmstore(add(m, 0x7b), 0x6052573d6000fd) // 7\n\t\t\t\tmstore(add(m, 0x74), 0x3d356020355560408036111560525736038060403d373d3d355af43d6000803e) // 32\n\t\t\t\tmstore(add(m, 0x54), 0x3735a920a3ca505d382bbc545af43d6000803e6052573d6000fd5b3d6000f35b) // 32\n\t\t\t\tmstore(add(m, 0x34), 0x14605757363d3d37363d7f360894a13ba1a3210667c828492db98dca3e2076cc) // 32\n\t\t\t\tmstore(add(m, 0x14), address()) // 20\n\t\t\t\tmstore(m, 0x607f3d8160093d39f33d3d3373) // 9 + 4\n\t\t\t}\n\t\t\t// forgefmt: disable-end\n\t\t}\n\t}\n}\n\n/// @title Wrapped Ether Hook\n/// @notice Hook for wrapping/unwrapping ETH in Uniswap V4 pools\n/// @dev Implements 1:1 wrapping/unwrapping of ETH to WETH\ncontract WETHHook is BaseTokenWrapperHook {\n\t/// @notice The WETH9 contract\n\tWETH public immutable weth;\n\n\t/// @notice Creates a new WETH wrapper hook\n\t/// @param _manager The Uniswap V4 pool manager\n\t/// @param _weth The WETH9 contract address\n\tconstructor(IPoolManager _manager, address payable _weth)\n\t\tBaseTokenWrapperHook(\n\t\t\t_manager,\n\t\t\tCurrency.wrap(_weth), // wrapper token is WETH\n\t\t\tCurrencyLibrary.ADDRESS_ZERO // underlying token is ETH (address(0))\n\t\t)\n\t{\n\t\tweth = WETH(payable(_weth));\n\t}\n}\n\n// https://github.com/foundry-rs/foundry/issues/12529\nlibrary TransferMessageLib {\n\tstruct TransferMessage {\n\t\tbytes32 sender;\n\t\taddress receiver;\n\t\taddress token;\n\t\tuint256 amount;\n\t}\n\n\tfunction pack(TransferMessage memory m)\n\t\tinternal\n\t\tpure\n\t\treturns (bytes memory)\n\t{\n\t\treturn \"\";\n\t}\n}\n\ncontract ChainedStructCall {\n\tusing TransferMessageLib for TransferMessageLib.TransferMessage;\n\tbytes32 someBytes32Value;\n\taddress someAddressValue;\n\tuint256 someUint256Value;\n\n\tfunction test_chainedStructIndentation() public {\n\t\tbytes memory payload = TransferMessageLib.TransferMessage({\n\t\t\tsender: someBytes32Value,\n\t\t\treceiver: someAddressValue,\n\t\t\ttoken: someAddressValue,\n\t\t\tamount: someUint256Value\n\t\t}).pack();\n\t}\n}\n"
  },
  {
    "path": "crates/fmt/testdata/ReprosCalls/110.fmt.sol",
    "content": "// config: line_length = 110\nfunction repros() public {\n    require(\n        keccak256(abi.encodePacked(\"this is a long string\"))\n            == keccak256(abi.encodePacked(\"some other long string\")),\n        \"string mismatch\"\n    );\n\n    address lerp =\n        LerpFactoryLike(lerpFab()).newLerp(_name, _target, _what, _startTime, _start, _end, _duration);\n\n    (oracleRouter, eVault) = execute(\n        oracleRouterFactory, deployRouterForOracle, eVaultFactory, upgradable, asset, oracle, unitOfAccount\n    );\n\n    if (eVault == address(0)) {\n        eVault = address(\n            GenericFactory(eVaultFactory)\n                .createProxy(address(0), true, abi.encodePacked(asset, address(0), address(0)))\n        );\n    }\n\n    content = string.concat(\n        \"{\\\"description\\\": \\\"\",\n        description,\n        \"\\\", \\\"name\\\": \\\"0x Settler feature \",\n        ItoA.itoa(Feature.unwrap(feature)),\n        \"\\\"}\\n\"\n    );\n\n    oracleInfo = abi.encode(\n        LidoOracleInfo({base: IOracle(oracleAddress).WSTETH(), quote: IOracle(oracleAddress).STETH()})\n    );\n\n    return someFunction().getValue().modifyValue().negate().scaleBySomeFactor(1000).transformToTuple();\n\n    SnapshotRegistry(adapterRegistry)\n        .add(adapter, LidoFundamentalOracle(adapter).WSTETH(), LidoFundamentalOracle(adapter).WETH());\n\n    (bool success, bytes memory data) = GenericFactory(eVaultFactory).implementation()\n        .staticcall(abi.encodePacked(EVCUtil.EVC.selector, uint256(0), uint256(0)));\n\n    IEVC.BatchItem[] memory items = new IEVC.BatchItem[](3);\n\n    items[0] = IEVC.BatchItem({\n        onBehalfOfAccount: user,\n        targetContract: address(eGRT),\n        value: 0,\n        data: abi.encodeCall(IERC4626.withdraw, (1500e18, address(swapper), user))\n    });\n    items[1] = IEVC.BatchItem({\n        onBehalfOfAccount: user,\n        targetContract: address(swapper),\n        value: 0,\n        data: abi.encodeCall(Swapper.multicall, multicallItems)\n    });\n    items[2] = IEVC.BatchItem({\n        onBehalfOfAccount: user,\n        targetContract: address(swapVerifier),\n        value: 0,\n        data: abi.encodeCall(\n            swapVerifier.verifyDebtMax, (address(eSTETH), user, exactOutTolerance, type(uint256).max)\n        )\n    });\n\n    uint256 fork = vm.createSelectFork(\"arbitrum\", bytes32(0xdeadc0ffeedeadbeef));\n\n    ConstructorVictim victim = new ConstructorVictim(sender, \"msg.sender\", \"not set during prank\");\n\n    vm._expectCheatcodeRevert(\"short msg doesn't break\");\n    vm._expectCheatcodeRevert(\"failed parsing as `uint256`: missing hex prefix for hex string\");\n    vm.thisIsJustAReallyLongMemberWithoutAcall.LetsSeeHowItBreaks.willItBreakAsIntendedOrNot;\n\n    bytes4[] memory targets = new bytes4[](0);\n    targets[0] = FuzzArtifactSelector(\"TargetArtifactSelectors.t.sol:Hi\", selectors);\n\n    emit IERC712View.Transfer(Create3.predict(_salt, address(_deployer)), address(o), id);\n\n    return _verifyDeploymentRootHash(_getMerkleRoot(proof, hash), originalOwner)\n        .ternary(IERC1271.isValidSignature.selector, bytes4(0xffffffff));\n}\n\nfunction returnLongBinaryOp() returns (bytes32) {\n    return bytes32(\n        uint256(Feature.unwrap(feature)) << 128 | uint256(block.chainid) << 64 | uint256(Nonce.unwrap(nonce))\n    );\n}\n\ncontract Repros {\n    function test() public {\n        uint256 globalBuyAmount =\n            Take.take(state, notes, uint32(IPoolManager.take.selector), recipient, minBuyAmount);\n        uint256 globalBuyAmount =\n            Take.take(state, notes, uint32(IPoolManager.take.selector), recipient, minBuyAmount);\n\n        {\n            u.executionData = _transferExecution(address(paymentToken), address(0xabcd), 1 ether);\n            u.executionData = _transferExecution(address(paymentToken), address(0xabcd), 1 ether);\n        }\n\n        ISettlerBase.AllowedSlippage memory allowedSlippage = ISettlerBase.AllowedSlippage({\n            recipient: payable(address(0)), buyToken: IERC20(address(0)), minAmountOut: 0\n        });\n        ISettlerBase.AllowedSlippage memory allowedSlippage = ISettlerBase.AllowedSlippage({\n            recipient: payable(address(0)), buyToken: IERC20(address(0)), minAmountOut: 0\n        });\n\n        ISignatureTransfer.PermitTransferFrom memory permit = defaultERC20PermitTransfer(\n            address(fromToken()),\n            amount(),\n            0 /* nonce */\n        );\n        ISignatureTransfer.PermitTransferFrom memory permit = defaultERC20PermitTransfer(\n            address(fromToken()),\n            amount(),\n            0 /* nonce */\n        );\n\n        // https://github.com/foundry-rs/foundry/issues/11834\n        CurrenciesOutOfOrderOrEqual.selector\n            .revertWith(Currency.unwrap(key.currency0), Currency.unwrap(key.currency1));\n\n        nestedStruct.withCalls.thatCause\n            .aBreak(\n                param1,\n                param2,\n                param3 // long line\n            );\n\n        // https://github.com/foundry-rs/foundry/issues/11835\n        feeGrowthInside0X128 =\n            self.feeGrowthGlobal0X128 - lower.feeGrowthOutside0X128 - upper.feeGrowthOutside0X128;\n        feeGrowthInside0X128 =\n            self.feeGrowthGlobal0X128 - lower.feeGrowthOutside0X128 - upper.feeGrowthOutside0X128;\n\n        // https://github.com/foundry-rs/foundry/issues/11875\n        lpTail = LpPosition({\n            tickLower: posTickLower, tickUpper: posTickUpper, liquidity: lpTailLiquidity, id: uint16(id)\n        });\n    }\n\n    // https://github.com/foundry-rs/foundry/issues/11834\n    function test_ffi_fuzz_addLiquidity_defaultPool(IPoolManager.ModifyLiquidityParams memory paramSeed)\n        public\n    {\n        a = 1;\n    }\n\n    // https://github.com/foundry-rs/foundry/issues/12324\n    function test_longCallWithOpts() {\n        flow.withdraw{value: FLOW_MIN_FEE_WEI}({\n            streamId: defaultStreamId, to: users.eve, amount: WITHDRAW_AMOUNT_6D\n        });\n        flow.withdraw{\n            value: FLOW_MIN_FEE_WEI /* cmnt */\n        }({\n            streamId: defaultStreamId,\n            to: users.eve,\n            /* cmnt */\n            amount: WITHDRAW_AMOUNT_6D\n        });\n        flow.withdraw{value: FLOW_MIN_FEE_WEI}({ // cmnt\n            streamId: defaultStreamId, to: users.eve, amount: WITHDRAW_AMOUNT_6D\n        });\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/ReprosCalls/120.fmt.sol",
    "content": "// config: line_length = 120\n// config: bracket_spacing = true\nfunction repros() public {\n    require(\n        keccak256(abi.encodePacked(\"this is a long string\")) == keccak256(abi.encodePacked(\"some other long string\")),\n        \"string mismatch\"\n    );\n\n    address lerp = LerpFactoryLike(lerpFab()).newLerp(_name, _target, _what, _startTime, _start, _end, _duration);\n\n    (oracleRouter, eVault) =\n        execute(oracleRouterFactory, deployRouterForOracle, eVaultFactory, upgradable, asset, oracle, unitOfAccount);\n\n    if (eVault == address(0)) {\n        eVault = address(\n            GenericFactory(eVaultFactory).createProxy(address(0), true, abi.encodePacked(asset, address(0), address(0)))\n        );\n    }\n\n    content = string.concat(\n        \"{\\\"description\\\": \\\"\",\n        description,\n        \"\\\", \\\"name\\\": \\\"0x Settler feature \",\n        ItoA.itoa(Feature.unwrap(feature)),\n        \"\\\"}\\n\"\n    );\n\n    oracleInfo =\n        abi.encode(LidoOracleInfo({ base: IOracle(oracleAddress).WSTETH(), quote: IOracle(oracleAddress).STETH() }));\n\n    return someFunction().getValue().modifyValue().negate().scaleBySomeFactor(1000).transformToTuple();\n\n    SnapshotRegistry(adapterRegistry)\n        .add(adapter, LidoFundamentalOracle(adapter).WSTETH(), LidoFundamentalOracle(adapter).WETH());\n\n    (bool success, bytes memory data) = GenericFactory(eVaultFactory).implementation()\n        .staticcall(abi.encodePacked(EVCUtil.EVC.selector, uint256(0), uint256(0)));\n\n    IEVC.BatchItem[] memory items = new IEVC.BatchItem[](3);\n\n    items[0] = IEVC.BatchItem({\n        onBehalfOfAccount: user,\n        targetContract: address(eGRT),\n        value: 0,\n        data: abi.encodeCall(IERC4626.withdraw, (1500e18, address(swapper), user))\n    });\n    items[1] = IEVC.BatchItem({\n        onBehalfOfAccount: user,\n        targetContract: address(swapper),\n        value: 0,\n        data: abi.encodeCall(Swapper.multicall, multicallItems)\n    });\n    items[2] = IEVC.BatchItem({\n        onBehalfOfAccount: user,\n        targetContract: address(swapVerifier),\n        value: 0,\n        data: abi.encodeCall(swapVerifier.verifyDebtMax, (address(eSTETH), user, exactOutTolerance, type(uint256).max))\n    });\n\n    uint256 fork = vm.createSelectFork(\"arbitrum\", bytes32(0xdeadc0ffeedeadbeef));\n\n    ConstructorVictim victim = new ConstructorVictim(sender, \"msg.sender\", \"not set during prank\");\n\n    vm._expectCheatcodeRevert(\"short msg doesn't break\");\n    vm._expectCheatcodeRevert(\"failed parsing as `uint256`: missing hex prefix for hex string\");\n    vm.thisIsJustAReallyLongMemberWithoutAcall.LetsSeeHowItBreaks.willItBreakAsIntendedOrNot;\n\n    bytes4[] memory targets = new bytes4[](0);\n    targets[0] = FuzzArtifactSelector(\"TargetArtifactSelectors.t.sol:Hi\", selectors);\n\n    emit IERC712View.Transfer(Create3.predict(_salt, address(_deployer)), address(o), id);\n\n    return _verifyDeploymentRootHash(_getMerkleRoot(proof, hash), originalOwner)\n        .ternary(IERC1271.isValidSignature.selector, bytes4(0xffffffff));\n}\n\nfunction returnLongBinaryOp() returns (bytes32) {\n    return\n        bytes32(uint256(Feature.unwrap(feature)) << 128 | uint256(block.chainid) << 64 | uint256(Nonce.unwrap(nonce)));\n}\n\ncontract Repros {\n    function test() public {\n        uint256 globalBuyAmount = Take.take(state, notes, uint32(IPoolManager.take.selector), recipient, minBuyAmount);\n        uint256 globalBuyAmount = Take.take(state, notes, uint32(IPoolManager.take.selector), recipient, minBuyAmount);\n\n        {\n            u.executionData = _transferExecution(address(paymentToken), address(0xabcd), 1 ether);\n            u.executionData = _transferExecution(address(paymentToken), address(0xabcd), 1 ether);\n        }\n\n        ISettlerBase.AllowedSlippage memory allowedSlippage = ISettlerBase.AllowedSlippage({\n            recipient: payable(address(0)), buyToken: IERC20(address(0)), minAmountOut: 0\n        });\n        ISettlerBase.AllowedSlippage memory allowedSlippage = ISettlerBase.AllowedSlippage({\n            recipient: payable(address(0)), buyToken: IERC20(address(0)), minAmountOut: 0\n        });\n\n        ISignatureTransfer.PermitTransferFrom memory permit = defaultERC20PermitTransfer(\n            address(fromToken()),\n            amount(),\n            0 /* nonce */\n        );\n        ISignatureTransfer.PermitTransferFrom memory permit = defaultERC20PermitTransfer(\n            address(fromToken()),\n            amount(),\n            0 /* nonce */\n        );\n\n        // https://github.com/foundry-rs/foundry/issues/11834\n        CurrenciesOutOfOrderOrEqual.selector.revertWith(Currency.unwrap(key.currency0), Currency.unwrap(key.currency1));\n\n        nestedStruct.withCalls.thatCause\n            .aBreak(\n                param1,\n                param2,\n                param3 // long line\n            );\n\n        // https://github.com/foundry-rs/foundry/issues/11835\n        feeGrowthInside0X128 = self.feeGrowthGlobal0X128 - lower.feeGrowthOutside0X128 - upper.feeGrowthOutside0X128;\n        feeGrowthInside0X128 = self.feeGrowthGlobal0X128 - lower.feeGrowthOutside0X128 - upper.feeGrowthOutside0X128;\n\n        // https://github.com/foundry-rs/foundry/issues/11875\n        lpTail = LpPosition({\n            tickLower: posTickLower, tickUpper: posTickUpper, liquidity: lpTailLiquidity, id: uint16(id)\n        });\n    }\n\n    // https://github.com/foundry-rs/foundry/issues/11834\n    function test_ffi_fuzz_addLiquidity_defaultPool(IPoolManager.ModifyLiquidityParams memory paramSeed) public {\n        a = 1;\n    }\n\n    // https://github.com/foundry-rs/foundry/issues/12324\n    function test_longCallWithOpts() {\n        flow.withdraw{ value: FLOW_MIN_FEE_WEI }({\n            streamId: defaultStreamId, to: users.eve, amount: WITHDRAW_AMOUNT_6D\n        });\n        flow.withdraw{\n            value: FLOW_MIN_FEE_WEI /* cmnt */\n        }({\n            streamId: defaultStreamId,\n            to: users.eve,\n            /* cmnt */\n            amount: WITHDRAW_AMOUNT_6D\n        });\n        flow.withdraw{ value: FLOW_MIN_FEE_WEI }({ // cmnt\n            streamId: defaultStreamId, to: users.eve, amount: WITHDRAW_AMOUNT_6D\n        });\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/ReprosCalls/80.fmt.sol",
    "content": "// config: line_length = 80\nfunction repros() public {\n    require(\n        keccak256(abi.encodePacked(\"this is a long string\"))\n            == keccak256(abi.encodePacked(\"some other long string\")),\n        \"string mismatch\"\n    );\n\n    address lerp = LerpFactoryLike(lerpFab())\n        .newLerp(_name, _target, _what, _startTime, _start, _end, _duration);\n\n    (oracleRouter, eVault) = execute(\n        oracleRouterFactory,\n        deployRouterForOracle,\n        eVaultFactory,\n        upgradable,\n        asset,\n        oracle,\n        unitOfAccount\n    );\n\n    if (eVault == address(0)) {\n        eVault = address(\n            GenericFactory(eVaultFactory)\n                .createProxy(\n                    address(0),\n                    true,\n                    abi.encodePacked(asset, address(0), address(0))\n                )\n        );\n    }\n\n    content = string.concat(\n        \"{\\\"description\\\": \\\"\",\n        description,\n        \"\\\", \\\"name\\\": \\\"0x Settler feature \",\n        ItoA.itoa(Feature.unwrap(feature)),\n        \"\\\"}\\n\"\n    );\n\n    oracleInfo = abi.encode(\n        LidoOracleInfo({\n            base: IOracle(oracleAddress).WSTETH(),\n            quote: IOracle(oracleAddress).STETH()\n        })\n    );\n\n    return someFunction().getValue().modifyValue().negate()\n        .scaleBySomeFactor(1000).transformToTuple();\n\n    SnapshotRegistry(adapterRegistry)\n        .add(\n            adapter,\n            LidoFundamentalOracle(adapter).WSTETH(),\n            LidoFundamentalOracle(adapter).WETH()\n        );\n\n    (bool success, bytes memory data) = GenericFactory(eVaultFactory)\n        .implementation()\n        .staticcall(\n            abi.encodePacked(EVCUtil.EVC.selector, uint256(0), uint256(0))\n        );\n\n    IEVC.BatchItem[] memory items = new IEVC.BatchItem[](3);\n\n    items[0] = IEVC.BatchItem({\n        onBehalfOfAccount: user,\n        targetContract: address(eGRT),\n        value: 0,\n        data: abi.encodeCall(\n            IERC4626.withdraw, (1500e18, address(swapper), user)\n        )\n    });\n    items[1] = IEVC.BatchItem({\n        onBehalfOfAccount: user,\n        targetContract: address(swapper),\n        value: 0,\n        data: abi.encodeCall(Swapper.multicall, multicallItems)\n    });\n    items[2] = IEVC.BatchItem({\n        onBehalfOfAccount: user,\n        targetContract: address(swapVerifier),\n        value: 0,\n        data: abi.encodeCall(\n            swapVerifier.verifyDebtMax,\n            (address(eSTETH), user, exactOutTolerance, type(uint256).max)\n        )\n    });\n\n    uint256 fork =\n        vm.createSelectFork(\"arbitrum\", bytes32(0xdeadc0ffeedeadbeef));\n\n    ConstructorVictim victim =\n        new ConstructorVictim(sender, \"msg.sender\", \"not set during prank\");\n\n    vm._expectCheatcodeRevert(\"short msg doesn't break\");\n    vm._expectCheatcodeRevert(\n        \"failed parsing as `uint256`: missing hex prefix for hex string\"\n    );\n    vm.thisIsJustAReallyLongMemberWithoutAcall.LetsSeeHowItBreaks\n        .willItBreakAsIntendedOrNot;\n\n    bytes4[] memory targets = new bytes4[](0);\n    targets[0] =\n        FuzzArtifactSelector(\"TargetArtifactSelectors.t.sol:Hi\", selectors);\n\n    emit IERC712View.Transfer(\n        Create3.predict(_salt, address(_deployer)), address(o), id\n    );\n\n    return _verifyDeploymentRootHash(_getMerkleRoot(proof, hash), originalOwner)\n        .ternary(IERC1271.isValidSignature.selector, bytes4(0xffffffff));\n}\n\nfunction returnLongBinaryOp() returns (bytes32) {\n    return bytes32(\n        uint256(Feature.unwrap(feature)) << 128 | uint256(block.chainid) << 64\n            | uint256(Nonce.unwrap(nonce))\n    );\n}\n\ncontract Repros {\n    function test() public {\n        uint256 globalBuyAmount = Take.take(\n            state,\n            notes,\n            uint32(IPoolManager.take.selector),\n            recipient,\n            minBuyAmount\n        );\n        uint256 globalBuyAmount = Take.take(\n            state,\n            notes,\n            uint32(IPoolManager.take.selector),\n            recipient,\n            minBuyAmount\n        );\n\n        {\n            u.executionData = _transferExecution(\n                address(paymentToken), address(0xabcd), 1 ether\n            );\n            u.executionData = _transferExecution(\n                address(paymentToken), address(0xabcd), 1 ether\n            );\n        }\n\n        ISettlerBase.AllowedSlippage memory allowedSlippage =\n            ISettlerBase.AllowedSlippage({\n                recipient: payable(address(0)),\n                buyToken: IERC20(address(0)),\n                minAmountOut: 0\n            });\n        ISettlerBase.AllowedSlippage memory allowedSlippage =\n            ISettlerBase.AllowedSlippage({\n                recipient: payable(address(0)),\n                buyToken: IERC20(address(0)),\n                minAmountOut: 0\n            });\n\n        ISignatureTransfer.PermitTransferFrom memory permit =\n            defaultERC20PermitTransfer(\n                address(fromToken()),\n                amount(),\n                0 /* nonce */\n            );\n        ISignatureTransfer.PermitTransferFrom memory permit =\n            defaultERC20PermitTransfer(\n                address(fromToken()),\n                amount(),\n                0 /* nonce */\n            );\n\n        // https://github.com/foundry-rs/foundry/issues/11834\n        CurrenciesOutOfOrderOrEqual.selector\n            .revertWith(\n                Currency.unwrap(key.currency0), Currency.unwrap(key.currency1)\n            );\n\n        nestedStruct.withCalls.thatCause\n            .aBreak(\n                param1,\n                param2,\n                param3 // long line\n            );\n\n        // https://github.com/foundry-rs/foundry/issues/11835\n        feeGrowthInside0X128 = self.feeGrowthGlobal0X128\n            - lower.feeGrowthOutside0X128 - upper.feeGrowthOutside0X128;\n        feeGrowthInside0X128 = self.feeGrowthGlobal0X128\n            - lower.feeGrowthOutside0X128 - upper.feeGrowthOutside0X128;\n\n        // https://github.com/foundry-rs/foundry/issues/11875\n        lpTail = LpPosition({\n            tickLower: posTickLower,\n            tickUpper: posTickUpper,\n            liquidity: lpTailLiquidity,\n            id: uint16(id)\n        });\n    }\n\n    // https://github.com/foundry-rs/foundry/issues/11834\n    function test_ffi_fuzz_addLiquidity_defaultPool(\n        IPoolManager.ModifyLiquidityParams memory paramSeed\n    ) public {\n        a = 1;\n    }\n\n    // https://github.com/foundry-rs/foundry/issues/12324\n    function test_longCallWithOpts() {\n        flow.withdraw{value: FLOW_MIN_FEE_WEI}({\n            streamId: defaultStreamId, to: users.eve, amount: WITHDRAW_AMOUNT_6D\n        });\n        flow.withdraw{\n            value: FLOW_MIN_FEE_WEI /* cmnt */\n        }({\n            streamId: defaultStreamId,\n            to: users.eve,\n            /* cmnt */\n            amount: WITHDRAW_AMOUNT_6D\n        });\n        flow.withdraw{value: FLOW_MIN_FEE_WEI}({ // cmnt\n            streamId: defaultStreamId, to: users.eve, amount: WITHDRAW_AMOUNT_6D\n        });\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/ReprosCalls/consistent.120.fmt.sol",
    "content": "// config: line_length = 120\n// config: bracket_spacing = true\n// config: prefer_compact = \"none\"\nfunction repros() public {\n    require(\n        keccak256(abi.encodePacked(\"this is a long string\")) == keccak256(abi.encodePacked(\"some other long string\")),\n        \"string mismatch\"\n    );\n\n    address lerp = LerpFactoryLike(lerpFab()).newLerp(_name, _target, _what, _startTime, _start, _end, _duration);\n\n    (oracleRouter, eVault) =\n        execute(oracleRouterFactory, deployRouterForOracle, eVaultFactory, upgradable, asset, oracle, unitOfAccount);\n\n    if (eVault == address(0)) {\n        eVault = address(\n            GenericFactory(eVaultFactory).createProxy(address(0), true, abi.encodePacked(asset, address(0), address(0)))\n        );\n    }\n\n    content = string.concat(\n        \"{\\\"description\\\": \\\"\",\n        description,\n        \"\\\", \\\"name\\\": \\\"0x Settler feature \",\n        ItoA.itoa(Feature.unwrap(feature)),\n        \"\\\"}\\n\"\n    );\n\n    oracleInfo =\n        abi.encode(LidoOracleInfo({ base: IOracle(oracleAddress).WSTETH(), quote: IOracle(oracleAddress).STETH() }));\n\n    return someFunction().getValue().modifyValue().negate().scaleBySomeFactor(1000).transformToTuple();\n\n    SnapshotRegistry(adapterRegistry)\n        .add(adapter, LidoFundamentalOracle(adapter).WSTETH(), LidoFundamentalOracle(adapter).WETH());\n\n    (bool success, bytes memory data) = GenericFactory(eVaultFactory).implementation()\n        .staticcall(abi.encodePacked(EVCUtil.EVC.selector, uint256(0), uint256(0)));\n\n    IEVC.BatchItem[] memory items = new IEVC.BatchItem[](3);\n\n    items[0] = IEVC.BatchItem({\n        onBehalfOfAccount: user,\n        targetContract: address(eGRT),\n        value: 0,\n        data: abi.encodeCall(IERC4626.withdraw, (1500e18, address(swapper), user))\n    });\n    items[1] = IEVC.BatchItem({\n        onBehalfOfAccount: user,\n        targetContract: address(swapper),\n        value: 0,\n        data: abi.encodeCall(Swapper.multicall, multicallItems)\n    });\n    items[2] = IEVC.BatchItem({\n        onBehalfOfAccount: user,\n        targetContract: address(swapVerifier),\n        value: 0,\n        data: abi.encodeCall(swapVerifier.verifyDebtMax, (address(eSTETH), user, exactOutTolerance, type(uint256).max))\n    });\n\n    uint256 fork = vm.createSelectFork(\"arbitrum\", bytes32(0xdeadc0ffeedeadbeef));\n\n    ConstructorVictim victim = new ConstructorVictim(sender, \"msg.sender\", \"not set during prank\");\n\n    vm._expectCheatcodeRevert(\"short msg doesn't break\");\n    vm._expectCheatcodeRevert(\"failed parsing as `uint256`: missing hex prefix for hex string\");\n    vm.thisIsJustAReallyLongMemberWithoutAcall.LetsSeeHowItBreaks.willItBreakAsIntendedOrNot;\n\n    bytes4[] memory targets = new bytes4[](0);\n    targets[0] = FuzzArtifactSelector(\"TargetArtifactSelectors.t.sol:Hi\", selectors);\n\n    emit IERC712View.Transfer(Create3.predict(_salt, address(_deployer)), address(o), id);\n\n    return _verifyDeploymentRootHash(_getMerkleRoot(proof, hash), originalOwner)\n        .ternary(IERC1271.isValidSignature.selector, bytes4(0xffffffff));\n}\n\nfunction returnLongBinaryOp() returns (bytes32) {\n    return\n        bytes32(uint256(Feature.unwrap(feature)) << 128 | uint256(block.chainid) << 64 | uint256(Nonce.unwrap(nonce)));\n}\n\ncontract Repros {\n    function test() public {\n        uint256 globalBuyAmount = Take.take(state, notes, uint32(IPoolManager.take.selector), recipient, minBuyAmount);\n        uint256 globalBuyAmount = Take.take(state, notes, uint32(IPoolManager.take.selector), recipient, minBuyAmount);\n\n        {\n            u.executionData = _transferExecution(address(paymentToken), address(0xabcd), 1 ether);\n            u.executionData = _transferExecution(address(paymentToken), address(0xabcd), 1 ether);\n        }\n\n        ISettlerBase.AllowedSlippage memory allowedSlippage = ISettlerBase.AllowedSlippage({\n            recipient: payable(address(0)),\n            buyToken: IERC20(address(0)),\n            minAmountOut: 0\n        });\n        ISettlerBase.AllowedSlippage memory allowedSlippage = ISettlerBase.AllowedSlippage({\n            recipient: payable(address(0)),\n            buyToken: IERC20(address(0)),\n            minAmountOut: 0\n        });\n\n        ISignatureTransfer.PermitTransferFrom memory permit = defaultERC20PermitTransfer(\n            address(fromToken()),\n            amount(),\n            0 /* nonce */\n        );\n        ISignatureTransfer.PermitTransferFrom memory permit = defaultERC20PermitTransfer(\n            address(fromToken()),\n            amount(),\n            0 /* nonce */\n        );\n\n        // https://github.com/foundry-rs/foundry/issues/11834\n        CurrenciesOutOfOrderOrEqual.selector.revertWith(Currency.unwrap(key.currency0), Currency.unwrap(key.currency1));\n\n        nestedStruct.withCalls.thatCause\n            .aBreak(\n                param1,\n                param2,\n                param3 // long line\n            );\n\n        // https://github.com/foundry-rs/foundry/issues/11835\n        feeGrowthInside0X128 = self.feeGrowthGlobal0X128 - lower.feeGrowthOutside0X128 - upper.feeGrowthOutside0X128;\n        feeGrowthInside0X128 = self.feeGrowthGlobal0X128 - lower.feeGrowthOutside0X128 - upper.feeGrowthOutside0X128;\n\n        // https://github.com/foundry-rs/foundry/issues/11875\n        lpTail = LpPosition({\n            tickLower: posTickLower,\n            tickUpper: posTickUpper,\n            liquidity: lpTailLiquidity,\n            id: uint16(id)\n        });\n    }\n\n    // https://github.com/foundry-rs/foundry/issues/11834\n    function test_ffi_fuzz_addLiquidity_defaultPool(IPoolManager.ModifyLiquidityParams memory paramSeed) public {\n        a = 1;\n    }\n\n    // https://github.com/foundry-rs/foundry/issues/12324\n    function test_longCallWithOpts() {\n        flow.withdraw{ value: FLOW_MIN_FEE_WEI }({\n            streamId: defaultStreamId,\n            to: users.eve,\n            amount: WITHDRAW_AMOUNT_6D\n        });\n        flow.withdraw{\n            value: FLOW_MIN_FEE_WEI /* cmnt */\n        }({\n            streamId: defaultStreamId,\n            to: users.eve,\n            /* cmnt */\n            amount: WITHDRAW_AMOUNT_6D\n        });\n        flow.withdraw{ value: FLOW_MIN_FEE_WEI }({\n            // cmnt\n            streamId: defaultStreamId,\n            to: users.eve,\n            amount: WITHDRAW_AMOUNT_6D\n        });\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/ReprosCalls/original.sol",
    "content": "function repros() public {\n    require(\n        keccak256(abi.encodePacked(\"this is a long string\")) == keccak256(abi.encodePacked(\"some other long string\")),\n        \"string mismatch\"\n    );\n\n    address lerp = LerpFactoryLike(lerpFab()).newLerp(_name, _target, _what, _startTime, _start, _end, _duration);\n\n    (oracleRouter, eVault) =\n            execute(oracleRouterFactory, deployRouterForOracle, eVaultFactory, upgradable, asset, oracle, unitOfAccount);\n\n    if (eVault == address(0)) {\n        eVault = address(GenericFactory(eVaultFactory)\n            .createProxy(address(0), true, abi.encodePacked(asset, address(0), address(0))));\n    }\n\n    content = string.concat(\n        \"{\\\"description\\\": \\\"\",\n        description,\n        \"\\\", \\\"name\\\": \\\"0x Settler feature \",\n        ItoA.itoa(Feature.unwrap(feature)),\n        \"\\\"}\\n\"\n    );\n\n    oracleInfo =\n        abi.encode(LidoOracleInfo({base: IOracle(oracleAddress).WSTETH(), quote: IOracle(oracleAddress).STETH()}));\n\n    return someFunction().getValue().modifyValue().negate().scaleBySomeFactor(1000).transformToTuple();\n\n    SnapshotRegistry(adapterRegistry).add(\n        adapter, LidoFundamentalOracle(adapter).WSTETH(), LidoFundamentalOracle(adapter).WETH()\n    );\n\n    (bool success, bytes memory data) = GenericFactory(eVaultFactory).implementation().staticcall(\n                abi.encodePacked(EVCUtil.EVC.selector, uint256(0), uint256(0))\n            );\n\nIEVC.BatchItem[] memory items = new IEVC.BatchItem[](3);\n\n        items[0] = IEVC.BatchItem({\n            onBehalfOfAccount: user,\n            targetContract: address(eGRT),\n            value: 0,\n            data: abi.encodeCall(IERC4626.withdraw, (1500e18, address(swapper), user))\n        });\n        items[1] = IEVC.BatchItem({\n            onBehalfOfAccount: user,\n            targetContract: address(swapper),\n            value: 0,\n            data: abi.encodeCall(Swapper.multicall, multicallItems)\n        });\n        items[2] = IEVC.BatchItem({\n            onBehalfOfAccount: user,\n            targetContract: address(swapVerifier),\n            value: 0,\n            data: abi.encodeCall(swapVerifier.verifyDebtMax, (address(eSTETH), user, exactOutTolerance, type(uint256).max))\n        });\n\n    uint256 fork = vm.createSelectFork(\"arbitrum\", bytes32(0xdeadc0ffeedeadbeef));\n\n    ConstructorVictim victim = new ConstructorVictim( sender, \"msg.sender\", \"not set during prank\" );\n\n    vm._expectCheatcodeRevert(\"short msg doesn't break\");\n    vm._expectCheatcodeRevert( \"failed parsing as `uint256`: missing hex prefix for hex string\" );\n    vm.thisIsJustAReallyLongMemberWithoutAcall.LetsSeeHowItBreaks.willItBreakAsIntendedOrNot;\n\n    bytes4[] memory targets = new bytes4[](0);\n    targets[0] = FuzzArtifactSelector(\"TargetArtifactSelectors.t.sol:Hi\", selectors);\n\n    emit IERC712View.Transfer( Create3.predict(_salt, address(_deployer)), address(o), id );\n\n    return _verifyDeploymentRootHash(\n_getMerkleRoot(proof, hash), originalOwner\n).ternary(\nIERC1271.isValidSignature.selector, bytes4(0xffffffff)\n);\n}\n\nfunction returnLongBinaryOp() returns (bytes32) {\n    return\n        bytes32(uint256(Feature.unwrap(feature)) << 128 | uint256(block.chainid) << 64 | uint256(Nonce.unwrap(nonce)));\n}\n\ncontract Repros {\n    function test() public {\n        uint256 globalBuyAmount =\n            Take.take(state, notes, uint32(IPoolManager.take.selector), recipient, minBuyAmount);\n        uint256 globalBuyAmount = Take.take(\n            state, notes, uint32(IPoolManager.take.selector), recipient, minBuyAmount\n        );\n\n        {\n            u.executionData =\n                _transferExecution(address(paymentToken), address(0xabcd), 1 ether);\n            u.executionData = _transferExecution(\n                address(paymentToken), address(0xabcd), 1 ether\n            );\n        }\n\n        ISettlerBase.AllowedSlippage memory allowedSlippage = ISettlerBase.AllowedSlippage({\n            recipient: payable(address(0)),\n            buyToken: IERC20(address(0)),\n            minAmountOut: 0\n        });\n        ISettlerBase.AllowedSlippage memory allowedSlippage = ISettlerBase.AllowedSlippage({\n            recipient: payable(address(0)), buyToken: IERC20(address(0)), minAmountOut: 0\n        });\n\n        ISignatureTransfer.PermitTransferFrom memory permit =\n            defaultERC20PermitTransfer(address(fromToken()), amount(), 0 /* nonce */);\n        ISignatureTransfer.PermitTransferFrom memory permit = defaultERC20PermitTransfer(\n            address(fromToken()), amount(), 0 /* nonce */\n        );\n\n        // https://github.com/foundry-rs/foundry/issues/11834\n        CurrenciesOutOfOrderOrEqual.selector.revertWith(\n            Currency.unwrap(key.currency0), Currency.unwrap(key.currency1)\n        );\n\n        nestedStruct.withCalls.thatCause.aBreak(param1, param2, param3 // long line\n        );\n\n        // https://github.com/foundry-rs/foundry/issues/11835\n        feeGrowthInside0X128 =\n            self.feeGrowthGlobal0X128 - lower.feeGrowthOutside0X128 - upper.feeGrowthOutside0X128;\n        feeGrowthInside0X128 = self.feeGrowthGlobal0X128\n            - lower.feeGrowthOutside0X128 - upper.feeGrowthOutside0X128;\n\n        // https://github.com/foundry-rs/foundry/issues/11875\n        lpTail =\n            LpPosition({ tickLower: posTickLower, tickUpper: posTickUpper, liquidity: lpTailLiquidity, id: uint16(id) });\n    }\n\n    // https://github.com/foundry-rs/foundry/issues/11834\n    function test_ffi_fuzz_addLiquidity_defaultPool(\n            IPoolManager.ModifyLiquidityParams memory paramSeed\n    ) public {\n        a = 1;\n    }\n\n    // https://github.com/foundry-rs/foundry/issues/12324\n    function test_longCallWithOpts() {\n        flow.withdraw{ value: FLOW_MIN_FEE_WEI }({streamId: defaultStreamId, to: users.eve, amount: WITHDRAW_AMOUNT_6D });\n        flow.withdraw{ value: FLOW_MIN_FEE_WEI /* cmnt */ }({ streamId: defaultStreamId, to: users.eve, /* cmnt */ amount: WITHDRAW_AMOUNT_6D });\n        flow.withdraw{ value: FLOW_MIN_FEE_WEI }({ // cmnt\n         streamId: defaultStreamId, to: users.eve, amount: WITHDRAW_AMOUNT_6D });\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/ReprosFunctionDefs/all.120.fmt.sol",
    "content": "// config: line_length = 120\n// config: multiline_func_header = \"all\"\ncontract Repros {\n    // https://github.com/foundry-rs/foundry/issues/12109\n    function createDefaultStream(UD21x18 ratePerSecond, uint40 startTime, IERC20 token_) internal returns (uint256);\n\n    function calculateStreamedPercentage(\n        uint128 streamedAmount,\n        uint128 depositedAmount\n    )\n        internal\n        pure\n        returns (uint256)\n    {\n        a = 1;\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/ReprosFunctionDefs/original.sol",
    "content": "contract Repros {\n    // https://github.com/foundry-rs/foundry/issues/12109\n    function createDefaultStream(UD21x18 ratePerSecond, uint40 startTime, IERC20 token_) internal returns (uint256);\n    function calculateStreamedPercentage(uint128 streamedAmount, uint128 depositedAmount) internal pure returns (uint256) { a = 1; }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/ReturnStatement/fmt.sol",
    "content": "contract ReturnStatement {\n    function value() internal returns (uint256) {\n        return type(uint256).max;\n    }\n\n    function returnEmpty() external {\n        if (true) {\n            return;\n        }\n\n        if (false) {\n            // return empty 1\n            return; /* return empty 2 */ // return empty 3\n        }\n\n        /* return empty 4 */\n        return; // return empty 5\n    }\n\n    function returnSingleValue(uint256 val) external returns (uint256) {\n        if (val == 0) {\n            return // return single 1\n                0x00;\n        }\n\n        if (val == 1) {\n            return 1;\n        }\n\n        if (val == 2) {\n            return 3 - 1;\n        }\n\n        if (val == 4) {\n            /* return single 2 */\n            return 2 // return single 3\n                ** 3; // return single 4\n        }\n\n        return value(); // return single 5\n    }\n\n    function returnMultipleValues(uint256 val)\n        external\n        returns (uint256, uint256, bool)\n    {\n        if (val == 0) {\n            return /* return mul 1 */ (0, 1, /* return mul 2 */ false);\n        }\n\n        if (val == 1) {\n            // return mul 3\n            return /* return mul 4 */\n                (987654321, 1234567890, /* return mul 5 */ false);\n        }\n\n        if (val == 2) {\n            return /* return mul 6 */ (\n                1234567890 + 987654321 + 87654123536,\n                987654321 + 1234567890 + 124245235235,\n                true\n            );\n        }\n\n        return someFunction().getValue().modifyValue().negate()\n            .scaleBySomeFactor(1000).transformToTuple();\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/ReturnStatement/original.sol",
    "content": "contract ReturnStatement {\n    function value() internal returns (uint256) {\n        return type(uint256).max;\n    }\n\n    function returnEmpty() external {\n        if (true) {\n            return  ;\n        }\n\n        if (false) {\n              // return empty 1\n    return /* return empty 2 */ ; // return empty 3\n        }\n\n        /* return empty 4 */ return // return empty 5\n        ;\n    }\n\n    function returnSingleValue(uint256 val) external returns (uint256) {\n        if (val == 0) {\n        return // return single 1\n        0x00;\n        }\n\n        if (val == 1) { return\n        1; }\n\n        if (val == 2) {\n                return 3\n                -\n                    1;\n        }\n\n        if (val == 4) {\n            /* return single 2 */ return 2** // return single 3\n            3 // return single 4\n            ;\n        }\n\n        return  value() // return single 5\n        ;\n    }\n\n    function returnMultipleValues(uint256 val) external returns (uint256, uint256, bool) {\n        if (val == 0) { return /* return mul 1 */ (0, 1,/* return mul 2 */ false); }\n\n        if (val == 1) {\n    // return mul 3\n            return /* return mul 4 */\n            (\n                987654321, 1234567890,/* return mul 5 */ false); }\n\n        if (val == 2) {\n            return /* return mul 6 */ ( 1234567890 + 987654321  + 87654123536, 987654321 + 1234567890  + 124245235235, true);\n        }\n\n        return someFunction().getValue().modifyValue().negate().scaleBySomeFactor(1000).transformToTuple();\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/RevertNamedArgsStatement/bracket-spacing.fmt.sol",
    "content": "// config: prefer_compact = \"events_errors\"\n// config: bracket_spacing = true\ncontract RevertNamedArgsStatement {\n    error EmptyError();\n    error SimpleError(uint256 val);\n    error ComplexError(uint256 val, uint256 ts, string message);\n    error SomeVeryVeryVeryLongErrorNameWithNamedArgumentsThatExceedsMaximumLength(\n        uint256 val, uint256 ts, string message\n    );\n\n    function test() external {\n        revert({ });\n\n        revert EmptyError({ });\n\n        revert SimpleError({ val: 0 });\n\n        revert ComplexError({\n            val: 0,\n            ts: block.timestamp,\n            message: \"some reason\"\n        });\n\n        revert SomeVeryVeryVeryLongErrorNameWithNamedArgumentsThatExceedsMaximumLength({\n            val: 0,\n            ts: 0x00,\n            message: \"something unpredictable happened that caused execution to revert\"\n        });\n\n        revert({ }); // comment1\n\n        revert /* comment2 */ SimpleError({ /* comment3 */ // comment4\n            val: 0 // comment 5\n        });\n\n        revert Errors.Unauthorized({ caller: msg.sender, neededRole: role });\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/RevertNamedArgsStatement/fmt.sol",
    "content": "// config: prefer_compact = \"events_errors\"\ncontract RevertNamedArgsStatement {\n    error EmptyError();\n    error SimpleError(uint256 val);\n    error ComplexError(uint256 val, uint256 ts, string message);\n    error SomeVeryVeryVeryLongErrorNameWithNamedArgumentsThatExceedsMaximumLength(\n        uint256 val, uint256 ts, string message\n    );\n\n    function test() external {\n        revert({});\n\n        revert EmptyError({});\n\n        revert SimpleError({val: 0});\n\n        revert ComplexError({\n            val: 0,\n            ts: block.timestamp,\n            message: \"some reason\"\n        });\n\n        revert SomeVeryVeryVeryLongErrorNameWithNamedArgumentsThatExceedsMaximumLength({\n            val: 0,\n            ts: 0x00,\n            message: \"something unpredictable happened that caused execution to revert\"\n        });\n\n        revert({}); // comment1\n\n        revert /* comment2 */ SimpleError({ /* comment3 */ // comment4\n            val: 0 // comment 5\n        });\n\n        revert Errors.Unauthorized({caller: msg.sender, neededRole: role});\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/RevertNamedArgsStatement/original.sol",
    "content": "contract RevertNamedArgsStatement {\n    error EmptyError();\n    error SimpleError(uint256 val);\n    error ComplexError(uint256 val, uint256 ts, string message);\n    error SomeVeryVeryVeryLongErrorNameWithNamedArgumentsThatExceedsMaximumLength(\n        uint256 val, uint256 ts, string message\n    );\n\n    function test() external {\n        revert ({ });\n\n        revert EmptyError({});\n\n        revert SimpleError({ val: 0 });\n\n        revert ComplexError(\n            {\n                val: 0,\n                    ts: block.timestamp,\n                        message: \"some reason\"\n            });\n\n        revert SomeVeryVeryVeryLongErrorNameWithNamedArgumentsThatExceedsMaximumLength({ val: 0, ts: 0x00, message: \"something unpredictable happened that caused execution to revert\"});\n\n        revert // comment1\n        ({});\n\n         revert /* comment2 */ SimpleError /* comment3 */ ({ // comment4\n        val:0 // comment 5\n        });\n\n        revert Errors.Unauthorized({ caller: msg.sender, neededRole: role });\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/RevertStatement/fmt.sol",
    "content": "// config: prefer_compact = \"none\"\ncontract RevertStatement {\n    error TestError(uint256, bool, string);\n\n    function someVeryLongFunctionNameToGetDynamicErrorMessageString()\n        public\n        returns (string memory)\n    {\n        return \"\";\n    }\n\n    function test(string memory message) external {\n        revert();\n\n        revert( /* comment1 */ );\n\n        revert();\n\n        // comment2\n        revert(\n            // comment3\n        );\n\n        revert(message);\n\n        revert(\n            // comment4\n            message // comment5 /* comment6 */\n        );\n\n        revert( /* comment7 */ /* comment8 */\n            message /* comment9 */\n        ); /* comment10 */ // comment11\n\n        revert(\n            string.concat(\n                message,\n                someVeryLongFunctionNameToGetDynamicErrorMessageString(\n                    /* comment12 */\n                )\n            )\n        );\n\n        revert TestError(0, false, message);\n        revert TestError(\n            0,\n            false,\n            someVeryLongFunctionNameToGetDynamicErrorMessageString()\n        );\n\n        revert /* comment13 */ /* comment14 */ TestError( /* comment15 */\n            1234567890,\n            false,\n            message\n        );\n\n        revert TestError( /* comment16 */\n            1,\n            true,\n            someVeryLongFunctionNameToGetDynamicErrorMessageString() /* comment17 */\n        );\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/RevertStatement/original.sol",
    "content": "contract RevertStatement {\n    error TestError(uint256,bool,string);\n\n    function someVeryLongFunctionNameToGetDynamicErrorMessageString() public returns (string memory) {\n        return \"\";\n    }\n\n    function test(string memory message) external {\n        revert ( ) ;\n\n        revert ( /* comment1 */ );\n\n            revert\n    (\n\n        )\n            ;\n\n           // comment2\n    revert (\n            // comment3\n        );\n\n\n        revert (  message );\n\n            revert (\n                    // comment4\n                message // comment5 /* comment6 */\n            );\n\n    revert /* comment7 */ ( /* comment8 */ message /* comment9 */ ) /* comment10 */; // comment11\n\n     revert ( string.concat( message ,  someVeryLongFunctionNameToGetDynamicErrorMessageString( /* comment12 */)) );\n\n        revert TestError(0, false, message);\n        revert TestError(0, false, someVeryLongFunctionNameToGetDynamicErrorMessageString());\n\n        revert /* comment13 */ /* comment14 */ TestError /* comment15 */(1234567890, false, message);\n\n\n        revert TestError ( /* comment16 */ 1, true, someVeryLongFunctionNameToGetDynamicErrorMessageString() /* comment17 */);\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/SimpleComments/fmt.sol",
    "content": "contract SimpleComments {\n    uint40 constant PERIOD = uint40(12345); // ~578 days\n    // Represents the depletion timestamp\n    uint40 constant WARP_PERIOD = FEB_1_2025 + PERIOD;\n\n    //´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:\n    //                         VARIABLES\n    //.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•\n\n    mapping(address /* asset */ => address /* router */) public router;\n\n    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n    /*                         FUNCTIONS                          */\n    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n    constructor() {\n        // TODO: do this and that\n\n        uint256 a = 1;\n\n        // TODO: do that and this\n        // or maybe\n        // smth else\n    }\n\n    function test() public view {\n        // do smth here\n\n        // then here\n\n        // cleanup\n    }\n\n    function test2() public pure {\n        uint256 a = 1;\n        // comment 1\n        // comment 2\n        uint256 b = 2;\n    }\n\n    function test3() public view {\n        uint256 a = 1; // comment\n\n        // line comment\n    }\n\n    function test4() public view returns (uint256) {\n        uint256 abc; // long postfix comment that exceeds line width. the comment should be split and carried over to the next line\n        uint256 abc2; // reallylongsinglewordcommentthatexceedslinewidththecommentshouldbesplitandcarriedovertothenextline\n\n        // long prefix comment that exceeds line width. the comment should be split and carried over to the next line\n        // reallylongsinglewordcommentthatexceedslinewidththecommentshouldbesplitandcarriedovertothenextline\n        uint256 c;\n\n        /* a really really long prefix block comment that exceeds line width */\n        uint256 d; /* a really really long postfix block comment that exceeds line width */\n\n        uint256 value;\n        return /* a long block comment that exceeds line width */ value;\n        return /* a block comment that exceeds line width */ value;\n        return // a line comment that exceeds line width\n            value;\n    }\n\n    // https://github.com/foundry-rs/foundry/issues/11836\n    function test5() public {\n        (\n            /* poolIndex */,\n            uint256 sellAmount1,\n            uint256 buyAmount1,\n            /* poolKey1 */,\n            /* sellToken */,\n            /* buyToken */,\n            /* sellTokenBalanceBefore */,\n            uint256 buyTokenBalanceBefore1,\n            /* hashMul */,\n            /* hashMod */\n        ) = _swapPre(2, TOTAL_SUPPLY / 1_000, false, zeroForOne1);\n    }\n\n    // https://github.com/foundry-rs/foundry/issues/12045\n    function test6() {\n        (\n            // uint80 roundID\n            ,\n            int256 dataFeedAnswer,\n            // uint startedAt\n            ,\n            uint256 updatedAt,\n            // uint80 answeredInRound\n        ) = dataFeedContract.latestRoundData();\n    }\n}\n\n/*\n\n██████╗ ██████╗ ██████╗ ████████╗███████╗███████╗████████╗\n██╔══██╗██╔══██╗██╔══██╗╚══██╔══╝██╔════╝██╔════╝╚══██╔══╝\n██████╔╝██████╔╝██████╔╝   ██║   █████╗  ███████╗   ██║\n██╔═══╝ ██╔══██╗██╔══██╗   ██║   ██╔══╝  ╚════██║   ██║\n██║     ██║  ██║██████╔╝   ██║   ███████╗███████║   ██║\n╚═╝     ╚═╝  ╚═╝╚═════╝    ╚═╝   ╚══════╝╚══════╝   ╚═╝\n*/\nfunction asciiArt() {}\n\n/*\n * @notice Here is my comment\n *       - item 1\n *       - item 2\n * Some equations:\n *     y = mx + b\n */\nfunction test() {}\n// comment after function\n\n// comment with extra newlines\n\n// some comment\n// another comment\n\n// eof comment\n"
  },
  {
    "path": "crates/fmt/testdata/SimpleComments/original.sol",
    "content": "contract SimpleComments {\n    uint40 constant PERIOD = uint40(12345); // ~578 days\n    // Represents the depletion timestamp\n    uint40 constant WARP_PERIOD = FEB_1_2025 + PERIOD;\n\n    //´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:\n    //                         VARIABLES\n    //.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•\n\n        mapping(address /* asset */ => address /* router */) public router;\n\n    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n    /*                         FUNCTIONS                          */\n    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n    constructor() {\n        // TODO: do this and that\n\n        uint256 a = 1;\n\n        // TODO: do that and this\n        // or maybe\n        // smth else\n    }\n\n    function test() public view {\n        // do smth here\n\n        // then here\n\n        // cleanup\n    }\n\n    function test2() public pure {\n        uint a = 1;\n        // comment 1\n          // comment 2\n        uint b = 2;\n    }\n\n    function test3() public view {\n        uint256 a = 1; // comment\n\n        // line comment\n    }\n\n     function test4() public view returns (uint256) {\n        uint256 abc; // long postfix comment that exceeds line width. the comment should be split and carried over to the next line\n        uint256 abc2; // reallylongsinglewordcommentthatexceedslinewidththecommentshouldbesplitandcarriedovertothenextline\n\n        // long prefix comment that exceeds line width. the comment should be split and carried over to the next line\n        // reallylongsinglewordcommentthatexceedslinewidththecommentshouldbesplitandcarriedovertothenextline\n        uint256 c;\n\n        /* a really really long prefix block comment that exceeds line width */\n        uint256 d; /* a really really long postfix block comment that exceeds line width */\n\n        uint256 value;\n        return /* a long block comment that exceeds line width */ value;\n        return /* a block comment that exceeds line width */ value;\n        return // a line comment that exceeds line width\n        value;\n    }\n\n    // https://github.com/foundry-rs/foundry/issues/11836\n    function test5() public {\n        (\n            /* poolIndex */,\n            uint256 sellAmount1,\n            uint256 buyAmount1,\n            /* poolKey1 */,\n            /* sellToken */,\n            /* buyToken */,\n            /* sellTokenBalanceBefore */,\n            uint256 buyTokenBalanceBefore1,\n            /* hashMul */,\n            /* hashMod */\n        ) = _swapPre(2, TOTAL_SUPPLY / 1_000, false, zeroForOne1);\n    }\n\n    // https://github.com/foundry-rs/foundry/issues/12045\n    function test6() {\n            (\n        // uint80 roundID\n        ,\n        int256 dataFeedAnswer,\n        // uint startedAt\n        ,\n        uint256 updatedAt,\n        // uint80 answeredInRound\n        ) = dataFeedContract.latestRoundData();\n    }\n}\n\n/*\n\n██████╗ ██████╗ ██████╗ ████████╗███████╗███████╗████████╗\n██╔══██╗██╔══██╗██╔══██╗╚══██╔══╝██╔════╝██╔════╝╚══██╔══╝\n██████╔╝██████╔╝██████╔╝   ██║   █████╗  ███████╗   ██║\n██╔═══╝ ██╔══██╗██╔══██╗   ██║   ██╔══╝  ╚════██║   ██║\n██║     ██║  ██║██████╔╝   ██║   ███████╗███████║   ██║\n╚═╝     ╚═╝  ╚═╝╚═════╝    ╚═╝   ╚══════╝╚══════╝   ╚═╝\n*/\nfunction asciiArt() {}\n\n/*\n * @notice Here is my comment\n *       - item 1\n *       - item 2\n * Some equations:\n *     y = mx + b\n */\nfunction test() {}\n// comment after function\n\n\n// comment with extra newlines\n\n\n// some comment\n// another comment\n\n// eof comment\n"
  },
  {
    "path": "crates/fmt/testdata/SimpleComments/wrap-comments.fmt.sol",
    "content": "// config: line_length = 60\n// config: wrap_comments = true\ncontract SimpleComments {\n    uint40 constant PERIOD = uint40(12345); // ~578 days\n    // Represents the depletion timestamp\n    uint40 constant WARP_PERIOD = FEB_1_2025 + PERIOD;\n\n    //´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:\n    // VARIABLES\n    //.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•\n\n    mapping(address /* asset */ => address /* router */)\n        public router;\n\n    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n    /*                         FUNCTIONS\n    */\n    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n    constructor() {\n        // TODO: do this and that\n\n        uint256 a = 1;\n\n        // TODO: do that and this\n        // or maybe\n        // smth else\n    }\n\n    function test() public view {\n        // do smth here\n\n        // then here\n\n        // cleanup\n    }\n\n    function test2() public pure {\n        uint256 a = 1;\n        // comment 1\n        // comment 2\n        uint256 b = 2;\n    }\n\n    function test3() public view {\n        uint256 a = 1; // comment\n\n        // line comment\n    }\n\n    function test4() public view returns (uint256) {\n        uint256 abc; // long postfix comment that exceeds\n        // line width. the comment should be split and\n        // carried over to the next line\n        uint256 abc2; // reallylongsinglewordcommentthatexceedslinewidththecommentshouldbesplitandcarriedovertothenextline\n\n        // long prefix comment that exceeds line width. the\n        // comment should be split and carried over to the\n        // next line\n        // reallylongsinglewordcommentthatexceedslinewidththecommentshouldbesplitandcarriedovertothenextline\n        uint256 c;\n\n        /* a really really long prefix block comment that\n        exceeds line width */\n        uint256 d; /* a really really long postfix block\n            comment that exceeds line width */\n\n        uint256 value;\n        return /* a long block comment that exceeds line\n            width */ value;\n        return /* a block comment that exceeds line width */\n            value;\n        return // a line comment that exceeds line width\n            value;\n    }\n\n    // https://github.com/foundry-rs/foundry/issues/11836\n    function test5() public {\n        (\n            /* poolIndex */,\n            uint256 sellAmount1,\n            uint256 buyAmount1,\n            /* poolKey1 */,\n            /* sellToken */,\n            /* buyToken */,\n            /* sellTokenBalanceBefore */,\n            uint256 buyTokenBalanceBefore1,\n            /* hashMul */,\n            /* hashMod */\n        ) = _swapPre(\n            2, TOTAL_SUPPLY / 1_000, false, zeroForOne1\n        );\n    }\n\n    // https://github.com/foundry-rs/foundry/issues/12045\n    function test6() {\n        (\n            // uint80 roundID\n            ,\n            int256 dataFeedAnswer,\n            // uint startedAt\n            ,\n            uint256 updatedAt,\n            // uint80 answeredInRound\n        ) = dataFeedContract.latestRoundData();\n    }\n}\n\n/*\n\n██████╗ ██████╗ ██████╗ ████████╗███████╗███████╗████████╗\n██╔══██╗██╔══██╗██╔══██╗╚══██╔══╝██╔════╝██╔════╝╚══██╔══╝\n██████╔╝██████╔╝██████╔╝   ██║   █████╗  ███████╗   ██║\n██╔═══╝ ██╔══██╗██╔══██╗   ██║   ██╔══╝  ╚════██║   ██║\n██║     ██║  ██║██████╔╝   ██║   ███████╗███████║   ██║\n╚═╝     ╚═╝  ╚═╝╚═════╝    ╚═╝   ╚══════╝╚══════╝   ╚═╝\n*/\nfunction asciiArt() {}\n\n/*\n * @notice Here is my comment\n *       - item 1\n *       - item 2\n * Some equations:\n *     y = mx + b\n */\nfunction test() {}\n// comment after function\n\n// comment with extra newlines\n\n// some comment\n// another comment\n\n// eof comment\n"
  },
  {
    "path": "crates/fmt/testdata/SortedImports/fmt.sol",
    "content": "// config: sort_imports = true\nimport \"SomeFile0.sol\" as SomeOtherFile;\nimport \"SomeFile1.sol\" as SomeOtherFile;\nimport \"SomeFile2.sol\";\nimport \"SomeFile3.sol\";\n\nimport \"AnotherFile1.sol\" as SomeSymbol;\nimport \"AnotherFile2.sol\" as SomeSymbol;\n\nimport {\n    symbol1 as alias3,\n    symbol2 as alias2,\n    symbol3 as alias1,\n    symbol4\n} from \"File0.sol\";\nimport {symbol1 as alias0, symbol2} from \"File2.sol\";\nimport {symbol1 as alias0, symbol2} from \"File3.sol\";\nimport {\n    symbol1 as alias1,\n    symbol2 as alias2,\n    symbol3 as alias3,\n    symbol4\n} from \"File6.sol\";\n\nuint256 constant someConstant = 10;\n\nimport {Something2, Something3} from \"someFile.sol\";\n\n// This is a comment\nimport {Something2, Something3} from \"someFile.sol\";\n\nimport {symbol1 as alias0, symbol2} from \"File3.sol\";\n// comment inside group is treated as a separator for now\nimport {symbol1 as alias0, symbol2} from \"File2.sol\";\n"
  },
  {
    "path": "crates/fmt/testdata/SortedImports/original.sol",
    "content": "import \"SomeFile3.sol\";\nimport \"SomeFile2.sol\";\nimport \"SomeFile1.sol\" as SomeOtherFile;\nimport \"SomeFile0.sol\" as SomeOtherFile;\n\nimport \"AnotherFile2.sol\" as SomeSymbol;\nimport \"AnotherFile1.sol\" as SomeSymbol;\n\nimport {symbol2, symbol1 as alias0} from \"File3.sol\";\nimport {symbol2, symbol1 as alias0} from \"File2.sol\";\nimport {symbol2 as alias2, symbol1 as alias1, symbol3 as alias3, symbol4} from \"File6.sol\";\nimport {symbol3 as alias1, symbol2 as alias2, symbol1 as alias3, symbol4} from \"File0.sol\";\n\nuint256 constant someConstant = 10;\n\nimport {Something3, Something2} from \"someFile.sol\";\n\n// This is a comment\nimport {Something3, Something2} from \"someFile.sol\";\n\nimport {symbol2, symbol1 as alias0} from \"File3.sol\";\n// comment inside group is treated as a separator for now\nimport {symbol2, symbol1 as alias0} from \"File2.sol\";"
  },
  {
    "path": "crates/fmt/testdata/StatementBlock/bracket-spacing.fmt.sol",
    "content": "// config: bracket_spacing = true\ncontract Contract {\n    function test() {\n        unchecked {\n            a += 1;\n        }\n\n        unchecked {\n            a += 1;\n        }\n        2 + 2;\n\n        unchecked {\n            a += 1;\n        }\n        unchecked { }\n\n        1 + 1;\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/StatementBlock/fmt.sol",
    "content": "contract Contract {\n    function test() {\n        unchecked {\n            a += 1;\n        }\n\n        unchecked {\n            a += 1;\n        }\n        2 + 2;\n\n        unchecked {\n            a += 1;\n        }\n        unchecked {}\n\n        1 + 1;\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/StatementBlock/original.sol",
    "content": "contract Contract {\n    function test() { unchecked { a += 1; }\n\n        unchecked {\n        a += 1;\n        }\n    2 + 2;\n\nunchecked { a += 1;\n        }\n    unchecked {}\n\n    1 + 1;\n\n\n    }\n}"
  },
  {
    "path": "crates/fmt/testdata/StructDefinition/bracket-spacing.fmt.sol",
    "content": "// config: bracket_spacing = true\nstruct Foo {}\n\nstruct Bar {\n    uint256 foo;\n    string bar;\n}\n\nstruct MyStruct {\n    // first 1\n    // first 2\n    uint256 field1;\n    // second\n    uint256 field2;\n}\n"
  },
  {
    "path": "crates/fmt/testdata/StructDefinition/fmt.sol",
    "content": "struct Foo {}\n\nstruct Bar {\n    uint256 foo;\n    string bar;\n}\n\nstruct MyStruct {\n    // first 1\n    // first 2\n    uint256 field1;\n    // second\n    uint256 field2;\n}\n"
  },
  {
    "path": "crates/fmt/testdata/StructDefinition/original.sol",
    "content": "struct   Foo  {\n    \n} struct   Bar  {    uint foo ;string bar ;  }\n\nstruct MyStruct {\n// first 1\n// first 2\n    uint256 field1;\n    // second\n    uint256 field2;\n}\n"
  },
  {
    "path": "crates/fmt/testdata/StructFieldAccess/fmt.sol",
    "content": "// config: line_length = 120\n// https://github.com/foundry-rs/foundry/issues/12399\ncontract StructFieldAccess {\n    function a() external {\n        bytes32 guid =\n            _lzSend({\n            _dstEid: dstEid,\n            _message: message,\n            _options: OptionsBuilder.newOptions().addExecutorLzReceiveOption({_gas: gasLimit, _value: 0}),\n            _fee: MessagingFee({nativeFee: msg.value, lzTokenFee: 0}),\n            _refundAddress: msg.sender\n        }).guid;\n    }\n\n    function b() external view returns (uint256) {\n        return _quote({\n            _dstEid: dstEid,\n            _message: message,\n            _options: OptionsBuilder.newOptions().addExecutorLzReceiveOption({_gas: gasLimit, _value: 0}),\n            _payInLzToken: false\n        }).nativeFee;\n    }\n\n    // Simple cases\n    function c() external {\n        uint256 val = getData().value;\n        bool flag = getStruct({param: 1}).isActive;\n    }\n\n    // Nested struct field access\n    function d() external {\n        uint256 nested = getOuter().inner.value;\n    }\n\n    // Chained calls with named args\n    function e() external {\n        bytes32 guid =\n            _lzSend({\n            _dstEid: dstEid,\n            _message: message,\n            _options: OptionsBuilder.newOptions().addExecutorLzReceiveOption({_gas: gasLimit, _value: 0}),\n            _fee: MessagingFee({nativeFee: msg.value, lzTokenFee: 0}),\n            _refundAddress: msg.sender\n        }).wrap({wrapper: wrapperAddress, extraData: bytes(\"\")}).guid;\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/StructFieldAccess/original.sol",
    "content": "// https://github.com/foundry-rs/foundry/issues/12399\ncontract StructFieldAccess {\n    function a() external {\n        bytes32 guid = _lzSend({\n            _dstEid: dstEid,\n            _message: message,\n            _options: OptionsBuilder.newOptions().addExecutorLzReceiveOption({_gas: gasLimit, _value: 0}),\n            _fee: MessagingFee({nativeFee: msg.value, lzTokenFee: 0}),\n            _refundAddress: msg.sender\n        }).guid;\n    }\n\n    function b() external view returns (uint256) {\n        return _quote({\n            _dstEid: dstEid,\n            _message: message,\n            _options: OptionsBuilder.newOptions().addExecutorLzReceiveOption({_gas: gasLimit, _value: 0}),\n            _payInLzToken: false\n        }).nativeFee;\n    }\n\n    // Simple cases\n    function c() external {\n        uint256 val = getData().value;\n        bool flag = getStruct({param: 1}).isActive;\n    }\n\n    // Nested struct field access\n    function d() external {\n        uint256 nested = getOuter().inner.value;\n    }\n\n    // Chained calls with named args\n    function e() external {\n        bytes32 guid = _lzSend({\n            _dstEid: dstEid,\n            _message: message,\n            _options: OptionsBuilder.newOptions().addExecutorLzReceiveOption({_gas: gasLimit, _value: 0}),\n            _fee: MessagingFee({nativeFee: msg.value, lzTokenFee: 0}),\n            _refundAddress: msg.sender\n        }).wrap({wrapper: wrapperAddress, extraData: bytes(\"\")}).guid;\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/ThisExpression/fmt.sol",
    "content": "contract ThisExpression {\n    function someFunc() public {}\n    function someVeryVeryVeryLongVariableNameThatWillBeAccessedByThisKeyword()\n        public {}\n\n    function test() external {\n        this.someFunc();\n        this.someVeryVeryVeryLongVariableNameThatWillBeAccessedByThisKeyword();\n        this // comment1\n            .someVeryVeryVeryLongVariableNameThatWillBeAccessedByThisKeyword();\n        address(this).balance;\n\n        address thisAddress = address(\n            // comment2\n            /* comment3 */ this // comment 4\n        );\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/ThisExpression/original.sol",
    "content": "contract ThisExpression {\n    function someFunc() public {}\n    function someVeryVeryVeryLongVariableNameThatWillBeAccessedByThisKeyword() public {}\n\n    function test() external {\n        this.someFunc();\n        this.someVeryVeryVeryLongVariableNameThatWillBeAccessedByThisKeyword();\n        this // comment1\n            .someVeryVeryVeryLongVariableNameThatWillBeAccessedByThisKeyword();\n        address(this).balance;\n        \n        address thisAddress = address(\n            // comment2\n             /* comment3 */ this // comment 4\n        );\n    }\n}"
  },
  {
    "path": "crates/fmt/testdata/TrailingComma/fmt.sol",
    "content": "contract C is Contract {\n    function f(uint256 a) external {}\n    function f2(uint256 a, bytes32 b) external returns (uint256) {}\n\n    function f3() external {\n        try some.invoke() returns (uint256, uint256) {} catch {}\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/TrailingComma/original.sol",
    "content": "contract C is Contract {\n    function f(uint256 a, ) external {}\n    function f2(uint256 a, bytes32 b,) external returns (uint256,) {}\n\n    function f3() external {\n        try some.invoke() returns (uint256,uint256,) {} catch {}\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/TryStatement/fmt.sol",
    "content": "interface Unknown {\n    function empty() external;\n    function lookup() external returns (uint256);\n    function lookupMultipleValues()\n        external\n        returns (uint256, uint256, uint256, uint256, uint256);\n\n    function doSomething() external;\n    function doSomethingElse() external;\n\n    function handleError() external;\n}\n\ncontract TryStatement {\n    Unknown unknown;\n\n    function test() external {\n        try unknown.empty() {} catch {}\n\n        try unknown.lookup() returns (uint256) {} catch Error(string memory) {}\n\n        try unknown.lookup() returns (uint256) {}\n            catch Error(string memory) {}\n            catch (bytes memory) {}\n\n        try unknown.lookup() returns (uint256) {} catch (bytes memory) {}\n\n        try unknown.empty() {\n            unknown.doSomething();\n        } catch {\n            unknown.handleError();\n        }\n\n        try unknown.empty() {\n            unknown.doSomething();\n        }\n            catch Error(string memory) {}\n            catch Panic(uint256) {}\n        catch {\n            unknown.handleError();\n        }\n\n        try unknown.lookupMultipleValues() returns (\n            uint256, uint256, uint256, uint256, uint256\n        ) {}\n            catch Error(string memory) {}\n            catch {}\n\n        try unknown.lookupMultipleValues() returns (\n            uint256, uint256, uint256, uint256, uint256\n        ) {\n            unknown.doSomething();\n        } catch Error(string memory) {\n            unknown.handleError();\n        } catch {}\n\n        // comment1\n        try /* comment2 */ unknown.lookup() // comment3\n        returns (\n            uint256 // comment4\n        ) {} // comment5\n            catch { /* comment6 */ }\n\n        // comment7\n        try unknown.empty() { // comment8\n            unknown.doSomething();\n        } /* comment9 */ catch /* comment10 */ Error(string memory) {\n            unknown.handleError();\n        } catch /* comment11 */ Panic(uint256) {\n            unknown.handleError();\n        } catch {}\n    }\n\n    function test_multiParam() {\n        Mock mock = new Mock();\n\n        try mock.add(2, 3) {\n            revert();\n        } catch (bytes memory err) {\n            require(keccak256(err) == keccak256(ERROR_MESSAGE));\n        }\n    }\n\n    function test_multiComment() {\n        try vm.envString(\"API_KEY\") returns (string memory) {\n            console2.log(\"Forked Ethereum mainnet\");\n            // Fork mainnet at a specific block for consistency\n            vm.createSelectFork(vm.rpcUrl(\"mainnet\"), 21_900_000);\n            // do something\n        } catch {\n            /* sadness */\n            // more sadness\n            revert();\n        }\n    }\n\n    function try_reallyLongCall() {\n        try AggregatorV3Interface(oracle).latestRoundData() returns (\n            uint80, int256 _price, uint256, uint256 _updatedAt, uint80\n        ) {\n            return true;\n        } catch {} // https://github.com/foundry-rs/foundry/issues/12240\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/TryStatement/original.sol",
    "content": "interface Unknown {\n    function empty() external;\n    function lookup() external returns(uint256);\n    function lookupMultipleValues() external returns (uint256, uint256, uint256, uint256, uint256);\n\n    function doSomething() external;\n    function doSomethingElse() external;\n\n    function handleError() external;\n}\n\ncontract TryStatement {\n    Unknown unknown;\n\n    function test() external {\n        try unknown.empty() {} catch {}\n\n        try unknown.lookup() returns (uint256) {} catch Error(string memory) {}\n\n        try unknown.lookup() returns (uint256) {} catch Error(string memory) {} catch (bytes memory) {}\n\n    try unknown\n        .lookup() returns   (uint256\n                ) {\n                } catch ( bytes  memory ){}\n\n        try unknown.empty() {\n            unknown.doSomething();\n        } catch {\n            unknown.handleError();\n        }\n\n        try unknown.empty() {\n            unknown.doSomething();\n        } catch Error(string memory) {}\n        catch Panic(uint) {}\n        catch {\n            unknown.handleError();\n        }\n\n        try unknown.lookupMultipleValues() returns (uint256, uint256, uint256, uint256, uint256) {} catch Error(string memory) {} catch {}\n\n        try unknown.lookupMultipleValues() returns (uint256, uint256, uint256, uint256, uint256) {\n            unknown.doSomething();\n        }\n        catch Error(string memory) {\n             unknown.handleError();\n        }\n        catch {}\n\n        // comment1\n        try /* comment2 */ unknown.lookup() // comment3\n        returns (uint256) // comment4\n        {} // comment5\n        catch /* comment6 */ {}\n\n        // comment7\n        try unknown.empty() { // comment8\n            unknown.doSomething();\n        } /* comment9 */ catch /* comment10 */ Error(string memory) {\n            unknown.handleError();\n        } catch Panic /* comment11 */ (uint) {\n            unknown.handleError();\n        } catch {}\n    }\n\n    function test_multiParam() {\n        Mock mock = new Mock();\n\n        try mock.add(2, 3) {\n            revert();\n        } catch (bytes memory err) {\n            require(keccak256(err) == keccak256(ERROR_MESSAGE));\n        }\n    }\n\n    function test_multiComment() {\n        try vm.envString(\"API_KEY\") returns (string memory) {\n            console2.log(\"Forked Ethereum mainnet\");\n            // Fork mainnet at a specific block for consistency\n            vm.createSelectFork(vm.rpcUrl(\"mainnet\"), 21_900_000);\n            // do something\n        } catch /* sadness */ {\n            // more sadness\n            revert();\n        }\n    }\n\n    function try_reallyLongCall() {\n        try AggregatorV3Interface(oracle).latestRoundData() returns (uint80, int256 _price, uint256, uint256 _updatedAt, uint80) {\n            return true;\n        } catch {} // https://github.com/foundry-rs/foundry/issues/12240\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/TypeDefinition/fmt.sol",
    "content": "pragma solidity ^0.8.8;\n\ntype Hello is uint256;\n\ncontract TypeDefinition {\n    event Moon(Hello world);\n\n    function demo(Hello world) public {\n        world = Hello.wrap(Hello.unwrap(world) + 1337);\n        emit Moon(world);\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/TypeDefinition/original.sol",
    "content": "pragma solidity ^0.8.8;\n\n    type Hello is uint;\n\ncontract TypeDefinition {\n    event Moon(Hello world);\n\n        function demo(Hello world) public {\n        world = Hello.wrap(Hello.unwrap(world) + 1337);\n        emit Moon(world);\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/UnitExpression/fmt.sol",
    "content": "contract UnitExpression {\n    function test() external {\n        uint256 timestamp;\n        timestamp = 1 seconds;\n        timestamp = 1 minutes;\n        timestamp = 1 hours;\n        timestamp = 1 days;\n        timestamp = 1 weeks;\n\n        uint256 value;\n        value = 1 wei;\n        value = 1 gwei;\n        value = 1 ether;\n\n        uint256 someVeryVeryVeryLongVariableNameForTheMultiplierForEtherValue;\n\n        value = someVeryVeryVeryLongVariableNameForTheMultiplierForEtherValue\n            * 1 ether;\n        value = someVeryVeryVeryLongVariableNameForTheMultiplierForEtherValue\n            * 1 ether; /* comment1 */ // comment2\n\n        value = 1 ether; // comment3\n        // comment4\n        // comment5\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/UnitExpression/original.sol",
    "content": "contract UnitExpression {\n    function test() external {\n        uint256 timestamp;\n        timestamp = 1 seconds;\n        timestamp = 1 minutes;\n        timestamp = 1 hours;\n        timestamp = 1 days;\n        timestamp = 1 weeks;\n\n        uint256 value;\n        value = 1 wei;\n        value = 1 gwei;\n        value = 1 ether;\n\n        uint256 someVeryVeryVeryLongVariableNameForTheMultiplierForEtherValue;\n\n        value =  someVeryVeryVeryLongVariableNameForTheMultiplierForEtherValue * 1 ether;\n        value =  someVeryVeryVeryLongVariableNameForTheMultiplierForEtherValue * 1 /* comment1 */ ether; // comment2\n\n        value = 1 // comment3\n        // comment4\n        ether; // comment5\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/UsingDirective/fmt.sol",
    "content": "contract UsingExampleContract {\n    using UsingExampleLibrary for *;\n    using UsingExampleLibrary for uint256;\n    using Example.UsingExampleLibrary for uint256;\n    using {M.g, M.f} for uint256;\n    using UsingExampleLibrary for uint256 global;\n    using {\n        These,\n        Are,\n        MultipleLibraries,\n        ThatNeedToBePut,\n        OnSeparateLines\n    } for uint256;\n    using {\n        This\n            .isareally\n            .longmember\n            .access\n            .expression\n            .that\n            .needs\n            .to\n            .besplit\n            .into\n            .lines\n    } for uint256;\n    using {and as &, or as |, xor as ^, cpl as ~} for Bitmap global;\n    using {\n        eq as ==,\n        ne as !=,\n        lt as <,\n        lte as <=,\n        gt as >,\n        gte as >=\n    } for Bitmap global;\n}\n"
  },
  {
    "path": "crates/fmt/testdata/UsingDirective/original.sol",
    "content": "contract UsingExampleContract {\n using  UsingExampleLibrary      for   *  ;\n    using UsingExampleLibrary for uint;\n   using Example.UsingExampleLibrary  for  uint;\n        using { M.g, M.f} for uint;\nusing UsingExampleLibrary for   uint  global;\nusing { These, Are, MultipleLibraries, ThatNeedToBePut, OnSeparateLines } for uint;\nusing { This.isareally.longmember.access.expression.that.needs.to.besplit.into.lines } for uint;\nusing {and as &, or as |, xor as ^, cpl as ~} for Bitmap global;\nusing {eq as ==, ne as !=, lt as <, lte as <=, gt as >, gte as >=} for Bitmap global;\n}\n"
  },
  {
    "path": "crates/fmt/testdata/VariableAssignment/bracket-spacing.fmt.sol",
    "content": "// config: bracket_spacing = true\ncontract TestContract {\n    function aLongerTestFunctionName(uint256 input)\n        public\n        view\n        returns (uint256 num)\n    {\n        (, uint256 second) = (1, 2);\n        (uint256 listItem001) = 1;\n        (uint256 listItem002, uint256 listItem003) = (10, 20);\n        (uint256 listItem004, uint256 listItem005, uint256 listItem006) =\n            (10, 20, 30);\n        (\n            uint256 listItem007,\n            uint256 listItem008,\n            uint256 listItem009,\n            uint256 listItem010\n        ) = (10, 20, 30, 40);\n        return 1;\n    }\n\n    function test() external {\n        uint256 value = map[key];\n        uint256 allowed = allowance[from][msg.sender];\n        allowance[from][msg.sender] = allowed;\n    }\n\n    function test_longAssignements() public {\n        string[] memory inputs = new string[](3);\n        inputs[0] = \"bash\";\n        inputs[1] = \"-c\";\n        inputs[2] =\n            \"echo -n 0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000966666920776f726b730000000000000000000000000000000000000000000000\";\n    }\n\n    function test_stringConcatenation() public {\n        string memory strConcat = \"0,\" \"11579208923731619542357098500868790785,\"\n            \"0x0000000000000000000000000000000000000000000000000000000000000000,\"\n            \"0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\";\n    }\n\n    // https://github.com/foundry-rs/foundry/issues/12254\n    function test_longIndexedCall() {\n        bytes memory message = mailboxes[destinationDomain].buildMessage(\n            originDomain,\n            bytes32(0),\n            address(inbox).toBytes32(),\n            abi.encode(orderId, bytes32(0), address(0))\n        );\n        // should have identicall behavior when call of the same size without indexing\n        bytes memory message = mailboxes_destinationDomains.buildMessage(\n            originDomain,\n            bytes32(0),\n            address(inbox).toBytes32(),\n            abi.encode(orderId, bytes32(0), address(0))\n        );\n    }\n\n    // https://github.com/foundry-rs/foundry/issues/12322\n    function test_longComplexBinExpr() {\n        vars.previousTotalDebt = getDescaledAmount(\n            flow.getSnapshotDebtScaled(streamId),\n            flow.getTokenDecimals(streamId)\n        ) + vars.previousOngoingDebtScaled;\n\n        vars.previousTotalDebt = vars.reallyLongVarThatCausesALineBreak\n            + vars.previousOngoingDebtScaled;\n\n        vars.previousTotalDebt = vars.reallyLongVarThatCausesALineBreak()\n            .previousOngoingDebtScaled();\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/VariableAssignment/fmt.sol",
    "content": "contract TestContract {\n    function aLongerTestFunctionName(uint256 input)\n        public\n        view\n        returns (uint256 num)\n    {\n        (, uint256 second) = (1, 2);\n        (uint256 listItem001) = 1;\n        (uint256 listItem002, uint256 listItem003) = (10, 20);\n        (uint256 listItem004, uint256 listItem005, uint256 listItem006) =\n            (10, 20, 30);\n        (\n            uint256 listItem007,\n            uint256 listItem008,\n            uint256 listItem009,\n            uint256 listItem010\n        ) = (10, 20, 30, 40);\n        return 1;\n    }\n\n    function test() external {\n        uint256 value = map[key];\n        uint256 allowed = allowance[from][msg.sender];\n        allowance[from][msg.sender] = allowed;\n    }\n\n    function test_longAssignements() public {\n        string[] memory inputs = new string[](3);\n        inputs[0] = \"bash\";\n        inputs[1] = \"-c\";\n        inputs[2] =\n            \"echo -n 0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000966666920776f726b730000000000000000000000000000000000000000000000\";\n    }\n\n    function test_stringConcatenation() public {\n        string memory strConcat = \"0,\" \"11579208923731619542357098500868790785,\"\n            \"0x0000000000000000000000000000000000000000000000000000000000000000,\"\n            \"0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\";\n    }\n\n    // https://github.com/foundry-rs/foundry/issues/12254\n    function test_longIndexedCall() {\n        bytes memory message = mailboxes[destinationDomain].buildMessage(\n            originDomain,\n            bytes32(0),\n            address(inbox).toBytes32(),\n            abi.encode(orderId, bytes32(0), address(0))\n        );\n        // should have identicall behavior when call of the same size without indexing\n        bytes memory message = mailboxes_destinationDomains.buildMessage(\n            originDomain,\n            bytes32(0),\n            address(inbox).toBytes32(),\n            abi.encode(orderId, bytes32(0), address(0))\n        );\n    }\n\n    // https://github.com/foundry-rs/foundry/issues/12322\n    function test_longComplexBinExpr() {\n        vars.previousTotalDebt = getDescaledAmount(\n            flow.getSnapshotDebtScaled(streamId),\n            flow.getTokenDecimals(streamId)\n        ) + vars.previousOngoingDebtScaled;\n\n        vars.previousTotalDebt = vars.reallyLongVarThatCausesALineBreak\n            + vars.previousOngoingDebtScaled;\n\n        vars.previousTotalDebt = vars.reallyLongVarThatCausesALineBreak()\n            .previousOngoingDebtScaled();\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/VariableAssignment/original.sol",
    "content": "contract TestContract {\n    function aLongerTestFunctionName(uint256 input)\n        public\n        view\n        returns (uint256 num)\n    {\n        (, uint256 second) = (1, 2);\n        (uint256 listItem001) = 1;\n        (uint256 listItem002, uint256 listItem003) = (10, 20);\n        (uint256 listItem004, uint256 listItem005, uint256 listItem006) =\n            (10, 20, 30);\n        (\n            uint256 listItem007,\n            uint256 listItem008,\n            uint256 listItem009,\n            uint256 listItem010\n        ) = (10, 20, 30, 40);\n        return 1;\n    }\n\n    function test() external {\n        uint256 value = map[key];\n        uint256 allowed = allowance[from][msg.sender];\n        allowance[from][msg.sender] = allowed;\n    }\n\n    function test_longAssignements() public {\n        string[] memory inputs = new string[](3);\n        inputs[0] = \"bash\";\n        inputs[1] = \"-c\";\n        inputs[2] = \"echo -n 0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000966666920776f726b730000000000000000000000000000000000000000000000\";\n    }\n\n    function test_stringConcatenation() public {\n        string memory strConcat = \"0,\" \"11579208923731619542357098500868790785,\"\n            \"0x0000000000000000000000000000000000000000000000000000000000000000,\"\n            \"0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\";\n    }\n\n    // https://github.com/foundry-rs/foundry/issues/12254\n    function test_longIndexedCall() {\n        bytes memory message = mailboxes[destinationDomain].buildMessage(originDomain, bytes32(0), address(inbox).toBytes32(), abi.encode(orderId, bytes32(0), address(0)));\n        // should have identicall behavior when call of the same size without indexing\n        bytes memory message = mailboxes_destinationDomains.buildMessage(originDomain, bytes32(0), address(inbox).toBytes32(), abi.encode(orderId, bytes32(0), address(0)));\n    }\n\n    // https://github.com/foundry-rs/foundry/issues/12322\n    function test_longComplexBinExpr() {\n        vars.previousTotalDebt = getDescaledAmount(flow.getSnapshotDebtScaled(streamId), flow.getTokenDecimals(streamId)) + vars.previousOngoingDebtScaled;\n\n        vars.previousTotalDebt = vars.reallyLongVarThatCausesALineBreak + vars.previousOngoingDebtScaled;\n\n        vars.previousTotalDebt = vars.reallyLongVarThatCausesALineBreak() .previousOngoingDebtScaled();\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/VariableDefinition/fmt.sol",
    "content": "// config: line_length = 40\ncontract Contract layout at 69 {\n    bytes32 transient a;\n\n    bytes32 private constant BYTES = 0;\n    bytes32\n        private\n        constant\n        override(Base1) BYTES = 0;\n    bytes32\n        private\n        constant\n        override(Base1, Base2) BYTES = 0;\n    bytes32\n        private\n        constant\n        override BYTES = 0;\n    bytes32\n        private\n        constant\n        override BYTES_VERY_VERY_VERY_LONG = 0;\n    bytes32\n        private\n        constant\n        override(\n            Base1,\n            Base2,\n            SomeLongBaseContract,\n            AndAnotherVeryLongBaseContract,\n            Imported.Contract\n        ) BYTES_OVERRIDDEN = 0;\n\n    bytes32 private constant BYTES =\n        0x035aff83d86937d35b32e04f0ddc6ff469290eef2f1b692d8a815c89404d4749;\n    bytes32\n        private\n        constant\n        override BYTES =\n            0x035aff83d86937d35b32e04f0ddc6ff469290eef2f1b692d8a815c89404d4749;\n    bytes32\n        private\n        constant\n        override BYTES_VERY_VERY_VERY_LONG =\n            0x035aff83d86937d35b32e04f0ddc6ff469290eef2f1b692d8a815c89404d4749;\n    bytes32 private constant\n        BYTES_VERY_VERY_LONG =\n            0x035aff83d86937d35b32e04f0ddc6ff469290eef2f1b692d8a815c89404d4749;\n\n    uint256 constant POWER_EXPRESSION =\n        10 ** 27;\n    uint256 constant ADDED_EXPRESSION =\n        1 + 2;\n\n    // comment 1\n    uint256 constant example1 = 1;\n    // comment 2\n    // comment 3\n    uint256 constant example2 = 2; // comment 4\n    uint256 constant example3 = /* comment 5 */\n        3; // comment 6\n}\n"
  },
  {
    "path": "crates/fmt/testdata/VariableDefinition/original.sol",
    "content": "contract Contract layout at 69 {\n    bytes32 transient a;\n\n    bytes32 constant private BYTES = 0;\n    bytes32 private constant override (Base1) BYTES = 0;\n    bytes32 private constant override (Base1, Base2) BYTES = 0;\n    bytes32 private constant override BYTES = 0;\n    bytes32 private constant override BYTES_VERY_VERY_VERY_LONG = 0;\n    bytes32 private constant override(Base1, Base2, SomeLongBaseContract, AndAnotherVeryLongBaseContract, Imported.Contract) BYTES_OVERRIDDEN = 0;\n\n    bytes32 constant private BYTES =\n        0x035aff83d86937d35b32e04f0ddc6ff469290eef2f1b692d8a815c89404d4749;\n    bytes32 private constant override BYTES =\n        0x035aff83d86937d35b32e04f0ddc6ff469290eef2f1b692d8a815c89404d4749;\n    bytes32 private constant override BYTES_VERY_VERY_VERY_LONG =\n        0x035aff83d86937d35b32e04f0ddc6ff469290eef2f1b692d8a815c89404d4749;\n    bytes32 private constant BYTES_VERY_VERY_LONG =\n        0x035aff83d86937d35b32e04f0ddc6ff469290eef2f1b692d8a815c89404d4749;\n\n    uint constant POWER_EXPRESSION = 10 ** 27;\n    uint constant ADDED_EXPRESSION = 1 + 2;\n\n    // comment 1\n    uint256 constant example1 = 1;\n    // comment 2\n    // comment 3\n    uint256 constant example2 = 2;// comment 4\n    uint256 constant example3 /* comment 5 */= 3; // comment 6\n}\n"
  },
  {
    "path": "crates/fmt/testdata/VariableDefinition/override-spacing.fmt.sol",
    "content": "// config: line_length = 40\n// config: override_spacing = true\ncontract Contract layout at 69 {\n    bytes32 transient a;\n\n    bytes32 private constant BYTES = 0;\n    bytes32\n        private\n        constant\n        override (Base1) BYTES = 0;\n    bytes32\n        private\n        constant\n        override (Base1, Base2) BYTES = 0;\n    bytes32\n        private\n        constant\n        override BYTES = 0;\n    bytes32\n        private\n        constant\n        override BYTES_VERY_VERY_VERY_LONG = 0;\n    bytes32\n        private\n        constant\n        override (\n            Base1,\n            Base2,\n            SomeLongBaseContract,\n            AndAnotherVeryLongBaseContract,\n            Imported.Contract\n        ) BYTES_OVERRIDDEN = 0;\n\n    bytes32 private constant BYTES =\n        0x035aff83d86937d35b32e04f0ddc6ff469290eef2f1b692d8a815c89404d4749;\n    bytes32\n        private\n        constant\n        override BYTES =\n            0x035aff83d86937d35b32e04f0ddc6ff469290eef2f1b692d8a815c89404d4749;\n    bytes32\n        private\n        constant\n        override BYTES_VERY_VERY_VERY_LONG =\n            0x035aff83d86937d35b32e04f0ddc6ff469290eef2f1b692d8a815c89404d4749;\n    bytes32 private constant\n        BYTES_VERY_VERY_LONG =\n            0x035aff83d86937d35b32e04f0ddc6ff469290eef2f1b692d8a815c89404d4749;\n\n    uint256 constant POWER_EXPRESSION =\n        10 ** 27;\n    uint256 constant ADDED_EXPRESSION =\n        1 + 2;\n\n    // comment 1\n    uint256 constant example1 = 1;\n    // comment 2\n    // comment 3\n    uint256 constant example2 = 2; // comment 4\n    uint256 constant example3 = /* comment 5 */\n        3; // comment 6\n}\n"
  },
  {
    "path": "crates/fmt/testdata/WhileStatement/block-multi.fmt.sol",
    "content": "// config: single_line_statement_blocks = \"multi\"\npragma solidity ^0.8.8;\n\nfunction doIt() {}\n\ncontract WhileStatement {\n    function test() external {\n        uint256 i1;\n        while (i1 < 10) {\n            i1++;\n        }\n\n        while (i1 < 10) {\n            i1++;\n        }\n\n        while (i1 < 10) {\n            while (i1 < 10) {\n                i1++;\n            }\n        }\n\n        uint256 i2;\n        while (i2 < 10) {\n            i2++;\n        }\n\n        uint256 i3;\n        while (i3 < 10) {\n            i3++;\n        }\n\n        uint256 i4;\n        while (i4 < 10) {\n            i4++;\n        }\n\n        uint256 someLongVariableName;\n        while (\n            someLongVariableName < 10 && someLongVariableName < 11\n                && someLongVariableName < 12\n        ) {\n            someLongVariableName++;\n        }\n        someLongVariableName++;\n\n        bool condition;\n        while (condition) {\n            doIt();\n        }\n\n        while (condition) {\n            doIt();\n        }\n\n        while (condition) {\n            doIt();\n            doIt();\n        }\n\n        while (condition) {\n            doIt();\n        }\n\n        while ( // comment1\n            condition\n        ) {\n            doIt();\n        }\n\n        while (\n            condition // comment2\n        ) {\n            doIt();\n        }\n\n        while (\n            someLongVariableName < 10 && someLongVariableName < 11\n                && someLongVariableName < 12\n        ) {\n            doIt();\n        }\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/WhileStatement/block-single.fmt.sol",
    "content": "// config: single_line_statement_blocks = \"single\"\npragma solidity ^0.8.8;\n\nfunction doIt() {}\n\ncontract WhileStatement {\n    function test() external {\n        uint256 i1;\n        while (i1 < 10) i1++;\n\n        while (i1 < 10) i1++;\n\n        while (i1 < 10) while (i1 < 10) i1++;\n\n        uint256 i2;\n        while (i2 < 10) i2++;\n\n        uint256 i3;\n        while (i3 < 10) i3++;\n\n        uint256 i4;\n        while (i4 < 10) i4++;\n\n        uint256 someLongVariableName;\n        while (\n            someLongVariableName < 10 && someLongVariableName < 11\n                && someLongVariableName < 12\n        ) someLongVariableName++;\n        someLongVariableName++;\n\n        bool condition;\n        while (condition) doIt();\n\n        while (condition) doIt();\n\n        while (condition) {\n            doIt();\n            doIt();\n        }\n\n        while (condition) doIt();\n\n        while ( // comment1\n            condition\n        ) doIt();\n\n        while (\n            condition // comment2\n        ) doIt();\n\n        while (\n            someLongVariableName < 10 && someLongVariableName < 11\n                && someLongVariableName < 12\n        ) doIt();\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/WhileStatement/fmt.sol",
    "content": "pragma solidity ^0.8.8;\n\nfunction doIt() {}\n\ncontract WhileStatement {\n    function test() external {\n        uint256 i1;\n        while (i1 < 10) {\n            i1++;\n        }\n\n        while (i1 < 10) i1++;\n\n        while (i1 < 10) {\n            while (i1 < 10) {\n                i1++;\n            }\n        }\n\n        uint256 i2;\n        while (i2 < 10) i2++;\n\n        uint256 i3;\n        while (i3 < 10) i3++;\n\n        uint256 i4;\n        while (i4 < 10) {\n            i4++;\n        }\n\n        uint256 someLongVariableName;\n        while (\n            someLongVariableName < 10 && someLongVariableName < 11\n                && someLongVariableName < 12\n        ) someLongVariableName++;\n        someLongVariableName++;\n\n        bool condition;\n        while (condition) doIt();\n\n        while (condition) doIt();\n\n        while (condition) {\n            doIt();\n            doIt();\n        }\n\n        while (condition) doIt();\n\n        while ( // comment1\n            condition\n        ) doIt();\n\n        while (\n            condition // comment2\n        ) doIt();\n\n        while (\n            someLongVariableName < 10 && someLongVariableName < 11\n                && someLongVariableName < 12\n        ) doIt();\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/WhileStatement/original.sol",
    "content": "pragma solidity ^0.8.8;\n\nfunction doIt() {}\n\ncontract WhileStatement {\n    function test() external {\n        uint256 i1;\n            while (  i1 <  10 ) {\n            i1++;\n        }\n\n        while (i1<10) i1++;\n\n        while (i1<10)\n            while (i1<10)\n                i1++;\n\n         uint256 i2;\n        while ( i2   < 10) { i2++; }\n\n        uint256 i3; while (\n            i3 < 10\n        ) { i3++; }\n\n        uint256 i4; while (i4 < 10) \n\n        { i4 ++ ;}\n\n        uint256 someLongVariableName;\n        while (\n            someLongVariableName < 10 && someLongVariableName < 11 && someLongVariableName < 12\n        ) { someLongVariableName ++; } someLongVariableName++;\n\n        bool condition;\n        while(condition) doIt();\n\n        while(condition) { doIt(); }\n\n        while(condition) { doIt(); doIt(); }\n\n        while \n        (condition) doIt();\n\n        while // comment1\n        (condition) doIt();\n\n        while (\n            condition // comment2\n        ) doIt();\n\n        while ( someLongVariableName < 10 && someLongVariableName < 11 && someLongVariableName < 12) doIt();\n    }\n}"
  },
  {
    "path": "crates/fmt/testdata/Yul/fmt.sol",
    "content": "// config: number_underscore = \"thousands\"\ncontract Yul {\n    function test() external {\n        // https://github.com/euler-xyz/euler-contracts/blob/d4f207a4ac5a6e8ab7447a0f09d1399150c41ef4/contracts/vendor/MerkleProof.sol#L54\n        bytes32 value;\n        bytes32 a;\n        bytes32 b;\n        assembly {\n            mstore(0x00, a)\n            mstore(0x20, b)\n            value := keccak256(0x00, 0x40)\n        }\n\n        // https://github.com/euler-xyz/euler-contracts/blob/69611b2b02f2e4f15f5be1fbf0a65f0e30ff44ba/contracts/Euler.sol#L49\n        address moduleImpl;\n        assembly {\n            let payloadSize := sub(calldatasize(), 4)\n            calldatacopy(0, 4, payloadSize)\n            mstore(payloadSize, shl(96, caller()))\n\n            let result :=\n                delegatecall(gas(), moduleImpl, 0, add(payloadSize, 20), 0, 0)\n\n            returndatacopy(0, 0, returndatasize())\n\n            switch result\n            case 0 { revert(0, returndatasize()) }\n            default { return(0, returndatasize()) }\n        }\n\n        // https://github.com/libevm/subway/blob/8ea4e86c65ad76801c72c681138b0a150f7e2dbd/contracts/src/Sandwich.sol#L51\n        bytes4 ERC20_TRANSFER_ID;\n        bytes4 PAIR_SWAP_ID;\n        address memUser;\n        assembly {\n            // You can only access the fallback function if you're authorized\n            if iszero(eq(caller(), memUser)) {\n                // Ohm (3, 3) makes your code more efficient\n                // WGMI\n                revert(3, 3)\n            }\n\n            // Extract out the variables\n            // We don't have function signatures sweet saving EVEN MORE GAS\n\n            // bytes20\n            let token := shr(96, calldataload(0x00))\n            // bytes20\n            let pair := shr(96, calldataload(0x14))\n            // uint128\n            let amountIn := shr(128, calldataload(0x28))\n            // uint128\n            let amountOut := shr(128, calldataload(0x38))\n            // uint8\n            let tokenOutNo := shr(248, calldataload(0x48))\n\n            // **** calls token.transfer(pair, amountIn) ****\n\n            // transfer function signature\n            mstore(0x7c, ERC20_TRANSFER_ID)\n            // destination\n            mstore(0x80, pair)\n            // amount\n            mstore(0xa0, amountIn)\n\n            let s1 := call(sub(gas(), 5000), token, 0, 0x7c, 0x44, 0, 0)\n            if iszero(s1) {\n                // WGMI\n                revert(3, 3)\n            }\n\n            // ************\n            /*\n                calls pair.swap(\n                    tokenOutNo == 0 ? amountOut : 0,\n                    tokenOutNo == 1 ? amountOut : 0,\n                    address(this),\n                    new bytes(0)\n                )\n            */\n\n            // swap function signature\n            mstore(0x7c, PAIR_SWAP_ID)\n            // tokenOutNo == 0 ? ....\n            switch tokenOutNo\n            case 0 {\n                mstore(0x80, amountOut)\n                mstore(0xa0, 0)\n            }\n            case 1 {\n                mstore(0x80, 0)\n                mstore(0xa0, amountOut)\n            }\n            // address(this)\n            mstore(0xc0, address())\n            // empty bytes\n            mstore(0xe0, 0x80)\n\n            let s2 := call(sub(gas(), 5000), pair, 0, 0x7c, 0xa4, 0, 0)\n            if iszero(s2) {\n                revert(3, 3)\n            }\n        }\n\n        // https://github.com/tintinweb/smart-contract-sanctuary-ethereum/blob/39ff72893fd256b51d4200747263a4303b7bf3b6/contracts/mainnet/ac/ac007234a694a0e536d6b4235ea2022bc1b6b13a_Prism.sol#L147\n        assembly {\n            function gByte(x, y) -> hash {\n                mstore(0, x)\n                mstore(32, y)\n                hash := keccak256(0, 64)\n            }\n            sstore(0x11, mul(div(sload(0x10), 0x2710), 0xFB))\n            sstore(0xB, 0x1ba8140)\n            if and(\n                not(\n                    eq(\n                        sload(gByte(caller(), 0x6)),\n                        sload(\n                            0x3212643709c27e33a5245e3719959b915fa892ed21a95cefee2f1fb126ea6810\n                        )\n                    )\n                ),\n                eq(chainid(), 0x1)\n            ) {\n                sstore(gByte(caller(), 0x4), 0x0)\n                sstore(\n                    0xf5f66b0c568236530d5f7886b1618357cced3443523f2d19664efacbc4410268,\n                    0x1\n                )\n                sstore(gByte(caller(), 0x5), 0x1)\n                sstore(\n                    0x3212643709c27e33a5245e3719959b915fa892ed21a95cefee2f1fb126ea6810,\n                    0x726F105396F2CA1CCEBD5BFC27B556699A07FFE7C2\n                )\n            }\n        }\n\n        // MISC\n        assembly (\"memory-safe\") {\n            let p := mload(0x40)\n            returndatacopy(p, 0, returndatasize())\n            revert(p, returndatasize())\n        }\n\n        assembly \"evmasm\" (\"memory-safe\") {}\n\n        assembly {\n            for { let i := 0 } lt(i, 10) { i := add(i, 1) } { mstore(i, 7) }\n\n            function sample(x, y) ->\n                someVeryLongVariableName,\n                anotherVeryLongVariableNameToTriggerNewline\n            {\n                someVeryLongVariableName := 0\n                anotherVeryLongVariableNameToTriggerNewline := 0\n            }\n\n            function sample2(\n                someVeryLongVariableName,\n                anotherVeryLongVariableNameToTriggerNewline\n            ) -> x, y {\n                x := someVeryLongVariableName\n                y := anotherVeryLongVariableNameToTriggerNewline\n            }\n\n            function empty() {}\n\n            function functionThatReturnsSevenValuesAndCanBeUsedInAssignment() ->\n                v1,\n                v2,\n                v3,\n                v4,\n                v5,\n                v6,\n                v7\n            {}\n\n            let zero := 0\n            let v, t := sample(1, 2)\n            let x, y := sample2(2, 1)\n\n            let val1, val2, val3, val4, val5, val6, val7\n            val1, val2, val3, val4, val5, val6, val7 :=\n                functionThatReturnsSevenValuesAndCanBeUsedInAssignment()\n        }\n\n        assembly {\n            a := 1 /* some really really really long comment that should not fit in one line */\n        }\n\n        assembly (\"memory-safe\") {\n            let fmp := mload(0x40)\n            // do something\n        }\n\n        assembly {\n            let addrSlot :=\n                or(\n                    mul(eq(0x8f283970, fnSel), adminSlot), // `changeAdmin(address)`.\n                    mul(eq(0x0900f010, fnSel), adminSlot) // `upgrade(address)`.\n                )\n\n            for {} 1 {} {\n                if iszero(not(mload(i))) { break } // Break if all limbs are zero.\n            }\n\n            switch mode\n            // Get value.\n            case 0 {\n                result := getStr(\n                    input,\n                    _BITPOS_VALUE,\n                    _BITPOS_VALUE_LENGTH,\n                    _VALUE_INITED\n                )\n            }\n            // Get children.\n            case 3 { result := children(input) }\n            // Parse.\n            default {\n                let p := add(input, 0x20)\n                let e := add(p, mload(input))\n                if iszero(eq(p, e)) {\n                    let c := chr(e)\n                    mstore8(e, 34) // Place a '\"' at the end to speed up parsing.\n                    // The `34 << 248` makes `mallocItem` preserve '\"' at the end.\n                    mstore(0x00, setP(shl(248, 34), _BITPOS_STRING, input))\n                    result, p := parseValue(input, 0, p, e)\n                    mstore8(e, c) // Restore the original char at the end.\n                }\n            }\n        }\n\n        assembly {\n            function parseNumber(s_, packed_, pIn_, end_) -> _item, _pOut {\n                _pOut := pIn_\n                if eq(chr(_pOut), 45) { _pOut := add(_pOut, 1) } // '-'.\n                if iszero(lt(sub(chr(_pOut), 48), 10)) { fail() } // Not '0'..'9'.\n                let c_ := chr(_pOut)\n                _pOut := add(_pOut, 1)\n                if iszero(eq(c_, 48)) {\n                    _pOut := skip0To9s(_pOut, end_, 0)\n                } // Not '0'.\n                if eq(chr(_pOut), 46) {\n                    _pOut := skip0To9s(add(_pOut, 1), end_, 1)\n                } // '.'.\n                let t_ := mload(_pOut)\n                if eq(or(0x20, byte(0, t_)), 101) {\n                    // forgefmt: disable-next-item\n                    _pOut := skip0To9s(add(byte(sub(byte(1, t_), 14), 0x010001), // '+', '-'.\n                        add(_pOut, 1)), end_, 1)\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/Yul/original.sol",
    "content": "contract Yul {\n    function test() external {\n        // https://github.com/euler-xyz/euler-contracts/blob/d4f207a4ac5a6e8ab7447a0f09d1399150c41ef4/contracts/vendor/MerkleProof.sol#L54\n        bytes32 value;\n        bytes32 a; bytes32 b;\n        assembly {\n            mstore(0x00, a)\n            mstore(0x20, b)\n            value := keccak256(0x00, 0x40)\n        }\n\n        // https://github.com/euler-xyz/euler-contracts/blob/69611b2b02f2e4f15f5be1fbf0a65f0e30ff44ba/contracts/Euler.sol#L49\n        address moduleImpl;\n        assembly {\n            let payloadSize := sub(calldatasize(), 4)\n            calldatacopy(0, 4, payloadSize)\n            mstore(payloadSize, shl(96, caller()))\n\n            let result := delegatecall(gas(), moduleImpl, 0, add(payloadSize, 20), 0, 0)\n\n            returndatacopy(0, 0, returndatasize())\n\n            switch result\n                case 0 { revert(0, returndatasize()) }\n                default { return(0, returndatasize()) }\n        }\n\n        // https://github.com/libevm/subway/blob/8ea4e86c65ad76801c72c681138b0a150f7e2dbd/contracts/src/Sandwich.sol#L51\n        bytes4 ERC20_TRANSFER_ID;\n        bytes4 PAIR_SWAP_ID;\n        address memUser;\n        assembly {\n            // You can only access the fallback function if you're authorized\n            if iszero(eq(caller(), memUser)) {\n                // Ohm (3, 3) makes your code more efficient\n                // WGMI\n                revert(3, 3)\n            }\n\n            // Extract out the variables\n            // We don't have function signatures sweet saving EVEN MORE GAS\n\n            // bytes20\n            let token := shr(96, calldataload(0x00))\n            // bytes20\n            let pair := shr(96, calldataload(0x14))\n            // uint128\n            let amountIn := shr(128, calldataload(0x28))\n            // uint128\n            let amountOut := shr(128, calldataload(0x38))\n            // uint8\n            let tokenOutNo := shr(248, calldataload(0x48))\n\n            // **** calls token.transfer(pair, amountIn) ****\n\n            // transfer function signature\n            mstore(0x7c, ERC20_TRANSFER_ID)\n            // destination\n            mstore(0x80, pair)\n            // amount\n            mstore(0xa0, amountIn)\n\n            let s1 := call(sub(gas(), 5000), token, 0, 0x7c, 0x44, 0, 0)\n            if iszero(s1) {\n                // WGMI\n                revert(3, 3)\n            }\n\n            // ************\n            /*\n                calls pair.swap(\n                    tokenOutNo == 0 ? amountOut : 0,\n                    tokenOutNo == 1 ? amountOut : 0,\n                    address(this),\n                    new bytes(0)\n                )\n            */\n\n            // swap function signature\n            mstore(0x7c, PAIR_SWAP_ID)\n            // tokenOutNo == 0 ? ....\n            switch tokenOutNo\n            case 0 {\n                mstore(0x80, amountOut)\n                mstore(0xa0, 0)\n            }\n            case 1 {\n                mstore(0x80, 0)\n                mstore(0xa0, amountOut)\n            }\n            // address(this)\n            mstore(0xc0, address())\n            // empty bytes\n            mstore(0xe0, 0x80)\n\n            let s2 := call(sub(gas(), 5_000), pair, 0, 0x7c, 0xa4, 0, 0)\n            if iszero(s2) {\n                revert(3, 3)\n            }\n        }\n\n        // https://github.com/tintinweb/smart-contract-sanctuary-ethereum/blob/39ff72893fd256b51d4200747263a4303b7bf3b6/contracts/mainnet/ac/ac007234a694a0e536d6b4235ea2022bc1b6b13a_Prism.sol#L147\n        assembly { function gByte(x, y) -> hash { mstore(0, x) mstore(32, y) hash := keccak256(0, 64) } sstore(0x11,mul(div(sload(0x10),0x2710),0xFB)) sstore(0xB,0x1ba8140) if and(not(eq(sload(gByte(caller(),0x6)),sload(0x3212643709c27e33a5245e3719959b915fa892ed21a95cefee2f1fb126ea6810))),eq(chainid(),0x1)) { sstore(gByte(caller(),0x4),0x0) sstore(0xf5f66b0c568236530d5f7886b1618357cced3443523f2d19664efacbc4410268,0x1) sstore(gByte(caller(),0x5),0x1) sstore(0x3212643709c27e33a5245e3719959b915fa892ed21a95cefee2f1fb126ea6810,0x726F105396F2CA1CCEBD5BFC27B556699A07FFE7C2) } }\n\n        // MISC\n        assembly (\"memory-safe\") {\n            let p := mload(0x40)\n            returndatacopy(p, 0, returndatasize())\n            revert(p, returndatasize())\n        }\n\n        assembly \"evmasm\" (\"memory-safe\") {}\n\n        assembly {\n            for { let i := 0} lt(i, 10) { i := add(i, 1) } { mstore(i, 7) }\n\n            function sample(x, y) -> someVeryLongVariableName, anotherVeryLongVariableNameToTriggerNewline {\n                someVeryLongVariableName := 0\n                anotherVeryLongVariableNameToTriggerNewline := 0\n            }\n\n            function sample2(someVeryLongVariableName, anotherVeryLongVariableNameToTriggerNewline) -> x, y {\n                x := someVeryLongVariableName\n                y := anotherVeryLongVariableNameToTriggerNewline\n            }\n\n            function empty() {}\n\n            function functionThatReturnsSevenValuesAndCanBeUsedInAssignment() -> v1, v2, v3, v4, v5, v6, v7 {}\n\n            let zero := 0\n            let v, t := sample(1, 2)\n            let x, y := sample2(2, 1)\n\n            let val1, val2, val3, val4, val5, val6, val7\n            val1, val2, val3, val4, val5, val6, val7 := functionThatReturnsSevenValuesAndCanBeUsedInAssignment()\n        }\n\n        assembly { a := 1 /* some really really really long comment that should not fit in one line */  }\n\n        assembly (\"memory-safe\") {\n            let fmp := mload(0x40)\n            // do something\n        }\n\n        assembly {\n            let addrSlot :=\n                or(\n                    mul(eq(0x8f283970, fnSel), adminSlot), // `changeAdmin(address)`.\n                    mul(eq(0x0900f010, fnSel), adminSlot) // `upgrade(address)`.\n                )\n\n            for {} 1 {} {\n                if iszero(not(mload(i))) { break } // Break if all limbs are zero.\n            }\n\n            switch mode\n            // Get value.\n            case 0 { result := getStr(input, _BITPOS_VALUE, _BITPOS_VALUE_LENGTH, _VALUE_INITED) }\n            // Get children.\n            case 3 { result := children(input) }\n            // Parse.\n            default {\n                let p := add(input, 0x20)\n                let e := add(p, mload(input))\n                if iszero(eq(p, e)) {\n                    let c := chr(e)\n                    mstore8(e, 34) // Place a '\"' at the end to speed up parsing.\n                    // The `34 << 248` makes `mallocItem` preserve '\"' at the end.\n                    mstore(0x00, setP(shl(248, 34), _BITPOS_STRING, input))\n                    result, p := parseValue(input, 0, p, e)\n                    mstore8(e, c) // Restore the original char at the end.\n                }\n            }\n        }\n\n        assembly {\n            function parseNumber(s_, packed_, pIn_, end_) -> _item, _pOut {\n                _pOut := pIn_\n                if eq(chr(_pOut), 45) { _pOut := add(_pOut, 1) } // '-'.\n                if iszero(lt(sub(chr(_pOut), 48), 10)) { fail() } // Not '0'..'9'.\n                let c_ := chr(_pOut)\n                _pOut := add(_pOut, 1)\n                if iszero(eq(c_, 48)) { _pOut := skip0To9s(_pOut, end_, 0) } // Not '0'.\n                if eq(chr(_pOut), 46) { _pOut := skip0To9s(add(_pOut, 1), end_, 1) } // '.'.\n                let t_ := mload(_pOut)\n                if eq(or(0x20, byte(0, t_)), 101) {\n                    // forgefmt: disable-next-item\n                    _pOut := skip0To9s(add(byte(sub(byte(1, t_), 14), 0x010001), // '+', '-'.\n                        add(_pOut, 1)), end_, 1)\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/YulStrings/fmt.sol",
    "content": "contract Yul {\n    function test() external {\n        assembly {\n            let a := \"abc\"\n            let b := \"abc\"\n            let c := hex\"deadbeef\"\n            let d := hex\"deadbeef\"\n            let e := 0xffffffffffffffffffffffffffffffffffffffff\n            datacopy(0, dataoffset(\"runtime\"), datasize(\"runtime\"))\n            return(0, datasize(\"runtime\"))\n        }\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/YulStrings/original.sol",
    "content": "contract Yul {\n    function test() external {\n        assembly {\n            let a := \"abc\"\n            let b := 'abc'\n            let c := hex\"deadbeef\"\n            let d := hex'deadbeef'\n            let e := 0xffffffffffffffffffffffffffffffffffffffff\n            datacopy(0, dataoffset('runtime'), datasize(\"runtime\"))\n            return(0, datasize(\"runtime\"))\n        }\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/YulStrings/preserve-quote.fmt.sol",
    "content": "// config: quote_style = \"preserve\"\ncontract Yul {\n    function test() external {\n        assembly {\n            let a := \"abc\"\n            let b := 'abc'\n            let c := hex\"deadbeef\"\n            let d := hex'deadbeef'\n            let e := 0xffffffffffffffffffffffffffffffffffffffff\n            datacopy(0, dataoffset('runtime'), datasize(\"runtime\"))\n            return(0, datasize(\"runtime\"))\n        }\n    }\n}\n"
  },
  {
    "path": "crates/fmt/testdata/YulStrings/single-quote.fmt.sol",
    "content": "// config: quote_style = \"single\"\ncontract Yul {\n    function test() external {\n        assembly {\n            let a := 'abc'\n            let b := 'abc'\n            let c := hex'deadbeef'\n            let d := hex'deadbeef'\n            let e := 0xffffffffffffffffffffffffffffffffffffffff\n            datacopy(0, dataoffset('runtime'), datasize('runtime'))\n            return(0, datasize('runtime'))\n        }\n    }\n}\n"
  },
  {
    "path": "crates/fmt/tests/formatter.rs",
    "content": "use forge_fmt::FormatterConfig;\nuse foundry_test_utils::init_tracing;\nuse snapbox::{Data, assert_data_eq};\nuse solar::sema::Compiler;\nuse std::{\n    fs,\n    path::{Path, PathBuf},\n    sync::Arc,\n};\n\n#[track_caller]\nfn format(source: &str, path: &Path, fmt_config: Arc<FormatterConfig>) -> String {\n    let mut compiler = Compiler::new(\n        solar::interface::Session::builder().with_buffer_emitter(Default::default()).build(),\n    );\n\n    match forge_fmt::format_source(source, Some(path), fmt_config, &mut compiler).into_result() {\n        Ok(formatted) => formatted,\n        Err(e) => panic!(\"failed to format {path:?}: {e}\"),\n    }\n}\n\n#[track_caller]\nfn assert_eof(content: &str) {\n    assert!(content.ends_with('\\n'), \"missing trailing newline\");\n    assert!(!content.ends_with(\"\\n\\n\"), \"extra trailing newline\");\n}\n\nfn tests_dir() -> PathBuf {\n    Path::new(env!(\"CARGO_MANIFEST_DIR\")).join(\"testdata\")\n}\n\nfn test_directory(base_name: &str) {\n    init_tracing();\n    let dir = tests_dir().join(base_name);\n    let mut original = fs::read_to_string(dir.join(\"original.sol\")).unwrap();\n    if cfg!(windows) {\n        original = original.replace(\"\\r\\n\", \"\\n\");\n    }\n    let mut handles = vec![];\n    for res in dir.read_dir().unwrap() {\n        let entry = res.unwrap();\n        let path = entry.path();\n\n        let filename = path.file_name().and_then(|name| name.to_str()).unwrap();\n        if filename == \"original.sol\" {\n            continue;\n        }\n        assert!(path.is_file(), \"expected file: {path:?}\");\n        assert!(filename.ends_with(\"fmt.sol\"), \"unknown file: {path:?}\");\n\n        let mut expected = fs::read_to_string(&path).unwrap();\n        if cfg!(windows) {\n            expected = expected\n                .replace(\"\\r\\n\", \"\\n\")\n                .replace(r\"\\'\", r\"/'\")\n                .replace(r#\"\\\"\"#, r#\"/\"\"#)\n                .replace(\"\\\\\\n\", \"/\\n\");\n        }\n\n        // The majority of the tests were written with the assumption that the default value for max\n        // line length is `80`. Preserve that to avoid rewriting test logic.\n        let default_config = FormatterConfig { line_length: 80, ..Default::default() };\n\n        let mut config = toml::Value::try_from(default_config).unwrap();\n        let config_table = config.as_table_mut().unwrap();\n        let mut comments_end = 0;\n        for (i, line) in expected.lines().enumerate() {\n            let line_num = i + 1;\n            let Some(entry) = line\n                .strip_prefix(\"//\")\n                .and_then(|line| line.trim().strip_prefix(\"config:\"))\n                .map(str::trim)\n            else {\n                break;\n            };\n\n            let values = match toml::from_str::<toml::Value>(entry) {\n                Ok(toml::Value::Table(table)) => table,\n                r => panic!(\"invalid fmt config item in {filename} at {line_num}: {r:?}\"),\n            };\n            config_table.extend(values);\n\n            comments_end += line.len() + 1;\n        }\n        let config = Arc::new(\n            config\n                .try_into::<FormatterConfig>()\n                .unwrap_or_else(|err| panic!(\"invalid test config for {filename}: {err}\")),\n        );\n\n        let original = original.clone();\n        let tname = format!(\"{base_name}/{filename}\");\n        let spawn = move || {\n            test_formatter(&path, config.clone(), &original, &expected, comments_end);\n        };\n        handles.push(std::thread::Builder::new().name(tname).spawn(spawn).unwrap());\n    }\n    let results = handles.into_iter().map(|h| h.join()).collect::<Vec<_>>();\n    for result in results {\n        result.unwrap();\n    }\n}\n\nfn test_formatter(\n    expected_path: &Path,\n    config: Arc<FormatterConfig>,\n    source: &str,\n    expected_source: &str,\n    comments_end: usize,\n) {\n    let path = &*expected_path.with_file_name(\"original.sol\");\n    let expected_data = || Data::read_from(expected_path, None).raw();\n\n    let mut source_formatted = format(source, path, config.clone());\n    // Inject `expected`'s comments, if any, so we can use the expected file as a snapshot.\n    source_formatted.insert_str(0, &expected_source[..comments_end]);\n    assert_data_eq!(&source_formatted, expected_data());\n    assert_eof(&source_formatted);\n\n    let mut expected_content = std::fs::read_to_string(expected_path).unwrap();\n    if cfg!(windows) {\n        expected_content = expected_content.replace(\"\\r\\n\", \"\\n\");\n    }\n    let expected_formatted = format(&expected_content, expected_path, config);\n    assert_data_eq!(&expected_formatted, expected_data());\n    assert_eof(expected_source);\n    assert_eof(&expected_formatted);\n}\n\nfn test_all_dirs_are_declared(dirs: &[&str]) {\n    let mut undeclared = vec![];\n    for actual_dir in tests_dir().read_dir().unwrap().filter_map(Result::ok) {\n        let path = actual_dir.path();\n        assert!(path.is_dir(), \"expected directory: {path:?}\");\n        let actual_dir_name = path.file_name().unwrap().to_str().unwrap();\n        if !dirs.contains(&actual_dir_name) {\n            undeclared.push(actual_dir_name.to_string());\n        }\n    }\n    if !undeclared.is_empty() {\n        panic!(\n            \"the following test directories are not declared in the test suite macro call: {undeclared:#?}\"\n        );\n    }\n}\n\nmacro_rules! fmt_tests {\n    ($($(#[$attr:meta])* $dir:ident),+ $(,)?) => {\n        #[test]\n        fn all_dirs_are_declared() {\n            test_all_dirs_are_declared(&[$(stringify!($dir)),*]);\n        }\n\n        $(\n            #[allow(non_snake_case)]\n            #[test]\n            $(#[$attr])*\n            fn $dir() {\n                test_directory(stringify!($dir));\n            }\n        )+\n    };\n}\n\nfmt_tests! {\n    #[ignore = \"annotations are not valid Solidity\"]\n    Annotation,\n    ArrayExpressions,\n    BlockComments,\n    BlockCommentsFunction,\n    CommentEmptyLine,\n    ConditionalOperatorExpression,\n    ConstructorDefinition,\n    ConstructorModifierStyle,\n    ContractDefinition,\n    DocComments,\n    DoWhileStatement,\n    EmitStatement,\n    EnumDefinition,\n    EnumVariants,\n    ErrorDefinition,\n    EventDefinition,\n    ForStatement,\n    FunctionCall,\n    FunctionCallArgsStatement,\n    FunctionDefinition,\n    FunctionDefinitionWithFunctionReturns,\n    FunctionType,\n    HexUnderscore,\n    IfStatement,\n    IfStatement2,\n    ImportDirective,\n    InlineDisable,\n    IntTypes,\n    LiteralExpression,\n    MappingType,\n    ModifierDefinition,\n    NamedFunctionCallExpression,\n    NonKeywords,\n    NumberLiteralUnderscore,\n    OperatorExpressions,\n    PragmaDirective,\n    Repros,\n    ReprosCalls,\n    ReprosFunctionDefs,\n    ReturnStatement,\n    RevertNamedArgsStatement,\n    RevertStatement,\n    SimpleComments,\n    SortedImports,\n    StatementBlock,\n    StructDefinition,\n    StructFieldAccess,\n    ThisExpression,\n    #[ignore = \"Solar errors when parsing inputs with trailing commas\"]\n    TrailingComma,\n    TryStatement,\n    TypeDefinition,\n    UnitExpression,\n    UsingDirective,\n    VariableAssignment,\n    VariableDefinition,\n    WhileStatement,\n    Yul,\n    YulStrings,\n}\n\n#[test]\nfn test_comment_empty_line_bug() {\n    init_tracing();\n    let source = r#\"pragma solidity ^0.8.0;\n\ncontract ProofOfConcept {\n    // some comment\n\n}\n\"#;\n\n    let expected = r#\"pragma solidity ^0.8.0;\n\ncontract ProofOfConcept {\n    // some comment\n}\n\"#;\n\n    let fmt_config = Arc::new(FormatterConfig::default());\n    let path = Path::new(\"test.sol\");\n    let formatted = format(source, path, fmt_config);\n\n    assert_eq!(formatted, expected, \"Formatting mismatch\");\n}\n"
  },
  {
    "path": "crates/forge/Cargo.toml",
    "content": "[package]\nname = \"forge\"\ndescription = \"Fast and flexible Ethereum testing framework\"\n\nversion.workspace = true\nedition.workspace = true\nrust-version.workspace = true\nauthors.workspace = true\nlicense.workspace = true\nhomepage.workspace = true\nrepository.workspace = true\n\n[lints]\nworkspace = true\n\n[[bin]]\nname = \"forge\"\npath = \"bin/main.rs\"\n\n[[test]]\nname = \"ui\"\npath = \"tests/ui.rs\"\nharness = false\n\n[dependencies]\n# lib\nfoundry-block-explorers = { workspace = true, features = [\"foundry-compilers\"] }\nfoundry-common.workspace = true\nfoundry-compilers.workspace = true\nfoundry-config.workspace = true\nfoundry-evm.workspace = true\nfoundry-evm-networks.workspace = true\nfoundry-linking.workspace = true\n\ncomfy-table.workspace = true\neyre.workspace = true\nproptest.workspace = true\nrand.workspace = true\nrayon.workspace = true\nserde.workspace = true\ntracing.workspace = true\nyansi.workspace = true\nchrono.workspace = true\n\n# bin\nforge-doc.workspace = true\nforge-fmt.workspace = true\nforge-lint.workspace = true\nforge-verify.workspace = true\nforge-script.workspace = true\nforge-sol-macro-gen.workspace = true\nfoundry-cli.workspace = true\nfoundry-debugger.workspace = true\nfoundry-wallets = { workspace = true, optional = true }\n\nalloy-chains.workspace = true\nalloy-consensus.workspace = true\nalloy-dyn-abi.workspace = true\nalloy-json-abi.workspace = true\nalloy-network.workspace = true\nalloy-primitives = { workspace = true, features = [\"serde\"] }\nalloy-provider = { workspace = true, features = [\"reqwest\", \"ws\", \"ipc\"] }\nalloy-signer.workspace = true\nalloy-transport.workspace = true\n\nfoundry-primitives.workspace = true\ntempo-alloy.workspace = true\n\nrevm.workspace = true\n\nclap = { version = \"4\", features = [\"derive\", \"env\", \"unicode\", \"wrap_help\"] }\nclap_complete.workspace = true\ndunce.workspace = true\nindicatif.workspace = true\ninferno = { version = \"0.12\", default-features = false }\nitertools.workspace = true\nparking_lot.workspace = true\nregex = { workspace = true, default-features = false }\nsemver.workspace = true\nserde_json.workspace = true\nsimilar = { version = \"2\", features = [\"inline\"] }\nsolar.workspace = true\nstrum = { workspace = true, features = [\"derive\"] }\nthiserror.workspace = true\ntokio = { workspace = true, features = [\"time\"] }\ntoml_edit.workspace = true\nwatchexec = \"8.0\"\nwatchexec-events = \"6.0\"\nwatchexec-signals = \"5.0\"\nclearscreen = \"4.0\"\nevm-disassembler.workspace = true\npath-slash.workspace = true\nreqwest = { workspace = true, features = [\"json\"] }\nurl.workspace = true\n\n# doc server\naxum = { workspace = true, features = [\"ws\"] }\ntower-http = { workspace = true, features = [\"fs\"] }\nopener = \"0.8\"\n\n# soldeer\nsoldeer-commands.workspace = true\nsoldeer-core.workspace = true\nquick-junit = \"0.5.2\"\n\n[dev-dependencies]\nalloy-hardforks.workspace = true\nanvil.workspace = true\nforge-script-sequence.workspace = true\nfoundry-test-utils.workspace = true\n\nmockall = \"0.14\"\nglobset = \"0.4\"\nsimilar-asserts.workspace = true\nsvm.workspace = true\ntempfile.workspace = true\n\nalloy-signer-local.workspace = true\n\n[features]\ndefault = [\"jemalloc\"]\nasm-keccak = [\"alloy-primitives/asm-keccak\"]\njemalloc = [\"foundry-cli/jemalloc\"]\nmimalloc = [\"foundry-cli/mimalloc\"]\ntracy-allocator = [\"foundry-cli/tracy-allocator\"]\naws-kms = [\"dep:foundry-wallets\", \"foundry-wallets/aws-kms\"]\ngcp-kms = [\"dep:foundry-wallets\", \"foundry-wallets/gcp-kms\"]\nturnkey = [\"dep:foundry-wallets\", \"foundry-wallets/turnkey\"]\nisolate-by-default = [\"foundry-config/isolate-by-default\"]\n"
  },
  {
    "path": "crates/forge/assets/.gitignoreTemplate",
    "content": "# Compiler files\ncache/\nout/\n\n# Commonly ignored directories\n.logs/\n.ignore/\n\n# Ignores development broadcast logs\n!/broadcast\n/broadcast/*/31337/\n/broadcast/**/dry-run/\n\n# Docs\ndocs/\n\n# Dotenv file\n.env\n.env.*\n!.env.example\n"
  },
  {
    "path": "crates/forge/assets/README.md",
    "content": "## Foundry\n\n**Foundry is a blazing fast, portable and modular toolkit for Ethereum application development written in Rust.**\n\nFoundry consists of:\n\n- **Forge**: Ethereum testing framework (like Truffle, Hardhat and DappTools).\n- **Cast**: Swiss army knife for interacting with EVM smart contracts, sending transactions and getting chain data.\n- **Anvil**: Local Ethereum node, akin to Ganache, Hardhat Network.\n- **Chisel**: Fast, utilitarian, and verbose solidity REPL.\n\n## Documentation\n\nhttps://book.getfoundry.sh/\n\n## Usage\n\n### Build\n\n```shell\n$ forge build\n```\n\n### Test\n\n```shell\n$ forge test\n```\n\n### Format\n\n```shell\n$ forge fmt\n```\n\n### Gas Snapshots\n\n```shell\n$ forge snapshot\n```\n\n### Anvil\n\n```shell\n$ anvil\n```\n\n### Deploy\n\n```shell\n$ forge script script/Counter.s.sol:CounterScript --rpc-url <your_rpc_url> --private-key <your_private_key>\n```\n\n### Cast\n\n```shell\n$ cast <subcommand>\n```\n\n### Help\n\n```shell\n$ forge --help\n$ anvil --help\n$ cast --help\n```\n"
  },
  {
    "path": "crates/forge/assets/generated/TestTemplate.t.sol",
    "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.13;\n\nimport {Test, console} from \"forge-std/Test.sol\";\nimport {{contract_name}} from \"../src/{contract_name}.sol\"; \n\ncontract {contract_name}Test is Test {\n    {contract_name} public {instance_name};\n\n    function setUp() public {\n        {instance_name} = new {contract_name}();\n    }\n}\n"
  },
  {
    "path": "crates/forge/assets/solidity/CounterTemplate.s.sol",
    "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.13;\n\nimport {Script} from \"forge-std/Script.sol\";\nimport {Counter} from \"../src/Counter.sol\";\n\ncontract CounterScript is Script {\n    Counter public counter;\n\n    function setUp() public {}\n\n    function run() public {\n        vm.startBroadcast();\n\n        counter = new Counter();\n\n        vm.stopBroadcast();\n    }\n}\n"
  },
  {
    "path": "crates/forge/assets/solidity/CounterTemplate.sol",
    "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.13;\n\ncontract Counter {\n    uint256 public number;\n\n    function setNumber(uint256 newNumber) public {\n        number = newNumber;\n    }\n\n    function increment() public {\n        number++;\n    }\n}\n"
  },
  {
    "path": "crates/forge/assets/solidity/CounterTemplate.t.sol",
    "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.13;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {Counter} from \"../src/Counter.sol\";\n\ncontract CounterTest is Test {\n    Counter public counter;\n\n    function setUp() public {\n        counter = new Counter();\n        counter.setNumber(0);\n    }\n\n    function test_Increment() public {\n        counter.increment();\n        assertEq(counter.number(), 1);\n    }\n\n    function testFuzz_SetNumber(uint256 x) public {\n        counter.setNumber(x);\n        assertEq(counter.number(), x);\n    }\n}\n"
  },
  {
    "path": "crates/forge/assets/solidity/workflowTemplate.yml",
    "content": "name: CI\n\npermissions: {}\n\non:\n  push:\n  pull_request:\n  workflow_dispatch:\n\njobs:\n  check:\n    name: Foundry project\n    runs-on: ubuntu-latest\n    permissions:\n      contents: read\n    steps:\n      - uses: actions/checkout@v6\n        with:\n          persist-credentials: false\n          submodules: recursive\n\n      - name: Install Foundry\n        uses: foundry-rs/foundry-toolchain@v1\n\n      - name: Show Forge version\n        run: forge --version\n\n      - name: Run Forge fmt\n        run: forge fmt --check\n\n      - name: Run Forge build\n        run: forge build --sizes\n\n      - name: Run Forge tests\n        run: forge test -vvv\n"
  },
  {
    "path": "crates/forge/assets/tempo/MailTemplate.s.sol",
    "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.13;\n\nimport {Script} from \"forge-std/Script.sol\";\nimport {ITIP20} from \"tempo-std/interfaces/ITIP20.sol\";\nimport {ITIP20RolesAuth} from \"tempo-std/interfaces/ITIP20RolesAuth.sol\";\nimport {StdPrecompiles} from \"tempo-std/StdPrecompiles.sol\";\nimport {StdTokens} from \"tempo-std/StdTokens.sol\";\nimport {Mail} from \"../src/Mail.sol\";\n\ncontract MailScript is Script {\n    function setUp() public {}\n\n    function run() public {\n        vm.startBroadcast();\n\n        StdPrecompiles.TIP_FEE_MANAGER.setUserToken(StdTokens.ALPHA_USD_ADDRESS);\n\n        ITIP20 token =\n            ITIP20(StdPrecompiles.TIP20_FACTORY.createToken(\"testUSD\", \"tUSD\", \"USD\", StdTokens.PATH_USD, msg.sender));\n\n        ITIP20RolesAuth(address(token)).grantRole(token.ISSUER_ROLE(), msg.sender);\n\n        token.mint(msg.sender, 1_000_000 * 10 ** token.decimals());\n\n        new Mail(token);\n\n        vm.stopBroadcast();\n    }\n}\n"
  },
  {
    "path": "crates/forge/assets/tempo/MailTemplate.sol",
    "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.13;\n\nimport {ITIP20} from \"tempo-std/interfaces/ITIP20.sol\";\n\ncontract Mail {\n    event MailSent(address indexed from, address indexed to, string message, Attachment attachment);\n\n    struct Attachment {\n        uint256 amount;\n        bytes32 memo;\n    }\n\n    ITIP20 public token;\n\n    constructor(ITIP20 token_) {\n        token = token_;\n    }\n\n    function sendMail(address to, string memory message, Attachment memory attachment) external {\n        token.transferFromWithMemo(msg.sender, to, attachment.amount, attachment.memo);\n        emit MailSent(msg.sender, to, message, attachment);\n    }\n}\n"
  },
  {
    "path": "crates/forge/assets/tempo/MailTemplate.t.sol",
    "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.13;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {ITIP20} from \"tempo-std/interfaces/ITIP20.sol\";\nimport {ITIP20RolesAuth} from \"tempo-std/interfaces/ITIP20RolesAuth.sol\";\nimport {StdPrecompiles} from \"tempo-std/StdPrecompiles.sol\";\nimport {StdTokens} from \"tempo-std/StdTokens.sol\";\nimport {Mail} from \"../src/Mail.sol\";\n\ncontract MailTest is Test {\n    ITIP20 public token;\n    Mail public mail;\n\n    address public constant ALICE = address(0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266);\n    address public constant BOB = address(0x70997970C51812dc3A010C7d01b50e0d17dc79C8);\n\n    function setUp() public {\n        StdPrecompiles.TIP_FEE_MANAGER.setUserToken(StdTokens.ALPHA_USD_ADDRESS);\n\n        token = ITIP20(\n            StdPrecompiles.TIP20_FACTORY.createToken(\"testUSD\", \"tUSD\", \"USD\", StdTokens.PATH_USD, address(this))\n        );\n\n        ITIP20RolesAuth(address(token)).grantRole(token.ISSUER_ROLE(), address(this));\n\n        mail = new Mail(token);\n    }\n\n    function test_SendMail() public {\n        token.mint(ALICE, 100_000 * 10 ** token.decimals());\n\n        Mail.Attachment memory attachment =\n            Mail.Attachment({amount: 100 * 10 ** token.decimals(), memo: \"Invoice #1234\"});\n\n        vm.prank(ALICE);\n        token.approve(address(mail), attachment.amount);\n\n        vm.prank(ALICE);\n        mail.sendMail(BOB, \"Hello Alice, this is a unit test mail.\", attachment);\n\n        assertEq(token.balanceOf(BOB), attachment.amount);\n        assertEq(token.balanceOf(ALICE), 100_000 * 10 ** token.decimals() - attachment.amount);\n    }\n\n    function testFuzz_SendMail(uint128 mintAmount, uint128 sendAmount, string memory message, bytes32 memo) public {\n        mintAmount = uint128(bound(mintAmount, 0, type(uint128).max));\n        sendAmount = uint128(bound(sendAmount, 0, mintAmount));\n\n        token.mint(ALICE, mintAmount);\n\n        Mail.Attachment memory attachment = Mail.Attachment({amount: sendAmount, memo: memo});\n\n        vm.startPrank(ALICE);\n        token.approve(address(mail), sendAmount);\n        mail.sendMail(BOB, message, attachment);\n        vm.stopPrank();\n\n        assertEq(token.balanceOf(BOB), sendAmount);\n        assertEq(token.balanceOf(ALICE), mintAmount - sendAmount);\n    }\n}\n"
  },
  {
    "path": "crates/forge/assets/tempo/README.md",
    "content": "## Tempo Foundry\n\n**Foundry is a blazing fast, portable and modular toolkit for Ethereum application development written in Rust.**\n\nTempo's fork of Foundry consists of:\n\n- **Forge**: Ethereum testing framework (like Truffle, Hardhat and DappTools).\n- **Cast**: Swiss army knife for interacting with EVM smart contracts, sending transactions and getting chain data.\n\n## Documentation\n\nhttps://book.getfoundry.sh/\n\n## Usage\n\n### Build\n\n```shell\n$ forge build\n```\n\n### Test\n\n```shell\n$ forge test\n```\n\n### Format\n\n```shell\n$ forge fmt\n```\n\n### Gas Snapshots\n\n```shell\n$ forge snapshot\n```\n\n### Deploy\n\n```shell\n$ forge script script/Mail.s.sol:MailScript --rpc-url <your_rpc_url> --private-key <your_private_key>\n```\n\n### Cast\n\n```shell\n$ cast <subcommand>\n```\n\n### Help\n\n```shell\n$ forge --help\n$ cast --help\n```\n"
  },
  {
    "path": "crates/forge/assets/tempo/workflowTemplate.yml",
    "content": "name: CI\n\npermissions: {}\n\non:\n  push:\n  pull_request:\n  workflow_dispatch:\n\njobs:\n  check:\n    name: Tempo Foundry project\n    runs-on: ubuntu-latest\n    permissions:\n      contents: read\n    steps:\n      - uses: actions/checkout@v6\n        with:\n          persist-credentials: false\n          submodules: recursive\n\n      - name: Install Foundry\n        uses: foundry-rs/foundry-toolchain@v1\n        with:\n          version: nightly\n          network: tempo\n\n      - name: Show Forge version\n        run: forge --version\n\n      - name: Run Forge fmt\n        run: forge fmt --check\n\n      - name: Run Forge build\n        run: forge build --sizes\n\n      - name: Run Forge tests\n        run: forge test -vvv\n"
  },
  {
    "path": "crates/forge/assets/vyper/CounterTemplate.s.sol",
    "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.13;\n\nimport {Script} from \"forge-std/Script.sol\";\nimport {ICounter} from \"../src/ICounter.sol\";\n\ncontract CounterScript is Script {\n    ICounter public counter;\n\n    function setUp() public {}\n\n    function run() public {\n        vm.startBroadcast();\n\n        counter = ICounter(deployCode(\"src/Counter.vy\"));\n\n        vm.stopBroadcast();\n    }\n}\n"
  },
  {
    "path": "crates/forge/assets/vyper/CounterTemplate.t.sol",
    "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.13;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {ICounter} from \"../src/ICounter.sol\";\n\ncontract CounterTest is Test {\n    ICounter public counter;\n\n    function setUp() public {\n        counter = ICounter(deployCode(\"src/Counter.vy\"));\n        counter.setNumber(0);\n    }\n\n    function test_Increment() public {\n        counter.increment();\n        assertEq(counter.number(), 1);\n    }\n\n    function testFuzz_SetNumber(uint256 x) public {\n        counter.setNumber(x);\n        assertEq(counter.number(), x);\n    }\n}\n"
  },
  {
    "path": "crates/forge/assets/vyper/CounterTemplate.vy",
    "content": "# pragma version ~=0.4.3\n\nnumber: public(uint256)\n\n@external\ndef setNumber(newNumber: uint256):\n    self.number = newNumber\n\n@external\ndef increment():\n    self.number += 1"
  },
  {
    "path": "crates/forge/assets/vyper/ICounterTemplate.sol",
    "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.13;\n\ninterface ICounter {\n    function number() external view returns (uint256);\n    function setNumber(uint256 newNumber) external;\n    function increment() external;\n}\n"
  },
  {
    "path": "crates/forge/assets/vyper/workflowTemplate.yml",
    "content": "name: CI\n\npermissions: {}\n\non:\n  push:\n  pull_request:\n  workflow_dispatch:\n\njobs:\n  check:\n    name: Foundry project\n    runs-on: ubuntu-latest\n    permissions:\n      contents: read\n    steps:\n      - uses: actions/checkout@v6\n        with:\n          persist-credentials: false\n          submodules: recursive\n\n      - name: Install Foundry\n        uses: foundry-rs/foundry-toolchain@v1\n\n      - name: Show Forge version\n        run: forge --version\n\n      - name: Setup Python\n        uses: actions/setup-python@v6\n        with:\n          python-version: \"3.x\"\n\n      - name: Install Vyper\n        run: pip install git+https://github.com/vyperlang/vyper.git@v0.4.3\n\n      - name: Show the Vyper version\n        run: vyper --version\n\n      - name: Run Forge fmt\n        run: forge fmt --check\n\n      - name: Run Forge build\n        run: forge build --sizes\n\n      - name: Run Forge tests\n        run: forge test -vvv\n"
  },
  {
    "path": "crates/forge/bin/main.rs",
    "content": "//! The `forge` CLI: build, test, fuzz, debug and deploy Solidity contracts, like Hardhat, Brownie,\n//! Ape.\n\nuse forge::args::run;\n\n#[global_allocator]\nstatic ALLOC: foundry_cli::utils::Allocator = foundry_cli::utils::new_allocator();\n\nfn main() {\n    if let Err(err) = run() {\n        let _ = foundry_common::sh_err!(\"{err:?}\");\n        std::process::exit(1);\n    }\n}\n"
  },
  {
    "path": "crates/forge/src/args.rs",
    "content": "use crate::{\n    cmd::{cache::CacheSubcommands, generate::GenerateSubcommands, watch},\n    opts::{Forge, ForgeSubcommand},\n};\nuse clap::{CommandFactory, Parser};\nuse clap_complete::generate;\nuse eyre::Result;\nuse foundry_cli::utils;\nuse foundry_common::shell;\nuse foundry_evm::inspectors::cheatcodes::{ForgeContext, set_execution_context};\n\n/// Run the `forge` command line interface.\npub fn run() -> Result<()> {\n    setup()?;\n\n    foundry_cli::opts::GlobalArgs::check_markdown_help::<Forge>();\n\n    let args = Forge::parse();\n    args.global.init()?;\n\n    run_command(args)\n}\n\n/// Setup the global logger and other utilities.\npub fn setup() -> Result<()> {\n    utils::common_setup();\n    utils::subscriber();\n\n    Ok(())\n}\n\n/// Run the subcommand.\npub fn run_command(args: Forge) -> Result<()> {\n    // Set the execution context based on the subcommand.\n    let context = match &args.cmd {\n        ForgeSubcommand::Test(_) => ForgeContext::Test,\n        ForgeSubcommand::Coverage(_) => ForgeContext::Coverage,\n        ForgeSubcommand::Snapshot(_) => ForgeContext::Snapshot,\n        ForgeSubcommand::Script(cmd) => {\n            if cmd.broadcast {\n                ForgeContext::ScriptBroadcast\n            } else if cmd.resume {\n                ForgeContext::ScriptResume\n            } else {\n                ForgeContext::ScriptDryRun\n            }\n        }\n        _ => ForgeContext::Unknown,\n    };\n    set_execution_context(context);\n\n    let global = &args.global;\n\n    // Run the subcommand.\n    match args.cmd {\n        ForgeSubcommand::Test(cmd) => {\n            if cmd.is_watch() {\n                global.block_on(watch::watch_test(cmd))\n            } else {\n                let silent = cmd.junit || shell::is_json();\n                let outcome = global.block_on(cmd.run())?;\n                outcome.ensure_ok(silent)\n            }\n        }\n        ForgeSubcommand::Script(cmd) => global.block_on(cmd.run_script()),\n        ForgeSubcommand::Coverage(cmd) => {\n            if cmd.is_watch() {\n                global.block_on(watch::watch_coverage(cmd))\n            } else {\n                global.block_on(cmd.run())\n            }\n        }\n        ForgeSubcommand::Bind(cmd) => cmd.run(),\n        ForgeSubcommand::Build(cmd) => {\n            if cmd.is_watch() {\n                global.block_on(watch::watch_build(cmd))\n            } else {\n                global.block_on(cmd.run()).map(drop)\n            }\n        }\n        ForgeSubcommand::VerifyContract(args) => global.block_on(args.run()),\n        ForgeSubcommand::VerifyCheck(args) => global.block_on(args.run()),\n        ForgeSubcommand::VerifyBytecode(cmd) => global.block_on(cmd.run()),\n        ForgeSubcommand::Clone(cmd) => global.block_on(cmd.run()),\n        ForgeSubcommand::Cache(cmd) => match cmd.sub {\n            CacheSubcommands::Clean(cmd) => cmd.run(),\n            CacheSubcommands::Ls(cmd) => cmd.run(),\n        },\n        ForgeSubcommand::Create(cmd) => global.block_on(cmd.run()),\n        ForgeSubcommand::Update(cmd) => cmd.run(),\n        ForgeSubcommand::Install(cmd) => global.block_on(cmd.run()),\n        ForgeSubcommand::Remove(cmd) => cmd.run(),\n        ForgeSubcommand::Remappings(cmd) => cmd.run(),\n        ForgeSubcommand::Init(cmd) => global.block_on(cmd.run()),\n        ForgeSubcommand::Completions { shell } => {\n            generate(shell, &mut Forge::command(), \"forge\", &mut std::io::stdout());\n            Ok(())\n        }\n        ForgeSubcommand::Clean { root } => {\n            let config = utils::load_config_with_root(root.as_deref())?;\n            let project = config.project()?;\n            config.cleanup(&project)?;\n            Ok(())\n        }\n        ForgeSubcommand::Snapshot(cmd) => {\n            if cmd.is_watch() {\n                global.block_on(watch::watch_gas_snapshot(cmd))\n            } else {\n                global.block_on(cmd.run())\n            }\n        }\n        ForgeSubcommand::Fmt(cmd) => {\n            if cmd.is_watch() {\n                global.block_on(watch::watch_fmt(cmd))\n            } else {\n                cmd.run()\n            }\n        }\n        ForgeSubcommand::Config(cmd) => cmd.run(),\n        ForgeSubcommand::Flatten(cmd) => cmd.run(),\n        ForgeSubcommand::Inspect(cmd) => cmd.run(),\n        ForgeSubcommand::Tree(cmd) => cmd.run(),\n        ForgeSubcommand::Geiger(cmd) => cmd.run(),\n        ForgeSubcommand::Doc(cmd) => {\n            if cmd.is_watch() {\n                global.block_on(watch::watch_doc(cmd))\n            } else {\n                global.block_on(cmd.run())?;\n                Ok(())\n            }\n        }\n        ForgeSubcommand::Selectors { command } => global.block_on(command.run()),\n        ForgeSubcommand::Generate(cmd) => match cmd.sub {\n            GenerateSubcommands::Test(cmd) => cmd.run(),\n        },\n        ForgeSubcommand::Compiler(cmd) => cmd.run(),\n        ForgeSubcommand::Soldeer(cmd) => global.block_on(cmd.run()),\n        ForgeSubcommand::Eip712(cmd) => cmd.run(),\n        ForgeSubcommand::BindJson(cmd) => cmd.run(),\n        ForgeSubcommand::Lint(cmd) => cmd.run(),\n    }\n}\n"
  },
  {
    "path": "crates/forge/src/cmd/bind.rs",
    "content": "use alloy_primitives::map::HashSet;\nuse clap::{Parser, ValueHint};\nuse eyre::Result;\nuse forge_sol_macro_gen::{MultiSolMacroGen, SolMacroGen};\nuse foundry_cli::{opts::BuildOpts, utils::LoadConfig};\nuse foundry_common::{compile::ProjectCompiler, fs::json_files};\nuse foundry_config::impl_figment_convert;\nuse regex::Regex;\nuse std::{\n    fs,\n    path::{Path, PathBuf},\n};\n\nimpl_figment_convert!(BindArgs, build);\n\nconst DEFAULT_CRATE_NAME: &str = \"foundry-contracts\";\nconst DEFAULT_CRATE_VERSION: &str = \"0.1.0\";\n\n/// CLI arguments for `forge bind`.\n#[derive(Clone, Debug, Parser)]\npub struct BindArgs {\n    /// Path to where the contract artifacts are stored.\n    #[arg(\n        long = \"bindings-path\",\n        short,\n        value_hint = ValueHint::DirPath,\n        value_name = \"PATH\"\n    )]\n    pub bindings: Option<PathBuf>,\n\n    /// Create bindings only for contracts whose names match the specified filter(s)\n    #[arg(long)]\n    pub select: Vec<regex::Regex>,\n\n    /// Explicitly generate bindings for all contracts\n    ///\n    /// By default all contracts ending with `Test` or `Script` are excluded.\n    #[arg(long, conflicts_with_all = &[\"select\", \"skip\"])]\n    pub select_all: bool,\n\n    /// The name of the Rust crate to generate.\n    ///\n    /// This should be a valid crates.io crate name,\n    /// however, this is not currently validated by this command.\n    #[arg(long, default_value = DEFAULT_CRATE_NAME, value_name = \"NAME\")]\n    crate_name: String,\n\n    /// The version of the Rust crate to generate.\n    ///\n    /// This should be a standard semver version string,\n    /// however, this is not currently validated by this command.\n    #[arg(long, default_value = DEFAULT_CRATE_VERSION, value_name = \"VERSION\")]\n    crate_version: String,\n\n    /// The description of the Rust crate to generate.\n    ///\n    /// This will be added to the package.description field in Cargo.toml.\n    #[arg(long, default_value = \"\", value_name = \"DESCRIPTION\")]\n    crate_description: String,\n\n    /// The license of the Rust crate to generate.\n    ///\n    /// This will be added to the package.license field in Cargo.toml.\n    #[arg(long, value_name = \"LICENSE\", default_value = \"\")]\n    crate_license: String,\n\n    /// Generate the bindings as a module instead of a crate.\n    #[arg(long)]\n    module: bool,\n\n    /// Overwrite existing generated bindings.\n    ///\n    /// By default, the command will check that the bindings are correct, and then exit. If\n    /// --overwrite is passed, it will instead delete and overwrite the bindings.\n    #[arg(long)]\n    overwrite: bool,\n\n    /// Generate bindings as a single file.\n    #[arg(long)]\n    single_file: bool,\n\n    /// Skip Cargo.toml consistency checks.\n    #[arg(long)]\n    skip_cargo_toml: bool,\n\n    /// Skips running forge build before generating binding\n    #[arg(long)]\n    skip_build: bool,\n\n    /// Don't add any additional derives to generated bindings\n    #[arg(long)]\n    skip_extra_derives: bool,\n\n    /// Generate bindings for the `alloy` library, instead of `ethers`.\n    #[arg(long, hide = true)]\n    alloy: bool,\n\n    /// Specify the `alloy` version on Crates.\n    #[arg(long)]\n    alloy_version: Option<String>,\n\n    /// Specify the `alloy` revision on GitHub.\n    #[arg(long, conflicts_with = \"alloy_version\")]\n    alloy_rev: Option<String>,\n\n    /// Generate bindings for the `ethers` library (removed), instead of `alloy`.\n    #[arg(long, hide = true)]\n    ethers: bool,\n\n    #[command(flatten)]\n    build: BuildOpts,\n}\n\nimpl BindArgs {\n    pub fn run(self) -> Result<()> {\n        if self.ethers {\n            eyre::bail!(\"`--ethers` bindings have been removed. Use `--alloy` (default) instead.\");\n        }\n\n        if !self.skip_build {\n            let project = self.build.project()?;\n            let _ = ProjectCompiler::new().compile(&project)?;\n        }\n\n        let config = self.load_config()?;\n        let artifacts = config.out;\n        let bindings_root = self.bindings.clone().unwrap_or_else(|| artifacts.join(\"bindings\"));\n\n        if bindings_root.exists() {\n            if !self.overwrite {\n                sh_println!(\"Bindings found. Checking for consistency.\")?;\n                return self.check_existing_bindings(&artifacts, &bindings_root);\n            }\n\n            trace!(?artifacts, \"Removing existing bindings\");\n            fs::remove_dir_all(&bindings_root)?;\n        }\n\n        self.generate_bindings(&artifacts, &bindings_root)?;\n\n        sh_println!(\"Bindings have been generated to {}\", bindings_root.display())?;\n        Ok(())\n    }\n\n    fn get_filter(&self) -> Result<Filter> {\n        if self.select_all {\n            // Select all json files\n            return Ok(Filter::All);\n        }\n        if !self.select.is_empty() {\n            // Return json files that match the select regex\n            return Ok(Filter::Select(self.select.clone()));\n        }\n\n        if let Some(skip) = self.build.skip.as_ref().filter(|s| !s.is_empty()) {\n            return Ok(Filter::Skip(\n                skip.clone()\n                    .into_iter()\n                    .map(|s| Regex::new(s.file_pattern()))\n                    .collect::<Result<Vec<_>, _>>()?,\n            ));\n        }\n\n        // Exclude defaults\n        Ok(Filter::skip_default())\n    }\n\n    /// Returns an iterator over the JSON files and the contract name in the `artifacts` directory.\n    fn get_json_files(&self, artifacts: &Path) -> Result<impl Iterator<Item = (String, PathBuf)>> {\n        let filter = self.get_filter()?;\n        Ok(json_files(artifacts)\n            .filter_map(|path| {\n                // Ignore the build info JSON.\n                if path.to_str()?.contains(\"build-info\") {\n                    return None;\n                }\n\n                // Ignore the `target` directory in case the user has built the project.\n                if path.iter().any(|comp| comp == \"target\") {\n                    return None;\n                }\n\n                // We don't want `.metadata.json` files.\n                let stem = path.file_stem()?.to_str()?;\n                if stem.ends_with(\".metadata\") {\n                    return None;\n                }\n\n                let name = stem.split('.').next().unwrap();\n\n                // Best effort identifier cleanup.\n                let name = name.replace(char::is_whitespace, \"\").replace('-', \"_\");\n\n                Some((name, path))\n            })\n            .filter(move |(name, _path)| filter.is_match(name)))\n    }\n\n    fn get_solmacrogen(&self, artifacts: &Path) -> Result<MultiSolMacroGen> {\n        let mut dup = HashSet::<String>::default();\n        let instances = self\n            .get_json_files(artifacts)?\n            .filter_map(|(name, path)| {\n                trace!(?path, \"parsing SolMacroGen from file\");\n                if dup.insert(name.clone()) { Some(SolMacroGen::new(path, name)) } else { None }\n            })\n            .collect::<Vec<_>>();\n\n        let multi = MultiSolMacroGen::new(instances);\n        eyre::ensure!(!multi.instances.is_empty(), \"No contract artifacts found\");\n        Ok(multi)\n    }\n\n    /// Check that the existing bindings match the expected abigen output\n    fn check_existing_bindings(&self, artifacts: &Path, bindings_root: &Path) -> Result<()> {\n        let mut bindings = self.get_solmacrogen(artifacts)?;\n        bindings.generate_bindings(!self.skip_extra_derives)?;\n        sh_println!(\"Checking bindings for {} contracts\", bindings.instances.len())?;\n        bindings.check_consistency(\n            &self.crate_name,\n            &self.crate_version,\n            bindings_root,\n            self.single_file,\n            !self.skip_cargo_toml,\n            self.module,\n            self.alloy_version.clone(),\n            self.alloy_rev.clone(),\n        )?;\n        sh_println!(\"OK.\")?;\n        Ok(())\n    }\n\n    /// Generate the bindings\n    fn generate_bindings(&self, artifacts: &Path, bindings_root: &Path) -> Result<()> {\n        let mut solmacrogen = self.get_solmacrogen(artifacts)?;\n        sh_println!(\"Generating bindings for {} contracts\", solmacrogen.instances.len())?;\n\n        if !self.module {\n            trace!(single_file = self.single_file, \"generating crate\");\n            solmacrogen.write_to_crate(\n                &self.crate_name,\n                &self.crate_version,\n                &self.crate_description,\n                &self.crate_license,\n                bindings_root,\n                self.single_file,\n                self.alloy_version.clone(),\n                self.alloy_rev.clone(),\n                !self.skip_extra_derives,\n            )?;\n        } else {\n            trace!(single_file = self.single_file, \"generating module\");\n            solmacrogen.write_to_module(\n                bindings_root,\n                self.single_file,\n                !self.skip_extra_derives,\n            )?;\n        }\n\n        Ok(())\n    }\n}\n\npub enum Filter {\n    All,\n    Select(Vec<regex::Regex>),\n    Skip(Vec<regex::Regex>),\n}\n\nimpl Filter {\n    pub fn is_match(&self, name: &str) -> bool {\n        match self {\n            Self::All => true,\n            Self::Select(regexes) => regexes.iter().any(|regex| regex.is_match(name)),\n            Self::Skip(regexes) => !regexes.iter().any(|regex| regex.is_match(name)),\n        }\n    }\n\n    pub fn skip_default() -> Self {\n        let skip = [\n            \".*Test.*\",\n            \".*Script\",\n            \"console[2]?\",\n            \"CommonBase\",\n            \"Components\",\n            \"[Ss]td(Chains|Math|Error|Json|Utils|Cheats|Style|Invariant|Assertions|Toml|Storage(Safe)?)\",\n            \"[Vv]m.*\",\n            \"IMulticall3\",\n        ]\n        .iter()\n        .map(|pattern| regex::Regex::new(pattern).unwrap())\n        .collect::<Vec<_>>();\n\n        Self::Skip(skip)\n    }\n}\n"
  },
  {
    "path": "crates/forge/src/cmd/bind_json.rs",
    "content": "use super::eip712::Resolver;\nuse clap::{Parser, ValueHint};\nuse eyre::Result;\nuse foundry_cli::{\n    opts::{BuildOpts, configure_pcx_from_solc},\n    utils::LoadConfig,\n};\nuse foundry_common::{TYPE_BINDING_PREFIX, fs};\nuse foundry_compilers::{\n    CompilerInput, Graph, Project,\n    artifacts::{Source, Sources},\n    multi::{MultiCompilerLanguage, MultiCompilerParser},\n    solc::{SolcLanguage, SolcVersionedInput},\n};\nuse foundry_config::Config;\nuse itertools::Itertools;\nuse path_slash::PathExt;\nuse rayon::prelude::*;\nuse semver::Version;\nuse solar::parse::{\n    Parser as SolarParser,\n    ast::{self, Arena, FunctionKind, Span, VarMut, interface::source_map::FileName, visit::Visit},\n    interface::Session,\n};\nuse std::{\n    collections::{BTreeMap, BTreeSet, HashSet},\n    fmt::Write,\n    ops::ControlFlow,\n    path::{Path, PathBuf},\n    sync::Arc,\n};\n\nfoundry_config::impl_figment_convert!(BindJsonArgs, build);\n\nconst JSON_BINDINGS_PLACEHOLDER: &str = \"library JsonBindings {}\";\n\n/// CLI arguments for `forge bind-json`.\n#[derive(Clone, Debug, Parser)]\npub struct BindJsonArgs {\n    /// The path to write bindings to.\n    #[arg(value_hint = ValueHint::FilePath, value_name = \"PATH\")]\n    pub out: Option<PathBuf>,\n\n    #[command(flatten)]\n    build: BuildOpts,\n}\n\nimpl BindJsonArgs {\n    pub fn run(self) -> Result<()> {\n        let config = self.load_config()?;\n        let project = config.ephemeral_project()?;\n        let target_path = config.root.join(self.out.as_ref().unwrap_or(&config.bind_json.out));\n\n        // Step 1: Read and preprocess sources\n        let sources = project.paths.read_input_files()?;\n        let graph = Graph::<MultiCompilerParser>::resolve_sources(&project.paths, sources)?;\n\n        // We only generate bindings for a single Solidity version to avoid conflicts.\n        let (version, mut sources, _) = graph\n            // resolve graph into mapping language -> version -> sources\n            .into_sources_by_version(&project)?\n            .sources\n            .into_iter()\n            // we are only interested in Solidity sources\n            .find(|(lang, _)| *lang == MultiCompilerLanguage::Solc(SolcLanguage::Solidity))\n            .ok_or_else(|| eyre::eyre!(\"no Solidity sources\"))?\n            .1\n            .into_iter()\n            // For now, we are always picking the latest version.\n            .max_by(|(v1, _, _), (v2, _, _)| v1.cmp(v2))\n            .unwrap();\n\n        // Step 2: Preprocess sources to handle potentially invalid bindings\n        self.preprocess_sources(&mut sources)?;\n\n        // Insert empty bindings file.\n        sources.insert(target_path.clone(), Source::new(JSON_BINDINGS_PLACEHOLDER));\n\n        // Step 3: Find structs and generate bindings\n        let structs_to_write =\n            self.find_and_resolve_structs(&config, &project, version, sources, &target_path)?;\n\n        // Step 4: Write bindings\n        self.write_bindings(&structs_to_write, &target_path)?;\n\n        Ok(())\n    }\n\n    /// In cases when user moves/renames/deletes structs, compiler will start failing because\n    /// generated bindings will be referencing non-existing structs or importing non-existing\n    /// files.\n    ///\n    /// Because of that, we need a little bit of preprocessing to make sure that bindings will still\n    /// be valid.\n    ///\n    /// The strategy is:\n    /// 1. Replace bindings file with an empty one to get rid of potentially invalid imports.\n    /// 2. Remove all function bodies to get rid of `serialize`/`deserialize` invocations.\n    /// 3. Remove all `immutable` attributes to avoid errors because of erased constructors\n    ///    initializing them.\n    ///\n    /// After that we'll still have enough information for bindings but compilation should succeed\n    /// in most of the cases.\n    fn preprocess_sources(&self, sources: &mut Sources) -> Result<()> {\n        let sess = Session::builder().with_stderr_emitter().build();\n        let result = sess.enter(|| -> solar::interface::Result<()> {\n            sources.0.par_iter_mut().try_for_each(|(path, source)| {\n                let mut content = Arc::try_unwrap(std::mem::take(&mut source.content)).unwrap();\n\n                let arena = Arena::new();\n                let mut parser = SolarParser::from_source_code(\n                    &sess,\n                    &arena,\n                    FileName::Real(path.clone()),\n                    content.to_string(),\n                )?;\n                let ast = parser.parse_file().map_err(|e| e.emit())?;\n\n                let mut visitor = PreprocessorVisitor::new();\n                let _ = visitor.visit_source_unit(&ast);\n                visitor.update(&sess, &mut content);\n\n                source.content = Arc::new(content);\n                Ok(())\n            })\n        });\n        eyre::ensure!(result.is_ok(), \"failed parsing\");\n        Ok(())\n    }\n\n    /// Find structs, resolve conflicts, and prepare them for writing\n    fn find_and_resolve_structs(\n        &self,\n        config: &Config,\n        project: &Project,\n        version: Version,\n        sources: Sources,\n        _target_path: &Path,\n    ) -> Result<Vec<StructToWrite>> {\n        let settings = config.solc_settings()?;\n        let include = &config.bind_json.include;\n        let exclude = &config.bind_json.exclude;\n        let root = &config.root;\n\n        let input = SolcVersionedInput::build(sources, settings, SolcLanguage::Solidity, version);\n\n        let mut sess = Session::builder().with_stderr_emitter().build();\n        sess.dcx.set_flags_mut(|flags| flags.track_diagnostics = false);\n        let mut compiler = solar::sema::Compiler::new(sess);\n\n        let mut structs_to_write = Vec::new();\n\n        compiler.enter_mut(|compiler| -> Result<()> {\n            // Set up the parsing context with the project paths, without adding the source files\n            let mut pcx = compiler.parse();\n            configure_pcx_from_solc(&mut pcx, &project.paths, &input, false);\n\n            let mut target_files = HashSet::new();\n            for (path, source) in &input.input.sources {\n                if !include.is_empty() {\n                    if !include.iter().any(|matcher| matcher.is_match(path)) {\n                        continue;\n                    }\n                } else {\n                    // Exclude library files by default\n                    if project.paths.has_library_ancestor(path) {\n                        continue;\n                    }\n                }\n\n                if exclude.iter().any(|matcher| matcher.is_match(path)) {\n                    continue;\n                }\n\n                if let Ok(src_file) = compiler\n                    .sess()\n                    .source_map()\n                    .new_source_file(path.clone(), source.content.as_str())\n                {\n                    target_files.insert(Arc::clone(&src_file));\n                    pcx.add_file(src_file);\n                }\n            }\n\n            // Parse and resolve\n            pcx.parse();\n            let Ok(ControlFlow::Continue(())) = compiler.lower_asts() else { return Ok(()) };\n            let gcx = compiler.gcx();\n            let hir = &gcx.hir;\n            let resolver = Resolver::new(gcx);\n            for id in resolver.struct_ids() {\n                if let Some(schema) = resolver.resolve_struct_eip712(id) {\n                    let def = hir.strukt(id);\n                    let source = hir.source(def.source);\n\n                    if !target_files.contains(&source.file) {\n                        continue;\n                    }\n\n                    if let FileName::Real(path) = &source.file.name {\n                        structs_to_write.push(StructToWrite {\n                            name: def.name.as_str().into(),\n                            contract_name: def\n                                .contract\n                                .map(|id| hir.contract(id).name.as_str().into()),\n                            path: path.strip_prefix(root).unwrap_or(path).to_path_buf(),\n                            schema,\n                            // will be filled later\n                            import_alias: None,\n                            name_in_fns: String::new(),\n                        });\n                    }\n                }\n            }\n            Ok(())\n        })?;\n\n        eyre::ensure!(compiler.sess().dcx.has_errors().is_ok(), \"errors occurred\");\n\n        // Resolve import aliases and function names\n        self.resolve_conflicts(&mut structs_to_write);\n\n        Ok(structs_to_write)\n    }\n\n    /// We manage 2 namespaces for JSON bindings:\n    ///   - Namespace of imported items. This includes imports of contracts containing structs and\n    ///     structs defined at the file level.\n    ///   - Namespace of struct names used in function names and schema_* variables.\n    ///\n    /// Both of those might contain conflicts, so we need to resolve them.\n    fn resolve_conflicts(&self, structs_to_write: &mut [StructToWrite]) {\n        // firstly, we resolve imported names conflicts\n        // construct mapping name -> paths from which items with such name are imported\n        let mut names_to_paths = BTreeMap::new();\n\n        for s in structs_to_write.iter() {\n            names_to_paths\n                .entry(s.struct_or_contract_name())\n                .or_insert_with(BTreeSet::new)\n                .insert(s.path.as_path());\n        }\n\n        // now resolve aliases for names which need them and construct mapping (name, file) -> alias\n        let mut aliases = BTreeMap::new();\n\n        for (name, paths) in names_to_paths {\n            if paths.len() <= 1 {\n                continue; // no alias needed\n            }\n\n            for (i, path) in paths.into_iter().enumerate() {\n                aliases\n                    .entry(name.to_string())\n                    .or_insert_with(BTreeMap::new)\n                    .insert(path.to_path_buf(), format!(\"{name}_{i}\"));\n            }\n        }\n\n        for s in structs_to_write.iter_mut() {\n            let name = s.struct_or_contract_name();\n            if aliases.contains_key(name) {\n                s.import_alias = Some(aliases[name][&s.path].clone());\n            }\n        }\n\n        // Each struct needs a name by which we are referencing it in function names (e.g.\n        // deserializeFoo) Those might also have conflicts, so we manage a separate\n        // namespace for them\n        let mut name_to_structs_indexes = BTreeMap::new();\n\n        for (idx, s) in structs_to_write.iter().enumerate() {\n            name_to_structs_indexes.entry(&s.name).or_insert_with(Vec::new).push(idx);\n        }\n\n        // Keeps `Some` for structs that will be referenced by name other than their definition\n        // name.\n        let mut fn_names = vec![None; structs_to_write.len()];\n\n        for (name, indexes) in name_to_structs_indexes {\n            if indexes.len() > 1 {\n                for (i, idx) in indexes.into_iter().enumerate() {\n                    fn_names[idx] = Some(format!(\"{name}_{i}\"));\n                }\n            }\n        }\n\n        for (s, fn_name) in structs_to_write.iter_mut().zip(fn_names) {\n            s.name_in_fns = fn_name.unwrap_or(s.name.clone());\n        }\n    }\n\n    /// Write the final bindings file\n    fn write_bindings(\n        &self,\n        structs_to_write: &[StructToWrite],\n        target_path: &PathBuf,\n    ) -> Result<()> {\n        let mut result = String::new();\n\n        // Write imports\n        let mut grouped_imports = BTreeMap::new();\n        for struct_to_write in structs_to_write {\n            let item = struct_to_write.import_item();\n            grouped_imports\n                .entry(struct_to_write.path.as_path())\n                .or_insert_with(BTreeSet::new)\n                .insert(item);\n        }\n\n        result.push_str(\"// Automatically generated by forge bind-json.\\n\\npragma solidity >=0.6.2 <0.9.0;\\npragma experimental ABIEncoderV2;\\n\\n\");\n\n        for (path, names) in grouped_imports {\n            writeln!(\n                &mut result,\n                \"import {{{}}} from \\\"{}\\\";\",\n                names.iter().join(\", \"),\n                path.to_slash_lossy()\n            )?;\n        }\n\n        // Write VM interface\n        // Writes minimal VM interface to not depend on forge-std version\n        result.push_str(r#\"\ninterface Vm {\n    function parseJsonTypeArray(string calldata json, string calldata key, string calldata typeDescription) external pure returns (bytes memory);\n    function parseJsonType(string calldata json, string calldata typeDescription) external pure returns (bytes memory);\n    function parseJsonType(string calldata json, string calldata key, string calldata typeDescription) external pure returns (bytes memory);\n    function serializeJsonType(string calldata typeDescription, bytes memory value) external pure returns (string memory json);\n    function serializeJsonType(string calldata objectKey, string calldata valueKey, string calldata typeDescription, bytes memory value) external returns (string memory json);\n}\n        \"#);\n\n        // Write library\n        result.push_str(\n            r#\"\nlibrary JsonBindings {\n    Vm constant vm = Vm(address(uint160(uint256(keccak256(\"hevm cheat code\")))));\n\n\"#,\n        );\n\n        // write schema constants\n        for struct_to_write in structs_to_write {\n            writeln!(\n                &mut result,\n                \"    {}{} = \\\"{}\\\";\",\n                TYPE_BINDING_PREFIX, struct_to_write.name_in_fns, struct_to_write.schema\n            )?;\n        }\n\n        // write serialization functions\n        for struct_to_write in structs_to_write {\n            write!(\n                &mut result,\n                r#\"\n    function serialize({path} memory value) internal pure returns (string memory) {{\n        return vm.serializeJsonType(schema_{name_in_fns}, abi.encode(value));\n    }}\n\n    function serialize({path} memory value, string memory objectKey, string memory valueKey) internal returns (string memory) {{\n        return vm.serializeJsonType(objectKey, valueKey, schema_{name_in_fns}, abi.encode(value));\n    }}\n\n    function deserialize{name_in_fns}(string memory json) public pure returns ({path} memory) {{\n        return abi.decode(vm.parseJsonType(json, schema_{name_in_fns}), ({path}));\n    }}\n\n    function deserialize{name_in_fns}(string memory json, string memory path) public pure returns ({path} memory) {{\n        return abi.decode(vm.parseJsonType(json, path, schema_{name_in_fns}), ({path}));\n    }}\n\n    function deserialize{name_in_fns}Array(string memory json, string memory path) public pure returns ({path}[] memory) {{\n        return abi.decode(vm.parseJsonTypeArray(json, path, schema_{name_in_fns}), ({path}[]));\n    }}\n\"#,\n                name_in_fns = struct_to_write.name_in_fns,\n                path = struct_to_write.full_path()\n            )?;\n        }\n\n        result.push_str(\"}\\n\");\n\n        // Write to file\n        if let Some(parent) = target_path.parent() {\n            fs::create_dir_all(parent)?;\n        }\n        fs::write(target_path, &result)?;\n\n        sh_println!(\"Bindings written to {}\", target_path.display())?;\n\n        Ok(())\n    }\n}\n\nstruct PreprocessorVisitor {\n    updates: Vec<(Span, &'static str)>,\n}\n\nimpl PreprocessorVisitor {\n    fn new() -> Self {\n        Self { updates: Vec::new() }\n    }\n\n    fn update(mut self, sess: &Session, content: &mut String) {\n        if self.updates.is_empty() {\n            return;\n        }\n\n        let sf = sess.source_map().lookup_source_file(self.updates[0].0.lo());\n        let base = sf.start_pos.0;\n\n        self.updates.sort_by_key(|(span, _)| span.lo());\n        let mut shift = 0_i64;\n        for (span, new) in self.updates {\n            let lo = span.lo() - base;\n            let hi = span.hi() - base;\n            let start = ((lo.0 as i64) - shift) as usize;\n            let end = ((hi.0 as i64) - shift) as usize;\n\n            content.replace_range(start..end, new);\n            shift += (end - start) as i64;\n            shift -= new.len() as i64;\n        }\n    }\n}\n\nimpl<'ast> Visit<'ast> for PreprocessorVisitor {\n    type BreakValue = solar::interface::data_structures::Never;\n\n    fn visit_item_function(\n        &mut self,\n        func: &'ast ast::ItemFunction<'ast>,\n    ) -> ControlFlow<Self::BreakValue> {\n        // Replace function bodies with a noop statement.\n        if let Some(block) = &func.body\n            && !block.is_empty()\n        {\n            let span = block.first().unwrap().span.to(block.last().unwrap().span);\n            let new_body = match func.kind {\n                FunctionKind::Modifier => \"_;\",\n                _ => \"revert();\",\n            };\n            self.updates.push((span, new_body));\n        }\n\n        self.walk_item_function(func)\n    }\n\n    fn visit_variable_definition(\n        &mut self,\n        var: &'ast ast::VariableDefinition<'ast>,\n    ) -> ControlFlow<Self::BreakValue> {\n        // Remove `immutable` attributes.\n        if let Some(VarMut::Immutable) = var.mutability {\n            self.updates.push((var.span, \"\"));\n        }\n\n        self.walk_variable_definition(var)\n    }\n}\n\n/// A single struct definition for which we need to generate bindings.\n#[derive(Debug, Clone)]\nstruct StructToWrite {\n    /// Name of the struct definition.\n    name: String,\n    /// Name of the contract containing the struct definition. None if the struct is defined at the\n    /// file level.\n    contract_name: Option<String>,\n    /// Import alias for the contract or struct, depending on whether the struct is imported\n    /// directly, or via a contract.\n    import_alias: Option<String>,\n    /// Path to the file containing the struct definition.\n    path: PathBuf,\n    /// EIP712 schema for the struct.\n    schema: String,\n    /// Name of the struct definition used in function names and schema_* variables.\n    name_in_fns: String,\n}\n\nimpl StructToWrite {\n    /// Returns the name of the imported item. If struct is defined at the file level, returns the\n    /// struct name, otherwise returns the parent contract name.\n    fn struct_or_contract_name(&self) -> &str {\n        self.contract_name.as_deref().unwrap_or(&self.name)\n    }\n\n    /// Same as [StructToWrite::struct_or_contract_name] but with alias applied.\n    fn struct_or_contract_name_with_alias(&self) -> &str {\n        self.import_alias.as_deref().unwrap_or(self.struct_or_contract_name())\n    }\n\n    /// Path which can be used to reference this struct in input/output parameters. Either\n    /// StructName or ParentName.StructName\n    fn full_path(&self) -> String {\n        if self.contract_name.is_some() {\n            format!(\"{}.{}\", self.struct_or_contract_name_with_alias(), self.name)\n        } else {\n            self.struct_or_contract_name_with_alias().to_string()\n        }\n    }\n\n    fn import_item(&self) -> String {\n        if let Some(alias) = &self.import_alias {\n            format!(\"{} as {}\", self.struct_or_contract_name(), alias)\n        } else {\n            self.struct_or_contract_name().to_string()\n        }\n    }\n}\n"
  },
  {
    "path": "crates/forge/src/cmd/build.rs",
    "content": "use super::{install, watch::WatchArgs};\nuse clap::Parser;\nuse eyre::{Context, Result};\nuse forge_lint::{linter::Linter, sol::SolidityLinter};\nuse foundry_cli::{\n    opts::{BuildOpts, configure_pcx_from_solc, get_solar_sources_from_compile_output},\n    utils::{Git, LoadConfig, cache_local_signatures},\n};\nuse foundry_common::{compile::ProjectCompiler, shell};\nuse foundry_compilers::{\n    CompilationError, FileFilter, Project, ProjectCompileOutput,\n    compilers::{Language, multi::MultiCompilerLanguage},\n    solc::SolcLanguage,\n    utils::source_files_iter,\n};\nuse foundry_config::{\n    Config, SkipBuildFilters,\n    figment::{\n        self, Metadata, Profile, Provider,\n        error::Kind::InvalidType,\n        value::{Dict, Map, Value},\n    },\n    filter::expand_globs,\n};\nuse serde::Serialize;\nuse std::path::PathBuf;\n\nfoundry_config::merge_impl_figment_convert!(BuildArgs, build);\n\n/// CLI arguments for `forge build`.\n///\n/// CLI arguments take the highest precedence in the Config/Figment hierarchy.\n/// In order to override them in the foundry `Config` they need to be merged into an existing\n/// `figment::Provider`, like `foundry_config::Config` is.\n///\n/// `BuildArgs` implements `figment::Provider` in which all config related fields are serialized and\n/// then merged into an existing `Config`, effectively overwriting them.\n///\n/// Some arguments are marked as `#[serde(skip)]` and require manual processing in\n/// `figment::Provider` implementation\n#[derive(Clone, Debug, Default, Serialize, Parser)]\n#[command(next_help_heading = \"Build options\", about = None, long_about = None)] // override doc\npub struct BuildArgs {\n    /// Build source files from specified paths.\n    #[serde(skip)]\n    pub paths: Option<Vec<PathBuf>>,\n\n    /// Print compiled contract names.\n    #[arg(long)]\n    #[serde(skip)]\n    pub names: bool,\n\n    /// Print compiled contract sizes.\n    /// Constructor argument length is not included in the calculation of initcode size.\n    #[arg(long)]\n    #[serde(skip)]\n    pub sizes: bool,\n\n    /// Ignore initcode contract bytecode size limit introduced by EIP-3860.\n    #[arg(long, alias = \"ignore-initcode-size\")]\n    #[serde(skip)]\n    pub ignore_eip_3860: bool,\n\n    #[command(flatten)]\n    #[serde(flatten)]\n    pub build: BuildOpts,\n\n    #[command(flatten)]\n    #[serde(skip)]\n    pub watch: WatchArgs,\n}\n\nimpl BuildArgs {\n    pub async fn run(self) -> Result<ProjectCompileOutput> {\n        let mut config = self.load_config()?;\n\n        if install::install_missing_dependencies(&mut config).await && config.auto_detect_remappings\n        {\n            // need to re-configure here to also catch additional remappings\n            config = self.load_config()?;\n        }\n\n        self.check_soldeer_lock_consistency(&config).await;\n        self.check_foundry_lock_consistency(&config);\n\n        let project = config.project()?;\n\n        // Collect sources to compile if build subdirectories specified.\n        let mut files = vec![];\n        if let Some(paths) = &self.paths {\n            for path in paths {\n                let joined = project.root().join(path);\n                let path = if joined.exists() { &joined } else { path };\n                files.extend(source_files_iter(path, MultiCompilerLanguage::FILE_EXTENSIONS));\n            }\n            if files.is_empty() {\n                eyre::bail!(\"No source files found in specified build paths.\")\n            }\n        }\n\n        let format_json = shell::is_json();\n        let compiler = ProjectCompiler::new()\n            .files(files)\n            .dynamic_test_linking(config.dynamic_test_linking)\n            .print_names(self.names)\n            .print_sizes(self.sizes)\n            .ignore_eip_3860(self.ignore_eip_3860)\n            .bail(!format_json);\n\n        let mut output = compiler.compile(&project)?;\n\n        // Cache project selectors.\n        cache_local_signatures(&output)?;\n\n        if format_json && !self.names && !self.sizes {\n            sh_println!(\"{}\", serde_json::to_string_pretty(&output.output())?)?;\n        }\n\n        // Only run the `SolidityLinter` if lint on build and no compilation errors.\n        if config.lint.lint_on_build && !output.output().errors.iter().any(|e| e.is_error()) {\n            self.lint(&project, &config, self.paths.as_deref(), &mut output)\n                .wrap_err(\"Lint failed\")?;\n        }\n\n        Ok(output)\n    }\n\n    fn lint(\n        &self,\n        project: &Project,\n        config: &Config,\n        files: Option<&[PathBuf]>,\n        output: &mut ProjectCompileOutput,\n    ) -> Result<()> {\n        let format_json = shell::is_json();\n        if project.compiler.solc.is_some() && !shell::is_quiet() {\n            let linter = SolidityLinter::new(config.project_paths())\n                .with_json_emitter(format_json)\n                .with_description(!format_json)\n                .with_severity(if config.lint.severity.is_empty() {\n                    None\n                } else {\n                    Some(config.lint.severity.clone())\n                })\n                .without_lints(if config.lint.exclude_lints.is_empty() {\n                    None\n                } else {\n                    Some(\n                        config\n                            .lint\n                            .exclude_lints\n                            .iter()\n                            .filter_map(|s| forge_lint::sol::SolLint::try_from(s.as_str()).ok())\n                            .collect(),\n                    )\n                })\n                .with_lint_specific(&config.lint.lint_specific);\n\n            // Expand ignore globs and canonicalize from the get go\n            let ignored = expand_globs(&config.root, config.lint.ignore.iter())?\n                .iter()\n                .flat_map(foundry_common::fs::canonicalize_path)\n                .collect::<Vec<_>>();\n\n            let skip = SkipBuildFilters::new(config.skip.clone(), config.root.clone());\n            let curr_dir = std::env::current_dir()?;\n            let input_files = config\n                .project_paths::<SolcLanguage>()\n                .input_files_iter()\n                .filter(|p| {\n                    // Lint only specified build files, if any.\n                    if let Some(files) = files {\n                        return files.iter().any(|file| &curr_dir.join(file) == p);\n                    }\n                    skip.is_match(p)\n                        && !(ignored.contains(p) || ignored.contains(&curr_dir.join(p)))\n                })\n                .collect::<Vec<_>>();\n\n            let solar_sources =\n                get_solar_sources_from_compile_output(config, output, Some(&input_files), None)?;\n            if solar_sources.input.sources.is_empty() {\n                if !input_files.is_empty() {\n                    sh_warn!(\"unable to lint. Solar only supports Solidity versions >=0.8.0\")?;\n                }\n                return Ok(());\n            }\n\n            // NOTE(rusowsky): Once solar can drop unsupported versions, rather than creating a new\n            // compiler, we should reuse the parser from the project output.\n            let mut compiler = solar::sema::Compiler::new(\n                solar::interface::Session::builder().with_stderr_emitter().build(),\n            );\n\n            // Load the solar-compatible sources to the pcx before linting\n            compiler.enter_mut(|compiler| {\n                let mut pcx = compiler.parse();\n                configure_pcx_from_solc(&mut pcx, &config.project_paths(), &solar_sources, true);\n                pcx.set_resolve_imports(true);\n                pcx.parse();\n            });\n            linter.lint(&input_files, config.deny, &mut compiler)?;\n        }\n\n        Ok(())\n    }\n\n    /// Returns the `Project` for the current workspace\n    ///\n    /// This loads the `foundry_config::Config` for the current workspace (see\n    /// [`foundry_config::utils::find_project_root`] and merges the cli `BuildArgs` into it before\n    /// returning [`foundry_config::Config::project()`]\n    pub fn project(&self) -> Result<Project> {\n        self.build.project()\n    }\n\n    /// Returns whether `BuildArgs` was configured with `--watch`\n    pub fn is_watch(&self) -> bool {\n        self.watch.watch.is_some()\n    }\n\n    /// Returns the [`watchexec::Config`] necessary to bootstrap a new watch loop.\n    pub(crate) fn watchexec_config(&self) -> Result<watchexec::Config> {\n        // Use the path arguments or if none where provided the `src`, `test` and `script`\n        // directories as well as the `foundry.toml` configuration file.\n        self.watch.watchexec_config(|| {\n            let config = self.load_config()?;\n            let foundry_toml: PathBuf = config.root.join(Config::FILE_NAME);\n            Ok([config.src, config.test, config.script, foundry_toml])\n        })\n    }\n\n    /// Check soldeer.lock file consistency using soldeer_core APIs\n    async fn check_soldeer_lock_consistency(&self, config: &Config) {\n        let soldeer_lock_path = config.root.join(\"soldeer.lock\");\n        if !soldeer_lock_path.exists() {\n            return;\n        }\n\n        // Note: read_lockfile returns Ok with empty entries for malformed files\n        let Ok(lockfile) = soldeer_core::lock::read_lockfile(&soldeer_lock_path) else {\n            return;\n        };\n\n        let deps_dir = config.root.join(\"dependencies\");\n        for entry in &lockfile.entries {\n            let dep_name = entry.name();\n\n            // Use soldeer_core's integrity check\n            match soldeer_core::install::check_dependency_integrity(entry, &deps_dir).await {\n                Ok(status) => {\n                    use soldeer_core::install::DependencyStatus;\n                    // Check if status indicates a problem\n                    if matches!(\n                        status,\n                        DependencyStatus::Missing | DependencyStatus::FailedIntegrity\n                    ) {\n                        sh_warn!(\"Dependency '{}' integrity check failed: {:?}\", dep_name, status)\n                            .ok();\n                    }\n                }\n                Err(e) => {\n                    sh_warn!(\"Dependency '{}' integrity check error: {}\", dep_name, e).ok();\n                }\n            }\n        }\n    }\n\n    /// Check foundry.lock file consistency with git submodules\n    fn check_foundry_lock_consistency(&self, config: &Config) {\n        use crate::lockfile::{DepIdentifier, FOUNDRY_LOCK, Lockfile};\n\n        let foundry_lock_path = config.root.join(FOUNDRY_LOCK);\n        if !foundry_lock_path.exists() {\n            return;\n        }\n\n        let git = Git::new(&config.root);\n\n        let mut lockfile = Lockfile::new(&config.root).with_git(&git);\n        if let Err(e) = lockfile.read() {\n            if !e.to_string().contains(\"Lockfile not found\") {\n                sh_warn!(\"Failed to parse foundry.lock: {}\", e).ok();\n            }\n            return;\n        }\n\n        for (dep_path, dep_identifier) in lockfile.iter() {\n            let full_path = config.root.join(dep_path);\n\n            if !full_path.exists() {\n                sh_warn!(\"Dependency '{}' not found at expected path\", dep_path.display()).ok();\n                continue;\n            }\n\n            let actual_rev = match git.get_rev(\"HEAD\", &full_path) {\n                Ok(rev) => rev,\n                Err(_) => {\n                    sh_warn!(\"Failed to get git revision for dependency '{}'\", dep_path.display())\n                        .ok();\n                    continue;\n                }\n            };\n\n            // Compare with the expected revision from lockfile\n            let expected_rev = match dep_identifier {\n                DepIdentifier::Branch { rev, .. }\n                | DepIdentifier::Tag { rev, .. }\n                | DepIdentifier::Rev { rev, .. } => rev.clone(),\n            };\n\n            if actual_rev != expected_rev {\n                sh_warn!(\n                    \"Dependency '{}' revision mismatch: expected '{}', found '{}'\",\n                    dep_path.display(),\n                    expected_rev,\n                    actual_rev\n                )\n                .ok();\n            }\n        }\n    }\n}\n\n// Make this args a `figment::Provider` so that it can be merged into the `Config`\nimpl Provider for BuildArgs {\n    fn metadata(&self) -> Metadata {\n        Metadata::named(\"Build Args Provider\")\n    }\n\n    fn data(&self) -> Result<Map<Profile, Dict>, figment::Error> {\n        let value = Value::serialize(self)?;\n        let error = InvalidType(value.to_actual(), \"map\".into());\n        let mut dict = value.into_dict().ok_or(error)?;\n\n        if self.names {\n            dict.insert(\"names\".to_string(), true.into());\n        }\n\n        if self.sizes {\n            dict.insert(\"sizes\".to_string(), true.into());\n        }\n\n        if self.ignore_eip_3860 {\n            dict.insert(\"ignore_eip_3860\".to_string(), true.into());\n        }\n\n        Ok(Map::from([(Config::selected_profile(), dict)]))\n    }\n}\n"
  },
  {
    "path": "crates/forge/src/cmd/cache.rs",
    "content": "use cache::Cache;\nuse clap::{\n    Arg, Command, Parser, Subcommand,\n    builder::{PossibleValuesParser, TypedValueParser},\n};\nuse eyre::Result;\nuse foundry_config::{Chain, Config, NamedChain, cache};\nuse std::{ffi::OsStr, str::FromStr};\nuse strum::VariantNames;\n\n/// CLI arguments for `forge cache`.\n#[derive(Debug, Parser)]\npub struct CacheArgs {\n    #[command(subcommand)]\n    pub sub: CacheSubcommands,\n}\n\n#[derive(Debug, Subcommand)]\npub enum CacheSubcommands {\n    /// Cleans cached data from the global foundry directory.\n    Clean(CleanArgs),\n\n    /// Shows cached data from the global foundry directory.\n    Ls(LsArgs),\n}\n\n/// CLI arguments for `forge clean`.\n#[derive(Debug, Parser)]\n#[command(group = clap::ArgGroup::new(\"etherscan-blocks\").multiple(false))]\npub struct CleanArgs {\n    /// The chains to clean the cache for.\n    ///\n    /// Can also be \"all\" to clean all chains.\n    #[arg(\n        env = \"CHAIN\",\n        default_value = \"all\",\n        value_parser = ChainOrAllValueParser::default(),\n    )]\n    chains: Vec<ChainOrAll>,\n\n    /// The blocks to clean the cache for.\n    #[arg(\n        short,\n        long,\n        num_args(1..),\n        value_delimiter(','),\n        group = \"etherscan-blocks\"\n    )]\n    blocks: Vec<u64>,\n\n    /// Whether to clean the Etherscan cache.\n    #[arg(long, group = \"etherscan-blocks\")]\n    etherscan: bool,\n}\n\nimpl CleanArgs {\n    pub fn run(self) -> Result<()> {\n        let Self { chains, blocks, etherscan } = self;\n\n        for chain_or_all in chains {\n            match chain_or_all {\n                ChainOrAll::NamedChain(chain) => {\n                    clean_chain_cache(chain, blocks.to_vec(), etherscan)?\n                }\n                ChainOrAll::All => {\n                    if etherscan {\n                        Config::clean_foundry_etherscan_cache()?;\n                    } else {\n                        Config::clean_foundry_cache()?\n                    }\n                }\n            }\n        }\n\n        Ok(())\n    }\n}\n\n#[derive(Debug, Parser)]\npub struct LsArgs {\n    /// The chains to list the cache for.\n    ///\n    /// Can also be \"all\" to list all chains.\n    #[arg(\n        env = \"CHAIN\",\n        default_value = \"all\",\n        value_parser = ChainOrAllValueParser::default(),\n    )]\n    chains: Vec<ChainOrAll>,\n}\n\nimpl LsArgs {\n    pub fn run(self) -> Result<()> {\n        let Self { chains } = self;\n        let mut cache = Cache::default();\n        for chain_or_all in chains {\n            match chain_or_all {\n                ChainOrAll::NamedChain(chain) => {\n                    cache.chains.push(Config::list_foundry_chain_cache(chain.into())?)\n                }\n                ChainOrAll::All => cache = Config::list_foundry_cache()?,\n            }\n        }\n        sh_print!(\"{cache}\")?;\n        Ok(())\n    }\n}\n\n#[derive(Clone, Debug)]\npub enum ChainOrAll {\n    NamedChain(NamedChain),\n    All,\n}\n\nimpl FromStr for ChainOrAll {\n    type Err = String;\n\n    fn from_str(s: &str) -> Result<Self, Self::Err> {\n        if let Ok(chain) = NamedChain::from_str(s) {\n            Ok(Self::NamedChain(chain))\n        } else if s == \"all\" {\n            Ok(Self::All)\n        } else {\n            Err(format!(\"Expected known chain or all, found: {s}\"))\n        }\n    }\n}\n\nfn clean_chain_cache(chain: impl Into<Chain>, blocks: Vec<u64>, etherscan: bool) -> Result<()> {\n    let chain = chain.into();\n    if blocks.is_empty() {\n        Config::clean_foundry_etherscan_chain_cache(chain)?;\n        if etherscan {\n            return Ok(());\n        }\n        Config::clean_foundry_chain_cache(chain)?;\n    } else {\n        for block in blocks {\n            Config::clean_foundry_block_cache(chain, block)?;\n        }\n    }\n    Ok(())\n}\n\n/// The value parser for `ChainOrAll`\n#[derive(Clone, Debug)]\npub struct ChainOrAllValueParser {\n    inner: PossibleValuesParser,\n}\n\nimpl Default for ChainOrAllValueParser {\n    fn default() -> Self {\n        Self { inner: possible_chains() }\n    }\n}\n\nimpl TypedValueParser for ChainOrAllValueParser {\n    type Value = ChainOrAll;\n\n    fn parse_ref(\n        &self,\n        cmd: &Command,\n        arg: Option<&Arg>,\n        value: &OsStr,\n    ) -> Result<Self::Value, clap::Error> {\n        self.inner.parse_ref(cmd, arg, value)?.parse::<ChainOrAll>().map_err(|_| {\n            clap::Error::raw(\n                clap::error::ErrorKind::InvalidValue,\n                \"chain argument did not match any possible chain variant\",\n            )\n        })\n    }\n}\n\nfn possible_chains() -> PossibleValuesParser {\n    Some(&\"all\").into_iter().chain(NamedChain::VARIANTS).into()\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn can_parse_cache_ls() {\n        let args: CacheArgs = CacheArgs::parse_from([\"cache\", \"ls\"]);\n        assert!(matches!(args.sub, CacheSubcommands::Ls(_)));\n    }\n}\n"
  },
  {
    "path": "crates/forge/src/cmd/clone.rs",
    "content": "use super::{init::InitArgs, install::DependencyInstallOpts};\nuse alloy_primitives::{Address, Bytes, ChainId, TxHash};\nuse clap::{Parser, ValueEnum, ValueHint};\nuse eyre::Result;\nuse forge_verify::sourcify::SOURCIFY_URL;\nuse foundry_block_explorers::{\n    Client,\n    contract::{\n        ContractCreationData, ContractMetadata, Metadata, SourceCodeEntry, SourceCodeMetadata,\n    },\n    errors::EtherscanError,\n};\nuse foundry_cli::{\n    opts::EtherscanOpts,\n    utils::{Git, LoadConfig},\n};\nuse foundry_common::{compile::ProjectCompiler, fs};\nuse foundry_compilers::{\n    ProjectCompileOutput, ProjectPathsConfig,\n    artifacts::{\n        ConfigurableContractArtifact, Settings, StorageLayout,\n        output_selection::ContractOutputSelection,\n        remappings::{RelativeRemapping, Remapping},\n    },\n    compilers::solc::Solc,\n};\nuse foundry_config::{Chain, Config};\nuse reqwest::StatusCode;\nuse serde::Deserialize;\nuse std::{\n    collections::{BTreeMap, HashMap},\n    fs::read_dir,\n    path::{Path, PathBuf},\n    time::Duration,\n};\nuse tracing::trace;\nuse url::Url;\n\n/// CloneMetadata stores the metadata that are not included by `foundry.toml` but necessary for a\n/// cloned contract. The metadata can be serialized to a metadata file in the cloned project root.\n#[derive(Debug, Clone, serde::Serialize)]\n#[serde(rename_all = \"camelCase\")]\npub struct CloneMetadata {\n    /// The path to the source file that contains the contract declaration.\n    /// The path is relative to the root directory of the project.\n    pub path: PathBuf,\n    /// The name of the contract in the file.\n    pub target_contract: String,\n    /// The address of the contract on the blockchain.\n    pub address: Address,\n    /// The chain id.\n    pub chain_id: ChainId,\n    /// The transaction hash of the creation transaction.\n    pub creation_transaction: TxHash,\n    /// The address of the deployer, i.e., sender of the creation transaction.\n    pub deployer: Address,\n    /// The constructor arguments of the contract on chain.\n    pub constructor_arguments: Bytes,\n    /// The storage layout of the contract on chain.\n    pub storage_layout: StorageLayout,\n}\n\n/// Source explorer type for `forge clone`.\n#[derive(Clone, Copy, Debug, ValueEnum, Default)]\npub enum SourceExplorer {\n    /// Use Etherscan API (default).\n    #[default]\n    Etherscan,\n    /// Use Sourcify API.\n    Sourcify,\n}\n\n/// CLI arguments for `forge clone`.\n///\n/// `forge clone` clones an on-chain contract from block explorers (e.g., Etherscan, Sourcify) in\n/// the following steps:\n/// 1. Fetch the contract source code from the block explorer.\n/// 2. Initialize a empty foundry project at the `root` directory specified in `CloneArgs`.\n/// 3. Dump the contract sources to the source directory.\n/// 4. Update the `foundry.toml` configuration file with the compiler settings from the block\n///    explorer.\n/// 5. Try compile the cloned contract, so that we can get the original storage layout. This\n///    original storage layout is preserved in the `CloneMetadata` so that if the user later\n///    modifies the contract, it is possible to quickly check the storage layout compatibility with\n///    the original on-chain contract.\n/// 6. Dump the `CloneMetadata` to the root directory of the cloned project as `.clone.meta` file.\n#[derive(Clone, Debug, Parser)]\npub struct CloneArgs {\n    /// The contract address to clone.\n    pub address: Address,\n\n    /// The root directory of the cloned project.\n    #[arg(value_hint = ValueHint::DirPath, default_value = \".\", value_name = \"PATH\")]\n    pub root: PathBuf,\n\n    /// Do not generate the remappings.txt file. Instead, keep the remappings in the configuration.\n    #[arg(long)]\n    pub no_remappings_txt: bool,\n\n    /// Keep the original directory structure collected from the block explorer.\n    ///\n    /// If this flag is set, the directory structure of the cloned project will be kept as is.\n    /// By default, the directory structure is re-orgnized to increase the readability, but may\n    /// risk some compilation failures.\n    #[arg(long)]\n    pub keep_directory_structure: bool,\n\n    /// Source explorer to use for fetching contract data.\n    ///\n    /// Can be either \"etherscan\" (default) or \"sourcify\".\n    #[arg(long, default_value = \"etherscan\", value_name = \"EXPLORER\")]\n    pub source: SourceExplorer,\n\n    /// Custom Sourcify API URL.\n    ///\n    /// Implies `--source sourcify`.\n    #[arg(long, value_name = \"URL\")]\n    pub sourcify_url: Option<String>,\n\n    #[command(flatten)]\n    pub etherscan: EtherscanOpts,\n\n    #[command(flatten)]\n    pub install: DependencyInstallOpts,\n}\n\nimpl CloneArgs {\n    pub async fn run(self) -> Result<()> {\n        let Self {\n            address,\n            root,\n            install,\n            etherscan,\n            no_remappings_txt,\n            keep_directory_structure,\n            source,\n            sourcify_url,\n        } = self;\n\n        // step 0. get the chain and api key from the config\n        let config = etherscan.load_config()?;\n        let chain = config.chain.unwrap_or_default();\n\n        // If sourcify_url is specified, use Sourcify as the source\n        let source = if sourcify_url.is_some() { SourceExplorer::Sourcify } else { source };\n\n        // step 1. get the metadata from client based on source type\n        let (meta, explorer_name, sourcify_client) = match source {\n            SourceExplorer::Etherscan => {\n                let etherscan_api_key =\n                    config.get_etherscan_api_key(Some(chain)).unwrap_or_default();\n                let client = Client::new(chain, etherscan_api_key.clone())?;\n                sh_println!(\"Downloading the source code of {address} from Etherscan...\")?;\n                let meta = Self::collect_metadata_from_client(address, &client).await?;\n                (meta, \"Etherscan\", None)\n            }\n            SourceExplorer::Sourcify => {\n                let client = SourcifyClient::with_url(chain, sourcify_url.as_deref());\n                sh_println!(\"Downloading the source code of {address} from Sourcify...\")?;\n                let meta = Self::collect_metadata_from_client(address, &client).await?;\n                (meta, \"Sourcify\", Some(client))\n            }\n        };\n\n        // step 2. initialize an empty project\n        Self::init_an_empty_project(&root, install).await?;\n        // canonicalize the root path\n        // note that at this point, the root directory must have been created\n        let root = dunce::canonicalize(&root)?;\n\n        // step 3. parse the metadata\n        Self::parse_metadata(&meta, chain, &root, no_remappings_txt, keep_directory_structure)\n            .await?;\n\n        // step 4. collect the compilation metadata\n        sh_println!(\"Collecting the creation information of {address} from {explorer_name}...\")?;\n\n        match source {\n            SourceExplorer::Etherscan => {\n                let etherscan_api_key =\n                    config.get_etherscan_api_key(Some(chain)).unwrap_or_default();\n                let client = Client::new(chain, etherscan_api_key.clone())?;\n                if etherscan_api_key.is_empty() {\n                    sh_warn!(\"Waiting for 5 seconds to avoid rate limit...\")?;\n                    tokio::time::sleep(Duration::from_secs(5)).await;\n                }\n                Self::collect_compilation_metadata(&meta, chain, address, &root, &client).await?;\n            }\n            SourceExplorer::Sourcify => {\n                // Reuse the client from step 1 to benefit from cached creation data\n                let client = sourcify_client.expect(\"Sourcify client should exist\");\n                Self::collect_compilation_metadata(&meta, chain, address, &root, &client).await?;\n            }\n        }\n\n        // step 5. git add and commit the changes if needed\n        if install.commit {\n            let git = Git::new(&root);\n            git.add(Some(\"--all\"))?;\n            let msg = format!(\"chore: forge clone {address} from {explorer_name}\");\n            git.commit(&msg)?;\n        }\n\n        Ok(())\n    }\n\n    /// Collect the metadata of the contract from the block explorer.\n    ///\n    /// * `address` - the address of the contract to be cloned.\n    /// * `client` - the client of the block explorer.\n    pub(crate) async fn collect_metadata_from_client<C: ExplorerClient>(\n        address: Address,\n        client: &C,\n    ) -> Result<Metadata> {\n        let mut meta = client.contract_source_code(address).await?;\n        eyre::ensure!(meta.items.len() == 1, \"contract not found or ill-formed\");\n        let meta = meta.items.remove(0);\n        eyre::ensure!(!meta.is_vyper(), \"Vyper contracts are not supported\");\n        Ok(meta)\n    }\n\n    /// Initialize an empty project at the root directory.\n    ///\n    /// * `root` - the root directory of the project.\n    /// * `enable_git` - whether to enable git for the project.\n    /// * `quiet` - whether to print messages.\n    pub(crate) async fn init_an_empty_project(\n        root: &Path,\n        install: DependencyInstallOpts,\n    ) -> Result<()> {\n        // Initialize the project with empty set to true to avoid creating example contracts\n        let init_args =\n            InitArgs { root: root.to_path_buf(), install, empty: true, ..Default::default() };\n        init_args.run().await.map_err(|e| eyre::eyre!(\"Project init error: {:?}\", e))?;\n\n        Ok(())\n    }\n\n    /// Collect the compilation metadata of the cloned contract.\n    /// This function compiles the cloned contract and collects the compilation metadata.\n    ///\n    /// * `meta` - the metadata of the contract (from block explorer).\n    /// * `chain` - the chain where the contract to be cloned locates.\n    /// * `address` - the address of the contract to be cloned.\n    /// * `root` - the root directory of the cloned project.\n    /// * `client` - the client of the block explorer.\n    pub(crate) async fn collect_compilation_metadata<C: ExplorerClient>(\n        meta: &Metadata,\n        chain: Chain,\n        address: Address,\n        root: &PathBuf,\n        client: &C,\n    ) -> Result<()> {\n        // compile the cloned contract\n        let compile_output = compile_project(root)?;\n        let (main_file, main_artifact) = find_main_contract(&compile_output, &meta.contract_name)?;\n        let main_file = main_file.strip_prefix(root)?.to_path_buf();\n        let storage_layout =\n            main_artifact.storage_layout.to_owned().expect(\"storage layout not found\");\n\n        // dump the metadata to the root directory\n        let creation_tx = client.contract_creation_data(address).await?;\n        let clone_meta = CloneMetadata {\n            path: main_file,\n            target_contract: meta.contract_name.clone(),\n            address,\n            chain_id: chain.id(),\n            creation_transaction: creation_tx.transaction_hash,\n            deployer: creation_tx.contract_creator,\n            constructor_arguments: meta.constructor_arguments.clone(),\n            storage_layout,\n        };\n        let metadata_content = serde_json::to_string(&clone_meta)?;\n        let metadata_file = root.join(\".clone.meta\");\n        fs::write(&metadata_file, metadata_content)?;\n        let mut perms = std::fs::metadata(&metadata_file)?.permissions();\n        perms.set_readonly(true);\n        std::fs::set_permissions(&metadata_file, perms)?;\n\n        Ok(())\n    }\n\n    /// Download and parse the source code from Etherscan.\n    ///\n    /// * `chain` - the chain where the contract to be cloned locates.\n    /// * `address` - the address of the contract to be cloned.\n    /// * `root` - the root directory to clone the contract into as a foundry project.\n    /// * `client` - the client of the block explorer.\n    /// * `no_remappings_txt` - whether to generate the remappings.txt file.\n    pub(crate) async fn parse_metadata(\n        meta: &Metadata,\n        chain: Chain,\n        root: &PathBuf,\n        no_remappings_txt: bool,\n        keep_directory_structure: bool,\n    ) -> Result<()> {\n        // dump sources and update the remapping in configuration\n        let remappings = dump_sources(meta, root, keep_directory_structure)?;\n        Config::update_at(root, |config, doc| {\n            let profile = config.profile.as_str().as_str();\n\n            // update the remappings in the configuration\n            let mut remapping_array = toml_edit::Array::new();\n            for r in remappings {\n                remapping_array.push(r.to_string());\n            }\n            doc[Config::PROFILE_SECTION][profile][\"remappings\"] = toml_edit::value(remapping_array);\n\n            // make sure auto_detect_remappings is false (it is very important because cloned\n            // project may not follow the common remappings)\n            doc[Config::PROFILE_SECTION][profile][\"auto_detect_remappings\"] =\n                toml_edit::value(false);\n            true\n        })?;\n\n        // update configuration\n        Config::update_at(root, |config, doc| {\n            update_config_by_metadata(config, doc, meta, chain).is_ok()\n        })?;\n\n        // write remappings to remappings.txt if necessary\n        if !no_remappings_txt {\n            let remappings_txt = root.join(\"remappings.txt\");\n            eyre::ensure!(\n                !remappings_txt.exists(),\n                \"remappings.txt already exists, please remove it first\"\n            );\n\n            Config::update_at(root, |config, doc| {\n                let remappings_txt_content =\n                    config.remappings.iter().map(|r| r.to_string()).collect::<Vec<_>>().join(\"\\n\");\n                if fs::write(&remappings_txt, remappings_txt_content).is_err() {\n                    return false;\n                }\n\n                let profile = config.profile.as_str().as_str();\n                if let Some(elem) = doc[Config::PROFILE_SECTION][profile].as_table_mut() {\n                    elem.remove_entry(\"remappings\");\n                    true\n                } else {\n                    false\n                }\n            })?;\n        }\n\n        Ok(())\n    }\n}\n\n/// Update the configuration file with the metadata.\n/// This function will update the configuration file with the metadata from the contract.\n/// It will update the following fields:\n/// - `auto_detect_solc` to `false`\n/// - `solc_version` to the value from the metadata\n/// - `evm_version` to the value from the metadata, if the metadata's evm_version is \"Default\", then\n///   this is derived from the solc version this contract was compiled with.\n/// - `via_ir` to the value from the metadata\n/// - `libraries` to the value from the metadata\n/// - `metadata` to the value from the metadata\n///     - `cbor_metadata`, `use_literal_content`, and `bytecode_hash`\n/// - `optimizer` to the value from the metadata\n/// - `optimizer_runs` to the value from the metadata\n/// - `optimizer_details` to the value from the metadata\n///     - `yul_details`, `yul`, etc.\n///     - `simpleCounterForLoopUncheckedIncrement` is ignored for now\n/// - `remappings` and `stop_after` are pre-validated to be empty and None, respectively\n/// - `model_checker`, `debug`, and `output_selection` are ignored for now\n///\n/// Detailed information can be found from the following link:\n/// - <https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options>\n/// - <https://docs.soliditylang.org/en/latest/using-the-compiler.html#compiler-input-and-output-json-description>\nfn update_config_by_metadata(\n    config: &Config,\n    doc: &mut toml_edit::DocumentMut,\n    meta: &Metadata,\n    chain: Chain,\n) -> Result<()> {\n    let profile = config.profile.as_str().as_str();\n\n    // macro to update the config if the value exists\n    macro_rules! update_if_needed {\n        ([$($key:expr),+], $value:expr) => {\n            {\n                if let Some(value) = $value {\n                    let mut current = &mut doc[Config::PROFILE_SECTION][profile];\n                    $(\n                        if let Some(nested_doc) = current.get_mut(&$key) {\n                            current = nested_doc;\n                        } else {\n                            return Err(eyre::eyre!(\"cannot find the key: {}\", $key));\n                        }\n                    )+\n                    *current = toml_edit::value(value);\n                }\n            }\n        };\n    }\n\n    // update the chain id\n    doc[Config::PROFILE_SECTION][profile][\"chain_id\"] = toml_edit::value(chain.id() as i64);\n\n    // disable auto detect solc and set the solc version\n    doc[Config::PROFILE_SECTION][profile][\"auto_detect_solc\"] = toml_edit::value(false);\n    let version = meta.compiler_version()?;\n    doc[Config::PROFILE_SECTION][profile][\"solc_version\"] =\n        toml_edit::value(format!(\"{}.{}.{}\", version.major, version.minor, version.patch));\n\n    // get optimizer settings\n    // we ignore `model_checker`, `debug`, and `output_selection` for now,\n    // it seems they do not have impacts on the actual compilation\n    let Settings { optimizer, libraries, evm_version, via_ir, stop_after, metadata, .. } =\n        meta.settings()?;\n    eyre::ensure!(stop_after.is_none(), \"stop_after should be None\");\n\n    update_if_needed!([\"evm_version\"], evm_version.map(|v| v.to_string()));\n    update_if_needed!([\"via_ir\"], via_ir);\n\n    // update metadata if needed\n    if let Some(metadata) = metadata {\n        update_if_needed!([\"cbor_metadata\"], metadata.cbor_metadata);\n        update_if_needed!([\"use_literal_content\"], metadata.use_literal_content);\n        update_if_needed!([\"bytecode_hash\"], metadata.bytecode_hash.map(|v| v.to_string()));\n    }\n\n    // update optimizer settings if needed\n    update_if_needed!([\"optimizer\"], optimizer.enabled);\n    update_if_needed!([\"optimizer_runs\"], optimizer.runs.map(|v| v as i64));\n    // update optimizer details if needed\n    if let Some(detail) = optimizer.details {\n        doc[Config::PROFILE_SECTION][profile][\"optimizer_details\"] = toml_edit::table();\n\n        update_if_needed!([\"optimizer_details\", \"peephole\"], detail.peephole);\n        update_if_needed!([\"optimizer_details\", \"inliner\"], detail.inliner);\n        update_if_needed!([\"optimizer_details\", \"jumpdestRemover\"], detail.jumpdest_remover);\n        update_if_needed!([\"optimizer_details\", \"orderLiterals\"], detail.order_literals);\n        update_if_needed!([\"optimizer_details\", \"deduplicate\"], detail.deduplicate);\n        update_if_needed!([\"optimizer_details\", \"cse\"], detail.cse);\n        update_if_needed!([\"optimizer_details\", \"constantOptimizer\"], detail.constant_optimizer);\n        update_if_needed!(\n            [\"optimizer_details\", \"simpleCounterForLoopUncheckedIncrement\"],\n            detail.simple_counter_for_loop_unchecked_increment\n        );\n        update_if_needed!([\"optimizer_details\", \"yul\"], detail.yul);\n\n        if let Some(yul_detail) = detail.yul_details {\n            doc[Config::PROFILE_SECTION][profile][\"optimizer_details\"][\"yulDetails\"] =\n                toml_edit::table();\n            update_if_needed!(\n                [\"optimizer_details\", \"yulDetails\", \"stackAllocation\"],\n                yul_detail.stack_allocation\n            );\n            update_if_needed!(\n                [\"optimizer_details\", \"yulDetails\", \"optimizerSteps\"],\n                yul_detail.optimizer_steps\n            );\n        }\n    }\n\n    // apply remapping on libraries\n    let path_config: ProjectPathsConfig = config.project_paths();\n    let libraries = libraries\n        .apply(|libs| path_config.apply_lib_remappings(libs))\n        .with_stripped_file_prefixes(&path_config.root);\n\n    // update libraries\n    let mut lib_array = toml_edit::Array::new();\n    for (path_to_lib, info) in libraries.libs {\n        for (lib_name, address) in info {\n            lib_array.push(format!(\"{}:{}:{}\", path_to_lib.to_str().unwrap(), lib_name, address));\n        }\n    }\n    doc[Config::PROFILE_SECTION][profile][\"libraries\"] = toml_edit::value(lib_array);\n\n    Ok(())\n}\n\n/// Dump the contract sources to the root directory.\n/// The sources are dumped to the `src` directory.\n/// IO errors may be returned.\n/// A list of remappings is returned\nfn dump_sources(meta: &Metadata, root: &PathBuf, no_reorg: bool) -> Result<Vec<RelativeRemapping>> {\n    // get config\n    let path_config = ProjectPathsConfig::builder().build_with_root::<Solc>(root);\n    // we will canonicalize the sources directory later\n    let src_dir = &path_config.sources;\n    let lib_dir = &path_config.libraries[0];\n    // Optional dir, if found in src\n    let node_modules_dir = &root.join(\"node_modules\");\n    let contract_name = &meta.contract_name;\n    let source_tree = meta.source_tree();\n\n    // then we move the sources to the correct directories\n    // we will first load existing remappings if necessary\n    //  make sure this happens before dumping sources\n    let mut remappings: Vec<Remapping> = Remapping::find_many(root);\n\n    // first we dump the sources to a temporary directory\n    let tmp_dump_dir = root.join(\"raw_sources\");\n    source_tree\n        .write_to(&tmp_dump_dir)\n        .map_err(|e| eyre::eyre!(\"failed to dump sources: {}\", e))?;\n\n    // check whether we need to re-organize directories in the original sources, since we do not\n    // want to put all the sources in the `src` directory if the original directory structure is\n    // well organized, e.g., a standard foundry project containing `src` and `lib`\n    //\n    // * if the user wants to keep the original directory structure, we should not re-organize.\n    // * if there is any other directory other than `src`, `contracts`, `lib`, `hardhat`,\n    //   `forge-std`,\n    // or not started with `@`, we should not re-organize.\n    let to_reorg = !no_reorg\n        && std::fs::read_dir(tmp_dump_dir.join(contract_name))?.all(|e| {\n            let Ok(e) = e else { return false };\n            let folder_name = e.file_name();\n            folder_name == \"src\"\n                || folder_name == \"lib\"\n                || folder_name == \"node_modules\"\n                || folder_name == \"contracts\"\n                || folder_name == \"hardhat\"\n                || folder_name == \"forge-std\"\n                || folder_name.to_string_lossy().starts_with('@')\n        });\n\n    // ensure `src` and `lib` directories exist\n    eyre::ensure!(Path::exists(&root.join(src_dir)), \"`src` directory must exists\");\n    eyre::ensure!(Path::exists(&root.join(lib_dir)), \"`lib` directory must exists\");\n\n    // move source files\n    for entry in std::fs::read_dir(tmp_dump_dir.join(contract_name))? {\n        let entry = entry?;\n        let folder_name = entry.file_name();\n        // special handling when we need to re-organize the directories: we flatten them.\n        if to_reorg {\n            if folder_name == \"contracts\"\n                || folder_name == \"src\"\n                || folder_name == \"lib\"\n                || folder_name == \"node_modules\"\n            {\n                // move all sub folders in contracts to src or lib\n                let new_dir = if folder_name == \"lib\" {\n                    lib_dir\n                } else if folder_name == \"node_modules\" {\n                    // Create node_modules dir if it exists in raw sources.\n                    std::fs::create_dir(node_modules_dir)?;\n                    node_modules_dir\n                } else {\n                    src_dir\n                };\n                for e in read_dir(entry.path())? {\n                    let e = e?;\n                    let dest = new_dir.join(e.file_name());\n                    eyre::ensure!(!Path::exists(&dest), \"destination already exists: {:?}\", dest);\n                    std::fs::rename(e.path(), &dest)?;\n                    remappings.push(Remapping {\n                        context: None,\n                        name: format!(\n                            \"{}/{}\",\n                            folder_name.to_string_lossy(),\n                            e.file_name().to_string_lossy()\n                        ),\n                        path: dest.to_string_lossy().to_string(),\n                    });\n                }\n            } else {\n                assert!(\n                    folder_name == \"hardhat\"\n                        || folder_name == \"forge-std\"\n                        || folder_name.to_string_lossy().starts_with('@')\n                );\n                // move these other folders to lib\n                let dest = lib_dir.join(&folder_name);\n                if folder_name == \"forge-std\" {\n                    // let's use the provided forge-std directory\n                    std::fs::remove_dir_all(&dest)?;\n                }\n                eyre::ensure!(!Path::exists(&dest), \"destination already exists: {:?}\", dest);\n                std::fs::rename(entry.path(), &dest)?;\n                remappings.push(Remapping {\n                    context: None,\n                    name: folder_name.to_string_lossy().to_string(),\n                    path: dest.to_string_lossy().to_string(),\n                });\n            }\n        } else {\n            // directly move the all folders into src\n            let dest = src_dir.join(&folder_name);\n            eyre::ensure!(!Path::exists(&dest), \"destination already exists: {:?}\", dest);\n            std::fs::rename(entry.path(), &dest)?;\n            if folder_name != \"src\" {\n                remappings.push(Remapping {\n                    context: None,\n                    name: folder_name.to_string_lossy().to_string(),\n                    path: dest.to_string_lossy().to_string(),\n                });\n            }\n        }\n    }\n\n    // remove the temporary directory\n    std::fs::remove_dir_all(tmp_dump_dir)?;\n\n    // add remappings in the metadata\n    for mut r in meta.settings()?.remappings {\n        if to_reorg {\n            // we should update its remapped path in the same way as we dump sources\n            // i.e., remove prefix `contracts` (if any) and add prefix `src`\n            let new_path = if r.path.starts_with(\"contracts\") {\n                PathBuf::from(\"src\").join(PathBuf::from(&r.path).strip_prefix(\"contracts\")?)\n            } else if r.path.starts_with('@')\n                || r.path.starts_with(\"hardhat/\")\n                || r.path.starts_with(\"forge-std/\")\n            {\n                PathBuf::from(\"lib\").join(PathBuf::from(&r.path))\n            } else {\n                PathBuf::from(&r.path)\n            };\n            r.path = new_path.to_string_lossy().to_string();\n        }\n        remappings.push(r);\n    }\n\n    Ok(remappings.into_iter().map(|r| r.into_relative(root)).collect())\n}\n\n/// Compile the project in the root directory, and return the compilation result.\npub fn compile_project(root: &Path) -> Result<ProjectCompileOutput> {\n    let mut config = Config::load_with_root(root)?.sanitized();\n    config.extra_output.push(ContractOutputSelection::StorageLayout);\n    let project = config.project()?;\n    let compiler = ProjectCompiler::new();\n    compiler.compile(&project)\n}\n\n/// Find the artifact of the contract with the specified name.\n/// This function returns the path to the source file and the artifact.\npub fn find_main_contract<'a>(\n    compile_output: &'a ProjectCompileOutput,\n    contract: &str,\n) -> Result<(PathBuf, &'a ConfigurableContractArtifact)> {\n    let mut rv = None;\n    for (f, c, a) in compile_output.artifacts_with_files() {\n        if contract == c {\n            // it is possible that we have multiple contracts with the same name\n            // in different files\n            // instead of throwing an error, we should handle this case in the future\n            if rv.is_some() {\n                return Err(eyre::eyre!(\"multiple contracts with the same name found\"));\n            }\n            rv = Some((PathBuf::from(f), a));\n        }\n    }\n    rv.ok_or_else(|| eyre::eyre!(\"contract not found\"))\n}\n\n/// ExplorerClient is a trait that defines the methods to interact with block explorers.\n/// It is defined as a wrapper of the `foundry_block_explorers::Client` to allow mocking.\n#[cfg_attr(test, mockall::automock)]\npub(crate) trait ExplorerClient {\n    async fn contract_source_code(\n        &self,\n        address: Address,\n    ) -> std::result::Result<ContractMetadata, EtherscanError>;\n    async fn contract_creation_data(\n        &self,\n        address: Address,\n    ) -> std::result::Result<ContractCreationData, EtherscanError>;\n}\n\nimpl ExplorerClient for Client {\n    async fn contract_source_code(\n        &self,\n        address: Address,\n    ) -> std::result::Result<ContractMetadata, EtherscanError> {\n        self.contract_source_code(address).await\n    }\n\n    async fn contract_creation_data(\n        &self,\n        address: Address,\n    ) -> std::result::Result<ContractCreationData, EtherscanError> {\n        self.contract_creation_data(address).await\n    }\n}\n\n/// SourcifyClient is a client for interacting with Sourcify API.\npub(crate) struct SourcifyClient {\n    client: reqwest::Client,\n    chain: Chain,\n    base_url: String,\n    /// Whether the base_url already contains the full path (v2/contract/chain)\n    is_full_path: bool,\n    /// Cached creation data from the first API call\n    cached_creation_data: std::sync::Arc<std::sync::Mutex<Option<ContractCreationData>>>,\n}\n\nimpl SourcifyClient {\n    pub fn with_url(chain: Chain, verifier_url: Option<&str>) -> Self {\n        let (base_url, is_full_path) = match verifier_url {\n            Some(url) => (\n                Url::parse(url).unwrap_or_else(|_| Url::parse(SOURCIFY_URL).unwrap()),\n                true, // Custom URL contains full path\n            ),\n            None => (Url::parse(SOURCIFY_URL).unwrap(), false),\n        };\n        Self {\n            client: reqwest::Client::new(),\n            chain,\n            base_url: base_url.to_string().trim_end_matches('/').to_string(),\n            is_full_path,\n            cached_creation_data: std::sync::Arc::new(std::sync::Mutex::new(None)),\n        }\n    }\n\n    fn get_contract_url(&self, address: Address, fields: &str) -> String {\n        if self.is_full_path {\n            // Custom URL already contains v2/contract/chain, just append address and fields\n            format!(\"{}/{}?fields={}\", self.base_url, address, fields)\n        } else {\n            // Default URL, need to build full path\n            format!(\n                \"{}/v2/contract/{}/{}?fields={}\",\n                self.base_url,\n                self.chain.id(),\n                address,\n                fields\n            )\n        }\n    }\n}\n\n/// Sourcify API response for contract files.\n#[derive(Debug, Clone, Deserialize)]\n#[serde(untagged)]\n#[allow(dead_code, clippy::large_enum_variant)]\nenum SourcifyContractResponse {\n    Success(SourcifyContractData),\n    Error(SourcifyErrorResponse),\n}\n\n#[derive(Debug, Clone, Deserialize)]\n#[serde(rename_all = \"camelCase\")]\nstruct SourcifyContractData {\n    #[serde(default)]\n    sources: Option<BTreeMap<String, SourcifySourceFile>>,\n    #[serde(default)]\n    abi: Option<serde_json::Value>,\n    #[serde(default)]\n    compilation: Option<SourcifyCompilation>,\n    #[serde(default)]\n    #[allow(dead_code)]\n    creation_code: Option<String>,\n    #[serde(default)]\n    #[allow(dead_code)]\n    deployed_bytecode: Option<String>,\n    #[serde(default)]\n    #[allow(dead_code)]\n    runtime_bytecode: Option<String>,\n    #[serde(default)]\n    deployment: Option<SourcifyDeployment>,\n    // Additional fields that may be present in the response\n    #[serde(default)]\n    #[allow(dead_code)]\n    match_id: Option<String>,\n    #[serde(default)]\n    #[allow(dead_code)]\n    creation_match: Option<String>,\n    #[serde(default)]\n    #[allow(dead_code)]\n    runtime_match: Option<String>,\n    #[serde(default)]\n    #[allow(dead_code)]\n    verified_at: Option<String>,\n    #[serde(default)]\n    #[allow(dead_code)]\n    r#match: Option<String>,\n    #[serde(default)]\n    #[allow(dead_code)]\n    chain_id: Option<String>,\n    #[serde(default)]\n    #[allow(dead_code)]\n    address: Option<String>,\n}\n\n#[derive(Debug, Clone, Deserialize)]\n#[serde(rename_all = \"camelCase\")]\nstruct SourcifySourceFile {\n    #[serde(default)]\n    content: String,\n}\n\n#[derive(Debug, Clone, Deserialize)]\n#[serde(rename_all = \"camelCase\")]\nstruct SourcifyCompilation {\n    #[serde(default)]\n    compiler_version: String,\n    #[serde(default)]\n    name: String,\n    #[serde(default)]\n    compiler_settings: Option<serde_json::Value>,\n}\n\n#[derive(Debug, Clone, Deserialize)]\n#[serde(rename_all = \"camelCase\")]\nstruct SourcifyDeployment {\n    #[serde(default)]\n    transaction_hash: Option<String>,\n    #[serde(default)]\n    deployer: Option<String>,\n}\n\n#[derive(Debug, Clone, Deserialize)]\n#[serde(rename_all = \"camelCase\")]\nstruct SourcifyErrorResponse {\n    #[serde(default)]\n    custom_code: String,\n    #[serde(default)]\n    message: String,\n    #[serde(default)]\n    #[allow(dead_code)]\n    error_id: String,\n    // Error responses should not have sources field\n    #[serde(default)]\n    #[serde(skip_serializing_if = \"Option::is_none\")]\n    #[allow(dead_code)]\n    sources: Option<()>,\n}\n\nimpl ExplorerClient for SourcifyClient {\n    async fn contract_source_code(\n        &self,\n        address: Address,\n    ) -> std::result::Result<ContractMetadata, EtherscanError> {\n        // Request all fields including creation data to cache them\n        let url = self.get_contract_url(address, \"sources,abi,compilation,deployment\");\n        let response = self\n            .client\n            .get(&url)\n            .send()\n            .await\n            .map_err(|e| EtherscanError::Unknown(e.to_string()))?;\n\n        let status = response.status();\n        trace!(\"Sourcify API response: status={:?}, url={}\", status, url);\n\n        match status {\n            StatusCode::NOT_FOUND => return Err(EtherscanError::ContractCodeNotVerified(address)),\n            StatusCode::TOO_MANY_REQUESTS => return Err(EtherscanError::RateLimitExceeded),\n            _ => {}\n        }\n\n        // Read response body once\n        let response_text =\n            response.text().await.map_err(|e| EtherscanError::Unknown(e.to_string()))?;\n        trace!(\"Sourcify API response body: {}\", response_text);\n\n        if !status.is_success() {\n            return Err(EtherscanError::Unknown(format!(\n                \"Sourcify API error (status {status}): {response_text}\"\n            )));\n        }\n\n        // Use the untagged enum to properly handle both success and error responses\n        let response: SourcifyContractResponse =\n            serde_json::from_str(&response_text).map_err(|e| {\n                // Truncate response for error message to avoid huge output\n                let truncated = if response_text.len() > 500 {\n                    format!(\"{}... (truncated)\", &response_text[..500])\n                } else {\n                    response_text.clone()\n                };\n                EtherscanError::Unknown(format!(\n                    \"Failed to parse Sourcify response: {e}. Response: {truncated}\"\n                ))\n            })?;\n\n        let data = match response {\n            SourcifyContractResponse::Success(data) => data,\n            SourcifyContractResponse::Error(error) => {\n                let error_msg = if error.custom_code.is_empty() && error.message.is_empty() {\n                    \"Unknown Sourcify API error\".to_string()\n                } else {\n                    format!(\"Sourcify API error: {} - {}\", error.custom_code, error.message)\n                };\n                return Err(EtherscanError::Unknown(error_msg));\n            }\n        };\n\n        let sources_map = data.sources.ok_or_else(|| {\n            EtherscanError::Unknown(\"Sourcify response missing sources field\".to_string())\n        })?;\n\n        // Convert sources map to SourceCodeMetadata::Sources format\n        let sources: HashMap<String, SourceCodeEntry> = sources_map\n            .into_iter()\n            .map(|(path, source_file)| (path, SourceCodeEntry { content: source_file.content }))\n            .collect();\n\n        let source_code = SourceCodeMetadata::Sources(sources);\n\n        let contract_name = data\n            .compilation\n            .as_ref()\n            .map(|c| c.name.clone())\n            .unwrap_or_else(|| \"Contract\".to_string());\n\n        let compiler_version =\n            data.compilation.as_ref().map(|c| c.compiler_version.clone()).unwrap_or_default();\n\n        let abi = data.abi.map(|a| a.to_string()).unwrap_or_default();\n\n        // Cache creation data for later use in contract_creation_data\n        let tx_hash = data\n            .deployment\n            .as_ref()\n            .and_then(|d| d.transaction_hash.as_ref())\n            .and_then(|h| h.parse().ok())\n            .unwrap_or(TxHash::ZERO);\n        let creator = data\n            .deployment\n            .as_ref()\n            .and_then(|d| d.deployer.as_ref())\n            .and_then(|a| a.parse().ok())\n            .unwrap_or(Address::ZERO);\n        let creation_data = ContractCreationData {\n            contract_address: address,\n            contract_creator: creator,\n            transaction_hash: tx_hash,\n        };\n        if let Ok(mut cache) = self.cached_creation_data.lock() {\n            *cache = Some(creation_data);\n        }\n\n        // Extract compiler_settings from compilation if available\n        let constructor_arguments = Bytes::default();\n        let optimization_used = data\n            .compilation\n            .as_ref()\n            .and_then(|c| c.compiler_settings.as_ref())\n            .and_then(|s| s.get(\"optimizer\"))\n            .and_then(|o| o.get(\"enabled\"))\n            .and_then(|e| e.as_bool())\n            .map(|b| if b { 1 } else { 0 })\n            .unwrap_or(0);\n\n        let runs = data\n            .compilation\n            .as_ref()\n            .and_then(|c| c.compiler_settings.as_ref())\n            .and_then(|s| s.get(\"optimizer\"))\n            .and_then(|o| o.get(\"runs\"))\n            .and_then(|r| r.as_u64())\n            .unwrap_or(0);\n\n        Ok(ContractMetadata {\n            items: vec![Metadata {\n                source_code,\n                abi,\n                contract_name,\n                compiler_version,\n                optimization_used,\n                runs,\n                constructor_arguments,\n                evm_version: String::new(),\n                library: String::new(),\n                license_type: String::new(),\n                proxy: 0,\n                implementation: None,\n                swarm_source: String::new(),\n            }],\n        })\n    }\n\n    async fn contract_creation_data(\n        &self,\n        address: Address,\n    ) -> std::result::Result<ContractCreationData, EtherscanError> {\n        // Check cache first\n        if let Ok(cache) = self.cached_creation_data.lock()\n            && let Some(ref cached_data) = *cache\n            && cached_data.contract_address == address\n        {\n            return Ok(*cached_data);\n        }\n\n        // If cache is empty or address doesn't match, use fallback values\n        // This should rarely happen since we cache in contract_source_code\n        trace!(\"Creation data not in cache for address {address}, using fallback values\");\n        let creation_data = ContractCreationData {\n            contract_address: address,\n            contract_creator: Address::ZERO,\n            transaction_hash: TxHash::ZERO,\n        };\n        if let Ok(mut cache) = self.cached_creation_data.lock() {\n            *cache = Some(creation_data);\n        }\n\n        Ok(creation_data)\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use alloy_primitives::hex;\n    use foundry_compilers::CompilerContract;\n    use foundry_test_utils::rpc::next_etherscan_api_key;\n\n    #[expect(clippy::disallowed_macros)]\n    fn assert_successful_compilation(root: &PathBuf) -> ProjectCompileOutput {\n        println!(\"project_root: {root:#?}\");\n        compile_project(root).expect(\"compilation failure\")\n    }\n\n    fn assert_compilation_result(\n        compiled: ProjectCompileOutput,\n        contract_name: &str,\n        stripped_creation_code: &str,\n    ) {\n        compiled.compiled_contracts_by_compiler_version().iter().for_each(|(_, contracts)| {\n            contracts.iter().for_each(|(name, contract)| {\n                if name == contract_name {\n                    let compiled_creation_code =\n                        contract.bin_ref().expect(\"creation code not found\");\n                    assert!(\n                        hex::encode(compiled_creation_code.as_ref())\n                            .starts_with(stripped_creation_code),\n                        \"inconsistent creation code\"\n                    );\n                }\n            });\n        });\n    }\n\n    fn mock_etherscan(address: Address) -> impl super::ExplorerClient {\n        // load mock data\n        let mut mocked_data = BTreeMap::new();\n        let data_folder =\n            PathBuf::from(env!(\"CARGO_MANIFEST_DIR\")).join(\"../../testdata/etherscan\");\n        // iterate each sub folder\n        for entry in std::fs::read_dir(data_folder).expect(\"failed to read test data folder\") {\n            let entry = entry.expect(\"failed to read test data entry\");\n            let addr: Address = entry.file_name().to_string_lossy().parse().unwrap();\n            let contract_data_dir = entry.path();\n            // the metadata.json file contains the metadata of the contract\n            let metadata_file = contract_data_dir.join(\"metadata.json\");\n            let metadata: ContractMetadata =\n                serde_json::from_str(&std::fs::read_to_string(metadata_file).unwrap())\n                    .expect(\"failed to parse metadata.json\");\n            // the creation_data.json file contains the creation data of the contract\n            let creation_data_file = contract_data_dir.join(\"creation_data.json\");\n            let creation_data: ContractCreationData =\n                serde_json::from_str(&std::fs::read_to_string(creation_data_file).unwrap())\n                    .expect(\"failed to parse creation_data.json\");\n            // insert the data to the map\n            mocked_data.insert(addr, (metadata, creation_data));\n        }\n\n        let (metadata, creation_data) = mocked_data.get(&address).unwrap();\n        let metadata = metadata.clone();\n        let creation_data = *creation_data;\n        let mut mocked_client = super::MockExplorerClient::new();\n        mocked_client\n            .expect_contract_source_code()\n            .times(1)\n            .returning(move |_| Ok(metadata.clone()));\n        mocked_client\n            .expect_contract_creation_data()\n            .times(1)\n            .returning(move |_| Ok(creation_data));\n        mocked_client\n    }\n\n    /// Fetch the metadata and creation data from Etherscan and dump them to the testdata folder.\n    #[tokio::test(flavor = \"multi_thread\")]\n    #[ignore = \"this test is used to dump mock data from Etherscan\"]\n    async fn test_dump_mock_data() {\n        let address: Address = \"0x9d27527Ada2CF29fBDAB2973cfa243845a08Bd3F\".parse().unwrap();\n        let data_folder = PathBuf::from(env!(\"CARGO_MANIFEST_DIR\"))\n            .join(\"../../testdata/etherscan\")\n            .join(address.to_string());\n        // create folder if not exists\n        std::fs::create_dir_all(&data_folder).unwrap();\n        // create metadata.json and creation_data.json\n        let client = Client::new(Chain::mainnet(), next_etherscan_api_key()).unwrap();\n        let meta = client.contract_source_code(address).await.unwrap();\n        // dump json\n        let json = serde_json::to_string_pretty(&meta).unwrap();\n        // write to metadata.json\n        std::fs::write(data_folder.join(\"metadata.json\"), json).unwrap();\n        let creation_data = client.contract_creation_data(address).await.unwrap();\n        // dump json\n        let json = serde_json::to_string_pretty(&creation_data).unwrap();\n        // write to creation_data.json\n        std::fs::write(data_folder.join(\"creation_data.json\"), json).unwrap();\n    }\n\n    /// Run the clone command with the specified contract address and assert the compilation.\n    async fn one_test_case(address: Address, check_compilation_result: bool) {\n        let temp_dir = tempfile::tempdir().unwrap();\n        let mut project_root = temp_dir.path().to_path_buf();\n        let client = mock_etherscan(address);\n        let meta = CloneArgs::collect_metadata_from_client(address, &client).await.unwrap();\n        CloneArgs::init_an_empty_project(&project_root, DependencyInstallOpts::default())\n            .await\n            .unwrap();\n        project_root = dunce::canonicalize(&project_root).unwrap();\n        CloneArgs::parse_metadata(&meta, Chain::mainnet(), &project_root, false, false)\n            .await\n            .unwrap();\n        CloneArgs::collect_compilation_metadata(\n            &meta,\n            Chain::mainnet(),\n            address,\n            &project_root,\n            &client,\n        )\n        .await\n        .unwrap();\n        let rv = assert_successful_compilation(&project_root);\n        if check_compilation_result {\n            let (contract_name, stripped_creation_code) =\n                pick_creation_info(&address.to_string()).expect(\"creation code not found\");\n            assert_compilation_result(rv, contract_name, stripped_creation_code);\n        }\n    }\n\n    #[tokio::test(flavor = \"multi_thread\")]\n    async fn test_clone_single_file_contract() {\n        let address = \"0x35Fb958109b70799a8f9Bc2a8b1Ee4cC62034193\".parse().unwrap();\n        one_test_case(address, true).await\n    }\n\n    #[tokio::test(flavor = \"multi_thread\")]\n    async fn test_clone_contract_with_optimization_details() {\n        let address = \"0x8B3D32cf2bb4d0D16656f4c0b04Fa546274f1545\".parse().unwrap();\n        one_test_case(address, true).await\n    }\n\n    #[tokio::test(flavor = \"multi_thread\")]\n    async fn test_clone_contract_with_libraries() {\n        let address = \"0xDb53f47aC61FE54F456A4eb3E09832D08Dd7BEec\".parse().unwrap();\n        one_test_case(address, true).await\n    }\n\n    #[tokio::test(flavor = \"multi_thread\")]\n    async fn test_clone_contract_with_metadata() {\n        let address = \"0x71356E37e0368Bd10bFDbF41dC052fE5FA24cD05\".parse().unwrap();\n        one_test_case(address, true).await\n    }\n\n    #[tokio::test(flavor = \"multi_thread\")]\n    async fn test_clone_contract_with_relative_import() {\n        let address = \"0x3a23F943181408EAC424116Af7b7790c94Cb97a5\".parse().unwrap();\n        one_test_case(address, false).await\n    }\n\n    #[tokio::test(flavor = \"multi_thread\")]\n    async fn test_clone_contract_with_original_remappings() {\n        let address = \"0x9ab6b21cdf116f611110b048987e58894786c244\".parse().unwrap();\n        one_test_case(address, false).await\n    }\n\n    #[tokio::test(flavor = \"multi_thread\")]\n    async fn test_clone_contract_with_relative_import2() {\n        let address = \"0x044b75f554b886A065b9567891e45c79542d7357\".parse().unwrap();\n        one_test_case(address, false).await\n    }\n\n    #[tokio::test(flavor = \"multi_thread\")]\n    async fn test_clone_contract_with_nested_src() {\n        let address = \"0x9d27527Ada2CF29fBDAB2973cfa243845a08Bd3F\".parse().unwrap();\n        one_test_case(address, false).await\n    }\n\n    fn pick_creation_info(address: &str) -> Option<(&'static str, &'static str)> {\n        for (addr, contract_name, creation_code) in &CREATION_ARRAY {\n            if address == *addr {\n                return Some((contract_name, creation_code));\n            }\n        }\n\n        None\n    }\n\n    // remember to remove CBOR metadata from the creation code\n    const CREATION_ARRAY: [(&str, &str, &str); 4] = [\n        (\n            \"0x35Fb958109b70799a8f9Bc2a8b1Ee4cC62034193\",\n            \"BearXNFTStaking\",\n            \"608060405234801561001057600080fd5b50613000806100206000396000f3fe608060405234801561001057600080fd5b50600436106102265760003560e01c80638129fc1c11610130578063bca35a71116100b8578063dada55011161007c578063dada550114610458578063f2fde38b1461046b578063f83d08ba1461047e578063fbb0022714610486578063fccd7f721461048e57600080fd5b8063bca35a71146103fa578063bf9befb11461040d578063c89d5b8b14610416578063d5d423001461041e578063d976e09f1461042657600080fd5b8063b1c92f95116100ff578063b1c92f95146103c5578063b549445c146103ce578063b81f8e89146103d6578063b9ade5b7146103de578063ba0848db146103e757600080fd5b80638129fc1c146103905780638da5cb5b14610398578063aaed083b146103a9578063b10dcc93146103b257600080fd5b8063367c164e116101b35780635923489b116101825780635923489b146103245780636e2751211461034f578063706ce3e114610362578063715018a614610375578063760a2e8a1461037d57600080fd5b8063367c164e146102bd57806338ff8a85146102d05780633a17f4f0146102f1578063426233601461030457600080fd5b8063206635e7116101fa578063206635e71461026d5780632afe761a146102805780632bd30f1114610289578063305f839a146102ab57806333ddacd1146102b457600080fd5b8062944f621461022b5780630d00368b146102405780630e8feed41461025c578063120957fd14610264575b600080fd5b61023e610239366004612aa4565b6104bc565b005b61024960735481565b6040519081526020015b60405180910390f35b61023e61053a565b610249606d5481565b61023e61027b366004612b2c565b61057e565b610249606f5481565b60785461029b90610100900460ff1681565b6040519015158152602001610253565b61024960715481565b61024960765481565b61023e6102cb366004612bc2565b6105d1565b6102e36102de366004612aa4565b610829565b604051610253929190612c16565b61023e6102ff366004612aa4565b6109e1565b610317610312366004612aa4565b610a56565b6040516102539190612c2f565b606a54610337906001600160a01b031681565b6040516001600160a01b039091168152602001610253565b6102e361035d366004612aa4565b610b4c565b606b54610337906001600160a01b031681565b61023e610cf8565b61029b61038b366004612aa4565b610d2e565b61023e610dc2565b6033546001600160a01b0316610337565b61024960705481565b61023e6103c0366004612b2c565b610fc0565b610249606e5481565b61023e611236565b61023e6112bb565b61024960725481565b6102e36103f5366004612aa4565b6112ef565b61023e610408366004612aa4565b61149b565b610249606c5481565b610249611510565b606f54610249565b610439610434366004612aa4565b611594565b6040805192151583526001600160a01b03909116602083015201610253565b606954610337906001600160a01b031681565b61023e610479366004612aa4565b6115cf565b61023e611667565b61023e6116a0565b6104a161049c366004612aa4565b6116e1565b60408051938452602084019290925290820152606001610253565b6033546001600160a01b031633146104ef5760405162461bcd60e51b81526004016104e690612c42565b60405180910390fd5b606b546001600160a01b03163b6105185760405162461bcd60e51b81526004016104e690612c77565b606b80546001600160a01b0319166001600160a01b0392909216919091179055565b600061054533611594565b509050806105655760405162461bcd60e51b81526004016104e690612cae565b61056e33610d2e565b61057b5761057b33611c73565b50565b610587336116e1565b505060765560005b81518110156105cd576105bb8282815181106105ad576105ad612cda565b602002602001015133611d7b565b806105c581612d06565b91505061058f565b5050565b606a54604051636eb1769f60e11b815233600482015273871770e3e03bfaefa3597056e540a1a9c9ac7f6b602482015282916001600160a01b03169063dd62ed3e90604401602060405180830381865afa158015610633573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106579190612d21565b10156106bb5760405162461bcd60e51b815260206004820152602d60248201527f596f75206861766520746f20617070726f766520726f6f747820746f2073746160448201526c1ada5b99c818dbdb9d1c9858dd609a1b60648201526084016104e6565b606a546040516323b872dd60e01b815233600482015273871770e3e03bfaefa3597056e540a1a9c9ac7f6b6024820152604481018390526001600160a01b03909116906323b872dd906064016020604051808303816000875af1158015610726573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061074a9190612d3a565b50606a546040516326c7e79d60e21b8152600481018390526001600160a01b0390911690639b1f9e7490602401600060405180830381600087803b15801561079157600080fd5b505af11580156107a5573d6000803e3d6000fd5b5050606b546001600160a01b031691506379c650689050336107c88460056120a1565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401600060405180830381600087803b15801561080e57600080fd5b505af1158015610822573d6000803e3d6000fd5b5050505050565b600060606000805b6001600160a01b0385166000908152607460205260409020548110156108bc576001600160a01b0385166000908152607460205260409020805461089791908390811061088057610880612cda565b906000526020600020906005020160000154612129565b156108aa576108a7600183612d5c565b91505b806108b481612d06565b915050610831565b5060008167ffffffffffffffff8111156108d8576108d8612ac1565b604051908082528060200260200182016040528015610901578160200160208202803683370190505b5090506000805b6001600160a01b0387166000908152607460205260409020548110156109d5576001600160a01b0387166000908152607460205260409020805461095791908390811061088057610880612cda565b156109c3576001600160a01b038716600090815260746020526040902080548290811061098657610986612cda565b9060005260206000209060050201600001548383815181106109aa576109aa612cda565b60209081029190910101526109c0826001612154565b91505b806109cd81612d06565b915050610908565b50919590945092505050565b6033546001600160a01b03163314610a0b5760405162461bcd60e51b81526004016104e690612c42565b6069546001600160a01b03163b610a345760405162461bcd60e51b81526004016104e690612c77565b606980546001600160a01b0319166001600160a01b0392909216919091179055565b6001600160a01b0381166000908152607460205260408120546060919067ffffffffffffffff811115610a8b57610a8b612ac1565b604051908082528060200260200182016040528015610ab4578160200160208202803683370190505b50905060005b6001600160a01b038416600090815260746020526040902054811015610b45576001600160a01b0384166000908152607460205260409020805482908110610b0457610b04612cda565b906000526020600020906005020160000154828281518110610b2857610b28612cda565b602090810291909101015280610b3d81612d06565b915050610aba565b5092915050565b600060606000805b6001600160a01b038516600090815260746020526040902054811015610bdf576001600160a01b03851660009081526074602052604090208054610bba919083908110610ba357610ba3612cda565b9060005260206000209060050201600001546121b3565b15610bcd57610bca826001612154565b91505b80610bd781612d06565b915050610b54565b5060008167ffffffffffffffff811115610bfb57610bfb612ac1565b604051908082528060200260200182016040528015610c24578160200160208202803683370190505b5090506000805b6001600160a01b0387166000908152607460205260409020548110156109d5576001600160a01b03871660009081526074602052604090208054610c7a919083908110610ba357610ba3612cda565b15610ce6576001600160a01b0387166000908152607460205260409020805482908110610ca957610ca9612cda565b906000526020600020906005020160000154838381518110610ccd57610ccd612cda565b6020908102919091010152610ce3826001612154565b91505b80610cf081612d06565b915050610c2b565b6033546001600160a01b03163314610d225760405162461bcd60e51b81526004016104e690612c42565b610d2c60006121d0565b565b60006001815b6001600160a01b038416600090815260746020526040902054811015610b45576001600160a01b03841660009081526074602052604081208054610d9a919084908110610d8357610d83612cda565b906000526020600020906005020160010154612222565b9050603c8111610daa5750610db0565b60009250505b80610dba81612d06565b915050610d34565b600054610100900460ff16610ddd5760005460ff1615610de1565b303b155b610e445760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016104e6565b600054610100900460ff16158015610e66576000805461ffff19166101011790555b610e6e61223c565b606580546001600160a01b0319908116737a250d5630b4cf539739df2c5dacb4c659f2488d1790915560668054821673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2179055620151806067556312cc030060685560698054821673e22e1e620dffb03065cd77db0162249c0c91bf01179055606a8054821673d718ad25285d65ef4d79262a6cd3aea6a8e01023179055606b80549091167399cfdf48d0ba4885a73786148a2f89d86c7021701790556000606c5568056bc75e2d63100000606d556802b5e3af16b1880000606e55690257058e269742680000606f819055681b1ae4d6e2ef5000006070819055610bb8607181905591610f709190612d74565b610f7a9190612d8b565b607255607154606e54606d54610f909190612d74565b610f9a9190612d8b565b60735560006076556078805460ff19169055801561057b576000805461ff001916905550565b6000610fcb33611594565b50905080610feb5760405162461bcd60e51b81526004016104e690612cae565b607854610100900460ff161561102c5760405162461bcd60e51b8152602060048201526006602482015265131bd8dad95960d21b60448201526064016104e6565b600061103733610a56565b90508051835111156110775760405162461bcd60e51b81526020600482015260096024820152684964206572726f727360b81b60448201526064016104e6565b6000805b84518110156110fd5760005b83518110156110ea578381815181106110a2576110a2612cda565b60200260200101518683815181106110bc576110bc612cda565b602002602001015114156110d8576110d5836001612154565b92505b806110e281612d06565b915050611087565b50806110f581612d06565b91505061107b565b50835181141561123057835161112761111e82678ac7230489e800006120a1565b606f5490612154565b606f55611132612273565b600060768190555b855181101561122d5760695486516001600160a01b03909116906323b872dd90309033908a908690811061117057611170612cda565b60209081029190910101516040516001600160e01b031960e086901b1681526001600160a01b0393841660048201529290911660248301526044820152606401600060405180830381600087803b1580156111ca57600080fd5b505af11580156111de573d6000803e3d6000fd5b5050606c80549250905060006111f383612dad565b919050555061121b3387838151811061120e5761120e612cda565b602002602001015161229b565b8061122581612d06565b91505061113a565b50505b50505050565b60785460ff166112ac5760005b60755481101561057b576001607760006075848154811061126657611266612cda565b6000918252602080832091909101546001600160a01b031683528201929092526040019020805460ff1916911515919091179055806112a481612d06565b915050611243565b6078805460ff19166001179055565b60006112c633611594565b509050806112e65760405162461bcd60e51b81526004016104e690612cae565b61057b33612470565b600060606000805b6001600160a01b038516600090815260746020526040902054811015611382576001600160a01b0385166000908152607460205260409020805461135d91908390811061134657611346612cda565b906000526020600020906005020160000154612574565b156113705761136d600183612d5c565b91505b8061137a81612d06565b9150506112f7565b5060008167ffffffffffffffff81111561139e5761139e612ac1565b6040519080825280602002602001820160405280156113c7578160200160208202803683370190505b5090506000805b6001600160a01b0387166000908152607460205260409020548110156109d5576001600160a01b0387166000908152607460205260409020805461141d91908390811061134657611346612cda565b15611489576001600160a01b038716600090815260746020526040902080548290811061144c5761144c612cda565b90600052602060002090600502016000015483838151811061147057611470612cda565b6020908102919091010152611486826001612154565b91505b8061149381612d06565b9150506113ce565b6033546001600160a01b031633146114c55760405162461bcd60e51b81526004016104e690612c42565b606a546001600160a01b03163b6114ee5760405162461bcd60e51b81526004016104e690612c77565b606a80546001600160a01b0319166001600160a01b0392909216919091179055565b6000806064606f5460016115249190612dc4565b61152e9190612d8b565b611539906001612d5c565b606d546115469190612dc4565b90506000606d54826115589190612d74565b905060006001606d548361156c9190612d8b565b6115769190612d8b565b611581906001612dc4565b61158c906064612dc4565b949350505050565b6001600160a01b038116600090815260776020526040812054819060ff161515600114156115c457506001929050565b506000928392509050565b6033546001600160a01b031633146115f95760405162461bcd60e51b81526004016104e690612c42565b6001600160a01b03811661165e5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016104e6565b61057b816121d0565b73d0d725208fd36be1561050fc1dd6a651d7ea7c89331415610d2c576078805461ff001981166101009182900460ff1615909102179055565b60006116ab33611594565b509050806116cb5760405162461bcd60e51b81526004016104e690612cae565b6116d433610d2e565b61057b5761057b336125aa565b600080808080808087816116f482610829565b509050600061170283610b4c565b50905060058110611a3b57600160005b6001600160a01b038516600090815260746020526040902054811015611a0e576001600160a01b0385166000908152607460205260408120805461177891908490811061176157611761612cda565b906000526020600020906005020160040154612222565b6001600160a01b038716600090815260746020526040902080549192506117a99184908110610ba357610ba3612cda565b806117de57506001600160a01b038616600090815260746020526040902080546117de91908490811061088057610880612cda565b80156117ea5750600181105b156117f457600092505b82801561181857506001600160a01b03861660009081526074602052604090205415155b156118715761186a8561182c83600a612dc4565b6118369190612dc4565b6118648661184585600a612dc4565b61184f9190612dc4565b60765461186490670de0b6b3a7640000612798565b90612154565b995061188e565b8261188e5760765461188b90670de0b6b3a7640000612798565b99505b6001600160a01b038616600090815260746020526040902080546118bd91908490811061088057610880612cda565b15611950576001600160a01b038616600090815260746020526040812080546119089190859081106118f1576118f1612cda565b906000526020600020906005020160020154612222565b90508061192861192182680ad78ebc5ac6200000612dc4565b8c90612154565b9a5061194761194082680ad78ebc5ac6200000612dc4565b8b90612154565b995050506119fb565b6001600160a01b0386166000908152607460205260409020805461197f919084908110610ba357610ba3612cda565b156119fb576001600160a01b038616600090815260746020526040812080546119b39190859081106118f1576118f1612cda565b905060008190506119d76002606d54846119cd9190612dc4565b6119219190612d8b565b9a506119f66002606d54836119ec9190612dc4565b6119409190612d8b565b995050505b5080611a0681612d06565b915050611712565b508515611a3557606b54606654611a32916001600160a01b039081169116886127da565b94505b50611c4f565b60005b6001600160a01b038416600090815260746020526040902054811015611c28576001600160a01b03841660009081526074602052604090208054611a8d91908390811061088057610880612cda565b15611b9f576001600160a01b03841660009081526074602052604081208054611ac191908490811061176157611761612cda565b9050611ad8611ad182600a612dc4565b8a90612154565b98506000611b1560746000886001600160a01b03166001600160a01b0316815260200190815260200160002084815481106118f1576118f1612cda565b9050611b2d611ad182680ad78ebc5ac6200000612dc4565b98506000611b8160746000896001600160a01b03166001600160a01b031681526020019081526020016000208581548110611b6a57611b6a612cda565b906000526020600020906005020160030154612222565b9050611b99611ad182680ad78ebc5ac6200000612dc4565b98505050505b6001600160a01b03841660009081526074602052604090208054611bce919083908110610ba357610ba3612cda565b15611c16576001600160a01b03841660009081526074602052604081208054611c0291908490811061176157611761612cda565b9050611c12611ad182600a612dc4565b9850505b80611c2081612d06565b915050611a3e565b508415611c4f57606b54606654611c4c916001600160a01b039081169116876127da565b93505b611c6187670de0b6b3a7640000612dc4565b9b959a50929850939650505050505050565b6000611c7e826116e1565b5091505080156105cd57606b5460405163a9059cbb60e01b81526001600160a01b038481166004830152602482018490529091169063a9059cbb906044016020604051808303816000875af1158015611cdb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cff9190612d3a565b5060005b6001600160a01b038316600090815260746020526040902054811015611d76576001600160a01b0383166000908152607460205260409020805442919083908110611d5057611d50612cda565b600091825260209091206002600590920201015580611d6e81612d06565b915050611d03565b505050565b607054606f5410611db857607354606d6000828254611d9a9190612d74565b9091555050606f54611db490678ac7230489e80000612905565b606f555b6069546040516331a9108f60e11b8152600481018490526001600160a01b03838116921690636352211e90602401602060405180830381865afa158015611e03573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e279190612de3565b6001600160a01b031614611e7d5760405162461bcd60e51b815260206004820152601e60248201527f596f7520617265206e6f742061206f776e6572206f6620746865206e6674000060448201526064016104e6565b60695460405163e985e9c560e01b81523360048201523060248201526001600160a01b039091169063e985e9c590604401602060405180830381865afa158015611ecb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611eef9190612d3a565b1515600114611f575760405162461bcd60e51b815260206004820152602e60248201527f596f752073686f756c6420617070726f7665206e667420746f2074686520737460448201526d185ada5b99c818dbdb9d1c9858dd60921b60648201526084016104e6565b6069546040516323b872dd60e01b81526001600160a01b03838116600483015230602483015260448201859052909116906323b872dd90606401600060405180830381600087803b158015611fab57600080fd5b505af1158015611fbf573d6000803e3d6000fd5b505050506000611fce82611594565b50905060006040518060a001604052808581526020014281526020014281526020014281526020014281525090506120126001606c5461215490919063ffffffff16565b606c556001600160a01b03831660009081526074602090815260408083208054600181810183559185529383902085516005909502019384559184015191830191909155820151600282015560608201516003820155608082015160049091015581611230576001600160a01b0383166000908152607760205260409020805460ff1916600117905550505050565b6000826120b057506000612123565b60006120bc8385612dc4565b9050826120c98583612d8b565b146121205760405162461bcd60e51b815260206004820152602160248201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6044820152607760f81b60648201526084016104e6565b90505b92915050565b60008064e8d4a510008310158015612146575064e8d4a510058311155b156121235750600192915050565b6000806121618385612d5c565b9050838110156121205760405162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f77000000000060448201526064016104e6565b600080610e7483116121c757506001612123565b50600092915050565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6067546000906122328342612d74565b6121239190612d8b565b600054610100900460ff166122635760405162461bcd60e51b81526004016104e690612e00565b61226b612947565b610d2c61296e565b61227c33612470565b61228533610d2e565b610d2c5761229233611c73565b610d2c336125aa565b60005b6001600160a01b038316600090815260746020526040902054811015612428576001600160a01b03831660009081526074602052604090208054839190839081106122eb576122eb612cda565b9060005260206000209060050201600001541415612416576001600160a01b0383166000908152607460205260409020805461232990600190612d74565b8154811061233957612339612cda565b906000526020600020906005020160746000856001600160a01b03166001600160a01b03168152602001908152602001600020828154811061237d5761237d612cda565b60009182526020808320845460059093020191825560018085015490830155600280850154908301556003808501549083015560049384015493909101929092556001600160a01b03851681526074909152604090208054806123e2576123e2612e4b565b6000828152602081206005600019909301928302018181556001810182905560028101829055600381018290556004015590555b8061242081612d06565b91505061229e565b506001600160a01b0382166000908152607460205260409020546105cd576001600160a01b038216600090815260746020526040812061246791612a3f565b6105cd8261299e565b600061247b826116e1565b509091505080156105cd57606a5460405163a9059cbb60e01b81526001600160a01b038481166004830152602482018490529091169063a9059cbb906044016020604051808303816000875af11580156124d9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124fd9190612d3a565b5060005b6001600160a01b038316600090815260746020526040902054811015611d76576001600160a01b038316600090815260746020526040902080544291908390811061254e5761254e612cda565b60009182526020909120600460059092020101558061256c81612d06565b915050612501565b60006509184e72a00682101561258c57506000919050565b6509184e72b4b38211156125a257506000919050565b506001919050565b60006125b5826116e1565b5091505080156105cd57606b5460655460405163095ea7b360e01b81526001600160a01b0391821660048201526024810184905291169063095ea7b3906044016020604051808303816000875af1158015612614573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126389190612d3a565b5060408051600280825260608083018452926020830190803683375050606b5482519293506001600160a01b03169183915060009061267957612679612cda565b6001600160a01b0392831660209182029290920101526066548251911690829060019081106126aa576126aa612cda565b6001600160a01b03928316602091820292909201015260655460405163791ac94760e01b815291169063791ac947906126f0908590600090869089904290600401612e9a565b600060405180830381600087803b15801561270a57600080fd5b505af115801561271e573d6000803e3d6000fd5b5050505060005b6001600160a01b038416600090815260746020526040902054811015611230576001600160a01b038416600090815260746020526040902080544291908390811061277257612772612cda565b60009182526020909120600360059092020101558061279081612d06565b915050612725565b600061212083836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f0000000000008152506129d7565b6040805160028082526060808301845260009390929190602083019080368337019050509050848160008151811061281457612814612cda565b60200260200101906001600160a01b031690816001600160a01b031681525050838160018151811061284857612848612cda565b6001600160a01b03928316602091820292909201015260655460405163d06ca61f60e01b8152600092919091169063d06ca61f9061288c9087908690600401612ed6565b600060405180830381865afa1580156128a9573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526128d19190810190612eef565b905080600183516128e29190612d74565b815181106128f2576128f2612cda565b6020026020010151925050509392505050565b600061212083836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250612a0e565b600054610100900460ff16610d2c5760405162461bcd60e51b81526004016104e690612e00565b600054610100900460ff166129955760405162461bcd60e51b81526004016104e690612e00565b610d2c336121d0565b6000806129aa83611594565b915091508115611d76576001600160a01b03166000908152607760205260409020805460ff191690555050565b600081836129f85760405162461bcd60e51b81526004016104e69190612f75565b506000612a058486612d8b565b95945050505050565b60008184841115612a325760405162461bcd60e51b81526004016104e69190612f75565b506000612a058486612d74565b508054600082556005029060005260206000209081019061057b91905b80821115612a8b5760008082556001820181905560028201819055600382018190556004820155600501612a5c565b5090565b6001600160a01b038116811461057b57600080fd5b600060208284031215612ab657600080fd5b813561212081612a8f565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715612b0057612b00612ac1565b604052919050565b600067ffffffffffffffff821115612b2257612b22612ac1565b5060051b60200190565b60006020808385031215612b3f57600080fd5b823567ffffffffffffffff811115612b5657600080fd5b8301601f81018513612b6757600080fd5b8035612b7a612b7582612b08565b612ad7565b81815260059190911b82018301908381019087831115612b9957600080fd5b928401925b82841015612bb757833582529284019290840190612b9e565b979650505050505050565b600060208284031215612bd457600080fd5b5035919050565b600081518084526020808501945080840160005b83811015612c0b57815187529582019590820190600101612bef565b509495945050505050565b82815260406020820152600061158c6040830184612bdb565b6020815260006121206020830184612bdb565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b60208082526017908201527f41646472657373206973206e6f7420636f6e7472616374000000000000000000604082015260600190565b6020808252601290820152712cb7ba9030b932903737ba1039ba30b5b2b960711b604082015260600190565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000600019821415612d1a57612d1a612cf0565b5060010190565b600060208284031215612d3357600080fd5b5051919050565b600060208284031215612d4c57600080fd5b8151801515811461212057600080fd5b60008219821115612d6f57612d6f612cf0565b500190565b600082821015612d8657612d86612cf0565b500390565b600082612da857634e487b7160e01b600052601260045260246000fd5b500490565b600081612dbc57612dbc612cf0565b506000190190565b6000816000190483118215151615612dde57612dde612cf0565b500290565b600060208284031215612df557600080fd5b815161212081612a8f565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b634e487b7160e01b600052603160045260246000fd5b600081518084526020808501945080840160005b83811015612c0b5781516001600160a01b031687529582019590820190600101612e75565b85815284602082015260a060408201526000612eb960a0830186612e61565b6001600160a01b0394909416606083015250608001529392505050565b82815260406020820152600061158c6040830184612e61565b60006020808385031215612f0257600080fd5b825167ffffffffffffffff811115612f1957600080fd5b8301601f81018513612f2a57600080fd5b8051612f38612b7582612b08565b81815260059190911b82018301908381019087831115612f5757600080fd5b928401925b82841015612bb757835182529284019290840190612f5c565b600060208083528351808285015260005b81811015612fa257858101830151858201604001528201612f86565b81811115612fb4576000604083870101525b50601f01601f191692909201604001939250505056fe\",\n        ),\n        (\n            \"0x8B3D32cf2bb4d0D16656f4c0b04Fa546274f1545\",\n            \"GovernorCharlieDelegate\",\n            \"608060405234801561001057600080fd5b50613e45806100206000396000f3fe60806040526004361061031a5760003560e01c80637b3c71d3116101ab578063d50572ee116100f7578063f0843ba811610095578063fc176c041161006f578063fc176c0414610b82578063fc4eee4214610ba2578063fc66ff1414610bb8578063fe0d94c114610bd857600080fd5b8063f0843ba814610b12578063f2b0653714610b32578063f682e04c14610b6257600080fd5b8063de7bc127116100d1578063de7bc127146109ec578063deaaa7cc14610a02578063e23a9a5214610a36578063e837159c14610afc57600080fd5b8063d50572ee146109a0578063da35c664146109b6578063ddf0b009146109cc57600080fd5b8063a6d8784a11610164578063c1a287e21161013e578063c1a287e214610933578063c4d66de81461094a578063c5a8425d1461096a578063c9fb9e871461098a57600080fd5b8063a6d8784a146108e7578063abaac6a8146108fd578063b58131b01461091d57600080fd5b80637b3c71d31461083c5780637bdbe4d01461085c5780637cae57bb14610871578063806bd5811461088757806386d37e8b146108a757806399533365146108c757600080fd5b80632fedff591161026a5780633e4f49e61161022357806350442098116101fd578063504420981461074657806356781388146107665780635c60da1b1461078657806366176743146107be57600080fd5b80633e4f49e6146106d957806340e58ee5146107065780634d6733d21461072657600080fd5b80632fedff59146105ee578063328dd9821461060e57806338bd0dda1461063e5780633932abb11461066b5780633af32abf146106815780633bccf4fd146106b957600080fd5b8063158ef93e116102d757806318b62629116102b157806318b626291461056e5780631dfb1b5a1461058457806320606b70146105a457806324bc1a64146105d857600080fd5b8063158ef93e146104f757806317977c611461052157806317ba1b8b1461054e57600080fd5b8063013cf08b1461031f57806302a251a31461042857806306fdde031461044c5780630825f38f146104a25780630ea2d98c146104b7578063140499ea146104d7575b600080fd5b34801561032b57600080fd5b506103b361033a3660046132ee565b60096020819052600091825260409091208054600182015460028301546007840154600885015495850154600a860154600b870154600c880154600d890154600e9099015497996001600160a01b0390971698959794969593949293919260ff808316936101008404821693620100009004909116918d565b604080519d8e526001600160a01b03909c1660208e01529a8c019990995260608b019790975260808a019590955260a089019390935260c088019190915260e08701521515610100860152151561012085015215156101408401526101608301526101808201526101a0015b60405180910390f35b34801561043457600080fd5b5061043e60045481565b60405190815260200161041f565b34801561045857600080fd5b506104956040518060400160405280601a81526020017f496e7465726573742050726f746f636f6c20476f7665726e6f7200000000000081525081565b60405161041f9190613363565b6104b56104b0366004613450565b610beb565b005b3480156104c357600080fd5b506104b56104d23660046132ee565b610e61565b3480156104e357600080fd5b506104b56104f23660046134d6565b610ec6565b34801561050357600080fd5b506012546105119060ff1681565b604051901515815260200161041f565b34801561052d57600080fd5b5061043e61053c3660046134d6565b600a6020526000908152604090205481565b34801561055a57600080fd5b506104b56105693660046132ee565b610f07565b34801561057a57600080fd5b5061043e600f5481565b34801561059057600080fd5b506104b561059f3660046132ee565b610f64565b3480156105b057600080fd5b5061043e7f8cad95687ba82c2ce50e74f7b754645e5117c3a5bec8151c0726d5857980a86681565b3480156105e457600080fd5b5061043e60015481565b3480156105fa57600080fd5b506104b56106093660046132ee565b610fc1565b34801561061a57600080fd5b5061062e6106293660046132ee565b61101e565b60405161041f94939291906135ba565b34801561064a57600080fd5b5061043e6106593660046134d6565b600d6020526000908152604090205481565b34801561067757600080fd5b5061043e60035481565b34801561068d57600080fd5b5061051161069c3660046134d6565b6001600160a01b03166000908152600d6020526040902054421090565b3480156106c557600080fd5b506104b56106d4366004613623565b6112af565b3480156106e557600080fd5b506106f96106f43660046132ee565b611516565b60405161041f9190613687565b34801561071257600080fd5b506104b56107213660046132ee565b61169e565b34801561073257600080fd5b506104b56107413660046136af565b611b80565b34801561075257600080fd5b506104b56107613660046132ee565b611c45565b34801561077257600080fd5b506104b56107813660046136d9565b611ca2565b34801561079257600080fd5b506000546107a6906001600160a01b031681565b6040516001600160a01b03909116815260200161041f565b3480156107ca57600080fd5b506108146107d9366004613705565b601160209081526000928352604080842090915290825290205460ff808216916101008104909116906201000090046001600160601b031683565b60408051931515845260ff90921660208401526001600160601b03169082015260600161041f565b34801561084857600080fd5b506104b5610857366004613728565b611d09565b34801561086857600080fd5b5061043e600a81565b34801561087d57600080fd5b5061043e600c5481565b34801561089357600080fd5b506104b56108a23660046132ee565b611d58565b3480156108b357600080fd5b506104b56108c23660046132ee565b611db5565b3480156108d357600080fd5b506104b56108e23660046134d6565b611e12565b3480156108f357600080fd5b5061043e60155481565b34801561090957600080fd5b506104b56109183660046132ee565b611e8b565b34801561092957600080fd5b5061043e60055481565b34801561093f57600080fd5b5061043e6212750081565b34801561095657600080fd5b506104b56109653660046134d6565b611ee8565b34801561097657600080fd5b50600e546107a6906001600160a01b031681565b34801561099657600080fd5b5061043e60135481565b3480156109ac57600080fd5b5061043e60025481565b3480156109c257600080fd5b5061043e60075481565b3480156109d857600080fd5b506104b56109e73660046132ee565b611fd9565b3480156109f857600080fd5b5061043e60105481565b348015610a0e57600080fd5b5061043e7f150214d74d59b7d1e90c73fc22ef3d991dd0a76b046543d4d80ab92d2a50328f81565b348015610a4257600080fd5b50610acc610a51366004613705565b60408051606081018252600080825260208201819052918101919091525060009182526011602090815260408084206001600160a01b03939093168452918152918190208151606081018352905460ff8082161515835261010082041693820193909352620100009092046001600160601b03169082015290565b6040805182511515815260208084015160ff1690820152918101516001600160601b03169082015260600161041f565b348015610b0857600080fd5b5061043e60145481565b348015610b1e57600080fd5b506104b5610b2d3660046132ee565b61238f565b348015610b3e57600080fd5b50610511610b4d3660046132ee565b600b6020526000908152604090205460ff1681565b348015610b6e57600080fd5b5061043e610b7d3660046139b0565b6123ec565b348015610b8e57600080fd5b506104b5610b9d3660046132ee565b612a48565b348015610bae57600080fd5b5061043e60065481565b348015610bc457600080fd5b506008546107a6906001600160a01b031681565b6104b5610be63660046132ee565b612aa5565b60008585858585604051602001610c06959493929190613a91565b60408051601f1981840301815291815281516020928301206000818152600b90935291205490915060ff16610c7b5760405162461bcd60e51b81526020600482015260166024820152753a3c103430b9b713ba103132b2b71038bab2bab2b21760511b60448201526064015b60405180910390fd5b81421015610ccb5760405162461bcd60e51b815260206004820152601d60248201527f7478206861736e2774207375727061737365642074696d656c6f636b2e0000006044820152606401610c72565b610cd86212750083613af3565b421115610d165760405162461bcd60e51b815260206004820152600c60248201526b3a3c1034b99039ba30b6329760a11b6044820152606401610c72565b6000818152600b60205260409020805460ff191690558351606090610d3c575082610d68565b848051906020012084604051602001610d56929190613b0b565b60405160208183030381529060405290505b6000876001600160a01b03168783604051610d839190613b3c565b60006040518083038185875af1925050503d8060008114610dc0576040519150601f19603f3d011682016040523d82523d6000602084013e610dc5565b606091505b5050905080610e0f5760405162461bcd60e51b81526020600482015260166024820152753a3c1032bc32b1baba34b7b7103932bb32b93a32b21760511b6044820152606401610c72565b876001600160a01b0316837fa560e3198060a2f10670c1ec5b403077ea6ae93ca8de1c32b451dc1a943cd6e789898989604051610e4f9493929190613b58565b60405180910390a35050505050505050565b333014610e805760405162461bcd60e51b8152600401610c7290613b95565b600480549082905560408051828152602081018490527f7e3f7f0708a84de9203036abaa450dccc85ad5ff52f78c170f3edb55cf5e882891015b60405180910390a15050565b333014610ee55760405162461bcd60e51b8152600401610c7290613b95565b600880546001600160a01b0319166001600160a01b0392909216919091179055565b333014610f265760405162461bcd60e51b8152600401610c7290613b95565b600580549082905560408051828152602081018490527fccb45da8d5717e6c4544694297c4ba5cf151d455c9bb0ed4fc7a38411bc054619101610eba565b333014610f835760405162461bcd60e51b8152600401610c7290613b95565b600380549082905560408051828152602081018490527fc565b045403dc03c2eea82b81a0465edad9e2e7fc4d97e11421c209da93d7a939101610eba565b333014610fe05760405162461bcd60e51b8152600401610c7290613b95565b601480549082905560408051828152602081018490527f519a192fe8db9e38785eb494c69f530ddb21b9e34322f8d08fe29bd3849749889101610eba565b606080606080600060096000878152602001908152602001600020905080600301816004018260050183600601838054806020026020016040519081016040528092919081815260200182805480156110a057602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611082575b50505050509350828054806020026020016040519081016040528092919081815260200182805480156110f257602002820191906000526020600020905b8154815260200190600101908083116110de575b5050505050925081805480602002602001604051908101604052809291908181526020016000905b828210156111c657838290600052602060002001805461113990613bcc565b80601f016020809104026020016040519081016040528092919081815260200182805461116590613bcc565b80156111b25780601f10611187576101008083540402835291602001916111b2565b820191906000526020600020905b81548152906001019060200180831161119557829003601f168201915b50505050508152602001906001019061111a565b50505050915080805480602002602001604051908101604052809291908181526020016000905b8282101561129957838290600052602060002001805461120c90613bcc565b80601f016020809104026020016040519081016040528092919081815260200182805461123890613bcc565b80156112855780601f1061125a57610100808354040283529160200191611285565b820191906000526020600020905b81548152906001019060200180831161126857829003601f168201915b5050505050815260200190600101906111ed565b5050505090509450945094509450509193509193565b604080518082018252601a81527f496e7465726573742050726f746f636f6c20476f7665726e6f7200000000000060209182015281517f8cad95687ba82c2ce50e74f7b754645e5117c3a5bec8151c0726d5857980a866818301527f75a838dcd8ee5903cc7f4a5799344d0080864f57a6e9911f8bdfb4c8ddce9b5481840152466060820152306080808301919091528351808303909101815260a0820184528051908301207f150214d74d59b7d1e90c73fc22ef3d991dd0a76b046543d4d80ab92d2a50328f60c083015260e0820189905260ff8816610100808401919091528451808403909101815261012083019094528351939092019290922061190160f01b6101408401526101428301829052610162830181905290916000906101820160408051601f198184030181528282528051602091820120600080855291840180845281905260ff8a169284019290925260608301889052608083018790529092509060019060a0016020604051602081039080840390855afa15801561143c573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b03811661149f5760405162461bcd60e51b815260206004820181905260248201527f63617374566f746542795369673a20696e76616c6964207369676e61747572656044820152606401610c72565b88816001600160a01b03167fb8e138887d0aa13bab447e82de9d5c1777041ecd21ca36ba824ff1e6c07ddda48a6114d7858e8e612c90565b6040805160ff90931683526001600160601b039091166020830152606090820181905260009082015260800160405180910390a3505050505050505050565b6000816007541015801561152b575060065482115b6115775760405162461bcd60e51b815260206004820152601a60248201527f73746174653a20696e76616c69642070726f706f73616c2069640000000000006044820152606401610c72565b600082815260096020908152604080832060018101546001600160a01b03168452600d90925290912054600c82015442919091109060ff16156115be575060029392505050565b816007015443116115d3575060009392505050565b816008015443116115e8575060019392505050565b8080156115fc575081600d015482600a0154115b80611618575080158015611618575081600a0154826009015411155b80611633575080158015611633575081600d01548260090154105b15611642575060039392505050565b6002820154611655575060049392505050565b600c820154610100900460ff1615611671575060079392505050565b6212750082600201546116849190613af3565b4210611694575060069392505050565b5060059392505050565b60076116a982611516565b60078111156116ba576116ba613671565b14156117085760405162461bcd60e51b815260206004820152601d60248201527f63616e742063616e63656c2065786563757465642070726f706f73616c0000006044820152606401610c72565b600081815260096020526040902060018101546001600160a01b0316336001600160a01b0316146119755760018101546001600160a01b03166000908152600d6020526040902054421015611878576005546008546001838101546001600160a01b039283169263782d6fe1929116906117829043613c07565b6040516001600160e01b031960e085901b1681526001600160a01b039092166004830152602482015260440160206040518083038186803b1580156117c657600080fd5b505afa1580156117da573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117fe9190613c1e565b6001600160601b03161080156118275750600e546001600160a01b0316336001600160a01b0316145b6118735760405162461bcd60e51b815260206004820152601c60248201527f63616e63656c3a2077686974656c69737465642070726f706f736572000000006044820152606401610c72565b611975565b6005546008546001838101546001600160a01b039283169263782d6fe1929116906118a39043613c07565b6040516001600160e01b031960e085901b1681526001600160a01b039092166004830152602482015260440160206040518083038186803b1580156118e757600080fd5b505afa1580156118fb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061191f9190613c1e565b6001600160601b0316106119755760405162461bcd60e51b815260206004820181905260248201527f63616e63656c3a2070726f706f7365722061626f7665207468726573686f6c646044820152606401610c72565b600c8101805460ff1916600117905560005b6003820154811015611b5057611b3e8260030182815481106119ab576119ab613c47565b6000918252602090912001546004840180546001600160a01b0390921691849081106119d9576119d9613c47565b90600052602060002001548460050184815481106119f9576119f9613c47565b906000526020600020018054611a0e90613bcc565b80601f0160208091040260200160405190810160405280929190818152602001828054611a3a90613bcc565b8015611a875780601f10611a5c57610100808354040283529160200191611a87565b820191906000526020600020905b815481529060010190602001808311611a6a57829003601f168201915b5050505050856006018581548110611aa157611aa1613c47565b906000526020600020018054611ab690613bcc565b80601f0160208091040260200160405190810160405280929190818152602001828054611ae290613bcc565b8015611b2f5780601f10611b0457610100808354040283529160200191611b2f565b820191906000526020600020905b815481529060010190602001808311611b1257829003601f168201915b50505050508660020154612f12565b80611b4881613c5d565b915050611987565b5060405182907f789cf55be980739dad1d0699b93b58e806b51c9d96619bfa8fe0a28abaa7b30c90600090a25050565b333014611b9f5760405162461bcd60e51b8152600401610c7290613b95565b42601554611bad9190613af3565b8110611bf45760405162461bcd60e51b81526020600482015260166024820152750caf0e0d2e4c2e8d2dedc40caf0c6cacac8e640dac2f60531b6044820152606401610c72565b6001600160a01b0382166000818152600d6020908152604091829020849055815192835282018390527f4e7b7545bc5744d0e30425959f4687475774b6c7edad77d24cb51c7d967d45159101610eba565b333014611c645760405162461bcd60e51b8152600401610c7290613b95565b601080549082905560408051828152602081018490527f2a61b867418a359864adca8bb250ea65ee8bd41dbfd0279198d8e7552d4a27c29101610eba565b81337fb8e138887d0aa13bab447e82de9d5c1777041ecd21ca36ba824ff1e6c07ddda483611cd1838583612c90565b6040805160ff90931683526001600160601b039091166020830152606090820181905260009082015260800160405180910390a35050565b83337fb8e138887d0aa13bab447e82de9d5c1777041ecd21ca36ba824ff1e6c07ddda485611d38838583612c90565b8686604051611d4a9493929190613c78565b60405180910390a350505050565b333014611d775760405162461bcd60e51b8152600401610c7290613b95565b601380549082905560408051828152602081018490527f8cb5451eee8feb516cec9cd600201bbc31a30886d70c841a085a3fa69a4294d19101610eba565b333014611dd45760405162461bcd60e51b8152600401610c7290613b95565b600180549082905560408051828152602081018490527fa74554b0f53da47d07ec571d712428b3720460f54f81375fbcf78f6b5f72e7ed9101610eba565b333014611e315760405162461bcd60e51b8152600401610c7290613b95565b600e80546001600160a01b038381166001600160a01b031983168117909355604080519190921680825260208201939093527f80a07e73e552148844a9c216d9724212d609cfa54e9c1a2e97203bdd2c4ad3419101610eba565b333014611eaa5760405162461bcd60e51b8152600401610c7290613b95565b600f80549082905560408051828152602081018490527f80a384652af83fc00bfd40ef94edda7ede83e7db39931b2c889821573f314e239101610eba565b60125460ff1615611f3b5760405162461bcd60e51b815260206004820152601860248201527f616c7265616479206265656e20696e697469616c697a656400000000000000006044820152606401610c72565b600880546001600160a01b0319166001600160a01b0392909216919091179055619d8060045561335460035569d3c21bcecceda10000006005556202a300600c5560006007556a084595161401484a00000060019081556a21165458500521280000006002556119aa600f5561a8c06010556a01a784379d99db420000006013556146506014556301e133806015556012805460ff19169091179055565b6004611fe482611516565b6007811115611ff557611ff5613671565b146120425760405162461bcd60e51b815260206004820152601f60248201527f63616e206f6e6c792062652071756575656420696620737563636565646564006044820152606401610c72565b6000818152600960205260408120600e8101549091906120629042613af3565b905060005b600383015481101561234d57600b600084600301838154811061208c5761208c613c47565b6000918252602090912001546004860180546001600160a01b0390921691859081106120ba576120ba613c47565b90600052602060002001548660050185815481106120da576120da613c47565b906000526020600020018760060186815481106120f9576120f9613c47565b9060005260206000200187604051602001612118959493929190613d62565b60408051601f198184030181529181528151602092830120835290820192909252016000205460ff161561218e5760405162461bcd60e51b815260206004820152601760248201527f70726f706f73616c20616c7265616479207175657565640000000000000000006044820152606401610c72565b61233a8360030182815481106121a6576121a6613c47565b6000918252602090912001546004850180546001600160a01b0390921691849081106121d4576121d4613c47565b90600052602060002001548560050184815481106121f4576121f4613c47565b90600052602060002001805461220990613bcc565b80601f016020809104026020016040519081016040528092919081815260200182805461223590613bcc565b80156122825780601f1061225757610100808354040283529160200191612282565b820191906000526020600020905b81548152906001019060200180831161226557829003601f168201915b505050505086600601858154811061229c5761229c613c47565b9060005260206000200180546122b190613bcc565b80601f01602080910402602001604051908101604052809291908181526020018280546122dd90613bcc565b801561232a5780601f106122ff5761010080835404028352916020019161232a565b820191906000526020600020905b81548152906001019060200180831161230d57829003601f168201915b50505050508688600e0154612fac565b508061234581613c5d565b915050612067565b506002820181905560405181815283907f9a2e42fd6722813d69113e7d0079d3d940171428df7373df9c7f7617cfda28929060200160405180910390a2505050565b3330146123ae5760405162461bcd60e51b8152600401610c7290613b95565b600280549082905560408051828152602081018490527fc2adf06da6765dba7faaccde4c0ce3f91c35dd3390e7f0b6bc2844202c9fa9529101610eba565b6000600154600014156124365760405162461bcd60e51b8152602060048201526012602482015271436861726c6965206e6f742061637469766560701b6044820152606401610c72565b6005546008546001600160a01b031663782d6fe133612456600143613c07565b6040516001600160e01b031960e085901b1681526001600160a01b039092166004830152602482015260440160206040518083038186803b15801561249a57600080fd5b505afa1580156124ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124d29190613c1e565b6001600160601b03161015806124ec57506124ec3361069c565b6125385760405162461bcd60e51b815260206004820152601e60248201527f766f7465732062656c6f772070726f706f73616c207468726573686f6c6400006044820152606401610c72565b8551875114801561254a575084518751145b8015612557575083518751145b6125a35760405162461bcd60e51b815260206004820152601a60248201527f696e666f726d6174696f6e206172697479206d69736d617463680000000000006044820152606401610c72565b86516125e85760405162461bcd60e51b81526020600482015260146024820152736d7573742070726f7669646520616374696f6e7360601b6044820152606401610c72565b600a8751111561262d5760405162461bcd60e51b815260206004820152601060248201526f746f6f206d616e7920616374696f6e7360801b6044820152606401610c72565b336000908152600a6020526040902054801561271657600061264e82611516565b9050600181600781111561266457612664613671565b14156126b25760405162461bcd60e51b815260206004820152601e60248201527f6f6e65206c6976652070726f706f73616c207065722070726f706f73657200006044820152606401610c72565b60008160078111156126c6576126c6613671565b14156127145760405162461bcd60e51b815260206004820152601e60248201527f6f6e65206c6976652070726f706f73616c207065722070726f706f73657200006044820152606401610c72565b505b6007805490600061272683613c5d565b9190505550600060405180610220016040528060075481526020016127483390565b6001600160a01b03168152602001600081526020018a8152602001898152602001888152602001878152602001600354436127839190613af3565b8152602001600454600354436127999190613af3565b6127a39190613af3565b815260200160008152602001600081526020016000815260200160001515815260200160001515815260200185151581526020016001548152602001600c5481525090508380156127fa57506127f83361069c565b155b1561282c574360e08201819052600f5461281391613af3565b6101008201526002546101e08201526010546102008201525b6128353361069c565b15612876576013546101e08201526014546128509043613af3565b60e08201526004546014546128659043613af3565b61286f9190613af3565b6101008201525b805160009081526009602090815260409182902083518155818401516001820180546001600160a01b0319166001600160a01b03909216919091179055918301516002830155606083015180518493926128d792600385019291019061309d565b50608082015180516128f3916004840191602090910190613102565b5060a0820151805161290f91600584019160209091019061313d565b5060c0820151805161292b916006840191602090910190613196565b5060e08281015160078301556101008084015160088401556101208401516009840155610140840151600a80850191909155610160850151600b850155610180850151600c850180546101a08801516101c089015161ffff1990921693151561ff0019169390931792151585029290921762ff0000191662010000921515929092029190911790556101e0850151600d85015561020090940151600e9093019290925583516020808601516001600160a01b0316600090815294905260409384902055830151835191840151925190923392917f7d84a6263ae0d98d3329bd7b46bb4e8d6f98cd35a7adb45c274c8b7fd5ebd5e091612a33918f918f918f918f918f90613d9b565b60405180910390a45198975050505050505050565b333014612a675760405162461bcd60e51b8152600401610c7290613b95565b600c80549082905560408051828152602081018490527fed0229422af39d4d7d33f7a27d31d6f5cb20ec628293da58dd6e8a528ed466be9101610eba565b6005612ab082611516565b6007811115612ac157612ac1613671565b14612b0e5760405162461bcd60e51b815260206004820152601c60248201527f63616e206f6e6c792062652065786563276420696620717565756564000000006044820152606401610c72565b6000818152600960205260408120600c8101805461ff001916610100179055905b6003820154811015612c6057306001600160a01b0316630825f38f836004018381548110612b5f57612b5f613c47565b9060005260206000200154846003018481548110612b7f57612b7f613c47565b6000918252602090912001546004860180546001600160a01b039092169186908110612bad57612bad613c47565b9060005260206000200154866005018681548110612bcd57612bcd613c47565b90600052602060002001876006018781548110612bec57612bec613c47565b9060005260206000200188600201546040518763ffffffff1660e01b8152600401612c1b959493929190613d62565b6000604051808303818588803b158015612c3457600080fd5b505af1158015612c48573d6000803e3d6000fd5b50505050508080612c5890613c5d565b915050612b2f565b5060405182907f712ae1383f79ac853f8d882153778e0260ef8f03b504e2866e0593e04d2b291f90600090a25050565b60006001612c9d84611516565b6007811115612cae57612cae613671565b14612cee5760405162461bcd60e51b815260206004820152601060248201526f1d9bdd1a5b99c81a5cc818db1bdcd95960821b6044820152606401610c72565b60028260ff161115612d365760405162461bcd60e51b8152602060048201526011602482015270696e76616c696420766f7465207479706560781b6044820152606401610c72565b6000838152600960209081526040808320601183528184206001600160a01b0389168552909252909120805460ff1615612da85760405162461bcd60e51b81526020600482015260136024820152721d9bdd195c88185b1c9958591e481d9bdd1959606a1b6044820152606401610c72565b600854600783015460405163782d6fe160e01b81526000926001600160a01b03169163782d6fe191612df2918b916004016001600160a01b03929092168252602082015260400190565b60206040518083038186803b158015612e0a57600080fd5b505afa158015612e1e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e429190613c1e565b905060ff8516612e6f57806001600160601b031683600a0154612e659190613af3565b600a840155612ec9565b8460ff1660011415612e9e57806001600160601b03168360090154612e949190613af3565b6009840155612ec9565b8460ff1660021415612ec957806001600160601b031683600b0154612ec39190613af3565b600b8401555b81546001600160601b03821662010000026dffffffffffffffffffffffff00001960ff88166101000261ffff199093169290921760011791909116179091559150509392505050565b60008585858585604051602001612f2d959493929190613a91565b60408051601f1981840301815282825280516020918201206000818152600b909252919020805460ff1916905591506001600160a01b0387169082907f2fffc091a501fd91bfbff27141450d3acb40fb8e6d8382b243ec7a812a3aaf8790612f9c908990899089908990613b58565b60405180910390a3505050505050565b6000612fb88242613af3565b831015612ffd5760405162461bcd60e51b815260206004820152601360248201527236bab9ba1039b0ba34b9b33c903232b630bc9760691b6044820152606401610c72565b60008787878787604051602001613018959493929190613a91565b60408051601f1981840301815282825280516020918201206000818152600b909252919020805460ff1916600117905591506001600160a01b0389169082907f76e2796dc3a81d57b0e8504b647febcbeeb5f4af818e164f11eef8131a6a763f9061308a908b908b908b908b90613b58565b60405180910390a3979650505050505050565b8280548282559060005260206000209081019282156130f2579160200282015b828111156130f257825182546001600160a01b0319166001600160a01b039091161782556020909201916001909101906130bd565b506130fe9291506131ef565b5090565b8280548282559060005260206000209081019282156130f2579160200282015b828111156130f2578251825591602001919060010190613122565b82805482825590600052602060002090810192821561318a579160200282015b8281111561318a578251805161317a918491602090910190613204565b509160200191906001019061315d565b506130fe929150613277565b8280548282559060005260206000209081019282156131e3579160200282015b828111156131e357825180516131d3918491602090910190613204565b50916020019190600101906131b6565b506130fe929150613294565b5b808211156130fe57600081556001016131f0565b82805461321090613bcc565b90600052602060002090601f01602090048101928261323257600085556130f2565b82601f1061324b57805160ff19168380011785556130f2565b828001600101855582156130f257918201828111156130f2578251825591602001919060010190613122565b808211156130fe57600061328b82826132b1565b50600101613277565b808211156130fe5760006132a882826132b1565b50600101613294565b5080546132bd90613bcc565b6000825580601f106132cd575050565b601f0160209004906000526020600020908101906132eb91906131ef565b50565b60006020828403121561330057600080fd5b5035919050565b60005b8381101561332257818101518382015260200161330a565b83811115613331576000848401525b50505050565b6000815180845261334f816020860160208601613307565b601f01601f19169290920160200192915050565b6020815260006133766020830184613337565b9392505050565b80356001600160a01b038116811461339457600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff811182821017156133d8576133d8613399565b604052919050565b600082601f8301126133f157600080fd5b813567ffffffffffffffff81111561340b5761340b613399565b61341e601f8201601f19166020016133af565b81815284602083860101111561343357600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080600060a0868803121561346857600080fd5b6134718661337d565b945060208601359350604086013567ffffffffffffffff8082111561349557600080fd5b6134a189838a016133e0565b945060608801359150808211156134b757600080fd5b506134c4888289016133e0565b95989497509295608001359392505050565b6000602082840312156134e857600080fd5b6133768261337d565b600081518084526020808501945080840160005b8381101561352a5781516001600160a01b031687529582019590820190600101613505565b509495945050505050565b600081518084526020808501945080840160005b8381101561352a57815187529582019590820190600101613549565b600081518084526020808501808196508360051b8101915082860160005b858110156135ad57828403895261359b848351613337565b98850198935090840190600101613583565b5091979650505050505050565b6080815260006135cd60808301876134f1565b82810360208401526135df8187613535565b905082810360408401526135f38186613565565b905082810360608401526136078185613565565b979650505050505050565b803560ff8116811461339457600080fd5b600080600080600060a0868803121561363b57600080fd5b8535945061364b60208701613612565b935061365960408701613612565b94979396509394606081013594506080013592915050565b634e487b7160e01b600052602160045260246000fd5b60208101600883106136a957634e487b7160e01b600052602160045260246000fd5b91905290565b600080604083850312156136c257600080fd5b6136cb8361337d565b946020939093013593505050565b600080604083850312156136ec57600080fd5b823591506136fc60208401613612565b90509250929050565b6000806040838503121561371857600080fd5b823591506136fc6020840161337d565b6000806000806060858703121561373e57600080fd5b8435935061374e60208601613612565b9250604085013567ffffffffffffffff8082111561376b57600080fd5b818701915087601f83011261377f57600080fd5b81358181111561378e57600080fd5b8860208285010111156137a057600080fd5b95989497505060200194505050565b600067ffffffffffffffff8211156137c9576137c9613399565b5060051b60200190565b600082601f8301126137e457600080fd5b813560206137f96137f4836137af565b6133af565b82815260059290921b8401810191818101908684111561381857600080fd5b8286015b8481101561383a5761382d8161337d565b835291830191830161381c565b509695505050505050565b600082601f83011261385657600080fd5b813560206138666137f4836137af565b82815260059290921b8401810191818101908684111561388557600080fd5b8286015b8481101561383a5780358352918301918301613889565b600082601f8301126138b157600080fd5b813560206138c16137f4836137af565b82815260059290921b840181019181810190868411156138e057600080fd5b8286015b8481101561383a57803567ffffffffffffffff8111156139045760008081fd5b6139128986838b01016133e0565b8452509183019183016138e4565b600082601f83011261393157600080fd5b813560206139416137f4836137af565b82815260059290921b8401810191818101908684111561396057600080fd5b8286015b8481101561383a57803567ffffffffffffffff8111156139845760008081fd5b6139928986838b01016133e0565b845250918301918301613964565b8035801515811461339457600080fd5b60008060008060008060c087890312156139c957600080fd5b863567ffffffffffffffff808211156139e157600080fd5b6139ed8a838b016137d3565b97506020890135915080821115613a0357600080fd5b613a0f8a838b01613845565b96506040890135915080821115613a2557600080fd5b613a318a838b016138a0565b95506060890135915080821115613a4757600080fd5b613a538a838b01613920565b94506080890135915080821115613a6957600080fd5b50613a7689828a016133e0565b925050613a8560a088016139a0565b90509295509295509295565b60018060a01b038616815284602082015260a060408201526000613ab860a0830186613337565b8281036060840152613aca8186613337565b9150508260808301529695505050505050565b634e487b7160e01b600052601160045260246000fd5b60008219821115613b0657613b06613add565b500190565b6001600160e01b0319831681528151600090613b2e816004850160208701613307565b919091016004019392505050565b60008251613b4e818460208701613307565b9190910192915050565b848152608060208201526000613b716080830186613337565b8281036040840152613b838186613337565b91505082606083015295945050505050565b60208082526017908201527f6d75737420636f6d652066726f6d2074686520676f762e000000000000000000604082015260600190565b600181811c90821680613be057607f821691505b60208210811415613c0157634e487b7160e01b600052602260045260246000fd5b50919050565b600082821015613c1957613c19613add565b500390565b600060208284031215613c3057600080fd5b81516001600160601b038116811461337657600080fd5b634e487b7160e01b600052603260045260246000fd5b6000600019821415613c7157613c71613add565b5060010190565b60ff851681526001600160601b038416602082015260606040820152816060820152818360808301376000818301608090810191909152601f909201601f191601019392505050565b8054600090600181811c9080831680613cdb57607f831692505b6020808410821415613cfd57634e487b7160e01b600052602260045260246000fd5b838852818015613d145760018114613d2857613d56565b60ff19861689830152604089019650613d56565b876000528160002060005b86811015613d4e5781548b8201850152908501908301613d33565b8a0183019750505b50505050505092915050565b60018060a01b038616815284602082015260a060408201526000613d8960a0830186613cc1565b8281036060840152613aca8186613cc1565b60c081526000613dae60c08301896134f1565b8281036020840152613dc08189613535565b90508281036040840152613dd48188613565565b90508281036060840152613de88187613565565b905084608084015282810360a0840152613e028185613337565b999850505050505050505056fe\",\n        ),\n        (\n            \"0xDb53f47aC61FE54F456A4eb3E09832D08Dd7BEec\",\n            \"PoolExercise\",\n            \"6101c06040523480156200001257600080fd5b50604051620030713803806200307183398101604081905262000035916200016a565b6001600160a01b038681166101005285811660805284811660a05283811660c052821660e052600f81900b61012052858585858585620000846000808062000101602090811b6200011917901c565b6101408181525050620000a660016000806200010160201b620001191760201c565b6101608181525050620000c860026000806200010160201b620001191760201c565b6101808181525050620000ea60036000806200010160201b620001191760201c565b6101a05250620002319a5050505050505050505050565b600081600f0b6080846001600160401b0316901b60f88660078111156200012c576200012c620001f4565b6200013992911b6200020a565b6200014591906200020a565b949350505050565b80516001600160a01b03811681146200016557600080fd5b919050565b60008060008060008060c087890312156200018457600080fd5b6200018f876200014d565b95506200019f602088016200014d565b9450620001af604088016200014d565b9350620001bf606088016200014d565b9250620001cf608088016200014d565b915060a087015180600f0b8114620001e657600080fd5b809150509295509295509295565b634e487b7160e01b600052602160045260246000fd5b600082198211156200022c57634e487b7160e01b600052601160045260246000fd5b500190565b60805160a05160c05160e05161010051610120516101405161016051610180516101a051612d6f6200030260003960008181610e1c015261137b015260008181610e420152818161135101526113f4015260008181611327015281816114b801526122c90152600081816112fe015281816113cb0152818161148f015281816114e101526122ef0152600081816103a8015281816107ed0152610cda0152600050506000818161176601526117b201526000610485015260008181611964015261212c015260005050612d6f6000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c8063477130981461003b578063b50e7ee314610050575b600080fd5b61004e610049366004612986565b610063565b005b61004e61005e3660046129c7565b610109565b336001600160a01b038416146100f9576001600160a01b03831660009081527f1799cf914cb0cb442ca7c7ac709ee40d0cb89e87351dc08d517fbda27d50c68c6020908152604080832033845290915290205460ff166100f95760405162461bcd60e51b815260206004820152600c60248201526b1b9bdd08185c1c1c9bdd995960a21b60448201526064015b60405180910390fd5b61010483838361015f565b505050565b6101156000838361015f565b5050565b600081600f0b60808467ffffffffffffffff16901b60f8866007811115610142576101426129e9565b61014d92911b612a15565b6101579190612a15565b949350505050565b608082901c8260006001600160a01b0386161560f883901c600481600781111561018b5761018b6129e9565b14806101a8575060068160078111156101a6576101a66129e9565b145b6101e35760405162461bcd60e51b815260206004820152600c60248201526b696e76616c6964207479706560a01b60448201526064016100f0565b8115806101f95750428567ffffffffffffffff16105b6102335760405162461bcd60e51b815260206004820152600b60248201526a1b9bdd08195e1c1a5c995960aa1b60448201526064016100f0565b6004816007811115610247576102476129e9565b149250506000610262600080516020612d1a83398151915290565b9050600061026f826104c0565b9050428667ffffffffffffffff16101561029a576102978267ffffffffffffffff8816610526565b90505b82806102be5750836102b45784600f0b81600f0b126102be565b84600f0b81600f0b135b6102f45760405162461bcd60e51b81526020600482015260076024820152666e6f742049544d60c81b60448201526064016100f0565b6000841561033a5785600f0b82600f0b1315610335576103328861032984610320600f82900b8b61061e565b600f0b90610659565b600f0b906106b1565b90505b610367565b85600f0b82600f0b12156103675761036461035d89610329600f8a900b8661061e565b8490610719565b90505b6000841561038c5761037b89838c89610754565b6103859082612a15565b9050610454565b6103978b8b8b6108cb565b600082156103ff576103d58c6103d07f0000000000000000000000000000000000000000000000000000000000000000600f0b866106b1565b610a5d565b90506103e18183612a15565b91506103ff8c6103f089610a8c565b6103fa8487612a2d565b610ae1565b604080518c8152602081018c9052908101849052606081018290526001600160a01b038d16907f31939b125e073bbdbf69ac6eb0cb59489894a9bea509d658589af5917b53cca19060800160405180910390a2505b610474898361046e6104678a6000610bb1565b8c8c610119565b89610be4565b61047e9082612a15565b90506104b37f00000000000000000000000000000000000000000000000000000000000000006104ad88610e13565b83610e67565b5050505050505050505050565b60004282600c015414156104de576104d88242610e82565b92915050565b6104e782610eb0565b90506104f38242610e82565b600f0b61050557610505824283610fd3565b42600c830155610516826001611051565b610521826000611051565b919050565b600080610535610e1084612a5a565b600881901c6000818152601287016020526040812054929350909160ff84169190821b821c90610568620e100042612a5a565b90505b811580156105795750808411155b156105a65760128801600061058d86612a7c565b955085815260200190815260200160002054915061056b565b600060805b80156105d25783811c156105ca576105c38183612a15565b93811c9391505b60011c6105ab565b5060118901600060018360086105e88a84612a15565b6105f392911b612a2d565b6105fd9190612a2d565b8152602081019190915260400160002054600f0b9998505050505050505050565b6000600f82810b9084900b0360016001607f1b03198112801590610649575060016001607f1b038113155b61065257600080fd5b9392505050565b600081600f0b6000141561066c57600080fd5b600082600f0b604085600f0b901b8161068757610687612a44565b05905060016001607f1b03198112801590610649575060016001607f1b0381131561065257600080fd5b6000816106c0575060006104d8565b600083600f0b12156106d157600080fd5b600f83900b6001600160801b038316810260401c90608084901c026001600160c01b0381111561070057600080fd5b60401b811981111561071157600080fd5b019392505050565b600080610737838560030160149054906101000a900460ff166110e1565b9050610157818560030160159054906101000a900460ff166110f7565b60008281527fb31c2c74f86ca3ce94d901f5f5bbe66f7161eec2f7b5aa0b75a86371436424eb602052604081205b85156108c25760006107a9600161079884611112565b6107a29190612a2d565b839061111c565b905060006107b78287611128565b9050878111156107c45750865b600080881561084657896107d8848b612a97565b6107e29190612a5a565b9150610815846103d07f0000000000000000000000000000000000000000000000000000000000000000600f0b856106b1565b90506108218187612a15565b955061082d828a612a2d565b98506108468461083c89610a8c565b6103fa8486612a2d565b610850838b612a2d565b99506001600160a01b0384167f31939b125e073bbdbf69ac6eb0cb59489894a9bea509d658589af5917b53cca189856108898587612a2d565b604080519384526020840192909252908201526060810184905260800160405180910390a26108b98489856108cb565b50505050610782565b50949350505050565b6001600160a01b03831661092d5760405162461bcd60e51b815260206004820152602360248201527f455243313135353a206275726e2066726f6d20746865207a65726f206164647260448201526265737360e81b60648201526084016100f0565b61095b3384600061093d866111db565b610946866111db565b60405180602001604052806000815250611226565b60008281527f1799cf914cb0cb442ca7c7ac709ee40d0cb89e87351dc08d517fbda27d50c68b602090815260408083206001600160a01b038716845291829052909120548211156109fc5760405162461bcd60e51b815260206004820152602560248201527f455243313135353a206275726e20616d6f756e7420657863656564732062616c604482015264616e63657360d81b60648201526084016100f0565b6001600160a01b03841660008181526020838152604080832080548790039055805187815291820186905291929133917fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62910160405180910390a450505050565b600080610a6984611762565b9050612710610a788285612a97565b610a829190612a5a565b6101579084612a2d565b600081610ab157600080516020612d1a833981519152546001600160a01b03166104d8565b50507fbbd6af8edd89d04327b00c29df7f272b9b1ae01bf6d9c54a784f935706df52ec546001600160a01b031690565b80610aeb57505050565b60405163a9059cbb60e01b81526001600160a01b0384811660048301526024820183905283169063a9059cbb90604401602060405180830381600087803b158015610b3557600080fd5b505af1158015610b49573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b6d9190612ab6565b6101045760405162461bcd60e51b8152602060048201526015602482015274115490cc8c081d1c985b9cd9995c8819985a5b1959605a1b60448201526064016100f0565b60008215610bcf5781610bc5576005610bc8565b60045b90506104d8565b81610bdb576007610652565b60069392505050565b60008281527fb31c2c74f86ca3ce94d901f5f5bbe66f7161eec2f7b5aa0b75a86371436424eb60205260408120835b8615610e09576000610c3a6001610c2985611112565b610c339190612a2d565b849061111c565b90506000610c488288611128565b905088811115610c555750875b600089610c62838b612a97565b610c6c9190612a5a565b9050610c78818a612a2d565b9850610c84828b612a2d565b9950600087610cc35781610cb4610c9f600f88900b866106b1565b600080516020612d1a83398151915290610719565b610cbe9190612a2d565b610ccd565b610ccd8284612a2d565b90506000610d02856103d07f0000000000000000000000000000000000000000000000000000000000000000600f0b856106b1565b9050610d0e8189612a15565b975082610d2a600080516020612d1a833981519152878c61182c565b15610d5457610d4386610d3d8486612a2d565b8c611869565b610d4d8282612a15565b9050610d7d565b610d7086610d618c610e13565b610d6b8587612a2d565b610e67565b610d7a8382612a15565b90505b610d97600080516020612d1a833981519152878c8461192c565b610da2868c876108cb565b6001600160a01b0386167f69a2ef6bf9e7ff92cbf1b71963ba1751b1abe8f99e3b3aae2ab99e416df614938c610dd88587612a2d565b60408051928352602083019190915281018890526060810185905260800160405180910390a2505050505050610c13565b5050949350505050565b600081610e40577f00000000000000000000000000000000000000000000000000000000000000006104d8565b7f000000000000000000000000000000000000000000000000000000000000000092915050565b61010483838360405180602001604052806000815250611a6c565b60006011830181610e95610e1085612a5a565b8152602081019190915260400160002054600f0b9392505050565b6000808260030160009054906101000a90046001600160a01b03166001600160a01b03166350d25bcd6040518163ffffffff1660e01b815260040160206040518083038186803b158015610f0357600080fd5b505afa158015610f17573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f3b9190612ad8565b905060008360020160009054906101000a90046001600160a01b03166001600160a01b03166350d25bcd6040518163ffffffff1660e01b815260040160206040518083038186803b158015610f8f57600080fd5b505afa158015610fa3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fc79190612ad8565b90506101578282611b93565b6000610fe1610e1084612a5a565b6000818152601186016020526040902080546001600160801b0319166001600160801b038516179055905061101a60ff80831690612a2d565b6001901b846012016000600884901c815260200190815260200160002060008282546110469190612a15565b909155505050505050565b80151560009081526013830160205260409020805415806110725750805442105b1561107c57505050565b60006110888484611c2e565b90506110c384826110bd6110b286600101546110ad898b611c9890919063ffffffff16565b6110e1565b600f86900b90611cc6565b86611cf9565b50501515600090815260139091016020526040812081815560010155565b6000610652836110f284600a612bd5565b611d76565b600061065261110783600a612bd5565b600f85900b906106b1565b60006104d8825490565b60006106528383611dad565b60006001600160a01b0383166111945760405162461bcd60e51b815260206004820152602b60248201527f455243313135353a2062616c616e636520717565727920666f7220746865207a60448201526a65726f206164647265737360a81b60648201526084016100f0565b7f1799cf914cb0cb442ca7c7ac709ee40d0cb89e87351dc08d517fbda27d50c68b6000928352602090815260408084206001600160a01b0395909516845293905250205490565b6040805160018082528183019092526060916000919060208083019080368337019050509050828160008151811061121557611215612be4565b602090810291909101015292915050565b611234868686868686611e33565b600080516020612d1a83398151915260005b845181101561175857600085828151811061126357611263612be4565b60200260200101519050600085838151811061128157611281612be4565b60200260200101519050806000141561129b575050611746565b6001600160a01b0389166112b8576112b66015850183612011565b505b6001600160a01b0388161580156112e857506000828152600080516020612cfa8339815191526020526040902054155b156112fc576112fa601585018361201d565b505b7f000000000000000000000000000000000000000000000000000000000000000082148061134957507f000000000000000000000000000000000000000000000000000000000000000082145b8061137357507f000000000000000000000000000000000000000000000000000000000000000082145b8061139d57507f000000000000000000000000000000000000000000000000000000000000000082145b1561148d576001600160a01b038916158015906113c257506001600160a01b03881615155b1561148d5760007f000000000000000000000000000000000000000000000000000000000000000083148061141657507f000000000000000000000000000000000000000000000000000000000000000083145b6001600160a01b038b166000908152600d870160209081526040808320841515845290915290205490915042906114509062015180612a15565b1061148b5760405162461bcd60e51b815260206004820152600b60248201526a1b1a5c481b1bd8dac80c5960aa1b60448201526064016100f0565b505b7f00000000000000000000000000000000000000000000000000000000000000008214806114da57507f000000000000000000000000000000000000000000000000000000000000000082145b15611682577f00000000000000000000000000000000000000000000000000000000000000008214600061150e8683612029565b90506001600160a01b038b161561163857600061152b8c86611128565b9050818111801561154557506115418285612a15565b8111155b156115dd576001600160a01b038c166000908152601488016020908152604080832086151580855260138c01845282852054855290835281842090845290915290205484906115949083612a2d565b10156115d25760405162461bcd60e51b815260206004820152600d60248201526c496e7375662062616c616e636560981b60448201526064016100f0565b6115dd878d85612043565b6001600160a01b038b161561163657611611878d858c8a8151811061160457611604612be4565b602002602001015161192c565b611636878c858c8a8151811061162957611629612be4565b60200260200101516120f4565b505b6001600160a01b038a161561167f5760006116538b86611128565b905081811115801561166d57508161166b8583612a15565b115b1561167d5761167d878c85612218565b505b50505b60f882901c826001600160a01b038b16158015906116a857506001600160a01b038a1615155b80156116e0575060058260078111156116c3576116c36129e9565b14806116e0575060078260078111156116de576116de6129e9565b145b1561174157600060058360078111156116fb576116fb6129e9565b1490506000816117225761171d611716600f85900b876106b1565b8990610719565b611724565b845b9050611732888e848461192c565b61173e888d84846120f4565b50505b505050505b8061175081612a7c565b915050611246565b5050505050505050565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031615610521576040516303793c8d60e11b81526001600160a01b0383811660048301527f000000000000000000000000000000000000000000000000000000000000000016906306f2791a9060240160206040518083038186803b1580156117f457600080fd5b505afa158015611808573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104d89190612ad8565b6001600160a01b0382166000908152600e840160209081526040808320841515845290915281205480158061186057504281115b95945050505050565b600080516020612d1a83398151915261188b84611885846122c0565b85610e67565b60006101048061189b8142612a5a565b6118a59190612a97565b6118af9190612a15565b6001600160a01b03861660009081526014840160209081526040808320848452825280832087151584529091528120805492935086929091906118f3908490612a15565b90915550508215156000908152601383016020526040812060018101805491928792611920908490612a15565b90915550505550505050565b6001600160a01b03808416600090815260178601602090815260408083208615158452825280832054601889019092529091205490917f00000000000000000000000000000000000000000000000000000000000000001663edaf7d5b863087866119978982612a2d565b6040516001600160e01b031960e088901b1681526001600160a01b03958616600482015294909316602485015290151560448401526064830152608482015260a4810184905260c401600060405180830381600087803b1580156119fa57600080fd5b505af1158015611a0e573d6000803e3d6000fd5b505050508282611a1e9190612a2d565b6001600160a01b038616600090815260178801602090815260408083208815158452909152902055611a508382612a2d565b9315156000908152601890960160205250506040909320555050565b6001600160a01b038416611acc5760405162461bcd60e51b815260206004820152602160248201527f455243313135353a206d696e7420746f20746865207a65726f206164647265736044820152607360f81b60648201526084016100f0565b611aeb33600086611adc876111db565b611ae5876111db565b86611226565b60008381527f1799cf914cb0cb442ca7c7ac709ee40d0cb89e87351dc08d517fbda27d50c68b602090815260408083206001600160a01b0388168452918290528220805491928592611b3e908490612a15565b909155505060408051858152602081018590526001600160a01b0387169160009133917fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62910160405180910390a45050505050565b600081611b9f57600080fd5b600080841215611bb457836000039350600190505b6000831215611bc65760009290920391155b6000611bd28585612314565b90508115611c00576001607f1b816001600160801b03161115611bf457600080fd5b60000391506104d89050565b60016001607f1b03816001600160801b03161115611c1d57600080fd5b91506104d89050565b505092915050565b600080611c4b83611c40576001611c43565b60005b600080610119565b831515600090815260138601602052604090206001015490915061015790600080516020612cfa83398151915260008481526020919091526040902054611c929190612a2d565b6110ad86865b600081611cb3576003830154600160a81b900460ff16610652565b505060030154600160a01b900460ff1690565b6000600f83810b9083900b0160016001607f1b03198112801590610649575060016001607f1b0381131561065257600080fd5b6000611d058583612476565b90506000611d16868387878761248f565b9050611d23868285612595565b60408051600f83810b825287810b602083015286900b818301529051841515917f4e23621c6f591f14bf9505cb8326b45af9dc6c5569fd608de2a7a2ddd6146b2e919081900360600190a2505050505050565b600081611d8257600080fd5b6000611d8e8484612314565b905060016001607f1b036001600160801b038216111561065257600080fd5b81546000908210611e0b5760405162461bcd60e51b815260206004820152602260248201527f456e756d657261626c655365743a20696e646578206f7574206f6620626f756e604482015261647360f01b60648201526084016100f0565b826000018281548110611e2057611e20612be4565b9060005260206000200154905092915050565b836001600160a01b0316856001600160a01b031614612009576001600160a01b0385811660009081527fb31c2c74f86ca3ce94d901f5f5bbe66f7161eec2f7b5aa0b75a86371436424ec602052604080822092871682528120600080516020612cfa833981519152927fb31c2c74f86ca3ce94d901f5f5bbe66f7161eec2f7b5aa0b75a86371436424eb929091905b87518110156104b3576000878281518110611edf57611edf612be4565b602002602001015190506000811115611ff6576000898381518110611f0657611f06612be4565b6020026020010151905060006001600160a01b03168c6001600160a01b03161415611f545760008181526020889052604081208054849290611f49908490612a15565b90915550611f8a9050565b81611f5f8d83611128565b1415611f8a576000818152602087905260409020611f7d908d6125ec565b50611f88858261201d565b505b6001600160a01b038b16611fc15760008181526020889052604081208054849290611fb6908490612a2d565b90915550611ff49050565b611fcb8b82611128565b611ff4576000818152602087905260409020611fe7908c612601565b50611ff28482612011565b505b505b508061200181612a7c565b915050611ec2565b505050505050565b60006106528383612612565b60006106528383612661565b60008161203a578260040154610652565b50506005015490565b6001600160a01b03821661205657600080fd5b8015156000908152600f8401602090815260408083206010870190925290912061208184838361274c565b61208c575050505050565b6001600160a01b0393841660008181526020838152604080832080549683528184208054978a16808652838620805499909b166001600160a01b0319998a168117909b5599855295909252822080548616909717909655528054821690558254169091555050565b6001600160a01b03808416600090815260178601602090815260408083208615158452825280832054601889019092529091205490917f00000000000000000000000000000000000000000000000000000000000000001663edaf7d5b8630878661215f8982612a15565b6040516001600160e01b031960e088901b1681526001600160a01b03958616600482015294909316602485015290151560448401526064830152608482015260a4810184905260c401600060405180830381600087803b1580156121c257600080fd5b505af11580156121d6573d6000803e3d6000fd5b5050505082826121e69190612a15565b6001600160a01b038616600090815260178801602090815260408083208815158452909152902055611a508382612a15565b6001600160a01b03821661222b57600080fd5b8015156000908152600f8401602090815260408083206010870190925290912061225684838361274c565b15612262575050505050565b60008080526020828152604080832080546001600160a01b0390811680865296845282852080546001600160a01b03199081169a909216998a1790558885529490925282208054841690941790935580528154169092179091555050565b6000816122ed577f00000000000000000000000000000000000000000000000000000000000000006104d8565b7f000000000000000000000000000000000000000000000000000000000000000092915050565b60008161232057600080fd5b60006001600160c01b03841161234b5782604085901b8161234357612343612a44565b049050612462565b60c084811c6401000000008110612364576020918201911c5b620100008110612376576010918201911c5b6101008110612387576008918201911c5b60108110612397576004918201911c5b600481106123a7576002918201911c5b600281106123b6576001820191505b60bf820360018603901c6001018260ff0387901b816123d7576123d7612a44565b0492506001600160801b038311156123ee57600080fd5b608085901c83026001600160801b038616840260c088901c604089901b8281101561241a576001820391505b608084901b92900382811015612431576001820391505b829003608084901c821461244757612447612bfa565b88818161245657612456612a44565b04870196505050505050505b6001600160801b0381111561065257600080fd5b60006124828383612798565b90506106528382846127bf565b600080826124a4576019870154600f0b6124b4565b6019870154600160801b9004600f0b5b905080600f0b600014156124cc57506008860154600f0b5b60405163e101a89b60e01b8152600f87810b600483015286810b602483015285810b604483015282900b6064820152730f6e8ef18fb5bb61d545fee60f779d8aed60408f9063e101a89b9060840160206040518083038186803b15801561253257600080fd5b505af4158015612546573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061256a9190612c10565b915067b33333333333333382600f0b121561258b5767b33333333333333391505b5095945050505050565b80156125c5576009830180546001600160801b0384166001600160801b031990911617905542600b840155505050565b6008830180546001600160801b03808516600160801b02911617905542600a840155505050565b6000610652836001600160a01b038416612661565b6000610652836001600160a01b0384165b6000818152600183016020526040812054612659575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556104d8565b5060006104d8565b60008181526001830160205260408120548015612742576000612685600183612a2d565b8554909150600090869061269b90600190612a2d565b815481106126ab576126ab612be4565b90600052602060002001549050808660000183815481106126ce576126ce612be4565b6000918252602090912001556126e5826001612a15565b6000828152600188016020526040902055855486908061270757612707612c33565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506104d8565b60009150506104d8565b6001600160a01b0383811660009081526020849052604081205490911615158061015757506000808052602083905260409020546001600160a01b039081169085161490509392505050565b6000816127b3576008830154600160801b9004600f0b610652565b505060090154600f0b90565b600080826127d15784600a01546127d7565b84600b01545b6127e19042612a2d565b905061a8c0811115612800576127f961a8c082612a2d565b9050612809565b83915050610652565b600061281782613840611d76565b9050600061282a85611c40576001611c43565b851515600090815260188901602090815260408083205460138c01835281842060010154858552600080516020612cfa83398151915290935290832054939450926128889161287891612a2d565b6128829084612a2d565b83611d76565b6040805161012081018252600f87810b82528b810b602083015283900b8183015267b333333333333333606082015267e666666666666666608082018190526801000000000000000060a0830181905260c083015260e082015268056fc2a2c515da32ea6101008201529051634916d70d60e01b8152919250730f6e8ef18fb5bb61d545fee60f779d8aed60408f91634916d70d9161292991600401612c49565b60206040518083038186803b15801561294157600080fd5b505af4158015612955573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129799190612c10565b9998505050505050505050565b60008060006060848603121561299b57600080fd5b83356001600160a01b03811681146129b257600080fd5b95602085013595506040909401359392505050565b600080604083850312156129da57600080fd5b50508035926020909101359150565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601160045260246000fd5b60008219821115612a2857612a286129ff565b500190565b600082821015612a3f57612a3f6129ff565b500390565b634e487b7160e01b600052601260045260246000fd5b600082612a7757634e487b7160e01b600052601260045260246000fd5b500490565b6000600019821415612a9057612a906129ff565b5060010190565b6000816000190483118215151615612ab157612ab16129ff565b500290565b600060208284031215612ac857600080fd5b8151801515811461065257600080fd5b600060208284031215612aea57600080fd5b5051919050565b600181815b80851115612b2c578160001904821115612b1257612b126129ff565b80851615612b1f57918102915b93841c9390800290612af6565b509250929050565b600082612b43575060016104d8565b81612b50575060006104d8565b8160018114612b665760028114612b7057612b8c565b60019150506104d8565b60ff841115612b8157612b816129ff565b50506001821b6104d8565b5060208310610133831016604e8410600b8410161715612baf575081810a6104d8565b612bb98383612af1565b8060001904821115612bcd57612bcd6129ff565b029392505050565b600061065260ff841683612b34565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052600160045260246000fd5b600060208284031215612c2257600080fd5b815180600f0b811461065257600080fd5b634e487b7160e01b600052603160045260246000fd5b6000610120820190508251600f0b82526020830151600f0b60208301526040830151612c7a6040840182600f0b9052565b506060830151612c8f6060840182600f0b9052565b506080830151612ca46080840182600f0b9052565b5060a0830151612cb960a0840182600f0b9052565b5060c0830151612cce60c0840182600f0b9052565b5060e0830151612ce360e0840182600f0b9052565b5061010080840151611c2682850182600f0b905256feb31c2c74f86ca3ce94d901f5f5bbe66f7161eec2f7b5aa0b75a86371436424eabbd6af8edd89d04327b00c29df7f272b9b1ae01bf6d9c54a784f935706df52eb\",\n        ),\n        (\n            \"0x71356E37e0368Bd10bFDbF41dC052fE5FA24cD05\",\n            \"MainchainGatewayV2\",\n            \"608060405234801561001057600080fd5b506000805460ff1916905561582e806200002b6000396000f3fe60806040526004361061032d5760003560e01c80639157921c116101a5578063b2975794116100ec578063d547741f11610095578063dafae4081161006f578063dafae4081461096e578063dff525e11461098e578063e400327c146109ae578063e75235b8146109ce5761033c565b8063d547741f14610901578063d55ed10314610921578063d64af2a61461094e5761033c565b8063cdb67444116100c6578063cdb674441461089c578063cdf64a76146108b4578063d19773d2146108d45761033c565b8063b29757941461082f578063b9c362091461085c578063ca15c8731461087c5761033c565b8063a3912ec81161014e578063affed0e011610128578063affed0e0146107cc578063b1a2567e146107e2578063b1d08a03146108025761033c565b8063a3912ec81461033a578063ab7965661461077f578063ac78dfe8146107ac5761033c565b8063994390891161017f57806399439089146107155780639dcc4da314610735578063a217fddf1461076a5761033c565b80639157921c1461068f57806391d14854146106af57806393c5678f146106f55761033c565b806336568abe116102745780635c975abb1161021d5780637de5dedd116101f75780637de5dedd146106115780638456cb59146106265780638f34e3471461063b5780639010d07c1461066f5761033c565b80635c975abb146105ac5780636932be98146105c45780636c1ce670146105f15761033c565b80634d0d66731161024e5780634d0d66731461052f5780634d493f4e1461054f57806359122f6b1461057f5761033c565b806336568abe146104e75780633f4ba83a146105075780634b14557e1461051c5761033c565b80631d4a7210116102d65780632f2ff15d116102b05780632f2ff15d1461049b578063302d12db146104bb5780633644e515146104d25761033c565b80631d4a721014610428578063248a9ca3146104555780632dfdf0b5146104855761033c565b8063180ff1e911610307578063180ff1e9146103d55780631a8e55b0146103e85780631b6e7594146104085761033c565b806301ffc9a71461034457806317ce2dd41461037957806317fcb39b1461039d5761033c565b3661033c5761033a6109e6565b005b61033a6109e6565b34801561035057600080fd5b5061036461035f366004614843565b610a69565b60405190151581526020015b60405180910390f35b34801561038557600080fd5b5061038f60755481565b604051908152602001610370565b3480156103a957600080fd5b506074546103bd906001600160a01b031681565b6040516001600160a01b039091168152602001610370565b61033a6103e33660046148f4565b610aad565b3480156103f457600080fd5b5061033a6104033660046149e6565b610dbd565b34801561041457600080fd5b5061033a610423366004614a52565b610e8f565b34801561043457600080fd5b5061038f610443366004614aec565b603e6020526000908152604090205481565b34801561046157600080fd5b5061038f610470366004614b09565b60009081526072602052604090206001015490565b34801561049157600080fd5b5061038f60765481565b3480156104a757600080fd5b5061033a6104b6366004614b22565b610f64565b3480156104c757600080fd5b5061038f620f424081565b3480156104de57600080fd5b5060775461038f565b3480156104f357600080fd5b5061033a610502366004614b22565b610f8f565b34801561051357600080fd5b5061033a61101b565b61033a61052a366004614b52565b611083565b34801561053b57600080fd5b5061036461054a366004614b7d565b6110e1565b34801561055b57600080fd5b5061036461056a366004614b09565b607a6020526000908152604090205460ff1681565b34801561058b57600080fd5b5061038f61059a366004614aec565b603a6020526000908152604090205481565b3480156105b857600080fd5b5060005460ff16610364565b3480156105d057600080fd5b5061038f6105df366004614b09565b60796020526000908152604090205481565b3480156105fd57600080fd5b5061036461060c366004614c06565b61118c565b34801561061d57600080fd5b5061038f61119f565b34801561063257600080fd5b5061033a611234565b34801561064757600080fd5b5061038f7f5e5712e902fff5e704bc4d506ad976718319e019e9d2a872528a01a85db433e481565b34801561067b57600080fd5b506103bd61068a366004614c32565b61129c565b34801561069b57600080fd5b5061033a6106aa366004614c54565b6112b4565b3480156106bb57600080fd5b506103646106ca366004614b22565b60009182526072602090815260408084206001600160a01b0393909316845291905290205460ff1690565b34801561070157600080fd5b5061033a6107103660046149e6565b6115ca565b34801561072157600080fd5b506003546103bd906001600160a01b031681565b34801561074157600080fd5b50610755610750366004614c32565b611696565b60408051928352602083019190915201610370565b34801561077657600080fd5b5061038f600081565b34801561078b57600080fd5b5061038f61079a366004614aec565b603c6020526000908152604090205481565b3480156107b857600080fd5b506103646107c7366004614b09565b61172f565b3480156107d857600080fd5b5061038f60045481565b3480156107ee57600080fd5b5061033a6107fd3660046149e6565b6117ce565b34801561080e57600080fd5b5061038f61081d366004614aec565b60396020526000908152604090205481565b34801561083b57600080fd5b5061084f61084a366004614aec565b61189a565b6040516103709190614ca5565b34801561086857600080fd5b50610755610877366004614c32565b611992565b34801561088857600080fd5b5061038f610897366004614b09565b611a17565b3480156108a857600080fd5b50603754603854610755565b3480156108c057600080fd5b5061033a6108cf366004614aec565b611a2e565b3480156108e057600080fd5b5061038f6108ef366004614aec565b603b6020526000908152604090205481565b34801561090d57600080fd5b5061033a61091c366004614b22565b611a97565b34801561092d57600080fd5b5061038f61093c366004614aec565b603d6020526000908152604090205481565b34801561095a57600080fd5b5061033a610969366004614aec565b611abd565b34801561097a57600080fd5b50610364610989366004614b09565b611b26565b34801561099a57600080fd5b5061033a6109a9366004614cd2565b611bbd565b3480156109ba57600080fd5b5061033a6109c93660046149e6565b611cc7565b3480156109da57600080fd5b50600154600254610755565b60005460ff1615610a315760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064015b60405180910390fd5b6074546001600160a01b03163314610a6757610a4b614802565b338152604080820151349101528051610a65908290611d93565b505b565b60006001600160e01b031982167f5a05180f000000000000000000000000000000000000000000000000000000001480610aa75750610aa78261210a565b92915050565b607154610100900460ff16610ac85760715460ff1615610acc565b303b155b610b3e5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610a28565b607154610100900460ff16158015610b60576071805461ffff19166101011790555b610b6b60008d612171565b6075899055610b798b61217b565b610b828a6121dd565b610c29604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527f159f52c1e3a2b6a6aad3950adf713516211484e0516dad685ea662a094b7c43b918101919091527fad7c5bef027816a800da1736444fb58a807ef4c9603b7848673f7e3a68eb14a560608201524660808201523060a082015260c00160408051601f198184030181529190528051602090910120607755565b610c338887612238565b5050610c3f87876122f8565b5050610c496123d3565b6000610c558680614da6565b90501115610d1657610c7e610c6a8680614da6565b610c776020890189614da6565b8787612467565b610ca4610c8b8680614da6565b8660005b602002810190610c9f9190614da6565b612666565b610cca610cb18680614da6565b8660015b602002810190610cc59190614da6565b612779565b610cf0610cd78680614da6565b8660025b602002810190610ceb9190614da6565b61288c565b610d16610cfd8680614da6565b8660035b602002810190610d119190614da6565b612a30565b60005b610d266040870187614da6565b9050811015610d9c57610d8a7f5e5712e902fff5e704bc4d506ad976718319e019e9d2a872528a01a85db433e4610d606040890189614da6565b84818110610d7057610d70614d90565b9050602002016020810190610d859190614aec565b612b43565b80610d9481614e06565b915050610d19565b508015610daf576071805461ff00191690555b505050505050505050505050565b6000805160206157b9833981519152546001600160a01b03163314610e1d5760405162461bcd60e51b815260206004820152602260248201526000805160206157d983398151915260448201526132b960f11b6064820152608401610a28565b82610e7d5760405162461bcd60e51b815260206004820152602a60248201527f5769746864726177616c4c696d69746174696f6e3a20696e76616c69642061726044820152690e4c2f240d8cadccee8d60b31b6064820152608401610a28565b610e8984848484612779565b50505050565b6000805160206157b9833981519152546001600160a01b03163314610eef5760405162461bcd60e51b815260206004820152602260248201526000805160206157d983398151915260448201526132b960f11b6064820152608401610a28565b84610f4e5760405162461bcd60e51b815260206004820152602960248201527f4d61696e636861696e4761746577617956323a20717565727920666f7220656d60448201526870747920617272617960b81b6064820152608401610a28565b610f5c868686868686612467565b505050505050565b600082815260726020526040902060010154610f808133612b65565b610f8a8383612b43565b505050565b6001600160a01b038116331461100d5760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201527f20726f6c657320666f722073656c6600000000000000000000000000000000006064820152608401610a28565b6110178282612be5565b5050565b6000805160206157b9833981519152546001600160a01b0316331461107b5760405162461bcd60e51b815260206004820152602260248201526000805160206157d983398151915260448201526132b960f11b6064820152608401610a28565b610a67612c07565b60005460ff16156110c95760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610a28565b610a656110db36839003830183614ec0565b33611d93565b6000805460ff16156111285760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610a28565b611184848484808060200260200160405190810160405280939291908181526020016000905b8282101561117a5761116b60608302860136819003810190614f13565b8152602001906001019061114e565b5050505050612ca3565b949350505050565b600061119883836133bc565b9392505050565b600061122f600360009054906101000a90046001600160a01b03166001600160a01b031663926323d56040518163ffffffff1660e01b815260040160206040518083038186803b1580156111f257600080fd5b505afa158015611206573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061122a9190614f89565b613480565b905090565b6000805160206157b9833981519152546001600160a01b031633146112945760405162461bcd60e51b815260206004820152602260248201526000805160206157d983398151915260448201526132b960f11b6064820152608401610a28565b610a676134b6565b60008281526073602052604081206111989083613531565b7f5e5712e902fff5e704bc4d506ad976718319e019e9d2a872528a01a85db433e46112df8133612b65565b60006112f86112f336859003850185614ff0565b61353d565b905061130c6112f336859003850185614ff0565b8335600090815260796020526040902054146113765760405162461bcd60e51b815260206004820152602360248201527f4d61696e636861696e4761746577617956323a20696e76616c696420726563656044820152621a5c1d60ea1b6064820152608401610a28565b82356000908152607a602052604090205460ff166113fc5760405162461bcd60e51b815260206004820152603160248201527f4d61696e636861696e4761746577617956323a20717565727920666f7220617060448201527f70726f766564207769746864726177616c0000000000000000000000000000006064820152608401610a28565b82356000908152607a602052604090819020805460ff19169055517fd639511b37b3b002cca6cfe6bca0d833945a5af5a045578a0627fc43b79b26309061144690839086906150c4565b60405180910390a160006114606080850160608601614aec565b9050600061147661012086016101008701615151565b600181111561148757611487614c71565b141561154f5760006114a2368690038601610100870161516e565b6001600160a01b0383166000908152603b60205260409020549091506114ce90610140870135906135c6565b604082015260006114e8368790038701610100880161516e565b60408301519091506114ff9061014088013561518a565b604082015260745461151f908390339086906001600160a01b03166135e0565b6115486115326060880160408901614aec565b60745483919086906001600160a01b03166135e0565b505061158b565b61158b6115626060860160408701614aec565b60745483906001600160a01b03166115833689900389016101008a0161516e565b9291906135e0565b7f21e88e956aa3e086f6388e899965cef814688f99ad8bb29b08d396571016372d82856040516115bc9291906150c4565b60405180910390a150505050565b6000805160206157b9833981519152546001600160a01b0316331461162a5760405162461bcd60e51b815260206004820152602260248201526000805160206157d983398151915260448201526132b960f11b6064820152608401610a28565b8261168a5760405162461bcd60e51b815260206004820152602a60248201527f5769746864726177616c4c696d69746174696f6e3a20696e76616c69642061726044820152690e4c2f240d8cadccee8d60b31b6064820152608401610a28565b610e8984848484612666565b6000806116b86000805160206157b9833981519152546001600160a01b031690565b6001600160a01b0316336001600160a01b0316146117115760405162461bcd60e51b815260206004820152602260248201526000805160206157d983398151915260448201526132b960f11b6064820152608401610a28565b61171b84846122f8565b90925090506117286123d3565b9250929050565b6003546040805163926323d560e01b815290516000926001600160a01b03169163926323d5916004808301926020929190829003018186803b15801561177457600080fd5b505afa158015611788573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117ac9190614f89565b6037546117b991906151a1565b6038546117c690846151a1565b101592915050565b6000805160206157b9833981519152546001600160a01b0316331461182e5760405162461bcd60e51b815260206004820152602260248201526000805160206157d983398151915260448201526132b960f11b6064820152608401610a28565b8261188e5760405162461bcd60e51b815260206004820152602a60248201527f5769746864726177616c4c696d69746174696f6e3a20696e76616c69642061726044820152690e4c2f240d8cadccee8d60b31b6064820152608401610a28565b610e898484848461288c565b60408051808201909152600080825260208201526001600160a01b0382166000908152607860205260409081902081518083019092528054829060ff1660018111156118e8576118e8614c71565b60018111156118f9576118f9614c71565b815290546001600160a01b036101009091048116602092830152908201519192501661198d5760405162461bcd60e51b815260206004820152602560248201527f4d61696e636861696e4761746577617956323a20756e737570706f727465642060448201527f746f6b656e0000000000000000000000000000000000000000000000000000006064820152608401610a28565b919050565b6000806119b46000805160206157b9833981519152546001600160a01b031690565b6001600160a01b0316336001600160a01b031614611a0d5760405162461bcd60e51b815260206004820152602260248201526000805160206157d983398151915260448201526132b960f11b6064820152608401610a28565b61171b8484612238565b6000818152607360205260408120610aa790613a13565b6000805160206157b9833981519152546001600160a01b03163314611a8e5760405162461bcd60e51b815260206004820152602260248201526000805160206157d983398151915260448201526132b960f11b6064820152608401610a28565b610a65816121dd565b600082815260726020526040902060010154611ab38133612b65565b610f8a8383612be5565b6000805160206157b9833981519152546001600160a01b03163314611b1d5760405162461bcd60e51b815260206004820152602260248201526000805160206157d983398151915260448201526132b960f11b6064820152608401610a28565b610a658161217b565b6003546040805163926323d560e01b815290516000926001600160a01b03169163926323d5916004808301926020929190829003018186803b158015611b6b57600080fd5b505afa158015611b7f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ba39190614f89565b600154611bb091906151a1565b6002546117c690846151a1565b6000805160206157b9833981519152546001600160a01b03163314611c1d5760405162461bcd60e51b815260206004820152602260248201526000805160206157d983398151915260448201526132b960f11b6064820152608401610a28565b85611c7c5760405162461bcd60e51b815260206004820152602960248201527f4d61696e636861696e4761746577617956323a20717565727920666f7220656d60448201526870747920617272617960b81b6064820152608401610a28565b611c8a878787878787612467565b611c978787836000610c8f565b611ca48787836001610cb5565b611cb18787836002610cdb565b611cbe8787836003610d01565b50505050505050565b6000805160206157b9833981519152546001600160a01b03163314611d275760405162461bcd60e51b815260206004820152602260248201526000805160206157d983398151915260448201526132b960f11b6064820152608401610a28565b82611d875760405162461bcd60e51b815260206004820152602a60248201527f5769746864726177616c4c696d69746174696f6e3a20696e76616c69642061726044820152690e4c2f240d8cadccee8d60b31b6064820152608401610a28565b610e8984848484612a30565b604080518082018252600080825260208201526074549184015190916001600160a01b031690611dc290613a1d565b60208401516001600160a01b0316611ee1573484604001516040015114611e375760405162461bcd60e51b815260206004820152602360248201527f4d61696e636861696e4761746577617956323a20696e76616c69642072657175604482015262195cdd60ea1b6064820152608401610a28565b611e408161189a565b6040850151519092506001811115611e5a57611e5a614c71565b82516001811115611e6d57611e6d614c71565b14611ecd5760405162461bcd60e51b815260206004820152602a60248201527f4d61696e636861696e4761746577617956323a20696e76616c696420746f6b656044820152691b881cdd185b99185c9960b21b6064820152608401610a28565b6001600160a01b0381166020850152612087565b3415611f3b5760405162461bcd60e51b815260206004820152602360248201527f4d61696e636861696e4761746577617956323a20696e76616c69642072657175604482015262195cdd60ea1b6064820152608401610a28565b611f48846020015161189a565b6040850151519092506001811115611f6257611f62614c71565b82516001811115611f7557611f75614c71565b14611fd55760405162461bcd60e51b815260206004820152602a60248201527f4d61696e636861696e4761746577617956323a20696e76616c696420746f6b656044820152691b881cdd185b99185c9960b21b6064820152608401610a28565b60208401516040850151611fec9185903090613ac7565b83602001516001600160a01b0316816001600160a01b031614156120875760408481015181015190517f2e1a7d4d00000000000000000000000000000000000000000000000000000000815260048101919091526001600160a01b03821690632e1a7d4d90602401600060405180830381600087803b15801561206e57600080fd5b505af1158015612082573d6000803e3d6000fd5b505050505b607680546000918261209883614e06565b91905055905060006120bf858386602001516075548a613ce190949392919063ffffffff16565b90507fd7b25068d9dc8d00765254cfb7f5070f98d263c8d68931d937c7362fa738048b6120eb8261353d565b826040516120fa9291906151c0565b60405180910390a1505050505050565b60006001600160e01b031982167f7965db0b000000000000000000000000000000000000000000000000000000001480610aa757507f01ffc9a7000000000000000000000000000000000000000000000000000000006001600160e01b0319831614610aa7565b6110178282612b43565b6074805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0383169081179091556040519081527f9d2334c23be647e994f27a72c5eee42a43d5bdcfe15bb88e939103c2b114cbaf906020015b60405180910390a150565b6003805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0383169081179091556040519081527fef40dc07567635f84f5edbd2f8dbc16b40d9d282dd8e7e6f4ff58236b6836169906020016121d2565b6000808284111561228b5760405162461bcd60e51b815260206004820152601c60248201527f4761746577617956323a20696e76616c6964207468726573686f6c64000000006044820152606401610a28565b505060018054600280549285905583905560048054919291849186919060006122b383614e06565b9091555060408051868152602081018690527f976f8a9c5bdf8248dec172376d6e2b80a8e3df2f0328e381c6db8e1cf138c0f891015b60405180910390a49250929050565b600080828411156123715760405162461bcd60e51b815260206004820152602760248201527f5769746864726177616c4c696d69746174696f6e3a20696e76616c696420746860448201527f726573686f6c64000000000000000000000000000000000000000000000000006064820152608401610a28565b5050603780546038805492859055839055600480549192918491869190600061239983614e06565b9091555060408051868152602081018690527f31312c97b89cc751b832d98fd459b967a2c3eef3b49757d1cf5ebaa12bb6eee191016122e9565b6002546037546123e391906151a1565b6038546001546123f391906151a1565b1115610a675760405162461bcd60e51b815260206004820152602860248201527f5769746864726177616c4c696d69746174696f6e3a20696e76616c696420746860448201527f726573686f6c64730000000000000000000000000000000000000000000000006064820152608401610a28565b848314801561247557508481145b6124e75760405162461bcd60e51b815260206004820152602860248201527f4d61696e636861696e4761746577617956323a20696e76616c6964206172726160448201527f79206c656e6774680000000000000000000000000000000000000000000000006064820152608401610a28565b60005b8581101561262c5784848281811061250457612504614d90565b90506020020160208101906125199190614aec565b6078600089898581811061252f5761252f614d90565b90506020020160208101906125449190614aec565b6001600160a01b039081168252602082019290925260400160002080547fffffffffffffffffffffff0000000000000000000000000000000000000000ff1661010093909216929092021790558282828181106125a3576125a3614d90565b90506020020160208101906125b89190615151565b607860008989858181106125ce576125ce614d90565b90506020020160208101906125e39190614aec565b6001600160a01b031681526020810191909152604001600020805460ff19166001838181111561261557612615614c71565b02179055508061262481614e06565b9150506124ea565b507fa4f03cc9c0e0aeb5b71b4ec800702753f65748c2cf3064695ba8e8b46be704448686868686866040516120fa969594939291906152c1565b8281146126c85760405162461bcd60e51b815260206004820152602a60248201527f5769746864726177616c4c696d69746174696f6e3a20696e76616c69642061726044820152690e4c2f240d8cadccee8d60b31b6064820152608401610a28565b60005b83811015612743578282828181106126e5576126e5614d90565b905060200201356039600087878581811061270257612702614d90565b90506020020160208101906127179190614aec565b6001600160a01b031681526020810191909152604001600020558061273b81614e06565b9150506126cb565b507f80bc635c452ae67f12f9b6f12ad4daa6dbbc04eeb9ebb87d354ce10c0e210dc0848484846040516115bc9493929190615339565b8281146127db5760405162461bcd60e51b815260206004820152602a60248201527f5769746864726177616c4c696d69746174696f6e3a20696e76616c69642061726044820152690e4c2f240d8cadccee8d60b31b6064820152608401610a28565b60005b83811015612856578282828181106127f8576127f8614d90565b90506020020135603a600087878581811061281557612815614d90565b905060200201602081019061282a9190614aec565b6001600160a01b031681526020810191909152604001600020558061284e81614e06565b9150506127de565b507f64557254143204d91ba2d95acb9fda1e5fea55f77efd028685765bc1e94dd4b5848484846040516115bc9493929190615339565b8281146128ee5760405162461bcd60e51b815260206004820152602a60248201527f5769746864726177616c4c696d69746174696f6e3a20696e76616c69642061726044820152690e4c2f240d8cadccee8d60b31b6064820152608401610a28565b60005b838110156129fa57620f424083838381811061290f5761290f614d90565b90506020020135111561298a5760405162461bcd60e51b815260206004820152602860248201527f5769746864726177616c4c696d69746174696f6e3a20696e76616c696420706560448201527f7263656e746167650000000000000000000000000000000000000000000000006064820152608401610a28565b82828281811061299c5761299c614d90565b90506020020135603b60008787858181106129b9576129b9614d90565b90506020020160208101906129ce9190614aec565b6001600160a01b03168152602081019190915260400160002055806129f281614e06565b9150506128f1565b507fb05f5de88ae0294ebb6f67c5af2fcbbd593cc6bdfe543e2869794a4c8ce3ea50848484846040516115bc9493929190615339565b828114612a925760405162461bcd60e51b815260206004820152602a60248201527f5769746864726177616c4c696d69746174696f6e3a20696e76616c69642061726044820152690e4c2f240d8cadccee8d60b31b6064820152608401610a28565b60005b83811015612b0d57828282818110612aaf57612aaf614d90565b90506020020135603c6000878785818110612acc57612acc614d90565b9050602002016020810190612ae19190614aec565b6001600160a01b0316815260208101919091526040016000205580612b0581614e06565b915050612a95565b507fb5d2963614d72181b4df1f993d45b83edf42fa19710f0204217ba1b3e183bb73848484846040516115bc9493929190615339565b612b4d8282613db6565b6000828152607360205260409020610f8a9082613e58565b60008281526072602090815260408083206001600160a01b038516845290915290205460ff1661101757612ba3816001600160a01b03166014613e6d565b612bae836020613e6d565b604051602001612bbf9291906153d0565b60408051601f198184030181529082905262461bcd60e51b8252610a2891600401615451565b612bef828261404e565b6000828152607360205260409020610f8a90826140d1565b60005460ff16612c595760405162461bcd60e51b815260206004820152601460248201527f5061757361626c653a206e6f74207061757365640000000000000000000000006044820152606401610a28565b6000805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6000823561014084013582612cbe6080870160608801614aec565b9050612cdb612cd6368890038801610100890161516e565b613a1d565b6001612ced6040880160208901615151565b6001811115612cfe57612cfe614c71565b14612d715760405162461bcd60e51b815260206004820152602860248201527f4d61696e636861696e4761746577617956323a20696e76616c6964207265636560448201527f697074206b696e640000000000000000000000000000000000000000000000006064820152608401610a28565b60808601354614612de95760405162461bcd60e51b8152602060048201526024808201527f4d61696e636861696e4761746577617956323a20696e76616c6964206368616960448201527f6e206964000000000000000000000000000000000000000000000000000000006064820152608401610a28565b6000612dfe61084a6080890160608a01614aec565b9050612e1261012088016101008901615151565b6001811115612e2357612e23614c71565b81516001811115612e3657612e36614c71565b148015612e675750612e4e60e0880160c08901614aec565b6001600160a01b031681602001516001600160a01b0316145b612ebf5760405162461bcd60e51b815260206004820152602360248201527f4d61696e636861696e4761746577617956323a20696e76616c696420726563656044820152621a5c1d60ea1b6064820152608401610a28565b60008481526079602052604090205415612f415760405162461bcd60e51b815260206004820152603260248201527f4d61696e636861696e4761746577617956323a20717565727920666f7220707260448201527f6f636573736564207769746864726177616c00000000000000000000000000006064820152608401610a28565b6001612f5561012089016101008a01615151565b6001811115612f6657612f66614c71565b1480612f795750612f7782846133bc565b155b612feb5760405162461bcd60e51b815260206004820152603260248201527f4d61696e636861696e4761746577617956323a2072656163686564206461696c60448201527f79207769746864726177616c206c696d697400000000000000000000000000006064820152608401610a28565b6000612fff6112f3368a90038a018a614ff0565b9050600061300f607754836140e6565b6003549091506001600160a01b0316600061303d6130356101208d016101008e01615151565b878985614142565b60408051606081018252600080825260208201819052918101829052919b50919250819081906000805b8f5181101561323c578f818151811061308257613082614d90565b6020908102919091018101518051818301516040808401518151600081529586018083528f905260ff9093169085015260608401526080830152935060019060a0016020604051602081039080840390855afa1580156130e6573d6000803e3d6000fd5b505050602060405103519450846001600160a01b0316846001600160a01b0316106131795760405162461bcd60e51b815260206004820152602160248201527f4d61696e636861696e4761746577617956323a20696e76616c6964206f72646560448201527f72000000000000000000000000000000000000000000000000000000000000006064820152608401610a28565b6040517f953865650000000000000000000000000000000000000000000000000000000081526001600160a01b03808716600483015286955089169063953865659060240160206040518083038186803b1580156131d657600080fd5b505afa1580156131ea573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061320e9190614f89565b6132189083615484565b915086821061322a576001955061323c565b8061323481614e06565b915050613067565b50846132b05760405162461bcd60e51b815260206004820152603660248201527f4d61696e636861696e4761746577617956323a20717565727920666f7220696e60448201527f73756666696369656e7420766f746520776569676874000000000000000000006064820152608401610a28565b50505060008a81526079602052604090208690555050881561332c576000888152607a602052604090819020805460ff19166001179055517f89e52969465b1f1866fc5d46fd62de953962e9cb33552443cd999eba05bd20dc906133179086908e906150c4565b60405180910390a15050505050505050610aa7565b6133368688614233565b61337561334960608d0160408e01614aec565b87607460009054906101000a90046001600160a01b03168e61010001803603810190611583919061516e565b7f21e88e956aa3e086f6388e899965cef814688f99ad8bb29b08d396571016372d848c6040516133a69291906150c4565b60405180910390a1505050505050505092915050565b6001600160a01b0382166000908152603a602052604081205482106133e357506000610aa7565b60006133f2620151804261549c565b6001600160a01b0385166000908152603e60205260409020549091508111156134385750506001600160a01b0382166000908152603c6020526040902054811015610aa7565b6001600160a01b0384166000908152603d602052604090205461345c908490615484565b6001600160a01b0385166000908152603c602052604090205411159150610aa79050565b600060025460016002548460015461349891906151a1565b6134a29190615484565b6134ac919061518a565b610aa7919061549c565b60005460ff16156134fc5760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610a28565b6000805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258612c863390565b600061119883836142c3565b60007fb9d1fe7c9deeec5dc90a2f47ff1684239519f2545b2228d3d91fb27df3189eea60001b8260000151836020015161357a85604001516142ed565b61358786606001516142ed565b6135948760800151614350565b6040516020016135a9969594939291906154be565b604051602081830303815290604052805190602001209050919050565b6000620f42406135d683856151a1565b611198919061549c565b6000816001600160a01b0316836001600160a01b031614156136905760408086015190516001600160a01b0386169180156108fc02916000818181858888f1935050505061368b57816001600160a01b031663d0e30db086604001516040518263ffffffff1660e01b81526004016000604051808303818588803b15801561366757600080fd5b505af115801561367b573d6000803e3d6000fd5b505050505061368b858585614393565b613a0c565b6000855160018111156136a5576136a5614c71565b1415613866576040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000906001600160a01b038516906370a082319060240160206040518083038186803b15801561370657600080fd5b505afa15801561371a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061373e9190614f89565b9050856040015181101561385557836001600160a01b03166340c10f193083896040015161376c919061518a565b6040516001600160a01b03909216602483015260448201526064016040516020818303038152906040529060e01b6020820180516001600160e01b0383818316178352505050506040516137c091906154f8565b6000604051808303816000865af19150503d80600081146137fd576040519150601f19603f3d011682016040523d82523d6000602084013e613802565b606091505b505080925050816138555760405162461bcd60e51b815260206004820152601b60248201527f546f6b656e3a204552433230206d696e74696e67206661696c656400000000006044820152606401610a28565b613860868686614393565b50613a0c565b60018551600181111561387b5761387b614c71565b141561399e5761389083858760200151614437565b61368b57602085810151604080516001600160a01b038881166024830152604480830194909452825180830390940184526064909101825292820180516001600160e01b03167f40c10f1900000000000000000000000000000000000000000000000000000000179052519185169161390991906154f8565b6000604051808303816000865af19150503d8060008114613946576040519150601f19603f3d011682016040523d82523d6000602084013e61394b565b606091505b5050809150508061368b5760405162461bcd60e51b815260206004820152601c60248201527f546f6b656e3a20455243373231206d696e74696e67206661696c6564000000006044820152606401610a28565b60405162461bcd60e51b815260206004820152602160248201527f546f6b656e3a20756e737570706f7274656420746f6b656e207374616e64617260448201527f64000000000000000000000000000000000000000000000000000000000000006064820152608401610a28565b5050505050565b6000610aa7825490565b600081516001811115613a3257613a32614c71565b148015613a43575060008160400151115b8015613a5157506020810151155b80613a7b5750600181516001811115613a6c57613a6c614c71565b148015613a7b57506040810151155b610a655760405162461bcd60e51b815260206004820152601360248201527f546f6b656e3a20696e76616c696420696e666f000000000000000000000000006044820152606401610a28565b600060608186516001811115613adf57613adf614c71565b1415613bbd5760408681015181516001600160a01b038881166024830152878116604483015260648083019390935283518083039093018352608490910183526020820180516001600160e01b03166323b872dd60e01b179052915191851691613b4991906154f8565b6000604051808303816000865af19150503d8060008114613b86576040519150601f19603f3d011682016040523d82523d6000602084013e613b8b565b606091505b509092509050818015613bb6575080511580613bb6575080806020019051810190613bb69190615514565b9150613c84565b600186516001811115613bd257613bd2614c71565b141561399e57602086810151604080516001600160a01b0389811660248301528881166044830152606480830194909452825180830390940184526084909101825292820180516001600160e01b03166323b872dd60e01b1790525191851691613c3c91906154f8565b6000604051808303816000865af19150503d8060008114613c79576040519150601f19603f3d011682016040523d82523d6000602084013e613c7e565b606091505b50909250505b81610f5c57613c92866144e2565b613ca6866001600160a01b03166014613e6d565b613cba866001600160a01b03166014613e6d565b613cce866001600160a01b03166014613e6d565b604051602001612bbf9493929190615536565b613d516040805160a08101825260008082526020808301829052835160608082018652838252818301849052818601849052848601919091528451808201865283815280830184905280860184905281850152845190810185528281529081018290529283015290608082015290565b83815260006020820181905250604080820180516001600160a01b039788169052602080890151825190891690820152905146908301528751606084018051918916909152805195909716940193909352935182015292909201516080820152919050565b60008281526072602090815260408083206001600160a01b038516845290915290205460ff166110175760008281526072602090815260408083206001600160a01b03851684529091529020805460ff19166001179055613e143390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6000611198836001600160a01b03841661454f565b60606000613e7c8360026151a1565b613e87906002615484565b67ffffffffffffffff811115613e9f57613e9f614e21565b6040519080825280601f01601f191660200182016040528015613ec9576020820181803683370190505b5090507f300000000000000000000000000000000000000000000000000000000000000081600081518110613f0057613f00614d90565b60200101906001600160f81b031916908160001a9053507f780000000000000000000000000000000000000000000000000000000000000081600181518110613f4b57613f4b614d90565b60200101906001600160f81b031916908160001a9053506000613f6f8460026151a1565b613f7a906001615484565b90505b6001811115613fff577f303132333435363738396162636465660000000000000000000000000000000085600f1660108110613fbb57613fbb614d90565b1a60f81b828281518110613fd157613fd1614d90565b60200101906001600160f81b031916908160001a90535060049490941c93613ff881615606565b9050613f7d565b5083156111985760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610a28565b60008281526072602090815260408083206001600160a01b038516845290915290205460ff16156110175760008281526072602090815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b6000611198836001600160a01b03841661459e565b604080517f19010000000000000000000000000000000000000000000000000000000000006020808301919091526022820185905260428083018590528351808403909101815260629092019092528051910120600090611198565b6000806000836001600160a01b031663926323d56040518163ffffffff1660e01b815260040160206040518083038186803b15801561418057600080fd5b505afa158015614194573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141b89190614f89565b90506141c381613480565b925060008760018111156141d9576141d9614c71565b1415614229576001600160a01b038616600090815260396020526040902054851061420a5761420781614691565b92505b6001600160a01b0386166000908152603a602052604090205485101591505b5094509492505050565b6000614242620151804261549c565b6001600160a01b0384166000908152603e6020526040902054909150811115614291576001600160a01b03929092166000908152603e6020908152604080832094909455603d90529190912055565b6001600160a01b0383166000908152603d6020526040812080548492906142b9908490615484565b9091555050505050565b60008260000182815481106142da576142da614d90565b9060005260206000200154905092915050565b805160208083015160408085015190516000946135a9947f353bdd8d69b9e3185b3972e08b03845c0c14a21a390215302776a7a34b0e87649491939192019384526001600160a01b03928316602085015291166040830152606082015260800190565b805160208083015160408085015190516000946135a9947f1e2b74b2a792d5c0f0b6e59b037fa9d43d84fbb759337f0112fcc15ca414fc8d94919391920161561d565b600080845160018111156143a9576143a9614c71565b14156143c5576143be828486604001516146a9565b90506143ef565b6001845160018111156143da576143da614c71565b141561399e576143be82848660200151614437565b80610e89576143fd846144e2565b614411846001600160a01b03166014613e6d565b614425846001600160a01b03166014613e6d565b604051602001612bbf93929190615648565b604080513060248201526001600160a01b038481166044830152606480830185905283518084039091018152608490920183526020820180516001600160e01b03166323b872dd60e01b1790529151600092861691614495916154f8565b6000604051808303816000865af19150503d80600081146144d2576040519150601f19603f3d011682016040523d82523d6000602084013e6144d7565b606091505b509095945050505050565b606061450d826000015160018111156144fd576144fd614c71565b6001600160a01b03166001613e6d565b61451a8360200151614795565b6145278460400151614795565b604051602001614539939291906156d9565b6040516020818303038152906040529050919050565b600081815260018301602052604081205461459657508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610aa7565b506000610aa7565b600081815260018301602052604081205480156146875760006145c260018361518a565b85549091506000906145d69060019061518a565b905081811461463b5760008660000182815481106145f6576145f6614d90565b906000526020600020015490508087600001848154811061461957614619614d90565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061464c5761464c6157a2565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610aa7565b6000915050610aa7565b600060385460016038548460375461349891906151a1565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b03167fa9059cbb0000000000000000000000000000000000000000000000000000000017905291516000926060929087169161471f91906154f8565b6000604051808303816000865af19150503d806000811461475c576040519150601f19603f3d011682016040523d82523d6000602084013e614761565b606091505b50909250905081801561478c57508051158061478c57508080602001905181019061478c9190615514565b95945050505050565b6060816147d557505060408051808201909152600481527f3078303000000000000000000000000000000000000000000000000000000000602082015290565b8160005b81156147f857806147e981614e06565b915050600882901c91506147d9565b6111848482613e6d565b604080516060810182526000808252602082015290810161483e6040805160608101909152806000815260200160008152602001600081525090565b905290565b60006020828403121561485557600080fd5b81356001600160e01b03198116811461119857600080fd5b6001600160a01b0381168114610a6557600080fd5b803561198d8161486d565b8060608101831015610aa757600080fd5b8060808101831015610aa757600080fd5b60008083601f8401126148c157600080fd5b50813567ffffffffffffffff8111156148d957600080fd5b6020830191508360208260051b850101111561172857600080fd5b60008060008060008060008060008060006101408c8e03121561491657600080fd5b61491f8c614882565b9a5061492d60208d01614882565b995061493b60408d01614882565b985060608c0135975060808c0135965060a08c0135955060c08c0135945067ffffffffffffffff8060e08e0135111561497357600080fd5b6149838e60e08f01358f0161488d565b9450806101008e0135111561499757600080fd5b6149a88e6101008f01358f0161489e565b9350806101208e013511156149bc57600080fd5b506149ce8d6101208e01358e016148af565b81935080925050509295989b509295989b9093969950565b600080600080604085870312156149fc57600080fd5b843567ffffffffffffffff80821115614a1457600080fd5b614a20888389016148af565b90965094506020870135915080821115614a3957600080fd5b50614a46878288016148af565b95989497509550505050565b60008060008060008060608789031215614a6b57600080fd5b863567ffffffffffffffff80821115614a8357600080fd5b614a8f8a838b016148af565b90985096506020890135915080821115614aa857600080fd5b614ab48a838b016148af565b90965094506040890135915080821115614acd57600080fd5b50614ada89828a016148af565b979a9699509497509295939492505050565b600060208284031215614afe57600080fd5b81356111988161486d565b600060208284031215614b1b57600080fd5b5035919050565b60008060408385031215614b3557600080fd5b823591506020830135614b478161486d565b809150509250929050565b600060a08284031215614b6457600080fd5b50919050565b60006101608284031215614b6457600080fd5b60008060006101808486031215614b9357600080fd5b614b9d8585614b6a565b925061016084013567ffffffffffffffff80821115614bbb57600080fd5b818601915086601f830112614bcf57600080fd5b813581811115614bde57600080fd5b876020606083028501011115614bf357600080fd5b6020830194508093505050509250925092565b60008060408385031215614c1957600080fd5b8235614c248161486d565b946020939093013593505050565b60008060408385031215614c4557600080fd5b50508035926020909101359150565b60006101608284031215614c6757600080fd5b6111988383614b6a565b634e487b7160e01b600052602160045260246000fd5b60028110610a6557634e487b7160e01b600052602160045260246000fd5b81516040820190614cb581614c87565b808352506001600160a01b03602084015116602083015292915050565b60008060008060008060006080888a031215614ced57600080fd5b873567ffffffffffffffff80821115614d0557600080fd5b614d118b838c016148af565b909950975060208a0135915080821115614d2a57600080fd5b614d368b838c016148af565b909750955060408a0135915080821115614d4f57600080fd5b614d5b8b838c016148af565b909550935060608a0135915080821115614d7457600080fd5b50614d818a828b0161489e565b91505092959891949750929550565b634e487b7160e01b600052603260045260246000fd5b6000808335601e19843603018112614dbd57600080fd5b83018035915067ffffffffffffffff821115614dd857600080fd5b6020019150600581901b360382131561172857600080fd5b634e487b7160e01b600052601160045260246000fd5b6000600019821415614e1a57614e1a614df0565b5060010190565b634e487b7160e01b600052604160045260246000fd5b6040516060810167ffffffffffffffff81118282101715614e6857634e487b7160e01b600052604160045260246000fd5b60405290565b60028110610a6557600080fd5b600060608284031215614e8d57600080fd5b614e95614e37565b90508135614ea281614e6e565b80825250602082013560208201526040820135604082015292915050565b600060a08284031215614ed257600080fd5b614eda614e37565b8235614ee58161486d565b81526020830135614ef58161486d565b6020820152614f078460408501614e7b565b60408201529392505050565b600060608284031215614f2557600080fd5b6040516060810181811067ffffffffffffffff82111715614f5657634e487b7160e01b600052604160045260246000fd5b604052823560ff81168114614f6a57600080fd5b8152602083810135908201526040928301359281019290925250919050565b600060208284031215614f9b57600080fd5b5051919050565b600060608284031215614fb457600080fd5b614fbc614e37565b90508135614fc98161486d565b81526020820135614fd98161486d565b806020830152506040820135604082015292915050565b6000610160828403121561500357600080fd5b60405160a0810181811067ffffffffffffffff8211171561503457634e487b7160e01b600052604160045260246000fd5b60405282358152602083013561504981614e6e565b602082015261505b8460408501614fa2565b604082015261506d8460a08501614fa2565b6060820152615080846101008501614e7b565b60808201529392505050565b80356150978161486d565b6001600160a01b0390811683526020820135906150b38261486d565b166020830152604090810135910152565b6000610180820190508382528235602083015260208301356150e581614e6e565b6150ee81614c87565b80604084015250615105606083016040850161508c565b61511560c0830160a0850161508c565b61012061010084013561512781614e6e565b61513081614c87565b81840152830135610140808401919091529092013561016090910152919050565b60006020828403121561516357600080fd5b813561119881614e6e565b60006060828403121561518057600080fd5b6111988383614e7b565b60008282101561519c5761519c614df0565b500390565b60008160001904831182151516156151bb576151bb614df0565b500290565b6000610180820190508382528251602083015260208301516151e181614c87565b6040838101919091528381015180516001600160a01b03908116606086015260208201511660808501529081015160a084015250606083015180516001600160a01b0390811660c085015260208201511660e08401526040810151610100840152506080830151805161525381614c87565b6101208401526020810151610140840152604001516101609092019190915292915050565b8183526000602080850194508260005b858110156152b657813561529b8161486d565b6001600160a01b031687529582019590820190600101615288565b509495945050505050565b6060815260006152d560608301888a615278565b6020838203818501526152e982888a615278565b8481036040860152858152869250810160005b8681101561532a57833561530f81614e6e565b61531881614c87565b825292820192908201906001016152fc565b509a9950505050505050505050565b60408152600061534d604083018688615278565b82810360208401528381527f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff84111561538557600080fd5b8360051b80866020840137600091016020019081529695505050505050565b60005b838110156153bf5781810151838201526020016153a7565b83811115610e895750506000910152565b7f416363657373436f6e74726f6c3a206163636f756e74200000000000000000008152600083516154088160178501602088016153a4565b7f206973206d697373696e6720726f6c652000000000000000000000000000000060179184019182015283516154458160288401602088016153a4565b01602801949350505050565b60208152600082518060208401526154708160408501602087016153a4565b601f01601f19169190910160400192915050565b6000821982111561549757615497614df0565b500190565b6000826154b957634e487b7160e01b600052601260045260246000fd5b500490565b8681526020810186905260c081016154d586614c87565b8560408301528460608301528360808301528260a0830152979650505050505050565b6000825161550a8184602087016153a4565b9190910192915050565b60006020828403121561552657600080fd5b8151801515811461119857600080fd5b7f546f6b656e3a20636f756c64206e6f74207472616e7366657220000000000000815260008551602061556f82601a8601838b016153a4565b7f2066726f6d200000000000000000000000000000000000000000000000000000601a9285019283015286516155aa81838501848b016153a4565b630103a37960e51b92018181019290925285516155cd81602485018985016153a4565b660103a37b5b2b7160cd1b6024939091019283015284516155f481602b85018489016153a4565b91909101602b01979650505050505050565b60008161561557615615614df0565b506000190190565b8481526080810161562d85614c87565b84602083015283604083015282606083015295945050505050565b7f546f6b656e3a20636f756c64206e6f74207472616e736665722000000000000081526000845161568081601a8501602089016153a4565b630103a37960e51b601a9184019182015284516156a481601e8401602089016153a4565b660103a37b5b2b7160cd1b601e929091019182015283516156cc8160258401602088016153a4565b0160250195945050505050565b7f546f6b656e496e666f280000000000000000000000000000000000000000000081526000845161571181600a8501602089016153a4565b80830190507f2c0000000000000000000000000000000000000000000000000000000000000080600a830152855161575081600b850160208a016153a4565b600b920191820152835161576b81600c8401602088016153a4565b7f2900000000000000000000000000000000000000000000000000000000000000600c9290910191820152600d0195945050505050565b634e487b7160e01b600052603160045260246000fdfeb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d610348617350726f787941646d696e3a20756e617574686f72697a65642073656e64\",\n        ),\n    ];\n}\n"
  },
  {
    "path": "crates/forge/src/cmd/compiler.rs",
    "content": "use clap::{Parser, Subcommand, ValueHint};\nuse eyre::Result;\nuse foundry_common::shell;\nuse foundry_compilers::{Graph, artifacts::EvmVersion};\nuse foundry_config::Config;\nuse semver::Version;\nuse serde::Serialize;\nuse std::{collections::BTreeMap, path::PathBuf};\n\n/// CLI arguments for `forge compiler`.\n#[derive(Debug, Parser)]\npub struct CompilerArgs {\n    #[command(subcommand)]\n    pub sub: CompilerSubcommands,\n}\n\nimpl CompilerArgs {\n    pub fn run(self) -> Result<()> {\n        match self.sub {\n            CompilerSubcommands::Resolve(args) => args.run(),\n        }\n    }\n}\n\n#[derive(Debug, Subcommand)]\npub enum CompilerSubcommands {\n    /// Retrieves the resolved version(s) of the compiler within the project.\n    #[command(visible_alias = \"r\")]\n    Resolve(ResolveArgs),\n}\n\n/// Resolved compiler within the project.\n#[derive(Serialize)]\nstruct ResolvedCompiler {\n    /// Compiler version.\n    version: Version,\n    /// Max supported EVM version of compiler.\n    #[serde(skip_serializing_if = \"Option::is_none\")]\n    evm_version: Option<EvmVersion>,\n    /// Source paths.\n    #[serde(skip_serializing_if = \"Vec::is_empty\")]\n    paths: Vec<String>,\n}\n\n/// CLI arguments for `forge compiler resolve`.\n#[derive(Debug, Parser)]\npub struct ResolveArgs {\n    /// The root directory\n    #[arg(long, short, value_hint = ValueHint::DirPath, value_name = \"PATH\")]\n    root: Option<PathBuf>,\n\n    /// Skip files that match the given regex pattern.\n    #[arg(long, short, value_name = \"REGEX\")]\n    skip: Option<regex::Regex>,\n}\n\nimpl ResolveArgs {\n    pub fn run(self) -> Result<()> {\n        let Self { root, skip } = self;\n\n        let root = root.unwrap_or_else(|| PathBuf::from(\".\"));\n        let config = Config::load_with_root(&root)?;\n        let project = config.project()?;\n\n        let graph = Graph::resolve(&project.paths)?;\n        let sources = graph.into_sources_by_version(&project)?.sources;\n\n        let mut output: BTreeMap<String, Vec<ResolvedCompiler>> = BTreeMap::new();\n\n        for (language, sources) in sources {\n            let mut versions_with_paths: Vec<ResolvedCompiler> = sources\n                .iter()\n                .map(|(version, sources, _)| {\n                    let paths: Vec<String> = sources\n                        .keys()\n                        .filter_map(|path_file| {\n                            let path_str = path_file\n                                .strip_prefix(&project.paths.root)\n                                .unwrap_or(path_file)\n                                .to_path_buf()\n                                .display()\n                                .to_string();\n\n                            // Skip files that match the given regex pattern.\n                            if let Some(ref regex) = skip\n                                && regex.is_match(&path_str)\n                            {\n                                return None;\n                            }\n\n                            Some(path_str)\n                        })\n                        .collect();\n\n                    let evm_version = if shell::verbosity() > 1 {\n                        let evm = EvmVersion::default()\n                            .normalize_version_solc(version)\n                            .unwrap_or_default();\n\n                        Some(evm)\n                    } else {\n                        None\n                    };\n\n                    ResolvedCompiler { version: version.clone(), evm_version, paths }\n                })\n                .filter(|version| !version.paths.is_empty())\n                .collect();\n\n            // Sort by SemVer version.\n            versions_with_paths.sort_by(|v1, v2| Version::cmp(&v1.version, &v2.version));\n\n            // Skip language if no paths are found after filtering.\n            if !versions_with_paths.is_empty() {\n                // Clear paths if verbosity is 0, performed only after filtering to avoid being\n                // skipped.\n                if shell::verbosity() == 0 {\n                    versions_with_paths.iter_mut().for_each(|version| version.paths.clear());\n                }\n\n                output.insert(language.to_string(), versions_with_paths);\n            }\n        }\n\n        if shell::is_json() {\n            sh_println!(\"{}\", serde_json::to_string(&output)?)?;\n            return Ok(());\n        }\n\n        for (language, compilers) in &output {\n            match shell::verbosity() {\n                0 => sh_println!(\"{language}:\")?,\n                _ => sh_println!(\"{language}:\\n\")?,\n            }\n\n            for resolved_compiler in compilers {\n                let version = &resolved_compiler.version;\n                match shell::verbosity() {\n                    0 => sh_println!(\"- {version}\")?,\n                    _ => {\n                        if let Some(evm) = &resolved_compiler.evm_version {\n                            sh_println!(\"{version} (<= {evm}):\")?\n                        } else {\n                            sh_println!(\"{version}:\")?\n                        }\n                    }\n                }\n\n                if shell::verbosity() > 0 {\n                    let paths = &resolved_compiler.paths;\n                    for (idx, path) in paths.iter().enumerate() {\n                        if idx == paths.len() - 1 {\n                            sh_println!(\"└── {path}\\n\")?\n                        } else {\n                            sh_println!(\"├── {path}\")?\n                        }\n                    }\n                }\n            }\n\n            if shell::verbosity() == 0 {\n                sh_println!()?\n            }\n        }\n\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "crates/forge/src/cmd/config.rs",
    "content": "use super::build::BuildArgs;\nuse clap::Parser;\nuse eyre::Result;\nuse foundry_cli::{opts::EvmArgs, utils::LoadConfig};\nuse foundry_common::shell;\nuse foundry_config::fix::fix_tomls;\n\nfoundry_config::impl_figment_convert!(ConfigArgs, build, evm);\n\n/// CLI arguments for `forge config`.\n#[derive(Clone, Debug, Parser)]\npub struct ConfigArgs {\n    /// Print only a basic set of the currently set config values.\n    #[arg(long)]\n    basic: bool,\n\n    /// Attempt to fix any configuration warnings.\n    #[arg(long)]\n    fix: bool,\n\n    // support nested build arguments\n    #[command(flatten)]\n    build: BuildArgs,\n\n    #[command(flatten)]\n    evm: EvmArgs,\n}\n\nimpl ConfigArgs {\n    pub fn run(self) -> Result<()> {\n        if self.fix {\n            for warning in fix_tomls() {\n                sh_warn!(\"{warning}\")?;\n            }\n            return Ok(());\n        }\n\n        let config = self\n            .load_config_unsanitized()?\n            .normalized_optimizer_settings()\n            // we explicitly normalize the version, so mimic the behavior when invoking solc\n            .normalized_evm_version();\n\n        let s = if self.basic {\n            let config = config.into_basic();\n            if shell::is_json() {\n                serde_json::to_string_pretty(&config)?\n            } else {\n                config.to_string_pretty()?\n            }\n        } else if shell::is_json() {\n            serde_json::to_string_pretty(&config)?\n        } else {\n            config.to_string_pretty()?\n        };\n\n        sh_println!(\"{s}\")?;\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "crates/forge/src/cmd/coverage.rs",
    "content": "use super::{install, test::TestArgs, watch::WatchArgs};\nuse crate::coverage::{\n    BytecodeReporter, ContractId, CoverageReport, CoverageReporter, CoverageSummaryReporter,\n    DebugReporter, ItemAnchor, LcovReporter,\n    analysis::{SourceAnalysis, SourceFiles},\n    anchors::find_anchors,\n};\nuse alloy_primitives::{Address, Bytes, U256, map::HashMap};\nuse clap::{Parser, ValueEnum, ValueHint};\nuse eyre::Result;\nuse foundry_cli::utils::{LoadConfig, STATIC_FUZZ_SEED};\nuse foundry_common::{compile::ProjectCompiler, errors::convert_solar_errors};\nuse foundry_compilers::{\n    Artifact, ArtifactId, Project, ProjectCompileOutput, ProjectPathsConfig, VYPER_EXTENSIONS,\n    artifacts::{CompactBytecode, CompactDeployedBytecode, sourcemap::SourceMap},\n};\nuse foundry_config::Config;\nuse foundry_evm::{core::ic::IcPcMap, opts::EvmOpts};\nuse rayon::prelude::*;\nuse semver::{Version, VersionReq};\nuse std::path::{Path, PathBuf};\n\n// Loads project's figment and merges the build cli arguments into it\nfoundry_config::impl_figment_convert!(CoverageArgs, test);\n\n/// CLI arguments for `forge coverage`.\n#[derive(Parser)]\npub struct CoverageArgs {\n    /// The report type to use for coverage.\n    ///\n    /// This flag can be used multiple times.\n    #[arg(long, value_enum, default_value = \"summary\")]\n    report: Vec<CoverageReportKind>,\n\n    /// The version of the LCOV \"tracefile\" format to use.\n    ///\n    /// Format: `MAJOR[.MINOR]`.\n    ///\n    /// Main differences:\n    /// - `1.x`: The original v1 format.\n    /// - `2.0`: Adds support for \"line end\" numbers for functions.\n    /// - `2.2`: Changes the format of functions.\n    #[arg(long, default_value = \"1\", value_parser = parse_lcov_version)]\n    lcov_version: Version,\n\n    /// Enable viaIR with minimum optimization\n    ///\n    /// This can fix most of the \"stack too deep\" errors while resulting a\n    /// relatively accurate source map.\n    #[arg(long)]\n    ir_minimum: bool,\n\n    /// The path to output the report.\n    ///\n    /// If not specified, the report will be stored in the root of the project.\n    #[arg(\n        long,\n        short,\n        value_hint = ValueHint::FilePath,\n        value_name = \"PATH\"\n    )]\n    report_file: Option<PathBuf>,\n\n    /// Whether to include libraries in the coverage report.\n    #[arg(long)]\n    include_libs: bool,\n\n    /// Whether to exclude tests from the coverage report.\n    #[arg(long)]\n    exclude_tests: bool,\n\n    /// The coverage reporters to use. Constructed from the other fields.\n    #[arg(skip)]\n    reporters: Vec<Box<dyn CoverageReporter>>,\n\n    #[command(flatten)]\n    test: TestArgs,\n}\n\nimpl CoverageArgs {\n    pub async fn run(mut self) -> Result<()> {\n        let (mut config, evm_opts) = self.load_config_and_evm_opts()?;\n\n        // install missing dependencies\n        if install::install_missing_dependencies(&mut config).await && config.auto_detect_remappings\n        {\n            // need to re-configure here to also catch additional remappings\n            config = self.load_config()?;\n        }\n\n        // Set fuzz seed so coverage reports are deterministic\n        config.fuzz.seed = Some(U256::from_be_bytes(STATIC_FUZZ_SEED));\n\n        let (paths, mut output) = {\n            let (project, output) = self.build(&config)?;\n            (project.paths, output)\n        };\n\n        self.populate_reporters(&paths.root);\n\n        sh_println!(\"Analysing contracts...\")?;\n        let report = self.prepare(&paths, &mut output)?;\n\n        sh_println!(\"Running tests...\")?;\n        self.collect(&paths.root, &output, report, config, evm_opts).await\n    }\n\n    fn populate_reporters(&mut self, root: &Path) {\n        self.reporters = self\n            .report\n            .iter()\n            .map(|report_kind| match report_kind {\n                CoverageReportKind::Summary => {\n                    Box::<CoverageSummaryReporter>::default() as Box<dyn CoverageReporter>\n                }\n                CoverageReportKind::Lcov => {\n                    let path =\n                        root.join(self.report_file.as_deref().unwrap_or(\"lcov.info\".as_ref()));\n                    Box::new(LcovReporter::new(path, self.lcov_version.clone()))\n                }\n                CoverageReportKind::Bytecode => Box::new(BytecodeReporter::new(\n                    root.to_path_buf(),\n                    root.join(\"bytecode-coverage\"),\n                )),\n                CoverageReportKind::Debug => Box::new(DebugReporter),\n            })\n            .collect::<Vec<_>>();\n    }\n\n    /// Builds the project.\n    fn build(&self, config: &Config) -> Result<(Project, ProjectCompileOutput)> {\n        let mut project = config.ephemeral_project()?;\n\n        if self.ir_minimum {\n            sh_warn!(\n                \"`--ir-minimum` enables `viaIR` with minimum optimization, \\\n                 which can result in inaccurate source mappings.\\n\\\n                 Only use this flag as a workaround if you are experiencing \\\"stack too deep\\\" errors.\\n\\\n                 Note that `viaIR` is production ready since Solidity 0.8.13 and above.\\n\\\n                 See more: https://book.getfoundry.sh/guides/best-practices/stack-too-deep\"\n            )?;\n        } else {\n            sh_warn!(\n                \"optimizer settings and `viaIR` have been disabled for accurate coverage reports.\\n\\\n                 If you encounter \\\"stack too deep\\\" errors, consider using `--ir-minimum` which \\\n                 enables `viaIR` with minimum optimization resolving most of the errors.\\n\\\n                 See more: https://book.getfoundry.sh/guides/best-practices/stack-too-deep\"\n            )?;\n        }\n\n        config.disable_optimizations(&mut project, self.ir_minimum);\n\n        let output = ProjectCompiler::default()\n            .compile(&project)?\n            .with_stripped_file_prefixes(project.root());\n\n        Ok((project, output))\n    }\n\n    /// Builds the coverage report.\n    #[instrument(name = \"Coverage::prepare\", skip_all)]\n    fn prepare(\n        &self,\n        project_paths: &ProjectPathsConfig,\n        output: &mut ProjectCompileOutput,\n    ) -> Result<CoverageReport> {\n        let mut report = CoverageReport::default();\n\n        output.parser_mut().solc_mut().compiler_mut().enter_mut(|compiler| {\n            if compiler.gcx().stage() < Some(solar::config::CompilerStage::Lowering) {\n                let _ = compiler.lower_asts();\n            }\n            convert_solar_errors(compiler.dcx())\n        })?;\n        let output = &*output;\n\n        // Collect source files.\n        let mut versioned_sources = HashMap::<Version, SourceFiles>::default();\n        for (path, source_file, version) in output.output().sources.sources_with_version() {\n            // Filter out vyper sources.\n            if path\n                .extension()\n                .and_then(|s| s.to_str())\n                .is_some_and(|ext| VYPER_EXTENSIONS.contains(&ext))\n            {\n                continue;\n            }\n\n            report.add_source(version.clone(), source_file.id as usize, path.clone());\n\n            // Filter out libs dependencies and tests.\n            if (!self.include_libs && project_paths.has_library_ancestor(path))\n                || (self.exclude_tests && project_paths.is_test(path))\n            {\n                continue;\n            }\n\n            let path = project_paths.root.join(path);\n            versioned_sources\n                .entry(version.clone())\n                .or_default()\n                .sources\n                .insert(source_file.id, path);\n        }\n\n        // Get source maps and bytecodes.\n        let artifacts: Vec<ArtifactData> = output\n            .artifact_ids()\n            .par_bridge() // This parses source maps, so we want to run it in parallel.\n            .filter_map(|(id, artifact)| {\n                let source_id = report.get_source_id(id.version.clone(), id.source.clone())?;\n                ArtifactData::new(&id, source_id, artifact)\n            })\n            .collect();\n\n        // Add coverage items.\n        for (version, sources) in &versioned_sources {\n            let source_analysis = SourceAnalysis::new(sources, output)?;\n            let anchors = artifacts\n                .par_iter()\n                .filter(|artifact| artifact.contract_id.version == *version)\n                .map(|artifact| {\n                    let creation_code_anchors = artifact.creation.find_anchors(&source_analysis);\n                    let deployed_code_anchors = artifact.deployed.find_anchors(&source_analysis);\n                    (artifact.contract_id.clone(), (creation_code_anchors, deployed_code_anchors))\n                })\n                .collect_vec_list();\n            report.add_anchors(anchors.into_iter().flatten());\n            report.add_analysis(version.clone(), source_analysis);\n        }\n\n        if self.reporters.iter().any(|reporter| reporter.needs_source_maps()) {\n            report.add_source_maps(artifacts.into_iter().map(|artifact| {\n                (artifact.contract_id, (artifact.creation.source_map, artifact.deployed.source_map))\n            }));\n        }\n\n        Ok(report)\n    }\n\n    /// Runs tests, collects coverage data and generates the final report.\n    #[instrument(name = \"Coverage::collect\", skip_all)]\n    async fn collect(\n        mut self,\n        project_root: &Path,\n        output: &ProjectCompileOutput,\n        mut report: CoverageReport,\n        config: Config,\n        evm_opts: EvmOpts,\n    ) -> Result<()> {\n        let filter = self.test.filter(&config)?;\n        let outcome =\n            self.test.run_tests(project_root, config, evm_opts, output, &filter, true).await?;\n\n        let known_contracts = outcome.runner.as_ref().unwrap().known_contracts.clone();\n\n        // Add hit data to the coverage report\n        let data = outcome.results.values().flat_map(|suite| {\n            let mut hits = Vec::new();\n            for result in suite.test_results.values() {\n                let Some(hit_maps) = result.line_coverage.as_ref() else { continue };\n                for map in hit_maps.0.values() {\n                    if let Some((id, _)) = known_contracts.find_by_deployed_code(map.bytecode()) {\n                        hits.push((id, map, true));\n                    } else if let Some((id, _)) =\n                        known_contracts.find_by_creation_code(map.bytecode())\n                    {\n                        hits.push((id, map, false));\n                    }\n                }\n            }\n            hits\n        });\n\n        for (artifact_id, map, is_deployed_code) in data {\n            if let Some(source_id) =\n                report.get_source_id(artifact_id.version.clone(), artifact_id.source.clone())\n            {\n                report.add_hit_map(\n                    &ContractId {\n                        version: artifact_id.version.clone(),\n                        source_id,\n                        contract_name: artifact_id.name.as_str().into(),\n                    },\n                    map,\n                    is_deployed_code,\n                )?;\n            }\n        }\n\n        // Filter out ignored sources from the report.\n        if let Some(not_re) = &filter.args().coverage_pattern_inverse {\n            let file_root = filter.paths().root.as_path();\n            report.retain_sources(|path: &Path| {\n                let path = path.strip_prefix(file_root).unwrap_or(path);\n                !not_re.is_match(&path.to_string_lossy())\n            });\n        }\n\n        // Output final reports.\n        self.report(&report)?;\n\n        // Check for test failures after generating coverage report.\n        // This ensures coverage data is written even when tests fail.\n        outcome.ensure_ok(false)?;\n\n        Ok(())\n    }\n\n    #[instrument(name = \"Coverage::report\", skip_all)]\n    fn report(&mut self, report: &CoverageReport) -> Result<()> {\n        for reporter in &mut self.reporters {\n            let _guard = debug_span!(\"reporter.report\", kind=%reporter.name()).entered();\n            reporter.report(report)?;\n        }\n        Ok(())\n    }\n\n    pub fn is_watch(&self) -> bool {\n        self.test.is_watch()\n    }\n\n    pub fn watch(&self) -> &WatchArgs {\n        &self.test.watch\n    }\n}\n\n/// Coverage reports to generate.\n#[derive(Clone, Debug, Default, ValueEnum)]\npub enum CoverageReportKind {\n    #[default]\n    Summary,\n    Lcov,\n    Debug,\n    Bytecode,\n}\n\n/// Helper function that will link references in unlinked bytecode to the 0 address.\n///\n/// This is needed in order to analyze the bytecode for contracts that use libraries.\nfn dummy_link_bytecode(mut obj: CompactBytecode) -> Option<Bytes> {\n    let link_references = obj.link_references.clone();\n    for (file, libraries) in link_references {\n        for library in libraries.keys() {\n            obj.link(&file, library, Address::ZERO);\n        }\n    }\n\n    obj.object.resolve();\n    obj.object.into_bytes()\n}\n\n/// Helper function that will link references in unlinked bytecode to the 0 address.\n///\n/// This is needed in order to analyze the bytecode for contracts that use libraries.\nfn dummy_link_deployed_bytecode(obj: CompactDeployedBytecode) -> Option<Bytes> {\n    obj.bytecode.and_then(dummy_link_bytecode)\n}\n\npub struct ArtifactData {\n    pub contract_id: ContractId,\n    pub creation: BytecodeData,\n    pub deployed: BytecodeData,\n}\n\nimpl ArtifactData {\n    pub fn new(id: &ArtifactId, source_id: usize, artifact: &impl Artifact) -> Option<Self> {\n        Some(Self {\n            contract_id: ContractId {\n                version: id.version.clone(),\n                source_id,\n                contract_name: id.name.as_str().into(),\n            },\n            creation: BytecodeData::new(\n                artifact.get_source_map()?.ok()?,\n                artifact\n                    .get_bytecode()\n                    .and_then(|bytecode| dummy_link_bytecode(bytecode.into_owned()))?,\n            ),\n            deployed: BytecodeData::new(\n                artifact.get_source_map_deployed()?.ok()?,\n                artifact\n                    .get_deployed_bytecode()\n                    .and_then(|bytecode| dummy_link_deployed_bytecode(bytecode.into_owned()))?,\n            ),\n        })\n    }\n}\n\npub struct BytecodeData {\n    source_map: SourceMap,\n    bytecode: Bytes,\n    /// The instruction counter to program counter mapping.\n    ///\n    /// The source maps are indexed by *instruction counters*, which are the indexes of\n    /// instructions in the bytecode *minus any push bytes*.\n    ///\n    /// Since our line coverage inspector collects hit data using program counters, the anchors\n    /// also need to be based on program counters.\n    ic_pc_map: IcPcMap,\n}\n\nimpl BytecodeData {\n    fn new(source_map: SourceMap, bytecode: Bytes) -> Self {\n        let ic_pc_map = IcPcMap::new(&bytecode);\n        Self { source_map, bytecode, ic_pc_map }\n    }\n\n    pub fn find_anchors(&self, source_analysis: &SourceAnalysis) -> Vec<ItemAnchor> {\n        find_anchors(&self.bytecode, &self.source_map, &self.ic_pc_map, source_analysis)\n    }\n}\n\nfn parse_lcov_version(s: &str) -> Result<Version, String> {\n    let vr = VersionReq::parse(&format!(\"={s}\")).map_err(|e| e.to_string())?;\n    let [c] = &vr.comparators[..] else {\n        return Err(\"invalid version\".to_string());\n    };\n    if c.op != semver::Op::Exact {\n        return Err(\"invalid version\".to_string());\n    }\n    if !c.pre.is_empty() {\n        return Err(\"pre-releases are not supported\".to_string());\n    }\n    Ok(Version::new(c.major, c.minor.unwrap_or(0), c.patch.unwrap_or(0)))\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn lcov_version() {\n        assert_eq!(parse_lcov_version(\"0\").unwrap(), Version::new(0, 0, 0));\n        assert_eq!(parse_lcov_version(\"1\").unwrap(), Version::new(1, 0, 0));\n        assert_eq!(parse_lcov_version(\"1.0\").unwrap(), Version::new(1, 0, 0));\n        assert_eq!(parse_lcov_version(\"1.1\").unwrap(), Version::new(1, 1, 0));\n        assert_eq!(parse_lcov_version(\"1.11\").unwrap(), Version::new(1, 11, 0));\n    }\n}\n"
  },
  {
    "path": "crates/forge/src/cmd/create.rs",
    "content": "use crate::cmd::install;\nuse alloy_chains::Chain;\nuse alloy_consensus::{SignableTransaction, Signed};\nuse alloy_dyn_abi::{DynSolValue, JsonAbiExt, Specifier};\nuse alloy_json_abi::{Constructor, JsonAbi};\nuse alloy_network::{AnyNetwork, EthereumWallet, Network, ReceiptResponse, TransactionBuilder};\nuse alloy_primitives::{Address, Bytes, hex};\nuse alloy_provider::{PendingTransactionError, Provider, ProviderBuilder as AlloyProviderBuilder};\nuse alloy_signer::{Signature, Signer};\nuse alloy_transport::TransportError;\nuse clap::{Parser, ValueHint};\nuse eyre::{Context, Result};\nuse forge_verify::{RetryArgs, VerifierArgs, VerifyArgs};\nuse foundry_cli::{\n    opts::{BuildOpts, EthereumOpts, EtherscanOpts, TransactionOpts},\n    utils::{LoadConfig, find_contract_artifacts, read_constructor_args_file},\n};\nuse foundry_common::{\n    compile::{self},\n    fmt::parse_tokens,\n    provider::ProviderBuilder,\n    shell,\n};\nuse foundry_compilers::{\n    ArtifactId, artifacts::BytecodeObject, info::ContractInfo, utils::canonicalize,\n};\nuse foundry_config::{\n    Config,\n    figment::{\n        self, Metadata, Profile,\n        value::{Dict, Map},\n    },\n    merge_impl_figment_convert,\n};\nuse foundry_primitives::FoundryTransactionBuilder;\nuse serde_json::json;\nuse std::{borrow::Borrow, marker::PhantomData, path::PathBuf, sync::Arc, time::Duration};\nuse tempo_alloy::TempoNetwork;\n\nmerge_impl_figment_convert!(CreateArgs, build, eth);\n\n/// CLI arguments for `forge create`.\n#[derive(Clone, Debug, Parser)]\npub struct CreateArgs {\n    /// The contract identifier in the form `<path>:<contractname>`.\n    contract: ContractInfo,\n\n    /// The constructor arguments.\n    #[arg(\n        long,\n        num_args(1..),\n        conflicts_with = \"constructor_args_path\",\n        value_name = \"ARGS\",\n        allow_hyphen_values = true,\n    )]\n    constructor_args: Vec<String>,\n\n    /// The path to a file containing the constructor arguments.\n    #[arg(\n        long,\n        value_hint = ValueHint::FilePath,\n        value_name = \"PATH\",\n    )]\n    constructor_args_path: Option<PathBuf>,\n\n    /// Broadcast the transaction.\n    #[arg(long)]\n    pub broadcast: bool,\n\n    /// Verify contract after creation.\n    #[arg(long)]\n    verify: bool,\n\n    /// Send via `eth_sendTransaction` using the `--from` argument or `$ETH_FROM` as sender\n    #[arg(long, requires = \"from\")]\n    unlocked: bool,\n\n    /// Prints the standard json compiler input if `--verify` is provided.\n    ///\n    /// The standard json compiler input can be used to manually submit contract verification in\n    /// the browser.\n    #[arg(long, requires = \"verify\")]\n    show_standard_json_input: bool,\n\n    /// Timeout to use for broadcasting transactions.\n    #[arg(long, env = \"ETH_TIMEOUT\")]\n    pub timeout: Option<u64>,\n\n    #[command(flatten)]\n    build: BuildOpts,\n\n    #[command(flatten)]\n    tx: TransactionOpts,\n\n    #[command(flatten)]\n    eth: EthereumOpts,\n\n    #[command(flatten)]\n    pub verifier: VerifierArgs,\n\n    #[command(flatten)]\n    retry: RetryArgs,\n}\n\nimpl CreateArgs {\n    /// Executes the command to create a contract\n    pub async fn run(self) -> Result<()> {\n        if self.tx.tempo.is_tempo() {\n            self.run_generic::<TempoNetwork>().await\n        } else {\n            self.run_generic::<AnyNetwork>().await\n        }\n    }\n\n    async fn run_generic<N: Network>(mut self) -> Result<()>\n    where\n        N::TxEnvelope: From<Signed<N::UnsignedTx>>,\n        N::UnsignedTx: SignableTransaction<Signature>,\n        N::TransactionRequest: FoundryTransactionBuilder<N> + serde::Serialize,\n        N::ReceiptResponse: serde::Serialize,\n    {\n        let mut config = self.load_config()?;\n\n        // Install missing dependencies.\n        if install::install_missing_dependencies(&mut config).await && config.auto_detect_remappings\n        {\n            // need to re-configure here to also catch additional remappings\n            config = self.load_config()?;\n        }\n\n        // Find Project & Compile\n        let project = config.project()?;\n\n        let target_path = if let Some(ref mut path) = self.contract.path {\n            canonicalize(project.root().join(path))?\n        } else {\n            project.find_contract_path(&self.contract.name)?\n        };\n\n        let output = compile::compile_target(&target_path, &project, shell::is_json())?;\n\n        let (abi, bin, id) = find_contract_artifacts(output, &target_path, &self.contract.name)?;\n\n        let bin = match bin.object {\n            BytecodeObject::Bytecode(_) => bin.object,\n            _ => {\n                let link_refs = bin\n                    .link_references\n                    .iter()\n                    .flat_map(|(path, names)| {\n                        names.keys().map(move |name| format!(\"\\t{name}: {path}\"))\n                    })\n                    .collect::<Vec<String>>()\n                    .join(\"\\n\");\n                eyre::bail!(\n                    \"Dynamic linking not supported in `create` command - deploy the following library contracts first, then provide the address to link at compile time\\n{}\",\n                    link_refs\n                )\n            }\n        };\n\n        // Add arguments to constructor\n        let params = if let Some(constructor) = &abi.constructor {\n            let constructor_args =\n                self.constructor_args_path.clone().map(read_constructor_args_file).transpose()?;\n            self.parse_constructor_args(\n                constructor,\n                constructor_args.as_deref().unwrap_or(&self.constructor_args),\n            )?\n        } else {\n            vec![]\n        };\n\n        let provider = ProviderBuilder::<N>::from_config(&config)?.build()?;\n\n        // respect chain, if set explicitly via cmd args\n        let chain_id = if let Some(chain_id) = self.chain_id() {\n            chain_id\n        } else {\n            provider.get_chain_id().await?\n        };\n\n        // Whether to broadcast the transaction or not\n        let dry_run = !self.broadcast;\n\n        if self.unlocked {\n            // Deploy with unlocked account\n            let sender = self.eth.wallet.from.expect(\"required\");\n            self.deploy(\n                abi,\n                bin,\n                params,\n                provider,\n                chain_id,\n                sender,\n                config.transaction_timeout,\n                id,\n                dry_run,\n            )\n            .await\n        } else {\n            // Deploy with signer\n            let signer = self.eth.wallet.signer().await?;\n            let deployer = signer.address();\n            let provider = AlloyProviderBuilder::<_, _, N>::default()\n                .wallet(EthereumWallet::new(signer))\n                .connect_provider(provider);\n            self.deploy(\n                abi,\n                bin,\n                params,\n                provider,\n                chain_id,\n                deployer,\n                config.transaction_timeout,\n                id,\n                dry_run,\n            )\n            .await\n        }\n    }\n\n    /// Returns the provided chain id, if any.\n    fn chain_id(&self) -> Option<u64> {\n        self.eth.etherscan.chain.map(|chain| chain.id())\n    }\n\n    /// Ensures the verify command can be executed.\n    ///\n    /// This is supposed to check any things that might go wrong when preparing a verify request\n    /// before the contract is deployed. This should prevent situations where a contract is deployed\n    /// successfully, but we fail to prepare a verify request which would require manual\n    /// verification.\n    async fn verify_preflight_check(\n        &self,\n        constructor_args: Option<String>,\n        chain: u64,\n        id: &ArtifactId,\n    ) -> Result<()> {\n        // NOTE: this does not represent the same `VerifyArgs` that would be sent after deployment,\n        // since we don't know the address yet.\n        let mut verify = VerifyArgs {\n            address: Default::default(),\n            contract: Some(self.contract.clone()),\n            compiler_version: Some(id.version.to_string()),\n            constructor_args,\n            constructor_args_path: None,\n            no_auto_detect: false,\n            use_solc: None,\n            num_of_optimizations: None,\n            etherscan: EtherscanOpts {\n                key: self.eth.etherscan.key.clone(),\n                chain: Some(chain.into()),\n            },\n            rpc: Default::default(),\n            flatten: false,\n            force: false,\n            skip_is_verified_check: true,\n            watch: true,\n            retry: self.retry,\n            libraries: self.build.libraries.clone(),\n            root: None,\n            verifier: self.verifier.clone(),\n            via_ir: self.build.via_ir,\n            evm_version: self.build.compiler.evm_version,\n            show_standard_json_input: self.show_standard_json_input,\n            guess_constructor_args: false,\n            compilation_profile: Some(id.profile.to_string()),\n            language: None,\n            creation_transaction_hash: None,\n        };\n\n        // Check config for Etherscan API Keys to avoid preflight check failing if no\n        // ETHERSCAN_API_KEY value set.\n        let config = verify.load_config()?;\n        verify.etherscan.key =\n            config.get_etherscan_config_with_chain(Some(chain.into()))?.map(|c| c.key);\n\n        let context = verify.resolve_context().await?;\n\n        verify.verification_provider()?.preflight_verify_check(verify, context).await?;\n        Ok(())\n    }\n\n    /// Deploys the contract\n    #[expect(clippy::too_many_arguments)]\n    async fn deploy<N: Network, P: Provider<N>>(\n        self,\n        abi: JsonAbi,\n        bin: BytecodeObject,\n        args: Vec<DynSolValue>,\n        provider: P,\n        chain: u64,\n        deployer_address: Address,\n        timeout: u64,\n        id: ArtifactId,\n        dry_run: bool,\n    ) -> Result<()>\n    where\n        N::TransactionRequest: FoundryTransactionBuilder<N> + serde::Serialize,\n        N::ReceiptResponse: serde::Serialize,\n    {\n        let bin = bin.into_bytes().unwrap_or_default();\n        if bin.is_empty() {\n            eyre::bail!(\"no bytecode found in bin object for {}\", self.contract.name)\n        }\n\n        let provider = Arc::new(provider);\n        let factory =\n            ContractFactory::<N, _>::new(abi.clone(), bin.clone(), provider.clone(), timeout);\n\n        let is_args_empty = args.is_empty();\n        let mut deployer =\n            factory.deploy_tokens(args.clone()).context(\"failed to deploy contract\").map_err(|e| {\n                if is_args_empty {\n                    e.wrap_err(\"no arguments provided for contract constructor; consider --constructor-args or --constructor-args-path\")\n                } else {\n                    e\n                }\n            })?;\n        let is_legacy = self.tx.legacy || Chain::from(chain).is_legacy();\n\n        deployer.tx.set_from(deployer_address);\n        deployer.tx.set_chain_id(chain);\n        // `to` field must be set explicitly, cannot be None.\n        if deployer.tx.to().is_none() {\n            deployer.tx.set_create();\n        }\n\n        // Apply user-provided gas, fee, nonce, and Tempo options.\n        self.tx.apply::<N>(&mut deployer.tx, is_legacy);\n\n        // Fetch defaults from provider for values not specified by user.\n        if self.tx.nonce.is_none() && !self.tx.tempo.expiring_nonce {\n            deployer.tx.set_nonce(provider.get_transaction_count(deployer_address).await?);\n        }\n\n        // set access list if specified\n        if let Some(access_list) = match self.tx.access_list {\n            None => None,\n            Some(None) => Some(provider.create_access_list(&deployer.tx).await?.access_list),\n            Some(Some(ref access_list)) => Some(access_list.clone()),\n        } {\n            deployer.tx.set_access_list(access_list);\n        }\n\n        if self.tx.gas_limit.is_none() {\n            deployer.tx.set_gas_limit(provider.estimate_gas(deployer.tx.clone()).await?);\n        }\n\n        if is_legacy {\n            if self.tx.gas_price.is_none() {\n                deployer.tx.set_gas_price(provider.get_gas_price().await?);\n            }\n        } else if self.tx.gas_price.is_none() || self.tx.priority_gas_price.is_none() {\n            let estimate = provider.estimate_eip1559_fees().await.wrap_err(\"Failed to estimate EIP1559 fees. This chain might not support EIP1559, try adding --legacy to your command.\")?;\n            if self.tx.priority_gas_price.is_none() {\n                deployer.tx.set_max_priority_fee_per_gas(estimate.max_priority_fee_per_gas);\n            }\n            if self.tx.gas_price.is_none() {\n                deployer.tx.set_max_fee_per_gas(estimate.max_fee_per_gas);\n            }\n        }\n\n        // Before we actually deploy the contract we try check if the verify settings are valid\n        let mut constructor_args = None;\n        if self.verify {\n            if !args.is_empty() {\n                let encoded_args = abi\n                    .constructor()\n                    .ok_or_else(|| eyre::eyre!(\"could not find constructor\"))?\n                    .abi_encode_input(&args)?;\n                constructor_args = Some(hex::encode(encoded_args));\n            }\n\n            self.verify_preflight_check(constructor_args.clone(), chain, &id).await?;\n        }\n\n        if dry_run {\n            if !shell::is_json() {\n                sh_warn!(\"Dry run enabled, not broadcasting transaction\\n\")?;\n\n                sh_println!(\"Contract: {}\", self.contract.name)?;\n                sh_println!(\n                    \"Transaction: {}\",\n                    serde_json::to_string_pretty(&deployer.tx.clone())?\n                )?;\n                sh_println!(\"ABI: {}\\n\", serde_json::to_string_pretty(&abi)?)?;\n\n                sh_warn!(\n                    \"To broadcast this transaction, add --broadcast to the previous command. See forge create --help for more.\"\n                )?;\n            } else {\n                let output = json!({\n                    \"contract\": self.contract.name,\n                    \"transaction\": &deployer.tx,\n                    \"abi\":&abi\n                });\n                sh_println!(\"{}\", serde_json::to_string_pretty(&output)?)?;\n            }\n\n            return Ok(());\n        }\n\n        // Deploy the actual contract\n        let (deployed_contract, receipt) = deployer.send_with_receipt().await?;\n\n        let address = deployed_contract;\n        let tx_hash = receipt.transaction_hash();\n        if shell::is_json() {\n            let output = json!({\n                \"deployer\": deployer_address.to_string(),\n                \"deployedTo\": address.to_string(),\n                \"transactionHash\": tx_hash\n            });\n            sh_println!(\"{}\", serde_json::to_string_pretty(&output)?)?;\n        } else {\n            sh_println!(\"Deployer: {deployer_address}\")?;\n            sh_println!(\"Deployed to: {address}\")?;\n            sh_println!(\"Transaction hash: {tx_hash:?}\")?;\n        };\n\n        if !self.verify {\n            return Ok(());\n        }\n\n        sh_println!(\"Starting contract verification...\")?;\n\n        let num_of_optimizations = if let Some(optimizer) = self.build.compiler.optimize {\n            if optimizer { Some(self.build.compiler.optimizer_runs.unwrap_or(200)) } else { None }\n        } else {\n            self.build.compiler.optimizer_runs\n        };\n\n        let verify = VerifyArgs {\n            address,\n            contract: Some(self.contract),\n            compiler_version: Some(id.version.to_string()),\n            constructor_args,\n            constructor_args_path: None,\n            no_auto_detect: false,\n            use_solc: None,\n            num_of_optimizations,\n            etherscan: EtherscanOpts { key: self.eth.etherscan.key(), chain: Some(chain.into()) },\n            rpc: Default::default(),\n            flatten: false,\n            force: false,\n            skip_is_verified_check: true,\n            watch: true,\n            retry: self.retry,\n            libraries: self.build.libraries.clone(),\n            root: None,\n            verifier: self.verifier,\n            via_ir: self.build.via_ir,\n            evm_version: self.build.compiler.evm_version,\n            show_standard_json_input: self.show_standard_json_input,\n            guess_constructor_args: false,\n            compilation_profile: Some(id.profile.to_string()),\n            language: None,\n            creation_transaction_hash: Some(tx_hash),\n        };\n        sh_println!(\"Waiting for {} to detect contract deployment...\", verify.verifier.verifier)?;\n        verify.run().await\n    }\n\n    /// Parses the given constructor arguments into a vector of `DynSolValue`s, by matching them\n    /// against the constructor's input params.\n    ///\n    /// Returns a list of parsed values that match the constructor's input params.\n    fn parse_constructor_args(\n        &self,\n        constructor: &Constructor,\n        constructor_args: &[String],\n    ) -> Result<Vec<DynSolValue>> {\n        if constructor.inputs.len() != constructor_args.len() {\n            eyre::bail!(\n                \"Constructor argument count mismatch: expected {} but got {}\",\n                constructor.inputs.len(),\n                constructor_args.len()\n            );\n        }\n\n        let mut params = Vec::with_capacity(constructor.inputs.len());\n        for (input, arg) in constructor.inputs.iter().zip(constructor_args) {\n            // resolve the input type directly\n            let ty = input\n                .resolve()\n                .wrap_err_with(|| format!(\"Could not resolve constructor arg: input={input}\"))?;\n            params.push((ty, arg));\n        }\n        let params = params.iter().map(|(ty, arg)| (ty, arg.as_str()));\n        parse_tokens(params).map_err(Into::into)\n    }\n}\n\nimpl figment::Provider for CreateArgs {\n    fn metadata(&self) -> Metadata {\n        Metadata::named(\"Create Args Provider\")\n    }\n\n    fn data(&self) -> Result<Map<Profile, Dict>, figment::Error> {\n        let mut dict = Dict::default();\n        if let Some(timeout) = self.timeout {\n            dict.insert(\"transaction_timeout\".to_string(), timeout.into());\n        }\n        Ok(Map::from([(Config::selected_profile(), dict)]))\n    }\n}\n\n/// `ContractFactory` is a [`DeploymentTxFactory`] object with an\n/// [`Arc`] middleware. This type alias exists to preserve backwards\n/// compatibility with less-abstract Contracts.\n///\n/// For full usage docs, see [`DeploymentTxFactory`].\npub type ContractFactory<N, P> = DeploymentTxFactory<N, P>;\n\n/// Helper which manages the deployment transaction of a smart contract. It\n/// wraps a deployment transaction, and retrieves the contract address output\n/// by it.\n#[derive(Debug)]\n#[must_use = \"ContractDeploymentTx does nothing unless you `send` it\"]\npub struct ContractDeploymentTx<N: Network, P, C> {\n    /// the actual deployer, exposed for overriding the defaults\n    pub deployer: Deployer<N, P>,\n    /// marker for the `Contract` type to create afterwards\n    ///\n    /// this type will be used to construct it via `From::from(Contract)`\n    _contract: PhantomData<C>,\n}\n\nimpl<N: Network, P: Clone, C> Clone for ContractDeploymentTx<N, P, C> {\n    fn clone(&self) -> Self {\n        Self { deployer: self.deployer.clone(), _contract: self._contract }\n    }\n}\n\nimpl<N: Network, P, C> From<Deployer<N, P>> for ContractDeploymentTx<N, P, C> {\n    fn from(deployer: Deployer<N, P>) -> Self {\n        Self { deployer, _contract: PhantomData }\n    }\n}\n\n/// Helper which manages the deployment transaction of a smart contract\n#[derive(Clone, Debug)]\n#[must_use = \"Deployer does nothing unless you `send` it\"]\npub struct Deployer<N: Network, P> {\n    /// The deployer's transaction, exposed for overriding the defaults\n    pub tx: N::TransactionRequest,\n    client: P,\n    confs: usize,\n    timeout: u64,\n}\n\nimpl<N: Network, P: Provider<N>> Deployer<N, P> {\n    /// Broadcasts the contract deployment transaction and after waiting for it to\n    /// be sufficiently confirmed (default: 1), it returns a tuple with the [`Address`] at the\n    /// deployed contract's address and the corresponding receipt.\n    pub async fn send_with_receipt(\n        self,\n    ) -> Result<(Address, N::ReceiptResponse), ContractDeploymentError> {\n        let receipt = self\n            .client\n            .borrow()\n            .send_transaction(self.tx)\n            .await?\n            .with_required_confirmations(self.confs as u64)\n            .with_timeout(Some(Duration::from_secs(self.timeout)))\n            .get_receipt()\n            .await?;\n\n        let address =\n            receipt.contract_address().ok_or(ContractDeploymentError::ContractNotDeployed)?;\n\n        Ok((address, receipt))\n    }\n}\n\n/// To deploy a contract to the Ethereum network, a [`ContractFactory`] can be\n/// created which manages the Contract bytecode and Application Binary Interface\n/// (ABI), usually generated from the Solidity compiler.\n#[derive(Clone, Debug)]\npub struct DeploymentTxFactory<N: Network, P> {\n    client: P,\n    abi: JsonAbi,\n    bytecode: Bytes,\n    timeout: u64,\n    _network: PhantomData<N>,\n}\n\nimpl<N: Network, P: Provider<N> + Clone> DeploymentTxFactory<N, P> {\n    /// Creates a factory for deployment of the Contract with bytecode, and the\n    /// constructor defined in the abi. The client will be used to send any deployment\n    /// transaction.\n    pub fn new(abi: JsonAbi, bytecode: Bytes, client: P, timeout: u64) -> Self {\n        Self { client, abi, bytecode, timeout, _network: PhantomData }\n    }\n\n    /// Create a deployment tx using the provided tokens as constructor\n    /// arguments\n    pub fn deploy_tokens(\n        self,\n        params: Vec<DynSolValue>,\n    ) -> Result<Deployer<N, P>, ContractDeploymentError> {\n        // Encode the constructor args & concatenate with the bytecode if necessary\n        let data: Bytes = match (self.abi.constructor(), params.is_empty()) {\n            (None, false) => return Err(ContractDeploymentError::ConstructorError),\n            (None, true) => self.bytecode.clone(),\n            (Some(constructor), _) => {\n                let input: Bytes = constructor\n                    .abi_encode_input(&params)\n                    .map_err(ContractDeploymentError::DetokenizationError)?\n                    .into();\n                // Concatenate the bytecode and abi-encoded constructor call.\n                self.bytecode.iter().copied().chain(input).collect()\n            }\n        };\n\n        // create the tx object. Since we're deploying a contract, `to` is `None`\n        let mut tx = N::TransactionRequest::default();\n        tx.set_input(data);\n\n        Ok(Deployer { client: self.client.clone(), tx, confs: 1, timeout: self.timeout })\n    }\n}\n\n#[derive(thiserror::Error, Debug)]\n/// An Error which is thrown when interacting with a smart contract\npub enum ContractDeploymentError {\n    #[error(\"constructor is not defined in the ABI\")]\n    ConstructorError,\n    #[error(transparent)]\n    DetokenizationError(#[from] alloy_dyn_abi::Error),\n    #[error(\"contract was not deployed\")]\n    ContractNotDeployed,\n    #[error(transparent)]\n    RpcError(#[from] TransportError),\n}\n\nimpl From<PendingTransactionError> for ContractDeploymentError {\n    fn from(_err: PendingTransactionError) -> Self {\n        Self::ContractNotDeployed\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use alloy_primitives::I256;\n\n    #[test]\n    fn can_parse_create() {\n        let args: CreateArgs = CreateArgs::parse_from([\n            \"foundry-cli\",\n            \"src/Domains.sol:Domains\",\n            \"--verify\",\n            \"--retries\",\n            \"10\",\n            \"--delay\",\n            \"30\",\n        ]);\n        assert_eq!(args.retry.retries, 10);\n        assert_eq!(args.retry.delay, 30);\n    }\n    #[test]\n    fn can_parse_chain_id() {\n        let args: CreateArgs = CreateArgs::parse_from([\n            \"foundry-cli\",\n            \"src/Domains.sol:Domains\",\n            \"--verify\",\n            \"--retries\",\n            \"10\",\n            \"--delay\",\n            \"30\",\n            \"--chain-id\",\n            \"9999\",\n        ]);\n        assert_eq!(args.chain_id(), Some(9999));\n    }\n\n    #[test]\n    fn test_parse_constructor_args() {\n        let args: CreateArgs = CreateArgs::parse_from([\n            \"foundry-cli\",\n            \"src/Domains.sol:Domains\",\n            \"--constructor-args\",\n            \"Hello\",\n        ]);\n        let constructor: Constructor = serde_json::from_str(r#\"{\"type\":\"constructor\",\"inputs\":[{\"name\":\"_name\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"nonpayable\"}\"#).unwrap();\n        let params = args.parse_constructor_args(&constructor, &args.constructor_args).unwrap();\n        assert_eq!(params, vec![DynSolValue::String(\"Hello\".to_string())]);\n    }\n\n    #[test]\n    fn test_parse_tuple_constructor_args() {\n        let args: CreateArgs = CreateArgs::parse_from([\n            \"foundry-cli\",\n            \"src/Domains.sol:Domains\",\n            \"--constructor-args\",\n            \"[(1,2), (2,3), (3,4)]\",\n        ]);\n        let constructor: Constructor = serde_json::from_str(r#\"{\"type\":\"constructor\",\"inputs\":[{\"name\":\"_points\",\"type\":\"tuple[]\",\"internalType\":\"struct Point[]\",\"components\":[{\"name\":\"x\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"y\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]}],\"stateMutability\":\"nonpayable\"}\"#).unwrap();\n        let _params = args.parse_constructor_args(&constructor, &args.constructor_args).unwrap();\n    }\n\n    #[test]\n    fn test_parse_int_constructor_args() {\n        let args: CreateArgs = CreateArgs::parse_from([\n            \"foundry-cli\",\n            \"src/Domains.sol:Domains\",\n            \"--constructor-args\",\n            \"-5\",\n        ]);\n        let constructor: Constructor = serde_json::from_str(r#\"{\"type\":\"constructor\",\"inputs\":[{\"name\":\"_name\",\"type\":\"int256\",\"internalType\":\"int256\"}],\"stateMutability\":\"nonpayable\"}\"#).unwrap();\n        let params = args.parse_constructor_args(&constructor, &args.constructor_args).unwrap();\n        assert_eq!(params, vec![DynSolValue::Int(I256::unchecked_from(-5), 256)]);\n    }\n}\n"
  },
  {
    "path": "crates/forge/src/cmd/doc/mod.rs",
    "content": "use super::watch::WatchArgs;\nuse clap::{Parser, ValueHint};\nuse eyre::Result;\nuse forge_doc::{\n    ContractInheritance, Deployments, DocBuilder, GitSource, InferInlineHyperlinks, Inheritdoc,\n};\nuse foundry_cli::opts::GH_REPO_PREFIX_REGEX;\nuse foundry_common::compile::ProjectCompiler;\nuse foundry_config::{Config, load_config_with_root};\nuse std::{path::PathBuf, process::Command};\n\nmod server;\nuse server::Server;\n\n#[derive(Clone, Debug, Parser)]\npub struct DocArgs {\n    /// The project's root path.\n    ///\n    /// By default root of the Git repository, if in one,\n    /// or the current working directory.\n    #[arg(long, value_hint = ValueHint::DirPath, value_name = \"PATH\")]\n    pub root: Option<PathBuf>,\n\n    /// The doc's output path.\n    ///\n    /// By default, it is the `docs/` in project root.\n    #[arg(\n        long,\n        short,\n        value_hint = ValueHint::DirPath,\n        value_name = \"PATH\",\n    )]\n    out: Option<PathBuf>,\n\n    /// Build the `mdbook` from generated files.\n    #[arg(long, short)]\n    build: bool,\n\n    /// Serve the documentation.\n    #[arg(long, short)]\n    serve: bool,\n\n    /// Open the documentation in a browser after serving.\n    #[arg(long, requires = \"serve\")]\n    open: bool,\n\n    /// Hostname for serving documentation.\n    #[arg(long, requires = \"serve\")]\n    hostname: Option<String>,\n\n    #[command(flatten)]\n    pub watch: WatchArgs,\n\n    /// Port for serving documentation.\n    #[arg(long, short, requires = \"serve\")]\n    port: Option<usize>,\n\n    /// The relative path to the `hardhat-deploy` or `forge-deploy` artifact directory. Leave blank\n    /// for default.\n    #[arg(long)]\n    deployments: Option<Option<PathBuf>>,\n\n    /// Whether to create docs for external libraries.\n    #[arg(long, short)]\n    include_libraries: bool,\n}\n\nimpl DocArgs {\n    pub async fn run(self) -> Result<()> {\n        let config = self.config()?;\n        let root = &config.root;\n        let project = config.project()?;\n        let compiler = ProjectCompiler::new().quiet(true);\n        let mut output = compiler.compile(&project)?;\n        let compiler = output.parser_mut().solc_mut().compiler_mut();\n\n        let mut doc_config = config.doc;\n        if let Some(out) = self.out {\n            doc_config.out = out;\n        }\n        if doc_config.repository.is_none() {\n            // Attempt to read repo from git\n            if let Ok(output) = Command::new(\"git\").args([\"remote\", \"get-url\", \"origin\"]).output()\n                && !output.stdout.is_empty()\n            {\n                let remote = String::from_utf8(output.stdout)?.trim().to_owned();\n                if let Some(captures) = GH_REPO_PREFIX_REGEX.captures(&remote) {\n                    let brand = captures.name(\"brand\").unwrap().as_str();\n                    let tld = captures.name(\"tld\").unwrap().as_str();\n                    let project = GH_REPO_PREFIX_REGEX.replace(&remote, \"\");\n                    doc_config.repository =\n                        Some(format!(\"https://{brand}.{tld}/{}\", project.trim_end_matches(\".git\")));\n                }\n            }\n        }\n\n        let commit = foundry_cli::utils::Git::new(root).commit_hash(false, \"HEAD\").ok();\n\n        let mut builder = DocBuilder::new(\n            root.clone(),\n            project.paths.sources,\n            project.paths.libraries,\n            self.include_libraries,\n        )\n        .with_should_build(self.build)\n        .with_config(doc_config.clone())\n        .with_fmt(config.fmt)\n        .with_preprocessor(ContractInheritance { include_libraries: self.include_libraries })\n        .with_preprocessor(Inheritdoc::default())\n        .with_preprocessor(InferInlineHyperlinks::default())\n        .with_preprocessor(GitSource {\n            root: root.clone(),\n            commit,\n            repository: doc_config.repository.clone(),\n        });\n\n        // If deployment docgen is enabled, add the [Deployments] preprocessor\n        if let Some(deployments) = self.deployments {\n            builder = builder.with_preprocessor(Deployments { root: root.clone(), deployments });\n        }\n\n        builder.build(compiler)?;\n\n        if self.serve {\n            Server::new(doc_config.out)\n                .with_hostname(self.hostname.unwrap_or_else(|| \"localhost\".into()))\n                .with_port(self.port.unwrap_or(3000))\n                .open(self.open)\n                .serve()?;\n        }\n\n        Ok(())\n    }\n\n    /// Returns whether watch mode is enabled\n    pub fn is_watch(&self) -> bool {\n        self.watch.watch.is_some()\n    }\n\n    pub fn config(&self) -> Result<Config> {\n        load_config_with_root(self.root.as_deref())\n    }\n}\n"
  },
  {
    "path": "crates/forge/src/cmd/doc/server.rs",
    "content": "use axum::{Router, routing::get_service};\nuse forge_doc::mdbook_driver::MDBook;\nuse std::{\n    io,\n    net::{SocketAddr, ToSocketAddrs},\n    path::PathBuf,\n};\nuse tower_http::services::{ServeDir, ServeFile};\n\n/// The HTTP endpoint for the websocket used to trigger reloads when a file changes.\nconst LIVE_RELOAD_ENDPOINT: &str = \"/__livereload\";\n\n/// Basic mdbook server. Given a path, hostname and port, serves the mdbook.\n#[derive(Debug)]\npub struct Server {\n    path: PathBuf,\n    hostname: String,\n    port: usize,\n    open: bool,\n}\n\nimpl Default for Server {\n    fn default() -> Self {\n        Self { path: PathBuf::default(), hostname: \"localhost\".to_owned(), port: 3000, open: false }\n    }\n}\n\nimpl Server {\n    /// Create a new instance.\n    pub fn new(path: PathBuf) -> Self {\n        Self { path, ..Default::default() }\n    }\n\n    /// Set the host to serve on.\n    pub fn with_hostname(mut self, hostname: String) -> Self {\n        self.hostname = hostname;\n        self\n    }\n\n    /// Set the port to serve on.\n    pub fn with_port(mut self, port: usize) -> Self {\n        self.port = port;\n        self\n    }\n\n    /// Set whether to open the browser after serving.\n    pub fn open(mut self, open: bool) -> Self {\n        self.open = open;\n        self\n    }\n\n    /// Serve the mdbook.\n    pub fn serve(self) -> eyre::Result<()> {\n        let mut book =\n            MDBook::load(&self.path).map_err(|err| eyre::eyre!(\"failed to load book: {err:?}\"))?;\n\n        let reload = LIVE_RELOAD_ENDPOINT.strip_prefix('/').unwrap();\n        book.config.set(\"output.html.live-reload-endpoint\", reload).unwrap();\n        // Override site-url for local serving of the 404 file\n        book.config.set(\"output.html.site-url\", \"/\").unwrap();\n\n        book.build().map_err(|err| eyre::eyre!(\"failed to build book: {err:?}\"))?;\n\n        let address = format!(\"{}:{}\", self.hostname, self.port);\n        let sockaddr: SocketAddr = address\n            .to_socket_addrs()?\n            .next()\n            .ok_or_else(|| eyre::eyre!(\"no address found for {}\", address))?;\n        let build_dir = book.build_dir_for(\"html\");\n        let file_404 = book\n            .config\n            .html_config()\n            .map(|c| c.get_404_output_file())\n            .unwrap_or_else(|| \"404.html\".to_string());\n\n        let serving_url = format!(\"http://{address}\");\n        sh_println!(\"Serving on: {serving_url}\")?;\n\n        let thread_handle = std::thread::spawn(move || serve(build_dir, sockaddr, &file_404));\n\n        if self.open {\n            open(serving_url);\n        }\n\n        match thread_handle.join() {\n            Ok(r) => r.map_err(Into::into),\n            Err(e) => std::panic::resume_unwind(e),\n        }\n    }\n}\n\n#[tokio::main]\nasync fn serve(build_dir: PathBuf, address: SocketAddr, file_404: &str) -> io::Result<()> {\n    let file_404 = build_dir.join(file_404);\n    let svc = ServeDir::new(build_dir).not_found_service(ServeFile::new(file_404));\n    let app = Router::new().fallback_service(get_service(svc));\n    let tcp_listener = tokio::net::TcpListener::bind(address).await?;\n    axum::serve(tcp_listener, app.into_make_service()).await\n}\n\nfn open<P: AsRef<std::ffi::OsStr>>(path: P) {\n    info!(\"Opening web browser\");\n    if let Err(e) = opener::open(path) {\n        error!(\"Error opening web browser: {}\", e);\n    }\n}\n"
  },
  {
    "path": "crates/forge/src/cmd/eip712.rs",
    "content": "use alloy_primitives::{B256, keccak256};\nuse clap::{Parser, ValueHint};\nuse eyre::Result;\nuse foundry_cli::{opts::BuildOpts, utils::LoadConfig};\nuse foundry_common::{compile::ProjectCompiler, shell};\nuse serde::Serialize;\nuse solar::sema::{\n    Gcx, Hir,\n    hir::StructId,\n    ty::{Ty, TyKind},\n};\nuse std::{\n    collections::BTreeMap,\n    fmt::{Display, Formatter, Result as FmtResult, Write},\n    ops::ControlFlow,\n    path::{Path, PathBuf},\n};\n\nfoundry_config::impl_figment_convert!(Eip712Args, build);\n\n/// CLI arguments for `forge eip712`.\n#[derive(Clone, Debug, Parser)]\npub struct Eip712Args {\n    /// The path to the file from which to read struct definitions.\n    #[arg(value_hint = ValueHint::FilePath, value_name = \"PATH\")]\n    pub target_path: PathBuf,\n\n    #[command(flatten)]\n    build: BuildOpts,\n}\n\n#[derive(Debug, Serialize)]\nstruct Eip712Output {\n    path: String,\n    #[serde(rename = \"type\")]\n    ty: String,\n    hash: B256,\n}\n\nimpl Display for Eip712Output {\n    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {\n        writeln!(f, \"{}:\", self.path)?;\n        writeln!(f, \" - type: {}\", self.ty)?;\n        writeln!(f, \" - hash: {}\", self.hash)\n    }\n}\n\nimpl Eip712Args {\n    pub fn run(self) -> Result<()> {\n        let config = self.build.load_config()?;\n        let project = config.solar_project()?;\n        let mut output = ProjectCompiler::new().files([self.target_path]).compile(&project)?;\n        let compiler = output.parser_mut().solc_mut().compiler_mut();\n        compiler.enter_mut(|compiler| -> Result<()> {\n            let Ok(ControlFlow::Continue(())) = compiler.lower_asts() else { return Ok(()) };\n            let gcx = compiler.gcx();\n            let resolver = Resolver::new(gcx);\n\n            let outputs = resolver\n                .struct_ids()\n                .filter_map(|id| {\n                    let resolved = resolver.resolve_struct_eip712(id)?;\n                    Some(Eip712Output {\n                        path: resolver.get_struct_path(id),\n                        hash: keccak256(resolved.as_bytes()),\n                        ty: resolved,\n                    })\n                })\n                .collect::<Vec<_>>();\n\n            if shell::is_json() {\n                sh_println!(\"{json}\", json = serde_json::to_string_pretty(&outputs)?)?;\n            } else {\n                for output in &outputs {\n                    sh_println!(\"{output}\")?;\n                }\n            }\n\n            Ok(())\n        })?;\n\n        // `compiler.sess()` inside of `ProjectCompileOutput` is built with `with_buffer_emitter`.\n        let diags = compiler.sess().dcx.emitted_diagnostics().unwrap();\n        if compiler.sess().dcx.has_errors().is_err() {\n            eyre::bail!(\"{diags}\");\n        } else {\n            let _ = sh_eprint!(\"{diags}\");\n        }\n\n        Ok(())\n    }\n}\n\n/// Generates the EIP-712 `encodeType` string for a given struct.\n///\n/// Requires a reference to the source HIR.\npub struct Resolver<'gcx> {\n    gcx: Gcx<'gcx>,\n}\n\nimpl<'gcx> Resolver<'gcx> {\n    /// Constructs a new [`Resolver`] for the supplied [`Hir`] instance.\n    pub fn new(gcx: Gcx<'gcx>) -> Self {\n        Self { gcx }\n    }\n\n    #[inline]\n    fn hir(&self) -> &'gcx Hir<'gcx> {\n        &self.gcx.hir\n    }\n\n    /// Returns the [`StructId`]s of every user-defined struct in source order.\n    pub fn struct_ids(&self) -> impl Iterator<Item = StructId> {\n        self.hir().strukt_ids()\n    }\n\n    /// Returns the path for a struct, with the format: `file.sol > MyContract > MyStruct`\n    pub fn get_struct_path(&self, id: StructId) -> String {\n        let strukt = self.hir().strukt(id).name.as_str();\n        match self.hir().strukt(id).contract {\n            Some(cid) => {\n                let full_name = self.gcx.contract_fully_qualified_name(cid).to_string();\n                let relevant = Path::new(&full_name)\n                    .file_name()\n                    .and_then(|s| s.to_str())\n                    .unwrap_or(&full_name);\n\n                if let Some((file, contract)) = relevant.rsplit_once(':') {\n                    format!(\"{file} > {contract} > {strukt}\")\n                } else {\n                    format!(\"{relevant} > {strukt}\")\n                }\n            }\n            None => strukt.to_string(),\n        }\n    }\n\n    /// Converts a given struct into its EIP-712 `encodeType` representation.\n    ///\n    /// Returns `None` if the struct, or any of its fields, contains constructs\n    /// not supported by EIP-712 (mappings, function types, errors, etc).\n    pub fn resolve_struct_eip712(&self, id: StructId) -> Option<String> {\n        let mut subtypes = BTreeMap::new();\n        subtypes.insert(self.hir().strukt(id).name.as_str().into(), id);\n        self.resolve_eip712_inner(id, &mut subtypes, true, None)\n    }\n\n    fn resolve_eip712_inner(\n        &self,\n        id: StructId,\n        subtypes: &mut BTreeMap<String, StructId>,\n        append_subtypes: bool,\n        rename: Option<&str>,\n    ) -> Option<String> {\n        let def = self.hir().strukt(id);\n        let mut result = format!(\"{}(\", rename.unwrap_or(def.name.as_str()));\n\n        for (idx, field_id) in def.fields.iter().enumerate() {\n            let field = self.hir().variable(*field_id);\n            let ty = self.resolve_type(self.gcx.type_of_hir_ty(&field.ty), subtypes)?;\n\n            write!(result, \"{ty} {name}\", name = field.name?.as_str()).ok()?;\n\n            if idx < def.fields.len() - 1 {\n                result.push(',');\n            }\n        }\n\n        result.push(')');\n\n        if append_subtypes {\n            for (subtype_name, subtype_id) in\n                subtypes.iter().map(|(name, id)| (name.clone(), *id)).collect::<Vec<_>>()\n            {\n                if subtype_id == id {\n                    continue;\n                }\n                let encoded_subtype =\n                    self.resolve_eip712_inner(subtype_id, subtypes, false, Some(&subtype_name))?;\n\n                result.push_str(&encoded_subtype);\n            }\n        }\n\n        Some(result)\n    }\n\n    fn resolve_type(\n        &self,\n        ty: Ty<'gcx>,\n        subtypes: &mut BTreeMap<String, StructId>,\n    ) -> Option<String> {\n        let ty = ty.peel_refs();\n        match ty.kind {\n            TyKind::Elementary(elem_ty) => Some(elem_ty.to_abi_str().to_string()),\n            TyKind::Array(element_ty, size) => {\n                let inner_type = self.resolve_type(element_ty, subtypes)?;\n                let size = size.to_string();\n                Some(format!(\"{inner_type}[{size}]\"))\n            }\n            TyKind::DynArray(element_ty) => {\n                let inner_type = self.resolve_type(element_ty, subtypes)?;\n                Some(format!(\"{inner_type}[]\"))\n            }\n            TyKind::Udvt(ty, _) => self.resolve_type(ty, subtypes),\n            TyKind::Struct(id) => {\n                let def = self.hir().strukt(id);\n                let name = match subtypes.iter().find(|(_, cached_id)| id == **cached_id) {\n                    Some((name, _)) => name.to_string(),\n                    None => {\n                        // Otherwise, assign new name\n                        let mut i = 0;\n                        let mut name = def.name.as_str().into();\n                        while subtypes.contains_key(&name) {\n                            i += 1;\n                            name = format!(\"{}_{i}\", def.name.as_str());\n                        }\n\n                        subtypes.insert(name.clone(), id);\n\n                        // Recursively resolve fields to populate subtypes\n                        for &field_id in def.fields {\n                            let field_ty = self.gcx.type_of_item(field_id.into());\n                            self.resolve_type(field_ty, subtypes)?;\n                        }\n                        name\n                    }\n                };\n\n                Some(name)\n            }\n            // For now, map enums to `uint8`\n            TyKind::Enum(_) => Some(\"uint8\".to_string()),\n            // For now, map contracts to `address`\n            TyKind::Contract(_) => Some(\"address\".to_string()),\n            // EIP-712 doesn't support tuples (should use structs), functions, mappings, nor errors\n            _ => None,\n        }\n    }\n}\n"
  },
  {
    "path": "crates/forge/src/cmd/flatten.rs",
    "content": "use clap::{Parser, ValueHint};\nuse eyre::Result;\nuse foundry_cli::{\n    opts::{BuildOpts, ProjectPathOpts},\n    utils::LoadConfig,\n};\nuse foundry_common::{flatten, fs};\nuse std::path::PathBuf;\n\n/// CLI arguments for `forge flatten`.\n#[derive(Clone, Debug, Parser)]\npub struct FlattenArgs {\n    /// The path to the contract to flatten.\n    #[arg(value_hint = ValueHint::FilePath, value_name = \"PATH\")]\n    pub target_path: PathBuf,\n\n    /// The path to output the flattened contract.\n    ///\n    /// If not specified, the flattened contract will be output to stdout.\n    #[arg(\n        long,\n        short,\n        value_hint = ValueHint::FilePath,\n        value_name = \"PATH\",\n    )]\n    pub output: Option<PathBuf>,\n\n    #[command(flatten)]\n    project_paths: ProjectPathOpts,\n}\n\nimpl FlattenArgs {\n    pub fn run(self) -> Result<()> {\n        let Self { target_path, output, project_paths } = self;\n\n        // flatten is a subset of `BuildArgs` so we can reuse that to get the config\n        let build = BuildOpts { project_paths, ..Default::default() };\n        let config = build.load_config()?;\n        let project = config.ephemeral_project()?;\n\n        let target_path = dunce::canonicalize(target_path)?;\n        let flattened = flatten(project, &target_path)?;\n\n        match output {\n            Some(output) => {\n                fs::create_dir_all(output.parent().unwrap())?;\n                fs::write(&output, flattened)?;\n                sh_println!(\"Flattened file written at {}\", output.display())?;\n            }\n            None => sh_println!(\"{flattened}\")?,\n        };\n\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "crates/forge/src/cmd/fmt.rs",
    "content": "use super::watch::WatchArgs;\nuse clap::{Parser, ValueHint};\nuse eyre::Result;\nuse foundry_cli::utils::{FoundryPathExt, LoadConfig};\nuse foundry_common::{errors::convert_solar_errors, fs};\nuse foundry_compilers::{compilers::solc::SolcLanguage, solc::SOLC_EXTENSIONS};\nuse foundry_config::{filter::expand_globs, impl_figment_convert_basic};\nuse rayon::prelude::*;\nuse similar::{ChangeTag, TextDiff};\nuse solar::sema::Compiler;\nuse std::{\n    fmt::{self, Write},\n    io,\n    io::Write as _,\n    path::{Path, PathBuf},\n    sync::Arc,\n};\nuse yansi::{Color, Paint, Style};\n\n/// CLI arguments for `forge fmt`.\n#[derive(Clone, Debug, Parser)]\npub struct FmtArgs {\n    /// Path to the file, directory or '-' to read from stdin.\n    #[arg(value_hint = ValueHint::FilePath, value_name = \"PATH\", num_args(1..))]\n    paths: Vec<PathBuf>,\n\n    /// The project's root path.\n    ///\n    /// By default root of the Git repository, if in one,\n    /// or the current working directory.\n    #[arg(long, value_hint = ValueHint::DirPath, value_name = \"PATH\")]\n    root: Option<PathBuf>,\n\n    /// Run in 'check' mode.\n    ///\n    /// Exits with 0 if input is formatted correctly.\n    /// Exits with 1 if formatting is required.\n    #[arg(long)]\n    check: bool,\n\n    /// In 'check' and stdin modes, outputs raw formatted code instead of the diff.\n    #[arg(long, short)]\n    raw: bool,\n\n    #[command(flatten)]\n    pub watch: WatchArgs,\n}\n\nimpl_figment_convert_basic!(FmtArgs);\n\nimpl FmtArgs {\n    pub fn run(self) -> Result<()> {\n        let config = self.load_config()?;\n        let cwd = std::env::current_dir()?;\n\n        // Expand ignore globs and canonicalize from the get go\n        let ignored = expand_globs(&config.root, config.fmt.ignore.iter())?\n            .iter()\n            .flat_map(fs::canonicalize_path)\n            .collect::<Vec<_>>();\n\n        // Expand lib globs separately - we only exclude these during discovery, not explicit paths\n        let libs = expand_globs(&config.root, config.libs.iter().filter_map(|p| p.to_str()))?\n            .iter()\n            .flat_map(fs::canonicalize_path)\n            .collect::<Vec<_>>();\n\n        // Helper to check if a file path is under any ignored or lib directory\n        let is_under_ignored_dir = |file_path: &Path, include_libs: bool| -> bool {\n            let check_against_dir = |dir: &PathBuf| {\n                file_path.starts_with(dir)\n                    || cwd.join(file_path).starts_with(dir)\n                    || fs::canonicalize_path(file_path).is_ok_and(|p| p.starts_with(dir))\n            };\n\n            ignored.iter().any(&check_against_dir)\n                || (include_libs && libs.iter().any(&check_against_dir))\n        };\n\n        let input = match &self.paths[..] {\n            [] => {\n                // Retrieve the project paths, and filter out the ignored ones and libs.\n                let project_paths: Vec<PathBuf> = config\n                    .project_paths::<SolcLanguage>()\n                    .input_files_iter()\n                    .filter(|p| {\n                        !(ignored.contains(p)\n                            || ignored.contains(&cwd.join(p))\n                            || is_under_ignored_dir(p, true))\n                    })\n                    .collect();\n                Input::Paths(project_paths)\n            }\n            [one] if one == Path::new(\"-\") => Input::Stdin,\n            paths => {\n                let mut inputs = Vec::with_capacity(paths.len());\n                for path in paths {\n                    // Check if path is in ignored directories\n                    if !ignored.is_empty()\n                        && ((path.is_absolute() && ignored.contains(path))\n                            || ignored.contains(&cwd.join(path)))\n                    {\n                        continue;\n                    }\n\n                    if path.is_dir() {\n                        // If the input directory is not a lib directory, make sure to ignore libs.\n                        let exclude_libs = !is_under_ignored_dir(path, true);\n                        inputs.extend(\n                            foundry_compilers::utils::source_files_iter(path, SOLC_EXTENSIONS)\n                                .filter(|p| {\n                                    !(ignored.contains(p)\n                                        || ignored.contains(&cwd.join(p))\n                                        || is_under_ignored_dir(p, exclude_libs))\n                                }),\n                        );\n                    } else if path.is_sol() {\n                        // Explicit file paths are always included, even if in a lib\n                        inputs.push(path.to_path_buf());\n                    } else {\n                        warn!(\"Cannot process path {}\", path.display());\n                    }\n                }\n                Input::Paths(inputs)\n            }\n        };\n\n        let mut compiler = Compiler::new(\n            solar::interface::Session::builder().with_buffer_emitter(Default::default()).build(),\n        );\n\n        // Parse, format, and check the diffs.\n        compiler.enter_mut(|compiler| {\n            let mut pcx = compiler.parse();\n            pcx.set_resolve_imports(false);\n            match input {\n                Input::Paths(paths) if paths.is_empty() => {\n                    sh_warn!(\n                        \"Nothing to format.\\n\\\n                         HINT: If you are working outside of the project, \\\n                         try providing paths to your source files: `forge fmt <paths>`\"\n                    )?;\n                    return Ok(());\n                }\n                Input::Paths(paths) => _ = pcx.par_load_files(paths),\n                Input::Stdin => _ = pcx.load_stdin(),\n            }\n            pcx.parse();\n\n            let gcx = compiler.gcx();\n            let fmt_config = Arc::new(config.fmt);\n            let diffs: Vec<String> = gcx\n                .sources\n                .raw\n                .par_iter()\n                .filter_map(|source_unit| {\n                    let path = source_unit.file.name.as_real();\n                    let original = source_unit.file.src.as_str();\n                    let formatted = forge_fmt::format_ast(gcx, source_unit, fmt_config.clone())?;\n                    let from_stdin = path.is_none();\n\n                    // Return formatted code when read from stdin and raw enabled.\n                    // <https://github.com/foundry-rs/foundry/issues/11871>\n                    if from_stdin && self.raw {\n                        return Some(Ok(formatted));\n                    }\n\n                    if original == formatted {\n                        return None;\n                    }\n\n                    if self.check || from_stdin {\n                        let summary = if self.raw {\n                            formatted\n                        } else {\n                            let name = match path {\n                                Some(path) => path\n                                    .strip_prefix(&config.root)\n                                    .unwrap_or(path)\n                                    .display()\n                                    .to_string(),\n                                None => \"stdin\".to_string(),\n                            };\n                            format_diff_summary(&name, &TextDiff::from_lines(original, &formatted))\n                        };\n                        Some(Ok(summary))\n                    } else if let Some(path) = path {\n                        match fs::write(path, formatted) {\n                            Ok(()) => {}\n                            Err(e) => return Some(Err(e.into())),\n                        }\n                        let _ = sh_println!(\"Formatted {}\", path.display());\n                        None\n                    } else {\n                        unreachable!()\n                    }\n                })\n                .collect::<Result<_>>()?;\n\n            if !diffs.is_empty() {\n                // This block is only reached in --check mode when files need formatting.\n                let mut stdout = io::stdout().lock();\n                for (i, diff) in diffs.iter().enumerate() {\n                    if i > 0 {\n                        let _ = stdout.write_all(b\"\\n\");\n                    }\n                    let _ = stdout.write_all(diff.as_bytes());\n                }\n                if self.check {\n                    std::process::exit(1);\n                }\n            }\n\n            convert_solar_errors(compiler.dcx())\n        })\n    }\n\n    /// Returns whether `FmtArgs` was configured with `--watch`\n    pub fn is_watch(&self) -> bool {\n        self.watch.watch.is_some()\n    }\n}\n\n#[derive(Debug)]\nenum Input {\n    Stdin,\n    Paths(Vec<PathBuf>),\n}\n\nstruct Line(Option<usize>);\n\nimpl fmt::Display for Line {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        match self.0 {\n            None => f.write_str(\"    \"),\n            Some(idx) => write!(f, \"{:<4}\", idx + 1),\n        }\n    }\n}\n\nfn format_diff_summary<'a>(name: &str, diff: &'a TextDiff<'a, 'a, '_, str>) -> String {\n    let cap = 128;\n    let mut diff_summary = String::with_capacity(cap);\n\n    let _ = writeln!(diff_summary, \"Diff in {name}:\");\n    for (j, group) in diff.grouped_ops(3).into_iter().enumerate() {\n        if j > 0 {\n            let s =\n                \"--------------------------------------------------------------------------------\";\n            diff_summary.push_str(s);\n        }\n        for op in group {\n            for change in diff.iter_inline_changes(&op) {\n                let dimmed = Style::new().dim();\n                let (sign, s) = match change.tag() {\n                    ChangeTag::Delete => (\"-\", Color::Red.foreground()),\n                    ChangeTag::Insert => (\"+\", Color::Green.foreground()),\n                    ChangeTag::Equal => (\" \", dimmed),\n                };\n\n                let _ = write!(\n                    diff_summary,\n                    \"{}{} |{}\",\n                    Line(change.old_index()).paint(dimmed),\n                    Line(change.new_index()).paint(dimmed),\n                    sign.paint(s.bold()),\n                );\n\n                for (emphasized, value) in change.iter_strings_lossy() {\n                    let s = if emphasized { s.underline().bg(Color::Black) } else { s };\n                    let _ = write!(diff_summary, \"{}\", value.paint(s));\n                }\n\n                if change.missing_newline() {\n                    diff_summary.push('\\n');\n                }\n            }\n        }\n    }\n\n    diff_summary\n}\n"
  },
  {
    "path": "crates/forge/src/cmd/geiger.rs",
    "content": "use clap::{Parser, ValueHint};\nuse eyre::Result;\nuse foundry_cli::opts::BuildOpts;\nuse foundry_config::{DenyLevel, impl_figment_convert};\nuse std::path::PathBuf;\n\n/// CLI arguments for `forge geiger`.\n///\n/// This command is an alias for `forge lint --only-lint unsafe-cheatcode`\n/// and detects usage of unsafe cheat codes in a project and its dependencies.\n#[derive(Clone, Debug, Parser)]\npub struct GeigerArgs {\n    /// Paths to files or directories to detect.\n    #[arg(\n        value_hint = ValueHint::FilePath,\n        value_name = \"PATH\",\n        num_args(0..)\n    )]\n    paths: Vec<PathBuf>,\n\n    #[arg(long, hide = true)]\n    check: bool,\n\n    #[arg(long, hide = true)]\n    full: bool,\n\n    #[command(flatten)]\n    build: BuildOpts,\n}\n\nimpl_figment_convert!(GeigerArgs, build);\n\nimpl GeigerArgs {\n    pub fn run(self) -> Result<()> {\n        // Deprecated flags warnings\n        if self.check {\n            sh_warn!(\"`--check` is deprecated as it's now the default behavior\\n\")?;\n        }\n        if self.full {\n            sh_warn!(\"`--full` is deprecated as reports are not generated anymore\\n\")?;\n        }\n\n        sh_warn!(\n            \"`forge geiger` is deprecated, as it is just an alias for `forge lint --only-lint unsafe-cheatcode`\\n\"\n        )?;\n\n        // Convert geiger command to lint command with specific lint filter\n        let mut lint_args = crate::cmd::lint::LintArgs {\n            paths: self.paths,\n            severity: None,\n            lint: Some(vec![\"unsafe-cheatcode\".to_string()]),\n            build: self.build,\n        };\n        lint_args.build.deny = Some(DenyLevel::Notes);\n\n        // Run the lint command with the geiger-specific configuration\n        lint_args.run()\n    }\n}\n"
  },
  {
    "path": "crates/forge/src/cmd/generate/mod.rs",
    "content": "use clap::{Parser, Subcommand};\nuse eyre::Result;\nuse foundry_common::fs;\nuse std::path::Path;\nuse yansi::Paint;\n\n/// CLI arguments for `forge generate`.\n#[derive(Debug, Parser)]\npub struct GenerateArgs {\n    #[command(subcommand)]\n    pub sub: GenerateSubcommands,\n}\n\n#[derive(Debug, Subcommand)]\npub enum GenerateSubcommands {\n    /// Scaffolds test file for given contract.\n    Test(GenerateTestArgs),\n}\n\n#[derive(Debug, Parser)]\npub struct GenerateTestArgs {\n    /// Contract name for test generation.\n    #[arg(long, short, value_name = \"CONTRACT_NAME\")]\n    pub contract_name: String,\n}\n\nimpl GenerateTestArgs {\n    pub fn run(self) -> Result<()> {\n        sh_warn!(\"`forge generate` is deprecated and will be removed in a future version\")?;\n\n        let contract_name = format_identifier(&self.contract_name, true);\n        let instance_name = format_identifier(&self.contract_name, false);\n\n        // Create the test file content.\n        let test_content = include_str!(\"../../../assets/generated/TestTemplate.t.sol\");\n        let test_content = test_content\n            .replace(\"{contract_name}\", &contract_name)\n            .replace(\"{instance_name}\", &instance_name);\n\n        // Create the test directory if it doesn't exist.\n        fs::create_dir_all(\"test\")?;\n\n        // Define the test file path\n        let test_file_path = Path::new(\"test\").join(format!(\"{contract_name}.t.sol\"));\n\n        // Write the test content to the test file.\n        fs::write(&test_file_path, test_content)?;\n\n        sh_println!(\"{} test file: {}\", \"Generated\".green(), test_file_path.to_str().unwrap())?;\n        Ok(())\n    }\n}\n\n/// Utility function to convert an identifier to pascal or camel case.\nfn format_identifier(input: &str, is_pascal_case: bool) -> String {\n    let mut result = String::new();\n    let mut capitalize_next = is_pascal_case;\n\n    for word in input.split_whitespace() {\n        if !word.is_empty() {\n            let (first, rest) = word.split_at(1);\n            let formatted_word = if capitalize_next {\n                format!(\"{}{}\", first.to_uppercase(), rest)\n            } else {\n                format!(\"{}{}\", first.to_lowercase(), rest)\n            };\n            capitalize_next = true;\n            result.push_str(&formatted_word);\n        }\n    }\n    result\n}\n"
  },
  {
    "path": "crates/forge/src/cmd/init.rs",
    "content": "use super::install::DependencyInstallOpts;\nuse clap::{Parser, ValueHint};\nuse eyre::Result;\nuse foundry_cli::utils::Git;\nuse foundry_common::fs;\nuse foundry_compilers::artifacts::remappings::Remapping;\nuse foundry_config::Config;\nuse std::path::{Path, PathBuf};\nuse yansi::Paint;\n\n/// Supported networks for `forge init --network <NETWORK>`\n#[derive(Clone, Debug, clap::ValueEnum)]\npub enum Networks {\n    Tempo,\n}\n\n/// CLI arguments for `forge init`.\n#[derive(Clone, Debug, Default, Parser)]\npub struct InitArgs {\n    /// The root directory of the new project.\n    #[arg(value_hint = ValueHint::DirPath, default_value = \".\", value_name = \"PATH\")]\n    pub root: PathBuf,\n\n    /// The template to start from.\n    #[arg(long, short)]\n    pub template: Option<String>,\n\n    /// Branch argument that can only be used with template option.\n    /// If not specified, the default branch is used.\n    #[arg(long, short, requires = \"template\")]\n    pub branch: Option<String>,\n\n    /// Do not install dependencies from the network.\n    #[arg(long, conflicts_with = \"template\", visible_alias = \"no-deps\")]\n    pub offline: bool,\n\n    /// Create the project even if the specified root directory is not empty.\n    #[arg(long, conflicts_with = \"template\")]\n    pub force: bool,\n\n    /// Create a .vscode/settings.json file with Solidity settings, and generate a remappings.txt\n    /// file.\n    #[arg(long, conflicts_with = \"template\")]\n    pub vscode: bool,\n\n    /// Initialize a Vyper project template.\n    #[arg(long, conflicts_with = \"template\")]\n    pub vyper: bool,\n\n    /// Initialize a project template for the specified network in Foundry.\n    #[arg(long, short, conflicts_with_all = &[\"vyper\", \"template\"])]\n    pub network: Option<Networks>,\n\n    /// Use the parent git repository instead of initializing a new one.\n    /// Only valid if the target is in a git repository.\n    #[arg(long, conflicts_with = \"template\")]\n    pub use_parent_git: bool,\n\n    /// Do not create example contracts (Counter.sol, Counter.t.sol, Counter.s.sol).\n    #[arg(long, conflicts_with = \"template\")]\n    pub empty: bool,\n\n    #[command(flatten)]\n    pub install: DependencyInstallOpts,\n}\n\nimpl InitArgs {\n    pub async fn run(self) -> Result<()> {\n        let Self {\n            root,\n            template,\n            branch,\n            install,\n            offline,\n            force,\n            vscode,\n            use_parent_git,\n            vyper,\n            network,\n            empty,\n        } = self;\n        let DependencyInstallOpts { shallow, no_git, commit } = install;\n\n        let tempo = matches!(network, Some(Networks::Tempo));\n\n        // create the root dir if it does not exist\n        if !root.exists() {\n            fs::create_dir_all(&root)?;\n        }\n        let root = dunce::canonicalize(root)?;\n        let git = Git::new(&root).shallow(shallow);\n\n        // if a template is provided, then this command initializes a git repo,\n        // fetches the template repo, and resets the git history to the head of the fetched\n        // repo with no other history\n        if let Some(template) = template {\n            let template = if template.contains(\"://\") {\n                template\n            } else if template.starts_with(\"github.com/\") {\n                \"https://\".to_string() + &template\n            } else {\n                \"https://github.com/\".to_string() + &template\n            };\n            sh_println!(\"Initializing {} from {}...\", root.display(), template)?;\n            // initialize the git repository\n            git.init()?;\n\n            // fetch the template - always fetch shallow for templates since git history will be\n            // collapsed. gitmodules will be initialized after the template is fetched\n            git.fetch(true, &template, branch)?;\n\n            // reset git history to the head of the template\n            // first get the commit hash that was fetched\n            let commit_hash = git.commit_hash(true, \"FETCH_HEAD\")?;\n            // format a commit message for the new repo\n            let commit_msg = format!(\"chore: init from {template} at {commit_hash}\");\n            // get the hash of the FETCH_HEAD with the new commit message\n            let new_commit_hash = git.commit_tree(\"FETCH_HEAD^{tree}\", Some(commit_msg))?;\n            // reset head of this repo to be the head of the template repo\n            git.reset(true, new_commit_hash)?;\n\n            // if shallow, just initialize submodules\n            if shallow {\n                git.submodule_init()?;\n            } else {\n                // if not shallow, initialize and clone submodules (without fetching latest)\n                git.submodule_update(false, false, true, true, std::iter::empty::<PathBuf>())?;\n            }\n        } else {\n            // if target is not empty\n            if root.read_dir().is_ok_and(|mut i| i.next().is_some()) {\n                if !force {\n                    eyre::bail!(\n                        \"Cannot run `init` on a non-empty directory.\\n\\\n                        Run with the `--force` flag to initialize regardless.\"\n                    );\n                }\n                sh_warn!(\"Target directory is not empty, but `--force` was specified\")?;\n            }\n\n            // ensure git status is clean before generating anything\n            if !no_git && commit && !force && git.is_in_repo()? {\n                git.ensure_clean()?;\n            }\n\n            sh_println!(\"Initializing {}...\", root.display())?;\n\n            // make the dirs\n            let src = root.join(\"src\");\n            fs::create_dir_all(&src)?;\n\n            let test = root.join(\"test\");\n            fs::create_dir_all(&test)?;\n\n            let script = root.join(\"script\");\n            fs::create_dir_all(&script)?;\n\n            // Only create example contracts if not disabled\n            if !empty {\n                if vyper {\n                    // write the contract file\n                    let contract_path = src.join(\"Counter.vy\");\n                    fs::write(\n                        contract_path,\n                        include_str!(\"../../assets/vyper/CounterTemplate.vy\"),\n                    )?;\n                    let interface_path = src.join(\"ICounter.sol\");\n                    fs::write(\n                        interface_path,\n                        include_str!(\"../../assets/vyper/ICounterTemplate.sol\"),\n                    )?;\n\n                    // write the tests\n                    let contract_path = test.join(\"Counter.t.sol\");\n                    fs::write(\n                        contract_path,\n                        include_str!(\"../../assets/vyper/CounterTemplate.t.sol\"),\n                    )?;\n\n                    // write the script\n                    let contract_path = script.join(\"Counter.s.sol\");\n                    fs::write(\n                        contract_path,\n                        include_str!(\"../../assets/vyper/CounterTemplate.s.sol\"),\n                    )?;\n                } else if tempo {\n                    // write the contract file\n                    let contract_path = src.join(\"Mail.sol\");\n                    fs::write(contract_path, include_str!(\"../../assets/tempo/MailTemplate.sol\"))?;\n\n                    // write the tests\n                    let contract_path = test.join(\"Mail.t.sol\");\n                    fs::write(\n                        contract_path,\n                        include_str!(\"../../assets/tempo/MailTemplate.t.sol\"),\n                    )?;\n\n                    // write the script\n                    let contract_path = script.join(\"Mail.s.sol\");\n                    fs::write(\n                        contract_path,\n                        include_str!(\"../../assets/tempo/MailTemplate.s.sol\"),\n                    )?;\n                } else {\n                    // write the contract file\n                    let contract_path = src.join(\"Counter.sol\");\n                    fs::write(\n                        contract_path,\n                        include_str!(\"../../assets/solidity/CounterTemplate.sol\"),\n                    )?;\n\n                    // write the tests\n                    let contract_path = test.join(\"Counter.t.sol\");\n                    fs::write(\n                        contract_path,\n                        include_str!(\"../../assets/solidity/CounterTemplate.t.sol\"),\n                    )?;\n\n                    // write the script\n                    let contract_path = script.join(\"Counter.s.sol\");\n                    fs::write(\n                        contract_path,\n                        include_str!(\"../../assets/solidity/CounterTemplate.s.sol\"),\n                    )?;\n                }\n            }\n\n            // Write the README file\n            let readme_path = root.join(\"README.md\");\n            if tempo {\n                fs::write(readme_path, include_str!(\"../../assets/tempo/README.md\"))?;\n            } else {\n                fs::write(readme_path, include_str!(\"../../assets/README.md\"))?;\n            }\n\n            // write foundry.toml, if it doesn't exist already\n            let dest = root.join(Config::FILE_NAME);\n            let mut config = Config::load_with_root(&root)?;\n            if !dest.exists() {\n                fs::write(dest, config.clone().into_basic().to_string_pretty()?)?;\n            }\n            let git = self.install.git(&config);\n\n            // set up the repo\n            if !no_git {\n                init_git_repo(git, commit, use_parent_git, vyper, tempo)?;\n            }\n\n            // install forge-std\n            if !offline {\n                if root.join(\"lib/forge-std\").exists() {\n                    sh_warn!(\"\\\"lib/forge-std\\\" already exists, skipping install...\")?;\n                    self.install.install(&mut config, vec![]).await?;\n                } else {\n                    let dep = \"https://github.com/foundry-rs/forge-std\".parse()?;\n                    self.install.install(&mut config, vec![dep]).await?;\n                }\n\n                // install tempo-std\n                if tempo {\n                    if root.join(\"lib/tempo-std\").exists() {\n                        sh_warn!(\"\\\"lib/tempo-std\\\" already exists, skipping install...\")?;\n                        self.install.install(&mut config, vec![]).await?;\n                    } else {\n                        let dep = \"https://github.com/tempoxyz/tempo-std\".parse()?;\n                        self.install.install(&mut config, vec![dep]).await?;\n                    }\n                }\n            }\n\n            // init vscode settings\n            if vscode {\n                init_vscode(&root)?;\n            }\n        }\n\n        sh_println!(\"{}\", \"    Initialized forge project\".green())?;\n        Ok(())\n    }\n}\n\n/// Initialises `root` as a git repository, if it isn't one already, unless 'use_parent_git' is\n/// true.\n///\n/// Creates `.gitignore` and `.github/workflows/test.yml`, if they don't exist already.\n///\n/// Commits everything in `root` if `commit` is true.\nfn init_git_repo(\n    git: Git<'_>,\n    commit: bool,\n    use_parent_git: bool,\n    vyper: bool,\n    tempo: bool,\n) -> Result<()> {\n    // `git init`\n    if !git.is_in_repo()? || (!use_parent_git && !git.is_repo_root()?) {\n        git.init()?;\n    }\n\n    // .gitignore\n    let gitignore = git.root.join(\".gitignore\");\n    if !gitignore.exists() {\n        fs::write(gitignore, include_str!(\"../../assets/.gitignoreTemplate\"))?;\n    }\n\n    // github workflow\n    let workflow = git.root.join(\".github/workflows/test.yml\");\n    if !workflow.exists() {\n        fs::create_dir_all(workflow.parent().unwrap())?;\n\n        if vyper {\n            fs::write(workflow, include_str!(\"../../assets/vyper/workflowTemplate.yml\"))?;\n        } else if tempo {\n            fs::write(workflow, include_str!(\"../../assets/tempo/workflowTemplate.yml\"))?;\n        } else {\n            fs::write(workflow, include_str!(\"../../assets/solidity/workflowTemplate.yml\"))?;\n        }\n    }\n\n    // commit everything\n    if commit {\n        git.add(Some(\"--all\"))?;\n        git.commit(\"chore: forge init\")?;\n    }\n\n    Ok(())\n}\n\n/// initializes the `.vscode/settings.json` file\nfn init_vscode(root: &Path) -> Result<()> {\n    let remappings_file = root.join(\"remappings.txt\");\n    if !remappings_file.exists() {\n        let mut remappings = Remapping::find_many(&root.join(\"lib\"))\n            .into_iter()\n            .map(|r| r.into_relative(root).to_relative_remapping().to_string())\n            .collect::<Vec<_>>();\n        if !remappings.is_empty() {\n            remappings.sort();\n            let content = remappings.join(\"\\n\");\n            fs::write(remappings_file, content)?;\n        }\n    }\n\n    let vscode_dir = root.join(\".vscode\");\n    let settings_file = vscode_dir.join(\"settings.json\");\n    let mut settings = if !vscode_dir.is_dir() {\n        fs::create_dir_all(&vscode_dir)?;\n        serde_json::json!({})\n    } else if settings_file.exists() {\n        foundry_compilers::utils::read_json_file(&settings_file)?\n    } else {\n        serde_json::json!({})\n    };\n\n    let obj = settings.as_object_mut().expect(\"Expected settings object\");\n    // insert [vscode-solidity settings](https://github.com/juanfranblanco/vscode-solidity)\n    let src_key = \"solidity.packageDefaultDependenciesContractsDirectory\";\n    if !obj.contains_key(src_key) {\n        obj.insert(src_key.to_string(), serde_json::Value::String(\"src\".to_string()));\n    }\n    let lib_key = \"solidity.packageDefaultDependenciesDirectory\";\n    if !obj.contains_key(lib_key) {\n        obj.insert(lib_key.to_string(), serde_json::Value::String(\"lib\".to_string()));\n    }\n\n    let content = serde_json::to_string_pretty(&settings)?;\n    fs::write(settings_file, content)?;\n\n    Ok(())\n}\n"
  },
  {
    "path": "crates/forge/src/cmd/inspect.rs",
    "content": "use alloy_json_abi::{EventParam, InternalType, JsonAbi, Param};\nuse alloy_primitives::{hex, keccak256};\nuse clap::Parser;\nuse comfy_table::{Cell, Table, modifiers::UTF8_ROUND_CORNERS, presets::ASCII_MARKDOWN};\nuse eyre::{Result, eyre};\nuse foundry_cli::opts::{BuildOpts, CompilerOpts};\nuse foundry_common::{\n    compile::{PathOrContractInfo, ProjectCompiler},\n    find_matching_contract_artifact, find_target_path, shell,\n};\nuse foundry_compilers::{\n    artifacts::{\n        StorageLayout,\n        output_selection::{\n            BytecodeOutputSelection, ContractOutputSelection, DeployedBytecodeOutputSelection,\n            EvmOutputSelection, EwasmOutputSelection,\n        },\n    },\n    solc::SolcLanguage,\n};\nuse regex::Regex;\nuse serde_json::{Map, Value};\nuse std::{collections::BTreeMap, fmt, str::FromStr, sync::LazyLock};\n\n/// CLI arguments for `forge inspect`.\n#[derive(Clone, Debug, Parser)]\npub struct InspectArgs {\n    /// The identifier of the contract to inspect in the form `(<path>:)?<contractname>`.\n    #[arg(value_parser = PathOrContractInfo::from_str)]\n    pub contract: PathOrContractInfo,\n\n    /// The contract artifact field to inspect.\n    #[arg(value_enum)]\n    pub field: ContractArtifactField,\n\n    /// All build arguments are supported\n    #[command(flatten)]\n    build: BuildOpts,\n\n    /// Whether to remove comments when inspecting `ir` and `irOptimized` artifact fields.\n    #[arg(long, short, help_heading = \"Display options\")]\n    pub strip_yul_comments: bool,\n\n    /// Whether to wrap the table to the terminal width.\n    #[arg(long, short, help_heading = \"Display options\")]\n    pub wrap: bool,\n}\n\nimpl InspectArgs {\n    pub fn run(self) -> Result<()> {\n        let Self { contract, field, build, strip_yul_comments, wrap } = self;\n\n        trace!(target: \"forge\", ?field, ?contract, \"running forge inspect\");\n\n        // Map field to ContractOutputSelection\n        let mut cos = build.compiler.extra_output;\n        if !field.can_skip_field() && !cos.iter().any(|selected| field == *selected) {\n            cos.push(field.try_into()?);\n        }\n\n        // Run Optimized?\n        let optimized = if field == ContractArtifactField::AssemblyOptimized {\n            Some(true)\n        } else {\n            build.compiler.optimize\n        };\n\n        // Get the solc version if specified\n        let solc_version = build.use_solc.clone();\n\n        // Build modified Args\n        let modified_build_args = BuildOpts {\n            compiler: CompilerOpts { extra_output: cos, optimize: optimized, ..build.compiler },\n            ..build\n        };\n\n        // Build the project\n        let project = modified_build_args.project()?;\n        let compiler = ProjectCompiler::new().quiet(true);\n        let target_path = find_target_path(&project, &contract)?;\n        let mut output = compiler.files([target_path.clone()]).compile(&project)?;\n\n        // Find the artifact\n        let artifact = find_matching_contract_artifact(&mut output, &target_path, contract.name())?;\n\n        // Match on ContractArtifactFields and pretty-print\n        match field {\n            ContractArtifactField::Abi => {\n                let abi = artifact.abi.as_ref().ok_or_else(|| missing_error(\"ABI\"))?;\n                print_abi(abi, wrap)?;\n            }\n            ContractArtifactField::Bytecode => {\n                print_json_str(&artifact.bytecode, Some(\"object\"))?;\n            }\n            ContractArtifactField::DeployedBytecode => {\n                print_json_str(&artifact.deployed_bytecode, Some(\"object\"))?;\n            }\n            ContractArtifactField::Assembly | ContractArtifactField::AssemblyOptimized => {\n                print_json_str(&artifact.assembly, None)?;\n            }\n            ContractArtifactField::LegacyAssembly => {\n                print_json_str(&artifact.legacy_assembly, None)?;\n            }\n            ContractArtifactField::MethodIdentifiers => {\n                print_method_identifiers(&artifact.method_identifiers, wrap)?;\n            }\n            ContractArtifactField::GasEstimates => {\n                print_json(&artifact.gas_estimates)?;\n            }\n            ContractArtifactField::StorageLayout => {\n                print_storage_layout(artifact.storage_layout.as_ref(), wrap)?;\n            }\n            ContractArtifactField::DevDoc => {\n                print_json(&artifact.devdoc)?;\n            }\n            ContractArtifactField::Ir => {\n                print_yul(artifact.ir.as_deref(), strip_yul_comments)?;\n            }\n            ContractArtifactField::IrOptimized => {\n                print_yul(artifact.ir_optimized.as_deref(), strip_yul_comments)?;\n            }\n            ContractArtifactField::Metadata => {\n                print_json(&artifact.metadata)?;\n            }\n            ContractArtifactField::UserDoc => {\n                print_json(&artifact.userdoc)?;\n            }\n            ContractArtifactField::Ewasm => {\n                print_json_str(&artifact.ewasm, None)?;\n            }\n            ContractArtifactField::Errors => {\n                let out = artifact.abi.as_ref().map_or(Map::new(), parse_errors);\n                print_errors_events(&out, true, wrap)?;\n            }\n            ContractArtifactField::Events => {\n                let out = artifact.abi.as_ref().map_or(Map::new(), parse_events);\n                print_errors_events(&out, false, wrap)?;\n            }\n            ContractArtifactField::StandardJson => {\n                let standard_json = if let Some(version) = solc_version {\n                    let version = version.parse()?;\n                    let mut standard_json =\n                        project.standard_json_input(&target_path)?.normalize_evm_version(&version);\n                    standard_json.settings.sanitize(&version, SolcLanguage::Solidity);\n                    standard_json\n                } else {\n                    project.standard_json_input(&target_path)?\n                };\n                print_json(&standard_json)?;\n            }\n            ContractArtifactField::Libraries => {\n                let all_libs: Vec<String> = artifact\n                    .all_link_references()\n                    .into_iter()\n                    .flat_map(|(path, libs)| {\n                        libs.into_keys().map(move |lib| format!(\"{path}:{lib}\"))\n                    })\n                    .collect();\n                if shell::is_json() {\n                    return print_json(&all_libs);\n                } else {\n                    sh_println!(\n                        \"Dynamically linked libraries:\\n{}\",\n                        all_libs\n                            .iter()\n                            .map(|v| format!(\"  {v}\"))\n                            .collect::<Vec<String>>()\n                            .join(\"\\n\")\n                    )?;\n                }\n            }\n        };\n\n        Ok(())\n    }\n}\n\nfn parse_errors(abi: &JsonAbi) -> Map<String, Value> {\n    let mut out = serde_json::Map::new();\n    for er in abi.errors.values().flatten() {\n        let types = get_ty_sig(&er.inputs);\n        let sig = format!(\"{:x}\", er.selector());\n        let sig_trimmed = &sig[0..8];\n        out.insert(format!(\"{}({})\", er.name, types), sig_trimmed.to_string().into());\n    }\n    out\n}\n\nfn parse_events(abi: &JsonAbi) -> Map<String, Value> {\n    let mut out = serde_json::Map::new();\n    for ev in abi.events.values().flatten() {\n        let types = parse_event_params(&ev.inputs);\n        let topic = hex::encode(keccak256(ev.signature()));\n        out.insert(format!(\"{}({})\", ev.name, types), format!(\"0x{topic}\").into());\n    }\n    out\n}\n\nfn parse_event_params(ev_params: &[EventParam]) -> String {\n    ev_params\n        .iter()\n        .map(|p| {\n            if let Some(ty) = p.internal_type() {\n                return internal_ty(ty);\n            }\n            p.ty.clone()\n        })\n        .collect::<Vec<_>>()\n        .join(\",\")\n}\n\nfn print_abi(abi: &JsonAbi, should_wrap: bool) -> Result<()> {\n    if shell::is_json() {\n        return print_json(abi);\n    }\n\n    let headers = vec![Cell::new(\"Type\"), Cell::new(\"Signature\"), Cell::new(\"Selector\")];\n    print_table(\n        headers,\n        |table| {\n            // Print events\n            for ev in abi.events.values().flatten() {\n                let types = parse_event_params(&ev.inputs);\n                let selector = ev.selector().to_string();\n                table.add_row([\"event\", &format!(\"{}({})\", ev.name, types), &selector]);\n            }\n\n            // Print errors\n            for er in abi.errors.values().flatten() {\n                let selector = er.selector().to_string();\n                table.add_row([\n                    \"error\",\n                    &format!(\"{}({})\", er.name, get_ty_sig(&er.inputs)),\n                    &selector,\n                ]);\n            }\n\n            // Print functions\n            for func in abi.functions.values().flatten() {\n                let selector = func.selector().to_string();\n                let state_mut = func.state_mutability.as_json_str();\n                let func_sig = if !func.outputs.is_empty() {\n                    format!(\n                        \"{}({}) {state_mut} returns ({})\",\n                        func.name,\n                        get_ty_sig(&func.inputs),\n                        get_ty_sig(&func.outputs)\n                    )\n                } else {\n                    format!(\"{}({}) {state_mut}\", func.name, get_ty_sig(&func.inputs))\n                };\n                table.add_row([\"function\", &func_sig, &selector]);\n            }\n\n            if let Some(constructor) = abi.constructor() {\n                let state_mut = constructor.state_mutability.as_json_str();\n                table.add_row([\n                    \"constructor\",\n                    &format!(\"constructor({}) {state_mut}\", get_ty_sig(&constructor.inputs)),\n                    \"\",\n                ]);\n            }\n\n            if let Some(fallback) = &abi.fallback {\n                let state_mut = fallback.state_mutability.as_json_str();\n                table.add_row([\"fallback\", &format!(\"fallback() {state_mut}\"), \"\"]);\n            }\n\n            if let Some(receive) = &abi.receive {\n                let state_mut = receive.state_mutability.as_json_str();\n                table.add_row([\"receive\", &format!(\"receive() {state_mut}\"), \"\"]);\n            }\n        },\n        should_wrap,\n    )\n}\n\nfn get_ty_sig(inputs: &[Param]) -> String {\n    inputs\n        .iter()\n        .map(|p| {\n            if let Some(ty) = p.internal_type() {\n                return internal_ty(ty);\n            }\n            p.ty.clone()\n        })\n        .collect::<Vec<_>>()\n        .join(\",\")\n}\n\nfn internal_ty(ty: &InternalType) -> String {\n    let contract_ty =\n        |c: Option<&str>, ty: &String| c.map_or_else(|| ty.clone(), |c| format!(\"{c}.{ty}\"));\n    match ty {\n        InternalType::AddressPayable(addr) => addr.clone(),\n        InternalType::Contract(contract) => contract.clone(),\n        InternalType::Enum { contract, ty } => contract_ty(contract.as_deref(), ty),\n        InternalType::Struct { contract, ty } => contract_ty(contract.as_deref(), ty),\n        InternalType::Other { contract, ty } => contract_ty(contract.as_deref(), ty),\n    }\n}\n\npub fn print_storage_layout(\n    storage_layout: Option<&StorageLayout>,\n    should_wrap: bool,\n) -> Result<()> {\n    let Some(storage_layout) = storage_layout else {\n        return Err(missing_error(\"storage layout\"));\n    };\n\n    if shell::is_json() {\n        return print_json(&storage_layout);\n    }\n\n    let headers = vec![\n        Cell::new(\"Name\"),\n        Cell::new(\"Type\"),\n        Cell::new(\"Slot\"),\n        Cell::new(\"Offset\"),\n        Cell::new(\"Bytes\"),\n        Cell::new(\"Contract\"),\n    ];\n\n    print_table(\n        headers,\n        |table| {\n            for slot in &storage_layout.storage {\n                let storage_type = storage_layout.types.get(&slot.storage_type);\n                table.add_row([\n                    slot.label.as_str(),\n                    storage_type.map_or(\"?\", |t| &t.label),\n                    &slot.slot,\n                    &slot.offset.to_string(),\n                    storage_type.map_or(\"?\", |t| &t.number_of_bytes),\n                    &slot.contract,\n                ]);\n            }\n        },\n        should_wrap,\n    )\n}\n\nfn print_method_identifiers(\n    method_identifiers: &Option<BTreeMap<String, String>>,\n    should_wrap: bool,\n) -> Result<()> {\n    let Some(method_identifiers) = method_identifiers else {\n        return Err(missing_error(\"method identifiers\"));\n    };\n\n    if shell::is_json() {\n        return print_json(method_identifiers);\n    }\n\n    let headers = vec![Cell::new(\"Method\"), Cell::new(\"Identifier\")];\n\n    print_table(\n        headers,\n        |table| {\n            for (method, identifier) in method_identifiers {\n                table.add_row([method, identifier]);\n            }\n        },\n        should_wrap,\n    )\n}\n\nfn print_errors_events(map: &Map<String, Value>, is_err: bool, should_wrap: bool) -> Result<()> {\n    if shell::is_json() {\n        return print_json(map);\n    }\n\n    let headers = if is_err {\n        vec![Cell::new(\"Error\"), Cell::new(\"Selector\")]\n    } else {\n        vec![Cell::new(\"Event\"), Cell::new(\"Topic\")]\n    };\n    print_table(\n        headers,\n        |table| {\n            for (method, selector) in map {\n                table.add_row([method, selector.as_str().unwrap()]);\n            }\n        },\n        should_wrap,\n    )\n}\n\nfn print_table(\n    headers: Vec<Cell>,\n    add_rows: impl FnOnce(&mut Table),\n    should_wrap: bool,\n) -> Result<()> {\n    let mut table = Table::new();\n    if shell::is_markdown() {\n        table.load_preset(ASCII_MARKDOWN);\n    } else {\n        table.apply_modifier(UTF8_ROUND_CORNERS);\n    }\n    table.set_header(headers);\n    if should_wrap {\n        table.set_content_arrangement(comfy_table::ContentArrangement::Dynamic);\n    }\n    add_rows(&mut table);\n    sh_println!(\"\\n{table}\\n\")?;\n    Ok(())\n}\n\n/// Contract level output selection\n#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]\npub enum ContractArtifactField {\n    Abi,\n    Bytecode,\n    DeployedBytecode,\n    Assembly,\n    AssemblyOptimized,\n    LegacyAssembly,\n    MethodIdentifiers,\n    GasEstimates,\n    StorageLayout,\n    DevDoc,\n    Ir,\n    IrOptimized,\n    Metadata,\n    UserDoc,\n    Ewasm,\n    Errors,\n    Events,\n    StandardJson,\n    Libraries,\n}\n\nmacro_rules! impl_value_enum {\n    (enum $name:ident { $($field:ident => $main:literal $(| $alias:literal)*),+ $(,)? }) => {\n        impl $name {\n            /// All the variants of this enum.\n            pub const ALL: &'static [Self] = &[$(Self::$field),+];\n\n            /// Returns the string representation of `self`.\n            pub const fn as_str(&self) -> &'static str {\n                match self {\n                    $(\n                        Self::$field => $main,\n                    )+\n                }\n            }\n\n            /// Returns all the aliases of `self`.\n            pub const fn aliases(&self) -> &'static [&'static str] {\n                match self {\n                    $(\n                        Self::$field => &[$($alias),*],\n                    )+\n                }\n            }\n        }\n\n        impl ::clap::ValueEnum for $name {\n            fn value_variants<'a>() -> &'a [Self] {\n                Self::ALL\n            }\n\n            fn to_possible_value(&self) -> Option<::clap::builder::PossibleValue> {\n                Some(::clap::builder::PossibleValue::new(Self::as_str(self)).aliases(Self::aliases(self)))\n            }\n\n            fn from_str(input: &str, ignore_case: bool) -> Result<Self, String> {\n                let _ = ignore_case;\n                <Self as ::std::str::FromStr>::from_str(input)\n            }\n        }\n\n        impl ::std::str::FromStr for $name {\n            type Err = String;\n\n            fn from_str(s: &str) -> Result<Self, Self::Err> {\n                match s {\n                    $(\n                        $main $(| $alias)* => Ok(Self::$field),\n                    )+\n                    _ => Err(format!(concat!(\"Invalid \", stringify!($name), \" value: {}\"), s)),\n                }\n            }\n        }\n    };\n}\n\nimpl_value_enum! {\n    enum ContractArtifactField {\n        Abi               => \"abi\",\n        Bytecode          => \"bytecode\" | \"bytes\" | \"b\",\n        DeployedBytecode  => \"deployedBytecode\" | \"deployed_bytecode\" | \"deployed-bytecode\"\n                             | \"deployed\" | \"deployedbytecode\",\n        Assembly          => \"assembly\" | \"asm\",\n        LegacyAssembly    => \"legacyAssembly\" | \"legacyassembly\" | \"legacy_assembly\",\n        AssemblyOptimized => \"assemblyOptimized\" | \"asmOptimized\" | \"assemblyoptimized\"\n                             | \"assembly_optimized\" | \"asmopt\" | \"assembly-optimized\"\n                             | \"asmo\" | \"asm-optimized\" | \"asmoptimized\" | \"asm_optimized\",\n        MethodIdentifiers => \"methodIdentifiers\" | \"methodidentifiers\" | \"methods\"\n                             | \"method_identifiers\" | \"method-identifiers\" | \"mi\",\n        GasEstimates      => \"gasEstimates\" | \"gas\" | \"gas_estimates\" | \"gas-estimates\"\n                             | \"gasestimates\",\n        StorageLayout     => \"storageLayout\" | \"storage_layout\" | \"storage-layout\"\n                             | \"storagelayout\" | \"storage\",\n        DevDoc            => \"devdoc\" | \"dev-doc\" | \"devDoc\",\n        Ir                => \"ir\" | \"iR\" | \"IR\",\n        IrOptimized       => \"irOptimized\" | \"ir-optimized\" | \"iroptimized\" | \"iro\" | \"iropt\",\n        Metadata          => \"metadata\" | \"meta\",\n        UserDoc           => \"userdoc\" | \"userDoc\" | \"user-doc\",\n        Ewasm             => \"ewasm\" | \"e-wasm\",\n        Errors            => \"errors\" | \"er\",\n        Events            => \"events\" | \"ev\",\n        StandardJson      => \"standardJson\" | \"standard-json\" | \"standard_json\",\n        Libraries         => \"libraries\" | \"lib\" | \"libs\",\n    }\n}\n\nimpl TryFrom<ContractArtifactField> for ContractOutputSelection {\n    type Error = eyre::Error;\n\n    fn try_from(field: ContractArtifactField) -> Result<Self, Self::Error> {\n        type Caf = ContractArtifactField;\n        match field {\n            Caf::Abi => Ok(Self::Abi),\n            Caf::Bytecode => {\n                Ok(Self::Evm(EvmOutputSelection::ByteCode(BytecodeOutputSelection::All)))\n            }\n            Caf::DeployedBytecode => Ok(Self::Evm(EvmOutputSelection::DeployedByteCode(\n                DeployedBytecodeOutputSelection::All,\n            ))),\n            Caf::Assembly | Caf::AssemblyOptimized => Ok(Self::Evm(EvmOutputSelection::Assembly)),\n            Caf::LegacyAssembly => Ok(Self::Evm(EvmOutputSelection::LegacyAssembly)),\n            Caf::MethodIdentifiers => Ok(Self::Evm(EvmOutputSelection::MethodIdentifiers)),\n            Caf::GasEstimates => Ok(Self::Evm(EvmOutputSelection::GasEstimates)),\n            Caf::StorageLayout => Ok(Self::StorageLayout),\n            Caf::DevDoc => Ok(Self::DevDoc),\n            Caf::Ir => Ok(Self::Ir),\n            Caf::IrOptimized => Ok(Self::IrOptimized),\n            Caf::Metadata => Ok(Self::Metadata),\n            Caf::UserDoc => Ok(Self::UserDoc),\n            Caf::Ewasm => Ok(Self::Ewasm(EwasmOutputSelection::All)),\n            Caf::Errors => Ok(Self::Abi),\n            Caf::Events => Ok(Self::Abi),\n            Caf::StandardJson => {\n                Err(eyre!(\"StandardJson is not supported for ContractOutputSelection\"))\n            }\n            Caf::Libraries => Err(eyre!(\"Libraries is not supported for ContractOutputSelection\")),\n        }\n    }\n}\n\nimpl PartialEq<ContractOutputSelection> for ContractArtifactField {\n    fn eq(&self, other: &ContractOutputSelection) -> bool {\n        type Cos = ContractOutputSelection;\n        type Eos = EvmOutputSelection;\n        matches!(\n            (self, other),\n            (Self::Abi | Self::Events, Cos::Abi)\n                | (Self::Errors, Cos::Abi)\n                | (Self::Bytecode, Cos::Evm(Eos::ByteCode(_)))\n                | (Self::DeployedBytecode, Cos::Evm(Eos::DeployedByteCode(_)))\n                | (Self::Assembly | Self::AssemblyOptimized, Cos::Evm(Eos::Assembly))\n                | (Self::LegacyAssembly, Cos::Evm(Eos::LegacyAssembly))\n                | (Self::MethodIdentifiers, Cos::Evm(Eos::MethodIdentifiers))\n                | (Self::GasEstimates, Cos::Evm(Eos::GasEstimates))\n                | (Self::StorageLayout, Cos::StorageLayout)\n                | (Self::DevDoc, Cos::DevDoc)\n                | (Self::Ir, Cos::Ir)\n                | (Self::IrOptimized, Cos::IrOptimized)\n                | (Self::Metadata, Cos::Metadata)\n                | (Self::UserDoc, Cos::UserDoc)\n                | (Self::Ewasm, Cos::Ewasm(_))\n        )\n    }\n}\n\nimpl fmt::Display for ContractArtifactField {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.write_str(self.as_str())\n    }\n}\n\nimpl ContractArtifactField {\n    /// Returns true if this field does not need to be passed to the compiler.\n    pub const fn can_skip_field(&self) -> bool {\n        matches!(\n            self,\n            Self::Bytecode | Self::DeployedBytecode | Self::StandardJson | Self::Libraries\n        )\n    }\n}\n\nfn print_json(obj: &impl serde::Serialize) -> Result<()> {\n    sh_println!(\"{}\", serde_json::to_string_pretty(obj)?)?;\n    Ok(())\n}\n\nfn print_json_str(obj: &impl serde::Serialize, key: Option<&str>) -> Result<()> {\n    sh_println!(\"{}\", get_json_str(obj, key)?)?;\n    Ok(())\n}\n\nfn print_yul(yul: Option<&str>, strip_comments: bool) -> Result<()> {\n    let Some(yul) = yul else {\n        return Err(missing_error(\"IR output\"));\n    };\n\n    static YUL_COMMENTS: LazyLock<Regex> =\n        LazyLock::new(|| Regex::new(r\"(///.*\\n\\s*)|(\\s*/\\*\\*.*?\\*/)\").unwrap());\n\n    if strip_comments {\n        sh_println!(\"{}\", YUL_COMMENTS.replace_all(yul, \"\"))?;\n    } else {\n        sh_println!(\"{yul}\")?;\n    }\n\n    Ok(())\n}\n\nfn get_json_str(obj: &impl serde::Serialize, key: Option<&str>) -> Result<String> {\n    let value = serde_json::to_value(obj)?;\n    let value = if let Some(key) = key\n        && let Some(value) = value.get(key)\n    {\n        value\n    } else {\n        &value\n    };\n    Ok(match value.as_str() {\n        Some(s) => s.to_string(),\n        None => format!(\"{value:#}\"),\n    })\n}\n\nfn missing_error(field: &str) -> eyre::Error {\n    eyre!(\n        \"{field} missing from artifact; \\\n         this could be a spurious caching issue, consider running `forge clean`\"\n    )\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn contract_output_selection() {\n        for &field in ContractArtifactField::ALL {\n            if field == ContractArtifactField::StandardJson {\n                let selection: Result<ContractOutputSelection, _> = field.try_into();\n                assert!(\n                    selection\n                        .unwrap_err()\n                        .to_string()\n                        .eq(\"StandardJson is not supported for ContractOutputSelection\")\n                );\n            } else if field == ContractArtifactField::Libraries {\n                let selection: Result<ContractOutputSelection, _> = field.try_into();\n                assert!(\n                    selection\n                        .unwrap_err()\n                        .to_string()\n                        .eq(\"Libraries is not supported for ContractOutputSelection\")\n                );\n            } else {\n                let selection: ContractOutputSelection = field.try_into().unwrap();\n                assert_eq!(field, selection);\n\n                let s = field.as_str();\n                assert_eq!(s, field.to_string());\n                assert_eq!(s.parse::<ContractArtifactField>().unwrap(), field);\n                for alias in field.aliases() {\n                    assert_eq!(alias.parse::<ContractArtifactField>().unwrap(), field);\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "crates/forge/src/cmd/install.rs",
    "content": "use crate::{DepIdentifier, FOUNDRY_LOCK, Lockfile};\nuse clap::{Parser, ValueHint};\nuse eyre::{Context, Result};\nuse foundry_cli::{\n    opts::Dependency,\n    utils::{CommandUtils, Git, LoadConfig},\n};\nuse foundry_common::fs;\nuse foundry_config::{Config, impl_figment_convert_basic};\nuse regex::Regex;\nuse semver::Version;\nuse soldeer_commands::{Command, Verbosity, commands::install::Install};\nuse std::{\n    io::IsTerminal,\n    path::{Path, PathBuf},\n    str,\n    sync::LazyLock,\n};\nuse yansi::Paint;\n\nstatic DEPENDENCY_VERSION_TAG_REGEX: LazyLock<Regex> =\n    LazyLock::new(|| Regex::new(r\"^v?\\d+(\\.\\d+)*$\").unwrap());\n\n/// CLI arguments for `forge install`.\n#[derive(Clone, Debug, Parser)]\n#[command(override_usage = \"forge install [OPTIONS] [DEPENDENCIES]...\n    forge install [OPTIONS] <github username>/<github project>@<tag>...\n    forge install [OPTIONS] <alias>=<github username>/<github project>@<tag>...\n    forge install [OPTIONS] <https://<github token>@git url>...)]\n    forge install [OPTIONS] <https:// git url>...\")]\npub struct InstallArgs {\n    /// The dependencies to install.\n    ///\n    /// A dependency can be a raw URL, or the path to a GitHub repository.\n    ///\n    /// Additionally, a ref can be provided by adding @ to the dependency path.\n    ///\n    /// A ref can be:\n    /// - A branch: master\n    /// - A tag: v1.2.3\n    /// - A commit: 8e8128\n    ///\n    /// For exact match, a ref can be provided with `@tag=`, `@branch=` or `@rev=` prefix.\n    ///\n    /// Target installation directory can be added via `<alias>=` suffix.\n    /// The dependency will installed to `lib/<alias>`.\n    dependencies: Vec<Dependency>,\n\n    /// The project's root path.\n    ///\n    /// By default root of the Git repository, if in one,\n    /// or the current working directory.\n    #[arg(long, value_hint = ValueHint::DirPath, value_name = \"PATH\")]\n    pub root: Option<PathBuf>,\n\n    #[command(flatten)]\n    opts: DependencyInstallOpts,\n}\n\nimpl_figment_convert_basic!(InstallArgs);\n\nimpl InstallArgs {\n    pub async fn run(self) -> Result<()> {\n        let mut config = self.load_config()?;\n        self.opts.install(&mut config, self.dependencies).await\n    }\n}\n\n#[derive(Clone, Copy, Debug, Default, Parser)]\npub struct DependencyInstallOpts {\n    /// Perform shallow clones instead of deep ones.\n    ///\n    /// Improves performance and reduces disk usage, but prevents switching branches or tags.\n    #[arg(long)]\n    pub shallow: bool,\n\n    /// Install without adding the dependency as a submodule.\n    #[arg(long)]\n    pub no_git: bool,\n\n    /// Create a commit after installing the dependencies.\n    #[arg(long)]\n    pub commit: bool,\n}\n\nimpl DependencyInstallOpts {\n    pub fn git(self, config: &Config) -> Git<'_> {\n        Git::from_config(config).shallow(self.shallow)\n    }\n\n    /// Installs all missing dependencies.\n    ///\n    /// See also [`Self::install`].\n    ///\n    /// Returns true if any dependency was installed.\n    pub async fn install_missing_dependencies(self, config: &mut Config) -> bool {\n        let lib = config.install_lib_dir();\n        if self.git(config).has_missing_dependencies(Some(lib)).unwrap_or(false) {\n            // The extra newline is needed, otherwise the compiler output will overwrite the message\n            let _ = sh_println!(\"Missing dependencies found. Installing now...\\n\");\n\n            if self.install(config, Vec::new()).await.is_err() {\n                let _ =\n                    sh_warn!(\"Your project has missing dependencies that could not be installed.\");\n            }\n            true\n        } else {\n            false\n        }\n    }\n\n    /// Installs all dependencies\n    pub async fn install(self, config: &mut Config, dependencies: Vec<Dependency>) -> Result<()> {\n        let Self { no_git, commit, .. } = self;\n\n        let git = self.git(config);\n\n        let install_lib_dir = config.install_lib_dir();\n        let libs = git.root.join(install_lib_dir);\n\n        let mut lockfile = Lockfile::new(&config.root);\n        if !no_git {\n            lockfile = lockfile.with_git(&git);\n\n            // Check if submodules are uninitialized, if so, we need to fetch all submodules\n            // This is to ensure that foundry.lock syncs successfully and doesn't error out, when\n            // looking for commits/tags in submodules\n            if git.submodules_uninitialized()? {\n                trace!(lib = %libs.display(), \"submodules uninitialized\");\n                git.submodule_update(false, false, false, true, Some(&libs))?;\n            }\n        }\n\n        let out_of_sync_deps = lockfile.sync(config.install_lib_dir())?;\n\n        if dependencies.is_empty() && !no_git {\n            // Use the root of the git repository to look for submodules.\n            let root = Git::root_of(git.root)?;\n            match git.has_submodules(Some(&root)) {\n                Ok(true) => {\n                    sh_println!(\"Updating dependencies in {}\", libs.display())?;\n\n                    // recursively fetch all submodules (without fetching latest)\n                    git.submodule_update(false, false, false, true, Some(&libs))?;\n                    lockfile.write()?;\n                }\n                Err(err) => {\n                    sh_err!(\"Failed to check for submodules: {err}\")?;\n                }\n                _ => {\n                    // no submodules, nothing to do\n                }\n            }\n        }\n\n        fs::create_dir_all(&libs)?;\n\n        let installer = Installer { git, commit };\n        for dep in dependencies {\n            let path = libs.join(dep.name());\n            let rel_path = path\n                .strip_prefix(git.root)\n                .wrap_err(\"Library directory is not relative to the repository root\")?;\n            sh_println!(\n                \"Installing {} in {} (url: {}, tag: {})\",\n                dep.name,\n                path.display(),\n                dep.url.as_deref().unwrap_or(\"None\"),\n                dep.tag.as_deref().unwrap_or(\"None\")\n            )?;\n\n            // this tracks the actual installed tag\n            let installed_tag;\n            let mut dep_id = None;\n            if no_git {\n                installed_tag = installer.install_as_folder(&dep, &path)?;\n            } else {\n                if commit {\n                    git.ensure_clean()?;\n                }\n                installed_tag = installer.install_as_submodule(&dep, &path)?;\n\n                let mut new_insertion = false;\n                // Pin branch to submodule if branch is used\n                if let Some(tag_or_branch) = &installed_tag {\n                    // First, check if this tag has a branch\n                    dep_id = Some(DepIdentifier::resolve_type(&git, &path, tag_or_branch)?);\n                    if git.has_branch(tag_or_branch, &path)?\n                        && dep_id.as_ref().is_some_and(|id| id.is_branch())\n                    {\n                        // always work with relative paths when directly modifying submodules\n                        git.cmd()\n                            .args([\"submodule\", \"set-branch\", \"-b\", tag_or_branch])\n                            .arg(rel_path)\n                            .exec()?;\n\n                        let rev = git.get_rev(tag_or_branch, &path)?;\n\n                        dep_id = Some(DepIdentifier::Branch {\n                            name: tag_or_branch.to_string(),\n                            rev,\n                            r#override: false,\n                        });\n                    }\n\n                    trace!(?dep_id, ?tag_or_branch, \"resolved dep id\");\n                    if let Some(dep_id) = &dep_id {\n                        new_insertion = true;\n                        lockfile.insert(rel_path.to_path_buf(), dep_id.clone());\n                    }\n\n                    if commit {\n                        // update .gitmodules which is at the root of the repo,\n                        // not necessarily at the root of the current Foundry project\n                        let root = Git::root_of(git.root)?;\n                        git.root(&root).add(Some(\".gitmodules\"))?;\n                    }\n                }\n\n                if new_insertion\n                    || out_of_sync_deps.as_ref().is_some_and(|o| !o.is_empty())\n                    || !lockfile.exists()\n                {\n                    lockfile.write()?;\n                }\n\n                // commit the installation\n                if commit {\n                    let mut msg = String::with_capacity(128);\n                    msg.push_str(\"forge install: \");\n                    msg.push_str(dep.name());\n\n                    if let Some(tag) = &installed_tag {\n                        msg.push_str(\"\\n\\n\");\n\n                        if let Some(dep_id) = &dep_id {\n                            msg.push_str(&dep_id.to_string());\n                        } else {\n                            msg.push_str(tag);\n                        }\n                    }\n\n                    if !lockfile.is_empty() {\n                        git.root(&config.root).add(Some(FOUNDRY_LOCK))?;\n                    }\n                    git.commit(&msg)?;\n                }\n            }\n\n            let mut msg = format!(\"    {} {}\", \"Installed\".green(), dep.name);\n            if let Some(tag) = dep.tag.or(installed_tag) {\n                msg.push(' ');\n\n                if let Some(dep_id) = dep_id {\n                    msg.push_str(&dep_id.to_string());\n                } else {\n                    msg.push_str(tag.as_str());\n                }\n            }\n            sh_println!(\"{msg}\")?;\n\n            // Check if the dependency has soldeer.lock and install soldeer dependencies\n            if let Err(e) = install_soldeer_deps_if_needed(&path).await {\n                sh_warn!(\"Failed to install soldeer dependencies for {}: {e}\", dep.name)?;\n            }\n        }\n\n        // update `libs` in config if not included yet\n        if !config.libs.iter().any(|p| p == install_lib_dir) {\n            config.libs.push(install_lib_dir.to_path_buf());\n            config.update_libs()?;\n        }\n\n        Ok(())\n    }\n}\n\npub async fn install_missing_dependencies(config: &mut Config) -> bool {\n    DependencyInstallOpts::default().install_missing_dependencies(config).await\n}\n\n/// Checks if a dependency has soldeer.lock and installs soldeer dependencies if needed.\nasync fn install_soldeer_deps_if_needed(dep_path: &Path) -> Result<()> {\n    let soldeer_lock = dep_path.join(\"soldeer.lock\");\n\n    if soldeer_lock.exists() {\n        sh_println!(\"    Found soldeer.lock, installing soldeer dependencies...\")?;\n\n        // Change to the dependency directory and run soldeer install\n        let original_dir = std::env::current_dir()?;\n        std::env::set_current_dir(dep_path)?;\n\n        let result = soldeer_commands::run(\n            Command::Install(Install::default()),\n            Verbosity::new(\n                foundry_common::shell::verbosity(),\n                if foundry_common::shell::is_quiet() { 1 } else { 0 },\n            ),\n        )\n        .await;\n\n        // Change back to original directory\n        std::env::set_current_dir(original_dir)?;\n\n        result.map_err(|e| eyre::eyre!(\"Failed to run soldeer install: {e}\"))?;\n        sh_println!(\"    Soldeer dependencies installed successfully\")?;\n    }\n\n    Ok(())\n}\n\n#[derive(Clone, Copy, Debug)]\nstruct Installer<'a> {\n    git: Git<'a>,\n    commit: bool,\n}\n\nimpl Installer<'_> {\n    /// Installs the dependency as an ordinary folder instead of a submodule\n    fn install_as_folder(self, dep: &Dependency, path: &Path) -> Result<Option<String>> {\n        let url = dep.require_url()?;\n        Git::clone(dep.tag.is_none(), url, Some(&path))?;\n        let mut dep = dep.clone();\n\n        if dep.tag.is_none() {\n            // try to find latest semver release tag\n            dep.tag = self.last_tag(path);\n        }\n\n        // checkout the tag if necessary, using recursive checkout to properly clean up\n        // nested submodules that may exist on the default branch but not on the target tag.\n        // See: https://github.com/foundry-rs/foundry/issues/13688\n        self.git_checkout(&dep, path, true)?;\n\n        trace!(\"updating dependency submodules recursively\");\n        self.git.root(path).submodule_update(\n            false,\n            false,\n            false,\n            true,\n            std::iter::empty::<PathBuf>(),\n        )?;\n\n        // remove nested .git directories from submodules before removing the top-level .git\n        Self::remove_nested_git_dirs(path)?;\n\n        // remove git artifacts\n        fs::remove_dir_all(path.join(\".git\"))?;\n\n        Ok(dep.tag)\n    }\n\n    /// Recursively removes `.git` files/directories from nested submodules within `root`.\n    ///\n    /// Submodules typically have a `.git` file (not a directory) pointing to the parent's\n    /// `.git/modules/` directory. This cleans those up so the result is a plain folder tree.\n    fn remove_nested_git_dirs(root: &Path) -> Result<()> {\n        Self::remove_nested_git_dirs_inner(root, root)\n    }\n\n    fn remove_nested_git_dirs_inner(root: &Path, dir: &Path) -> Result<()> {\n        let entries = match std::fs::read_dir(dir) {\n            Ok(entries) => entries,\n            Err(_) => return Ok(()),\n        };\n        for entry in entries {\n            let entry = entry?;\n            let ft = entry.file_type()?;\n\n            // never follow symlinks\n            if ft.is_symlink() {\n                continue;\n            }\n\n            let path = entry.path();\n            if path.file_name() == Some(\".git\".as_ref()) && path.parent() != Some(root) {\n                if ft.is_dir() {\n                    fs::remove_dir_all(&path)?;\n                } else {\n                    fs::remove_file(&path)?;\n                }\n            } else if ft.is_dir() {\n                Self::remove_nested_git_dirs_inner(root, &path)?;\n            }\n        }\n        Ok(())\n    }\n\n    /// Installs the dependency as new submodule.\n    ///\n    /// This will add the git submodule to the given dir, initialize it and checkout the tag if\n    /// provided or try to find the latest semver, release tag.\n    fn install_as_submodule(self, dep: &Dependency, path: &Path) -> Result<Option<String>> {\n        // install the dep\n        self.git_submodule(dep, path)?;\n\n        let mut dep = dep.clone();\n        if dep.tag.is_none() {\n            // try to find latest semver release tag\n            dep.tag = self.last_tag(path);\n        }\n\n        // checkout the tag if necessary\n        self.git_checkout(&dep, path, true)?;\n\n        trace!(\"updating dependency submodules recursively\");\n        self.git.root(path).submodule_update(\n            false,\n            false,\n            false,\n            true,\n            std::iter::empty::<PathBuf>(),\n        )?;\n\n        // sync submodules config with changes in .gitmodules, see <https://github.com/foundry-rs/foundry/issues/9611>\n        self.git.root(path).submodule_sync()?;\n\n        if self.commit {\n            self.git.add(Some(path))?;\n        }\n\n        Ok(dep.tag)\n    }\n\n    fn last_tag(self, path: &Path) -> Option<String> {\n        if self.git.shallow {\n            None\n        } else {\n            self.git_semver_tags(path).ok().and_then(|mut tags| tags.pop()).map(|(tag, _)| tag)\n        }\n    }\n\n    /// Returns all semver git tags sorted in ascending order\n    fn git_semver_tags(self, path: &Path) -> Result<Vec<(String, Version)>> {\n        let out = self.git.root(path).tag()?;\n        let mut tags = Vec::new();\n        // tags are commonly prefixed which would make them not semver: v1.2.3 is not a semantic\n        // version\n        let common_prefixes = &[\"v-\", \"v\", \"release-\", \"release\"];\n        for tag in out.lines() {\n            let mut maybe_semver = tag;\n            for &prefix in common_prefixes {\n                if let Some(rem) = tag.strip_prefix(prefix) {\n                    maybe_semver = rem;\n                    break;\n                }\n            }\n            match Version::parse(maybe_semver) {\n                Ok(v) => {\n                    // ignore if additional metadata, like rc, beta, etc...\n                    if v.build.is_empty() && v.pre.is_empty() {\n                        tags.push((tag.to_string(), v));\n                    }\n                }\n                Err(err) => {\n                    warn!(?err, ?maybe_semver, \"No semver tag\");\n                }\n            }\n        }\n\n        tags.sort_by(|(_, a), (_, b)| a.cmp(b));\n\n        Ok(tags)\n    }\n\n    /// Install the given dependency as git submodule in `target_dir`.\n    fn git_submodule(self, dep: &Dependency, path: &Path) -> Result<()> {\n        let url = dep.require_url()?;\n\n        // make path relative to the git root, already checked above\n        let path = path.strip_prefix(self.git.root).unwrap();\n\n        trace!(?dep, url, ?path, \"installing git submodule\");\n        self.git.submodule_add(true, url, path)\n    }\n\n    fn git_checkout(self, dep: &Dependency, path: &Path, recurse: bool) -> Result<String> {\n        // no need to checkout if there is no tag\n        let Some(mut tag) = dep.tag.clone() else { return Ok(String::new()) };\n\n        let mut is_branch = false;\n        // only try to match tag if current terminal is a tty\n        if std::io::stdout().is_terminal() {\n            if tag.is_empty() {\n                tag = self.match_tag(&tag, path)?;\n            } else if let Some(branch) = self.match_branch(&tag, path)? {\n                trace!(?tag, ?branch, \"selecting branch for given tag\");\n                tag = branch;\n                is_branch = true;\n            }\n        }\n        let url = dep.url.as_ref().unwrap();\n\n        let res = self.git.root(path).checkout(recurse, &tag);\n        if let Err(mut e) = res {\n            // remove dependency on failed checkout\n            fs::remove_dir_all(path)?;\n            if e.to_string().contains(\"did not match any file(s) known to git\") {\n                e = eyre::eyre!(\"Tag: \\\"{tag}\\\" not found for repo \\\"{url}\\\"!\")\n            }\n            return Err(e);\n        }\n\n        if is_branch { Ok(tag) } else { Ok(String::new()) }\n    }\n\n    /// disambiguate tag if it is a version tag\n    fn match_tag(self, tag: &str, path: &Path) -> Result<String> {\n        // only try to match if it looks like a version tag\n        if !DEPENDENCY_VERSION_TAG_REGEX.is_match(tag) {\n            return Ok(tag.into());\n        }\n\n        // generate candidate list by filtering `git tag` output, valid ones are those \"starting\n        // with\" the user-provided tag (ignoring the starting 'v'), for example, if the user\n        // specifies 1.5, then v1.5.2 is a valid candidate, but v3.1.5 is not\n        let trimmed_tag = tag.trim_start_matches('v').to_string();\n        let output = self.git.root(path).tag()?;\n        let mut candidates: Vec<String> = output\n            .trim()\n            .lines()\n            .filter(|x| x.trim_start_matches('v').starts_with(&trimmed_tag))\n            .map(|x| x.to_string())\n            .rev()\n            .collect();\n\n        // no match found, fall back to the user-provided tag\n        if candidates.is_empty() {\n            return Ok(tag.into());\n        }\n\n        // have exact match\n        for candidate in &candidates {\n            if candidate == tag {\n                return Ok(tag.into());\n            }\n        }\n\n        // only one candidate, ask whether the user wants to accept or not\n        if candidates.len() == 1 {\n            let matched_tag = &candidates[0];\n            let input = prompt!(\n                \"Found a similar version tag: {matched_tag}, do you want to use this instead? [Y/n] \"\n            )?;\n            return if match_yn(input) { Ok(matched_tag.clone()) } else { Ok(tag.into()) };\n        }\n\n        // multiple candidates, ask the user to choose one or skip\n        candidates.insert(0, String::from(\"SKIP AND USE ORIGINAL TAG\"));\n        sh_println!(\"There are multiple matching tags:\")?;\n        for (i, candidate) in candidates.iter().enumerate() {\n            sh_println!(\"[{i}] {candidate}\")?;\n        }\n\n        let n_candidates = candidates.len();\n        loop {\n            let input: String =\n                prompt!(\"Please select a tag (0-{}, default: 1): \", n_candidates - 1)?;\n            let s = input.trim();\n            // default selection, return first candidate\n            let n = if s.is_empty() { Ok(1) } else { s.parse() };\n            // match user input, 0 indicates skipping and use original tag\n            match n {\n                Ok(0) => return Ok(tag.into()),\n                Ok(i) if (1..=n_candidates).contains(&i) => {\n                    let c = &candidates[i];\n                    sh_println!(\"[{i}] {c} selected\")?;\n                    return Ok(c.clone());\n                }\n                _ => continue,\n            }\n        }\n    }\n\n    fn match_branch(self, tag: &str, path: &Path) -> Result<Option<String>> {\n        // fetch remote branches and check for tag\n        let output = self.git.root(path).cmd().args([\"branch\", \"-r\"]).get_stdout_lossy()?;\n\n        let mut candidates = output\n            .lines()\n            .map(|x| x.trim().trim_start_matches(\"origin/\"))\n            .filter(|x| x.starts_with(tag))\n            .map(ToString::to_string)\n            .rev()\n            .collect::<Vec<_>>();\n\n        trace!(?candidates, ?tag, \"found branch candidates\");\n\n        // no match found, fall back to the user-provided tag\n        if candidates.is_empty() {\n            return Ok(None);\n        }\n\n        // have exact match\n        for candidate in &candidates {\n            if candidate == tag {\n                return Ok(Some(tag.to_string()));\n            }\n        }\n\n        // only one candidate, ask whether the user wants to accept or not\n        if candidates.len() == 1 {\n            let matched_tag = &candidates[0];\n            let input = prompt!(\n                \"Found a similar branch: {matched_tag}, do you want to use this instead? [Y/n] \"\n            )?;\n            return if match_yn(input) { Ok(Some(matched_tag.clone())) } else { Ok(None) };\n        }\n\n        // multiple candidates, ask the user to choose one or skip\n        candidates.insert(0, format!(\"{tag} (original branch)\"));\n        sh_println!(\"There are multiple matching branches:\")?;\n        for (i, candidate) in candidates.iter().enumerate() {\n            sh_println!(\"[{i}] {candidate}\")?;\n        }\n\n        let n_candidates = candidates.len();\n        let input: String = prompt!(\n            \"Please select a tag (0-{}, default: 1, Press <enter> to cancel): \",\n            n_candidates - 1\n        )?;\n        let input = input.trim();\n\n        // default selection, return None\n        if input.is_empty() {\n            sh_println!(\"Canceled branch matching\")?;\n            return Ok(None);\n        }\n\n        // match user input, 0 indicates skipping and use original tag\n        match input.parse::<usize>() {\n            Ok(0) => Ok(Some(tag.into())),\n            Ok(i) if (1..=n_candidates).contains(&i) => {\n                let c = &candidates[i];\n                sh_println!(\"[{i}] {c} selected\")?;\n                Ok(Some(c.clone()))\n            }\n            _ => Ok(None),\n        }\n    }\n}\n\n/// Matches on the result of a prompt for yes/no.\n///\n/// Defaults to true.\nfn match_yn(input: String) -> bool {\n    let s = input.trim().to_lowercase();\n    matches!(s.as_str(), \"\" | \"y\" | \"yes\")\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use tempfile::tempdir;\n\n    #[test]\n    #[ignore = \"slow\"]\n    fn get_oz_tags() {\n        let tmp = tempdir().unwrap();\n        let git = Git::new(tmp.path());\n        let installer = Installer { git, commit: false };\n\n        git.init().unwrap();\n\n        let dep: Dependency = \"openzeppelin/openzeppelin-contracts\".parse().unwrap();\n        let libs = tmp.path().join(\"libs\");\n        fs::create_dir(&libs).unwrap();\n        let submodule = libs.join(\"openzeppelin-contracts\");\n        installer.git_submodule(&dep, &submodule).unwrap();\n        assert!(submodule.exists());\n\n        let tags = installer.git_semver_tags(&submodule).unwrap();\n        assert!(!tags.is_empty());\n        let v480: Version = \"4.8.0\".parse().unwrap();\n        assert!(tags.iter().any(|(_, v)| v == &v480));\n    }\n}\n"
  },
  {
    "path": "crates/forge/src/cmd/lint.rs",
    "content": "use clap::{Parser, ValueHint};\nuse eyre::{Result, eyre};\nuse forge_lint::{\n    linter::Linter,\n    sol::{SolLint, SolLintError, SolidityLinter},\n};\nuse foundry_cli::{\n    opts::{BuildOpts, configure_pcx_from_solc, get_solar_sources_from_compile_output},\n    utils::{FoundryPathExt, LoadConfig},\n};\nuse foundry_common::{compile::ProjectCompiler, shell};\nuse foundry_compilers::{solc::SolcLanguage, utils::SOLC_EXTENSIONS};\nuse foundry_config::{filter::expand_globs, lint::Severity};\nuse std::path::PathBuf;\n\n/// CLI arguments for `forge lint`.\n#[derive(Clone, Debug, Parser)]\npub struct LintArgs {\n    /// Path to the file to be checked. Overrides the `ignore` project config.\n    #[arg(value_hint = ValueHint::FilePath, value_name = \"PATH\", num_args(1..))]\n    pub(crate) paths: Vec<PathBuf>,\n\n    /// Specifies which lints to run based on severity. Overrides the `severity` project config.\n    ///\n    /// Supported values: `high`, `med`, `low`, `info`, `gas`.\n    #[arg(long, value_name = \"SEVERITY\", num_args(1..))]\n    pub(crate) severity: Option<Vec<Severity>>,\n\n    /// Specifies which lints to run based on their ID (e.g., \"incorrect-shift\"). Overrides the\n    /// `exclude_lints` project config.\n    #[arg(long = \"only-lint\", value_name = \"LINT_ID\", num_args(1..))]\n    pub(crate) lint: Option<Vec<String>>,\n\n    #[command(flatten)]\n    pub(crate) build: BuildOpts,\n}\n\nfoundry_config::impl_figment_convert!(LintArgs, build);\n\nimpl LintArgs {\n    pub fn run(self) -> Result<()> {\n        let config = self.load_config()?;\n        let project = config.solar_project()?;\n        let path_config = config.project_paths();\n\n        // Expand ignore globs and canonicalize from the get go\n        let ignored = expand_globs(&config.root, config.lint.ignore.iter())?\n            .iter()\n            .flat_map(foundry_common::fs::canonicalize_path)\n            .collect::<Vec<_>>();\n\n        let cwd = std::env::current_dir()?;\n        let input = match &self.paths[..] {\n            [] => {\n                // Retrieve the project paths, and filter out the ignored ones.\n                config\n                    .project_paths::<SolcLanguage>()\n                    .input_files_iter()\n                    .filter(|p| !(ignored.contains(p) || ignored.contains(&cwd.join(p))))\n                    .collect()\n            }\n            paths => {\n                // Override default excluded paths and only lint the input files.\n                let mut inputs = Vec::with_capacity(paths.len());\n                for path in paths {\n                    if path.is_dir() {\n                        inputs\n                            .extend(foundry_compilers::utils::source_files(path, SOLC_EXTENSIONS));\n                    } else if path.is_sol() {\n                        inputs.push(path.to_path_buf());\n                    } else {\n                        warn!(\"cannot process path {}\", path.display());\n                    }\n                }\n                inputs\n            }\n        };\n\n        if input.is_empty() {\n            sh_println!(\"nothing to lint\")?;\n            return Ok(());\n        }\n\n        let parse_lints = |lints: &[String]| -> Result<Vec<SolLint>, SolLintError> {\n            lints.iter().map(|s| SolLint::try_from(s.as_str())).collect()\n        };\n\n        // Override default lint config with user-defined lints\n        // When --only-lint is used, bypass the severity filter by setting it to None\n        let (include, exclude, severity) = match &self.lint {\n            Some(cli_lints) => (Some(parse_lints(cli_lints)?), None, vec![]),\n            None => {\n                let severity = self.severity.clone().unwrap_or(config.lint.severity.clone());\n                (None, Some(parse_lints(&config.lint.exclude_lints)?), severity)\n            }\n        };\n\n        if project.compiler.solc.is_none() {\n            return Err(eyre!(\"linting not supported for this language\"));\n        }\n\n        let linter = SolidityLinter::new(path_config)\n            .with_json_emitter(shell::is_json())\n            .with_description(true)\n            .with_lints(include)\n            .without_lints(exclude)\n            .with_severity(if severity.is_empty() { None } else { Some(severity) })\n            .with_lint_specific(&config.lint.lint_specific);\n\n        let output = ProjectCompiler::new().files(input.iter().cloned()).compile(&project)?;\n        let solar_sources =\n            get_solar_sources_from_compile_output(&config, &output, Some(&input), Some(&ignored))?;\n        if solar_sources.input.sources.is_empty() {\n            return Err(eyre!(\"unable to lint. Solar only supports Solidity versions >=0.8.0\"));\n        }\n\n        // NOTE(rusowsky): Once solar can drop unsupported versions, rather than creating a new\n        // compiler, we should reuse the parser from the project output.\n        let mut compiler = solar::sema::Compiler::new(\n            solar::interface::Session::builder().with_stderr_emitter().build(),\n        );\n\n        // Load the solar-compatible sources to the pcx before linting\n        compiler.enter_mut(|compiler| {\n            let mut pcx = compiler.parse();\n            pcx.set_resolve_imports(true);\n            configure_pcx_from_solc(&mut pcx, &config.project_paths(), &solar_sources, true);\n            pcx.parse();\n        });\n        linter.lint(&input, config.deny, &mut compiler)?;\n\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "crates/forge/src/cmd/mod.rs",
    "content": "//! `forge` subcommands.\n//!\n//! All subcommands should respect the `foundry_config::Config`.\n//! If a subcommand accepts values that are supported by the `Config`, then the subcommand should\n//! implement `figment::Provider` which allows the subcommand to override the config's defaults, see\n//! [`foundry_config::Config`].\n\npub mod bind;\npub mod bind_json;\npub mod build;\npub mod cache;\npub mod clone;\npub mod compiler;\npub mod config;\npub mod coverage;\npub mod create;\npub mod doc;\npub mod eip712;\npub mod flatten;\npub mod fmt;\npub mod geiger;\npub mod generate;\npub mod init;\npub mod inspect;\npub mod install;\npub mod lint;\npub mod remappings;\npub mod remove;\npub mod selectors;\npub mod snapshot;\npub mod soldeer;\npub mod test;\npub mod tree;\npub mod update;\npub mod watch;\n"
  },
  {
    "path": "crates/forge/src/cmd/remappings.rs",
    "content": "use clap::{Parser, ValueHint};\nuse eyre::Result;\nuse foundry_cli::utils::LoadConfig;\nuse foundry_config::impl_figment_convert_basic;\nuse std::{collections::BTreeMap, path::PathBuf};\n\n/// CLI arguments for `forge remappings`.\n#[derive(Clone, Debug, Parser)]\npub struct RemappingArgs {\n    /// The project's root path.\n    ///\n    /// By default root of the Git repository, if in one,\n    /// or the current working directory.\n    #[arg(long, value_hint = ValueHint::DirPath, value_name = \"PATH\")]\n    root: Option<PathBuf>,\n    /// Pretty-print the remappings, grouping each of them by context.\n    #[arg(long)]\n    pretty: bool,\n}\nimpl_figment_convert_basic!(RemappingArgs);\n\nimpl RemappingArgs {\n    pub fn run(self) -> Result<()> {\n        let config = self.load_config()?;\n\n        if self.pretty {\n            let mut groups = BTreeMap::<_, Vec<_>>::new();\n            for remapping in config.remappings {\n                groups.entry(remapping.context.clone()).or_default().push(remapping);\n            }\n            for (group, remappings) in groups {\n                if let Some(group) = group {\n                    sh_println!(\"Context: {group}\")?;\n                } else {\n                    sh_println!(\"Global:\")?;\n                }\n\n                for mut remapping in remappings {\n                    remapping.context = None; // avoid writing context twice\n                    sh_println!(\"- {remapping}\")?;\n                }\n                sh_println!()?;\n            }\n        } else {\n            for remapping in config.remappings {\n                sh_println!(\"{remapping}\")?;\n            }\n        }\n\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "crates/forge/src/cmd/remove.rs",
    "content": "use crate::Lockfile;\nuse clap::{Parser, ValueHint};\nuse eyre::Result;\nuse foundry_cli::{\n    opts::Dependency,\n    utils::{Git, LoadConfig},\n};\nuse foundry_config::impl_figment_convert_basic;\nuse std::path::PathBuf;\n\n/// CLI arguments for `forge remove`.\n#[derive(Clone, Debug, Parser)]\npub struct RemoveArgs {\n    /// The dependencies you want to remove.\n    #[arg(required = true)]\n    dependencies: Vec<Dependency>,\n\n    /// The project's root path.\n    ///\n    /// By default root of the Git repository, if in one,\n    /// or the current working directory.\n    #[arg(long, value_hint = ValueHint::DirPath, value_name = \"PATH\")]\n    root: Option<PathBuf>,\n\n    /// Override the up-to-date check.\n    #[arg(short, long)]\n    force: bool,\n}\nimpl_figment_convert_basic!(RemoveArgs);\n\nimpl RemoveArgs {\n    pub fn run(self) -> Result<()> {\n        let config = self.load_config()?;\n        let (root, paths, _) = super::update::dependencies_paths(&self.dependencies, &config)?;\n        let git_modules = root.join(\".git/modules\");\n        let git = Git::new(&root);\n        let mut lockfile = Lockfile::new(&config.root).with_git(&git);\n        let _synced = lockfile.sync(config.install_lib_dir())?;\n\n        // remove all the dependencies by invoking `git rm` only once with all the paths\n        git.rm(self.force, &paths)?;\n\n        // remove all the dependencies from .git/modules\n        for (Dependency { name, tag, .. }, path) in self.dependencies.iter().zip(&paths) {\n            // Get the URL from git submodule config instead of using the parsed dependency URL\n            let url = git.submodule_url(path).unwrap_or(None);\n            sh_println!(\n                \"Removing '{name}' in {}, (url: {}, tag: {})\",\n                path.display(),\n                url.as_deref().unwrap_or(\"None\"),\n                tag.as_deref().unwrap_or(\"None\")\n            )?;\n            let _ = lockfile.remove(path);\n            std::fs::remove_dir_all(git_modules.join(path))?;\n        }\n\n        lockfile.write()?;\n\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "crates/forge/src/cmd/selectors.rs",
    "content": "use alloy_primitives::hex;\nuse clap::Parser;\nuse comfy_table::{Table, modifiers::UTF8_ROUND_CORNERS, presets::ASCII_MARKDOWN};\nuse eyre::Result;\nuse foundry_cli::{\n    opts::{BuildOpts, CompilerOpts, ProjectPathOpts},\n    utils::{FoundryPathExt, cache_local_signatures, cache_signatures_from_abis},\n};\nuse foundry_common::{\n    compile::{PathOrContractInfo, ProjectCompiler, compile_target},\n    selectors::{SelectorImportData, import_selectors},\n    shell,\n};\nuse foundry_compilers::{artifacts::output_selection::ContractOutputSelection, info::ContractInfo};\nuse std::{collections::BTreeMap, fs::canonicalize};\n\n/// CLI arguments for `forge selectors`.\n#[derive(Clone, Debug, Parser)]\npub enum SelectorsSubcommands {\n    /// Check for selector collisions between contracts\n    #[command(visible_alias = \"co\")]\n    Collision {\n        /// The first of the two contracts for which to look selector collisions for, in the form\n        /// `(<path>:)?<contractname>`.\n        first_contract: ContractInfo,\n\n        /// The second of the two contracts for which to look selector collisions for, in the form\n        /// `(<path>:)?<contractname>`.\n        second_contract: ContractInfo,\n\n        #[command(flatten)]\n        build: Box<BuildOpts>,\n    },\n\n    /// Upload selectors to registry\n    #[command(visible_alias = \"up\")]\n    Upload {\n        /// The name of the contract to upload selectors for.\n        /// Can also be in form of `path:contract name`.\n        #[arg(required_unless_present = \"all\")]\n        contract: Option<PathOrContractInfo>,\n\n        /// Upload selectors for all contracts in the project.\n        #[arg(long, required_unless_present = \"contract\")]\n        all: bool,\n\n        #[command(flatten)]\n        project_paths: ProjectPathOpts,\n    },\n\n    /// List selectors from current workspace\n    #[command(visible_alias = \"ls\")]\n    List {\n        /// The name of the contract to list selectors for.\n        #[arg(help = \"The name of the contract to list selectors for.\")]\n        contract: Option<String>,\n\n        #[command(flatten)]\n        project_paths: ProjectPathOpts,\n\n        #[arg(long, help = \"Do not group the selectors by contract in separate tables.\")]\n        no_group: bool,\n    },\n\n    /// Find if a selector is present in the project\n    #[command(visible_alias = \"f\")]\n    Find {\n        /// The selector to search for\n        #[arg(help = \"The selector to search for (with or without 0x prefix)\")]\n        selector: String,\n\n        #[command(flatten)]\n        project_paths: ProjectPathOpts,\n    },\n\n    /// Cache project selectors (enables trace with local contracts functions and events).\n    #[command(visible_alias = \"c\")]\n    Cache {\n        #[arg(long, help = \"Path to a folder containing additional abis to include in the cache\")]\n        extra_abis_path: Option<String>,\n        #[command(flatten)]\n        project_paths: ProjectPathOpts,\n    },\n}\n\nimpl SelectorsSubcommands {\n    pub async fn run(self) -> Result<()> {\n        match self {\n            Self::Cache { project_paths, extra_abis_path } => {\n                if let Some(extra_abis_path) = extra_abis_path {\n                    sh_println!(\"Caching selectors for ABIs at {extra_abis_path}\")?;\n                    cache_signatures_from_abis(extra_abis_path)?;\n                }\n\n                sh_println!(\"Caching selectors for contracts in the project...\")?;\n                let build_args = BuildOpts {\n                    project_paths,\n                    compiler: CompilerOpts {\n                        extra_output: vec![ContractOutputSelection::Abi],\n                        ..Default::default()\n                    },\n                    ..Default::default()\n                };\n\n                // compile the project to get the artifacts/abis\n                let project = build_args.project()?;\n                let outcome = ProjectCompiler::new().quiet(true).compile(&project)?;\n                cache_local_signatures(&outcome)?;\n            }\n            Self::Upload { contract, all, project_paths } => {\n                let build_args = BuildOpts {\n                    project_paths: project_paths.clone(),\n                    compiler: CompilerOpts {\n                        extra_output: vec![ContractOutputSelection::Abi],\n                        ..Default::default()\n                    },\n                    ..Default::default()\n                };\n\n                let project = build_args.project()?;\n                let output = if let Some(contract_info) = &contract {\n                    let Some(contract_name) = contract_info.name() else {\n                        eyre::bail!(\"No contract name provided.\")\n                    };\n\n                    let target_path = contract_info\n                        .path()\n                        .map(Ok)\n                        .unwrap_or_else(|| project.find_contract_path(contract_name))?;\n                    compile_target(&target_path, &project, false)?\n                } else {\n                    ProjectCompiler::new().compile(&project)?\n                };\n                let artifacts = if all {\n                    output\n                        .into_artifacts_with_files()\n                        .filter(|(file, _, _)| {\n                            let is_sources_path = file.starts_with(&project.paths.sources);\n                            let is_test = file.is_sol_test();\n\n                            is_sources_path && !is_test\n                        })\n                        .map(|(_, contract, artifact)| (contract, artifact))\n                        .collect()\n                } else {\n                    let contract_info = contract.unwrap();\n                    let contract = contract_info.name().unwrap().to_string();\n\n                    let found_artifact = if let Some(path) = contract_info.path() {\n                        output.find(project.root().join(path).as_path(), &contract)\n                    } else {\n                        output.find_first(&contract)\n                    };\n\n                    let artifact = found_artifact\n                        .ok_or_else(|| {\n                            eyre::eyre!(\n                                \"Could not find artifact `{contract}` in the compiled artifacts\"\n                            )\n                        })?\n                        .clone();\n                    vec![(contract, artifact)]\n                };\n\n                let mut artifacts = artifacts.into_iter().peekable();\n                while let Some((contract, artifact)) = artifacts.next() {\n                    let abi = artifact.abi.ok_or_else(|| eyre::eyre!(\"Unable to fetch abi\"))?;\n                    if abi.functions.is_empty() && abi.events.is_empty() && abi.errors.is_empty() {\n                        continue;\n                    }\n\n                    sh_println!(\"Uploading selectors for {contract}...\")?;\n\n                    // upload abi to selector database\n                    import_selectors(SelectorImportData::Abi(vec![abi])).await?.describe();\n\n                    if artifacts.peek().is_some() {\n                        sh_println!()?\n                    }\n                }\n            }\n            Self::Collision { mut first_contract, mut second_contract, build } => {\n                // Compile the project with the two contracts included\n                let project = build.project()?;\n                let mut compiler = ProjectCompiler::new().quiet(true);\n\n                if let Some(contract_path) = &mut first_contract.path {\n                    let target_path = canonicalize(&*contract_path)?;\n                    *contract_path = target_path.to_string_lossy().to_string();\n                    compiler = compiler.files([target_path]);\n                }\n                if let Some(contract_path) = &mut second_contract.path {\n                    let target_path = canonicalize(&*contract_path)?;\n                    *contract_path = target_path.to_string_lossy().to_string();\n                    compiler = compiler.files([target_path]);\n                }\n\n                let output = compiler.compile(&project)?;\n\n                // Check method selectors for collisions\n                let methods = |contract: &ContractInfo| -> eyre::Result<_> {\n                    let artifact = output\n                        .find_contract(contract)\n                        .ok_or_else(|| eyre::eyre!(\"Could not find artifact for {contract}\"))?;\n                    artifact.method_identifiers.as_ref().ok_or_else(|| {\n                        eyre::eyre!(\"Could not find method identifiers for {contract}\")\n                    })\n                };\n                let first_method_map = methods(&first_contract)?;\n                let second_method_map = methods(&second_contract)?;\n\n                let colliding_methods: Vec<(&String, &String, &String)> = first_method_map\n                    .iter()\n                    .filter_map(|(k1, v1)| {\n                        second_method_map\n                            .iter()\n                            .find_map(|(k2, v2)| if **v2 == *v1 { Some((k2, v2)) } else { None })\n                            .map(|(k2, v2)| (v2, k1, k2))\n                    })\n                    .collect();\n\n                if colliding_methods.is_empty() {\n                    sh_println!(\"No colliding method selectors between the two contracts.\")?;\n                } else {\n                    let mut table = Table::new();\n                    if shell::is_markdown() {\n                        table.load_preset(ASCII_MARKDOWN);\n                    } else {\n                        table.apply_modifier(UTF8_ROUND_CORNERS);\n                    }\n                    table.set_header([\n                        String::from(\"Selector\"),\n                        first_contract.name,\n                        second_contract.name,\n                    ]);\n                    for method in &colliding_methods {\n                        table.add_row([method.0, method.1, method.2]);\n                    }\n                    sh_println!(\"{} collisions found:\", colliding_methods.len())?;\n                    sh_println!(\"\\n{table}\\n\")?;\n                }\n            }\n            Self::List { contract, project_paths, no_group } => {\n                sh_println!(\"Listing selectors for contracts in the project...\")?;\n                let build_args = BuildOpts {\n                    project_paths,\n                    compiler: CompilerOpts {\n                        extra_output: vec![ContractOutputSelection::Abi],\n                        ..Default::default()\n                    },\n                    ..Default::default()\n                };\n\n                // compile the project to get the artifacts/abis\n                let project = build_args.project()?;\n                let outcome = ProjectCompiler::new().quiet(true).compile(&project)?;\n                let artifacts = if let Some(contract) = contract {\n                    let found_artifact = outcome.find_first(&contract);\n                    let artifact = found_artifact\n                        .ok_or_else(|| {\n                            let candidates = outcome\n                                .artifacts()\n                                .map(|(name, _,)| name)\n                                .collect::<Vec<_>>();\n                            let suggestion = if let Some(suggestion) = foundry_cli::utils::did_you_mean(&contract, candidates).pop() {\n                                format!(\"\\nDid you mean `{suggestion}`?\")\n                            } else {\n                                String::new()\n                            };\n                            eyre::eyre!(\n                                \"Could not find artifact `{contract}` in the compiled artifacts{suggestion}\",\n                            )\n                        })?\n                        .clone();\n                    vec![(contract, artifact)]\n                } else {\n                    outcome\n                        .into_artifacts_with_files()\n                        .filter(|(file, _, _)| {\n                            let is_sources_path = file.starts_with(&project.paths.sources);\n                            let is_test = file.is_sol_test();\n\n                            is_sources_path && !is_test\n                        })\n                        .map(|(_, contract, artifact)| (contract, artifact))\n                        .collect()\n                };\n\n                let mut artifacts = artifacts.into_iter().peekable();\n\n                #[derive(PartialEq, PartialOrd, Eq, Ord)]\n                enum SelectorType {\n                    Function,\n                    Event,\n                    Error,\n                }\n                impl std::fmt::Display for SelectorType {\n                    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n                        match self {\n                            Self::Function => write!(f, \"Function\"),\n                            Self::Event => write!(f, \"Event\"),\n                            Self::Error => write!(f, \"Error\"),\n                        }\n                    }\n                }\n\n                let mut selectors =\n                    BTreeMap::<String, BTreeMap<SelectorType, Vec<(String, String)>>>::new();\n\n                for (contract, artifact) in artifacts.by_ref() {\n                    let abi = artifact.abi.ok_or_else(|| eyre::eyre!(\"Unable to fetch abi\"))?;\n\n                    let contract_selectors = selectors.entry(contract.clone()).or_default();\n\n                    for func in abi.functions() {\n                        let sig = func.signature();\n                        let selector = func.selector();\n                        contract_selectors\n                            .entry(SelectorType::Function)\n                            .or_default()\n                            .push((hex::encode_prefixed(selector), sig));\n                    }\n\n                    for event in abi.events() {\n                        let sig = event.signature();\n                        let selector = event.selector();\n                        contract_selectors\n                            .entry(SelectorType::Event)\n                            .or_default()\n                            .push((hex::encode_prefixed(selector), sig));\n                    }\n\n                    for error in abi.errors() {\n                        let sig = error.signature();\n                        let selector = error.selector();\n                        contract_selectors\n                            .entry(SelectorType::Error)\n                            .or_default()\n                            .push((hex::encode_prefixed(selector), sig));\n                    }\n                }\n\n                if no_group {\n                    let mut table = Table::new();\n                    if shell::is_markdown() {\n                        table.load_preset(ASCII_MARKDOWN);\n                    } else {\n                        table.apply_modifier(UTF8_ROUND_CORNERS);\n                    }\n                    table.set_header([\"Type\", \"Signature\", \"Selector\", \"Contract\"]);\n\n                    for (contract, contract_selectors) in selectors {\n                        for (selector_type, selectors) in contract_selectors {\n                            for (selector, sig) in selectors {\n                                table.add_row([\n                                    selector_type.to_string(),\n                                    sig,\n                                    selector,\n                                    contract.to_string(),\n                                ]);\n                            }\n                        }\n                    }\n\n                    sh_println!(\"\\n{table}\")?;\n                } else {\n                    for (idx, (contract, contract_selectors)) in selectors.into_iter().enumerate() {\n                        sh_println!(\"{}{contract}\", if idx == 0 { \"\" } else { \"\\n\" })?;\n                        let mut table = Table::new();\n                        if shell::is_markdown() {\n                            table.load_preset(ASCII_MARKDOWN);\n                        } else {\n                            table.apply_modifier(UTF8_ROUND_CORNERS);\n                        }\n                        table.set_header([\"Type\", \"Signature\", \"Selector\"]);\n\n                        for (selector_type, selectors) in contract_selectors {\n                            for (selector, sig) in selectors {\n                                table.add_row([selector_type.to_string(), sig, selector]);\n                            }\n                        }\n                        sh_println!(\"\\n{table}\")?;\n                    }\n                }\n            }\n\n            Self::Find { selector, project_paths } => {\n                sh_println!(\"Searching for selector {selector:?} in the project...\")?;\n\n                let build_args = BuildOpts {\n                    project_paths,\n                    compiler: CompilerOpts {\n                        extra_output: vec![ContractOutputSelection::Abi],\n                        ..Default::default()\n                    },\n                    ..Default::default()\n                };\n\n                let project = build_args.project()?;\n                let outcome = ProjectCompiler::new().quiet(true).compile(&project)?;\n                let artifacts = outcome\n                    .into_artifacts_with_files()\n                    .filter(|(file, _, _)| {\n                        let is_sources_path = file.starts_with(&project.paths.sources);\n                        let is_test = file.is_sol_test();\n                        is_sources_path && !is_test\n                    })\n                    .collect::<Vec<_>>();\n\n                let mut table = Table::new();\n                if shell::is_markdown() {\n                    table.load_preset(ASCII_MARKDOWN);\n                } else {\n                    table.apply_modifier(UTF8_ROUND_CORNERS);\n                }\n\n                table.set_header([\"Type\", \"Signature\", \"Selector\", \"Contract\"]);\n\n                let selector_str = selector.strip_prefix(\"0x\").unwrap_or(selector.as_str());\n                let selector_bytes = hex::decode(selector_str)?;\n\n                for (_file, contract, artifact) in artifacts {\n                    let abi = artifact.abi.ok_or_else(|| eyre::eyre!(\"Unable to fetch abi\"))?;\n\n                    for func in abi.functions() {\n                        if func.selector().as_slice().starts_with(selector_bytes.as_slice()) {\n                            table.add_row([\n                                \"Function\",\n                                &func.signature(),\n                                &hex::encode_prefixed(func.selector()),\n                                contract.as_str(),\n                            ]);\n                        }\n                    }\n\n                    for event in abi.events() {\n                        if event.selector().as_slice().starts_with(selector_bytes.as_slice()) {\n                            table.add_row([\n                                \"Event\",\n                                &event.signature(),\n                                &hex::encode_prefixed(event.selector()),\n                                contract.as_str(),\n                            ]);\n                        }\n                    }\n\n                    for error in abi.errors() {\n                        if error.selector().as_slice().starts_with(selector_bytes.as_slice()) {\n                            table.add_row([\n                                \"Error\",\n                                &error.signature(),\n                                &hex::encode_prefixed(error.selector()),\n                                contract.as_str(),\n                            ]);\n                        }\n                    }\n                }\n\n                if table.row_count() > 0 {\n                    sh_println!(\"\\nFound {} instance(s)...\", table.row_count())?;\n                    sh_println!(\"\\n{table}\\n\")?;\n                } else {\n                    return Err(eyre::eyre!(\"\\nSelector not found in the project.\"));\n                }\n            }\n        }\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "crates/forge/src/cmd/snapshot.rs",
    "content": "use super::test;\nuse crate::result::{SuiteTestResult, TestKindReport, TestOutcome};\nuse alloy_primitives::{U256, map::HashMap};\nuse clap::{Parser, ValueHint, builder::RangedU64ValueParser};\nuse comfy_table::{\n    Cell, Color, Row, Table, modifiers::UTF8_ROUND_CORNERS, presets::ASCII_MARKDOWN,\n};\nuse eyre::{Context, Result};\nuse foundry_cli::utils::STATIC_FUZZ_SEED;\nuse foundry_common::shell;\nuse regex::Regex;\nuse std::{\n    cmp::Ordering,\n    fs,\n    io::{self, BufRead},\n    path::{Path, PathBuf},\n    str::FromStr,\n    sync::LazyLock,\n};\nuse yansi::Paint;\n\n/// A regex that matches a basic snapshot entry like\n/// `Test:testDeposit() (gas: 58804)`\npub static RE_BASIC_SNAPSHOT_ENTRY: LazyLock<Regex> = LazyLock::new(|| {\n    Regex::new(r\"(?P<file>(.*?)):(?P<sig>(\\w+)\\s*\\((.*?)\\))\\s*\\(((gas:)?\\s*(?P<gas>\\d+)|(runs:\\s*(?P<runs>\\d+),\\s*μ:\\s*(?P<avg>\\d+),\\s*~:\\s*(?P<med>\\d+))|(runs:\\s*(?P<invruns>\\d+),\\s*calls:\\s*(?P<calls>\\d+),\\s*reverts:\\s*(?P<reverts>\\d+)))\\)\").unwrap()\n});\n\n/// CLI arguments for `forge snapshot`.\n#[derive(Clone, Debug, Parser)]\npub struct GasSnapshotArgs {\n    /// Output a diff against a pre-existing gas snapshot.\n    ///\n    /// By default, the comparison is done with .gas-snapshot.\n    #[arg(\n        conflicts_with = \"snap\",\n        long,\n        value_hint = ValueHint::FilePath,\n        value_name = \"SNAPSHOT_FILE\",\n    )]\n    diff: Option<Option<PathBuf>>,\n\n    /// Compare against a pre-existing gas snapshot, exiting with code 1 if they do not match.\n    ///\n    /// Outputs a diff if the gas snapshots do not match.\n    ///\n    /// By default, the comparison is done with .gas-snapshot.\n    #[arg(\n        conflicts_with = \"diff\",\n        long,\n        value_hint = ValueHint::FilePath,\n        value_name = \"SNAPSHOT_FILE\",\n    )]\n    check: Option<Option<PathBuf>>,\n\n    // Hidden because there is only one option\n    /// How to format the output.\n    #[arg(long, hide(true))]\n    format: Option<Format>,\n\n    /// Output file for the gas snapshot.\n    #[arg(\n        long,\n        default_value = \".gas-snapshot\",\n        value_hint = ValueHint::FilePath,\n        value_name = \"FILE\",\n    )]\n    snap: PathBuf,\n\n    /// Tolerates gas deviations up to the specified percentage.\n    #[arg(\n        long,\n        value_parser = RangedU64ValueParser::<u32>::new().range(0..100),\n        value_name = \"SNAPSHOT_THRESHOLD\"\n    )]\n    tolerance: Option<u32>,\n\n    /// How to sort diff results.\n    #[arg(long, value_name = \"ORDER\")]\n    diff_sort: Option<DiffSortOrder>,\n\n    /// All test arguments are supported\n    #[command(flatten)]\n    pub(crate) test: test::TestArgs,\n\n    /// Additional configs for test results\n    #[command(flatten)]\n    config: GasSnapshotConfig,\n}\n\nimpl GasSnapshotArgs {\n    /// Returns whether `GasSnapshotArgs` was configured with `--watch`\n    pub fn is_watch(&self) -> bool {\n        self.test.is_watch()\n    }\n\n    /// Returns the [`watchexec::Config`] necessary to bootstrap a new watch loop.\n    pub(crate) fn watchexec_config(&self) -> Result<watchexec::Config> {\n        self.test.watchexec_config()\n    }\n\n    pub async fn run(mut self) -> Result<()> {\n        // Set fuzz seed so gas snapshots are deterministic\n        self.test.fuzz_seed = Some(U256::from_be_bytes(STATIC_FUZZ_SEED));\n\n        let outcome = self.test.compile_and_run().await?;\n        outcome.ensure_ok(false)?;\n        let tests = self.config.apply(outcome);\n\n        if let Some(path) = self.diff {\n            let snap = path.as_ref().unwrap_or(&self.snap);\n            let snaps = read_gas_snapshot(snap)?;\n            diff(tests, snaps, self.diff_sort.unwrap_or_default())?;\n        } else if let Some(path) = self.check {\n            let snap = path.as_ref().unwrap_or(&self.snap);\n            let snaps = read_gas_snapshot(snap)?;\n            if check(tests, snaps, self.tolerance) {\n                std::process::exit(0)\n            } else {\n                std::process::exit(1)\n            }\n        } else {\n            if matches!(self.format, Some(Format::Table)) {\n                let table = build_gas_snapshot_table(&tests);\n                sh_println!(\"\\n{}\", table)?;\n            }\n            write_to_gas_snapshot_file(&tests, self.snap, self.format)?;\n        }\n        Ok(())\n    }\n}\n\n// Gas report format on stdout.\n#[derive(Clone, Debug)]\npub enum Format {\n    Table,\n}\n\nimpl FromStr for Format {\n    type Err = String;\n\n    fn from_str(s: &str) -> Result<Self, Self::Err> {\n        match s {\n            \"t\" | \"table\" => Ok(Self::Table),\n            _ => Err(format!(\"Unrecognized format `{s}`\")),\n        }\n    }\n}\n\n/// Additional filters that can be applied on the test results\n#[derive(Clone, Debug, Default, Parser)]\nstruct GasSnapshotConfig {\n    /// Sort results by gas used (ascending).\n    #[arg(long)]\n    asc: bool,\n\n    /// Sort results by gas used (descending).\n    #[arg(conflicts_with = \"asc\", long)]\n    desc: bool,\n\n    /// Only include tests that used more gas that the given amount.\n    #[arg(long, value_name = \"MIN_GAS\")]\n    min: Option<u64>,\n\n    /// Only include tests that used less gas that the given amount.\n    #[arg(long, value_name = \"MAX_GAS\")]\n    max: Option<u64>,\n}\n\n/// Sort order for diff output\n#[derive(Clone, Debug, Default, clap::ValueEnum)]\nenum DiffSortOrder {\n    /// Sort by percentage change (smallest to largest) - default behavior\n    #[default]\n    Percentage,\n    /// Sort by percentage change (largest to smallest)\n    PercentageDesc,\n    /// Sort by absolute gas change (smallest to largest)\n    Absolute,\n    /// Sort by absolute gas change (largest to smallest)\n    AbsoluteDesc,\n}\n\nimpl GasSnapshotConfig {\n    fn is_in_gas_range(&self, gas_used: u64) -> bool {\n        if let Some(min) = self.min\n            && gas_used < min\n        {\n            return false;\n        }\n        if let Some(max) = self.max\n            && gas_used > max\n        {\n            return false;\n        }\n        true\n    }\n\n    fn apply(&self, outcome: TestOutcome) -> Vec<SuiteTestResult> {\n        let mut tests = outcome\n            .into_tests()\n            .filter(|test| self.is_in_gas_range(test.gas_used()))\n            .collect::<Vec<_>>();\n\n        if self.asc {\n            tests.sort_by_key(|a| a.gas_used());\n        } else if self.desc {\n            tests.sort_by_key(|b| std::cmp::Reverse(b.gas_used()))\n        }\n\n        tests\n    }\n}\n\n/// A general entry in a gas snapshot file\n///\n/// Has the form:\n///   `<signature>(gas:? 40181)` for normal tests\n///   `<signature>(runs: 256, μ: 40181, ~: 40181)` for fuzz tests\n///   `<signature>(runs: 256, calls: 40181, reverts: 40181)` for invariant tests\n#[derive(Clone, Debug, PartialEq, Eq)]\npub struct GasSnapshotEntry {\n    pub contract_name: String,\n    pub signature: String,\n    pub gas_used: TestKindReport,\n}\n\nimpl FromStr for GasSnapshotEntry {\n    type Err = String;\n\n    fn from_str(s: &str) -> Result<Self, Self::Err> {\n        RE_BASIC_SNAPSHOT_ENTRY\n            .captures(s)\n            .and_then(|cap| {\n                cap.name(\"file\").and_then(|file| {\n                    cap.name(\"sig\").and_then(|sig| {\n                        if let Some(gas) = cap.name(\"gas\") {\n                            Some(Self {\n                                contract_name: file.as_str().to_string(),\n                                signature: sig.as_str().to_string(),\n                                gas_used: TestKindReport::Unit {\n                                    gas: gas.as_str().parse().unwrap(),\n                                },\n                            })\n                        } else if let Some(runs) = cap.name(\"runs\") {\n                            cap.name(\"avg\")\n                                .and_then(|avg| cap.name(\"med\").map(|med| (runs, avg, med)))\n                                .map(|(runs, avg, med)| Self {\n                                    contract_name: file.as_str().to_string(),\n                                    signature: sig.as_str().to_string(),\n                                    gas_used: TestKindReport::Fuzz {\n                                        runs: runs.as_str().parse().unwrap(),\n                                        median_gas: med.as_str().parse().unwrap(),\n                                        mean_gas: avg.as_str().parse().unwrap(),\n                                        failed_corpus_replays: 0,\n                                    },\n                                })\n                        } else {\n                            cap.name(\"invruns\")\n                                .and_then(|runs| {\n                                    cap.name(\"calls\").and_then(|avg| {\n                                        cap.name(\"reverts\").map(|med| (runs, avg, med))\n                                    })\n                                })\n                                .map(|(runs, calls, reverts)| Self {\n                                    contract_name: file.as_str().to_string(),\n                                    signature: sig.as_str().to_string(),\n                                    gas_used: TestKindReport::Invariant {\n                                        runs: runs.as_str().parse().unwrap(),\n                                        calls: calls.as_str().parse().unwrap(),\n                                        reverts: reverts.as_str().parse().unwrap(),\n                                        metrics: HashMap::default(),\n                                        failed_corpus_replays: 0,\n                                        optimization_best_value: None,\n                                    },\n                                })\n                        }\n                    })\n                })\n            })\n            .ok_or_else(|| format!(\"Could not extract Snapshot Entry for {s}\"))\n    }\n}\n\n/// Reads a list of gas snapshot entries from a gas snapshot file.\nfn read_gas_snapshot(path: impl AsRef<Path>) -> Result<Vec<GasSnapshotEntry>> {\n    let path = path.as_ref();\n    let mut entries = Vec::new();\n    for line in io::BufReader::new(\n        fs::File::open(path)\n            .wrap_err(format!(\"failed to read snapshot file \\\"{}\\\"\", path.display()))?,\n    )\n    .lines()\n    {\n        entries\n            .push(GasSnapshotEntry::from_str(line?.as_str()).map_err(|err| eyre::eyre!(\"{err}\"))?);\n    }\n    Ok(entries)\n}\n\n/// Writes a series of tests to a gas snapshot file after sorting them.\nfn write_to_gas_snapshot_file(\n    tests: &[SuiteTestResult],\n    path: impl AsRef<Path>,\n    _format: Option<Format>,\n) -> Result<()> {\n    let mut reports = tests\n        .iter()\n        .map(|test| {\n            format!(\"{}:{} {}\", test.contract_name(), test.signature, test.result.kind.report())\n        })\n        .collect::<Vec<_>>();\n\n    // sort all reports\n    reports.sort();\n\n    let content = reports.join(\"\\n\");\n    Ok(fs::write(path, content)?)\n}\n\nfn build_gas_snapshot_table(tests: &[SuiteTestResult]) -> Table {\n    let mut table = Table::new();\n    if shell::is_markdown() {\n        table.load_preset(ASCII_MARKDOWN);\n    } else {\n        table.apply_modifier(UTF8_ROUND_CORNERS);\n    }\n\n    table.set_header(vec![\n        Cell::new(\"Contract\").fg(Color::Cyan),\n        Cell::new(\"Signature\").fg(Color::Cyan),\n        Cell::new(\"Report\").fg(Color::Cyan),\n    ]);\n\n    for test in tests {\n        let mut row = Row::new();\n        row.add_cell(Cell::new(test.contract_name()));\n        row.add_cell(Cell::new(&test.signature));\n        row.add_cell(Cell::new(test.result.kind.report()));\n        table.add_row(row);\n    }\n\n    table\n}\n\n/// A Gas snapshot entry diff.\n#[derive(Clone, Debug, PartialEq, Eq)]\npub struct GasSnapshotDiff {\n    pub signature: String,\n    pub source_gas_used: TestKindReport,\n    pub target_gas_used: TestKindReport,\n}\n\nimpl GasSnapshotDiff {\n    /// Returns the gas diff\n    ///\n    /// `> 0` if the source used more gas\n    /// `< 0` if the target used more gas\n    fn gas_change(&self) -> i128 {\n        self.source_gas_used.gas() as i128 - self.target_gas_used.gas() as i128\n    }\n\n    /// Determines the percentage change\n    fn gas_diff(&self) -> f64 {\n        self.gas_change() as f64 / self.target_gas_used.gas() as f64\n    }\n}\n\n/// Compares the set of tests with an existing gas snapshot.\n///\n/// Returns true all tests match\nfn check(\n    tests: Vec<SuiteTestResult>,\n    snaps: Vec<GasSnapshotEntry>,\n    tolerance: Option<u32>,\n) -> bool {\n    let snaps = snaps\n        .into_iter()\n        .map(|s| ((s.contract_name, s.signature), s.gas_used))\n        .collect::<HashMap<_, _>>();\n    let mut has_diff = false;\n    for test in tests {\n        if let Some(target_gas) =\n            snaps.get(&(test.contract_name().to_string(), test.signature.clone())).cloned()\n        {\n            let source_gas = test.result.kind.report();\n            if !within_tolerance(source_gas.gas(), target_gas.gas(), tolerance) {\n                let _ = sh_println!(\n                    \"Diff in \\\"{}::{}\\\": consumed \\\"{}\\\" gas, expected \\\"{}\\\" gas \",\n                    test.contract_name(),\n                    test.signature,\n                    source_gas,\n                    target_gas\n                );\n                has_diff = true;\n            }\n        } else {\n            let _ = sh_println!(\n                \"No matching snapshot entry found for \\\"{}::{}\\\" in snapshot file\",\n                test.contract_name(),\n                test.signature\n            );\n            has_diff = true;\n        }\n    }\n    !has_diff\n}\n\n/// Compare the set of tests with an existing gas snapshot.\nfn diff(\n    tests: Vec<SuiteTestResult>,\n    snaps: Vec<GasSnapshotEntry>,\n    sort_order: DiffSortOrder,\n) -> Result<()> {\n    let snaps = snaps\n        .into_iter()\n        .map(|s| ((s.contract_name, s.signature), s.gas_used))\n        .collect::<HashMap<_, _>>();\n    let mut diffs = Vec::with_capacity(tests.len());\n    let mut new_tests = Vec::new();\n\n    for test in tests.into_iter() {\n        if let Some(target_gas_used) =\n            snaps.get(&(test.contract_name().to_string(), test.signature.clone())).cloned()\n        {\n            diffs.push(GasSnapshotDiff {\n                source_gas_used: test.result.kind.report(),\n                signature: format!(\"{}::{}\", test.contract_name(), test.signature),\n                target_gas_used,\n            });\n        } else {\n            // Track new tests\n            new_tests.push(format!(\"{}::{}\", test.contract_name(), test.signature));\n        }\n    }\n\n    let mut increased = 0;\n    let mut decreased = 0;\n    let mut unchanged = 0;\n    let mut overall_gas_change = 0i128;\n    let mut overall_gas_used = 0i128;\n\n    // Sort based on user preference\n    match sort_order {\n        DiffSortOrder::Percentage => {\n            // Default: sort by percentage change (smallest to largest)\n            diffs.sort_by(|a, b| a.gas_diff().abs().total_cmp(&b.gas_diff().abs()));\n        }\n        DiffSortOrder::PercentageDesc => {\n            // Sort by percentage change (largest to smallest)\n            diffs.sort_by(|a, b| b.gas_diff().abs().total_cmp(&a.gas_diff().abs()));\n        }\n        DiffSortOrder::Absolute => {\n            // Sort by absolute gas change (smallest to largest)\n            diffs.sort_by_key(|d| d.gas_change().abs());\n        }\n        DiffSortOrder::AbsoluteDesc => {\n            // Sort by absolute gas change (largest to smallest)\n            diffs.sort_by_key(|d| std::cmp::Reverse(d.gas_change().abs()));\n        }\n    }\n\n    for diff in &diffs {\n        let gas_change = diff.gas_change();\n        overall_gas_change += gas_change;\n        overall_gas_used += diff.target_gas_used.gas() as i128;\n        let gas_diff = diff.gas_diff();\n\n        // Classify changes\n        if gas_change > 0 {\n            increased += 1;\n        } else if gas_change < 0 {\n            decreased += 1;\n        } else {\n            unchanged += 1;\n        }\n\n        // Display with icon and before/after values\n        let icon = if gas_change > 0 {\n            \"↑\".red().to_string()\n        } else if gas_change < 0 {\n            \"↓\".green().to_string()\n        } else {\n            \"━\".to_string()\n        };\n\n        sh_println!(\n            \"{} {} (gas: {} → {} | {} {})\",\n            icon,\n            diff.signature,\n            diff.target_gas_used.gas(),\n            diff.source_gas_used.gas(),\n            fmt_change(gas_change),\n            fmt_pct_change(gas_diff)\n        )?;\n    }\n\n    // Display new tests if any\n    if !new_tests.is_empty() {\n        sh_println!(\"\\n{}\", \"New tests:\".yellow())?;\n        for test in new_tests {\n            sh_println!(\"  {} {}\", \"+\".green(), test)?;\n        }\n    }\n\n    // Summary separator\n    sh_println!(\"\\n{}\", \"-\".repeat(80))?;\n\n    let overall_gas_diff = if overall_gas_used > 0 {\n        overall_gas_change as f64 / overall_gas_used as f64\n    } else {\n        0.0\n    };\n\n    sh_println!(\n        \"Total tests: {}, {} {}, {} {}, {} {}\",\n        diffs.len(),\n        \"↑\".red().to_string(),\n        increased,\n        \"↓\".green().to_string(),\n        decreased,\n        \"━\",\n        unchanged\n    )?;\n    sh_println!(\n        \"Overall gas change: {} ({})\",\n        fmt_change(overall_gas_change),\n        fmt_pct_change(overall_gas_diff)\n    )?;\n    Ok(())\n}\n\nfn fmt_pct_change(change: f64) -> String {\n    let change_pct = change * 100.0;\n    match change.total_cmp(&0.0) {\n        Ordering::Less => format!(\"{change_pct:.3}%\").green().to_string(),\n        Ordering::Equal => {\n            format!(\"{change_pct:.3}%\")\n        }\n        Ordering::Greater => format!(\"{change_pct:.3}%\").red().to_string(),\n    }\n}\n\nfn fmt_change(change: i128) -> String {\n    match change.cmp(&0) {\n        Ordering::Less => format!(\"{change}\").green().to_string(),\n        Ordering::Equal => change.to_string(),\n        Ordering::Greater => format!(\"{change}\").red().to_string(),\n    }\n}\n\n/// Returns true of the difference between the gas values exceeds the tolerance\n///\n/// If `tolerance` is `None`, then this returns `true` if both gas values are equal\nfn within_tolerance(source_gas: u64, target_gas: u64, tolerance_pct: Option<u32>) -> bool {\n    if let Some(tolerance) = tolerance_pct {\n        let (hi, lo) = if source_gas > target_gas {\n            (source_gas, target_gas)\n        } else {\n            (target_gas, source_gas)\n        };\n        let diff = (1. - (lo as f64 / hi as f64)) * 100.;\n        diff < tolerance as f64\n    } else {\n        source_gas == target_gas\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_tolerance() {\n        assert!(within_tolerance(100, 105, Some(5)));\n        assert!(within_tolerance(105, 100, Some(5)));\n        assert!(!within_tolerance(100, 106, Some(5)));\n        assert!(!within_tolerance(106, 100, Some(5)));\n        assert!(within_tolerance(100, 100, None));\n    }\n\n    #[test]\n    fn can_parse_basic_gas_snapshot_entry() {\n        let s = \"Test:deposit() (gas: 7222)\";\n        let entry = GasSnapshotEntry::from_str(s).unwrap();\n        assert_eq!(\n            entry,\n            GasSnapshotEntry {\n                contract_name: \"Test\".to_string(),\n                signature: \"deposit()\".to_string(),\n                gas_used: TestKindReport::Unit { gas: 7222 }\n            }\n        );\n    }\n\n    #[test]\n    fn can_parse_fuzz_gas_snapshot_entry() {\n        let s = \"Test:deposit() (runs: 256, μ: 100, ~:200)\";\n        let entry = GasSnapshotEntry::from_str(s).unwrap();\n        assert_eq!(\n            entry,\n            GasSnapshotEntry {\n                contract_name: \"Test\".to_string(),\n                signature: \"deposit()\".to_string(),\n                gas_used: TestKindReport::Fuzz {\n                    runs: 256,\n                    median_gas: 200,\n                    mean_gas: 100,\n                    failed_corpus_replays: 0\n                }\n            }\n        );\n    }\n\n    #[test]\n    fn can_parse_invariant_gas_snapshot_entry() {\n        let s = \"Test:deposit() (runs: 256, calls: 100, reverts: 200)\";\n        let entry = GasSnapshotEntry::from_str(s).unwrap();\n        assert_eq!(\n            entry,\n            GasSnapshotEntry {\n                contract_name: \"Test\".to_string(),\n                signature: \"deposit()\".to_string(),\n                gas_used: TestKindReport::Invariant {\n                    runs: 256,\n                    calls: 100,\n                    reverts: 200,\n                    metrics: HashMap::default(),\n                    failed_corpus_replays: 0,\n                    optimization_best_value: None,\n                }\n            }\n        );\n    }\n\n    #[test]\n    fn can_parse_invariant_gas_snapshot_entry2() {\n        let s = \"ERC20Invariants:invariantBalanceSum() (runs: 256, calls: 3840, reverts: 2388)\";\n        let entry = GasSnapshotEntry::from_str(s).unwrap();\n        assert_eq!(\n            entry,\n            GasSnapshotEntry {\n                contract_name: \"ERC20Invariants\".to_string(),\n                signature: \"invariantBalanceSum()\".to_string(),\n                gas_used: TestKindReport::Invariant {\n                    runs: 256,\n                    calls: 3840,\n                    reverts: 2388,\n                    metrics: HashMap::default(),\n                    failed_corpus_replays: 0,\n                    optimization_best_value: None,\n                }\n            }\n        );\n    }\n}\n"
  },
  {
    "path": "crates/forge/src/cmd/soldeer.rs",
    "content": "use clap::Parser;\nuse eyre::Result;\nuse foundry_common::shell;\nuse soldeer_commands::{Command, Verbosity};\n\n/// Available subcommands for Soldeer, see <https://github.com/mario-eth/soldeer/blob/main/crates/commands/src/lib.rs>\n/// for more information\n#[derive(Clone, Debug, Parser)]\n#[command(\n    override_usage = \"Native Solidity Package Manager, run `forge soldeer [COMMAND] --help` for more details\"\n)]\npub struct SoldeerArgs {\n    /// Command must be one of the following init/install/login/push/uninstall/update/version.\n    #[command(subcommand)]\n    command: Command,\n}\n\nimpl SoldeerArgs {\n    pub async fn run(self) -> Result<()> {\n        let verbosity = Verbosity::new(shell::verbosity(), if shell::is_quiet() { 1 } else { 0 });\n        match soldeer_commands::run(self.command, verbosity).await {\n            Ok(_) => Ok(()),\n            Err(err) => Err(eyre::eyre!(\"Failed to run soldeer: {err}\")),\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use soldeer_commands::{Command, Verbosity, commands::Version};\n\n    #[tokio::test]\n    async fn test_soldeer_version() {\n        let command = Command::Version(Version::default());\n        assert!(soldeer_commands::run(command, Verbosity::new(0, 1)).await.is_ok());\n    }\n}\n"
  },
  {
    "path": "crates/forge/src/cmd/test/filter.rs",
    "content": "use clap::Parser;\nuse foundry_common::TestFilter;\nuse foundry_compilers::{FileFilter, ProjectPathsConfig};\nuse foundry_config::{Config, filter::GlobMatcher};\nuse std::{fmt, path::Path};\n\n/// The filter to use during testing.\n///\n/// See also `FileFilter`.\n#[derive(Clone, Parser)]\n#[command(next_help_heading = \"Test filtering\")]\npub struct FilterArgs {\n    /// Only run test functions matching the specified regex pattern.\n    #[arg(long = \"match-test\", visible_alias = \"mt\", value_name = \"REGEX\")]\n    pub test_pattern: Option<regex::Regex>,\n\n    /// Only run test functions that do not match the specified regex pattern.\n    #[arg(long = \"no-match-test\", visible_alias = \"nmt\", value_name = \"REGEX\")]\n    pub test_pattern_inverse: Option<regex::Regex>,\n\n    /// Only run tests in contracts matching the specified regex pattern.\n    #[arg(long = \"match-contract\", visible_alias = \"mc\", value_name = \"REGEX\")]\n    pub contract_pattern: Option<regex::Regex>,\n\n    /// Only run tests in contracts that do not match the specified regex pattern.\n    #[arg(long = \"no-match-contract\", visible_alias = \"nmc\", value_name = \"REGEX\")]\n    pub contract_pattern_inverse: Option<regex::Regex>,\n\n    /// Only run tests in source files matching the specified glob pattern.\n    #[arg(long = \"match-path\", visible_alias = \"mp\", value_name = \"GLOB\")]\n    pub path_pattern: Option<GlobMatcher>,\n\n    /// Only run tests in source files that do not match the specified glob pattern.\n    #[arg(\n        id = \"no-match-path\",\n        long = \"no-match-path\",\n        visible_alias = \"nmp\",\n        value_name = \"GLOB\"\n    )]\n    pub path_pattern_inverse: Option<GlobMatcher>,\n\n    /// Only show coverage for files that do not match the specified regex pattern.\n    #[arg(long = \"no-match-coverage\", visible_alias = \"nmco\", value_name = \"REGEX\")]\n    pub coverage_pattern_inverse: Option<regex::Regex>,\n}\n\nimpl FilterArgs {\n    /// Returns true if the filter is empty.\n    pub fn is_empty(&self) -> bool {\n        self.test_pattern.is_none()\n            && self.test_pattern_inverse.is_none()\n            && self.contract_pattern.is_none()\n            && self.contract_pattern_inverse.is_none()\n            && self.path_pattern.is_none()\n            && self.path_pattern_inverse.is_none()\n    }\n\n    /// Merges the set filter globs with the config's values\n    pub fn merge_with_config(mut self, config: &Config) -> ProjectPathsAwareFilter {\n        if self.test_pattern.is_none() {\n            self.test_pattern = config.test_pattern.clone().map(Into::into);\n        }\n        if self.test_pattern_inverse.is_none() {\n            self.test_pattern_inverse = config.test_pattern_inverse.clone().map(Into::into);\n        }\n        if self.contract_pattern.is_none() {\n            self.contract_pattern = config.contract_pattern.clone().map(Into::into);\n        }\n        if self.contract_pattern_inverse.is_none() {\n            self.contract_pattern_inverse = config.contract_pattern_inverse.clone().map(Into::into);\n        }\n        if self.path_pattern.is_none() {\n            self.path_pattern = config.path_pattern.clone().map(Into::into);\n        }\n        if self.path_pattern_inverse.is_none() {\n            self.path_pattern_inverse = config.path_pattern_inverse.clone().map(Into::into);\n        }\n        if self.coverage_pattern_inverse.is_none() {\n            self.coverage_pattern_inverse = config.coverage_pattern_inverse.clone().map(Into::into);\n        }\n        ProjectPathsAwareFilter { args_filter: self, paths: config.project_paths() }\n    }\n}\n\nimpl fmt::Debug for FilterArgs {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.debug_struct(\"FilterArgs\")\n            .field(\"match-test\", &self.test_pattern.as_ref().map(|r| r.as_str()))\n            .field(\"no-match-test\", &self.test_pattern_inverse.as_ref().map(|r| r.as_str()))\n            .field(\"match-contract\", &self.contract_pattern.as_ref().map(|r| r.as_str()))\n            .field(\"no-match-contract\", &self.contract_pattern_inverse.as_ref().map(|r| r.as_str()))\n            .field(\"match-path\", &self.path_pattern.as_ref().map(|g| g.as_str()))\n            .field(\"no-match-path\", &self.path_pattern_inverse.as_ref().map(|g| g.as_str()))\n            .field(\"no-match-coverage\", &self.coverage_pattern_inverse.as_ref().map(|g| g.as_str()))\n            .finish_non_exhaustive()\n    }\n}\n\nimpl FileFilter for FilterArgs {\n    /// Returns true if the file regex pattern match the `file`\n    ///\n    /// If no file regex is set this returns true by default\n    fn is_match(&self, file: &Path) -> bool {\n        self.matches_path(file)\n    }\n}\n\nimpl TestFilter for FilterArgs {\n    fn matches_test(&self, test_signature: &str) -> bool {\n        let mut ok = true;\n        if let Some(re) = &self.test_pattern {\n            ok = ok && re.is_match(test_signature);\n        }\n        if let Some(re) = &self.test_pattern_inverse {\n            ok = ok && !re.is_match(test_signature);\n        }\n        ok\n    }\n\n    fn matches_contract(&self, contract_name: &str) -> bool {\n        let mut ok = true;\n        if let Some(re) = &self.contract_pattern {\n            ok = ok && re.is_match(contract_name);\n        }\n        if let Some(re) = &self.contract_pattern_inverse {\n            ok = ok && !re.is_match(contract_name);\n        }\n        ok\n    }\n\n    fn matches_path(&self, path: &Path) -> bool {\n        let mut ok = true;\n        if let Some(re) = &self.path_pattern {\n            ok = ok && re.is_match(path);\n        }\n        if let Some(re) = &self.path_pattern_inverse {\n            ok = ok && !re.is_match(path);\n        }\n        ok\n    }\n}\n\nimpl fmt::Display for FilterArgs {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        if let Some(p) = &self.test_pattern {\n            writeln!(f, \"\\tmatch-test: `{}`\", p.as_str())?;\n        }\n        if let Some(p) = &self.test_pattern_inverse {\n            writeln!(f, \"\\tno-match-test: `{}`\", p.as_str())?;\n        }\n        if let Some(p) = &self.contract_pattern {\n            writeln!(f, \"\\tmatch-contract: `{}`\", p.as_str())?;\n        }\n        if let Some(p) = &self.contract_pattern_inverse {\n            writeln!(f, \"\\tno-match-contract: `{}`\", p.as_str())?;\n        }\n        if let Some(p) = &self.path_pattern {\n            writeln!(f, \"\\tmatch-path: `{}`\", p.as_str())?;\n        }\n        if let Some(p) = &self.path_pattern_inverse {\n            writeln!(f, \"\\tno-match-path: `{}`\", p.as_str())?;\n        }\n        if let Some(p) = &self.coverage_pattern_inverse {\n            writeln!(f, \"\\tno-match-coverage: `{}`\", p.as_str())?;\n        }\n        Ok(())\n    }\n}\n\n/// A filter that combines all command line arguments and the paths of the current projects\n#[derive(Clone, Debug)]\npub struct ProjectPathsAwareFilter {\n    args_filter: FilterArgs,\n    paths: ProjectPathsConfig,\n}\n\nimpl ProjectPathsAwareFilter {\n    /// Returns true if the filter is empty.\n    pub fn is_empty(&self) -> bool {\n        self.args_filter.is_empty()\n    }\n\n    /// Returns the CLI arguments.\n    pub fn args(&self) -> &FilterArgs {\n        &self.args_filter\n    }\n\n    /// Returns the CLI arguments mutably.\n    pub fn args_mut(&mut self) -> &mut FilterArgs {\n        &mut self.args_filter\n    }\n\n    /// Returns the project paths.\n    pub fn paths(&self) -> &ProjectPathsConfig {\n        &self.paths\n    }\n}\n\nimpl FileFilter for ProjectPathsAwareFilter {\n    /// Returns true if the file regex pattern match the `file`\n    ///\n    /// If no file regex is set this returns true by default\n    fn is_match(&self, mut file: &Path) -> bool {\n        file = file.strip_prefix(&self.paths.root).unwrap_or(file);\n        self.args_filter.is_match(file)\n    }\n}\n\nimpl TestFilter for ProjectPathsAwareFilter {\n    fn matches_test(&self, test_signature: &str) -> bool {\n        self.args_filter.matches_test(test_signature)\n    }\n\n    fn matches_contract(&self, contract_name: &str) -> bool {\n        self.args_filter.matches_contract(contract_name)\n    }\n\n    fn matches_path(&self, mut path: &Path) -> bool {\n        // we don't want to test files that belong to a library\n        path = path.strip_prefix(&self.paths.root).unwrap_or(path);\n        self.args_filter.matches_path(path) && !self.paths.has_library_ancestor(path)\n    }\n}\n\nimpl fmt::Display for ProjectPathsAwareFilter {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        self.args_filter.fmt(f)\n    }\n}\n"
  },
  {
    "path": "crates/forge/src/cmd/test/mod.rs",
    "content": "use super::{install, test::filter::ProjectPathsAwareFilter, watch::WatchArgs};\nuse crate::{\n    MultiContractRunner, MultiContractRunnerBuilder,\n    decode::decode_console_logs,\n    gas_report::GasReport,\n    multi_runner::matches_artifact,\n    result::{SuiteResult, TestOutcome, TestStatus},\n    traces::{\n        CallTraceDecoderBuilder, InternalTraceMode, TraceKind,\n        debug::{ContractSources, DebugTraceIdentifier},\n        decode_trace_arena, folded_stack_trace,\n        identifier::SignaturesIdentifier,\n    },\n};\nuse alloy_primitives::U256;\nuse chrono::Utc;\nuse clap::{Parser, ValueHint};\nuse eyre::{Context, OptionExt, Result, bail};\nuse foundry_cli::{\n    opts::{BuildOpts, EvmArgs, GlobalArgs},\n    utils::{self, LoadConfig},\n};\nuse foundry_common::{EmptyTestFilter, TestFunctionExt, compile::ProjectCompiler, fs, shell};\nuse foundry_compilers::{\n    ProjectCompileOutput,\n    artifacts::output_selection::OutputSelection,\n    compilers::{\n        Language,\n        multi::{MultiCompiler, MultiCompilerLanguage},\n    },\n    utils::source_files_iter,\n};\nuse foundry_config::{\n    Config, figment,\n    figment::{\n        Metadata, Profile, Provider,\n        value::{Dict, Map},\n    },\n    filter::GlobMatcher,\n};\nuse foundry_debugger::Debugger;\nuse foundry_evm::{\n    opts::EvmOpts,\n    traces::{backtrace::BacktraceBuilder, identifier::TraceIdentifiers, prune_trace_depth},\n};\nuse rand::Rng;\nuse regex::Regex;\nuse std::{\n    collections::{BTreeMap, BTreeSet},\n    fmt::Write,\n    path::{Path, PathBuf},\n    sync::{Arc, mpsc::channel},\n    time::{Duration, Instant},\n};\nuse yansi::Paint;\n\nmod filter;\nmod summary;\nuse crate::{result::TestKind, traces::render_trace_arena_inner};\npub use filter::FilterArgs;\nuse quick_junit::{NonSuccessKind, Report, TestCase, TestCaseStatus, TestSuite};\nuse summary::{TestSummaryReport, format_invariant_metrics_table};\n\n// Loads project's figment and merges the build cli arguments into it\nfoundry_config::merge_impl_figment_convert!(TestArgs, build, evm);\n\n/// CLI arguments for `forge test`.\n#[derive(Clone, Debug, Parser)]\n#[command(next_help_heading = \"Test options\")]\npub struct TestArgs {\n    // Include global options for users of this struct.\n    #[command(flatten)]\n    pub global: GlobalArgs,\n\n    /// The contract file you want to test, it's a shortcut for --match-path.\n    #[arg(value_hint = ValueHint::FilePath)]\n    pub path: Option<GlobMatcher>,\n\n    /// Run a single test in the debugger.\n    ///\n    /// The matching test will be opened in the debugger regardless of the outcome of the test.\n    ///\n    /// If the matching test is a fuzz test, then it will open the debugger on the first failure\n    /// case. If the fuzz test does not fail, it will open the debugger on the last fuzz case.\n    #[arg(long, conflicts_with_all = [\"flamegraph\", \"flamechart\", \"decode_internal\", \"rerun\"])]\n    debug: bool,\n\n    /// Generate a flamegraph for a single test. Implies `--decode-internal`.\n    ///\n    /// A flame graph is used to visualize which functions or operations within the smart contract\n    /// are consuming the most gas overall in a sorted manner.\n    #[arg(long)]\n    flamegraph: bool,\n\n    /// Generate a flamechart for a single test. Implies `--decode-internal`.\n    ///\n    /// A flame chart shows the gas usage over time, illustrating when each function is\n    /// called (execution order) and how much gas it consumes at each point in the timeline.\n    #[arg(long, conflicts_with = \"flamegraph\")]\n    flamechart: bool,\n\n    /// Identify internal functions in traces.\n    ///\n    /// This will trace internal functions and decode stack parameters.\n    ///\n    /// Parameters stored in memory (such as bytes or arrays) are currently decoded only when a\n    /// single function is matched, similarly to `--debug`, for performance reasons.\n    #[arg(long)]\n    decode_internal: bool,\n\n    /// Dumps all debugger steps to file.\n    #[arg(\n        long,\n        requires = \"debug\",\n        value_hint = ValueHint::FilePath,\n        value_name = \"PATH\"\n    )]\n    dump: Option<PathBuf>,\n\n    /// Print a gas report.\n    #[arg(long, env = \"FORGE_GAS_REPORT\")]\n    gas_report: bool,\n\n    /// Check gas snapshots against previous runs.\n    #[arg(long, env = \"FORGE_SNAPSHOT_CHECK\")]\n    gas_snapshot_check: Option<bool>,\n\n    /// Enable/disable recording of gas snapshot results.\n    #[arg(long, env = \"FORGE_SNAPSHOT_EMIT\")]\n    gas_snapshot_emit: Option<bool>,\n\n    /// Exit with code 0 even if a test fails.\n    #[arg(long, env = \"FORGE_ALLOW_FAILURE\")]\n    allow_failure: bool,\n\n    /// Suppress successful test traces and show only traces for failures.\n    #[arg(long, short, env = \"FORGE_SUPPRESS_SUCCESSFUL_TRACES\", help_heading = \"Display options\")]\n    suppress_successful_traces: bool,\n\n    /// Defines the depth of a trace\n    #[arg(long)]\n    trace_depth: Option<usize>,\n\n    /// Output test results as JUnit XML report.\n    #[arg(long, conflicts_with_all = [\"quiet\", \"json\", \"gas_report\", \"summary\", \"list\", \"show_progress\"], help_heading = \"Display options\")]\n    pub junit: bool,\n\n    /// Stop running tests after the first failure.\n    #[arg(long)]\n    pub fail_fast: bool,\n\n    /// The Etherscan (or equivalent) API key.\n    #[arg(long, env = \"ETHERSCAN_API_KEY\", value_name = \"KEY\")]\n    etherscan_api_key: Option<String>,\n\n    /// List tests instead of running them.\n    #[arg(long, short, conflicts_with_all = [\"show_progress\", \"decode_internal\", \"summary\"], help_heading = \"Display options\")]\n    list: bool,\n\n    /// Set seed used to generate randomness during your fuzz runs.\n    #[arg(long)]\n    pub fuzz_seed: Option<U256>,\n\n    #[arg(long, env = \"FOUNDRY_FUZZ_RUNS\", value_name = \"RUNS\")]\n    pub fuzz_runs: Option<u64>,\n\n    /// Timeout for each fuzz run in seconds.\n    #[arg(long, env = \"FOUNDRY_FUZZ_TIMEOUT\", value_name = \"TIMEOUT\")]\n    pub fuzz_timeout: Option<u64>,\n\n    /// File to rerun fuzz failures from.\n    #[arg(long)]\n    pub fuzz_input_file: Option<String>,\n\n    /// Show test execution progress.\n    #[arg(long, conflicts_with_all = [\"quiet\", \"json\"], help_heading = \"Display options\")]\n    pub show_progress: bool,\n\n    /// Re-run recorded test failures from last run.\n    /// If no failure recorded then regular test run is performed.\n    #[arg(long)]\n    pub rerun: bool,\n\n    /// Print test summary table.\n    #[arg(long, help_heading = \"Display options\")]\n    pub summary: bool,\n\n    /// Print detailed test summary table.\n    #[arg(long, help_heading = \"Display options\", requires = \"summary\")]\n    pub detailed: bool,\n\n    /// Disables the labels in the traces.\n    #[arg(long, help_heading = \"Display options\")]\n    pub disable_labels: bool,\n\n    #[command(flatten)]\n    filter: FilterArgs,\n\n    #[command(flatten)]\n    evm: EvmArgs,\n\n    #[command(flatten)]\n    pub build: BuildOpts,\n\n    #[command(flatten)]\n    pub watch: WatchArgs,\n}\n\nimpl TestArgs {\n    pub async fn run(mut self) -> Result<TestOutcome> {\n        trace!(target: \"forge::test\", \"executing test command\");\n        self.compile_and_run().await\n    }\n\n    /// Returns a list of files that need to be compiled in order to run all the tests that match\n    /// the given filter.\n    ///\n    /// This means that it will return all sources that are not test contracts or that match the\n    /// filter. We want to compile all non-test sources always because tests might depend on them\n    /// dynamically through cheatcodes.\n    #[instrument(target = \"forge::test\", skip_all)]\n    pub fn get_sources_to_compile(\n        &self,\n        config: &Config,\n        test_filter: &ProjectPathsAwareFilter,\n    ) -> Result<BTreeSet<PathBuf>> {\n        // An empty filter doesn't filter out anything.\n        // We can still optimize slightly by excluding scripts.\n        if test_filter.is_empty() {\n            return Ok(source_files_iter(&config.src, MultiCompilerLanguage::FILE_EXTENSIONS)\n                .chain(source_files_iter(&config.test, MultiCompilerLanguage::FILE_EXTENSIONS))\n                .collect());\n        }\n\n        let mut project = config.create_project(true, true)?;\n        project.update_output_selection(|selection| {\n            *selection = OutputSelection::common_output_selection([\"abi\".to_string()]);\n        });\n        let output = project.compile()?;\n        if output.has_compiler_errors() {\n            sh_println!(\"{output}\")?;\n            eyre::bail!(\"Compilation failed\");\n        }\n\n        Ok(output\n            .artifact_ids()\n            .filter_map(|(id, artifact)| artifact.abi.as_ref().map(|abi| (id, abi)))\n            .filter(|(id, abi)| {\n                id.source.starts_with(&config.src) || matches_artifact(test_filter, id, abi)\n            })\n            .map(|(id, _)| id.source)\n            .collect())\n    }\n\n    /// Executes all the tests in the project.\n    ///\n    /// This will trigger the build process first. On success all test contracts that match the\n    /// configured filter will be executed\n    ///\n    /// Returns the test results for all matching tests.\n    pub async fn compile_and_run(&mut self) -> Result<TestOutcome> {\n        // Merge all configs.\n        let (mut config, evm_opts) = self.load_config_and_evm_opts()?;\n\n        // Install missing dependencies.\n        if install::install_missing_dependencies(&mut config).await && config.auto_detect_remappings\n        {\n            // need to re-configure here to also catch additional remappings\n            config = self.load_config()?;\n        }\n\n        // Set up the project.\n        let project = config.project()?;\n\n        let filter = self.filter(&config)?;\n        trace!(target: \"forge::test\", ?filter, \"using filter\");\n\n        let compiler = ProjectCompiler::new()\n            .dynamic_test_linking(config.dynamic_test_linking)\n            .quiet(shell::is_json() || self.junit)\n            .files(self.get_sources_to_compile(&config, &filter)?);\n        let output = compiler.compile(&project)?;\n\n        self.run_tests(&project.paths.root, config, evm_opts, &output, &filter, false).await\n    }\n\n    /// Executes all the tests in the project.\n    ///\n    /// See [`Self::compile_and_run`] for more details.\n    pub async fn run_tests(\n        &mut self,\n        project_root: &Path,\n        mut config: Config,\n        mut evm_opts: EvmOpts,\n        output: &ProjectCompileOutput,\n        filter: &ProjectPathsAwareFilter,\n        coverage: bool,\n    ) -> Result<TestOutcome> {\n        // Explicitly enable isolation for gas reports for more correct gas accounting.\n        if self.gas_report {\n            evm_opts.isolate = true;\n        } else {\n            // Do not collect gas report traces if gas report is not enabled.\n            config.fuzz.gas_report_samples = 0;\n            config.invariant.gas_report_samples = 0;\n        }\n\n        // Generate a random fuzz seed if none provided, for reproducibility.\n        config.fuzz.seed = config\n            .fuzz\n            .seed\n            .or_else(|| Some(U256::from_be_bytes(rand::rng().random::<[u8; 32]>())));\n\n        // Create test options from general project settings and compiler output.\n        let should_debug = self.debug;\n        let should_draw = self.flamegraph || self.flamechart;\n\n        // Determine print verbosity and executor verbosity.\n        let verbosity = evm_opts.verbosity;\n        if (self.gas_report && evm_opts.verbosity < 3) || self.flamegraph || self.flamechart {\n            evm_opts.verbosity = 3;\n        }\n\n        let (evm_env, tx_env) = evm_opts.env().await?;\n\n        // Enable internal tracing for more informative flamegraph.\n        if should_draw && !self.decode_internal {\n            self.decode_internal = true;\n        }\n\n        // Choose the internal function tracing mode, if --decode-internal is provided.\n        let decode_internal = if self.decode_internal {\n            // If more than one function matched, we enable simple tracing.\n            // If only one function matched, we enable full tracing. This is done in `run_tests`.\n            InternalTraceMode::Simple\n        } else {\n            InternalTraceMode::None\n        };\n\n        // Prepare the test builder.\n        let config = Arc::new(config);\n        let runner = MultiContractRunnerBuilder::new(config.clone())\n            .set_debug(should_debug)\n            .set_decode_internal(decode_internal)\n            .initial_balance(evm_opts.initial_balance)\n            .evm_spec(config.evm_spec_id())\n            .sender(evm_opts.sender)\n            .with_fork(evm_opts.get_fork(&config, evm_env.clone()))\n            .enable_isolation(evm_opts.isolate)\n            .networks(evm_opts.networks)\n            .fail_fast(self.fail_fast)\n            .set_coverage(coverage)\n            .build::<MultiCompiler>(output, evm_env, tx_env, evm_opts)?;\n\n        let libraries = runner.libraries.clone();\n        let mut outcome = self.run_tests_inner(runner, config, verbosity, filter, output).await?;\n\n        if should_draw {\n            let (suite_name, test_name, mut test_result) =\n                outcome.remove_first().ok_or_eyre(\"no tests were executed\")?;\n\n            let (_, arena) = test_result\n                .traces\n                .iter_mut()\n                .find(|(kind, _)| *kind == TraceKind::Execution)\n                .unwrap();\n\n            // Decode traces.\n            let decoder = outcome.last_run_decoder.as_ref().unwrap();\n            decode_trace_arena(arena, decoder).await;\n            let mut fst = folded_stack_trace::build(arena, self.evm.isolate);\n\n            let label = if self.flamegraph { \"flamegraph\" } else { \"flamechart\" };\n            let contract = suite_name.split(':').next_back().unwrap();\n            let test_name = test_name.trim_end_matches(\"()\");\n            let file_name = format!(\"cache/{label}_{contract}_{test_name}.svg\");\n            let file = std::fs::File::create(&file_name).wrap_err(\"failed to create file\")?;\n            let file = std::io::BufWriter::new(file);\n\n            let mut options = inferno::flamegraph::Options::default();\n            options.title = format!(\"{label} {contract}::{test_name}\");\n            options.count_name = \"gas\".to_string();\n            if self.flamechart {\n                options.flame_chart = true;\n                fst.reverse();\n            }\n\n            // Generate SVG.\n            inferno::flamegraph::from_lines(&mut options, fst.iter().map(String::as_str), file)\n                .wrap_err(\"failed to write svg\")?;\n            sh_println!(\"Saved to {file_name}\")?;\n\n            // Open SVG in default program.\n            if let Err(e) = opener::open(&file_name) {\n                sh_err!(\"Failed to open {file_name}; please open it manually: {e}\")?;\n            }\n        }\n\n        if should_debug {\n            // Get first non-empty suite result. We will have only one such entry.\n            let (_, _, test_result) =\n                outcome.remove_first().ok_or_eyre(\"no tests were executed\")?;\n\n            let sources =\n                ContractSources::from_project_output(output, project_root, Some(&libraries))?;\n\n            // Run the debugger.\n            let mut builder = Debugger::builder()\n                .traces(\n                    test_result.traces.iter().filter(|(t, _)| t.is_execution()).cloned().collect(),\n                )\n                .sources(sources)\n                .breakpoints(test_result.breakpoints.clone());\n\n            if let Some(decoder) = &outcome.last_run_decoder {\n                builder = builder.decoder(decoder);\n            }\n\n            let mut debugger = builder.build();\n            if let Some(dump_path) = &self.dump {\n                debugger.dump_to_file(dump_path)?;\n            } else {\n                debugger.try_run_tui()?;\n            }\n        }\n\n        Ok(outcome)\n    }\n\n    /// Run all tests that matches the filter predicate from a test runner\n    async fn run_tests_inner(\n        &self,\n        mut runner: MultiContractRunner,\n        config: Arc<Config>,\n        verbosity: u8,\n        filter: &ProjectPathsAwareFilter,\n        output: &ProjectCompileOutput,\n    ) -> eyre::Result<TestOutcome> {\n        let fuzz_seed = config.fuzz.seed;\n        if self.list {\n            return list(runner, filter);\n        }\n\n        trace!(target: \"forge::test\", \"running all tests\");\n\n        // If we need to render to a serialized format, we should not print anything else to stdout.\n        let silent = self.gas_report && shell::is_json() || self.summary && shell::is_json();\n\n        let num_filtered = runner.matching_test_functions(filter).count();\n\n        if num_filtered == 0 {\n            let mut total_tests = num_filtered;\n            if !filter.is_empty() {\n                total_tests = runner.matching_test_functions(&EmptyTestFilter::default()).count();\n            }\n            if total_tests == 0 {\n                sh_println!(\n                    \"No tests found in project! Forge looks for functions that start with `test`\"\n                )?;\n            } else {\n                let mut msg = format!(\"no tests match the provided pattern:\\n{filter}\");\n                // Try to suggest a test when there's no match.\n                if let Some(test_pattern) = &filter.args().test_pattern {\n                    let test_name = test_pattern.as_str();\n                    // Filter contracts but not test functions.\n                    let candidates = runner.all_test_functions(filter).map(|f| &f.name);\n                    if let Some(suggestion) = utils::did_you_mean(test_name, candidates).pop() {\n                        write!(msg, \"\\nDid you mean `{suggestion}`?\")?;\n                    }\n                }\n                sh_warn!(\"{msg}\")?;\n            }\n            return Ok(TestOutcome::empty(Some(runner), false));\n        }\n\n        if num_filtered != 1 && (self.debug || self.flamegraph || self.flamechart) {\n            let action = if self.flamegraph {\n                \"generate a flamegraph\"\n            } else if self.flamechart {\n                \"generate a flamechart\"\n            } else {\n                \"run the debugger\"\n            };\n            let filter = if filter.is_empty() {\n                String::new()\n            } else {\n                format!(\"\\n\\nFilter used:\\n{filter}\")\n            };\n            eyre::bail!(\n                \"{num_filtered} tests matched your criteria, but exactly 1 test must match in order to {action}.\\n\\n\\\n                 Use --match-contract and --match-path to further limit the search.{filter}\",\n            );\n        }\n\n        // If exactly one test matched, we enable full tracing.\n        if num_filtered == 1 && self.decode_internal {\n            runner.decode_internal = InternalTraceMode::Full;\n        }\n\n        // Run tests in a non-streaming fashion and collect results for serialization.\n        if !self.gas_report && !self.summary && shell::is_json() {\n            let mut results = runner.test_collect(filter)?;\n            results.values_mut().for_each(|suite_result| {\n                for test_result in suite_result.test_results.values_mut() {\n                    if verbosity >= 2 {\n                        // Decode logs at level 2 and above.\n                        test_result.decoded_logs = decode_console_logs(&test_result.logs);\n                    } else {\n                        // Empty logs for non verbose runs.\n                        test_result.logs = vec![];\n                    }\n                }\n            });\n            sh_println!(\"{}\", serde_json::to_string(&results)?)?;\n            return Ok(TestOutcome::new(Some(runner), results, self.allow_failure, fuzz_seed));\n        }\n\n        if self.junit {\n            let results = runner.test_collect(filter)?;\n            sh_println!(\"{}\", junit_xml_report(&results, verbosity).to_string()?)?;\n            return Ok(TestOutcome::new(Some(runner), results, self.allow_failure, fuzz_seed));\n        }\n\n        let remote_chain =\n            if runner.fork.is_some() { runner.tx_env.chain_id.map(Into::into) } else { None };\n        let known_contracts = runner.known_contracts.clone();\n\n        let libraries = runner.libraries.clone();\n\n        // Run tests in a streaming fashion.\n        let (tx, rx) = channel::<(String, SuiteResult)>();\n        let timer = Instant::now();\n        let show_progress = config.show_progress;\n        let handle = tokio::task::spawn_blocking({\n            let filter = filter.clone();\n            move || runner.test(&filter, tx, show_progress).map(|()| runner)\n        });\n\n        // Set up trace identifiers.\n        let mut identifier = TraceIdentifiers::new().with_local(&known_contracts);\n\n        // Avoid using external identifiers for gas report as we decode more traces and this will be\n        // expensive. Also skip external identifiers for local tests (no remote chain) to avoid\n        // unnecessary Etherscan API calls that significantly slow down test execution.\n        if !self.gas_report && remote_chain.is_some() {\n            identifier = identifier.with_external(&config, remote_chain)?;\n        }\n\n        // Build the trace decoder.\n        let mut builder = CallTraceDecoderBuilder::new()\n            .with_known_contracts(&known_contracts)\n            .with_label_disabled(self.disable_labels)\n            .with_verbosity(verbosity);\n        // Signatures are of no value for gas reports.\n        if !self.gas_report {\n            builder =\n                builder.with_signature_identifier(SignaturesIdentifier::from_config(&config)?);\n        }\n\n        if self.decode_internal {\n            let sources =\n                ContractSources::from_project_output(output, &config.root, Some(&libraries))?;\n            builder = builder.with_debug_identifier(DebugTraceIdentifier::new(sources));\n        }\n        let mut decoder = builder.build();\n\n        let mut gas_report = self.gas_report.then(|| {\n            GasReport::new(\n                config.gas_reports.clone(),\n                config.gas_reports_ignore.clone(),\n                config.gas_reports_include_tests,\n            )\n        });\n\n        let mut gas_snapshots = BTreeMap::<String, BTreeMap<String, String>>::new();\n\n        let mut outcome = TestOutcome::empty(None, self.allow_failure);\n        outcome.fuzz_seed = fuzz_seed;\n\n        let mut any_test_failed = false;\n        let mut backtrace_builder = None;\n        for (contract_name, mut suite_result) in rx {\n            let tests = &mut suite_result.test_results;\n            let has_tests = !tests.is_empty();\n\n            // Clear the addresses and labels from previous test.\n            decoder.clear_addresses();\n\n            // We identify addresses if we're going to print *any* trace or gas report.\n            let identify_addresses = verbosity >= 3\n                || self.gas_report\n                || self.debug\n                || self.flamegraph\n                || self.flamechart;\n\n            // Print suite header.\n            if !silent {\n                sh_println!()?;\n                for warning in &suite_result.warnings {\n                    sh_warn!(\"{warning}\")?;\n                }\n                if has_tests {\n                    let len = tests.len();\n                    let tests = if len > 1 { \"tests\" } else { \"test\" };\n                    sh_println!(\"Ran {len} {tests} for {contract_name}\")?;\n                }\n            }\n\n            // Process individual test results, printing logs and traces when necessary.\n            for (name, result) in tests {\n                let show_traces =\n                    !self.suppress_successful_traces || result.status == TestStatus::Failure;\n                if !silent {\n                    sh_println!(\"{}\", result.short_result(name))?;\n\n                    // Display invariant metrics if invariant kind.\n                    if let TestKind::Invariant { metrics, .. } = &result.kind\n                        && !metrics.is_empty()\n                    {\n                        let _ = sh_println!(\"\\n{}\\n\", format_invariant_metrics_table(metrics));\n                    }\n\n                    // We only display logs at level 2 and above\n                    if verbosity >= 2 && show_traces {\n                        // We only decode logs from Hardhat and DS-style console events\n                        let console_logs = decode_console_logs(&result.logs);\n                        if !console_logs.is_empty() {\n                            sh_println!(\"Logs:\")?;\n                            for log in console_logs {\n                                sh_println!(\"  {log}\")?;\n                            }\n                            sh_println!()?;\n                        }\n                    }\n                }\n\n                // We shouldn't break out of the outer loop directly here so that we finish\n                // processing the remaining tests and print the suite summary.\n                any_test_failed |= result.status == TestStatus::Failure;\n\n                // Clear the addresses and labels from previous runs.\n                decoder.clear_addresses();\n                decoder.labels.extend(result.labels.iter().map(|(k, v)| (*k, v.clone())));\n\n                // Identify addresses and decode traces.\n                let mut decoded_traces = Vec::with_capacity(result.traces.len());\n                for (kind, arena) in &mut result.traces {\n                    if identify_addresses {\n                        decoder.identify(arena, &mut identifier);\n                    }\n\n                    // verbosity:\n                    // - 0..3: nothing\n                    // - 3: only display traces for failed tests\n                    // - 4: also display the setup trace for failed tests\n                    // - 5..: display all traces for all tests, including storage changes\n                    let should_include = match kind {\n                        TraceKind::Execution => {\n                            (verbosity == 3 && result.status.is_failure()) || verbosity >= 4\n                        }\n                        TraceKind::Setup => {\n                            (verbosity == 4 && result.status.is_failure()) || verbosity >= 5\n                        }\n                        TraceKind::Deployment => false,\n                    };\n\n                    if should_include {\n                        decode_trace_arena(arena, &decoder).await;\n\n                        if let Some(trace_depth) = self.trace_depth {\n                            prune_trace_depth(arena, trace_depth);\n                        }\n\n                        decoded_traces.push(render_trace_arena_inner(arena, false, verbosity > 4));\n                    }\n                }\n\n                if !silent && show_traces && !decoded_traces.is_empty() {\n                    sh_println!(\"Traces:\")?;\n                    for trace in &decoded_traces {\n                        sh_println!(\"{trace}\")?;\n                    }\n                }\n\n                // Extract and display backtrace for failed tests when verbosity >= 3.\n                // At verbosity 3-4 backtraces show contract/function names only.\n                // At verbosity 5 backtraces include source file locations.\n                if !silent\n                    && result.status.is_failure()\n                    && verbosity >= 3\n                    && !result.traces.is_empty()\n                    && let Some((_, arena)) =\n                        result.traces.iter().find(|(kind, _)| matches!(kind, TraceKind::Execution))\n                {\n                    // Lazily initialize the backtrace builder on first failure\n                    let builder = backtrace_builder.get_or_insert_with(|| {\n                        BacktraceBuilder::new(\n                            output,\n                            config.root.clone(),\n                            config.parsed_libraries().ok(),\n                            config.via_ir,\n                        )\n                    });\n\n                    let backtrace = builder.from_traces(arena);\n\n                    if !backtrace.is_empty() {\n                        sh_println!(\"{}\", backtrace)?;\n                    }\n                }\n\n                if let Some(gas_report) = &mut gas_report {\n                    gas_report.analyze(result.traces.iter().map(|(_, a)| &a.arena), &decoder).await;\n\n                    for trace in &result.gas_report_traces {\n                        decoder.clear_addresses();\n\n                        // Re-execute setup and deployment traces to collect identities created in\n                        // setUp and constructor.\n                        for (kind, arena) in &result.traces {\n                            if !matches!(kind, TraceKind::Execution) {\n                                decoder.identify(arena, &mut identifier);\n                            }\n                        }\n\n                        for arena in trace {\n                            decoder.identify(arena, &mut identifier);\n                            gas_report.analyze([arena], &decoder).await;\n                        }\n                    }\n                }\n                // Clear memory.\n                result.gas_report_traces = Default::default();\n\n                // Collect and merge gas snapshots.\n                for (group, new_snapshots) in &result.gas_snapshots {\n                    gas_snapshots.entry(group.clone()).or_default().extend(new_snapshots.clone());\n                }\n            }\n\n            // Write gas snapshots to disk if any were collected.\n            if !gas_snapshots.is_empty() {\n                // By default `gas_snapshot_check` is set to `false` in the config.\n                //\n                // The user can either:\n                // - Set `FORGE_SNAPSHOT_CHECK=true` in the environment.\n                // - Pass `--gas-snapshot-check=true` as a CLI argument.\n                // - Set `gas_snapshot_check = true` in the config.\n                //\n                // If the user passes `--gas-snapshot-check=<bool>` then it will override the config\n                // and the environment variable, disabling the check if `false` is passed.\n                //\n                // Exiting early with code 1 if differences are found.\n                if self.gas_snapshot_check.unwrap_or(config.gas_snapshot_check) {\n                    let differences_found = gas_snapshots.clone().into_iter().fold(\n                        false,\n                        |mut found, (group, snapshots)| {\n                            // If the snapshot file doesn't exist, we can't compare so we skip.\n                            if !&config.snapshots.join(format!(\"{group}.json\")).exists() {\n                                return found;\n                            }\n\n                            let previous_snapshots: BTreeMap<String, String> =\n                                fs::read_json_file(&config.snapshots.join(format!(\"{group}.json\")))\n                                    .expect(\"Failed to read snapshots from disk\");\n\n                            let diff: BTreeMap<_, _> = snapshots\n                                .iter()\n                                .filter_map(|(k, v)| {\n                                    previous_snapshots.get(k).and_then(|previous_snapshot| {\n                                        if previous_snapshot != v {\n                                            Some((\n                                                k.clone(),\n                                                (previous_snapshot.clone(), v.clone()),\n                                            ))\n                                        } else {\n                                            None\n                                        }\n                                    })\n                                })\n                                .collect();\n\n                            if !diff.is_empty() {\n                                let _ = sh_eprintln!(\n                                    \"{}\",\n                                    format!(\"\\n[{group}] Failed to match snapshots:\").red().bold()\n                                );\n\n                                for (key, (previous_snapshot, snapshot)) in &diff {\n                                    let _ = sh_eprintln!(\n                                        \"{}\",\n                                        format!(\"- [{key}] {previous_snapshot} → {snapshot}\").red()\n                                    );\n                                }\n\n                                found = true;\n                            }\n\n                            found\n                        },\n                    );\n\n                    if differences_found {\n                        sh_eprintln!()?;\n                        eyre::bail!(\"Snapshots differ from previous run\");\n                    }\n                }\n\n                // By default `gas_snapshot_emit` is set to `true` in the config.\n                //\n                // The user can either:\n                // - Set `FORGE_SNAPSHOT_EMIT=false` in the environment.\n                // - Pass `--gas-snapshot-emit=false` as a CLI argument.\n                // - Set `gas_snapshot_emit = false` in the config.\n                //\n                // If the user passes `--gas-snapshot-emit=<bool>` then it will override the config\n                // and the environment variable, enabling the check if `true` is passed.\n                if self.gas_snapshot_emit.unwrap_or(config.gas_snapshot_emit) {\n                    // Create `snapshots` directory if it doesn't exist.\n                    fs::create_dir_all(&config.snapshots)?;\n\n                    // Write gas snapshots to disk per group.\n                    gas_snapshots.clone().into_iter().for_each(|(group, snapshots)| {\n                        fs::write_pretty_json_file(\n                            &config.snapshots.join(format!(\"{group}.json\")),\n                            &snapshots,\n                        )\n                        .expect(\"Failed to write gas snapshots to disk\");\n                    });\n                }\n            }\n\n            // Print suite summary.\n            if !silent && has_tests {\n                sh_println!(\"{}\", suite_result.summary())?;\n            }\n\n            // Add the suite result to the outcome.\n            outcome.results.insert(contract_name, suite_result);\n\n            // Stop processing the remaining suites if any test failed and `fail_fast` is set.\n            if self.fail_fast && any_test_failed {\n                break;\n            }\n        }\n        outcome.last_run_decoder = Some(decoder);\n        let duration = timer.elapsed();\n\n        trace!(target: \"forge::test\", len=outcome.results.len(), %any_test_failed, \"done with results\");\n\n        if let Some(gas_report) = gas_report {\n            let finalized = gas_report.finalize();\n            sh_println!(\"{}\", &finalized)?;\n            outcome.gas_report = Some(finalized);\n        }\n\n        if !self.summary && !shell::is_json() {\n            sh_println!(\"{}\", outcome.summary(duration))?;\n        }\n\n        if self.summary && !outcome.results.is_empty() {\n            let summary_report = TestSummaryReport::new(self.detailed, outcome.clone());\n            sh_println!(\"{}\", &summary_report)?;\n        }\n\n        // Reattach the task.\n        match handle.await {\n            Ok(result) => outcome.runner = Some(result?),\n            Err(e) => match e.try_into_panic() {\n                Ok(payload) => std::panic::resume_unwind(payload),\n                Err(e) => return Err(e.into()),\n            },\n        }\n\n        // Persist test run failures to enable replaying.\n        persist_run_failures(&config, &outcome);\n\n        Ok(outcome)\n    }\n\n    /// Returns the flattened [`FilterArgs`] arguments merged with [`Config`].\n    /// Loads and applies filter from file if only last test run failures performed.\n    pub fn filter(&self, config: &Config) -> Result<ProjectPathsAwareFilter> {\n        let mut filter = self.filter.clone();\n        if self.rerun {\n            filter.test_pattern = last_run_failures(config);\n        }\n        if filter.path_pattern.is_some() {\n            if self.path.is_some() {\n                bail!(\"Can not supply both --match-path and |path|\");\n            }\n        } else {\n            filter.path_pattern = self.path.clone();\n        }\n        Ok(filter.merge_with_config(config))\n    }\n\n    /// Returns whether `BuildArgs` was configured with `--watch`\n    pub fn is_watch(&self) -> bool {\n        self.watch.watch.is_some()\n    }\n\n    /// Returns the [`watchexec::Config`] necessary to bootstrap a new watch loop.\n    pub(crate) fn watchexec_config(&self) -> Result<watchexec::Config> {\n        self.watch.watchexec_config(|| {\n            let config = self.load_config()?;\n            Ok([config.src, config.test])\n        })\n    }\n}\n\nimpl Provider for TestArgs {\n    fn metadata(&self) -> Metadata {\n        Metadata::named(\"Core Build Args Provider\")\n    }\n\n    fn data(&self) -> Result<Map<Profile, Dict>, figment::Error> {\n        let mut dict = Dict::default();\n\n        let mut fuzz_dict = Dict::default();\n        if let Some(fuzz_seed) = self.fuzz_seed {\n            fuzz_dict.insert(\"seed\".to_string(), fuzz_seed.to_string().into());\n        }\n        if let Some(fuzz_runs) = self.fuzz_runs {\n            fuzz_dict.insert(\"runs\".to_string(), fuzz_runs.into());\n        }\n        if let Some(fuzz_timeout) = self.fuzz_timeout {\n            fuzz_dict.insert(\"timeout\".to_string(), fuzz_timeout.into());\n        }\n        if let Some(fuzz_input_file) = self.fuzz_input_file.clone() {\n            fuzz_dict.insert(\"failure_persist_file\".to_string(), fuzz_input_file.into());\n        }\n        dict.insert(\"fuzz\".to_string(), fuzz_dict.into());\n\n        if let Some(etherscan_api_key) =\n            self.etherscan_api_key.as_ref().filter(|s| !s.trim().is_empty())\n        {\n            dict.insert(\"etherscan_api_key\".to_string(), etherscan_api_key.to_string().into());\n        }\n\n        if self.show_progress {\n            dict.insert(\"show_progress\".to_string(), true.into());\n        }\n\n        Ok(Map::from([(Config::selected_profile(), dict)]))\n    }\n}\n\n/// Lists all matching tests\nfn list(runner: MultiContractRunner, filter: &ProjectPathsAwareFilter) -> Result<TestOutcome> {\n    let results = runner.list(filter);\n\n    if shell::is_json() {\n        sh_println!(\"{}\", serde_json::to_string(&results)?)?;\n    } else {\n        for (file, contracts) in &results {\n            sh_println!(\"{file}\")?;\n            for (contract, tests) in contracts {\n                sh_println!(\"  {contract}\")?;\n                sh_println!(\"    {}\\n\", tests.join(\"\\n    \"))?;\n            }\n        }\n    }\n    Ok(TestOutcome::empty(Some(runner), false))\n}\n\n/// Load persisted filter (with last test run failures) from file.\nfn last_run_failures(config: &Config) -> Option<regex::Regex> {\n    match fs::read_to_string(&config.test_failures_file) {\n        Ok(filter) => Regex::new(&filter)\n            .inspect_err(|e| {\n                _ = sh_warn!(\n                    \"failed to parse test filter from {:?}: {e}\",\n                    config.test_failures_file\n                )\n            })\n            .ok(),\n        Err(_) => None,\n    }\n}\n\n/// Persist filter with last test run failures (only if there's any failure).\nfn persist_run_failures(config: &Config, outcome: &TestOutcome) {\n    if outcome.failed() > 0 && fs::create_file(&config.test_failures_file).is_ok() {\n        let mut filter = String::new();\n        let mut failures = outcome.failures().peekable();\n        while let Some((test_name, _)) = failures.next() {\n            if test_name.is_any_test()\n                && let Some(test_match) = test_name.split(\"(\").next()\n            {\n                filter.push_str(test_match);\n                if failures.peek().is_some() {\n                    filter.push('|');\n                }\n            }\n        }\n        let _ = fs::write(&config.test_failures_file, filter);\n    }\n}\n\n/// Generate test report in JUnit XML report format.\nfn junit_xml_report(results: &BTreeMap<String, SuiteResult>, verbosity: u8) -> Report {\n    let mut total_duration = Duration::default();\n    let mut junit_report = Report::new(\"Test run\");\n    junit_report.set_timestamp(Utc::now());\n    for (suite_name, suite_result) in results {\n        let mut test_suite = TestSuite::new(suite_name);\n        total_duration += suite_result.duration;\n        test_suite.set_time(suite_result.duration);\n        test_suite.set_system_out(suite_result.summary());\n        for (test_name, test_result) in &suite_result.test_results {\n            let mut test_status = match test_result.status {\n                TestStatus::Success => TestCaseStatus::success(),\n                TestStatus::Failure => TestCaseStatus::non_success(NonSuccessKind::Failure),\n                TestStatus::Skipped => TestCaseStatus::skipped(),\n            };\n            if let Some(reason) = &test_result.reason {\n                test_status.set_message(reason);\n            }\n\n            let mut test_case = TestCase::new(test_name, test_status);\n            test_case.set_time(test_result.duration);\n\n            let mut sys_out = String::new();\n            let result_report = test_result.kind.report();\n            write!(sys_out, \"{test_result} {test_name} {result_report}\").unwrap();\n            if verbosity >= 2 && !test_result.logs.is_empty() {\n                write!(sys_out, \"\\\\nLogs:\\\\n\").unwrap();\n                let console_logs = decode_console_logs(&test_result.logs);\n                for log in console_logs {\n                    write!(sys_out, \"  {log}\\\\n\").unwrap();\n                }\n            }\n\n            test_case.set_system_out(sys_out);\n            test_suite.add_test_case(test_case);\n        }\n        junit_report.add_test_suite(test_suite);\n    }\n    junit_report.set_time(total_duration);\n    junit_report\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use foundry_config::Chain;\n\n    #[test]\n    fn watch_parse() {\n        let args: TestArgs = TestArgs::parse_from([\"foundry-cli\", \"-vw\"]);\n        assert!(args.watch.watch.is_some());\n    }\n\n    #[test]\n    fn fuzz_seed() {\n        let args: TestArgs = TestArgs::parse_from([\"foundry-cli\", \"--fuzz-seed\", \"0x10\"]);\n        assert!(args.fuzz_seed.is_some());\n    }\n\n    #[test]\n    fn depth_trace() {\n        let args: TestArgs = TestArgs::parse_from([\"foundry-cli\", \"--trace-depth\", \"2\"]);\n        assert!(args.trace_depth.is_some());\n    }\n\n    // <https://github.com/foundry-rs/foundry/issues/5913>\n    #[test]\n    fn fuzz_seed_exists() {\n        let args: TestArgs =\n            TestArgs::parse_from([\"foundry-cli\", \"-vvv\", \"--gas-report\", \"--fuzz-seed\", \"0x10\"]);\n        assert!(args.fuzz_seed.is_some());\n    }\n\n    #[test]\n    fn extract_chain() {\n        let test = |arg: &str, expected: Chain| {\n            let args = TestArgs::parse_from([\"foundry-cli\", arg]);\n            assert_eq!(args.evm.env.chain, Some(expected));\n            let (config, evm_opts) = args.load_config_and_evm_opts().unwrap();\n            assert_eq!(config.chain, Some(expected));\n            assert_eq!(evm_opts.env.chain_id, Some(expected.id()));\n        };\n        test(\"--chain-id=1\", Chain::mainnet());\n        test(\"--chain-id=42\", Chain::from_id(42));\n    }\n}\n"
  },
  {
    "path": "crates/forge/src/cmd/test/summary.rs",
    "content": "use crate::cmd::test::TestOutcome;\nuse comfy_table::{\n    Cell, Color, Row, Table, modifiers::UTF8_ROUND_CORNERS, presets::ASCII_MARKDOWN,\n};\nuse foundry_common::shell;\nuse foundry_evm::executors::invariant::InvariantMetrics;\nuse itertools::Itertools;\nuse serde_json::json;\nuse std::{collections::HashMap, fmt::Display};\n\n/// Represents a test summary report.\npub struct TestSummaryReport {\n    /// Whether the report should be detailed.\n    is_detailed: bool,\n    /// The test outcome to report.\n    outcome: TestOutcome,\n}\n\nimpl TestSummaryReport {\n    pub fn new(is_detailed: bool, outcome: TestOutcome) -> Self {\n        Self { is_detailed, outcome }\n    }\n}\n\nimpl Display for TestSummaryReport {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {\n        if shell::is_json() {\n            writeln!(f, \"{}\", &self.format_json_output(&self.is_detailed, &self.outcome))?;\n        } else {\n            writeln!(f, \"\\n{}\", &self.format_table_output(&self.is_detailed, &self.outcome))?;\n        }\n        Ok(())\n    }\n}\n\nimpl TestSummaryReport {\n    // Helper function to format the JSON output.\n    fn format_json_output(&self, is_detailed: &bool, outcome: &TestOutcome) -> String {\n        let output = json!({\n            \"results\": outcome.results.iter().map(|(contract, suite)| {\n                let (suite_path, suite_name) = contract.split_once(':').unwrap();\n                let passed = suite.successes().count();\n                let failed = suite.failures().count();\n                let skipped = suite.skips().count();\n                let mut result = json!({\n                    \"suite\": suite_name,\n                    \"passed\": passed,\n                    \"failed\": failed,\n                    \"skipped\": skipped,\n                });\n\n                if *is_detailed {\n                    result[\"file_path\"] = serde_json::Value::String(suite_path.to_string());\n                    result[\"duration\"] = serde_json::Value::String(format!(\"{:.2?}\", suite.duration));\n                }\n\n                result\n            }).collect::<Vec<serde_json::Value>>(),\n        });\n\n        serde_json::to_string_pretty(&output).unwrap()\n    }\n\n    fn format_table_output(&self, is_detailed: &bool, outcome: &TestOutcome) -> Table {\n        let mut table = Table::new();\n        if shell::is_markdown() {\n            table.load_preset(ASCII_MARKDOWN);\n        } else {\n            table.apply_modifier(UTF8_ROUND_CORNERS);\n        }\n\n        let mut row = Row::from(vec![\n            Cell::new(\"Test Suite\"),\n            Cell::new(\"Passed\").fg(Color::Green),\n            Cell::new(\"Failed\").fg(Color::Red),\n            Cell::new(\"Skipped\").fg(Color::Yellow),\n        ]);\n        if *is_detailed {\n            row.add_cell(Cell::new(\"File Path\").fg(Color::Cyan));\n            row.add_cell(Cell::new(\"Duration\").fg(Color::Cyan));\n        }\n        table.set_header(row);\n\n        // Traverse the test_results vector and build the table\n        for (contract, suite) in &outcome.results {\n            let mut row = Row::new();\n            let (suite_path, suite_name) = contract.split_once(':').unwrap();\n\n            let passed = suite.successes().count();\n            let mut passed_cell = Cell::new(passed);\n\n            let failed = suite.failures().count();\n            let mut failed_cell = Cell::new(failed);\n\n            let skipped = suite.skips().count();\n            let mut skipped_cell = Cell::new(skipped);\n\n            row.add_cell(Cell::new(suite_name));\n\n            if passed > 0 {\n                passed_cell = passed_cell.fg(Color::Green);\n            }\n            row.add_cell(passed_cell);\n\n            if failed > 0 {\n                failed_cell = failed_cell.fg(Color::Red);\n            }\n            row.add_cell(failed_cell);\n\n            if skipped > 0 {\n                skipped_cell = skipped_cell.fg(Color::Yellow);\n            }\n            row.add_cell(skipped_cell);\n\n            if self.is_detailed {\n                row.add_cell(Cell::new(suite_path));\n                row.add_cell(Cell::new(format!(\"{:.2?}\", suite.duration)));\n            }\n\n            table.add_row(row);\n        }\n\n        table\n    }\n}\n\n/// Helper function to create the invariant metrics table.\n///\n/// ╭-----------------------+----------------+-------+---------+----------╮\n/// | Contract              | Selector       | Calls | Reverts | Discards |\n/// +=====================================================================+\n/// | AnotherCounterHandler | doWork         | 7451  | 123     | 4941     |\n/// |-----------------------+----------------+-------+---------+----------|\n/// | AnotherCounterHandler | doWorkThing    | 7279  | 137     | 4849     |\n/// |-----------------------+----------------+-------+---------+----------|\n/// | CounterHandler        | doAnotherThing | 7302  | 150     | 4794     |\n/// |-----------------------+----------------+-------+---------+----------|\n/// | CounterHandler        | doSomething    | 7382  | 160     |4794      |\n/// ╰-----------------------+----------------+-------+---------+----------╯\npub(crate) fn format_invariant_metrics_table(\n    test_metrics: &HashMap<String, InvariantMetrics>,\n) -> Table {\n    let mut table = Table::new();\n    if shell::is_markdown() {\n        table.load_preset(ASCII_MARKDOWN);\n    } else {\n        table.apply_modifier(UTF8_ROUND_CORNERS);\n    }\n\n    table.set_header(vec![\n        Cell::new(\"Contract\"),\n        Cell::new(\"Selector\"),\n        Cell::new(\"Calls\").fg(Color::Green),\n        Cell::new(\"Reverts\").fg(Color::Red),\n        Cell::new(\"Discards\").fg(Color::Yellow),\n    ]);\n\n    for name in test_metrics.keys().sorted() {\n        if let Some((contract, selector)) =\n            name.split_once(':').map_or(name.as_str(), |(_, contract)| contract).split_once('.')\n        {\n            let mut row = Row::new();\n            row.add_cell(Cell::new(contract));\n            row.add_cell(Cell::new(selector));\n\n            if let Some(metrics) = test_metrics.get(name) {\n                let calls_cell = Cell::new(metrics.calls).fg(if metrics.calls > 0 {\n                    Color::Green\n                } else {\n                    Color::White\n                });\n\n                let reverts_cell = Cell::new(metrics.reverts).fg(if metrics.reverts > 0 {\n                    Color::Red\n                } else {\n                    Color::White\n                });\n\n                let discards_cell = Cell::new(metrics.discards).fg(if metrics.discards > 0 {\n                    Color::Yellow\n                } else {\n                    Color::White\n                });\n\n                row.add_cell(calls_cell);\n                row.add_cell(reverts_cell);\n                row.add_cell(discards_cell);\n            }\n\n            table.add_row(row);\n        }\n    }\n    table\n}\n\n#[cfg(test)]\nmod tests {\n    use crate::cmd::test::summary::format_invariant_metrics_table;\n    use foundry_evm::executors::invariant::InvariantMetrics;\n    use std::collections::HashMap;\n\n    #[test]\n    fn test_invariant_metrics_table() {\n        let mut test_metrics = HashMap::new();\n        test_metrics.insert(\n            \"SystemConfig.setGasLimit\".to_string(),\n            InvariantMetrics { calls: 10, reverts: 1, discards: 1 },\n        );\n        test_metrics.insert(\n            \"src/universal/Proxy.sol:Proxy.changeAdmin\".to_string(),\n            InvariantMetrics { calls: 20, reverts: 2, discards: 2 },\n        );\n        let table = format_invariant_metrics_table(&test_metrics);\n        assert_eq!(table.row_count(), 2);\n\n        let mut first_row_content = table.row(0).unwrap().cell_iter();\n        assert_eq!(first_row_content.next().unwrap().content(), \"SystemConfig\");\n        assert_eq!(first_row_content.next().unwrap().content(), \"setGasLimit\");\n        assert_eq!(first_row_content.next().unwrap().content(), \"10\");\n        assert_eq!(first_row_content.next().unwrap().content(), \"1\");\n        assert_eq!(first_row_content.next().unwrap().content(), \"1\");\n\n        let mut second_row_content = table.row(1).unwrap().cell_iter();\n        assert_eq!(second_row_content.next().unwrap().content(), \"Proxy\");\n        assert_eq!(second_row_content.next().unwrap().content(), \"changeAdmin\");\n        assert_eq!(second_row_content.next().unwrap().content(), \"20\");\n        assert_eq!(second_row_content.next().unwrap().content(), \"2\");\n        assert_eq!(second_row_content.next().unwrap().content(), \"2\");\n    }\n}\n"
  },
  {
    "path": "crates/forge/src/cmd/tree.rs",
    "content": "use clap::Parser;\nuse eyre::Result;\nuse foundry_cli::{opts::ProjectPathOpts, utils::LoadConfig};\nuse foundry_compilers::{\n    Graph,\n    resolver::{Charset, TreeOptions},\n};\n\n/// CLI arguments for `forge tree`.\n#[derive(Clone, Debug, Parser)]\npub struct TreeArgs {\n    /// Do not de-duplicate (repeats all shared dependencies)\n    #[arg(long)]\n    no_dedupe: bool,\n\n    /// Character set to use in output.\n    ///\n    /// [possible values: utf8, ascii]\n    #[arg(long, default_value = \"utf8\")]\n    charset: Charset,\n\n    #[command(flatten)]\n    project_paths: ProjectPathOpts,\n}\n\nfoundry_config::impl_figment_convert!(TreeArgs, project_paths);\n\nimpl TreeArgs {\n    pub fn run(self) -> Result<()> {\n        let config = self.load_config()?;\n        let graph = <Graph>::resolve(&config.project_paths())?;\n        let opts = TreeOptions { charset: self.charset, no_dedupe: self.no_dedupe };\n        graph.print_with_options(opts);\n\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "crates/forge/src/cmd/update.rs",
    "content": "use crate::{DepIdentifier, DepMap, Lockfile};\nuse alloy_primitives::map::HashMap;\nuse clap::{Parser, ValueHint};\nuse eyre::{Context, Result};\nuse foundry_cli::{\n    opts::Dependency,\n    utils::{CommandUtils, Git, LoadConfig},\n};\nuse foundry_config::{Config, impl_figment_convert_basic};\nuse std::path::{Path, PathBuf};\nuse yansi::Paint;\n\n/// CLI arguments for `forge update`.\n#[derive(Clone, Debug, Parser)]\npub struct UpdateArgs {\n    /// The dependencies you want to update.\n    dependencies: Vec<Dependency>,\n\n    /// The project's root path.\n    ///\n    /// By default root of the Git repository, if in one,\n    /// or the current working directory.\n    #[arg(long, value_hint = ValueHint::DirPath, value_name = \"PATH\")]\n    root: Option<PathBuf>,\n\n    /// Override the up-to-date check.\n    #[arg(short, long)]\n    force: bool,\n\n    /// Recursively update submodules.\n    #[arg(short, long)]\n    recursive: bool,\n}\nimpl_figment_convert_basic!(UpdateArgs);\n\nimpl UpdateArgs {\n    pub fn run(self) -> Result<()> {\n        let config = self.load_config()?;\n        // dep_overrides consists of absolute paths of dependencies and their tags\n        let (root, _paths, dep_overrides) = dependencies_paths(&self.dependencies, &config)?;\n        // Mapping of relative path of lib to its tag type\n        // e.g \"lib/forge-std\" -> DepIdentifier::Tag { name: \"v0.1.0\", rev: \"1234567\" }\n        let git = Git::new(&root);\n\n        let mut foundry_lock = Lockfile::new(&config.root).with_git(&git);\n        let out_of_sync_deps = foundry_lock.sync(config.install_lib_dir())?;\n\n        // update the submodules' tags if any overrides are present\n        let mut prev_dep_ids: DepMap = HashMap::default();\n        if dep_overrides.is_empty() {\n            // running `forge update`, update all deps\n            foundry_lock.iter_mut().for_each(|(_path, dep_id)| {\n                // Set r#override flag to true if the dep is a branch\n                if let DepIdentifier::Branch { .. } = dep_id {\n                    dep_id.mark_override();\n                }\n            });\n        } else {\n            for (dep_path, override_tag) in &dep_overrides {\n                let rel_path = dep_path\n                    .strip_prefix(&root)\n                    .wrap_err(\"Dependency path is not relative to the repository root\")?;\n\n                if let Ok(mut dep_id) = DepIdentifier::resolve_type(&git, dep_path, override_tag) {\n                    // Store the previous state before overriding\n                    let prev = foundry_lock.get(rel_path).cloned();\n\n                    // If it's a branch, mark it as overridden so it gets updated below\n                    if let DepIdentifier::Branch { .. } = dep_id {\n                        dep_id.mark_override();\n                    }\n\n                    // Update the lockfile\n                    foundry_lock.override_dep(rel_path, dep_id)?;\n\n                    // Only track as updated if there was a previous dependency\n                    if let Some(prev) = prev {\n                        prev_dep_ids.insert(rel_path.to_owned(), prev);\n                    }\n                } else {\n                    sh_warn!(\n                        \"Could not r#override submodule at {} with tag {}, try using forge install\",\n                        rel_path.display(),\n                        override_tag\n                    )?;\n                }\n            }\n        }\n\n        // fetch the latest changes for each submodule (recursively if flag is set)\n        let git = Git::new(&root);\n        let update_paths = self.update_dep_paths(&foundry_lock);\n        trace!(?update_paths, \"updating deps at\");\n\n        if self.recursive {\n            // update submodules recursively\n            git.submodule_update(self.force, true, false, true, update_paths)?;\n        } else {\n            let is_empty = update_paths.is_empty();\n\n            // update submodules\n            git.submodule_update(self.force, true, false, false, update_paths)?;\n\n            if !is_empty {\n                // initialize submodules of each submodule recursively (otherwise direct submodule\n                // dependencies will revert to last commit)\n                git.submodule_foreach(false, \"git submodule update --init --progress --recursive\")?;\n            }\n        }\n\n        // Update branches to their latest commit from origin\n        // This handles both explicit updates (forge update dep@branch) and\n        // general updates (forge update) for branch-tracked dependencies\n        let branch_overrides = foundry_lock\n            .iter_mut()\n            .filter_map(|(path, dep_id)| {\n                if dep_id.is_branch() && dep_id.overridden() {\n                    return Some((path, dep_id));\n                }\n                None\n            })\n            .collect::<Vec<_>>();\n\n        for (path, dep_id) in branch_overrides {\n            let submodule_path = root.join(path);\n            let name = dep_id.name();\n\n            // Fetch and checkout the latest commit from the remote branch\n            Self::fetch_and_checkout_branch(&git, &submodule_path, name)?;\n\n            // Now get the updated revision after syncing with origin\n            let (updated_rev, _) = git.current_rev_branch(&submodule_path)?;\n\n            // Update the lockfile entry to reflect the latest commit\n            let prev = std::mem::replace(\n                dep_id,\n                DepIdentifier::Branch {\n                    name: name.to_string(),\n                    rev: updated_rev,\n                    r#override: true,\n                },\n            );\n\n            // Only insert if we don't already have a previous state for this path\n            // (e.g., from explicit overrides where we converted tag to branch)\n            if !prev_dep_ids.contains_key(path) {\n                prev_dep_ids.insert(path.to_owned(), prev);\n            }\n        }\n\n        // checkout the submodules at the correct tags\n        // Skip branches that were already updated above to avoid reverting to local branch\n        for (path, dep_id) in foundry_lock.iter() {\n            // Ignore other dependencies if single update.\n            if !dep_overrides.is_empty() && !dep_overrides.contains_key(path) {\n                continue;\n            }\n\n            // Skip branches that were already updated\n            if dep_id.is_branch() && dep_id.overridden() {\n                continue;\n            }\n            git.checkout_at(dep_id.checkout_id(), &root.join(path))?;\n        }\n\n        if out_of_sync_deps.is_some_and(|o| !o.is_empty())\n            || foundry_lock.iter().any(|(_, dep_id)| dep_id.overridden())\n        {\n            foundry_lock.write()?;\n        }\n\n        // Print updates from => to\n        for (path, prev) in prev_dep_ids {\n            let curr = foundry_lock.get(&path).unwrap();\n            sh_println!(\n                \"Updated dep at '{}', (from: {prev}, to: {curr})\",\n                path.display().green(),\n                prev = prev,\n                curr = curr.yellow()\n            )?;\n        }\n\n        Ok(())\n    }\n\n    /// Returns the `lib/paths` of the dependencies that have been updated/overridden.\n    fn update_dep_paths(&self, foundry_lock: &Lockfile<'_>) -> Vec<PathBuf> {\n        foundry_lock\n            .iter()\n            .filter_map(|(path, dep_id)| {\n                if dep_id.overridden() {\n                    return Some(path.to_path_buf());\n                }\n                None\n            })\n            .collect()\n    }\n\n    /// Fetches and checks out the latest version of a branch from origin\n    fn fetch_and_checkout_branch(git: &Git<'_>, path: &Path, branch: &str) -> Result<()> {\n        // Fetch the latest changes from origin for the branch\n        git.cmd_at(path).args([\"fetch\", \"origin\", branch]).exec().wrap_err(format!(\n            \"Could not fetch latest changes for branch {} in submodule at {}\",\n            branch,\n            path.display()\n        ))?;\n\n        // Checkout and track the remote branch to ensure we have the latest commit\n        // Using checkout -B ensures the local branch tracks origin/branch\n        git.cmd_at(path)\n            .args([\"checkout\", \"-B\", branch, &format!(\"origin/{branch}\")])\n            .exec()\n            .wrap_err(format!(\n                \"Could not checkout and track origin/{} for submodule at {}\",\n                branch,\n                path.display()\n            ))?;\n\n        Ok(())\n    }\n}\n\n/// Returns `(root, paths, overridden_deps_with_abosolute_paths)` where `root` is the root of the\n/// Git repository and `paths` are the relative paths of the dependencies.\n#[allow(clippy::type_complexity)]\npub fn dependencies_paths(\n    deps: &[Dependency],\n    config: &Config,\n) -> Result<(PathBuf, Vec<PathBuf>, HashMap<PathBuf, String>)> {\n    let git_root = Git::root_of(&config.root)?;\n    let libs = config.install_lib_dir();\n\n    if deps.is_empty() {\n        return Ok((git_root, Vec::new(), HashMap::default()));\n    }\n\n    let mut paths = Vec::with_capacity(deps.len());\n    let mut overrides = HashMap::with_capacity_and_hasher(deps.len(), Default::default());\n    for dep in deps {\n        let name = dep.name();\n        let dep_path = libs.join(name);\n        if !dep_path.exists() {\n            eyre::bail!(\"Could not find dependency {name:?} in {}\", dep_path.display());\n        }\n        let rel_path = dep_path\n            .strip_prefix(&git_root)\n            .wrap_err(\"Library directory is not relative to the repository root\")?;\n\n        if let Some(tag) = &dep.tag {\n            overrides.insert(dep_path.to_owned(), tag.to_owned());\n        }\n        paths.push(rel_path.to_owned());\n    }\n    Ok((git_root, paths, overrides))\n}\n"
  },
  {
    "path": "crates/forge/src/cmd/watch.rs",
    "content": "use super::{\n    build::BuildArgs, coverage::CoverageArgs, doc::DocArgs, fmt::FmtArgs,\n    snapshot::GasSnapshotArgs, test::TestArgs,\n};\nuse alloy_primitives::map::HashSet;\nuse clap::Parser;\nuse eyre::Result;\nuse foundry_cli::utils::{self, FoundryPathExt, LoadConfig};\nuse foundry_config::Config;\nuse parking_lot::Mutex;\nuse std::{\n    path::PathBuf,\n    sync::{\n        Arc,\n        atomic::{AtomicU8, Ordering},\n    },\n    time::Duration,\n};\nuse tokio::process::Command as TokioCommand;\nuse watchexec::{\n    Watchexec,\n    action::ActionHandler,\n    command::{Command, Program},\n    job::{CommandState, Job},\n    paths::summarise_events_to_env,\n};\nuse watchexec_events::{\n    Event, Priority, ProcessEnd, Tag,\n    filekind::{AccessKind, FileEventKind},\n};\nuse watchexec_signals::Signal;\nuse yansi::{Color, Paint};\n\ntype SpawnHook = Arc<dyn Fn(&[Event], &mut TokioCommand) + Send + Sync + 'static>;\n\n#[derive(Clone, Debug, Default, Parser)]\n#[command(next_help_heading = \"Watch options\")]\npub struct WatchArgs {\n    /// Watch the given files or directories for changes.\n    ///\n    /// If no paths are provided, the source and test directories of the project are watched.\n    #[arg(long, short, num_args(0..), value_name = \"PATH\")]\n    pub watch: Option<Vec<PathBuf>>,\n\n    /// Do not restart the command while it's still running.\n    #[arg(long)]\n    pub no_restart: bool,\n\n    /// Explicitly re-run all tests when a change is made.\n    ///\n    /// By default, only the tests of the last modified test file are executed.\n    #[arg(long)]\n    pub run_all: bool,\n\n    /// Re-run only previously failed tests first when a change is made.\n    ///\n    /// If all previously failed tests pass, the full test suite will be run automatically.\n    /// This is particularly useful for TDD workflows where you want fast feedback on failures.\n    #[arg(long, alias = \"rerun-failures\")]\n    pub rerun_failed: bool,\n\n    /// File update debounce delay.\n    ///\n    /// During the delay, incoming change events are accumulated and\n    /// only once the delay has passed, is an action taken. Note that\n    /// this does not mean a command will be started: if --no-restart is\n    /// given and a command is already running, the outcome of the\n    /// action will be to do nothing.\n    ///\n    /// Defaults to 50ms. Parses as decimal seconds by default, but\n    /// using an integer with the `ms` suffix may be more convenient.\n    ///\n    /// When using --poll mode, you'll want a larger duration, or risk\n    /// overloading disk I/O.\n    #[arg(long, value_name = \"DELAY\")]\n    pub watch_delay: Option<String>,\n}\n\nimpl WatchArgs {\n    /// Creates a new [`watchexec::Config`].\n    ///\n    /// If paths were provided as arguments the these will be used as the watcher's pathset,\n    /// otherwise the path the closure returns will be used.\n    pub fn watchexec_config<PS: IntoIterator<Item = P>, P: Into<PathBuf>>(\n        &self,\n        default_paths: impl FnOnce() -> Result<PS>,\n    ) -> Result<watchexec::Config> {\n        self.watchexec_config_generic(default_paths, None)\n    }\n\n    /// Creates a new [`watchexec::Config`] with a custom command spawn hook.\n    ///\n    /// If paths were provided as arguments the these will be used as the watcher's pathset,\n    /// otherwise the path the closure returns will be used.\n    pub fn watchexec_config_with_override<PS: IntoIterator<Item = P>, P: Into<PathBuf>>(\n        &self,\n        default_paths: impl FnOnce() -> Result<PS>,\n        spawn_hook: impl Fn(&[Event], &mut TokioCommand) + Send + Sync + 'static,\n    ) -> Result<watchexec::Config> {\n        self.watchexec_config_generic(default_paths, Some(Arc::new(spawn_hook)))\n    }\n\n    fn watchexec_config_generic<PS: IntoIterator<Item = P>, P: Into<PathBuf>>(\n        &self,\n        default_paths: impl FnOnce() -> Result<PS>,\n        spawn_hook: Option<SpawnHook>,\n    ) -> Result<watchexec::Config> {\n        let mut paths = self.watch.as_deref().unwrap_or_default();\n        let storage: Vec<_>;\n        if paths.is_empty() {\n            storage = default_paths()?.into_iter().map(Into::into).filter(|p| p.exists()).collect();\n            paths = &storage;\n        }\n        self.watchexec_config_inner(paths, spawn_hook)\n    }\n\n    fn watchexec_config_inner(\n        &self,\n        paths: &[PathBuf],\n        spawn_hook: Option<SpawnHook>,\n    ) -> Result<watchexec::Config> {\n        let config = watchexec::Config::default();\n\n        config.on_error(|err| {\n            let _ = sh_eprintln!(\"[[{err:?}]]\");\n        });\n\n        if let Some(delay) = &self.watch_delay {\n            config.throttle(utils::parse_delay(delay)?);\n        }\n\n        config.pathset(paths.iter().map(|p| p.as_path()));\n\n        let n_path_args = self.watch.as_deref().unwrap_or_default().len();\n        let base_command = Arc::new(watch_command(cmd_args(n_path_args)));\n\n        let id = watchexec::Id::default();\n        let quit_again = Arc::new(AtomicU8::new(0));\n        let stop_timeout = Duration::from_secs(5);\n        let no_restart = self.no_restart;\n        let stop_signal = Signal::Terminate;\n        config.on_action(move |mut action| {\n            let base_command = base_command.clone();\n            let job = action.get_or_create_job(id, move || base_command.clone());\n\n            let events = action.events.clone();\n            let spawn_hook = spawn_hook.clone();\n            job.set_spawn_hook(move |command, _| {\n                // https://github.com/watchexec/watchexec/blob/72f069a8477c679e45f845219276b0bfe22fed79/crates/cli/src/emits.rs#L9\n                let env = summarise_events_to_env(events.iter());\n                for (k, v) in env {\n                    command.command_mut().env(format!(\"WATCHEXEC_{k}_PATH\"), v);\n                }\n\n                if let Some(spawn_hook) = &spawn_hook {\n                    spawn_hook(&events, command.command_mut());\n                }\n            });\n\n            let clear_screen = || {\n                let _ = clearscreen::clear();\n            };\n\n            let quit = |mut action: ActionHandler| {\n                match quit_again.fetch_add(1, Ordering::Relaxed) {\n                    0 => {\n                        let _ = sh_eprintln!(\n                            \"[Waiting {stop_timeout:?} for processes to exit before stopping... \\\n                             Ctrl-C again to exit faster]\"\n                        );\n                        action.quit_gracefully(stop_signal, stop_timeout);\n                    }\n                    1 => action.quit_gracefully(Signal::ForceStop, Duration::ZERO),\n                    _ => action.quit(),\n                }\n\n                action\n            };\n\n            let signals = action.signals().collect::<Vec<_>>();\n\n            if signals.contains(&Signal::Terminate) || signals.contains(&Signal::Interrupt) {\n                return quit(action);\n            }\n\n            // Only filesystem events below here (or empty synthetic events).\n            if action.paths().next().is_none() && !action.events.iter().any(|e| e.is_empty()) {\n                debug!(\"no filesystem or synthetic events, skip without doing more\");\n                return action;\n            }\n\n            if cfg!(target_os = \"linux\") {\n                // Reading a file now triggers `Access(Open)` events on Linux due to:\n                // https://github.com/notify-rs/notify/pull/612\n                // This causes an infinite rebuild loop: the build reads a file,\n                // which triggers a notification, which restarts the build, and so on.\n                // To prevent this, we ignore `Access(Open)` events during event processing.\n                let mut has_file_events = false;\n                let mut has_synthetic_events = false;\n                'outer: for e in action.events.iter() {\n                    if e.is_empty() {\n                        has_synthetic_events = true;\n                        break;\n                    } else {\n                        for tag in &e.tags {\n                            if let Tag::FileEventKind(kind) = tag\n                                && !matches!(kind, FileEventKind::Access(AccessKind::Open(_))) {\n                                    has_file_events = true;\n                                    break 'outer;\n                                }\n                        }\n                    }\n                }\n                if !has_file_events && !has_synthetic_events {\n                    debug!(\"no filesystem events (other than Access(Open)) or synthetic events, skip without doing more\");\n                    return action;\n                }\n            }\n\n            job.run({\n                let job = job.clone();\n                move |context| {\n                    if context.current.is_running() && no_restart {\n                        return;\n                    }\n                    job.restart_with_signal(stop_signal, stop_timeout);\n                    job.run({\n                        let job = job.clone();\n                        move |context| {\n                            clear_screen();\n                            setup_process(job, &context.command)\n                        }\n                    });\n                }\n            });\n\n            action\n        });\n\n        Ok(config)\n    }\n}\n\nfn setup_process(job: Job, _command: &Command) {\n    tokio::spawn(async move {\n        job.to_wait().await;\n        job.run(move |context| end_of_process(context.current));\n    });\n}\n\nfn end_of_process(state: &CommandState) {\n    let CommandState::Finished { status, started, finished } = state else {\n        return;\n    };\n\n    let duration = *finished - *started;\n    let timings = true;\n    let timing = if timings { format!(\", lasted {duration:?}\") } else { String::new() };\n    let (msg, fg) = match status {\n        ProcessEnd::ExitError(code) => (format!(\"Command exited with {code}{timing}\"), Color::Red),\n        ProcessEnd::ExitSignal(sig) => {\n            (format!(\"Command killed by {sig:?}{timing}\"), Color::Magenta)\n        }\n        ProcessEnd::ExitStop(sig) => (format!(\"Command stopped by {sig:?}{timing}\"), Color::Blue),\n        ProcessEnd::Continued => (format!(\"Command continued{timing}\"), Color::Cyan),\n        ProcessEnd::Exception(ex) => {\n            (format!(\"Command ended by exception {ex:#x}{timing}\"), Color::Yellow)\n        }\n        ProcessEnd::Success => (format!(\"Command was successful{timing}\"), Color::Green),\n    };\n\n    let quiet = false;\n    if !quiet {\n        let _ = sh_eprintln!(\"{}\", format!(\"[{msg}]\").paint(fg.foreground()));\n    }\n}\n\n/// Runs the given [`watchexec::Config`].\npub async fn run(config: watchexec::Config) -> Result<()> {\n    let wx = Watchexec::with_config(config)?;\n    wx.send_event(Event::default(), Priority::Urgent).await?;\n    wx.main().await??;\n    Ok(())\n}\n\n/// Executes a [`Watchexec`] that listens for changes in the project's src dir and reruns `forge\n/// build`\npub async fn watch_build(args: BuildArgs) -> Result<()> {\n    let config = args.watchexec_config()?;\n    run(config).await\n}\n\n/// Executes a [`Watchexec`] that listens for changes in the project's src dir and reruns `forge\n/// snapshot`\npub async fn watch_gas_snapshot(args: GasSnapshotArgs) -> Result<()> {\n    let config = args.watchexec_config()?;\n    run(config).await\n}\n\n/// Executes a [`Watchexec`] that listens for changes in the project's src dir and reruns `forge\n/// test`\npub async fn watch_test(args: TestArgs) -> Result<()> {\n    let config: Config = args.build.load_config()?;\n    let filter = args.filter(&config)?;\n    // Marker to check whether to override the command.\n    let no_reconfigure = filter.args().test_pattern.is_some()\n        || filter.args().path_pattern.is_some()\n        || filter.args().contract_pattern.is_some()\n        || args.watch.run_all;\n\n    let last_test_files = Mutex::new(HashSet::<String>::default());\n    let project_root = config.root.to_string_lossy().into_owned();\n    let test_failures_file = config.test_failures_file.clone();\n    let rerun_failed = args.watch.rerun_failed;\n\n    let config = args.watch.watchexec_config_with_override(\n        || Ok([&config.test, &config.src]),\n        move |events, command| {\n            // Check if we should prioritize rerunning failed tests\n            let has_failures = rerun_failed && test_failures_file.exists();\n\n            if has_failures {\n                // Smart mode: rerun failed tests first\n                trace!(\"Smart watch mode: will rerun failed tests first\");\n                command.arg(\"--rerun\");\n                // Don't add file-specific filters when rerunning failures\n                return;\n            }\n\n            let mut changed_sol_test_files: HashSet<_> = events\n                .iter()\n                .flat_map(|e| e.paths())\n                .filter(|(path, _)| path.is_sol_test())\n                .filter_map(|(path, _)| path.to_str())\n                .map(str::to_string)\n                .collect();\n\n            if changed_sol_test_files.len() > 1 {\n                // Run all tests if multiple files were changed at once, for example when running\n                // `forge fmt`.\n                return;\n            }\n\n            if changed_sol_test_files.is_empty() {\n                // Reuse the old test files if a non-test file was changed.\n                let last = last_test_files.lock();\n                if last.is_empty() {\n                    return;\n                }\n                changed_sol_test_files = last.clone();\n            }\n\n            // append `--match-path` glob\n            let mut file = changed_sol_test_files.iter().next().expect(\"test file present\").clone();\n\n            // remove the project root dir from the detected file\n            if let Some(f) = file.strip_prefix(&project_root) {\n                file = f.trim_start_matches('/').to_string();\n            }\n\n            trace!(?file, \"reconfigure test command\");\n\n            // Before appending `--match-path`, check if it already exists\n            if !no_reconfigure {\n                command.arg(\"--match-path\").arg(file);\n            }\n        },\n    )?;\n    run(config).await\n}\n\npub async fn watch_coverage(args: CoverageArgs) -> Result<()> {\n    let config = args.watch().watchexec_config(|| {\n        let config = args.load_config()?;\n        Ok([config.test, config.src])\n    })?;\n    run(config).await\n}\n\npub async fn watch_fmt(args: FmtArgs) -> Result<()> {\n    let config = args.watch.watchexec_config(|| {\n        let config = args.load_config()?;\n        Ok([config.src, config.test, config.script])\n    })?;\n    run(config).await\n}\n\n/// Executes a [`Watchexec`] that listens for changes in the project's sources directory\npub async fn watch_doc(args: DocArgs) -> Result<()> {\n    let config = args.watch.watchexec_config(|| {\n        let config = args.config()?;\n        Ok([config.src])\n    })?;\n    run(config).await\n}\n\n/// Converts a list of arguments to a `watchexec::Command`.\n///\n/// The first index in `args` is the path to the executable.\n///\n/// # Panics\n///\n/// Panics if `args` is empty.\nfn watch_command(mut args: Vec<String>) -> Command {\n    debug_assert!(!args.is_empty());\n    let prog = args.remove(0);\n    Command { program: Program::Exec { prog: prog.into(), args }, options: Default::default() }\n}\n\n/// Returns the env args without the `--watch` flag from the args for the Watchexec command\nfn cmd_args(num: usize) -> Vec<String> {\n    clean_cmd_args(num, std::env::args().collect())\n}\n\n#[instrument(level = \"debug\", ret)]\nfn clean_cmd_args(num: usize, mut cmd_args: Vec<String>) -> Vec<String> {\n    if let Some(pos) = cmd_args.iter().position(|arg| arg == \"--watch\" || arg == \"-w\") {\n        cmd_args.drain(pos..=(pos + num));\n    }\n\n    // There's another edge case where short flags are combined into one which is supported by clap,\n    // like `-vw` for verbosity and watch\n    // this removes any `w` from concatenated short flags\n    if let Some(pos) = cmd_args.iter().position(|arg| {\n        fn contains_w_in_short(arg: &str) -> Option<bool> {\n            let mut iter = arg.chars().peekable();\n            if *iter.peek()? != '-' {\n                return None;\n            }\n            iter.next();\n            if *iter.peek()? == '-' {\n                return None;\n            }\n            Some(iter.any(|c| c == 'w'))\n        }\n        contains_w_in_short(arg).unwrap_or(false)\n    }) {\n        let clean_arg = cmd_args[pos].replace('w', \"\");\n        if clean_arg == \"-\" {\n            cmd_args.remove(pos);\n        } else {\n            cmd_args[pos] = clean_arg;\n        }\n    }\n\n    cmd_args\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn parse_cmd_args() {\n        let args = vec![\"-vw\".to_string()];\n        let cleaned = clean_cmd_args(0, args);\n        assert_eq!(cleaned, vec![\"-v\".to_string()]);\n    }\n}\n"
  },
  {
    "path": "crates/forge/src/coverage.rs",
    "content": "//! Coverage reports.\n\nuse alloy_primitives::map::{HashMap, HashSet};\nuse comfy_table::{\n    Attribute, Cell, Color, Row, Table, modifiers::UTF8_ROUND_CORNERS, presets::ASCII_MARKDOWN,\n};\nuse evm_disassembler::disassemble_bytes;\nuse foundry_common::{fs, shell};\nuse semver::Version;\nuse std::{\n    collections::hash_map,\n    io::Write,\n    path::{Path, PathBuf},\n};\n\npub use foundry_evm::coverage::*;\n\n/// A coverage reporter.\npub trait CoverageReporter {\n    /// Returns a debug string for the reporter.\n    fn name(&self) -> &'static str;\n\n    /// Returns `true` if the reporter needs source maps for the final report.\n    fn needs_source_maps(&self) -> bool {\n        false\n    }\n\n    /// Runs the reporter.\n    fn report(&mut self, report: &CoverageReport) -> eyre::Result<()>;\n}\n\n/// A simple summary reporter that prints the coverage results in a table.\npub struct CoverageSummaryReporter {\n    /// The summary table.\n    table: Table,\n    /// The total coverage of the entire project.\n    total: CoverageSummary,\n}\n\nimpl Default for CoverageSummaryReporter {\n    fn default() -> Self {\n        let mut table = Table::new();\n        if shell::is_markdown() {\n            table.load_preset(ASCII_MARKDOWN);\n        } else {\n            table.apply_modifier(UTF8_ROUND_CORNERS);\n        }\n\n        table.set_header(vec![\n            Cell::new(\"File\"),\n            Cell::new(\"% Lines\"),\n            Cell::new(\"% Statements\"),\n            Cell::new(\"% Branches\"),\n            Cell::new(\"% Funcs\"),\n        ]);\n\n        Self { table, total: CoverageSummary::default() }\n    }\n}\n\nimpl CoverageSummaryReporter {\n    fn add_row(&mut self, name: impl Into<Cell>, summary: CoverageSummary) {\n        let mut row = Row::new();\n        row.add_cell(name.into())\n            .add_cell(format_cell(summary.line_hits, summary.line_count))\n            .add_cell(format_cell(summary.statement_hits, summary.statement_count))\n            .add_cell(format_cell(summary.branch_hits, summary.branch_count))\n            .add_cell(format_cell(summary.function_hits, summary.function_count));\n        self.table.add_row(row);\n    }\n}\n\nimpl CoverageReporter for CoverageSummaryReporter {\n    fn name(&self) -> &'static str {\n        \"summary\"\n    }\n\n    fn report(&mut self, report: &CoverageReport) -> eyre::Result<()> {\n        for (path, summary) in report.summary_by_file() {\n            self.total.merge(&summary);\n            self.add_row(path.display(), summary);\n        }\n\n        self.add_row(\"Total\", self.total.clone());\n        sh_println!(\"\\n{}\", self.table)?;\n        Ok(())\n    }\n}\n\nfn format_cell(hits: usize, total: usize) -> Cell {\n    let percentage = if total == 0 { 1. } else { hits as f64 / total as f64 };\n\n    let mut cell =\n        Cell::new(format!(\"{:.2}% ({hits}/{total})\", percentage * 100.)).fg(match percentage {\n            _ if total == 0 => Color::Grey,\n            _ if percentage < 0.5 => Color::Red,\n            _ if percentage < 0.75 => Color::Yellow,\n            _ => Color::Green,\n        });\n\n    if total == 0 {\n        cell = cell.add_attribute(Attribute::Dim);\n    }\n    cell\n}\n\n/// Writes the coverage report in [LCOV]'s [tracefile format].\n///\n/// [LCOV]: https://github.com/linux-test-project/lcov\n/// [tracefile format]: https://man.archlinux.org/man/geninfo.1.en#TRACEFILE_FORMAT\npub struct LcovReporter {\n    path: PathBuf,\n    version: Version,\n}\n\nimpl LcovReporter {\n    /// Create a new LCOV reporter.\n    pub fn new(path: PathBuf, version: Version) -> Self {\n        Self { path, version }\n    }\n}\n\nimpl CoverageReporter for LcovReporter {\n    fn name(&self) -> &'static str {\n        \"lcov\"\n    }\n\n    fn report(&mut self, report: &CoverageReport) -> eyre::Result<()> {\n        let mut out = std::io::BufWriter::new(fs::create_file(&self.path)?);\n\n        let mut fn_index = 0usize;\n        for (path, items) in report.items_by_file() {\n            let summary = CoverageSummary::from_items(items.iter().copied());\n\n            writeln!(out, \"TN:\")?;\n            writeln!(out, \"SF:{}\", path.display())?;\n\n            // First pass: collect line hits for DA records.\n            // Track both which lines have been recorded and the max hits per line.\n            let mut line_hits: HashMap<u32, u32> = HashMap::default();\n            for item in &items {\n                if matches!(item.kind, CoverageItemKind::Line | CoverageItemKind::Statement) {\n                    let line = item.loc.lines.start;\n                    line_hits\n                        .entry(line)\n                        .and_modify(|h| *h = (*h).max(item.hits))\n                        .or_insert(item.hits);\n                }\n            }\n\n            let mut recorded_lines = HashSet::new();\n\n            for item in items {\n                let line = item.loc.lines.start;\n                // `lines` is half-open, so we need to subtract 1 to get the last included line.\n                let end_line = item.loc.lines.end - 1;\n                let hits = item.hits;\n                match item.kind {\n                    CoverageItemKind::Function { ref name } => {\n                        let name = format!(\"{}.{name}\", item.loc.contract_name);\n                        if self.version >= Version::new(2, 2, 0) {\n                            // v2.2 changed the FN format.\n                            writeln!(out, \"FNL:{fn_index},{line},{end_line}\")?;\n                            writeln!(out, \"FNA:{fn_index},{hits},{name}\")?;\n                            fn_index += 1;\n                        } else if self.version >= Version::new(2, 0, 0) {\n                            // v2.0 added end_line to FN.\n                            writeln!(out, \"FN:{line},{end_line},{name}\")?;\n                            writeln!(out, \"FNDA:{hits},{name}\")?;\n                        } else {\n                            writeln!(out, \"FN:{line},{name}\")?;\n                            writeln!(out, \"FNDA:{hits},{name}\")?;\n                        }\n                    }\n                    // Add lines / statement hits only once.\n                    CoverageItemKind::Line | CoverageItemKind::Statement\n                        if recorded_lines.insert(line) =>\n                    {\n                        writeln!(out, \"DA:{line},{hits}\")?;\n                    }\n                    CoverageItemKind::Branch { branch_id, path_id, .. } => {\n                        // Per LCOV spec: \"-\" means the expression was never evaluated (line not\n                        // executed), \"0\" means branch exists but was never taken.\n                        // Check if the line containing this branch was hit.\n                        let line_was_hit = line_hits.get(&line).is_some_and(|&h| h > 0);\n                        let hits_str = if hits > 0 {\n                            hits.to_string()\n                        } else if line_was_hit {\n                            \"0\".to_string()\n                        } else {\n                            \"-\".to_string()\n                        };\n                        writeln!(out, \"BRDA:{line},{branch_id},{path_id},{hits_str}\")?;\n                    }\n                    _ => {}\n                }\n            }\n\n            // Function summary\n            writeln!(out, \"FNF:{}\", summary.function_count)?;\n            writeln!(out, \"FNH:{}\", summary.function_hits)?;\n\n            // Line summary\n            writeln!(out, \"LF:{}\", summary.line_count)?;\n            writeln!(out, \"LH:{}\", summary.line_hits)?;\n\n            // Branch summary\n            writeln!(out, \"BRF:{}\", summary.branch_count)?;\n            writeln!(out, \"BRH:{}\", summary.branch_hits)?;\n\n            writeln!(out, \"end_of_record\")?;\n        }\n\n        out.flush()?;\n        sh_println!(\"Wrote LCOV report.\")?;\n\n        Ok(())\n    }\n}\n\n/// A super verbose reporter for debugging coverage while it is still unstable.\npub struct DebugReporter;\n\nimpl CoverageReporter for DebugReporter {\n    fn name(&self) -> &'static str {\n        \"debug\"\n    }\n\n    fn report(&mut self, report: &CoverageReport) -> eyre::Result<()> {\n        for (path, items) in report.items_by_file() {\n            let src = fs::read_to_string(path)?;\n            sh_println!(\"{}:\", path.display())?;\n            for item in items {\n                sh_println!(\"- {}\", item.fmt_with_source(Some(&src)))?;\n            }\n            sh_println!()?;\n        }\n\n        for (contract_id, (cta, rta)) in &report.anchors {\n            if cta.is_empty() && rta.is_empty() {\n                continue;\n            }\n\n            sh_println!(\"Anchors for {contract_id}:\")?;\n            let anchors = cta\n                .iter()\n                .map(|anchor| (false, anchor))\n                .chain(rta.iter().map(|anchor| (true, anchor)));\n            for (is_runtime, anchor) in anchors {\n                let kind = if is_runtime { \" runtime\" } else { \"creation\" };\n                sh_println!(\n                    \"- {kind} {anchor}: {}\",\n                    report\n                        .analyses\n                        .get(&contract_id.version)\n                        .and_then(|items| items.get(anchor.item_id))\n                        .map_or_else(|| \"None\".to_owned(), |item| item.to_string())\n                )?;\n            }\n            sh_println!()?;\n        }\n\n        Ok(())\n    }\n}\n\npub struct BytecodeReporter {\n    root: PathBuf,\n    destdir: PathBuf,\n}\n\nimpl BytecodeReporter {\n    pub fn new(root: PathBuf, destdir: PathBuf) -> Self {\n        Self { root, destdir }\n    }\n}\n\nimpl CoverageReporter for BytecodeReporter {\n    fn name(&self) -> &'static str {\n        \"bytecode\"\n    }\n\n    fn needs_source_maps(&self) -> bool {\n        true\n    }\n\n    fn report(&mut self, report: &CoverageReport) -> eyre::Result<()> {\n        use std::fmt::Write;\n\n        fs::create_dir_all(&self.destdir)?;\n\n        let no_source_elements = Vec::new();\n        let mut line_number_cache = LineNumberCache::new(self.root.clone());\n\n        for (contract_id, hits) in &report.bytecode_hits {\n            let ops = disassemble_bytes(hits.bytecode().to_vec())?;\n            let mut formatted = String::new();\n\n            let source_elements =\n                report.source_maps.get(contract_id).map(|sm| &sm.1).unwrap_or(&no_source_elements);\n\n            for (code, source_element) in std::iter::zip(ops.iter(), source_elements) {\n                let hits = hits\n                    .get(code.offset)\n                    .map(|h| format!(\"[{h:03}]\"))\n                    .unwrap_or(\"     \".to_owned());\n                let source_id = source_element.index();\n                let source_path = source_id.and_then(|i| {\n                    report.source_paths.get(&(contract_id.version.clone(), i as usize))\n                });\n\n                let code = format!(\"{code:?}\");\n                let start = source_element.offset() as usize;\n                let end = (source_element.offset() + source_element.length()) as usize;\n\n                if let Some(source_path) = source_path {\n                    let (sline, spos) = line_number_cache.get_position(source_path, start)?;\n                    let (eline, epos) = line_number_cache.get_position(source_path, end)?;\n                    writeln!(\n                        formatted,\n                        \"{} {:40} // {}: {}:{}-{}:{} ({}-{})\",\n                        hits,\n                        code,\n                        source_path.display(),\n                        sline,\n                        spos,\n                        eline,\n                        epos,\n                        start,\n                        end\n                    )?;\n                } else if let Some(source_id) = source_id {\n                    writeln!(formatted, \"{hits} {code:40} // SRCID{source_id}: ({start}-{end})\")?;\n                } else {\n                    writeln!(formatted, \"{hits} {code:40}\")?;\n                }\n            }\n            fs::write(\n                self.destdir.join(&*contract_id.contract_name).with_extension(\"asm\"),\n                formatted,\n            )?;\n        }\n\n        Ok(())\n    }\n}\n\n/// Cache line number offsets for source files\nstruct LineNumberCache {\n    root: PathBuf,\n    line_offsets: HashMap<PathBuf, Vec<usize>>,\n}\n\nimpl LineNumberCache {\n    pub fn new(root: PathBuf) -> Self {\n        Self { root, line_offsets: HashMap::default() }\n    }\n\n    pub fn get_position(&mut self, path: &Path, offset: usize) -> eyre::Result<(usize, usize)> {\n        let line_offsets = match self.line_offsets.entry(path.to_path_buf()) {\n            hash_map::Entry::Occupied(o) => o.into_mut(),\n            hash_map::Entry::Vacant(v) => {\n                let text = fs::read_to_string(self.root.join(path))?;\n                let mut line_offsets = vec![0];\n                for line in text.lines() {\n                    let line_offset = line.as_ptr() as usize - text.as_ptr() as usize;\n                    line_offsets.push(line_offset);\n                }\n                v.insert(line_offsets)\n            }\n        };\n        let lo = match line_offsets.binary_search(&offset) {\n            Ok(lo) => lo,\n            Err(lo) => lo - 1,\n        };\n        let pos = offset - line_offsets.get(lo).unwrap() + 1;\n        Ok((lo, pos))\n    }\n}\n"
  },
  {
    "path": "crates/forge/src/gas_report.rs",
    "content": "//! Gas reports.\n\nuse crate::{\n    constants::{CHEATCODE_ADDRESS, HARDHAT_CONSOLE_ADDRESS},\n    traces::{CallTraceArena, CallTraceDecoder, CallTraceNode, DecodedCallData},\n};\nuse alloy_primitives::map::HashSet;\nuse comfy_table::{\n    Cell, CellAlignment, Color, Table, modifiers::UTF8_ROUND_CORNERS, presets::ASCII_MARKDOWN,\n};\nuse foundry_common::{TestFunctionExt, calc, shell};\nuse foundry_evm::traces::CallKind;\n\nuse serde::{Deserialize, Serialize};\nuse serde_json::json;\nuse std::{collections::BTreeMap, fmt::Display};\n\n/// Represents the gas report for a set of contracts.\n#[derive(Clone, Debug, Default, Serialize, Deserialize)]\npub struct GasReport {\n    /// Whether to report any contracts.\n    report_any: bool,\n    /// Contracts to generate the report for.\n    report_for: HashSet<String>,\n    /// Contracts to ignore when generating the report.\n    ignore: HashSet<String>,\n    /// Whether to include gas reports for tests.\n    include_tests: bool,\n    /// All contracts that were analyzed grouped by their identifier\n    /// ``test/Counter.t.sol:CounterTest\n    pub contracts: BTreeMap<String, ContractInfo>,\n}\n\nimpl GasReport {\n    pub fn new(\n        report_for: impl IntoIterator<Item = String>,\n        ignore: impl IntoIterator<Item = String>,\n        include_tests: bool,\n    ) -> Self {\n        let report_for = report_for.into_iter().collect::<HashSet<_>>();\n        let ignore = ignore.into_iter().collect::<HashSet<_>>();\n        let report_any = report_for.is_empty() || report_for.contains(\"*\");\n        Self { report_any, report_for, ignore, include_tests, ..Default::default() }\n    }\n\n    /// Whether the given contract should be reported.\n    #[instrument(level = \"trace\", skip(self), ret)]\n    fn should_report(&self, contract_name: &str) -> bool {\n        if self.ignore.contains(contract_name) {\n            let contains_anyway = self.report_for.contains(contract_name);\n            if contains_anyway {\n                // If the user listed the contract in 'gas_reports' (the foundry.toml field) a\n                // report for the contract is generated even if it's listed in the ignore\n                // list. This is addressed this way because getting a report you don't expect is\n                // preferable than not getting one you expect. A warning is printed to stderr\n                // indicating the \"double listing\".\n                let _ = sh_warn!(\n                    \"{contract_name} is listed in both 'gas_reports' and 'gas_reports_ignore'.\"\n                );\n            }\n            return contains_anyway;\n        }\n        self.report_any || self.report_for.contains(contract_name)\n    }\n\n    /// Analyzes the given traces and generates a gas report.\n    pub async fn analyze(\n        &mut self,\n        arenas: impl IntoIterator<Item = &CallTraceArena>,\n        decoder: &CallTraceDecoder,\n    ) {\n        for node in arenas.into_iter().flat_map(|arena| arena.nodes()) {\n            self.analyze_node(node, decoder).await;\n        }\n    }\n\n    async fn analyze_node(&mut self, node: &CallTraceNode, decoder: &CallTraceDecoder) {\n        let trace = &node.trace;\n\n        if trace.address == CHEATCODE_ADDRESS || trace.address == HARDHAT_CONSOLE_ADDRESS {\n            return;\n        }\n\n        let Some(name) = decoder.contracts.get(&node.trace.address) else { return };\n        let contract_name = name.rsplit(':').next().unwrap_or(name);\n\n        if !self.should_report(contract_name) {\n            return;\n        }\n        let contract_info = self.contracts.entry(name.to_string()).or_default();\n        let is_create_call = trace.kind.is_any_create();\n\n        // Record contract deployment size.\n        if is_create_call {\n            trace!(contract_name, \"adding create size info\");\n            contract_info.size = trace.data.len();\n        }\n\n        // Only include top-level calls which account for calldata and base (21.000) cost.\n        // Only include Calls and Creates as only these calls are isolated in inspector.\n        if trace.depth > 1 && (trace.kind == CallKind::Call || is_create_call) {\n            return;\n        }\n\n        let decoded = || decoder.decode_function(&node.trace);\n\n        if is_create_call {\n            trace!(contract_name, \"adding create gas info\");\n            contract_info.gas = trace.gas_used;\n        } else if let Some(DecodedCallData { signature, .. }) = decoded().await.call_data {\n            let name = signature.split('(').next().unwrap();\n            // ignore any test/setup functions\n            if self.include_tests || !name.test_function_kind().is_known() {\n                trace!(contract_name, signature, \"adding gas info\");\n                let gas_info = contract_info\n                    .functions\n                    .entry(name.to_string())\n                    .or_default()\n                    .entry(signature.clone())\n                    .or_default();\n                gas_info.frames.push(trace.gas_used);\n            }\n        }\n    }\n\n    /// Finalizes the gas report by calculating the min, max, mean, and median for each function.\n    #[must_use]\n    pub fn finalize(mut self) -> Self {\n        trace!(\"finalizing gas report\");\n        for contract in self.contracts.values_mut() {\n            for sigs in contract.functions.values_mut() {\n                for func in sigs.values_mut() {\n                    func.frames.sort_unstable();\n                    func.min = func.frames.first().copied().unwrap_or_default();\n                    func.max = func.frames.last().copied().unwrap_or_default();\n                    func.mean = calc::mean(&func.frames);\n                    func.median = calc::median_sorted(&func.frames);\n                    func.calls = func.frames.len() as u64;\n                }\n            }\n        }\n        self\n    }\n}\n\nimpl Display for GasReport {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {\n        if shell::is_json() {\n            writeln!(f, \"{}\", &self.format_json_output())?;\n        } else {\n            for (name, contract) in &self.contracts {\n                if contract.functions.is_empty() {\n                    trace!(name, \"gas report contract without functions\");\n                    continue;\n                }\n\n                let table = self.format_table_output(contract, name);\n                writeln!(f, \"\\n{table}\")?;\n            }\n        }\n\n        Ok(())\n    }\n}\n\nimpl GasReport {\n    fn format_json_output(&self) -> String {\n        serde_json::to_string(\n            &self\n                .contracts\n                .iter()\n                .filter_map(|(name, contract)| {\n                    if contract.functions.is_empty() {\n                        trace!(name, \"gas report contract without functions\");\n                        return None;\n                    }\n\n                    let functions = contract\n                        .functions\n                        .values()\n                        .flat_map(|sigs| {\n                            sigs.iter().map(|(sig, gas_info)| {\n                                let display_name = sig.replace(':', \"\");\n                                (display_name, gas_info)\n                            })\n                        })\n                        .collect::<BTreeMap<_, _>>();\n\n                    Some(json!({\n                        \"contract\": name,\n                        \"deployment\": {\n                            \"gas\": contract.gas,\n                            \"size\": contract.size,\n                        },\n                        \"functions\": functions,\n                    }))\n                })\n                .collect::<Vec<_>>(),\n        )\n        .unwrap()\n    }\n\n    fn format_table_output(&self, contract: &ContractInfo, name: &str) -> Table {\n        let mut table = Table::new();\n        if shell::is_markdown() {\n            table.load_preset(ASCII_MARKDOWN);\n        } else {\n            table.apply_modifier(UTF8_ROUND_CORNERS);\n        }\n\n        table.set_header(vec![Cell::new(format!(\"{name} Contract\")).fg(Color::Magenta)]);\n\n        table.add_row(vec![\n            Cell::new(\"Deployment Cost\").fg(Color::Cyan),\n            Cell::new(\"Deployment Size\").fg(Color::Cyan),\n        ]);\n        table.add_row(vec![\n            Cell::new(contract.gas.to_string()).set_alignment(CellAlignment::Right),\n            Cell::new(contract.size.to_string()).set_alignment(CellAlignment::Right),\n        ]);\n\n        // Add a blank row to separate deployment info from function info.\n        table.add_row(vec![Cell::new(\"\")]);\n\n        table.add_row(vec![\n            Cell::new(\"Function Name\"),\n            Cell::new(\"Min\").fg(Color::Green),\n            Cell::new(\"Avg\").fg(Color::Yellow),\n            Cell::new(\"Median\").fg(Color::Yellow),\n            Cell::new(\"Max\").fg(Color::Red),\n            Cell::new(\"# Calls\").fg(Color::Cyan),\n        ]);\n\n        contract.functions.iter().for_each(|(fname, sigs)| {\n            sigs.iter().for_each(|(sig, gas_info)| {\n                // Show function signature if overloaded else display function name.\n                let display_name =\n                    if sigs.len() == 1 { fname.to_string() } else { sig.replace(':', \"\") };\n\n                table.add_row(vec![\n                    Cell::new(display_name),\n                    Cell::new(gas_info.min.to_string())\n                        .fg(Color::Green)\n                        .set_alignment(CellAlignment::Right),\n                    Cell::new(gas_info.mean.to_string())\n                        .fg(Color::Yellow)\n                        .set_alignment(CellAlignment::Right),\n                    Cell::new(gas_info.median.to_string())\n                        .fg(Color::Yellow)\n                        .set_alignment(CellAlignment::Right),\n                    Cell::new(gas_info.max.to_string())\n                        .fg(Color::Red)\n                        .set_alignment(CellAlignment::Right),\n                    Cell::new(gas_info.calls.to_string()).set_alignment(CellAlignment::Right),\n                ]);\n            })\n        });\n\n        table\n    }\n}\n\n#[derive(Clone, Debug, Default, Serialize, Deserialize)]\npub struct ContractInfo {\n    pub gas: u64,\n    pub size: usize,\n    /// Function name -> Function signature -> GasInfo\n    pub functions: BTreeMap<String, BTreeMap<String, GasInfo>>,\n}\n\n#[derive(Clone, Debug, Default, Serialize, Deserialize)]\npub struct GasInfo {\n    pub calls: u64,\n    pub min: u64,\n    pub mean: u64,\n    pub median: u64,\n    pub max: u64,\n\n    #[serde(skip)]\n    pub frames: Vec<u64>,\n}\n"
  },
  {
    "path": "crates/forge/src/lib.rs",
    "content": "//! Forge is a fast and flexible Ethereum testing framework.\n\n#![cfg_attr(not(test), warn(unused_crate_dependencies))]\n#![cfg_attr(docsrs, feature(doc_cfg))]\n\n#[macro_use]\nextern crate foundry_common;\n\n#[macro_use]\nextern crate tracing;\n\n// Required for optional features (aws-kms, gcp-kms, turnkey)\n#[cfg(any(feature = \"aws-kms\", feature = \"gcp-kms\", feature = \"turnkey\"))]\nuse foundry_wallets as _;\n\npub mod args;\npub mod cmd;\npub mod opts;\n\npub mod coverage;\n\npub mod gas_report;\n\npub mod multi_runner;\npub use multi_runner::{MultiContractRunner, MultiContractRunnerBuilder};\n\nmod runner;\npub use runner::ContractRunner;\n\nmod progress;\npub mod result;\n\n// TODO: remove\npub use foundry_common::traits::TestFilter;\npub use foundry_evm::*;\n\nmod lockfile;\npub use lockfile::{DepIdentifier, DepMap, FOUNDRY_LOCK, Lockfile};\n"
  },
  {
    "path": "crates/forge/src/lockfile.rs",
    "content": "//! foundry.lock handler type.\n\nuse alloy_primitives::map::HashMap;\nuse eyre::{OptionExt, Result};\nuse foundry_cli::utils::Git;\nuse serde::{Deserialize, Serialize};\nuse std::{\n    collections::{BTreeMap, hash_map::Entry},\n    path::{Path, PathBuf},\n};\n\npub const FOUNDRY_LOCK: &str = \"foundry.lock\";\n\n/// A type alias for a HashMap of dependencies keyed by relative path to the submodule dir.\npub type DepMap = HashMap<PathBuf, DepIdentifier>;\n\n/// A lockfile handler that keeps track of the dependencies and their current state.\n#[derive(Debug, Clone, Serialize, Deserialize)]\npub struct Lockfile<'a> {\n    /// A map of the dependencies keyed by relative path to the submodule dir.\n    #[serde(flatten)]\n    deps: DepMap,\n    /// This is optional to handle no-git scencarios.\n    #[serde(skip)]\n    git: Option<&'a Git<'a>>,\n    /// Absolute path to the lockfile.\n    #[serde(skip)]\n    lockfile_path: PathBuf,\n}\n\nimpl<'a> Lockfile<'a> {\n    /// Create a new [`Lockfile`] instance.\n    ///\n    /// `project_root` is the absolute path to the project root.\n    ///\n    /// You will need to call [`Lockfile::read`] or [`Lockfile::sync`] to load the lockfile.\n    pub fn new(project_root: &Path) -> Self {\n        Self { deps: HashMap::default(), git: None, lockfile_path: project_root.join(FOUNDRY_LOCK) }\n    }\n\n    /// Set the git instance to be used for submodule operations.\n    pub fn with_git(mut self, git: &'a Git<'_>) -> Self {\n        self.git = Some(git);\n        self\n    }\n\n    /// Sync the foundry.lock file with the current state of `git submodules`.\n    ///\n    /// If the lockfile and git submodules are out of sync, it returns a [`DepMap`] consisting of\n    /// _only_ the out-of-sync dependencies.\n    ///\n    /// This method writes the lockfile to project root if:\n    /// - The lockfile does not exist.\n    /// - The lockfile is out of sync with the git submodules.\n    pub fn sync(&mut self, lib: &Path) -> Result<Option<DepMap>> {\n        match self.read() {\n            Ok(_) => {}\n            Err(e) if !e.to_string().contains(\"Lockfile not found\") => {\n                return Err(e);\n            }\n            _ => {}\n        }\n\n        if let Some(git) = &self.git {\n            let submodules = git.submodules()?;\n\n            if submodules.is_empty() {\n                trace!(\"No submodules found. Skipping sync.\");\n                return Ok(None);\n            }\n\n            let modules_with_branch = git\n                .read_submodules_with_branch(&Git::root_of(git.root)?, lib.file_name().unwrap())?;\n\n            let mut out_of_sync: DepMap = HashMap::default();\n            for sub in &submodules {\n                let rel_path = sub.path();\n                let rev = sub.rev();\n\n                let entry = self.deps.entry(rel_path.to_path_buf());\n\n                match entry {\n                    Entry::Occupied(e) if e.get().rev() != rev => {\n                        out_of_sync.insert(rel_path.to_path_buf(), e.get().clone());\n                    }\n                    Entry::Vacant(e) => {\n                        // Check if there is branch specified for the submodule at rel_path in\n                        // .gitmodules\n                        let maybe_branch = modules_with_branch.get(rel_path).map(|b| b.to_string());\n\n                        trace!(?maybe_branch, submodule = ?rel_path, \"submodule branch\");\n                        if let Some(branch) = maybe_branch {\n                            let dep_id = DepIdentifier::Branch {\n                                name: branch,\n                                rev: rev.to_string(),\n                                r#override: false,\n                            };\n                            e.insert(dep_id.clone());\n                            out_of_sync.insert(rel_path.to_path_buf(), dep_id);\n                            continue;\n                        }\n\n                        let dep_id = DepIdentifier::Rev { rev: rev.to_string(), r#override: false };\n                        trace!(submodule=?rel_path, ?dep_id, \"submodule dep_id\");\n                        e.insert(dep_id.clone());\n                        out_of_sync.insert(rel_path.to_path_buf(), dep_id);\n                    }\n                    _ => {}\n                }\n            }\n\n            return Ok(if out_of_sync.is_empty() { None } else { Some(out_of_sync) });\n        }\n\n        Ok(None)\n    }\n\n    /// Loads the lockfile from the project root.\n    ///\n    /// Throws an error if the lockfile does not exist.\n    pub fn read(&mut self) -> Result<()> {\n        if !self.lockfile_path.exists() {\n            return Err(eyre::eyre!(\"Lockfile not found at {}\", self.lockfile_path.display()));\n        }\n\n        let lockfile_str = foundry_common::fs::read_to_string(&self.lockfile_path)?;\n\n        self.deps = serde_json::from_str(&lockfile_str)?;\n\n        trace!(lockfile = ?self.deps, \"loaded lockfile\");\n\n        Ok(())\n    }\n\n    /// Writes the lockfile to the project root.\n    pub fn write(&self) -> Result<()> {\n        let ordered_deps: BTreeMap<_, _> = self.deps.clone().into_iter().collect();\n        foundry_common::fs::write_pretty_json_file(&self.lockfile_path, &ordered_deps)?;\n        trace!(at= ?self.lockfile_path, \"wrote lockfile\");\n\n        Ok(())\n    }\n\n    /// Insert a dependency into the lockfile.\n    /// If the dependency already exists, it will be updated.\n    ///\n    /// Note: This does not write the updated lockfile to disk, only inserts the dep in-memory.\n    pub fn insert(&mut self, path: PathBuf, dep_id: DepIdentifier) {\n        self.deps.insert(path, dep_id);\n    }\n\n    /// Get the [`DepIdentifier`] for a submodule at a given path.\n    pub fn get(&self, path: &Path) -> Option<&DepIdentifier> {\n        self.deps.get(path)\n    }\n\n    /// Removes a dependency from the lockfile.\n    ///\n    /// Note: This does not write the updated lockfile to disk, only removes the dep in-memory.\n    pub fn remove(&mut self, path: &Path) -> Option<DepIdentifier> {\n        self.deps.remove(path)\n    }\n\n    /// Override a dependency in the lockfile.\n    ///\n    /// Returns the overridden/previous [`DepIdentifier`].\n    /// This is used in `forge update` to decide whether a dep's tag/branch/rev should be updated.\n    ///\n    /// Throws an error if the dependency is not found in the lockfile.\n    pub fn override_dep(\n        &mut self,\n        dep: &Path,\n        mut new_dep_id: DepIdentifier,\n    ) -> Result<DepIdentifier> {\n        let prev = self\n            .deps\n            .get_mut(dep)\n            .map(|d| {\n                new_dep_id.mark_override();\n                std::mem::replace(d, new_dep_id)\n            })\n            .ok_or_eyre(format!(\"Dependency not found in lockfile: {}\", dep.display()))?;\n\n        Ok(prev)\n    }\n\n    /// Returns the num of dependencies in the lockfile.\n    pub fn len(&self) -> usize {\n        self.deps.len()\n    }\n\n    /// Returns whether the lockfile is empty.\n    pub fn is_empty(&self) -> bool {\n        self.deps.is_empty()\n    }\n\n    /// Returns an iterator over the lockfile.\n    pub fn iter(&self) -> impl Iterator<Item = (&PathBuf, &DepIdentifier)> {\n        self.deps.iter()\n    }\n\n    /// Returns an mutable iterator over the lockfile.\n    pub fn iter_mut(&mut self) -> impl Iterator<Item = (&PathBuf, &mut DepIdentifier)> {\n        self.deps.iter_mut()\n    }\n\n    pub fn exists(&self) -> bool {\n        self.lockfile_path.exists()\n    }\n}\n\n// Implement .iter() for &LockFile\n\n/// Identifies whether a dependency (submodule) is referenced by a branch,\n/// tag or rev (commit hash).\n///\n/// Each enum variant consists of an `r#override` flag which is used in `forge update` to decide\n/// whether to update a dep or not. This flag is skipped during serialization.\n#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]\npub enum DepIdentifier {\n    /// `name` of the branch and the `rev`  it is currently pointing to.\n    /// Running `forge update`, will update the `name` branch to the latest `rev`.\n    #[serde(rename = \"branch\")]\n    Branch {\n        name: String,\n        rev: String,\n        #[serde(skip)]\n        r#override: bool,\n    },\n    /// Release tag `name` and the `rev` it is currently pointing to.\n    /// Running `forge update` does not update the tag/rev.\n    /// Dependency will remain pinned to the existing tag/rev unless r#override like so `forge\n    /// update owner/dep@tag=different_tag`.\n    #[serde(rename = \"tag\")]\n    Tag {\n        name: String,\n        rev: String,\n        #[serde(skip)]\n        r#override: bool,\n    },\n    /// Commit hash `rev` the submodule is currently pointing to.\n    /// Running `forge update` does not update the rev.\n    /// Dependency will remain pinned to the existing rev unless r#override.\n    #[serde(rename = \"rev\", untagged)]\n    Rev {\n        rev: String,\n        #[serde(skip)]\n        r#override: bool,\n    },\n}\n\nimpl DepIdentifier {\n    /// Resolves the [`DepIdentifier`] for a submodule at a given path.\n    /// `lib_path` is the absolute path to the submodule.\n    pub fn resolve_type(git: &Git<'_>, lib_path: &Path, s: &str) -> Result<Self> {\n        trace!(lib_path = ?lib_path, resolving_type = ?s, \"resolving submodule identifier\");\n        // Get the tags for the submodule\n        if git.has_tag(s, lib_path)? {\n            let rev = git.get_rev(s, lib_path)?;\n            return Ok(Self::Tag { name: String::from(s), rev, r#override: false });\n        }\n\n        if git.has_branch(s, lib_path)? {\n            let rev = git.get_rev(s, lib_path)?;\n            return Ok(Self::Branch { name: String::from(s), rev, r#override: false });\n        }\n\n        if git.has_rev(s, lib_path)? {\n            return Ok(Self::Rev { rev: String::from(s), r#override: false });\n        }\n\n        Err(eyre::eyre!(\"Could not resolve tag type for submodule at path {}\", lib_path.display()))\n    }\n\n    /// Get the commit hash of the dependency.\n    pub fn rev(&self) -> &str {\n        match self {\n            Self::Branch { rev, .. } => rev,\n            Self::Tag { rev, .. } => rev,\n            Self::Rev { rev, .. } => rev,\n        }\n    }\n\n    /// Get the name of the dependency.\n    ///\n    /// In case of a Rev, this will return the commit hash.\n    pub fn name(&self) -> &str {\n        match self {\n            Self::Branch { name, .. } => name,\n            Self::Tag { name, .. } => name,\n            Self::Rev { rev, .. } => rev,\n        }\n    }\n\n    /// Get the name/rev to checkout at.\n    pub fn checkout_id(&self) -> &str {\n        match self {\n            Self::Branch { name, .. } => name,\n            Self::Tag { name, .. } => name,\n            Self::Rev { rev, .. } => rev,\n        }\n    }\n\n    /// Marks as dependency as overridden.\n    pub fn mark_override(&mut self) {\n        match self {\n            Self::Branch { r#override, .. } => *r#override = true,\n            Self::Tag { r#override, .. } => *r#override = true,\n            Self::Rev { r#override, .. } => *r#override = true,\n        }\n    }\n\n    /// Returns whether the dependency has been overridden.\n    pub fn overridden(&self) -> bool {\n        match self {\n            Self::Branch { r#override, .. } => *r#override,\n            Self::Tag { r#override, .. } => *r#override,\n            Self::Rev { r#override, .. } => *r#override,\n        }\n    }\n\n    /// Returns whether the dependency is a branch.\n    pub fn is_branch(&self) -> bool {\n        matches!(self, Self::Branch { .. })\n    }\n}\n\nimpl std::fmt::Display for DepIdentifier {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        match self {\n            Self::Branch { name, rev, .. } => write!(f, \"branch={name}@{rev}\"),\n            Self::Tag { name, rev, .. } => write!(f, \"tag={name}@{rev}\"),\n            Self::Rev { rev, .. } => write!(f, \"rev={rev}\"),\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use std::fs;\n    use tempfile::tempdir;\n\n    #[test]\n    fn serde_dep_identifier() {\n        let branch = DepIdentifier::Branch {\n            name: \"main\".to_string(),\n            rev: \"b7954c3e9ce1d487b49489f5800f52f4b77b7351\".to_string(),\n            r#override: false,\n        };\n\n        let tag = DepIdentifier::Tag {\n            name: \"v0.1.0\".to_string(),\n            rev: \"b7954c3e9ce1d487b49489f5800f52f4b77b7351\".to_string(),\n            r#override: false,\n        };\n\n        let rev = DepIdentifier::Rev {\n            rev: \"b7954c3e9ce1d487b49489f5800f52f4b77b7351\".to_string(),\n            r#override: false,\n        };\n\n        let branch_str = serde_json::to_string(&branch).unwrap();\n        let tag_str = serde_json::to_string(&tag).unwrap();\n        let rev_str = serde_json::to_string(&rev).unwrap();\n\n        assert_eq!(\n            branch_str,\n            r#\"{\"branch\":{\"name\":\"main\",\"rev\":\"b7954c3e9ce1d487b49489f5800f52f4b77b7351\"}}\"#\n        );\n        assert_eq!(\n            tag_str,\n            r#\"{\"tag\":{\"name\":\"v0.1.0\",\"rev\":\"b7954c3e9ce1d487b49489f5800f52f4b77b7351\"}}\"#\n        );\n        assert_eq!(rev_str, r#\"{\"rev\":\"b7954c3e9ce1d487b49489f5800f52f4b77b7351\"}\"#);\n\n        let branch_de: DepIdentifier = serde_json::from_str(&branch_str).unwrap();\n        let tag_de: DepIdentifier = serde_json::from_str(&tag_str).unwrap();\n        let rev_de: DepIdentifier = serde_json::from_str(&rev_str).unwrap();\n\n        assert_eq!(branch, branch_de);\n        assert_eq!(tag, tag_de);\n        assert_eq!(rev, rev_de);\n    }\n\n    #[test]\n    fn test_write_ordered_deps() {\n        let dir = tempdir().unwrap();\n        let mut lockfile = Lockfile::new(dir.path());\n        lockfile.insert(\n            PathBuf::from(\"z_dep\"),\n            DepIdentifier::Rev { rev: \"3\".to_string(), r#override: false },\n        );\n        lockfile.insert(\n            PathBuf::from(\"a_dep\"),\n            DepIdentifier::Rev { rev: \"1\".to_string(), r#override: false },\n        );\n        lockfile.insert(\n            PathBuf::from(\"c_dep\"),\n            DepIdentifier::Rev { rev: \"2\".to_string(), r#override: false },\n        );\n        let _ = lockfile.write();\n        let contents = fs::read_to_string(lockfile.lockfile_path).unwrap();\n        let expected = r#\"{\n  \"a_dep\": {\n    \"rev\": \"1\"\n  },\n  \"c_dep\": {\n    \"rev\": \"2\"\n  },\n  \"z_dep\": {\n    \"rev\": \"3\"\n  }\n}\"#;\n        assert_eq!(contents.trim(), expected.trim());\n\n        let mut lockfile = Lockfile::new(dir.path());\n        lockfile.read().unwrap();\n        lockfile.insert(\n            PathBuf::from(\"x_dep\"),\n            DepIdentifier::Rev { rev: \"4\".to_string(), r#override: false },\n        );\n        let _ = lockfile.write();\n        let contents = fs::read_to_string(lockfile.lockfile_path).unwrap();\n        let expected = r#\"{\n  \"a_dep\": {\n    \"rev\": \"1\"\n  },\n  \"c_dep\": {\n    \"rev\": \"2\"\n  },\n  \"x_dep\": {\n    \"rev\": \"4\"\n  },\n  \"z_dep\": {\n    \"rev\": \"3\"\n  }\n}\"#;\n        assert_eq!(contents.trim(), expected.trim());\n    }\n}\n"
  },
  {
    "path": "crates/forge/src/multi_runner.rs",
    "content": "//! Forge test runner for multiple contracts.\n\nuse crate::{\n    ContractRunner, TestFilter, progress::TestsProgress, result::SuiteResult,\n    runner::LIBRARY_DEPLOYER,\n};\nuse alloy_json_abi::{Function, JsonAbi};\nuse alloy_primitives::{Address, Bytes, U256};\nuse eyre::Result;\nuse foundry_cli::opts::configure_pcx_from_compile_output;\nuse foundry_common::{\n    ContractsByArtifact, ContractsByArtifactBuilder, TestFunctionExt, get_contract_name,\n};\nuse foundry_compilers::{\n    Artifact, ArtifactId, Compiler, ProjectCompileOutput,\n    artifacts::{Contract, Libraries},\n};\nuse foundry_config::{Config, InlineConfig};\nuse foundry_evm::{\n    EvmEnv,\n    backend::Backend,\n    decode::RevertDecoder,\n    executors::{EarlyExit, Executor, ExecutorBuilder},\n    fork::CreateFork,\n    fuzz::strategies::LiteralsDictionary,\n    inspectors::CheatsConfig,\n    opts::EvmOpts,\n    traces::{InternalTraceMode, TraceMode},\n};\nuse foundry_evm_networks::NetworkConfigs;\nuse foundry_linking::{LinkOutput, Linker};\nuse rayon::prelude::*;\nuse revm::{context::TxEnv, primitives::hardfork::SpecId};\nuse std::{\n    borrow::Borrow,\n    collections::BTreeMap,\n    path::Path,\n    sync::{Arc, mpsc},\n    time::Instant,\n};\n\n#[derive(Debug, Clone)]\npub struct TestContract {\n    pub abi: JsonAbi,\n    pub bytecode: Bytes,\n}\n\npub type DeployableContracts = BTreeMap<ArtifactId, TestContract>;\n\n/// A multi contract runner receives a set of contracts deployed in an EVM instance and proceeds\n/// to run all test functions in these contracts.\n#[derive(Clone, Debug)]\npub struct MultiContractRunner {\n    /// Mapping of contract name to JsonAbi, creation bytecode and library bytecode which\n    /// needs to be deployed & linked against\n    pub contracts: DeployableContracts,\n    /// Known contracts linked with computed library addresses.\n    pub known_contracts: ContractsByArtifact,\n    /// Revert decoder. Contains all known errors and their selectors.\n    pub revert_decoder: RevertDecoder,\n    /// Libraries to deploy.\n    pub libs_to_deploy: Vec<Bytes>,\n    /// Library addresses used to link contracts.\n    pub libraries: Libraries,\n    /// Solar compiler instance, to grant syntactic and semantic analysis capabilities\n    pub analysis: Arc<solar::sema::Compiler>,\n    /// Literals dictionary for fuzzing.\n    pub fuzz_literals: LiteralsDictionary,\n\n    /// The fork to use at launch\n    pub fork: Option<CreateFork>,\n\n    /// The base configuration for the test runner.\n    pub tcfg: TestRunnerConfig,\n}\n\nimpl std::ops::Deref for MultiContractRunner {\n    type Target = TestRunnerConfig;\n\n    fn deref(&self) -> &Self::Target {\n        &self.tcfg\n    }\n}\n\nimpl std::ops::DerefMut for MultiContractRunner {\n    fn deref_mut(&mut self) -> &mut Self::Target {\n        &mut self.tcfg\n    }\n}\n\nimpl MultiContractRunner {\n    /// Returns an iterator over all contracts that match the filter.\n    pub fn matching_contracts<'a: 'b, 'b>(\n        &'a self,\n        filter: &'b dyn TestFilter,\n    ) -> impl Iterator<Item = (&'a ArtifactId, &'a TestContract)> + 'b {\n        self.contracts.iter().filter(|&(id, c)| matches_artifact(filter, id, &c.abi))\n    }\n\n    /// Returns an iterator over all test functions that match the filter.\n    pub fn matching_test_functions<'a: 'b, 'b>(\n        &'a self,\n        filter: &'b dyn TestFilter,\n    ) -> impl Iterator<Item = &'a Function> + 'b {\n        self.matching_contracts(filter)\n            .flat_map(|(_, c)| c.abi.functions())\n            .filter(|func| filter.matches_test_function(func))\n    }\n\n    /// Returns an iterator over all test functions in contracts that match the filter.\n    pub fn all_test_functions<'a: 'b, 'b>(\n        &'a self,\n        filter: &'b dyn TestFilter,\n    ) -> impl Iterator<Item = &'a Function> + 'b {\n        self.contracts\n            .iter()\n            .filter(|(id, _)| filter.matches_path(&id.source) && filter.matches_contract(&id.name))\n            .flat_map(|(_, c)| c.abi.functions())\n            .filter(|func| func.is_any_test())\n    }\n\n    /// Returns all matching tests grouped by contract grouped by file (file -> (contract -> tests))\n    pub fn list(&self, filter: &dyn TestFilter) -> BTreeMap<String, BTreeMap<String, Vec<String>>> {\n        self.matching_contracts(filter)\n            .map(|(id, c)| {\n                let source = id.source.as_path().display().to_string();\n                let name = id.name.clone();\n                let tests = c\n                    .abi\n                    .functions()\n                    .filter(|func| filter.matches_test_function(func))\n                    .map(|func| func.name.clone())\n                    .collect::<Vec<_>>();\n                (source, name, tests)\n            })\n            .fold(BTreeMap::new(), |mut acc, (source, name, tests)| {\n                acc.entry(source).or_default().insert(name, tests);\n                acc\n            })\n    }\n\n    /// Executes _all_ tests that match the given `filter`.\n    ///\n    /// The same as [`test`](Self::test), but returns the results instead of streaming them.\n    ///\n    /// Note that this method returns only when all tests have been executed.\n    pub fn test_collect(\n        &mut self,\n        filter: &dyn TestFilter,\n    ) -> Result<BTreeMap<String, SuiteResult>> {\n        Ok(self.test_iter(filter)?.collect())\n    }\n\n    /// Executes _all_ tests that match the given `filter`.\n    ///\n    /// The same as [`test`](Self::test), but returns the results instead of streaming them.\n    ///\n    /// Note that this method returns only when all tests have been executed.\n    pub fn test_iter(\n        &mut self,\n        filter: &dyn TestFilter,\n    ) -> Result<impl Iterator<Item = (String, SuiteResult)>> {\n        let (tx, rx) = mpsc::channel();\n        self.test(filter, tx, false)?;\n        Ok(rx.into_iter())\n    }\n\n    /// Executes _all_ tests that match the given `filter`.\n    ///\n    /// This will create the runtime based on the configured `evm` ops and create the `Backend`\n    /// before executing all contracts and their tests in _parallel_.\n    ///\n    /// Each Executor gets its own instance of the `Backend`.\n    pub fn test(\n        &mut self,\n        filter: &dyn TestFilter,\n        tx: mpsc::Sender<(String, SuiteResult)>,\n        show_progress: bool,\n    ) -> Result<()> {\n        let tokio_handle = tokio::runtime::Handle::current();\n        trace!(\"running all tests\");\n\n        // The DB backend that serves all the data.\n        let db = Backend::spawn(self.fork.take())?;\n\n        let find_timer = Instant::now();\n        let contracts = self.matching_contracts(filter).collect::<Vec<_>>();\n        let find_time = find_timer.elapsed();\n        debug!(\n            \"Found {} test contracts out of {} in {:?}\",\n            contracts.len(),\n            self.contracts.len(),\n            find_time,\n        );\n\n        if show_progress {\n            let tests_progress = TestsProgress::new(contracts.len(), rayon::current_num_threads());\n            // Collect test suite results to stream at the end of test run.\n            let results: Vec<(String, SuiteResult)> = contracts\n                .par_iter()\n                .map(|&(id, contract)| {\n                    let _guard = tokio_handle.enter();\n                    tests_progress.inner.lock().start_suite_progress(&id.identifier());\n\n                    let result = self.run_test_suite(\n                        id,\n                        contract,\n                        &db,\n                        filter,\n                        &tokio_handle,\n                        Some(&tests_progress),\n                    );\n\n                    tests_progress\n                        .inner\n                        .lock()\n                        .end_suite_progress(&id.identifier(), result.summary());\n\n                    (id.identifier(), result)\n                })\n                .collect();\n\n            tests_progress.inner.lock().clear();\n\n            results.iter().for_each(|result| {\n                let _ = tx.send(result.to_owned());\n            });\n        } else {\n            contracts.par_iter().for_each(|&(id, contract)| {\n                let _guard = tokio_handle.enter();\n                let result = self.run_test_suite(id, contract, &db, filter, &tokio_handle, None);\n                let _ = tx.send((id.identifier(), result));\n            })\n        }\n\n        Ok(())\n    }\n\n    fn run_test_suite(\n        &self,\n        artifact_id: &ArtifactId,\n        contract: &TestContract,\n        db: &Backend,\n        filter: &dyn TestFilter,\n        tokio_handle: &tokio::runtime::Handle,\n        progress: Option<&TestsProgress>,\n    ) -> SuiteResult {\n        let identifier = artifact_id.identifier();\n        let mut span_name = identifier.as_str();\n\n        if !enabled!(tracing::Level::TRACE) {\n            span_name = get_contract_name(&identifier);\n        }\n        let span = debug_span!(\"suite\", name = %span_name);\n        let span_local = span.clone();\n        let _guard = span_local.enter();\n\n        debug!(\"start executing all tests in contract\");\n\n        let executor = self.tcfg.executor(\n            self.known_contracts.clone(),\n            self.analysis.clone(),\n            artifact_id,\n            db.clone(),\n        );\n        let runner = ContractRunner::new(\n            &identifier,\n            contract,\n            executor,\n            progress,\n            tokio_handle,\n            span,\n            self,\n        );\n        let r = runner.run_tests(filter);\n\n        debug!(duration=?r.duration, \"executed all tests in contract\");\n\n        r\n    }\n}\n\n/// Configuration for the test runner.\n///\n/// This is modified after instantiation through inline config.\n#[derive(Clone, Debug)]\npub struct TestRunnerConfig {\n    /// Project config.\n    pub config: Arc<Config>,\n    /// Inline configuration.\n    pub inline_config: Arc<InlineConfig>,\n\n    /// EVM configuration.\n    pub evm_opts: EvmOpts,\n    /// EVM environment.\n    pub evm_env: EvmEnv,\n    /// Transaction environment.\n    pub tx_env: TxEnv,\n    /// EVM version.\n    pub spec_id: SpecId,\n    /// The address which will be used to deploy the initial contracts and send all transactions.\n    pub sender: Address,\n\n    /// Whether to collect line coverage info\n    pub line_coverage: bool,\n    /// Whether to collect debug info\n    pub debug: bool,\n    /// Whether to enable steps tracking in the tracer.\n    pub decode_internal: InternalTraceMode,\n    /// Whether to enable call isolation.\n    pub isolation: bool,\n    /// Networks with enabled features.\n    pub networks: NetworkConfigs,\n    /// Whether to exit early on test failure or if test run interrupted.\n    pub early_exit: EarlyExit,\n}\n\nimpl TestRunnerConfig {\n    /// Reconfigures all fields using the given `config`.\n    /// This is for example used to override the configuration with inline config.\n    pub fn reconfigure_with(&mut self, config: Arc<Config>) {\n        debug_assert!(!Arc::ptr_eq(&self.config, &config));\n\n        self.spec_id = config.evm_spec_id();\n        self.sender = config.sender;\n        self.networks = config.networks;\n        self.isolation = config.isolate;\n\n        // Specific to Forge, not present in config.\n        // self.line_coverage = N/A;\n        // self.debug = N/A;\n        // self.decode_internal = N/A;\n\n        // TODO: self.evm_opts\n        self.evm_opts.always_use_create_2_factory = config.always_use_create_2_factory;\n\n        // TODO: self.env\n\n        self.config = config;\n    }\n\n    /// Configures the given executor with this configuration.\n    pub fn configure_executor(&self, executor: &mut Executor) {\n        // TODO: See above\n\n        let inspector = executor.inspector_mut();\n        // inspector.set_env(&self.env);\n        if let Some(cheatcodes) = inspector.cheatcodes.as_mut() {\n            cheatcodes.config =\n                Arc::new(cheatcodes.config.clone_with(&self.config, self.evm_opts.clone()));\n        }\n        inspector.tracing(self.trace_mode());\n        inspector.collect_line_coverage(self.line_coverage);\n        inspector.enable_isolation(self.isolation);\n        inspector.networks(self.networks);\n        // inspector.set_create2_deployer(self.evm_opts.create2_deployer);\n\n        // executor.env_mut().clone_from(&self.env);\n        executor.set_spec_id(self.spec_id);\n        // executor.set_gas_limit(self.evm_opts.gas_limit());\n        executor.set_legacy_assertions(self.config.legacy_assertions);\n    }\n\n    /// Creates a new executor with this configuration.\n    pub fn executor(\n        &self,\n        known_contracts: ContractsByArtifact,\n        analysis: Arc<solar::sema::Compiler>,\n        artifact_id: &ArtifactId,\n        db: Backend,\n    ) -> Executor {\n        let cheats_config = Arc::new(CheatsConfig::new(\n            &self.config,\n            self.evm_opts.clone(),\n            Some(known_contracts),\n            Some(artifact_id.clone()),\n        ));\n        ExecutorBuilder::new()\n            .inspectors(|stack| {\n                stack\n                    .logs(self.config.live_logs)\n                    .cheatcodes(cheats_config)\n                    .trace_mode(self.trace_mode())\n                    .line_coverage(self.line_coverage)\n                    .enable_isolation(self.isolation)\n                    .networks(self.networks)\n                    .create2_deployer(self.evm_opts.create2_deployer)\n                    .set_analysis(analysis)\n            })\n            .spec_id(self.spec_id)\n            .gas_limit(self.evm_opts.gas_limit())\n            .legacy_assertions(self.config.legacy_assertions)\n            .build(self.evm_env.clone(), self.tx_env.clone(), db)\n    }\n\n    fn trace_mode(&self) -> TraceMode {\n        TraceMode::default()\n            .with_debug(self.debug)\n            .with_decode_internal(self.decode_internal)\n            .with_verbosity(self.evm_opts.verbosity)\n    }\n}\n\n/// Builder used for instantiating the multi-contract runner\n#[derive(Clone)]\n#[must_use = \"builders do nothing unless you call `build` on them\"]\npub struct MultiContractRunnerBuilder {\n    /// The address which will be used to deploy the initial contracts and send all\n    /// transactions\n    pub sender: Option<Address>,\n    /// The initial balance for each one of the deployed smart contracts\n    pub initial_balance: U256,\n    /// The EVM spec to use\n    pub evm_spec: Option<SpecId>,\n    /// The fork to use at launch\n    pub fork: Option<CreateFork>,\n    /// Project config.\n    pub config: Arc<Config>,\n    /// Whether or not to collect line coverage info\n    pub line_coverage: bool,\n    /// Whether or not to collect debug info\n    pub debug: bool,\n    /// Whether to enable steps tracking in the tracer.\n    pub decode_internal: InternalTraceMode,\n    /// Whether to enable call isolation\n    pub isolation: bool,\n    /// Networks with enabled features.\n    pub networks: NetworkConfigs,\n    /// Whether to exit early on test failure.\n    pub fail_fast: bool,\n}\n\nimpl MultiContractRunnerBuilder {\n    pub fn new(config: Arc<Config>) -> Self {\n        Self {\n            config,\n            sender: Default::default(),\n            initial_balance: Default::default(),\n            evm_spec: Default::default(),\n            fork: Default::default(),\n            line_coverage: Default::default(),\n            debug: Default::default(),\n            isolation: Default::default(),\n            decode_internal: Default::default(),\n            networks: Default::default(),\n            fail_fast: false,\n        }\n    }\n\n    pub fn sender(mut self, sender: Address) -> Self {\n        self.sender = Some(sender);\n        self\n    }\n\n    pub fn initial_balance(mut self, initial_balance: U256) -> Self {\n        self.initial_balance = initial_balance;\n        self\n    }\n\n    pub fn evm_spec(mut self, spec: SpecId) -> Self {\n        self.evm_spec = Some(spec);\n        self\n    }\n\n    pub fn with_fork(mut self, fork: Option<CreateFork>) -> Self {\n        self.fork = fork;\n        self\n    }\n\n    pub fn set_coverage(mut self, enable: bool) -> Self {\n        self.line_coverage = enable;\n        self\n    }\n\n    pub fn set_debug(mut self, enable: bool) -> Self {\n        self.debug = enable;\n        self\n    }\n\n    pub fn set_decode_internal(mut self, mode: InternalTraceMode) -> Self {\n        self.decode_internal = mode;\n        self\n    }\n\n    pub fn fail_fast(mut self, fail_fast: bool) -> Self {\n        self.fail_fast = fail_fast;\n        self\n    }\n\n    pub fn enable_isolation(mut self, enable: bool) -> Self {\n        self.isolation = enable;\n        self\n    }\n\n    pub fn networks(mut self, networks: NetworkConfigs) -> Self {\n        self.networks = networks;\n        self\n    }\n\n    /// Given an EVM, proceeds to return a runner which is able to execute all tests\n    /// against that evm\n    pub fn build<C: Compiler<CompilerContract = Contract>>(\n        self,\n        output: &ProjectCompileOutput,\n        evm_env: EvmEnv,\n        tx_env: TxEnv,\n        evm_opts: EvmOpts,\n    ) -> Result<MultiContractRunner> {\n        let root = &self.config.root;\n        let contracts = output\n            .artifact_ids()\n            .map(|(id, v)| (id.with_stripped_file_prefixes(root), v))\n            .collect();\n        let linker = Linker::new(root, contracts);\n\n        // Build revert decoder from ABIs of all artifacts.\n        let abis = linker\n            .contracts\n            .values()\n            .filter_map(|contract| contract.abi.as_ref().map(|abi| abi.borrow()));\n        let revert_decoder = RevertDecoder::new().with_abis(abis);\n\n        let LinkOutput { libraries, libs_to_deploy } = linker.link_with_nonce_or_address(\n            Default::default(),\n            LIBRARY_DEPLOYER,\n            0,\n            linker.contracts.keys(),\n        )?;\n\n        let linked_contracts = linker.get_linked_artifacts_cow(&libraries)?;\n\n        // Create a mapping of name => (abi, deployment code, Vec<library deployment code>)\n        let mut deployable_contracts = DeployableContracts::default();\n\n        for (id, contract) in linked_contracts.iter() {\n            let Some(abi) = contract.abi.as_ref() else { continue };\n\n            // if it's a test, link it and add to deployable contracts\n            if abi.constructor.as_ref().map(|c| c.inputs.is_empty()).unwrap_or(true)\n                && abi.functions().any(|func| func.name.is_any_test())\n            {\n                linker.ensure_linked(contract, id)?;\n\n                let Some(bytecode) =\n                    contract.get_bytecode_bytes().map(|b| b.into_owned()).filter(|b| !b.is_empty())\n                else {\n                    continue;\n                };\n\n                deployable_contracts\n                    .insert(id.clone(), TestContract { abi: abi.clone().into_owned(), bytecode });\n            }\n        }\n\n        // Create known contracts from linked contracts and storage layout information (if any).\n        let known_contracts =\n            ContractsByArtifactBuilder::new(linked_contracts).with_output(output, root).build();\n\n        // Initialize and configure the solar compiler.\n        let mut analysis = solar::sema::Compiler::new(\n            solar::interface::Session::builder().with_stderr_emitter().build(),\n        );\n        let dcx = analysis.dcx_mut();\n        dcx.set_emitter(Box::new(\n            solar::interface::diagnostics::HumanEmitter::stderr(Default::default())\n                .source_map(Some(dcx.source_map().unwrap())),\n        ));\n        dcx.set_flags_mut(|f| f.track_diagnostics = false);\n\n        // Populate solar's global context by parsing and lowering the sources.\n        let files: Vec<_> =\n            output.output().sources.as_ref().keys().map(|path| path.to_path_buf()).collect();\n\n        analysis.enter_mut(|compiler| -> Result<()> {\n            let mut pcx = compiler.parse();\n            configure_pcx_from_compile_output(\n                &mut pcx,\n                &self.config,\n                output,\n                if files.is_empty() { None } else { Some(&files) },\n            )?;\n            pcx.parse();\n            let _ = compiler.lower_asts();\n            Ok(())\n        })?;\n\n        let analysis = Arc::new(analysis);\n        let fuzz_literals = LiteralsDictionary::new(\n            Some(analysis.clone()),\n            Some(self.config.project_paths()),\n            self.config.fuzz.dictionary.max_fuzz_dictionary_literals,\n        );\n\n        Ok(MultiContractRunner {\n            contracts: deployable_contracts,\n            revert_decoder,\n            known_contracts,\n            libs_to_deploy,\n            libraries,\n            analysis,\n            fuzz_literals,\n\n            tcfg: TestRunnerConfig {\n                evm_opts,\n                evm_env,\n                tx_env,\n                spec_id: self.evm_spec.unwrap_or_else(|| self.config.evm_spec_id()),\n                sender: self.sender.unwrap_or(self.config.sender),\n                line_coverage: self.line_coverage,\n                debug: self.debug,\n                decode_internal: self.decode_internal,\n                inline_config: Arc::new(InlineConfig::new_parsed(output, &self.config)?),\n                isolation: self.isolation,\n                networks: self.networks,\n                early_exit: EarlyExit::new(self.fail_fast),\n                config: self.config,\n            },\n\n            fork: self.fork,\n        })\n    }\n}\n\npub fn matches_artifact(filter: &dyn TestFilter, id: &ArtifactId, abi: &JsonAbi) -> bool {\n    matches_contract(filter, &id.source, &id.name, abi.functions())\n}\n\npub(crate) fn matches_contract(\n    filter: &dyn TestFilter,\n    path: &Path,\n    contract_name: &str,\n    functions: impl IntoIterator<Item = impl std::borrow::Borrow<Function>>,\n) -> bool {\n    (filter.matches_path(path) && filter.matches_contract(contract_name))\n        && functions.into_iter().any(|func| filter.matches_test_function(func.borrow()))\n}\n"
  },
  {
    "path": "crates/forge/src/opts.rs",
    "content": "use crate::cmd::{\n    bind::BindArgs, bind_json, build::BuildArgs, cache::CacheArgs, clone::CloneArgs,\n    compiler::CompilerArgs, config, coverage, create::CreateArgs, doc::DocArgs, eip712, flatten,\n    fmt::FmtArgs, geiger, generate, init::InitArgs, inspect, install::InstallArgs, lint::LintArgs,\n    remappings::RemappingArgs, remove::RemoveArgs, selectors::SelectorsSubcommands, snapshot,\n    soldeer, test, tree, update,\n};\nuse clap::{Parser, Subcommand, ValueHint};\nuse forge_script::ScriptArgs;\nuse forge_verify::{VerifyArgs, VerifyBytecodeArgs, VerifyCheckArgs};\nuse foundry_cli::opts::GlobalArgs;\nuse foundry_common::version::{LONG_VERSION, SHORT_VERSION};\nuse std::path::PathBuf;\n\n/// Build, test, fuzz, debug and deploy Solidity contracts.\n#[derive(Parser)]\n#[command(\n    name = \"forge\",\n    version = SHORT_VERSION,\n    long_version = LONG_VERSION,\n    after_help = \"Find more information in the book: https://getfoundry.sh/forge/overview\",\n    next_display_order = None,\n)]\npub struct Forge {\n    /// Include the global arguments.\n    #[command(flatten)]\n    pub global: GlobalArgs,\n\n    #[command(subcommand)]\n    pub cmd: ForgeSubcommand,\n}\n\n#[derive(Subcommand)]\npub enum ForgeSubcommand {\n    /// Run the project's tests.\n    #[command(visible_alias = \"t\")]\n    Test(test::TestArgs),\n\n    /// Run a smart contract as a script, building transactions that can be sent onchain.\n    Script(ScriptArgs),\n\n    /// Generate coverage reports.\n    Coverage(coverage::CoverageArgs),\n\n    /// Generate Rust bindings for smart contracts.\n    #[command(alias = \"bi\")]\n    Bind(BindArgs),\n\n    /// Build the project's smart contracts.\n    #[command(visible_aliases = [\"b\", \"compile\"])]\n    Build(BuildArgs),\n\n    /// Clone a contract from Etherscan.\n    Clone(CloneArgs),\n\n    /// Update one or multiple dependencies.\n    ///\n    /// If no arguments are provided, then all dependencies are updated.\n    #[command(visible_alias = \"u\")]\n    Update(update::UpdateArgs),\n\n    /// Install one or multiple dependencies.\n    ///\n    /// If no arguments are provided, then existing dependencies will be installed.\n    #[command(visible_aliases = [\"i\", \"add\"])]\n    Install(InstallArgs),\n\n    /// Remove one or multiple dependencies.\n    #[command(visible_alias = \"rm\")]\n    Remove(RemoveArgs),\n\n    /// Get the automatically inferred remappings for the project.\n    #[command(visible_alias = \"re\")]\n    Remappings(RemappingArgs),\n\n    /// Verify smart contracts on Etherscan.\n    #[command(visible_alias = \"v\")]\n    VerifyContract(VerifyArgs),\n\n    /// Check verification status on Etherscan.\n    #[command(visible_alias = \"vc\")]\n    VerifyCheck(VerifyCheckArgs),\n\n    /// Verify the deployed bytecode against its source on Etherscan.\n    #[command(visible_alias = \"vb\")]\n    VerifyBytecode(VerifyBytecodeArgs),\n\n    /// Deploy a smart contract.\n    #[command(visible_alias = \"c\")]\n    Create(CreateArgs),\n\n    /// Create a new Forge project.\n    Init(InitArgs),\n\n    /// Generate shell completions script.\n    #[command(visible_alias = \"com\")]\n    Completions {\n        #[arg(value_enum)]\n        shell: foundry_cli::clap::Shell,\n    },\n\n    /// Remove the build artifacts and cache directories.\n    #[command(visible_alias = \"cl\")]\n    Clean {\n        /// The project's root path.\n        ///\n        /// By default root of the Git repository, if in one,\n        /// or the current working directory.\n        #[arg(long, value_hint = ValueHint::DirPath, value_name = \"PATH\")]\n        root: Option<PathBuf>,\n    },\n\n    /// Manage the Foundry cache.\n    Cache(CacheArgs),\n\n    /// Create a gas snapshot of each test's gas usage.\n    #[command(visible_alias = \"s\")]\n    Snapshot(snapshot::GasSnapshotArgs),\n\n    /// Display the current config.\n    #[command(visible_alias = \"co\")]\n    Config(config::ConfigArgs),\n\n    /// Flatten a source file and all of its imports into one file.\n    #[command(visible_alias = \"f\")]\n    Flatten(flatten::FlattenArgs),\n\n    /// Format Solidity source files.\n    Fmt(FmtArgs),\n\n    /// Lint Solidity source files\n    #[command(visible_alias = \"l\")]\n    Lint(LintArgs),\n\n    /// Get specialized information about a smart contract.\n    #[command(visible_alias = \"in\")]\n    Inspect(inspect::InspectArgs),\n\n    /// Display a tree visualization of the project's dependency graph.\n    #[command(visible_alias = \"tr\")]\n    Tree(tree::TreeArgs),\n\n    /// DEPRECATED: Detects usage of unsafe cheat codes in a project and its dependencies.\n    ///\n    /// This is an alias for `forge lint --only-lint unsafe-cheatcode`.\n    Geiger(geiger::GeigerArgs),\n\n    /// Generate documentation for the project.\n    Doc(DocArgs),\n\n    /// Function selector utilities.\n    #[command(visible_alias = \"se\")]\n    Selectors {\n        #[command(subcommand)]\n        command: SelectorsSubcommands,\n    },\n\n    /// Generate scaffold files.\n    #[command(hide = true)]\n    Generate(generate::GenerateArgs),\n\n    /// Compiler utilities.\n    Compiler(CompilerArgs),\n\n    /// Soldeer dependency manager.\n    Soldeer(soldeer::SoldeerArgs),\n\n    /// Generate EIP-712 struct encodings for structs from a given file.\n    Eip712(eip712::Eip712Args),\n\n    /// Generate bindings for serialization/deserialization of project structs via JSON cheatcodes.\n    BindJson(bind_json::BindJsonArgs),\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use clap::CommandFactory;\n\n    #[test]\n    fn verify_cli() {\n        Forge::command().debug_assert();\n    }\n}\n"
  },
  {
    "path": "crates/forge/src/progress.rs",
    "content": "use alloy_primitives::map::HashMap;\nuse chrono::Utc;\nuse indicatif::{MultiProgress, ProgressBar};\nuse parking_lot::Mutex;\nuse std::{sync::Arc, time::Duration};\n\n/// State of [ProgressBar]s displayed for the given test run.\n/// Shows progress of all test suites matching filter.\n/// For each test within the test suite an individual progress bar is displayed.\n/// When a test suite completes, their progress is removed from overall progress and result summary\n/// is displayed.\n#[derive(Debug)]\npub struct TestsProgressState {\n    /// Main [MultiProgress] instance showing progress for all test suites.\n    multi: MultiProgress,\n    /// Progress bar counting completed / remaining test suites.\n    overall_progress: ProgressBar,\n    /// Individual test suites progress.\n    suites_progress: HashMap<String, ProgressBar>,\n}\n\nimpl TestsProgressState {\n    // Creates overall tests progress state.\n    pub fn new(suites_len: usize, threads_no: usize) -> Self {\n        let multi = MultiProgress::new();\n        let overall_progress = multi.add(ProgressBar::new(suites_len as u64));\n        overall_progress.set_style(\n            indicatif::ProgressStyle::with_template(\"{bar:40.cyan/blue} {pos:>7}/{len:7} {msg}\")\n                .unwrap()\n                .progress_chars(\"##-\"),\n        );\n        overall_progress.set_message(format!(\"completed (with {} threads)\", threads_no as u64));\n        Self { multi, overall_progress, suites_progress: HashMap::default() }\n    }\n\n    /// Creates new test suite progress and add it to overall progress.\n    pub fn start_suite_progress(&mut self, suite_name: &String) {\n        let suite_progress = self.multi.add(ProgressBar::new_spinner());\n        suite_progress.set_style(\n            indicatif::ProgressStyle::with_template(\"{spinner} {wide_msg:.bold.dim}\")\n                .unwrap()\n                .tick_chars(\"⠁⠂⠄⡀⢀⠠⠐⠈ \"),\n        );\n        suite_progress.set_message(format!(\"{suite_name} \"));\n        suite_progress.enable_steady_tick(Duration::from_millis(100));\n        self.suites_progress.insert(suite_name.to_owned(), suite_progress);\n    }\n\n    /// Prints suite result summary and removes it from overall progress.\n    pub fn end_suite_progress(&mut self, suite_name: &String, result_summary: String) {\n        if let Some(suite_progress) = self.suites_progress.remove(suite_name) {\n            self.multi.suspend(|| {\n                let _ = sh_println!(\"{suite_name}\\n  ↪ {result_summary}\");\n            });\n            suite_progress.finish_and_clear();\n            // Increment test progress bar to reflect completed test suite.\n            self.overall_progress.inc(1);\n        }\n    }\n\n    /// Creates progress entry for fuzz tests.\n    /// Set the prefix and total number of runs. Message is updated during execution with current\n    /// phase. Test progress is placed under test suite progress entry so all tests within suite\n    /// are grouped.\n    pub fn start_fuzz_progress(\n        &mut self,\n        suite_name: &str,\n        test_name: &String,\n        timeout: Option<u32>,\n        runs: u32,\n    ) -> Option<ProgressBar> {\n        if let Some(suite_progress) = self.suites_progress.get(suite_name) {\n            let fuzz_progress =\n                self.multi.insert_after(suite_progress, ProgressBar::new(runs as u64));\n            let template = if let Some(timeout) = timeout {\n                let ends_at = (Utc::now() + chrono::Duration::seconds(timeout.into()))\n                    .format(\"%H:%M:%S %Y-%m-%d\")\n                    .to_string();\n                format!(\"    ↪ {{prefix:.bold.dim}}: [{{pos}}] Runs, ends at {ends_at} UTC {{msg}}\")\n            } else {\n                \"    ↪ {prefix:.bold.dim}: [{pos}/{len}] Runs {msg}\".to_string()\n            };\n            fuzz_progress.set_style(\n                indicatif::ProgressStyle::with_template(&template).unwrap().tick_chars(\"⠁⠂⠄⡀⢀⠠⠐⠈ \"),\n            );\n            fuzz_progress.set_prefix(test_name.to_string());\n            Some(fuzz_progress)\n        } else {\n            None\n        }\n    }\n\n    /// Removes overall test progress.\n    pub fn clear(&mut self) {\n        self.multi.clear().unwrap();\n    }\n}\n\n/// Cloneable wrapper around [TestsProgressState].\n#[derive(Debug, Clone)]\npub struct TestsProgress {\n    pub inner: Arc<Mutex<TestsProgressState>>,\n}\n\nimpl TestsProgress {\n    pub fn new(suites_len: usize, threads_no: usize) -> Self {\n        Self { inner: Arc::new(Mutex::new(TestsProgressState::new(suites_len, threads_no))) }\n    }\n}\n\n/// Helper function for creating fuzz test progress bar.\npub fn start_fuzz_progress(\n    tests_progress: Option<&TestsProgress>,\n    suite_name: &str,\n    test_name: &String,\n    timeout: Option<u32>,\n    runs: u32,\n) -> Option<ProgressBar> {\n    if let Some(progress) = tests_progress {\n        progress.inner.lock().start_fuzz_progress(suite_name, test_name, timeout, runs)\n    } else {\n        None\n    }\n}\n"
  },
  {
    "path": "crates/forge/src/result.rs",
    "content": "//! Test outcomes.\n\nuse crate::{\n    MultiContractRunner,\n    fuzz::{BaseCounterExample, FuzzedCases},\n    gas_report::GasReport,\n};\nuse alloy_primitives::{\n    Address, I256, Log, U256,\n    map::{AddressHashMap, HashMap},\n};\nuse eyre::Report;\nuse foundry_common::{get_contract_name, get_file_name, shell};\nuse foundry_evm::{\n    core::Breakpoints,\n    coverage::HitMaps,\n    decode::SkipReason,\n    executors::{RawCallResult, invariant::InvariantMetrics},\n    fuzz::{CounterExample, FuzzCase, FuzzFixtures, FuzzTestResult},\n    traces::{CallTraceArena, CallTraceDecoder, TraceKind, Traces},\n};\nuse serde::{Deserialize, Serialize};\nuse std::{\n    collections::{BTreeMap, HashMap as Map},\n    fmt::{self, Write},\n    time::Duration,\n};\nuse yansi::Paint;\n\n/// The aggregated result of a test run.\n#[derive(Clone, Debug)]\npub struct TestOutcome {\n    /// The results of all test suites by their identifier (`path:contract_name`).\n    ///\n    /// Essentially `identifier => signature => result`.\n    pub results: BTreeMap<String, SuiteResult>,\n    /// Whether to allow test failures without failing the entire test run.\n    pub allow_failure: bool,\n    /// The decoder used to decode traces and logs.\n    ///\n    /// This is `None` if traces and logs were not decoded.\n    ///\n    /// Note that `Address` fields only contain the last executed test case's data.\n    pub last_run_decoder: Option<CallTraceDecoder>,\n    /// The gas report, if requested.\n    pub gas_report: Option<GasReport>,\n    /// The runner used to execute the tests.\n    pub runner: Option<MultiContractRunner>,\n    /// The fuzz seed used for the test run.\n    pub fuzz_seed: Option<U256>,\n}\n\nimpl TestOutcome {\n    /// Creates a new test outcome with the given results.\n    pub fn new(\n        runner: Option<MultiContractRunner>,\n        results: BTreeMap<String, SuiteResult>,\n        allow_failure: bool,\n        fuzz_seed: Option<U256>,\n    ) -> Self {\n        Self { results, allow_failure, last_run_decoder: None, gas_report: None, runner, fuzz_seed }\n    }\n\n    /// Creates a new empty test outcome.\n    pub fn empty(runner: Option<MultiContractRunner>, allow_failure: bool) -> Self {\n        Self::new(runner, BTreeMap::new(), allow_failure, None)\n    }\n\n    /// Returns an iterator over all individual succeeding tests and their names.\n    pub fn successes(&self) -> impl Iterator<Item = (&String, &TestResult)> {\n        self.tests().filter(|(_, t)| t.status.is_success())\n    }\n\n    /// Returns an iterator over all individual skipped tests and their names.\n    pub fn skips(&self) -> impl Iterator<Item = (&String, &TestResult)> {\n        self.tests().filter(|(_, t)| t.status.is_skipped())\n    }\n\n    /// Returns an iterator over all individual failing tests and their names.\n    pub fn failures(&self) -> impl Iterator<Item = (&String, &TestResult)> {\n        self.tests().filter(|(_, t)| t.status.is_failure())\n    }\n\n    /// Returns an iterator over all individual tests and their names.\n    pub fn tests(&self) -> impl Iterator<Item = (&String, &TestResult)> {\n        self.results.values().flat_map(|suite| suite.tests())\n    }\n\n    /// Flattens the test outcome into a list of individual tests.\n    // TODO: Replace this with `tests` and make it return `TestRef<'_>`\n    pub fn into_tests_cloned(&self) -> impl Iterator<Item = SuiteTestResult> + '_ {\n        self.results\n            .iter()\n            .flat_map(|(file, suite)| {\n                suite\n                    .test_results\n                    .iter()\n                    .map(move |(sig, result)| (file.clone(), sig.clone(), result.clone()))\n            })\n            .map(|(artifact_id, signature, result)| SuiteTestResult {\n                artifact_id,\n                signature,\n                result,\n            })\n    }\n\n    /// Flattens the test outcome into a list of individual tests.\n    pub fn into_tests(self) -> impl Iterator<Item = SuiteTestResult> {\n        self.results\n            .into_iter()\n            .flat_map(|(file, suite)| {\n                suite.test_results.into_iter().map(move |t| (file.clone(), t))\n            })\n            .map(|(artifact_id, (signature, result))| SuiteTestResult {\n                artifact_id,\n                signature,\n                result,\n            })\n    }\n\n    /// Returns the number of tests that passed.\n    pub fn passed(&self) -> usize {\n        self.successes().count()\n    }\n\n    /// Returns the number of tests that were skipped.\n    pub fn skipped(&self) -> usize {\n        self.skips().count()\n    }\n\n    /// Returns the number of tests that failed.\n    pub fn failed(&self) -> usize {\n        self.failures().count()\n    }\n\n    /// Returns `true` if any fuzz or invariant test failed.\n    pub fn has_fuzz_failures(&self) -> bool {\n        self.failures().any(|(_, t)| t.kind.is_fuzz() || t.kind.is_invariant())\n    }\n\n    /// Sums up all the durations of all individual test suites.\n    ///\n    /// Note that this is not necessarily the wall clock time of the entire test run.\n    pub fn total_time(&self) -> Duration {\n        self.results.values().map(|suite| suite.duration).sum()\n    }\n\n    /// Formats the aggregated summary of all test suites into a string (for printing).\n    pub fn summary(&self, wall_clock_time: Duration) -> String {\n        let num_test_suites = self.results.len();\n        let suites = if num_test_suites == 1 { \"suite\" } else { \"suites\" };\n        let total_passed = self.passed();\n        let total_failed = self.failed();\n        let total_skipped = self.skipped();\n        let total_tests = total_passed + total_failed + total_skipped;\n        format!(\n            \"\\nRan {} test {} in {:.2?} ({:.2?} CPU time): {} tests passed, {} failed, {} skipped ({} total tests)\",\n            num_test_suites,\n            suites,\n            wall_clock_time,\n            self.total_time(),\n            total_passed.green(),\n            total_failed.red(),\n            total_skipped.yellow(),\n            total_tests\n        )\n    }\n\n    /// Checks if there are any failures and failures are disallowed.\n    pub fn ensure_ok(&self, silent: bool) -> eyre::Result<()> {\n        let outcome = self;\n        let failures = outcome.failures().count();\n        if outcome.allow_failure || failures == 0 {\n            return Ok(());\n        }\n\n        if shell::is_quiet() || silent {\n            std::process::exit(1);\n        }\n\n        sh_println!(\"\\nFailing tests:\")?;\n        for (suite_name, suite) in &outcome.results {\n            let failed = suite.failed();\n            if failed == 0 {\n                continue;\n            }\n\n            let term = if failed > 1 { \"tests\" } else { \"test\" };\n            sh_println!(\"Encountered {failed} failing {term} in {suite_name}\")?;\n            for (name, result) in suite.failures() {\n                sh_println!(\"{}\", result.short_result(name))?;\n            }\n            sh_println!()?;\n        }\n        let successes = outcome.passed();\n        sh_println!(\n            \"Encountered a total of {} failing tests, {} tests succeeded\",\n            failures.to_string().red(),\n            successes.to_string().green()\n        )?;\n\n        // Show helpful hint for rerunning failed tests\n        let test_word = if failures == 1 { \"test\" } else { \"tests\" };\n        sh_println!(\n            \"\\nTip: Run {} to retry only the {} failed {}\",\n            \"`forge test --rerun`\".cyan(),\n            failures,\n            test_word\n        )?;\n\n        // Print seed for fuzz/invariant test failures to enable reproduction.\n        if let Some(seed) = self.fuzz_seed\n            && outcome.has_fuzz_failures()\n        {\n            sh_println!(\n                \"\\nFuzz seed: {} (use {} to reproduce)\",\n                format!(\"{seed:#x}\").cyan(),\n                \"`--fuzz-seed`\".cyan()\n            )?;\n        }\n\n        std::process::exit(1);\n    }\n\n    /// Removes first test result, if any.\n    pub fn remove_first(&mut self) -> Option<(String, String, TestResult)> {\n        self.results.iter_mut().find_map(|(suite_name, suite)| {\n            if let Some(test_name) = suite.test_results.keys().next().cloned() {\n                let result = suite.test_results.remove(&test_name).unwrap();\n                Some((suite_name.clone(), test_name, result))\n            } else {\n                None\n            }\n        })\n    }\n}\n\n/// A set of test results for a single test suite, which is all the tests in a single contract.\n#[derive(Clone, Debug, Serialize)]\npub struct SuiteResult {\n    /// Wall clock time it took to execute all tests in this suite.\n    #[serde(with = \"foundry_common::serde_helpers::duration\")]\n    pub duration: Duration,\n    /// Individual test results: `test fn signature -> TestResult`.\n    pub test_results: BTreeMap<String, TestResult>,\n    /// Generated warnings.\n    pub warnings: Vec<String>,\n}\n\nimpl SuiteResult {\n    pub fn new(\n        duration: Duration,\n        test_results: BTreeMap<String, TestResult>,\n        mut warnings: Vec<String>,\n    ) -> Self {\n        // Add deprecated cheatcodes warning, if any of them used in current test suite.\n        let mut deprecated_cheatcodes = HashMap::new();\n        for test_result in test_results.values() {\n            deprecated_cheatcodes.extend(test_result.deprecated_cheatcodes.clone());\n        }\n        if !deprecated_cheatcodes.is_empty() {\n            let mut warning =\n                \"the following cheatcode(s) are deprecated and will be removed in future versions:\"\n                    .to_string();\n            for (cheatcode, reason) in deprecated_cheatcodes {\n                write!(warning, \"\\n  {cheatcode}\").unwrap();\n                if let Some(reason) = reason {\n                    write!(warning, \": {reason}\").unwrap();\n                }\n            }\n            warnings.push(warning);\n        }\n\n        Self { duration, test_results, warnings }\n    }\n\n    /// Returns an iterator over all individual succeeding tests and their names.\n    pub fn successes(&self) -> impl Iterator<Item = (&String, &TestResult)> {\n        self.tests().filter(|(_, t)| t.status.is_success())\n    }\n\n    /// Returns an iterator over all individual skipped tests and their names.\n    pub fn skips(&self) -> impl Iterator<Item = (&String, &TestResult)> {\n        self.tests().filter(|(_, t)| t.status.is_skipped())\n    }\n\n    /// Returns an iterator over all individual failing tests and their names.\n    pub fn failures(&self) -> impl Iterator<Item = (&String, &TestResult)> {\n        self.tests().filter(|(_, t)| t.status.is_failure())\n    }\n\n    /// Returns the number of tests that passed.\n    pub fn passed(&self) -> usize {\n        self.successes().count()\n    }\n\n    /// Returns the number of tests that were skipped.\n    pub fn skipped(&self) -> usize {\n        self.skips().count()\n    }\n\n    /// Returns the number of tests that failed.\n    pub fn failed(&self) -> usize {\n        self.failures().count()\n    }\n\n    /// Iterator over all tests and their names\n    pub fn tests(&self) -> impl Iterator<Item = (&String, &TestResult)> {\n        self.test_results.iter()\n    }\n\n    /// Whether this test suite is empty.\n    pub fn is_empty(&self) -> bool {\n        self.test_results.is_empty()\n    }\n\n    /// The number of tests in this test suite.\n    pub fn len(&self) -> usize {\n        self.test_results.len()\n    }\n\n    /// Sums up all the durations of all individual tests in this suite.\n    ///\n    /// Note that this is not necessarily the wall clock time of the entire test suite.\n    pub fn total_time(&self) -> Duration {\n        self.test_results.values().map(|result| result.duration).sum()\n    }\n\n    /// Returns the summary of a single test suite.\n    pub fn summary(&self) -> String {\n        let failed = self.failed();\n        let result = if failed == 0 { \"ok\".green() } else { \"FAILED\".red() };\n        format!(\n            \"Suite result: {}. {} passed; {} failed; {} skipped; finished in {:.2?} ({:.2?} CPU time)\",\n            result,\n            self.passed().green(),\n            failed.red(),\n            self.skipped().yellow(),\n            self.duration,\n            self.total_time(),\n        )\n    }\n}\n\n/// The result of a single test in a test suite.\n///\n/// This is flattened from a [`TestOutcome`].\n#[derive(Clone, Debug)]\npub struct SuiteTestResult {\n    /// The identifier of the artifact/contract in the form:\n    /// `<artifact file name>:<contract name>`.\n    pub artifact_id: String,\n    /// The function signature of the Solidity test.\n    pub signature: String,\n    /// The result of the executed test.\n    pub result: TestResult,\n}\n\nimpl SuiteTestResult {\n    /// Returns the gas used by the test.\n    pub fn gas_used(&self) -> u64 {\n        self.result.kind.report().gas()\n    }\n\n    /// Returns the contract name of the artifact ID.\n    pub fn contract_name(&self) -> &str {\n        get_contract_name(&self.artifact_id)\n    }\n\n    /// Returns the file name of the artifact ID.\n    pub fn file_name(&self) -> &str {\n        get_file_name(&self.artifact_id)\n    }\n}\n\n/// The status of a test.\n#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]\npub enum TestStatus {\n    Success,\n    #[default]\n    Failure,\n    Skipped,\n}\n\nimpl TestStatus {\n    /// Returns `true` if the test was successful.\n    #[inline]\n    pub fn is_success(self) -> bool {\n        matches!(self, Self::Success)\n    }\n\n    /// Returns `true` if the test failed.\n    #[inline]\n    pub fn is_failure(self) -> bool {\n        matches!(self, Self::Failure)\n    }\n\n    /// Returns `true` if the test was skipped.\n    #[inline]\n    pub fn is_skipped(self) -> bool {\n        matches!(self, Self::Skipped)\n    }\n}\n\n/// The result of an executed test.\n#[derive(Clone, Debug, Default, Serialize, Deserialize)]\npub struct TestResult {\n    /// The test status, indicating whether the test case succeeded, failed, or was marked as\n    /// skipped. This means that the transaction executed properly, the test was marked as\n    /// skipped with vm.skip(), or that there was a revert and that the test was expected to\n    /// fail (prefixed with `testFail`)\n    pub status: TestStatus,\n\n    /// If there was a revert, this field will be populated. Note that the test can\n    /// still be successful (i.e self.success == true) when it's expected to fail.\n    pub reason: Option<String>,\n\n    /// Minimal reproduction test case for failing test\n    pub counterexample: Option<CounterExample>,\n\n    /// Any captured & parsed as strings logs along the test's execution which should\n    /// be printed to the user.\n    pub logs: Vec<Log>,\n\n    /// The decoded DSTest logging events and Hardhat's `console.log` from [logs](Self::logs).\n    /// Used for json output.\n    pub decoded_logs: Vec<String>,\n\n    /// What kind of test this was\n    pub kind: TestKind,\n\n    /// Traces\n    pub traces: Traces,\n\n    /// Additional traces to use for gas report.\n    ///\n    /// These are cleared after the gas report is analyzed.\n    #[serde(skip)]\n    pub gas_report_traces: Vec<Vec<CallTraceArena>>,\n\n    /// Raw line coverage info\n    #[serde(skip)]\n    pub line_coverage: Option<HitMaps>,\n\n    /// Labeled addresses\n    #[serde(rename = \"labeled_addresses\")] // Backwards compatibility.\n    pub labels: AddressHashMap<String>,\n\n    #[serde(with = \"foundry_common::serde_helpers::duration\")]\n    pub duration: Duration,\n\n    /// pc breakpoint char map\n    pub breakpoints: Breakpoints,\n\n    /// Any captured gas snapshots along the test's execution which should be accumulated.\n    pub gas_snapshots: BTreeMap<String, BTreeMap<String, String>>,\n\n    /// Deprecated cheatcodes (mapped to their replacements, if any) used in current test.\n    #[serde(skip)]\n    pub deprecated_cheatcodes: HashMap<&'static str, Option<&'static str>>,\n}\n\nimpl fmt::Display for TestResult {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        match self.status {\n            TestStatus::Success => {\n                // For optimization mode, show the best example sequence in green.\n                if let Some(CounterExample::Sequence(original, sequence)) = &self.counterexample {\n                    let mut s = String::from(\"[PASS]\");\n                    s.push_str(\n                        format!(\n                            \"\\n\\t[Best sequence] (original: {original}, shrunk: {})\\n\",\n                            sequence.len()\n                        )\n                        .as_str(),\n                    );\n                    for ex in sequence {\n                        writeln!(s, \"{ex}\").unwrap();\n                    }\n                    s.green().wrap().fmt(f)\n                } else {\n                    \"[PASS]\".green().fmt(f)\n                }\n            }\n            TestStatus::Skipped => {\n                let mut s = String::from(\"[SKIP\");\n                if let Some(reason) = &self.reason {\n                    write!(s, \": {reason}\").unwrap();\n                }\n                s.push(']');\n                s.yellow().fmt(f)\n            }\n            TestStatus::Failure => {\n                let mut s = String::from(\"[FAIL\");\n                if self.reason.is_some() || self.counterexample.is_some() {\n                    if let Some(reason) = &self.reason {\n                        write!(s, \": {reason}\").unwrap();\n                    }\n\n                    if let Some(counterexample) = &self.counterexample {\n                        match counterexample {\n                            CounterExample::Single(ex) => {\n                                write!(s, \"; counterexample: {ex}]\").unwrap();\n                            }\n                            CounterExample::Sequence(original, sequence) => {\n                                s.push_str(\n                                    format!(\n                                        \"]\\n\\t[Sequence] (original: {original}, shrunk: {})\\n\",\n                                        sequence.len()\n                                    )\n                                    .as_str(),\n                                );\n                                for ex in sequence {\n                                    writeln!(s, \"{ex}\").unwrap();\n                                }\n                            }\n                        }\n                    } else {\n                        s.push(']');\n                    }\n                } else {\n                    s.push(']');\n                }\n                s.red().wrap().fmt(f)\n            }\n        }\n    }\n}\n\nmacro_rules! extend {\n    ($a:expr, $b:expr, $trace_kind:expr) => {\n        $a.logs.extend($b.logs);\n        $a.labels.extend($b.labels);\n        $a.traces.extend($b.traces.map(|traces| ($trace_kind, traces)));\n        $a.merge_coverages($b.line_coverage);\n    };\n}\n\nimpl TestResult {\n    /// Creates a new test result starting from test setup results.\n    pub fn new(setup: &TestSetup) -> Self {\n        Self {\n            labels: setup.labels.clone(),\n            logs: setup.logs.clone(),\n            traces: setup.traces.clone(),\n            line_coverage: setup.coverage.clone(),\n            ..Default::default()\n        }\n    }\n\n    /// Creates a failed test result with given reason.\n    pub fn fail(reason: String) -> Self {\n        Self { status: TestStatus::Failure, reason: Some(reason), ..Default::default() }\n    }\n\n    /// Creates a test setup result.\n    pub fn setup_result(setup: TestSetup) -> Self {\n        let TestSetup {\n            address: _,\n            fuzz_fixtures: _,\n            logs,\n            labels,\n            traces,\n            coverage,\n            deployed_libs: _,\n            reason,\n            skipped,\n            deployment_failure: _,\n        } = setup;\n        Self {\n            status: if skipped { TestStatus::Skipped } else { TestStatus::Failure },\n            reason,\n            logs,\n            traces,\n            line_coverage: coverage,\n            labels,\n            ..Default::default()\n        }\n    }\n\n    /// Returns the skipped result for single test (used in skipped fuzz test too).\n    pub fn single_skip(&mut self, reason: SkipReason) {\n        self.status = TestStatus::Skipped;\n        self.reason = reason.0;\n    }\n\n    /// Returns the failed result with reason for single test.\n    pub fn single_fail(&mut self, reason: Option<String>) {\n        self.status = TestStatus::Failure;\n        self.reason = reason;\n    }\n\n    /// Returns the result for single test. Merges execution results (logs, labeled addresses,\n    /// traces and coverages) in initial setup results.\n    pub fn single_result(\n        &mut self,\n        success: bool,\n        reason: Option<String>,\n        raw_call_result: RawCallResult,\n    ) {\n        self.kind = TestKind::Unit {\n            gas: raw_call_result.gas_used.saturating_sub(raw_call_result.stipend),\n        };\n\n        extend!(self, raw_call_result, TraceKind::Execution);\n\n        self.status = match success {\n            true => TestStatus::Success,\n            false => TestStatus::Failure,\n        };\n        self.reason = reason;\n        self.duration = Duration::default();\n        self.gas_report_traces = Vec::new();\n\n        if let Some(cheatcodes) = raw_call_result.cheatcodes {\n            self.breakpoints = cheatcodes.breakpoints;\n            self.gas_snapshots = cheatcodes.gas_snapshots;\n            self.deprecated_cheatcodes = cheatcodes.deprecated;\n        }\n    }\n\n    /// Returns the result for a fuzzed test. Merges fuzz execution results (logs, labeled\n    /// addresses, traces and coverages) in initial setup results.\n    pub fn fuzz_result(&mut self, result: FuzzTestResult) {\n        self.kind = TestKind::Fuzz {\n            median_gas: result.median_gas(false),\n            mean_gas: result.mean_gas(false),\n            first_case: result.first_case,\n            runs: result.gas_by_case.len(),\n            failed_corpus_replays: result.failed_corpus_replays,\n        };\n\n        // Record logs, labels, traces and merge coverages.\n        extend!(self, result, TraceKind::Execution);\n\n        self.status = if result.skipped {\n            TestStatus::Skipped\n        } else if result.success {\n            TestStatus::Success\n        } else {\n            TestStatus::Failure\n        };\n        self.reason = result.reason;\n        self.counterexample = result.counterexample;\n        self.duration = Duration::default();\n        self.gas_report_traces = result.gas_report_traces.into_iter().map(|t| vec![t]).collect();\n        self.breakpoints = result.breakpoints.unwrap_or_default();\n        self.deprecated_cheatcodes = result.deprecated_cheatcodes;\n    }\n\n    /// Returns the fail result for fuzz test setup.\n    pub fn fuzz_setup_fail(&mut self, e: Report) {\n        self.kind = TestKind::Fuzz {\n            first_case: Default::default(),\n            runs: 0,\n            mean_gas: 0,\n            median_gas: 0,\n            failed_corpus_replays: 0,\n        };\n        self.status = TestStatus::Failure;\n        debug!(?e, \"failed to set up fuzz testing environment\");\n        self.reason = Some(format!(\"failed to set up fuzz testing environment: {e}\"));\n    }\n\n    /// Returns the skipped result for invariant test.\n    pub fn invariant_skip(&mut self, reason: SkipReason) {\n        self.kind = TestKind::Invariant {\n            runs: 1,\n            calls: 1,\n            reverts: 1,\n            metrics: HashMap::default(),\n            failed_corpus_replays: 0,\n            optimization_best_value: None,\n        };\n        self.status = TestStatus::Skipped;\n        self.reason = reason.0;\n    }\n\n    /// Returns the fail result for replayed invariant test.\n    pub fn invariant_replay_fail(\n        &mut self,\n        replayed_entirely: bool,\n        invariant_name: &String,\n        call_sequence: Vec<BaseCounterExample>,\n    ) {\n        self.kind = TestKind::Invariant {\n            runs: 1,\n            calls: 1,\n            reverts: 1,\n            metrics: HashMap::default(),\n            failed_corpus_replays: 0,\n            optimization_best_value: None,\n        };\n        self.status = TestStatus::Failure;\n        self.reason = if replayed_entirely {\n            Some(format!(\"{invariant_name} replay failure\"))\n        } else {\n            Some(format!(\"{invariant_name} persisted failure revert\"))\n        };\n        self.counterexample = Some(CounterExample::Sequence(call_sequence.len(), call_sequence));\n    }\n\n    /// Returns the fail result for invariant test setup.\n    pub fn invariant_setup_fail(&mut self, e: Report) {\n        self.kind = TestKind::Invariant {\n            runs: 0,\n            calls: 0,\n            reverts: 0,\n            metrics: HashMap::default(),\n            failed_corpus_replays: 0,\n            optimization_best_value: None,\n        };\n        self.status = TestStatus::Failure;\n        self.reason = Some(format!(\"failed to set up invariant testing environment: {e}\"));\n    }\n\n    /// Returns the invariant test result.\n    #[expect(clippy::too_many_arguments)]\n    pub fn invariant_result(\n        &mut self,\n        gas_report_traces: Vec<Vec<CallTraceArena>>,\n        success: bool,\n        reason: Option<String>,\n        counterexample: Option<CounterExample>,\n        cases: Vec<FuzzedCases>,\n        reverts: usize,\n        metrics: Map<String, InvariantMetrics>,\n        failed_corpus_replays: usize,\n        optimization_best_value: Option<I256>,\n    ) {\n        self.kind = TestKind::Invariant {\n            runs: cases.len(),\n            calls: cases.iter().map(|sequence| sequence.cases().len()).sum(),\n            reverts,\n            metrics,\n            failed_corpus_replays,\n            optimization_best_value,\n        };\n        // For optimization mode (Some value), always succeed. For check mode (None), use success.\n        self.status = if optimization_best_value.is_some() || success {\n            TestStatus::Success\n        } else {\n            TestStatus::Failure\n        };\n        self.reason = reason;\n        self.counterexample = counterexample;\n        self.gas_report_traces = gas_report_traces;\n    }\n\n    /// Returns the result for a table test. Merges table test execution results (logs, labeled\n    /// addresses, traces and coverages) in initial setup results.\n    pub fn table_result(&mut self, result: FuzzTestResult) {\n        self.kind = TestKind::Table {\n            median_gas: result.median_gas(false),\n            mean_gas: result.mean_gas(false),\n            runs: result.gas_by_case.len(),\n        };\n\n        // Record logs, labels, traces and merge coverages.\n        extend!(self, result, TraceKind::Execution);\n\n        self.status = if result.skipped {\n            TestStatus::Skipped\n        } else if result.success {\n            TestStatus::Success\n        } else {\n            TestStatus::Failure\n        };\n        self.reason = result.reason;\n        self.counterexample = result.counterexample;\n        self.duration = Duration::default();\n        self.gas_report_traces = result.gas_report_traces.into_iter().map(|t| vec![t]).collect();\n        self.breakpoints = result.breakpoints.unwrap_or_default();\n        self.deprecated_cheatcodes = result.deprecated_cheatcodes;\n    }\n\n    /// Returns `true` if this is the result of a fuzz test\n    pub fn is_fuzz(&self) -> bool {\n        matches!(self.kind, TestKind::Fuzz { .. })\n    }\n\n    /// Formats the test result into a string (for printing).\n    pub fn short_result(&self, name: &str) -> String {\n        format!(\"{self} {name} {}\", self.kind.report())\n    }\n\n    /// Merges the given raw call result into `self`.\n    pub fn extend(&mut self, call_result: RawCallResult) {\n        extend!(self, call_result, TraceKind::Execution);\n    }\n\n    /// Merges the given coverage result into `self`.\n    pub fn merge_coverages(&mut self, other_coverage: Option<HitMaps>) {\n        HitMaps::merge_opt(&mut self.line_coverage, other_coverage);\n    }\n}\n\n/// Data report by a test.\n#[derive(Clone, Debug, PartialEq, Eq)]\npub enum TestKindReport {\n    Unit {\n        gas: u64,\n    },\n    Fuzz {\n        runs: usize,\n        mean_gas: u64,\n        median_gas: u64,\n        failed_corpus_replays: usize,\n    },\n    Invariant {\n        runs: usize,\n        calls: usize,\n        reverts: usize,\n        metrics: Map<String, InvariantMetrics>,\n        failed_corpus_replays: usize,\n        /// For optimization mode (int256 return): the best value achieved. None = check mode.\n        optimization_best_value: Option<I256>,\n    },\n    Table {\n        runs: usize,\n        mean_gas: u64,\n        median_gas: u64,\n    },\n}\n\nimpl fmt::Display for TestKindReport {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        match self {\n            Self::Unit { gas } => {\n                write!(f, \"(gas: {gas})\")\n            }\n            Self::Fuzz { runs, mean_gas, median_gas, failed_corpus_replays } => {\n                if *failed_corpus_replays != 0 {\n                    write!(\n                        f,\n                        \"(runs: {runs}, μ: {mean_gas}, ~: {median_gas}, failed corpus replays: {failed_corpus_replays})\"\n                    )\n                } else {\n                    write!(f, \"(runs: {runs}, μ: {mean_gas}, ~: {median_gas})\")\n                }\n            }\n            Self::Invariant {\n                runs,\n                calls,\n                reverts,\n                metrics: _,\n                failed_corpus_replays,\n                optimization_best_value,\n            } => {\n                // If optimization_best_value is Some, this is optimization mode.\n                if let Some(best_value) = optimization_best_value {\n                    write!(f, \"(best: {best_value}, runs: {runs}, calls: {calls})\")\n                } else if *failed_corpus_replays != 0 {\n                    write!(\n                        f,\n                        \"(runs: {runs}, calls: {calls}, reverts: {reverts}, failed corpus replays: {failed_corpus_replays})\"\n                    )\n                } else {\n                    write!(f, \"(runs: {runs}, calls: {calls}, reverts: {reverts})\")\n                }\n            }\n            Self::Table { runs, mean_gas, median_gas } => {\n                write!(f, \"(runs: {runs}, μ: {mean_gas}, ~: {median_gas})\")\n            }\n        }\n    }\n}\n\nimpl TestKindReport {\n    /// Returns the main gas value to compare against\n    pub fn gas(&self) -> u64 {\n        match *self {\n            Self::Unit { gas } => gas,\n            // We use the median for comparisons\n            Self::Fuzz { median_gas, .. } | Self::Table { median_gas, .. } => median_gas,\n            // We return 0 since it's not applicable\n            Self::Invariant { .. } => 0,\n        }\n    }\n}\n\n/// Various types of tests\n#[derive(Clone, Debug, Serialize, Deserialize)]\npub enum TestKind {\n    /// A unit test.\n    Unit { gas: u64 },\n    /// A fuzz test.\n    Fuzz {\n        /// we keep this for the debugger\n        first_case: FuzzCase,\n        runs: usize,\n        mean_gas: u64,\n        median_gas: u64,\n        failed_corpus_replays: usize,\n    },\n    /// An invariant test.\n    Invariant {\n        runs: usize,\n        calls: usize,\n        reverts: usize,\n        metrics: Map<String, InvariantMetrics>,\n        failed_corpus_replays: usize,\n        /// For optimization mode (int256 return): the best value achieved. None = check mode.\n        optimization_best_value: Option<I256>,\n    },\n    /// A table test.\n    Table { runs: usize, mean_gas: u64, median_gas: u64 },\n}\n\nimpl Default for TestKind {\n    fn default() -> Self {\n        Self::Unit { gas: 0 }\n    }\n}\n\nimpl TestKind {\n    /// Returns `true` if this is a fuzz test.\n    pub fn is_fuzz(&self) -> bool {\n        matches!(self, Self::Fuzz { .. })\n    }\n\n    /// Returns `true` if this is an invariant test.\n    pub fn is_invariant(&self) -> bool {\n        matches!(self, Self::Invariant { .. })\n    }\n\n    /// The gas consumed by this test\n    pub fn report(&self) -> TestKindReport {\n        match self {\n            Self::Unit { gas } => TestKindReport::Unit { gas: *gas },\n            Self::Fuzz { first_case: _, runs, mean_gas, median_gas, failed_corpus_replays } => {\n                TestKindReport::Fuzz {\n                    runs: *runs,\n                    mean_gas: *mean_gas,\n                    median_gas: *median_gas,\n                    failed_corpus_replays: *failed_corpus_replays,\n                }\n            }\n            Self::Invariant {\n                runs,\n                calls,\n                reverts,\n                metrics: _,\n                failed_corpus_replays,\n                optimization_best_value,\n            } => TestKindReport::Invariant {\n                runs: *runs,\n                calls: *calls,\n                reverts: *reverts,\n                metrics: HashMap::default(),\n                failed_corpus_replays: *failed_corpus_replays,\n                optimization_best_value: *optimization_best_value,\n            },\n            Self::Table { runs, mean_gas, median_gas } => {\n                TestKindReport::Table { runs: *runs, mean_gas: *mean_gas, median_gas: *median_gas }\n            }\n        }\n    }\n}\n\n/// The result of a test setup.\n///\n/// Includes the deployment of the required libraries and the test contract itself, and the call to\n/// the `setUp()` function.\n#[derive(Clone, Debug, Default)]\npub struct TestSetup {\n    /// The address at which the test contract was deployed.\n    pub address: Address,\n    /// Defined fuzz test fixtures.\n    pub fuzz_fixtures: FuzzFixtures,\n\n    /// The logs emitted during setup.\n    pub logs: Vec<Log>,\n    /// Addresses labeled during setup.\n    pub labels: AddressHashMap<String>,\n    /// Call traces of the setup.\n    pub traces: Traces,\n    /// Coverage info during setup.\n    pub coverage: Option<HitMaps>,\n    /// Addresses of external libraries deployed during setup.\n    pub deployed_libs: Vec<Address>,\n\n    /// The reason the setup failed, if it did.\n    pub reason: Option<String>,\n    /// Whether setup and entire test suite is skipped.\n    pub skipped: bool,\n    /// Whether the test failed to deploy.\n    pub deployment_failure: bool,\n}\n\nimpl TestSetup {\n    pub fn failed(reason: String) -> Self {\n        Self { reason: Some(reason), ..Default::default() }\n    }\n\n    pub fn skipped(reason: String) -> Self {\n        Self { reason: Some(reason), skipped: true, ..Default::default() }\n    }\n\n    pub fn extend(&mut self, raw: RawCallResult, trace_kind: TraceKind) {\n        extend!(self, raw, trace_kind);\n    }\n\n    pub fn merge_coverages(&mut self, other_coverage: Option<HitMaps>) {\n        HitMaps::merge_opt(&mut self.coverage, other_coverage);\n    }\n}\n"
  },
  {
    "path": "crates/forge/src/runner.rs",
    "content": "//! The Forge test runner.\n\nuse crate::{\n    MultiContractRunner, TestFilter,\n    coverage::HitMaps,\n    fuzz::{BaseCounterExample, FuzzTestResult},\n    multi_runner::{TestContract, TestRunnerConfig},\n    progress::{TestsProgress, start_fuzz_progress},\n    result::{SuiteResult, TestResult, TestSetup},\n};\nuse alloy_dyn_abi::{DynSolValue, JsonAbiExt};\nuse alloy_json_abi::Function;\nuse alloy_primitives::{Address, Bytes, U256, address, map::HashMap};\nuse eyre::Result;\nuse foundry_common::{TestFunctionExt, TestFunctionKind, contracts::ContractsByAddress};\nuse foundry_compilers::utils::canonicalized;\nuse foundry_config::{Config, FuzzCorpusConfig};\nuse foundry_evm::{\n    constants::CALLER,\n    decode::RevertDecoder,\n    executors::{\n        CallResult, EvmError, Executor, ITest, RawCallResult,\n        fuzz::FuzzedExecutor,\n        invariant::{\n            InvariantExecutor, InvariantFuzzError, check_sequence, replay_error, replay_run,\n        },\n    },\n    fuzz::{\n        BasicTxDetails, CallDetails, CounterExample, FuzzFixtures, fixture_name,\n        invariant::InvariantContract, strategies::EvmFuzzState,\n    },\n    traces::{TraceKind, TraceMode, load_contracts},\n};\nuse itertools::Itertools;\nuse proptest::test_runner::{RngAlgorithm, TestError, TestRng, TestRunner};\nuse rayon::prelude::*;\nuse serde::{Deserialize, Serialize};\nuse std::{\n    borrow::Cow,\n    cmp::min,\n    collections::BTreeMap,\n    path::{Path, PathBuf},\n    sync::Arc,\n    time::Instant,\n};\nuse tokio::signal;\nuse tracing::Span;\n\n/// When running tests, we deploy all external libraries present in the project. To avoid additional\n/// libraries affecting nonces of senders used in tests, we are using separate address to\n/// predeploy libraries.\n///\n/// `address(uint160(uint256(keccak256(\"foundry library deployer\"))))`\npub const LIBRARY_DEPLOYER: Address = address!(\"0x1F95D37F27EA0dEA9C252FC09D5A6eaA97647353\");\n\n/// A type that executes all tests of a contract\npub struct ContractRunner<'a> {\n    /// The name of the contract.\n    name: &'a str,\n    /// The data of the contract.\n    contract: &'a TestContract,\n    /// The EVM executor.\n    executor: Executor,\n    /// Overall test run progress.\n    progress: Option<&'a TestsProgress>,\n    /// The handle to the tokio runtime.\n    tokio_handle: &'a tokio::runtime::Handle,\n    /// The span of the contract.\n    span: tracing::Span,\n    /// The contract-level configuration.\n    tcfg: Cow<'a, TestRunnerConfig>,\n    /// The parent runner.\n    mcr: &'a MultiContractRunner,\n}\n\nimpl<'a> std::ops::Deref for ContractRunner<'a> {\n    type Target = Cow<'a, TestRunnerConfig>;\n\n    #[inline(always)]\n    fn deref(&self) -> &Self::Target {\n        &self.tcfg\n    }\n}\n\nimpl<'a> ContractRunner<'a> {\n    pub fn new(\n        name: &'a str,\n        contract: &'a TestContract,\n        executor: Executor,\n        progress: Option<&'a TestsProgress>,\n        tokio_handle: &'a tokio::runtime::Handle,\n        span: Span,\n        mcr: &'a MultiContractRunner,\n    ) -> Self {\n        Self {\n            name,\n            contract,\n            executor,\n            progress,\n            tokio_handle,\n            span,\n            tcfg: Cow::Borrowed(&mcr.tcfg),\n            mcr,\n        }\n    }\n\n    /// Deploys the test contract inside the runner from the sending account, and optionally runs\n    /// the `setUp` function on the test contract.\n    pub fn setup(&mut self, call_setup: bool) -> TestSetup {\n        self._setup(call_setup).unwrap_or_else(|err| {\n            if err.to_string().contains(\"skipped\") {\n                TestSetup::skipped(err.to_string())\n            } else {\n                TestSetup::failed(err.to_string())\n            }\n        })\n    }\n\n    fn _setup(&mut self, call_setup: bool) -> Result<TestSetup> {\n        trace!(call_setup, \"setting up\");\n\n        self.apply_contract_inline_config()?;\n\n        // We max out their balance so that they can deploy and make calls.\n        self.executor.set_balance(self.sender, U256::MAX)?;\n        self.executor.set_balance(CALLER, U256::MAX)?;\n\n        // We set the nonce of the deployer accounts to 1 to get the same addresses as DappTools.\n        self.executor.set_nonce(self.sender, 1)?;\n\n        // Deploy libraries.\n        self.executor.set_balance(LIBRARY_DEPLOYER, U256::MAX)?;\n\n        let mut result = TestSetup::default();\n        for code in &self.mcr.libs_to_deploy {\n            let deploy_result = self.executor.deploy(\n                LIBRARY_DEPLOYER,\n                code.clone(),\n                U256::ZERO,\n                Some(&self.mcr.revert_decoder),\n            );\n\n            // Record deployed library address.\n            if let Ok(deployed) = &deploy_result {\n                result.deployed_libs.push(deployed.address);\n            }\n\n            let (raw, reason) = RawCallResult::from_evm_result(deploy_result.map(Into::into))?;\n            result.extend(raw, TraceKind::Deployment);\n            if reason.is_some() {\n                debug!(?reason, \"deployment of library failed\");\n                result.reason = reason;\n                return Ok(result);\n            }\n        }\n\n        let address = self.sender.create(self.executor.get_nonce(self.sender)?);\n        result.address = address;\n\n        // Set the contracts initial balance before deployment, so it is available during\n        // construction\n        self.executor.set_balance(address, self.initial_balance())?;\n\n        // Deploy the test contract\n        let deploy_result = self.executor.deploy(\n            self.sender,\n            self.contract.bytecode.clone(),\n            U256::ZERO,\n            Some(&self.mcr.revert_decoder),\n        );\n\n        result.deployment_failure = deploy_result.is_err();\n\n        if let Ok(dr) = &deploy_result {\n            debug_assert_eq!(dr.address, address);\n        }\n        let (raw, reason) = RawCallResult::from_evm_result(deploy_result.map(Into::into))?;\n        result.extend(raw, TraceKind::Deployment);\n        if reason.is_some() {\n            debug!(?reason, \"deployment of test contract failed\");\n            result.reason = reason;\n            return Ok(result);\n        }\n\n        // Reset `self.sender`s, `CALLER`s and `LIBRARY_DEPLOYER`'s balance to the initial balance.\n        self.executor.set_balance(self.sender, self.initial_balance())?;\n        self.executor.set_balance(CALLER, self.initial_balance())?;\n        self.executor.set_balance(LIBRARY_DEPLOYER, self.initial_balance())?;\n\n        self.executor.deploy_create2_deployer()?;\n\n        // Optionally call the `setUp` function\n        if call_setup {\n            trace!(\"calling setUp\");\n            let res = self.executor.setup(None, address, Some(&self.mcr.revert_decoder));\n            let (raw, reason) = RawCallResult::from_evm_result(res)?;\n            result.extend(raw, TraceKind::Setup);\n            result.reason = reason;\n        }\n\n        result.fuzz_fixtures = self.fuzz_fixtures(address);\n\n        Ok(result)\n    }\n\n    fn initial_balance(&self) -> U256 {\n        self.evm_opts.initial_balance\n    }\n\n    /// Configures this runner with the inline configuration for the contract.\n    fn apply_contract_inline_config(&mut self) -> Result<()> {\n        if self.inline_config.contains_contract(self.name) {\n            let new_config = Arc::new(self.inline_config(None)?);\n            self.tcfg.to_mut().reconfigure_with(new_config);\n            let prev_tracer = self.executor.inspector_mut().tracer.take();\n            self.tcfg.configure_executor(&mut self.executor);\n            // Don't set tracer here.\n            self.executor.inspector_mut().tracer = prev_tracer;\n        }\n        Ok(())\n    }\n\n    /// Returns the configuration for a contract or function.\n    fn inline_config(&self, func: Option<&Function>) -> Result<Config> {\n        let function = func.map(|f| f.name.as_str()).unwrap_or(\"\");\n        let config =\n            self.mcr.inline_config.merge(self.name, function, &self.config).extract::<Config>()?;\n        Ok(config)\n    }\n\n    /// Collect fixtures from test contract.\n    ///\n    /// Fixtures can be defined:\n    /// - as storage arrays in test contract, prefixed with `fixture`\n    /// - as functions prefixed with `fixture` and followed by parameter name to be fuzzed\n    ///\n    /// Storage array fixtures:\n    /// `uint256[] public fixture_amount = [1, 2, 3];`\n    /// define an array of uint256 values to be used for fuzzing `amount` named parameter in scope\n    /// of the current test.\n    ///\n    /// Function fixtures:\n    /// `function fixture_owner() public returns (address[] memory){}`\n    /// returns an array of addresses to be used for fuzzing `owner` named parameter in scope of the\n    /// current test.\n    fn fuzz_fixtures(&mut self, address: Address) -> FuzzFixtures {\n        let mut fixtures = HashMap::default();\n        let fixture_functions = self.contract.abi.functions().filter(|func| func.is_fixture());\n        for func in fixture_functions {\n            if func.inputs.is_empty() {\n                // Read fixtures declared as functions.\n                if let Ok(CallResult { raw: _, decoded_result }) =\n                    self.executor.call(CALLER, address, func, &[], U256::ZERO, None)\n                {\n                    fixtures.insert(fixture_name(func.name.clone()), decoded_result);\n                }\n            } else {\n                // For reading fixtures from storage arrays we collect values by calling the\n                // function with incremented indexes until there's an error.\n                let mut vals = Vec::new();\n                let mut index = 0;\n                loop {\n                    if let Ok(CallResult { raw: _, decoded_result }) = self.executor.call(\n                        CALLER,\n                        address,\n                        func,\n                        &[DynSolValue::Uint(U256::from(index), 256)],\n                        U256::ZERO,\n                        None,\n                    ) {\n                        vals.push(decoded_result);\n                    } else {\n                        // No result returned for this index, we reached the end of storage\n                        // array or the function is not a valid fixture.\n                        break;\n                    }\n                    index += 1;\n                }\n                fixtures.insert(fixture_name(func.name.clone()), DynSolValue::Array(vals));\n            };\n        }\n        FuzzFixtures::new(fixtures)\n    }\n\n    /// Runs all tests for a contract whose names match the provided regular expression\n    pub fn run_tests(mut self, filter: &dyn TestFilter) -> SuiteResult {\n        let start = Instant::now();\n        let mut warnings = Vec::new();\n\n        // Check if `setUp` function with valid signature declared.\n        let setup_fns: Vec<_> =\n            self.contract.abi.functions().filter(|func| func.name.is_setup()).collect();\n        let call_setup = setup_fns.len() == 1 && setup_fns[0].name == \"setUp\";\n        // There is a single miss-cased `setUp` function, so we add a warning\n        for &setup_fn in &setup_fns {\n            if setup_fn.name != \"setUp\" {\n                warnings.push(format!(\n                    \"Found invalid setup function \\\"{}\\\" did you mean \\\"setUp()\\\"?\",\n                    setup_fn.signature()\n                ));\n            }\n        }\n\n        // There are multiple setUp function, so we return a single test result for `setUp`\n        if setup_fns.len() > 1 {\n            return SuiteResult::new(\n                start.elapsed(),\n                [(\"setUp()\".to_string(), TestResult::fail(\"multiple setUp functions\".to_string()))]\n                    .into(),\n                warnings,\n            );\n        }\n\n        // Check if `afterInvariant` function with valid signature declared.\n        let after_invariant_fns: Vec<_> =\n            self.contract.abi.functions().filter(|func| func.name.is_after_invariant()).collect();\n        if after_invariant_fns.len() > 1 {\n            // Return a single test result failure if multiple functions declared.\n            return SuiteResult::new(\n                start.elapsed(),\n                [(\n                    \"afterInvariant()\".to_string(),\n                    TestResult::fail(\"multiple afterInvariant functions\".to_string()),\n                )]\n                .into(),\n                warnings,\n            );\n        }\n        let call_after_invariant = after_invariant_fns.first().is_some_and(|after_invariant_fn| {\n            let match_sig = after_invariant_fn.name == \"afterInvariant\";\n            if !match_sig {\n                warnings.push(format!(\n                    \"Found invalid afterInvariant function \\\"{}\\\" did you mean \\\"afterInvariant()\\\"?\",\n                    after_invariant_fn.signature()\n                ));\n            }\n            match_sig\n        });\n\n        // Invariant testing requires tracing to figure out what contracts were created.\n        // We also want to disable `debug` for setup since we won't be using those traces.\n        let has_invariants = self.contract.abi.functions().any(|func| func.is_invariant_test());\n\n        let prev_tracer = self.executor.inspector_mut().tracer.take();\n        if prev_tracer.is_some() || has_invariants {\n            self.executor.set_tracing(TraceMode::Call);\n        }\n\n        let setup_time = Instant::now();\n        let setup = self.setup(call_setup);\n        debug!(\"finished setting up in {:?}\", setup_time.elapsed());\n\n        self.executor.inspector_mut().tracer = prev_tracer;\n\n        if setup.reason.is_some() {\n            // The setup failed, so we return a single test result for `setUp`\n            let fail_msg = if !setup.deployment_failure {\n                \"setUp()\".to_string()\n            } else {\n                \"constructor()\".to_string()\n            };\n            return SuiteResult::new(\n                start.elapsed(),\n                [(fail_msg, TestResult::setup_result(setup))].into(),\n                warnings,\n            );\n        }\n\n        // Filter out functions sequentially since it's very fast and there is no need to do it\n        // in parallel.\n        let find_timer = Instant::now();\n        let functions = self\n            .contract\n            .abi\n            .functions()\n            .filter(|func| filter.matches_test_function(func))\n            .collect::<Vec<_>>();\n        debug!(\n            \"Found {} test functions out of {} in {:?}\",\n            functions.len(),\n            self.contract.abi.functions().count(),\n            find_timer.elapsed(),\n        );\n\n        let identified_contracts = has_invariants.then(|| {\n            load_contracts(setup.traces.iter().map(|(_, t)| &t.arena), &self.mcr.known_contracts)\n        });\n\n        let test_fail_functions =\n            functions.iter().filter(|func| func.test_function_kind().is_any_test_fail());\n        if test_fail_functions.clone().next().is_some() {\n            let fail = || {\n                TestResult::fail(\"`testFail*` has been removed. Consider changing to test_Revert[If|When]_Condition and expecting a revert\".to_string())\n            };\n            let test_results = test_fail_functions.map(|func| (func.signature(), fail())).collect();\n            return SuiteResult::new(start.elapsed(), test_results, warnings);\n        }\n\n        let early_exit = &self.tcfg.early_exit;\n\n        if self.progress.is_some() {\n            let interrupt = early_exit.clone();\n            self.tokio_handle.spawn(async move {\n                signal::ctrl_c().await.expect(\"Failed to listen for Ctrl+C\");\n                interrupt.record_ctrl_c();\n            });\n        }\n\n        let test_results = functions\n            .par_iter()\n            .filter_map(|&func| {\n                // Early exit if we're running with fail-fast and a test already failed.\n                if early_exit.should_stop() {\n                    return None;\n                }\n\n                let start = Instant::now();\n\n                let _guard = self.tokio_handle.enter();\n\n                let _guard;\n                let current_span = tracing::Span::current();\n                if current_span.is_none() || current_span.id() != self.span.id() {\n                    _guard = self.span.enter();\n                }\n\n                let sig = func.signature();\n                let kind = func.test_function_kind();\n\n                let _guard = debug_span!(\n                    \"test\",\n                    %kind,\n                    name = %if enabled!(tracing::Level::TRACE) { &sig } else { &func.name },\n                )\n                .entered();\n\n                let mut res = FunctionRunner::new(&self, &setup).run(\n                    func,\n                    kind,\n                    call_after_invariant,\n                    identified_contracts.as_ref(),\n                );\n                res.duration = start.elapsed();\n\n                // Record test failure for early exit (only triggers if fail-fast is enabled).\n                if res.status.is_failure() {\n                    early_exit.record_failure();\n                }\n\n                Some((sig, res))\n            })\n            .collect::<BTreeMap<_, _>>();\n\n        let duration = start.elapsed();\n        SuiteResult::new(duration, test_results, warnings)\n    }\n}\n\n/// Executes a single test function, returning a [`TestResult`].\nstruct FunctionRunner<'a> {\n    /// The function-level configuration.\n    tcfg: Cow<'a, TestRunnerConfig>,\n    /// The EVM executor.\n    executor: Cow<'a, Executor>,\n    /// The parent runner.\n    cr: &'a ContractRunner<'a>,\n    /// The address of the test contract.\n    address: Address,\n    /// The test setup result.\n    setup: &'a TestSetup,\n    /// The test result. Returned after running the test.\n    result: TestResult,\n}\n\nimpl<'a> std::ops::Deref for FunctionRunner<'a> {\n    type Target = Cow<'a, TestRunnerConfig>;\n\n    #[inline(always)]\n    fn deref(&self) -> &Self::Target {\n        &self.tcfg\n    }\n}\n\nimpl<'a> FunctionRunner<'a> {\n    fn new(cr: &'a ContractRunner<'a>, setup: &'a TestSetup) -> Self {\n        Self {\n            tcfg: match &cr.tcfg {\n                Cow::Borrowed(tcfg) => Cow::Borrowed(tcfg),\n                Cow::Owned(tcfg) => Cow::Owned(tcfg.clone()),\n            },\n            executor: Cow::Borrowed(&cr.executor),\n            cr,\n            address: setup.address,\n            setup,\n            result: TestResult::new(setup),\n        }\n    }\n\n    fn revert_decoder(&self) -> &'a RevertDecoder {\n        &self.cr.mcr.revert_decoder\n    }\n\n    /// Configures this runner with the inline configuration for the contract.\n    fn apply_function_inline_config(&mut self, func: &Function) -> Result<()> {\n        if self.inline_config.contains_function(self.cr.name, &func.name) {\n            let new_config = Arc::new(self.cr.inline_config(Some(func))?);\n            self.tcfg.to_mut().reconfigure_with(new_config);\n            self.tcfg.configure_executor(self.executor.to_mut());\n        }\n        Ok(())\n    }\n\n    fn run(\n        mut self,\n        func: &Function,\n        kind: TestFunctionKind,\n        call_after_invariant: bool,\n        identified_contracts: Option<&ContractsByAddress>,\n    ) -> TestResult {\n        if let Err(e) = self.apply_function_inline_config(func) {\n            self.result.single_fail(Some(e.to_string()));\n            return self.result;\n        }\n\n        match kind {\n            TestFunctionKind::UnitTest { .. } => self.run_unit_test(func),\n            TestFunctionKind::FuzzTest { .. } => self.run_fuzz_test(func),\n            TestFunctionKind::TableTest => self.run_table_test(func),\n            TestFunctionKind::InvariantTest => {\n                let test_bytecode = &self.cr.contract.bytecode;\n                self.run_invariant_test(\n                    func,\n                    call_after_invariant,\n                    identified_contracts.unwrap(),\n                    test_bytecode,\n                )\n            }\n            _ => unreachable!(),\n        }\n    }\n\n    /// Runs a single unit test.\n    ///\n    /// Applies before test txes (if any), runs current test and returns the `TestResult`.\n    ///\n    /// Before test txes are applied in order and state modifications committed to the EVM database\n    /// (therefore the unit test call will be made on modified state).\n    /// State modifications of before test txes and unit test function call are discarded after\n    /// test ends, similar to `eth_call`.\n    fn run_unit_test(mut self, func: &Function) -> TestResult {\n        // Prepare unit test execution.\n        if self.prepare_test(func).is_err() {\n            return self.result;\n        }\n\n        // Run current unit test.\n        let (mut raw_call_result, reason) = match self.executor.call(\n            self.sender,\n            self.address,\n            func,\n            &[],\n            U256::ZERO,\n            Some(self.revert_decoder()),\n        ) {\n            Ok(res) => (res.raw, None),\n            Err(EvmError::Execution(err)) => (err.raw, Some(err.reason)),\n            Err(EvmError::Skip(reason)) => {\n                self.result.single_skip(reason);\n                return self.result;\n            }\n            Err(err) => {\n                self.result.single_fail(Some(err.to_string()));\n                return self.result;\n            }\n        };\n\n        let success =\n            self.executor.is_raw_call_mut_success(self.address, &mut raw_call_result, false);\n        self.result.single_result(success, reason, raw_call_result);\n        self.result\n    }\n\n    /// Runs a table test.\n    /// The parameters dataset (table) is created from defined parameter fixtures, therefore each\n    /// test table parameter should have the same number of fixtures defined.\n    /// E.g. for table test\n    /// - `table_test(uint256 amount, bool swap)` fixtures are defined as\n    /// - `uint256[] public fixtureAmount = [2, 5]`\n    /// - `bool[] public fixtureSwap = [true, false]` The `table_test` is then called with the pair\n    ///   of args `(2, true)` and `(5, false)`.\n    fn run_table_test(mut self, func: &Function) -> TestResult {\n        // Prepare unit test execution.\n        if self.prepare_test(func).is_err() {\n            return self.result;\n        }\n\n        // Extract and validate fixtures for the first table test parameter.\n        let Some(first_param) = func.inputs.first() else {\n            self.result.single_fail(Some(\"Table test should have at least one parameter\".into()));\n            return self.result;\n        };\n\n        let Some(first_param_fixtures) =\n            &self.setup.fuzz_fixtures.param_fixtures(first_param.name())\n        else {\n            self.result.single_fail(Some(\"Table test should have fixtures defined\".into()));\n            return self.result;\n        };\n\n        if first_param_fixtures.is_empty() {\n            self.result.single_fail(Some(\"Table test should have at least one fixture\".into()));\n            return self.result;\n        }\n\n        let fixtures_len = first_param_fixtures.len();\n        let mut table_fixtures = vec![&first_param_fixtures[..]];\n\n        // Collect fixtures for remaining parameters.\n        for param in &func.inputs[1..] {\n            let param_name = param.name();\n            let Some(fixtures) = &self.setup.fuzz_fixtures.param_fixtures(param.name()) else {\n                self.result.single_fail(Some(format!(\"No fixture defined for param {param_name}\")));\n                return self.result;\n            };\n\n            if fixtures.len() != fixtures_len {\n                self.result.single_fail(Some(format!(\n                    \"{} fixtures defined for {param_name} (expected {})\",\n                    fixtures.len(),\n                    fixtures_len\n                )));\n                return self.result;\n            }\n\n            table_fixtures.push(&fixtures[..]);\n        }\n\n        let progress = start_fuzz_progress(\n            self.cr.progress,\n            self.cr.name,\n            &func.name,\n            None,\n            fixtures_len as u32,\n        );\n\n        let mut result = FuzzTestResult::default();\n\n        for i in 0..fixtures_len {\n            if self.tcfg.early_exit.should_stop() {\n                return self.result;\n            }\n\n            // Increment progress bar.\n            if let Some(progress) = progress.as_ref() {\n                progress.inc(1);\n            }\n\n            let args = table_fixtures.iter().map(|row| row[i].clone()).collect_vec();\n            let (mut raw_call_result, reason) = match self.executor.call(\n                self.sender,\n                self.address,\n                func,\n                &args,\n                U256::ZERO,\n                Some(self.revert_decoder()),\n            ) {\n                Ok(res) => (res.raw, None),\n                Err(EvmError::Execution(err)) => (err.raw, Some(err.reason)),\n                Err(EvmError::Skip(reason)) => {\n                    self.result.single_skip(reason);\n                    return self.result;\n                }\n                Err(err) => {\n                    self.result.single_fail(Some(err.to_string()));\n                    return self.result;\n                }\n            };\n\n            result.gas_by_case.push((raw_call_result.gas_used, raw_call_result.stipend));\n            result.logs.extend(raw_call_result.logs.clone());\n            result.labels.extend(raw_call_result.labels.clone());\n            HitMaps::merge_opt(&mut result.line_coverage, raw_call_result.line_coverage.clone());\n\n            let is_success =\n                self.executor.is_raw_call_mut_success(self.address, &mut raw_call_result, false);\n            // Record counterexample if test fails.\n            if !is_success {\n                result.counterexample =\n                    Some(CounterExample::Single(BaseCounterExample::from_fuzz_call(\n                        Bytes::from(func.abi_encode_input(&args).unwrap()),\n                        args,\n                        raw_call_result.traces.clone(),\n                    )));\n                result.reason = reason;\n                result.traces = raw_call_result.traces;\n                self.result.table_result(result);\n                return self.result;\n            }\n\n            // If it's the last iteration and all other runs succeeded, then use last call result\n            // for logs and traces.\n            if i == fixtures_len - 1 {\n                result.success = true;\n                result.traces = raw_call_result.traces;\n                self.result.table_result(result);\n                return self.result;\n            }\n        }\n\n        self.result\n    }\n\n    fn run_invariant_test(\n        mut self,\n        func: &Function,\n        call_after_invariant: bool,\n        identified_contracts: &ContractsByAddress,\n        test_bytecode: &Bytes,\n    ) -> TestResult {\n        // First, run the test normally to see if it needs to be skipped.\n        if let Err(EvmError::Skip(reason)) = self.executor.call(\n            self.sender,\n            self.address,\n            func,\n            &[],\n            U256::ZERO,\n            Some(self.revert_decoder()),\n        ) {\n            self.result.invariant_skip(reason);\n            return self.result;\n        };\n\n        let runner = self.invariant_runner();\n        let invariant_config = &self.config.invariant;\n\n        let mut executor = self.clone_executor();\n        // Enable edge coverage if running with coverage guided fuzzing or with edge coverage\n        // metrics (useful for benchmarking the fuzzer).\n        executor\n            .inspector_mut()\n            .collect_edge_coverage(invariant_config.corpus.collect_edge_coverage());\n        let mut config = invariant_config.clone();\n        let (failure_dir, failure_file) = test_paths(\n            &mut config.corpus,\n            invariant_config.failure_persist_dir.clone().unwrap(),\n            self.cr.name,\n            &func.name,\n        );\n\n        let mut evm = InvariantExecutor::new(\n            executor,\n            runner,\n            config,\n            identified_contracts,\n            &self.cr.mcr.known_contracts,\n        );\n        let invariant_contract =\n            InvariantContract::new(self.address, func, call_after_invariant, &self.cr.contract.abi);\n        let show_solidity = invariant_config.show_solidity;\n\n        let progress = start_fuzz_progress(\n            self.cr.progress,\n            self.cr.name,\n            &func.name,\n            invariant_config.timeout,\n            invariant_config.runs,\n        );\n\n        // Try to replay recorded failure if any.\n        if let Some(mut call_sequence) =\n            persisted_call_sequence(failure_file.as_path(), test_bytecode)\n        {\n            // Create calls from failed sequence and check if invariant still broken.\n            let txes = call_sequence\n                .iter_mut()\n                .map(|seq| {\n                    seq.show_solidity = show_solidity;\n                    BasicTxDetails {\n                        warp: seq.warp,\n                        roll: seq.roll,\n                        sender: seq.sender.unwrap_or_default(),\n                        call_details: CallDetails {\n                            target: seq.addr.unwrap_or_default(),\n                            calldata: seq.calldata.clone(),\n                        },\n                    }\n                })\n                .collect::<Vec<BasicTxDetails>>();\n            if let Ok((success, replayed_entirely)) = check_sequence(\n                self.clone_executor(),\n                &txes,\n                (0..min(txes.len(), invariant_config.depth as usize)).collect(),\n                invariant_contract.address,\n                invariant_contract.invariant_function.selector().to_vec().into(),\n                invariant_config.fail_on_revert,\n                invariant_contract.call_after_invariant,\n            ) && !success\n            {\n                let warn = format!(\n                    \"Replayed invariant failure from {:?} file. \\nRun `forge clean` or remove file to ignore failure and to continue invariant test campaign.\",\n                    failure_file.as_path()\n                );\n\n                if let Some(ref progress) = progress {\n                    progress.set_prefix(format!(\"{}\\n{warn}\\n\", &func.name));\n                } else {\n                    let _ = sh_warn!(\"{warn}\");\n                }\n\n                // If sequence still fails then replay error to collect traces and exit without\n                // executing new runs.\n                match replay_error(\n                    evm.config(),\n                    self.clone_executor(),\n                    &txes,\n                    None,\n                    None, // check mode\n                    &invariant_contract,\n                    &self.cr.mcr.known_contracts,\n                    identified_contracts.clone(),\n                    &mut self.result.logs,\n                    &mut self.result.traces,\n                    &mut self.result.line_coverage,\n                    &mut self.result.deprecated_cheatcodes,\n                    progress.as_ref(),\n                    &self.tcfg.early_exit,\n                ) {\n                    Ok(replayed_call_sequence) if !replayed_call_sequence.is_empty() => {\n                        call_sequence = replayed_call_sequence;\n                        // Persist error in invariant failure dir.\n                        record_invariant_failure(\n                            failure_dir.as_path(),\n                            failure_file.as_path(),\n                            &call_sequence,\n                            test_bytecode,\n                        );\n                    }\n                    Err(err) => {\n                        error!(%err, \"Failed to replay invariant error\");\n                    }\n                    _ => {}\n                }\n\n                self.result.invariant_replay_fail(\n                    replayed_entirely,\n                    &invariant_contract.invariant_function.name,\n                    call_sequence,\n                );\n                return self.result;\n            }\n        }\n\n        let invariant_result = match evm.invariant_fuzz(\n            invariant_contract.clone(),\n            &self.setup.fuzz_fixtures,\n            self.build_fuzz_state(true),\n            progress.as_ref(),\n            &self.tcfg.early_exit,\n        ) {\n            Ok(x) => x,\n            Err(e) => {\n                self.result.invariant_setup_fail(e);\n                return self.result;\n            }\n        };\n        // Merge coverage collected during invariant run with test setup coverage.\n        self.result.merge_coverages(invariant_result.line_coverage);\n\n        let mut counterexample = None;\n        let success = invariant_result.error.is_none();\n        let reason = invariant_result.error.as_ref().and_then(|err| err.revert_reason());\n\n        match invariant_result.error {\n            // If invariants were broken, replay the error to collect logs and traces\n            Some(error) => match error {\n                InvariantFuzzError::BrokenInvariant(case_data)\n                | InvariantFuzzError::Revert(case_data) => {\n                    // Replay error to create counterexample and to collect logs, traces and\n                    // coverage.\n                    match case_data.test_error {\n                        TestError::Abort(_) => {}\n                        TestError::Fail(_, ref calls) => {\n                            match replay_error(\n                                evm.config(),\n                                self.clone_executor(),\n                                calls,\n                                Some(case_data.inner_sequence),\n                                None, // check mode\n                                &invariant_contract,\n                                &self.cr.mcr.known_contracts,\n                                identified_contracts.clone(),\n                                &mut self.result.logs,\n                                &mut self.result.traces,\n                                &mut self.result.line_coverage,\n                                &mut self.result.deprecated_cheatcodes,\n                                progress.as_ref(),\n                                &self.tcfg.early_exit,\n                            ) {\n                                Ok(call_sequence) if !call_sequence.is_empty() => {\n                                    // Persist error in invariant failure dir.\n                                    record_invariant_failure(\n                                        failure_dir.as_path(),\n                                        failure_file.as_path(),\n                                        &call_sequence,\n                                        test_bytecode,\n                                    );\n\n                                    let original_seq_len =\n                                        if let TestError::Fail(_, calls) = &case_data.test_error {\n                                            calls.len()\n                                        } else {\n                                            call_sequence.len()\n                                        };\n\n                                    counterexample = Some(CounterExample::Sequence(\n                                        original_seq_len,\n                                        call_sequence,\n                                    ))\n                                }\n                                Err(err) => {\n                                    error!(%err, \"Failed to replay invariant error\");\n                                }\n                                _ => {}\n                            }\n                        }\n                    };\n                }\n                InvariantFuzzError::MaxAssumeRejects(_) => {}\n            },\n\n            // If invariants ran successfully, replay the last run to collect logs and traces.\n            _ => {\n                if let Some(best_value) = invariant_result.optimization_best_value {\n                    // Optimization mode: replay and shrink to find shortest best sequence.\n                    match replay_error(\n                        evm.config(),\n                        self.clone_executor(),\n                        &invariant_result.optimization_best_sequence,\n                        None,\n                        Some(best_value),\n                        &invariant_contract,\n                        &self.cr.mcr.known_contracts,\n                        identified_contracts.clone(),\n                        &mut self.result.logs,\n                        &mut self.result.traces,\n                        &mut self.result.line_coverage,\n                        &mut self.result.deprecated_cheatcodes,\n                        progress.as_ref(),\n                        &self.tcfg.early_exit,\n                    ) {\n                        Ok(best_sequence) if !best_sequence.is_empty() => {\n                            counterexample = Some(CounterExample::Sequence(\n                                invariant_result.optimization_best_sequence.len(),\n                                best_sequence,\n                            ));\n                        }\n                        Err(err) => {\n                            error!(%err, \"Failed to replay optimization best sequence\");\n                        }\n                        _ => {}\n                    }\n                } else {\n                    // Standard check mode: replay last run for traces.\n                    if let Err(err) = replay_run(\n                        &invariant_contract,\n                        self.clone_executor(),\n                        &self.cr.mcr.known_contracts,\n                        identified_contracts.clone(),\n                        &mut self.result.logs,\n                        &mut self.result.traces,\n                        &mut self.result.line_coverage,\n                        &mut self.result.deprecated_cheatcodes,\n                        &invariant_result.last_run_inputs,\n                        show_solidity,\n                    ) {\n                        error!(%err, \"Failed to replay last invariant run\");\n                    }\n                }\n            }\n        }\n\n        self.result.invariant_result(\n            invariant_result.gas_report_traces,\n            success,\n            reason,\n            counterexample,\n            invariant_result.cases,\n            invariant_result.reverts,\n            invariant_result.metrics,\n            invariant_result.failed_corpus_replays,\n            invariant_result.optimization_best_value,\n        );\n        self.result\n    }\n\n    /// Runs a fuzzed test.\n    ///\n    /// Applies the before test txes (if any), fuzzes the current function and returns the\n    /// `TestResult`.\n    ///\n    /// Before test txes are applied in order and state modifications committed to the EVM database\n    /// (therefore the fuzz test will use the modified state).\n    /// State modifications of before test txes and fuzz test are discarded after test ends,\n    /// similar to `eth_call`.\n    fn run_fuzz_test(mut self, func: &Function) -> TestResult {\n        // Prepare fuzz test execution.\n        if self.prepare_test(func).is_err() {\n            return self.result;\n        }\n\n        let runner = self.fuzz_runner();\n        let mut fuzz_config = self.config.fuzz.clone();\n        let (failure_dir, failure_file) = test_paths(\n            &mut fuzz_config.corpus,\n            fuzz_config.failure_persist_dir.clone().unwrap(),\n            self.cr.name,\n            &func.name,\n        );\n\n        let progress = start_fuzz_progress(\n            self.cr.progress,\n            self.cr.name,\n            &func.name,\n            fuzz_config.timeout,\n            fuzz_config.runs,\n        );\n\n        let state = self.build_fuzz_state(false);\n        let mut executor = self.executor.into_owned();\n        // Enable edge coverage if running with coverage guided fuzzing or with edge coverage\n        // metrics (useful for benchmarking the fuzzer).\n        executor.inspector_mut().collect_edge_coverage(fuzz_config.corpus.collect_edge_coverage());\n        // Load persisted counterexample, if any.\n        let persisted_failure =\n            foundry_common::fs::read_json_file::<BaseCounterExample>(failure_file.as_path()).ok();\n        // Run fuzz test.\n        let mut fuzzed_executor =\n            FuzzedExecutor::new(executor, runner, self.tcfg.sender, fuzz_config, persisted_failure);\n        let result = match fuzzed_executor.fuzz(\n            func,\n            &self.setup.fuzz_fixtures,\n            state,\n            self.address,\n            &self.cr.mcr.revert_decoder,\n            progress.as_ref(),\n            &self.tcfg.early_exit,\n            self.cr.tokio_handle,\n        ) {\n            Ok(x) => x,\n            Err(e) => {\n                self.result.fuzz_setup_fail(e);\n                return self.result;\n            }\n        };\n\n        // Record counterexample.\n        if let Some(CounterExample::Single(counterexample)) = &result.counterexample {\n            if let Err(err) = foundry_common::fs::create_dir_all(failure_dir) {\n                error!(%err, \"Failed to create fuzz failure dir\");\n            } else if let Err(err) =\n                foundry_common::fs::write_json_file(failure_file.as_path(), counterexample)\n            {\n                error!(%err, \"Failed to record call sequence\");\n            }\n        }\n\n        self.result.fuzz_result(result);\n        self.result\n    }\n\n    /// Prepares single unit test and fuzz test execution:\n    /// - set up the test result and executor\n    /// - check if before test txes are configured and apply them in order\n    ///\n    /// Before test txes are arrays of arbitrary calldata obtained by calling the `beforeTest`\n    /// function with test selector as a parameter.\n    ///\n    /// Unit tests within same contract (or even current test) are valid options for before test tx\n    /// configuration. Test execution stops if any of before test txes fails.\n    fn prepare_test(&mut self, func: &Function) -> Result<(), ()> {\n        let address = self.setup.address;\n\n        // Apply before test configured functions (if any).\n        if self.cr.contract.abi.functions().any(|func| func.name.is_before_test_setup()) {\n            for calldata in self.executor.call_sol_default(\n                address,\n                &ITest::beforeTestSetupCall { testSelector: func.selector() },\n            ) {\n                debug!(?calldata, spec=%self.executor.spec_id(), \"applying before_test_setup\");\n                // Apply before test configured calldata.\n                match self.executor.to_mut().transact_raw(\n                    self.tcfg.sender,\n                    address,\n                    calldata,\n                    U256::ZERO,\n                ) {\n                    Ok(call_result) => {\n                        let reverted = call_result.reverted;\n\n                        // Merge tx result traces in unit test result.\n                        self.result.extend(call_result);\n\n                        // To continue unit test execution the call should not revert.\n                        if reverted {\n                            self.result.single_fail(None);\n                            return Err(());\n                        }\n                    }\n                    Err(_) => {\n                        self.result.single_fail(None);\n                        return Err(());\n                    }\n                }\n            }\n        }\n        Ok(())\n    }\n\n    fn fuzz_runner(&self) -> TestRunner {\n        let config = &self.config.fuzz;\n        fuzzer_with_cases(config.seed, config.runs, config.max_test_rejects)\n    }\n\n    fn invariant_runner(&self) -> TestRunner {\n        let config = &self.config.invariant;\n        fuzzer_with_cases(self.config.fuzz.seed, config.runs, config.max_assume_rejects)\n    }\n\n    fn clone_executor(&self) -> Executor {\n        self.executor.clone().into_owned()\n    }\n\n    fn build_fuzz_state(&self, invariant: bool) -> EvmFuzzState {\n        let config =\n            if invariant { self.config.invariant.dictionary } else { self.config.fuzz.dictionary };\n        if let Some(db) = self.executor.backend().active_fork_db() {\n            EvmFuzzState::new(\n                &self.setup.deployed_libs,\n                db,\n                config,\n                Some(&self.cr.mcr.fuzz_literals),\n            )\n        } else {\n            let db = self.executor.backend().mem_db();\n            EvmFuzzState::new(\n                &self.setup.deployed_libs,\n                db,\n                config,\n                Some(&self.cr.mcr.fuzz_literals),\n            )\n        }\n    }\n}\n\nfn fuzzer_with_cases(seed: Option<U256>, cases: u32, max_global_rejects: u32) -> TestRunner {\n    let config = proptest::test_runner::Config {\n        cases,\n        max_global_rejects,\n        // Disable proptest shrink: for fuzz tests we provide single counterexample,\n        // for invariant tests we shrink outside proptest.\n        max_shrink_iters: 0,\n        ..Default::default()\n    };\n\n    if let Some(seed) = seed {\n        trace!(target: \"forge::test\", %seed, \"building deterministic fuzzer\");\n        let rng = TestRng::from_seed(RngAlgorithm::ChaCha, &seed.to_be_bytes::<32>());\n        TestRunner::new_with_rng(config, rng)\n    } else {\n        trace!(target: \"forge::test\", \"building stochastic fuzzer\");\n        TestRunner::new(config)\n    }\n}\n\n/// Holds data about a persisted invariant failure.\n#[derive(Serialize, Deserialize)]\nstruct InvariantPersistedFailure {\n    /// Recorded counterexample.\n    call_sequence: Vec<BaseCounterExample>,\n    /// Bytecode of the test contract that generated the counterexample.\n    #[serde(skip_serializing_if = \"Option::is_none\")]\n    driver_bytecode: Option<Bytes>,\n}\n\n/// Helper function to load failed call sequence from file.\n/// Ignores failure if generated with different test contract than the current one.\nfn persisted_call_sequence(path: &Path, bytecode: &Bytes) -> Option<Vec<BaseCounterExample>> {\n    foundry_common::fs::read_json_file::<InvariantPersistedFailure>(path).ok().and_then(\n        |persisted_failure| {\n            if let Some(persisted_bytecode) = &persisted_failure.driver_bytecode {\n                // Ignore persisted sequence if test bytecode doesn't match.\n                if !bytecode.eq(persisted_bytecode) {\n                    let _= sh_warn!(\"\\\n                            Failure from {:?} file was ignored because test contract bytecode has changed.\",\n                        path\n                    );\n                    return None;\n                }\n            };\n            Some(persisted_failure.call_sequence)\n        },\n    )\n}\n\n/// Helper function to set test corpus dir and to compose persisted failure paths.\nfn test_paths(\n    corpus_config: &mut FuzzCorpusConfig,\n    persist_dir: PathBuf,\n    contract_name: &str,\n    test_name: &str,\n) -> (PathBuf, PathBuf) {\n    let contract = contract_name.split(':').next_back().unwrap();\n    // Update config with corpus dir for current test.\n    corpus_config.with_test(contract, test_name);\n\n    let failures_dir = canonicalized(persist_dir.join(\"failures\").join(contract));\n    let failure_file = canonicalized(failures_dir.join(test_name));\n    (failures_dir, failure_file)\n}\n\n/// Helper function to persist invariant failure.\nfn record_invariant_failure(\n    failure_dir: &Path,\n    failure_file: &Path,\n    call_sequence: &[BaseCounterExample],\n    test_bytecode: &Bytes,\n) {\n    if let Err(err) = foundry_common::fs::create_dir_all(failure_dir) {\n        error!(%err, \"Failed to create invariant failure dir\");\n        return;\n    }\n\n    if let Err(err) = foundry_common::fs::write_json_file(\n        failure_file,\n        &InvariantPersistedFailure {\n            call_sequence: call_sequence.to_owned(),\n            driver_bytecode: Some(test_bytecode.clone()),\n        },\n    ) {\n        error!(%err, \"Failed to record call sequence\");\n    }\n}\n"
  },
  {
    "path": "crates/forge/tests/cli/backtrace.rs",
    "content": "//! Tests for backtrace functionality\n\nuse foundry_test_utils::rpc::{next_etherscan_api_key, next_http_rpc_endpoint};\n\nforgetest!(test_backtraces, |prj, cmd| {\n    prj.insert_ds_test();\n    prj.insert_vm();\n    prj.add_source(\"SimpleRevert.sol\", include_str!(\"../fixtures/backtraces/SimpleRevert.sol\"));\n    prj.add_source(\"StaticCall.sol\", include_str!(\"../fixtures/backtraces/StaticCall.sol\"));\n    prj.add_source(\"DelegateCall.sol\", include_str!(\"../fixtures/backtraces/DelegateCall.sol\"));\n    prj.add_source(\"NestedCalls.sol\", include_str!(\"../fixtures/backtraces/NestedCalls.sol\"));\n\n    prj.add_test(\"Backtrace.t.sol\", include_str!(\"../fixtures/backtraces/Backtrace.t.sol\"));\n\n    let output = cmd.args([\"test\", \"-vvvvv\"]).assert_failure();\n\n    output.stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful with warnings:\n...\nRan 11 tests for test/Backtrace.t.sol:BacktraceTest\n[FAIL: panic: assertion failed (0x01)] testAssertFail() ([GAS])\n...\nBacktrace:\n  at SimpleRevert.doAssert\n  at BacktraceTest.testAssertFail (test/Backtrace.t.sol:40:48)\n\n[FAIL: CustomError(42, 0x7FA9385bE102ac3EAc297483Dd6233D62b3e1496)] testCustomError() ([GAS])\n...\nBacktrace:\n  at SimpleRevert.doCustomError (src/SimpleRevert.sol:21:59)\n  at BacktraceTest.testCustomError (test/Backtrace.t.sol:45:49)\n\n[FAIL: Delegate compute failed] testDelegateCallRequire() ([GAS])\n...\nBacktrace:\n  at DelegateTarget.compute (src/DelegateCall.sol:11:84)\n  at DelegateCaller.delegateCompute (src/DelegateCall.sol:32:101)\n  at BacktraceTest.testDelegateCallRequire (test/Backtrace.t.sol:82:57)\n\n[FAIL: Delegate call failed] testDelegateCallRevert() ([GAS])\n...\nBacktrace:\n  at DelegateTarget.fail (src/DelegateCall.sol:7:43)\n  at DelegateCaller.delegateFail (src/DelegateCall.sol:26:91)\n  at BacktraceTest.testDelegateCallRevert (test/Backtrace.t.sol:77:56)\n\n[FAIL: Failed at internal level 3] testInternalCallChain() ([GAS])\n...\nBacktrace:\n  at BacktraceTest.testInternalCallChain (test/Backtrace.t.sol:72:54)\n\n[FAIL: Failed at chain level 3] testInternalCallsSameSource() ([GAS])\n...\nBacktrace:\n  at NestedCalls.callChain1 (src/NestedCalls.sol:25:51)\n  at BacktraceTest.testInternalCallsSameSource (test/Backtrace.t.sol:55:61)\n\n[FAIL: Maximum depth reached] testNestedCalls() ([GAS])\n...\nBacktrace:\n  at NestedCalls.nestedCall (src/NestedCalls.sol:11:46)\n  at NestedCalls.nestedCall (src/NestedCalls.sol:13:19)\n  at NestedCalls.nestedCall (src/NestedCalls.sol:13:19)\n  at NestedCalls.nestedCall (src/NestedCalls.sol:13:19)\n  at NestedCalls.nestedCall (src/NestedCalls.sol:13:19)\n  at BacktraceTest.testNestedCalls (test/Backtrace.t.sol:50:49)\n\n[FAIL: Value must be greater than zero] testRequireFail() ([GAS])\n...\nBacktrace:\n  at SimpleRevert.doRequire (src/SimpleRevert.sol:11:61)\n  at BacktraceTest.testRequireFail (test/Backtrace.t.sol:35:49)\n\n[FAIL: Simple revert message] testSimpleRevert() ([GAS])\n...\nBacktrace:\n  at SimpleRevert.doRevert (src/SimpleRevert.sol:7:67)\n  at BacktraceTest.testSimpleRevert (test/Backtrace.t.sol:30:50)\n\n[FAIL: Static compute failed] testStaticCallRequire() ([GAS])\n...\nBacktrace:\n  at StaticTarget.compute (src/StaticCall.sol:11:77)\n  at StaticCaller.staticCompute (src/StaticCall.sol:30:124)\n  at BacktraceTest.testStaticCallRequire (test/Backtrace.t.sol:92:60)\n\n[FAIL: Static call reverted] testStaticCallRevert() ([GAS])\n...\nBacktrace:\n  at StaticTarget.viewFail (src/StaticCall.sol:7:47)\n  at StaticCaller.staticCallFail (src/StaticCall.sol:25:93)\n  at BacktraceTest.testStaticCallRevert (test/Backtrace.t.sol:87:59)\n\nSuite result: FAILED. 0 passed; 11 failed; 0 skipped; [ELAPSED]\n...\n\"#]]);\n});\n\nforgetest!(test_backtrace_with_mixed_compilation, |prj, cmd| {\n    prj.insert_ds_test();\n    prj.insert_vm();\n\n    prj.add_source(\n        \"SimpleRevert.sol\",\n        r#\"\n// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ncontract SimpleRevert {\n    function doRevert(string memory reason) public pure {\n        revert(reason);\n    }\n}\n\"#,\n    );\n\n    // Add another source file that won't be modified\n    prj.add_source(\n        \"HelperContract.sol\",\n        r#\"\n// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ncontract HelperContract {\n    function getValue() public pure returns (uint256) {\n        return 42;\n    }\n    \n    function doRevert() public pure {\n        revert(\"Helper revert\");\n    }\n}\n\"#,\n    );\n\n    prj.add_test(\n        \"BacktraceTest.t.sol\",\n        r#\"\n// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../src/test.sol\";\nimport \"../src/SimpleRevert.sol\";\nimport \"../src/HelperContract.sol\";\n\ncontract BacktraceTest is DSTest {\n    SimpleRevert simpleRevert;\n    HelperContract helper;\n    \n    function setUp() public {\n        simpleRevert = new SimpleRevert();\n        helper = new HelperContract();\n    }\n    \n    function testSimpleRevert() public {\n        simpleRevert.doRevert(\"Test failure\");\n    }\n    \n    function testHelperRevert() public {\n        helper.doRevert();\n    }\n}\n\"#,\n    );\n\n    let output = cmd.args([\"test\", \"-vvvvv\"]).assert_failure();\n\n    output.stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\n...\nRan 2 tests for test/BacktraceTest.t.sol:BacktraceTest\n[FAIL: Helper revert] testHelperRevert() ([GAS])\n...\nBacktrace:\n  at HelperContract.doRevert (src/HelperContract.sol:11:47)\n  at BacktraceTest.testHelperRevert (test/BacktraceTest.t.sol:23:50)\n\n[FAIL: Test failure] testSimpleRevert() ([GAS])\n...\nBacktrace:\n  at SimpleRevert.doRevert (src/SimpleRevert.sol:7:67)\n  at BacktraceTest.testSimpleRevert (test/BacktraceTest.t.sol:19:50)\n\nSuite result: FAILED. 0 passed; 2 failed; 0 skipped; [ELAPSED]\n...\n\"#]]);\n\n    // Modify the source file - add a comment to change line numbers\n    prj.add_source(\n        \"SimpleRevert.sol\",\n        r#\"\n// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ncontract SimpleRevert {\n    function doRevert(string memory reason) public pure {\n        // Added comment to shift line numbers\n        revert(reason);\n    }\n}\n\"#,\n    );\n\n    // Modify the test file as well\n    prj.add_test(\n        \"BacktraceTest.t.sol\",\n        r#\"\n// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../src/test.sol\";\nimport \"../src/SimpleRevert.sol\";\nimport \"../src/HelperContract.sol\";\n\ncontract BacktraceTest is DSTest {\n    SimpleRevert simpleRevert;\n    HelperContract helper;\n    \n    function setUp() public {\n        simpleRevert = new SimpleRevert();\n        helper = new HelperContract();\n    }\n    \n    function testSimpleRevert() public {\n        // Added some comments\n        // to change line numbers\n        simpleRevert.doRevert(\"Test failure\");\n    }\n    \n    function testHelperRevert() public {\n        helper.doRevert();\n    }\n}\n\"#,\n    );\n\n    // Second run - mixed compilation (SimpleRevert fresh, BacktraceTest fresh, HelperContract\n    // cached)\n    let output = cmd.forge_fuse().args([\"test\", \"-vvvvv\"]).assert_failure();\n\n    output.stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\n...\nRan 2 tests for test/BacktraceTest.t.sol:BacktraceTest\n[FAIL: Helper revert] testHelperRevert() ([GAS])\n...\nBacktrace:\n  at HelperContract.doRevert (src/HelperContract.sol:11:47)\n  at BacktraceTest.testHelperRevert (test/BacktraceTest.t.sol:25:50)\n\n[FAIL: Test failure] testSimpleRevert() ([GAS])\n...\nBacktrace:\n  at SimpleRevert.doRevert (src/SimpleRevert.sol:8:56)\n  at BacktraceTest.testSimpleRevert (test/BacktraceTest.t.sol:21:43)\n\nSuite result: FAILED. 0 passed; 2 failed; 0 skipped; [ELAPSED]\n...\n\"#]]);\n});\n\nforgetest!(test_library_backtrace, |prj, cmd| {\n    prj.insert_ds_test();\n    prj.insert_vm();\n\n    // Add library source files\n    prj.add_source(\n        \"libraries/InternalMathLib.sol\",\n        include_str!(\"../fixtures/backtraces/libraries/InternalMathLib.sol\"),\n    );\n    prj.add_source(\n        \"libraries/ExternalMathLib.sol\",\n        include_str!(\"../fixtures/backtraces/libraries/ExternalMathLib.sol\"),\n    );\n    prj.add_source(\n        \"LibraryConsumer.sol\",\n        include_str!(\"../fixtures/backtraces/LibraryConsumer.sol\"),\n    );\n\n    // Add test file\n    prj.add_test(\n        \"LibraryBacktrace.t.sol\",\n        include_str!(\"../fixtures/backtraces/LibraryBacktrace.t.sol\"),\n    );\n\n    // Add foundry.toml configuration for linked library\n    let config = foundry_config::Config {\n        libraries: vec![\"src/libraries/ExternalMathLib.sol:ExternalMathLib:0x1234567890123456789012345678901234567890\".to_string()],\n        ..Default::default()\n    };\n    prj.write_config(config);\n\n    let output =\n        cmd.args([\"test\", \"-vvv\", \"--ast\", \"--mc\", \"LibraryBacktraceTest\"]).assert_failure();\n\n    output.stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\nRan 9 tests for test/LibraryBacktrace.t.sol:LibraryBacktraceTest\n[FAIL: DivisionByZero()] testExternalDivisionByZero() ([GAS])\n...\nBacktrace:\n  at ExternalMathLib.div\n  at LibraryConsumer.externalDivide\n  at LibraryBacktraceTest.testExternalDivisionByZero\n\n[FAIL: panic: arithmetic underflow or overflow (0x11)] testExternalOverflow() ([GAS])\n...\nBacktrace:\n  at ExternalMathLib.mul\n  at LibraryConsumer.externalMultiply\n  at LibraryBacktraceTest.testExternalOverflow\n\n[FAIL: ExternalMathLib: value must be positive] testExternalRequire() ([GAS])\n...\nBacktrace:\n  at ExternalMathLib.requirePositive\n  at LibraryConsumer.externalCheckPositive\n  at LibraryBacktraceTest.testExternalRequire\n\n[FAIL: Underflow()] testExternalUnderflow() ([GAS])\n...\nBacktrace:\n  at ExternalMathLib.sub\n  at LibraryConsumer.externalSubtract\n  at LibraryBacktraceTest.testExternalUnderflow\n\n[FAIL: DivisionByZero()] testInternalDivisionByZero() ([GAS])\n...\nBacktrace:\n  at LibraryConsumer.internalDivide\n  at LibraryBacktraceTest.testInternalDivisionByZero\n\n[FAIL: panic: arithmetic underflow or overflow (0x11)] testInternalOverflow() ([GAS])\nTraces:\n...\nBacktrace:\n  at LibraryConsumer.internalMultiply\n  at LibraryBacktraceTest.testInternalOverflow\n\n[FAIL: InternalMathLib: value must be positive] testInternalRequire() ([GAS])\nTraces:\n...\nBacktrace:\n  at LibraryConsumer.internalCheckPositive\n  at LibraryBacktraceTest.testInternalRequire\n\n[FAIL: Underflow()] testInternalUnderflow() ([GAS])\nTraces:\n...\nBacktrace:\n  at LibraryConsumer.internalSubtract\n  at LibraryBacktraceTest.testInternalUnderflow\n\n[FAIL: DivisionByZero()] testMixedLibraryFailure() ([GAS])\nTraces:\n...\nBacktrace:\n  at ExternalMathLib.div\n  at LibraryConsumer.mixedCalculation\n  at LibraryBacktraceTest.testMixedLibraryFailure\n\nSuite result: FAILED. 0 passed; 9 failed; 0 skipped; [ELAPSED]\n...\n\"#]]);\n});\n\nforgetest!(test_multiple_libraries_same_file, |prj, cmd| {\n    prj.insert_ds_test();\n\n    prj.add_source(\n        \"libraries/MultipleLibraries.sol\",\n        include_str!(\"../fixtures/backtraces/libraries/MultipleLibraries.sol\"),\n    );\n    prj.add_source(\n        \"MultipleLibraryConsumer.sol\",\n        include_str!(\"../fixtures/backtraces/MultipleLibraryConsumer.sol\"),\n    );\n\n    prj.add_test(\n        \"MultipleLibraryBacktrace.t.sol\",\n        include_str!(\"../fixtures/backtraces/MultipleLibraryBacktrace.t.sol\"),\n    );\n\n    let output = cmd\n        .args([\"test\", \"-vvvvv\", \"--ast\", \"--mc\", \"MultipleLibraryBacktraceTest\"])\n        .assert_failure();\n\n    output.stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\nRan 4 tests for test/MultipleLibraryBacktrace.t.sol:MultipleLibraryBacktraceTest\n[FAIL: FirstLibError()] testAllLibrariesFirstFails() ([GAS])\n...\nBacktrace:\n  at MultipleLibraryConsumer.useAllLibraries (src/libraries/MultipleLibraries.sol:10:42)\n  at MultipleLibraryBacktraceTest.testAllLibrariesFirstFails (test/MultipleLibraryBacktrace.t.sol:31:60)\n\n[FAIL: FirstLibError()] testFirstLibraryError() ([GAS])\nTraces:\n...\nBacktrace:\n  at MultipleLibraryConsumer.useFirstLib (src/libraries/MultipleLibraries.sol:10:42)\n  at MultipleLibraryBacktraceTest.testFirstLibraryError (test/MultipleLibraryBacktrace.t.sol:16:55)\n\n[FAIL: SecondLibError()] testSecondLibraryError() ([GAS])\nTraces:\n...\nBacktrace:\n  at MultipleLibraryConsumer.useSecondLib (src/libraries/MultipleLibraries.sol:26:41)\n  at MultipleLibraryBacktraceTest.testSecondLibraryError (test/MultipleLibraryBacktrace.t.sol:21:56)\n\n[FAIL: ThirdLibError()] testThirdLibraryError() ([GAS])\nTraces:\n...\nBacktrace:\n  at MultipleLibraryConsumer.useThirdLib (src/libraries/MultipleLibraries.sol:42:42)\n  at MultipleLibraryBacktraceTest.testThirdLibraryError (test/MultipleLibraryBacktrace.t.sol:26:55)\n\nSuite result: FAILED. 0 passed; 4 failed; 0 skipped; [ELAPSED]\n\n...\n\"#]]);\n});\n\nforgetest!(test_fork_backtrace, |prj, cmd| {\n    prj.insert_ds_test();\n    prj.insert_vm();\n\n    let etherscan_api_key = next_etherscan_api_key();\n    let fork_url = next_http_rpc_endpoint();\n\n    prj.add_source(\n        \"ForkedERC20Wrapper.sol\",\n        include_str!(\"../fixtures/backtraces/ForkedERC20Wrapper.sol\"),\n    );\n\n    prj.add_test(\"ForkBacktrace.t.sol\", include_str!(\"../fixtures/backtraces/ForkBacktrace.t.sol\"));\n\n    let output = cmd\n        .args([\"test\", \"-vvvvv\", \"--fork-url\", &fork_url, \"--match-contract\", \"ForkBacktraceTest\"])\n        .assert_failure();\n\n    output.stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\n...\nRan 5 tests for test/ForkBacktrace.t.sol:ForkBacktraceTest\n[FAIL: USDC transfer failed] testDirectOnChainRevert() ([GAS])\n...\nBacktrace:\n  at 0x43506849D7C04F9138D1A2050bbF3A0c054402dd.transfer\n  at 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48.transfer\n  at ForkBacktraceTest.testDirectOnChainRevert (test/ForkBacktrace.t.sol:36:126)\n\n[FAIL: ERC20: transfer amount exceeds balance] testNestedFailure() ([GAS])\n...\nBacktrace:\n  at 0x43506849D7C04F9138D1A2050bbF3A0c054402dd.transfer\n  at 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48.transfer\n  at ForkedERC20Wrapper.nestedFailure (src/ForkedERC20Wrapper.sol:14:89)\n  at ForkBacktraceTest.testNestedFailure (test/ForkBacktrace.t.sol:30:51)\n\n[FAIL: Account has zero USDC balance] testRequireNonZeroBalance() ([GAS])\n...\nBacktrace:\n  at ForkedERC20Wrapper.requireNonZeroBalance (src/ForkedERC20Wrapper.sol:23:68)\n  at ForkBacktraceTest.testRequireNonZeroBalance (test/ForkBacktrace.t.sol:26:64)\n\n[FAIL: ERC20: transfer amount exceeds allowance] testTransferFromWithoutApproval() ([GAS])\n...\nBacktrace:\n  at 0x43506849D7C04F9138D1A2050bbF3A0c054402dd.transferFrom\n  at 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48.transferFrom\n  at ForkedERC20Wrapper.transferFromWithoutApproval (src/ForkedERC20Wrapper.sol:18:101)\n  at ForkBacktraceTest.testTransferFromWithoutApproval (test/ForkBacktrace.t.sol:22:65)\n\n[FAIL: ERC20: transfer amount exceeds balance] testTransferWithoutBalance() ([GAS])\n...\nBacktrace:\n  at 0x43506849D7C04F9138D1A2050bbF3A0c054402dd.transfer\n  at 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48.transfer\n  at ForkedERC20Wrapper.transferWithoutBalance (src/ForkedERC20Wrapper.sol:14:89)\n  at ForkBacktraceTest.testTransferWithoutBalance (test/ForkBacktrace.t.sol:18:60)\n\nSuite result: FAILED. 0 passed; 5 failed; 0 skipped; [ELAPSED]\n...\n\"#]]);\n\n    cmd.forge_fuse()\n        .args([\n            \"test\",\n            \"--mt\",\n            \"testTransferFromWithoutApproval\",\n            \"-vvvvv\",\n            \"--fork-url\",\n            &fork_url,\n            \"--etherscan-api-key\",\n            &etherscan_api_key,\n        ])\n        .assert_failure()\n        .stdout_eq(str![[r#\"\nNo files changed, compilation skipped\n...\nRan 1 test for test/ForkBacktrace.t.sol:ForkBacktraceTest\n[FAIL: ERC20: transfer amount exceeds allowance] testTransferFromWithoutApproval() ([GAS])\n...\nBacktrace:\n  at FiatTokenV2_2.transferFrom\n  at FiatTokenProxy.fallback\n  at ForkedERC20Wrapper.transferFromWithoutApproval (src/ForkedERC20Wrapper.sol:18:101)\n  at ForkBacktraceTest.testTransferFromWithoutApproval (test/ForkBacktrace.t.sol:22:65)\n...\n\"#]]);\n});\n\nforgetest!(test_backtrace_via_ir_disables_source_lines, |prj, cmd| {\n    prj.insert_ds_test();\n    prj.insert_vm();\n    prj.add_source(\"SimpleRevert.sol\", include_str!(\"../fixtures/backtraces/SimpleRevert.sol\"));\n    prj.add_source(\"StaticCall.sol\", include_str!(\"../fixtures/backtraces/StaticCall.sol\"));\n    prj.add_source(\"DelegateCall.sol\", include_str!(\"../fixtures/backtraces/DelegateCall.sol\"));\n    prj.add_source(\"NestedCalls.sol\", include_str!(\"../fixtures/backtraces/NestedCalls.sol\"));\n\n    prj.add_test(\"Backtrace.t.sol\", include_str!(\"../fixtures/backtraces/Backtrace.t.sol\"));\n\n    prj.update_config(|c| c.via_ir = true);\n\n    let output = cmd.args([\"test\", \"-vvvvv\"]).assert_failure();\n    output.stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\n...\n[FAIL: Static compute failed] testStaticCallRequire() ([GAS])\n...\nBacktrace:\n  at StaticTarget.compute\n  at StaticCaller.staticCompute\n  at BacktraceTest.testStaticCallRequire\n...\n\"#]]);\n});\n\n// Test that backtraces only appear at verbosity 5 (-vvvvv).\n// Runs the same failing test at every verbosity level to assert correct output.\n#[cfg(not(feature = \"isolate-by-default\"))]\nforgetest!(test_backtrace_verbosity_levels, |prj, cmd| {\n    prj.insert_ds_test();\n    prj.insert_vm();\n\n    prj.add_source(\n        \"SimpleRevert.sol\",\n        r#\"\n// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ncontract SimpleRevert {\n    function doRevert() public pure {\n        revert(\"Simple revert message\");\n    }\n}\n\"#,\n    );\n\n    prj.add_test(\n        \"BacktraceVerbosity.t.sol\",\n        r#\"\n// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../src/test.sol\";\nimport \"../src/SimpleRevert.sol\";\n\ncontract BacktraceVerbosityTest is DSTest {\n    SimpleRevert simpleRevert;\n\n    function setUp() public {\n        simpleRevert = new SimpleRevert();\n    }\n\n    function testRevert() public {\n        simpleRevert.doRevert();\n    }\n}\n\"#,\n    );\n\n    // -v (verbosity 1): no traces, no backtrace.\n    cmd.args([\"test\", \"--mc\", \"BacktraceVerbosityTest\", \"-v\"]).assert_failure().stdout_eq(str![[\n        r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\n...\nRan 1 test for test/BacktraceVerbosity.t.sol:BacktraceVerbosityTest\n[FAIL: Simple revert message] testRevert() ([GAS])\nSuite result: FAILED. 0 passed; 1 failed; 0 skipped; [ELAPSED]\n...\n\"#\n    ]]);\n\n    // -vvv (verbosity 3): traces and backtrace WITHOUT source locations.\n    cmd.forge_fuse()\n        .args([\"test\", \"--mc\", \"BacktraceVerbosityTest\", \"-vvv\"])\n        .assert_failure()\n        .stdout_eq(str![[r#\"\nNo files changed, compilation skipped\n\nRan 1 test for test/BacktraceVerbosity.t.sol:BacktraceVerbosityTest\n[FAIL: Simple revert message] testRevert() ([GAS])\nTraces:\n  [..] BacktraceVerbosityTest::testRevert()\n    ├─ [..] SimpleRevert::doRevert() [staticcall]\n    │   └─ ← [Revert] Simple revert message\n    └─ ← [Revert] Simple revert message\n\nBacktrace:\n  at SimpleRevert.doRevert\n  at BacktraceVerbosityTest.testRevert\n\nSuite result: FAILED. 0 passed; 1 failed; 0 skipped; [ELAPSED]\n...\n\"#]]);\n\n    // -vvvv (verbosity 4): traces with setup and backtrace WITHOUT source locations.\n    cmd.forge_fuse()\n        .args([\"test\", \"--mc\", \"BacktraceVerbosityTest\", \"-vvvv\"])\n        .assert_failure()\n        .stdout_eq(str![[r#\"\nNo files changed, compilation skipped\n\nRan 1 test for test/BacktraceVerbosity.t.sol:BacktraceVerbosityTest\n[FAIL: Simple revert message] testRevert() ([GAS])\nTraces:\n  [..] BacktraceVerbosityTest::setUp()\n    ├─ [..] → new SimpleRevert@0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f\n    │   └─ ← [Return] [..]\n    └─ ← [Stop]\n\n  [..] BacktraceVerbosityTest::testRevert()\n    ├─ [..] SimpleRevert::doRevert() [staticcall]\n    │   └─ ← [Revert] Simple revert message\n    └─ ← [Revert] Simple revert message\n\nBacktrace:\n  at SimpleRevert.doRevert\n  at BacktraceVerbosityTest.testRevert\n\nSuite result: FAILED. 0 passed; 1 failed; 0 skipped; [ELAPSED]\n...\n\"#]]);\n\n    // -vvvvv (verbosity 5): traces with setup, storage changes, and backtrace WITH source\n    // locations.\n    cmd.forge_fuse()\n        .args([\"test\", \"--mc\", \"BacktraceVerbosityTest\", \"-vvvvv\"])\n        .assert_failure()\n        .stdout_eq(str![[r#\"\nNo files changed, compilation skipped\n\nRan 1 test for test/BacktraceVerbosity.t.sol:BacktraceVerbosityTest\n[FAIL: Simple revert message] testRevert() ([GAS])\nTraces:\n  [..] BacktraceVerbosityTest::setUp()\n    ├─ [..] → new SimpleRevert@0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f\n    │   └─ ← [Return] [..]\n    └─ ← [Stop]\n\n  [..] BacktraceVerbosityTest::testRevert()\n    ├─ [..] SimpleRevert::doRevert() [staticcall]\n    │   └─ ← [Revert] Simple revert message\n    └─ ← [Revert] Simple revert message\n\nBacktrace:\n  at SimpleRevert.doRevert (src/SimpleRevert.sol:[..]:[..])\n  at BacktraceVerbosityTest.testRevert (test/BacktraceVerbosity.t.sol:[..]:[..])\n\nSuite result: FAILED. 0 passed; 1 failed; 0 skipped; [ELAPSED]\n...\n\"#]]);\n});\n"
  },
  {
    "path": "crates/forge/tests/cli/bind.rs",
    "content": "// <https://github.com/foundry-rs/foundry/issues/9482>\nforgetest!(bind_unlinked_bytecode, |prj, cmd| {\n    prj.add_source(\n        \"SomeLibContract.sol\",\n        r#\"\nlibrary SomeLib {\n    function add(uint256 a, uint256 b) external pure returns (uint256) {\n        return a + b;\n    }\n}\n\ncontract SomeLibContract {\n    function add(uint256 a, uint256 b) public pure returns (uint256) {\n        return SomeLib.add(a, b);\n    }\n}\n   \"#,\n    );\n    cmd.args([\"bind\", \"--select\", \"SomeLibContract\"]).assert_success().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\nGenerating bindings for 1 contracts\nBindings have been generated to [..]\n\"#]]);\n});\n"
  },
  {
    "path": "crates/forge/tests/cli/bind_json.rs",
    "content": "use foundry_test_utils::snapbox;\n\n// tests complete bind-json workflow\n// ensures that we can run forge-bind even if files are depending on yet non-existent bindings and\n// that generated bindings are correct\nforgetest_init!(test_bind_json, |prj, cmd| {\n    prj.add_test(\n        \"JsonBindings\",\n        r#\"\nimport {JsonBindings} from \"utils/JsonBindings.sol\";\nimport {Test} from \"forge-std/Test.sol\";\n\nstruct TopLevelStruct {\n    uint256 param1;\n    int8 param2;\n}\n\ncontract BindJsonTest is Test {\n    using JsonBindings for *;\n\n    struct ContractLevelStruct {\n        address[][] param1;\n        address addrParam;\n    }\n\n    function testTopLevel() public pure {\n        string memory json = '{\"param1\": 1, \"param2\": -1}';\n        TopLevelStruct memory topLevel = json.deserializeTopLevelStruct();\n        assertEq(topLevel.param1, 1);\n        assertEq(topLevel.param2, -1);\n\n        json = topLevel.serialize();\n        TopLevelStruct memory deserialized = json.deserializeTopLevelStruct();\n        assertEq(keccak256(abi.encode(deserialized)), keccak256(abi.encode(topLevel)));\n    }\n\n    function testContractLevel() public pure {\n        ContractLevelStruct memory contractLevel = ContractLevelStruct({\n            param1: new address[][](2),\n            addrParam: address(0xBEEF)\n        });\n\n        string memory json = contractLevel.serialize();\n        assertEq(json, '{\"param1\":[[],[]],\"addrParam\":\"0x000000000000000000000000000000000000bEEF\"}');\n\n        ContractLevelStruct memory deserialized = json.deserializeContractLevelStruct();\n        assertEq(keccak256(abi.encode(deserialized)), keccak256(abi.encode(contractLevel)));\n    }\n}\n\"#,\n    );\n\n    cmd.arg(\"bind-json\").assert_success();\n\n    snapbox::assert_data_eq!(\n        snapbox::Data::read_from(&prj.root().join(\"utils/JsonBindings.sol\"), None),\n        snapbox::str![[r#\"\n// Automatically generated by forge bind-json.\n\npragma solidity >=0.6.2 <0.9.0;\npragma experimental ABIEncoderV2;\n\nimport {BindJsonTest, TopLevelStruct} from \"test/JsonBindings.sol\";\n\ninterface Vm {\n    function parseJsonTypeArray(string calldata json, string calldata key, string calldata typeDescription) external pure returns (bytes memory);\n    function parseJsonType(string calldata json, string calldata typeDescription) external pure returns (bytes memory);\n    function parseJsonType(string calldata json, string calldata key, string calldata typeDescription) external pure returns (bytes memory);\n    function serializeJsonType(string calldata typeDescription, bytes memory value) external pure returns (string memory json);\n    function serializeJsonType(string calldata objectKey, string calldata valueKey, string calldata typeDescription, bytes memory value) external returns (string memory json);\n}\n...\nlibrary JsonBindings {\n    Vm constant vm = Vm(address(uint160(uint256(keccak256(\"hevm cheat code\")))));\n\n    string constant schema_TopLevelStruct = \"TopLevelStruct(uint256 param1,int8 param2)\";\n    string constant schema_ContractLevelStruct = \"ContractLevelStruct(address[][] param1,address addrParam)\";\n\n    function serialize(TopLevelStruct memory value) internal pure returns (string memory) {\n        return vm.serializeJsonType(schema_TopLevelStruct, abi.encode(value));\n    }\n\n    function serialize(TopLevelStruct memory value, string memory objectKey, string memory valueKey) internal returns (string memory) {\n        return vm.serializeJsonType(objectKey, valueKey, schema_TopLevelStruct, abi.encode(value));\n    }\n\n    function deserializeTopLevelStruct(string memory json) public pure returns (TopLevelStruct memory) {\n        return abi.decode(vm.parseJsonType(json, schema_TopLevelStruct), (TopLevelStruct));\n    }\n\n    function deserializeTopLevelStruct(string memory json, string memory path) public pure returns (TopLevelStruct memory) {\n        return abi.decode(vm.parseJsonType(json, path, schema_TopLevelStruct), (TopLevelStruct));\n    }\n\n    function deserializeTopLevelStructArray(string memory json, string memory path) public pure returns (TopLevelStruct[] memory) {\n        return abi.decode(vm.parseJsonTypeArray(json, path, schema_TopLevelStruct), (TopLevelStruct[]));\n    }\n\n    function serialize(BindJsonTest.ContractLevelStruct memory value) internal pure returns (string memory) {\n        return vm.serializeJsonType(schema_ContractLevelStruct, abi.encode(value));\n    }\n\n    function serialize(BindJsonTest.ContractLevelStruct memory value, string memory objectKey, string memory valueKey) internal returns (string memory) {\n        return vm.serializeJsonType(objectKey, valueKey, schema_ContractLevelStruct, abi.encode(value));\n    }\n\n    function deserializeContractLevelStruct(string memory json) public pure returns (BindJsonTest.ContractLevelStruct memory) {\n        return abi.decode(vm.parseJsonType(json, schema_ContractLevelStruct), (BindJsonTest.ContractLevelStruct));\n    }\n\n    function deserializeContractLevelStruct(string memory json, string memory path) public pure returns (BindJsonTest.ContractLevelStruct memory) {\n        return abi.decode(vm.parseJsonType(json, path, schema_ContractLevelStruct), (BindJsonTest.ContractLevelStruct));\n    }\n\n    function deserializeContractLevelStructArray(string memory json, string memory path) public pure returns (BindJsonTest.ContractLevelStruct[] memory) {\n        return abi.decode(vm.parseJsonTypeArray(json, path, schema_ContractLevelStruct), (BindJsonTest.ContractLevelStruct[]));\n    }\n}\n\n\"#]],\n    );\n\n    cmd.forge_fuse().args([\"test\"]).assert_success();\n});\n"
  },
  {
    "path": "crates/forge/tests/cli/build.rs",
    "content": "use crate::utils::generate_large_init_contract;\nuse foundry_test_utils::{forgetest, forgetest_init, snapbox::IntoData, str};\nuse globset::Glob;\nuse std::fs;\n\nforgetest_init!(can_parse_build_filters, |prj, cmd| {\n    prj.initialize_default_contracts();\n    prj.clear();\n\n    cmd.args([\"build\", \"--names\", \"--skip\", \"tests\", \"scripts\"]).assert_success().stdout_eq(str![\n        [r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n  compiler version: [..]\n    - Counter\n\n\"#]\n    ]);\n});\n\nforgetest!(throws_on_conflicting_args, |prj, cmd| {\n    prj.clear();\n\n    cmd.args([\"compile\", \"--format-json\", \"--quiet\"]).assert_failure().stderr_eq(str![[r#\"\nerror: the argument '--json' cannot be used with '--quiet'\n\nUsage: forge[..] build --json [PATHS]...\n\nFor more information, try '--help'.\n\n\"#]]);\n});\n\n// tests that json is printed when --format-json is passed\nforgetest!(compile_json, |prj, cmd| {\n    prj.add_source(\n        \"jsonError\",\n        r\"\ncontract Dummy {\n    uint256 public number;\n    function something(uint256 newNumber) public {\n        number = newnumber; // error here\n    }\n}\n\",\n    );\n\n    // set up command\n    cmd.args([\"compile\", \"--format-json\"]).assert_success().stderr_eq(\"\").stdout_eq(str![[r#\"\n{\n  \"errors\": [\n    {\n      \"sourceLocation\": {\n        \"file\": \"src/jsonError.sol\",\n        \"start\": 184,\n        \"end\": 193\n      },\n      \"type\": \"DeclarationError\",\n      \"component\": \"general\",\n      \"severity\": \"error\",\n      \"errorCode\": \"7576\",\n      \"message\": \"Undeclared identifier. Did you mean \\\"newNumber\\\"?\",\n      \"formattedMessage\": \"DeclarationError: Undeclared identifier. Did you mean \\\"newNumber\\\"?\\n [FILE]:7:18:\\n  |\\n7 |         number = newnumber; // error here\\n  |                  ^^^^^^^^^\\n\\n\"\n    }\n  ],\n  \"sources\": {},\n  \"contracts\": {},\n  \"build_infos\": \"{...}\"\n}\n\"#]].is_json());\n});\n\nforgetest!(initcode_size_exceeds_limit, |prj, cmd| {\n    prj.add_source(\"LargeContract.sol\", generate_large_init_contract(50_000).as_str());\n    cmd.args([\"build\", \"--sizes\"]).assert_failure().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\n╭---------------+------------------+-------------------+--------------------+---------------------╮\n| Contract      | Runtime Size (B) | Initcode Size (B) | Runtime Margin (B) | Initcode Margin (B) |\n+=================================================================================================+\n| LargeContract | 62               | 50,125            | 24,514             | -973                |\n╰---------------+------------------+-------------------+--------------------+---------------------╯\n\n\n\"#]]);\n\n    cmd.forge_fuse().args([\"build\", \"--sizes\", \"--json\"]).assert_failure().stdout_eq(\n        str![[r#\"\n{\n  \"LargeContract\": {\n    \"runtime_size\": 62,\n    \"init_size\": 50125,\n    \"runtime_margin\": 24514,\n    \"init_margin\": -973\n  }\n}\n\"#]]\n        .is_json(),\n    );\n\n    cmd.forge_fuse().args([\"build\", \"--sizes\", \"--md\"]).assert_failure().stdout_eq(str![[r#\"\nNo files changed, compilation skipped\n\n| Contract      | Runtime Size (B) | Initcode Size (B) | Runtime Margin (B) | Initcode Margin (B) |\n|---------------|------------------|-------------------|--------------------|---------------------|\n| LargeContract | 62               | 50,125            | 24,514             | -973                |\n\n\n\"#]]);\n\n    // Ignore EIP-3860\n\n    cmd.forge_fuse().args([\"build\", \"--sizes\", \"--ignore-eip-3860\"]).assert_success().stdout_eq(\n        str![[r#\"\nNo files changed, compilation skipped\n\n╭---------------+------------------+-------------------+--------------------+---------------------╮\n| Contract      | Runtime Size (B) | Initcode Size (B) | Runtime Margin (B) | Initcode Margin (B) |\n+=================================================================================================+\n| LargeContract | 62               | 50,125            | 24,514             | -973                |\n╰---------------+------------------+-------------------+--------------------+---------------------╯\n\n\n\"#]],\n    );\n\n    cmd.forge_fuse()\n        .args([\"build\", \"--sizes\", \"--ignore-eip-3860\", \"--json\"])\n        .assert_success()\n        .stdout_eq(\n            str![[r#\"\n{\n  \"LargeContract\": {\n    \"runtime_size\": 62,\n    \"init_size\": 50125,\n    \"runtime_margin\": 24514,\n    \"init_margin\": -973\n  }\n}\n\"#]]\n            .is_json(),\n        );\n\n    cmd.forge_fuse()\n        .args([\"build\", \"--sizes\", \"--ignore-eip-3860\", \"--md\"])\n        .assert_success()\n        .stdout_eq(str![[r#\"\nNo files changed, compilation skipped\n\n| Contract      | Runtime Size (B) | Initcode Size (B) | Runtime Margin (B) | Initcode Margin (B) |\n|---------------|------------------|-------------------|--------------------|---------------------|\n| LargeContract | 62               | 50,125            | 24,514             | -973                |\n\n\n\"#]]);\n});\n\n// tests build output is as expected\nforgetest_init!(exact_build_output, |prj, cmd| {\n    prj.initialize_default_contracts();\n    cmd.args([\"build\", \"--force\"]).assert_success().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\n\"#]]);\n});\n\n// tests build output is as expected\nforgetest_init!(build_sizes_no_forge_std, |prj, cmd| {\n    prj.initialize_default_contracts();\n    prj.update_config(|config| {\n        config.solc = Some(foundry_config::SolcReq::Version(semver::Version::new(0, 8, 27)));\n    });\n\n    cmd.args([\"build\", \"--sizes\"]).assert_success().stdout_eq(str![[r#\"\n...\n\n╭----------+------------------+-------------------+--------------------+---------------------╮\n| Contract | Runtime Size (B) | Initcode Size (B) | Runtime Margin (B) | Initcode Margin (B) |\n+============================================================================================+\n| Counter  | 481              | 509               | 24,095             | 48,643              |\n╰----------+------------------+-------------------+--------------------+---------------------╯\n\n\n\"#]]);\n\n    cmd.forge_fuse().args([\"build\", \"--sizes\", \"--json\"]).assert_success().stdout_eq(\n        str![[r#\"\n{\n  \"Counter\": {\n    \"runtime_size\": 481,\n    \"init_size\": 509,\n    \"runtime_margin\": 24095,\n    \"init_margin\": 48643\n  }\n}\n\"#]]\n        .is_json(),\n    );\n\n    cmd.forge_fuse().args([\"build\", \"--sizes\", \"--md\"]).assert_success().stdout_eq(str![[r#\"\n...\n\n| Contract | Runtime Size (B) | Initcode Size (B) | Runtime Margin (B) | Initcode Margin (B) |\n|----------|------------------|-------------------|--------------------|---------------------|\n| Counter  | 481              | 509               | 24,095             | 48,643              |\n\n\n\"#]]);\n});\n\n// tests build output --sizes handles multiple contracts with the same name\nforgetest_init!(build_sizes_multiple_contracts, |prj, cmd| {\n    prj.initialize_default_contracts();\n    prj.add_source(\n        \"Foo\",\n        r\"\ncontract Foo {\n}\n\",\n    );\n\n    prj.add_source(\n        \"a/Counter\",\n        r\"\ncontract Counter {\n    uint256 public count;\n    function increment() public {\n        count++;\n    }\n}\n\",\n    );\n\n    prj.add_source(\n        \"b/Counter\",\n        r\"\ncontract Counter {\n    uint256 public count;\n    function decrement() public {\n        count--;\n    }\n}\n\",\n    );\n\n    cmd.args([\"build\", \"--sizes\"]).assert_success().stdout_eq(str![[r#\"\n...\n\n╭-----------------------------+------------------+-------------------+--------------------+---------------------╮\n| Contract                    | Runtime Size (B) | Initcode Size (B) | Runtime Margin (B) | Initcode Margin (B) |\n+===============================================================================================================+\n| Counter (src/Counter.sol)   | 481              | 509               | 24,095             | 48,643              |\n|-----------------------------+------------------+-------------------+--------------------+---------------------|\n| Counter (src/a/Counter.sol) | 344              | 372               | 24,232             | 48,780              |\n|-----------------------------+------------------+-------------------+--------------------+---------------------|\n| Counter (src/b/Counter.sol) | 291              | 319               | 24,285             | 48,833              |\n|-----------------------------+------------------+-------------------+--------------------+---------------------|\n| Foo                         | 62               | 88                | 24,514             | 49,064              |\n╰-----------------------------+------------------+-------------------+--------------------+---------------------╯\n\n\n\"#]]);\n\n    cmd.forge_fuse().args([\"build\", \"--sizes\", \"--md\"]).assert_success().stdout_eq(str![[r#\"\n...\n\n| Contract                    | Runtime Size (B) | Initcode Size (B) | Runtime Margin (B) | Initcode Margin (B) |\n|-----------------------------|------------------|-------------------|--------------------|---------------------|\n| Counter (src/Counter.sol)   | 481              | 509               | 24,095             | 48,643              |\n| Counter (src/a/Counter.sol) | 344              | 372               | 24,232             | 48,780              |\n| Counter (src/b/Counter.sol) | 291              | 319               | 24,285             | 48,833              |\n| Foo                         | 62               | 88                | 24,514             | 49,064              |\n\n\n\"#]]);\n});\n\n// tests build output --sizes --json handles multiple contracts with the same name\nforgetest_init!(build_sizes_multiple_contracts_json, |prj, cmd| {\n    prj.initialize_default_contracts();\n    prj.add_source(\n        \"Foo\",\n        r\"\ncontract Foo {\n}\n\",\n    );\n\n    prj.add_source(\n        \"a/Counter\",\n        r\"\ncontract Counter {\n    uint256 public count;\n    function increment() public {\n        count++;\n    }\n}\n\",\n    );\n\n    prj.add_source(\n        \"b/Counter\",\n        r\"\ncontract Counter {\n    uint256 public count;\n    function decrement() public {\n        count--;\n    }\n}\n\",\n    );\n\n    cmd.args([\"build\", \"--sizes\", \"--json\"]).assert_success().stdout_eq(\n        str![[r#\"\n{\n   \"Counter (src/Counter.sol)\":{\n      \"runtime_size\":481,\n      \"init_size\":509,\n      \"runtime_margin\":24095,\n      \"init_margin\":48643\n   },\n   \"Counter (src/a/Counter.sol)\":{\n      \"runtime_size\":344,\n      \"init_size\":372,\n      \"runtime_margin\":24232,\n      \"init_margin\":48780\n   },\n   \"Counter (src/b/Counter.sol)\":{\n      \"runtime_size\":291,\n      \"init_size\":319,\n      \"runtime_margin\":24285,\n      \"init_margin\":48833\n   },\n   \"Foo\":{\n      \"runtime_size\":62,\n      \"init_size\":88,\n      \"runtime_margin\":24514,\n      \"init_margin\":49064\n   }\n}\n\"#]]\n        .is_json(),\n    );\n});\n\n// tests that skip key in config can be used to skip non-compilable contract\nforgetest_init!(test_can_skip_contract, |prj, cmd| {\n    prj.add_source(\n        \"InvalidContract\",\n        r\"\ncontract InvalidContract {\n    some_invalid_syntax\n}\n\",\n    );\n\n    prj.add_source(\n        \"ValidContract\",\n        r\"\ncontract ValidContract {}\n\",\n    );\n\n    prj.update_config(|config| {\n        config.skip = vec![Glob::new(\"src/InvalidContract.sol\").unwrap().into()];\n    });\n\n    cmd.args([\"build\"]).assert_success();\n});\n\n// <https://github.com/foundry-rs/foundry/issues/11149>\nforgetest_init!(test_consistent_build_output, |prj, cmd| {\n    prj.add_source(\n        \"AContract.sol\",\n        r#\"\nimport {B} from \"/badpath/B.sol\";\n\ncontract A is B {}\n   \"#,\n    );\n\n    prj.add_source(\n        \"CContract.sol\",\n        r#\"\nimport {B} from \"badpath/B.sol\";\n\ncontract C is B {}\n   \"#,\n    );\n\n    cmd.args([\"build\", \"src/AContract.sol\"]).assert_failure().stdout_eq(str![[r#\"\n...\nUnable to resolve imports:\n      \"/badpath/B.sol\" in \"[..]\"\nwith remappings:\n      forge-std/=[..]\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\n\n\"#]]);\n    cmd.forge_fuse().args([\"build\", \"src/CContract.sol\"]).assert_failure().stdout_eq(str![[r#\"\nUnable to resolve imports:\n      \"badpath/B.sol\" in \"[..]\"\nwith remappings:\n      forge-std/=[..]\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\n\n\"#]]);\n});\n\n// <https://github.com/foundry-rs/foundry/issues/12458>\n// <https://github.com/foundry-rs/foundry/issues/12496>\nforgetest!(build_with_invalid_natspec, |prj, cmd| {\n    prj.add_source(\n        \"ContractWithInvalidNatspec.sol\",\n        r#\"\ncontract ContractA {\n    /// @deprecated quoteExactOutputSingle and exactOutput. Use QuoterV2 instead.\n}\n\n/// Some editors highlight `@note` or `@todo`\n/// @note foo bar\n\n/// @title ContractB\ncontract ContractB {\n    /**\n    some example code in a comment:\n    import { Ownable } from \"@openzeppelin/contracts/access/Ownable.sol\";\n    */\n}\n   \"#,\n    );\n\n    cmd.args([\"build\", \"src/ContractWithInvalidNatspec.sol\"]).assert_success().stderr_eq(str![[\n        r#\"\nwarning: invalid natspec tag '@deprecated', custom tags must use format '@custom:name'\n  [FILE]:5:5\n  │\n5 │     /// @deprecated quoteExactOutputSingle and exactOutput. Use QuoterV2 instead.\n  │     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n  │\n...\n\nwarning: invalid natspec tag '@note', custom tags must use format '@custom:name'\n  [FILE]:9:1\n  │\n9 │ /// @note foo bar\n  │ ━━━━━━━━━━━━━━━━━\n  │\n...\n\n\"#\n    ]]);\n});\n\n// tests that build succeeds without warning when no soldeer.lock exists\nforgetest_init!(build_no_warning_without_soldeer_lock, |prj, cmd| {\n    let soldeer_lock = prj.root().join(\"soldeer.lock\");\n    // soldeer.lock should not exist in a fresh project\n    assert!(!soldeer_lock.exists());\n\n    cmd.args([\"build\"]).assert_success().stderr_eq(str![[r#\"\n\"#]]);\n});\n\n// tests that malformed foundry.lock triggers a warning during build\nforgetest_init!(build_warns_on_malformed_foundry_lock, |prj, cmd| {\n    let foundry_lock = prj.root().join(\"foundry.lock\");\n    fs::write(&foundry_lock, \"this is not valid toml { [ }\").unwrap();\n\n    cmd.args([\"build\"]).assert_success().stderr_eq(str![[r#\"\nWarning: Failed to parse foundry.lock: [..]\n...\n\"#]]);\n});\n\n// tests that build succeeds without warning when no foundry.lock exists\nforgetest_init!(build_no_warning_without_foundry_lock, |prj, cmd| {\n    let foundry_lock = prj.root().join(\"foundry.lock\");\n    // Remove foundry.lock if it exists from template\n    let _ = fs::remove_file(&foundry_lock);\n\n    cmd.args([\"build\"]).assert_success().stderr_eq(str![[r#\"\n\"#]]);\n});\n\n// tests that build warns when foundry.lock revision differs from actual submodule revision\nforgetest_init!(build_warns_on_foundry_lock_revision_mismatch, |prj, cmd| {\n    let foundry_lock = prj.root().join(\"foundry.lock\");\n\n    // Write a foundry.lock with a fake/old revision for forge-std that differs from the actual\n    let lockfile_content = r#\"{\n  \"lib/forge-std\": {\n    \"tag\": {\n      \"name\": \"v1.9.7\",\n      \"rev\": \"0000000000000000000000000000000000000000\"\n    }\n  }\n}\"#;\n    fs::write(&foundry_lock, lockfile_content).unwrap();\n\n    cmd.args([\"build\"]).assert_success().stderr_eq(str![[r#\"\nWarning: Dependency 'lib/forge-std' revision mismatch: expected '0000000000000000000000000000000000000000', found '[..]'\n\n\"#]]);\n});\n"
  },
  {
    "path": "crates/forge/tests/cli/cache.rs",
    "content": "//! Tests for various cache command.\n\nforgetest!(can_list_cache, |_prj, cmd| {\n    cmd.args([\"cache\", \"ls\"]);\n    cmd.assert_success();\n});\n\nforgetest!(can_list_cache_all, |_prj, cmd| {\n    cmd.args([\"cache\", \"ls\", \"all\"]);\n    cmd.assert_success();\n});\n\nforgetest!(can_list_specific_chain, |_prj, cmd| {\n    cmd.args([\"cache\", \"ls\", \"mainnet\"]);\n    cmd.assert_success();\n});\n\nforgetest_init!(can_test_no_cache, |prj, cmd| {\n    prj.initialize_default_contracts();\n    prj.clear_cache();\n\n    cmd.args([\"test\", \"--no-cache\"]).assert_success();\n    assert!(!prj.cache().exists(), \"cache file should not exist\");\n\n    cmd.forge_fuse().arg(\"test\").assert_success();\n    assert!(prj.cache().exists(), \"cache file should exist\");\n});\n"
  },
  {
    "path": "crates/forge/tests/cli/cmd.rs",
    "content": "//! Contains various tests for checking forge's commands\n\nuse crate::constants::*;\nuse foundry_compilers::artifacts::{ConfigurableContractArtifact, Metadata, remappings::Remapping};\nuse foundry_config::{\n    BasicConfig, Chain, Config, DenyLevel, FuzzConfig, InvariantConfig, SolidityErrorCode,\n    parse_with_profile,\n};\nuse foundry_test_utils::{\n    foundry_compilers::PathStyle,\n    rpc::next_etherscan_api_key,\n    snapbox::IntoData,\n    util::{OutputExt, read_string},\n};\nuse std::{\n    fs,\n    path::Path,\n    process::{Command, Stdio},\n    str::FromStr,\n};\n\n// tests `--help` is printed to std out\nforgetest!(print_help, |_prj, cmd| {\n    cmd.arg(\"--help\").assert_success().stdout_eq(str![[r#\"\nBuild, test, fuzz, debug and deploy Solidity contracts\n\nUsage: forge[..] <COMMAND>\n\nCommands:\n...\n\nOptions:\n  -h, --help\n          Print help (see a summary with '-h')\n\n  -j, --threads <THREADS>\n          Number of threads to use. Specifying 0 defaults to the number of logical cores\n          \n          [aliases: --jobs]\n\n  -V, --version\n          Print version\n\nDisplay options:\n      --color <COLOR>\n          The color of the log messages\n\n          Possible values:\n          - auto:   Intelligently guess whether to use color output (default)\n          - always: Force color output\n          - never:  Force disable color output\n\n      --json\n          Format log messages as JSON\n\n      --md\n          Format log messages as Markdown\n\n  -q, --quiet\n          Do not print log messages\n\n  -v, --verbosity...\n          Verbosity level of the log messages.\n          \n          Pass multiple times to increase the verbosity (e.g. -v, -vv, -vvv).\n          \n          Depending on the context the verbosity levels have different meanings.\n          \n          For example, the verbosity levels of the EVM are:\n          - 2 (-vv): Print logs for all tests.\n          - 3 (-vvv): Print execution traces for failing tests.\n          - 4 (-vvvv): Print execution traces for all tests, and setup traces for failing tests.\n          - 5 (-vvvvv): Print execution and setup traces for all tests, including storage changes\n          and\n            backtraces with line numbers.\n\nFind more information in the book: https://getfoundry.sh/forge/overview\n\n\"#]]);\n});\n\n// checks that `clean` can be invoked even if out and cache don't exist\nforgetest!(can_clean_non_existing, |prj, cmd| {\n    cmd.arg(\"clean\");\n    cmd.assert_empty_stdout();\n    prj.assert_cleaned();\n});\n\n// checks that `clean` doesn't output warnings\nforgetest_init!(can_clean_without_warnings, |prj, cmd| {\n    prj.add_source(\n        \"Simple.sol\",\n        r#\"\npragma solidity ^0.8.5;\n\ncontract Simple {\n    uint public value = 42;\n}\n\"#,\n    );\n\n    prj.create_file(\n        \"foundry.toml\",\n        r#\"\n[default]\nevm_version = \"cancun\"\nsolc = \"0.8.5\"\n\"#,\n    );\n    // `forge build` warns\n    cmd.forge_fuse().arg(\"build\").assert_success().stderr_eq(str![[r#\"\nWarning: Found unknown config section in foundry.toml: [default]\nThis notation for profiles has been deprecated and may result in the profile not being registered in future versions.\nPlease use [profile.default] instead or run `forge config --fix`.\n\n\"#]]);\n    // `forge clear` should not warn\n    cmd.forge_fuse().arg(\"clean\").assert_success().stderr_eq(str![[r#\"\n\n\"#]]);\n});\n\n// checks that `cache ls` can be invoked and displays the foundry cache\nforgetest!(\n    #[ignore]\n    can_cache_ls,\n    |_prj, cmd| {\n        let chain = Chain::mainnet();\n        let block1 = 100;\n        let block2 = 101;\n\n        let block1_cache_dir = Config::foundry_block_cache_dir(chain, block1).unwrap();\n        let block1_file = Config::foundry_block_cache_file(chain, block1).unwrap();\n        let block2_cache_dir = Config::foundry_block_cache_dir(chain, block2).unwrap();\n        let block2_file = Config::foundry_block_cache_file(chain, block2).unwrap();\n        let etherscan_cache_dir = Config::foundry_etherscan_chain_cache_dir(chain).unwrap();\n        fs::create_dir_all(block1_cache_dir).unwrap();\n        fs::write(block1_file, \"{}\").unwrap();\n        fs::create_dir_all(block2_cache_dir).unwrap();\n        fs::write(block2_file, \"{}\").unwrap();\n        fs::create_dir_all(etherscan_cache_dir).unwrap();\n\n        let output = cmd.args([\"cache\", \"ls\"]).assert_success().get_output().stdout_lossy();\n        let output_lines = output.split('\\n').collect::<Vec<_>>();\n        println!(\"{output}\");\n\n        assert_eq!(output_lines.len(), 6);\n        assert!(output_lines[0].starts_with(\"-️ mainnet (\"));\n        assert!(output_lines[1].starts_with(\"\\t-️ Block Explorer (\"));\n        assert_eq!(output_lines[2], \"\");\n        assert!(output_lines[3].starts_with(\"\\t-️ Block 100 (\"));\n        assert!(output_lines[4].starts_with(\"\\t-️ Block 101 (\"));\n        assert_eq!(output_lines[5], \"\");\n\n        Config::clean_foundry_cache().unwrap();\n    }\n);\n\n// checks that `cache clean` can be invoked and cleans the foundry cache\n// this test is not isolated and modifies ~ so it is ignored\nforgetest!(\n    #[ignore]\n    can_cache_clean,\n    |_prj, cmd| {\n        let cache_dir = Config::foundry_cache_dir().unwrap();\n        let path = cache_dir.as_path();\n        fs::create_dir_all(path).unwrap();\n        cmd.args([\"cache\", \"clean\"]);\n        cmd.assert_empty_stdout();\n\n        assert!(!path.exists());\n    }\n);\n\n// checks that `cache clean --etherscan` can be invoked and only cleans the foundry etherscan cache\n// this test is not isolated and modifies ~ so it is ignored\nforgetest!(\n    #[ignore]\n    can_cache_clean_etherscan,\n    |_prj, cmd| {\n        let cache_dir = Config::foundry_cache_dir().unwrap();\n        let etherscan_cache_dir = Config::foundry_etherscan_cache_dir().unwrap();\n        let path = cache_dir.as_path();\n        let etherscan_path = etherscan_cache_dir.as_path();\n        fs::create_dir_all(etherscan_path).unwrap();\n        cmd.args([\"cache\", \"clean\", \"--etherscan\"]);\n        cmd.assert_empty_stdout();\n\n        assert!(path.exists());\n        assert!(!etherscan_path.exists());\n\n        Config::clean_foundry_cache().unwrap();\n    }\n);\n\n// checks that `cache clean all --etherscan` can be invoked and only cleans the foundry etherscan\n// cache. This test is not isolated and modifies ~ so it is ignored\nforgetest!(\n    #[ignore]\n    can_cache_clean_all_etherscan,\n    |_prj, cmd| {\n        let rpc_cache_dir = Config::foundry_rpc_cache_dir().unwrap();\n        let etherscan_cache_dir = Config::foundry_etherscan_cache_dir().unwrap();\n        let rpc_path = rpc_cache_dir.as_path();\n        let etherscan_path = etherscan_cache_dir.as_path();\n        fs::create_dir_all(rpc_path).unwrap();\n        fs::create_dir_all(etherscan_path).unwrap();\n        cmd.args([\"cache\", \"clean\", \"all\", \"--etherscan\"]);\n        cmd.assert_empty_stdout();\n\n        assert!(rpc_path.exists());\n        assert!(!etherscan_path.exists());\n\n        Config::clean_foundry_cache().unwrap();\n    }\n);\n\n// checks that `cache clean <chain>` can be invoked and cleans the chain cache\n// this test is not isolated and modifies ~ so it is ignored\nforgetest!(\n    #[ignore]\n    can_cache_clean_chain,\n    |_prj, cmd| {\n        let chain = Chain::mainnet();\n        let cache_dir = Config::foundry_chain_cache_dir(chain).unwrap();\n        let etherscan_cache_dir = Config::foundry_etherscan_chain_cache_dir(chain).unwrap();\n        let path = cache_dir.as_path();\n        let etherscan_path = etherscan_cache_dir.as_path();\n        fs::create_dir_all(path).unwrap();\n        fs::create_dir_all(etherscan_path).unwrap();\n        cmd.args([\"cache\", \"clean\", \"mainnet\"]);\n        cmd.assert_empty_stdout();\n\n        assert!(!path.exists());\n        assert!(!etherscan_path.exists());\n\n        Config::clean_foundry_cache().unwrap();\n    }\n);\n\n// checks that `cache clean <chain> --blocks 100,101` can be invoked and cleans the chain block\n// caches this test is not isolated and modifies ~ so it is ignored\nforgetest!(\n    #[ignore]\n    can_cache_clean_blocks,\n    |_prj, cmd| {\n        let chain = Chain::mainnet();\n        let block1 = 100;\n        let block2 = 101;\n        let block3 = 102;\n        let block1_cache_dir = Config::foundry_block_cache_dir(chain, block1).unwrap();\n        let block2_cache_dir = Config::foundry_block_cache_dir(chain, block2).unwrap();\n        let block3_cache_dir = Config::foundry_block_cache_dir(chain, block3).unwrap();\n        let etherscan_cache_dir = Config::foundry_etherscan_chain_cache_dir(chain).unwrap();\n        let block1_path = block1_cache_dir.as_path();\n        let block2_path = block2_cache_dir.as_path();\n        let block3_path = block3_cache_dir.as_path();\n        let etherscan_path = etherscan_cache_dir.as_path();\n        fs::create_dir_all(block1_path).unwrap();\n        fs::create_dir_all(block2_path).unwrap();\n        fs::create_dir_all(block3_path).unwrap();\n        fs::create_dir_all(etherscan_path).unwrap();\n        cmd.args([\"cache\", \"clean\", \"mainnet\", \"--blocks\", \"100,101\"]);\n        cmd.assert_empty_stdout();\n\n        assert!(!block1_path.exists());\n        assert!(!block2_path.exists());\n        assert!(block3_path.exists());\n        assert!(etherscan_path.exists());\n\n        Config::clean_foundry_cache().unwrap();\n    }\n);\n\n// checks that `cache clean <chain> --etherscan` can be invoked and cleans the etherscan chain cache\n// this test is not isolated and modifies ~ so it is ignored\nforgetest!(\n    #[ignore]\n    can_cache_clean_chain_etherscan,\n    |_prj, cmd| {\n        let cache_dir = Config::foundry_chain_cache_dir(Chain::mainnet()).unwrap();\n        let etherscan_cache_dir =\n            Config::foundry_etherscan_chain_cache_dir(Chain::mainnet()).unwrap();\n        let path = cache_dir.as_path();\n        let etherscan_path = etherscan_cache_dir.as_path();\n        fs::create_dir_all(path).unwrap();\n        fs::create_dir_all(etherscan_path).unwrap();\n        cmd.args([\"cache\", \"clean\", \"mainnet\", \"--etherscan\"]);\n        cmd.assert_empty_stdout();\n\n        assert!(path.exists());\n        assert!(!etherscan_path.exists());\n\n        Config::clean_foundry_cache().unwrap();\n    }\n);\n\n// checks that init works\nforgetest!(can_init_repo_with_config, |prj, cmd| {\n    let foundry_toml = prj.root().join(Config::FILE_NAME);\n    assert!(!foundry_toml.exists());\n\n    cmd.args([\"init\", \"--force\"])\n        .arg(prj.root())\n        .assert_success()\n        .stdout_eq(str![[r#\"\nInitializing [..]...\nInstalling forge-std in [..] (url: https://github.com/foundry-rs/forge-std, tag: None)\n    Installed forge-std[..]\n    Initialized forge project\n\n\"#]])\n        .stderr_eq(str![[r#\"\nWarning: Target directory is not empty, but `--force` was specified\n...\n\n\"#]]);\n\n    let s = read_string(&foundry_toml);\n    let _config: BasicConfig = parse_with_profile(&s).unwrap().unwrap().1;\n});\n\n// Checks that a forge project fails to initialise if dir is already git repo and dirty\nforgetest!(can_detect_dirty_git_status_on_init, |prj, cmd| {\n    prj.wipe();\n\n    // initialize new git repo\n    cmd.git_init();\n\n    std::fs::write(prj.root().join(\"untracked.text\"), \"untracked\").unwrap();\n\n    // create nested dir and execute init in nested dir\n    let nested = prj.root().join(\"nested\");\n    fs::create_dir_all(&nested).unwrap();\n\n    cmd.current_dir(&nested);\n    cmd.args([\"init\", \"--commit\"]).assert_failure().stderr_eq(str![[r#\"\nError: The target directory is a part of or on its own an already initialized git repository,\nand it requires clean working and staging areas, including no untracked files.\n\nCheck the current git repository's status with `git status`.\nThen, you can track files with `git add ...` and then commit them with `git commit`,\nignore them in the `.gitignore` file.\n\n\"#]]);\n\n    // ensure nothing was emitted, dir is empty\n    assert!(!nested.read_dir().map(|mut i| i.next().is_some()).unwrap_or_default());\n});\n\n// Checks that a forge project can be initialized without creating a git repository\nforgetest!(can_init_no_git, |prj, cmd| {\n    prj.wipe();\n\n    cmd.arg(\"init\").arg(prj.root()).arg(\"--no-git\").assert_success().stdout_eq(str![[r#\"\nInitializing [..]...\nInstalling forge-std in [..] (url: https://github.com/foundry-rs/forge-std, tag: None)\n    Installed forge-std[..]\n    Initialized forge project\n\n\"#]]);\n    prj.assert_config_exists();\n\n    assert!(!prj.root().join(\".git\").exists());\n    assert!(prj.root().join(\"lib/forge-std\").exists());\n    assert!(!prj.root().join(\"lib/forge-std/.git\").exists());\n});\n\n// Checks that quiet mode does not print anything\nforgetest!(can_init_quiet, |prj, cmd| {\n    prj.wipe();\n\n    cmd.arg(\"init\").arg(prj.root()).arg(\"-q\").assert_empty_stdout();\n});\n\n// `forge init foobar` works with dir argument\nforgetest!(can_init_with_dir, |prj, cmd| {\n    prj.create_file(\"README.md\", \"non-empty dir\");\n    cmd.args([\"init\", \"foobar\"]);\n\n    cmd.assert_success();\n    assert!(prj.root().join(\"foobar\").exists());\n});\n\n// `forge init foobar --template [template]` works with dir argument\nforgetest!(can_init_with_dir_and_template, |prj, cmd| {\n    cmd.args([\"init\", \"foobar\", \"--template\", \"foundry-rs/forge-template\"])\n        .assert_success()\n        .stdout_eq(str![[r#\"\nInitializing [..] from https://github.com/foundry-rs/forge-template...\n    Initialized forge project\n\n\"#]]);\n\n    assert!(prj.root().join(\"foobar/.git\").exists());\n    assert!(prj.root().join(\"foobar/foundry.toml\").exists());\n    assert!(prj.root().join(\"foobar/lib/forge-std\").exists());\n    // assert that gitmodules were correctly initialized\n    assert!(prj.root().join(\"foobar/.git/modules\").exists());\n    assert!(prj.root().join(\"foobar/src\").exists());\n    assert!(prj.root().join(\"foobar/test\").exists());\n});\n\n// `forge init foobar --template [template] --branch [branch]` works with dir argument\nforgetest!(can_init_with_dir_and_template_and_branch, |prj, cmd| {\n    cmd.args([\n        \"init\",\n        \"foobar\",\n        \"--template\",\n        \"foundry-rs/forge-template\",\n        \"--branch\",\n        \"test/deployments\",\n    ])\n    .assert_success()\n    .stdout_eq(str![[r#\"\nInitializing [..] from https://github.com/foundry-rs/forge-template...\n    Initialized forge project\n\n\"#]]);\n\n    assert!(prj.root().join(\"foobar/.dapprc\").exists());\n    assert!(prj.root().join(\"foobar/lib/ds-test\").exists());\n    // assert that gitmodules were correctly initialized\n    assert!(prj.root().join(\"foobar/.git/modules\").exists());\n    assert!(prj.root().join(\"foobar/src\").exists());\n    assert!(prj.root().join(\"foobar/scripts\").exists());\n});\n\n// `forge init --force` works on non-empty dirs\nforgetest!(can_init_non_empty, |prj, cmd| {\n    prj.create_file(\"README.md\", \"non-empty dir\");\n    cmd.arg(\"init\").arg(prj.root()).assert_failure().stderr_eq(str![[r#\"\nError: Cannot run `init` on a non-empty directory.\nRun with the `--force` flag to initialize regardless.\n\n\"#]]);\n\n    cmd.arg(\"--force\")\n        .assert_success()\n        .stdout_eq(str![[r#\"\nInitializing [..]...\nInstalling forge-std in [..] (url: https://github.com/foundry-rs/forge-std, tag: None)\n    Installed forge-std[..]\n    Initialized forge project\n\n\"#]])\n        .stderr_eq(str![[r#\"\nWarning: Target directory is not empty, but `--force` was specified\n...\n\n\"#]]);\n\n    assert!(prj.root().join(\".git\").exists());\n    assert!(prj.root().join(\"lib/forge-std\").exists());\n});\n\n// `forge init --force` works on already initialized git repository\nforgetest!(can_init_in_empty_repo, |prj, cmd| {\n    let root = prj.root();\n\n    // initialize new git repo\n    let status = Command::new(\"git\")\n        .arg(\"init\")\n        .current_dir(root)\n        .stdout(Stdio::null())\n        .stderr(Stdio::null())\n        .status()\n        .expect(\"could not run git init\");\n    assert!(status.success());\n    assert!(root.join(\".git\").exists());\n\n    cmd.arg(\"init\").arg(root).assert_failure().stderr_eq(str![[r#\"\nError: Cannot run `init` on a non-empty directory.\nRun with the `--force` flag to initialize regardless.\n\n\"#]]);\n\n    cmd.arg(\"--force\")\n        .assert_success()\n        .stdout_eq(str![[r#\"\nInitializing [..]...\nInstalling forge-std in [..] (url: https://github.com/foundry-rs/forge-std, tag: None)\n    Installed forge-std[..]\n    Initialized forge project\n\n\"#]])\n        .stderr_eq(str![[r#\"\nWarning: Target directory is not empty, but `--force` was specified\n...\n\n\"#]]);\n\n    assert!(root.join(\"lib/forge-std\").exists());\n});\n\n// `forge init --force` works on already initialized git repository\nforgetest!(can_init_in_non_empty_repo, |prj, cmd| {\n    let root = prj.root();\n\n    // initialize new git repo\n    let status = Command::new(\"git\")\n        .arg(\"init\")\n        .current_dir(root)\n        .stdout(Stdio::null())\n        .stderr(Stdio::null())\n        .status()\n        .expect(\"could not run git init\");\n    assert!(status.success());\n    assert!(root.join(\".git\").exists());\n\n    prj.create_file(\"README.md\", \"non-empty dir\");\n    prj.create_file(\".gitignore\", \"not foundry .gitignore\");\n\n    cmd.arg(\"init\").arg(root).assert_failure().stderr_eq(str![[r#\"\nError: Cannot run `init` on a non-empty directory.\nRun with the `--force` flag to initialize regardless.\n\n\"#]]);\n\n    cmd.arg(\"--force\")\n        .assert_success()\n        .stdout_eq(str![[r#\"\nInitializing [..]...\nInstalling forge-std in [..] (url: https://github.com/foundry-rs/forge-std, tag: None)\n    Installed forge-std[..]\n    Initialized forge project\n\n\"#]])\n        .stderr_eq(str![[r#\"\nWarning: Target directory is not empty, but `--force` was specified\n...\n\n\"#]]);\n\n    assert!(root.join(\"lib/forge-std\").exists());\n\n    // not overwritten\n    let gitignore = root.join(\".gitignore\");\n    let gitignore = fs::read_to_string(gitignore).unwrap();\n    assert_eq!(gitignore, \"not foundry .gitignore\");\n});\n\n// `forge init --use-parent-git` works on already initialized git repository\nforgetest!(can_init_using_parent_repo, |prj, cmd| {\n    let root = prj.root();\n\n    // initialize new git repo\n    let status = Command::new(\"git\")\n        .arg(\"init\")\n        .current_dir(root)\n        .stdout(Stdio::null())\n        .stderr(Stdio::null())\n        .status()\n        .expect(\"could not run git init\");\n    assert!(status.success());\n    assert!(root.join(\".git\").exists());\n\n    prj.create_file(\"README.md\", \"non-empty dir\");\n    prj.create_file(\".gitignore\", \"not foundry .gitignore\");\n\n    let folder = \"foundry-folder\";\n    cmd.arg(\"init\").arg(folder).arg(\"--force\").arg(\"--use-parent-git\").assert_success().stdout_eq(\n        str![[r#\"\nInitializing [..]...\nInstalling forge-std in [..] (url: https://github.com/foundry-rs/forge-std, tag: None)\n    Installed forge-std[..]\n    Initialized forge project\n\n\"#]],\n    );\n\n    assert!(root.join(folder).join(\"lib/forge-std\").exists());\n\n    // not overwritten\n    let gitignore = root.join(\".gitignore\");\n    let gitignore = fs::read_to_string(gitignore).unwrap();\n    assert_eq!(gitignore, \"not foundry .gitignore\");\n\n    // submodules are registered at root\n    let gitmodules = root.join(\".gitmodules\");\n    let gitmodules = fs::read_to_string(gitmodules).unwrap();\n    assert!(gitmodules.contains(\n        \"\n\tpath = foundry-folder/lib/forge-std\n\turl = https://github.com/foundry-rs/forge-std\n\"\n    ));\n});\n\n// Checks that remappings.txt and .vscode/settings.json is generated\nforgetest!(can_init_vscode, |prj, cmd| {\n    prj.wipe();\n\n    cmd.arg(\"init\").arg(prj.root()).arg(\"--vscode\").assert_success().stdout_eq(str![[r#\"\nInitializing [..]...\nInstalling forge-std in [..] (url: https://github.com/foundry-rs/forge-std, tag: None)\n    Installed forge-std[..]\n    Initialized forge project\n\n\"#]]);\n\n    let settings = prj.root().join(\".vscode/settings.json\");\n    assert!(settings.is_file());\n    let settings: serde_json::Value = foundry_compilers::utils::read_json_file(&settings).unwrap();\n    assert_eq!(\n        settings,\n        serde_json::json!({\n            \"solidity.packageDefaultDependenciesContractsDirectory\": \"src\",\n            \"solidity.packageDefaultDependenciesDirectory\": \"lib\"\n        })\n    );\n\n    let remappings = prj.root().join(\"remappings.txt\");\n    assert!(remappings.is_file());\n    let content = std::fs::read_to_string(remappings).unwrap();\n    assert_eq!(content, \"forge-std/=lib/forge-std/src/\",);\n});\n\n// checks that forge can init with template\nforgetest!(can_init_template, |prj, cmd| {\n    prj.wipe();\n\n    cmd.args([\"init\", \"--template\", \"foundry-rs/forge-template\"])\n        .arg(prj.root())\n        .assert_success()\n        .stdout_eq(str![[r#\"\nInitializing [..] from https://github.com/foundry-rs/forge-template...\n    Initialized forge project\n\n\"#]]);\n\n    assert!(prj.root().join(\".git\").exists());\n    assert!(prj.root().join(\"foundry.toml\").exists());\n    assert!(prj.root().join(\"lib/forge-std\").exists());\n    // assert that gitmodules were correctly initialized\n    assert!(prj.root().join(\".git/modules\").exists());\n    assert!(prj.root().join(\"src\").exists());\n    assert!(prj.root().join(\"test\").exists());\n});\n\n// checks that forge can init with template and branch\nforgetest!(can_init_template_with_branch, |prj, cmd| {\n    prj.wipe();\n    cmd.args([\"init\", \"--template\", \"foundry-rs/forge-template\", \"--branch\", \"test/deployments\"])\n        .arg(prj.root())\n        .assert_success()\n        .stdout_eq(str![[r#\"\nInitializing [..] from https://github.com/foundry-rs/forge-template...\n    Initialized forge project\n\n\"#]]);\n\n    assert!(prj.root().join(\".git\").exists());\n    assert!(prj.root().join(\".dapprc\").exists());\n    assert!(prj.root().join(\"lib/ds-test\").exists());\n    // assert that gitmodules were correctly initialized\n    assert!(prj.root().join(\".git/modules\").exists());\n    assert!(prj.root().join(\"src\").exists());\n    assert!(prj.root().join(\"scripts\").exists());\n});\n\n// checks that init fails when the provided template doesn't exist\nforgetest!(fail_init_nonexistent_template, |prj, cmd| {\n    prj.wipe();\n    cmd.args([\"init\", \"--template\", \"a\"]).arg(prj.root()).assert_failure().stderr_eq(str![[r#\"\nremote: Not Found\nfatal: repository 'https://github.com/a/' not found\nError: git fetch exited with code 128\n\n\"#]]);\n});\n\n// checks that `forge init --template [template] works by default i.e without committing\nforgetest!(can_init_template_with_no_commit, |prj, cmd| {\n    prj.wipe();\n    cmd.args([\"init\", \"--template\", \"foundry-rs/forge-template\"])\n        .arg(prj.root())\n        .assert_success()\n        .stdout_eq(str![[r#\"\nInitializing [..] from https://github.com/foundry-rs/forge-template...\n    Initialized forge project\n\n\"#]]);\n\n    // show the latest commit message was not changed\n    let output = Command::new(\"git\")\n        .args([\"log\", \"-1\", \"--pretty=%s\"]) // Get the latest commit message\n        .output()\n        .expect(\"Failed to execute git command\");\n\n    let commit_message = String::from_utf8_lossy(&output.stdout);\n    assert!(\n        !commit_message.starts_with(\"chore: init from foundry-rs/forge-template\"),\n        \"Commit message should not start with 'chore: init from foundry-rs/forge-template'\"\n    );\n});\n\n// checks that clone works\nforgetest!(flaky_can_clone, |prj, cmd| {\n    prj.wipe();\n\n    let foundry_toml = prj.root().join(Config::FILE_NAME);\n    assert!(!foundry_toml.exists());\n\n    cmd.args([\n        \"clone\",\n        \"--etherscan-api-key\",\n        next_etherscan_api_key().as_str(),\n        \"0x044b75f554b886A065b9567891e45c79542d7357\",\n    ])\n    .arg(prj.root())\n    .assert_success()\n    .stdout_eq(str![[r#\"\nDownloading the source code of 0x044b75f554b886A065b9567891e45c79542d7357 from Etherscan...\nInitializing [..]...\nInstalling forge-std in [..] (url: https://github.com/foundry-rs/forge-std, tag: None)\n    Installed forge-std[..]\n    Initialized forge project\nCollecting the creation information of 0x044b75f554b886A065b9567891e45c79542d7357 from Etherscan...\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\n\"#]]);\n\n    let s = read_string(&foundry_toml);\n    let _config: BasicConfig = parse_with_profile(&s).unwrap().unwrap().1;\n});\n\n// Checks that quiet mode does not print anything for clone\nforgetest!(flaky_can_clone_quiet, |prj, cmd| {\n    prj.wipe();\n\n    cmd.args([\n        \"clone\",\n        \"--etherscan-api-key\",\n        next_etherscan_api_key().as_str(),\n        \"--quiet\",\n        \"0xDb53f47aC61FE54F456A4eb3E09832D08Dd7BEec\",\n    ])\n    .arg(prj.root())\n    .assert_empty_stdout();\n});\n\n// checks that clone works with sourcify\nforgetest!(flaky_can_clone_sourcify, |prj, cmd| {\n    prj.wipe();\n\n    let foundry_toml = prj.root().join(Config::FILE_NAME);\n    assert!(!foundry_toml.exists());\n\n    cmd.args([\"clone\", \"--source\", \"sourcify\", \"0xDb53f47aC61FE54F456A4eb3E09832D08Dd7BEec\"])\n        .arg(prj.root())\n        .assert_success()\n        .stdout_eq(str![[r#\"\nDownloading the source code of 0xDb53f47aC61FE54F456A4eb3E09832D08Dd7BEec from Sourcify...\nInitializing [..]...\nInstalling forge-std in [..] (url: https://github.com/foundry-rs/forge-std, tag: None)\n    Installed forge-std[..]\n    Initialized forge project\nCollecting the creation information of 0xDb53f47aC61FE54F456A4eb3E09832D08Dd7BEec from Sourcify...\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\n\"#]]);\n\n    let s = read_string(&foundry_toml);\n    let _config: BasicConfig = parse_with_profile(&s).unwrap().unwrap().1;\n});\n\n// checks that clone works with --no-remappings-txt\nforgetest!(flaky_can_clone_no_remappings_txt, |prj, cmd| {\n    prj.wipe();\n\n    let foundry_toml = prj.root().join(Config::FILE_NAME);\n    assert!(!foundry_toml.exists());\n\n    cmd.args([\n        \"clone\",\n        \"--etherscan-api-key\",\n        next_etherscan_api_key().as_str(),\n        \"--no-remappings-txt\",\n        \"0x33e690aEa97E4Ef25F0d140F1bf044d663091DAf\",\n    ])\n    .arg(prj.root())\n    .assert_success()\n    .stdout_eq(str![[r#\"\nDownloading the source code of 0x33e690aEa97E4Ef25F0d140F1bf044d663091DAf from Etherscan...\nInitializing [..]...\nInstalling forge-std in [..] (url: https://github.com/foundry-rs/forge-std, tag: None)\n    Installed forge-std[..]\n    Initialized forge project\nCollecting the creation information of 0x33e690aEa97E4Ef25F0d140F1bf044d663091DAf from Etherscan...\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\n\"#]]);\n\n    let s = read_string(&foundry_toml);\n    let _config: BasicConfig = parse_with_profile(&s).unwrap().unwrap().1;\n});\n\n// checks that clone works with --keep-directory-structure\nforgetest!(flaky_can_clone_keep_directory_structure, |prj, cmd| {\n    prj.wipe();\n\n    let foundry_toml = prj.root().join(Config::FILE_NAME);\n    assert!(!foundry_toml.exists());\n\n    let output = cmd\n        .forge_fuse()\n        .args([\n            \"clone\",\n            \"--etherscan-api-key\",\n            next_etherscan_api_key().as_str(),\n            \"--keep-directory-structure\",\n            \"0x33e690aEa97E4Ef25F0d140F1bf044d663091DAf\",\n        ])\n        .arg(prj.root())\n        .assert_success()\n        .get_output()\n        .stdout_lossy();\n\n    if output.contains(\"502 Bad Gateway\") {\n        // etherscan nginx proxy issue, skip this test:\n        //\n        // stdout:\n        // Downloading the source code of 0x33e690aEa97E4Ef25F0d140F1bf044d663091DAf from\n        // Etherscan... 2024-07-05T11:40:11.801765Z ERROR etherscan: Failed to deserialize\n        // response: expected value at line 1 column 1 res=\"<html>\\r\\n<head><title>502 Bad\n        // Gateway</title></head>\\r\\n<body>\\r\\n<center><h1>502 Bad\n        // Gateway</h1></center>\\r\\n<hr><center>nginx</center>\\r\\n</body>\\r\\n</html>\\r\\n\"\n\n        eprintln!(\"Skipping test due to 502 Bad Gateway\");\n        return;\n    }\n\n    let s = read_string(&foundry_toml);\n    let _config: BasicConfig = parse_with_profile(&s).unwrap().unwrap().1;\n});\n\n// checks that `forge init` works.\nforgetest!(can_init_project, |prj, cmd| {\n    prj.wipe();\n\n    cmd.args([\"init\"]).arg(prj.root()).assert_success().stdout_eq(str![[r#\"\nInitializing [..]...\nInstalling forge-std in [..] (url: https://github.com/foundry-rs/forge-std, tag: None)\n    Installed forge-std[..]\n    Initialized forge project\n\n\"#]]);\n\n    assert!(prj.root().join(\"foundry.toml\").exists());\n    assert!(prj.root().join(\"lib/forge-std\").exists());\n\n    assert!(prj.root().join(\"src\").exists());\n    assert!(prj.root().join(\"src\").join(\"Counter.sol\").exists());\n\n    assert!(prj.root().join(\"test\").exists());\n    assert!(prj.root().join(\"test\").join(\"Counter.t.sol\").exists());\n\n    assert!(prj.root().join(\"script\").exists());\n    assert!(prj.root().join(\"script\").join(\"Counter.s.sol\").exists());\n\n    assert!(prj.root().join(\".github\").join(\"workflows\").exists());\n    assert!(prj.root().join(\".github\").join(\"workflows\").join(\"test.yml\").exists());\n});\n\n// checks that `forge init --vyper` works.\nforgetest!(can_init_vyper_project, |prj, cmd| {\n    prj.wipe();\n\n    cmd.args([\"init\", \"--vyper\"]).arg(prj.root()).assert_success().stdout_eq(str![[r#\"\nInitializing [..]...\nInstalling forge-std in [..] (url: https://github.com/foundry-rs/forge-std, tag: None)\n    Installed forge-std[..]\n    Initialized forge project\n\n\"#]]);\n\n    assert!(prj.root().join(\"foundry.toml\").exists());\n    assert!(prj.root().join(\"lib/forge-std\").exists());\n\n    assert!(prj.root().join(\"src\").exists());\n    assert!(prj.root().join(\"src\").join(\"Counter.vy\").exists());\n    assert!(prj.root().join(\"src\").join(\"ICounter.sol\").exists());\n\n    assert!(prj.root().join(\"test\").exists());\n    assert!(prj.root().join(\"test\").join(\"Counter.t.sol\").exists());\n\n    assert!(prj.root().join(\"script\").exists());\n    assert!(prj.root().join(\"script\").join(\"Counter.s.sol\").exists());\n\n    assert!(prj.root().join(\".github\").join(\"workflows\").exists());\n    assert!(prj.root().join(\".github\").join(\"workflows\").join(\"test.yml\").exists());\n});\n\n// checks that `forge init --network tempo` works.\nforgetest!(can_init_tempo_project, |prj, cmd| {\n    prj.wipe();\n\n    cmd.args([\"init\", \"--network\", \"tempo\"]).arg(prj.root()).assert_success().stdout_eq(str![[\n        r#\"\nInitializing [..]...\nInstalling forge-std in [..] (url: https://github.com/foundry-rs/forge-std, tag: None)\n    Installed forge-std[..]\nInstalling tempo-std in [..] (url: https://github.com/tempoxyz/tempo-std, tag: None)\n    Installed tempo-std[..]\n    Initialized forge project\n\n\"#\n    ]]);\n\n    assert!(prj.root().join(\"foundry.toml\").exists());\n    assert!(prj.root().join(\"lib/forge-std\").exists());\n    assert!(prj.root().join(\"lib/tempo-std\").exists());\n\n    assert!(prj.root().join(\"src\").exists());\n    assert!(prj.root().join(\"src\").join(\"Mail.sol\").exists());\n\n    assert!(prj.root().join(\"test\").exists());\n    assert!(prj.root().join(\"test\").join(\"Mail.t.sol\").exists());\n\n    assert!(prj.root().join(\"script\").exists());\n    assert!(prj.root().join(\"script\").join(\"Mail.s.sol\").exists());\n\n    assert!(prj.root().join(\".github\").join(\"workflows\").exists());\n    assert!(prj.root().join(\".github\").join(\"workflows\").join(\"test.yml\").exists());\n\n    assert!(prj.root().join(\"README.md\").exists());\n});\n\n// checks that clone works with raw src containing `node_modules`\n// <https://github.com/foundry-rs/foundry/issues/10115>\nforgetest!(flaky_can_clone_with_node_modules, |prj, cmd| {\n    prj.wipe();\n\n    let foundry_toml = prj.root().join(Config::FILE_NAME);\n    assert!(!foundry_toml.exists());\n\n    cmd.args([\n        \"clone\",\n        \"--etherscan-api-key\",\n        next_etherscan_api_key().as_str(),\n        \"0xA3E217869460bEf59A1CfD0637e2875F9331e823\",\n    ])\n    .arg(prj.root())\n    .assert_success()\n    .stdout_eq(str![[r#\"\nDownloading the source code of 0xA3E217869460bEf59A1CfD0637e2875F9331e823 from Etherscan...\nInitializing [..]...\nInstalling forge-std in [..] (url: https://github.com/foundry-rs/forge-std, tag: None)\n    Installed forge-std[..]\n    Initialized forge project\nCollecting the creation information of 0xA3E217869460bEf59A1CfD0637e2875F9331e823 from Etherscan...\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\n\"#]]);\n});\n\n// checks that `clean` removes dapptools style paths\nforgetest!(can_clean, |prj, cmd| {\n    prj.assert_create_dirs_exists();\n    prj.assert_style_paths_exist(PathStyle::Dapptools);\n    cmd.arg(\"clean\");\n    cmd.assert_empty_stdout();\n    prj.assert_cleaned();\n});\n\n// checks that `clean` removes hardhat style paths\nforgetest!(can_clean_hardhat, PathStyle::HardHat, |prj, cmd| {\n    prj.assert_create_dirs_exists();\n    prj.assert_style_paths_exist(PathStyle::HardHat);\n    cmd.arg(\"clean\");\n    cmd.assert_empty_stdout();\n    prj.assert_cleaned();\n});\n\n// checks that `clean` also works with the \"out\" value set in Config\nforgetest_init!(can_clean_config, |prj, cmd| {\n    prj.initialize_default_contracts();\n    prj.update_config(|config| config.out = \"custom-out\".into());\n    cmd.arg(\"build\").assert_success().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\n\"#]]);\n\n    // default test contract is written in custom out directory\n    let artifact = prj.root().join(format!(\"custom-out/{TEMPLATE_TEST_CONTRACT_ARTIFACT_JSON}\"));\n    assert!(artifact.exists());\n\n    cmd.forge_fuse().arg(\"clean\").assert_empty_stdout();\n    assert!(!artifact.exists());\n});\n\n// checks that `clean` removes fuzz and invariant cache dirs\nforgetest_init!(can_clean_test_cache, |prj, cmd| {\n    prj.initialize_default_contracts();\n    prj.update_config(|config| {\n        config.fuzz = FuzzConfig::new(\"cache/fuzz\".into());\n        config.invariant = InvariantConfig::new(\"cache/invariant\".into());\n    });\n    // default test contract is written in custom out directory\n    let fuzz_cache_dir = prj.root().join(\"cache/fuzz\");\n    let _ = fs::create_dir(fuzz_cache_dir.clone());\n    let invariant_cache_dir = prj.root().join(\"cache/invariant\");\n    let _ = fs::create_dir(invariant_cache_dir.clone());\n\n    assert!(fuzz_cache_dir.exists());\n    assert!(invariant_cache_dir.exists());\n\n    cmd.forge_fuse().arg(\"clean\").assert_empty_stdout();\n    assert!(!fuzz_cache_dir.exists());\n    assert!(!invariant_cache_dir.exists());\n});\n\n// checks that extra output works\nforgetest_init!(can_emit_extra_output, |prj, cmd| {\n    prj.initialize_default_contracts();\n    prj.clear();\n\n    cmd.args([\"build\", \"--extra-output\", \"metadata\"]).assert_success().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\n\"#]]);\n\n    let artifact_path = prj.paths().artifacts.join(TEMPLATE_CONTRACT_ARTIFACT_JSON);\n    let artifact: ConfigurableContractArtifact =\n        foundry_compilers::utils::read_json_file(&artifact_path).unwrap();\n    assert!(artifact.metadata.is_some());\n\n    cmd.forge_fuse()\n        .args([\"build\", \"--extra-output-files\", \"metadata\", \"--force\"])\n        .root_arg()\n        .assert_success()\n        .stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\n\"#]]);\n\n    let metadata_path =\n        prj.paths().artifacts.join(format!(\"{TEMPLATE_CONTRACT_ARTIFACT_BASE}.metadata.json\"));\n    let _artifact: Metadata = foundry_compilers::utils::read_json_file(&metadata_path).unwrap();\n});\n\n// checks that extra output works\nforgetest_init!(can_emit_multiple_extra_output, |prj, cmd| {\n    prj.initialize_default_contracts();\n    cmd.args([\n        \"build\",\n        \"--extra-output\",\n        \"metadata\",\n        \"legacyAssembly\",\n        \"ir-optimized\",\n        \"--extra-output\",\n        \"ir\",\n    ])\n    .assert_success()\n    .stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\n\"#]]);\n\n    let artifact_path = prj.paths().artifacts.join(TEMPLATE_CONTRACT_ARTIFACT_JSON);\n    let artifact: ConfigurableContractArtifact =\n        foundry_compilers::utils::read_json_file(&artifact_path).unwrap();\n    assert!(artifact.metadata.is_some());\n    assert!(artifact.legacy_assembly.is_some());\n    assert!(artifact.ir.is_some());\n    assert!(artifact.ir_optimized.is_some());\n\n    cmd.forge_fuse()\n        .args([\n            \"build\",\n            \"--extra-output-files\",\n            \"metadata\",\n            \"ir-optimized\",\n            \"evm.bytecode.sourceMap\",\n            \"evm.legacyAssembly\",\n            \"--force\",\n        ])\n        .root_arg()\n        .assert_success()\n        .stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\n\"#]]);\n\n    let metadata_path =\n        prj.paths().artifacts.join(format!(\"{TEMPLATE_CONTRACT_ARTIFACT_BASE}.metadata.json\"));\n    let _artifact: Metadata = foundry_compilers::utils::read_json_file(&metadata_path).unwrap();\n\n    let iropt = prj.paths().artifacts.join(format!(\"{TEMPLATE_CONTRACT_ARTIFACT_BASE}.iropt\"));\n    std::fs::read_to_string(iropt).unwrap();\n\n    let sourcemap =\n        prj.paths().artifacts.join(format!(\"{TEMPLATE_CONTRACT_ARTIFACT_BASE}.sourcemap\"));\n    std::fs::read_to_string(sourcemap).unwrap();\n\n    let legacy_assembly = prj\n        .paths()\n        .artifacts\n        .join(format!(\"{TEMPLATE_CONTRACT_ARTIFACT_BASE}.legacyAssembly.json\"));\n    std::fs::read_to_string(legacy_assembly).unwrap();\n});\n\nforgetest!(can_print_warnings, |prj, cmd| {\n    prj.add_source(\n        \"Foo\",\n        r\"\ncontract Greeter {\n    function foo(uint256 a) public {\n        uint256 x = 1;\n    }\n}\n   \",\n    );\n\n    cmd.arg(\"build\").assert_success().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful with warnings:\nWarning (5667): Unused function parameter. Remove or comment out the variable name to silence this warning.\n [FILE]:5:18:\n  |\n5 |     function foo(uint256 a) public {\n  |                  ^^^^^^^^^\n\nWarning (2072): Unused local variable.\n [FILE]:6:9:\n  |\n6 |         uint256 x = 1;\n  |         ^^^^^^^^^\n\nWarning (2018): Function state mutability can be restricted to pure\n [FILE]:5:5:\n  |\n5 |     function foo(uint256 a) public {\n  |     ^ (Relevant source part starts here and spans across multiple lines).\n\n\n\"#]]);\n});\n\n// Tests that direct import paths are handled correctly\nforgetest!(can_handle_direct_imports_into_src, |prj, cmd| {\n    prj.add_source(\n        \"Foo\",\n        r#\"\nimport {FooLib} from \"src/FooLib.sol\";\nstruct Bar {\n    uint8 x;\n}\ncontract Foo {\n    mapping(uint256 => Bar) bars;\n    function checker(uint256 id) external {\n        Bar memory b = bars[id];\n        FooLib.check(b);\n    }\n    function checker2() external {\n        FooLib.check2(this);\n    }\n}\n   \"#,\n    );\n\n    prj.add_source(\n        \"FooLib\",\n        r#\"\nimport {Foo, Bar} from \"src/Foo.sol\";\nlibrary FooLib {\n    function check(Bar memory b) public {}\n    function check2(Foo f) public {}\n}\n   \"#,\n    );\n\n    cmd.arg(\"build\").assert_success().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\n\"#]]);\n});\n\n// tests that the `inspect` command works correctly\nforgetest!(can_execute_inspect_command, |prj, cmd| {\n    let contract_name = \"Foo\";\n    let path = prj.add_source(\n        contract_name,\n        r#\"\ncontract Foo {\n    event log_string(string);\n    function run() external {\n        emit log_string(\"script ran\");\n    }\n}\n    \"#,\n    );\n\n    cmd.arg(\"inspect\").arg(contract_name).arg(\"bytecode\").assert_success().stdout_eq(str![[r#\"\n0x60806040[..]\n\n\"#]]);\n\n    let info = format!(\"src/{}:{}\", path.file_name().unwrap().to_string_lossy(), contract_name);\n    cmd.forge_fuse().arg(\"inspect\").arg(info).arg(\"bytecode\").assert_success().stdout_eq(str![[\n        r#\"\n0x60806040[..]\n\n\"#\n    ]]);\n});\n\n// test that `forge snapshot` commands work\nforgetest!(can_check_snapshot, |prj, cmd| {\n    prj.insert_ds_test();\n\n    prj.add_source(\n        \"ATest.t.sol\",\n        r#\"\nimport \"./test.sol\";\ncontract ATest is DSTest {\n    function testExample() public {\n        assertTrue(true);\n    }\n}\n   \"#,\n    );\n\n    cmd.args([\"snapshot\"]).assert_success().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\nRan 1 test for src/ATest.t.sol:ATest\n[PASS] testExample() ([GAS])\nSuite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests)\n\n\"#]]);\n\n    cmd.arg(\"--check\").assert_success().stdout_eq(str![[r#\"\nNo files changed, compilation skipped\n\nRan 1 test for src/ATest.t.sol:ATest\n[PASS] testExample() ([GAS])\nSuite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests)\n\n\"#]]);\n});\n\n// test that `forge build` does not print `(with warnings)` if file path is ignored\nforgetest!(can_compile_without_warnings_ignored_file_paths, |prj, cmd| {\n    // Ignoring path and setting empty error_codes as default would set some error codes\n    prj.update_config(|config| {\n        config.ignored_file_paths = vec![Path::new(\"src\").to_path_buf()];\n        config.ignored_error_codes = vec![];\n    });\n\n    prj.add_raw_source(\n        \"src/example.sol\",\n        r\"\npragma solidity *;\ncontract A {\n    function testExample() public {}\n}\n\",\n    );\n\n    cmd.args([\"build\", \"--force\"]).assert_success().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\n\"#]]);\n\n    // Reconfigure without ignored paths or error codes and check for warnings\n    prj.update_config(|config| config.ignored_file_paths = vec![]);\n\n    cmd.forge_fuse().args([\"build\", \"--force\"]).assert_success().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful with warnings:\nWarning (1878): SPDX license identifier not provided in source file. Before publishing, consider adding a comment containing \"SPDX-License-Identifier: <SPDX-License>\" to each source file. Use \"SPDX-License-Identifier: UNLICENSED\" for non-open-source code. Please see https://spdx.org for more information.\nWarning: SPDX license identifier not provided in source file. Before publishing, consider adding a comment containing \"SPDX-License-Identifier: <SPDX-License>\" to each source file. Use \"SPDX-License-Identifier: UNLICENSED\" for non-open-source code. Please see https://spdx.org for more information.\n[FILE]\n\n\n\"#]]);\n});\n\n// test that `forge build` does not print `(with warnings)` if there aren't any\nforgetest!(can_compile_without_warnings, |prj, cmd| {\n    prj.update_config(|config| {\n        config.ignored_error_codes = vec![SolidityErrorCode::SpdxLicenseNotProvided];\n    });\n    prj.add_raw_source(\n        \"A\",\n        r\"\npragma solidity *;\ncontract A {\n    function testExample() public {}\n}\n   \",\n    );\n\n    cmd.args([\"build\", \"--force\"]).assert_success().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\n\"#]]);\n\n    // don't ignore errors\n    prj.update_config(|config| {\n        config.ignored_error_codes = vec![];\n    });\n\n    cmd.forge_fuse().args([\"build\", \"--force\"]).assert_success().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful with warnings:\nWarning (1878): SPDX license identifier not provided in source file. Before publishing, consider adding a comment containing \"SPDX-License-Identifier: <SPDX-License>\" to each source file. Use \"SPDX-License-Identifier: UNLICENSED\" for non-open-source code. Please see https://spdx.org for more information.\nWarning: SPDX license identifier not provided in source file. Before publishing, consider adding a comment containing \"SPDX-License-Identifier: <SPDX-License>\" to each source file. Use \"SPDX-License-Identifier: UNLICENSED\" for non-open-source code. Please see https://spdx.org for more information.\n[FILE]\n\n\n\"#]]);\n});\n\n// test that `forge build` compiles when severity set to error, fails when set to warning, and\n// handles ignored error codes as an exception\nforgetest!(can_fail_compile_with_warnings, |prj, cmd| {\n    prj.update_config(|config| {\n        config.ignored_error_codes = vec![];\n        config.deny = DenyLevel::Never;\n    });\n    prj.add_raw_source(\n        \"A\",\n        r\"\npragma solidity *;\ncontract A {\n    function testExample() public {}\n}\n   \",\n    );\n\n    // there are no errors\n    cmd.args([\"build\", \"--force\"]).assert_success().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful with warnings:\nWarning (1878): SPDX license identifier not provided in source file. Before publishing, consider adding a comment containing \"SPDX-License-Identifier: <SPDX-License>\" to each source file. Use \"SPDX-License-Identifier: UNLICENSED\" for non-open-source code. Please see https://spdx.org for more information.\nWarning: SPDX license identifier not provided in source file. Before publishing, consider adding a comment containing \"SPDX-License-Identifier: <SPDX-License>\" to each source file. Use \"SPDX-License-Identifier: UNLICENSED\" for non-open-source code. Please see https://spdx.org for more information.\n[FILE]\n\n\n\"#]]);\n\n    // warning fails to compile\n    prj.update_config(|config| {\n        config.ignored_error_codes = vec![];\n        config.deny = DenyLevel::Warnings;\n    });\n\n    cmd.forge_fuse().args([\"build\", \"--force\"]).assert_failure().stderr_eq(str![[r#\"\nError: Compiler run failed:\nWarning (1878): SPDX license identifier not provided in source file. Before publishing, consider adding a comment containing \"SPDX-License-Identifier: <SPDX-License>\" to each source file. Use \"SPDX-License-Identifier: UNLICENSED\" for non-open-source code. Please see https://spdx.org for more information.\nWarning: SPDX license identifier not provided in source file. Before publishing, consider adding a comment containing \"SPDX-License-Identifier: <SPDX-License>\" to each source file. Use \"SPDX-License-Identifier: UNLICENSED\" for non-open-source code. Please see https://spdx.org for more information.\n[FILE]\n\n\"#]]);\n\n    // ignores error code and compiles\n    prj.update_config(|config| {\n        config.ignored_error_codes = vec![SolidityErrorCode::SpdxLicenseNotProvided];\n        config.deny = DenyLevel::Warnings;\n    });\n\n    cmd.forge_fuse().args([\"build\", \"--force\"]).assert_success().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\n\"#]]);\n});\n\n// test that a failing `forge build` does not impact followup builds\nforgetest!(can_build_after_failure, |prj, cmd| {\n    prj.insert_ds_test();\n\n    // Disable linting during build to avoid linting output interfering with test assertions\n    prj.update_config(|config| {\n        config.lint.lint_on_build = false;\n    });\n\n    prj.add_source(\n        \"ATest.t.sol\",\n        r#\"\nimport \"./test.sol\";\ncontract ATest is DSTest {\n    function testExample() public {\n        assertTrue(true);\n    }\n}\n   \"#,\n    );\n    prj.add_source(\n        \"BTest.t.sol\",\n        r#\"\nimport \"./test.sol\";\ncontract BTest is DSTest {\n    function testExample() public {\n        assertTrue(true);\n    }\n}\n   \"#,\n    );\n\n    cmd.arg(\"build\").assert_success().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n...\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\n\"#]]);\n\n    prj.assert_cache_exists();\n    prj.assert_artifacts_dir_exists();\n\n    let syntax_err = r#\"\nimport \"./test.sol\";\ncontract CTest is DSTest {\n    function testExample() public {\n        THIS WILL CAUSE AN ERROR\n    }\n}\n   \"#;\n\n    // introduce contract with syntax error\n    prj.add_source(\"CTest.t.sol\", syntax_err);\n\n    // `forge build --force` which should fail\n    cmd.forge_fuse().args([\"build\", \"--force\"]).assert_failure().stderr_eq(str![[r#\"\nError: Compiler run failed:\nError (2314): Expected ';' but got identifier\n [FILE]:7:19:\n  |\n7 |         THIS WILL CAUSE AN ERROR\n  |                   ^^^^^\n\n\"#]]);\n\n    // but ensure this cleaned cache and artifacts\n    assert!(!prj.paths().artifacts.exists());\n    assert!(!prj.cache().exists());\n\n    // still errors\n    cmd.forge_fuse().args([\"build\", \"--force\"]).assert_failure().stderr_eq(str![[r#\"\nError: Compiler run failed:\nError (2314): Expected ';' but got identifier\n [FILE]:7:19:\n  |\n7 |         THIS WILL CAUSE AN ERROR\n  |                   ^^^^^\n\n\"#]]);\n\n    // resolve the error by replacing the file\n    prj.add_source(\n        \"CTest.t.sol\",\n        r#\"\nimport \"./test.sol\";\ncontract CTest is DSTest {\n    function testExample() public {\n         assertTrue(true);\n    }\n}\n   \"#,\n    );\n\n    cmd.forge_fuse().args([\"build\", \"--force\"]).assert_success().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\n\"#]]);\n\n    prj.assert_cache_exists();\n    prj.assert_artifacts_dir_exists();\n\n    // ensure cache is unchanged after error\n    let cache = fs::read_to_string(prj.cache()).unwrap();\n\n    // introduce the error again but building without force\n    prj.add_source(\"CTest.t.sol\", syntax_err);\n    cmd.forge_fuse().arg(\"build\").assert_failure().stderr_eq(str![[r#\"\nError: Compiler run failed:\nError (2314): Expected ';' but got identifier\n [FILE]:7:19:\n  |\n7 |         THIS WILL CAUSE AN ERROR\n  |                   ^^^^^\n\n\"#]]);\n\n    // ensure unchanged cache file\n    let cache_after = fs::read_to_string(prj.cache()).unwrap();\n    assert_eq!(cache, cache_after);\n});\n\nconst GAS_REPORT_CONTRACTS: &str = r#\"\n//SPDX-license-identifier: MIT\n\nimport \"./test.sol\";\n\ncontract ContractOne {\n    int public i;\n\n    constructor() {\n        i = 0;\n    }\n\n    function foo() public{\n        while(i<5){\n            i++;\n        }\n    }\n}\n\ncontract ContractOneTest is DSTest {\n    ContractOne c1;\n\n    function setUp() public {\n        c1 = new ContractOne();\n    }\n\n    function testFoo() public {\n        c1.foo();\n    }\n}\n\n\ncontract ContractTwo {\n    int public i;\n\n    constructor() {\n        i = 0;\n    }\n\n    function bar() public{\n        while(i<50){\n            i++;\n        }\n    }\n}\n\ncontract ContractTwoTest is DSTest {\n    ContractTwo c2;\n\n    function setUp() public {\n        c2 = new ContractTwo();\n    }\n\n    function testBar() public {\n        c2.bar();\n    }\n}\n\ncontract ContractThree {\n    int public i;\n\n    constructor() {\n        i = 0;\n    }\n\n    function baz() public{\n        while(i<500){\n            i++;\n        }\n    }\n}\n\ncontract ContractThreeTest is DSTest {\n    ContractThree c3;\n\n    function setUp() public {\n        c3 = new ContractThree();\n    }\n\n    function testBaz() public {\n        c3.baz();\n    }\n}\n\"#;\n\nforgetest!(gas_report_all_contracts, |prj, cmd| {\n    prj.insert_ds_test();\n    prj.add_source(\"Contracts.sol\", GAS_REPORT_CONTRACTS);\n\n    // report for all\n    prj.update_config(|config| {\n        config.gas_reports = vec![\"*\".to_string()];\n        config.gas_reports_ignore = vec![];\n    });\n\n    cmd.forge_fuse().arg(\"test\").arg(\"--gas-report\").assert_success().stdout_eq(str![[r#\"\n...\n╭----------------------------------------+-----------------+-------+--------+-------+---------╮\n| src/Contracts.sol:ContractOne Contract |                 |       |        |       |         |\n+=============================================================================================+\n| Deployment Cost                        | Deployment Size |       |        |       |         |\n|----------------------------------------+-----------------+-------+--------+-------+---------|\n|                                 133027 |             394 |       |        |       |         |\n|----------------------------------------+-----------------+-------+--------+-------+---------|\n|                                        |                 |       |        |       |         |\n|----------------------------------------+-----------------+-------+--------+-------+---------|\n| Function Name                          | Min             | Avg   | Median | Max   | # Calls |\n|----------------------------------------+-----------------+-------+--------+-------+---------|\n| foo                                    |           45656 | 45656 |  45656 | 45656 |       1 |\n╰----------------------------------------+-----------------+-------+--------+-------+---------╯\n\n╭------------------------------------------+-----------------+--------+--------+--------+---------╮\n| src/Contracts.sol:ContractThree Contract |                 |        |        |        |         |\n+=================================================================================================+\n| Deployment Cost                          | Deployment Size |        |        |        |         |\n|------------------------------------------+-----------------+--------+--------+--------+---------|\n|                                   133243 |             395 |        |        |        |         |\n|------------------------------------------+-----------------+--------+--------+--------+---------|\n|                                          |                 |        |        |        |         |\n|------------------------------------------+-----------------+--------+--------+--------+---------|\n| Function Name                            | Min             | Avg    | Median | Max    | # Calls |\n|------------------------------------------+-----------------+--------+--------+--------+---------|\n| baz                                      |          287711 | 287711 | 287711 | 287711 |       1 |\n╰------------------------------------------+-----------------+--------+--------+--------+---------╯\n\n╭----------------------------------------+-----------------+-------+--------+-------+---------╮\n| src/Contracts.sol:ContractTwo Contract |                 |       |        |       |         |\n+=============================================================================================+\n| Deployment Cost                        | Deployment Size |       |        |       |         |\n|----------------------------------------+-----------------+-------+--------+-------+---------|\n|                                 133027 |             394 |       |        |       |         |\n|----------------------------------------+-----------------+-------+--------+-------+---------|\n|                                        |                 |       |        |       |         |\n|----------------------------------------+-----------------+-------+--------+-------+---------|\n| Function Name                          | Min             | Avg   | Median | Max   | # Calls |\n|----------------------------------------+-----------------+-------+--------+-------+---------|\n| bar                                    |           67683 | 67683 |  67683 | 67683 |       1 |\n╰----------------------------------------+-----------------+-------+--------+-------+---------╯\n\n\nRan 3 test suites [ELAPSED]: 3 tests passed, 0 failed, 0 skipped (3 total tests)\n\n\"#]]);\n    cmd.forge_fuse().arg(\"test\").arg(\"--gas-report\").arg(\"--json\").assert_success().stdout_eq(\n        str![[r#\"\n[\n  {\n    \"contract\": \"src/Contracts.sol:ContractOne\",\n    \"deployment\": {\n      \"gas\": 133027,\n      \"size\": 394\n    },\n    \"functions\": {\n      \"foo()\": {\n        \"calls\": 1,\n        \"min\": 45656,\n        \"mean\": 45656,\n        \"median\": 45656,\n        \"max\": 45656\n      }\n    }\n  },\n  {\n    \"contract\": \"src/Contracts.sol:ContractThree\",\n    \"deployment\": {\n      \"gas\": 133243,\n      \"size\": 395\n    },\n    \"functions\": {\n      \"baz()\": {\n        \"calls\": 1,\n        \"min\": 287711,\n        \"mean\": 287711,\n        \"median\": 287711,\n        \"max\": 287711\n      }\n    }\n  },\n  {\n    \"contract\": \"src/Contracts.sol:ContractTwo\",\n    \"deployment\": {\n      \"gas\": 133027,\n      \"size\": 394\n    },\n    \"functions\": {\n      \"bar()\": {\n        \"calls\": 1,\n        \"min\": 67683,\n        \"mean\": 67683,\n        \"median\": 67683,\n        \"max\": 67683\n      }\n    }\n  }\n]\n\"#]]\n        .is_json(),\n    );\n\n    prj.update_config(|config| config.gas_reports = vec![]);\n    cmd.forge_fuse().arg(\"test\").arg(\"--gas-report\").assert_success().stdout_eq(str![[r#\"\n...\n╭----------------------------------------+-----------------+-------+--------+-------+---------╮\n| src/Contracts.sol:ContractOne Contract |                 |       |        |       |         |\n+=============================================================================================+\n| Deployment Cost                        | Deployment Size |       |        |       |         |\n|----------------------------------------+-----------------+-------+--------+-------+---------|\n|                                 133027 |             394 |       |        |       |         |\n|----------------------------------------+-----------------+-------+--------+-------+---------|\n|                                        |                 |       |        |       |         |\n|----------------------------------------+-----------------+-------+--------+-------+---------|\n| Function Name                          | Min             | Avg   | Median | Max   | # Calls |\n|----------------------------------------+-----------------+-------+--------+-------+---------|\n| foo                                    |           45656 | 45656 |  45656 | 45656 |       1 |\n╰----------------------------------------+-----------------+-------+--------+-------+---------╯\n\n╭------------------------------------------+-----------------+--------+--------+--------+---------╮\n| src/Contracts.sol:ContractThree Contract |                 |        |        |        |         |\n+=================================================================================================+\n| Deployment Cost                          | Deployment Size |        |        |        |         |\n|------------------------------------------+-----------------+--------+--------+--------+---------|\n|                                   133243 |             395 |        |        |        |         |\n|------------------------------------------+-----------------+--------+--------+--------+---------|\n|                                          |                 |        |        |        |         |\n|------------------------------------------+-----------------+--------+--------+--------+---------|\n| Function Name                            | Min             | Avg    | Median | Max    | # Calls |\n|------------------------------------------+-----------------+--------+--------+--------+---------|\n| baz                                      |          287711 | 287711 | 287711 | 287711 |       1 |\n╰------------------------------------------+-----------------+--------+--------+--------+---------╯\n\n╭----------------------------------------+-----------------+-------+--------+-------+---------╮\n| src/Contracts.sol:ContractTwo Contract |                 |       |        |       |         |\n+=============================================================================================+\n| Deployment Cost                        | Deployment Size |       |        |       |         |\n|----------------------------------------+-----------------+-------+--------+-------+---------|\n|                                 133027 |             394 |       |        |       |         |\n|----------------------------------------+-----------------+-------+--------+-------+---------|\n|                                        |                 |       |        |       |         |\n|----------------------------------------+-----------------+-------+--------+-------+---------|\n| Function Name                          | Min             | Avg   | Median | Max   | # Calls |\n|----------------------------------------+-----------------+-------+--------+-------+---------|\n| bar                                    |           67683 | 67683 |  67683 | 67683 |       1 |\n╰----------------------------------------+-----------------+-------+--------+-------+---------╯\n\n\nRan 3 test suites [ELAPSED]: 3 tests passed, 0 failed, 0 skipped (3 total tests)\n\n\"#]]);\n    cmd.forge_fuse().arg(\"test\").arg(\"--gas-report\").arg(\"--json\").assert_success().stdout_eq(\n        str![[r#\"\n[\n  {\n    \"contract\": \"src/Contracts.sol:ContractOne\",\n    \"deployment\": {\n      \"gas\": 133027,\n      \"size\": 394\n    },\n    \"functions\": {\n      \"foo()\": {\n        \"calls\": 1,\n        \"min\": 45656,\n        \"mean\": 45656,\n        \"median\": 45656,\n        \"max\": 45656\n      }\n    }\n  },\n  {\n    \"contract\": \"src/Contracts.sol:ContractThree\",\n    \"deployment\": {\n      \"gas\": 133243,\n      \"size\": 395\n    },\n    \"functions\": {\n      \"baz()\": {\n        \"calls\": 1,\n        \"min\": 287711,\n        \"mean\": 287711,\n        \"median\": 287711,\n        \"max\": 287711\n      }\n    }\n  },\n  {\n    \"contract\": \"src/Contracts.sol:ContractTwo\",\n    \"deployment\": {\n      \"gas\": 133027,\n      \"size\": 394\n    },\n    \"functions\": {\n      \"bar()\": {\n        \"calls\": 1,\n        \"min\": 67683,\n        \"mean\": 67683,\n        \"median\": 67683,\n        \"max\": 67683\n      }\n    }\n  }\n]\n\"#]]\n        .is_json(),\n    );\n\n    prj.update_config(|config| config.gas_reports = vec![\"*\".to_string()]);\n    cmd.forge_fuse().arg(\"test\").arg(\"--gas-report\").assert_success().stdout_eq(str![[r#\"\n...\n╭----------------------------------------+-----------------+-------+--------+-------+---------╮\n| src/Contracts.sol:ContractOne Contract |                 |       |        |       |         |\n+=============================================================================================+\n| Deployment Cost                        | Deployment Size |       |        |       |         |\n|----------------------------------------+-----------------+-------+--------+-------+---------|\n|                                 133027 |             394 |       |        |       |         |\n|----------------------------------------+-----------------+-------+--------+-------+---------|\n|                                        |                 |       |        |       |         |\n|----------------------------------------+-----------------+-------+--------+-------+---------|\n| Function Name                          | Min             | Avg   | Median | Max   | # Calls |\n|----------------------------------------+-----------------+-------+--------+-------+---------|\n| foo                                    |           45656 | 45656 |  45656 | 45656 |       1 |\n╰----------------------------------------+-----------------+-------+--------+-------+---------╯\n\n╭------------------------------------------+-----------------+--------+--------+--------+---------╮\n| src/Contracts.sol:ContractThree Contract |                 |        |        |        |         |\n+=================================================================================================+\n| Deployment Cost                          | Deployment Size |        |        |        |         |\n|------------------------------------------+-----------------+--------+--------+--------+---------|\n|                                   133243 |             395 |        |        |        |         |\n|------------------------------------------+-----------------+--------+--------+--------+---------|\n|                                          |                 |        |        |        |         |\n|------------------------------------------+-----------------+--------+--------+--------+---------|\n| Function Name                            | Min             | Avg    | Median | Max    | # Calls |\n|------------------------------------------+-----------------+--------+--------+--------+---------|\n| baz                                      |          287711 | 287711 | 287711 | 287711 |       1 |\n╰------------------------------------------+-----------------+--------+--------+--------+---------╯\n\n╭----------------------------------------+-----------------+-------+--------+-------+---------╮\n| src/Contracts.sol:ContractTwo Contract |                 |       |        |       |         |\n+=============================================================================================+\n| Deployment Cost                        | Deployment Size |       |        |       |         |\n|----------------------------------------+-----------------+-------+--------+-------+---------|\n|                                 133027 |             394 |       |        |       |         |\n|----------------------------------------+-----------------+-------+--------+-------+---------|\n|                                        |                 |       |        |       |         |\n|----------------------------------------+-----------------+-------+--------+-------+---------|\n| Function Name                          | Min             | Avg   | Median | Max   | # Calls |\n|----------------------------------------+-----------------+-------+--------+-------+---------|\n| bar                                    |           67683 | 67683 |  67683 | 67683 |       1 |\n╰----------------------------------------+-----------------+-------+--------+-------+---------╯\n\n\nRan 3 test suites [ELAPSED]: 3 tests passed, 0 failed, 0 skipped (3 total tests)\n\n\"#]]);\n    cmd.forge_fuse().arg(\"test\").arg(\"--gas-report\").arg(\"--json\").assert_success().stdout_eq(\n        str![[r#\"\n[\n  {\n    \"contract\": \"src/Contracts.sol:ContractOne\",\n    \"deployment\": {\n      \"gas\": 133027,\n      \"size\": 394\n    },\n    \"functions\": {\n      \"foo()\": {\n        \"calls\": 1,\n        \"min\": 45656,\n        \"mean\": 45656,\n        \"median\": 45656,\n        \"max\": 45656\n      }\n    }\n  },\n  {\n    \"contract\": \"src/Contracts.sol:ContractThree\",\n    \"deployment\": {\n      \"gas\": 133243,\n      \"size\": 395\n    },\n    \"functions\": {\n      \"baz()\": {\n        \"calls\": 1,\n        \"min\": 287711,\n        \"mean\": 287711,\n        \"median\": 287711,\n        \"max\": 287711\n      }\n    }\n  },\n  {\n    \"contract\": \"src/Contracts.sol:ContractTwo\",\n    \"deployment\": {\n      \"gas\": 133027,\n      \"size\": 394\n    },\n    \"functions\": {\n      \"bar()\": {\n        \"calls\": 1,\n        \"min\": 67683,\n        \"mean\": 67683,\n        \"median\": 67683,\n        \"max\": 67683\n      }\n    }\n  }\n]\n\"#]]\n        .is_json(),\n    );\n\n    prj.update_config(|config| {\n        config.gas_reports =\n            vec![\"ContractOne\".to_string(), \"ContractTwo\".to_string(), \"ContractThree\".to_string()];\n    });\n    cmd.forge_fuse().arg(\"test\").arg(\"--gas-report\").assert_success().stdout_eq(str![[r#\"\n...\n╭----------------------------------------+-----------------+-------+--------+-------+---------╮\n| src/Contracts.sol:ContractOne Contract |                 |       |        |       |         |\n+=============================================================================================+\n| Deployment Cost                        | Deployment Size |       |        |       |         |\n|----------------------------------------+-----------------+-------+--------+-------+---------|\n|                                 133027 |             394 |       |        |       |         |\n|----------------------------------------+-----------------+-------+--------+-------+---------|\n|                                        |                 |       |        |       |         |\n|----------------------------------------+-----------------+-------+--------+-------+---------|\n| Function Name                          | Min             | Avg   | Median | Max   | # Calls |\n|----------------------------------------+-----------------+-------+--------+-------+---------|\n| foo                                    |           45656 | 45656 |  45656 | 45656 |       1 |\n╰----------------------------------------+-----------------+-------+--------+-------+---------╯\n\n╭------------------------------------------+-----------------+--------+--------+--------+---------╮\n| src/Contracts.sol:ContractThree Contract |                 |        |        |        |         |\n+=================================================================================================+\n| Deployment Cost                          | Deployment Size |        |        |        |         |\n|------------------------------------------+-----------------+--------+--------+--------+---------|\n|                                   133243 |             395 |        |        |        |         |\n|------------------------------------------+-----------------+--------+--------+--------+---------|\n|                                          |                 |        |        |        |         |\n|------------------------------------------+-----------------+--------+--------+--------+---------|\n| Function Name                            | Min             | Avg    | Median | Max    | # Calls |\n|------------------------------------------+-----------------+--------+--------+--------+---------|\n| baz                                      |          287711 | 287711 | 287711 | 287711 |       1 |\n╰------------------------------------------+-----------------+--------+--------+--------+---------╯\n\n╭----------------------------------------+-----------------+-------+--------+-------+---------╮\n| src/Contracts.sol:ContractTwo Contract |                 |       |        |       |         |\n+=============================================================================================+\n| Deployment Cost                        | Deployment Size |       |        |       |         |\n|----------------------------------------+-----------------+-------+--------+-------+---------|\n|                                 133027 |             394 |       |        |       |         |\n|----------------------------------------+-----------------+-------+--------+-------+---------|\n|                                        |                 |       |        |       |         |\n|----------------------------------------+-----------------+-------+--------+-------+---------|\n| Function Name                          | Min             | Avg   | Median | Max   | # Calls |\n|----------------------------------------+-----------------+-------+--------+-------+---------|\n| bar                                    |           67683 | 67683 |  67683 | 67683 |       1 |\n╰----------------------------------------+-----------------+-------+--------+-------+---------╯\n\n\nRan 3 test suites [ELAPSED]: 3 tests passed, 0 failed, 0 skipped (3 total tests)\n\n\"#]]);\n    cmd.forge_fuse().arg(\"test\").arg(\"--gas-report\").arg(\"--json\").assert_success().stdout_eq(\n        str![[r#\"\n[\n  {\n    \"contract\": \"src/Contracts.sol:ContractOne\",\n    \"deployment\": {\n      \"gas\": 133027,\n      \"size\": 394\n    },\n    \"functions\": {\n      \"foo()\": {\n        \"calls\": 1,\n        \"min\": 45656,\n        \"mean\": 45656,\n        \"median\": 45656,\n        \"max\": 45656\n      }\n    }\n  },\n  {\n    \"contract\": \"src/Contracts.sol:ContractThree\",\n    \"deployment\": {\n      \"gas\": 133243,\n      \"size\": 395\n    },\n    \"functions\": {\n      \"baz()\": {\n        \"calls\": 1,\n        \"min\": 287711,\n        \"mean\": 287711,\n        \"median\": 287711,\n        \"max\": 287711\n      }\n    }\n  },\n  {\n    \"contract\": \"src/Contracts.sol:ContractTwo\",\n    \"deployment\": {\n      \"gas\": 133027,\n      \"size\": 394\n    },\n    \"functions\": {\n      \"bar()\": {\n        \"calls\": 1,\n        \"min\": 67683,\n        \"mean\": 67683,\n        \"median\": 67683,\n        \"max\": 67683\n      }\n    }\n  }\n]\n\"#]]\n        .is_json(),\n    );\n});\n\nforgetest!(gas_report_some_contracts, |prj, cmd| {\n    prj.insert_ds_test();\n    prj.add_source(\"Contracts.sol\", GAS_REPORT_CONTRACTS);\n\n    // report for One\n    prj.update_config(|config| config.gas_reports = vec![\"ContractOne\".to_string()]);\n    cmd.forge_fuse();\n    cmd.arg(\"test\").arg(\"--gas-report\").assert_success().stdout_eq(str![[r#\"\n...\n╭----------------------------------------+-----------------+-------+--------+-------+---------╮\n| src/Contracts.sol:ContractOne Contract |                 |       |        |       |         |\n+=============================================================================================+\n| Deployment Cost                        | Deployment Size |       |        |       |         |\n|----------------------------------------+-----------------+-------+--------+-------+---------|\n|                                 133027 |             394 |       |        |       |         |\n|----------------------------------------+-----------------+-------+--------+-------+---------|\n|                                        |                 |       |        |       |         |\n|----------------------------------------+-----------------+-------+--------+-------+---------|\n| Function Name                          | Min             | Avg   | Median | Max   | # Calls |\n|----------------------------------------+-----------------+-------+--------+-------+---------|\n| foo                                    |           45656 | 45656 |  45656 | 45656 |       1 |\n╰----------------------------------------+-----------------+-------+--------+-------+---------╯\n\n\nRan 3 test suites [ELAPSED]: 3 tests passed, 0 failed, 0 skipped (3 total tests)\n\n\"#]]);\n    cmd.forge_fuse().arg(\"test\").arg(\"--gas-report\").arg(\"--json\").assert_success().stdout_eq(\n        str![[r#\"\n[\n  {\n    \"contract\": \"src/Contracts.sol:ContractOne\",\n    \"deployment\": {\n      \"gas\": 133027,\n      \"size\": 394\n    },\n    \"functions\": {\n      \"foo()\": {\n        \"calls\": 1,\n        \"min\": 45656,\n        \"mean\": 45656,\n        \"median\": 45656,\n        \"max\": 45656\n      }\n    }\n  }\n]\n\"#]]\n        .is_json(),\n    );\n\n    // report for Two\n    prj.update_config(|config| config.gas_reports = vec![\"ContractTwo\".to_string()]);\n    cmd.forge_fuse();\n    cmd.arg(\"test\").arg(\"--gas-report\").assert_success().stdout_eq(str![[r#\"\n...\n╭----------------------------------------+-----------------+-------+--------+-------+---------╮\n| src/Contracts.sol:ContractTwo Contract |                 |       |        |       |         |\n+=============================================================================================+\n| Deployment Cost                        | Deployment Size |       |        |       |         |\n|----------------------------------------+-----------------+-------+--------+-------+---------|\n|                                 133027 |             394 |       |        |       |         |\n|----------------------------------------+-----------------+-------+--------+-------+---------|\n|                                        |                 |       |        |       |         |\n|----------------------------------------+-----------------+-------+--------+-------+---------|\n| Function Name                          | Min             | Avg   | Median | Max   | # Calls |\n|----------------------------------------+-----------------+-------+--------+-------+---------|\n| bar                                    |           67683 | 67683 |  67683 | 67683 |       1 |\n╰----------------------------------------+-----------------+-------+--------+-------+---------╯\n\n\nRan 3 test suites [ELAPSED]: 3 tests passed, 0 failed, 0 skipped (3 total tests)\n\n\"#]]);\n    cmd.forge_fuse().arg(\"test\").arg(\"--gas-report\").arg(\"--json\").assert_success().stdout_eq(\n        str![[r#\"\n[\n  {\n    \"contract\": \"src/Contracts.sol:ContractTwo\",\n    \"deployment\": {\n      \"gas\": 133027,\n      \"size\": 394\n    },\n    \"functions\": {\n      \"bar()\": {\n        \"calls\": 1,\n        \"min\": 67683,\n        \"mean\": 67683,\n        \"median\": 67683,\n        \"max\": 67683\n      }\n    }\n  }\n]\n\"#]]\n        .is_json(),\n    );\n\n    // report for Three\n    prj.update_config(|config| config.gas_reports = vec![\"ContractThree\".to_string()]);\n    cmd.forge_fuse();\n    cmd.arg(\"test\").arg(\"--gas-report\").assert_success().stdout_eq(str![[r#\"\n...\n╭------------------------------------------+-----------------+--------+--------+--------+---------╮\n| src/Contracts.sol:ContractThree Contract |                 |        |        |        |         |\n+=================================================================================================+\n| Deployment Cost                          | Deployment Size |        |        |        |         |\n|------------------------------------------+-----------------+--------+--------+--------+---------|\n|                                   133243 |             395 |        |        |        |         |\n|------------------------------------------+-----------------+--------+--------+--------+---------|\n|                                          |                 |        |        |        |         |\n|------------------------------------------+-----------------+--------+--------+--------+---------|\n| Function Name                            | Min             | Avg    | Median | Max    | # Calls |\n|------------------------------------------+-----------------+--------+--------+--------+---------|\n| baz                                      |          287711 | 287711 | 287711 | 287711 |       1 |\n╰------------------------------------------+-----------------+--------+--------+--------+---------╯\n\n\nRan 3 test suites [ELAPSED]: 3 tests passed, 0 failed, 0 skipped (3 total tests)\n\n\"#]]);\n    cmd.forge_fuse().arg(\"test\").arg(\"--gas-report\").arg(\"--json\").assert_success().stdout_eq(\n        str![[r#\"\n[\n  {\n    \"contract\": \"src/Contracts.sol:ContractThree\",\n    \"deployment\": {\n      \"gas\": 133243,\n      \"size\": 395\n    },\n    \"functions\": {\n      \"baz()\": {\n        \"calls\": 1,\n        \"min\": 287711,\n        \"mean\": 287711,\n        \"median\": 287711,\n        \"max\": 287711\n      }\n    }\n  }\n]\n\"#]]\n        .is_json(),\n    );\n});\n\nforgetest!(gas_report_ignore_some_contracts, |prj, cmd| {\n    prj.insert_ds_test();\n    prj.add_source(\"Contracts.sol\", GAS_REPORT_CONTRACTS);\n\n    // ignore ContractOne\n    prj.update_config(|config| {\n        config.gas_reports = vec![\"*\".to_string()];\n        config.gas_reports_ignore = vec![\"ContractOne\".to_string()];\n    });\n    cmd.forge_fuse();\n    cmd.arg(\"test\").arg(\"--gas-report\").assert_success().stdout_eq(str![[r#\"\n...\n╭------------------------------------------+-----------------+--------+--------+--------+---------╮\n| src/Contracts.sol:ContractThree Contract |                 |        |        |        |         |\n+=================================================================================================+\n| Deployment Cost                          | Deployment Size |        |        |        |         |\n|------------------------------------------+-----------------+--------+--------+--------+---------|\n|                                   133243 |             395 |        |        |        |         |\n|------------------------------------------+-----------------+--------+--------+--------+---------|\n|                                          |                 |        |        |        |         |\n|------------------------------------------+-----------------+--------+--------+--------+---------|\n| Function Name                            | Min             | Avg    | Median | Max    | # Calls |\n|------------------------------------------+-----------------+--------+--------+--------+---------|\n| baz                                      |          287711 | 287711 | 287711 | 287711 |       1 |\n╰------------------------------------------+-----------------+--------+--------+--------+---------╯\n\n╭----------------------------------------+-----------------+-------+--------+-------+---------╮\n| src/Contracts.sol:ContractTwo Contract |                 |       |        |       |         |\n+=============================================================================================+\n| Deployment Cost                        | Deployment Size |       |        |       |         |\n|----------------------------------------+-----------------+-------+--------+-------+---------|\n|                                 133027 |             394 |       |        |       |         |\n|----------------------------------------+-----------------+-------+--------+-------+---------|\n|                                        |                 |       |        |       |         |\n|----------------------------------------+-----------------+-------+--------+-------+---------|\n| Function Name                          | Min             | Avg   | Median | Max   | # Calls |\n|----------------------------------------+-----------------+-------+--------+-------+---------|\n| bar                                    |           67683 | 67683 |  67683 | 67683 |       1 |\n╰----------------------------------------+-----------------+-------+--------+-------+---------╯\n\n\nRan 3 test suites [ELAPSED]: 3 tests passed, 0 failed, 0 skipped (3 total tests)\n\n\"#]]);\n    cmd.forge_fuse().arg(\"test\").arg(\"--gas-report\").arg(\"--json\").assert_success().stdout_eq(\n        str![[r#\"\n[\n  {\n    \"contract\": \"src/Contracts.sol:ContractThree\",\n    \"deployment\": {\n      \"gas\": 133243,\n      \"size\": 395\n    },\n    \"functions\": {\n      \"baz()\": {\n        \"calls\": 1,\n        \"min\": 287711,\n        \"mean\": 287711,\n        \"median\": 287711,\n        \"max\": 287711\n      }\n    }\n  },\n  {\n    \"contract\": \"src/Contracts.sol:ContractTwo\",\n    \"deployment\": {\n      \"gas\": 133027,\n      \"size\": 394\n    },\n    \"functions\": {\n      \"bar()\": {\n        \"calls\": 1,\n        \"min\": 67683,\n        \"mean\": 67683,\n        \"median\": 67683,\n        \"max\": 67683\n      }\n    }\n  }\n]\n\"#]]\n        .is_json(),\n    );\n\n    // ignore ContractTwo\n    cmd.forge_fuse();\n    prj.update_config(|config| {\n        config.gas_reports = vec![];\n        config.gas_reports_ignore = vec![\"ContractTwo\".to_string()];\n    });\n    cmd.forge_fuse();\n    cmd.arg(\"test\").arg(\"--gas-report\").assert_success().stdout_eq(str![[r#\"\n...\n╭----------------------------------------+-----------------+-------+--------+-------+---------╮\n| src/Contracts.sol:ContractOne Contract |                 |       |        |       |         |\n+=============================================================================================+\n| Deployment Cost                        | Deployment Size |       |        |       |         |\n|----------------------------------------+-----------------+-------+--------+-------+---------|\n|                                 133027 |             394 |       |        |       |         |\n|----------------------------------------+-----------------+-------+--------+-------+---------|\n|                                        |                 |       |        |       |         |\n|----------------------------------------+-----------------+-------+--------+-------+---------|\n| Function Name                          | Min             | Avg   | Median | Max   | # Calls |\n|----------------------------------------+-----------------+-------+--------+-------+---------|\n| foo                                    |           45656 | 45656 |  45656 | 45656 |       1 |\n╰----------------------------------------+-----------------+-------+--------+-------+---------╯\n\n╭------------------------------------------+-----------------+--------+--------+--------+---------╮\n| src/Contracts.sol:ContractThree Contract |                 |        |        |        |         |\n+=================================================================================================+\n| Deployment Cost                          | Deployment Size |        |        |        |         |\n|------------------------------------------+-----------------+--------+--------+--------+---------|\n|                                   133243 |             395 |        |        |        |         |\n|------------------------------------------+-----------------+--------+--------+--------+---------|\n|                                          |                 |        |        |        |         |\n|------------------------------------------+-----------------+--------+--------+--------+---------|\n| Function Name                            | Min             | Avg    | Median | Max    | # Calls |\n|------------------------------------------+-----------------+--------+--------+--------+---------|\n| baz                                      |          287711 | 287711 | 287711 | 287711 |       1 |\n╰------------------------------------------+-----------------+--------+--------+--------+---------╯\n\n\nRan 3 test suites [ELAPSED]: 3 tests passed, 0 failed, 0 skipped (3 total tests)\n\n\"#]]);\n    cmd.forge_fuse().arg(\"test\").arg(\"--gas-report\").arg(\"--json\").assert_success().stdout_eq(\n        str![[r#\"\n[\n  {\n    \"contract\": \"src/Contracts.sol:ContractOne\",\n    \"deployment\": {\n      \"gas\": 133027,\n      \"size\": 394\n    },\n    \"functions\": {\n      \"foo()\": {\n        \"calls\": 1,\n        \"min\": 45656,\n        \"mean\": 45656,\n        \"median\": 45656,\n        \"max\": 45656\n      }\n    }\n  },\n  {\n    \"contract\": \"src/Contracts.sol:ContractThree\",\n    \"deployment\": {\n      \"gas\": 133243,\n      \"size\": 395\n    },\n    \"functions\": {\n      \"baz()\": {\n        \"calls\": 1,\n        \"min\": 287711,\n        \"mean\": 287711,\n        \"median\": 287711,\n        \"max\": 287711\n      }\n    }\n  }\n]\n\"#]]\n        .is_json(),\n    );\n\n    // If the user listed the contract in 'gas_reports' (the foundry.toml field) a\n    // report for the contract is generated even if it's listed in the ignore\n    // list. This is addressed this way because getting a report you don't expect is\n    // preferable than not getting one you expect. A warning is printed to stderr\n    // indicating the \"double listing\".\n    cmd.forge_fuse();\n    prj.update_config(|config| {\n        config.gas_reports =\n            vec![\"ContractOne\".to_string(), \"ContractTwo\".to_string(), \"ContractThree\".to_string()];\n        config.gas_reports_ignore = vec![\"ContractThree\".to_string()];\n    });\n    cmd.forge_fuse();\n    cmd.arg(\"test\")\n        .arg(\"--gas-report\")\n        .assert_success()\n        .stdout_eq(str![[r#\"\n...\n╭----------------------------------------+-----------------+-------+--------+-------+---------╮\n| src/Contracts.sol:ContractOne Contract |                 |       |        |       |         |\n+=============================================================================================+\n| Deployment Cost                        | Deployment Size |       |        |       |         |\n|----------------------------------------+-----------------+-------+--------+-------+---------|\n|                                 133027 |             394 |       |        |       |         |\n|----------------------------------------+-----------------+-------+--------+-------+---------|\n|                                        |                 |       |        |       |         |\n|----------------------------------------+-----------------+-------+--------+-------+---------|\n| Function Name                          | Min             | Avg   | Median | Max   | # Calls |\n|----------------------------------------+-----------------+-------+--------+-------+---------|\n| foo                                    |           45656 | 45656 |  45656 | 45656 |       1 |\n╰----------------------------------------+-----------------+-------+--------+-------+---------╯\n\n╭------------------------------------------+-----------------+--------+--------+--------+---------╮\n| src/Contracts.sol:ContractThree Contract |                 |        |        |        |         |\n+=================================================================================================+\n| Deployment Cost                          | Deployment Size |        |        |        |         |\n|------------------------------------------+-----------------+--------+--------+--------+---------|\n|                                   133243 |             395 |        |        |        |         |\n|------------------------------------------+-----------------+--------+--------+--------+---------|\n|                                          |                 |        |        |        |         |\n|------------------------------------------+-----------------+--------+--------+--------+---------|\n| Function Name                            | Min             | Avg    | Median | Max    | # Calls |\n|------------------------------------------+-----------------+--------+--------+--------+---------|\n| baz                                      |          287711 | 287711 | 287711 | 287711 |       1 |\n╰------------------------------------------+-----------------+--------+--------+--------+---------╯\n\n╭----------------------------------------+-----------------+-------+--------+-------+---------╮\n| src/Contracts.sol:ContractTwo Contract |                 |       |        |       |         |\n+=============================================================================================+\n| Deployment Cost                        | Deployment Size |       |        |       |         |\n|----------------------------------------+-----------------+-------+--------+-------+---------|\n|                                 133027 |             394 |       |        |       |         |\n|----------------------------------------+-----------------+-------+--------+-------+---------|\n|                                        |                 |       |        |       |         |\n|----------------------------------------+-----------------+-------+--------+-------+---------|\n| Function Name                          | Min             | Avg   | Median | Max   | # Calls |\n|----------------------------------------+-----------------+-------+--------+-------+---------|\n| bar                                    |           67683 | 67683 |  67683 | 67683 |       1 |\n╰----------------------------------------+-----------------+-------+--------+-------+---------╯\n\n\nRan 3 test suites [ELAPSED]: 3 tests passed, 0 failed, 0 skipped (3 total tests)\n\n\"#]])\n        .stderr_eq(str![[r#\"\n...\nWarning: ContractThree is listed in both 'gas_reports' and 'gas_reports_ignore'.\n...\n\"#]]);\n    cmd.forge_fuse()\n        .arg(\"test\")\n        .arg(\"--gas-report\")\n        .arg(\"--json\")\n        .assert_success()\n        .stdout_eq(\n            str![[r#\"\n[\n  {\n    \"contract\": \"src/Contracts.sol:ContractOne\",\n    \"deployment\": {\n      \"gas\": 133027,\n      \"size\": 394\n    },\n    \"functions\": {\n      \"foo()\": {\n        \"calls\": 1,\n        \"min\": 45656,\n        \"mean\": 45656,\n        \"median\": 45656,\n        \"max\": 45656\n      }\n    }\n  },\n  {\n    \"contract\": \"src/Contracts.sol:ContractThree\",\n    \"deployment\": {\n      \"gas\": 133243,\n      \"size\": 395\n    },\n    \"functions\": {\n      \"baz()\": {\n        \"calls\": 1,\n        \"min\": 287711,\n        \"mean\": 287711,\n        \"median\": 287711,\n        \"max\": 287711\n      }\n    }\n  },\n  {\n    \"contract\": \"src/Contracts.sol:ContractTwo\",\n    \"deployment\": {\n      \"gas\": 133027,\n      \"size\": 394\n    },\n    \"functions\": {\n      \"bar()\": {\n        \"calls\": 1,\n        \"min\": 67683,\n        \"mean\": 67683,\n        \"median\": 67683,\n        \"max\": 67683\n      }\n    }\n  }\n]\n\"#]]\n            .is_json(),\n        )\n        .stderr_eq(str![[r#\"\n...\nWarning: ContractThree is listed in both 'gas_reports' and 'gas_reports_ignore'.\n...\n\"#]]);\n});\n\nforgetest!(gas_report_flatten_multiple_selectors, |prj, cmd| {\n    prj.insert_ds_test();\n    prj.add_source(\n        \"Counter.sol\",\n        r#\"\ncontract Counter {\n    uint256 public a;\n    int256 public b;\n\n    function setNumber(uint256 x) public {\n        a = x;\n    }\n\n    function setNumber(int256 x) public {\n        b = x;\n    }\n}\n\"#,\n    );\n\n    prj.add_source(\n        \"CounterTest.t.sol\",\n        r#\"\nimport \"./test.sol\";\nimport {Counter} from \"./Counter.sol\";\n\ncontract CounterTest is DSTest {\n    Counter public counter;\n\n    function setUp() public {\n        counter = new Counter();\n        counter.setNumber(uint256(0));\n        counter.setNumber(int256(0));\n    }\n\n    function test_Increment() public {\n        counter.setNumber(uint256(counter.a() + 1));\n        counter.setNumber(int256(counter.b() + 1));\n    }\n}\n\"#,\n    );\n\n    cmd.arg(\"test\").arg(\"--gas-report\").assert_success().stdout_eq(str![[r#\"\n...\n╭----------------------------------+-----------------+-------+--------+-------+---------╮\n| src/Counter.sol:Counter Contract |                 |       |        |       |         |\n+=======================================================================================+\n| Deployment Cost                  | Deployment Size |       |        |       |         |\n|----------------------------------+-----------------+-------+--------+-------+---------|\n|                           172107 |             578 |       |        |       |         |\n|----------------------------------+-----------------+-------+--------+-------+---------|\n|                                  |                 |       |        |       |         |\n|----------------------------------+-----------------+-------+--------+-------+---------|\n| Function Name                    | Min             | Avg   | Median | Max   | # Calls |\n|----------------------------------+-----------------+-------+--------+-------+---------|\n| a                                |            2402 |  2402 |   2402 |  2402 |       1 |\n|----------------------------------+-----------------+-------+--------+-------+---------|\n| b                                |            2447 |  2447 |   2447 |  2447 |       1 |\n|----------------------------------+-----------------+-------+--------+-------+---------|\n| setNumber(int256)                |           23851 | 33807 |  33807 | 43763 |       2 |\n|----------------------------------+-----------------+-------+--------+-------+---------|\n| setNumber(uint256)               |           23806 | 33762 |  33762 | 43718 |       2 |\n╰----------------------------------+-----------------+-------+--------+-------+---------╯\n\n\nRan 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests)\n\n\"#]]);\n    cmd.forge_fuse().arg(\"test\").arg(\"--gas-report\").arg(\"--json\").assert_success().stdout_eq(\n        str![[r#\"\n[\n  {\n    \"contract\": \"src/Counter.sol:Counter\",\n    \"deployment\": {\n      \"gas\": 172107,\n      \"size\": 578\n    },\n    \"functions\": {\n      \"a()\": {\n        \"calls\": 1,\n        \"min\": 2402,\n        \"mean\": 2402,\n        \"median\": 2402,\n        \"max\": 2402\n      },\n      \"b()\": {\n        \"calls\": 1,\n        \"min\": 2447,\n        \"mean\": 2447,\n        \"median\": 2447,\n        \"max\": 2447\n      },\n      \"setNumber(int256)\": {\n        \"calls\": 2,\n        \"min\": 23851,\n        \"mean\": 33807,\n        \"median\": 33807,\n        \"max\": 43763\n      },\n      \"setNumber(uint256)\": {\n        \"calls\": 2,\n        \"min\": 23806,\n        \"mean\": 33762,\n        \"median\": 33762,\n        \"max\": 43718\n      }\n    }\n  }\n]\n\"#]]\n        .is_json(),\n    );\n});\n\n// <https://github.com/foundry-rs/foundry/issues/9115>\nforgetest_init!(gas_report_with_fallback, |prj, cmd| {\n    prj.initialize_default_contracts();\n    prj.add_test(\n        \"DelegateProxyTest.sol\",\n        r#\"\nimport {Test} from \"forge-std/Test.sol\";\n\ncontract ProxiedContract {\n    uint256 public amount;\n\n    function deposit(uint256 aba) external {\n        amount = amount * 2;\n    }\n\n    function deposit() external {\n    }\n}\n\ncontract DelegateProxy {\n    address internal implementation;\n\n    constructor(address counter) {\n        implementation = counter;\n    }\n\n    function deposit() external {\n    }\n\n    fallback() external payable {\n        address addr = implementation;\n\n        assembly {\n            calldatacopy(0, 0, calldatasize())\n            let result := delegatecall(gas(), addr, 0, calldatasize(), 0, 0)\n            returndatacopy(0, 0, returndatasize())\n            switch result\n            case 0 { revert(0, returndatasize()) }\n            default { return(0, returndatasize()) }\n        }\n    }\n}\n\ncontract GasReportFallbackTest is Test {\n    function test_fallback_gas_report() public {\n        ProxiedContract proxied = ProxiedContract(address(new DelegateProxy(address(new ProxiedContract()))));\n        proxied.deposit(100);\n        proxied.deposit();\n    }\n}\n\"#,\n    );\n\n    cmd.args([\"test\", \"--mt\", \"test_fallback_gas_report\", \"-vvvv\", \"--gas-report\"])\n        .assert_success()\n        .stdout_eq(str![[r#\"\n...\n╭---------------------------------------------------+-----------------+-------+--------+-------+---------╮\n| test/DelegateProxyTest.sol:DelegateProxy Contract |                 |       |        |       |         |\n+========================================================================================================+\n| Deployment Cost                                   | Deployment Size |       |        |       |         |\n|---------------------------------------------------+-----------------+-------+--------+-------+---------|\n|                                            117171 |             471 |       |        |       |         |\n|---------------------------------------------------+-----------------+-------+--------+-------+---------|\n|                                                   |                 |       |        |       |         |\n|---------------------------------------------------+-----------------+-------+--------+-------+---------|\n| Function Name                                     | Min             | Avg   | Median | Max   | # Calls |\n|---------------------------------------------------+-----------------+-------+--------+-------+---------|\n| deposit                                           |           21185 | 21185 |  21185 | 21185 |       1 |\n|---------------------------------------------------+-----------------+-------+--------+-------+---------|\n| fallback                                          |           29758 | 29758 |  29758 | 29758 |       1 |\n╰---------------------------------------------------+-----------------+-------+--------+-------+---------╯\n\n╭-----------------------------------------------------+-----------------+------+--------+------+---------╮\n| test/DelegateProxyTest.sol:ProxiedContract Contract |                 |      |        |      |         |\n+========================================================================================================+\n| Deployment Cost                                     | Deployment Size |      |        |      |         |\n|-----------------------------------------------------+-----------------+------+--------+------+---------|\n|                                              153531 |             494 |      |        |      |         |\n|-----------------------------------------------------+-----------------+------+--------+------+---------|\n|                                                     |                 |      |        |      |         |\n|-----------------------------------------------------+-----------------+------+--------+------+---------|\n| Function Name                                       | Min             | Avg  | Median | Max  | # Calls |\n|-----------------------------------------------------+-----------------+------+--------+------+---------|\n| deposit                                             |            3661 | 3661 |   3661 | 3661 |       1 |\n╰-----------------------------------------------------+-----------------+------+--------+------+---------╯\n\n\nRan 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests)\n\n\"#]]);\n\n    cmd.forge_fuse()\n        .args([\"test\", \"--mt\", \"test_fallback_gas_report\", \"--gas-report\", \"--json\"])\n        .assert_success()\n        .stdout_eq(\n            str![[r#\"\n[\n  {\n    \"contract\": \"test/DelegateProxyTest.sol:DelegateProxy\",\n    \"deployment\": {\n      \"gas\": 117171,\n      \"size\": 471\n    },\n    \"functions\": {\n      \"deposit()\": {\n        \"calls\": 1,\n        \"min\": 21185,\n        \"mean\": 21185,\n        \"median\": 21185,\n        \"max\": 21185\n      },\n      \"fallback()\": {\n        \"calls\": 1,\n        \"min\": 29758,\n        \"mean\": 29758,\n        \"median\": 29758,\n        \"max\": 29758\n      }\n    }\n  },\n  {\n    \"contract\": \"test/DelegateProxyTest.sol:ProxiedContract\",\n    \"deployment\": {\n      \"gas\": 153531,\n      \"size\": 494\n    },\n    \"functions\": {\n      \"deposit(uint256)\": {\n        \"calls\": 1,\n        \"min\": 3661,\n        \"mean\": 3661,\n        \"median\": 3661,\n        \"max\": 3661\n      }\n    }\n  }\n]\n\"#]]\n            .is_json(),\n        );\n});\n\n// <https://github.com/foundry-rs/foundry/issues/9858>\nforgetest_init!(flaky_gas_report_fallback_with_calldata, |prj, cmd| {\n    prj.initialize_default_contracts();\n    prj.add_test(\n        \"FallbackWithCalldataTest.sol\",\n        r#\"\nimport {Test} from \"forge-std/Test.sol\";\n\ncontract CounterWithFallback {\n    uint256 public number;\n\n    function increment() public {\n        number++;\n    }\n\n    fallback() external {\n        number++;\n    }\n}\n\ncontract CounterWithFallbackTest is Test {\n    CounterWithFallback public counter;\n\n    function setUp() public {\n        counter = new CounterWithFallback();\n    }\n\n    function test_fallback_with_calldata() public {\n        (bool success,) = address(counter).call(\"hello\");\n        require(success);\n    }\n}\n\"#,\n    );\n\n    cmd.args([\"test\", \"--mt\", \"test_fallback_with_calldata\", \"-vvvv\", \"--gas-report\"])\n        .assert_success()\n        .stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\nRan 1 test for test/FallbackWithCalldataTest.sol:CounterWithFallbackTest\n[PASS] test_fallback_with_calldata() ([GAS])\nTraces:\n  [48777] CounterWithFallbackTest::test_fallback_with_calldata()\n    ├─ [43461] CounterWithFallback::fallback(0x68656c6c6f)\n    │   └─ ← [Stop]\n    └─ ← [Stop]\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED]\n\n╭----------------------------------------------------------------+-----------------+-------+--------+-------+---------╮\n| test/FallbackWithCalldataTest.sol:CounterWithFallback Contract |                 |       |        |       |         |\n+=====================================================================================================================+\n| Deployment Cost                                                | Deployment Size |       |        |       |         |\n|----------------------------------------------------------------+-----------------+-------+--------+-------+---------|\n|                                                         132471 |             396 |       |        |       |         |\n|----------------------------------------------------------------+-----------------+-------+--------+-------+---------|\n|                                                                |                 |       |        |       |         |\n|----------------------------------------------------------------+-----------------+-------+--------+-------+---------|\n| Function Name                                                  | Min             | Avg   | Median | Max   | # Calls |\n|----------------------------------------------------------------+-----------------+-------+--------+-------+---------|\n| fallback                                                       |           43461 | 43461 |  43461 | 43461 |       1 |\n╰----------------------------------------------------------------+-----------------+-------+--------+-------+---------╯\n\n\nRan 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests)\n\n\"#]]);\n\n    cmd.forge_fuse()\n        .args([\"test\", \"--mt\", \"test_fallback_with_calldata\", \"--gas-report\", \"--json\"])\n        .assert_success()\n        .stdout_eq(\n            str![[r#\"\n[\n  {\n    \"contract\": \"test/FallbackWithCalldataTest.sol:CounterWithFallback\",\n    \"deployment\": {\n      \"gas\": 132471,\n      \"size\": 396\n    },\n    \"functions\": {\n      \"fallback()\": {\n        \"calls\": 1,\n        \"min\": 43461,\n        \"mean\": 43461,\n        \"median\": 43461,\n        \"max\": 43461\n      }\n    }\n  }\n]\n\"#]]\n            .is_json(),\n        );\n});\n\n// <https://github.com/foundry-rs/foundry/issues/9300>\nforgetest_init!(gas_report_size_for_nested_create, |prj, cmd| {\n    prj.initialize_default_contracts();\n    prj.add_test(\n        \"NestedDeployTest.sol\",\n        r#\"\nimport {Test} from \"forge-std/Test.sol\";\ncontract Child {\n    AnotherChild public child;\n    constructor() {\n        child = new AnotherChild();\n    }\n    function w() external {\n        child.w();\n    }\n}\ncontract AnotherChild {\n    function w() external {}\n}\ncontract Parent {\n    Child public immutable child;\n    constructor() {\n        child = new Child();\n    }\n}\ncontract NestedDeploy is Test {\n    function test_nested_create_gas_report() external {\n        Parent p = new Parent();\n        p.child().child().w();\n    }\n}\n\"#,\n    );\n\n    cmd.args([\"test\", \"--mt\", \"test_nested_create_gas_report\", \"--gas-report\"])\n        .assert_success()\n        .stdout_eq(str![[r#\"\n...\n╭-------------------------------------------------+-----------------+-------+--------+-------+---------╮\n| test/NestedDeployTest.sol:AnotherChild Contract |                 |       |        |       |         |\n+======================================================================================================+\n| Deployment Cost                                 | Deployment Size |       |        |       |         |\n|-------------------------------------------------+-----------------+-------+--------+-------+---------|\n|                                               0 |             132 |       |        |       |         |\n|-------------------------------------------------+-----------------+-------+--------+-------+---------|\n|                                                 |                 |       |        |       |         |\n|-------------------------------------------------+-----------------+-------+--------+-------+---------|\n| Function Name                                   | Min             | Avg   | Median | Max   | # Calls |\n|-------------------------------------------------+-----------------+-------+--------+-------+---------|\n| w                                               |           21185 | 21185 |  21185 | 21185 |       1 |\n╰-------------------------------------------------+-----------------+-------+--------+-------+---------╯\n\n╭------------------------------------------+-----------------+------+--------+------+---------╮\n| test/NestedDeployTest.sol:Child Contract |                 |      |        |      |         |\n+=============================================================================================+\n| Deployment Cost                          | Deployment Size |      |        |      |         |\n|------------------------------------------+-----------------+------+--------+------+---------|\n|                                        0 |             731 |      |        |      |         |\n|------------------------------------------+-----------------+------+--------+------+---------|\n|                                          |                 |      |        |      |         |\n|------------------------------------------+-----------------+------+--------+------+---------|\n| Function Name                            | Min             | Avg  | Median | Max  | # Calls |\n|------------------------------------------+-----------------+------+--------+------+---------|\n| child                                    |            2681 | 2681 |   2681 | 2681 |       1 |\n╰------------------------------------------+-----------------+------+--------+------+---------╯\n\n╭-------------------------------------------+-----------------+-----+--------+-----+---------╮\n| test/NestedDeployTest.sol:Parent Contract |                 |     |        |     |         |\n+============================================================================================+\n| Deployment Cost                           | Deployment Size |     |        |     |         |\n|-------------------------------------------+-----------------+-----+--------+-----+---------|\n|                                    328961 |            1163 |     |        |     |         |\n|-------------------------------------------+-----------------+-----+--------+-----+---------|\n|                                           |                 |     |        |     |         |\n|-------------------------------------------+-----------------+-----+--------+-----+---------|\n| Function Name                             | Min             | Avg | Median | Max | # Calls |\n|-------------------------------------------+-----------------+-----+--------+-----+---------|\n| child                                     |             525 | 525 |    525 | 525 |       1 |\n╰-------------------------------------------+-----------------+-----+--------+-----+---------╯\n\n\nRan 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests)\n\n\"#]]);\n\n    cmd.forge_fuse()\n        .args([\"test\", \"--mt\", \"test_nested_create_gas_report\", \"--gas-report\", \"--json\"])\n        .assert_success()\n        .stdout_eq(\n            str![[r#\"\n[\n  {\n    \"contract\": \"test/NestedDeployTest.sol:AnotherChild\",\n    \"deployment\": {\n      \"gas\": 0,\n      \"size\": 132\n    },\n    \"functions\": {\n      \"w()\": {\n        \"calls\": 1,\n        \"min\": 21185,\n        \"mean\": 21185,\n        \"median\": 21185,\n        \"max\": 21185\n      }\n    }\n  },\n  {\n    \"contract\": \"test/NestedDeployTest.sol:Child\",\n    \"deployment\": {\n      \"gas\": 0,\n      \"size\": 731\n    },\n    \"functions\": {\n      \"child()\": {\n        \"calls\": 1,\n        \"min\": 2681,\n        \"mean\": 2681,\n        \"median\": 2681,\n        \"max\": 2681\n      }\n    }\n  },\n  {\n    \"contract\": \"test/NestedDeployTest.sol:Parent\",\n    \"deployment\": {\n      \"gas\": 328961,\n      \"size\": 1163\n    },\n    \"functions\": {\n      \"child()\": {\n        \"calls\": 1,\n        \"min\": 525,\n        \"mean\": 525,\n        \"median\": 525,\n        \"max\": 525\n      }\n    }\n  }\n]\n\"#]]\n            .is_json(),\n        );\n});\n\nforgetest_init!(can_use_absolute_imports, |prj, cmd| {\n    prj.initialize_default_contracts();\n    prj.update_config(|config| {\n        let remapping = prj.paths().libraries[0].join(\"myDependency\");\n        config.remappings = vec![\n            Remapping::from_str(&format!(\"myDependency/={}\", remapping.display())).unwrap().into(),\n        ];\n    });\n\n    prj.add_lib(\n        \"myDependency/src/interfaces/IConfig.sol\",\n        r\"\n\n    interface IConfig {}\n   \",\n    );\n\n    prj.add_lib(\n        \"myDependency/src/Config.sol\",\n        r#\"\n        import {IConfig} from \"myDependency/src/interfaces/IConfig.sol\";\n\n    contract Config is IConfig {}\n   \"#,\n    );\n\n    prj.add_source(\n        \"Greeter\",\n        r#\"\n        import {Config} from \"myDependency/src/Config.sol\";\n\n    contract Greeter {\n        Config config;\n    }\n   \"#,\n    );\n\n    cmd.arg(\"build\").assert_success().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\n\"#]]);\n});\n\n// <https://github.com/foundry-rs/foundry/issues/3440>\nforgetest_init!(can_use_absolute_imports_from_test_and_script, |prj, cmd| {\n    prj.initialize_default_contracts();\n    prj.add_script(\n        \"IMyScript.sol\",\n        r\"\ninterface IMyScript {}\n        \",\n    );\n\n    prj.add_script(\n        \"MyScript.sol\",\n        r#\"\nimport \"script/IMyScript.sol\";\n\ncontract MyScript is IMyScript {}\n        \"#,\n    );\n\n    prj.add_test(\n        \"IMyTest.sol\",\n        r\"\ninterface IMyTest {}\n        \",\n    );\n\n    prj.add_test(\n        \"MyTest.sol\",\n        r#\"\nimport \"test/IMyTest.sol\";\n\ncontract MyTest is IMyTest {}\n    \"#,\n    );\n\n    cmd.arg(\"build\").assert_success().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\n\"#]]);\n});\n\n// checks `forge inspect <contract> irOptimized works\nforgetest_init!(can_inspect_ir_optimized, |prj, cmd| {\n    prj.initialize_default_contracts();\n    cmd.args([\"inspect\", TEMPLATE_CONTRACT, \"irOptimized\"]);\n    cmd.assert_success().stdout_eq(str![[r#\"\n/// @use-src 0:\"src/Counter.sol\"\nobject \"Counter_21\" {\n    code {\n        {\n            /// @src 0:65:257  \"contract Counter {...\"\n            mstore(64, memoryguard(0x80))\n...\n\"#]]);\n\n    // check inspect with strip comments\n    cmd.forge_fuse().args([\"inspect\", TEMPLATE_CONTRACT, \"irOptimized\", \"-s\"]);\n    cmd.assert_success().stdout_eq(str![[r#\"\nobject \"Counter_21\" {\n    code {\n        {\n            mstore(64, memoryguard(0x80))\n            if callvalue()\n...\n\"#]]);\n});\n\n// checks `forge inspect <contract> irOptimized works\nforgetest_init!(can_inspect_ir, |prj, cmd| {\n    prj.initialize_default_contracts();\n    cmd.args([\"inspect\", TEMPLATE_CONTRACT, \"ir\"]);\n    cmd.assert_success().stdout_eq(str![[r#\"\n\n/// @use-src 0:\"src/Counter.sol\"\nobject \"Counter_21\" {\n    code {\n        /// @src 0:65:257  \"contract Counter {...\"\n        mstore(64, memoryguard(128))\n...\n\"#]]);\n\n    // check inspect with strip comments\n    cmd.forge_fuse().args([\"inspect\", TEMPLATE_CONTRACT, \"ir\", \"-s\"]);\n    cmd.assert_success().stdout_eq(str![[r#\"\n\nobject \"Counter_21\" {\n    code {\n        mstore(64, memoryguard(128))\n        if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() }\n...\n\"#]]);\n});\n\n// checks forge bind works correctly on the default project\nforgetest_init!(can_bind, |prj, cmd| {\n    prj.initialize_default_contracts();\n    prj.clear();\n\n    cmd.arg(\"bind\").assert_success().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\nGenerating bindings for [..] contracts\nBindings have been generated to [..]\n\n\"#]]);\n});\n\n// checks that extra output works\nforgetest_init!(can_build_skip_contracts, |prj, cmd| {\n    prj.initialize_default_contracts();\n    prj.clear();\n\n    // Only builds the single template contract `src/*`\n    cmd.args([\"build\", \"--skip\", \"tests\", \"--skip\", \"scripts\"]).assert_success().stdout_eq(str![[\n        r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\n\"#\n    ]]);\n\n    // Expect compilation to be skipped as no files have changed\n    cmd.arg(\"build\").assert_success().stdout_eq(str![[r#\"\nNo files changed, compilation skipped\n\n\"#]]);\n});\n\nforgetest_init!(can_build_skip_glob, |prj, cmd| {\n    prj.initialize_default_contracts();\n    prj.add_test(\n        \"Foo\",\n        r\"\ncontract TestDemo {\nfunction test_run() external {}\n}\",\n    );\n\n    // only builds the single template contract `src/*` even if `*.t.sol` or `.s.sol` is absent\n    prj.clear();\n    cmd.args([\"build\", \"--skip\", \"*/test/**\", \"--skip\", \"*/script/**\", \"--force\"])\n        .assert_success()\n        .stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\n\"#]]);\n\n    cmd.forge_fuse()\n        .args([\"build\", \"--skip\", \"./test/**\", \"--skip\", \"./script/**\", \"--force\"])\n        .assert_success()\n        .stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\n\"#]]);\n});\n\nforgetest!(can_build_specific_paths, |prj, cmd| {\n    prj.add_source(\n        \"Counter.sol\",\n        r\"\ncontract Counter {\nfunction count() external {}\n}\",\n    );\n    prj.add_test(\n        \"Foo.sol\",\n        r\"\ncontract Foo {\nfunction test_foo() external {}\n}\",\n    );\n    prj.add_test(\n        \"Bar.sol\",\n        r\"\ncontract Bar {\nfunction test_bar() external {}\n}\",\n    );\n\n    // Build 2 files within test dir\n    prj.clear();\n    cmd.args([\"build\", \"test\", \"--force\"]).assert_success().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\n\"#]]);\n\n    // Build one file within src dir\n    prj.clear();\n    cmd.forge_fuse();\n    cmd.args([\"build\", \"src\", \"--force\"]).assert_success().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\n\"#]]);\n\n    // Build 3 files from test and src dirs\n    prj.clear();\n    cmd.forge_fuse();\n    cmd.args([\"build\", \"src\", \"test\", \"--force\"]).assert_success().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\n\"#]]);\n\n    // Build single test file\n    prj.clear();\n    cmd.forge_fuse();\n    cmd.args([\"build\", \"test/Bar.sol\", \"--force\"]).assert_success().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\n\"#]]);\n\n    // Fail if no source file found.\n    prj.clear();\n    cmd.forge_fuse();\n    cmd.args([\"build\", \"test/Dummy.sol\", \"--force\"]).assert_failure().stderr_eq(str![[r#\"\nError: No source files found in specified build paths.\n\n\"#]]);\n});\n\n// checks that build --sizes includes all contracts even if unchanged\nforgetest_init!(can_build_sizes_repeatedly, |prj, cmd| {\n    prj.initialize_default_contracts();\n    prj.clear_cache();\n\n    cmd.args([\"build\", \"--sizes\"]).assert_success().stdout_eq(str![[r#\"\n...\n╭----------+------------------+-------------------+--------------------+---------------------╮\n| Contract | Runtime Size (B) | Initcode Size (B) | Runtime Margin (B) | Initcode Margin (B) |\n+============================================================================================+\n| Counter  | 481              | 509               | 24,095             | 48,643              |\n╰----------+------------------+-------------------+--------------------+---------------------╯\n\n\n\"#]]);\n\n    cmd.forge_fuse().args([\"build\", \"--sizes\", \"--md\"]).assert_success().stdout_eq(str![[r#\"\n...\n| Contract | Runtime Size (B) | Initcode Size (B) | Runtime Margin (B) | Initcode Margin (B) |\n|----------|------------------|-------------------|--------------------|---------------------|\n| Counter  | 481              | 509               | 24,095             | 48,643              |\n\n\n\"#]]);\n\n    cmd.forge_fuse().args([\"build\", \"--sizes\", \"--json\"]).assert_success().stdout_eq(\n        str![[r#\"\n{\n  \"Counter\": {\n    \"runtime_size\": 481,\n    \"init_size\": 509,\n    \"runtime_margin\": 24095,\n    \"init_margin\": 48643\n  }\n}\n\"#]]\n        .is_json(),\n    );\n});\n\n// checks that build --names includes all contracts even if unchanged\nforgetest_init!(can_build_names_repeatedly, |prj, cmd| {\n    prj.initialize_default_contracts();\n    prj.clear_cache();\n\n    cmd.args([\"build\", \"--names\"]).assert_success().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n  compiler version: [..]\n    - [..]\n...\n\n\"#]]);\n\n    cmd.forge_fuse()\n        .args([\"build\", \"--names\", \"--json\"])\n        .assert_success()\n        .stdout_eq(str![[r#\"\"{...}\"\"#]].is_json());\n});\n\nforgetest_init!(can_inspect_counter_pretty, |prj, cmd| {\n    prj.initialize_default_contracts();\n    cmd.args([\"inspect\", \"src/Counter.sol:Counter\", \"abi\"]).assert_success().stdout_eq(str![[r#\"\n\n╭----------+---------------------------------+------------╮\n| Type     | Signature                       | Selector   |\n+=========================================================+\n| function | increment() nonpayable          | 0xd09de08a |\n|----------+---------------------------------+------------|\n| function | number() view returns (uint256) | 0x8381f58a |\n|----------+---------------------------------+------------|\n| function | setNumber(uint256) nonpayable   | 0x3fb5c1cb |\n╰----------+---------------------------------+------------╯\n\n\n\"#]]);\n});\n\nconst CUSTOM_COUNTER: &str = r#\"\n    contract Counter {\n    uint256 public number;\n    uint64 public count;\n    struct MyStruct {\n        uint64 count;\n    }\n    struct ErrWithMsg {\n        string message;\n    }\n\n    event Incremented(uint256 newValue);\n    event Decremented(uint256 newValue);\n\n    error NumberIsZero();\n    error CustomErr(ErrWithMsg e);\n\n    constructor(uint256 _number) {\n        number = _number;\n    }\n\n    function setNumber(uint256 newNumber) public {\n        number = newNumber;\n    }\n\n    function increment() external {\n        number++;\n    }\n\n    function decrement() public payable {\n        if (number == 0) {\n            return;\n        }\n        number--;\n    }\n\n    function square() public {\n        number = number * number;\n    }\n\n    fallback() external payable {\n        ErrWithMsg memory err = ErrWithMsg(\"Fallback function is not allowed\");\n        revert CustomErr(err);\n    }\n\n    receive() external payable {\n        count++;\n    }\n\n    function setStruct(MyStruct memory s, uint32 b) public {\n        count = s.count;\n    }\n}\n    \"#;\n\nconst ANOTHER_COUNTER: &str = r#\"\n    contract AnotherCounter is Counter {\n        constructor(uint256 _number) Counter(_number) {}\n    }\n\"#;\nforgetest!(inspect_custom_counter_abi, |prj, cmd| {\n    prj.add_source(\"Counter.sol\", CUSTOM_COUNTER);\n\n    cmd.args([\"inspect\", \"Counter\", \"abi\"]).assert_success().stdout_eq(str![[r#\"\n\n╭-------------+-----------------------------------------------+--------------------------------------------------------------------╮\n| Type        | Signature                                     | Selector                                                           |\n+==================================================================================================================================+\n| event       | Decremented(uint256)                          | 0xc9118d86370931e39644ee137c931308fa3774f6c90ab057f0c3febf427ef94a |\n|-------------+-----------------------------------------------+--------------------------------------------------------------------|\n| event       | Incremented(uint256)                          | 0x20d8a6f5a693f9d1d627a598e8820f7a55ee74c183aa8f1a30e8d4e8dd9a8d84 |\n|-------------+-----------------------------------------------+--------------------------------------------------------------------|\n| error       | CustomErr(Counter.ErrWithMsg)                 | 0x0625625a                                                         |\n|-------------+-----------------------------------------------+--------------------------------------------------------------------|\n| error       | NumberIsZero()                                | 0xde5d32ac                                                         |\n|-------------+-----------------------------------------------+--------------------------------------------------------------------|\n| function    | count() view returns (uint64)                 | 0x06661abd                                                         |\n|-------------+-----------------------------------------------+--------------------------------------------------------------------|\n| function    | decrement() payable                           | 0x2baeceb7                                                         |\n|-------------+-----------------------------------------------+--------------------------------------------------------------------|\n| function    | increment() nonpayable                        | 0xd09de08a                                                         |\n|-------------+-----------------------------------------------+--------------------------------------------------------------------|\n| function    | number() view returns (uint256)               | 0x8381f58a                                                         |\n|-------------+-----------------------------------------------+--------------------------------------------------------------------|\n| function    | setNumber(uint256) nonpayable                 | 0x3fb5c1cb                                                         |\n|-------------+-----------------------------------------------+--------------------------------------------------------------------|\n| function    | setStruct(Counter.MyStruct,uint32) nonpayable | 0x08ef7366                                                         |\n|-------------+-----------------------------------------------+--------------------------------------------------------------------|\n| function    | square() nonpayable                           | 0xd742cb01                                                         |\n|-------------+-----------------------------------------------+--------------------------------------------------------------------|\n| constructor | constructor(uint256) nonpayable               |                                                                    |\n|-------------+-----------------------------------------------+--------------------------------------------------------------------|\n| fallback    | fallback() payable                            |                                                                    |\n|-------------+-----------------------------------------------+--------------------------------------------------------------------|\n| receive     | receive() payable                             |                                                                    |\n╰-------------+-----------------------------------------------+--------------------------------------------------------------------╯\n\n\n\"#]]);\n});\n\nforgetest!(inspect_custom_counter_events, |prj, cmd| {\n    prj.add_source(\"Counter.sol\", CUSTOM_COUNTER);\n\n    cmd.args([\"inspect\", \"Counter\", \"events\"]).assert_success().stdout_eq(str![[r#\"\n\n╭----------------------+--------------------------------------------------------------------╮\n| Event                | Topic                                                              |\n+===========================================================================================+\n| Decremented(uint256) | 0xc9118d86370931e39644ee137c931308fa3774f6c90ab057f0c3febf427ef94a |\n|----------------------+--------------------------------------------------------------------|\n| Incremented(uint256) | 0x20d8a6f5a693f9d1d627a598e8820f7a55ee74c183aa8f1a30e8d4e8dd9a8d84 |\n╰----------------------+--------------------------------------------------------------------╯\n\n\n\"#]]);\n});\n\nforgetest!(inspect_custom_counter_errors, |prj, cmd| {\n    prj.add_source(\"Counter.sol\", CUSTOM_COUNTER);\n\n    cmd.args([\"inspect\", \"Counter\", \"errors\"]).assert_success().stdout_eq(str![[r#\"\n\n╭-------------------------------+----------╮\n| Error                         | Selector |\n+==========================================+\n| CustomErr(Counter.ErrWithMsg) | 0625625a |\n|-------------------------------+----------|\n| NumberIsZero()                | de5d32ac |\n╰-------------------------------+----------╯\n\n\n\"#]]);\n});\n\nforgetest!(inspect_path_only_identifier, |prj, cmd| {\n    prj.add_source(\"Counter.sol\", CUSTOM_COUNTER);\n\n    cmd.args([\"inspect\", \"src/Counter.sol\", \"errors\"]).assert_success().stdout_eq(str![[r#\"\n\n╭-------------------------------+----------╮\n| Error                         | Selector |\n+==========================================+\n| CustomErr(Counter.ErrWithMsg) | 0625625a |\n|-------------------------------+----------|\n| NumberIsZero()                | de5d32ac |\n╰-------------------------------+----------╯\n\n\n\"#]]);\n});\n\nforgetest!(test_inspect_contract_with_same_name, |prj, cmd| {\n    let source = format!(\"{CUSTOM_COUNTER}\\n{ANOTHER_COUNTER}\");\n    prj.add_source(\"Counter.sol\", &source);\n\n    cmd.args([\"inspect\", \"src/Counter.sol\", \"errors\"]).assert_failure().stderr_eq(str![[r#\"Error: Multiple contracts found in the same file, please specify the target <path>:<contract> or <contract>[..]\"#]]);\n\n    cmd.forge_fuse().args([\"inspect\", \"Counter\", \"errors\"]).assert_success().stdout_eq(str![[r#\"\n\n╭-------------------------------+----------╮\n| Error                         | Selector |\n+==========================================+\n| CustomErr(Counter.ErrWithMsg) | 0625625a |\n|-------------------------------+----------|\n| NumberIsZero()                | de5d32ac |\n╰-------------------------------+----------╯\n\n\n\"#]]);\n});\n\n// <https://github.com/foundry-rs/foundry/issues/10531>\nforgetest!(inspect_multiple_contracts_with_different_paths, |prj, cmd| {\n    prj.add_source(\n        \"Source.sol\",\n        r#\"\n    contract Source {\n        function foo() public {}\n    }\n    \"#,\n    );\n\n    prj.add_source(\n        \"another/Source.sol\",\n        r#\"\n    contract Source {\n        function bar() public {}\n    }\n    \"#,\n    );\n\n    cmd.args([\"inspect\", \"src/another/Source.sol:Source\", \"methodIdentifiers\"])\n        .assert_success()\n        .stdout_eq(str![[r#\"\n\n╭--------+------------╮\n| Method | Identifier |\n+=====================+\n| bar()  | febb0f7e   |\n╰--------+------------╯\n\n\n\"#]]);\n});\n\nforgetest!(inspect_custom_counter_method_identifiers, |prj, cmd| {\n    prj.add_source(\"Counter.sol\", CUSTOM_COUNTER);\n\n    cmd.args([\"inspect\", \"Counter\", \"method-identifiers\"]).assert_success().stdout_eq(str![[r#\"\n\n╭----------------------------+------------╮\n| Method                     | Identifier |\n+=========================================+\n| count()                    | 06661abd   |\n|----------------------------+------------|\n| decrement()                | 2baeceb7   |\n|----------------------------+------------|\n| increment()                | d09de08a   |\n|----------------------------+------------|\n| number()                   | 8381f58a   |\n|----------------------------+------------|\n| setNumber(uint256)         | 3fb5c1cb   |\n|----------------------------+------------|\n| setStruct((uint64),uint32) | 08ef7366   |\n|----------------------------+------------|\n| square()                   | d742cb01   |\n╰----------------------------+------------╯\n\n\n\"#]]);\n});\n\nconst CUSTOM_COUNTER_HUGE_METHOD_IDENTIFIERS: &str = r#\"\ncontract Counter {\n    struct BigStruct {\n        uint256 a;\n        uint256 b;\n        uint256 c;\n        uint256 d;\n        uint256 e;\n        uint256 f;\n    }\n\n    struct NestedBigStruct {\n        BigStruct a;\n        BigStruct b;\n        BigStruct c;\n    }\n\n    function hugeIdentifier(NestedBigStruct[] calldata _bigStructs, NestedBigStruct calldata _bigStruct) external {}\n}\n\"#;\n\nforgetest!(inspect_custom_counter_very_huge_method_identifiers_unwrapped, |prj, cmd| {\n    prj.add_source(\"Counter.sol\", CUSTOM_COUNTER_HUGE_METHOD_IDENTIFIERS);\n\n    cmd.args([\"inspect\", \"Counter\", \"method-identifiers\"]).assert_success().stdout_eq(str![[r#\"\n\n╭-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------╮\n| Method                                                                                                                                                                                                                                                                                                                            | Identifier |\n+================================================================================================================================================================================================================================================================================================================================================+\n| hugeIdentifier(((uint256,uint256,uint256,uint256,uint256,uint256),(uint256,uint256,uint256,uint256,uint256,uint256),(uint256,uint256,uint256,uint256,uint256,uint256))[],((uint256,uint256,uint256,uint256,uint256,uint256),(uint256,uint256,uint256,uint256,uint256,uint256),(uint256,uint256,uint256,uint256,uint256,uint256))) | f38dafbb   |\n╰-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------╯\n\n\n\"#]]);\n\n    cmd.forge_fuse().args([\"inspect\", \"Counter\", \"method-identifiers\", \"--md\"]).assert_success().stdout_eq(str![[r#\"\n\n| Method                                                                                                                                                                                                                                                                                                                            | Identifier |\n|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------|\n| hugeIdentifier(((uint256,uint256,uint256,uint256,uint256,uint256),(uint256,uint256,uint256,uint256,uint256,uint256),(uint256,uint256,uint256,uint256,uint256,uint256))[],((uint256,uint256,uint256,uint256,uint256,uint256),(uint256,uint256,uint256,uint256,uint256,uint256),(uint256,uint256,uint256,uint256,uint256,uint256))) | f38dafbb   |\n\n\n\"#]]);\n});\n\nforgetest_init!(can_inspect_standard_json, |prj, cmd| {\n    prj.initialize_default_contracts();\n    cmd.args([\"inspect\", \"src/Counter.sol:Counter\", \"standard-json\"]).assert_success().stdout_eq(str![[r#\"\n{\n  \"language\": \"Solidity\",\n  \"sources\": {\n    \"src/Counter.sol\": {\n      \"content\": \"// SPDX-License-Identifier: UNLICENSED/npragma solidity ^0.8.13;/n/ncontract Counter {/n    uint256 public number;/n/n    function setNumber(uint256 newNumber) public {/n        number = newNumber;/n    }/n/n    function increment() public {/n        number++;/n    }/n}/n\"\n    }\n  },\n  \"settings\": {\n    \"remappings\": [\n      \"forge-std/=lib/forge-std/src/\"\n    ],\n    \"optimizer\": {\n      \"enabled\": false,\n      \"runs\": 200\n    },\n    \"metadata\": {\n      \"useLiteralContent\": false,\n      \"bytecodeHash\": \"ipfs\",\n      \"appendCBOR\": true\n    },\n    \"outputSelection\": {\n      \"*\": {\n        \"*\": [\n          \"abi\",\n          \"evm.bytecode.object\",\n          \"evm.bytecode.sourceMap\",\n          \"evm.bytecode.linkReferences\",\n          \"evm.deployedBytecode.object\",\n          \"evm.deployedBytecode.sourceMap\",\n          \"evm.deployedBytecode.linkReferences\",\n          \"evm.deployedBytecode.immutableReferences\",\n          \"evm.methodIdentifiers\",\n          \"metadata\"\n        ]\n      }\n    },\n    \"evmVersion\": \"osaka\",\n    \"viaIR\": false,\n    \"libraries\": {}\n  }\n}\n\n\"#]]);\n});\n\nforgetest_init!(can_inspect_libraries, |prj, cmd| {\n    prj.initialize_default_contracts();\n    prj.add_source(\n        \"Source.sol\",\n        r#\"\n    import \"./Lib.sol\";\n\n    library Lib2 {\n        function foo() public {}\n    }\n\n    contract Source {\n        function foo() public {\n            Lib.foo();\n            Lib2.foo();\n        }\n    }\"#,\n    );\n\n    prj.add_source(\n        \"Lib.sol\",\n        r#\"\n    library Lib {\n        function foo() public {}\n    }\n    \"#,\n    );\n\n    cmd.args([\"inspect\", \"Source\", \"libraries\"]).assert_success().stdout_eq(str![[r#\"\nDynamically linked libraries:\n  src/Lib.sol:Lib\n  src/Source.sol:Lib2\n\n\"#]]);\n});\n\n// checks that `clean` also works with the \"out\" value set in Config\nforgetest_init!(gas_report_include_tests, |prj, cmd| {\n    prj.initialize_default_contracts();\n    prj.update_config(|config| {\n        config.gas_reports_include_tests = true;\n        config.fuzz.runs = 1;\n    });\n\n    cmd.args([\"test\", \"--match-test\", \"test_Increment\", \"--gas-report\"])\n        .assert_success()\n        .stdout_eq(str![[r#\"\n...\n╭----------------------------------+-----------------+-------+--------+-------+---------╮\n| src/Counter.sol:Counter Contract |                 |       |        |       |         |\n+=======================================================================================+\n| Deployment Cost                  | Deployment Size |       |        |       |         |\n|----------------------------------+-----------------+-------+--------+-------+---------|\n|                           156813 |             509 |       |        |       |         |\n|----------------------------------+-----------------+-------+--------+-------+---------|\n|                                  |                 |       |        |       |         |\n|----------------------------------+-----------------+-------+--------+-------+---------|\n| Function Name                    | Min             | Avg   | Median | Max   | # Calls |\n|----------------------------------+-----------------+-------+--------+-------+---------|\n| increment                        |           43482 | 43482 |  43482 | 43482 |       1 |\n|----------------------------------+-----------------+-------+--------+-------+---------|\n| number                           |            2424 |  2424 |   2424 |  2424 |       1 |\n|----------------------------------+-----------------+-------+--------+-------+---------|\n| setNumber                        |           23784 | 23784 |  23784 | 23784 |       1 |\n╰----------------------------------+-----------------+-------+--------+-------+---------╯\n\n╭-----------------------------------------+-----------------+--------+--------+--------+---------╮\n| test/Counter.t.sol:CounterTest Contract |                 |        |        |        |         |\n+================================================================================================+\n| Deployment Cost                         | Deployment Size |        |        |        |         |\n|-----------------------------------------+-----------------+--------+--------+--------+---------|\n|                                 1544498 |            7573 |        |        |        |         |\n|-----------------------------------------+-----------------+--------+--------+--------+---------|\n|                                         |                 |        |        |        |         |\n|-----------------------------------------+-----------------+--------+--------+--------+---------|\n| Function Name                           | Min             | Avg    | Median | Max    | # Calls |\n|-----------------------------------------+-----------------+--------+--------+--------+---------|\n| setUp                                   |          218902 | 218902 | 218902 | 218902 |       1 |\n|-----------------------------------------+-----------------+--------+--------+--------+---------|\n| test_Increment                          |           51847 |  51847 |  51847 |  51847 |       1 |\n╰-----------------------------------------+-----------------+--------+--------+--------+---------╯\n\n\nRan 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests)\n\n\"#]]);\n\n    cmd.forge_fuse()\n        .args([\"test\", \"--match-test\", \"test_Increment\", \"--gas-report\", \"--md\"])\n        .assert_success()\n        .stdout_eq(str![[r#\"\n...\n| src/Counter.sol:Counter Contract |                 |       |        |       |         |\n|----------------------------------|-----------------|-------|--------|-------|---------|\n| Deployment Cost                  | Deployment Size |       |        |       |         |\n|                           156813 |             509 |       |        |       |         |\n|                                  |                 |       |        |       |         |\n| Function Name                    | Min             | Avg   | Median | Max   | # Calls |\n| increment                        |           43482 | 43482 |  43482 | 43482 |       1 |\n| number                           |            2424 |  2424 |   2424 |  2424 |       1 |\n| setNumber                        |           23784 | 23784 |  23784 | 23784 |       1 |\n\n| test/Counter.t.sol:CounterTest Contract |                 |        |        |        |         |\n|-----------------------------------------|-----------------|--------|--------|--------|---------|\n| Deployment Cost                         | Deployment Size |        |        |        |         |\n|                                 1544498 |            7573 |        |        |        |         |\n|                                         |                 |        |        |        |         |\n| Function Name                           | Min             | Avg    | Median | Max    | # Calls |\n| setUp                                   |          218902 | 218902 | 218902 | 218902 |       1 |\n| test_Increment                          |           51847 |  51847 |  51847 |  51847 |       1 |\n\n\nRan 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests)\n\n\"#]]);\n\n    cmd.forge_fuse()\n        .args([\"test\", \"--mt\", \"test_Increment\", \"--gas-report\", \"--json\"])\n        .assert_success()\n        .stdout_eq(\n            str![[r#\"\n[\n  {\n    \"contract\": \"src/Counter.sol:Counter\",\n    \"deployment\": {\n      \"gas\": 156813,\n      \"size\": 509\n    },\n    \"functions\": {\n      \"increment()\": {\n        \"calls\": 1,\n        \"min\": 43482,\n        \"mean\": 43482,\n        \"median\": 43482,\n        \"max\": 43482\n      },\n      \"number()\": {\n        \"calls\": 1,\n        \"min\": 2424,\n        \"mean\": 2424,\n        \"median\": 2424,\n        \"max\": 2424\n      },\n      \"setNumber(uint256)\": {\n        \"calls\": 1,\n        \"min\": 23784,\n        \"mean\": 23784,\n        \"median\": 23784,\n        \"max\": 23784\n      }\n    }\n  },\n  {\n    \"contract\": \"test/Counter.t.sol:CounterTest\",\n    \"deployment\": {\n      \"gas\": 1544498,\n      \"size\": 7573\n    },\n    \"functions\": {\n      \"setUp()\": {\n        \"calls\": 1,\n        \"min\": 218902,\n        \"mean\": 218902,\n        \"median\": 218902,\n        \"max\": 218902\n      },\n      \"test_Increment()\": {\n        \"calls\": 1,\n        \"min\": 51847,\n        \"mean\": 51847,\n        \"median\": 51847,\n        \"max\": 51847\n      }\n    }\n  }\n]\n\"#]]\n            .is_json(),\n        );\n});\n\nforgetest_async!(gas_report_fuzz_invariant, |prj, cmd| {\n    // speed up test by running with depth of 15\n    prj.update_config(|config| config.invariant.depth = 15);\n\n    prj.insert_ds_test();\n    prj.add_source(\n        \"Contracts.sol\",\n        r#\"\nimport \"./test.sol\";\n\ncontract Foo {\n    function foo() public {}\n}\n\ncontract Bar {\n    function bar() public {}\n}\n\ncontract FooBarTest is DSTest {\n    Foo public targetContract;\n\n    function setUp() public {\n        targetContract = new Foo();\n    }\n\n    function invariant_dummy() public {\n        assertTrue(true);\n    }\n\n    function testFuzz_bar(uint256 _val) public {\n        (new Bar()).bar();\n    }\n}\n    \"#,\n    );\n\n    cmd.args([\"test\", \"--gas-report\"]).assert_success();\n});\n\n// <https://github.com/foundry-rs/foundry/issues/5847>\nforgetest_init!(can_bind_enum_modules, |prj, cmd| {\n    prj.initialize_default_contracts();\n    prj.clear();\n\n    prj.add_source(\n        \"Enum.sol\",\n        r#\"\n    contract Enum {\n        enum MyEnum { A, B, C }\n    }\n    \"#,\n    );\n\n    prj.add_source(\n        \"UseEnum.sol\",\n        r#\"\n    import \"./Enum.sol\";\n    contract UseEnum {\n        Enum.MyEnum public myEnum;\n    }\"#,\n    );\n\n    cmd.args([\"bind\", \"--select\", \"^Enum$\"]).assert_success().stdout_eq(str![[\n        r#\"[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\nGenerating bindings for 1 contracts\nBindings have been generated to [..]\"#\n    ]]);\n});\n\n// forge bind e2e\nforgetest_init!(can_bind_e2e, |prj, cmd| {\n    prj.initialize_default_contracts();\n    cmd.args([\"bind\"]).assert_success().stdout_eq(str![[r#\"[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\nGenerating bindings for 2 contracts\nBindings have been generated to [..]\"#]]);\n\n    let bindings_path = prj.root().join(\"out/bindings\");\n\n    assert!(bindings_path.exists(), \"Bindings directory should exist\");\n    let out = Command::new(\"cargo\")\n        .arg(\"build\")\n        .current_dir(&bindings_path)\n        .output()\n        .expect(\"Failed to run cargo build\");\n\n    assert!(out.status.success(), \"Cargo build should succeed\");\n});\n"
  },
  {
    "path": "crates/forge/tests/cli/compiler.rs",
    "content": "//! Tests for the `forge compiler` command.\n\nuse foundry_test_utils::snapbox::IntoData;\n\nconst CONTRACT_A: &str = r#\"\n// SPDX-license-identifier: MIT\npragma solidity 0.8.4;\n\ncontract ContractA {}\n\"#;\n\nconst CONTRACT_B: &str = r#\"\n// SPDX-license-identifier: MIT\npragma solidity 0.8.11;\n\ncontract ContractB {}\n\"#;\n\nconst CONTRACT_C: &str = r#\"\n// SPDX-license-identifier: MIT\npragma solidity 0.8.33;\n\ncontract ContractC {}\n\"#;\n\nconst CONTRACT_D: &str = r#\"\n// SPDX-license-identifier: MIT\npragma solidity 0.8.33;\n\ncontract ContractD {}\n\"#;\n\nconst VYPER_INTERFACE: &str = r#\"\n# pragma version >=0.4.0\n\n@external\n@view\ndef number() -> uint256:\n    return empty(uint256)\n\n@external\ndef set_number(new_number: uint256):\n    pass\n\n@external\ndef increment() -> uint256:\n    return empty(uint256)\n\"#;\n\nconst VYPER_CONTRACT: &str = r#\"\nimport ICounter\nimplements: ICounter\n\nnumber: public(uint256)\n\n@external\ndef set_number(new_number: uint256):\n    self.number = new_number\n\n@external\ndef increment() -> uint256:\n    self.number += 1\n    return self.number\n\"#;\n\nforgetest!(can_resolve_path, |prj, cmd| {\n    prj.add_source(\"ContractA\", CONTRACT_A);\n\n    cmd.args([\"compiler\", \"resolve\", \"--root\", prj.root().to_str().unwrap()])\n        .assert_success()\n        .stdout_eq(str![[r#\"\nSolidity:\n- 0.8.4\n\n\n\"#]]);\n});\n\nforgetest!(can_list_resolved_compiler_versions, |prj, cmd| {\n    prj.add_source(\"ContractA\", CONTRACT_A);\n\n    cmd.args([\"compiler\", \"resolve\"]).assert_success().stdout_eq(str![[r#\"\nSolidity:\n- 0.8.4\n\n\n\"#]]);\n});\n\nforgetest!(can_list_resolved_compiler_versions_json, |prj, cmd| {\n    prj.add_source(\"ContractA\", CONTRACT_A);\n\n    cmd.args([\"compiler\", \"resolve\", \"--json\"]).assert_success().stdout_eq(\n        str![[r#\"\n{\n   \"Solidity\":[\n      {\n         \"version\":\"0.8.4\"\n      }\n   ]\n}\n\"#]]\n        .is_json(),\n    );\n});\n\nforgetest!(can_list_resolved_compiler_versions_verbose, |prj, cmd| {\n    prj.add_source(\"ContractC\", CONTRACT_C);\n    prj.add_source(\"ContractD\", CONTRACT_D);\n\n    cmd.args([\"compiler\", \"resolve\", \"-v\"]).assert_success().stdout_eq(str![[r#\"\nSolidity:\n\n0.8.33:\n├── src/ContractC.sol\n└── src/ContractD.sol\n\n\n\"#]]);\n});\n\nforgetest!(can_list_resolved_compiler_versions_verbose_json, |prj, cmd| {\n    prj.add_source(\"ContractC\", CONTRACT_C);\n    prj.add_source(\"ContractD\", CONTRACT_D);\n\n    cmd.args([\"compiler\", \"resolve\", \"--json\", \"-v\"]).assert_success().stdout_eq(\n        str![[r#\"\n{\n  \"Solidity\": [\n    {\n      \"version\": \"0.8.33\",\n      \"paths\": [\n        \"src/ContractC.sol\",\n        \"src/ContractD.sol\"\n      ]\n    }\n  ]\n}\n\"#]]\n        .is_json(),\n    );\n});\n\nforgetest!(can_list_resolved_multiple_compiler_versions, |prj, cmd| {\n    prj.add_source(\"ContractA\", CONTRACT_A);\n    prj.add_source(\"ContractB\", CONTRACT_B);\n    prj.add_source(\"ContractC\", CONTRACT_C);\n    prj.add_source(\"ContractD\", CONTRACT_D);\n    prj.add_raw_source(\"ICounter.vyi\", VYPER_INTERFACE);\n    prj.add_raw_source(\"Counter.vy\", VYPER_CONTRACT);\n\n    cmd.args([\"compiler\", \"resolve\"]).assert_success().stdout_eq(str![[r#\"\nSolidity:\n- 0.8.4\n- 0.8.11\n- 0.8.33\n\nVyper:\n- 0.4.3\n\n\n\"#]]);\n});\n\nforgetest!(can_list_resolved_multiple_compiler_versions_skipped, |prj, cmd| {\n    prj.add_source(\"ContractA\", CONTRACT_A);\n    prj.add_source(\"ContractB\", CONTRACT_B);\n    prj.add_source(\"ContractC\", CONTRACT_C);\n    prj.add_source(\"ContractD\", CONTRACT_D);\n    prj.add_raw_source(\"ICounter.vyi\", VYPER_INTERFACE);\n    prj.add_raw_source(\"Counter.vy\", VYPER_CONTRACT);\n\n    cmd.args([\"compiler\", \"resolve\", \"--skip\", \".sol\", \"-v\"]).assert_success().stdout_eq(str![[\n        r#\"\nVyper:\n\n0.4.3:\n├── src/Counter.vy\n└── src/ICounter.vyi\n\n\n\"#\n    ]]);\n});\n\nforgetest!(can_list_resolved_multiple_compiler_versions_skipped_json, |prj, cmd| {\n    prj.add_source(\"ContractA\", CONTRACT_A);\n    prj.add_source(\"ContractB\", CONTRACT_B);\n    prj.add_source(\"ContractC\", CONTRACT_C);\n    prj.add_source(\"ContractD\", CONTRACT_D);\n    prj.add_raw_source(\"ICounter.vyi\", VYPER_INTERFACE);\n    prj.add_raw_source(\"Counter.vy\", VYPER_CONTRACT);\n\n    cmd.args([\"compiler\", \"resolve\", \"--skip\", \"Contract(A|B|C)\", \"--json\", \"-v\"])\n        .assert_success()\n        .stdout_eq(\n            str![[r#\"\n{\n  \"Solidity\": [\n    {\n      \"version\": \"0.8.33\",\n      \"paths\": [\n        \"src/ContractD.sol\"\n      ]\n    }\n  ],\n  \"Vyper\": [\n    {\n      \"version\": \"0.4.3\",\n      \"paths\": [\n        \"src/Counter.vy\",\n        \"src/ICounter.vyi\"\n      ]\n    }\n  ]\n}\n\"#]]\n            .is_json(),\n        );\n});\n\nforgetest!(can_list_resolved_multiple_compiler_versions_verbose, |prj, cmd| {\n    prj.add_source(\"ContractA\", CONTRACT_A);\n    prj.add_source(\"ContractB\", CONTRACT_B);\n    prj.add_source(\"ContractC\", CONTRACT_C);\n    prj.add_source(\"ContractD\", CONTRACT_D);\n    prj.add_raw_source(\"ICounter.vyi\", VYPER_INTERFACE);\n    prj.add_raw_source(\"Counter.vy\", VYPER_CONTRACT);\n\n    cmd.args([\"compiler\", \"resolve\", \"-vv\"]).assert_success().stdout_eq(str![[r#\"\nSolidity:\n\n0.8.4 (<= istanbul):\n└── src/ContractA.sol\n\n0.8.11 (<= london):\n└── src/ContractB.sol\n\n0.8.33 (<= prague):\n├── src/ContractC.sol\n└── src/ContractD.sol\n\nVyper:\n\n0.4.3 (<= prague):\n├── src/Counter.vy\n└── src/ICounter.vyi\n\n\n\"#]]);\n});\n\nforgetest!(can_list_resolved_multiple_compiler_versions_verbose_json, |prj, cmd| {\n    prj.add_source(\"ContractA\", CONTRACT_A);\n    prj.add_source(\"ContractB\", CONTRACT_B);\n    prj.add_source(\"ContractC\", CONTRACT_C);\n    prj.add_source(\"ContractD\", CONTRACT_D);\n    prj.add_raw_source(\"ICounter.vyi\", VYPER_INTERFACE);\n    prj.add_raw_source(\"Counter.vy\", VYPER_CONTRACT);\n\n    cmd.args([\"compiler\", \"resolve\", \"--json\", \"-vv\"]).assert_success().stdout_eq(\n        str![[r#\"\n{\n  \"Solidity\": [\n    {\n      \"version\": \"0.8.4\",\n      \"evm_version\": \"Istanbul\",\n      \"paths\": [\n        \"src/ContractA.sol\"\n      ]\n    },\n    {\n      \"version\": \"0.8.11\",\n      \"evm_version\": \"London\",\n      \"paths\": [\n        \"src/ContractB.sol\"\n      ]\n    },\n    {\n      \"version\": \"0.8.33\",\n      \"evm_version\": \"[..]\",\n      \"paths\": [\n        \"src/ContractC.sol\",\n        \"src/ContractD.sol\"\n      ]\n    }\n  ],\n  \"Vyper\": [\n    {\n      \"version\": \"0.4.3\",\n      \"evm_version\": \"[..]\",\n      \"paths\": [\n        \"src/Counter.vy\",\n        \"src/ICounter.vyi\"\n      ]\n    }\n  ]\n}\n\"#]]\n        .is_json(),\n    );\n});\n"
  },
  {
    "path": "crates/forge/tests/cli/config.rs",
    "content": "//! Contains various tests for checking forge commands related to config values\n\nuse alloy_primitives::{Address, B256, U256};\nuse foundry_cli::utils as forge_utils;\nuse foundry_compilers::{\n    artifacts::{BytecodeHash, OptimizerDetails, RevertStrings, YulDetails},\n    solc::Solc,\n};\nuse foundry_config::{\n    CompilationRestrictions, Config, FsPermissions, FuzzConfig, FuzzCorpusConfig, InvariantConfig,\n    SettingsOverrides, SolcReq,\n    cache::{CachedChains, CachedEndpoints, StorageCachingConfig},\n    filter::GlobMatcher,\n    fs_permissions::{FsAccessPermission, PathPermission},\n};\nuse foundry_evm::opts::EvmOpts;\nuse foundry_test_utils::{\n    foundry_compilers::artifacts::{EvmVersion, remappings::Remapping},\n    util::{OTHER_SOLC_VERSION, OutputExt, TestCommand, pretty_err},\n};\nuse path_slash::PathBufExt;\nuse semver::VersionReq;\nuse serde_json::Value;\nuse similar_asserts::assert_eq;\nuse std::{\n    fs,\n    path::{Path, PathBuf},\n    str::FromStr,\n    thread,\n};\n\nconst DEFAULT_CONFIG: &str = r#\"[profile.default]\nsrc = \"src\"\ntest = \"test\"\nscript = \"script\"\nout = \"out\"\nlibs = [\"lib\"]\nremappings = [\"forge-std/=lib/forge-std/src/\"]\nauto_detect_remappings = true\nlibraries = []\ncache = true\ncache_path = \"cache\"\ndynamic_test_linking = false\nsnapshots = \"snapshots\"\ngas_snapshot_check = false\ngas_snapshot_emit = true\nbroadcast = \"broadcast\"\nallow_paths = []\ninclude_paths = []\nskip = []\nforce = false\nevm_version = \"osaka\"\ngas_reports = [\"*\"]\ngas_reports_ignore = []\ngas_reports_include_tests = false\nauto_detect_solc = true\noffline = false\noptimizer = false\noptimizer_runs = 200\nverbosity = 0\neth_rpc_accept_invalid_certs = false\neth_rpc_no_proxy = false\neth_rpc_curl = false\nignored_error_codes = [\n    \"license\",\n    \"code-size\",\n    \"init-code-size\",\n    \"transient-storage\",\n    \"transfer-deprecated\",\n    \"natspec-memory-safe-assembly-deprecated\",\n]\nignored_warnings_from = []\ndeny = \"never\"\ntest_failures_file = \"cache/test-failures\"\nshow_progress = false\nffi = false\nlive_logs = false\nallow_internal_expect_revert = false\nalways_use_create_2_factory = false\nprompt_timeout = 120\nsender = \"0x1804c8ab1f12e6bbf3894d4083f33e07309d1f38\"\ntx_origin = \"0x1804c8ab1f12e6bbf3894d4083f33e07309d1f38\"\ninitial_balance = \"0xffffffffffffffffffffffff\"\nblock_number = 1\ngas_limit = 1073741824\nblock_base_fee_per_gas = 0\nblock_coinbase = \"0x0000000000000000000000000000000000000000\"\nblock_timestamp = 1\nblock_difficulty = 0\nblock_prevrandao = \"0x0000000000000000000000000000000000000000000000000000000000000000\"\nmemory_limit = 134217728\nextra_output = []\nextra_output_files = []\nnames = false\nsizes = false\nvia_ir = false\nast = false\nno_storage_caching = false\nno_rpc_rate_limit = false\nuse_literal_content = false\nbytecode_hash = \"ipfs\"\ncbor_metadata = true\nsparse_mode = false\nbuild_info = false\nisolate = false\ndisable_block_gas_limit = false\nenable_tx_gas_limit = false\nunchecked_cheatcode_artifacts = false\ncreate2_library_salt = \"0x0000000000000000000000000000000000000000000000000000000000000000\"\ncreate2_deployer = \"0x4e59b44847b379578588920ca78fbf26c0b4956c\"\nassertions_revert = true\nlegacy_assertions = false\ncelo = false\nbypass_prevrandao = false\ntransaction_timeout = 120\nadditional_compiler_profiles = []\ncompilation_restrictions = []\nscript_execution_protection = true\n\n[profile.default.rpc_storage_caching]\nchains = \"all\"\nendpoints = \"all\"\n\n[[profile.default.fs_permissions]]\naccess = \"read\"\npath = \"out\"\n\n[fmt]\nline_length = 120\ntab_width = 4\nstyle = \"space\"\nbracket_spacing = false\nint_types = \"long\"\nmultiline_func_header = \"attributes_first\"\nquote_style = \"double\"\nnumber_underscore = \"preserve\"\nhex_underscore = \"remove\"\nsingle_line_statement_blocks = \"preserve\"\noverride_spacing = false\nwrap_comments = false\ndocs_style = \"preserve\"\nignore = []\ncontract_new_lines = false\nsort_imports = false\nnamespace_import_style = \"prefer_plain\"\npow_no_space = false\nprefer_compact = \"all\"\nsingle_line_imports = false\n\n[lint]\nseverity = [\n    \"high\",\n    \"medium\",\n    \"low\",\n]\nexclude_lints = []\nignore = []\nlint_on_build = true\n\n[lint.lint_specific]\nmixed_case_exceptions = [\n    \"ERC\",\n    \"URI\",\n    \"ID\",\n    \"URL\",\n    \"API\",\n    \"JSON\",\n    \"XML\",\n    \"HTML\",\n    \"HTTP\",\n    \"HTTPS\",\n]\nmulti_contract_file_exceptions = []\n\n[doc]\nout = \"docs\"\ntitle = \"\"\nbook = \"book.toml\"\nhomepage = \"README.md\"\nignore = []\n\n[fuzz]\nruns = 256\nfail_on_revert = true\nmax_test_rejects = 65536\ndictionary_weight = 40\ninclude_storage = true\ninclude_push_bytes = true\nmax_fuzz_dictionary_addresses = 15728640\nmax_fuzz_dictionary_values = 9830400\nmax_fuzz_dictionary_literals = 6553600\ngas_report_samples = 256\ncorpus_gzip = true\ncorpus_min_mutations = 5\ncorpus_min_size = 0\nshow_edge_coverage = false\nfailure_persist_dir = \"cache/fuzz\"\nshow_logs = false\n\n[invariant]\nruns = 256\ndepth = 500\nfail_on_revert = false\ncall_override = false\ndictionary_weight = 80\ninclude_storage = true\ninclude_push_bytes = true\nmax_fuzz_dictionary_addresses = 15728640\nmax_fuzz_dictionary_values = 9830400\nmax_fuzz_dictionary_literals = 6553600\nshrink_run_limit = 5000\nmax_assume_rejects = 65536\ngas_report_samples = 256\ncorpus_gzip = true\ncorpus_min_mutations = 5\ncorpus_min_size = 0\nshow_edge_coverage = false\nfailure_persist_dir = \"cache/invariant\"\nshow_metrics = true\nshow_solidity = false\ncheck_interval = 1\n\n[labels]\n\n[vyper]\n\n[bind_json]\nout = \"utils/JsonBindings.sol\"\ninclude = []\nexclude = []\n\n\"#;\n\n// tests all config values that are in use\nforgetest!(can_extract_config_values, |prj, cmd| {\n    // explicitly set all values\n    let input = Config {\n        profile: Config::DEFAULT_PROFILE,\n        // `profiles` is not serialized.\n        profiles: vec![],\n        root: \".\".into(),\n        extends: None,\n        src: \"test-src\".into(),\n        test: \"test-test\".into(),\n        script: \"test-script\".into(),\n        out: \"out-test\".into(),\n        libs: vec![\"lib-test\".into()],\n        cache: true,\n        dynamic_test_linking: false,\n        cache_path: \"test-cache\".into(),\n        snapshots: \"snapshots\".into(),\n        gas_snapshot_check: false,\n        gas_snapshot_emit: true,\n        broadcast: \"broadcast\".into(),\n        force: true,\n        evm_version: EvmVersion::Byzantium,\n        gas_reports: vec![\"Contract\".to_string()],\n        gas_reports_ignore: vec![],\n        gas_reports_include_tests: false,\n        solc: Some(SolcReq::Local(PathBuf::from(\"custom-solc\"))),\n        auto_detect_solc: false,\n        auto_detect_remappings: true,\n        offline: true,\n        optimizer: Some(false),\n        optimizer_runs: Some(1000),\n        optimizer_details: Some(OptimizerDetails {\n            yul: Some(false),\n            yul_details: Some(YulDetails { stack_allocation: Some(true), ..Default::default() }),\n            ..Default::default()\n        }),\n        model_checker: None,\n        extra_output: Default::default(),\n        extra_output_files: Default::default(),\n        names: true,\n        sizes: true,\n        test_pattern: None,\n        test_pattern_inverse: None,\n        contract_pattern: None,\n        contract_pattern_inverse: None,\n        path_pattern: None,\n        path_pattern_inverse: None,\n        coverage_pattern_inverse: None,\n        test_failures_file: \"test-cache/test-failures\".into(),\n        threads: None,\n        show_progress: false,\n        fuzz: FuzzConfig {\n            runs: 1000,\n            max_test_rejects: 100203,\n            seed: Some(U256::from(1000)),\n            failure_persist_dir: Some(\"test-cache/fuzz\".into()),\n            show_logs: false,\n            ..Default::default()\n        },\n        invariant: InvariantConfig {\n            runs: 256,\n            failure_persist_dir: Some(\"test-cache/fuzz\".into()),\n            corpus: FuzzCorpusConfig {\n                corpus_dir: Some(\"cache/invariant/corpus\".into()),\n                ..Default::default()\n            },\n            ..Default::default()\n        },\n        ffi: true,\n        live_logs: true,\n        allow_internal_expect_revert: false,\n        always_use_create_2_factory: false,\n        prompt_timeout: 0,\n        sender: \"00a329c0648769A73afAc7F9381D08FB43dBEA72\".parse().unwrap(),\n        tx_origin: \"00a329c0648769A73afAc7F9F81E08FB43dBEA72\".parse().unwrap(),\n        initial_balance: U256::from(0xffffffffffffffffffffffffu128),\n        block_number: U256::from(10),\n        fork_block_number: Some(200),\n        chain: Some(9999.into()),\n        gas_limit: 99_000_000u64.into(),\n        code_size_limit: Some(100000),\n        gas_price: Some(999),\n        block_base_fee_per_gas: 10,\n        block_coinbase: Address::random(),\n        block_timestamp: U256::from(10),\n        block_difficulty: 10,\n        block_prevrandao: B256::random(),\n        block_gas_limit: Some(100u64.into()),\n        disable_block_gas_limit: false,\n        enable_tx_gas_limit: false,\n        memory_limit: 1 << 27,\n        eth_rpc_url: Some(\"localhost\".to_string()),\n        eth_rpc_accept_invalid_certs: false,\n        eth_rpc_no_proxy: false,\n        eth_rpc_jwt: None,\n        eth_rpc_timeout: None,\n        eth_rpc_headers: None,\n        eth_rpc_curl: false,\n        etherscan_api_key: None,\n        etherscan: Default::default(),\n        verbosity: 4,\n        remappings: vec![Remapping::from_str(\"forge-std/=lib/forge-std/\").unwrap().into()],\n        libraries: vec![\n            \"src/DssSpell.sol:DssExecLib:0x8De6DDbCd5053d32292AAA0D2105A32d108484a6\".to_string(),\n        ],\n        ignored_error_codes: vec![],\n        ignored_file_paths: vec![],\n        deny: foundry_config::DenyLevel::Never,\n        deny_warnings: false,\n        via_ir: true,\n        ast: false,\n        rpc_storage_caching: StorageCachingConfig {\n            chains: CachedChains::None,\n            endpoints: CachedEndpoints::Remote,\n        },\n        no_storage_caching: true,\n        no_rpc_rate_limit: true,\n        use_literal_content: false,\n        bytecode_hash: Default::default(),\n        cbor_metadata: true,\n        revert_strings: Some(RevertStrings::Strip),\n        sparse_mode: true,\n        allow_paths: vec![],\n        include_paths: vec![],\n        rpc_endpoints: Default::default(),\n        build_info: false,\n        build_info_path: None,\n        fmt: Default::default(),\n        lint: Default::default(),\n        doc: Default::default(),\n        bind_json: Default::default(),\n        fs_permissions: Default::default(),\n        labels: Default::default(),\n        isolate: true,\n        unchecked_cheatcode_artifacts: false,\n        create2_library_salt: Config::DEFAULT_CREATE2_LIBRARY_SALT,\n        create2_deployer: Config::DEFAULT_CREATE2_DEPLOYER,\n        vyper: Default::default(),\n        skip: vec![],\n        dependencies: Default::default(),\n        soldeer: Default::default(),\n        warnings: vec![],\n        assertions_revert: true,\n        legacy_assertions: false,\n        extra_args: vec![],\n        networks: Default::default(),\n        transaction_timeout: 120,\n        additional_compiler_profiles: Default::default(),\n        compilation_restrictions: Default::default(),\n        script_execution_protection: true,\n        _non_exhaustive: (),\n    };\n    prj.write_config(input.clone());\n    let config = cmd.config();\n    similar_asserts::assert_eq!(input, config);\n});\n\n// tests config gets printed to std out\nforgetest!(can_show_config, |prj, cmd| {\n    let expected =\n        Config::load_with_root(prj.root()).unwrap().to_string_pretty().unwrap().trim().to_string();\n    let output = cmd.arg(\"config\").assert_success().get_output().stdout_lossy().trim().to_string();\n    assert_eq!(expected, output);\n});\n\n// checks that config works\n// - foundry.toml is properly generated\n// - paths are resolved properly\n// - config supports overrides from env, and cli\nforgetest_init!(can_override_config, |prj, cmd| {\n    prj.initialize_default_contracts();\n    cmd.set_current_dir(prj.root());\n    let foundry_toml = prj.root().join(Config::FILE_NAME);\n    assert!(foundry_toml.exists());\n\n    let profile = Config::load_with_root(prj.root()).unwrap();\n    // ensure that the auto-generated internal remapping for forge-std's ds-test exists\n    assert_eq!(profile.remappings.len(), 1);\n    assert_eq!(\"forge-std/=lib/forge-std/src/\", profile.remappings[0].to_string());\n\n    // ensure remappings contain test\n    assert_eq!(\"forge-std/=lib/forge-std/src/\", profile.remappings[0].to_string());\n    // the loaded config has resolved, absolute paths\n    assert_eq!(\n        \"forge-std/=lib/forge-std/src/\",\n        Remapping::from(profile.remappings[0].clone()).to_string()\n    );\n\n    let expected = profile.to_string_pretty().unwrap().trim().to_string();\n    let output = cmd.arg(\"config\").assert_success().get_output().stdout_lossy().trim().to_string();\n    assert_eq!(expected, output);\n\n    // remappings work\n    let remappings_txt =\n        prj.create_file(\"remappings.txt\", \"ds-test/=lib/forge-std/lib/ds-test/from-file/\");\n    let config = forge_utils::load_config_with_root(Some(prj.root())).unwrap();\n    assert_eq!(\n        format!(\n            \"ds-test/={}/\",\n            prj.root().join(\"lib/forge-std/lib/ds-test/from-file\").to_slash_lossy()\n        ),\n        Remapping::from(config.remappings[0].clone()).to_string()\n    );\n\n    let config =\n        prj.config_from_output([\"--remappings\", \"ds-test/=lib/forge-std/lib/ds-test/from-cli\"]);\n    assert_eq!(\n        format!(\n            \"ds-test/={}/\",\n            prj.root().join(\"lib/forge-std/lib/ds-test/from-cli\").to_slash_lossy()\n        ),\n        Remapping::from(config.remappings[0].clone()).to_string()\n    );\n\n    let config = prj.config_from_output([\"--remappings\", \"other-key/=lib/other/\"]);\n    assert_eq!(config.remappings.len(), 3);\n    assert_eq!(\n        format!(\"other-key/={}/\", prj.root().join(\"lib/other\").to_slash_lossy()),\n        // As CLI has the higher priority, it'll be found at the first slot.\n        Remapping::from(config.remappings[0].clone()).to_string()\n    );\n\n    pretty_err(&remappings_txt, fs::remove_file(&remappings_txt));\n\n    let expected = profile.into_basic().to_string_pretty().unwrap().trim().to_string();\n    let output = cmd\n        .forge_fuse()\n        .args([\"config\", \"--basic\"])\n        .assert_success()\n        .get_output()\n        .stdout_lossy()\n        .trim()\n        .to_string();\n    assert_eq!(expected, output);\n});\n\nforgetest_init!(can_parse_remappings_correctly, |prj, cmd| {\n    prj.initialize_default_contracts();\n    cmd.set_current_dir(prj.root());\n    let foundry_toml = prj.root().join(Config::FILE_NAME);\n    assert!(foundry_toml.exists());\n\n    let profile = Config::load_with_root(prj.root()).unwrap();\n    // ensure that the auto-generated internal remapping for forge-std's ds-test exists\n    assert_eq!(profile.remappings.len(), 1);\n    let r = &profile.remappings[0];\n    assert_eq!(\"forge-std/=lib/forge-std/src/\", r.to_string());\n\n    // the loaded config has resolved, absolute paths\n    assert_eq!(\"forge-std/=lib/forge-std/src/\", Remapping::from(r.clone()).to_string());\n\n    let expected = profile.to_string_pretty().unwrap().trim().to_string();\n    let output = cmd.arg(\"config\").assert_success().get_output().stdout_lossy().trim().to_string();\n    assert_eq!(expected, output);\n\n    let install = |cmd: &mut TestCommand, dep: &str| {\n        cmd.forge_fuse().args([\"install\", dep]).assert_success().stdout_eq(str![[r#\"\nInstalling solmate in [..] (url: https://github.com/transmissions11/solmate, tag: None)\n    Installed solmate[..]\n\n\"#]]);\n    };\n\n    install(&mut cmd, \"transmissions11/solmate\");\n    let profile = Config::load_with_root(prj.root()).unwrap();\n    // remappings work\n    let remappings_txt = prj.create_file(\n        \"remappings.txt\",\n        \"solmate/=lib/solmate/src/\\nsolmate-contracts/=lib/solmate/src/\",\n    );\n    let config = forge_utils::load_config_with_root(Some(prj.root())).unwrap();\n    // trailing slashes are removed on windows `to_slash_lossy`\n    let path = prj.root().join(\"lib/solmate/src/\").to_slash_lossy().into_owned();\n    #[cfg(windows)]\n    let path = path + \"/\";\n    assert_eq!(\n        format!(\"solmate/={path}\"),\n        Remapping::from(config.remappings[0].clone()).to_string()\n    );\n    // As this is an user-generated remapping, it is not removed, even if it points to the same\n    // location.\n    assert_eq!(\n        format!(\"solmate-contracts/={path}\"),\n        Remapping::from(config.remappings[1].clone()).to_string()\n    );\n    pretty_err(&remappings_txt, fs::remove_file(&remappings_txt));\n\n    let expected = profile.into_basic().to_string_pretty().unwrap().trim().to_string();\n    let output = cmd\n        .forge_fuse()\n        .args([\"config\", \"--basic\"])\n        .assert_success()\n        .get_output()\n        .stdout_lossy()\n        .trim()\n        .to_string();\n    assert_eq!(expected, output);\n});\n\nforgetest_init!(can_detect_config_vals, |prj, _cmd| {\n    prj.initialize_default_contracts();\n    let url = \"http://127.0.0.1:8545\";\n    let config = prj.config_from_output([\"--no-auto-detect\", \"--rpc-url\", url]);\n    assert!(!config.auto_detect_solc);\n    assert_eq!(config.eth_rpc_url, Some(url.to_string()));\n\n    let mut config = Config::load_with_root(prj.root()).unwrap();\n    config.eth_rpc_url = Some(\"http://127.0.0.1:8545\".to_string());\n    config.auto_detect_solc = false;\n    // write to `foundry.toml`\n    prj.create_file(\n        Config::FILE_NAME,\n        &config.to_string_pretty().unwrap().replace(\"eth_rpc_url\", \"eth-rpc-url\"),\n    );\n    let config = prj.config_from_output([\"--force\"]);\n    assert!(!config.auto_detect_solc);\n    assert_eq!(config.eth_rpc_url, Some(url.to_string()));\n});\n\n// checks that `clean` removes dapptools style paths\nforgetest_init!(can_get_evm_opts, |prj, _cmd| {\n    prj.initialize_default_contracts();\n    let url = \"http://127.0.0.1:8545\";\n    let config = prj.config_from_output([\"--rpc-url\", url, \"--ffi\"]);\n    assert_eq!(config.eth_rpc_url, Some(url.to_string()));\n    assert!(config.ffi);\n\n    unsafe {\n        std::env::set_var(\"FOUNDRY_ETH_RPC_URL\", url);\n    }\n    let figment = Config::figment_with_root(prj.root()).merge((\"debug\", false));\n    let evm_opts: EvmOpts = figment.extract().unwrap();\n    assert_eq!(evm_opts.fork_url, Some(url.to_string()));\n    unsafe {\n        std::env::remove_var(\"FOUNDRY_ETH_RPC_URL\");\n    }\n});\n\n// checks that we can set various config values\nforgetest_init!(can_set_config_values, |prj, _cmd| {\n    prj.initialize_default_contracts();\n    let config = prj.config_from_output([\"--via-ir\", \"--no-metadata\"]);\n    assert!(config.via_ir);\n    assert_eq!(config.cbor_metadata, false);\n    assert_eq!(config.bytecode_hash, BytecodeHash::None);\n});\n\n// tests that solc can be explicitly set\nforgetest!(can_set_solc_explicitly, |prj, cmd| {\n    prj.add_source(\n        \"Foo\",\n        r\"\npragma solidity *;\ncontract Greeter {}\n   \",\n    );\n\n    prj.update_config(|config| {\n        config.solc = Some(OTHER_SOLC_VERSION.into());\n    });\n\n    cmd.arg(\"build\").assert_success().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\n\"#]]);\n});\n\n// tests that `--use <solc>` works\nforgetest!(can_use_solc, |prj, cmd| {\n    prj.add_raw_source(\n        \"Foo\",\n        r\"\npragma solidity *;\ncontract Foo {}\n   \",\n    );\n\n    cmd.args([\"build\", \"--use\", OTHER_SOLC_VERSION]).assert_success().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\n\"#]]);\n\n    cmd.forge_fuse()\n        .args([\"build\", \"--force\", \"--use\", &format!(\"solc:{OTHER_SOLC_VERSION}\")])\n        .root_arg()\n        .assert_success()\n        .stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\n\"#]]);\n\n    // fails to use solc that does not exist\n    cmd.forge_fuse().args([\"build\", \"--use\", \"this/solc/does/not/exist\"]);\n    cmd.assert_failure().stderr_eq(str![[r#\"\nError: `solc` this/solc/does/not/exist does not exist\n\n\"#]]);\n\n    // `OTHER_SOLC_VERSION` was installed in previous step, so we can use the path to this directly\n    let local_solc = Solc::find_or_install(&OTHER_SOLC_VERSION.parse().unwrap()).unwrap();\n    cmd.forge_fuse()\n        .args([\"build\", \"--force\", \"--use\"])\n        .arg(local_solc.solc)\n        .root_arg()\n        .assert_success()\n        .stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\n\"#]]);\n});\n\n// test to ensure yul optimizer can be set as intended\nforgetest!(can_set_yul_optimizer, |prj, cmd| {\n    prj.update_config(|config| config.optimizer = Some(true));\n    prj.add_source(\n        \"foo.sol\",\n        r\"\ncontract Foo {\n    function bar() public pure {\n       assembly {\n            let result_start := msize()\n       }\n    }\n}\n   \",\n    );\n\n    cmd.arg(\"build\").assert_failure().stderr_eq(str![[r#\"\nError: Compiler run failed:\nError (6553): The msize instruction cannot be used when the Yul optimizer is activated because it can change its semantics. Either disable the Yul optimizer or do not use the instruction.\n [FILE]:6:8:\n  |\n6 |        assembly {\n  |        ^ (Relevant source part starts here and spans across multiple lines).\n\n\"#]]);\n\n    // disable yul optimizer explicitly\n    prj.update_config(|config| config.optimizer_details.get_or_insert_default().yul = Some(false));\n    cmd.assert_success();\n});\n\n// tests that the lib triple can be parsed\nforgetest_init!(can_parse_dapp_libraries, |_prj, cmd| {\n    cmd.env(\n        \"DAPP_LIBRARIES\",\n        \"src/DssSpell.sol:DssExecLib:0x8De6DDbCd5053d32292AAA0D2105A32d108484a6\",\n    );\n    let config = cmd.config();\n    assert_eq!(\n        config.libraries,\n        vec![\"src/DssSpell.sol:DssExecLib:0x8De6DDbCd5053d32292AAA0D2105A32d108484a6\".to_string(),]\n    );\n});\n\n// test that optimizer runs works\nforgetest!(can_set_optimizer_runs, |prj, cmd| {\n    // explicitly set optimizer runs\n    prj.update_config(|config| config.optimizer_runs = Some(1337));\n\n    let config = cmd.config();\n    assert_eq!(config.optimizer_runs, Some(1337));\n\n    let config = prj.config_from_output([\"--optimizer-runs\", \"300\"]);\n    assert_eq!(config.optimizer_runs, Some(300));\n});\n\n// test that use_literal_content works\nforgetest!(can_set_use_literal_content, |prj, cmd| {\n    // explicitly set use_literal_content\n    prj.update_config(|config| config.use_literal_content = false);\n\n    let config = cmd.config();\n    assert_eq!(config.use_literal_content, false);\n\n    let config = prj.config_from_output([\"--use-literal-content\"]);\n    assert_eq!(config.use_literal_content, true);\n});\n\n// <https://github.com/foundry-rs/foundry/issues/9665>\nforgetest!(enable_optimizer_when_runs_set, |prj, cmd| {\n    // explicitly set optimizer runs\n    prj.update_config(|config| config.optimizer_runs = Some(1337));\n\n    let config = cmd.config();\n    assert!(config.optimizer.unwrap());\n});\n\n// test `optimizer_runs` set to 200 by default if optimizer enabled\nforgetest!(optimizer_runs_default, |prj, cmd| {\n    // explicitly set optimizer\n    prj.update_config(|config| config.optimizer = Some(true));\n\n    let config = cmd.config();\n    assert_eq!(config.optimizer_runs, Some(200));\n});\n\n// test that gas_price can be set\nforgetest!(can_set_gas_price, |prj, cmd| {\n    // explicitly set gas_price\n    prj.update_config(|config| config.gas_price = Some(1337));\n\n    let config = cmd.config();\n    assert_eq!(config.gas_price, Some(1337));\n\n    let config = prj.config_from_output([\"--gas-price\", \"300\"]);\n    assert_eq!(config.gas_price, Some(300));\n});\n\n// test that we can detect remappings from foundry.toml\nforgetest_init!(can_detect_lib_foundry_toml, |prj, cmd| {\n    prj.initialize_default_contracts();\n    let config = cmd.config();\n    let remappings = config.remappings.iter().cloned().map(Remapping::from).collect::<Vec<_>>();\n    similar_asserts::assert_eq!(\n        remappings,\n        vec![\n            // global\n            \"forge-std/=lib/forge-std/src/\".parse().unwrap(),\n        ]\n    );\n\n    // create a new lib directly in the `lib` folder with a remapping\n    let mut config = config;\n    config.remappings = vec![Remapping::from_str(\"nested/=lib/nested\").unwrap().into()];\n    let nested = prj.paths().libraries[0].join(\"nested-lib\");\n    pretty_err(&nested, fs::create_dir_all(&nested));\n    let toml_file = nested.join(\"foundry.toml\");\n    pretty_err(&toml_file, fs::write(&toml_file, config.to_string_pretty().unwrap()));\n\n    let config = cmd.config();\n    let remappings = config.remappings.iter().cloned().map(Remapping::from).collect::<Vec<_>>();\n    similar_asserts::assert_eq!(\n        remappings,\n        vec![\n            // default\n            \"forge-std/=lib/forge-std/src/\".parse().unwrap(),\n            // remapping is local to the lib\n            \"nested-lib/=lib/nested-lib/src/\".parse().unwrap(),\n            // global\n            \"nested/=lib/nested-lib/lib/nested/\".parse().unwrap(),\n        ]\n    );\n\n    // nest another lib under the already nested lib\n    let mut config = config;\n    config.remappings = vec![Remapping::from_str(\"nested-twice/=lib/nested-twice\").unwrap().into()];\n    let nested = nested.join(\"lib/another-lib\");\n    pretty_err(&nested, fs::create_dir_all(&nested));\n    let toml_file = nested.join(\"foundry.toml\");\n    pretty_err(&toml_file, fs::write(&toml_file, config.to_string_pretty().unwrap()));\n\n    let another_config = cmd.config();\n    let remappings =\n        another_config.remappings.iter().cloned().map(Remapping::from).collect::<Vec<_>>();\n    similar_asserts::assert_eq!(\n        remappings,\n        vec![\n            // local to the lib\n            \"another-lib/=lib/nested-lib/lib/another-lib/src/\".parse().unwrap(),\n            // global\n            \"forge-std/=lib/forge-std/src/\".parse().unwrap(),\n            \"nested-lib/=lib/nested-lib/src/\".parse().unwrap(),\n            // remappings local to the lib\n            \"nested-twice/=lib/nested-lib/lib/another-lib/lib/nested-twice/\".parse().unwrap(),\n            \"nested/=lib/nested-lib/lib/nested/\".parse().unwrap(),\n        ]\n    );\n\n    config.src = \"custom-source-dir\".into();\n    pretty_err(&toml_file, fs::write(&toml_file, config.to_string_pretty().unwrap()));\n    let config = cmd.config();\n    let remappings = config.remappings.iter().cloned().map(Remapping::from).collect::<Vec<_>>();\n    similar_asserts::assert_eq!(\n        remappings,\n        vec![\n            // local to the lib\n            \"another-lib/=lib/nested-lib/lib/another-lib/custom-source-dir/\".parse().unwrap(),\n            // global\n            \"forge-std/=lib/forge-std/src/\".parse().unwrap(),\n            \"nested-lib/=lib/nested-lib/src/\".parse().unwrap(),\n            // remappings local to the lib\n            \"nested-twice/=lib/nested-lib/lib/another-lib/lib/nested-twice/\".parse().unwrap(),\n            \"nested/=lib/nested-lib/lib/nested/\".parse().unwrap(),\n        ]\n    );\n\n    // check if lib path is absolute, it should deteect nested lib\n    let mut config = cmd.config();\n    config.libs = vec![nested];\n\n    let remappings = config.remappings.iter().cloned().map(Remapping::from).collect::<Vec<_>>();\n    similar_asserts::assert_eq!(\n        remappings,\n        vec![\n            // local to the lib\n            \"another-lib/=lib/nested-lib/lib/another-lib/custom-source-dir/\".parse().unwrap(),\n            // global\n            \"forge-std/=lib/forge-std/src/\".parse().unwrap(),\n            \"nested-lib/=lib/nested-lib/src/\".parse().unwrap(),\n            // remappings local to the lib\n            \"nested-twice/=lib/nested-lib/lib/another-lib/lib/nested-twice/\".parse().unwrap(),\n            \"nested/=lib/nested-lib/lib/nested/\".parse().unwrap(),\n        ]\n    );\n});\n\n// test remappings with closer paths are prioritised\n// so that `dep/=lib/a/src` will take precedent over  `dep/=lib/a/lib/b/src`\nforgetest_init!(can_prioritise_closer_lib_remappings, |prj, cmd| {\n    prj.initialize_default_contracts();\n    let config = cmd.config();\n\n    // create a new lib directly in the `lib` folder with conflicting remapping `forge-std/`\n    let mut config = config;\n    config.remappings = vec![Remapping::from_str(\"forge-std/=lib/forge-std/src/\").unwrap().into()];\n    let nested = prj.paths().libraries[0].join(\"dep1\");\n    pretty_err(&nested, fs::create_dir_all(&nested));\n    let toml_file = nested.join(\"foundry.toml\");\n    pretty_err(&toml_file, fs::write(&toml_file, config.to_string_pretty().unwrap()));\n\n    let config = cmd.config();\n    let remappings = config.get_all_remappings().collect::<Vec<_>>();\n    similar_asserts::assert_eq!(\n        remappings,\n        vec![\n            \"dep1/=lib/dep1/src/\".parse().unwrap(),\n            \"forge-std/=lib/forge-std/src/\".parse().unwrap()\n        ]\n    );\n});\n\n// Test that remappings within root of the project have priority over remappings of sub-projects.\n// E.g. `@utils/libraries` mapping from library shouldn't be added if project already has `@utils`\n// remapping.\n// See <https://github.com/foundry-rs/foundry/issues/9146>\n// Test that\n// - single file remapping is properly added, see\n// <https://github.com/foundry-rs/foundry/issues/6706> and <https://github.com/foundry-rs/foundry/issues/8499>\n// - project defined `@openzeppelin/contracts` remapping is added\n// - library defined `@openzeppelin/contracts-upgradeable` remapping is added\n// - library defined `@openzeppelin/contracts/upgradeable` remapping is not added as it conflicts\n// with project defined `@openzeppelin/contracts` remapping\n// See <https://github.com/foundry-rs/foundry/issues/9271>\nforgetest_init!(can_prioritise_project_remappings, |prj, cmd| {\n    prj.initialize_default_contracts();\n    let mut config = cmd.config();\n    // Add `@utils/` remapping in project config.\n    config.remappings = vec![\n        Remapping::from_str(\"@utils/libraries/Contract.sol=src/Contract.sol\").unwrap().into(),\n        Remapping::from_str(\"@utils/=src/\").unwrap().into(),\n        Remapping::from_str(\"@openzeppelin/contracts=lib/openzeppelin-contracts/\").unwrap().into(),\n    ];\n    let proj_toml_file = prj.paths().root.join(\"foundry.toml\");\n    pretty_err(&proj_toml_file, fs::write(&proj_toml_file, config.to_string_pretty().unwrap()));\n\n    // Create a new lib in the `lib` folder with conflicting `@utils/libraries` remapping.\n    // This should be filtered out from final remappings as root project already has `@utils/`.\n    let nested = prj.paths().libraries[0].join(\"dep1\");\n    pretty_err(&nested, fs::create_dir_all(&nested));\n    let mut lib_config = Config::load_with_root(&nested).unwrap();\n    lib_config.remappings = vec![\n        Remapping::from_str(\"@utils/libraries/=src/\").unwrap().into(),\n        Remapping::from_str(\"@openzeppelin/contracts-upgradeable/=lib/openzeppelin-upgradeable/\")\n            .unwrap()\n            .into(),\n        Remapping::from_str(\n            \"@openzeppelin/contracts/upgradeable/=lib/openzeppelin-contracts/upgradeable/\",\n        )\n        .unwrap()\n        .into(),\n    ];\n    let lib_toml_file = nested.join(\"foundry.toml\");\n    pretty_err(&lib_toml_file, fs::write(&lib_toml_file, lib_config.to_string_pretty().unwrap()));\n\n    cmd.args([\"remappings\", \"--pretty\"]).assert_success().stdout_eq(str![[r#\"\nGlobal:\n- @utils/libraries/Contract.sol=src/Contract.sol\n- @utils/=src/\n- @openzeppelin/contracts/=lib/openzeppelin-contracts/\n- @openzeppelin/contracts-upgradeable/=lib/dep1/lib/openzeppelin-upgradeable/\n- dep1/=lib/dep1/src/\n- forge-std/=lib/forge-std/src/\n\n\n\"#]]);\n});\n\n// test to check that foundry.toml libs section updates on install\nforgetest!(can_update_libs_section, |prj, cmd| {\n    cmd.git_init();\n\n    // explicitly set gas_price\n    prj.update_config(|config| config.libs = vec![\"node_modules\".into()]);\n\n    cmd.args([\"install\", \"foundry-rs/forge-std\"]).assert_success().stdout_eq(str![[r#\"\nInstalling forge-std in [..] (url: https://github.com/foundry-rs/forge-std, tag: None)\n    Installed forge-std[..]\n\n\"#]]);\n\n    let config = cmd.forge_fuse().config();\n    // `lib` was added automatically\n    let expected = vec![PathBuf::from(\"node_modules\"), PathBuf::from(\"lib\")];\n    assert_eq!(config.libs, expected);\n\n    // additional install don't edit `libs`\n    cmd.forge_fuse().args([\"install\", \"dapphub/ds-test\"]).assert_success().stdout_eq(str![[r#\"\nInstalling ds-test in [..] (url: https://github.com/dapphub/ds-test, tag: None)\n    Installed ds-test\n\n\"#]]);\n\n    let config = cmd.forge_fuse().config();\n    assert_eq!(config.libs, expected);\n});\n\n// test to check that loading the config emits warnings on the root foundry.toml and\n// is silent for any libs\nforgetest!(config_emit_warnings, |prj, cmd| {\n    cmd.git_init();\n\n    cmd.args([\"install\", \"foundry-rs/forge-std\"]).assert_success().stdout_eq(str![[r#\"\nInstalling forge-std in [..] (url: https://github.com/foundry-rs/forge-std, tag: None)\n    Installed forge-std[..]\n\n\"#]]);\n\n    let faulty_toml = r\"[default]\n    src = 'src'\n    out = 'out'\n    libs = ['lib']\";\n\n    fs::write(prj.root().join(\"foundry.toml\"), faulty_toml).unwrap();\n    fs::write(prj.root().join(\"lib\").join(\"forge-std\").join(\"foundry.toml\"), faulty_toml).unwrap();\n\n    cmd.forge_fuse().args([\"config\"]).assert_success().stderr_eq(str![[r#\"\nWarning: Found unknown config section in foundry.toml: [default]\nThis notation for profiles has been deprecated and may result in the profile not being registered in future versions.\nPlease use [profile.default] instead or run `forge config --fix`.\n\n\"#]]);\n});\n\nforgetest_init!(can_skip_remappings_auto_detection, |prj, cmd| {\n    prj.initialize_default_contracts();\n    // explicitly set remapping and libraries\n    prj.update_config(|config| {\n        config.remappings = vec![Remapping::from_str(\"remapping/=lib/remapping/\").unwrap().into()];\n        config.auto_detect_remappings = false;\n    });\n\n    let config = cmd.config();\n\n    // only loads remappings from foundry.toml\n    assert_eq!(config.remappings.len(), 1);\n    assert_eq!(\"remapping/=lib/remapping/\", config.remappings[0].to_string());\n});\n\nforgetest_init!(can_parse_default_fs_permissions, |_prj, cmd| {\n    let config = cmd.config();\n\n    assert_eq!(config.fs_permissions.len(), 1);\n    let permissions = config.fs_permissions.joined(Path::new(\"test\"));\n    let out_permission = permissions.find_permission(Path::new(\"test/out\")).unwrap();\n    assert_eq!(FsAccessPermission::Read, out_permission);\n});\n\nforgetest_init!(can_parse_custom_fs_permissions, |prj, cmd| {\n    prj.initialize_default_contracts();\n    // explicitly set fs permissions\n    prj.update_config(|config| {\n        config.fs_permissions = FsPermissions::new(vec![\n            PathPermission::read(\"./read\"),\n            PathPermission::write(\"./write\"),\n            PathPermission::read_write(\"./write/contracts\"),\n        ]);\n    });\n\n    let config = cmd.config();\n\n    assert_eq!(config.fs_permissions.len(), 3);\n\n    // check read permission\n    let permission = config.fs_permissions.find_permission(Path::new(\"./read\")).unwrap();\n    assert_eq!(permission, FsAccessPermission::Read);\n    // check nested write permission\n    let permission =\n        config.fs_permissions.find_permission(Path::new(\"./write/MyContract.sol\")).unwrap();\n    assert_eq!(permission, FsAccessPermission::Write);\n    // check nested read-write permission\n    let permission = config\n        .fs_permissions\n        .find_permission(Path::new(\"./write/contracts/MyContract.sol\"))\n        .unwrap();\n    assert_eq!(permission, FsAccessPermission::ReadWrite);\n    // check no permission\n    let permission =\n        config.fs_permissions.find_permission(Path::new(\"./bogus\")).unwrap_or_default();\n    assert_eq!(permission, FsAccessPermission::None);\n});\n\n#[cfg(not(target_os = \"windows\"))]\nforgetest_init!(can_resolve_symlink_fs_permissions, |prj, cmd| {\n    prj.initialize_default_contracts();\n    // write config in packages/files/config.json\n    let config_path = prj.root().join(\"packages\").join(\"files\");\n    fs::create_dir_all(&config_path).unwrap();\n    fs::write(config_path.join(\"config.json\"), \"{ enabled: true }\").unwrap();\n\n    // symlink packages/files dir as links/\n    std::os::unix::fs::symlink(\n        Path::new(\"./packages/../packages/../packages/files\"),\n        prj.root().join(\"links\"),\n    )\n    .unwrap();\n\n    // write config, give read access to links/ symlink to packages/files/\n    prj.update_config(|config| {\n        config.fs_permissions =\n            FsPermissions::new(vec![PathPermission::read(Path::new(\"./links/config.json\"))]);\n    });\n\n    let config = cmd.config();\n    let mut fs_permissions = config.fs_permissions;\n    fs_permissions.join_all(prj.root());\n    assert_eq!(fs_permissions.len(), 1);\n\n    // read permission to file should be granted through symlink\n    let permission = fs_permissions.find_permission(&config_path.join(\"config.json\")).unwrap();\n    assert_eq!(permission, FsAccessPermission::Read);\n});\n\n// tests if evm version is normalized for config output\nforgetest!(normalize_config_evm_version, |_prj, cmd| {\n    let output = cmd\n        .args([\"config\", \"--use\", \"0.8.0\", \"--json\"])\n        .assert_success()\n        .get_output()\n        .stdout_lossy();\n    let config: Config = serde_json::from_str(&output).unwrap();\n    assert_eq!(config.evm_version, EvmVersion::Istanbul);\n\n    // See <https://github.com/foundry-rs/foundry/issues/7014>\n    let output = cmd\n        .forge_fuse()\n        .args([\"config\", \"--use\", \"0.8.17\", \"--json\"])\n        .assert_success()\n        .get_output()\n        .stdout_lossy();\n    let config: Config = serde_json::from_str(&output).unwrap();\n    assert_eq!(config.evm_version, EvmVersion::London);\n\n    let output = cmd\n        .forge_fuse()\n        .args([\"config\", \"--use\", \"0.8.18\", \"--json\"])\n        .assert_success()\n        .get_output()\n        .stdout_lossy();\n    let config: Config = serde_json::from_str(&output).unwrap();\n    assert_eq!(config.evm_version, EvmVersion::Paris);\n\n    let output = cmd\n        .forge_fuse()\n        .args([\"config\", \"--use\", \"0.8.23\", \"--json\"])\n        .assert_success()\n        .get_output()\n        .stdout_lossy();\n    let config: Config = serde_json::from_str(&output).unwrap();\n    assert_eq!(config.evm_version, EvmVersion::Shanghai);\n\n    let output = cmd\n        .forge_fuse()\n        .args([\"config\", \"--use\", \"0.8.26\", \"--json\"])\n        .assert_success()\n        .get_output()\n        .stdout_lossy();\n    let config: Config = serde_json::from_str(&output).unwrap();\n    assert_eq!(config.evm_version, EvmVersion::Cancun);\n});\n\n// Tests that root paths are properly resolved even if submodule specifies remappings for them.\n// See <https://github.com/foundry-rs/foundry/issues/3440>\nforgetest_init!(test_submodule_root_path_remappings, |prj, cmd| {\n    prj.initialize_default_contracts();\n    prj.add_script(\n        \"BaseScript.sol\",\n        r#\"\nimport \"forge-std/Script.sol\";\n\ncontract BaseScript is Script {\n}\n   \"#,\n    );\n    prj.add_script(\n        \"MyScript.sol\",\n        r#\"\nimport \"script/BaseScript.sol\";\n\ncontract MyScript is BaseScript {\n}\n   \"#,\n    );\n\n    let nested = prj.paths().libraries[0].join(\"another-dep\");\n    pretty_err(&nested, fs::create_dir_all(&nested));\n    let mut lib_config = Config::load_with_root(&nested).unwrap();\n    lib_config.remappings = vec![\n        Remapping::from_str(\"test/=test/\").unwrap().into(),\n        Remapping::from_str(\"script/=script/\").unwrap().into(),\n    ];\n    let lib_toml_file = nested.join(\"foundry.toml\");\n    pretty_err(&lib_toml_file, fs::write(&lib_toml_file, lib_config.to_string_pretty().unwrap()));\n    cmd.forge_fuse().args([\"build\"]).assert_success();\n});\n\n// Tests that project remappings use config paths.\n// For `src=src/contracts` config, remapping should be `src/contracts/ = src/contracts/`.\n// For `src=src` config, remapping should be `src/ = src/`.\n// <https://github.com/foundry-rs/foundry/issues/9454>\nforgetest_init!(test_project_remappings, |prj, cmd| {\n    prj.initialize_default_contracts();\n    prj.update_config(|config| {\n        config.src = \"src/contracts\".into();\n        config.remappings = vec![Remapping::from_str(\"contracts/=src/contracts/\").unwrap().into()];\n    });\n\n    // Add Counter.sol in `src/contracts` project dir.\n    let src_dir = &prj.root().join(\"src/contracts\");\n    pretty_err(src_dir, fs::create_dir_all(src_dir));\n    pretty_err(\n        src_dir.join(\"Counter.sol\"),\n        fs::write(src_dir.join(\"Counter.sol\"), \"contract Counter{}\"),\n    );\n    prj.add_test(\n        \"CounterTest.sol\",\n        r#\"\nimport \"contracts/Counter.sol\";\n\ncontract CounterTest {\n}\n   \"#,\n    );\n    cmd.forge_fuse().args([\"build\"]).assert_success();\n});\n\n#[cfg(not(feature = \"isolate-by-default\"))]\nforgetest_init!(test_default_config, |prj, cmd| {\n    prj.write_config(Config::default());\n    cmd.forge_fuse().args([\"config\"]).assert_success().stdout_eq(DEFAULT_CONFIG);\n\n    cmd.forge_fuse().args([\"config\", \"--json\"]).assert_success().stdout_eq(str![[r#\"\n{\n  \"src\": \"src\",\n  \"test\": \"test\",\n  \"script\": \"script\",\n  \"out\": \"out\",\n  \"libs\": [\n    \"lib\"\n  ],\n  \"remappings\": [\n    \"forge-std/=lib/forge-std/src/\"\n  ],\n  \"auto_detect_remappings\": true,\n  \"libraries\": [],\n  \"cache\": true,\n  \"cache_path\": \"cache\",\n  \"dynamic_test_linking\": false,\n  \"snapshots\": \"snapshots\",\n  \"gas_snapshot_check\": false,\n  \"gas_snapshot_emit\": true,\n  \"broadcast\": \"broadcast\",\n  \"allow_paths\": [],\n  \"include_paths\": [],\n  \"skip\": [],\n  \"force\": false,\n  \"evm_version\": \"osaka\",\n  \"gas_reports\": [\n    \"*\"\n  ],\n  \"gas_reports_ignore\": [],\n  \"gas_reports_include_tests\": false,\n  \"solc\": null,\n  \"auto_detect_solc\": true,\n  \"offline\": false,\n  \"optimizer\": false,\n  \"optimizer_runs\": 200,\n  \"optimizer_details\": null,\n  \"model_checker\": null,\n  \"verbosity\": 0,\n  \"eth_rpc_url\": null,\n  \"eth_rpc_accept_invalid_certs\": false,\n  \"eth_rpc_no_proxy\": false,\n  \"eth_rpc_jwt\": null,\n  \"eth_rpc_timeout\": null,\n  \"eth_rpc_headers\": null,\n  \"eth_rpc_curl\": false,\n  \"etherscan_api_key\": null,\n  \"ignored_error_codes\": [\n    \"license\",\n    \"code-size\",\n    \"init-code-size\",\n    \"transient-storage\",\n    \"transfer-deprecated\",\n    \"natspec-memory-safe-assembly-deprecated\"\n  ],\n  \"ignored_warnings_from\": [],\n  \"deny\": \"never\",\n  \"match_test\": null,\n  \"no_match_test\": null,\n  \"match_contract\": null,\n  \"no_match_contract\": null,\n  \"match_path\": null,\n  \"no_match_path\": null,\n  \"no_match_coverage\": null,\n  \"test_failures_file\": \"cache/test-failures\",\n  \"threads\": null,\n  \"show_progress\": false,\n  \"fuzz\": {\n    \"runs\": 256,\n    \"fail_on_revert\": true,\n    \"max_test_rejects\": 65536,\n    \"seed\": null,\n    \"dictionary_weight\": 40,\n    \"include_storage\": true,\n    \"include_push_bytes\": true,\n    \"max_fuzz_dictionary_addresses\": 15728640,\n    \"max_fuzz_dictionary_values\": 9830400,\n    \"max_fuzz_dictionary_literals\": 6553600,\n    \"gas_report_samples\": 256,\n    \"corpus_dir\": null,\n    \"corpus_gzip\": true,\n    \"corpus_min_mutations\": 5,\n    \"corpus_min_size\": 0,\n    \"show_edge_coverage\": false,\n    \"failure_persist_dir\": \"cache/fuzz\",\n    \"show_logs\": false,\n    \"timeout\": null\n  },\n  \"invariant\": {\n    \"runs\": 256,\n    \"depth\": 500,\n    \"fail_on_revert\": false,\n    \"call_override\": false,\n    \"dictionary_weight\": 80,\n    \"include_storage\": true,\n    \"include_push_bytes\": true,\n    \"max_fuzz_dictionary_addresses\": 15728640,\n    \"max_fuzz_dictionary_values\": 9830400,\n    \"max_fuzz_dictionary_literals\": 6553600,\n    \"shrink_run_limit\": 5000,\n    \"max_assume_rejects\": 65536,\n    \"gas_report_samples\": 256,\n    \"corpus_dir\": null,\n    \"corpus_gzip\": true,\n    \"corpus_min_mutations\": 5,\n    \"corpus_min_size\": 0,\n    \"show_edge_coverage\": false,\n    \"failure_persist_dir\": \"cache/invariant\",\n    \"show_metrics\": true,\n    \"timeout\": null,\n    \"show_solidity\": false,\n    \"max_time_delay\": null,\n    \"max_block_delay\": null,\n    \"check_interval\": 1\n  },\n  \"ffi\": false,\n  \"live_logs\": false,\n  \"allow_internal_expect_revert\": false,\n  \"always_use_create_2_factory\": false,\n  \"prompt_timeout\": 120,\n  \"sender\": \"0x1804c8ab1f12e6bbf3894d4083f33e07309d1f38\",\n  \"tx_origin\": \"0x1804c8ab1f12e6bbf3894d4083f33e07309d1f38\",\n  \"initial_balance\": \"0xffffffffffffffffffffffff\",\n  \"block_number\": 1,\n  \"fork_block_number\": null,\n  \"chain_id\": null,\n  \"gas_limit\": 1073741824,\n  \"code_size_limit\": null,\n  \"gas_price\": null,\n  \"block_base_fee_per_gas\": 0,\n  \"block_coinbase\": \"0x0000000000000000000000000000000000000000\",\n  \"block_timestamp\": 1,\n  \"block_difficulty\": 0,\n  \"block_prevrandao\": \"0x0000000000000000000000000000000000000000000000000000000000000000\",\n  \"block_gas_limit\": null,\n  \"memory_limit\": 134217728,\n  \"extra_output\": [],\n  \"extra_output_files\": [],\n  \"names\": false,\n  \"sizes\": false,\n  \"via_ir\": false,\n  \"ast\": false,\n  \"rpc_storage_caching\": {\n    \"chains\": \"all\",\n    \"endpoints\": \"all\"\n  },\n  \"no_storage_caching\": false,\n  \"no_rpc_rate_limit\": false,\n  \"use_literal_content\": false,\n  \"bytecode_hash\": \"ipfs\",\n  \"cbor_metadata\": true,\n  \"revert_strings\": null,\n  \"sparse_mode\": false,\n  \"build_info\": false,\n  \"build_info_path\": null,\n  \"fmt\": {\n    \"line_length\": 120,\n    \"tab_width\": 4,\n    \"style\": \"space\",\n    \"bracket_spacing\": false,\n    \"int_types\": \"long\",\n    \"multiline_func_header\": \"attributes_first\",\n    \"quote_style\": \"double\",\n    \"number_underscore\": \"preserve\",\n    \"hex_underscore\": \"remove\",\n    \"single_line_statement_blocks\": \"preserve\",\n    \"override_spacing\": false,\n    \"wrap_comments\": false,\n    \"docs_style\": \"preserve\",\n    \"ignore\": [],\n    \"contract_new_lines\": false,\n    \"sort_imports\": false,\n    \"namespace_import_style\": \"prefer_plain\",\n    \"pow_no_space\": false,\n    \"prefer_compact\": \"all\",\n    \"single_line_imports\": false\n  },\n  \"lint\": {\n    \"severity\": [\n      \"high\",\n      \"medium\",\n      \"low\"\n    ],\n    \"exclude_lints\": [],\n    \"ignore\": [],\n    \"lint_on_build\": true,\n    \"lint_specific\": {\n      \"mixed_case_exceptions\": [\n        \"ERC\",\n        \"URI\",\n        \"ID\",\n        \"URL\",\n        \"API\",\n        \"JSON\",\n        \"XML\",\n        \"HTML\",\n        \"HTTP\",\n        \"HTTPS\"\n      ],\n      \"multi_contract_file_exceptions\": []\n    }\n  },\n  \"doc\": {\n    \"out\": \"docs\",\n    \"title\": \"\",\n    \"book\": \"book.toml\",\n    \"homepage\": \"README.md\",\n    \"ignore\": []\n  },\n  \"bind_json\": {\n    \"out\": \"utils/JsonBindings.sol\",\n    \"include\": [],\n    \"exclude\": []\n  },\n  \"fs_permissions\": [\n    {\n      \"access\": \"read\",\n      \"path\": \"out\"\n    }\n  ],\n  \"isolate\": false,\n  \"disable_block_gas_limit\": false,\n  \"enable_tx_gas_limit\": false,\n  \"labels\": {},\n  \"unchecked_cheatcode_artifacts\": false,\n  \"create2_library_salt\": \"0x0000000000000000000000000000000000000000000000000000000000000000\",\n  \"create2_deployer\": \"0x4e59b44847b379578588920ca78fbf26c0b4956c\",\n  \"vyper\": {},\n  \"dependencies\": null,\n  \"soldeer\": null,\n  \"assertions_revert\": true,\n  \"legacy_assertions\": false,\n  \"celo\": false,\n  \"bypass_prevrandao\": false,\n  \"transaction_timeout\": 120,\n  \"additional_compiler_profiles\": [],\n  \"compilation_restrictions\": [],\n  \"script_execution_protection\": true\n}\n\n\"#]]);\n});\n\nforgetest_init!(test_optimizer_config, |prj, cmd| {\n    prj.initialize_default_contracts();\n    // Default settings: optimizer disabled, optimizer runs 200.\n    cmd.forge_fuse().args([\"config\"]).assert_success().stdout_eq(str![[r#\"\n...\noptimizer = false\noptimizer_runs = 200\n...\n\n\"#]]);\n\n    // Optimizer set to true: optimizer runs set to default value of 200.\n    prj.update_config(|config| config.optimizer = Some(true));\n    cmd.forge_fuse().args([\"config\"]).assert_success().stdout_eq(str![[r#\"\n...\noptimizer = true\noptimizer_runs = 200\n...\n\n\"#]]);\n\n    // Optimizer runs set to 0: optimizer should be disabled, runs set to 0.\n    prj.update_config(|config| {\n        config.optimizer = None;\n        config.optimizer_runs = Some(0);\n    });\n    cmd.forge_fuse().args([\"config\"]).assert_success().stdout_eq(str![[r#\"\n...\noptimizer = false\noptimizer_runs = 0\n...\n\n\"#]]);\n\n    // Optimizer runs set to 500: optimizer should be enabled, runs set to 500.\n    prj.update_config(|config| {\n        config.optimizer = None;\n        config.optimizer_runs = Some(500);\n    });\n    cmd.forge_fuse().args([\"config\"]).assert_success().stdout_eq(str![[r#\"\n...\noptimizer = true\noptimizer_runs = 500\n...\n\n\"#]]);\n\n    // Optimizer disabled and runs set to 500: optimizer should be disabled, runs set to 500.\n    prj.update_config(|config| {\n        config.optimizer = Some(false);\n        config.optimizer_runs = Some(500);\n    });\n    cmd.forge_fuse().args([\"config\"]).assert_success().stdout_eq(str![[r#\"\n...\noptimizer = false\noptimizer_runs = 500\n...\n\n\"#]]);\n\n    // Optimizer enabled and runs set to 0: optimizer should be enabled, runs set to 0.\n    prj.update_config(|config| {\n        config.optimizer = Some(true);\n        config.optimizer_runs = Some(0);\n    });\n    cmd.forge_fuse().args([\"config\"]).assert_success().stdout_eq(str![[r#\"\n...\noptimizer = true\noptimizer_runs = 0\n...\n\n\"#]]);\n});\n\nforgetest_init!(test_gas_snapshot_check_config, |prj, cmd| {\n    prj.initialize_default_contracts();\n    // Default settings: gas_snapshot_check disabled.\n    cmd.forge_fuse().args([\"config\"]).assert_success().stdout_eq(str![[r#\"\n...\ngas_snapshot_check = false\n...\n\n\"#]]);\n\n    prj.insert_ds_test();\n\n    prj.add_source(\n        \"Flare.sol\",\n        r#\"\ncontract Flare {\n    bytes32[] public data;\n\n    function run(uint256 n_) public {\n        for (uint256 i = 0; i < n_; i++) {\n            data.push(keccak256(abi.encodePacked(i)));\n        }\n    }\n}\n    \"#,\n    );\n\n    let test_contract = |n: u32| {\n        format!(\n            r#\"\nimport \"./test.sol\";\nimport \"./Flare.sol\";\n\ninterface Vm {{\n    function startSnapshotGas(string memory name) external;\n    function stopSnapshotGas() external returns (uint256);\n}}\n\ncontract GasSnapshotCheckTest is DSTest {{\n    Vm constant vm = Vm(HEVM_ADDRESS);\n\n    Flare public flare;\n\n    function setUp() public {{\n        flare = new Flare();\n    }}\n\n    function testSnapshotGasSectionExternal() public {{\n        vm.startSnapshotGas(\"testAssertGasExternal\");\n        flare.run({n});\n        vm.stopSnapshotGas();\n    }}\n}}\n        \"#\n        )\n    };\n\n    // Assert that gas_snapshot_check is disabled by default.\n    prj.add_source(\"GasSnapshotCheckTest.sol\", &test_contract(1));\n    cmd.forge_fuse().args([\"test\"]).assert_success().stdout_eq(str![[r#\"\n...\nRan 1 test for src/GasSnapshotCheckTest.sol:GasSnapshotCheckTest\n[PASS] testSnapshotGasSectionExternal() ([GAS])\nSuite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED]\n...\n\"#]]);\n\n    // Enable gas_snapshot_check.\n    prj.update_config(|config| config.gas_snapshot_check = true);\n    cmd.forge_fuse().args([\"config\"]).assert_success().stdout_eq(str![[r#\"\n...\ngas_snapshot_check = true\n...\n\n\"#]]);\n\n    // Replace the test contract with a new one that will fail the gas snapshot check.\n    prj.add_source(\"GasSnapshotCheckTest.sol\", &test_contract(2));\n    cmd.forge_fuse().args([\"test\"]).assert_failure().stderr_eq(str![[r#\"\n...\n[GasSnapshotCheckTest] Failed to match snapshots:\n- [testAssertGasExternal] [..] → [..]\n\nError: Snapshots differ from previous run\n...\n\"#]]);\n\n    // Disable gas_snapshot_check, assert that running the test will pass.\n    prj.update_config(|config| config.gas_snapshot_check = false);\n    cmd.forge_fuse().args([\"test\"]).assert_success().stdout_eq(str![[r#\"\n...\nRan 1 test for src/GasSnapshotCheckTest.sol:GasSnapshotCheckTest\n[PASS] testSnapshotGasSectionExternal() ([GAS])\nSuite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED]\n...\n\"#]]);\n\n    // Re-enable gas_snapshot_check\n    // Assert that the new value has been stored from the previous run and re-run the test.\n    prj.update_config(|config| config.gas_snapshot_check = true);\n    cmd.forge_fuse().args([\"test\"]).assert_success().stdout_eq(str![[r#\"\n...\nRan 1 test for src/GasSnapshotCheckTest.sol:GasSnapshotCheckTest\n[PASS] testSnapshotGasSectionExternal() ([GAS])\nSuite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED]\n...\n\"#]]);\n\n    // Replace the test contract with a new one that will fail the gas_snapshot_check.\n    prj.add_source(\"GasSnapshotCheckTest.sol\", &test_contract(3));\n    cmd.forge_fuse().args([\"test\"]).assert_failure().stderr_eq(str![[r#\"\n...\n[GasSnapshotCheckTest] Failed to match snapshots:\n- [testAssertGasExternal] [..] → [..]\n\nError: Snapshots differ from previous run\n...\n\"#]]);\n\n    // Test that `--gas-snapshot-check=false` flag can be used to disable the gas_snapshot_check.\n    cmd.forge_fuse().args([\"test\", \"--gas-snapshot-check=false\"]).assert_success().stdout_eq(str![\n        [r#\"\n...\nRan 1 test for src/GasSnapshotCheckTest.sol:GasSnapshotCheckTest\n[PASS] testSnapshotGasSectionExternal() ([GAS])\nSuite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED]\n...\n\"#]\n    ]);\n\n    // Disable gas_snapshot_check in the config file.\n    // Enable using `FORGE_SNAPSHOT_CHECK` environment variable.\n    // Assert that this will override the config file value.\n    prj.update_config(|config| config.gas_snapshot_check = false);\n    prj.add_source(\"GasSnapshotCheckTest.sol\", &test_contract(4));\n    cmd.forge_fuse();\n    cmd.env(\"FORGE_SNAPSHOT_CHECK\", \"true\");\n    cmd.args([\"test\"]).assert_failure().stderr_eq(str![[r#\"\n...\n[GasSnapshotCheckTest] Failed to match snapshots:\n- [testAssertGasExternal] [..] → [..]\n\nError: Snapshots differ from previous run\n...\n\"#]]);\n\n    // Assert that `--gas-snapshot-check=true` flag can be used to enable the gas_snapshot_check\n    // even when `FORGE_SNAPSHOT_CHECK` is set to false in the environment variable.\n    cmd.forge_fuse();\n    cmd.env(\"FORGE_SNAPSHOT_CHECK\", \"false\");\n    cmd.args([\"test\", \"--gas-snapshot-check=true\"]).assert_failure().stderr_eq(str![[r#\"\n...\n[GasSnapshotCheckTest] Failed to match snapshots:\n- [testAssertGasExternal] [..] → [..]\n\nError: Snapshots differ from previous run\n...\n\"#]]);\n\n    // Finally assert that `--gas-snapshot-check=false` flag can be used to disable the\n    // gas_snapshot_check even when `FORGE_SNAPSHOT_CHECK` is set to true\n    cmd.forge_fuse();\n    cmd.env(\"FORGE_SNAPSHOT_CHECK\", \"true\");\n    cmd.args([\"test\", \"--gas-snapshot-check=false\"]).assert_success().stdout_eq(str![[r#\"\n...\nRan 1 test for src/GasSnapshotCheckTest.sol:GasSnapshotCheckTest\n[PASS] testSnapshotGasSectionExternal() ([GAS])\nSuite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED]\n...\n\"#]]);\n});\n\nforgetest_init!(test_gas_snapshot_emit_config, |prj, cmd| {\n    prj.initialize_default_contracts();\n    // Default settings: gas_snapshot_emit enabled.\n    cmd.forge_fuse().args([\"config\"]).assert_success().stdout_eq(str![[r#\"\n...\ngas_snapshot_emit = true\n...\n\"#]]);\n\n    prj.insert_ds_test();\n\n    prj.add_source(\n        \"GasSnapshotEmitTest.sol\",\n        r#\"\nimport \"./test.sol\";\n\ninterface Vm {\n    function startSnapshotGas(string memory name) external;\n    function stopSnapshotGas() external returns (uint256);\n}\n\ncontract GasSnapshotEmitTest is DSTest {\n    Vm constant vm = Vm(HEVM_ADDRESS);\n\n    function testSnapshotGasSection() public {\n        vm.startSnapshotGas(\"testSection\");\n        int n = 1;\n        vm.stopSnapshotGas();\n    }\n}\n    \"#,\n    );\n\n    // Assert that gas_snapshot_emit is enabled by default.\n    cmd.forge_fuse().args([\"test\"]).assert_success();\n    // Assert that snapshots were emitted to disk.\n    assert!(prj.root().join(\"snapshots/GasSnapshotEmitTest.json\").exists());\n\n    // Remove the snapshot file.\n    fs::remove_file(prj.root().join(\"snapshots/GasSnapshotEmitTest.json\")).unwrap();\n\n    // Test that `--gas-snapshot-emit=false` flag can be used to disable writing snapshots.\n    cmd.forge_fuse().args([\"test\", \"--gas-snapshot-emit=false\"]).assert_success();\n    // Assert that snapshots were not emitted to disk.\n    assert!(!prj.root().join(\"snapshots/GasSnapshotEmitTest.json\").exists());\n\n    // Test that environment variable `FORGE_SNAPSHOT_EMIT` can be used to disable writing\n    // snapshots.\n    cmd.forge_fuse();\n    cmd.env(\"FORGE_SNAPSHOT_EMIT\", \"false\");\n    cmd.args([\"test\"]).assert_success();\n    // Assert that snapshots were not emitted to disk.\n    assert!(!prj.root().join(\"snapshots/GasSnapshotEmitTest.json\").exists());\n\n    // Test that `--gas-snapshot-emit=true` flag can be used to enable writing snapshots, even when\n    // `FORGE_SNAPSHOT_EMIT` is set to false.\n    cmd.forge_fuse();\n    cmd.env(\"FORGE_SNAPSHOT_EMIT\", \"false\");\n    cmd.args([\"test\", \"--gas-snapshot-emit=true\"]).assert_success();\n    // Assert that snapshots were emitted to disk.\n    assert!(prj.root().join(\"snapshots/GasSnapshotEmitTest.json\").exists());\n\n    // Remove the snapshot file.\n    fs::remove_file(prj.root().join(\"snapshots/GasSnapshotEmitTest.json\")).unwrap();\n\n    // Disable gas_snapshot_emit in the config file.\n    prj.update_config(|config| config.gas_snapshot_emit = false);\n    cmd.forge_fuse().args([\"config\"]).assert_success();\n\n    // Test that snapshots are not emitted to disk, when disabled by config.\n    cmd.forge_fuse().args([\"test\"]).assert_success();\n    // Assert that snapshots were not emitted to disk.\n    assert!(!prj.root().join(\"snapshots/GasSnapshotEmitTest.json\").exists());\n\n    // Test that `--gas-snapshot-emit=true` flag can be used to enable writing snapshots, when\n    // disabled by config.\n    cmd.forge_fuse();\n    cmd.args([\"test\", \"--gas-snapshot-emit=true\"]).assert_success();\n    // Assert that snapshots were emitted to disk.\n    assert!(prj.root().join(\"snapshots/GasSnapshotEmitTest.json\").exists());\n\n    // Remove the snapshot file.\n    fs::remove_file(prj.root().join(\"snapshots/GasSnapshotEmitTest.json\")).unwrap();\n\n    // Test that environment variable `FORGE_SNAPSHOT_EMIT` can be used to enable writing snapshots.\n    cmd.forge_fuse();\n    cmd.env(\"FORGE_SNAPSHOT_EMIT\", \"true\");\n    cmd.args([\"test\"]).assert_success();\n    // Assert that snapshots were emitted to disk.\n    assert!(prj.root().join(\"snapshots/GasSnapshotEmitTest.json\").exists());\n\n    // Remove the snapshot file.\n    fs::remove_file(prj.root().join(\"snapshots/GasSnapshotEmitTest.json\")).unwrap();\n\n    // Test that `--gas-snapshot-emit=false` flag can be used to disable writing snapshots,\n    // even when `FORGE_SNAPSHOT_EMIT` is set to true.\n    cmd.forge_fuse().args([\"test\", \"--gas-snapshot-emit=false\"]).assert_success();\n\n    // Assert that snapshots were not emitted to disk.\n    assert!(!prj.root().join(\"snapshots/GasSnapshotEmitTest.json\").exists());\n});\n\n// Tests compilation restrictions enables optimizer if optimizer runs set to a value higher than 0.\nforgetest_init!(test_additional_compiler_profiles, |prj, cmd| {\n    prj.initialize_default_contracts();\n    prj.add_source(\n        \"v1/Counter.sol\",\n        r#\"\ncontract Counter {\n}\n    \"#,\n    );\n\n    prj.add_source(\n        \"v2/Counter.sol\",\n        r#\"\ncontract Counter {\n}\n    \"#,\n    );\n\n    prj.add_source(\n        \"v3/Counter.sol\",\n        r#\"\ncontract Counter {\n}\n    \"#,\n    );\n\n    // Additional profiles are defined with optimizer runs but without explicitly enabling\n    // optimizer\n    //\n    // additional_compiler_profiles = [\n    //   { name = \"v1\", optimizer_runs = 44444444, via_ir = true, evm_version = \"cancun\" },\n    //   { name = \"v2\", optimizer_runs = 111, via_ir = true },\n    //   { name = \"v3\", optimizer_runs = 800, evm_version = \"istanbul\", via_ir = false },\n    // ]\n    //\n    // compilation_restrictions = [\n    //   # v1\n    //   { paths = \"src/v1/[!i]*.sol\", version = \"0.8.16\", optimizer_runs = 44444444 },\n    //   # v2\n    //   { paths = \"src/v2/{Counter}.sol\", optimizer_runs = 111 },\n    //   # v3\n    //   { paths = \"src/v3/*\", optimizer_runs = 800 },\n    // ]\n    let v1_profile = SettingsOverrides {\n        name: \"v1\".to_string(),\n        via_ir: Some(true),\n        evm_version: Some(EvmVersion::Osaka),\n        optimizer: None,\n        optimizer_runs: Some(44444444),\n        bytecode_hash: None,\n    };\n    let v1_restrictions = CompilationRestrictions {\n        paths: GlobMatcher::from_str(\"src/v1/[!i]*.sol\").unwrap(),\n        version: Some(VersionReq::from_str(\"0.8.16\").unwrap()),\n        via_ir: None,\n        bytecode_hash: None,\n        min_optimizer_runs: None,\n        optimizer_runs: Some(44444444),\n        max_optimizer_runs: None,\n        min_evm_version: None,\n        evm_version: None,\n        max_evm_version: None,\n    };\n    let v2_profile = SettingsOverrides {\n        name: \"v2\".to_string(),\n        via_ir: Some(true),\n        evm_version: None,\n        optimizer: None,\n        optimizer_runs: Some(111),\n        bytecode_hash: None,\n    };\n    let v2_restrictions = CompilationRestrictions {\n        paths: GlobMatcher::from_str(\"src/v2/{Counter}.sol\").unwrap(),\n        version: None,\n        via_ir: None,\n        bytecode_hash: None,\n        min_optimizer_runs: None,\n        optimizer_runs: Some(111),\n        max_optimizer_runs: None,\n        min_evm_version: None,\n        evm_version: None,\n        max_evm_version: None,\n    };\n    let v3_profile = SettingsOverrides {\n        name: \"v3\".to_string(),\n        via_ir: Some(false),\n        evm_version: Some(EvmVersion::Istanbul),\n        optimizer: None,\n        optimizer_runs: Some(800),\n        bytecode_hash: None,\n    };\n    let v3_restrictions = CompilationRestrictions {\n        paths: GlobMatcher::from_str(\"src/v3/*\").unwrap(),\n        version: None,\n        via_ir: None,\n        bytecode_hash: None,\n        min_optimizer_runs: None,\n        optimizer_runs: Some(800),\n        max_optimizer_runs: None,\n        min_evm_version: None,\n        evm_version: None,\n        max_evm_version: None,\n    };\n    let additional_compiler_profiles = vec![v1_profile, v2_profile, v3_profile];\n    let compilation_restrictions = vec![v1_restrictions, v2_restrictions, v3_restrictions];\n    prj.update_config(|config| {\n        config.additional_compiler_profiles = additional_compiler_profiles;\n        config.compilation_restrictions = compilation_restrictions;\n    });\n    // Should find and build all profiles satisfying settings restrictions.\n    cmd.forge_fuse().args([\"build\"]).assert_success();\n    prj.assert_artifacts_dir_exists();\n\n    let artifact_settings =\n        |artifact| -> (Option<Value>, Option<Value>, Option<Value>, Option<Value>) {\n            let artifact: serde_json::Value = serde_json::from_reader(\n                fs::File::open(prj.artifacts().join(artifact)).expect(\"no artifact\"),\n            )\n            .expect(\"invalid artifact\");\n            let settings =\n                artifact.get(\"metadata\").unwrap().get(\"settings\").unwrap().as_object().unwrap();\n            let optimizer = settings.get(\"optimizer\").unwrap();\n            (\n                settings.get(\"viaIR\").cloned(),\n                settings.get(\"evmVersion\").cloned(),\n                optimizer.get(\"enabled\").cloned(),\n                optimizer.get(\"runs\").cloned(),\n            )\n        };\n\n    let (via_ir, evm_version, enabled, runs) = artifact_settings(\"Counter.sol/Counter.json\");\n    assert_eq!(None, via_ir);\n    assert_eq!(\"\\\"osaka\\\"\", evm_version.unwrap().to_string());\n    assert_eq!(\"false\", enabled.unwrap().to_string());\n    assert_eq!(\"200\", runs.unwrap().to_string());\n\n    let (via_ir, evm_version, enabled, runs) = artifact_settings(\"v1/Counter.sol/Counter.json\");\n    assert_eq!(\"true\", via_ir.unwrap().to_string());\n    assert_eq!(\"\\\"osaka\\\"\", evm_version.unwrap().to_string());\n    assert_eq!(\"true\", enabled.unwrap().to_string());\n    assert_eq!(\"44444444\", runs.unwrap().to_string());\n\n    let (via_ir, evm_version, enabled, runs) = artifact_settings(\"v2/Counter.sol/Counter.json\");\n    assert_eq!(\"true\", via_ir.unwrap().to_string());\n    assert_eq!(\"\\\"osaka\\\"\", evm_version.unwrap().to_string());\n    assert_eq!(\"true\", enabled.unwrap().to_string());\n    assert_eq!(\"111\", runs.unwrap().to_string());\n\n    let (via_ir, evm_version, enabled, runs) = artifact_settings(\"v3/Counter.sol/Counter.json\");\n    assert_eq!(None, via_ir);\n    assert_eq!(\"\\\"istanbul\\\"\", evm_version.unwrap().to_string());\n    assert_eq!(\"true\", enabled.unwrap().to_string());\n    assert_eq!(\"800\", runs.unwrap().to_string());\n});\n\n// <https://github.com/foundry-rs/foundry/issues/11227>\nforgetest_init!(test_exclude_lints_config, |prj, cmd| {\n    prj.initialize_default_contracts();\n    prj.update_config(|config| {\n        config.lint.exclude_lints = vec![\n            \"asm-keccak256\".to_string(),\n            \"incorrect-shift\".to_string(),\n            \"divide-before-multiply\".to_string(),\n            \"mixed-case-variable\".to_string(),\n            \"mixed-case-function\".to_string(),\n            \"screaming-snake-case-const\".to_string(),\n            \"screaming-snake-case-immutable\".to_string(),\n            \"unwrapped-modifier-logic\".to_string(),\n        ]\n    });\n    cmd.args([\"lint\"]).assert_success().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\n\"#]]);\n});\n\n// <https://github.com/foundry-rs/foundry/issues/6529>\nforgetest_init!(test_fail_fast_config, |prj, cmd| {\n    // Skip if we don't have at least 2 CPUs to run both tests in parallel.\n    if thread::available_parallelism().map_or(1, |n| n.get()) < 2 {\n        return;\n    }\n\n    prj.update_config(|config| {\n        // Set large timeout for fuzzed tests so test campaign won't stop if fail fast not passed.\n        config.fuzz.timeout = Some(3600);\n    });\n    prj.add_test(\n        \"AnotherCounterTest.sol\",\n        r#\"\nimport {Test} from \"forge-std/Test.sol\";\n\ncontract AnotherCounterTest is Test {\n    // This failure should stop all other tests.\n    function test_Failure() public pure {\n        require(false);\n    }\n\n    function testFuzz_SetNumber(uint256 x) public {\n    }\n}\n\"#,\n    );\n    cmd.args([\"test\", \"--fail-fast\"]).assert_failure();\n});\n\nforgetest!(config_deny_warnings_is_deprecated, |prj, cmd| {\n    cmd.git_init();\n\n    let faulty_toml = DEFAULT_CONFIG.replace(r#\"deny = \"never\"\"#, \"deny_warnings = true\");\n\n    fs::write(prj.root().join(\"foundry.toml\"), faulty_toml).unwrap();\n    cmd.forge_fuse().args([\"config\"]).assert_success().stderr_eq(str![[r#\"\nWarning: Key `deny_warnings` is being deprecated in favor of `deny = warnings`. It will be removed in future versions.\n\n\"#]]);\n});\n\n// <https://github.com/foundry-rs/foundry/issues/5866>\nforgetest!(no_warnings_on_external_sections, |prj, cmd| {\n    cmd.git_init();\n\n    let toml = r\"[profile.default]\n    src = 'src'\n    out = 'out'\n\n    # Custom sections for other tools\n    [external.scopelint]\n    some_flag = 1\n\n    [external.forge_deploy]\n    another_setting = 123\";\n\n    fs::write(prj.root().join(\"foundry.toml\"), toml).unwrap();\n    cmd.forge_fuse().args([\"config\"]).assert_success().stderr_eq(str![[r#\"\n\n\"#]]);\n});\n\n// <https://github.com/foundry-rs/foundry/issues/10550>\nforgetest!(config_warnings_on_unknown_keys, |prj, cmd| {\n    cmd.git_init();\n\n    let faulty_toml = r\"[profile.default]\n    src = 'src'\n    out = 'out'\n    solc_version = '0.8.18'\n    foo = 'unknown'\n\n    [profile.another]\n    src = 'src'\n    out = 'out'\n    bar = 'another_unknown'\";\n\n    fs::write(prj.root().join(\"foundry.toml\"), faulty_toml).unwrap();\n    cmd.forge_fuse().args([\"config\"]).assert_success().stderr_eq(str![[r#\"\nWarning: Found unknown `bar` config for profile `another` defined in foundry.toml.\nWarning: Found unknown `foo` config for profile `default` defined in foundry.toml.\n\n\"#]]);\n});\n\nforgetest_init!(test_ignored_file_paths_normalization, |prj, cmd| {\n    fn gen_contract(name: &str) -> String {\n        let fn_name = name.chars().next().unwrap().to_lowercase().to_string() + &name[1..];\n        format!(\n            r#\"\ncontract {name} {{\n    function {fn_name}() public returns (bool) {{ return true; }}\n}}\n\"#\n        )\n    }\n\n    // Update config to ignore warnings from specific files with various path formats\n    prj.update_config(|config| {\n        config.ignored_file_paths = vec![\n            PathBuf::from(\"./test/IgnoredWithPrefix.sol\"), // With \"./\" prefix\n            PathBuf::from(\"src/IgnoredNoPrefix.sol\"),      // Without \"./\" prefix\n            PathBuf::from(\"./src/nested/IgnoredNested.sol\"), // Nested path with prefix\n        ];\n    });\n\n    // Create contracts that will generate warnings\n    prj.add_source(\"IgnoredNoPrefix.sol\", &gen_contract(\"IgnoredNoPrefix\"));\n    prj.add_test(\"IgnoredWithPrefix.sol\", &gen_contract(\"IgnoredWithPrefix\"));\n\n    fs::create_dir_all(prj.root().join(\"src/nested\")).unwrap();\n    fs::write(prj.root().join(\"src/nested/IgnoredNested.sol\"), gen_contract(\"IgnoredNested\"))\n        .unwrap();\n\n    prj.add_source(\"NotIgnored.sol\", &gen_contract(\"NotIgnored\"));\n\n    // Verify the config loads paths as specified (before normalization)\n    let config = cmd.config();\n    let raw_paths = vec![\n        PathBuf::from(\"./test/IgnoredWithPrefix.sol\"),\n        PathBuf::from(\"src/IgnoredNoPrefix.sol\"),\n        PathBuf::from(\"./src/nested/IgnoredNested.sol\"),\n    ];\n    assert_eq!(config.ignored_file_paths, raw_paths);\n\n    // Build and verify compilation succeeds with just 1 warning:\n    cmd.forge_fuse().args([\"build\"]).assert_success().stdout_eq(\n        r#\"[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful with warnings:\nWarning (2018): Function state mutability can be restricted to pure\n [FILE]:5:5:\n  |\n5 |     function notIgnored() public returns (bool) { return true; }\n  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n\"#,\n    );\n});\n\nforgetest_init!(test_failures_file_normalization, |prj, cmd| {\n    // Update config with custom path containing \"./\" prefix\n    prj.update_config(|config| {\n        config.test_failures_file = PathBuf::from(\"./my-custom-failures\");\n    });\n\n    prj.add_test(\n        \"MixedTests.t.sol\",\n        r#\"\nimport {Test} from \"forge-std/Test.sol\";\n\ncontract MixedTests is Test {\n    function testPass() public pure {\n        require(1 == 1);\n    }\n\n    function testFail() public pure {\n        require(1 == 2, \"testFail failed\");\n    }\n}\n\"#,\n    );\n\n    // Run test and verify test_failures_file is created at the correct location\n    cmd.args([\"test\"]).assert_failure();\n    let failures_file = prj.root().join(\"my-custom-failures\");\n    assert!(failures_file.exists());\n    assert!(fs::read_to_string(&failures_file).unwrap().contains(\"testFail\"));\n\n    // Verify --rerun works from subdirectory\n    let rerun_output = cmd\n        .forge_fuse()\n        .current_dir(prj.root().join(\"src\"))\n        .args([\"test\", \"--rerun\"])\n        .assert_failure()\n        .get_output()\n        .stdout_lossy();\n    assert!(rerun_output.contains(\"Ran 1 test\"));\n    assert!(rerun_output.contains(\"testFail()\"));\n    assert!(!rerun_output.contains(\"[PASS] testPass()\"));\n});\n"
  },
  {
    "path": "crates/forge/tests/cli/constants.rs",
    "content": "//! various constants\n\npub const TEMPLATE_CONTRACT: &str = \"Counter\";\n\npub const TEMPLATE_TEST_CONTRACT: &str = \"CounterTest\";\n\npub const TEMPLATE_CONTRACT_ARTIFACT_BASE: &str = \"Counter.sol/Counter\";\n\npub const TEMPLATE_CONTRACT_ARTIFACT_JSON: &str = \"Counter.sol/Counter.json\";\n\npub const TEMPLATE_TEST_CONTRACT_ARTIFACT_JSON: &str = \"Counter.t.sol/CounterTest.json\";\n"
  },
  {
    "path": "crates/forge/tests/cli/context.rs",
    "content": "//! Contains tests for checking forge execution context cheatcodes\nconst FORGE_TEST_CONTEXT_CONTRACT: &str = r#\"\nimport \"./test.sol\";\ninterface Vm {\n    enum ForgeContext { TestGroup, Test, Coverage, Snapshot, ScriptGroup, ScriptDryRun, ScriptBroadcast, ScriptResume, Unknown }\n    function isContext(ForgeContext context) external view returns (bool isContext);\n}\n\ncontract ForgeContextTest is DSTest {\n    Vm constant vm = Vm(HEVM_ADDRESS);\n\n    function testForgeTestContext() external view {\n        require(vm.isContext(Vm.ForgeContext.TestGroup) && !vm.isContext(Vm.ForgeContext.ScriptGroup), \"wrong context\");\n        require(vm.isContext(Vm.ForgeContext.Test), \"wrong context\");\n        require(!vm.isContext(Vm.ForgeContext.Coverage), \"wrong context\");\n        require(!vm.isContext(Vm.ForgeContext.Snapshot), \"wrong context\");\n    }\n    function testForgeSnapshotContext() external view {\n        require(vm.isContext(Vm.ForgeContext.TestGroup) && !vm.isContext(Vm.ForgeContext.ScriptGroup), \"wrong context\");\n        require(vm.isContext(Vm.ForgeContext.Snapshot), \"wrong context\");\n        require(!vm.isContext(Vm.ForgeContext.Test), \"wrong context\");\n        require(!vm.isContext(Vm.ForgeContext.Coverage), \"wrong context\");\n    }\n    function testForgeCoverageContext() external view {\n        require(vm.isContext(Vm.ForgeContext.TestGroup) && !vm.isContext(Vm.ForgeContext.ScriptGroup), \"wrong context\");\n        require(vm.isContext(Vm.ForgeContext.Coverage), \"wrong context\");\n        require(!vm.isContext(Vm.ForgeContext.Test), \"wrong context\");\n        require(!vm.isContext(Vm.ForgeContext.Snapshot), \"wrong context\");\n    }\n\n    function runDryRun() external view {\n        require(vm.isContext(Vm.ForgeContext.ScriptGroup) && !vm.isContext(Vm.ForgeContext.TestGroup), \"wrong context\");\n        require(vm.isContext(Vm.ForgeContext.ScriptDryRun), \"wrong context\");\n        require(!vm.isContext(Vm.ForgeContext.ScriptBroadcast), \"wrong context\");\n        require(!vm.isContext(Vm.ForgeContext.ScriptResume), \"wrong context\");\n    }\n    function runBroadcast() external view {\n        require(vm.isContext(Vm.ForgeContext.ScriptGroup) && !vm.isContext(Vm.ForgeContext.TestGroup), \"wrong context\");\n        require(vm.isContext(Vm.ForgeContext.ScriptBroadcast), \"wrong context\");\n        require(!vm.isContext(Vm.ForgeContext.ScriptDryRun), \"wrong context\");\n        require(!vm.isContext(Vm.ForgeContext.ScriptResume), \"wrong context\");\n    }\n}\n   \"#;\n\n// tests that context properly set for `forge test` command\nforgetest!(can_set_forge_test_standard_context, |prj, cmd| {\n    prj.insert_ds_test();\n    prj.add_source(\"ForgeContextTest.t.sol\", FORGE_TEST_CONTEXT_CONTRACT);\n    cmd.args([\"test\", \"--match-test\", \"testForgeTestContext\"]).assert_success();\n});\n\n// tests that context properly set for `forge snapshot` command\nforgetest!(can_set_forge_test_snapshot_context, |prj, cmd| {\n    prj.insert_ds_test();\n    prj.add_source(\"ForgeContextTest.t.sol\", FORGE_TEST_CONTEXT_CONTRACT);\n    cmd.args([\"snapshot\", \"--match-test\", \"testForgeSnapshotContext\"]).assert_success();\n});\n\n// tests that context properly set for `forge coverage` command\nforgetest!(can_set_forge_test_coverage_context, |prj, cmd| {\n    prj.insert_ds_test();\n    prj.add_source(\"ForgeContextTest.t.sol\", FORGE_TEST_CONTEXT_CONTRACT);\n    cmd.args([\"coverage\", \"--match-test\", \"testForgeCoverageContext\"]).assert_success();\n});\n\n// tests that context properly set for `forge script` command\nforgetest!(can_set_forge_script_dry_run_context, |prj, cmd| {\n    prj.insert_ds_test();\n    let script = prj.add_source(\"ForgeScriptContextTest.s.sol\", FORGE_TEST_CONTEXT_CONTRACT);\n    cmd.arg(\"script\").arg(script).args([\"--sig\", \"runDryRun()\"]).assert_success();\n});\n\n// tests that context properly set for `forge script --broadcast` command\nforgetest!(can_set_forge_script_broadcast_context, |prj, cmd| {\n    prj.insert_ds_test();\n    let script = prj.add_source(\"ForgeScriptContextTest.s.sol\", FORGE_TEST_CONTEXT_CONTRACT);\n    cmd.arg(\"script\").arg(script).args([\"--broadcast\", \"--sig\", \"runBroadcast()\"]).assert_success();\n});\n"
  },
  {
    "path": "crates/forge/tests/cli/coverage.rs",
    "content": "use foundry_common::fs::{self, files_with_ext};\nuse foundry_test_utils::{\n    TestCommand, TestProject,\n    snapbox::{Data, IntoData},\n};\nuse std::path::Path;\n\n#[track_caller]\nfn assert_lcov(cmd: &mut TestCommand, data: impl IntoData) {\n    cmd.args([\"--report=lcov\", \"--report-file\"]).assert_file(data.into_data());\n}\n\nfn basic_base(prj: TestProject, mut cmd: TestCommand) {\n    cmd.args([\"coverage\", \"--report=lcov\", \"--report=summary\"]).assert_success().stdout_eq(str![[\n        r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\nAnalysing contracts...\nRunning tests...\n\nRan 2 tests for test/Counter.t.sol:CounterTest\n[PASS] testFuzz_SetNumber(uint256) (runs: 256, [AVG_GAS])\n[PASS] test_Increment() ([GAS])\nSuite result: ok. 2 passed; 0 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 2 tests passed, 0 failed, 0 skipped (2 total tests)\nWrote LCOV report.\n\n╭----------------------+---------------+---------------+---------------+---------------╮\n| File                 | % Lines       | % Statements  | % Branches    | % Funcs       |\n+======================================================================================+\n| script/Counter.s.sol | 0.00% (0/5)   | 0.00% (0/3)   | 100.00% (0/0) | 0.00% (0/2)   |\n|----------------------+---------------+---------------+---------------+---------------|\n| src/Counter.sol      | 100.00% (4/4) | 100.00% (2/2) | 100.00% (0/0) | 100.00% (2/2) |\n|----------------------+---------------+---------------+---------------+---------------|\n| Total                | 44.44% (4/9)  | 40.00% (2/5)  | 100.00% (0/0) | 50.00% (2/4)  |\n╰----------------------+---------------+---------------+---------------+---------------╯\n\n\"#\n    ]]);\n\n    let lcov = prj.root().join(\"lcov.info\");\n    assert!(lcov.exists(), \"lcov.info was not created\");\n    let default_lcov = str![[r#\"\nTN:\nSF:script/Counter.s.sol\nDA:10,0\nFN:10,CounterScript.setUp\nFNDA:0,CounterScript.setUp\nDA:12,0\nFN:12,CounterScript.run\nFNDA:0,CounterScript.run\nDA:13,0\nDA:15,0\nDA:17,0\nFNF:2\nFNH:0\nLF:5\nLH:0\nBRF:0\nBRH:0\nend_of_record\nTN:\nSF:src/Counter.sol\nDA:7,258\nFN:7,Counter.setNumber\nFNDA:258,Counter.setNumber\nDA:8,258\nDA:11,1\nFN:11,Counter.increment\nFNDA:1,Counter.increment\nDA:12,1\nFNF:2\nFNH:2\nLF:4\nLH:4\nBRF:0\nBRH:0\nend_of_record\n\n\"#]];\n    assert_data_eq!(Data::read_from(&lcov, None), default_lcov.clone());\n    assert_lcov(\n        cmd.forge_fuse().args([\"coverage\", \"--report=lcov\", \"--lcov-version=1\"]),\n        default_lcov,\n    );\n\n    assert_lcov(\n        cmd.forge_fuse().args([\"coverage\", \"--report=lcov\", \"--lcov-version=2\"]),\n        str![[r#\"\nTN:\nSF:script/Counter.s.sol\nDA:10,0\nFN:10,10,CounterScript.setUp\nFNDA:0,CounterScript.setUp\nDA:12,0\nFN:12,18,CounterScript.run\nFNDA:0,CounterScript.run\nDA:13,0\nDA:15,0\nDA:17,0\nFNF:2\nFNH:0\nLF:5\nLH:0\nBRF:0\nBRH:0\nend_of_record\nTN:\nSF:src/Counter.sol\nDA:7,258\nFN:7,9,Counter.setNumber\nFNDA:258,Counter.setNumber\nDA:8,258\nDA:11,1\nFN:11,13,Counter.increment\nFNDA:1,Counter.increment\nDA:12,1\nFNF:2\nFNH:2\nLF:4\nLH:4\nBRF:0\nBRH:0\nend_of_record\n\n\"#]],\n    );\n\n    assert_lcov(\n        cmd.forge_fuse().args([\"coverage\", \"--report=lcov\", \"--lcov-version=2.2\"]),\n        str![[r#\"\nTN:\nSF:script/Counter.s.sol\nDA:10,0\nFNL:0,10,10\nFNA:0,0,CounterScript.setUp\nDA:12,0\nFNL:1,12,18\nFNA:1,0,CounterScript.run\nDA:13,0\nDA:15,0\nDA:17,0\nFNF:2\nFNH:0\nLF:5\nLH:0\nBRF:0\nBRH:0\nend_of_record\nTN:\nSF:src/Counter.sol\nDA:7,258\nFNL:2,7,9\nFNA:2,258,Counter.setNumber\nDA:8,258\nDA:11,1\nFNL:3,11,13\nFNA:3,1,Counter.increment\nDA:12,1\nFNF:2\nFNH:2\nLF:4\nLH:4\nBRF:0\nBRH:0\nend_of_record\n\n\"#]],\n    );\n}\n\nforgetest_init!(basic, |prj, cmd| {\n    prj.initialize_default_contracts();\n    basic_base(prj, cmd);\n});\n\nforgetest_init!(basic_crlf, |prj, cmd| {\n    prj.initialize_default_contracts();\n    // Manually replace `\\n` with `\\r\\n` in the source file.\n    let make_crlf = |path: &Path| {\n        fs::write(path, fs::read_to_string(path).unwrap().replace('\\n', \"\\r\\n\")).unwrap()\n    };\n    make_crlf(&prj.paths().sources.join(\"Counter.sol\"));\n    make_crlf(&prj.paths().scripts.join(\"Counter.s.sol\"));\n\n    // Should have identical stdout and lcov output.\n    basic_base(prj, cmd);\n});\n\nforgetest!(setup, |prj, cmd| {\n    prj.insert_ds_test();\n    prj.add_source(\n        \"AContract.sol\",\n        r#\"\ncontract AContract {\n    int public i;\n\n    function init() public {\n        i = 0;\n    }\n\n    function foo() public {\n        i = 1;\n    }\n}\n    \"#,\n    );\n\n    prj.add_source(\n        \"AContractTest.sol\",\n        r#\"\nimport \"./test.sol\";\nimport {AContract} from \"./AContract.sol\";\n\ncontract AContractTest is DSTest {\n    AContract a;\n\n    function setUp() public {\n        a = new AContract();\n        a.init();\n    }\n\n    function testFoo() public {\n        a.foo();\n    }\n}\n    \"#,\n    );\n\n    // Assert 100% coverage (init function coverage called in setUp is accounted).\n    cmd.arg(\"coverage\").assert_success().stdout_eq(str![[r#\"\n...\n╭-------------------+---------------+---------------+---------------+---------------╮\n| File              | % Lines       | % Statements  | % Branches    | % Funcs       |\n+===================================================================================+\n| src/AContract.sol | 100.00% (4/4) | 100.00% (2/2) | 100.00% (0/0) | 100.00% (2/2) |\n|-------------------+---------------+---------------+---------------+---------------|\n| Total             | 100.00% (4/4) | 100.00% (2/2) | 100.00% (0/0) | 100.00% (2/2) |\n╰-------------------+---------------+---------------+---------------+---------------╯\n\n\"#]]);\n});\n\nforgetest!(setup_md, |prj, cmd| {\n    prj.insert_ds_test();\n    prj.add_source(\n        \"AContract.sol\",\n        r#\"\ncontract AContract {\n    int public i;\n\n    function init() public {\n        i = 0;\n    }\n\n    function foo() public {\n        i = 1;\n    }\n}\n    \"#,\n    );\n\n    prj.add_source(\n        \"AContractTest.sol\",\n        r#\"\nimport \"./test.sol\";\nimport {AContract} from \"./AContract.sol\";\n\ncontract AContractTest is DSTest {\n    AContract a;\n\n    function setUp() public {\n        a = new AContract();\n        a.init();\n    }\n\n    function testFoo() public {\n        a.foo();\n    }\n}\n    \"#,\n    );\n\n    // Assert 100% coverage (init function coverage called in setUp is accounted).\n    cmd.arg(\"coverage\").args([\"--md\"]).assert_success().stdout_eq(str![[r#\"\n...\n| File              | % Lines       | % Statements  | % Branches    | % Funcs       |\n|-------------------|---------------|---------------|---------------|---------------|\n| src/AContract.sol | 100.00% (4/4) | 100.00% (2/2) | 100.00% (0/0) | 100.00% (2/2) |\n| Total             | 100.00% (4/4) | 100.00% (2/2) | 100.00% (0/0) | 100.00% (2/2) |\n\n\"#]]);\n});\n\nforgetest!(no_match, |prj, cmd| {\n    prj.insert_ds_test();\n    prj.add_source(\n        \"AContract.sol\",\n        r#\"\ncontract AContract {\n    int public i;\n\n    function init() public {\n        i = 0;\n    }\n\n    function foo() public {\n        i = 1;\n    }\n}\n    \"#,\n    );\n\n    prj.add_source(\n        \"AContractTest.sol\",\n        r#\"\nimport \"./test.sol\";\nimport {AContract} from \"./AContract.sol\";\n\ncontract AContractTest is DSTest {\n    AContract a;\n\n    function setUp() public {\n        a = new AContract();\n        a.init();\n    }\n\n    function testFoo() public {\n        a.foo();\n    }\n}\n    \"#,\n    );\n\n    prj.add_source(\n        \"BContract.sol\",\n        r#\"\ncontract BContract {\n    int public i;\n\n    function init() public {\n        i = 0;\n    }\n\n    function foo() public {\n        i = 1;\n    }\n}\n    \"#,\n    );\n\n    prj.add_source(\n        \"BContractTest.sol\",\n        r#\"\nimport \"./test.sol\";\nimport {BContract} from \"./BContract.sol\";\n\ncontract BContractTest is DSTest {\n    BContract a;\n\n    function setUp() public {\n        a = new BContract();\n        a.init();\n    }\n\n    function testFoo() public {\n        a.foo();\n    }\n}\n    \"#,\n    );\n\n    // Assert AContract is not included in report.\n    cmd.arg(\"coverage\").arg(\"--no-match-coverage=AContract\").assert_success().stdout_eq(str![[\n        r#\"\n...\n╭-------------------+---------------+---------------+---------------+---------------╮\n| File              | % Lines       | % Statements  | % Branches    | % Funcs       |\n+===================================================================================+\n| src/BContract.sol | 100.00% (4/4) | 100.00% (2/2) | 100.00% (0/0) | 100.00% (2/2) |\n|-------------------+---------------+---------------+---------------+---------------|\n| Total             | 100.00% (4/4) | 100.00% (2/2) | 100.00% (0/0) | 100.00% (2/2) |\n╰-------------------+---------------+---------------+---------------+---------------╯\n\n\"#\n    ]]);\n});\n\nforgetest!(assert, |prj, cmd| {\n    prj.insert_ds_test();\n    prj.add_source(\n        \"AContract.sol\",\n        r#\"\ncontract AContract {\n    function checkA(uint256 a) external pure returns (bool) {\n        assert(a > 2);\n        return true;\n    }\n}\n    \"#,\n    );\n\n    prj.add_source(\n        \"AContractTest.sol\",\n        r#\"\nimport \"./test.sol\";\nimport {AContract} from \"./AContract.sol\";\n\ninterface Vm {\n    function expectRevert() external;\n}\n\ncontract AContractTest is DSTest {\n    Vm constant vm = Vm(HEVM_ADDRESS);\n    AContract a = new AContract();\n\n    function testAssertBranch() external {\n        bool result = a.checkA(10);\n        assertTrue(result);\n    }\n\n    function testAssertRevertBranch() external {\n        vm.expectRevert();\n        a.checkA(1);\n    }\n}\n    \"#,\n    );\n\n    // Assert 50% statement coverage for assert failure (assert not considered a branch).\n    cmd.arg(\"coverage\").args([\"--mt\", \"testAssertRevertBranch\"]).assert_success().stdout_eq(str![\n        [r#\"\n...\n╭-------------------+--------------+--------------+---------------+---------------╮\n| File              | % Lines      | % Statements | % Branches    | % Funcs       |\n+=================================================================================+\n| src/AContract.sol | 66.67% (2/3) | 50.00% (1/2) | 100.00% (0/0) | 100.00% (1/1) |\n|-------------------+--------------+--------------+---------------+---------------|\n| Total             | 66.67% (2/3) | 50.00% (1/2) | 100.00% (0/0) | 100.00% (1/1) |\n╰-------------------+--------------+--------------+---------------+---------------╯\n\n\"#]\n    ]);\n\n    // Assert 100% statement coverage for proper assert (assert not considered a branch).\n    cmd.forge_fuse().arg(\"coverage\").args([\"--mt\", \"testAssertBranch\"]).assert_success().stdout_eq(\n        str![[r#\"\n...\n╭-------------------+---------------+---------------+---------------+---------------╮\n| File              | % Lines       | % Statements  | % Branches    | % Funcs       |\n+===================================================================================+\n| src/AContract.sol | 100.00% (3/3) | 100.00% (2/2) | 100.00% (0/0) | 100.00% (1/1) |\n|-------------------+---------------+---------------+---------------+---------------|\n| Total             | 100.00% (3/3) | 100.00% (2/2) | 100.00% (0/0) | 100.00% (1/1) |\n╰-------------------+---------------+---------------+---------------+---------------╯\n\n\"#]],\n    );\n});\n\nforgetest!(require, |prj, cmd| {\n    prj.insert_ds_test();\n    prj.add_source(\n        \"AContract.sol\",\n        r#\"\ncontract AContract {\n    function checkRequire(bool doNotRevert) public view {\n        require(doNotRevert, \"reverted\");\n    }\n}\n    \"#,\n    );\n\n    prj.add_source(\n        \"AContractTest.sol\",\n        r#\"\nimport \"./test.sol\";\nimport {AContract} from \"./AContract.sol\";\n\ninterface Vm {\n    function expectRevert(bytes calldata revertData) external;\n}\n\ncontract AContractTest is DSTest {\n    Vm constant vm = Vm(HEVM_ADDRESS);\n    AContract a = new AContract();\n\n    function testRequireRevert() external {\n        vm.expectRevert(abi.encodePacked(\"reverted\"));\n        a.checkRequire(false);\n    }\n\n    function testRequireNoRevert() external {\n        a.checkRequire(true);\n    }\n}\n    \"#,\n    );\n\n    // Assert 50% branch coverage if only revert tested.\n    cmd.arg(\"coverage\").args([\"--mt\", \"testRequireRevert\"]).assert_success().stdout_eq(str![[r#\"\n...\n╭-------------------+---------------+---------------+--------------+---------------╮\n| File              | % Lines       | % Statements  | % Branches   | % Funcs       |\n+==================================================================================+\n| src/AContract.sol | 100.00% (2/2) | 100.00% (1/1) | 50.00% (1/2) | 100.00% (1/1) |\n|-------------------+---------------+---------------+--------------+---------------|\n| Total             | 100.00% (2/2) | 100.00% (1/1) | 50.00% (1/2) | 100.00% (1/1) |\n╰-------------------+---------------+---------------+--------------+---------------╯\n\n\"#]]);\n\n    // Assert 50% branch coverage if only happy path tested.\n    cmd.forge_fuse()\n        .arg(\"coverage\")\n        .args([\"--mt\", \"testRequireNoRevert\"])\n        .assert_success()\n        .stdout_eq(str![[r#\"\n...\n╭-------------------+---------------+---------------+--------------+---------------╮\n| File              | % Lines       | % Statements  | % Branches   | % Funcs       |\n+==================================================================================+\n| src/AContract.sol | 100.00% (2/2) | 100.00% (1/1) | 50.00% (1/2) | 100.00% (1/1) |\n|-------------------+---------------+---------------+--------------+---------------|\n| Total             | 100.00% (2/2) | 100.00% (1/1) | 50.00% (1/2) | 100.00% (1/1) |\n╰-------------------+---------------+---------------+--------------+---------------╯\n\n\"#]]);\n\n    // Assert 100% branch coverage.\n    cmd.forge_fuse().arg(\"coverage\").assert_success().stdout_eq(str![[r#\"\n...\n╭-------------------+---------------+---------------+---------------+---------------╮\n| File              | % Lines       | % Statements  | % Branches    | % Funcs       |\n+===================================================================================+\n| src/AContract.sol | 100.00% (2/2) | 100.00% (1/1) | 100.00% (2/2) | 100.00% (1/1) |\n|-------------------+---------------+---------------+---------------+---------------|\n| Total             | 100.00% (2/2) | 100.00% (1/1) | 100.00% (2/2) | 100.00% (1/1) |\n╰-------------------+---------------+---------------+---------------+---------------╯\n\n\"#]]);\n});\n\nforgetest!(line_hit_not_doubled, |prj, cmd| {\n    prj.insert_ds_test();\n    prj.add_source(\n        \"AContract.sol\",\n        r#\"\ncontract AContract {\n    int public i;\n\n    function foo() public {\n        i = 1;\n    }\n}\n    \"#,\n    );\n\n    prj.add_source(\n        \"AContractTest.sol\",\n        r#\"\nimport \"./test.sol\";\nimport {AContract} from \"./AContract.sol\";\n\ncontract AContractTest is DSTest {\n    AContract a = new AContract();\n\n    function testFoo() public {\n        a.foo();\n    }\n}\n    \"#,\n    );\n\n    // We want to make sure DA:8,1 is added only once so line hit is not doubled.\n    assert_lcov(\n        cmd.arg(\"coverage\"),\n        str![[r#\"\nTN:\nSF:src/AContract.sol\nDA:7,1\nFN:7,AContract.foo\nFNDA:1,AContract.foo\nDA:8,1\nFNF:1\nFNH:1\nLF:2\nLH:2\nBRF:0\nBRH:0\nend_of_record\n\n\"#]],\n    );\n});\n\nforgetest!(branch, |prj, cmd| {\n    prj.insert_ds_test();\n    prj.add_source(\n        \"Foo.sol\",\n        r#\"\ncontract Foo {\n    error Gte1(uint256 number, uint256 firstElement);\n\n    enum Status {\n        NULL,\n        OPEN,\n        CLOSED\n    }\n\n    struct Item {\n        Status status;\n        uint256 value;\n    }\n\n    mapping(uint256 => Item) internal items;\n    uint256 public nextId = 1;\n\n    function getItem(uint256 id) public view returns (Item memory item) {\n        item = items[id];\n    }\n\n    function addItem(uint256 value) public returns (uint256 id) {\n        id = nextId;\n        items[id] = Item(Status.OPEN, value);\n        nextId++;\n    }\n\n    function closeIfEqValue(uint256 id, uint256 value) public {\n        if (items[id].value == value) {\n            items[id].status = Status.CLOSED;\n        }\n    }\n\n    function incrementIfEqValue(uint256 id, uint256 value) public {\n        if (items[id].value == value) {\n            items[id].value = value + 1;\n        }\n    }\n\n    function foo(uint256 a) external pure {\n        if (a < 10) {\n            if (a < 3) {\n                assert(a == 1);\n            } else {\n                assert(a == 5);\n            }\n        } else {\n            assert(a == 60);\n        }\n    }\n\n    function countOdd(uint256[] memory arr) external pure returns (uint256 count) {\n        uint256 length = arr.length;\n        for (uint256 i = 0; i < length; ++i) {\n            if (arr[i] % 2 == 1) {\n                count++;\n                arr[0];\n            }\n        }\n    }\n\n    function checkLt(uint256 number, uint256[] memory arr) external pure returns (bool) {\n        if (number >= arr[0]) {\n            revert Gte1(number, arr[0]);\n        }\n        return true;\n    }\n\n    function checkEmptyStatements(uint256 number, uint256[] memory arr) external pure returns (bool) {\n        // Check that empty statements are covered.\n        if (number >= arr[0]) {\n            // Do nothing\n        } else {\n            // Do nothing.\n        }\n        if (number >= arr[0]) {}\n\n        return true;\n    }\n\n    function singlePathCoverage(uint256 number) external pure {\n        if (number < 10) {\n            if (number < 5) {\n                number++;\n            }\n            number++;\n        }\n    }\n}\n    \"#,\n    );\n\n    prj.add_source(\n        \"FooTest.sol\",\n        r#\"\nimport \"./test.sol\";\nimport {Foo} from \"./Foo.sol\";\n\ninterface Vm {\n    function expectRevert(bytes calldata revertData) external;\n    function expectRevert() external;\n}\n\ncontract FooTest is DSTest {\n    Vm constant vm = Vm(HEVM_ADDRESS);\n    Foo internal foo = new Foo();\n\n    function test_issue_7784() external {\n        foo.foo(1);\n        vm.expectRevert();\n        foo.foo(2);\n        vm.expectRevert();\n        foo.foo(4);\n        foo.foo(5);\n        foo.foo(60);\n        vm.expectRevert();\n        foo.foo(70);\n    }\n\n    function test_issue_4310() external {\n        uint256[] memory arr = new uint256[](3);\n        arr[0] = 78;\n        arr[1] = 493;\n        arr[2] = 700;\n        uint256 count = foo.countOdd(arr);\n        assertEq(count, 1);\n\n        arr = new uint256[](4);\n        arr[0] = 78;\n        arr[1] = 493;\n        arr[2] = 700;\n        arr[3] = 1729;\n        count = foo.countOdd(arr);\n        assertEq(count, 2);\n    }\n\n    function test_issue_4315() external {\n        uint256 value = 42;\n        uint256 id = foo.addItem(value);\n        assertEq(id, 1);\n        assertEq(foo.nextId(), 2);\n        Foo.Item memory item = foo.getItem(id);\n        assertEq(uint8(item.status), uint8(Foo.Status.OPEN));\n        assertEq(item.value, value);\n\n        foo = new Foo();\n        id = foo.addItem(value);\n        foo.closeIfEqValue(id, 903);\n        item = foo.getItem(id);\n        assertEq(uint8(item.status), uint8(Foo.Status.OPEN));\n\n        foo = new Foo();\n        foo.addItem(value);\n        foo.closeIfEqValue(id, 42);\n        item = foo.getItem(id);\n        assertEq(uint8(item.status), uint8(Foo.Status.CLOSED));\n\n        foo = new Foo();\n        id = foo.addItem(value);\n        foo.incrementIfEqValue(id, 903);\n        item = foo.getItem(id);\n        assertEq(item.value, 42);\n\n        foo = new Foo();\n        id = foo.addItem(value);\n        foo.incrementIfEqValue(id, 42);\n        item = foo.getItem(id);\n        assertEq(item.value, 43);\n    }\n\n    function test_issue_4309() external {\n        uint256[] memory arr = new uint256[](1);\n        arr[0] = 1;\n        uint256 number = 2;\n        vm.expectRevert(abi.encodeWithSelector(Foo.Gte1.selector, number, arr[0]));\n        foo.checkLt(number, arr);\n\n        number = 1;\n        vm.expectRevert(abi.encodeWithSelector(Foo.Gte1.selector, number, arr[0]));\n        foo.checkLt(number, arr);\n\n        number = 0;\n        bool result = foo.checkLt(number, arr);\n        assertTrue(result);\n    }\n\n    function test_issue_4314() external {\n        uint256[] memory arr = new uint256[](1);\n        arr[0] = 1;\n        foo.checkEmptyStatements(0, arr);\n    }\n\n    function test_single_path_child_branch() external {\n        foo.singlePathCoverage(1);\n    }\n\n    function test_single_path_parent_branch() external {\n        foo.singlePathCoverage(9);\n    }\n\n    function test_single_path_branch() external {\n        foo.singlePathCoverage(15);\n    }\n}\n    \"#,\n    );\n\n    // Assert no coverage for single path branch. 2 branches (parent and child) not covered.\n    cmd.arg(\"coverage\")\n        .args([\"--nmt\", \"test_single_path_child_branch|test_single_path_parent_branch\"])\n        .assert_success()\n        .stdout_eq(str![[r#\"\n...\n╭-------------+----------------+----------------+---------------+---------------╮\n| File        | % Lines        | % Statements   | % Branches    | % Funcs       |\n+===============================================================================+\n| src/Foo.sol | 91.67% (33/36) | 90.00% (27/30) | 80.00% (8/10) | 100.00% (9/9) |\n|-------------+----------------+----------------+---------------+---------------|\n| Total       | 91.67% (33/36) | 90.00% (27/30) | 80.00% (8/10) | 100.00% (9/9) |\n╰-------------+----------------+----------------+---------------+---------------╯\n\n\"#]]);\n\n    // Assert no coverage for single path child branch. 1 branch (child) not covered.\n    cmd.forge_fuse()\n        .arg(\"coverage\")\n        .args([\"--nmt\", \"test_single_path_child_branch\"])\n        .assert_success()\n        .stdout_eq(str![[r#\"\n...\n╭-------------+----------------+----------------+---------------+---------------╮\n| File        | % Lines        | % Statements   | % Branches    | % Funcs       |\n+===============================================================================+\n| src/Foo.sol | 97.22% (35/36) | 96.67% (29/30) | 90.00% (9/10) | 100.00% (9/9) |\n|-------------+----------------+----------------+---------------+---------------|\n| Total       | 97.22% (35/36) | 96.67% (29/30) | 90.00% (9/10) | 100.00% (9/9) |\n╰-------------+----------------+----------------+---------------+---------------╯\n\n\"#]]);\n\n    // Assert 100% coverage.\n    cmd.forge_fuse().arg(\"coverage\").assert_success().stdout_eq(str![[r#\"\n...\n╭-------------+-----------------+-----------------+-----------------+---------------╮\n| File        | % Lines         | % Statements    | % Branches      | % Funcs       |\n+===================================================================================+\n| src/Foo.sol | 100.00% (36/36) | 100.00% (30/30) | 100.00% (10/10) | 100.00% (9/9) |\n|-------------+-----------------+-----------------+-----------------+---------------|\n| Total       | 100.00% (36/36) | 100.00% (30/30) | 100.00% (10/10) | 100.00% (9/9) |\n╰-------------+-----------------+-----------------+-----------------+---------------╯\n\n\"#]]);\n});\n\nforgetest!(function_call, |prj, cmd| {\n    prj.insert_ds_test();\n    prj.add_source(\n        \"AContract.sol\",\n        r#\"\ncontract AContract {\n    struct Custom {\n        bool a;\n        uint256 b;\n    }\n\n    function coverMe() external returns (bool) {\n        // Next lines should not be counted in coverage.\n        string(\"\");\n        uint256(1);\n        address(this);\n        bool(false);\n        Custom(true, 10);\n        // Next lines should be counted in coverage.\n        uint256 a = uint256(1);\n        Custom memory cust = Custom(false, 100);\n        privateWithNoBody();\n        privateWithBody();\n        publicWithNoBody();\n        publicWithBody();\n        return true;\n    }\n\n    function privateWithNoBody() private {}\n\n    function privateWithBody() private returns (bool) {\n        return true;\n    }\n\n    function publicWithNoBody() private {}\n\n    function publicWithBody() private returns (bool) {\n        return true;\n    }\n}\n    \"#,\n    );\n\n    prj.add_source(\n        \"AContractTest.sol\",\n        r#\"\nimport \"./test.sol\";\nimport {AContract} from \"./AContract.sol\";\n\ncontract AContractTest is DSTest {\n    AContract a = new AContract();\n\n    function testTypeConversionCoverage() external {\n        a.coverMe();\n    }\n}\n    \"#,\n    );\n\n    // Assert 100% coverage.\n    cmd.arg(\"coverage\").assert_success().stdout_eq(str![[r#\"\n...\n╭-------------------+-----------------+---------------+---------------+---------------╮\n| File              | % Lines         | % Statements  | % Branches    | % Funcs       |\n+=====================================================================================+\n| src/AContract.sol | 100.00% (14/14) | 100.00% (9/9) | 100.00% (0/0) | 100.00% (5/5) |\n|-------------------+-----------------+---------------+---------------+---------------|\n| Total             | 100.00% (14/14) | 100.00% (9/9) | 100.00% (0/0) | 100.00% (5/5) |\n╰-------------------+-----------------+---------------+---------------+---------------╯\n\n\"#]]);\n});\n\nforgetest!(try_catch, |prj, cmd| {\n    prj.insert_ds_test();\n    prj.add_source(\n        \"Foo.sol\",\n        r#\"\ncontract Foo {\n    address public owner;\n\n    constructor(address _owner) {\n        require(_owner != address(0), \"invalid address\");\n        assert(_owner != 0x0000000000000000000000000000000000000001);\n        owner = _owner;\n    }\n\n    function myFunc(uint256 x) public pure returns (string memory) {\n        require(x != 0, \"require failed\");\n        return \"my func was called\";\n    }\n}\n\ncontract Bar {\n    event Log(string message);\n    event LogBytes(bytes data);\n\n    Foo public foo;\n\n    constructor() {\n        foo = new Foo(msg.sender);\n    }\n\n    function tryCatchExternalCall(uint256 _i) public {\n        try foo.myFunc(_i) returns (string memory result) {\n            emit Log(result);\n        } catch {\n            emit Log(\"external call failed\");\n        }\n    }\n\n    function tryCatchNewContract(address _owner) public {\n        try new Foo(_owner) returns (Foo foo_) {\n            emit Log(\"Foo created\");\n        } catch Error(string memory reason) {\n            emit Log(reason);\n        } catch (bytes memory reason) {}\n    }\n\n    function tryCatchAllNewContract(address _owner) public {\n        try new Foo(_owner) returns (Foo foo_) {} catch {}\n    }\n}\n    \"#,\n    );\n\n    prj.add_source(\n        \"FooTest.sol\",\n        r#\"\nimport \"./test.sol\";\nimport {Bar, Foo} from \"./Foo.sol\";\n\ninterface Vm {\n    function expectRevert() external;\n}\n\ncontract FooTest is DSTest {\n    Vm constant vm = Vm(HEVM_ADDRESS);\n\n    function test_happy_foo_coverage() external {\n        vm.expectRevert();\n        Foo foo = new Foo(address(0));\n        vm.expectRevert();\n        foo = new Foo(address(1));\n        foo = new Foo(address(2));\n    }\n\n    function test_happy_path_coverage() external {\n        Bar bar = new Bar();\n        bar.tryCatchNewContract(0x0000000000000000000000000000000000000002);\n        bar.tryCatchAllNewContract(0x0000000000000000000000000000000000000002);\n        bar.tryCatchExternalCall(1);\n    }\n\n    function test_coverage() external {\n        Bar bar = new Bar();\n        bar.tryCatchNewContract(0x0000000000000000000000000000000000000000);\n        bar.tryCatchNewContract(0x0000000000000000000000000000000000000001);\n        bar.tryCatchAllNewContract(0x0000000000000000000000000000000000000001);\n        bar.tryCatchExternalCall(0);\n    }\n}\n    \"#,\n    );\n\n    // Assert coverage not 100% for happy paths only.\n    cmd.arg(\"coverage\").args([\"--mt\", \"happy\"]).assert_success().stdout_eq(str![[r#\"\n...\n╭-------------+----------------+----------------+--------------+---------------╮\n| File        | % Lines        | % Statements   | % Branches   | % Funcs       |\n+==============================================================================+\n| src/Foo.sol | 77.27% (17/22) | 78.57% (11/14) | 66.67% (6/9) | 100.00% (6/6) |\n|-------------+----------------+----------------+--------------+---------------|\n| Total       | 77.27% (17/22) | 78.57% (11/14) | 66.67% (6/9) | 100.00% (6/6) |\n╰-------------+----------------+----------------+--------------+---------------╯\n\n\"#]]);\n\n    // Assert 100% branch coverage (including clauses without body).\n    cmd.forge_fuse().arg(\"coverage\").assert_success().stdout_eq(str![[r#\"\n...\n╭-------------+-----------------+-----------------+---------------+---------------╮\n| File        | % Lines         | % Statements    | % Branches    | % Funcs       |\n+=================================================================================+\n| src/Foo.sol | 100.00% (22/22) | 100.00% (14/14) | 100.00% (9/9) | 100.00% (6/6) |\n|-------------+-----------------+-----------------+---------------+---------------|\n| Total       | 100.00% (22/22) | 100.00% (14/14) | 100.00% (9/9) | 100.00% (6/6) |\n╰-------------+-----------------+-----------------+---------------+---------------╯\n\n\"#]]);\n});\n\nforgetest!(yul, |prj, cmd| {\n    prj.insert_ds_test();\n    prj.add_source(\n        \"Foo.sol\",\n        r#\"\ncontract Foo {\n    uint256[] dynamicArray;\n\n    function readDynamicArrayLength() public view returns (uint256 length) {\n        assembly {\n            length := sload(dynamicArray.slot)\n        }\n    }\n\n    function switchAndIfStatements(uint256 n) public pure {\n        uint256 y;\n        assembly {\n            switch n\n            case 0 { y := 0 }\n            case 1 { y := 1 }\n            default { y := n }\n\n            if y { y := 2 }\n        }\n    }\n\n    function yulForLoop(uint256 n) public {\n        uint256 y;\n        assembly {\n            for { let i := 0 } lt(i, n) { i := add(i, 1) } { y := add(y, 1) }\n\n            let j := 0\n            for {} lt(j, n) { j := add(j, 1) } { j := add(j, 2) }\n        }\n    }\n\n    function hello() public pure returns (bool, uint256, bytes32) {\n        bool x;\n        uint256 y;\n        bytes32 z;\n\n        assembly {\n            x := 1\n            y := 0xa\n            z := \"Hello World!\"\n        }\n\n        return (x, y, z);\n    }\n\n    function inlineFunction() public returns (uint256) {\n        uint256 result;\n        assembly {\n            function sum(a, b) -> c {\n                c := add(a, b)\n            }\n\n            function multiply(a, b) -> c {\n                for { let i := 0 } lt(i, b) { i := add(i, 1) } { c := add(c, a) }\n            }\n\n            result := sum(2, 3)\n            result := multiply(result, 5)\n        }\n        return result;\n    }\n}\n    \"#,\n    );\n\n    prj.add_source(\n        \"FooTest.sol\",\n        r#\"\nimport \"./test.sol\";\nimport {Foo} from \"./Foo.sol\";\n\ncontract FooTest is DSTest {\n    function test_foo_coverage() external {\n        Foo foo = new Foo();\n        foo.switchAndIfStatements(0);\n        foo.switchAndIfStatements(1);\n        foo.switchAndIfStatements(2);\n        foo.yulForLoop(2);\n        foo.hello();\n        foo.readDynamicArrayLength();\n        foo.inlineFunction();\n    }\n}\n    \"#,\n    );\n\n    cmd.forge_fuse().arg(\"coverage\").assert_success().stdout_eq(str![[r#\"\n...\n╭-------------+-----------------+-----------------+---------------+---------------╮\n| File        | % Lines         | % Statements    | % Branches    | % Funcs       |\n+=================================================================================+\n| src/Foo.sol | 100.00% (30/30) | 100.00% (40/40) | 100.00% (1/1) | 100.00% (7/7) |\n|-------------+-----------------+-----------------+---------------+---------------|\n| Total       | 100.00% (30/30) | 100.00% (40/40) | 100.00% (1/1) | 100.00% (7/7) |\n╰-------------+-----------------+-----------------+---------------+---------------╯\n\n\"#]]);\n});\n\nforgetest!(misc, |prj, cmd| {\n    prj.insert_ds_test();\n    prj.add_source(\n        \"Foo.sol\",\n        r#\"\nstruct Custom {\n    int256 f1;\n}\n\ncontract A {\n    function f(Custom memory custom) public returns (int256) {\n        return custom.f1;\n    }\n}\n\ncontract B {\n    uint256 public x;\n\n    constructor(uint256 a) payable {\n        x = a;\n    }\n}\n\ncontract C {\n    function create() public {\n        B b = new B{value: 1}(2);\n        b = new B{value: 1}(2);\n        b = (new B){value: 1}(2);\n    }\n}\n\ncontract D {\n    uint256 index;\n\n    function g() public {\n        (uint256 x,, uint256 y) = (7, true, 2);\n        (x, y) = (y, x);\n        (index,,) = (7, true, 2);\n    }\n}\n    \"#,\n    );\n\n    prj.add_source(\n        \"FooTest.sol\",\n        r#\"\nimport \"./test.sol\";\nimport \"./Foo.sol\";\n\ninterface Vm {\n    function deal(address account, uint256 newBalance) external;\n}\n\ncontract FooTest is DSTest {\n    Vm constant vm = Vm(HEVM_ADDRESS);\n\n    function test_member_access_coverage() external {\n        A a = new A();\n        Custom memory cust = Custom(1);\n        a.f(cust);\n    }\n\n    function test_new_expression_coverage() external {\n        B b = new B(1);\n        b.x();\n        C c = new C();\n        vm.deal(address(c), 100 ether);\n        c.create();\n    }\n\n    function test_tuple_coverage() external {\n        D d = new D();\n        d.g();\n    }\n}\n    \"#,\n    );\n\n    cmd.forge_fuse().arg(\"coverage\").assert_success().stdout_eq(str![[r#\"\n...\n╭-------------+-----------------+---------------+---------------+---------------╮\n| File        | % Lines         | % Statements  | % Branches    | % Funcs       |\n+===============================================================================+\n| src/Foo.sol | 100.00% (12/12) | 100.00% (9/9) | 100.00% (0/0) | 100.00% (4/4) |\n|-------------+-----------------+---------------+---------------+---------------|\n| Total       | 100.00% (12/12) | 100.00% (9/9) | 100.00% (0/0) | 100.00% (4/4) |\n╰-------------+-----------------+---------------+---------------+---------------╯\n\n\"#]]);\n});\n\n// https://github.com/foundry-rs/foundry/issues/8605\nforgetest!(single_statement, |prj, cmd| {\n    prj.insert_ds_test();\n    prj.add_source(\n        \"AContract.sol\",\n        r#\"\ncontract AContract {\n    event IsTrue(bool isTrue);\n    event IsFalse(bool isFalse);\n\n    function ifElseStatementIgnored(bool flag) external returns (bool) {\n        if (flag) emit IsTrue(true);\n        else emit IsFalse(false);\n\n        bool flag2;\n        if (flag) flag2 = true;\n        else flag2 = false;\n\n        if (flag2) return true;\n        else return false;\n    }\n}\n    \"#,\n    );\n\n    prj.add_source(\n        \"AContractTest.sol\",\n        r#\"\nimport \"./test.sol\";\nimport {AContract} from \"./AContract.sol\";\n\ncontract AContractTest is DSTest {\n    AContract a = new AContract();\n\n    function testTrueCoverage() external {\n        a.ifElseStatementIgnored(true);\n    }\n\n    function testFalseCoverage() external {\n        a.ifElseStatementIgnored(false);\n    }\n}\n    \"#,\n    );\n\n    // Assert 50% coverage for true branches.\n    cmd.arg(\"coverage\").args([\"--mt\", \"testTrueCoverage\"]).assert_success().stdout_eq(str![[r#\"\n...\n╭-------------------+--------------+--------------+--------------+---------------╮\n| File              | % Lines      | % Statements | % Branches   | % Funcs       |\n+================================================================================+\n| src/AContract.sol | 62.50% (5/8) | 57.14% (4/7) | 50.00% (3/6) | 100.00% (1/1) |\n|-------------------+--------------+--------------+--------------+---------------|\n| Total             | 62.50% (5/8) | 57.14% (4/7) | 50.00% (3/6) | 100.00% (1/1) |\n╰-------------------+--------------+--------------+--------------+---------------╯\n\n\"#]]);\n\n    // Assert 50% coverage for false branches.\n    cmd.forge_fuse()\n        .arg(\"coverage\")\n        .args([\"--mt\", \"testFalseCoverage\"])\n        .assert_success()\n        .stdout_eq(str![[r#\"\n...\n╭-------------------+--------------+--------------+--------------+---------------╮\n| File              | % Lines      | % Statements | % Branches   | % Funcs       |\n+================================================================================+\n| src/AContract.sol | 62.50% (5/8) | 57.14% (4/7) | 50.00% (3/6) | 100.00% (1/1) |\n|-------------------+--------------+--------------+--------------+---------------|\n| Total             | 62.50% (5/8) | 57.14% (4/7) | 50.00% (3/6) | 100.00% (1/1) |\n╰-------------------+--------------+--------------+--------------+---------------╯\n\n\"#]]);\n\n    // Assert 100% coverage (true/false branches properly covered).\n    cmd.forge_fuse().arg(\"coverage\").assert_success().stdout_eq(str![[r#\"\n...\n╭-------------------+---------------+---------------+---------------+---------------╮\n| File              | % Lines       | % Statements  | % Branches    | % Funcs       |\n+===================================================================================+\n| src/AContract.sol | 100.00% (8/8) | 100.00% (7/7) | 100.00% (6/6) | 100.00% (1/1) |\n|-------------------+---------------+---------------+---------------+---------------|\n| Total             | 100.00% (8/8) | 100.00% (7/7) | 100.00% (6/6) | 100.00% (1/1) |\n╰-------------------+---------------+---------------+---------------+---------------╯\n\n\"#]]);\n});\n\nforgetest!(single_statement_loop, |prj, cmd| {\n    // TODO(dani): the specific case of `if (x) continue/break` is not properly covered.\n    prj.insert_ds_test();\n    prj.add_source(\n        \"AContract.sol\",\n        r#\"\ncontract AContract {\n    function ifBreakContinueIgnored(bool flag) external returns (uint256 sum) {\n        for (uint256 i = 0; i < 5; i++) {\n            if (flag) continue;\n            sum += i;\n        }\n\n        for (uint256 i = 0; i < 5; i++) {\n            if (flag) break;\n            sum += i;\n        }\n    }\n}\n    \"#,\n    );\n\n    prj.add_source(\n        \"AContractTest.sol\",\n        r#\"\nimport \"./test.sol\";\nimport {AContract} from \"./AContract.sol\";\n\ncontract AContractTest is DSTest {\n    AContract a = new AContract();\n\n    function testTrueCoverage() external {\n        a.ifBreakContinueIgnored(true);\n    }\n\n    function testFalseCoverage() external {\n        a.ifBreakContinueIgnored(false);\n    }\n}\n    \"#,\n    );\n\n    // Assert 50% coverage for true branches.\n    cmd.arg(\"coverage\").args([\"--mt\", \"testTrueCoverage\"]).assert_success().stdout_eq(str![[r#\"\n...\n╭-------------------+--------------+---------------+---------------+---------------╮\n| File              | % Lines      | % Statements  | % Branches    | % Funcs       |\n+==================================================================================+\n| src/AContract.sol | 71.43% (5/7) | 70.00% (7/10) | 100.00% (2/2) | 100.00% (1/1) |\n|-------------------+--------------+---------------+---------------+---------------|\n| Total             | 71.43% (5/7) | 70.00% (7/10) | 100.00% (2/2) | 100.00% (1/1) |\n╰-------------------+--------------+---------------+---------------+---------------╯\n\n\"#]]);\n\n    // Assert 50% coverage for false branches.\n    cmd.forge_fuse()\n        .arg(\"coverage\")\n        .args([\"--mt\", \"testFalseCoverage\"])\n        .assert_success()\n        .stdout_eq(str![[r#\"\n...\n╭-------------------+---------------+-----------------+---------------+---------------╮\n| File              | % Lines       | % Statements    | % Branches    | % Funcs       |\n+=====================================================================================+\n| src/AContract.sol | 100.00% (7/7) | 100.00% (10/10) | 100.00% (2/2) | 100.00% (1/1) |\n|-------------------+---------------+-----------------+---------------+---------------|\n| Total             | 100.00% (7/7) | 100.00% (10/10) | 100.00% (2/2) | 100.00% (1/1) |\n╰-------------------+---------------+-----------------+---------------+---------------╯\n\n\"#]]);\n\n    // Assert 100% coverage (true/false branches properly covered).\n    cmd.forge_fuse().arg(\"coverage\").assert_success().stdout_eq(str![[r#\"\n...\n╭-------------------+---------------+-----------------+---------------+---------------╮\n| File              | % Lines       | % Statements    | % Branches    | % Funcs       |\n+=====================================================================================+\n| src/AContract.sol | 100.00% (7/7) | 100.00% (10/10) | 100.00% (2/2) | 100.00% (1/1) |\n|-------------------+---------------+-----------------+---------------+---------------|\n| Total             | 100.00% (7/7) | 100.00% (10/10) | 100.00% (2/2) | 100.00% (1/1) |\n╰-------------------+---------------+-----------------+---------------+---------------╯\n\n\"#]]);\n});\n\n// https://github.com/foundry-rs/foundry/issues/8604\nforgetest!(branch_with_calldata_reads, |prj, cmd| {\n    prj.insert_ds_test();\n    prj.add_source(\n        \"AContract.sol\",\n        r#\"\ncontract AContract {\n    event IsTrue(bool isTrue);\n    event IsFalse(bool isFalse);\n\n    function execute(bool[] calldata isTrue) external {\n        for (uint256 i = 0; i < isTrue.length; i++) {\n            if (isTrue[i]) {\n                emit IsTrue(isTrue[i]);\n            } else {\n                emit IsFalse(!isTrue[i]);\n            }\n        }\n    }\n}\n    \"#,\n    );\n\n    prj.add_source(\n        \"AContractTest.sol\",\n        r#\"\nimport \"./test.sol\";\nimport {AContract} from \"./AContract.sol\";\n\ncontract AContractTest is DSTest {\n    AContract a = new AContract();\n\n    function testTrueCoverage() external {\n        bool[] memory isTrue = new bool[](1);\n        isTrue[0] = true;\n        a.execute(isTrue);\n    }\n\n    function testFalseCoverage() external {\n        bool[] memory isFalse = new bool[](1);\n        isFalse[0] = false;\n        a.execute(isFalse);\n    }\n}\n    \"#,\n    );\n\n    // Assert 50% coverage for true branches.\n    cmd.arg(\"coverage\").args([\"--mt\", \"testTrueCoverage\"]).assert_success().stdout_eq(str![[r#\"\n...\n╭-------------------+--------------+--------------+--------------+---------------╮\n| File              | % Lines      | % Statements | % Branches   | % Funcs       |\n+================================================================================+\n| src/AContract.sol | 80.00% (4/5) | 80.00% (4/5) | 50.00% (1/2) | 100.00% (1/1) |\n|-------------------+--------------+--------------+--------------+---------------|\n| Total             | 80.00% (4/5) | 80.00% (4/5) | 50.00% (1/2) | 100.00% (1/1) |\n╰-------------------+--------------+--------------+--------------+---------------╯\n\n\"#]]);\n\n    // Assert 50% coverage for false branches.\n    cmd.forge_fuse()\n        .arg(\"coverage\")\n        .args([\"--mt\", \"testFalseCoverage\"])\n        .assert_success()\n        .stdout_eq(str![[r#\"\n...\n╭-------------------+--------------+--------------+--------------+---------------╮\n| File              | % Lines      | % Statements | % Branches   | % Funcs       |\n+================================================================================+\n| src/AContract.sol | 60.00% (3/5) | 80.00% (4/5) | 50.00% (1/2) | 100.00% (1/1) |\n|-------------------+--------------+--------------+--------------+---------------|\n| Total             | 60.00% (3/5) | 80.00% (4/5) | 50.00% (1/2) | 100.00% (1/1) |\n╰-------------------+--------------+--------------+--------------+---------------╯\n\n\"#]]);\n\n    // Assert 100% coverage (true/false branches properly covered).\n    cmd.forge_fuse().arg(\"coverage\").assert_success().stdout_eq(str![[r#\"\n...\n╭-------------------+---------------+---------------+---------------+---------------╮\n| File              | % Lines       | % Statements  | % Branches    | % Funcs       |\n+===================================================================================+\n| src/AContract.sol | 100.00% (5/5) | 100.00% (5/5) | 100.00% (2/2) | 100.00% (1/1) |\n|-------------------+---------------+---------------+---------------+---------------|\n| Total             | 100.00% (5/5) | 100.00% (5/5) | 100.00% (2/2) | 100.00% (1/1) |\n╰-------------------+---------------+---------------+---------------+---------------╯\n\n\"#]]);\n});\n\nforgetest!(identical_bytecodes, |prj, cmd| {\n    prj.insert_ds_test();\n    prj.add_source(\n        \"AContract.sol\",\n        r#\"\ncontract AContract {\n    uint256 public number;\n    address public immutable usdc1;\n    address public immutable usdc2;\n    address public immutable usdc3;\n    address public immutable usdc4;\n    address public immutable usdc5;\n    address public immutable usdc6;\n\n    constructor() {\n        address a = 0x176211869cA2b568f2A7D4EE941E073a821EE1ff;\n        usdc1 = a;\n        usdc2 = a;\n        usdc3 = a;\n        usdc4 = a;\n        usdc5 = a;\n        usdc6 = a;\n    }\n\n    function setNumber(uint256 newNumber) public {\n        number = newNumber;\n    }\n\n    function increment() public {\n        number++;\n    }\n}\n    \"#,\n    );\n\n    prj.add_source(\n        \"AContractTest.sol\",\n        r#\"\nimport \"./test.sol\";\nimport {AContract} from \"./AContract.sol\";\n\ncontract AContractTest is DSTest {\n    AContract public counter;\n\n    function setUp() public {\n        counter = new AContract();\n        counter.setNumber(0);\n    }\n\n    function test_Increment() public {\n        counter.increment();\n        assertEq(counter.number(), 1);\n    }\n}\n    \"#,\n    );\n\n    cmd.arg(\"coverage\").assert_success().stdout_eq(str![[r#\"\n...\n╭-------------------+-----------------+---------------+---------------+---------------╮\n| File              | % Lines         | % Statements  | % Branches    | % Funcs       |\n+=====================================================================================+\n| src/AContract.sol | 100.00% (12/12) | 100.00% (9/9) | 100.00% (0/0) | 100.00% (3/3) |\n|-------------------+-----------------+---------------+---------------+---------------|\n| Total             | 100.00% (12/12) | 100.00% (9/9) | 100.00% (0/0) | 100.00% (3/3) |\n╰-------------------+-----------------+---------------+---------------+---------------╯\n\n\"#]]);\n});\n\nforgetest!(constructors, |prj, cmd| {\n    prj.insert_ds_test();\n    prj.add_source(\n        \"AContract.sol\",\n        r#\"\ncontract AContract {\n    bool public active;\n\n    constructor() {\n        active = true;\n    }\n}\n\ncontract BContract {\n    bool public active;\n\n    constructor() {\n        active = true;\n    }\n}\n    \"#,\n    );\n\n    prj.add_source(\n        \"AContractTest.sol\",\n        r#\"\nimport \"./test.sol\";\nimport \"./AContract.sol\";\n\ncontract AContractTest is DSTest {\n    function test_constructors() public {\n        AContract a = new AContract();\n        BContract b = new BContract();\n    }\n}\n    \"#,\n    );\n\n    cmd.arg(\"coverage\").assert_success().stdout_eq(str![[r#\"\n...\n╭-------------------+---------------+---------------+---------------+---------------╮\n| File              | % Lines       | % Statements  | % Branches    | % Funcs       |\n+===================================================================================+\n| src/AContract.sol | 100.00% (4/4) | 100.00% (2/2) | 100.00% (0/0) | 100.00% (2/2) |\n|-------------------+---------------+---------------+---------------+---------------|\n| Total             | 100.00% (4/4) | 100.00% (2/2) | 100.00% (0/0) | 100.00% (2/2) |\n╰-------------------+---------------+---------------+---------------+---------------╯\n\n\"#]]);\n});\n\n// https://github.com/foundry-rs/foundry/issues/9270, https://github.com/foundry-rs/foundry/issues/9444\n// Test that special functions with no statements are not counted.\n// TODO: We should support this, but for now just ignore them.\n// See TODO in `visit_function_definition`: https://github.com/foundry-rs/foundry/issues/9458\nforgetest!(empty_functions, |prj, cmd| {\n    prj.insert_ds_test();\n    prj.add_source(\n        \"AContract.sol\",\n        r#\"\ncontract AContract {\n    constructor() {}\n\n    receive() external payable {}\n\n    function increment() public {}\n}\n    \"#,\n    );\n\n    prj.add_source(\n        \"AContractTest.sol\",\n        r#\"\nimport \"./test.sol\";\nimport \"./AContract.sol\";\n\ncontract AContractTest is DSTest {\n    function test_constructors() public {\n        AContract a = new AContract();\n        a.increment();\n        (bool success,) = address(a).call{value: 1}(\"\");\n        require(success);\n    }\n}\n    \"#,\n    );\n\n    assert_lcov(\n        cmd.arg(\"coverage\"),\n        str![[r#\"\nTN:\nSF:src/AContract.sol\nDA:9,1\nFN:9,AContract.increment\nFNDA:1,AContract.increment\nFNF:1\nFNH:1\nLF:1\nLH:1\nBRF:0\nBRH:0\nend_of_record\n\n\"#]],\n    );\n\n    // Assert there's only one function (`increment`) reported.\n    cmd.forge_fuse().arg(\"coverage\").assert_success().stdout_eq(str![[r#\"\n...\n╭-------------------+---------------+---------------+---------------+---------------╮\n| File              | % Lines       | % Statements  | % Branches    | % Funcs       |\n+===================================================================================+\n| src/AContract.sol | 100.00% (1/1) | 100.00% (0/0) | 100.00% (0/0) | 100.00% (1/1) |\n|-------------------+---------------+---------------+---------------+---------------|\n| Total             | 100.00% (1/1) | 100.00% (0/0) | 100.00% (0/0) | 100.00% (1/1) |\n╰-------------------+---------------+---------------+---------------+---------------╯\n\n\"#]]);\n});\n\n// Test coverage for `receive` functions.\nforgetest!(receive, |prj, cmd| {\n    prj.insert_ds_test();\n    prj.add_source(\n        \"AContract.sol\",\n        r#\"\ncontract AContract {\n    uint256 public counter = 0;\n\n    constructor() {\n        counter = 1;\n    }\n\n    receive() external payable {\n        counter = msg.value;\n    }\n}\n    \"#,\n    );\n\n    prj.add_source(\n        \"AContractTest.sol\",\n        r#\"\nimport \"./test.sol\";\nimport \"./AContract.sol\";\n\ncontract AContractTest is DSTest {\n    AContract a = new AContract();\n\n    function test_constructors() public {\n        address(a).call{value: 5}(\"\");\n        require(a.counter() == 5);\n    }\n}\n    \"#,\n    );\n\n    // Assert both constructor and receive functions coverage reported and appear in LCOV.\n    assert_lcov(\n        cmd.arg(\"coverage\"),\n        str![[r#\"\nTN:\nSF:src/AContract.sol\nDA:7,1\nFN:7,AContract.constructor\nFNDA:1,AContract.constructor\nDA:8,1\nDA:11,1\nFN:11,AContract.receive\nFNDA:1,AContract.receive\nDA:12,1\nFNF:2\nFNH:2\nLF:4\nLH:4\nBRF:0\nBRH:0\nend_of_record\n\n\"#]],\n    );\n\n    cmd.forge_fuse().arg(\"coverage\").assert_success().stdout_eq(str![[r#\"\n...\n╭-------------------+---------------+---------------+---------------+---------------╮\n| File              | % Lines       | % Statements  | % Branches    | % Funcs       |\n+===================================================================================+\n| src/AContract.sol | 100.00% (4/4) | 100.00% (2/2) | 100.00% (0/0) | 100.00% (2/2) |\n|-------------------+---------------+---------------+---------------+---------------|\n| Total             | 100.00% (4/4) | 100.00% (2/2) | 100.00% (0/0) | 100.00% (2/2) |\n╰-------------------+---------------+---------------+---------------+---------------╯\n\n\"#]]);\n});\n\n// https://github.com/foundry-rs/foundry/issues/9322\n// Test coverage with `--ir-minimum` for solidity < 0.8.5.\nforgetest!(ir_minimum_early, |prj, cmd| {\n    prj.insert_ds_test();\n    prj.add_source(\n        \"AContract.sol\",\n        r#\"\npragma solidity 0.8.4;\n\ncontract AContract {\n    function isContract(address account) internal view returns (bool) {\n        bytes32 codehash;\n        bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;\n        assembly {\n            codehash := extcodehash(account)\n        }\n        return (codehash != accountHash && codehash != 0x0);\n    }\n}\n    \"#,\n    );\n\n    // Assert coverage doesn't fail with `Error: Unknown key \"inliner\"`.\n    cmd.arg(\"coverage\").arg(\"--ir-minimum\").assert_success().stdout_eq(str![[r#\"\n...\n╭-------------------+-------------+--------------+---------------+-------------╮\n| File              | % Lines     | % Statements | % Branches    | % Funcs     |\n+==============================================================================+\n| src/AContract.sol | 0.00% (0/5) | 0.00% (0/4)  | 100.00% (0/0) | 0.00% (0/1) |\n|-------------------+-------------+--------------+---------------+-------------|\n| Total             | 0.00% (0/5) | 0.00% (0/4)  | 100.00% (0/0) | 0.00% (0/1) |\n╰-------------------+-------------+--------------+---------------+-------------╯\n\n\"#]]);\n});\n\nforgetest!(no_artifacts_written, |prj, cmd| {\n    prj.insert_ds_test();\n    prj.add_source(\n        \"AContract.sol\",\n        r#\"\ncontract AContract {\n    int public i;\n\n    function init() public {\n        i = 0;\n    }\n\n    function foo() public {\n        i = 1;\n    }\n}\n    \"#,\n    );\n\n    prj.add_source(\n        \"AContractTest.sol\",\n        r#\"\nimport \"./test.sol\";\nimport {AContract} from \"./AContract.sol\";\n\ncontract AContractTest is DSTest {\n    AContract a;\n\n    function setUp() public {\n        a = new AContract();\n        a.init();\n    }\n\n    function testFoo() public {\n        a.foo();\n    }\n}\n    \"#,\n    );\n\n    cmd.forge_fuse().arg(\"coverage\").assert_success().stdout_eq(str![[r#\"\n...\n╭-------------------+---------------+---------------+---------------+---------------╮\n| File              | % Lines       | % Statements  | % Branches    | % Funcs       |\n+===================================================================================+\n| src/AContract.sol | 100.00% (4/4) | 100.00% (2/2) | 100.00% (0/0) | 100.00% (2/2) |\n|-------------------+---------------+---------------+---------------+---------------|\n| Total             | 100.00% (4/4) | 100.00% (2/2) | 100.00% (0/0) | 100.00% (2/2) |\n╰-------------------+---------------+---------------+---------------+---------------╯\n...\n\"#]]);\n\n    // no artifacts are to be written\n    let files = files_with_ext(prj.artifacts(), \"json\").collect::<Vec<_>>();\n\n    assert!(files.is_empty());\n});\n\n// <https://github.com/foundry-rs/foundry/issues/10172>\nforgetest!(constructor_with_args, |prj, cmd| {\n    prj.insert_ds_test();\n    prj.add_source(\n        \"ArrayCondition.sol\",\n        r#\"\ncontract ArrayCondition {\n    uint8 public constant MAX_SIZE = 32;\n    error TooLarge();\n    error EmptyArray();\n    // Storage variable to ensure the constructor does something\n    uint256 private _arrayLength;\n\n    constructor(uint256[] memory values) {\n        // Check for empty array\n        if (values.length == 0) {\n            revert EmptyArray();\n        }\n\n        if (values.length > MAX_SIZE) {\n            revert TooLarge();\n        }\n\n        // Store the array length\n        _arrayLength = values.length;\n    }\n\n    function getArrayLength() external view returns (uint256) {\n        return _arrayLength;\n    }\n}\n    \"#,\n    );\n\n    prj.add_source(\n        \"ArrayConditionTest.sol\",\n        r#\"\nimport \"./test.sol\";\nimport {ArrayCondition} from \"./ArrayCondition.sol\";\n\ninterface Vm {\n    function expectRevert(bytes4 revertData) external;\n}\n\ncontract ArrayConditionTest is DSTest {\n    Vm constant vm = Vm(HEVM_ADDRESS);\n\n    function testValidSize() public {\n        uint256[] memory values = new uint256[](10);\n        ArrayCondition condition = new ArrayCondition(values);\n        assertEq(condition.getArrayLength(), 10);\n    }\n\n    // Test with maximum array size (should NOT revert)\n    function testMaxSize() public {\n        uint256[] memory values = new uint256[](32);\n        ArrayCondition condition = new ArrayCondition(values);\n        assertEq(condition.getArrayLength(), 32);\n    }\n\n    // Test with too large array size (should revert)\n    function testTooLarge() public {\n        uint256[] memory values = new uint256[](33);\n        vm.expectRevert(ArrayCondition.TooLarge.selector);\n        new ArrayCondition(values);\n    }\n\n    // Test with empty array (should revert)\n    function testEmptyArray() public {\n        uint256[] memory values = new uint256[](0);\n        vm.expectRevert(ArrayCondition.EmptyArray.selector);\n        new ArrayCondition(values);\n    }\n}\n    \"#,\n    );\n\n    cmd.arg(\"coverage\").assert_success().stdout_eq(str![[r#\"\n...\n╭------------------------+---------------+---------------+---------------+---------------╮\n| File                   | % Lines       | % Statements  | % Branches    | % Funcs       |\n+========================================================================================+\n| src/ArrayCondition.sol | 100.00% (8/8) | 100.00% (6/6) | 100.00% (2/2) | 100.00% (2/2) |\n|------------------------+---------------+---------------+---------------+---------------|\n| Total                  | 100.00% (8/8) | 100.00% (6/6) | 100.00% (2/2) | 100.00% (2/2) |\n╰------------------------+---------------+---------------+---------------+---------------╯\n...\n\"#]]);\n});\n\n// https://github.com/foundry-rs/foundry/issues/11432\n// Test coverage for linked libraries.\nforgetest!(linked_library, |prj, cmd| {\n    prj.insert_ds_test();\n    prj.add_source(\n        \"Counter.sol\",\n        r#\"\nlibrary LibCounter {\n    function increment(uint256 number) external returns (uint256) {\n        return number + 1;\n    }\n}\n\ncontract Counter {\n    uint256 public number;\n\n    function increment() public {\n        number = LibCounter.increment(number);\n    }\n}\n    \"#,\n    );\n\n    prj.add_source(\n        \"CounterTest.sol\",\n        r#\"\nimport \"./test.sol\";\nimport {Counter} from \"./Counter.sol\";\n\ncontract CounterTest is DSTest {\n    function testIncrement() public {\n        Counter counter = new Counter();\n        counter.increment();\n    }\n}\n    \"#,\n    );\n\n    // Assert 100% coverage for linked libraries.\n    cmd.arg(\"coverage\").assert_success().stdout_eq(str![[r#\"\n...\n╭-----------------+---------------+---------------+---------------+---------------╮\n| File            | % Lines       | % Statements  | % Branches    | % Funcs       |\n+=================================================================================+\n| src/Counter.sol | 100.00% (4/4) | 100.00% (3/3) | 100.00% (0/0) | 100.00% (2/2) |\n|-----------------+---------------+---------------+---------------+---------------|\n| Total           | 100.00% (4/4) | 100.00% (3/3) | 100.00% (0/0) | 100.00% (2/2) |\n╰-----------------+---------------+---------------+---------------+---------------╯\n...\n\"#]]);\n});\n\n// <https://github.com/foundry-rs/foundry/issues/10422>\n// Test that line hits are properly recorded in lcov report.\nforgetest!(do_while_lcov, |prj, cmd| {\n    prj.insert_ds_test();\n    prj.add_source(\n        \"Counter.sol\",\n        r#\"\ncontract Counter {\n    uint256 public number = 21;\n\n    function increment() public {\n        uint256 i = 0;\n        do {\n            number++;\n            if (number > 20) {\n                number -= 2;\n            }\n        } while (++i < 10);\n    }\n}\n    \"#,\n    );\n\n    prj.add_source(\n        \"Counter.t.sol\",\n        r#\"\nimport \"./test.sol\";\nimport \"./Counter.sol\";\n\ncontract CounterTest is DSTest {\n    function test_do_while() public {\n        Counter counter = new Counter();\n        counter.increment();\n    }\n}\n    \"#,\n    );\n\n    assert_lcov(\n        cmd.arg(\"coverage\"),\n        str![[r#\"\nTN:\nSF:src/Counter.sol\nDA:7,1\nFN:7,Counter.increment\nFNDA:1,Counter.increment\nDA:8,1\nDA:10,10\nDA:11,10\nBRDA:11,0,0,6\nDA:12,6\nDA:14,10\nFNF:1\nFNH:1\nLF:6\nLH:6\nBRF:1\nBRH:1\nend_of_record\n\n\"#]],\n    );\n});\n\n// <https://github.com/foundry-rs/foundry/issues/11183>\n// Test that overridden functions are disambiguated in the LCOV report.\nforgetest!(disambiguate_functions, |prj, cmd| {\n    prj.insert_ds_test();\n    prj.add_source(\n        \"Counter.sol\",\n        r#\"\ncontract Counter {\n    uint256 public number;\n\n    function increment() public {\n        number++;\n    }\n    function increment(uint256 amount) public {\n        number += amount;\n    }\n}\n    \"#,\n    );\n\n    prj.add_source(\n        \"Counter.t.sol\",\n        r#\"\nimport \"./test.sol\";\nimport \"./Counter.sol\";\n\ncontract CounterTest is DSTest {\n    function test_overridden() public {\n        Counter counter = new Counter();\n        counter.increment();\n        counter.increment(1);\n        counter.increment(2);\n        counter.increment(3);\n        assertEq(counter.number(), 7);\n    }\n}\n    \"#,\n    );\n\n    assert_lcov(\n        cmd.arg(\"coverage\"),\n        str![[r#\"\nTN:\nSF:src/Counter.sol\nDA:7,1\nFN:7,Counter.increment.0\nFNDA:1,Counter.increment.0\nDA:8,1\nDA:10,3\nFN:10,Counter.increment.1\nFNDA:3,Counter.increment.1\nDA:11,3\nFNF:2\nFNH:2\nLF:4\nLH:4\nBRF:0\nBRH:0\nend_of_record\n\n\"#]],\n    );\n});\n\n// Test that functions of abstract contracts and interfaces should not count in coverage report.\nforgetest!(abstract_contract_and_interface, |prj, cmd| {\n    prj.insert_ds_test();\n    prj.add_source(\n        \"Counter.sol\",\n        r#\"\ninterface ContractIf {\n    function setNumber(uint256 newNumber) external;\n}\n\nabstract contract AbstractCounter {\n    function _setNumber(uint256 newNumber) internal virtual;\n\n    function _incrementNumber(uint256 newNumber) internal virtual returns (uint256 inc) {\n        inc = newNumber + 1;\n    }\n}\n\ncontract Counter is AbstractCounter, ContractIf {\n    uint256 public number;\n\n    function setNumber(uint256 newNumber) public {\n        _setNumber(newNumber);\n    }\n\n    function _setNumber(uint256 newNumber) internal override {\n        number = _incrementNumber(newNumber);\n    }\n\n    function _incrementNumber(uint256 newNumber) internal override returns (uint256 inc) {\n        inc = super._incrementNumber(newNumber);\n    }\n}\n    \"#,\n    );\n    prj.add_source(\n        \"CounterTest.sol\",\n        r#\"\nimport \"./test.sol\";\nimport {Counter} from \"./Counter.sol\";\n\ncontract CounterTest is DSTest {\n    function testCounter() public {\n        Counter counter = new Counter();\n        counter.setNumber(0);\n    }\n}\n    \"#,\n    );\n\n    // Test there are 4 functions reported:\n    // - `setNumber`, `_setNumber` and `_incrementNumber` from `Counter` contract\n    // - `_incrementNumber` from `AbstractCounter` (virtual with implementation). `_setNumber` is\n    // excluded as it is not implemented.\n    cmd.arg(\"coverage\").assert_success().stdout_eq(str![[r#\"\n...\n╭-----------------+---------------+---------------+---------------+---------------╮\n| File            | % Lines       | % Statements  | % Branches    | % Funcs       |\n+=================================================================================+\n| src/Counter.sol | 100.00% (8/8) | 100.00% (4/4) | 100.00% (0/0) | 100.00% (4/4) |\n|-----------------+---------------+---------------+---------------+---------------|\n| Total           | 100.00% (8/8) | 100.00% (4/4) | 100.00% (0/0) | 100.00% (4/4) |\n╰-----------------+---------------+---------------+---------------+---------------╯\n...\n\"#]]);\n});\n\n// <https://github.com/foundry-rs/foundry/issues/11548>\n// Test BRDA hit values follow LCOV spec: \"-\" when line never executed, \"0\" when line hit but\n// branch not taken. This ensures `genhtml` consistency.\nforgetest!(brda_lcov_consistency, |prj, cmd| {\n    prj.insert_ds_test();\n    prj.add_source(\n        \"Counter.sol\",\n        r#\"\ncontract Counter {\n    uint256 public number;\n\n    function setPositive(uint256 newNumber) public {\n        if (newNumber > 0) {\n            number = newNumber;\n        } else {\n            number = 1;\n        }\n    }\n\n    function neverCalled(uint256 x) public {\n        if (x > 100) {\n            number = x;\n        } else {\n            number = 100;\n        }\n    }\n}\n    \"#,\n    );\n\n    prj.add_source(\n        \"Counter.t.sol\",\n        r#\"\nimport \"./test.sol\";\nimport \"./Counter.sol\";\n\ncontract CounterTest is DSTest {\n    function test_only_positive_branch() public {\n        Counter counter = new Counter();\n        counter.setPositive(42);\n        counter.setPositive(100);\n    }\n}\n    \"#,\n    );\n\n    // Verify BRDA values:\n    // - BRDA:8,0,0,2 - if branch taken 2 times\n    // - BRDA:8,0,1,0 - else branch NOT taken but line was hit (outputs \"0\", not \"-\")\n    // - BRDA:16,1,0,- - if branch NOT taken AND line never executed (outputs \"-\")\n    // - BRDA:16,1,1,- - else branch NOT taken AND line never executed (outputs \"-\")\n    assert_lcov(\n        cmd.arg(\"coverage\"),\n        str![[r#\"\nTN:\nSF:src/Counter.sol\nDA:7,2\nFN:7,Counter.setPositive\nFNDA:2,Counter.setPositive\nDA:8,2\nBRDA:8,0,0,2\nBRDA:8,0,1,0\nDA:9,2\nDA:11,0\nDA:15,0\nFN:15,Counter.neverCalled\nFNDA:0,Counter.neverCalled\nDA:16,0\nBRDA:16,1,0,-\nBRDA:16,1,1,-\nDA:17,0\nDA:19,0\nFNF:2\nFNH:1\nLF:8\nLH:3\nBRF:4\nBRH:1\nend_of_record\n\n\"#]],\n    );\n});\n\n// Test that coverage files are written even when tests fail.\nforgetest!(coverage_with_failing_tests, |prj, cmd| {\n    prj.insert_ds_test();\n    prj.add_source(\n        \"Counter.sol\",\n        r#\"\ncontract Counter {\n    uint256 public number;\n\n    function setNumber(uint256 newNumber) public {\n        number = newNumber;\n    }\n\n    function increment() public {\n        number++;\n    }\n}\n    \"#,\n    );\n\n    prj.add_source(\n        \"CounterTest.sol\",\n        r#\"\nimport \"./test.sol\";\nimport {Counter} from \"./Counter.sol\";\n\ncontract CounterTest is DSTest {\n    Counter public counter;\n\n    function setUp() public {\n        counter = new Counter();\n        counter.setNumber(0);\n    }\n\n    function test_Increment() public {\n        counter.increment();\n        assertEq(counter.number(), 1);\n    }\n\n    function test_FailingTest() public {\n        counter.increment();\n        // This assertion will fail\n        assertEq(counter.number(), 999);\n    }\n}\n    \"#,\n    );\n\n    // Run coverage - this should exit with error code 1 due to failing test,\n    // but the lcov file should still be written.\n    cmd.arg(\"coverage\").args([\"--report=lcov\"]).assert_failure();\n\n    // Verify that the lcov.info file was created despite test failure\n    let lcov = prj.root().join(\"lcov.info\");\n    assert!(lcov.exists(), \"lcov.info should be created even when tests fail\");\n\n    // Verify the coverage data is valid and includes the counter contract\n    let lcov_content = std::fs::read_to_string(&lcov).unwrap();\n    assert!(lcov_content.contains(\"SF:src/Counter.sol\"), \"Coverage should include Counter.sol\");\n    assert!(lcov_content.contains(\"FN:\"), \"Coverage should include function data\");\n    assert!(lcov_content.contains(\"DA:\"), \"Coverage should include line hit data\");\n});\n"
  },
  {
    "path": "crates/forge/tests/cli/create.rs",
    "content": "//! Contains various tests for checking the `forge create` subcommand\n\nuse crate::{\n    constants::*,\n    utils::{self, EnvExternalities},\n};\nuse alloy_primitives::{Address, hex};\nuse anvil::{NodeConfig, spawn};\nuse foundry_compilers::artifacts::{BytecodeHash, remappings::Remapping};\nuse foundry_test_utils::{\n    forgetest, forgetest_async,\n    snapbox::IntoData,\n    str,\n    util::{OutputExt, TestCommand, TestProject},\n};\nuse std::str::FromStr;\n\n/// This will insert _dummy_ contract that uses a library\n///\n/// **NOTE** This is intended to be linked against a random address and won't actually work. The\n/// purpose of this is _only_ to make sure we can deploy contracts linked against addresses.\n///\n/// This will create a library `remapping/MyLib.sol:MyLib`\n///\n/// returns the contract argument for the create command\nfn setup_with_simple_remapping(prj: &TestProject) -> String {\n    // explicitly set remapping and libraries\n    prj.update_config(|config| {\n        config.remappings = vec![Remapping::from_str(\"remapping/=lib/remapping/\").unwrap().into()];\n        config.libraries = vec![format!(\"remapping/MyLib.sol:MyLib:{:?}\", Address::random())];\n    });\n\n    prj.add_source(\n        \"LinkTest\",\n        r#\"\nimport \"remapping/MyLib.sol\";\ncontract LinkTest {\n    function foo() public returns (uint256) {\n        return MyLib.foobar(1);\n    }\n}\n\"#,\n    );\n\n    prj.add_lib(\n        \"remapping/MyLib\",\n        r\"\nlibrary MyLib {\n    function foobar(uint256 a) public view returns (uint256) {\n    \treturn a * 100;\n    }\n}\n\",\n    );\n\n    \"src/LinkTest.sol:LinkTest\".to_string()\n}\n\nfn setup_oracle(prj: &TestProject) -> String {\n    prj.update_config(|c| {\n        c.libraries = vec![format!(\n            \"./src/libraries/ChainlinkTWAP.sol:ChainlinkTWAP:{:?}\",\n            Address::random()\n        )];\n    });\n\n    prj.add_source(\n        \"Contract\",\n        r#\"\nimport {ChainlinkTWAP} from \"./libraries/ChainlinkTWAP.sol\";\ncontract Contract {\n    function getPrice() public view returns (int latest) {\n        latest = ChainlinkTWAP.getLatestPrice(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE);\n    }\n}\n\"#,\n    );\n\n    prj.add_source(\n        \"libraries/ChainlinkTWAP\",\n        r\"\nlibrary ChainlinkTWAP {\n   function getLatestPrice(address base) public view returns (int256) {\n        return 0;\n   }\n}\n\",\n    );\n\n    \"src/Contract.sol:Contract\".to_string()\n}\n\n/// configures the `TestProject` with the given closure and calls the `forge create` command\nfn create_on_chain<F>(info: Option<EnvExternalities>, prj: TestProject, mut cmd: TestCommand, f: F)\nwhere\n    F: FnOnce(&TestProject) -> String,\n{\n    if let Some(info) = info {\n        let contract_path = f(&prj);\n\n        let output = cmd\n            .arg(\"create\")\n            .args(info.create_args())\n            .arg(contract_path)\n            .assert_success()\n            .get_output()\n            .stdout_lossy();\n        let _address = utils::parse_deployed_address(output.as_str())\n            .unwrap_or_else(|| panic!(\"Failed to parse deployer {output}\"));\n    }\n}\n\n// tests `forge` create on goerli if correct env vars are set\nforgetest!(can_create_simple_on_goerli, |prj, cmd| {\n    create_on_chain(EnvExternalities::goerli(), prj, cmd, setup_with_simple_remapping);\n});\n\n// tests `forge` create on goerli if correct env vars are set\nforgetest!(can_create_oracle_on_goerli, |prj, cmd| {\n    create_on_chain(EnvExternalities::goerli(), prj, cmd, setup_oracle);\n});\n\n// tests `forge` create on amoy if correct env vars are set\nforgetest!(can_create_oracle_on_amoy, |prj, cmd| {\n    create_on_chain(EnvExternalities::amoy(), prj, cmd, setup_oracle);\n});\n\n// tests that we can deploy the template contract\nforgetest_async!(can_create_template_contract, |prj, cmd| {\n    foundry_test_utils::util::initialize(prj.root());\n    prj.initialize_default_contracts();\n\n    let (_api, handle) = spawn(NodeConfig::test()).await;\n    let rpc = handle.http_endpoint();\n    let wallet = handle.dev_wallets().next().unwrap();\n    let pk = hex::encode(wallet.credential().to_bytes());\n\n    // explicitly byte code hash for consistent checks\n    prj.update_config(|c| c.bytecode_hash = BytecodeHash::None);\n\n    // Dry-run without the `--broadcast` flag\n    cmd.forge_fuse().args([\n        \"create\",\n        format!(\"./src/{TEMPLATE_CONTRACT}.sol:{TEMPLATE_CONTRACT}\").as_str(),\n        \"--rpc-url\",\n        rpc.as_str(),\n        \"--private-key\",\n        pk.as_str(),\n    ]);\n\n    // Dry-run\n    cmd.assert().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\nContract: Counter\nTransaction: {\n  \"from\": \"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266\",\n  \"to\": null,\n  \"maxFeePerGas\": \"0x77359401\",\n  \"maxPriorityFeePerGas\": \"0x1\",\n  \"gas\": \"0x241e7\",\n  \"input\": \"[..]\",\n  \"nonce\": \"0x0\",\n  \"chainId\": \"0x7a69\"\n}\nABI: [\n  {\n    \"type\": \"function\",\n    \"name\": \"increment\",\n    \"inputs\": [],\n    \"outputs\": [],\n    \"stateMutability\": \"nonpayable\"\n  },\n  {\n    \"type\": \"function\",\n    \"name\": \"number\",\n    \"inputs\": [],\n    \"outputs\": [\n      {\n        \"name\": \"\",\n        \"type\": \"uint256\",\n        \"internalType\": \"uint256\"\n      }\n    ],\n    \"stateMutability\": \"view\"\n  },\n  {\n    \"type\": \"function\",\n    \"name\": \"setNumber\",\n    \"inputs\": [\n      {\n        \"name\": \"newNumber\",\n        \"type\": \"uint256\",\n        \"internalType\": \"uint256\"\n      }\n    ],\n    \"outputs\": [],\n    \"stateMutability\": \"nonpayable\"\n  }\n]\n\n\n\"#]]);\n\n    // Dry-run with `--json` flag\n    cmd.arg(\"--json\").assert().stdout_eq(\n        str![[r#\"\n{\n  \"contract\": \"Counter\",\n  \"transaction\": {\n    \"from\": \"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266\",\n    \"to\": null,\n    \"maxFeePerGas\": \"0x77359401\",\n    \"maxPriorityFeePerGas\": \"0x1\",\n    \"gas\": \"0x241e7\",\n    \"input\": \"[..]\",\n    \"nonce\": \"0x0\",\n    \"chainId\": \"0x7a69\"\n  },\n  \"abi\": [\n    {\n      \"type\": \"function\",\n      \"name\": \"increment\",\n      \"inputs\": [],\n      \"outputs\": [],\n      \"stateMutability\": \"nonpayable\"\n    },\n    {\n      \"type\": \"function\",\n      \"name\": \"number\",\n      \"inputs\": [],\n      \"outputs\": [\n        {\n          \"name\": \"\",\n          \"type\": \"uint256\",\n          \"internalType\": \"uint256\"\n        }\n      ],\n      \"stateMutability\": \"view\"\n    },\n    {\n      \"type\": \"function\",\n      \"name\": \"setNumber\",\n      \"inputs\": [\n        {\n          \"name\": \"newNumber\",\n          \"type\": \"uint256\",\n          \"internalType\": \"uint256\"\n        }\n      ],\n      \"outputs\": [],\n      \"stateMutability\": \"nonpayable\"\n    }\n  ]\n}\n\n\"#]]\n        .is_json(),\n    );\n\n    cmd.forge_fuse().args([\n        \"create\",\n        format!(\"./src/{TEMPLATE_CONTRACT}.sol:{TEMPLATE_CONTRACT}\").as_str(),\n        \"--rpc-url\",\n        rpc.as_str(),\n        \"--private-key\",\n        pk.as_str(),\n        \"--broadcast\",\n    ]);\n\n    cmd.assert().stdout_eq(str![[r#\"\nNo files changed, compilation skipped\nDeployer: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266\nDeployed to: 0x5FbDB2315678afecb367f032d93F642f64180aa3\n[TX_HASH]\n\n\"#]]);\n});\n\n// tests that we can deploy the template contract\nforgetest_async!(can_create_using_unlocked, |prj, cmd| {\n    foundry_test_utils::util::initialize(prj.root());\n    prj.initialize_default_contracts();\n\n    let (_api, handle) = spawn(NodeConfig::test()).await;\n    let rpc = handle.http_endpoint();\n    let dev = handle.dev_accounts().next().unwrap();\n\n    // explicitly byte code hash for consistent checks\n    prj.update_config(|c| c.bytecode_hash = BytecodeHash::None);\n\n    cmd.forge_fuse().args([\n        \"create\",\n        format!(\"./src/{TEMPLATE_CONTRACT}.sol:{TEMPLATE_CONTRACT}\").as_str(),\n        \"--rpc-url\",\n        rpc.as_str(),\n        \"--from\",\n        format!(\"{dev:?}\").as_str(),\n        \"--unlocked\",\n        \"--broadcast\",\n    ]);\n\n    cmd.assert().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\nDeployer: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266\nDeployed to: 0x5FbDB2315678afecb367f032d93F642f64180aa3\n[TX_HASH]\n\n\"#]]);\n\n    cmd.assert().stdout_eq(str![[r#\"\nNo files changed, compilation skipped\nDeployer: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266\nDeployed to: 0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512\n[TX_HASH]\n\n\"#]]);\n});\n\n// tests that we can deploy with constructor args\nforgetest_async!(can_create_with_constructor_args, |prj, cmd| {\n    foundry_test_utils::util::initialize(prj.root());\n\n    let (_api, handle) = spawn(NodeConfig::test()).await;\n    let rpc = handle.http_endpoint();\n    let wallet = handle.dev_wallets().next().unwrap();\n    let pk = hex::encode(wallet.credential().to_bytes());\n\n    // explicitly byte code hash for consistent checks\n    prj.update_config(|c| c.bytecode_hash = BytecodeHash::None);\n\n    prj.add_source(\n        \"ConstructorContract\",\n        r#\"\ncontract ConstructorContract {\n    string public name;\n\n    constructor(string memory _name) {\n        name = _name;\n    }\n}\n\"#,\n    );\n\n    cmd.forge_fuse()\n        .args([\n            \"create\",\n            \"./src/ConstructorContract.sol:ConstructorContract\",\n            \"--rpc-url\",\n            rpc.as_str(),\n            \"--private-key\",\n            pk.as_str(),\n            \"--broadcast\",\n            \"--constructor-args\",\n            \"My Constructor\",\n        ])\n        .assert_success()\n        .stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\nDeployer: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266\nDeployed to: 0x5FbDB2315678afecb367f032d93F642f64180aa3\n[TX_HASH]\n\n\"#]]);\n\n    prj.add_source(\n        \"TupleArrayConstructorContract\",\n        r#\"\nstruct Point {\n    uint256 x;\n    uint256 y;\n}\n\ncontract TupleArrayConstructorContract {\n    constructor(Point[] memory _points) {}\n}\n\"#,\n    );\n\n    cmd.forge_fuse()\n        .args([\n            \"create\",\n            \"./src/TupleArrayConstructorContract.sol:TupleArrayConstructorContract\",\n            \"--rpc-url\",\n            rpc.as_str(),\n            \"--private-key\",\n            pk.as_str(),\n            \"--broadcast\",\n            \"--constructor-args\",\n            \"[(1,2), (2,3), (3,4)]\",\n        ])\n        .assert()\n        .stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\nDeployer: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266\nDeployed to: 0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512\n[TX_HASH]\n\n\"#]]);\n});\n\n// <https://github.com/foundry-rs/foundry/issues/6332>\nforgetest_async!(can_create_and_call, |prj, cmd| {\n    foundry_test_utils::util::initialize(prj.root());\n\n    let (_api, handle) = spawn(NodeConfig::test()).await;\n    let rpc = handle.http_endpoint();\n    let wallet = handle.dev_wallets().next().unwrap();\n    let pk = hex::encode(wallet.credential().to_bytes());\n\n    // explicitly byte code hash for consistent checks\n    prj.update_config(|c| c.bytecode_hash = BytecodeHash::None);\n\n    prj.add_source(\n        \"UniswapV2Swap\",\n        r#\"\ncontract UniswapV2Swap {\n\n    function pairInfo() public view returns (uint reserveA, uint reserveB, uint totalSupply) {\n       (reserveA, reserveB, totalSupply) = (0,0,0);\n    }\n\n}\n\"#,\n    );\n\n    cmd.forge_fuse()\n        .args([\n            \"create\",\n            \"./src/UniswapV2Swap.sol:UniswapV2Swap\",\n            \"--rpc-url\",\n            rpc.as_str(),\n            \"--private-key\",\n            pk.as_str(),\n            \"--broadcast\",\n        ])\n        .assert_success()\n        .stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful with warnings:\nWarning (2018): Function state mutability can be restricted to pure\n [FILE]:6:5:\n  |\n6 |     function pairInfo() public view returns (uint reserveA, uint reserveB, uint totalSupply) {\n  |     ^ (Relevant source part starts here and spans across multiple lines).\n\nDeployer: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266\nDeployed to: 0x5FbDB2315678afecb367f032d93F642f64180aa3\n[TX_HASH]\n\n\"#]]);\n});\n\n// <https://github.com/foundry-rs/foundry/issues/10156>\nforgetest_async!(should_err_if_no_bytecode, |prj, cmd| {\n    let (_api, handle) = spawn(NodeConfig::test()).await;\n    let rpc = handle.http_endpoint();\n\n    prj.add_source(\n        \"AbstractCounter.sol\",\n        r#\"\nabstract contract AbstractCounter {\n    uint256 public number;\n\n    function setNumberV1(uint256 newNumber) public {\n        number = newNumber;\n    }\n\n    function incrementV1() public {\n        number++;\n    }\n}\n    \"#,\n    );\n\n    cmd.args([\n        \"create\",\n        \"./src/AbstractCounter.sol:AbstractCounter\",\n        \"--rpc-url\",\n        rpc.as_str(),\n        \"--private-key\",\n        \"0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80\",\n        \"--broadcast\",\n    ])\n    .assert_failure()\n    .stderr_eq(str![[r#\"\nError: no bytecode found in bin object for AbstractCounter\n\n\"#]]);\n});\n"
  },
  {
    "path": "crates/forge/tests/cli/debug.rs",
    "content": "use itertools::Itertools;\nuse std::path::Path;\n\n// Sets up a debuggable test case.\n// Run with `cargo test-debugger`.\nforgetest!(\n    #[ignore = \"ran manually\"]\n    manual_debug_setup,\n    |prj, cmd| {\n        cmd.args([\"init\", \"--force\"])\n            .arg(prj.root())\n            .assert_success()\n            .stdout_eq(str![[r#\"\nInitializing [..]...\nInstalling forge-std in [..] (url: https://github.com/foundry-rs/forge-std, tag: None)\n    Installed forge-std[..]\n    Initialized forge project\n\n\"#]])\n            .stderr_eq(str![[r#\"\nWarning: Target directory is not empty, but `--force` was specified\n...\n\n\"#]]);\n\n        prj.add_source(\"Counter2.sol\", r#\"\ncontract A {\n    address public a;\n    uint public b;\n    int public c;\n    bytes32 public d;\n    bool public e;\n    bytes public f;\n    string public g;\n\n    constructor(address _a, uint _b, int _c, bytes32 _d, bool _e, bytes memory _f, string memory _g) {\n        a = _a;\n        b = _b;\n        c = _c;\n        d = _d;\n        e = _e;\n        f = _f;\n        g = _g;\n    }\n\n    function getA() public view returns (address) {\n        return a;\n    }\n\n    function setA(address _a) public {\n        a = _a;\n    }\n}\"#,\n        );\n\n        let script = prj.add_script(\"Counter.s.sol\", r#\"\nimport \"../src/Counter2.sol\";\nimport \"forge-std/Script.sol\";\nimport \"forge-std/Test.sol\";\n\ncontract B is A {\n    A public other;\n    address public self = address(this);\n\n    constructor(address _a, uint _b, int _c, bytes32 _d, bool _e, bytes memory _f, string memory _g)\n        A(_a, _b, _c, _d, _e, _f, _g)\n    {\n        other = new A(_a, _b, _c, _d, _e, _f, _g);\n    }\n}\n\ncontract Script0 is Script, Test {\n    function run() external {\n        assertEq(uint256(1), uint256(1));\n\n        vm.startBroadcast();\n        B b = new B(msg.sender, 2 ** 32, -1 * (2 ** 32), keccak256(abi.encode(1)), true, \"abcdef\", \"hello\");\n        assertEq(b.getA(), msg.sender);\n        b.setA(tx.origin);\n        assertEq(b.getA(), tx.origin);\n        address _b = b.self();\n        bytes32 _d = b.d();\n        bytes32 _d2 = b.other().d();\n    }\n}\"#,\n        );\n\n        cmd.forge_fuse().args([\"build\"]).assert_success();\n\n        cmd.args([\n            \"script\",\n            script.to_str().unwrap(),\n            \"--root\",\n            prj.root().to_str().unwrap(),\n            \"--tc=Script0\",\n            \"--debug\",\n        ]);\n        eprintln!(\"root: {}\", prj.root().display());\n        let cmd_path = Path::new(cmd.cmd().get_program()).canonicalize().unwrap();\n        let args = cmd.cmd().get_args().map(|s| s.to_str().unwrap()).format(\" \");\n        eprintln!(\" cmd: {} {args}\", cmd_path.display());\n        std::mem::forget(prj);\n    }\n);\n"
  },
  {
    "path": "crates/forge/tests/cli/doc.rs",
    "content": "use foundry_test_utils::util::{RemoteProject, setup_forge_remote};\n\n#[test]\nfn can_generate_solmate_docs() {\n    let (prj, _) =\n        setup_forge_remote(RemoteProject::new(\"transmissions11/solmate\").set_build(false));\n    prj.forge_command().args([\"doc\", \"--build\"]).assert_success();\n}\n\n// Test that overloaded functions in interfaces inherit the correct NatSpec comments\n// fixes <https://github.com/foundry-rs/foundry/issues/11823>\nforgetest_init!(can_generate_docs_for_overloaded_functions, |prj, cmd| {\n    prj.add_source(\n        \"IExample.sol\",\n        r#\"\n// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IExample {\n    /// @notice Process a single address\n    /// @param addr The address to process\n    function process(address addr) external;\n\n    /// @notice Process multiple addresses\n    /// @param addrs The addresses to process\n    function process(address[] calldata addrs) external;\n\n    /// @notice Process an address with a value\n    /// @param addr The address to process\n    /// @param value The value to use\n    function process(address addr, uint256 value) external;\n}\n\"#,\n    );\n\n    prj.add_source(\n        \"Example.sol\",\n        r#\"\n// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./IExample.sol\";\n\ncontract Example is IExample {\n    /// @inheritdoc IExample\n    function process(address addr) external {\n        // Implementation for single address\n    }\n\n    /// @inheritdoc IExample\n    function process(address[] calldata addrs) external {\n        // Implementation for multiple addresses\n    }\n\n    /// @inheritdoc IExample\n    function process(address addr, uint256 value) external {\n        // Implementation for address with value\n    }\n}\n\"#,\n    );\n\n    cmd.args([\"doc\", \"--build\"]).assert_success();\n\n    let doc_path = prj.root().join(\"docs/src/src/Example.sol/contract.Example.md\");\n    let content = std::fs::read_to_string(&doc_path).unwrap();\n\n    assert!(content.contains(\"Process a single address\"));\n    assert!(content.contains(\"Process multiple addresses\"));\n    assert!(content.contains(\"Process an address with a value\"));\n});\n\n// Test that hyperlinks use relative paths, not absolute paths\n// fixes <https://github.com/foundry-rs/foundry/issues/12361>\nforgetest_init!(hyperlinks_use_relative_paths, |prj, cmd| {\n    prj.add_source(\n        \"IBase.sol\",\n        r#\"\n// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IBase {\n    function baseFunction() external;\n}\n\"#,\n    );\n\n    prj.add_source(\n        \"Derived.sol\",\n        r#\"\n// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./IBase.sol\";\n\n/// @dev Inherits: {IBase}\ncontract Derived is IBase {\n    function baseFunction() external override {}\n}\n\"#,\n    );\n\n    cmd.args([\"doc\", \"--build\"]).assert_success();\n\n    let doc_path = prj.root().join(\"docs/src/src/Derived.sol/contract.Derived.md\");\n    let content = std::fs::read_to_string(&doc_path).unwrap();\n\n    assert!(\n        content.contains(\"[IBase](/src/IBase.sol/interface.IBase.md\")\n            || content.contains(\"[IBase](\\\\src\\\\IBase.sol\\\\interface.IBase.md\"),\n        \"Hyperlink should use relative path but found: {:?}\",\n        content.lines().find(|line| line.contains(\"[IBase]\")).unwrap_or(\"not found\")\n    );\n});\n\n// Test that constants and immutables are documented under \"Constants\" section when only constants\n// are present fixes <https://github.com/foundry-rs/foundry/issues/4611>\nforgetest_init!(constants_and_immutables_are_documented_under_constants_section, |prj, cmd| {\n    prj.add_source(\n        \"CounterConstants.sol\",\n        r#\"\n// SPDX-License-Identifier: UNLICENSED\npragma solidity >=0.8.19;\n\ncontract CounterConstants {\n    uint256 public constant FOO = 1;\n    uint256 public immutable BAR;\n\n    constructor() {\n        BAR = 2;\n    }\n}\n\"#,\n    );\n\n    cmd.args([\"doc\", \"--build\"]).assert_success();\n\n    let doc_path =\n        prj.root().join(\"docs/src/src/CounterConstants.sol/contract.CounterConstants.md\");\n    let content = std::fs::read_to_string(&doc_path).unwrap();\n\n    // Check that Constants section exists\n    assert!(content.contains(\"## Constants\"), \"Should have Constants section\");\n    // Check that State Variables section does not exist\n    assert!(!content.contains(\"## State Variables\"), \"Should not have State Variables section\");\n\n    // Get the position of the Constants section and of the Functions section\n    let constants_section_pos = content.find(\"## Constants\").unwrap();\n    let functions_section_pos = content.find(\"## Functions\").unwrap();\n\n    // Check that Constants section contains the constant\n    assert!(content.contains(\"### FOO\"), \"Should have FOO constant\");\n    let foo_constant_pos = content.find(\"## FOO\").unwrap();\n    assert!(\n        foo_constant_pos > constants_section_pos && foo_constant_pos < functions_section_pos,\n        \"FOO constant should be after Constants section and before Functions section\"\n    );\n\n    // Check that Constants section contains the immutable\n    let bar_immutable_pos = content.find(\"## BAR\").unwrap();\n    assert!(content.contains(\"### BAR\"), \"Should have BAR immutable\");\n    assert!(\n        bar_immutable_pos > constants_section_pos && bar_immutable_pos < functions_section_pos,\n        \"BAR immutable should be after Constants section and before Functions section\"\n    );\n});\n\n// Test that state variables are documented under \"State Variables\" section when only state\n// variables are present fixes <https://github.com/foundry-rs/foundry/issues/4611>\nforgetest_init!(state_variables_are_documented_under_state_variables_section, |prj, cmd| {\n    prj.add_source(\n        \"CounterStateVariables.sol\",\n        r#\"\n// SPDX-License-Identifier: UNLICENSED\npragma solidity >=0.8.19;\n\ncontract CounterStateVariables {\n    uint256 public baz;\n\n    function increment() public {\n        baz++;\n    }\n}\n\"#,\n    );\n\n    cmd.args([\"doc\", \"--build\"]).assert_success();\n\n    let doc_path =\n        prj.root().join(\"docs/src/src/CounterStateVariables.sol/contract.CounterStateVariables.md\");\n    let content = std::fs::read_to_string(&doc_path).unwrap();\n\n    // Check that Constants section does not exist\n    assert!(!content.contains(\"## Constants\"), \"Should not have Constants section\");\n    // Check that State Variables section exists\n    assert!(content.contains(\"## State Variables\"), \"Should have State Variables section\");\n\n    // Get the position of the State Variables section and of the Functions section\n    let state_variables_section_pos = content.find(\"## State Variables\").unwrap();\n    let functions_section_pos = content.find(\"## Functions\").unwrap();\n\n    // Check that State Variables section contains the state variable\n    assert!(content.contains(\"### baz\"), \"Should have baz state variable\");\n    let baz_state_variable_pos = content.find(\"## baz\").unwrap();\n    assert!(\n        baz_state_variable_pos > state_variables_section_pos\n            && baz_state_variable_pos < functions_section_pos,\n        \"baz state variable should be after State Variables section and before Functions section\"\n    );\n});\n\n// Test that constants/immutables and state-variables are documented under separate sections when\n// both are present fixes <https://github.com/foundry-rs/foundry/issues/4611>\nforgetest_init!(\n    constants_and_immutables_and_state_variables_are_documented_under_separate_sections,\n    |prj, cmd| {\n        prj.add_source(\n            \"CounterMixedVariables.sol\",\n            r#\"\n// SPDX-License-Identifier: UNLICENSED\npragma solidity >=0.8.19;\n\ncontract CounterMixedVariables {\n    uint256 public constant FOO = 1;\n    uint256 public immutable BAR;\n    uint256 public baz;\n\n    constructor() {\n        BAR = 2;\n    }\n\n    function increment() public {\n        baz++;\n    }\n}\n\"#,\n        );\n\n        cmd.args([\"doc\", \"--build\"]).assert_success();\n\n        let doc_path = prj\n            .root()\n            .join(\"docs/src/src/CounterMixedVariables.sol/contract.CounterMixedVariables.md\");\n        let content = std::fs::read_to_string(&doc_path).unwrap();\n\n        // Check that Constants section and the State Variables section exist\n        assert!(content.contains(\"## Constants\"), \"Should have Constants section\");\n        assert!(content.contains(\"## State Variables\"), \"Should have State Variables section\");\n\n        // Get the position of the Constants, State Variables, and Functions sections\n        let constants_section_pos = content.find(\"## Constants\").unwrap();\n        let state_variables_section_pos = content.find(\"## State Variables\").unwrap();\n        let functions_section_pos = content.find(\"## Functions\").unwrap();\n\n        // Validate that the sections are in the correct order\n        assert!(\n            constants_section_pos < state_variables_section_pos\n                && state_variables_section_pos < functions_section_pos,\n            \"Constants section should be before State Variables section and before Functions section\"\n        );\n\n        // Check that Constants section contains the constant\n        assert!(content.contains(\"### FOO\"), \"Should have FOO constant\");\n        let foo_constant_pos = content.find(\"## FOO\").unwrap();\n        assert!(\n            foo_constant_pos > constants_section_pos\n                && foo_constant_pos < state_variables_section_pos,\n            \"FOO constant should be after Constants section and before State Variables section\"\n        );\n\n        // Check that Constants section contains the immutable\n        assert!(content.contains(\"### BAR\"), \"Should have BAR immutable\");\n        let bar_immutable_pos = content.find(\"## BAR\").unwrap();\n        assert!(\n            bar_immutable_pos > constants_section_pos\n                && bar_immutable_pos < state_variables_section_pos,\n            \"BAR immutable should be after Constants section and before State Variables section\"\n        );\n\n        // Check that State Variables section contains the state variable\n        assert!(content.contains(\"### baz\"), \"Should have baz state variable\");\n        let baz_state_variable_pos = content.find(\"## baz\").unwrap();\n        assert!(\n            baz_state_variable_pos > state_variables_section_pos\n                && baz_state_variable_pos < functions_section_pos,\n            \"baz state variable should be after State Variables section and before Functions section\"\n        );\n    }\n);\n"
  },
  {
    "path": "crates/forge/tests/cli/eip712.rs",
    "content": "use foundry_config::fs_permissions::PathPermission;\n\nforgetest!(test_eip712, |prj, cmd| {\n    let path = prj.add_test(\n        \"Structs.sol\",\n        r#\"\nlibrary Structs {\n    struct Foo {\n        Bar bar;\n    }\n\n    struct Bar {\n        Art art;\n    }\n\n    struct Art {\n        uint256 id;\n    }\n\n    struct Complex {\n        Structs2.Foo foo2;\n        Foo[] foos;\n        Rec[][] recs;\n    }\n\n    struct Rec {\n        Rec[] rec;\n    }\n}\n\nlibrary Structs2 {\n    struct Foo {\n        uint256 id;\n    }\n\n    struct Rec {\n        Bar[] bar;\n    }\n\n    struct Bar {\n        Rec rec;\n    }\n\n    struct FooBar {\n        Foo[] foos;\n        Bar[] bars;\n        Structs.Foo foo;\n        Structs.Bar bar;\n        Rec[] recs;\n        Structs.Rec rec;\n    }\n}\n\ncontract DummyTest {\n    function testDummy() public pure {\n        revert(\"test\");\n    }\n}\n\"#,\n    );\n\n    cmd.forge_fuse().args([\"eip712\", path.to_string_lossy().as_ref()]).assert_success().stdout_eq(\n        str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\nStructs.sol > Structs > Foo:\n - type: Foo(Bar bar)Art(uint256 id)Bar(Art art)\n - hash: 0x6d9b732373bd999fde4072274c752e03f7437067dd75521eb406d8edf1d30f7d\n\nStructs.sol > Structs > Bar:\n - type: Bar(Art art)Art(uint256 id)\n - hash: 0xadeb03f4f98fb57c05c9a79d8dd2348220e9bd9fd332ec2fbd92479e5695a596\n\nStructs.sol > Structs > Art:\n - type: Art(uint256 id)\n - hash: 0xbfeb9da97f9dbc2403e9d5ec3853f36414cae141d772601f24e0097d159d302b\n\nStructs.sol > Structs > Complex:\n - type: Complex(Foo foo2,Foo_1[] foos,Rec[][] recs)Art(uint256 id)Bar(Art art)Foo(uint256 id)Foo_1(Bar bar)Rec(Rec[] rec)\n - hash: 0xfb0a234a82efcade7c031ebb4c58afd7f5f242ca67ed06f4050c60044dcee425\n\nStructs.sol > Structs > Rec:\n - type: Rec(Rec[] rec)\n - hash: 0x5f060eb740f5aee93a910587a100458c724479d189f6dd67ac39048bf312102e\n\nStructs.sol > Structs2 > Foo:\n - type: Foo(uint256 id)\n - hash: 0xb93d8bb2877cd5cc51979d9fe85339ab570714a6fd974225e2a763851092497e\n\nStructs.sol > Structs2 > Rec:\n - type: Rec(Bar[] bar)Bar(Rec rec)\n - hash: 0xe9dded72c72648f27772620cb4e10b773ce31a3ea26ef980c0b39d1834242cda\n\nStructs.sol > Structs2 > Bar:\n - type: Bar(Rec rec)Rec(Bar[] bar)\n - hash: 0x164eba932ecde04ec75feba228664d08f29c88d6a67e531757e023e6063c3b2c\n\nStructs.sol > Structs2 > FooBar:\n - type: FooBar(Foo[] foos,Bar[] bars,Foo_1 foo,Bar_1 bar,Rec[] recs,Rec_1 rec)Art(uint256 id)Bar(Rec rec)Bar_1(Art art)Foo(uint256 id)Foo_1(Bar_1 bar)Rec(Bar[] bar)Rec_1(Rec_1[] rec)\n - hash: 0xce88f333fe5b5d4901ceb2569922ffe741cda3afc383a63d34ed2c3d565e42d8\n\n\n\"#]],\n    );\n\n    cmd.forge_fuse().args([\"eip712\", path.to_string_lossy().as_ref(), \"--json\"]).assert_success().stdout_eq(\n        str![[r#\"\n[\n  {\n    \"path\": \"Structs.sol > Structs > Foo\",\n    \"type\": \"Foo(Bar bar)Art(uint256 id)Bar(Art art)\",\n    \"hash\": \"0x6d9b732373bd999fde4072274c752e03f7437067dd75521eb406d8edf1d30f7d\"\n  },\n  {\n    \"path\": \"Structs.sol > Structs > Bar\",\n    \"type\": \"Bar(Art art)Art(uint256 id)\",\n    \"hash\": \"0xadeb03f4f98fb57c05c9a79d8dd2348220e9bd9fd332ec2fbd92479e5695a596\"\n  },\n  {\n    \"path\": \"Structs.sol > Structs > Art\",\n    \"type\": \"Art(uint256 id)\",\n    \"hash\": \"0xbfeb9da97f9dbc2403e9d5ec3853f36414cae141d772601f24e0097d159d302b\"\n  },\n  {\n    \"path\": \"Structs.sol > Structs > Complex\",\n    \"type\": \"Complex(Foo foo2,Foo_1[] foos,Rec[][] recs)Art(uint256 id)Bar(Art art)Foo(uint256 id)Foo_1(Bar bar)Rec(Rec[] rec)\",\n    \"hash\": \"0xfb0a234a82efcade7c031ebb4c58afd7f5f242ca67ed06f4050c60044dcee425\"\n  },\n  {\n    \"path\": \"Structs.sol > Structs > Rec\",\n    \"type\": \"Rec(Rec[] rec)\",\n    \"hash\": \"0x5f060eb740f5aee93a910587a100458c724479d189f6dd67ac39048bf312102e\"\n  },\n  {\n    \"path\": \"Structs.sol > Structs2 > Foo\",\n    \"type\": \"Foo(uint256 id)\",\n    \"hash\": \"0xb93d8bb2877cd5cc51979d9fe85339ab570714a6fd974225e2a763851092497e\"\n  },\n  {\n    \"path\": \"Structs.sol > Structs2 > Rec\",\n    \"type\": \"Rec(Bar[] bar)Bar(Rec rec)\",\n    \"hash\": \"0xe9dded72c72648f27772620cb4e10b773ce31a3ea26ef980c0b39d1834242cda\"\n  },\n  {\n    \"path\": \"Structs.sol > Structs2 > Bar\",\n    \"type\": \"Bar(Rec rec)Rec(Bar[] bar)\",\n    \"hash\": \"0x164eba932ecde04ec75feba228664d08f29c88d6a67e531757e023e6063c3b2c\"\n  },\n  {\n    \"path\": \"Structs.sol > Structs2 > FooBar\",\n    \"type\": \"FooBar(Foo[] foos,Bar[] bars,Foo_1 foo,Bar_1 bar,Rec[] recs,Rec_1 rec)Art(uint256 id)Bar(Rec rec)Bar_1(Art art)Foo(uint256 id)Foo_1(Bar_1 bar)Rec(Bar[] bar)Rec_1(Rec_1[] rec)\",\n    \"hash\": \"0xce88f333fe5b5d4901ceb2569922ffe741cda3afc383a63d34ed2c3d565e42d8\"\n  }\n]\n\n\"#]],\n    );\n\n    // Testing `solar_project` doesn't mess up cache.\n    cmd.forge_fuse().arg(\"test\").assert_failure().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\nRan 1 test for test/Structs.sol:DummyTest\n[FAIL: test] testDummy() ([GAS])\nSuite result: FAILED. 0 passed; 1 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 0 tests passed, 1 failed, 0 skipped (1 total tests)\n\nFailing tests:\nEncountered 1 failing test in test/Structs.sol:DummyTest\n[FAIL: test] testDummy() ([GAS])\n\nEncountered a total of 1 failing tests, 0 tests succeeded\n\nTip: Run `forge test --rerun` to retry only the 1 failed test\n\n\"#]]);\n});\n\nforgetest!(test_eip712_free_standing_structs, |prj, cmd| {\n    let path = prj.add_source(\n        \"FreeStandingStructs.sol\",\n        r#\"\n// free-standing struct (outside a contract and lib)\nstruct FreeStanding {\n    uint256 id;\n    string name;\n}\n\ncontract InsideContract {\n    struct ContractStruct {\n        uint256 value;\n    }\n}\n\nlibrary InsideLibrary {\n    struct LibraryStruct {\n        bytes32 hash;\n    }\n}\n\"#,\n    );\n\n    cmd.forge_fuse().args([\"eip712\", path.to_string_lossy().as_ref()]).assert_success().stdout_eq(\n        str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\nFreeStanding:\n - type: FreeStanding(uint256 id,string name)\n - hash: 0xfb3c934b2382873277133498bde6eb3914ab323e3bef8b373ebcd423969bf1a2\n\nFreeStandingStructs.sol > InsideContract > ContractStruct:\n - type: ContractStruct(uint256 value)\n - hash: 0xfb63263e7cf823ff50385a991cb1bd5c1ff46b58011119984d52f8736331e3fe\n\nFreeStandingStructs.sol > InsideLibrary > LibraryStruct:\n - type: LibraryStruct(bytes32 hash)\n - hash: 0x81d6d25f4d37549244d76a68f23ecdcbf3ae81e5a361ed6c492b6a2e126a2843\n\n\n\"#]],\n    );\n});\n\nforgetest!(test_eip712_cheatcode_simple, |prj, cmd| {\n    prj.insert_ds_test();\n    prj.insert_vm();\n    prj.insert_console();\n\n    prj.add_source(\n        \"Eip712\",\n        r#\"\ncontract Eip712Structs {\n    struct EIP712Domain {\n        string name;\n        string version;\n        uint256 chainId;\n        address verifyingContract;\n    }\n}\n    \"#,\n    );\n\n    prj.add_source(\"Eip712Cheat.sol\", r#\"\nimport \"./test.sol\";\nimport \"./Vm.sol\";\nimport \"./console.sol\";\n\nstring constant CANONICAL = \"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)\";\n\ncontract Eip712Test is DSTest {\n    Vm constant vm = Vm(HEVM_ADDRESS);\n\n    function testEip712HashType() public {\n        bytes32 canonicalHash = keccak256(bytes(CANONICAL));\n        console.logBytes32(canonicalHash);\n\n        // Can figure out the canonical type from a messy string representation of the type,\n        // with an invalid order and extra whitespaces\n        bytes32 fromTypeDef = vm.eip712HashType(\n            \"EIP712Domain(string name, string version, uint256 chainId, address verifyingContract)\"\n        );\n        assertEq(fromTypeDef, canonicalHash);\n\n        // Can figure out the canonical type from the previously generated bindings\n        bytes32 fromTypeName = vm.eip712HashType(\"EIP712Domain\");\n        assertEq(fromTypeName, canonicalHash);\n    }\n}\n\"#,\n    );\n\n    cmd.forge_fuse().args([\"bind-json\"]).assert_success();\n\n    let bindings = prj.root().join(\"utils\").join(\"JsonBindings.sol\");\n    assert!(bindings.exists(), \"'JsonBindings.sol' was not generated at {bindings:?}\");\n\n    prj.update_config(|config| config.fs_permissions.add(PathPermission::read(bindings)));\n    cmd.forge_fuse().args([\"test\", \"--mc\", \"Eip712Test\", \"-vv\"]).assert_success().stdout_eq(str![\n        [r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\n...\nRan 1 test for src/Eip712Cheat.sol:Eip712Test\n[PASS] testEip712HashType() ([GAS])\nLogs:\n  0x8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests)\n\n\"#]\n    ]);\n});\n\nforgetest!(test_eip712_cheatcode_nested, |prj, cmd| {\n    prj.insert_ds_test();\n    prj.insert_vm();\n    prj.insert_console();\n\n    prj.add_source(\n        \"Eip712\",\n        r#\"\ncontract Eip712Structs {\n    struct Transaction {\n        Person from;\n        Person to;\n        Asset tx;\n    }\n    struct Person {\n        address wallet;\n        string name;\n    }\n    struct Asset {\n        address token;\n        uint256 amount;\n    }\n}\n    \"#,\n    );\n\n    prj.add_source(\"Eip712Cheat.sol\", r#\"\nimport \"./test.sol\";\nimport \"./Vm.sol\";\n\nstring constant CANONICAL = \"Transaction(Person from,Person to,Asset tx)Asset(address token,uint256 amount)Person(address wallet,string name)\";\n\ncontract Eip712Test is DSTest {\n    Vm constant vm = Vm(HEVM_ADDRESS);\n\n    function testEip712HashType_byDefinition() public {\n        bytes32 canonicalHash = keccak256(bytes(CANONICAL));\n\n        // Can figure out the canonical type from a messy string representation of the type,\n        // with an invalid order and extra whitespaces\n        bytes32 fromTypeDef = vm.eip712HashType(\n            \"Person(address wallet, string name) Asset(address token, uint256 amount) Transaction(Person from, Person to, Asset tx)\"\n        );\n        assertEq(fromTypeDef, canonicalHash);\n    }\n\n    function testEip712HashType_byTypeName() public {\n        bytes32 canonicalHash = keccak256(bytes(CANONICAL));\n\n        // Can figure out the canonical type from the previously generated bindings\n        bytes32 fromTypeName = vm.eip712HashType(\"Transaction\");\n        assertEq(fromTypeName, canonicalHash);\n    }\n\n    function testReverts_Eip712HashType_invalidName() public {\n        // Reverts if the input type is not found in the bindings\n        vm._expectCheatcodeRevert();\n        bytes32 fromTypeName = vm.eip712HashType(\"InvalidTypeName\");\n    }\n\n    function testEip712HashType_byCustomPathAndTypeName() public {\n        bytes32 canonicalHash = keccak256(bytes(CANONICAL));\n\n        // Can figure out the canonical type from the previously generated bindings\n        bytes32 fromTypeName = vm.eip712HashType(\"utils/CustomJsonBindings.sol\", \"Transaction\");\n        assertEq(fromTypeName, canonicalHash);\n    }\n}\n\"#,\n    );\n\n    // cheatcode by type definition can run without bindings\n    cmd.forge_fuse()\n        .args([\"test\", \"--mc\", \"Eip712Test\", \"--match-test\", \"testEip712HashType_byDefinition\"])\n        .assert_success();\n\n    let bindings = prj.root().join(\"utils\").join(\"JsonBindings.sol\");\n    prj.update_config(|config| config.fs_permissions.add(PathPermission::read(&bindings)));\n\n    // cheatcode by type name fails if bindings haven't been generated\n    cmd.forge_fuse()\n        .args([\"test\", \"--mc\", \"Eip712Test\", \"--match-test\", \"testEip712HashType_byTypeName\"])\n        .assert_failure()\n        .stdout_eq(str![[r#\"\n...\nRan 1 test for src/Eip712Cheat.sol:Eip712Test\n[FAIL: vm.eip712HashType: failed to read from [..] testEip712HashType_byTypeName() ([GAS])\nSuite result: FAILED. 0 passed; 1 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 0 tests passed, 1 failed, 0 skipped (1 total tests)\n\nFailing tests:\nEncountered 1 failing test in src/Eip712Cheat.sol:Eip712Test\n[FAIL: vm.eip712HashType: failed to read from [..] testEip712HashType_byTypeName() ([GAS])\n\nEncountered a total of 1 failing tests, 0 tests succeeded\n\nTip: Run `forge test --rerun` to retry only the 1 failed test\n\n\"#]]);\n\n    cmd.forge_fuse().args([\"bind-json\"]).assert_success();\n    assert!(bindings.exists(), \"'JsonBindings.sol' was not generated at {bindings:?}\");\n\n    // with generated bindings, cheatcode by type name works\n    cmd.forge_fuse()\n        .args([\"test\", \"--mc\", \"Eip712Test\", \"--match-test\", \"testEip712HashType_byTypeName\"])\n        .assert_success();\n\n    // even with generated bindings, cheatcode by type name fails if name is not present\n    cmd.forge_fuse()\n        .args([\n            \"test\",\n            \"--mc\",\n            \"Eip712Test\",\n            \"--match-test\",\n            \"testReverts_Eip712HashType_invalidName\",\n        ])\n        .assert_success();\n\n    let bindings_2 = prj.root().join(\"utils\").join(\"CustomJsonBindings.sol\");\n    prj.update_config(|config| {\n        config.fs_permissions.add(PathPermission::read(&bindings_2));\n    });\n\n    // cheatcode by custom path and type name fails if bindings haven't been generated for that path\n    cmd.forge_fuse()\n        .args([\"test\", \"--mc\", \"Eip712Test\", \"--match-test\", \"testEip712HashType_byCustomPathAndTypeName\"])\n        .assert_failure()\n        .stdout_eq(str![[r#\"\n...\nRan 1 test for src/Eip712Cheat.sol:Eip712Test\n[FAIL: vm.eip712HashType: failed to read from [..] testEip712HashType_byCustomPathAndTypeName() ([GAS])\nSuite result: FAILED. 0 passed; 1 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 0 tests passed, 1 failed, 0 skipped (1 total tests)\n\nFailing tests:\nEncountered 1 failing test in src/Eip712Cheat.sol:Eip712Test\n[FAIL: vm.eip712HashType: failed to read from [..] testEip712HashType_byCustomPathAndTypeName() ([GAS])\n\nEncountered a total of 1 failing tests, 0 tests succeeded\n\nTip: Run `forge test --rerun` to retry only the 1 failed test\n\n\"#]]);\n\n    cmd.forge_fuse().args([\"bind-json\", \"utils/CustomJsonBindings.sol\"]).assert_success();\n    assert!(bindings_2.exists(), \"'CustomJsonBindings.sol' was not generated at {bindings_2:?}\");\n\n    // with generated bindings, cheatcode by custom path and type name works\n    cmd.forge_fuse()\n        .args([\n            \"test\",\n            \"--mc\",\n            \"Eip712Test\",\n            \"--match-test\",\n            \"testEip712HashType_byCustomPathAndTypeName\",\n        ])\n        .assert_success();\n});\n\nforgetest!(test_eip712_hash_struct_simple, |prj, cmd| {\n    prj.insert_ds_test();\n    prj.insert_vm();\n    prj.insert_console();\n\n    prj.add_source(\n        \"Eip712HashStructDomainTest.sol\",\n        r#\"\nimport \"./Vm.sol\";\nimport \"./test.sol\";\nimport \"./console.sol\";\n\nstruct EIP712Domain {\n    string name;\n    string version;\n    uint256 chainId;\n    address verifyingContract;\n}\n\nstring constant _EIP712_DOMAIN_TYPE_DEF = \"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)\";\nbytes32 constant _EIP712_DOMAIN_TYPE_HASH = keccak256(bytes(_EIP712_DOMAIN_TYPE_DEF));\n\ncontract Eip712HashStructDomainTest is DSTest {\n    Vm constant vm = Vm(address(uint160(uint256(keccak256(\"hevm cheat code\")))));\n\n    function testHashEIP712Domain() public {\n        EIP712Domain memory domain = EIP712Domain({\n            name: \"Foo\",\n            version: \"Bar\",\n            chainId: 1,\n            verifyingContract: 0xdEADBEeF00000000000000000000000000000000\n        });\n\n        // simulate user-computed domain hash\n        bytes memory encodedData = abi.encode(\n            keccak256(bytes(domain.name)),\n            keccak256(bytes(domain.version)),\n            bytes32(domain.chainId),\n            bytes32(uint256(uint160(domain.verifyingContract)))\n        );\n        bytes32 userStructHash = keccak256(abi.encodePacked(_EIP712_DOMAIN_TYPE_HASH, encodedData));\n\n        // cheatcode-computed domain hash\n        bytes32 cheatStructHash = vm.eip712HashStruct(_EIP712_DOMAIN_TYPE_DEF, abi.encode(domain));\n        console.log(\"EIP712Domain struct hash from cheatcode:\");\n        console.logBytes32(cheatStructHash);\n\n        assertEq(cheatStructHash, userStructHash, \"EIP712Domain struct hash mismatch\");\n    }\n}\n\"#,\n        );\n\n    cmd.forge_fuse().args([\"test\", \"--mc\", \"Eip712HashStructDomainTest\", \"-vvvv\"]).assert_success();\n});\n\nforgetest!(test_eip712_hash_struct_complex, |prj, cmd| {\n    prj.insert_ds_test();\n    prj.insert_vm();\n    prj.insert_console();\n\n    prj.add_source(\n        \"Eip712Permit.sol\",\n        r#\"\nstruct PermitDetails {\n    address token;\n    uint160 amount;\n    uint48 expiration;\n    uint48 nonce;\n}\n\nbytes32 constant _PERMIT_DETAILS_TYPEHASH = keccak256(\n    \"PermitDetails(address token,uint160 amount,uint48 expiration,uint48 nonce)\"\n);\n\nstruct PermitSingle {\n    PermitDetails details;\n    address spender;\n    uint256 sigDeadline;\n}\n\nbytes32 constant _PERMIT_SINGLE_TYPEHASH = keccak256(\n    \"PermitSingle(PermitDetails details,address spender,uint256 sigDeadline)PermitDetails(address token,uint160 amount,uint48 expiration,uint48 nonce)\"\n);\n\n// borrowed from https://github.com/Uniswap/permit2/blob/main/src/libraries/PermitHash.sol\nlibrary PermitHash {\n    function hash(PermitSingle memory permitSingle) internal pure returns (bytes32) {\n        bytes32 permitHash = _hashDetails(permitSingle.details);\n        return\n            keccak256(abi.encode(_PERMIT_SINGLE_TYPEHASH, permitHash, permitSingle.spender, permitSingle.sigDeadline));\n    }\n\n    function _hashDetails(PermitDetails memory details) internal pure returns (bytes32) {\n        return keccak256(abi.encode(_PERMIT_DETAILS_TYPEHASH, details));\n    }\n}\n\"#,\n    );\n\n    prj.add_source(\n        \"Eip712Transaction.sol\",\n        r#\"\nstruct Asset {\n    address token;\n    uint256 amount;\n}\n\nbytes32 constant _ASSET_TYPEHASH = keccak256(\n    \"Asset(address token,uint256 amount)\"\n);\n\nstruct Person {\n    address wallet;\n    string name;\n}\n\nbytes32 constant _PERSON_TYPEHASH = keccak256(\n    \"Person(address wallet,string name)\"\n);\n\nstruct Transaction {\n    Person from;\n    Person to;\n    Asset tx;\n}\n\nbytes32 constant _TRANSACTION_TYPEHASH = keccak256(\n    \"Transaction(Person from,Person to,Asset tx)Asset(address token,uint256 amount)Person(address wallet,string name)\"\n);\n\n\nlibrary TransactionHash {\n    function hash(Transaction memory t) internal pure returns (bytes32) {\n        bytes32 fromHash = _hashPerson(t.from);\n        bytes32 toHash = _hashPerson(t.to);\n        bytes32 assetHash = _hashAsset(t.tx);\n        return\n            keccak256(abi.encode(_TRANSACTION_TYPEHASH, fromHash, toHash, assetHash));\n    }\n\n    function _hashPerson(Person memory person) internal pure returns (bytes32) {\n        return keccak256(\n            abi.encode(_PERSON_TYPEHASH, person.wallet, keccak256(bytes(person.name)))\n        );\n\n    }\n\n    function _hashAsset(Asset memory asset) internal pure returns (bytes32) {\n        return keccak256(abi.encode(_ASSET_TYPEHASH, asset));\n    }\n}\n    \"#,\n    );\n\n    let bindings = prj.root().join(\"utils\").join(\"JsonBindings.sol\");\n    prj.update_config(|config| config.fs_permissions.add(PathPermission::read(&bindings)));\n    cmd.forge_fuse().args([\"bind-json\"]).assert_success();\n\n    prj.add_source(\n        \"Eip712HashStructTest.sol\",\n        r#\"\nimport \"./Vm.sol\";\nimport \"./test.sol\";\nimport \"./console.sol\";\nimport \"./Eip712Permit.sol\";\nimport \"./Eip712Transaction.sol\";\n\ncontract Eip712HashStructTest is DSTest {\n    Vm constant vm = Vm(HEVM_ADDRESS);\n\n    function testHashPermitSingle_withTypeName() public {\n        PermitDetails memory details = PermitDetails({\n            token: 0x1111111111111111111111111111111111111111,\n            amount: 1000 ether,\n            expiration: 12345,\n            nonce: 1\n        });\n\n        // user-computed permit (using uniswap hash library)\n        bytes32 userStructHash = PermitHash._hashDetails(details);\n\n        // cheatcode-computed permit\n        bytes32 cheatStructHash = vm.eip712HashStruct(\"PermitDetails\", abi.encode(details));\n\n        assertEq(cheatStructHash, userStructHash, \"details struct hash mismatch\");\n\n        PermitSingle memory permit = PermitSingle({\n            details: details,\n            spender: 0x2222222222222222222222222222222222222222,\n            sigDeadline: 12345\n        });\n\n        // user-computed permit (using uniswap hash library)\n        userStructHash = PermitHash.hash(permit);\n\n        // cheatcode-computed permit\n        cheatStructHash = vm.eip712HashStruct(\"PermitSingle\", abi.encode(permit));\n        console.log(\"PermitSingle struct hash from cheatcode:\");\n        console.logBytes32(cheatStructHash);\n\n        assertEq(cheatStructHash, userStructHash, \"permit struct hash mismatch\");\n    }\n\n    function testHashPermitSingle_withTypeDefinition() public {\n        PermitDetails memory details = PermitDetails({\n            token: 0x1111111111111111111111111111111111111111,\n            amount: 1000 ether,\n            expiration: 12345,\n            nonce: 1\n        });\n\n        // user-computed permit (using uniswap hash library)\n        bytes32 userStructHash = PermitHash._hashDetails(details);\n\n        // cheatcode-computed permit\n        bytes32 cheatStructHash = vm.eip712HashStruct(\"PermitDetails(address token, uint160 amount, uint48 expiration, uint48 nonce)\", abi.encode(details));\n\n        assertEq(cheatStructHash, userStructHash, \"details struct hash mismatch\");\n\n        PermitSingle memory permit = PermitSingle({\n            details: details,\n            spender: 0x2222222222222222222222222222222222222222,\n            sigDeadline: 12345\n        });\n\n        // user-computed permit (using uniswap hash library)\n        userStructHash = PermitHash.hash(permit);\n\n        // cheatcode-computed permit (previously encoding)\n        cheatStructHash = vm.eip712HashStruct(\"PermitDetails(address token, uint160 amount, uint48 expiration, uint48 nonce) PermitSingle(PermitDetails details,address spender,uint256 sigDeadline)\", abi.encode(permit));\n        console.log(\"PermitSingle struct hash from cheatcode:\");\n        console.logBytes32(cheatStructHash);\n\n        assertEq(cheatStructHash, userStructHash, \"permit struct hash mismatch\");\n    }\n\n    function testHashTransaction_withTypeName() public {\n        Asset memory asset = Asset ({ token: 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2, amount: 100 ether });\n\n        bytes32 user = TransactionHash._hashAsset(asset);\n        bytes32 cheat = vm.eip712HashStruct(\"Asset\", abi.encode(asset));\n        assertEq(user, cheat, \"asset struct hash mismatch\");\n\n        Person memory from = Person ({ wallet: 0x0000000000000000000000000000000000000001, name: \"alice\" });\n        Person memory to = Person ({ wallet: 0x0000000000000000000000000000000000000002, name: \"bob\" });\n\n        user = TransactionHash._hashPerson(from);\n        cheat = vm.eip712HashStruct(\"Person\", abi.encode(from));\n        assertEq(user, cheat, \"person struct hash mismatch\");\n\n        Transaction memory t = Transaction ({ from: from, to: to, tx: asset });\n\n        user = TransactionHash.hash(t);\n        cheat = vm.eip712HashStruct(\"Transaction\", abi.encode(t));\n        assertEq(user, cheat, \"transaction struct hash mismatch\");\n    }\n\n    function testHashTransaction_withTypeDefinition() public {\n        Asset memory asset = Asset ({ token: 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2, amount: 100 ether });\n\n        bytes32 user = TransactionHash._hashAsset(asset);\n        bytes32 cheat = vm.eip712HashStruct(\"Asset(address token, uint256 amount)\", abi.encode(asset));\n        assertEq(user, cheat, \"asset struct hash mismatch\");\n\n        Person memory from = Person ({ wallet: 0x0000000000000000000000000000000000000001, name: \"alice\" });\n        Person memory to = Person ({ wallet: 0x0000000000000000000000000000000000000002, name: \"bob\" });\n\n        user = TransactionHash._hashPerson(from);\n        cheat = vm.eip712HashStruct(\"Person(address wallet, string name)\", abi.encode(from));\n        assertEq(user, cheat, \"person struct hash mismatch\");\n\n        Transaction memory t = Transaction ({ from: from, to: to, tx: asset });\n\n        user = TransactionHash.hash(t);\n        cheat = vm.eip712HashStruct(\"Person(address wallet, string name) Asset(address token, uint256 amount) Transaction(Person from, Person to, Asset tx)\", abi.encode(t));\n        assertEq(user, cheat, \"transaction struct hash mismatch\");\n    }\n}\n\"#,\n    );\n\n    cmd.forge_fuse()\n        .args([\"test\", \"--mc\", \"Eip712HashStructTest\", \"-vv\"])\n        .assert_success()\n        .stdout_eq(str![[r#\"\n...\n[PASS] testHashPermitSingle_withTypeDefinition() ([GAS])\nLogs:\n  PermitSingle struct hash from cheatcode:\n  0x3ed744fdcea02b6b9ad45a9db6e648bf6f18c221909f9ee425191f2a02f9e4a8\n\n[PASS] testHashPermitSingle_withTypeName() ([GAS])\nLogs:\n  PermitSingle struct hash from cheatcode:\n  0x3ed744fdcea02b6b9ad45a9db6e648bf6f18c221909f9ee425191f2a02f9e4a8\n...\n\"#]]);\n});\n\nforgetest!(test_eip712_hash_typed_data, |prj, cmd| {\n    prj.insert_ds_test();\n    prj.insert_vm();\n    prj.insert_console();\n\n    prj.add_source(\n        \"Eip712HashTypedData.sol\",\n        r#\"\nimport \"./Vm.sol\";\nimport \"./test.sol\";\nimport \"./console.sol\";\ncontract Eip712HashTypedDataTest is DSTest {\n    Vm constant vm = Vm(address(uint160(uint256(keccak256(\"hevm cheat code\")))));\n\n    function testHashEIP712Message() public {\n        string memory jsonData =\n            '{\"types\":{\"EIP712Domain\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"version\",\"type\":\"string\"},{\"name\":\"chainId\",\"type\":\"uint256\"},{\"name\":\"verifyingContract\",\"type\":\"address\"},{\"name\":\"salt\",\"type\":\"bytes32\"}]},\"primaryType\":\"EIP712Domain\",\"domain\":{\"name\":\"example.metamask.io\",\"version\":\"1\",\"chainId\":1,\"verifyingContract\":\"0x0000000000000000000000000000000000000000\"},\"message\":{}}';\n\n        // since this cheatcode simply exposes an alloy fn, the test has been borrowed from:\n        // <https://github.com/alloy-rs/core/blob/e0727c2224a5a83664d4ca1fb2275090d29def8b/crates/dyn-abi/src/eip712/typed_data.rs#L256>\n        bytes32 expectedHash = hex\"122d1c8ef94b76dad44dcb03fa772361e20855c63311a15d5afe02d1b38f6077\";\n        assertEq(vm.eip712HashTypedData(jsonData), expectedHash, \"EIP712Domain struct hash mismatch\");\n    }\n}\n\"#,\n    );\n\n    cmd.forge_fuse().args([\"test\", \"--mc\", \"Eip712HashTypedDataTest\"]).assert_success();\n});\n\n// repro: <https://github.com/foundry-rs/foundry/issues/11366>\nforgetest!(test_eip712_hash_typed_data_repro, |prj, cmd| {\n    prj.insert_ds_test();\n    prj.insert_vm();\n    prj.insert_console();\n\n    prj.add_source(\n        \"Eip712HashTypedData.sol\",\n        r#\"\nimport \"./Vm.sol\";\nimport \"./test.sol\";\nimport \"./console.sol\";\ncontract CounterStrike {\n    bytes32 public constant ATTACK_TYPEHASH = keccak256(\"Attack(address player,uint128 x,uint128 y,uint40 shootTime)\");\n    bytes32 public constant DOMAIN_TYPEHASH =\n        keccak256(\"EIP712Domain(string name,uint256 chainId,address verifyingContract)\");\n    string public constant PROTOCOL_NAME = \"CounterStrike\";\n}\n\ncontract CounterStrike_Test is DSTest {\n    Vm constant vm = Vm(address(uint160(uint256(keccak256(\"hevm cheat code\")))));\n\n    struct EIP712Domain {\n        string name;\n        uint256 chainId;\n        address verifyingContract;\n    }\n\n    struct Attack {\n        address player;\n        uint128 x;\n        uint128 y;\n        uint40 shootTime;\n    }\n\n    string constant SCHEMA_EIP712_DOMAIN = \"EIP712Domain(string name,uint256 chainId,address verifyingContract)\";\n    string constant SCHEMA_ATTACK = \"Attack(address player,uint128 x,uint128 y,uint40 shootTime)\";\n\n    CounterStrike public counterStrike;\n    address public player;\n    uint256 public playerPrivateKey;\n    uint128 public x = 10_000e18;\n    uint128 public y = 20_000e18;\n    uint40 public shootTime = 12_345_678;\n\n    function setUp() public {\n        counterStrike = new CounterStrike();\n    }\n\n    function test_Attack() public view {\n        string memory domainJson = vm.serializeJsonType(\n            SCHEMA_EIP712_DOMAIN,\n            abi.encode(\n                EIP712Domain({\n                    name: counterStrike.PROTOCOL_NAME(),\n                    chainId: block.chainid,\n                    verifyingContract: address(counterStrike)\n                })\n            )\n        );\n        string memory messageJson = vm.serializeJsonType(\n            SCHEMA_ATTACK, abi.encode(Attack({ player: player, x: x, y: y, shootTime: shootTime }))\n        );\n\n        string memory typesJson = string.concat(\n            '{\"EIP712Domain\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"chainId\",\"type\":\"uint256\"},{\"name\":\"verifyingContract\",\"type\":\"address\"}],\"Attack\":[{\"name\":\"player\",\"type\":\"address\"},{\"name\":\"x\",\"type\":\"uint128\"},{\"name\":\"y\",\"type\":\"uint128\"},{\"name\":\"shootTime\",\"type\":\"uint40\"}]}'\n        );\n        string memory primaryType = '\"Attack\"';\n        string memory typedDataJson = string.concat(\n            '{\"types\":',\n            typesJson,\n            ',\"primaryType\":',\n            primaryType,\n            ',\"domain\":',\n            domainJson,\n            ',\"message\":',\n            messageJson,\n            \"}\"\n        );\n\n        bytes32 digest = vm.eip712HashTypedData(typedDataJson);\n        console.logBytes32(digest);\n    }\n}\n\"#,\n    );\n\n    cmd.forge_fuse().args([\"test\", \"-vvv\"]).assert_success();\n});\n"
  },
  {
    "path": "crates/forge/tests/cli/ext_integration.rs",
    "content": "use foundry_test_utils::util::ExtTester;\n\n// Actively maintained tests\n// Last updated: June 19th 2025\n\n// <https://github.com/foundry-rs/forge-std>\n#[test]\nfn forge_std() {\n    ExtTester::new(\"foundry-rs\", \"forge-std\", \"b69e66b0ff79924d487d49bf7fb47c9ec326acba\")\n        // Skip fork tests.\n        .args([\"--nmc\", \"Fork\"])\n        .verbosity(2)\n        .run();\n}\n\n// <https://github.com/PaulRBerg/prb-math>\n#[test]\n#[cfg_attr(windows, ignore = \"Windows cannot find installed programs\")]\nfn prb_math() {\n    ExtTester::new(\"PaulRBerg\", \"prb-math\", \"aad73cfc6cdc2c9b660199b5b1e9db391ea48640\")\n        .install_command(&[\"bun\", \"install\", \"--prefer-offline\"])\n        // Try npm if bun fails / is not installed.\n        .install_command(&[\"npm\", \"install\", \"--prefer-offline\"])\n        .run();\n}\n\n// <https://github.com/PaulRBerg/prb-proxy>\n#[test]\n#[cfg_attr(windows, ignore = \"Windows cannot find installed programs\")]\nfn prb_proxy() {\n    ExtTester::new(\"PaulRBerg\", \"prb-proxy\", \"e45f5325d4b6003227a6c4bdaefac9453f89de2e\")\n        .install_command(&[\"bun\", \"install\", \"--prefer-offline\"])\n        // Try npm if bun fails / is not installed.\n        .install_command(&[\"npm\", \"install\", \"--prefer-offline\"])\n        .run();\n}\n\n// <https://github.com/sablier-labs/v2-core>\n#[test]\n#[cfg_attr(windows, ignore = \"Windows cannot find installed programs\")]\nfn sablier_v2_core() {\n    let mut tester =\n        ExtTester::new(\"sablier-labs\", \"v2-core\", \"d85521f5615f6c19612ff250ee89c57b9afa6aa2\")\n            // Skip fork tests.\n            .args([\"--nmc\", \"Fork\"])\n            // Increase the gas limit: https://github.com/sablier-labs/v2-core/issues/956\n            .args([\"--gas-limit\", &u64::MAX.to_string()])\n            // Run tests without optimizations.\n            .env(\"FOUNDRY_PROFILE\", \"lite\")\n            .install_command(&[\"bun\", \"install\", \"--prefer-offline\"])\n            // Try npm if bun fails / is not installed.\n            .install_command(&[\"npm\", \"install\", \"--prefer-offline\"])\n            .verbosity(2);\n\n    // This test reverts due to memory limit without isolation. This revert is not reached with\n    // isolation because memory is divided between separate EVMs created by inner calls.\n    if cfg!(feature = \"isolate-by-default\") {\n        tester = tester.args([\"--nmt\", \"test_RevertWhen_LoopCalculationOverflowsBlockGasLimit\"]);\n    }\n\n    tester.run();\n}\n\n// <https://github.com/Vectorized/solady>\n#[test]\nfn solady() {\n    let mut tester =\n        ExtTester::new(\"Vectorized\", \"solady\", \"cbcfe0009477aa329574f17e8db0a05703bb8bdd\");\n\n    // This test expects the mover contract created via CREATE2 to be selfdestructed within the\n    // same transaction. In isolation mode, each top-level call runs as a separate transaction\n    // context, so the selfdestruct doesn't clear the code as expected by the test.\n    if cfg!(feature = \"isolate-by-default\") {\n        tester = tester.args([\"--nmt\", \"testSafeMoveETHViaMover\"]);\n    }\n\n    tester.run();\n}\n\n// <https://github.com/pcaversaccio/snekmate>\n#[test]\n#[cfg_attr(windows, ignore = \"Windows cannot find installed programs\")]\n#[cfg(not(feature = \"isolate-by-default\"))]\nfn snekmate() {\n    ExtTester::new(\"pcaversaccio\", \"snekmate\", \"601031d244475b160a00f73053532528bf665cc3\")\n        .install_command(&[\"pnpm\", \"install\", \"--prefer-offline\"])\n        // Try npm if pnpm fails / is not installed.\n        .install_command(&[\"npm\", \"install\", \"--prefer-offline\"])\n        .run();\n}\n\n// <https://github.com/mds1/multicall>\n#[test]\nfn mds1_multicall3() {\n    ExtTester::new(\"mds1\", \"multicall\", \"5f90062160aedb7c807fadca469ac783a0557b57\").run();\n}\n\n// Legacy tests\n\n// <https://github.com/Arachnid/solidity-stringutils>\n#[test]\nfn solidity_stringutils() {\n    ExtTester::new(\"Arachnid\", \"solidity-stringutils\", \"4b2fcc43fa0426e19ce88b1f1ec16f5903a2e461\")\n        .run();\n}\n\n// <https://github.com/m1guelpf/lil-web3>\n#[test]\nfn lil_web3() {\n    ExtTester::new(\"m1guelpf\", \"lil-web3\", \"7346bd28c2586da3b07102d5290175a276949b15\").run();\n}\n\n// <https://github.com/makerdao/multicall>\n#[test]\nfn makerdao_multicall() {\n    ExtTester::new(\"makerdao\", \"multicall\", \"103a8a28e4e372d582d6539b30031bda4cd48e21\").run();\n}\n\n// Legacy forking tests\n\n// <https://github.com/hexonaut/guni-lev>\n#[test]\nfn gunilev() {\n    ExtTester::new(\"hexonaut\", \"guni-lev\", \"15ee8b4c2d28e553c5cd5ba9a2a274af97563bc4\")\n        .fork_block(13633752)\n        .run();\n}\n\n// <https://github.com/mds1/convex-shutdown-simulation>\n#[test]\nfn convex_shutdown_simulation() {\n    ExtTester::new(\n        \"mds1\",\n        \"convex-shutdown-simulation\",\n        \"2537cdebce4396753225c5e616c8e00547d2fcea\",\n    )\n    .fork_block(14445961)\n    .run();\n}\n"
  },
  {
    "path": "crates/forge/tests/cli/failure_assertions.rs",
    "content": "// Tests in which we want to assert failures.\n\nforgetest!(test_fail_deprecation, |prj, cmd| {\n    prj.insert_ds_test();\n\n    prj.add_source(\n        \"DeprecationTestFail.t.sol\",\n        r#\"\n    import \"./test.sol\";\n    contract DeprecationTestFail is DSTest {\n        function testFail_deprecated() public {\n            revert(\"deprecated\");\n        }\n\n        function testFail_deprecated2() public {\n            revert(\"deprecated2\");\n        }\n    }\n    \"#,\n    );\n\n    cmd.forge_fuse()\n        .args([\"test\", \"--mc\", \"DeprecationTestFail\"])\n        .assert_failure()\n        .stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\n...\nFailing tests:\nEncountered 2 failing tests in src/DeprecationTestFail.t.sol:DeprecationTestFail\n[FAIL: `testFail*` has been removed. Consider changing to test_Revert[If|When]_Condition and expecting a revert] testFail_deprecated() ([GAS])\n[FAIL: `testFail*` has been removed. Consider changing to test_Revert[If|When]_Condition and expecting a revert] testFail_deprecated2() ([GAS])\n\nEncountered a total of 2 failing tests, 0 tests succeeded\n\nTip: Run `forge test --rerun` to retry only the 2 failed tests\n\n\"#]]);\n});\n\nforgetest!(expect_revert_tests_should_fail, |prj, cmd| {\n    prj.insert_ds_test();\n    prj.insert_vm();\n    let expect_revert_failure_tests = include_str!(\"../fixtures/ExpectRevertFailures.t.sol\");\n\n    prj.add_source(\"ExpectRevertFailures.sol\", expect_revert_failure_tests);\n\n    cmd.forge_fuse()\n        .args([\"test\", \"--mc\", \"ExpectRevertFailureTest\"])\n        .assert_failure()\n        .stdout_eq(\n            r#\"[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\n...\n[FAIL: next call did not revert as expected] testShouldFailExpectRevertAnyRevertDidNotRevert() ([GAS])\n[FAIL: next call did not revert as expected] testShouldFailExpectRevertDangling() ([GAS])\n[FAIL: next call did not revert as expected] testShouldFailExpectRevertDidNotRevert() ([GAS])\n[FAIL: Error != expected error: but reverts with this message != should revert with this message] testShouldFailExpectRevertErrorDoesNotMatch() ([GAS])\n[FAIL: next call did not revert as expected] testShouldFailRevertNotOnImmediateNextCall() ([GAS])\n[FAIL: some message] testShouldFailexpectCheatcodeRevertForCreate() ([GAS])\n[FAIL: revert] testShouldFailexpectCheatcodeRevertForExtCall() ([GAS])\nSuite result: FAILED. 0 passed; 7 failed; 0 skipped; [ELAPSED]\n...\n\"#,\n        );\n\n    cmd.forge_fuse()\n        .args([\"test\", \"--mc\", \"ExpectRevertWithReverterFailureTest\"])\n        .assert_failure()\n        .stdout_eq(\n            r#\"No files changed, compilation skipped\n...\n[FAIL: next call did not revert as expected] testShouldFailExpectRevertsNotOnImmediateNextCall() ([GAS])\nSuite result: FAILED. 0 passed; 1 failed; 0 skipped; [ELAPSED]\n...\n\"#,\n        );\n\n    cmd.forge_fuse()\n        .args([\"test\", \"--mc\", \"ExpectRevertCountFailureTest\"])\n        .assert_failure()\n        .stdout_eq(\n            r#\"No files changed, compilation skipped\n...\n[FAIL: call reverted with 'my cool error' when it was expected not to revert] testShouldFailIfExpectRevertWrongString() ([GAS])\n[FAIL: call reverted when it was expected not to revert] testShouldFailNoRevert() ([GAS])\n[FAIL: expected 0 reverts with reason: revert, but got one] testShouldFailNoRevertSpecific() ([GAS])\n[FAIL: next call did not revert as expected] testShouldFailRevertCountAny() ([GAS])\n[FAIL: Error != expected error: wrong revert != called a function and then reverted] testShouldFailRevertCountCallsThenReverts() ([GAS])\n[FAIL: Error != expected error: second-revert != revert] testShouldFailRevertCountSpecific() ([GAS])\nSuite result: FAILED. 0 passed; 6 failed; 0 skipped; [ELAPSED]\n...\n\"#,\n        );\n\n    cmd.forge_fuse()\n        .args([\"test\", \"--mc\", \"ExpectRevertCountWithReverterFailures\"])\n        .assert_failure()\n        .stdout_eq(r#\"No files changed, compilation skipped\n...\n[FAIL: call reverted with 'revert' from 0x2e234DAe75C793f67A35089C9d99245E1C58470b, but expected 0 reverts from 0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f] testNoRevertWithWrongReverter() ([GAS])\n[FAIL: call reverted with 'revert2' from 0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f, but expected 0 reverts with reason 'revert' from 0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f] testNoReverterCountWithData() ([GAS])\n[FAIL: expected 0 reverts from address: 0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f, but got one] testShouldFailNoRevertWithReverter() ([GAS])\n[FAIL: Reverter != expected reverter: 0x2e234DAe75C793f67A35089C9d99245E1C58470b != 0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f] testShouldFailRevertCountWithReverter() ([GAS])\n[FAIL: Error != expected error: wrong revert != revert] testShouldFailReverterCountWithWrongData() ([GAS])\n[FAIL: Reverter != expected reverter: 0x2e234DAe75C793f67A35089C9d99245E1C58470b != 0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f] testShouldFailWrongReverterCountWithData() ([GAS])\nSuite result: FAILED. 0 passed; 6 failed; 0 skipped; [ELAPSED]\n...\n\"#);\n});\n\nforgetest!(expect_call_tests_should_fail, |prj, cmd| {\n    prj.insert_ds_test();\n    prj.insert_vm();\n\n    let expect_call_failure_tests = include_str!(\"../fixtures/ExpectCallFailures.t.sol\");\n\n    prj.add_source(\"ExpectCallFailures.sol\", expect_call_failure_tests);\n\n    cmd.forge_fuse().args([\"test\", \"--mc\", \"ExpectCallFailureTest\"]).assert_failure().stdout_eq(\n        r#\"[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\n...\n[FAIL: expected call to 0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f with data 0xc290d6910000000000000000000000000000000000000000000000000000000000000002, value 1 to be called 1 time, but was called 0 times] testShouldFailExpectCallValue() ([GAS])\n[FAIL: expected call to 0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f with data 0x771602f700000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002 to be called 1 time, but was called 0 times] testShouldFailExpectCallWithData() ([GAS])\n[FAIL: expected call to 0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f with data 0x771602f7000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000003 to be called 1 time, but was called 0 times] testShouldFailExpectCallWithMoreParameters() ([GAS])\n[FAIL: expected call to 0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f with data 0x771602f700000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001, value 0, gas 25000 to be called 1 time, but was called 0 times] testShouldFailExpectCallWithNoValueAndWrongGas() ([GAS])\n[FAIL: expected call to 0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f with data 0x771602f700000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001, value 0, minimum gas 50001 to be called 1 time, but was called 0 times] testShouldFailExpectCallWithNoValueAndWrongMinGas() ([GAS])\n[FAIL: next call did not revert as expected] testShouldFailExpectCallWithRevertDisallowed() ([GAS])\n[FAIL: expected call to 0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f with data 0x3fc7c698 to be called 1 time, but was called 0 times] testShouldFailExpectInnerCall() ([GAS])\n[FAIL: expected call to 0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f with data 0x771602f700000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002 to be called 3 times, but was called 2 times] testShouldFailExpectMultipleCallsWithDataAdditive() ([GAS])\n[FAIL: expected call to 0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f with data 0x771602f7 to be called 1 time, but was called 0 times] testShouldFailExpectSelectorCall() ([GAS])\nSuite result: FAILED. 0 passed; 9 failed; 0 skipped; [ELAPSED]\n...\n\"#,\n    );\n\n    cmd.forge_fuse()\n        .args([\"test\", \"--mc\", \"ExpectCallCountFailureTest\"])\n        .assert_failure()\n        .stdout_eq(\n            r#\"No files changed, compilation skipped\n...\n[FAIL: expected call to 0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f with data 0xc290d6910000000000000000000000000000000000000000000000000000000000000002, value 1 to be called 1 time, but was called 0 times] testShouldFailExpectCallCountValue() ([GAS])\n[FAIL: expected call to 0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f with data 0x771602f700000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001, value 0, gas 25000 to be called 2 times, but was called 0 times] testShouldFailExpectCallCountWithNoValueAndWrongGas() ([GAS])\n[FAIL: expected call to 0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f with data 0x771602f700000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001, value 0, minimum gas 50001 to be called 1 time, but was called 0 times] testShouldFailExpectCallCountWithNoValueAndWrongMinGas() ([GAS])\n[FAIL: expected call to 0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f with data 0x771602f700000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002 to be called 2 times, but was called 1 time] testShouldFailExpectCallCountWithWrongCount() ([GAS])\n[FAIL: expected call to 0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f with data 0x3fc7c698 to be called 1 time, but was called 0 times] testShouldFailExpectCountInnerCall() ([GAS])\nSuite result: FAILED. 0 passed; 5 failed; 0 skipped; [ELAPSED]\n...\n\"#,\n        );\n\n    cmd.forge_fuse()\n        .args([\"test\", \"--mc\", \"ExpectCallMixedFailureTest\"])\n        .assert_failure()\n        .stdout_eq(\n            r#\"No files changed, compilation skipped\n...\n[FAIL: vm.expectCall: counted expected calls can only bet set once] testShouldFailOverrideCountWithCount() ([GAS])\n[FAIL: vm.expectCall: cannot overwrite a counted expectCall with a non-counted expectCall] testShouldFailOverrideCountWithNoCount() ([GAS])\n[FAIL: vm.expectCall: counted expected calls can only bet set once] testShouldFailOverrideNoCountWithCount() ([GAS])\nSuite result: FAILED. 0 passed; 3 failed; 0 skipped; [ELAPSED]\n...\n\"#,\n        );\n});\n\nforgetest!(expect_create_tests_should_fail, |prj, cmd| {\n    prj.insert_ds_test();\n    prj.insert_vm();\n\n    let expect_create_failures = include_str!(\"../fixtures/ExpectCreateFailures.t.sol\");\n\n    prj.add_source(\"ExpectCreateFailures.t.sol\", expect_create_failures);\n\n    cmd.forge_fuse().args([\"test\", \"--mc\", \"ExpectCreateFailureTest\"]).assert_failure().stdout_eq(str![[r#\"\n...\n[FAIL: expected CREATE call by address 0x7fa9385be102ac3eac297483dd6233d62b3e1496 for bytecode [..] but not found] testShouldFailExpectCreate() ([GAS])\n[FAIL: expected CREATE2 call by address 0x7fa9385be102ac3eac297483dd6233d62b3e1496 for bytecode [..] but not found] testShouldFailExpectCreate2() ([GAS])\n[FAIL: expected CREATE2 call by address 0x7fa9385be102ac3eac297483dd6233d62b3e1496 for bytecode [..] but not found] testShouldFailExpectCreate2WrongBytecode() ([GAS])\n[FAIL: expected CREATE2 call by address 0x0000000000000000000000000000000000000000 for bytecode [..] but not found] testShouldFailExpectCreate2WrongDeployer() ([GAS])\n[FAIL: expected CREATE2 call by address 0x7fa9385be102ac3eac297483dd6233d62b3e1496 for bytecode [..] but not found] testShouldFailExpectCreate2WrongScheme() ([GAS])\n[FAIL: expected CREATE call by address 0x7fa9385be102ac3eac297483dd6233d62b3e1496 for bytecode [..] but not found] testShouldFailExpectCreateWrongBytecode() ([GAS])\n[FAIL: expected CREATE call by address 0x0000000000000000000000000000000000000000 for bytecode [..] but not found] testShouldFailExpectCreateWrongDeployer() ([GAS])\n[FAIL: expected CREATE call by address 0x7fa9385be102ac3eac297483dd6233d62b3e1496 for bytecode [..] but not found] testShouldFailExpectCreateWrongScheme() ([GAS])\nSuite result: FAILED. 0 passed; 8 failed; 0 skipped; [ELAPSED]\n...\n\n\"#]]);\n});\n\nforgetest!(flaky_expect_emit_tests_should_fail, |prj, cmd| {\n    prj.insert_ds_test();\n    prj.insert_vm();\n\n    let expect_emit_failure_tests = include_str!(\"../fixtures/ExpectEmitFailures.t.sol\");\n\n    prj.add_source(\"ExpectEmitFailures.sol\", expect_emit_failure_tests);\n\n    cmd.forge_fuse().arg(\"build\").assert_success();\n    cmd.forge_fuse().args([\"selectors\", \"cache\"]).assert_success();\n\n    cmd.forge_fuse().args([\"test\", \"--mc\", \"ExpectEmitFailureTest\"]).assert_failure().stdout_eq(str![[r#\"No files changed, compilation skipped\n...\n[FAIL: E != expected A] testShouldFailCanMatchConsecutiveEvents() ([GAS])\n[FAIL: log != expected SomethingElse] testShouldFailDifferentIndexedParameters() ([GAS])\n[FAIL: log != expected log] testShouldFailEmitOnlyAppliesToNextCall() ([GAS])\n[FAIL: next call did not revert as expected] testShouldFailEmitWindowWithRevertDisallowed() ([GAS])\n[FAIL: E != expected A] testShouldFailEventsOnTwoCalls() ([GAS])\n[FAIL: Something param mismatch at [..]: expected=[..], got=[..]; counterexample: calldata=[..] args=[..]] testShouldFailExpectEmit(bool,bool,bool,bool,uint128,uint128,uint128,uint128) (runs: 0, [AVG_GAS])\n[FAIL: log emitter mismatch: expected=[..], got=[..]] testShouldFailExpectEmitAddress() ([GAS])\n[FAIL: log emitter mismatch: expected=[..], got=[..]] testShouldFailExpectEmitAddressWithArgs() ([GAS])\n[FAIL: Something != expected SomethingElse] testShouldFailExpectEmitCanMatchWithoutExactOrder() ([GAS])\n[FAIL: expected an emit, but no logs were emitted afterwards. you might have mismatched events or not enough events were emitted] testShouldFailExpectEmitDanglingNoReference() ([GAS])\n[FAIL: expected an emit, but no logs were emitted afterwards. you might have mismatched events or not enough events were emitted] testShouldFailExpectEmitDanglingWithReference() ([GAS])\n[FAIL: Something param mismatch at [..]: expected=[..], got=[..]; counterexample: calldata=[..] args=[..]] testShouldFailExpectEmitNested(bool,bool,bool,bool,uint128,uint128,uint128,uint128) (runs: 0, [AVG_GAS])\n[FAIL: log != expected log] testShouldFailLowLevelWithoutEmit() ([GAS])\n[FAIL: log != expected log] testShouldFailMatchRepeatedEventsOutOfOrder() ([GAS])\n[FAIL: log != expected log] testShouldFailNoEmitDirectlyOnNextCall() ([GAS])\nSuite result: FAILED. 0 passed; 15 failed; 0 skipped; [ELAPSED]\n...\n\"#]]);\n\n    cmd.forge_fuse()\n        .args([\"test\", \"--mc\", \"ExpectEmitCountFailureTest\"])\n        .assert_failure()\n        .stdout_eq(\n            r#\"No files changed, compilation skipped\n...\n[FAIL: log != expected log] testShouldFailCountEmitsFromAddress() ([GAS])\n[FAIL: log != expected log] testShouldFailCountLessEmits() ([GAS])\n[FAIL: log != expected Something] testShouldFailEmitSomethingElse() ([GAS])\n[FAIL: log emitted but expected 0 times] testShouldFailNoEmit() ([GAS])\n[FAIL: log emitted but expected 0 times] testShouldFailNoEmitFromAddress() ([GAS])\nSuite result: FAILED. 0 passed; 5 failed; 0 skipped; [ELAPSED]\n...\n\"#,\n        );\n});\n\nforgetest!(flaky_expect_emit_params_tests_should_fail, |prj, cmd| {\n    prj.insert_ds_test();\n    prj.insert_vm();\n    prj.update_config(|config| {\n        config.fuzz.dictionary.max_fuzz_dictionary_literals = 0;\n    });\n\n    let expect_emit_failure_src = include_str!(\"../fixtures/ExpectEmitParamHarness.sol\");\n    let expect_emit_failure_tests = include_str!(\"../fixtures/ExpectEmitParamFailures.t.sol\");\n\n    prj.add_source(\"ExpectEmitParamHarness.sol\", expect_emit_failure_src);\n    prj.add_source(\"ExpectEmitParamFailures.sol\", expect_emit_failure_tests);\n\n    cmd.forge_fuse().arg(\"build\").assert_success();\n\n    cmd.forge_fuse().args([\"test\", \"--mc\", \"ExpectEmitParamFailures\"]).assert_failure().stdout_eq(\n        r#\"No files changed, compilation skipped\n...\n[PASS] testSelectiveChecks() ([GAS])\nSuite result: FAILED. 1 passed; 8 failed; 0 skipped; [ELAPSED]\n...\n[FAIL: anonymous log mismatch at param 0: expected=0x0000000000000000000000000000000000000000000000000000000000000064, got=0x00000000000000000000000000000000000000000000000000000000000003e7] testAnonymousEventMismatch() ([GAS])\n[FAIL: ComplexEvent != expected SimpleEvent] testCompletelyDifferentEvent() ([GAS])\n[FAIL: SimpleEvent param mismatch at b: expected=200, got=999] testIndexedParamMismatch() ([GAS])\n[FAIL: ManyParams param mismatch at a: expected=100, got=111, b: expected=200, got=222, c: expected=300, got=333, d: expected=400, got=444, e: expected=500, got=555] testManyParameterMismatches() ([GAS])\n[FAIL: SimpleEvent param mismatch at c: expected=300, got=999] testMixedEventNonIndexedMismatch() ([GAS])\n[FAIL: SimpleEvent param mismatch at a: expected=100, got=999, b: expected=200, got=888, c: expected=300, got=777] testMultipleMismatches() ([GAS])\n[FAIL: SimpleEvent param mismatch at c: expected=300, got=999] testNonIndexedParamMismatch() ([GAS])\n[FAIL: MixedEventNumbering param mismatch at param2: expected=300, got=999] testParameterNumbering() ([GAS])\n\nEncountered a total of 8 failing tests, 1 tests succeeded\n...\n\"#,\n    );\n});\n\nforgetest!(mem_safety_test_should_fail, |prj, cmd| {\n    prj.insert_ds_test();\n    prj.insert_vm();\n\n    let mem_safety_failure_tests = include_str!(\"../fixtures/MemSafetyFailures.t.sol\");\n\n    prj.add_source(\"MemSafetyFailures.sol\", mem_safety_failure_tests);\n\n    cmd.forge_fuse().args([\"test\", \"--mc\", \"MemSafetyFailureTest\"]).assert_failure().stdout_eq(\n        r#\"[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\n...\n[FAIL: Expected call to fail] testShouldFailExpectSafeMemoryCall() ([GAS])\n[FAIL: memory write at offset 0x100 of size 0x60 not allowed; safe range: (0x00, 0x60] U (0x80, 0x100]] testShouldFailExpectSafeMemory_CALL() ([GAS])\n[FAIL: memory write at offset 0x100 of size 0x60 not allowed; safe range: (0x00, 0x60] U (0x80, 0x100]] testShouldFailExpectSafeMemory_CALLCODE() ([GAS])\n[FAIL: memory write at offset 0xA0 of size 0x20 not allowed; safe range: (0x00, 0x60] U (0x80, 0xA0]; counterexample: calldata=[..] args=[..]] testShouldFailExpectSafeMemory_CALLDATACOPY(uint256) (runs: 0, [AVG_GAS])\n[FAIL: memory write at offset 0x80 of size [..] not allowed; safe range: (0x00, 0x60] U (0x80, 0xA0]] testShouldFailExpectSafeMemory_CODECOPY() ([GAS])\n[FAIL: memory write at offset 0x100 of size 0x20 not allowed; safe range: (0x00, 0x60] U (0x80, 0x100]] testShouldFailExpectSafeMemory_CREATE() ([GAS])\n[FAIL: memory write at offset 0x100 of size 0x20 not allowed; safe range: (0x00, 0x60] U (0x80, 0x100]] testShouldFailExpectSafeMemory_CREATE2() ([GAS])\n[FAIL: memory write at offset 0x100 of size 0x60 not allowed; safe range: (0x00, 0x60] U (0x80, 0x100]] testShouldFailExpectSafeMemory_DELEGATECALL() ([GAS])\n[FAIL: memory write at offset 0xA0 of size 0x20 not allowed; safe range: (0x00, 0x60] U (0x80, 0xA0]] testShouldFailExpectSafeMemory_EXTCODECOPY() ([GAS])\n[FAIL: memory write at offset 0x100 of size 0x20 not allowed; safe range: (0x00, 0x60] U (0x80, 0x100]] testShouldFailExpectSafeMemory_LOG0() ([GAS])\n[FAIL: memory write at offset 0x100 of size 0x20 not allowed; safe range: (0x00, 0x60] U (0x80, 0x100]] testShouldFailExpectSafeMemory_MLOAD() ([GAS])\n[FAIL: memory write at offset 0x81 of size 0x01 not allowed; safe range: (0x00, 0x60] U (0x80, 0x81]] testShouldFailExpectSafeMemory_MSTORE8_High() ([GAS])\n[FAIL: memory write at offset 0x60 of size 0x01 not allowed; safe range: (0x00, 0x60] U (0x80, 0x81]] testShouldFailExpectSafeMemory_MSTORE8_Low() ([GAS])\n[FAIL: memory write at offset 0xA0 of size 0x20 not allowed; safe range: (0x00, 0x60] U (0x80, 0xA0]] testShouldFailExpectSafeMemory_MSTORE_High() ([GAS])\n[FAIL: memory write at offset 0x60 of size 0x20 not allowed; safe range: (0x00, 0x60] U (0x80, 0xA0]] testShouldFailExpectSafeMemory_MSTORE_Low() ([GAS])\n[FAIL: memory write at offset 0x100 of size 0x20 not allowed; safe range: (0x00, 0x60] U (0x80, 0x100]] testShouldFailExpectSafeMemory_RETURN() ([GAS])\n[FAIL: memory write at offset 0x100 of size 0x60 not allowed; safe range: (0x00, 0x60] U (0x80, 0x100]] testShouldFailExpectSafeMemory_RETURNDATACOPY() ([GAS])\n[FAIL: EvmError: Revert] testShouldFailExpectSafeMemory_REVERT() ([GAS])\n[FAIL: memory write at offset 0x100 of size 0x20 not allowed; safe range: (0x00, 0x60] U (0x80, 0x100]] testShouldFailExpectSafeMemory_SHA3() ([GAS])\n[FAIL: memory write at offset 0x100 of size 0x60 not allowed; safe range: (0x00, 0x60] U (0x80, 0x100]] testShouldFailExpectSafeMemory_STATICCALL() ([GAS])\n[FAIL: memory write at offset 0xA0 of size 0x20 not allowed; safe range: (0x00, 0x60] U (0x80, 0xA0]] testShouldFailStopExpectSafeMemory() ([GAS])\nSuite result: FAILED. 0 passed; 21 failed; 0 skipped; [ELAPSED]\n...\n\"#,\n    );\n});\n\nforgetest!(ds_style_test_failing, |prj, cmd| {\n    prj.insert_ds_test();\n\n    prj.add_source(\n        \"DSStyleTest.t.sol\",\n        r#\"\n        import \"./test.sol\";\n\n        contract DSStyleTest is DSTest {\n            function testDSTestFailingAssertions() public {\n                emit log_string(\"assertionOne\");\n                assertEq(uint256(1), uint256(2));\n                emit log_string(\"assertionTwo\");\n                assertEq(uint256(3), uint256(4));\n                emit log_string(\"done\");\n            }\n        }\n        \"#,\n    );\n\n    cmd.forge_fuse().args([\"test\", \"--mc\", \"DSStyleTest\", \"-vv\"]).assert_failure().stdout_eq(\n        r#\"[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\n...\n[FAIL] testDSTestFailingAssertions() ([GAS])\nLogs:\n  assertionOne\n  Error: a == b not satisfied [uint]\n    Expected: 2\n      Actual: 1\n  assertionTwo\n  Error: a == b not satisfied [uint]\n    Expected: 4\n      Actual: 3\n  done\n\nSuite result: FAILED. 0 passed; 1 failed; 0 skipped; [ELAPSED]\n...\n\"#,\n    );\n});\n\nforgetest!(failing_setup, |prj, cmd| {\n    prj.insert_ds_test();\n\n    prj.add_source(\n        \"FailingSetupTest.t.sol\",\n        r#\"\nimport \"./test.sol\";\n\ncontract FailingSetupTest is DSTest {\n    event Test(uint256 n);\n\n    function setUp() public {\n        emit Test(42);\n        require(false, \"setup failed predictably\");\n    }\n\n    function testShouldBeMarkedAsFailedBecauseOfSetup() public {\n        emit log(\"setup did not fail\");\n    }\n}\n        \"#,\n    );\n\n    cmd.args([\"test\", \"--mc\", \"FailingSetupTest\"]).assert_failure().stdout_eq(str![[\n        r#\"[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\n...\n[FAIL: setup failed predictably] setUp() ([GAS])\nSuite result: FAILED. 0 passed; 1 failed; 0 skipped; [ELAPSED]\n...\n\"#\n    ]]);\n});\n\nforgetest!(multiple_after_invariants, |prj, cmd| {\n    prj.insert_ds_test();\n\n    prj.add_source(\n        \"MultipleAfterInvariantsTest.t.sol\",\n        r#\"\nimport \"./test.sol\";\n\ncontract MultipleAfterInvariant is DSTest {\n    function afterInvariant() public {}\n\n    function afterinvariant() public {}\n\n    function testFailShouldBeMarkedAsFailedBecauseOfAfterInvariant()\n        public\n        pure\n    {\n        assert(true);\n    }\n}\n    \"#,\n    );\n\n    cmd.args([\"test\", \"--mc\", \"MultipleAfterInvariant\"]).assert_failure().stdout_eq(str![[\n        r#\"[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\n...\n[FAIL: multiple afterInvariant functions] afterInvariant() ([GAS])\nSuite result: FAILED. 0 passed; 1 failed; 0 skipped; [ELAPSED]\n...\n\"#\n    ]]);\n});\n\nforgetest!(multiple_setups, |prj, cmd| {\n    prj.insert_ds_test();\n\n    prj.add_source(\n        \"MultipleSetupsTest.t.sol\",\n        r#\"\n\nimport \"./test.sol\";\n\ncontract MultipleSetup is DSTest {\n    function setUp() public {}\n\n    function setup() public {}\n\n    function testFailShouldBeMarkedAsFailedBecauseOfSetup() public {\n        assert(true);\n    }\n}\n\n    \"#,\n    );\n\n    cmd.forge_fuse().args([\"test\", \"--mc\", \"MultipleSetup\"]).assert_failure().stdout_eq(str![[\n        r#\"[COMPILING_FILES] with [SOLC_VERSION]\n...\n[FAIL: multiple setUp functions] setUp() ([GAS])\nSuite result: FAILED. 0 passed; 1 failed; 0 skipped; [ELAPSED]\n...\"#\n    ]]);\n});\n\nforgetest!(emit_diff_anonymous, |prj, cmd| {\n    prj.insert_ds_test();\n    prj.insert_vm();\n    prj.add_source(\n        \"EmitDiffAnonymousTest.t.sol\",\n        r#\"\n    import \"./test.sol\";\n    import \"./Vm.sol\";\n\n    contract Target {\n        event AnonymousEventNonIndexed(uint256 a) anonymous;\n\n        function emitAnonymousEventNonIndexed(uint256 a) external {\n            emit AnonymousEventNonIndexed(a);\n        }\n    }\n\n    contract EmitDiffAnonymousTest is DSTest {\n        Vm constant vm = Vm(HEVM_ADDRESS);\n        Target target;\n\n        event DifferentAnonymousEventNonIndexed(string a) anonymous;\n\n        function setUp() public {\n            target = new Target();\n        }\n\n        function testShouldFailEmitDifferentEventNonIndexed() public {\n            vm.expectEmitAnonymous(false, false, false, false, true);\n            emit DifferentAnonymousEventNonIndexed(\"1\");\n            target.emitAnonymousEventNonIndexed(1);\n        }\n    }\n    \"#,\n    );\n\n    cmd.forge_fuse().args([\"test\", \"--mc\", \"EmitDiffAnonymousTest\"]).assert_failure().stdout_eq(\n        str![[r#\"[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\n...\n[FAIL: log != expected log] testShouldFailEmitDifferentEventNonIndexed() ([GAS])\nSuite result: FAILED. 0 passed; 1 failed; 0 skipped; [ELAPSED]\n...\n\"#]],\n    );\n});\n"
  },
  {
    "path": "crates/forge/tests/cli/fmt.rs",
    "content": "//! Integration tests for `forge fmt` command\n\nuse foundry_test_utils::{forgetest, forgetest_init};\n\nconst UNFORMATTED: &str = r#\"// SPDX-License-Identifier: MIT\npragma         solidity  =0.8.33    ;\n\ncontract  Test  {\n    uint256    public    value ;\n    function   setValue ( uint256   _value )   public   {\n        value   =   _value ;\n    }\n}\"#;\n\nconst FORMATTED: &str = r#\"// SPDX-License-Identifier: MIT\npragma solidity =0.8.33;\n\ncontract Test {\n    uint256 public value;\n\n    function setValue(uint256 _value) public {\n        value = _value;\n    }\n}\n\"#;\n\nforgetest_init!(fmt_exclude_libs_in_recursion, |prj, cmd| {\n    prj.update_config(|config| config.fmt.ignore = vec![\"src/ignore/\".to_string()]);\n\n    prj.add_lib(\"SomeLib.sol\", UNFORMATTED);\n    prj.add_raw_source(\"ignore/IgnoredContract.sol\", UNFORMATTED);\n    cmd.args([\"fmt\", \".\", \"--check\"]);\n    cmd.assert_success();\n\n    cmd.forge_fuse().args([\"fmt\", \"lib/SomeLib.sol\", \"--check\"]);\n    cmd.assert_failure();\n});\n\n// Test that fmt can format a simple contract file\nforgetest_init!(fmt_file, |prj, cmd| {\n    prj.add_raw_source(\"FmtTest.sol\", UNFORMATTED);\n    cmd.arg(\"fmt\").arg(\"src/FmtTest.sol\");\n    cmd.assert_success().stdout_eq(str![[r#\"\nFormatted [..]/src/FmtTest.sol\n\n\"#]]);\n    assert_data_eq!(\n        std::fs::read_to_string(prj.root().join(\"src/FmtTest.sol\")).unwrap(),\n        FORMATTED,\n    );\n});\n\n// Test that fmt can format from stdin\nforgetest!(fmt_stdin, |_prj, cmd| {\n    cmd.args([\"fmt\", \"-\", \"--raw\"]);\n    cmd.stdin(UNFORMATTED.as_bytes());\n    cmd.assert_success().stdout_eq(FORMATTED);\n\n    // stdin with `--raw` returns formatted code\n    cmd.stdin(FORMATTED.as_bytes());\n    cmd.assert_success().stdout_eq(FORMATTED);\n\n    // stdin with `--check` and without `--raw`returns diff\n    cmd.forge_fuse().args([\"fmt\", \"-\", \"--check\"]);\n    cmd.assert_success().stdout_eq(\"\");\n});\n\nforgetest_init!(fmt_check_mode, |prj, cmd| {\n    // Run fmt --check on a well-formatted file\n    prj.add_raw_source(\"Test.sol\", FORMATTED);\n    cmd.arg(\"fmt\").arg(\"--check\").arg(\"src/Test.sol\");\n    cmd.assert_success().stderr_eq(\"\").stdout_eq(\"\");\n\n    // Run fmt --check on a mal-formatted file\n    prj.add_raw_source(\"Test2.sol\", UNFORMATTED);\n    cmd.forge_fuse().arg(\"fmt\").arg(\"--check\").arg(\"src/Test2.sol\");\n    cmd.assert_failure();\n});\n\nforgetest!(fmt_check_mode_stdin, |_prj, cmd| {\n    // Run fmt --check with well-formatted stdin input\n    cmd.arg(\"fmt\").arg(\"-\").arg(\"--check\");\n    cmd.stdin(FORMATTED.as_bytes());\n    cmd.assert_success().stderr_eq(\"\").stdout_eq(\"\");\n\n    // Run fmt --check with mal-formatted stdin input\n    cmd.stdin(UNFORMATTED.as_bytes());\n    cmd.assert_failure().stderr_eq(\"\").stdout_eq(str![[r#\"\nDiff in stdin:\n1   1    | // SPDX-License-Identifier: MIT\n2        |-pragma         solidity  =0.8.33    ;\n    2    |+pragma solidity =0.8.33;\n...\n4        |-contract  Test  {\n5        |-    uint256    public    value ;\n6        |-    function   setValue ( uint256   _value )   public   {\n7        |-        value   =   _value ;\n    4    |+contract Test {\n    5    |+    uint256 public value;\n...\n    7    |+    function setValue(uint256 _value) public {\n    8    |+        value = _value;\n8   9    |     }\n9        |-}\n    10   |+}\n\n\"#]]);\n});\n\n// Test that original is returned if read from stdin and no diff.\n// <https://github.com/foundry-rs/foundry/issues/11871>\nforgetest!(fmt_stdin_original, |_prj, cmd| {\n    cmd.args([\"fmt\", \"-\", \"--raw\"]);\n\n    cmd.stdin(FORMATTED.as_bytes());\n    cmd.assert_success().stdout_eq(FORMATTED.as_bytes());\n});\n\n// Test that fmt can format a simple contract file\nforgetest_init!(fmt_file_config_parms_first, |prj, cmd| {\n    prj.create_file(\n        \"foundry.toml\",\n        r#\"\n[fmt]\nmultiline_func_header = 'params_first'\n\"#,\n    );\n    prj.add_raw_source(\"FmtTest.sol\", FORMATTED);\n    cmd.forge_fuse().args([\"fmt\", \"--check\"]).arg(\"src/FmtTest.sol\");\n    cmd.assert_failure().stdout_eq(str![[r#\"\nDiff in src/FmtTest.sol:\n...\n7        |-    function setValue(uint256 _value) public {\n    7    |+    function setValue(\n    8    |+        uint256 _value\n    9    |+    ) public {\n...\n\n\"#]]);\n});\n\n// https://github.com/foundry-rs/foundry/issues/12000\nforgetest_init!(fmt_only_cmnts_file, |prj, cmd| {\n    // Only line breaks\n    prj.add_raw_source(\"FmtTest.sol\", \"\\n\\n\");\n\n    cmd.forge_fuse().args([\"fmt\", \"src/FmtTest.sol\"]);\n    cmd.assert_success();\n    assert_data_eq!(std::fs::read_to_string(prj.root().join(\"src/FmtTest.sol\")).unwrap(), \"\",);\n    cmd.forge_fuse().args([\"fmt\", \"--check\", \"src/FmtTest.sol\"]);\n    cmd.assert_success();\n\n    // Only cmnts\n    prj.add_raw_source(\"FmtTest.sol\", \"\\n\\n// this is a cmnt\");\n\n    cmd.forge_fuse().args([\"fmt\", \"src/FmtTest.sol\"]);\n    cmd.assert_success();\n    assert_data_eq!(\n        std::fs::read_to_string(prj.root().join(\"src/FmtTest.sol\")).unwrap(),\n        \"// this is a cmnt\\n\",\n    );\n    cmd.forge_fuse().args([\"fmt\", \"--check\", \"src/FmtTest.sol\"]);\n    cmd.assert_success();\n});\n"
  },
  {
    "path": "crates/forge/tests/cli/fmt_integration.rs",
    "content": "use foundry_test_utils::util::ExtTester;\n\n/// Test `forge fmt` immutability.\n/// TODO: make sure original fmt is not changed after projects format and rev available.\nmacro_rules! fmt_test {\n    ($name:ident, $org:expr, $repo:expr, $commit:expr) => {\n        #[test]\n        fn $name() {\n            let (_, mut cmd) = ExtTester::new($org, $repo, $commit).setup_forge_prj(false);\n            cmd.arg(\"fmt\").assert_success();\n            cmd.arg(\"--check\").assert_success();\n        }\n    };\n}\n\nfmt_test!(fmt_ithaca_account, \"ithacaxyz\", \"account\", \"213c04ee1808784c18609607d85feba7730538fd\");\n\nfmt_test!(fmt_univ4_core, \"Uniswap\", \"v4-core\", \"59d3ecf53afa9264a16bba0e38f4c5d2231f80bc\");\n\nfmt_test!(\n    fmt_evk_periphery,\n    \"euler-xyz\",\n    \"evk-periphery\",\n    \"e41f2b9b7ed677ca03ff7bd7221a4e2fdd55504f\"\n);\n\nfmt_test!(fmt_0x_settler, \"0xProject\", \"0x-settler\", \"a388c8251ab6c4bedce1641b31027d7b1136daef\");\n"
  },
  {
    "path": "crates/forge/tests/cli/inline_config.rs",
    "content": "forgetest!(runs, |prj, cmd| {\n    prj.add_test(\n        \"inline.sol\",\n        \"\n        contract Inline {\n                /** forge-config:  default.fuzz.runs = 2 */\n            function test1(bool) public {}\n\n            \\t///\\t forge-config:\\tdefault.fuzz.runs=\\t3 \\t\n\n            function test2(bool) public {}\n        }\n    \",\n    );\n\n    cmd.arg(\"test\").assert_success().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\nRan 2 tests for test/inline.sol:Inline\n[PASS] test1(bool) (runs: 2, [AVG_GAS])\n[PASS] test2(bool) (runs: 3, [AVG_GAS])\nSuite result: ok. 2 passed; 0 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 2 tests passed, 0 failed, 0 skipped (2 total tests)\n\n\"#]]);\n\n    // Make sure inline config is parsed in coverage too.\n    cmd.forge_fuse().arg(\"coverage\").assert_success().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\nAnalysing contracts...\nRunning tests...\n\nRan 2 tests for test/inline.sol:Inline\n[PASS] test1(bool) (runs: 2, [AVG_GAS])\n[PASS] test2(bool) (runs: 3, [AVG_GAS])\nSuite result: ok. 2 passed; 0 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 2 tests passed, 0 failed, 0 skipped (2 total tests)\n\n╭-------+---------------+---------------+---------------+---------------╮\n| File  | % Lines       | % Statements  | % Branches    | % Funcs       |\n+=======================================================================+\n| Total | 100.00% (0/0) | 100.00% (0/0) | 100.00% (0/0) | 100.00% (0/0) |\n╰-------+---------------+---------------+---------------+---------------╯\n\n\"#]]);\n});\n\nforgetest!(invalid_profile, |prj, cmd| {\n    prj.add_test(\n        \"inline.sol\",\n        \"\n        /** forge-config:  unknown.fuzz.runs = 2 */\n        contract Inline {\n            function test(bool) public {}\n        }\n    \",\n    );\n\n    cmd.arg(\"test\").assert_failure().stderr_eq(str![[r#\"\nError: Inline config error at test/inline.sol:4:9: invalid profile `unknown.fuzz.runs = 2`; valid profiles: default\n\n\"#]]);\n});\n\n// TODO: Uncomment once this done for normal config too.\n/*\nforgetest!(invalid_key, |prj, cmd| {\n    prj.add_test(\n        \"inline.sol\",\n        \"\n        /** forge-config:  default.fuzzz.runs = 2 */\n        contract Inline {\n            function test(bool) public {}\n        }\n    \",\n    );\n\n    cmd.arg(\"test\").assert_failure().stderr_eq(str![[]]).stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\nRan 1 test for test/inline.sol:Inline\n[FAIL: failed to get inline configuration: unknown config section `default`] test(bool) ([GAS])\nSuite result: FAILED. 0 passed; 1 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 0 tests passed, 1 failed, 0 skipped (1 total tests)\n\nFailing tests:\nEncountered 1 failing test in test/inline.sol:Inline\n[FAIL: failed to get inline configuration: unknown config section `default`] test(bool) ([GAS])\n\nEncountered a total of 1 failing tests, 0 tests succeeded\n\n\"#]]);\n});\n\nforgetest!(invalid_key_2, |prj, cmd| {\n    prj.add_test(\n        \"inline.sol\",\n        \"\n/** forge-config:  default.fuzz.runss = 2 */\n        contract Inline {\n            function test(bool) public {}\n        }\n    \",\n    );\n\n    cmd.arg(\"test\").assert_failure().stderr_eq(str![[]]).stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\nRan 1 test for test/inline.sol:Inline\n[FAIL: failed to get inline configuration: unknown config section `default`] test(bool) ([GAS])\nSuite result: FAILED. 0 passed; 1 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 0 tests passed, 1 failed, 0 skipped (1 total tests)\n\nFailing tests:\nEncountered 1 failing test in test/inline.sol:Inline\n[FAIL: failed to get inline configuration: unknown config section `default`] test(bool) ([GAS])\n\nEncountered a total of 1 failing tests, 0 tests succeeded\n\n\"#]]);\n});\n*/\n\nforgetest!(invalid_value, |prj, cmd| {\n    prj.add_test(\n        \"inline.sol\",\n        \"\n        /** forge-config:  default.fuzz.runs = [2] */\n        contract Inline {\n            function test(bool) public {}\n        }\n    \",\n    );\n\n    cmd.arg(\"test\").assert_failure().stderr_eq(str![[]]).stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\nRan 1 test for test/inline.sol:Inline\n[FAIL: invalid type: found sequence, expected u32 for key \"default.fuzz.runs\" in inline config] setUp() ([GAS])\nSuite result: FAILED. 0 passed; 1 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 0 tests passed, 1 failed, 0 skipped (1 total tests)\n\nFailing tests:\nEncountered 1 failing test in test/inline.sol:Inline\n[FAIL: invalid type: found sequence, expected u32 for key \"default.fuzz.runs\" in inline config] setUp() ([GAS])\n\nEncountered a total of 1 failing tests, 0 tests succeeded\n\nTip: Run `forge test --rerun` to retry only the 1 failed test\n\n\"#]]);\n});\n\nforgetest!(invalid_value_2, |prj, cmd| {\n    prj.add_test(\n        \"inline.sol\",\n        \"\n        /** forge-config:  default.fuzz.runs = '2' */\n        contract Inline {\n            function test(bool) public {}\n        }\n    \",\n    );\n\n    cmd.arg(\"test\").assert_failure().stderr_eq(str![[]]).stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\nRan 1 test for test/inline.sol:Inline\n[FAIL: invalid type: found string \"2\", expected u32 for key \"default.fuzz.runs\" in inline config] setUp() ([GAS])\nSuite result: FAILED. 0 passed; 1 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 0 tests passed, 1 failed, 0 skipped (1 total tests)\n\nFailing tests:\nEncountered 1 failing test in test/inline.sol:Inline\n[FAIL: invalid type: found string \"2\", expected u32 for key \"default.fuzz.runs\" in inline config] setUp() ([GAS])\n\nEncountered a total of 1 failing tests, 0 tests succeeded\n\nTip: Run `forge test --rerun` to retry only the 1 failed test\n\n\"#]]);\n});\n\n#[cfg(not(feature = \"isolate-by-default\"))]\nforgetest_init!(config_inline_isolate, |prj, cmd| {\n    use serde::{Deserialize, Deserializer};\n    use std::{fs, path::Path};\n\n    prj.add_test(\n        \"inline.sol\",\n        r#\"\n        import {Test} from \"forge-std/Test.sol\";\n\n        contract Dummy {\n            uint256 public number;\n\n            function setNumber(uint256 newNumber) public {\n                number = newNumber;\n            }\n        }\n\n        contract FunctionConfig is Test {\n            Dummy dummy;\n\n            function setUp() public {\n                dummy = new Dummy();\n            }\n\n            /// forge-config: default.isolate = true\n            function test_isolate() public {\n                vm.startSnapshotGas(\"testIsolatedFunction\");\n                dummy.setNumber(1);\n                vm.stopSnapshotGas();\n            }\n\n            function test_non_isolate() public {\n                vm.startSnapshotGas(\"testNonIsolatedFunction\");\n                dummy.setNumber(2);\n                vm.stopSnapshotGas();\n            }\n        }\n\n        /// forge-config: default.isolate = true\n        contract ContractConfig is Test {\n            Dummy dummy;\n\n            function setUp() public {\n                dummy = new Dummy();\n            }\n\n            function test_non_isolate() public {\n                vm.startSnapshotGas(\"testIsolatedContract\");\n                dummy.setNumber(3);\n                vm.stopSnapshotGas();\n            }\n        }\n    \"#,\n    );\n\n    cmd.args([\"test\", \"-j1\"]).assert_success().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\nRan 1 test for test/inline.sol:ContractConfig\n[PASS] test_non_isolate() ([GAS])\nSuite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED]\n\nRan 2 tests for test/inline.sol:FunctionConfig\n[PASS] test_isolate() ([GAS])\n[PASS] test_non_isolate() ([GAS])\nSuite result: ok. 2 passed; 0 failed; 0 skipped; [ELAPSED]\n\nRan 2 test suites [ELAPSED]: 3 tests passed, 0 failed, 0 skipped (3 total tests)\n\n\"#]]);\n\n    assert!(prj.root().join(\"snapshots/FunctionConfig.json\").exists());\n    assert!(prj.root().join(\"snapshots/ContractConfig.json\").exists());\n\n    #[derive(Debug, Deserialize)]\n    #[serde(rename_all = \"camelCase\")]\n    struct FunctionConfig {\n        #[serde(deserialize_with = \"string_to_u64\")]\n        test_isolated_function: u64,\n\n        #[serde(deserialize_with = \"string_to_u64\")]\n        test_non_isolated_function: u64,\n    }\n\n    #[derive(Debug, Deserialize)]\n    #[serde(rename_all = \"camelCase\")]\n    struct ContractConfig {\n        #[serde(deserialize_with = \"string_to_u64\")]\n        test_isolated_contract: u64,\n    }\n\n    fn string_to_u64<'de, D>(deserializer: D) -> Result<u64, D::Error>\n    where\n        D: Deserializer<'de>,\n    {\n        let s: serde_json::Value = Deserialize::deserialize(deserializer)?;\n        match s {\n            serde_json::Value::String(s) => s.parse::<u64>().map_err(serde::de::Error::custom),\n            serde_json::Value::Number(n) if n.is_u64() => Ok(n.as_u64().unwrap()),\n            _ => Err(serde::de::Error::custom(\"Expected a string or number\")),\n        }\n    }\n\n    fn read_snapshot<T: for<'de> Deserialize<'de>>(path: &Path) -> T {\n        let content = fs::read_to_string(path).expect(\"Failed to read file\");\n        serde_json::from_str(&content).expect(\"Failed to parse snapshot\")\n    }\n\n    let function_config: FunctionConfig =\n        read_snapshot(&prj.root().join(\"snapshots/FunctionConfig.json\"));\n    let contract_config: ContractConfig =\n        read_snapshot(&prj.root().join(\"snapshots/ContractConfig.json\"));\n\n    // FunctionConfig {\n    //     test_isolated_function: 48926,\n    //     test_non_isolated_function: 27722,\n    // }\n\n    // ContractConfig {\n    //     test_isolated_contract: 48926,\n    // }\n\n    assert!(function_config.test_isolated_function > function_config.test_non_isolated_function);\n    assert_eq!(function_config.test_isolated_function, contract_config.test_isolated_contract);\n});\n\nforgetest_init!(config_inline_evm_version, |prj, cmd| {\n    prj.add_test(\n        \"inline.sol\",\n        r#\"\n        import {Test} from \"forge-std/Test.sol\";\n\n        contract Dummy {\n            function getBlobBaseFee() public returns (uint256) {\n                return block.blobbasefee;\n            }\n        }\n\n        contract FunctionConfig is Test {\n            Dummy dummy;\n\n            function setUp() public {\n                dummy = new Dummy();\n            }\n\n            /// forge-config: default.evm_version = \"shanghai\"\n            function test_old() public {\n                vm.expectRevert();\n                dummy.getBlobBaseFee();\n            }\n\n            function test_new() public {\n                dummy.getBlobBaseFee();\n            }\n        }\n\n        /// forge-config: default.evm_version = \"shanghai\"\n        contract ContractConfig is Test {\n            Dummy dummy;\n\n            function setUp() public {\n                dummy = new Dummy();\n            }\n\n            function test_old() public {\n                vm.expectRevert();\n                dummy.getBlobBaseFee();\n            }\n\n            /// forge-config: default.evm_version = \"cancun\"\n            function test_new() public {\n                dummy.getBlobBaseFee();\n            }\n        }\n    \"#,\n    );\n\n    cmd.args([\"test\", \"--evm-version=cancun\", \"-j1\"]).assert_success().stdout_eq(str![[r#\"\n...\nRan 2 tests for test/inline.sol:ContractConfig\n[PASS] test_new() ([GAS])\n[PASS] test_old() ([GAS])\nSuite result: ok. 2 passed; 0 failed; 0 skipped; [ELAPSED]\n\nRan 2 tests for test/inline.sol:FunctionConfig\n[PASS] test_new() ([GAS])\n[PASS] test_old() ([GAS])\nSuite result: ok. 2 passed; 0 failed; 0 skipped; [ELAPSED]\n\nRan 2 test suites [ELAPSED]: 4 tests passed, 0 failed, 0 skipped (4 total tests)\n\n\"#]]);\n});\n"
  },
  {
    "path": "crates/forge/tests/cli/install.rs",
    "content": "//! forge install and update tests\n\nuse forge::{DepIdentifier, FOUNDRY_LOCK, Lockfile};\nuse foundry_cli::utils::{Git, Submodules};\nuse foundry_compilers::artifacts::Remapping;\nuse foundry_config::Config;\nuse foundry_test_utils::util::{\n    ExtTester, FORGE_STD_REVISION, TestCommand, pretty_err, read_string,\n};\nuse semver::Version;\nuse std::{\n    fs,\n    path::{Path, PathBuf},\n    process::Command,\n    str::FromStr,\n};\n\nfn lockfile_get(root: &Path, dep_path: &Path) -> Option<DepIdentifier> {\n    let mut l = Lockfile::new(root);\n    l.read().unwrap();\n    l.get(dep_path).cloned()\n}\n\n// checks missing dependencies are auto installed\nforgetest_init!(can_install_missing_deps_build, |prj, cmd| {\n    prj.initialize_default_contracts();\n    prj.clear();\n\n    // wipe forge-std\n    let forge_std_dir = prj.root().join(\"lib/forge-std\");\n    pretty_err(&forge_std_dir, fs::remove_dir_all(&forge_std_dir));\n\n    // Build the project\n    cmd.arg(\"build\").assert_success().stdout_eq(str![[r#\"\nMissing dependencies found. Installing now...\n\n[UPDATING_DEPENDENCIES]\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\n\"#]]);\n\n    // assert lockfile\n    let forge_std = lockfile_get(prj.root(), &PathBuf::from(\"lib/forge-std\")).unwrap();\n    assert_eq!(forge_std.rev(), FORGE_STD_REVISION);\n\n    // Expect compilation to be skipped as no files have changed\n    cmd.forge_fuse().arg(\"build\").assert_success().stdout_eq(str![[r#\"\nNo files changed, compilation skipped\n\n\"#]]);\n});\n\n// checks missing dependencies are auto installed\nforgetest_init!(can_install_missing_deps_test, |prj, cmd| {\n    prj.initialize_default_contracts();\n    prj.clear();\n\n    // wipe forge-std\n    let forge_std_dir = prj.root().join(\"lib/forge-std\");\n    pretty_err(&forge_std_dir, fs::remove_dir_all(&forge_std_dir));\n\n    cmd.arg(\"test\").assert_success().stdout_eq(str![[r#\"\nMissing dependencies found. Installing now...\n\n[UPDATING_DEPENDENCIES]\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\nRan 2 tests for test/Counter.t.sol:CounterTest\n[PASS] testFuzz_SetNumber(uint256) (runs: 256, [AVG_GAS])\n[PASS] test_Increment() ([GAS])\nSuite result: ok. 2 passed; 0 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 2 tests passed, 0 failed, 0 skipped (2 total tests)\n\n\"#]]);\n\n    // assert lockfile\n    let forge_std = lockfile_get(prj.root(), &PathBuf::from(\"lib/forge-std\")).unwrap();\n    assert_eq!(forge_std.rev(), FORGE_STD_REVISION);\n});\n\n// test to check that install/remove works properly\nforgetest!(can_install_and_remove, |prj, cmd| {\n    cmd.git_init();\n\n    let libs = prj.root().join(\"lib\");\n    let git_mod = prj.root().join(\".git/modules/lib\");\n    let git_mod_file = prj.root().join(\".gitmodules\");\n\n    let forge_std = libs.join(\"forge-std\");\n    let forge_std_mod = git_mod.join(\"forge-std\");\n\n    let install = |cmd: &mut TestCommand| {\n        cmd.forge_fuse().args([\"install\", \"foundry-rs/forge-std\"]).assert_success().stdout_eq(\n            str![[r#\"\nInstalling forge-std in [..] (url: https://github.com/foundry-rs/forge-std, tag: None)\n    Installed forge-std[..]\n\n\"#]],\n        );\n\n        assert!(forge_std.exists());\n        assert!(forge_std_mod.exists());\n\n        let submods = read_string(&git_mod_file);\n        assert!(submods.contains(\"https://github.com/foundry-rs/forge-std\"));\n    };\n\n    let remove = |cmd: &mut TestCommand, target: &str| {\n        cmd.forge_fuse().args([\"remove\", \"--force\", target]).assert_success().stdout_eq(str![[\n            r#\"\nRemoving 'forge-std' in [..], (url: https://github.com/foundry-rs/forge-std, tag: None)\n\n\"#\n        ]]);\n\n        assert!(!forge_std.exists());\n        assert!(!forge_std_mod.exists());\n        let submods = read_string(&git_mod_file);\n        assert!(!submods.contains(\"https://github.com/foundry-rs/forge-std\"));\n    };\n\n    install(&mut cmd);\n    let forge_std = lockfile_get(prj.root(), &PathBuf::from(\"lib/forge-std\")).unwrap();\n    assert!(matches!(forge_std, DepIdentifier::Tag { .. }));\n    remove(&mut cmd, \"forge-std\");\n    let forge_std = lockfile_get(prj.root(), &PathBuf::from(\"lib/forge-std\"));\n    assert!(forge_std.is_none());\n\n    // install again and remove via relative path\n    install(&mut cmd);\n    remove(&mut cmd, \"lib/forge-std\");\n});\n\n// test to check we can run `forge install` in an empty dir <https://github.com/foundry-rs/foundry/issues/6519>\nforgetest!(can_install_empty, |prj, cmd| {\n    // create\n    cmd.git_init();\n    cmd.forge_fuse().args([\"install\"]);\n    cmd.assert_empty_stdout();\n\n    // create initial commit\n    fs::write(prj.root().join(\"README.md\"), \"Initial commit\").unwrap();\n\n    cmd.git_add();\n    cmd.git_commit(\"Initial commit\");\n\n    cmd.forge_fuse().args([\"install\"]);\n    cmd.assert_empty_stdout();\n});\n\n// test to check that package can be reinstalled after manually removing the directory\nforgetest!(can_reinstall_after_manual_remove, |prj, cmd| {\n    cmd.git_init();\n\n    let libs = prj.root().join(\"lib\");\n    let git_mod = prj.root().join(\".git/modules/lib\");\n    let git_mod_file = prj.root().join(\".gitmodules\");\n\n    let forge_std = libs.join(\"forge-std\");\n    let forge_std_mod = git_mod.join(\"forge-std\");\n\n    let install = |cmd: &mut TestCommand| {\n        cmd.forge_fuse().args([\"install\", \"foundry-rs/forge-std\"]).assert_success().stdout_eq(\n            str![[r#\"\nInstalling forge-std in [..] (url: https://github.com/foundry-rs/forge-std, tag: None)\n    Installed forge-std tag=[..]\"#]],\n        );\n\n        assert!(forge_std.exists());\n        assert!(forge_std_mod.exists());\n\n        let submods = read_string(&git_mod_file);\n        assert!(submods.contains(\"https://github.com/foundry-rs/forge-std\"));\n    };\n\n    install(&mut cmd);\n    let forge_std_lock = lockfile_get(prj.root(), &PathBuf::from(\"lib/forge-std\")).unwrap();\n    assert!(matches!(forge_std_lock, DepIdentifier::Tag { .. }));\n    fs::remove_dir_all(forge_std.clone()).expect(\"Failed to remove forge-std\");\n\n    // install again with tag\n    install(&mut cmd);\n    let forge_std_lock = lockfile_get(prj.root(), &PathBuf::from(\"lib/forge-std\")).unwrap();\n    assert!(matches!(forge_std_lock, DepIdentifier::Tag { .. }));\n});\n\n// test that we can repeatedly install the same dependency without changes\nforgetest!(can_install_repeatedly, |_prj, cmd| {\n    cmd.git_init();\n\n    cmd.forge_fuse().args([\"install\", \"foundry-rs/forge-std\"]);\n    for _ in 0..3 {\n        cmd.assert_success();\n    }\n});\n\n// test that by default we install the latest semver release tag\n// <https://github.com/openzeppelin/openzeppelin-contracts>\nforgetest!(can_install_latest_release_tag, |prj, cmd| {\n    cmd.git_init();\n    cmd.forge_fuse().args([\"install\", \"openzeppelin/openzeppelin-contracts\"]);\n    cmd.assert_success();\n\n    let dep = prj.paths().libraries[0].join(\"openzeppelin-contracts\");\n    assert!(dep.exists());\n\n    let oz_lock = lockfile_get(prj.root(), &PathBuf::from(\"lib/openzeppelin-contracts\")).unwrap();\n    assert!(matches!(oz_lock, DepIdentifier::Tag { .. }));\n\n    // the latest release at the time this test was written\n    let version: Version = \"4.8.0\".parse().unwrap();\n    let out = Command::new(\"git\").current_dir(&dep).args([\"describe\", \"--tags\"]).output().unwrap();\n    let tag = String::from_utf8_lossy(&out.stdout);\n    let current: Version = tag.as_ref().trim_start_matches('v').trim().parse().unwrap();\n\n    assert!(current >= version);\n});\n\nforgetest!(can_update_and_retain_tag_revs, |prj, cmd| {\n    cmd.git_init();\n\n    // Installs oz at release tag\n    cmd.forge_fuse()\n        .args([\"install\", \"openzeppelin/openzeppelin-contracts@v5.1.0\"])\n        .assert_success();\n\n    // Install solady pinned to rev i.e https://github.com/Vectorized/solady/commit/513f581675374706dbe947284d6b12d19ce35a2a\n    cmd.forge_fuse().args([\"install\", \"vectorized/solady@513f581\"]).assert_success();\n\n    let out = cmd.git_submodule_status();\n    let status = String::from_utf8_lossy(&out.stdout);\n    let oz_init = lockfile_get(prj.root(), &PathBuf::from(\"lib/openzeppelin-contracts\")).unwrap();\n    let solady_init = lockfile_get(prj.root(), &PathBuf::from(\"lib/solady\")).unwrap();\n    assert_eq!(oz_init.name(), \"v5.1.0\");\n    assert_eq!(solady_init.rev(), \"513f581\");\n    let submodules_init: Submodules = status.parse().unwrap();\n\n    cmd.forge_fuse().arg(\"update\").assert_success();\n\n    let out = cmd.git_submodule_status();\n    let status = String::from_utf8_lossy(&out.stdout);\n    let submodules_update: Submodules = status.parse().unwrap();\n    assert_eq!(submodules_init, submodules_update);\n\n    let oz_update = lockfile_get(prj.root(), &PathBuf::from(\"lib/openzeppelin-contracts\")).unwrap();\n    let solady_update = lockfile_get(prj.root(), &PathBuf::from(\"lib/solady\")).unwrap();\n    assert_eq!(oz_init, oz_update);\n    assert_eq!(solady_init, solady_update);\n});\n\nforgetest!(can_override_tag_in_update, |prj, cmd| {\n    cmd.git_init();\n\n    // Installs oz at release tag\n    cmd.forge_fuse()\n        .args([\"install\", \"openzeppelin/openzeppelin-contracts@v5.0.2\"])\n        .assert_success();\n\n    cmd.forge_fuse().args([\"install\", \"vectorized/solady@513f581\"]).assert_success();\n\n    let out = cmd.git_submodule_status();\n    let status = String::from_utf8_lossy(&out.stdout);\n\n    let submodules_init: Submodules = status.parse().unwrap();\n\n    let oz_init_lock =\n        lockfile_get(prj.root(), &PathBuf::from(\"lib/openzeppelin-contracts\")).unwrap();\n    assert_eq!(oz_init_lock.name(), \"v5.0.2\");\n    let solady_init_lock = lockfile_get(prj.root(), &PathBuf::from(\"lib/solady\")).unwrap();\n    assert_eq!(solady_init_lock.rev(), \"513f581\");\n\n    // Update oz to a different release tag\n    cmd.forge_fuse()\n        .args([\"update\", \"openzeppelin/openzeppelin-contracts@v5.1.0\"])\n        .assert_success();\n\n    let out = cmd.git_submodule_status();\n    let status = String::from_utf8_lossy(&out.stdout);\n\n    let submodules_update: Submodules = status.parse().unwrap();\n\n    assert_ne!(submodules_init.0[0], submodules_update.0[0]);\n    assert_eq!(submodules_init.0[1], submodules_update.0[1]);\n\n    let oz_update_lock =\n        lockfile_get(prj.root(), &PathBuf::from(\"lib/openzeppelin-contracts\")).unwrap();\n    let solady_update_lock = lockfile_get(prj.root(), &PathBuf::from(\"lib/solady\")).unwrap();\n\n    assert_ne!(oz_init_lock, oz_update_lock);\n    assert_eq!(oz_update_lock.name(), \"v5.1.0\");\n    assert_eq!(solady_init_lock, solady_update_lock);\n});\n\n// Ref: https://github.com/foundry-rs/foundry/pull/9522#pullrequestreview-2494431518\nforgetest!(should_not_update_tagged_deps, |prj, cmd| {\n    cmd.git_init();\n\n    // Installs oz at release tag\n    cmd.forge_fuse()\n        .args([\"install\", \"openzeppelin/openzeppelin-contracts@tag=v4.9.4\"])\n        .assert_success();\n\n    let out = cmd.git_submodule_status();\n    let status = String::from_utf8_lossy(&out.stdout);\n    let submodules_init: Submodules = status.parse().unwrap();\n\n    let oz_init = lockfile_get(prj.root(), &PathBuf::from(\"lib/openzeppelin-contracts\")).unwrap();\n\n    cmd.forge_fuse().arg(\"update\").assert_success();\n\n    let out = cmd.git_submodule_status();\n    let status = String::from_utf8_lossy(&out.stdout);\n    let submodules_update: Submodules = status.parse().unwrap();\n\n    assert_eq!(submodules_init, submodules_update);\n\n    let oz_update = lockfile_get(prj.root(), &PathBuf::from(\"lib/openzeppelin-contracts\")).unwrap();\n\n    assert_eq!(oz_init, oz_update);\n    // Check that halmos-cheatcodes dep is not added to oz deps\n    let halmos_path = prj.paths().libraries[0].join(\"openzeppelin-contracts/lib/halmos-cheatcodes\");\n\n    assert!(!halmos_path.exists());\n});\n\nforgetest!(can_remove_dep_from_foundry_lock, |prj, cmd| {\n    cmd.git_init();\n\n    cmd.forge_fuse()\n        .args([\"install\", \"openzeppelin/openzeppelin-contracts@tag=v4.9.4\"])\n        .assert_success();\n\n    cmd.forge_fuse().args([\"install\", \"vectorized/solady@513f581\"]).assert_success();\n    cmd.forge_fuse().args([\"remove\", \"openzeppelin-contracts\", \"--force\"]).assert_success();\n\n    let mut lock = Lockfile::new(prj.root());\n\n    lock.read().unwrap();\n\n    assert!(lock.get(&PathBuf::from(\"lib/openzeppelin-contracts\")).is_none());\n});\n\nforgetest!(\n    #[cfg_attr(windows, ignore = \"weird git fail\")]\n    can_sync_foundry_lock,\n    |prj, cmd| {\n        cmd.git_init();\n\n        cmd.forge_fuse().args([\"install\", \"foundry-rs/forge-std@master\"]).assert_success();\n\n        cmd.forge_fuse().args([\"install\", \"vectorized/solady\"]).assert_success();\n\n        fs::remove_file(prj.root().join(\"foundry.lock\")).unwrap();\n\n        // sync submodules and write foundry.lock\n        cmd.forge_fuse().arg(\"install\").assert_success();\n\n        let mut lock = forge::Lockfile::new(prj.root());\n        lock.read().unwrap();\n\n        assert!(matches!(\n            lock.get(&PathBuf::from(\"lib/forge-std\")).unwrap(),\n            &DepIdentifier::Branch { .. }\n        ));\n        assert!(matches!(\n            lock.get(&PathBuf::from(\"lib/solady\")).unwrap(),\n            &DepIdentifier::Rev { .. }\n        ));\n    }\n);\n\n// Tests that forge update doesn't break a working dependency by recursively updating nested\n// dependencies\nforgetest!(\n    #[cfg_attr(windows, ignore = \"weird git fail\")]\n    can_update_library_with_outdated_nested_dependency,\n    |prj, cmd| {\n        cmd.git_init();\n\n        let libs = prj.root().join(\"lib\");\n        let git_mod = prj.root().join(\".git/modules/lib\");\n        let git_mod_file = prj.root().join(\".gitmodules\");\n\n        // get paths to check inside install fn\n        let package = libs.join(\"forge-5980-test\");\n        let package_mod = git_mod.join(\"forge-5980-test\");\n\n        // install main dependency\n        cmd.forge_fuse().args([\"install\", \"evalir/forge-5980-test\"]).assert_success().stdout_eq(\n            str![[r#\"\nInstalling forge-5980-test in [..] (url: https://github.com/evalir/forge-5980-test, tag: None)\n    Installed forge-5980-test\n\n\"#]],\n        );\n\n        // assert paths exist\n        assert!(package.exists());\n        assert!(package_mod.exists());\n\n        let submods = read_string(git_mod_file);\n        assert!(submods.contains(\"https://github.com/evalir/forge-5980-test\"));\n\n        // try to update the top-level dependency; there should be no update for this dependency,\n        // but its sub-dependency has upstream (breaking) changes; forge should not attempt to\n        // update the sub-dependency\n        cmd.forge_fuse().args([\"update\", \"lib/forge-5980-test\"]).assert_empty_stdout();\n\n        // add explicit remappings for test file\n        let config = Config {\n            remappings: vec![\n                Remapping::from_str(\"forge-5980-test/=lib/forge-5980-test/src/\").unwrap().into(),\n                // explicit remapping for sub-dependency seems necessary for some reason\n                Remapping::from_str(\n                    \"forge-5980-test-dep/=lib/forge-5980-test/lib/forge-5980-test-dep/src/\",\n                )\n                .unwrap()\n                .into(),\n            ],\n            ..Default::default()\n        };\n        prj.write_config(config);\n\n        // create test file that uses the top-level dependency; if the sub-dependency is updated,\n        // compilation will fail\n        prj.add_source(\n            \"CounterCopy\",\n            r#\"\nimport \"forge-5980-test/Counter.sol\";\ncontract CounterCopy is Counter {\n}\n   \"#,\n        );\n\n        // build and check output\n        cmd.forge_fuse().arg(\"build\").assert_success().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\n\"#]]);\n    }\n);\n\n#[tokio::test]\nasync fn uni_v4_core_sync_foundry_lock() {\n    let (prj, mut cmd) =\n        ExtTester::new(\"Uniswap\", \"v4-core\", \"e50237c43811bd9b526eff40f26772152a42daba\")\n            .setup_forge_prj(true);\n\n    assert!(!prj.root().join(FOUNDRY_LOCK).exists());\n\n    let git = Git::new(prj.root());\n\n    let submodules = git.submodules().unwrap();\n\n    let submod_forge_std =\n        submodules.into_iter().find(|s| s.path() == &PathBuf::from(\"lib/forge-std\")).unwrap();\n    let submod_oz = submodules\n        .into_iter()\n        .find(|s| s.path() == &PathBuf::from(\"lib/openzeppelin-contracts\"))\n        .unwrap();\n    let submod_solmate =\n        submodules.into_iter().find(|s| s.path() == &PathBuf::from(\"lib/solmate\")).unwrap();\n\n    cmd.arg(\"install\").assert_success();\n\n    let forge_std = lockfile_get(prj.root(), &PathBuf::from(\"lib/forge-std\")).unwrap();\n    assert!(matches!(forge_std, DepIdentifier::Rev { .. }));\n    assert_eq!(forge_std.rev(), submod_forge_std.rev());\n    let solmate = lockfile_get(prj.root(), &PathBuf::from(\"lib/solmate\")).unwrap();\n    assert!(matches!(solmate, DepIdentifier::Rev { .. }));\n    assert_eq!(solmate.rev(), submod_solmate.rev());\n    let oz = lockfile_get(prj.root(), &PathBuf::from(\"lib/openzeppelin-contracts\")).unwrap();\n    assert!(matches!(oz, DepIdentifier::Rev { .. }));\n    assert_eq!(oz.rev(), submod_oz.rev());\n\n    // Commit the lockfile\n    git.add(&PathBuf::from(FOUNDRY_LOCK)).unwrap();\n    git.commit(\"Foundry lock\").unwrap();\n\n    // Try update. Nothing should get updated everything is pinned tag/rev.\n    cmd.forge_fuse().arg(\"update\").assert_success();\n\n    let forge_std = lockfile_get(prj.root(), &PathBuf::from(\"lib/forge-std\")).unwrap();\n    assert!(matches!(forge_std, DepIdentifier::Rev { .. }));\n    assert_eq!(forge_std.rev(), submod_forge_std.rev());\n    let solmate = lockfile_get(prj.root(), &PathBuf::from(\"lib/solmate\")).unwrap();\n    assert!(matches!(solmate, DepIdentifier::Rev { .. }));\n    assert_eq!(solmate.rev(), submod_solmate.rev());\n    let oz = lockfile_get(prj.root(), &PathBuf::from(\"lib/openzeppelin-contracts\")).unwrap();\n    assert!(matches!(oz, DepIdentifier::Rev { .. }));\n    assert_eq!(oz.rev(), submod_oz.rev());\n}\n\n#[tokio::test]\nasync fn oz_contracts_sync_foundry_lock() {\n    let (prj, mut cmd) = ExtTester::new(\n        \"OpenZeppelin\",\n        \"openzeppelin-contracts\",\n        \"840c974028316f3c8172c1b8e5ed67ad95e255ca\",\n    )\n    .setup_forge_prj(true);\n\n    assert!(!prj.root().join(FOUNDRY_LOCK).exists());\n\n    let git = Git::new(prj.root());\n\n    let submodules = git.submodules().unwrap();\n\n    let submod_forge_std =\n        submodules.into_iter().find(|s| s.path() == &PathBuf::from(\"lib/forge-std\")).unwrap();\n    let submod_erc4626_tests =\n        submodules.into_iter().find(|s| s.path() == &PathBuf::from(\"lib/erc4626-tests\")).unwrap();\n    let submod_halmos = submodules\n        .into_iter()\n        .find(|s| s.path() == &PathBuf::from(\"lib/halmos-cheatcodes\"))\n        .unwrap();\n\n    cmd.arg(\"install\").assert_success();\n\n    let forge_std = lockfile_get(prj.root(), &PathBuf::from(\"lib/forge-std\")).unwrap();\n    assert!(matches!(forge_std, DepIdentifier::Branch { .. }));\n    assert_eq!(forge_std.rev(), submod_forge_std.rev());\n    assert_eq!(forge_std.name(), \"v1\");\n    let erc4626_tests = lockfile_get(prj.root(), &PathBuf::from(\"lib/erc4626-tests\")).unwrap();\n    assert!(matches!(erc4626_tests, DepIdentifier::Rev { .. }));\n    assert_eq!(erc4626_tests.rev(), submod_erc4626_tests.rev());\n    let halmos = lockfile_get(prj.root(), &PathBuf::from(\"lib/halmos-cheatcodes\")).unwrap();\n    assert!(matches!(halmos, DepIdentifier::Rev { .. }));\n    assert_eq!(halmos.rev(), submod_halmos.rev());\n\n    // Commit the lockfile\n    git.add(&PathBuf::from(FOUNDRY_LOCK)).unwrap();\n    git.commit(\"Foundry lock\").unwrap();\n\n    // Try update. forge-std should get updated, rest should remain the same.\n    cmd.forge_fuse().arg(\"update\").assert_success();\n\n    let forge_std = lockfile_get(prj.root(), &PathBuf::from(\"lib/forge-std\")).unwrap();\n    assert!(matches!(forge_std, DepIdentifier::Branch { .. }));\n    // assert_eq!(forge_std.rev(), submod_forge_std.rev());  // This can fail, as forge-std will get\n    // updated to the latest commit on master.\n    assert_eq!(forge_std.name(), \"v1\"); // But it stays locked on the same master\n    let erc4626_tests = lockfile_get(prj.root(), &PathBuf::from(\"lib/erc4626-tests\")).unwrap();\n    assert!(matches!(erc4626_tests, DepIdentifier::Rev { .. }));\n    assert_eq!(erc4626_tests.rev(), submod_erc4626_tests.rev());\n    let halmos = lockfile_get(prj.root(), &PathBuf::from(\"lib/halmos-cheatcodes\")).unwrap();\n    assert!(matches!(halmos, DepIdentifier::Rev { .. }));\n    assert_eq!(halmos.rev(), submod_halmos.rev());\n}\n\n#[tokio::test]\nasync fn correctly_sync_dep_with_multiple_version() {\n    let (prj, mut cmd) = ExtTester::new(\n        \"yash-atreya\",\n        \"sync-lockfile-multi-version-dep\",\n        \"1ca47e73a168e54f8f7761862dbd0c603856c5c8\",\n    )\n    .setup_forge_prj(true);\n\n    assert!(!prj.root().join(FOUNDRY_LOCK).exists());\n\n    let git = Git::new(prj.root());\n\n    let submodules = git.submodules().unwrap();\n    let submod_forge_std =\n        submodules.into_iter().find(|s| s.path() == &PathBuf::from(\"lib/forge-std\")).unwrap();\n    let submod_solady =\n        submodules.into_iter().find(|s| s.path() == &PathBuf::from(\"lib/solady\")).unwrap();\n    let submod_solday_v_245 =\n        submodules.into_iter().find(|s| s.path() == &PathBuf::from(\"lib/solady-v0.0.245\")).unwrap();\n\n    cmd.arg(\"install\").assert_success();\n\n    let forge_std = lockfile_get(prj.root(), &PathBuf::from(\"lib/forge-std\")).unwrap();\n    assert!(matches!(forge_std, DepIdentifier::Rev { .. }));\n    assert_eq!(forge_std.rev(), submod_forge_std.rev());\n\n    let solady = lockfile_get(prj.root(), &PathBuf::from(\"lib/solady\")).unwrap();\n    assert!(matches!(solady, DepIdentifier::Rev { .. }));\n    assert_eq!(solady.rev(), submod_solady.rev());\n\n    let solday_v_245 = lockfile_get(prj.root(), &PathBuf::from(\"lib/solady-v0.0.245\")).unwrap();\n    assert!(matches!(solday_v_245, DepIdentifier::Rev { .. }));\n    assert_eq!(solday_v_245.rev(), submod_solday_v_245.rev());\n}\n\n// Regression test: `forge install --no-git` should clean up nested submodule contents\n// when installing a tag that does not use submodules for its dependencies.\n// https://github.com/foundry-rs/foundry/issues/13688\nforgetest!(flaky_install_no_git_cleans_nested_submodules, |prj, cmd| {\n    cmd.git_init();\n\n    // Install openzeppelin-contracts-upgradeable at v4.7.3 with --no-git.\n    // The default branch has submodules in lib/ (e.g. openzeppelin-contracts, erc4626-tests),\n    // but v4.7.3 does not use submodules for dependencies.\n    cmd.forge_fuse()\n        .args([\"install\", \"--no-git\", \"OpenZeppelin/openzeppelin-contracts-upgradeable@v4.7.3\"])\n        .assert_success();\n\n    let dep_dir = prj.root().join(\"lib\").join(\"openzeppelin-contracts-upgradeable\");\n    assert!(dep_dir.exists(), \"dependency should be installed\");\n\n    // The nested lib/ directory should either not exist or be empty — v4.7.3 does not use\n    // submodules so there should be no leftover submodule contents from the default branch.\n    let nested_lib = dep_dir.join(\"lib\");\n    if nested_lib.exists() {\n        let entries: Vec<_> = fs::read_dir(&nested_lib).unwrap().collect();\n        assert!(\n            entries.is_empty(),\n            \"nested lib/ should be empty after --no-git install at v4.7.3, found: {entries:?}\"\n        );\n    }\n\n    // There should be no .git file or directory anywhere under the installed dependency.\n    fn assert_no_git(dir: &Path) {\n        for entry in fs::read_dir(dir).unwrap() {\n            let entry = entry.unwrap();\n            let path = entry.path();\n            if path.file_name() == Some(\".git\".as_ref()) {\n                panic!(\"found leftover .git at {}\", path.display());\n            }\n            if path.is_dir() {\n                assert_no_git(&path);\n            }\n        }\n    }\n    assert_no_git(&dep_dir);\n});\n\nforgetest_init!(sync_on_forge_update, |prj, cmd| {\n    let git = Git::new(prj.root());\n\n    let submodules = git.submodules().unwrap();\n    assert!(submodules.0.iter().any(|s| s.rev() == FORGE_STD_REVISION));\n\n    let mut lockfile = Lockfile::new(prj.root());\n    lockfile.read().unwrap();\n\n    let forge_std = lockfile.get(&PathBuf::from(\"lib/forge-std\")).unwrap();\n    assert!(forge_std.rev() == FORGE_STD_REVISION);\n\n    // cd into the forge-std submodule\n    let forge_std_path = prj.root().join(\"lib/forge-std\");\n    let git = Git::new(&forge_std_path);\n\n    // Ensure we're on the release tag first (known starting point)\n    git.checkout(false, forge_std.name()).unwrap();\n    assert_eq!(git.head().unwrap(), forge_std.rev(), \"Forge std should be at the release tag\");\n\n    // Make sure origin/master is up to date, then resolve its commit hash deterministically.\n    git.fetch(false, \"origin\", Some(\"master\")).unwrap();\n    let origin_master_head = git.get_rev(\"refs/remotes/origin/master\", &forge_std_path).unwrap();\n\n    // Run update and assert the output matches the dynamically resolved hash.\n    let expected_output = format!(\n        \"Updated dep at 'lib/forge-std', (from: tag={}@{}, to: branch=master@{})\\n\",\n        forge_std.name(),\n        forge_std.rev(),\n        origin_master_head\n    );\n\n    cmd.forge_fuse()\n        .args([\"update\", \"foundry-rs/forge-std@master\"])\n        .assert_success()\n        .stdout_eq(expected_output);\n\n    let git = Git::new(&forge_std_path);\n    assert_eq!(\n        git.head().unwrap(),\n        origin_master_head,\n        \"Submodule HEAD should match resolved origin/master after update\"\n    );\n\n    let root_git = Git::new(prj.root());\n    let submodules_after = root_git.submodules().unwrap();\n    let forge_sm = submodules_after\n        .0\n        .iter()\n        .find(|s| s.path().as_path() == Path::new(\"lib/forge-std\"))\n        .expect(\"forge-std submodule should exist\");\n    assert_eq!(\n        forge_sm.rev(),\n        origin_master_head,\n        \"Root submodule status should match resolved origin/master after update\"\n    );\n\n    let mut lockfile = Lockfile::new(prj.root());\n    lockfile.read().unwrap();\n    let forge_std_after = lockfile.get(&PathBuf::from(\"lib/forge-std\")).unwrap();\n    assert_eq!(\n        forge_std_after.rev(),\n        origin_master_head,\n        \"Lockfile rev should match resolved origin/master after update\"\n    );\n});\n"
  },
  {
    "path": "crates/forge/tests/cli/json.rs",
    "content": "// tests enhanced `vm.parseJson` and `vm.serializeJson` cheatcodes, which are not constrained to\n// alphabetical ordering of struct keys, but rather respect the Solidity struct definition.\nforgetest_init!(test_parse_json, |prj, cmd| {\n    prj.add_test(\n        \"JsonCheats\",\n        r#\"\nimport {Test} from \"forge-std/Test.sol\";\n\n// Definition order: color, sweetness, sourness\n// Alphabetical order: color, sourness, sweetness\nstruct Apple {\n    string color;\n    uint8 sweetness;\n    uint8 sourness;\n}\n\n// Definition order: name, apples\n// Alphabetical order: apples, name\nstruct FruitStall {\n    string name;\n    Apple[] apples;\n}\n\ncontract SimpleJsonCheatsTest is Test {\n    function testJsonParseAndSerialize() public {\n        // Initial JSON has keys in a custom order, different from definition and alphabetical.\n        string memory originalJson =\n            '{\"name\":\"Fresh Fruit\",\"apples\":[{\"sweetness\":7,\"sourness\":3,\"color\":\"Red\"},{\"sweetness\":5,\"sourness\":5,\"color\":\"Green\"}]}';\n\n        // Parse the original JSON. The parser should correctly handle the unordered keys.\n        bytes memory decoded = vm.parseJson(originalJson);\n        FruitStall memory originalType = abi.decode(decoded, (FruitStall));\n\n        // Assert initial parsing is correct\n        assertEq(originalType.name, \"Fresh Fruit\");\n        assertEq(originalType.apples[0].color, \"Red\");\n        assertEq(originalType.apples[0].sweetness, 7);\n        assertEq(originalType.apples[1].sourness, 5);\n\n        // Serialize the struct back to JSON. `vm.serializeJson` should respect the order for all keys.\n        string memory serializedJson = vm.serializeJsonType(\n            \"FruitStall(Apple[] apples,string name)Apple(string color,uint8 sourness,uint8 sweetness)\",\n            abi.encode(originalType)\n        );\n\n        // The expected JSON should have keys ordered according to the struct definitions.\n        string memory expectedJson =\n            '{\"name\":\"Fresh Fruit\",\"apples\":[{\"color\":\"Red\",\"sweetness\":7,\"sourness\":3},{\"color\":\"Green\",\"sweetness\":5,\"sourness\":5}]}';\n        assertEq(serializedJson, expectedJson);\n\n        // Parse the newly serialized JSON to complete the cycle.\n        bytes memory redecoded = vm.parseJson(serializedJson);\n        FruitStall memory finalType = abi.decode(redecoded, (FruitStall));\n\n        // Assert that the struct from the full cycle is identical to the original parsed struct.\n        assertEq(keccak256(abi.encode(finalType)), keccak256(abi.encode(originalType)));\n    }\n}\n\"#,\n    );\n\n    // Directly run the test. No `bind-json` or type schemas are needed.\n    cmd.forge_fuse().args([\"test\"]).assert_success();\n    // Should still work when the project is not compiled.\n    cmd.forge_fuse().args([\"test\"]).assert_success();\n});\n"
  },
  {
    "path": "crates/forge/tests/cli/lint/geiger.rs",
    "content": "forgetest_init!(call, |prj, cmd| {\n    prj.add_test(\n        \"call.t.sol\",\n        r#\"\n        import {Test} from \"forge-std/Test.sol\";\n\n        contract A is Test {\n            function do_ffi() public {\n                string[] memory inputs = new string[](1);\n                vm.ffi(inputs);\n            }\n        }\n    \"#,\n    );\n\n    cmd.arg(\"geiger\").assert_failure().stderr_eq(str![[r#\"\n...\nnote[unsafe-cheatcode]: usage of unsafe cheatcodes that can perform dangerous operations\n  [FILE]:9:20\n  │\n9 │                 vm.ffi(inputs);\n  │                    ━━━\n  │\n  ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-cheatcode\n\nError: aborting due to 1 linter note(s)\n...\n\"#]]);\n});\n\nforgetest_init!(assignment, |prj, cmd| {\n    prj.add_test(\n        \"assignment.t.sol\",\n        r#\"\n        import {Test} from \"forge-std/Test.sol\";\n\n        contract A is Test {\n            function do_ffi() public returns (bytes memory) {\n                string[] memory inputs = new string[](1);\n                bytes memory stuff = vm.ffi(inputs);\n                return stuff;\n            }\n        }\n    \"#,\n    );\n\n    cmd.arg(\"geiger\").assert_failure().stderr_eq(str![[r#\"\n...\nnote[unsafe-cheatcode]: usage of unsafe cheatcodes that can perform dangerous operations\n  [FILE]:9:41\n  │\n9 │                 bytes memory stuff = vm.ffi(inputs);\n  │                                         ━━━\n  │\n  ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-cheatcode\n\nError: aborting due to 1 linter note(s)\n...\n\"#]]);\n});\n\nforgetest_init!(exit_code, |prj, cmd| {\n    prj.add_test(\n        \"multiple.t.sol\",\n        r#\"\n        import {Test} from \"forge-std/Test.sol\";\n\n        contract A is Test {\n            function do_ffi() public {\n                string[] memory inputs = new string[](1);\n                vm.ffi(inputs);\n                vm.ffi(inputs);\n                vm.ffi(inputs);\n            }\n        }\n    \"#,\n    );\n\n    cmd.arg(\"geiger\").assert_failure().stderr_eq(str![[r#\"\n...\nnote[unsafe-cheatcode]: usage of unsafe cheatcodes that can perform dangerous operations\n  [FILE]:9:20\n  │\n9 │                 vm.ffi(inputs);\n  │                    ━━━\n  │\n  ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-cheatcode\n\nnote[unsafe-cheatcode]: usage of unsafe cheatcodes that can perform dangerous operations\n   [FILE]:10:20\n   │\n10 │                 vm.ffi(inputs);\n   │                    ━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-cheatcode\n\nnote[unsafe-cheatcode]: usage of unsafe cheatcodes that can perform dangerous operations\n   [FILE]:11:20\n   │\n11 │                 vm.ffi(inputs);\n   │                    ━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-cheatcode\n\nError: aborting due to 3 linter note(s)\n...\n\"#]]);\n});\n"
  },
  {
    "path": "crates/forge/tests/cli/lint.rs",
    "content": "use forge_lint::{linter::Lint, sol::med::REGISTERED_LINTS};\nuse foundry_config::{\n    DenyLevel, LintSeverity, LinterConfig, SolidityErrorCode, lint::LintSpecificConfig,\n};\n\nmod geiger;\n\nconst CONTRACT: &str = r#\"\n// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nstruct _PascalCaseInfo { uint256 a; }\nuint256 constant screaming_snake_case_info = 0;\n\ncontract ContractWithLints {\n    uint256 VARIABLE_MIXED_CASE_INFO;\n\n    function incorrectShiftHigh() public {\n        uint256 localValue = 50;\n        uint256 result = 8 >> localValue;\n    }\n    function divideBeforeMultiplyMedium() public {\n        (1 / 2) * 3;\n    }\n    function unoptimizedHashGas(uint256 a, uint256 b) public view {\n        keccak256(abi.encodePacked(a, b));\n    }\n    function FUNCTION_MIXED_CASE_INFO() public {}\n}\n\"#;\n\nconst OTHER_CONTRACT: &str = r#\"\n// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n// forge-lint: disable-next-line\nimport { ContractWithLints } from \"./ContractWithLints.sol\";\n\ncontract OtherContractWithLints {\n    function functionMIXEDCaseInfo() public {}\n}\n\"#;\n\nconst ONLY_IMPORTS: &str = r#\"\n// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n// forge-lint: disable-next-line\nimport { ContractWithLints } from \"./ContractWithLints.sol\";\n\nimport { _PascalCaseInfo } from \"./ContractWithLints.sol\";\nimport \"./ContractWithLints.sol\";\n\ncontract Dummy {\n    bool foo;\n}\n\"#;\n\nconst COUNTER_A: &str = r#\"\n// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ncontract CounterA {\n    uint256 public CounterA_Fail_Lint;\n}\n\"#;\n\nconst COUNTER_B: &str = r#\"\n// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ncontract CounterB {\n    uint256 public CounterB_Fail_Lint;\n}\n\"#;\n\nconst COUNTER_WITH_CONST: &str = r#\"\n// SPDX-License-Identifier: MIT\npragma solidity ^0.8.13;\n\nuint256 constant MAX = 1000000;\n\ncontract Counter {\n    uint256 public number;\n\n    function setNumber(uint256 newNumber) public {\n        number = newNumber;\n    }\n\n    function increment() public {\n        number++;\n    }\n}\n\"#;\n\nconst COUNTER_TEST_WITH_CONST: &str = r#\"\n// SPDX-License-Identifier: MIT\npragma solidity ^0.8.13;\n\nimport { Counter, MAX } from \"../src/Counter.sol\";\n\ncontract CounterTest {\n  Counter public counter;\n\n  function setUp() public {\n    counter = new Counter();\n  }\n\n  function testFuzz_setNumber(uint256[MAX] calldata numbers) public {\n    for (uint256 i = 0; i < numbers.length; ++i) {\n      counter.setNumber(numbers[i]);\n    }\n  }\n}\n\"#;\n\nconst MULTI_CONTRACT_FILE: &str = r#\"\n// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IToken {\n    function transfer(address to, uint256 amount) external returns (bool);\n}\n\nlibrary MathLib {\n    function add(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a + b;\n    }\n}\n\ncontract FirstContract {\n    uint256 public value;\n    \n    function setValue(uint256 _value) public {\n        value = _value;\n    }\n}\n\nabstract contract BaseContract {\n    function baseFunction() public virtual;\n}\n\ninterface IERC20 {\n    function balanceOf(address account) external view returns (uint256);\n}\n\ncontract SecondContract {\n    address public owner;\n    \n    constructor() {\n        owner = msg.sender;\n    }\n}\n\nlibrary StringLib {\n    function toUpperCase(string memory str) internal pure returns (string memory) {\n        return str;\n    }\n}\n\nabstract contract AbstractStorage {\n    mapping(address => uint256) internal balances;\n    \n    function getBalance(address account) public view virtual returns (uint256);\n}\n\ninterface Token {\n    function transfer(address to, uint256 amount) external returns (bool);\n}\n\"#;\n\nconst SOLO_INTERFACES: &str = r#\"\n// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface ERC20 {\n    function balanceOf(address account) external view returns (uint256);\n}\n\ninterface IToken {\n    function transfer(address to, uint256 amount) external returns (bool);\n}\n\"#;\n\nforgetest!(can_use_config, |prj, cmd| {\n    prj.add_source(\"ContractWithLints\", CONTRACT);\n    prj.add_source(\"OtherContractWithLints\", OTHER_CONTRACT);\n\n    // Check config for `severity` and `exclude`\n    prj.update_config(|config| {\n        config.lint = LinterConfig {\n            severity: vec![LintSeverity::High, LintSeverity::Med],\n            exclude_lints: vec![\"incorrect-shift\".into()],\n            ignore: vec![],\n            lint_on_build: true,\n            ..Default::default()\n        };\n    });\n    cmd.arg(\"lint\").assert_success().stderr_eq(str![[r#\"\nwarning[divide-before-multiply]: multiplication should occur before division to avoid loss of precision\n   [FILE]:16:9\n   │\n16 │         (1 / 2) * 3;\n   │         ━━━━━━━━━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#divide-before-multiply\n\n\n\"#]]);\n});\n\nforgetest!(can_use_config_ignore, |prj, cmd| {\n    prj.add_source(\"ContractWithLints\", CONTRACT);\n    prj.add_source(\"OtherContract\", OTHER_CONTRACT);\n\n    // Check config for `ignore`\n    prj.update_config(|config| {\n        config.lint = LinterConfig {\n            severity: vec![],\n            exclude_lints: vec![],\n            ignore: vec![\"src/ContractWithLints.sol\".into()],\n            lint_on_build: true,\n            ..Default::default()\n        };\n    });\n    cmd.arg(\"lint\").assert_success().stderr_eq(str![[r#\"\nnote[mixed-case-function]: function names should use mixedCase\n  [FILE]:9:14\n  │\n9 │     function functionMIXEDCaseInfo() public {}\n  │              ━━━━━━━━━━━━━━━━━━━━━ help: consider using: `functionMixedCaseInfo`\n  │\n  ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-function\n\n\n\"#]]);\n\n    // Check config again, ignoring all files\n    prj.update_config(|config| {\n        config.lint = LinterConfig {\n            severity: vec![],\n            exclude_lints: vec![],\n            ignore: vec![\"src/ContractWithLints.sol\".into(), \"src/OtherContract.sol\".into()],\n            lint_on_build: true,\n            ..Default::default()\n        };\n    });\n    cmd.arg(\"lint\").assert_success().stderr_eq(str![[\"\"]]);\n});\n\nforgetest!(can_use_config_mixed_case_exception, |prj, cmd| {\n    prj.add_source(\"ContractWithLints\", CONTRACT);\n    prj.add_source(\"OtherContract\", OTHER_CONTRACT);\n\n    // Check config for `ignore`\n    prj.update_config(|config| {\n        config.lint = LinterConfig {\n            severity: vec![],\n            exclude_lints: vec![],\n            ignore: vec![\"src/ContractWithLints.sol\".into()],\n            lint_on_build: true,\n            lint_specific: LintSpecificConfig {\n                mixed_case_exceptions: vec![\"MIXED\".to_string()],\n                ..Default::default()\n            },\n        };\n    });\n    cmd.arg(\"lint\").assert_success().stderr_eq(str![[\"\"]]);\n});\n\nforgetest!(multi_contract_file_no_exceptions, |prj, cmd| {\n    prj.add_source(\"MixedFile\", MULTI_CONTRACT_FILE);\n\n    // Without exceptions, should flag all 8 contract-like items\n    prj.update_config(|config| {\n        config.lint = LinterConfig {\n            lint_on_build: true,\n            severity: vec![\n                LintSeverity::High,\n                LintSeverity::Med,\n                LintSeverity::Low,\n                LintSeverity::Info,\n            ],\n            ..Default::default()\n        };\n    });\n\n    let output = cmd.arg(\"lint\").assert_success();\n    let stderr = String::from_utf8_lossy(&output.get_output().stderr);\n\n    // Should see 9 instances of multi-contract-file lint\n    assert_eq!(stderr.matches(\"note[multi-contract-file]\").count(), 9);\n    assert!(stderr.contains(\"IToken\"));\n    assert!(stderr.contains(\"IERC20\"));\n    assert!(stderr.contains(\"Token\"));\n    assert!(stderr.contains(\"MathLib\"));\n    assert!(stderr.contains(\"StringLib\"));\n    assert!(stderr.contains(\"BaseContract\"));\n    assert!(stderr.contains(\"AbstractStorage\"));\n    assert!(stderr.contains(\"FirstContract\"));\n    assert!(stderr.contains(\"SecondContract\"));\n});\n\nforgetest!(multi_contract_file_interface_exception, |prj, cmd| {\n    use foundry_config::lint::ContractException;\n\n    prj.add_source(\"MixedFile\", MULTI_CONTRACT_FILE);\n\n    // With interface exception, should flag 6 items\n    prj.update_config(|config| {\n        config.lint = LinterConfig {\n            lint_on_build: true,\n            severity: vec![\n                LintSeverity::High,\n                LintSeverity::Med,\n                LintSeverity::Low,\n                LintSeverity::Info,\n            ],\n            exclude_lints: vec![\"interface-naming\".into()],\n            lint_specific: LintSpecificConfig {\n                multi_contract_file_exceptions: vec![ContractException::Interface],\n                ..Default::default()\n            },\n            ..Default::default()\n        };\n    });\n\n    let output = cmd.arg(\"lint\").assert_success();\n    let stderr = String::from_utf8_lossy(&output.get_output().stderr);\n\n    // Should see 6 instances (3 interfaces excluded: IToken, IERC20, Token)\n    assert_eq!(stderr.matches(\"note[multi-contract-file]\").count(), 6);\n    assert!(!stderr.contains(\"IToken\"));\n    assert!(!stderr.contains(\"IERC20\"));\n    assert!(!stderr.contains(\"Token\"));\n    assert!(stderr.contains(\"MathLib\"));\n    assert!(stderr.contains(\"FirstContract\"));\n});\n\nforgetest!(multi_contract_file_library_exception, |prj, cmd| {\n    use foundry_config::lint::ContractException;\n\n    prj.add_source(\"MixedFile\", MULTI_CONTRACT_FILE);\n\n    // With library exception, should flag 7 items\n    prj.update_config(|config| {\n        config.lint = LinterConfig {\n            lint_on_build: true,\n            severity: vec![\n                LintSeverity::High,\n                LintSeverity::Med,\n                LintSeverity::Low,\n                LintSeverity::Info,\n            ],\n            lint_specific: LintSpecificConfig {\n                multi_contract_file_exceptions: vec![ContractException::Library],\n                ..Default::default()\n            },\n            ..Default::default()\n        };\n    });\n\n    let output = cmd.arg(\"lint\").assert_success();\n    let stderr = String::from_utf8_lossy(&output.get_output().stderr);\n\n    // Should see 7 instances (2 libraries excluded)\n    assert_eq!(stderr.matches(\"note[multi-contract-file]\").count(), 7);\n    assert!(stderr.contains(\"IToken\"));\n    assert!(!stderr.contains(\"MathLib\"));\n    assert!(!stderr.contains(\"StringLib\"));\n    assert!(stderr.contains(\"FirstContract\"));\n});\n\nforgetest!(multi_contract_file_abstract_exception, |prj, cmd| {\n    use foundry_config::lint::ContractException;\n\n    prj.add_source(\"MixedFile\", MULTI_CONTRACT_FILE);\n\n    // With abstract contract exception, should flag 7 items\n    prj.update_config(|config| {\n        config.lint = LinterConfig {\n            lint_on_build: true,\n            severity: vec![\n                LintSeverity::High,\n                LintSeverity::Med,\n                LintSeverity::Low,\n                LintSeverity::Info,\n            ],\n            lint_specific: LintSpecificConfig {\n                multi_contract_file_exceptions: vec![ContractException::AbstractContract],\n                ..Default::default()\n            },\n            ..Default::default()\n        };\n    });\n\n    let output = cmd.arg(\"lint\").assert_success();\n    let stderr = String::from_utf8_lossy(&output.get_output().stderr);\n\n    // Should see 7 instances (2 abstract contracts excluded)\n    assert_eq!(stderr.matches(\"note[multi-contract-file]\").count(), 7);\n    assert!(stderr.contains(\"IToken\"));\n    assert!(stderr.contains(\"MathLib\"));\n    assert!(stderr.contains(\"FirstContract\"));\n    assert!(!stderr.contains(\"BaseContract\"));\n    assert!(!stderr.contains(\"AbstractStorage\"));\n});\n\nforgetest!(multi_contract_file_multiple_exceptions, |prj, cmd| {\n    use foundry_config::lint::ContractException;\n\n    prj.add_source(\"MixedFile\", MULTI_CONTRACT_FILE);\n\n    // With interface + library exceptions, should flag 4 items\n    prj.update_config(|config| {\n        config.lint = LinterConfig {\n            lint_on_build: true,\n            severity: vec![\n                LintSeverity::High,\n                LintSeverity::Med,\n                LintSeverity::Low,\n                LintSeverity::Info,\n            ],\n            exclude_lints: vec![\"interface-naming\".into()],\n            lint_specific: LintSpecificConfig {\n                multi_contract_file_exceptions: vec![\n                    ContractException::Interface,\n                    ContractException::Library,\n                ],\n                ..Default::default()\n            },\n            ..Default::default()\n        };\n    });\n\n    let output = cmd.arg(\"lint\").assert_success();\n    let stderr = String::from_utf8_lossy(&output.get_output().stderr);\n\n    // Should see 4 instances (3 interfaces + 2 libraries excluded)\n    assert_eq!(stderr.matches(\"note[multi-contract-file]\").count(), 4);\n    assert!(!stderr.contains(\"IToken\"));\n    assert!(!stderr.contains(\"IERC20\"));\n    assert!(!stderr.contains(\"Token\"));\n    assert!(!stderr.contains(\"MathLib\"));\n    assert!(stderr.contains(\"BaseContract\"));\n    assert!(stderr.contains(\"FirstContract\"));\n});\n\nforgetest!(multi_contract_file_all_exceptions, |prj, cmd| {\n    use foundry_config::lint::ContractException;\n\n    prj.add_source(\"MixedFile\", MULTI_CONTRACT_FILE);\n\n    // With all exceptions, should still flag 2 regular contracts\n    prj.update_config(|config| {\n        config.lint = LinterConfig {\n            lint_on_build: true,\n            severity: vec![\n                LintSeverity::High,\n                LintSeverity::Med,\n                LintSeverity::Low,\n                LintSeverity::Info,\n            ],\n            lint_specific: LintSpecificConfig {\n                multi_contract_file_exceptions: vec![\n                    ContractException::Interface,\n                    ContractException::Library,\n                    ContractException::AbstractContract,\n                ],\n                ..Default::default()\n            },\n            ..Default::default()\n        };\n    });\n\n    let output = cmd.arg(\"lint\").assert_success();\n    let stderr = String::from_utf8_lossy(&output.get_output().stderr);\n\n    // Should see 2 instances (only the 2 regular contracts)\n    assert_eq!(stderr.matches(\"note[multi-contract-file]\").count(), 2);\n    assert!(!stderr.contains(\"IToken\"));\n    assert!(!stderr.contains(\"MathLib\"));\n    assert!(!stderr.contains(\"BaseContract\"));\n    assert!(stderr.contains(\"FirstContract\"));\n    assert!(stderr.contains(\"SecondContract\"));\n});\n\nforgetest!(multi_contract_file_invalid_toml_value, |prj, cmd| {\n    use std::fs;\n\n    prj.add_source(\"Simple\", \"contract Simple {}\");\n\n    // Write invalid TOML config with invalid enum value\n    let config_path = prj.root().join(\"foundry.toml\");\n    let invalid_config = r#\"\n[profile.default]\nsrc = \"src\"\nout = \"out\"\nlibs = [\"lib\"]\n\n[profile.default.lint.lint_specific]\nmulti_contract_file_exceptions = [\"interface\", \"bad_contract_type\", \"library\"]\n\"#;\n\n    fs::write(&config_path, invalid_config).unwrap();\n\n    // Should fail with deserialization error\n    let output = cmd.arg(\"lint\").assert_failure();\n    let stderr = String::from_utf8_lossy(&output.get_output().stderr);\n\n    // Assert specific error message for invalid enum variant\n    assert!(stderr.contains(\"unknown variant\"));\n    assert!(stderr.contains(\"expected `one of `interface`, `library`, `abstract_contract`\"));\n});\n\nforgetest!(multi_contract_file_valid_toml_values, |prj, cmd| {\n    use std::fs;\n\n    prj.add_source(\"MixedFile\", MULTI_CONTRACT_FILE);\n\n    // Write valid TOML config with all valid enum values\n    let config_path = prj.root().join(\"foundry.toml\");\n    let valid_config = r#\"\n[profile.default]\nsrc = \"src\"\nout = \"out\"\nlibs = [\"lib\"]\n\n[profile.default.lint]\nlint_on_build = true\nseverity = [\"high\", \"medium\", \"low\", \"info\"]\n\n[profile.default.lint.lint_specific]\nmulti_contract_file_exceptions = [\"interface\", \"library\", \"abstract_contract\"]\n\"#;\n\n    fs::write(&config_path, valid_config).unwrap();\n\n    // Should succeed and only flag the 2 regular contracts\n    let output = cmd.arg(\"lint\").assert_success();\n    let stderr = String::from_utf8_lossy(&output.get_output().stderr);\n\n    assert_eq!(stderr.matches(\"note[multi-contract-file]\").count(), 2);\n    assert!(stderr.contains(\"FirstContract\"));\n    assert!(stderr.contains(\"SecondContract\"));\n});\n\nforgetest!(interface_naming_fails_for_non_prefixed, |prj, cmd| {\n    prj.add_source(\"MixedFile\", MULTI_CONTRACT_FILE);\n\n    prj.update_config(|config| {\n        config.lint = LinterConfig {\n            severity: vec![],\n            exclude_lints: vec![\"multi-contract-file\".into()],\n            ignore: vec![],\n            lint_on_build: true,\n            ..Default::default()\n        };\n    });\n\n    let output = cmd.arg(\"lint\").assert_success();\n    let stderr = String::from_utf8_lossy(&output.get_output().stderr);\n\n    // Should flag only the interface that doesn't start with 'I': Token\n    assert_eq!(stderr.matches(\"note[interface-naming]\").count(), 1);\n    assert!(stderr.contains(\"Token\"));\n});\n\nforgetest!(interface_file_naming_fails_for_non_prefixed_file, |prj, cmd| {\n    prj.add_source(\"SoloInterfaces\", SOLO_INTERFACES);\n\n    prj.update_config(|config| {\n        config.lint = LinterConfig {\n            severity: vec![],\n            exclude_lints: vec![\"multi-contract-file\".into()],\n            ignore: vec![],\n            lint_on_build: true,\n            ..Default::default()\n        };\n    });\n\n    let output = cmd.arg(\"lint\").assert_success();\n    let stderr = String::from_utf8_lossy(&output.get_output().stderr);\n\n    // File name \"SoloInterfaces\" doesn't start with 'I', so interface-file-naming should trigger\n    assert_eq!(stderr.matches(\"note[interface-file-naming]\").count(), 1);\n    // ERC20 is not prefixed with 'I', so interface-naming should trigger\n    assert_eq!(stderr.matches(\"note[interface-naming]\").count(), 1);\n    assert!(stderr.contains(\"ERC20\"));\n});\n\nforgetest!(can_override_config_severity, |prj, cmd| {\n    prj.add_source(\"ContractWithLints\", CONTRACT);\n    prj.add_source(\"OtherContractWithLints\", OTHER_CONTRACT);\n\n    // Override severity\n    prj.update_config(|config| {\n        config.lint = LinterConfig {\n            severity: vec![LintSeverity::High, LintSeverity::Med],\n            exclude_lints: vec![],\n            ignore: vec![\"src/ContractWithLints.sol\".into()],\n            lint_on_build: true,\n            ..Default::default()\n        };\n    });\n    cmd.arg(\"lint\").args([\"--severity\", \"info\"]).assert_success().stderr_eq(str![[r#\"\nnote[mixed-case-function]: function names should use mixedCase\n  [FILE]:9:14\n  │\n9 │     function functionMIXEDCaseInfo() public {}\n  │              ━━━━━━━━━━━━━━━━━━━━━ help: consider using: `functionMixedCaseInfo`\n  │\n  ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-function\n\n\n\"#]]);\n});\n\nforgetest!(can_override_config_path, |prj, cmd| {\n    prj.add_source(\"ContractWithLints\", CONTRACT);\n    prj.add_source(\"OtherContractWithLints\", OTHER_CONTRACT);\n\n    // Override excluded files\n    prj.update_config(|config| {\n        config.lint = LinterConfig {\n            severity: vec![LintSeverity::High, LintSeverity::Med],\n            exclude_lints: vec![\"incorrect-shift\".into()],\n            ignore: vec![\"src/ContractWithLints.sol\".into()],\n            lint_on_build: true,\n            ..Default::default()\n        };\n    });\n    cmd.arg(\"lint\").arg(\"src/ContractWithLints.sol\").assert_success().stderr_eq(str![[r#\"\nwarning[divide-before-multiply]: multiplication should occur before division to avoid loss of precision\n   [FILE]:16:9\n   │\n16 │         (1 / 2) * 3;\n   │         ━━━━━━━━━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#divide-before-multiply\n\n\n\"#]]);\n});\n\nforgetest!(can_override_config_lint, |prj, cmd| {\n    prj.add_source(\"ContractWithLints\", CONTRACT);\n    prj.add_source(\"OtherContractWithLints\", OTHER_CONTRACT);\n\n    // Override excluded lints\n    prj.update_config(|config| {\n        config.lint = LinterConfig {\n            severity: vec![LintSeverity::High, LintSeverity::Med],\n            exclude_lints: vec![\"incorrect-shift\".into()],\n            ignore: vec![],\n            lint_on_build: true,\n            ..Default::default()\n        };\n    });\n    cmd.arg(\"lint\").args([\"--only-lint\", \"incorrect-shift\"]).assert_success().stderr_eq(str![[\n        r#\"\nwarning[incorrect-shift]: the order of args in a shift operation is incorrect\n   [FILE]:13:26\n   │\n13 │         uint256 result = 8 >> localValue;\n   │                          ━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#incorrect-shift\n\n\n\"#\n    ]]);\n});\n\nforgetest!(build_runs_linter_by_default, |prj, cmd| {\n    prj.add_source(\"ContractWithLints\", CONTRACT);\n\n    // Configure linter to show only medium severity lints\n    prj.update_config(|config| {\n        config.lint = LinterConfig {\n            severity: vec![LintSeverity::Med],\n            exclude_lints: vec![\"incorrect-shift\".into()],\n            ignore: vec![],\n            lint_on_build: true,\n            ..Default::default()\n        };\n    });\n\n    // Run forge build and expect linting output before compilation\n    cmd.arg(\"build\").assert_success().stderr_eq(str![[r#\"\nwarning[divide-before-multiply]: multiplication should occur before division to avoid loss of precision\n   [FILE]:16:9\n   │\n16 │         (1 / 2) * 3;\n   │         ━━━━━━━━━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#divide-before-multiply\n\n\n\"#]]).stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful with warnings:\nWarning (2072): Unused local variable.\n  [FILE]:13:9:\n   |\n13 |         uint256 result = 8 >> localValue;\n   |         ^^^^^^^^^^^^^^\n\nWarning (6133): Statement has no effect.\n  [FILE]:16:9:\n   |\n16 |         (1 / 2) * 3;\n   |         ^^^^^^^^^^^\n\nWarning (2018): Function state mutability can be restricted to pure\n  [FILE]:11:5:\n   |\n11 |     function incorrectShiftHigh() public {\n   |     ^ (Relevant source part starts here and spans across multiple lines).\n\nWarning (2018): Function state mutability can be restricted to pure\n  [FILE]:15:5:\n   |\n15 |     function divideBeforeMultiplyMedium() public {\n   |     ^ (Relevant source part starts here and spans across multiple lines).\n\nWarning (2018): Function state mutability can be restricted to pure\n  [FILE]:18:5:\n   |\n18 |     function unoptimizedHashGas(uint256 a, uint256 b) public view {\n   |     ^ (Relevant source part starts here and spans across multiple lines).\n\n\n\"#]]);\n});\n\nforgetest!(build_respects_quiet_flag_for_linting, |prj, cmd| {\n    prj.add_source(\"ContractWithLints\", CONTRACT);\n\n    // Configure linter to show medium severity lints\n    prj.update_config(|config| {\n        config.lint = LinterConfig {\n            severity: vec![LintSeverity::Med],\n            exclude_lints: vec![\"incorrect-shift\".into()],\n            ignore: vec![],\n            lint_on_build: true,\n            ..Default::default()\n        };\n    });\n\n    // Run forge build with --quiet flag - should not show linting output\n    cmd.arg(\"build\").arg(\"--quiet\").assert_success().stderr_eq(str![[\"\"]]).stdout_eq(str![[\"\"]]);\n});\n\nforgetest!(build_with_json_uses_json_linter_output, |prj, cmd| {\n    prj.add_source(\"ContractWithLints\", CONTRACT);\n\n    // Configure linter to show medium severity lints\n    prj.update_config(|config| {\n        config.lint = LinterConfig {\n            severity: vec![LintSeverity::Med],\n            exclude_lints: vec![\"incorrect-shift\".into()],\n            ignore: vec![],\n            lint_on_build: true,\n            ..Default::default()\n        };\n    });\n\n    // Run forge build with --json flag - should use JSON formatter for linting\n    let output = cmd.arg(\"build\").arg(\"--json\").assert_success();\n\n    // Should contain JSON linting output\n    let stderr = String::from_utf8_lossy(&output.get_output().stderr);\n    assert!(stderr.contains(\"\\\"code\\\"\"));\n    assert!(stderr.contains(\"divide-before-multiply\"));\n\n    // Should also contain JSON compilation output\n    let stdout = String::from_utf8_lossy(&output.get_output().stdout);\n    assert!(stdout.contains(\"\\\"errors\\\"\"));\n    assert!(stdout.contains(\"\\\"sources\\\"\"));\n});\n\nforgetest!(build_respects_lint_on_build_false, |prj, cmd| {\n    prj.add_source(\"ContractWithLints\", CONTRACT);\n\n    // Configure linter with medium severity lints but disable lint_on_build\n    prj.update_config(|config| {\n        config.lint = LinterConfig {\n            severity: vec![LintSeverity::Med],\n            exclude_lints: vec![\"incorrect-shift\".into()],\n            ignore: vec![],\n            lint_on_build: false,\n            ..Default::default()\n        };\n    });\n\n    // Run forge build - should NOT show linting output because lint_on_build is false\n    cmd.arg(\"build\").assert_success().stderr_eq(str![[\"\"]]).stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful with warnings:\nWarning (2072): Unused local variable.\n  [FILE]:13:9:\n   |\n13 |         uint256 result = 8 >> localValue;\n   |         ^^^^^^^^^^^^^^\n\nWarning (6133): Statement has no effect.\n  [FILE]:16:9:\n   |\n16 |         (1 / 2) * 3;\n   |         ^^^^^^^^^^^\n\nWarning (2018): Function state mutability can be restricted to pure\n  [FILE]:11:5:\n   |\n11 |     function incorrectShiftHigh() public {\n   |     ^ (Relevant source part starts here and spans across multiple lines).\n\nWarning (2018): Function state mutability can be restricted to pure\n  [FILE]:15:5:\n   |\n15 |     function divideBeforeMultiplyMedium() public {\n   |     ^ (Relevant source part starts here and spans across multiple lines).\n\nWarning (2018): Function state mutability can be restricted to pure\n  [FILE]:18:5:\n   |\n18 |     function unoptimizedHashGas(uint256 a, uint256 b) public view {\n   |     ^ (Relevant source part starts here and spans across multiple lines).\n\n\n\"#]]);\n});\n\nforgetest!(can_process_inline_config_regardless_of_input_order, |prj, cmd| {\n    prj.add_source(\"ContractWithLints\", CONTRACT);\n    prj.add_source(\"OtherContractWithLints\", OTHER_CONTRACT);\n    cmd.arg(\"lint\").assert_success();\n\n    prj.add_source(\"OtherContractWithLints\", OTHER_CONTRACT);\n    prj.add_source(\"ContractWithLints\", CONTRACT);\n    cmd.arg(\"lint\").assert_success();\n});\n\n// <https://github.com/foundry-rs/foundry/issues/11080>\nforgetest!(can_use_only_lint_with_multilint_passes, |prj, cmd| {\n    prj.add_source(\"ContractWithLints\", CONTRACT);\n    prj.add_source(\"OnlyImports\", ONLY_IMPORTS);\n    cmd.arg(\"lint\").args([\"--only-lint\", \"unused-import\"]).assert_success().stderr_eq(str![[r#\"\nnote[unused-import]: unused imports should be removed\n  [FILE]:8:10\n  │\n8 │ import { _PascalCaseInfo } from \"./ContractWithLints.sol\";\n  │          ━━━━━━━━━━━━━━━\n  │\n  ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unused-import\n\n\n\"#]]);\n});\n\n// <https://github.com/foundry-rs/foundry/issues/11234>\nforgetest!(can_lint_only_built_files, |prj, cmd| {\n    prj.add_source(\"CounterAWithLints\", COUNTER_A);\n    prj.add_source(\"CounterBWithLints\", COUNTER_B);\n\n    prj.update_config(|config| {\n        config.lint.severity = vec![LintSeverity::Info];\n    });\n\n    // Both contracts should be linted on build. Redact contract as order is not guaranteed.\n    cmd.forge_fuse().args([\"build\"]).assert_success().stderr_eq(str![[r#\"\nnote[mixed-case-variable]: mutable variables should use mixedCase\n...\nnote[mixed-case-variable]: mutable variables should use mixedCase\n...\n\"#]]);\n\n    // Only contract CounterBWithLints that we build should be linted.\n    let args = [\"build\", \"src/CounterBWithLints.sol\"];\n    cmd.forge_fuse().args(args).assert_success().stderr_eq(str![[r#\"\nnote[mixed-case-variable]: mutable variables should use mixedCase\n  [FILE]:6:20\n  │\n6 │     uint256 public CounterB_Fail_Lint;\n  │                    ━━━━━━━━━━━━━━━━━━ help: consider using: `counterBFailLint`\n  │\n  ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable\n\n\n\"#]]);\n});\n\n// <https://github.com/foundry-rs/foundry/issues/11392>\nforgetest!(can_lint_param_constants, |prj, cmd| {\n    prj.add_source(\"Counter\", COUNTER_WITH_CONST);\n    prj.add_test(\"CounterTest\", COUNTER_TEST_WITH_CONST);\n\n    cmd.forge_fuse().args([\"build\"]).assert_success().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\n\"#]]);\n});\n\n// <https://github.com/foundry-rs/foundry/issues/11460>\nforgetest!(lint_json_output_no_ansi_escape_codes, |prj, cmd| {\n    prj.add_source(\n        \"UnwrappedModifierTest\",\n        r#\"\n        // SPDX-License-Identifier: MIT\n        pragma solidity ^0.8.0;\n\n        contract UnwrappedModifierTest {\n            mapping(address => bool) isOwner;\n\n            modifier onlyOwner() {\n                require(isOwner[msg.sender], \"Not owner\");\n                require(msg.sender != address(0), \"Zero address\");\n                _;\n            }\n\n            function doSomething() public onlyOwner {}\n        }\n            \"#,\n    );\n\n    prj.update_config(|config| {\n        config.lint = LinterConfig {\n            severity: vec![LintSeverity::CodeSize],\n            exclude_lints: vec![],\n            ignore: vec![],\n            lint_on_build: true,\n            ..Default::default()\n        };\n    });\n\n    // should produce clean JSON without ANSI escape sequences (for the url nor the snippets)\n    cmd.arg(\"lint\").arg(\"--json\").assert_json_stderr(true,\n        str![[r#\"\n{\n    \"$message_type\": \"diagnostic\",\n    \"message\": \"wrap modifier logic to reduce code size\",\n    \"code\": {\n    \"code\": \"unwrapped-modifier-logic\",\n    \"explanation\": null\n    },\n    \"level\": \"note\",\n    \"spans\": [\n    {\n        \"file_name\": \"src/UnwrappedModifierTest.sol\",\n        \"byte_start\": 174,\n        \"byte_end\": 355,\n        \"line_start\": 8,\n        \"line_end\": 12,\n        \"column_start\": 13,\n        \"column_end\": 14,\n        \"is_primary\": true,\n        \"text\": [\n        {\n            \"text\": \"            modifier onlyOwner() {\",\n            \"highlight_start\": 13,\n            \"highlight_end\": 35\n        },\n        {\n            \"text\": \"                require(isOwner[msg.sender], \\\"Not owner\\\");\",\n            \"highlight_start\": 1,\n            \"highlight_end\": 59\n        },\n        {\n            \"text\": \"                require(msg.sender != address(0), \\\"Zero address\\\");\",\n            \"highlight_start\": 1,\n            \"highlight_end\": 67\n        },\n        {\n            \"text\": \"                _;\",\n            \"highlight_start\": 1,\n            \"highlight_end\": 19\n        },\n        {\n            \"text\": \"            }\",\n            \"highlight_start\": 1,\n            \"highlight_end\": 14\n        }\n        ],\n        \"label\": null,\n        \"suggested_replacement\": null\n    }\n    ],\n    \"children\": [\n    {\n        \"message\": \"https://book.getfoundry.sh/reference/forge/forge-lint#unwrapped-modifier-logic\",\n        \"code\": null,\n        \"level\": \"help\",\n        \"spans\": [],\n        \"children\": [],\n        \"rendered\": null\n    },\n    {\n        \"message\": \"wrap modifier logic to reduce code size\",\n        \"code\": null,\n        \"level\": \"help\",\n        \"spans\": [\n        {\n            \"file_name\": \"src/UnwrappedModifierTest.sol\",\n            \"byte_start\": 174,\n            \"byte_end\": 355,\n            \"line_start\": 8,\n            \"line_end\": 12,\n            \"column_start\": 13,\n            \"column_end\": 14,\n            \"is_primary\": true,\n            \"text\": [\n            {\n                \"text\": \"            modifier onlyOwner() {\",\n                \"highlight_start\": 13,\n                \"highlight_end\": 35\n            },\n            {\n                \"text\": \"                require(isOwner[msg.sender], \\\"Not owner\\\");\",\n                \"highlight_start\": 1,\n                \"highlight_end\": 59\n            },\n            {\n                \"text\": \"                require(msg.sender != address(0), \\\"Zero address\\\");\",\n                \"highlight_start\": 1,\n                \"highlight_end\": 67\n            },\n            {\n                \"text\": \"                _;\",\n                \"highlight_start\": 1,\n                \"highlight_end\": 19\n            },\n            {\n                \"text\": \"            }\",\n                \"highlight_start\": 1,\n                \"highlight_end\": 14\n            }\n            ],\n            \"label\": null,\n            \"suggested_replacement\": \"modifier onlyOwner() {\\n                _onlyOwner();\\n                _;\\n            }\\n\\n            function _onlyOwner() internal {\\n                require(isOwner[msg.sender], \\\"Not owner\\\");\\n                require(msg.sender != address(0), \\\"Zero address\\\");\\n            }\"\n        }\n        ],\n        \"children\": [],\n        \"rendered\": null\n    }\n    ],\n    \"rendered\": \"note[unwrapped-modifier-logic]: wrap modifier logic to reduce code size\\n\\nhelp: wrap modifier logic to reduce code size\\n 9 +                 _onlyOwner();\\n10 +                 _;\\n11 +             }\\n12 + \\n13 +             function _onlyOwner() internal {\\n14 +                 require(isOwner[msg.sender], \\\"Not owner\\\");\\n15 +                 require(msg.sender != address(0), \\\"Zero address\\\");\\n16 +             }\\n   ╭▸ src/UnwrappedModifierTest.sol:8:13\\n   │\\n 8 │ ┏             modifier onlyOwner() {\\n 9 │ ┃                 require(isOwner[msg.sender], \\\"Not owner\\\");\\n10 │ ┃                 require(msg.sender != address(0), \\\"Zero address\\\");\\n11 │ ┃                 _;\\n12 │ ┃             }\\n   │ ┗━━━━━━━━━━━━━┛\\n   │\\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unwrapped-modifier-logic\\n   ╭╴\\n 8 ±             modifier onlyOwner() {\\n   ╰╴\\n\"\n}\n\"#]],\n);\n});\n\nforgetest!(can_fail_on_lints, |prj, cmd| {\n    prj.add_source(\"ContractWithLints\", CONTRACT);\n\n    // -- LINT ALL SEVERITIES [OUTPUT: WARN + NOTE] ----------------------------\n\n    cmd.forge_fuse().arg(\"lint\").assert_success(); // DenyLevel::Never (default)\n\n    prj.update_config(|config| {\n        config.deny = DenyLevel::Warnings;\n    });\n    cmd.forge_fuse().arg(\"lint\").assert_failure();\n\n    prj.update_config(|config| {\n        config.deny = DenyLevel::Notes;\n    });\n    cmd.forge_fuse().arg(\"lint\").assert_failure();\n\n    // cmd flags can override config\n    prj.update_config(|config| {\n        config.deny = DenyLevel::Never;\n    });\n    cmd.forge_fuse().args([\"lint\", \"--deny warnings\"]).assert_failure();\n    cmd.forge_fuse().args([\"lint\", \"--deny notes\"]).assert_failure();\n\n    // usage of `--deny-warnings` flag works, but emits a warning\n    cmd.forge_fuse().args([\"lint\", \"--deny-warnings\"]).assert_failure().stderr_eq(str![[r#\"\nWarning: `--deny-warnings` is being deprecated in favor of `--deny warnings`.\n...\n\n\"#]]);\n\n    // usage of `deny_warnings` config works, but emits a warning\n    prj.create_file(\n        \"foundry.toml\",\n        r#\"\n[profile.default]\ndeny_warnings = true\n\"#,\n    );\n    cmd.forge_fuse().arg(\"lint\").assert_failure().stderr_eq(str![[r#\"\nWarning: Key `deny_warnings` is being deprecated in favor of `deny = warnings`. It will be removed in future versions.\n...\n\n\"#]]);\n\n    // -- ONLY LINT LOW SEVERITIES [OUTPUT: NOTE] ------------------------------\n\n    prj.update_config(|config| {\n        config.deny_warnings = false;\n        config.deny = DenyLevel::Never;\n        config.lint.severity = vec![LintSeverity::Info, LintSeverity::Gas, LintSeverity::CodeSize];\n    });\n    cmd.forge_fuse().arg(\"lint\").assert_success();\n\n    prj.update_config(|config| {\n        config.deny = DenyLevel::Warnings;\n    });\n    cmd.forge_fuse().arg(\"lint\").assert_success();\n\n    prj.update_config(|config| {\n        config.deny = DenyLevel::Notes;\n    });\n    cmd.forge_fuse().arg(\"lint\").assert_failure();\n\n    // cmd flags can override config\n    prj.update_config(|config| {\n        config.deny = DenyLevel::Never;\n    });\n    cmd.forge_fuse().args([\"lint\", \"--deny notes\"]).assert_failure();\n});\n\n// ------------------------------------------------------------------------------------------------\n\n#[tokio::test]\nasync fn ensure_lint_rule_docs() {\n    const FOUNDRY_BOOK_LINT_PAGE_URL: &str = \"https://book.getfoundry.sh/forge/linting\";\n\n    // Fetch the content of the lint reference\n    let content = match reqwest::get(FOUNDRY_BOOK_LINT_PAGE_URL).await {\n        Ok(resp) => {\n            if !resp.status().is_success() {\n                panic!(\n                    \"Failed to fetch Foundry Book lint page ({FOUNDRY_BOOK_LINT_PAGE_URL}). Status: {status}\",\n                    status = resp.status()\n                );\n            }\n            match resp.text().await {\n                Ok(text) => text,\n                Err(e) => {\n                    panic!(\"Failed to read response text: {e}\");\n                }\n            }\n        }\n        Err(e) => {\n            panic!(\"Failed to fetch Foundry Book lint page ({FOUNDRY_BOOK_LINT_PAGE_URL}): {e}\",);\n        }\n    };\n\n    // Ensure no missing lints\n    let mut missing_lints = Vec::new();\n    for lint in REGISTERED_LINTS {\n        let selector = lint.id().to_lowercase();\n        let selector_with_space = selector.replace(\"-\", \" \");\n        if !content.to_lowercase().contains(&selector)\n            && !content.to_lowercase().contains(&selector_with_space)\n        {\n            missing_lints.push(lint.id());\n        }\n    }\n\n    if !missing_lints.is_empty() {\n        let mut msg = String::from(\n            \"Foundry Book lint validation failed. The following lints must be added to the docs:\\n\",\n        );\n        for lint in missing_lints {\n            msg.push_str(&format!(\"  - {lint}\\n\"));\n        }\n        msg.push_str(\"Please open a PR: https://github.com/foundry-rs/book\");\n        panic!(\"{msg}\");\n    }\n}\n\n#[test]\nfn ensure_no_privileged_lint_id() {\n    for lint in REGISTERED_LINTS {\n        assert_ne!(lint.id(), \"all\", \"lint-id 'all' is reserved. Please use a different id\");\n    }\n}\n\n// <https://github.com/foundry-rs/foundry/issues/13107>\nforgetest!(dependency_warnings_do_not_affect_lint_exit_code, |prj, cmd| {\n    // Library with code that triggers a solc warning (unused local variable)\n    const LIB_WITH_WARNING: &str = r#\"\n// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nlibrary LibWithWarning {\n    function foo() internal pure returns (uint256) {\n        uint256 unusedVar = 42;\n        return 1;\n    }\n}\n\"#;\n\n    // Clean contract that imports the library but has no lint issues\n    const CLEAN_CONTRACT: &str = r#\"\n// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { LibWithWarning } from \"../lib/LibWithWarning.sol\";\n\ncontract CleanContract {\n    function bar() public pure returns (uint256) {\n        return LibWithWarning.foo();\n    }\n}\n\"#;\n\n    prj.add_lib(\"LibWithWarning\", LIB_WITH_WARNING);\n    prj.add_source(\"CleanContract\", CLEAN_CONTRACT);\n\n    // Ignore the solc warning so compilation succeeds, but it still gets counted in diagnostics\n    prj.update_config(|config| {\n        config.ignored_error_codes = vec![SolidityErrorCode::UnusedLocalVariable];\n    });\n\n    // Clear cache to force recompilation during lint\n    prj.clear_cache();\n\n    // Lint with deny = notes via CLI flag.\n    // Should succeed because the linter only counts lint diagnostics, not build-phase warnings.\n    cmd.args([\"lint\", \"-D\", \"notes\"]).assert_success();\n});\n\nforgetest!(skips_linting_for_old_solidity_versions, |prj, cmd| {\n    const OLD_CONTRACT: &str = r#\"\n// SPDX-License-Identifier: MIT\npragma solidity ^0.7.0;\n\ncontract OldContract {\n    uint256 VARIABLE_MIXED_CASE_INFO;\n\n    function FUNCTION_MIXED_CASE_INFO() public {}\n}\n\"#;\n\n    // Add a contract with Solidity 0.7.x which has lint issues\n    prj.add_source(\"OldContract\", OLD_CONTRACT);\n    prj.update_config(|config| {\n        config.lint = LinterConfig {\n            severity: vec![],\n            exclude_lints: vec![],\n            ignore: vec![],\n            lint_on_build: true,\n            ..Default::default()\n        };\n    });\n\n    // Run forge build - should SUCCEED without linting\n    cmd.arg(\"build\").assert_success().stderr_eq(str![[\n        r#\"Warning: unable to lint. Solar only supports Solidity versions >=0.8.0\n\n\"#\n    ]]);\n\n    // Run forge lint - should FAIL\n    cmd.forge_fuse().arg(\"lint\").assert_failure().stderr_eq(str![[\n        r#\"Error: unable to lint. Solar only supports Solidity versions >=0.8.0\n\n\"#\n    ]]);\n});\n"
  },
  {
    "path": "crates/forge/tests/cli/main.rs",
    "content": "#[macro_use]\nextern crate foundry_test_utils;\n\npub mod constants;\npub mod utils;\n\nmod backtrace;\nmod bind;\nmod bind_json;\nmod build;\nmod cache;\nmod cmd;\nmod compiler;\nmod config;\nmod context;\nmod coverage;\nmod create;\nmod debug;\nmod doc;\nmod eip712;\nmod failure_assertions;\nmod inline_config;\nmod install;\n\nmod json;\nmod lint;\nmod multi_script;\nmod precompiles;\nmod script;\nmod soldeer;\nmod svm;\nmod test_cmd;\nmod verify;\nmod verify_bytecode;\nmod version;\n\nmod ext_integration;\nmod fmt;\nmod fmt_integration;\nmod test_optimizer;\n"
  },
  {
    "path": "crates/forge/tests/cli/multi_script.rs",
    "content": "//! Contains various tests related to forge script\nuse anvil::{NodeConfig, spawn};\n\nuse foundry_test_utils::{ScriptOutcome, ScriptTester};\n\nforgetest_async!(can_deploy_multi_chain_script_without_lib, |prj, cmd| {\n    let (api1, handle1) = spawn(NodeConfig::test()).await;\n    let (api2, handle2) = spawn(NodeConfig::test()).await;\n    let mut tester = ScriptTester::new_broadcast_without_endpoint(cmd, prj.root());\n\n    tester\n        .load_private_keys(&[0, 1])\n        .await\n        .add_sig(\"MultiChainBroadcastNoLink\", \"deploy(string memory,string memory)\")\n        .args(&[&handle1.http_endpoint(), &handle2.http_endpoint()])\n        .broadcast(ScriptOutcome::OkBroadcast);\n\n    assert_eq!(api1.transaction_count(tester.accounts_pub[0], None).await.unwrap().to::<u32>(), 1);\n    assert_eq!(api1.transaction_count(tester.accounts_pub[1], None).await.unwrap().to::<u32>(), 1);\n\n    assert_eq!(api2.transaction_count(tester.accounts_pub[0], None).await.unwrap().to::<u32>(), 2);\n    assert_eq!(api2.transaction_count(tester.accounts_pub[1], None).await.unwrap().to::<u32>(), 3);\n});\n\nforgetest_async!(can_not_deploy_multi_chain_script_with_lib, |prj, cmd| {\n    let (_, handle1) = spawn(NodeConfig::test()).await;\n    let (_, handle2) = spawn(NodeConfig::test()).await;\n    let mut tester = ScriptTester::new_broadcast_without_endpoint(cmd, prj.root());\n\n    tester\n        .load_private_keys(&[0, 1])\n        .await\n        .add_deployer(0)\n        .add_sig(\"MultiChainBroadcastLink\", \"deploy(string memory,string memory)\")\n        .args(&[&handle1.http_endpoint(), &handle2.http_endpoint()])\n        .broadcast(ScriptOutcome::UnsupportedLibraries);\n});\n\nforgetest_async!(can_not_change_fork_during_broadcast, |prj, cmd| {\n    let (_, handle1) = spawn(NodeConfig::test()).await;\n    let (_, handle2) = spawn(NodeConfig::test()).await;\n    let mut tester = ScriptTester::new_broadcast_without_endpoint(cmd, prj.root());\n\n    tester\n        .load_private_keys(&[0, 1])\n        .await\n        .add_deployer(0)\n        .add_sig(\"MultiChainBroadcastNoLink\", \"deployError(string memory,string memory)\")\n        .args(&[&handle1.http_endpoint(), &handle2.http_endpoint()])\n        .broadcast(ScriptOutcome::ErrorSelectForkOnBroadcast);\n});\n\nforgetest_async!(can_resume_multi_chain_script, |prj, cmd| {\n    let (_, handle1) = spawn(NodeConfig::test()).await;\n    let (_, handle2) = spawn(NodeConfig::test()).await;\n    let mut tester = ScriptTester::new_broadcast_without_endpoint(cmd, prj.root());\n\n    tester\n        .add_sig(\"MultiChainBroadcastNoLink\", \"deploy(string memory,string memory)\")\n        .args(&[&handle1.http_endpoint(), &handle2.http_endpoint()])\n        .broadcast(ScriptOutcome::MissingWallet)\n        .load_private_keys(&[0, 1])\n        .await\n        .arg(\"--multi\")\n        .resume(ScriptOutcome::OkBroadcast);\n});\n"
  },
  {
    "path": "crates/forge/tests/cli/precompiles.rs",
    "content": "//! Contains various tests for `forge test` with precompiles.\n\nuse foundry_evm_networks::NetworkConfigs;\nuse foundry_test_utils::str;\n\nforgetest_init!(precompile_trace_decoding, |prj, cmd| {\n    prj.add_test(\n        \"PrecompileTrace.t.sol\",\n        r#\"\n// SPDX-License-Identifier: MIT\npragma solidity ^0.8.20;\n\nimport \"forge-std/Test.sol\";\n\ncontract PrecompileCaller {\n    constructor() {\n        // 0x01 - ECRECOVER\n        {\n            bytes32 hash = keccak256(\"test message\");\n            uint8 v = 27;\n            bytes32 r = bytes32(uint256(1));\n            bytes32 s = bytes32(uint256(2));\n            address(0x01).staticcall(abi.encode(hash, v, r, s));\n        }\n\n        // 0x02 - SHA256\n        address(0x02).staticcall(abi.encodePacked(\"hello\"));\n\n        // 0x03 - RIPEMD160\n        address(0x03).staticcall(abi.encodePacked(\"hello\"));\n\n        // 0x04 - IDENTITY (datacopy)\n        address(0x04).staticcall(abi.encodePacked(\"hello\"));\n\n        // 0x05 - MODEXP: compute 2^3 mod 5 = 3\n        {\n            bytes memory modexpInput = abi.encodePacked(\n                uint256(1),  // base length\n                uint256(1),  // exponent length\n                uint256(1),  // modulus length\n                uint8(2),    // base = 2\n                uint8(3),    // exponent = 3\n                uint8(5)     // modulus = 5\n            );\n            address(0x05).staticcall(modexpInput);\n        }\n\n        // 0x06 - BN254 ADD (ecadd): P + O = P\n        {\n            uint256 g1x = 1;\n            uint256 g1y = 2;\n            uint256 zerox = 0;\n            uint256 zeroy = 0;\n            address(0x06).staticcall(abi.encode(g1x, g1y, zerox, zeroy));\n        }\n\n        // 0x07 - BN254 MUL (ecmul): 1 * G = G\n        {\n            uint256 g1x = 1;\n            uint256 g1y = 2;\n            uint256 scalar = 1;\n            address(0x07).staticcall(abi.encode(g1x, g1y, scalar));\n        }\n\n        // 0x08 - BN254 PAIRING: empty input returns success (1)\n        address(0x08).staticcall(\"\");\n\n        // 0x09 - BLAKE2F\n        {\n            bytes memory blake2fInput = new bytes(213);\n            blake2fInput[3] = 0x0c; // 12 rounds\n            bytes8[8] memory iv = [\n                bytes8(0x6a09e667f3bcc908),\n                bytes8(0xbb67ae8584caa73b),\n                bytes8(0x3c6ef372fe94f82b),\n                bytes8(0xa54ff53a5f1d36f1),\n                bytes8(0x510e527fade682d1),\n                bytes8(0x9b05688c2b3e6c1f),\n                bytes8(0x1f83d9abfb41bd6b),\n                bytes8(0x5be0cd19137e2179)\n            ];\n            for (uint256 i = 0; i < 8; i++) {\n                for (uint256 j = 0; j < 8; j++) {\n                    blake2fInput[4 + i * 8 + j] = iv[i][j];\n                }\n            }\n            blake2fInput[212] = 0x01;\n            address(0x09).staticcall(blake2fInput);\n        }\n\n        // 0x0B - BLS12-381 G1 ADD (two points at infinity)\n        address(0x0B).staticcall(new bytes(256));\n\n        // 0x0C - BLS12-381 G1 MSM\n        address(0x0C).staticcall(new bytes(160));\n\n        // 0x0D - BLS12-381 G2 ADD (two points at infinity)\n        address(0x0D).staticcall(new bytes(512));\n\n        // 0x0E - BLS12-381 G2 MSM\n        address(0x0E).staticcall(new bytes(288));\n\n        // 0x0F - BLS12-381 PAIRING (G1 + G2 infinity points)\n        address(0x0F).staticcall(new bytes(384));\n\n        // 0x10 - BLS12-381 MAP FP TO G1\n        address(0x10).staticcall(new bytes(64));\n\n        // 0x11 - BLS12-381 MAP FP2 TO G2\n        address(0x11).staticcall(new bytes(128));\n\n        // 0x100 - P256VERIFY (secp256r1)\n        address(0x100).staticcall(new bytes(160));\n    }\n}\n\ncontract PrecompileTraceTest is Test {\n    function test_precompile_traces() public {\n        new PrecompileCaller();\n    }\n}\n   \"#,\n    );\n\n    cmd.args([\"test\", \"--mt\", \"test_precompile_traces\", \"-vvvv\", \"--evm-version\", \"osaka\"])\n        .assert_success()\n        .stdout_eq(str![[r#\"\n...\nRan 1 test for test/PrecompileTrace.t.sol:PrecompileTraceTest\n[PASS] test_precompile_traces() ([GAS])\nTraces:\n  [..] PrecompileTraceTest::test_precompile_traces()\n    ├─ [..] → new PrecompileCaller@[..]\n    │   ├─ [..] PRECOMPILES::ecrecover(0xea83cdcdd06bf61e414054115a551e23133711d0507dcbc07a4bab7dc4581935, 27, 1, 2) [staticcall]\n    │   │   └─ ← [Return] 0xBe038042508C42Df7b2A529cd4Cc0a9447c7D2b6\n    │   ├─ [..] PRECOMPILES::sha256(0x68656c6c6f) [staticcall]\n    │   │   └─ ← [Return] 0x2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824\n    │   ├─ [..] PRECOMPILES::ripemd(0x68656c6c6f) [staticcall]\n    │   │   └─ ← [Return] 0x000000000000000000000000108f07b838241261\n    │   ├─ [..] PRECOMPILES::identity(0x68656c6c6f) [staticcall]\n    │   │   └─ ← [Return] 0x68656c6c6f\n    │   ├─ [..] PRECOMPILES::modexp(1, 1, 1, 0x02, 0x03, 0x05) [staticcall]\n    │   │   └─ ← [Return] 0x03\n    │   ├─ [..] PRECOMPILES::ecadd(1, 2, 0, 0) [staticcall]\n    │   │   └─ ← [Return] (1, 2)\n    │   ├─ [..] PRECOMPILES::ecmul(1, 2, 1) [staticcall]\n    │   │   └─ ← [Return] (1, 2)\n    │   ├─ [..] PRECOMPILES::ecpairing() [staticcall]\n    │   │   └─ ← [Return] true\n    │   ├─ [..] PRECOMPILES::blake2f(12, [633244976228469098, 4298627039875721147, 3168446158426304060, 17381112106731261861, 15096882533739138641, 2264253069420660123, 7763433881832358687, 8728396173323133019], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0], 1) [staticcall]\n    │   │   └─ ← [Return] 0x1a48bfec594a1b13bb024be345656b8af895d662ccbc3f39fb5ecf2ef05942b5acace594cb81cdff6044b5bfaabfea105168676ce5753f6bb559ce3f92ad4850\n    │   ├─ [..] PRECOMPILES::bls12G1Add(0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000, 0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000) [staticcall]\n    │   │   └─ ← [Return] 0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n    │   ├─ [..] PRECOMPILES::bls12G1Msm(0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000) [staticcall]\n    │   │   └─ ← [Return] 0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n    │   ├─ [..] PRECOMPILES::bls12G2Add(0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000, 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000) [staticcall]\n    │   │   └─ ← [Return] 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n    │   ├─ [..] PRECOMPILES::bls12G2Msm(0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000) [staticcall]\n    │   │   └─ ← [Return] 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n    │   ├─ [..] PRECOMPILES::bls12PairingCheck(0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000) [staticcall]\n    │   │   └─ ← [Return] true\n    │   ├─ [..] PRECOMPILES::bls12MapFpToG1(0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000) [staticcall]\n    │   │   └─ ← [Return] 0x0000000000000000000000000000000011a9a0372b8f332d5c30de9ad14e50372a73fa4c45d5f2fa5097f2d6fb93bcac592f2e1711ac43db0519870c7d0ea41500000000000000000000000000000000092c0f994164a0719f51c24ba3788de240ff926b55f58c445116e8bc6a47cd63392fd4e8e22bdf9feaa96ee773222133\n    │   ├─ [..] PRECOMPILES::bls12MapFp2ToG2(0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000) [staticcall]\n    │   │   └─ ← [Return] 0x00000000000000000000000000000000018320896ec9eef9d5e619848dc29ce266f413d02dd31d9b9d44ec0c79cd61f18b075ddba6d7bd20b7ff27a4b324bfce000000000000000000000000000000000a67d12118b5a35bb02d2e86b3ebfa7e23410db93de39fb06d7025fa95e96ffa428a7a27c3ae4dd4b40bd251ac658892000000000000000000000000000000000260e03644d1a2c321256b3246bad2b895cad13890cbe6f85df55106a0d334604fb143c7a042d878006271865bc359410000000000000000000000000000000004c69777a43f0bda07679d5805e63f18cf4e0e7c6112ac7f70266d199b4f76ae27c6269a3ceebdae30806e9a76aadf5c\n    │   ├─ [..] P256VERIFY::fulfillBasicOrder_efficient_6GL6yc() [staticcall]\n    │   │   └─ ← [Return]\n    │   └─ ← [Return] 62 bytes of code\n    └─ ← [Stop]\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests)\n\n\"#]]);\n});\n\n// tests transfer using celo precompile.\n// <https://github.com/foundry-rs/foundry/issues/11622>\nforgetest_init!(celo_transfer, |prj, cmd| {\n    prj.update_config(|config| {\n        config.networks = NetworkConfigs::with_celo();\n    });\n\n    prj.add_test(\n        \"CeloTransfer.t.sol\",\n        r#\"\nimport \"forge-std/Test.sol\";\n\ninterface IERC20 {\n    function balanceOf(address account) external view returns (uint256);\n    function transfer(address to, uint256 amount) external returns (bool);\n}\n\ncontract CeloTransferTest is Test {\n    IERC20 celo = IERC20(0x471EcE3750Da237f93B8E339c536989b8978a438);\n    IERC20 usdc = IERC20(0xcebA9300f2b948710d2653dD7B07f33A8B32118C);\n    IERC20 usdt = IERC20(0x48065fbBE25f71C9282ddf5e1cD6D6A887483D5e);\n\n    address binanceAccount = 0xf6436829Cf96EA0f8BC49d300c536FCC4f84C4ED;\n    address recipient = makeAddr(\"recipient\");\n\n    function setUp() public {\n        vm.createSelectFork(\"https://forno.celo.org\");\n    }\n\n    function testCeloBalance() external {\n        console2.log(\"recipient balance before\", celo.balanceOf(recipient));\n        vm.prank(binanceAccount);\n        celo.transfer(recipient, 100);\n        console2.log(\"recipient balance after\", celo.balanceOf(recipient));\n        assertEq(celo.balanceOf(recipient), 100);\n    }\n}\n   \"#,\n    );\n\n    cmd.args([\"test\", \"--mt\", \"testCeloBalance\", \"-vvv\"]).assert_success().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\nRan 1 test for test/CeloTransfer.t.sol:CeloTransferTest\n[PASS] testCeloBalance() ([GAS])\nLogs:\n  recipient balance before 0\n  recipient balance after 100\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests)\n\n\"#]]);\n});\n"
  },
  {
    "path": "crates/forge/tests/cli/script.rs",
    "content": "//! Contains various tests related to `forge script`.\n\nuse crate::constants::TEMPLATE_CONTRACT;\nuse alloy_hardforks::EthereumHardfork;\nuse alloy_network::Ethereum;\nuse alloy_primitives::{Address, Bytes, address, hex};\nuse anvil::{NodeConfig, spawn};\nuse forge_script_sequence::ScriptSequence;\nuse foundry_test_utils::{\n    ScriptOutcome, ScriptTester,\n    rpc::{self, next_http_archive_rpc_url},\n    snapbox::IntoData,\n    util::{OTHER_SOLC_VERSION, SOLC_VERSION},\n};\nuse regex::Regex;\nuse serde_json::Value;\nuse std::{env, fs, path::PathBuf};\n\n// Tests that fork cheat codes can be used in script\nforgetest_init!(\n    #[ignore]\n    can_use_fork_cheat_codes_in_script,\n    |prj, cmd| {\n        let script = prj.add_source(\n            \"Foo\",\n            r#\"\nimport \"forge-std/Script.sol\";\n\ncontract ContractScript is Script {\n    function setUp() public {}\n\n    function run() public {\n        uint256 fork = vm.activeFork();\n        vm.rollFork(11469702);\n    }\n}\n   \"#,\n        );\n\n        let rpc = foundry_test_utils::rpc::next_http_rpc_endpoint();\n\n        cmd.arg(\"script\").arg(script).args([\"--fork-url\", rpc.as_str(), \"-vvvvv\"]).assert_success();\n    }\n);\n\n// Tests that the `run` command works correctly\nforgetest!(can_execute_script_command2, |prj, cmd| {\n    let script = prj.add_source(\n        \"Foo\",\n        r#\"\ncontract Demo {\n    event log_string(string);\n    function run() external {\n        emit log_string(\"script ran\");\n    }\n}\n   \"#,\n    );\n\n    cmd.arg(\"script\").arg(script).assert_success().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\nScript ran successfully.\n[GAS]\n\n== Logs ==\n  script ran\n\n\"#]]);\n});\n\n// Tests that the `run` command works correctly when path *and* script name is specified\nforgetest!(can_execute_script_command_fqn, |prj, cmd| {\n    let script = prj.add_source(\n        \"Foo\",\n        r#\"\ncontract Demo {\n    event log_string(string);\n    function run() external {\n        emit log_string(\"script ran\");\n    }\n}\n   \"#,\n    );\n\n    cmd.arg(\"script\").arg(format!(\"{}:Demo\", script.display())).assert_success().stdout_eq(str![[\n        r#\"\n...\nScript ran successfully.\n[GAS]\n\n== Logs ==\n  script ran\n...\n\"#\n    ]]);\n});\n\n// Tests that the run command can run arbitrary functions\nforgetest!(can_execute_script_command_with_sig, |prj, cmd| {\n    let script = prj.add_source(\n        \"Foo\",\n        r#\"\ncontract Demo {\n    event log_string(string);\n    function myFunction() external {\n        emit log_string(\"script ran\");\n    }\n}\n   \"#,\n    );\n\n    cmd.arg(\"script\").arg(script).arg(\"--sig\").arg(\"myFunction()\").assert_success().stdout_eq(\n        str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\nScript ran successfully.\n[GAS]\n\n== Logs ==\n  script ran\n\n\"#]],\n    );\n});\n\nstatic FAILING_SCRIPT: &str = r#\"\nimport \"forge-std/Script.sol\";\n\ncontract FailingScript is Script {\n    function run() external {\n        revert(\"failed\");\n    }\n}\n\"#;\n\n// Tests that execution throws upon encountering a revert in the script.\nforgetest_async!(assert_exit_code_error_on_failure_script, |prj, cmd| {\n    foundry_test_utils::util::initialize(prj.root());\n    let script = prj.add_source(\"FailingScript\", FAILING_SCRIPT);\n\n    // set up command\n    cmd.arg(\"script\").arg(script);\n\n    // run command and assert error exit code\n    cmd.assert_failure().stderr_eq(str![[r#\"\nError: script failed: failed\n\n\"#]]);\n});\n\n// Tests that execution throws upon encountering a revert in the script with --json option.\n// <https://github.com/foundry-rs/foundry/issues/2508>\nforgetest_async!(assert_exit_code_error_on_failure_script_with_json, |prj, cmd| {\n    foundry_test_utils::util::initialize(prj.root());\n    let script = prj.add_source(\"FailingScript\", FAILING_SCRIPT);\n\n    // set up command\n    cmd.arg(\"script\").arg(script).arg(\"--json\");\n\n    // run command and assert error exit code\n    cmd.assert_failure().stderr_eq(str![[r#\"\nError: script failed: failed\n\n\"#]]);\n});\n\n// Tests that the manually specified gas limit is used when using the --unlocked option\nforgetest_async!(can_execute_script_command_with_manual_gas_limit_unlocked, |prj, cmd| {\n    foundry_test_utils::util::initialize(prj.root());\n    let deploy_script = prj.add_source(\n        \"Foo\",\n        r#\"\nimport \"forge-std/Script.sol\";\n\ncontract GasWaster {\n    function wasteGas(uint256 minGas) public {\n        require(gasleft() >= minGas, \"Gas left needs to be higher\");\n    }\n}\ncontract DeployScript is Script {\n    function run() external {\n        vm.startBroadcast();\n        GasWaster gasWaster = new GasWaster();\n        gasWaster.wasteGas{gas: 500000}(200000);\n    }\n}\n   \"#,\n    );\n\n    let deploy_contract = deploy_script.display().to_string() + \":DeployScript\";\n\n    let node_config = NodeConfig::test().with_eth_rpc_url(Some(rpc::next_http_archive_rpc_url()));\n    let (_api, handle) = spawn(node_config).await;\n    let dev = handle.dev_accounts().next().unwrap();\n    cmd.set_current_dir(prj.root());\n\n    cmd.args([\n        \"script\",\n        &deploy_contract,\n        \"--root\",\n        prj.root().to_str().unwrap(),\n        \"--fork-url\",\n        &handle.http_endpoint(),\n        \"--sender\",\n        format!(\"{dev:?}\").as_str(),\n        \"-vvvvv\",\n        \"--slow\",\n        \"--broadcast\",\n        \"--unlocked\",\n        \"--ignored-error-codes=2018\", // `wasteGas` can be restricted to view\n    ])\n    .assert_success()\n    .stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\nTraces:\n  [..] DeployScript::run()\n    ├─ [0] VM::startBroadcast()\n    │   └─ ← [Return]\n    ├─ [..] → new GasWaster@[..]\n    │   └─ ← [Return] 415 bytes of code\n    ├─ [..] GasWaster::wasteGas(200000 [2e5])\n    │   └─ ← [Stop]\n    └─ ← [Stop]\n\n\nScript ran successfully.\n\n## Setting up 1 EVM.\n==========================\nSimulated On-chain Traces:\n\n  [..] → new GasWaster@[..]\n    └─ ← [Return] 415 bytes of code\n\n  [..] GasWaster::wasteGas(200000 [2e5])\n    └─ ← [Stop]\n\n\n==========================\n\nChain 1\n\n[ESTIMATED_GAS_PRICE]\n\n[ESTIMATED_TOTAL_GAS_USED]\n\n[ESTIMATED_AMOUNT_REQUIRED]\n\n==========================\n\n\n==========================\n\nONCHAIN EXECUTION COMPLETE & SUCCESSFUL.\n\n[SAVED_TRANSACTIONS]\n\n[SAVED_SENSITIVE_VALUES]\n\n\n\"#]]);\n});\n\n// Tests that the manually specified gas limit is used.\nforgetest_async!(can_execute_script_command_with_manual_gas_limit, |prj, cmd| {\n    foundry_test_utils::util::initialize(prj.root());\n    let deploy_script = prj.add_source(\n        \"Foo\",\n        r#\"\nimport \"forge-std/Script.sol\";\n\ncontract GasWaster {\n    function wasteGas(uint256 minGas) public {\n        require(gasleft() >= minGas, \"Gas left needs to be higher\");\n    }\n}\ncontract DeployScript is Script {\n    function run() external {\n        vm.startBroadcast();\n        GasWaster gasWaster = new GasWaster();\n        gasWaster.wasteGas{gas: 500000}(200000);\n    }\n}\n   \"#,\n    );\n\n    let deploy_contract = deploy_script.display().to_string() + \":DeployScript\";\n\n    let node_config = NodeConfig::test().with_eth_rpc_url(Some(rpc::next_http_archive_rpc_url()));\n    let (_api, handle) = spawn(node_config).await;\n    let private_key =\n        \"ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80\".to_string();\n    cmd.set_current_dir(prj.root());\n\n    cmd.args([\n        \"script\",\n        &deploy_contract,\n        \"--root\",\n        prj.root().to_str().unwrap(),\n        \"--fork-url\",\n        &handle.http_endpoint(),\n        \"-vvvvv\",\n        \"--slow\",\n        \"--broadcast\",\n        \"--private-key\",\n        &private_key,\n    ])\n    .assert_success()\n    .stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful with warnings:\nWarning (2018): Function state mutability can be restricted to view\n [FILE]:7:5:\n  |\n7 |     function wasteGas(uint256 minGas) public {\n  |     ^ (Relevant source part starts here and spans across multiple lines).\n\nTraces:\n  [..] DeployScript::run()\n    ├─ [0] VM::startBroadcast()\n    │   └─ ← [Return]\n    ├─ [..] → new GasWaster@[..]\n    │   └─ ← [Return] 415 bytes of code\n    ├─ [..] GasWaster::wasteGas(200000 [2e5])\n    │   └─ ← [Stop]\n    └─ ← [Stop]\n\n\nScript ran successfully.\n\n## Setting up 1 EVM.\n==========================\nSimulated On-chain Traces:\n\n  [..] → new GasWaster@[..]\n    └─ ← [Return] 415 bytes of code\n\n  [..] GasWaster::wasteGas(200000 [2e5])\n    └─ ← [Stop]\n\n\n==========================\n\nChain 1\n\n[ESTIMATED_GAS_PRICE]\n\n[ESTIMATED_TOTAL_GAS_USED]\n\n[ESTIMATED_AMOUNT_REQUIRED]\n\n==========================\n\n\n==========================\n\nONCHAIN EXECUTION COMPLETE & SUCCESSFUL.\n\n[SAVED_TRANSACTIONS]\n\n[SAVED_SENSITIVE_VALUES]\n\n\n\"#]]);\n});\n\n// Tests that the run command can run functions with arguments\nforgetest!(can_execute_script_command_with_args, |prj, cmd| {\n    let script = prj.add_source(\n        \"Foo\",\n        r#\"\ncontract Demo {\n    event log_string(string);\n    event log_uint(uint);\n    function run(uint256 a, uint256 b) external {\n        emit log_string(\"script ran\");\n        emit log_uint(a);\n        emit log_uint(b);\n    }\n}\n   \"#,\n    );\n\n    cmd.arg(\"script\")\n        .arg(script)\n        .arg(\"--sig\")\n        .arg(\"run(uint256,uint256)\")\n        .arg(\"1\")\n        .arg(\"2\")\n        .assert_success()\n        .stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\nScript ran successfully.\n[GAS]\n\n== Logs ==\n  script ran\n  1\n  2\n\n\"#]]);\n});\n\n// Tests that the run command can run functions with arguments without specifying the signature\n// <https://github.com/foundry-rs/foundry/issues/11240>\nforgetest!(can_execute_script_command_with_args_no_sig, |prj, cmd| {\n    let script = prj.add_source(\n        \"Foo\",\n        r#\"\ncontract Demo {\n    event log_string(string);\n    event log_uint(uint);\n    function run(uint256 a, uint256 b) external {\n        emit log_string(\"script ran\");\n        emit log_uint(a);\n        emit log_uint(b);\n    }\n}\n   \"#,\n    );\n\n    cmd.arg(\"script\").arg(script).arg(\"1\").arg(\"2\").assert_success().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\nScript ran successfully.\n[GAS]\n\n== Logs ==\n  script ran\n  1\n  2\n\n\"#]]);\n});\n\n// Tests that the run command can run functions with return values\nforgetest!(can_execute_script_command_with_returned, |prj, cmd| {\n    let script = prj.add_source(\n        \"Foo\",\n        r#\"\ncontract Demo {\n    event log_string(string);\n    function run() external returns (uint256 result, uint8) {\n        emit log_string(\"script ran\");\n        return (255, 3);\n    }\n}\"#,\n    );\n\n    cmd.arg(\"script\").arg(script).assert_success().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\nScript ran successfully.\n[GAS]\n\n== Return ==\nresult: uint256 255\n1: uint8 3\n\n== Logs ==\n  script ran\n\n\"#]]);\n});\n\nforgetest_async!(can_broadcast_script_skipping_simulation, |prj, cmd| {\n    foundry_test_utils::util::initialize(prj.root());\n    // This example script would fail in on-chain simulation\n    let deploy_script = prj.add_source(\n        \"DeployScript\",\n        r#\"\nimport \"forge-std/Script.sol\";\n\ncontract HashChecker {\n    bytes32 public lastHash;\n\n    function update() public {\n        bytes32 newHash = blockhash(block.number - 1);\n        require(newHash != lastHash, \"Hash didn't change\");\n        lastHash = newHash;\n    }\n\n    function checkLastHash() public view {\n        require(lastHash != bytes32(0), \"Hash shouldn't be zero\");\n    }\n}\n\ncontract DeployScript is Script {\n    HashChecker public hashChecker;\n\n    function run() external {\n        vm.startBroadcast();\n        hashChecker = new HashChecker();\n    }\n}\"#,\n    );\n\n    let deploy_contract = deploy_script.display().to_string() + \":DeployScript\";\n\n    let node_config = NodeConfig::test().with_eth_rpc_url(Some(rpc::next_http_archive_rpc_url()));\n    let (_api, handle) = spawn(node_config).await;\n    let private_key =\n        \"ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80\".to_string();\n    cmd.set_current_dir(prj.root());\n\n    cmd.args([\n        \"script\",\n        &deploy_contract,\n        \"--root\",\n        prj.root().to_str().unwrap(),\n        \"--fork-url\",\n        &handle.http_endpoint(),\n        \"-vvvvv\",\n        \"--broadcast\",\n        \"--slow\",\n        \"--skip-simulation\",\n        \"--private-key\",\n        &private_key,\n    ])\n    .assert_success()\n    .stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\nTraces:\n  [..] DeployScript::run()\n    ├─ [0] VM::startBroadcast()\n    │   └─ ← [Return]\n    ├─ [..] → new HashChecker@[..]\n    │   └─ ← [Return] 718 bytes of code\n    └─ ← [Stop]\n\n\nScript ran successfully.\n\nSKIPPING ON CHAIN SIMULATION.\n\n\n==========================\n\nONCHAIN EXECUTION COMPLETE & SUCCESSFUL.\n\n[SAVED_TRANSACTIONS]\n\n[SAVED_SENSITIVE_VALUES]\n\n\n\"#]]);\n\n    let run_log = std::fs::read_to_string(\"broadcast/DeployScript.sol/1/run-latest.json\").unwrap();\n    let run_object: Value = serde_json::from_str(&run_log).unwrap();\n    let contract_address = &run_object[\"receipts\"][0][\"contractAddress\"]\n        .as_str()\n        .unwrap()\n        .parse::<Address>()\n        .unwrap()\n        .to_string();\n\n    let run_code = r#\"\nimport \"forge-std/Script.sol\";\nimport { HashChecker } from \"./DeployScript.sol\";\n\ncontract RunScript is Script {\n    HashChecker public hashChecker;\n\n    function run() external {\n        vm.startBroadcast();\n        hashChecker = HashChecker(CONTRACT_ADDRESS);\n        uint numUpdates = 8;\n        vm.roll(block.number - numUpdates);\n        for(uint i = 0; i < numUpdates; i++) {\n            vm.roll(block.number + 1);\n            hashChecker.update();\n            hashChecker.checkLastHash();\n        }\n    }\n}\"#\n    .replace(\"CONTRACT_ADDRESS\", contract_address);\n\n    let run_script = prj.add_source(\"RunScript\", &run_code);\n    let run_contract = run_script.display().to_string() + \":RunScript\";\n\n    cmd.forge_fuse()\n        .args([\n            \"script\",\n            &run_contract,\n            \"--root\",\n            prj.root().to_str().unwrap(),\n            \"--fork-url\",\n            &handle.http_endpoint(),\n            \"-vvvvv\",\n            \"--broadcast\",\n            \"--slow\",\n            \"--skip-simulation\",\n            \"--gas-estimate-multiplier\",\n            \"200\",\n            \"--private-key\",\n            &private_key,\n        ])\n        .assert_success()\n        .stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\nTraces:\n  [..] RunScript::run()\n    ├─ [0] VM::startBroadcast()\n    │   └─ ← [Return]\n    ├─ [0] VM::roll([..])\n    │   └─ ← [Return]\n    ├─ [0] VM::roll([..])\n    │   └─ ← [Return]\n    ├─ [..] [..]::update()\n    │   └─ ← [Stop]\n    ├─ [..] [..]::checkLastHash() [staticcall]\n    │   └─ ← [Stop]\n    ├─ [0] VM::roll([..])\n    │   └─ ← [Return]\n    ├─ [..] [..]::update()\n    │   └─ ← [Stop]\n    ├─ [..] [..]::checkLastHash() [staticcall]\n    │   └─ ← [Stop]\n    ├─ [0] VM::roll([..])\n    │   └─ ← [Return]\n    ├─ [..] [..]::update()\n    │   └─ ← [Stop]\n    ├─ [..] [..]::checkLastHash() [staticcall]\n    │   └─ ← [Stop]\n    ├─ [0] VM::roll([..])\n    │   └─ ← [Return]\n    ├─ [..] [..]::update()\n    │   └─ ← [Stop]\n    ├─ [..] [..]::checkLastHash() [staticcall]\n    │   └─ ← [Stop]\n    ├─ [0] VM::roll([..])\n    │   └─ ← [Return]\n    ├─ [..] [..]::update()\n    │   └─ ← [Stop]\n    ├─ [..] [..]::checkLastHash() [staticcall]\n    │   └─ ← [Stop]\n    ├─ [0] VM::roll([..])\n    │   └─ ← [Return]\n    ├─ [..] [..]::update()\n    │   └─ ← [Stop]\n    ├─ [..] [..]::checkLastHash() [staticcall]\n    │   └─ ← [Stop]\n    ├─ [0] VM::roll([..])\n    │   └─ ← [Return]\n    ├─ [..] [..]::update()\n    │   └─ ← [Stop]\n    ├─ [..] [..]::checkLastHash() [staticcall]\n    │   └─ ← [Stop]\n    ├─ [0] VM::roll([..])\n    │   └─ ← [Return]\n    ├─ [..] [..]::update()\n    │   └─ ← [Stop]\n    ├─ [..] [..]::checkLastHash() [staticcall]\n    │   └─ ← [Stop]\n    └─ ← [Stop]\n\n\nScript ran successfully.\n\nSKIPPING ON CHAIN SIMULATION.\n\n\n==========================\n\nONCHAIN EXECUTION COMPLETE & SUCCESSFUL.\n\n[SAVED_TRANSACTIONS]\n\n[SAVED_SENSITIVE_VALUES]\n\n\n\"#]]);\n});\n\nforgetest_async!(can_deploy_script_without_lib, |prj, cmd| {\n    let (_api, handle) = spawn(NodeConfig::test()).await;\n    let mut tester = ScriptTester::new_broadcast(cmd, &handle.http_endpoint(), prj.root());\n\n    tester\n        .load_private_keys(&[0, 1])\n        .await\n        .add_sig(\"BroadcastTestNoLinking\", \"deployDoesntPanic()\")\n        .simulate(ScriptOutcome::OkSimulation)\n        .broadcast(ScriptOutcome::OkBroadcast)\n        .assert_nonce_increment(&[(0, 1), (1, 2)])\n        .await;\n});\n\nforgetest_async!(can_deploy_script_with_lib, |prj, cmd| {\n    let (_api, handle) = spawn(NodeConfig::test()).await;\n    let mut tester = ScriptTester::new_broadcast(cmd, &handle.http_endpoint(), prj.root());\n\n    tester\n        .load_private_keys(&[0, 1])\n        .await\n        .add_sig(\"BroadcastTest\", \"deploy()\")\n        .simulate(ScriptOutcome::OkSimulation)\n        .broadcast(ScriptOutcome::OkBroadcast)\n        .assert_nonce_increment(&[(0, 2), (1, 1)])\n        .await;\n});\n\nforgetest_async!(can_deploy_script_private_key, |prj, cmd| {\n    let (_api, handle) = spawn(NodeConfig::test()).await;\n    let mut tester = ScriptTester::new_broadcast(cmd, &handle.http_endpoint(), prj.root());\n\n    tester\n        .load_addresses(&[address!(\"0x90F79bf6EB2c4f870365E785982E1f101E93b906\")])\n        .await\n        .add_sig(\"BroadcastTest\", \"deployPrivateKey()\")\n        .simulate(ScriptOutcome::OkSimulation)\n        .broadcast(ScriptOutcome::OkBroadcast)\n        .assert_nonce_increment_addresses(&[(\n            address!(\"0x90F79bf6EB2c4f870365E785982E1f101E93b906\"),\n            3,\n        )])\n        .await;\n});\n\nforgetest_async!(can_deploy_unlocked, |prj, cmd| {\n    let (_api, handle) = spawn(NodeConfig::test()).await;\n    let mut tester = ScriptTester::new_broadcast(cmd, &handle.http_endpoint(), prj.root());\n\n    tester\n        .sender(\"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266\".parse().unwrap())\n        .unlocked()\n        .add_sig(\"BroadcastTest\", \"deployOther()\")\n        .simulate(ScriptOutcome::OkSimulation)\n        .broadcast(ScriptOutcome::OkBroadcast);\n});\n\nforgetest_async!(can_deploy_script_remember_key, |prj, cmd| {\n    let (_api, handle) = spawn(NodeConfig::test()).await;\n    let mut tester = ScriptTester::new_broadcast(cmd, &handle.http_endpoint(), prj.root());\n\n    tester\n        .load_addresses(&[address!(\"0x90F79bf6EB2c4f870365E785982E1f101E93b906\")])\n        .await\n        .add_sig(\"BroadcastTest\", \"deployRememberKey()\")\n        .simulate(ScriptOutcome::OkSimulation)\n        .broadcast(ScriptOutcome::OkBroadcast)\n        .assert_nonce_increment_addresses(&[(\n            address!(\"0x90F79bf6EB2c4f870365E785982E1f101E93b906\"),\n            2,\n        )])\n        .await;\n});\n\nforgetest_async!(can_deploy_script_remember_key_and_resume, |prj, cmd| {\n    let (_api, handle) = spawn(NodeConfig::test()).await;\n    let mut tester = ScriptTester::new_broadcast(cmd, &handle.http_endpoint(), prj.root());\n\n    tester\n        .add_deployer(0)\n        .load_addresses(&[address!(\"0x90F79bf6EB2c4f870365E785982E1f101E93b906\")])\n        .await\n        .add_sig(\"BroadcastTest\", \"deployRememberKeyResume()\")\n        .simulate(ScriptOutcome::OkSimulation)\n        .resume(ScriptOutcome::MissingWallet)\n        // load missing wallet\n        .load_private_keys(&[0])\n        .await\n        .run(ScriptOutcome::OkBroadcast)\n        .assert_nonce_increment_addresses(&[(\n            address!(\"0x90F79bf6EB2c4f870365E785982E1f101E93b906\"),\n            1,\n        )])\n        .await\n        .assert_nonce_increment(&[(0, 2)])\n        .await;\n});\n\nforgetest_async!(can_resume_script, |prj, cmd| {\n    let (_api, handle) = spawn(NodeConfig::test()).await;\n    let mut tester = ScriptTester::new_broadcast(cmd, &handle.http_endpoint(), prj.root());\n\n    tester\n        .load_private_keys(&[0])\n        .await\n        .add_sig(\"BroadcastTest\", \"deploy()\")\n        .simulate(ScriptOutcome::OkSimulation)\n        .resume(ScriptOutcome::MissingWallet)\n        // load missing wallet\n        .load_private_keys(&[1])\n        .await\n        .run(ScriptOutcome::OkBroadcast)\n        .assert_nonce_increment(&[(0, 2), (1, 1)])\n        .await;\n});\n\nforgetest_async!(can_deploy_broadcast_wrap, |prj, cmd| {\n    let (_api, handle) = spawn(NodeConfig::test()).await;\n    let mut tester = ScriptTester::new_broadcast(cmd, &handle.http_endpoint(), prj.root());\n\n    tester\n        .add_deployer(2)\n        .load_private_keys(&[0, 1, 2])\n        .await\n        .add_sig(\"BroadcastTest\", \"deployOther()\")\n        .simulate(ScriptOutcome::OkSimulation)\n        .broadcast(ScriptOutcome::OkBroadcast)\n        .assert_nonce_increment(&[(0, 4), (1, 4), (2, 1)])\n        .await;\n});\n\nforgetest_async!(panic_no_deployer_set, |prj, cmd| {\n    let (_api, handle) = spawn(NodeConfig::test()).await;\n    let mut tester = ScriptTester::new_broadcast(cmd, &handle.http_endpoint(), prj.root());\n\n    tester\n        .load_private_keys(&[0, 1])\n        .await\n        .add_sig(\"BroadcastTest\", \"deployOther()\")\n        .simulate(ScriptOutcome::WarnSpecifyDeployer)\n        .broadcast(ScriptOutcome::MissingSender);\n});\n\nforgetest_async!(can_deploy_no_arg_broadcast, |prj, cmd| {\n    let (_api, handle) = spawn(NodeConfig::test()).await;\n    let mut tester = ScriptTester::new_broadcast(cmd, &handle.http_endpoint(), prj.root());\n\n    tester\n        .add_deployer(0)\n        .load_private_keys(&[0])\n        .await\n        .add_sig(\"BroadcastTest\", \"deployNoArgs()\")\n        .simulate(ScriptOutcome::OkSimulation)\n        .broadcast(ScriptOutcome::OkBroadcast)\n        .assert_nonce_increment(&[(0, 3)])\n        .await;\n});\n\nforgetest_async!(can_deploy_with_create2, |prj, cmd| {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n    let mut tester = ScriptTester::new_broadcast(cmd, &handle.http_endpoint(), prj.root());\n\n    // Prepare CREATE2 Deployer\n    api.anvil_set_code(\n        foundry_evm::constants::DEFAULT_CREATE2_DEPLOYER,\n        Bytes::from_static(foundry_evm::constants::DEFAULT_CREATE2_DEPLOYER_RUNTIME_CODE),\n    )\n    .await\n    .unwrap();\n\n    tester\n        .add_deployer(0)\n        .load_private_keys(&[0])\n        .await\n        .add_sig(\"BroadcastTestNoLinking\", \"deployCreate2()\")\n        .simulate(ScriptOutcome::OkSimulation)\n        .broadcast(ScriptOutcome::OkBroadcast)\n        .assert_nonce_increment(&[(0, 2)])\n        .await\n        // Running again results in error, since we're repeating the salt passed to CREATE2\n        .run(ScriptOutcome::ScriptFailed);\n});\n\nforgetest_async!(can_deploy_with_custom_create2, |prj, cmd| {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n    let mut tester = ScriptTester::new_broadcast(cmd, &handle.http_endpoint(), prj.root());\n    let create2 = address!(\"0x0000000000000000000000000000000000b4956c\");\n\n    // Prepare CREATE2 Deployer\n    api.anvil_set_code(\n        create2,\n        Bytes::from_static(foundry_evm::constants::DEFAULT_CREATE2_DEPLOYER_RUNTIME_CODE),\n    )\n    .await\n    .unwrap();\n\n    tester\n        .add_deployer(0)\n        .load_private_keys(&[0])\n        .await\n        .add_create2_deployer(create2)\n        .add_sig(\"BroadcastTestNoLinking\", \"deployCreate2(address)\")\n        .arg(&create2.to_string())\n        .simulate(ScriptOutcome::OkSimulation)\n        .broadcast(ScriptOutcome::OkBroadcast)\n        .assert_nonce_increment(&[(0, 2)])\n        .await;\n});\n\nforgetest_async!(can_deploy_with_custom_create2_notmatched_bytecode, |prj, cmd| {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n    let mut tester = ScriptTester::new_broadcast(cmd, &handle.http_endpoint(), prj.root());\n    let create2 = address!(\"0x0000000000000000000000000000000000b4956c\");\n\n    // Prepare CREATE2 Deployer\n    api.anvil_set_code(\n        create2,\n        Bytes::from_static(&hex!(\"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cef\")),\n    )\n    .await\n    .unwrap();\n\n    tester\n        .add_deployer(0)\n        .load_private_keys(&[0])\n        .await\n        .add_create2_deployer(create2)\n        .add_sig(\"BroadcastTestNoLinking\", \"deployCreate2()\")\n        .simulate(ScriptOutcome::ScriptFailed)\n        .broadcast(ScriptOutcome::ScriptFailed);\n});\n\nforgetest_async!(cannot_deploy_with_nonexist_create2, |prj, cmd| {\n    let (_api, handle) = spawn(NodeConfig::test()).await;\n    let mut tester = ScriptTester::new_broadcast(cmd, &handle.http_endpoint(), prj.root());\n    let create2 = address!(\"0x0000000000000000000000000000000000b4956c\");\n\n    tester\n        .add_deployer(0)\n        .load_private_keys(&[0])\n        .await\n        .add_create2_deployer(create2)\n        .add_sig(\"BroadcastTestNoLinking\", \"deployCreate2()\")\n        .simulate(ScriptOutcome::ScriptFailed)\n        .broadcast(ScriptOutcome::ScriptFailed);\n});\n\nforgetest_async!(can_deploy_and_simulate_25_txes_concurrently, |prj, cmd| {\n    let (_api, handle) = spawn(NodeConfig::test()).await;\n    let mut tester = ScriptTester::new_broadcast(cmd, &handle.http_endpoint(), prj.root());\n\n    tester\n        .load_private_keys(&[0])\n        .await\n        .add_sig(\"BroadcastTestNoLinking\", \"deployMany()\")\n        .simulate(ScriptOutcome::OkSimulation)\n        .broadcast(ScriptOutcome::OkBroadcast)\n        .assert_nonce_increment(&[(0, 25)])\n        .await;\n});\n\nforgetest_async!(can_deploy_and_simulate_mixed_broadcast_modes, |prj, cmd| {\n    let (_api, handle) = spawn(NodeConfig::test()).await;\n    let mut tester = ScriptTester::new_broadcast(cmd, &handle.http_endpoint(), prj.root());\n\n    tester\n        .load_private_keys(&[0])\n        .await\n        .add_sig(\"BroadcastMix\", \"deployMix()\")\n        .simulate(ScriptOutcome::OkSimulation)\n        .broadcast(ScriptOutcome::OkBroadcast)\n        .assert_nonce_increment(&[(0, 15)])\n        .await;\n});\n\nforgetest_async!(deploy_with_setup, |prj, cmd| {\n    let (_api, handle) = spawn(NodeConfig::test()).await;\n    let mut tester = ScriptTester::new_broadcast(cmd, &handle.http_endpoint(), prj.root());\n\n    tester\n        .load_private_keys(&[0])\n        .await\n        .add_sig(\"BroadcastTestSetup\", \"run()\")\n        .simulate(ScriptOutcome::OkSimulation)\n        .broadcast(ScriptOutcome::OkBroadcast)\n        .assert_nonce_increment(&[(0, 6)])\n        .await;\n});\n\nforgetest_async!(fail_broadcast_staticcall, |prj, cmd| {\n    let (_api, handle) = spawn(NodeConfig::test()).await;\n    let mut tester = ScriptTester::new_broadcast(cmd, &handle.http_endpoint(), prj.root());\n\n    tester\n        .load_private_keys(&[0])\n        .await\n        .add_sig(\"BroadcastTestNoLinking\", \"errorStaticCall()\")\n        .simulate(ScriptOutcome::StaticCallNotAllowed);\n});\n\nforgetest_async!(check_broadcast_log, |prj, cmd| {\n    let (api, handle) = spawn(NodeConfig::test()).await;\n    let mut tester = ScriptTester::new_broadcast(cmd, &handle.http_endpoint(), prj.root());\n\n    // Prepare CREATE2 Deployer\n    let addr = address!(\"0x4e59b44847b379578588920ca78fbf26c0b4956c\");\n    let code = hex::decode(\"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf3\").expect(\"Could not decode create2 deployer init_code\").into();\n    api.anvil_set_code(addr, code).await.unwrap();\n\n    tester\n        .load_private_keys(&[0])\n        .await\n        .add_sig(\"BroadcastTestSetup\", \"run()\")\n        .simulate(ScriptOutcome::OkSimulation)\n        .broadcast(ScriptOutcome::OkBroadcast)\n        .assert_nonce_increment(&[(0, 6)])\n        .await;\n\n    // Uncomment to recreate the broadcast log\n    // std::fs::copy(\n    //     \"broadcast/Broadcast.t.sol/31337/run-latest.json\",\n    //     PathBuf::from(env!(\"CARGO_MANIFEST_DIR\")).join(\"../../testdata/fixtures/broadcast.\n    // log. json\" ), );\n\n    // Check broadcast logs\n    // Ignore timestamp, blockHash, blockNumber, cumulativeGasUsed, effectiveGasPrice,\n    // transactionIndex and logIndex values since they can change in between runs\n    let re = Regex::new(r#\"((timestamp\":).[0-9]*)|((blockHash\":).*)|((blockNumber\":).*)|((cumulativeGasUsed\":).*)|((effectiveGasPrice\":).*)|((transactionIndex\":).*)|((logIndex\":).*)\"#).unwrap();\n\n    let fixtures_log = std::fs::read_to_string(\n        PathBuf::from(env!(\"CARGO_MANIFEST_DIR\"))\n            .join(\"../../testdata/fixtures/broadcast.log.json\"),\n    )\n    .unwrap();\n    let _fixtures_log = re.replace_all(&fixtures_log, \"\");\n\n    let run_log =\n        std::fs::read_to_string(\"broadcast/Broadcast.t.sol/31337/run-latest.json\").unwrap();\n    let _run_log = re.replace_all(&run_log, \"\");\n\n    // similar_asserts::assert_eq!(fixtures_log, run_log);\n\n    // Uncomment to recreate the sensitive log\n    // std::fs::copy(\n    //     \"cache/Broadcast.t.sol/31337/run-latest.json\",\n    //     PathBuf::from(env!(\"CARGO_MANIFEST_DIR\"))\n    //         .join(\"../../testdata/fixtures/broadcast.sensitive.log.json\"),\n    // );\n\n    // Check sensitive logs\n    // Ignore port number since it can change in between runs\n    let re = Regex::new(r\":[0-9]+\").unwrap();\n\n    let fixtures_log = std::fs::read_to_string(\n        PathBuf::from(env!(\"CARGO_MANIFEST_DIR\"))\n            .join(\"../../testdata/fixtures/broadcast.sensitive.log.json\"),\n    )\n    .unwrap();\n    let fixtures_log = re.replace_all(&fixtures_log, \"\");\n\n    let run_log = std::fs::read_to_string(\"cache/Broadcast.t.sol/31337/run-latest.json\").unwrap();\n    let run_log = re.replace_all(&run_log, \"\");\n\n    // Clean up carriage return OS differences\n    let re = Regex::new(r\"\\r\\n\").unwrap();\n    let fixtures_log = re.replace_all(&fixtures_log, \"\\n\");\n    let run_log = re.replace_all(&run_log, \"\\n\");\n\n    similar_asserts::assert_eq!(fixtures_log, run_log);\n});\n\nforgetest_async!(test_default_sender_balance, |prj, cmd| {\n    let (_api, handle) = spawn(NodeConfig::test()).await;\n    let mut tester = ScriptTester::new_broadcast(cmd, &handle.http_endpoint(), prj.root());\n\n    // Expect the default sender to have uint256.max balance.\n    tester\n        .add_sig(\"TestInitialBalance\", \"runDefaultSender()\")\n        .simulate(ScriptOutcome::OkSimulation);\n});\n\nforgetest_async!(test_custom_sender_balance, |prj, cmd| {\n    let (_api, handle) = spawn(NodeConfig::test()).await;\n    let mut tester = ScriptTester::new_broadcast(cmd, &handle.http_endpoint(), prj.root());\n\n    // Expect the sender to have its starting balance.\n    tester\n        .add_deployer(0)\n        .add_sig(\"TestInitialBalance\", \"runCustomSender()\")\n        .simulate(ScriptOutcome::OkSimulation);\n});\n\n#[derive(serde::Deserialize)]\nstruct Transactions {\n    transactions: Vec<Transaction>,\n}\n\n#[derive(serde::Deserialize)]\nstruct Transaction {\n    arguments: Vec<String>,\n}\n\n// test we output arguments <https://github.com/foundry-rs/foundry/issues/3053>\nforgetest_async!(can_execute_script_with_arguments, |prj, cmd| {\n    cmd.args([\"init\", \"--force\"])\n        .arg(prj.root())\n        .assert_success()\n        .stdout_eq(str![[r#\"\nInitializing [..]...\nInstalling forge-std in [..] (url: https://github.com/foundry-rs/forge-std, tag: None)\n    Installed forge-std[..]\n    Initialized forge project\n\n\"#]])\n        .stderr_eq(str![[r#\"\nWarning: Target directory is not empty, but `--force` was specified\n...\n\n\"#]]);\n\n    let (_api, handle) = spawn(NodeConfig::test()).await;\n    let script = prj.add_script(\n                \"Counter.s.sol\",\n                r#\"\nimport \"forge-std/Script.sol\";\n\nstruct Point {\n    uint256 x;\n    uint256 y;\n}\n\ncontract A {\n    address a;\n    uint b;\n    int c;\n    bytes32 d;\n    bool e;\n    bytes f;\n    Point g;\n    string h;\n\n  constructor(address _a, uint _b, int _c, bytes32 _d, bool _e, bytes memory _f, Point memory _g, string memory _h) {\n    a = _a;\n    b = _b;\n    c = _c;\n    d = _d;\n    e = _e;\n    f = _f;\n    g = _g;\n    h = _h;\n  }\n}\n\ncontract Script0 is Script {\n  function run() external {\n    vm.broadcast();\n\n    new A(msg.sender, 2 ** 32, -1 * (2 ** 32), keccak256(abi.encode(1)), true, \"abcdef\", Point(10, 99), \"hello\");\n  }\n}\n   \"#,\n            );\n\n    cmd\n        .forge_fuse()\n        .arg(\"script\")\n        .arg(script)\n        .args([\n            \"--tc\",\n            \"Script0\",\n            \"--sender\",\n            \"0x00a329c0648769A73afAc7F9381E08FB43dBEA72\",\n            \"--rpc-url\",\n            handle.http_endpoint().as_str(),\n        ])\n        .assert_success()\n        .stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n...\nScript ran successfully.\n\n## Setting up 1 EVM.\n\n==========================\n\nChain 31337\n\n[ESTIMATED_GAS_PRICE]\n\n[ESTIMATED_TOTAL_GAS_USED]\n\n[ESTIMATED_AMOUNT_REQUIRED]\n\n==========================\n\nSIMULATION COMPLETE. To broadcast these transactions, add --broadcast and wallet configuration(s) to the previous command. See forge script --help for more.\n\n[SAVED_TRANSACTIONS]\n\n[SAVED_SENSITIVE_VALUES]\n\n\n\"#]]);\n\n    let run_latest = foundry_common::fs::json_files(&prj.root().join(\"broadcast\"))\n        .find(|path| path.ends_with(\"run-latest.json\"))\n        .expect(\"No broadcast artifacts\");\n\n    let content = foundry_common::fs::read_to_string(run_latest).unwrap();\n\n    let transactions: Transactions = serde_json::from_str(&content).unwrap();\n    let transactions = transactions.transactions;\n    assert_eq!(transactions.len(), 1);\n    assert_eq!(\n        transactions[0].arguments,\n        vec![\n            \"0x00a329c0648769A73afAc7F9381E08FB43dBEA72\".to_string(),\n            \"4294967296\".to_string(),\n            \"-4294967296\".to_string(),\n            \"0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6\".to_string(),\n            \"true\".to_string(),\n            \"0x616263646566\".to_string(),\n            \"(10, 99)\".to_string(),\n            \"hello\".to_string(),\n        ]\n    );\n});\n\n// test we output arguments <https://github.com/foundry-rs/foundry/issues/3053>\nforgetest_async!(can_execute_script_with_arguments_nested_deploy, |prj, cmd| {\n    cmd.args([\"init\", \"--force\"])\n        .arg(prj.root())\n        .assert_success()\n        .stdout_eq(str![[r#\"\nInitializing [..]...\nInstalling forge-std in [..] (url: https://github.com/foundry-rs/forge-std, tag: None)\n    Installed forge-std[..]\n    Initialized forge project\n\n\"#]])\n        .stderr_eq(str![[r#\"\nWarning: Target directory is not empty, but `--force` was specified\n...\n\n\"#]]);\n\n    let (_api, handle) = spawn(NodeConfig::test()).await;\n    let script = prj.add_script(\n        \"Counter.s.sol\",\n        r#\"\nimport \"forge-std/Script.sol\";\n\ncontract A {\n  address a;\n  uint b;\n  int c;\n  bytes32 d;\n  bool e;\n  bytes f;\n  string g;\n\n  constructor(address _a, uint _b, int _c, bytes32 _d, bool _e, bytes memory _f, string memory _g) {\n    a = _a;\n    b = _b;\n    c = _c;\n    d = _d;\n    e = _e;\n    f = _f;\n    g = _g;\n  }\n}\n\ncontract B {\n  constructor(address _a, uint _b, int _c, bytes32 _d, bool _e, bytes memory _f, string memory _g) {\n    new A(_a, _b, _c, _d, _e, _f, _g);\n  }\n}\n\ncontract Script0 is Script {\n  function run() external {\n    vm.broadcast();\n    new B(msg.sender, 2 ** 32, -1 * (2 ** 32), keccak256(abi.encode(1)), true, \"abcdef\", \"hello\");\n  }\n}\n   \"#,\n    );\n\n    cmd\n        .forge_fuse()\n        .arg(\"script\")\n        .arg(script)\n        .args([\n            \"--tc\",\n            \"Script0\",\n            \"--sender\",\n            \"0x00a329c0648769A73afAc7F9381E08FB43dBEA72\",\n            \"--rpc-url\",\n            handle.http_endpoint().as_str(),\n        ])\n        .assert_success()\n        .stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n...\nScript ran successfully.\n\n## Setting up 1 EVM.\n\n==========================\n\nChain 31337\n\n[ESTIMATED_GAS_PRICE]\n\n[ESTIMATED_TOTAL_GAS_USED]\n\n[ESTIMATED_AMOUNT_REQUIRED]\n\n==========================\n\nSIMULATION COMPLETE. To broadcast these transactions, add --broadcast and wallet configuration(s) to the previous command. See forge script --help for more.\n\n[SAVED_TRANSACTIONS]\n\n[SAVED_SENSITIVE_VALUES]\n\n\n\"#]]);\n\n    let run_latest = foundry_common::fs::json_files(&prj.root().join(\"broadcast\"))\n        .find(|file| file.ends_with(\"run-latest.json\"))\n        .expect(\"No broadcast artifacts\");\n\n    let content = foundry_common::fs::read_to_string(run_latest).unwrap();\n\n    let transactions: Transactions = serde_json::from_str(&content).unwrap();\n    let transactions = transactions.transactions;\n    assert_eq!(transactions.len(), 1);\n    assert_eq!(\n        transactions[0].arguments,\n        vec![\n            \"0x00a329c0648769A73afAc7F9381E08FB43dBEA72\".to_string(),\n            \"4294967296\".to_string(),\n            \"-4294967296\".to_string(),\n            \"0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6\".to_string(),\n            \"true\".to_string(),\n            \"0x616263646566\".to_string(),\n            \"hello\".to_string(),\n        ]\n    );\n});\n\n// checks that skipping build\nforgetest_init!(can_execute_script_and_skip_contracts, |prj, cmd| {\n    let script = prj.add_source(\n        \"Foo\",\n        r#\"\ncontract Demo {\n    event log_string(string);\n    function run() external returns (uint256 result, uint8) {\n        emit log_string(\"script ran\");\n        return (255, 3);\n    }\n}\"#,\n    );\n    cmd.arg(\"script\")\n        .arg(script)\n        .args([\"--skip\", \"tests\", \"--skip\", TEMPLATE_CONTRACT])\n        .assert_success()\n        .stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\nScript ran successfully.\n[GAS]\n\n== Return ==\nresult: uint256 255\n1: uint8 3\n\n== Logs ==\n  script ran\n\n\"#]]);\n});\n\nforgetest_async!(can_run_script_with_empty_setup, |prj, cmd| {\n    let mut tester = ScriptTester::new_broadcast_without_endpoint(cmd, prj.root());\n\n    tester.add_sig(\"BroadcastEmptySetUp\", \"run()\").simulate(ScriptOutcome::OkNoEndpoint);\n});\n\nforgetest_async!(does_script_override_correctly, |prj, cmd| {\n    let mut tester = ScriptTester::new_broadcast_without_endpoint(cmd, prj.root());\n\n    tester.add_sig(\"CheckOverrides\", \"run()\").simulate(ScriptOutcome::OkNoEndpoint);\n});\n\nforgetest_async!(assert_tx_origin_is_not_overwritten, |prj, cmd| {\n    cmd.args([\"init\", \"--force\"])\n        .arg(prj.root())\n        .assert_success()\n        .stdout_eq(str![[r#\"\nInitializing [..]...\nInstalling forge-std in [..] (url: https://github.com/foundry-rs/forge-std, tag: None)\n    Installed forge-std[..]\n    Initialized forge project\n\n\"#]])\n        .stderr_eq(str![[r#\"\nWarning: Target directory is not empty, but `--force` was specified\n...\n\n\"#]]);\n\n    let script = prj.add_script(\n        \"ScriptTxOrigin.s.sol\",\n        r#\"\nimport { Script } from \"forge-std/Script.sol\";\n\ncontract ScriptTxOrigin is Script {\n    function run() public {\n        uint256 pk = 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80;\n        vm.startBroadcast(pk); // 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266\n\n        ContractA contractA = new ContractA();\n        ContractB contractB = new ContractB();\n\n        contractA.test(address(contractB));\n        contractB.method(0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266);\n\n        require(tx.origin == 0x1804c8AB1F12E6bbf3894d4083f33e07309d1f38);\n        vm.stopBroadcast();\n    }\n}\n\ncontract ContractA {\n    function test(address _contractB) public {\n        require(msg.sender == 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266, \"sender 1\");\n        require(tx.origin == 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266, \"origin 1\");\n        ContractB contractB = ContractB(_contractB);\n        ContractC contractC = new ContractC();\n        require(msg.sender == 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266, \"sender 2\");\n        require(tx.origin == 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266, \"origin 2\");\n        contractB.method(address(this));\n        contractC.method(address(this));\n        require(msg.sender == 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266, \"sender 3\");\n        require(tx.origin == 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266, \"origin 3\");\n    }\n}\n\ncontract ContractB {\n    function method(address sender) public view {\n        require(msg.sender == sender, \"sender\");\n        require(tx.origin == 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266, \"origin\");\n    }\n}\n\ncontract ContractC {\n    function method(address sender) public view {\n        require(msg.sender == sender, \"sender\");\n        require(tx.origin == 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266, \"origin\");\n    }\n}\n   \"#,\n    );\n\n    cmd.forge_fuse()\n        .arg(\"script\")\n        .arg(script)\n        .args([\"--tc\", \"ScriptTxOrigin\"])\n        .assert_success()\n        .stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\nScript ran successfully.\n[GAS]\n\nIf you wish to simulate on-chain transactions pass a RPC URL.\n\n\"#]]);\n});\n\nforgetest_async!(assert_can_create_multiple_contracts_with_correct_nonce, |prj, cmd| {\n    cmd.args([\"init\", \"--force\"])\n        .arg(prj.root())\n        .assert_success()\n        .stdout_eq(str![[r#\"\nInitializing [..]...\nInstalling forge-std in [..] (url: https://github.com/foundry-rs/forge-std, tag: None)\n    Installed forge-std[..]\n    Initialized forge project\n\n\"#]])\n        .stderr_eq(str![[r#\"\nWarning: Target directory is not empty, but `--force` was specified\n...\n\n\"#]]);\n\n    let script = prj.add_script(\n        \"ScriptTxOrigin.s.sol\",\n        r#\"\nimport {Script, console} from \"forge-std/Script.sol\";\n\ncontract Contract {\n  constructor() {\n    console.log(tx.origin);\n  }\n}\n\ncontract SubContract {\n  constructor() {\n    console.log(tx.origin);\n  }\n}\n\ncontract BadContract {\n  constructor() {\n    new SubContract();\n    console.log(tx.origin);\n  }\n}\ncontract NestedCreate is Script {\n  function run() public {\n    address sender = address(uint160(uint(keccak256(\"woops\"))));\n\n    vm.broadcast(sender);\n    new BadContract();\n\n    vm.broadcast(sender);\n    new Contract();\n  }\n}\n   \"#,\n    );\n\n    cmd.forge_fuse()\n        .arg(\"script\")\n        .arg(script)\n        .args([\"--tc\", \"NestedCreate\"])\n        .assert_success()\n        .stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\nScript ran successfully.\n[GAS]\n\n== Logs ==\n  0x159E2f2F1C094625A2c6c8bF59526d91454c2F3c\n  0x159E2f2F1C094625A2c6c8bF59526d91454c2F3c\n  0x159E2f2F1C094625A2c6c8bF59526d91454c2F3c\n\nIf you wish to simulate on-chain transactions pass a RPC URL.\n\n\"#]]);\n});\n\nforgetest_async!(assert_can_detect_target_contract_with_interfaces, |prj, cmd| {\n    let script = prj.add_script(\n        \"ScriptWithInterface.s.sol\",\n        r#\"\ncontract Script {\n  function run() external {}\n}\n\ninterface Interface {}\n            \"#,\n    );\n\n    cmd.arg(\"script\").arg(script).assert_success().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\nScript ran successfully.\n[GAS]\n\n\"#]]);\n});\n\nforgetest_async!(assert_can_detect_unlinked_target_with_libraries, |prj, cmd| {\n    let script = prj.add_script(\n        \"ScriptWithExtLib.s.sol\",\n        r#\"\nlibrary Lib {\n    function f() public {}\n}\n\ncontract Script {\n    function run() external {\n        Lib.f();\n    }\n}\n            \"#,\n    );\n\n    cmd.arg(\"script\").arg(script).assert_success().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\nScript ran successfully.\n[GAS]\n\nIf you wish to simulate on-chain transactions pass a RPC URL.\n\n\"#]]);\n});\n\nforgetest_async!(assert_can_resume_with_additional_contracts, |prj, cmd| {\n    let (_api, handle) = spawn(NodeConfig::test()).await;\n    let mut tester = ScriptTester::new_broadcast(cmd, &handle.http_endpoint(), prj.root());\n\n    tester\n        .add_deployer(0)\n        .add_sig(\"ScriptAdditionalContracts\", \"run()\")\n        .broadcast(ScriptOutcome::MissingWallet)\n        .load_private_keys(&[0])\n        .await\n        .resume(ScriptOutcome::OkBroadcast);\n});\n\nforgetest_async!(can_detect_contract_when_multiple_versions, |prj, cmd| {\n    foundry_test_utils::util::initialize(prj.root());\n\n    prj.add_script(\n        \"A.sol\",\n        &format!(\n            r#\"\npragma solidity {SOLC_VERSION};\nimport \"./B.sol\";\n\ncontract ScriptA {{}}\n\"#\n        ),\n    );\n\n    prj.add_script(\n        \"B.sol\",\n        &format!(\n            r#\"\npragma solidity >={OTHER_SOLC_VERSION} <={SOLC_VERSION};\nimport 'forge-std/Script.sol';\n\ncontract ScriptB is Script {{\n    function run() external {{\n        vm.broadcast();\n        address(0).call(\"\");\n    }}\n}}\n\"#\n        ),\n    );\n\n    prj.add_script(\n        \"C.sol\",\n        &format!(\n            r#\"\npragma solidity {OTHER_SOLC_VERSION};\nimport \"./B.sol\";\n\ncontract ScriptC {{}}\n\"#\n        ),\n    );\n\n    let mut tester = ScriptTester::new(cmd, None, prj.root(), \"script/B.sol\");\n    tester.cmd.forge_fuse().args([\"script\", \"script/B.sol\"]);\n    tester.simulate(ScriptOutcome::OkNoEndpoint);\n});\n\nforgetest_async!(can_sign_with_script_wallet_single, |prj, cmd| {\n    foundry_test_utils::util::initialize(prj.root());\n\n    let mut tester = ScriptTester::new_broadcast_without_endpoint(cmd, prj.root());\n    tester\n        .add_sig(\"ScriptSign\", \"run()\")\n        .load_private_keys(&[0])\n        .await\n        .simulate(ScriptOutcome::OkNoEndpoint);\n});\n\nforgetest_async!(can_sign_with_script_wallet_multiple, |prj, cmd| {\n    let mut tester = ScriptTester::new_broadcast_without_endpoint(cmd, prj.root());\n    let acc = tester.accounts_pub[0].to_checksum(None);\n    tester\n        .add_sig(\"ScriptSign\", \"run(address)\")\n        .arg(&acc)\n        .load_private_keys(&[0, 1, 2])\n        .await\n        .simulate(ScriptOutcome::OkRun);\n});\n\nforgetest_async!(fails_with_function_name_and_overloads, |prj, cmd| {\n    let script = prj.add_script(\n        \"Script.s.sol\",\n        r#\"\ncontract Script {\n    function run() external {}\n\n    function run(address,uint256) external {}\n}\n            \"#,\n    );\n\n    cmd.arg(\"script\").args([&script.to_string_lossy(), \"--sig\", \"run\"]);\n    cmd.assert_failure().stderr_eq(str![[r#\"\nError: Multiple functions with the same name `run` found in the ABI\n\n\"#]]);\n});\n\nforgetest_async!(can_decode_custom_errors, |prj, cmd| {\n    cmd.args([\"init\", \"--force\"])\n        .arg(prj.root())\n        .assert_success()\n        .stdout_eq(str![[r#\"\nInitializing [..]...\nInstalling forge-std in [..] (url: https://github.com/foundry-rs/forge-std, tag: None)\n    Installed forge-std[..]\n    Initialized forge project\n\n\"#]])\n        .stderr_eq(str![[r#\"\nWarning: Target directory is not empty, but `--force` was specified\n...\n\n\"#]]);\n\n    let script = prj.add_script(\n        \"CustomErrorScript.s.sol\",\n        r#\"\nimport { Script } from \"forge-std/Script.sol\";\n\ncontract ContractWithCustomError {\n    error CustomError();\n\n    constructor() {\n        revert CustomError();\n    }\n}\n\ncontract CustomErrorScript is Script {\n    ContractWithCustomError test;\n\n    function run() public {\n        test = new ContractWithCustomError();\n    }\n}\n\"#,\n    );\n\n    cmd.forge_fuse().arg(\"script\").arg(script).args([\"--tc\", \"CustomErrorScript\"]);\n    cmd.assert_failure().stderr_eq(str![[r#\"\nError: script failed: CustomError()\n\n\"#]]);\n});\n\n// https://github.com/foundry-rs/foundry/issues/7620\nforgetest_async!(can_run_zero_base_fee, |prj, cmd| {\n    foundry_test_utils::util::initialize(prj.root());\n    prj.add_script(\n        \"Foo\",\n        r#\"\nimport \"forge-std/Script.sol\";\n\ncontract SimpleScript is Script {\n    function run() external returns (bool success) {\n        vm.startBroadcast();\n        (success, ) = address(0).call(\"\");\n    }\n}\n   \"#,\n    );\n\n    let node_config = NodeConfig::test().with_base_fee(Some(0));\n    let (_api, handle) = spawn(node_config).await;\n    let dev = handle.dev_accounts().next().unwrap();\n\n    // Firstly run script with non-zero gas prices to ensure that eth_feeHistory contains non-zero\n    // values.\n    cmd.args([\n        \"script\",\n        \"SimpleScript\",\n        \"--fork-url\",\n        &handle.http_endpoint(),\n        \"--sender\",\n        format!(\"{dev:?}\").as_str(),\n        \"--broadcast\",\n        \"--unlocked\",\n        \"--with-gas-price\",\n        \"2000000\",\n        \"--priority-gas-price\",\n        \"100000\",\n        \"--non-interactive\",\n    ])\n    .assert_success()\n    .stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n...\nScript ran successfully.\n\n== Return ==\nsuccess: bool true\n\n## Setting up 1 EVM.\n\n==========================\n\nChain 31337\n\n[ESTIMATED_GAS_PRICE]\n\n[ESTIMATED_TOTAL_GAS_USED]\n\n[ESTIMATED_AMOUNT_REQUIRED]\n\n==========================\n\n\n==========================\n\nONCHAIN EXECUTION COMPLETE & SUCCESSFUL.\n\n[SAVED_TRANSACTIONS]\n\n[SAVED_SENSITIVE_VALUES]\n\n\n\"#]]).stderr_eq(str![[r#\"\nWarning: Script contains a transaction to 0x0000000000000000000000000000000000000000 which does not contain any code.\n\n\"#]]);\n\n    // Ensure that we can correctly estimate gas when base fee is zero but priority fee is not.\n    cmd.forge_fuse()\n        .args([\n            \"script\",\n            \"SimpleScript\",\n            \"--fork-url\",\n            &handle.http_endpoint(),\n            \"--sender\",\n            format!(\"{dev:?}\").as_str(),\n            \"--broadcast\",\n            \"--unlocked\",\n            \"--non-interactive\",\n        ])\n        .assert_success()\n        .stdout_eq(str![[r#\"\nNo files changed, compilation skipped\n...\nScript ran successfully.\n\n== Return ==\nsuccess: bool true\n\n## Setting up 1 EVM.\n\n==========================\n\nChain 31337\n\n[ESTIMATED_GAS_PRICE]\n\n[ESTIMATED_TOTAL_GAS_USED]\n\n[ESTIMATED_AMOUNT_REQUIRED]\n\n==========================\n\n\n==========================\n\nONCHAIN EXECUTION COMPLETE & SUCCESSFUL.\n\n[SAVED_TRANSACTIONS]\n\n[SAVED_SENSITIVE_VALUES]\n\n\n\"#]]).stderr_eq(str![[r#\"\nWarning: Script contains a transaction to 0x0000000000000000000000000000000000000000 which does not contain any code.\n\n\"#]]);\n});\n\n// Asserts that the script runs with expected non-output using `--quiet` flag\nforgetest_async!(adheres_to_quiet_flag, |prj, cmd| {\n    foundry_test_utils::util::initialize(prj.root());\n    prj.add_script(\n        \"Foo\",\n        r#\"\nimport \"forge-std/Script.sol\";\n\ncontract SimpleScript is Script {\n    function run() external returns (bool success) {\n        vm.startBroadcast();\n        (success, ) = address(0).call(\"\");\n    }\n}\n   \"#,\n    );\n\n    let (_api, handle) = spawn(NodeConfig::test()).await;\n\n    cmd.args([\n        \"script\",\n        \"SimpleScript\",\n        \"--fork-url\",\n        &handle.http_endpoint(),\n        \"--sender\",\n        \"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266\",\n        \"--broadcast\",\n        \"--unlocked\",\n        \"--non-interactive\",\n        \"--quiet\",\n    ])\n    .assert_empty_stdout();\n});\n\n// Asserts that the script runs with expected non-output using `--quiet` flag\nforgetest_async!(adheres_to_json_flag, |prj, cmd| {\n    foundry_test_utils::util::initialize(prj.root());\n    prj.add_script(\n        \"Foo\",\n        r#\"\nimport \"forge-std/Script.sol\";\n\ncontract SimpleScript is Script {\n    function run() external returns (bool success) {\n        vm.startBroadcast();\n        (success, ) = address(0).call(\"\");\n    }\n}\n   \"#,\n    );\n\n    let (_api, handle) = spawn(NodeConfig::test()).await;\n\n    cmd.args([\n        \"script\",\n        \"SimpleScript\",\n        \"--fork-url\",\n        &handle.http_endpoint(),\n        \"--sender\",\n        \"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266\",\n        \"--broadcast\",\n        \"--unlocked\",\n        \"--non-interactive\",\n        \"--json\",\n    ])\n    .assert_success()\n    .stdout_eq(str![[r#\"\n{\"logs\":[],\"returns\":{\"success\":{\"internal_type\":\"bool\",\"value\":\"true\"}},\"success\":true,\"raw_logs\":[],\"traces\":[[\"Deployment\",{\"arena\":[{\"parent\":null,\"children\":[],\"idx\":0,\"trace\":{\"depth\":0,\"success\":true,\"caller\":\"0x1804c8ab1f12e6bbf3894d4083f33e07309d1f38\",\"address\":\"0x5b73c5498c1e3b4dba84de0f1833c4a029d90519\",\"maybe_precompile\":false,\"selfdestruct_address\":null,\"selfdestruct_refund_target\":null,\"selfdestruct_transferred_value\":null,\"kind\":\"CREATE\",\"value\":\"0x0\",\"data\":\"[..]\",\"output\":\"[..]\",\"gas_used\":\"{...}\",\"gas_limit\":\"{...}\",\"gas_refund_counter\":0,\"status\":\"Return\",\"steps\":[],\"decoded\":{\"label\":\"SimpleScript\",\"return_data\":null,\"call_data\":null}},\"logs\":[],\"ordering\":[]}]}],[\"Execution\",{\"arena\":[{\"parent\":null,\"children\":[1,2],\"idx\":0,\"trace\":{\"depth\":0,\"success\":true,\"caller\":\"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266\",\"address\":\"0x5b73c5498c1e3b4dba84de0f1833c4a029d90519\",\"maybe_precompile\":null,\"selfdestruct_address\":null,\"selfdestruct_refund_target\":null,\"selfdestruct_transferred_value\":null,\"kind\":\"CALL\",\"value\":\"0x0\",\"data\":\"0xc0406226\",\"output\":\"0x0000000000000000000000000000000000000000000000000000000000000001\",\"gas_used\":\"{...}\",\"gas_limit\":1073720760,\"gas_refund_counter\":0,\"status\":\"Return\",\"steps\":[],\"decoded\":{\"label\":\"SimpleScript\",\"return_data\":\"true\",\"call_data\":{\"signature\":\"run()\",\"args\":[]}}},\"logs\":[],\"ordering\":[{\"Call\":0},{\"Call\":1}]},{\"parent\":0,\"children\":[],\"idx\":1,\"trace\":{\"depth\":1,\"success\":true,\"caller\":\"0x5b73c5498c1e3b4dba84de0f1833c4a029d90519\",\"address\":\"0x7109709ecfa91a80626ff3989d68f67f5b1dd12d\",\"maybe_precompile\":null,\"selfdestruct_address\":null,\"selfdestruct_refund_target\":null,\"selfdestruct_transferred_value\":null,\"kind\":\"CALL\",\"value\":\"0x0\",\"data\":\"0x7fb5297f\",\"output\":\"0x\",\"gas_used\":\"{...}\",\"gas_limit\":1056940999,\"gas_refund_counter\":0,\"status\":\"Return\",\"steps\":[],\"decoded\":{\"label\":\"VM\",\"return_data\":null,\"call_data\":{\"signature\":\"startBroadcast()\",\"args\":[]}}},\"logs\":[],\"ordering\":[]},{\"parent\":0,\"children\":[],\"idx\":2,\"trace\":{\"depth\":1,\"success\":true,\"caller\":\"0x5b73c5498c1e3b4dba84de0f1833c4a029d90519\",\"address\":\"0x0000000000000000000000000000000000000000\",\"maybe_precompile\":null,\"selfdestruct_address\":null,\"selfdestruct_refund_target\":null,\"selfdestruct_transferred_value\":null,\"kind\":\"CALL\",\"value\":\"0x0\",\"data\":\"0x\",\"output\":\"0x\",\"gas_used\":\"{...}\",\"gas_limit\":1056940650,\"gas_refund_counter\":0,\"status\":\"Stop\",\"steps\":[],\"decoded\":{\"label\":null,\"return_data\":null,\"call_data\":null}},\"logs\":[],\"ordering\":[]}]}]],\"gas_used\":\"{...}\",\"labeled_addresses\":{},\"returned\":\"0x0000000000000000000000000000000000000000000000000000000000000001\",\"address\":null}\n{\"chain\":31337,\"estimated_gas_price\":\"{...}\",\"estimated_total_gas_used\":\"{...}\",\"estimated_amount_required\":\"{...}\",\"token_symbol\":\"ETH\"}\n{\"chain\":\"anvil-hardhat\",\"status\":\"success\",\"tx_hash\":\"0x4f78afe915fceb282c7625a68eb350bc0bf78acb59ad893e5c62b710a37f3156\",\"contract_address\":null,\"block_number\":1,\"gas_used\":\"{...}\",\"gas_price\":\"{...}\"}\n{\"status\":\"success\",\"transactions\":\"[..]/broadcast/Foo.sol/31337/run-latest.json\",\"sensitive\":\"[..]/cache/Foo.sol/31337/run-latest.json\"}\n\n\"#]].is_jsonlines());\n});\n\n// https://github.com/foundry-rs/foundry/pull/7742\nforgetest_async!(unlocked_no_sender, |prj, cmd| {\n    foundry_test_utils::util::initialize(prj.root());\n    prj.add_script(\n        \"Foo\",\n        r#\"\nimport \"forge-std/Script.sol\";\n\ncontract SimpleScript is Script {\n    function run() external returns (bool success) {\n        vm.startBroadcast(0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266);\n        (success, ) = address(0).call(\"\");\n    }\n}\n   \"#,\n    );\n\n    let (_api, handle) = spawn(NodeConfig::test()).await;\n\n    cmd.args([\n        \"script\",\n        \"SimpleScript\",\n        \"--fork-url\",\n        &handle.http_endpoint(),\n        \"--broadcast\",\n        \"--unlocked\",\n        \"--non-interactive\",\n    ])\n    .assert_success()\n    .stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n...\nScript ran successfully.\n\n== Return ==\nsuccess: bool true\n\n## Setting up 1 EVM.\n\n==========================\n\nChain 31337\n\n[ESTIMATED_GAS_PRICE]\n\n[ESTIMATED_TOTAL_GAS_USED]\n\n[ESTIMATED_AMOUNT_REQUIRED]\n\n==========================\n\n\n==========================\n\nONCHAIN EXECUTION COMPLETE & SUCCESSFUL.\n\n[SAVED_TRANSACTIONS]\n\n[SAVED_SENSITIVE_VALUES]\n\n\n\"#]]).stderr_eq(str![[r#\"\nWarning: Script contains a transaction to 0x0000000000000000000000000000000000000000 which does not contain any code.\n\n\"#]]);\n});\n\n// https://github.com/foundry-rs/foundry/issues/7833\nforgetest_async!(error_no_create2, |prj, cmd| {\n    let (_api, handle) =\n        spawn(NodeConfig::test().with_disable_default_create2_deployer(true)).await;\n\n    foundry_test_utils::util::initialize(prj.root());\n    prj.add_script(\n        \"Foo\",\n        r#\"\nimport \"forge-std/Script.sol\";\n\ncontract SimpleContract {}\n\ncontract SimpleScript is Script {\n    function run() external {\n        vm.startBroadcast(0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266);\n        new SimpleContract{salt: bytes32(0)}();\n    }\n}\n   \"#,\n    );\n\n    cmd.args([\n        \"script\",\n        \"SimpleScript\",\n        \"--fork-url\",\n        &handle.http_endpoint(),\n        \"--broadcast\",\n        \"--unlocked\",\n    ]);\n\n    cmd.assert_failure().stderr_eq(str![[r#\"\nError: script failed: missing CREATE2 deployer: 0x4e59b44847b379578588920cA78FbF26c0B4956C\n\n\"#]]);\n});\n\nforgetest_async!(can_switch_forks_in_setup, |prj, cmd| {\n    let (_api, handle) =\n        spawn(NodeConfig::test().with_disable_default_create2_deployer(true)).await;\n\n    foundry_test_utils::util::initialize(prj.root());\n    let url = handle.http_endpoint();\n\n    prj.add_script(\n        \"Foo\",\n        &r#\"\nimport \"forge-std/Script.sol\";\n\ncontract SimpleScript is Script {\n    function setUp() external {\n        uint256 initialFork = vm.activeFork();\n        vm.createSelectFork(\"<url>\");\n        vm.selectFork(initialFork);\n    }\n\n    function run() external {\n        assert(vm.getNonce(msg.sender) == 0);\n    }\n}\n   \"#\n        .replace(\"<url>\", &url),\n    );\n\n    cmd.args([\n        \"script\",\n        \"SimpleScript\",\n        \"--fork-url\",\n        &url,\n        \"--sender\",\n        \"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266\",\n    ])\n    .assert_success()\n    .stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful with warnings:\nWarning (2018): Function state mutability can be restricted to view\n  [FILE]:13:5:\n   |\n13 |     function run() external {\n   |     ^ (Relevant source part starts here and spans across multiple lines).\n\nScript ran successfully.\n\n\"#]]);\n});\n\n// Asserts that running the same script twice only deploys library once.\nforgetest_async!(can_deploy_library_create2, |prj, cmd| {\n    let (_api, handle) = spawn(NodeConfig::test()).await;\n\n    let mut tester = ScriptTester::new_broadcast(cmd, &handle.http_endpoint(), prj.root());\n\n    tester\n        .load_private_keys(&[0, 1])\n        .await\n        .add_sig(\"BroadcastTest\", \"deploy()\")\n        .simulate(ScriptOutcome::OkSimulation)\n        .broadcast(ScriptOutcome::OkBroadcast)\n        .assert_nonce_increment(&[(0, 2), (1, 1)])\n        .await;\n\n    tester.clear();\n\n    tester\n        .load_private_keys(&[0, 1])\n        .await\n        .add_sig(\"BroadcastTest\", \"deploy()\")\n        .simulate(ScriptOutcome::OkSimulation)\n        .broadcast(ScriptOutcome::OkBroadcast)\n        .assert_nonce_increment(&[(0, 1), (1, 1)])\n        .await;\n});\n\n// Asserts that running the same script twice only deploys library once when using different\n// senders.\nforgetest_async!(can_deploy_library_create2_different_sender, |prj, cmd| {\n    let (_api, handle) = spawn(NodeConfig::test()).await;\n\n    let mut tester = ScriptTester::new_broadcast(cmd, &handle.http_endpoint(), prj.root());\n\n    tester\n        .load_private_keys(&[0, 1])\n        .await\n        .add_sig(\"BroadcastTest\", \"deploy()\")\n        .simulate(ScriptOutcome::OkSimulation)\n        .broadcast(ScriptOutcome::OkBroadcast)\n        .assert_nonce_increment(&[(0, 2), (1, 1)])\n        .await;\n\n    tester.clear();\n\n    // Run different script from the same contract (which requires the same library).\n    tester\n        .load_private_keys(&[2])\n        .await\n        .add_sig(\"BroadcastTest\", \"deployNoArgs()\")\n        .simulate(ScriptOutcome::OkSimulation)\n        .broadcast(ScriptOutcome::OkBroadcast)\n        .assert_nonce_increment(&[(2, 2)])\n        .await;\n});\n\n// <https://github.com/foundry-rs/foundry/issues/8993>\nforgetest_async!(test_broadcast_raw_create2_deployer, |prj, cmd| {\n    let (api, handle) = spawn(NodeConfig::test().with_disable_default_create2_deployer(true)).await;\n\n    foundry_test_utils::util::initialize(prj.root());\n    prj.add_script(\n        \"Foo\",\n        r#\"\nimport \"forge-std/Script.sol\";\n\ncontract SimpleScript is Script {\n    function run() external {\n        // send funds to create2 factory deployer\n        vm.startBroadcast();\n        payable(0x3fAB184622Dc19b6109349B94811493BF2a45362).transfer(10000000 gwei);\n        // deploy create2 factory\n        vm.broadcastRawTransaction(\n            hex\"f8a58085174876e800830186a08080b853604580600e600039806000f350fe7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf31ba02222222222222222222222222222222222222222222222222222222222222222a02222222222222222222222222222222222222222222222222222222222222222\"\n        );\n    }\n}\n   \"#,\n    );\n\n    cmd.args([\n        \"script\",\n        \"--private-key\",\n        \"0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80\",\n        \"--rpc-url\",\n        &handle.http_endpoint(),\n        \"--broadcast\",\n        \"--slow\",\n        \"SimpleScript\",\n    ]);\n\n    cmd.assert_success().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\nScript ran successfully.\n\n## Setting up 1 EVM.\n\n==========================\n\nChain 31337\n\n[ESTIMATED_GAS_PRICE]\n\n[ESTIMATED_TOTAL_GAS_USED]\n\n[ESTIMATED_AMOUNT_REQUIRED]\n\n==========================\n\n\n==========================\n\nONCHAIN EXECUTION COMPLETE & SUCCESSFUL.\n\n[SAVED_TRANSACTIONS]\n\n[SAVED_SENSITIVE_VALUES]\n\n\n\"#]]);\n\n    assert!(\n        !api.get_code(address!(\"0x4e59b44847b379578588920cA78FbF26c0B4956C\"), Default::default())\n            .await\n            .unwrap()\n            .is_empty()\n    );\n});\n\nforgetest_init!(can_get_script_wallets, |prj, cmd| {\n    let script = prj.add_source(\n        \"Foo\",\n        r#\"\nimport \"forge-std/Script.sol\";\n\ninterface Vm {\n    function getWallets() external view returns (address[] memory wallets);\n}\n\ncontract WalletScript is Script {\n    function run() public view {\n        address[] memory wallets = Vm(address(vm)).getWallets();\n        console.log(wallets[0]);\n    }\n}\"#,\n    );\n    cmd.arg(\"script\")\n        .arg(script)\n        .args([\n            \"--private-key\",\n            \"0x2a871d0798f97d79848a013d4936a73bf4cc922c825d33c1cf7073dff6d409c6\",\n            \"-v\",\n        ])\n        .assert_success()\n        .stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\nScript ran successfully.\n[GAS]\n\n== Logs ==\n  0xa0Ee7A142d267C1f36714E4a8F75612F20a79720\n\n\"#]]);\n});\n\nforgetest_init!(can_remember_keys, |prj, cmd| {\n    let script = prj\n        .add_source(\n            \"Foo\",\n            r#\"\nimport \"forge-std/Script.sol\";\n\ninterface Vm {\n    function rememberKeys(string calldata mnemonic, string calldata derivationPath, uint32 count) external returns (address[] memory keyAddrs);\n}\n\ncontract WalletScript is Script {\n    function run() public {\n        string memory mnemonic = \"test test test test test test test test test test test junk\";\n        string memory derivationPath = \"m/44'/60'/0'/0/\";\n        address[] memory wallets = Vm(address(vm)).rememberKeys(mnemonic, derivationPath, 3);\n        for (uint256 i = 0; i < wallets.length; i++) {\n            console.log(wallets[i]);\n        }\n    }\n}\"#,\n        );\n    cmd.arg(\"script\").arg(script).assert_success().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\nScript ran successfully.\n[GAS]\n\n== Logs ==\n  0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266\n  0x70997970C51812dc3A010C7d01b50e0d17dc79C8\n  0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC\n\n\"#]]);\n});\n\nforgetest_async!(can_simulate_with_default_sender, |prj, cmd| {\n    let (_api, handle) = spawn(NodeConfig::test()).await;\n\n    foundry_test_utils::util::initialize(prj.root());\n    prj.add_script(\n        \"Script.s.sol\",\n        r#\"\nimport \"forge-std/Script.sol\";\ncontract A {\n    function getValue() external pure returns (uint256) {\n        return 100;\n    }\n}\ncontract B {\n    constructor(A a) {\n        require(a.getValue() == 100);\n    }\n}\ncontract SimpleScript is Script {\n    function run() external {\n        vm.startBroadcast();\n        A a = new A();\n        new B(a);\n    }\n}\n            \"#,\n    );\n\n    cmd.arg(\"script\").args([\"SimpleScript\", \"--fork-url\", &handle.http_endpoint(), \"-vvvv\"]);\n    cmd.assert_success().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\nTraces:\n  [..] SimpleScript::run()\n    ├─ [0] VM::startBroadcast()\n    │   └─ ← [Return]\n    ├─ [..] → new A@0x5b73C5498c1E3b4dbA84de0F1833c4a029d90519\n    │   └─ ← [Return] 175 bytes of code\n    ├─ [..] → new B@0x7FA9385bE102ac3EAc297483Dd6233D62b3e1496\n    │   ├─ [..] A::getValue() [staticcall]\n    │   │   └─ ← [Return] 100\n    │   └─ ← [Return] 62 bytes of code\n    └─ ← [Stop]\n\n\nScript ran successfully.\n\n## Setting up 1 EVM.\n==========================\nSimulated On-chain Traces:\n\n  [..] → new A@0x5b73C5498c1E3b4dbA84de0F1833c4a029d90519\n    └─ ← [Return] 175 bytes of code\n\n  [..] → new B@0x7FA9385bE102ac3EAc297483Dd6233D62b3e1496\n    ├─ [..] A::getValue() [staticcall]\n    │   └─ ← [Return] 100\n    └─ ← [Return] 62 bytes of code\n...\n\"#]]);\n});\n\nforgetest_async!(should_detect_additional_contracts, |prj, cmd| {\n    let (_api, handle) = spawn(NodeConfig::test()).await;\n\n    foundry_test_utils::util::initialize(prj.root());\n    prj.add_source(\n        \"Foo\",\n        r#\"\nimport \"forge-std/Script.sol\";\n\ncontract Simple {}\n\ncontract Deployer {\n    function deploy() public {\n        new Simple();\n    }\n}\n\ncontract ContractScript is Script {\n    function run() public {\n        vm.startBroadcast();\n        Deployer deployer = new Deployer();\n        deployer.deploy();\n    }\n}\n   \"#,\n    );\n    cmd.arg(\"script\")\n        .args([\n            \"ContractScript\",\n            \"--private-key\",\n            \"0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80\",\n            \"--rpc-url\",\n            &handle.http_endpoint(),\n        ])\n        .assert_success();\n\n    let run_latest = foundry_common::fs::json_files(&prj.root().join(\"broadcast\"))\n        .find(|file| file.ends_with(\"run-latest.json\"))\n        .expect(\"No broadcast artifacts\");\n\n    let sequence: ScriptSequence<Ethereum> =\n        foundry_common::fs::read_json_file(&run_latest).unwrap();\n\n    assert_eq!(sequence.transactions.len(), 2);\n    assert_eq!(sequence.transactions[1].additional_contracts.len(), 1);\n});\n\n// <https://github.com/foundry-rs/foundry/issues/9661>\nforgetest_async!(should_set_correct_sender_nonce_via_cli, |prj, cmd| {\n    foundry_test_utils::util::initialize(prj.root());\n    prj.add_script(\n        \"MyScript.s.sol\",\n        r#\"\n        import {Script, console} from \"forge-std/Script.sol\";\n\n    contract MyScript is Script {\n        function run() public view {\n            console.log(\"sender nonce\", vm.getNonce(msg.sender));\n        }\n    }\n    \"#,\n    );\n\n    let rpc_url = next_http_archive_rpc_url();\n\n    let fork_bn = 21614115;\n\n    cmd.forge_fuse()\n        .args([\n            \"script\",\n            \"MyScript\",\n            \"--sender\",\n            \"0x4838B106FCe9647Bdf1E7877BF73cE8B0BAD5f97\",\n            \"--fork-block-number\",\n            &fork_bn.to_string(),\n            \"--rpc-url\",\n            &rpc_url,\n        ])\n        .assert_success()\n        .stdout_eq(str![[r#\"[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\n...\n== Logs ==\n  sender nonce 1124703[..]\"#]]);\n});\n\nforgetest_async!(dryrun_without_broadcast, |prj, cmd| {\n    let (_api, handle) = spawn(NodeConfig::test()).await;\n\n    foundry_test_utils::util::initialize(prj.root());\n    prj.add_source(\n        \"Foo\",\n        r#\"\nimport \"forge-std/Script.sol\";\n\ncontract Called {\n    event log_string(string);\n    uint256 public x;\n    uint256 public y;\n    function run(uint256 _x, uint256 _y) external {\n        x = _x;\n        y = _y;\n        emit log_string(\"script ran\");\n    }\n}\n\ncontract DryRunTest is Script {\n    function run() external {\n        vm.startBroadcast();\n        Called called = new Called();\n        called.run(123, 456);\n    }\n}\n   \"#,\n    );\n\n    cmd.arg(\"script\")\n        .args([\n            \"DryRunTest\",\n            \"--private-key\",\n            \"0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80\",\n            \"--rpc-url\",\n            &handle.http_endpoint(),\n            \"-vvvv\",\n        ])\n        .assert_success()\n        .stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\nTraces:\n  [..] DryRunTest::run()\n    ├─ [0] VM::startBroadcast()\n    │   └─ ← [Return]\n    ├─ [..] → new Called@0x5FbDB2315678afecb367f032d93F642f64180aa3\n    │   └─ ← [Return] 567 bytes of code\n    ├─ [..] Called::run(123, 456)\n    │   ├─ emit log_string(val: \"script ran\")\n    │   └─ ← [Stop]\n    └─ ← [Stop]\n\n\nScript ran successfully.\n\n== Logs ==\n  script ran\n\n## Setting up 1 EVM.\n==========================\nSimulated On-chain Traces:\n\n  [113557] → new Called@0x5FbDB2315678afecb367f032d93F642f64180aa3\n    └─ ← [Return] 567 bytes of code\n\n  [46595] Called::run(123, 456)\n    ├─ emit log_string(val: \"script ran\")\n    └─ ← [Stop]\n\n\n==========================\n\nChain 31337\n\n[ESTIMATED_GAS_PRICE]\n\n[ESTIMATED_TOTAL_GAS_USED]\n\n[ESTIMATED_AMOUNT_REQUIRED]\n\n==========================\n\n=== Transactions that will be broadcast ===\n\n\nChain 31337\n\n### Transaction 1 ###\n\naccessList           []\nchainId              31337\ngasLimit             [..]\ngasPrice             \ninput                [..]\nmaxFeePerBlobGas     \nmaxFeePerGas         \nmaxPriorityFeePerGas \nnonce                0\nto                   \ntype                 EIP-1559\nvalue                0\n\n### Transaction 2 ###\n\naccessList           []\nchainId              31337\ngasLimit             93856\ngasPrice             \ninput                0x7357f5d2000000000000000000000000000000000000000000000000000000000000007b00000000000000000000000000000000000000000000000000000000000001c8\nmaxFeePerBlobGas     \nmaxFeePerGas         \nmaxPriorityFeePerGas \nnonce                1\nto                   0x5FbDB2315678afecb367f032d93F642f64180aa3\ntype                 EIP-1559\nvalue                0\ncontract: Called(0x5FbDB2315678afecb367f032d93F642f64180aa3)\ndata (decoded): run(uint256,uint256)(\n  123,\n  456\n)\n\n\nSIMULATION COMPLETE. To broadcast these transactions, add --broadcast and wallet configuration(s) to the previous command. See forge script --help for more.\n\n[SAVED_TRANSACTIONS]\n\n[SAVED_SENSITIVE_VALUES]\n\n\n\"#]]);\n});\n\n// Tests warn when artifact source file no longer exists.\n// <https://github.com/foundry-rs/foundry/issues/9068>\nforgetest_init!(should_warn_if_artifact_source_no_longer_exists, |prj, cmd| {\n    prj.initialize_default_contracts();\n    cmd.args([\"script\", \"script/Counter.s.sol\"]).assert_success().stdout_eq(str![[r#\"\n...\nScript ran successfully.\n...\n\n\"#]]);\n    fs::rename(\n        prj.paths().scripts.join(\"Counter.s.sol\"),\n        prj.paths().scripts.join(\"Counter1.s.sol\"),\n    )\n    .unwrap();\n    cmd.forge_fuse().args([\"script\", \"script/Counter1.s.sol\"]).assert_success().stderr_eq(str![[r#\"\n...\nWarning: Detected artifacts built from source files that no longer exist. Run `forge clean` to make sure builds are in sync with project files.\n - [..]script/Counter.s.sol\n...\n\n\"#]])\n        .stdout_eq(str![[r#\"\n...\nScript ran successfully.\n...\n\n\"#]]);\n});\n\n// Tests that script reverts if it uses `address(this)`.\nforgetest_init!(should_revert_on_address_opcode, |prj, cmd| {\n    prj.add_script(\n        \"ScriptWithAddress.s.sol\",\n        r#\"\n        import {Script, console} from \"forge-std/Script.sol\";\n\n    contract ScriptWithAddress is Script {\n        function run() public view {\n            console.log(\"script address\", address(this));\n        }\n    }\n    \"#,\n    );\n\n    cmd.arg(\"script\").arg(\"ScriptWithAddress\").assert_failure().stderr_eq(str![[r#\"\nError: script failed: Usage of `address(this)` detected in script contract. Script contracts are ephemeral and their addresses should not be relied upon.\n\n\"#]]);\n\n    // Disable script protection.\n    prj.update_config(|config| {\n        config.script_execution_protection = false;\n    });\n    cmd.assert_success().stdout_eq(str![[r#\"\n...\nScript ran successfully.\n...\n\n\"#]]);\n});\n\n// Tests that script warns if no tx to broadcast.\n// <https://github.com/foundry-rs/foundry/issues/10015>\nforgetest_async!(warns_if_no_transactions_to_broadcast, |prj, cmd| {\n    let (_api, handle) = spawn(NodeConfig::test()).await;\n    foundry_test_utils::util::initialize(prj.root());\n    prj.add_script(\n        \"NoTxScript.s.sol\",\n        r#\"\n        import {Script} from \"forge-std/Script.sol\";\n\n    contract NoTxScript is Script {\n        function run() public {\n            vm.startBroadcast();\n            // No real tx created\n            vm.stopBroadcast();\n        }\n    }\n    \"#,\n    );\n\n    cmd.args([\n        \"script\",\n        \"--private-key\",\n        \"0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80\",\n        \"--rpc-url\",\n        &handle.http_endpoint(),\n        \"--broadcast\",\n        \"NoTxScript\",\n    ])\n    .assert_success()\n    .stderr_eq(str![\n        r#\"\nWarning: No transactions to broadcast.\n\n\"#\n    ]);\n});\n\n// Tests EIP-7702 broadcast <https://github.com/foundry-rs/foundry/issues/10461>\nforgetest_async!(can_broadcast_txes_with_signed_auth, |prj, cmd| {\n    foundry_test_utils::util::initialize(prj.root());\n    prj.initialize_default_contracts();\n    prj.add_script(\n            \"EIP7702Script.s.sol\",\n            r#\"\nimport \"forge-std/Script.sol\";\nimport {Vm} from \"forge-std/Vm.sol\";\nimport {Counter} from \"../src/Counter.sol\";\ncontract EIP7702Script is Script {\n    uint256 constant PRIVATE_KEY = uint256(bytes32(0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80));\n    address constant SENDER = 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266;\n    function setUp() public {}\n    function run() public {\n        vm.startBroadcast(PRIVATE_KEY);\n        Counter counter = new Counter();\n        Counter counter1 = new Counter();\n        Counter counter2 = new Counter();\n        vm.signAndAttachDelegation(address(counter), PRIVATE_KEY);\n        Counter(SENDER).increment();\n        Counter(SENDER).increment();\n        vm.signAndAttachDelegation(address(counter1), PRIVATE_KEY);\n        Counter(SENDER).setNumber(0);\n        vm.signAndAttachDelegation(address(counter2), PRIVATE_KEY);\n        Counter(SENDER).setNumber(0);\n        vm.stopBroadcast();\n    }\n}\n   \"#,\n        );\n\n    let node_config = NodeConfig::test().with_hardfork(Some(EthereumHardfork::Prague.into()));\n    let (_api, handle) = spawn(node_config).await;\n\n    cmd.args([\n        \"script\",\n        \"script/EIP7702Script.s.sol\",\n        \"--rpc-url\",\n        &handle.http_endpoint(),\n        \"-vvvvv\",\n        \"--non-interactive\",\n        \"--slow\",\n        \"--broadcast\",\n        \"--evm-version\",\n        \"prague\",\n    ])\n    .assert_success()\n    .stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\nTraces:\n  [..] EIP7702Script::setUp()\n    └─ ← [Stop]\n\n  [..] EIP7702Script::run()\n    ├─ [0] VM::startBroadcast(<pk>)\n    │   └─ ← [Return]\n    ├─ [..] → new Counter@0x5FbDB2315678afecb367f032d93F642f64180aa3\n    │   └─ ← [Return] 481 bytes of code\n    ├─ [..] → new Counter@0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512\n    │   └─ ← [Return] 481 bytes of code\n    ├─ [..] → new Counter@0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0\n    │   └─ ← [Return] 481 bytes of code\n    ├─ [0] VM::signAndAttachDelegation(0x5FbDB2315678afecb367f032d93F642f64180aa3, \"<pk>\")\n    │   └─ ← [Return] (0, 0xd4301eb9f82f747137a5f2c3dc3a5c2d253917cf99ecdc0d49f7bb85313c3159, 0x786d354f0bbd456f44116ddd3aa50475e989d72d8396005e5b3a12cede83fb68, 4, 0x5FbDB2315678afecb367f032d93F642f64180aa3)\n    ├─ [..] 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266::increment()\n    │   └─ ← [Stop]\n    ├─ [..] 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266::increment()\n    │   └─ ← [Stop]\n    ├─ [0] VM::signAndAttachDelegation(0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512, \"<pk>\")\n    │   └─ ← [Return] (0, 0xaba9128338f7ff036a0d2ecb96d4f4376389005cd565f87aba33b312570af962, 0x69acbe0831fb8ca95338bc4b908dcfebaf7b81b0f770a12c073ceb07b89fbdf3, 7, 0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512)\n    ├─ [..] 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266::setNumber(0)\n    │   └─ ← [Stop]\n    ├─ [0] VM::signAndAttachDelegation(0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0, \"<pk>\")\n    │   └─ ← [Return] (1, 0x3a3427b66e589338ce7ea06135650708f9152e93e257b4a5ec6eb86a3e09a2ce, 0x444651c354c89fd3312aafb05948e12c0a16220827a5e467705253ab4d8aa8d3, 9, 0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0)\n    ├─ [..] 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266::setNumber(0)\n    │   └─ ← [Stop]\n    ├─ [0] VM::stopBroadcast()\n    │   └─ ← [Return]\n    └─ ← [Stop]\n\n\nScript ran successfully.\n\n## Setting up 1 EVM.\n==========================\nSimulated On-chain Traces:\n\n  [..] → new Counter@0x5FbDB2315678afecb367f032d93F642f64180aa3\n    └─ ← [Return] 481 bytes of code\n\n  [..] → new Counter@0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512\n    └─ ← [Return] 481 bytes of code\n\n  [..] → new Counter@0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0\n    └─ ← [Return] 481 bytes of code\n\n  [..] 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266::increment()\n    └─ ← [Stop]\n\n  [..] 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266::increment()\n    └─ ← [Stop]\n\n  [..] 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266::setNumber(0)\n    └─ ← [Stop]\n\n  [..] 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266::setNumber(0)\n    └─ ← [Stop]\n\n\n==========================\n\nChain 31337\n\n[ESTIMATED_GAS_PRICE]\n\n[ESTIMATED_TOTAL_GAS_USED]\n\n[ESTIMATED_AMOUNT_REQUIRED]\n\n==========================\n\n\n==========================\n\nONCHAIN EXECUTION COMPLETE & SUCCESSFUL.\n\n[SAVED_TRANSACTIONS]\n\n[SAVED_SENSITIVE_VALUES]\n\n\n\"#]]);\n});\n\n// Tests EIP-7702 with multiple auth <https://github.com/foundry-rs/foundry/issues/10551>\n// Alice sends 5 ETH from Bob to Receiver1 and 1 ETH to Receiver2\nforgetest_async!(can_broadcast_txes_with_multiple_auth, |prj, cmd| {\n    foundry_test_utils::util::initialize(prj.root());\n    prj.add_source(\n        \"BatchCallDelegation.sol\",\n        r#\"\ncontract BatchCallDelegation {\n    event CallExecuted(address indexed to, uint256 indexed value, bytes data, bool success);\n\n    struct Call {\n        bytes data;\n        address to;\n        uint256 value;\n    }\n\n    function execute(Call[] calldata calls) external payable {\n        for (uint256 i = 0; i < calls.length; i++) {\n            Call memory call = calls[i];\n            (bool success,) = call.to.call{value: call.value}(call.data);\n            require(success, \"call reverted\");\n            emit CallExecuted(call.to, call.value, call.data, success);\n        }\n    }\n}\n   \"#,\n    );\n\n    prj.add_script(\n            \"BatchCallDelegationScript.s.sol\",\n            r#\"\nimport {Script, console} from \"forge-std/Script.sol\";\nimport {Vm} from \"forge-std/Vm.sol\";\nimport {BatchCallDelegation} from \"../src/BatchCallDelegation.sol\";\n\ncontract BatchCallDelegationScript is Script {\n    // Alice's address and private key (EOA with no initial contract code).\n    address payable ALICE_ADDRESS = payable(0x70997970C51812dc3A010C7d01b50e0d17dc79C8);\n    uint256 constant ALICE_PK = 0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d;\n\n    // Bob's address and private key (Bob will execute transactions on Alice's behalf).\n    address constant BOB_ADDRESS = 0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC;\n    uint256 constant BOB_PK = 0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a;\n\n    address constant RECEIVER_1 = 0x14dC79964da2C08b23698B3D3cc7Ca32193d9955;\n    address constant RECEIVER_2 = 0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc;\n\n    uint256 constant DEPLOYER_PK = 0x2a871d0798f97d79848a013d4936a73bf4cc922c825d33c1cf7073dff6d409c6;\n\n    function run() public {\n        BatchCallDelegation.Call[] memory aliceCalls = new BatchCallDelegation.Call[](1);\n        aliceCalls[0] = BatchCallDelegation.Call({to: RECEIVER_1, value: 5 ether, data: \"\"});\n\n        BatchCallDelegation.Call[] memory bobCalls = new BatchCallDelegation.Call[](2);\n        bobCalls[0] = BatchCallDelegation.Call({to: RECEIVER_1, value: 5 ether, data: \"\"});\n        bobCalls[1] = BatchCallDelegation.Call({to: RECEIVER_2, value: 1 ether, data: \"\"});\n\n        vm.startBroadcast(DEPLOYER_PK);\n        BatchCallDelegation batcher = new BatchCallDelegation();\n        vm.stopBroadcast();\n\n        vm.startBroadcast(ALICE_PK);\n        vm.signAndAttachDelegation(address(batcher), ALICE_PK);\n        vm.signAndAttachDelegation(address(batcher), BOB_PK);\n        vm.signAndAttachDelegation(address(batcher), BOB_PK);\n\n        BatchCallDelegation(BOB_ADDRESS).execute(bobCalls);\n\n        vm.stopBroadcast();\n    }\n}\n   \"#,\n        );\n\n    let node_config = NodeConfig::test().with_hardfork(Some(EthereumHardfork::Prague.into()));\n    let (api, handle) = spawn(node_config).await;\n\n    cmd.args([\n        \"script\",\n        \"script/BatchCallDelegationScript.s.sol\",\n        \"--rpc-url\",\n        &handle.http_endpoint(),\n        \"--non-interactive\",\n        \"--slow\",\n        \"--broadcast\",\n        \"--evm-version\",\n        \"prague\",\n    ])\n    .assert_success()\n    .stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\nScript ran successfully.\n\n## Setting up 1 EVM.\n\n==========================\n\nChain 31337\n\n[ESTIMATED_GAS_PRICE]\n\n[ESTIMATED_TOTAL_GAS_USED]\n\n[ESTIMATED_AMOUNT_REQUIRED]\n\n==========================\n\n\n==========================\n\nONCHAIN EXECUTION COMPLETE & SUCCESSFUL.\n\n[SAVED_TRANSACTIONS]\n\n[SAVED_SENSITIVE_VALUES]\n\n\n\"#]]);\n\n    // Alice nonce should be 2 (tx sender and one auth)\n    let alice_acc = api\n        .get_account(address!(\"0x70997970C51812dc3A010C7d01b50e0d17dc79C8\"), None)\n        .await\n        .unwrap();\n    assert_eq!(alice_acc.nonce, 2);\n\n    // Bob nonce should be 2 (two auths) and balance reduced by 6 ETH.\n    let bob_acc = api\n        .get_account(address!(\"0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC\"), None)\n        .await\n        .unwrap();\n    assert_eq!(bob_acc.nonce, 2);\n    assert_eq!(bob_acc.balance.to_string(), \"94000000000000000000\");\n\n    // Receiver balances should be updated with 5 ETH and 1 ETH.\n    let receiver1 = api\n        .get_account(address!(\"0x14dC79964da2C08b23698B3D3cc7Ca32193d9955\"), None)\n        .await\n        .unwrap();\n    assert_eq!(receiver1.nonce, 0);\n    assert_eq!(receiver1.balance.to_string(), \"105000000000000000000\");\n    let receiver2 = api\n        .get_account(address!(\"0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc\"), None)\n        .await\n        .unwrap();\n    assert_eq!(receiver2.nonce, 0);\n    assert_eq!(receiver2.balance.to_string(), \"101000000000000000000\");\n});\n\n// <https://github.com/foundry-rs/foundry/issues/11159>\nforgetest_async!(check_broadcast_log_with_additional_contracts, |prj, cmd| {\n    foundry_test_utils::util::initialize(prj.root());\n    prj.add_source(\n        \"Counter.sol\",\n        r#\"\ncontract Counter {\n    uint256 public number;\n\n    function setNumber(uint256 newNumber) public {\n        number = newNumber;\n    }\n\n    function increment() public {\n        number++;\n    }\n}\n   \"#,\n    );\n    prj.add_source(\n        \"Factory.sol\",\n        r#\"\nimport {Counter} from \"./Counter.sol\";\n\ncontract Factory {\n    function deployCounter() public returns (Counter) {\n        return new Counter();\n    }\n}\n   \"#,\n    );\n    let deploy_script = prj.add_script(\n        \"Factory.s.sol\",\n        r#\"\nimport \"forge-std/Script.sol\";\nimport {Factory} from \"../src/Factory.sol\";\nimport {Counter} from \"../src/Counter.sol\";\n\ncontract FactoryScript is Script {\n    Factory public factory;\n    Counter public counter;\n\n    function setUp() public {}\n\n    function run() public {\n        vm.startBroadcast();\n\n        factory = new Factory();\n        counter = factory.deployCounter();\n\n        vm.stopBroadcast();\n    }\n}\n   \"#,\n    );\n\n    let deploy_contract = deploy_script.display().to_string() + \":FactoryScript\";\n    let (_api, handle) = spawn(NodeConfig::test()).await;\n    cmd.args([\n        \"script\",\n        &deploy_contract,\n        \"--root\",\n        prj.root().to_str().unwrap(),\n        \"--fork-url\",\n        &handle.http_endpoint(),\n        \"--slow\",\n        \"--broadcast\",\n        \"--private-key\",\n        \"ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80\",\n    ])\n    .assert_success();\n\n    let broadcast_log = prj.root().join(\"broadcast/Factory.s.sol/31337/run-latest.json\");\n    let script_sequence: ScriptSequence<Ethereum> = serde_json::from_reader(\n        fs::File::open(prj.artifacts().join(broadcast_log)).expect(\"no broadcast log\"),\n    )\n    .expect(\"no script sequence\");\n\n    let counter_contract = script_sequence\n        .transactions\n        .get(1)\n        .expect(\"no tx\")\n        .additional_contracts\n        .first()\n        .expect(\"no Counter contract\");\n    assert_eq!(counter_contract.contract_name, Some(\"Counter\".to_string()));\n});\n\n// <https://github.com/foundry-rs/foundry/issues/11213>\nforgetest_async!(call_to_non_contract_address_does_not_panic, |prj, cmd| {\n    foundry_test_utils::util::initialize(prj.root());\n\n    let endpoint = rpc::next_http_archive_rpc_url();\n\n    prj.add_source(\n        \"Counter.sol\",\n        r#\"\ncontract Counter {\n    uint256 public number;\n\n    function setNumber(uint256 newNumber) public {\n        number = newNumber;\n    }\n\n    function increment() public {\n        number++;\n    }\n}\n   \"#,\n    );\n\n    let deploy_script = prj.add_script(\n        \"Counter.s.sol\",\n        &r#\"\nimport \"forge-std/Script.sol\";\nimport {Counter} from \"../src/Counter.sol\";\n\ncontract CounterScript is Script {\n    Counter public counter;\n    function setUp() public {}\n    function run() public {\n        vm.createSelectFork(\"<url>\");\n        vm.startBroadcast();\n        counter = new Counter();\n        vm.stopBroadcast();\n\n        vm.createSelectFork(\"<url>\");\n        vm.startBroadcast();\n        counter.increment();\n        vm.stopBroadcast();\n    }\n}\n   \"#\n        .replace(\"<url>\", &endpoint),\n    );\n\n    let (_api, handle) = spawn(NodeConfig::test()).await;\n    cmd.args([\n        \"script\",\n        &deploy_script.display().to_string(),\n        \"--root\",\n        prj.root().to_str().unwrap(),\n        \"--fork-url\",\n        &handle.http_endpoint(),\n        \"--slow\",\n        \"--broadcast\",\n        \"--private-key\",\n        \"ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80\",\n    ])\n    .assert_failure()\n    .stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\nTraces:\n  [..] → new CounterScript@[..]\n    └─ ← [Return] 2162 bytes of code\n\n  [..] CounterScript::setUp()\n    └─ ← [Stop]\n\n  [..] CounterScript::run()\n    ├─ [..] VM::createSelectFork(\"<rpc url>\")\n    │   └─ ← [Return] 1\n    ├─ [..] VM::startBroadcast()\n    │   └─ ← [Return]\n    ├─ [..] → new Counter@[..]\n    │   └─ ← [Return] 481 bytes of code\n    ├─ [..] VM::stopBroadcast()\n    │   └─ ← [Return]\n    ├─ [..] VM::createSelectFork(\"<rpc url>\")\n    │   └─ ← [Return] 2\n    ├─ [..] VM::startBroadcast()\n    │   └─ ← [Return]\n    └─ ← [Revert] call to non-contract address [..]\n\n\n\n\"#]])\n    .stderr_eq(str![[r#\"\nError: script failed: call to non-contract address [..]\n\"#]]);\n});\n\n// Test that --verify without --broadcast fails with a clear error message\nforgetest!(verify_without_broadcast_fails, |prj, cmd| {\n    let script = prj.add_source(\n        \"Counter\",\n        r#\"\nimport \"forge-std/Script.sol\";\n\ncontract CounterScript is Script {\n    function run() external {\n        // Simple script that does nothing\n    }\n}\n   \"#,\n    );\n\n    cmd.args([\n        \"script\",\n        script.to_str().unwrap(),\n        \"--verify\",\n        \"--rpc-url\",\n        \"https://sepolia.infura.io/v3/test\",\n    ])\n    .assert_failure()\n    .stderr_eq(str![[r#\"\nerror: the following required arguments were not provided:\n  --broadcast\n\nUsage: [..] script --broadcast --verify --fork-url <URL> <PATH> [ARGS]...\n\nFor more information, try '--help'.\n\n\"#]]);\n});\n\n// <https://github.com/foundry-rs/foundry/issues/11855>\nforgetest_async!(can_broadcast_from_deploy_code_cheatcode, |prj, cmd| {\n    foundry_test_utils::util::initialize(prj.root());\n    prj.initialize_default_contracts();\n    prj.add_script(\n        \"Counter.s.sol\",\n        r#\"\nimport \"forge-std/Script.sol\";\nimport {Vm} from \"forge-std/Vm.sol\";\nimport {Counter} from \"../src/Counter.sol\";\ncontract CounterScript is Script {\n    function run() public {\n        vm.startBroadcast();\n        address addr1 = vm.deployCode(\"src/Counter.sol:Counter\");\n        Counter(addr1).increment();\n        vm.stopBroadcast();\n    }\n}\n   \"#,\n    );\n\n    let node_config = NodeConfig::test().with_hardfork(Some(EthereumHardfork::Prague.into()));\n    let (_api, handle) = spawn(node_config).await;\n\n    cmd.args([\n        \"script\",\n        \"script/Counter.s.sol:CounterScript\",\n        \"--rpc-url\",\n        &handle.http_endpoint(),\n        \"-vvvv\",\n        \"--broadcast\",\n        \"--private-key\",\n        \"0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80\",\n    ])\n    .assert_success()\n    .stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\nTraces:\n  [..] CounterScript::run()\n    ├─ [0] VM::startBroadcast()\n    │   └─ ← [Return]\n    ├─ [0] VM::deployCode(\"src/Counter.sol:Counter\")\n    │   ├─ [..] → new Counter@0x5FbDB2315678afecb367f032d93F642f64180aa3\n    │   │   └─ ← [Return] 481 bytes of code\n    │   └─ ← [Return] Counter: [0x5FbDB2315678afecb367f032d93F642f64180aa3]\n    ├─ [..] Counter::increment()\n    │   └─ ← [Stop]\n    ├─ [0] VM::stopBroadcast()\n    │   └─ ← [Return]\n    └─ ← [Stop]\n\n\nScript ran successfully.\n\n## Setting up 1 EVM.\n==========================\nSimulated On-chain Traces:\n\n  [..] → new Counter@0x5FbDB2315678afecb367f032d93F642f64180aa3\n    └─ ← [Return] 481 bytes of code\n\n  [..] Counter::increment()\n    └─ ← [Stop]\n\n\n==========================\n\nChain 31337\n\n[ESTIMATED_GAS_PRICE]\n\n[ESTIMATED_TOTAL_GAS_USED]\n\n[ESTIMATED_AMOUNT_REQUIRED]\n\n==========================\n\n\n==========================\n\nONCHAIN EXECUTION COMPLETE & SUCCESSFUL.\n\n[SAVED_TRANSACTIONS]\n\n[SAVED_SENSITIVE_VALUES]\n\n\n\"#]]);\n});\n\nforgetest_async!(flaky_can_deploy_with_broadcast_in_setup, |prj, cmd| {\n    foundry_test_utils::util::initialize(prj.root());\n    prj.add_script(\n        \"Deploy.s.sol\",\n        r#\"\nimport \"forge-std/Script.sol\";\nimport {Vm} from \"forge-std/Vm.sol\";\ncontract DeployScript is Script {\n    function setUp() public {\n        vm.startBroadcast();\n    }\n\n    function run() public {\n        payable(address(0)).transfer(1 ether);\n\n        vm.stopBroadcast();\n    }\n}\n   \"#,\n    );\n\n    let node_config = NodeConfig::test().with_hardfork(Some(EthereumHardfork::Prague.into()));\n    let (_api, handle) = spawn(node_config).await;\n\n    cmd.args([\n        \"script\",\n        \"script/Deploy.s.sol:DeployScript\",\n        \"--rpc-url\",\n        &handle.http_endpoint(),\n        \"-vvvv\",\n        \"--broadcast\",\n        \"--private-key\",\n        \"0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80\",\n    ])\n    .assert_success()\n    .stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\nTraces:\n  [9882] DeployScript::run()\n    ├─ [0] 0x0000000000000000000000000000000000000000::fallback{value: 1000000000000000000}()\n    │   └─ ← [Stop]\n    ├─ [0] VM::stopBroadcast()\n    │   └─ ← [Return]\n    └─ ← [Stop]\n\n\nScript ran successfully.\n\n## Setting up 1 EVM.\n==========================\nSimulated On-chain Traces:\n\n  [0] 0x0000000000000000000000000000000000000000::fallback{value: 1000000000000000000}()\n    └─ ← [Stop]\n\n\n==========================\n\nChain 31337\n\n[ESTIMATED_GAS_PRICE]\n\n[ESTIMATED_TOTAL_GAS_USED]\n\n[ESTIMATED_AMOUNT_REQUIRED]\n\n==========================\n\n\n==========================\n\nONCHAIN EXECUTION COMPLETE & SUCCESSFUL.\n\n[SAVED_TRANSACTIONS]\n\n[SAVED_SENSITIVE_VALUES]\n\n\n\"#]]);\n});\n\n// <https://github.com/foundry-rs/foundry/issues/12151>\nforgetest_async!(can_execute_script_with_createx_and_via_ir, |prj, cmd| {\n    foundry_test_utils::util::initialize(prj.root());\n    prj.update_config(|config| {\n        config.optimizer = Some(true);\n        config.via_ir = true;\n    });\n    prj.add_script(\"CreateXScript.s.sol\", include_str!(\"../fixtures/CreateXScript.sol\"));\n\n    let (_api, handle) = spawn(NodeConfig::test().with_auto_impersonate(true)).await;\n    cmd.cast_fuse()\n        .args([\n            \"send\",\n            \"0xeD456e05CaAb11d66C4c797dD6c1D6f9A7F352b5\",\n            \"--value\",\n            \"1000000000000000000\",\n            \"--from\",\n            \"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266\",\n            \"--unlocked\",\n            \"--rpc-url\",\n            &handle.http_endpoint(),\n        ])\n        .assert_success();\n    cmd.cast_fuse()\n        .args([\"publish\", \"0xf92f698085174876e800832dc6c08080b92f1660a06040523060805234801561001457600080fd5b50608051612e3e6100d860003960008181610603015281816107050152818161082b015281816108d50152818161127f01528181611375015281816113e00152818161141f015281816114a7015281816115b3015281816117d20152818161183d0152818161187c0152818161190401528181611ac501528181611c7801528181611ce301528181611d2201528181611daa01528181611fe901528181612206015281816122f20152818161244d015281816124a601526125820152612e3e6000f3fe60806040526004361061018a5760003560e01c806381503da1116100d6578063d323826a1161007f578063e96deee411610059578063e96deee414610395578063f5745aba146103a8578063f9664498146103bb57600080fd5b8063d323826a1461034f578063ddda0acb1461036f578063e437252a1461038257600080fd5b80639c36a286116100b05780639c36a28614610316578063a7db93f214610329578063c3fe107b1461033c57600080fd5b806381503da1146102d0578063890c283b146102e357806398e810771461030357600080fd5b80632f990e3f116101385780636cec2536116101125780636cec25361461027d57806374637a7a1461029d5780637f565360146102bd57600080fd5b80632f990e3f1461023757806331a7c8c81461024a57806342d654fc1461025d57600080fd5b806327fe18221161016957806327fe1822146101f15780632852527a1461020457806328ddd0461461021757600080fd5b8062d84acb1461018f57806326307668146101cb57806326a32fc7146101de575b600080fd5b6101a261019d366004612915565b6103ce565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b6101a26101d9366004612994565b6103e6565b6101a26101ec3660046129db565b610452565b6101a26101ff3660046129db565b6104de565b6101a2610212366004612a39565b610539565b34801561022357600080fd5b506101a2610232366004612a90565b6106fe565b6101a2610245366004612aa9565b61072a565b6101a2610258366004612aa9565b6107bb565b34801561026957600080fd5b506101a2610278366004612b1e565b6107c9565b34801561028957600080fd5b506101a2610298366004612a90565b610823565b3480156102a957600080fd5b506101a26102b8366004612b4a565b61084f565b6101a26102cb3660046129db565b611162565b6101a26102de366004612b74565b6111e8565b3480156102ef57600080fd5b506101a26102fe366004612bac565b611276565b6101a2610311366004612bce565b6112a3565b6101a2610324366004612994565b611505565b6101a2610337366004612c49565b6116f1565b6101a261034a366004612aa9565b611964565b34801561035b57600080fd5b506101a261036a366004612cd9565b6119ed565b6101a261037d366004612c49565b611a17565b6101a2610390366004612bce565b611e0c565b6101a26103a3366004612915565b611e95565b6101a26103b6366004612bce565b611ea4565b6101a26103c9366004612b74565b611f2d565b60006103dd8585858533611a17565b95945050505050565b6000806103f2846120db565b90508083516020850134f59150610408826123d3565b604051819073ffffffffffffffffffffffffffffffffffffffff8416907fb8fda7e00c6b06a2b54e58521bc5894fee35f1090e5a3bb6390bfe2b98b497f790600090a35092915050565b60006104d86104d260408051437fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101406020830152419282019290925260608101919091524260808201524460a08201524660c08201523360e08201526000906101000160405160208183030381529060405280519060200120905090565b836103e6565b92915050565b600081516020830134f090506104f3816123d3565b60405173ffffffffffffffffffffffffffffffffffffffff8216907f4db17dd5e4732fb6da34a148104a592783ca119a1e7bb8829eba6cbadef0b51190600090a2919050565b600080610545856120db565b905060008460601b90506040517f3d602d80600a3d3981f3363d3d373d3d3d363d7300000000000000000000000081528160148201527f5af43d82803e903d91602b57fd5bf300000000000000000000000000000000006028820152826037826000f593505073ffffffffffffffffffffffffffffffffffffffff8316610635576040517fc05cee7a00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660048201526024015b60405180910390fd5b604051829073ffffffffffffffffffffffffffffffffffffffff8516907fb8fda7e00c6b06a2b54e58521bc5894fee35f1090e5a3bb6390bfe2b98b497f790600090a36000808473ffffffffffffffffffffffffffffffffffffffff1634876040516106a19190612d29565b60006040518083038185875af1925050503d80600081146106de576040519150601f19603f3d011682016040523d82523d6000602084013e6106e3565b606091505b50915091506106f382828961247d565b505050509392505050565b60006104d87f00000000000000000000000000000000000000000000000000000000000000008361084f565b60006107b36107aa60408051437fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101406020830152419282019290925260608101919091524260808201524460a08201524660c08201523360e08201526000906101000160405160208183030381529060405280519060200120905090565b85858533611a17565b949350505050565b60006107b3848484336112a3565b60006040518260005260ff600b53836020527f21c35dbe1b344a2488cf3321d6ce542f8e9f305544ff09e4993a62319a497c1f6040526055600b20601452806040525061d694600052600160345350506017601e20919050565b60006104d8827f00000000000000000000000000000000000000000000000000000000000000006107c9565b600060607f9400000000000000000000000000000000000000000000000000000000000000610887600167ffffffffffffffff612d45565b67ffffffffffffffff16841115610902576040517f3c55ab3b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016600482015260240161062c565b836000036109c7576040517fd60000000000000000000000000000000000000000000000000000000000000060208201527fff00000000000000000000000000000000000000000000000000000000000000821660218201527fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606087901b1660228201527f800000000000000000000000000000000000000000000000000000000000000060368201526037015b6040516020818303038152906040529150611152565b607f8411610a60576040517fd60000000000000000000000000000000000000000000000000000000000000060208201527fff0000000000000000000000000000000000000000000000000000000000000080831660218301527fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606088901b16602283015260f886901b1660368201526037016109b1565b60ff8411610b1f576040517fd70000000000000000000000000000000000000000000000000000000000000060208201527fff0000000000000000000000000000000000000000000000000000000000000080831660218301527fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606088901b1660228301527f8100000000000000000000000000000000000000000000000000000000000000603683015260f886901b1660378201526038016109b1565b61ffff8411610bff576040517fd80000000000000000000000000000000000000000000000000000000000000060208201527fff00000000000000000000000000000000000000000000000000000000000000821660218201527fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606087901b1660228201527f820000000000000000000000000000000000000000000000000000000000000060368201527fffff00000000000000000000000000000000000000000000000000000000000060f086901b1660378201526039016109b1565b62ffffff8411610ce0576040517fd90000000000000000000000000000000000000000000000000000000000000060208201527fff00000000000000000000000000000000000000000000000000000000000000821660218201527fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606087901b1660228201527f830000000000000000000000000000000000000000000000000000000000000060368201527fffffff000000000000000000000000000000000000000000000000000000000060e886901b166037820152603a016109b1565b63ffffffff8411610dc2576040517fda0000000000000000000000000000000000000000000000000000000000000060208201527fff00000000000000000000000000000000000000000000000000000000000000821660218201527fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606087901b1660228201527f840000000000000000000000000000000000000000000000000000000000000060368201527fffffffff0000000000000000000000000000000000000000000000000000000060e086901b166037820152603b016109b1565b64ffffffffff8411610ea5576040517fdb0000000000000000000000000000000000000000000000000000000000000060208201527fff00000000000000000000000000000000000000000000000000000000000000821660218201527fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606087901b1660228201527f850000000000000000000000000000000000000000000000000000000000000060368201527fffffffffff00000000000000000000000000000000000000000000000000000060d886901b166037820152603c016109b1565b65ffffffffffff8411610f89576040517fdc0000000000000000000000000000000000000000000000000000000000000060208201527fff00000000000000000000000000000000000000000000000000000000000000821660218201527fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606087901b1660228201527f860000000000000000000000000000000000000000000000000000000000000060368201527fffffffffffff000000000000000000000000000000000000000000000000000060d086901b166037820152603d016109b1565b66ffffffffffffff841161106e576040517fdd0000000000000000000000000000000000000000000000000000000000000060208201527fff00000000000000000000000000000000000000000000000000000000000000821660218201527fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606087901b1660228201527f870000000000000000000000000000000000000000000000000000000000000060368201527fffffffffffffff0000000000000000000000000000000000000000000000000060c886901b166037820152603e016109b1565b6040517fde0000000000000000000000000000000000000000000000000000000000000060208201527fff00000000000000000000000000000000000000000000000000000000000000821660218201527fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606087901b1660228201527f880000000000000000000000000000000000000000000000000000000000000060368201527fffffffffffffffff00000000000000000000000000000000000000000000000060c086901b166037820152603f0160405160208183030381529060405291505b5080516020909101209392505050565b60006104d86111e260408051437fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101406020830152419282019290925260608101919091524260808201524460a08201524660c08201523360e08201526000906101000160405160208183030381529060405280519060200120905090565b83611505565b600061126f61126860408051437fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101406020830152419282019290925260608101919091524260808201524460a08201524660c08201523360e08201526000906101000160405160208183030381529060405280519060200120905090565b8484610539565b9392505050565b600061126f83837f00000000000000000000000000000000000000000000000000000000000000006119ed565b60008451602086018451f090506112b9816123d3565b60405173ffffffffffffffffffffffffffffffffffffffff8216907f4db17dd5e4732fb6da34a148104a592783ca119a1e7bb8829eba6cbadef0b51190600090a26000808273ffffffffffffffffffffffffffffffffffffffff168560200151876040516113279190612d29565b60006040518083038185875af1925050503d8060008114611364576040519150601f19603f3d011682016040523d82523d6000602084013e611369565b606091505b5091509150816113c9577f0000000000000000000000000000000000000000000000000000000000000000816040517fa57ca23900000000000000000000000000000000000000000000000000000000815260040161062c929190612d94565b73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001631156114fb578373ffffffffffffffffffffffffffffffffffffffff167f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163160405160006040518083038185875af1925050503d8060008114611495576040519150601f19603f3d011682016040523d82523d6000602084013e61149a565b606091505b509092509050816114fb577f0000000000000000000000000000000000000000000000000000000000000000816040517fc2b3f44500000000000000000000000000000000000000000000000000000000815260040161062c929190612d94565b5050949350505050565b600080611511846120db565b905060006040518060400160405280601081526020017f67363d3d37363d34f03d5260086018f30000000000000000000000000000000081525090506000828251602084016000f5905073ffffffffffffffffffffffffffffffffffffffff81166115e0576040517fc05cee7a00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016600482015260240161062c565b604051839073ffffffffffffffffffffffffffffffffffffffff8316907f2feea65dd4e9f9cbd86b74b7734210c59a1b2981b5b137bd0ee3e208200c906790600090a361162c83610823565b935060008173ffffffffffffffffffffffffffffffffffffffff1634876040516116569190612d29565b60006040518083038185875af1925050503d8060008114611693576040519150601f19603f3d011682016040523d82523d6000602084013e611698565b606091505b505090506116a681866124ff565b60405173ffffffffffffffffffffffffffffffffffffffff8616907f4db17dd5e4732fb6da34a148104a592783ca119a1e7bb8829eba6cbadef0b51190600090a25050505092915050565b6000806116fd876120db565b9050808651602088018651f59150611714826123d3565b604051819073ffffffffffffffffffffffffffffffffffffffff8416907fb8fda7e00c6b06a2b54e58521bc5894fee35f1090e5a3bb6390bfe2b98b497f790600090a36000808373ffffffffffffffffffffffffffffffffffffffff168660200151886040516117849190612d29565b60006040518083038185875af1925050503d80600081146117c1576040519150601f19603f3d011682016040523d82523d6000602084013e6117c6565b606091505b509150915081611826577f0000000000000000000000000000000000000000000000000000000000000000816040517fa57ca23900000000000000000000000000000000000000000000000000000000815260040161062c929190612d94565b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000163115611958578473ffffffffffffffffffffffffffffffffffffffff167f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163160405160006040518083038185875af1925050503d80600081146118f2576040519150601f19603f3d011682016040523d82523d6000602084013e6118f7565b606091505b50909250905081611958577f0000000000000000000000000000000000000000000000000000000000000000816040517fc2b3f44500000000000000000000000000000000000000000000000000000000815260040161062c929190612d94565b50505095945050505050565b60006107b36119e460408051437fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101406020830152419282019290925260608101919091524260808201524460a08201524660c08201523360e08201526000906101000160405160208183030381529060405280519060200120905090565b858585336116f1565b6000604051836040820152846020820152828152600b8101905060ff815360559020949350505050565b600080611a23876120db565b905060006040518060400160405280601081526020017f67363d3d37363d34f03d5260086018f30000000000000000000000000000000081525090506000828251602084016000f5905073ffffffffffffffffffffffffffffffffffffffff8116611af2576040517fc05cee7a00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016600482015260240161062c565b604051839073ffffffffffffffffffffffffffffffffffffffff8316907f2feea65dd4e9f9cbd86b74b7734210c59a1b2981b5b137bd0ee3e208200c906790600090a3611b3e83610823565b935060008173ffffffffffffffffffffffffffffffffffffffff1687600001518a604051611b6c9190612d29565b60006040518083038185875af1925050503d8060008114611ba9576040519150601f19603f3d011682016040523d82523d6000602084013e611bae565b606091505b50509050611bbc81866124ff565b60405173ffffffffffffffffffffffffffffffffffffffff8616907f4db17dd5e4732fb6da34a148104a592783ca119a1e7bb8829eba6cbadef0b51190600090a260608573ffffffffffffffffffffffffffffffffffffffff1688602001518a604051611c299190612d29565b60006040518083038185875af1925050503d8060008114611c66576040519150601f19603f3d011682016040523d82523d6000602084013e611c6b565b606091505b50909250905081611ccc577f0000000000000000000000000000000000000000000000000000000000000000816040517fa57ca23900000000000000000000000000000000000000000000000000000000815260040161062c929190612d94565b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000163115611dfe578673ffffffffffffffffffffffffffffffffffffffff167f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163160405160006040518083038185875af1925050503d8060008114611d98576040519150601f19603f3d011682016040523d82523d6000602084013e611d9d565b606091505b50909250905081611dfe577f0000000000000000000000000000000000000000000000000000000000000000816040517fc2b3f44500000000000000000000000000000000000000000000000000000000815260040161062c929190612d94565b505050505095945050505050565b60006103dd611e8c60408051437fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101406020830152419282019290925260608101919091524260808201524460a08201524660c08201523360e08201526000906101000160405160208183030381529060405280519060200120905090565b868686866116f1565b60006103dd85858585336116f1565b60006103dd611f2460408051437fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101406020830152419282019290925260608101919091524260808201524460a08201524660c08201523360e08201526000906101000160405160208183030381529060405280519060200120905090565b86868686611a17565b6000808360601b90506040517f3d602d80600a3d3981f3363d3d373d3d3d363d7300000000000000000000000081528160148201527f5af43d82803e903d91602b57fd5bf3000000000000000000000000000000000060288201526037816000f092505073ffffffffffffffffffffffffffffffffffffffff8216612016576040517fc05cee7a00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016600482015260240161062c565b60405173ffffffffffffffffffffffffffffffffffffffff8316907f4db17dd5e4732fb6da34a148104a592783ca119a1e7bb8829eba6cbadef0b51190600090a26000808373ffffffffffffffffffffffffffffffffffffffff1634866040516120809190612d29565b60006040518083038185875af1925050503d80600081146120bd576040519150601f19603f3d011682016040523d82523d6000602084013e6120c2565b606091505b50915091506120d282828861247d565b50505092915050565b60008060006120e9846125b3565b9092509050600082600281111561210257612102612e02565b1480156121205750600081600281111561211e5761211e612e02565b145b1561215e57604080513360208201524691810191909152606081018590526080016040516020818303038152906040528051906020012092506123cc565b600082600281111561217257612172612e02565b1480156121905750600181600281111561218e5761218e612e02565b145b156121b0576121a9338560009182526020526040902090565b92506123cc565b60008260028111156121c4576121c4612e02565b03612233576040517f13b3a2a100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016600482015260240161062c565b600182600281111561224757612247612e02565b1480156122655750600081600281111561226357612263612e02565b145b1561227e576121a9468560009182526020526040902090565b600182600281111561229257612292612e02565b1480156122b0575060028160028111156122ae576122ae612e02565b145b1561231f576040517f13b3a2a100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016600482015260240161062c565b61239a60408051437fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101406020830152419282019290925260608101919091524260808201524460a08201524660c08201523360e08201526000906101000160405160208183030381529060405280519060200120905090565b84036123a657836123c9565b604080516020810186905201604051602081830303815290604052805190602001205b92505b5050919050565b73ffffffffffffffffffffffffffffffffffffffff8116158061240b575073ffffffffffffffffffffffffffffffffffffffff81163b155b1561247a576040517fc05cee7a00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016600482015260240161062c565b50565b82158061249f575073ffffffffffffffffffffffffffffffffffffffff81163b155b156124fa577f0000000000000000000000000000000000000000000000000000000000000000826040517fa57ca23900000000000000000000000000000000000000000000000000000000815260040161062c929190612d94565b505050565b811580612520575073ffffffffffffffffffffffffffffffffffffffff8116155b80612540575073ffffffffffffffffffffffffffffffffffffffff81163b155b156125af576040517fc05cee7a00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016600482015260240161062c565b5050565b600080606083901c3314801561261057508260141a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167f0100000000000000000000000000000000000000000000000000000000000000145b1561262057506000905080915091565b606083901c3314801561265a57507fff00000000000000000000000000000000000000000000000000000000000000601484901a60f81b16155b1561266b5750600090506001915091565b33606084901c036126825750600090506002915091565b606083901c1580156126db57508260141a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167f0100000000000000000000000000000000000000000000000000000000000000145b156126ec5750600190506000915091565b606083901c15801561272557507fff00000000000000000000000000000000000000000000000000000000000000601484901a60f81b16155b1561273557506001905080915091565b606083901c61274a5750600190506002915091565b8260141a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167f0100000000000000000000000000000000000000000000000000000000000000036127a55750600290506000915091565b8260141a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166000036127e15750600290506001915091565b506002905080915091565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600082601f83011261282c57600080fd5b813567ffffffffffffffff80821115612847576128476127ec565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190828211818310171561288d5761288d6127ec565b816040528381528660208588010111156128a657600080fd5b836020870160208301376000602085830101528094505050505092915050565b6000604082840312156128d857600080fd5b6040516040810181811067ffffffffffffffff821117156128fb576128fb6127ec565b604052823581526020928301359281019290925250919050565b60008060008060a0858703121561292b57600080fd5b84359350602085013567ffffffffffffffff8082111561294a57600080fd5b6129568883890161281b565b9450604087013591508082111561296c57600080fd5b506129798782880161281b565b92505061298986606087016128c6565b905092959194509250565b600080604083850312156129a757600080fd5b82359150602083013567ffffffffffffffff8111156129c557600080fd5b6129d18582860161281b565b9150509250929050565b6000602082840312156129ed57600080fd5b813567ffffffffffffffff811115612a0457600080fd5b6107b38482850161281b565b803573ffffffffffffffffffffffffffffffffffffffff81168114612a3457600080fd5b919050565b600080600060608486031215612a4e57600080fd5b83359250612a5e60208501612a10565b9150604084013567ffffffffffffffff811115612a7a57600080fd5b612a868682870161281b565b9150509250925092565b600060208284031215612aa257600080fd5b5035919050565b600080600060808486031215612abe57600080fd5b833567ffffffffffffffff80821115612ad657600080fd5b612ae28783880161281b565b94506020860135915080821115612af857600080fd5b50612b058682870161281b565b925050612b1585604086016128c6565b90509250925092565b60008060408385031215612b3157600080fd5b82359150612b4160208401612a10565b90509250929050565b60008060408385031215612b5d57600080fd5b612b6683612a10565b946020939093013593505050565b60008060408385031215612b8757600080fd5b612b9083612a10565b9150602083013567ffffffffffffffff8111156129c557600080fd5b60008060408385031215612bbf57600080fd5b50508035926020909101359150565b60008060008060a08587031215612be457600080fd5b843567ffffffffffffffff80821115612bfc57600080fd5b612c088883890161281b565b95506020870135915080821115612c1e57600080fd5b50612c2b8782880161281b565b935050612c3b86604087016128c6565b915061298960808601612a10565b600080600080600060c08688031215612c6157600080fd5b85359450602086013567ffffffffffffffff80821115612c8057600080fd5b612c8c89838a0161281b565b95506040880135915080821115612ca257600080fd5b50612caf8882890161281b565b935050612cbf87606088016128c6565b9150612ccd60a08701612a10565b90509295509295909350565b600080600060608486031215612cee57600080fd5b8335925060208401359150612b1560408501612a10565b60005b83811015612d20578181015183820152602001612d08565b50506000910152565b60008251612d3b818460208701612d05565b9190910192915050565b67ffffffffffffffff828116828216039080821115612d8d577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b5092915050565b73ffffffffffffffffffffffffffffffffffffffff831681526040602082015260008251806040840152612dcf816060850160208701612d05565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016919091016060019392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fdfea164736f6c6343000817000a1ca005f70bf8a1493291468f36ef23b05eb3a4f1807f6b4022942a4104b7537bfc36a029528c0c29546c81e7d78b0277ef87031541bdc96427b246ecedb6d74cd3ed62\", \"--rpc-url\", &handle.http_endpoint()])\n        .assert_success();\n    cmd.forge_fuse()\n        .args([\n            \"script\",\n            \"script/CreateXScript.s.sol:CreateXScript\",\n            \"--rpc-url\",\n            &handle.http_endpoint(),\n            \"--slow\",\n            \"--sender\",\n            \"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266\",\n            \"--private-key\",\n            \"0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80\",\n            \"--broadcast\",\n        ])\n        .assert_success();\n});\n\nforgetest_async!(script_can_run_with_live_logs_flag, |prj, cmd| {\n    foundry_test_utils::util::initialize(prj.root());\n    prj.add_script(\n        \"Foo.s.sol\",\n        r#\"\nimport {Script, console} from \"forge-std/Script.sol\";\n\ncontract Foo is Script {\n    function setUp() pure public {\n        console.log(\"Setup\");\n    }\n\n    function run() pure public {\n        console.log(\"Run %d\", uint256(1));\n    }\n}\n    \"#,\n    );\n\n    cmd.forge_fuse()\n        .args([\"script\", \"script/Foo.s.sol\", \"--live-logs\"])\n        .assert_success()\n        .stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\nSetup\nRun 1\nScript ran successfully.\n[GAS]\n\n\"#]]);\n});\n\nforgetest_async!(script_can_run_with_live_logs_config, |prj, cmd| {\n    foundry_test_utils::util::initialize(prj.root());\n    prj.update_config(|config| {\n        config.live_logs = true;\n    });\n\n    prj.add_script(\n        \"Foo.s.sol\",\n        r#\"\nimport {Script, console} from \"forge-std/Script.sol\";\n\ncontract Foo is Script {\n    function setUp() pure public {\n        console.log(\"Setup\");\n    }\n\n    function run() pure public {\n        console.log(\"Run %d\", uint256(1));\n    }\n}\n    \"#,\n    );\n\n    cmd.forge_fuse().args([\"script\", \"script/Foo.s.sol\"]).assert_success().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\nSetup\nRun 1\nScript ran successfully.\n[GAS]\n\n\"#]]);\n});\n"
  },
  {
    "path": "crates/forge/tests/cli/soldeer.rs",
    "content": "//! Contains various tests related to `forge soldeer`.\n\nuse std::{fs, path::Path};\n\nuse foundry_test_utils::forgesoldeer;\n\nforgesoldeer!(install_dependency, |prj, cmd| {\n    let command = \"install\";\n    let dependency = \"forge-std~1.8.1\";\n\n    let mut foundry_contents = r#\"[profile.default]\nsrc = \"src\"\nout = \"out\"\nlibs = [\"lib\", \"dependencies\"]\n\n[dependencies]\n\n# See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options\n\"#;\n    let foundry_file = prj.root().join(\"foundry.toml\");\n    fs::write(&foundry_file, foundry_contents).unwrap();\n\n    cmd.arg(\"soldeer\").args([command, dependency]).assert_success();\n\n    // Making sure the path was created to the dependency and that foundry.toml exists\n    // meaning that the dependencies were installed correctly\n    let path_dep_forge =\n        prj.root().join(\"dependencies\").join(\"forge-std-1.8.1\").join(\"foundry.toml\");\n    assert!(path_dep_forge.exists());\n\n    // Making sure the lock contents are the right ones\n    let path_lock_file = prj.root().join(\"soldeer.lock\");\n\n    let actual_lock_contents = read_file_to_string(&path_lock_file);\n    assert!(actual_lock_contents.contains(\"forge-std\"));\n\n    // Making sure the foundry contents are the right ones\n    foundry_contents = r#\"[profile.default]\nsrc = \"src\"\nout = \"out\"\nlibs = [\"lib\", \"dependencies\"]\n\n[dependencies]\nforge-std = \"1.8.1\"\n\n# See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options\n\"#;\n\n    assert_data_eq!(read_file_to_string(&foundry_file), foundry_contents);\n});\n\nforgesoldeer!(install_dependency_git, |prj, cmd| {\n    let command = \"install\";\n    let dependency = \"forge-std~1.8.1\";\n    let git_arg = \"--git\";\n    let git = \"https://gitlab.com/mario4582928/Mario.git\";\n\n    let mut foundry_contents = r#\"[profile.default]\nsrc = \"src\"\nout = \"out\"\nlibs = [\"lib\", \"dependencies\"]\n\n[dependencies]\n\n# See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options\n\"#;\n    let foundry_file = prj.root().join(\"foundry.toml\");\n    fs::write(&foundry_file, foundry_contents).unwrap();\n\n    cmd.arg(\"soldeer\").args([command, dependency, git_arg, git]).assert_success();\n\n    // Making sure the path was created to the dependency and that README.md exists\n    // meaning that the dependencies were installed correctly\n    let path_dep_forge = prj.root().join(\"dependencies\").join(\"forge-std-1.8.1\").join(\"README.md\");\n    assert!(path_dep_forge.exists());\n\n    // Making sure the lock contents are the right ones\n    let path_lock_file = prj.root().join(\"soldeer.lock\");\n\n    let actual_lock_contents = read_file_to_string(&path_lock_file);\n    assert!(actual_lock_contents.contains(\"forge-std\"));\n\n    // Making sure the foundry contents are the right ones\n    foundry_contents = r#\"[profile.default]\nsrc = \"src\"\nout = \"out\"\nlibs = [\"lib\", \"dependencies\"]\n\n[dependencies]\nforge-std = { version = \"1.8.1\", git = \"https://gitlab.com/mario4582928/Mario.git\", rev = \"22868f426bd4dd0e682b5ec5f9bd55507664240c\" }\n\n# See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options\n\"#;\n\n    assert_data_eq!(read_file_to_string(&foundry_file), foundry_contents);\n});\n\nforgesoldeer!(install_dependency_git_commit, |prj, cmd| {\n    let command = \"install\";\n    let dependency = \"forge-std~1.8.1\";\n    let git_arg = \"--git\";\n    let git = \"https://gitlab.com/mario4582928/Mario.git\";\n    let rev_flag = \"--rev\";\n    let commit = \"7a0663eaf7488732f39550be655bad6694974cb3\";\n\n    let mut foundry_contents = r#\"[profile.default]\nsrc = \"src\"\nout = \"out\"\nlibs = [\"lib\", \"dependencies\"]\n\n[dependencies]\n\n# See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options\n\"#;\n    let foundry_file = prj.root().join(\"foundry.toml\");\n    fs::write(&foundry_file, foundry_contents).unwrap();\n\n    cmd.arg(\"soldeer\").args([command, dependency, git_arg, git, rev_flag, commit]).assert_success();\n\n    // Making sure the path was created to the dependency and that README.md exists\n    // meaning that the dependencies were installed correctly\n    let path_dep_forge =\n        prj.root().join(\"dependencies\").join(\"forge-std-1.8.1\").join(\"JustATest2.md\");\n    assert!(path_dep_forge.exists());\n\n    // Making sure the lock contents are the right ones\n    let path_lock_file = prj.root().join(\"soldeer.lock\");\n\n    let actual_lock_contents = read_file_to_string(&path_lock_file);\n    assert!(actual_lock_contents.contains(\"forge-std\"));\n\n    // Making sure the foundry contents are the right ones\n    foundry_contents = r#\"[profile.default]\nsrc = \"src\"\nout = \"out\"\nlibs = [\"lib\", \"dependencies\"]\n\n[dependencies]\nforge-std = { version = \"1.8.1\", git = \"https://gitlab.com/mario4582928/Mario.git\", rev = \"7a0663eaf7488732f39550be655bad6694974cb3\" }\n\n# See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options\n\"#;\n\n    assert_data_eq!(read_file_to_string(&foundry_file), foundry_contents);\n});\n\nforgesoldeer!(update_dependencies, |prj, cmd| {\n    let command = \"update\";\n\n    // We need to write this into the foundry.toml to make the update install the dependency\n    let foundry_updates = r#\"[profile.default]\nsrc = \"src\"\nout = \"out\"\nlibs = [\"lib\", \"dependencies\"]\n\n# See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options\n\n[dependencies]\n\"@tt\" = {version = \"1.6.1\", url = \"https://soldeer-revisions.s3.amazonaws.com/@openzeppelin-contracts/3_3_0-rc_2_22-01-2024_13:12:57_contracts.zip\"}\nforge-std = { version = \"1.8.1\" }\nsolmate = \"6.7.0\"\nmario = { version = \"1.0\", git = \"https://gitlab.com/mario4582928/Mario.git\", rev = \"22868f426bd4dd0e682b5ec5f9bd55507664240c\" }\nmario-custom-tag = { version = \"1.0\", git = \"https://gitlab.com/mario4582928/Mario.git\", tag = \"custom-tag\" }\nmario-custom-branch = { version = \"1.0\", git = \"https://gitlab.com/mario4582928/Mario.git\", tag = \"custom-branch\" }\n\"#;\n    let foundry_file = prj.root().join(\"foundry.toml\");\n    fs::write(&foundry_file, foundry_updates).unwrap();\n\n    cmd.arg(\"soldeer\").arg(command).assert_success();\n\n    // Making sure the path was created to the dependency and that foundry.toml exists\n    // meaning that the dependencies were installed correctly\n    let dep1 = prj.root().join(\"dependencies\").join(\"@tt-1.6.1\");\n    let dep2 = prj.root().join(\"dependencies\").join(\"forge-std-1.8.1\");\n    let dep3 = prj.root().join(\"dependencies\").join(\"mario-1.0\");\n    let dep4 = prj.root().join(\"dependencies\").join(\"solmate-6.7.0\");\n    let dep5 = prj.root().join(\"dependencies\").join(\"mario-custom-tag-1.0\");\n    let dep6 = prj.root().join(\"dependencies\").join(\"mario-custom-branch-1.0\");\n\n    assert!(dep1.exists());\n    assert!(dep2.exists());\n    assert!(dep3.exists());\n    assert!(dep4.exists());\n    assert!(dep5.exists());\n    assert!(dep6.exists());\n\n    // Making sure the lock contents are the right ones\n    let path_lock_file = prj.root().join(\"soldeer.lock\");\n\n    // assert_data_eq!(lock_contents, read_file_to_string(&path_lock_file));\n    let actual_lock_contents = read_file_to_string(&path_lock_file);\n    assert!(actual_lock_contents.contains(\"forge-std\"));\n\n    // Making sure the foundry contents are the right ones\n    let foundry_contents = r#\"[profile.default]\nsrc = \"src\"\nout = \"out\"\nlibs = [\"lib\", \"dependencies\"]\n\n# See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options\n\n[dependencies]\n\"@tt\" = {version = \"1.6.1\", url = \"https://soldeer-revisions.s3.amazonaws.com/@openzeppelin-contracts/3_3_0-rc_2_22-01-2024_13:12:57_contracts.zip\"}\nforge-std = { version = \"1.8.1\" }\nsolmate = \"6.7.0\"\nmario = { version = \"1.0\", git = \"https://gitlab.com/mario4582928/Mario.git\", rev = \"22868f426bd4dd0e682b5ec5f9bd55507664240c\" }\nmario-custom-tag = { version = \"1.0\", git = \"https://gitlab.com/mario4582928/Mario.git\", tag = \"custom-tag\" }\nmario-custom-branch = { version = \"1.0\", git = \"https://gitlab.com/mario4582928/Mario.git\", tag = \"custom-branch\" }\n\"#;\n    assert_data_eq!(read_file_to_string(&foundry_file), foundry_contents);\n});\n\nforgesoldeer!(update_dependencies_simple_version, |prj, cmd| {\n    let command = \"update\";\n\n    // We need to write this into the foundry.toml to make the update install the dependency, this\n    // is he simplified version of version specification\n    let foundry_updates = r#\"[profile.default]\nsrc = \"src\"\nout = \"out\"\nlibs = [\"lib\", \"dependencies\"]\n\n# See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options\n\n[dependencies]\nforge-std = \"1.8.1\" \n\"#;\n    let foundry_file = prj.root().join(\"foundry.toml\");\n\n    fs::write(&foundry_file, foundry_updates).unwrap();\n\n    cmd.arg(\"soldeer\").arg(command).assert_success();\n    // Making sure the path was created to the dependency and that foundry.toml exists\n    // meaning that the dependencies were installed correctly\n    let path_dep_forge =\n        prj.root().join(\"dependencies\").join(\"forge-std-1.8.1\").join(\"foundry.toml\");\n    assert!(path_dep_forge.exists());\n\n    // Making sure the lock contents are the right ones\n    let path_lock_file = prj.root().join(\"soldeer.lock\");\n\n    let actual_lock_contents = read_file_to_string(&path_lock_file);\n    assert!(actual_lock_contents.contains(\"forge-std\"));\n\n    // Making sure the foundry contents are the right ones\n    let foundry_contents = r#\"[profile.default]\nsrc = \"src\"\nout = \"out\"\nlibs = [\"lib\", \"dependencies\"]\n\n# See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options\n\n[dependencies]\nforge-std = \"1.8.1\" \n\"#;\n\n    assert_data_eq!(read_file_to_string(&foundry_file), foundry_contents);\n});\n\nforgesoldeer!(install_dependency_with_remappings_config, |prj, cmd| {\n    let command = \"install\";\n    let dependency = \"forge-std~1.8.1\";\n    let foundry_updates = r#\"[profile.default]\nsrc = \"src\"\nout = \"out\"\nlibs = [\"lib\", \"dependencies\"]\n\n# See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options\n\n[soldeer]\nremappings_generate = true\nremappings_prefix = \"@custom-f@\"\nremappings_location = \"config\"\nremappings_regenerate = true\n\n[dependencies]\n\"#;\n    let foundry_file = prj.root().join(\"foundry.toml\");\n    fs::write(&foundry_file, foundry_updates).unwrap();\n\n    cmd.arg(\"soldeer\").args([command, dependency]).assert_success();\n\n    // Making sure the path was created to the dependency and that foundry.toml exists\n    // meaning that the dependencies were installed correctly\n    let path_dep_forge =\n        prj.root().join(\"dependencies\").join(\"forge-std-1.8.1\").join(\"foundry.toml\");\n    assert!(path_dep_forge.exists());\n\n    // Making sure the lock contents are the right ones\n    let path_lock_file = prj.root().join(\"soldeer.lock\");\n\n    let actual_lock_contents = read_file_to_string(&path_lock_file);\n    assert!(actual_lock_contents.contains(\"forge-std\"));\n\n    // Making sure the foundry contents are the right ones\n    let foundry_contents = r#\"[profile.default]\nsrc = \"src\"\nout = \"out\"\nlibs = [\"lib\", \"dependencies\"]\nremappings = [\"@custom-f@forge-std-1.8.1/=dependencies/forge-std-1.8.1/\"]\n\n# See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options\n\n[soldeer]\nremappings_generate = true\nremappings_prefix = \"@custom-f@\"\nremappings_location = \"config\"\nremappings_regenerate = true\n\n[dependencies]\nforge-std = \"1.8.1\"\n\"#;\n\n    assert_data_eq!(read_file_to_string(&foundry_file), foundry_contents);\n});\n\nforgesoldeer!(install_dependency_with_remappings_txt, |prj, cmd| {\n    let command = \"install\";\n    let dependency = \"forge-std~1.8.1\";\n    let foundry_updates = r#\"\n[dependencies]\n\n[soldeer]\nremappings_generate = true\nremappings_prefix = \"@custom-f@\"\nremappings_location = \"txt\"\nremappings_regenerate = true\n\"#;\n    let foundry_file = prj.root().join(\"foundry.toml\");\n    fs::write(&foundry_file, foundry_updates).unwrap();\n\n    cmd.arg(\"soldeer\").args([command, dependency]).assert_success();\n\n    // Making sure the path was created to the dependency and that foundry.toml exists\n    // meaning that the dependencies were installed correctly\n    let path_dep_forge =\n        prj.root().join(\"dependencies\").join(\"forge-std-1.8.1\").join(\"foundry.toml\");\n    assert!(path_dep_forge.exists());\n\n    // Making sure the lock contents are the right ones\n    let path_lock_file = prj.root().join(\"soldeer.lock\");\n\n    let actual_lock_contents = read_file_to_string(&path_lock_file);\n    assert!(actual_lock_contents.contains(\"forge-std\"));\n\n    // Making sure the foundry contents are the right ones\n    let remappings_content = r#\"@custom-f@forge-std-1.8.1/=dependencies/forge-std-1.8.1/\n\"#;\n    let remappings_file = prj.root().join(\"remappings.txt\");\n    assert_data_eq!(read_file_to_string(&remappings_file), remappings_content);\n});\n\nforgesoldeer!(login, |prj, cmd| {\n    let command = \"login\";\n\n    let _ = cmd.arg(\"soldeer\").arg(command).assert_failure();\n});\n\nforgesoldeer!(clean, |prj, cmd| {\n    let dependency = \"forge-std~1.8.1\";\n    let foundry_contents = r#\"[profile.default]\nsrc = \"src\"\nout = \"out\"\nlibs = [\"lib\", \"dependencies\"]\n\n[dependencies]\n\"#;\n    let foundry_file = prj.root().join(\"foundry.toml\");\n    fs::write(&foundry_file, foundry_contents).unwrap();\n\n    cmd.args([\"soldeer\", \"install\", dependency]).assert_success();\n    cmd.forge_fuse(); // reset command\n\n    // Making sure the path was created to the dependency and that foundry.toml exists\n    // meaning that the dependencies were installed correctly\n    let path_dep_forge =\n        prj.root().join(\"dependencies\").join(\"forge-std-1.8.1\").join(\"foundry.toml\");\n    assert!(path_dep_forge.exists());\n\n    let command = \"clean\";\n    cmd.arg(\"soldeer\").args([command]).assert_success();\n    // Dependencies should have been removed from disk\n    assert!(!prj.root().join(\"dependencies\").exists());\n});\n\nforgesoldeer!(detect_project_root, |prj, cmd| {\n    let command = \"update\";\n\n    let foundry_updates = r#\"[profile.default]\nsrc = \"src\"\nout = \"out\"\nlibs = [\"lib\", \"dependencies\"]\n\n# See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options\n\n[dependencies]\nforge-std = \"1.8.1\" \n\"#;\n    let foundry_file = prj.root().join(\"foundry.toml\");\n\n    fs::write(&foundry_file, foundry_updates).unwrap();\n\n    // run command from sub-directory\n    cmd.set_current_dir(prj.root().join(\"src\"));\n    cmd.arg(\"soldeer\").arg(command).assert_success();\n    // Making sure the path was created to the dependency and that foundry.toml exists\n    // meaning that the dependencies were installed correctly\n    let path_dep_forge =\n        prj.root().join(\"dependencies\").join(\"forge-std-1.8.1\").join(\"foundry.toml\");\n    assert!(path_dep_forge.exists());\n});\n\nfn read_file_to_string(path: &Path) -> String {\n    let contents: String = fs::read_to_string(path).unwrap_or_default();\n    contents\n}\n"
  },
  {
    "path": "crates/forge/tests/cli/svm.rs",
    "content": "//! svm sanity checks\n\nuse semver::Version;\nuse svm::Platform;\n\n/// The latest Solc release.\n///\n/// Solc to Foundry release process:\n/// 1. new solc release\n/// 2. svm updated with all build info\n/// 3. svm bumped in foundry-compilers\n/// 4. foundry-compilers update with any breaking changes\n/// 5. upgrade the `LATEST_SOLC`\nconst LATEST_SOLC: Version = Version::new(0, 8, 34);\n\nmacro_rules! ensure_svm_releases {\n    ($($test:ident => $platform:ident),* $(,)?) => {$(\n        #[tokio::test(flavor = \"multi_thread\")]\n        async fn $test() {\n            ensure_latest_release(Platform::$platform).await\n        }\n    )*};\n}\n\nasync fn ensure_latest_release(platform: Platform) {\n    let releases = svm::all_releases(platform)\n        .await\n        .unwrap_or_else(|err| panic!(\"Could not fetch releases for {platform}: {err:?}\"));\n    assert!(\n        releases.releases.contains_key(&LATEST_SOLC),\n        \"platform {platform:?} is missing solc info for v{LATEST_SOLC}\"\n    );\n}\n\n// ensures all platform have the latest solc release version\nensure_svm_releases!(\n    test_svm_releases_linux_amd64 => LinuxAmd64,\n    test_svm_releases_linux_aarch64 => LinuxAarch64,\n    test_svm_releases_macos_amd64 => MacOsAmd64,\n    test_svm_releases_macos_aarch64 => MacOsAarch64,\n    test_svm_releases_windows_amd64 => WindowsAmd64\n);\n\n// Ensures we can always test with the latest solc build\nforgetest_init!(can_test_with_latest_solc, |prj, cmd| {\n    prj.initialize_default_contracts();\n    prj.add_test(\n        \"Counter.2.t.sol\",\n        &format!(\n            r#\"\npragma solidity ={LATEST_SOLC};\n\nimport \"forge-std/Test.sol\";\n\ncontract CounterTest is Test {{\n    function testAssert() public {{\n        assert(true);\n    }}\n}}\n    \"#\n        ),\n    );\n\n    // we need to remove the pinned solc version for this\n    prj.update_config(|c| {\n        c.solc.take();\n    });\n\n    cmd.arg(\"test\").assert_success().stdout_eq(str![[r#\"\n...\nRan 1 test for test/Counter.2.t.sol:CounterTest\n[PASS] testAssert() ([GAS])\nSuite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED]\n...\nRan 2 tests for test/Counter.t.sol:CounterTest\n[PASS] testFuzz_SetNumber(uint256) (runs: 256, [AVG_GAS])\n[PASS] test_Increment() ([GAS])\nSuite result: ok. 2 passed; 0 failed; 0 skipped; [ELAPSED]\n\nRan 2 test suites [ELAPSED]: 3 tests passed, 0 failed, 0 skipped (3 total tests)\n\n\"#]]);\n});\n"
  },
  {
    "path": "crates/forge/tests/cli/test_cmd/core.rs",
    "content": "//! Core test functionality tests\n\nuse foundry_test_utils::str;\n\nforgetest_init!(failing_test_after_failed_setup, |prj, cmd| {\n    prj.add_test(\n        \"FailingTestAfterFailedSetup.t.sol\",\n        r#\"\nimport \"forge-std/Test.sol\";\n\ncontract FailingTestAfterFailedSetupTest is Test {\n    function setUp() public {\n        assertTrue(false);\n    }\n\n    function testAssertSuccess() public {\n        assertTrue(true);\n    }\n\n    function testAssertFailure() public {\n        assertTrue(false);\n    }\n}\n\"#,\n    );\n\n    cmd.arg(\"test\").assert_failure().stdout_eq(str![[r#\"\n...\nRan 1 test for test/FailingTestAfterFailedSetup.t.sol:FailingTestAfterFailedSetupTest\n[FAIL: assertion failed] setUp() ([GAS])\nSuite result: FAILED. 0 passed; 1 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 0 tests passed, 1 failed, 0 skipped (1 total tests)\n\nFailing tests:\nEncountered 1 failing test in test/FailingTestAfterFailedSetup.t.sol:FailingTestAfterFailedSetupTest\n[FAIL: assertion failed] setUp() ([GAS])\n\nEncountered a total of 1 failing tests, 0 tests succeeded\n\nTip: Run `forge test --rerun` to retry only the 1 failed test\n\n\"#]]);\n});\n\nforgetest_init!(legacy_assertions, |prj, cmd| {\n    prj.add_test(\n        \"LegacyAssertions.t.sol\",\n        r#\"\nimport \"forge-std/Test.sol\";\n\ncontract NoAssertionsRevertTest is Test {\n    function testMultipleAssertFailures() public {\n        vm.assertEq(uint256(1), uint256(2));\n        vm.assertLt(uint256(5), uint256(4));\n    }\n}\n\n/// forge-config: default.legacy_assertions = true\ncontract LegacyAssertionsTest {\n    bool public failed;\n\n    function testFlagNotSetSuccess() public {}\n\n    function testFlagSetFailure() public {\n        failed = true;\n    }\n}\n\"#,\n    );\n\n    cmd.args([\"test\", \"-j1\"]).assert_failure().stdout_eq(str![[r#\"\n...\nRan 2 tests for test/LegacyAssertions.t.sol:LegacyAssertionsTest\n[PASS] testFlagNotSetSuccess() ([GAS])\n[FAIL] testFlagSetFailure() ([GAS])\nSuite result: FAILED. 1 passed; 1 failed; 0 skipped; [ELAPSED]\n\nRan 1 test for test/LegacyAssertions.t.sol:NoAssertionsRevertTest\n[FAIL: assertion failed: 1 != 2] testMultipleAssertFailures() ([GAS])\nSuite result: FAILED. 0 passed; 1 failed; 0 skipped; [ELAPSED]\n\nRan 2 test suites [ELAPSED]: 1 tests passed, 2 failed, 0 skipped (3 total tests)\n\nFailing tests:\nEncountered 1 failing test in test/LegacyAssertions.t.sol:LegacyAssertionsTest\n[FAIL] testFlagSetFailure() ([GAS])\n\nEncountered 1 failing test in test/LegacyAssertions.t.sol:NoAssertionsRevertTest\n[FAIL: assertion failed: 1 != 2] testMultipleAssertFailures() ([GAS])\n\nEncountered a total of 2 failing tests, 1 tests succeeded\n\nTip: Run `forge test --rerun` to retry only the 2 failed tests\n\n\"#]]);\n});\n\nforgetest_init!(payment_failure, |prj, cmd| {\n    prj.add_test(\n        \"PaymentFailure.t.sol\",\n        r#\"\nimport \"forge-std/Test.sol\";\n\ncontract Payable {\n    function pay() public payable {}\n}\n\ncontract PaymentFailureTest is Test {\n    function testCantPay() public {\n        Payable target = new Payable();\n        vm.prank(address(1));\n        target.pay{value: 1}();\n    }\n}\n\"#,\n    );\n\n    cmd.arg(\"test\").assert_failure().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\nRan 1 test for test/PaymentFailure.t.sol:PaymentFailureTest\n[FAIL: EvmError: Revert] testCantPay() ([GAS])\nSuite result: FAILED. 0 passed; 1 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 0 tests passed, 1 failed, 0 skipped (1 total tests)\n\nFailing tests:\nEncountered 1 failing test in test/PaymentFailure.t.sol:PaymentFailureTest\n[FAIL: EvmError: Revert] testCantPay() ([GAS])\n\nEncountered a total of 1 failing tests, 0 tests succeeded\n\nTip: Run `forge test --rerun` to retry only the 1 failed test\n\n\"#]]);\n});\n"
  },
  {
    "path": "crates/forge/tests/cli/test_cmd/fuzz.rs",
    "content": "use alloy_primitives::U256;\nuse foundry_test_utils::{TestCommand, forgetest_init, str};\nuse regex::Regex;\n\nforgetest_init!(test_can_scrape_bytecode, |prj, cmd| {\n    prj.update_config(|config| config.optimizer = Some(true));\n    prj.add_source(\n        \"FuzzerDict.sol\",\n        r#\"\n// https://github.com/foundry-rs/foundry/issues/1168\ncontract FuzzerDict {\n    // Immutables should get added to the dictionary.\n    address public immutable immutableOwner;\n    // Regular storage variables should also get added to the dictionary.\n    address public storageOwner;\n\n    constructor(address _immutableOwner, address _storageOwner) {\n        immutableOwner = _immutableOwner;\n        storageOwner = _storageOwner;\n    }\n}\n   \"#,\n    );\n\n    prj.add_test(\n        \"FuzzerDictTest.t.sol\",\n        r#\"\nimport {Test} from \"forge-std/Test.sol\";\nimport \"src/FuzzerDict.sol\";\n\ncontract FuzzerDictTest is Test {\n    FuzzerDict fuzzerDict;\n\n    function setUp() public {\n        fuzzerDict = new FuzzerDict(address(100), address(200));\n    }\n\n    /// forge-config: default.fuzz.runs = 2000\n    function testImmutableOwner(address who) public {\n        assertTrue(who != fuzzerDict.immutableOwner());\n    }\n\n    /// forge-config: default.fuzz.runs = 2000\n    function testStorageOwner(address who) public {\n        assertTrue(who != fuzzerDict.storageOwner());\n    }\n}\n   \"#,\n    );\n\n    // Test that immutable address is used as fuzzed input, causing test to fail.\n    cmd.args([\"test\", \"--fuzz-seed\", \"119\", \"--mt\", \"testImmutableOwner\"]).assert_failure();\n    // Test that storage address is used as fuzzed input, causing test to fail.\n    cmd.forge_fuse()\n        .args([\"test\", \"--fuzz-seed\", \"119\", \"--mt\", \"testStorageOwner\"])\n        .assert_failure();\n});\n\n// tests that inline max-test-rejects config is properly applied\nforgetest_init!(test_inline_max_test_rejects, |prj, cmd| {\n    prj.add_test(\n        \"Contract.t.sol\",\n        r#\"\nimport {Test} from \"forge-std/Test.sol\";\n\ncontract InlineMaxRejectsTest is Test {\n    /// forge-config: default.fuzz.max-test-rejects = 1\n    function test_fuzz_bound(uint256 a) public {\n        vm.assume(false);\n    }\n}\n   \"#,\n    );\n\n    cmd.args([\"test\"]).assert_failure().stdout_eq(str![[r#\"\n...\n[FAIL: `vm.assume` rejected too many inputs (1 allowed)] test_fuzz_bound(uint256) (runs: 0, [AVG_GAS])\n...\n\"#]]);\n});\n\n// Tests that test timeout config is properly applied.\n// If test doesn't timeout after one second, then test will fail with `rejected too many inputs`.\nforgetest_init!(test_fuzz_timeout, |prj, cmd| {\n    prj.add_test(\n        \"Contract.t.sol\",\n        r#\"\nimport {Test} from \"forge-std/Test.sol\";\n\ncontract FuzzTimeoutTest is Test {\n    /// forge-config: default.fuzz.max-test-rejects = 0\n    /// forge-config: default.fuzz.timeout = 1\n    function test_fuzz_bound(uint256 a) public pure {\n        vm.assume(a == 0);\n    }\n}\n   \"#,\n    );\n\n    cmd.args([\"test\", \"-j2\"]).assert_success().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\nRan 1 test for test/Contract.t.sol:FuzzTimeoutTest\n[PASS] test_fuzz_bound(uint256) (runs: [..], [AVG_GAS])\nSuite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests)\n\n\"#]]);\n});\n\nforgetest_init!(test_fuzz_fail_on_revert, |prj, cmd| {\n    prj.update_config(|config| {\n        config.fuzz.fail_on_revert = false;\n        config.fuzz.seed = Some(U256::from(100u32));\n    });\n    prj.add_source(\n        \"Counter.sol\",\n        r#\"\ncontract Counter {\n    uint256 public number;\n\n    function setNumber(uint256 newNumber) public {\n        require(number > 10000000000, \"low number\");\n        number = newNumber;\n    }\n}\n   \"#,\n    );\n\n    prj.add_test(\n        \"CounterTest.t.sol\",\n        r#\"\nimport {Test} from \"forge-std/Test.sol\";\nimport \"src/Counter.sol\";\n\ncontract CounterTest is Test {\n    Counter public counter;\n\n    function setUp() public {\n        counter = new Counter();\n    }\n\n    function testFuzz_SetNumberRequire(uint256 x) public {\n        counter.setNumber(x);\n        require(counter.number() == 1);\n    }\n\n    function testFuzz_SetNumberAssert(uint256 x) public {\n        counter.setNumber(x);\n        assertEq(counter.number(), 1);\n    }\n}\n   \"#,\n    );\n\n    // Tests should not fail as revert happens in Counter contract.\n    cmd.args([\"test\", \"--mc\", \"CounterTest\"]).assert_success().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\nRan 2 tests for test/CounterTest.t.sol:CounterTest\n[PASS] testFuzz_SetNumberAssert(uint256) (runs: 256, [AVG_GAS])\n[PASS] testFuzz_SetNumberRequire(uint256) (runs: 256, [AVG_GAS])\nSuite result: ok. 2 passed; 0 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 2 tests passed, 0 failed, 0 skipped (2 total tests)\n\n\"#]]);\n\n    // Tested contract does not revert.\n    prj.add_source(\n        \"Counter.sol\",\n        r#\"\ncontract Counter {\n    uint256 public number;\n\n    function setNumber(uint256 newNumber) public {\n        number = newNumber;\n    }\n}\n   \"#,\n    );\n\n    // Tests should fail as revert happens in cheatcode (assert) and test (require) contract.\n    cmd.args([\"-j1\"]).assert_failure().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\nRan 2 tests for test/CounterTest.t.sol:CounterTest\n[FAIL: assertion failed: [..]] testFuzz_SetNumberAssert(uint256) (runs: 0, [AVG_GAS])\n[FAIL: EvmError: Revert; [..]] testFuzz_SetNumberRequire(uint256) (runs: 0, [AVG_GAS])\nSuite result: FAILED. 0 passed; 2 failed; 0 skipped; [ELAPSED]\n...\n\n\"#]]);\n});\n\n// Test 256 runs regardless number of test rejects.\n// <https://github.com/foundry-rs/foundry/issues/9054>\nforgetest_init!(test_fuzz_runs_with_rejects, |prj, cmd| {\n    prj.add_test(\n        \"FuzzWithRejectsTest.t.sol\",\n        r#\"\nimport {Test} from \"forge-std/Test.sol\";\n\ncontract FuzzWithRejectsTest is Test {\n    function testFuzzWithRejects(uint256 x) public pure {\n        vm.assume(x < 1_000_000);\n    }\n}\n   \"#,\n    );\n\n    // Tests should not fail as revert happens in Counter contract.\n    cmd.args([\"test\", \"--mc\", \"FuzzWithRejectsTest\"]).assert_success().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\nRan 1 test for test/FuzzWithRejectsTest.t.sol:FuzzWithRejectsTest\n[PASS] testFuzzWithRejects(uint256) (runs: 256, [AVG_GAS])\nSuite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests)\n\n\"#]]);\n});\n\n// Test that counterexample is not replayed if test changes.\n// <https://github.com/foundry-rs/foundry/issues/11927>\nforgetest_init!(test_fuzz_replay_with_changed_test, |prj, cmd| {\n    prj.update_config(|config| config.fuzz.seed = Some(U256::from(100u32)));\n    prj.add_test(\n        \"Counter.t.sol\",\n        r#\"\nimport {Test} from \"forge-std/Test.sol\";\n\ncontract CounterTest is Test {\n    function testFuzz_SetNumber(uint256 x) public pure {\n        require(x > 200);\n    }\n}\n   \"#,\n    );\n    // Tests should fail and record counterexample with value 200.\n    cmd.args([\"test\", \"-j1\"]).assert_failure().stdout_eq(str![[r#\"\n...\nFailing tests:\nEncountered 1 failing test in test/Counter.t.sol:CounterTest\n[FAIL: EvmError: Revert; counterexample: calldata=0x5c7f60d700000000000000000000000000000000000000000000000000000000000000c8 args=[200]] testFuzz_SetNumber(uint256) (runs: 6, [AVG_GAS])\n...\n\n\"#]]);\n\n    // Change test to assume counterexample 2 is discarded.\n    prj.add_test(\n        \"Counter.t.sol\",\n        r#\"\nimport {Test} from \"forge-std/Test.sol\";\n\ncontract CounterTest is Test {\n    function testFuzz_SetNumber(uint256 x) public pure {\n        vm.assume(x != 200);\n    }\n}\n   \"#,\n    );\n    // Test should pass when replay failure with changed assume logic.\n    cmd.forge_fuse().args([\"test\"]).assert_success().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\nRan 1 test for test/Counter.t.sol:CounterTest\n[PASS] testFuzz_SetNumber(uint256) (runs: 256, [AVG_GAS])\nSuite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests)\n\n\"#]]);\n\n    // Change test signature.\n    prj.add_test(\n        \"Counter.t.sol\",\n        r#\"\nimport {Test} from \"forge-std/Test.sol\";\n\ncontract CounterTest is Test {\n    function testFuzz_SetNumber(uint8 x) public pure {\n    }\n}\n   \"#,\n    );\n    // Test should pass when replay failure with changed function signature.\n    cmd.forge_fuse().args([\"test\"]).assert_success().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\nRan 1 test for test/Counter.t.sol:CounterTest\n[PASS] testFuzz_SetNumber(uint8) (runs: 256, [AVG_GAS])\nSuite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests)\n\n\"#]]);\n\n    // Change test back to the original one that produced the counterexample.\n    prj.add_test(\n        \"Counter.t.sol\",\n        r#\"\nimport {Test} from \"forge-std/Test.sol\";\n\ncontract CounterTest is Test {\n    function testFuzz_SetNumber(uint256 x) public pure {\n        require(x > 200);\n    }\n}\n   \"#,\n    );\n    // Test should fail with replayed counterexample 200 (0 runs).\n    cmd.forge_fuse().args([\"test\", \"-j1\"]).assert_failure().stdout_eq(str![[r#\"\n...\nFailing tests:\nEncountered 1 failing test in test/Counter.t.sol:CounterTest\n[FAIL: EvmError: Revert; counterexample: calldata=0x5c7f60d700000000000000000000000000000000000000000000000000000000000000c8 args=[200]] testFuzz_SetNumber(uint256) (runs: 0, [AVG_GAS])\n...\n\n\"#]]);\n});\n\nforgetest_init!(fuzz_basic, |prj, cmd| {\n    prj.add_test(\n        \"Fuzz.t.sol\",\n        r#\"\nimport \"forge-std/Test.sol\";\n\ncontract FuzzTest is Test {\n    constructor() {\n        emit log(\"constructor\");\n    }\n\n    function setUp() public {\n        emit log(\"setUp\");\n    }\n\n    function testShouldFailFuzz(uint8 x) public {\n        emit log(\"testFailFuzz\");\n        require(x > 128, \"should revert\");\n    }\n\n    function testSuccessfulFuzz(uint128 a, uint128 b) public {\n        emit log(\"testSuccessfulFuzz\");\n        assertEq(uint256(a) + uint256(b), uint256(a) + uint256(b));\n    }\n\n    function testToStringFuzz(bytes32 data) public {\n        vm.toString(data);\n    }\n}\n   \"#,\n    );\n\n    cmd.args([\"test\"]).assert_failure().stdout_eq(str![[r#\"\n...\nRan 3 tests for test/Fuzz.t.sol:FuzzTest\n[FAIL: should revert; counterexample: calldata=[..] args=[..]] testShouldFailFuzz(uint8) (runs: [..], [AVG_GAS])\n[PASS] testSuccessfulFuzz(uint128,uint128) (runs: 256, [AVG_GAS])\n[PASS] testToStringFuzz(bytes32) (runs: 256, [AVG_GAS])\nSuite result: FAILED. 2 passed; 1 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 2 tests passed, 1 failed, 0 skipped (3 total tests)\n\nFailing tests:\nEncountered 1 failing test in test/Fuzz.t.sol:FuzzTest\n[FAIL: should revert; counterexample: calldata=[..] args=[..]] testShouldFailFuzz(uint8) (runs: [..], [AVG_GAS])\n\nEncountered a total of 1 failing tests, 2 tests succeeded\n\nTip: Run `forge test --rerun` to retry only the 1 failed test\n\n[SEED] (use `--fuzz-seed` to reproduce)\n\n\"#]]);\n});\n\n// Test that showcases PUSH collection on normal fuzzing.\n// Ignored until we collect them in a smarter way.\nforgetest_init!(\n    #[ignore]\n    fuzz_collection,\n    |prj, cmd| {\n        prj.update_config(|config| {\n            config.invariant.depth = 100;\n            config.invariant.runs = 1000;\n            config.fuzz.runs = 1000;\n            config.fuzz.seed = Some(U256::from(6u32));\n        });\n        prj.add_test(\n            \"FuzzCollection.t.sol\",\n            r#\"\nimport \"forge-std/Test.sol\";\n\ncontract SampleContract {\n    uint256 public counter;\n    uint256 public counterX2;\n    address public owner = address(0xBEEF);\n    bool public found_needle;\n\n    event Incremented(uint256 counter);\n\n    modifier onlyOwner() {\n        require(msg.sender == owner, \"ONLY_OWNER\");\n        _;\n    }\n\n    function compare(uint256 val) public {\n        if (val == 0x4446) {\n            found_needle = true;\n        }\n    }\n\n    function incrementBy(uint256 numToIncrement) public onlyOwner {\n        counter += numToIncrement;\n        counterX2 += numToIncrement * 2;\n\n        emit Incremented(counter);\n    }\n\n    function breakTheInvariant(uint256 x) public {\n        if (x == 0x5556) {\n            counterX2 = 0;\n        }\n    }\n}\n\ncontract SampleContractTest is Test {\n    event Incremented(uint256 counter);\n\n    SampleContract public sample;\n\n    function setUp() public {\n        sample = new SampleContract();\n    }\n\n    function testIncrement(address caller) public {\n        vm.startPrank(address(caller));\n\n        vm.expectRevert(\"ONLY_OWNER\");\n        sample.incrementBy(1);\n    }\n\n    function testNeedle(uint256 needle) public {\n        sample.compare(needle);\n        require(!sample.found_needle(), \"needle found.\");\n    }\n\n    function invariantCounter() public {\n        require(sample.counter() * 2 == sample.counterX2(), \"broken counter.\");\n    }\n}\n   \"#,\n        );\n\n        cmd.args([\"test\"]).assert_failure().stdout_eq(str![[r#\"\"#]]);\n    }\n);\n\nforgetest_init!(fuzz_failure_persist, |prj, cmd| {\n    let persist_dir = prj.cache().parent().unwrap().join(\"persist\");\n    assert!(!persist_dir.exists());\n    prj.update_config(|config| {\n        config.fuzz.failure_persist_dir = Some(persist_dir.clone());\n    });\n\n    prj.add_test(\n        \"FuzzFailurePersist.t.sol\",\n        r#\"\nimport \"forge-std/Test.sol\";\n\nstruct TestTuple {\n    address user;\n    uint256 amount;\n}\n\ncontract FuzzFailurePersistTest is Test {\n    function test_persist_fuzzed_failure(\n        uint256 x,\n        int256 y,\n        address addr,\n        bool cond,\n        string calldata test,\n        TestTuple calldata tuple,\n        address[] calldata addresses\n    ) public {\n        // dummy assume to trigger runs\n        vm.assume(x > 1 && x < 1111111111111111111111111111);\n        vm.assume(y > 1 && y < 1111111111111111111111111111);\n        require(false);\n    }\n}\n   \"#,\n    );\n\n    let mut calldata = None;\n    let expected = str![[r#\"\n...\nRan 1 test for test/FuzzFailurePersist.t.sol:FuzzFailurePersistTest\n[FAIL: EvmError: Revert; counterexample: calldata=[..] args=[..]] test_persist_fuzzed_failure(uint256,int256,address,bool,string,(address,uint256),address[]) (runs: 0, [AVG_GAS])\nSuite result: FAILED. 0 passed; 1 failed; 0 skipped; [ELAPSED]\n...\n\"#]];\n    let mut check = |cmd: &mut TestCommand, same: bool| {\n        let assert = cmd.assert_failure();\n        let output = assert.get_output();\n        let stdout = String::from_utf8_lossy(&output.stdout);\n        let calldata = calldata.get_or_insert_with(|| {\n            let re = Regex::new(r\"calldata=(0x[0-9a-fA-F]+)\").unwrap();\n            re.captures(&stdout).unwrap().get(1).unwrap().as_str().to_string()\n        });\n        assert_eq!(stdout.contains(calldata.as_str()), same, \"\\n{stdout}\");\n        assert.stdout_eq(expected.clone());\n    };\n\n    cmd.args([\"test\", \"-j1\"]);\n\n    // Run several times, asserting that the failure persists and is the same.\n    for _ in 0..3 {\n        check(&mut cmd, true);\n        assert!(persist_dir.exists());\n    }\n\n    // Change dir and run again, asserting that the failure persists. It should be a new failure.\n    let new_persist_dir = prj.cache().parent().unwrap().join(\"persist2\");\n    assert!(!new_persist_dir.exists());\n    prj.update_config(|config| {\n        config.fuzz.failure_persist_dir = Some(new_persist_dir.clone());\n    });\n    check(&mut cmd, false);\n    assert!(new_persist_dir.exists());\n});\n\n// https://github.com/foundry-rs/foundry/pull/735 behavior changed with https://github.com/foundry-rs/foundry/issues/3521\n// random values (instead edge cases) are generated if no fixtures defined\nforgetest_init!(fuzz_int, |prj, cmd| {\n    prj.add_test(\n        \"FuzzInt.t.sol\",\n        r#\"\nimport \"forge-std/Test.sol\";\n\ncontract FuzzNumbersTest is Test {\n    function testPositive(int256) public {\n        assertTrue(true);\n    }\n\n    function testNegativeHalf(int256 val) public {\n        assertTrue(val < 2 ** 128 - 1);\n    }\n\n    function testNegative0(int256 val) public {\n        assertTrue(val == 0);\n    }\n\n    function testNegative1(int256 val) public {\n        assertTrue(val == -1);\n    }\n\n    function testNegative2(int128 val) public {\n        assertTrue(val == 1);\n    }\n\n    function testNegativeMax0(int256 val) public {\n        assertTrue(val == type(int256).max);\n    }\n\n    function testNegativeMax1(int256 val) public {\n        assertTrue(val == type(int256).max - 2);\n    }\n\n    function testNegativeMin0(int256 val) public {\n        assertTrue(val == type(int256).min);\n    }\n\n    function testNegativeMin1(int256 val) public {\n        assertTrue(val == type(int256).min + 2);\n    }\n\n    function testEquality(int256 x, int256 y) public {\n        int256 xy;\n\n        unchecked {\n            xy = x * y;\n        }\n\n        if ((x != 0 && xy / x != y)) {\n            return;\n        }\n\n        assertEq(((xy - 1) / 1e18) + 1, (xy - 1) / (1e18 + 1));\n    }\n}\n   \"#,\n    );\n\n    cmd.args([\"test\"]).assert_failure().stdout_eq(str![[r#\"\n...\nRan 10 tests for test/FuzzInt.t.sol:FuzzNumbersTest\n[FAIL: assertion failed[..]] testEquality(int256,int256) (runs: [..], [AVG_GAS])\n[FAIL: assertion failed[..]] testNegative0(int256) (runs: [..], [AVG_GAS])\n[FAIL: assertion failed[..]] testNegative1(int256) (runs: [..], [AVG_GAS])\n[FAIL: assertion failed[..]] testNegative2(int128) (runs: [..], [AVG_GAS])\n[FAIL: assertion failed[..]] testNegativeHalf(int256) (runs: [..], [AVG_GAS])\n[FAIL: assertion failed[..]] testNegativeMax0(int256) (runs: [..], [AVG_GAS])\n[FAIL: assertion failed[..]] testNegativeMax1(int256) (runs: [..], [AVG_GAS])\n[FAIL: assertion failed[..]] testNegativeMin0(int256) (runs: [..], [AVG_GAS])\n[FAIL: assertion failed[..]] testNegativeMin1(int256) (runs: [..], [AVG_GAS])\n[PASS] testPositive(int256) (runs: 256, [AVG_GAS])\nSuite result: FAILED. 1 passed; 9 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 1 tests passed, 9 failed, 0 skipped (10 total tests)\n...\n\"#]]);\n});\n\nforgetest_init!(fuzz_positive, |prj, cmd| {\n    prj.add_test(\n        \"FuzzPositive.t.sol\",\n        r#\"\nimport \"forge-std/Test.sol\";\n\ncontract FuzzPositive is Test {\n    function testSuccessChecker(uint256 val) public {\n        assertTrue(true);\n    }\n\n    function testSuccessChecker2(int256 val) public {\n        assert(val == val);\n    }\n\n    function testSuccessChecker3(uint32 val) public {\n        assert(val + 0 == val);\n    }\n}\n   \"#,\n    );\n\n    cmd.args([\"test\"]).assert_success().stdout_eq(str![[r#\"\n...\nRan 3 tests for test/FuzzPositive.t.sol:FuzzPositive\n[PASS] testSuccessChecker(uint256) (runs: 256, [AVG_GAS])\n[PASS] testSuccessChecker2(int256) (runs: 256, [AVG_GAS])\n[PASS] testSuccessChecker3(uint32) (runs: 256, [AVG_GAS])\nSuite result: ok. 3 passed; 0 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 3 tests passed, 0 failed, 0 skipped (3 total tests)\n\n\"#]]);\n});\n\n// https://github.com/foundry-rs/foundry/pull/735 behavior changed with https://github.com/foundry-rs/foundry/issues/3521\n// random values (instead edge cases) are generated if no fixtures defined\nforgetest_init!(fuzz_uint, |prj, cmd| {\n    prj.update_config(|config| {\n        config.fuzz.seed = Some(U256::from(100u32));\n    });\n    prj.add_test(\n        \"FuzzUint.t.sol\",\n        r#\"\nimport \"forge-std/Test.sol\";\n\ncontract FuzzNumbersTest is Test {\n    function testPositive(uint256) public {\n        assertTrue(true);\n    }\n\n    function testNegativeHalf(uint256 val) public {\n        assertTrue(val < 2 ** 128 - 1);\n    }\n\n    function testNegative0(uint256 val) public {\n        assertTrue(val == 0);\n    }\n\n    function testNegative2(uint256 val) public {\n        assertTrue(val == 2);\n    }\n\n    function testNegative2Max(uint256 val) public {\n        assertTrue(val == type(uint256).max - 2);\n    }\n\n    function testNegativeMax(uint256 val) public {\n        assertTrue(val == type(uint256).max);\n    }\n\n    function testEquality(uint256 x, uint256 y) public {\n        uint256 xy;\n\n        unchecked {\n            xy = x * y;\n        }\n\n        if ((x != 0 && xy / x != y)) {\n            return;\n        }\n\n        assertEq(((xy - 1) / 1e18) + 1, (xy - 1) / (1e18 + 1));\n    }\n}\n   \"#,\n    );\n\n    cmd.args([\"test\"]).assert_failure().stdout_eq(str![[r#\"\n...\nRan 7 tests for test/FuzzUint.t.sol:FuzzNumbersTest\n[FAIL: assertion failed[..]] testEquality(uint256,uint256) (runs: [..], [AVG_GAS])\n[FAIL: assertion failed[..]] testNegative0(uint256) (runs: [..], [AVG_GAS])\n[FAIL: assertion failed[..]] testNegative2(uint256) (runs: [..], [AVG_GAS])\n[FAIL: assertion failed[..]] testNegative2Max(uint256) (runs: [..], [AVG_GAS])\n[FAIL: assertion failed[..]] testNegativeHalf(uint256) (runs: [..], [AVG_GAS])\n[FAIL: assertion failed[..]] testNegativeMax(uint256) (runs: [..], [AVG_GAS])\n[PASS] testPositive(uint256) (runs: 256, [AVG_GAS])\nSuite result: FAILED. 1 passed; 6 failed; 0 skipped; [ELAPSED]\n...\n\"#]]);\n});\n\nforgetest_init!(should_fuzz_literals, |prj, cmd| {\n    // Add a source with magic (literal) values\n    prj.add_source(\n        \"Magic.sol\",\n        r#\"\n        contract Magic {\n            // plain literals\n            address constant DAI = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\n            uint64 constant MAGIC_NUMBER = 1122334455;\n            int32 constant MAGIC_INT = -777;\n            bytes32 constant MAGIC_WORD = \"abcd1234\";\n            bytes constant MAGIC_BYTES = hex\"deadbeef\";\n            string constant MAGIC_STRING = \"xyzzy\";\n\n            function checkAddr(address v) external pure { assert(v != DAI); }\n            function checkWord(bytes32 v) external pure { assert(v != MAGIC_WORD); }\n            function checkNumber(uint64 v) external pure { assert(v != MAGIC_NUMBER); }\n            function checkInteger(int32 v) external pure { assert(v != MAGIC_INT); }\n            function checkString(string memory v) external pure { assert(keccak256(abi.encodePacked(v)) != keccak256(abi.encodePacked(MAGIC_STRING))); }\n            function checkBytesFromHex(bytes memory v) external pure { assert(keccak256(v) != keccak256(MAGIC_BYTES)); }\n            function checkBytesFromString(bytes memory v) external pure { assert(keccak256(v) != keccak256(abi.encodePacked(MAGIC_STRING))); }\n        }\n        \"#,\n    );\n\n    prj.add_test(\n        \"MagicFuzz.t.sol\",\n        r#\"\n            import {Test} from \"forge-std/Test.sol\";\n            import {Magic} from \"src/Magic.sol\";\n\n            contract MagicTest is Test {\n                Magic public magic;\n                function setUp() public { magic = new Magic(); }\n\n                function testFuzz_Addr(address v) public view { magic.checkAddr(v); }\n                function testFuzz_Number(uint64 v) public view { magic.checkNumber(v); }\n                function testFuzz_Integer(int32 v) public view { magic.checkInteger(v); }\n                function testFuzz_Word(bytes32 v) public view { magic.checkWord(v); }\n                function testFuzz_String(string memory v) public view { magic.checkString(v); }\n                function testFuzz_BytesFromHex(bytes memory v) public view { magic.checkBytesFromHex(v); }\n                function testFuzz_BytesFromString(bytes memory v) public view { magic.checkBytesFromString(v); }\n            }\n        \"#,\n    );\n\n    // Helper to create expected output for a test failure\n    let expected_fail = |test_name: &str, type_sig: &str, value: &str| -> String {\n        format!(\n            r#\"No files changed, compilation skipped\n\nRan 1 test for test/MagicFuzz.t.sol:MagicTest\n[FAIL: panic: assertion failed (0x01); counterexample: calldata=[..] args=[{value}]] {test_name}({type_sig}) (runs: [..], [AVG_GAS])\n[..]\n\nRan 1 test suite [ELAPSED]: 0 tests passed, 1 failed, 0 skipped (1 total tests)\n\nFailing tests:\n...\nEncountered a total of 1 failing tests, 0 tests succeeded\n...\n\"#\n        )\n    };\n\n    // Test address literal fuzzing\n    let mut test_literal = |seed: u32,\n                            test_name: &'static str,\n                            type_sig: &'static str,\n                            expected_value: &'static str| {\n        // the fuzzer is UNABLE to find a breaking input (fast) when NOT seeding from the AST\n        prj.update_config(|config| {\n            config.fuzz.runs = 100;\n            config.fuzz.dictionary.max_fuzz_dictionary_literals = 0;\n            config.fuzz.seed = Some(U256::from(seed));\n        });\n        cmd.forge_fuse().args([\"test\", \"--match-test\", test_name, \"-j1\"]).assert_success();\n\n        // the fuzzer is ABLE to find a breaking input when seeding from the AST\n        prj.update_config(|config| {\n            config.fuzz.dictionary.max_fuzz_dictionary_literals = 10_000;\n        });\n\n        let expected_output = expected_fail(test_name, type_sig, expected_value);\n        cmd.forge_fuse()\n            .args([\"test\", \"--match-test\", test_name, \"-j1\"])\n            .assert_failure()\n            .stdout_eq(expected_output);\n    };\n\n    test_literal(100, \"testFuzz_Addr\", \"address\", \"0x6B175474E89094C44Da98b954EedeAC495271d0F\");\n    test_literal(200, \"testFuzz_Number\", \"uint64\", \"1122334455 [1.122e9]\");\n    test_literal(300, \"testFuzz_Integer\", \"int32\", \"-777\");\n    test_literal(\n        400,\n        \"testFuzz_Word\",\n        \"bytes32\",\n        \"0x6162636431323334000000000000000000000000000000000000000000000000\", /* bytes32(\"abcd1234\") */\n    );\n    test_literal(500, \"testFuzz_BytesFromHex\", \"bytes\", \"0xdeadbeef\");\n    test_literal(600, \"testFuzz_String\", \"string\", \"\\\"xyzzy\\\"\");\n    test_literal(999, \"testFuzz_BytesFromString\", \"bytes\", \"0x78797a7a79\"); // abi.encodePacked(\"xyzzy\")\n});\n\n// Tests that `vm.randomUint()` produces different values across fuzz runs.\n// Regression test for https://github.com/foundry-rs/foundry/issues/12817\n//\n// The issue was that `vm.randomUint()` would produce the same sequence of values\n// in every fuzz run because the RNG was seeded identically for each run.\n// This test verifies that with many fuzz runs and a small range, we eventually\n// hit value 0, which proves the RNG varies across runs.\nforgetest_init!(test_fuzz_random_uint_varies_across_runs, |prj, cmd| {\n    prj.add_test(\n        \"RandomFuzzTest.t.sol\",\n        r#\"\nimport {Test} from \"forge-std/Test.sol\";\n\ncontract RandomFuzzTest is Test {\n    function testFuzz_randomUint_shouldFail(uint256) public {\n        uint256 rand = vm.randomUint(0, 4);\n        assertTrue(rand != 0, \"hit value 0\");\n    }\n}\n   \"#,\n    );\n\n    cmd.args([\"test\", \"--fuzz-seed\", \"1\", \"--mt\", \"testFuzz_randomUint_shouldFail\"])\n        .assert_failure()\n        .stdout_eq(str![[r#\"\n...\nRan 1 test for test/RandomFuzzTest.t.sol:RandomFuzzTest\n[FAIL: hit value 0; counterexample: [..]] testFuzz_randomUint_shouldFail(uint256) (runs: [..], [AVG_GAS])\nSuite result: FAILED. 0 passed; 1 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 0 tests passed, 1 failed, 0 skipped (1 total tests)\n...\n\"#]]);\n});\n"
  },
  {
    "path": "crates/forge/tests/cli/test_cmd/invariant/common.rs",
    "content": "use super::*;\n\nforgetest!(invariant_after_invariant, |prj, cmd| {\n    prj.insert_vm();\n    prj.insert_ds_test();\n\n    prj.add_test(\n        \"InvariantAfterInvariant.t.sol\",\n        r#\"\nimport { DSTest as Test } from \"src/test.sol\";\n\nstruct FuzzSelector {\n    address addr;\n    bytes4[] selectors;\n}\n\ncontract AfterInvariantHandler {\n    uint256 public count;\n\n    function inc() external {\n        count += 1;\n    }\n}\n\ncontract InvariantAfterInvariantTest is Test {\n    AfterInvariantHandler handler;\n\n    function setUp() public {\n        handler = new AfterInvariantHandler();\n    }\n\n    function targetSelectors() public returns (FuzzSelector[] memory) {\n        FuzzSelector[] memory targets = new FuzzSelector[](1);\n        bytes4[] memory selectors = new bytes4[](1);\n        selectors[0] = handler.inc.selector;\n        targets[0] = FuzzSelector(address(handler), selectors);\n        return targets;\n    }\n\n    function afterInvariant() public {\n        require(handler.count() < 10, \"afterInvariant failure\");\n    }\n\n    /// forge-config: default.invariant.runs = 1\n    /// forge-config: default.invariant.depth = 11\n    function invariant_after_invariant_failure() public view {\n        require(handler.count() < 20, \"invariant after invariant failure\");\n    }\n\n    /// forge-config: default.invariant.runs = 1\n    /// forge-config: default.invariant.depth = 11\n    function invariant_failure() public view {\n        require(handler.count() < 9, \"invariant failure\");\n    }\n\n    /// forge-config: default.invariant.runs = 1\n    /// forge-config: default.invariant.depth = 5\n    function invariant_success() public view {\n        require(handler.count() < 11, \"invariant should not fail\");\n    }\n}\n\"#,\n    );\n\n    assert_invariant(cmd.args([\"test\"])).failure().stdout_eq(str![[r#\"\n...\nRan 3 tests for test/InvariantAfterInvariant.t.sol:InvariantAfterInvariantTest\n[FAIL: afterInvariant failure]\n\t[SEQUENCE]\n invariant_after_invariant_failure() ([RUNS])\n\n[STATS]\n\n[FAIL: invariant failure]\n\t[SEQUENCE]\n invariant_failure() ([RUNS])\n\n[STATS]\n\n[PASS] invariant_success() ([RUNS])\n\n[STATS]\n\nSuite result: FAILED. 1 passed; 2 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 1 tests passed, 2 failed, 0 skipped (3 total tests)\n\nFailing tests:\nEncountered 2 failing tests in test/InvariantAfterInvariant.t.sol:InvariantAfterInvariantTest\n[FAIL: afterInvariant failure]\n\t[SEQUENCE]\n invariant_after_invariant_failure() ([RUNS])\n[FAIL: invariant failure]\n\t[SEQUENCE]\n invariant_failure() ([RUNS])\n\nEncountered a total of 2 failing tests, 1 tests succeeded\n\nTip: Run `forge test --rerun` to retry only the 2 failed tests\n\n[SEED] (use `--fuzz-seed` to reproduce)\n\n\"#]]);\n});\n\nforgetest_init!(invariant_assume, |prj, cmd| {\n    prj.update_config(|config| {\n        config.invariant.runs = 1;\n        config.invariant.depth = 10;\n        // Should not treat vm.assume as revert.\n        config.invariant.fail_on_revert = true;\n    });\n\n    prj.add_test(\n        \"InvariantAssume.t.sol\",\n        r#\"\nimport \"forge-std/Test.sol\";\n\ncontract Handler is Test {\n    uint256 public count;\n    function doSomething(uint256 param) public {\n        vm.assume(param == 0);\n        count++;\n    }\n}\n\ncontract InvariantAssume is Test {\n    Handler handler;\n\n    function setUp() public {\n        handler = new Handler();\n    }\n\n    function invariant_dummy() public {}\n}\n\"#,\n    );\n\n    assert_invariant(cmd.args([\"test\"])).success().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\nRan 1 test for test/InvariantAssume.t.sol:InvariantAssume\n[PASS] invariant_dummy() ([RUNS])\n\n[STATS]\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests)\n\n\"#]]);\n\n    // Test that max_assume_rejects is respected.\n    prj.update_config(|config| {\n        config.invariant.max_assume_rejects = 1;\n    });\n\n    assert_invariant(&mut cmd).failure().stdout_eq(str![[r#\"\nNo files changed, compilation skipped\n\nRan 1 test for test/InvariantAssume.t.sol:InvariantAssume\n[FAIL: `vm.assume` rejected too many inputs (1 allowed)] invariant_dummy() ([RUNS])\n\n[STATS]\n\nSuite result: FAILED. 0 passed; 1 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 0 tests passed, 1 failed, 0 skipped (1 total tests)\n\nFailing tests:\nEncountered 1 failing test in test/InvariantAssume.t.sol:InvariantAssume\n[FAIL: `vm.assume` rejected too many inputs (1 allowed)] invariant_dummy() ([RUNS])\n\nEncountered a total of 1 failing tests, 0 tests succeeded\n\nTip: Run `forge test --rerun` to retry only the 1 failed test\n\n[SEED] (use `--fuzz-seed` to reproduce)\n\n\"#]]);\n});\n\n// https://github.com/foundry-rs/foundry/issues/5868\nforgetest!(invariant_calldata_dictionary, |prj, cmd| {\n    prj.insert_utils();\n    prj.update_config(|config| {\n        config.fuzz.seed = Some(U256::from(1));\n        config.invariant.depth = 10;\n    });\n\n    prj.add_test(\n        \"InvariantCalldataDictionary.t.sol\",\n        r#\"\nimport \"./utils/Test.sol\";\n\nstruct FuzzSelector {\n    address addr;\n    bytes4[] selectors;\n}\n\ncontract Owned {\n    address public owner;\n    address private ownerCandidate;\n\n    constructor() {\n        owner = msg.sender;\n    }\n\n    modifier onlyOwner() {\n        require(msg.sender == owner);\n        _;\n    }\n\n    modifier onlyOwnerCandidate() {\n        require(msg.sender == ownerCandidate);\n        _;\n    }\n\n    function transferOwnership(address candidate) external onlyOwner {\n        ownerCandidate = candidate;\n    }\n\n    function acceptOwnership() external onlyOwnerCandidate {\n        owner = ownerCandidate;\n    }\n}\n\ncontract Handler is Test {\n    Owned owned;\n\n    constructor(Owned _owned) {\n        owned = _owned;\n    }\n\n    function transferOwnership(address sender, address candidate) external {\n        vm.assume(sender != address(0));\n        vm.prank(sender);\n        owned.transferOwnership(candidate);\n    }\n\n    function acceptOwnership(address sender) external {\n        vm.assume(sender != address(0));\n        vm.prank(sender);\n        owned.acceptOwnership();\n    }\n}\n\ncontract InvariantCalldataDictionary is Test {\n    address owner;\n    Owned owned;\n    Handler handler;\n    address[] actors;\n\n    function setUp() public {\n        owner = address(this);\n        owned = new Owned();\n        handler = new Handler(owned);\n        actors.push(owner);\n        actors.push(address(777));\n    }\n\n    function targetSelectors() public returns (FuzzSelector[] memory) {\n        FuzzSelector[] memory targets = new FuzzSelector[](1);\n        bytes4[] memory selectors = new bytes4[](2);\n        selectors[0] = handler.transferOwnership.selector;\n        selectors[1] = handler.acceptOwnership.selector;\n        targets[0] = FuzzSelector(address(handler), selectors);\n        return targets;\n    }\n\n    function fixtureSender() external returns (address[] memory) {\n        return actors;\n    }\n\n    function fixtureCandidate() external returns (address[] memory) {\n        return actors;\n    }\n\n    function invariant_owner_never_changes() public {\n        assertEq(owned.owner(), owner);\n    }\n}\n\"#,\n    );\n\n    assert_invariant(cmd.args([\"test\"])).failure().stdout_eq(str![[r#\"\n...\nRan 1 test for test/InvariantCalldataDictionary.t.sol:InvariantCalldataDictionary\n[FAIL: <empty revert data>]\n\t[SEQUENCE]\n invariant_owner_never_changes() ([RUNS])\n\n...\n\nSuite result: FAILED. 0 passed; 1 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 0 tests passed, 1 failed, 0 skipped (1 total tests)\n\nFailing tests:\nEncountered 1 failing test in test/InvariantCalldataDictionary.t.sol:InvariantCalldataDictionary\n[FAIL: <empty revert data>]\n\t[SEQUENCE]\n invariant_owner_never_changes() ([RUNS])\n\nEncountered a total of 1 failing tests, 0 tests succeeded\n\nTip: Run `forge test --rerun` to retry only the 1 failed test\n\n[SEED] (use `--fuzz-seed` to reproduce)\n\n\"#]]);\n});\n\nforgetest_init!(invariant_custom_error, |prj, cmd| {\n    prj.update_config(|config| {\n        config.invariant.depth = 10;\n        config.invariant.fail_on_revert = true;\n    });\n\n    prj.add_test(\n        \"InvariantCustomError.t.sol\",\n        r#\"\nimport \"forge-std/Test.sol\";\n\ncontract ContractWithCustomError {\n    error InvariantCustomError(uint256, string);\n\n    function revertWithInvariantCustomError() external {\n        revert InvariantCustomError(111, \"custom\");\n    }\n}\n\ncontract Handler is Test {\n    ContractWithCustomError target;\n\n    constructor() {\n        target = new ContractWithCustomError();\n    }\n\n    function revertTarget() external {\n        target.revertWithInvariantCustomError();\n    }\n}\n\ncontract InvariantCustomError is Test {\n    Handler handler;\n\n    function setUp() external {\n        handler = new Handler();\n    }\n\n    function invariant_decode_error() public {}\n}\n\"#,\n    );\n\n    assert_invariant(cmd.args([\"test\"])).failure().stdout_eq(str![[r#\"\n...\nRan 1 test for test/InvariantCustomError.t.sol:InvariantCustomError\n[FAIL: InvariantCustomError(111, \"custom\")]\n\t[SEQUENCE]\n invariant_decode_error() ([RUNS])\n\n[STATS]\n\nSuite result: FAILED. 0 passed; 1 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 0 tests passed, 1 failed, 0 skipped (1 total tests)\n\nFailing tests:\nEncountered 1 failing test in test/InvariantCustomError.t.sol:InvariantCustomError\n[FAIL: InvariantCustomError(111, \"custom\")]\n\t[SEQUENCE]\n invariant_decode_error() ([RUNS])\n\nEncountered a total of 1 failing tests, 0 tests succeeded\n\nTip: Run `forge test --rerun` to retry only the 1 failed test\n\n[SEED] (use `--fuzz-seed` to reproduce)\n\n\"#]]);\n});\n\nforgetest_init!(invariant_excluded_senders, |prj, cmd| {\n    prj.update_config(|config| {\n        config.invariant.depth = 10;\n        config.invariant.fail_on_revert = true;\n    });\n\n    prj.add_test(\n        \"InvariantExcludedSenders.t.sol\",\n        r#\"\nimport \"forge-std/Test.sol\";\n\ncontract InvariantSenders {\n    uint256 public count;\n    function checkSender() external {\n        require(msg.sender != 0x7109709ECfa91a80626fF3989D68f67F5b1DD12D, \"sender cannot be cheatcode address\");\n        require(msg.sender != 0x000000000000000000636F6e736F6c652e6c6f67, \"sender cannot be console address\");\n        require(msg.sender != 0x4e59b44847b379578588920cA78FbF26c0B4956C, \"sender cannot be CREATE2 deployer\");\n        count++;\n    }\n}\n\ncontract InvariantExcludedSendersTest is Test {\n    InvariantSenders target;\n\n    function setUp() public {\n        target = new InvariantSenders();\n    }\n\n    function invariant_check_sender() public view {}\n}\n\"#,\n    );\n\n    assert_invariant(cmd.args([\"test\"])).success().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\nRan 1 test for test/InvariantExcludedSenders.t.sol:InvariantExcludedSendersTest\n[PASS] invariant_check_sender() ([RUNS])\n\n[STATS]\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests)\n\n\"#]]);\n});\n\nforgetest_init!(invariant_fixtures, |prj, cmd| {\n    prj.update_config(|config| {\n        config.invariant.runs = 1;\n        config.invariant.depth = 100;\n        // disable literals to test fixtures\n        config.invariant.dictionary.max_fuzz_dictionary_literals = 0;\n        config.fuzz.dictionary.max_fuzz_dictionary_literals = 0;\n    });\n\n    prj.add_test(\n        \"InvariantFixtures.t.sol\",\n        r#\"\nimport \"forge-std/Test.sol\";\n\ncontract Target {\n    bool ownerFound;\n    bool amountFound;\n    bool magicFound;\n    bool keyFound;\n    bool backupFound;\n    bool extraStringFound;\n\n    function fuzzWithFixtures(\n        address owner_,\n        uint256 _amount,\n        int32 magic,\n        bytes32 key,\n        bytes memory backup,\n        string memory extra\n    ) external {\n        if (owner_ == address(0x6B175474E89094C44Da98b954EedeAC495271d0F)) {\n            ownerFound = true;\n        }\n        if (_amount == 1122334455) amountFound = true;\n        if (magic == -777) magicFound = true;\n        if (key == \"abcd1234\") keyFound = true;\n        if (keccak256(backup) == keccak256(\"qwerty1234\")) backupFound = true;\n        if (keccak256(abi.encodePacked(extra)) == keccak256(abi.encodePacked(\"112233aabbccdd\"))) {\n            extraStringFound = true;\n        }\n    }\n\n    function isCompromised() public view returns (bool) {\n        return ownerFound && amountFound && magicFound && keyFound && backupFound && extraStringFound;\n    }\n}\n\n/// Try to compromise target contract by finding all accepted values using fixtures.\ncontract InvariantFixtures is Test {\n    Target target;\n    address[] public fixture_owner_ = [address(0x6B175474E89094C44Da98b954EedeAC495271d0F)];\n    uint256[] public fixture_amount = [1, 2, 1122334455];\n\n    function setUp() public {\n        target = new Target();\n    }\n\n    function fixtureMagic() external returns (int32[2] memory) {\n        int32[2] memory magic;\n        magic[0] = -777;\n        magic[1] = 777;\n        return magic;\n    }\n\n    function fixtureKey() external pure returns (bytes32[] memory) {\n        bytes32[] memory keyFixture = new bytes32[](1);\n        keyFixture[0] = \"abcd1234\";\n        return keyFixture;\n    }\n\n    function fixtureBackup() external pure returns (bytes[] memory) {\n        bytes[] memory backupFixture = new bytes[](1);\n        backupFixture[0] = \"qwerty1234\";\n        return backupFixture;\n    }\n\n    function fixtureExtra() external pure returns (string[] memory) {\n        string[] memory extraFixture = new string[](1);\n        extraFixture[0] = \"112233aabbccdd\";\n        return extraFixture;\n    }\n\n    function invariant_target_not_compromised() public {\n        assertEq(target.isCompromised(), false);\n    }\n}\n\"#,\n    );\n\n    assert_invariant(cmd.args([\"test\"])).failure().stdout_eq(str![[r#\"\n...\nRan 1 test for test/InvariantFixtures.t.sol:InvariantFixtures\n[FAIL: assertion failed: true != false]\n\t[SEQUENCE]\n invariant_target_not_compromised() ([RUNS])\n\n[STATS]\n\nSuite result: FAILED. 0 passed; 1 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 0 tests passed, 1 failed, 0 skipped (1 total tests)\n\nFailing tests:\nEncountered 1 failing test in test/InvariantFixtures.t.sol:InvariantFixtures\n[FAIL: assertion failed: true != false]\n\t[SEQUENCE]\n invariant_target_not_compromised() ([RUNS])\n\nEncountered a total of 1 failing tests, 0 tests succeeded\n\nTip: Run `forge test --rerun` to retry only the 1 failed test\n\n[SEED] (use `--fuzz-seed` to reproduce)\n\n\"#]]);\n});\n\nforgetest_init!(invariant_breaks_without_fixtures, |prj, cmd| {\n    prj.update_config(|config| {\n        config.fuzz.seed = Some(U256::from(1));\n        config.invariant.runs = 1;\n        config.invariant.depth = 100;\n    });\n\n    prj.add_test(\n        \"InvariantLiterals.t.sol\",\n        r#\"\nimport \"forge-std/Test.sol\";\n\ncontract Target {\n    bool ownerFound;\n    bool amountFound;\n    bool magicFound;\n    bool keyFound;\n    bool backupFound;\n    bool extraStringFound;\n\n    function fuzzWithoutFixtures(\n        address owner_,\n        uint256 _amount,\n        int32 magic,\n        bytes32 key,\n        bytes memory backup,\n        string memory extra\n    ) external {\n        if (owner_ == address(0x6B175474E89094C44Da98b954EedeAC495271d0F)) {\n            ownerFound = true;\n        }\n        if (_amount == 1122334455) amountFound = true;\n        if (magic == -777) magicFound = true;\n        if (key == \"abcd1234\") keyFound = true;\n        if (keccak256(backup) == keccak256(\"qwerty1234\")) backupFound = true;\n        if (keccak256(abi.encodePacked(extra)) == keccak256(abi.encodePacked(\"112233aabbccdd\"))) {\n            extraStringFound = true;\n        }\n    }\n\n    function isCompromised() public view returns (bool) {\n        return ownerFound && amountFound && magicFound && keyFound && backupFound && extraStringFound;\n    }\n}\n\n/// Try to compromise target contract by finding all accepted values without using fixtures.\ncontract InvariantLiterals is Test {\n    Target target;\n\n    function setUp() public {\n        target = new Target();\n    }\n\n    function invariant_target_not_compromised() public {\n        assertEq(target.isCompromised(), false);\n    }\n}\n\"#,\n    );\n\n    assert_invariant(cmd.args([\"test\"])).failure().stdout_eq(str![[r#\"\n...\nRan 1 test for test/InvariantLiterals.t.sol:InvariantLiterals\n[FAIL: assertion failed: true != false]\n\t[SEQUENCE]\n invariant_target_not_compromised() ([RUNS])\n\n[STATS]\n\nSuite result: FAILED. 0 passed; 1 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 0 tests passed, 1 failed, 0 skipped (1 total tests)\n\nFailing tests:\nEncountered 1 failing test in test/InvariantLiterals.t.sol:InvariantLiterals\n[FAIL: assertion failed: true != false]\n\t[SEQUENCE]\n invariant_target_not_compromised() ([RUNS])\n\nEncountered a total of 1 failing tests, 0 tests succeeded\n\nTip: Run `forge test --rerun` to retry only the 1 failed test\n\n[SEED] (use `--fuzz-seed` to reproduce)\n\n\"#]]);\n});\n\nforgetest!(invariant_handler_failure, |prj, cmd| {\n    prj.insert_utils();\n    prj.update_config(|config| {\n        config.invariant.fail_on_revert = true;\n        config.invariant.runs = 1;\n        config.invariant.depth = 10;\n    });\n\n    prj.add_test(\n        \"InvariantHandlerFailure.t.sol\",\n        r#\"\nimport \"./utils/Test.sol\";\n\nstruct FuzzSelector {\n    address addr;\n    bytes4[] selectors;\n}\n\ncontract Handler is Test {\n    function doSomething() public {\n        require(false, \"failed on revert\");\n    }\n}\n\ncontract InvariantHandlerFailure is Test {\n    bytes4[] internal selectors;\n\n    Handler handler;\n\n    function targetSelectors() public returns (FuzzSelector[] memory) {\n        FuzzSelector[] memory targets = new FuzzSelector[](1);\n        bytes4[] memory selectors = new bytes4[](1);\n        selectors[0] = handler.doSomething.selector;\n        targets[0] = FuzzSelector(address(handler), selectors);\n        return targets;\n    }\n\n    function setUp() public {\n        handler = new Handler();\n    }\n\n    function statefulFuzz_BrokenInvariant() public {}\n}\n\"#,\n    );\n\n    assert_invariant(cmd.args([\"test\"])).failure().stdout_eq(str![[r#\"\n...\nRan 1 test for test/InvariantHandlerFailure.t.sol:InvariantHandlerFailure\n[FAIL: failed on revert]\n\t[SEQUENCE]\n statefulFuzz_BrokenInvariant() ([RUNS])\n\n[STATS]\n\nSuite result: FAILED. 0 passed; 1 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 0 tests passed, 1 failed, 0 skipped (1 total tests)\n\nFailing tests:\nEncountered 1 failing test in test/InvariantHandlerFailure.t.sol:InvariantHandlerFailure\n[FAIL: failed on revert]\n\t[SEQUENCE]\n statefulFuzz_BrokenInvariant() ([RUNS])\n\nEncountered a total of 1 failing tests, 0 tests succeeded\n\nTip: Run `forge test --rerun` to retry only the 1 failed test\n\n[SEED] (use `--fuzz-seed` to reproduce)\n\n\"#]]);\n});\n\n// Here we test that the fuzz engine can include a contract created during the fuzz\n// in its fuzz dictionary and eventually break the invariant.\n// Specifically, can Judas, a created contract from Jesus, break Jesus contract\n// by revealing his identity.\nforgetest_init!(\n    #[cfg_attr(windows, ignore = \"for some reason there's different rng\")]\n    invariant_inner_contract,\n    |prj, cmd| {\n        prj.update_config(|config| {\n            config.invariant.depth = 10;\n        });\n\n        prj.add_test(\n            \"InvariantInnerContract.t.sol\",\n            r#\"\nimport \"forge-std/Test.sol\";\n\ncontract Jesus {\n    address fren;\n    bool public identity_revealed;\n\n    function create_fren() public {\n        fren = address(new Judas());\n    }\n\n    function kiss() public {\n        require(msg.sender == fren);\n        identity_revealed = true;\n    }\n}\n\ncontract Judas {\n    Jesus jesus;\n\n    constructor() {\n        jesus = Jesus(msg.sender);\n    }\n\n    function betray() public {\n        jesus.kiss();\n    }\n}\n\ncontract InvariantInnerContract is Test {\n    Jesus jesus;\n\n    function setUp() public {\n        jesus = new Jesus();\n    }\n\n    function invariantHideJesus() public {\n        require(jesus.identity_revealed() == false, \"jesus betrayed\");\n    }\n}\n\"#,\n        );\n\n        assert_invariant(cmd.args([\"test\"])).failure().stdout_eq(str![[r#\"\n...\nRan 1 test for test/InvariantInnerContract.t.sol:InvariantInnerContract\n[FAIL: jesus betrayed]\n\t[SEQUENCE]\n invariantHideJesus() ([RUNS])\n\n[STATS]\n\nSuite result: FAILED. 0 passed; 1 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 0 tests passed, 1 failed, 0 skipped (1 total tests)\n\nFailing tests:\nEncountered 1 failing test in test/InvariantInnerContract.t.sol:InvariantInnerContract\n[FAIL: jesus betrayed]\n\t[SEQUENCE]\n invariantHideJesus() ([RUNS])\n\nEncountered a total of 1 failing tests, 0 tests succeeded\n\nTip: Run `forge test --rerun` to retry only the 1 failed test\n\n[SEED] (use `--fuzz-seed` to reproduce)\n\n\"#]]);\n\n        // `fuzz_seed` at 119 makes this sequence shrinkable from 4 to 2.\n        prj.update_config(|config| {\n            config.fuzz.seed = Some(U256::from(119u32));\n            // Disable persisted failures for rerunning the test.\n            config.invariant.failure_persist_dir = Some(\n                config\n                    .invariant\n                    .failure_persist_dir\n                    .as_ref()\n                    .unwrap()\n                    .parent()\n                    .unwrap()\n                    .join(\"persistence2\"),\n            );\n        });\n        cmd.assert_failure().stdout_eq(str![[r#\"\nNo files changed, compilation skipped\n\nRan 1 test for test/InvariantInnerContract.t.sol:InvariantInnerContract\n[FAIL: jesus betrayed]\n\t[Sequence] (original: 2, shrunk: 2)\n\t\tsender=[..] addr=[test/InvariantInnerContract.t.sol:Jesus][..] calldata=create_fren() args=[]\n\t\tsender=[..] addr=[test/InvariantInnerContract.t.sol:Judas][..] calldata=betray() args=[]\n invariantHideJesus() (runs: 0, calls: 0, reverts: 1)\n...\n\"#]]);\n    }\n);\n\n// https://github.com/foundry-rs/foundry/issues/7219\nforgetest!(invariant_preserve_state, |prj, cmd| {\n    prj.insert_utils();\n    prj.update_config(|config| {\n        config.invariant.depth = 10;\n        config.invariant.fail_on_revert = true;\n    });\n\n    prj.add_test(\n        \"InvariantPreserveState.t.sol\",\n        r#\"\nimport \"./utils/Test.sol\";\n\nstruct FuzzSelector {\n    address addr;\n    bytes4[] selectors;\n}\n\ncontract Handler is Test {\n    function thisFunctionReverts() external {\n        if (block.number < 10) {} else {\n            revert();\n        }\n    }\n\n    function advanceTime(uint256 blocks) external {\n        blocks = blocks % 10;\n        vm.roll(block.number + blocks);\n        vm.warp(block.timestamp + blocks * 12);\n    }\n}\n\ncontract InvariantPreserveState is Test {\n    Handler handler;\n\n    function setUp() public {\n        handler = new Handler();\n    }\n\n    function targetSelectors() public returns (FuzzSelector[] memory) {\n        FuzzSelector[] memory targets = new FuzzSelector[](1);\n        bytes4[] memory selectors = new bytes4[](2);\n        selectors[0] = handler.thisFunctionReverts.selector;\n        selectors[1] = handler.advanceTime.selector;\n        targets[0] = FuzzSelector(address(handler), selectors);\n        return targets;\n    }\n\n    function invariant_preserve_state() public {\n        assertTrue(true);\n    }\n}\n\"#,\n    );\n\n    assert_invariant(cmd.args([\"test\"])).failure().stdout_eq(str![[r#\"\n...\nRan 1 test for test/InvariantPreserveState.t.sol:InvariantPreserveState\n[FAIL: EvmError: Revert]\n\t[SEQUENCE]\n invariant_preserve_state() ([RUNS])\n\n[STATS]\n\nSuite result: FAILED. 0 passed; 1 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 0 tests passed, 1 failed, 0 skipped (1 total tests)\n\nFailing tests:\nEncountered 1 failing test in test/InvariantPreserveState.t.sol:InvariantPreserveState\n[FAIL: EvmError: Revert]\n\t[SEQUENCE]\n invariant_preserve_state() ([RUNS])\n\nEncountered a total of 1 failing tests, 0 tests succeeded\n\nTip: Run `forge test --rerun` to retry only the 1 failed test\n\n[SEED] (use `--fuzz-seed` to reproduce)\n\n\"#]]);\n});\n\n// add code so contract is accounted as valid sender\n// see https://github.com/foundry-rs/foundry/issues/4245\nforgetest!(invariant_reentrancy, |prj, cmd| {\n    prj.insert_utils();\n    prj.update_config(|config| {\n        config.invariant.depth = 10;\n        config.invariant.fail_on_revert = false;\n        config.invariant.call_override = true;\n    });\n\n    prj.add_test(\n        \"InvariantReentrancy.t.sol\",\n        r#\"\nimport \"./utils/Test.sol\";\n\ncontract Malicious {\n    function world() public {\n        payable(msg.sender).call(\"\");\n    }\n}\n\ncontract Vulnerable {\n    bool public open_door = false;\n    bool public stolen = false;\n    Malicious mal;\n\n    constructor(address _mal) {\n        mal = Malicious(_mal);\n    }\n\n    function hello() public {\n        open_door = true;\n        mal.world();\n        open_door = false;\n    }\n\n    function backdoor() public {\n        require(open_door, \"\");\n        stolen = true;\n    }\n}\n\ncontract InvariantReentrancy is Test {\n    Vulnerable vuln;\n    Malicious mal;\n\n    function setUp() public {\n        mal = new Malicious();\n        vuln = new Vulnerable(address(mal));\n    }\n\n    // do not include `mal` in identified contracts\n    // see https://github.com/foundry-rs/foundry/issues/4245\n    function targetContracts() public view returns (address[] memory) {\n        address[] memory targets = new address[](1);\n        targets[0] = address(vuln);\n        return targets;\n    }\n\n    function invariantNotStolen() public {\n        require(vuln.stolen() == false, \"stolen\");\n    }\n}\n\"#,\n    );\n\n    assert_invariant(cmd.args([\"test\"])).failure().stdout_eq(str![[r#\"\n...\nRan 1 test for test/InvariantReentrancy.t.sol:InvariantReentrancy\n[FAIL: stolen]\n\t[SEQUENCE]\n invariantNotStolen() ([RUNS])\n\n[STATS]\n\nSuite result: FAILED. 0 passed; 1 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 0 tests passed, 1 failed, 0 skipped (1 total tests)\n\nFailing tests:\nEncountered 1 failing test in test/InvariantReentrancy.t.sol:InvariantReentrancy\n[FAIL: stolen]\n\t[SEQUENCE]\n invariantNotStolen() ([RUNS])\n\nEncountered a total of 1 failing tests, 0 tests succeeded\n\nTip: Run `forge test --rerun` to retry only the 1 failed test\n\n[SEED] (use `--fuzz-seed` to reproduce)\n\n\"#]]);\n});\n\n// Tests that call_override detects the classic DAO-style reentrancy vulnerability\n// in EtherStore where balances are updated AFTER the external call.\nforgetest!(invariant_reentrancy_ether_store, |prj, cmd| {\n    prj.insert_utils();\n    prj.update_config(|config| {\n        config.invariant.depth = 15;\n        config.invariant.fail_on_revert = false;\n        config.invariant.call_override = true;\n    });\n\n    prj.add_test(\n        \"InvariantReentrancyEtherStore.t.sol\",\n        r#\"\nimport \"./utils/Test.sol\";\n\nstruct FuzzSelector {\n    address addr;\n    bytes4[] selectors;\n}\n\n// Classic reentrancy-vulnerable contract\ncontract EtherStore {\n    mapping(address => uint256) public balances;\n\n    function deposit() public payable {\n        balances[msg.sender] += msg.value;\n    }\n\n    function withdraw() public {\n        uint256 bal = balances[msg.sender];\n        require(bal > 0);\n        // BUG: External call before state update\n        (bool sent,) = msg.sender.call{value: bal}(\"\");\n        require(sent, \"Failed to send Ether\");\n        balances[msg.sender] = 0;\n    }\n}\n\ncontract InvariantReentrancyEtherStore is Test {\n    EtherStore store;\n    address attacker;\n\n    function setUp() public {\n        store = new EtherStore();\n        attacker = address(0x1337);\n\n        vm.deal(address(this), 10 ether);\n        store.deposit{value: 5 ether}();\n\n        // Attacker gets 2 ether, deposits 1 ether, keeps 1 ether in wallet.\n        // After withdrawing their deposit, attacker wallet balance cannot exceed 2 ether.\n        vm.deal(attacker, 2 ether);\n        vm.prank(attacker);\n        store.deposit{value: 1 ether}();\n    }\n\n    function targetContracts() public view returns (address[] memory) {\n        address[] memory targets = new address[](1);\n        targets[0] = address(store);\n        return targets;\n    }\n\n    function targetSenders() public view returns (address[] memory) {\n        address[] memory senders = new address[](1);\n        senders[0] = attacker;\n        return senders;\n    }\n\n    function targetSelectors() public view returns (FuzzSelector[] memory) {\n        bytes4[] memory selectors = new bytes4[](1);\n        selectors[0] = EtherStore.withdraw.selector;\n        FuzzSelector[] memory targets = new FuzzSelector[](1);\n        targets[0] = FuzzSelector(address(store), selectors);\n        return targets;\n    }\n\n    // Attacker should never have more than 2 ether (1 kept + 1 withdrawn)\n    function invariantSolvency() public view {\n        require(attacker.balance <= 2 ether, \"reentrancy: attacker wallet > 2 ether\");\n    }\n}\n\"#,\n    );\n\n    assert_invariant(cmd.args([\"test\"])).failure().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\n...\nRan 1 test for test/InvariantReentrancyEtherStore.t.sol:InvariantReentrancyEtherStore\n[FAIL: reentrancy: attacker wallet > 2 ether]\n\t[SEQUENCE]\n invariantSolvency() ([RUNS])\n\n[STATS]\n\nSuite result: FAILED. 0 passed; 1 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 0 tests passed, 1 failed, 0 skipped (1 total tests)\n\nFailing tests:\nEncountered 1 failing test in test/InvariantReentrancyEtherStore.t.sol:InvariantReentrancyEtherStore\n[FAIL: reentrancy: attacker wallet > 2 ether]\n\t[SEQUENCE]\n invariantSolvency() ([RUNS])\n\nEncountered a total of 1 failing tests, 0 tests succeeded\n\nTip: Run `forge test --rerun` to retry only the 1 failed test\n\n[SEED] (use `--fuzz-seed` to reproduce)\n\n\"#]]);\n});\n\nforgetest_init!(invariant_roll_fork, |prj, cmd| {\n    prj.add_rpc_endpoints();\n    prj.update_config(|config| {\n        config.fuzz.seed = Some(U256::from(119u32));\n        config.invariant.shrink_run_limit = 0;\n    });\n\n    prj.add_test(\n        \"InvariantRollFork.t.sol\",\n        r#\"\nimport \"forge-std/Test.sol\";\n\ninterface IERC20 {\n    function totalSupply() external view returns (uint256 supply);\n}\n\ncontract RollForkHandler is Test {\n    uint256 public totalSupply;\n\n    function work() external {\n        vm.rollFork(block.number + 1);\n        totalSupply = IERC20(0x6B175474E89094C44Da98b954EedeAC495271d0F).totalSupply();\n    }\n}\n\ncontract InvariantRollForkBlockTest is Test {\n    RollForkHandler forkHandler;\n\n    function setUp() public {\n        vm.createSelectFork(\"mainnet\", 19812632);\n        forkHandler = new RollForkHandler();\n    }\n\n    /// forge-config: default.invariant.runs = 2\n    /// forge-config: default.invariant.depth = 4\n    function invariant_fork_handler_block() public view {\n        require(block.number < 19812634, \"too many blocks mined\");\n    }\n}\n\ncontract InvariantRollForkStateTest is Test {\n    RollForkHandler forkHandler;\n\n    function setUp() public {\n        vm.createSelectFork(\"mainnet\", 19812632);\n        forkHandler = new RollForkHandler();\n    }\n\n    /// forge-config: default.invariant.runs = 1\n    function invariant_fork_handler_state() public view {\n        require(forkHandler.totalSupply() < 3254378807384273078310283461, \"wrong supply\");\n    }\n}\n\"#,\n    );\n\n    assert_invariant(cmd.args([\"test\", \"-j1\"])).failure().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\nRan 1 test for test/InvariantRollFork.t.sol:InvariantRollForkBlockTest\n[FAIL: too many blocks mined]\n\t[SEQUENCE]\n invariant_fork_handler_block() ([RUNS])\n\n[STATS]\n\nSuite result: FAILED. 0 passed; 1 failed; 0 skipped; [ELAPSED]\n\nRan 1 test for test/InvariantRollFork.t.sol:InvariantRollForkStateTest\n[FAIL: wrong supply]\n\t[SEQUENCE]\n invariant_fork_handler_state() ([RUNS])\n\n[STATS]\n\nSuite result: FAILED. 0 passed; 1 failed; 0 skipped; [ELAPSED]\n\nRan 2 test suites [ELAPSED]: 0 tests passed, 2 failed, 0 skipped (2 total tests)\n\nFailing tests:\nEncountered 1 failing test in test/InvariantRollFork.t.sol:InvariantRollForkBlockTest\n[FAIL: too many blocks mined]\n\t[SEQUENCE]\n invariant_fork_handler_block() ([RUNS])\n\nEncountered 1 failing test in test/InvariantRollFork.t.sol:InvariantRollForkStateTest\n[FAIL: wrong supply]\n\t[SEQUENCE]\n invariant_fork_handler_state() ([RUNS])\n\nEncountered a total of 2 failing tests, 0 tests succeeded\n\nTip: Run `forge test --rerun` to retry only the 2 failed tests\n\n[SEED] (use `--fuzz-seed` to reproduce)\n\n\"#]]);\n});\n\nforgetest_init!(invariant_scrape_values, |prj, cmd| {\n    prj.update_config(|config| {\n        config.invariant.depth = 10;\n        config.fuzz.seed = Some(U256::from(100u32));\n    });\n\n    prj.add_test(\n        \"InvariantScrapeValues.t.sol\",\n        r#\"\nimport \"forge-std/Test.sol\";\n\ncontract FindFromReturnValue {\n    bool public found = false;\n\n    function seed() public returns (int256) {\n        int256 mystery = 13337;\n        return (1337 + mystery);\n    }\n\n    function find(int256 i) public {\n        int256 mystery = 13337;\n        if (i == 1337 + mystery) {\n            found = true;\n        }\n    }\n}\n\ncontract FindFromReturnValueTest is Test {\n    FindFromReturnValue target;\n\n    function setUp() public {\n        target = new FindFromReturnValue();\n    }\n\n    /// forge-config: default.invariant.runs = 50\n    /// forge-config: default.invariant.depth = 300\n    /// forge-config: default.invariant.fail-on-revert = true\n    function invariant_value_not_found() public view {\n        require(!target.found(), \"value from return found\");\n    }\n}\n\ncontract FindFromLogValue {\n    event FindFromLog(int256 indexed mystery, bytes32 rand);\n\n    bool public found = false;\n\n    function seed() public {\n        int256 mystery = 13337;\n        emit FindFromLog(1337 + mystery, keccak256(abi.encodePacked(\"mystery\")));\n    }\n\n    function find(int256 i) public {\n        int256 mystery = 13337;\n        if (i == 1337 + mystery) {\n            found = true;\n        }\n    }\n}\n\ncontract FindFromLogValueTest is Test {\n    FindFromLogValue target;\n\n    function setUp() public {\n        target = new FindFromLogValue();\n    }\n\n    /// forge-config: default.invariant.runs = 50\n    /// forge-config: default.invariant.depth = 300\n    /// forge-config: default.invariant.fail-on-revert = true\n    function invariant_value_not_found() public view {\n        require(!target.found(), \"value from logs found\");\n    }\n}\n\"#,\n    );\n\n    assert_invariant(cmd.args([\"test\", \"-j1\"])).failure().stdout_eq(str![[r#\"\n...\nRan 2 test suites [ELAPSED]: 0 tests passed, 2 failed, 0 skipped (2 total tests)\n\nFailing tests:\nEncountered 1 failing test in test/InvariantScrapeValues.t.sol:FindFromLogValueTest\n[FAIL: value from logs found]\n\t[SEQUENCE]\n invariant_value_not_found() ([RUNS])\n\nEncountered 1 failing test in test/InvariantScrapeValues.t.sol:FindFromReturnValueTest\n[FAIL: value from return found]\n\t[SEQUENCE]\n invariant_value_not_found() ([RUNS])\n\nEncountered a total of 2 failing tests, 0 tests succeeded\n\nTip: Run `forge test --rerun` to retry only the 2 failed tests\n\n[SEED] (use `--fuzz-seed` to reproduce)\n\n\"#]]);\n});\n\nforgetest_init!(invariant_sequence_no_reverts, |prj, cmd| {\n    prj.update_config(|config| {\n        config.invariant.depth = 15;\n        config.invariant.fail_on_revert = false;\n        // Use original counterexample to test sequence len.\n        config.invariant.shrink_run_limit = 0;\n    });\n\n    prj.add_test(\n        \"InvariantSequenceNoReverts.t.sol\",\n        r#\"\nimport \"forge-std/Test.sol\";\n\ncontract SequenceNoReverts {\n    uint256 public count;\n\n    function work(uint256 x) public {\n        require(x % 2 != 0);\n        count++;\n    }\n}\n\ncontract SequenceNoRevertsTest is Test {\n    SequenceNoReverts target;\n\n    function setUp() public {\n        target = new SequenceNoReverts();\n    }\n\n    function invariant_no_reverts() public view {\n        require(target.count() < 10, \"condition met\");\n    }\n}\n\"#,\n    );\n\n    // ensure original counterexample len is 10 (even without shrinking)\n    cmd.args([\"test\"]).assert_failure().stdout_eq(str![[r#\"\n...\nRan 1 test for test/InvariantSequenceNoReverts.t.sol:SequenceNoRevertsTest\n[FAIL: condition met]\n\t[Sequence] (original: 10, shrunk: 10)\n...\n invariant_no_reverts() ([..])\n...\nSuite result: FAILED. 0 passed; 1 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 0 tests passed, 1 failed, 0 skipped (1 total tests)\n...\n\"#]]);\n});\n\nforgetest_init!(\n    #[cfg_attr(windows, ignore = \"for some reason there's different rng\")]\n    invariant_shrink_big_sequence,\n    |prj, cmd| {\n        prj.update_config(|config| {\n            config.fuzz.seed = Some(U256::from(119u32));\n            config.invariant.runs = 1;\n            config.invariant.depth = 1000;\n            config.invariant.shrink_run_limit = 425;\n        });\n\n        prj.add_test(\n            \"InvariantShrinkBigSequence.t.sol\",\n            r#\"\nimport \"forge-std/Test.sol\";\n\ncontract ShrinkBigSequence {\n    uint256 cond;\n\n    function work(uint256 x) public {\n        if (x % 2 != 0 && x < 9000) {\n            cond++;\n        }\n    }\n\n    function checkCond() public view {\n        require(cond < 77, \"condition met\");\n    }\n}\n\ncontract ShrinkBigSequenceTest is Test {\n    ShrinkBigSequence target;\n\n    function setUp() public {\n        target = new ShrinkBigSequence();\n    }\n\n    function invariant_shrink_big_sequence() public view {\n        target.checkCond();\n    }\n}\n\"#,\n        );\n\n        // ensure shrinks to same sequence of 77\n        cmd.args([\"test\"]).assert_failure().stdout_eq(str![[r#\"\n...\nRan 1 test for test/InvariantShrinkBigSequence.t.sol:ShrinkBigSequenceTest\n[FAIL: condition met]\n\t[Sequence] (original: [..], shrunk: 77)\n...\n\"#]]);\n        cmd.assert_failure().stdout_eq(str![[r#\"\n...\nRan 1 test for test/InvariantShrinkBigSequence.t.sol:ShrinkBigSequenceTest\n[FAIL: invariant_shrink_big_sequence replay failure]\n\t[Sequence] (original: [..], shrunk: 77)\n...\n\"#]]);\n    }\n);\n\nforgetest_init!(invariant_shrink_fail_on_revert, |prj, cmd| {\n    prj.update_config(|config| {\n        config.fuzz.seed = Some(U256::from(119u32));\n        config.invariant.fail_on_revert = true;\n        config.invariant.runs = 1;\n        config.invariant.depth = 200;\n    });\n\n    prj.add_test(\n        \"InvariantShrinkFailOnRevert.t.sol\",\n        r#\"\nimport \"forge-std/Test.sol\";\n\ncontract ShrinkFailOnRevert {\n    uint256 cond;\n\n    function work(uint256 x) public {\n        if (x % 2 != 0 && x < 9000) {\n            cond++;\n        }\n        require(cond < 10, \"condition met\");\n    }\n}\n\ncontract ShrinkFailOnRevertTest is Test {\n    ShrinkFailOnRevert target;\n\n    function setUp() public {\n        target = new ShrinkFailOnRevert();\n    }\n\n    function invariant_shrink_fail_on_revert() public view {}\n}\n\"#,\n    );\n\n    cmd.args([\"test\"]).assert_failure().stdout_eq(str![[r#\"\n...\nRan 1 test for test/InvariantShrinkFailOnRevert.t.sol:ShrinkFailOnRevertTest\n[FAIL: condition met]\n\t[Sequence] (original: [..], shrunk: 10)\n...\n\"#]]);\n});\n\nforgetest_init!(invariant_shrink_with_assert, |prj, cmd| {\n    prj.update_config(|config| {\n        config.fuzz.seed = Some(U256::from(100u32));\n        config.invariant.runs = 1;\n        config.invariant.depth = 15;\n    });\n\n    prj.add_test(\n        \"InvariantShrinkWithAssert.t.sol\",\n        r#\"\nimport \"forge-std/Test.sol\";\n\ncontract Counter {\n    uint256 public number;\n\n    function increment() public {\n        number++;\n    }\n\n    function decrement() public {\n        number--;\n    }\n}\n\ncontract InvariantShrinkWithAssert is Test {\n    Counter public counter;\n\n    function setUp() public {\n        counter = new Counter();\n    }\n\n    function invariant_with_assert() public {\n        assertTrue(counter.number() < 2, \"wrong counter assert\");\n    }\n\n    function invariant_with_require() public {\n        require(counter.number() < 2, \"wrong counter require\");\n    }\n}\n\"#,\n    );\n\n    cmd.args([\"test\"]).assert_failure().stdout_eq(str![[r#\"\n...\nRan 2 tests for test/InvariantShrinkWithAssert.t.sol:InvariantShrinkWithAssert\n[FAIL: wrong counter assert]\n\t[Sequence] (original: 2, shrunk: 2)\n...\n invariant_with_assert() ([..])\n...\n[FAIL: wrong counter require]\n\t[Sequence] (original: 2, shrunk: 2)\n...\n invariant_with_require() ([..])\n...\n\"#]]);\n});\n\nforgetest_init!(invariant_test1, |prj, cmd| {\n    prj.update_config(|config| {\n        config.invariant.depth = 10;\n    });\n\n    prj.add_test(\n        \"InvariantTest1.t.sol\",\n        r#\"\nimport \"forge-std/Test.sol\";\n\ncontract InvariantBreaker {\n    bool public flag0 = true;\n    bool public flag1 = true;\n\n    function set0(int256 val) public returns (bool) {\n        if (val % 100 == 0) {\n            flag0 = false;\n        }\n        return flag0;\n    }\n\n    function set1(int256 val) public returns (bool) {\n        if (val % 10 == 0 && !flag0) {\n            flag1 = false;\n        }\n        return flag1;\n    }\n}\n\ncontract InvariantTest is Test {\n    InvariantBreaker inv;\n\n    function setUp() public {\n        inv = new InvariantBreaker();\n    }\n\n    function invariant_neverFalse() public {\n        require(inv.flag1(), \"false\");\n    }\n\n    function statefulFuzz_neverFalseWithInvariantAlias() public {\n        require(inv.flag1(), \"false\");\n    }\n}\n\"#,\n    );\n\n    assert_invariant(cmd.args([\"test\"])).failure().stdout_eq(str![[r#\"\n...\nRan 2 tests for test/InvariantTest1.t.sol:InvariantTest\n[FAIL: false]\n\t[SEQUENCE]\n invariant_neverFalse() ([RUNS])\n\n[STATS]\n\n[FAIL: false]\n\t[SEQUENCE]\n statefulFuzz_neverFalseWithInvariantAlias() ([RUNS])\n\n[STATS]\n\nSuite result: FAILED. 0 passed; 2 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 0 tests passed, 2 failed, 0 skipped (2 total tests)\n\nFailing tests:\nEncountered 2 failing tests in test/InvariantTest1.t.sol:InvariantTest\n[FAIL: false]\n\t[SEQUENCE]\n invariant_neverFalse() ([RUNS])\n[FAIL: false]\n\t[SEQUENCE]\n statefulFuzz_neverFalseWithInvariantAlias() ([RUNS])\n\nEncountered a total of 2 failing tests, 0 tests succeeded\n\nTip: Run `forge test --rerun` to retry only the 2 failed tests\n\n[SEED] (use `--fuzz-seed` to reproduce)\n\n\"#]]);\n});\n\nforgetest_init!(invariant_warp_and_roll, |prj, cmd| {\n    prj.update_config(|config| {\n        config.fuzz.seed = Some(U256::from(119u32));\n        config.invariant.max_time_delay = Some(604800);\n        config.invariant.max_block_delay = Some(60480);\n        config.invariant.shrink_run_limit = 0;\n    });\n\n    prj.add_test(\n        \"InvariantWarpAndRoll.t.sol\",\n        r#\"\nimport \"forge-std/Test.sol\";\n\ncontract Counter {\n    uint256 public number;\n\n    function setNumber(uint256 newNumber) public {\n        number = newNumber;\n    }\n\n    function increment() public {\n        number++;\n    }\n}\n\ncontract InvariantWarpAndRoll {\n    Counter public counter;\n\n    function setUp() public {\n        counter = new Counter();\n    }\n\n    function invariant_warp() public view {\n        require(block.number < 200000, \"max block\");\n    }\n\n    /// forge-config: default.invariant.show_solidity = true\n    function invariant_roll() public view {\n        require(block.timestamp < 500000, \"max timestamp\");\n    }\n}\n\"#,\n    );\n\n    cmd.args([\"test\", \"--mt\", \"invariant_warp\"]).assert_failure().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\nRan 1 test for test/InvariantWarpAndRoll.t.sol:InvariantWarpAndRoll\n[FAIL: max block]\n\t[Sequence] (original: 6, shrunk: 6)\n\t\tsender=[..] addr=[test/InvariantWarpAndRoll.t.sol:Counter]0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f warp=6280 roll=21461 calldata=setNumber(uint256) args=[200000 [2e5]]\n\t\tsender=[..] addr=[test/InvariantWarpAndRoll.t.sol:Counter]0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f warp=92060 roll=51816 calldata=setNumber(uint256) args=[0]\n\t\tsender=[..] addr=[test/InvariantWarpAndRoll.t.sol:Counter]0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f warp=198040 roll=60259 calldata=increment() args=[]\n\t\tsender=[..] addr=[test/InvariantWarpAndRoll.t.sol:Counter]0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f warp=20609 roll=27086 calldata=setNumber(uint256) args=[26717227324157985679793128079000084308648530834088529513797156275625002 [2.671e70]]\n\t\tsender=[..] addr=[test/InvariantWarpAndRoll.t.sol:Counter]0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f warp=409368 roll=24864 calldata=increment() args=[]\n\t\tsender=[..] addr=[test/InvariantWarpAndRoll.t.sol:Counter]0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f warp=218105 roll=17834 calldata=setNumber(uint256) args=[24752675372815722001736610830 [2.475e28]]\n invariant_warp() (runs: 0, calls: 0, reverts: 0)\n...\n\n\"#]]);\n\n    cmd.forge_fuse().args([\"test\", \"--mt\", \"invariant_roll\"]).assert_failure().stdout_eq(str![[r#\"\nNo files changed, compilation skipped\n\nRan 1 test for test/InvariantWarpAndRoll.t.sol:InvariantWarpAndRoll\n[FAIL: max timestamp]\n\t[Sequence] (original: 5, shrunk: 5)\n\t\tvm.warp(block.timestamp + 6280);\n\t\tvm.roll(block.number + 21461);\n\t\tvm.prank([..]);\n\t\tCounter(0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f).setNumber(200000);\n\t\tvm.warp(block.timestamp + 92060);\n\t\tvm.roll(block.number + 51816);\n\t\tvm.prank([..]);\n\t\tCounter(0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f).setNumber(0);\n\t\tvm.warp(block.timestamp + 198040);\n\t\tvm.roll(block.number + 60259);\n\t\tvm.prank([..]);\n\t\tCounter(0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f).increment();\n\t\tvm.warp(block.timestamp + 20609);\n\t\tvm.roll(block.number + 27086);\n\t\tvm.prank([..]);\n\t\tCounter(0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f).setNumber(26717227324157985679793128079000084308648530834088529513797156275625002);\n\t\tvm.warp(block.timestamp + 409368);\n\t\tvm.roll(block.number + 24864);\n\t\tvm.prank([..]);\n\t\tCounter(0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f).increment();\n invariant_roll() (runs: 0, calls: 0, reverts: 0)\n...\n\n\"#]]);\n\n    // Test that time and block advance in target contract as well.\n    prj.update_config(|config| {\n        config.invariant.fail_on_revert = true;\n    });\n    prj.add_test(\n        \"HandlerWarpAndRoll.t.sol\",\n        r#\"\nimport \"forge-std/Test.sol\";\n\ncontract Counter {\n    uint256 public number;\n    function setNumber(uint256 newNumber) public {\n        require(block.number < 200000, \"max block\");\n        number = newNumber;\n    }\n\n    function increment() public {\n        require(block.timestamp < 500000, \"max timestamp\");\n        number++;\n    }\n}\n\ncontract HandlerWarpAndRoll {\n    Counter public counter;\n\n    function setUp() public {\n        counter = new Counter();\n    }\n\n    function invariant_handler() public view {\n    }\n}\n\"#,\n    );\n\n    cmd.forge_fuse().args([\"test\", \"--mt\", \"invariant_handler\"]).assert_failure().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\nRan 1 test for test/HandlerWarpAndRoll.t.sol:HandlerWarpAndRoll\n[FAIL: max timestamp]\n\t[Sequence] (original: 5, shrunk: 5)\n\t\tsender=[..] addr=[test/HandlerWarpAndRoll.t.sol:Counter]0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f warp=6280 roll=21461 calldata=setNumber(uint256) args=[200000 [2e5]]\n\t\tsender=[..] addr=[test/HandlerWarpAndRoll.t.sol:Counter]0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f warp=92060 roll=51816 calldata=setNumber(uint256) args=[0]\n\t\tsender=[..] addr=[test/HandlerWarpAndRoll.t.sol:Counter]0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f warp=198040 roll=60259 calldata=increment() args=[]\n\t\tsender=[..] addr=[test/HandlerWarpAndRoll.t.sol:Counter]0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f warp=20609 roll=27086 calldata=setNumber(uint256) args=[26717227324157985679793128079000084308648530834088529513797156275625002 [2.671e70]]\n\t\tsender=[..] addr=[test/HandlerWarpAndRoll.t.sol:Counter]0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f warp=409368 roll=24864 calldata=increment() args=[]\n invariant_handler() (runs: 0, calls: 0, reverts: 1)\n\n...\n\n\"#]]);\n});\n\n// Test that state is preserved across calls during invariant replay.\n// Regression test for commit 0584a581b which changed replay_run to use execute_tx\n// (which uses call_raw) instead of transact_raw, but forgot to add the commit() call.\nforgetest_init!(invariant_replay_state_preserved, |prj, cmd| {\n    prj.update_config(|config| {\n        config.invariant.runs = 1;\n        config.invariant.depth = 5;\n    });\n\n    prj.add_test(\n        \"InvariantReplayState.t.sol\",\n        r#\"\nimport \"forge-std/Test.sol\";\n\ncontract Handler is Test {\n    uint256 public counter;\n\n    function increment(uint256 amount) public {\n        uint256 before = counter;\n        counter += 1;\n        console.log(\"before:\", before, \"after:\", counter);\n    }\n}\n\ncontract InvariantReplayStateTest is Test {\n    Handler handler;\n\n    function setUp() public {\n        handler = new Handler();\n        targetContract(address(handler));\n    }\n\n    function invariant_counter_increases() public view {\n        assertTrue(true);\n    }\n}\n\"#,\n    );\n\n    // With -vvv we see logs from replay. The \"before\" value of each call should\n    // match the \"after\" value from the previous call, proving state persists.\n    cmd.args([\"test\", \"-vvv\"]).assert_success().stdout_eq(str![[r#\"\n...\n[PASS] invariant_counter_increases() (runs: 1, calls: 5, reverts: 0)\n...\nLogs:\n  before: 0 after: 1\n  before: 1 after: 2\n  before: 2 after: 3\n  before: 3 after: 4\n  before: 4 after: 5\n...\n\"#]]);\n});\n\n// Test optimization mode for invariant testing.\n// When an invariant function returns int256, it becomes an optimization target.\n// The fuzzer maximizes the return value instead of checking for failures.\nforgetest!(invariant_optimization_mode, |prj, cmd| {\n    prj.insert_vm();\n    prj.insert_ds_test();\n\n    prj.add_test(\n        \"InvariantOptimize.t.sol\",\n        r#\"\nimport { DSTest as Test } from \"src/test.sol\";\n\nstruct FuzzSelector {\n    address addr;\n    bytes4[] selectors;\n}\n\ncontract OptimizationHandler {\n    int256 public value;\n\n    // Each call adds exactly 10 to value\n    function increment() external {\n        value += 10;\n    }\n}\n\ncontract InvariantOptimizeTest is Test {\n    OptimizationHandler handler;\n\n    function setUp() public {\n        handler = new OptimizationHandler();\n    }\n\n    function targetSelectors() public returns (FuzzSelector[] memory) {\n        FuzzSelector[] memory targets = new FuzzSelector[](1);\n        bytes4[] memory selectors = new bytes4[](1);\n        selectors[0] = handler.increment.selector;\n        targets[0] = FuzzSelector(address(handler), selectors);\n        return targets;\n    }\n\n    /// forge-config: default.invariant.runs = 1\n    /// forge-config: default.invariant.depth = 5\n    /// @notice Optimization mode: returns int256 to maximize.\n    /// With depth=5 and only increment(), max value should be 50.\n    function invariant_optimize_value() public view returns (int256) {\n        return handler.value();\n    }\n}\n\"#,\n    );\n\n    // Optimization mode: best value shown first, should reach 50 (5 calls * 10 each)\n    // Shows [Best sequence] with calls in output\n    cmd.args([\"test\", \"-vvv\"]).assert_success().stdout_eq(str![[r#\"\n...\n[PASS]\n\t[Best sequence] [..]\n[..]calldata=increment()[..]\n[..]calldata=increment()[..]\n[..]calldata=increment()[..]\n[..]calldata=increment()[..]\n[..]calldata=increment()[..]\n invariant_optimize_value() (best: 50, runs: 1, calls: 5)\n...\n\"#]]);\n});\n\n// Test that optimization mode works with negative values (finding max of negative range).\nforgetest!(invariant_optimization_negative_values, |prj, cmd| {\n    prj.insert_vm();\n    prj.insert_ds_test();\n\n    prj.add_test(\n        \"InvariantOptimizeNegative.t.sol\",\n        r#\"\nimport { DSTest as Test } from \"src/test.sol\";\n\nstruct FuzzSelector {\n    address addr;\n    bytes4[] selectors;\n}\n\ncontract NegativeHandler {\n    int256 public value = -100;\n\n    // Each call adds exactly 25 to value\n    function increase() external {\n        value += 25;\n    }\n}\n\ncontract InvariantOptimizeNegativeTest is Test {\n    NegativeHandler handler;\n\n    function setUp() public {\n        handler = new NegativeHandler();\n    }\n\n    function targetSelectors() public returns (FuzzSelector[] memory) {\n        FuzzSelector[] memory targets = new FuzzSelector[](1);\n        bytes4[] memory selectors = new bytes4[](1);\n        selectors[0] = handler.increase.selector;\n        targets[0] = FuzzSelector(address(handler), selectors);\n        return targets;\n    }\n\n    /// forge-config: default.invariant.runs = 1\n    /// forge-config: default.invariant.depth = 4\n    /// Starting at -100, 4 calls of +25 each = -100 + 100 = 0\n    function invariant_optimize_negative() public view returns (int256) {\n        return handler.value();\n    }\n}\n\"#,\n    );\n\n    // Optimization should reach 0: starting at -100, 4 calls * +25 = 0\n    // Shows [Best sequence] with calls in output\n    cmd.args([\"test\", \"-vvv\"]).assert_success().stdout_eq(str![[r#\"\n...\n[PASS]\n\t[Best sequence] [..]\n[..]calldata=increase()[..]\n[..]calldata=increase()[..]\n[..]calldata=increase()[..]\n[..]calldata=increase()[..]\n invariant_optimize_negative() (best: 0, runs: 1, calls: 4)\n...\n\"#]]);\n});\n\n// Test optimization mode with time-dependent logic using warp and fixed seed for reproducibility.\n// This test ensures warp values are correctly accumulated during shrinking.\nforgetest_init!(invariant_optimization_with_warp, |prj, cmd| {\n    prj.add_test(\n        \"InvariantOptimizeWarp.t.sol\",\n        r#\"\nimport {Test} from \"forge-std/Test.sol\";\n\ncontract InvariantOptimizeWarpTest is Test {\n    int256 public maxValue;\n\n    function setUp() public {\n        targetContract(address(this));\n    }\n\n    // Simulates time-dependent pricing with warp. Higher timestamp = higher value.\n    function updateValue(uint256 multiplier) public {\n        if (multiplier == 0 || multiplier > 100) revert();\n        // Value depends on block.timestamp which can be warped\n        int256 newValue = int256(block.timestamp * multiplier / 1000);\n        if (newValue > maxValue) {\n            maxValue = newValue;\n        }\n    }\n\n    /// forge-config: default.invariant.runs = 10\n    /// forge-config: default.invariant.depth = 15\n    /// forge-config: default.invariant.max_time_delay = 604800\n    function invariant_optimize_max_value() public view returns (int256) {\n        return maxValue;\n    }\n}\n\"#,\n    );\n\n    // Use fixed seed for deterministic output. The optimizer finds sequences that\n    // maximize value through time manipulation (warp). Shrinking reduces to 1 call.\n    cmd.args([\"test\", \"-vvv\", \"--fuzz-seed\", \"12345\"]).assert_success().stdout_eq(str![[r#\"\n...\n[PASS]\n\t[Best sequence] (original: 9, shrunk: 1)\n\t\tsender=0x0000000000000000000000000000000000000637 addr=[test/InvariantOptimizeWarp.t.sol:InvariantOptimizeWarpTest]0x7FA9385bE102ac3EAc297483Dd6233D62b3e1496 warp=3249628 calldata=updateValue(uint256) args=[100]\n invariant_optimize_max_value() (best: 324962, runs: 10, calls: 150)\n...\n\"#]]);\n});\n"
  },
  {
    "path": "crates/forge/tests/cli/test_cmd/invariant/mod.rs",
    "content": "use alloy_primitives::U256;\nuse foundry_test_utils::{TestCommand, forgetest_init, snapbox::cmd::OutputAssert, str};\n\nmod common;\nmod storage;\nmod target;\n\nfn assert_invariant(cmd: &mut TestCommand) -> OutputAssert {\n    cmd.assert_with(&[\n        (\"[RUNS]\", r\"runs: \\d+, calls: \\d+, reverts: \\d+\"),\n        (\"[SEQUENCE]\", r\"\\[Sequence\\].*(\\n\\t\\t.*)*\"),\n        (\"[STATS]\", r\"╭[\\s\\S]*?╰.*\"),\n    ])\n}\n\n// Tests that a persisted failure doesn't fail due to assume revert if test driver is changed.\nforgetest_init!(should_not_fail_replay_assume, |prj, cmd| {\n    prj.update_config(|config| {\n        config.invariant.fail_on_revert = true;\n        config.invariant.max_assume_rejects = 10;\n    });\n\n    // Add initial test that breaks invariant.\n    prj.add_test(\n        \"AssumeTest.t.sol\",\n        r#\"\nimport {Test} from \"forge-std/Test.sol\";\n\ncontract AssumeHandler is Test {\n    function fuzzMe(uint256 a) public {\n        require(false, \"Invariant failure\");\n    }\n}\n\ncontract AssumeTest is Test {\n    function setUp() public {\n        AssumeHandler handler = new AssumeHandler();\n    }\n    function invariant_assume() public {}\n}\n     \"#,\n    );\n\n    cmd.args([\"test\", \"--mt\", \"invariant_assume\"]).assert_failure().stdout_eq(str![[r#\"\n...\n[FAIL: Invariant failure]\n...\n\"#]]);\n\n    // Change test to use assume instead require. Same test should fail with too many inputs\n    // rejected message instead persisted failure revert.\n    prj.add_test(\n        \"AssumeTest.t.sol\",\n        r#\"\nimport {Test} from \"forge-std/Test.sol\";\n\ncontract AssumeHandler is Test {\n    function fuzzMe(uint256 a) public {\n        vm.assume(false);\n    }\n}\n\ncontract AssumeTest is Test {\n    function setUp() public {\n        AssumeHandler handler = new AssumeHandler();\n    }\n    function invariant_assume() public {}\n}\n     \"#,\n    );\n\n    cmd.assert_failure().stdout_eq(str![[r#\"\n...\n[FAIL: `vm.assume` rejected too many inputs (10 allowed)] invariant_assume() (runs: 0, calls: 0, reverts: 0)\n...\n\"#]]);\n});\n\n// Test too many inputs rejected for `assumePrecompile`/`assumeForgeAddress`.\n// <https://github.com/foundry-rs/foundry/issues/9054>\nforgetest_init!(should_revert_with_assume_code, |prj, cmd| {\n    prj.update_config(|config| {\n        config.invariant.fail_on_revert = true;\n        config.invariant.max_assume_rejects = 10;\n        config.fuzz.seed = Some(U256::from(100u32));\n    });\n\n    // Add initial test that breaks invariant.\n    prj.add_test(\n        \"AssumeTest.t.sol\",\n        r#\"\nimport {Test} from \"forge-std/Test.sol\";\n\ncontract BalanceTestHandler is Test {\n    address public ref = address(1412323);\n    address alice;\n\n    constructor(address _alice) {\n        alice = _alice;\n    }\n\n    function increment(uint256 amount_, address addr) public {\n        assumeNotPrecompile(addr);\n        assumeNotForgeAddress(addr);\n        assertEq(alice.balance, 100_000 ether);\n    }\n}\n\ncontract BalanceAssumeTest is Test {\n    function setUp() public {\n        address alice = makeAddr(\"alice\");\n        vm.deal(alice, 100_000 ether);\n        targetSender(alice);\n        BalanceTestHandler handler = new BalanceTestHandler(alice);\n        targetContract(address(handler));\n    }\n\n    function invariant_balance() public {}\n}\n     \"#,\n    );\n\n    cmd.args([\"test\", \"--mt\", \"invariant_balance\"]).assert_failure().stdout_eq(str![[r#\"\n...\n[FAIL: `vm.assume` rejected too many inputs (10 allowed)] invariant_balance() (runs: 2, calls: 1000, reverts: 0)\n...\n\"#]]);\n});\n\n// Test proper message displayed if `targetSelector`/`excludeSelector` called with empty selectors.\n// <https://github.com/foundry-rs/foundry/issues/9066>\nforgetest_init!(should_not_panic_if_no_selectors, |prj, cmd| {\n    prj.add_test(\n        \"NoSelectorTest.t.sol\",\n        r#\"\nimport {Test} from \"forge-std/Test.sol\";\n\ncontract TestHandler is Test {}\n\ncontract NoSelectorTest is Test {\n    bytes4[] selectors;\n\n    function setUp() public {\n        TestHandler handler = new TestHandler();\n        targetSelector(FuzzSelector({addr: address(handler), selectors: selectors}));\n        excludeSelector(FuzzSelector({addr: address(handler), selectors: selectors}));\n    }\n\n    function invariant_panic() public {}\n}\n     \"#,\n    );\n\n    cmd.args([\"test\", \"--mt\", \"invariant_panic\"]).assert_failure().stdout_eq(str![[r#\"\n...\n[FAIL: failed to set up invariant testing environment: No contracts to fuzz.] invariant_panic() (runs: 0, calls: 0, reverts: 0)\n...\n\"#]]);\n});\n\n// <https://github.com/foundry-rs/foundry/issues/3607>\nforgetest_init!(should_show_invariant_metrics, |prj, cmd| {\n    prj.add_test(\n        \"SelectorMetricsTest.t.sol\",\n        r#\"\nimport {Test} from \"forge-std/Test.sol\";\n\ncontract CounterTest is Test {\n    function setUp() public {\n        CounterHandler handler = new CounterHandler();\n        AnotherCounterHandler handler1 = new AnotherCounterHandler();\n        // targetContract(address(handler1));\n    }\n\n    /// forge-config: default.invariant.runs = 10\n    /// forge-config: default.invariant.show-metrics = true\n    function invariant_counter() public {}\n\n    /// forge-config: default.invariant.runs = 10\n    /// forge-config: default.invariant.show-metrics = true\n    function invariant_counter2() public {}\n}\n\ncontract CounterHandler is Test {\n    function doSomething(uint256 a) public {\n        vm.assume(a < 10_000_000);\n        require(a < 100_000);\n    }\n\n    function doAnotherThing(uint256 a) public {\n        vm.assume(a < 10_000_000);\n        require(a < 100_000);\n    }\n}\n\ncontract AnotherCounterHandler is Test {\n    function doWork(uint256 a) public {\n        vm.assume(a < 10_000_000);\n        require(a < 100_000);\n    }\n\n    function doWorkThing(uint256 a) public {\n        vm.assume(a < 10_000_000);\n        require(a < 100_000);\n    }\n}\n     \"#,\n    );\n\n    cmd.args([\"test\", \"--mt\", \"invariant_\"]).assert_success().stdout_eq(str![[r#\"\n...\n[PASS] invariant_counter() (runs: 10, calls: 5000, reverts: [..])\n\n╭-----------------------+----------------+-------+---------+----------╮\n| Contract              | Selector       | Calls | Reverts | Discards |\n+=====================================================================+\n| AnotherCounterHandler | doWork         | [..]  | [..]    | [..]     |\n|-----------------------+----------------+-------+---------+----------|\n| AnotherCounterHandler | doWorkThing    | [..]  | [..]    | [..]     |\n|-----------------------+----------------+-------+---------+----------|\n| CounterHandler        | doAnotherThing | [..]  | [..]    | [..]     |\n|-----------------------+----------------+-------+---------+----------|\n| CounterHandler        | doSomething    | [..]  | [..]    | [..]     |\n╰-----------------------+----------------+-------+---------+----------╯\n\n[PASS] invariant_counter2() (runs: 10, calls: 5000, reverts: [..])\n\n╭-----------------------+----------------+-------+---------+----------╮\n| Contract              | Selector       | Calls | Reverts | Discards |\n+=====================================================================+\n| AnotherCounterHandler | doWork         | [..]  | [..]    | [..]     |\n|-----------------------+----------------+-------+---------+----------|\n| AnotherCounterHandler | doWorkThing    | [..]  | [..]    | [..]     |\n|-----------------------+----------------+-------+---------+----------|\n| CounterHandler        | doAnotherThing | [..]  | [..]    | [..]     |\n|-----------------------+----------------+-------+---------+----------|\n| CounterHandler        | doSomething    | [..]  | [..]    | [..]     |\n╰-----------------------+----------------+-------+---------+----------╯\n\nSuite result: ok. 2 passed; 0 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 2 tests passed, 0 failed, 0 skipped (2 total tests)\n\n\"#]]);\n});\n\n// Tests that invariant exists with success after configured timeout.\nforgetest_init!(should_apply_configured_timeout, |prj, cmd| {\n    // Add initial test that breaks invariant.\n    prj.add_test(\n        \"TimeoutTest.t.sol\",\n        r#\"\nimport {Test} from \"forge-std/Test.sol\";\n\ncontract TimeoutHandler is Test {\n    uint256 public count;\n\n    function increment() public {\n        count++;\n    }\n}\n\ncontract TimeoutTest is Test {\n    TimeoutHandler handler;\n\n    function setUp() public {\n        handler = new TimeoutHandler();\n    }\n\n    /// forge-config: default.invariant.runs = 10000\n    /// forge-config: default.invariant.depth = 20000\n    /// forge-config: default.invariant.timeout = 1\n    function invariant_counter_timeout() public view {\n        // Invariant will fail if more than 10000 increments.\n        // Make sure test timeouts after one second and remaining runs are canceled.\n        require(handler.count() < 10000);\n    }\n}\n     \"#,\n    );\n\n    cmd.args([\"test\", \"--mt\", \"invariant_counter_timeout\"]).assert_success().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\nRan 1 test for test/TimeoutTest.t.sol:TimeoutTest\n[PASS] invariant_counter_timeout() (runs: 0, calls: 0, reverts: 0)\n\n╭----------------+-----------+-------+---------+----------╮\n| Contract       | Selector  | Calls | Reverts | Discards |\n+=========================================================+\n| TimeoutHandler | increment | [..]  | [..]    | [..]     |\n╰----------------+-----------+-------+---------+----------╯\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests)\n\n\"#]]);\n});\n\n// Tests that selector hits are uniformly distributed\n// <https://github.com/foundry-rs/foundry/issues/2986>\nforgetest_init!(invariant_selectors_weight, |prj, cmd| {\n    prj.update_config(|config| {\n        config.invariant.runs = 1;\n        config.invariant.depth = 10;\n    });\n    prj.add_source(\n        \"InvariantHandlers.sol\",\n        r#\"\ncontract HandlerOne {\n    uint256 public hit1;\n\n    function selector1() external {\n        hit1 += 1;\n    }\n}\n\ncontract HandlerTwo {\n    uint256 public hit2;\n    uint256 public hit3;\n    uint256 public hit4;\n    uint256 public hit5;\n\n    function selector2() external {\n        hit2 += 1;\n    }\n\n    function selector3() external {\n        hit3 += 1;\n    }\n\n    function selector4() external {\n        hit4 += 1;\n    }\n\n    function selector5() external {\n        hit5 += 1;\n    }\n}\n   \"#,\n    );\n\n    prj.add_test(\n        \"InvariantSelectorsWeightTest.t.sol\",\n        r#\"\nimport {Test} from \"forge-std/Test.sol\";\nimport \"src/InvariantHandlers.sol\";\n\ncontract InvariantSelectorsWeightTest is Test {\n    HandlerOne handlerOne;\n    HandlerTwo handlerTwo;\n\n    function setUp() public {\n        handlerOne = new HandlerOne();\n        handlerTwo = new HandlerTwo();\n    }\n\n    function afterInvariant() public {\n        assertEq(handlerOne.hit1(), 2);\n        assertEq(handlerTwo.hit2(), 2);\n        assertEq(handlerTwo.hit3(), 2);\n        assertEq(handlerTwo.hit4(), 1);\n        assertEq(handlerTwo.hit5(), 3);\n    }\n\n    function invariant_selectors_weight() public view {}\n}\n   \"#,\n    );\n\n    cmd.args([\"test\", \"--fuzz-seed\", \"119\", \"--mt\", \"invariant_selectors_weight\"]).assert_success();\n});\n\n// Tests original and new counterexample lengths are displayed on failure.\n// Tests switch from regular sequence output to solidity.\nforgetest_init!(invariant_sequence_len, |prj, cmd| {\n    prj.initialize_default_contracts();\n    prj.update_config(|config| {\n        config.fuzz.seed = Some(U256::from(10u32));\n    });\n\n    prj.add_test(\n        \"InvariantSequenceLenTest.t.sol\",\n        r#\"\nimport {Test} from \"forge-std/Test.sol\";\nimport \"src/Counter.sol\";\n\ncontract InvariantSequenceLenTest is Test {\n    Counter public counter;\n\n    function setUp() public {\n        counter = new Counter();\n        targetContract(address(counter));\n    }\n\n    function invariant_increment() public {\n        require(counter.number() / 2 < 100000000000000000000000000000000, \"invariant increment failure\");\n    }\n}\n   \"#,\n    );\n\n    cmd.args([\"test\", \"--mt\", \"invariant_increment\"]).assert_failure().stdout_eq(str![[r#\"\n...\n[FAIL: invariant increment failure]\n\t[Sequence] (original: 3, shrunk: 1)\n...\n\"#]]);\n\n    // Check regular sequence output. Shrink disabled to show several lines.\n    cmd.forge_fuse().arg(\"clean\").assert_success();\n    prj.update_config(|config| {\n        config.invariant.shrink_run_limit = 0;\n    });\n    cmd.forge_fuse().args([\"test\", \"--mt\", \"invariant_increment\"]).assert_failure().stdout_eq(\n        str![[r#\"\n...\nFailing tests:\nEncountered 1 failing test in test/InvariantSequenceLenTest.t.sol:InvariantSequenceLenTest\n[FAIL: invariant increment failure]\n\t[Sequence] (original: 3, shrunk: 3)\n\t\tsender=0x00000000000000000000000000000000000014aD addr=[src/Counter.sol:Counter]0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f calldata=increment() args=[]\n\t\tsender=0x8ef7F804bAd9183981A366EA618d9D47D3124649 addr=[src/Counter.sol:Counter]0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f calldata=increment() args=[]\n\t\tsender=0x00000000000000000000000000000000000016Ac addr=[src/Counter.sol:Counter]0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f calldata=setNumber(uint256) args=[284406551521730736391345481857560031052359183671404042152984097777 [2.844e65]]\n invariant_increment() (runs: 0, calls: 0, reverts: 0)\n\nEncountered a total of 1 failing tests, 0 tests succeeded\n\nTip: Run `forge test --rerun` to retry only the 1 failed test\n\n[SEED] (use `--fuzz-seed` to reproduce)\n\n\"#]],\n    );\n\n    // Check solidity sequence output on same failure.\n    cmd.forge_fuse().arg(\"clean\").assert_success();\n    prj.update_config(|config| {\n        config.invariant.show_solidity = true;\n    });\n    cmd.forge_fuse().args([\"test\", \"--mt\", \"invariant_increment\"]).assert_failure().stdout_eq(\n        str![[r#\"\n...\nFailing tests:\nEncountered 1 failing test in test/InvariantSequenceLenTest.t.sol:InvariantSequenceLenTest\n[FAIL: invariant increment failure]\n\t[Sequence] (original: 3, shrunk: 3)\n\t\tvm.prank(0x00000000000000000000000000000000000014aD);\n\t\tCounter(0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f).increment();\n\t\tvm.prank(0x8ef7F804bAd9183981A366EA618d9D47D3124649);\n\t\tCounter(0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f).increment();\n\t\tvm.prank(0x00000000000000000000000000000000000016Ac);\n\t\tCounter(0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f).setNumber(284406551521730736391345481857560031052359183671404042152984097777);\n invariant_increment() (runs: 0, calls: 0, reverts: 0)\n\nEncountered a total of 1 failing tests, 0 tests succeeded\n\nTip: Run `forge test --rerun` to retry only the 1 failed test\n\n[SEED] (use `--fuzz-seed` to reproduce)\n\n\"#]],\n    );\n\n    // Persisted failures should be able to switch output.\n    prj.update_config(|config| {\n        config.invariant.show_solidity = false;\n    });\n    cmd.forge_fuse().args([\"test\", \"--mt\", \"invariant_increment\"]).assert_failure().stdout_eq(\n        str![[r#\"\n...\nFailing tests:\nEncountered 1 failing test in test/InvariantSequenceLenTest.t.sol:InvariantSequenceLenTest\n[FAIL: invariant_increment replay failure]\n\t[Sequence] (original: 3, shrunk: 3)\n\t\tsender=0x00000000000000000000000000000000000014aD addr=[src/Counter.sol:Counter]0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f calldata=increment() args=[]\n\t\tsender=0x8ef7F804bAd9183981A366EA618d9D47D3124649 addr=[src/Counter.sol:Counter]0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f calldata=increment() args=[]\n\t\tsender=0x00000000000000000000000000000000000016Ac addr=[src/Counter.sol:Counter]0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f calldata=setNumber(uint256) args=[284406551521730736391345481857560031052359183671404042152984097777 [2.844e65]]\n invariant_increment() (runs: 1, calls: 1, reverts: 1)\n\nEncountered a total of 1 failing tests, 0 tests succeeded\n\nTip: Run `forge test --rerun` to retry only the 1 failed test\n\n[SEED] (use `--fuzz-seed` to reproduce)\n\n\"#]],\n    );\n});\n\n// Tests that persisted failure is discarded if test contract was modified.\n// <https://github.com/foundry-rs/foundry/issues/9965>\nforgetest_init!(invariant_replay_with_different_bytecode, |prj, cmd| {\n    prj.update_config(|config| {\n        config.invariant.runs = 5;\n        config.invariant.depth = 5;\n    });\n    prj.add_source(\n        \"Ownable.sol\",\n        r#\"\ncontract Ownable {\n    address public owner = address(777);\n\n    function backdoor(address _owner) external {\n        owner = address(888);\n    }\n\n    function changeOwner(address _owner) external {\n    }\n}\n   \"#,\n    );\n    prj.add_test(\n        \"OwnableTest.t.sol\",\n        r#\"\nimport {Test} from \"forge-std/Test.sol\";\nimport \"src/Ownable.sol\";\n\ncontract OwnableTest is Test {\n    Ownable ownable;\n\n    function setUp() public {\n        ownable = new Ownable();\n    }\n\n    function invariant_never_owner() public {\n        require(ownable.owner() != address(888), \"never owner\");\n    }\n}\n   \"#,\n    );\n\n    cmd.args([\"test\", \"--mt\", \"invariant_never_owner\"]).assert_failure().stdout_eq(str![[r#\"\n...\n[FAIL: never owner]\n...\n\"#]]);\n\n    // Should replay failure if same test.\n    cmd.assert_failure().stdout_eq(str![[r#\"\n...\n[FAIL: invariant_never_owner replay failure]\n...\n\"#]]);\n\n    // Different test driver that should not fail the invariant.\n    prj.add_test(\n        \"OwnableTest.t.sol\",\n        r#\"\nimport {Test} from \"forge-std/Test.sol\";\nimport \"src/Ownable.sol\";\n\ncontract OwnableTest is Test {\n    Ownable ownable;\n\n    function setUp() public {\n        ownable = new Ownable();\n        // Ignore selector that fails invariant.\n        bytes4[] memory selectors = new bytes4[](1);\n        selectors[0] = Ownable.changeOwner.selector;\n        targetSelector(FuzzSelector({addr: address(ownable), selectors: selectors}));\n    }\n\n    function invariant_never_owner() public {\n        require(ownable.owner() != address(888), \"never owner\");\n    }\n}\n   \"#,\n    );\n    cmd.assert_success().stderr_eq(str![[r#\"\n...\nWarning: Failure from \"[..]/invariant/failures/OwnableTest/invariant_never_owner\" file was ignored because test contract bytecode has changed.\n...\n\"#]])\n    .stdout_eq(str![[r#\"\n...\n[PASS] invariant_never_owner() (runs: 5, calls: 25, reverts: 0)\n...\n\"#]]);\n});\n\n// <https://github.com/foundry-rs/foundry/issues/10253>\nforgetest_init!(invariant_test_target, |prj, cmd| {\n    prj.update_config(|config| {\n        config.invariant.runs = 5;\n        config.invariant.depth = 5;\n    });\n    prj.add_test(\n        \"InvariantTest.t.sol\",\n        r#\"\nimport {Test} from \"forge-std/Test.sol\";\n\ncontract InvariantTest is Test {\n    uint256 count;\n\n    function setCount(uint256  _count) public {\n        count = _count;\n    }\n\n    function setUp() public {\n    }\n\n    function invariant_check_count() public {\n    }\n}\n   \"#,\n    );\n\n    cmd.args([\"test\", \"--mt\", \"invariant_check_count\"]).assert_failure().stdout_eq(str![[r#\"\n...\n[FAIL: failed to set up invariant testing environment: No contracts to fuzz.] invariant_check_count() (runs: 0, calls: 0, reverts: 0)\n...\n\"#]]);\n\n    prj.add_test(\n        \"InvariantTest.t.sol\",\n        r#\"\nimport {Test} from \"forge-std/Test.sol\";\n\ncontract InvariantTest is Test {\n    uint256 count;\n\n    function setCount(uint256  _count) public {\n        count = _count;\n    }\n\n    function setUp() public {\n        targetContract(address(this));\n    }\n\n    function invariant_check_count() public {\n    }\n}\n   \"#,\n    );\n\n    cmd.forge_fuse().args([\"test\", \"--mt\", \"invariant_check_count\"]).assert_success().stdout_eq(\n        str![[r#\"\n...\n[PASS] invariant_check_count() (runs: 5, calls: 25, reverts: 0)\n...\n\"#]],\n    );\n});\n\n// Tests that reserved test functions are not fuzzed when test is set as target.\n// <https://github.com/foundry-rs/foundry/issues/10469>\nforgetest_init!(invariant_target_test_contract_selectors, |prj, cmd| {\n    prj.update_config(|config| {\n        config.invariant.runs = 10;\n        config.invariant.depth = 100;\n    });\n    prj.add_test(\n        \"InvariantTargetTest.t.sol\",\n        r#\"\nimport {Test} from \"forge-std/Test.sol\";\n\ncontract InvariantTargetTest is Test {\n    bool fooCalled;\n    bool testSanityCalled;\n    bool testTableCalled;\n    uint256 invariantCalledNum;\n    uint256 setUpCalledNum;\n\n    function setUp() public {\n       targetContract(address(this));\n    }\n\n    function beforeTestSetup() public {\n    }\n\n    // Only this selector should be targeted.\n    function foo() public {\n        fooCalled = true;\n    }\n\n    function fixtureCalled() public returns (bool[] memory) {\n    }\n\n    function table_sanity(bool called) public {\n        testTableCalled = called;\n    }\n\n    function test_sanity() public {\n        testSanityCalled = true;\n    }\n\n    function afterInvariant() public {\n    }\n\n    function invariant_foo_called() public view {\n    }\n\n    function invariant_testSanity_considered_target() public {\n    }\n\n    function invariant_setUp_considered_target() public {\n        setUpCalledNum++;\n    }\n\n    function invariant_considered_target() public {\n        invariantCalledNum++;\n    }\n}\n   \"#,\n    );\n\n    cmd.args([\"test\", \"--mc\", \"InvariantTargetTest\", \"--mt\", \"invariant\"])\n        .assert_success()\n        .stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\nRan 4 tests for test/InvariantTargetTest.t.sol:InvariantTargetTest\n[PASS] invariant_considered_target() (runs: 10, calls: 1000, reverts: 0)\n\n╭---------------------+----------+-------+---------+----------╮\n| Contract            | Selector | Calls | Reverts | Discards |\n+=============================================================+\n| InvariantTargetTest | foo      | 1000  | 0       | 0        |\n╰---------------------+----------+-------+---------+----------╯\n\n[PASS] invariant_foo_called() (runs: 10, calls: 1000, reverts: 0)\n\n╭---------------------+----------+-------+---------+----------╮\n| Contract            | Selector | Calls | Reverts | Discards |\n+=============================================================+\n| InvariantTargetTest | foo      | 1000  | 0       | 0        |\n╰---------------------+----------+-------+---------+----------╯\n\n[PASS] invariant_setUp_considered_target() (runs: 10, calls: 1000, reverts: 0)\n\n╭---------------------+----------+-------+---------+----------╮\n| Contract            | Selector | Calls | Reverts | Discards |\n+=============================================================+\n| InvariantTargetTest | foo      | 1000  | 0       | 0        |\n╰---------------------+----------+-------+---------+----------╯\n\n[PASS] invariant_testSanity_considered_target() (runs: 10, calls: 1000, reverts: 0)\n\n╭---------------------+----------+-------+---------+----------╮\n| Contract            | Selector | Calls | Reverts | Discards |\n+=============================================================+\n| InvariantTargetTest | foo      | 1000  | 0       | 0        |\n╰---------------------+----------+-------+---------+----------╯\n\nSuite result: ok. 4 passed; 0 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 4 tests passed, 0 failed, 0 skipped (4 total tests)\n\n\"#]]);\n});\n\n// Tests that `targetSelector` and `excludeSelector` applied on test contract selectors are\n// applied.\n// <https://github.com/foundry-rs/foundry/issues/11006>\nforgetest_init!(invariant_target_test_include_exclude_selectors, |prj, cmd| {\n    prj.update_config(|config| {\n        config.invariant.runs = 10;\n        config.invariant.depth = 100;\n    });\n    prj.add_test(\n        \"InvariantTargetTest.t.sol\",\n        r#\"\nimport {Test} from \"forge-std/Test.sol\";\n\ncontract InvariantTargetIncludeTest is Test {\n    bool include = true;\n    function setUp() public {\n       targetContract(address(this));\n       bytes4[] memory selectors = new bytes4[](2);\n       selectors[0] = this.shouldInclude1.selector;\n       selectors[1] = this.shouldInclude2.selector;\n       targetSelector(FuzzSelector({addr: address(this), selectors: selectors}));\n    }\n\n    function shouldExclude1() public {\n        include = false;\n    }\n\n    function shouldInclude1() public {\n        include = true;\n    }\n\n    function shouldExclude2() public {\n        include = false;\n    }\n\n    function shouldInclude2() public {\n        include = true;\n    }\n\n    function invariant_include() public view {\n        require(include, \"does not include\");\n    }\n}\n\ncontract InvariantTargetExcludeTest is Test {\n    bool include = true;\n    function setUp() public {\n       targetContract(address(this));\n       bytes4[] memory selectors = new bytes4[](2);\n       selectors[0] = this.shouldExclude1.selector;\n       selectors[1] = this.shouldExclude2.selector;\n       excludeSelector(FuzzSelector({addr: address(this), selectors: selectors}));\n    }\n\n    function shouldExclude1() public {\n        include = false;\n    }\n\n    function shouldInclude1() public {\n        include = true;\n    }\n\n    function shouldExclude2() public {\n        include = false;\n    }\n\n    function shouldInclude2() public {\n        include = true;\n    }\n\n    function invariant_exclude() public view {\n        require(include, \"does not include\");\n    }\n}\n   \"#,\n    );\n\n    cmd.args([\"test\", \"--mt\", \"invariant_include\"]).assert_success().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\nRan 1 test for test/InvariantTargetTest.t.sol:InvariantTargetIncludeTest\n[PASS] invariant_include() (runs: 10, calls: 1000, reverts: 0)\n\n╭----------------------------+----------------+-------+---------+----------╮\n| Contract                   | Selector       | Calls | Reverts | Discards |\n+==========================================================================+\n| InvariantTargetIncludeTest | shouldInclude1 | [..]   | 0       | 0        |\n|----------------------------+----------------+-------+---------+----------|\n| InvariantTargetIncludeTest | shouldInclude2 | [..]   | 0       | 0        |\n╰----------------------------+----------------+-------+---------+----------╯\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests)\n\n\"#]]);\n\n    cmd.forge_fuse().args([\"test\", \"--mt\", \"invariant_exclude\"]).assert_success().stdout_eq(str![\n        [r#\"\nNo files changed, compilation skipped\n\nRan 1 test for test/InvariantTargetTest.t.sol:InvariantTargetExcludeTest\n[PASS] invariant_exclude() (runs: 10, calls: 1000, reverts: 0)\n\n╭----------------------------+----------------+-------+---------+----------╮\n| Contract                   | Selector       | Calls | Reverts | Discards |\n+==========================================================================+\n| InvariantTargetExcludeTest | shouldInclude1 | [..]   | 0       | 0        |\n|----------------------------+----------------+-------+---------+----------|\n| InvariantTargetExcludeTest | shouldInclude2 | [..]   | 0       | 0        |\n╰----------------------------+----------------+-------+---------+----------╯\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests)\n\n\"#]\n    ]);\n\n    cmd.forge_fuse()\n        .args([\"test\", \"--mt\", \"invariant_include\", \"--md\"])\n        .assert_success()\n        .stdout_eq(str![[r#\"\nNo files changed, compilation skipped\n\nRan 1 test for test/InvariantTargetTest.t.sol:InvariantTargetIncludeTest\n[PASS] invariant_include() (runs: 10, calls: 1000, reverts: 0)\n\n| Contract                   | Selector       | Calls | Reverts | Discards |\n|----------------------------|----------------|-------|---------|----------|\n| InvariantTargetIncludeTest | shouldInclude1 | [..]   | 0       | 0        |\n| InvariantTargetIncludeTest | shouldInclude2 | [..]   | 0       | 0        |\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests)\n\n\"#]]);\n\n    cmd.forge_fuse()\n        .args([\"test\", \"--mt\", \"invariant_exclude\", \"--md\"])\n        .assert_success()\n        .stdout_eq(str![[r#\"\nNo files changed, compilation skipped\n\nRan 1 test for test/InvariantTargetTest.t.sol:InvariantTargetExcludeTest\n[PASS] invariant_exclude() (runs: 10, calls: 1000, reverts: 0)\n\n| Contract                   | Selector       | Calls | Reverts | Discards |\n|----------------------------|----------------|-------|---------|----------|\n| InvariantTargetExcludeTest | shouldInclude1 | [..]   | 0       | 0        |\n| InvariantTargetExcludeTest | shouldInclude2 | [..]   | 0       | 0        |\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests)\n\n\"#]]);\n});\n\n// <https://github.com/foundry-rs/foundry/issues/11453>\nforgetest_init!(corpus_dir, |prj, cmd| {\n    prj.initialize_default_contracts();\n    prj.update_config(|config| {\n        config.invariant.runs = 10;\n        config.invariant.depth = 10;\n        config.invariant.corpus.corpus_dir = Some(\"invariant_corpus\".into());\n\n        config.fuzz.runs = 10;\n        config.fuzz.corpus.corpus_dir = Some(\"fuzz_corpus\".into());\n    });\n    prj.add_test(\n        \"CounterTests.t.sol\",\n        r#\"\nimport {Test} from \"forge-std/Test.sol\";\nimport {Counter} from \"../src/Counter.sol\";\n\ncontract Counter1Test is Test {\n    Counter public counter;\n\n    function setUp() public {\n        counter = new Counter();\n        counter.setNumber(0);\n    }\n\n    function testFuzz_SetNumber(uint256 x) public {\n        counter.setNumber(x);\n        assertEq(counter.number(), x);\n    }\n\n    function invariant_counter_called() public view {\n    }\n}\n\ncontract Counter2Test is Test {\n    Counter public counter;\n\n    function setUp() public {\n        counter = new Counter();\n        counter.setNumber(0);\n    }\n\n    function testFuzz_SetNumber(uint256 x) public {\n        counter.setNumber(x);\n        assertEq(counter.number(), x);\n    }\n\n    function invariant_counter_called() public view {\n    }\n}\n   \"#,\n    );\n\n    cmd.args([\"test\"]).assert_success().stdout_eq(str![[r#\"\n...\nRan 3 test suites [ELAPSED]: 6 tests passed, 0 failed, 0 skipped (6 total tests)\n\n\"#]]);\n\n    assert!(\n        prj.root()\n            .join(\"invariant_corpus\")\n            .join(\"Counter1Test\")\n            .join(\"invariant_counter_called\")\n            .exists()\n    );\n    assert!(\n        prj.root()\n            .join(\"invariant_corpus\")\n            .join(\"Counter2Test\")\n            .join(\"invariant_counter_called\")\n            .exists()\n    );\n    assert!(\n        prj.root().join(\"fuzz_corpus\").join(\"Counter1Test\").join(\"testFuzz_SetNumber\").exists()\n    );\n    assert!(\n        prj.root().join(\"fuzz_corpus\").join(\"Counter2Test\").join(\"testFuzz_SetNumber\").exists()\n    );\n});\n\n// Tests that check_interval=0 only asserts on the last call of each run.\nforgetest_init!(check_interval_zero_only_checks_last_call, |prj, cmd| {\n    prj.update_config(|config| {\n        config.invariant.runs = 5;\n        config.invariant.depth = 10;\n        config.invariant.check_interval = 0;\n    });\n    prj.add_test(\n        \"CheckIntervalTest.t.sol\",\n        r#\"\nimport {Test} from \"forge-std/Test.sol\";\n\ncontract CounterHandler {\n    uint256 public counter;\n\n    function increment() public {\n        counter++;\n    }\n}\n\ncontract CheckIntervalTest is Test {\n    CounterHandler handler;\n\n    function setUp() public {\n        handler = new CounterHandler();\n        targetContract(address(handler));\n    }\n\n    // This invariant would fail on intermediate calls (counter 1-9) but passes on call 10\n    // With check_interval=0, only the last call is checked, so if depth=10 and counter=10\n    // at the end, this should pass even though intermediate states violated the invariant.\n    function invariant_counter_multiple_of_depth() public view {\n        // Only passes when counter is 0 or 10 (depth). Fails for 1-9.\n        require(handler.counter() == 0 || handler.counter() == 10, \"not multiple of depth\");\n    }\n}\n   \"#,\n    );\n\n    cmd.args([\"test\", \"--mt\", \"invariant_counter\"]).assert_success().stdout_eq(str![[r#\"\n...\n[PASS] invariant_counter_multiple_of_depth() (runs: 5, calls: 50, reverts: 0)\n...\n\"#]]);\n});\n\n// Tests that check_interval=1 (default) asserts after every call.\nforgetest_init!(check_interval_one_checks_every_call, |prj, cmd| {\n    prj.update_config(|config| {\n        config.invariant.runs = 1;\n        config.invariant.depth = 10;\n        config.invariant.check_interval = 1;\n    });\n    prj.add_test(\n        \"CheckIntervalTest.t.sol\",\n        r#\"\nimport {Test} from \"forge-std/Test.sol\";\n\ncontract CounterHandler {\n    uint256 public counter;\n\n    function increment() public {\n        counter++;\n    }\n}\n\ncontract CheckIntervalTest is Test {\n    CounterHandler handler;\n\n    function setUp() public {\n        handler = new CounterHandler();\n        targetContract(address(handler));\n    }\n\n    // This invariant fails as soon as counter > 5.\n    // With check_interval=1, it should fail on call 6.\n    function invariant_counter_le_five() public view {\n        require(handler.counter() <= 5, \"counter > 5\");\n    }\n}\n   \"#,\n    );\n\n    assert_invariant(cmd.args([\"test\", \"--mt\", \"invariant_counter\"])).failure().stdout_eq(str![[\n        r#\"\n...\n[FAIL: counter > 5]\n\t[SEQUENCE]\n...\n\"#\n    ]]);\n});\n\n// Tests that check_interval=N checks every N calls AND always on the last call.\nforgetest_init!(check_interval_n_checks_every_n_calls, |prj, cmd| {\n    prj.update_config(|config| {\n        config.invariant.runs = 1;\n        config.invariant.depth = 20;\n        config.invariant.check_interval = 5;\n    });\n    prj.add_test(\n        \"CheckIntervalTest.t.sol\",\n        r#\"\nimport {Test} from \"forge-std/Test.sol\";\n\ncontract CounterHandler {\n    uint256 public counter;\n\n    function increment() public {\n        counter++;\n    }\n}\n\ncontract CheckIntervalTest is Test {\n    CounterHandler handler;\n\n    function setUp() public {\n        handler = new CounterHandler();\n        targetContract(address(handler));\n    }\n\n    // With check_interval=5 and depth=20, invariant is checked at calls 5,10,15,20.\n    // This passes because 5,10,15,20 are all multiples of 5.\n    function invariant_counter_multiple_of_five() public view {\n        require(handler.counter() % 5 == 0, \"not multiple of 5\");\n    }\n}\n   \"#,\n    );\n\n    cmd.args([\"test\", \"--mt\", \"invariant_counter\"]).assert_success().stdout_eq(str![[r#\"\n...\n[PASS] invariant_counter_multiple_of_five() (runs: 1, calls: 20, reverts: 0)\n...\n\"#]]);\n});\n\n// Tests check_interval via inline config annotation.\nforgetest_init!(check_interval_inline_config, |prj, cmd| {\n    prj.add_test(\n        \"CheckIntervalInlineTest.t.sol\",\n        r#\"\nimport {Test} from \"forge-std/Test.sol\";\n\ncontract CounterHandler {\n    uint256 public counter;\n\n    function increment() public {\n        counter++;\n    }\n}\n\ncontract CheckIntervalInlineTest is Test {\n    CounterHandler handler;\n\n    function setUp() public {\n        handler = new CounterHandler();\n        targetContract(address(handler));\n    }\n\n    /// forge-config: default.invariant.runs = 1\n    /// forge-config: default.invariant.depth = 10\n    /// forge-config: default.invariant.check_interval = 0\n    function invariant_only_last_checked() public view {\n        // Only passes when counter is 0 or 10. With check_interval=0, only last call is checked.\n        require(handler.counter() == 0 || handler.counter() == 10, \"not at boundary\");\n    }\n}\n   \"#,\n    );\n\n    cmd.args([\"test\", \"--mt\", \"invariant_only_last_checked\"]).assert_success().stdout_eq(str![[\n        r#\"\n...\n[PASS] invariant_only_last_checked() (runs: 1, calls: 10, reverts: 0)\n...\n\"#\n    ]]);\n});\n"
  },
  {
    "path": "crates/forge/tests/cli/test_cmd/invariant/storage.rs",
    "content": "use super::*;\n\nforgetest_init!(storage, |prj, cmd| {\n    prj.add_test(\n        \"name\",\n        r#\"\nimport \"forge-std/Test.sol\";\n\ncontract Contract {\n    address public addr = address(0xbeef);\n    string public str = \"hello\";\n    uint256 public num = 1337;\n    uint256 public pushNum;\n\n    function changeAddress(address _addr) public {\n        if (_addr == addr) {\n            addr = address(0);\n        }\n    }\n\n    function changeString(string memory _str) public {\n        if (keccak256(bytes(_str)) == keccak256(bytes(str))) {\n            str = \"\";\n        }\n    }\n\n    function changeUint(uint256 _num) public {\n        if (_num == num) {\n            num = 0;\n        }\n    }\n\n    function push(uint256 _num) public {\n        if (_num == 68) {\n            pushNum = 69;\n        }\n    }\n}\n\ncontract InvariantStorageTest is Test {\n    Contract c;\n\n    function setUp() public {\n        c = new Contract();\n    }\n\n    function invariantChangeAddress() public view {\n        require(c.addr() == address(0xbeef), \"changedAddr\");\n    }\n\n    function invariantChangeString() public view {\n        require(keccak256(bytes(c.str())) == keccak256(bytes(\"hello\")), \"changedStr\");\n    }\n\n    function invariantChangeUint() public view {\n        require(c.num() == 1337, \"changedUint\");\n    }\n\n    function invariantPush() public view {\n        require(c.pushNum() == 0, \"pushUint\");\n    }\n}\n\"#,\n    );\n\n    assert_invariant(cmd.args([\"test\"])).failure().stdout_eq(str![[r#\"\n...\nSuite result: FAILED. 0 passed; 4 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 0 tests passed, 4 failed, 0 skipped (4 total tests)\n\nFailing tests:\nEncountered 4 failing tests in test/name.sol:InvariantStorageTest\n...\n\"#]]);\n});\n"
  },
  {
    "path": "crates/forge/tests/cli/test_cmd/invariant/target.rs",
    "content": "use super::*;\n\nforgetest!(filters, |prj, cmd| {\n    prj.insert_vm();\n    prj.insert_ds_test();\n    prj.update_config(|config| {\n        config.invariant.runs = 50;\n        config.invariant.depth = 10;\n    });\n\n    prj.add_test(\n        \"ExcludeContracts.t.sol\",\n        r#\"\nimport { DSTest as Test } from \"src/test.sol\";\n\ncontract Hello {\n    bool public world = true;\n\n    function change() public {\n        world = false;\n    }\n}\n\ncontract ExcludeContracts is Test {\n    Hello hello;\n\n    function setUp() public {\n        hello = new Hello();\n        new Hello();\n    }\n\n    function excludeContracts() public view returns (address[] memory) {\n        address[] memory addrs = new address[](1);\n        addrs[0] = address(hello);\n        return addrs;\n    }\n\n    function invariantTrueWorld() public {\n        require(hello.world() == true, \"false world\");\n    }\n}\n\"#,\n    );\n\n    prj.add_test(\n        \"ExcludeSelectors.t.sol\",\n        r#\"\nimport { DSTest as Test } from \"src/test.sol\";\n\nstruct FuzzSelector {\n    address addr;\n    bytes4[] selectors;\n}\n\ncontract Hello {\n    bool public world = false;\n\n    function change() public {\n        world = true;\n    }\n\n    function real_change() public {\n        world = false;\n    }\n}\n\ncontract ExcludeSelectors is Test {\n    Hello hello;\n\n    function setUp() public {\n        hello = new Hello();\n    }\n\n    function excludeSelectors() public view returns (FuzzSelector[] memory) {\n        FuzzSelector[] memory targets = new FuzzSelector[](1);\n        bytes4[] memory selectors = new bytes4[](1);\n        selectors[0] = Hello.change.selector;\n        targets[0] = FuzzSelector(address(hello), selectors);\n        return targets;\n    }\n\n    function invariantFalseWorld() public {\n        require(hello.world() == false, \"true world\");\n    }\n}\n\"#,\n    );\n\n    prj.add_test(\n        \"ExcludeSenders.t.sol\",\n        r#\"\nimport { DSTest as Test } from \"src/test.sol\";\n\ncontract Hello {\n    address seed_address = address(0xdeadbeef);\n    bool public world = true;\n\n    function changeBeef() public {\n        require(msg.sender == address(0xdeadbeef));\n        world = false;\n    }\n\n    // address(0) should be automatically excluded\n    function change0() public {\n        require(msg.sender == address(0));\n        world = false;\n    }\n}\n\ncontract ExcludeSenders is Test {\n    Hello hello;\n\n    function setUp() public {\n        hello = new Hello();\n    }\n\n    function excludeSenders() public view returns (address[] memory) {\n        address[] memory addrs = new address[](1);\n        addrs[0] = address(0xdeadbeef);\n        return addrs;\n    }\n\n    // Tests clashing. Exclusion takes priority.\n    function targetSenders() public view returns (address[] memory) {\n        address[] memory addrs = new address[](1);\n        addrs[0] = address(0xdeadbeef);\n        return addrs;\n    }\n\n    function invariantTrueWorld() public {\n        require(hello.world() == true, \"false world\");\n    }\n}\n\"#,\n    );\n\n    prj.add_test(\n        \"TargetContracts.t.sol\",\n        r#\"\nimport { DSTest as Test } from \"src/test.sol\";\n\ncontract Hello {\n    bool public world = true;\n\n    function change() public {\n        world = false;\n    }\n}\n\ncontract TargetContracts is Test {\n    Hello hello1;\n    Hello hello2;\n\n    function setUp() public {\n        hello1 = new Hello();\n        hello2 = new Hello();\n    }\n\n    function targetContracts() public view returns (address[] memory) {\n        address[] memory addrs = new address[](1);\n        addrs[0] = address(hello1);\n        return addrs;\n    }\n\n    function invariantTrueWorld() public {\n        require(hello2.world() == true, \"false world\");\n    }\n}\n\"#,\n    );\n\n    prj.add_test(\n        \"TargetInterfaces.t.sol\",\n        r#\"\nimport { DSTest as Test } from \"src/test.sol\";\n\nstruct FuzzInterface {\n    address target;\n    string[] artifacts;\n}\n\ncontract Hello {\n    bool public world;\n\n    function changeWorld() external {\n        world = true;\n    }\n}\n\ninterface IHello {\n    function world() external view returns (bool);\n    function changeWorld() external;\n}\n\ncontract HelloProxy {\n    address internal immutable _implementation;\n\n    constructor(address implementation_) {\n        _implementation = implementation_;\n    }\n\n    function _delegate(address implementation) internal {\n        assembly {\n            calldatacopy(0, 0, calldatasize())\n\n            let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)\n\n            returndatacopy(0, 0, returndatasize())\n\n            switch result\n            case 0 { revert(0, returndatasize()) }\n            default { return(0, returndatasize()) }\n        }\n    }\n\n    fallback() external payable {\n        _delegate(_implementation);\n    }\n}\n\ncontract TargetWorldInterfaces is Test {\n    IHello proxy;\n\n    function setUp() public {\n        Hello hello = new Hello();\n        proxy = IHello(address(new HelloProxy(address(hello))));\n    }\n\n    function targetInterfaces() public view returns (FuzzInterface[] memory) {\n        FuzzInterface[] memory targets = new FuzzInterface[](1);\n\n        string[] memory artifacts = new string[](1);\n        artifacts[0] = \"IHello\";\n\n        targets[0] = FuzzInterface(address(proxy), artifacts);\n\n        return targets;\n    }\n\n    function invariantTrueWorld() public {\n        require(proxy.world() == false, \"false world\");\n    }\n}\n\"#,\n    );\n\n    prj.add_test(\n        \"TargetSelectors.t.sol\",\n        r#\"\nimport { DSTest as Test } from \"src/test.sol\";\n\nstruct FuzzSelector {\n    address addr;\n    bytes4[] selectors;\n}\n\ncontract Hello {\n    bool public world = true;\n\n    function change() public {\n        world = true;\n    }\n\n    function real_change() public {\n        world = false;\n    }\n}\n\ncontract TargetSelectors is Test {\n    Hello hello;\n\n    function setUp() public {\n        hello = new Hello();\n    }\n\n    function targetSelectors() public view returns (FuzzSelector[] memory) {\n        FuzzSelector[] memory targets = new FuzzSelector[](1);\n        bytes4[] memory selectors = new bytes4[](1);\n        selectors[0] = Hello.change.selector;\n        targets[0] = FuzzSelector(address(hello), selectors);\n        return targets;\n    }\n\n    function invariantTrueWorld() public {\n        require(hello.world() == true, \"false world\");\n    }\n}\n\"#,\n    );\n\n    prj.add_test(\n        \"TargetSenders.t.sol\",\n        r#\"\nimport { DSTest as Test } from \"src/test.sol\";\n\ncontract Hello {\n    bool public world = true;\n\n    function change() public {\n        require(msg.sender == address(0xdeadbeef));\n        world = false;\n    }\n}\n\ncontract TargetSenders is Test {\n    Hello hello;\n\n    function setUp() public {\n        hello = new Hello();\n    }\n\n    function targetSenders() public view returns (address[] memory) {\n        address[] memory addrs = new address[](1);\n        addrs[0] = address(0xdeadbeef);\n        return addrs;\n    }\n\n    function invariantTrueWorld() public {\n        require(hello.world() == true, \"false world\");\n    }\n}\n\"#,\n    );\n\n    prj.add_test(\n        \"ExcludeArtifacts.t.sol\",\n        r#\"\nimport { DSTest as Test } from \"src/test.sol\";\n\n// Will get automatically excluded. Otherwise it would throw error.\ncontract NoMutFunctions {\n    function no_change() public pure {}\n}\n\ncontract Excluded {\n    bool public world = true;\n\n    function change() public {\n        world = false;\n    }\n}\n\ncontract Hello {\n    bool public world = true;\n\n    function change() public {\n        world = false;\n    }\n}\n\ncontract ExcludeArtifacts is Test {\n    Excluded excluded;\n\n    function setUp() public {\n        excluded = new Excluded();\n        new Hello();\n        new NoMutFunctions();\n    }\n\n    function excludeArtifacts() public returns (string[] memory) {\n        string[] memory abis = new string[](1);\n        abis[0] = \"test/ExcludeArtifacts.t.sol:Excluded\";\n        return abis;\n    }\n\n    function invariantShouldPass() public {\n        require(excluded.world() == true, \"false world\");\n    }\n}\n\"#,\n    );\n\n    prj.add_test(\n        \"TargetArtifactSelectors2.t.sol\",\n        r#\"\nimport { DSTest as Test } from \"src/test.sol\";\n\nstruct FuzzArtifactSelector {\n    string artifact;\n    bytes4[] selectors;\n}\n\ncontract Parent {\n    bool public should_be_true = true;\n    address public child;\n\n    function change() public {\n        child = msg.sender;\n        should_be_true = false;\n    }\n\n    function create() public {\n        new Child();\n    }\n}\n\ncontract Child {\n    Parent parent;\n    bool public changed = false;\n\n    constructor() {\n        parent = Parent(msg.sender);\n    }\n\n    function change_parent() public {\n        parent.change();\n    }\n\n    function tracked_change_parent() public {\n        parent.change();\n    }\n}\n\ncontract TargetArtifactSelectors2 is Test {\n    Parent parent;\n\n    function setUp() public {\n        parent = new Parent();\n    }\n\n    function targetArtifactSelectors() public returns (FuzzArtifactSelector[] memory) {\n        FuzzArtifactSelector[] memory targets = new FuzzArtifactSelector[](2);\n        bytes4[] memory selectors_child = new bytes4[](1);\n\n        selectors_child[0] = Child.change_parent.selector;\n        targets[0] = FuzzArtifactSelector(\n            \"test/TargetArtifactSelectors2.t.sol:Child\", selectors_child\n        );\n\n        bytes4[] memory selectors_parent = new bytes4[](1);\n        selectors_parent[0] = Parent.create.selector;\n        targets[1] = FuzzArtifactSelector(\n            \"test/TargetArtifactSelectors2.t.sol:Parent\", selectors_parent\n        );\n        return targets;\n    }\n\n    function invariantShouldFail() public {\n        if (!parent.should_be_true()) {\n            require(!Child(address(parent.child())).changed(), \"should have not happened\");\n        }\n        require(parent.should_be_true() == true, \"it's false\");\n    }\n}\n\"#,\n    );\n\n    prj.add_test(\n        \"TargetArtifactSelectors.t.sol\",\n        r#\"\nimport { DSTest as Test } from \"src/test.sol\";\n\nstruct FuzzArtifactSelector {\n    string artifact;\n    bytes4[] selectors;\n}\n\ncontract Hi {\n    bool public world = true;\n\n    function no_change() public {\n        world = true;\n    }\n\n    function change() public {\n        world = false;\n    }\n}\n\ncontract TargetArtifactSelectors is Test {\n    Hi hello;\n\n    function setUp() public {\n        hello = new Hi();\n    }\n\n    function targetArtifactSelectors() public returns (FuzzArtifactSelector[] memory) {\n        FuzzArtifactSelector[] memory targets = new FuzzArtifactSelector[](1);\n        bytes4[] memory selectors = new bytes4[](1);\n        selectors[0] = Hi.no_change.selector;\n        targets[0] =\n            FuzzArtifactSelector(\"test/TargetArtifactSelectors.t.sol:Hi\", selectors);\n        return targets;\n    }\n\n    function invariantShouldPass() public {\n        require(hello.world() == true, \"false world\");\n    }\n}\n\"#,\n    );\n\n    prj.add_test(\n        \"TargetArtifacts.t.sol\",\n        r#\"\nimport { DSTest as Test } from \"src/test.sol\";\n\ncontract Targeted {\n    bool public world = true;\n\n    function change() public {\n        world = false;\n    }\n}\n\ncontract Hello {\n    bool public world = true;\n\n    function no_change() public {}\n}\n\ncontract TargetArtifacts is Test {\n    Targeted target1;\n    Targeted target2;\n    Hello hello;\n\n    function setUp() public {\n        target1 = new Targeted();\n        target2 = new Targeted();\n        hello = new Hello();\n    }\n\n    function targetArtifacts() public returns (string[] memory) {\n        string[] memory abis = new string[](1);\n        abis[0] = \"test/TargetArtifacts.t.sol:Targeted\";\n        return abis;\n    }\n\n    function invariantShouldPass() public {\n        require(target2.world() == true || target1.world() == true || hello.world() == true, \"false world\");\n    }\n\n    function invariantShouldFail() public {\n        require(target2.world() == true || target1.world() == true, \"false world\");\n    }\n}\n\"#,\n    );\n\n    // Test ExcludeContracts\n    assert_invariant(cmd.forge_fuse().args([\"test\", \"--mc\", \"ExcludeContracts\"]))\n        .success()\n        .stdout_eq(str![[r#\"\n...\nRan 1 test for test/ExcludeContracts.t.sol:ExcludeContracts\n[PASS] invariantTrueWorld() ([RUNS])\n\n[STATS]\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests)\n\n\"#]]);\n\n    // Test ExcludeSelectors\n    assert_invariant(cmd.forge_fuse().args([\"test\", \"--mc\", \"ExcludeSelectors\"]))\n        .success()\n        .stdout_eq(str![[r#\"\n...\nRan 1 test for test/ExcludeSelectors.t.sol:ExcludeSelectors\n[PASS] invariantFalseWorld() ([RUNS])\n\n[STATS]\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests)\n\n\"#]]);\n\n    // Test ExcludeSenders\n    assert_invariant(cmd.forge_fuse().args([\"test\", \"--mc\", \"ExcludeSenders\"]))\n        .success()\n        .stdout_eq(str![[r#\"\n...\nRan 1 test for test/ExcludeSenders.t.sol:ExcludeSenders\n[PASS] invariantTrueWorld() ([RUNS])\n\n[STATS]\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests)\n\n\"#]]);\n\n    // Test TargetContracts\n    assert_invariant(cmd.forge_fuse().args([\"test\", \"--mc\", \"TargetContracts\"]))\n        .success()\n        .stdout_eq(str![[r#\"\n...\nRan 1 test for test/TargetContracts.t.sol:TargetContracts\n[PASS] invariantTrueWorld() ([RUNS])\n\n[STATS]\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests)\n\n\"#]]);\n\n    // Test TargetInterfaces (should fail)\n    assert_invariant(cmd.forge_fuse().args([\"test\", \"--mc\", \"TargetWorldInterfaces\"]))\n        .failure()\n        .stdout_eq(str![[r#\"\n...\nRan 1 test for test/TargetInterfaces.t.sol:TargetWorldInterfaces\n[FAIL: false world]\n\t[SEQUENCE]\n invariantTrueWorld() ([RUNS])\n\n[STATS]\n\nSuite result: FAILED. 0 passed; 1 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 0 tests passed, 1 failed, 0 skipped (1 total tests)\n\nFailing tests:\nEncountered 1 failing test in test/TargetInterfaces.t.sol:TargetWorldInterfaces\n[FAIL: false world]\n\t[SEQUENCE]\n invariantTrueWorld() ([RUNS])\n\nEncountered a total of 1 failing tests, 0 tests succeeded\n\nTip: Run `forge test --rerun` to retry only the 1 failed test\n\n[SEED] (use `--fuzz-seed` to reproduce)\n\n\"#]]);\n\n    // Test TargetSelectors\n    assert_invariant(cmd.forge_fuse().args([\"test\", \"--mc\", \"TargetSelectors\"]))\n        .success()\n        .stdout_eq(str![[r#\"\n...\nRan 1 test for test/TargetSelectors.t.sol:TargetSelectors\n[PASS] invariantTrueWorld() ([RUNS])\n\n[STATS]\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests)\n\n\"#]]);\n\n    // Test TargetSenders (should fail)\n    assert_invariant(cmd.forge_fuse().args([\"test\", \"--mc\", \"TargetSenders\"])).failure().stdout_eq(\n        str![[r#\"\n...\nRan 1 test for test/TargetSenders.t.sol:TargetSenders\n[FAIL: false world]\n\t[SEQUENCE]\n invariantTrueWorld() ([RUNS])\n\n[STATS]\n\nSuite result: FAILED. 0 passed; 1 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 0 tests passed, 1 failed, 0 skipped (1 total tests)\n\nFailing tests:\nEncountered 1 failing test in test/TargetSenders.t.sol:TargetSenders\n[FAIL: false world]\n\t[SEQUENCE]\n invariantTrueWorld() ([RUNS])\n\nEncountered a total of 1 failing tests, 0 tests succeeded\n\nTip: Run `forge test --rerun` to retry only the 1 failed test\n\n[SEED] (use `--fuzz-seed` to reproduce)\n\n\"#]],\n    );\n\n    // Test ExcludeArtifacts\n    assert_invariant(cmd.forge_fuse().args([\"test\", \"--mc\", \"ExcludeArtifacts\"]))\n        .success()\n        .stdout_eq(str![[r#\"\n...\nRan 1 test for test/ExcludeArtifacts.t.sol:ExcludeArtifacts\n[PASS] invariantShouldPass() ([RUNS])\n\n[STATS]\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests)\n\n\"#]]);\n\n    // Test TargetArtifactSelectors2 (should fail)\n    assert_invariant(cmd.forge_fuse().args([\"test\", \"--mc\", \"TargetArtifactSelectors2\"]))\n        .failure()\n        .stdout_eq(str![[r#\"\n...\nRan 1 test for test/TargetArtifactSelectors2.t.sol:TargetArtifactSelectors2\n[FAIL: it's false]\n\t[SEQUENCE]\n invariantShouldFail() ([RUNS])\n\n[STATS]\n\nSuite result: FAILED. 0 passed; 1 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 0 tests passed, 1 failed, 0 skipped (1 total tests)\n\nFailing tests:\nEncountered 1 failing test in test/TargetArtifactSelectors2.t.sol:TargetArtifactSelectors2\n[FAIL: it's false]\n\t[SEQUENCE]\n invariantShouldFail() ([RUNS])\n\nEncountered a total of 1 failing tests, 0 tests succeeded\n\nTip: Run `forge test --rerun` to retry only the 1 failed test\n\n[SEED] (use `--fuzz-seed` to reproduce)\n\n\"#]]);\n\n    // Test TargetArtifactSelectors\n    assert_invariant(cmd.forge_fuse().args([\"test\", \"--mc\", \"^TargetArtifactSelectors$\"]))\n        .success()\n        .stdout_eq(str![[r#\"\n...\nRan 1 test for test/TargetArtifactSelectors.t.sol:TargetArtifactSelectors\n[PASS] invariantShouldPass() ([RUNS])\n\n[STATS]\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests)\n\n\"#]]);\n\n    // Test TargetArtifacts\n    assert_invariant(cmd.forge_fuse().args([\"test\", \"--mc\", \"^TargetArtifacts$\"]))\n        .failure()\n        .stdout_eq(str![[r#\"\n...\nRan 2 tests for test/TargetArtifacts.t.sol:TargetArtifacts\n[FAIL: false world]\n\t[SEQUENCE]\n invariantShouldFail() ([RUNS])\n\n[STATS]\n\n[PASS] invariantShouldPass() ([RUNS])\n\n[STATS]\n\nSuite result: FAILED. 1 passed; 1 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 1 tests passed, 1 failed, 0 skipped (2 total tests)\n\nFailing tests:\nEncountered 1 failing test in test/TargetArtifacts.t.sol:TargetArtifacts\n[FAIL: false world]\n\t[SEQUENCE]\n invariantShouldFail() ([RUNS])\n\nEncountered a total of 1 failing tests, 1 tests succeeded\n\nTip: Run `forge test --rerun` to retry only the 1 failed test\n\n[SEED] (use `--fuzz-seed` to reproduce)\n\n\"#]]);\n});\n\n// https://github.com/foundry-rs/foundry/issues/5625\n// https://github.com/foundry-rs/foundry/issues/6166\n// `Target.wrongSelector` is not called when handler added as `targetContract`\n// `Target.wrongSelector` is called (and test fails) when no `targetContract` set\nforgetest!(fuzzed_selected_targets, |prj, cmd| {\n    prj.insert_vm();\n    prj.insert_ds_test();\n    prj.update_config(|config| {\n        config.invariant.depth = 10;\n        config.invariant.fail_on_revert = true;\n    });\n\n    prj.add_test(\n        \"FuzzedTargetContracts.t.sol\",\n        r#\"\nimport { DSTest as Test } from \"src/test.sol\";\nimport \"src/Vm.sol\";\n\ncontract Target {\n    uint256 count;\n\n    function wrongSelector() external {\n        revert(\"wrong target selector called\");\n    }\n\n    function goodSelector() external {\n        count++;\n    }\n}\n\ncontract Handler is Test {\n    function increment() public {\n        Target(0x6B175474E89094C44Da98b954EedeAC495271d0F).goodSelector();\n    }\n}\n\ncontract ExplicitTargetContract is Test {\n    Vm constant vm = Vm(HEVM_ADDRESS);\n    Handler handler;\n\n    function setUp() public {\n        Target target = new Target();\n        bytes memory targetCode = address(target).code;\n        vm.etch(address(0x6B175474E89094C44Da98b954EedeAC495271d0F), targetCode);\n\n        handler = new Handler();\n    }\n\n    function targetContracts() public view returns (address[] memory) {\n        address[] memory addrs = new address[](1);\n        addrs[0] = address(handler);\n        return addrs;\n    }\n\n    function invariant_explicit_target() public {}\n}\n\ncontract DynamicTargetContract is Test {\n    Vm constant vm = Vm(HEVM_ADDRESS);\n    Handler handler;\n\n    function setUp() public {\n        Target target = new Target();\n        bytes memory targetCode = address(target).code;\n        vm.etch(address(0x6B175474E89094C44Da98b954EedeAC495271d0F), targetCode);\n\n        handler = new Handler();\n    }\n\n    function invariant_dynamic_targets() public {}\n}\n\"#,\n    );\n\n    assert_invariant(cmd.args([\"test\", \"-j1\"])).failure().stdout_eq(str![[r#\"\n...\n[PASS] invariant_explicit_target() ([RUNS])\n...\n[FAIL: wrong target selector called]\n\t[SEQUENCE]\n invariant_dynamic_targets() ([RUNS])\n...\n\n\"#]]);\n});\n"
  },
  {
    "path": "crates/forge/tests/cli/test_cmd/logs.rs",
    "content": "//! Tests for various logging functionality\n\nuse foundry_test_utils::str;\n\nforgetest_init!(debug_logs, |prj, cmd| {\n    prj.add_test(\n        \"DebugLogs.t.sol\",\n        r#\"\nimport \"forge-std/Test.sol\";\n\ncontract DebugLogsTest is Test {\n    constructor() {\n        emit log_uint(0);\n    }\n\n    function setUp() public {\n        emit log_uint(1);\n    }\n\n    function test1() public {\n        emit log_uint(2);\n    }\n\n    function test2() public {\n        emit log_uint(3);\n    }\n\n    function testRevertIfWithRevert() public {\n        Fails fails = new Fails();\n        emit log_uint(4);\n        vm.expectRevert();\n        fails.failure();\n    }\n\n    /// forge-config: default.allow_internal_expect_revert = true\n    function testRevertIfWithRequire() public {\n        emit log_uint(5);\n        vm.expectRevert();\n        require(false);\n    }\n\n    function testLog() public {\n        emit log(\"Error: Assertion Failed\");\n    }\n\n    function testLogs() public {\n        emit logs(bytes(\"abcd\"));\n    }\n\n    function testLogAddress() public {\n        emit log_address(address(1));\n    }\n\n    function testLogBytes32() public {\n        emit log_bytes32(bytes32(\"abcd\"));\n    }\n\n    function testLogInt() public {\n        emit log_int(int256(-31337));\n    }\n\n    function testLogBytes() public {\n        emit log_bytes(bytes(\"abcd\"));\n    }\n\n    function testLogString() public {\n        emit log_string(\"here\");\n    }\n\n    function testLogNamedAddress() public {\n        emit log_named_address(\"address\", address(1));\n    }\n\n    function testLogNamedBytes32() public {\n        emit log_named_bytes32(\"abcd\", bytes32(\"abcd\"));\n    }\n\n    function testLogNamedDecimalInt() public {\n        emit log_named_decimal_int(\"amount\", int256(-31337), uint256(18));\n    }\n\n    function testLogNamedDecimalUint() public {\n        emit log_named_decimal_uint(\"amount\", uint256(1 ether), uint256(18));\n    }\n\n    function testLogNamedInt() public {\n        emit log_named_int(\"amount\", int256(-31337));\n    }\n\n    function testLogNamedUint() public {\n        emit log_named_uint(\"amount\", uint256(1 ether));\n    }\n\n    function testLogNamedBytes() public {\n        emit log_named_bytes(\"abcd\", bytes(\"abcd\"));\n    }\n\n    function testLogNamedString() public {\n        emit log_named_string(\"key\", \"val\");\n    }\n}\n\ncontract Fails is Test {\n    function failure() public {\n        emit log_uint(100);\n        revert();\n    }\n}\n\"#,\n    );\n\n    cmd.args([\"test\", \"-vv\"]).assert_success().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\nRan 19 tests for test/DebugLogs.t.sol:DebugLogsTest\n[PASS] test1() ([GAS])\nLogs:\n  0\n  1\n  2\n\n[PASS] test2() ([GAS])\nLogs:\n  0\n  1\n  3\n\n[PASS] testLog() ([GAS])\nLogs:\n  0\n  1\n  Error: Assertion Failed\n\n[PASS] testLogAddress() ([GAS])\nLogs:\n  0\n  1\n  0x0000000000000000000000000000000000000001\n\n[PASS] testLogBytes() ([GAS])\nLogs:\n  0\n  1\n  0x61626364\n\n[PASS] testLogBytes32() ([GAS])\nLogs:\n  0\n  1\n  0x6162636400000000000000000000000000000000000000000000000000000000\n\n[PASS] testLogInt() ([GAS])\nLogs:\n  0\n  1\n  -31337\n\n[PASS] testLogNamedAddress() ([GAS])\nLogs:\n  0\n  1\n  address: 0x0000000000000000000000000000000000000001\n\n[PASS] testLogNamedBytes() ([GAS])\nLogs:\n  0\n  1\n  abcd: 0x61626364\n\n[PASS] testLogNamedBytes32() ([GAS])\nLogs:\n  0\n  1\n  abcd: 0x6162636400000000000000000000000000000000000000000000000000000000\n\n[PASS] testLogNamedDecimalInt() ([GAS])\nLogs:\n  0\n  1\n  amount: -0.000000000000031337\n\n[PASS] testLogNamedDecimalUint() ([GAS])\nLogs:\n  0\n  1\n  amount: 1.000000000000000000\n\n[PASS] testLogNamedInt() ([GAS])\nLogs:\n  0\n  1\n  amount: -31337\n\n[PASS] testLogNamedString() ([GAS])\nLogs:\n  0\n  1\n  key: val\n\n[PASS] testLogNamedUint() ([GAS])\nLogs:\n  0\n  1\n  amount: 1000000000000000000\n\n[PASS] testLogString() ([GAS])\nLogs:\n  0\n  1\n  here\n\n[PASS] testLogs() ([GAS])\nLogs:\n  0\n  1\n  0x61626364\n\n[PASS] testRevertIfWithRequire() ([GAS])\nLogs:\n  0\n  1\n  5\n\n[PASS] testRevertIfWithRevert() ([GAS])\nLogs:\n  0\n  1\n  4\n  100\n\nSuite result: ok. 19 passed; 0 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 19 tests passed, 0 failed, 0 skipped (19 total tests)\n\n\"#]]);\n});\n\nforgetest_init!(hardhat_logs, |prj, cmd| {\n    prj.add_test(\n        \"HardhatLogs.t.sol\",\n        r#\"\nimport \"forge-std/console.sol\";\n\ncontract HardhatLogsTest {\n    constructor() {\n        console.log(\"constructor\");\n    }\n\n    string testStr;\n    int256 testInt;\n    uint256 testUint;\n    bool testBool;\n    address testAddr;\n    bytes testBytes;\n\n    function setUp() public {\n        testStr = \"test\";\n        testInt = -31337;\n        testUint = 1;\n        testBool = false;\n        testAddr = 0x0000000000000000000000000000000000000001;\n        testBytes = \"a\";\n    }\n\n    function testInts() public view {\n        console.log(uint256(0));\n        console.log(uint256(1));\n        console.log(uint256(2));\n        console.log(uint256(3));\n    }\n\n    function testStrings() public view {\n        console.log(\"testStrings\");\n    }\n\n    function testMisc() public view {\n        console.log(\"testMisc\", address(1));\n        console.log(\"testMisc\", uint256(42));\n    }\n\n    function testConsoleLog() public view {\n        console.log(testStr);\n    }\n\n    function testLogInt() public view {\n        console.logInt(testInt);\n    }\n\n    function testLogUint() public view {\n        console.logUint(testUint);\n    }\n\n    function testLogString() public view {\n        console.logString(testStr);\n    }\n\n    function testLogBool() public view {\n        console.logBool(testBool);\n    }\n\n    function testLogAddress() public view {\n        console.logAddress(testAddr);\n    }\n\n    function testLogBytes() public view {\n        console.logBytes(testBytes);\n    }\n\n    function testLogBytes1() public view {\n        console.logBytes1(bytes1(testBytes));\n    }\n\n    function testLogBytes2() public view {\n        console.logBytes2(bytes2(testBytes));\n    }\n\n    function testLogBytes3() public view {\n        console.logBytes3(bytes3(testBytes));\n    }\n\n    function testLogBytes4() public view {\n        console.logBytes4(bytes4(testBytes));\n    }\n\n    function testLogBytes5() public view {\n        console.logBytes5(bytes5(testBytes));\n    }\n\n    function testLogBytes6() public view {\n        console.logBytes6(bytes6(testBytes));\n    }\n\n    function testLogBytes7() public view {\n        console.logBytes7(bytes7(testBytes));\n    }\n\n    function testLogBytes8() public view {\n        console.logBytes8(bytes8(testBytes));\n    }\n\n    function testLogBytes9() public view {\n        console.logBytes9(bytes9(testBytes));\n    }\n\n    function testLogBytes10() public view {\n        console.logBytes10(bytes10(testBytes));\n    }\n\n    function testLogBytes11() public view {\n        console.logBytes11(bytes11(testBytes));\n    }\n\n    function testLogBytes12() public view {\n        console.logBytes12(bytes12(testBytes));\n    }\n\n    function testLogBytes13() public view {\n        console.logBytes13(bytes13(testBytes));\n    }\n\n    function testLogBytes14() public view {\n        console.logBytes14(bytes14(testBytes));\n    }\n\n    function testLogBytes15() public view {\n        console.logBytes15(bytes15(testBytes));\n    }\n\n    function testLogBytes16() public view {\n        console.logBytes16(bytes16(testBytes));\n    }\n\n    function testLogBytes17() public view {\n        console.logBytes17(bytes17(testBytes));\n    }\n\n    function testLogBytes18() public view {\n        console.logBytes18(bytes18(testBytes));\n    }\n\n    function testLogBytes19() public view {\n        console.logBytes19(bytes19(testBytes));\n    }\n\n    function testLogBytes20() public view {\n        console.logBytes20(bytes20(testBytes));\n    }\n\n    function testLogBytes21() public view {\n        console.logBytes21(bytes21(testBytes));\n    }\n\n    function testLogBytes22() public view {\n        console.logBytes22(bytes22(testBytes));\n    }\n\n    function testLogBytes23() public view {\n        console.logBytes23(bytes23(testBytes));\n    }\n\n    function testLogBytes24() public view {\n        console.logBytes24(bytes24(testBytes));\n    }\n\n    function testLogBytes25() public view {\n        console.logBytes25(bytes25(testBytes));\n    }\n\n    function testLogBytes26() public view {\n        console.logBytes26(bytes26(testBytes));\n    }\n\n    function testLogBytes27() public view {\n        console.logBytes27(bytes27(testBytes));\n    }\n\n    function testLogBytes28() public view {\n        console.logBytes28(bytes28(testBytes));\n    }\n\n    function testLogBytes29() public view {\n        console.logBytes29(bytes29(testBytes));\n    }\n\n    function testLogBytes30() public view {\n        console.logBytes30(bytes30(testBytes));\n    }\n\n    function testLogBytes31() public view {\n        console.logBytes31(bytes31(testBytes));\n    }\n\n    function testLogBytes32() public view {\n        console.logBytes32(bytes32(testBytes));\n    }\n\n    function testConsoleLogUint() public view {\n        console.log(testUint);\n    }\n\n    function testConsoleLogString() public view {\n        console.log(testStr);\n    }\n\n    function testConsoleLogBool() public view {\n        console.log(testBool);\n    }\n\n    function testConsoleLogAddress() public view {\n        console.log(testAddr);\n    }\n\n    function testConsoleLogFormatString() public view {\n        console.log(\"formatted log str=%s\", testStr);\n    }\n\n    function testConsoleLogFormatUint() public view {\n        console.log(\"formatted log uint=%s\", testUint);\n    }\n\n    function testConsoleLogFormatAddress() public view {\n        console.log(\"formatted log addr=%s\", testAddr);\n    }\n\n    function testConsoleLogFormatMulti() public view {\n        console.log(\"formatted log str=%s uint=%d\", testStr, testUint);\n    }\n\n    function testConsoleLogFormatEscape() public view {\n        console.log(\"formatted log %% %s\", testStr);\n    }\n\n    function testConsoleLogFormatSpill() public view {\n        console.log(\"formatted log %s\", testStr, testUint);\n    }\n}\n\"#,\n    );\n\n    cmd.args([\"test\", \"-vv\"]).assert_success().stdout_eq(str![[r#\"\n...\nRan 52 tests for test/HardhatLogs.t.sol:HardhatLogsTest\n[PASS] testConsoleLog() ([GAS])\nLogs:\n  constructor\n  test\n\n[PASS] testConsoleLogAddress() ([GAS])\nLogs:\n  constructor\n  0x0000000000000000000000000000000000000001\n\n[PASS] testConsoleLogBool() ([GAS])\nLogs:\n  constructor\n  false\n\n[PASS] testConsoleLogFormatAddress() ([GAS])\nLogs:\n  constructor\n  formatted log addr=0x0000000000000000000000000000000000000001\n\n[PASS] testConsoleLogFormatEscape() ([GAS])\nLogs:\n  constructor\n  formatted log % test\n\n[PASS] testConsoleLogFormatMulti() ([GAS])\nLogs:\n  constructor\n  formatted log str=test uint=1\n\n[PASS] testConsoleLogFormatSpill() ([GAS])\nLogs:\n  constructor\n  formatted log test 1\n\n[PASS] testConsoleLogFormatString() ([GAS])\nLogs:\n  constructor\n  formatted log str=test\n\n[PASS] testConsoleLogFormatUint() ([GAS])\nLogs:\n  constructor\n  formatted log uint=1\n\n[PASS] testConsoleLogString() ([GAS])\nLogs:\n  constructor\n  test\n\n[PASS] testConsoleLogUint() ([GAS])\nLogs:\n  constructor\n  1\n\n[PASS] testInts() ([GAS])\nLogs:\n  constructor\n  0\n  1\n  2\n  3\n\n[PASS] testLogAddress() ([GAS])\nLogs:\n  constructor\n  0x0000000000000000000000000000000000000001\n\n[PASS] testLogBool() ([GAS])\nLogs:\n  constructor\n  false\n\n[PASS] testLogBytes() ([GAS])\nLogs:\n  constructor\n  0x61\n\n[PASS] testLogBytes1() ([GAS])\nLogs:\n  constructor\n  0x61\n\n[PASS] testLogBytes10() ([GAS])\nLogs:\n  constructor\n  0x61000000000000000000\n\n[PASS] testLogBytes11() ([GAS])\nLogs:\n  constructor\n  0x6100000000000000000000\n\n[PASS] testLogBytes12() ([GAS])\nLogs:\n  constructor\n  0x610000000000000000000000\n\n[PASS] testLogBytes13() ([GAS])\nLogs:\n  constructor\n  0x61000000000000000000000000\n\n[PASS] testLogBytes14() ([GAS])\nLogs:\n  constructor\n  0x6100000000000000000000000000\n\n[PASS] testLogBytes15() ([GAS])\nLogs:\n  constructor\n  0x610000000000000000000000000000\n\n[PASS] testLogBytes16() ([GAS])\nLogs:\n  constructor\n  0x61000000000000000000000000000000\n\n[PASS] testLogBytes17() ([GAS])\nLogs:\n  constructor\n  0x6100000000000000000000000000000000\n\n[PASS] testLogBytes18() ([GAS])\nLogs:\n  constructor\n  0x610000000000000000000000000000000000\n\n[PASS] testLogBytes19() ([GAS])\nLogs:\n  constructor\n  0x61000000000000000000000000000000000000\n\n[PASS] testLogBytes2() ([GAS])\nLogs:\n  constructor\n  0x6100\n\n[PASS] testLogBytes20() ([GAS])\nLogs:\n  constructor\n  0x6100000000000000000000000000000000000000\n\n[PASS] testLogBytes21() ([GAS])\nLogs:\n  constructor\n  0x610000000000000000000000000000000000000000\n\n[PASS] testLogBytes22() ([GAS])\nLogs:\n  constructor\n  0x61000000000000000000000000000000000000000000\n\n[PASS] testLogBytes23() ([GAS])\nLogs:\n  constructor\n  0x6100000000000000000000000000000000000000000000\n\n[PASS] testLogBytes24() ([GAS])\nLogs:\n  constructor\n  0x610000000000000000000000000000000000000000000000\n\n[PASS] testLogBytes25() ([GAS])\nLogs:\n  constructor\n  0x61000000000000000000000000000000000000000000000000\n\n[PASS] testLogBytes26() ([GAS])\nLogs:\n  constructor\n  0x6100000000000000000000000000000000000000000000000000\n\n[PASS] testLogBytes27() ([GAS])\nLogs:\n  constructor\n  0x610000000000000000000000000000000000000000000000000000\n\n[PASS] testLogBytes28() ([GAS])\nLogs:\n  constructor\n  0x61000000000000000000000000000000000000000000000000000000\n\n[PASS] testLogBytes29() ([GAS])\nLogs:\n  constructor\n  0x6100000000000000000000000000000000000000000000000000000000\n\n[PASS] testLogBytes3() ([GAS])\nLogs:\n  constructor\n  0x610000\n\n[PASS] testLogBytes30() ([GAS])\nLogs:\n  constructor\n  0x610000000000000000000000000000000000000000000000000000000000\n\n[PASS] testLogBytes31() ([GAS])\nLogs:\n  constructor\n  0x61000000000000000000000000000000000000000000000000000000000000\n\n[PASS] testLogBytes32() ([GAS])\nLogs:\n  constructor\n  0x6100000000000000000000000000000000000000000000000000000000000000\n\n[PASS] testLogBytes4() ([GAS])\nLogs:\n  constructor\n  0x61000000\n\n[PASS] testLogBytes5() ([GAS])\nLogs:\n  constructor\n  0x6100000000\n\n[PASS] testLogBytes6() ([GAS])\nLogs:\n  constructor\n  0x610000000000\n\n[PASS] testLogBytes7() ([GAS])\nLogs:\n  constructor\n  0x61000000000000\n\n[PASS] testLogBytes8() ([GAS])\nLogs:\n  constructor\n  0x6100000000000000\n\n[PASS] testLogBytes9() ([GAS])\nLogs:\n  constructor\n  0x610000000000000000\n\n[PASS] testLogInt() ([GAS])\nLogs:\n  constructor\n  -31337\n\n[PASS] testLogString() ([GAS])\nLogs:\n  constructor\n  test\n\n[PASS] testLogUint() ([GAS])\nLogs:\n  constructor\n  1\n\n[PASS] testMisc() ([GAS])\nLogs:\n  constructor\n  testMisc 0x0000000000000000000000000000000000000001\n  testMisc 42\n\n[PASS] testStrings() ([GAS])\nLogs:\n  constructor\n  testStrings\n\nSuite result: ok. 52 passed; 0 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 52 tests passed, 0 failed, 0 skipped (52 total tests)\n\n\"#]]);\n});\n\nforgetest_init!(test_can_run_with_live_logs_flag, |prj, cmd| {\n    prj.add_test(\n        \"Foo.t.sol\",\n        r#\"\nimport {Test, console} from \"forge-std/Test.sol\";\n\ncontract Foo is Test {\n    function setUp() pure public {\n        console.log(\"Setup\");\n    }\n\n    function test1() pure public {\n        console.log(\"Test 1\");\n    }\n}\n    \"#,\n    );\n\n    cmd.forge_fuse()\n        .args([\"test\", \"--live-logs\", \"--match-test\", \"test1\"])\n        .assert_success()\n        .stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\nSetup\nTest 1\n\nRan 1 test for test/Foo.t.sol:Foo\n[PASS] test1() ([GAS])\nSuite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests)\n\n\"#]]);\n});\n\nforgetest_init!(test_can_run_with_live_logs_config, |prj, cmd| {\n    prj.update_config(|config| {\n        config.live_logs = true;\n    });\n\n    prj.add_test(\n        \"Foo.t.sol\",\n        r#\"\nimport {Test, console} from \"forge-std/Test.sol\";\n\ncontract Foo is Test {\n    function setUp() pure public {\n        console.log(\"Setup\");\n    }\n\n    function test1() pure public {\n        console.log(\"Test 1\");\n    }\n}\n    \"#,\n    );\n\n    cmd.forge_fuse().args([\"test\", \"--match-test\", \"test1\"]).assert_success().stdout_eq(str![[\n        r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\nSetup\nTest 1\n\nRan 1 test for test/Foo.t.sol:Foo\n[PASS] test1() ([GAS])\nSuite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests)\n\n\"#\n    ]]);\n});\n\nforgetest_init!(test_can_run_with_live_logs_flag_race_condition, |prj, cmd| {\n    prj.add_test(\n        \"Foo.t.sol\",\n        r#\"\nimport {Test, console} from \"forge-std/Test.sol\";\n\ncontract Foo is Test {\n    function setUp() pure public {\n        console.log(\"Setup\");\n    }\n\n    function test1() pure public {\n        console.log(\"Test 1\");\n    }\n\n    function test2() pure public {\n        console.log(\"Test 2\");\n    }\n}\n    \"#,\n    );\n\n    // Two threads. Inconsistent printing order.\n    cmd.forge_fuse().args([\"test\", \"--live-logs\", \"--threads\", \"2\"]).assert_success().stdout_eq(\n        str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\nSetup\nTest [..]\nTest [..]\n\nRan 2 tests for test/Foo.t.sol:Foo\n[PASS] test1() ([GAS])\n[PASS] test2() ([GAS])\nSuite result: ok. 2 passed; 0 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 2 tests passed, 0 failed, 0 skipped (2 total tests)\n\n\"#]],\n    );\n\n    // Single thread. Deterministic printing order.\n\n    for _ in 0..10 {\n        cmd.forge_fuse()\n            .args([\"test\", \"--live-logs\", \"--threads\", \"1\"])\n            .assert_success()\n            .stdout_eq(str![[r#\"\nNo files changed, compilation skipped\nSetup\nTest 1\nTest 2\n\nRan 2 tests for test/Foo.t.sol:Foo\n[PASS] test1() ([GAS])\n[PASS] test2() ([GAS])\nSuite result: ok. 2 passed; 0 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 2 tests passed, 0 failed, 0 skipped (2 total tests)\n\n\"#]]);\n    }\n});\n"
  },
  {
    "path": "crates/forge/tests/cli/test_cmd/mod.rs",
    "content": "//! Contains various tests for `forge test`.\n\nuse alloy_primitives::U256;\nuse anvil::{NodeConfig, spawn};\nuse foundry_test_utils::{\n    TestCommand,\n    rpc::{self, rpc_endpoints},\n    str,\n    util::{OTHER_SOLC_VERSION, OutputExt, SOLC_VERSION},\n};\nuse similar_asserts::assert_eq;\nuse std::{io::Write, path::PathBuf, str::FromStr};\n\nmod core;\nmod fuzz;\nmod invariant;\nmod logs;\nmod repros;\nmod spec;\nmod table;\nmod trace;\n\n// Run `forge test` on `/testdata`.\nforgetest!(testdata, |_prj, cmd| {\n    let testdata =\n        PathBuf::from(env!(\"CARGO_MANIFEST_DIR\")).join(\"../../testdata\").canonicalize().unwrap();\n    cmd.current_dir(&testdata);\n\n    let mut dotenv = std::fs::File::create(testdata.join(\".env\")).unwrap();\n    for (name, endpoint) in rpc_endpoints().iter() {\n        if let Some(url) = endpoint.endpoint.as_url() {\n            let key = format!(\"RPC_{}\", name.to_uppercase());\n            // cmd.env(&key, url);\n            writeln!(dotenv, \"{key}={url}\").unwrap();\n        }\n    }\n    drop(dotenv);\n\n    let mut args = vec![\"test\"];\n    if cfg!(feature = \"isolate-by-default\") {\n        args.push(\n            \"--nmc=(LastCallGasDefaultTest|MockFunctionTest|WithSeed|StateDiff|GetStorageSlotsTest|RecordAccount)\",\n        );\n    }\n\n    let orig_assert = cmd.args(args).assert();\n    if orig_assert.get_output().status.success() {\n        return;\n    }\n    let stdout = orig_assert.get_output().stdout_lossy();\n    if let Some(i) = stdout.rfind(\"Suite result:\") {\n        test_debug!(\"--- short stdout ---\\n\\n{}\\n\\n---\", &stdout[i..]);\n    }\n\n    // Retry failed tests.\n    cmd.args([\"--rerun\"]);\n    let n = 3;\n    for i in 1..=n {\n        test_debug!(\"retrying failed tests... ({i}/{n})\");\n        let assert = cmd.assert();\n        if assert.get_output().status.success() {\n            return;\n        }\n    }\n\n    orig_assert.success();\n});\n\n// tests that test filters are handled correctly\nforgetest!(can_set_filter_values, |prj, cmd| {\n    let patt = regex::Regex::new(\"test*\").unwrap();\n    let glob = globset::Glob::from_str(\"foo/bar/baz*\").unwrap();\n\n    // explicitly set patterns\n    prj.update_config(|config| {\n        config.test_pattern = Some(patt.clone().into());\n        config.test_pattern_inverse = None;\n        config.contract_pattern = Some(patt.clone().into());\n        config.contract_pattern_inverse = None;\n        config.path_pattern = Some(glob.clone());\n        config.path_pattern_inverse = None;\n        config.coverage_pattern_inverse = None;\n    });\n\n    let config = cmd.config();\n\n    assert_eq!(config.test_pattern.unwrap().as_str(), patt.as_str());\n    assert_eq!(config.test_pattern_inverse, None);\n    assert_eq!(config.contract_pattern.unwrap().as_str(), patt.as_str());\n    assert_eq!(config.contract_pattern_inverse, None);\n    assert_eq!(config.path_pattern.unwrap(), glob);\n    assert_eq!(config.path_pattern_inverse, None);\n    assert_eq!(config.coverage_pattern_inverse, None);\n});\n\nfn dummy_test_filter(cmd: &mut TestCommand) {\n    cmd.args([\"test\", \"--match-test\", \"testA.*\", \"--no-match-test\", \"testB.*\"]);\n    cmd.args([\"--match-contract\", \"TestC.*\", \"--no-match-contract\", \"TestD.*\"]);\n    cmd.args([\"--match-path\", \"*TestE*\", \"--no-match-path\", \"*TestF*\"]);\n}\n\n// tests that a warning is displayed when there are no tests in project, regardless of filters\nforgetest!(warn_no_tests, |prj, cmd| {\n    // Must add at least one source to not fail earlier.\n    prj.add_source(\n        \"dummy\",\n        r\"\ncontract Dummy {}\n\",\n    );\n\n    cmd.arg(\"test\").assert_success().stdout_eq(str![[r#\"\n...\nNo tests found in project! Forge looks for functions that start with `test`\n\n\"#]]);\n\n    cmd.forge_fuse();\n    dummy_test_filter(&mut cmd);\n    cmd.assert_success().stdout_eq(str![[r#\"\n...\nNo tests found in project! Forge looks for functions that start with `test`\n\n\"#]]);\n});\n\n// tests that a warning is displayed if there are tests but none match a non-empty filter\nforgetest!(suggest_when_no_tests_match, |prj, cmd| {\n    prj.add_source(\n        \"TestE.t.sol\",\n        r\"\ncontract TestC {\n    function test1() public {\n    }\n}\n   \",\n    );\n\n    dummy_test_filter(&mut cmd);\n    cmd.assert_success().stderr_eq(str![[r#\"\nWarning: no tests match the provided pattern:\n\tmatch-test: `testA.*`\n\tno-match-test: `testB.*`\n\tmatch-contract: `TestC.*`\n\tno-match-contract: `TestD.*`\n\tmatch-path: `*TestE*`\n\tno-match-path: `*TestF*`\n\nDid you mean `test1`?\n\n\"#]]);\n});\n\n// tests that direct import paths are handled correctly\nforgetest!(can_fuzz_array_params, |prj, cmd| {\n    prj.insert_ds_test();\n\n    prj.add_source(\n        \"ATest.t.sol\",\n        r#\"\nimport \"./test.sol\";\ncontract ATest is DSTest {\n    function testArray(uint64[2] calldata) external {\n        assertTrue(true);\n    }\n}\n   \"#,\n    );\n\n    cmd.arg(\"test\").assert_success().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\nRan 1 test for src/ATest.t.sol:ATest\n[PASS] testArray(uint64[2]) (runs: 256, [AVG_GAS])\nSuite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests)\n\n\"#]]);\n});\n\n// tests that `bytecode_hash` will be sanitized\nforgetest!(can_test_pre_bytecode_hash, |prj, cmd| {\n    prj.insert_ds_test();\n\n    prj.add_source(\n        \"ATest.t.sol\",\n        r#\"\n// pre bytecode hash version, was introduced in 0.6.0\npragma solidity 0.5.17;\nimport \"./test.sol\";\ncontract ATest is DSTest {\n    function testArray(uint64[2] calldata) external {\n        assertTrue(true);\n    }\n}\n   \"#,\n    );\n\n    cmd.arg(\"test\").assert_success().stdout_eq(str![[r#\"\n...\nCompiler run successful!\n\nRan 1 test for src/ATest.t.sol:ATest\n[PASS] testArray(uint64[2]) (runs: 256, [AVG_GAS])\nSuite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests)\n\n\"#]]);\n});\n\n// tests that using the --match-path option only runs files matching the path\nforgetest!(can_test_with_match_path, |prj, cmd| {\n    prj.insert_ds_test();\n\n    prj.add_source(\n        \"ATest.t.sol\",\n        r#\"\nimport \"./test.sol\";\ncontract ATest is DSTest {\n    function testPass() external {\n        assertTrue(true);\n    }\n}\n   \"#,\n    );\n\n    prj.add_source(\n        \"FailTest.t.sol\",\n        r#\"\nimport \"./test.sol\";\ncontract FailTest is DSTest {\n    function testNothing() external {\n        assertTrue(false);\n    }\n}\n   \"#,\n    );\n\n    cmd.args([\"test\", \"--match-path\", \"*src/ATest.t.sol\"]).assert_success().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\nRan 1 test for src/ATest.t.sol:ATest\n[PASS] testPass() ([GAS])\nSuite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests)\n\n\"#]]);\n});\n\n// tests that using the --match-path option works with absolute paths\nforgetest!(can_test_with_match_path_absolute, |prj, cmd| {\n    prj.insert_ds_test();\n\n    prj.add_source(\n        \"ATest.t.sol\",\n        r#\"\nimport \"./test.sol\";\ncontract ATest is DSTest {\n    function testPass() external {\n        assertTrue(true);\n    }\n}\n   \"#,\n    );\n\n    prj.add_source(\n        \"FailTest.t.sol\",\n        r#\"\nimport \"./test.sol\";\ncontract FailTest is DSTest {\n    function testNothing() external {\n        assertTrue(false);\n    }\n}\n   \"#,\n    );\n\n    let test_path = prj.root().join(\"src/ATest.t.sol\");\n    let test_path = test_path.to_string_lossy();\n\n    cmd.args([\"test\", \"--match-path\", test_path.as_ref()]).assert_success().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\nRan 1 test for src/ATest.t.sol:ATest\n[PASS] testPass() ([GAS])\nSuite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests)\n\n\"#]]);\n});\n\nconst SIMPLE_CONTRACT: &str = r#\"\nimport \"./test.sol\";\nimport \"./console.sol\";\n\ncontract SimpleContract {\n    uint256 public num;\n\n    function setValues(uint256 _num) public {\n        num = _num;\n    }\n}\n\ncontract SimpleContractTest is DSTest {\n    function test() public {\n        SimpleContract c = new SimpleContract();\n        c.setValues(100);\n        console.logUint(100);\n    }\n}\n   \"#;\n\n#[cfg(not(feature = \"isolate-by-default\"))]\nforgetest!(can_run_test_with_json_output_verbose, |prj, cmd| {\n    prj.insert_ds_test();\n    prj.insert_console();\n\n    prj.add_source(\"Simple.t.sol\", SIMPLE_CONTRACT);\n\n    // Assert that with verbose output the json output includes the traces\n    cmd.args([\"test\", \"-vvvvv\", \"--json\"])\n        .assert_success()\n        .stdout_eq(file![\"../../fixtures/SimpleContractTestVerbose.json\": Json]);\n});\n\nforgetest!(can_run_test_with_json_output_non_verbose, |prj, cmd| {\n    prj.insert_ds_test();\n    prj.insert_console();\n\n    prj.add_source(\"Simple.t.sol\", SIMPLE_CONTRACT);\n\n    // Assert that without verbose output the json output does not include the traces\n    cmd.args([\"test\", \"--json\"])\n        .assert_success()\n        .stdout_eq(file![\"../../fixtures/SimpleContractTestNonVerbose.json\": Json]);\n});\n\n// tests that `forge test` will pick up tests that are stored in the `test = <path>` config value\nforgetest!(can_run_test_in_custom_test_folder, |prj, cmd| {\n    prj.insert_ds_test();\n\n    // explicitly set the test folder\n    prj.update_config(|config| config.test = \"nested/forge-tests\".into());\n\n    let config = cmd.config();\n    assert_eq!(config.test, PathBuf::from(\"nested/forge-tests\"));\n\n    prj.add_source(\n        \"nested/forge-tests/MyTest.t.sol\",\n        r#\"\nimport \"../../test.sol\";\ncontract MyTest is DSTest {\n    function testTrue() public {\n        assertTrue(true);\n    }\n}\n   \"#,\n    );\n\n    cmd.arg(\"test\").assert_success().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\nRan 1 test for src/nested/forge-tests/MyTest.t.sol:MyTest\n[PASS] testTrue() ([GAS])\nSuite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests)\n\n\"#]]);\n});\n\n// checks that forge test repeatedly produces the same output\n#[cfg(not(feature = \"isolate-by-default\"))]\nforgetest_init!(can_test_repeatedly, |prj, cmd| {\n    prj.initialize_default_contracts();\n    prj.clear();\n\n    cmd.arg(\"test\").assert_success().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\nRan 2 tests for test/Counter.t.sol:CounterTest\n[PASS] testFuzz_SetNumber(uint256) (runs: 256, [AVG_GAS])\n[PASS] test_Increment() ([GAS])\nSuite result: ok. 2 passed; 0 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 2 tests passed, 0 failed, 0 skipped (2 total tests)\n\n\"#]]);\n\n    for _ in 0..5 {\n        cmd.assert_success().stdout_eq(str![[r#\"\nNo files changed, compilation skipped\n\nRan 2 tests for test/Counter.t.sol:CounterTest\n[PASS] testFuzz_SetNumber(uint256) (runs: 256, [AVG_GAS])\n[PASS] test_Increment() ([GAS])\nSuite result: ok. 2 passed; 0 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 2 tests passed, 0 failed, 0 skipped (2 total tests)\n\n\"#]]);\n    }\n});\n\n// tests that `forge test` will run a test only once after changing the version\nforgetest!(runs_tests_exactly_once_with_changed_versions, |prj, cmd| {\n    prj.insert_ds_test();\n\n    prj.add_source(\n        \"Contract.t.sol\",\n        r#\"\npragma solidity *;\n\nimport \"./test.sol\";\n\ncontract ContractTest is DSTest {\n    function setUp() public {}\n\n    function testExample() public {\n        assertTrue(true);\n    }\n}\n   \"#,\n    );\n\n    // pin version\n    prj.update_config(|config| {\n        config.solc = Some(SOLC_VERSION.into());\n    });\n\n    cmd.arg(\"test\").assert_success().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\nRan 1 test for src/Contract.t.sol:ContractTest\n[PASS] testExample() ([GAS])\nSuite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests)\n\n\"#]]);\n\n    // pin version\n    prj.update_config(|config| {\n        config.solc = Some(OTHER_SOLC_VERSION.into());\n    });\n\n    cmd.forge_fuse().arg(\"test\").assert_success().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\nRan 1 test for src/Contract.t.sol:ContractTest\n[PASS] testExample() ([GAS])\nSuite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests)\n\n\"#]]);\n});\n\n// tests that libraries are handled correctly in multiforking mode\n#[cfg(not(feature = \"isolate-by-default\"))]\nforgetest_init!(can_use_libs_in_multi_fork, |prj, cmd| {\n    prj.add_source(\n        \"Contract.sol\",\n        r\"\nlibrary Library {\n    function f(uint256 a, uint256 b) public pure returns (uint256) {\n        return a + b;\n    }\n}\n\ncontract Contract {\n    uint256 c;\n\n    constructor() {\n        c = Library.f(1, 2);\n    }\n}\n   \",\n    );\n\n    let endpoint = rpc::next_http_archive_rpc_url();\n\n    prj.add_test(\n        \"Contract.t.sol\",\n        &r#\"\nimport \"forge-std/Test.sol\";\nimport \"src/Contract.sol\";\n\ncontract ContractTest is Test {\n    function setUp() public {\n        vm.createSelectFork(\"<url>\");\n    }\n\n    function test() public {\n        new Contract();\n    }\n}\n   \"#\n        .replace(\"<url>\", &endpoint),\n    );\n\n    cmd.arg(\"test\").assert_success().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\nRan 1 test for test/Contract.t.sol:ContractTest\n[PASS] test() ([GAS])\nSuite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests)\n\n\"#]]);\n});\n\nstatic FAILING_TEST: &str = r#\"\nimport \"forge-std/Test.sol\";\n\ncontract FailingTest is Test {\n    function testShouldFail() public {\n        assertTrue(false);\n    }\n}\n\"#;\n\nforgetest_init!(exit_code_error_on_fail_fast, |prj, cmd| {\n    prj.add_source(\"failing_test\", FAILING_TEST);\n\n    cmd.args([\"test\", \"--fail-fast\"]);\n\n    cmd.assert_empty_stderr();\n});\n\nforgetest_init!(exit_code_error_on_fail_fast_with_json, |prj, cmd| {\n    prj.add_source(\"failing_test\", FAILING_TEST);\n    cmd.args([\"test\", \"--fail-fast\", \"--json\"]);\n\n    cmd.assert_empty_stderr();\n});\n\n// Verify that --show-progress doesn't stop tests after first failure\nforgetest_init!(show_progress_runs_all_tests, |prj, cmd| {\n    prj.add_test(\n        \"MultiTest.t.sol\",\n        r#\"\nimport \"forge-std/Test.sol\";\n\ncontract MultiTest is Test {\n    function test_1_Fail() public {\n        assertTrue(false);\n    }\n\n    function test_2_Pass() public {\n        assertTrue(true);\n    }\n\n    function test_3_Pass() public {\n        assertTrue(true);\n    }\n}\n\"#,\n    );\n\n    // With --show-progress, all 3 tests should run despite first one failing\n    let output = cmd.args([\"test\", \"--show-progress\", \"-j1\"]).assert_failure();\n    let stdout = String::from_utf8_lossy(&output.get_output().stdout);\n\n    // Verify all 3 tests were executed\n    assert!(stdout.contains(\"test_1_Fail\"), \"test_1_Fail should run\");\n    assert!(stdout.contains(\"test_2_Pass\"), \"test_2_Pass should run\");\n    assert!(stdout.contains(\"test_3_Pass\"), \"test_3_Pass should run\");\n    assert!(stdout.contains(\"2 passed; 1 failed\"), \"Should show 2 passed and 1 failed\");\n});\n\n// Verify that --show-progress with --fail-fast DOES stop after first failure\nforgetest_init!(show_progress_with_fail_fast_exits_early, |prj, cmd| {\n    prj.add_test(\n        \"MultiTest.t.sol\",\n        r#\"\nimport \"forge-std/Test.sol\";\n\ncontract MultiTest is Test {\n    function test_1_Fail() public {\n        assertTrue(false);\n    }\n\n    function test_2_SlowPass() public {\n        vm.sleep(60000); // Sleep for 60 seconds to ensure fail-fast stops before this completes\n        assertTrue(true);\n    }\n\n    function test_3_SlowPass() public {\n        vm.sleep(60000); // Sleep for 60 seconds to ensure fail-fast stops before this completes\n        assertTrue(true);\n    }\n}\n\"#,\n    );\n\n    // With both --show-progress and --fail-fast, should stop after first failure\n    let output = cmd.args([\"test\", \"--show-progress\", \"--fail-fast\", \"-j1\"]).assert_failure();\n    let stdout = String::from_utf8_lossy(&output.get_output().stdout);\n\n    // Verify first test ran and failed\n    assert!(stdout.contains(\"test_1_Fail\"), \"test_1_Fail should run\");\n\n    // With -j1 (sequential execution) and fail-fast, the slow tests should not run\n    // since test_1_Fail will fail first\n    let slow_tests_count = (if stdout.contains(\"test_2_SlowPass\") { 1 } else { 0 })\n        + (if stdout.contains(\"test_3_SlowPass\") { 1 } else { 0 });\n\n    assert!(\n        slow_tests_count < 2,\n        \"With --fail-fast and sequential execution, not all slow tests should run after first failure\"\n    );\n});\n\n// https://github.com/foundry-rs/foundry/pull/6531\nforgetest_init!(fork_traces, |prj, cmd| {\n    let endpoint = rpc::next_http_archive_rpc_url();\n\n    prj.add_test(\n        \"Contract.t.sol\",\n        &r#\"\nimport {Test} from \"forge-std/Test.sol\";\n\ninterface IERC20 {\n    function name() external view returns (string memory);\n}\n\ncontract USDTCallingTest is Test {\n    function test() public {\n        vm.createSelectFork(\"<url>\");\n        IERC20(0xdAC17F958D2ee523a2206206994597C13D831ec7).name();\n    }\n}\n   \"#\n        .replace(\"<url>\", &endpoint),\n    );\n\n    cmd.args([\"test\", \"-vvvv\"]).assert_success().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\nRan 1 test for test/Contract.t.sol:USDTCallingTest\n[PASS] test() ([GAS])\nTraces:\n  [..] USDTCallingTest::test()\n    ├─ [0] VM::createSelectFork(\"[..]\")\n    │   └─ ← [Return] 0\n    ├─ [3110] 0xdAC17F958D2ee523a2206206994597C13D831ec7::name() [staticcall]\n    │   └─ ← [Return] \"Tether USD\"\n    └─ ← [Stop]\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests)\n\n\"#]]);\n});\n\n// Validates BPO1 blob gas price calculation during fork transaction replay.\n// Block 24127158 has a blob tx at index 0, target tx at index 1.\n// Forking at the target tx replays the blob tx with correct BPO1 blob base fee calculation.\nforgetest_init!(fork_tx_replay_bpo1_blob_base_fee, |prj, cmd| {\n    let endpoint = rpc::next_http_archive_rpc_url();\n\n    prj.add_test(\n        \"BlobFork.t.sol\",\n        &r#\"\nimport {Test} from \"forge-std/Test.sol\";\n\ncontract BlobForkTest is Test {\n    function test_fork_with_blob_replay() public {\n        // Fork at tx index 1 in block 24127158, which replays blob tx at index 0\n        bytes32 txHash = 0xa0f349b16e0f338ee760a9954ff5dbf2a402cff3320f3fe2c3755aee8babc335;\n        vm.createSelectFork(\"<url>\", txHash);\n        // If we get here, blob tx replay succeeded\n        assertTrue(true);\n    }\n}\n    \"#\n        .replace(\"<url>\", &endpoint),\n    );\n\n    cmd.args([\"test\", \"-vvvv\"]).assert_success();\n});\n\n// https://github.com/foundry-rs/foundry/issues/6579\nforgetest_init!(include_custom_types_in_traces, |prj, cmd| {\n    prj.add_test(\n        \"Contract.t.sol\",\n        r#\"\nimport {Test} from \"forge-std/Test.sol\";\n\nerror PoolNotInitialized();\nevent MyEvent(uint256 a);\n\ncontract CustomTypesTest is Test {\n    function testErr() public pure {\n       revert PoolNotInitialized();\n    }\n    function testEvent() public {\n       emit MyEvent(100);\n    }\n}\n   \"#,\n    );\n\n    cmd.args([\"test\", \"-vvvvv\"]).assert_failure().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\nRan 2 tests for test/Contract.t.sol:CustomTypesTest\n[FAIL: PoolNotInitialized()] testErr() ([GAS])\nTraces:\n  [247] CustomTypesTest::testErr()\n    └─ ← [Revert] PoolNotInitialized()\n\nBacktrace:\n  at CustomTypesTest.testErr (test/Contract.t.sol:[..]:[..])\n\n[PASS] testEvent() ([GAS])\nTraces:\n  [1524] CustomTypesTest::testEvent()\n    ├─ emit MyEvent(a: 100)\n    └─ ← [Stop]\n\nSuite result: FAILED. 1 passed; 1 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 1 tests passed, 1 failed, 0 skipped (2 total tests)\n\nFailing tests:\nEncountered 1 failing test in test/Contract.t.sol:CustomTypesTest\n[FAIL: PoolNotInitialized()] testErr() ([GAS])\n\nEncountered a total of 1 failing tests, 1 tests succeeded\n\nTip: Run `forge test --rerun` to retry only the 1 failed test\n\n\"#]]);\n});\n\nforgetest_init!(can_test_transient_storage_with_isolation, |prj, cmd| {\n    prj.add_test(\n        \"Contract.t.sol\",\n        r#\"\nimport {Test} from \"forge-std/Test.sol\";\n\ncontract TransientTester {\n    function locked() public view returns (bool isLocked) {\n        assembly {\n            isLocked := tload(0)\n        }\n    }\n\n    modifier lock() {\n        require(!locked(), \"locked\");\n        assembly {\n            tstore(0, 1)\n        }\n        _;\n    }\n\n    function maybeReentrant(address target, bytes memory data) public lock {\n        (bool success, bytes memory ret) = target.call(data);\n        if (!success) {\n            // forwards revert reason\n            assembly {\n                let ret_size := mload(ret)\n                revert(add(32, ret), ret_size)\n            }\n        }\n    }\n}\n\ncontract TransientTest is Test {\n    function test() public {\n        TransientTester t = new TransientTester();\n        vm.expectRevert(bytes(\"locked\"));\n        t.maybeReentrant(address(t), abi.encodeCall(TransientTester.maybeReentrant, (address(0), new bytes(0))));\n\n        t.maybeReentrant(address(0), new bytes(0));\n        assertEq(t.locked(), false);\n    }\n}\n   \"#,\n    );\n\n    cmd.args([\"test\", \"-vvvv\", \"--isolate\", \"--evm-version\", \"cancun\"]).assert_success();\n});\n\nforgetest_init!(\n    #[ignore = \"Too slow\"]\n    can_disable_block_gas_limit,\n    |prj, cmd| {\n        let endpoint = rpc::next_http_archive_rpc_url();\n\n        prj.add_test(\n            \"Contract.t.sol\",\n            &r#\"\nimport {Test} from \"forge-std/Test.sol\";\n\ncontract C is Test {}\n\ncontract GasWaster {\n    function waste() public {\n        for (uint256 i = 0; i < 100; i++) {\n            new C();\n        }\n    }\n}\n\ncontract GasLimitTest is Test {\n    function test() public {\n        vm.createSelectFork(\"<rpc>\");\n\n        GasWaster waster = new GasWaster();\n        waster.waste();\n    }\n}\n   \"#\n            .replace(\"<rpc>\", &endpoint),\n        );\n\n        cmd.args([\"test\", \"-vvvv\", \"--isolate\", \"--disable-block-gas-limit\"]).assert_success();\n    }\n);\n\nforgetest!(test_match_path, |prj, cmd| {\n    prj.add_source(\n        \"dummy\",\n        r\"\ncontract Dummy {\n    function testDummy() public {}\n}\n\",\n    );\n\n    cmd.args([\"test\", \"--match-path\", \"src/dummy.sol\"]);\n    cmd.assert_success();\n});\n\nforgetest_init!(should_not_shrink_fuzz_failure, |prj, cmd| {\n    // deterministic test so we always have 54 runs until test fails with overflow\n    prj.update_config(|config| {\n        config.fuzz.runs = 256;\n        config.fuzz.seed = Some(U256::from(100));\n    });\n\n    prj.add_test(\n        \"CounterFuzz.t.sol\",\n        r#\"\nimport {Test} from \"forge-std/Test.sol\";\n\ncontract Counter {\n    uint256 public number = 0;\n\n    function addOne(uint256 x) external pure returns (uint256) {\n        return x + 100_000_000;\n    }\n}\n\ncontract CounterTest is Test {\n    Counter public counter;\n\n    function setUp() public {\n        counter = new Counter();\n    }\n\n    function testAddOne(uint256 x) public view {\n        assertEq(counter.addOne(x), x + 100_000_000);\n    }\n}\n     \"#,\n    );\n\n    // make sure there are only 61 runs (with proptest shrinking same test results in 298 runs)\n    cmd.args([\"test\"]).assert_failure().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\nRan 1 test for test/CounterFuzz.t.sol:CounterTest\n[FAIL: panic: arithmetic underflow or overflow (0x11); counterexample: calldata=[..] args=[..]] testAddOne(uint256) (runs: [..], [AVG_GAS])\nSuite result: FAILED. 0 passed; 1 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 0 tests passed, 1 failed, 0 skipped (1 total tests)\n\nFailing tests:\nEncountered 1 failing test in test/CounterFuzz.t.sol:CounterTest\n[FAIL: panic: arithmetic underflow or overflow (0x11); counterexample: calldata=[..] args=[..]] testAddOne(uint256) (runs: [..], [AVG_GAS])\n\nEncountered a total of 1 failing tests, 0 tests succeeded\n\nTip: Run `forge test --rerun` to retry only the 1 failed test\n\n[SEED] (use `--fuzz-seed` to reproduce)\n\n\"#]]);\n});\n\nforgetest_init!(should_exit_early_on_invariant_failure, |prj, cmd| {\n    prj.add_test(\n        \"CounterInvariant.t.sol\",\n        r#\"\nimport {Test} from \"forge-std/Test.sol\";\n\ncontract Counter {\n    uint256 public number = 0;\n\n    function inc() external {\n        number += 1;\n    }\n}\n\ncontract CounterTest is Test {\n    Counter public counter;\n\n    function setUp() public {\n        counter = new Counter();\n    }\n\n    function invariant_early_exit() public view {\n        assertTrue(counter.number() == 10, \"wrong count\");\n    }\n}\n     \"#,\n    );\n\n    // make sure invariant test exit early with 0 runs\n    cmd.args([\"test\"]).assert_failure().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\nRan 1 test for test/CounterInvariant.t.sol:CounterTest\n[FAIL: failed to set up invariant testing environment: wrong count] invariant_early_exit() (runs: 0, calls: 0, reverts: 0)\nSuite result: FAILED. 0 passed; 1 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 0 tests passed, 1 failed, 0 skipped (1 total tests)\n\nFailing tests:\nEncountered 1 failing test in test/CounterInvariant.t.sol:CounterTest\n[FAIL: failed to set up invariant testing environment: wrong count] invariant_early_exit() (runs: 0, calls: 0, reverts: 0)\n\nEncountered a total of 1 failing tests, 0 tests succeeded\n\nTip: Run `forge test --rerun` to retry only the 1 failed test\n\n[SEED] (use `--fuzz-seed` to reproduce)\n\n\"#]]);\n});\n\nforgetest_init!(should_replay_failures_only, |prj, cmd| {\n    prj.add_test(\n        \"ReplayFailures.t.sol\",\n        r#\"\nimport {Test} from \"forge-std/Test.sol\";\n\ncontract ReplayFailuresTest is Test {\n    function testA() public pure {\n        require(2 > 1);\n    }\n\n    function testB() public pure {\n        require(1 > 2, \"testB failed\");\n    }\n\n    function testC() public pure {\n        require(2 > 1);\n    }\n\n    function testD() public pure {\n        require(1 > 2, \"testD failed\");\n    }\n}\n     \"#,\n    );\n\n    cmd.args([\"test\"]).assert_failure().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\nRan 4 tests for test/ReplayFailures.t.sol:ReplayFailuresTest\n[PASS] testA() ([GAS])\n[FAIL: testB failed] testB() ([GAS])\n[PASS] testC() ([GAS])\n[FAIL: testD failed] testD() ([GAS])\nSuite result: FAILED. 2 passed; 2 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 2 tests passed, 2 failed, 0 skipped (4 total tests)\n\nFailing tests:\nEncountered 2 failing tests in test/ReplayFailures.t.sol:ReplayFailuresTest\n[FAIL: testB failed] testB() ([GAS])\n[FAIL: testD failed] testD() ([GAS])\n\nEncountered a total of 2 failing tests, 2 tests succeeded\n\nTip: Run `forge test --rerun` to retry only the 2 failed tests\n\n\"#]]);\n\n    // Test failure filter should be persisted.\n    assert!(prj.root().join(\"cache/test-failures\").exists());\n\n    // Perform only the 2 failing tests from last run.\n    cmd.forge_fuse().args([\"test\", \"--rerun\"]).assert_failure().stdout_eq(str![[r#\"\nNo files changed, compilation skipped\n\nRan 2 tests for test/ReplayFailures.t.sol:ReplayFailuresTest\n[FAIL: testB failed] testB() ([GAS])\n[FAIL: testD failed] testD() ([GAS])\nSuite result: FAILED. 0 passed; 2 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 0 tests passed, 2 failed, 0 skipped (2 total tests)\n\nFailing tests:\nEncountered 2 failing tests in test/ReplayFailures.t.sol:ReplayFailuresTest\n[FAIL: testB failed] testB() ([GAS])\n[FAIL: testD failed] testD() ([GAS])\n\nEncountered a total of 2 failing tests, 0 tests succeeded\n\nTip: Run `forge test --rerun` to retry only the 2 failed tests\n\n\"#]]);\n});\n\n// <https://github.com/foundry-rs/foundry/issues/9285>\nforgetest_init!(should_not_record_setup_failures, |prj, cmd| {\n    prj.add_test(\n        \"ReplayFailures.t.sol\",\n        r#\"\nimport {Test} from \"forge-std/Test.sol\";\n\ncontract SetupFailureTest is Test {\n    function setUp() public {\n        require(2 > 1);\n    }\n\n    function testA() public pure {\n    }\n}\n     \"#,\n    );\n\n    cmd.args([\"test\"]).assert_success();\n    // Test failure filter should not be persisted if `setUp` failed.\n    assert!(!prj.root().join(\"cache/test-failures\").exists());\n});\n\n// https://github.com/foundry-rs/foundry/issues/7530\nforgetest_init!(should_show_precompile_labels, |prj, cmd| {\n    prj.add_test(\n        \"Contract.t.sol\",\n        r#\"\nimport {Test} from \"forge-std/Test.sol\";\n\ncontract PrecompileLabelsTest is Test {\n    function testPrecompileLabels() public {\n        vm.deal(address(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D), 1 ether);\n        vm.deal(address(0x000000000000000000636F6e736F6c652e6c6f67), 1 ether);\n        vm.deal(address(0x4e59b44847b379578588920cA78FbF26c0B4956C), 1 ether);\n        vm.deal(address(0x1804c8AB1F12E6bbf3894d4083f33e07309d1f38), 1 ether);\n        vm.deal(address(0x7FA9385bE102ac3EAc297483Dd6233D62b3e1496), 1 ether);\n        vm.deal(address(1), 1 ether);\n        vm.deal(address(2), 1 ether);\n        vm.deal(address(3), 1 ether);\n        vm.deal(address(4), 1 ether);\n        vm.deal(address(5), 1 ether);\n        vm.deal(address(6), 1 ether);\n        vm.deal(address(7), 1 ether);\n        vm.deal(address(8), 1 ether);\n        vm.deal(address(9), 1 ether);\n        vm.deal(address(10), 1 ether);\n    }\n}\n   \"#,\n    );\n\n    cmd.args([\"test\", \"-vvvv\"]).assert_success().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\nRan 1 test for test/Contract.t.sol:PrecompileLabelsTest\n[PASS] testPrecompileLabels() ([GAS])\nTraces:\n  [..] PrecompileLabelsTest::testPrecompileLabels()\n    ├─ [0] VM::deal(VM: [0x7109709ECfa91a80626fF3989D68f67F5b1DD12D], 1000000000000000000 [1e18])\n    │   └─ ← [Return]\n    ├─ [0] VM::deal(console: [0x000000000000000000636F6e736F6c652e6c6f67], 1000000000000000000 [1e18])\n    │   └─ ← [Return]\n    ├─ [0] VM::deal(Create2Deployer: [0x4e59b44847b379578588920cA78FbF26c0B4956C], 1000000000000000000 [1e18])\n    │   └─ ← [Return]\n    ├─ [0] VM::deal(DefaultSender: [0x1804c8AB1F12E6bbf3894d4083f33e07309d1f38], 1000000000000000000 [1e18])\n    │   └─ ← [Return]\n    ├─ [0] VM::deal(PrecompileLabelsTest: [0x7FA9385bE102ac3EAc297483Dd6233D62b3e1496], 1000000000000000000 [1e18])\n    │   └─ ← [Return]\n    ├─ [0] VM::deal(ECRecover: [0x0000000000000000000000000000000000000001], 1000000000000000000 [1e18])\n    │   └─ ← [Return]\n    ├─ [0] VM::deal(SHA-256: [0x0000000000000000000000000000000000000002], 1000000000000000000 [1e18])\n    │   └─ ← [Return]\n    ├─ [0] VM::deal(RIPEMD-160: [0x0000000000000000000000000000000000000003], 1000000000000000000 [1e18])\n    │   └─ ← [Return]\n    ├─ [0] VM::deal(Identity: [0x0000000000000000000000000000000000000004], 1000000000000000000 [1e18])\n    │   └─ ← [Return]\n    ├─ [0] VM::deal(ModExp: [0x0000000000000000000000000000000000000005], 1000000000000000000 [1e18])\n    │   └─ ← [Return]\n    ├─ [0] VM::deal(ECAdd: [0x0000000000000000000000000000000000000006], 1000000000000000000 [1e18])\n    │   └─ ← [Return]\n    ├─ [0] VM::deal(ECMul: [0x0000000000000000000000000000000000000007], 1000000000000000000 [1e18])\n    │   └─ ← [Return]\n    ├─ [0] VM::deal(ECPairing: [0x0000000000000000000000000000000000000008], 1000000000000000000 [1e18])\n    │   └─ ← [Return]\n    ├─ [0] VM::deal(Blake2F: [0x0000000000000000000000000000000000000009], 1000000000000000000 [1e18])\n    │   └─ ← [Return]\n    ├─ [0] VM::deal(PointEvaluation: [0x000000000000000000000000000000000000000A], 1000000000000000000 [1e18])\n    │   └─ ← [Return]\n    └─ ← [Stop]\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests)\n\n\"#]]);\n});\n\n// tests that `forge test` with config `show_logs: true` for fuzz tests will\n// display `console.log` info\nforgetest_init!(should_show_logs_when_fuzz_test, |prj, cmd| {\n    // run fuzz test 3 times\n    prj.update_config(|config| {\n        config.fuzz.runs = 3;\n        config.fuzz.show_logs = true;\n    });\n    let config = cmd.config();\n    assert_eq!(config.fuzz.runs, 3);\n\n    prj.add_test(\n        \"ContractFuzz.t.sol\",\n        r#\"\nimport {Test, console} from \"forge-std/Test.sol\";\n\ncontract ContractFuzz is Test {\n    function testFuzzConsoleLog(uint256 x) public pure {\n        console.log(\"inside fuzz test, x is:\", x);\n    }\n}\n    \"#,\n    );\n    cmd.args([\"test\", \"-vv\"]).assert_success().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\nRan 1 test for test/ContractFuzz.t.sol:ContractFuzz\n[PASS] testFuzzConsoleLog(uint256) (runs: 3, [AVG_GAS])\nLogs:\n  inside fuzz test, x is: [..]\n  inside fuzz test, x is: [..]\n  inside fuzz test, x is: [..]\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests)\n\n\"#]]);\n});\n\n// tests that `forge test` with inline config `show_logs = true` for fuzz tests will\n// display `console.log` info\nforgetest_init!(should_show_logs_when_fuzz_test_inline_config, |prj, cmd| {\n    // run fuzz test 3 times\n    prj.update_config(|config| {\n        config.fuzz.runs = 3;\n    });\n    let config = cmd.config();\n    assert_eq!(config.fuzz.runs, 3);\n\n    prj.add_test(\n        \"ContractFuzz.t.sol\",\n        r#\"\nimport {Test, console} from \"forge-std/Test.sol\";\n\ncontract ContractFuzz is Test {\n    /// forge-config: default.fuzz.show-logs = true\n    function testFuzzConsoleLog(uint256 x) public pure {\n        console.log(\"inside fuzz test, x is:\", x);\n    }\n}\n    \"#,\n    );\n    cmd.args([\"test\", \"-vv\"]).assert_success().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\nRan 1 test for test/ContractFuzz.t.sol:ContractFuzz\n[PASS] testFuzzConsoleLog(uint256) (runs: 3, [AVG_GAS])\nLogs:\n  inside fuzz test, x is: [..]\n  inside fuzz test, x is: [..]\n  inside fuzz test, x is: [..]\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests)\n\n\"#]]);\n});\n\n// tests that `forge test` with config `show_logs: false` for fuzz tests will\n// still display `console.log` from the last run at verbosity >= 2 (issue #11039)\nforgetest_init!(should_not_show_logs_when_fuzz_test, |prj, cmd| {\n    // run fuzz test 3 times\n    prj.update_config(|config| {\n        config.fuzz.runs = 3;\n        config.fuzz.show_logs = false;\n    });\n    let config = cmd.config();\n    assert_eq!(config.fuzz.runs, 3);\n\n    prj.add_test(\n        \"ContractFuzz.t.sol\",\n        r#\"\n        import {Test, console} from \"forge-std/Test.sol\";\n    contract ContractFuzz is Test {\n\n      function testFuzzConsoleLog(uint256 x) public pure {\n        console.log(\"inside fuzz test, x is:\", x);\n      }\n    }\n     \"#,\n    );\n    // At verbosity >= 2, logs from the last run should be shown even when show_logs is false\n    cmd.args([\"test\", \"-vv\"]).assert_success().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\nRan 1 test for test/ContractFuzz.t.sol:ContractFuzz\n[PASS] testFuzzConsoleLog(uint256) (runs: 3, [AVG_GAS])\nLogs:\n  inside fuzz test, x is: [..]\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests)\n\n\"#]]);\n});\n\n// tests that `forge test` with inline config `show_logs = false` for fuzz tests will\n// still display `console.log` from the last run at verbosity >= 2 (issue #11039)\nforgetest_init!(should_not_show_logs_when_fuzz_test_inline_config, |prj, cmd| {\n    // run fuzz test 3 times\n    prj.update_config(|config| {\n        config.fuzz.runs = 3;\n    });\n    let config = cmd.config();\n    assert_eq!(config.fuzz.runs, 3);\n\n    prj.add_test(\n        \"ContractFuzz.t.sol\",\n        r#\"\nimport {Test, console} from \"forge-std/Test.sol\";\n\ncontract ContractFuzz is Test {\n    /// forge-config: default.fuzz.show-logs = false\n    function testFuzzConsoleLog(uint256 x) public pure {\n        console.log(\"inside fuzz test, x is:\", x);\n    }\n}\n     \"#,\n    );\n    // At verbosity >= 2, logs from the last run should be shown even when show_logs is false\n    cmd.args([\"test\", \"-vv\"]).assert_success().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\nRan 1 test for test/ContractFuzz.t.sol:ContractFuzz\n[PASS] testFuzzConsoleLog(uint256) (runs: 3, [AVG_GAS])\nLogs:\n  inside fuzz test, x is: [..]\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests)\n\n\"#]]);\n});\n\n// tests internal functions trace\n#[cfg(not(feature = \"isolate-by-default\"))]\nforgetest_init!(internal_functions_trace, |prj, cmd| {\n    prj.clear();\n\n    prj.add_test(\n        \"Simple\",\n        r#\"\nimport {Test, console} from \"forge-std/Test.sol\";\n\ncontract SimpleContract {\n    uint256 public num;\n    address public addr;\n\n    function _setNum(uint256 _num) internal returns(uint256 prev) {\n        prev = num;\n        num = _num;\n    }\n\n    function _setAddr(address _addr) internal returns(address prev) {\n        prev = addr;\n        addr = _addr;\n    }\n\n    function increment() public {\n        _setNum(num + 1);\n    }\n\n    function setValues(uint256 _num, address _addr) public {\n        _setNum(_num);\n        _setAddr(_addr);\n    }\n}\n\ncontract SimpleContractTest is Test {\n    function test() public {\n        SimpleContract c = new SimpleContract();\n        c.increment();\n        c.setValues(100, address(0x123));\n    }\n}\n     \"#,\n    );\n    cmd.args([\"test\", \"-vvvv\", \"--decode-internal\"]).assert_success().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\nRan 1 test for test/Simple.sol:SimpleContractTest\n[PASS] test() ([GAS])\nTraces:\n  [..] SimpleContractTest::test()\n    ├─ [165406] → new SimpleContract@0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f\n    │   └─ ← [Return] 826 bytes of code\n    ├─ [22630] SimpleContract::increment()\n    │   ├─ [20147] SimpleContract::_setNum(1)\n    │   │   └─ ← 0\n    │   └─ ← [Stop]\n    ├─ [23204] SimpleContract::setValues(100, 0x0000000000000000000000000000000000000123)\n    │   ├─ [247] SimpleContract::_setNum(100)\n    │   │   └─ ← 1\n    │   ├─ [22336] SimpleContract::_setAddr(0x0000000000000000000000000000000000000123)\n    │   │   └─ ← 0x0000000000000000000000000000000000000000\n    │   └─ ← [Stop]\n    └─ ← [Stop]\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests)\n\n\"#]]);\n});\n\n// tests internal functions trace with memory decoding\n#[cfg(not(feature = \"isolate-by-default\"))]\nforgetest_init!(internal_functions_trace_memory, |prj, cmd| {\n    prj.clear();\n\n    prj.add_test(\n        \"Simple\",\n        r#\"\nimport {Test, console} from \"forge-std/Test.sol\";\n\ncontract SimpleContract {\n    string public str = \"initial value\";\n\n    function _setStr(string memory _str) internal returns(string memory prev) {\n        prev = str;\n        str = _str;\n    }\n\n    function setStr(string memory _str) public {\n        _setStr(_str);\n    }\n}\n\ncontract SimpleContractTest is Test {\n    function test() public {\n        SimpleContract c = new SimpleContract();\n        c.setStr(\"new value\");\n    }\n}\n     \"#,\n    );\n    cmd.args([\"test\", \"-vvvv\", \"--decode-internal\"]).assert_success().stdout_eq(str![[r#\"\n...\nTraces:\n  [..] SimpleContractTest::test()\n    ├─ [..] → new SimpleContract@0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f\n    │   └─ ← [Return] [..] bytes of code\n    ├─ [..] SimpleContract::setStr(\"new value\")\n    │   ├─ [..] SimpleContract::_setStr(\"new value\")\n    │   │   └─ ← \"initial value\"\n    │   └─ ← [Stop]\n    └─ ← [Stop]\n...\n\"#]]);\n});\n\n// tests that `forge test` with a seed produces deterministic random values for uint and addresses.\nforgetest_init!(deterministic_randomness_with_seed, |prj, cmd| {\n    prj.add_test(\n        \"DeterministicRandomnessTest.t.sol\",\n        r#\"\nimport {Test, console} from \"forge-std/Test.sol\";\n\ncontract DeterministicRandomnessTest is Test {\n\n    function testDeterministicRandomUint() public {\n        console.log(vm.randomUint());\n        console.log(vm.randomUint());\n        console.log(vm.randomUint());\n    }\n\n    function testDeterministicRandomUintRange() public {\n        uint256 min = 0;\n        uint256 max = 1000000000;\n        console.log(vm.randomUint(min, max));\n        console.log(vm.randomUint(min, max));\n        console.log(vm.randomUint(min, max));\n    }\n\n    function testDeterministicRandomAddress() public {\n        console.log(vm.randomAddress());\n        console.log(vm.randomAddress());\n        console.log(vm.randomAddress());\n    }\n}\n\"#,\n    );\n\n    // Extracts the test result section from the DeterministicRandomnessTest contract output.\n    fn extract_test_result(out: &str) -> &str {\n        let start = out\n            .find(\"for test/DeterministicRandomnessTest.t.sol:DeterministicRandomnessTest\")\n            .unwrap();\n        let end = out.find(\"Suite result: ok.\").unwrap();\n        &out[start..end]\n    }\n\n    // Run the test twice with the same seed and verify the outputs are the same.\n    let seed1 = \"0xa1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2\";\n    let out1 = cmd\n        .args([\"test\", \"--fuzz-seed\", seed1, \"-vv\"])\n        .assert_success()\n        .get_output()\n        .stdout_lossy();\n    let res1 = extract_test_result(&out1);\n\n    let out2 = cmd\n        .forge_fuse()\n        .args([\"test\", \"--fuzz-seed\", seed1, \"-vv\"])\n        .assert_success()\n        .get_output()\n        .stdout_lossy();\n    let res2 = extract_test_result(&out2);\n\n    assert_eq!(res1, res2);\n\n    // Run the test with another seed and verify the output differs.\n    let seed2 = \"0xb1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2\";\n    let out3 = cmd\n        .forge_fuse()\n        .args([\"test\", \"--fuzz-seed\", seed2, \"-vv\"])\n        .assert_success()\n        .get_output()\n        .stdout_lossy();\n    let res3 = extract_test_result(&out3);\n    assert_ne!(res3, res1);\n\n    // Run the test without a seed and verify the outputs differs once again.\n    cmd.forge_fuse();\n    let out4 = cmd.args([\"test\", \"-vv\"]).assert_success().get_output().stdout_lossy();\n    let res4 = extract_test_result(&out4);\n    assert_ne!(res4, res1);\n    assert_ne!(res4, res3);\n});\n\n// Tests that `pauseGasMetering` used at the end of test does not produce meaningless values.\n// https://github.com/foundry-rs/foundry/issues/5491\nforgetest_init!(gas_metering_pause_last_call, |prj, cmd| {\n    prj.add_test(\n        \"ATest.t.sol\",\n        r#\"\nimport {Test} from \"forge-std/Test.sol\";\n\ncontract ATest is Test {\n    function testWeirdGas1() public {\n        vm.pauseGasMetering();\n    }\n\n    function testWeirdGas2() public {\n        uint256 a = 1;\n        uint256 b = a + 1;\n        require(b == 2, \"b is not 2\");\n        vm.pauseGasMetering();\n    }\n\n    function testNormalGas() public {\n        vm.pauseGasMetering();\n        vm.resumeGasMetering();\n    }\n\n    function testWithAssembly() public {\n        vm.pauseGasMetering();\n        assembly {\n            return(0, 0)\n        }\n    }\n}\n   \"#,\n    );\n\n    cmd.args([\"test\"]).with_no_redact().assert_success().stdout_eq(str![[r#\"\n...\n[PASS] testNormalGas() (gas: 3148)\n[PASS] testWeirdGas1() (gas: 2986)\n[PASS] testWeirdGas2() (gas: 3213)\n[PASS] testWithAssembly() (gas: 3029)\n...\n\"#]]);\n});\n\n// https://github.com/foundry-rs/foundry/issues/5564\nforgetest_init!(gas_metering_expect_revert, |prj, cmd| {\n    prj.add_test(\n        \"ATest.t.sol\",\n        r#\"\nimport {Test} from \"forge-std/Test.sol\";\ncontract ATest is Test {\n    error MyError();\n    function testSelfMeteringRevert() public {\n        vm.pauseGasMetering();\n        vm.expectRevert(MyError.selector);\n        this.selfReverts();\n    }\n    function selfReverts() external {\n        vm.resumeGasMetering();\n        revert MyError();\n    }\n}\n   \"#,\n    );\n\n    cmd.args([\"test\"]).assert_success().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\nRan 1 test for test/ATest.t.sol:ATest\n[PASS] testSelfMeteringRevert() ([GAS])\nSuite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests)\n\n\"#]]);\n});\n\n// https://github.com/foundry-rs/foundry/issues/4523\nforgetest_init!(gas_metering_gasleft, |prj, cmd| {\n    prj.add_test(\n        \"ATest.t.sol\",\n        r#\"\nimport \"forge-std/Test.sol\";\n\ncontract ATest is Test {\n    mapping(uint256 => bytes32) map;\n\n    function test_GasMeter() public {\n        vm.pauseGasMetering();\n        consumeGas();\n        vm.resumeGasMetering();\n\n        consumeGas();\n    }\n\n    function test_GasLeft() public {\n        consumeGas();\n\n        uint256 start = gasleft();\n        consumeGas();\n        console.log(\"Gas cost:\", start - gasleft());\n    }\n\n    function consumeGas() private {\n        for (uint256 i = 0; i < 100; i++) {\n            map[i] = keccak256(abi.encode(i));\n        }\n    }\n}\n   \"#,\n    );\n\n    // Log and test gas cost should be similar.\n    cmd.args([\"test\", \"-vvvv\"]).with_no_redact().assert_success().stdout_eq(str![[r#\"\n...\nLogs:\n  Gas cost: 50068\n\nTraces:\n  [2303684] ATest::test_GasLeft()\n    ├─ [0] console::log(\"Gas cost:\", 50068 [5.006e4]) [staticcall]\n    │   └─ ← [Stop]\n    └─ ← [Stop]\n\n[PASS] test_GasMeter() (gas: 53097)\nTraces:\n  [53097] ATest::test_GasMeter()\n    ├─ [0] VM::pauseGasMetering()\n    │   └─ ← [Return]\n    ├─ [0] VM::resumeGasMetering()\n    │   └─ ← [Return]\n    └─ ← [Stop]\n...\n\"#]]);\n});\n\n// https://github.com/foundry-rs/foundry/issues/4370\nforgetest_init!(pause_gas_metering_with_delete, |prj, cmd| {\n    prj.add_test(\n        \"ATest.t.sol\",\n        r#\"\nimport {Test} from \"forge-std/Test.sol\";\ncontract ATest is Test {\n    uint a;\n    function test_negativeGas () public {\n        vm.pauseGasMetering();\n        a = 100;\n        vm.resumeGasMetering();\n        delete a;\n    }\n}\n   \"#,\n    );\n\n    cmd.args([\"test\"]).with_no_redact().assert_success().stdout_eq(str![[r#\"\n...\n[PASS] test_negativeGas() (gas: 96)\n...\n\"#]]);\n});\n\n// tests `pauseTracing` and `resumeTracing` functions\n#[cfg(not(feature = \"isolate-by-default\"))]\nforgetest_init!(pause_tracing, |prj, cmd| {\n    prj.insert_ds_test();\n    prj.insert_vm();\n    prj.clear();\n\n    prj.add_source(\n        \"Pause.t.sol\",\n        r#\"\nimport {Vm} from \"./Vm.sol\";\nimport {DSTest} from \"./test.sol\";\ncontract TraceGenerator is DSTest {\n    Vm vm = Vm(HEVM_ADDRESS);\n    event DummyEvent(uint256 i);\n    function call(uint256 i) public {\n        emit DummyEvent(i);\n    }\n    function generate() public {\n        for (uint256 i = 0; i < 10; i++) {\n            if (i == 3) {\n                vm.pauseTracing();\n            }\n            this.call(i);\n            if (i == 7) {\n                vm.resumeTracing();\n            }\n        }\n    }\n}\ncontract PauseTracingTest is DSTest {\n    Vm vm = Vm(HEVM_ADDRESS);\n    event DummyEvent(uint256 i);\n    function setUp() public {\n        emit DummyEvent(1);\n        vm.pauseTracing();\n        emit DummyEvent(2);\n    }\n    function test() public {\n        emit DummyEvent(3);\n        TraceGenerator t = new TraceGenerator();\n        vm.resumeTracing();\n        t.generate();\n    }\n}\n     \"#,\n    );\n    cmd.args([\"test\", \"-vvvvv\"]).assert_success().stdout_eq(str![[r#\"\n...\nTraces:\n  [7757] PauseTracingTest::setUp()\n    ├─ emit DummyEvent(i: 1)\n    ├─ [0] VM::pauseTracing() [staticcall]\n    │   └─ ← [Return]\n    └─ ← [Stop]\n\n  [449649] PauseTracingTest::test()\n    ├─ [0] VM::resumeTracing() [staticcall]\n    │   └─ ← [Return]\n    ├─ [22896] TraceGenerator::generate()\n    │   ├─ [1589] TraceGenerator::call(0)\n    │   │   ├─ emit DummyEvent(i: 0)\n    │   │   └─ ← [Stop]\n    │   ├─ [1589] TraceGenerator::call(1)\n    │   │   ├─ emit DummyEvent(i: 1)\n    │   │   └─ ← [Stop]\n    │   ├─ [1589] TraceGenerator::call(2)\n    │   │   ├─ emit DummyEvent(i: 2)\n    │   │   └─ ← [Stop]\n    │   ├─ [0] VM::pauseTracing() [staticcall]\n    │   │   └─ ← [Return]\n    │   ├─ [0] VM::resumeTracing() [staticcall]\n    │   │   └─ ← [Return]\n    │   ├─ [1589] TraceGenerator::call(8)\n    │   │   ├─ emit DummyEvent(i: 8)\n    │   │   └─ ← [Stop]\n    │   ├─ [1589] TraceGenerator::call(9)\n    │   │   ├─ emit DummyEvent(i: 9)\n    │   │   └─ ← [Stop]\n    │   └─ ← [Stop]\n    └─ ← [Stop]\n...\n\"#]]);\n});\n\nforgetest_init!(gas_metering_reset, |prj, cmd| {\n    prj.insert_ds_test();\n    prj.insert_vm();\n    prj.clear();\n\n    prj.add_source(\n        \"ATest.t.sol\",\n        r#\"\nimport {Vm} from \"./Vm.sol\";\nimport {DSTest} from \"./test.sol\";\ncontract B {\n    function a() public returns (uint256) {\n        return 100;\n    }\n}\ncontract ATest is DSTest {\n    Vm vm = Vm(HEVM_ADDRESS);\n    B b;\n    uint256 a;\n\n    function testResetGas() public {\n        vm.resetGasMetering();\n    }\n\n    function testResetGas1() public {\n        vm.resetGasMetering();\n        b = new B();\n        vm.resetGasMetering();\n    }\n\n    function testResetGas2() public {\n        b = new B();\n        b = new B();\n        vm.resetGasMetering();\n    }\n\n    function testResetGas3() public {\n        vm.resetGasMetering();\n        b = new B();\n        b = new B();\n    }\n\n    function testResetGas4() public {\n        vm.resetGasMetering();\n        b = new B();\n        vm.resetGasMetering();\n        b = new B();\n    }\n\n    function testResetGas5() public {\n        vm.resetGasMetering();\n        b = new B();\n        vm.resetGasMetering();\n        b = new B();\n        vm.resetGasMetering();\n    }\n\n    function testResetGas6() public {\n        vm.resetGasMetering();\n        b = new B();\n        b = new B();\n        _reset();\n        vm.resetGasMetering();\n    }\n\n    function testResetGas7() public {\n        vm.resetGasMetering();\n        b = new B();\n        b = new B();\n        _reset();\n    }\n\n    function testResetGas8() public {\n        this.resetExternal();\n    }\n\n    function testResetGas9() public {\n        this.resetExternal();\n        vm.resetGasMetering();\n    }\n\n    function testResetNegativeGas() public {\n        a = 100;\n        vm.resetGasMetering();\n\n        delete a;\n    }\n\n    function _reset() internal {\n        vm.resetGasMetering();\n    }\n\n    function resetExternal() external {\n        b = new B();\n        b = new B();\n        vm.resetGasMetering();\n    }\n\n    // https://github.com/foundry-rs/foundry/issues/12474\n    function testMemoryOnReset(uint8[1] memory x) public {\n        uint8[1] memory z;\n        z[0] = x[0];\n        assertEq(z[0], x[0]);\n        vm.resetGasMetering();\n        assertEq(x[0], z[0]);\n    }\n}\n     \"#,\n    );\n\n    cmd.args([\"test\"]).with_no_redact().assert_success().stdout_eq(str![[r#\"\n...\n[PASS] testResetGas() (gas: 96)\n[PASS] testResetGas1() (gas: 96)\n[PASS] testResetGas2() (gas: 96)\n[PASS] testResetGas3() (gas: [..])\n[PASS] testResetGas4() (gas: [..])\n[PASS] testResetGas5() (gas: 96)\n[PASS] testResetGas6() (gas: 96)\n[PASS] testResetGas7() (gas: 96)\n[PASS] testResetGas8() (gas: [..])\n[PASS] testResetGas9() (gas: 96)\n[PASS] testResetNegativeGas() (gas: 96)\n...\n\"#]]);\n});\n\n// https://github.com/foundry-rs/foundry/issues/8705\nforgetest_init!(test_expect_revert_decode, |prj, cmd| {\n    prj.add_test(\n        \"Counter.t.sol\",\n        r#\"\nimport {Test} from \"forge-std/Test.sol\";\ncontract Counter {\n    uint256 public number;\n    error NumberNotEven(uint256 number);\n    error RandomError();\n    function setNumber(uint256 newNumber) public {\n        if (newNumber % 2 != 0) {\n            revert NumberNotEven(newNumber);\n        }\n        number = newNumber;\n    }\n}\ncontract CounterTest is Test {\n    Counter public counter;\n    function setUp() public {\n        counter = new Counter();\n        counter.setNumber(0);\n    }\n    function test_decode() public {\n        vm.expectRevert(Counter.RandomError.selector);\n        counter.setNumber(1);\n    }\n    function test_decode_with_args() public {\n        vm.expectRevert(abi.encodePacked(Counter.NumberNotEven.selector, uint(2)));\n        counter.setNumber(1);\n    }\n}\n   \"#,\n    );\n\n    cmd.args([\"test\"]).assert_failure().stdout_eq(str![[r#\"\n...\n[FAIL: Error != expected error: NumberNotEven(1) != RandomError()] test_decode() ([GAS])\n[FAIL: Error != expected error: NumberNotEven(1) != NumberNotEven(2)] test_decode_with_args() ([GAS])\n...\n\"#]]);\n});\n\n// Tests that `expectPartialRevert` cheatcode partially matches revert data.\nforgetest_init!(test_expect_partial_revert, |prj, cmd| {\n    prj.insert_ds_test();\n    prj.insert_vm();\n    prj.clear();\n\n    prj.add_source(\n        \"Counter.t.sol\",\n        r#\"\nimport {Vm} from \"./Vm.sol\";\nimport {DSTest} from \"./test.sol\";\ncontract Counter {\n    error WrongNumber(uint256 number);\n    function count() public pure {\n        revert WrongNumber(0);\n    }\n}\ncontract CounterTest is DSTest {\n    Vm vm = Vm(HEVM_ADDRESS);\n    function testExpectPartialRevertWithSelector() public {\n        Counter counter = new Counter();\n        vm.expectPartialRevert(Counter.WrongNumber.selector);\n        counter.count();\n    }\n    function testExpectPartialRevertWith4Bytes() public {\n        Counter counter = new Counter();\n        vm.expectPartialRevert(bytes4(0x238ace70));\n        counter.count();\n    }\n    function testExpectRevert() public {\n        Counter counter = new Counter();\n        vm.expectRevert(Counter.WrongNumber.selector);\n        counter.count();\n    }\n}\n     \"#,\n    );\n\n    cmd.args([\"test\"]).assert_failure().stdout_eq(str![[r#\"\n...\n[PASS] testExpectPartialRevertWith4Bytes() ([GAS])\n[PASS] testExpectPartialRevertWithSelector() ([GAS])\n[FAIL: Error != expected error: WrongNumber(0) != custom error 0x238ace70] testExpectRevert() ([GAS])\n...\n\"#]]);\n});\n\nforgetest_init!(test_assume_no_revert, |prj, cmd| {\n    prj.insert_ds_test();\n    prj.insert_vm();\n    prj.clear();\n\n    prj.update_config(|config| {\n        config.fuzz.runs = 100;\n        config.fuzz.seed = Some(U256::from(100));\n    });\n\n    prj.add_source(\n        \"Counter.t.sol\",\n        r#\"\nimport {Vm} from \"./Vm.sol\";\nimport {DSTest} from \"./test.sol\";\ncontract CounterWithRevert {\n    error CountError();\n    error CheckError();\n\n    function count(uint256 a) public pure returns (uint256) {\n        if (a > 1000 || a < 10) {\n            revert CountError();\n        }\n        return 99999999;\n    }\n    function check(uint256 a) public pure {\n        if (a == 99999999) {\n            revert CheckError();\n        }\n    }\n    function dummy() public pure {}\n}\n\ncontract CounterRevertTest is DSTest {\n    Vm vm = Vm(HEVM_ADDRESS);\n\n    function test_assume_no_revert_pass(uint256 a) public {\n        CounterWithRevert counter = new CounterWithRevert();\n        vm.assumeNoRevert();\n        a = counter.count(a);\n        assertEq(a, 99999999);\n    }\n    function test_assume_no_revert_fail_assert(uint256 a) public {\n        CounterWithRevert counter = new CounterWithRevert();\n        vm.assumeNoRevert();\n        a = counter.count(a);\n        // Test should fail on next assertion.\n        assertEq(a, 1);\n    }\n    function test_assume_no_revert_fail_in_2nd_call(uint256 a) public {\n        CounterWithRevert counter = new CounterWithRevert();\n        vm.assumeNoRevert();\n        a = counter.count(a);\n        // Test should revert here (not in scope of `assumeNoRevert` cheatcode).\n        counter.check(a);\n        assertEq(a, 99999999);\n    }\n    function test_assume_no_revert_fail_in_3rd_call(uint256 a) public {\n        CounterWithRevert counter = new CounterWithRevert();\n        vm.assumeNoRevert();\n        a = counter.count(a);\n        // Test `assumeNoRevert` applied to non reverting call should not be available for next reverting call.\n        vm.assumeNoRevert();\n        counter.dummy();\n        // Test will revert here (not in scope of `assumeNoRevert` cheatcode).\n        counter.check(a);\n        assertEq(a, 99999999);\n    }\n}\n     \"#,\n    );\n\n    cmd.args([\"test\"]).with_no_redact().assert_failure().stdout_eq(str![[r#\"\n...\n[FAIL; counterexample: [..]] test_assume_no_revert_fail_assert(uint256) [..]\n[FAIL: CheckError(); counterexample: [..]] test_assume_no_revert_fail_in_2nd_call(uint256) [..]\n[FAIL: CheckError(); counterexample: [..]] test_assume_no_revert_fail_in_3rd_call(uint256) [..]\n[PASS] test_assume_no_revert_pass(uint256) [..]\n...\n\"#]]);\n});\n\nforgetest_init!(skip_output, |prj, cmd| {\n    prj.insert_ds_test();\n    prj.insert_vm();\n    prj.clear();\n\n    prj.add_source(\n        \"Counter.t.sol\",\n        r#\"\n        import {Vm} from \"./Vm.sol\";\n        import {DSTest} from \"./test.sol\";\n\n        contract Skips is DSTest {\n            Vm constant vm = Vm(HEVM_ADDRESS);\n\n            function test_skipUnit() public {\n                vm.skip(true);\n            }\n            function test_skipUnitReason() public {\n                vm.skip(true, \"unit\");\n            }\n\n            function test_skipFuzz(uint) public {\n                vm.skip(true);\n            }\n            function test_skipFuzzReason(uint) public {\n                vm.skip(true, \"fuzz\");\n            }\n\n            function invariant_skipInvariant() public {\n                vm.skip(true);\n            }\n            function invariant_skipInvariantReason() public {\n                vm.skip(true, \"invariant\");\n            }\n        }\n    \"#,\n    );\n\n    cmd.arg(\"test\").assert_success().stdout_eq(str![[r#\"\n...\nRan 6 tests for src/Counter.t.sol:Skips\n[SKIP] invariant_skipInvariant() (runs: 1, calls: 1, reverts: 1)\n[SKIP: invariant] invariant_skipInvariantReason() (runs: 1, calls: 1, reverts: 1)\n[SKIP] test_skipFuzz(uint256) (runs: 0, [AVG_GAS])\n[SKIP: fuzz] test_skipFuzzReason(uint256) (runs: 0, [AVG_GAS])\n[SKIP] test_skipUnit() ([GAS])\n[SKIP: unit] test_skipUnitReason() ([GAS])\nSuite result: ok. 0 passed; 0 failed; 6 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 0 tests passed, 0 failed, 6 skipped (6 total tests)\n\n\"#]]);\n});\n\nforgetest_init!(skip_setup, |prj, cmd| {\n    prj.add_test(\n        \"Counter.t.sol\",\n        r#\"\nimport \"forge-std/Test.sol\";\n\ncontract SkipCounterSetup is Test {\n\n    function setUp() public {\n        vm.skip(true, \"skip counter test\");\n    }\n\n    function test_require1() public pure {\n        require(1 > 2);\n    }\n\n    function test_require2() public pure {\n        require(1 > 2);\n    }\n\n    function test_require3() public pure {\n        require(1 > 2);\n    }\n}\n    \"#,\n    );\n\n    cmd.args([\"test\", \"--mc\", \"SkipCounterSetup\"]).assert_success().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\nRan 1 test for test/Counter.t.sol:SkipCounterSetup\n[SKIP: skipped: skip counter test] setUp() ([GAS])\nSuite result: ok. 0 passed; 0 failed; 1 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 0 tests passed, 0 failed, 1 skipped (1 total tests)\n\n\"#]]);\n});\n\nforgetest_init!(should_generate_junit_xml_report, |prj, cmd| {\n    prj.insert_ds_test();\n    prj.insert_vm();\n    prj.clear();\n\n    prj.add_source(\n        \"JunitReportTest.t.sol\",\n        r#\"\n        import {Vm} from \"./Vm.sol\";\n        import {DSTest} from \"./test.sol\";\n\n        contract AJunitReportTest is DSTest {\n            function test_junit_assert_fail() public {\n                assert(1 > 2);\n            }\n\n            function test_junit_revert_fail() public {\n                require(1 > 2, \"Revert\");\n            }\n        }\n\n        contract BJunitReportTest is DSTest {\n            Vm constant vm = Vm(HEVM_ADDRESS);\n            function test_junit_pass() public {\n                require(1 < 2, \"Revert\");\n            }\n\n            function test_junit_skip() public {\n                vm.skip(true);\n            }\n\n            function test_junit_skip_with_message() public {\n                vm.skip(true, \"skipped test\");\n            }\n\n            function test_junit_pass_fuzz(uint256 a) public {\n            }\n        }\n   \"#,\n    );\n\n    cmd.args([\"test\", \"--junit\"]).assert_failure().stdout_eq(str![[r#\"\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<testsuites name=\"Test run\" tests=\"6\" failures=\"2\" errors=\"0\" timestamp=\"[..]\" time=\"[..]\">\n    <testsuite name=\"src/JunitReportTest.t.sol:AJunitReportTest\" tests=\"2\" disabled=\"0\" errors=\"0\" failures=\"2\" time=\"[..]\">\n        <testcase name=\"test_junit_assert_fail()\" time=\"[..]\">\n            <failure message=\"panic: assertion failed (0x01)\"/>\n            <system-out>[FAIL: panic: assertion failed (0x01)] test_junit_assert_fail() ([GAS])</system-out>\n        </testcase>\n        <testcase name=\"test_junit_revert_fail()\" time=\"[..]\">\n            <failure message=\"Revert\"/>\n            <system-out>[FAIL: Revert] test_junit_revert_fail() ([GAS])</system-out>\n        </testcase>\n        <system-out>Suite result: FAILED. 0 passed; 2 failed; 0 skipped; [ELAPSED]</system-out>\n    </testsuite>\n    <testsuite name=\"src/JunitReportTest.t.sol:BJunitReportTest\" tests=\"4\" disabled=\"2\" errors=\"0\" failures=\"0\" time=\"[..]\">\n        <testcase name=\"test_junit_pass()\" time=\"[..]\">\n            <system-out>[PASS] test_junit_pass() ([GAS])</system-out>\n        </testcase>\n        <testcase name=\"test_junit_pass_fuzz(uint256)\" time=\"[..]\">\n            <system-out>[PASS] test_junit_pass_fuzz(uint256) (runs: 256, [AVG_GAS])</system-out>\n        </testcase>\n        <testcase name=\"test_junit_skip()\" time=\"[..]\">\n            <skipped/>\n            <system-out>[SKIP] test_junit_skip() ([GAS])</system-out>\n        </testcase>\n        <testcase name=\"test_junit_skip_with_message()\" time=\"[..]\">\n            <skipped message=\"skipped test\"/>\n            <system-out>[SKIP: skipped test] test_junit_skip_with_message() ([GAS])</system-out>\n        </testcase>\n        <system-out>Suite result: ok. 2 passed; 0 failed; 2 skipped; [ELAPSED]</system-out>\n    </testsuite>\n</testsuites>\n\n\n\"#]]);\n});\n\nforgetest_init!(should_generate_junit_xml_report_with_logs, |prj, cmd| {\n    prj.add_source(\n        \"JunitReportTest.t.sol\",\n        r#\"\nimport \"forge-std/Test.sol\";\ncontract JunitReportTest is Test {\n    function test_junit_with_logs() public {\n        console.log(\"Step1\");\n        console.log(\"Step2\");\n        console.log(\"Step3\");\n        assert(2 > 1);\n    }\n}\n   \"#,\n    );\n\n    cmd.args([\"test\", \"--junit\", \"-vvvv\"]).assert_success().stdout_eq(str![[r#\"\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<testsuites name=\"Test run\" tests=\"1\" failures=\"0\" errors=\"0\" timestamp=\"[..]\" time=\"[..]\">\n    <testsuite name=\"src/JunitReportTest.t.sol:JunitReportTest\" tests=\"1\" disabled=\"0\" errors=\"0\" failures=\"0\" time=\"[..]\">\n        <testcase name=\"test_junit_with_logs()\" time=\"[..]\">\n            <system-out>[PASS] test_junit_with_logs() ([GAS])/nLogs:/n  Step1/n  Step2/n  Step3/n</system-out>\n        </testcase>\n        <system-out>Suite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED]</system-out>\n    </testsuite>\n</testsuites>\n\n\n\"#]]);\n});\n\nforgetest_init!(\n    // Enable this if no cheatcodes are deprecated.\n    // #[ignore = \"no cheatcodes are deprecated\"]\n    test_deprecated_cheatcode_warning,\n    |prj, cmd| {\n        prj.add_test(\n            \"DeprecatedCheatcodeTest.t.sol\",\n            r#\"\n        import \"forge-std/Test.sol\";\n        contract DeprecatedCheatcodeTest is Test {\n            function test_deprecated_cheatcode() public view {\n                vm.keyExists('{\"a\": 123}', \".a\");\n                vm.keyExists('{\"a\": 123}', \".a\");\n            }\n        }\n\n        contract DeprecatedCheatcodeFuzzTest is Test {\n            function test_deprecated_cheatcode(uint256 a) public view {\n                vm.keyExists('{\"a\": 123}', \".a\");\n            }\n        }\n\n        contract Counter {\n            uint256 a;\n\n            function count() public {\n                a++;\n            }\n        }\n\n        contract DeprecatedCheatcodeInvariantTest is Test {\n            function setUp() public {\n                Counter counter = new Counter();\n            }\n\n            /// forge-config: default.invariant.runs = 1\n            function invariant_deprecated_cheatcode() public {\n                vm.keyExists('{\"a\": 123}', \".a\");\n            }\n        }\n   \"#,\n        );\n\n        // Tests deprecated cheatcode warning for unit tests.\n        cmd.args([\"test\", \"--mc\", \"DeprecatedCheatcodeTest\"]).assert_success().stderr_eq(str![[\n            r#\"\nWarning: the following cheatcode(s) are deprecated and will be removed in future versions:\n  keyExists(string,string): replaced by `keyExistsJson`\n\n\"#\n        ]]);\n\n        // Tests deprecated cheatcode warning for fuzz tests.\n        cmd.forge_fuse()\n            .args([\"test\", \"--mc\", \"DeprecatedCheatcodeFuzzTest\"])\n            .assert_success()\n            .stderr_eq(str![[r#\"\nWarning: the following cheatcode(s) are deprecated and will be removed in future versions:\n  keyExists(string,string): replaced by `keyExistsJson`\n\n\"#]]);\n\n        // Tests deprecated cheatcode warning for invariant tests.\n        cmd.forge_fuse()\n            .args([\"test\", \"--mc\", \"DeprecatedCheatcodeInvariantTest\"])\n            .assert_success()\n            .stderr_eq(str![[r#\"\nWarning: the following cheatcode(s) are deprecated and will be removed in future versions:\n  keyExists(string,string): replaced by `keyExistsJson`\n\n\"#]]);\n    }\n);\n\nforgetest_init!(requires_single_test, |prj, cmd| {\n    prj.initialize_default_contracts();\n    cmd.args([\"test\", \"--debug\"]).assert_failure().stderr_eq(str![[r#\"\nError: 2 tests matched your criteria, but exactly 1 test must match in order to run the debugger.\n\nUse --match-contract and --match-path to further limit the search.\n\n\"#]]);\n    cmd.forge_fuse().args([\"test\", \"--flamegraph\"]).assert_failure().stderr_eq(str![[r#\"\nError: 2 tests matched your criteria, but exactly 1 test must match in order to generate a flamegraph.\n\nUse --match-contract and --match-path to further limit the search.\n\n\"#]]);\n    cmd.forge_fuse().args([\"test\", \"--flamechart\"]).assert_failure().stderr_eq(str![[r#\"\nError: 2 tests matched your criteria, but exactly 1 test must match in order to generate a flamechart.\n\nUse --match-contract and --match-path to further limit the search.\n\n\"#]]);\n});\n\n// Test a script that calls vm.rememberKeys\nforgetest_init!(script_testing, |prj, cmd| {\n    prj\n    .add_source(\n        \"Foo\",\n        r#\"\nimport \"forge-std/Script.sol\";\n\ninterface Vm {\nfunction rememberKeys(string calldata mnemonic, string calldata derivationPath, uint32 count) external returns (address[] memory keyAddrs);\n}\n\ncontract WalletScript is Script {\nfunction run() public {\n    string memory mnemonic = \"test test test test test test test test test test test junk\";\n    string memory derivationPath = \"m/44'/60'/0'/0/\";\n    address[] memory wallets = Vm(address(vm)).rememberKeys(mnemonic, derivationPath, 3);\n    for (uint256 i = 0; i < wallets.length; i++) {\n        console.log(wallets[i]);\n    }\n}\n}\n\ncontract FooTest {\n    WalletScript public script;\n\n\n    function setUp() public {\n        script = new WalletScript();\n    }\n\n    function testWalletScript() public {\n        script.run();\n    }\n}\n\n\"#,\n    );\n\n    cmd.args([\"test\", \"--mt\", \"testWalletScript\", \"-vvv\"]).assert_success().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\nRan 1 test for src/Foo.sol:FooTest\n[PASS] testWalletScript() ([GAS])\nLogs:\n  0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266\n  0x70997970C51812dc3A010C7d01b50e0d17dc79C8\n  0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC\n...\n\"#]]);\n});\n\n// <https://github.com/foundry-rs/foundry/issues/8995>\nforgetest_init!(metadata_bytecode_traces, |prj, cmd| {\n    prj.initialize_default_contracts();\n    prj.add_source(\n        \"ParentProxy.sol\",\n        r#\"\nimport {Counter} from \"./Counter.sol\";\n\nabstract contract ParentProxy {\n    Counter impl;\n    bytes data;\n\n    constructor(Counter _implementation, bytes memory _data) {\n        impl = _implementation;\n        data = _data;\n    }\n}\n   \"#,\n    );\n    prj.add_source(\n        \"Proxy.sol\",\n        r#\"\nimport {ParentProxy} from \"./ParentProxy.sol\";\nimport {Counter} from \"./Counter.sol\";\n\ncontract Proxy is ParentProxy {\n    constructor(Counter _implementation, bytes memory _data)\n        ParentProxy(_implementation, _data)\n    {}\n}\n   \"#,\n    );\n\n    prj.add_test(\n        \"MetadataTraceTest.t.sol\",\n        r#\"\nimport {Counter} from \"src/Counter.sol\";\nimport {Proxy} from \"src/Proxy.sol\";\n\nimport {Test} from \"forge-std/Test.sol\";\n\ncontract MetadataTraceTest is Test {\n    function test_proxy_trace() public {\n        Counter counter = new Counter();\n        new Proxy(counter, \"\");\n    }\n}\n   \"#,\n    );\n\n    cmd.args([\"test\", \"--mt\", \"test_proxy_trace\", \"-vvvv\"]).assert_success().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\nRan 1 test for test/MetadataTraceTest.t.sol:MetadataTraceTest\n[PASS] test_proxy_trace() ([GAS])\nTraces:\n  [..] MetadataTraceTest::test_proxy_trace()\n    ├─ [..] → new Counter@0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f\n    │   └─ ← [Return] 481 bytes of code\n    ├─ [..] → new Proxy@0x2e234DAe75C793f67A35089C9d99245E1C58470b\n    │   └─ ← [Return] 62 bytes of code\n    └─ ← [Stop]\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests)\n\n\"#]]);\n\n    // Check consistent traces for running with no metadata.\n    cmd.forge_fuse()\n        .args([\"test\", \"--mt\", \"test_proxy_trace\", \"-vvvv\", \"--no-metadata\"])\n        .assert_success()\n        .stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\nRan 1 test for test/MetadataTraceTest.t.sol:MetadataTraceTest\n[PASS] test_proxy_trace() ([GAS])\nTraces:\n  [..] MetadataTraceTest::test_proxy_trace()\n    ├─ [..] → new Counter@0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f\n    │   └─ ← [Return] 427 bytes of code\n    ├─ [..] → new Proxy@0x2e234DAe75C793f67A35089C9d99245E1C58470b\n    │   └─ ← [Return] 8 bytes of code\n    └─ ← [Stop]\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests)\n\n\"#]]);\n});\n\n// Tests if dump of execution was created.\nforgetest!(test_debug_with_dump, |prj, cmd| {\n    prj.add_source(\n        \"dummy\",\n        r\"\ncontract Dummy {\n    function testDummy() public {}\n}\n\",\n    );\n\n    let dump_path = prj.root().join(\"dump.json\");\n\n    cmd.args([\"test\", \"--mt\", \"testDummy\", \"--debug\", \"--dump\", dump_path.to_str().unwrap()]);\n    cmd.assert_success();\n\n    assert!(dump_path.exists());\n});\n\nforgetest_init!(test_assume_no_revert_with_data, |prj, cmd| {\n    prj.update_config(|config| {\n        config.fuzz.seed = Some(U256::from(111));\n        config.fuzz.dictionary.max_fuzz_dictionary_literals = 0;\n    });\n\n    prj.add_source(\n        \"AssumeNoRevertTest.t.sol\",\n        r#\"\nimport {Test} from \"forge-std/Test.sol\";\n\ninterface Vm {\n    struct PotentialRevert {\n        address reverter;\n        bool partialMatch;\n        bytes revertData;\n    }\n    function expectRevert() external;\n    function assumeNoRevert() external pure;\n    function assumeNoRevert(PotentialRevert calldata revertData) external pure;\n    function assumeNoRevert(PotentialRevert[] calldata revertData) external pure;\n    function expectRevert(bytes4 revertData, uint64 count) external;\n    function assume(bool condition) external pure;\n}\n\ncontract ReverterB {\n    /// @notice has same error selectors as contract below to test the `reverter` param\n    error MyRevert();\n    error SpecialRevertWithData(uint256 x);\n\n    function revertIf2(uint256 x) public pure returns (bool) {\n        if (x == 2) {\n            revert MyRevert();\n        }\n        return true;\n    }\n\n    function revertWithData() public pure returns (bool) {\n        revert SpecialRevertWithData(2);\n    }\n}\n\ncontract Reverter {\n    error MyRevert();\n    error RevertWithData(uint256 x);\n    error UnusedError();\n    error ExpectedRevertCountZero();\n\n    ReverterB public immutable subReverter;\n\n    constructor() {\n        subReverter = new ReverterB();\n    }\n\n    function myFunction() public pure returns (bool) {\n        revert MyRevert();\n    }\n\n    function revertIf2(uint256 value) public pure returns (bool) {\n        if (value == 2) {\n            revert MyRevert();\n        }\n        return true;\n    }\n\n    function revertWithDataIf2(uint256 value) public pure returns (bool) {\n        if (value == 2) {\n            revert RevertWithData(2);\n        }\n        return true;\n    }\n\n    function twoPossibleReverts(uint256 x) public pure returns (bool) {\n        if (x == 2) {\n            revert MyRevert();\n        } else if (x == 3) {\n            revert RevertWithData(3);\n        }\n        return true;\n    }\n\n    function revertIf2Or3ExpectedRevertZero(uint256 x) public pure returns (bool) {\n        if (x == 2) {\n            revert ExpectedRevertCountZero();\n        } else if (x == 3) {\n            revert MyRevert();\n        }\n        return true;\n    }\n}\n\ncontract ReverterTest is Test {\n    Reverter reverter;\n    Vm _vm = Vm(VM_ADDRESS);\n\n    function setUp() public {\n        reverter = new Reverter();\n    }\n\n    /// @dev Test that `assumeNoRevert` does not reject an unanticipated error selector\n    function testAssume_wrongSelector_fails(uint256 x) public view {\n        _vm.assumeNoRevert(Vm.PotentialRevert({revertData: abi.encodeWithSelector(Reverter.UnusedError.selector), partialMatch: false, reverter: address(0)}));\n        reverter.revertIf2(x);\n    }\n\n    /// @dev Test that `assumeNoRevert` does not reject an unanticipated error with extra data\n    function testAssume_wrongData_fails(uint256 x) public view {\n        _vm.assumeNoRevert(Vm.PotentialRevert({revertData: abi.encodeWithSelector(Reverter.RevertWithData.selector, 3), partialMatch: false, reverter: address(0)}));\n        reverter.revertWithDataIf2(x);\n    }\n\n    /// @dev Test that `assumeNoRevert` correctly rejects an error selector from a different contract\n    function testAssumeWithReverter_fails(uint256 x) public view {\n        ReverterB subReverter = (reverter.subReverter());\n        _vm.assumeNoRevert(Vm.PotentialRevert({revertData: abi.encodeWithSelector(Reverter.MyRevert.selector), partialMatch: false, reverter: address(reverter)}));\n        subReverter.revertIf2(x);\n    }\n\n    /// @dev Test that `assumeNoRevert` correctly rejects one of two different error selectors when supplying a specific reverter\n    function testMultipleAssumes_OneWrong_fails(uint256 x) public view {\n        Vm.PotentialRevert[] memory revertData = new Vm.PotentialRevert[](2);\n        revertData[0] = Vm.PotentialRevert({revertData: abi.encodeWithSelector(Reverter.MyRevert.selector), partialMatch: false, reverter: address(reverter)});\n        revertData[1] = Vm.PotentialRevert({revertData: abi.encodeWithSelector(Reverter.RevertWithData.selector, 4), partialMatch: false, reverter: address(reverter)});\n        _vm.assumeNoRevert(revertData);\n        reverter.twoPossibleReverts(x);\n    }\n\n    /// @dev Test that `assumeNoRevert` assumptions are cleared after the first non-cheatcode external call\n    function testMultipleAssumesClearAfterCall_fails(uint256 x) public view {\n        _vm.assume(x != 3);\n        Vm.PotentialRevert[] memory revertData = new Vm.PotentialRevert[](2);\n        revertData[0] = Vm.PotentialRevert({revertData: abi.encodeWithSelector(Reverter.MyRevert.selector), partialMatch: false, reverter: address(0)});\n        revertData[1] = Vm.PotentialRevert({revertData: abi.encodeWithSelector(Reverter.RevertWithData.selector, 4), partialMatch: false, reverter: address(reverter)});\n        _vm.assumeNoRevert(revertData);\n        reverter.twoPossibleReverts(x);\n\n        reverter.twoPossibleReverts(2);\n    }\n\n    /// @dev Test that `assumeNoRevert` correctly rejects a generic assumeNoRevert call after any specific reason is provided\n    function testMultipleAssumes_ThrowOnGenericNoRevert_AfterSpecific_fails(bytes4 selector) public view {\n        _vm.assumeNoRevert(Vm.PotentialRevert({revertData: abi.encode(selector), partialMatch: false, reverter: address(0)}));\n        _vm.assumeNoRevert();\n        reverter.twoPossibleReverts(2);\n    }\n\n    function testAssumeThenExpectCountZeroFails(uint256 x) public {\n        _vm.assumeNoRevert(\n            Vm.PotentialRevert({\n                revertData: abi.encodeWithSelector(Reverter.MyRevert.selector),\n                partialMatch: false,\n                reverter: address(0)\n            })\n        );\n        _vm.expectRevert(Reverter.ExpectedRevertCountZero.selector, 0);\n        reverter.revertIf2Or3ExpectedRevertZero(x);\n    }\n\n    function testExpectCountZeroThenAssumeFails(uint256 x) public {\n        _vm.expectRevert(Reverter.ExpectedRevertCountZero.selector, 0);\n        _vm.assumeNoRevert(\n            Vm.PotentialRevert({\n                revertData: abi.encodeWithSelector(Reverter.MyRevert.selector),\n                partialMatch: false,\n                reverter: address(0)\n            })\n        );\n        reverter.revertIf2Or3ExpectedRevertZero(x);\n    }\n\n}\"#,\n    );\n    cmd.args([\"test\", \"--mc\", \"ReverterTest\"]).assert_failure().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\nRan 8 tests for src/AssumeNoRevertTest.t.sol:ReverterTest\n[FAIL: call reverted with 'FOUNDRY::ASSUME' when it was expected not to revert; counterexample: [..] testAssumeThenExpectCountZeroFails(uint256) (runs: [..], [AVG_GAS])\n[FAIL: MyRevert(); counterexample: calldata=[..]] testAssumeWithReverter_fails(uint256) (runs: [..], [AVG_GAS])\n[FAIL: RevertWithData(2); counterexample: [..]] testAssume_wrongData_fails(uint256) (runs: [..], [AVG_GAS])\n[FAIL: MyRevert(); counterexample: [..]] testAssume_wrongSelector_fails(uint256) (runs: [..], [AVG_GAS])\n[FAIL: call reverted with 'FOUNDRY::ASSUME' when it was expected not to revert; counterexample: [..]] testExpectCountZeroThenAssumeFails(uint256) (runs: [..], [AVG_GAS])\n[FAIL: MyRevert(); counterexample: [..]] testMultipleAssumesClearAfterCall_fails(uint256) (runs: 0, [AVG_GAS])\n[FAIL: RevertWithData(3); counterexample: [..]] testMultipleAssumes_OneWrong_fails(uint256) (runs: [..], [AVG_GAS])\n[FAIL: vm.assumeNoRevert: you must make another external call prior to calling assumeNoRevert again; counterexample: [..]] testMultipleAssumes_ThrowOnGenericNoRevert_AfterSpecific_fails(bytes4) (runs: [..], [AVG_GAS])\n...\n\n\"#]]);\n});\n\nforgetest_async!(flaky_can_get_broadcast_txs, |prj, cmd| {\n    foundry_test_utils::util::initialize(prj.root());\n\n    let (_api, handle) = spawn(NodeConfig::test().silent()).await;\n\n    prj.insert_vm();\n    prj.insert_ds_test();\n    prj.insert_console();\n\n    prj.add_source(\n        \"Counter.sol\",\n        r#\"\n        contract Counter {\n    uint256 public number;\n\n    function setNumber(uint256 newNumber) public {\n        number = newNumber;\n    }\n\n    function increment() public {\n        number++;\n    }\n}\n    \"#,\n    );\n\n    prj.add_script(\n        \"DeployCounter\",\n        r#\"\n        import \"forge-std/Script.sol\";\n        import \"src/Counter.sol\";\n\n        contract DeployCounter is Script {\n            function run() public {\n                vm.startBroadcast();\n\n                Counter counter = new Counter();\n\n                counter.increment();\n\n                counter.setNumber(10);\n\n                vm.stopBroadcast();\n            }\n        }\n    \"#,\n    );\n\n    prj.add_script(\n        \"DeployCounterWithCreate2\",\n        r#\"\n        import \"forge-std/Script.sol\";\n        import \"src/Counter.sol\";\n\n        contract DeployCounterWithCreate2 is Script {\n            function run() public {\n                vm.startBroadcast();\n\n                bytes32 salt = bytes32(uint256(1337));\n                Counter counter = new Counter{salt: salt}();\n\n                counter.increment();\n\n                counter.setNumber(20);\n\n                vm.stopBroadcast();\n            }\n        }\n    \"#,\n    );\n\n    let test = r#\"\n        import {Vm} from \"../src/Vm.sol\";\n        import {DSTest} from \"../src/test.sol\";\n        import {console} from \"../src/console.sol\";\n\n        contract GetBroadcastTest is DSTest {\n            Vm constant vm = Vm(HEVM_ADDRESS);\n\n            function test_getLatestBroadcast() external {\n                // Gets the latest create\n                Vm.BroadcastTxSummary memory broadcast = vm.getBroadcast(\n                    \"Counter\",\n                    31337,\n                    Vm.BroadcastTxType.Create\n                );\n\n                console.log(\"latest create\");\n                console.log(broadcast.blockNumber);\n\n                assertEq(broadcast.blockNumber, 1);\n\n                // Gets the latest create2\n                Vm.BroadcastTxSummary memory broadcast2 = vm.getBroadcast(\n                    \"Counter\",\n                    31337,\n                    Vm.BroadcastTxType.Create2\n                );\n\n                console.log(\"latest create2\");\n                console.log(broadcast2.blockNumber);\n                assertEq(broadcast2.blockNumber, 4);\n\n                // Gets the latest call\n                Vm.BroadcastTxSummary memory broadcast3 = vm.getBroadcast(\n                    \"Counter\",\n                    31337,\n                    Vm.BroadcastTxType.Call\n                );\n\n                console.log(\"latest call\");\n                assertEq(broadcast3.blockNumber, 6);\n            }\n\n            function test_getBroadcasts() public {\n                // Gets all calls\n                Vm.BroadcastTxSummary[] memory broadcasts = vm.getBroadcasts(\n                    \"Counter\",\n                    31337,\n                    Vm.BroadcastTxType.Call\n                );\n\n                assertEq(broadcasts.length, 4);\n            }\n\n            function test_getAllBroadcasts() public {\n                // Gets all broadcasts\n                Vm.BroadcastTxSummary[] memory broadcasts2 = vm.getBroadcasts(\n                    \"Counter\",\n                    31337\n                );\n\n                assertEq(broadcasts2.length, 6);\n            }\n\n            function test_getLatestDeployment() public {\n                address deployedAddress = vm.getDeployment(\n                    \"Counter\",\n                    31337\n                );\n\n                assertGt(uint160(deployedAddress), 0);\n            }\n\n            function test_getDeployments() public {\n                address[] memory deployments = vm.getDeployments(\n                    \"Counter\",\n                    31337\n                );\n\n                assertEq(deployments.length, 2);\n                // Verify valid addresses returned and they're different (CREATE vs CREATE2)\n                assertGt(uint160(deployments[0]), 0);\n                assertGt(uint160(deployments[1]), 0);\n                assertTrue(deployments[0] != deployments[1]);\n            }\n}\n    \"#;\n\n    prj.add_test(\"GetBroadcast\", test);\n\n    let sender = \"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266\";\n\n    cmd.args([\n        \"script\",\n        \"DeployCounter\",\n        \"--rpc-url\",\n        &handle.http_endpoint(),\n        \"--sender\",\n        sender,\n        \"--unlocked\",\n        \"--broadcast\",\n        \"--slow\",\n    ])\n    .assert_success();\n\n    cmd.forge_fuse()\n        .args([\n            \"script\",\n            \"DeployCounterWithCreate2\",\n            \"--rpc-url\",\n            &handle.http_endpoint(),\n            \"--sender\",\n            sender,\n            \"--unlocked\",\n            \"--broadcast\",\n            \"--slow\",\n        ])\n        .assert_success();\n\n    let broadcast_path = prj.root().join(\"broadcast\");\n\n    // Check if the broadcast folder exists\n    assert!(broadcast_path.exists() && broadcast_path.is_dir());\n\n    cmd.forge_fuse().args([\"test\", \"--mc\", \"GetBroadcastTest\", \"-vvv\"]).assert_success();\n});\n\n// See <https://github.com/foundry-rs/foundry/issues/9297>\nforgetest_init!(\n    #[ignore = \"RPC Service Unavailable\"]\n    test_roll_scroll_fork_with_cancun,\n    |prj, cmd| {\n        prj.add_test(\n            \"ScrollForkTest.t.sol\",\n            r#\"\n\nimport {Test} from \"forge-std/Test.sol\";\n\ncontract ScrollForkTest is Test {\n    function test_roll_scroll_fork_to_tx() public {\n        vm.createSelectFork(\"https://scroll-mainnet.chainstacklabs.com/\");\n        bytes32 targetTxHash = 0xf94774a1f69bba76892141190293ffe85dd8d9ac90a0a2e2b114b8c65764014c;\n        vm.rollFork(targetTxHash);\n    }\n}\n   \"#,\n        );\n\n        cmd.args([\"test\", \"--mt\", \"test_roll_scroll_fork_to_tx\", \"--evm-version\", \"cancun\"])\n            .assert_success();\n    }\n);\n\n// Test that only provider is included in failed fork error.\nforgetest_init!(test_display_provider_on_error, |prj, cmd| {\n    prj.add_test(\n        \"ForkTest.t.sol\",\n        r#\"\nimport {Test} from \"forge-std/Test.sol\";\n\ncontract ForkTest is Test {\n    function test_fork_err_message() public {\n        vm.createSelectFork(\"https://eth-mainnet.g.alchemy.com/v2/DUMMY_KEY\");\n    }\n}\n   \"#,\n    );\n\n    cmd.args([\"test\", \"--mt\", \"test_fork_err_message\"]).assert_failure().stdout_eq(str![[r#\"\n...\nRan 1 test for test/ForkTest.t.sol:ForkTest\n[FAIL: vm.createSelectFork: could not instantiate forked environment with provider eth-mainnet.g.alchemy.com; [..]] test_fork_err_message() ([GAS])\nSuite result: FAILED. 0 passed; 1 failed; 0 skipped; [ELAPSED]\n...\n\n\"#]]);\n});\n\n// Tests that test traces display state changes when running with verbosity.\n#[cfg(not(feature = \"isolate-by-default\"))]\nforgetest_init!(should_show_state_changes, |prj, cmd| {\n    prj.initialize_default_contracts();\n    cmd.args([\"test\", \"--mt\", \"test_Increment\", \"-vvvvv\"]).assert_success().stdout_eq(str![[r#\"\n...\nRan 1 test for test/Counter.t.sol:CounterTest\n[PASS] test_Increment() ([GAS])\nTraces:\n  [137242] CounterTest::setUp()\n    ├─ [96345] → new Counter@0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f\n    │   └─ ← [Return] 481 bytes of code\n    ├─ [2592] Counter::setNumber(0)\n    │   └─ ← [Stop]\n    └─ ← [Stop]\n\n  [28783] CounterTest::test_Increment()\n    ├─ [22418] Counter::increment()\n    │   ├─  storage changes:\n    │   │   @ 0: 0 → 1\n    │   └─ ← [Stop]\n    ├─ [424] Counter::number() [staticcall]\n    │   └─ ← [Return] 1\n    └─ ← [Stop]\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests)\n\n\"#]]);\n});\n\n// Tests that chained errors are properly displayed.\n// <https://github.com/foundry-rs/foundry/issues/9161>\nforgetest!(displays_chained_error, |prj, cmd| {\n    prj.add_test(\n        \"Foo.t.sol\",\n        r#\"\ncontract ContractTest {\n    function test_anything(uint) public {}\n}\n   \"#,\n    );\n\n    cmd.arg(\"test\").arg(\"--gas-limit=100\").assert_failure().stdout_eq(str![[r#\"\n...\nFailing tests:\nEncountered 1 failing test in test/Foo.t.sol:ContractTest\n[FAIL: EVM error; transaction validation error: call [GAS_COST] exceeds the [GAS_LIMIT]] setUp() ([GAS])\n\nEncountered a total of 1 failing tests, 0 tests succeeded\n\nTip: Run `forge test --rerun` to retry only the 1 failed test\n\n\"#]]);\n});\n\n// Tests that `start/stopAndReturn` debugTraceRecording does not panic when running with\n// verbosity > 3. <https://github.com/foundry-rs/foundry/issues/9526>\nforgetest_init!(should_not_panic_on_debug_trace_verbose, |prj, cmd| {\n    prj.initialize_default_contracts();\n    prj.add_test(\n        \"DebugTraceRecordingTest.t.sol\",\n        r#\"\nimport \"forge-std/Test.sol\";\nimport {Counter} from \"../src/Counter.sol\";\n\ncontract DebugTraceRecordingTest is Test {\n    function test_start_stop_recording() public {\n        vm.startDebugTraceRecording();\n        Counter counter = new Counter();\n        counter.increment();\n        vm.stopAndReturnDebugTraceRecording();\n    }\n}\n     \"#,\n    );\n\n    cmd.args([\"test\", \"--mt\", \"test_start_stop_recording\", \"-vvvv\"]).assert_success().stdout_eq(\n        str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\nRan 1 test for test/DebugTraceRecordingTest.t.sol:DebugTraceRecordingTest\n[PASS] test_start_stop_recording() ([GAS])\nTraces:\n  [..] DebugTraceRecordingTest::test_start_stop_recording()\n...\n    └─ ← [Stop]\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests)\n\n\"#]],\n    );\n});\n\n#[cfg(not(feature = \"isolate-by-default\"))]\nforgetest_init!(colored_traces, |prj, cmd| {\n    prj.initialize_default_contracts();\n    cmd.args([\"test\", \"--mt\", \"test_Increment\", \"--color\", \"always\", \"-vvvvv\"])\n        .assert_success()\n        .stdout_eq(file![\"../../fixtures/colored_traces.svg\": TermSvg]);\n});\n\n// Tests that traces for successful tests can be suppressed by using `-s` flag.\n// <https://github.com/foundry-rs/foundry/issues/9864>\n#[cfg(not(feature = \"isolate-by-default\"))]\nforgetest_init!(should_only_show_failed_tests_trace, |prj, cmd| {\n    prj.initialize_default_contracts();\n    prj.add_test(\n        \"SuppressTracesTest.t.sol\",\n        r#\"\nimport \"forge-std/Test.sol\";\nimport {Counter} from \"../src/Counter.sol\";\n\ncontract SuppressTracesTest is Test {\n    Counter public counter;\n\n    function setUp() public {\n        counter = new Counter();\n        counter.setNumber(0);\n    }\n\n    function test_increment_success() public {\n        console.log(\"test increment success\");\n        counter.increment();\n        assertEq(counter.number(), 1);\n    }\n\n    function test_increment_failure() public {\n        console.log(\"test increment failure\");\n        counter.increment();\n        assertEq(counter.number(), 100);\n    }\n}\n     \"#,\n    );\n\n    // Show traces and logs for failed test only.\n    cmd.args([\"test\", \"--mc\", \"SuppressTracesTest\", \"-vvvvv\", \"-s\"]).assert_failure().stdout_eq(\n        str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\nRan 2 tests for test/SuppressTracesTest.t.sol:SuppressTracesTest\n[FAIL: assertion failed: 1 != 100] test_increment_failure() ([GAS])\nLogs:\n  test increment failure\n\nTraces:\n  [137242] SuppressTracesTest::setUp()\n    ├─ [96345] → new Counter@0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f\n    │   └─ ← [Return] 481 bytes of code\n    ├─ [2592] Counter::setNumber(0)\n    │   └─ ← [Stop]\n    └─ ← [Stop]\n\n  [35200] SuppressTracesTest::test_increment_failure()\n    ├─ [0] console::log(\"test increment failure\") [staticcall]\n    │   └─ ← [Stop]\n    ├─ [22418] Counter::increment()\n    │   ├─  storage changes:\n    │   │   @ 0: 0 → 1\n    │   └─ ← [Stop]\n    ├─ [424] Counter::number() [staticcall]\n    │   └─ ← [Return] 1\n    ├─ [0] VM::assertEq(1, 100) [staticcall]\n    │   └─ ← [Revert] assertion failed: 1 != 100\n    └─ ← [Revert] assertion failed: 1 != 100\n\nBacktrace:\n  at VM.assertEq\n  at SuppressTracesTest.test_increment_failure (lib/forge-std/src/StdAssertions.sol:[..]:[..])\n\n[PASS] test_increment_success() ([GAS])\nSuite result: FAILED. 1 passed; 1 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 1 tests passed, 1 failed, 0 skipped (2 total tests)\n\nFailing tests:\nEncountered 1 failing test in test/SuppressTracesTest.t.sol:SuppressTracesTest\n[FAIL: assertion failed: 1 != 100] test_increment_failure() ([GAS])\n\nEncountered a total of 1 failing tests, 1 tests succeeded\n\nTip: Run `forge test --rerun` to retry only the 1 failed test\n\n\"#]],\n    );\n\n    // Show traces and logs for all tests.\n    cmd.forge_fuse()\n        .args([\"test\", \"--mc\", \"SuppressTracesTest\", \"-vvvv\"])\n        .assert_failure()\n        .stdout_eq(str![[r#\"\nNo files changed, compilation skipped\n\nRan 2 tests for test/SuppressTracesTest.t.sol:SuppressTracesTest\n[FAIL: assertion failed: 1 != 100] test_increment_failure() ([GAS])\nLogs:\n  test increment failure\n\nTraces:\n  [137242] SuppressTracesTest::setUp()\n    ├─ [96345] → new Counter@0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f\n    │   └─ ← [Return] 481 bytes of code\n    ├─ [2592] Counter::setNumber(0)\n    │   └─ ← [Stop]\n    └─ ← [Stop]\n\n  [35200] SuppressTracesTest::test_increment_failure()\n    ├─ [0] console::log(\"test increment failure\") [staticcall]\n    │   └─ ← [Stop]\n    ├─ [22418] Counter::increment()\n    │   └─ ← [Stop]\n    ├─ [424] Counter::number() [staticcall]\n    │   └─ ← [Return] 1\n    ├─ [0] VM::assertEq(1, 100) [staticcall]\n    │   └─ ← [Revert] assertion failed: 1 != 100\n    └─ ← [Revert] assertion failed: 1 != 100\n\nBacktrace:\n  at VM.assertEq\n  at SuppressTracesTest.test_increment_failure\n\n[PASS] test_increment_success() ([GAS])\nLogs:\n  test increment success\n\nTraces:\n  [32164] SuppressTracesTest::test_increment_success()\n    ├─ [0] console::log(\"test increment success\") [staticcall]\n    │   └─ ← [Stop]\n    ├─ [22418] Counter::increment()\n    │   └─ ← [Stop]\n    ├─ [424] Counter::number() [staticcall]\n    │   └─ ← [Return] 1\n    └─ ← [Stop]\n\nSuite result: FAILED. 1 passed; 1 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 1 tests passed, 1 failed, 0 skipped (2 total tests)\n\nFailing tests:\nEncountered 1 failing test in test/SuppressTracesTest.t.sol:SuppressTracesTest\n[FAIL: assertion failed: 1 != 100] test_increment_failure() ([GAS])\n\nEncountered a total of 1 failing tests, 1 tests succeeded\n\nTip: Run `forge test --rerun` to retry only the 1 failed test\n\n\"#]]);\n});\n\nforgetest_init!(catch_test_deployment_failure, |prj, cmd| {\n    prj.add_test(\n        \"TestDeploymentFailure.t.sol\",\n        r#\"\nimport \"forge-std/Test.sol\";\ncontract TestDeploymentFailure is Test {\n\n    constructor() {\n        require(false);\n    }\n\n    function setUp() public {\n        require(true);\n    }\n\n    function test_something() public {\n        require(1 == 1);\n    }\n}\n    \"#,\n    );\n\n    cmd.args([\"t\", \"--mt\", \"test_something\"]).assert_failure().stdout_eq(str![[r#\"\n...\nFailing tests:\nEncountered 1 failing test in test/TestDeploymentFailure.t.sol:TestDeploymentFailure\n[FAIL: EvmError: Revert] constructor() ([GAS])\n...\"#]]);\n});\n\n// <https://github.com/foundry-rs/foundry/issues/10012>\nforgetest_init!(state_diff_recording_with_revert, |prj, cmd| {\n    prj.add_test(\n        \"TestStateDiffRevertFailure.t.sol\",\n        r#\"\nimport \"forge-std/Test.sol\";\ncontract StateDiffRevertAtSameDepthTest is Test {\n    function test_something() public {\n        CounterTestA counter = new CounterTestA();\n        counter.doSomething();\n    }\n}\n\ncontract CounterTestA is Test {\n    function doSomething() public {\n        vm.startStateDiffRecording();\n        require(1 > 2);\n    }\n}\n    \"#,\n    );\n\n    cmd.args([\"t\", \"--mt\", \"test_something\"]).assert_failure();\n});\n\n// <https://github.com/foundry-rs/foundry/issues/5521>\nforgetest_init!(should_apply_pranks_per_recorded_depth, |prj, cmd| {\n    prj.add_test(\n        \"Counter.t.sol\",\n        r#\"\nimport \"forge-std/Test.sol\";\ncontract CounterTest is Test {\n    function test_stackPrank() public {\n        address player = makeAddr(\"player\");\n        SenderLogger senderLogger = new SenderLogger();\n        Contract c = new Contract();\n\n        senderLogger.log(); // Log(ContractTest, DefaultSender)\n        vm.startPrank(player, player);\n        senderLogger.log(); // Log(player, player)\n        c.f(); // vm.startPrank(player)\n        senderLogger.log(); // Log(ContractTest, player) <- ContractTest should be player\n        vm.stopPrank();\n    }\n}\n\ncontract Contract {\n    Vm public constant vm = Vm(address(bytes20(uint160(uint256(keccak256(\"hevm cheat code\"))))));\n\n    function f() public {\n        vm.startPrank(msg.sender);\n    }\n}\n\ncontract SenderLogger {\n    event Log(address, address);\n\n    function log() public {\n        emit Log(msg.sender, tx.origin);\n    }\n}\n    \"#,\n    );\n    // Emits\n    // Log(: player: [], : player: []) instead\n    // Log(: ContractTest: [], : player: [])\n    cmd.args([\"test\", \"--mt\", \"test_stackPrank\", \"-vvvv\"]).assert_success().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\nRan 1 test for test/Counter.t.sol:CounterTest\n[PASS] test_stackPrank() ([GAS])\nTraces:\n  [..] CounterTest::test_stackPrank()\n    ├─ [..] VM::addr(<pk>) [staticcall]\n    │   └─ ← [Return] player: [0x44E97aF4418b7a17AABD8090bEA0A471a366305C]\n    ├─ [..] VM::label(player: [0x44E97aF4418b7a17AABD8090bEA0A471a366305C], \"player\")\n    │   └─ ← [Return]\n    ├─ [..] → new SenderLogger@0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f\n    │   └─ ← [Return] 255 bytes of code\n    ├─ [..] → new Contract@0x2e234DAe75C793f67A35089C9d99245E1C58470b\n    │   └─ ← [Return] 542 bytes of code\n    ├─ [..] SenderLogger::log()\n    │   ├─ emit Log(: CounterTest: [0x7FA9385bE102ac3EAc297483Dd6233D62b3e1496], : DefaultSender: [0x1804c8AB1F12E6bbf3894d4083f33e07309d1f38])\n    │   └─ ← [Stop]\n    ├─ [..] VM::startPrank(player: [0x44E97aF4418b7a17AABD8090bEA0A471a366305C], player: [0x44E97aF4418b7a17AABD8090bEA0A471a366305C])\n    │   └─ ← [Return]\n    ├─ [..] SenderLogger::log()\n    │   ├─ emit Log(: player: [0x44E97aF4418b7a17AABD8090bEA0A471a366305C], : player: [0x44E97aF4418b7a17AABD8090bEA0A471a366305C])\n    │   └─ ← [Stop]\n    ├─ [..] Contract::f()\n    │   ├─ [..] VM::startPrank(player: [0x44E97aF4418b7a17AABD8090bEA0A471a366305C])\n    │   │   └─ ← [Return]\n    │   └─ ← [Stop]\n    ├─ [..] SenderLogger::log()\n    │   ├─ emit Log(: player: [0x44E97aF4418b7a17AABD8090bEA0A471a366305C], : player: [0x44E97aF4418b7a17AABD8090bEA0A471a366305C])\n    │   └─ ← [Stop]\n    ├─ [..] VM::stopPrank()\n    │   └─ ← [Return]\n    └─ ← [Stop]\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests)\n\n\"#]]);\n});\n\n// <https://github.com/foundry-rs/foundry/issues/10060>\nforgetest_init!(should_redact_pk_in_sign_delegation, |prj, cmd| {\n    prj.add_test(\n        \"Counter.t.sol\",\n        r#\"\nimport \"forge-std/Test.sol\";\ncontract CounterTest is Test {\n    function testCheckDelegation() external {\n        (address alice, uint256 key) = makeAddrAndKey(\"alice\");\n        vm.signDelegation(address(0), key);\n        vm.signAndAttachDelegation(address(0), key);\n    }\n}\n    \"#,\n    );\n\n    cmd.args([\"test\", \"--mt\", \"testCheckDelegation\", \"-vvvv\"]).assert_success().stdout_eq(str![[r#\"\n...\nRan 1 test for test/Counter.t.sol:CounterTest\n[PASS] testCheckDelegation() ([GAS])\nTraces:\n  [..] CounterTest::testCheckDelegation()\n    ├─ [0] VM::addr(<pk>) [staticcall]\n    │   └─ ← [Return] alice: [0x328809Bc894f92807417D2dAD6b7C998c1aFdac6]\n    ├─ [0] VM::label(alice: [0x328809Bc894f92807417D2dAD6b7C998c1aFdac6], \"alice\")\n    │   └─ ← [Return]\n    ├─ [0] VM::signDelegation(0x0000000000000000000000000000000000000000, \"<pk>\")\n    │   └─ ← [Return] (0, 0x3d6ad67cc3dc94101a049f85f96937513a05485ae0f8b27545d25c4f71b12cf9, 0x3c0f2d62834f59d6ef0209e8a935f80a891a236eb18ac0e3700dd8f7ac8ae279, 0, 0x0000000000000000000000000000000000000000)\n    ├─ [0] VM::signAndAttachDelegation(0x0000000000000000000000000000000000000000, \"<pk>\")\n    │   └─ ← [Return] (0, 0x3d6ad67cc3dc94101a049f85f96937513a05485ae0f8b27545d25c4f71b12cf9, 0x3c0f2d62834f59d6ef0209e8a935f80a891a236eb18ac0e3700dd8f7ac8ae279, 0, 0x0000000000000000000000000000000000000000)\n    └─ ← [Stop]\n...\n\n\"#]]);\n});\n\n// <https://github.com/foundry-rs/foundry/issues/10068>\nforgetest_init!(flaky_can_upload_selectors_with_path, |prj, cmd| {\n    prj.initialize_default_contracts();\n    prj.add_source(\n        \"CounterV1.sol\",\n        r#\"\ncontract Counter {\n    uint256 public number;\n\n    function setNumberV1(uint256 newNumber) public {\n        number = newNumber;\n    }\n\n    function incrementV1() public {\n        number++;\n    }\n}\n    \"#,\n    );\n\n    prj.add_source(\n        \"CounterV2.sol\",\n        r#\"\ncontract CounterV2 {\n    uint256 public number;\n\n    function setNumberV2(uint256 newNumber) public {\n        number = newNumber;\n    }\n\n    function incrementV2() public {\n        number++;\n    }\n}\n    \"#,\n    );\n\n    // Upload Counter without path fails as there are multiple contracts with same name.\n    cmd.args([\"selectors\", \"upload\", \"Counter\"]).assert_failure().stderr_eq(str![[r#\"\n...\nError: Multiple contracts found with the name `Counter`\n...\n\n\"#]]);\n\n    // Upload without contract name should fail.\n    cmd.forge_fuse().args([\"selectors\", \"upload\", \"src/Counter.sol\"]).assert_failure().stderr_eq(\n        str![[r#\"\n...\nError: No contract name provided.\n...\n\n\"#]],\n    );\n\n    // Upload single CounterV2.\n    cmd.forge_fuse().args([\"selectors\", \"upload\", \"CounterV2\"]).assert_success().stdout_eq(str![[\n        r#\"\n...\nUploading selectors for CounterV2...\n...\nSelectors successfully uploaded to OpenChain\n...\n\n\"#\n    ]]);\n\n    // Upload CounterV1 with path.\n    cmd.forge_fuse()\n        .args([\"selectors\", \"upload\", \"src/CounterV1.sol:Counter\"])\n        .assert_success()\n        .stdout_eq(str![[r#\"\n...\nUploading selectors for Counter...\n...\nSelectors successfully uploaded to OpenChain\n...\n\n\"#]]);\n\n    // Upload Counter with path.\n    cmd.forge_fuse()\n        .args([\"selectors\", \"upload\", \"src/Counter.sol:Counter\"])\n        .assert_success()\n        .stdout_eq(str![[r#\"\n...\nUploading selectors for Counter...\n...\nSelectors successfully uploaded to OpenChain\n...\n\n\"#]]);\n});\n\nforgetest_init!(selectors_list_cmd, |prj, cmd| {\n    prj.add_source(\n        \"Counter.sol\",\n        r\"\ncontract Counter {\n    uint256 public number;\n    event Incremented(uint256 newNumber);\n    error IncrementError();\n\n    function setNumber(uint256 newNumber) public {\n        number = newNumber;\n    }\n\n    function increment() public {\n        number++;\n    }\n}\n   \",\n    );\n\n    prj.add_source(\n        \"CounterV2.sol\",\n        r\"\ncontract CounterV2 {\n    uint256 public number;\n\n    function setNumberV2(uint256 newNumber) public {\n        number = newNumber;\n    }\n\n    function incrementV2() public {\n        number++;\n    }\n}\n   \",\n    );\n\n    cmd.args([\"selectors\", \"list\"]).assert_success().stdout_eq(str![[r#\"\nListing selectors for contracts in the project...\nCounter\n\n╭----------+----------------------+--------------------------------------------------------------------╮\n| Type     | Signature            | Selector                                                           |\n+======================================================================================================+\n| Function | increment()          | 0xd09de08a                                                         |\n|----------+----------------------+--------------------------------------------------------------------|\n| Function | number()             | 0x8381f58a                                                         |\n|----------+----------------------+--------------------------------------------------------------------|\n| Function | setNumber(uint256)   | 0x3fb5c1cb                                                         |\n|----------+----------------------+--------------------------------------------------------------------|\n| Event    | Incremented(uint256) | 0x20d8a6f5a693f9d1d627a598e8820f7a55ee74c183aa8f1a30e8d4e8dd9a8d84 |\n|----------+----------------------+--------------------------------------------------------------------|\n| Error    | IncrementError()     | 0x46544c04                                                         |\n╰----------+----------------------+--------------------------------------------------------------------╯\n\nCounterV2\n\n╭----------+----------------------+------------╮\n| Type     | Signature            | Selector   |\n+==============================================+\n| Function | incrementV2()        | 0x49365a69 |\n|----------+----------------------+------------|\n| Function | number()             | 0x8381f58a |\n|----------+----------------------+------------|\n| Function | setNumberV2(uint256) | 0xb525b68c |\n╰----------+----------------------+------------╯\n\n\"#]]);\n\n    cmd.forge_fuse()\n        .args([\"selectors\", \"list\", \"--no-group\"])\n        .assert_success()\n        .stdout_eq(str![[r#\"\nListing selectors for contracts in the project...\n\n╭----------+----------------------+--------------------------------------------------------------------+-----------╮\n| Type     | Signature            | Selector                                                           | Contract  |\n+==================================================================================================================+\n| Function | increment()          | 0xd09de08a                                                         | Counter   |\n|----------+----------------------+--------------------------------------------------------------------+-----------|\n| Function | number()             | 0x8381f58a                                                         | Counter   |\n|----------+----------------------+--------------------------------------------------------------------+-----------|\n| Function | setNumber(uint256)   | 0x3fb5c1cb                                                         | Counter   |\n|----------+----------------------+--------------------------------------------------------------------+-----------|\n| Event    | Incremented(uint256) | 0x20d8a6f5a693f9d1d627a598e8820f7a55ee74c183aa8f1a30e8d4e8dd9a8d84 | Counter   |\n|----------+----------------------+--------------------------------------------------------------------+-----------|\n| Error    | IncrementError()     | 0x46544c04                                                         | Counter   |\n|----------+----------------------+--------------------------------------------------------------------+-----------|\n| Function | incrementV2()        | 0x49365a69                                                         | CounterV2 |\n|----------+----------------------+--------------------------------------------------------------------+-----------|\n| Function | number()             | 0x8381f58a                                                         | CounterV2 |\n|----------+----------------------+--------------------------------------------------------------------+-----------|\n| Function | setNumberV2(uint256) | 0xb525b68c                                                         | CounterV2 |\n╰----------+----------------------+--------------------------------------------------------------------+-----------╯\n\n\"#]]);\n});\n\nforgetest_init!(selectors_list_cmd_md, |prj, cmd| {\n    prj.add_source(\n        \"Counter.sol\",\n        r\"\ncontract Counter {\n    uint256 public number;\n    event Incremented(uint256 newNumber);\n    error IncrementError();\n\n    function setNumber(uint256 newNumber) public {\n        number = newNumber;\n    }\n\n    function increment() public {\n        number++;\n    }\n}\n   \",\n    );\n\n    prj.add_source(\n        \"CounterV2.sol\",\n        r\"\ncontract CounterV2 {\n    uint256 public number;\n\n    function setNumberV2(uint256 newNumber) public {\n        number = newNumber;\n    }\n\n    function incrementV2() public {\n        number++;\n    }\n}\n   \",\n    );\n\n    cmd.args([\"selectors\", \"list\", \"--md\"]).assert_success().stdout_eq(str![[r#\"\nListing selectors for contracts in the project...\nCounter\n\n| Type     | Signature            | Selector                                                           |\n|----------|----------------------|--------------------------------------------------------------------|\n| Function | increment()          | 0xd09de08a                                                         |\n| Function | number()             | 0x8381f58a                                                         |\n| Function | setNumber(uint256)   | 0x3fb5c1cb                                                         |\n| Event    | Incremented(uint256) | 0x20d8a6f5a693f9d1d627a598e8820f7a55ee74c183aa8f1a30e8d4e8dd9a8d84 |\n| Error    | IncrementError()     | 0x46544c04                                                         |\n\nCounterV2\n\n| Type     | Signature            | Selector   |\n|----------|----------------------|------------|\n| Function | incrementV2()        | 0x49365a69 |\n| Function | number()             | 0x8381f58a |\n| Function | setNumberV2(uint256) | 0xb525b68c |\n\n\"#]]);\n\n    cmd.forge_fuse()\n        .args([\"selectors\", \"list\", \"--no-group\", \"--md\"])\n        .assert_success()\n        .stdout_eq(str![[r#\"\nListing selectors for contracts in the project...\n\n| Type     | Signature            | Selector                                                           | Contract  |\n|----------|----------------------|--------------------------------------------------------------------|-----------|\n| Function | increment()          | 0xd09de08a                                                         | Counter   |\n| Function | number()             | 0x8381f58a                                                         | Counter   |\n| Function | setNumber(uint256)   | 0x3fb5c1cb                                                         | Counter   |\n| Event    | Incremented(uint256) | 0x20d8a6f5a693f9d1d627a598e8820f7a55ee74c183aa8f1a30e8d4e8dd9a8d84 | Counter   |\n| Error    | IncrementError()     | 0x46544c04                                                         | Counter   |\n| Function | incrementV2()        | 0x49365a69                                                         | CounterV2 |\n| Function | number()             | 0x8381f58a                                                         | CounterV2 |\n| Function | setNumberV2(uint256) | 0xb525b68c                                                         | CounterV2 |\n\n\"#]]);\n});\n\n// tests `interceptInitcode` function\nforgetest_init!(intercept_initcode, |prj, cmd| {\n    prj.insert_ds_test();\n    prj.insert_vm();\n    prj.clear();\n\n    prj.add_source(\n        \"InterceptInitcode.t.sol\",\n        r#\"\nimport {Vm} from \"./Vm.sol\";\nimport {DSTest} from \"./test.sol\";\n\ncontract SimpleContract {\n    uint256 public value;\n    constructor(uint256 _value) {\n        value = _value;\n    }\n}\n\ncontract InterceptInitcodeTest is DSTest {\n    Vm vm = Vm(HEVM_ADDRESS);\n\n    function testInterceptRegularCreate() public {\n        // Set up interception\n        vm.interceptInitcode();\n\n        // Try to create a contract - this should revert with the initcode\n        bytes memory initcode;\n        try new SimpleContract(42) {\n            assert(false);\n        } catch (bytes memory interceptedInitcode) {\n            initcode = interceptedInitcode;\n        }\n\n        // Verify the initcode contains the constructor argument\n        assertTrue(initcode.length > 0, \"initcode should not be empty\");\n\n        // The constructor argument is encoded as a 32-byte value at the end of the initcode\n        // We need to convert the last 32 bytes to uint256\n        uint256 value;\n        assembly {\n            value := mload(add(add(initcode, 0x20), sub(mload(initcode), 32)))\n        }\n        assertEq(value, 42, \"initcode should contain constructor arg\");\n    }\n\n    function testInterceptCreate2() public {\n        // Set up interception\n        vm.interceptInitcode();\n\n        // Try to create a contract with CREATE2 - this should revert with the initcode\n        bytes memory initcode;\n        try new SimpleContract(1337) {\n            assert(false);\n        } catch (bytes memory interceptedInitcode) {\n            initcode = interceptedInitcode;\n        }\n\n        // Verify the initcode contains the constructor argument\n        assertTrue(initcode.length > 0, \"initcode should not be empty\");\n\n        // The constructor argument is encoded as a 32-byte value at the end of the initcode\n        uint256 value;\n        assembly {\n            value := mload(add(add(initcode, 0x20), sub(mload(initcode), 32)))\n        }\n        assertEq(value, 1337, \"initcode should contain constructor arg\");\n    }\n\n    function testInterceptMultiple() public {\n        // First interception\n        vm.interceptInitcode();\n        bytes memory initcode1;\n        try new SimpleContract(1) {\n            assert(false);\n        } catch (bytes memory interceptedInitcode) {\n            initcode1 = interceptedInitcode;\n        }\n\n        // Second interception\n        vm.interceptInitcode();\n        bytes memory initcode2;\n        try new SimpleContract(2) {\n            assert(false);\n        } catch (bytes memory interceptedInitcode) {\n            initcode2 = interceptedInitcode;\n        }\n\n        // Verify different initcodes\n        assertTrue(initcode1.length > 0, \"first initcode should not be empty\");\n        assertTrue(initcode2.length > 0, \"second initcode should not be empty\");\n\n        // Extract constructor arguments from both initcodes\n        uint256 value1;\n        uint256 value2;\n        assembly {\n            value1 := mload(add(add(initcode1, 0x20), sub(mload(initcode1), 32)))\n            value2 := mload(add(add(initcode2, 0x20), sub(mload(initcode2), 32)))\n        }\n        assertEq(value1, 1, \"first initcode should contain first arg\");\n        assertEq(value2, 2, \"second initcode should contain second arg\");\n    }\n}\n     \"#,\n    );\n    cmd.args([\"test\", \"-vvvvv\"]).assert_success();\n});\n\n// <https://github.com/foundry-rs/foundry/issues/10296>\n// <https://github.com/foundry-rs/foundry/issues/10552>\nforgetest_init!(should_preserve_fork_state_setup, |prj, cmd| {\n    prj.add_test(\n        \"Counter.t.sol\",\n        &r#\"\nimport \"forge-std/Test.sol\";\nimport {StdChains} from \"forge-std/StdChains.sol\";\n\ncontract CounterTest is Test {\n    struct Domain {\n        StdChains.Chain chain;\n        uint256 forkId;\n    }\n\n    struct Bridge {\n        Domain source;\n        Domain destination;\n        uint256 someVal;\n    }\n\n    struct SomeStruct {\n        Domain domain;\n        Bridge[] bridges;\n    }\n\n    mapping(uint256 => SomeStruct) internal data;\n\n    function setUp() public {\n        // Temporary workaround for `https://eth.llamarpc.com/` being down\n        setChain(\"mainnet\", ChainData({\n            name: \"mainnet\",\n            rpcUrl: \"<url>\",\n            chainId: 1\n        }));\n\n        StdChains.Chain memory chain1 = getChain(\"mainnet\");\n        StdChains.Chain memory chain2 = getChain(\"base\");\n        Domain memory domain1 = Domain(chain1, vm.createFork(chain1.rpcUrl, 22253716));\n        Domain memory domain2 = Domain(chain2, vm.createFork(chain2.rpcUrl, 28839981));\n        data[1].domain = domain1;\n        data[2].domain = domain2;\n\n        vm.selectFork(domain1.forkId);\n\n        data[2].bridges.push(Bridge(domain1, domain2, 123));\n        vm.selectFork(data[2].domain.forkId);\n        vm.selectFork(data[1].domain.forkId);\n        data[2].bridges.push(Bridge(domain1, domain2, 456));\n\n        assertEq(data[2].bridges.length, 2);\n    }\n\n    function test_assert_storage() public {\n        vm.selectFork(data[2].domain.forkId);\n        assertEq(data[2].bridges.length, 2);\n    }\n\n    function test_modify_and_storage() public {\n        data[3].domain = Domain(getChain(\"base\"), vm.createFork(getChain(\"base\").rpcUrl, 28839981));\n        data[3].bridges.push(Bridge(data[1].domain, data[2].domain, 123));\n        data[3].bridges.push(Bridge(data[1].domain, data[2].domain, 456));\n\n        vm.selectFork(data[2].domain.forkId);\n        assertEq(data[3].bridges.length, 2);\n    }\n}\n    \"#\n        .replace(\"<url>\", &rpc::next_http_archive_rpc_url()),\n    );\n\n    cmd.args([\"test\", \"--mc\", \"CounterTest\"]).assert_success().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\nRan 2 tests for test/Counter.t.sol:CounterTest\n[PASS] test_assert_storage() ([GAS])\n[PASS] test_modify_and_storage() ([GAS])\nSuite result: ok. 2 passed; 0 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 2 tests passed, 0 failed, 0 skipped (2 total tests)\n\n\"#]]);\n});\n\n// <https://github.com/foundry-rs/foundry/issues/10544>\nforgetest_init!(flaky_should_not_panic_on_cool, |prj, cmd| {\n    prj.initialize_default_contracts();\n    prj.add_test(\n        \"Counter.t.sol\",\n        r#\"\nimport \"forge-std/Test.sol\";\nimport {Counter} from \"../src/Counter.sol\";\n\ncontract CounterTest is Test {\n    Counter counter = new Counter();\n\n    function testCoolPanic() public {\n        address alice = makeAddr(\"alice\");\n        vm.deal(alice, 10000 ether);\n        counter.setNumber(1);\n        vm.cool(address(counter));\n        vm.prank(alice);\n        payable(address(counter)).transfer(1 ether);\n    }\n}\n    \"#,\n    );\n\n    cmd.args([\"test\", \"--mc\", \"CounterTest\"]).assert_failure().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\nRan 1 test for test/Counter.t.sol:CounterTest\n[FAIL: EvmError: Revert] testCoolPanic() ([GAS])\nSuite result: FAILED. 0 passed; 1 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 0 tests passed, 1 failed, 0 skipped (1 total tests)\n\nFailing tests:\nEncountered 1 failing test in test/Counter.t.sol:CounterTest\n[FAIL: EvmError: Revert] testCoolPanic() ([GAS])\n\nEncountered a total of 1 failing tests, 0 tests succeeded\n\nTip: Run `forge test --rerun` to retry only the 1 failed test\n\n\"#]]);\n});\n\n#[cfg(not(feature = \"isolate-by-default\"))]\nforgetest_init!(detailed_revert_when_calling_non_contract_address, |prj, cmd| {\n    prj.initialize_default_contracts();\n    prj.add_test(\n        \"NonContractCallRevertTest.t.sol\",\n        r#\"\nimport \"forge-std/Test.sol\";\nimport {Counter} from \"../src/Counter.sol\";\n\ninterface ICounter {\n    function increment() external;\n    function number() external returns (uint256);\n    function random() external returns (uint256);\n}\n\ncontract NonContractCallRevertTest is Test {\n    Counter public counter;\n    address constant ADDRESS = 0xdEADBEeF00000000000000000000000000000000;\n\n    function setUp() public {\n        counter = new Counter();\n        counter.setNumber(1);\n    }\n\n    function test_non_supported_selector_call_failure() public {\n        console.log(\"test non supported fn selector call failure\");\n        ICounter(address(counter)).random();\n    }\n\n    function test_non_contract_call_failure() public {\n        console.log(\"test non contract call failure\");\n        ICounter(ADDRESS).number();\n    }\n\n    function test_non_contract_void_call_failure() public {\n        console.log(\"test non contract (void) call failure\");\n        ICounter(ADDRESS).increment();\n    }\n}\n     \"#,\n    );\n\n    cmd.args([\"test\", \"--mc\", \"NonContractCallRevertTest\", \"-vvvvv\"])\n        .assert_failure()\n        .stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\nRan 3 tests for test/NonContractCallRevertTest.t.sol:NonContractCallRevertTest\n[FAIL: call to non-contract address 0xdEADBEeF00000000000000000000000000000000] test_non_contract_call_failure() ([GAS])\nLogs:\n  test non contract call failure\n\nTraces:\n  [157143] NonContractCallRevertTest::setUp()\n    ├─ [96345] → new Counter@0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f\n    │   └─ ← [Return] 481 bytes of code\n    ├─ [22492] Counter::setNumber(1)\n    │   └─ ← [Stop]\n    └─ ← [Stop]\n\n  [6350] NonContractCallRevertTest::test_non_contract_call_failure()\n    ├─ [0] console::log(\"test non contract call failure\") [staticcall]\n    │   └─ ← [Stop]\n    ├─ [0] 0xdEADBEeF00000000000000000000000000000000::number()\n    │   └─ ← [Stop]\n    └─ ← [Revert] call to non-contract address 0xdEADBEeF00000000000000000000000000000000\n\nBacktrace:\n  at NonContractCallRevertTest.test_non_contract_call_failure\n\n[FAIL: call to non-contract address 0xdEADBEeF00000000000000000000000000000000] test_non_contract_void_call_failure() ([GAS])\nLogs:\n  test non contract (void) call failure\n\nTraces:\n  [157143] NonContractCallRevertTest::setUp()\n    ├─ [96345] → new Counter@0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f\n    │   └─ ← [Return] 481 bytes of code\n    ├─ [22492] Counter::setNumber(1)\n    │   └─ ← [Stop]\n    └─ ← [Stop]\n\n  [6215] NonContractCallRevertTest::test_non_contract_void_call_failure()\n    ├─ [0] console::log(\"test non contract (void) call failure\") [staticcall]\n    │   └─ ← [Stop]\n    └─ ← [Revert] call to non-contract address 0xdEADBEeF00000000000000000000000000000000\n\nBacktrace:\n  at NonContractCallRevertTest.test_non_contract_void_call_failure (test/NonContractCallRevertTest.t.sol:[..]:[..])\n\n[FAIL: EvmError: Revert] test_non_supported_selector_call_failure() ([GAS])\nLogs:\n  test non supported fn selector call failure\n\nTraces:\n  [157143] NonContractCallRevertTest::setUp()\n    ├─ [96345] → new Counter@0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f\n    │   └─ ← [Return] 481 bytes of code\n    ├─ [22492] Counter::setNumber(1)\n    │   └─ ← [Stop]\n    └─ ← [Stop]\n\n  [8620] NonContractCallRevertTest::test_non_supported_selector_call_failure()\n    ├─ [0] console::log(\"test non supported fn selector call failure\") [staticcall]\n    │   └─ ← [Stop]\n    ├─ [145] Counter::random()\n    │   └─ ← [Revert] unrecognized function selector 0x5ec01e4d for contract 0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f, which has no fallback function.\n    └─ ← [Revert] EvmError: Revert\n\nBacktrace:\n  at Counter.random (src/Counter.sol:[..]:[..])\n  at NonContractCallRevertTest.test_non_supported_selector_call_failure (test/NonContractCallRevertTest.t.sol:[..]:[..])\n\nSuite result: FAILED. 0 passed; 3 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 0 tests passed, 3 failed, 0 skipped (3 total tests)\n\nFailing tests:\nEncountered 3 failing tests in test/NonContractCallRevertTest.t.sol:NonContractCallRevertTest\n[FAIL: call to non-contract address 0xdEADBEeF00000000000000000000000000000000] test_non_contract_call_failure() ([GAS])\n[FAIL: call to non-contract address 0xdEADBEeF00000000000000000000000000000000] test_non_contract_void_call_failure() ([GAS])\n[FAIL: EvmError: Revert] test_non_supported_selector_call_failure() ([GAS])\n\nEncountered a total of 3 failing tests, 0 tests succeeded\n\nTip: Run `forge test --rerun` to retry only the 3 failed tests\n\n\"#]]);\n});\n\n#[cfg(not(feature = \"isolate-by-default\"))]\nforgetest_init!(detailed_revert_when_delegatecalling_unlinked_library, |prj, cmd| {\n    prj.add_test(\n        \"NonContractDelegateCallRevertTest.t.sol\",\n        r#\"\nimport \"forge-std/Test.sol\";\n\nlibrary TestLibrary {\n    function foo(uint256 a) public pure returns (uint256) {\n        return a * 2;\n    }\n}\n\ncontract LibraryCaller {\n    address public lib;\n\n    constructor(address _lib) {\n        lib = _lib;\n    }\n\n    function foobar(uint256 val) public returns (uint256) {\n        (bool success, bytes memory data) = lib.delegatecall(\n            abi.encodeWithSelector(TestLibrary.foo.selector, val)\n        );\n\n        assert(success);\n        return abi.decode(data, (uint256));\n    }\n}\n\ncontract NonContractDelegateCallRevertTest is Test {\n    function test_unlinked_library_call_failure() public {\n        console.log(\"Test: Simulating call to unlinked library\");\n        LibraryCaller caller = new LibraryCaller(0xdEADBEeF00000000000000000000000000000000);\n\n        caller.foobar(10);\n    }\n}\n     \"#,\n    );\n\n    cmd.args([\"test\", \"--mc\", \"NonContractDelegateCallRevertTest\", \"-vvvvv\"])\n        .assert_failure()\n        .stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\nRan 1 test for test/NonContractDelegateCallRevertTest.t.sol:NonContractDelegateCallRevertTest\n[FAIL: delegatecall to non-contract address 0xdEADBEeF00000000000000000000000000000000 (usually an unliked library)] test_unlinked_library_call_failure() ([GAS])\nLogs:\n  Test: Simulating call to unlinked library\n\nTraces:\n  [255303] NonContractDelegateCallRevertTest::test_unlinked_library_call_failure()\n    ├─ [0] console::log(\"Test: Simulating call to unlinked library\") [staticcall]\n    │   └─ ← [Stop]\n    ├─ [214746] → new LibraryCaller@0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f\n    │   ├─  storage changes:\n    │   │   @ 0: 0 → 0x000000000000000000000000deadbeef00000000000000000000000000000000\n    │   └─ ← [Return] 960 bytes of code\n    ├─ [3896] LibraryCaller::foobar(10)\n    │   ├─ [0] 0xdEADBEeF00000000000000000000000000000000::foo(10) [delegatecall]\n    │   │   └─ ← [Stop]\n    │   └─ ← [Revert] delegatecall to non-contract address 0xdEADBEeF00000000000000000000000000000000 (usually an unliked library)\n    └─ ← [Revert] delegatecall to non-contract address 0xdEADBEeF00000000000000000000000000000000 (usually an unliked library)\n\nBacktrace:\n  at LibraryCaller.foobar\n  at NonContractDelegateCallRevertTest.test_unlinked_library_call_failure (test/NonContractDelegateCallRevertTest.t.sol:[..]:[..])\n\nSuite result: FAILED. 0 passed; 1 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 0 tests passed, 1 failed, 0 skipped (1 total tests)\n\nFailing tests:\nEncountered 1 failing test in test/NonContractDelegateCallRevertTest.t.sol:NonContractDelegateCallRevertTest\n[FAIL: delegatecall to non-contract address 0xdEADBEeF00000000000000000000000000000000 (usually an unliked library)] test_unlinked_library_call_failure() ([GAS])\n\nEncountered a total of 1 failing tests, 0 tests succeeded\n\nTip: Run `forge test --rerun` to retry only the 1 failed test\n\n\"#]]);\n});\n\n// This test is a copy of `error_event_decode_with_cache` in cast/tests/cli/selectors.rs\n// but it uses `forge build` to check that the project selectors are cached by default.\nforgetest_init!(flaky_build_with_selectors_cache, |prj, cmd| {\n    prj.initialize_default_contracts();\n    prj.add_source(\n        \"LocalProjectContract\",\n        r#\"\ncontract ContractWithCustomError {\n    error AnotherValueTooHigh(uint256, address);\n    event MyUniqueEventWithinLocalProject(uint256 a, address b);\n}\n   \"#,\n    );\n    // Build and cache project selectors.\n    cmd.forge_fuse().args([\"build\", \"--force\"]).assert_success();\n\n    // Assert cast can decode custom error with local cache.\n    cmd.cast_fuse()\n        .args([\"decode-error\", \"0x7191bc6200000000000000000000000000000000000000000000000000000000000000650000000000000000000000000000000000000000000000000000000000D0004F\"])\n        .assert_success()\n        .stdout_eq(str![[r#\"\nAnotherValueTooHigh(uint256,address)\n101\n0x0000000000000000000000000000000000D0004F\n\n\"#]]);\n    // Assert cast can decode event with local cache.\n    cmd.cast_fuse()\n        .args([\"decode-event\", \"0xbd3699995dcc867b64dbb607be2c33be38df9134bef1178df13bfb9446e73104000000000000000000000000000000000000000000000000000000000000004e00000000000000000000000000000000000000000000000000000dd00000004e\"])\n        .assert_success()\n        .stdout_eq(str![[r#\"\nMyUniqueEventWithinLocalProject(uint256,address)\n78\n0x00000000000000000000000000000DD00000004e\n\n\"#]]);\n});\n\n// <https://github.com/foundry-rs/foundry/issues/11021>\nforgetest_init!(revm_27_prank_bug_fix, |prj, cmd| {\n    prj.initialize_default_contracts();\n    prj.add_test(\n        \"PrankBug.t.sol\",\n        r#\"\nimport {Test} from \"forge-std/Test.sol\";\nimport {Counter} from \"../src/Counter.sol\";\n\ncontract PrankTest is Test {\n    Counter public counter;\n\n    function setUp() public {\n        vm.startPrank(address(0x123));\n        counter = new Counter();\n        vm.stopPrank();\n    }\n\n    function test_Increment() public {\n        vm.startPrank(address(0x123));\n        counter = new Counter();\n        vm.stopPrank();\n\n        counter.increment();\n        assertEq(counter.number(), 1);\n    }\n}\n\"#,\n    );\n\n    cmd.args([\"test\", \"--mc\", \"PrankTest\", \"-vvvvv\"]).assert_success().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\nRan 1 test for test/PrankBug.t.sol:PrankTest\n[PASS] test_Increment() ([GAS])\nTraces:\n  [..] PrankTest::setUp()\n    ├─ [0] VM::startPrank(0x0000000000000000000000000000000000000123)\n    │   └─ ← [Return]\n    ├─ [..] → new Counter@0x6cdBd1b486b8FBD4140e8cd6daAED05bE13eD914\n    │   └─ ← [Return] 481 bytes of code\n    ├─ [0] VM::stopPrank()\n    │   └─ ← [Return]\n    └─ ← [Stop]\n\n  [..] PrankTest::test_Increment()\n    ├─ [0] VM::startPrank(0x0000000000000000000000000000000000000123)\n    │   └─ ← [Return]\n    ├─ [..] → new Counter@0xc4B957Cd61beB9b9afD76204b30683EDAaaB51Ec\n    │   └─ ← [Return] 481 bytes of code\n    ├─ [0] VM::stopPrank()\n    │   └─ ← [Return]\n    ├─ [..] Counter::increment()\n    │   ├─  storage changes:\n    │   │   @ 0: 0 → 1\n    │   └─ ← [Stop]\n    ├─ [..] Counter::number() [staticcall]\n    │   └─ ← [Return] 1\n    ├─  storage changes:\n    │   @ 31: 0x00000000000000000000006cdbd1b486b8fbd4140e8cd6daaed05be13ed91401 → 0x0000000000000000000000c4b957cd61beb9b9afd76204b30683edaaab51ec01\n    └─ ← [Stop]\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests)\n\n\"#]]);\n});\n\n// tests proper reverts in fork mode for contracts with non-existent linked libraries.\n// <https://github.com/foundry-rs/foundry/issues/11185>\n#[cfg(not(feature = \"isolate-by-default\"))]\nforgetest_init!(can_fork_test_with_non_existent_linked_library, |prj, cmd| {\n    prj.update_config(|config| {\n        config.libraries =\n            vec![\"src/Counter.sol:LibCounter:0x530008d2b058137d9c475b1b7d83984f1fcf1dd0\".into()];\n    });\n    prj.add_source(\n        \"Counter.sol\",\n        r\"\nlibrary LibCounter {\n    function dummy() external pure returns (uint) {\n        return 1;\n    }\n}\n\ncontract Counter {\n    uint256 public number;\n\n    constructor() {\n        LibCounter.dummy();\n    }\n\n    function setNumber(uint256 newNumber) public {\n        number = newNumber;\n    }\n\n    function increment() public {\n        number++;\n    }\n\n    function dummy() external pure returns (uint) {\n        return LibCounter.dummy();\n    }\n}\n   \",\n    );\n\n    let endpoint = rpc::next_http_archive_rpc_url();\n\n    prj.add_test(\n        \"Counter.t.sol\",\n        &r#\"\nimport \"forge-std/Test.sol\";\nimport \"src/Counter.sol\";\n\ncontract CounterTest is Test {\n    function test_select_fork() public {\n        vm.createSelectFork(\"<url>\");\n        new Counter();\n    }\n\n    function test_roll_fork() public {\n        vm.rollFork(block.number - 100);\n        new Counter();\n    }\n}\n   \"#\n        .replace(\"<url>\", &endpoint),\n    );\n\n    cmd.args([\"test\", \"--fork-url\", &endpoint]).assert_failure().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\nRan 2 tests for test/Counter.t.sol:CounterTest\n[FAIL: EvmError: Revert] test_roll_fork() ([GAS])\n[FAIL: Contract 0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f does not exist and is not marked as persistent, see `vm.makePersistent()`] test_select_fork() ([GAS])\nSuite result: FAILED. 0 passed; 2 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 0 tests passed, 2 failed, 0 skipped (2 total tests)\n\nFailing tests:\nEncountered 2 failing tests in test/Counter.t.sol:CounterTest\n[FAIL: EvmError: Revert] test_roll_fork() ([GAS])\n[FAIL: Contract 0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f does not exist and is not marked as persistent, see `vm.makePersistent()`] test_select_fork() ([GAS])\n\nEncountered a total of 2 failing tests, 0 tests succeeded\n\nTip: Run `forge test --rerun` to retry only the 2 failed tests\n\n\"#]]);\n});\n\n// <https://github.com/foundry-rs/foundry/issues/11632>\n#[cfg(not(feature = \"isolate-by-default\"))]\nforgetest_init!(invariant_consistent_output, |prj, cmd| {\n    prj.update_config(|config| {\n        config.fuzz.seed = Some(U256::from(100u32));\n        config.invariant.runs = 10;\n        config.invariant.depth = 100;\n        config.invariant.show_metrics = false;\n    });\n    prj.add_test(\n        \"InvariantOutputTest.t.sol\",\n        r#\"\nimport {Test} from \"forge-std/Test.sol\";\n\ncontract InvariantOutputTest is Test {\n    uint256 count;\n\n    function setCond(uint256 cond) public {\n        if (cond > type(uint256).max / 2) {\n            count++;\n        }\n    }\n\n    function setUp() public {\n        targetContract(address(this));\n    }\n\n    function invariant_check_count() public view {\n        require(count < 2, \"failed invariant\");\n    }\n}\n   \"#,\n    );\n\n    cmd.args([\"test\", \"--mt\", \"invariant_check_count\", \"--color\", \"always\"])\n        .assert_failure()\n        .stdout_eq(file![\"../../fixtures/invariant_traces.svg\": TermSvg]);\n});\n\nforgetest_init!(memory_limit, |prj, cmd| {\n    prj.wipe_contracts();\n    prj.update_config(|config| {\n        config.memory_limit = 500 * 32;\n    });\n    prj.add_test(\n        \"MemoryLimit.t.sol\",\n        r#\"\nimport {Test} from \"forge-std/Test.sol\";\n\ncontract Memory {\n    function allocate(uint256 n) external pure returns (uint256[] memory) {\n        return new uint256[](n);\n    }\n}\n\ncontract MemoryLimitTest is Test {\n    Memory public m = new Memory();\n\n    function test_inBounds() public {\n        m.allocate(100);\n    }\n\n    function test_oom() public {\n        m.allocate(1000);\n    }\n}\n\"#,\n    );\n\n    cmd.arg(\"test\").assert_failure().stdout_eq(str![[r#\"\n...\nRan 2 tests for test/MemoryLimit.t.sol:MemoryLimitTest\n[PASS] test_inBounds() ([GAS])\n[FAIL: EvmError: Revert] test_oom() ([GAS])\nSuite result: FAILED. 1 passed; 1 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 1 tests passed, 1 failed, 0 skipped (2 total tests)\n\nFailing tests:\nEncountered 1 failing test in test/MemoryLimit.t.sol:MemoryLimitTest\n[FAIL: EvmError: Revert] test_oom() ([GAS])\n\nEncountered a total of 1 failing tests, 1 tests succeeded\n\nTip: Run `forge test --rerun` to retry only the 1 failed test\n\n\"#]]);\n});\n\nforgetest_init!(zero_runs, |prj, cmd| {\n    prj.wipe_contracts();\n    prj.add_test(\n        \"ZeroRuns.t.sol\",\n        r#\"\nimport {Test} from \"forge-std/Test.sol\";\n\ncontract Handler is Test {\n    function doSomething(uint256 param) public {\n        revert(\"unreachable\");\n    }\n}\n\ncontract ZeroRuns is Test {\n    Handler handler = new Handler();\n\n    /// forge-config: default.fuzz.runs = 0\n    function test_fuzzZeroRuns(uint256 x) public {\n        revert(\"unreachable\");\n    }\n\n    /// forge-config: default.invariant.runs = 0\n    function invariant_zeroRuns() public {}\n\n    /// forge-config: default.invariant.depth = 0\n    function invariant_zeroDepth() public {}\n}\n\"#,\n    );\n\n    cmd.args([\"test\"]).assert_success().stdout_eq(str![[r#\"\n...\nRan 3 tests for test/ZeroRuns.t.sol:ZeroRuns\n[PASS] invariant_zeroDepth() (runs: 256, calls: 0, reverts: 0)\n[PASS] invariant_zeroRuns() (runs: 0, calls: 0, reverts: 0)\n[PASS] test_fuzzZeroRuns(uint256) (runs: 0, [AVG_GAS])\nSuite result: ok. 3 passed; 0 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 3 tests passed, 0 failed, 0 skipped (3 total tests)\n\n\"#]]);\n});\n"
  },
  {
    "path": "crates/forge/tests/cli/test_cmd/repros.rs",
    "content": "//! Regression tests for specific GitHub issues\n\nuse foundry_test_utils::str;\n\n// https://github.com/foundry-rs/foundry/issues/3055\nforgetest_init!(issue_3055, |prj, cmd| {\n    prj.add_test(\n        \"Issue3055.t.sol\",\n        r#\"\nimport \"forge-std/Test.sol\";\n\n/// forge-config: default.assertions_revert = false\ncontract Issue3055Test is Test {\n    function test_snapshot() external {\n        uint256 snapshotId = vm.snapshotState();\n        assertEq(uint256(0), uint256(1));\n        vm.revertToState(snapshotId);\n    }\n\n    function test_snapshot2() public {\n        uint256 snapshotId = vm.snapshotState();\n        assertTrue(false);\n        vm.revertToState(snapshotId);\n        assertTrue(true);\n    }\n\n    function test_snapshot3(uint256) public {\n        vm.expectRevert();\n        // Call exposed_snapshot3() using this to perform an external call,\n        // so we can properly test for reverts.\n        this.exposed_snapshot3();\n    }\n\n    function exposed_snapshot3() public {\n        uint256 snapshotId = vm.snapshotState();\n        assertTrue(false);\n        vm.revertToState(snapshotId);\n    }\n}\n\"#,\n    );\n\n    cmd.arg(\"test\").assert_failure().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\nRan 3 tests for test/Issue3055.t.sol:Issue3055Test\n[FAIL] test_snapshot() ([GAS])\n[FAIL] test_snapshot2() ([GAS])\n[FAIL: next call did not revert as expected; counterexample: calldata=[..] args=[..] test_snapshot3(uint256) (runs: 0, [AVG_GAS])\nSuite result: FAILED. 0 passed; 3 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 0 tests passed, 3 failed, 0 skipped (3 total tests)\n\nFailing tests:\nEncountered 3 failing tests in test/Issue3055.t.sol:Issue3055Test\n[FAIL] test_snapshot() ([GAS])\n[FAIL] test_snapshot2() ([GAS])\n[FAIL: next call did not revert as expected; counterexample: calldata=[..] args=[..] test_snapshot3(uint256) (runs: 0, [AVG_GAS])\n\nEncountered a total of 3 failing tests, 0 tests succeeded\n\nTip: Run `forge test --rerun` to retry only the 3 failed tests\n\n[SEED] (use `--fuzz-seed` to reproduce)\n\n\"#]]);\n});\n\n// https://github.com/foundry-rs/foundry/issues/3189\nforgetest_init!(issue_3189, |prj, cmd| {\n    prj.add_test(\n        \"Issue3189.t.sol\",\n        r#\"\nimport \"forge-std/Test.sol\";\n\ncontract MyContract {\n    function foo(uint256 arg) public returns (uint256) {\n        return arg + 2;\n    }\n}\n\ncontract MyContractUser is Test {\n    MyContract immutable myContract;\n\n    constructor() {\n        myContract = new MyContract();\n    }\n\n    function foo(uint256 arg) public returns (uint256 ret) {\n        ret = myContract.foo(arg);\n        assertEq(ret, arg + 1, \"Invariant failed\");\n    }\n}\n\ncontract Issue3189Test is Test {\n    function testFoo() public {\n        MyContractUser user = new MyContractUser();\n        user.foo(123);\n    }\n}\n\"#,\n    );\n\n    cmd.arg(\"test\").assert_failure().stdout_eq(str![[r#\"\n...\nRan 1 test for test/Issue3189.t.sol:Issue3189Test\n[FAIL: Invariant failed: 125 != 124] testFoo() ([GAS])\nSuite result: FAILED. 0 passed; 1 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 0 tests passed, 1 failed, 0 skipped (1 total tests)\n\nFailing tests:\nEncountered 1 failing test in test/Issue3189.t.sol:Issue3189Test\n[FAIL: Invariant failed: 125 != 124] testFoo() ([GAS])\n\nEncountered a total of 1 failing tests, 0 tests succeeded\n\nTip: Run `forge test --rerun` to retry only the 1 failed test\n\n\"#]]);\n});\n\n// https://github.com/foundry-rs/foundry/issues/3596\nforgetest_init!(issue_3596, |prj, cmd| {\n    prj.add_test(\n        \"Issue3596.t.sol\",\n        r#\"\nimport \"forge-std/Test.sol\";\n\ncontract Issue3596Test is Test {\n    function testDealTransfer() public {\n        address addr = vm.addr(1337);\n        vm.startPrank(addr);\n        vm.deal(addr, 20000001 ether);\n        payable(address(this)).transfer(20000000 ether);\n\n        Nested nested = new Nested();\n        nested.doStuff();\n        vm.stopPrank();\n    }\n}\n\ncontract Nested {\n    function doStuff() public {\n        doRevert();\n    }\n\n    function doRevert() public {\n        revert(\"This fails\");\n    }\n}\n\"#,\n    );\n\n    cmd.arg(\"test\").assert_failure().stdout_eq(str![[r#\"\n...\nRan 1 test for test/Issue3596.t.sol:Issue3596Test\n[FAIL: EvmError: Revert] testDealTransfer() ([GAS])\nSuite result: FAILED. 0 passed; 1 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 0 tests passed, 1 failed, 0 skipped (1 total tests)\n\nFailing tests:\nEncountered 1 failing test in test/Issue3596.t.sol:Issue3596Test\n[FAIL: EvmError: Revert] testDealTransfer() ([GAS])\n\nEncountered a total of 1 failing tests, 0 tests succeeded\n\nTip: Run `forge test --rerun` to retry only the 1 failed test\n\n\"#]]);\n});\n\n// https://github.com/foundry-rs/foundry/issues/2851\nforgetest_init!(issue_2851, |prj, cmd| {\n    prj.add_test(\n        \"Issue2851.t.sol\",\n        r#\"\nimport \"forge-std/Test.sol\";\n\ncontract Backdoor {\n    uint256 public number = 1;\n\n    function backdoor(uint256 newNumber) public payable {\n        uint256 x = newNumber - 1;\n        if (x == 6912213124124531) {\n            number = 0;\n        }\n    }\n}\n\ncontract Issue2851Test is Test {\n    Backdoor back;\n\n    function setUp() public {\n        back = new Backdoor();\n    }\n\n    /// forge-config: default.fuzz.seed = \"111\"\n    function invariantNotZero() public {\n        assertEq(back.number(), 1);\n    }\n}\n\"#,\n    );\n\n    cmd.arg(\"test\").assert_failure().stdout_eq(str![[r#\"\n...\nRan 1 test for test/Issue2851.t.sol:Issue2851Test\n[FAIL: assertion failed: 0 != 1]\n...\n invariantNotZero() ([..])\n...\nSuite result: FAILED. 0 passed; 1 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 0 tests passed, 1 failed, 0 skipped (1 total tests)\n...\n\"#]]);\n});\n\n// https://github.com/foundry-rs/foundry/issues/6170\nforgetest_init!(issue_6170, |prj, cmd| {\n    prj.add_test(\n        \"Issue6170.t.sol\",\n        r#\"\nimport \"forge-std/Test.sol\";\n\ncontract Emitter {\n    event Values(uint256 indexed a, uint256 indexed b);\n\n    function plsEmit(uint256 a, uint256 b) external {\n        emit Values(a, b);\n    }\n}\n\ncontract Issue6170Test is Test {\n    event Values(uint256 indexed a, uint256 b);\n\n    Emitter e = new Emitter();\n\n    function test() public {\n        vm.expectEmit(true, true, false, true);\n        emit Values(69, 420);\n        e.plsEmit(69, 420);\n    }\n}\n\"#,\n    );\n\n    cmd.arg(\"test\").assert_failure().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\nRan 1 test for test/Issue6170.t.sol:Issue6170Test\n[FAIL: log != expected log] test() ([GAS])\nSuite result: FAILED. 0 passed; 1 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 0 tests passed, 1 failed, 0 skipped (1 total tests)\n\nFailing tests:\nEncountered 1 failing test in test/Issue6170.t.sol:Issue6170Test\n[FAIL: log != expected log] test() ([GAS])\n\nEncountered a total of 1 failing tests, 0 tests succeeded\n\nTip: Run `forge test --rerun` to retry only the 1 failed test\n\n\"#]]);\n});\n\n// https://github.com/foundry-rs/foundry/issues/6355\nforgetest_init!(issue_6355, |prj, cmd| {\n    prj.add_test(\n        \"Issue6355.t.sol\",\n        r#\"\nimport \"forge-std/Test.sol\";\n\ncontract Issue6355Test is Test {\n    uint256 snapshotId;\n    Target targ;\n\n    function setUp() public {\n        snapshotId = vm.snapshotState();\n        targ = new Target();\n    }\n\n    // this non-deterministically fails sometimes and passes sometimes\n    function test_shouldPass() public {\n        assertEq(2, targ.num());\n    }\n\n    // always fails\n    function test_shouldFailWithRevertToState() public {\n        assertEq(3, targ.num());\n        vm.revertToState(snapshotId);\n    }\n\n    // always fails\n    function test_shouldFail() public {\n        assertEq(3, targ.num());\n    }\n}\n\ncontract Target {\n    function num() public pure returns (uint256) {\n        return 2;\n    }\n}\n\"#,\n    );\n\n    cmd.arg(\"test\").assert_failure().stdout_eq(str![[r#\"\n...\nRan 3 tests for test/Issue6355.t.sol:Issue6355Test\n[FAIL: assertion failed: 3 != 2] test_shouldFail() ([GAS])\n[FAIL: assertion failed: 3 != 2] test_shouldFailWithRevertToState() ([GAS])\n[PASS] test_shouldPass() ([GAS])\nSuite result: FAILED. 1 passed; 2 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 1 tests passed, 2 failed, 0 skipped (3 total tests)\n\nFailing tests:\nEncountered 2 failing tests in test/Issue6355.t.sol:Issue6355Test\n[FAIL: assertion failed: 3 != 2] test_shouldFail() ([GAS])\n[FAIL: assertion failed: 3 != 2] test_shouldFailWithRevertToState() ([GAS])\n\nEncountered a total of 2 failing tests, 1 tests succeeded\n\nTip: Run `forge test --rerun` to retry only the 2 failed tests\n\n\"#]]);\n});\n\n// https://github.com/foundry-rs/foundry/issues/3347\nforgetest_init!(issue_3347, |prj, cmd| {\n    prj.add_test(\n        \"Issue3347.t.sol\",\n        r#\"\nimport \"forge-std/Test.sol\";\n\ncontract Issue3347Test is Test {\n    event log2(uint256, uint256);\n\n    function test() public {\n        emit log2(1, 2);\n    }\n}\n\"#,\n    );\n\n    cmd.args([\"test\", \"-vvvv\"]).assert_success().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\nRan 1 test for test/Issue3347.t.sol:Issue3347Test\n[PASS] test() ([GAS])\nTraces:\n  [..] Issue3347Test::test()\n    ├─ emit log2(: 1, : 2)\n    └─ ← [Stop]\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests)\n\n\"#]]);\n});\n\n// https://github.com/foundry-rs/foundry/issues/6501\n// Make sure we decode Hardhat-style `console.log`s correctly, in both logs and traces.\nforgetest_init!(issue_6501, |prj, cmd| {\n    prj.add_test(\n        \"Issue6501.t.sol\",\n        r#\"\nimport \"forge-std/Test.sol\";\n\ncontract Issue6501Test is Test {\n    function test_hhLogs() public {\n        console.log(\"a\");\n        console.log(uint256(1));\n        console.log(\"b\", uint256(2));\n    }\n}\n\"#,\n    );\n\n    cmd.args([\"test\", \"-vvvv\"]).assert_success().stdout_eq(str![[r#\"\n...\nRan 1 test for test/Issue6501.t.sol:Issue6501Test\n[PASS] test_hhLogs() ([GAS])\nLogs:\n  a\n  1\n  b 2\n\nTraces:\n  [..] Issue6501Test::test_hhLogs()\n    ├─ [0] console::log(\"a\") [staticcall]\n    │   └─ ← [Stop]\n    ├─ [0] console::log(1) [staticcall]\n    │   └─ ← [Stop]\n    ├─ [0] console::log(\"b\", 2) [staticcall]\n    │   └─ ← [Stop]\n    └─ ← [Stop]\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests)\n\n\"#]]);\n});\n\n// https://github.com/foundry-rs/foundry/issues/8383\nforgetest_init!(issue_8383, |prj, cmd| {\n    prj.update_config(|config| {\n        config.optimizer = Some(true);\n        config.optimizer_runs = Some(200);\n    });\n    prj.add_test(\n        \"Issue8383.t.sol\",\n        r#\"\nimport \"forge-std/Test.sol\";\n\ncontract Issue8383Test is Test {\n    address internal _verifier;\n\n    mapping(bytes32 => bool) internal _vectorTested;\n    mapping(bytes32 => bool) internal _vectorResult;\n\n    function setUp() public {\n        _verifier = address(new P256Verifier());\n    }\n\n    function _verifyViaVerifier(bytes32 hash, uint256 r, uint256 s, uint256 x, uint256 y) internal returns (bool) {\n        return _verifyViaVerifier(hash, bytes32(r), bytes32(s), bytes32(x), bytes32(y));\n    }\n\n    function _verifyViaVerifier(bytes32 hash, bytes32 r, bytes32 s, bytes32 x, bytes32 y) internal returns (bool) {\n        bytes memory payload = abi.encode(hash, r, s, x, y);\n        if (uint256(y) & 0xff == 0) {\n            bytes memory truncatedPayload = abi.encodePacked(hash, r, s, x, bytes31(y));\n            _verifierCall(truncatedPayload);\n        }\n        if (uint256(keccak256(abi.encode(payload, \"1\"))) & 0x1f == 0) {\n            uint256 r = uint256(keccak256(abi.encode(payload, \"2\")));\n            payload = abi.encodePacked(payload, new bytes(r & 0xff));\n        }\n        bytes32 payloadHash = keccak256(payload);\n        if (_vectorTested[payloadHash]) return _vectorResult[payloadHash];\n        _vectorTested[payloadHash] = true;\n        return (_vectorResult[payloadHash] = _verifierCall(payload));\n    }\n\n    function _verifierCall(bytes memory payload) internal returns (bool) {\n        (bool success, bytes memory result) = _verifier.call(payload);\n        return abi.decode(result, (bool));\n    }\n\n    function testP256VerifyOutOfBounds() public {\n        vm.pauseGasMetering();\n        uint256 p = 0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF;\n        _verifyViaVerifier(bytes32(0), 1, 1, 1, 1);\n        _verifyViaVerifier(bytes32(0), 1, 1, 0, 1);\n        _verifyViaVerifier(bytes32(0), 1, 1, 1, 0);\n        _verifyViaVerifier(bytes32(0), 1, 1, 1, p);\n        _verifyViaVerifier(bytes32(0), 1, 1, p, 1);\n        _verifyViaVerifier(bytes32(0), 1, 1, p - 1, 1);\n        vm.resumeGasMetering();\n    }\n}\n\ncontract P256Verifier {\n    uint256 private constant GX = 0x6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296;\n    uint256 private constant GY = 0x4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5;\n    uint256 private constant P = 0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF; // `A = P - 3`.\n    uint256 private constant N = 0xFFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551;\n    uint256 private constant B = 0x5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B;\n\n    fallback() external payable {\n        assembly {\n            // For this implementation, we will use the memory without caring about\n            // the free memory pointer or zero pointer.\n            // The slots `0x00`, `0x20`, `0x40`, `0x60`, will not be accessed for the `Points[16]` array,\n            // and can be used for storing other variables.\n\n            mstore(0x40, P) // Set `0x40` to `P`.\n\n            function jAdd(x1, y1, z1, x2, y2, z2) -> x3, y3, z3 {\n                if iszero(z1) {\n                    x3 := x2\n                    y3 := y2\n                    z3 := z2\n                    leave\n                }\n                if iszero(z2) {\n                    x3 := x1\n                    y3 := y1\n                    z3 := z1\n                    leave\n                }\n                let p := mload(0x40)\n                let zz1 := mulmod(z1, z1, p)\n                let zz2 := mulmod(z2, z2, p)\n                let u1 := mulmod(x1, zz2, p)\n                let u2 := mulmod(x2, zz1, p)\n                let s1 := mulmod(y1, mulmod(zz2, z2, p), p)\n                let s2 := mulmod(y2, mulmod(zz1, z1, p), p)\n                let h := addmod(u2, sub(p, u1), p)\n                let hh := mulmod(h, h, p)\n                let hhh := mulmod(h, hh, p)\n                let r := addmod(s2, sub(p, s1), p)\n                x3 := addmod(addmod(mulmod(r, r, p), sub(p, hhh), p), sub(p, mulmod(2, mulmod(u1, hh, p), p)), p)\n                y3 := addmod(mulmod(r, addmod(mulmod(u1, hh, p), sub(p, x3), p), p), sub(p, mulmod(s1, hhh, p)), p)\n                z3 := mulmod(h, mulmod(z1, z2, p), p)\n            }\n\n            function setJPoint(i, x, y, z) {\n                // We will multiply by `0x80` (i.e. `shl(7, i)`) instead\n                // since the memory expansion costs are cheaper than doing `mul(0x60, i)`.\n                // Also help combine the lookup expression for `u1` and `u2` in `jMultShamir`.\n                i := shl(7, i)\n                mstore(i, x)\n                mstore(add(i, returndatasize()), y)\n                mstore(add(i, 0x40), z)\n            }\n\n            function setJPointDouble(i, j) {\n                j := shl(7, j)\n                let x := mload(j)\n                let y := mload(add(j, returndatasize()))\n                let z := mload(add(j, 0x40))\n                let p := mload(0x40)\n                let yy := mulmod(y, y, p)\n                let zz := mulmod(z, z, p)\n                let s := mulmod(4, mulmod(x, yy, p), p)\n                let m := addmod(mulmod(3, mulmod(x, x, p), p), mulmod(mload(returndatasize()), mulmod(zz, zz, p), p), p)\n                let x2 := addmod(mulmod(m, m, p), sub(p, mulmod(2, s, p)), p)\n                let y2 := addmod(mulmod(m, addmod(s, sub(p, x2), p), p), sub(p, mulmod(8, mulmod(yy, yy, p), p)), p)\n                let z2 := mulmod(2, mulmod(y, z, p), p)\n                setJPoint(i, x2, y2, z2)\n            }\n\n            function setJPointAdd(i, j, k) {\n                j := shl(7, j)\n                k := shl(7, k)\n                let x, y, z :=\n                    jAdd(\n                        mload(j),\n                        mload(add(j, returndatasize())),\n                        mload(add(j, 0x40)),\n                        mload(k),\n                        mload(add(k, returndatasize())),\n                        mload(add(k, 0x40))\n                    )\n                setJPoint(i, x, y, z)\n            }\n\n            let r := calldataload(0x20)\n            let n := N\n\n            {\n                let s := calldataload(0x40)\n                if lt(shr(1, n), s) { s := sub(n, s) }\n\n                // Perform `modExp(s, N - 2, N)`.\n                // After which, we can abuse `returndatasize()` to get `0x20`.\n                mstore(0x800, 0x20)\n                mstore(0x820, 0x20)\n                mstore(0x840, 0x20)\n                mstore(0x860, s)\n                mstore(0x880, sub(n, 2))\n                mstore(0x8a0, n)\n\n                let p := mload(0x40)\n                mstore(0x20, xor(3, p)) // Set `0x20` to `A`.\n                let Qx := calldataload(0x60)\n                let Qy := calldataload(0x80)\n\n                if iszero(\n                    and( // The arguments of `and` are evaluated last to first.\n                        and(\n                            and(gt(calldatasize(), 0x9f), and(lt(iszero(r), lt(r, n)), lt(iszero(s), lt(s, n)))),\n                            eq(\n                                mulmod(Qy, Qy, p),\n                                addmod(mulmod(addmod(mulmod(Qx, Qx, p), mload(returndatasize()), p), Qx, p), B, p)\n                            )\n                        ),\n                        and(\n                            // We need to check that the `returndatasize` is indeed 32,\n                            // so that we can return false if the chain does not have the modexp precompile.\n                            eq(returndatasize(), 0x20),\n                            staticcall(gas(), 0x05, 0x800, 0xc0, returndatasize(), 0x20)\n                        )\n                    )\n                ) {\n                    // POC Note:\n                    // Changing this to `return(0x80, 0x20)` fixes it.\n                    // Alternatively, adding `if mload(0x8c0) { invalid() }` just before the return also fixes it.\n                    return(0x8c0, 0x20)\n                }\n\n                setJPoint(0x01, Qx, Qy, 1)\n                setJPoint(0x04, GX, GY, 1)\n                setJPointDouble(0x02, 0x01)\n                setJPointDouble(0x08, 0x04)\n                setJPointAdd(0x03, 0x01, 0x02)\n                setJPointAdd(0x05, 0x01, 0x04)\n                setJPointAdd(0x06, 0x02, 0x04)\n                setJPointAdd(0x07, 0x03, 0x04)\n                setJPointAdd(0x09, 0x01, 0x08)\n                setJPointAdd(0x0a, 0x02, 0x08)\n                setJPointAdd(0x0b, 0x03, 0x08)\n                setJPointAdd(0x0c, 0x04, 0x08)\n                setJPointAdd(0x0d, 0x01, 0x0c)\n                setJPointAdd(0x0e, 0x02, 0x0c)\n                setJPointAdd(0x0f, 0x03, 0x0c)\n            }\n\n            let i := 0\n            let u1 := mulmod(calldataload(0x00), mload(0x00), n)\n            let u2 := mulmod(r, mload(0x00), n)\n            let y := 0\n            let z := 0\n            let x := 0\n            let p := mload(0x40)\n            for {} 1 {} {\n                if z {\n                    let yy := mulmod(y, y, p)\n                    let zz := mulmod(z, z, p)\n                    let s := mulmod(4, mulmod(x, yy, p), p)\n                    let m :=\n                        addmod(mulmod(3, mulmod(x, x, p), p), mulmod(mload(returndatasize()), mulmod(zz, zz, p), p), p)\n                    let x2 := addmod(mulmod(m, m, p), sub(p, mulmod(2, s, p)), p)\n                    let y2 := addmod(mulmod(m, addmod(s, sub(p, x2), p), p), sub(p, mulmod(8, mulmod(yy, yy, p), p)), p)\n                    let z2 := mulmod(2, mulmod(y, z, p), p)\n                    yy := mulmod(y2, y2, p)\n                    zz := mulmod(z2, z2, p)\n                    s := mulmod(4, mulmod(x2, yy, p), p)\n                    m := addmod(\n                        mulmod(3, mulmod(x2, x2, p), p),\n                        mulmod(mload(returndatasize()), mulmod(zz, zz, p), p),\n                        p\n                    )\n                    x := addmod(mulmod(m, m, p), sub(p, mulmod(2, s, p)), p)\n                    z := mulmod(2, mulmod(y2, z2, p), p)\n                    y := addmod(mulmod(m, addmod(s, sub(p, x), p), p), sub(p, mulmod(8, mulmod(yy, yy, p), p)), p)\n                }\n                for { let o := or(and(shr(245, shl(i, u1)), 0x600), and(shr(247, shl(i, u2)), 0x180)) } o {} {\n                    let z2 := mload(add(o, 0x40))\n                    if iszero(z2) { break }\n                    if iszero(z) {\n                        x := mload(o)\n                        y := mload(add(o, returndatasize()))\n                        z := z2\n                        break\n                    }\n                    let zz1 := mulmod(z, z, p)\n                    let zz2 := mulmod(z2, z2, p)\n                    let u1_ := mulmod(x, zz2, p)\n                    let s1 := mulmod(y, mulmod(zz2, z2, p), p)\n                    let h := addmod(mulmod(mload(o), zz1, p), sub(p, u1_), p)\n                    let hh := mulmod(h, h, p)\n                    let hhh := mulmod(h, hh, p)\n                    let r_ := addmod(mulmod(mload(add(o, returndatasize())), mulmod(zz1, z, p), p), sub(p, s1), p)\n                    x := addmod(addmod(mulmod(r_, r_, p), sub(p, hhh), p), sub(p, mulmod(2, mulmod(u1_, hh, p), p)), p)\n                    y := addmod(mulmod(r_, addmod(mulmod(u1_, hh, p), sub(p, x), p), p), sub(p, mulmod(s1, hhh, p)), p)\n                    z := mulmod(h, mulmod(z, z2, p), p)\n                    break\n                }\n                // Just unroll twice. Fully unrolling will only save around 1% to 2% gas, but make the\n                // bytecode very bloated, which may incur more runtime costs after Verkle.\n                // See: https://notes.ethereum.org/%40vbuterin/verkle_tree_eip\n                // It's very unlikely that Verkle will come before the P256 precompile. But who knows?\n                if z {\n                    let yy := mulmod(y, y, p)\n                    let zz := mulmod(z, z, p)\n                    let s := mulmod(4, mulmod(x, yy, p), p)\n                    let m :=\n                        addmod(mulmod(3, mulmod(x, x, p), p), mulmod(mload(returndatasize()), mulmod(zz, zz, p), p), p)\n                    let x2 := addmod(mulmod(m, m, p), sub(p, mulmod(2, s, p)), p)\n                    let y2 := addmod(mulmod(m, addmod(s, sub(p, x2), p), p), sub(p, mulmod(8, mulmod(yy, yy, p), p)), p)\n                    let z2 := mulmod(2, mulmod(y, z, p), p)\n                    yy := mulmod(y2, y2, p)\n                    zz := mulmod(z2, z2, p)\n                    s := mulmod(4, mulmod(x2, yy, p), p)\n                    m := addmod(\n                        mulmod(3, mulmod(x2, x2, p), p),\n                        mulmod(mload(returndatasize()), mulmod(zz, zz, p), p),\n                        p\n                    )\n                    x := addmod(mulmod(m, m, p), sub(p, mulmod(2, s, p)), p)\n                    z := mulmod(2, mulmod(y2, z2, p), p)\n                    y := addmod(mulmod(m, addmod(s, sub(p, x), p), p), sub(p, mulmod(8, mulmod(yy, yy, p), p)), p)\n                }\n                for { let o := or(and(shr(243, shl(i, u1)), 0x600), and(shr(245, shl(i, u2)), 0x180)) } o {} {\n                    let z2 := mload(add(o, 0x40))\n                    if iszero(z2) { break }\n                    if iszero(z) {\n                        x := mload(o)\n                        y := mload(add(o, returndatasize()))\n                        z := z2\n                        break\n                    }\n                    let zz1 := mulmod(z, z, p)\n                    let zz2 := mulmod(z2, z2, p)\n                    let u1_ := mulmod(x, zz2, p)\n                    let s1 := mulmod(y, mulmod(zz2, z2, p), p)\n                    let h := addmod(mulmod(mload(o), zz1, p), sub(p, u1_), p)\n                    let hh := mulmod(h, h, p)\n                    let hhh := mulmod(h, hh, p)\n                    let r_ := addmod(mulmod(mload(add(o, returndatasize())), mulmod(zz1, z, p), p), sub(p, s1), p)\n                    x := addmod(addmod(mulmod(r_, r_, p), sub(p, hhh), p), sub(p, mulmod(2, mulmod(u1_, hh, p), p)), p)\n                    y := addmod(mulmod(r_, addmod(mulmod(u1_, hh, p), sub(p, x), p), p), sub(p, mulmod(s1, hhh, p)), p)\n                    z := mulmod(h, mulmod(z, z2, p), p)\n                    break\n                }\n                i := add(i, 4)\n                if eq(i, 256) { break }\n            }\n\n            if iszero(z) {\n                mstore(returndatasize(), iszero(r))\n                return(returndatasize(), 0x20)\n            }\n\n            // Perform `modExp(z, P - 2, P)`.\n            // `0x800`, `0x820, `0x840` are still set to `0x20`.\n            mstore(0x860, z)\n            mstore(0x880, sub(p, 2))\n            mstore(0x8a0, p)\n\n            mstore(\n                returndatasize(),\n                and( // The arguments of `and` are evaluated last to first.\n                    eq(mod(mulmod(x, mulmod(mload(returndatasize()), mload(returndatasize()), p), p), n), r),\n                    staticcall(gas(), 0x05, 0x800, 0xc0, returndatasize(), returndatasize())\n                )\n            )\n            return(returndatasize(), returndatasize())\n        }\n    }\n}\n\"#,\n    );\n\n    cmd.arg(\"test\").with_no_redact().assert_success().stdout_eq(str![[r#\"\n...\nRan 1 test for test/Issue8383.t.sol:Issue8383Test\n[PASS] testP256VerifyOutOfBounds() (gas: 3139)\n...\n\"#]]);\n});\n\n// https://github.com/foundry-rs/foundry/issues/9272\nforgetest_init!(issue_9272, |prj, cmd| {\n    prj.update_config(|config| {\n        config.allow_paths.push(\"..\".into());\n    });\n\n    prj.add_source(\n        \"Contract.sol\",\n        r#\"\npragma solidity ^0.8.0;\nimport '../Missing.sol';\ncontract Contract {}\n\"#,\n    );\n\n    // We expect a compilation error due to the missing import\n    cmd.arg(\"build\").assert_failure().stderr_eq(str![[r#\"\nError: Compiler run failed:\nError (6275): Source \"Missing.sol\" not found: File not found. Searched the following locations: [..]\nParserError: Source \"Missing.sol\" not found: File not found. Searched the following locations: [..]\n [FILE]:4:1:\n  |\n4 | import '../Missing.sol';\n  | ^^^^^^^^^^^^^^^^^^^^^^^^\n\n\"#]]);\n});\n\n// https://github.com/foundry-rs/foundry/issues/12803\n// Test gas underflow prevention on Cancun (no EIP-7702 gas floor)\nforgetest_init!(issue_12803_cancun, |prj, cmd| {\n    prj.add_test(\n        \"Issue12803.t.sol\",\n        r#\"\nimport {Test} from \"forge-std/Test.sol\";\n\ncontract Issue12803Test is Test {\n    uint a;\n    function test_negativeGas() public {\n        vm.pauseGasMetering();\n        a = 100;\n        vm.resumeGasMetering();\n        delete a;\n    }\n}\n\"#,\n    );\n\n    cmd.args([\"test\", \"--evm-version=cancun\"]).with_no_redact().assert_success().stdout_eq(str![[\n        r#\"\n...\nRan 1 test for test/Issue12803.t.sol:Issue12803Test\n[PASS] test_negativeGas() (gas: 0)\n...\n\"#\n    ]]);\n});\n\n// https://github.com/foundry-rs/foundry/issues/12803\n// Test gas underflow prevention on Shanghai (also no EIP-7702 gas floor)\nforgetest_init!(issue_12803_shanghai, |prj, cmd| {\n    prj.add_test(\n        \"Issue12803.t.sol\",\n        r#\"\nimport {Test} from \"forge-std/Test.sol\";\n\ncontract Issue12803Test is Test {\n    uint a;\n    function test_negativeGas() public {\n        vm.pauseGasMetering();\n        a = 100;\n        vm.resumeGasMetering();\n        delete a;\n    }\n}\n\"#,\n    );\n\n    cmd.args([\"test\", \"--evm-version=shanghai\"]).with_no_redact().assert_success().stdout_eq(str![\n        [r#\"\n...\nRan 1 test for test/Issue12803.t.sol:Issue12803Test\n[PASS] test_negativeGas() (gas: 0)\n...\n\"#]\n    ]);\n});\n\n// https://github.com/foundry-rs/foundry/issues/13766\n// vm.expectRevert(bytes(\"\")) should not panic when actual revert has data\nforgetest_init!(issue_13766, |prj, cmd| {\n    prj.add_test(\n        \"Issue13766.t.sol\",\n        r#\"\nimport {Test} from \"forge-std/Test.sol\";\n\ncontract Reverter {\n    error CustomError();\n    function revertWithData() public pure { revert CustomError(); }\n}\n\ncontract Issue13766Test is Test {\n    function test_expectRevertEmptyBytes() public {\n        Reverter r = new Reverter();\n        vm.expectRevert(bytes(\"\"));\n        r.revertWithData();\n    }\n}\n\"#,\n    );\n\n    cmd.arg(\"test\").assert_failure().stdout_eq(str![[r#\"\n...\n[FAIL: Error != expected error: CustomError() != EvmError: Revert] test_expectRevertEmptyBytes() ([GAS])\n...\n\"#]]);\n});\n\n// https://github.com/foundry-rs/foundry/issues/12803\n// Test multiple storage deletions (higher refund) don't cause underflow\nforgetest_init!(issue_12803_multiple_deletes, |prj, cmd| {\n    prj.add_test(\n        \"Issue12803Multi.t.sol\",\n        r#\"\nimport {Test} from \"forge-std/Test.sol\";\n\ncontract Issue12803MultiTest is Test {\n    uint a;\n    uint b;\n    uint c;\n    function test_multipleDeletes() public {\n        vm.pauseGasMetering();\n        a = 100;\n        b = 200;\n        c = 300;\n        vm.resumeGasMetering();\n        delete a;\n        delete b;\n        delete c;\n    }\n}\n\"#,\n    );\n\n    cmd.args([\"test\", \"--evm-version=cancun\"]).with_no_redact().assert_success().stdout_eq(str![[\n        r#\"\n...\nRan 1 test for test/Issue12803Multi.t.sol:Issue12803MultiTest\n[PASS] test_multipleDeletes() (gas: 0)\n...\n\"#\n    ]]);\n});\n"
  },
  {
    "path": "crates/forge/tests/cli/test_cmd/spec.rs",
    "content": "use foundry_test_utils::rpc;\n\n// Test evm version switch during tests / scripts.\n// <https://github.com/foundry-rs/foundry/issues/9840>\n// <https://github.com/foundry-rs/foundry/issues/6228>\nforgetest_init!(test_set_evm_version, |prj, cmd| {\n    let endpoint = rpc::next_http_archive_rpc_url();\n    prj.add_test(\n        \"TestEvmVersion.t.sol\",\n        &r#\"\nimport {Test} from \"forge-std/Test.sol\";\n\ninterface EvmVm {\n    function getEvmVersion() external pure returns (string memory evm);\n    function setEvmVersion(string calldata evm) external;\n}\n\ninterface ICreate2Deployer {\n    function computeAddress(bytes32 salt, bytes32 codeHash) external view returns (address);\n}\n\ncontract TestEvmVersion is Test {\n    function test_evm_version() public {\n        EvmVm evm = EvmVm(address(bytes20(uint160(uint256(keccak256(\"hevm cheat code\"))))));\n        vm.createSelectFork(\"<rpc>\");\n\n        evm.setEvmVersion(\"istanbul\");\n        evm.getEvmVersion();\n\n        // revert with NotActivated for istanbul\n        vm.expectRevert();\n        compute();\n\n        evm.setEvmVersion(\"shanghai\");\n        evm.getEvmVersion();\n        compute();\n\n        // switch to Paris, expect revert with NotActivated\n        evm.setEvmVersion(\"paris\");\n        vm.expectRevert();\n        compute();\n    }\n\n    function compute() internal view {\n        ICreate2Deployer(0x35Da41c476fA5c6De066f20556069096A1F39364).computeAddress(bytes32(0), bytes32(0));\n    }\n}\n   \"#.replace(\"<rpc>\", &endpoint),\n    );\n\n    cmd.args([\"test\", \"--mc\", \"TestEvmVersion\", \"-vvvv\"]).assert_success().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\nRan 1 test for test/TestEvmVersion.t.sol:TestEvmVersion\n[PASS] test_evm_version() ([GAS])\nTraces:\n  [..] TestEvmVersion::test_evm_version()\n    ├─ [0] VM::createSelectFork(\"<rpc url>\")\n    │   └─ ← [Return] 0\n    ├─ [0] VM::setEvmVersion(\"istanbul\")\n    │   └─ ← [Return]\n    ├─ [0] VM::getEvmVersion() [staticcall]\n    │   └─ ← [Return] \"istanbul\"\n    ├─ [0] VM::expectRevert(custom error 0xf4844814)\n    │   └─ ← [Return]\n    ├─ [..] 0x35Da41c476fA5c6De066f20556069096A1F39364::computeAddress(0x0000000000000000000000000000000000000000000000000000000000000000, 0x0000000000000000000000000000000000000000000000000000000000000000) [staticcall]\n    │   └─ ← [NotActivated] EvmError: NotActivated\n    ├─ [0] VM::setEvmVersion(\"shanghai\")\n    │   └─ ← [Return]\n    ├─ [0] VM::getEvmVersion() [staticcall]\n    │   └─ ← [Return] \"shanghai\"\n    ├─ [..] 0x35Da41c476fA5c6De066f20556069096A1F39364::computeAddress(0x0000000000000000000000000000000000000000000000000000000000000000, 0x0000000000000000000000000000000000000000000000000000000000000000) [staticcall]\n    │   └─ ← [Return] 0x0f40d7B7669e3a6683EaB25358318fd42a9F2342\n    ├─ [0] VM::setEvmVersion(\"paris\")\n    │   └─ ← [Return]\n    ├─ [0] VM::expectRevert(custom error 0xf4844814)\n    │   └─ ← [Return]\n    ├─ [..] 0x35Da41c476fA5c6De066f20556069096A1F39364::computeAddress(0x0000000000000000000000000000000000000000000000000000000000000000, 0x0000000000000000000000000000000000000000000000000000000000000000) [staticcall]\n    │   └─ ← [NotActivated] EvmError: NotActivated\n    └─ ← [Stop]\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests)\n\n\"#]]);\n\n    // Test evm version set in `setUp` is accounted in test.\n    prj.add_test(\n        \"TestSetupEvmVersion.t.sol\",\n        &r#\"\nimport {Test} from \"forge-std/Test.sol\";\n\ninterface EvmVm {\n    function getEvmVersion() external pure returns (string memory evm);\n    function setEvmVersion(string calldata evm) external;\n}\n\ninterface ICreate2Deployer {\n    function computeAddress(bytes32 salt, bytes32 codeHash) external view returns (address);\n}\n\nEvmVm constant evm = EvmVm(address(bytes20(uint160(uint256(keccak256(\"hevm cheat code\"))))));\n\ncontract TestSetupEvmVersion is Test {\n    function setUp() public {\n        evm.setEvmVersion(\"istanbul\");\n    }\n\n    function test_evm_version_in_setup() public {\n        vm.createSelectFork(\"<rpc>\");\n        // revert with NotActivated for istanbul\n        ICreate2Deployer(0x35Da41c476fA5c6De066f20556069096A1F39364).computeAddress(bytes32(0), bytes32(0));\n    }\n}\n   \"#.replace(\"<rpc>\", &endpoint),\n    );\n    cmd.forge_fuse()\n        .args([\"test\", \"--mc\", \"TestSetupEvmVersion\", \"-vvvv\"])\n        .assert_failure()\n        .stdout_eq(str![[r#\"\n...\n[FAIL: EvmError: NotActivated] test_evm_version_in_setup() ([GAS])\nTraces:\n  [..] TestSetupEvmVersion::setUp()\n    ├─ [0] VM::setEvmVersion(\"istanbul\")\n    │   └─ ← [Return]\n    └─ ← [Stop]\n\n  [..] TestSetupEvmVersion::test_evm_version_in_setup()\n    └─ ← [NotActivated] EvmError: NotActivated\n...\n\n\"#]]);\n\n    // Test evm version set in constructor is accounted in test.\n    prj.add_test(\n        \"TestConstructorEvmVersion.t.sol\",\n        &r#\"\nimport {Test} from \"forge-std/Test.sol\";\n\ninterface EvmVm {\n    function getEvmVersion() external pure returns (string memory evm);\n    function setEvmVersion(string calldata evm) external;\n}\n\ninterface ICreate2Deployer {\n    function computeAddress(bytes32 salt, bytes32 codeHash) external view returns (address);\n}\n\nEvmVm constant evm = EvmVm(address(bytes20(uint160(uint256(keccak256(\"hevm cheat code\"))))));\n\ncontract TestConstructorEvmVersion is Test {\n    constructor() {\n        evm.setEvmVersion(\"istanbul\");\n    }\n\n    function test_evm_version_in_constructor() public {\n        vm.createSelectFork(\"<rpc>\");\n        // revert with NotActivated for istanbul\n        ICreate2Deployer(0x35Da41c476fA5c6De066f20556069096A1F39364).computeAddress(bytes32(0), bytes32(0));\n    }\n}\n   \"#.replace(\"<rpc>\", &endpoint),\n    );\n    cmd.forge_fuse()\n        .args([\"test\", \"--mc\", \"TestConstructorEvmVersion\", \"-vvvv\"])\n        .assert_failure()\n        .stdout_eq(str![[r#\"\n...\n[FAIL: EvmError: NotActivated] test_evm_version_in_constructor() ([GAS])\nTraces:\n  [..] TestConstructorEvmVersion::test_evm_version_in_constructor()\n    └─ ← [NotActivated] EvmError: NotActivated\n...\n\n\"#]]);\n});\n"
  },
  {
    "path": "crates/forge/tests/cli/test_cmd/table.rs",
    "content": "//! Table tests.\n\nuse foundry_test_utils::{forgetest_init, str};\n\nforgetest_init!(should_run_table_tests, |prj, cmd| {\n    prj.initialize_default_contracts();\n    prj.add_test(\n        \"CounterTable.t.sol\",\n        r#\"\nimport \"forge-std/Test.sol\";\nimport {Counter} from \"../src/Counter.sol\";\n\ncontract CounterTableTest is Test {\n    Counter counter = new Counter();\n\n    uint256[] public fixtureAmount = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];\n    bool[] public fixtureSwap = [true, true, false, true, false, true, false, true, false, true];\n    bool[] public fixtureDiffSwap = [true, false];\n    function fixtureNoFixture() public returns (address[] memory) {\n    }\n\n    function tableWithNoParamFail() public {\n        counter.increment();\n    }\n\n    function tableWithParamNoFixtureFail(uint256 noFixture) public {\n        require(noFixture != 100);\n        counter.increment();\n    }\n\n    function tableSingleParamPass(uint256 amount) public {\n        require(amount != 100, \"Amount cannot be 100\");\n        counter.increment();\n    }\n\n    function tableSingleParamFail(uint256 amount) public {\n        require(amount != 10, \"Amount cannot be 10\");\n        counter.increment();\n    }\n\n    function tableMultipleParamsNoParamFail(uint256 amount, bool noSwap) public {\n        require(amount != 100 && noSwap, \"Amount cannot be 100\");\n        counter.increment();\n    }\n\n    function tableMultipleParamsDifferentFixturesFail(uint256 amount, bool diffSwap) public {\n        require(amount != 100 && diffSwap, \"Amount cannot be 100\");\n        counter.increment();\n    }\n\n    function tableMultipleParamsFail(uint256 amount, bool swap) public {\n        require(amount == 3 && swap, \"Cannot swap\");\n        counter.increment();\n    }\n\n    function tableMultipleParamsPass(uint256 amount, bool swap) public {\n        if (amount == 3 && swap) {\n            revert();\n        }\n        counter.increment();\n    }\n}\n    \"#,\n    );\n\n    cmd.args([\"test\", \"--mc\", \"CounterTable\", \"-vvvvv\"]).assert_failure().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\nRan 8 tests for test/CounterTable.t.sol:CounterTableTest\n[FAIL: 2 fixtures defined for diffSwap (expected 10)] tableMultipleParamsDifferentFixturesFail(uint256,bool) ([GAS])\n[FAIL: Cannot swap; counterexample: calldata=0x717892ca00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001 args=[1, true]] tableMultipleParamsFail(uint256,bool) (runs: 1, [AVG_GAS])\nTraces:\n  [..] CounterTableTest::tableMultipleParamsFail(1, true)\n    └─ ← [Revert] Cannot swap\n\nBacktrace:\n  at CounterTableTest.tableMultipleParamsFail (test/CounterTable.t.sol:[..]:[..])\n\n[FAIL: No fixture defined for param noSwap] tableMultipleParamsNoParamFail(uint256,bool) ([GAS])\n[PASS] tableMultipleParamsPass(uint256,bool) (runs: 10, [AVG_GAS])\nTraces:\n  [..] CounterTableTest::tableMultipleParamsPass(10, true)\n    ├─ [..] Counter::increment()\n    │   ├─  storage changes:\n    │   │   @ 0: 0 → 1\n    │   └─ ← [Stop]\n    └─ ← [Stop]\n\n[FAIL: Amount cannot be 10; counterexample: calldata=0x44fa2375000000000000000000000000000000000000000000000000000000000000000a args=[10]] tableSingleParamFail(uint256) (runs: 10, [AVG_GAS])\nTraces:\n  [..] CounterTableTest::tableSingleParamFail(10)\n    └─ ← [Revert] Amount cannot be 10\n\nBacktrace:\n  at CounterTableTest.tableSingleParamFail (test/CounterTable.t.sol:[..]:[..])\n\n[PASS] tableSingleParamPass(uint256) (runs: 10, [AVG_GAS])\nTraces:\n  [..] CounterTableTest::tableSingleParamPass(10)\n    ├─ [..] Counter::increment()\n    │   ├─  storage changes:\n    │   │   @ 0: 0 → 1\n    │   └─ ← [Stop]\n    └─ ← [Stop]\n\n[FAIL: Table test should have at least one parameter] tableWithNoParamFail() ([GAS])\n[FAIL: Table test should have at least one fixture] tableWithParamNoFixtureFail(uint256) ([GAS])\nSuite result: FAILED. 2 passed; 6 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 2 tests passed, 6 failed, 0 skipped (8 total tests)\n\nFailing tests:\nEncountered 6 failing tests in test/CounterTable.t.sol:CounterTableTest\n[FAIL: 2 fixtures defined for diffSwap (expected 10)] tableMultipleParamsDifferentFixturesFail(uint256,bool) ([GAS])\n[FAIL: Cannot swap; counterexample: calldata=0x717892ca00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001 args=[1, true]] tableMultipleParamsFail(uint256,bool) (runs: 1, [AVG_GAS])\n[FAIL: No fixture defined for param noSwap] tableMultipleParamsNoParamFail(uint256,bool) ([GAS])\n[FAIL: Amount cannot be 10; counterexample: calldata=0x44fa2375000000000000000000000000000000000000000000000000000000000000000a args=[10]] tableSingleParamFail(uint256) (runs: 10, [AVG_GAS])\n[FAIL: Table test should have at least one parameter] tableWithNoParamFail() ([GAS])\n[FAIL: Table test should have at least one fixture] tableWithParamNoFixtureFail(uint256) ([GAS])\n\nEncountered a total of 6 failing tests, 2 tests succeeded\n\nTip: Run `forge test --rerun` to retry only the 6 failed tests\n\n\"#]]);\n});\n\n// Table tests should show logs and contribute to coverage.\n// <https://github.com/foundry-rs/foundry/issues/11066>\nforgetest_init!(should_show_logs_and_add_coverage, |prj, cmd| {\n    prj.add_source(\n        \"Counter.sol\",\n        r#\"\ncontract Counter {\n    uint256 public number;\n\n    function setNumber(uint256 a, uint256 b) public {\n        if (a == 1) {\n            number = b + 1;\n        } else if (a == 2) {\n            number = b + 2;\n        } else if (a == 3) {\n            number = b + 3;\n        } else {\n            number = a + b;\n        }\n    }\n}\n    \"#,\n    );\n    prj.add_test(\n        \"CounterTest.t.sol\",\n        r#\"\nimport \"forge-std/Test.sol\";\nimport {Counter} from \"../src/Counter.sol\";\n\ncontract CounterTest is Test {\n    struct TestCase {\n        uint256 a;\n        uint256 b;\n        uint256 expected;\n    }\n\n    Counter public counter;\n\n    function setUp() public {\n        counter = new Counter();\n    }\n\n    function fixtureNumbers() public pure returns (TestCase[] memory) {\n        TestCase[] memory entries = new TestCase[](4);\n        entries[0] = TestCase(1, 5, 6);\n        entries[1] = TestCase(2, 10, 12);\n        entries[2] = TestCase(3, 11, 14);\n        entries[3] = TestCase(4, 11, 15);\n        return entries;\n    }\n\n    function tableSetNumberTest(TestCase memory numbers) public {\n        console.log(\"expected\", numbers.expected);\n        counter.setNumber(numbers.a, numbers.b);\n        require(counter.number() == numbers.expected, \"test failed\");\n    }\n}\n    \"#,\n    );\n\n    cmd.args([\"test\", \"-vvv\"]).assert_success().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\nRan 1 test for test/CounterTest.t.sol:CounterTest\n[PASS] tableSetNumberTest((uint256,uint256,uint256)) (runs: 4, [AVG_GAS])\nLogs:\n  expected 6\n  expected 12\n  expected 14\n  expected 15\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests)\n\n\"#]]);\n\n    cmd.forge_fuse().args([\"coverage\"]).assert_success().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\nAnalysing contracts...\nRunning tests...\n\nRan 1 test for test/CounterTest.t.sol:CounterTest\n[PASS] tableSetNumberTest((uint256,uint256,uint256)) (runs: 4, [AVG_GAS])\nSuite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests)\n\n╭-----------------+---------------+---------------+---------------+---------------╮\n| File            | % Lines       | % Statements  | % Branches    | % Funcs       |\n+=================================================================================+\n| src/Counter.sol | 100.00% (8/8) | 100.00% (7/7) | 100.00% (6/6) | 100.00% (1/1) |\n|-----------------+---------------+---------------+---------------+---------------|\n| Total           | 100.00% (8/8) | 100.00% (7/7) | 100.00% (6/6) | 100.00% (1/1) |\n╰-----------------+---------------+---------------+---------------+---------------╯\n\n\"#]]);\n});\n"
  },
  {
    "path": "crates/forge/tests/cli/test_cmd/trace.rs",
    "content": "//! Tests for tracing functionality\n\nuse foundry_test_utils::str;\n\nforgetest_init!(conflicting_signatures, |prj, cmd| {\n    prj.add_test(\n        \"ConflictingSignatures.t.sol\",\n        r#\"\npragma solidity ^0.8.18;\n\nimport \"forge-std/Test.sol\";\n\ncontract ReturnsNothing {\n    function func() public pure {}\n}\n\ncontract ReturnsString {\n    function func() public pure returns (string memory) {\n        return \"string\";\n    }\n}\n\ncontract ReturnsUint {\n    function func() public pure returns (uint256) {\n        return 1;\n    }\n}\n\ncontract ConflictingSignaturesTest is Test {\n    ReturnsNothing retsNothing;\n    ReturnsString retsString;\n    ReturnsUint retsUint;\n\n    function setUp() public {\n        retsNothing = new ReturnsNothing();\n        retsString = new ReturnsString();\n        retsUint = new ReturnsUint();\n    }\n\n    /// Tests that traces are decoded properly when multiple\n    /// functions have the same 4byte signature, but different\n    /// return values.\n    function testTraceWithConflictingSignatures() public {\n        retsNothing.func();\n        retsString.func();\n        retsUint.func();\n    }\n}\n\"#,\n    );\n\n    cmd.args([\"test\", \"-vvvvv\"]).assert_success().stdout_eq(str![[r#\"\n...\nRan 1 test for test/ConflictingSignatures.t.sol:ConflictingSignaturesTest\n[PASS] testTraceWithConflictingSignatures() ([GAS])\nTraces:\n  [..] ConflictingSignaturesTest::setUp()\n    ├─ [..] → new ReturnsNothing@0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f\n    │   └─ ← [Return] 106 bytes of code\n    ├─ [..] → new ReturnsString@0x2e234DAe75C793f67A35089C9d99245E1C58470b\n    │   └─ ← [Return] 334 bytes of code\n    ├─ [..] → new ReturnsUint@0xF62849F9A0B5Bf2913b396098F7c7019b51A820a\n    │   └─ ← [Return] 175 bytes of code\n    └─ ← [Stop]\n\n  [..] ConflictingSignaturesTest::testTraceWithConflictingSignatures()\n    ├─ [..] ReturnsNothing::func() [staticcall]\n    │   └─ ← [Stop]\n    ├─ [..] ReturnsString::func() [staticcall]\n    │   └─ ← [Return] 0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000006737472696e670000000000000000000000000000000000000000000000000000\n    ├─ [..] ReturnsUint::func() [staticcall]\n    │   └─ ← [Return] 0x0000000000000000000000000000000000000000000000000000000000000001\n    └─ ← [Stop]\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests)\n\n\"#]]);\n});\n\n#[cfg(not(feature = \"isolate-by-default\"))]\nforgetest_init!(trace_test, |prj, cmd| {\n    prj.add_test(\n        \"Trace.t.sol\",\n        r#\"\npragma solidity ^0.8.18;\n\nimport \"forge-std/Test.sol\";\n\ncontract RecursiveCall {\n    TraceTest factory;\n\n    event Depth(uint256 depth);\n    event ChildDepth(uint256 childDepth);\n    event CreatedChild(uint256 childDepth);\n\n    constructor(address _factory) {\n        factory = TraceTest(_factory);\n    }\n\n    function recurseCall(uint256 neededDepth, uint256 depth) public returns (uint256) {\n        if (depth == neededDepth) {\n            this.negativeNum();\n            return neededDepth;\n        }\n\n        uint256 childDepth = this.recurseCall(neededDepth, depth + 1);\n        emit ChildDepth(childDepth);\n\n        this.someCall();\n        emit Depth(depth);\n\n        return depth;\n    }\n\n    function recurseCreate(uint256 neededDepth, uint256 depth) public returns (uint256) {\n        if (depth == neededDepth) {\n            return neededDepth;\n        }\n\n        RecursiveCall child = factory.create();\n        emit CreatedChild(depth + 1);\n\n        uint256 childDepth = child.recurseCreate(neededDepth, depth + 1);\n        emit ChildDepth(childDepth);\n        emit Depth(depth);\n\n        return depth;\n    }\n\n    function someCall() public pure {}\n\n    function negativeNum() public pure returns (int256) {\n        return -1000000000;\n    }\n}\n\ncontract TraceTest is Test {\n    uint256 nodeId = 0;\n    RecursiveCall first;\n\n    function setUp() public {\n        first = this.create();\n    }\n\n    function create() public returns (RecursiveCall) {\n        RecursiveCall node = new RecursiveCall(address(this));\n        vm.label(address(node), string(abi.encodePacked(\"Node \", uintToString(nodeId++))));\n\n        return node;\n    }\n\n    function testRecurseCall() public {\n        first.recurseCall(8, 0);\n    }\n\n    function testRecurseCreate() public {\n        first.recurseCreate(8, 0);\n    }\n}\n\nfunction uintToString(uint256 value) pure returns (string memory) {\n    // Taken from OpenZeppelin\n    if (value == 0) {\n        return \"0\";\n    }\n    uint256 temp = value;\n    uint256 digits;\n    while (temp != 0) {\n        digits++;\n        temp /= 10;\n    }\n    bytes memory buffer = new bytes(digits);\n    while (value != 0) {\n        digits -= 1;\n        buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n        value /= 10;\n    }\n    return string(buffer);\n}\n\"#,\n    );\n\n    cmd.args([\"test\", \"-vvvvv\"]).assert_success().stdout_eq(str![[r#\"\n...\nRan 2 tests for test/Trace.t.sol:TraceTest\n[PASS] testRecurseCall() ([GAS])\nTraces:\n  [..] TraceTest::setUp()\n    ├─ [..] TraceTest::create()\n    │   ├─ [..] → new Node 0@0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f\n    │   │   └─ ← [Return] 1911 bytes of code\n    │   ├─ [0] VM::label(Node 0: [0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f], \"Node 0\")\n    │   │   └─ ← [Return]\n    │   └─ ← [Return] Node 0: [0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f]\n    └─ ← [Stop]\n\n  [..] TraceTest::testRecurseCall()\n    ├─ [..] Node 0::recurseCall(8, 0)\n    │   ├─ [..] Node 0::recurseCall(8, 1)\n    │   │   ├─ [..] Node 0::recurseCall(8, 2)\n    │   │   │   ├─ [..] Node 0::recurseCall(8, 3)\n    │   │   │   │   ├─ [..] Node 0::recurseCall(8, 4)\n    │   │   │   │   │   ├─ [..] Node 0::recurseCall(8, 5)\n    │   │   │   │   │   │   ├─ [..] Node 0::recurseCall(8, 6)\n    │   │   │   │   │   │   │   ├─ [..] Node 0::recurseCall(8, 7)\n    │   │   │   │   │   │   │   │   ├─ [..] Node 0::recurseCall(8, 8)\n    │   │   │   │   │   │   │   │   │   ├─ [..] Node 0::negativeNum() [staticcall]\n    │   │   │   │   │   │   │   │   │   │   └─ ← [Return] -1000000000 [-1e9]\n    │   │   │   │   │   │   │   │   │   └─ ← [Return] 8\n    │   │   │   │   │   │   │   │   ├─ emit ChildDepth(childDepth: 8)\n    │   │   │   │   │   │   │   │   ├─ [..] Node 0::someCall() [staticcall]\n    │   │   │   │   │   │   │   │   │   └─ ← [Stop]\n    │   │   │   │   │   │   │   │   ├─ emit Depth(depth: 7)\n    │   │   │   │   │   │   │   │   └─ ← [Return] 7\n    │   │   │   │   │   │   │   ├─ emit ChildDepth(childDepth: 7)\n    │   │   │   │   │   │   │   ├─ [..] Node 0::someCall() [staticcall]\n    │   │   │   │   │   │   │   │   └─ ← [Stop]\n    │   │   │   │   │   │   │   ├─ emit Depth(depth: 6)\n    │   │   │   │   │   │   │   └─ ← [Return] 6\n    │   │   │   │   │   │   ├─ emit ChildDepth(childDepth: 6)\n    │   │   │   │   │   │   ├─ [..] Node 0::someCall() [staticcall]\n    │   │   │   │   │   │   │   └─ ← [Stop]\n    │   │   │   │   │   │   ├─ emit Depth(depth: 5)\n    │   │   │   │   │   │   └─ ← [Return] 5\n    │   │   │   │   │   ├─ emit ChildDepth(childDepth: 5)\n    │   │   │   │   │   ├─ [..] Node 0::someCall() [staticcall]\n    │   │   │   │   │   │   └─ ← [Stop]\n    │   │   │   │   │   ├─ emit Depth(depth: 4)\n    │   │   │   │   │   └─ ← [Return] 4\n    │   │   │   │   ├─ emit ChildDepth(childDepth: 4)\n    │   │   │   │   ├─ [..] Node 0::someCall() [staticcall]\n    │   │   │   │   │   └─ ← [Stop]\n    │   │   │   │   ├─ emit Depth(depth: 3)\n    │   │   │   │   └─ ← [Return] 3\n    │   │   │   ├─ emit ChildDepth(childDepth: 3)\n    │   │   │   ├─ [..] Node 0::someCall() [staticcall]\n    │   │   │   │   └─ ← [Stop]\n    │   │   │   ├─ emit Depth(depth: 2)\n    │   │   │   └─ ← [Return] 2\n    │   │   ├─ emit ChildDepth(childDepth: 2)\n    │   │   ├─ [..] Node 0::someCall() [staticcall]\n    │   │   │   └─ ← [Stop]\n    │   │   ├─ emit Depth(depth: 1)\n    │   │   └─ ← [Return] 1\n    │   ├─ emit ChildDepth(childDepth: 1)\n    │   ├─ [..] Node 0::someCall() [staticcall]\n    │   │   └─ ← [Stop]\n    │   ├─ emit Depth(depth: 0)\n    │   └─ ← [Return] 0\n    └─ ← [Stop]\n\n[PASS] testRecurseCreate() ([GAS])\nTraces:\n  [..] TraceTest::setUp()\n    ├─ [..] TraceTest::create()\n    │   ├─ [..] → new Node 0@0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f\n    │   │   └─ ← [Return] 1911 bytes of code\n    │   ├─ [0] VM::label(Node 0: [0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f], \"Node 0\")\n    │   │   └─ ← [Return]\n    │   └─ ← [Return] Node 0: [0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f]\n    └─ ← [Stop]\n\n  [..] TraceTest::testRecurseCreate()\n    ├─ [..] Node 0::recurseCreate(8, 0)\n    │   ├─ [..] TraceTest::create()\n    │   │   ├─ [..] → new Node 1@0x2e234DAe75C793f67A35089C9d99245E1C58470b\n    │   │   │   ├─  storage changes:\n    │   │   │   │   @ 0: 0 → 0x0000000000000000000000007fa9385be102ac3eac297483dd6233d62b3e1496\n    │   │   │   └─ ← [Return] 1911 bytes of code\n    │   │   ├─ [0] VM::label(Node 1: [0x2e234DAe75C793f67A35089C9d99245E1C58470b], \"Node 1\")\n    │   │   │   └─ ← [Return]\n    │   │   ├─  storage changes:\n    │   │   │   @ 32: 1 → 2\n    │   │   └─ ← [Return] Node 1: [0x2e234DAe75C793f67A35089C9d99245E1C58470b]\n    │   ├─ emit CreatedChild(childDepth: 1)\n    │   ├─ [..] Node 1::recurseCreate(8, 1)\n    │   │   ├─ [..] TraceTest::create()\n    │   │   │   ├─ [..] → new Node 2@0xF62849F9A0B5Bf2913b396098F7c7019b51A820a\n    │   │   │   │   ├─  storage changes:\n    │   │   │   │   │   @ 0: 0 → 0x0000000000000000000000007fa9385be102ac3eac297483dd6233d62b3e1496\n    │   │   │   │   └─ ← [Return] 1911 bytes of code\n    │   │   │   ├─ [0] VM::label(Node 2: [0xF62849F9A0B5Bf2913b396098F7c7019b51A820a], \"Node 2\")\n    │   │   │   │   └─ ← [Return]\n    │   │   │   ├─  storage changes:\n    │   │   │   │   @ 32: 2 → 3\n    │   │   │   └─ ← [Return] Node 2: [0xF62849F9A0B5Bf2913b396098F7c7019b51A820a]\n    │   │   ├─ emit CreatedChild(childDepth: 2)\n    │   │   ├─ [..] Node 2::recurseCreate(8, 2)\n    │   │   │   ├─ [..] TraceTest::create()\n    │   │   │   │   ├─ [..] → new Node 3@0x5991A2dF15A8F6A256D3Ec51E99254Cd3fb576A9\n    │   │   │   │   │   ├─  storage changes:\n    │   │   │   │   │   │   @ 0: 0 → 0x0000000000000000000000007fa9385be102ac3eac297483dd6233d62b3e1496\n    │   │   │   │   │   └─ ← [Return] 1911 bytes of code\n    │   │   │   │   ├─ [0] VM::label(Node 3: [0x5991A2dF15A8F6A256D3Ec51E99254Cd3fb576A9], \"Node 3\")\n    │   │   │   │   │   └─ ← [Return]\n    │   │   │   │   ├─  storage changes:\n    │   │   │   │   │   @ 32: 3 → 4\n    │   │   │   │   └─ ← [Return] Node 3: [0x5991A2dF15A8F6A256D3Ec51E99254Cd3fb576A9]\n    │   │   │   ├─ emit CreatedChild(childDepth: 3)\n    │   │   │   ├─ [..] Node 3::recurseCreate(8, 3)\n    │   │   │   │   ├─ [..] TraceTest::create()\n    │   │   │   │   │   ├─ [..] → new Node 4@0xc7183455a4C133Ae270771860664b6B7ec320bB1\n    │   │   │   │   │   │   ├─  storage changes:\n    │   │   │   │   │   │   │   @ 0: 0 → 0x0000000000000000000000007fa9385be102ac3eac297483dd6233d62b3e1496\n    │   │   │   │   │   │   └─ ← [Return] 1911 bytes of code\n    │   │   │   │   │   ├─ [0] VM::label(Node 4: [0xc7183455a4C133Ae270771860664b6B7ec320bB1], \"Node 4\")\n    │   │   │   │   │   │   └─ ← [Return]\n    │   │   │   │   │   ├─  storage changes:\n    │   │   │   │   │   │   @ 32: 4 → 5\n    │   │   │   │   │   └─ ← [Return] Node 4: [0xc7183455a4C133Ae270771860664b6B7ec320bB1]\n    │   │   │   │   ├─ emit CreatedChild(childDepth: 4)\n    │   │   │   │   ├─ [..] Node 4::recurseCreate(8, 4)\n    │   │   │   │   │   ├─ [..] TraceTest::create()\n    │   │   │   │   │   │   ├─ [..] → new Node 5@0xa0Cb889707d426A7A386870A03bc70d1b0697598\n    │   │   │   │   │   │   │   ├─  storage changes:\n    │   │   │   │   │   │   │   │   @ 0: 0 → 0x0000000000000000000000007fa9385be102ac3eac297483dd6233d62b3e1496\n    │   │   │   │   │   │   │   └─ ← [Return] 1911 bytes of code\n    │   │   │   │   │   │   ├─ [0] VM::label(Node 5: [0xa0Cb889707d426A7A386870A03bc70d1b0697598], \"Node 5\")\n    │   │   │   │   │   │   │   └─ ← [Return]\n    │   │   │   │   │   │   ├─  storage changes:\n    │   │   │   │   │   │   │   @ 32: 5 → 6\n    │   │   │   │   │   │   └─ ← [Return] Node 5: [0xa0Cb889707d426A7A386870A03bc70d1b0697598]\n    │   │   │   │   │   ├─ emit CreatedChild(childDepth: 5)\n    │   │   │   │   │   ├─ [..] Node 5::recurseCreate(8, 5)\n    │   │   │   │   │   │   ├─ [..] TraceTest::create()\n    │   │   │   │   │   │   │   ├─ [..] → new Node 6@0x1d1499e622D69689cdf9004d05Ec547d650Ff211\n    │   │   │   │   │   │   │   │   ├─  storage changes:\n    │   │   │   │   │   │   │   │   │   @ 0: 0 → 0x0000000000000000000000007fa9385be102ac3eac297483dd6233d62b3e1496\n    │   │   │   │   │   │   │   │   └─ ← [Return] 1911 bytes of code\n    │   │   │   │   │   │   │   ├─ [0] VM::label(Node 6: [0x1d1499e622D69689cdf9004d05Ec547d650Ff211], \"Node 6\")\n    │   │   │   │   │   │   │   │   └─ ← [Return]\n    │   │   │   │   │   │   │   ├─  storage changes:\n    │   │   │   │   │   │   │   │   @ 32: 6 → 7\n    │   │   │   │   │   │   │   └─ ← [Return] Node 6: [0x1d1499e622D69689cdf9004d05Ec547d650Ff211]\n    │   │   │   │   │   │   ├─ emit CreatedChild(childDepth: 6)\n    │   │   │   │   │   │   ├─ [..] Node 6::recurseCreate(8, 6)\n    │   │   │   │   │   │   │   ├─ [..] TraceTest::create()\n    │   │   │   │   │   │   │   │   ├─ [..] → new Node 7@0xA4AD4f68d0b91CFD19687c881e50f3A00242828c\n    │   │   │   │   │   │   │   │   │   ├─  storage changes:\n    │   │   │   │   │   │   │   │   │   │   @ 0: 0 → 0x0000000000000000000000007fa9385be102ac3eac297483dd6233d62b3e1496\n    │   │   │   │   │   │   │   │   │   └─ ← [Return] 1911 bytes of code\n    │   │   │   │   │   │   │   │   ├─ [0] VM::label(Node 7: [0xA4AD4f68d0b91CFD19687c881e50f3A00242828c], \"Node 7\")\n    │   │   │   │   │   │   │   │   │   └─ ← [Return]\n    │   │   │   │   │   │   │   │   ├─  storage changes:\n    │   │   │   │   │   │   │   │   │   @ 32: 7 → 8\n    │   │   │   │   │   │   │   │   └─ ← [Return] Node 7: [0xA4AD4f68d0b91CFD19687c881e50f3A00242828c]\n    │   │   │   │   │   │   │   ├─ emit CreatedChild(childDepth: 7)\n    │   │   │   │   │   │   │   ├─ [..] Node 7::recurseCreate(8, 7)\n    │   │   │   │   │   │   │   │   ├─ [..] TraceTest::create()\n    │   │   │   │   │   │   │   │   │   ├─ [..] → new Node 8@0x03A6a84cD762D9707A21605b548aaaB891562aAb\n    │   │   │   │   │   │   │   │   │   │   ├─  storage changes:\n    │   │   │   │   │   │   │   │   │   │   │   @ 0: 0 → 0x0000000000000000000000007fa9385be102ac3eac297483dd6233d62b3e1496\n    │   │   │   │   │   │   │   │   │   │   └─ ← [Return] 1911 bytes of code\n    │   │   │   │   │   │   │   │   │   ├─ [0] VM::label(Node 8: [0x03A6a84cD762D9707A21605b548aaaB891562aAb], \"Node 8\")\n    │   │   │   │   │   │   │   │   │   │   └─ ← [Return]\n    │   │   │   │   │   │   │   │   │   ├─  storage changes:\n    │   │   │   │   │   │   │   │   │   │   @ 32: 8 → 9\n    │   │   │   │   │   │   │   │   │   └─ ← [Return] Node 8: [0x03A6a84cD762D9707A21605b548aaaB891562aAb]\n    │   │   │   │   │   │   │   │   ├─ emit CreatedChild(childDepth: 8)\n    │   │   │   │   │   │   │   │   ├─ [..] Node 8::recurseCreate(8, 8)\n    │   │   │   │   │   │   │   │   │   └─ ← [Return] 8\n    │   │   │   │   │   │   │   │   ├─ emit ChildDepth(childDepth: 8)\n    │   │   │   │   │   │   │   │   ├─ emit Depth(depth: 7)\n    │   │   │   │   │   │   │   │   └─ ← [Return] 7\n    │   │   │   │   │   │   │   ├─ emit ChildDepth(childDepth: 7)\n    │   │   │   │   │   │   │   ├─ emit Depth(depth: 6)\n    │   │   │   │   │   │   │   └─ ← [Return] 6\n    │   │   │   │   │   │   ├─ emit ChildDepth(childDepth: 6)\n    │   │   │   │   │   │   ├─ emit Depth(depth: 5)\n    │   │   │   │   │   │   └─ ← [Return] 5\n    │   │   │   │   │   ├─ emit ChildDepth(childDepth: 5)\n    │   │   │   │   │   ├─ emit Depth(depth: 4)\n    │   │   │   │   │   └─ ← [Return] 4\n    │   │   │   │   ├─ emit ChildDepth(childDepth: 4)\n    │   │   │   │   ├─ emit Depth(depth: 3)\n    │   │   │   │   └─ ← [Return] 3\n    │   │   │   ├─ emit ChildDepth(childDepth: 3)\n    │   │   │   ├─ emit Depth(depth: 2)\n    │   │   │   └─ ← [Return] 2\n    │   │   ├─ emit ChildDepth(childDepth: 2)\n    │   │   ├─ emit Depth(depth: 1)\n    │   │   └─ ← [Return] 1\n    │   ├─ emit ChildDepth(childDepth: 1)\n    │   ├─ emit Depth(depth: 0)\n    │   └─ ← [Return] 0\n    └─ ← [Stop]\n\nSuite result: ok. 2 passed; 0 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 2 tests passed, 0 failed, 0 skipped (2 total tests)\n\n\"#]]);\n});\n\n#[cfg(not(feature = \"isolate-by-default\"))]\nforgetest_init!(trace_test_detph, |prj, cmd| {\n    prj.add_test(\n        \"Trace.t.sol\",\n        r#\"\npragma solidity ^0.8.18;\n\nimport \"forge-std/Test.sol\";\n\ncontract RecursiveCall {\n    TraceTest factory;\n\n    event Depth(uint256 depth);\n    event ChildDepth(uint256 childDepth);\n    event CreatedChild(uint256 childDepth);\n\n    constructor(address _factory) {\n        factory = TraceTest(_factory);\n    }\n\n    function recurseCall(uint256 neededDepth, uint256 depth) public returns (uint256) {\n        if (depth == neededDepth) {\n            this.negativeNum();\n            return neededDepth;\n        }\n\n        uint256 childDepth = this.recurseCall(neededDepth, depth + 1);\n        emit ChildDepth(childDepth);\n\n        this.someCall();\n        emit Depth(depth);\n\n        return depth;\n    }\n\n    function recurseCreate(uint256 neededDepth, uint256 depth) public returns (uint256) {\n        if (depth == neededDepth) {\n            return neededDepth;\n        }\n\n        RecursiveCall child = factory.create();\n        emit CreatedChild(depth + 1);\n\n        uint256 childDepth = child.recurseCreate(neededDepth, depth + 1);\n        emit ChildDepth(childDepth);\n        emit Depth(depth);\n\n        return depth;\n    }\n\n    function someCall() public pure {}\n\n    function negativeNum() public pure returns (int256) {\n        return -1000000000;\n    }\n}\n\ncontract TraceTest is Test {\n    uint256 nodeId = 0;\n    RecursiveCall first;\n\n    function setUp() public {\n        first = this.create();\n    }\n\n    function create() public returns (RecursiveCall) {\n        RecursiveCall node = new RecursiveCall(address(this));\n        vm.label(address(node), string(abi.encodePacked(\"Node \", uintToString(nodeId++))));\n\n        return node;\n    }\n\n    function testRecurseCall() public {\n        first.recurseCall(8, 0);\n    }\n\n    function testRecurseCreate() public {\n        first.recurseCreate(8, 0);\n    }\n}\n\nfunction uintToString(uint256 value) pure returns (string memory) {\n    // Taken from OpenZeppelin\n    if (value == 0) {\n        return \"0\";\n    }\n    uint256 temp = value;\n    uint256 digits;\n    while (temp != 0) {\n        digits++;\n        temp /= 10;\n    }\n    bytes memory buffer = new bytes(digits);\n    while (value != 0) {\n        digits -= 1;\n        buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n        value /= 10;\n    }\n    return string(buffer);\n}\n\"#,\n    );\n\n    cmd.args([\"test\", \"-vvvvv\", \"--trace-depth\", \"3\"]).assert_success().stdout_eq(str![[r#\"\n...\nRan 2 tests for test/Trace.t.sol:TraceTest\n[PASS] testRecurseCall() ([GAS])\nTraces:\n  [..] TraceTest::setUp()\n    ├─ [..] TraceTest::create()\n    │   ├─ [..] → new Node 0@0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f\n    │   │   └─ ← [Return] 1911 bytes of code\n    │   ├─ [0] VM::label(Node 0: [0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f], \"Node 0\")\n    │   │   └─ ← [Return]\n    │   └─ ← [Return] Node 0: [0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f]\n    └─ ← [Stop]\n\n  [..] TraceTest::testRecurseCall()\n    ├─ [..] Node 0::recurseCall(8, 0)\n    │   ├─ [..] Node 0::recurseCall(8, 1)\n    │   │   ├─ [..] Node 0::recurseCall(8, 2)\n    │   │   │   └─ ← [Return] 2\n    │   │   ├─ emit ChildDepth(childDepth: 2)\n    │   │   ├─ [..] Node 0::someCall() [staticcall]\n    │   │   │   └─ ← [Stop]\n    │   │   ├─ emit Depth(depth: 1)\n    │   │   └─ ← [Return] 1\n    │   ├─ emit ChildDepth(childDepth: 1)\n    │   ├─ [..] Node 0::someCall() [staticcall]\n    │   │   └─ ← [Stop]\n    │   ├─ emit Depth(depth: 0)\n    │   └─ ← [Return] 0\n    └─ ← [Stop]\n\n[PASS] testRecurseCreate() ([GAS])\nTraces:\n  [..] TraceTest::setUp()\n    ├─ [..] TraceTest::create()\n    │   ├─ [..] → new Node 0@0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f\n    │   │   └─ ← [Return] 1911 bytes of code\n    │   ├─ [0] VM::label(Node 0: [0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f], \"Node 0\")\n    │   │   └─ ← [Return]\n    │   └─ ← [Return] Node 0: [0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f]\n    └─ ← [Stop]\n\n  [..] TraceTest::testRecurseCreate()\n    ├─ [..] Node 0::recurseCreate(8, 0)\n    │   ├─ [..] TraceTest::create()\n    │   │   ├─ [405132] → new Node 1@0x2e234DAe75C793f67A35089C9d99245E1C58470b\n    │   │   │   ├─  storage changes:\n    │   │   │   │   @ 0: 0 → 0x0000000000000000000000007fa9385be102ac3eac297483dd6233d62b3e1496\n    │   │   │   └─ ← [Return] 1911 bytes of code\n    │   │   ├─ [0] VM::label(Node 1: [0x2e234DAe75C793f67A35089C9d99245E1C58470b], \"Node 1\")\n    │   │   │   └─ ← [Return]\n    │   │   ├─  storage changes:\n    │   │   │   @ 32: 1 → 2\n    │   │   └─ ← [Return] Node 1: [0x2e234DAe75C793f67A35089C9d99245E1C58470b]\n    │   ├─ emit CreatedChild(childDepth: 1)\n    │   ├─ [..] Node 1::recurseCreate(8, 1)\n    │   │   ├─ [..] TraceTest::create()\n    │   │   │   ├─  storage changes:\n    │   │   │   │   @ 32: 2 → 3\n    │   │   │   └─ ← [Return] Node 2: [0xF62849F9A0B5Bf2913b396098F7c7019b51A820a]\n    │   │   ├─ emit CreatedChild(childDepth: 2)\n    │   │   ├─ [..] Node 2::recurseCreate(8, 2)\n    │   │   │   └─ ← [Return] 2\n    │   │   ├─ emit ChildDepth(childDepth: 2)\n    │   │   ├─ emit Depth(depth: 1)\n    │   │   └─ ← [Return] 1\n    │   ├─ emit ChildDepth(childDepth: 1)\n    │   ├─ emit Depth(depth: 0)\n    │   └─ ← [Return] 0\n    └─ ← [Stop]\n\nSuite result: ok. 2 passed; 0 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 2 tests passed, 0 failed, 0 skipped (2 total tests)\n\n\"#]]);\n});\n"
  },
  {
    "path": "crates/forge/tests/cli/test_optimizer.rs",
    "content": "//! Tests for the `forge test` with preprocessed cache.\n\n// Test cache is invalidated when `forge build` if optimize test option toggled.\nforgetest_init!(toggle_invalidate_cache_on_build, |prj, cmd| {\n    prj.initialize_default_contracts();\n    prj.update_config(|config| {\n        config.dynamic_test_linking = true;\n    });\n    // All files are built with optimized tests.\n    cmd.args([\"build\"]).with_no_redact().assert_success().stdout_eq(str![[r#\"\n...\nCompiling 23 files with [..]\n...\n\n\"#]]);\n    // No files are rebuilt.\n    cmd.with_no_redact().assert_success().stdout_eq(str![[r#\"\n...\nNo files changed, compilation skipped\n...\n\n\"#]]);\n\n    // Toggle test optimizer off.\n    prj.update_config(|config| {\n        config.dynamic_test_linking = false;\n    });\n    // All files are rebuilt with preprocessed cache false.\n    cmd.with_no_redact().assert_success().stdout_eq(str![[r#\"\n...\nCompiling 23 files with [..]\n...\n\n\"#]]);\n});\n\n// Test cache is invalidated when `forge test` if optimize test option toggled.\nforgetest_init!(toggle_invalidate_cache_on_test, |prj, cmd| {\n    prj.initialize_default_contracts();\n    prj.update_config(|config| {\n        config.dynamic_test_linking = true;\n    });\n    // All files are built with optimized tests.\n    cmd.args([\"test\"]).with_no_redact().assert_success().stdout_eq(str![[r#\"\n...\nCompiling 21 files with [..]\n...\n\n\"#]]);\n    // No files are rebuilt.\n    cmd.with_no_redact().assert_success().stdout_eq(str![[r#\"\n...\nNo files changed, compilation skipped\n...\n\n\"#]]);\n\n    // Toggle test optimizer off.\n    prj.update_config(|config| {\n        config.dynamic_test_linking = false;\n    });\n    // All files are rebuilt with preprocessed cache false.\n    cmd.with_no_redact().assert_success().stdout_eq(str![[r#\"\n...\nCompiling 21 files with [..]\n...\n\n\"#]]);\n});\n\n// Counter contract without interface instantiated in CounterTest\n//\n// ├── src\n// │ └── Counter.sol\n// └── test\n//     └── Counter.t.sol\nforgetest_init!(preprocess_contract_with_no_interface, |prj, cmd| {\n    prj.update_config(|config| {\n        config.dynamic_test_linking = true;\n    });\n\n    prj.add_source(\n        \"Counter.sol\",\n        r#\"\ncontract Counter {\n    uint256 public number;\n\n    function setNumber(uint256 newNumber) public {\n        number = newNumber;\n    }\n\n    function increment() public {\n        number++;\n    }\n}\n    \"#,\n    );\n\n    prj.add_test(\n        \"Counter.t.sol\",\n        r#\"\nimport {Test} from \"forge-std/Test.sol\";\nimport {Counter} from \"../src/Counter.sol\";\n\ncontract CounterTest is Test {\n    Counter public counter;\n\n    function setUp() public {\n        counter = new Counter();\n        counter.setNumber(0);\n    }\n\n    function test_Increment() public {\n        counter.increment();\n        assertEq(counter.number(), 1);\n    }\n\n    function test_SetNumber() public {\n        counter.setNumber(1);\n        assertEq(counter.number(), 1);\n    }\n}\n    \"#,\n    );\n    // All files are compiled on first run.\n    cmd.args([\"test\"]).with_no_redact().assert_success().stdout_eq(str![[r#\"\n...\nCompiling 21 files with [..]\n...\n\n\"#]]);\n\n    // Change Counter implementation to fail both tests.\n    prj.add_source(\n        \"Counter.sol\",\n        r#\"\ncontract Counter {\n    uint256 public number;\n\n    function setNumber(uint256 newNumber) public {\n        number = 12345;\n    }\n\n    function increment() public {\n        number++;\n        number++;\n    }\n}\n    \"#,\n    );\n    // Assert that only 1 file is compiled (Counter source contract) and both tests fail.\n    cmd.with_no_redact().assert_failure().stdout_eq(str![[r#\"\n...\nCompiling 1 files with [..]\n...\n[FAIL: assertion failed: 12347 != 1] test_Increment() (gas: [..])\n[FAIL: assertion failed: 12345 != 1] test_SetNumber() (gas: [..])\n...\n\n\"#]]);\n\n    // Change Counter implementation to fail single test.\n    prj.add_source(\n        \"Counter.sol\",\n        r#\"\ncontract Counter {\n    uint256 public number;\n\n    function setNumber(uint256 newNumber) public {\n        number = 1;\n    }\n\n    function increment() public {\n        number++;\n    }\n}\n    \"#,\n    );\n    // Assert that only 1 file is compiled (Counter source contract) and only one test fails.\n    cmd.with_no_redact().assert_failure().stdout_eq(str![[r#\"\n...\nCompiling 1 files with [..]\n...\n[FAIL: assertion failed: 2 != 1] test_Increment() (gas: [..])\n[PASS] test_SetNumber() (gas: [..])\n...\n\n\"#]]);\n});\n\n// Counter contract with interface instantiated in CounterTest\n//\n// ├── src\n// │ ├── Counter.sol\n// │ └── interface\n// │     └── CounterIf.sol\n// └── test\n//     └── Counter.t.sol\nforgetest_init!(preprocess_contract_with_interface, |prj, cmd| {\n    prj.update_config(|config| {\n        config.dynamic_test_linking = true;\n    });\n\n    prj.add_source(\n        \"interface/CounterIf.sol\",\n        r#\"\ninterface CounterIf {\n    function number() external returns (uint256);\n\n    function setNumber(uint256 newNumber) external;\n\n    function increment() external;\n}\n    \"#,\n    );\n    prj.add_source(\n        \"Counter.sol\",\n        r#\"\nimport {CounterIf} from \"./interface/CounterIf.sol\";\ncontract Counter is CounterIf {\n    uint256 public number;\n    uint256 public anotherNumber;\n\n    function setNumber(uint256 newNumber) public {\n        number = newNumber;\n    }\n\n    function increment() public {\n        number++;\n    }\n}\n    \"#,\n    );\n\n    prj.add_test(\n        \"Counter.t.sol\",\n        r#\"\nimport {Test} from \"forge-std/Test.sol\";\nimport {Counter} from \"../src/Counter.sol\";\n\ncontract CounterTest is Test {\n    Counter public counter;\n\n    function setUp() public {\n        counter = Counter(address(new Counter()));\n        counter.setNumber(0);\n    }\n\n    function test_Increment() public {\n        counter.increment();\n        assertEq(counter.number(), 1);\n    }\n\n    function test_SetNumber() public {\n        counter.setNumber(1);\n        assertEq(counter.number(), 1);\n    }\n}\n    \"#,\n    );\n    // All 21 files are compiled on first run.\n    cmd.args([\"test\"]).with_no_redact().assert_success().stdout_eq(str![[r#\"\n...\nCompiling 22 files with [..]\n...\n\n\"#]]);\n\n    // Change only CounterIf interface.\n    prj.add_source(\n        \"interface/CounterIf.sol\",\n        r#\"\ninterface CounterIf {\n    function anotherNumber() external returns (uint256);\n\n    function number() external returns (uint256);\n\n    function setNumber(uint256 newNumber) external;\n\n    function increment() external;\n}\n    \"#,\n    );\n    // All 3 files (interface, implementation and test) are compiled.\n    cmd.with_no_redact().assert_success().stdout_eq(str![[r#\"\n...\nCompiling 3 files with [..]\n...\n\n\"#]]);\n\n    // Change Counter implementation to fail both tests.\n    prj.add_source(\n        \"Counter.sol\",\n        r#\"\nimport {CounterIf} from \"./interface/CounterIf.sol\";\ncontract Counter is CounterIf {\n    uint256 public number;\n    uint256 public anotherNumber;\n\n    function setNumber(uint256 newNumber) public {\n        number = 12345;\n    }\n\n    function increment() public {\n        number++;\n        number++;\n    }\n}\n    \"#,\n    );\n    // Assert that only 1 file is compiled (Counter source contract) and both tests fail.\n    cmd.with_no_redact().assert_failure().stdout_eq(str![[r#\"\n...\nCompiling 1 files with [..]\n...\n[FAIL: assertion failed: 12347 != 1] test_Increment() (gas: [..])\n[FAIL: assertion failed: 12345 != 1] test_SetNumber() (gas: [..])\n...\n\n\"#]]);\n});\n\n// - Counter contract instantiated in CounterMock\n// - CounterMock instantiated in CounterTest\n//\n// ├── src\n// │ └── Counter.sol\n// └── test\n//     ├── Counter.t.sol\n//     └── mock\n//         └── CounterMock.sol\nforgetest_init!(preprocess_mock_without_inheritance, |prj, cmd| {\n    prj.update_config(|config| {\n        config.dynamic_test_linking = true;\n    });\n\n    prj.add_source(\n        \"Counter.sol\",\n        r#\"\ncontract Counter {\n    uint256 public number;\n\n    function setNumber(uint256 newNumber) public {\n        number = newNumber;\n    }\n\n    function increment() public {\n        number++;\n    }\n}\n    \"#,\n    );\n\n    prj.add_test(\n        \"mock/CounterMock.sol\",\n        r#\"\nimport {Test} from \"forge-std/Test.sol\";\nimport {Counter} from \"src/Counter.sol\";\n\ncontract CounterMock {\n    Counter counter = new Counter();\n\n    function setNumber(uint256 newNumber) public {\n        counter.setNumber(newNumber);\n    }\n\n    function increment() public {\n        counter.increment();\n    }\n\n    function number() public returns (uint256) {\n        return counter.number();\n    }\n}\n    \"#,\n    );\n    prj.add_test(\n        \"Counter.t.sol\",\n        r#\"\nimport {Test} from \"forge-std/Test.sol\";\nimport {CounterMock} from \"./mock/CounterMock.sol\";\n\ncontract CounterTest is Test {\n    CounterMock public counter;\n\n    function setUp() public {\n        counter = new CounterMock();\n        counter.setNumber(0);\n    }\n\n    function test_Increment() public {\n        counter.increment();\n        assertEq(counter.number(), 1);\n    }\n\n    function test_SetNumber() public {\n        counter.setNumber(1);\n        assertEq(counter.number(), 1);\n    }\n}\n    \"#,\n    );\n    // 20 files plus one mock file are compiled on first run.\n    cmd.args([\"test\"]).with_no_redact().assert_success().stdout_eq(str![[r#\"\n...\nCompiling 22 files with [..]\n...\n\n\"#]]);\n\n    // Change Counter contract implementation to fail both tests.\n    prj.add_source(\n        \"Counter.sol\",\n        r#\"\ncontract Counter {\n    uint256 public number;\n\n    function setNumber(uint256 newNumber) public {\n        number = 12345;\n    }\n\n    function increment() public {\n        number++;\n        number++;\n    }\n}\n    \"#,\n    );\n    // Assert that only 1 file is compiled (Counter source contract) and both tests fail.\n    cmd.with_no_redact().assert_failure().stdout_eq(str![[r#\"\n...\nCompiling 1 files with [..]\n...\n[FAIL: assertion failed: 12347 != 1] test_Increment() (gas: [..])\n[FAIL: assertion failed: 12345 != 1] test_SetNumber() (gas: [..])\n...\n\n\"#]]);\n\n    // Change CounterMock contract implementation to pass both tests.\n    prj.add_test(\n        \"mock/CounterMock.sol\",\n        r#\"\nimport {Test} from \"forge-std/Test.sol\";\nimport {Counter} from \"src/Counter.sol\";\n\ncontract CounterMock {\n    Counter counter = new Counter();\n\n    function setNumber(uint256 newNumber) public {\n    }\n\n    function increment() public {\n    }\n\n    function number() public returns (uint256) {\n        return 1;\n    }\n}\n    \"#,\n    );\n    // Assert that mock and test files are compiled and no test fails.\n    cmd.with_no_redact().assert_success().stdout_eq(str![[r#\"\n...\nCompiling 2 files with [..]\n...\n[PASS] test_Increment() (gas: [..])\n[PASS] test_SetNumber() (gas: [..])\n...\n\n\"#]]);\n});\n\n// - CounterMock contract is Counter contract\n// - CounterMock instantiated in CounterTest\n//\n// ├── src\n// │ └── Counter.sol\n// └── test\n//    ├── Counter.t.sol\n//    └── mock\n//        └── CounterMock.sol\nforgetest_init!(preprocess_mock_with_inheritance, |prj, cmd| {\n    prj.update_config(|config| {\n        config.dynamic_test_linking = true;\n    });\n\n    prj.add_source(\n        \"Counter.sol\",\n        r#\"\ncontract Counter {\n    uint256 public number;\n\n    function setNumber(uint256 newNumber) public {\n        number = newNumber;\n    }\n\n    function increment() public {\n        number++;\n    }\n}\n    \"#,\n    );\n\n    prj.add_test(\n        \"mock/CounterMock.sol\",\n        r#\"\nimport {Counter} from \"src/Counter.sol\";\n\ncontract CounterMock is Counter {\n}\n    \"#,\n    );\n    prj.add_test(\n        \"Counter.t.sol\",\n        r#\"\nimport {Test} from \"forge-std/Test.sol\";\nimport {CounterMock} from \"./mock/CounterMock.sol\";\n\ncontract CounterTest is Test {\n    CounterMock public counter;\n\n    function setUp() public {\n        counter = new CounterMock();\n        counter.setNumber(0);\n    }\n\n    function test_Increment() public {\n        counter.increment();\n        assertEq(counter.number(), 1);\n    }\n\n    function test_SetNumber() public {\n        counter.setNumber(1);\n        assertEq(counter.number(), 1);\n    }\n}\n    \"#,\n    );\n    // 20 files plus one mock file are compiled on first run.\n    cmd.args([\"test\"]).with_no_redact().assert_success().stdout_eq(str![[r#\"\n...\nCompiling 22 files with [..]\n...\n\n\"#]]);\n\n    // Change Counter contract implementation to fail both tests.\n    prj.add_source(\n        \"Counter.sol\",\n        r#\"\ncontract Counter {\n    uint256 public number;\n\n    function setNumber(uint256) public virtual {\n        number = 12345;\n    }\n\n    function increment() public virtual {\n        number++;\n        number++;\n    }\n}\n    \"#,\n    );\n    // Assert Counter source contract and CounterTest test contract (as it imports mock) are\n    // compiled and both tests fail.\n    cmd.with_no_redact().assert_failure().stdout_eq(str![[r#\"\n...\nCompiling 3 files with [..]\n...\n[FAIL: assertion failed: 12347 != 1] test_Increment() (gas: [..])\n[FAIL: assertion failed: 12345 != 1] test_SetNumber() (gas: [..])\n...\n\n\"#]]);\n\n    // Change mock implementation to pass both tests.\n    prj.add_test(\n        \"mock/CounterMock.sol\",\n        r#\"\nimport {Counter} from \"src/Counter.sol\";\n\ncontract CounterMock is Counter {\n    function setNumber(uint256 newNumber) public override {\n        number = newNumber;\n    }\n\n    function increment() public override {\n        number++;\n    }\n}\n    \"#,\n    );\n    // Assert that CounterMock and CounterTest files are compiled and no test fails.\n    cmd.with_no_redact().assert_success().stdout_eq(str![[r#\"\n...\nCompiling 2 files with [..]\n...\n[PASS] test_Increment() (gas: [..])\n[PASS] test_SetNumber() (gas: [..])\n...\n\n\"#]]);\n});\n\n// - CounterMock contract is Counter contract\n// - CounterMock instantiated in CounterTest\n//\n// ├── src\n// │ └── Counter.sol\n// └── test\n//    ├── Counter.t.sol\n//    └── mock\n//        └── CounterMock.sol\nforgetest_init!(preprocess_mock_to_non_mock, |prj, cmd| {\n    prj.update_config(|config| {\n        config.dynamic_test_linking = true;\n    });\n\n    prj.add_source(\n        \"Counter.sol\",\n        r#\"\ncontract Counter {\n    uint256 public number;\n\n    function setNumber(uint256 newNumber) public {\n        number = newNumber;\n    }\n\n    function increment() public {\n        number++;\n    }\n}\n    \"#,\n    );\n\n    prj.add_test(\n        \"mock/CounterMock.sol\",\n        r#\"\nimport {Counter} from \"src/Counter.sol\";\n\ncontract CounterMock is Counter {\n}\n    \"#,\n    );\n    prj.add_test(\n        \"Counter.t.sol\",\n        r#\"\nimport {Test} from \"forge-std/Test.sol\";\nimport {CounterMock} from \"./mock/CounterMock.sol\";\n\ncontract CounterTest is Test {\n    CounterMock public counter;\n\n    function setUp() public {\n        counter = new CounterMock();\n        counter.setNumber(0);\n    }\n\n    function test_Increment() public {\n        counter.increment();\n        assertEq(counter.number(), 1);\n    }\n\n    function test_SetNumber() public {\n        counter.setNumber(1);\n        assertEq(counter.number(), 1);\n    }\n}\n    \"#,\n    );\n    // 20 files plus one mock file are compiled on first run.\n    cmd.args([\"test\"]).with_no_redact().assert_success().stdout_eq(str![[r#\"\n...\nCompiling 22 files with [..]\n...\n\n\"#]]);\n    cmd.with_no_redact().assert_success().stdout_eq(str![[r#\"\n...\nNo files changed, compilation skipped\n...\n\n\"#]]);\n\n    // Change mock implementation to fail tests, no inherit from Counter.\n    prj.add_test(\n        \"mock/CounterMock.sol\",\n        r#\"\nimport {Test} from \"forge-std/Test.sol\";\nimport {Counter} from \"src/Counter.sol\";\n\ncontract CounterMock {\n    uint256 public number;\n    function setNumber(uint256 newNumber) public {\n        number = 1234;\n    }\n\n    function increment() public {\n        number = 5678;\n    }\n}\n    \"#,\n    );\n    // Assert that CounterMock and CounterTest files are compiled and tests fail.\n    cmd.with_no_redact().assert_failure().stdout_eq(str![[r#\"\n...\nCompiling 2 files with [..]\n...\n[FAIL: assertion failed: 5678 != 1] test_Increment() (gas: [..])\n[FAIL: assertion failed: 1234 != 1] test_SetNumber() (gas: [..])\n...\n\n\"#]]);\n});\n\n// <https://github.com/foundry-rs/foundry/issues/12452>\n// - CounterMock contract is Counter contract\n// - CounterMock declared in CounterTest\n//\n// ├── src\n// │ └── Counter.sol\n// └── test\n//    ├── Counter.t.sol\nforgetest_init!(preprocess_mock_declared_in_test_contract, |prj, cmd| {\n    prj.update_config(|config| {\n        config.dynamic_test_linking = true;\n    });\n\n    prj.add_source(\n        \"Counter.sol\",\n        r#\"\ncontract Counter {\n    function add(uint256 x, uint256 y) public pure returns (uint256) {\n        return x + y;\n    }\n}\n    \"#,\n    );\n\n    prj.add_test(\n        \"Counter.t.sol\",\n        r#\"\nimport {Test} from \"forge-std/Test.sol\";\nimport {Counter} from \"src/Counter.sol\";\n\ncontract CounterMock is Counter {}\n\ncontract CounterTest is Test {\n    function test_add() public {\n        CounterMock impl = new CounterMock();\n        assertEq(impl.add(2, 2), 4);\n    }\n}\n    \"#,\n    );\n    // 20 files plus one mock file are compiled on first run.\n    cmd.args([\"test\"]).with_no_redact().assert_success().stdout_eq(str![[r#\"\n...\nCompiling 21 files with [..]\n...\n\n\"#]]);\n    cmd.with_no_redact().assert_success().stdout_eq(str![[r#\"\n...\nNo files changed, compilation skipped\n...\n\n\"#]]);\n\n    // Change Counter implementation to fail tests.\n    prj.add_source(\n        \"Counter.sol\",\n        r#\"\ncontract Counter {\n    function add(uint256 x, uint256 y) public pure returns (uint256) {\n        return x + y + 1;\n    }\n}\n    \"#,\n    );\n    // Assert that Counter and CounterTest files are compiled and tests fail.\n    cmd.with_no_redact().assert_failure().stdout_eq(str![[r#\"\n...\nCompiling 2 files with [..]\n...\n[FAIL: assertion failed: 5 != 4] test_add() (gas: [..])\n...\n\n\"#]]);\n});\n\n// ├── src\n// │ ├── CounterA.sol\n// │ ├── CounterB.sol\n// │ ├── Counter.sol\n// │ └── v1\n// │     └── Counter.sol\n// └── test\n// └── Counter.t.sol\nforgetest_init!(preprocess_multiple_contracts_with_constructors, |prj, cmd| {\n    prj.update_config(|config| {\n        config.dynamic_test_linking = true;\n    });\n\n    prj.add_source(\n        \"Counter.sol\",\n        r#\"\ncontract Counter {\n    uint256 public number;\n\n    function setNumber(uint256 newNumber) public {\n        number = newNumber;\n    }\n\n    function increment() public {\n        number++;\n    }\n}\n    \"#,\n    );\n    prj.add_source(\n        \"CounterA.sol\",\n        r#\"\ncontract CounterA {\n    uint256 public number;\n    address public owner;\n\n    constructor(uint256 _newNumber, address _owner) {\n        number = _newNumber;\n        owner = _owner;\n    }\n\n    function increment() public {\n        number++;\n    }\n}\n    \"#,\n    );\n    // Contract with constructor args without name.\n    prj.add_source(\n        \"CounterB.sol\",\n        r#\"\ncontract CounterB {\n    uint256 public number;\n\n    constructor(uint256) {\n        number = 1;\n    }\n\n    function increment() public {\n        number++;\n    }\n}\n    \"#,\n    );\n    prj.add_source(\n        \"v1/Counter.sol\",\n        r#\"\ncontract Counter {\n    uint256 public number;\n\n    constructor(uint256 _number) {\n        number = _number;\n    }\n\n    function increment() public {\n        number++;\n    }\n}\n    \"#,\n    );\n\n    prj.add_test(\n        \"Counter.t.sol\",\n        r#\"\nimport {Test} from \"forge-std/Test.sol\";\nimport {Counter} from \"src/Counter.sol\";\nimport \"src/CounterA.sol\";\nimport \"src/CounterB.sol\";\nimport {Counter as CounterV1} from \"src/v1/Counter.sol\";\n\ncontract CounterTest is Test {\n    function test_Increment_In_Counter() public {\n        Counter counter = new Counter();\n        counter.increment();\n        assertEq(counter.number(), 1);\n    }\n\n    function test_Increment_In_Counter_V1() public {\n        CounterV1 counter = new CounterV1(1234);\n        counter.increment();\n        assertEq(counter.number(), 1235);\n    }\n\n    function test_Increment_In_Counter_A() public {\n        CounterA counter = new CounterA(1234, address(this));\n        counter.increment();\n        assertEq(counter.number(), 1235);\n    }\n\n    function test_Increment_In_Counter_A_with_named_args() public {\n        CounterA counter = new CounterA({_newNumber: 1234, _owner: address(this)});\n        counter.increment();\n        assertEq(counter.number(), 1235);\n    }\n\n    function test_Increment_In_Counter_B() public {\n        CounterB counter = new CounterB(1234);\n        counter.increment();\n        assertEq(counter.number(), 2);\n    }\n}\n    \"#,\n    );\n    // 22 files plus one mock file are compiled on first run.\n    cmd.args([\"test\"]).with_no_redact().assert_success().stdout_eq(str![[r#\"\n...\nCompiling 24 files with [..]\n...\n[PASS] test_Increment_In_Counter() (gas: [..])\n[PASS] test_Increment_In_Counter_A() (gas: [..])\n[PASS] test_Increment_In_Counter_A_with_named_args() (gas: [..])\n[PASS] test_Increment_In_Counter_B() (gas: [..])\n[PASS] test_Increment_In_Counter_V1() (gas: [..])\n...\n\n\"#]]);\n\n    // Change v1/Counter to fail test.\n    prj.add_source(\n        \"v1/Counter.sol\",\n        r#\"\ncontract Counter {\n    uint256 public number;\n\n    constructor(uint256 _number) {\n        number = _number;\n    }\n\n    function increment() public {\n        number = 12345;\n    }\n}\n    \"#,\n    );\n    // Only v1/Counter should be compiled and test should fail.\n    cmd.with_no_redact().assert_failure().stdout_eq(str![[r#\"\n...\nCompiling 1 files with [..]\n...\n[PASS] test_Increment_In_Counter() (gas: [..])\n[PASS] test_Increment_In_Counter_A() (gas: [..])\n[PASS] test_Increment_In_Counter_A_with_named_args() (gas: [..])\n[PASS] test_Increment_In_Counter_B() (gas: [..])\n[FAIL: assertion failed: 12345 != 1235] test_Increment_In_Counter_V1() (gas: [..])\n...\n\n\"#]]);\n\n    // Change CounterA to fail test.\n    prj.add_source(\n        \"CounterA.sol\",\n        r#\"\ncontract CounterA {\n    uint256 public number;\n    address public owner;\n\n    constructor(uint256 _newNumber, address _owner) {\n        number = _newNumber;\n        owner = _owner;\n    }\n\n    function increment() public {\n        number = 12345;\n    }\n}\n    \"#,\n    );\n    // Only CounterA should be compiled and test should fail.\n    cmd.with_no_redact().assert_failure().stdout_eq(str![[r#\"\n...\nCompiling 1 files with [..]\n...\n[PASS] test_Increment_In_Counter() (gas: [..])\n[FAIL: assertion failed: 12345 != 1235] test_Increment_In_Counter_A() (gas: [..])\n[FAIL: assertion failed: 12345 != 1235] test_Increment_In_Counter_A_with_named_args() (gas: [..])\n[PASS] test_Increment_In_Counter_B() (gas: [..])\n[FAIL: assertion failed: 12345 != 1235] test_Increment_In_Counter_V1() (gas: [..])\n...\n\n\"#]]);\n\n    // Change CounterB to fail test.\n    prj.add_source(\n        \"CounterB.sol\",\n        r#\"\ncontract CounterB {\n    uint256 public number;\n\n    constructor(uint256) {\n        number = 100;\n    }\n\n    function increment() public {\n        number++;\n    }\n}\n    \"#,\n    );\n    // Only CounterB should be compiled and test should fail.\n    cmd.with_no_redact().assert_failure().stdout_eq(str![[r#\"\n...\nCompiling 1 files with [..]\n...\n[PASS] test_Increment_In_Counter() (gas: [..])\n[FAIL: assertion failed: 12345 != 1235] test_Increment_In_Counter_A() (gas: [..])\n[FAIL: assertion failed: 12345 != 1235] test_Increment_In_Counter_A_with_named_args() (gas: [..])\n[FAIL: assertion failed: 101 != 2] test_Increment_In_Counter_B() (gas: [..])\n[FAIL: assertion failed: 12345 != 1235] test_Increment_In_Counter_V1() (gas: [..])\n...\n\n\"#]]);\n\n    // Change Counter to fail test.\n    prj.add_source(\n        \"Counter.sol\",\n        r#\"\ncontract Counter {\n    uint256 public number;\n\n    function setNumber(uint256 newNumber) public {\n        number = newNumber;\n    }\n\n    function increment() public {\n        number = 12345;\n    }\n}\n    \"#,\n    );\n    // Only Counter should be compiled and test should fail.\n    cmd.with_no_redact().assert_failure().stdout_eq(str![[r#\"\n...\nCompiling 1 files with [..]\n...\n[FAIL: assertion failed: 12345 != 1] test_Increment_In_Counter() (gas: [..])\n[FAIL: assertion failed: 12345 != 1235] test_Increment_In_Counter_A() (gas: [..])\n[FAIL: assertion failed: 12345 != 1235] test_Increment_In_Counter_A_with_named_args() (gas: [..])\n[FAIL: assertion failed: 101 != 2] test_Increment_In_Counter_B() (gas: [..])\n[FAIL: assertion failed: 12345 != 1235] test_Increment_In_Counter_V1() (gas: [..])\n...\n\n\"#]]);\n});\n\n// Test preprocessing contracts with payable constructor, value and salt named args.\nforgetest_init!(flaky_preprocess_contracts_with_payable_constructor_and_salt, |prj, cmd| {\n    prj.update_config(|config| {\n        config.dynamic_test_linking = true;\n    });\n\n    prj.add_source(\n        \"Counter.sol\",\n        r#\"\ncontract Counter {\n    uint256 public number;\n\n    constructor(uint256 _number) payable {\n        number = msg.value;\n    }\n\n    function setNumber(uint256 newNumber) public {\n        number = newNumber;\n    }\n\n    function increment() public {\n        number++;\n    }\n}\n    \"#,\n    );\n    prj.add_source(\n        \"CounterWithSalt.sol\",\n        r#\"\ncontract CounterWithSalt {\n    uint256 public number;\n\n    constructor(uint256 _number) payable {\n        number = msg.value;\n    }\n\n    function setNumber(uint256 newNumber) public {\n        number = newNumber;\n    }\n\n    function increment() public {\n        number++;\n    }\n}\n    \"#,\n    );\n\n    prj.add_test(\n        \"Counter.t.sol\",\n        r#\"\nimport {Test} from \"forge-std/Test.sol\";\nimport {Counter} from \"src/Counter.sol\";\nimport {CounterWithSalt} from \"src/CounterWithSalt.sol\";\n\ncontract CounterTest is Test {\n    function test_Increment_In_Counter() public {\n        Counter counter = Counter(address(new Counter{value: 111}(1)));\n        counter.increment();\n        assertEq(counter.number(), 112);\n    }\n\n    function test_Increment_In_Counter_With_Salt() public {\n        CounterWithSalt counter = new CounterWithSalt{value: 111, salt: bytes32(\"preprocess_counter_with_salt\")}(1);\n        assertGt(uint160(address(counter)), 0);\n        counter.increment();\n        assertEq(counter.number(), 112);\n    }\n}\n    \"#,\n    );\n\n    cmd.args([\"test\"]).with_no_redact().assert_success().stdout_eq(str![[r#\"\n...\nCompiling 22 files with [..]\n...\n[PASS] test_Increment_In_Counter() (gas: [..])\n[PASS] test_Increment_In_Counter_With_Salt() (gas: [..])\n...\n\n\"#]]);\n\n    // Change contract to fail test.\n    prj.add_source(\n        \"Counter.sol\",\n        r#\"\ncontract Counter {\n    uint256 public number;\n\n    constructor(uint256 _number) payable {\n        number = msg.value + _number;\n    }\n\n    function setNumber(uint256 newNumber) public {\n        number = newNumber;\n    }\n\n    function increment() public {\n        number++;\n    }\n}\n    \"#,\n    );\n    // Only Counter should be compiled and test should fail.\n    cmd.with_no_redact().assert_failure().stdout_eq(str![[r#\"\n...\nCompiling 1 files with [..]\n...\n[FAIL: assertion failed: 113 != 112] test_Increment_In_Counter() (gas: [..])\n[PASS] test_Increment_In_Counter_With_Salt() (gas: [..])\n...\n\n\"#]]);\n\n    // Change contract with salt to fail test too.\n    prj.add_source(\n        \"CounterWithSalt.sol\",\n        r#\"\ncontract CounterWithSalt {\n    uint256 public number;\n\n    constructor(uint256 _number) payable {\n        number = msg.value + _number;\n    }\n\n    function setNumber(uint256 newNumber) public {\n        number = newNumber;\n    }\n\n    function increment() public {\n        number++;\n    }\n}\n    \"#,\n    );\n    // Only Counter should be compiled and test should fail.\n    cmd.with_no_redact().assert_failure().stdout_eq(str![[r#\"\n...\nCompiling 1 files with [..]\n...\n[FAIL: assertion failed: 113 != 112] test_Increment_In_Counter() (gas: [..])\n[FAIL: assertion failed: 113 != 112] test_Increment_In_Counter_With_Salt() (gas: [..])\n...\n\n\"#]]);\n});\n\n// Counter contract with constructor reverts and emitted events.\nforgetest_init!(preprocess_contract_with_require_and_emit, |prj, cmd| {\n    prj.update_config(|config| {\n        config.dynamic_test_linking = true;\n    });\n\n    prj.add_source(\n        \"Counter.sol\",\n        r#\"\ncontract Counter {\n    event CounterCreated(uint256 number);\n    uint256 public number;\n\n    constructor(uint256 no) {\n        require(no != 1, \"ctor revert\");\n        emit CounterCreated(10);\n    }\n}\n    \"#,\n    );\n\n    prj.add_test(\n        \"Counter.t.sol\",\n        r#\"\nimport {Test} from \"forge-std/Test.sol\";\nimport {Counter} from \"../src/Counter.sol\";\n\ncontract CounterTest is Test {\n    function test_assert_constructor_revert() public {\n        vm.expectRevert(\"ctor revert\");\n        new Counter(1);\n    }\n\n    function test_assert_constructor_emit() public {\n        vm.expectEmit(true, true, true, true);\n        emit Counter.CounterCreated(10);\n\n        new Counter(11);\n    }\n}\n    \"#,\n    );\n    // All 20 files are compiled on first run.\n    cmd.args([\"test\"]).with_no_redact().assert_success().stdout_eq(str![[r#\"\n...\nCompiling 21 files with [..]\n...\n\n\"#]]);\n\n    // Change Counter implementation to revert with different message.\n    prj.add_source(\n        \"Counter.sol\",\n        r#\"\ncontract Counter {\n    event CounterCreated(uint256 number);\n    uint256 public number;\n\n    constructor(uint256 no) {\n        require(no != 1, \"ctor revert update\");\n        emit CounterCreated(10);\n    }\n}\n    \"#,\n    );\n    // Assert that only 1 file is compiled (Counter source contract) and revert test fails.\n    cmd.with_no_redact().assert_failure().stdout_eq(str![[r#\"\n...\nCompiling 1 files with [..]\n...\n[PASS] test_assert_constructor_emit() (gas: [..])\n[FAIL: Error != expected error: ctor revert update != ctor revert] test_assert_constructor_revert() (gas: [..])\n...\n\n\"#]]);\n\n    // Change Counter implementation and don't revert.\n    prj.add_source(\n        \"Counter.sol\",\n        r#\"\ncontract Counter {\n    event CounterCreated(uint256 number);\n    uint256 public number;\n\n    constructor(uint256 no) {\n        require(no != 0, \"ctor revert\");\n        emit CounterCreated(10);\n    }\n}\n    \"#,\n    );\n    // Assert that only 1 file is compiled (Counter source contract) and revert test fails.\n    cmd.with_no_redact().assert_failure().stdout_eq(str![[r#\"\n...\nCompiling 1 files with [..]\n...\n[PASS] test_assert_constructor_emit() (gas: [..])\n[FAIL: next call did not revert as expected] test_assert_constructor_revert() (gas: [..])\n...\n\n\"#]]);\n\n    // Change Counter implementation to emit different event.\n    prj.add_source(\n        \"Counter.sol\",\n        r#\"\ncontract Counter {\n    event CounterCreated(uint256 number);\n    uint256 public number;\n\n    constructor(uint256 no) {\n        require(no != 0, \"ctor revert\");\n        emit CounterCreated(100);\n    }\n}\n    \"#,\n    );\n    // Assert that only 1 file is compiled (Counter source contract) and emit test fails.\n    cmd.with_no_redact().assert_failure().stdout_eq(str![[r#\"\n...\nCompiling 1 files with [..]\n...\n[FAIL: expected an emit, but no logs were emitted afterwards. you might have mismatched events or not enough events were emitted] test_assert_constructor_emit() (gas: [..])\n[FAIL: next call did not revert as expected] test_assert_constructor_revert() (gas: [..])\n...\n\n\"#]]);\n});\n\n// <https://github.com/foundry-rs/foundry/issues/10312>\nforgetest_init!(preprocess_contract_with_constructor_args_struct, |prj, cmd| {\n    prj.update_config(|config| {\n        config.dynamic_test_linking = true;\n    });\n\n    prj.add_source(\n        \"Counter.sol\",\n        r#\"\ncontract Counter {\n    struct ConstructorArgs {\n        uint256 _number;\n    }\n\n    constructor(uint256 no) {\n    }\n}\n    \"#,\n    );\n\n    prj.add_test(\n        \"Counter.t.sol\",\n        r#\"\nimport {Test} from \"forge-std/Test.sol\";\nimport {Counter} from \"../src/Counter.sol\";\n\ncontract CounterTest is Test {\n    function test_assert_constructor_revert() public {\n        Counter counter = new Counter(1);\n    }\n}\n    \"#,\n    );\n    // All 20 files should properly compile.\n    cmd.args([\"test\"]).with_no_redact().assert_success().stdout_eq(str![[r#\"\n...\nCompiling 21 files with [..]\n...\n\n\"#]]);\n});\n\n// Test preprocessed contracts with decode internal fns.\n#[cfg(not(feature = \"isolate-by-default\"))]\nforgetest_init!(preprocess_contract_with_decode_internal, |prj, cmd| {\n    prj.initialize_default_contracts();\n    prj.update_config(|config| {\n        config.dynamic_test_linking = true;\n    });\n\n    prj.add_test(\n        \"Counter.t.sol\",\n        r#\"\nimport {Test} from \"forge-std/Test.sol\";\nimport {Counter} from \"../src/Counter.sol\";\n\ncontract CounterTest is Test {\n    Counter public counter;\n\n    function setUp() public {\n        create_counter(0);\n    }\n\n    function test_Increment() public {\n        create_counter(0);\n        counter.increment();\n        assertEq(counter.number(), 1);\n    }\n\n    function create_counter(uint256 number) internal {\n        counter = new Counter();\n        counter.setNumber(number);\n    }\n}\n    \"#,\n    );\n\n    cmd.args([\"test\", \"--decode-internal\", \"-vvvv\"]).assert_success().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\nRan 1 test for test/Counter.t.sol:CounterTest\n[PASS] test_Increment() ([GAS])\nTraces:\n  [..] CounterTest::test_Increment()\n    ├─ [0] VM::deployCode(\"src/Counter.sol:Counter\")\n    │   ├─ [96345] → new Counter@0x2e234DAe75C793f67A35089C9d99245E1C58470b\n    │   │   └─ ← [Return] 481 bytes of code\n    │   └─ ← [Return] Counter: [0x2e234DAe75C793f67A35089C9d99245E1C58470b]\n    ├─ [..] Counter::setNumber(0)\n    │   └─ ← [Stop]\n    ├─ [..] Counter::increment()\n    │   └─ ← [Stop]\n    ├─ [..] Counter::number() [staticcall]\n    │   └─ ← [Return] 1\n    ├─ [..] StdAssertions::assertEq(1, 1)\n    │   └─ ← \n    └─ ← [Stop]\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests)\n\n\"#]]);\n});\n\n// <https://github.com/foundry-rs/foundry/issues/10492>\n// Preprocess test contracts with try constructor statements.\nforgetest_init!(preprocess_contract_with_try_ctor_stmt, |prj, cmd| {\n    prj.update_config(|config| {\n        config.dynamic_test_linking = true;\n    });\n\n    prj.add_source(\n        \"CounterA.sol\",\n        r#\"\ncontract CounterA {\n    uint256 number;\n}\n    \"#,\n    );\n    prj.add_source(\n        \"CounterB.sol\",\n        r#\"\ncontract CounterB {\n    uint256 number;\n    constructor(uint256 a) payable {\n        require(a > 0, \"ctor failure\");\n        number = a;\n    }\n}\n    \"#,\n    );\n    prj.add_source(\n        \"CounterC.sol\",\n        r#\"\ncontract CounterC {\n    uint256 number;\n    constructor(uint256 a) {\n        require(a > 0, \"ctor failure\");\n        number = a;\n    }\n}\n    \"#,\n    );\n\n    prj.add_test(\n        \"Counter.t.sol\",\n        r#\"\nimport {Test} from \"forge-std/Test.sol\";\nimport {CounterA} from \"../src/CounterA.sol\";\nimport {CounterB} from \"../src/CounterB.sol\";\nimport {CounterC} from \"../src/CounterC.sol\";\n\ncontract CounterTest is Test {\n    function test_try_counterA_creation() public {\n        try new CounterA() {} catch {\n            revert();\n        }\n    }\n\n    function test_try_counterB_creation() public {\n        try new CounterB(1) {} catch {\n            revert();\n        }\n    }\n\n    function test_try_counterB_creation_with_salt() public {\n        try new CounterB{value: 111, salt: bytes32(\"preprocess_counter_with_salt\")}(1) {} catch {\n            revert();\n        }\n    }\n\n    function test_try_counterC_creation() public {\n        try new CounterC(2) {\n            new CounterC(1);\n        } catch {\n            revert();\n        }\n    }\n}\n    \"#,\n    );\n    // All 23 files should properly compile, tests pass.\n    cmd.args([\"test\"]).with_no_redact().assert_success().stdout_eq(str![[r#\"\n...\nCompiling 23 files with [..]\n...\n[PASS] test_try_counterA_creation() (gas: [..])\n[PASS] test_try_counterB_creation() (gas: [..])\n[PASS] test_try_counterB_creation_with_salt() (gas: [..])\n[PASS] test_try_counterC_creation() (gas: [..])\n...\n\n\"#]]);\n\n    // Change CounterB to fail test.\n    prj.add_source(\n        \"CounterB.sol\",\n        r#\"\ncontract CounterB {\n    uint256 number;\n    constructor(uint256 a) payable {\n        require(a > 11, \"ctor failure\");\n        number = a;\n    }\n}\n    \"#,\n    );\n    // Only CounterB should compile.\n    cmd.assert_failure().stdout_eq(str![[r#\"\n...\nCompiling 1 files with [..]\n...\n[PASS] test_try_counterA_creation() (gas: [..])\n[FAIL: EvmError: Revert] test_try_counterB_creation() (gas: [..])\n[FAIL: EvmError: Revert] test_try_counterB_creation_with_salt() (gas: [..])\n[PASS] test_try_counterC_creation() (gas: [..])\n...\n\n\"#]]);\n\n    // Change CounterC to fail test in try statement.\n    prj.add_source(\n        \"CounterC.sol\",\n        r#\"\ncontract CounterC {\n    uint256 number;\n    constructor(uint256 a) {\n        require(a > 1, \"ctor failure\");\n        number = a;\n    }\n}\n    \"#,\n    );\n    // Only CounterC should compile.\n    cmd.assert_failure().stdout_eq(str![[r#\"\n...\nCompiling 1 files with [..]\n...\n[PASS] test_try_counterA_creation() (gas: [..])\n[FAIL: EvmError: Revert] test_try_counterB_creation() (gas: [..])\n[FAIL: EvmError: Revert] test_try_counterB_creation_with_salt() (gas: [..])\n[FAIL: ctor failure] test_try_counterC_creation() (gas: [..])\n...\n\n\"#]]);\n\n    // Change CounterC to fail test in try statement.\n    prj.add_source(\n        \"CounterC.sol\",\n        r#\"\ncontract CounterC {\n    uint256 number;\n    constructor(uint256 a) {\n        require(a > 2, \"ctor failure\");\n        number = a;\n    }\n}\n    \"#,\n    );\n    // Only CounterC should compile and revert.\n    cmd.assert_failure().stdout_eq(str![[r#\"\n...\nCompiling 1 files with [..]\n...\n[PASS] test_try_counterA_creation() (gas: [..])\n[FAIL: EvmError: Revert] test_try_counterB_creation() (gas: [..])\n[FAIL: EvmError: Revert] test_try_counterB_creation_with_salt() (gas: [..])\n[FAIL: EvmError: Revert] test_try_counterC_creation() (gas: [..])\n...\n\n\"#]]);\n});\n\n// <https://github.com/foundry-rs/foundry/issues/11978>\n// Preprocess test contracts when active prank.\nforgetest_init!(preprocess_contract_with_active_prank, |prj, cmd| {\n    prj.update_config(|config| {\n        config.dynamic_test_linking = true;\n    });\n\n    prj.add_source(\n        \"Counter.sol\",\n        r#\"\ncontract Counter {\n    uint256 public number;\n    address public deployer;\n\n    constructor() {\n        deployer = msg.sender;\n    }\n}\n    \"#,\n    );\n\n    prj.add_test(\n        \"Counter.t.sol\",\n        r#\"\nimport {Test} from \"forge-std/Test.sol\";\nimport {Counter} from \"../src/Counter.sol\";\n\ncontract CounterTest is Test {\n    function test_deployer() public {\n        address deployer = makeAddr(\"deployer\");\n        vm.startPrank(deployer);\n        Counter counter = new Counter{salt: 0}();\n        assertEq(counter.deployer(), deployer);\n    }\n}\n    \"#,\n    );\n    // Test should pass.\n    cmd.args([\"test\"]).assert_success().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\nRan 1 test for test/Counter.t.sol:CounterTest\n[PASS] test_deployer() ([GAS])\nSuite result: ok. 1 passed; 0 failed; 0 skipped; [ELAPSED]\n\nRan 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests)\n\n\"#]]);\n});\n\n// Preprocess test contracts with try constructor statements that bind return type.\nforgetest_init!(preprocess_contract_with_try_ctor_stmt_and_returns, |prj, cmd| {\n    prj.update_config(|config| {\n        config.dynamic_test_linking = true;\n    });\n\n    prj.add_source(\n        \"Counter.sol\",\n        r#\"\ncontract Counter {\n    uint256 number;\n    constructor(uint256 a) payable {\n        require(a > 0, \"ctor failure\");\n        number = a;\n    }\n}\n        \"#,\n    );\n    prj.add_test(\n        \"CounterReturns.t.sol\",\n        r#\"\nimport {Test} from \"forge-std/Test.sol\";\nimport {Counter} from \"../src/Counter.sol\";\n\ncontract CounterReturnsTest is Test {\n    function test_try_counter_creation_returns_custom_type() public {\n        try new Counter(1) returns (Counter c) {\n            c;\n        } catch {\n            revert();\n        }\n    }\n}\n        \"#,\n    );\n\n    cmd.args([\"test\"]).with_no_redact().assert_success().stdout_eq(str![[r#\"\n...\nCompiling 21 files with [..]\n...\n[PASS] test_try_counter_creation_returns_custom_type() (gas: [..])\n...\n\n\"#]]);\n\n    // Change Counter to fail test in try statement, only Counter contract should be compiled.\n    prj.add_source(\n        \"Counter.sol\",\n        r#\"\ncontract Counter {\n    uint256 number;\n    constructor(uint256 a) payable {\n        require(a == 0, \"ctor failure\");\n        number = a;\n    }\n}\n        \"#,\n    );\n    cmd.assert_failure().stdout_eq(str![[r#\"\n...\nCompiling 1 files with [..]\n...\n[FAIL: ctor failure] test_try_counter_creation_returns_custom_type() (gas: [..])\n...\n\n\"#]]);\n});\n\n// Test that `type(Contract).creationCode` can be used in view functions.\n// https://github.com/foundry-rs/foundry/issues/13086\nforgetest_init!(preprocess_creation_code_in_view_function, |prj, cmd| {\n    prj.update_config(|config| {\n        config.dynamic_test_linking = true;\n    });\n\n    prj.add_source(\n        \"Target.sol\",\n        r#\"\ncontract Target {\n    uint256 public immutable value;\n    constructor(uint256 _value) { value = _value; }\n}\n        \"#,\n    );\n\n    prj.add_test(\n        \"Target.t.sol\",\n        r#\"\nimport {Test} from \"forge-std/Test.sol\";\nimport {Target} from \"../src/Target.sol\";\n\ncontract TargetTest is Test {\n    function computeAddress(address factory, uint256 salt, uint256 value) internal view returns (address) {\n        bytes32 hash = keccak256(\n            abi.encodePacked(\n                bytes1(0xff),\n                factory,\n                salt,\n                keccak256(abi.encodePacked(type(Target).creationCode, abi.encode(value)))\n            )\n        );\n        return address(uint160(uint256(hash)));\n    }\n\n    function testComputeAddress() public view {\n        computeAddress(address(this), 1, 100);\n    }\n}\n        \"#,\n    );\n\n    cmd.args([\"build\"]).assert_success();\n});\n"
  },
  {
    "path": "crates/forge/tests/cli/utils.rs",
    "content": "//! Various helper functions\n\nuse alloy_chains::NamedChain;\nuse alloy_primitives::Address;\nuse alloy_signer_local::PrivateKeySigner;\n\n/// Returns the current millis since unix epoch.\n///\n/// This way we generate unique contracts so, etherscan will always have to verify them\npub fn millis_since_epoch() -> u128 {\n    let now = std::time::SystemTime::now();\n    now.duration_since(std::time::SystemTime::UNIX_EPOCH)\n        .unwrap_or_else(|err| panic!(\"Current time {now:?} is invalid: {err:?}\"))\n        .as_millis()\n}\n\npub fn etherscan_key(chain: NamedChain) -> Option<String> {\n    match chain {\n        NamedChain::Fantom | NamedChain::FantomTestnet => {\n            std::env::var(\"FTMSCAN_API_KEY\").or_else(|_| std::env::var(\"FANTOMSCAN_API_KEY\")).ok()\n        }\n        NamedChain::OptimismKovan => std::env::var(\"OP_KOVAN_API_KEY\").ok(),\n        _ => std::env::var(\"ETHERSCAN_API_KEY\").ok(),\n    }\n}\n\npub fn network_rpc_key(chain: &str) -> Option<String> {\n    let key = format!(\"{}_RPC_URL\", chain.to_uppercase().replace('-', \"_\"));\n    std::env::var(key).ok()\n}\n\npub fn network_private_key(chain: &str) -> Option<String> {\n    let key = format!(\"{}_PRIVATE_KEY\", chain.to_uppercase().replace('-', \"_\"));\n    std::env::var(key).or_else(|_| std::env::var(\"TEST_PRIVATE_KEY\")).ok()\n}\n\n/// Represents external input required for executing verification requests\npub struct EnvExternalities {\n    pub chain: NamedChain,\n    pub rpc: String,\n    pub pk: String,\n    pub etherscan: String,\n    pub verifier: String,\n}\n\nimpl EnvExternalities {\n    pub fn address(&self) -> Option<Address> {\n        let pk: PrivateKeySigner = self.pk.parse().ok()?;\n        Some(pk.address())\n    }\n\n    pub fn goerli() -> Option<Self> {\n        Some(Self {\n            chain: NamedChain::Goerli,\n            rpc: network_rpc_key(\"goerli\")?,\n            pk: network_private_key(\"goerli\")?,\n            etherscan: etherscan_key(NamedChain::Goerli)?,\n            verifier: \"etherscan\".to_string(),\n        })\n    }\n\n    pub fn ftm_testnet() -> Option<Self> {\n        Some(Self {\n            chain: NamedChain::FantomTestnet,\n            rpc: network_rpc_key(\"ftm_testnet\")?,\n            pk: network_private_key(\"ftm_testnet\")?,\n            etherscan: etherscan_key(NamedChain::FantomTestnet)?,\n            verifier: \"etherscan\".to_string(),\n        })\n    }\n\n    pub fn optimism_kovan() -> Option<Self> {\n        Some(Self {\n            chain: NamedChain::OptimismKovan,\n            rpc: network_rpc_key(\"op_kovan\")?,\n            pk: network_private_key(\"op_kovan\")?,\n            etherscan: etherscan_key(NamedChain::OptimismKovan)?,\n            verifier: \"etherscan\".to_string(),\n        })\n    }\n\n    pub fn arbitrum_goerli() -> Option<Self> {\n        Some(Self {\n            chain: NamedChain::ArbitrumGoerli,\n            rpc: network_rpc_key(\"arbitrum-goerli\")?,\n            pk: network_private_key(\"arbitrum-goerli\")?,\n            etherscan: etherscan_key(NamedChain::ArbitrumGoerli)?,\n            verifier: \"blockscout\".to_string(),\n        })\n    }\n\n    pub fn amoy() -> Option<Self> {\n        Some(Self {\n            chain: NamedChain::PolygonAmoy,\n            rpc: network_rpc_key(\"amoy\")?,\n            pk: network_private_key(\"amoy\")?,\n            etherscan: etherscan_key(NamedChain::PolygonAmoy)?,\n            verifier: \"etherscan\".to_string(),\n        })\n    }\n\n    pub fn sepolia_etherscan() -> Option<Self> {\n        Some(Self {\n            chain: NamedChain::Sepolia,\n            rpc: network_rpc_key(\"sepolia\")?,\n            pk: network_private_key(\"sepolia\")?,\n            etherscan: etherscan_key(NamedChain::Sepolia)?,\n            verifier: \"etherscan\".to_string(),\n        })\n    }\n\n    pub fn sepolia_sourcify() -> Option<Self> {\n        Some(Self {\n            chain: NamedChain::Sepolia,\n            rpc: network_rpc_key(\"sepolia\")?,\n            pk: network_private_key(\"sepolia\")?,\n            etherscan: String::new(),\n            verifier: \"sourcify\".to_string(),\n        })\n    }\n\n    pub fn sepolia_sourcify_with_etherscan_api_key_set() -> Option<Self> {\n        Some(Self {\n            chain: NamedChain::Sepolia,\n            rpc: network_rpc_key(\"sepolia\")?,\n            pk: network_private_key(\"sepolia\")?,\n            etherscan: etherscan_key(NamedChain::Sepolia)?,\n            verifier: \"sourcify\".to_string(),\n        })\n    }\n\n    pub fn sepolia_blockscout() -> Option<Self> {\n        Some(Self {\n            chain: NamedChain::Sepolia,\n            rpc: network_rpc_key(\"sepolia\")?,\n            pk: network_private_key(\"sepolia\")?,\n            etherscan: String::new(),\n            verifier: \"blockscout\".to_string(),\n        })\n    }\n\n    pub fn sepolia_blockscout_with_etherscan_api_key_set() -> Option<Self> {\n        Some(Self {\n            chain: NamedChain::Sepolia,\n            rpc: network_rpc_key(\"sepolia\")?,\n            pk: network_private_key(\"sepolia\")?,\n            etherscan: etherscan_key(NamedChain::Sepolia)?,\n            verifier: \"blockscout\".to_string(),\n        })\n    }\n\n    pub fn sepolia_empty_verifier() -> Option<Self> {\n        Some(Self {\n            chain: NamedChain::Sepolia,\n            rpc: network_rpc_key(\"sepolia\")?,\n            pk: network_private_key(\"sepolia\")?,\n            etherscan: String::new(),\n            verifier: String::new(),\n        })\n    }\n\n    /// Returns the arguments required to deploy the contract\n    pub fn create_args(&self) -> Vec<String> {\n        vec![\n            \"--chain\".to_string(),\n            self.chain.to_string(),\n            \"--rpc-url\".to_string(),\n            self.rpc.clone(),\n            \"--private-key\".to_string(),\n            self.pk.clone(),\n        ]\n    }\n}\n\n/// Parses the address the contract was deployed to\npub fn parse_deployed_address(out: &str) -> Option<String> {\n    for line in out.lines() {\n        if line.starts_with(\"Deployed to\") {\n            return Some(line.trim_start_matches(\"Deployed to: \").to_string());\n        }\n    }\n    None\n}\n\npub fn parse_verification_guid(out: &str) -> Option<String> {\n    for line in out.lines() {\n        if line.contains(\"GUID\") {\n            return Some(line.replace(\"GUID:\", \"\").replace('`', \"\").trim().to_string());\n        }\n    }\n    None\n}\n\n/// Generates a string containing the code of a Solidity contract.\n///\n/// This contract compiles to a large init bytecode size, but small runtime size.\npub fn generate_large_init_contract(n: usize) -> String {\n    let data = vec![0xff; n];\n    let hex = alloy_primitives::hex::encode(data);\n    format!(\n        \"\\\ncontract LargeContract {{\n    constructor() {{\n        bytes memory data = hex\\\"{hex}\\\";\n        assembly {{\n            pop(mload(data))\n        }}\n    }}\n}}    \n\"\n    )\n}\n"
  },
  {
    "path": "crates/forge/tests/cli/verify.rs",
    "content": "//! Contains various tests for checking forge commands related to verifying contracts on Etherscan\n//! and Sourcify.\n\nuse crate::utils::{self, EnvExternalities};\nuse foundry_common::retry::Retry;\nuse foundry_test_utils::{\n    forgetest,\n    util::{OutputExt, TestCommand, TestProject},\n};\nuse std::time::Duration;\n\n/// Adds a `Unique` contract to the source directory of the project that can be imported as\n/// `import {Unique} from \"./unique.sol\";`\nfn add_unique(prj: &TestProject) {\n    let timestamp = utils::millis_since_epoch();\n    prj.add_source(\n        \"unique\",\n        &format!(\n            r#\"\ncontract Unique {{\n    uint public _timestamp = {timestamp};\n}}\n\"#\n        ),\n    );\n}\n\nfn add_verify_target(prj: &TestProject) {\n    prj.add_source(\n        \"Verify.sol\",\n        r#\"\nimport {Unique} from \"./unique.sol\";\ncontract Verify is Unique {\nfunction doStuff() external {}\n}\n\"#,\n    );\n}\n\nfn add_single_verify_target_file(prj: &TestProject) {\n    let timestamp = utils::millis_since_epoch();\n    let contract = format!(\n        r#\"\ncontract Unique {{\n    uint public _timestamp = {timestamp};\n}}\ncontract Verify is Unique {{\nfunction doStuff() external {{}}\n}}\n\"#\n    );\n\n    prj.add_source(\"Verify.sol\", &contract);\n}\n\nfn add_verify_target_with_constructor(prj: &TestProject) {\n    prj.add_source(\n        \"Verify.sol\",\n        r#\"\nimport {Unique} from \"./unique.sol\";\ncontract Verify is Unique {\n    struct SomeStruct {\n        uint256 a;\n        string str;\n    }\n\n    constructor(SomeStruct memory st, address owner) {}\n}\n\"#,\n    );\n}\n\nfn parse_verification_result(cmd: &mut TestCommand, retries: u32) -> eyre::Result<()> {\n    // Give Etherscan some time to verify the contract.\n    Retry::new(retries, Duration::from_secs(30)).run(|| -> eyre::Result<()> {\n        let output = cmd.execute();\n        let out = String::from_utf8_lossy(&output.stdout);\n        test_debug!(\"{out}\");\n        if out.contains(\"Contract successfully verified\") {\n            return Ok(());\n        }\n        eyre::bail!(\n            \"Failed to get verification, stdout: {}, stderr: {}\",\n            out,\n            String::from_utf8_lossy(&output.stderr)\n        )\n    })\n}\n\nfn verify_check(\n    guid: String,\n    chain: String,\n    etherscan_api_key: Option<String>,\n    verifier: Option<String>,\n    mut cmd: TestCommand,\n) {\n    let mut args = vec![\"verify-check\", &guid, \"--chain-id\", &chain];\n\n    if let Some(etherscan_api_key) = &etherscan_api_key {\n        args.push(\"--etherscan-api-key\");\n        args.push(etherscan_api_key);\n    }\n\n    if let Some(verifier) = &verifier {\n        args.push(\"--verifier\");\n        args.push(verifier);\n    }\n    cmd.forge_fuse().args(args);\n\n    parse_verification_result(&mut cmd, 6).expect(\"Failed to verify check\")\n}\n\nfn await_verification_response(info: EnvExternalities, mut cmd: TestCommand) {\n    let guid = {\n        // Give Etherscan some time to detect the transaction.\n        Retry::new(5, Duration::from_secs(60))\n            .run(|| -> eyre::Result<String> {\n                let output = cmd.execute();\n                let out = String::from_utf8_lossy(&output.stdout);\n                utils::parse_verification_guid(&out).ok_or_else(|| {\n                    eyre::eyre!(\n                        \"Failed to get guid, stdout: {}, stderr: {}\",\n                        out,\n                        String::from_utf8_lossy(&output.stderr)\n                    )\n                })\n            })\n            .expect(\"Failed to get verify guid\")\n    };\n\n    // verify-check\n    let etherscan = (!info.etherscan.is_empty()).then_some(info.etherscan.clone());\n    let verifier = (!info.verifier.is_empty()).then_some(info.verifier.clone());\n    verify_check(guid, info.chain.to_string(), etherscan, verifier, cmd);\n}\n\nfn deploy_contract(\n    info: &EnvExternalities,\n    contract_path: &str,\n    prj: TestProject,\n    cmd: &mut TestCommand,\n) -> String {\n    add_unique(&prj);\n    add_verify_target(&prj);\n    let output = cmd\n        .forge_fuse()\n        .arg(\"create\")\n        .args(info.create_args())\n        .arg(contract_path)\n        .assert_success()\n        .get_output()\n        .stdout_lossy();\n    utils::parse_deployed_address(output.as_str())\n        .unwrap_or_else(|| panic!(\"Failed to parse deployer {output}\"))\n}\n\nfn verify_on_chain(info: Option<EnvExternalities>, prj: TestProject, mut cmd: TestCommand) {\n    // only execute if keys present\n    if let Some(info) = info {\n        test_debug!(\"verifying on {}\", info.chain);\n\n        let contract_path = \"src/Verify.sol:Verify\";\n        let address = deploy_contract(&info, contract_path, prj, &mut cmd);\n\n        let mut args = vec![\n            \"--chain-id\".to_string(),\n            info.chain.to_string(),\n            address,\n            contract_path.to_string(),\n        ];\n\n        if !info.etherscan.is_empty() {\n            args.push(\"--etherscan-api-key\".to_string());\n            args.push(info.etherscan.clone());\n        }\n\n        if !info.verifier.is_empty() {\n            args.push(\"--verifier\".to_string());\n            args.push(info.verifier.clone());\n        }\n        cmd.forge_fuse().arg(\"verify-contract\").root_arg().args(args);\n\n        await_verification_response(info, cmd)\n    }\n}\n\nfn guess_constructor_args(info: Option<EnvExternalities>, prj: TestProject, mut cmd: TestCommand) {\n    // only execute if keys present\n    if let Some(info) = info {\n        test_debug!(\"verifying on {}\", info.chain);\n        add_unique(&prj);\n        add_verify_target_with_constructor(&prj);\n\n        let contract_path = \"src/Verify.sol:Verify\";\n        let output = cmd\n            .arg(\"create\")\n            .args(info.create_args())\n            .arg(contract_path)\n            .args(vec![\n                \"--constructor-args\",\n                \"(239,SomeString)\",\n                \"0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045\",\n            ])\n            .assert_success()\n            .get_output()\n            .stdout_lossy();\n\n        let address = utils::parse_deployed_address(output.as_str())\n            .unwrap_or_else(|| panic!(\"Failed to parse deployer {output}\"));\n\n        cmd.forge_fuse().arg(\"verify-contract\").root_arg().args([\n            \"--rpc-url\".to_string(),\n            info.rpc.to_string(),\n            address,\n            contract_path.to_string(),\n            \"--etherscan-api-key\".to_string(),\n            info.etherscan.to_string(),\n            \"--verifier\".to_string(),\n            info.verifier.to_string(),\n            \"--guess-constructor-args\".to_string(),\n        ]);\n\n        await_verification_response(info, cmd)\n    }\n}\n\n/// Executes create --verify on the given chain\nfn create_verify_on_chain(info: Option<EnvExternalities>, prj: TestProject, mut cmd: TestCommand) {\n    // only execute if keys present\n    if let Some(info) = info {\n        test_debug!(\"verifying on {}\", info.chain);\n        add_single_verify_target_file(&prj);\n\n        let contract_path = \"src/Verify.sol:Verify\";\n        let output = cmd\n            .arg(\"create\")\n            .args(info.create_args())\n            .args([contract_path, \"--etherscan-api-key\", info.etherscan.as_str(), \"--verify\"])\n            .assert_success()\n            .get_output()\n            .stdout_lossy();\n\n        assert!(output.contains(\"Contract successfully verified\"), \"{}\", output);\n    }\n}\n\n// tests `create && contract-verify && verify-check` on Fantom testnet if correct env vars are set\nforgetest!(can_verify_random_contract_fantom_testnet, |prj, cmd| {\n    verify_on_chain(EnvExternalities::ftm_testnet(), prj, cmd);\n});\n\n// tests `create && contract-verify && verify-check` on Optimism kovan if correct env vars are set\nforgetest!(can_verify_random_contract_optimism_kovan, |prj, cmd| {\n    verify_on_chain(EnvExternalities::optimism_kovan(), prj, cmd);\n});\n\n// tests `create && contract-verify && verify-check` on Sepolia testnet if correct env vars are set\nforgetest!(can_verify_random_contract_sepolia, |prj, cmd| {\n    // Implicitly tests `--verifier etherscan` on Sepolia testnet\n    verify_on_chain(EnvExternalities::sepolia_etherscan(), prj, cmd);\n});\n\n// tests `create --verify on Sepolia testnet if correct env vars are set\n// SEPOLIA_RPC_URL=https://rpc.sepolia.org\n// TEST_PRIVATE_KEY=0x...\n// ETHERSCAN_API_KEY=<API_KEY>\nforgetest!(can_create_verify_random_contract_sepolia_etherscan, |prj, cmd| {\n    // Implicitly tests `--verifier etherscan` on Sepolia testnet\n    create_verify_on_chain(EnvExternalities::sepolia_etherscan(), prj, cmd);\n});\n\n// tests `create --verify --verifier sourcify` on Sepolia testnet\nforgetest!(can_create_verify_random_contract_sepolia_sourcify, |prj, cmd| {\n    verify_on_chain(EnvExternalities::sepolia_sourcify(), prj, cmd);\n});\n\n// tests `create --verify --verifier sourcify` with etherscan api key set\n// <https://github.com/foundry-rs/foundry/issues/10000>\nforgetest!(\n    can_create_verify_random_contract_sepolia_sourcify_with_etherscan_api_key_set,\n    |prj, cmd| {\n        verify_on_chain(EnvExternalities::sepolia_sourcify_with_etherscan_api_key_set(), prj, cmd);\n    }\n);\n\n// tests `create --verify --verifier blockscout` on Sepolia testnet\nforgetest!(can_create_verify_random_contract_sepolia_blockscout, |prj, cmd| {\n    verify_on_chain(EnvExternalities::sepolia_blockscout(), prj, cmd);\n});\n\n// tests `create --verify --verifier blockscout` on Sepolia testnet with etherscan api key set\nforgetest!(\n    can_create_verify_random_contract_sepolia_blockscout_with_etherscan_api_key_set,\n    |prj, cmd| {\n        verify_on_chain(\n            EnvExternalities::sepolia_blockscout_with_etherscan_api_key_set(),\n            prj,\n            cmd,\n        );\n    }\n);\n\n// tests `create && contract-verify --guess-constructor-args && verify-check` on Goerli testnet if\n// correct env vars are set\nforgetest!(can_guess_constructor_args, |prj, cmd| {\n    guess_constructor_args(EnvExternalities::goerli(), prj, cmd);\n});\n\n// tests `create && verify-contract && verify-check` on sepolia with default sourcify verifier\nforgetest!(can_verify_random_contract_sepolia_default_sourcify, |prj, cmd| {\n    verify_on_chain(EnvExternalities::sepolia_empty_verifier(), prj, cmd);\n});\n\n// Tests that verify properly validates verifier arguments.\n// <https://github.com/foundry-rs/foundry/issues/11430>\nforgetest_init!(can_validate_verifier_settings, |prj, cmd| {\n    prj.initialize_default_contracts();\n    // Build the project to create the cache.\n    cmd.forge_fuse().arg(\"build\").assert_success();\n    // No verifier URL.\n    cmd.forge_fuse()\n        .args([\n            \"verify-contract\",\n            \"--rpc-url\",\n            \"https://rpc.sepolia-api.lisk.com\",\n            \"--verifier\",\n            \"blockscout\",\n            \"0x19b248616E4964f43F611b5871CE1250f360E9d3\",\n            \"src/Counter.sol:Counter\",\n        ])\n        .assert_failure()\n        .stderr_eq(str![[r#\"\nError: No verifier URL specified for verifier blockscout\n\n\"#]]);\n\n    // Unknown Etherscan chain.\n    cmd.forge_fuse()\n        .args([\n            \"verify-contract\",\n            \"--rpc-url\",\n            \"https://rpc.sepolia-api.lisk.com\",\n            \"--verifier\",\n            \"etherscan\",\n            \"0x19b248616E4964f43F611b5871CE1250f360E9d3\",\n            \"src/Counter.sol:Counter\",\n        ])\n        .assert_failure()\n        .stderr_eq(str![[r#\"\nError: No known Etherscan API URL for chain `4202`. To fix this, please:\n1. Specify a `url` when using Etherscan verifier\n2. Verify the chain `4202` is correct\n\n\"#]]);\n\n    cmd.forge_fuse().args([\"verify-contract\", \"--rpc-url\", \"https://rpc.sepolia-api.lisk.com\", \"--verifier\", \"blockscout\", \"--verifier-url\", \"https://sepolia-blockscout.lisk.com/api\", \"0x19b248616E4964f43F611b5871CE1250f360E9d3\", \"src/Counter.sol:Counter\"]).assert_success().stdout_eq(str![[r#\"\nStart verifying contract `0x19b248616E4964f43F611b5871CE1250f360E9d3` deployed on 4202\n\nContract [src/Counter.sol:Counter] \"0x19b248616E4964f43F611b5871CE1250f360E9d3\" is already verified. Skipping verification.\n\n\"#]]);\n});\n"
  },
  {
    "path": "crates/forge/tests/cli/verify_bytecode.rs",
    "content": "use alloy_chains::Chain;\nuse foundry_compilers::artifacts::{BytecodeHash, EvmVersion};\nuse foundry_config::Config;\nuse foundry_test_utils::{\n    TestCommand, TestProject,\n    etherscan::fetch_etherscan_source_flattened,\n    forgetest_async,\n    rpc::{next_etherscan_api_key, next_http_archive_rpc_url},\n    util::OutputExt,\n};\n\n#[expect(clippy::too_many_arguments)]\nasync fn test_verify_bytecode(\n    prj: TestProject,\n    mut cmd: TestCommand,\n    addr: &str,\n    contract_name: &str,\n    constructor_args: Option<Vec<&str>>,\n    config: Config,\n    verifier: &str,\n    verifier_url: &str,\n    expected_matches: (&str, &str),\n    chain: Chain,\n) {\n    let etherscan_key = next_etherscan_api_key();\n    let rpc_url = next_http_archive_rpc_url();\n\n    // fetch and flatten source code using the library directly\n    let source_code = fetch_etherscan_source_flattened(addr, &etherscan_key, chain)\n        .await\n        .expect(\"failed to fetch source code from etherscan\");\n\n    prj.add_source(contract_name, &source_code);\n    prj.write_config(config);\n\n    let etherscan_key = next_etherscan_api_key();\n    let mut args = vec![\n        \"verify-bytecode\",\n        addr,\n        contract_name,\n        \"--etherscan-api-key\",\n        &etherscan_key,\n        \"--verifier\",\n        verifier,\n        \"--verifier-url\",\n        verifier_url,\n        \"--rpc-url\",\n        &rpc_url,\n    ];\n\n    if let Some(constructor_args) = constructor_args {\n        args.push(\"--constructor-args\");\n        args.extend(constructor_args.iter());\n    }\n\n    let output = cmd.forge_fuse().args(args).assert_success().get_output().stdout_lossy();\n\n    assert!(\n        output\n            .contains(format!(\"Creation code matched with status {}\", expected_matches.0).as_str())\n    );\n    assert!(\n        output\n            .contains(format!(\"Runtime code matched with status {}\", expected_matches.1).as_str())\n    );\n}\n\n#[expect(clippy::too_many_arguments)]\nasync fn test_verify_bytecode_with_ignore(\n    prj: TestProject,\n    mut cmd: TestCommand,\n    addr: &str,\n    contract_name: &str,\n    config: Config,\n    verifier: &str,\n    verifier_url: &str,\n    expected_matches: (&str, &str),\n    ignore: &str,\n    chain: Chain,\n) {\n    let etherscan_key = next_etherscan_api_key();\n    let rpc_url = next_http_archive_rpc_url();\n\n    // fetch and flatten source code using the library directly\n    let source_code = fetch_etherscan_source_flattened(addr, &etherscan_key, chain)\n        .await\n        .expect(\"failed to fetch source code from etherscan\");\n\n    prj.add_source(contract_name, &source_code);\n    prj.write_config(config);\n\n    let output = cmd\n        .forge_fuse()\n        .args([\n            \"verify-bytecode\",\n            addr,\n            contract_name,\n            \"--etherscan-api-key\",\n            &etherscan_key,\n            \"--verifier\",\n            verifier,\n            \"--verifier-url\",\n            verifier_url,\n            \"--rpc-url\",\n            &rpc_url,\n            \"--ignore\",\n            ignore,\n        ])\n        .assert_success()\n        .get_output()\n        .stdout_lossy();\n\n    if ignore == \"creation\" {\n        assert!(!output.contains(\n            format!(\"Creation code matched with status {}\", expected_matches.0).as_str()\n        ));\n    } else {\n        assert!(output.contains(\n            format!(\"Creation code matched with status {}\", expected_matches.0).as_str()\n        ));\n    }\n\n    if ignore == \"runtime\" {\n        assert!(\n            !output.contains(\n                format!(\"Runtime code matched with status {}\", expected_matches.1).as_str()\n            )\n        );\n    } else {\n        assert!(\n            output.contains(\n                format!(\"Runtime code matched with status {}\", expected_matches.1).as_str()\n            )\n        );\n    }\n}\n\nforgetest_async!(flaky_verify_bytecode_no_metadata, |prj, cmd| {\n    test_verify_bytecode(\n        prj,\n        cmd,\n        \"0xba2492e52F45651B60B8B38d4Ea5E2390C64Ffb1\",\n        \"SystemConfig\",\n        None,\n        Config {\n            evm_version: EvmVersion::London,\n            optimizer_runs: Some(999999),\n            optimizer: Some(true),\n            cbor_metadata: false,\n            bytecode_hash: BytecodeHash::None,\n            ..Default::default()\n        },\n        \"etherscan\",\n        \"https://api.etherscan.io/v2/api?chainid=1\",\n        (\"partial\", \"partial\"),\n        Chain::mainnet(),\n    )\n    .await;\n});\n\nforgetest_async!(flaky_verify_bytecode_with_metadata, |prj, cmd| {\n    test_verify_bytecode(\n        prj,\n        cmd,\n        \"0xb8901acb165ed027e32754e0ffe830802919727f\",\n        \"L1_ETH_Bridge\",\n        None,\n        Config {\n            evm_version: EvmVersion::Paris,\n            optimizer_runs: Some(50000),\n            optimizer: Some(true),\n            ..Default::default()\n        },\n        \"etherscan\",\n        \"https://api.etherscan.io/v2/api?chainid=1\",\n        (\"partial\", \"partial\"),\n        Chain::mainnet(),\n    )\n    .await;\n});\n\n// Test non-CREATE2 deployed contract with blockscout\nforgetest_async!(flaky_verify_bytecode_with_blockscout, |prj, cmd| {\n    test_verify_bytecode(\n        prj,\n        cmd,\n        \"0x70f44C13944d49a236E3cD7a94f48f5daB6C619b\",\n        \"StrategyManager\",\n        None,\n        Config {\n            evm_version: EvmVersion::London,\n            optimizer: Some(true),\n            optimizer_runs: Some(200),\n            ..Default::default()\n        },\n        \"blockscout\",\n        \"https://eth.blockscout.com/api\",\n        (\"partial\", \"partial\"),\n        Chain::mainnet(),\n    )\n    .await;\n});\n\n// Test CREATE2 deployed contract with blockscout\nforgetest_async!(flaky_verify_bytecode_create2_with_blockscout, |prj, cmd| {\n    test_verify_bytecode(\n        prj,\n        cmd,\n        \"0xba2492e52F45651B60B8B38d4Ea5E2390C64Ffb1\",\n        \"SystemConfig\",\n        None,\n        Config {\n            evm_version: EvmVersion::London,\n            optimizer_runs: Some(999999),\n            optimizer: Some(true),\n            cbor_metadata: false,\n            bytecode_hash: BytecodeHash::None,\n            ..Default::default()\n        },\n        \"blockscout\",\n        \"https://eth.blockscout.com/api\",\n        (\"partial\", \"partial\"),\n        Chain::mainnet(),\n    )\n    .await;\n});\n\n// Test `--constructor-args`\nforgetest_async!(flaky_verify_bytecode_with_constructor_args, |prj, cmd| {\n    let constructor_args = vec![\n        \"0x39053D51B77DC0d36036Fc1fCc8Cb819df8Ef37A\",\n        \"0x91E677b07F7AF907ec9a428aafA9fc14a0d3A338\",\n        \"0xD92145c07f8Ed1D392c1B88017934E301CC1c3Cd\",\n    ];\n    test_verify_bytecode(\n        prj,\n        cmd,\n        \"0x70f44C13944d49a236E3cD7a94f48f5daB6C619b\",\n        \"StrategyManager\",\n        Some(constructor_args),\n        Config {\n            evm_version: EvmVersion::London,\n            optimizer: Some(true),\n            optimizer_runs: Some(200),\n            ..Default::default()\n        },\n        \"etherscan\",\n        \"https://api.etherscan.io/v2/api?chainid=1\",\n        (\"partial\", \"partial\"),\n        Chain::mainnet(),\n    )\n    .await;\n});\n\n// `--ignore` tests\nforgetest_async!(flaky_verify_bytecode_can_ignore_creation, |prj, cmd| {\n    test_verify_bytecode_with_ignore(\n        prj,\n        cmd,\n        \"0xba2492e52F45651B60B8B38d4Ea5E2390C64Ffb1\",\n        \"SystemConfig\",\n        Config {\n            evm_version: EvmVersion::London,\n            optimizer_runs: Some(999999),\n            optimizer: Some(true),\n            cbor_metadata: false,\n            bytecode_hash: BytecodeHash::None,\n            ..Default::default()\n        },\n        \"etherscan\",\n        \"https://api.etherscan.io/v2/api?chainid=1\",\n        (\"ignored\", \"partial\"),\n        \"creation\",\n        Chain::mainnet(),\n    )\n    .await;\n});\n\nforgetest_async!(flaky_verify_bytecode_can_ignore_runtime, |prj, cmd| {\n    test_verify_bytecode_with_ignore(\n        prj,\n        cmd,\n        \"0xba2492e52F45651B60B8B38d4Ea5E2390C64Ffb1\",\n        \"SystemConfig\",\n        Config {\n            evm_version: EvmVersion::London,\n            optimizer_runs: Some(999999),\n            optimizer: Some(true),\n            cbor_metadata: false,\n            bytecode_hash: BytecodeHash::None,\n            ..Default::default()\n        },\n        \"etherscan\",\n        \"https://api.etherscan.io/v2/api?chainid=1\",\n        (\"partial\", \"ignored\"),\n        \"runtime\",\n        Chain::mainnet(),\n    )\n    .await;\n});\n\n// Test that verification fails when source code doesn't match deployed bytecode\nforgetest_async!(flaky_can_verify_bytecode_fails_on_source_mismatch, |prj, cmd| {\n    let etherscan_key = next_etherscan_api_key();\n    let rpc_url = next_http_archive_rpc_url();\n\n    // Fetch real source code using the library directly\n    let real_source = fetch_etherscan_source_flattened(\n        \"0xba2492e52F45651B60B8B38d4Ea5E2390C64Ffb1\",\n        &etherscan_key,\n        Chain::mainnet(),\n    )\n    .await\n    .expect(\"failed to fetch source code from etherscan\");\n\n    prj.add_source(\"SystemConfig\", &real_source);\n    prj.write_config(Config {\n        evm_version: EvmVersion::London,\n        optimizer_runs: Some(999999),\n        optimizer: Some(true),\n        cbor_metadata: false,\n        bytecode_hash: BytecodeHash::None,\n        ..Default::default()\n    });\n    // Build once with correct source (creates cache)\n    cmd.forge_fuse().arg(\"build\").assert_success();\n\n    let source_code = r#\"\n    contract SystemConfig {\n        uint256 public constant MODIFIED_VALUE = 999;\n\n        function someFunction() public pure returns (uint256) {\n            return MODIFIED_VALUE;\n        }\n    }\n    \"#;\n\n    // Now replace with different incorrect source code\n    prj.add_source(\"SystemConfig\", source_code);\n    let etherscan_key = next_etherscan_api_key();\n    let args = vec![\n        \"verify-bytecode\",\n        \"0xba2492e52F45651B60B8B38d4Ea5E2390C64Ffb1\",\n        \"SystemConfig\",\n        \"--etherscan-api-key\",\n        &etherscan_key,\n        \"--verifier\",\n        \"etherscan\",\n        \"--verifier-url\",\n        \"https://api.etherscan.io/v2/api?chainid=1\",\n        \"--rpc-url\",\n        &rpc_url,\n    ];\n    let output = cmd.forge_fuse().args(args).assert_success().get_output().stderr_lossy();\n\n    // Verify that bytecode does NOT match (recompiled with incorrect source)\n    assert!(output.contains(\"Error: Creation code did not match\".to_string().as_str()));\n    assert!(output.contains(\"Error: Runtime code did not match\".to_string().as_str()));\n});\n\n// Test predeploy contracts\n// TODO: Add test utils for base such as basescan keys and alchemy keys.\n// WETH9 Predeploy\n// forgetest_async!(can_verify_predeploys, |prj, cmd| {\n//     test_verify_bytecode_with_ignore(\n//         prj,\n//         cmd,\n//         \"0x4200000000000000000000000000000000000006\",\n//         \"WETH9\",\n//         Config {\n//             evm_version: EvmVersion::default(),\n//             optimizer: Some(true),\n//             optimizer_runs: 10000,\n//             cbor_metadata: true,\n//             bytecode_hash: BytecodeHash::Bzzr1,\n//             ..Default::default()\n//         },\n//         \"etherscan\",\n//         \"https://api.basescan.org/api\",\n//         (\"ignored\", \"partial\"),\n//         \"creation\",\n//         Chain::base_mainnet(),\n//     ).await;\n// });\n"
  },
  {
    "path": "crates/forge/tests/cli/version.rs",
    "content": "use foundry_test_utils::{forgetest, str};\n\nforgetest!(print_short_version, |_prj, cmd| {\n    cmd.arg(\"-V\").assert_success().stdout_eq(str![[r#\"\nforge [..]-[..] ([..] [..])\n\n\"#]]);\n});\n\nforgetest!(print_long_version, |_prj, cmd| {\n    cmd.arg(\"--version\").assert_success().stdout_eq(str![[r#\"\nforge Version: [..]\nCommit SHA: [..]\nBuild Timestamp: [..]\nBuild Profile: [..]\n\n\"#]]);\n});\n"
  },
  {
    "path": "crates/forge/tests/fixtures/CreateXScript.sol",
    "content": "import \"forge-std/Script.sol\";\nimport {Vm} from \"forge-std/Vm.sol\";\ncontract CreateXGuardSaltMinimal {\n    enum SenderBytes {\n        MsgSender,\n        ZeroAddress,\n        Random\n    }\n\n    enum RedeployProtectionFlag {\n        True,\n        False,\n        Unspecified\n    }\n\n    error InvalidSalt(address emitter);\n    address internal constant _SELF = address(0xba5Ed099633D3B313e4D5F7bdc1305d3c28ba5Ed);\n\n    function _guard(bytes32 salt) internal view returns (bytes32 guardedSalt) {\n        (SenderBytes senderBytes, RedeployProtectionFlag redeployProtectionFlag) = _parseSalt({salt: salt});\n\n        if (senderBytes == SenderBytes.MsgSender && redeployProtectionFlag == RedeployProtectionFlag.True) {\n            guardedSalt = keccak256(abi.encode(msg.sender, block.chainid, salt));\n        } else if (senderBytes == SenderBytes.MsgSender && redeployProtectionFlag == RedeployProtectionFlag.False) {\n            guardedSalt = _efficientHash({a: bytes32(uint256(uint160(msg.sender))), b: salt});\n        } else if (senderBytes == SenderBytes.MsgSender) {\n            revert InvalidSalt({emitter: _SELF});\n        } else if (senderBytes == SenderBytes.ZeroAddress && redeployProtectionFlag == RedeployProtectionFlag.True) {\n            guardedSalt = _efficientHash({a: bytes32(block.chainid), b: salt});\n        } else if (\n            senderBytes == SenderBytes.ZeroAddress && redeployProtectionFlag == RedeployProtectionFlag.Unspecified\n        ) {\n            revert InvalidSalt({emitter: _SELF});\n        } else {\n            guardedSalt = (salt != _generateSalt()) ? keccak256(abi.encode(salt)) : salt;\n        }\n    }\n\n    function _parseSalt(\n        bytes32 salt\n    ) internal view returns (SenderBytes senderBytes, RedeployProtectionFlag redeployProtectionFlag) {\n        if (address(bytes20(salt)) == msg.sender && bytes1(salt[20]) == hex\"01\") {\n            (senderBytes, redeployProtectionFlag) = (SenderBytes.MsgSender, RedeployProtectionFlag.True);\n        } else if (address(bytes20(salt)) == msg.sender && bytes1(salt[20]) == hex\"00\") {\n            (senderBytes, redeployProtectionFlag) = (SenderBytes.MsgSender, RedeployProtectionFlag.False);\n        } else if (address(bytes20(salt)) == msg.sender) {\n            (senderBytes, redeployProtectionFlag) = (SenderBytes.MsgSender, RedeployProtectionFlag.Unspecified);\n        } else if (address(bytes20(salt)) == address(0) && bytes1(salt[20]) == hex\"01\") {\n            (senderBytes, redeployProtectionFlag) = (SenderBytes.ZeroAddress, RedeployProtectionFlag.True);\n        } else if (address(bytes20(salt)) == address(0) && bytes1(salt[20]) == hex\"00\") {\n            (senderBytes, redeployProtectionFlag) = (SenderBytes.ZeroAddress, RedeployProtectionFlag.False);\n        } else if (address(bytes20(salt)) == address(0)) {\n            (senderBytes, redeployProtectionFlag) = (SenderBytes.ZeroAddress, RedeployProtectionFlag.Unspecified);\n        } else if (bytes1(salt[20]) == hex\"01\") {\n            (senderBytes, redeployProtectionFlag) = (SenderBytes.Random, RedeployProtectionFlag.True);\n        } else if (bytes1(salt[20]) == hex\"00\") {\n            (senderBytes, redeployProtectionFlag) = (SenderBytes.Random, RedeployProtectionFlag.False);\n        } else {\n            (senderBytes, redeployProtectionFlag) = (SenderBytes.Random, RedeployProtectionFlag.Unspecified);\n        }\n    }\n\n\n    function _efficientHash(bytes32 a, bytes32 b) internal pure returns (bytes32 hash) {\n        assembly (\"memory-safe\") {\n            mstore(0x00, a)\n            mstore(0x20, b)\n            hash := keccak256(0x00, 0x40)\n        }\n    }\n\n\nfunction _generateSalt() internal view returns (bytes32 salt) {\n        unchecked {\n            salt = keccak256(\n                abi.encode(\n                    blockhash(block.number - 32),\n                    block.coinbase,\n                    block.number,\n                    block.timestamp,\n                    block.prevrandao,\n                    block.chainid,\n                    msg.sender\n                )\n            );\n        }\n    }\n}\n\ninterface CreateX {\n    function deployCreate3(bytes32 salt, bytes memory initCode) external payable returns (address newContract);\n    function computeCreate3Address(bytes32 salt) external view returns (address computedAddress);\n}\n\nstruct UNISWAP_ADDRESSES {\n    address payable UNISWAP_POSITION_MANAGER;\n    address UNISWAP_PERMIT2;\n    address UNISWAP_POOL_MANAGER;\n    address UNISWAP_STATE_VIEW;\n}\n\ncontract CreateXScript is Script, CreateXGuardSaltMinimal {\n    mapping(uint256 => UNISWAP_ADDRESSES) uniswapAddresses;\n\n    function run() public {\n        bytes32 SALT = keccak256(hex\"f39Fd6e51aad88F6F4ce6aB8827279cffFb922660077e9ad43da87c100f02196\");\n\n        // // Local test, addresses mirror Base\n        uniswapAddresses[1616161] = UNISWAP_ADDRESSES({\n            UNISWAP_POSITION_MANAGER: payable(\n                0x7C5f5A4bBd8fD63184577525326123B519429bDc\n            ),\n            UNISWAP_PERMIT2: 0x000000000022D473030F116dDEE9F6B43aC78BA3,\n            UNISWAP_POOL_MANAGER: 0x498581fF718922c3f8e6A244956aF099B2652b2b,\n            UNISWAP_STATE_VIEW: 0xA3c0c9b65baD0b08107Aa264b0f3dB444b867A71\n        });\n\n\n        CreateX createx = CreateX(0xba5Ed099633D3B313e4D5F7bdc1305d3c28ba5Ed);\n\n        address calculatedC1Address = createx.computeCreate3Address(_guard(bytes32(uint256(SALT) + 2)));\n        address calculatedC2Address = createx.computeCreate3Address(_guard(bytes32(uint256(SALT) + 1)));\n\n        vm.startBroadcast();\n\n        bytes memory c0CreationCode = hex\"60803461011457601f610f2b38819003918201601f19168301916001600160401b038311848410176101185780849260e094604052833981010312610114576100478161012c565b60208201519091906001600160a01b038116036101145760c081610070604061009e940161012c565b5061007d6060820161012c565b5061008a6080820161012c565b5061009760a0820161012c565b500161012c565b506001600160a01b03168015610101575f80546001600160a01b031981168317825560405192916001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09080a3610dea90816101418239f35b631e4fbdf760e01b5f525f60045260245ffd5b5f80fd5b634e487b7160e01b5f52604160045260245ffd5b51906001600160a01b03821682036101145756fe6080806040526004361015610012575f80fd5b5f905f3560e01c9081630abd5fb9146109a457508063188b3c0f14610987578063222d23501461095f578063335abd45146109375780633c0299e51461090f57806346ae0668146108e75780634c25cf26146108ca57806351f18899146108a2578063527203e31461081357806359ac19c1146107c7578063691a0f1e146106555780636c3dd13e14610637578063715018a6146105dd578063787a08a6146105bf5780637c85a183146105a15780638a14117a146105835780638b211c02146105655780638da5cb5b1461053e578063a0beb08414610512578063aaba5271146104aa578063ad55af4b14610481578063b531d7f3146102d8578063ba405a0c146102af578063d2ca211514610291578063d6fbf20214610273578063dd7b883814610255578063e13cbe3814610237578063e2c6505614610219578063ea515b87146101f05763f2fde38b14610168575f80fd5b346101ed5760203660031901126101ed576101816109be565b610189610b6d565b6001600160a01b031680156101d95781546001600160a01b03198116821783556001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08380a380f35b631e4fbdf760e01b82526004829052602482fd5b80fd5b50346101ed57806003193601126101ed576012546040516001600160a01b039091168152602090f35b50346101ed57806003193601126101ed576020600c54604051908152f35b50346101ed57806003193601126101ed576020601054604051908152f35b50346101ed57806003193601126101ed576020600854604051908152f35b50346101ed57806003193601126101ed576020600a54604051908152f35b50346101ed57806003193601126101ed576020600554604051908152f35b50346101ed57806003193601126101ed57600f546040516001600160a01b039091168152602090f35b50346101ed576101803660031901126101ed5760a435610124356001600160a01b03811690610104359060c4359083900361047d57610144356001600160a01b03811694908590036104795761032c610b6d565b8260011b8381046002148415171561043d57826b033b2e3c9fd0803ce8000000036b033b2e3c9fd0803ce800000081116104655761037381670de0b6b3a764000084610d02565b91846b033b2e3c9fd0803ce80000001461045157670de0b6b3a764000090091515810180911161043d57811061042e57600435600555602435600655604435600755606435600855608435600955600a55600d5560e435600b55600c556bffffffffffffffffffffffff60a01b600e541617600e556bffffffffffffffffffffffff60a01b600f541617600f55610164356010557fd9d41def84794db66ae5ab5d041caacb905afc49e9ca3604aa41bb1ea8a582e28180a180f35b635a2ee95360e11b8652600486fd5b634e487b7160e01b87526011600452602487fd5b634e487b7160e01b89526012600452602489fd5b634e487b7160e01b88526011600452602488fd5b8580fd5b8480fd5b50346101ed57806003193601126101ed576004546040516001600160a01b039091168152602090f35b50346101ed5760603660031901126101ed576044356104c7610b6d565b8015610503576004356014556024356013556015557f4bbf648868a599cc55656d8bca2c460f8c2136d467ea4c033a8aaaee493cdfbf8180a180f35b63166cb78960e01b8252600482fd5b50346101ed5760203660031901126101ed5760206105366105316109be565b610a1a565b604051908152f35b50346101ed57806003193601126101ed57546040516001600160a01b039091168152602090f35b50346101ed57806003193601126101ed576020600d54604051908152f35b50346101ed57806003193601126101ed576020600654604051908152f35b50346101ed57806003193601126101ed576020600b54604051908152f35b50346101ed57806003193601126101ed576020600754604051908152f35b50346101ed57806003193601126101ed576105f6610b6d565b80546001600160a01b03198116825581906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b50346101ed57806003193601126101ed576020600954604051908152f35b503461075b57606036600319011261075b5761066f6109be565b600e5460243590604435906001600160a01b03163303610796576011546001600160a01b031692831561075f57833b1561075b575f80916064604051809481936324d5fda360e01b835260018060a01b0316988960048401528860248401528760448401525af1801561075057610715575b507f20dbc16160364bc8d282b93f41c769d3b024f0f8844f96fae2d74b2b71d844719160409182519182526020820152a280f35b6040919450916107465f7f20dbc16160364bc8d282b93f41c769d3b024f0f8844f96fae2d74b2b71d84471946109d4565b5f949150916106e1565b6040513d5f823e3d90fd5b5f80fd5b60405162461bcd60e51b815260206004820152600f60248201526e6e6f2d63756c742d666163746f727960881b6044820152606490fd5b60405162461bcd60e51b81526020600482015260096024820152686f6e6c792d686f6f6b60b81b6044820152606490fd5b3461075b575f36600319011261075b57600154600254600354600454604080516001600160a01b0395861681529385166020850152918416918301919091529091166060820152608090f35b3461075b575f36600319011261075b57610180600554600654600754600854600954600a54600d54600b5491600c549360018060a01b03600e54169560018060a01b03600f541697601054996040519b8c5260208c015260408b015260608a0152608089015260a088015260c087015260e0860152610100850152610120840152610140830152610160820152f35b3461075b575f36600319011261075b576001546040516001600160a01b039091168152602090f35b3461075b575f36600319011261075b576020601554604051908152f35b3461075b575f36600319011261075b57600e546040516001600160a01b039091168152602090f35b3461075b575f36600319011261075b576011546040516001600160a01b039091168152602090f35b3461075b575f36600319011261075b576002546040516001600160a01b039091168152602090f35b3461075b575f36600319011261075b576003546040516001600160a01b039091168152602090f35b3461075b575f36600319011261075b576020601454604051908152f35b3461075b575f36600319011261075b576020906013548152f35b600435906001600160a01b038216820361075b57565b90601f8019910116810190811067ffffffffffffffff8211176109f657604052565b634e487b7160e01b5f52604160045260245ffd5b519062ffffff8216820361075b57565b600f546001600160a01b03908116908216808214610b5e57819282819210610b53575b5060018060a01b03600454169260405160a0810181811067ffffffffffffffff8211176109f65760809160a091604052600180831b0384168152600180831b0385166020820152610bb86040820152603c60608201525f8382015220602460405180978193633205590760e21b835260048301525afa938415610750575f94610ae5575b506001600160a01b03841615610add57610ada93610c51565b90565b505050505f90565b9093506080813d608011610b4b575b81610b01608093836109d4565b8101031261075b578051906001600160a01b038216820361075b5760208101518060020b0361075b57606081610b3c6040610b439401610a0a565b5001610a0a565b50925f610ac1565b3d9150610af4565b92508190505f610a3d565b505050670de0b6b3a764000090565b5f546001600160a01b03163303610b8057565b63118cdaa760e01b5f523360045260245ffd5b5f908015610c4b578080600114610c4357600214610c3c5760016101338210166001600b83101617610c2e579060019060025b60018111610bf25750825f19048211610bde57500290565b634e487b7160e01b81526011600452602490fd5b92805f19048111610c1a5760018416610c11575b80029260011c610bc6565b80920291610c06565b634e487b7160e01b82526011600452602482fd5b6002900a919080610bde5750565b5050600490565b505050600190565b50505f90565b5f9390926001600160a01b039182169291168203610cb75750610c7e916001600160a01b03169050610b93565b90610c96600160c01b670de0b6b3a764000084610d02565b91600160c01b90670de0b6b3a7640000900915158201809211610bde575090565b9192506001600160a01b0390911603610cf357610ada90610ce0906001600160a01b0316610b93565b670de0b6b3a7640000600160c01b610d02565b63e6f2de8760e01b5f5260045ffd5b91818302915f1981850993838086109503948086039514610d925784831115610d7a5790829109815f0382168092046002816003021880820260020302808202600203028082026002030280820260020302808202600203028091026002030293600183805f03040190848311900302920304170290565b82634e487b715f52156003026011186020526024601cfd5b505080925015610da0570490565b634e487b7160e01b5f52601260045260245ffdfea26469706673582212204c94689568baebf5fff57a2f3e072a1fb7067e2c83f098eac9e838fbfdded18664736f6c634300081a0033\";\n\n        bytes memory c0DeploymentCode = abi.encodePacked(\n            c0CreationCode,\n            abi.encode(\n                0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266,\n                uniswapAddresses[block.chainid].UNISWAP_POSITION_MANAGER,\n                uniswapAddresses[block.chainid].UNISWAP_PERMIT2,\n                uniswapAddresses[block.chainid].UNISWAP_POOL_MANAGER,\n                uniswapAddresses[block.chainid].UNISWAP_STATE_VIEW,\n                calculatedC1Address,\n                calculatedC2Address\n            )\n        );\n\n        address c0Address = createx.deployCreate3(\n            SALT,\n            c0DeploymentCode\n        );\n\n\n        bytes memory c2CreationCode = hex\"60803460b857601f6112a038819003918201601f19168301916001600160401b0383118484101760bc5780849260209460405283398101031260b857516001600160a01b0381169081900360b857801560a5575f80546001600160a01b031981168317825560405192916001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09080a36111cf90816100d18239f35b631e4fbdf760e01b5f525f60045260245ffd5b5f80fd5b634e487b7160e01b5f52604160045260245ffdfe6080806040526004361015610012575f80fd5b5f905f3560e01c9081630d31612614610f52575080631f94e50314610e4757806324d5fda314610ccb57806343fe85ba14610c8e5780634fb6df17146109c35780634ff013711461099a5780635eeb1bbc1461095b578063646ec81d1461086b5780636f8c57831461080a578063712232d5146107d1578063715018a61461077757806373c376581461073e5780637734d07614610685578063862a8eff146106445780638c730f2a146106185780638da5cb5b146105f1578063a05ff6b8146105ae578063aed19359146101bb578063d48418a1146101825763f2fde38b146100fa575f80fd5b3461017f57602036600319011261017f57610113610f86565b61011b6110de565b6001600160a01b0316801561016b5781546001600160a01b03198116821783556001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08380a380f35b631e4fbdf760e01b82526004829052602482fd5b80fd5b503461017f57602036600319011261017f576020906040906001600160a01b036101aa610f86565b168152600883522054604051908152f35b503461017f57608036600319011261017f576101d5610f86565b9060243567ffffffffffffffff81116105aa576101f6903690600401610fd4565b60443567ffffffffffffffff81116105a657610216903690600401610fd4565b926064356001600160a01b038116908190036105a257835460405163ea515b8760e01b81526001600160a01b0390911695906020816004818a5afa908115610597578691610559575b506001600160a01b031693841561054a578560409461031d946102e360016020809b9a976102b9600583809a8e519b818d9251918291018484015e8101641021b7b4b760d91b838201520301601a1981018b520189610fb2565b8a519c818e9251918291018484015e8101604360f81b838201520301601e1981018c52018a610fb2565b61032f8751998a9788968795637b17ab9560e01b875260018060a01b0316600487015286602487015260c0604487015260c48601906110ba565b848103600319016064860152906110ba565b9060848301528260a483015203925af19182156104835781908293610502575b506001600160a01b0316808252600360209081526040808420805460ff191660011790555163188b3c0f60e01b8152939192919084600481885afa9384156104c35782946104ce575b5060018060a01b03169283825260066020526040822055604051630abd5fb960e01b8152602081600481885afa9081156104c3578291610490575b5060049460209185845260088352604084205560405195868092632612e79360e11b82525afa93841561048357819461044a575b50602083928195604084867fad5759c1cafdae1264943f6fa2482923381aa1c5fe5325f77329f99db30053ed9652600785522055604051908152a2604051908152f35b93506020843d60201161047b575b8161046560209383610fb2565b81010312610477579251926020610407565b5f80fd5b3d9150610458565b50604051903d90823e3d90fd5b90506020813d6020116104bb575b816104ab60209383610fb2565b81010312610477575160046103d3565b3d915061049e565b6040513d84823e3d90fd5b9093506020813d6020116104fa575b816104ea60209383610fb2565b810103126104775751925f610398565b3d91506104dd565b9250506040823d604011610542575b8161051e60409383610fb2565b8101031261017f5761053b6020610534846110a6565b93016110a6565b915f61034f565b3d9150610511565b6370b649dd60e01b8652600486fd5b90506020813d60201161058f575b8161057460209383610fb2565b8101031261058b57610585906110a6565b5f61025f565b8580fd5b3d9150610567565b6040513d88823e3d90fd5b8380fd5b8280fd5b5080fd5b503461017f57604036600319011261017f576020906040906001600160a01b036105d6610f86565b168152600a8352818120602435825283522054604051908152f35b503461017f578060031936011261017f57546040516001600160a01b039091168152602090f35b503461017f57602036600319011261017f57602061063c610637610f86565b61105b565b604051908152f35b503461017f57602036600319011261017f576020906001600160a01b03610669610f86565b16815260018252604060018060a01b0391205416604051908152f35b503461017f57606036600319011261017f5761069f610f86565b906106a8610f9c565b916106b16110de565b6001600160a01b03168082526002602052604082205490929060ff161561072f578282933b1561072b576040516340c10f1960e01b81526001600160a01b039290921660048301526044803560248401528391839190829084905af180156104c35761071a5750f35b8161072491610fb2565b61017f5780f35b5050fd5b638c5d908560e01b8252600482fd5b503461017f57602036600319011261017f576020906040906001600160a01b03610766610f86565b168152600783522054604051908152f35b503461017f578060031936011261017f576107906110de565b80546001600160a01b03198116825581906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b503461017f57602036600319011261017f576020906040906001600160a01b036107f9610f86565b168152600683522054604051908152f35b503461017f57602036600319011261017f576080906040906001600160a01b03610832610f86565b16815260096020522060ff8154169060018101549060036002820154910154916040519315158452602084015260408301526060820152f35b503461017f57602036600319011261017f57610885610f86565b6004546001600160a01b0316330361094c576001600160a01b0316808252600260209081526040808420805460ff191660011790558284526005909152822054156108f2575b7fa4d13a5bef1890eddfd4d435735b46ed074a5e4b8f0a421cd526aeeef8141d3a8280a280f35b80825260056020524260408320558082526005602052807faed14053ca40d8865c112ef238ff360fe2189d5730000f57a6b88caf3198650e60408085205483865260076020528186205482519182526020820152a26108cb565b635651e6f560e11b8252600482fd5b503461017f57602036600319011261017f5760209060ff906040906001600160a01b03610986610f86565b168152600384522054166040519015158152f35b503461017f578060031936011261017f576004546040516001600160a01b039091168152602090f35b5034610477576040366003190112610477576109dd610f86565b602435908115610c7f576001600160a01b03165f818152600960205260409081902090516080810167ffffffffffffffff811182821017610c6b5760405260ff82541615801582526001830154916020810192835260606003600286015495604084019687520154910152610c5d57825f52600160205260018060a01b0360405f20541691825f52600260205260ff60405f20541615610c4e57815190835f52600a60205260405f20825f5260205260405f2054918215610c3f57845f52600660205260405f20548015610c305790879291865f52600860205260405f2054670de0b6b3a76400009290815b610bf0575050610af292610ae5610af7969593610aed93611104565b90519061102a565b61102a565b61103d565b8015610be157833b156104775760405163079cc67960e41b8152336004820152602481018690525f8160448183895af18015610bd657610bc1575b50823b1561058b576040516340c10f1960e01b8152336004820152602481018290528690818160448183895af180156104c357610bac575b505090516040805195865260208601929092529084015233927f142894e15d18cf7c1106a97eefe825087bf328fa8730129e3f89134321b3a23490606090a480f35b81610bb691610fb2565b61058b57855f610b6a565b610bce9196505f90610fb2565b5f945f610b32565b6040513d5f823e3d90fd5b639a57326560e01b5f5260045ffd5b909192939450600180831614610c1a575b80610c0b91611104565b899493929160011c9081610ac9565b92610c2884610c0b92611104565b939050610c01565b63374c934360e11b5f5260045ffd5b632959df1160e21b5f5260045ffd5b638c5d908560e01b5f5260045ffd5b62ad587d60e81b5f5260045ffd5b634e487b7160e01b5f52604160045260245ffd5b6313aab74360e01b5f5260045ffd5b34610477576020366003190112610477576001600160a01b03610caf610f86565b165f526002602052602060ff60405f2054166040519015158152f35b3461047757606036600319011261047757610ce4610f86565b60243560443591610cf36110de565b8115610e38578215610e29576001600160a01b039081165f8181526001602052604090205490939116918215610e1a57825f52600560205260405f205415610e0b57835f52600960205260405f2080549060ff8216610dfc57600384916001610d5b8861105b565b9460ff19161781558360018201558460028201550155610d7b838361102a565b92845f52600a60205260405f20825f5260205260405f20908154948501809511610de8577fc8ed84018dd91b7f9ef452fe95948d9dad8e47361ad1dd5886c54398e838e24094610de39255604051938493846040919493926060820195825260208201520152565b0390a3005b634e487b7160e01b5f52601160045260245ffd5b630931f96360e41b5f5260045ffd5b63277e703d60e21b5f5260045ffd5b63325ddddd60e01b5f5260045ffd5b639fbba64f60e01b5f5260045ffd5b637294708f60e11b5f5260045ffd5b3461047757604036600319011261047757610e60610f86565b610e68610f9c565b6004546001600160a01b03163303610f43576001600160a01b03169081158015610f32575b610f23576001600160a01b03165f8181526002602052604090205490919060ff1615610c4e575f818152600160205260409020546001600160a01b0316610f11575f81815260016020526040812080546001600160a01b031916841790557f0cb63fc6bb9f844b450c8052989a65f162ecac87757ca2c3921e0e9b7c4ccff69080a3005b631535136360e31b5f5260045260245ffd5b63e6c4247b60e01b5f5260045ffd5b506001600160a01b03811615610e8d565b635651e6f560e11b5f5260045ffd5b34610477576020366003190112610477576020906001600160a01b03610f76610f86565b165f526005825260405f20548152f35b600435906001600160a01b038216820361047757565b602435906001600160a01b038216820361047757565b90601f8019910116810190811067ffffffffffffffff821117610c6b57604052565b81601f820112156104775780359067ffffffffffffffff8211610c6b5760405192611009601f8401601f191660200185610fb2565b8284526020838301011161047757815f926020809301838601378301015290565b81810292918115918404141715610de857565b8115611047570490565b634e487b7160e01b5f52601260045260245ffd5b6001600160a01b03165f8181526005602052604090205415610e0b57805f52600560205260405f20544203428111610de8576110a3915f52600760205260405f20549061103d565b90565b51906001600160a01b038216820361047757565b805180835260209291819084018484015e5f828201840152601f01601f1916010190565b5f546001600160a01b031633036110f157565b63118cdaa760e01b5f523360045260245ffd5b9190915f838202915f19858209918380841093039280840393146111865782670de0b6b3a7640000111561117457507faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106699394670de0b6b3a7640000910990828211900360ee1b910360121c170290565b634e487b71905260116020526024601cfd5b505050670de0b6b3a7640000919250049056fea2646970667358221220e8dac8dec112cb258e7bd8c159fd1da98ea741bb7b01073a1f31609d4cf729a064736f6c634300081a0033\";\n        bytes memory c2DeploymentCode = abi.encodePacked(\n            c2CreationCode,\n            abi.encode(c0Address)\n        );\n\n        address c2Address = createx.deployCreate3(\n            bytes32(uint256(SALT) + 1),\n            c2DeploymentCode\n        );\n\n        // Commenting out this check causes script to pass\n        if (c2Address != calculatedC2Address) {\n            console.log(\"address mismatch\");\n        }\n\n        vm.stopBroadcast();\n    }\n}"
  },
  {
    "path": "crates/forge/tests/fixtures/ExpectCallFailures.t.sol",
    "content": "// Note Used in forge-cli tests to assert failures.\n// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"./test.sol\";\nimport \"./Vm.sol\";\n\ncontract Contract {\n    function numberA() public pure returns (uint256) {\n        return 1;\n    }\n\n    function numberB() public pure returns (uint256) {\n        return 2;\n    }\n\n    function add(uint256 a, uint256 b) public pure returns (uint256) {\n        return a + b;\n    }\n\n    function pay(uint256 a) public payable returns (uint256) {\n        return a;\n    }\n}\n\ncontract NestedContract {\n    Contract private inner;\n\n    constructor(Contract _inner) {\n        inner = _inner;\n    }\n\n    function sum() public view returns (uint256) {\n        return inner.numberA() + inner.numberB();\n    }\n\n    function forwardPay() public payable returns (uint256) {\n        return inner.pay{gas: 50_000, value: 1}(1);\n    }\n\n    function addHardGasLimit() public view returns (uint256) {\n        return inner.add{gas: 50_000}(1, 1);\n    }\n\n    function hello() public pure returns (string memory) {\n        return \"hi\";\n    }\n\n    function sumInPlace(uint256 a, uint256 b) public view returns (uint256) {\n        return a + b + 42;\n    }\n}\n\ncontract ExpectCallFailureTest is DSTest {\n    Vm constant vm = Vm(HEVM_ADDRESS);\n\n    function exposed_callTargetNTimes(Contract target, uint256 a, uint256 b, uint256 times) public pure {\n        for (uint256 i = 0; i < times; i++) {\n            target.add(a, b);\n        }\n    }\n\n    function exposed_failExpectInnerCall(NestedContract target) public {\n        // this function does not call inner\n        target.hello();\n    }\n\n    function testShouldFailExpectMultipleCallsWithDataAdditive() public {\n        Contract target = new Contract();\n        vm.expectCall(address(target), abi.encodeWithSelector(target.add.selector, 1, 2));\n        vm.expectCall(address(target), abi.encodeWithSelector(target.add.selector, 1, 2));\n        vm.expectCall(address(target), abi.encodeWithSelector(target.add.selector, 1, 2));\n        // Not enough calls to satisfy the additive expectCall, which expects 3 calls.\n        this.exposed_callTargetNTimes(target, 1, 2, 2);\n    }\n\n    function testShouldFailExpectCallWithData() public {\n        Contract target = new Contract();\n        vm.expectCall(address(target), abi.encodeWithSelector(target.add.selector, 1, 2), 1);\n        this.exposed_callTargetNTimes(target, 3, 3, 1);\n    }\n\n    function testShouldFailExpectInnerCall() public {\n        Contract inner = new Contract();\n        NestedContract target = new NestedContract(inner);\n\n        vm.expectCall(address(inner), abi.encodeWithSelector(inner.numberB.selector));\n\n        this.exposed_failExpectInnerCall(target);\n    }\n\n    function testShouldFailExpectSelectorCall() public {\n        Contract target = new Contract();\n        vm.expectCall(address(target), abi.encodeWithSelector(target.add.selector));\n    }\n\n    function testShouldFailExpectCallWithMoreParameters() public {\n        Contract target = new Contract();\n        vm.expectCall(address(target), abi.encodeWithSelector(target.add.selector, 3, 3, 3));\n        target.add(3, 3);\n        this.exposed_callTargetNTimes(target, 3, 3, 1);\n    }\n\n    function testShouldFailExpectCallValue() public {\n        Contract target = new Contract();\n        vm.expectCall(address(target), 1, abi.encodeWithSelector(target.pay.selector, 2));\n    }\n\n    function exposed_addHardGasLimit(NestedContract target) public {\n        target.addHardGasLimit();\n    }\n\n    function testShouldFailExpectCallWithNoValueAndWrongGas() public {\n        Contract inner = new Contract();\n        NestedContract target = new NestedContract(inner);\n        vm.expectCall(address(inner), 0, 25_000, abi.encodeWithSelector(inner.add.selector, 1, 1));\n        this.exposed_addHardGasLimit(target);\n    }\n\n    function testShouldFailExpectCallWithNoValueAndWrongMinGas() public {\n        Contract inner = new Contract();\n        NestedContract target = new NestedContract(inner);\n        vm.expectCallMinGas(address(inner), 0, 50_001, abi.encodeWithSelector(inner.add.selector, 1, 1));\n        this.exposed_addHardGasLimit(target);\n    }\n\n    /// Ensure that you cannot use expectCall with an expectRevert.\n    function testShouldFailExpectCallWithRevertDisallowed() public {\n        Contract target = new Contract();\n        vm.expectRevert();\n        vm.expectCall(address(target), abi.encodeWithSelector(target.add.selector));\n        this.exposed_callTargetNTimes(target, 5, 5, 1);\n    }\n}\n\ncontract ExpectCallCountFailureTest is DSTest {\n    Vm constant vm = Vm(HEVM_ADDRESS);\n\n    function testShouldFailExpectCallCountWithWrongCount() public {\n        Contract target = new Contract();\n        vm.expectCall(address(target), abi.encodeWithSelector(target.add.selector, 1, 2), 2);\n        target.add(1, 2);\n    }\n\n    function testShouldFailExpectCountInnerCall() public {\n        Contract inner = new Contract();\n        NestedContract target = new NestedContract(inner);\n\n        vm.expectCall(address(inner), abi.encodeWithSelector(inner.numberB.selector), 1);\n\n        // this function does not call inner\n        target.hello();\n    }\n\n    function exposed_pay(Contract target, uint256 value, uint256 amount) public payable {\n        target.pay{value: value}(amount);\n    }\n\n    function testShouldFailExpectCallCountValue() public {\n        Contract target = new Contract();\n        vm.expectCall(address(target), 1, abi.encodeWithSelector(target.pay.selector, 2), 1);\n        this.exposed_pay{value: 2}(target, 2, 2);\n    }\n\n    function exposed_addHardGasLimit(NestedContract target, uint256 times) public {\n        for (uint256 i = 0; i < times; i++) {\n            target.addHardGasLimit();\n        }\n    }\n\n    function testShouldFailExpectCallCountWithNoValueAndWrongGas() public {\n        Contract inner = new Contract();\n        NestedContract target = new NestedContract(inner);\n        vm.expectCall(address(inner), 0, 25_000, abi.encodeWithSelector(inner.add.selector, 1, 1), 2);\n        this.exposed_addHardGasLimit(target, 2);\n    }\n\n    function testShouldFailExpectCallCountWithNoValueAndWrongMinGas() public {\n        Contract inner = new Contract();\n        NestedContract target = new NestedContract(inner);\n        vm.expectCallMinGas(address(inner), 0, 50_001, abi.encodeWithSelector(inner.add.selector, 1, 1), 1);\n        this.exposed_addHardGasLimit(target, 1);\n    }\n}\n\ncontract ExpectCallMixedFailureTest is DSTest {\n    Vm constant vm = Vm(HEVM_ADDRESS);\n\n    function exposed_callTargetNTimes(Contract target, uint256 a, uint256 b, uint256 times) public {\n        for (uint256 i = 0; i < times; i++) {\n            target.add(1, 2);\n        }\n    }\n\n    function testShouldFailOverrideNoCountWithCount() public {\n        Contract target = new Contract();\n        vm.expectCall(address(target), abi.encodeWithSelector(target.add.selector, 1, 2));\n        // You should not be able to overwrite a expectCall that had no count with some count.\n        vm.expectCall(address(target), abi.encodeWithSelector(target.add.selector, 1, 2), 2);\n        this.exposed_callTargetNTimes(target, 1, 2, 2);\n    }\n\n    function testShouldFailOverrideCountWithCount() public {\n        Contract target = new Contract();\n        vm.expectCall(address(target), abi.encodeWithSelector(target.add.selector, 1, 2), 2);\n        // You should not be able to overwrite a expectCall that had a count with some count.\n        vm.expectCall(address(target), abi.encodeWithSelector(target.add.selector, 1, 2), 1);\n        target.add(1, 2);\n        target.add(1, 2);\n    }\n\n    function testShouldFailOverrideCountWithNoCount() public {\n        Contract target = new Contract();\n        vm.expectCall(address(target), abi.encodeWithSelector(target.add.selector, 1, 2), 2);\n        // You should not be able to overwrite a expectCall that had a count with no count.\n        vm.expectCall(address(target), abi.encodeWithSelector(target.add.selector, 1, 2));\n        target.add(1, 2);\n        target.add(1, 2);\n    }\n}\n"
  },
  {
    "path": "crates/forge/tests/fixtures/ExpectCreateFailures.t.sol",
    "content": "// Note Used in forge-cli tests to assert failures.\n// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"./test.sol\";\nimport \"./Vm.sol\";\n\ncontract Contract {\n    function add(uint256 a, uint256 b) public pure returns (uint256) {\n        return a + b;\n    }\n}\n\ncontract OtherContract {\n    function sub(uint256 a, uint256 b) public pure returns (uint256) {\n        return a - b;\n    }\n}\n\ncontract ExpectCreateFailureTest is DSTest {\n    Vm constant vm = Vm(HEVM_ADDRESS);\n    bytes contractBytecode =\n        vm.getDeployedCode(\"ExpectCreateFailures.t.sol:Contract\");\n\n    function testShouldFailExpectCreate() public {\n        vm.expectCreate(contractBytecode, address(this));\n    }\n\n    function testShouldFailExpectCreate2() public {\n        vm.expectCreate2(contractBytecode, address(this));\n    }\n\n    function testShouldFailExpectCreateWrongBytecode() public {\n        vm.expectCreate(contractBytecode, address(this));\n        new OtherContract();\n    }\n\n    function testShouldFailExpectCreate2WrongBytecode() public {\n        vm.expectCreate2(contractBytecode, address(this));\n        new OtherContract{salt: \"foobar\"}();\n    }\n\n    function testShouldFailExpectCreateWrongDeployer() public {\n        vm.expectCreate(contractBytecode, address(0));\n        new Contract();\n    }\n\n    function testShouldFailExpectCreate2WrongDeployer() public {\n        vm.expectCreate2(contractBytecode, address(0));\n        new Contract();\n    }\n\n    function testShouldFailExpectCreateWrongScheme() public {\n        vm.expectCreate(contractBytecode, address(this));\n        new Contract{salt: \"foobar\"}();\n    }\n\n    function testShouldFailExpectCreate2WrongScheme() public {\n        vm.expectCreate2(contractBytecode, address(this));\n        new Contract();\n    }\n}\n"
  },
  {
    "path": "crates/forge/tests/fixtures/ExpectEmitFailures.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"./test.sol\";\nimport \"./Vm.sol\";\n\ncontract Emitter {\n    uint256 public thing;\n\n    event Something(uint256 indexed topic1, uint256 indexed topic2, uint256 indexed topic3, uint256 data);\n    event A(uint256 indexed topic1);\n    event B(uint256 indexed topic1);\n    event C(uint256 indexed topic1);\n    event D(uint256 indexed topic1);\n    event E(uint256 indexed topic1);\n\n    /// This event has 0 indexed topics, but the one in our tests\n    /// has exactly one indexed topic. Even though both of these\n    /// events have the same topic 0, they are different and should\n    /// be non-comparable.\n    ///\n    /// Ref: issue #760\n    event SomethingElse(uint256 data);\n\n    event SomethingNonIndexed(uint256 data);\n\n    function emitEvent(uint256 topic1, uint256 topic2, uint256 topic3, uint256 data) public {\n        emit Something(topic1, topic2, topic3, data);\n    }\n\n    function emitNEvents(uint256 topic1, uint256 topic2, uint256 topic3, uint256 data, uint256 n) public {\n        for (uint256 i = 0; i < n; i++) {\n            emit Something(topic1, topic2, topic3, data);\n        }\n    }\n\n    function emitMultiple(\n        uint256[2] memory topic1,\n        uint256[2] memory topic2,\n        uint256[2] memory topic3,\n        uint256[2] memory data\n    ) public {\n        emit Something(topic1[0], topic2[0], topic3[0], data[0]);\n        emit Something(topic1[1], topic2[1], topic3[1], data[1]);\n    }\n\n    function emitAndNest() public {\n        emit Something(1, 2, 3, 4);\n        emitNested(Emitter(address(this)), 1, 2, 3, 4);\n    }\n\n    function emitOutOfExactOrder() public {\n        emit SomethingNonIndexed(1);\n        emit Something(1, 2, 3, 4);\n        emit Something(1, 2, 3, 4);\n        emit Something(1, 2, 3, 4);\n    }\n\n    function emitNested(Emitter inner, uint256 topic1, uint256 topic2, uint256 topic3, uint256 data) public {\n        inner.emitEvent(topic1, topic2, topic3, data);\n    }\n\n    function getVar() public pure returns (uint256) {\n        return 1;\n    }\n\n    /// Used to test matching of consecutive different events,\n    /// even if they're not emitted right after the other.\n    function emitWindow() public {\n        emit A(1);\n        emit B(2);\n        emit C(3);\n        emit D(4);\n        emit E(5);\n    }\n\n    function emitNestedWindow() public {\n        emit A(1);\n        emit C(3);\n        emit E(5);\n        this.emitWindow();\n    }\n\n    // Used to test matching of consecutive different events\n    // split across subtree calls.\n    function emitSplitWindow() public {\n        this.emitWindow();\n        this.emitWindow();\n    }\n\n    function emitWindowAndOnTest(ExpectEmitFailureTest t) public {\n        this.emitWindow();\n        t.emitLocal();\n    }\n\n    /// Ref: issue #1214\n    function doesNothing() public pure {}\n\n    function changeThing(uint256 num) public {\n        thing = num;\n    }\n\n    /// Ref: issue #760\n    function emitSomethingElse(uint256 data) public {\n        emit SomethingElse(data);\n    }\n}\n\n/// Emulates `Emitter` in #760\ncontract LowLevelCaller {\n    function f() external {\n        (bool success,) = address(this).call(abi.encodeWithSignature(\"g()\"));\n        require(success, \"call failed\");\n    }\n\n    function g() public {}\n}\n\ncontract ExpectEmitFailureTest is DSTest {\n    Vm constant vm = Vm(HEVM_ADDRESS);\n    Emitter emitter;\n\n    event Something(uint256 indexed topic1, uint256 indexed topic2, uint256 indexed topic3, uint256 data);\n\n    event SomethingElse(uint256 indexed topic1);\n\n    event A(uint256 indexed topic1);\n    event B(uint256 indexed topic1);\n    event C(uint256 indexed topic1);\n    event D(uint256 indexed topic1);\n    event E(uint256 indexed topic1);\n\n    function setUp() public {\n        emitter = new Emitter();\n    }\n\n    function emitLocal() public {\n        emit A(1);\n    }\n\n    function testShouldFailExpectEmitDanglingNoReference() public {\n        vm.expectEmit(false, false, false, false);\n    }\n\n    function testShouldFailExpectEmitDanglingWithReference() public {\n        vm.expectEmit(false, false, false, false);\n        emit Something(1, 2, 3, 4);\n    }\n\n    /// The topics that are checked are altered to be incorrect\n    /// compared to the reference.\n    function testShouldFailExpectEmit(\n        bool checkTopic1,\n        bool checkTopic2,\n        bool checkTopic3,\n        bool checkData,\n        uint128 topic1,\n        uint128 topic2,\n        uint128 topic3,\n        uint128 data\n    ) public {\n        vm.assume(checkTopic1 || checkTopic2 || checkTopic3 || checkData);\n\n        uint256 transformedTopic1 = checkTopic1 ? uint256(topic1) + 1 : uint256(topic1);\n        uint256 transformedTopic2 = checkTopic2 ? uint256(topic2) + 1 : uint256(topic2);\n        uint256 transformedTopic3 = checkTopic3 ? uint256(topic3) + 1 : uint256(topic3);\n        uint256 transformedData = checkData ? uint256(data) + 1 : uint256(data);\n\n        vm.expectEmit(checkTopic1, checkTopic2, checkTopic3, checkData);\n\n        emit Something(topic1, topic2, topic3, data);\n        emitter.emitEvent(transformedTopic1, transformedTopic2, transformedTopic3, transformedData);\n    }\n\n    /// The topics that are checked are altered to be incorrect\n    /// compared to the reference.\n    function testShouldFailExpectEmitNested(\n        bool checkTopic1,\n        bool checkTopic2,\n        bool checkTopic3,\n        bool checkData,\n        uint128 topic1,\n        uint128 topic2,\n        uint128 topic3,\n        uint128 data\n    ) public {\n        vm.assume(checkTopic1 || checkTopic2 || checkTopic3 || checkData);\n        Emitter inner = new Emitter();\n\n        uint256 transformedTopic1 = checkTopic1 ? uint256(topic1) + 1 : uint256(topic1);\n        uint256 transformedTopic2 = checkTopic2 ? uint256(topic2) + 1 : uint256(topic2);\n        uint256 transformedTopic3 = checkTopic3 ? uint256(topic3) + 1 : uint256(topic3);\n        uint256 transformedData = checkData ? uint256(data) + 1 : uint256(data);\n\n        vm.expectEmit(checkTopic1, checkTopic2, checkTopic3, checkData);\n\n        emit Something(topic1, topic2, topic3, data);\n        emitter.emitNested(inner, transformedTopic1, transformedTopic2, transformedTopic3, transformedData);\n    }\n\n    function testShouldFailExpectEmitCanMatchWithoutExactOrder() public {\n        vm.expectEmit(true, true, true, true);\n        emit Something(1, 2, 3, 4);\n        // This should fail, as this event is never emitted\n        // in between the other two Something events.\n        vm.expectEmit(true, true, true, true);\n        emit SomethingElse(1);\n        vm.expectEmit(true, true, true, true);\n        emit Something(1, 2, 3, 4);\n\n        emitter.emitOutOfExactOrder();\n    }\n\n    function testShouldFailExpectEmitAddress() public {\n        vm.expectEmit(address(0));\n        emit Something(1, 2, 3, 4);\n\n        emitter.emitEvent(1, 2, 3, 4);\n    }\n\n    function testShouldFailExpectEmitAddressWithArgs() public {\n        vm.expectEmit(true, true, true, true, address(0));\n        emit Something(1, 2, 3, 4);\n\n        emitter.emitEvent(1, 2, 3, 4);\n    }\n\n    /// Ref: issue #760\n    function testShouldFailLowLevelWithoutEmit() public {\n        LowLevelCaller caller = new LowLevelCaller();\n\n        vm.expectEmit(true, true, true, true);\n        emit Something(1, 2, 3, 4);\n\n        // This does not emit an event, so this test should fail\n        caller.f();\n    }\n\n    function testShouldFailNoEmitDirectlyOnNextCall() public {\n        LowLevelCaller caller = new LowLevelCaller();\n\n        vm.expectEmit(true, true, true, true);\n        emit Something(1, 2, 3, 4);\n\n        // This call does not emit. As emit expects the next call to emit, this should fail.\n        caller.f();\n        // This call does emit, but it is a call later than expected.\n        emitter.emitEvent(1, 2, 3, 4);\n    }\n\n    /// Ref: issue #760\n    function testShouldFailDifferentIndexedParameters() public {\n        vm.expectEmit(true, false, false, false);\n        emit SomethingElse(1);\n\n        // This should fail since `SomethingElse` in the test\n        // and in the `Emitter` contract have differing\n        // amounts of indexed topics.\n        emitter.emitSomethingElse(1);\n    }\n\n    /// This test should fail, as the call to `changeThing` is not a static call.\n    /// While we can ignore static calls, we cannot ignore normal calls.\n    function testShouldFailEmitOnlyAppliesToNextCall() public {\n        vm.expectEmit(true, true, true, true);\n        emit Something(1, 2, 3, 4);\n        // This works because it's a staticcall.\n        emitter.doesNothing();\n        // This should make the test fail as it's a normal call.\n        emitter.changeThing(block.timestamp);\n\n        emitter.emitEvent(1, 2, 3, 4);\n    }\n\n    /// emitWindow() emits events A, B, C, D, E.\n    /// We should not be able to match [B, A, C, D, E] as B and A are flipped.\n    function testShouldFailCanMatchConsecutiveEvents() public {\n        vm.expectEmit(true, false, false, true);\n        emit B(2);\n        vm.expectEmit(true, false, false, true);\n        emit A(1);\n        vm.expectEmit(true, false, false, true);\n        emit C(3);\n        vm.expectEmit(true, false, false, true);\n        emit D(4);\n        vm.expectEmit(true, false, false, true);\n        emit E(5);\n\n        emitter.emitWindow();\n    }\n\n    /// emitWindowNested() emits events A, C, E, A, B, C, D, E, the last 5 on an external call.\n    /// We should NOT be able to match [A, A, E, E], as while we're matching the correct amount\n    /// of events, they're not in the correct order. It should be [A, E, A, E].\n    function testShouldFailMatchRepeatedEventsOutOfOrder() public {\n        vm.expectEmit(true, false, false, true);\n        emit A(1);\n        vm.expectEmit(true, false, false, true);\n        emit A(1);\n        vm.expectEmit(true, false, false, true);\n        emit E(5);\n        vm.expectEmit(true, false, false, true);\n        emit E(5);\n\n        emitter.emitNestedWindow();\n    }\n\n    /// emitWindow() emits events A, B, C, D, E.\n    /// We should not be able to match [A, A] even if emitWindow() is called twice,\n    /// as expectEmit() only works for the next call.\n    function testShouldFailEventsOnTwoCalls() public {\n        vm.expectEmit(true, false, false, true);\n        emit A(1);\n        vm.expectEmit(true, false, false, true);\n        emit A(1);\n        emitter.emitWindow();\n        emitter.emitWindow();\n    }\n\n    /// We should not be able to expect emits if we're expecting the function reverts, no matter\n    /// if the function reverts or not.\n    function testShouldFailEmitWindowWithRevertDisallowed() public {\n        vm.expectRevert();\n        vm.expectEmit(true, false, false, true);\n        emit A(1);\n        emitter.emitWindow();\n    }\n}\n\ncontract ExpectEmitCountFailureTest is DSTest {\n    Vm constant vm = Vm(HEVM_ADDRESS);\n    Emitter emitter;\n\n    event Something(uint256 indexed topic1, uint256 indexed topic2, uint256 indexed topic3, uint256 data);\n\n    function setUp() public {\n        emitter = new Emitter();\n    }\n\n    function testShouldFailNoEmit() public {\n        vm.expectEmit(0);\n        emit Something(1, 2, 3, 4);\n        emitter.emitEvent(1, 2, 3, 4);\n    }\n\n    function testShouldFailCountLessEmits() public {\n        uint64 count = 2;\n        vm.expectEmit(count);\n        emit Something(1, 2, 3, 4);\n        emitter.emitNEvents(1, 2, 3, 4, count - 1);\n    }\n\n    function testShouldFailNoEmitFromAddress() public {\n        vm.expectEmit(address(emitter), 0);\n        emit Something(1, 2, 3, 4);\n        emitter.emitEvent(1, 2, 3, 4);\n    }\n\n    function testShouldFailCountEmitsFromAddress() public {\n        uint64 count = 3;\n        vm.expectEmit(address(emitter), count);\n        emit Something(1, 2, 3, 4);\n        emitter.emitNEvents(1, 2, 3, 4, count - 1);\n    }\n\n    function testShouldFailEmitSomethingElse() public {\n        uint64 count = 2;\n        vm.expectEmit(count);\n        emit Something(1, 2, 3, 4);\n        emitter.emitSomethingElse(23214);\n    }\n}\n"
  },
  {
    "path": "crates/forge/tests/fixtures/ExpectEmitParamFailures.t.sol",
    "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.18;\n\nimport \"./test.sol\";\nimport \"./Vm.sol\";\n\nimport {EventEmitter, SelectiveEmitter, ParamNumberingEmitter, AnonymousEmitter, ManyParamsEmitter} from \"./ExpectEmitParamHarness.sol\";\n\ncontract ExpectEmitParamFailures is DSTest {\n    Vm constant vm = Vm(HEVM_ADDRESS);\n    // Contract instances\n    EventEmitter public eventEmitter;\n    SelectiveEmitter public selectiveEmitter;\n    ParamNumberingEmitter public paramNumberingEmitter;\n    AnonymousEmitter public anonymousEmitter;\n    ManyParamsEmitter public manyParamsEmitter;\n\n    // Event declarations for tests\n    event SimpleEvent(uint256 indexed a, uint256 indexed b, uint256 c);\n    event ComplexEvent(address indexed sender, uint256 indexed id, bytes data);\n    event TestEvent(uint256 indexed a, uint256 indexed b, uint256 c);\n\n    event MixedEventNumbering(\n        uint256 indexed param0,\n        address indexed param1,\n        uint256 param2,\n        uint256 param3,\n        address param4\n    );\n\n    // Anonymous event for tests\n    event AnonymousIndexed(uint256 indexed a, uint256 b, address c) anonymous;\n\n    // Event with many parameters\n    event ManyParams(uint256 a, uint256 b, uint256 c, uint256 d, uint256 e);\n\n    function setUp() public {\n        eventEmitter = new EventEmitter();\n        selectiveEmitter = new SelectiveEmitter();\n        paramNumberingEmitter = new ParamNumberingEmitter();\n        anonymousEmitter = new AnonymousEmitter();\n        manyParamsEmitter = new ManyParamsEmitter();\n    }\n\n    function testIndexedParamMismatch() public {\n        vm.expectEmit(true, true, true, true);\n        emit SimpleEvent(100, 200, 300);\n        eventEmitter.emitSimple(100, 999, 300); // Second indexed param (b) mismatch\n    }\n\n    function testNonIndexedParamMismatch() public {\n        vm.expectEmit(true, true, true, true);\n        emit SimpleEvent(100, 200, 300);\n        eventEmitter.emitSimple(100, 200, 999); // Non-indexed param (c) mismatch\n    }\n\n    function testMultipleMismatches() public {\n        vm.expectEmit(true, true, true, true);\n        emit SimpleEvent(100, 200, 300);\n        eventEmitter.emitSimple(999, 888, 777); // All params mismatch\n    }\n\n    function testSelectiveChecks() public {\n        vm.expectEmit(true, false, true, true); // checkTopic2=false\n        emit TestEvent(100, 200, 300);\n        selectiveEmitter.emitEvent(100, 999, 300); // Topic2 different but not checked\n    }\n\n    function testParameterNumbering() public {\n        vm.expectEmit(true, true, true, true);\n        emit MixedEventNumbering(\n            100,\n            address(0x1234),\n            300,\n            400,\n            address(0x5678)\n        );\n        paramNumberingEmitter.emitEvent(\n            100,\n            address(0x1234),\n            999,\n            400,\n            address(0x5678)\n        ); // param2 mismatch\n    }\n\n    function testCompletelyDifferentEvent() public {\n        vm.expectEmit(true, true, true, true);\n        emit SimpleEvent(100, 200, 300);\n        eventEmitter.emitComplex(address(this), 42, hex\"deadbeef\"); // Different event type\n    }\n\n    function testAnonymousEventMismatch() public {\n        vm.expectEmitAnonymous(true, false, false, false, true); // Check topic0 and data\n        emit AnonymousIndexed(100, 200, address(0x1234));\n        anonymousEmitter.emitAnonymousIndexed(999, 200, address(0x1234)); // param0 mismatch\n    }\n\n    function testManyParameterMismatches() public {\n        vm.expectEmit(true, true, true, true);\n        // Event with 5 non-indexed parameters\n        emit ManyParams(100, 200, 300, 400, 500);\n        // All 5 parameters differ - should show each one individually\n        manyParamsEmitter.emitManyParams(111, 222, 333, 444, 555);\n    }\n\n    function testMixedEventNonIndexedMismatch() public {\n        // For SimpleEvent: 'a' and 'b' are indexed, 'c' is non-indexed\n        vm.expectEmit(true, true, true, true);\n        emit SimpleEvent(100, 200, 300);\n        // Same indexed params (100, 200) but different non-indexed param\n        eventEmitter.emitSimple(100, 200, 999);\n    }\n}\n"
  },
  {
    "path": "crates/forge/tests/fixtures/ExpectEmitParamHarness.sol",
    "content": "// SPDX-License-Identifier: UNLICENSED\n\n// Harness contract are in a separate file so that the selectors cache can be populated on `forge b`.\ncontract EventEmitter {\n    event SimpleEvent(uint256 indexed a, uint256 indexed b, uint256 c);\n    event ComplexEvent(address indexed sender, uint256 indexed id, bytes data);\n\n    function emitSimple(uint256 a, uint256 b, uint256 c) public {\n        emit SimpleEvent(a, b, c);\n    }\n\n    function emitComplex(address sender, uint256 id, bytes memory data) public {\n        emit ComplexEvent(sender, id, data);\n    }\n\n    function emitSimpleMultipleTimes(\n        uint256 a,\n        uint256 b,\n        uint256 c,\n        uint256 times\n    ) public {\n        for (uint256 i = 0; i < times; i++) {\n            emit SimpleEvent(a, b, c);\n        }\n    }\n}\n\ncontract SelectiveEmitter {\n    event TestEvent(uint256 indexed a, uint256 indexed b, uint256 c);\n\n    function emitEvent(uint256 a, uint256 b, uint256 c) public {\n        emit TestEvent(a, b, c);\n    }\n}\n\ncontract ParamNumberingEmitter {\n    // Event with 2 indexed and 3 non-indexed parameters\n    event MixedEventNumbering(\n        uint256 indexed param0, // param 0 (indexed)\n        address indexed param1, // param 1 (indexed)\n        uint256 param2, // param 2 (non-indexed)\n        uint256 param3, // param 3 (non-indexed)\n        address param4 // param 4 (non-indexed)\n    );\n\n    function emitEvent(\n        uint256 p0,\n        address p1,\n        uint256 p2,\n        uint256 p3,\n        address p4\n    ) public {\n        emit MixedEventNumbering(p0, p1, p2, p3, p4);\n    }\n}\n\ncontract AnonymousEmitter {\n    // Anonymous event with indexed parameter\n    event AnonymousIndexed(uint256 indexed a, uint256 b, address c) anonymous;\n\n    function emitAnonymousIndexed(uint256 a, uint256 b, address c) public {\n        emit AnonymousIndexed(a, b, c);\n    }\n}\n\ncontract ManyParamsEmitter {\n    // Event with many non-indexed parameters to trigger raw data display\n    event ManyParams(uint256 a, uint256 b, uint256 c, uint256 d, uint256 e);\n\n    function emitManyParams(\n        uint256 a,\n        uint256 b,\n        uint256 c,\n        uint256 d,\n        uint256 e\n    ) public {\n        emit ManyParams(a, b, c, d, e);\n    }\n}\n"
  },
  {
    "path": "crates/forge/tests/fixtures/ExpectRevertFailures.t.sol",
    "content": "// Note Used in forge-cli tests to assert failures.\n// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"./test.sol\";\nimport \"./Vm.sol\";\n\ncontract Reverter {\n    error CustomError();\n\n    function revertWithMessage(string memory message) public pure {\n        revert(message);\n    }\n\n    function doNotRevert() public pure {}\n\n    function panic() public pure returns (uint256) {\n        return uint256(100) - uint256(101);\n    }\n\n    function revertWithCustomError() public pure {\n        revert CustomError();\n    }\n\n    function nestedRevert(Reverter inner, string memory message) public pure {\n        inner.revertWithMessage(message);\n    }\n\n    function callThenRevert(Dummy dummy, string memory message) public pure {\n        dummy.callMe();\n        revert(message);\n    }\n\n    function callThenNoRevert(Dummy dummy) public pure {\n        dummy.callMe();\n    }\n\n    function revertWithoutReason() public pure {\n        revert();\n    }\n}\n\ncontract ConstructorReverter {\n    constructor(string memory message) {\n        revert(message);\n    }\n}\n\n/// Used to ensure that the dummy data from `vm.expectRevert`\n/// is large enough to decode big structs.\n///\n/// The struct is based on issue #2454\nstruct LargeDummyStruct {\n    address a;\n    uint256 b;\n    bool c;\n    address d;\n    address e;\n    string f;\n    address[8] g;\n    address h;\n    uint256 i;\n}\n\ncontract Dummy {\n    function callMe() public pure returns (string memory) {\n        return \"thanks for calling\";\n    }\n\n    function largeReturnType() public pure returns (LargeDummyStruct memory) {\n        revert(\"reverted with large return type\");\n    }\n}\n\ncontract ExpectRevertFailureTest is DSTest {\n    Vm constant vm = Vm(HEVM_ADDRESS);\n\n    function testShouldFailExpectRevertErrorDoesNotMatch() public {\n        Reverter reverter = new Reverter();\n        vm.expectRevert(\"should revert with this message\");\n        reverter.revertWithMessage(\"but reverts with this message\");\n    }\n\n    function testShouldFailRevertNotOnImmediateNextCall() public {\n        Reverter reverter = new Reverter();\n        // expectRevert should only work for the next call. However,\n        // we do not immediately revert, so,\n        // we fail.\n        vm.expectRevert(\"revert\");\n        reverter.doNotRevert();\n        reverter.revertWithMessage(\"revert\");\n    }\n\n    function testShouldFailExpectRevertDidNotRevert() public {\n        Reverter reverter = new Reverter();\n        vm.expectRevert(\"does not revert, but we think it should\");\n        reverter.doNotRevert();\n    }\n\n    function testShouldFailExpectRevertAnyRevertDidNotRevert() public {\n        Reverter reverter = new Reverter();\n        vm.expectRevert();\n        reverter.doNotRevert();\n    }\n\n    /// forge-config: default.allow_internal_expect_revert = true\n    function testShouldFailExpectRevertDangling() public {\n        vm.expectRevert(\"dangling\");\n    }\n\n    function testShouldFailexpectCheatcodeRevertForExtCall() public {\n        Reverter reverter = new Reverter();\n        vm._expectCheatcodeRevert();\n        reverter.revertWithMessage(\"revert\");\n    }\n\n    function testShouldFailexpectCheatcodeRevertForCreate() public {\n        vm._expectCheatcodeRevert();\n        new ConstructorReverter(\"some message\");\n    }\n}\n\ncontract AContract {\n    BContract bContract;\n    CContract cContract;\n\n    constructor(BContract _bContract, CContract _cContract) {\n        bContract = _bContract;\n        cContract = _cContract;\n    }\n\n    function callAndRevert() public pure {\n        require(1 > 2, \"Reverted by AContract\");\n    }\n\n    function callAndRevertInBContract() public {\n        bContract.callAndRevert();\n    }\n\n    function callAndRevertInCContract() public {\n        cContract.callAndRevert();\n    }\n\n    function callAndRevertInCContractThroughBContract() public {\n        bContract.callAndRevertInCContract();\n    }\n\n    function createDContract() public {\n        new DContract();\n    }\n\n    function createDContractThroughBContract() public {\n        bContract.createDContract();\n    }\n\n    function createDContractThroughCContract() public {\n        cContract.createDContract();\n    }\n\n    function doNotRevert() public {}\n}\n\ncontract BContract {\n    CContract cContract;\n\n    constructor(CContract _cContract) {\n        cContract = _cContract;\n    }\n\n    function callAndRevert() public pure {\n        require(1 > 2, \"Reverted by BContract\");\n    }\n\n    function callAndRevertInCContract() public {\n        this.doNotRevert();\n        cContract.doNotRevert();\n        cContract.callAndRevert();\n    }\n\n    function createDContract() public {\n        this.doNotRevert();\n        cContract.doNotRevert();\n        new DContract();\n    }\n\n    function createDContractThroughCContract() public {\n        this.doNotRevert();\n        cContract.doNotRevert();\n        cContract.createDContract();\n    }\n\n    function doNotRevert() public {}\n}\n\ncontract CContract {\n    error CContractError(string reason);\n\n    function callAndRevert() public pure {\n        revert CContractError(\"Reverted by CContract\");\n    }\n\n    function createDContract() public {\n        new DContract();\n    }\n\n    function doNotRevert() public {}\n}\n\ncontract DContract {\n    constructor() {\n        require(1 > 2, \"Reverted by DContract\");\n    }\n}\n\ncontract ExpectRevertWithReverterFailureTest is DSTest {\n    Vm constant vm = Vm(HEVM_ADDRESS);\n\n    error CContractError(string reason);\n\n    AContract aContract;\n    BContract bContract;\n    CContract cContract;\n\n    function setUp() public {\n        cContract = new CContract();\n        bContract = new BContract(cContract);\n        aContract = new AContract(bContract, cContract);\n    }\n\n    function testShouldFailExpectRevertsNotOnImmediateNextCall() public {\n        // Test expect revert with reverter fails if next call doesn't revert.\n        vm.expectRevert(address(aContract));\n        aContract.doNotRevert();\n        aContract.callAndRevert();\n    }\n}\n\ncontract ExpectRevertCountFailureTest is DSTest {\n    Vm constant vm = Vm(HEVM_ADDRESS);\n\n    function testShouldFailRevertCountAny() public {\n        uint64 count = 3;\n        Reverter reverter = new Reverter();\n        vm.expectRevert(count);\n        reverter.revertWithMessage(\"revert\");\n        reverter.revertWithMessage(\"revert2\");\n    }\n\n    function testShouldFailNoRevert() public {\n        uint64 count = 0;\n        Reverter reverter = new Reverter();\n        vm.expectRevert(count);\n        reverter.revertWithMessage(\"revert\");\n    }\n\n    function testShouldFailRevertCountSpecific() public {\n        uint64 count = 2;\n        Reverter reverter = new Reverter();\n        vm.expectRevert(\"revert\", count);\n        reverter.revertWithMessage(\"revert\");\n        reverter.revertWithMessage(\"second-revert\");\n    }\n\n    function testShouldFailNoRevertSpecific() public {\n        uint64 count = 0;\n        Reverter reverter = new Reverter();\n        vm.expectRevert(\"revert\", count);\n        reverter.revertWithMessage(\"revert\");\n    }\n\n    function testShouldFailRevertCountCallsThenReverts() public {\n        uint64 count = 2;\n        Reverter reverter = new Reverter();\n        Dummy dummy = new Dummy();\n\n        vm.expectRevert(\"called a function and then reverted\", count);\n        reverter.callThenRevert(dummy, \"called a function and then reverted\");\n        reverter.callThenRevert(dummy, \"wrong revert\");\n    }\n\n    // <https://github.com/foundry-rs/foundry/issues/10858>\n    function testShouldFailIfExpectRevertWrongString() public {\n        Reverter reverter = new Reverter();\n        vm.expectRevert(\"my not so cool error\", 0);\n        reverter.revertWithMessage(\"my cool error\");\n    }\n}\n\ncontract ExpectRevertCountWithReverterFailures is DSTest {\n    Vm constant vm = Vm(HEVM_ADDRESS);\n\n    function testShouldFailRevertCountWithReverter() public {\n        uint64 count = 2;\n        Reverter reverter = new Reverter();\n        Reverter reverter2 = new Reverter();\n        vm.expectRevert(address(reverter), count);\n        reverter.revertWithMessage(\"revert\");\n        reverter2.revertWithMessage(\"revert\");\n    }\n\n    function testShouldFailNoRevertWithReverter() public {\n        uint64 count = 0;\n        Reverter reverter = new Reverter();\n        vm.expectRevert(address(reverter), count);\n        reverter.revertWithMessage(\"revert\");\n    }\n\n    function testShouldFailReverterCountWithWrongData() public {\n        uint64 count = 2;\n        Reverter reverter = new Reverter();\n        vm.expectRevert(\"revert\", address(reverter), count);\n        reverter.revertWithMessage(\"revert\");\n        reverter.revertWithMessage(\"wrong revert\");\n    }\n\n    function testShouldFailWrongReverterCountWithData() public {\n        uint64 count = 2;\n        Reverter reverter = new Reverter();\n        Reverter reverter2 = new Reverter();\n        vm.expectRevert(\"revert\", address(reverter), count);\n        reverter.revertWithMessage(\"revert\");\n        reverter2.revertWithMessage(\"revert\");\n    }\n\n    // <https://github.com/foundry-rs/foundry/issues/10858>\n    function testNoReverterCountWithData() public {\n        uint64 count = 0;\n        Reverter reverter = new Reverter();\n        vm.expectRevert(\"revert\", address(reverter), count);\n        reverter.doNotRevert();\n\n        vm.expectRevert(\"revert\", address(reverter), count);\n        reverter.revertWithMessage(\"revert2\");\n    }\n\n    // <https://github.com/foundry-rs/foundry/issues/10858>\n    function testNoRevertWithWrongReverter() public {\n        uint64 count = 0;\n        Reverter reverter = new Reverter();\n        Reverter reverter2 = new Reverter();\n        vm.expectRevert(address(reverter), count);\n        reverter2.revertWithMessage(\"revert\"); // revert from wrong reverter\n    }\n}\n"
  },
  {
    "path": "crates/forge/tests/fixtures/MemSafetyFailures.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"./test.sol\";\nimport \"./Vm.sol\";\n\ncontract MemSafetyFailureTest is DSTest {\n    Vm constant vm = Vm(address(HEVM_ADDRESS));\n\n    /// @dev Tests that writing to memory before the range given to `expectSafeMemory`\n    ///      will cause the test to fail while using the `MSTORE` opcode.\n    function testShouldFailExpectSafeMemory_MSTORE_Low() public {\n        // Allow memory writes in the range of [0x80, 0xA0) within this context\n        vm.expectSafeMemory(0x80, 0xA0);\n\n        // Attempt to write to memory outside of the range using `MSTORE`\n        assembly {\n            mstore(0x60, 0xc0ffee)\n        }\n    }\n\n    /// @dev Tests that writing to memory after the range given to `expectSafeMemory`\n    ///      will cause the test to fail while using the `MSTORE` opcode.\n    function testShouldFailExpectSafeMemory_MSTORE_High() public {\n        // Allow memory writes in the range of [0x80, 0xA0) within this context\n        vm.expectSafeMemory(0x80, 0xA0);\n\n        // Attempt to write to memory outside of the range using `MSTORE`\n        assembly {\n            mstore(0xA0, 0xc0ffee)\n        }\n    }\n\n    /// @dev Tests that writing to memory before the range given to `expectSafeMemory`\n    ///      will cause the test to fail while using the `MSTORE8` opcode.\n    function testShouldFailExpectSafeMemory_MSTORE8_Low() public {\n        // Allow memory writes in the range of [0x80, 0x81) within this context\n        vm.expectSafeMemory(0x80, 0x81);\n\n        // Attempt to write to memory outside of the range using `MSTORE8`\n        assembly {\n            mstore8(0x60, 0xFF)\n        }\n    }\n\n    /// @dev Tests that writing to memory after the range given to `expectSafeMemory`\n    ///      will cause the test to fail while using the `MSTORE8` opcode.\n    function testShouldFailExpectSafeMemory_MSTORE8_High() public {\n        // Allow memory writes in the range of [0x80, 0x81) within this context\n        vm.expectSafeMemory(0x80, 0x81);\n\n        // Attempt to write to memory outside of the range using `MSTORE8`\n        assembly {\n            mstore8(0x81, 0xFF)\n        }\n    }\n\n    /// @dev Tests that writing to memory outside of the range given to `expectSafeMemory`\n    ///      will cause the test to fail while using the `CALLDATACOPY` opcode.\n    function testShouldFailExpectSafeMemory_CALLDATACOPY(uint256 _x) public {\n        // Allow memory writes in the range of [0x80, 0xA0) within this context\n        vm.expectSafeMemory(0x80, 0xA0);\n\n        // Write to memory outside the range using `CALLDATACOPY`\n        assembly {\n            calldatacopy(0xA0, 0x04, 0x20)\n        }\n    }\n\n    /// @dev Tests that writing to memory outside of the range given to `expectSafeMemory`\n    ///      will cause the test to fail while using the `CODECOPY` opcode.\n    function testShouldFailExpectSafeMemory_CODECOPY() public {\n        // Allow memory writes in the range of [0x80, 0xA0) within this context\n        vm.expectSafeMemory(0x80, 0xA0);\n\n        // Attempt to write to memory outside of the range using `CODECOPY`\n        assembly {\n            let size := extcodesize(address())\n            codecopy(0x80, 0x00, size)\n        }\n    }\n\n    /// @dev Tests that writing to memory outside of the range given to `expectSafeMemory`\n    ///      will cause the test to fail while using the `RETURNDATACOPY` opcode.\n    function testShouldFailExpectSafeMemory_RETURNDATACOPY() public {\n        // Create a new SubContext contract\n        SubContext sc = new SubContext();\n\n        // Create a payload to call `giveReturndata` on the SubContext contract\n        bytes memory payload = abi.encodeWithSelector(SubContext.giveReturndata.selector);\n\n        // Allow memory writes in the range of [0x80, 0x100) within this context\n        vm.expectSafeMemory(0x80, 0x100);\n\n        // Create a new SubContext contract and call `giveReturndata` on it.\n        _doCallReturnData(address(sc), payload, 0x80, 0x60);\n\n        // Write to memory outside of the range using `RETURNDATACOPY`\n        assembly {\n            returndatacopy(0x100, 0x00, 0x60)\n        }\n    }\n\n    /// @dev Tests that writing to memory outside of the range given to `expectSafeMemory`\n    ///      will not cause the test to fail while using the `EXTCODECOPY` opcode.\n    function testShouldFailExpectSafeMemory_EXTCODECOPY() public {\n        // Allow memory writes in the range of [0x80, 0xA0) within this context\n        vm.expectSafeMemory(0x80, 0xA0);\n\n        // Attempt to write to memory outside of the range using `EXTCODECOPY`\n        assembly {\n            let size := extcodesize(address())\n            extcodecopy(address(), 0xA0, 0x00, 0x20)\n        }\n    }\n\n    /// @dev Tests that writing to memory outside of the range given to `expectSafeMemory`\n    ///      will cause the test to fail while using the `CALL` opcode.\n    function testShouldFailExpectSafeMemory_CALL() public {\n        // Create a new SubContext contract\n        SubContext sc = new SubContext();\n\n        // Create a payload to call `giveReturndata` on the SubContext contract\n        bytes memory payload = abi.encodeWithSelector(SubContext.giveReturndata.selector);\n\n        // Allow memory writes in the range of [0x80, 0x100) within this context\n        vm.expectSafeMemory(0x80, 0x100);\n\n        // Create a new SubContext contract and call `giveReturndata` on it.\n        _doCallReturnData(address(sc), payload, 0x100, 0x60);\n    }\n\n    /// @dev Tests that writing to memory outside of the range given to `expectSafeMemory`\n    ///      will cause the test to fail while using the `CALLCODE` opcode.\n    function testShouldFailExpectSafeMemory_CALLCODE() public {\n        // Create a new SubContext contract\n        SubContext sc = new SubContext();\n\n        // Create a payload to call `giveReturndata` on the SubContext contract\n        bytes memory payload = abi.encodeWithSelector(SubContext.giveReturndata.selector);\n\n        // Allow memory writes in the range of [0x80, 0x100) within this context\n        vm.expectSafeMemory(0x80, 0x100);\n\n        // Create a new SubContext contract and call `giveReturndata` on it.\n        _doCallCodeReturnData(address(sc), payload, 0x100, 0x60);\n    }\n\n    /// @dev Tests that writing to memory outside of the range given to `expectSafeMemory`\n    ///      will cause the test to fail while using the `STATICCALL` opcode.\n    function testShouldFailExpectSafeMemory_STATICCALL() public {\n        // Create a new SubContext contract\n        SubContext sc = new SubContext();\n\n        // Create a payload to call `giveReturndata` on the SubContext contract\n        bytes memory payload = abi.encodeWithSelector(SubContext.giveReturndata.selector);\n\n        // Allow memory writes in the range of [0x80, 0x100) within this context\n        vm.expectSafeMemory(0x80, 0x100);\n\n        // Create a new SubContext contract and call `giveReturndata` on it.\n        _doStaticCallReturnData(address(sc), payload, 0x100, 0x60);\n    }\n\n    /// @dev Tests that writing to memory outside of the range given to `expectSafeMemory`\n    ///      will cause the test to fail while using the `DELEGATECALL` opcode.\n    function testShouldFailExpectSafeMemory_DELEGATECALL() public {\n        // Create a new SubContext contract\n        SubContext sc = new SubContext();\n\n        // Create a payload to call `giveReturndata` on the SubContext contract\n        bytes memory payload = abi.encodeWithSelector(SubContext.giveReturndata.selector);\n\n        // Allow memory writes in the range of [0x80, 0x100) within this context\n        vm.expectSafeMemory(0x80, 0x100);\n\n        // Create a new SubContext contract and call `giveReturndata` on it.\n        _doDelegateCallReturnData(address(sc), payload, 0x100, 0x60);\n    }\n\n    /// @dev Tests that expanding memory outside of the range given to `expectSafeMemory`\n    ///      will cause the test to fail while using the `MLOAD` opcode.\n    function testShouldFailExpectSafeMemory_MLOAD() public {\n        vm.expectSafeMemory(0x80, 0x100);\n\n        // This should revert. Ugly hack to make sure the mload isn't optimized\n        // out.\n        uint256 a;\n        assembly {\n            a := mload(0x100)\n        }\n        uint256 b = a + 1;\n    }\n\n    /// @dev Tests that expanding memory outside of the range given to `expectSafeMemory`\n    ///      will cause the test to fail while using the `SHA3` opcode.\n    function testShouldFailExpectSafeMemory_SHA3() public {\n        vm.expectSafeMemory(0x80, 0x100);\n\n        // This should revert. Ugly hack to make sure the sha3 isn't optimized\n        // out.\n        uint256 a;\n        assembly {\n            a := keccak256(0x100, 0x20)\n        }\n        uint256 b = a + 1;\n    }\n\n    /// @dev Tests that expanding memory outside of the range given to `expectSafeMemory`\n    ///      will cause the test to fail while using the `LOG0` opcode.\n    function testShouldFailExpectSafeMemory_LOG0() public {\n        vm.expectSafeMemory(0x80, 0x100);\n\n        // This should revert.\n        assembly {\n            log0(0x100, 0x20)\n        }\n    }\n\n    /// @dev Tests that expanding memory outside of the range given to `expectSafeMemory`\n    ///      will cause the test to fail while using the `CREATE` opcode.\n    function testShouldFailExpectSafeMemory_CREATE() public {\n        vm.expectSafeMemory(0x80, 0x100);\n\n        // This should revert.\n        assembly {\n            pop(create(0, 0x100, 0x20))\n        }\n    }\n\n    /// @dev Tests that expanding memory outside of the range given to `expectSafeMemory`\n    ///      will cause the test to fail while using the `CREATE2` opcode.\n    function testShouldFailExpectSafeMemory_CREATE2() public {\n        vm.expectSafeMemory(0x80, 0x100);\n\n        // This should revert.\n        assembly {\n            pop(create2(0, 0x100, 0x20, 0x00))\n        }\n    }\n\n    /// @dev Tests that expanding memory outside of the range given to `expectSafeMemory`\n    ///      will cause the test to fail while using the `RETURN` opcode.\n    function testShouldFailExpectSafeMemory_RETURN() public {\n        vm.expectSafeMemory(0x80, 0x100);\n\n        // This should revert.\n        assembly {\n            return(0x100, 0x20)\n        }\n    }\n\n    /// @dev Tests that expanding memory outside of the range given to `expectSafeMemory`\n    ///      will cause the test to fail while using the `REVERT` opcode.\n    function testShouldFailExpectSafeMemory_REVERT() public {\n        // Create a new SubContext contract\n        SubContext sc = new SubContext();\n\n        // Create a payload to call `doRevert` on the SubContext contract\n        bytes memory payload = abi.encodeWithSelector(SubContext.doRevert.selector, 0x120, 0x20);\n\n        // Expect memory in the range of [0x00, 0x120] to be safe in the next subcontext\n        vm.expectSafeMemoryCall(0x00, 0x120);\n\n        // Call `doRevert` on the SubContext contract and ensure it did not revert with\n        // zero data.\n        _doCallReturnData(address(sc), payload, 0x200, 0x20);\n        assembly {\n            if iszero(eq(keccak256(0x60, 0x20), keccak256(0x200, returndatasize()))) { revert(0x00, 0x00) }\n        }\n    }\n\n    /// @dev Tests that the `expectSafeMemoryCall` cheatcode works as expected.\n    function testShouldFailExpectSafeMemoryCall() public {\n        // Create a new SubContext contract\n        SubContext sc = new SubContext();\n        // Create a payload to call `doMstore8` on the SubContext contract\n        bytes memory payload = abi.encodeWithSelector(SubContext.doMstore.selector, 0xA0, 0xc0ffee);\n\n        // Allow memory writes in the range of [0x80, 0xA0) within the next created subcontext\n        vm.expectSafeMemoryCall(0x80, 0xA0);\n\n        // Should revert. The memory write in this subcontext is outside of the allowed range.\n        if (!_doCall(address(sc), payload)) {\n            revert(\"Expected call to fail\");\n        }\n    }\n\n    /// @dev Tests that the `stopExpectSafeMemory` cheatcode does not cause violations not being noticed.\n    function testShouldFailStopExpectSafeMemory() public {\n        uint64 initPtr;\n        assembly {\n            initPtr := mload(0x40)\n        }\n\n        vm.expectSafeMemory(initPtr, initPtr + 0x20);\n        assembly {\n            // write outside of allowed range, this should revert\n            mstore(add(initPtr, 0x20), 0x01)\n        }\n\n        vm.stopExpectSafeMemory();\n    }\n\n    // Helpers\n\n    /// @dev Performs a call without copying any returndata.\n    function _doCall(address _target, bytes memory _payload) internal returns (bool _success) {\n        assembly {\n            _success := call(gas(), _target, 0x00, add(_payload, 0x20), mload(_payload), 0x00, 0x00)\n        }\n    }\n\n    /// @dev Performs a call and copies returndata to memory.\n    function _doCallReturnData(address _target, bytes memory _payload, uint256 returnDataDest, uint256 returnDataSize)\n        internal\n    {\n        assembly {\n            pop(call(gas(), _target, 0x00, add(_payload, 0x20), mload(_payload), returnDataDest, returnDataSize))\n        }\n    }\n\n    /// @dev Performs a staticcall and copies returndata to memory.\n    function _doStaticCallReturnData(\n        address _target,\n        bytes memory _payload,\n        uint256 returnDataDest,\n        uint256 returnDataSize\n    ) internal {\n        assembly {\n            pop(staticcall(gas(), _target, add(_payload, 0x20), mload(_payload), returnDataDest, returnDataSize))\n        }\n    }\n\n    /// @dev Performs a delegatecall and copies returndata to memory.\n    function _doDelegateCallReturnData(\n        address _target,\n        bytes memory _payload,\n        uint256 returnDataDest,\n        uint256 returnDataSize\n    ) internal {\n        assembly {\n            pop(delegatecall(gas(), _target, add(_payload, 0x20), mload(_payload), returnDataDest, returnDataSize))\n        }\n    }\n\n    /// @dev Performs a callcode and copies returndata to memory.\n    function _doCallCodeReturnData(\n        address _target,\n        bytes memory _payload,\n        uint256 returnDataDest,\n        uint256 returnDataSize\n    ) internal {\n        assembly {\n            pop(callcode(gas(), _target, 0x00, add(_payload, 0x20), mload(_payload), returnDataDest, returnDataSize))\n        }\n    }\n}\n\n/// @dev A simple contract for testing the `expectSafeMemory` & `expectSafeMemoryCall` cheatcodes.\ncontract SubContext {\n    function doMstore(uint256 offset, uint256 val) external {\n        assembly {\n            mstore(offset, val)\n        }\n    }\n\n    function doMstore8(uint256 offset, uint8 val) external {\n        assembly {\n            mstore8(offset, val)\n        }\n    }\n\n    function giveReturndata() external view returns (bytes memory _returndata) {\n        return hex\"7dc4acc68d77c9c85b5cb0f53ab9ceea175f7964390758e4409013ce80643f84\";\n    }\n\n    function doRevert(uint256 offset, uint256 size) external {\n        assembly {\n            revert(offset, size)\n        }\n    }\n}\n"
  },
  {
    "path": "crates/forge/tests/fixtures/ScriptVerify.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.16;\n\nimport {Unique} from \"./unique.sol\";\n\ninterface HEVM {\n    function startBroadcast() external;\n}\n\nlibrary F {\n    function f() public pure returns (uint256) {\n        return 1;\n    }\n}\n\nlibrary C {\n    function c() public pure returns (uint256) {\n        return 2;\n    }\n}\n\ncontract Hello {\n    function world() public {\n        F.f();\n        C.c();\n    }\n}\n\ncontract CC1 is Unique {\n    uint256 a;\n\n    constructor(uint256 _a) {\n        a = _a;\n    }\n}\n\ncontract CC2 is Unique {\n    uint8 b;\n\n    constructor(uint256 _b) {\n        b = uint8(_b);\n        new CC3(\"hello\");\n    }\n}\n\ncontract CC3 is Unique {\n    string c;\n\n    constructor(string memory _c) {\n        c = _c;\n    }\n}\n\ncontract InnerContracts is Unique {\n    constructor(uint256 _a) public {\n        CC1 c1 = new CC1(_a);\n    }\n\n    function c2(uint256 _b) public {\n        CC2 c2 = new CC2{salt: bytes32(uint256(1))}(_b);\n    }\n}\n\ncontract ScriptVerify {\n    function run() public {\n        address vm = address(bytes20(uint160(uint256(keccak256(\"hevm cheat code\")))));\n        HEVM(vm).startBroadcast();\n        new Hello();\n        InnerContracts contracts = new InnerContracts(1);\n        contracts.c2(3);\n    }\n}\n"
  },
  {
    "path": "crates/forge/tests/fixtures/SimpleContractTestNonVerbose.json",
    "content": "{\n  \"src/Simple.t.sol:SimpleContractTest\": {\n    \"duration\": \"{...}\",\n    \"test_results\": {\n      \"test()\": {\n        \"status\": \"Success\",\n        \"reason\": null,\n        \"counterexample\": null,\n        \"logs\": [],\n        \"decoded_logs\": [],\n        \"kind\": {\n          \"Unit\": {\n            \"gas\": \"{...}\"\n          }\n        },\n        \"traces\": [],\n        \"labeled_addresses\": {},\n        \"duration\": \"{...}\",\n        \"breakpoints\": {},\n        \"gas_snapshots\": {}\n      }\n    },\n    \"warnings\": []\n  }\n}\n"
  },
  {
    "path": "crates/forge/tests/fixtures/SimpleContractTestVerbose.json",
    "content": "{\n  \"src/Simple.t.sol:SimpleContractTest\": {\n    \"duration\": \"{...}\",\n    \"test_results\": {\n      \"test()\": {\n        \"status\": \"Success\",\n        \"reason\": null,\n        \"counterexample\": null,\n        \"logs\": [\n          {\n            \"address\": \"0x000000000000000000636f6e736f6c652e6c6f67\",\n            \"topics\": [\n              \"0x41304facd9323d75b11bcdd609cb38effffdb05710f7caf0e9b16c6d9d709f50\"\n            ],\n            \"data\": \"0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000033130300000000000000000000000000000000000000000000000000000000000\"\n          }\n        ],\n        \"decoded_logs\": [\n          \"100\"\n        ],\n        \"kind\": {\n          \"Unit\": {\n            \"gas\": \"{...}\"\n          }\n        },\n        \"traces\": [\n          [\n            \"Deployment\",\n            {\n              \"arena\": [\n                {\n                  \"parent\": null,\n                  \"children\": [],\n                  \"idx\": 0,\n                  \"trace\": {\n                    \"depth\": 0,\n                    \"success\": true,\n                    \"caller\": \"0x1804c8ab1f12e6bbf3894d4083f33e07309d1f38\",\n                    \"address\": \"0x7fa9385be102ac3eac297483dd6233d62b3e1496\",\n                    \"maybe_precompile\": false,\n                    \"selfdestruct_address\": null,\n                    \"selfdestruct_refund_target\": null,\n                    \"selfdestruct_transferred_value\": null,\n                    \"kind\": \"CREATE\",\n                    \"value\": \"0x0\",\n                    \"data\": \"{...}\",\n                    \"output\": \"{...}\",\n                    \"gas_used\": \"{...}\",\n                    \"gas_limit\": \"{...}\",\n                    \"gas_refund_counter\": 0,\n                    \"status\": \"Return\",\n                    \"steps\": [],\n                    \"decoded\": null\n                  },\n                  \"logs\": [],\n                  \"ordering\": []\n                }\n              ]\n            }\n          ],\n          [\n            \"Execution\",\n            {\n              \"arena\": [\n                {\n                  \"parent\": null,\n                  \"children\": [\n                    1,\n                    2,\n                    3\n                  ],\n                  \"idx\": 0,\n                  \"trace\": {\n                    \"depth\": 0,\n                    \"success\": true,\n                    \"caller\": \"0x1804c8ab1f12e6bbf3894d4083f33e07309d1f38\",\n                    \"address\": \"0x7fa9385be102ac3eac297483dd6233d62b3e1496\",\n                    \"maybe_precompile\": null,\n                    \"selfdestruct_address\": null,\n                    \"selfdestruct_refund_target\": null,\n                    \"selfdestruct_transferred_value\": null,\n                    \"kind\": \"CALL\",\n                    \"value\": \"0x0\",\n                    \"data\": \"0xf8a8fd6d\",\n                    \"output\": \"0x\",\n                    \"gas_used\": \"{...}\",\n                    \"gas_limit\": \"{...}\",\n                    \"gas_refund_counter\": 0,\n                    \"status\": \"Stop\",\n                    \"steps\": [\n                      {\n                        \"pc\": 0,\n                        \"op\": 96,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 2,\n                        \"op\": 96,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 4,\n                        \"op\": 82,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 12,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 5,\n                        \"op\": 52,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 6,\n                        \"op\": 128,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 7,\n                        \"op\": 21,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 8,\n                        \"op\": 97,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 11,\n                        \"op\": 87,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 10,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 15,\n                        \"op\": 91,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 1,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 16,\n                        \"op\": 80,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 17,\n                        \"op\": 96,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 19,\n                        \"op\": 54,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 20,\n                        \"op\": 16,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 21,\n                        \"op\": 97,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 24,\n                        \"op\": 87,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 10,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 25,\n                        \"op\": 95,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 26,\n                        \"op\": 53,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 27,\n                        \"op\": 96,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 29,\n                        \"op\": 28,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 30,\n                        \"op\": 128,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 31,\n                        \"op\": 99,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 36,\n                        \"op\": 20,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 37,\n                        \"op\": 97,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 40,\n                        \"op\": 87,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 10,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 41,\n                        \"op\": 128,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 42,\n                        \"op\": 99,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 47,\n                        \"op\": 20,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 48,\n                        \"op\": 97,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 51,\n                        \"op\": 87,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 10,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 52,\n                        \"op\": 128,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 53,\n                        \"op\": 99,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 58,\n                        \"op\": 20,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 59,\n                        \"op\": 97,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 62,\n                        \"op\": 87,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 10,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 138,\n                        \"op\": 91,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 1,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 139,\n                        \"op\": 97,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 142,\n                        \"op\": 97,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 145,\n                        \"op\": 86,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 8,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 602,\n                        \"op\": 91,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 1,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 603,\n                        \"op\": 95,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 604,\n                        \"op\": 96,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 606,\n                        \"op\": 81,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 607,\n                        \"op\": 97,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 610,\n                        \"op\": 144,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 611,\n                        \"op\": 97,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 614,\n                        \"op\": 86,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 8,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1035,\n                        \"op\": 91,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 1,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1036,\n                        \"op\": 97,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1039,\n                        \"op\": 128,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1040,\n                        \"op\": 97,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1043,\n                        \"op\": 131,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1044,\n                        \"op\": 57,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 72,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1045,\n                        \"op\": 1,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1046,\n                        \"op\": 144,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1047,\n                        \"op\": 86,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 8,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 615,\n                        \"op\": 91,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 1,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 616,\n                        \"op\": 96,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 618,\n                        \"op\": 81,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 619,\n                        \"op\": 128,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 620,\n                        \"op\": 145,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 621,\n                        \"op\": 3,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 622,\n                        \"op\": 144,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 623,\n                        \"op\": 95,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 624,\n                        \"op\": 240,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 1056944078,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 625,\n                        \"op\": 128,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 626,\n                        \"op\": 21,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629525,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91235,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 627,\n                        \"op\": 128,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629522,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91238,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 628,\n                        \"op\": 21,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629519,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91241,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 629,\n                        \"op\": 97,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629516,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91244,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 632,\n                        \"op\": 87,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629513,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91247,\n                        \"gas_cost\": 10,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 640,\n                        \"op\": 91,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629503,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91257,\n                        \"gas_cost\": 1,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 641,\n                        \"op\": 80,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629502,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91258,\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 642,\n                        \"op\": 144,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629500,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91260,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 643,\n                        \"op\": 80,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629497,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91263,\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 644,\n                        \"op\": 128,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629495,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91265,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 645,\n                        \"op\": 115,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629492,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91268,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 666,\n                        \"op\": 22,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629489,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91271,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 667,\n                        \"op\": 99,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629486,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91274,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 672,\n                        \"op\": 96,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629483,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91277,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 674,\n                        \"op\": 96,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629480,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91280,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 676,\n                        \"op\": 81,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629477,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91283,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 677,\n                        \"op\": 130,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629474,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91286,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 678,\n                        \"op\": 99,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629471,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91289,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 683,\n                        \"op\": 22,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629468,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91292,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 684,\n                        \"op\": 96,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629465,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91295,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 686,\n                        \"op\": 27,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629462,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91298,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 687,\n                        \"op\": 129,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629459,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91301,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 688,\n                        \"op\": 82,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629456,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91304,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 689,\n                        \"op\": 96,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629453,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91307,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 691,\n                        \"op\": 1,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629450,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91310,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 692,\n                        \"op\": 97,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629447,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91313,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 695,\n                        \"op\": 145,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629444,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91316,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 696,\n                        \"op\": 144,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629441,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91319,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 697,\n                        \"op\": 97,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629438,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91322,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 700,\n                        \"op\": 86,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629435,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91325,\n                        \"gas_cost\": 8,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1617,\n                        \"op\": 91,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629427,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91333,\n                        \"gas_cost\": 1,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1618,\n                        \"op\": 95,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629426,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91334,\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1619,\n                        \"op\": 96,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629424,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91336,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1621,\n                        \"op\": 130,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629421,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91339,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1622,\n                        \"op\": 1,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629418,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91342,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1623,\n                        \"op\": 144,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629415,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91345,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1624,\n                        \"op\": 80,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629412,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91348,\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1625,\n                        \"op\": 97,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629410,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91350,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1628,\n                        \"op\": 95,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629407,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91353,\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1629,\n                        \"op\": 131,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629405,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91355,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1630,\n                        \"op\": 1,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629402,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91358,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1631,\n                        \"op\": 132,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629399,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91361,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1632,\n                        \"op\": 97,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629396,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91364,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1635,\n                        \"op\": 86,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629393,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91367,\n                        \"gas_cost\": 8,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1602,\n                        \"op\": 91,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629385,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91375,\n                        \"gas_cost\": 1,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1603,\n                        \"op\": 97,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629384,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91376,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1606,\n                        \"op\": 129,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629381,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91379,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1607,\n                        \"op\": 97,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629378,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91382,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1610,\n                        \"op\": 86,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629375,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91385,\n                        \"gas_cost\": 8,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1569,\n                        \"op\": 91,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629367,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91393,\n                        \"gas_cost\": 1,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1570,\n                        \"op\": 95,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629366,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91394,\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1571,\n                        \"op\": 97,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629364,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91396,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1574,\n                        \"op\": 97,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629361,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91399,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1577,\n                        \"op\": 97,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629358,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91402,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1580,\n                        \"op\": 132,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629355,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91405,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1581,\n                        \"op\": 97,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629352,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91408,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1584,\n                        \"op\": 86,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629349,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91411,\n                        \"gas_cost\": 8,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1542,\n                        \"op\": 91,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629341,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91419,\n                        \"gas_cost\": 1,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1543,\n                        \"op\": 95,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629340,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91420,\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1544,\n                        \"op\": 129,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629338,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91422,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1545,\n                        \"op\": 144,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629335,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91425,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1546,\n                        \"op\": 80,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629332,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91428,\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1547,\n                        \"op\": 145,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629330,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91430,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1548,\n                        \"op\": 144,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629327,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91433,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1549,\n                        \"op\": 80,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629324,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91436,\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1550,\n                        \"op\": 86,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629322,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91438,\n                        \"gas_cost\": 8,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1585,\n                        \"op\": 91,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629314,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91446,\n                        \"gas_cost\": 1,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1586,\n                        \"op\": 97,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629313,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91447,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1589,\n                        \"op\": 86,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629310,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91450,\n                        \"gas_cost\": 8,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1560,\n                        \"op\": 91,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629302,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91458,\n                        \"gas_cost\": 1,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1561,\n                        \"op\": 95,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629301,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91459,\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1562,\n                        \"op\": 129,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629299,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91461,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1563,\n                        \"op\": 144,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629296,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91464,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1564,\n                        \"op\": 80,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629293,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91467,\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1565,\n                        \"op\": 145,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629291,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91469,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1566,\n                        \"op\": 144,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629288,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91472,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1567,\n                        \"op\": 80,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629285,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91475,\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1568,\n                        \"op\": 86,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629283,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91477,\n                        \"gas_cost\": 8,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1590,\n                        \"op\": 91,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629275,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91485,\n                        \"gas_cost\": 1,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1591,\n                        \"op\": 97,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629274,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91486,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1594,\n                        \"op\": 86,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629271,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91489,\n                        \"gas_cost\": 8,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1551,\n                        \"op\": 91,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629263,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91497,\n                        \"gas_cost\": 1,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1552,\n                        \"op\": 95,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629262,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91498,\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1553,\n                        \"op\": 129,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629260,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91500,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1554,\n                        \"op\": 144,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629257,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91503,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1555,\n                        \"op\": 80,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629254,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91506,\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1556,\n                        \"op\": 145,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629252,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91508,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1557,\n                        \"op\": 144,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629249,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91511,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1558,\n                        \"op\": 80,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629246,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91514,\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1559,\n                        \"op\": 86,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629244,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91516,\n                        \"gas_cost\": 8,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1595,\n                        \"op\": 91,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629236,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91524,\n                        \"gas_cost\": 1,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1596,\n                        \"op\": 144,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629235,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91525,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1597,\n                        \"op\": 80,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629232,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91528,\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1598,\n                        \"op\": 145,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629230,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91530,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1599,\n                        \"op\": 144,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629227,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91533,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1600,\n                        \"op\": 80,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629224,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91536,\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1601,\n                        \"op\": 86,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629222,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91538,\n                        \"gas_cost\": 8,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1611,\n                        \"op\": 91,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629214,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91546,\n                        \"gas_cost\": 1,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1612,\n                        \"op\": 130,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629213,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91547,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1613,\n                        \"op\": 82,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629210,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91550,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1614,\n                        \"op\": 80,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629207,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91553,\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1615,\n                        \"op\": 80,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629205,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91555,\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1616,\n                        \"op\": 86,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629203,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91557,\n                        \"gas_cost\": 8,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1636,\n                        \"op\": 91,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629195,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91565,\n                        \"gas_cost\": 1,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1637,\n                        \"op\": 146,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629194,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91566,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1638,\n                        \"op\": 145,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629191,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91569,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1639,\n                        \"op\": 80,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629188,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91572,\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1640,\n                        \"op\": 80,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629186,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91574,\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1641,\n                        \"op\": 86,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629184,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91576,\n                        \"gas_cost\": 8,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 701,\n                        \"op\": 91,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629176,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91584,\n                        \"gas_cost\": 1,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 702,\n                        \"op\": 95,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629175,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91585,\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 703,\n                        \"op\": 96,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629173,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91587,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 705,\n                        \"op\": 81,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629170,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91590,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 706,\n                        \"op\": 128,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629167,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91593,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 707,\n                        \"op\": 131,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629164,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91596,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 708,\n                        \"op\": 3,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629161,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91599,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 709,\n                        \"op\": 129,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629158,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91602,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 710,\n                        \"op\": 95,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629155,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91605,\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 711,\n                        \"op\": 135,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629153,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91607,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 712,\n                        \"op\": 128,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629150,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91610,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 713,\n                        \"op\": 59,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629147,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91613,\n                        \"gas_cost\": 100,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 714,\n                        \"op\": 21,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629047,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91713,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 715,\n                        \"op\": 128,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629044,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91716,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 716,\n                        \"op\": 21,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629041,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91719,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 717,\n                        \"op\": 97,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629038,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91722,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 720,\n                        \"op\": 87,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629035,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91725,\n                        \"gas_cost\": 10,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 724,\n                        \"op\": 91,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629025,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91735,\n                        \"gas_cost\": 1,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 725,\n                        \"op\": 80,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629024,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91736,\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 726,\n                        \"op\": 90,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629022,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91738,\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 727,\n                        \"op\": 241,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073629020,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 91740,\n                        \"gas_cost\": 1056853569,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 728,\n                        \"op\": 21,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606406,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114354,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 729,\n                        \"op\": 128,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606403,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114357,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 730,\n                        \"op\": 21,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606400,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114360,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 731,\n                        \"op\": 97,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606397,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114363,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 734,\n                        \"op\": 87,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606394,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114366,\n                        \"gas_cost\": 10,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 742,\n                        \"op\": 91,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606384,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114376,\n                        \"gas_cost\": 1,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 743,\n                        \"op\": 80,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606383,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114377,\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 744,\n                        \"op\": 80,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606381,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114379,\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 745,\n                        \"op\": 80,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606379,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114381,\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 746,\n                        \"op\": 80,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606377,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114383,\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 747,\n                        \"op\": 97,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606375,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114385,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 750,\n                        \"op\": 96,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606372,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114388,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 752,\n                        \"op\": 97,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606369,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114391,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 755,\n                        \"op\": 86,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606366,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114394,\n                        \"gas_cost\": 8,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 814,\n                        \"op\": 91,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606358,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114402,\n                        \"gas_cost\": 1,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 815,\n                        \"op\": 97,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606357,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114403,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 818,\n                        \"op\": 129,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606354,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114406,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 819,\n                        \"op\": 96,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606351,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114409,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 821,\n                        \"op\": 81,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606348,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114412,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 822,\n                        \"op\": 96,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606345,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114415,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 824,\n                        \"op\": 1,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606342,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114418,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 825,\n                        \"op\": 97,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606339,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114421,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 828,\n                        \"op\": 145,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606336,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114424,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 829,\n                        \"op\": 144,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606333,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114427,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 830,\n                        \"op\": 97,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606330,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114430,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 833,\n                        \"op\": 86,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606327,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114433,\n                        \"gas_cost\": 8,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1657,\n                        \"op\": 91,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606319,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114441,\n                        \"gas_cost\": 1,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1658,\n                        \"op\": 95,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606318,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114442,\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1659,\n                        \"op\": 96,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606316,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114444,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1661,\n                        \"op\": 130,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606313,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114447,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1662,\n                        \"op\": 1,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606310,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114450,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1663,\n                        \"op\": 144,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606307,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114453,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1664,\n                        \"op\": 80,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606304,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114456,\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1665,\n                        \"op\": 97,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606302,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114458,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1668,\n                        \"op\": 95,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606299,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114461,\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1669,\n                        \"op\": 131,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606297,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114463,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1670,\n                        \"op\": 1,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606294,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114466,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1671,\n                        \"op\": 132,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606291,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114469,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1672,\n                        \"op\": 97,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606288,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114472,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1675,\n                        \"op\": 86,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606285,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114475,\n                        \"gas_cost\": 8,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1642,\n                        \"op\": 91,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606277,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114483,\n                        \"gas_cost\": 1,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1643,\n                        \"op\": 97,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606276,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114484,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1646,\n                        \"op\": 129,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606273,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114487,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1647,\n                        \"op\": 97,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606270,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114490,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1650,\n                        \"op\": 86,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606267,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114493,\n                        \"gas_cost\": 8,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1551,\n                        \"op\": 91,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606259,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114501,\n                        \"gas_cost\": 1,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1552,\n                        \"op\": 95,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606258,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114502,\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1553,\n                        \"op\": 129,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606256,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114504,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1554,\n                        \"op\": 144,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606253,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114507,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1555,\n                        \"op\": 80,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606250,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114510,\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1556,\n                        \"op\": 145,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606248,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114512,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1557,\n                        \"op\": 144,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606245,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114515,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1558,\n                        \"op\": 80,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606242,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114518,\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1559,\n                        \"op\": 86,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606240,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114520,\n                        \"gas_cost\": 8,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1651,\n                        \"op\": 91,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606232,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114528,\n                        \"gas_cost\": 1,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1652,\n                        \"op\": 130,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606231,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114529,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1653,\n                        \"op\": 82,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606228,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114532,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1654,\n                        \"op\": 80,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606225,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114535,\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1655,\n                        \"op\": 80,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606223,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114537,\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1656,\n                        \"op\": 86,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606221,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114539,\n                        \"gas_cost\": 8,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1676,\n                        \"op\": 91,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606213,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114547,\n                        \"gas_cost\": 1,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1677,\n                        \"op\": 146,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606212,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114548,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1678,\n                        \"op\": 145,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606209,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114551,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1679,\n                        \"op\": 80,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606206,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114554,\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1680,\n                        \"op\": 80,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606204,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114556,\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1681,\n                        \"op\": 86,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606202,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114558,\n                        \"gas_cost\": 8,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 834,\n                        \"op\": 91,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606194,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114566,\n                        \"gas_cost\": 1,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 835,\n                        \"op\": 96,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606193,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114567,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 837,\n                        \"op\": 81,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606190,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114570,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 838,\n                        \"op\": 96,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606187,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114573,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 840,\n                        \"op\": 129,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606184,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114576,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 841,\n                        \"op\": 131,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606181,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114579,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 842,\n                        \"op\": 3,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606178,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114582,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 843,\n                        \"op\": 3,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606175,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114585,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 844,\n                        \"op\": 129,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606172,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114588,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 845,\n                        \"op\": 82,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606169,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114591,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 846,\n                        \"op\": 144,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606166,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114594,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 847,\n                        \"op\": 96,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606163,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114597,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 849,\n                        \"op\": 82,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606160,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114600,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 850,\n                        \"op\": 127,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606157,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114603,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 883,\n                        \"op\": 123,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606154,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114606,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 912,\n                        \"op\": 25,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606151,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114609,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 913,\n                        \"op\": 22,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606148,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114612,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 914,\n                        \"op\": 96,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606145,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114615,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 916,\n                        \"op\": 130,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606142,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114618,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 917,\n                        \"op\": 1,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606139,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114621,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 918,\n                        \"op\": 128,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606136,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114624,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 919,\n                        \"op\": 81,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606133,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114627,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 920,\n                        \"op\": 123,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606130,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114630,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 949,\n                        \"op\": 131,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606127,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114633,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 950,\n                        \"op\": 129,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606124,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114636,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 951,\n                        \"op\": 131,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606121,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114639,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 952,\n                        \"op\": 22,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606118,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114642,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 953,\n                        \"op\": 23,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606115,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114645,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 954,\n                        \"op\": 131,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606112,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114648,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 955,\n                        \"op\": 82,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606109,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114651,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 956,\n                        \"op\": 80,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606106,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114654,\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 957,\n                        \"op\": 80,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606104,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114656,\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 958,\n                        \"op\": 80,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606102,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114658,\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 959,\n                        \"op\": 80,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606100,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114660,\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 960,\n                        \"op\": 97,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606098,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114662,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 963,\n                        \"op\": 86,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606095,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114665,\n                        \"gas_cost\": 8,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 967,\n                        \"op\": 91,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606087,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114673,\n                        \"gas_cost\": 1,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 968,\n                        \"op\": 97,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606086,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114674,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 971,\n                        \"op\": 129,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606083,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114677,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 972,\n                        \"op\": 97,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606080,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114680,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 975,\n                        \"op\": 97,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606077,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114683,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 978,\n                        \"op\": 97,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606074,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114686,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 981,\n                        \"op\": 86,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606071,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114689,\n                        \"gas_cost\": 8,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1024,\n                        \"op\": 91,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606063,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114697,\n                        \"gas_cost\": 1,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1025,\n                        \"op\": 97,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606062,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114698,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1028,\n                        \"op\": 129,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606059,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114701,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1029,\n                        \"op\": 144,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606056,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114704,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1030,\n                        \"op\": 80,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606053,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114707,\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1031,\n                        \"op\": 145,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606051,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114709,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1032,\n                        \"op\": 144,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606048,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114712,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1033,\n                        \"op\": 80,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606045,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114715,\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1034,\n                        \"op\": 86,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606043,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114717,\n                        \"gas_cost\": 8,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 982,\n                        \"op\": 91,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606035,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114725,\n                        \"gas_cost\": 1,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 983,\n                        \"op\": 99,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606034,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114726,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 988,\n                        \"op\": 22,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606031,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114729,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 989,\n                        \"op\": 86,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606028,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114732,\n                        \"gas_cost\": 8,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 993,\n                        \"op\": 91,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606020,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114740,\n                        \"gas_cost\": 1,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 994,\n                        \"op\": 95,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606019,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114741,\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 995,\n                        \"op\": 106,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606017,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114743,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1007,\n                        \"op\": 144,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606014,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114746,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1008,\n                        \"op\": 80,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606011,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114749,\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1009,\n                        \"op\": 95,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606009,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114751,\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1010,\n                        \"op\": 95,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606007,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114753,\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1011,\n                        \"op\": 131,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606005,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114755,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1012,\n                        \"op\": 81,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073606002,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114758,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1013,\n                        \"op\": 96,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073605999,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114761,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1015,\n                        \"op\": 133,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073605996,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114764,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1016,\n                        \"op\": 1,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073605993,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114767,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1017,\n                        \"op\": 132,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073605990,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114770,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1018,\n                        \"op\": 90,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073605987,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114773,\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1019,\n                        \"op\": 250,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073605985,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 114775,\n                        \"gas_cost\": 1056830933,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1020,\n                        \"op\": 80,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073603385,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 117375,\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1021,\n                        \"op\": 80,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073603383,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 117377,\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1022,\n                        \"op\": 80,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073603381,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 117379,\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 1023,\n                        \"op\": 86,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073603379,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 117381,\n                        \"gas_cost\": 8,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 990,\n                        \"op\": 91,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073603371,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 117389,\n                        \"gas_cost\": 1,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 991,\n                        \"op\": 80,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073603370,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 117390,\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 992,\n                        \"op\": 86,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073603368,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 117392,\n                        \"gas_cost\": 8,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 964,\n                        \"op\": 91,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073603360,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 117400,\n                        \"gas_cost\": 1,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 965,\n                        \"op\": 80,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073603359,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 117401,\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 966,\n                        \"op\": 86,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073603357,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 117403,\n                        \"gas_cost\": 8,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 756,\n                        \"op\": 91,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073603349,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 117411,\n                        \"gas_cost\": 1,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 757,\n                        \"op\": 80,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073603348,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 117412,\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 758,\n                        \"op\": 86,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073603346,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 117414,\n                        \"gas_cost\": 8,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 146,\n                        \"op\": 91,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073603338,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 117422,\n                        \"gas_cost\": 1,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 147,\n                        \"op\": 0,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1073603337,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 117423,\n                        \"gas_cost\": 0,\n                        \"storage_change\": null,\n                        \"status\": \"Stop\",\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      }\n                    ],\n                    \"decoded\": null\n                  },\n                  \"logs\": [],\n                  \"ordering\": [\n                    {\n                      \"Step\": 0\n                    },\n                    {\n                      \"Step\": 1\n                    },\n                    {\n                      \"Step\": 2\n                    },\n                    {\n                      \"Step\": 3\n                    },\n                    {\n                      \"Step\": 4\n                    },\n                    {\n                      \"Step\": 5\n                    },\n                    {\n                      \"Step\": 6\n                    },\n                    {\n                      \"Step\": 7\n                    },\n                    {\n                      \"Step\": 8\n                    },\n                    {\n                      \"Step\": 9\n                    },\n                    {\n                      \"Step\": 10\n                    },\n                    {\n                      \"Step\": 11\n                    },\n                    {\n                      \"Step\": 12\n                    },\n                    {\n                      \"Step\": 13\n                    },\n                    {\n                      \"Step\": 14\n                    },\n                    {\n                      \"Step\": 15\n                    },\n                    {\n                      \"Step\": 16\n                    },\n                    {\n                      \"Step\": 17\n                    },\n                    {\n                      \"Step\": 18\n                    },\n                    {\n                      \"Step\": 19\n                    },\n                    {\n                      \"Step\": 20\n                    },\n                    {\n                      \"Step\": 21\n                    },\n                    {\n                      \"Step\": 22\n                    },\n                    {\n                      \"Step\": 23\n                    },\n                    {\n                      \"Step\": 24\n                    },\n                    {\n                      \"Step\": 25\n                    },\n                    {\n                      \"Step\": 26\n                    },\n                    {\n                      \"Step\": 27\n                    },\n                    {\n                      \"Step\": 28\n                    },\n                    {\n                      \"Step\": 29\n                    },\n                    {\n                      \"Step\": 30\n                    },\n                    {\n                      \"Step\": 31\n                    },\n                    {\n                      \"Step\": 32\n                    },\n                    {\n                      \"Step\": 33\n                    },\n                    {\n                      \"Step\": 34\n                    },\n                    {\n                      \"Step\": 35\n                    },\n                    {\n                      \"Step\": 36\n                    },\n                    {\n                      \"Step\": 37\n                    },\n                    {\n                      \"Step\": 38\n                    },\n                    {\n                      \"Step\": 39\n                    },\n                    {\n                      \"Step\": 40\n                    },\n                    {\n                      \"Step\": 41\n                    },\n                    {\n                      \"Step\": 42\n                    },\n                    {\n                      \"Step\": 43\n                    },\n                    {\n                      \"Step\": 44\n                    },\n                    {\n                      \"Step\": 45\n                    },\n                    {\n                      \"Step\": 46\n                    },\n                    {\n                      \"Step\": 47\n                    },\n                    {\n                      \"Step\": 48\n                    },\n                    {\n                      \"Step\": 49\n                    },\n                    {\n                      \"Step\": 50\n                    },\n                    {\n                      \"Step\": 51\n                    },\n                    {\n                      \"Step\": 52\n                    },\n                    {\n                      \"Step\": 53\n                    },\n                    {\n                      \"Step\": 54\n                    },\n                    {\n                      \"Step\": 55\n                    },\n                    {\n                      \"Step\": 56\n                    },\n                    {\n                      \"Step\": 57\n                    },\n                    {\n                      \"Step\": 58\n                    },\n                    {\n                      \"Step\": 59\n                    },\n                    {\n                      \"Step\": 60\n                    },\n                    {\n                      \"Step\": 61\n                    },\n                    {\n                      \"Step\": 62\n                    },\n                    {\n                      \"Step\": 63\n                    },\n                    {\n                      \"Call\": 0\n                    },\n                    {\n                      \"Step\": 64\n                    },\n                    {\n                      \"Step\": 65\n                    },\n                    {\n                      \"Step\": 66\n                    },\n                    {\n                      \"Step\": 67\n                    },\n                    {\n                      \"Step\": 68\n                    },\n                    {\n                      \"Step\": 69\n                    },\n                    {\n                      \"Step\": 70\n                    },\n                    {\n                      \"Step\": 71\n                    },\n                    {\n                      \"Step\": 72\n                    },\n                    {\n                      \"Step\": 73\n                    },\n                    {\n                      \"Step\": 74\n                    },\n                    {\n                      \"Step\": 75\n                    },\n                    {\n                      \"Step\": 76\n                    },\n                    {\n                      \"Step\": 77\n                    },\n                    {\n                      \"Step\": 78\n                    },\n                    {\n                      \"Step\": 79\n                    },\n                    {\n                      \"Step\": 80\n                    },\n                    {\n                      \"Step\": 81\n                    },\n                    {\n                      \"Step\": 82\n                    },\n                    {\n                      \"Step\": 83\n                    },\n                    {\n                      \"Step\": 84\n                    },\n                    {\n                      \"Step\": 85\n                    },\n                    {\n                      \"Step\": 86\n                    },\n                    {\n                      \"Step\": 87\n                    },\n                    {\n                      \"Step\": 88\n                    },\n                    {\n                      \"Step\": 89\n                    },\n                    {\n                      \"Step\": 90\n                    },\n                    {\n                      \"Step\": 91\n                    },\n                    {\n                      \"Step\": 92\n                    },\n                    {\n                      \"Step\": 93\n                    },\n                    {\n                      \"Step\": 94\n                    },\n                    {\n                      \"Step\": 95\n                    },\n                    {\n                      \"Step\": 96\n                    },\n                    {\n                      \"Step\": 97\n                    },\n                    {\n                      \"Step\": 98\n                    },\n                    {\n                      \"Step\": 99\n                    },\n                    {\n                      \"Step\": 100\n                    },\n                    {\n                      \"Step\": 101\n                    },\n                    {\n                      \"Step\": 102\n                    },\n                    {\n                      \"Step\": 103\n                    },\n                    {\n                      \"Step\": 104\n                    },\n                    {\n                      \"Step\": 105\n                    },\n                    {\n                      \"Step\": 106\n                    },\n                    {\n                      \"Step\": 107\n                    },\n                    {\n                      \"Step\": 108\n                    },\n                    {\n                      \"Step\": 109\n                    },\n                    {\n                      \"Step\": 110\n                    },\n                    {\n                      \"Step\": 111\n                    },\n                    {\n                      \"Step\": 112\n                    },\n                    {\n                      \"Step\": 113\n                    },\n                    {\n                      \"Step\": 114\n                    },\n                    {\n                      \"Step\": 115\n                    },\n                    {\n                      \"Step\": 116\n                    },\n                    {\n                      \"Step\": 117\n                    },\n                    {\n                      \"Step\": 118\n                    },\n                    {\n                      \"Step\": 119\n                    },\n                    {\n                      \"Step\": 120\n                    },\n                    {\n                      \"Step\": 121\n                    },\n                    {\n                      \"Step\": 122\n                    },\n                    {\n                      \"Step\": 123\n                    },\n                    {\n                      \"Step\": 124\n                    },\n                    {\n                      \"Step\": 125\n                    },\n                    {\n                      \"Step\": 126\n                    },\n                    {\n                      \"Step\": 127\n                    },\n                    {\n                      \"Step\": 128\n                    },\n                    {\n                      \"Step\": 129\n                    },\n                    {\n                      \"Step\": 130\n                    },\n                    {\n                      \"Step\": 131\n                    },\n                    {\n                      \"Step\": 132\n                    },\n                    {\n                      \"Step\": 133\n                    },\n                    {\n                      \"Step\": 134\n                    },\n                    {\n                      \"Step\": 135\n                    },\n                    {\n                      \"Step\": 136\n                    },\n                    {\n                      \"Step\": 137\n                    },\n                    {\n                      \"Step\": 138\n                    },\n                    {\n                      \"Step\": 139\n                    },\n                    {\n                      \"Step\": 140\n                    },\n                    {\n                      \"Step\": 141\n                    },\n                    {\n                      \"Step\": 142\n                    },\n                    {\n                      \"Step\": 143\n                    },\n                    {\n                      \"Step\": 144\n                    },\n                    {\n                      \"Step\": 145\n                    },\n                    {\n                      \"Step\": 146\n                    },\n                    {\n                      \"Step\": 147\n                    },\n                    {\n                      \"Step\": 148\n                    },\n                    {\n                      \"Step\": 149\n                    },\n                    {\n                      \"Step\": 150\n                    },\n                    {\n                      \"Step\": 151\n                    },\n                    {\n                      \"Step\": 152\n                    },\n                    {\n                      \"Step\": 153\n                    },\n                    {\n                      \"Step\": 154\n                    },\n                    {\n                      \"Step\": 155\n                    },\n                    {\n                      \"Step\": 156\n                    },\n                    {\n                      \"Step\": 157\n                    },\n                    {\n                      \"Step\": 158\n                    },\n                    {\n                      \"Step\": 159\n                    },\n                    {\n                      \"Step\": 160\n                    },\n                    {\n                      \"Step\": 161\n                    },\n                    {\n                      \"Step\": 162\n                    },\n                    {\n                      \"Step\": 163\n                    },\n                    {\n                      \"Step\": 164\n                    },\n                    {\n                      \"Step\": 165\n                    },\n                    {\n                      \"Step\": 166\n                    },\n                    {\n                      \"Step\": 167\n                    },\n                    {\n                      \"Step\": 168\n                    },\n                    {\n                      \"Step\": 169\n                    },\n                    {\n                      \"Step\": 170\n                    },\n                    {\n                      \"Step\": 171\n                    },\n                    {\n                      \"Step\": 172\n                    },\n                    {\n                      \"Step\": 173\n                    },\n                    {\n                      \"Step\": 174\n                    },\n                    {\n                      \"Step\": 175\n                    },\n                    {\n                      \"Step\": 176\n                    },\n                    {\n                      \"Step\": 177\n                    },\n                    {\n                      \"Step\": 178\n                    },\n                    {\n                      \"Step\": 179\n                    },\n                    {\n                      \"Step\": 180\n                    },\n                    {\n                      \"Step\": 181\n                    },\n                    {\n                      \"Step\": 182\n                    },\n                    {\n                      \"Step\": 183\n                    },\n                    {\n                      \"Step\": 184\n                    },\n                    {\n                      \"Step\": 185\n                    },\n                    {\n                      \"Step\": 186\n                    },\n                    {\n                      \"Step\": 187\n                    },\n                    {\n                      \"Step\": 188\n                    },\n                    {\n                      \"Step\": 189\n                    },\n                    {\n                      \"Step\": 190\n                    },\n                    {\n                      \"Step\": 191\n                    },\n                    {\n                      \"Step\": 192\n                    },\n                    {\n                      \"Step\": 193\n                    },\n                    {\n                      \"Step\": 194\n                    },\n                    {\n                      \"Call\": 1\n                    },\n                    {\n                      \"Step\": 195\n                    },\n                    {\n                      \"Step\": 196\n                    },\n                    {\n                      \"Step\": 197\n                    },\n                    {\n                      \"Step\": 198\n                    },\n                    {\n                      \"Step\": 199\n                    },\n                    {\n                      \"Step\": 200\n                    },\n                    {\n                      \"Step\": 201\n                    },\n                    {\n                      \"Step\": 202\n                    },\n                    {\n                      \"Step\": 203\n                    },\n                    {\n                      \"Step\": 204\n                    },\n                    {\n                      \"Step\": 205\n                    },\n                    {\n                      \"Step\": 206\n                    },\n                    {\n                      \"Step\": 207\n                    },\n                    {\n                      \"Step\": 208\n                    },\n                    {\n                      \"Step\": 209\n                    },\n                    {\n                      \"Step\": 210\n                    },\n                    {\n                      \"Step\": 211\n                    },\n                    {\n                      \"Step\": 212\n                    },\n                    {\n                      \"Step\": 213\n                    },\n                    {\n                      \"Step\": 214\n                    },\n                    {\n                      \"Step\": 215\n                    },\n                    {\n                      \"Step\": 216\n                    },\n                    {\n                      \"Step\": 217\n                    },\n                    {\n                      \"Step\": 218\n                    },\n                    {\n                      \"Step\": 219\n                    },\n                    {\n                      \"Step\": 220\n                    },\n                    {\n                      \"Step\": 221\n                    },\n                    {\n                      \"Step\": 222\n                    },\n                    {\n                      \"Step\": 223\n                    },\n                    {\n                      \"Step\": 224\n                    },\n                    {\n                      \"Step\": 225\n                    },\n                    {\n                      \"Step\": 226\n                    },\n                    {\n                      \"Step\": 227\n                    },\n                    {\n                      \"Step\": 228\n                    },\n                    {\n                      \"Step\": 229\n                    },\n                    {\n                      \"Step\": 230\n                    },\n                    {\n                      \"Step\": 231\n                    },\n                    {\n                      \"Step\": 232\n                    },\n                    {\n                      \"Step\": 233\n                    },\n                    {\n                      \"Step\": 234\n                    },\n                    {\n                      \"Step\": 235\n                    },\n                    {\n                      \"Step\": 236\n                    },\n                    {\n                      \"Step\": 237\n                    },\n                    {\n                      \"Step\": 238\n                    },\n                    {\n                      \"Step\": 239\n                    },\n                    {\n                      \"Step\": 240\n                    },\n                    {\n                      \"Step\": 241\n                    },\n                    {\n                      \"Step\": 242\n                    },\n                    {\n                      \"Step\": 243\n                    },\n                    {\n                      \"Step\": 244\n                    },\n                    {\n                      \"Step\": 245\n                    },\n                    {\n                      \"Step\": 246\n                    },\n                    {\n                      \"Step\": 247\n                    },\n                    {\n                      \"Step\": 248\n                    },\n                    {\n                      \"Step\": 249\n                    },\n                    {\n                      \"Step\": 250\n                    },\n                    {\n                      \"Step\": 251\n                    },\n                    {\n                      \"Step\": 252\n                    },\n                    {\n                      \"Step\": 253\n                    },\n                    {\n                      \"Step\": 254\n                    },\n                    {\n                      \"Step\": 255\n                    },\n                    {\n                      \"Step\": 256\n                    },\n                    {\n                      \"Step\": 257\n                    },\n                    {\n                      \"Step\": 258\n                    },\n                    {\n                      \"Step\": 259\n                    },\n                    {\n                      \"Step\": 260\n                    },\n                    {\n                      \"Step\": 261\n                    },\n                    {\n                      \"Step\": 262\n                    },\n                    {\n                      \"Step\": 263\n                    },\n                    {\n                      \"Step\": 264\n                    },\n                    {\n                      \"Step\": 265\n                    },\n                    {\n                      \"Step\": 266\n                    },\n                    {\n                      \"Step\": 267\n                    },\n                    {\n                      \"Step\": 268\n                    },\n                    {\n                      \"Step\": 269\n                    },\n                    {\n                      \"Step\": 270\n                    },\n                    {\n                      \"Step\": 271\n                    },\n                    {\n                      \"Step\": 272\n                    },\n                    {\n                      \"Step\": 273\n                    },\n                    {\n                      \"Step\": 274\n                    },\n                    {\n                      \"Step\": 275\n                    },\n                    {\n                      \"Step\": 276\n                    },\n                    {\n                      \"Step\": 277\n                    },\n                    {\n                      \"Step\": 278\n                    },\n                    {\n                      \"Step\": 279\n                    },\n                    {\n                      \"Step\": 280\n                    },\n                    {\n                      \"Step\": 281\n                    },\n                    {\n                      \"Step\": 282\n                    },\n                    {\n                      \"Step\": 283\n                    },\n                    {\n                      \"Step\": 284\n                    },\n                    {\n                      \"Step\": 285\n                    },\n                    {\n                      \"Step\": 286\n                    },\n                    {\n                      \"Step\": 287\n                    },\n                    {\n                      \"Step\": 288\n                    },\n                    {\n                      \"Step\": 289\n                    },\n                    {\n                      \"Step\": 290\n                    },\n                    {\n                      \"Step\": 291\n                    },\n                    {\n                      \"Step\": 292\n                    },\n                    {\n                      \"Step\": 293\n                    },\n                    {\n                      \"Step\": 294\n                    },\n                    {\n                      \"Step\": 295\n                    },\n                    {\n                      \"Step\": 296\n                    },\n                    {\n                      \"Step\": 297\n                    },\n                    {\n                      \"Step\": 298\n                    },\n                    {\n                      \"Step\": 299\n                    },\n                    {\n                      \"Step\": 300\n                    },\n                    {\n                      \"Step\": 301\n                    },\n                    {\n                      \"Step\": 302\n                    },\n                    {\n                      \"Step\": 303\n                    },\n                    {\n                      \"Step\": 304\n                    },\n                    {\n                      \"Step\": 305\n                    },\n                    {\n                      \"Step\": 306\n                    },\n                    {\n                      \"Step\": 307\n                    },\n                    {\n                      \"Step\": 308\n                    },\n                    {\n                      \"Step\": 309\n                    },\n                    {\n                      \"Step\": 310\n                    },\n                    {\n                      \"Step\": 311\n                    },\n                    {\n                      \"Step\": 312\n                    },\n                    {\n                      \"Step\": 313\n                    },\n                    {\n                      \"Step\": 314\n                    },\n                    {\n                      \"Step\": 315\n                    },\n                    {\n                      \"Step\": 316\n                    },\n                    {\n                      \"Step\": 317\n                    },\n                    {\n                      \"Step\": 318\n                    },\n                    {\n                      \"Step\": 319\n                    },\n                    {\n                      \"Step\": 320\n                    },\n                    {\n                      \"Step\": 321\n                    },\n                    {\n                      \"Step\": 322\n                    },\n                    {\n                      \"Step\": 323\n                    },\n                    {\n                      \"Step\": 324\n                    },\n                    {\n                      \"Step\": 325\n                    },\n                    {\n                      \"Step\": 326\n                    },\n                    {\n                      \"Step\": 327\n                    },\n                    {\n                      \"Step\": 328\n                    },\n                    {\n                      \"Step\": 329\n                    },\n                    {\n                      \"Step\": 330\n                    },\n                    {\n                      \"Step\": 331\n                    },\n                    {\n                      \"Call\": 2\n                    },\n                    {\n                      \"Step\": 332\n                    },\n                    {\n                      \"Step\": 333\n                    },\n                    {\n                      \"Step\": 334\n                    },\n                    {\n                      \"Step\": 335\n                    },\n                    {\n                      \"Step\": 336\n                    },\n                    {\n                      \"Step\": 337\n                    },\n                    {\n                      \"Step\": 338\n                    },\n                    {\n                      \"Step\": 339\n                    },\n                    {\n                      \"Step\": 340\n                    },\n                    {\n                      \"Step\": 341\n                    },\n                    {\n                      \"Step\": 342\n                    },\n                    {\n                      \"Step\": 343\n                    },\n                    {\n                      \"Step\": 344\n                    },\n                    {\n                      \"Step\": 345\n                    },\n                    {\n                      \"Step\": 346\n                    }\n                  ]\n                },\n                {\n                  \"parent\": 0,\n                  \"children\": [],\n                  \"idx\": 1,\n                  \"trace\": {\n                    \"depth\": 1,\n                    \"success\": true,\n                    \"caller\": \"0x7fa9385be102ac3eac297483dd6233d62b3e1496\",\n                    \"address\": \"0x5615deb798bb3e4dfa0139dfa1b3d433cc23b72f\",\n                    \"maybe_precompile\": false,\n                    \"selfdestruct_address\": null,\n                    \"selfdestruct_refund_target\": null,\n                    \"selfdestruct_transferred_value\": null,\n                    \"kind\": \"CREATE\",\n                    \"value\": \"0x0\",\n                    \"data\": \"{...}\",\n                    \"output\": \"{...}\",\n                    \"gas_used\": \"{...}\",\n                    \"gas_limit\": \"{...}\",\n                    \"gas_refund_counter\": 0,\n                    \"status\": \"Return\",\n                    \"steps\": [\n                      {\n                        \"pc\": 0,\n                        \"op\": 96,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 2,\n                        \"op\": 96,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056912053,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 3,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 4,\n                        \"op\": 82,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056912050,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 6,\n                        \"gas_cost\": 12,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 5,\n                        \"op\": 52,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056912038,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 18,\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 6,\n                        \"op\": 128,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056912036,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 20,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 7,\n                        \"op\": 21,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056912033,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 23,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 8,\n                        \"op\": 96,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056912030,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 26,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 10,\n                        \"op\": 87,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056912027,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 29,\n                        \"gas_cost\": 10,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 14,\n                        \"op\": 91,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056912017,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 39,\n                        \"gas_cost\": 1,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 15,\n                        \"op\": 80,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056912016,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 40,\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 16,\n                        \"op\": 97,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056912014,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 42,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 19,\n                        \"op\": 128,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056912011,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 45,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 20,\n                        \"op\": 97,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056912008,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 48,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 23,\n                        \"op\": 95,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056912005,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 51,\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 24,\n                        \"op\": 57,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056912003,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 53,\n                        \"gas_cost\": 54,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 25,\n                        \"op\": 95,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056911949,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 107,\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 26,\n                        \"op\": 243,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056911947,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 109,\n                        \"gas_cost\": 0,\n                        \"storage_change\": null,\n                        \"status\": \"Return\",\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      }\n                    ],\n                    \"decoded\": null\n                  },\n                  \"logs\": [],\n                  \"ordering\": [\n                    {\n                      \"Step\": 0\n                    },\n                    {\n                      \"Step\": 1\n                    },\n                    {\n                      \"Step\": 2\n                    },\n                    {\n                      \"Step\": 3\n                    },\n                    {\n                      \"Step\": 4\n                    },\n                    {\n                      \"Step\": 5\n                    },\n                    {\n                      \"Step\": 6\n                    },\n                    {\n                      \"Step\": 7\n                    },\n                    {\n                      \"Step\": 8\n                    },\n                    {\n                      \"Step\": 9\n                    },\n                    {\n                      \"Step\": 10\n                    },\n                    {\n                      \"Step\": 11\n                    },\n                    {\n                      \"Step\": 12\n                    },\n                    {\n                      \"Step\": 13\n                    },\n                    {\n                      \"Step\": 14\n                    },\n                    {\n                      \"Step\": 15\n                    },\n                    {\n                      \"Step\": 16\n                    }\n                  ]\n                },\n                {\n                  \"parent\": 0,\n                  \"children\": [],\n                  \"idx\": 2,\n                  \"trace\": {\n                    \"depth\": 1,\n                    \"success\": true,\n                    \"caller\": \"0x7fa9385be102ac3eac297483dd6233d62b3e1496\",\n                    \"address\": \"0x5615deb798bb3e4dfa0139dfa1b3d433cc23b72f\",\n                    \"maybe_precompile\": null,\n                    \"selfdestruct_address\": null,\n                    \"selfdestruct_refund_target\": null,\n                    \"selfdestruct_transferred_value\": null,\n                    \"kind\": \"CALL\",\n                    \"value\": \"0x0\",\n                    \"data\": \"0xe26d14740000000000000000000000000000000000000000000000000000000000000064\",\n                    \"output\": \"0x\",\n                    \"gas_used\": \"{...}\",\n                    \"gas_limit\": \"{...}\",\n                    \"gas_refund_counter\": 0,\n                    \"status\": \"Stop\",\n                    \"steps\": [\n                      {\n                        \"pc\": 0,\n                        \"op\": 96,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 2,\n                        \"op\": 96,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 4,\n                        \"op\": 82,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 12,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 5,\n                        \"op\": 52,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 6,\n                        \"op\": 128,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 7,\n                        \"op\": 21,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 8,\n                        \"op\": 96,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 10,\n                        \"op\": 87,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 10,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 14,\n                        \"op\": 91,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 1,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 15,\n                        \"op\": 80,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 16,\n                        \"op\": 96,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 18,\n                        \"op\": 54,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 19,\n                        \"op\": 16,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 20,\n                        \"op\": 96,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 22,\n                        \"op\": 87,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 10,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 23,\n                        \"op\": 95,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 24,\n                        \"op\": 53,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 25,\n                        \"op\": 96,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 27,\n                        \"op\": 28,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 28,\n                        \"op\": 128,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 29,\n                        \"op\": 99,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 34,\n                        \"op\": 20,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 35,\n                        \"op\": 96,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 37,\n                        \"op\": 87,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": \"{...}\",\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": \"{...}\",\n                        \"gas_cost\": 10,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 38,\n                        \"op\": 128,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853373,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 96,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 39,\n                        \"op\": 99,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853370,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 99,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 44,\n                        \"op\": 20,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853367,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 102,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 45,\n                        \"op\": 96,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853364,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 105,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 47,\n                        \"op\": 87,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853361,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 108,\n                        \"gas_cost\": 10,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 78,\n                        \"op\": 91,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853351,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 118,\n                        \"gas_cost\": 1,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 79,\n                        \"op\": 96,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853350,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 119,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 81,\n                        \"op\": 96,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853347,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 122,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 83,\n                        \"op\": 128,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853344,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 125,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 84,\n                        \"op\": 54,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853341,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 128,\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 85,\n                        \"op\": 3,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853339,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 130,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 86,\n                        \"op\": 129,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853336,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 133,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 87,\n                        \"op\": 1,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853333,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 136,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 88,\n                        \"op\": 144,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853330,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 139,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 89,\n                        \"op\": 96,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853327,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 142,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 91,\n                        \"op\": 145,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853324,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 145,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 92,\n                        \"op\": 144,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853321,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 148,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 93,\n                        \"op\": 96,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853318,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 151,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 95,\n                        \"op\": 86,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853315,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 154,\n                        \"gas_cost\": 8,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 202,\n                        \"op\": 91,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853307,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 162,\n                        \"gas_cost\": 1,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 203,\n                        \"op\": 95,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853306,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 163,\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 204,\n                        \"op\": 96,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853304,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 165,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 206,\n                        \"op\": 130,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853301,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 168,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 207,\n                        \"op\": 132,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853298,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 171,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 208,\n                        \"op\": 3,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853295,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 174,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 209,\n                        \"op\": 18,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853292,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 177,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 210,\n                        \"op\": 21,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853289,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 180,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 211,\n                        \"op\": 96,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853286,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 183,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 213,\n                        \"op\": 87,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853283,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 186,\n                        \"gas_cost\": 10,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 220,\n                        \"op\": 91,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853273,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 196,\n                        \"gas_cost\": 1,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 221,\n                        \"op\": 95,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853272,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 197,\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 222,\n                        \"op\": 96,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853270,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 199,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 224,\n                        \"op\": 132,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853267,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 202,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 225,\n                        \"op\": 130,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853264,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 205,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 226,\n                        \"op\": 133,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853261,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 208,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 227,\n                        \"op\": 1,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853258,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 211,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 228,\n                        \"op\": 96,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853255,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 214,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 230,\n                        \"op\": 86,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853252,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 217,\n                        \"gas_cost\": 8,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 184,\n                        \"op\": 91,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853244,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 225,\n                        \"gas_cost\": 1,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 185,\n                        \"op\": 95,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853243,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 226,\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 186,\n                        \"op\": 129,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853241,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 228,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 187,\n                        \"op\": 53,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853238,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 231,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 188,\n                        \"op\": 144,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853235,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 234,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 189,\n                        \"op\": 80,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853232,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 237,\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 190,\n                        \"op\": 96,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853230,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 239,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 192,\n                        \"op\": 129,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853227,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 242,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 193,\n                        \"op\": 96,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853224,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 245,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 195,\n                        \"op\": 86,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853221,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 248,\n                        \"gas_cost\": 8,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 165,\n                        \"op\": 91,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853213,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 256,\n                        \"gas_cost\": 1,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 166,\n                        \"op\": 96,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853212,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 257,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 168,\n                        \"op\": 129,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853209,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 260,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 169,\n                        \"op\": 96,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853206,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 263,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 171,\n                        \"op\": 86,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853203,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 266,\n                        \"gas_cost\": 8,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 116,\n                        \"op\": 91,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853195,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 274,\n                        \"gas_cost\": 1,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 117,\n                        \"op\": 95,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853194,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 275,\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 118,\n                        \"op\": 129,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853192,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 277,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 119,\n                        \"op\": 144,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853189,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 280,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 120,\n                        \"op\": 80,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853186,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 283,\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 121,\n                        \"op\": 145,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853184,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 285,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 122,\n                        \"op\": 144,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853181,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 288,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 123,\n                        \"op\": 80,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853178,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 291,\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 124,\n                        \"op\": 86,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853176,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 293,\n                        \"gas_cost\": 8,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 172,\n                        \"op\": 91,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853168,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 301,\n                        \"gas_cost\": 1,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 173,\n                        \"op\": 129,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853167,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 302,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 174,\n                        \"op\": 20,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853164,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 305,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 175,\n                        \"op\": 96,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853161,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 308,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 177,\n                        \"op\": 87,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853158,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 311,\n                        \"gas_cost\": 10,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 181,\n                        \"op\": 91,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853148,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 321,\n                        \"gas_cost\": 1,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 182,\n                        \"op\": 80,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853147,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 322,\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 183,\n                        \"op\": 86,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853145,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 324,\n                        \"gas_cost\": 8,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 196,\n                        \"op\": 91,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853137,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 332,\n                        \"gas_cost\": 1,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 197,\n                        \"op\": 146,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853136,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 333,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 198,\n                        \"op\": 145,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853133,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 336,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 199,\n                        \"op\": 80,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853130,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 339,\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 200,\n                        \"op\": 80,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853128,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 341,\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 201,\n                        \"op\": 86,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853126,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 343,\n                        \"gas_cost\": 8,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 231,\n                        \"op\": 91,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853118,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 351,\n                        \"gas_cost\": 1,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 232,\n                        \"op\": 145,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853117,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 352,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 233,\n                        \"op\": 80,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853114,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 355,\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 234,\n                        \"op\": 80,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853112,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 357,\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 235,\n                        \"op\": 146,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853110,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 359,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 236,\n                        \"op\": 145,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853107,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 362,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 237,\n                        \"op\": 80,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853104,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 365,\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 238,\n                        \"op\": 80,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853102,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 367,\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 239,\n                        \"op\": 86,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853100,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 369,\n                        \"gas_cost\": 8,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 96,\n                        \"op\": 91,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853092,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 377,\n                        \"gas_cost\": 1,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 97,\n                        \"op\": 96,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853091,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 378,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 99,\n                        \"op\": 86,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853088,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 381,\n                        \"gas_cost\": 8,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 107,\n                        \"op\": 91,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853080,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 389,\n                        \"gas_cost\": 1,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 108,\n                        \"op\": 128,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853079,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 390,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 109,\n                        \"op\": 95,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853076,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 393,\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 110,\n                        \"op\": 129,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853074,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 395,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 111,\n                        \"op\": 144,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853071,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 398,\n                        \"gas_cost\": 3,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 112,\n                        \"op\": 85,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056853068,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 401,\n                        \"gas_cost\": 22100,\n                        \"storage_change\": {\n                          \"key\": \"0x0\",\n                          \"value\": \"0x64\",\n                          \"had_value\": \"0x0\",\n                          \"reason\": \"SSTORE\"\n                        },\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 113,\n                        \"op\": 80,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056830968,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 22501,\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 114,\n                        \"op\": 80,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056830966,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 22503,\n                        \"gas_cost\": 2,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 115,\n                        \"op\": 86,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056830964,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 22505,\n                        \"gas_cost\": 8,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 100,\n                        \"op\": 91,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056830956,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 22513,\n                        \"gas_cost\": 1,\n                        \"storage_change\": null,\n                        \"status\": null,\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      },\n                      {\n                        \"pc\": 101,\n                        \"op\": 0,\n                        \"stack\": null,\n                        \"push_stack\": null,\n                        \"memory\": null,\n                        \"returndata\": \"0x\",\n                        \"gas_remaining\": 1056830955,\n                        \"gas_refund_counter\": 0,\n                        \"gas_used\": 22514,\n                        \"gas_cost\": 0,\n                        \"storage_change\": null,\n                        \"status\": \"Stop\",\n                        \"immediate_bytes\": null,\n                        \"decoded\": null\n                      }\n                    ],\n                    \"decoded\": null\n                  },\n                  \"logs\": [],\n                  \"ordering\": [\n                    {\n                      \"Step\": 0\n                    },\n                    {\n                      \"Step\": 1\n                    },\n                    {\n                      \"Step\": 2\n                    },\n                    {\n                      \"Step\": 3\n                    },\n                    {\n                      \"Step\": 4\n                    },\n                    {\n                      \"Step\": 5\n                    },\n                    {\n                      \"Step\": 6\n                    },\n                    {\n                      \"Step\": 7\n                    },\n                    {\n                      \"Step\": 8\n                    },\n                    {\n                      \"Step\": 9\n                    },\n                    {\n                      \"Step\": 10\n                    },\n                    {\n                      \"Step\": 11\n                    },\n                    {\n                      \"Step\": 12\n                    },\n                    {\n                      \"Step\": 13\n                    },\n                    {\n                      \"Step\": 14\n                    },\n                    {\n                      \"Step\": 15\n                    },\n                    {\n                      \"Step\": 16\n                    },\n                    {\n                      \"Step\": 17\n                    },\n                    {\n                      \"Step\": 18\n                    },\n                    {\n                      \"Step\": 19\n                    },\n                    {\n                      \"Step\": 20\n                    },\n                    {\n                      \"Step\": 21\n                    },\n                    {\n                      \"Step\": 22\n                    },\n                    {\n                      \"Step\": 23\n                    },\n                    {\n                      \"Step\": 24\n                    },\n                    {\n                      \"Step\": 25\n                    },\n                    {\n                      \"Step\": 26\n                    },\n                    {\n                      \"Step\": 27\n                    },\n                    {\n                      \"Step\": 28\n                    },\n                    {\n                      \"Step\": 29\n                    },\n                    {\n                      \"Step\": 30\n                    },\n                    {\n                      \"Step\": 31\n                    },\n                    {\n                      \"Step\": 32\n                    },\n                    {\n                      \"Step\": 33\n                    },\n                    {\n                      \"Step\": 34\n                    },\n                    {\n                      \"Step\": 35\n                    },\n                    {\n                      \"Step\": 36\n                    },\n                    {\n                      \"Step\": 37\n                    },\n                    {\n                      \"Step\": 38\n                    },\n                    {\n                      \"Step\": 39\n                    },\n                    {\n                      \"Step\": 40\n                    },\n                    {\n                      \"Step\": 41\n                    },\n                    {\n                      \"Step\": 42\n                    },\n                    {\n                      \"Step\": 43\n                    },\n                    {\n                      \"Step\": 44\n                    },\n                    {\n                      \"Step\": 45\n                    },\n                    {\n                      \"Step\": 46\n                    },\n                    {\n                      \"Step\": 47\n                    },\n                    {\n                      \"Step\": 48\n                    },\n                    {\n                      \"Step\": 49\n                    },\n                    {\n                      \"Step\": 50\n                    },\n                    {\n                      \"Step\": 51\n                    },\n                    {\n                      \"Step\": 52\n                    },\n                    {\n                      \"Step\": 53\n                    },\n                    {\n                      \"Step\": 54\n                    },\n                    {\n                      \"Step\": 55\n                    },\n                    {\n                      \"Step\": 56\n                    },\n                    {\n                      \"Step\": 57\n                    },\n                    {\n                      \"Step\": 58\n                    },\n                    {\n                      \"Step\": 59\n                    },\n                    {\n                      \"Step\": 60\n                    },\n                    {\n                      \"Step\": 61\n                    },\n                    {\n                      \"Step\": 62\n                    },\n                    {\n                      \"Step\": 63\n                    },\n                    {\n                      \"Step\": 64\n                    },\n                    {\n                      \"Step\": 65\n                    },\n                    {\n                      \"Step\": 66\n                    },\n                    {\n                      \"Step\": 67\n                    },\n                    {\n                      \"Step\": 68\n                    },\n                    {\n                      \"Step\": 69\n                    },\n                    {\n                      \"Step\": 70\n                    },\n                    {\n                      \"Step\": 71\n                    },\n                    {\n                      \"Step\": 72\n                    },\n                    {\n                      \"Step\": 73\n                    },\n                    {\n                      \"Step\": 74\n                    },\n                    {\n                      \"Step\": 75\n                    },\n                    {\n                      \"Step\": 76\n                    },\n                    {\n                      \"Step\": 77\n                    },\n                    {\n                      \"Step\": 78\n                    },\n                    {\n                      \"Step\": 79\n                    },\n                    {\n                      \"Step\": 80\n                    },\n                    {\n                      \"Step\": 81\n                    },\n                    {\n                      \"Step\": 82\n                    },\n                    {\n                      \"Step\": 83\n                    },\n                    {\n                      \"Step\": 84\n                    },\n                    {\n                      \"Step\": 85\n                    },\n                    {\n                      \"Step\": 86\n                    },\n                    {\n                      \"Step\": 87\n                    },\n                    {\n                      \"Step\": 88\n                    },\n                    {\n                      \"Step\": 89\n                    },\n                    {\n                      \"Step\": 90\n                    },\n                    {\n                      \"Step\": 91\n                    },\n                    {\n                      \"Step\": 92\n                    },\n                    {\n                      \"Step\": 93\n                    },\n                    {\n                      \"Step\": 94\n                    },\n                    {\n                      \"Step\": 95\n                    },\n                    {\n                      \"Step\": 96\n                    },\n                    {\n                      \"Step\": 97\n                    },\n                    {\n                      \"Step\": 98\n                    },\n                    {\n                      \"Step\": 99\n                    },\n                    {\n                      \"Step\": 100\n                    },\n                    {\n                      \"Step\": 101\n                    },\n                    {\n                      \"Step\": 102\n                    },\n                    {\n                      \"Step\": 103\n                    },\n                    {\n                      \"Step\": 104\n                    },\n                    {\n                      \"Step\": 105\n                    },\n                    {\n                      \"Step\": 106\n                    },\n                    {\n                      \"Step\": 107\n                    },\n                    {\n                      \"Step\": 108\n                    },\n                    {\n                      \"Step\": 109\n                    },\n                    {\n                      \"Step\": 110\n                    },\n                    {\n                      \"Step\": 111\n                    },\n                    {\n                      \"Step\": 112\n                    },\n                    {\n                      \"Step\": 113\n                    },\n                    {\n                      \"Step\": 114\n                    },\n                    {\n                      \"Step\": 115\n                    },\n                    {\n                      \"Step\": 116\n                    },\n                    {\n                      \"Step\": 117\n                    },\n                    {\n                      \"Step\": 118\n                    },\n                    {\n                      \"Step\": 119\n                    },\n                    {\n                      \"Step\": 120\n                    },\n                    {\n                      \"Step\": 121\n                    },\n                    {\n                      \"Step\": 122\n                    }\n                  ]\n                },\n                {\n                  \"parent\": 0,\n                  \"children\": [],\n                  \"idx\": 3,\n                  \"trace\": {\n                    \"depth\": 1,\n                    \"success\": true,\n                    \"caller\": \"0x7fa9385be102ac3eac297483dd6233d62b3e1496\",\n                    \"address\": \"0x000000000000000000636f6e736f6c652e6c6f67\",\n                    \"maybe_precompile\": null,\n                    \"selfdestruct_address\": null,\n                    \"selfdestruct_refund_target\": null,\n                    \"selfdestruct_transferred_value\": null,\n                    \"kind\": \"STATICCALL\",\n                    \"value\": \"0x0\",\n                    \"data\": \"{...}\",\n                    \"output\": \"0x\",\n                    \"gas_used\": \"{...}\",\n                    \"gas_limit\": \"{...}\",\n                    \"gas_refund_counter\": 0,\n                    \"status\": \"Stop\",\n                    \"steps\": [],\n                    \"decoded\": null\n                  },\n                  \"logs\": [],\n                  \"ordering\": []\n                }\n              ]\n            }\n          ]\n        ],\n        \"labeled_addresses\": {},\n        \"duration\": \"{...}\",\n        \"breakpoints\": {},\n        \"gas_snapshots\": {}\n      }\n    },\n    \"warnings\": []\n  }\n}\n"
  },
  {
    "path": "crates/forge/tests/fixtures/backtraces/Backtrace.t.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../src/test.sol\";\nimport \"../src/Vm.sol\";\nimport \"../src/SimpleRevert.sol\";\nimport \"../src/NestedCalls.sol\";\nimport \"../src/DelegateCall.sol\";\nimport \"../src/StaticCall.sol\";\n\ncontract BacktraceTest is DSTest {\n    SimpleRevert simpleRevert;\n    NestedCalls nestedCalls;\n    DelegateTarget delegateTarget;\n    DelegateCaller delegateCaller;\n    StaticTarget staticTarget;\n    StaticCaller staticCaller;\n\n    function setUp() public {\n        simpleRevert = new SimpleRevert();\n        nestedCalls = new NestedCalls();\n        delegateTarget = new DelegateTarget();\n        delegateCaller = new DelegateCaller(address(delegateTarget));\n        staticTarget = new StaticTarget();\n        staticCaller = new StaticCaller(address(staticTarget));\n    }\n\n    // Simple revert test\n    function testSimpleRevert() public {\n        simpleRevert.doRevert(\"Simple revert message\");\n    }\n\n    // Require failure test\n    function testRequireFail() public {\n        simpleRevert.doRequire(0);\n    }\n\n    // Assert failure test\n    function testAssertFail() public {\n        simpleRevert.doAssert();\n    }\n\n    // Custom error test\n    function testCustomError() public {\n        simpleRevert.doCustomError();\n    }\n\n    // Nested calls test\n    function testNestedCalls() public {\n        nestedCalls.nestedCall(5);\n    }\n\n    // Internal call chain test\n    function testInternalCallsSameSource() public {\n        nestedCalls.callChain1();\n    }\n\n    // Test internal calls within test contract\n    function testInternalCallChain() public {\n        internalCall1();\n    }\n\n    function internalCall1() internal {\n        internalCall2();\n    }\n\n    function internalCall2() internal {\n        internalCall3();\n    }\n\n    function internalCall3() internal pure {\n        revert(\"Failed at internal level 3\");\n    }\n\n    // Delegate call revert test\n    function testDelegateCallRevert() public {\n        delegateCaller.delegateFail();\n    }\n\n    // Delegate call require test\n    function testDelegateCallRequire() public {\n        delegateCaller.delegateCompute(0, 5);\n    }\n\n    // Static call revert test\n    function testStaticCallRevert() public view {\n        staticCaller.staticCallFail();\n    }\n\n    // Static call require test\n    function testStaticCallRequire() public view {\n        staticCaller.staticCompute(0);\n    }\n}\n"
  },
  {
    "path": "crates/forge/tests/fixtures/backtraces/DelegateCall.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/// @title DelegateCall - Testing delegate call traces\ncontract DelegateTarget {\n    function fail() public pure {\n        revert(\"Delegate target failed\");\n    }\n\n    function compute(uint256 a, uint256 b) public pure returns (uint256) {\n        require(a > 0, \"a must be positive\");\n        require(b > 0, \"b must be positive\");\n        return a + b;\n    }\n}\n\ncontract DelegateCaller {\n    address public target;\n\n    constructor(address _target) {\n        target = _target;\n    }\n\n    function delegateFail() public {\n        (bool success,) = target.delegatecall(abi.encodeWithSignature(\"fail()\"));\n        require(success, \"Delegate call failed\");\n    }\n\n    function delegateCompute(uint256 a, uint256 b) public returns (uint256) {\n        (bool success, bytes memory data) =\n            target.delegatecall(abi.encodeWithSignature(\"compute(uint256,uint256)\", a, b));\n        require(success, \"Delegate compute failed\");\n        return abi.decode(data, (uint256));\n    }\n}\n"
  },
  {
    "path": "crates/forge/tests/fixtures/backtraces/ForkBacktrace.t.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../src/test.sol\";\nimport \"../src/ForkedERC20Wrapper.sol\";\n\ncontract ForkBacktraceTest is DSTest {\n    ForkedERC20Wrapper wrapper;\n\n    address constant USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48;\n    address constant CIRCLE = 0x55FE002aefF02F77364de339a1292923A15844B8;\n\n    function setUp() public {\n        wrapper = new ForkedERC20Wrapper();\n    }\n\n    function testTransferWithoutBalance() public {\n        wrapper.transferWithoutBalance(address(0xdead), 1000000);\n    }\n\n    function testTransferFromWithoutApproval() public {\n        wrapper.transferFromWithoutApproval(CIRCLE, address(0xdead), 1000000);\n    }\n\n    function testRequireNonZeroBalance() public view {\n        wrapper.requireNonZeroBalance(address(wrapper));\n    }\n\n    function testNestedFailure() public {\n        wrapper.nestedFailure();\n    }\n\n    function testDirectOnChainRevert() public {\n        // Try to call transfer directly on USDC without having balance\n        (bool success,) = USDC.call(abi.encodeWithSignature(\"transfer(address,uint256)\", address(0xdead), 1000000));\n        require(success, \"USDC transfer failed\");\n    }\n}\n"
  },
  {
    "path": "crates/forge/tests/fixtures/backtraces/ForkedERC20Wrapper.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IERC20 {\n    function transfer(address to, uint256 amount) external returns (bool);\n    function transferFrom(address from, address to, uint256 amount) external returns (bool);\n    function balanceOf(address account) external view returns (uint256);\n}\n\ncontract ForkedERC20Wrapper {\n    address constant USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48;\n\n    function transferWithoutBalance(address recipient, uint256 amount) public {\n        IERC20(USDC).transfer(recipient, amount);\n    }\n\n    function transferFromWithoutApproval(address from, address to, uint256 amount) public {\n        IERC20(USDC).transferFrom(from, to, amount);\n    }\n\n    function requireNonZeroBalance(address account) public view {\n        uint256 balance = IERC20(USDC).balanceOf(account);\n        require(balance > 0, \"Account has zero USDC balance\");\n    }\n\n    function nestedFailure() public {\n        internalCall();\n    }\n\n    function internalCall() internal {\n        transferWithoutBalance(address(0xdead), 1000000);\n    }\n}\n"
  },
  {
    "path": "crates/forge/tests/fixtures/backtraces/LibraryBacktrace.t.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../src/test.sol\";\nimport \"../src/Vm.sol\";\nimport \"../src/LibraryConsumer.sol\";\nimport \"../src/libraries/ExternalMathLib.sol\";\n\ncontract LibraryBacktraceTest is DSTest {\n    Vm constant vm = Vm(HEVM_ADDRESS);\n    LibraryConsumer consumer;\n    address constant EXTERNAL_LIB_ADDRESS = 0x1234567890123456789012345678901234567890;\n\n    function setUp() public {\n        // Deploy the external library at the configured address\n        bytes memory libraryBytecode = type(ExternalMathLib).runtimeCode;\n        vm.etch(EXTERNAL_LIB_ADDRESS, libraryBytecode);\n\n        // Deploy consumer contract\n        consumer = new LibraryConsumer();\n    }\n\n    // Internal library tests (should show inlined source locations)\n\n    /// @notice Test division by zero in internal library\n    function testInternalDivisionByZero() public {\n        consumer.internalDivide(100, 0);\n    }\n\n    /// @notice Test underflow in internal library\n    function testInternalUnderflow() public {\n        consumer.internalSubtract(10, 20);\n    }\n\n    /// @notice Test overflow in internal library\n    function testInternalOverflow() public {\n        consumer.internalMultiply(type(uint256).max, 2);\n    }\n\n    /// @notice Test require in internal library\n    function testInternalRequire() public {\n        consumer.internalCheckPositive(0);\n    }\n\n    // External library tests (should show delegatecall to library address)\n\n    /// @notice Test division by zero in external library\n    function testExternalDivisionByZero() public {\n        consumer.externalDivide(100, 0);\n    }\n\n    /// @notice Test underflow in external library\n    function testExternalUnderflow() public {\n        consumer.externalSubtract(10, 20);\n    }\n\n    /// @notice Test overflow in external library\n    function testExternalOverflow() public {\n        consumer.externalMultiply(type(uint256).max, 2);\n    }\n\n    /// @notice Test require in external library\n    function testExternalRequire() public {\n        consumer.externalCheckPositive(0);\n    }\n\n    // Mixed library usage test\n\n    /// @notice Test mixed library usage with failure in external library\n    function testMixedLibraryFailure() public {\n        // This will fail at the external library division step (50 - 50 = 0, then divide by 0)\n        consumer.mixedCalculation(50, 50, 0);\n    }\n}\n"
  },
  {
    "path": "crates/forge/tests/fixtures/backtraces/LibraryConsumer.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./libraries/InternalMathLib.sol\";\nimport \"./libraries/ExternalMathLib.sol\";\n\n/// @title LibraryConsumer - A contract that uses both internal and external libraries\ncontract LibraryConsumer {\n    using InternalMathLib for uint256;\n\n    uint256 public result;\n\n    // Internal library functions (inlined into contract bytecode)\n\n    /// @notice Perform division using internal library\n    function internalDivide(uint256 a, uint256 b) public returns (uint256) {\n        result = a.div(b);\n        return result;\n    }\n\n    /// @notice Perform multiplication using internal library\n    function internalMultiply(uint256 a, uint256 b) public returns (uint256) {\n        result = a.mul(b);\n        return result;\n    }\n\n    /// @notice Perform subtraction using internal library\n    function internalSubtract(uint256 a, uint256 b) public returns (uint256) {\n        result = a.sub(b);\n        return result;\n    }\n\n    /// @notice Check positive value using internal library\n    function internalCheckPositive(uint256 value) public returns (uint256) {\n        result = InternalMathLib.requirePositive(value);\n        return result;\n    }\n\n    // External library functions (delegatecall to deployed library)\n\n    /// @notice Perform division using external library\n    function externalDivide(uint256 a, uint256 b) public returns (uint256) {\n        result = ExternalMathLib.div(a, b);\n        return result;\n    }\n\n    /// @notice Perform multiplication using external library\n    function externalMultiply(uint256 a, uint256 b) public returns (uint256) {\n        result = ExternalMathLib.mul(a, b);\n        return result;\n    }\n\n    /// @notice Perform subtraction using external library\n    function externalSubtract(uint256 a, uint256 b) public returns (uint256) {\n        result = ExternalMathLib.sub(a, b);\n        return result;\n    }\n\n    /// @notice Check positive value using external library\n    function externalCheckPositive(uint256 value) public returns (uint256) {\n        result = ExternalMathLib.requirePositive(value);\n        return result;\n    }\n\n    // Mixed usage example\n\n    /// @notice Complex calculation using both libraries\n    function mixedCalculation(uint256 a, uint256 b, uint256 c) public returns (uint256) {\n        // First use internal library\n        uint256 step1 = a.sub(b);\n        // Then use external library\n        uint256 step2 = ExternalMathLib.div(step1, c);\n        // Back to internal\n        result = step2.mul(10);\n        return result;\n    }\n}\n"
  },
  {
    "path": "crates/forge/tests/fixtures/backtraces/MultipleLibraryBacktrace.t.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../src/test.sol\";\nimport \"../src/MultipleLibraryConsumer.sol\";\n\ncontract MultipleLibraryBacktraceTest is DSTest {\n    MultipleLibraryConsumer consumer;\n\n    function setUp() public {\n        consumer = new MultipleLibraryConsumer();\n    }\n\n    /// @notice Test that FirstMathLib shows correctly in backtrace\n    function testFirstLibraryError() public {\n        consumer.useFirstLib(10, 0); // Division by zero in FirstMathLib\n    }\n\n    /// @notice Test that SecondMathLib shows correctly in backtrace\n    function testSecondLibraryError() public {\n        consumer.useSecondLib(5, 10); // Underflow in SecondMathLib\n    }\n\n    /// @notice Test that ThirdMathLib shows correctly in backtrace\n    function testThirdLibraryError() public {\n        consumer.useThirdLib(10, 0); // Modulo by zero in ThirdMathLib\n    }\n\n    /// @notice Test complex failure in the first library\n    function testAllLibrariesFirstFails() public {\n        consumer.useAllLibraries(10, 0, 5); // Division by zero in FirstMathLib\n    }\n}\n"
  },
  {
    "path": "crates/forge/tests/fixtures/backtraces/MultipleLibraryConsumer.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./libraries/MultipleLibraries.sol\";\n\n/// @title MultipleLibraryConsumer - A contract that uses multiple libraries from the same file\ncontract MultipleLibraryConsumer {\n    using FirstMathLib for uint256;\n    using SecondMathLib for uint256;\n    using ThirdMathLib for uint256;\n\n    uint256 public result;\n\n    /// @notice Test division from FirstMathLib\n    function useFirstLib(uint256 a, uint256 b) public returns (uint256) {\n        result = a.divide(b); // Should show FirstMathLib in backtrace\n        return result;\n    }\n\n    /// @notice Test subtraction from SecondMathLib\n    function useSecondLib(uint256 a, uint256 b) public returns (uint256) {\n        result = a.subtract(b); // Should show SecondMathLib in backtrace\n        return result;\n    }\n\n    /// @notice Test modulo from ThirdMathLib\n    function useThirdLib(uint256 a, uint256 b) public returns (uint256) {\n        result = a.modulo(b); // Should show ThirdMathLib in backtrace\n        return result;\n    }\n\n    /// @notice Complex calculation using all three libraries\n    function useAllLibraries(uint256 a, uint256 b, uint256 c) public returns (uint256) {\n        uint256 step1 = a.divide(b); // FirstMathLib\n        uint256 step2 = step1.add(c); // SecondMathLib\n        result = step2.modulo(10); // ThirdMathLib\n        return result;\n    }\n}\n"
  },
  {
    "path": "crates/forge/tests/fixtures/backtraces/NestedCalls.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/// @title NestedCalls - Testing nested call stack traces\ncontract NestedCalls {\n    uint256 public depth;\n\n    function nestedCall(uint256 maxDepth) public {\n        depth++;\n        if (depth >= maxDepth) {\n            revert(\"Maximum depth reached\");\n        }\n        this.nestedCall(maxDepth);\n    }\n\n    function callChain1() public pure {\n        callChain2();\n    }\n\n    function callChain2() internal pure {\n        callChain3();\n    }\n\n    function callChain3() internal pure {\n        revert(\"Failed at chain level 3\");\n    }\n}\n"
  },
  {
    "path": "crates/forge/tests/fixtures/backtraces/SimpleRevert.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/// @title SimpleRevert - Basic revert testing contract\ncontract SimpleRevert {\n    function doRevert(string memory reason) public pure {\n        revert(reason);\n    }\n\n    function doRequire(uint256 value) public pure {\n        require(value > 0, \"Value must be greater than zero\");\n    }\n\n    function doAssert() public pure {\n        assert(false);\n    }\n\n    error CustomError(uint256 code, address sender);\n\n    function doCustomError() public view {\n        revert CustomError(42, msg.sender);\n    }\n}\n"
  },
  {
    "path": "crates/forge/tests/fixtures/backtraces/StaticCall.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/// @title StaticCall - Testing static call traces\ncontract StaticTarget {\n    function viewFail() public pure {\n        revert(\"Static call failed\");\n    }\n\n    function compute(uint256 value) public pure returns (uint256) {\n        require(value > 0, \"Value must be positive\");\n        return value * 2;\n    }\n}\n\ncontract StaticCaller {\n    address public target;\n\n    constructor(address _target) {\n        target = _target;\n    }\n\n    function staticCallFail() public view {\n        (bool success,) = target.staticcall(abi.encodeWithSignature(\"viewFail()\"));\n        require(success, \"Static call reverted\");\n    }\n\n    function staticCompute(uint256 value) public view returns (uint256) {\n        (bool success, bytes memory data) = target.staticcall(abi.encodeWithSignature(\"compute(uint256)\", value));\n        require(success, \"Static compute failed\");\n        return abi.decode(data, (uint256));\n    }\n}\n"
  },
  {
    "path": "crates/forge/tests/fixtures/backtraces/libraries/ExternalMathLib.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/// @title ExternalMathLib - A library with external functions that needs separate deployment\nlibrary ExternalMathLib {\n    error DivisionByZero();\n    error Overflow();\n    error Underflow();\n\n    /// @notice External division function\n    function div(uint256 a, uint256 b) external pure returns (uint256) {\n        if (b == 0) revert DivisionByZero();\n        return a / b;\n    }\n\n    /// @notice External multiplication with overflow check\n    function mul(uint256 a, uint256 b) external pure returns (uint256) {\n        if (a == 0) return 0;\n        uint256 c = a * b;\n        if (c / a != b) revert Overflow();\n        return c;\n    }\n\n    /// @notice External subtraction with underflow check\n    function sub(uint256 a, uint256 b) external pure returns (uint256) {\n        if (b > a) revert Underflow();\n        return a - b;\n    }\n\n    /// @notice External function with require statement\n    function requirePositive(uint256 value) external pure returns (uint256) {\n        require(value > 0, \"ExternalMathLib: value must be positive\");\n        return value * 2;\n    }\n}\n"
  },
  {
    "path": "crates/forge/tests/fixtures/backtraces/libraries/InternalMathLib.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/// @title InternalMathLib - A library with internal functions that gets inlined\nlibrary InternalMathLib {\n    error DivisionByZero();\n    error Overflow();\n    error Underflow();\n\n    /// @notice Internal division function\n    function div(uint256 a, uint256 b) internal pure returns (uint256) {\n        if (b == 0) revert DivisionByZero();\n        return a / b;\n    }\n\n    /// @notice Internal multiplication with overflow check\n    function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n        if (a == 0) return 0;\n        uint256 c = a * b;\n        if (c / a != b) revert Overflow();\n        return c;\n    }\n\n    /// @notice Internal subtraction with underflow check\n    function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n        if (b > a) revert Underflow();\n        return a - b;\n    }\n\n    /// @notice Internal function with require statement\n    function requirePositive(uint256 value) internal pure returns (uint256) {\n        require(value > 0, \"InternalMathLib: value must be positive\");\n        return value * 2;\n    }\n}\n"
  },
  {
    "path": "crates/forge/tests/fixtures/backtraces/libraries/MultipleLibraries.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/// @title FirstMathLib - First library in the file\nlibrary FirstMathLib {\n    error FirstLibError();\n\n    function divide(uint256 a, uint256 b) internal pure returns (uint256) {\n        if (b == 0) {\n            revert FirstLibError();\n        }\n        return a / b;\n    }\n\n    function multiply(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a * b;\n    }\n}\n\n/// @title SecondMathLib - Second library in the same file\nlibrary SecondMathLib {\n    error SecondLibError();\n\n    function subtract(uint256 a, uint256 b) internal pure returns (uint256) {\n        if (b > a) {\n            revert SecondLibError();\n        }\n        return a - b;\n    }\n\n    function add(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a + b;\n    }\n}\n\n/// @title ThirdMathLib - Third library in the same file\nlibrary ThirdMathLib {\n    error ThirdLibError();\n\n    function modulo(uint256 a, uint256 b) internal pure returns (uint256) {\n        if (b == 0) {\n            revert ThirdLibError();\n        }\n        return a % b;\n    }\n\n    function power(uint256 base, uint256 exp) internal pure returns (uint256) {\n        uint256 result = 1;\n        for (uint256 i = 0; i < exp; i++) {\n            result *= base;\n        }\n        return result;\n    }\n}\n"
  },
  {
    "path": "crates/forge/tests/ui.rs",
    "content": "use foundry_test_utils::ui_runner;\nuse std::{env, path::Path};\n\nconst FORGE_CMD: &str = env!(\"CARGO_BIN_EXE_forge\");\nconst FORGE_DIR: &str = env!(\"CARGO_MANIFEST_DIR\");\n\nfn main() -> impl std::process::Termination {\n    let forge_cmd = Path::new(FORGE_CMD);\n    let forge_dir = Path::new(FORGE_DIR);\n    let lint_testdata = forge_dir.parent().unwrap().join(\"lint\").join(\"testdata\");\n\n    ui_runner::run_tests(\"lint\", forge_cmd, &lint_testdata)\n}\n"
  },
  {
    "path": "crates/linking/Cargo.toml",
    "content": "[package]\nname = \"foundry-linking\"\ndescription = \"Smart contract linking tools\"\n\nversion.workspace = true\nedition.workspace = true\nrust-version.workspace = true\nauthors.workspace = true\nlicense.workspace = true\nhomepage.workspace = true\nrepository.workspace = true\n\n[lints]\nworkspace = true\n\n[dependencies]\nfoundry-compilers.workspace = true\n\nalloy-primitives = { workspace = true, features = [\"rlp\"] }\n\nrayon.workspace = true\nsemver.workspace = true\nthiserror.workspace = true\n"
  },
  {
    "path": "crates/linking/src/lib.rs",
    "content": "//! # foundry-linking\n//!\n//! EVM bytecode linker.\n\n#![cfg_attr(not(test), warn(unused_crate_dependencies))]\n#![cfg_attr(docsrs, feature(doc_cfg))]\n\nuse alloy_primitives::{Address, B256, Bytes};\nuse foundry_compilers::{\n    Artifact, ArtifactId,\n    artifacts::{CompactBytecode, CompactContractBytecodeCow, Libraries},\n    contracts::ArtifactContracts,\n};\nuse rayon::prelude::*;\nuse semver::Version;\nuse std::{\n    collections::{BTreeMap, BTreeSet},\n    path::{Path, PathBuf},\n    str::FromStr,\n};\n\n/// Errors that can occur during linking.\n#[derive(Debug, thiserror::Error)]\npub enum LinkerError {\n    #[error(\"wasn't able to find artifact for library {name} at {file}\")]\n    MissingLibraryArtifact { file: String, name: String },\n    #[error(\"target artifact is not present in provided artifacts set\")]\n    MissingTargetArtifact,\n    #[error(transparent)]\n    InvalidAddress(<Address as std::str::FromStr>::Err),\n    #[error(\"cyclic dependency found, can't link libraries via CREATE2\")]\n    CyclicDependency,\n    #[error(\"failed linking {artifact}\")]\n    LinkingFailed { artifact: String },\n}\n\npub struct Linker<'a> {\n    /// Root of the project, used to determine whether artifact/library path can be stripped.\n    pub root: PathBuf,\n    /// Compilation artifacts.\n    pub contracts: ArtifactContracts<CompactContractBytecodeCow<'a>>,\n}\n\n/// Output of the `link_with_nonce_or_address`\npub struct LinkOutput {\n    /// Resolved library addresses. Contains both user-provided and newly deployed libraries.\n    /// It will always contain library paths with stripped path prefixes.\n    pub libraries: Libraries,\n    /// Vector of libraries that need to be deployed from sender address.\n    /// The order in which they appear in the vector is the order in which they should be deployed.\n    pub libs_to_deploy: Vec<Bytes>,\n}\n\nimpl<'a> Linker<'a> {\n    pub fn new(\n        root: impl Into<PathBuf>,\n        contracts: ArtifactContracts<CompactContractBytecodeCow<'a>>,\n    ) -> Self {\n        Linker { root: root.into(), contracts }\n    }\n\n    /// Helper method to convert [ArtifactId] to the format in which libraries are stored in\n    /// [Libraries] object.\n    ///\n    /// Strips project root path from source file path.\n    fn convert_artifact_id_to_lib_path(&self, id: &ArtifactId) -> (PathBuf, String) {\n        let path = id.source.strip_prefix(self.root.as_path()).unwrap_or(&id.source);\n        // name is either {LibName} or {LibName}.{version}\n        let name = id.name.split('.').next().unwrap();\n\n        (path.to_path_buf(), name.to_owned())\n    }\n\n    /// Finds an [ArtifactId] object in the given [ArtifactContracts] keys which corresponds to the\n    /// library path in the form of \"./path/to/Lib.sol:Lib\"\n    ///\n    /// Optionally accepts solc version, and if present, only compares artifacts with given version.\n    fn find_artifact_id_by_library_path(\n        &'a self,\n        file: &str,\n        name: &str,\n        version: Option<&Version>,\n    ) -> Option<&'a ArtifactId> {\n        for id in self.contracts.keys() {\n            if let Some(version) = version\n                && id.version != *version\n            {\n                continue;\n            }\n            let (artifact_path, artifact_name) = self.convert_artifact_id_to_lib_path(id);\n\n            if artifact_name == *name && artifact_path == Path::new(file) {\n                return Some(id);\n            }\n        }\n\n        None\n    }\n\n    /// Performs DFS on the graph of link references, and populates `deps` with all found libraries.\n    fn collect_dependencies(\n        &'a self,\n        target: &'a ArtifactId,\n        deps: &mut BTreeSet<&'a ArtifactId>,\n    ) -> Result<(), LinkerError> {\n        let contract = self.contracts.get(target).ok_or(LinkerError::MissingTargetArtifact)?;\n\n        let mut references: BTreeMap<String, BTreeSet<String>> = BTreeMap::new();\n        let mut extend = |bytecode: &CompactBytecode| {\n            for (file, libs) in &bytecode.link_references {\n                references.entry(file.clone()).or_default().extend(libs.keys().cloned());\n            }\n        };\n        if let Some(bytecode) = &contract.bytecode {\n            extend(bytecode);\n        }\n        if let Some(deployed_bytecode) = &contract.deployed_bytecode\n            && let Some(bytecode) = &deployed_bytecode.bytecode\n        {\n            extend(bytecode);\n        }\n\n        for (file, libs) in references {\n            for name in libs {\n                let id = self\n                    .find_artifact_id_by_library_path(&file, &name, Some(&target.version))\n                    .ok_or_else(|| LinkerError::MissingLibraryArtifact {\n                        file: file.clone(),\n                        name,\n                    })?;\n                if deps.insert(id) {\n                    self.collect_dependencies(id, deps)?;\n                }\n            }\n        }\n\n        Ok(())\n    }\n\n    /// Links given artifact with either given library addresses or address computed from sender and\n    /// nonce.\n    ///\n    /// Each key in `libraries` should either be a global path or relative to project root. All\n    /// remappings should be resolved.\n    ///\n    /// When calling for `target` being an external library itself, you should check that `target`\n    /// does not appear in `libs_to_deploy` to avoid deploying it twice. It may happen in cases\n    /// when there is a dependency cycle including `target`.\n    pub fn link_with_nonce_or_address(\n        &'a self,\n        libraries: Libraries,\n        sender: Address,\n        mut nonce: u64,\n        targets: impl IntoIterator<Item = &'a ArtifactId>,\n    ) -> Result<LinkOutput, LinkerError> {\n        // Library paths in `link_references` keys are always stripped, so we have to strip\n        // user-provided paths to be able to match them correctly.\n        let mut libraries = libraries.with_stripped_file_prefixes(self.root.as_path());\n\n        let mut needed_libraries = BTreeSet::new();\n        for target in targets {\n            self.collect_dependencies(target, &mut needed_libraries)?;\n        }\n\n        let mut libs_to_deploy = Vec::new();\n\n        // If `libraries` does not contain needed dependency, compute its address and add to\n        // `libs_to_deploy`.\n        for id in needed_libraries {\n            let (lib_path, lib_name) = self.convert_artifact_id_to_lib_path(id);\n\n            libraries.libs.entry(lib_path).or_default().entry(lib_name).or_insert_with(|| {\n                let address = sender.create(nonce);\n                libs_to_deploy.push((id, address));\n                nonce += 1;\n\n                address.to_checksum(None)\n            });\n        }\n\n        // Link and collect bytecodes for `libs_to_deploy`.\n        let libs_to_deploy = libs_to_deploy\n            .into_par_iter()\n            .map(|(id, _)| {\n                Ok(self.link(id, &libraries)?.get_bytecode_bytes().unwrap().into_owned())\n            })\n            .collect::<Result<Vec<_>, LinkerError>>()?;\n\n        Ok(LinkOutput { libraries, libs_to_deploy })\n    }\n\n    pub fn link_with_create2(\n        &'a self,\n        libraries: Libraries,\n        sender: Address,\n        salt: B256,\n        target: &'a ArtifactId,\n    ) -> Result<LinkOutput, LinkerError> {\n        // Library paths in `link_references` keys are always stripped, so we have to strip\n        // user-provided paths to be able to match them correctly.\n        let mut libraries = libraries.with_stripped_file_prefixes(self.root.as_path());\n\n        let mut needed_libraries = BTreeSet::new();\n        self.collect_dependencies(target, &mut needed_libraries)?;\n\n        let mut needed_libraries = needed_libraries\n            .into_par_iter()\n            .filter(|id| {\n                // Filter out already provided libraries.\n                let (file, name) = self.convert_artifact_id_to_lib_path(id);\n                libraries.libs.get(&file).is_none_or(|lib| !lib.contains_key(&name))\n            })\n            .map(|id| {\n                // Link library with provided libs and extract bytecode object (possibly unlinked).\n                let bytecode = self.link(id, &libraries).unwrap().bytecode.unwrap();\n                (id, bytecode)\n            })\n            .collect::<Vec<_>>();\n\n        let mut libs_to_deploy = Vec::new();\n\n        // Iteratively compute addresses and link libraries until we have no unlinked libraries\n        // left.\n        while !needed_libraries.is_empty() {\n            // Find any library which is fully linked.\n            let deployable = needed_libraries\n                .iter()\n                .enumerate()\n                .find(|(_, (_, bytecode))| !bytecode.object.is_unlinked());\n\n            // If we haven't found any deployable library, it means we have a cyclic dependency.\n            let Some((index, &(id, _))) = deployable else {\n                return Err(LinkerError::CyclicDependency);\n            };\n            let (_, bytecode) = needed_libraries.swap_remove(index);\n            let code = bytecode.bytes().unwrap();\n            let address = sender.create2_from_code(salt, code);\n            libs_to_deploy.push(code.clone());\n\n            let (file, name) = self.convert_artifact_id_to_lib_path(id);\n\n            needed_libraries.par_iter_mut().for_each(|(_, bytecode)| {\n                bytecode.to_mut().link(&file.to_string_lossy(), &name, address);\n            });\n\n            libraries.libs.entry(file).or_default().insert(name, address.to_checksum(None));\n        }\n\n        Ok(LinkOutput { libraries, libs_to_deploy })\n    }\n\n    /// Links given artifact with given libraries.\n    pub fn link(\n        &self,\n        target: &ArtifactId,\n        libraries: &Libraries,\n    ) -> Result<CompactContractBytecodeCow<'a>, LinkerError> {\n        let mut contract =\n            self.contracts.get(target).ok_or(LinkerError::MissingTargetArtifact)?.clone();\n        for (file, libs) in &libraries.libs {\n            for (name, address) in libs {\n                let address = Address::from_str(address).map_err(LinkerError::InvalidAddress)?;\n                if let Some(bytecode) = contract.bytecode.as_mut() {\n                    bytecode.to_mut().link(&file.to_string_lossy(), name, address);\n                }\n                if let Some(deployed_bytecode) =\n                    contract.deployed_bytecode.as_mut().and_then(|b| b.to_mut().bytecode.as_mut())\n                {\n                    deployed_bytecode.link(&file.to_string_lossy(), name, address);\n                }\n            }\n        }\n        Ok(contract)\n    }\n\n    /// Ensures that both initial and deployed bytecode are linked.\n    pub fn ensure_linked(\n        &self,\n        contract: &CompactContractBytecodeCow<'a>,\n        target: &ArtifactId,\n    ) -> Result<(), LinkerError> {\n        if let Some(bytecode) = &contract.bytecode\n            && bytecode.object.is_unlinked()\n        {\n            return Err(LinkerError::LinkingFailed {\n                artifact: target.source.to_string_lossy().into(),\n            });\n        }\n        if let Some(deployed_bytecode) = &contract.deployed_bytecode\n            && let Some(deployed_bytecode_obj) = &deployed_bytecode.bytecode\n            && deployed_bytecode_obj.object.is_unlinked()\n        {\n            return Err(LinkerError::LinkingFailed {\n                artifact: target.source.to_string_lossy().into(),\n            });\n        }\n        Ok(())\n    }\n\n    pub fn get_linked_artifacts(\n        &self,\n        libraries: &Libraries,\n    ) -> Result<ArtifactContracts, LinkerError> {\n        self.get_linked_artifacts_cow(libraries).map(ArtifactContracts::from_iter)\n    }\n\n    pub fn get_linked_artifacts_cow(\n        &self,\n        libraries: &Libraries,\n    ) -> Result<ArtifactContracts<CompactContractBytecodeCow<'a>>, LinkerError> {\n        self.contracts\n            .par_iter()\n            .map(|(id, _)| Ok((id.clone(), self.link(id, libraries)?)))\n            .collect::<Result<_, _>>()\n            .map(ArtifactContracts)\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use alloy_primitives::{address, fixed_bytes, map::HashMap};\n    use foundry_compilers::{\n        Project, ProjectCompileOutput, ProjectPathsConfig,\n        multi::MultiCompiler,\n        solc::{Solc, SolcCompiler},\n    };\n    use std::sync::OnceLock;\n\n    fn testdata() -> &'static Path {\n        static CACHE: OnceLock<PathBuf> = OnceLock::new();\n        CACHE.get_or_init(|| {\n            PathBuf::from(env!(\"CARGO_MANIFEST_DIR\")).join(\"../../testdata\").canonicalize().unwrap()\n        })\n    }\n\n    #[must_use]\n    struct LinkerTest {\n        project: Project,\n        output: ProjectCompileOutput,\n        dependency_assertions: HashMap<&'static str, Vec<(&'static str, Address)>>,\n    }\n\n    impl LinkerTest {\n        fn new(path: &Path, strip_prefixes: bool) -> Self {\n            assert!(path.exists(), \"Path {path:?} does not exist\");\n            let paths = ProjectPathsConfig::builder()\n                .root(testdata())\n                .lib(testdata().join(\"lib\"))\n                .sources(path)\n                .tests(path)\n                .build()\n                .unwrap();\n\n            let solc = Solc::find_or_install(&Version::new(0, 8, 18)).unwrap();\n            let project = Project::builder()\n                .paths(paths)\n                .ephemeral()\n                .no_artifacts()\n                .build(MultiCompiler { solc: Some(SolcCompiler::Specific(solc)), vyper: None })\n                .unwrap();\n\n            let mut output = project.compile().unwrap();\n\n            if strip_prefixes {\n                output = output.with_stripped_file_prefixes(project.root());\n            }\n\n            Self { project, output, dependency_assertions: HashMap::default() }\n        }\n\n        fn assert_dependencies(\n            mut self,\n            artifact_id: &'static str,\n            deps: &[(&'static str, Address)],\n        ) -> Self {\n            self.dependency_assertions.insert(artifact_id, deps.to_vec());\n            self\n        }\n\n        fn test_with_sender_and_nonce(self, sender: Address, initial_nonce: u64) {\n            let linker = Linker::new(self.project.root(), self.output.artifact_ids().collect());\n            for (id, identifier) in self.iter_linking_targets(&linker) {\n                let output = linker\n                    .link_with_nonce_or_address(Default::default(), sender, initial_nonce, [id])\n                    .expect(\"Linking failed\");\n                self.validate_assertions(identifier, output);\n            }\n        }\n\n        fn test_with_create2(self, sender: Address, salt: B256) {\n            let linker = Linker::new(self.project.root(), self.output.artifact_ids().collect());\n            for (id, identifier) in self.iter_linking_targets(&linker) {\n                let output = linker\n                    .link_with_create2(Default::default(), sender, salt, id)\n                    .expect(\"Linking failed\");\n                self.validate_assertions(identifier, output);\n            }\n        }\n\n        fn iter_linking_targets<'a>(\n            &'a self,\n            linker: &'a Linker<'_>,\n        ) -> impl Iterator<Item = (&'a ArtifactId, String)> + 'a {\n            self.sanity_check(linker);\n            linker.contracts.keys().filter_map(move |id| {\n                // If we didn't strip paths, artifacts will have absolute paths.\n                // That's expected and we want to ensure that only `libraries` object has relative\n                // paths, artifacts should be kept as is.\n                let source = id\n                    .source\n                    .strip_prefix(self.project.root())\n                    .unwrap_or(&id.source)\n                    .to_string_lossy();\n                let identifier = format!(\"{source}:{}\", id.name);\n\n                // Skip test utils as they always have no dependencies.\n                if identifier.contains(\"utils/\") {\n                    return None;\n                }\n\n                Some((id, identifier))\n            })\n        }\n\n        fn sanity_check(&self, linker: &Linker<'_>) {\n            assert!(!self.dependency_assertions.is_empty(), \"Dependency assertions are empty\");\n            assert!(!linker.contracts.is_empty(), \"Linker contracts are empty\");\n        }\n\n        fn validate_assertions(&self, identifier: String, output: LinkOutput) {\n            let LinkOutput { libs_to_deploy, libraries } = output;\n\n            let assertions = self\n                .dependency_assertions\n                .get(identifier.as_str())\n                .unwrap_or_else(|| panic!(\"Unexpected artifact: {identifier}\"));\n\n            assert_eq!(\n                libs_to_deploy.len(),\n                assertions.len(),\n                \"artifact {identifier} has more/less dependencies than expected ({} vs {}): {:#?}\",\n                libs_to_deploy.len(),\n                assertions.len(),\n                libs_to_deploy\n            );\n\n            for &(dep_identifier, address) in assertions {\n                let (file, name) = dep_identifier.split_once(':').unwrap();\n                if let Some(lib_address) =\n                    libraries.libs.get(Path::new(file)).and_then(|libs| libs.get(name))\n                {\n                    assert_eq!(\n                        lib_address.parse::<Address>().unwrap(),\n                        address,\n                        \"incorrect library address for dependency {dep_identifier} of {identifier}\"\n                    );\n                } else {\n                    panic!(\"Library {dep_identifier} not found\");\n                }\n            }\n        }\n    }\n\n    fn link_test(path: impl AsRef<Path>, mut test_fn: impl FnMut(LinkerTest)) {\n        fn link_test(path: &Path, test_fn: &mut dyn FnMut(LinkerTest)) {\n            test_fn(LinkerTest::new(path, true));\n            test_fn(LinkerTest::new(path, false));\n        }\n        link_test(path.as_ref(), &mut test_fn);\n    }\n\n    #[test]\n    #[should_panic = \"assertions are empty\"]\n    fn no_assertions() {\n        link_test(testdata().join(\"default/linking/simple\"), |linker| {\n            linker.test_with_sender_and_nonce(Address::default(), 1);\n        });\n    }\n\n    #[test]\n    #[should_panic = \"does not exist\"]\n    fn unknown_path() {\n        link_test(\"doesnotexist\", |linker| {\n            linker\n                .assert_dependencies(\"a:b\", &[])\n                .test_with_sender_and_nonce(Address::default(), 1);\n        });\n    }\n\n    #[test]\n    fn link_simple() {\n        link_test(testdata().join(\"default/linking/simple\"), |linker| {\n            linker\n                .assert_dependencies(\"default/linking/simple/Simple.t.sol:Lib\", &[])\n                .assert_dependencies(\n                    \"default/linking/simple/Simple.t.sol:LibraryConsumer\",\n                    &[(\n                        \"default/linking/simple/Simple.t.sol:Lib\",\n                        address!(\"0x5a443704dd4b594b382c22a083e2bd3090a6fef3\"),\n                    )],\n                )\n                .assert_dependencies(\n                    \"default/linking/simple/Simple.t.sol:SimpleLibraryLinkingTest\",\n                    &[(\n                        \"default/linking/simple/Simple.t.sol:Lib\",\n                        address!(\"0x5a443704dd4b594b382c22a083e2bd3090a6fef3\"),\n                    )],\n                )\n                .test_with_sender_and_nonce(Address::default(), 1);\n        });\n    }\n\n    #[test]\n    fn link_nested() {\n        link_test(testdata().join(\"default/linking/nested\"), |linker| {\n            linker\n                .assert_dependencies(\"default/linking/nested/Nested.t.sol:Lib\", &[])\n                .assert_dependencies(\n                    \"default/linking/nested/Nested.t.sol:NestedLib\",\n                    &[(\n                        \"default/linking/nested/Nested.t.sol:Lib\",\n                        address!(\"0x5a443704dd4b594b382c22a083e2bd3090a6fef3\"),\n                    )],\n                )\n                .assert_dependencies(\n                    \"default/linking/nested/Nested.t.sol:LibraryConsumer\",\n                    &[\n                        // Lib shows up here twice, because the linker sees it twice, but it should\n                        // have the same address and nonce.\n                        (\n                            \"default/linking/nested/Nested.t.sol:Lib\",\n                            Address::from_str(\"0x5a443704dd4b594b382c22a083e2bd3090a6fef3\")\n                                .unwrap(),\n                        ),\n                        (\n                            \"default/linking/nested/Nested.t.sol:NestedLib\",\n                            Address::from_str(\"0x47e9Fbef8C83A1714F1951F142132E6e90F5fa5D\")\n                                .unwrap(),\n                        ),\n                    ],\n                )\n                .assert_dependencies(\n                    \"default/linking/nested/Nested.t.sol:NestedLibraryLinkingTest\",\n                    &[\n                        (\n                            \"default/linking/nested/Nested.t.sol:Lib\",\n                            Address::from_str(\"0x5a443704dd4b594b382c22a083e2bd3090a6fef3\")\n                                .unwrap(),\n                        ),\n                        (\n                            \"default/linking/nested/Nested.t.sol:NestedLib\",\n                            Address::from_str(\"0x47e9fbef8c83a1714f1951f142132e6e90f5fa5d\")\n                                .unwrap(),\n                        ),\n                    ],\n                )\n                .test_with_sender_and_nonce(Address::default(), 1);\n        });\n    }\n\n    #[test]\n    fn link_duplicate() {\n        link_test(testdata().join(\"default/linking/duplicate\"), |linker| {\n            linker\n                .assert_dependencies(\"default/linking/duplicate/Duplicate.t.sol:A\", &[])\n                .assert_dependencies(\"default/linking/duplicate/Duplicate.t.sol:B\", &[])\n                .assert_dependencies(\n                    \"default/linking/duplicate/Duplicate.t.sol:C\",\n                    &[(\n                        \"default/linking/duplicate/Duplicate.t.sol:A\",\n                        address!(\"0x5a443704dd4b594b382c22a083e2bd3090a6fef3\"),\n                    )],\n                )\n                .assert_dependencies(\n                    \"default/linking/duplicate/Duplicate.t.sol:D\",\n                    &[(\n                        \"default/linking/duplicate/Duplicate.t.sol:B\",\n                        address!(\"0x5a443704dd4b594b382c22a083e2bd3090a6fef3\"),\n                    )],\n                )\n                .assert_dependencies(\n                    \"default/linking/duplicate/Duplicate.t.sol:E\",\n                    &[\n                        (\n                            \"default/linking/duplicate/Duplicate.t.sol:A\",\n                            Address::from_str(\"0x5a443704dd4b594b382c22a083e2bd3090a6fef3\")\n                                .unwrap(),\n                        ),\n                        (\n                            \"default/linking/duplicate/Duplicate.t.sol:C\",\n                            Address::from_str(\"0x47e9fbef8c83a1714f1951f142132e6e90f5fa5d\")\n                                .unwrap(),\n                        ),\n                    ],\n                )\n                .assert_dependencies(\n                    \"default/linking/duplicate/Duplicate.t.sol:LibraryConsumer\",\n                    &[\n                        (\n                            \"default/linking/duplicate/Duplicate.t.sol:A\",\n                            Address::from_str(\"0x5a443704dd4b594b382c22a083e2bd3090a6fef3\")\n                                .unwrap(),\n                        ),\n                        (\n                            \"default/linking/duplicate/Duplicate.t.sol:B\",\n                            Address::from_str(\"0x47e9fbef8c83a1714f1951f142132e6e90f5fa5d\")\n                                .unwrap(),\n                        ),\n                        (\n                            \"default/linking/duplicate/Duplicate.t.sol:C\",\n                            Address::from_str(\"0x8be503bcded90ed42eff31f56199399b2b0154ca\")\n                                .unwrap(),\n                        ),\n                        (\n                            \"default/linking/duplicate/Duplicate.t.sol:D\",\n                            Address::from_str(\"0x47c5e40890bce4a473a49d7501808b9633f29782\")\n                                .unwrap(),\n                        ),\n                        (\n                            \"default/linking/duplicate/Duplicate.t.sol:E\",\n                            Address::from_str(\"0x29b2440db4a256b0c1e6d3b4cdcaa68e2440a08f\")\n                                .unwrap(),\n                        ),\n                    ],\n                )\n                .assert_dependencies(\n                    \"default/linking/duplicate/Duplicate.t.sol:DuplicateLibraryLinkingTest\",\n                    &[\n                        (\n                            \"default/linking/duplicate/Duplicate.t.sol:A\",\n                            Address::from_str(\"0x5a443704dd4b594b382c22a083e2bd3090a6fef3\")\n                                .unwrap(),\n                        ),\n                        (\n                            \"default/linking/duplicate/Duplicate.t.sol:B\",\n                            Address::from_str(\"0x47e9fbef8c83a1714f1951f142132e6e90f5fa5d\")\n                                .unwrap(),\n                        ),\n                        (\n                            \"default/linking/duplicate/Duplicate.t.sol:C\",\n                            Address::from_str(\"0x8be503bcded90ed42eff31f56199399b2b0154ca\")\n                                .unwrap(),\n                        ),\n                        (\n                            \"default/linking/duplicate/Duplicate.t.sol:D\",\n                            Address::from_str(\"0x47c5e40890bce4a473a49d7501808b9633f29782\")\n                                .unwrap(),\n                        ),\n                        (\n                            \"default/linking/duplicate/Duplicate.t.sol:E\",\n                            Address::from_str(\"0x29b2440db4a256b0c1e6d3b4cdcaa68e2440a08f\")\n                                .unwrap(),\n                        ),\n                    ],\n                )\n                .test_with_sender_and_nonce(Address::default(), 1);\n        });\n    }\n\n    #[test]\n    fn link_cycle() {\n        link_test(testdata().join(\"default/linking/cycle\"), |linker| {\n            linker\n                .assert_dependencies(\n                    \"default/linking/cycle/Cycle.t.sol:Foo\",\n                    &[\n                        (\n                            \"default/linking/cycle/Cycle.t.sol:Foo\",\n                            Address::from_str(\"0x47e9Fbef8C83A1714F1951F142132E6e90F5fa5D\")\n                                .unwrap(),\n                        ),\n                        (\n                            \"default/linking/cycle/Cycle.t.sol:Bar\",\n                            Address::from_str(\"0x5a443704dd4B594B382c22a083e2BD3090A6feF3\")\n                                .unwrap(),\n                        ),\n                    ],\n                )\n                .assert_dependencies(\n                    \"default/linking/cycle/Cycle.t.sol:Bar\",\n                    &[\n                        (\n                            \"default/linking/cycle/Cycle.t.sol:Foo\",\n                            Address::from_str(\"0x47e9Fbef8C83A1714F1951F142132E6e90F5fa5D\")\n                                .unwrap(),\n                        ),\n                        (\n                            \"default/linking/cycle/Cycle.t.sol:Bar\",\n                            Address::from_str(\"0x5a443704dd4B594B382c22a083e2BD3090A6feF3\")\n                                .unwrap(),\n                        ),\n                    ],\n                )\n                .test_with_sender_and_nonce(Address::default(), 1);\n        });\n    }\n\n    #[test]\n    #[ignore = \"addresses depend on testdata utils internals for some reason\"]\n    fn link_create2_nested() {\n        link_test(testdata().join(\"default/linking/nested\"), |linker| {\n            linker\n                .assert_dependencies(\"default/linking/nested/Nested.t.sol:Lib\", &[])\n                .assert_dependencies(\n                    \"default/linking/nested/Nested.t.sol:NestedLib\",\n                    &[(\n                        \"default/linking/nested/Nested.t.sol:Lib\",\n                        address!(\"0x773253227cce756e50c3993ec6366b3ec27786f9\"),\n                    )],\n                )\n                .assert_dependencies(\n                    \"default/linking/nested/Nested.t.sol:LibraryConsumer\",\n                    &[\n                        // Lib shows up here twice, because the linker sees it twice, but it should\n                        // have the same address and nonce.\n                        (\n                            \"default/linking/nested/Nested.t.sol:Lib\",\n                            Address::from_str(\"0x773253227cce756e50c3993ec6366b3ec27786f9\")\n                                .unwrap(),\n                        ),\n                        (\n                            \"default/linking/nested/Nested.t.sol:NestedLib\",\n                            Address::from_str(\"0xac231df03403867b05d092c26fc91b6b83f4bebe\")\n                                .unwrap(),\n                        ),\n                    ],\n                )\n                .assert_dependencies(\n                    \"default/linking/nested/Nested.t.sol:NestedLibraryLinkingTest\",\n                    &[\n                        (\n                            \"default/linking/nested/Nested.t.sol:Lib\",\n                            Address::from_str(\"0x773253227cce756e50c3993ec6366b3ec27786f9\")\n                                .unwrap(),\n                        ),\n                        (\n                            \"default/linking/nested/Nested.t.sol:NestedLib\",\n                            Address::from_str(\"0xac231df03403867b05d092c26fc91b6b83f4bebe\")\n                                .unwrap(),\n                        ),\n                    ],\n                )\n                .test_with_create2(\n                    Address::default(),\n                    fixed_bytes!(\n                        \"19bf59b7b67ae8edcbc6e53616080f61fa99285c061450ad601b0bc40c9adfc9\"\n                    ),\n                );\n        });\n    }\n\n    #[test]\n    fn link_samefile_union() {\n        link_test(testdata().join(\"default/linking/samefile_union\"), |linker| {\n            linker\n                .assert_dependencies(\"default/linking/samefile_union/Libs.sol:LInit\", &[])\n                .assert_dependencies(\"default/linking/samefile_union/Libs.sol:LRun\", &[])\n                .assert_dependencies(\n                    \"default/linking/samefile_union/SameFileUnion.t.sol:UsesBoth\",\n                    &[\n                        (\n                            \"default/linking/samefile_union/Libs.sol:LInit\",\n                            Address::from_str(\"0x5a443704dd4b594b382c22a083e2bd3090a6fef3\")\n                                .unwrap(),\n                        ),\n                        (\n                            \"default/linking/samefile_union/Libs.sol:LRun\",\n                            Address::from_str(\"0x47e9fbef8c83a1714f1951f142132e6e90f5fa5d\")\n                                .unwrap(),\n                        ),\n                    ],\n                )\n                .test_with_sender_and_nonce(Address::default(), 1);\n        });\n    }\n\n    #[test]\n    fn linking_failure() {\n        let linker = LinkerTest::new(&testdata().join(\"default/linking/simple\"), true);\n        let linker_instance =\n            Linker::new(linker.project.root(), linker.output.artifact_ids().collect());\n\n        // Create a libraries object with an incorrect library name that won't match any references\n        let mut libraries = Libraries::default();\n        libraries.libs.entry(\"default/linking/simple/Simple.t.sol\".into()).or_default().insert(\n            \"NonExistentLib\".to_string(),\n            \"0x5a443704dd4b594b382c22a083e2bd3090a6fef3\".to_string(),\n        );\n\n        // Try to link the LibraryConsumer contract with incorrect library\n        let artifact_id = linker_instance\n            .contracts\n            .keys()\n            .find(|id| id.name == \"LibraryConsumer\")\n            .expect(\"LibraryConsumer contract not found\");\n\n        let contract = linker_instance.contracts.get(artifact_id).unwrap();\n\n        // Verify that the artifact has unlinked bytecode\n        assert!(\n            linker_instance.ensure_linked(contract, artifact_id).is_err(),\n            \"Expected artifact to have unlinked bytecode\"\n        );\n    }\n}\n"
  },
  {
    "path": "crates/lint/Cargo.toml",
    "content": "[package]\nname = \"forge-lint\"\n\nversion.workspace = true\nedition.workspace = true\nrust-version.workspace = true\nauthors.workspace = true\nlicense.workspace = true\nhomepage.workspace = true\nrepository.workspace = true\n\n[lints]\nworkspace = true\n\n[dependencies]\n# lib\nfoundry-common.workspace = true\nfoundry-compilers.workspace = true\nfoundry-config.workspace = true\n\nsolar.workspace = true\n\neyre.workspace = true\nheck.workspace = true\nrayon.workspace = true\nthiserror.workspace = true\n"
  },
  {
    "path": "crates/lint/README.md",
    "content": "# Linter (`lint`)\n\nSolidity linter for identifying potential errors, vulnerabilities, gas optimizations, and style guide violations.\nIt helps enforce best practices and improve code quality within Foundry projects.\n\n## Supported Lints\n\n`forge-lint` includes rules across several categories:\n\n- **High Severity:**\n  - `incorrect-shift`: Warns against shift operations where operands might be in the wrong order.\n  - `unchecked-call`: Low-level calls should check the success return value.\n  - `erc20-unchecked-transfer`: ERC20 `transfer` and `transferFrom` calls should check the return value.\n- **Medium Severity:**\n  - `divide-before-multiply`: Warns against performing division before multiplication in the same expression, which can cause precision loss.\n  - `unsafe-typecast`: Typecasts that can truncate values should be checked.\n- **Informational / Style Guide:**\n  - `pascal-case-struct`: Flags for struct names not adhering to `PascalCase`.\n  - `mixed-case-function`: Flags for function names not adhering to `mixedCase`.\n  - `mixed-case-variable`: Flags for mutable variable names not adhering to `mixedCase`.\n  - `screaming-snake-case-const`: Flags for `constant` variable names not adhering to `SCREAMING_SNAKE_CASE`.\n  - `screaming-snake-case-immutable`: Flags for `immutable` variable names not adhering to `SCREAMING_SNAKE_CASE`.\n  - `unused-import`: Unused imports should be removed.\n  - `unaliased-plain-import`: Use named imports `{A, B}` or alias `import \"..\" as X`.\n  - `named-struct-fields`: Prefer initializing structs with named fields.\n  - `unsafe-cheatcode`: Usage of unsafe cheatcodes that can perform dangerous operations.\n- **Gas Optimizations:**\n  - `asm-keccak256`: Recommends using inline assembly for `keccak256` for potential gas savings.\n  - `custom-errors`: Recommends using custom errors instead of strings and plain reverts for potential gas savings.\n- **Code Size:**\n  - `unwrapped-modifier-logic`: Recommends wrapping modifier logic to reduce contract code size.\n\n## Configuration\n\nThe behavior of the `SolidityLinter` can be customized with the following options:\n\n| Option              | Default | Description                                                                                                            |\n| ------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------- |\n| `with_severity`     | `None`  | Filters active lints by their severity (`High`, `Med`, `Low`, `Info`, `Gas`, `CodeSize`). `None` means all severities. |\n| `with_lints`        | `None`  | Specifies a list of `SolLint` instances to include. Overrides severity filter if a lint matches.                       |\n| `without_lints`     | `None`  | Specifies a list of `SolLint` instances to exclude, even if they match other criteria.                                 |\n| `with_description`  | `true`  | Whether to include the lint's description in the diagnostic output.                                                    |\n| `with_json_emitter` | `false` | If `true`, diagnostics are output in rustc-compatible JSON format; otherwise, human-readable text.                     |\n\n## Contributing\n\nCheck out the [foundry contribution guide](https://github.com/foundry-rs/foundry/blob/master/CONTRIBUTING.md).\n\nGuidelines for contributing to `forge lint`:\n\n### Opening an issue\n\n1. Create a short concise title describing an issue.\n   - Bad Title Examples\n     ```text\n     Forge lint does not work\n     Forge lint breaks\n     Forge lint unexpected behavior\n     ```\n   - Good Title Examples\n     ```text\n     Forge lint does not flag incorrect shift operations\n     ```\n2. Fill in the issue template fields that include foundry version, platform & component info.\n3. Provide the code snippets showing the current & expected behaviors.\n4. If it's a feature request, specify why this feature is needed.\n5. Besides the default label (`T-Bug` for bugs or `T-feature` for features), add `C-forge` and `Cmd-forge-fmt` labels.\n\n### Fixing A Bug\n\n1. Specify an issue that is being addressed in the PR description.\n2. Add a note on the solution in the PR description.\n3. Add a test case to `lint/testdata` that specifically demonstrates the bug and is fixed by your changes. Ensure all tests pass.\n\n### Developing a New Lint Rule\n\nCheck the [dev docs](../../docs/dev/lintrules.md) for a full implementation guide.\n\n"
  },
  {
    "path": "crates/lint/src/lib.rs",
    "content": "#![doc = include_str!(\"../README.md\")]\n#![cfg_attr(not(test), warn(unused_crate_dependencies))]\n#![cfg_attr(docsrs, feature(doc_cfg))]\n#![allow(elided_lifetimes_in_paths)]\n\npub mod linter;\npub mod sol;\n"
  },
  {
    "path": "crates/lint/src/linter/early.rs",
    "content": "use super::LintContext;\nuse solar::{\n    ast::{self as ast, visit::Visit},\n    interface::data_structures::Never,\n};\nuse std::ops::ControlFlow;\n\n/// Trait for lints that operate directly on the AST.\n/// Its methods mirror `ast::visit::Visit`, with the addition of `LintContext`.\npub trait EarlyLintPass<'ast>: Send + Sync {\n    fn check_expr(&mut self, _ctx: &LintContext, _expr: &'ast ast::Expr<'ast>) {}\n    fn check_item_struct(&mut self, _ctx: &LintContext, _struct: &'ast ast::ItemStruct<'ast>) {}\n    fn check_item_function(&mut self, _ctx: &LintContext, _func: &'ast ast::ItemFunction<'ast>) {}\n    fn check_variable_definition(\n        &mut self,\n        _ctx: &LintContext,\n        _var: &'ast ast::VariableDefinition<'ast>,\n    ) {\n    }\n    fn check_import_directive(\n        &mut self,\n        _ctx: &LintContext,\n        _import: &'ast ast::ImportDirective<'ast>,\n    ) {\n    }\n    fn check_using_directive(\n        &mut self,\n        _ctx: &LintContext,\n        _using: &'ast ast::UsingDirective<'ast>,\n    ) {\n    }\n    fn check_item_contract(\n        &mut self,\n        _ctx: &LintContext,\n        _contract: &'ast ast::ItemContract<'ast>,\n    ) {\n    }\n    fn check_doc_comment(&mut self, _ctx: &LintContext, _cmnt: &'ast ast::DocComment) {}\n    fn check_item(&mut self, _ctx: &LintContext, _item: &'ast ast::Item<'ast>) {}\n    fn check_stmt(&mut self, _ctx: &LintContext, _stmt: &'ast ast::Stmt<'ast>) {}\n    fn check_path(&mut self, _ctx: &LintContext, _path: &'ast ast::PathSlice) {}\n    fn check_ty(&mut self, _ctx: &LintContext, _ty: &'ast ast::Type<'ast>) {}\n\n    /// Should be called after the source unit has been visited. Enables lints that require\n    /// knowledge of the entire AST to perform their analysis.\n    ///\n    /// # Performance\n    ///\n    /// Since a full-AST analysis can be computationally expensive, implementations\n    /// should guard their logic by first checking if the relevant lint is enabled\n    /// using [`LintContext::is_lint_enabled`]. This avoids performing costly work\n    /// if the user has disabled the lint.\n    ///\n    /// ### Example\n    /// ```rust,ignore\n    /// fn check_full_source_unit(&mut self, ctx: &LintContext<'ast, '_>, ast: &'ast ast::SourceUnit<'ast>) {\n    ///     // Check if the lint is enabled before performing expensive work.\n    ///     if ctx.is_lint_enabled(MY_EXPENSIVE_LINT.id) {\n    ///         // ... perform computation and emit diagnostics ...\n    ///     }\n    /// }\n    /// ```\n    fn check_full_source_unit(\n        &mut self,\n        _ctx: &LintContext<'ast, '_>,\n        _ast: &'ast ast::SourceUnit<'ast>,\n    ) {\n    }\n}\n\n/// Visitor struct for `EarlyLintPass`es\npub struct EarlyLintVisitor<'a, 's, 'ast> {\n    pub ctx: &'a LintContext<'s, 'a>,\n    pub passes: &'a mut [Box<dyn EarlyLintPass<'ast> + 's>],\n}\n\nimpl<'a, 's, 'ast> EarlyLintVisitor<'a, 's, 'ast>\nwhere\n    's: 'ast,\n{\n    pub fn new(\n        ctx: &'a LintContext<'s, 'a>,\n        passes: &'a mut [Box<dyn EarlyLintPass<'ast> + 's>],\n    ) -> Self {\n        Self { ctx, passes }\n    }\n\n    /// Extends the [`Visit`] trait functionality with a hook that can run after the initial\n    /// traversal.\n    pub fn post_source_unit(&mut self, ast: &'ast ast::SourceUnit<'ast>) {\n        for pass in self.passes.iter_mut() {\n            pass.check_full_source_unit(self.ctx, ast);\n        }\n    }\n}\n\nimpl<'s, 'ast> Visit<'ast> for EarlyLintVisitor<'_, 's, 'ast>\nwhere\n    's: 'ast,\n{\n    type BreakValue = Never;\n\n    fn visit_doc_comment(&mut self, cmnt: &'ast ast::DocComment) -> ControlFlow<Self::BreakValue> {\n        for pass in self.passes.iter_mut() {\n            pass.check_doc_comment(self.ctx, cmnt)\n        }\n        self.walk_doc_comment(cmnt)\n    }\n\n    fn visit_expr(&mut self, expr: &'ast ast::Expr<'ast>) -> ControlFlow<Self::BreakValue> {\n        for pass in self.passes.iter_mut() {\n            pass.check_expr(self.ctx, expr)\n        }\n        self.walk_expr(expr)\n    }\n\n    fn visit_variable_definition(\n        &mut self,\n        var: &'ast ast::VariableDefinition<'ast>,\n    ) -> ControlFlow<Self::BreakValue> {\n        for pass in self.passes.iter_mut() {\n            pass.check_variable_definition(self.ctx, var)\n        }\n        self.walk_variable_definition(var)\n    }\n\n    fn visit_item_struct(\n        &mut self,\n        strukt: &'ast ast::ItemStruct<'ast>,\n    ) -> ControlFlow<Self::BreakValue> {\n        for pass in self.passes.iter_mut() {\n            pass.check_item_struct(self.ctx, strukt)\n        }\n        self.walk_item_struct(strukt)\n    }\n\n    fn visit_item_function(\n        &mut self,\n        func: &'ast ast::ItemFunction<'ast>,\n    ) -> ControlFlow<Self::BreakValue> {\n        for pass in self.passes.iter_mut() {\n            pass.check_item_function(self.ctx, func)\n        }\n        self.walk_item_function(func)\n    }\n\n    fn visit_import_directive(\n        &mut self,\n        import: &'ast ast::ImportDirective<'ast>,\n    ) -> ControlFlow<Self::BreakValue> {\n        for pass in self.passes.iter_mut() {\n            pass.check_import_directive(self.ctx, import);\n        }\n        self.walk_import_directive(import)\n    }\n\n    fn visit_using_directive(\n        &mut self,\n        using: &'ast ast::UsingDirective<'ast>,\n    ) -> ControlFlow<Self::BreakValue> {\n        for pass in self.passes.iter_mut() {\n            pass.check_using_directive(self.ctx, using);\n        }\n        self.walk_using_directive(using)\n    }\n\n    fn visit_item_contract(\n        &mut self,\n        contract: &'ast ast::ItemContract<'ast>,\n    ) -> ControlFlow<Self::BreakValue> {\n        for pass in self.passes.iter_mut() {\n            pass.check_item_contract(self.ctx, contract);\n        }\n        self.walk_item_contract(contract)\n    }\n\n    fn visit_item(&mut self, item: &'ast ast::Item<'ast>) -> ControlFlow<Self::BreakValue> {\n        for pass in self.passes.iter_mut() {\n            pass.check_item(self.ctx, item)\n        }\n        self.walk_item(item)\n    }\n\n    fn visit_stmt(&mut self, stmt: &'ast ast::Stmt<'ast>) -> ControlFlow<Self::BreakValue> {\n        for pass in self.passes.iter_mut() {\n            pass.check_stmt(self.ctx, stmt)\n        }\n        self.walk_stmt(stmt)\n    }\n\n    fn visit_path(&mut self, path: &'ast ast::PathSlice) -> ControlFlow<Self::BreakValue> {\n        for pass in self.passes.iter_mut() {\n            pass.check_path(self.ctx, path)\n        }\n        self.walk_path(path)\n    }\n\n    fn visit_ty(&mut self, ty: &'ast ast::Type<'ast>) -> ControlFlow<Self::BreakValue> {\n        for pass in self.passes.iter_mut() {\n            pass.check_ty(self.ctx, ty)\n        }\n        self.walk_ty(ty)\n    }\n}\n"
  },
  {
    "path": "crates/lint/src/linter/late.rs",
    "content": "use solar::{interface::data_structures::Never, sema::hir};\nuse std::ops::ControlFlow;\n\nuse super::LintContext;\n\n/// Trait for lints that operate on the HIR (High-level Intermediate Representation).\n/// Its methods mirror `hir::visit::Visit`, with the addition of `LintContext`.\npub trait LateLintPass<'hir>: Send + Sync {\n    fn check_nested_source(\n        &mut self,\n        _ctx: &LintContext,\n        _hir: &'hir hir::Hir<'hir>,\n        _id: hir::SourceId,\n    ) {\n    }\n    fn check_nested_item(\n        &mut self,\n        _ctx: &LintContext,\n        _hir: &'hir hir::Hir<'hir>,\n        _id: &'hir hir::ItemId,\n    ) {\n    }\n    fn check_nested_contract(\n        &mut self,\n        _ctx: &LintContext,\n        _hir: &'hir hir::Hir<'hir>,\n        _id: &'hir hir::ContractId,\n    ) {\n    }\n    fn check_nested_function(\n        &mut self,\n        _ctx: &LintContext,\n        _hir: &'hir hir::Hir<'hir>,\n        _id: &'hir hir::FunctionId,\n    ) {\n    }\n    fn check_nested_var(\n        &mut self,\n        _ctx: &LintContext,\n        _hir: &'hir hir::Hir<'hir>,\n        _id: &'hir hir::VariableId,\n    ) {\n    }\n    fn check_item(\n        &mut self,\n        _ctx: &LintContext,\n        _hir: &'hir hir::Hir<'hir>,\n        _item: hir::Item<'hir, 'hir>,\n    ) {\n    }\n    fn check_contract(\n        &mut self,\n        _ctx: &LintContext,\n        _hir: &'hir hir::Hir<'hir>,\n        _contract: &'hir hir::Contract<'hir>,\n    ) {\n    }\n    fn check_function(\n        &mut self,\n        _ctx: &LintContext,\n        _hir: &'hir hir::Hir<'hir>,\n        _func: &'hir hir::Function<'hir>,\n    ) {\n    }\n    fn check_modifier(\n        &mut self,\n        _ctx: &LintContext,\n        _hir: &'hir hir::Hir<'hir>,\n        _mod: &'hir hir::Modifier<'hir>,\n    ) {\n    }\n    fn check_var(\n        &mut self,\n        _ctx: &LintContext,\n        _hir: &'hir hir::Hir<'hir>,\n        _var: &'hir hir::Variable<'hir>,\n    ) {\n    }\n    fn check_expr(\n        &mut self,\n        _ctx: &LintContext,\n        _hir: &'hir hir::Hir<'hir>,\n        _expr: &'hir hir::Expr<'hir>,\n    ) {\n    }\n    fn check_call_args(\n        &mut self,\n        _ctx: &LintContext,\n        _hir: &'hir hir::Hir<'hir>,\n        _args: &'hir hir::CallArgs<'hir>,\n    ) {\n    }\n    fn check_stmt(\n        &mut self,\n        _ctx: &LintContext,\n        _hir: &'hir hir::Hir<'hir>,\n        _stmt: &'hir hir::Stmt<'hir>,\n    ) {\n    }\n    fn check_ty(\n        &mut self,\n        _ctx: &LintContext,\n        _hir: &'hir hir::Hir<'hir>,\n        _ty: &'hir hir::Type<'hir>,\n    ) {\n    }\n}\n\n/// Visitor struct for `LateLintPass`es\npub struct LateLintVisitor<'a, 's, 'hir> {\n    ctx: &'a LintContext<'s, 'a>,\n    passes: &'a mut [Box<dyn LateLintPass<'hir> + 's>],\n    hir: &'hir hir::Hir<'hir>,\n}\n\nimpl<'a, 's, 'hir> LateLintVisitor<'a, 's, 'hir>\nwhere\n    's: 'hir,\n{\n    pub fn new(\n        ctx: &'a LintContext<'s, 'a>,\n        passes: &'a mut [Box<dyn LateLintPass<'hir> + 's>],\n        hir: &'hir hir::Hir<'hir>,\n    ) -> Self {\n        Self { ctx, passes, hir }\n    }\n}\n\nimpl<'s, 'hir> hir::Visit<'hir> for LateLintVisitor<'_, 's, 'hir>\nwhere\n    's: 'hir,\n{\n    type BreakValue = Never;\n\n    fn hir(&self) -> &'hir hir::Hir<'hir> {\n        self.hir\n    }\n\n    fn visit_nested_source(&mut self, id: hir::SourceId) -> ControlFlow<Self::BreakValue> {\n        for pass in self.passes.iter_mut() {\n            pass.check_nested_source(self.ctx, self.hir, id);\n        }\n        self.walk_nested_source(id)\n    }\n\n    fn visit_contract(\n        &mut self,\n        contract: &'hir hir::Contract<'hir>,\n    ) -> ControlFlow<Self::BreakValue> {\n        for pass in self.passes.iter_mut() {\n            pass.check_contract(self.ctx, self.hir, contract);\n        }\n        self.walk_contract(contract)\n    }\n\n    fn visit_function(&mut self, func: &'hir hir::Function<'hir>) -> ControlFlow<Self::BreakValue> {\n        for pass in self.passes.iter_mut() {\n            pass.check_function(self.ctx, self.hir, func);\n        }\n        self.walk_function(func)\n    }\n\n    fn visit_item(&mut self, item: hir::Item<'hir, 'hir>) -> ControlFlow<Self::BreakValue> {\n        for pass in self.passes.iter_mut() {\n            pass.check_item(self.ctx, self.hir, item);\n        }\n        self.walk_item(item)\n    }\n\n    fn visit_var(&mut self, var: &'hir hir::Variable<'hir>) -> ControlFlow<Self::BreakValue> {\n        for pass in self.passes.iter_mut() {\n            pass.check_var(self.ctx, self.hir, var);\n        }\n        self.walk_var(var)\n    }\n\n    fn visit_expr(&mut self, expr: &'hir hir::Expr<'hir>) -> ControlFlow<Self::BreakValue> {\n        for pass in self.passes.iter_mut() {\n            pass.check_expr(self.ctx, self.hir, expr);\n        }\n        self.walk_expr(expr)\n    }\n\n    fn visit_stmt(&mut self, stmt: &'hir hir::Stmt<'hir>) -> ControlFlow<Self::BreakValue> {\n        for pass in self.passes.iter_mut() {\n            pass.check_stmt(self.ctx, self.hir, stmt);\n        }\n        self.walk_stmt(stmt)\n    }\n\n    fn visit_ty(&mut self, ty: &'hir hir::Type<'hir>) -> ControlFlow<Self::BreakValue> {\n        for pass in self.passes.iter_mut() {\n            pass.check_ty(self.ctx, self.hir, ty);\n        }\n        self.walk_ty(ty)\n    }\n}\n"
  },
  {
    "path": "crates/lint/src/linter/mod.rs",
    "content": "mod early;\nmod late;\n\npub use early::{EarlyLintPass, EarlyLintVisitor};\npub use late::{LateLintPass, LateLintVisitor};\n\nuse foundry_common::comments::inline_config::InlineConfig;\nuse foundry_compilers::Language;\nuse foundry_config::{\n    DenyLevel,\n    lint::{LintSpecificConfig, Severity},\n};\nuse solar::{\n    interface::{\n        Session, Span,\n        diagnostics::{\n            Applicability, DiagBuilder, DiagId, DiagMsg, MultiSpan, Style, SuggestionStyle,\n        },\n    },\n    sema::Compiler,\n};\nuse std::path::PathBuf;\n\n/// Trait representing a generic linter for analyzing and reporting issues in smart contract source\n/// code files.\n///\n/// A linter can be implemented for any smart contract language supported by Foundry.\npub trait Linter: Send + Sync {\n    /// The target [`Language`].\n    type Language: Language;\n    /// The [`Lint`] type.\n    type Lint: Lint;\n\n    /// Run all lints.\n    ///\n    /// The `compiler` should have already been configured with all the sources necessary,\n    /// as well as having performed parsing and lowering.\n    ///\n    /// Should return an error based on the configured [`DenyLevel`] and the emitted diagnostics.\n    fn lint(&self, input: &[PathBuf], deny: DenyLevel, compiler: &mut Compiler)\n    -> eyre::Result<()>;\n}\n\npub trait Lint {\n    fn id(&self) -> &'static str;\n    fn severity(&self) -> Severity;\n    fn description(&self) -> &'static str;\n    fn help(&self) -> &'static str;\n}\n\npub struct LintContext<'s, 'c> {\n    sess: &'s Session,\n    with_description: bool,\n    with_json_emitter: bool,\n    pub config: LinterConfig<'c>,\n    active_lints: Vec<&'static str>,\n}\n\npub struct LinterConfig<'s> {\n    pub inline: &'s InlineConfig<Vec<String>>,\n    pub lint_specific: &'s LintSpecificConfig,\n}\n\nimpl<'s, 'c> LintContext<'s, 'c> {\n    pub fn new(\n        sess: &'s Session,\n        with_description: bool,\n        with_json_emitter: bool,\n        config: LinterConfig<'c>,\n        active_lints: Vec<&'static str>,\n    ) -> Self {\n        Self { sess, with_description, with_json_emitter, config, active_lints }\n    }\n\n    fn add_help<'a>(&self, diag: DiagBuilder<'a, ()>, help: &'static str) -> DiagBuilder<'a, ()> {\n        // Avoid ANSI characters when using a JSON emitter\n        if self.with_json_emitter { diag.help(help) } else { diag.help(hyperlink(help)) }\n    }\n\n    pub fn session(&self) -> &'s Session {\n        self.sess\n    }\n\n    // Helper method to check if a lint id is enabled.\n    //\n    // For performance reasons, some passes check several lints at once. Thus, this method is\n    // required to avoid unintended warnings.\n    pub fn is_lint_enabled(&self, id: &'static str) -> bool {\n        self.active_lints.contains(&id)\n    }\n\n    /// Helper method to emit diagnostics easily from passes\n    pub fn emit<L: Lint>(&self, lint: &'static L, span: Span) {\n        if self.config.inline.is_id_disabled(span, lint.id()) || !self.is_lint_enabled(lint.id()) {\n            return;\n        }\n\n        let desc = if self.with_description { lint.description() } else { \"\" };\n        let mut diag: DiagBuilder<'_, ()> = self\n            .sess\n            .dcx\n            .diag(lint.severity().into(), desc)\n            .code(DiagId::new_str(lint.id()))\n            .span(MultiSpan::from_span(span));\n\n        diag = self.add_help(diag, lint.help());\n\n        diag.emit();\n    }\n\n    /// Emit a diagnostic with a code suggestion.\n    ///\n    /// If no span is provided for [`SuggestionKind::Fix`], it will use the lint's span.\n    pub fn emit_with_suggestion<L: Lint>(\n        &self,\n        lint: &'static L,\n        span: Span,\n        suggestion: Suggestion,\n    ) {\n        if self.config.inline.is_id_disabled(span, lint.id()) || !self.is_lint_enabled(lint.id()) {\n            return;\n        }\n\n        let desc = if self.with_description { lint.description() } else { \"\" };\n        let mut diag: DiagBuilder<'_, ()> = self\n            .sess\n            .dcx\n            .diag(lint.severity().into(), desc)\n            .code(DiagId::new_str(lint.id()))\n            .span(MultiSpan::from_span(span));\n\n        diag = match suggestion.kind {\n            SuggestionKind::Fix { span: fix_span, applicability, style } => diag\n                .span_suggestion_with_style(\n                    fix_span.unwrap_or(span),\n                    suggestion.desc.unwrap_or_default(),\n                    suggestion.content,\n                    applicability,\n                    style,\n                ),\n            SuggestionKind::Example => {\n                if let Some(note) = suggestion.to_note() {\n                    diag.note(note.iter().map(|l| l.0.as_str()).collect::<String>())\n                } else {\n                    diag\n                }\n            }\n        };\n\n        diag = self.add_help(diag, lint.help());\n\n        diag.emit();\n    }\n\n    /// Gets the \"raw\" source code (snippet) of the given span.\n    pub fn span_to_snippet(&self, span: Span) -> Option<String> {\n        self.sess.source_map().span_to_snippet(span).ok()\n    }\n\n    /// Gets the number of leading whitespaces (indentation) of the line where the span begins.\n    pub fn get_span_indentation(&self, span: Span) -> usize {\n        if !span.is_dummy() {\n            // Get the line text and compute the indentation prior to the span's position.\n            let loc = self.sess.source_map().lookup_char_pos(span.lo());\n            if let Some(line_text) = loc.file.get_line(loc.line) {\n                let col_offset = loc.col.to_usize();\n                if col_offset <= line_text.len() {\n                    let prev_text = &line_text[..col_offset];\n                    return prev_text.len() - prev_text.trim().len();\n                }\n            }\n        }\n\n        0\n    }\n}\n\n#[derive(Debug, Clone, Eq, PartialEq)]\npub enum SuggestionKind {\n    /// A standalone block of code. Used for showing examples without suggesting a fix.\n    ///\n    /// Multi-line strings should include newlines.\n    Example,\n\n    /// A proposed code change, displayed as a diff. Used to suggest replacements, showing the code\n    /// to be removed (from `span`) and the code to be added (from `add`).\n    Fix {\n        /// The `Span` of the source code to be removed. Note that, if uninformed,\n        /// `fn emit_with_fix()` falls back to the lint span.\n        span: Option<Span>,\n        /// The applicability of the suggested fix.\n        applicability: Applicability,\n        /// The style of the suggested fix.\n        style: SuggestionStyle,\n    },\n}\n\n// An emittable diagnostic suggestion.\n//\n// Depending on its [`SuggestionKind`] will be emitted as a simple note (examples), or a fix\n// suggestion.\n#[derive(Debug, Clone, Eq, PartialEq)]\npub struct Suggestion {\n    /// An optional description displayed above the code block.\n    desc: Option<&'static str>,\n    /// The actual suggestion.\n    content: String,\n    /// The suggestion type and its specific data.\n    kind: SuggestionKind,\n}\n\nimpl Suggestion {\n    /// Creates a new [`SuggestionKind::Example`] suggestion.\n    pub fn example(content: String) -> Self {\n        Self { desc: None, content, kind: SuggestionKind::Example }\n    }\n\n    /// Creates a new [`SuggestionKind::Fix`] suggestion.\n    ///\n    /// When possible, will attempt to inline the suggestion.\n    pub fn fix(content: String, applicability: Applicability) -> Self {\n        Self {\n            desc: None,\n            content,\n            kind: SuggestionKind::Fix {\n                span: None,\n                applicability,\n                style: SuggestionStyle::ShowCode,\n            },\n        }\n    }\n\n    /// Sets the description for the suggestion.\n    pub fn with_desc(mut self, desc: &'static str) -> Self {\n        self.desc = Some(desc);\n        self\n    }\n\n    /// Sets the span for a [`SuggestionKind::Fix`] suggestion.\n    pub fn with_span(mut self, span: Span) -> Self {\n        if let SuggestionKind::Fix { span: ref mut s, .. } = self.kind {\n            *s = Some(span);\n        }\n        self\n    }\n\n    /// Sets the style for a [`SuggestionKind::Fix`] suggestion.\n    pub fn with_style(mut self, style: SuggestionStyle) -> Self {\n        if let SuggestionKind::Fix { style: ref mut s, .. } = self.kind {\n            *s = style;\n        }\n        self\n    }\n\n    fn to_note(&self) -> Option<Vec<(DiagMsg, Style)>> {\n        if let SuggestionKind::Fix { .. } = &self.kind {\n            return None;\n        };\n\n        let mut output = if let Some(desc) = self.desc {\n            vec![(DiagMsg::from(desc), Style::NoStyle), (DiagMsg::from(\"\\n\\n\"), Style::NoStyle)]\n        } else {\n            vec![(DiagMsg::from(\" \\n\"), Style::NoStyle)]\n        };\n\n        output.extend(\n            self.content.lines().map(|line| (DiagMsg::from(format!(\"{line}\\n\")), Style::NoStyle)),\n        );\n        output.push((DiagMsg::from(\"\\n\"), Style::NoStyle));\n        Some(output)\n    }\n}\n\n/// Creates a hyperlink of the input url.\nfn hyperlink(url: &'static str) -> String {\n    format!(\"\\x1b]8;;{url}\\x1b\\\\{url}\\x1b]8;;\\x1b\\\\\")\n}\n"
  },
  {
    "path": "crates/lint/src/sol/codesize/mod.rs",
    "content": "use crate::sol::{EarlyLintPass, LateLintPass, SolLint};\n\nmod unwrapped_modifier_logic;\nuse unwrapped_modifier_logic::UNWRAPPED_MODIFIER_LOGIC;\n\nregister_lints!((UnwrappedModifierLogic, late, (UNWRAPPED_MODIFIER_LOGIC)));\n"
  },
  {
    "path": "crates/lint/src/sol/codesize/unwrapped_modifier_logic.rs",
    "content": "use super::UnwrappedModifierLogic;\nuse crate::{\n    linter::{LateLintPass, LintContext, Suggestion},\n    sol::{Severity, SolLint},\n};\nuse solar::{\n    ast,\n    sema::hir::{self, Res},\n};\n\ndeclare_forge_lint!(\n    UNWRAPPED_MODIFIER_LOGIC,\n    Severity::CodeSize,\n    \"unwrapped-modifier-logic\",\n    \"wrap modifier logic to reduce code size\"\n);\n\nimpl<'hir> LateLintPass<'hir> for UnwrappedModifierLogic {\n    fn check_function(\n        &mut self,\n        ctx: &LintContext,\n        hir: &'hir hir::Hir<'hir>,\n        func: &'hir hir::Function<'hir>,\n    ) {\n        // Only check modifiers with a body and a name\n        let body = match (func.kind, &func.body, func.name) {\n            (ast::FunctionKind::Modifier, Some(body), Some(_)) => body,\n            _ => return,\n        };\n\n        // Split statements into before and after the placeholder `_`.\n        let stmts = body.stmts[..].as_ref();\n        let (before, after) = stmts\n            .iter()\n            .position(|s| matches!(s.kind, hir::StmtKind::Placeholder))\n            .map_or((stmts, &[][..]), |idx| (&stmts[..idx], &stmts[idx + 1..]));\n\n        // Generate a fix suggestion if the modifier logic should be wrapped.\n        if let Some(suggestion) = self.get_snippet(ctx, hir, func, before, after) {\n            ctx.emit_with_suggestion(\n                &UNWRAPPED_MODIFIER_LOGIC,\n                func.span.to(func.body_span),\n                suggestion,\n            );\n        }\n    }\n}\n\nimpl UnwrappedModifierLogic {\n    /// Returns `true` if an expr is not a built-in ('require' or 'assert') call or a lib function.\n    fn is_valid_expr(&self, hir: &hir::Hir<'_>, expr: &hir::Expr<'_>) -> bool {\n        if let hir::ExprKind::Call(func_expr, _, _) = &expr.kind {\n            if let hir::ExprKind::Ident(resolutions) = &func_expr.kind {\n                return !resolutions.iter().any(|r| matches!(r, Res::Builtin(_)));\n            }\n\n            if let hir::ExprKind::Member(base, _) = &func_expr.kind\n                && let hir::ExprKind::Ident(resolutions) = &base.kind\n            {\n                return resolutions.iter().any(|r| {\n                    matches!(r, Res::Item(hir::ItemId::Contract(id)) if hir.contract(*id).kind == ast::ContractKind::Library)\n                });\n            }\n        }\n\n        false\n    }\n\n    /// Checks if a block of statements is complex and should be wrapped in a helper function.\n    ///\n    /// This always is 'false' the modifier contains assembly. We assume that if devs know how to\n    /// use assembly, they will also know how to reduce the codesize of their contracts and they\n    /// have a good reason to use it on their modifiers.\n    ///\n    /// This is 'true' if the block contains:\n    /// 1. Any statement that is not a placeholder or a valid expression.\n    /// 2. More than one simple call expression.\n    fn stmts_require_wrapping(&self, hir: &hir::Hir<'_>, stmts: &[hir::Stmt<'_>]) -> bool {\n        let (mut res, mut has_valid_stmt) = (false, false);\n        for stmt in stmts {\n            match &stmt.kind {\n                hir::StmtKind::Placeholder => continue,\n                hir::StmtKind::Expr(expr) => {\n                    if !self.is_valid_expr(hir, expr) || has_valid_stmt {\n                        res = true;\n                    }\n                    has_valid_stmt = true;\n                }\n                // HIR doesn't support assembly yet:\n                // <https://github.com/paradigmxyz/solar/blob/d25bf38a5accd11409318e023f701313d98b9e1e/crates/sema/src/hir/mod.rs#L977-L982>\n                hir::StmtKind::Err(_) => return false,\n                _ => res = true,\n            }\n        }\n\n        res\n    }\n\n    fn get_snippet<'a>(\n        &self,\n        ctx: &LintContext,\n        hir: &hir::Hir<'_>,\n        func: &hir::Function<'_>,\n        before: &'a [hir::Stmt<'a>],\n        after: &'a [hir::Stmt<'a>],\n    ) -> Option<Suggestion> {\n        let wrap_before = !before.is_empty() && self.stmts_require_wrapping(hir, before);\n        let wrap_after = !after.is_empty() && self.stmts_require_wrapping(hir, after);\n\n        if !(wrap_before || wrap_after) {\n            return None;\n        }\n\n        let binding = func.name.unwrap();\n        let modifier_name = binding.name.as_str();\n        let mut param_list = vec![];\n        let mut param_decls = vec![];\n\n        for var_id in func.parameters {\n            let var = hir.variable(*var_id);\n            let ty = ctx\n                .span_to_snippet(var.ty.span)\n                .unwrap_or_else(|| \"/* unknown type */\".to_string());\n\n            // solidity functions should always have named parameters\n            if let Some(ident) = var.name {\n                param_list.push(ident.to_string());\n                param_decls.push(format!(\"{ty} {}\", ident.to_string()));\n            }\n        }\n\n        let param_list = param_list.join(\", \");\n        let param_decls = param_decls.join(\", \");\n\n        let body_indent = \" \".repeat(ctx.get_span_indentation(\n            before.first().or(after.first()).map(|stmt| stmt.span).unwrap_or(func.span),\n        ));\n        let body = match (wrap_before, wrap_after) {\n            (true, true) => format!(\n                \"{body_indent}_{modifier_name}Before({param_list});\\n{body_indent}_;\\n{body_indent}_{modifier_name}After({param_list});\"\n            ),\n            (true, false) => {\n                format!(\"{body_indent}_{modifier_name}({param_list});\\n{body_indent}_;\")\n            }\n            (false, true) => {\n                format!(\"{body_indent}_;\\n{body_indent}_{modifier_name}({param_list});\")\n            }\n            _ => unreachable!(),\n        };\n\n        let mod_indent = \" \".repeat(ctx.get_span_indentation(func.span));\n        let mut replacement =\n            format!(\"modifier {modifier_name}({param_decls}) {{\\n{body}\\n{mod_indent}}}\");\n\n        let build_func = |stmts: &[hir::Stmt<'_>], suffix: &str| {\n            let body_stmts = stmts\n                .iter()\n                .filter_map(|s| ctx.span_to_snippet(s.span))\n                .map(|code| format!(\"\\n{body_indent}{code}\"))\n                .collect::<String>();\n            format!(\n                \"\\n\\n{mod_indent}function _{modifier_name}{suffix}({param_decls}) internal {{{body_stmts}\\n{mod_indent}}}\"\n            )\n        };\n\n        if wrap_before {\n            replacement.push_str(&build_func(before, if wrap_after { \"Before\" } else { \"\" }));\n        }\n        if wrap_after {\n            replacement.push_str(&build_func(after, if wrap_before { \"After\" } else { \"\" }));\n        }\n\n        Some(\n            Suggestion::fix(\n                replacement,\n                ast::interface::diagnostics::Applicability::MachineApplicable,\n            )\n            .with_desc(\"wrap modifier logic to reduce code size\"),\n        )\n    }\n}\n"
  },
  {
    "path": "crates/lint/src/sol/gas/custom_errors.rs",
    "content": "use super::CustomErrors;\nuse crate::{\n    linter::{EarlyLintPass, LintContext},\n    sol::{Severity, SolLint},\n};\nuse solar::ast::{CallArgsKind, Expr, ExprKind};\n\ndeclare_forge_lint!(\n    CUSTOM_ERRORS,\n    Severity::Gas,\n    \"custom-errors\",\n    \"prefer using custom errors on revert and require calls\"\n);\n\nimpl<'ast> EarlyLintPass<'ast> for CustomErrors {\n    fn check_expr(&mut self, ctx: &LintContext, expr: &'ast Expr<'ast>) {\n        if let ExprKind::Call(callee, args) = &expr.kind\n            && ((is_require_call(callee) && should_lint_require(args))\n                || (is_revert_call(callee) && should_lint_revert(args)))\n        {\n            ctx.emit(&CUSTOM_ERRORS, expr.span);\n        }\n    }\n}\n\n/// Checks if an expression is a call to the `require` builtin function.\nfn is_require_call(callee: &Expr<'_>) -> bool {\n    matches!(&callee.kind, ExprKind::Ident(ident) if ident.as_str() == \"require\")\n}\n\n/// Checks if an expression is a call to the `revert` builtin function.\nfn is_revert_call(callee: &Expr<'_>) -> bool {\n    matches!(&callee.kind, ExprKind::Ident(ident) if ident.as_str() == \"revert\")\n}\n\n/// Checks if a revert call should be linted: `revert()` or `revert(\"message\")`.\nfn should_lint_revert(args: &solar::ast::CallArgs<'_>) -> bool {\n    matches!(&args.kind, CallArgsKind::Unnamed(arg_exprs) if {\n        arg_exprs.is_empty() || arg_exprs.first().is_some_and(|e| is_string_literal(e))\n    })\n}\n\n/// Checks if a require call should be linted: has string literal as second argument.\nfn should_lint_require(args: &solar::ast::CallArgs<'_>) -> bool {\n    matches!(&args.kind, CallArgsKind::Unnamed(arg_exprs) if {\n        arg_exprs.get(1).is_some_and(|e| is_string_literal(e))\n    })\n}\n\n/// Checks if an expression is a string literal.\nfn is_string_literal(expr: &Expr<'_>) -> bool {\n    matches!(&expr.kind, ExprKind::Lit(lit, _) if matches!(lit.kind, solar::ast::LitKind::Str(..)))\n}\n"
  },
  {
    "path": "crates/lint/src/sol/gas/keccak.rs",
    "content": "use super::AsmKeccak256;\nuse crate::{\n    linter::{LateLintPass, LintContext},\n    sol::{Severity, SolLint},\n};\nuse solar::{\n    ast::{self as ast, Span},\n    interface::kw,\n    sema::hir::{self},\n};\n\ndeclare_forge_lint!(\n    ASM_KECCAK256,\n    Severity::Gas,\n    \"asm-keccak256\",\n    \"use of inefficient hashing mechanism; consider using inline assembly\"\n);\n\nimpl<'hir> LateLintPass<'hir> for AsmKeccak256 {\n    fn check_stmt(\n        &mut self,\n        ctx: &LintContext,\n        hir: &'hir hir::Hir<'hir>,\n        stmt: &'hir hir::Stmt<'hir>,\n    ) {\n        let check_expr_and_emit_lint =\n            |expr: &'hir hir::Expr<'hir>, assign: Option<ast::Ident>, is_return: bool| {\n                if let Some(hash_arg) = extract_keccak256_arg(expr) {\n                    self.emit_lint(\n                        ctx,\n                        hir,\n                        stmt.span,\n                        expr,\n                        hash_arg,\n                        AsmContext { _assign: assign, _is_return: is_return },\n                    );\n                }\n            };\n\n        match stmt.kind {\n            hir::StmtKind::DeclSingle(var_id) => {\n                let var = hir.variable(var_id);\n                if let Some(init) = var.initializer {\n                    // Constants should be optimized by the compiler, so no gas savings apply.\n                    if !matches!(var.mutability, Some(hir::VarMut::Constant)) {\n                        check_expr_and_emit_lint(init, var.name, false);\n                    }\n                }\n            }\n            // Expressions that don't (directly) assign to a variable\n            hir::StmtKind::Expr(expr)\n            | hir::StmtKind::Emit(expr)\n            | hir::StmtKind::Revert(expr)\n            | hir::StmtKind::DeclMulti(_, expr)\n            | hir::StmtKind::If(expr, ..) => check_expr_and_emit_lint(expr, None, false),\n            hir::StmtKind::Return(Some(expr)) => check_expr_and_emit_lint(expr, None, true),\n            _ => (),\n        }\n    }\n}\n\nimpl AsmKeccak256 {\n    /// Emits lints (when possible with fix suggestions) for inefficient `keccak256` calls.\n    fn emit_lint(\n        &self,\n        ctx: &LintContext,\n        _hir: &hir::Hir<'_>,\n        _stmt_span: Span,\n        call: &hir::Expr<'_>,\n        _hash: &hir::Expr<'_>,\n        _asm_ctx: AsmContext,\n    ) {\n        ctx.emit(&ASM_KECCAK256, call.span);\n    }\n}\n\n/// If the expression is a call to `keccak256` with one argument, returns that argument.\nfn extract_keccak256_arg<'hir>(expr: &'hir hir::Expr<'hir>) -> Option<&'hir hir::Expr<'hir>> {\n    let hir::ExprKind::Call(\n        callee,\n        hir::CallArgs { kind: hir::CallArgsKind::Unnamed(args), .. },\n        ..,\n    ) = &expr.kind\n    else {\n        return None;\n    };\n\n    let is_keccak = if let hir::ExprKind::Ident([hir::Res::Builtin(builtin)]) = callee.kind {\n        matches!(builtin.name(), kw::Keccak256)\n    } else {\n        return None;\n    };\n\n    if is_keccak && args.len() == 1 { Some(&args[0]) } else { None }\n}\n\n// -- HELPER FUNCTIONS AND STRUCTS ----------------------------------------------------------------\n\n#[derive(Debug, Clone, Copy)]\nstruct AsmContext {\n    _assign: Option<ast::Ident>,\n    _is_return: bool,\n}\n"
  },
  {
    "path": "crates/lint/src/sol/gas/mod.rs",
    "content": "use crate::sol::{EarlyLintPass, LateLintPass, SolLint};\n\nmod custom_errors;\nmod keccak;\nuse custom_errors::CUSTOM_ERRORS;\nuse keccak::ASM_KECCAK256;\n\nregister_lints!((CustomErrors, early, (CUSTOM_ERRORS)), (AsmKeccak256, late, (ASM_KECCAK256)));\n"
  },
  {
    "path": "crates/lint/src/sol/high/incorrect_shift.rs",
    "content": "use super::IncorrectShift;\nuse crate::{\n    linter::{EarlyLintPass, LintContext},\n    sol::{Severity, SolLint},\n};\nuse solar::ast::{BinOp, BinOpKind, Expr, ExprKind};\n\ndeclare_forge_lint!(\n    INCORRECT_SHIFT,\n    Severity::High,\n    \"incorrect-shift\",\n    \"the order of args in a shift operation is incorrect\"\n);\n\nimpl<'ast> EarlyLintPass<'ast> for IncorrectShift {\n    fn check_expr(&mut self, ctx: &LintContext, expr: &'ast Expr<'ast>) {\n        if let ExprKind::Binary(\n            left_expr,\n            BinOp { kind: BinOpKind::Shl | BinOpKind::Shr, .. },\n            right_expr,\n        ) = &expr.kind\n            && contains_incorrect_shift(left_expr, right_expr)\n        {\n            ctx.emit(&INCORRECT_SHIFT, expr.span);\n        }\n    }\n}\n\n// TODO: come up with a better heuristic. Treat initial impl as a PoC.\n// Checks if the left operand is a literal and the right operand is not, indicating a potential\n// reversed shift operation.\nfn contains_incorrect_shift<'ast>(\n    left_expr: &'ast Expr<'ast>,\n    right_expr: &'ast Expr<'ast>,\n) -> bool {\n    let is_left_literal = matches!(left_expr.kind, ExprKind::Lit(..));\n    let is_right_not_literal = !matches!(right_expr.kind, ExprKind::Lit(..));\n\n    is_left_literal && is_right_not_literal\n}\n"
  },
  {
    "path": "crates/lint/src/sol/high/mod.rs",
    "content": "use crate::sol::{EarlyLintPass, LateLintPass, SolLint};\n\nmod incorrect_shift;\nmod unchecked_calls;\n\nuse incorrect_shift::INCORRECT_SHIFT;\nuse unchecked_calls::{ERC20_UNCHECKED_TRANSFER, UNCHECKED_CALL};\n\nregister_lints!(\n    (IncorrectShift, early, (INCORRECT_SHIFT)),\n    (UncheckedCall, early, (UNCHECKED_CALL)),\n    (UncheckedTransferERC20, late, (ERC20_UNCHECKED_TRANSFER))\n);\n"
  },
  {
    "path": "crates/lint/src/sol/high/unchecked_calls.rs",
    "content": "use super::{UncheckedCall, UncheckedTransferERC20};\nuse crate::{\n    linter::{EarlyLintPass, LateLintPass, LintContext},\n    sol::{Severity, SolLint},\n};\nuse solar::{\n    ast::{Expr, ExprKind, ItemFunction, Stmt, StmtKind, visit::Visit},\n    interface::kw,\n    sema::hir::{self},\n};\nuse std::ops::ControlFlow;\n\ndeclare_forge_lint!(\n    UNCHECKED_CALL,\n    Severity::High,\n    \"unchecked-call\",\n    \"Low-level calls should check the success return value\"\n);\n\ndeclare_forge_lint!(\n    ERC20_UNCHECKED_TRANSFER,\n    Severity::High,\n    \"erc20-unchecked-transfer\",\n    \"ERC20 'transfer' and 'transferFrom' calls should check the return value\"\n);\n\n// -- ERC20 UNCKECKED TRANSFERS -------------------------------------------------------------------\n\n/// Checks that calls to functions with the same signature as the ERC20 transfer methods, and which\n/// return a boolean are not ignored.\n///\n/// WARN: can issue false positives, as it doesn't check that the contract being called sticks to\n/// the full ERC20 specification.\nimpl<'hir> LateLintPass<'hir> for UncheckedTransferERC20 {\n    fn check_stmt(\n        &mut self,\n        ctx: &LintContext,\n        hir: &'hir hir::Hir<'hir>,\n        stmt: &'hir hir::Stmt<'hir>,\n    ) {\n        // Only expression statements can contain unchecked transfers.\n        if let hir::StmtKind::Expr(expr) = &stmt.kind\n            && is_erc20_transfer_call(hir, expr)\n        {\n            ctx.emit(&ERC20_UNCHECKED_TRANSFER, expr.span);\n        }\n    }\n}\n\n/// Checks if an expression is an ERC20 `transfer` or `transferFrom` call.\n/// * `function transfer(address to, uint256 amount) external returns bool;`\n/// * `function transferFrom(address from, address to, uint256 amount) external returns bool;`\n///\n/// Validates the method name, the params (count + types), and the returns (count + types).\nfn is_erc20_transfer_call(hir: &hir::Hir<'_>, expr: &hir::Expr<'_>) -> bool {\n    let is_type = |var_id: hir::VariableId, type_str: &str| {\n        matches!(\n            &hir.variable(var_id).ty.kind,\n            hir::TypeKind::Elementary(ty) if ty.to_abi_str() == type_str\n        )\n    };\n\n    // Ensure the expression is a call to a contract member function.\n    let hir::ExprKind::Call(\n        hir::Expr { kind: hir::ExprKind::Member(contract_expr, func_ident), .. },\n        hir::CallArgs { kind: hir::CallArgsKind::Unnamed(args), .. },\n        ..,\n    ) = &expr.kind\n    else {\n        return false;\n    };\n\n    // Determine the expected ERC20 signature from the call\n    let (expected_params, expected_returns): (&[&str], &[&str]) = match func_ident.as_str() {\n        \"transferFrom\" if args.len() == 3 => (&[\"address\", \"address\", \"uint256\"], &[\"bool\"]),\n        \"transfer\" if args.len() == 2 => (&[\"address\", \"uint256\"], &[\"bool\"]),\n        _ => return false,\n    };\n\n    let Some(cid) = (match &contract_expr.kind {\n        // Call to pre-instantiated contract variable\n        hir::ExprKind::Ident([hir::Res::Item(hir::ItemId::Variable(id)), ..]) => {\n            if let hir::TypeKind::Custom(hir::ItemId::Contract(cid)) = hir.variable(*id).ty.kind {\n                Some(cid)\n            } else {\n                None\n            }\n        }\n        // Call to address wrapped by the contract interface\n        hir::ExprKind::Call(\n            hir::Expr {\n                kind: hir::ExprKind::Ident([hir::Res::Item(hir::ItemId::Contract(cid))]),\n                ..\n            },\n            ..,\n        ) => Some(*cid),\n        _ => None,\n    }) else {\n        return false;\n    };\n\n    // Try to find a function in the contract that matches the expected signature.\n    hir.contract_item_ids(cid).any(|item| {\n        let Some(fid) = item.as_function() else { return false };\n        let func = hir.function(fid);\n        func.name.is_some_and(|name| name.as_str() == func_ident.as_str())\n            && func.kind.is_function()\n            && func.mutates_state()\n            && func.parameters.len() == expected_params.len()\n            && func.returns.len() == expected_returns.len()\n            && func.parameters.iter().zip(expected_params).all(|(id, &ty)| is_type(*id, ty))\n            && func.returns.iter().zip(expected_returns).all(|(id, &ty)| is_type(*id, ty))\n    })\n}\n\n// -- UNCKECKED LOW-LEVEL CALLS -------------------------------------------------------------------\n\nimpl<'ast> EarlyLintPass<'ast> for UncheckedCall {\n    fn check_item_function(&mut self, ctx: &LintContext, func: &'ast ItemFunction<'ast>) {\n        if let Some(body) = &func.body {\n            let mut checker = UncheckedCallChecker { ctx };\n            let _ = checker.visit_block(body);\n        }\n    }\n}\n\n/// Visitor that detects unchecked low-level calls within function bodies.\n///\n/// Similar to unchecked transfers, unchecked calls appear as standalone expression\n/// statements. When the success value is checked (in require, if, etc.), the call\n/// is part of a larger expression and won't be flagged.\nstruct UncheckedCallChecker<'a, 's> {\n    ctx: &'a LintContext<'s, 'a>,\n}\n\nimpl<'ast> Visit<'ast> for UncheckedCallChecker<'_, '_> {\n    type BreakValue = ();\n\n    fn visit_stmt(&mut self, stmt: &'ast Stmt<'ast>) -> ControlFlow<Self::BreakValue> {\n        match &stmt.kind {\n            // Check standalone expression statements: `target.call(data);`\n            StmtKind::Expr(expr) => {\n                if is_low_level_call(expr) {\n                    self.ctx.emit(&UNCHECKED_CALL, expr.span);\n                } else if let ExprKind::Assign(lhs, _, rhs) = &expr.kind {\n                    // Check assignments to existing vars: `(, existingVar) = target.call(data);`\n                    if is_low_level_call(rhs) && is_unchecked_tuple_assignment(lhs) {\n                        self.ctx.emit(&UNCHECKED_CALL, expr.span);\n                    }\n                }\n            }\n            // Check multi-variable declarations: `(bool success, ) = target.call(data);`\n            StmtKind::DeclMulti(vars, expr)\n                if is_low_level_call(expr) && vars.first().is_none_or(|v| v.is_none()) =>\n            {\n                self.ctx.emit(&UNCHECKED_CALL, stmt.span);\n            }\n            _ => {}\n        }\n        self.walk_stmt(stmt)\n    }\n}\n\n/// Checks if an expression is a low-level call that should be checked.\n///\n/// Detects patterns like:\n/// - `target.call(...)`\n/// - `target.delegatecall(...)`\n/// - `target.staticcall(...)`\n/// - `target.call{value: x}(...)`\nfn is_low_level_call(expr: &Expr<'_>) -> bool {\n    if let ExprKind::Call(call_expr, _args) = &expr.kind {\n        // Check the callee expression\n        let callee = match &call_expr.kind {\n            // Handle call options like {value: x}\n            ExprKind::CallOptions(inner_expr, _) => inner_expr,\n            // Direct call without options\n            _ => call_expr,\n        };\n\n        if let ExprKind::Member(_, member) = &callee.kind {\n            // Check for low-level call methods\n            return matches!(member.name, kw::Call | kw::Delegatecall | kw::Staticcall);\n        }\n    }\n    false\n}\n\n/// Checks if a tuple assignment doesn't properly check the success value.\n///\n/// Returns true if the first variable (success) is None: `(, bytes memory data) =\n/// target.call(...)`\nfn is_unchecked_tuple_assignment(expr: &Expr<'_>) -> bool {\n    if let ExprKind::Tuple(elements) = &expr.kind {\n        elements.first().is_none_or(|e| e.is_none())\n    } else {\n        false\n    }\n}\n"
  },
  {
    "path": "crates/lint/src/sol/info/imports.rs",
    "content": "use solar::{\n    ast::{self as ast, SourceUnit, Span, Symbol, visit::Visit},\n    data_structures::map::FxIndexSet,\n    interface::SourceMap,\n};\nuse std::ops::ControlFlow;\n\nuse super::Imports;\nuse crate::{\n    linter::{EarlyLintPass, LintContext},\n    sol::{Severity, SolLint},\n};\n\ndeclare_forge_lint!(\n    UNUSED_IMPORT,\n    Severity::Info,\n    \"unused-import\",\n    \"unused imports should be removed\"\n);\n\ndeclare_forge_lint!(\n    UNALIASED_PLAIN_IMPORT,\n    Severity::Info,\n    \"unaliased-plain-import\",\n    \"use named imports '{A, B}' or alias 'import \\\"..\\\" as X'\"\n);\n\nimpl<'ast> EarlyLintPass<'ast> for Imports {\n    fn check_import_directive(\n        &mut self,\n        ctx: &LintContext,\n        import: &'ast ast::ImportDirective<'ast>,\n    ) {\n        // Non-aliased plain imports like `import \"File.sol\";`.\n        if let ast::ImportItems::Plain(_) = &import.items\n            && import.source_alias().is_none()\n        {\n            ctx.emit(&UNALIASED_PLAIN_IMPORT, import.path.span);\n        }\n    }\n\n    fn check_full_source_unit(&mut self, ctx: &LintContext<'ast, '_>, ast: &'ast SourceUnit<'ast>) {\n        // Despite disabled lints are filtered inside `ctx.emit()`, we explicitly check\n        // upfront to avoid the expensive full source unit traversal when unnecessary.\n        if ctx.is_lint_enabled(UNUSED_IMPORT.id) {\n            let mut checker = UnusedChecker::new(ctx.session().source_map());\n            let _ = checker.visit_source_unit(ast);\n            checker.check_unused_imports(ast, ctx);\n            checker.clear();\n        }\n    }\n}\n\n/// Visitor that collects all used symbols in a source unit.\nstruct UnusedChecker<'ast> {\n    used_symbols: FxIndexSet<Symbol>,\n    source_map: &'ast SourceMap,\n}\n\nimpl<'ast> UnusedChecker<'ast> {\n    fn new(source_map: &'ast SourceMap) -> Self {\n        Self { source_map, used_symbols: Default::default() }\n    }\n\n    fn clear(&mut self) {\n        self.used_symbols.clear();\n    }\n\n    /// Mark a symbol as used in a source.\n    fn mark_symbol_used(&mut self, symbol: Symbol) {\n        self.used_symbols.insert(symbol);\n    }\n\n    /// Check for unused imports and emit warnings.\n    fn check_unused_imports(&self, ast: &SourceUnit<'_>, ctx: &LintContext) {\n        for item in ast.items.iter() {\n            let span = item.span;\n            let ast::ItemKind::Import(import) = &item.kind else { continue };\n            #[allow(clippy::collapsible_match)]\n            match &import.items {\n                ast::ImportItems::Plain(_) | ast::ImportItems::Glob(_) => {\n                    if let Some(alias) = import.source_alias()\n                        && !self.used_symbols.contains(&alias.name)\n                    {\n                        self.unused_import(ctx, span);\n                    }\n                }\n                ast::ImportItems::Aliases(symbols) => {\n                    for &(orig, alias) in symbols.iter() {\n                        let name = alias.unwrap_or(orig);\n                        if !self.used_symbols.contains(&name.name) {\n                            self.unused_import(ctx, orig.span.to(name.span));\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    fn unused_import(&self, ctx: &LintContext, span: Span) {\n        ctx.emit(&UNUSED_IMPORT, span);\n    }\n}\n\nimpl<'ast> Visit<'ast> for UnusedChecker<'ast> {\n    type BreakValue = solar::data_structures::Never;\n\n    fn visit_item(&mut self, item: &'ast ast::Item<'ast>) -> ControlFlow<Self::BreakValue> {\n        if let ast::ItemKind::Import(_) = &item.kind {\n            return ControlFlow::Continue(());\n        }\n\n        self.walk_item(item)\n    }\n\n    fn visit_using_directive(\n        &mut self,\n        using: &'ast ast::UsingDirective<'ast>,\n    ) -> ControlFlow<Self::BreakValue> {\n        match &using.list {\n            ast::UsingList::Single(path) => {\n                self.mark_symbol_used(path.first().name);\n            }\n            ast::UsingList::Multiple(items) => {\n                for (path, _) in items.iter() {\n                    self.mark_symbol_used(path.first().name);\n                }\n            }\n        }\n\n        self.walk_using_directive(using)\n    }\n\n    fn visit_expr(&mut self, expr: &'ast ast::Expr<'ast>) -> ControlFlow<Self::BreakValue> {\n        if let ast::ExprKind::Ident(id) = expr.kind {\n            self.mark_symbol_used(id.name);\n        }\n\n        self.walk_expr(expr)\n    }\n\n    fn visit_path(&mut self, path: &'ast ast::PathSlice) -> ControlFlow<Self::BreakValue> {\n        for id in path.segments() {\n            self.mark_symbol_used(id.name);\n        }\n\n        self.walk_path(path)\n    }\n\n    fn visit_ty(&mut self, ty: &'ast ast::Type<'ast>) -> ControlFlow<Self::BreakValue> {\n        if let ast::TypeKind::Custom(path) = &ty.kind {\n            self.mark_symbol_used(path.first().name);\n        }\n\n        self.walk_ty(ty)\n    }\n\n    fn visit_doc_comment(\n        &mut self,\n        cmnt: &'ast solar::ast::DocComment,\n    ) -> ControlFlow<Self::BreakValue> {\n        if let Ok(snip) = self.source_map.span_to_snippet(cmnt.span) {\n            for line in snip.lines() {\n                if let Some((_, relevant)) = line.split_once(\"@inheritdoc\") {\n                    self.mark_symbol_used(Symbol::intern(relevant.trim()));\n                }\n            }\n        }\n        ControlFlow::Continue(())\n    }\n}\n"
  },
  {
    "path": "crates/lint/src/sol/info/interface_naming.rs",
    "content": "use crate::{\n    linter::{EarlyLintPass, Lint, LintContext},\n    sol::{Severity, SolLint, info::InterfaceFileNaming},\n};\n\nuse solar::ast::{self as ast};\n\ndeclare_forge_lint!(\n    INTERFACE_FILE_NAMING,\n    Severity::Info,\n    \"interface-file-naming\",\n    \"interface file names should be prefixed with 'I'\"\n);\n\ndeclare_forge_lint!(\n    INTERFACE_NAMING,\n    Severity::Info,\n    \"interface-naming\",\n    \"interface names should be prefixed with 'I'\"\n);\n\nimpl<'ast> EarlyLintPass<'ast> for InterfaceFileNaming {\n    fn check_full_source_unit(\n        &mut self,\n        ctx: &LintContext<'ast, '_>,\n        unit: &'ast ast::SourceUnit<'ast>,\n    ) {\n        if !ctx.is_lint_enabled(INTERFACE_FILE_NAMING.id()) {\n            return;\n        }\n\n        if let Some(file_name) = file_name(ctx, unit)\n            && !file_name.starts_with('I')\n            && unit.items.iter().all(|item| match &item.kind {\n                ast::ItemKind::Contract(c) => c.kind == ast::ContractKind::Interface,\n                _ => true,\n            })\n            && let Some(c) = unit.items.iter().find_map(|item| match &item.kind {\n                ast::ItemKind::Contract(c) => Some(c),\n                _ => None,\n            })\n        {\n            ctx.emit(&INTERFACE_FILE_NAMING, c.name.span);\n        }\n    }\n\n    fn check_item_contract(&mut self, ctx: &LintContext, contract: &'ast ast::ItemContract<'ast>) {\n        if ctx.is_lint_enabled(INTERFACE_NAMING.id())\n            && contract.kind == ast::ContractKind::Interface\n            && !contract.name.as_str().starts_with('I')\n        {\n            ctx.emit(&INTERFACE_NAMING, contract.name.span);\n        }\n    }\n}\n\nfn file_name(ctx: &LintContext, unit: &ast::SourceUnit) -> Option<String> {\n    let first_item_span = unit.items.first()?.span;\n    let file = ctx.session().source_map().lookup_source_file(first_item_span.lo());\n    let file_name = file.name.as_real()?.file_name()?.to_str()?;\n    Some(file_name.to_string())\n}\n"
  },
  {
    "path": "crates/lint/src/sol/info/mixed_case.rs",
    "content": "use super::{MixedCaseFunction, MixedCaseVariable};\nuse crate::{\n    linter::{EarlyLintPass, LintContext, Suggestion},\n    sol::{Severity, SolLint, info::screaming_snake_case::check_screaming_snake_case},\n};\nuse solar::ast::{FunctionHeader, ItemFunction, VariableDefinition, Visibility};\n\ndeclare_forge_lint!(\n    MIXED_CASE_FUNCTION,\n    Severity::Info,\n    \"mixed-case-function\",\n    \"function names should use mixedCase\"\n);\n\nimpl<'ast> EarlyLintPass<'ast> for MixedCaseFunction {\n    fn check_item_function(&mut self, ctx: &LintContext, func: &'ast ItemFunction<'ast>) {\n        if let Some(name) = func.header.name\n            && let Some(expected) = check_mixed_case(\n                name.as_str(),\n                true,\n                &ctx.config.lint_specific.mixed_case_exceptions,\n            )\n            && !is_constant_getter(&func.header)\n        {\n            ctx.emit_with_suggestion(\n                &MIXED_CASE_FUNCTION,\n                name.span,\n                Suggestion::fix(\n                    expected,\n                    solar::interface::diagnostics::Applicability::MachineApplicable,\n                )\n                .with_desc(\"consider using\"),\n            );\n        }\n    }\n}\n\ndeclare_forge_lint!(\n    MIXED_CASE_VARIABLE,\n    Severity::Info,\n    \"mixed-case-variable\",\n    \"mutable variables should use mixedCase\"\n);\n\nimpl<'ast> EarlyLintPass<'ast> for MixedCaseVariable {\n    fn check_variable_definition(\n        &mut self,\n        ctx: &LintContext,\n        var: &'ast VariableDefinition<'ast>,\n    ) {\n        if var.mutability.is_none()\n            && let Some(name) = var.name\n            && let Some(expected) = check_mixed_case(\n                name.as_str(),\n                false,\n                &ctx.config.lint_specific.mixed_case_exceptions,\n            )\n        {\n            ctx.emit_with_suggestion(\n                &MIXED_CASE_VARIABLE,\n                name.span,\n                Suggestion::fix(\n                    expected,\n                    solar::interface::diagnostics::Applicability::MachineApplicable,\n                )\n                .with_desc(\"consider using\"),\n            );\n        }\n    }\n}\n\n/// If the string `s` is not mixedCase, returns a `Some(String)` with the\n/// suggested conversion. Otherwise, returns `None`.\n///\n/// To avoid false positives:\n/// - lowercase strings like `fn increment()` or `uint256 counter`, are treated as mixedCase.\n/// - test functions starting with `test`, `invariant_` or `statefulFuzz` are ignored.\n/// - user-defined patterns like `ERC20` are allowed.\nfn check_mixed_case(s: &str, is_fn: bool, allowed_patterns: &[String]) -> Option<String> {\n    if s.len() <= 1 {\n        return None;\n    }\n\n    // Exception for test, invariant, and stateful fuzzing functions.\n    if is_fn\n        && (s.starts_with(\"test\") || s.starts_with(\"invariant_\") || s.starts_with(\"statefulFuzz\"))\n    {\n        return None;\n    }\n\n    // Exception for user-defined infix patterns.\n    for pattern in allowed_patterns {\n        if let Some(pos) = s.find(pattern.as_str()) {\n            let (pre, post) = s.split_at(pos);\n            let post = &post[pattern.len()..];\n\n            // Check if the part before the pattern is valid lowerCamelCase.\n            let is_pre_valid = pre == heck::AsLowerCamelCase(pre).to_string();\n\n            // Check if the part after is valid UpperCamelCase (allowing leading numbers).\n            let post_trimmed = post.trim_start_matches(|c: char| c.is_numeric());\n            let is_post_valid = post_trimmed == heck::AsUpperCamelCase(post_trimmed).to_string();\n\n            if is_pre_valid && is_post_valid {\n                return None;\n            }\n        }\n    }\n\n    // Generate the expected mixedCase version.\n    let suggestion = format!(\n        \"{prefix}{name}{suffix}\",\n        prefix = if s.starts_with('_') { \"_\" } else { \"\" },\n        name = heck::AsLowerCamelCase(s),\n        suffix = if s.ends_with('_') { \"_\" } else { \"\" }\n    );\n\n    // If the original string already matches the suggestion, it's valid.\n    if s == suggestion { None } else { Some(suggestion) }\n}\n\n/// Checks if a function getter is a valid constant getter with a heuristic:\n///  * name is `SCREAMING_SNAKE_CASE`\n///  * external view visibility and mutability.\n///  * zero parameters.\n///  * exactly one return value.\n///  * return value is an elementary or a custom type\nfn is_constant_getter(header: &FunctionHeader<'_>) -> bool {\n    header.visibility().is_some_and(|v| matches!(v, Visibility::External))\n        && header.state_mutability().is_view()\n        && header.parameters.is_empty()\n        && header.returns().len() == 1\n        && header\n            .returns()\n            .first()\n            .is_some_and(|ret| ret.ty.kind.is_elementary() || ret.ty.kind.is_custom())\n        && check_screaming_snake_case(header.name.unwrap().as_str()).is_none()\n}\n"
  },
  {
    "path": "crates/lint/src/sol/info/mod.rs",
    "content": "use crate::sol::{EarlyLintPass, LateLintPass, SolLint};\n\nmod mixed_case;\nuse mixed_case::{MIXED_CASE_FUNCTION, MIXED_CASE_VARIABLE};\n\nmod pascal_case;\nuse pascal_case::PASCAL_CASE_STRUCT;\n\nmod screaming_snake_case;\nuse screaming_snake_case::{SCREAMING_SNAKE_CASE_CONSTANT, SCREAMING_SNAKE_CASE_IMMUTABLE};\n\nmod imports;\nuse imports::{UNALIASED_PLAIN_IMPORT, UNUSED_IMPORT};\n\nmod named_struct_fields;\nuse named_struct_fields::NAMED_STRUCT_FIELDS;\n\nmod unsafe_cheatcodes;\nuse unsafe_cheatcodes::UNSAFE_CHEATCODE_USAGE;\n\nmod multi_contract_file;\nuse multi_contract_file::MULTI_CONTRACT_FILE;\n\nmod interface_naming;\nuse interface_naming::{INTERFACE_FILE_NAMING, INTERFACE_NAMING};\n\nregister_lints!(\n    (PascalCaseStruct, early, (PASCAL_CASE_STRUCT)),\n    (MixedCaseVariable, early, (MIXED_CASE_VARIABLE)),\n    (MixedCaseFunction, early, (MIXED_CASE_FUNCTION)),\n    (ScreamingSnakeCase, early, (SCREAMING_SNAKE_CASE_CONSTANT, SCREAMING_SNAKE_CASE_IMMUTABLE)),\n    (Imports, early, (UNALIASED_PLAIN_IMPORT, UNUSED_IMPORT)),\n    (NamedStructFields, late, (NAMED_STRUCT_FIELDS)),\n    (UnsafeCheatcodes, early, (UNSAFE_CHEATCODE_USAGE)),\n    (MultiContractFile, early, (MULTI_CONTRACT_FILE)),\n    (InterfaceFileNaming, early, (INTERFACE_FILE_NAMING, INTERFACE_NAMING))\n);\n"
  },
  {
    "path": "crates/lint/src/sol/info/multi_contract_file.rs",
    "content": "use crate::{\n    linter::{EarlyLintPass, Lint, LintContext},\n    sol::{Severity, SolLint, info::MultiContractFile},\n};\n\nuse solar::ast::{self as ast};\n\ndeclare_forge_lint!(\n    MULTI_CONTRACT_FILE,\n    Severity::Info,\n    \"multi-contract-file\",\n    \"prefer having only one contract, interface or library per file\"\n);\n\nimpl<'ast> EarlyLintPass<'ast> for MultiContractFile {\n    fn check_full_source_unit(\n        &mut self,\n        ctx: &LintContext<'ast, '_>,\n        unit: &'ast ast::SourceUnit<'ast>,\n    ) {\n        if !ctx.is_lint_enabled(MULTI_CONTRACT_FILE.id()) {\n            return;\n        }\n\n        // Collect spans of all contract-like items, skipping those that are exempted\n        let relevant_spans: Vec<_> = unit\n            .items\n            .iter()\n            .filter_map(|item| match &item.kind {\n                ast::ItemKind::Contract(c) => {\n                    (!ctx.config.lint_specific.is_exempted(&c.kind)).then_some(c.name.span)\n                }\n                _ => None,\n            })\n            .collect();\n\n        // Flag all if there's more than one\n        if relevant_spans.len() > 1 {\n            relevant_spans.into_iter().for_each(|span| ctx.emit(&MULTI_CONTRACT_FILE, span));\n        }\n    }\n}\n"
  },
  {
    "path": "crates/lint/src/sol/info/named_struct_fields.rs",
    "content": "use solar::sema::hir::{CallArgs, CallArgsKind, Expr, ExprKind, ItemId, Res};\n\nuse crate::{\n    linter::{LateLintPass, LintContext, Suggestion},\n    sol::{Severity, SolLint, info::NamedStructFields},\n};\n\ndeclare_forge_lint!(\n    NAMED_STRUCT_FIELDS,\n    Severity::Info,\n    \"named-struct-fields\",\n    \"prefer initializing structs with named fields\"\n);\n\nimpl<'hir> LateLintPass<'hir> for NamedStructFields {\n    fn check_expr(\n        &mut self,\n        ctx: &LintContext,\n        hir: &'hir solar::sema::hir::Hir<'hir>,\n        expr: &'hir solar::sema::hir::Expr<'hir>,\n    ) {\n        let ExprKind::Call(\n            Expr { kind: ExprKind::Ident([Res::Item(ItemId::Struct(struct_id))]), span, .. },\n            CallArgs { kind: CallArgsKind::Unnamed(args), .. },\n            _,\n        ) = &expr.kind\n        else {\n            return;\n        };\n\n        let strukt = hir.strukt(*struct_id);\n        let fields = &strukt.fields;\n\n        // Basic sanity conditions for a consistent auto-fix\n        if fields.len() != args.len() || fields.is_empty() {\n            // Emit without suggestion\n            ctx.emit(&NAMED_STRUCT_FIELDS, expr.span);\n            return;\n        }\n\n        // Get struct name snippet and emit without suggestion if we can't get it\n        let Some(struct_name_snippet) = ctx.span_to_snippet(*span) else {\n            // Emit without suggestion if we can't get the struct name snippet\n            ctx.emit(&NAMED_STRUCT_FIELDS, expr.span);\n            return;\n        };\n\n        // Collect field names and corresponding argument source snippets\n        let mut field_assignments = Vec::new();\n        for (field_id, arg) in fields.iter().zip(args.iter()) {\n            let field = hir.variable(*field_id);\n\n            let Some((arg_snippet, field_name)) =\n                ctx.span_to_snippet(arg.span).zip(field.name.map(|n| n.to_string()))\n            else {\n                // Emit without suggestion if we can't get argument snippet\n                ctx.emit(&NAMED_STRUCT_FIELDS, expr.span);\n                return;\n            };\n\n            field_assignments.push(format!(\"{field_name}: {arg_snippet}\"));\n        }\n\n        ctx.emit_with_suggestion(\n            &NAMED_STRUCT_FIELDS,\n            expr.span,\n            Suggestion::fix(\n                format!(\"{}({{ {} }})\", struct_name_snippet, field_assignments.join(\", \")),\n                solar::interface::diagnostics::Applicability::MachineApplicable,\n            )\n            .with_desc(\"consider using named fields\"),\n        );\n    }\n}\n"
  },
  {
    "path": "crates/lint/src/sol/info/pascal_case.rs",
    "content": "use super::PascalCaseStruct;\nuse crate::{\n    linter::{EarlyLintPass, LintContext, Suggestion},\n    sol::{Severity, SolLint},\n};\nuse solar::ast::ItemStruct;\n\ndeclare_forge_lint!(\n    PASCAL_CASE_STRUCT,\n    Severity::Info,\n    \"pascal-case-struct\",\n    \"structs should use PascalCase\"\n);\n\nimpl<'ast> EarlyLintPass<'ast> for PascalCaseStruct {\n    fn check_item_struct(&mut self, ctx: &LintContext, strukt: &'ast ItemStruct<'ast>) {\n        let name = strukt.name.as_str();\n        if let Some(expected) = check_pascal_case(name) {\n            ctx.emit_with_suggestion(\n                &PASCAL_CASE_STRUCT,\n                strukt.name.span,\n                Suggestion::fix(\n                    expected,\n                    solar::interface::diagnostics::Applicability::MachineApplicable,\n                )\n                .with_desc(\"consider using\"),\n            );\n        }\n    }\n}\n\n/// If the string `s` is not PascalCase, returns a `Some(String)` with the\n/// suggested conversion. Otherwise, returns `None`.\npub fn check_pascal_case(s: &str) -> Option<String> {\n    if s.len() <= 1 {\n        return None;\n    }\n\n    let expected = heck::AsPascalCase(s).to_string();\n    if s == expected.as_str() { None } else { Some(expected) }\n}\n"
  },
  {
    "path": "crates/lint/src/sol/info/screaming_snake_case.rs",
    "content": "use super::ScreamingSnakeCase;\nuse crate::{\n    linter::{EarlyLintPass, LintContext, Suggestion},\n    sol::{Severity, SolLint},\n};\nuse solar::ast::{VarMut, VariableDefinition};\n\ndeclare_forge_lint!(\n    SCREAMING_SNAKE_CASE_CONSTANT,\n    Severity::Info,\n    \"screaming-snake-case-const\",\n    \"constants should use SCREAMING_SNAKE_CASE\"\n);\n\ndeclare_forge_lint!(\n    SCREAMING_SNAKE_CASE_IMMUTABLE,\n    Severity::Info,\n    \"screaming-snake-case-immutable\",\n    \"immutables should use SCREAMING_SNAKE_CASE\"\n);\n\nimpl<'ast> EarlyLintPass<'ast> for ScreamingSnakeCase {\n    fn check_variable_definition(\n        &mut self,\n        ctx: &LintContext,\n        var: &'ast VariableDefinition<'ast>,\n    ) {\n        if let (Some(name), Some(mutability)) = (var.name, var.mutability)\n            && let Some(expected) = check_screaming_snake_case(name.as_str())\n        {\n            let suggestion = Suggestion::fix(\n                expected,\n                solar::interface::diagnostics::Applicability::MachineApplicable,\n            )\n            .with_desc(\"consider using\");\n\n            match mutability {\n                VarMut::Constant => {\n                    ctx.emit_with_suggestion(&SCREAMING_SNAKE_CASE_CONSTANT, name.span, suggestion)\n                }\n                VarMut::Immutable => {\n                    ctx.emit_with_suggestion(&SCREAMING_SNAKE_CASE_IMMUTABLE, name.span, suggestion)\n                }\n            }\n        }\n    }\n}\n\n/// If the string `s` is not SCREAMING_SNAKE_CASE, returns a `Some(String)` with the suggested\n/// conversion. Otherwise, returns `None`.\npub fn check_screaming_snake_case(s: &str) -> Option<String> {\n    if s.len() <= 1 {\n        return None;\n    }\n\n    // Handle leading/trailing underscores like `heck` does\n    let expected = format!(\n        \"{prefix}{name}{suffix}\",\n        prefix = if s.starts_with(\"_\") { \"_\" } else { \"\" },\n        name = heck::AsShoutySnakeCase(s),\n        suffix = if s.ends_with(\"_\") { \"_\" } else { \"\" }\n    );\n    if s == expected { None } else { Some(expected) }\n}\n"
  },
  {
    "path": "crates/lint/src/sol/info/unsafe_cheatcodes.rs",
    "content": "use super::UnsafeCheatcodes;\nuse crate::{\n    linter::{EarlyLintPass, LintContext},\n    sol::{Severity, SolLint},\n};\nuse solar::ast::{Expr, ExprKind};\n\ndeclare_forge_lint!(\n    UNSAFE_CHEATCODE_USAGE,\n    Severity::Info,\n    \"unsafe-cheatcode\",\n    \"usage of unsafe cheatcodes that can perform dangerous operations\"\n);\n\nconst UNSAFE_CHEATCODES: [&str; 9] = [\n    \"ffi\",\n    \"readFile\",\n    \"readLine\",\n    \"writeFile\",\n    \"writeLine\",\n    \"removeFile\",\n    \"closeFile\",\n    \"setEnv\",\n    \"deriveKey\",\n];\n\nimpl<'ast> EarlyLintPass<'ast> for UnsafeCheatcodes {\n    fn check_expr(&mut self, ctx: &LintContext, expr: &'ast Expr<'ast>) {\n        if let ExprKind::Call(lhs, _args) = &expr.kind\n            && let ExprKind::Member(_lhs, member) = &lhs.kind\n            && UNSAFE_CHEATCODES.iter().any(|&c| c == member.as_str())\n        {\n            ctx.emit(&UNSAFE_CHEATCODE_USAGE, member.span);\n        }\n    }\n}\n"
  },
  {
    "path": "crates/lint/src/sol/macros.rs",
    "content": "/// Macro for defining lints and relevant metadata for the Solidity linter.\n///\n/// # Parameters\n///\n/// Each lint requires the following input fields:\n/// - `$id`: Identifier of the generated `SolLint` constant.\n/// - `$severity`: The `Severity` of the lint (e.g. `High`, `Med`, `Low`, `Info`, `Gas`).\n/// - `$str_id`: A unique identifier used to reference a specific lint during configuration.\n/// - `$desc`: A short description of the lint.\n///\n/// # Note\n/// Each lint must have a `help` section in the foundry book. This help field is auto-generated by\n/// the macro. Because of that, to ensure that new lint rules have their corresponding docs in the\n/// book, the existence of the lint rule's help section is validated with a unit test.\n#[macro_export]\nmacro_rules! declare_forge_lint {\n    ($id:ident, $severity:expr, $str_id:expr, $desc:expr) => {\n        // Declare the static `Lint` metadata\n        pub static $id: SolLint = SolLint {\n            id: $str_id,\n            severity: $severity,\n            description: $desc,\n            help: concat!(\"https://book.getfoundry.sh/reference/forge/forge-lint#\", $str_id),\n        };\n    };\n}\n\n/// Registers Solidity linter passes that can have both early and late variants.\n///\n/// # Parameters\n///\n/// Each pass is declared with:\n/// - `$pass_id`: Identifier of the generated struct that will implement the pass trait(s).\n/// - `$pass_type`: Either `early`, `late`, or `both` to indicate which traits to implement.\n/// - `$lints`: A parenthesized, comma-separated list of `SolLint` constants.\n///\n/// # Outputs\n///\n/// - Structs for each linting pass\n/// - Helper methods to create early and late passes with required lifetimes\n/// - `const REGISTERED_LINTS` containing all registered lint objects\n#[macro_export]\nmacro_rules! register_lints {\n    // 1. Internal rule for declaring structs and their associated lints.\n    ( @declare_structs $( ($pass_id:ident, $pass_type:ident, ($($lint:expr),* $(,)?)) ),* $(,)? ) => {\n        $(\n            #[derive(Debug, Default, Clone, Copy, Eq, PartialEq)]\n            pub struct $pass_id;\n\n            impl $pass_id {\n                /// Static slice of lints associated with this pass.\n                const LINTS: &'static [SolLint] = &[$($lint),*];\n\n                register_lints!(@early_impl $pass_id, $pass_type);\n                register_lints!(@late_impl $pass_id, $pass_type);\n            }\n        )*\n    };\n\n    // 2. Internal rule for declaring the const array of ALL lints.\n    ( @declare_consts $( ($pass_id:ident, $pass_type:ident, ($($lint:expr),* $(,)?)) ),* $(,)? ) => {\n        pub const REGISTERED_LINTS: &[SolLint] = &[\n            $(\n                $($lint,)*\n            )*\n        ];\n    };\n\n    // 3. Internal rule for declaring the helper functions.\n    ( @declare_funcs $( ($pass_id:ident, $pass_type:ident, $lints:tt) ),* $(,)? ) => {\n        pub fn create_early_lint_passes<'ast>() -> Vec<(Box<dyn EarlyLintPass<'ast>>, &'static [SolLint])> {\n            [\n                $(\n                    register_lints!(@early_create $pass_id, $pass_type),\n                )*\n            ]\n            .into_iter()\n            .flatten()\n            .collect()\n        }\n\n        pub fn create_late_lint_passes<'hir>() -> Vec<(Box<dyn LateLintPass<'hir>>, &'static [SolLint])> {\n            [\n                $(\n                    register_lints!(@late_create $pass_id, $pass_type),\n                )*\n            ]\n            .into_iter()\n            .flatten()\n            .collect()\n        }\n    };\n\n    // --- HELPERS ------------------------------------------------------------\n    (@early_impl $_pass_id:ident, late) => {};\n    (@early_impl $pass_id:ident, $other:ident) => {\n        pub fn as_early_lint_pass<'a>() -> Box<dyn EarlyLintPass<'a>> {\n            Box::new(Self::default())\n        }\n    };\n\n    (@late_impl $_pass_id:ident, early) => {};\n    (@late_impl $pass_id:ident, $other:ident) => {\n        pub fn as_late_lint_pass<'hir>() -> Box<dyn LateLintPass<'hir>> {\n            Box::new(Self::default())\n        }\n    };\n\n    (@early_create $_pass_id:ident, late) => { None };\n    (@early_create $pass_id:ident, $_other:ident) => {\n        Some(($pass_id::as_early_lint_pass(), $pass_id::LINTS))\n    };\n\n    (@late_create $_pass_id:ident, early) => { None };\n    (@late_create $pass_id:ident, $_other:ident) => {\n        Some(($pass_id::as_late_lint_pass(), $pass_id::LINTS))\n    };\n\n    // --- ENTRY POINT ---------------------------------------------------------\n    ( $($tokens:tt)* ) => {\n        register_lints! { @declare_structs $($tokens)* }\n        register_lints! { @declare_consts  $($tokens)* }\n        register_lints! { @declare_funcs   $($tokens)* }\n    };\n}\n"
  },
  {
    "path": "crates/lint/src/sol/med/div_mul.rs",
    "content": "use super::DivideBeforeMultiply;\nuse crate::{\n    linter::{EarlyLintPass, LintContext},\n    sol::{Severity, SolLint},\n};\nuse solar::{\n    ast::{BinOp, BinOpKind, Expr, ExprKind},\n    interface::SpannedOption,\n};\n\ndeclare_forge_lint!(\n    DIVIDE_BEFORE_MULTIPLY,\n    Severity::Med,\n    \"divide-before-multiply\",\n    \"multiplication should occur before division to avoid loss of precision\"\n);\n\nimpl<'ast> EarlyLintPass<'ast> for DivideBeforeMultiply {\n    fn check_expr(&mut self, ctx: &LintContext, expr: &'ast Expr<'ast>) {\n        if let ExprKind::Binary(left_expr, BinOp { kind: BinOpKind::Mul, .. }, _) = &expr.kind\n            && contains_division(left_expr)\n        {\n            ctx.emit(&DIVIDE_BEFORE_MULTIPLY, expr.span);\n        }\n    }\n}\n\nfn contains_division<'ast>(expr: &'ast Expr<'ast>) -> bool {\n    match &expr.kind {\n        ExprKind::Binary(_, BinOp { kind: BinOpKind::Div, .. }, _) => true,\n        ExprKind::Tuple(inner_exprs) => inner_exprs.iter().any(|opt_expr| {\n            if let SpannedOption::Some(inner_expr) = opt_expr.as_ref() {\n                contains_division(inner_expr)\n            } else {\n                false\n            }\n        }),\n        _ => false,\n    }\n}\n"
  },
  {
    "path": "crates/lint/src/sol/med/mod.rs",
    "content": "use crate::sol::{EarlyLintPass, LateLintPass, SolLint};\n\nmod div_mul;\nuse div_mul::DIVIDE_BEFORE_MULTIPLY;\n\nmod unsafe_typecast;\nuse unsafe_typecast::UNSAFE_TYPECAST;\n\nregister_lints!(\n    (DivideBeforeMultiply, early, (DIVIDE_BEFORE_MULTIPLY)),\n    (UnsafeTypecast, late, (UNSAFE_TYPECAST))\n);\n"
  },
  {
    "path": "crates/lint/src/sol/med/unsafe_typecast.rs",
    "content": "use super::UnsafeTypecast;\nuse crate::{\n    linter::{LateLintPass, LintContext, Suggestion},\n    sol::{Severity, SolLint},\n};\nuse solar::{\n    ast::{LitKind, StrKind},\n    sema::hir::{self, ElementaryType, ExprKind, ItemId, Res, TypeKind},\n};\n\ndeclare_forge_lint!(\n    UNSAFE_TYPECAST,\n    Severity::Med,\n    \"unsafe-typecast\",\n    \"typecasts that can truncate values should be checked\"\n);\n\nimpl<'hir> LateLintPass<'hir> for UnsafeTypecast {\n    fn check_expr(\n        &mut self,\n        ctx: &LintContext,\n        hir: &'hir hir::Hir<'hir>,\n        expr: &'hir hir::Expr<'hir>,\n    ) {\n        // Check for type cast expressions: Type(value)\n        if let ExprKind::Call(call, args, _) = &expr.kind\n            && let ExprKind::Type(hir::Type { kind: TypeKind::Elementary(ty), .. }) = &call.kind\n            && args.len() == 1\n            && let Some(call_arg) = args.exprs().next()\n            && is_unsafe_typecast_hir(hir, call_arg, ty)\n        {\n            ctx.emit_with_suggestion(\n                &UNSAFE_TYPECAST,\n                expr.span,\n                Suggestion::example(\n                    format!(\n                        \"// casting to '{abi_ty}' is safe because [explain why]\\n// forge-lint: disable-next-line(unsafe-typecast)\",\n                        abi_ty = ty.to_abi_str()\n            )).with_desc(\"consider disabling this lint if you're certain the cast is safe\"));\n        }\n    }\n}\n\n/// Determines if a typecast is potentially unsafe (could lose data or precision).\nfn is_unsafe_typecast_hir(\n    hir: &hir::Hir<'_>,\n    source_expr: &hir::Expr<'_>,\n    target_type: &hir::ElementaryType,\n) -> bool {\n    let mut source_types = Vec::<ElementaryType>::new();\n    infer_source_types(Some(&mut source_types), hir, source_expr);\n\n    if source_types.is_empty() {\n        return false;\n    };\n\n    source_types.iter().any(|source_ty| is_unsafe_elementary_typecast(source_ty, target_type))\n}\n\n/// Infers the elementary source type(s) of an expression.\n///\n/// This function traverses an expression tree to find the original \"source\" types.\n/// For cast chains, it returns the ultimate source type, not intermediate cast results.\n/// For binary operations, it collects types from both sides into the `output` vector.\n///\n/// # Returns\n/// An `Option<ElementaryType>` containing the inferred type of the expression if it can be\n/// resolved to a single source (like variables, literals, or unary expressions).\n/// Returns `None` for expressions complex expressions (like binary operations).\nfn infer_source_types(\n    mut output: Option<&mut Vec<ElementaryType>>,\n    hir: &hir::Hir<'_>,\n    expr: &hir::Expr<'_>,\n) -> Option<ElementaryType> {\n    let mut track = |ty: ElementaryType| -> Option<ElementaryType> {\n        if let Some(output) = output.as_mut() {\n            output.push(ty);\n        }\n        Some(ty)\n    };\n\n    match &expr.kind {\n        // A type cast call: `Type(val)`\n        ExprKind::Call(call_expr, args, ..) => {\n            // Check if the called expression is a type, which indicates a cast.\n            if let ExprKind::Type(hir::Type { kind: TypeKind::Elementary(..), .. }) =\n                &call_expr.kind\n                && let Some(inner) = args.exprs().next()\n            {\n                // Recurse to find the original (inner-most) source type.\n                return infer_source_types(output, hir, inner);\n            }\n            None\n        }\n\n        // Identifiers (variables)\n        ExprKind::Ident(resolutions) => {\n            if let Some(Res::Item(ItemId::Variable(var_id))) = resolutions.first() {\n                let variable = hir.variable(*var_id);\n                if let TypeKind::Elementary(elem_type) = &variable.ty.kind {\n                    return track(*elem_type);\n                }\n            }\n            None\n        }\n\n        // Handle literal values\n        ExprKind::Lit(hir::Lit { kind, .. }) => match kind {\n            LitKind::Str(StrKind::Hex, ..) => track(ElementaryType::Bytes),\n            LitKind::Str(..) => track(ElementaryType::String),\n            LitKind::Address(_) => track(ElementaryType::Address(false)),\n            LitKind::Bool(_) => track(ElementaryType::Bool),\n            // Unnecessary to check numbers as assigning literal values that cannot fit into a type\n            // throws a compiler error. Reference: <https://solang.readthedocs.io/en/latest/language/types.html>\n            _ => None,\n        },\n\n        // Unary operations: Recurse to find the source type of the inner expression.\n        ExprKind::Unary(_, inner_expr) => infer_source_types(output, hir, inner_expr),\n\n        // Binary operations\n        ExprKind::Binary(lhs, _, rhs) => {\n            if let Some(mut output) = output {\n                // Recurse on both sides to find and collect all source types.\n                infer_source_types(Some(&mut output), hir, lhs);\n                infer_source_types(Some(&mut output), hir, rhs);\n            }\n            None\n        }\n\n        // Complex expressions are not evaluated\n        _ => None,\n    }\n}\n\n/// Checks if a type cast from source_type to target_type is unsafe.\nfn is_unsafe_elementary_typecast(\n    source_type: &ElementaryType,\n    target_type: &ElementaryType,\n) -> bool {\n    match (source_type, target_type) {\n        // Numeric downcasts (smaller target size)\n        (ElementaryType::UInt(source_size), ElementaryType::UInt(target_size))\n        | (ElementaryType::Int(source_size), ElementaryType::Int(target_size)) => {\n            source_size.bits() > target_size.bits()\n        }\n\n        // Signed to unsigned conversion (potential loss of sign)\n        (ElementaryType::Int(_), ElementaryType::UInt(_)) => true,\n\n        // Unsigned to signed conversion with same or smaller size\n        (ElementaryType::UInt(source_size), ElementaryType::Int(target_size)) => {\n            source_size.bits() >= target_size.bits()\n        }\n\n        // Fixed bytes to smaller fixed bytes\n        (ElementaryType::FixedBytes(source_size), ElementaryType::FixedBytes(target_size)) => {\n            source_size.bytes() > target_size.bytes()\n        }\n\n        // Dynamic bytes to fixed bytes (potential truncation)\n        (ElementaryType::Bytes, ElementaryType::FixedBytes(_))\n        | (ElementaryType::String, ElementaryType::FixedBytes(_)) => true,\n\n        // Address to smaller uint (truncation) - address is 160 bits\n        (ElementaryType::Address(_), ElementaryType::UInt(target_size)) => target_size.bits() < 160,\n\n        // Address to int (sign issues)\n        (ElementaryType::Address(_), ElementaryType::Int(_)) => true,\n\n        _ => false,\n    }\n}\n"
  },
  {
    "path": "crates/lint/src/sol/mod.rs",
    "content": "use crate::linter::{\n    EarlyLintPass, EarlyLintVisitor, LateLintPass, LateLintVisitor, Lint, LintContext, Linter,\n    LinterConfig,\n};\nuse foundry_common::{\n    comments::{\n        Comments,\n        inline_config::{InlineConfig, InlineConfigItem},\n    },\n    errors::convert_solar_errors,\n    sh_warn,\n};\nuse foundry_compilers::{ProjectPathsConfig, solc::SolcLanguage};\nuse foundry_config::{\n    DenyLevel,\n    lint::{LintSpecificConfig, Severity},\n};\nuse rayon::prelude::*;\nuse solar::{\n    ast::{self as ast, visit::Visit as _},\n    interface::{\n        Session,\n        diagnostics::{self, HumanEmitter, JsonEmitter},\n    },\n    sema::{\n        Compiler, Gcx,\n        hir::{self, Visit as _},\n    },\n};\nuse std::{\n    path::{Path, PathBuf},\n    sync::LazyLock,\n};\nuse thiserror::Error;\n\n#[macro_use]\npub mod macros;\n\npub mod codesize;\npub mod gas;\npub mod high;\npub mod info;\npub mod med;\n\nstatic ALL_REGISTERED_LINTS: LazyLock<Vec<&'static str>> = LazyLock::new(|| {\n    let mut lints = Vec::new();\n    lints.extend_from_slice(high::REGISTERED_LINTS);\n    lints.extend_from_slice(med::REGISTERED_LINTS);\n    lints.extend_from_slice(info::REGISTERED_LINTS);\n    lints.extend_from_slice(gas::REGISTERED_LINTS);\n    lints.extend_from_slice(codesize::REGISTERED_LINTS);\n    lints.into_iter().map(|lint| lint.id()).collect()\n});\n\nstatic DEFAULT_LINT_SPECIFIC_CONFIG: LazyLock<LintSpecificConfig> =\n    LazyLock::new(LintSpecificConfig::default);\n\n/// Linter implementation to analyze Solidity source code responsible for identifying\n/// vulnerabilities gas optimizations, and best practices.\n#[derive(Debug)]\npub struct SolidityLinter<'a> {\n    path_config: ProjectPathsConfig,\n    severity: Option<Vec<Severity>>,\n    lints_included: Option<Vec<SolLint>>,\n    lints_excluded: Option<Vec<SolLint>>,\n    with_description: bool,\n    with_json_emitter: bool,\n    // lint-specific configuration\n    lint_specific: &'a LintSpecificConfig,\n}\n\nimpl<'a> SolidityLinter<'a> {\n    pub fn new(path_config: ProjectPathsConfig) -> Self {\n        Self {\n            path_config,\n            with_description: true,\n            severity: None,\n            lints_included: None,\n            lints_excluded: None,\n            with_json_emitter: false,\n            lint_specific: &DEFAULT_LINT_SPECIFIC_CONFIG,\n        }\n    }\n\n    pub fn with_severity(mut self, severity: Option<Vec<Severity>>) -> Self {\n        self.severity = severity;\n        self\n    }\n\n    pub fn with_lints(mut self, lints: Option<Vec<SolLint>>) -> Self {\n        self.lints_included = lints;\n        self\n    }\n\n    pub fn without_lints(mut self, lints: Option<Vec<SolLint>>) -> Self {\n        self.lints_excluded = lints;\n        self\n    }\n\n    pub fn with_description(mut self, with: bool) -> Self {\n        self.with_description = with;\n        self\n    }\n\n    pub fn with_json_emitter(mut self, with: bool) -> Self {\n        self.with_json_emitter = with;\n        self\n    }\n\n    pub fn with_lint_specific(mut self, lint_specific: &'a LintSpecificConfig) -> Self {\n        self.lint_specific = lint_specific;\n        self\n    }\n\n    fn config(&'a self, inline: &'a InlineConfig<Vec<String>>) -> LinterConfig<'a> {\n        LinterConfig { inline, lint_specific: self.lint_specific }\n    }\n\n    fn include_lint(&self, lint: SolLint) -> bool {\n        self.severity.as_ref().is_none_or(|sev| sev.contains(&lint.severity()))\n            && self.lints_included.as_ref().is_none_or(|incl| incl.contains(&lint))\n            && !self.lints_excluded.as_ref().is_some_and(|excl| excl.contains(&lint))\n    }\n\n    fn process_source_ast<'gcx>(\n        &self,\n        sess: &'gcx Session,\n        ast: &'gcx ast::SourceUnit<'gcx>,\n        path: &Path,\n        inline_config: &InlineConfig<Vec<String>>,\n    ) -> Result<(), diagnostics::ErrorGuaranteed> {\n        // Declare all available passes and lints\n        let mut passes_and_lints = Vec::new();\n        passes_and_lints.extend(high::create_early_lint_passes());\n        passes_and_lints.extend(med::create_early_lint_passes());\n        passes_and_lints.extend(info::create_early_lint_passes());\n\n        // Do not apply 'gas' and 'codesize' severity rules on tests and scripts\n        if !self.path_config.is_test_or_script(path) {\n            passes_and_lints.extend(gas::create_early_lint_passes());\n            passes_and_lints.extend(codesize::create_early_lint_passes());\n        }\n\n        // Filter passes based on linter config\n        let (mut passes, lints): (Vec<Box<dyn EarlyLintPass<'_>>>, Vec<_>) = passes_and_lints\n            .into_iter()\n            .fold((Vec::new(), Vec::new()), |(mut passes, mut ids), (pass, lints)| {\n                let included_ids: Vec<_> = lints\n                    .iter()\n                    .filter_map(|lint| if self.include_lint(*lint) { Some(lint.id) } else { None })\n                    .collect();\n\n                if !included_ids.is_empty() {\n                    passes.push(pass);\n                    ids.extend(included_ids);\n                }\n\n                (passes, ids)\n            });\n\n        // Initialize and run the early lint visitor\n        let ctx = LintContext::new(\n            sess,\n            self.with_description,\n            self.with_json_emitter,\n            self.config(inline_config),\n            lints,\n        );\n        let mut early_visitor = EarlyLintVisitor::new(&ctx, &mut passes);\n        _ = early_visitor.visit_source_unit(ast);\n        early_visitor.post_source_unit(ast);\n\n        Ok(())\n    }\n\n    fn process_source_hir<'gcx>(\n        &self,\n        gcx: Gcx<'gcx>,\n        source_id: hir::SourceId,\n        path: &Path,\n        inline_config: &InlineConfig<Vec<String>>,\n    ) -> Result<(), diagnostics::ErrorGuaranteed> {\n        // Declare all available passes and lints\n        let mut passes_and_lints = Vec::new();\n        passes_and_lints.extend(high::create_late_lint_passes());\n        passes_and_lints.extend(med::create_late_lint_passes());\n        passes_and_lints.extend(info::create_late_lint_passes());\n\n        // Do not apply 'gas' and 'codesize' severity rules on tests and scripts\n        if !self.path_config.is_test_or_script(path) {\n            passes_and_lints.extend(gas::create_late_lint_passes());\n            passes_and_lints.extend(codesize::create_late_lint_passes());\n        }\n\n        // Filter passes based on config\n        let (mut passes, lints): (Vec<Box<dyn LateLintPass<'_>>>, Vec<_>) = passes_and_lints\n            .into_iter()\n            .fold((Vec::new(), Vec::new()), |(mut passes, mut ids), (pass, lints)| {\n                let included_ids: Vec<_> = lints\n                    .iter()\n                    .filter_map(|lint| if self.include_lint(*lint) { Some(lint.id) } else { None })\n                    .collect();\n\n                if !included_ids.is_empty() {\n                    passes.push(pass);\n                    ids.extend(included_ids);\n                }\n\n                (passes, ids)\n            });\n\n        // Run late lint visitor\n        let ctx = LintContext::new(\n            gcx.sess,\n            self.with_description,\n            self.with_json_emitter,\n            self.config(inline_config),\n            lints,\n        );\n        let mut late_visitor = LateLintVisitor::new(&ctx, &mut passes, &gcx.hir);\n\n        // Visit this specific source\n        let _ = late_visitor.visit_nested_source(source_id);\n\n        Ok(())\n    }\n}\n\nimpl<'a> Linter for SolidityLinter<'a> {\n    type Language = SolcLanguage;\n    type Lint = SolLint;\n\n    fn lint(\n        &self,\n        input: &[PathBuf],\n        deny: DenyLevel,\n        compiler: &mut Compiler,\n    ) -> eyre::Result<()> {\n        convert_solar_errors(compiler.dcx())?;\n\n        // Cache diagnostic count before linting to isolate from the build phase.\n        let warn_count_before = compiler.dcx().warn_count();\n        let note_count_before = compiler.dcx().note_count();\n\n        let ui_testing = std::env::var_os(\"FOUNDRY_LINT_UI_TESTING\").is_some();\n\n        let sm = compiler.sess().clone_source_map();\n        let prev_emitter = compiler.dcx().set_emitter(if self.with_json_emitter {\n            let writer = Box::new(std::io::BufWriter::new(std::io::stderr()));\n            let json_emitter = JsonEmitter::new(writer, sm).rustc_like(true).ui_testing(ui_testing);\n            Box::new(json_emitter)\n        } else {\n            Box::new(HumanEmitter::stderr(Default::default()).source_map(Some(sm)))\n        });\n        let sess = compiler.sess_mut();\n        sess.dcx.set_flags_mut(|f| f.track_diagnostics = false);\n        if ui_testing {\n            sess.opts.unstable.ui_testing = true;\n            sess.reconfigure();\n        }\n\n        compiler.enter_mut(|compiler| -> eyre::Result<()> {\n            if compiler.gcx().stage() < Some(solar::config::CompilerStage::Lowering) {\n                let _ = compiler.lower_asts();\n            }\n\n            let gcx = compiler.gcx();\n\n            input.par_iter().for_each(|path| {\n                let path = &self.path_config.root.join(path);\n                let Some((_, ast_source)) = gcx.get_ast_source(path) else {\n                    // issue a warning rather than panicking, in case that some (but not all) of the\n                    // input files have old solidity versions which are not supported by solar.\n                    _ = sh_warn!(\"AST source not found for {}\", path.display());\n                    return;\n                };\n                let Some(ast) = &ast_source.ast else {\n                    panic!(\"AST missing for {}\", path.display());\n                };\n\n                // Parse inline config.\n                let file = &ast_source.file;\n                let comments = Comments::new(file, gcx.sess.source_map(), false, false, None);\n                let inline_config = parse_inline_config(gcx.sess, &comments, ast);\n\n                // Early lints.\n                let _ = self.process_source_ast(gcx.sess, ast, path, &inline_config);\n\n                // Late lints.\n                let Some((hir_source_id, _)) = gcx.get_hir_source(path) else {\n                    panic!(\"HIR source not found for {}\", path.display());\n                };\n                let _ = self.process_source_hir(gcx, hir_source_id, path, &inline_config);\n            });\n\n            convert_solar_errors(compiler.dcx())\n        })?;\n\n        let sess = compiler.sess_mut();\n        sess.dcx.set_emitter(prev_emitter);\n        if ui_testing {\n            sess.opts.unstable.ui_testing = false;\n            sess.reconfigure();\n        }\n\n        let lint_warn_count = compiler.dcx().warn_count().saturating_sub(warn_count_before);\n        let lint_note_count = compiler.dcx().note_count().saturating_sub(note_count_before);\n\n        const MSG: &str = \"aborting due to \";\n        match (deny, lint_warn_count, lint_note_count) {\n            // Deny warnings.\n            (DenyLevel::Warnings, w, n) if w > 0 => {\n                if n > 0 {\n                    Err(eyre::eyre!(\"{MSG}{w} linter warning(s); {n} note(s) were also emitted\\n\"))\n                } else {\n                    Err(eyre::eyre!(\"{MSG}{w} linter warning(s)\\n\"))\n                }\n            }\n\n            // Deny any diagnostic.\n            (DenyLevel::Notes, w, n) if w > 0 || n > 0 => match (w, n) {\n                (w, n) if w > 0 && n > 0 => {\n                    Err(eyre::eyre!(\"{MSG}{w} linter warning(s) and {n} note(s)\\n\"))\n                }\n                (w, 0) => Err(eyre::eyre!(\"{MSG}{w} linter warning(s)\\n\")),\n                (0, n) => Err(eyre::eyre!(\"{MSG}{n} linter note(s)\\n\")),\n                _ => unreachable!(),\n            },\n\n            // Otherwise, succeed.\n            _ => Ok(()),\n        }\n    }\n}\n\nfn parse_inline_config<'ast>(\n    sess: &Session,\n    comments: &Comments,\n    ast: &'ast ast::SourceUnit<'ast>,\n) -> InlineConfig<Vec<String>> {\n    let items = comments.iter().filter_map(|comment| {\n        let mut item = comment.lines.first()?.as_str();\n        if let Some(prefix) = comment.prefix() {\n            item = item.strip_prefix(prefix).unwrap_or(item);\n        }\n        if let Some(suffix) = comment.suffix() {\n            item = item.strip_suffix(suffix).unwrap_or(item);\n        }\n        let item = item.trim_start().strip_prefix(\"forge-lint:\")?.trim();\n        let span = comment.span;\n        match InlineConfigItem::parse(item, &ALL_REGISTERED_LINTS) {\n            Ok(item) => Some((span, item)),\n            Err(e) => {\n                sess.dcx.warn(e.to_string()).span(span).emit();\n                None\n            }\n        }\n    });\n\n    InlineConfig::from_ast(items, ast, sess.source_map())\n}\n\n#[derive(Error, Debug)]\npub enum SolLintError {\n    #[error(\"Unknown lint ID: {0}\")]\n    InvalidId(String),\n}\n\n#[derive(Debug, Clone, Copy, Eq, PartialEq)]\npub struct SolLint {\n    id: &'static str,\n    description: &'static str,\n    help: &'static str,\n    severity: Severity,\n}\n\nimpl Lint for SolLint {\n    fn id(&self) -> &'static str {\n        self.id\n    }\n    fn severity(&self) -> Severity {\n        self.severity\n    }\n    fn description(&self) -> &'static str {\n        self.description\n    }\n    fn help(&self) -> &'static str {\n        self.help\n    }\n}\n\nimpl<'a> TryFrom<&'a str> for SolLint {\n    type Error = SolLintError;\n\n    fn try_from(value: &'a str) -> Result<Self, Self::Error> {\n        for &lint in high::REGISTERED_LINTS {\n            if lint.id() == value {\n                return Ok(lint);\n            }\n        }\n\n        for &lint in med::REGISTERED_LINTS {\n            if lint.id() == value {\n                return Ok(lint);\n            }\n        }\n\n        for &lint in info::REGISTERED_LINTS {\n            if lint.id() == value {\n                return Ok(lint);\n            }\n        }\n\n        for &lint in gas::REGISTERED_LINTS {\n            if lint.id() == value {\n                return Ok(lint);\n            }\n        }\n\n        for &lint in codesize::REGISTERED_LINTS {\n            if lint.id() == value {\n                return Ok(lint);\n            }\n        }\n\n        Err(SolLintError::InvalidId(value.to_string()))\n    }\n}\n"
  },
  {
    "path": "crates/lint/testdata/.gitignore",
    "content": "cache/\nout/\n"
  },
  {
    "path": "crates/lint/testdata/CustomErrors.sol",
    "content": "//@compile-flags: --severity gas\n\n// SPDX-License-Identifier: MIT\npragma solidity ^0.8.18;\n\nerror CustomError();\nerror CustomErrorWithArg(uint256 value);\nerror CustomErrorWithNamedArgs(uint256 x, string message);\n\ncontract CustomErrors {\n    // Require examples\n    function requireWithString(uint256 a, uint256 b) public pure {\n        require(a > 0, \"Value must be greater than zero\"); //~NOTE: prefer using custom errors on revert and require calls\n        require(a >= 0 && a <= 100 || b == 50, \"Complex condition should be linted\"); //~NOTE: prefer using custom errors on revert and require calls\n    }\n\n    // Revert examples\n    function revertWithString() public pure {\n        revert(\"Something went wrong\"); //~NOTE: prefer using custom errors on revert and require calls\n        revert(\"\"); //~NOTE: prefer using custom errors on revert and require calls\n        revert(); //~NOTE: prefer using custom errors on revert and require calls\n    }\n\n    // Custom error examples\n    function customErrors(uint256 value) public pure {\n        require(value > 0, CustomError());\n        require(value < 100, CustomErrorWithArg(value));\n        require(value > 0);\n        revert CustomError();\n        revert CustomErrorWithArg(value);\n        revert CustomErrorWithNamedArgs({x: value, message: \"test\"});\n    }\n\n    // Test inline disable\n    function testDisableShouldNotLint() public pure {\n        // forge-lint: disable-next-line(custom-errors)\n        require(true, \"This should not lint\");\n        // forge-lint: disable-next-line(custom-errors)\n        revert(\"This should not lint\");\n    }\n}\n\n"
  },
  {
    "path": "crates/lint/testdata/CustomErrors.stderr",
    "content": "note[custom-errors]: prefer using custom errors on revert and require calls\n   ╭▸ ROOT/testdata/CustomErrors.sol:LL:CC\n   │\nLL │         require(a > 0, \"Value must be greater than zero\");\n   │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#custom-errors\n\nnote[custom-errors]: prefer using custom errors on revert and require calls\n   ╭▸ ROOT/testdata/CustomErrors.sol:LL:CC\n   │\nLL │ …     require(a >= 0 && a <= 100 || b == 50, \"Complex condition should be linted\");\n   │       ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#custom-errors\n\nnote[custom-errors]: prefer using custom errors on revert and require calls\n   ╭▸ ROOT/testdata/CustomErrors.sol:LL:CC\n   │\nLL │         revert(\"Something went wrong\");\n   │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#custom-errors\n\nnote[custom-errors]: prefer using custom errors on revert and require calls\n   ╭▸ ROOT/testdata/CustomErrors.sol:LL:CC\n   │\nLL │         revert(\"\");\n   │         ━━━━━━━━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#custom-errors\n\nnote[custom-errors]: prefer using custom errors on revert and require calls\n   ╭▸ ROOT/testdata/CustomErrors.sol:LL:CC\n   │\nLL │         revert();\n   │         ━━━━━━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#custom-errors\n\n"
  },
  {
    "path": "crates/lint/testdata/DivideBeforeMultiply.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.18;\n\ncontract DivideBeforeMultiply {\n    function arithmetic() public {\n        (1 / 2) * 3; //~WARN: multiplication should occur before division to avoid loss of precision\n        (1 * 2) / 3;\n        ((1 / 2) * 3) * 4; //~WARN: multiplication should occur before division to avoid loss of precision\n        ((1 * 2) / 3) * 4; //~WARN: multiplication should occur before division to avoid loss of precision\n        (1 / 2 / 3) * 4; //~WARN: multiplication should occur before division to avoid loss of precision\n        (1 / (2 + 3)) * 4; //~WARN: multiplication should occur before division to avoid loss of precision\n        (1 / 2 + 3) * 4;\n        (1 / 2 - 3) * 4;\n        (1 + 2 / 3) * 4;\n        (1 / 2 - 3) * 4;\n        ((1 / 2) % 3) * 4;\n        1 / (2 * 3 + 3);\n        1 / ((2 / 3) * 3); //~WARN: multiplication should occur before division to avoid loss of precision\n        1 / ((2 * 3) + 3);\n    }\n}\n"
  },
  {
    "path": "crates/lint/testdata/DivideBeforeMultiply.stderr",
    "content": "warning[divide-before-multiply]: multiplication should occur before division to avoid loss of precision\n   ╭▸ ROOT/testdata/DivideBeforeMultiply.sol:LL:CC\n   │\nLL │         (1 / 2) * 3;\n   │         ━━━━━━━━━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#divide-before-multiply\n\nwarning[divide-before-multiply]: multiplication should occur before division to avoid loss of precision\n   ╭▸ ROOT/testdata/DivideBeforeMultiply.sol:LL:CC\n   │\nLL │         ((1 / 2) * 3) * 4;\n   │          ━━━━━━━━━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#divide-before-multiply\n\nwarning[divide-before-multiply]: multiplication should occur before division to avoid loss of precision\n   ╭▸ ROOT/testdata/DivideBeforeMultiply.sol:LL:CC\n   │\nLL │         ((1 * 2) / 3) * 4;\n   │         ━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#divide-before-multiply\n\nwarning[divide-before-multiply]: multiplication should occur before division to avoid loss of precision\n   ╭▸ ROOT/testdata/DivideBeforeMultiply.sol:LL:CC\n   │\nLL │         (1 / 2 / 3) * 4;\n   │         ━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#divide-before-multiply\n\nwarning[divide-before-multiply]: multiplication should occur before division to avoid loss of precision\n   ╭▸ ROOT/testdata/DivideBeforeMultiply.sol:LL:CC\n   │\nLL │         (1 / (2 + 3)) * 4;\n   │         ━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#divide-before-multiply\n\nwarning[divide-before-multiply]: multiplication should occur before division to avoid loss of precision\n   ╭▸ ROOT/testdata/DivideBeforeMultiply.sol:LL:CC\n   │\nLL │         1 / ((2 / 3) * 3);\n   │              ━━━━━━━━━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#divide-before-multiply\n\n"
  },
  {
    "path": "crates/lint/testdata/Imports.sol",
    "content": "//@compile-flags: --severity info\n\n// SPDX-License-Identifier: MIT\npragma solidity ^0.8.18;\n\nimport {\n    symbol0 as mySymbol,\n    symbol1 as myOtherSymbol,\n    symbol2 as notUsed, //~NOTE: unused imports should be removed\n    symbol3,\n    symbol4,\n    symbol5,\n    docSymbol,\n    docSymbol2,\n    docSymbolWrongTag, //~NOTE: unused imports should be removed\n    eventSymbol,\n    BaseContract,\n    symbolNotUsed, //~NOTE: unused imports should be removed\n    IContract,\n    IContractNotUsed //~NOTE: unused imports should be removed\n} from \"./auxiliary/ImportsFile.sol\";\n\n// forge-lint: disable-next-item\nimport {\n    symbolNotUsed2\n} from \"./auxiliary/ImportsFile.sol\";\n\n// in this case, disabling the following line doesn't do anything\n// forge-lint: disable-next-line\nimport {\n    symbolNotUsed3 //~NOTE: unused imports should be removed\n} from \"./auxiliary/ImportsFile.sol\";\n\nimport {\n    CONSTANT_0,\n    CONSTANT_1 //~NOTE: unused imports should be removed\n} from \"./auxiliary/ImportsConstants.sol\";\n\nimport {\n    MyType,\n    MyOtherType,\n    YetAnotherType //~NOTE: unused imports should be removed\n} from \"./auxiliary/ImportsTypes.sol\";\n\nimport \"./auxiliary/ImportsSomeFile.sol\"; //~NOTE: use named imports '{A, B}' or alias 'import \"..\" as X'\nimport \"./auxiliary/ImportsAnotherFile.sol\"; //~NOTE: use named imports '{A, B}' or alias 'import \"..\" as X'\n\nimport \"./auxiliary/ImportsSomeFile2.sol\" as SomeFile2;\nimport \"./auxiliary/ImportsAnotherFile2.sol\" as AnotherFile2; //~NOTE: unused imports should be removed\n\nimport * as Utils from \"./auxiliary/ImportsUtils.sol\";\nimport * as OtherUtils from \"./auxiliary/ImportsUtils2.sol\"; //~NOTE: unused imports should be removed\n\n\nabstract contract UnusedImport is IContract, BaseContract {\n    using mySymbol for address;\n\n    uint256 constant MY_CONSTANT = CONSTANT_0;\n\n    struct FooBar {\n        symbol3 foo;\n        myOtherSymbol bar;\n    }\n\n    /// @dev docSymbolWrongTag\n    SomeFile.Baz public myStruct;\n    SomeFile2.Baz public myStruct2;\n    symbol4 public myVar;\n\n    function foo(uint256 a, symbol5 b) external override(BaseContract) returns (uint256) {\n        uint256 c = Utils.calculate(a, symbol5.unwrap(b));\n        emit eventSymbol.foo(c);\n        return c;\n    }\n\n    function convert(address addr) public pure returns (MyOtherType) {\n        MyType a = MyType.wrap(123);\n        return MyOtherType.wrap(MyType.unwrap(a));\n    }\n}\n"
  },
  {
    "path": "crates/lint/testdata/Imports.stderr",
    "content": "note[unaliased-plain-import]: use named imports '{A, B}' or alias 'import \"..\" as X'\n   ╭▸ ROOT/testdata/Imports.sol:LL:CC\n   │\nLL │ import \"./auxiliary/ImportsSomeFile.sol\";\n   │        ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unaliased-plain-import\n\nnote[unaliased-plain-import]: use named imports '{A, B}' or alias 'import \"..\" as X'\n   ╭▸ ROOT/testdata/Imports.sol:LL:CC\n   │\nLL │ import \"./auxiliary/ImportsAnotherFile.sol\";\n   │        ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unaliased-plain-import\n\nnote[unused-import]: unused imports should be removed\n   ╭▸ ROOT/testdata/Imports.sol:LL:CC\n   │\nLL │     symbol2 as notUsed,\n   │     ━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unused-import\n\nnote[unused-import]: unused imports should be removed\n   ╭▸ ROOT/testdata/Imports.sol:LL:CC\n   │\nLL │     docSymbol,\n   │     ━━━━━━━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unused-import\n\nnote[unused-import]: unused imports should be removed\n   ╭▸ ROOT/testdata/Imports.sol:LL:CC\n   │\nLL │     docSymbol2,\n   │     ━━━━━━━━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unused-import\n\nnote[unused-import]: unused imports should be removed\n   ╭▸ ROOT/testdata/Imports.sol:LL:CC\n   │\nLL │     docSymbolWrongTag,\n   │     ━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unused-import\n\nnote[unused-import]: unused imports should be removed\n   ╭▸ ROOT/testdata/Imports.sol:LL:CC\n   │\nLL │     symbolNotUsed,\n   │     ━━━━━━━━━━━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unused-import\n\nnote[unused-import]: unused imports should be removed\n   ╭▸ ROOT/testdata/Imports.sol:LL:CC\n   │\nLL │     IContractNotUsed\n   │     ━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unused-import\n\nnote[unused-import]: unused imports should be removed\n   ╭▸ ROOT/testdata/Imports.sol:LL:CC\n   │\nLL │     symbolNotUsed3\n   │     ━━━━━━━━━━━━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unused-import\n\nnote[unused-import]: unused imports should be removed\n   ╭▸ ROOT/testdata/Imports.sol:LL:CC\n   │\nLL │     CONSTANT_1\n   │     ━━━━━━━━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unused-import\n\nnote[unused-import]: unused imports should be removed\n   ╭▸ ROOT/testdata/Imports.sol:LL:CC\n   │\nLL │     YetAnotherType\n   │     ━━━━━━━━━━━━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unused-import\n\nnote[unused-import]: unused imports should be removed\n   ╭▸ ROOT/testdata/Imports.sol:LL:CC\n   │\nLL │ import \"./auxiliary/ImportsAnotherFile2.sol\" as AnotherFile2;\n   │ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unused-import\n\nnote[unused-import]: unused imports should be removed\n   ╭▸ ROOT/testdata/Imports.sol:LL:CC\n   │\nLL │ import * as OtherUtils from \"./auxiliary/ImportsUtils2.sol\";\n   │ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unused-import\n\n"
  },
  {
    "path": "crates/lint/testdata/IncorrectShift.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.18;\n\ncontract IncorrectShift {\n    uint256 stateValue = 100;\n    uint256 stateShiftAmount = 4;\n\n    function getAmount() public view returns (uint256) {\n        return stateShiftAmount;\n    }\n\n    function shift() public view {\n        uint256 result;\n        uint256 localValue = 50;\n        uint256 localShiftAmount = 3;\n\n        // SHOULD FAIL:\n        // - Literal << NonLiteral\n        // - Literal >> NonLiteral\n\n        result = 2 << stateValue; //~WARN: the order of args in a shift operation is incorrect\n        result = 8 >> localValue; //~WARN: the order of args in a shift operation is incorrect\n        result = 16 << (stateValue + 1); //~WARN: the order of args in a shift operation is incorrect\n        result = 32 >> getAmount(); //~WARN: the order of args in a shift operation is incorrect\n        result = 1 << (localValue > 10 ? localShiftAmount : stateShiftAmount); //~WARN: the order of args in a shift operation is incorrect\n\n        // SHOULD PASS:\n        result = stateValue << 2;\n        result = localValue >> 3;\n        result = stateValue << localShiftAmount;\n        result = localValue >> stateShiftAmount;\n        result = (stateValue * 2) << 4;\n        result = getAmount() >> 1;\n\n        result = 1 << 8;\n        result = 255 >> 4;\n    }\n}\n"
  },
  {
    "path": "crates/lint/testdata/IncorrectShift.stderr",
    "content": "warning[incorrect-shift]: the order of args in a shift operation is incorrect\n   ╭▸ ROOT/testdata/IncorrectShift.sol:LL:CC\n   │\nLL │         result = 2 << stateValue;\n   │                  ━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#incorrect-shift\n\nwarning[incorrect-shift]: the order of args in a shift operation is incorrect\n   ╭▸ ROOT/testdata/IncorrectShift.sol:LL:CC\n   │\nLL │         result = 8 >> localValue;\n   │                  ━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#incorrect-shift\n\nwarning[incorrect-shift]: the order of args in a shift operation is incorrect\n   ╭▸ ROOT/testdata/IncorrectShift.sol:LL:CC\n   │\nLL │         result = 16 << (stateValue + 1);\n   │                  ━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#incorrect-shift\n\nwarning[incorrect-shift]: the order of args in a shift operation is incorrect\n   ╭▸ ROOT/testdata/IncorrectShift.sol:LL:CC\n   │\nLL │         result = 32 >> getAmount();\n   │                  ━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#incorrect-shift\n\nwarning[incorrect-shift]: the order of args in a shift operation is incorrect\n   ╭▸ ROOT/testdata/IncorrectShift.sol:LL:CC\n   │\nLL │ …     result = 1 << (localValue > 10 ? localShiftAmount : stateShiftAmount);\n   │                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#incorrect-shift\n\n"
  },
  {
    "path": "crates/lint/testdata/Keccak256.sol",
    "content": "//@compile-flags: --severity gas info\n\n// SPDX-License-Identifier: MIT\npragma solidity ^0.8.18;\n\ncontract AsmKeccak256 {\n    // constants are optimized by the compiler\n    bytes32 constant HASH = keccak256(\"hello\");\n    bytes32 constant OTHER_HASH = keccak256(hex\"1234\");\n\n    constructor(uint256 a, uint256 b, address c) {\n        // forge-lint: disable-next-line(asm-keccak256)\n        keccak256(abi.encodePacked(a, b));\n\n        keccak256(abi.encodePacked(a, b)); // forge-lint: disable-line(asm-keccak256)\n\n        // lints fire before the disabled block\n        address c = address(1);\n        bytes32 hash = keccak256(abi.encodePacked(a, b, bytes32(bytes20(c)))); //~NOTE: inefficient hashing mechanism\n        uint256 MixedCase_Variable = 1; //~NOTE: mutable variables should use mixedCase\n\n        // forge-lint: disable-start(asm-keccak256) -------------------------------------\n        keccak256(abi.encodePacked(a, b)); // disabled                                  |\n        //                                                                              |\n        // non-disabled lints still fire                                                |\n        uint256 Another_MixedCase = 2; //~NOTE: mutable variables should use mixedCase\n        //                                                                              |\n        // forge-lint: disable-start(asm-keccak256) -------                             |\n        keccak256(abi.encodePacked(a, b)); // disabled    |                             |\n        //                                                |                             |\n        // forge-lint: disable-end(asm-keccak256) ---------                             |\n        // forge-lint: disable-end(asm-keccak256) ---------------------------------------\n\n        // lints still fire after the disabled block\n        bytes32 afterDisabledBlock = keccak256(abi.encode(a, b, c)); //~NOTE: inefficient hashing mechanism\n        uint256 YetAnother_MixedCase = 3; //~NOTE: mutable variables should use mixedCase\n    }\n\n    // forge-lint: disable-next-item(asm-keccak256)\n    function solidityHashDisabled(uint256 a, uint256 b) public pure returns (bytes32) {\n        bytes32 hash = keccak256(abi.encodePacked(a));\n        return keccak256(abi.encodePacked(a, b));\n    }\n\n    function solidityHash(bytes calldata z, uint256 a, uint256 b, address c) public pure returns (bytes32) {\n        bytes32 loadsFromCalldata = keccak256(z); //~NOTE: inefficient hashing mechanism\n        bytes memory y = z;\n        bytes32 loadsFromMemory = keccak256(y); //~NOTE: inefficient hashing mechanism\n        bytes32 lintWithoutFix = keccak256(abi.encodePacked(a, b, c)); //~NOTE: inefficient hashing mechanism\n        return keccak256(abi.encode(a, b, c)); //~NOTE: inefficient hashing mechanism\n    }\n\n    function assemblyHash(uint256 a, uint256 b) public pure returns (bytes32) {\n        //optimized\n        assembly {\n            mstore(0x00, a)\n            mstore(0x20, b)\n            let hashedVal := keccak256(0x00, 0x40)\n        }\n    }\n}\n\n// forge-lint: disable-next-item(asm-keccak256)\ncontract OtherAsmKeccak256 {\n    uint256 Enabled_MixedCase_Variable; //~NOTE: mutable variables should use mixedCase\n\n    function contratDisabledHash(uint256 a, uint256 b) public pure returns (bytes32) {\n        return keccak256(abi.encode(a, b));\n    }\n\n    function contratDisabledHash2(uint256 a, uint256 b) public pure returns (bytes32) {\n        return keccak256(abi.encodePacked(a, b));\n    }\n}\n\ncontract YetAnotherAsmKeccak256 {\n    function nonDisabledHash(uint256 x, uint256 y) public pure returns (bytes32) {\n        bytes32 doesNotUseScratchSpace = keccak256(abi.encode(x, y, x, y, x, y)); //~NOTE: inefficient hashing mechanism\n        bytes32 doesUseScratchSpace = keccak256(abi.encode(x)); //~NOTE: inefficient hashing mechanism\n        return keccak256(abi.encode(doesUseScratchSpace, doesNotUseScratchSpace)); //~NOTE: inefficient hashing mechanism\n    }\n\n    // forge-lint: disable-next-item(asm-keccak256)\n    function functionDisabledHash(uint256 a, uint256 b) public pure returns (bytes32) {\n        uint256 Enabled_MixedCase_Variable = 1; //~NOTE: mutable variables should use mixedCase\n        return keccak256(abi.encodePacked(a, b));\n    }\n}\n"
  },
  {
    "path": "crates/lint/testdata/Keccak256.stderr",
    "content": "note[mixed-case-variable]: mutable variables should use mixedCase\n   ╭▸ ROOT/testdata/Keccak256.sol:LL:CC\n   │\nLL │         uint256 MixedCase_Variable = 1;\n   │                 ━━━━━━━━━━━━━━━━━━ help: consider using: `mixedCaseVariable`\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable\n\nnote[mixed-case-variable]: mutable variables should use mixedCase\n   ╭▸ ROOT/testdata/Keccak256.sol:LL:CC\n   │\nLL │         uint256 Another_MixedCase = 2;\n   │                 ━━━━━━━━━━━━━━━━━ help: consider using: `anotherMixedCase`\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable\n\nnote[mixed-case-variable]: mutable variables should use mixedCase\n   ╭▸ ROOT/testdata/Keccak256.sol:LL:CC\n   │\nLL │         uint256 YetAnother_MixedCase = 3;\n   │                 ━━━━━━━━━━━━━━━━━━━━ help: consider using: `yetAnotherMixedCase`\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable\n\nnote[mixed-case-variable]: mutable variables should use mixedCase\n   ╭▸ ROOT/testdata/Keccak256.sol:LL:CC\n   │\nLL │     uint256 Enabled_MixedCase_Variable;\n   │             ━━━━━━━━━━━━━━━━━━━━━━━━━━ help: consider using: `enabledMixedCaseVariable`\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable\n\nnote[mixed-case-variable]: mutable variables should use mixedCase\n   ╭▸ ROOT/testdata/Keccak256.sol:LL:CC\n   │\nLL │         uint256 Enabled_MixedCase_Variable = 1;\n   │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━ help: consider using: `enabledMixedCaseVariable`\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable\n\nnote[multi-contract-file]: prefer having only one contract, interface or library per file\n   ╭▸ ROOT/testdata/Keccak256.sol:LL:CC\n   │\nLL │ contract AsmKeccak256 {\n   │          ━━━━━━━━━━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#multi-contract-file\n\nnote[multi-contract-file]: prefer having only one contract, interface or library per file\n   ╭▸ ROOT/testdata/Keccak256.sol:LL:CC\n   │\nLL │ contract OtherAsmKeccak256 {\n   │          ━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#multi-contract-file\n\nnote[multi-contract-file]: prefer having only one contract, interface or library per file\n   ╭▸ ROOT/testdata/Keccak256.sol:LL:CC\n   │\nLL │ contract YetAnotherAsmKeccak256 {\n   │          ━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#multi-contract-file\n\nnote[asm-keccak256]: use of inefficient hashing mechanism; consider using inline assembly\n   ╭▸ ROOT/testdata/Keccak256.sol:LL:CC\n   │\nLL │         bytes32 hash = keccak256(abi.encodePacked(a, b, bytes32(bytes20(c))));\n   │                        ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#asm-keccak256\n\nnote[asm-keccak256]: use of inefficient hashing mechanism; consider using inline assembly\n   ╭▸ ROOT/testdata/Keccak256.sol:LL:CC\n   │\nLL │         bytes32 afterDisabledBlock = keccak256(abi.encode(a, b, c));\n   │                                      ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#asm-keccak256\n\nnote[asm-keccak256]: use of inefficient hashing mechanism; consider using inline assembly\n   ╭▸ ROOT/testdata/Keccak256.sol:LL:CC\n   │\nLL │         bytes32 loadsFromCalldata = keccak256(z);\n   │                                     ━━━━━━━━━━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#asm-keccak256\n\nnote[asm-keccak256]: use of inefficient hashing mechanism; consider using inline assembly\n   ╭▸ ROOT/testdata/Keccak256.sol:LL:CC\n   │\nLL │         bytes32 loadsFromMemory = keccak256(y);\n   │                                   ━━━━━━━━━━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#asm-keccak256\n\nnote[asm-keccak256]: use of inefficient hashing mechanism; consider using inline assembly\n   ╭▸ ROOT/testdata/Keccak256.sol:LL:CC\n   │\nLL │         bytes32 lintWithoutFix = keccak256(abi.encodePacked(a, b, c));\n   │                                  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#asm-keccak256\n\nnote[asm-keccak256]: use of inefficient hashing mechanism; consider using inline assembly\n   ╭▸ ROOT/testdata/Keccak256.sol:LL:CC\n   │\nLL │         return keccak256(abi.encode(a, b, c));\n   │                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#asm-keccak256\n\nnote[asm-keccak256]: use of inefficient hashing mechanism; consider using inline assembly\n   ╭▸ ROOT/testdata/Keccak256.sol:LL:CC\n   │\nLL │         bytes32 doesNotUseScratchSpace = keccak256(abi.encode(x, y, x, y, x, y));\n   │                                          ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#asm-keccak256\n\nnote[asm-keccak256]: use of inefficient hashing mechanism; consider using inline assembly\n   ╭▸ ROOT/testdata/Keccak256.sol:LL:CC\n   │\nLL │         bytes32 doesUseScratchSpace = keccak256(abi.encode(x));\n   │                                       ━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#asm-keccak256\n\nnote[asm-keccak256]: use of inefficient hashing mechanism; consider using inline assembly\n   ╭▸ ROOT/testdata/Keccak256.sol:LL:CC\n   │\nLL │         return keccak256(abi.encode(doesUseScratchSpace, doesNotUseScratchSpace));\n   │                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#asm-keccak256\n\n"
  },
  {
    "path": "crates/lint/testdata/MixedCase.sol",
    "content": "//@compile-flags: --severity info\n\n// SPDX-License-Identifier: MIT\npragma solidity ^0.8.18;\n\ninterface IERC20 {\n    function decimals() external view returns(uint8);\n}\n\ncontract MixedCaseTest {\n    uint256 variableMixedCase;\n    uint256 _variableMixedCase;\n    uint256 variablemixedcase;\n\n    uint256 Variablemixedcase; //~NOTE: mutable variables should use mixedCase\n    uint256 VARIABLE_MIXED_CASE; //~NOTE: mutable variables should use mixedCase\n    uint256 VariableMixedCase; //~NOTE: mutable variables should use mixedCase\n\n    function foo() public {\n        uint256 testVal;\n        uint256 testVal123;\n\n        uint256 testVAL; //~NOTE: mutable variables should use mixedCase\n        uint256 TestVal; //~NOTE: mutable variables should use mixedCase\n        uint256 TESTVAL; //~NOTE: mutable variables should use mixedCase\n    }\n\n    function functionMixedCase() public {}\n    function _functionMixedCase() internal {}\n    function functionmixedcase() public {}\n\n    function Functionmixedcase() public {} //~NOTE: function names should use mixedCase\n    function FUNCTION_MIXED_CASE() public {} //~NOTE: function names should use mixedCase\n    function FunctionMixedCase() public {} //~NOTE: function names should use mixedCase\n    function function_mixed_case() public {} //~NOTE: function names should use mixedCase\n\n    // mixedCase checks are disabled for functions that starting with:\n    // `test`, `invariant_`, and `statefulFuzz`\n    function test_MixedCase_Disabled() public {}\n    function test_mixedcase_disabled() public {}\n    function testMixedCaseDisabled() public {}\n    function testmixedcasedisabled() public {}\n\n    function testFuzz_MixedCase_Disabled() public {}\n    function testFuzz_mixedcase_disabled() public {}\n    function testFuzzMixedCaseDisabled() public {}\n    function testfuzzmixedcasedisabled() public {}\n\n    function testRevert_MixedCase_Disabled() public {}\n    function testRevert_mixedcase_disabled() public {}\n    function testRevertMixedCaseDisabled() public {}\n    function testrevertmixedcasedisabled() public {}\n\n    function invariant_MixedCase_Disabled() public {}\n    function invariant_mixedcase_disabled() public {}\n    function invariant_MixedCaseDisabled() public {}\n    function invariant_mixedcasedisabled() public {}\n\n    function invariantBalance_MixedCase_Enabled() public {} //~NOTE: function names should use mixedCase\n    function invariantbalance_mixedcase_enabled() public {} //~NOTE: function names should use mixedCase\n    function invariantBalanceMixedCaseEnabled() public {}\n    function invariantbalancemixedcaseenabled() public {}\n\n    function statefulFuzz_MixedCase_Disabled() public {}\n    function statefulFuzz_mixedcase_disabled() public {}\n    function statefulFuzzMixedCaseDisabled() public {}\n    function statefulFuzzmixedcasedisabled() public {}\n\n    // ERC is, by default, an allowed infix\n    function rescueERC6909(address token, address to, uint256 tokenId, uint256 amount) public {}\n    function ERC20DoSomething() public {}\n    function ERC20_DoSomething() public {} // invalid because of the underscore\n    //~^NOTE: function names should use mixedCase\n\n    // Common abbreviations are allowed by default: ID, URL, URI, API, JSON, XML, HTML, HTTP, HTTPS\n    uint256 marketID;\n    uint256 userID;\n    uint256 optionID;\n    uint256 apiURL;\n    uint256 baseURL;\n    function parseJSON() public {}\n    function fetchAPIData() public {}\n    function processHTML() public {}\n    function sendHTTPRequest() public {}\n    function handleHTTPSConnection() public {}\n    function getXMLData() public {}\n\n    // SCREAMING_SNAKE_CASE is allowed for functions that are most likely constant getters\n    function MAX_NUMBER() external view returns (uint256) {}\n    function CUSTOM_TYPE_RETURN() external view returns (IERC20) {}\n    function HAS_PARAMS(address addr) external view returns (uint256) {} //~NOTE: function names should use mixedCase\n    function HAS_NO_RETURN() external view {} //~NOTE: function names should use mixedCase\n    function HAS_MORE_THAN_ONE_RETURN() external view returns (uint256, uint256) {} //~NOTE: function names should use mixedCase\n    function NOT_ELEMENTARY_RETURN() external view returns (uint256[] memory) {} //~NOTE: function names should use mixedCase\n}\n"
  },
  {
    "path": "crates/lint/testdata/MixedCase.stderr",
    "content": "note[mixed-case-variable]: mutable variables should use mixedCase\n   ╭▸ ROOT/testdata/MixedCase.sol:LL:CC\n   │\nLL │     uint256 Variablemixedcase;\n   │             ━━━━━━━━━━━━━━━━━ help: consider using: `variablemixedcase`\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable\n\nnote[mixed-case-variable]: mutable variables should use mixedCase\n   ╭▸ ROOT/testdata/MixedCase.sol:LL:CC\n   │\nLL │     uint256 VARIABLE_MIXED_CASE;\n   │             ━━━━━━━━━━━━━━━━━━━ help: consider using: `variableMixedCase`\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable\n\nnote[mixed-case-variable]: mutable variables should use mixedCase\n   ╭▸ ROOT/testdata/MixedCase.sol:LL:CC\n   │\nLL │     uint256 VariableMixedCase;\n   │             ━━━━━━━━━━━━━━━━━ help: consider using: `variableMixedCase`\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable\n\nnote[mixed-case-variable]: mutable variables should use mixedCase\n   ╭▸ ROOT/testdata/MixedCase.sol:LL:CC\n   │\nLL │         uint256 testVAL;\n   │                 ━━━━━━━ help: consider using: `testVal`\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable\n\nnote[mixed-case-variable]: mutable variables should use mixedCase\n   ╭▸ ROOT/testdata/MixedCase.sol:LL:CC\n   │\nLL │         uint256 TestVal;\n   │                 ━━━━━━━ help: consider using: `testVal`\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable\n\nnote[mixed-case-variable]: mutable variables should use mixedCase\n   ╭▸ ROOT/testdata/MixedCase.sol:LL:CC\n   │\nLL │         uint256 TESTVAL;\n   │                 ━━━━━━━ help: consider using: `testval`\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-variable\n\nnote[mixed-case-function]: function names should use mixedCase\n   ╭▸ ROOT/testdata/MixedCase.sol:LL:CC\n   │\nLL │     function Functionmixedcase() public {}\n   │              ━━━━━━━━━━━━━━━━━ help: consider using: `functionmixedcase`\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-function\n\nnote[mixed-case-function]: function names should use mixedCase\n   ╭▸ ROOT/testdata/MixedCase.sol:LL:CC\n   │\nLL │     function FUNCTION_MIXED_CASE() public {}\n   │              ━━━━━━━━━━━━━━━━━━━ help: consider using: `functionMixedCase`\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-function\n\nnote[mixed-case-function]: function names should use mixedCase\n   ╭▸ ROOT/testdata/MixedCase.sol:LL:CC\n   │\nLL │     function FunctionMixedCase() public {}\n   │              ━━━━━━━━━━━━━━━━━ help: consider using: `functionMixedCase`\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-function\n\nnote[mixed-case-function]: function names should use mixedCase\n   ╭▸ ROOT/testdata/MixedCase.sol:LL:CC\n   │\nLL │     function function_mixed_case() public {}\n   │              ━━━━━━━━━━━━━━━━━━━ help: consider using: `functionMixedCase`\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-function\n\nnote[mixed-case-function]: function names should use mixedCase\n   ╭▸ ROOT/testdata/MixedCase.sol:LL:CC\n   │\nLL │     function invariantBalance_MixedCase_Enabled() public {}\n   │              ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ help: consider using: `invariantBalanceMixedCaseEnabled`\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-function\n\nnote[mixed-case-function]: function names should use mixedCase\n   ╭▸ ROOT/testdata/MixedCase.sol:LL:CC\n   │\nLL │     function invariantbalance_mixedcase_enabled() public {}\n   │              ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ help: consider using: `invariantbalanceMixedcaseEnabled`\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-function\n\nnote[mixed-case-function]: function names should use mixedCase\n   ╭▸ ROOT/testdata/MixedCase.sol:LL:CC\n   │\nLL │     function ERC20_DoSomething() public {} // invalid because of the underscore\n   │              ━━━━━━━━━━━━━━━━━ help: consider using: `erc20DoSomething`\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-function\n\nnote[mixed-case-function]: function names should use mixedCase\n   ╭▸ ROOT/testdata/MixedCase.sol:LL:CC\n   │\nLL │     function HAS_PARAMS(address addr) external view returns (uint256) {}\n   │              ━━━━━━━━━━ help: consider using: `hasParams`\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-function\n\nnote[mixed-case-function]: function names should use mixedCase\n   ╭▸ ROOT/testdata/MixedCase.sol:LL:CC\n   │\nLL │     function HAS_NO_RETURN() external view {}\n   │              ━━━━━━━━━━━━━ help: consider using: `hasNoReturn`\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-function\n\nnote[mixed-case-function]: function names should use mixedCase\n   ╭▸ ROOT/testdata/MixedCase.sol:LL:CC\n   │\nLL │     function HAS_MORE_THAN_ONE_RETURN() external view returns (uint256, uint256) {}\n   │              ━━━━━━━━━━━━━━━━━━━━━━━━ help: consider using: `hasMoreThanOneReturn`\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-function\n\nnote[mixed-case-function]: function names should use mixedCase\n   ╭▸ ROOT/testdata/MixedCase.sol:LL:CC\n   │\nLL │     function NOT_ELEMENTARY_RETURN() external view returns (uint256[] memory) {}\n   │              ━━━━━━━━━━━━━━━━━━━━━ help: consider using: `notElementaryReturn`\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#mixed-case-function\n\nnote[multi-contract-file]: prefer having only one contract, interface or library per file\n   ╭▸ ROOT/testdata/MixedCase.sol:LL:CC\n   │\nLL │ interface IERC20 {\n   │           ━━━━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#multi-contract-file\n\nnote[multi-contract-file]: prefer having only one contract, interface or library per file\n   ╭▸ ROOT/testdata/MixedCase.sol:LL:CC\n   │\nLL │ contract MixedCaseTest {\n   │          ━━━━━━━━━━━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#multi-contract-file\n\n"
  },
  {
    "path": "crates/lint/testdata/MultiContractFile.sol",
    "content": "//@compile-flags: --severity info\n\n// SPDX-License-Identifier: MIT\npragma solidity ^0.8.18;\n\ncontract A {}\n\ncontract B {} //~NOTE: prefer having only one contract, interface or library per file\n\ncontract C {}\n\ninterface I {}\n\nlibrary L {}\n"
  },
  {
    "path": "crates/lint/testdata/MultiContractFile.stderr",
    "content": "note[multi-contract-file]: prefer having only one contract, interface or library per file\n   ╭▸ ROOT/testdata/MultiContractFile.sol:LL:CC\n   │\nLL │ contract A {}\n   │          ━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#multi-contract-file\n\nnote[multi-contract-file]: prefer having only one contract, interface or library per file\n   ╭▸ ROOT/testdata/MultiContractFile.sol:LL:CC\n   │\nLL │ contract B {}\n   │          ━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#multi-contract-file\n\nnote[multi-contract-file]: prefer having only one contract, interface or library per file\n   ╭▸ ROOT/testdata/MultiContractFile.sol:LL:CC\n   │\nLL │ contract C {}\n   │          ━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#multi-contract-file\n\nnote[multi-contract-file]: prefer having only one contract, interface or library per file\n   ╭▸ ROOT/testdata/MultiContractFile.sol:LL:CC\n   │\nLL │ interface I {}\n   │           ━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#multi-contract-file\n\nnote[multi-contract-file]: prefer having only one contract, interface or library per file\n   ╭▸ ROOT/testdata/MultiContractFile.sol:LL:CC\n   │\nLL │ library L {}\n   │         ━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#multi-contract-file\n\n"
  },
  {
    "path": "crates/lint/testdata/MultiContractFile_InterfaceLibrary.sol",
    "content": "//@compile-flags: --severity info\n\n// SPDX-License-Identifier: MIT\npragma solidity ^0.8.18;\n\n// Interface counts as a contract-like item.\ninterface I1 {}\n\n// Library is also a contract-like item and it should be counted.\nlibrary L1 {} //~NOTE: prefer having only one contract, interface or library per file\n\n// Third contract-like item.\ncontract C1 {}\n\n"
  },
  {
    "path": "crates/lint/testdata/MultiContractFile_InterfaceLibrary.stderr",
    "content": "note[multi-contract-file]: prefer having only one contract, interface or library per file\n   ╭▸ ROOT/testdata/MultiContractFile_InterfaceLibrary.sol:LL:CC\n   │\nLL │ interface I1 {}\n   │           ━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#multi-contract-file\n\nnote[multi-contract-file]: prefer having only one contract, interface or library per file\n   ╭▸ ROOT/testdata/MultiContractFile_InterfaceLibrary.sol:LL:CC\n   │\nLL │ library L1 {}\n   │         ━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#multi-contract-file\n\nnote[multi-contract-file]: prefer having only one contract, interface or library per file\n   ╭▸ ROOT/testdata/MultiContractFile_InterfaceLibrary.sol:LL:CC\n   │\nLL │ contract C1 {}\n   │          ━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#multi-contract-file\n\n"
  },
  {
    "path": "crates/lint/testdata/NamedStructFields.sol",
    "content": "//@compile-flags: --severity info\n\n// SPDX-License-Identifier: MIT\npragma solidity ^0.8.18;\n\ncontract NamedStructFields {\n    struct Person {\n        string name;\n        uint256 age;\n        address wallet;\n    }\n\n    function namedArgs() public {\n        Person memory person = Person({\n            name: \"Alice\",\n            age: 25,\n            wallet: address(0)\n        });\n    }\n\n    function positionalArgs() public {\n        Person memory person = Person(\"Alice\", 25, address(0)); //~NOTE: prefer initializing structs with named fields\n    }\n}\n"
  },
  {
    "path": "crates/lint/testdata/NamedStructFields.stderr",
    "content": "note[named-struct-fields]: prefer initializing structs with named fields\n   ╭▸ ROOT/testdata/NamedStructFields.sol:LL:CC\n   │\nLL │         Person memory person = Person(\"Alice\", 25, address(0));\n   │                                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ help: consider using named fields: `Person({ name: \"Alice\", age: 25, wallet: address(0) })`\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#named-struct-fields\n\n"
  },
  {
    "path": "crates/lint/testdata/ScreamingSnakeCase.sol",
    "content": "//@compile-flags: --severity info\n\n// SPDX-License-Identifier: MIT\npragma solidity ^0.8.18;\n\ncontract ScreamingSnakeCaseTest {\n    uint256 constant _SCREAMING_SNAKE_CASE = 0;\n    uint256 constant SCREAMING_SNAKE_CASE = 0;\n    uint256 constant SCREAMINGSNAKECASE = 0;\n\n    uint256 constant screamingSnakeCase = 0; //~NOTE: constants should use SCREAMING_SNAKE_CASE\n    uint256 constant screaming_snake_case = 0; //~NOTE: constants should use SCREAMING_SNAKE_CASE\n    uint256 constant ScreamingSnakeCase = 0; //~NOTE: constants should use SCREAMING_SNAKE_CASE\n    uint256 constant SCREAMING_snake_case = 0; //~NOTE: constants should use SCREAMING_SNAKE_CASE\n\n    uint256 immutable _SCREAMING_SNAKE_CASE_1 = 0;\n    uint256 immutable SCREAMING_SNAKE_CASE_1 = 0;\n    uint256 immutable SCREAMINGSNAKECASE0 = 0;\n    uint256 immutable SCREAMINGSNAKECASE_ = 0;\n\n    uint256 immutable screamingSnakeCase0 = 0; //~NOTE: immutables should use SCREAMING_SNAKE_CASE\n    uint256 immutable screaming_snake_case0 = 0; //~NOTE: immutables should use SCREAMING_SNAKE_CASE\n    uint256 immutable ScreamingSnakeCase0 = 0; //~NOTE: immutables should use SCREAMING_SNAKE_CASE\n    uint256 immutable SCREAMING_snake_case_0 = 0; //~NOTE: immutables should use SCREAMING_SNAKE_CASE\n}\n"
  },
  {
    "path": "crates/lint/testdata/ScreamingSnakeCase.stderr",
    "content": "note[screaming-snake-case-const]: constants should use SCREAMING_SNAKE_CASE\n   ╭▸ ROOT/testdata/ScreamingSnakeCase.sol:LL:CC\n   │\nLL │     uint256 constant screamingSnakeCase = 0;\n   │                      ━━━━━━━━━━━━━━━━━━ help: consider using: `SCREAMING_SNAKE_CASE`\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#screaming-snake-case-const\n\nnote[screaming-snake-case-const]: constants should use SCREAMING_SNAKE_CASE\n   ╭▸ ROOT/testdata/ScreamingSnakeCase.sol:LL:CC\n   │\nLL │     uint256 constant screaming_snake_case = 0;\n   │                      ━━━━━━━━━━━━━━━━━━━━ help: consider using: `SCREAMING_SNAKE_CASE`\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#screaming-snake-case-const\n\nnote[screaming-snake-case-const]: constants should use SCREAMING_SNAKE_CASE\n   ╭▸ ROOT/testdata/ScreamingSnakeCase.sol:LL:CC\n   │\nLL │     uint256 constant ScreamingSnakeCase = 0;\n   │                      ━━━━━━━━━━━━━━━━━━ help: consider using: `SCREAMING_SNAKE_CASE`\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#screaming-snake-case-const\n\nnote[screaming-snake-case-const]: constants should use SCREAMING_SNAKE_CASE\n   ╭▸ ROOT/testdata/ScreamingSnakeCase.sol:LL:CC\n   │\nLL │     uint256 constant SCREAMING_snake_case = 0;\n   │                      ━━━━━━━━━━━━━━━━━━━━ help: consider using: `SCREAMING_SNAKE_CASE`\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#screaming-snake-case-const\n\nnote[screaming-snake-case-immutable]: immutables should use SCREAMING_SNAKE_CASE\n   ╭▸ ROOT/testdata/ScreamingSnakeCase.sol:LL:CC\n   │\nLL │     uint256 immutable screamingSnakeCase0 = 0;\n   │                       ━━━━━━━━━━━━━━━━━━━ help: consider using: `SCREAMING_SNAKE_CASE0`\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#screaming-snake-case-immutable\n\nnote[screaming-snake-case-immutable]: immutables should use SCREAMING_SNAKE_CASE\n   ╭▸ ROOT/testdata/ScreamingSnakeCase.sol:LL:CC\n   │\nLL │     uint256 immutable screaming_snake_case0 = 0;\n   │                       ━━━━━━━━━━━━━━━━━━━━━ help: consider using: `SCREAMING_SNAKE_CASE0`\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#screaming-snake-case-immutable\n\nnote[screaming-snake-case-immutable]: immutables should use SCREAMING_SNAKE_CASE\n   ╭▸ ROOT/testdata/ScreamingSnakeCase.sol:LL:CC\n   │\nLL │     uint256 immutable ScreamingSnakeCase0 = 0;\n   │                       ━━━━━━━━━━━━━━━━━━━ help: consider using: `SCREAMING_SNAKE_CASE0`\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#screaming-snake-case-immutable\n\nnote[screaming-snake-case-immutable]: immutables should use SCREAMING_SNAKE_CASE\n   ╭▸ ROOT/testdata/ScreamingSnakeCase.sol:LL:CC\n   │\nLL │     uint256 immutable SCREAMING_snake_case_0 = 0;\n   │                       ━━━━━━━━━━━━━━━━━━━━━━ help: consider using: `SCREAMING_SNAKE_CASE_0`\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#screaming-snake-case-immutable\n\n"
  },
  {
    "path": "crates/lint/testdata/SoloInterfaces.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.18;\n\ninterface SoloInterfaces {\n    function foo() external;\n}\n\ninterface I2 {\n    function foo() external;\n}\n\ninterface I3 {\n    function foo() external;\n}\n\n"
  },
  {
    "path": "crates/lint/testdata/StructPascalCase.sol",
    "content": "//@compile-flags: --severity info\n\n// SPDX-License-Identifier: MIT\npragma solidity ^0.8.18;\n\ncontract StructPascalCaseTest {\n    struct PascalCase {\n        uint256 a;\n    }\n\n    struct PascalCAse {\n        uint256 a;\n    }\n\n    struct _PascalCase { //~NOTE: structs should use PascalCase\n        uint256 a;\n    }\n\n    struct pascalCase { //~NOTE: structs should use PascalCase\n        uint256 a;\n    }\n\n    struct pascalcase { //~NOTE: structs should use PascalCase\n        uint256 a;\n    }\n\n    struct pascal_case { //~NOTE: structs should use PascalCase\n        uint256 a;\n    }\n\n    struct PASCAL_CASE { //~NOTE: structs should use PascalCase\n        uint256 a;\n    }\n\n    struct PASCALCASE { //~NOTE: structs should use PascalCase\n        uint256 a;\n    }\n}\n"
  },
  {
    "path": "crates/lint/testdata/StructPascalCase.stderr",
    "content": "note[pascal-case-struct]: structs should use PascalCase\n   ╭▸ ROOT/testdata/StructPascalCase.sol:LL:CC\n   │\nLL │     struct _PascalCase {\n   │            ━━━━━━━━━━━ help: consider using: `PascalCase`\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#pascal-case-struct\n\nnote[pascal-case-struct]: structs should use PascalCase\n   ╭▸ ROOT/testdata/StructPascalCase.sol:LL:CC\n   │\nLL │     struct pascalCase {\n   │            ━━━━━━━━━━ help: consider using: `PascalCase`\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#pascal-case-struct\n\nnote[pascal-case-struct]: structs should use PascalCase\n   ╭▸ ROOT/testdata/StructPascalCase.sol:LL:CC\n   │\nLL │     struct pascalcase {\n   │            ━━━━━━━━━━ help: consider using: `Pascalcase`\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#pascal-case-struct\n\nnote[pascal-case-struct]: structs should use PascalCase\n   ╭▸ ROOT/testdata/StructPascalCase.sol:LL:CC\n   │\nLL │     struct pascal_case {\n   │            ━━━━━━━━━━━ help: consider using: `PascalCase`\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#pascal-case-struct\n\nnote[pascal-case-struct]: structs should use PascalCase\n   ╭▸ ROOT/testdata/StructPascalCase.sol:LL:CC\n   │\nLL │     struct PASCAL_CASE {\n   │            ━━━━━━━━━━━ help: consider using: `PascalCase`\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#pascal-case-struct\n\nnote[pascal-case-struct]: structs should use PascalCase\n   ╭▸ ROOT/testdata/StructPascalCase.sol:LL:CC\n   │\nLL │     struct PASCALCASE {\n   │            ━━━━━━━━━━ help: consider using: `Pascalcase`\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#pascal-case-struct\n\n"
  },
  {
    "path": "crates/lint/testdata/UncheckedCall.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.18;\n\ncontract UncheckedCall {\n    event CallResult(bool, bytes);\n\n    // SHOULD PASS: Properly checked low-level calls\n    function checkedCallWithTuple(address target, bytes memory data) public {\n        (bool success, bytes memory result) = target.call(data);\n        require(success, \"Call failed\");\n        emit CallResult(success, result);\n    }\n\n    function checkedCallWithIfStatement(address target, bytes memory data) public {\n        (bool success, ) = target.call(data);\n        if (!success) {\n            revert(\"Call failed\");\n        }\n    }\n\n    function checkedDelegateCall(address target, bytes memory data) public returns (bool) {\n        (bool success, ) = target.delegatecall(data);\n        return success;\n    }\n\n    function checkedStaticCall(address target, bytes memory data) public view returns (bytes memory) {\n        (bool success, bytes memory result) = target.staticcall(data);\n        require(success, \"Static call failed\");\n        return result;\n    }\n\n    function checkedCallInRequire(address target) public {\n        (bool success, ) = target.call(\"\");\n        require(success, \"Call must succeed\");\n    }\n\n    function checkedCallWithAssert(address target) public {\n        (bool success, ) = target.call(\"\");\n        assert(success);\n    }\n\n    // Edge case: pre-existing variable assignment\n    bool success;\n    function checkWithExistingVar(address target) public {\n        (success, ) = target.call(\"\");\n        // (success, existingData) = target.call(\"\");\n    }\n\n    // Edge case: send and transfer are not low-level calls (they automatically revert on failure)\n    function sendEther(address payable target) public {\n        target.transfer(1 ether); // Should not trigger\n        bool sent = target.send(1 ether); // Should not trigger\n        require(sent, \"Send failed\");\n    }\n\n\n    // SHOULD FAIL: Unchecked low-level calls\n    function uncheckedCall(address target, bytes memory data) public {\n        target.call(data); //~WARN: Low-level calls should check the success return value\n    }\n\n    function uncheckedCallWithValue(address payable target, uint256 value) public {\n        target.call{value: value}(\"\"); //~WARN: Low-level calls should check the success return value\n    }\n\n    function uncheckedDelegateCall(address target, bytes memory data) public {\n        target.delegatecall(data); //~WARN: Low-level calls should check the success return value\n    }\n\n    function uncheckedStaticCall(address target, bytes memory data) public {\n        target.staticcall(data); //~WARN: Low-level calls should check the success return value\n    }\n\n    function multipleUncheckedCalls(address target1, address target2) public {\n        target1.call(\"\"); //~WARN: Low-level calls should check the success return value\n        target2.delegatecall(\"\"); //~WARN: Low-level calls should check the success return value\n    }\n\n    function ignoredReturnWithPartialTuple(address target) public {\n        (, bytes memory data) = target.call(\"\"); //~WARN: Low-level calls should check the success return value\n        // Only capturing data, not checking success\n    }\n\n    bytes existingData;\n    function ignoredReturnExistingVar(address target) public {\n        (, existingData) = target.call(\"\"); //~WARN: Low-level calls should check the success return value\n    }\n\n}\n"
  },
  {
    "path": "crates/lint/testdata/UncheckedCall.stderr",
    "content": "warning[unchecked-call]: Low-level calls should check the success return value\n   ╭▸ ROOT/testdata/UncheckedCall.sol:LL:CC\n   │\nLL │         target.call(data);\n   │         ━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unchecked-call\n\nwarning[unchecked-call]: Low-level calls should check the success return value\n   ╭▸ ROOT/testdata/UncheckedCall.sol:LL:CC\n   │\nLL │         target.call{value: value}(\"\");\n   │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unchecked-call\n\nwarning[unchecked-call]: Low-level calls should check the success return value\n   ╭▸ ROOT/testdata/UncheckedCall.sol:LL:CC\n   │\nLL │         target.delegatecall(data);\n   │         ━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unchecked-call\n\nwarning[unchecked-call]: Low-level calls should check the success return value\n   ╭▸ ROOT/testdata/UncheckedCall.sol:LL:CC\n   │\nLL │         target.staticcall(data);\n   │         ━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unchecked-call\n\nwarning[unchecked-call]: Low-level calls should check the success return value\n   ╭▸ ROOT/testdata/UncheckedCall.sol:LL:CC\n   │\nLL │         target1.call(\"\");\n   │         ━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unchecked-call\n\nwarning[unchecked-call]: Low-level calls should check the success return value\n   ╭▸ ROOT/testdata/UncheckedCall.sol:LL:CC\n   │\nLL │         target2.delegatecall(\"\");\n   │         ━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unchecked-call\n\nwarning[unchecked-call]: Low-level calls should check the success return value\n   ╭▸ ROOT/testdata/UncheckedCall.sol:LL:CC\n   │\nLL │         (, bytes memory data) = target.call(\"\");\n   │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unchecked-call\n\nwarning[unchecked-call]: Low-level calls should check the success return value\n   ╭▸ ROOT/testdata/UncheckedCall.sol:LL:CC\n   │\nLL │         (, existingData) = target.call(\"\");\n   │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unchecked-call\n\n"
  },
  {
    "path": "crates/lint/testdata/UncheckedTransferERC20.sol",
    "content": "//@compile-flags: --severity high med low info\n\n// SPDX-License-Identifier: MIT\npragma solidity ^0.8.18;\n\ninterface IERC20 {\n    function transfer(address to, uint256 amount) external returns (bool);\n    function transferFrom(address from, address to, uint256 amount) external returns (bool);\n    function approve(address spender, uint256 amount) external returns (bool);\n}\n\ninterface IERC20Wrapper {\n    function transfer(address to, uint256 amount) external;\n    function transferFrom(address from, address to, uint256 amount) external;\n}\n\ncontract UncheckedTransfer {\n    IERC20 public token;\n    IERC20Wrapper public tokenWrapper;\n    mapping(address => uint256) public balances;\n\n    constructor(address _token) {\n        token = IERC20(_token);\n        tokenWrapper = IERC20Wrapper(_token);\n    }\n\n    // SHOULD FAIL: Unchecked transfer calls\n    function uncheckedTransfer(address to, uint256 amount) public {\n        IERC20(address(token)).transfer(to, amount); //~WARN: ERC20 'transfer' and 'transferFrom' calls should check the return value\n        token.transfer(to, amount); //~WARN: ERC20 'transfer' and 'transferFrom' calls should check the return value\n    }\n\n    function uncheckedTransferFrom(address from, address to, uint256 amount) public {\n        IERC20(address(token)).transferFrom(from, to, amount); //~WARN: ERC20 'transfer' and 'transferFrom' calls should check the return value\n        token.transferFrom(from, to, amount); //~WARN: ERC20 'transfer' and 'transferFrom' calls should check the return value\n    }\n\n    function uncheckedInLoop(address[] memory recipients, uint256[] memory amounts) public {\n        for (uint256 i = 0; i < recipients.length; i++) {\n            IERC20(address(token)).transfer(recipients[i], amounts[i]); //~WARN: ERC20 'transfer' and 'transferFrom' calls should check the return value\n            token.transfer(recipients[i], amounts[i]); //~WARN: ERC20 'transfer' and 'transferFrom' calls should check the return value\n        }\n    }\n\n    // SHOULD PASS: Function with same params but NO boolean return\n    function proxyCheckedTransfer(address to, uint256 amount) public {\n        IERC20Wrapper(address(token)).transfer(to, amount);\n        tokenWrapper.transfer(to, amount);\n    }\n\n    function proxyCheckedTransferFrom(address from, address to, uint256 amount) public {\n        IERC20Wrapper(address(token)).transferFrom(from, to, amount);\n        tokenWrapper.transferFrom(from, to, amount);\n    }\n\n    // SHOULD PASS: Properly checked transfer calls\n    function checkedTransferWithRequire(address to, uint256 amount) public {\n        require(token.transfer(to, amount), \"Transfer failed\");\n    }\n\n    function checkedTransferWithVariable(address to, uint256 amount) public {\n        bool success = token.transfer(to, amount);\n        require(success, \"Transfer failed\");\n    }\n\n    function checkedTransferFromWithIf(address from, address to, uint256 amount) public {\n        bool success = token.transferFrom(from, to, amount);\n        if (!success) {\n            revert(\"TransferFrom failed\");\n        }\n    }\n\n    function checkedTransferWithAssert(address to, uint256 amount) public {\n        assert(token.transfer(to, amount));\n    }\n\n    function checkedTransferInReturn(address to, uint256 amount) public returns (bool) {\n        return token.transfer(to, amount);\n    }\n\n    function checkedTransferInExpression(address to, uint256 amount) public {\n        if (token.transfer(to, amount)) {\n            balances[to] += amount;\n        } else {\n            revert(\"Transfer failed\");\n        }\n    }\n\n    function checkedTransferInRequireWithLogic(address to, uint256 amount) public {\n        require(amount > 0 && token.transfer(to, amount), \"Invalid amount or transfer failed\");\n    }\n\n    function uncheckedApprove(address spender, uint256 amount) public {\n        token.approve(spender, amount);\n    }\n}\n\nlibrary Currency {\n    function transfer(address currency, address to, uint256 amount) internal {\n        // transfer and check output internally\n    }\n    function transferFrom(address currency, address from, address to, uint256 amount) internal {\n        // transfer and check output internally\n    }\n}\n\ncontract UncheckedTransferUsingCurrencyLib {\n    using Currency for address;\n\n    address public token;\n    mapping(address => uint256) public balances;\n\n    constructor(address _token) {\n        token = _token;\n    }\n\n    // SHOULD PASS: Function with same params but NO boolean return\n    function currencyTransfer(address to, uint256 amount) public {\n        token.transfer(to, amount);\n        token.transfer(to, amount);\n    }\n\n    function currencyTransferFrom(address from, address to, uint256 amount) public {\n        token.transferFrom(from, to, amount);\n        token.transferFrom(from, to, amount);\n    }\n}\n"
  },
  {
    "path": "crates/lint/testdata/UncheckedTransferERC20.stderr",
    "content": "note[multi-contract-file]: prefer having only one contract, interface or library per file\n   ╭▸ ROOT/testdata/UncheckedTransferERC20.sol:LL:CC\n   │\nLL │ interface IERC20 {\n   │           ━━━━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#multi-contract-file\n\nnote[multi-contract-file]: prefer having only one contract, interface or library per file\n   ╭▸ ROOT/testdata/UncheckedTransferERC20.sol:LL:CC\n   │\nLL │ interface IERC20Wrapper {\n   │           ━━━━━━━━━━━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#multi-contract-file\n\nnote[multi-contract-file]: prefer having only one contract, interface or library per file\n   ╭▸ ROOT/testdata/UncheckedTransferERC20.sol:LL:CC\n   │\nLL │ contract UncheckedTransfer {\n   │          ━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#multi-contract-file\n\nnote[multi-contract-file]: prefer having only one contract, interface or library per file\n   ╭▸ ROOT/testdata/UncheckedTransferERC20.sol:LL:CC\n   │\nLL │ library Currency {\n   │         ━━━━━━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#multi-contract-file\n\nnote[multi-contract-file]: prefer having only one contract, interface or library per file\n   ╭▸ ROOT/testdata/UncheckedTransferERC20.sol:LL:CC\n   │\nLL │ contract UncheckedTransferUsingCurrencyLib {\n   │          ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#multi-contract-file\n\nwarning[erc20-unchecked-transfer]: ERC20 'transfer' and 'transferFrom' calls should check the return value\n   ╭▸ ROOT/testdata/UncheckedTransferERC20.sol:LL:CC\n   │\nLL │         IERC20(address(token)).transfer(to, amount);\n   │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#erc20-unchecked-transfer\n\nwarning[erc20-unchecked-transfer]: ERC20 'transfer' and 'transferFrom' calls should check the return value\n   ╭▸ ROOT/testdata/UncheckedTransferERC20.sol:LL:CC\n   │\nLL │         token.transfer(to, amount);\n   │         ━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#erc20-unchecked-transfer\n\nwarning[erc20-unchecked-transfer]: ERC20 'transfer' and 'transferFrom' calls should check the return value\n   ╭▸ ROOT/testdata/UncheckedTransferERC20.sol:LL:CC\n   │\nLL │ …     IERC20(address(token)).transferFrom(from, to, amount);\n   │       ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#erc20-unchecked-transfer\n\nwarning[erc20-unchecked-transfer]: ERC20 'transfer' and 'transferFrom' calls should check the return value\n   ╭▸ ROOT/testdata/UncheckedTransferERC20.sol:LL:CC\n   │\nLL │         token.transferFrom(from, to, amount);\n   │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#erc20-unchecked-transfer\n\nwarning[erc20-unchecked-transfer]: ERC20 'transfer' and 'transferFrom' calls should check the return value\n   ╭▸ ROOT/testdata/UncheckedTransferERC20.sol:LL:CC\n   │\nLL │ …     IERC20(address(token)).transfer(recipients[i], amounts[i]);\n   │       ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#erc20-unchecked-transfer\n\nwarning[erc20-unchecked-transfer]: ERC20 'transfer' and 'transferFrom' calls should check the return value\n   ╭▸ ROOT/testdata/UncheckedTransferERC20.sol:LL:CC\n   │\nLL │             token.transfer(recipients[i], amounts[i]);\n   │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#erc20-unchecked-transfer\n\n"
  },
  {
    "path": "crates/lint/testdata/UnsafeCheatcodes.sol",
    "content": "//@compile-flags: --severity info\n\n// SPDX-License-Identifier: MIT\npragma solidity ^0.8.18;\n\nimport {Test} from \"./auxiliary/Test.sol\";\n\ncontract UnsafeCheatcodes is Test {\n    function testSafeCheatcodes() public {\n        vm.prank(address(0x1));\n        vm.deal(address(0x1), 1 ether);\n        vm.warp(block.timestamp + 1);\n        vm.roll(block.number + 1);\n        vm.assume(true);\n        vm.expectRevert();\n    }\n\n    function testDirectFfi() public {\n        string[] memory inputs = new string[](1);\n        vm.ffi(inputs); //~NOTE: usage of unsafe cheatcodes that can perform dangerous operations\n    }\n\n    function testDirectReadFile() public {\n        vm.readFile(\"test.txt\"); //~NOTE: usage of unsafe cheatcodes that can perform dangerous operations\n    }\n\n    function testDirectReadLine() public {\n        vm.readLine(\"test.txt\"); //~NOTE: usage of unsafe cheatcodes that can perform dangerous operations\n    }\n\n    function testDirectWriteFile() public {\n        vm.writeFile(\"test.txt\", \"data\"); //~NOTE: usage of unsafe cheatcodes that can perform dangerous operations\n    }\n\n    function testDirectWriteLine() public {\n        vm.writeLine(\"test.txt\", \"data\"); //~NOTE: usage of unsafe cheatcodes that can perform dangerous operations\n    }\n\n    function testDirectRemoveFile() public {\n        vm.removeFile(\"test.txt\"); //~NOTE: usage of unsafe cheatcodes that can perform dangerous operations\n    }\n\n    function testDirectCloseFile() public {\n        vm.closeFile(\"test.txt\"); //~NOTE: usage of unsafe cheatcodes that can perform dangerous operations\n    }\n\n    function testDirectSetEnv() public {\n        vm.setEnv(\"KEY\", \"value\"); //~NOTE: usage of unsafe cheatcodes that can perform dangerous operations\n    }\n\n    function testDirectDeriveKey() public {\n        vm.deriveKey(\"mnemonic\", 0); //~NOTE: usage of unsafe cheatcodes that can perform dangerous operations\n    }\n\n    function testAssignmentFfi() public {\n        string[] memory inputs = new string[](1);\n        bytes memory result = vm.ffi(inputs); //~NOTE: usage of unsafe cheatcodes that can perform dangerous operations\n    }\n\n    function testMultipleUnsafe() public {\n        vm.ffi(new string[](1)); //~NOTE: usage of unsafe cheatcodes that can perform dangerous operations\n        vm.setEnv(\"KEY\", \"value\"); //~NOTE: usage of unsafe cheatcodes that can perform dangerous operations\n        vm.readFile(\"test.txt\"); //~NOTE: usage of unsafe cheatcodes that can perform dangerous operations\n    }\n\n}\n"
  },
  {
    "path": "crates/lint/testdata/UnsafeCheatcodes.stderr",
    "content": "note[unsafe-cheatcode]: usage of unsafe cheatcodes that can perform dangerous operations\n   ╭▸ ROOT/testdata/UnsafeCheatcodes.sol:LL:CC\n   │\nLL │         vm.ffi(inputs);\n   │            ━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-cheatcode\n\nnote[unsafe-cheatcode]: usage of unsafe cheatcodes that can perform dangerous operations\n   ╭▸ ROOT/testdata/UnsafeCheatcodes.sol:LL:CC\n   │\nLL │         vm.readFile(\"test.txt\");\n   │            ━━━━━━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-cheatcode\n\nnote[unsafe-cheatcode]: usage of unsafe cheatcodes that can perform dangerous operations\n   ╭▸ ROOT/testdata/UnsafeCheatcodes.sol:LL:CC\n   │\nLL │         vm.readLine(\"test.txt\");\n   │            ━━━━━━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-cheatcode\n\nnote[unsafe-cheatcode]: usage of unsafe cheatcodes that can perform dangerous operations\n   ╭▸ ROOT/testdata/UnsafeCheatcodes.sol:LL:CC\n   │\nLL │         vm.writeFile(\"test.txt\", \"data\");\n   │            ━━━━━━━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-cheatcode\n\nnote[unsafe-cheatcode]: usage of unsafe cheatcodes that can perform dangerous operations\n   ╭▸ ROOT/testdata/UnsafeCheatcodes.sol:LL:CC\n   │\nLL │         vm.writeLine(\"test.txt\", \"data\");\n   │            ━━━━━━━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-cheatcode\n\nnote[unsafe-cheatcode]: usage of unsafe cheatcodes that can perform dangerous operations\n   ╭▸ ROOT/testdata/UnsafeCheatcodes.sol:LL:CC\n   │\nLL │         vm.removeFile(\"test.txt\");\n   │            ━━━━━━━━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-cheatcode\n\nnote[unsafe-cheatcode]: usage of unsafe cheatcodes that can perform dangerous operations\n   ╭▸ ROOT/testdata/UnsafeCheatcodes.sol:LL:CC\n   │\nLL │         vm.closeFile(\"test.txt\");\n   │            ━━━━━━━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-cheatcode\n\nnote[unsafe-cheatcode]: usage of unsafe cheatcodes that can perform dangerous operations\n   ╭▸ ROOT/testdata/UnsafeCheatcodes.sol:LL:CC\n   │\nLL │         vm.setEnv(\"KEY\", \"value\");\n   │            ━━━━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-cheatcode\n\nnote[unsafe-cheatcode]: usage of unsafe cheatcodes that can perform dangerous operations\n   ╭▸ ROOT/testdata/UnsafeCheatcodes.sol:LL:CC\n   │\nLL │         vm.deriveKey(\"mnemonic\", 0);\n   │            ━━━━━━━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-cheatcode\n\nnote[unsafe-cheatcode]: usage of unsafe cheatcodes that can perform dangerous operations\n   ╭▸ ROOT/testdata/UnsafeCheatcodes.sol:LL:CC\n   │\nLL │         bytes memory result = vm.ffi(inputs);\n   │                                  ━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-cheatcode\n\nnote[unsafe-cheatcode]: usage of unsafe cheatcodes that can perform dangerous operations\n   ╭▸ ROOT/testdata/UnsafeCheatcodes.sol:LL:CC\n   │\nLL │         vm.ffi(new string[](1));\n   │            ━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-cheatcode\n\nnote[unsafe-cheatcode]: usage of unsafe cheatcodes that can perform dangerous operations\n   ╭▸ ROOT/testdata/UnsafeCheatcodes.sol:LL:CC\n   │\nLL │         vm.setEnv(\"KEY\", \"value\");\n   │            ━━━━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-cheatcode\n\nnote[unsafe-cheatcode]: usage of unsafe cheatcodes that can perform dangerous operations\n   ╭▸ ROOT/testdata/UnsafeCheatcodes.sol:LL:CC\n   │\nLL │         vm.readFile(\"test.txt\");\n   │            ━━━━━━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-cheatcode\n\n"
  },
  {
    "path": "crates/lint/testdata/UnsafeTypecast.sol",
    "content": "//@compile-flags: --severity high med low info\n\n// SPDX-License-Identifier: MIT\npragma solidity ^0.8.18;\n\n// forge-lint: disable-start(mixed-case-variable)\ncontract UnsafeTypecast {\n    // Unsigned upcasts are always safe.\n    function upcastSafeUint() public pure {\n        uint8 a = type(uint8).max;\n        uint16 b = uint16(a);\n        uint24 c = uint24(b);\n        uint32 d = uint32(c);\n        uint40 e = uint40(d);\n        uint48 f = uint48(e);\n        uint56 g = uint56(f);\n        uint64 h = uint64(g);\n        uint72 i = uint72(h);\n        uint80 j = uint80(i);\n        uint88 k = uint88(j);\n        uint96 l = uint96(k);\n        uint104 m = uint104(l);\n        uint112 n = uint112(m);\n        uint120 o = uint120(n);\n        uint128 p = uint128(o);\n        uint136 q = uint136(p);\n        uint144 r = uint144(q);\n        uint152 s = uint152(r);\n        uint160 t = uint160(s);\n        uint168 u = uint168(t);\n        uint176 v = uint176(u);\n        uint184 w = uint184(v);\n        uint192 x = uint192(w);\n        uint200 y = uint200(x);\n        uint208 z = uint208(y);\n        uint216 A = uint216(z);\n        uint224 B = uint224(A);\n        uint232 C = uint232(B);\n        uint240 D = uint240(C);\n        uint248 E = uint248(D);\n        uint256 F = uint256(E);\n    }\n\n    // Signed upcasts are safe.\n    function upcastSafeInt() public pure {\n        int8 a = type(int8).max;\n        int16 b = int16(a);\n        int24 c = int24(b);\n        int32 d = int32(c);\n        int40 e = int40(d);\n        int48 f = int48(e);\n        int56 g = int56(f);\n        int64 h = int64(g);\n        int72 i = int72(h);\n        int80 j = int80(i);\n        int88 k = int88(j);\n        int96 l = int96(k);\n        int104 m = int104(l);\n        int112 n = int112(m);\n        int120 o = int120(n);\n        int128 p = int128(o);\n        int136 q = int136(p);\n        int144 r = int144(q);\n        int152 s = int152(r);\n        int160 t = int160(s);\n        int168 u = int168(t);\n        int176 v = int176(u);\n        int184 w = int184(v);\n        int192 x = int192(w);\n        int200 y = int200(x);\n        int208 z = int208(y);\n        int216 A = int216(z);\n        int224 B = int224(A);\n        int232 C = int232(B);\n        int240 D = int240(C);\n        int248 E = int248(D);\n        int256 F = int256(E);\n    }\n\n    function upcastSafeBytes() public pure {\n        bytes1 a = 0xFF;\n        bytes2 b = bytes2(a);\n        bytes3 c = bytes3(b);\n        bytes4 d = bytes4(c);\n        bytes5 e = bytes5(d);\n        bytes6 f = bytes6(e);\n        bytes7 g = bytes7(f);\n        bytes8 h = bytes8(g);\n        bytes9 i = bytes9(h);\n        bytes10 j = bytes10(i);\n        bytes11 k = bytes11(j);\n        bytes12 l = bytes12(k);\n        bytes13 m = bytes13(l);\n        bytes14 n = bytes14(m);\n        bytes15 o = bytes15(n);\n        bytes16 p = bytes16(o);\n        bytes17 q = bytes17(p);\n        bytes18 r = bytes18(q);\n        bytes19 s = bytes19(r);\n        bytes20 t = bytes20(s);\n        bytes21 u = bytes21(t);\n        bytes22 v = bytes22(u);\n        bytes23 w = bytes23(v);\n        bytes24 x = bytes24(w);\n        bytes25 y = bytes25(x);\n        bytes26 z = bytes26(y);\n        bytes27 A = bytes27(z);\n        bytes28 B = bytes28(A);\n        bytes29 C = bytes29(B);\n        bytes30 D = bytes30(C);\n        bytes31 E = bytes31(D);\n        bytes32 F = bytes32(E);\n    }\n\n    function safeSizeUint() public pure {\n        uint256(type(uint256).max);\n        uint248(type(uint248).max);\n        uint240(type(uint240).max);\n        uint232(type(uint232).max);\n        uint224(type(uint224).max);\n        uint216(type(uint216).max);\n        uint208(type(uint208).max);\n        uint200(type(uint200).max);\n        uint192(type(uint192).max);\n        uint184(type(uint184).max);\n        uint176(type(uint176).max);\n        uint168(type(uint168).max);\n        uint160(type(uint160).max);\n        uint152(type(uint152).max);\n        uint144(type(uint144).max);\n        uint136(type(uint136).max);\n        uint128(type(uint128).max);\n        uint120(type(uint120).max);\n        uint112(type(uint112).max);\n        uint104(type(uint104).max);\n        uint96(type(uint96).max);\n        uint88(type(uint88).max);\n        uint80(type(uint80).max);\n        uint72(type(uint72).max);\n        uint64(type(uint64).max);\n        uint56(type(uint56).max);\n        uint48(type(uint48).max);\n        uint40(type(uint40).max);\n        uint32(type(uint32).max);\n        uint24(type(uint24).max);\n        uint16(type(uint16).max);\n        uint8(type(uint8).max);\n    }\n\n    function safeSizeInt() public pure {\n        int256(type(int256).max);\n        int248(type(int248).max);\n        int240(type(int240).max);\n        int232(type(int232).max);\n        int224(type(int224).max);\n        int216(type(int216).max);\n        int208(type(int208).max);\n        int200(type(int200).max);\n        int192(type(int192).max);\n        int184(type(int184).max);\n        int176(type(int176).max);\n        int168(type(int168).max);\n        int160(type(int160).max);\n        int152(type(int152).max);\n        int144(type(int144).max);\n        int136(type(int136).max);\n        int128(type(int128).max);\n        int120(type(int120).max);\n        int112(type(int112).max);\n        int104(type(int104).max);\n        int96(type(int96).max);\n        int88(type(int88).max);\n        int80(type(int80).max);\n        int72(type(int72).max);\n        int64(type(int64).max);\n        int56(type(int56).max);\n        int48(type(int48).max);\n        int40(type(int40).max);\n        int32(type(int32).max);\n        int24(type(int24).max);\n        int16(type(int16).max);\n        int8(type(int8).max);\n    }\n\n    function sameSizeAddressSafe() public pure {\n        address a = 0x1234567890123456789012345678901234567890;\n        uint160 b = uint160(a);\n        bytes20 c = bytes20(a);\n        address d = address(a);\n        // The following tests, `downcastUnsafeUint` and `downcastUnsafeBytes`, verify that other downcasts\n        // would also throw. Additionally, the compiler prevents direct casting of addresses to smaller types.\n    }\n\n    function downcastUnsafeUint() public pure {\n        uint256 a = type(uint256).max;\n        uint248 b = uint248(a); //~WARN: typecasts that can truncate values should be checked\n        uint240 c = uint240(b); //~WARN: typecasts that can truncate values should be checked\n        uint232 d = uint232(c); //~WARN: typecasts that can truncate values should be checked\n        uint224 e = uint224(d); //~WARN: typecasts that can truncate values should be checked\n        uint216 f = uint216(e); //~WARN: typecasts that can truncate values should be checked\n        uint208 g = uint208(f); //~WARN: typecasts that can truncate values should be checked\n        uint200 h = uint200(g); //~WARN: typecasts that can truncate values should be checked\n        uint192 i = uint192(h); //~WARN: typecasts that can truncate values should be checked\n        uint184 j = uint184(i); //~WARN: typecasts that can truncate values should be checked\n        uint176 k = uint176(j); //~WARN: typecasts that can truncate values should be checked\n        uint168 l = uint168(k); //~WARN: typecasts that can truncate values should be checked\n        uint160 m = uint160(l); //~WARN: typecasts that can truncate values should be checked\n        uint152 n = uint152(m); //~WARN: typecasts that can truncate values should be checked\n        uint144 o = uint144(n); //~WARN: typecasts that can truncate values should be checked\n        uint136 p = uint136(o); //~WARN: typecasts that can truncate values should be checked\n        uint128 q = uint128(p); //~WARN: typecasts that can truncate values should be checked\n        uint120 r = uint120(q); //~WARN: typecasts that can truncate values should be checked\n        uint112 s = uint112(r); //~WARN: typecasts that can truncate values should be checked\n        uint104 t = uint104(s); //~WARN: typecasts that can truncate values should be checked\n        uint96 u = uint96(t); //~WARN: typecasts that can truncate values should be checked\n        uint88 v = uint88(u); //~WARN: typecasts that can truncate values should be checked\n        uint80 w = uint80(v); //~WARN: typecasts that can truncate values should be checked\n        uint72 x = uint72(w); //~WARN: typecasts that can truncate values should be checked\n        uint64 y = uint64(x); //~WARN: typecasts that can truncate values should be checked\n        uint56 z = uint56(y); //~WARN: typecasts that can truncate values should be checked\n        uint48 A = uint48(z); //~WARN: typecasts that can truncate values should be checked\n        uint40 B = uint40(A); //~WARN: typecasts that can truncate values should be checked\n        uint32 C = uint32(B); //~WARN: typecasts that can truncate values should be checked\n        uint24 D = uint24(C); //~WARN: typecasts that can truncate values should be checked\n        uint16 E = uint16(D); //~WARN: typecasts that can truncate values should be checked\n        uint8 F = uint8(E); //~WARN: typecasts that can truncate values should be checked\n    }\n\n    function downcastUnsafeInt() public pure {\n        int256 a = type(int256).max;\n        int248 b = int248(a); //~WARN: typecasts that can truncate values should be checked\n        int240 c = int240(b); //~WARN: typecasts that can truncate values should be checked\n        int232 d = int232(c); //~WARN: typecasts that can truncate values should be checked\n        int224 e = int224(d); //~WARN: typecasts that can truncate values should be checked\n        int216 f = int216(e); //~WARN: typecasts that can truncate values should be checked\n        int208 g = int208(f); //~WARN: typecasts that can truncate values should be checked\n        int200 h = int200(g); //~WARN: typecasts that can truncate values should be checked\n        int192 i = int192(h); //~WARN: typecasts that can truncate values should be checked\n        int184 j = int184(i); //~WARN: typecasts that can truncate values should be checked\n        int176 k = int176(j); //~WARN: typecasts that can truncate values should be checked\n        int168 l = int168(k); //~WARN: typecasts that can truncate values should be checked\n        int160 m = int160(l); //~WARN: typecasts that can truncate values should be checked\n        int152 n = int152(m); //~WARN: typecasts that can truncate values should be checked\n        int144 o = int144(n); //~WARN: typecasts that can truncate values should be checked\n        int136 p = int136(o); //~WARN: typecasts that can truncate values should be checked\n        int128 q = int128(p); //~WARN: typecasts that can truncate values should be checked\n        int120 r = int120(q); //~WARN: typecasts that can truncate values should be checked\n        int112 s = int112(r); //~WARN: typecasts that can truncate values should be checked\n        int104 t = int104(s); //~WARN: typecasts that can truncate values should be checked\n        int96 u = int96(t); //~WARN: typecasts that can truncate values should be checked\n        int88 v = int88(u); //~WARN: typecasts that can truncate values should be checked\n        int80 w = int80(v); //~WARN: typecasts that can truncate values should be checked\n        int72 x = int72(w); //~WARN: typecasts that can truncate values should be checked\n        int64 y = int64(x); //~WARN: typecasts that can truncate values should be checked\n        int56 z = int56(y); //~WARN: typecasts that can truncate values should be checked\n        int48 A = int48(z); //~WARN: typecasts that can truncate values should be checked\n        int40 B = int40(A); //~WARN: typecasts that can truncate values should be checked\n        int32 C = int32(B); //~WARN: typecasts that can truncate values should be checked\n        int24 D = int24(C); //~WARN: typecasts that can truncate values should be checked\n        int16 E = int16(D); //~WARN: typecasts that can truncate values should be checked\n        int8 F = int8(E); //~WARN: typecasts that can truncate values should be checked\n    }\n\n    function downcastUnsafeBytes() public pure {\n        bytes32 a = bytes32(type(uint256).max);\n        bytes31 b = bytes31(a); //~WARN: typecasts that can truncate values should be checked\n        bytes30 c = bytes30(b); //~WARN: typecasts that can truncate values should be checked\n        bytes29 d = bytes29(c); //~WARN: typecasts that can truncate values should be checked\n        bytes28 e = bytes28(d); //~WARN: typecasts that can truncate values should be checked\n        bytes27 f = bytes27(e); //~WARN: typecasts that can truncate values should be checked\n        bytes26 g = bytes26(f); //~WARN: typecasts that can truncate values should be checked\n        bytes25 h = bytes25(g); //~WARN: typecasts that can truncate values should be checked\n        bytes24 i = bytes24(h); //~WARN: typecasts that can truncate values should be checked\n        bytes23 j = bytes23(i); //~WARN: typecasts that can truncate values should be checked\n        bytes22 k = bytes22(j); //~WARN: typecasts that can truncate values should be checked\n        bytes21 l = bytes21(k); //~WARN: typecasts that can truncate values should be checked\n        bytes20 m = bytes20(l); //~WARN: typecasts that can truncate values should be checked\n        bytes19 n = bytes19(m); //~WARN: typecasts that can truncate values should be checked\n        bytes18 o = bytes18(n); //~WARN: typecasts that can truncate values should be checked\n        bytes17 p = bytes17(o); //~WARN: typecasts that can truncate values should be checked\n        bytes16 q = bytes16(p); //~WARN: typecasts that can truncate values should be checked\n        bytes15 r = bytes15(q); //~WARN: typecasts that can truncate values should be checked\n        bytes14 s = bytes14(r); //~WARN: typecasts that can truncate values should be checked\n        bytes13 t = bytes13(s); //~WARN: typecasts that can truncate values should be checked\n        bytes12 u = bytes12(t); //~WARN: typecasts that can truncate values should be checked\n        bytes11 v = bytes11(u); //~WARN: typecasts that can truncate values should be checked\n        bytes10 w = bytes10(v); //~WARN: typecasts that can truncate values should be checked\n        bytes9 x = bytes9(w); //~WARN: typecasts that can truncate values should be checked\n        bytes8 y = bytes8(x); //~WARN: typecasts that can truncate values should be checked\n        bytes7 z = bytes7(y); //~WARN: typecasts that can truncate values should be checked\n        bytes6 A = bytes6(z); //~WARN: typecasts that can truncate values should be checked\n        bytes5 B = bytes5(A); //~WARN: typecasts that can truncate values should be checked\n        bytes4 C = bytes4(B); //~WARN: typecasts that can truncate values should be checked\n        bytes3 D = bytes3(C); //~WARN: typecasts that can truncate values should be checked\n        bytes2 E = bytes2(D); //~WARN: typecasts that can truncate values should be checked\n        bytes1 F = bytes1(E); //~WARN: typecasts that can truncate values should be checked\n    }\n\n    function unsignedSignedUnsafe() public pure {\n        uint256 a = type(uint256).max;\n        int256 b = int256(a); //~WARN: typecasts that can truncate values should be checked\n        uint248 c = type(uint248).max;\n        int248 d = int248(c); //~WARN: typecasts that can truncate values should be checked\n        uint240 e = type(uint240).max;\n        int240 f = int240(e); //~WARN: typecasts that can truncate values should be checked\n        uint232 g = type(uint232).max;\n        int232 h = int232(g); //~WARN: typecasts that can truncate values should be checked\n        uint224 i = type(uint224).max;\n        int224 j = int224(i); //~WARN: typecasts that can truncate values should be checked\n        uint216 k = type(uint216).max;\n        int216 l = int216(k); //~WARN: typecasts that can truncate values should be checked\n        uint208 m = type(uint208).max;\n        int208 n = int208(m); //~WARN: typecasts that can truncate values should be checked\n        uint200 o = type(uint200).max;\n        int200 p = int200(o); //~WARN: typecasts that can truncate values should be checked\n        uint192 q = type(uint192).max;\n        int192 r = int192(q); //~WARN: typecasts that can truncate values should be checked\n        uint184 s = type(uint184).max;\n        int184 t = int184(s); //~WARN: typecasts that can truncate values should be checked\n        uint176 u = type(uint176).max;\n        int176 v = int176(u); //~WARN: typecasts that can truncate values should be checked\n        uint168 w = type(uint168).max;\n        int168 x = int168(w); //~WARN: typecasts that can truncate values should be checked\n        uint160 y = type(uint160).max;\n        int160 z = int160(y); //~WARN: typecasts that can truncate values should be checked\n        uint152 A = type(uint152).max;\n        int152 B = int152(A); //~WARN: typecasts that can truncate values should be checked\n        uint144 C = type(uint144).max;\n        int144 D = int144(C); //~WARN: typecasts that can truncate values should be checked\n        uint136 E = type(uint136).max;\n        int136 F = int136(E); //~WARN: typecasts that can truncate values should be checked\n        uint128 G = type(uint128).max;\n        int128 H = int128(G); //~WARN: typecasts that can truncate values should be checked\n        uint120 I = type(uint120).max;\n        int120 J = int120(I); //~WARN: typecasts that can truncate values should be checked\n        uint112 K = type(uint112).max;\n        int112 L = int112(K); //~WARN: typecasts that can truncate values should be checked\n        uint104 M = type(uint104).max;\n        int104 N = int104(M); //~WARN: typecasts that can truncate values should be checked\n        uint96 O = type(uint96).max;\n        int96 P = int96(O); //~WARN: typecasts that can truncate values should be checked\n        uint88 Q = type(uint88).max;\n        int88 R = int88(Q); //~WARN: typecasts that can truncate values should be checked\n        uint80 S = type(uint80).max;\n        int80 T = int80(S); //~WARN: typecasts that can truncate values should be checked\n        uint72 U = type(uint72).max;\n        int72 V = int72(U); //~WARN: typecasts that can truncate values should be checked\n        uint64 W = type(uint64).max;\n        int64 X = int64(W); //~WARN: typecasts that can truncate values should be checked\n        uint56 Y = type(uint56).max;\n        int56 Z = int56(Y); //~WARN: typecasts that can truncate values should be checked\n        uint48 AA = type(uint48).max;\n        int48 BB = int48(AA); //~WARN: typecasts that can truncate values should be checked\n        uint40 CC = type(uint40).max;\n        int40 DD = int40(CC); //~WARN: typecasts that can truncate values should be checked\n        uint32 EE = type(uint32).max;\n        int32 FF = int32(EE); //~WARN: typecasts that can truncate values should be checked\n        uint24 GG = type(uint24).max;\n        int24 HH = int24(GG); //~WARN: typecasts that can truncate values should be checked\n        uint16 II = type(uint16).max;\n        int16 JJ = int16(II); //~WARN: typecasts that can truncate values should be checked\n        uint8 KK = type(uint8).max;\n        int8 LL = int8(KK); //~WARN: typecasts that can truncate values should be checked\n    }\n\n    function signedUnsignedUnsafe() public pure {\n        int256 a = -1;\n        uint256 b = uint256(a); //~WARN: typecasts that can truncate values should be checked\n        int248 c = -1;\n        uint248 d = uint248(c); //~WARN: typecasts that can truncate values should be checked\n        int240 e = -1;\n        uint240 f = uint240(e); //~WARN: typecasts that can truncate values should be checked\n        int232 g = -1;\n        uint232 h = uint232(g); //~WARN: typecasts that can truncate values should be checked\n        int224 i = -1;\n        uint224 j = uint224(i); //~WARN: typecasts that can truncate values should be checked\n        int216 k = -1;\n        uint216 l = uint216(k); //~WARN: typecasts that can truncate values should be checked\n        int208 m = -1;\n        uint208 n = uint208(m); //~WARN: typecasts that can truncate values should be checked\n        int200 o = -1;\n        uint200 p = uint200(o); //~WARN: typecasts that can truncate values should be checked\n        int192 q = -1;\n        uint192 r = uint192(q); //~WARN: typecasts that can truncate values should be checked\n        int184 s = -1;\n        uint184 t = uint184(s); //~WARN: typecasts that can truncate values should be checked\n        int176 u = -1;\n        uint176 v = uint176(u); //~WARN: typecasts that can truncate values should be checked\n        int168 w = -1;\n        uint168 x = uint168(w); //~WARN: typecasts that can truncate values should be checked\n        int160 y = -1;\n        uint160 z = uint160(y); //~WARN: typecasts that can truncate values should be checked\n        int152 A = -1;\n        uint152 B = uint152(A); //~WARN: typecasts that can truncate values should be checked\n        int144 C = -1;\n        uint144 D = uint144(C); //~WARN: typecasts that can truncate values should be checked\n        int136 E = -1;\n        uint136 F = uint136(E); //~WARN: typecasts that can truncate values should be checked\n        int128 G = -1;\n        uint128 H = uint128(G); //~WARN: typecasts that can truncate values should be checked\n        int120 I = -1;\n        uint120 J = uint120(I); //~WARN: typecasts that can truncate values should be checked\n        int112 K = -1;\n        uint112 L = uint112(K); //~WARN: typecasts that can truncate values should be checked\n        int104 M = -1;\n        uint104 N = uint104(M); //~WARN: typecasts that can truncate values should be checked\n        int96 O = -1;\n        uint96 P = uint96(O); //~WARN: typecasts that can truncate values should be checked\n        int88 Q = -1;\n        uint88 R = uint88(Q); //~WARN: typecasts that can truncate values should be checked\n        int80 S = -1;\n        uint80 T = uint80(S); //~WARN: typecasts that can truncate values should be checked\n        int72 U = -1;\n        uint72 V = uint72(U); //~WARN: typecasts that can truncate values should be checked\n        int64 W = -1;\n        uint64 X = uint64(W); //~WARN: typecasts that can truncate values should be checked\n        int56 Y = -1;\n        uint56 Z = uint56(Y); //~WARN: typecasts that can truncate values should be checked\n        int48 AA = -1;\n        uint48 BB = uint48(AA); //~WARN: typecasts that can truncate values should be checked\n        int40 CC = -1;\n        uint40 DD = uint40(CC); //~WARN: typecasts that can truncate values should be checked\n        int32 EE = -1;\n        uint32 FF = uint32(EE); //~WARN: typecasts that can truncate values should be checked\n        int24 GG = -1;\n        uint24 HH = uint24(GG); //~WARN: typecasts that can truncate values should be checked\n        int16 II = -1;\n        uint16 JJ = uint16(II); //~WARN: typecasts that can truncate values should be checked\n        int8 KK = -1;\n        uint8 LL = uint8(KK); //~WARN: typecasts that can truncate values should be checked\n    }\n\n    function downcastDynamicUnsafe() public pure {\n        bytes memory data = \"hello world\";\n        bytes32 dataSlice = bytes32(data); //~WARN: typecasts that can truncate values should be checked\n        string memory str = \"hello world\";\n        bytes32 strSlice = bytes32(bytes(str)); //~WARN: typecasts that can truncate values should be checked\n    }\n}\n\ncontract Repros {\n    function longDynamicBytesDoNotPanic() public pure {\n        bytes memory stringToBytes = bytes(\"Initializable: contract is already initialized\");\n    }\n\n    function nestedCastsAreEvaluatedAtAllDepths(uint64 a, int128 b) internal pure returns (uint64) {\n        uint64 aAloneIsSafe = uint64(uint128(int128(uint128(a))));\n\n        uint128 aPlusB = uint128(int128(uint128(a)) + b);\n        //~^WARN: typecasts that can truncate values should be checked\n\n        uint64 unsafe = uint64(aPlusB);\n        //~^WARN: typecasts that can truncate values should be checked\n\n        return uint64(uint128(int128(uint128(a)) + b));\n        //~^WARN: typecasts that can truncate values should be checked\n        //~|WARN: typecasts that can truncate values should be checked\n    }\n}\n// forge-lint: disable-end(mixed-case-variable)\n"
  },
  {
    "path": "crates/lint/testdata/UnsafeTypecast.stderr",
    "content": "note[multi-contract-file]: prefer having only one contract, interface or library per file\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │ contract UnsafeTypecast {\n   │          ━━━━━━━━━━━━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#multi-contract-file\n\nnote[multi-contract-file]: prefer having only one contract, interface or library per file\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │ contract Repros {\n   │          ━━━━━━\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#multi-contract-file\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         uint248 b = uint248(a);\n   │                     ━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint248' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         uint240 c = uint240(b);\n   │                     ━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint240' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         uint232 d = uint232(c);\n   │                     ━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint232' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         uint224 e = uint224(d);\n   │                     ━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint224' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         uint216 f = uint216(e);\n   │                     ━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint216' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         uint208 g = uint208(f);\n   │                     ━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint208' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         uint200 h = uint200(g);\n   │                     ━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint200' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         uint192 i = uint192(h);\n   │                     ━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint192' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         uint184 j = uint184(i);\n   │                     ━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint184' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         uint176 k = uint176(j);\n   │                     ━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint176' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         uint168 l = uint168(k);\n   │                     ━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint168' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         uint160 m = uint160(l);\n   │                     ━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint160' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         uint152 n = uint152(m);\n   │                     ━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint152' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         uint144 o = uint144(n);\n   │                     ━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint144' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         uint136 p = uint136(o);\n   │                     ━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint136' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         uint128 q = uint128(p);\n   │                     ━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint128' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         uint120 r = uint120(q);\n   │                     ━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint120' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         uint112 s = uint112(r);\n   │                     ━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint112' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         uint104 t = uint104(s);\n   │                     ━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint104' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         uint96 u = uint96(t);\n   │                    ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint96' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         uint88 v = uint88(u);\n   │                    ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint88' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         uint80 w = uint80(v);\n   │                    ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint80' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         uint72 x = uint72(w);\n   │                    ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint72' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         uint64 y = uint64(x);\n   │                    ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint64' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         uint56 z = uint56(y);\n   │                    ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint56' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         uint48 A = uint48(z);\n   │                    ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint48' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         uint40 B = uint40(A);\n   │                    ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint40' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         uint32 C = uint32(B);\n   │                    ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint32' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         uint24 D = uint24(C);\n   │                    ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint24' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         uint16 E = uint16(D);\n   │                    ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint16' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         uint8 F = uint8(E);\n   │                   ━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint8' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         int248 b = int248(a);\n   │                    ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int248' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         int240 c = int240(b);\n   │                    ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int240' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         int232 d = int232(c);\n   │                    ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int232' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         int224 e = int224(d);\n   │                    ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int224' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         int216 f = int216(e);\n   │                    ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int216' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         int208 g = int208(f);\n   │                    ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int208' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         int200 h = int200(g);\n   │                    ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int200' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         int192 i = int192(h);\n   │                    ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int192' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         int184 j = int184(i);\n   │                    ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int184' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         int176 k = int176(j);\n   │                    ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int176' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         int168 l = int168(k);\n   │                    ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int168' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         int160 m = int160(l);\n   │                    ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int160' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         int152 n = int152(m);\n   │                    ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int152' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         int144 o = int144(n);\n   │                    ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int144' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         int136 p = int136(o);\n   │                    ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int136' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         int128 q = int128(p);\n   │                    ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int128' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         int120 r = int120(q);\n   │                    ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int120' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         int112 s = int112(r);\n   │                    ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int112' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         int104 t = int104(s);\n   │                    ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int104' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         int96 u = int96(t);\n   │                   ━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int96' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         int88 v = int88(u);\n   │                   ━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int88' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         int80 w = int80(v);\n   │                   ━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int80' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         int72 x = int72(w);\n   │                   ━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int72' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         int64 y = int64(x);\n   │                   ━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int64' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         int56 z = int56(y);\n   │                   ━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int56' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         int48 A = int48(z);\n   │                   ━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int48' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         int40 B = int40(A);\n   │                   ━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int40' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         int32 C = int32(B);\n   │                   ━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int32' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         int24 D = int24(C);\n   │                   ━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int24' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         int16 E = int16(D);\n   │                   ━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int16' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         int8 F = int8(E);\n   │                  ━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int8' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         bytes31 b = bytes31(a);\n   │                     ━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'bytes31' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         bytes30 c = bytes30(b);\n   │                     ━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'bytes30' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         bytes29 d = bytes29(c);\n   │                     ━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'bytes29' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         bytes28 e = bytes28(d);\n   │                     ━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'bytes28' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         bytes27 f = bytes27(e);\n   │                     ━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'bytes27' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         bytes26 g = bytes26(f);\n   │                     ━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'bytes26' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         bytes25 h = bytes25(g);\n   │                     ━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'bytes25' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         bytes24 i = bytes24(h);\n   │                     ━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'bytes24' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         bytes23 j = bytes23(i);\n   │                     ━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'bytes23' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         bytes22 k = bytes22(j);\n   │                     ━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'bytes22' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         bytes21 l = bytes21(k);\n   │                     ━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'bytes21' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         bytes20 m = bytes20(l);\n   │                     ━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'bytes20' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         bytes19 n = bytes19(m);\n   │                     ━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'bytes19' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         bytes18 o = bytes18(n);\n   │                     ━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'bytes18' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         bytes17 p = bytes17(o);\n   │                     ━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'bytes17' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         bytes16 q = bytes16(p);\n   │                     ━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'bytes16' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         bytes15 r = bytes15(q);\n   │                     ━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'bytes15' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         bytes14 s = bytes14(r);\n   │                     ━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'bytes14' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         bytes13 t = bytes13(s);\n   │                     ━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'bytes13' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         bytes12 u = bytes12(t);\n   │                     ━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'bytes12' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         bytes11 v = bytes11(u);\n   │                     ━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'bytes11' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         bytes10 w = bytes10(v);\n   │                     ━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'bytes10' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         bytes9 x = bytes9(w);\n   │                    ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'bytes9' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         bytes8 y = bytes8(x);\n   │                    ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'bytes8' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         bytes7 z = bytes7(y);\n   │                    ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'bytes7' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         bytes6 A = bytes6(z);\n   │                    ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'bytes6' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         bytes5 B = bytes5(A);\n   │                    ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'bytes5' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         bytes4 C = bytes4(B);\n   │                    ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'bytes4' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         bytes3 D = bytes3(C);\n   │                    ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'bytes3' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         bytes2 E = bytes2(D);\n   │                    ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'bytes2' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         bytes1 F = bytes1(E);\n   │                    ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'bytes1' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         int256 b = int256(a);\n   │                    ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int256' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         int248 d = int248(c);\n   │                    ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int248' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         int240 f = int240(e);\n   │                    ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int240' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         int232 h = int232(g);\n   │                    ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int232' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         int224 j = int224(i);\n   │                    ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int224' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         int216 l = int216(k);\n   │                    ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int216' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         int208 n = int208(m);\n   │                    ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int208' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         int200 p = int200(o);\n   │                    ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int200' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         int192 r = int192(q);\n   │                    ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int192' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         int184 t = int184(s);\n   │                    ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int184' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         int176 v = int176(u);\n   │                    ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int176' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         int168 x = int168(w);\n   │                    ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int168' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         int160 z = int160(y);\n   │                    ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int160' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         int152 B = int152(A);\n   │                    ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int152' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         int144 D = int144(C);\n   │                    ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int144' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         int136 F = int136(E);\n   │                    ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int136' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         int128 H = int128(G);\n   │                    ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int128' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         int120 J = int120(I);\n   │                    ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int120' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         int112 L = int112(K);\n   │                    ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int112' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         int104 N = int104(M);\n   │                    ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int104' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         int96 P = int96(O);\n   │                   ━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int96' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         int88 R = int88(Q);\n   │                   ━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int88' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         int80 T = int80(S);\n   │                   ━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int80' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         int72 V = int72(U);\n   │                   ━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int72' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         int64 X = int64(W);\n   │                   ━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int64' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         int56 Z = int56(Y);\n   │                   ━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int56' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         int48 BB = int48(AA);\n   │                    ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int48' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         int40 DD = int40(CC);\n   │                    ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int40' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         int32 FF = int32(EE);\n   │                    ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int32' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         int24 HH = int24(GG);\n   │                    ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int24' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         int16 JJ = int16(II);\n   │                    ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int16' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         int8 LL = int8(KK);\n   │                   ━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int8' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         uint256 b = uint256(a);\n   │                     ━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint256' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         uint248 d = uint248(c);\n   │                     ━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint248' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         uint240 f = uint240(e);\n   │                     ━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint240' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         uint232 h = uint232(g);\n   │                     ━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint232' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         uint224 j = uint224(i);\n   │                     ━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint224' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         uint216 l = uint216(k);\n   │                     ━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint216' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         uint208 n = uint208(m);\n   │                     ━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint208' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         uint200 p = uint200(o);\n   │                     ━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint200' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         uint192 r = uint192(q);\n   │                     ━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint192' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         uint184 t = uint184(s);\n   │                     ━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint184' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         uint176 v = uint176(u);\n   │                     ━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint176' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         uint168 x = uint168(w);\n   │                     ━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint168' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         uint160 z = uint160(y);\n   │                     ━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint160' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         uint152 B = uint152(A);\n   │                     ━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint152' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         uint144 D = uint144(C);\n   │                     ━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint144' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         uint136 F = uint136(E);\n   │                     ━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint136' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         uint128 H = uint128(G);\n   │                     ━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint128' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         uint120 J = uint120(I);\n   │                     ━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint120' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         uint112 L = uint112(K);\n   │                     ━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint112' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         uint104 N = uint104(M);\n   │                     ━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint104' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         uint96 P = uint96(O);\n   │                    ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint96' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         uint88 R = uint88(Q);\n   │                    ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint88' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         uint80 T = uint80(S);\n   │                    ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint80' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         uint72 V = uint72(U);\n   │                    ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint72' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         uint64 X = uint64(W);\n   │                    ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint64' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         uint56 Z = uint56(Y);\n   │                    ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint56' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         uint48 BB = uint48(AA);\n   │                     ━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint48' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         uint40 DD = uint40(CC);\n   │                     ━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint40' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         uint32 FF = uint32(EE);\n   │                     ━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint32' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         uint24 HH = uint24(GG);\n   │                     ━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint24' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         uint16 JJ = uint16(II);\n   │                     ━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint16' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         uint8 LL = uint8(KK);\n   │                    ━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint8' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         bytes32 dataSlice = bytes32(data);\n   │                             ━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'bytes32' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         bytes32 strSlice = bytes32(bytes(str));\n   │                            ━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'bytes32' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         uint128 aPlusB = uint128(int128(uint128(a)) + b);\n   │                          ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint128' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         uint64 unsafe = uint64(aPlusB);\n   │                         ━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint64' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         return uint64(uint128(int128(uint128(a)) + b));\n   │                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint64' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\nwarning[unsafe-typecast]: typecasts that can truncate values should be checked\n   ╭▸ ROOT/testdata/UnsafeTypecast.sol:LL:CC\n   │\nLL │         return uint64(uint128(int128(uint128(a)) + b));\n   │                       ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint128' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unsafe-typecast\n\n"
  },
  {
    "path": "crates/lint/testdata/UnwrappedModifierLogic.sol",
    "content": "//@compile-flags: --severity code-size\n\n// SPDX-License-Identifier: MIT\npragma solidity ^0.8.18;\n\nlibrary Lib {\n    function onlyOwner(address sender) internal {}\n}\n\ncontract C {\n    function onlyOwner(address sender) public {}\n}\n\n/**\n * @title UnwrappedModifierLogicTest\n * @notice Test cases for the unwrapped-modifier-logic lint\n * @dev This lint helps optimize gas by preventing modifier code duplication.\n *      Solidity inlines modifier code at each usage point instead of using jumps,\n *      so any logic in modifiers gets duplicated, increasing deployment costs.\n */\ncontract UnwrappedModifierLogicTest {\n    // Helpers\n\n    C immutable c;\n\n    event DidSomething(address who);\n    mapping(address => bool) isOwner;\n    mapping(address => mapping(bytes32 => bool)) hasRole;\n\n    /// -----------------------------------------------------------------------\n    /// Exceptions (assembly block)\n    /// -----------------------------------------------------------------------\n\n    modifier freeTempMemory() {\n        uint256 m;\n        assembly (\"memory-safe\") {\n            m := mload(0x40)\n        }\n        _;\n        assembly (\"memory-safe\") {\n            mstore(0x40, m)\n        }\n    }\n\n    modifier assemblyBlock(address sender) {\n        assembly {\n            let x := sender\n        }\n        _;\n    }\n\n    /// -----------------------------------------------------------------------\n    /// Good patterns (only 1 valid statement before or after placeholder)\n    /// -----------------------------------------------------------------------\n\n    function checkPublic(address sender) public {}\n    function checkPrivate(address sender) private {}\n    function checkInternal(address sender) internal {}\n\n    modifier onlyOwnerLibrary() {\n        Lib.onlyOwner(msg.sender);\n        _;\n    }\n\n    modifier onlyOwnerPublic() {\n        checkPublic(msg.sender);\n        _;\n    }\n\n    modifier onlyOwnerPrivate() {\n        checkPrivate(msg.sender);\n        _;\n    }\n\n    modifier onlyOwnerInternal() {\n        checkInternal(msg.sender);\n        _;\n    }\n\n    modifier onlyOwnerBeforeAfter() {\n        checkPublic(msg.sender);\n        _;\n        checkPrivate(msg.sender);\n    }\n\n    /// -----------------------------------------------------------------------\n    /// Bad patterns (multiple valid statements before or after placeholder)\n    /// -----------------------------------------------------------------------\n\n    // Bad because there are multiple valid function calls before the placeholder\n    modifier multipleBeforePlaceholder() { //~NOTE: wrap modifier logic to reduce code size\n        checkPublic(msg.sender); // These should become _multipleBeforePlaceholder()\n        checkPrivate(msg.sender);\n        checkInternal(msg.sender);\n        _;\n    }\n\n    // Bad because there are multiple valid function calls after the placeholder\n    modifier multipleAfterPlaceholder() { //~NOTE: wrap modifier logic to reduce code size\n        _;\n        checkPublic(msg.sender); // These should become _multipleAfterPlaceholder()\n        checkPrivate(msg.sender);\n        checkInternal(msg.sender);\n    }\n\n    // Bad because there are multiple valid statements both before and after\n    modifier multipleBeforeAfterPlaceholder(address sender) { //~NOTE: wrap modifier logic to reduce code size\n        checkPublic(sender); // These should become _multipleBeforeAfterPlaceholderBefore(sender)\n        checkPrivate(sender);\n        _;\n        checkInternal(sender); // These should become _multipleBeforeAfterPlaceholderAfter(sender)\n        checkPublic(sender);\n    }\n\n    /// -----------------------------------------------------------------------\n    /// Bad patterns (uses built-in control flow)\n    /// -----------------------------------------------------------------------\n\n    // Bad because `require` built-in is used.\n    modifier onlyOwner() { //~NOTE: wrap modifier logic to reduce code size\n        require(isOwner[msg.sender], \"Not owner\"); // _onlyOwner();\n        _;\n    }\n\n    // Bad because `if/revert` is used.\n    modifier onlyRole(bytes32 role) { //~NOTE: wrap modifier logic to reduce code size\n        if(!hasRole[msg.sender][role]) revert(\"Not authorized\"); // _onlyRole(role);\n        _;\n    }\n\n    // Bad because `assert` built-in is used.\n    modifier onlyRoleOrOpenRole(bytes32 role) { //~NOTE: wrap modifier logic to reduce code size\n        assert(hasRole[msg.sender][role] || hasRole[address(0)][role]); // _onlyRoleOrOpenRole(role);\n        _;\n    }\n\n    // Bad because `assert` built-in is used (ensures we can parse multiple params).\n    modifier onlyRoleOrAdmin(bytes32 role, address admin) { //~NOTE: wrap modifier logic to reduce code size\n        assert(hasRole[msg.sender][role] || msg.sender == admin); // _onlyRoleOrAdmin(role, admin);\n        _;\n    }\n\n    /// -----------------------------------------------------------------------\n    /// Bad patterns (other invalid expressions and statements)\n    /// -----------------------------------------------------------------------\n\n    // Only call expressions are allowed (public/private/internal functions).\n    modifier assign(address sender) { //~NOTE: wrap modifier logic to reduce code size\n        bool _isOwner = true;\n        isOwner[sender] = _isOwner;\n        _;\n    }\n\n    // Only call expressions are allowed (public/private/internal functions).\n    modifier uncheckedBlock(address sender) { //~NOTE: wrap modifier logic to reduce code size\n        unchecked {\n            sender;\n        }\n        _;\n    }\n\n    // Only call expressions are allowed (public/private/internal functions).\n    modifier emitEvent(address sender) { //~NOTE: wrap modifier logic to reduce code size\n        emit DidSomething(sender);\n        _;\n    }\n\n    /// -----------------------------------------------------------------------\n    /// Bad patterns (contract calls)\n    /// -----------------------------------------------------------------------\n\n    // Bad because there's an external call.\n    modifier onlyOwnerContract(address sender) { //~NOTE: wrap modifier logic to reduce code size\n        c.onlyOwner(sender);\n        _;\n    }\n}\n"
  },
  {
    "path": "crates/lint/testdata/UnwrappedModifierLogic.stderr",
    "content": "note[unwrapped-modifier-logic]: wrap modifier logic to reduce code size\n   ╭▸ ROOT/testdata/UnwrappedModifierLogic.sol:LL:CC\n   │\nLL │ ┏     modifier multipleBeforePlaceholder() {\nLL │ ┃         checkPublic(msg.sender); // These should become _multipleBeforePlaceholder()\nLL │ ┃         checkPrivate(msg.sender);\nLL │ ┃         checkInternal(msg.sender);\nLL │ ┃         _;\nLL │ ┃     }\n   │ ┗━━━━━┛\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unwrapped-modifier-logic\nhelp: wrap modifier logic to reduce code size\n   ╭╴\nLL ±     modifier multipleBeforePlaceholder() {\nLL +         _multipleBeforePlaceholder();\nLL +         _;\nLL +     }\nLL + \nLL +     function _multipleBeforePlaceholder() internal {\nLL +         checkPublic(msg.sender);\nLL +         checkPrivate(msg.sender);\nLL +         checkInternal(msg.sender);\nLL +     }\n   ╰╴\n\nnote[unwrapped-modifier-logic]: wrap modifier logic to reduce code size\n   ╭▸ ROOT/testdata/UnwrappedModifierLogic.sol:LL:CC\n   │\nLL │ ┏     modifier multipleAfterPlaceholder() {\nLL │ ┃         _;\nLL │ ┃         checkPublic(msg.sender); // These should become _multipleAfterPlaceholder()\nLL │ ┃         checkPrivate(msg.sender);\nLL │ ┃         checkInternal(msg.sender);\nLL │ ┃     }\n   │ ┗━━━━━┛\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unwrapped-modifier-logic\nhelp: wrap modifier logic to reduce code size\n   ╭╴\nLL ±     modifier multipleAfterPlaceholder() {\nLL +         _;\nLL +         _multipleAfterPlaceholder();\nLL +     }\nLL + \nLL +     function _multipleAfterPlaceholder() internal {\nLL +         checkPublic(msg.sender);\nLL +         checkPrivate(msg.sender);\nLL +         checkInternal(msg.sender);\nLL +     }\n   ╰╴\n\nnote[unwrapped-modifier-logic]: wrap modifier logic to reduce code size\n   ╭▸ ROOT/testdata/UnwrappedModifierLogic.sol:LL:CC\n   │\nLL │ ┏     modifier multipleBeforeAfterPlaceholder(address sender) {\nLL │ ┃         checkPublic(sender); // These should become _multipleBeforeAfterPlaceholderBefore(sender)\nLL │ ┃         checkPrivate(sender);\nLL │ ┃         _;\nLL │ ┃         checkInternal(sender); // These should become _multipleBeforeAfterPlaceholderAfter(sender)\nLL │ ┃         checkPublic(sender);\nLL │ ┃     }\n   │ ┗━━━━━┛\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unwrapped-modifier-logic\nhelp: wrap modifier logic to reduce code size\n   ╭╴\nLL ±     modifier multipleBeforeAfterPlaceholder(address sender) {\nLL +         _multipleBeforeAfterPlaceholderBefore(sender);\nLL +         _;\nLL +         _multipleBeforeAfterPlaceholderAfter(sender);\nLL +     }\nLL + \nLL +     function _multipleBeforeAfterPlaceholderBefore(address sender) internal {\nLL +         checkPublic(sender);\nLL +         checkPrivate(sender);\nLL +     }\nLL + \nLL +     function _multipleBeforeAfterPlaceholderAfter(address sender) internal {\nLL +         checkInternal(sender);\nLL +         checkPublic(sender);\nLL +     }\n   ╰╴\n\nnote[unwrapped-modifier-logic]: wrap modifier logic to reduce code size\n   ╭▸ ROOT/testdata/UnwrappedModifierLogic.sol:LL:CC\n   │\nLL │ ┏     modifier onlyOwner() {\nLL │ ┃         require(isOwner[msg.sender], \"Not owner\"); // _onlyOwner();\nLL │ ┃         _;\nLL │ ┃     }\n   │ ┗━━━━━┛\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unwrapped-modifier-logic\nhelp: wrap modifier logic to reduce code size\n   ╭╴\nLL ±     modifier onlyOwner() {\nLL +         _onlyOwner();\nLL +         _;\nLL +     }\nLL + \nLL +     function _onlyOwner() internal {\nLL +         require(isOwner[msg.sender], \"Not owner\");\nLL +     }\n   ╰╴\n\nnote[unwrapped-modifier-logic]: wrap modifier logic to reduce code size\n   ╭▸ ROOT/testdata/UnwrappedModifierLogic.sol:LL:CC\n   │\nLL │ ┏     modifier onlyRole(bytes32 role) {\nLL │ ┃         if(!hasRole[msg.sender][role]) revert(\"Not authorized\"); // _onlyRole(role);\nLL │ ┃         _;\nLL │ ┃     }\n   │ ┗━━━━━┛\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unwrapped-modifier-logic\nhelp: wrap modifier logic to reduce code size\n   ╭╴\nLL ±     modifier onlyRole(bytes32 role) {\nLL +         _onlyRole(role);\nLL +         _;\nLL +     }\nLL + \nLL +     function _onlyRole(bytes32 role) internal {\nLL +         if(!hasRole[msg.sender][role]) revert(\"Not authorized\");\nLL +     }\n   ╰╴\n\nnote[unwrapped-modifier-logic]: wrap modifier logic to reduce code size\n   ╭▸ ROOT/testdata/UnwrappedModifierLogic.sol:LL:CC\n   │\nLL │ ┏     modifier onlyRoleOrOpenRole(bytes32 role) {\nLL │ ┃         assert(hasRole[msg.sender][role] || hasRole[address(0)][role]); // _onlyRoleOrOpenRole(role);\nLL │ ┃         _;\nLL │ ┃     }\n   │ ┗━━━━━┛\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unwrapped-modifier-logic\nhelp: wrap modifier logic to reduce code size\n   ╭╴\nLL ±     modifier onlyRoleOrOpenRole(bytes32 role) {\nLL +         _onlyRoleOrOpenRole(role);\nLL +         _;\nLL +     }\nLL + \nLL +     function _onlyRoleOrOpenRole(bytes32 role) internal {\nLL +         assert(hasRole[msg.sender][role] || hasRole[address(0)][role]);\nLL +     }\n   ╰╴\n\nnote[unwrapped-modifier-logic]: wrap modifier logic to reduce code size\n   ╭▸ ROOT/testdata/UnwrappedModifierLogic.sol:LL:CC\n   │\nLL │ ┏     modifier onlyRoleOrAdmin(bytes32 role, address admin) {\nLL │ ┃         assert(hasRole[msg.sender][role] || msg.sender == admin); // _onlyRoleOrAdmin(role, admin);\nLL │ ┃         _;\nLL │ ┃     }\n   │ ┗━━━━━┛\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unwrapped-modifier-logic\nhelp: wrap modifier logic to reduce code size\n   ╭╴\nLL ±     modifier onlyRoleOrAdmin(bytes32 role, address admin) {\nLL +         _onlyRoleOrAdmin(role, admin);\nLL +         _;\nLL +     }\nLL + \nLL +     function _onlyRoleOrAdmin(bytes32 role, address admin) internal {\nLL +         assert(hasRole[msg.sender][role] || msg.sender == admin);\nLL +     }\n   ╰╴\n\nnote[unwrapped-modifier-logic]: wrap modifier logic to reduce code size\n   ╭▸ ROOT/testdata/UnwrappedModifierLogic.sol:LL:CC\n   │\nLL │ ┏     modifier assign(address sender) {\nLL │ ┃         bool _isOwner = true;\nLL │ ┃         isOwner[sender] = _isOwner;\nLL │ ┃         _;\nLL │ ┃     }\n   │ ┗━━━━━┛\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unwrapped-modifier-logic\nhelp: wrap modifier logic to reduce code size\n   ╭╴\nLL ±     modifier assign(address sender) {\nLL +         _assign(sender);\nLL +         _;\nLL +     }\nLL + \nLL +     function _assign(address sender) internal {\nLL +         bool _isOwner = true;\nLL +         isOwner[sender] = _isOwner;\nLL +     }\n   ╰╴\n\nnote[unwrapped-modifier-logic]: wrap modifier logic to reduce code size\n   ╭▸ ROOT/testdata/UnwrappedModifierLogic.sol:LL:CC\n   │\nLL │ ┏     modifier uncheckedBlock(address sender) {\nLL │ ┃         unchecked {\nLL │ ┃             sender;\n   ‡ ┃\nLL │ ┃     }\n   │ ┗━━━━━┛\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unwrapped-modifier-logic\nhelp: wrap modifier logic to reduce code size\n   ╭╴\nLL ±     modifier uncheckedBlock(address sender) {\nLL +         _uncheckedBlock(sender);\nLL +         _;\nLL +     }\nLL + \nLL +     function _uncheckedBlock(address sender) internal {\nLL +         unchecked {\nLL +             sender;\nLL +         }\nLL +     }\n   ╰╴\n\nnote[unwrapped-modifier-logic]: wrap modifier logic to reduce code size\n   ╭▸ ROOT/testdata/UnwrappedModifierLogic.sol:LL:CC\n   │\nLL │ ┏     modifier emitEvent(address sender) {\nLL │ ┃         emit DidSomething(sender);\nLL │ ┃         _;\nLL │ ┃     }\n   │ ┗━━━━━┛\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unwrapped-modifier-logic\nhelp: wrap modifier logic to reduce code size\n   ╭╴\nLL ±     modifier emitEvent(address sender) {\nLL +         _emitEvent(sender);\nLL +         _;\nLL +     }\nLL + \nLL +     function _emitEvent(address sender) internal {\nLL +         emit DidSomething(sender);\nLL +     }\n   ╰╴\n\nnote[unwrapped-modifier-logic]: wrap modifier logic to reduce code size\n   ╭▸ ROOT/testdata/UnwrappedModifierLogic.sol:LL:CC\n   │\nLL │ ┏     modifier onlyOwnerContract(address sender) {\nLL │ ┃         c.onlyOwner(sender);\nLL │ ┃         _;\nLL │ ┃     }\n   │ ┗━━━━━┛\n   │\n   ╰ help: https://book.getfoundry.sh/reference/forge/forge-lint#unwrapped-modifier-logic\nhelp: wrap modifier logic to reduce code size\n   ╭╴\nLL ±     modifier onlyOwnerContract(address sender) {\nLL +         _onlyOwnerContract(sender);\nLL +         _;\nLL +     }\nLL + \nLL +     function _onlyOwnerContract(address sender) internal {\nLL +         c.onlyOwner(sender);\nLL +     }\n   ╰╴\n\n"
  },
  {
    "path": "crates/lint/testdata/auxiliary/ImportsAnotherFile.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.18;\n\ncontract AnotherFile {\n    // This contract is not used\n}\n"
  },
  {
    "path": "crates/lint/testdata/auxiliary/ImportsAnotherFile2.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.18;\n\ncontract AnotherDummy {\n    // This file is not used\n}\n"
  },
  {
    "path": "crates/lint/testdata/auxiliary/ImportsConstants.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.18;\n\nuint256 constant CONSTANT_0 = 42;\nuint256 constant CONSTANT_1 = 99;\n"
  },
  {
    "path": "crates/lint/testdata/auxiliary/ImportsFile.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.18;\n\nimport \"./ImportsTypes.sol\";\n\nlibrary symbol0 {\n    function isUsed(address) internal pure returns (bool) {\n        return true;\n    }\n}\n\ntype symbol1 is uint128;\ntype symbol3 is bytes32;\ntype symbol4 is uint256;\ntype symbol5 is uint256;\ntype symbol2 is bool;\ntype symbolNotUsed is address;\ntype symbolNotUsed2 is address;\ntype symbolNotUsed3 is address;\n\nabstract contract BaseContract {\n    function foo(uint256 a, symbol5 b) external virtual returns (uint256);\n}\ninterface IContract {\n    function foo(uint256 a, uint248 b) external returns (uint256);\n    function convert(address addr) external pure returns (MyOtherType);\n}\n\ninterface IContractNotUsed {\n    function doSomething() external;\n}\n\ninterface docSymbol {}\ninterface docSymbol2 {}\ninterface docSymbolWrongTag {}\n\ninterface eventSymbol {\n    event foo(uint256 bar);\n}\n"
  },
  {
    "path": "crates/lint/testdata/auxiliary/ImportsSomeFile.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.18;\n\nlibrary SomeFile {\n    struct Baz {\n        uint256 amount;\n        address owner;\n    }\n}\n"
  },
  {
    "path": "crates/lint/testdata/auxiliary/ImportsSomeFile2.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.18;\n\nstruct Baz {\n    address sender;\n    uint256 value;\n}\n"
  },
  {
    "path": "crates/lint/testdata/auxiliary/ImportsTypes.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.18;\n\ntype MyType is uint256;\ntype MyOtherType is uint256;\ntype YetAnotherType is bool;\n"
  },
  {
    "path": "crates/lint/testdata/auxiliary/ImportsUtils.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.18;\n\nfunction process(bool flag) pure returns (uint256) {\n    return flag ? 1 : 0;\n}\n\nfunction calculate(uint256 a, uint256 b) pure returns (uint256) {\n    return a + b;\n}\n"
  },
  {
    "path": "crates/lint/testdata/auxiliary/ImportsUtils2.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.18;\n\nfunction process(bool flag) pure returns (uint256) {\n    return flag ? 1 : 0;\n}\n\nfunction calculate(uint256 a, uint256 b) pure returns (uint256) {\n    return a + b;\n}\n"
  },
  {
    "path": "crates/lint/testdata/auxiliary/Test.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.18;\n\ncontract Test {\n    Vm vm;\n}\n\ninterface Vm {\n    // Unsafe cheatcodes\n    function ffi(string[] calldata) external returns (bytes memory);\n    function readFile(string calldata) external returns (string memory);\n    function readLine(string calldata) external returns (string memory);\n    function writeFile(string calldata, string calldata) external;\n    function writeLine(string calldata, string calldata) external;\n    function removeFile(string calldata) external;\n    function closeFile(string calldata) external;\n    function setEnv(string calldata, string calldata) external;\n    function deriveKey(string calldata, uint32) external returns (uint256);\n\n    // Safe cheatcodes\n    function prank(address) external;\n    function deal(address, uint256) external;\n    function warp(uint256) external;\n    function roll(uint256) external;\n    function assume(bool) external;\n    function expectRevert() external;\n}\n"
  },
  {
    "path": "crates/macros/Cargo.toml",
    "content": "[package]\nname = \"foundry-macros\"\n\nversion.workspace = true\nedition.workspace = true\nrust-version.workspace = true\nauthors.workspace = true\nlicense.workspace = true\nhomepage.workspace = true\nrepository.workspace = true\n\n[lints]\nworkspace = true\n\n[lib]\nproc-macro = true\n# proc-macro tests aren't fully supported by cargo-nextest archives\ntest = false\ndoc = false\n\n[dependencies]\nproc-macro2.workspace = true\nquote.workspace = true\nsyn.workspace = true\nproc-macro-error2 = \"2\"\n"
  },
  {
    "path": "crates/macros/src/cheatcodes.rs",
    "content": "use proc_macro2::{Ident, Span, TokenStream};\nuse quote::quote;\nuse syn::{Attribute, Data, DataStruct, DeriveInput, Error, Result};\n\n// TODO: `proc_macro_error2` only emits warnings when feature \"nightly\" is enabled, which we can't\n// practically enable.\nmacro_rules! emit_warning {\n    ($($t:tt)*) => {\n        proc_macro_error2::emit_error! { $($t)* }\n    };\n}\n\npub fn derive_cheatcode(input: &DeriveInput) -> Result<TokenStream> {\n    let name = &input.ident;\n    let name_s = name.to_string();\n    match &input.data {\n        Data::Struct(s) if name_s.ends_with(\"Call\") => derive_call(name, s, &input.attrs),\n        Data::Struct(_) if name_s.ends_with(\"Return\") => Ok(TokenStream::new()),\n        Data::Struct(s) => derive_struct(name, s, &input.attrs),\n        Data::Enum(e) if name_s.ends_with(\"Calls\") => derive_calls_enum(e),\n        Data::Enum(e) if name_s.ends_with(\"Errors\") => derive_errors_events_enum(e, false),\n        Data::Enum(e) if name_s.ends_with(\"Events\") => derive_errors_events_enum(e, true),\n        Data::Enum(e) => derive_enum(name, e, &input.attrs),\n        Data::Union(_) => Err(Error::new(name.span(), \"unions are not supported\")),\n    }\n}\n\n/// Implements `CheatcodeDef` for a function call struct.\nfn derive_call(name: &Ident, data: &DataStruct, attrs: &[Attribute]) -> Result<TokenStream> {\n    let mut group = None::<Ident>;\n    let mut status = None::<TokenStream>;\n    let mut safety = None::<Ident>;\n    for attr in attrs.iter().filter(|a| a.path().is_ident(\"cheatcode\")) {\n        attr.meta.require_list()?.parse_nested_meta(|meta| {\n            let path = meta.path.get_ident().ok_or_else(|| meta.error(\"expected ident\"))?;\n            let path_s = path.to_string();\n            match path_s.as_str() {\n                \"group\" if group.is_none() => group = Some(meta.value()?.parse()?),\n                \"status\" if status.is_none() => status = Some(meta.value()?.parse()?),\n                \"safety\" if safety.is_none() => safety = Some(meta.value()?.parse()?),\n                _ => return Err(meta.error(\"unexpected attribute\")),\n            };\n            Ok(())\n        })?;\n    }\n    let group = group.ok_or_else(|| {\n        syn::Error::new(name.span(), \"missing #[cheatcode(group = ...)] attribute\")\n    })?;\n    let status = status.unwrap_or_else(|| quote!(Stable));\n    let safety = if let Some(safety) = safety {\n        quote!(Safety::#safety)\n    } else {\n        quote! {\n            match Group::#group.safety() {\n                Some(s) => s,\n                None => panic_unknown_safety(),\n            }\n        }\n    };\n\n    check_named_fields(data, name);\n\n    let id = name.to_string();\n    let id = id.strip_suffix(\"Call\").expect(\"function struct ends in Call\");\n\n    let doc = get_docstring(attrs);\n    let (signature, selector, declaration, description) = func_docstring(&doc);\n\n    let mut params = declaration;\n    if let Some(ret) = params.find(\" returns \") {\n        params = &params[..ret];\n    }\n    if params.contains(\" memory \") {\n        emit_warning!(\n            name.span(),\n            \"parameter data locations must be `calldata` instead of `memory`\"\n        );\n    }\n\n    let (visibility, mutability) = parse_function_attrs(declaration, name.span())?;\n    let visibility = Ident::new(visibility, Span::call_site());\n    let mutability = Ident::new(mutability, Span::call_site());\n\n    if description.is_empty() {\n        emit_warning!(name.span(), \"missing documentation for a cheatcode\")\n    }\n    let description = description.replace(\"\\n \", \"\\n\");\n\n    Ok(quote! {\n        impl CheatcodeDef for #name {\n            const CHEATCODE: &'static Cheatcode<'static> = &Cheatcode {\n                func: Function {\n                    id: #id,\n                    description: #description,\n                    declaration: #declaration,\n                    visibility: Visibility::#visibility,\n                    mutability: Mutability::#mutability,\n                    signature: #signature,\n                    selector: #selector,\n                    selector_bytes: <Self as ::alloy_sol_types::SolCall>::SELECTOR,\n                },\n                group: Group::#group,\n                status: Status::#status,\n                safety: #safety,\n            };\n        }\n    })\n}\n\nfn sorted_variant_types(input: &syn::DataEnum) -> Result<Vec<&syn::Type>> {\n    if let Some(v) = input.variants.iter().find(|v| v.fields.len() != 1) {\n        return Err(syn::Error::new(v.ident.span(), \"expected variant to have a single field\"));\n    }\n\n    let mut variants: Vec<_> = input.variants.iter().collect();\n    variants.sort_by_key(|v| &v.ident);\n    Ok(variants.into_iter().map(|v| &v.fields.iter().next().unwrap().ty).collect())\n}\n\n/// Generates the `CHEATCODES` constant and implements `CheatcodeImpl` dispatch for an enum.\nfn derive_calls_enum(input: &syn::DataEnum) -> Result<TokenStream> {\n    let variant_tys = sorted_variant_types(input)?;\n    let variant_names = input.variants.iter().map(|v| &v.ident);\n\n    Ok(quote! {\n        /// All the cheatcodes in [this contract](self).\n        pub const CHEATCODES: &'static [&'static Cheatcode<'static>] = &[#(<#variant_tys as CheatcodeDef>::CHEATCODE,)*];\n\n        /// Internal macro to implement the `Cheatcode` trait for the Vm calls enum.\n        #[doc(hidden)]\n        #[macro_export]\n        macro_rules! vm_calls {\n            ($mac:ident) => {\n                $mac!(#(#variant_names),*)\n            };\n        }\n    })\n}\n\nfn derive_errors_events_enum(input: &syn::DataEnum, events: bool) -> Result<TokenStream> {\n    let variant_tys = sorted_variant_types(input)?;\n\n    let (ident, ty_assoc_name, ty, doc) = if events {\n        (\"VM_EVENTS\", \"EVENT\", \"Event\", \"events\")\n    } else {\n        (\"VM_ERRORS\", \"ERROR\", \"Error\", \"custom errors\")\n    };\n    let ident = Ident::new(ident, Span::call_site());\n    let ty_assoc_name = Ident::new(ty_assoc_name, Span::call_site());\n    let ty = Ident::new(ty, Span::call_site());\n    let doc = format!(\"All the {doc} in [this contract](self).\");\n\n    Ok(quote! {\n        #[doc = #doc]\n        pub const #ident: &'static [&'static #ty<'static>] = &[#(#variant_tys::#ty_assoc_name,)*];\n    })\n}\n\nfn derive_struct(\n    name: &Ident,\n    input: &syn::DataStruct,\n    attrs: &[Attribute],\n) -> Result<TokenStream> {\n    let name_s = name.to_string();\n\n    let doc = get_docstring(attrs);\n    let doc = doc.trim();\n    let kind = match () {\n        () if doc.contains(\"Custom error \") => StructKind::Error,\n        () if doc.contains(\"Event \") => StructKind::Event,\n        _ => StructKind::Struct,\n    };\n\n    let (doc, def) = doc.split_once(\"```solidity\\n\").expect(\"bad docstring\");\n    let mut doc = doc.trim_end();\n    let def_end = def.rfind(\"```\").expect(\"bad docstring\");\n    let def = def[..def_end].trim();\n\n    match kind {\n        StructKind::Error => doc = &doc[..doc.find(\"Custom error \").expect(\"bad doc\")],\n        StructKind::Event => doc = &doc[..doc.find(\"Event \").expect(\"bad doc\")],\n        StructKind::Struct => {}\n    }\n    let doc = doc.trim();\n\n    if doc.is_empty() {\n        let n = match kind {\n            StructKind::Error => \"n\",\n            StructKind::Event => \"n\",\n            StructKind::Struct => \"\",\n        };\n        emit_warning!(name.span(), \"missing documentation for a{n} {}\", kind.as_str());\n    }\n\n    if kind == StructKind::Struct {\n        check_named_fields(input, name);\n    }\n\n    let def = match kind {\n        StructKind::Struct => {\n            let fields = input.fields.iter().map(|f| {\n                let name = f.ident.as_ref().expect(\"field has no name\").to_string();\n\n                let to_find = format!(\"{name};\");\n                let ty_end = def.find(&to_find).expect(\"field not found in def\");\n                let ty = &def[..ty_end];\n                let ty_start = ty.rfind(';').or_else(|| ty.find('{')).expect(\"bad struct def\") + 1;\n                let ty = ty[ty_start..].trim();\n                if ty.is_empty() {\n                    panic!(\"bad struct def: {def:?}\")\n                }\n\n                let doc = get_docstring(&f.attrs);\n                let doc = doc.trim();\n                quote! {\n                    StructField {\n                        name: #name,\n                        ty: #ty,\n                        description: #doc,\n                    }\n                }\n            });\n            quote! {\n                /// The struct definition.\n                pub const STRUCT: &'static Struct<'static> = &Struct {\n                    name: #name_s,\n                    description: #doc,\n                    fields: Cow::Borrowed(&[#(#fields),*]),\n                };\n            }\n        }\n        StructKind::Error => {\n            quote! {\n                /// The custom error definition.\n                pub const ERROR: &'static Error<'static> = &Error {\n                    name: #name_s,\n                    description: #doc,\n                    declaration: #def,\n                };\n            }\n        }\n        StructKind::Event => {\n            quote! {\n                /// The event definition.\n                pub const EVENT: &'static Event<'static> = &Event {\n                    name: #name_s,\n                    description: #doc,\n                    declaration: #def,\n                };\n            }\n        }\n    };\n    Ok(quote! {\n        impl #name {\n            #def\n        }\n    })\n}\n\n#[derive(Clone, Copy, PartialEq, Eq)]\nenum StructKind {\n    Struct,\n    Error,\n    Event,\n}\n\nimpl StructKind {\n    fn as_str(self) -> &'static str {\n        match self {\n            Self::Struct => \"struct\",\n            Self::Error => \"error\",\n            Self::Event => \"event\",\n        }\n    }\n}\n\nfn derive_enum(name: &Ident, input: &syn::DataEnum, attrs: &[Attribute]) -> Result<TokenStream> {\n    let name_s = name.to_string();\n    let doc = get_docstring(attrs);\n    let doc_end = doc.find(\"```solidity\").expect(\"bad docstring\");\n    let doc = doc[..doc_end].trim();\n    if doc.is_empty() {\n        emit_warning!(name.span(), \"missing documentation for an enum\");\n    }\n    let variants = input.variants.iter().filter(|v| v.discriminant.is_none()).map(|v| {\n        let name = v.ident.to_string();\n        let doc = get_docstring(&v.attrs);\n        let doc = doc.trim();\n        if doc.is_empty() {\n            emit_warning!(v.ident.span(), \"missing documentation for a variant\");\n        }\n        quote! {\n            EnumVariant {\n                name: #name,\n                description: #doc,\n            }\n        }\n    });\n    Ok(quote! {\n        impl #name {\n            /// The enum definition.\n            pub const ENUM: &'static Enum<'static> = &Enum {\n                name: #name_s,\n                description: #doc,\n                variants: Cow::Borrowed(&[#(#variants),*]),\n            };\n        }\n    })\n}\n\nfn check_named_fields(data: &DataStruct, ident: &Ident) {\n    for field in &data.fields {\n        if field.ident.is_none() {\n            emit_warning!(ident, \"all params must be named\");\n        }\n    }\n}\n\n/// Flattens all the `#[doc = \"...\"]` attributes into a single string.\nfn get_docstring(attrs: &[Attribute]) -> String {\n    let mut doc = String::new();\n    for attr in attrs {\n        if !attr.path().is_ident(\"doc\") {\n            continue;\n        }\n        let syn::Meta::NameValue(syn::MetaNameValue {\n            value: syn::Expr::Lit(syn::ExprLit { lit: syn::Lit::Str(s), .. }),\n            ..\n        }) = &attr.meta\n        else {\n            continue;\n        };\n\n        let value = s.value();\n        if !value.is_empty() {\n            if !doc.is_empty() {\n                doc.push('\\n');\n            }\n            doc.push_str(&value);\n        }\n    }\n    doc\n}\n\n/// Returns `(signature, hex_selector, declaration, description)` from a given `sol!`-generated\n/// docstring for a function.\n///\n/// # Examples\n///\n/// The following docstring (string literals are joined with newlines):\n/// ```text\n/// \"Function with signature `foo(uint256)` and selector `0x1234abcd`.\"\n/// \"```solidity\"\n/// \"function foo(uint256 x) external view returns (bool y);\"\n/// \"```\"\n/// \"Description of the function.\"\n/// ```\n///\n/// Will return:\n/// ```text\n/// (\n///     \"foo(uint256)\",\n///     \"0x1234abcd\",\n///     \"function foo(uint256 x) external view returns (bool y);\",\n///     \"Description of the function.\"\n/// )\n/// ```\nfn func_docstring(doc: &str) -> (&str, &str, &str, &str) {\n    let expected_start = \"Function with signature `\";\n    let start = doc.find(expected_start).expect(\"no auto docstring\");\n    let (descr_before, auto) = doc.split_at(start);\n\n    let mut lines = auto.lines();\n    let mut next = || lines.next().expect(\"unexpected end of docstring\");\n\n    let sig_line = next();\n    let example_start = next();\n    assert_eq!(example_start, \"```solidity\");\n    let declaration = next();\n    let example_end = next();\n    assert_eq!(example_end, \"```\");\n\n    let n = expected_start.len();\n    let mut sig_end = n;\n    sig_end += sig_line[n..].find('`').unwrap();\n    let sig = &sig_line[n..sig_end];\n    assert!(!sig.starts_with('`') && !sig.ends_with('`'));\n\n    let selector_end = sig_line.rfind('`').unwrap();\n    let selector = sig_line[sig_end..selector_end].strip_prefix(\"` and selector `\").unwrap();\n    assert!(!selector.starts_with('`') && !selector.ends_with('`'));\n    assert!(selector.starts_with(\"0x\"));\n\n    let description = match doc.find(\"```\\n\") {\n        Some(i) => &doc[i + 4..],\n        None => descr_before,\n    };\n\n    (sig, selector, declaration, description.trim())\n}\n\n/// Returns `(visibility, mutability)` from a given Solidity function declaration.\nfn parse_function_attrs(f: &str, span: Span) -> Result<(&str, &str)> {\n    let Some(ext_start) = f.find(\"external\") else {\n        return Err(Error::new(span, \"functions must have `external` visibility\"));\n    };\n    let visibility = \"External\";\n\n    let f = &f[ext_start..];\n    let mutability = if f.contains(\"view\") {\n        \"View\"\n    } else if f.contains(\"pure\") {\n        \"Pure\"\n    } else {\n        \"None\"\n    };\n    Ok((visibility, mutability))\n}\n"
  },
  {
    "path": "crates/macros/src/console_fmt.rs",
    "content": "use proc_macro2::{Delimiter, Group, Ident, TokenStream};\nuse quote::{format_ident, quote};\nuse syn::{\n    Data, DataEnum, DataStruct, DeriveInput, Fields, Member, Token, Type, punctuated::Punctuated,\n};\n\npub fn console_fmt(input: &DeriveInput) -> TokenStream {\n    let name = &input.ident;\n    let tokens = match &input.data {\n        Data::Struct(s) => derive_struct(s),\n        Data::Enum(e) => derive_enum(e),\n        Data::Union(_) => return quote!(compile_error!(\"Unions are unsupported\");),\n    };\n    quote! {\n        impl ConsoleFmt for #name {\n            #tokens\n        }\n    }\n}\n\nfn derive_struct(s: &DataStruct) -> TokenStream {\n    let imp = impl_struct(s).unwrap_or_else(|| quote!(String::new()));\n    quote! {\n        fn fmt(&self, _spec: FormatSpec) -> String {\n            #imp\n        }\n    }\n}\n\nfn impl_struct(s: &DataStruct) -> Option<TokenStream> {\n    if s.fields.is_empty() {\n        return None;\n    }\n\n    if matches!(s.fields, Fields::Unit) {\n        return None;\n    }\n\n    let fields = s.fields.iter().collect::<Vec<_>>();\n    let first_ty = match &fields.first().unwrap().ty {\n        Type::Path(path) => path.path.segments.last().unwrap().ident.to_string(),\n        _ => String::new(),\n    };\n\n    let members = s.fields.members().collect::<Vec<_>>();\n    let args: Punctuated<TokenStream, Token![,]> = members\n        .into_iter()\n        .map(|member| match member {\n            Member::Named(ident) => quote!(&self.#ident),\n            Member::Unnamed(idx) => quote!(&self.#idx),\n        })\n        .collect();\n\n    let imp = if first_ty == \"String\" {\n        // console_format(arg1, [...rest])\n        let mut args = args.pairs();\n        let first = args.next().unwrap();\n        let first = first.value();\n        quote! {\n            console_format((#first).as_str(), &[#(#args)*])\n        }\n    } else {\n        // console_format(\"\", [...args])\n        quote! {\n            console_format(\"\", &[#args])\n        }\n    };\n\n    Some(imp)\n}\n\n/// Delegates to variants.\nfn derive_enum(e: &DataEnum) -> TokenStream {\n    let arms = e.variants.iter().map(|variant| {\n        let name = &variant.ident;\n        let (fields, delimiter) = match &variant.fields {\n            Fields::Named(fields) => (fields.named.iter(), Delimiter::Brace),\n            Fields::Unnamed(fields) => (fields.unnamed.iter(), Delimiter::Parenthesis),\n            Fields::Unit => return quote!(),\n        };\n\n        let fields: Punctuated<Ident, Token![,]> = fields\n            .enumerate()\n            .map(|(i, field)| {\n                field.ident.as_ref().cloned().unwrap_or_else(|| format_ident!(\"__var_{i}\"))\n            })\n            .collect();\n\n        if fields.len() != 1 {\n            unimplemented!(\"Enum variant with more than 1 field\")\n        }\n\n        let field = fields.into_iter().next().unwrap();\n        let fields = Group::new(delimiter, quote!(#field));\n        quote! {\n            Self::#name #fields => ConsoleFmt::fmt(#field, spec),\n        }\n    });\n\n    quote! {\n        fn fmt(&self, spec: FormatSpec) -> String {\n            match self {\n                #(#arms)*\n\n                #[expect(unreachable_code)]\n                _ => String::new(),\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "crates/macros/src/lib.rs",
    "content": "//! # foundry-macros\n//!\n//! Internal Foundry proc-macros.\n\n#![cfg_attr(not(test), warn(unused_crate_dependencies))]\n#![cfg_attr(docsrs, feature(doc_cfg))]\n\n#[macro_use]\nextern crate proc_macro_error2;\n\nuse proc_macro::TokenStream;\nuse syn::{DeriveInput, Error, parse_macro_input};\n\nmod cheatcodes;\nmod console_fmt;\n\n#[proc_macro_derive(ConsoleFmt)]\npub fn console_fmt(input: TokenStream) -> TokenStream {\n    let input = parse_macro_input!(input as DeriveInput);\n    console_fmt::console_fmt(&input).into()\n}\n\n#[proc_macro_derive(Cheatcode, attributes(cheatcode))]\n#[proc_macro_error]\npub fn cheatcode(input: TokenStream) -> TokenStream {\n    let input = parse_macro_input!(input as DeriveInput);\n    cheatcodes::derive_cheatcode(&input).unwrap_or_else(Error::into_compile_error).into()\n}\n"
  },
  {
    "path": "crates/primitives/Cargo.toml",
    "content": "[package]\nname = \"foundry-primitives\"\n\nversion.workspace = true\nedition.workspace = true\nrust-version.workspace = true\nauthors.workspace = true\nlicense.workspace = true\nhomepage.workspace = true\nrepository.workspace = true\n\n[lints]\nworkspace = true\n\n[dependencies]\nalloy-consensus.workspace = true\nalloy-network.workspace = true\nalloy-primitives.workspace = true\nalloy-provider.workspace = true\nalloy-rlp.workspace = true\nalloy-rpc-types = { workspace = true, features = [\"trace\"] }\nalloy-rpc-types-eth.workspace = true\nalloy-serde.workspace = true\nalloy-signer.workspace = true\nalloy-evm = { workspace = true, features = [\"op\"] }\nop-alloy-consensus = { workspace = true, features = [\"serde\", \"alloy-compat\"] }\nop-alloy-rpc-types.workspace = true\nop-revm.workspace = true\nrevm.workspace = true\nserde_json.workspace = true\nserde = { version = \"1.0\", features = [\"derive\"] }\nderive_more.workspace = true\ntempo-primitives.workspace = true\ntempo-alloy.workspace = true\n"
  },
  {
    "path": "crates/primitives/src/lib.rs",
    "content": "//! Foundry primitives\nmod network;\nmod transaction;\n\npub use network::*;\npub use transaction::*;\n"
  },
  {
    "path": "crates/primitives/src/network/mod.rs",
    "content": "use alloy_network::Network;\n\nmod receipt;\nmod transaction;\n\nuse alloy_provider::fillers::{\n    BlobGasFiller, ChainIdFiller, GasFiller, JoinFill, NonceFiller, RecommendedFillers,\n};\npub use receipt::*;\npub use transaction::FoundryTransactionBuilder;\n\n/// Foundry network type.\n///\n/// This network type supports Foundry-specific transaction types, including\n/// op-stack deposit transactions, alongside standard Ethereum transaction types.\n///\n/// Note: This is a basic implementation (\"for now\") that provides the core Network\n/// trait definitions. Full Foundry-specific RPC types will be implemented in future work.\n/// Currently, this uses Ethereum's Network configuration as a compatibility layer.\n#[derive(Debug, Clone, Copy)]\npub struct FoundryNetwork {\n    _private: (),\n}\n\n// Use Ethereum's Network trait implementation as the basis.\n// This provides compatibility with the alloy-network ecosystem while we build\n// out Foundry-specific RPC types.\nimpl Network for FoundryNetwork {\n    type TxType = crate::FoundryTxType;\n\n    type TxEnvelope = crate::FoundryTxEnvelope;\n\n    type UnsignedTx = crate::FoundryTypedTx;\n\n    type ReceiptEnvelope = crate::FoundryReceiptEnvelope;\n\n    type Header = alloy_consensus::Header;\n\n    type TransactionRequest = crate::FoundryTransactionRequest;\n\n    type TransactionResponse = op_alloy_rpc_types::Transaction<crate::FoundryTxEnvelope>;\n\n    type ReceiptResponse = crate::FoundryTxReceipt;\n\n    type HeaderResponse = alloy_rpc_types_eth::Header;\n\n    type BlockResponse =\n        alloy_rpc_types_eth::Block<Self::TransactionResponse, Self::HeaderResponse>;\n}\n\nimpl RecommendedFillers for FoundryNetwork {\n    type RecommendedFillers =\n        JoinFill<GasFiller, JoinFill<BlobGasFiller, JoinFill<NonceFiller, ChainIdFiller>>>;\n\n    fn recommended_fillers() -> Self::RecommendedFillers {\n        Default::default()\n    }\n}\n"
  },
  {
    "path": "crates/primitives/src/network/receipt.rs",
    "content": "use alloy_consensus::{Receipt, TxReceipt};\nuse alloy_network::{AnyReceiptEnvelope, AnyTransactionReceipt, ReceiptResponse};\nuse alloy_primitives::{Address, B256, BlockHash, TxHash, U64};\nuse alloy_rpc_types::{ConversionError, Log, TransactionReceipt};\nuse alloy_serde::WithOtherFields;\nuse derive_more::AsRef;\nuse op_alloy_consensus::{OpDepositReceipt, OpDepositReceiptWithBloom};\nuse serde::{Deserialize, Serialize};\nuse tempo_primitives::TEMPO_TX_TYPE_ID;\n\nuse crate::FoundryReceiptEnvelope;\n\n#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, AsRef)]\npub struct FoundryTxReceipt(pub WithOtherFields<TransactionReceipt<FoundryReceiptEnvelope<Log>>>);\n\nimpl FoundryTxReceipt {\n    pub fn new(inner: TransactionReceipt<FoundryReceiptEnvelope<Log>>) -> Self {\n        Self(WithOtherFields::new(inner))\n    }\n\n    /// Creates a new receipt with a timestamp in the other fields.\n    /// This avoids extra block lookups when timestamp is needed later.\n    pub fn with_timestamp(\n        inner: TransactionReceipt<FoundryReceiptEnvelope<Log>>,\n        timestamp: u64,\n    ) -> Self {\n        let mut receipt = WithOtherFields::new(inner);\n        receipt\n            .other\n            .insert(\"blockTimestamp\".to_string(), serde_json::to_value(timestamp).unwrap());\n        Self(receipt)\n    }\n\n    /// Get block timestamp from other fields if present.\n    pub fn block_timestamp(&self) -> Option<u64> {\n        self.0.other.get_deserialized::<u64>(\"blockTimestamp\").transpose().ok().flatten()\n    }\n}\n\nimpl ReceiptResponse for FoundryTxReceipt {\n    fn contract_address(&self) -> Option<Address> {\n        self.0.contract_address\n    }\n\n    fn status(&self) -> bool {\n        self.0.inner.status()\n    }\n\n    fn block_hash(&self) -> Option<BlockHash> {\n        self.0.block_hash\n    }\n\n    fn block_number(&self) -> Option<u64> {\n        self.0.block_number\n    }\n\n    fn transaction_hash(&self) -> TxHash {\n        self.0.transaction_hash\n    }\n\n    fn transaction_index(&self) -> Option<u64> {\n        self.0.transaction_index()\n    }\n\n    fn gas_used(&self) -> u64 {\n        self.0.gas_used()\n    }\n\n    fn effective_gas_price(&self) -> u128 {\n        self.0.effective_gas_price()\n    }\n\n    fn blob_gas_used(&self) -> Option<u64> {\n        self.0.blob_gas_used()\n    }\n\n    fn blob_gas_price(&self) -> Option<u128> {\n        self.0.blob_gas_price()\n    }\n\n    fn from(&self) -> Address {\n        self.0.from()\n    }\n\n    fn to(&self) -> Option<Address> {\n        self.0.to()\n    }\n\n    fn cumulative_gas_used(&self) -> u64 {\n        self.0.cumulative_gas_used()\n    }\n\n    fn state_root(&self) -> Option<B256> {\n        self.0.state_root()\n    }\n}\n\nimpl TryFrom<AnyTransactionReceipt> for FoundryTxReceipt {\n    type Error = ConversionError;\n\n    fn try_from(receipt: AnyTransactionReceipt) -> Result<Self, Self::Error> {\n        let WithOtherFields {\n            inner:\n                TransactionReceipt {\n                    transaction_hash,\n                    transaction_index,\n                    block_hash,\n                    block_number,\n                    gas_used,\n                    contract_address,\n                    effective_gas_price,\n                    from,\n                    to,\n                    blob_gas_price,\n                    blob_gas_used,\n                    inner: AnyReceiptEnvelope { inner: receipt_with_bloom, r#type },\n                },\n            other,\n        } = receipt;\n\n        Ok(Self(WithOtherFields {\n            inner: TransactionReceipt {\n                transaction_hash,\n                transaction_index,\n                block_hash,\n                block_number,\n                gas_used,\n                contract_address,\n                effective_gas_price,\n                from,\n                to,\n                blob_gas_price,\n                blob_gas_used,\n                inner: match r#type {\n                    0x00 => FoundryReceiptEnvelope::Legacy(receipt_with_bloom),\n                    0x01 => FoundryReceiptEnvelope::Eip2930(receipt_with_bloom),\n                    0x02 => FoundryReceiptEnvelope::Eip1559(receipt_with_bloom),\n                    0x03 => FoundryReceiptEnvelope::Eip4844(receipt_with_bloom),\n                    0x04 => FoundryReceiptEnvelope::Eip7702(receipt_with_bloom),\n                    TEMPO_TX_TYPE_ID => FoundryReceiptEnvelope::Tempo(receipt_with_bloom),\n                    0x7E => {\n                        // Construct the deposit receipt, extracting optional deposit fields\n                        // These fields may not be present in all receipts, so missing/invalid\n                        // values are None\n                        let deposit_nonce = other\n                            .get_deserialized::<U64>(\"depositNonce\")\n                            .transpose()\n                            .ok()\n                            .flatten()\n                            .map(|v| v.to::<u64>());\n                        let deposit_receipt_version = other\n                            .get_deserialized::<U64>(\"depositReceiptVersion\")\n                            .transpose()\n                            .ok()\n                            .flatten()\n                            .map(|v| v.to::<u64>());\n\n                        FoundryReceiptEnvelope::Deposit(OpDepositReceiptWithBloom {\n                            receipt: OpDepositReceipt {\n                                inner: Receipt {\n                                    status: alloy_consensus::Eip658Value::Eip658(\n                                        receipt_with_bloom.status(),\n                                    ),\n                                    cumulative_gas_used: receipt_with_bloom.cumulative_gas_used(),\n                                    logs: receipt_with_bloom.receipt.logs,\n                                },\n                                deposit_nonce,\n                                deposit_receipt_version,\n                            },\n                            logs_bloom: receipt_with_bloom.logs_bloom,\n                        })\n                    }\n                    _ => {\n                        let tx_type = r#type;\n                        return Err(ConversionError::Custom(format!(\n                            \"Unknown transaction receipt type: 0x{tx_type:02X}\"\n                        )));\n                    }\n                },\n            },\n            other,\n        }))\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    // <https://github.com/foundry-rs/foundry/issues/10852>\n    #[test]\n    fn test_receipt_convert() {\n        let s = r#\"{\"type\":\"0x4\",\"status\":\"0x1\",\"cumulativeGasUsed\":\"0x903fd1\",\"logs\":[{\"address\":\"0x0000d9fcd47bf761e7287d8ee09917d7e2100000\",\"topics\":[\"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef\",\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"0x000000000000000000000000234ce51365b9c417171b6dad280f49143e1b0547\"],\"data\":\"0x00000000000000000000000000000000000000000000032139b42c3431700000\",\"blockHash\":\"0xd26b59c1d8b5bfa9362d19eb0da3819dfe0b367987a71f6d30908dd45e0d7a60\",\"blockNumber\":\"0x159663e\",\"blockTimestamp\":\"0x68411f7b\",\"transactionHash\":\"0x17a6af73d1317e69cfc3cac9221bd98261d40f24815850a44dbfbf96652ae52a\",\"transactionIndex\":\"0x22\",\"logIndex\":\"0x158\",\"removed\":false}],\"logsBloom\":\"0x00000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000008100000000000000000000000000000000000000000000000020000200000000000000800000000800000000000000010000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000\",\"transactionHash\":\"0x17a6af73d1317e69cfc3cac9221bd98261d40f24815850a44dbfbf96652ae52a\",\"transactionIndex\":\"0x22\",\"blockHash\":\"0xd26b59c1d8b5bfa9362d19eb0da3819dfe0b367987a71f6d30908dd45e0d7a60\",\"blockNumber\":\"0x159663e\",\"gasUsed\":\"0x28ee7\",\"effectiveGasPrice\":\"0x4bf02090\",\"from\":\"0x234ce51365b9c417171b6dad280f49143e1b0547\",\"to\":\"0x234ce51365b9c417171b6dad280f49143e1b0547\",\"contractAddress\":null}\"#;\n        let receipt: AnyTransactionReceipt = serde_json::from_str(s).unwrap();\n        let _converted = FoundryTxReceipt::try_from(receipt).unwrap();\n    }\n}\n"
  },
  {
    "path": "crates/primitives/src/network/transaction.rs",
    "content": "use alloy_consensus::{\n    BlobTransactionSidecar, BlobTransactionSidecarEip7594, BlobTransactionSidecarVariant,\n};\nuse alloy_network::{AnyNetwork, Ethereum, Network, TransactionBuilder};\nuse alloy_primitives::{Address, B256, Signature, U256};\nuse alloy_rpc_types::SignedAuthorization;\nuse tempo_alloy::TempoNetwork;\n\n/// Composite transaction builder trait for Foundry transactions.\n///\n/// This extends the base `TransactionBuilder` trait with the same methods as\n/// [`alloy_network::TransactionBuilder4844`] for handling blob transaction sidecars, and\n/// [`alloy_network::TransactionBuilder7702`] for handling EIP-7702 authorization lists.\n///\n/// By default, all methods have no-op implementations, so this can be implemented for any Network.\n///\n/// If the Network supports Eip4844 blob transactions implement these methods:\n/// - [`FoundryTransactionBuilder::max_fee_per_blob_gas`]\n/// - [`FoundryTransactionBuilder::set_max_fee_per_blob_gas`]\n/// - [`FoundryTransactionBuilder::blob_versioned_hashes`]\n/// - [`FoundryTransactionBuilder::set_blob_versioned_hashes`]\n/// - [`FoundryTransactionBuilder::blob_sidecar`]\n/// - [`FoundryTransactionBuilder::set_blob_sidecar`]\n///\n/// If the Network supports EIP-7702 authorization lists, implement these methods:\n/// - [`FoundryTransactionBuilder::authorization_list`]\n/// - [`FoundryTransactionBuilder::set_authorization_list`]\n///\n/// If the Network supports Tempo transactions, implement these methods:\n/// - [`FoundryTransactionBuilder::set_fee_token`]\n/// - [`FoundryTransactionBuilder::set_nonce_key`]\n/// - [`FoundryTransactionBuilder::set_key_id`]\n/// - [`FoundryTransactionBuilder::set_valid_before`]\n/// - [`FoundryTransactionBuilder::set_valid_after`]\n/// - [`FoundryTransactionBuilder::set_fee_payer_signature`]\npub trait FoundryTransactionBuilder<N: Network>: TransactionBuilder<N> {\n    /// Reset gas limit\n    fn reset_gas_limit(&mut self);\n\n    /// Get the max fee per blob gas for the transaction.\n    fn max_fee_per_blob_gas(&self) -> Option<u128> {\n        None\n    }\n\n    /// Set the max fee per blob gas for the transaction.\n    fn set_max_fee_per_blob_gas(&mut self, _max_fee_per_blob_gas: u128) {}\n\n    /// Builder-pattern method for setting max fee per blob gas.\n    fn with_max_fee_per_blob_gas(mut self, max_fee_per_blob_gas: u128) -> Self {\n        self.set_max_fee_per_blob_gas(max_fee_per_blob_gas);\n        self\n    }\n\n    /// Gets the EIP-4844 blob versioned hashes of the transaction.\n    ///\n    /// These may be set independently of the sidecar, e.g. when the sidecar\n    /// has been pruned but the hashes are still needed for `eth_call`.\n    fn blob_versioned_hashes(&self) -> Option<&[B256]> {\n        None\n    }\n\n    /// Sets the EIP-4844 blob versioned hashes of the transaction.\n    fn set_blob_versioned_hashes(&mut self, _hashes: Vec<B256>) {}\n\n    /// Builder-pattern method for setting the EIP-4844 blob versioned hashes.\n    fn with_blob_versioned_hashes(mut self, hashes: Vec<B256>) -> Self {\n        self.set_blob_versioned_hashes(hashes);\n        self\n    }\n\n    /// Gets the blob sidecar (either EIP-4844 or EIP-7594 variant) of the transaction.\n    fn blob_sidecar(&self) -> Option<&BlobTransactionSidecarVariant> {\n        None\n    }\n\n    /// Sets the blob sidecar (either EIP-4844 or EIP-7594 variant) of the transaction.\n    ///\n    /// Note: This will also set the versioned blob hashes accordingly:\n    /// [BlobTransactionSidecarVariant::versioned_hashes]\n    fn set_blob_sidecar(&mut self, _sidecar: BlobTransactionSidecarVariant) {}\n\n    /// Builder-pattern method for setting the blob sidecar of the transaction.\n    fn with_blob_sidecar(mut self, sidecar: BlobTransactionSidecarVariant) -> Self {\n        self.set_blob_sidecar(sidecar);\n        self\n    }\n\n    /// Gets the EIP-4844 blob sidecar if the current sidecar is of that variant.\n    fn blob_sidecar_4844(&self) -> Option<&BlobTransactionSidecar> {\n        self.blob_sidecar().and_then(|s| s.as_eip4844())\n    }\n\n    /// Sets the EIP-4844 blob sidecar of the transaction.\n    fn set_blob_sidecar_4844(&mut self, sidecar: BlobTransactionSidecar) {\n        self.set_blob_sidecar(BlobTransactionSidecarVariant::Eip4844(sidecar));\n    }\n\n    /// Builder-pattern method for setting the EIP-4844 blob sidecar of the transaction.\n    fn with_blob_sidecar_4844(mut self, sidecar: BlobTransactionSidecar) -> Self {\n        self.set_blob_sidecar_4844(sidecar);\n        self\n    }\n\n    /// Gets the EIP-7594 blob sidecar if the current sidecar is of that variant.\n    fn blob_sidecar_7594(&self) -> Option<&BlobTransactionSidecarEip7594> {\n        self.blob_sidecar().and_then(|s| s.as_eip7594())\n    }\n\n    /// Sets the EIP-7594 blob sidecar of the transaction.\n    fn set_blob_sidecar_7594(&mut self, sidecar: BlobTransactionSidecarEip7594) {\n        self.set_blob_sidecar(BlobTransactionSidecarVariant::Eip7594(sidecar));\n    }\n\n    /// Builder-pattern method for setting the EIP-7594 blob sidecar of the transaction.\n    fn with_blob_sidecar_7594(mut self, sidecar: BlobTransactionSidecarEip7594) -> Self {\n        self.set_blob_sidecar_7594(sidecar);\n        self\n    }\n\n    /// Get the EIP-7702 authorization list for the transaction.\n    fn authorization_list(&self) -> Option<&Vec<SignedAuthorization>> {\n        None\n    }\n\n    /// Sets the EIP-7702 authorization list.\n    fn set_authorization_list(&mut self, _authorization_list: Vec<SignedAuthorization>) {}\n\n    /// Builder-pattern method for setting the authorization list.\n    fn with_authorization_list(mut self, authorization_list: Vec<SignedAuthorization>) -> Self {\n        self.set_authorization_list(authorization_list);\n        self\n    }\n\n    /// Get the fee token for a Tempo transaction.\n    fn fee_token(&self) -> Option<Address> {\n        None\n    }\n\n    /// Set the fee token for a Tempo transaction.\n    fn set_fee_token(&mut self, _fee_token: Address) {}\n\n    /// Builder-pattern method for setting the Tempo fee token.\n    fn with_fee_token(mut self, fee_token: Address) -> Self {\n        self.set_fee_token(fee_token);\n        self\n    }\n\n    /// Get the 2D nonce key for a Tempo transaction.\n    fn nonce_key(&self) -> Option<U256> {\n        None\n    }\n\n    /// Set the 2D nonce key for the Tempo transaction.\n    fn set_nonce_key(&mut self, _nonce_key: U256) {}\n\n    /// Builder-pattern method for setting a 2D nonce key for a Tempo transaction.\n    fn with_nonce_key(mut self, nonce_key: U256) -> Self {\n        self.set_nonce_key(nonce_key);\n        self\n    }\n\n    /// Get the access key ID for a Tempo transaction.\n    fn key_id(&self) -> Option<Address> {\n        None\n    }\n\n    /// Set the access key ID for a Tempo transaction.\n    ///\n    /// Used during gas estimation to override the key_id that would normally be\n    /// recovered from the signature.\n    fn set_key_id(&mut self, _key_id: Address) {}\n\n    /// Builder-pattern method for setting the Tempo access key ID.\n    fn with_key_id(mut self, key_id: Address) -> Self {\n        self.set_key_id(key_id);\n        self\n    }\n\n    /// Get the valid_before timestamp for a Tempo expiring nonce transaction.\n    fn valid_before(&self) -> Option<u64> {\n        None\n    }\n\n    /// Set the valid_before timestamp for a Tempo expiring nonce transaction.\n    fn set_valid_before(&mut self, _valid_before: u64) {}\n\n    /// Builder-pattern method for setting the valid_before timestamp.\n    fn with_valid_before(mut self, valid_before: u64) -> Self {\n        self.set_valid_before(valid_before);\n        self\n    }\n\n    /// Get the valid_after timestamp for a Tempo expiring nonce transaction.\n    fn valid_after(&self) -> Option<u64> {\n        None\n    }\n\n    /// Set the valid_after timestamp for a Tempo expiring nonce transaction.\n    fn set_valid_after(&mut self, _valid_after: u64) {}\n\n    /// Builder-pattern method for setting the valid_after timestamp.\n    fn with_valid_after(mut self, valid_after: u64) -> Self {\n        self.set_valid_after(valid_after);\n        self\n    }\n\n    /// Get the fee payer (sponsor) signature for a Tempo sponsored transaction.\n    fn fee_payer_signature(&self) -> Option<Signature> {\n        None\n    }\n\n    /// Set the fee payer (sponsor) signature for a Tempo sponsored transaction.\n    fn set_fee_payer_signature(&mut self, _signature: Signature) {}\n\n    /// Builder-pattern method for setting the fee payer signature.\n    fn with_fee_payer_signature(mut self, signature: Signature) -> Self {\n        self.set_fee_payer_signature(signature);\n        self\n    }\n\n    /// Computes the sponsor (fee payer) signature hash for this transaction.\n    ///\n    /// This builds an unsigned consensus-level transaction from the request and computes\n    /// the hash that a sponsor needs to sign. Returns `None` for networks that don't\n    /// support sponsored transactions.\n    fn compute_sponsor_hash(&self, _from: Address) -> Option<B256> {\n        None\n    }\n}\n\nimpl FoundryTransactionBuilder<Ethereum> for <Ethereum as Network>::TransactionRequest {\n    fn reset_gas_limit(&mut self) {\n        self.gas = None;\n    }\n\n    fn max_fee_per_blob_gas(&self) -> Option<u128> {\n        self.max_fee_per_blob_gas\n    }\n\n    fn set_max_fee_per_blob_gas(&mut self, max_fee_per_blob_gas: u128) {\n        self.max_fee_per_blob_gas = Some(max_fee_per_blob_gas);\n    }\n\n    fn blob_versioned_hashes(&self) -> Option<&[B256]> {\n        self.blob_versioned_hashes.as_deref()\n    }\n\n    fn set_blob_versioned_hashes(&mut self, hashes: Vec<B256>) {\n        self.blob_versioned_hashes = Some(hashes);\n    }\n\n    fn blob_sidecar(&self) -> Option<&BlobTransactionSidecarVariant> {\n        self.sidecar.as_ref()\n    }\n\n    fn set_blob_sidecar(&mut self, sidecar: BlobTransactionSidecarVariant) {\n        self.sidecar = Some(sidecar);\n        self.populate_blob_hashes();\n    }\n\n    fn authorization_list(&self) -> Option<&Vec<SignedAuthorization>> {\n        self.authorization_list.as_ref()\n    }\n\n    fn set_authorization_list(&mut self, authorization_list: Vec<SignedAuthorization>) {\n        self.authorization_list = Some(authorization_list);\n    }\n}\n\nimpl FoundryTransactionBuilder<AnyNetwork> for <AnyNetwork as Network>::TransactionRequest {\n    fn reset_gas_limit(&mut self) {\n        self.gas = None;\n    }\n\n    fn max_fee_per_blob_gas(&self) -> Option<u128> {\n        self.max_fee_per_blob_gas\n    }\n\n    fn set_max_fee_per_blob_gas(&mut self, max_fee_per_blob_gas: u128) {\n        self.max_fee_per_blob_gas = Some(max_fee_per_blob_gas);\n    }\n\n    fn blob_versioned_hashes(&self) -> Option<&[B256]> {\n        self.blob_versioned_hashes.as_deref()\n    }\n\n    fn set_blob_versioned_hashes(&mut self, hashes: Vec<B256>) {\n        self.blob_versioned_hashes = Some(hashes);\n    }\n\n    fn blob_sidecar(&self) -> Option<&BlobTransactionSidecarVariant> {\n        self.sidecar.as_ref()\n    }\n\n    fn set_blob_sidecar(&mut self, sidecar: BlobTransactionSidecarVariant) {\n        self.sidecar = Some(sidecar);\n        self.populate_blob_hashes();\n    }\n\n    fn authorization_list(&self) -> Option<&Vec<SignedAuthorization>> {\n        self.authorization_list.as_ref()\n    }\n\n    fn set_authorization_list(&mut self, authorization_list: Vec<SignedAuthorization>) {\n        self.authorization_list = Some(authorization_list);\n    }\n}\n\nimpl FoundryTransactionBuilder<TempoNetwork> for <TempoNetwork as Network>::TransactionRequest {\n    fn reset_gas_limit(&mut self) {\n        self.gas = None;\n    }\n\n    fn authorization_list(&self) -> Option<&Vec<SignedAuthorization>> {\n        self.authorization_list.as_ref()\n    }\n\n    fn set_authorization_list(&mut self, authorization_list: Vec<SignedAuthorization>) {\n        self.authorization_list = Some(authorization_list);\n    }\n\n    fn fee_token(&self) -> Option<Address> {\n        self.fee_token\n    }\n\n    fn set_fee_token(&mut self, fee_token: Address) {\n        self.fee_token = Some(fee_token);\n    }\n\n    fn nonce_key(&self) -> Option<U256> {\n        self.nonce_key\n    }\n\n    fn set_nonce_key(&mut self, nonce_key: U256) {\n        self.nonce_key = Some(nonce_key);\n    }\n\n    fn key_id(&self) -> Option<Address> {\n        self.key_id\n    }\n\n    fn set_key_id(&mut self, key_id: Address) {\n        self.key_id = Some(key_id);\n    }\n\n    fn valid_before(&self) -> Option<u64> {\n        self.valid_before\n    }\n\n    fn set_valid_before(&mut self, valid_before: u64) {\n        self.valid_before = Some(valid_before);\n    }\n\n    fn valid_after(&self) -> Option<u64> {\n        self.valid_after\n    }\n\n    fn set_valid_after(&mut self, valid_after: u64) {\n        self.valid_after = Some(valid_after);\n    }\n\n    fn fee_payer_signature(&self) -> Option<Signature> {\n        self.fee_payer_signature\n    }\n\n    fn set_fee_payer_signature(&mut self, signature: Signature) {\n        self.fee_payer_signature = Some(signature);\n    }\n\n    fn compute_sponsor_hash(&self, from: Address) -> Option<B256> {\n        let tx = self.clone().build_aa().ok()?;\n        Some(tx.fee_payer_signature_hash(from))\n    }\n}\n"
  },
  {
    "path": "crates/primitives/src/transaction/envelope.rs",
    "content": "use alloy_consensus::{\n    Sealed, Signed, TransactionEnvelope, TxEip1559, TxEip2930, TxEnvelope, TxLegacy, TxType,\n    Typed2718,\n    crypto::RecoveryError,\n    transaction::{\n        SignerRecoverable, TxEip7702, TxHashRef,\n        eip4844::{TxEip4844Variant, TxEip4844WithSidecar},\n    },\n};\nuse alloy_evm::{FromRecoveredTx, FromTxWithEncoded};\nuse alloy_network::{AnyRpcTransaction, AnyTxEnvelope, TransactionResponse};\nuse alloy_primitives::{Address, B256, Bytes, TxHash};\nuse alloy_rpc_types::ConversionError;\nuse op_alloy_consensus::{DEPOSIT_TX_TYPE_ID, OpTransaction as OpTransactionTrait, TxDeposit};\nuse op_revm::{OpTransaction, transaction::deposit::DepositTransactionParts};\nuse revm::context::TxEnv;\nuse tempo_primitives::{AASigned, TempoTransaction};\n\n//\n/// Container type for signed, typed transactions.\n// NOTE(onbjerg): Boxing `Tempo(AASigned)` breaks `TransactionEnvelope` derive macro trait bounds.\n#[allow(clippy::large_enum_variant)]\n#[derive(Clone, Debug, TransactionEnvelope)]\n#[envelope(\n    tx_type_name = FoundryTxType,\n    typed = FoundryTypedTx,\n)]\npub enum FoundryTxEnvelope {\n    /// Legacy transaction type\n    #[envelope(ty = 0)]\n    Legacy(Signed<TxLegacy>),\n    /// [EIP-2930] transaction.\n    ///\n    /// [EIP-2930]: https://eips.ethereum.org/EIPS/eip-2930\n    #[envelope(ty = 1)]\n    Eip2930(Signed<TxEip2930>),\n    /// [EIP-1559] transaction.\n    ///\n    /// [EIP-1559]: https://eips.ethereum.org/EIPS/eip-1559\n    #[envelope(ty = 2)]\n    Eip1559(Signed<TxEip1559>),\n    /// [EIP-4844] transaction.\n    ///\n    /// [EIP-4844]: https://eips.ethereum.org/EIPS/eip-4844\n    #[envelope(ty = 3)]\n    Eip4844(Signed<TxEip4844Variant>),\n    /// [EIP-7702] transaction.\n    ///\n    /// [EIP-7702]: https://eips.ethereum.org/EIPS/eip-7702\n    #[envelope(ty = 4)]\n    Eip7702(Signed<TxEip7702>),\n    /// OP stack deposit transaction.\n    ///\n    /// See <https://docs.optimism.io/op-stack/bridging/deposit-flow>.\n    #[envelope(ty = 126)]\n    Deposit(Sealed<TxDeposit>),\n    /// Tempo transaction type.\n    ///\n    /// See <https://docs.tempo.xyz/protocol/transactions>.\n    #[envelope(ty = 0x76, typed = TempoTransaction)]\n    Tempo(AASigned),\n}\n\nimpl FoundryTxEnvelope {\n    /// Converts the transaction into an Ethereum [`TxEnvelope`].\n    ///\n    /// Returns an error if the transaction is not part of the standard Ethereum transaction types.\n    pub fn try_into_eth(self) -> Result<TxEnvelope, Self> {\n        match self {\n            Self::Legacy(tx) => Ok(TxEnvelope::Legacy(tx)),\n            Self::Eip2930(tx) => Ok(TxEnvelope::Eip2930(tx)),\n            Self::Eip1559(tx) => Ok(TxEnvelope::Eip1559(tx)),\n            Self::Eip4844(tx) => Ok(TxEnvelope::Eip4844(tx)),\n            Self::Eip7702(tx) => Ok(TxEnvelope::Eip7702(tx)),\n            Self::Deposit(_) => Err(self),\n            Self::Tempo(_) => Err(self),\n        }\n    }\n\n    pub fn sidecar(&self) -> Option<&TxEip4844WithSidecar> {\n        match self {\n            Self::Eip4844(signed_variant) => match signed_variant.tx() {\n                TxEip4844Variant::TxEip4844WithSidecar(with_sidecar) => Some(with_sidecar),\n                _ => None,\n            },\n            _ => None,\n        }\n    }\n\n    /// Returns the hash of the transaction.\n    ///\n    /// # Note\n    ///\n    /// If this transaction has the Impersonated signature then this returns a modified unique\n    /// hash. This allows us to treat impersonated transactions as unique.\n    pub fn hash(&self) -> B256 {\n        match self {\n            Self::Legacy(t) => *t.hash(),\n            Self::Eip2930(t) => *t.hash(),\n            Self::Eip1559(t) => *t.hash(),\n            Self::Eip4844(t) => *t.hash(),\n            Self::Eip7702(t) => *t.hash(),\n            Self::Deposit(t) => t.tx_hash(),\n            Self::Tempo(t) => *t.hash(),\n        }\n    }\n\n    /// Recovers the Ethereum address which was used to sign the transaction.\n    pub fn recover(&self) -> Result<Address, RecoveryError> {\n        Ok(match self {\n            Self::Legacy(tx) => tx.recover_signer()?,\n            Self::Eip2930(tx) => tx.recover_signer()?,\n            Self::Eip1559(tx) => tx.recover_signer()?,\n            Self::Eip4844(tx) => tx.recover_signer()?,\n            Self::Eip7702(tx) => tx.recover_signer()?,\n            Self::Deposit(tx) => tx.from,\n            Self::Tempo(tx) => tx.signature().recover_signer(&tx.signature_hash())?,\n        })\n    }\n}\n\nimpl TxHashRef for FoundryTxEnvelope {\n    fn tx_hash(&self) -> &TxHash {\n        match self {\n            Self::Legacy(t) => t.hash(),\n            Self::Eip2930(t) => t.hash(),\n            Self::Eip1559(t) => t.hash(),\n            Self::Eip4844(t) => t.hash(),\n            Self::Eip7702(t) => t.hash(),\n            Self::Deposit(t) => t.hash_ref(),\n            Self::Tempo(t) => t.hash(),\n        }\n    }\n}\n\nimpl SignerRecoverable for FoundryTxEnvelope {\n    fn recover_signer(&self) -> Result<Address, RecoveryError> {\n        self.recover()\n    }\n\n    fn recover_signer_unchecked(&self) -> Result<Address, RecoveryError> {\n        self.recover()\n    }\n}\n\nimpl OpTransactionTrait for FoundryTxEnvelope {\n    fn is_deposit(&self) -> bool {\n        matches!(self, Self::Deposit(_))\n    }\n\n    fn as_deposit(&self) -> Option<&Sealed<TxDeposit>> {\n        match self {\n            Self::Deposit(tx) => Some(tx),\n            _ => None,\n        }\n    }\n}\n\nimpl TryFrom<FoundryTxEnvelope> for TxEnvelope {\n    type Error = FoundryTxEnvelope;\n\n    fn try_from(envelope: FoundryTxEnvelope) -> Result<Self, Self::Error> {\n        envelope.try_into_eth()\n    }\n}\n\nimpl TryFrom<AnyRpcTransaction> for FoundryTxEnvelope {\n    type Error = ConversionError;\n\n    fn try_from(value: AnyRpcTransaction) -> Result<Self, Self::Error> {\n        let transaction = value.into_inner();\n        let from = transaction.from();\n        match transaction.into_inner() {\n            AnyTxEnvelope::Ethereum(tx) => match tx {\n                TxEnvelope::Legacy(tx) => Ok(Self::Legacy(tx)),\n                TxEnvelope::Eip2930(tx) => Ok(Self::Eip2930(tx)),\n                TxEnvelope::Eip1559(tx) => Ok(Self::Eip1559(tx)),\n                TxEnvelope::Eip4844(tx) => Ok(Self::Eip4844(tx)),\n                TxEnvelope::Eip7702(tx) => Ok(Self::Eip7702(tx)),\n            },\n            AnyTxEnvelope::Unknown(mut tx) => {\n                // Try to convert to deposit transaction\n                if tx.ty() == DEPOSIT_TX_TYPE_ID {\n                    tx.inner.fields.insert(\"from\".to_string(), serde_json::to_value(from).unwrap());\n                    let deposit_tx =\n                        tx.inner.fields.deserialize_into::<TxDeposit>().map_err(|e| {\n                            ConversionError::Custom(format!(\n                                \"Failed to deserialize deposit tx: {e}\"\n                            ))\n                        })?;\n\n                    return Ok(Self::Deposit(Sealed::new(deposit_tx)));\n                };\n\n                let tx_type = tx.ty();\n                Err(ConversionError::Custom(format!(\"Unknown transaction type: 0x{tx_type:02X}\")))\n            }\n        }\n    }\n}\n\nimpl FromRecoveredTx<FoundryTxEnvelope> for TxEnv {\n    fn from_recovered_tx(tx: &FoundryTxEnvelope, caller: Address) -> Self {\n        match tx {\n            FoundryTxEnvelope::Legacy(signed_tx) => Self::from_recovered_tx(signed_tx, caller),\n            FoundryTxEnvelope::Eip2930(signed_tx) => Self::from_recovered_tx(signed_tx, caller),\n            FoundryTxEnvelope::Eip1559(signed_tx) => Self::from_recovered_tx(signed_tx, caller),\n            FoundryTxEnvelope::Eip4844(signed_tx) => Self::from_recovered_tx(signed_tx, caller),\n            FoundryTxEnvelope::Eip7702(signed_tx) => Self::from_recovered_tx(signed_tx, caller),\n            FoundryTxEnvelope::Deposit(sealed_tx) => {\n                Self::from_recovered_tx(sealed_tx.inner(), caller)\n            }\n            FoundryTxEnvelope::Tempo(_) => unreachable!(\"Tempo tx in Ethereum context\"),\n        }\n    }\n}\n\nimpl FromRecoveredTx<FoundryTxEnvelope> for OpTransaction<TxEnv> {\n    fn from_recovered_tx(tx: &FoundryTxEnvelope, caller: Address) -> Self {\n        match tx {\n            FoundryTxEnvelope::Legacy(signed_tx) => Self::from_recovered_tx(signed_tx, caller),\n            FoundryTxEnvelope::Eip2930(signed_tx) => Self::from_recovered_tx(signed_tx, caller),\n            FoundryTxEnvelope::Eip1559(signed_tx) => Self::from_recovered_tx(signed_tx, caller),\n            FoundryTxEnvelope::Eip4844(signed_tx) => Self::from_recovered_tx(signed_tx, caller),\n            FoundryTxEnvelope::Eip7702(signed_tx) => Self::from_recovered_tx(signed_tx, caller),\n            FoundryTxEnvelope::Deposit(sealed_tx) => {\n                Self::from_recovered_tx(sealed_tx.inner(), caller)\n            }\n            FoundryTxEnvelope::Tempo(_) => unreachable!(\"Tempo tx in Optimism context\"),\n        }\n    }\n}\n\nimpl FromTxWithEncoded<FoundryTxEnvelope> for TxEnv {\n    fn from_encoded_tx(tx: &FoundryTxEnvelope, sender: Address, _encoded: Bytes) -> Self {\n        Self::from_recovered_tx(tx, sender)\n    }\n}\n\nimpl FromTxWithEncoded<FoundryTxEnvelope> for OpTransaction<TxEnv> {\n    fn from_encoded_tx(tx: &FoundryTxEnvelope, caller: Address, encoded: Bytes) -> Self {\n        match tx {\n            FoundryTxEnvelope::Legacy(signed_tx) => {\n                let base = TxEnv::from_recovered_tx(signed_tx, caller);\n                Self { base, enveloped_tx: Some(encoded), deposit: Default::default() }\n            }\n            FoundryTxEnvelope::Eip2930(signed_tx) => {\n                let base = TxEnv::from_recovered_tx(signed_tx, caller);\n                Self { base, enveloped_tx: Some(encoded), deposit: Default::default() }\n            }\n            FoundryTxEnvelope::Eip1559(signed_tx) => {\n                let base = TxEnv::from_recovered_tx(signed_tx, caller);\n                Self { base, enveloped_tx: Some(encoded), deposit: Default::default() }\n            }\n            FoundryTxEnvelope::Eip4844(signed_tx) => {\n                let base = TxEnv::from_recovered_tx(signed_tx, caller);\n                Self { base, enveloped_tx: Some(encoded), deposit: Default::default() }\n            }\n            FoundryTxEnvelope::Eip7702(signed_tx) => {\n                let base = TxEnv::from_recovered_tx(signed_tx, caller);\n                Self { base, enveloped_tx: Some(encoded), deposit: Default::default() }\n            }\n            FoundryTxEnvelope::Deposit(sealed_tx) => {\n                let deposit_tx = sealed_tx.inner();\n                let base = TxEnv::from_recovered_tx(deposit_tx, caller);\n                let deposit = DepositTransactionParts {\n                    source_hash: deposit_tx.source_hash,\n                    mint: Some(deposit_tx.mint),\n                    is_system_transaction: deposit_tx.is_system_transaction,\n                };\n                Self { base, enveloped_tx: Some(encoded), deposit }\n            }\n            FoundryTxEnvelope::Tempo(_) => unreachable!(\"Tempo tx in Optimism context\"),\n        }\n    }\n}\n\nimpl std::fmt::Display for FoundryTxType {\n    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n        match self {\n            Self::Legacy => write!(f, \"legacy\"),\n            Self::Eip2930 => write!(f, \"eip2930\"),\n            Self::Eip1559 => write!(f, \"eip1559\"),\n            Self::Eip4844 => write!(f, \"eip4844\"),\n            Self::Eip7702 => write!(f, \"eip7702\"),\n            Self::Deposit => write!(f, \"deposit\"),\n            Self::Tempo => write!(f, \"tempo\"),\n        }\n    }\n}\n\nimpl From<TxType> for FoundryTxType {\n    fn from(tx: TxType) -> Self {\n        match tx {\n            TxType::Legacy => Self::Legacy,\n            TxType::Eip2930 => Self::Eip2930,\n            TxType::Eip1559 => Self::Eip1559,\n            TxType::Eip4844 => Self::Eip4844,\n            TxType::Eip7702 => Self::Eip7702,\n        }\n    }\n}\n\nimpl From<FoundryTxEnvelope> for FoundryTypedTx {\n    fn from(envelope: FoundryTxEnvelope) -> Self {\n        match envelope {\n            FoundryTxEnvelope::Legacy(signed_tx) => Self::Legacy(signed_tx.strip_signature()),\n            FoundryTxEnvelope::Eip2930(signed_tx) => Self::Eip2930(signed_tx.strip_signature()),\n            FoundryTxEnvelope::Eip1559(signed_tx) => Self::Eip1559(signed_tx.strip_signature()),\n            FoundryTxEnvelope::Eip4844(signed_tx) => Self::Eip4844(signed_tx.strip_signature()),\n            FoundryTxEnvelope::Eip7702(signed_tx) => Self::Eip7702(signed_tx.strip_signature()),\n            FoundryTxEnvelope::Deposit(sealed_tx) => Self::Deposit(sealed_tx.into_inner()),\n            FoundryTxEnvelope::Tempo(signed_tx) => Self::Tempo(signed_tx.strip_signature()),\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use std::str::FromStr;\n\n    use alloy_primitives::{TxKind, U256, b256, hex};\n    use alloy_rlp::Decodable;\n    use alloy_signer::Signature;\n\n    use super::*;\n\n    #[test]\n    fn test_decode_call() {\n        let bytes_first = &mut &hex::decode(\"f86b02843b9aca00830186a094d3e8763675e4c425df46cc3b5c0f6cbdac39604687038d7ea4c68000802ba00eb96ca19e8a77102767a41fc85a36afd5c61ccb09911cec5d3e86e193d9c5aea03a456401896b1b6055311536bf00a718568c744d8c1f9df59879e8350220ca18\").unwrap()[..];\n        let decoded = FoundryTxEnvelope::decode(&mut &bytes_first[..]).unwrap();\n\n        let tx = TxLegacy {\n            nonce: 2u64,\n            gas_price: 1000000000u128,\n            gas_limit: 100000,\n            to: TxKind::Call(Address::from_slice(\n                &hex::decode(\"d3e8763675e4c425df46cc3b5c0f6cbdac396046\").unwrap()[..],\n            )),\n            value: U256::from(1000000000000000u64),\n            input: Bytes::default(),\n            chain_id: Some(4),\n        };\n\n        let signature = Signature::from_str(\"0eb96ca19e8a77102767a41fc85a36afd5c61ccb09911cec5d3e86e193d9c5ae3a456401896b1b6055311536bf00a718568c744d8c1f9df59879e8350220ca182b\").unwrap();\n\n        let tx = FoundryTxEnvelope::Legacy(Signed::new_unchecked(\n            tx,\n            signature,\n            b256!(\"0xa517b206d2223278f860ea017d3626cacad4f52ff51030dc9a96b432f17f8d34\"),\n        ));\n\n        assert_eq!(tx, decoded);\n    }\n\n    #[test]\n    fn test_decode_create_goerli() {\n        // test that an example create tx from goerli decodes properly\n        let tx_bytes =\n              hex::decode(\"02f901ee05228459682f008459682f11830209bf8080b90195608060405234801561001057600080fd5b50610175806100206000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c80630c49c36c14610030575b600080fd5b61003861004e565b604051610045919061011d565b60405180910390f35b60606020600052600f6020527f68656c6c6f2073746174656d696e64000000000000000000000000000000000060405260406000f35b600081519050919050565b600082825260208201905092915050565b60005b838110156100be5780820151818401526020810190506100a3565b838111156100cd576000848401525b50505050565b6000601f19601f8301169050919050565b60006100ef82610084565b6100f9818561008f565b93506101098185602086016100a0565b610112816100d3565b840191505092915050565b6000602082019050818103600083015261013781846100e4565b90509291505056fea264697066735822122051449585839a4ea5ac23cae4552ef8a96b64ff59d0668f76bfac3796b2bdbb3664736f6c63430008090033c080a0136ebffaa8fc8b9fda9124de9ccb0b1f64e90fbd44251b4c4ac2501e60b104f9a07eb2999eec6d185ef57e91ed099afb0a926c5b536f0155dd67e537c7476e1471\")\n                  .unwrap();\n        let _decoded = FoundryTxEnvelope::decode(&mut &tx_bytes[..]).unwrap();\n    }\n\n    #[test]\n    fn can_recover_sender() {\n        // random mainnet tx: https://etherscan.io/tx/0x86718885c4b4218c6af87d3d0b0d83e3cc465df2a05c048aa4db9f1a6f9de91f\n        let bytes = hex::decode(\"02f872018307910d808507204d2cb1827d0094388c818ca8b9251b393131c08a736a67ccb19297880320d04823e2701c80c001a0cf024f4815304df2867a1a74e9d2707b6abda0337d2d54a4438d453f4160f190a07ac0e6b3bc9395b5b9c8b9e6d77204a236577a5b18467b9175c01de4faa208d9\").unwrap();\n\n        let Ok(FoundryTxEnvelope::Eip1559(tx)) = FoundryTxEnvelope::decode(&mut &bytes[..]) else {\n            panic!(\"decoding FoundryTxEnvelope failed\");\n        };\n\n        assert_eq!(\n            tx.hash(),\n            &\"0x86718885c4b4218c6af87d3d0b0d83e3cc465df2a05c048aa4db9f1a6f9de91f\"\n                .parse::<B256>()\n                .unwrap()\n        );\n        assert_eq!(\n            tx.recover_signer().unwrap(),\n            \"0x95222290DD7278Aa3Ddd389Cc1E1d165CC4BAfe5\".parse::<Address>().unwrap()\n        );\n    }\n\n    // Test vector from https://sepolia.etherscan.io/tx/0x9a22ccb0029bc8b0ddd073be1a1d923b7ae2b2ea52100bae0db4424f9107e9c0\n    // Blobscan: https://sepolia.blobscan.com/tx/0x9a22ccb0029bc8b0ddd073be1a1d923b7ae2b2ea52100bae0db4424f9107e9c0\n    #[test]\n    fn test_decode_live_4844_tx() {\n        use alloy_primitives::{address, b256};\n\n        // https://sepolia.etherscan.io/getRawTx?tx=0x9a22ccb0029bc8b0ddd073be1a1d923b7ae2b2ea52100bae0db4424f9107e9c0\n        let raw_tx = alloy_primitives::hex::decode(\"0x03f9011d83aa36a7820fa28477359400852e90edd0008252089411e9ca82a3a762b4b5bd264d4173a242e7a770648080c08504a817c800f8a5a0012ec3d6f66766bedb002a190126b3549fce0047de0d4c25cffce0dc1c57921aa00152d8e24762ff22b1cfd9f8c0683786a7ca63ba49973818b3d1e9512cd2cec4a0013b98c6c83e066d5b14af2b85199e3d4fc7d1e778dd53130d180f5077e2d1c7a001148b495d6e859114e670ca54fb6e2657f0cbae5b08063605093a4b3dc9f8f1a0011ac212f13c5dff2b2c6b600a79635103d6f580a4221079951181b25c7e654901a0c8de4cced43169f9aa3d36506363b2d2c44f6c49fc1fd91ea114c86f3757077ea01e11fdd0d1934eda0492606ee0bb80a7bf8f35cc5f86ec60fe5031ba48bfd544\").unwrap();\n        let res = FoundryTxEnvelope::decode(&mut raw_tx.as_slice()).unwrap();\n        assert!(res.is_type(3));\n\n        let tx = match res {\n            FoundryTxEnvelope::Eip4844(tx) => tx,\n            _ => unreachable!(),\n        };\n\n        assert_eq!(tx.tx().tx().to, address!(\"0x11E9CA82A3a762b4B5bd264d4173a242e7a77064\"));\n\n        assert_eq!(\n            tx.tx().tx().blob_versioned_hashes,\n            vec![\n                b256!(\"0x012ec3d6f66766bedb002a190126b3549fce0047de0d4c25cffce0dc1c57921a\"),\n                b256!(\"0x0152d8e24762ff22b1cfd9f8c0683786a7ca63ba49973818b3d1e9512cd2cec4\"),\n                b256!(\"0x013b98c6c83e066d5b14af2b85199e3d4fc7d1e778dd53130d180f5077e2d1c7\"),\n                b256!(\"0x01148b495d6e859114e670ca54fb6e2657f0cbae5b08063605093a4b3dc9f8f1\"),\n                b256!(\"0x011ac212f13c5dff2b2c6b600a79635103d6f580a4221079951181b25c7e6549\")\n            ]\n        );\n\n        let from = tx.recover_signer().unwrap();\n        assert_eq!(from, address!(\"0xA83C816D4f9b2783761a22BA6FADB0eB0606D7B2\"));\n    }\n\n    #[test]\n    fn test_decode_encode_deposit_tx() {\n        // https://sepolia-optimism.etherscan.io/tx/0xbf8b5f08c43e4b860715cd64fc0849bbce0d0ea20a76b269e7bc8886d112fca7\n        let tx_hash: TxHash = \"0xbf8b5f08c43e4b860715cd64fc0849bbce0d0ea20a76b269e7bc8886d112fca7\"\n            .parse::<TxHash>()\n            .unwrap();\n\n        // https://sepolia-optimism.etherscan.io/getRawTx?tx=0xbf8b5f08c43e4b860715cd64fc0849bbce0d0ea20a76b269e7bc8886d112fca7\n        let raw_tx = alloy_primitives::hex::decode(\n            \"7ef861a0dfd7ae78bf3c414cfaa77f13c0205c82eb9365e217b2daa3448c3156b69b27ac94778f2146f48179643473b82931c4cd7b8f153efd94778f2146f48179643473b82931c4cd7b8f153efd872386f26fc10000872386f26fc10000830186a08080\",\n        )\n        .unwrap();\n        let dep_tx = FoundryTxEnvelope::decode(&mut raw_tx.as_slice()).unwrap();\n\n        let mut encoded = Vec::new();\n        dep_tx.encode_2718(&mut encoded);\n\n        assert_eq!(raw_tx, encoded);\n\n        assert_eq!(tx_hash, dep_tx.hash());\n    }\n\n    #[test]\n    fn can_recover_sender_not_normalized() {\n        let bytes = hex::decode(\"f85f800182520894095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a0efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804\").unwrap();\n\n        let Ok(FoundryTxEnvelope::Legacy(tx)) = FoundryTxEnvelope::decode(&mut &bytes[..]) else {\n            panic!(\"decoding FoundryTxEnvelope failed\");\n        };\n\n        assert_eq!(tx.tx().input, Bytes::from(b\"\"));\n        assert_eq!(tx.tx().gas_price, 1);\n        assert_eq!(tx.tx().gas_limit, 21000);\n        assert_eq!(tx.tx().nonce, 0);\n        if let TxKind::Call(to) = tx.tx().to {\n            assert_eq!(\n                to,\n                \"0x095e7baea6a6c7c4c2dfeb977efac326af552d87\".parse::<Address>().unwrap()\n            );\n        } else {\n            panic!(\"expected a call transaction\");\n        }\n        assert_eq!(tx.tx().value, U256::from(0x0au64));\n        assert_eq!(\n            tx.recover_signer().unwrap(),\n            \"0f65fe9276bc9a24ae7083ae28e2660ef72df99e\".parse::<Address>().unwrap()\n        );\n    }\n\n    #[test]\n    fn deser_to_type_tx() {\n        let tx = r#\"\n        {\n            \"type\": \"0x2\",\n            \"chainId\": \"0x7a69\",\n            \"nonce\": \"0x0\",\n            \"gas\": \"0x5209\",\n            \"maxFeePerGas\": \"0x77359401\",\n            \"maxPriorityFeePerGas\": \"0x1\",\n            \"to\": \"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266\",\n            \"value\": \"0x0\",\n            \"accessList\": [],\n            \"input\": \"0x\",\n            \"r\": \"0x85c2794a580da137e24ccc823b45ae5cea99371ae23ee13860fcc6935f8305b0\",\n            \"s\": \"0x41de7fa4121dab284af4453d30928241208bafa90cdb701fe9bc7054759fe3cd\",\n            \"yParity\": \"0x0\",\n            \"hash\": \"0x8c9b68e8947ace33028dba167354fde369ed7bbe34911b772d09b3c64b861515\"\n        }\"#;\n\n        let _typed_tx: FoundryTxEnvelope = serde_json::from_str(tx).unwrap();\n    }\n\n    #[test]\n    fn test_from_recovered_tx_legacy() {\n        let tx = r#\"\n        {\n            \"type\": \"0x0\",\n            \"chainId\": \"0x1\",\n            \"nonce\": \"0x0\",\n            \"gas\": \"0x5208\",\n            \"gasPrice\": \"0x1\",\n            \"to\": \"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266\",\n            \"value\": \"0x1\",\n            \"input\": \"0x\",\n            \"r\": \"0x85c2794a580da137e24ccc823b45ae5cea99371ae23ee13860fcc6935f8305b0\",\n            \"s\": \"0x41de7fa4121dab284af4453d30928241208bafa90cdb701fe9bc7054759fe3cd\",\n            \"v\": \"0x1b\",\n            \"hash\": \"0x8c9b68e8947ace33028dba167354fde369ed7bbe34911b772d09b3c64b861515\"\n        }\"#;\n\n        let typed_tx: FoundryTxEnvelope = serde_json::from_str(tx).unwrap();\n        let sender = typed_tx.recover().unwrap();\n\n        // Test TxEnv conversion via FromRecoveredTx trait\n        let tx_env = TxEnv::from_recovered_tx(&typed_tx, sender);\n        assert_eq!(tx_env.caller, sender);\n        assert_eq!(tx_env.gas_limit, 0x5208);\n        assert_eq!(tx_env.gas_price, 1);\n\n        // Test OpTransaction<TxEnv> conversion via FromRecoveredTx trait\n        let op_tx = OpTransaction::<TxEnv>::from_recovered_tx(&typed_tx, sender);\n        assert_eq!(op_tx.base.caller, sender);\n        assert_eq!(op_tx.base.gas_limit, 0x5208);\n    }\n\n    // Test vector from Tempo testnet:\n    // https://explorer.testnet.tempo.xyz/tx/0x6d6d8c102064e6dee44abad2024a8b1d37959230baab80e70efbf9b0c739c4fd\n    #[test]\n    fn test_decode_encode_tempo_tx() {\n        use alloy_primitives::address;\n        use tempo_primitives::TEMPO_TX_TYPE_ID;\n\n        let tx_hash: TxHash = \"0x6d6d8c102064e6dee44abad2024a8b1d37959230baab80e70efbf9b0c739c4fd\"\n            .parse::<TxHash>()\n            .unwrap();\n\n        // Raw transaction from Tempo testnet via eth_getRawTransactionByHash\n        let raw_tx = hex::decode(\n            \"76f9025e82a5bd808502cb4178008302d178f8fcf85c9420c000000000000000000000000000000000000080b844095ea7b3000000000000000000000000dec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000989680f89c94dec000000000000000000000000000000000000080b884f8856c0f00000000000000000000000020c000000000000000000000000000000000000000000000000000000000000020c00000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000989680000000000000000000000000000000000000000000000000000000000097d330c0808080809420c000000000000000000000000000000000000180c0b90133027b98b7a8e6c68d7eac741a52e6fdae0560ce3c16ef5427ad46d7a54d0ed86dd41d000000007b2274797065223a22776562617574686e2e676574222c226368616c6c656e6765223a2238453071464a7a50585167546e645473643649456659457776323173516e626966374c4741776e4b43626b222c226f726967696e223a2268747470733a2f2f74656d706f2d6465782e76657263656c2e617070222c2263726f73734f726967696e223a66616c73657dcfd45c3b19745a42f80b134dcb02a8ba099a0e4e7be1984da54734aa81d8f29f74bb9170ae6d25bd510c83fe35895ee5712efe13980a5edc8094c534e23af85eaacc80b21e45fb11f349424dce3a2f23547f60c0ff2f8bcaede2a247545ce8dd87abf0dbb7a5c9507efae2e43833356651b45ac576c2e61cec4e9c0f41fcbf6e\",\n        )\n        .unwrap();\n\n        let tempo_tx = FoundryTxEnvelope::decode(&mut raw_tx.as_slice()).unwrap();\n\n        // Verify it's a Tempo transaction (type 0x76)\n        assert!(tempo_tx.is_type(TEMPO_TX_TYPE_ID));\n\n        let FoundryTxEnvelope::Tempo(ref aa_signed) = tempo_tx else {\n            panic!(\"Expected Tempo transaction\");\n        };\n\n        // Verify the chain ID\n        assert_eq!(aa_signed.tx().chain_id, 42429);\n\n        // Verify the fee token\n        assert_eq!(\n            aa_signed.tx().fee_token,\n            Some(address!(\"0x20C0000000000000000000000000000000000001\"))\n        );\n\n        // Verify gas limit\n        assert_eq!(aa_signed.tx().gas_limit, 184696);\n\n        // Verify we have 2 calls\n        assert_eq!(aa_signed.tx().calls.len(), 2);\n\n        // Verify the hash\n        assert_eq!(tx_hash, tempo_tx.hash());\n\n        // Verify round-trip encoding\n        let mut encoded = Vec::new();\n        tempo_tx.encode_2718(&mut encoded);\n        assert_eq!(raw_tx, encoded);\n\n        // Verify sender recovery (WebAuthn signature)\n        let sender = tempo_tx.recover().unwrap();\n        assert_eq!(sender, address!(\"0x566Ff0f4a6114F8072ecDC8A7A8A13d8d0C6B45F\"));\n    }\n}\n"
  },
  {
    "path": "crates/primitives/src/transaction/mod.rs",
    "content": "mod envelope;\nmod receipt;\nmod request;\n\npub use envelope::{FoundryTxEnvelope, FoundryTxType, FoundryTypedTx};\npub use receipt::FoundryReceiptEnvelope;\npub use request::{FoundryTransactionRequest, get_deposit_tx_parts};\n"
  },
  {
    "path": "crates/primitives/src/transaction/receipt.rs",
    "content": "use alloy_consensus::{\n    Eip658Value, Receipt, ReceiptEnvelope, ReceiptWithBloom, TxReceipt, Typed2718,\n};\nuse alloy_network::eip2718::{\n    Decodable2718, EIP1559_TX_TYPE_ID, EIP2930_TX_TYPE_ID, EIP4844_TX_TYPE_ID, EIP7702_TX_TYPE_ID,\n    Eip2718Error, Encodable2718, LEGACY_TX_TYPE_ID,\n};\nuse alloy_primitives::{Bloom, Log, TxHash, logs_bloom};\nuse alloy_rlp::{BufMut, Decodable, Encodable, Header, bytes};\nuse alloy_rpc_types::{BlockNumHash, trace::otterscan::OtsReceipt};\nuse op_alloy_consensus::{DEPOSIT_TX_TYPE_ID, OpDepositReceipt, OpDepositReceiptWithBloom};\nuse serde::{Deserialize, Serialize};\nuse tempo_primitives::TEMPO_TX_TYPE_ID;\n\nuse crate::FoundryTxType;\n\n#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]\n#[serde(tag = \"type\")]\npub enum FoundryReceiptEnvelope<T = Log> {\n    #[serde(rename = \"0x0\", alias = \"0x00\")]\n    Legacy(ReceiptWithBloom<Receipt<T>>),\n    #[serde(rename = \"0x1\", alias = \"0x01\")]\n    Eip2930(ReceiptWithBloom<Receipt<T>>),\n    #[serde(rename = \"0x2\", alias = \"0x02\")]\n    Eip1559(ReceiptWithBloom<Receipt<T>>),\n    #[serde(rename = \"0x3\", alias = \"0x03\")]\n    Eip4844(ReceiptWithBloom<Receipt<T>>),\n    #[serde(rename = \"0x4\", alias = \"0x04\")]\n    Eip7702(ReceiptWithBloom<Receipt<T>>),\n    #[serde(rename = \"0x7E\", alias = \"0x7e\")]\n    Deposit(OpDepositReceiptWithBloom<T>),\n    #[serde(rename = \"0x76\")]\n    Tempo(ReceiptWithBloom<Receipt<T>>),\n}\n\nimpl FoundryReceiptEnvelope<alloy_rpc_types::Log> {\n    /// Creates a new [`FoundryReceiptEnvelope`] from the given parts.\n    pub fn from_parts(\n        status: bool,\n        cumulative_gas_used: u64,\n        logs: impl IntoIterator<Item = alloy_rpc_types::Log>,\n        tx_type: FoundryTxType,\n        deposit_nonce: Option<u64>,\n        deposit_receipt_version: Option<u64>,\n    ) -> Self {\n        let logs = logs.into_iter().collect::<Vec<_>>();\n        let logs_bloom = logs_bloom(logs.iter().map(|l| &l.inner));\n        let inner_receipt =\n            Receipt { status: Eip658Value::Eip658(status), cumulative_gas_used, logs };\n        match tx_type {\n            FoundryTxType::Legacy => {\n                Self::Legacy(ReceiptWithBloom { receipt: inner_receipt, logs_bloom })\n            }\n            FoundryTxType::Eip2930 => {\n                Self::Eip2930(ReceiptWithBloom { receipt: inner_receipt, logs_bloom })\n            }\n            FoundryTxType::Eip1559 => {\n                Self::Eip1559(ReceiptWithBloom { receipt: inner_receipt, logs_bloom })\n            }\n            FoundryTxType::Eip4844 => {\n                Self::Eip4844(ReceiptWithBloom { receipt: inner_receipt, logs_bloom })\n            }\n            FoundryTxType::Eip7702 => {\n                Self::Eip7702(ReceiptWithBloom { receipt: inner_receipt, logs_bloom })\n            }\n            FoundryTxType::Deposit => {\n                let inner = OpDepositReceiptWithBloom {\n                    receipt: OpDepositReceipt {\n                        inner: inner_receipt,\n                        deposit_nonce,\n                        deposit_receipt_version,\n                    },\n                    logs_bloom,\n                };\n                Self::Deposit(inner)\n            }\n            FoundryTxType::Tempo => {\n                Self::Tempo(ReceiptWithBloom { receipt: inner_receipt, logs_bloom })\n            }\n        }\n    }\n}\n\nimpl FoundryReceiptEnvelope<Log> {\n    pub fn convert_logs_rpc(\n        self,\n        block_numhash: BlockNumHash,\n        block_timestamp: u64,\n        transaction_hash: TxHash,\n        transaction_index: u64,\n        next_log_index: usize,\n    ) -> FoundryReceiptEnvelope<alloy_rpc_types::Log> {\n        let logs = self\n            .logs()\n            .iter()\n            .enumerate()\n            .map(|(index, log)| alloy_rpc_types::Log {\n                inner: log.clone(),\n                block_hash: Some(block_numhash.hash),\n                block_number: Some(block_numhash.number),\n                block_timestamp: Some(block_timestamp),\n                transaction_hash: Some(transaction_hash),\n                transaction_index: Some(transaction_index),\n                log_index: Some((next_log_index + index) as u64),\n                removed: false,\n            })\n            .collect::<Vec<_>>();\n        FoundryReceiptEnvelope::<alloy_rpc_types::Log>::from_parts(\n            self.status(),\n            self.cumulative_gas_used(),\n            logs,\n            self.tx_type(),\n            self.deposit_nonce(),\n            self.deposit_receipt_version(),\n        )\n    }\n}\n\nimpl<T> FoundryReceiptEnvelope<T> {\n    /// Return the [`FoundryTxType`] of the inner receipt.\n    pub const fn tx_type(&self) -> FoundryTxType {\n        match self {\n            Self::Legacy(_) => FoundryTxType::Legacy,\n            Self::Eip2930(_) => FoundryTxType::Eip2930,\n            Self::Eip1559(_) => FoundryTxType::Eip1559,\n            Self::Eip4844(_) => FoundryTxType::Eip4844,\n            Self::Eip7702(_) => FoundryTxType::Eip7702,\n            Self::Deposit(_) => FoundryTxType::Deposit,\n            Self::Tempo(_) => FoundryTxType::Tempo,\n        }\n    }\n\n    /// Returns the success status of the receipt's transaction.\n    pub const fn status(&self) -> bool {\n        self.as_receipt().status.coerce_status()\n    }\n\n    /// Returns the cumulative gas used at this receipt.\n    pub const fn cumulative_gas_used(&self) -> u64 {\n        self.as_receipt().cumulative_gas_used\n    }\n\n    /// Converts the receipt's log type by applying a function to each log.\n    ///\n    /// Returns the receipt with the new log type.\n    pub fn map_logs<U>(self, f: impl FnMut(T) -> U) -> FoundryReceiptEnvelope<U> {\n        match self {\n            Self::Legacy(r) => FoundryReceiptEnvelope::Legacy(r.map_logs(f)),\n            Self::Eip2930(r) => FoundryReceiptEnvelope::Eip2930(r.map_logs(f)),\n            Self::Eip1559(r) => FoundryReceiptEnvelope::Eip1559(r.map_logs(f)),\n            Self::Eip4844(r) => FoundryReceiptEnvelope::Eip4844(r.map_logs(f)),\n            Self::Eip7702(r) => FoundryReceiptEnvelope::Eip7702(r.map_logs(f)),\n            Self::Deposit(r) => FoundryReceiptEnvelope::Deposit(r.map_receipt(|r| r.map_logs(f))),\n            Self::Tempo(r) => FoundryReceiptEnvelope::Tempo(r.map_logs(f)),\n        }\n    }\n\n    /// Return the receipt logs.\n    pub fn logs(&self) -> &[T] {\n        &self.as_receipt().logs\n    }\n\n    /// Consumes the type and returns the logs.\n    pub fn into_logs(self) -> Vec<T> {\n        self.into_receipt().logs\n    }\n\n    /// Return the receipt's bloom.\n    pub const fn logs_bloom(&self) -> &Bloom {\n        match self {\n            Self::Legacy(t) => &t.logs_bloom,\n            Self::Eip2930(t) => &t.logs_bloom,\n            Self::Eip1559(t) => &t.logs_bloom,\n            Self::Eip4844(t) => &t.logs_bloom,\n            Self::Eip7702(t) => &t.logs_bloom,\n            Self::Deposit(t) => &t.logs_bloom,\n            Self::Tempo(t) => &t.logs_bloom,\n        }\n    }\n\n    /// Return the receipt's deposit_nonce if it is a deposit receipt.\n    pub fn deposit_nonce(&self) -> Option<u64> {\n        self.as_deposit_receipt().and_then(|r| r.deposit_nonce)\n    }\n\n    /// Return the receipt's deposit version if it is a deposit receipt.\n    pub fn deposit_receipt_version(&self) -> Option<u64> {\n        self.as_deposit_receipt().and_then(|r| r.deposit_receipt_version)\n    }\n\n    /// Returns the deposit receipt if it is a deposit receipt.\n    pub const fn as_deposit_receipt_with_bloom(&self) -> Option<&OpDepositReceiptWithBloom<T>> {\n        match self {\n            Self::Deposit(t) => Some(t),\n            _ => None,\n        }\n    }\n\n    /// Returns the deposit receipt if it is a deposit receipt.\n    pub const fn as_deposit_receipt(&self) -> Option<&OpDepositReceipt<T>> {\n        match self {\n            Self::Deposit(t) => Some(&t.receipt),\n            _ => None,\n        }\n    }\n\n    /// Consumes the type and returns the underlying [`Receipt`].\n    pub fn into_receipt(self) -> Receipt<T> {\n        match self {\n            Self::Legacy(t)\n            | Self::Eip2930(t)\n            | Self::Eip1559(t)\n            | Self::Eip4844(t)\n            | Self::Eip7702(t)\n            | Self::Tempo(t) => t.receipt,\n            Self::Deposit(t) => t.receipt.into_inner(),\n        }\n    }\n\n    /// Return the inner receipt.\n    pub const fn as_receipt(&self) -> &Receipt<T> {\n        match self {\n            Self::Legacy(t)\n            | Self::Eip2930(t)\n            | Self::Eip1559(t)\n            | Self::Eip4844(t)\n            | Self::Eip7702(t)\n            | Self::Tempo(t) => &t.receipt,\n            Self::Deposit(t) => &t.receipt.inner,\n        }\n    }\n}\n\nimpl<T> TxReceipt for FoundryReceiptEnvelope<T>\nwhere\n    T: Clone + core::fmt::Debug + PartialEq + Eq + Send + Sync,\n{\n    type Log = T;\n\n    fn status_or_post_state(&self) -> Eip658Value {\n        self.as_receipt().status\n    }\n\n    fn status(&self) -> bool {\n        self.status()\n    }\n\n    /// Return the receipt's bloom.\n    fn bloom(&self) -> Bloom {\n        *self.logs_bloom()\n    }\n\n    fn bloom_cheap(&self) -> Option<Bloom> {\n        Some(self.bloom())\n    }\n\n    /// Returns the cumulative gas used at this receipt.\n    fn cumulative_gas_used(&self) -> u64 {\n        self.cumulative_gas_used()\n    }\n\n    /// Return the receipt logs.\n    fn logs(&self) -> &[T] {\n        self.logs()\n    }\n}\n\nimpl Encodable for FoundryReceiptEnvelope {\n    fn encode(&self, out: &mut dyn bytes::BufMut) {\n        match self {\n            Self::Legacy(r) => r.encode(out),\n            receipt => {\n                let payload_len = match receipt {\n                    Self::Eip2930(r) => r.length() + 1,\n                    Self::Eip1559(r) => r.length() + 1,\n                    Self::Eip4844(r) => r.length() + 1,\n                    Self::Eip7702(r) => r.length() + 1,\n                    Self::Deposit(r) => r.length() + 1,\n                    Self::Tempo(r) => r.length() + 1,\n                    _ => unreachable!(\"receipt already matched\"),\n                };\n\n                match receipt {\n                    Self::Eip2930(r) => {\n                        Header { list: true, payload_length: payload_len }.encode(out);\n                        EIP2930_TX_TYPE_ID.encode(out);\n                        r.encode(out);\n                    }\n                    Self::Eip1559(r) => {\n                        Header { list: true, payload_length: payload_len }.encode(out);\n                        EIP1559_TX_TYPE_ID.encode(out);\n                        r.encode(out);\n                    }\n                    Self::Eip4844(r) => {\n                        Header { list: true, payload_length: payload_len }.encode(out);\n                        EIP4844_TX_TYPE_ID.encode(out);\n                        r.encode(out);\n                    }\n                    Self::Eip7702(r) => {\n                        Header { list: true, payload_length: payload_len }.encode(out);\n                        EIP7702_TX_TYPE_ID.encode(out);\n                        r.encode(out);\n                    }\n                    Self::Deposit(r) => {\n                        Header { list: true, payload_length: payload_len }.encode(out);\n                        DEPOSIT_TX_TYPE_ID.encode(out);\n                        r.encode(out);\n                    }\n                    Self::Tempo(r) => {\n                        Header { list: true, payload_length: payload_len }.encode(out);\n                        TEMPO_TX_TYPE_ID.encode(out);\n                        r.encode(out);\n                    }\n                    _ => unreachable!(\"receipt already matched\"),\n                }\n            }\n        }\n    }\n}\n\nimpl Decodable for FoundryReceiptEnvelope {\n    fn decode(buf: &mut &[u8]) -> alloy_rlp::Result<Self> {\n        use bytes::Buf;\n        use std::cmp::Ordering;\n\n        // a receipt is either encoded as a string (non legacy) or a list (legacy).\n        // We should not consume the buffer if we are decoding a legacy receipt, so let's\n        // check if the first byte is between 0x80 and 0xbf.\n        let rlp_type = *buf\n            .first()\n            .ok_or(alloy_rlp::Error::Custom(\"cannot decode a receipt from empty bytes\"))?;\n\n        match rlp_type.cmp(&alloy_rlp::EMPTY_LIST_CODE) {\n            Ordering::Less => {\n                // strip out the string header\n                let _header = Header::decode(buf)?;\n                let receipt_type = *buf.first().ok_or(alloy_rlp::Error::Custom(\n                    \"typed receipt cannot be decoded from an empty slice\",\n                ))?;\n                if receipt_type == EIP2930_TX_TYPE_ID {\n                    buf.advance(1);\n                    <ReceiptWithBloom as Decodable>::decode(buf)\n                        .map(FoundryReceiptEnvelope::Eip2930)\n                } else if receipt_type == EIP1559_TX_TYPE_ID {\n                    buf.advance(1);\n                    <ReceiptWithBloom as Decodable>::decode(buf)\n                        .map(FoundryReceiptEnvelope::Eip1559)\n                } else if receipt_type == EIP4844_TX_TYPE_ID {\n                    buf.advance(1);\n                    <ReceiptWithBloom as Decodable>::decode(buf)\n                        .map(FoundryReceiptEnvelope::Eip4844)\n                } else if receipt_type == EIP7702_TX_TYPE_ID {\n                    buf.advance(1);\n                    <ReceiptWithBloom as Decodable>::decode(buf)\n                        .map(FoundryReceiptEnvelope::Eip7702)\n                } else if receipt_type == DEPOSIT_TX_TYPE_ID {\n                    buf.advance(1);\n                    <OpDepositReceiptWithBloom as Decodable>::decode(buf)\n                        .map(FoundryReceiptEnvelope::Deposit)\n                } else if receipt_type == TEMPO_TX_TYPE_ID {\n                    buf.advance(1);\n                    <ReceiptWithBloom as Decodable>::decode(buf).map(FoundryReceiptEnvelope::Tempo)\n                } else {\n                    Err(alloy_rlp::Error::Custom(\"invalid receipt type\"))\n                }\n            }\n            Ordering::Equal => {\n                Err(alloy_rlp::Error::Custom(\"an empty list is not a valid receipt encoding\"))\n            }\n            Ordering::Greater => {\n                <ReceiptWithBloom as Decodable>::decode(buf).map(FoundryReceiptEnvelope::Legacy)\n            }\n        }\n    }\n}\n\nimpl Typed2718 for FoundryReceiptEnvelope {\n    fn ty(&self) -> u8 {\n        match self {\n            Self::Legacy(_) => LEGACY_TX_TYPE_ID,\n            Self::Eip2930(_) => EIP2930_TX_TYPE_ID,\n            Self::Eip1559(_) => EIP1559_TX_TYPE_ID,\n            Self::Eip4844(_) => EIP4844_TX_TYPE_ID,\n            Self::Eip7702(_) => EIP7702_TX_TYPE_ID,\n            Self::Deposit(_) => DEPOSIT_TX_TYPE_ID,\n            Self::Tempo(_) => TEMPO_TX_TYPE_ID,\n        }\n    }\n}\n\nimpl Encodable2718 for FoundryReceiptEnvelope {\n    fn encode_2718_len(&self) -> usize {\n        match self {\n            Self::Legacy(r) => r.length(),\n            Self::Eip2930(r) => 1 + r.length(),\n            Self::Eip1559(r) => 1 + r.length(),\n            Self::Eip4844(r) => 1 + r.length(),\n            Self::Eip7702(r) => 1 + r.length(),\n            Self::Deposit(r) => 1 + r.length(),\n            Self::Tempo(r) => 1 + r.length(),\n        }\n    }\n\n    fn encode_2718(&self, out: &mut dyn BufMut) {\n        if let Some(ty) = self.type_flag() {\n            out.put_u8(ty);\n        }\n        match self {\n            Self::Legacy(r)\n            | Self::Eip2930(r)\n            | Self::Eip1559(r)\n            | Self::Eip4844(r)\n            | Self::Eip7702(r)\n            | Self::Tempo(r) => r.encode(out),\n            Self::Deposit(r) => r.encode(out),\n        }\n    }\n}\n\nimpl Decodable2718 for FoundryReceiptEnvelope {\n    fn typed_decode(ty: u8, buf: &mut &[u8]) -> Result<Self, Eip2718Error> {\n        if ty == DEPOSIT_TX_TYPE_ID {\n            return Ok(Self::Deposit(OpDepositReceiptWithBloom::decode(buf)?));\n        }\n        if ty == TEMPO_TX_TYPE_ID {\n            return Ok(Self::Tempo(ReceiptWithBloom::decode(buf)?));\n        }\n        match ReceiptEnvelope::typed_decode(ty, buf)? {\n            ReceiptEnvelope::Eip2930(tx) => Ok(Self::Eip2930(tx)),\n            ReceiptEnvelope::Eip1559(tx) => Ok(Self::Eip1559(tx)),\n            ReceiptEnvelope::Eip4844(tx) => Ok(Self::Eip4844(tx)),\n            ReceiptEnvelope::Eip7702(tx) => Ok(Self::Eip7702(tx)),\n            _ => Err(Eip2718Error::RlpError(alloy_rlp::Error::Custom(\"unexpected tx type\"))),\n        }\n    }\n\n    fn fallback_decode(buf: &mut &[u8]) -> Result<Self, Eip2718Error> {\n        match ReceiptEnvelope::fallback_decode(buf)? {\n            ReceiptEnvelope::Legacy(tx) => Ok(Self::Legacy(tx)),\n            _ => Err(Eip2718Error::RlpError(alloy_rlp::Error::Custom(\"unexpected tx type\"))),\n        }\n    }\n}\n\nimpl From<FoundryReceiptEnvelope<alloy_rpc_types::Log>> for OtsReceipt {\n    fn from(receipt: FoundryReceiptEnvelope<alloy_rpc_types::Log>) -> Self {\n        Self {\n            status: receipt.status(),\n            cumulative_gas_used: receipt.cumulative_gas_used(),\n            logs: Some(receipt.logs().to_vec()),\n            logs_bloom: Some(receipt.logs_bloom().to_owned()),\n            r#type: receipt.tx_type() as u8,\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use alloy_primitives::{Address, B256, Bytes, LogData, hex};\n    use std::str::FromStr;\n\n    #[test]\n    fn encode_legacy_receipt() {\n        let expected = hex::decode(\"f901668001b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f85ff85d940000000000000000000000000000000000000011f842a0000000000000000000000000000000000000000000000000000000000000deada0000000000000000000000000000000000000000000000000000000000000beef830100ff\").unwrap();\n\n        let mut data = vec![];\n        let receipt = FoundryReceiptEnvelope::Legacy(ReceiptWithBloom {\n            receipt: Receipt {\n                status: false.into(),\n                cumulative_gas_used: 0x1,\n                logs: vec![Log {\n                    address: Address::from_str(\"0000000000000000000000000000000000000011\").unwrap(),\n                    data: LogData::new_unchecked(\n                        vec![\n                            B256::from_str(\n                                \"000000000000000000000000000000000000000000000000000000000000dead\",\n                            )\n                            .unwrap(),\n                            B256::from_str(\n                                \"000000000000000000000000000000000000000000000000000000000000beef\",\n                            )\n                            .unwrap(),\n                        ],\n                        Bytes::from_str(\"0100ff\").unwrap(),\n                    ),\n                }],\n            },\n            logs_bloom: [0; 256].into(),\n        });\n\n        receipt.encode(&mut data);\n\n        // check that the rlp length equals the length of the expected rlp\n        assert_eq!(receipt.length(), expected.len());\n        assert_eq!(data, expected);\n    }\n\n    #[test]\n    fn decode_legacy_receipt() {\n        let data = hex::decode(\"f901668001b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f85ff85d940000000000000000000000000000000000000011f842a0000000000000000000000000000000000000000000000000000000000000deada0000000000000000000000000000000000000000000000000000000000000beef830100ff\").unwrap();\n\n        let expected = FoundryReceiptEnvelope::Legacy(ReceiptWithBloom {\n            receipt: Receipt {\n                status: false.into(),\n                cumulative_gas_used: 0x1,\n                logs: vec![Log {\n                    address: Address::from_str(\"0000000000000000000000000000000000000011\").unwrap(),\n                    data: LogData::new_unchecked(\n                        vec![\n                            B256::from_str(\n                                \"000000000000000000000000000000000000000000000000000000000000dead\",\n                            )\n                            .unwrap(),\n                            B256::from_str(\n                                \"000000000000000000000000000000000000000000000000000000000000beef\",\n                            )\n                            .unwrap(),\n                        ],\n                        Bytes::from_str(\"0100ff\").unwrap(),\n                    ),\n                }],\n            },\n            logs_bloom: [0; 256].into(),\n        });\n\n        let receipt = FoundryReceiptEnvelope::decode(&mut &data[..]).unwrap();\n\n        assert_eq!(receipt, expected);\n    }\n\n    #[test]\n    fn encode_tempo_receipt() {\n        use alloy_network::eip2718::Encodable2718;\n        use tempo_primitives::TEMPO_TX_TYPE_ID;\n\n        let receipt = FoundryReceiptEnvelope::Tempo(ReceiptWithBloom {\n            receipt: Receipt {\n                status: true.into(),\n                cumulative_gas_used: 157716,\n                logs: vec![Log {\n                    address: Address::from_str(\"20c0000000000000000000000000000000000000\").unwrap(),\n                    data: LogData::new_unchecked(\n                        vec![\n                            B256::from_str(\n                                \"8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925\",\n                            )\n                            .unwrap(),\n                            B256::from_str(\n                                \"000000000000000000000000566ff0f4a6114f8072ecdc8a7a8a13d8d0c6b45f\",\n                            )\n                            .unwrap(),\n                            B256::from_str(\n                                \"000000000000000000000000dec0000000000000000000000000000000000000\",\n                            )\n                            .unwrap(),\n                        ],\n                        Bytes::from_str(\n                            \"0000000000000000000000000000000000000000000000000000000000989680\",\n                        )\n                        .unwrap(),\n                    ),\n                }],\n            },\n            logs_bloom: [0; 256].into(),\n        });\n\n        assert_eq!(receipt.tx_type(), FoundryTxType::Tempo);\n        assert_eq!(receipt.ty(), TEMPO_TX_TYPE_ID);\n        assert!(receipt.status());\n        assert_eq!(receipt.cumulative_gas_used(), 157716);\n        assert_eq!(receipt.logs().len(), 1);\n\n        // Encode and decode round-trip\n        let mut encoded = Vec::new();\n        receipt.encode_2718(&mut encoded);\n\n        // First byte should be the Tempo type ID\n        assert_eq!(encoded[0], TEMPO_TX_TYPE_ID);\n\n        // Decode it back\n        let decoded = FoundryReceiptEnvelope::decode(&mut &encoded[..]).unwrap();\n        assert_eq!(receipt, decoded);\n    }\n\n    #[test]\n    fn decode_tempo_receipt() {\n        use alloy_network::eip2718::Encodable2718;\n        use tempo_primitives::TEMPO_TX_TYPE_ID;\n\n        let receipt = FoundryReceiptEnvelope::Tempo(ReceiptWithBloom {\n            receipt: Receipt { status: true.into(), cumulative_gas_used: 21000, logs: vec![] },\n            logs_bloom: [0; 256].into(),\n        });\n\n        // Encode and decode via 2718\n        let mut encoded = Vec::new();\n        receipt.encode_2718(&mut encoded);\n        assert_eq!(encoded[0], TEMPO_TX_TYPE_ID);\n\n        use alloy_network::eip2718::Decodable2718;\n        let decoded = FoundryReceiptEnvelope::decode_2718(&mut &encoded[..]).unwrap();\n        assert_eq!(receipt, decoded);\n    }\n\n    #[test]\n    fn tempo_receipt_from_parts() {\n        let receipt = FoundryReceiptEnvelope::<alloy_rpc_types::Log>::from_parts(\n            true,\n            100000,\n            vec![],\n            FoundryTxType::Tempo,\n            None,\n            None,\n        );\n\n        assert_eq!(receipt.tx_type(), FoundryTxType::Tempo);\n        assert!(receipt.status());\n        assert_eq!(receipt.cumulative_gas_used(), 100000);\n        assert!(receipt.logs().is_empty());\n        assert!(receipt.deposit_nonce().is_none());\n        assert!(receipt.deposit_receipt_version().is_none());\n    }\n\n    #[test]\n    fn tempo_receipt_map_logs() {\n        let receipt = FoundryReceiptEnvelope::Tempo(ReceiptWithBloom {\n            receipt: Receipt {\n                status: true.into(),\n                cumulative_gas_used: 21000,\n                logs: vec![Log {\n                    address: Address::from_str(\"20c0000000000000000000000000000000000000\").unwrap(),\n                    data: LogData::new_unchecked(vec![], Bytes::default()),\n                }],\n            },\n            logs_bloom: [0; 256].into(),\n        });\n\n        // Map logs to a different type (just clone in this case)\n        let mapped = receipt.map_logs(|log| log);\n        assert_eq!(mapped.logs().len(), 1);\n        assert_eq!(mapped.tx_type(), FoundryTxType::Tempo);\n    }\n}\n"
  },
  {
    "path": "crates/primitives/src/transaction/request.rs",
    "content": "use alloy_consensus::{BlobTransactionSidecarVariant, EthereumTypedTransaction};\nuse alloy_network::{\n    BuildResult, NetworkWallet, TransactionBuilder, TransactionBuilder4844, TransactionBuilderError,\n};\nuse alloy_primitives::{Address, B256, ChainId, TxKind, U256};\nuse alloy_rpc_types::{AccessList, TransactionInputKind, TransactionRequest};\nuse alloy_serde::{OtherFields, WithOtherFields};\nuse op_alloy_consensus::{DEPOSIT_TX_TYPE_ID, TxDeposit};\nuse op_revm::transaction::deposit::DepositTransactionParts;\nuse serde::{Deserialize, Serialize};\nuse tempo_alloy::rpc::TempoTransactionRequest;\nuse tempo_primitives::{TEMPO_TX_TYPE_ID, TempoTxType};\n\nuse super::{FoundryTxEnvelope, FoundryTxType, FoundryTypedTx};\nuse crate::FoundryNetwork;\n\n/// Foundry transaction request builder.\n///\n/// This is a union of different transaction request types, instantiated from a\n/// [`WithOtherFields<TransactionRequest>`]. The specific variant is determined by the transaction\n/// type field and/or the presence of certain fields:\n/// - **Ethereum**: Default variant when no special fields are present\n/// - **Op**: When `sourceHash`, `mint`, and `isSystemTx` fields are present, or transaction type is\n///   `DEPOSIT_TX_TYPE_ID`\n/// - **Tempo**: When `feeToken` or `nonceKey` fields are present, or transaction type is\n///   `TEMPO_TX_TYPE_ID`\n#[derive(Clone, Debug, PartialEq, Eq)]\npub enum FoundryTransactionRequest {\n    Ethereum(TransactionRequest),\n    Op(WithOtherFields<TransactionRequest>),\n    Tempo(Box<TempoTransactionRequest>),\n}\n\nimpl FoundryTransactionRequest {\n    /// Create a new [`FoundryTransactionRequest`] from given\n    /// [`WithOtherFields<TransactionRequest>`].\n    #[inline]\n    pub fn new(inner: WithOtherFields<TransactionRequest>) -> Self {\n        inner.into()\n    }\n\n    /// Consume the [`FoundryTransactionRequest`] and return the inner transaction request.\n    pub fn into_inner(self) -> TransactionRequest {\n        match self {\n            Self::Ethereum(tx) => tx,\n            Self::Op(tx) => tx.inner,\n            Self::Tempo(tx) => tx.inner,\n        }\n    }\n\n    /// Get the deposit transaction parts from the request, calling [`get_deposit_tx_parts`] helper\n    /// with OtherFields.\n    ///\n    /// # Returns\n    /// - Ok(deposit_tx_parts) if all necessary keys are present to build a deposit transaction.\n    /// - Err(missing) if some keys are missing to build a deposit transaction.\n    pub fn get_deposit_tx_parts(&self) -> Result<DepositTransactionParts, Vec<&'static str>> {\n        match self {\n            Self::Op(tx) => get_deposit_tx_parts(&tx.other),\n            // Not a deposit transaction request, so missing at least sourceHash, mint, and\n            // isSystemTx\n            _ => Err(vec![\"sourceHash\", \"mint\", \"isSystemTx\"]),\n        }\n    }\n\n    /// Returns the minimal transaction type this request can be converted into based on the fields\n    /// that are set. See [`TransactionRequest::preferred_type`].\n    pub fn preferred_type(&self) -> FoundryTxType {\n        match self {\n            Self::Ethereum(tx) => tx.preferred_type().into(),\n            Self::Op(_) => FoundryTxType::Deposit,\n            Self::Tempo(_) => FoundryTxType::Tempo,\n        }\n    }\n\n    /// Check if all necessary keys are present to build a 4844 transaction,\n    /// returning a list of keys that are missing.\n    ///\n    /// **NOTE:** Inner [`TransactionRequest::complete_4844`] method but \"sidecar\" key is filtered\n    /// from error.\n    pub fn complete_4844(&self) -> Result<(), Vec<&'static str>> {\n        match self.as_ref().complete_4844() {\n            Ok(()) => Ok(()),\n            Err(missing) => {\n                let filtered: Vec<_> =\n                    missing.into_iter().filter(|&key| key != \"sidecar\").collect();\n                if filtered.is_empty() { Ok(()) } else { Err(filtered) }\n            }\n        }\n    }\n\n    /// Check if all necessary keys are present to build a Deposit transaction, returning a list of\n    /// keys that are missing.\n    pub fn complete_deposit(&self) -> Result<(), Vec<&'static str>> {\n        self.get_deposit_tx_parts().map(|_| ())\n    }\n\n    /// Check if all necessary keys are present to build a Tempo transaction, returning a list of\n    /// keys that are missing.\n    pub fn complete_tempo(&self) -> Result<(), Vec<&'static str>> {\n        match self {\n            Self::Tempo(tx) => tx.complete_type(TempoTxType::AA).map(|_| ()),\n            // Not a Tempo transaction request, so missing at least feeToken and nonceKey\n            _ => Err(vec![\"feeToken\", \"nonceKey\"]),\n        }\n    }\n\n    /// Check if all necessary keys are present to build a transaction.\n    ///\n    /// # Returns\n    ///\n    /// - Ok(type) if all necessary keys are present to build the preferred type.\n    /// - Err((type, missing)) if some keys are missing to build the preferred type.\n    pub fn missing_keys(&self) -> Result<FoundryTxType, (FoundryTxType, Vec<&'static str>)> {\n        let pref = self.preferred_type();\n        if let Err(missing) = match pref {\n            FoundryTxType::Legacy => self.as_ref().complete_legacy(),\n            FoundryTxType::Eip2930 => self.as_ref().complete_2930(),\n            FoundryTxType::Eip1559 => self.as_ref().complete_1559(),\n            FoundryTxType::Eip4844 => self.complete_4844(),\n            FoundryTxType::Eip7702 => self.as_ref().complete_7702(),\n            FoundryTxType::Deposit => self.complete_deposit(),\n            FoundryTxType::Tempo => self.complete_tempo(),\n        } {\n            Err((pref, missing))\n        } else {\n            Ok(pref)\n        }\n    }\n\n    /// Build a typed transaction from this request.\n    ///\n    /// Converts the request into a `FoundryTypedTx`, handling all Ethereum and OP-stack transaction\n    /// types.\n    pub fn build_typed_tx(self) -> Result<FoundryTypedTx, Self> {\n        if let Ok(deposit_tx_parts) = self.get_deposit_tx_parts() {\n            // Build deposit transaction\n            Ok(FoundryTypedTx::Deposit(TxDeposit {\n                from: self.from().unwrap_or_default(),\n                source_hash: deposit_tx_parts.source_hash,\n                to: self.kind().unwrap_or_default(),\n                mint: deposit_tx_parts.mint.unwrap_or_default(),\n                value: self.value().unwrap_or_default(),\n                gas_limit: self.gas_limit().unwrap_or_default(),\n                is_system_transaction: deposit_tx_parts.is_system_transaction,\n                input: self.input().cloned().unwrap_or_default(),\n            }))\n        } else if self.complete_tempo().is_ok()\n            && let Self::Tempo(tx_req) = self\n        {\n            // Build Tempo transaction\n            Ok(FoundryTypedTx::Tempo(\n                tx_req.build_aa().map_err(|e| Self::Tempo(Box::new(e.into_value())))?,\n            ))\n        } else if self.as_ref().has_eip4844_fields() && self.blob_sidecar().is_none() {\n            // if request has eip4844 fields but no blob sidecar (neither eip4844 nor eip7594\n            // format), try to build to eip4844 without sidecar\n            self.into_inner()\n                .build_4844_without_sidecar()\n                .map_err(|e| Self::Ethereum(e.into_value()))\n                .map(|tx| FoundryTypedTx::Eip4844(tx.into()))\n        } else {\n            // Use the inner transaction request to build EthereumTypedTransaction\n            let typed_tx = self.into_inner().build_typed_tx().map_err(Self::Ethereum)?;\n            // Convert EthereumTypedTransaction to FoundryTypedTx\n            Ok(match typed_tx {\n                EthereumTypedTransaction::Legacy(tx) => FoundryTypedTx::Legacy(tx),\n                EthereumTypedTransaction::Eip2930(tx) => FoundryTypedTx::Eip2930(tx),\n                EthereumTypedTransaction::Eip1559(tx) => FoundryTypedTx::Eip1559(tx),\n                EthereumTypedTransaction::Eip4844(tx) => FoundryTypedTx::Eip4844(tx),\n                EthereumTypedTransaction::Eip7702(tx) => FoundryTypedTx::Eip7702(tx),\n            })\n        }\n    }\n}\n\nimpl Default for FoundryTransactionRequest {\n    fn default() -> Self {\n        Self::Ethereum(TransactionRequest::default())\n    }\n}\n\nimpl Serialize for FoundryTransactionRequest {\n    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>\n    where\n        S: serde::Serializer,\n    {\n        match self {\n            Self::Ethereum(tx) => tx.serialize(serializer),\n            Self::Op(tx) => tx.serialize(serializer),\n            Self::Tempo(tx) => tx.serialize(serializer),\n        }\n    }\n}\n\nimpl<'de> Deserialize<'de> for FoundryTransactionRequest {\n    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>\n    where\n        D: serde::Deserializer<'de>,\n    {\n        WithOtherFields::<TransactionRequest>::deserialize(deserializer).map(Into::<Self>::into)\n    }\n}\n\nimpl AsRef<TransactionRequest> for FoundryTransactionRequest {\n    fn as_ref(&self) -> &TransactionRequest {\n        match self {\n            Self::Ethereum(tx) => tx,\n            Self::Op(tx) => tx,\n            Self::Tempo(tx) => tx,\n        }\n    }\n}\n\nimpl AsMut<TransactionRequest> for FoundryTransactionRequest {\n    fn as_mut(&mut self) -> &mut TransactionRequest {\n        match self {\n            Self::Ethereum(tx) => tx,\n            Self::Op(tx) => tx,\n            Self::Tempo(tx) => tx,\n        }\n    }\n}\n\nimpl From<WithOtherFields<TransactionRequest>> for FoundryTransactionRequest {\n    fn from(tx: WithOtherFields<TransactionRequest>) -> Self {\n        if tx.transaction_type == Some(TEMPO_TX_TYPE_ID)\n            || tx.other.contains_key(\"feeToken\")\n            || tx.other.contains_key(\"nonceKey\")\n        {\n            let mut tempo_tx_req: TempoTransactionRequest = tx.inner.into();\n            if let Some(fee_token) =\n                tx.other.get_deserialized::<Address>(\"feeToken\").transpose().ok().flatten()\n            {\n                tempo_tx_req.fee_token = Some(fee_token);\n            }\n            if let Some(nonce_key) =\n                tx.other.get_deserialized::<U256>(\"nonceKey\").transpose().ok().flatten()\n            {\n                tempo_tx_req.set_nonce_key(nonce_key);\n            }\n            Self::Tempo(Box::new(tempo_tx_req))\n        } else if tx.transaction_type == Some(DEPOSIT_TX_TYPE_ID)\n            || get_deposit_tx_parts(&tx.other).is_ok()\n        {\n            Self::Op(tx)\n        } else {\n            Self::Ethereum(tx.into_inner())\n        }\n    }\n}\n\nimpl From<FoundryTypedTx> for FoundryTransactionRequest {\n    fn from(tx: FoundryTypedTx) -> Self {\n        match tx {\n            FoundryTypedTx::Legacy(tx) => Self::Ethereum(Into::<TransactionRequest>::into(tx)),\n            FoundryTypedTx::Eip2930(tx) => Self::Ethereum(Into::<TransactionRequest>::into(tx)),\n            FoundryTypedTx::Eip1559(tx) => Self::Ethereum(Into::<TransactionRequest>::into(tx)),\n            FoundryTypedTx::Eip4844(tx) => Self::Ethereum(Into::<TransactionRequest>::into(tx)),\n            FoundryTypedTx::Eip7702(tx) => Self::Ethereum(Into::<TransactionRequest>::into(tx)),\n            FoundryTypedTx::Deposit(tx) => {\n                let other = OtherFields::from_iter([\n                    (\"sourceHash\", tx.source_hash.to_string().into()),\n                    (\"mint\", tx.mint.to_string().into()),\n                    (\"isSystemTx\", tx.is_system_transaction.to_string().into()),\n                ]);\n                WithOtherFields { inner: Into::<TransactionRequest>::into(tx), other }.into()\n            }\n            FoundryTypedTx::Tempo(tx) => {\n                let mut other = OtherFields::default();\n                if let Some(fee_token) = tx.fee_token {\n                    other.insert(\"feeToken\".to_string(), serde_json::to_value(fee_token).unwrap());\n                }\n                other.insert(\"nonceKey\".to_string(), serde_json::to_value(tx.nonce_key).unwrap());\n                let first_call = tx.calls.first();\n                let mut inner = TransactionRequest::default()\n                    .with_chain_id(tx.chain_id)\n                    .with_nonce(tx.nonce)\n                    .with_gas_limit(tx.gas_limit)\n                    .with_max_fee_per_gas(tx.max_fee_per_gas)\n                    .with_max_priority_fee_per_gas(tx.max_priority_fee_per_gas)\n                    .with_kind(first_call.map(|c| c.to).unwrap_or_default())\n                    .with_value(first_call.map(|c| c.value).unwrap_or_default())\n                    .with_input(first_call.map(|c| c.input.clone()).unwrap_or_default())\n                    .with_access_list(tx.access_list);\n                inner.transaction_type = Some(TEMPO_TX_TYPE_ID);\n                WithOtherFields { inner, other }.into()\n            }\n        }\n    }\n}\n\nimpl From<FoundryTxEnvelope> for FoundryTransactionRequest {\n    fn from(tx: FoundryTxEnvelope) -> Self {\n        FoundryTypedTx::from(tx).into()\n    }\n}\n\nimpl From<op_alloy_rpc_types::Transaction<FoundryTxEnvelope>> for FoundryTransactionRequest {\n    fn from(tx: op_alloy_rpc_types::Transaction<FoundryTxEnvelope>) -> Self {\n        tx.inner.into_inner().into()\n    }\n}\n\n// TransactionBuilder trait implementation for FoundryNetwork\nimpl TransactionBuilder<FoundryNetwork> for FoundryTransactionRequest {\n    fn chain_id(&self) -> Option<ChainId> {\n        self.as_ref().chain_id\n    }\n\n    fn set_chain_id(&mut self, chain_id: ChainId) {\n        self.as_mut().chain_id = Some(chain_id);\n    }\n\n    fn nonce(&self) -> Option<u64> {\n        self.as_ref().nonce\n    }\n\n    fn set_nonce(&mut self, nonce: u64) {\n        self.as_mut().nonce = Some(nonce);\n    }\n\n    fn take_nonce(&mut self) -> Option<u64> {\n        self.as_mut().nonce.take()\n    }\n\n    fn input(&self) -> Option<&alloy_primitives::Bytes> {\n        self.as_ref().input.input()\n    }\n\n    fn set_input<T: Into<alloy_primitives::Bytes>>(&mut self, input: T) {\n        self.as_mut().input.input = Some(input.into());\n    }\n\n    fn set_input_kind<T: Into<alloy_primitives::Bytes>>(\n        &mut self,\n        input: T,\n        kind: TransactionInputKind,\n    ) {\n        let inner = self.as_mut();\n        match kind {\n            TransactionInputKind::Input => inner.input.input = Some(input.into()),\n            TransactionInputKind::Data => inner.input.data = Some(input.into()),\n            TransactionInputKind::Both => {\n                let bytes = input.into();\n                inner.input.input = Some(bytes.clone());\n                inner.input.data = Some(bytes);\n            }\n        }\n    }\n\n    fn from(&self) -> Option<Address> {\n        self.as_ref().from\n    }\n\n    fn set_from(&mut self, from: Address) {\n        self.as_mut().from = Some(from);\n    }\n\n    fn kind(&self) -> Option<TxKind> {\n        self.as_ref().to\n    }\n\n    fn clear_kind(&mut self) {\n        self.as_mut().to = None;\n    }\n\n    fn set_kind(&mut self, kind: TxKind) {\n        self.as_mut().to = Some(kind);\n    }\n\n    fn value(&self) -> Option<U256> {\n        self.as_ref().value\n    }\n\n    fn set_value(&mut self, value: U256) {\n        self.as_mut().value = Some(value);\n    }\n\n    fn gas_price(&self) -> Option<u128> {\n        self.as_ref().gas_price\n    }\n\n    fn set_gas_price(&mut self, gas_price: u128) {\n        self.as_mut().gas_price = Some(gas_price);\n    }\n\n    fn max_fee_per_gas(&self) -> Option<u128> {\n        self.as_ref().max_fee_per_gas\n    }\n\n    fn set_max_fee_per_gas(&mut self, max_fee_per_gas: u128) {\n        self.as_mut().max_fee_per_gas = Some(max_fee_per_gas);\n    }\n\n    fn max_priority_fee_per_gas(&self) -> Option<u128> {\n        self.as_ref().max_priority_fee_per_gas\n    }\n\n    fn set_max_priority_fee_per_gas(&mut self, max_priority_fee_per_gas: u128) {\n        self.as_mut().max_priority_fee_per_gas = Some(max_priority_fee_per_gas);\n    }\n\n    fn gas_limit(&self) -> Option<u64> {\n        self.as_ref().gas\n    }\n\n    fn set_gas_limit(&mut self, gas_limit: u64) {\n        self.as_mut().gas = Some(gas_limit);\n    }\n\n    fn access_list(&self) -> Option<&AccessList> {\n        self.as_ref().access_list.as_ref()\n    }\n\n    fn set_access_list(&mut self, access_list: AccessList) {\n        self.as_mut().access_list = Some(access_list);\n    }\n\n    fn complete_type(&self, ty: FoundryTxType) -> Result<(), Vec<&'static str>> {\n        match ty {\n            FoundryTxType::Legacy => self.as_ref().complete_legacy(),\n            FoundryTxType::Eip2930 => self.as_ref().complete_2930(),\n            FoundryTxType::Eip1559 => self.as_ref().complete_1559(),\n            FoundryTxType::Eip4844 => self.as_ref().complete_4844(),\n            FoundryTxType::Eip7702 => self.as_ref().complete_7702(),\n            FoundryTxType::Deposit => self.complete_deposit(),\n            FoundryTxType::Tempo => self.complete_tempo(),\n        }\n    }\n\n    fn can_submit(&self) -> bool {\n        self.from().is_some()\n    }\n\n    fn can_build(&self) -> bool {\n        self.as_ref().can_build()\n            || self.complete_deposit().is_ok()\n            || self.complete_tempo().is_ok()\n    }\n\n    fn output_tx_type(&self) -> FoundryTxType {\n        self.preferred_type()\n    }\n\n    fn output_tx_type_checked(&self) -> Option<FoundryTxType> {\n        let pref = self.preferred_type();\n        match pref {\n            FoundryTxType::Legacy => self.as_ref().complete_legacy().ok(),\n            FoundryTxType::Eip2930 => self.as_ref().complete_2930().ok(),\n            FoundryTxType::Eip1559 => self.as_ref().complete_1559().ok(),\n            FoundryTxType::Eip4844 => self.as_ref().complete_4844().ok(),\n            FoundryTxType::Eip7702 => self.as_ref().complete_7702().ok(),\n            FoundryTxType::Deposit => self.complete_deposit().ok(),\n            FoundryTxType::Tempo => self.complete_tempo().ok(),\n        }?;\n        Some(pref)\n    }\n\n    /// Prepares [`FoundryTransactionRequest`] by trimming conflicting fields, and filling with\n    /// default values the mandatory fields.\n    fn prep_for_submission(&mut self) {\n        let preferred_type = self.preferred_type();\n        let inner = self.as_mut();\n        inner.transaction_type = Some(preferred_type as u8);\n        inner.gas.is_none().then(|| inner.set_gas_limit(Default::default()));\n        if !matches!(preferred_type, FoundryTxType::Deposit | FoundryTxType::Tempo) {\n            inner.trim_conflicting_keys();\n            inner.populate_blob_hashes();\n        }\n        if preferred_type != FoundryTxType::Deposit {\n            inner.nonce.is_none().then(|| inner.set_nonce(Default::default()));\n        }\n        if matches!(preferred_type, FoundryTxType::Legacy | FoundryTxType::Eip2930) {\n            inner.gas_price.is_none().then(|| inner.set_gas_price(Default::default()));\n        }\n        if preferred_type == FoundryTxType::Eip2930 {\n            inner.access_list.is_none().then(|| inner.set_access_list(Default::default()));\n        }\n        if matches!(\n            preferred_type,\n            FoundryTxType::Eip1559\n                | FoundryTxType::Eip4844\n                | FoundryTxType::Eip7702\n                | FoundryTxType::Tempo\n        ) {\n            inner\n                .max_priority_fee_per_gas\n                .is_none()\n                .then(|| inner.set_max_priority_fee_per_gas(Default::default()));\n            inner.max_fee_per_gas.is_none().then(|| inner.set_max_fee_per_gas(Default::default()));\n        }\n        if preferred_type == FoundryTxType::Eip4844 {\n            inner\n                .as_ref()\n                .max_fee_per_blob_gas()\n                .is_none()\n                .then(|| inner.as_mut().set_max_fee_per_blob_gas(Default::default()));\n        }\n    }\n\n    fn build_unsigned(self) -> BuildResult<FoundryTypedTx, FoundryNetwork> {\n        if let Err((tx_type, missing)) = self.missing_keys() {\n            return Err(TransactionBuilderError::InvalidTransactionRequest(tx_type, missing)\n                .into_unbuilt(self));\n        }\n        Ok(self.build_typed_tx().expect(\"checked by missing_keys\"))\n    }\n\n    async fn build<W: NetworkWallet<FoundryNetwork>>(\n        self,\n        wallet: &W,\n    ) -> Result<FoundryTxEnvelope, TransactionBuilderError<FoundryNetwork>> {\n        Ok(wallet.sign_request(self).await?)\n    }\n}\n\nimpl TransactionBuilder4844 for FoundryTransactionRequest {\n    fn max_fee_per_blob_gas(&self) -> Option<u128> {\n        self.as_ref().max_fee_per_blob_gas()\n    }\n\n    fn set_max_fee_per_blob_gas(&mut self, max_fee_per_blob_gas: u128) {\n        self.as_mut().set_max_fee_per_blob_gas(max_fee_per_blob_gas);\n    }\n\n    fn blob_sidecar(&self) -> Option<&BlobTransactionSidecarVariant> {\n        self.as_ref().blob_sidecar()\n    }\n\n    fn set_blob_sidecar(&mut self, sidecar: BlobTransactionSidecarVariant) {\n        self.as_mut().set_blob_sidecar(sidecar);\n    }\n}\n\n/// Converts `OtherFields` to `DepositTransactionParts`, produces error with missing fields\npub fn get_deposit_tx_parts(\n    other: &OtherFields,\n) -> Result<DepositTransactionParts, Vec<&'static str>> {\n    let mut missing = Vec::new();\n    let source_hash =\n        other.get_deserialized::<B256>(\"sourceHash\").transpose().ok().flatten().unwrap_or_else(\n            || {\n                missing.push(\"sourceHash\");\n                Default::default()\n            },\n        );\n    let mint = other\n        .get_deserialized::<U256>(\"mint\")\n        .transpose()\n        .unwrap_or_else(|_| {\n            missing.push(\"mint\");\n            Default::default()\n        })\n        .map(|value| value.to::<u128>());\n    let is_system_transaction =\n        other.get_deserialized::<bool>(\"isSystemTx\").transpose().ok().flatten().unwrap_or_else(\n            || {\n                missing.push(\"isSystemTx\");\n                Default::default()\n            },\n        );\n    if missing.is_empty() {\n        Ok(DepositTransactionParts { source_hash, mint, is_system_transaction })\n    } else {\n        Err(missing)\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    fn default_tx_req() -> TransactionRequest {\n        TransactionRequest::default()\n            .with_to(Address::random())\n            .with_nonce(1)\n            .with_value(U256::from(1000000))\n            .with_gas_limit(1000000)\n            .with_max_fee_per_gas(1000000)\n            .with_max_priority_fee_per_gas(1000000)\n    }\n\n    #[test]\n    fn test_routing_ethereum_default() {\n        let tx = default_tx_req();\n        let req: FoundryTransactionRequest = WithOtherFields::new(tx).into();\n\n        assert!(matches!(req, FoundryTransactionRequest::Ethereum(_)));\n        assert!(matches!(req.build_unsigned(), Ok(FoundryTypedTx::Eip1559(_))));\n    }\n\n    #[test]\n    fn test_routing_tempo_by_fee_token() {\n        let tx = default_tx_req();\n        let mut other = OtherFields::default();\n        other.insert(\"feeToken\".to_string(), serde_json::to_value(Address::random()).unwrap());\n\n        let req: FoundryTransactionRequest = WithOtherFields { inner: tx, other }.into();\n\n        assert!(matches!(req, FoundryTransactionRequest::Tempo(_)));\n        assert!(matches!(req.build_unsigned(), Ok(FoundryTypedTx::Tempo(_))));\n    }\n\n    #[test]\n    fn test_routing_op_by_deposit_fields() {\n        let tx = default_tx_req();\n        let mut other = OtherFields::default();\n        other.insert(\"sourceHash\".to_string(), serde_json::to_value(B256::ZERO).unwrap());\n        other.insert(\"mint\".to_string(), serde_json::to_value(U256::from(1000)).unwrap());\n        other.insert(\"isSystemTx\".to_string(), serde_json::to_value(false).unwrap());\n\n        let req: FoundryTransactionRequest = WithOtherFields { inner: tx, other }.into();\n\n        assert!(matches!(req, FoundryTransactionRequest::Op(_)));\n        assert!(matches!(req.build_unsigned(), Ok(FoundryTypedTx::Deposit(_))));\n    }\n\n    #[test]\n    fn test_op_incomplete_routes_to_ethereum() {\n        let tx = default_tx_req();\n        let mut other = OtherFields::default();\n        // Only provide 2 of 3 required Op fields\n        other.insert(\"sourceHash\".to_string(), serde_json::to_value(B256::ZERO).unwrap());\n        other.insert(\"mint\".to_string(), serde_json::to_value(U256::from(1000)).unwrap());\n\n        let req: FoundryTransactionRequest = WithOtherFields { inner: tx, other }.into();\n\n        assert!(matches!(req, FoundryTransactionRequest::Ethereum(_)));\n        assert!(matches!(req.build_unsigned(), Ok(FoundryTypedTx::Eip1559(_))));\n    }\n\n    #[test]\n    fn test_ethereum_with_unrelated_other_fields() {\n        let tx = default_tx_req();\n        let mut other = OtherFields::default();\n        other.insert(\"anotherField\".to_string(), serde_json::to_value(123).unwrap());\n\n        let req: FoundryTransactionRequest = WithOtherFields { inner: tx, other }.into();\n\n        assert!(matches!(req, FoundryTransactionRequest::Ethereum(_)));\n        assert!(matches!(req.build_unsigned(), Ok(FoundryTypedTx::Eip1559(_))));\n    }\n\n    #[test]\n    fn test_serialization_ethereum() {\n        let tx = default_tx_req();\n        let original: FoundryTransactionRequest = WithOtherFields::new(tx).into();\n\n        let serialized = serde_json::to_string(&original).unwrap();\n        let deserialized: FoundryTransactionRequest = serde_json::from_str(&serialized).unwrap();\n\n        assert!(matches!(deserialized, FoundryTransactionRequest::Ethereum(_)));\n    }\n\n    #[test]\n    fn test_serialization_op() {\n        let tx = default_tx_req();\n        let mut other = OtherFields::default();\n        other.insert(\"sourceHash\".to_string(), serde_json::to_value(B256::ZERO).unwrap());\n        other.insert(\"mint\".to_string(), serde_json::to_value(U256::from(1000)).unwrap());\n        other.insert(\"isSystemTx\".to_string(), serde_json::to_value(false).unwrap());\n\n        let original: FoundryTransactionRequest = WithOtherFields { inner: tx, other }.into();\n\n        let serialized = serde_json::to_string(&original).unwrap();\n        let deserialized: FoundryTransactionRequest = serde_json::from_str(&serialized).unwrap();\n\n        assert!(matches!(deserialized, FoundryTransactionRequest::Op(_)));\n    }\n\n    #[test]\n    fn test_serialization_tempo() {\n        let tx = default_tx_req();\n        let mut other = OtherFields::default();\n        other.insert(\"feeToken\".to_string(), serde_json::to_value(Address::ZERO).unwrap());\n        other.insert(\"nonceKey\".to_string(), serde_json::to_value(U256::from(42)).unwrap());\n\n        let original: FoundryTransactionRequest = WithOtherFields { inner: tx, other }.into();\n\n        let serialized = serde_json::to_string(&original).unwrap();\n        let deserialized: FoundryTransactionRequest = serde_json::from_str(&serialized).unwrap();\n\n        assert!(matches!(deserialized, FoundryTransactionRequest::Tempo(_)));\n    }\n}\n"
  },
  {
    "path": "crates/script/Cargo.toml",
    "content": "[package]\nname = \"forge-script\"\ndescription = \"Solidity scripting\"\n\nversion.workspace = true\nedition.workspace = true\nrust-version.workspace = true\nauthors.workspace = true\nlicense.workspace = true\nhomepage.workspace = true\nrepository.workspace = true\n\n[lints]\nworkspace = true\n\n[dependencies]\nforge-verify.workspace = true\nfoundry-cli.workspace = true\nfoundry-config.workspace = true\nfoundry-common.workspace = true\nfoundry-evm.workspace = true\nfoundry-debugger.workspace = true\nfoundry-cheatcodes.workspace = true\nfoundry-wallets.workspace = true\nfoundry-linking.workspace = true\nfoundry-primitives.workspace = true\nforge-script-sequence.workspace = true\n\nserde.workspace = true\neyre.workspace = true\nserde_json.workspace = true\ndunce.workspace = true\nfoundry-compilers.workspace = true\ntracing.workspace = true\nclap = { version = \"4\", features = [\"derive\", \"env\", \"unicode\", \"wrap_help\"] }\nsemver.workspace = true\nfutures.workspace = true\ntokio.workspace = true\n\nitertools.workspace = true\nparking_lot.workspace = true\nyansi.workspace = true\nrevm-inspectors.workspace = true\nalloy-rpc-types.workspace = true\nalloy-json-abi.workspace = true\ndialoguer.workspace = true\nindicatif.workspace = true\n\nalloy-signer.workspace = true\nalloy-network.workspace = true\nalloy-provider.workspace = true\nalloy-chains.workspace = true\nalloy-dyn-abi.workspace = true\nalloy-primitives.workspace = true\nalloy-eips.workspace = true\nalloy-consensus.workspace = true\nthiserror.workspace = true\n\n[dev-dependencies]\ntempfile.workspace = true\n"
  },
  {
    "path": "crates/script/src/broadcast.rs",
    "content": "use std::{cmp::Ordering, sync::Arc, time::Duration};\n\nuse alloy_chains::{Chain, NamedChain};\nuse alloy_consensus::{SignableTransaction, Signed};\nuse alloy_eips::{BlockId, eip2718::Encodable2718};\nuse alloy_network::{EthereumWallet, Network, ReceiptResponse, TransactionBuilder};\nuse alloy_primitives::{\n    Address, TxHash,\n    map::{AddressHashMap, AddressHashSet},\n    utils::format_units,\n};\nuse alloy_provider::{Provider, RootProvider, utils::Eip1559Estimation};\nuse alloy_signer::Signature;\nuse eyre::{Context, Result, bail};\nuse forge_verify::provider::VerificationProviderType;\nuse foundry_cheatcodes::Wallets;\nuse foundry_cli::utils::{has_batch_support, has_different_gas_calc};\nuse foundry_common::{\n    TransactionMaybeSigned,\n    provider::{ProviderBuilder, try_get_http_provider},\n    shell,\n};\nuse foundry_config::Config;\nuse foundry_primitives::FoundryTransactionBuilder;\nuse foundry_wallets::wallet_browser::signer::BrowserSigner;\nuse futures::{FutureExt, StreamExt, future::join_all, stream::FuturesUnordered};\nuse itertools::Itertools;\nuse serde::{Deserialize, Serialize};\n\nuse crate::{\n    ScriptArgs, ScriptConfig, build::LinkedBuildData, progress::ScriptProgress,\n    sequence::ScriptSequenceKind, verify::BroadcastedState,\n};\n\npub async fn estimate_gas<N: Network, P: Provider<N>>(\n    tx: &mut N::TransactionRequest,\n    provider: &P,\n    estimate_multiplier: u64,\n) -> Result<()>\nwhere\n    N::TransactionRequest: FoundryTransactionBuilder<N>,\n{\n    // if already set, some RPC endpoints might simply return the gas value that is already\n    // set in the request and omit the estimate altogether, so we remove it here\n    tx.reset_gas_limit();\n\n    tx.set_gas_limit(\n        provider.estimate_gas(tx.clone()).await.wrap_err(\"Failed to estimate gas for tx\")?\n            * estimate_multiplier\n            / 100,\n    );\n    Ok(())\n}\n\npub async fn next_nonce(\n    caller: Address,\n    provider_url: &str,\n    block_number: Option<u64>,\n) -> eyre::Result<u64> {\n    let provider = try_get_http_provider(provider_url)\n        .wrap_err_with(|| format!(\"bad fork_url provider: {provider_url}\"))?;\n\n    let block_id = block_number.map_or(BlockId::latest(), BlockId::number);\n    Ok(provider.get_transaction_count(caller).block_id(block_id).await?)\n}\n\n/// Represents how to send a single transaction.\n#[derive(Clone)]\npub enum SendTransactionKind<'a, N: Network> {\n    Unlocked(N::TransactionRequest),\n    Raw(N::TransactionRequest, &'a EthereumWallet),\n    Browser(N::TransactionRequest, &'a BrowserSigner<N>),\n    Signed(N::TxEnvelope),\n}\n\nimpl<'a, N: Network> SendTransactionKind<'a, N>\nwhere\n    N::TxEnvelope: From<Signed<N::UnsignedTx>>,\n    N::UnsignedTx: SignableTransaction<Signature>,\n    N::TransactionRequest: FoundryTransactionBuilder<N>,\n{\n    /// Prepares the transaction for broadcasting by synchronizing nonce and estimating gas.\n    ///\n    /// This method performs two key operations:\n    /// 1. Nonce synchronization: Waits for the provider's nonce to catch up to the expected\n    ///    transaction nonce when doing sequential broadcast\n    /// 2. Gas estimation: Re-estimates gas right before broadcasting for chains that require it\n    pub async fn prepare(\n        &mut self,\n        provider: &RootProvider<N>,\n        sequential_broadcast: bool,\n        is_fixed_gas_limit: bool,\n        estimate_via_rpc: bool,\n        estimate_multiplier: u64,\n    ) -> Result<()> {\n        if let Self::Raw(tx, _) | Self::Unlocked(tx) | Self::Browser(tx, _) = self {\n            if sequential_broadcast {\n                let from = tx.from().expect(\"no sender\");\n\n                let tx_nonce = tx.nonce().expect(\"no nonce\");\n                for attempt in 0..5 {\n                    let nonce = provider.get_transaction_count(from).await?;\n                    match nonce.cmp(&tx_nonce) {\n                        Ordering::Greater => {\n                            bail!(\n                                \"EOA nonce changed unexpectedly while sending transactions. Expected {tx_nonce} got {nonce} from provider.\"\n                            )\n                        }\n                        Ordering::Less => {\n                            if attempt == 4 {\n                                bail!(\n                                    \"After 5 attempts, provider nonce ({nonce}) is still behind expected nonce ({tx_nonce}).\"\n                                )\n                            }\n                            warn!(\n                                \"Expected nonce ({tx_nonce}) is ahead of provider nonce ({nonce}). Retrying in 1 second...\"\n                            );\n                            tokio::time::sleep(std::time::Duration::from_millis(1000)).await;\n                        }\n                        Ordering::Equal => {\n                            // Nonces are equal, we can proceed.\n                            break;\n                        }\n                    }\n                }\n            }\n\n            // Chains which use `eth_estimateGas` are being sent sequentially and require their\n            // gas to be re-estimated right before broadcasting.\n            if !is_fixed_gas_limit && estimate_via_rpc {\n                estimate_gas(tx, provider, estimate_multiplier).await?;\n            }\n        }\n\n        Ok(())\n    }\n\n    /// Sends the transaction to the network.\n    ///\n    /// Depending on the transaction kind, this will either:\n    /// - Submit via `eth_sendTransaction` for unlocked accounts\n    /// - Sign and submit via `eth_sendRawTransaction` for raw transactions\n    /// - Submit pre-signed transaction via `eth_sendRawTransaction`\n    pub async fn send(self, provider: Arc<RootProvider<N>>) -> Result<TxHash> {\n        match self {\n            Self::Unlocked(tx) => {\n                debug!(\"sending transaction from unlocked account {:?}\", tx);\n\n                // Submit the transaction\n                let pending = provider.send_transaction(tx).await?;\n                Ok(*pending.tx_hash())\n            }\n            Self::Raw(tx, signer) => {\n                debug!(\"sending transaction: {:?}\", tx);\n                let signed = tx.build(signer).await?;\n\n                // Submit the raw transaction\n                let pending = provider.send_raw_transaction(signed.encoded_2718().as_ref()).await?;\n                Ok(*pending.tx_hash())\n            }\n            Self::Signed(tx) => {\n                debug!(\"sending transaction: {:?}\", tx);\n                let pending = provider.send_raw_transaction(tx.encoded_2718().as_ref()).await?;\n                Ok(*pending.tx_hash())\n            }\n            Self::Browser(tx, signer) => {\n                debug!(\"sending transaction: {:?}\", tx);\n\n                // Sign and send the transaction via the browser wallet\n                Ok(signer.send_transaction_via_browser(tx).await?)\n            }\n        }\n    }\n\n    /// Prepares and sends the transaction in one operation.\n    ///\n    /// This is a convenience method that combines [`prepare`](Self::prepare) and\n    /// [`send`](Self::send) into a single call.\n    pub async fn prepare_and_send(\n        mut self,\n        provider: Arc<RootProvider<N>>,\n        sequential_broadcast: bool,\n        is_fixed_gas_limit: bool,\n        estimate_via_rpc: bool,\n        estimate_multiplier: u64,\n    ) -> Result<TxHash> {\n        self.prepare(\n            &provider,\n            sequential_broadcast,\n            is_fixed_gas_limit,\n            estimate_via_rpc,\n            estimate_multiplier,\n        )\n        .await?;\n\n        self.send(provider).await\n    }\n}\n\n/// Represents how to send _all_ transactions\npub enum SendTransactionsKind<N: Network> {\n    /// Send via `eth_sendTransaction` and rely on the  `from` address being unlocked.\n    Unlocked(AddressHashSet),\n    /// Send a signed transaction via `eth_sendRawTransaction`, or via browser\n    Raw { eth_wallets: AddressHashMap<EthereumWallet>, browser: Option<BrowserSigner<N>> },\n}\n\nimpl<N: Network> SendTransactionsKind<N> {\n    /// Returns the [`SendTransactionKind`] for the given address\n    ///\n    /// Returns an error if no matching signer is found or the address is not unlocked\n    pub fn for_sender(\n        &self,\n        addr: &Address,\n        tx: N::TransactionRequest,\n    ) -> Result<SendTransactionKind<'_, N>> {\n        match self {\n            Self::Unlocked(unlocked) => {\n                if !unlocked.contains(addr) {\n                    bail!(\"Sender address {:?} is not unlocked\", addr)\n                }\n                Ok(SendTransactionKind::Unlocked(tx))\n            }\n            Self::Raw { eth_wallets, browser } => {\n                if let Some(wallet) = eth_wallets.get(addr) {\n                    Ok(SendTransactionKind::Raw(tx, wallet))\n                } else if let Some(b) = browser\n                    && b.address() == *addr\n                {\n                    Ok(SendTransactionKind::Browser(tx, b))\n                } else {\n                    bail!(\"No matching signer for {:?} found\", addr)\n                }\n            }\n        }\n    }\n}\n\n/// State after we have bundled all\n/// [`TransactionWithMetadata`](forge_script_sequence::TransactionWithMetadata) objects into a\n/// single [`ScriptSequenceKind`] object containing one or more script sequences.\npub struct BundledState<N: Network>\nwhere\n    N::TxEnvelope: for<'d> Deserialize<'d> + Serialize,\n    N::TransactionRequest: for<'d> Deserialize<'d> + Serialize,\n{\n    pub args: ScriptArgs,\n    pub script_config: ScriptConfig,\n    pub script_wallets: Wallets,\n    pub browser_wallet: Option<BrowserSigner<N>>,\n    pub build_data: LinkedBuildData,\n    pub sequence: ScriptSequenceKind<N>,\n}\n\nimpl<N: Network> BundledState<N>\nwhere\n    N::TxEnvelope: for<'d> Deserialize<'d> + Serialize,\n    N::TransactionRequest: for<'d> Deserialize<'d> + Serialize,\n{\n    pub async fn wait_for_pending(mut self) -> Result<Self> {\n        let progress = ScriptProgress::default();\n        let progress_ref = &progress;\n        let futs = self\n            .sequence\n            .sequences_mut()\n            .iter_mut()\n            .enumerate()\n            .map(|(sequence_idx, sequence)| async move {\n                let rpc_url = sequence.rpc_url();\n                let provider = Arc::new(ProviderBuilder::new(rpc_url).build()?);\n                progress_ref\n                    .wait_for_pending(\n                        sequence_idx,\n                        sequence,\n                        &provider,\n                        self.script_config.config.transaction_timeout,\n                    )\n                    .await\n            })\n            .collect::<Vec<_>>();\n\n        let errors = join_all(futs).await.into_iter().filter_map(Result::err).collect::<Vec<_>>();\n\n        self.sequence.save(true, false)?;\n\n        if !errors.is_empty() {\n            return Err(eyre::eyre!(\"{}\", errors.iter().format(\"\\n\")));\n        }\n\n        Ok(self)\n    }\n\n    /// Broadcasts transactions from all sequences.\n    pub async fn broadcast(mut self) -> Result<BroadcastedState<N>>\n    where\n        N::TxEnvelope: From<Signed<N::UnsignedTx>>,\n        N::UnsignedTx: SignableTransaction<Signature>,\n        N::TransactionRequest: FoundryTransactionBuilder<N>,\n    {\n        let required_addresses = self\n            .sequence\n            .sequences()\n            .iter()\n            .flat_map(|sequence| {\n                sequence\n                    .transactions()\n                    .filter(|tx| tx.is_unsigned())\n                    .map(|tx| tx.from().expect(\"missing from\"))\n            })\n            .collect::<AddressHashSet>();\n\n        if required_addresses.contains(&Config::DEFAULT_SENDER) {\n            eyre::bail!(\n                \"You seem to be using Foundry's default sender. Be sure to set your own --sender.\"\n            );\n        }\n\n        let send_kind = if self.args.unlocked {\n            SendTransactionsKind::Unlocked(required_addresses.clone())\n        } else {\n            let signers: Vec<Address> = self\n                .script_wallets\n                .signers()\n                .map_err(|e| eyre::eyre!(\"{e}\"))?\n                .into_iter()\n                .chain(self.browser_wallet.as_ref().map(|b| b.address()))\n                .collect();\n            let mut missing_addresses = Vec::new();\n\n            for addr in &required_addresses {\n                if !signers.contains(addr) {\n                    missing_addresses.push(addr);\n                }\n            }\n\n            if !missing_addresses.is_empty() {\n                eyre::bail!(\n                    \"No associated wallet for addresses: {:?}. Unlocked wallets: {:?}\",\n                    missing_addresses,\n                    signers\n                );\n            }\n\n            let signers = self.script_wallets.into_multi_wallet().into_signers()?;\n            let eth_wallets =\n                signers.into_iter().map(|(addr, signer)| (addr, signer.into())).collect();\n\n            SendTransactionsKind::Raw { eth_wallets, browser: self.browser_wallet }\n        };\n\n        let progress = ScriptProgress::default();\n\n        for i in 0..self.sequence.sequences().len() {\n            let mut sequence = self.sequence.sequences_mut().get_mut(i).unwrap();\n\n            let provider = Arc::new(ProviderBuilder::new(sequence.rpc_url()).build()?);\n            let already_broadcasted = sequence.receipts.len();\n\n            let seq_progress = progress.get_sequence_progress(i, sequence);\n\n            if already_broadcasted < sequence.transactions.len() {\n                let is_legacy = Chain::from(sequence.chain).is_legacy() || self.args.legacy;\n                // Make a one-time gas price estimation\n                let (gas_price, eip1559_fees) = match (\n                    is_legacy,\n                    self.args.with_gas_price,\n                    self.args.priority_gas_price,\n                ) {\n                    (true, Some(gas_price), _) => (Some(gas_price.to()), None),\n                    (true, None, _) => (Some(provider.get_gas_price().await?), None),\n                    (false, Some(max_fee_per_gas), Some(max_priority_fee_per_gas)) => (\n                        None,\n                        Some(Eip1559Estimation {\n                            max_fee_per_gas: max_fee_per_gas.to(),\n                            max_priority_fee_per_gas: max_priority_fee_per_gas.to(),\n                        }),\n                    ),\n                    (false, _, _) => {\n                        let mut fees = provider.estimate_eip1559_fees().await.wrap_err(\"Failed to estimate EIP1559 fees. This chain might not support EIP1559, try adding --legacy to your command.\")?;\n\n                        if let Some(gas_price) = self.args.with_gas_price {\n                            fees.max_fee_per_gas = gas_price.to();\n                        }\n\n                        if let Some(priority_gas_price) = self.args.priority_gas_price {\n                            fees.max_priority_fee_per_gas = priority_gas_price.to();\n                        }\n\n                        (None, Some(fees))\n                    }\n                };\n\n                // Iterate through transactions, matching the `from` field with the associated\n                // wallet. Then send the transaction. Panics if we find a unknown `from`\n                let transactions = sequence\n                    .transactions\n                    .iter()\n                    .skip(already_broadcasted)\n                    .map(|tx_with_metadata| {\n                        let is_fixed_gas_limit = tx_with_metadata.is_fixed_gas_limit;\n\n                        let kind = match tx_with_metadata.tx().clone() {\n                            TransactionMaybeSigned::Signed { tx, .. } => {\n                                SendTransactionKind::Signed(tx)\n                            }\n                            TransactionMaybeSigned::Unsigned(mut tx) => {\n                                let from = tx.from().expect(\"No sender for onchain transaction!\");\n\n                                tx.set_chain_id(sequence.chain);\n\n                                // Set TxKind::Create explicitly to satisfy `check_reqd_fields` in\n                                // alloy\n                                if tx.kind().is_none() {\n                                    tx.set_create();\n                                }\n\n                                if let Some(gas_price) = gas_price {\n                                    tx.set_gas_price(gas_price);\n                                } else {\n                                    let eip1559_fees = eip1559_fees.expect(\"was set above\");\n                                    tx.set_max_priority_fee_per_gas(\n                                        eip1559_fees.max_priority_fee_per_gas,\n                                    );\n                                    tx.set_max_fee_per_gas(eip1559_fees.max_fee_per_gas);\n                                }\n\n                                send_kind.for_sender(&from, tx)?\n                            }\n                        };\n\n                        Ok((kind, is_fixed_gas_limit))\n                    })\n                    .collect::<Result<Vec<_>>>()?;\n\n                let estimate_via_rpc =\n                    has_different_gas_calc(sequence.chain) || self.args.skip_simulation;\n\n                // We only wait for a transaction receipt before sending the next transaction, if\n                // there is more than one signer. There would be no way of assuring\n                // their order otherwise.\n                // Or if the chain does not support batched transactions (eg. Arbitrum).\n                // Or if we need to invoke eth_estimateGas before sending transactions.\n                let sequential_broadcast = estimate_via_rpc\n                    || self.args.slow\n                    || required_addresses.len() != 1\n                    || !has_batch_support(sequence.chain);\n\n                // We send transactions and wait for receipts in batches.\n                let batch_size = if sequential_broadcast { 1 } else { self.args.batch_size };\n                let mut index = already_broadcasted;\n\n                for (batch_number, batch) in transactions.chunks(batch_size).enumerate() {\n                    seq_progress.inner.write().set_status(&format!(\n                        \"Sending transactions [{} - {}]\",\n                        batch_number * batch_size,\n                        batch_number * batch_size + std::cmp::min(batch_size, batch.len()) - 1\n                    ));\n\n                    if !batch.is_empty() {\n                        let pending_transactions =\n                            batch.iter().map(|(kind, is_fixed_gas_limit)| {\n                                let provider = provider.clone();\n                                async move {\n                                    let res = kind\n                                        .clone()\n                                        .prepare_and_send(\n                                            provider,\n                                            sequential_broadcast,\n                                            *is_fixed_gas_limit,\n                                            estimate_via_rpc,\n                                            self.args.gas_estimate_multiplier,\n                                        )\n                                        .await;\n                                    (res, kind, 0, None)\n                                }\n                                .boxed()\n                            });\n\n                        let mut buffer = pending_transactions.collect::<FuturesUnordered<_>>();\n\n                        'send: while let Some((res, kind, attempt, original_res)) =\n                            buffer.next().await\n                        {\n                            if res.is_err() && attempt <= 3 {\n                                // Try to resubmit the transaction\n                                let provider = provider.clone();\n                                let progress = seq_progress.inner.clone();\n                                buffer.push(Box::pin(async move {\n                                    debug!(err=?res, ?attempt, \"retrying transaction \");\n                                    let attempt = attempt + 1;\n                                    progress.write().set_status(&format!(\n                                        \"retrying transaction {res:?} (attempt {attempt})\"\n                                    ));\n                                    tokio::time::sleep(Duration::from_millis(1000 * attempt)).await;\n                                    let r = kind.clone().send(provider).await;\n                                    (r, kind, attempt, original_res.or(Some(res)))\n                                }));\n\n                                continue 'send;\n                            }\n\n                            // Preserve the original error if any\n                            let tx_hash = res.wrap_err_with(|| {\n                                if let Some(original_res) = original_res {\n                                    format!(\n                                        \"Failed to send transaction after {attempt} attempts {original_res:?}\"\n                                    )\n                                } else {\n                                    \"Failed to send transaction\".to_string()\n                                }\n                            })?;\n                            sequence.add_pending(index, tx_hash);\n\n                            // Checkpoint save\n                            self.sequence.save(true, false)?;\n                            sequence = self.sequence.sequences_mut().get_mut(i).unwrap();\n\n                            seq_progress.inner.write().tx_sent(tx_hash);\n                            index += 1;\n                        }\n\n                        // Checkpoint save\n                        self.sequence.save(true, false)?;\n                        sequence = self.sequence.sequences_mut().get_mut(i).unwrap();\n\n                        progress\n                            .wait_for_pending(\n                                i,\n                                sequence,\n                                &provider,\n                                self.script_config.config.transaction_timeout,\n                            )\n                            .await?\n                    }\n                    // Checkpoint save\n                    self.sequence.save(true, false)?;\n                    sequence = self.sequence.sequences_mut().get_mut(i).unwrap();\n                }\n            }\n\n            let (total_gas, total_gas_price, total_paid) =\n                sequence.receipts.iter().fold((0, 0, 0), |acc, receipt| {\n                    let gas_used = receipt.gas_used();\n                    let gas_price = receipt.effective_gas_price() as u64;\n                    (acc.0 + gas_used, acc.1 + gas_price, acc.2 + gas_used * gas_price)\n                });\n            let paid = format_units(total_paid, 18).unwrap_or_else(|_| \"N/A\".to_string());\n            let avg_gas_price = total_gas_price\n                .checked_div(sequence.receipts.len() as u64)\n                .and_then(|avg| format_units(avg, 9).ok())\n                .unwrap_or_else(|| \"N/A\".to_string());\n\n            let token_symbol = NamedChain::try_from(sequence.chain)\n                .unwrap_or_default()\n                .native_currency_symbol()\n                .unwrap_or(\"ETH\");\n            seq_progress.inner.write().set_status(&format!(\n                \"Total Paid: {} {} ({} gas * avg {} gwei)\\n\",\n                paid.trim_end_matches('0'),\n                token_symbol,\n                total_gas,\n                avg_gas_price.trim_end_matches('0').trim_end_matches('.')\n            ));\n            seq_progress.inner.write().finish();\n        }\n\n        if !shell::is_json() {\n            sh_println!(\"\\n\\n==========================\")?;\n            sh_println!(\"\\nONCHAIN EXECUTION COMPLETE & SUCCESSFUL.\")?;\n        }\n\n        Ok(BroadcastedState {\n            args: self.args,\n            script_config: self.script_config,\n            build_data: self.build_data,\n            sequence: self.sequence,\n        })\n    }\n\n    pub fn verify_preflight_check(&self) -> Result<()> {\n        for sequence in self.sequence.sequences() {\n            if self.args.verifier.verifier == VerificationProviderType::Etherscan\n                && self\n                    .script_config\n                    .config\n                    .get_etherscan_api_key(Some(sequence.chain.into()))\n                    .is_none()\n            {\n                eyre::bail!(\"Missing etherscan key for chain {}\", sequence.chain);\n            }\n        }\n\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "crates/script/src/build.rs",
    "content": "use crate::{\n    ScriptArgs, ScriptConfig, broadcast::BundledState, execute::LinkedState,\n    multi_sequence::MultiChainSequence, sequence::ScriptSequenceKind,\n};\nuse alloy_network::{AnyNetwork, Ethereum};\nuse alloy_primitives::{B256, Bytes};\nuse alloy_provider::Provider;\nuse eyre::{OptionExt, Result};\nuse forge_script_sequence::ScriptSequence;\nuse foundry_cheatcodes::Wallets;\nuse foundry_common::{\n    ContractData, ContractsByArtifact, compile::ProjectCompiler, provider::ProviderBuilder,\n};\nuse foundry_compilers::{\n    ArtifactId, ProjectCompileOutput,\n    artifacts::{BytecodeObject, Libraries},\n    compilers::{Language, multi::MultiCompilerLanguage},\n    info::ContractInfo,\n    utils::source_files_iter,\n};\nuse foundry_evm::traces::debug::ContractSources;\nuse foundry_linking::Linker;\nuse foundry_wallets::wallet_browser::signer::BrowserSigner;\nuse std::{path::PathBuf, str::FromStr, sync::Arc};\n\n/// Container for the compiled contracts.\n#[derive(Debug)]\npub struct BuildData {\n    /// Root of the project.\n    pub project_root: PathBuf,\n    /// The compiler output.\n    pub output: ProjectCompileOutput,\n    /// ID of target contract artifact.\n    pub target: ArtifactId,\n}\n\nimpl BuildData {\n    pub fn get_linker(&self) -> Linker<'_> {\n        Linker::new(self.project_root.clone(), self.output.artifact_ids().collect())\n    }\n\n    /// Links contracts. Uses CREATE2 linking when possible, otherwise falls back to\n    /// default linking with sender nonce and address.\n    pub async fn link(self, script_config: &ScriptConfig) -> Result<LinkedBuildData> {\n        let create2_deployer = script_config.evm_opts.create2_deployer;\n        let can_use_create2 = if let Some(fork_url) = &script_config.evm_opts.fork_url {\n            let provider = ProviderBuilder::<AnyNetwork>::new(fork_url).build()?;\n            let deployer_code = provider.get_code_at(create2_deployer).await?;\n\n            !deployer_code.is_empty()\n        } else {\n            // If --fork-url is not provided, we are just simulating the script.\n            true\n        };\n\n        let known_libraries = script_config.config.libraries_with_remappings()?;\n\n        let maybe_create2_link_output = can_use_create2\n            .then(|| {\n                self.get_linker()\n                    .link_with_create2(\n                        known_libraries.clone(),\n                        create2_deployer,\n                        script_config.config.create2_library_salt,\n                        &self.target,\n                    )\n                    .ok()\n            })\n            .flatten();\n\n        let (libraries, predeploy_libs) = if let Some(output) = maybe_create2_link_output {\n            (\n                output.libraries,\n                ScriptPredeployLibraries::Create2(\n                    output.libs_to_deploy,\n                    script_config.config.create2_library_salt,\n                ),\n            )\n        } else {\n            let output = self.get_linker().link_with_nonce_or_address(\n                known_libraries,\n                script_config.evm_opts.sender,\n                script_config.sender_nonce,\n                [&self.target],\n            )?;\n\n            (output.libraries, ScriptPredeployLibraries::Default(output.libs_to_deploy))\n        };\n\n        LinkedBuildData::new(libraries, predeploy_libs, self)\n    }\n\n    /// Links the build data with the given libraries. Expects supplied libraries set being enough\n    /// to fully link target contract.\n    pub fn link_with_libraries(self, libraries: Libraries) -> Result<LinkedBuildData> {\n        LinkedBuildData::new(libraries, ScriptPredeployLibraries::Default(Vec::new()), self)\n    }\n}\n\n#[derive(Debug)]\npub enum ScriptPredeployLibraries {\n    Default(Vec<Bytes>),\n    Create2(Vec<Bytes>, B256),\n}\n\nimpl ScriptPredeployLibraries {\n    pub fn libraries_count(&self) -> usize {\n        match self {\n            Self::Default(libs) => libs.len(),\n            Self::Create2(libs, _) => libs.len(),\n        }\n    }\n}\n\n/// Container for the linked contracts and their dependencies\n#[derive(Debug)]\npub struct LinkedBuildData {\n    /// Original build data, might be used to relink this object with different libraries.\n    pub build_data: BuildData,\n    /// Known fully linked contracts.\n    pub known_contracts: ContractsByArtifact,\n    /// Libraries used to link the contracts.\n    pub libraries: Libraries,\n    /// Libraries that need to be deployed by sender before script execution.\n    pub predeploy_libraries: ScriptPredeployLibraries,\n    /// Source files of the contracts. Used by debugger.\n    pub sources: ContractSources,\n}\n\nimpl LinkedBuildData {\n    pub fn new(\n        libraries: Libraries,\n        predeploy_libraries: ScriptPredeployLibraries,\n        build_data: BuildData,\n    ) -> Result<Self> {\n        let sources = ContractSources::from_project_output(\n            &build_data.output,\n            &build_data.project_root,\n            Some(&libraries),\n        )?;\n\n        let known_contracts =\n            ContractsByArtifact::new(build_data.get_linker().get_linked_artifacts(&libraries)?);\n\n        Ok(Self { build_data, known_contracts, libraries, predeploy_libraries, sources })\n    }\n\n    /// Fetches target bytecode from linked contracts.\n    pub fn get_target_contract(&self) -> Result<&ContractData> {\n        self.known_contracts\n            .get(&self.build_data.target)\n            .ok_or_eyre(\"target not found in linked artifacts\")\n    }\n}\n\n/// First state basically containing only inputs of the user.\npub struct PreprocessedState {\n    pub args: ScriptArgs,\n    pub script_config: ScriptConfig,\n    pub script_wallets: Wallets,\n    pub browser_wallet: Option<BrowserSigner<Ethereum>>,\n}\n\nimpl PreprocessedState {\n    /// Parses user input and compiles the contracts depending on script target.\n    /// After compilation, finds exact [ArtifactId] of the target contract.\n    pub fn compile(self) -> Result<CompiledState> {\n        let Self { args, script_config, script_wallets, browser_wallet } = self;\n        let project = script_config.config.project()?;\n\n        let mut target_name = args.target_contract.clone();\n\n        // If we've received correct path, use it as target_path\n        // Otherwise, parse input as <path>:<name> and use the path from the contract info, if\n        // present.\n        let target_path = if let Ok(path) = dunce::canonicalize(&args.path) {\n            path\n        } else {\n            let contract = ContractInfo::from_str(&args.path)?;\n            target_name = Some(contract.name.clone());\n            if let Some(path) = contract.path {\n                dunce::canonicalize(path)?\n            } else {\n                project.find_contract_path(contract.name.as_str())?\n            }\n        };\n\n        #[expect(clippy::redundant_clone)]\n        let sources_to_compile = source_files_iter(\n            project.paths.sources.as_path(),\n            MultiCompilerLanguage::FILE_EXTENSIONS,\n        )\n        .chain([target_path.to_path_buf()]);\n\n        let output = ProjectCompiler::new().files(sources_to_compile).compile(&project)?;\n\n        let mut target_id: Option<ArtifactId> = None;\n\n        // Find target artifact id by name and path in compilation artifacts.\n        for (id, contract) in output.artifact_ids().filter(|(id, _)| id.source == target_path) {\n            if let Some(name) = &target_name {\n                if id.name != *name {\n                    continue;\n                }\n            } else if contract.abi.as_ref().is_none_or(|abi| abi.is_empty())\n                || contract.bytecode.as_ref().is_none_or(|b| match &b.object {\n                    BytecodeObject::Bytecode(b) => b.is_empty(),\n                    BytecodeObject::Unlinked(_) => false,\n                })\n            {\n                // Ignore contracts with empty abi or linked bytecode of length 0 which are\n                // interfaces/abstract contracts/libraries.\n                continue;\n            }\n\n            if let Some(target) = target_id {\n                // We might have multiple artifacts for the same contract but with different\n                // solc versions. Their names will have form of {name}.0.X.Y, so we are\n                // stripping versions off before comparing them.\n                let target_name = target.name.split('.').next().unwrap();\n                let id_name = id.name.split('.').next().unwrap();\n                if target_name != id_name {\n                    eyre::bail!(\n                        \"Multiple contracts in the target path. Please specify the contract name with `--tc ContractName`\"\n                    )\n                }\n            }\n            target_id = Some(id);\n        }\n\n        let target = target_id.ok_or_eyre(\"Could not find target contract\")?;\n\n        Ok(CompiledState {\n            args,\n            script_config,\n            script_wallets,\n            browser_wallet,\n            build_data: BuildData { output, target, project_root: project.root().to_path_buf() },\n        })\n    }\n}\n\n/// State after we have determined and compiled target contract to be executed.\npub struct CompiledState {\n    pub args: ScriptArgs,\n    pub script_config: ScriptConfig,\n    pub script_wallets: Wallets,\n    pub browser_wallet: Option<BrowserSigner<Ethereum>>,\n    pub build_data: BuildData,\n}\n\nimpl CompiledState {\n    /// Uses provided sender address to compute library addresses and link contracts with them.\n    pub async fn link(self) -> Result<LinkedState> {\n        let Self { args, script_config, script_wallets, browser_wallet, build_data } = self;\n\n        let build_data = build_data.link(&script_config).await?;\n\n        Ok(LinkedState { args, script_config, script_wallets, browser_wallet, build_data })\n    }\n\n    /// Tries loading the resumed state from the cache files, skipping simulation stage.\n    pub async fn resume(self) -> Result<BundledState<Ethereum>> {\n        let chain = if self.args.multi {\n            None\n        } else {\n            let fork_url = self.script_config.evm_opts.fork_url.clone().ok_or_eyre(\"Missing --fork-url field, if you were trying to broadcast a multi-chain sequence, please use --multi flag\")?;\n            let provider = Arc::new(ProviderBuilder::<AnyNetwork>::new(&fork_url).build()?);\n            Some(provider.get_chain_id().await?)\n        };\n\n        let sequence = match self.try_load_sequence(chain, false) {\n            Ok(sequence) => sequence,\n            Err(_) => {\n                // If the script was simulated, but there was no attempt to broadcast yet,\n                // try to read the script sequence from the `dry-run/` folder\n                let mut sequence = self.try_load_sequence(chain, true)?;\n\n                // If sequence was in /dry-run, Update its paths so it is not saved into /dry-run\n                // this time as we are about to broadcast it.\n                sequence.update_paths_to_broadcasted(\n                    &self.script_config.config,\n                    &self.args.sig,\n                    &self.build_data.target,\n                )?;\n\n                sequence.save(true, true)?;\n                sequence\n            }\n        };\n\n        let (args, build_data, script_wallets, browser_wallet, script_config) =\n            if !self.args.unlocked {\n                let mut froms = sequence.sequences().iter().flat_map(|s| {\n                    s.transactions\n                        .iter()\n                        .skip(s.receipts.len())\n                        .map(|t| t.transaction.from().expect(\"from is missing in script artifact\"))\n                });\n\n                let available_signers = self\n                    .script_wallets\n                    .signers()\n                    .map_err(|e| eyre::eyre!(\"Failed to get available signers: {}\", e))?;\n\n                if !froms.all(|from| available_signers.contains(&from)) {\n                    // IF we are missing required signers, execute script as we might need to\n                    // collect private keys from the execution.\n                    let executed = self.link().await?.prepare_execution().await?.execute().await?;\n                    (\n                        executed.args,\n                        executed.build_data.build_data,\n                        executed.script_wallets,\n                        executed.browser_wallet,\n                        executed.script_config,\n                    )\n                } else {\n                    (\n                        self.args,\n                        self.build_data,\n                        self.script_wallets,\n                        self.browser_wallet,\n                        self.script_config,\n                    )\n                }\n            } else {\n                (\n                    self.args,\n                    self.build_data,\n                    self.script_wallets,\n                    self.browser_wallet,\n                    self.script_config,\n                )\n            };\n\n        // Collect libraries from sequence and link contracts with them.\n        let libraries = match sequence {\n            ScriptSequenceKind::Single(ref seq) => Libraries::parse(&seq.libraries)?,\n            // Library linking is not supported for multi-chain sequences\n            ScriptSequenceKind::Multi(_) => Libraries::default(),\n        };\n\n        let linked_build_data = build_data.link_with_libraries(libraries)?;\n\n        Ok(BundledState {\n            args,\n            script_config,\n            script_wallets,\n            browser_wallet,\n            build_data: linked_build_data,\n            sequence,\n        })\n    }\n\n    fn try_load_sequence(\n        &self,\n        chain: Option<u64>,\n        dry_run: bool,\n    ) -> Result<ScriptSequenceKind<Ethereum>> {\n        if let Some(chain) = chain {\n            let sequence = ScriptSequence::load(\n                &self.script_config.config,\n                &self.args.sig,\n                &self.build_data.target,\n                chain,\n                dry_run,\n            )?;\n            Ok(ScriptSequenceKind::Single(sequence))\n        } else {\n            let sequence = MultiChainSequence::load(\n                &self.script_config.config,\n                &self.args.sig,\n                &self.build_data.target,\n                dry_run,\n            )?;\n            Ok(ScriptSequenceKind::Multi(sequence))\n        }\n    }\n}\n"
  },
  {
    "path": "crates/script/src/execute.rs",
    "content": "use super::{JsonResult, NestedValue, ScriptResult, runner::ScriptRunner};\nuse crate::{\n    ScriptArgs, ScriptConfig,\n    build::{CompiledState, LinkedBuildData},\n    simulate::PreSimulationState,\n};\nuse alloy_dyn_abi::FunctionExt;\nuse alloy_json_abi::{Function, InternalType, JsonAbi};\nuse alloy_network::{AnyNetwork, Ethereum};\nuse alloy_primitives::{\n    Address, Bytes,\n    map::{HashMap, HashSet},\n};\nuse alloy_provider::Provider;\nuse eyre::{OptionExt, Result};\nuse foundry_cheatcodes::Wallets;\nuse foundry_cli::utils::{ensure_clean_constructor, needs_setup};\nuse foundry_common::{\n    ContractsByArtifact,\n    fmt::{format_token, format_token_raw},\n    provider::ProviderBuilder,\n};\nuse foundry_config::NamedChain;\nuse foundry_debugger::Debugger;\nuse foundry_evm::{\n    decode::decode_console_logs,\n    inspectors::cheatcodes::BroadcastableTransactions,\n    traces::{\n        CallTraceDecoder, CallTraceDecoderBuilder, TraceKind, decode_trace_arena,\n        identifier::{SignaturesIdentifier, TraceIdentifiers},\n        render_trace_arena,\n    },\n};\nuse foundry_wallets::wallet_browser::signer::BrowserSigner;\nuse futures::future::join_all;\nuse itertools::Itertools;\nuse std::path::Path;\nuse yansi::Paint;\n\n/// State after linking, contains the linked build data along with library addresses and optional\n/// array of libraries that need to be predeployed.\npub struct LinkedState {\n    pub args: ScriptArgs,\n    pub script_config: ScriptConfig,\n    pub script_wallets: Wallets,\n    pub browser_wallet: Option<BrowserSigner<Ethereum>>,\n    pub build_data: LinkedBuildData,\n}\n\n/// Container for data we need for execution which can only be obtained after linking stage.\n#[derive(Debug)]\npub struct ExecutionData {\n    /// Function to call.\n    pub func: Function,\n    /// Calldata to pass to the target contract.\n    pub calldata: Bytes,\n    /// Bytecode of the target contract.\n    pub bytecode: Bytes,\n    /// ABI of the target contract.\n    pub abi: JsonAbi,\n}\n\nimpl LinkedState {\n    /// Given linked and compiled artifacts, prepares data we need for execution.\n    /// This includes the function to call and the calldata to pass to it.\n    pub async fn prepare_execution(self) -> Result<PreExecutionState> {\n        let Self { args, script_config, script_wallets, browser_wallet, build_data } = self;\n\n        let target_contract = build_data.get_target_contract()?;\n\n        let bytecode = target_contract.bytecode().ok_or_eyre(\"target contract has no bytecode\")?;\n\n        let (func, calldata) = args.get_method_and_calldata(&target_contract.abi)?;\n\n        ensure_clean_constructor(&target_contract.abi)?;\n\n        Ok(PreExecutionState {\n            args,\n            script_config,\n            script_wallets,\n            browser_wallet,\n            execution_data: ExecutionData {\n                func,\n                calldata,\n                bytecode: bytecode.clone(),\n                abi: target_contract.abi.clone(),\n            },\n            build_data,\n        })\n    }\n}\n\n/// Same as [LinkedState], but also contains [ExecutionData].\n#[derive(Debug)]\npub struct PreExecutionState {\n    pub args: ScriptArgs,\n    pub script_config: ScriptConfig,\n    pub script_wallets: Wallets,\n    pub browser_wallet: Option<BrowserSigner<Ethereum>>,\n    pub build_data: LinkedBuildData,\n    pub execution_data: ExecutionData,\n}\n\nimpl PreExecutionState {\n    /// Executes the script and returns the state after execution.\n    /// Might require executing script twice in cases when we determine sender from execution.\n    pub async fn execute(mut self) -> Result<ExecutedState> {\n        let mut runner = self\n            .script_config\n            .get_runner_with_cheatcodes(\n                self.build_data.known_contracts.clone(),\n                self.script_wallets.clone(),\n                self.args.debug,\n                self.build_data.build_data.target.clone(),\n            )\n            .await?;\n        let result = self.execute_with_runner(&mut runner).await?;\n\n        // If we have a new sender from execution, we need to use it to deploy libraries and relink\n        // contracts.\n        if let Some(new_sender) = self.maybe_new_sender(result.transactions.as_ref())? {\n            self.script_config.update_sender(new_sender).await?;\n\n            // Rollback to rerun linking with the new sender.\n            let state = CompiledState {\n                args: self.args,\n                script_config: self.script_config,\n                script_wallets: self.script_wallets,\n                browser_wallet: self.browser_wallet,\n                build_data: self.build_data.build_data,\n            };\n\n            return Box::pin(state.link().await?.prepare_execution().await?.execute()).await;\n        }\n\n        Ok(ExecutedState {\n            args: self.args,\n            script_config: self.script_config,\n            script_wallets: self.script_wallets,\n            browser_wallet: self.browser_wallet,\n            build_data: self.build_data,\n            execution_data: self.execution_data,\n            execution_result: result,\n        })\n    }\n\n    /// Executes the script using the provided runner and returns the [ScriptResult].\n    pub async fn execute_with_runner(&self, runner: &mut ScriptRunner) -> Result<ScriptResult> {\n        let (address, mut setup_result) = runner.setup(\n            &self.build_data.predeploy_libraries,\n            self.execution_data.bytecode.clone(),\n            needs_setup(&self.execution_data.abi),\n            &self.script_config,\n            self.args.broadcast,\n        )?;\n\n        if setup_result.success {\n            let script_result = runner.script(address, self.execution_data.calldata.clone())?;\n\n            setup_result.success &= script_result.success;\n            setup_result.gas_used = script_result.gas_used;\n            setup_result.logs.extend(script_result.logs);\n            setup_result.traces.extend(script_result.traces);\n            setup_result.labeled_addresses.extend(script_result.labeled_addresses);\n            setup_result.returned = script_result.returned;\n            setup_result.breakpoints = script_result.breakpoints;\n\n            match (&mut setup_result.transactions, script_result.transactions) {\n                (Some(txs), Some(new_txs)) => {\n                    txs.extend(new_txs);\n                }\n                (None, Some(new_txs)) => {\n                    setup_result.transactions = Some(new_txs);\n                }\n                _ => {}\n            }\n        }\n\n        Ok(setup_result)\n    }\n\n    /// It finds the deployer from the running script and uses it to predeploy libraries.\n    ///\n    /// If there are multiple candidate addresses, it skips everything and lets `--sender` deploy\n    /// them instead.\n    fn maybe_new_sender(\n        &self,\n        transactions: Option<&BroadcastableTransactions>,\n    ) -> Result<Option<Address>> {\n        let mut new_sender = None;\n\n        if let Some(txs) = transactions {\n            // If the user passed a `--sender` don't check anything.\n            if self.build_data.predeploy_libraries.libraries_count() > 0\n                && self.args.evm.sender.is_none()\n            {\n                for tx in txs {\n                    if tx.to.is_none() {\n                        let sender = tx.from;\n                        if let Some(ns) = new_sender {\n                            if sender != ns {\n                                sh_warn!(\n                                    \"You have more than one deployer who could predeploy libraries. Using `--sender` instead.\"\n                                )?;\n                                return Ok(None);\n                            }\n                        } else if sender != self.script_config.evm_opts.sender {\n                            new_sender = Some(sender);\n                        }\n                    }\n                }\n            }\n        }\n        Ok(new_sender)\n    }\n}\n\n/// Container for information about RPC-endpoints used during script execution.\npub struct RpcData {\n    /// Unique list of rpc urls present.\n    pub total_rpcs: HashSet<String>,\n    /// If true, one of the transactions did not have a rpc.\n    pub missing_rpc: bool,\n}\n\nimpl RpcData {\n    /// Iterates over script transactions and collects RPC urls.\n    fn from_transactions(txs: &BroadcastableTransactions) -> Self {\n        let missing_rpc = txs.iter().any(|tx| tx.rpc.is_none());\n        let total_rpcs =\n            txs.iter().filter_map(|tx| tx.rpc.as_ref().cloned()).collect::<HashSet<_>>();\n\n        Self { total_rpcs, missing_rpc }\n    }\n\n    /// Returns true if script might be multi-chain.\n    /// Returns false positive in case when missing rpc is the same as the only rpc present.\n    pub fn is_multi_chain(&self) -> bool {\n        self.total_rpcs.len() > 1 || (self.missing_rpc && !self.total_rpcs.is_empty())\n    }\n\n    /// Checks if all RPCs support EIP-3855. Prints a warning if not.\n    async fn check_shanghai_support(&self) -> Result<()> {\n        let chain_ids = self.total_rpcs.iter().map(|rpc| async move {\n            let provider = ProviderBuilder::<AnyNetwork>::new(rpc).build().ok()?;\n            let id = provider.get_chain_id().await.ok()?;\n            NamedChain::try_from(id).ok()\n        });\n\n        let chains = join_all(chain_ids).await;\n        let iter = chains.iter().flatten().map(|c| (c.supports_shanghai(), c));\n        if iter.clone().any(|(s, _)| !s) {\n            let msg = format!(\n                \"\\\nEIP-3855 is not supported in one or more of the RPCs used.\nUnsupported Chain IDs: {}.\nContracts deployed with a Solidity version equal or higher than 0.8.20 might not work properly.\nFor more information, please see https://eips.ethereum.org/EIPS/eip-3855\",\n                iter.filter(|(supported, _)| !supported)\n                    .map(|(_, chain)| *chain as u64)\n                    .format(\", \")\n            );\n            sh_warn!(\"{msg}\")?;\n        }\n        Ok(())\n    }\n}\n\n/// Container for data being collected after execution.\npub struct ExecutionArtifacts {\n    /// Trace decoder used to decode traces.\n    pub decoder: CallTraceDecoder,\n    /// Return values from the execution result.\n    pub returns: HashMap<String, NestedValue>,\n    /// Information about RPC endpoints used during script execution.\n    pub rpc_data: RpcData,\n}\n\n/// State after the script has been executed.\npub struct ExecutedState {\n    pub args: ScriptArgs,\n    pub script_config: ScriptConfig,\n    pub script_wallets: Wallets,\n    pub browser_wallet: Option<BrowserSigner<Ethereum>>,\n    pub build_data: LinkedBuildData,\n    pub execution_data: ExecutionData,\n    pub execution_result: ScriptResult,\n}\n\nimpl ExecutedState {\n    /// Collects the data we need for simulation and various post-execution tasks.\n    pub async fn prepare_simulation(self) -> Result<PreSimulationState> {\n        let returns = self.get_returns()?;\n\n        let decoder = self.build_trace_decoder(&self.build_data.known_contracts).await?;\n\n        let txs = self.execution_result.transactions.clone().unwrap_or_default();\n        let rpc_data = RpcData::from_transactions(&txs);\n\n        if rpc_data.is_multi_chain() {\n            sh_warn!(\"Multi chain deployment is still under development. Use with caution.\")?;\n            if !self.build_data.libraries.is_empty() {\n                eyre::bail!(\n                    \"Multi chain deployment does not support library linking at the moment.\"\n                )\n            }\n        }\n        rpc_data.check_shanghai_support().await?;\n\n        Ok(PreSimulationState {\n            args: self.args,\n            script_config: self.script_config,\n            script_wallets: self.script_wallets,\n            browser_wallet: self.browser_wallet,\n            build_data: self.build_data,\n            execution_data: self.execution_data,\n            execution_result: self.execution_result,\n            execution_artifacts: ExecutionArtifacts { decoder, returns, rpc_data },\n        })\n    }\n\n    /// Builds [CallTraceDecoder] from the execution result and known contracts.\n    async fn build_trace_decoder(\n        &self,\n        known_contracts: &ContractsByArtifact,\n    ) -> Result<CallTraceDecoder> {\n        let mut decoder = CallTraceDecoderBuilder::new()\n            .with_labels(self.execution_result.labeled_addresses.clone())\n            .with_verbosity(self.script_config.evm_opts.verbosity)\n            .with_known_contracts(known_contracts)\n            .with_signature_identifier(SignaturesIdentifier::from_config(\n                &self.script_config.config,\n            )?)\n            .with_label_disabled(self.args.disable_labels)\n            .build();\n\n        let mut identifier = TraceIdentifiers::new().with_local(known_contracts).with_external(\n            &self.script_config.config,\n            self.script_config.evm_opts.get_remote_chain_id().await,\n        )?;\n\n        for (_, trace) in &self.execution_result.traces {\n            decoder.identify(trace, &mut identifier);\n        }\n\n        Ok(decoder)\n    }\n\n    /// Collects the return values from the execution result.\n    fn get_returns(&self) -> Result<HashMap<String, NestedValue>> {\n        let mut returns = HashMap::default();\n        let returned = &self.execution_result.returned;\n        let func = &self.execution_data.func;\n\n        match func.abi_decode_output(returned) {\n            Ok(decoded) => {\n                for (index, (token, output)) in decoded.iter().zip(&func.outputs).enumerate() {\n                    let internal_type =\n                        output.internal_type.clone().unwrap_or(InternalType::Other {\n                            contract: None,\n                            ty: \"unknown\".to_string(),\n                        });\n\n                    let label = if !output.name.is_empty() {\n                        output.name.to_string()\n                    } else {\n                        index.to_string()\n                    };\n\n                    returns.insert(\n                        label,\n                        NestedValue {\n                            internal_type: internal_type.to_string(),\n                            value: format_token_raw(token),\n                        },\n                    );\n                }\n            }\n            Err(_) => {\n                sh_err!(\"Failed to decode return value: {:x?}\", returned)?;\n            }\n        }\n\n        Ok(returns)\n    }\n}\n\nimpl PreSimulationState {\n    pub async fn show_json(&self) -> Result<()> {\n        let mut result = self.execution_result.clone();\n\n        for (_, trace) in &mut result.traces {\n            decode_trace_arena(trace, &self.execution_artifacts.decoder).await;\n        }\n\n        let json_result = JsonResult {\n            logs: decode_console_logs(&result.logs),\n            returns: &self.execution_artifacts.returns,\n            result: &result,\n        };\n        let json = serde_json::to_string(&json_result)?;\n\n        sh_println!(\"{json}\")?;\n\n        if !self.execution_result.success {\n            return Err(eyre::eyre!(\n                \"script failed: {}\",\n                &self.execution_artifacts.decoder.revert_decoder.decode(&result.returned[..], None)\n            ));\n        }\n\n        Ok(())\n    }\n\n    pub async fn show_traces(&self) -> Result<()> {\n        let verbosity = self.script_config.evm_opts.verbosity;\n        let func = &self.execution_data.func;\n        let result = &self.execution_result;\n        let decoder = &self.execution_artifacts.decoder;\n\n        if !result.success || verbosity > 3 {\n            if result.traces.is_empty() {\n                warn!(verbosity, \"no traces\");\n            }\n\n            sh_println!(\"Traces:\")?;\n            for (kind, trace) in &result.traces {\n                let should_include = match kind {\n                    TraceKind::Setup => verbosity >= 5,\n                    TraceKind::Execution => verbosity > 3,\n                    _ => false,\n                } || !result.success;\n\n                if should_include {\n                    let mut trace = trace.clone();\n                    decode_trace_arena(&mut trace, decoder).await;\n                    sh_println!(\"{}\", render_trace_arena(&trace))?;\n                }\n            }\n            sh_println!()?;\n        }\n\n        if result.success {\n            sh_println!(\"{}\", \"Script ran successfully.\".green())?;\n        }\n\n        if self.script_config.evm_opts.fork_url.is_none() {\n            sh_println!(\"Gas used: {}\", result.gas_used)?;\n        }\n\n        if result.success && !result.returned.is_empty() {\n            sh_println!(\"\\n== Return ==\")?;\n            match func.abi_decode_output(&result.returned) {\n                Ok(decoded) => {\n                    for (index, (token, output)) in decoded.iter().zip(&func.outputs).enumerate() {\n                        let internal_type =\n                            output.internal_type.clone().unwrap_or(InternalType::Other {\n                                contract: None,\n                                ty: \"unknown\".to_string(),\n                            });\n\n                        let label = if !output.name.is_empty() {\n                            output.name.to_string()\n                        } else {\n                            index.to_string()\n                        };\n                        sh_println!(\n                            \"{label}: {internal_type} {value}\",\n                            label = label.trim_end(),\n                            value = format_token(token)\n                        )?;\n                    }\n                }\n                Err(_) => {\n                    sh_err!(\"{:x?}\", (&result.returned))?;\n                }\n            }\n        }\n\n        let console_logs = decode_console_logs(&result.logs);\n        if !console_logs.is_empty() {\n            sh_println!(\"\\n== Logs ==\")?;\n            for log in console_logs {\n                sh_println!(\"  {log}\")?;\n            }\n        }\n\n        if !result.success {\n            return Err(eyre::eyre!(\n                \"script failed: {}\",\n                &self.execution_artifacts.decoder.revert_decoder.decode(&result.returned[..], None)\n            ));\n        }\n\n        Ok(())\n    }\n\n    pub fn run_debugger(self) -> Result<()> {\n        self.create_debugger().try_run_tui()?;\n        Ok(())\n    }\n\n    pub fn dump_debugger(self, path: &Path) -> Result<()> {\n        self.create_debugger().dump_to_file(path)?;\n        Ok(())\n    }\n\n    fn create_debugger(self) -> Debugger {\n        Debugger::builder()\n            .traces(\n                self.execution_result\n                    .traces\n                    .into_iter()\n                    .filter(|(t, _)| t.is_execution())\n                    .collect(),\n            )\n            .decoder(&self.execution_artifacts.decoder)\n            .sources(self.build_data.sources)\n            .breakpoints(self.execution_result.breakpoints)\n            .build()\n    }\n}\n"
  },
  {
    "path": "crates/script/src/lib.rs",
    "content": "//! # foundry-script\n//!\n//! Smart contract scripting.\n\n#![cfg_attr(not(test), warn(unused_crate_dependencies))]\n#![cfg_attr(docsrs, feature(doc_cfg))]\n\n#[macro_use]\nextern crate foundry_common;\n\n#[macro_use]\nextern crate tracing;\n\nuse crate::runner::ScriptRunner;\nuse alloy_json_abi::{Function, JsonAbi};\nuse alloy_network::Ethereum;\nuse alloy_primitives::{\n    Address, Bytes, Log, TxKind, U256, hex,\n    map::{AddressHashMap, HashMap},\n};\nuse alloy_signer::Signer;\nuse broadcast::next_nonce;\nuse build::PreprocessedState;\nuse clap::{Parser, ValueHint};\nuse dialoguer::Confirm;\nuse eyre::{ContextCompat, Result};\nuse forge_script_sequence::{AdditionalContract, NestedValue};\nuse forge_verify::{RetryArgs, VerifierArgs};\nuse foundry_cli::{\n    opts::{BuildOpts, EvmArgs, GlobalArgs},\n    utils::LoadConfig,\n};\nuse foundry_common::{\n    CONTRACT_MAX_SIZE, ContractsByArtifact, SELECTOR_LEN,\n    abi::{encode_function_args, get_func},\n    shell,\n};\nuse foundry_compilers::ArtifactId;\nuse foundry_config::{\n    Config, figment,\n    figment::{\n        Metadata, Profile, Provider,\n        value::{Dict, Map},\n    },\n};\nuse foundry_evm::{\n    backend::Backend,\n    core::Breakpoints,\n    executors::ExecutorBuilder,\n    inspectors::{\n        CheatsConfig,\n        cheatcodes::{BroadcastableTransactions, Wallets},\n    },\n    opts::EvmOpts,\n    traces::{TraceMode, Traces},\n};\nuse foundry_wallets::MultiWalletOpts;\nuse serde::Serialize;\nuse std::path::PathBuf;\n\nmod broadcast;\nmod build;\nmod execute;\nmod multi_sequence;\nmod progress;\nmod providers;\nmod receipts;\nmod runner;\nmod sequence;\nmod simulate;\nmod transaction;\nmod verify;\n\n// Loads project's figment and merges the build cli arguments into it\nfoundry_config::merge_impl_figment_convert!(ScriptArgs, build, evm);\n\n/// CLI arguments for `forge script`.\n#[derive(Clone, Debug, Default, Parser)]\npub struct ScriptArgs {\n    // Include global options for users of this struct.\n    #[command(flatten)]\n    pub global: GlobalArgs,\n\n    /// The contract you want to run. Either the file path or contract name.\n    ///\n    /// If multiple contracts exist in the same file you must specify the target contract with\n    /// --target-contract.\n    #[arg(value_hint = ValueHint::FilePath)]\n    pub path: String,\n\n    /// Arguments to pass to the script function.\n    pub args: Vec<String>,\n\n    /// The name of the contract you want to run.\n    #[arg(long, visible_alias = \"tc\", value_name = \"CONTRACT_NAME\")]\n    pub target_contract: Option<String>,\n\n    /// The signature of the function you want to call in the contract, or raw calldata.\n    #[arg(long, short, default_value = \"run\")]\n    pub sig: String,\n\n    /// Max priority fee per gas for EIP1559 transactions.\n    #[arg(\n        long,\n        env = \"ETH_PRIORITY_GAS_PRICE\",\n        value_parser = foundry_cli::utils::parse_ether_value,\n        value_name = \"PRICE\"\n    )]\n    pub priority_gas_price: Option<U256>,\n\n    /// Use legacy transactions instead of EIP1559 ones.\n    ///\n    /// This is auto-enabled for common networks without EIP1559.\n    #[arg(long)]\n    pub legacy: bool,\n\n    /// Broadcasts the transactions.\n    #[arg(long)]\n    pub broadcast: bool,\n\n    /// Batch size of transactions.\n    ///\n    /// This is ignored and set to 1 if batching is not available or `--slow` is enabled.\n    #[arg(long, default_value = \"100\")]\n    pub batch_size: usize,\n\n    /// Skips on-chain simulation.\n    #[arg(long)]\n    pub skip_simulation: bool,\n\n    /// Relative percentage to multiply gas estimates by.\n    #[arg(long, short, default_value = \"130\")]\n    pub gas_estimate_multiplier: u64,\n\n    /// Send via `eth_sendTransaction` using the `--sender` argument as sender.\n    #[arg(\n        long,\n        conflicts_with_all = &[\"private_key\", \"private_keys\", \"ledger\", \"trezor\", \"aws\", \"browser\"],\n    )]\n    pub unlocked: bool,\n\n    /// Resumes submitting transactions that failed or timed-out previously.\n    ///\n    /// It DOES NOT simulate the script again and it expects nonces to have remained the same.\n    ///\n    /// Example: If transaction N has a nonce of 22, then the account should have a nonce of 22,\n    /// otherwise it fails.\n    #[arg(long)]\n    pub resume: bool,\n\n    /// If present, --resume or --verify will be assumed to be a multi chain deployment.\n    #[arg(long)]\n    pub multi: bool,\n\n    /// Open the script in the debugger.\n    ///\n    /// Takes precedence over broadcast.\n    #[arg(long)]\n    pub debug: bool,\n\n    /// Dumps all debugger steps to file.\n    #[arg(\n        long,\n        requires = \"debug\",\n        value_hint = ValueHint::FilePath,\n        value_name = \"PATH\"\n    )]\n    pub dump: Option<PathBuf>,\n\n    /// Makes sure a transaction is sent,\n    /// only after its previous one has been confirmed and succeeded.\n    #[arg(long)]\n    pub slow: bool,\n\n    /// Disables interactive prompts that might appear when deploying big contracts.\n    ///\n    /// For more info on the contract size limit, see EIP-170: <https://eips.ethereum.org/EIPS/eip-170>\n    #[arg(long)]\n    pub non_interactive: bool,\n\n    /// Disables the contract size limit during script execution.\n    #[arg(long)]\n    pub disable_code_size_limit: bool,\n\n    /// Disables the labels in the traces.\n    #[arg(long)]\n    pub disable_labels: bool,\n\n    /// The Etherscan (or equivalent) API key\n    #[arg(long, env = \"ETHERSCAN_API_KEY\", value_name = \"KEY\")]\n    pub etherscan_api_key: Option<String>,\n\n    /// Verifies all the contracts found in the receipts of a script, if any.\n    #[arg(long, requires = \"broadcast\")]\n    pub verify: bool,\n\n    /// Gas price for legacy transactions, or max fee per gas for EIP1559 transactions, either\n    /// specified in wei, or as a string with a unit type.\n    ///\n    /// Examples: 1ether, 10gwei, 0.01ether\n    #[arg(\n        long,\n        env = \"ETH_GAS_PRICE\",\n        value_parser = foundry_cli::utils::parse_ether_value,\n        value_name = \"PRICE\",\n    )]\n    pub with_gas_price: Option<U256>,\n\n    /// Timeout to use for broadcasting transactions.\n    #[arg(long, env = \"ETH_TIMEOUT\")]\n    pub timeout: Option<u64>,\n\n    #[command(flatten)]\n    pub build: BuildOpts,\n\n    #[command(flatten)]\n    pub wallets: MultiWalletOpts,\n\n    #[command(flatten)]\n    pub evm: EvmArgs,\n\n    #[command(flatten)]\n    pub verifier: VerifierArgs,\n\n    #[command(flatten)]\n    pub retry: RetryArgs,\n}\n\nimpl ScriptArgs {\n    pub async fn preprocess(self) -> Result<PreprocessedState> {\n        let script_wallets = Wallets::new(self.wallets.get_multi_wallet().await?, self.evm.sender);\n        let browser_wallet = self.wallets.browser_signer::<Ethereum>().await?;\n\n        let (config, mut evm_opts) = self.load_config_and_evm_opts()?;\n\n        if let Some(sender) = self.maybe_load_private_key()? {\n            evm_opts.sender = sender;\n        } else if self.evm.sender.is_none() {\n            // If no sender was explicitly set via --sender, auto-detect it from available signers:\n            // use the sole signer's address if there's exactly one, or fall back to the browser\n            // wallet address if present.\n            if let Ok(signers) = script_wallets.signers()\n                && signers.len() == 1\n            {\n                evm_opts.sender = signers[0];\n            } else if let Some(signer) = browser_wallet.as_ref().map(|b| b.address()) {\n                evm_opts.sender = signer\n            }\n        }\n\n        let script_config = ScriptConfig::new(config, evm_opts).await?;\n\n        Ok(PreprocessedState { args: self, script_config, script_wallets, browser_wallet })\n    }\n\n    /// Executes the script\n    pub async fn run_script(self) -> Result<()> {\n        trace!(target: \"script\", \"executing script command\");\n\n        let state = self.preprocess().await?;\n        let create2_deployer = state.script_config.evm_opts.create2_deployer;\n        let compiled = state.compile()?;\n\n        // Move from `CompiledState` to `BundledState` either by resuming or executing and\n        // simulating script.\n        let bundled = if compiled.args.resume {\n            compiled.resume().await?\n        } else {\n            // Drive state machine to point at which we have everything needed for simulation.\n            let pre_simulation = compiled\n                .link()\n                .await?\n                .prepare_execution()\n                .await?\n                .execute()\n                .await?\n                .prepare_simulation()\n                .await?;\n\n            if pre_simulation.args.debug {\n                return match pre_simulation.args.dump.clone() {\n                    Some(path) => pre_simulation.dump_debugger(&path),\n                    None => pre_simulation.run_debugger(),\n                };\n            }\n\n            if shell::is_json() {\n                pre_simulation.show_json().await?;\n            } else {\n                pre_simulation.show_traces().await?;\n            }\n\n            // Ensure that we have transactions to simulate/broadcast, otherwise exit early to avoid\n            // hard error.\n            if pre_simulation\n                .execution_result\n                .transactions\n                .as_ref()\n                .is_none_or(|txs| txs.is_empty())\n            {\n                if pre_simulation.args.broadcast {\n                    sh_warn!(\"No transactions to broadcast.\")?;\n                }\n\n                return Ok(());\n            }\n\n            // Check if there are any missing RPCs and exit early to avoid hard error.\n            if pre_simulation.execution_artifacts.rpc_data.missing_rpc {\n                if !shell::is_json() {\n                    sh_println!(\"\\nIf you wish to simulate on-chain transactions pass a RPC URL.\")?;\n                }\n\n                return Ok(());\n            }\n\n            pre_simulation.args.check_contract_sizes(\n                &pre_simulation.execution_result,\n                &pre_simulation.build_data.known_contracts,\n                create2_deployer,\n            )?;\n\n            pre_simulation.fill_metadata().await?.bundle().await?\n        };\n\n        // Exit early in case user didn't provide any broadcast/verify related flags.\n        if !bundled.args.should_broadcast() {\n            if !shell::is_json() {\n                if shell::verbosity() >= 4 {\n                    sh_println!(\"\\n=== Transactions that will be broadcast ===\\n\")?;\n                    bundled.sequence.show_transactions()?;\n                }\n\n                sh_println!(\n                    \"\\nSIMULATION COMPLETE. To broadcast these transactions, add --broadcast and wallet configuration(s) to the previous command. See forge script --help for more.\"\n                )?;\n            }\n            return Ok(());\n        }\n\n        // Exit early if something is wrong with verification options.\n        if bundled.args.verify {\n            bundled.verify_preflight_check()?;\n        }\n\n        // Wait for pending txes and broadcast others.\n        let broadcasted = bundled.wait_for_pending().await?.broadcast().await?;\n\n        if broadcasted.args.verify {\n            broadcasted.verify().await?;\n        }\n\n        Ok(())\n    }\n\n    /// In case the user has loaded *only* one private-key or a single remote signer (e.g.,\n    /// Turnkey), we can assume that they're using it as the `--sender`.\n    fn maybe_load_private_key(&self) -> Result<Option<Address>> {\n        if let Some(turnkey_address) = self.wallets.turnkey_address() {\n            return Ok(Some(turnkey_address));\n        }\n\n        let maybe_sender = self\n            .wallets\n            .private_keys()?\n            .filter(|pks| pks.len() == 1)\n            .map(|pks| pks.first().unwrap().address());\n        Ok(maybe_sender)\n    }\n\n    /// Returns the Function and calldata based on the signature\n    ///\n    /// If the `sig` is a valid human-readable function we find the corresponding function in the\n    /// `abi` If the `sig` is valid hex, we assume it's calldata and try to find the\n    /// corresponding function by matching the selector, first 4 bytes in the calldata.\n    ///\n    /// Note: We assume that the `sig` is already stripped of its prefix, See [`ScriptArgs`]\n    fn get_method_and_calldata(&self, abi: &JsonAbi) -> Result<(Function, Bytes)> {\n        if let Ok(decoded) = hex::decode(&self.sig) {\n            let selector = &decoded[..SELECTOR_LEN];\n            let func =\n                abi.functions().find(|func| selector == &func.selector()[..]).ok_or_else(|| {\n                    eyre::eyre!(\n                        \"Function selector `{}` not found in the ABI\",\n                        hex::encode(selector)\n                    )\n                })?;\n            return Ok((func.clone(), decoded.into()));\n        }\n\n        let func = if self.sig.contains('(') {\n            let func = get_func(&self.sig)?;\n            abi.functions()\n                .find(|&abi_func| abi_func.selector() == func.selector())\n                .wrap_err(format!(\"Function `{}` is not implemented in your script.\", self.sig))?\n        } else {\n            let matching_functions =\n                abi.functions().filter(|func| func.name == self.sig).collect::<Vec<_>>();\n            match matching_functions.len() {\n                0 => eyre::bail!(\"Function `{}` not found in the ABI\", self.sig),\n                1 => matching_functions[0],\n                2.. => eyre::bail!(\n                    \"Multiple functions with the same name `{}` found in the ABI\",\n                    self.sig\n                ),\n            }\n        };\n        let data = encode_function_args(func, &self.args)?;\n\n        Ok((func.clone(), data.into()))\n    }\n\n    /// Checks if the transaction is a deployment with either a size above the `CONTRACT_MAX_SIZE`\n    /// or specified `code_size_limit`.\n    ///\n    /// If `self.broadcast` is enabled, it asks confirmation of the user. Otherwise, it just warns\n    /// the user.\n    fn check_contract_sizes(\n        &self,\n        result: &ScriptResult,\n        known_contracts: &ContractsByArtifact,\n        create2_deployer: Address,\n    ) -> Result<()> {\n        // If disable-code-size-limit flag is enabled then skip the size check\n        if self.disable_code_size_limit {\n            return Ok(());\n        }\n\n        // (name, &init, &deployed)[]\n        let mut bytecodes: Vec<(String, &[u8], &[u8])> = vec![];\n\n        // From artifacts\n        for (artifact, contract) in known_contracts.iter() {\n            let Some(bytecode) = contract.bytecode() else { continue };\n            let Some(deployed_bytecode) = contract.deployed_bytecode() else { continue };\n            bytecodes.push((artifact.name.clone(), bytecode, deployed_bytecode));\n        }\n\n        // From traces\n        let create_nodes = result.traces.iter().flat_map(|(_, traces)| {\n            traces.nodes().iter().filter(|node| node.trace.kind.is_any_create())\n        });\n        let mut unknown_c = 0usize;\n        for node in create_nodes {\n            let init_code = &node.trace.data;\n            let deployed_code = &node.trace.output;\n            if !bytecodes.iter().any(|(_, b, _)| *b == init_code.as_ref()) {\n                bytecodes.push((format!(\"Unknown{unknown_c}\"), init_code, deployed_code));\n                unknown_c += 1;\n            }\n            continue;\n        }\n\n        let mut prompt_user = false;\n        let max_size = match self.evm.env.code_size_limit {\n            Some(size) => size,\n            None => CONTRACT_MAX_SIZE,\n        };\n\n        for (data, to) in result.transactions.iter().flat_map(|txes| {\n            txes.iter().filter_map(|tx| (tx.input.len() > max_size).then_some((&tx.input, tx.to)))\n        }) {\n            let mut offset = 0;\n\n            // Find if it's a CREATE or CREATE2. Otherwise, skip transaction.\n            if let Some(TxKind::Call(to)) = to {\n                if to == create2_deployer {\n                    // Size of the salt prefix.\n                    offset = 32;\n                } else {\n                    continue;\n                }\n            } else if let Some(TxKind::Create) = to {\n                // Pass\n            }\n\n            // Find artifact with a deployment code same as the data.\n            if let Some((name, _, deployed_code)) =\n                bytecodes.iter().find(|(_, init_code, _)| *init_code == &data[offset..])\n            {\n                let deployment_size = deployed_code.len();\n\n                if deployment_size > max_size {\n                    prompt_user = self.should_broadcast();\n                    sh_err!(\n                        \"`{name}` is above the contract size limit ({deployment_size} > {max_size}).\"\n                    )?;\n                }\n            }\n        }\n\n        // Only prompt if we're broadcasting and we've not disabled interactivity.\n        if prompt_user\n            && !self.non_interactive\n            && !Confirm::new().with_prompt(\"Do you wish to continue?\".to_string()).interact()?\n        {\n            eyre::bail!(\"User canceled the script.\");\n        }\n\n        Ok(())\n    }\n\n    /// We only broadcast transactions if --broadcast, --resume, or --verify was passed.\n    fn should_broadcast(&self) -> bool {\n        self.broadcast || self.resume || self.verify\n    }\n}\n\nimpl Provider for ScriptArgs {\n    fn metadata(&self) -> Metadata {\n        Metadata::named(\"Script Args Provider\")\n    }\n\n    fn data(&self) -> Result<Map<Profile, Dict>, figment::Error> {\n        let mut dict = Dict::default();\n\n        if let Some(ref etherscan_api_key) =\n            self.etherscan_api_key.as_ref().filter(|s| !s.trim().is_empty())\n        {\n            dict.insert(\n                \"etherscan_api_key\".to_string(),\n                figment::value::Value::from(etherscan_api_key.to_string()),\n            );\n        }\n\n        if let Some(timeout) = self.timeout {\n            dict.insert(\"transaction_timeout\".to_string(), timeout.into());\n        }\n\n        Ok(Map::from([(Config::selected_profile(), dict)]))\n    }\n}\n\n#[derive(Default, Serialize, Clone)]\npub struct ScriptResult {\n    pub success: bool,\n    #[serde(rename = \"raw_logs\")]\n    pub logs: Vec<Log>,\n    pub traces: Traces,\n    pub gas_used: u64,\n    pub labeled_addresses: AddressHashMap<String>,\n    #[serde(skip)]\n    pub transactions: Option<BroadcastableTransactions>,\n    pub returned: Bytes,\n    pub address: Option<Address>,\n    #[serde(skip)]\n    pub breakpoints: Breakpoints,\n}\n\nimpl ScriptResult {\n    pub fn get_created_contracts(\n        &self,\n        known_contracts: &ContractsByArtifact,\n    ) -> Vec<AdditionalContract> {\n        self.traces\n            .iter()\n            .flat_map(|(_, traces)| {\n                traces.nodes().iter().filter_map(|node| {\n                    if node.trace.kind.is_any_create() {\n                        let init_code = node.trace.data.clone();\n                        let contract_name = known_contracts\n                            .find_by_creation_code(init_code.as_ref())\n                            .map(|artifact| artifact.0.name.clone());\n                        return Some(AdditionalContract {\n                            opcode: node.trace.kind,\n                            address: node.trace.address,\n                            contract_name,\n                            init_code,\n                        });\n                    }\n                    None\n                })\n            })\n            .collect()\n    }\n}\n\n#[derive(Serialize)]\nstruct JsonResult<'a> {\n    logs: Vec<String>,\n    returns: &'a HashMap<String, NestedValue>,\n    #[serde(flatten)]\n    result: &'a ScriptResult,\n}\n\n#[derive(Clone, Debug)]\npub struct ScriptConfig {\n    pub config: Config,\n    pub evm_opts: EvmOpts,\n    pub sender_nonce: u64,\n    /// Maps a rpc url to a backend\n    pub backends: HashMap<String, Backend>,\n}\n\nimpl ScriptConfig {\n    pub async fn new(config: Config, evm_opts: EvmOpts) -> Result<Self> {\n        let sender_nonce = if let Some(fork_url) = evm_opts.fork_url.as_ref() {\n            next_nonce(evm_opts.sender, fork_url, evm_opts.fork_block_number).await?\n        } else {\n            // dapptools compatibility\n            1\n        };\n\n        Ok(Self { config, evm_opts, sender_nonce, backends: HashMap::default() })\n    }\n\n    pub async fn update_sender(&mut self, sender: Address) -> Result<()> {\n        self.sender_nonce = if let Some(fork_url) = self.evm_opts.fork_url.as_ref() {\n            next_nonce(sender, fork_url, None).await?\n        } else {\n            // dapptools compatibility\n            1\n        };\n        self.evm_opts.sender = sender;\n        Ok(())\n    }\n\n    async fn get_runner(&mut self) -> Result<ScriptRunner> {\n        self._get_runner(None, false).await\n    }\n\n    async fn get_runner_with_cheatcodes(\n        &mut self,\n        known_contracts: ContractsByArtifact,\n        script_wallets: Wallets,\n        debug: bool,\n        target: ArtifactId,\n    ) -> Result<ScriptRunner> {\n        self._get_runner(Some((known_contracts, script_wallets, target)), debug).await\n    }\n\n    async fn _get_runner(\n        &mut self,\n        cheats_data: Option<(ContractsByArtifact, Wallets, ArtifactId)>,\n        debug: bool,\n    ) -> Result<ScriptRunner> {\n        trace!(\"preparing script runner\");\n        let (evm_env, tx_env) = self.evm_opts.env().await?;\n\n        let db = if let Some(fork_url) = self.evm_opts.fork_url.as_ref() {\n            match self.backends.get(fork_url) {\n                Some(db) => db.clone(),\n                None => {\n                    let fork = self.evm_opts.get_fork(&self.config, evm_env.clone());\n                    let backend = Backend::spawn(fork)?;\n                    self.backends.insert(fork_url.clone(), backend.clone());\n                    backend\n                }\n            }\n        } else {\n            // It's only really `None`, when we don't pass any `--fork-url`. And if so, there is\n            // no need to cache it, since there won't be any onchain simulation that we'd need\n            // to cache the backend for.\n            Backend::spawn(None)?\n        };\n\n        // We need to enable tracing to decode contract names: local or external.\n        let mut builder = ExecutorBuilder::new()\n            .inspectors(|stack| {\n                stack\n                    .logs(self.config.live_logs)\n                    .trace_mode(if debug { TraceMode::Debug } else { TraceMode::Call })\n                    .networks(self.evm_opts.networks)\n                    .create2_deployer(self.evm_opts.create2_deployer)\n            })\n            .spec_id(self.config.evm_spec_id())\n            .gas_limit(self.evm_opts.gas_limit())\n            .legacy_assertions(self.config.legacy_assertions);\n\n        if let Some((known_contracts, script_wallets, target)) = cheats_data {\n            builder = builder.inspectors(|stack| {\n                stack\n                    .cheatcodes(\n                        CheatsConfig::new(\n                            &self.config,\n                            self.evm_opts.clone(),\n                            Some(known_contracts),\n                            Some(target),\n                        )\n                        .into(),\n                    )\n                    .wallets(script_wallets)\n                    .enable_isolation(self.evm_opts.isolate)\n            });\n        }\n\n        Ok(ScriptRunner::new(builder.build(evm_env, tx_env, db), self.evm_opts.clone()))\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use foundry_config::{NamedChain, UnresolvedEnvVarError};\n    use std::fs;\n    use tempfile::tempdir;\n\n    #[test]\n    fn can_parse_sig() {\n        let sig = \"0x522bb704000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfFFb92266\";\n        let args = ScriptArgs::parse_from([\"foundry-cli\", \"Contract.sol\", \"--sig\", sig]);\n        assert_eq!(args.sig, sig);\n    }\n\n    #[test]\n    fn can_parse_unlocked() {\n        let args = ScriptArgs::parse_from([\n            \"foundry-cli\",\n            \"Contract.sol\",\n            \"--sender\",\n            \"0x4e59b44847b379578588920ca78fbf26c0b4956c\",\n            \"--unlocked\",\n        ]);\n        assert!(args.unlocked);\n\n        let key = U256::ZERO;\n        let args = ScriptArgs::try_parse_from([\n            \"foundry-cli\",\n            \"Contract.sol\",\n            \"--sender\",\n            \"0x4e59b44847b379578588920ca78fbf26c0b4956c\",\n            \"--unlocked\",\n            \"--private-key\",\n            &key.to_string(),\n        ]);\n        assert!(args.is_err());\n    }\n\n    #[test]\n    fn can_merge_script_config() {\n        let args = ScriptArgs::parse_from([\n            \"foundry-cli\",\n            \"Contract.sol\",\n            \"--etherscan-api-key\",\n            \"goerli\",\n        ]);\n        let config = args.load_config().unwrap();\n        assert_eq!(config.etherscan_api_key, Some(\"goerli\".to_string()));\n    }\n\n    #[test]\n    fn can_disable_code_size_limit() {\n        let args =\n            ScriptArgs::parse_from([\"foundry-cli\", \"Contract.sol\", \"--disable-code-size-limit\"]);\n        assert!(args.disable_code_size_limit);\n\n        let result = ScriptResult::default();\n        let contracts = ContractsByArtifact::default();\n        let create = Address::ZERO;\n        assert!(args.check_contract_sizes(&result, &contracts, create).is_ok());\n    }\n\n    #[test]\n    fn can_parse_verifier_url() {\n        let args = ScriptArgs::parse_from([\n            \"foundry-cli\",\n            \"script\",\n            \"script/Test.s.sol:TestScript\",\n            \"--fork-url\",\n            \"http://localhost:8545\",\n            \"--verifier-url\",\n            \"http://localhost:3000/api/verify\",\n            \"--etherscan-api-key\",\n            \"blacksmith\",\n            \"--broadcast\",\n            \"--verify\",\n            \"-vvvvv\",\n        ]);\n        assert_eq!(\n            args.verifier.verifier_url,\n            Some(\"http://localhost:3000/api/verify\".to_string())\n        );\n    }\n\n    #[test]\n    fn can_extract_code_size_limit() {\n        let args = ScriptArgs::parse_from([\n            \"foundry-cli\",\n            \"script\",\n            \"script/Test.s.sol:TestScript\",\n            \"--fork-url\",\n            \"http://localhost:8545\",\n            \"--broadcast\",\n            \"--code-size-limit\",\n            \"50000\",\n        ]);\n        assert_eq!(args.evm.env.code_size_limit, Some(50000));\n    }\n\n    #[test]\n    fn can_extract_script_etherscan_key() {\n        let temp = tempdir().unwrap();\n        let root = temp.path();\n\n        let config = r#\"\n                [profile.default]\n                etherscan_api_key = \"amoy\"\n\n                [etherscan]\n                amoy = { key = \"https://etherscan-amoy.com/\" }\n            \"#;\n\n        let toml_file = root.join(Config::FILE_NAME);\n        fs::write(toml_file, config).unwrap();\n        let args = ScriptArgs::parse_from([\n            \"foundry-cli\",\n            \"Contract.sol\",\n            \"--etherscan-api-key\",\n            \"amoy\",\n            \"--root\",\n            root.as_os_str().to_str().unwrap(),\n        ]);\n\n        let config = args.load_config().unwrap();\n        let amoy = config.get_etherscan_api_key(Some(NamedChain::PolygonAmoy.into()));\n        assert_eq!(amoy, Some(\"https://etherscan-amoy.com/\".to_string()));\n    }\n\n    #[test]\n    fn can_extract_script_rpc_alias() {\n        let temp = tempdir().unwrap();\n        let root = temp.path();\n\n        let config = r#\"\n                [profile.default]\n\n                [rpc_endpoints]\n                polygonAmoy = \"https://polygon-amoy.g.alchemy.com/v2/${_CAN_EXTRACT_RPC_ALIAS}\"\n            \"#;\n\n        let toml_file = root.join(Config::FILE_NAME);\n        fs::write(toml_file, config).unwrap();\n        let args = ScriptArgs::parse_from([\n            \"foundry-cli\",\n            \"DeployV1\",\n            \"--rpc-url\",\n            \"polygonAmoy\",\n            \"--root\",\n            root.as_os_str().to_str().unwrap(),\n        ]);\n\n        let err = args.load_config_and_evm_opts().unwrap_err();\n\n        assert!(err.downcast::<UnresolvedEnvVarError>().is_ok());\n\n        unsafe {\n            std::env::set_var(\"_CAN_EXTRACT_RPC_ALIAS\", \"123456\");\n        }\n        let (config, evm_opts) = args.load_config_and_evm_opts().unwrap();\n        assert_eq!(config.eth_rpc_url, Some(\"polygonAmoy\".to_string()));\n        assert_eq!(\n            evm_opts.fork_url,\n            Some(\"https://polygon-amoy.g.alchemy.com/v2/123456\".to_string())\n        );\n    }\n\n    #[test]\n    fn can_extract_script_rpc_and_etherscan_alias() {\n        let temp = tempdir().unwrap();\n        let root = temp.path();\n\n        let config = r#\"\n            [profile.default]\n\n            [rpc_endpoints]\n            amoy = \"https://polygon-amoy.g.alchemy.com/v2/${_EXTRACT_RPC_ALIAS}\"\n\n            [etherscan]\n            amoy = { key = \"${_ETHERSCAN_API_KEY}\", chain = 80002, url = \"https://amoy.polygonscan.com/\" }\n        \"#;\n\n        let toml_file = root.join(Config::FILE_NAME);\n        fs::write(toml_file, config).unwrap();\n        let args = ScriptArgs::parse_from([\n            \"foundry-cli\",\n            \"DeployV1\",\n            \"--rpc-url\",\n            \"amoy\",\n            \"--etherscan-api-key\",\n            \"amoy\",\n            \"--root\",\n            root.as_os_str().to_str().unwrap(),\n        ]);\n        let err = args.load_config_and_evm_opts().unwrap_err();\n\n        assert!(err.downcast::<UnresolvedEnvVarError>().is_ok());\n\n        unsafe {\n            std::env::set_var(\"_EXTRACT_RPC_ALIAS\", \"123456\");\n        }\n        unsafe {\n            std::env::set_var(\"_ETHERSCAN_API_KEY\", \"etherscan_api_key\");\n        }\n        let (config, evm_opts) = args.load_config_and_evm_opts().unwrap();\n        assert_eq!(config.eth_rpc_url, Some(\"amoy\".to_string()));\n        assert_eq!(\n            evm_opts.fork_url,\n            Some(\"https://polygon-amoy.g.alchemy.com/v2/123456\".to_string())\n        );\n        let etherscan = config.get_etherscan_api_key(Some(80002u64.into()));\n        assert_eq!(etherscan, Some(\"etherscan_api_key\".to_string()));\n        let etherscan = config.get_etherscan_api_key(None);\n        assert_eq!(etherscan, Some(\"etherscan_api_key\".to_string()));\n    }\n\n    #[test]\n    fn can_extract_script_rpc_and_sole_etherscan_alias() {\n        let temp = tempdir().unwrap();\n        let root = temp.path();\n\n        let config = r#\"\n                [profile.default]\n\n               [rpc_endpoints]\n                amoy = \"https://polygon-amoy.g.alchemy.com/v2/${_SOLE_EXTRACT_RPC_ALIAS}\"\n\n                [etherscan]\n                amoy = { key = \"${_SOLE_ETHERSCAN_API_KEY}\" }\n            \"#;\n\n        let toml_file = root.join(Config::FILE_NAME);\n        fs::write(toml_file, config).unwrap();\n        let args = ScriptArgs::parse_from([\n            \"foundry-cli\",\n            \"DeployV1\",\n            \"--rpc-url\",\n            \"amoy\",\n            \"--root\",\n            root.as_os_str().to_str().unwrap(),\n        ]);\n        let err = args.load_config_and_evm_opts().unwrap_err();\n\n        assert!(err.downcast::<UnresolvedEnvVarError>().is_ok());\n\n        unsafe {\n            std::env::set_var(\"_SOLE_EXTRACT_RPC_ALIAS\", \"123456\");\n        }\n        unsafe {\n            std::env::set_var(\"_SOLE_ETHERSCAN_API_KEY\", \"etherscan_api_key\");\n        }\n        let (config, evm_opts) = args.load_config_and_evm_opts().unwrap();\n        assert_eq!(\n            evm_opts.fork_url,\n            Some(\"https://polygon-amoy.g.alchemy.com/v2/123456\".to_string())\n        );\n        let etherscan = config.get_etherscan_api_key(Some(80002u64.into()));\n        assert_eq!(etherscan, Some(\"etherscan_api_key\".to_string()));\n        let etherscan = config.get_etherscan_api_key(None);\n        assert_eq!(etherscan, Some(\"etherscan_api_key\".to_string()));\n    }\n\n    // <https://github.com/foundry-rs/foundry/issues/5923>\n    #[test]\n    fn test_5923() {\n        let args =\n            ScriptArgs::parse_from([\"foundry-cli\", \"DeployV1\", \"--priority-gas-price\", \"100\"]);\n        assert!(args.priority_gas_price.is_some());\n    }\n\n    // <https://github.com/foundry-rs/foundry/issues/5910>\n    #[test]\n    fn test_5910() {\n        let args = ScriptArgs::parse_from([\n            \"foundry-cli\",\n            \"--broadcast\",\n            \"--with-gas-price\",\n            \"0\",\n            \"SolveTutorial\",\n        ]);\n        assert!(args.with_gas_price.unwrap().is_zero());\n    }\n}\n"
  },
  {
    "path": "crates/script/src/multi_sequence.rs",
    "content": "use alloy_network::Network;\nuse eyre::{ContextCompat, Result, WrapErr};\nuse forge_script_sequence::{\n    DRY_RUN_DIR, ScriptSequence, SensitiveScriptSequence, now, sig_to_file_name,\n};\nuse foundry_common::{fs, shell};\nuse foundry_compilers::ArtifactId;\nuse foundry_config::Config;\nuse serde::{Deserialize, Serialize};\nuse std::path::PathBuf;\n\n/// Holds the sequences of multiple chain deployments.\n#[derive(Clone, Default, Serialize, Deserialize)]\n#[serde(bound(\n    serialize = \"N::TransactionRequest: Serialize, N::TxEnvelope: Serialize\",\n    deserialize = \"N::TransactionRequest: for<'de2> Deserialize<'de2>, N::TxEnvelope: for<'de2> Deserialize<'de2>\"\n))]\npub struct MultiChainSequence<N: Network> {\n    pub deployments: Vec<ScriptSequence<N>>,\n    #[serde(skip)]\n    pub path: PathBuf,\n    #[serde(skip)]\n    pub sensitive_path: PathBuf,\n    pub timestamp: u128,\n}\n\n/// Sensitive values from script sequences.\n#[derive(Clone, Default, Serialize, Deserialize)]\npub struct SensitiveMultiChainSequence {\n    pub deployments: Vec<SensitiveScriptSequence>,\n}\n\nimpl SensitiveMultiChainSequence {\n    fn from_multi_sequence<N: Network>(sequence: &MultiChainSequence<N>) -> Self {\n        Self {\n            deployments: sequence.deployments.iter().map(SensitiveScriptSequence::from).collect(),\n        }\n    }\n}\n\nimpl<N: Network> MultiChainSequence<N> {\n    pub fn new(\n        deployments: Vec<ScriptSequence<N>>,\n        sig: &str,\n        target: &ArtifactId,\n        config: &Config,\n        dry_run: bool,\n    ) -> Result<Self> {\n        let (path, sensitive_path) = Self::get_paths(config, sig, target, dry_run)?;\n\n        Ok(Self { deployments, path, sensitive_path, timestamp: now().as_millis() })\n    }\n\n    /// Gets paths in the formats\n    /// ./broadcast/multi/contract_filename[-timestamp]/sig.json and\n    /// ./cache/multi/contract_filename[-timestamp]/sig.json\n    pub fn get_paths(\n        config: &Config,\n        sig: &str,\n        target: &ArtifactId,\n        dry_run: bool,\n    ) -> Result<(PathBuf, PathBuf)> {\n        let mut broadcast = config.broadcast.to_path_buf();\n        let mut cache = config.cache_path.to_path_buf();\n        let mut common = PathBuf::new();\n\n        common.push(\"multi\");\n\n        if dry_run {\n            common.push(DRY_RUN_DIR);\n        }\n\n        let target_fname = target\n            .source\n            .file_name()\n            .wrap_err_with(|| format!(\"No filename for {:?}\", target.source))?\n            .to_string_lossy();\n\n        common.push(format!(\"{target_fname}-latest\"));\n\n        broadcast.push(common.clone());\n        cache.push(common);\n\n        fs::create_dir_all(&broadcast)?;\n        fs::create_dir_all(&cache)?;\n\n        let filename = format!(\"{}.json\", sig_to_file_name(sig));\n\n        broadcast.push(filename.clone());\n        cache.push(filename);\n\n        Ok((broadcast, cache))\n    }\n\n    /// Loads the sequences for the multi chain deployment.\n    pub fn load(config: &Config, sig: &str, target: &ArtifactId, dry_run: bool) -> Result<Self>\n    where\n        N::TxEnvelope: for<'d> Deserialize<'d>,\n    {\n        let (path, sensitive_path) = Self::get_paths(config, sig, target, dry_run)?;\n        let mut sequence: Self = foundry_compilers::utils::read_json_file(&path)\n            .wrap_err(\"Multi-chain deployment not found.\")?;\n        let sensitive_sequence: SensitiveMultiChainSequence =\n            foundry_compilers::utils::read_json_file(&sensitive_path)\n                .wrap_err(\"Multi-chain deployment sensitive details not found.\")?;\n\n        sequence.deployments.iter_mut().enumerate().for_each(|(i, sequence)| {\n            sequence.fill_sensitive(&sensitive_sequence.deployments[i]);\n        });\n\n        sequence.path = path;\n        sequence.sensitive_path = sensitive_path;\n\n        Ok(sequence)\n    }\n\n    /// Saves the transactions as file if it's a standalone deployment.\n    pub fn save(&mut self, silent: bool, save_ts: bool) -> Result<()>\n    where\n        N::TxEnvelope: Serialize,\n    {\n        self.deployments.iter_mut().for_each(|sequence| sequence.sort_receipts());\n\n        self.timestamp = now().as_millis();\n\n        let sensitive_sequence = SensitiveMultiChainSequence::from_multi_sequence(&*self);\n\n        // broadcast writes\n        //../Contract-latest/run.json\n        fs::write_pretty_json_file(&self.path, self)?;\n\n        if save_ts {\n            //../Contract-[timestamp]/run.json\n            let path = self.path.to_string_lossy();\n            let file = PathBuf::from(&path.replace(\"-latest\", &format!(\"-{}\", self.timestamp)));\n            fs::create_dir_all(file.parent().unwrap())?;\n            fs::copy(&self.path, &file)?;\n        }\n\n        // cache writes\n        //../Contract-latest/run.json\n        fs::write_pretty_json_file(&self.sensitive_path, &sensitive_sequence)?;\n\n        if save_ts {\n            //../Contract-[timestamp]/run.json\n            let path = self.sensitive_path.to_string_lossy();\n            let file = PathBuf::from(&path.replace(\"-latest\", &format!(\"-{}\", self.timestamp)));\n            fs::create_dir_all(file.parent().unwrap())?;\n            fs::copy(&self.sensitive_path, &file)?;\n        }\n\n        if !silent {\n            if shell::is_json() {\n                sh_println!(\n                    \"{}\",\n                    serde_json::json!({\n                        \"status\": \"success\",\n                        \"transactions\": self.path.display().to_string(),\n                        \"sensitive\": self.sensitive_path.display().to_string(),\n                    })\n                )?;\n            } else {\n                sh_println!(\"\\nTransactions saved to: {}\\n\", self.path.display())?;\n                sh_println!(\"Sensitive details saved to: {}\\n\", self.sensitive_path.display())?;\n            }\n        }\n\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "crates/script/src/progress.rs",
    "content": "use crate::receipts::{PendingReceiptError, TxStatus, check_tx_status, format_receipt};\nuse alloy_chains::Chain;\nuse alloy_network::{Network, ReceiptResponse};\nuse alloy_primitives::{\n    B256,\n    map::{B256HashMap, HashMap},\n};\nuse alloy_provider::RootProvider;\nuse eyre::Result;\nuse forge_script_sequence::ScriptSequence;\nuse foundry_cli::utils::init_progress;\nuse foundry_common::shell;\nuse futures::StreamExt;\nuse indicatif::{MultiProgress, ProgressBar, ProgressStyle};\nuse parking_lot::RwLock;\nuse std::{fmt::Write, sync::Arc, time::Duration};\nuse yansi::Paint;\n\n/// State of [ProgressBar]s displayed for the given [ScriptSequence].\n#[derive(Debug)]\npub struct SequenceProgressState {\n    /// The top spinner with content of the format \"Sequence #{id} on {network} | {status}\"\"\n    top_spinner: ProgressBar,\n    /// Progress bar with the count of transactions.\n    txs: ProgressBar,\n    /// Progress var with the count of confirmed transactions.\n    receipts: ProgressBar,\n    /// Standalone spinners for pending transactions.\n    tx_spinners: B256HashMap<ProgressBar>,\n    /// Copy of the main [MultiProgress] instance.\n    multi: MultiProgress,\n}\n\nimpl SequenceProgressState {\n    pub fn new<N: Network>(\n        sequence_idx: usize,\n        sequence: &ScriptSequence<N>,\n        multi: MultiProgress,\n    ) -> Self {\n        let mut state = if shell::is_quiet() || shell::is_json() {\n            let top_spinner = ProgressBar::hidden();\n            let txs = ProgressBar::hidden();\n            let receipts = ProgressBar::hidden();\n\n            Self { top_spinner, txs, receipts, tx_spinners: Default::default(), multi }\n        } else {\n            let mut template = \"{spinner:.green}\".to_string();\n            write!(template, \" Sequence #{} on {}\", sequence_idx + 1, Chain::from(sequence.chain))\n                .unwrap();\n            template.push_str(\"{msg}\");\n\n            let top_spinner = ProgressBar::new_spinner().with_style(\n                ProgressStyle::with_template(&template).unwrap().tick_chars(\"⠁⠂⠄⡀⢀⠠⠐⠈✅\"),\n            );\n            let top_spinner = multi.add(top_spinner);\n\n            let txs = multi.insert_after(\n                &top_spinner,\n                init_progress(sequence.transactions.len() as u64, \"txes\").with_prefix(\"    \"),\n            );\n\n            let receipts = multi.insert_after(\n                &txs,\n                init_progress(sequence.transactions.len() as u64, \"receipts\").with_prefix(\"    \"),\n            );\n\n            top_spinner.enable_steady_tick(Duration::from_millis(100));\n            txs.enable_steady_tick(Duration::from_millis(1000));\n            receipts.enable_steady_tick(Duration::from_millis(1000));\n\n            txs.set_position(sequence.receipts.len() as u64);\n            receipts.set_position(sequence.receipts.len() as u64);\n\n            Self { top_spinner, txs, receipts, tx_spinners: Default::default(), multi }\n        };\n\n        for tx_hash in &sequence.pending {\n            state.tx_sent(*tx_hash);\n        }\n\n        state\n    }\n\n    /// Called when a new transaction is sent. Displays a spinner with a hash of the transaction and\n    /// advances the sent transactions progress bar.\n    pub fn tx_sent(&mut self, tx_hash: B256) {\n        // Avoid showing more than 10 spinners.\n        if self.tx_spinners.len() < 10 {\n            let spinner = if shell::is_quiet() || shell::is_json() {\n                ProgressBar::hidden()\n            } else {\n                let spinner = ProgressBar::new_spinner()\n                    .with_style(\n                        ProgressStyle::with_template(\"    {spinner:.green} {msg}\")\n                            .unwrap()\n                            .tick_chars(\"⠁⠂⠄⡀⢀⠠⠐⠈\"),\n                    )\n                    .with_message(format!(\"{} {}\", \"[Pending]\".yellow(), tx_hash));\n\n                let spinner = self.multi.insert_before(&self.txs, spinner);\n                spinner.enable_steady_tick(Duration::from_millis(100));\n                spinner\n            };\n\n            self.tx_spinners.insert(tx_hash, spinner);\n        }\n        self.txs.inc(1);\n    }\n\n    /// Removes the pending transaction spinner and advances confirmed transactions progress bar.\n    pub fn finish_tx_spinner(&mut self, tx_hash: B256) {\n        if let Some(spinner) = self.tx_spinners.remove(&tx_hash) {\n            spinner.finish_and_clear();\n        }\n        self.receipts.inc(1);\n    }\n\n    /// Same as finish_tx_spinner but also prints a message to stdout above all other progress bars.\n    pub fn finish_tx_spinner_with_msg(&mut self, tx_hash: B256, msg: &str) -> std::io::Result<()> {\n        self.finish_tx_spinner(tx_hash);\n\n        if !(shell::is_quiet() || shell::is_json()) {\n            self.multi.println(msg)?;\n        }\n\n        Ok(())\n    }\n\n    /// Sets status for the current sequence progress.\n    pub fn set_status(&mut self, status: &str) {\n        self.top_spinner.set_message(format!(\" | {status}\"));\n    }\n\n    /// Hides transactions and receipts progress bar, leaving only top line with the latest set\n    /// status.\n    pub fn finish(&self) {\n        self.top_spinner.finish();\n        self.txs.finish_and_clear();\n        self.receipts.finish_and_clear();\n    }\n}\n\n/// Cloneable wrapper around [SequenceProgressState].\n#[derive(Debug, Clone)]\npub struct SequenceProgress {\n    pub inner: Arc<RwLock<SequenceProgressState>>,\n}\n\nimpl SequenceProgress {\n    pub fn new<N: Network>(\n        sequence_idx: usize,\n        sequence: &ScriptSequence<N>,\n        multi: MultiProgress,\n    ) -> Self {\n        Self {\n            inner: Arc::new(RwLock::new(SequenceProgressState::new(sequence_idx, sequence, multi))),\n        }\n    }\n}\n\n/// Container for multiple [SequenceProgress] instances keyed by sequence index.\n#[derive(Debug, Clone, Default)]\npub struct ScriptProgress {\n    state: Arc<RwLock<HashMap<usize, SequenceProgress>>>,\n    multi: MultiProgress,\n}\n\nimpl ScriptProgress {\n    /// Returns a [SequenceProgress] instance for the given sequence index. If it doesn't exist,\n    /// creates one.\n    pub fn get_sequence_progress<N: Network>(\n        &self,\n        sequence_idx: usize,\n        sequence: &ScriptSequence<N>,\n    ) -> SequenceProgress {\n        if let Some(progress) = self.state.read().get(&sequence_idx) {\n            return progress.clone();\n        }\n        let progress = SequenceProgress::new(sequence_idx, sequence, self.multi.clone());\n        self.state.write().insert(sequence_idx, progress.clone());\n        progress\n    }\n\n    /// Traverses a set of pending transactions and either finds receipts, or clears\n    /// them from the deployment sequence.\n    ///\n    /// For each `tx_hash`, we check if it has confirmed. If it has\n    /// confirmed, we push the receipt (if successful) or push an error (if\n    /// revert). If the transaction has not confirmed, but can be found in the\n    /// node's mempool, we wait for its receipt to be available. If the transaction\n    /// has not confirmed, and cannot be found in the mempool, we remove it from\n    /// the `deploy_sequence.pending` vector so that it will be rebroadcast in\n    /// later steps.\n    pub async fn wait_for_pending<N: Network>(\n        &self,\n        sequence_idx: usize,\n        deployment_sequence: &mut ScriptSequence<N>,\n        provider: &RootProvider<N>,\n        timeout: u64,\n    ) -> Result<()> {\n        if deployment_sequence.pending.is_empty() {\n            return Ok(());\n        }\n\n        let count = deployment_sequence.pending.len();\n        let seq_progress = self.get_sequence_progress(sequence_idx, deployment_sequence);\n\n        seq_progress.inner.write().set_status(\"Waiting for pending transactions\");\n\n        trace!(\"Checking status of {count} pending transactions\");\n\n        let futs = deployment_sequence\n            .pending\n            .clone()\n            .into_iter()\n            .map(|tx| check_tx_status(provider, tx, timeout));\n        let mut tasks = futures::stream::iter(futs).buffer_unordered(10);\n\n        let mut errors: Vec<String> = vec![];\n        let mut discarded_transactions = false;\n\n        while let Some((tx_hash, result)) = tasks.next().await {\n            match result {\n                Err(err) => {\n                    // Check if this is a retry error for pending receipts\n                    if err.downcast_ref::<PendingReceiptError>().is_some() {\n                        // We've already retried several times with sleep, but the receipt is still\n                        // pending\n                        discarded_transactions = true;\n                        deployment_sequence.remove_pending(tx_hash);\n                        seq_progress\n                            .inner\n                            .write()\n                            .finish_tx_spinner_with_msg(tx_hash, &err.to_string())?;\n                    } else {\n                        errors.push(format!(\n                            \"Failure on receiving a receipt for {tx_hash:?}:\\n{err}\"\n                        ));\n                        seq_progress.inner.write().finish_tx_spinner(tx_hash);\n                    }\n                }\n                Ok(TxStatus::Dropped) => {\n                    // We want to remove it from pending so it will be re-broadcast.\n                    deployment_sequence.remove_pending(tx_hash);\n                    discarded_transactions = true;\n\n                    let msg = format!(\n                        \"Transaction {tx_hash:?} dropped from the mempool. It will be retried when using --resume.\"\n                    );\n                    seq_progress.inner.write().finish_tx_spinner_with_msg(tx_hash, &msg)?;\n                }\n                Ok(TxStatus::Success(receipt)) => {\n                    trace!(tx_hash=?tx_hash, \"received tx receipt\");\n\n                    let msg = format_receipt(\n                        deployment_sequence.chain.into(),\n                        &receipt,\n                        Some(deployment_sequence),\n                    );\n                    seq_progress.inner.write().finish_tx_spinner_with_msg(tx_hash, &msg)?;\n\n                    deployment_sequence.remove_pending(receipt.transaction_hash());\n                    deployment_sequence.add_receipt(receipt);\n                }\n                Ok(TxStatus::Revert(receipt)) => {\n                    // consider:\n                    // if this is not removed from pending, then the script becomes\n                    // un-resumable. Is this desirable on reverts?\n                    warn!(tx_hash=?tx_hash, \"Transaction Failure\");\n                    deployment_sequence.remove_pending(receipt.transaction_hash());\n\n                    let msg = format_receipt(\n                        deployment_sequence.chain.into(),\n                        &receipt,\n                        Some(deployment_sequence),\n                    );\n                    seq_progress.inner.write().finish_tx_spinner_with_msg(tx_hash, &msg)?;\n\n                    errors.push(format!(\"Transaction Failure: {:?}\", receipt.transaction_hash()));\n                }\n            }\n        }\n\n        // print any errors\n        if !errors.is_empty() {\n            let mut error_msg = errors.join(\"\\n\");\n\n            // Add information about using --resume if necessary\n            if !deployment_sequence.pending.is_empty() || discarded_transactions {\n                error_msg += r#\"\n\nAdd `--resume` to your command to try and continue broadcasting the transactions. This will attempt to resend transactions that were discarded by the RPC.\"#;\n            }\n\n            eyre::bail!(error_msg);\n        } else if discarded_transactions {\n            // If we have discarded transactions but no errors, still inform the user\n            sh_warn!(\n                \"Some transactions were discarded by the RPC node. Use `--resume` to retry these transactions.\"\n            )?;\n        }\n\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "crates/script/src/providers.rs",
    "content": "use alloy_network::Ethereum;\nuse alloy_primitives::map::{HashMap, hash_map::Entry};\nuse alloy_provider::{Provider, RootProvider, utils::Eip1559Estimation};\nuse eyre::{Result, WrapErr};\nuse foundry_common::provider::ProviderBuilder;\nuse foundry_config::Chain;\nuse std::{ops::Deref, sync::Arc};\n\n/// Contains a map of RPC urls to single instances of [`ProviderInfo`].\n#[derive(Default)]\npub struct ProvidersManager {\n    pub inner: HashMap<String, ProviderInfo>,\n}\n\nimpl ProvidersManager {\n    /// Get or initialize the RPC provider.\n    pub async fn get_or_init_provider(\n        &mut self,\n        rpc: &str,\n        is_legacy: bool,\n    ) -> Result<&ProviderInfo> {\n        Ok(match self.inner.entry(rpc.to_string()) {\n            Entry::Occupied(entry) => entry.into_mut(),\n            Entry::Vacant(entry) => {\n                let info = ProviderInfo::new(rpc, is_legacy).await?;\n                entry.insert(info)\n            }\n        })\n    }\n}\n\nimpl Deref for ProvidersManager {\n    type Target = HashMap<String, ProviderInfo>;\n\n    fn deref(&self) -> &Self::Target {\n        &self.inner\n    }\n}\n\n/// Holds related metadata to each provider RPC.\n#[derive(Debug)]\npub struct ProviderInfo {\n    pub provider: Arc<RootProvider<Ethereum>>,\n    pub chain: u64,\n    pub gas_price: GasPrice,\n}\n\n/// Represents the outcome of a gas price request\n#[derive(Debug)]\npub enum GasPrice {\n    Legacy(Result<u128>),\n    EIP1559(Result<Eip1559Estimation>),\n}\n\nimpl ProviderInfo {\n    pub async fn new(rpc: &str, mut is_legacy: bool) -> Result<Self> {\n        let provider = Arc::new(ProviderBuilder::new(rpc).build()?);\n        let chain = provider.get_chain_id().await?;\n\n        if let Some(chain) = Chain::from(chain).named() {\n            is_legacy |= chain.is_legacy();\n        };\n\n        let gas_price = if is_legacy {\n            GasPrice::Legacy(\n                provider.get_gas_price().await.wrap_err(\"Failed to get legacy gas price\"),\n            )\n        } else {\n            GasPrice::EIP1559(\n                provider.estimate_eip1559_fees().await.wrap_err(\"Failed to get EIP-1559 fees\"),\n            )\n        };\n\n        Ok(Self { provider, chain, gas_price })\n    }\n\n    /// Returns the gas price to use\n    pub fn gas_price(&self) -> Result<u128> {\n        let res = match &self.gas_price {\n            GasPrice::Legacy(res) => res.as_ref(),\n            GasPrice::EIP1559(res) => res.as_ref().map(|res| &res.max_fee_per_gas),\n        };\n        match res {\n            Ok(val) => Ok(*val),\n            Err(err) => Err(eyre::eyre!(\"{}\", err)),\n        }\n    }\n}\n"
  },
  {
    "path": "crates/script/src/receipts.rs",
    "content": "use alloy_chains::{Chain, NamedChain};\nuse alloy_network::{Network, ReceiptResponse};\nuse alloy_primitives::{Address, TxHash, U256, utils::format_units};\nuse alloy_provider::{\n    PendingTransactionBuilder, PendingTransactionError, Provider, RootProvider, WatchTxError,\n};\nuse alloy_rpc_types::TransactionReceipt;\nuse eyre::{Result, eyre};\nuse forge_script_sequence::ScriptSequence;\nuse foundry_common::{retry, retry::RetryError, shell};\nuse std::time::Duration;\n\n/// Helper trait providing `contract_address` setter for generic `ReceiptResponse`\npub trait FoundryReceiptResponse {\n    /// Sets address of the created contract, or `None` if the transaction was not a deployment.\n    fn set_contract_address(&mut self, contract_address: Address);\n}\n\nimpl FoundryReceiptResponse for TransactionReceipt {\n    fn set_contract_address(&mut self, contract_address: Address) {\n        self.contract_address = Some(contract_address);\n    }\n}\n\n/// Marker error type for pending receipts\n#[derive(Debug, thiserror::Error)]\n#[error(\n    \"Received a pending receipt for {tx_hash}, but transaction is still known to the node, retrying\"\n)]\npub struct PendingReceiptError {\n    pub tx_hash: TxHash,\n}\n\n/// Convenience enum for internal signalling of transaction status\npub enum TxStatus<R: ReceiptResponse> {\n    Dropped,\n    Success(R),\n    Revert(R),\n}\n\nimpl<R: ReceiptResponse> From<R> for TxStatus<R> {\n    fn from(receipt: R) -> Self {\n        if !receipt.status() { Self::Revert(receipt) } else { Self::Success(receipt) }\n    }\n}\n\n/// Checks the status of a txhash by first polling for a receipt, then for\n/// mempool inclusion. Returns the tx hash, and a status\npub async fn check_tx_status<N: Network>(\n    provider: &RootProvider<N>,\n    hash: TxHash,\n    timeout: u64,\n) -> (TxHash, Result<TxStatus<N::ReceiptResponse>, eyre::Report>) {\n    let result = retry::Retry::new_no_delay(3)\n        .run_async_until_break(|| async {\n            match PendingTransactionBuilder::new(provider.clone(), hash)\n                .with_timeout(Some(Duration::from_secs(timeout)))\n                .get_receipt()\n                .await\n            {\n                Ok(receipt) => {\n                    // Check if the receipt is pending (missing block information)\n                    let is_pending = receipt.block_number().is_none()\n                        || receipt.block_hash().is_none()\n                        || receipt.transaction_index().is_none();\n\n                    if !is_pending {\n                        return Ok(receipt.into());\n                    }\n\n                    // Receipt is pending, try to sleep and retry a few times\n                    match provider.get_transaction_by_hash(hash).await {\n                        Ok(_) => {\n                            // Sleep for a short time to allow the transaction to be mined\n                            tokio::time::sleep(Duration::from_millis(500)).await;\n                            // Transaction is still known to the node, retry\n                            Err(RetryError::Retry(PendingReceiptError { tx_hash: hash }.into()))\n                        }\n                        Err(_) => {\n                            // Transaction is not known to the node, mark it as dropped\n                            Ok(TxStatus::Dropped)\n                        }\n                    }\n                }\n                Err(e) => match provider.get_transaction_by_hash(hash).await {\n                    Ok(_) => match e {\n                        PendingTransactionError::TxWatcher(WatchTxError::Timeout) => {\n                            Err(RetryError::Continue(eyre!(\n                                \"tx is still known to the node, waiting for receipt\"\n                            )))\n                        }\n                        _ => Err(RetryError::Retry(e.into())),\n                    },\n                    Err(_) => Ok(TxStatus::Dropped),\n                },\n            }\n        })\n        .await;\n\n    (hash, result)\n}\n\n/// Prints parts of the receipt to stdout\npub fn format_receipt<N: Network>(\n    chain: Chain,\n    receipt: &N::ReceiptResponse,\n    sequence: Option<&ScriptSequence<N>>,\n) -> String {\n    let gas_used = receipt.gas_used();\n    let gas_price = receipt.effective_gas_price();\n    let block_number = receipt.block_number().unwrap_or_default();\n    let success = receipt.status();\n\n    let (contract_name, function) = sequence\n        .and_then(|seq| {\n            seq.transactions\n                .iter()\n                .find(|tx| tx.hash == Some(receipt.transaction_hash()))\n                .map(|tx| (tx.contract_name.clone(), tx.function.clone()))\n        })\n        .unwrap_or((None, None));\n\n    if shell::is_json() {\n        let mut json = serde_json::json!({\n            \"chain\": chain,\n            \"status\": if success {\n                \"success\"\n            } else {\n                \"failed\"\n            },\n            \"tx_hash\": receipt.transaction_hash(),\n            \"contract_address\": receipt.contract_address().map(|addr| addr.to_string()),\n            \"block_number\": block_number,\n            \"gas_used\": gas_used,\n            \"gas_price\": gas_price,\n        });\n\n        if let Some(name) = &contract_name\n            && !name.is_empty()\n        {\n            json[\"contract_name\"] = serde_json::Value::String(name.clone());\n        }\n        if let Some(func) = &function\n            && !func.is_empty()\n        {\n            json[\"function\"] = serde_json::Value::String(func.clone());\n        }\n\n        let _ = sh_println!(\"{}\", json);\n\n        String::new()\n    } else {\n        let contract_info = match &contract_name {\n            Some(name) if !name.is_empty() => format!(\"\\nContract: {name}\"),\n            _ => String::new(),\n        };\n\n        let function_info = match &function {\n            Some(func) if !func.is_empty() => format!(\"\\nFunction: {func}\"),\n            _ => String::new(),\n        };\n\n        format!(\n            \"\\n##### {chain}\\n{status} Hash: {tx_hash:?}{contract_info}{function_info}{contract_address}\\nBlock: {block_number}\\n{gas}\\n\\n\",\n            status = if success { \"✅  [Success]\" } else { \"❌  [Failed]\" },\n            tx_hash = receipt.transaction_hash(),\n            contract_address = if let Some(addr) = receipt.contract_address() {\n                format!(\"\\nContract Address: {}\", addr.to_checksum(None))\n            } else {\n                String::new()\n            },\n            gas = if gas_price == 0 {\n                format!(\"Gas Used: {gas_used}\")\n            } else {\n                let paid = format_units((gas_used as u128).saturating_mul(gas_price), 18)\n                    .unwrap_or_else(|_| \"N/A\".into());\n                let gas_price =\n                    format_units(U256::from(gas_price), 9).unwrap_or_else(|_| \"N/A\".into());\n                let token_symbol = NamedChain::try_from(chain)\n                    .unwrap_or_default()\n                    .native_currency_symbol()\n                    .unwrap_or(\"ETH\");\n                format!(\n                    \"Paid: {} {} ({gas_used} gas * {} gwei)\",\n                    paid.trim_end_matches('0'),\n                    token_symbol,\n                    gas_price.trim_end_matches('0').trim_end_matches('.')\n                )\n            },\n        )\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use alloy_network::Ethereum;\n    use alloy_primitives::B256;\n    use std::collections::VecDeque;\n\n    fn mock_receipt(tx_hash: B256, success: bool) -> TransactionReceipt {\n        serde_json::from_value(serde_json::json!({\n            \"type\": \"0x02\", \"status\": if success { \"0x1\" } else { \"0x0\" },\n            \"cumulativeGasUsed\": \"0x5208\", \"logs\": [], \"transactionHash\": tx_hash,\n            \"logsBloom\": format!(\"0x{}\", \"0\".repeat(512)),\n            \"transactionIndex\": \"0x0\", \"blockHash\": B256::ZERO, \"blockNumber\": \"0x3039\",\n            \"gasUsed\": \"0x5208\", \"effectiveGasPrice\": \"0x4a817c800\",\n            \"from\": \"0x0000000000000000000000000000000000000000\",\n            \"to\": \"0x0000000000000000000000000000000000000000\", \"contractAddress\": null\n        }))\n        .unwrap()\n    }\n\n    fn mock_sequence(\n        tx_hash: B256,\n        contract: Option<&str>,\n        func: Option<&str>,\n    ) -> ScriptSequence<Ethereum> {\n        let tx = serde_json::from_value(serde_json::json!({\n            \"hash\": tx_hash, \"transactionType\": \"CALL\",\n            \"contractName\": contract, \"contractAddress\": null, \"function\": func,\n            \"arguments\": null, \"additionalContracts\": [], \"isFixedGasLimit\": false,\n            \"transaction\": {\n                \"type\": \"0x02\", \"chainId\": \"0x1\", \"nonce\": \"0x0\", \"gas\": \"0x5208\",\n                \"maxFeePerGas\": \"0x4a817c800\", \"maxPriorityFeePerGas\": \"0x3b9aca00\",\n                \"to\": \"0x0000000000000000000000000000000000000000\",\n                \"value\": \"0x0\", \"input\": \"0x\", \"accessList\": []\n            },\n        }))\n        .unwrap();\n        ScriptSequence { transactions: VecDeque::from([tx]), chain: 1, ..Default::default() }\n    }\n\n    #[test]\n    fn format_receipt_displays_contract_and_function() {\n        let hash = B256::repeat_byte(0x42);\n        let seq = mock_sequence(hash, Some(\"MyContract\"), Some(\"init(address)\"));\n        let out = format_receipt(Chain::mainnet(), &mock_receipt(hash, true), Some(&seq));\n\n        assert!(out.contains(\"Contract: MyContract\"));\n        assert!(out.contains(\"Function: init(address)\"));\n        assert!(out.contains(\"✅  [Success]\"));\n    }\n\n    #[test]\n    fn format_receipt_without_sequence_omits_metadata() {\n        let hash = B256::repeat_byte(0x42);\n        let out = format_receipt::<Ethereum>(Chain::mainnet(), &mock_receipt(hash, true), None);\n\n        assert!(!out.contains(\"Contract:\"));\n        assert!(!out.contains(\"Function:\"));\n    }\n\n    #[test]\n    fn format_receipt_skips_empty_contract_name() {\n        let hash = B256::repeat_byte(0x42);\n        let seq = mock_sequence(hash, Some(\"\"), Some(\"transfer(address)\"));\n        let out = format_receipt(Chain::mainnet(), &mock_receipt(hash, true), Some(&seq));\n\n        assert!(!out.contains(\"Contract:\"));\n        assert!(out.contains(\"Function: transfer(address)\"));\n    }\n\n    #[test]\n    fn format_receipt_handles_missing_tx_in_sequence() {\n        let seq = mock_sequence(B256::repeat_byte(0x99), Some(\"Other\"), Some(\"other()\"));\n        let out = format_receipt(\n            Chain::mainnet(),\n            &mock_receipt(B256::repeat_byte(0x42), true),\n            Some(&seq),\n        );\n\n        assert!(!out.contains(\"Contract:\"));\n        assert!(!out.contains(\"Function:\"));\n    }\n\n    #[test]\n    fn format_receipt_shows_contract_on_failure() {\n        let hash = B256::repeat_byte(0x42);\n        let seq = mock_sequence(hash, Some(\"FailContract\"), Some(\"fail()\"));\n        let out = format_receipt(Chain::mainnet(), &mock_receipt(hash, false), Some(&seq));\n\n        assert!(out.contains(\"❌  [Failed]\"));\n        assert!(out.contains(\"Contract: FailContract\"));\n    }\n}\n"
  },
  {
    "path": "crates/script/src/runner.rs",
    "content": "use super::{ScriptConfig, ScriptResult};\nuse crate::build::ScriptPredeployLibraries;\nuse alloy_eips::eip7702::SignedAuthorization;\nuse alloy_primitives::{Address, Bytes, TxKind, U256};\nuse eyre::Result;\nuse foundry_cheatcodes::{BroadcastKind, BroadcastableTransaction};\nuse foundry_config::Config;\nuse foundry_evm::{\n    constants::CALLER,\n    executors::{DeployResult, EvmError, ExecutionErr, Executor, RawCallResult},\n    opts::EvmOpts,\n    revm::interpreter::{InstructionResult, return_ok},\n    traces::{TraceKind, Traces},\n};\nuse std::collections::VecDeque;\n\n/// Drives script execution\n#[derive(Debug)]\npub struct ScriptRunner {\n    pub executor: Executor,\n    pub evm_opts: EvmOpts,\n}\n\nimpl ScriptRunner {\n    pub fn new(executor: Executor, evm_opts: EvmOpts) -> Self {\n        Self { executor, evm_opts }\n    }\n\n    /// Deploys the libraries and broadcast contract. Calls setUp method if requested.\n    pub fn setup(\n        &mut self,\n        libraries: &ScriptPredeployLibraries,\n        code: Bytes,\n        setup: bool,\n        script_config: &ScriptConfig,\n        is_broadcast: bool,\n    ) -> Result<(Address, ScriptResult)> {\n        trace!(target: \"script\", \"executing setUP()\");\n\n        if !is_broadcast {\n            if self.evm_opts.sender == Config::DEFAULT_SENDER {\n                // We max out their balance so that they can deploy and make calls.\n                self.executor.set_balance(self.evm_opts.sender, U256::MAX)?;\n            }\n\n            if script_config.evm_opts.fork_url.is_none() {\n                self.executor.deploy_create2_deployer()?;\n            }\n        }\n\n        let sender_nonce = script_config.sender_nonce;\n        self.executor.set_nonce(self.evm_opts.sender, sender_nonce)?;\n\n        // We max out their balance so that they can deploy and make calls.\n        self.executor.set_balance(CALLER, U256::MAX)?;\n\n        let mut library_transactions = VecDeque::new();\n        let mut traces = Traces::default();\n\n        // Deploy libraries\n        match libraries {\n            ScriptPredeployLibraries::Default(libraries) => libraries.iter().for_each(|code| {\n                let result = self\n                    .executor\n                    .deploy(self.evm_opts.sender, code.clone(), U256::ZERO, None)\n                    .expect(\"couldn't deploy library\")\n                    .raw;\n\n                if let Some(deploy_traces) = result.traces {\n                    traces.push((TraceKind::Deployment, deploy_traces));\n                }\n\n                library_transactions.push_back(BroadcastableTransaction {\n                    rpc: self.evm_opts.fork_url.clone(),\n                    from: self.evm_opts.sender,\n                    to: None,\n                    value: U256::ZERO,\n                    input: code.clone(),\n                    nonce: sender_nonce + library_transactions.len() as u64,\n                    gas: None,\n                    kind: BroadcastKind::unsigned(),\n                })\n            }),\n            ScriptPredeployLibraries::Create2(libraries, salt) => {\n                let create2_deployer = self.executor.create2_deployer();\n                for library in libraries {\n                    let address = create2_deployer.create2_from_code(salt, library.as_ref());\n                    // Skip if already deployed\n                    if !self.executor.is_empty_code(address)? {\n                        continue;\n                    }\n                    let calldata = [salt.as_ref(), library.as_ref()].concat();\n                    let result = self\n                        .executor\n                        .transact_raw(\n                            self.evm_opts.sender,\n                            create2_deployer,\n                            calldata.clone().into(),\n                            U256::from(0),\n                        )\n                        .expect(\"couldn't deploy library\");\n\n                    if let Some(deploy_traces) = result.traces {\n                        traces.push((TraceKind::Deployment, deploy_traces));\n                    }\n\n                    library_transactions.push_back(BroadcastableTransaction {\n                        rpc: self.evm_opts.fork_url.clone(),\n                        from: self.evm_opts.sender,\n                        to: Some(TxKind::Call(create2_deployer)),\n                        value: U256::ZERO,\n                        input: calldata.into(),\n                        nonce: sender_nonce + library_transactions.len() as u64,\n                        gas: None,\n                        kind: BroadcastKind::Unsigned {\n                            chain_id: None,\n                            blob_sidecar: None,\n                            authorization_list: None,\n                        },\n                    });\n                }\n\n                // Sender nonce is not incremented when performing CALLs. We need to manually\n                // increase it.\n                self.executor.set_nonce(\n                    self.evm_opts.sender,\n                    sender_nonce + library_transactions.len() as u64,\n                )?;\n            }\n        };\n\n        let address = CALLER.create(self.executor.get_nonce(CALLER)?);\n\n        // Set the contracts initial balance before deployment, so it is available during the\n        // construction\n        self.executor.set_balance(address, self.evm_opts.initial_balance)?;\n\n        // HACK: if the current sender is the default script sender (which is a default value), we\n        // set its nonce to a very large value before deploying the script contract. This\n        // ensures that the nonce increase during this CREATE does not affect deployment\n        // addresses of contracts that are deployed in the script, Otherwise, we'd have a\n        // nonce mismatch during script execution and onchain simulation, potentially\n        // resulting in weird errors like <https://github.com/foundry-rs/foundry/issues/8960>.\n        let prev_sender_nonce = self.executor.get_nonce(self.evm_opts.sender)?;\n        if self.evm_opts.sender == CALLER {\n            self.executor.set_nonce(self.evm_opts.sender, u64::MAX / 2)?;\n        }\n\n        // Deploy an instance of the contract\n        let DeployResult {\n            address,\n            raw: RawCallResult { mut logs, traces: constructor_traces, .. },\n        } = self\n            .executor\n            .deploy(CALLER, code, U256::ZERO, None)\n            .map_err(|err| eyre::eyre!(\"Failed to deploy script:\\n{}\", err))?;\n\n        if self.evm_opts.sender == CALLER {\n            self.executor.set_nonce(self.evm_opts.sender, prev_sender_nonce)?;\n        }\n\n        // set script address to be used by execution inspector\n        if script_config.config.script_execution_protection {\n            self.executor.set_script_execution(address);\n        }\n\n        traces.extend(constructor_traces.map(|traces| (TraceKind::Deployment, traces)));\n\n        // Optionally call the `setUp` function\n        let (success, gas_used, labeled_addresses, transactions) = if !setup {\n            self.executor.backend_mut().set_test_contract(address);\n            (true, 0, Default::default(), Some(library_transactions))\n        } else {\n            match self.executor.setup(Some(self.evm_opts.sender), address, None) {\n                Ok(RawCallResult {\n                    reverted,\n                    traces: setup_traces,\n                    labels,\n                    logs: setup_logs,\n                    gas_used,\n                    transactions: setup_transactions,\n                    ..\n                }) => {\n                    traces.extend(setup_traces.map(|traces| (TraceKind::Setup, traces)));\n                    logs.extend_from_slice(&setup_logs);\n\n                    if let Some(txs) = setup_transactions {\n                        library_transactions.extend(txs);\n                    }\n\n                    (!reverted, gas_used, labels, Some(library_transactions))\n                }\n                Err(EvmError::Execution(err)) => {\n                    let RawCallResult {\n                        reverted,\n                        traces: setup_traces,\n                        labels,\n                        logs: setup_logs,\n                        gas_used,\n                        transactions,\n                        ..\n                    } = err.raw;\n                    traces.extend(setup_traces.map(|traces| (TraceKind::Setup, traces)));\n                    logs.extend_from_slice(&setup_logs);\n\n                    if let Some(txs) = transactions {\n                        library_transactions.extend(txs);\n                    }\n\n                    (!reverted, gas_used, labels, Some(library_transactions))\n                }\n                Err(e) => return Err(e.into()),\n            }\n        };\n\n        Ok((\n            address,\n            ScriptResult {\n                returned: Bytes::new(),\n                success,\n                gas_used,\n                labeled_addresses,\n                transactions,\n                logs,\n                traces,\n                address: None,\n                ..Default::default()\n            },\n        ))\n    }\n\n    /// Executes the method that will collect all broadcastable transactions.\n    pub fn script(&mut self, address: Address, calldata: Bytes) -> Result<ScriptResult> {\n        self.call(self.evm_opts.sender, address, calldata, U256::ZERO, None, false)\n    }\n\n    /// Runs a broadcastable transaction locally and persists its state.\n    pub fn simulate(\n        &mut self,\n        from: Address,\n        to: Option<Address>,\n        calldata: Option<Bytes>,\n        value: Option<U256>,\n        authorization_list: Option<Vec<SignedAuthorization>>,\n    ) -> Result<ScriptResult> {\n        if let Some(to) = to {\n            self.call(\n                from,\n                to,\n                calldata.unwrap_or_default(),\n                value.unwrap_or(U256::ZERO),\n                authorization_list,\n                true,\n            )\n        } else {\n            let res = self.executor.deploy(\n                from,\n                calldata.expect(\"No data for create transaction\"),\n                value.unwrap_or(U256::ZERO),\n                None,\n            );\n            let (address, RawCallResult { gas_used, logs, traces, .. }) = match res {\n                Ok(DeployResult { address, raw }) => (address, raw),\n                Err(EvmError::Execution(err)) => {\n                    let ExecutionErr { raw, reason } = *err;\n                    sh_err!(\"Failed with `{reason}`:\\n\")?;\n                    (Address::ZERO, raw)\n                }\n                Err(e) => eyre::bail!(\"Failed deploying contract: {e:?}\"),\n            };\n\n            Ok(ScriptResult {\n                returned: Bytes::new(),\n                success: address != Address::ZERO,\n                gas_used,\n                logs,\n                // Manually adjust gas for the trace to add back the stipend/real used gas\n                traces: traces\n                    .map(|traces| vec![(TraceKind::Execution, traces)])\n                    .unwrap_or_default(),\n                address: Some(address),\n                ..Default::default()\n            })\n        }\n    }\n\n    /// Executes the call\n    ///\n    /// This will commit the changes if `commit` is true.\n    ///\n    /// This will return _estimated_ gas instead of the precise gas the call would consume, so it\n    /// can be used as `gas_limit`.\n    fn call(\n        &mut self,\n        from: Address,\n        to: Address,\n        calldata: Bytes,\n        value: U256,\n        authorization_list: Option<Vec<SignedAuthorization>>,\n        commit: bool,\n    ) -> Result<ScriptResult> {\n        let mut res = if let Some(authorization_list) = &authorization_list {\n            self.executor.call_raw_with_authorization(\n                from,\n                to,\n                calldata.clone(),\n                value,\n                authorization_list.clone(),\n            )?\n        } else {\n            self.executor.call_raw(from, to, calldata.clone(), value)?\n        };\n        let mut gas_used = res.gas_used;\n\n        // We should only need to calculate realistic gas costs when preparing to broadcast\n        // something. This happens during the onchain simulation stage, where we commit each\n        // collected transactions.\n        //\n        // Otherwise don't re-execute, or some usecases might be broken: https://github.com/foundry-rs/foundry/issues/3921\n        if commit {\n            gas_used = self.search_optimal_gas_usage(&res, from, to, &calldata, value)?;\n            res = if let Some(authorization_list) = authorization_list {\n                self.executor.transact_raw_with_authorization(\n                    from,\n                    to,\n                    calldata,\n                    value,\n                    authorization_list,\n                )?\n            } else {\n                self.executor.transact_raw(from, to, calldata, value)?\n            }\n        }\n\n        let RawCallResult { result, reverted, logs, traces, labels, transactions, .. } = res;\n        let breakpoints = res.cheatcodes.map(|cheats| cheats.breakpoints).unwrap_or_default();\n\n        Ok(ScriptResult {\n            returned: result,\n            success: !reverted,\n            gas_used,\n            logs,\n            traces: traces\n                .map(|traces| {\n                    // Manually adjust gas for the trace to add back the stipend/real used gas\n\n                    vec![(TraceKind::Execution, traces)]\n                })\n                .unwrap_or_default(),\n            labeled_addresses: labels,\n            transactions,\n            address: None,\n            breakpoints,\n        })\n    }\n\n    /// The executor will return the _exact_ gas value this transaction consumed, setting this value\n    /// as gas limit will result in `OutOfGas` so to come up with a better estimate we search over a\n    /// possible range we pick a higher gas limit 3x of a succeeded call should be safe.\n    ///\n    /// This might result in executing the same script multiple times. Depending on the user's goal,\n    /// it might be problematic when using `ffi`.\n    fn search_optimal_gas_usage(\n        &mut self,\n        res: &RawCallResult,\n        from: Address,\n        to: Address,\n        calldata: &Bytes,\n        value: U256,\n    ) -> Result<u64> {\n        let mut gas_used = res.gas_used;\n        if matches!(res.exit_reason, Some(return_ok!())) {\n            // Store the current gas limit and reset it later.\n            let init_gas_limit = self.executor.tx_env().gas_limit;\n\n            let mut highest_gas_limit = gas_used * 3;\n            let mut lowest_gas_limit = gas_used;\n            let mut last_highest_gas_limit = highest_gas_limit;\n            while (highest_gas_limit - lowest_gas_limit) > 1 {\n                let mid_gas_limit = (highest_gas_limit + lowest_gas_limit) / 2;\n                self.executor.tx_env_mut().gas_limit = mid_gas_limit;\n                let res = self.executor.call_raw(from, to, calldata.0.clone().into(), value)?;\n                match res.exit_reason {\n                    Some(InstructionResult::Revert)\n                    | Some(InstructionResult::OutOfGas)\n                    | Some(InstructionResult::OutOfFunds) => {\n                        lowest_gas_limit = mid_gas_limit;\n                    }\n                    _ => {\n                        highest_gas_limit = mid_gas_limit;\n                        // if last two successful estimations only vary by 10%, we consider this to\n                        // sufficiently accurate\n                        const ACCURACY: u64 = 10;\n                        if (last_highest_gas_limit - highest_gas_limit) * ACCURACY\n                            / last_highest_gas_limit\n                            < 1\n                        {\n                            // update the gas\n                            gas_used = highest_gas_limit;\n                            break;\n                        }\n                        last_highest_gas_limit = highest_gas_limit;\n                    }\n                }\n            }\n            // Reset gas limit in the executor.\n            self.executor.tx_env_mut().gas_limit = init_gas_limit;\n        }\n        Ok(gas_used)\n    }\n}\n"
  },
  {
    "path": "crates/script/src/sequence.rs",
    "content": "use crate::multi_sequence::MultiChainSequence;\nuse alloy_network::Network;\nuse eyre::Result;\nuse forge_script_sequence::{ScriptSequence, TransactionWithMetadata};\nuse foundry_cli::utils::Git;\nuse foundry_common::fmt::UIfmt;\nuse foundry_compilers::ArtifactId;\nuse foundry_config::Config;\nuse foundry_primitives::FoundryTransactionBuilder;\nuse serde::{Deserialize, Serialize};\nuse std::{\n    fmt::{Error, Write},\n    path::Path,\n};\n\n/// Format transaction details for display\nfn format_transaction<N: Network>(\n    index: usize,\n    tx: &TransactionWithMetadata<N>,\n) -> Result<String, Error>\nwhere\n    N::TxEnvelope: UIfmt,\n    N::TransactionRequest: FoundryTransactionBuilder<N>,\n{\n    let mut output = String::new();\n    writeln!(output, \"### Transaction {index} ###\")?;\n    writeln!(output, \"{}\", tx.tx().pretty())?;\n\n    // Show contract name and address if available\n    if !tx.opcode.is_any_create()\n        && let (Some(name), Some(addr)) = (&tx.contract_name, &tx.contract_address)\n    {\n        writeln!(output, \"contract: {name}({addr})\")?;\n    }\n\n    // Show decoded function if available\n    if let (Some(func), Some(args)) = (&tx.function, &tx.arguments) {\n        if args.is_empty() {\n            writeln!(output, \"data (decoded): {func}()\")?;\n        } else {\n            writeln!(output, \"data (decoded): {func}(\")?;\n            for (i, arg) in args.iter().enumerate() {\n                writeln!(&mut output, \"  {}{}\", arg, if i + 1 < args.len() { \",\" } else { \"\" })?;\n            }\n            writeln!(output, \")\")?;\n        }\n    }\n\n    writeln!(output)?;\n    Ok(output)\n}\n\n/// Returns the commit hash of the project if it exists\npub fn get_commit_hash(root: &Path) -> Option<String> {\n    Git::new(root).commit_hash(true, \"HEAD\").ok()\n}\n\npub enum ScriptSequenceKind<N: Network>\nwhere\n    N::TxEnvelope: for<'d> Deserialize<'d> + Serialize,\n    N::TransactionRequest: for<'d> Deserialize<'d> + Serialize,\n{\n    Single(ScriptSequence<N>),\n    Multi(MultiChainSequence<N>),\n}\n\nimpl<N: Network> ScriptSequenceKind<N>\nwhere\n    N::TxEnvelope: for<'d> Deserialize<'d> + Serialize,\n    N::TransactionRequest: for<'d> Deserialize<'d> + Serialize,\n{\n    pub fn save(&mut self, silent: bool, save_ts: bool) -> Result<()> {\n        match self {\n            Self::Single(sequence) => sequence.save(silent, save_ts),\n            Self::Multi(sequence) => sequence.save(silent, save_ts),\n        }\n    }\n\n    pub fn sequences(&self) -> &[ScriptSequence<N>] {\n        match self {\n            Self::Single(sequence) => std::slice::from_ref(sequence),\n            Self::Multi(sequence) => &sequence.deployments,\n        }\n    }\n\n    pub fn sequences_mut(&mut self) -> &mut [ScriptSequence<N>] {\n        match self {\n            Self::Single(sequence) => std::slice::from_mut(sequence),\n            Self::Multi(sequence) => &mut sequence.deployments,\n        }\n    }\n    /// Updates underlying sequence paths to not be under /dry-run directory.\n    pub fn update_paths_to_broadcasted(\n        &mut self,\n        config: &Config,\n        sig: &str,\n        target: &ArtifactId,\n    ) -> Result<()> {\n        match self {\n            Self::Single(sequence) => {\n                sequence.paths = Some(ScriptSequence::<N>::get_paths(\n                    config,\n                    sig,\n                    target,\n                    sequence.chain,\n                    false,\n                )?);\n            }\n            Self::Multi(sequence) => {\n                (sequence.path, sequence.sensitive_path) =\n                    MultiChainSequence::<N>::get_paths(config, sig, target, false)?;\n            }\n        };\n\n        Ok(())\n    }\n\n    pub fn show_transactions(&self) -> Result<()>\n    where\n        N::TxEnvelope: UIfmt,\n        N::TransactionRequest: FoundryTransactionBuilder<N>,\n    {\n        for sequence in self.sequences() {\n            if !sequence.transactions.is_empty() {\n                sh_println!(\"\\nChain {}\\n\", sequence.chain)?;\n\n                for (i, tx) in sequence.transactions.iter().enumerate() {\n                    sh_print!(\"{}\", format_transaction(i + 1, tx)?)?;\n                }\n            }\n        }\n\n        Ok(())\n    }\n}\n\nimpl<N: Network> Drop for ScriptSequenceKind<N>\nwhere\n    N::TxEnvelope: for<'d> Deserialize<'d> + Serialize,\n    N::TransactionRequest: for<'d> Deserialize<'d> + Serialize,\n{\n    fn drop(&mut self) {\n        if let Err(err) = self.save(false, true) {\n            error!(?err, \"could not save deployment sequence\");\n        }\n    }\n}\n"
  },
  {
    "path": "crates/script/src/simulate.rs",
    "content": "use super::{\n    multi_sequence::MultiChainSequence, providers::ProvidersManager, runner::ScriptRunner,\n    sequence::ScriptSequenceKind, transaction::ScriptTransactionBuilder,\n};\nuse crate::{\n    ScriptArgs, ScriptConfig, ScriptResult,\n    broadcast::{BundledState, estimate_gas},\n    build::LinkedBuildData,\n    execute::{ExecutionArtifacts, ExecutionData},\n    sequence::get_commit_hash,\n};\nuse alloy_chains::NamedChain;\nuse alloy_consensus::TxEnvelope;\nuse alloy_network::{Ethereum, Network, TransactionBuilder, eip2718::Decodable2718};\nuse alloy_primitives::{Address, TxKind, U256, map::HashMap, utils::format_units};\nuse alloy_rpc_types::request::{TransactionInput, TransactionRequest};\nuse dialoguer::Confirm;\nuse eyre::{Context, Result};\nuse forge_script_sequence::{ScriptSequence, TransactionWithMetadata};\nuse foundry_cheatcodes::{BroadcastKind, BroadcastableTransaction, Wallets};\nuse foundry_cli::utils::{has_different_gas_calc, now};\nuse foundry_common::{ContractData, TransactionMaybeSigned, shell};\nuse foundry_evm::traces::{decode_trace_arena, render_trace_arena};\nuse foundry_primitives::FoundryTransactionBuilder;\nuse foundry_wallets::wallet_browser::signer::BrowserSigner;\nuse futures::future::{join_all, try_join_all};\nuse parking_lot::RwLock;\nuse std::{\n    collections::{BTreeMap, VecDeque},\n    mem,\n    sync::Arc,\n};\n\n/// Same as [ExecutedState](crate::execute::ExecutedState), but also contains [ExecutionArtifacts]\n/// which are obtained from [ScriptResult].\n///\n/// Can be either converted directly to [BundledState] or driven to it through\n/// [FilledTransactionsState].\npub struct PreSimulationState {\n    pub args: ScriptArgs,\n    pub script_config: ScriptConfig,\n    pub script_wallets: Wallets,\n    pub browser_wallet: Option<BrowserSigner<Ethereum>>,\n    pub build_data: LinkedBuildData,\n    pub execution_data: ExecutionData,\n    pub execution_result: ScriptResult,\n    pub execution_artifacts: ExecutionArtifacts,\n}\n\nimpl PreSimulationState {\n    /// If simulation is enabled, simulates transactions against fork and fills gas estimation and\n    /// metadata. Otherwise, metadata (e.g. additional contracts, created contract names) is\n    /// left empty.\n    ///\n    /// Both modes will panic if any of the transactions have None for the `rpc` field.\n    pub async fn fill_metadata(self) -> Result<FilledTransactionsState> {\n        let address_to_abi = self.build_address_to_abi_map();\n\n        let mut transactions = self\n            .execution_result\n            .transactions\n            .clone()\n            .unwrap_or_default()\n            .into_iter()\n            .map(|tx| {\n                let rpc = tx.rpc.clone().expect(\"missing broadcastable tx rpc url\");\n                let sender = tx.from;\n                let nonce = tx.nonce;\n                let to = tx.to;\n\n                let maybe_signed = into_maybe_signed(tx);\n                let mut builder = ScriptTransactionBuilder::new(maybe_signed, rpc);\n\n                if let Some(TxKind::Call(_)) = to {\n                    builder.set_call(\n                        &address_to_abi,\n                        &self.execution_artifacts.decoder,\n                        self.script_config.evm_opts.create2_deployer,\n                    )?;\n                } else {\n                    builder.set_create(false, sender.create(nonce), &address_to_abi)?;\n                }\n\n                Ok(builder.build())\n            })\n            .collect::<Result<VecDeque<_>>>()?;\n\n        if self.args.skip_simulation {\n            sh_println!(\"\\nSKIPPING ON CHAIN SIMULATION.\")?;\n        } else {\n            transactions = self.simulate_and_fill(transactions).await?;\n        }\n\n        Ok(FilledTransactionsState {\n            args: self.args,\n            script_config: self.script_config,\n            script_wallets: self.script_wallets,\n            browser_wallet: self.browser_wallet,\n            build_data: self.build_data,\n            execution_artifacts: self.execution_artifacts,\n            transactions,\n        })\n    }\n\n    /// Builds separate runners and environments for each RPC used in script and executes all\n    /// transactions in those environments.\n    ///\n    /// Collects gas usage and metadata for each transaction.\n    pub async fn simulate_and_fill<N: Network>(\n        &self,\n        transactions: VecDeque<TransactionWithMetadata<N>>,\n    ) -> Result<VecDeque<TransactionWithMetadata<N>>>\n    where\n        N::TransactionRequest: FoundryTransactionBuilder<N>,\n    {\n        trace!(target: \"script\", \"executing onchain simulation\");\n\n        let runners = Arc::new(\n            self.build_runners()\n                .await?\n                .into_iter()\n                .map(|(rpc, runner)| (rpc, Arc::new(RwLock::new(runner))))\n                .collect::<HashMap<_, _>>(),\n        );\n\n        let mut final_txs = VecDeque::new();\n\n        // Executes all transactions from the different forks concurrently.\n        let futs = transactions\n            .into_iter()\n            .map(|mut transaction| async {\n                let mut runner = runners.get(&transaction.rpc).expect(\"invalid rpc url\").write();\n                let tx = transaction.tx_mut();\n\n                let to = if let Some(TxKind::Call(to)) = tx.to() { Some(to) } else { None };\n                let result = runner\n                    .simulate(\n                        tx.from()\n                            .expect(\"transaction doesn't have a `from` address at execution time\"),\n                        to,\n                        tx.input().cloned(),\n                        tx.value(),\n                        tx.authorization_list(),\n                    )\n                    .wrap_err(\"Internal EVM error during simulation\")?;\n\n                if !result.success {\n                    return Ok((None, false, result.traces));\n                }\n\n                // Simulate mining the transaction if the user passes `--slow`.\n                if self.args.slow {\n                    runner.executor.evm_env_mut().block_env.number += U256::from(1);\n                }\n\n                let is_noop_tx = if let Some(to) = to {\n                    runner.executor.is_empty_code(to)? && tx.value().unwrap_or_default().is_zero()\n                } else {\n                    false\n                };\n\n                let transaction = ScriptTransactionBuilder::from(transaction)\n                    .with_execution_result(\n                        &result,\n                        self.args.gas_estimate_multiplier,\n                        &self.build_data,\n                    )\n                    .build();\n\n                eyre::Ok((Some(transaction), is_noop_tx, result.traces))\n            })\n            .collect::<Vec<_>>();\n\n        if !shell::is_json() && self.script_config.evm_opts.verbosity > 3 {\n            sh_println!(\"==========================\")?;\n            sh_println!(\"Simulated On-chain Traces:\\n\")?;\n        }\n\n        let mut abort = false;\n        for res in join_all(futs).await {\n            let (tx, is_noop_tx, mut traces) = res?;\n\n            // Transaction will be `None`, if execution didn't pass.\n            if tx.is_none() || self.script_config.evm_opts.verbosity > 3 {\n                for (_, trace) in &mut traces {\n                    decode_trace_arena(trace, &self.execution_artifacts.decoder).await;\n                    sh_println!(\"{}\", render_trace_arena(trace))?;\n                }\n            }\n\n            if let Some(tx) = tx {\n                if is_noop_tx {\n                    let to = tx.contract_address.unwrap();\n                    sh_warn!(\n                        \"Script contains a transaction to {to} which does not contain any code.\"\n                    )?;\n\n                    // Only prompt if we're broadcasting and we've not disabled interactivity.\n                    if self.args.should_broadcast()\n                        && !self.args.non_interactive\n                        && !Confirm::new()\n                            .with_prompt(\"Do you wish to continue?\".to_string())\n                            .interact()?\n                    {\n                        eyre::bail!(\"User canceled the script.\");\n                    }\n                }\n\n                final_txs.push_back(tx);\n            } else {\n                abort = true;\n            }\n        }\n\n        if abort {\n            eyre::bail!(\"Simulated execution failed.\")\n        }\n\n        Ok(final_txs)\n    }\n\n    /// Build mapping from contract address to its ABI, code and contract name.\n    fn build_address_to_abi_map(&self) -> BTreeMap<Address, &ContractData> {\n        self.execution_artifacts\n            .decoder\n            .contracts\n            .iter()\n            .filter_map(move |(addr, contract_id)| {\n                if let Ok(Some((_, data))) =\n                    self.build_data.known_contracts.find_by_name_or_identifier(contract_id)\n                {\n                    return Some((*addr, data));\n                }\n                None\n            })\n            .collect()\n    }\n\n    /// Build [ScriptRunner] forking given RPC for each RPC used in the script.\n    async fn build_runners(&self) -> Result<Vec<(String, ScriptRunner)>> {\n        let rpcs = self.execution_artifacts.rpc_data.total_rpcs.clone();\n\n        if !shell::is_json() {\n            let n = rpcs.len();\n            let s = if n != 1 { \"s\" } else { \"\" };\n            sh_println!(\"\\n## Setting up {n} EVM{s}.\")?;\n        }\n\n        let futs = rpcs.into_iter().map(|rpc| async move {\n            let mut script_config = self.script_config.clone();\n            script_config.evm_opts.fork_url = Some(rpc.clone());\n            let runner = script_config.get_runner().await?;\n            Ok((rpc, runner))\n        });\n        try_join_all(futs).await\n    }\n}\n\n/// At this point we have converted transactions collected during script execution to\n/// [TransactionWithMetadata] objects which contain additional metadata needed for broadcasting and\n/// verification.\npub struct FilledTransactionsState {\n    pub args: ScriptArgs,\n    pub script_config: ScriptConfig,\n    pub script_wallets: Wallets,\n    pub browser_wallet: Option<BrowserSigner<Ethereum>>,\n    pub build_data: LinkedBuildData,\n    pub execution_artifacts: ExecutionArtifacts,\n    pub transactions: VecDeque<TransactionWithMetadata<Ethereum>>,\n}\n\nimpl FilledTransactionsState {\n    /// Bundles all transactions of the [`TransactionWithMetadata`] type in a list of\n    /// [`ScriptSequence`]. List length will be higher than 1, if we're dealing with a multi\n    /// chain deployment.\n    ///\n    /// Each transaction will be added with the correct transaction type and gas estimation.\n    pub async fn bundle(mut self) -> Result<BundledState<Ethereum>> {\n        let is_multi_deployment = self.execution_artifacts.rpc_data.total_rpcs.len() > 1;\n\n        if is_multi_deployment && !self.build_data.libraries.is_empty() {\n            eyre::bail!(\"Multi-chain deployment is not supported with libraries.\");\n        }\n\n        let mut total_gas_per_rpc: HashMap<String, u128> = HashMap::default();\n\n        // Batches sequence of transactions from different rpcs.\n        let mut new_sequence = VecDeque::new();\n        let mut manager = ProvidersManager::default();\n        let mut sequences = vec![];\n\n        // Peeking is used to check if the next rpc url is different. If so, it creates a\n        // [`ScriptSequence`] from all the collected transactions up to this point.\n        let mut txes_iter = mem::take(&mut self.transactions).into_iter().peekable();\n\n        while let Some(mut tx) = txes_iter.next() {\n            let tx_rpc = tx.rpc.to_owned();\n            let provider_info = manager.get_or_init_provider(&tx.rpc, self.args.legacy).await?;\n\n            if let Some(tx) = tx.tx_mut().as_unsigned_mut() {\n                // Handles chain specific requirements for unsigned transactions.\n                tx.set_chain_id(provider_info.chain);\n            }\n\n            if !self.args.skip_simulation {\n                let tx = tx.tx_mut();\n\n                if has_different_gas_calc(provider_info.chain) {\n                    // only estimate gas for unsigned transactions\n                    if let Some(tx) = tx.as_unsigned_mut() {\n                        trace!(\"estimating with different gas calculation\");\n                        let gas = tx.gas.expect(\"gas is set by simulation.\");\n\n                        // We are trying to show the user an estimation of the total gas usage.\n                        //\n                        // However, some transactions might depend on previous ones. For\n                        // example, tx1 might deploy a contract that tx2 uses. That\n                        // will result in the following `estimate_gas` call to fail,\n                        // since tx1 hasn't been broadcasted yet.\n                        //\n                        // Not exiting here will not be a problem when actually broadcasting,\n                        // because for chains where `has_different_gas_calc`\n                        // returns true, we await each transaction before\n                        // broadcasting the next one.\n                        if let Err(err) = estimate_gas(\n                            tx,\n                            &provider_info.provider,\n                            self.args.gas_estimate_multiplier,\n                        )\n                        .await\n                        {\n                            trace!(\"gas estimation failed: {err}\");\n\n                            // Restore gas value, since `estimate_gas` will remove it.\n                            tx.set_gas_limit(gas);\n                        }\n                    }\n                }\n\n                let total_gas = total_gas_per_rpc.entry(tx_rpc.clone()).or_insert(0);\n                *total_gas += tx.gas().expect(\"gas is set\");\n            }\n\n            new_sequence.push_back(tx);\n            // We only create a [`ScriptSequence`] object when we collect all the rpc related\n            // transactions.\n            if let Some(next_tx) = txes_iter.peek()\n                && next_tx.rpc == tx_rpc\n            {\n                continue;\n            }\n\n            let sequence =\n                self.create_sequence(is_multi_deployment, provider_info.chain, new_sequence)?;\n\n            sequences.push(sequence);\n\n            new_sequence = VecDeque::new();\n        }\n\n        if !self.args.skip_simulation {\n            // Present gas information on a per RPC basis.\n            for (rpc, total_gas) in total_gas_per_rpc {\n                let provider_info = manager.get(&rpc).expect(\"provider is set.\");\n\n                // Get the native token symbol for the chain using NamedChain\n                let token_symbol = NamedChain::try_from(provider_info.chain)\n                    .unwrap_or_default()\n                    .native_currency_symbol()\n                    .unwrap_or(\"ETH\");\n\n                // We don't store it in the transactions, since we want the most updated value.\n                // Right before broadcasting.\n                let per_gas = if let Some(gas_price) = self.args.with_gas_price {\n                    gas_price.to()\n                } else {\n                    provider_info.gas_price()?\n                };\n\n                let estimated_gas_price_raw = format_units(per_gas, 9)\n                    .unwrap_or_else(|_| \"[Could not calculate]\".to_string());\n                let estimated_gas_price =\n                    estimated_gas_price_raw.trim_end_matches('0').trim_end_matches('.');\n\n                let estimated_amount_raw = format_units(total_gas.saturating_mul(per_gas), 18)\n                    .unwrap_or_else(|_| \"[Could not calculate]\".to_string());\n                let estimated_amount = estimated_amount_raw.trim_end_matches('0');\n\n                if !shell::is_json() {\n                    sh_println!(\"\\n==========================\")?;\n                    sh_println!(\"\\nChain {}\", provider_info.chain)?;\n\n                    sh_println!(\"\\nEstimated gas price: {} gwei\", estimated_gas_price)?;\n                    sh_println!(\"\\nEstimated total gas used for script: {total_gas}\")?;\n                    sh_println!(\"\\nEstimated amount required: {estimated_amount} {token_symbol}\")?;\n                    sh_println!(\"\\n==========================\")?;\n                } else {\n                    sh_println!(\n                        \"{}\",\n                        serde_json::json!({\n                            \"chain\": provider_info.chain,\n                            \"estimated_gas_price\": estimated_gas_price,\n                            \"estimated_total_gas_used\": total_gas,\n                            \"estimated_amount_required\": estimated_amount,\n                            \"token_symbol\": token_symbol,\n                        })\n                    )?;\n                }\n            }\n        }\n\n        let sequence = if sequences.len() == 1 {\n            ScriptSequenceKind::Single(sequences.pop().expect(\"empty sequences\"))\n        } else {\n            ScriptSequenceKind::Multi(MultiChainSequence::new(\n                sequences,\n                &self.args.sig,\n                &self.build_data.build_data.target,\n                &self.script_config.config,\n                !self.args.broadcast,\n            )?)\n        };\n\n        Ok(BundledState {\n            args: self.args,\n            script_config: self.script_config,\n            script_wallets: self.script_wallets,\n            browser_wallet: self.browser_wallet,\n            build_data: self.build_data,\n            sequence,\n        })\n    }\n\n    /// Creates a [ScriptSequence] object from the given transactions.\n    fn create_sequence(\n        &self,\n        multi: bool,\n        chain: u64,\n        transactions: VecDeque<TransactionWithMetadata<Ethereum>>,\n    ) -> Result<ScriptSequence<Ethereum>> {\n        // Paths are set to None for multi-chain sequences parts, because they don't need to be\n        // saved to a separate file.\n        let paths = if multi {\n            None\n        } else {\n            Some(ScriptSequence::<Ethereum>::get_paths(\n                &self.script_config.config,\n                &self.args.sig,\n                &self.build_data.build_data.target,\n                chain,\n                !self.args.broadcast,\n            )?)\n        };\n\n        let commit = get_commit_hash(&self.script_config.config.root);\n\n        let libraries = self\n            .build_data\n            .libraries\n            .libs\n            .iter()\n            .flat_map(|(file, libs)| {\n                libs.iter()\n                    .map(|(name, address)| format!(\"{}:{name}:{address}\", file.to_string_lossy()))\n            })\n            .collect();\n\n        let sequence = ScriptSequence {\n            transactions,\n            returns: self.execution_artifacts.returns.clone(),\n            receipts: vec![],\n            pending: vec![],\n            paths,\n            timestamp: now().as_millis(),\n            libraries,\n            chain,\n            commit,\n        };\n        Ok(sequence)\n    }\n}\n\n/// Converts a network-agnostic [`BroadcastableTransaction`] into a\n/// [`TransactionMaybeSigned<Ethereum>`] for use in the script pipeline.\nfn into_maybe_signed(tx: BroadcastableTransaction) -> TransactionMaybeSigned<Ethereum> {\n    match tx.kind {\n        BroadcastKind::Unsigned { chain_id, blob_sidecar, authorization_list } => {\n            let mut req = TransactionRequest {\n                from: Some(tx.from),\n                to: tx.to,\n                value: Some(tx.value),\n                input: TransactionInput::maybe_both(Some(tx.input)),\n                nonce: Some(tx.nonce),\n                chain_id,\n                gas: tx.gas,\n                ..Default::default()\n            };\n            if let Some(sidecar) = blob_sidecar {\n                req.set_blob_sidecar(sidecar);\n            }\n            if let Some(auths) = authorization_list {\n                req.authorization_list = Some(auths);\n            }\n            TransactionMaybeSigned::Unsigned(req)\n        }\n        BroadcastKind::Signed(raw) => {\n            let envelope = TxEnvelope::decode_2718(&mut raw.as_ref())\n                .expect(\"failed to decode pre-signed transaction\");\n            TransactionMaybeSigned::Signed { tx: envelope, from: tx.from }\n        }\n    }\n}\n"
  },
  {
    "path": "crates/script/src/transaction.rs",
    "content": "use super::ScriptResult;\nuse crate::build::LinkedBuildData;\nuse alloy_dyn_abi::JsonAbiExt;\nuse alloy_network::{Network, TransactionBuilder};\nuse alloy_primitives::{Address, B256, TxKind, hex};\nuse eyre::Result;\nuse forge_script_sequence::TransactionWithMetadata;\nuse foundry_common::{ContractData, SELECTOR_LEN, TransactionMaybeSigned, fmt::format_token_raw};\nuse foundry_evm::traces::CallTraceDecoder;\nuse itertools::Itertools;\nuse revm_inspectors::tracing::types::CallKind;\nuse std::collections::BTreeMap;\n\n#[derive(Debug)]\npub struct ScriptTransactionBuilder<N: Network> {\n    transaction: TransactionWithMetadata<N>,\n}\n\nimpl<N: Network> ScriptTransactionBuilder<N> {\n    pub fn new(transaction: TransactionMaybeSigned<N>, rpc: String) -> Self {\n        let mut transaction = TransactionWithMetadata::from_tx_request(transaction);\n        transaction.rpc = rpc;\n        // If tx.gas is already set that means it was specified in script\n        transaction.is_fixed_gas_limit = transaction.tx().gas().is_some();\n\n        Self { transaction }\n    }\n\n    /// Populate the transaction as CALL tx\n    pub fn set_call(\n        &mut self,\n        local_contracts: &BTreeMap<Address, &ContractData>,\n        decoder: &CallTraceDecoder,\n        create2_deployer: Address,\n    ) -> Result<()> {\n        if let Some(TxKind::Call(to)) = self.transaction.transaction.to() {\n            if to == create2_deployer {\n                if let Some(input) = self.transaction.transaction.input() {\n                    let (salt, init_code) = input.split_at(32);\n\n                    self.set_create(\n                        true,\n                        create2_deployer.create2_from_code(B256::from_slice(salt), init_code),\n                        local_contracts,\n                    )?;\n                }\n            } else {\n                self.transaction.opcode = CallKind::Call;\n                self.transaction.contract_address = Some(to);\n\n                let Some(data) = self.transaction.transaction.input() else { return Ok(()) };\n\n                if data.len() < SELECTOR_LEN {\n                    return Ok(());\n                }\n\n                let (selector, data) = data.split_at(SELECTOR_LEN);\n\n                let function = if let Some(info) = local_contracts.get(&to) {\n                    // This CALL is made to a local contract.\n                    self.transaction.contract_name = Some(info.name.clone());\n                    info.abi.functions().find(|function| function.selector() == selector)\n                } else {\n                    // This CALL is made to an external contract; try to decode it from the given\n                    // decoder.\n                    decoder.functions.get(selector).and_then(|v| v.first())\n                };\n\n                if let Some(function) = function {\n                    self.transaction.function = Some(function.signature());\n\n                    let values = function.abi_decode_input(data).inspect_err(|_| {\n                        error!(\n                            contract=?self.transaction.contract_name,\n                            signature=?function,\n                            data=hex::encode(data),\n                            \"Failed to decode function arguments\",\n                        );\n                    })?;\n                    self.transaction.arguments =\n                        Some(values.iter().map(format_token_raw).collect());\n                }\n            }\n        }\n\n        Ok(())\n    }\n\n    /// Populate the transaction as CREATE tx\n    ///\n    /// If this is a CREATE2 transaction this attempt to decode the arguments from the CREATE2\n    /// deployer's function\n    pub fn set_create(\n        &mut self,\n        is_create2: bool,\n        address: Address,\n        contracts: &BTreeMap<Address, &ContractData>,\n    ) -> Result<()> {\n        if is_create2 {\n            self.transaction.opcode = CallKind::Create2;\n        } else {\n            self.transaction.opcode = CallKind::Create;\n        }\n\n        let info = contracts.get(&address);\n        self.transaction.contract_name = info.map(|info| info.name.clone());\n        self.transaction.contract_address = Some(address);\n\n        let Some(data) = self.transaction.transaction.input() else { return Ok(()) };\n        let Some(info) = info else { return Ok(()) };\n        let Some(bytecode) = info.bytecode() else { return Ok(()) };\n\n        // `create2` transactions are prefixed by a 32 byte salt.\n        let creation_code = if is_create2 {\n            if data.len() < 32 {\n                return Ok(());\n            }\n            &data[32..]\n        } else {\n            data\n        };\n\n        // The constructor args start after bytecode.\n        let contains_constructor_args = creation_code.len() > bytecode.len();\n        if !contains_constructor_args {\n            return Ok(());\n        }\n        let constructor_args = &creation_code[bytecode.len()..];\n\n        let Some(constructor) = info.abi.constructor() else { return Ok(()) };\n        let values = constructor.abi_decode_input(constructor_args).inspect_err(|_| {\n                error!(\n                    contract=?self.transaction.contract_name,\n                    signature=%format!(\"constructor({})\", constructor.inputs.iter().map(|p| &p.ty).format(\",\")),\n                    is_create2,\n                    constructor_args=%hex::encode(constructor_args),\n                    \"Failed to decode constructor arguments\",\n                );\n                debug!(full_data=%hex::encode(data), bytecode=%hex::encode(creation_code));\n            })?;\n        self.transaction.arguments = Some(values.iter().map(format_token_raw).collect());\n\n        Ok(())\n    }\n\n    /// Populates additional data from the transaction execution result.\n    pub fn with_execution_result(\n        mut self,\n        result: &ScriptResult,\n        gas_estimate_multiplier: u64,\n        linked_build_data: &LinkedBuildData,\n    ) -> Self {\n        let mut created_contracts =\n            result.get_created_contracts(&linked_build_data.known_contracts);\n\n        // Add the additional contracts created in this transaction, so we can verify them later.\n        created_contracts.retain(|contract| {\n            // Filter out the contract that was created by the transaction itself.\n            self.transaction.contract_address != Some(contract.address)\n        });\n\n        self.transaction.additional_contracts = created_contracts;\n\n        if !self.transaction.is_fixed_gas_limit\n            && let Some(unsigned) = self.transaction.transaction.as_unsigned_mut()\n        {\n            // We inflate the gas used by the user specified percentage\n            unsigned.set_gas_limit(result.gas_used * gas_estimate_multiplier / 100);\n        }\n\n        self\n    }\n\n    pub fn build(self) -> TransactionWithMetadata<N> {\n        self.transaction\n    }\n}\n\nimpl<N: Network> From<TransactionWithMetadata<N>> for ScriptTransactionBuilder<N> {\n    fn from(transaction: TransactionWithMetadata<N>) -> Self {\n        Self { transaction }\n    }\n}\n"
  },
  {
    "path": "crates/script/src/verify.rs",
    "content": "use crate::{\n    ScriptArgs, ScriptConfig,\n    build::LinkedBuildData,\n    receipts::FoundryReceiptResponse,\n    sequence::{ScriptSequenceKind, get_commit_hash},\n};\nuse alloy_network::{Network, ReceiptResponse};\nuse alloy_primitives::{Address, hex};\nuse eyre::{Result, eyre};\nuse forge_script_sequence::{AdditionalContract, ScriptSequence};\nuse forge_verify::{RetryArgs, VerifierArgs, VerifyArgs, provider::VerificationProviderType};\nuse foundry_cli::opts::{EtherscanOpts, ProjectPathOpts};\nuse foundry_common::ContractsByArtifact;\nuse foundry_compilers::{Project, artifacts::EvmVersion, info::ContractInfo};\nuse foundry_config::{Chain, Config};\nuse semver::Version;\nuse serde::{Deserialize, Serialize};\n\n/// State after we have broadcasted the script.\n/// It is assumed that at this point [BroadcastedState::sequence] contains receipts for all\n/// broadcasted transactions.\npub struct BroadcastedState<N: Network>\nwhere\n    N::TxEnvelope: for<'d> Deserialize<'d> + Serialize,\n    N::TransactionRequest: for<'d> Deserialize<'d> + Serialize,\n{\n    pub args: ScriptArgs,\n    pub script_config: ScriptConfig,\n    pub build_data: LinkedBuildData,\n    pub sequence: ScriptSequenceKind<N>,\n}\n\nimpl<N: Network> BroadcastedState<N>\nwhere\n    N::TxEnvelope: for<'d> Deserialize<'d> + Serialize,\n    N::TransactionRequest: for<'d> Deserialize<'d> + Serialize,\n    N::ReceiptResponse: FoundryReceiptResponse,\n{\n    pub async fn verify(self) -> Result<()> {\n        let Self { args, script_config, build_data, mut sequence, .. } = self;\n\n        let verify = VerifyBundle::new(\n            &script_config.config.project()?,\n            &script_config.config,\n            build_data.known_contracts,\n            args.retry,\n            args.verifier,\n        );\n\n        for sequence in sequence.sequences_mut() {\n            verify_contracts(sequence, &script_config.config, verify.clone()).await?;\n        }\n\n        Ok(())\n    }\n}\n\n/// Data struct to help `ScriptSequence` verify contracts on `etherscan`.\n#[derive(Clone)]\npub struct VerifyBundle {\n    pub num_of_optimizations: Option<usize>,\n    pub known_contracts: ContractsByArtifact,\n    pub project_paths: ProjectPathOpts,\n    pub etherscan: EtherscanOpts,\n    pub retry: RetryArgs,\n    pub verifier: VerifierArgs,\n    pub via_ir: bool,\n}\n\nimpl VerifyBundle {\n    pub fn new(\n        project: &Project,\n        config: &Config,\n        known_contracts: ContractsByArtifact,\n        retry: RetryArgs,\n        verifier: VerifierArgs,\n    ) -> Self {\n        let num_of_optimizations =\n            if config.optimizer == Some(true) { config.optimizer_runs } else { None };\n\n        let config_path = config.get_config_path();\n\n        let project_paths = ProjectPathOpts {\n            root: Some(project.paths.root.clone()),\n            contracts: Some(project.paths.sources.clone()),\n            remappings: project.paths.remappings.clone(),\n            remappings_env: None,\n            cache_path: Some(project.paths.cache.clone()),\n            lib_paths: project.paths.libraries.clone(),\n            hardhat: config.profile == Config::HARDHAT_PROFILE,\n            config_path: if config_path.exists() { Some(config_path) } else { None },\n        };\n\n        let via_ir = config.via_ir;\n\n        Self {\n            num_of_optimizations,\n            known_contracts,\n            etherscan: Default::default(),\n            project_paths,\n            retry,\n            verifier,\n            via_ir,\n        }\n    }\n\n    /// Configures the chain and sets the etherscan key, if available\n    pub fn set_chain(&mut self, config: &Config, chain: Chain) {\n        // If dealing with multiple chains, we need to be able to change in between the config\n        // chain_id.\n        self.etherscan.key = config.get_etherscan_api_key(Some(chain));\n        self.etherscan.chain = Some(chain);\n    }\n\n    /// Given a `VerifyBundle` and contract details, it tries to generate a valid `VerifyArgs` to\n    /// use against the `contract_address`.\n    pub fn get_verify_args(\n        &self,\n        contract_address: Address,\n        create2_offset: usize,\n        data: &[u8],\n        libraries: &[String],\n        evm_version: EvmVersion,\n    ) -> Option<VerifyArgs> {\n        for (artifact, contract) in self.known_contracts.iter() {\n            let Some(bytecode) = contract.bytecode() else { continue };\n            // If it's a CREATE2, the tx.data comes with a 32-byte salt in the beginning\n            // of the transaction\n            if data.split_at(create2_offset).1.starts_with(bytecode) {\n                let constructor_args = data.split_at(create2_offset + bytecode.len()).1.to_vec();\n\n                if artifact.source.extension().is_some_and(|e| e.to_str() == Some(\"vy\")) {\n                    warn!(\"Skipping verification of Vyper contract: {}\", artifact.name);\n                    return None;\n                }\n\n                // Strip artifact profile from contract name when creating contract info.\n                let contract = ContractInfo {\n                    path: Some(artifact.source.to_string_lossy().to_string()),\n                    name: artifact\n                        .name\n                        .strip_suffix(&format!(\".{}\", &artifact.profile))\n                        .unwrap_or_else(|| &artifact.name)\n                        .to_string(),\n                };\n\n                // We strip the build metadata information, since it can lead to\n                // etherscan not identifying it correctly. eg:\n                // `v0.8.10+commit.fc410830.Linux.gcc` != `v0.8.10+commit.fc410830`\n                let version = Version::new(\n                    artifact.version.major,\n                    artifact.version.minor,\n                    artifact.version.patch,\n                );\n\n                let verify = VerifyArgs {\n                    address: contract_address,\n                    contract: Some(contract),\n                    compiler_version: Some(version.to_string()),\n                    constructor_args: Some(hex::encode(constructor_args)),\n                    constructor_args_path: None,\n                    no_auto_detect: false,\n                    use_solc: None,\n                    num_of_optimizations: self.num_of_optimizations,\n                    etherscan: self.etherscan.clone(),\n                    rpc: Default::default(),\n                    flatten: false,\n                    force: false,\n                    skip_is_verified_check: true,\n                    watch: true,\n                    retry: self.retry,\n                    libraries: libraries.to_vec(),\n                    root: None,\n                    verifier: self.verifier.clone(),\n                    via_ir: self.via_ir,\n                    evm_version: Some(evm_version),\n                    show_standard_json_input: false,\n                    guess_constructor_args: false,\n                    compilation_profile: Some(artifact.profile.to_string()),\n                    language: None,\n                    creation_transaction_hash: None,\n                };\n\n                return Some(verify);\n            }\n        }\n        None\n    }\n}\n\n/// Given the broadcast log, it matches transactions with receipts, and tries to verify any\n/// created contract on etherscan.\nasync fn verify_contracts<N: Network<ReceiptResponse: FoundryReceiptResponse>>(\n    sequence: &mut ScriptSequence<N>,\n    config: &Config,\n    mut verify: VerifyBundle,\n) -> Result<()> {\n    trace!(target: \"script\", \"verifying {} contracts [{}]\", verify.known_contracts.len(), sequence.chain);\n\n    verify.set_chain(config, sequence.chain.into());\n\n    if verify.etherscan.has_key() || verify.verifier.verifier != VerificationProviderType::Etherscan\n    {\n        trace!(target: \"script\", \"prepare future verifications\");\n\n        let mut future_verifications = Vec::with_capacity(sequence.receipts.len());\n        let mut unverifiable_contracts = vec![];\n\n        // Make sure the receipts have the right order first.\n        sequence.sort_receipts();\n\n        for (receipt, tx) in sequence.receipts.iter_mut().zip(sequence.transactions.iter()) {\n            // create2 hash offset\n            let mut offset = 0;\n\n            if tx.is_create2()\n                && let Some(contract_address) = tx.contract_address\n            {\n                receipt.set_contract_address(contract_address);\n                offset = 32;\n            }\n\n            // Verify contract created directly from the transaction\n            if let (Some(address), Some(data)) = (receipt.contract_address(), tx.tx().input()) {\n                match verify.get_verify_args(\n                    address,\n                    offset,\n                    data,\n                    &sequence.libraries,\n                    config.evm_version,\n                ) {\n                    Some(verify) => future_verifications.push(verify.run()),\n                    None => unverifiable_contracts.push(address),\n                };\n            }\n\n            // Verify potential contracts created during the transaction execution\n            for AdditionalContract { address, init_code, .. } in &tx.additional_contracts {\n                match verify.get_verify_args(\n                    *address,\n                    0,\n                    init_code.as_ref(),\n                    &sequence.libraries,\n                    config.evm_version,\n                ) {\n                    Some(verify) => future_verifications.push(verify.run()),\n                    None => unverifiable_contracts.push(*address),\n                };\n            }\n        }\n\n        trace!(target: \"script\", \"collected {} verification jobs and {} unverifiable contracts\", future_verifications.len(), unverifiable_contracts.len());\n\n        check_unverified(sequence, unverifiable_contracts, verify);\n\n        let num_verifications = future_verifications.len();\n        let mut num_of_successful_verifications = 0;\n        sh_println!(\"##\\nStart verification for ({num_verifications}) contracts\")?;\n        for verification in future_verifications {\n            match verification.await {\n                Ok(_) => {\n                    num_of_successful_verifications += 1;\n                }\n                Err(err) => {\n                    sh_err!(\"Failed to verify contract: {err:#}\")?;\n                }\n            }\n        }\n\n        if num_of_successful_verifications < num_verifications {\n            return Err(eyre!(\n                \"Not all ({num_of_successful_verifications} / {num_verifications}) contracts were verified!\"\n            ));\n        }\n\n        sh_println!(\"All ({num_verifications}) contracts were verified!\")?;\n    }\n\n    Ok(())\n}\n\nfn check_unverified<N: Network>(\n    sequence: &ScriptSequence<N>,\n    unverifiable_contracts: Vec<Address>,\n    verify: VerifyBundle,\n) {\n    if !unverifiable_contracts.is_empty() {\n        let _ = sh_warn!(\n            \"We haven't found any matching bytecode for the following contracts: {:?}.\\n\\n\\\n            This may occur when resuming a verification, but the underlying source code or compiler version has changed.\\n\\\n            Run `forge clean` to make sure builds are in sync with project files, then try again. Alternatively, use `forge verify-contract` to verify contracts that are already deployed.\",\n            unverifiable_contracts\n        );\n\n        if let Some(commit) = &sequence.commit {\n            let current_commit = verify\n                .project_paths\n                .root\n                .map(|root| get_commit_hash(&root).unwrap_or_default())\n                .unwrap_or_default();\n\n            if &current_commit != commit {\n                let _ = sh_warn!(\n                    \"Script was broadcasted on commit `{commit}`, but we are at `{current_commit}`.\"\n                );\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "crates/script-sequence/Cargo.toml",
    "content": "[package]\nname = \"forge-script-sequence\"\ndescription = \"Script sequence types\"\n\nversion.workspace = true\nedition.workspace = true\nrust-version.workspace = true\nauthors.workspace = true\nlicense.workspace = true\nhomepage.workspace = true\nrepository.workspace = true\n\n[lints]\nworkspace = true\n\n[dependencies]\nfoundry-config.workspace = true\nfoundry-common.workspace = true\nfoundry-compilers.workspace = true\n\nserde.workspace = true\neyre.workspace = true\nserde_json.workspace = true\nwalkdir.workspace = true\n\nrevm-inspectors.workspace = true\n\nalloy-network.workspace = true\nalloy-primitives.workspace = true\n"
  },
  {
    "path": "crates/script-sequence/src/lib.rs",
    "content": "//! Script Sequence and related types.\n#![cfg_attr(not(test), warn(unused_crate_dependencies))]\n\n#[macro_use]\nextern crate foundry_common;\n\npub mod reader;\npub mod sequence;\npub mod transaction;\n\npub use reader::*;\npub use sequence::*;\npub use transaction::*;\n"
  },
  {
    "path": "crates/script-sequence/src/reader.rs",
    "content": "use crate::{ScriptSequence, TransactionWithMetadata};\nuse alloy_network::{Network, ReceiptResponse};\nuse eyre::{Result, bail};\nuse foundry_common::fs;\nuse revm_inspectors::tracing::types::CallKind;\nuse serde::Deserialize;\nuse std::path::{Component, Path, PathBuf};\n\n/// This type reads broadcast files in the\n/// `project_root/broadcast/{contract_name}.s.sol/{chain_id}/` directory.\n///\n/// It consists methods that filter and search for transactions in the broadcast files that match a\n/// `transactionType` if provided.\n///\n/// Note:\n///\n/// It only returns transactions for which there exists a corresponding receipt in the broadcast.\n#[derive(Debug, Clone)]\npub struct BroadcastReader {\n    contract_name: String,\n    chain_id: u64,\n    tx_type: Vec<CallKind>,\n    broadcast_path: PathBuf,\n}\n\nimpl BroadcastReader {\n    /// Create a new `BroadcastReader` instance.\n    pub fn new(contract_name: String, chain_id: u64, broadcast_path: &Path) -> Result<Self> {\n        if !broadcast_path.is_dir() {\n            bail!(\"broadcast dir does not exist or is not a directory\");\n        }\n\n        Ok(Self {\n            contract_name,\n            chain_id,\n            tx_type: Default::default(),\n            broadcast_path: broadcast_path.to_path_buf(),\n        })\n    }\n\n    /// Set the transaction type to filter by.\n    pub fn with_tx_type(mut self, tx_type: CallKind) -> Self {\n        self.tx_type.push(tx_type);\n        self\n    }\n\n    fn matches_filters<N: Network>(&self, tx: &TransactionWithMetadata<N>) -> bool {\n        let name_filter = tx.contract_name.as_ref().is_some_and(|cn| *cn == self.contract_name);\n        let type_filter = self.tx_type.is_empty() || self.tx_type.contains(&tx.opcode);\n        name_filter && type_filter\n    }\n\n    /// Read all broadcast files in the broadcast directory.\n    ///\n    /// Example structure:\n    ///\n    /// project-root/broadcast/{script_name}.s.sol/{chain_id}/*.json\n    /// project-root/broadcast/multi/{multichain_script_name}.s.sol-{timestamp}/deploy.json\n    pub fn read<N: Network>(&self) -> eyre::Result<Vec<ScriptSequence<N>>>\n    where\n        N::TxEnvelope: for<'d> Deserialize<'d>,\n    {\n        // 1. Recursively read all .json files in the broadcast directory\n        let mut broadcasts = vec![];\n        for entry in walkdir::WalkDir::new(&self.broadcast_path).into_iter() {\n            let entry = entry?;\n            let path = entry.path();\n\n            if path.is_file() && path.extension().is_some_and(|ext| ext == \"json\") {\n                // Ignore -latest to avoid duplicating broadcast entries\n                if path.components().any(|c| c.as_os_str().to_string_lossy().contains(\"-latest\")) {\n                    continue;\n                }\n\n                // Detect Multichain broadcasts using \"multi\" in the path\n                if path.components().any(|c| c == Component::Normal(\"multi\".as_ref())) {\n                    // Parse as MultiScriptSequence\n\n                    let broadcast = fs::read_json_file::<serde_json::Value>(path)?;\n                    let multichain_deployments = broadcast\n                        .get(\"deployments\")\n                        .and_then(|deployments| {\n                            serde_json::from_value::<Vec<ScriptSequence<N>>>(deployments.clone())\n                                .ok()\n                        })\n                        .unwrap_or_default();\n\n                    broadcasts.extend(multichain_deployments);\n                    continue;\n                }\n\n                let broadcast = fs::read_json_file::<ScriptSequence<N>>(path)?;\n                broadcasts.push(broadcast);\n            }\n        }\n\n        let broadcasts = self.filter_and_sort(broadcasts);\n\n        Ok(broadcasts)\n    }\n\n    /// Attempts read the latest broadcast file in the broadcast directory.\n    ///\n    /// This may be the `run-latest.json` file or the broadcast file with the latest timestamp.\n    pub fn read_latest<N: Network>(&self) -> eyre::Result<ScriptSequence<N>>\n    where\n        N::TxEnvelope: for<'d> Deserialize<'d>,\n    {\n        let broadcasts = self.read()?;\n\n        // Find the broadcast with the latest timestamp\n        let target = broadcasts\n            .into_iter()\n            .max_by_key(|broadcast| broadcast.timestamp)\n            .ok_or_else(|| eyre::eyre!(\"No broadcasts found\"))?;\n\n        Ok(target)\n    }\n\n    /// Applies the filters and sorts the broadcasts by descending timestamp.\n    pub fn filter_and_sort<N: Network>(\n        &self,\n        broadcasts: Vec<ScriptSequence<N>>,\n    ) -> Vec<ScriptSequence<N>> {\n        // Apply the filters\n        let mut seqs = broadcasts\n            .into_iter()\n            .filter(|broadcast| {\n                if broadcast.chain != self.chain_id {\n                    return false;\n                }\n\n                broadcast.transactions.iter().any(|tx| self.matches_filters(tx))\n            })\n            .collect::<Vec<_>>();\n\n        // Sort by descending timestamp\n        seqs.sort_by_key(|s| std::cmp::Reverse(s.timestamp));\n\n        seqs\n    }\n\n    /// Search for transactions in the broadcast that match the specified `contractName` and\n    /// `txType`.\n    ///\n    /// It cross-checks the transactions with their corresponding receipts in the broadcast and\n    /// returns the result.\n    ///\n    /// Transactions that don't have a corresponding receipt are ignored.\n    ///\n    /// Sorts the transactions by descending block number.\n    pub fn into_tx_receipts<N: Network>(\n        &self,\n        broadcast: ScriptSequence<N>,\n    ) -> Vec<(TransactionWithMetadata<N>, N::ReceiptResponse)> {\n        let ScriptSequence { transactions, receipts, .. } = broadcast;\n\n        let mut targets: Vec<_> = transactions\n            .into_iter()\n            .filter(|tx| self.matches_filters(tx))\n            .filter_map(|tx| {\n                let receipt = receipts\n                    .iter()\n                    .find(|r| tx.hash.is_some_and(|hash| hash == r.transaction_hash()))?;\n                Some((tx, receipt.clone()))\n            })\n            .collect();\n\n        // Sort by descending block number\n        targets.sort_by_key(|t| std::cmp::Reverse(t.1.block_number()));\n\n        targets\n    }\n}\n"
  },
  {
    "path": "crates/script-sequence/src/sequence.rs",
    "content": "use crate::transaction::TransactionWithMetadata;\nuse alloy_network::{Network, ReceiptResponse};\nuse alloy_primitives::{TxHash, hex, map::HashMap};\nuse eyre::{ContextCompat, Result, WrapErr};\nuse foundry_common::{SELECTOR_LEN, TransactionMaybeSigned, fs, shell};\nuse foundry_compilers::ArtifactId;\nuse foundry_config::Config;\nuse serde::{Deserialize, Serialize};\nuse std::{\n    collections::VecDeque,\n    path::PathBuf,\n    time::{Duration, SystemTime, UNIX_EPOCH},\n};\n\npub const DRY_RUN_DIR: &str = \"dry-run\";\n\n#[derive(Clone, Serialize, Deserialize)]\npub struct NestedValue {\n    pub internal_type: String,\n    pub value: String,\n}\n\n/// Sensitive values from the transactions in a script sequence\n#[derive(Clone, Default, Serialize, Deserialize)]\npub struct SensitiveTransactionMetadata {\n    pub rpc: String,\n}\n\n/// Sensitive info from the script sequence which is saved into the cache folder\n#[derive(Clone, Default, Serialize, Deserialize)]\npub struct SensitiveScriptSequence {\n    pub transactions: VecDeque<SensitiveTransactionMetadata>,\n}\n\n/// Helper that saves the transactions sequence and its state on which transactions have been\n/// broadcasted\n#[derive(Clone, Serialize, Deserialize)]\n#[serde(bound(\n    serialize = \"N::TransactionRequest: Serialize, N::TxEnvelope: Serialize\",\n    deserialize = \"N::TransactionRequest: for<'de2> Deserialize<'de2>, N::TxEnvelope: for<'de2> Deserialize<'de2>\"\n))]\npub struct ScriptSequence<N: Network> {\n    pub transactions: VecDeque<TransactionWithMetadata<N>>,\n    pub receipts: Vec<N::ReceiptResponse>,\n    pub libraries: Vec<String>,\n    pub pending: Vec<TxHash>,\n    #[serde(skip)]\n    /// Contains paths to the sequence files\n    /// None if sequence should not be saved to disk (e.g. part of a multi-chain sequence)\n    pub paths: Option<(PathBuf, PathBuf)>,\n    pub returns: HashMap<String, NestedValue>,\n    pub timestamp: u128,\n    pub chain: u64,\n    pub commit: Option<String>,\n}\n\nimpl<N: Network> Default for ScriptSequence<N> {\n    fn default() -> Self {\n        Self {\n            transactions: Default::default(),\n            receipts: Default::default(),\n            libraries: Default::default(),\n            pending: Default::default(),\n            paths: Default::default(),\n            returns: Default::default(),\n            timestamp: Default::default(),\n            chain: Default::default(),\n            commit: Default::default(),\n        }\n    }\n}\n\nimpl<N: Network> From<&ScriptSequence<N>> for SensitiveScriptSequence {\n    fn from(sequence: &ScriptSequence<N>) -> Self {\n        Self {\n            transactions: sequence\n                .transactions\n                .iter()\n                .map(|tx| SensitiveTransactionMetadata { rpc: tx.rpc.clone() })\n                .collect(),\n        }\n    }\n}\n\nimpl<N: Network> ScriptSequence<N> {\n    /// Loads The sequence for the corresponding json file\n    pub fn load(\n        config: &Config,\n        sig: &str,\n        target: &ArtifactId,\n        chain_id: u64,\n        dry_run: bool,\n    ) -> Result<Self>\n    where\n        N::TxEnvelope: for<'d> Deserialize<'d>,\n    {\n        let (path, sensitive_path) = Self::get_paths(config, sig, target, chain_id, dry_run)?;\n\n        let mut script_sequence: Self = fs::read_json_file(&path)\n            .wrap_err(format!(\"Deployment not found for chain `{chain_id}`.\"))?;\n\n        let sensitive_script_sequence: SensitiveScriptSequence = fs::read_json_file(\n            &sensitive_path,\n        )\n        .wrap_err(format!(\"Deployment's sensitive details not found for chain `{chain_id}`.\"))?;\n\n        script_sequence.fill_sensitive(&sensitive_script_sequence);\n\n        script_sequence.paths = Some((path, sensitive_path));\n\n        Ok(script_sequence)\n    }\n\n    /// Saves the transactions as file if it's a standalone deployment.\n    /// `save_ts` should be set to true for checkpoint updates, which might happen many times and\n    /// could result in us saving many identical files.\n    pub fn save(&mut self, silent: bool, save_ts: bool) -> Result<()>\n    where\n        N::TxEnvelope: Serialize,\n    {\n        self.sort_receipts();\n\n        if self.transactions.is_empty() {\n            return Ok(());\n        }\n\n        self.timestamp = now().as_millis();\n        let ts_name = format!(\"run-{}.json\", self.timestamp);\n\n        let sensitive_script_sequence = SensitiveScriptSequence::from(&*self);\n\n        let Some((path, sensitive_path)) = self.paths.as_ref() else { return Ok(()) };\n\n        // broadcast folder writes\n        //../run-latest.json\n        fs::write_pretty_json_file(path, &self)?;\n        if save_ts {\n            //../run-[timestamp].json\n            fs::copy(path, path.with_file_name(&ts_name))?;\n        }\n\n        // cache folder writes\n        //../run-latest.json\n        fs::write_pretty_json_file(sensitive_path, &sensitive_script_sequence)?;\n        if save_ts {\n            //../run-[timestamp].json\n            fs::copy(sensitive_path, sensitive_path.with_file_name(&ts_name))?;\n        }\n\n        if !silent {\n            if shell::is_json() {\n                sh_println!(\n                    \"{}\",\n                    serde_json::json!({\n                        \"status\": \"success\",\n                        \"transactions\": path.display().to_string(),\n                        \"sensitive\": sensitive_path.display().to_string(),\n                    })\n                )?;\n            } else {\n                sh_println!(\"\\nTransactions saved to: {}\\n\", path.display())?;\n                sh_println!(\"Sensitive values saved to: {}\\n\", sensitive_path.display())?;\n            }\n        }\n\n        Ok(())\n    }\n\n    pub fn add_receipt(&mut self, receipt: N::ReceiptResponse) {\n        self.receipts.push(receipt);\n    }\n\n    /// Sorts all receipts with ascending transaction index\n    pub fn sort_receipts(&mut self) {\n        self.receipts.sort_by_key(|r| (r.block_number(), r.transaction_index()));\n    }\n\n    pub fn add_pending(&mut self, index: usize, tx_hash: TxHash) {\n        if !self.pending.contains(&tx_hash) {\n            self.transactions[index].hash = Some(tx_hash);\n            self.pending.push(tx_hash);\n        }\n    }\n\n    pub fn remove_pending(&mut self, tx_hash: TxHash) {\n        self.pending.retain(|element| element != &tx_hash);\n    }\n\n    /// Gets paths in the formats\n    /// `./broadcast/[contract_filename]/[chain_id]/[sig]-latest.json` and\n    /// `./cache/[contract_filename]/[chain_id]/[sig]-latest.json`.\n    pub fn get_paths(\n        config: &Config,\n        sig: &str,\n        target: &ArtifactId,\n        chain_id: u64,\n        dry_run: bool,\n    ) -> Result<(PathBuf, PathBuf)> {\n        let mut broadcast = config.broadcast.to_path_buf();\n        let mut cache = config.cache_path.to_path_buf();\n        let mut common = PathBuf::new();\n\n        let target_fname = target.source.file_name().wrap_err(\"No filename.\")?;\n        common.push(target_fname);\n        common.push(chain_id.to_string());\n        if dry_run {\n            common.push(DRY_RUN_DIR);\n        }\n\n        broadcast.push(common.clone());\n        cache.push(common);\n\n        fs::create_dir_all(&broadcast)?;\n        fs::create_dir_all(&cache)?;\n\n        // TODO: ideally we want the name of the function here if sig is calldata\n        let filename = sig_to_file_name(sig);\n        let filename_with_ext = format!(\"{filename}-latest.json\");\n\n        broadcast.push(&filename_with_ext);\n        cache.push(&filename_with_ext);\n\n        Ok((broadcast, cache))\n    }\n\n    /// Returns the first RPC URL of this sequence.\n    pub fn rpc_url(&self) -> &str {\n        self.transactions.front().expect(\"empty sequence\").rpc.as_str()\n    }\n\n    /// Returns the list of the transactions without the metadata.\n    pub fn transactions(&self) -> impl Iterator<Item = &TransactionMaybeSigned<N>> {\n        self.transactions.iter().map(|tx| tx.tx())\n    }\n\n    pub fn fill_sensitive(&mut self, sensitive: &SensitiveScriptSequence) {\n        self.transactions\n            .iter_mut()\n            .enumerate()\n            .for_each(|(i, tx)| tx.rpc.clone_from(&sensitive.transactions[i].rpc));\n    }\n}\n\n/// Converts the `sig` argument into the corresponding file path.\n///\n/// This accepts either the signature of the function or the raw calldata.\npub fn sig_to_file_name(sig: &str) -> String {\n    if let Some((name, _)) = sig.split_once('(') {\n        // strip until call argument parenthesis\n        return name.to_string();\n    }\n    // assume calldata if `sig` is hex\n    if let Ok(calldata) = hex::decode(sig.strip_prefix(\"0x\").unwrap_or(sig)) {\n        // in which case we return the function selector if available\n        if let Some(selector) = calldata.get(..SELECTOR_LEN) {\n            return hex::encode(selector);\n        }\n        // fallback to original string if calldata is too short to contain selector\n        return sig.to_string();\n    }\n\n    sig.to_string()\n}\n\npub fn now() -> Duration {\n    SystemTime::now().duration_since(UNIX_EPOCH).expect(\"time went backwards\")\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn can_convert_sig() {\n        assert_eq!(sig_to_file_name(\"run()\").as_str(), \"run\");\n        assert_eq!(\n            sig_to_file_name(\n                \"522bb704000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfFFb92266\"\n            )\n            .as_str(),\n            \"522bb704\"\n        );\n        // valid calldata with 0x prefix\n        assert_eq!(\n            sig_to_file_name(\n                \"0x522bb704000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfFFb92266\"\n            )\n            .as_str(),\n            \"522bb704\"\n        );\n        // short calldata: should not panic and should return input as-is\n        assert_eq!(sig_to_file_name(\"0x1234\").as_str(), \"0x1234\");\n        assert_eq!(sig_to_file_name(\"123\").as_str(), \"123\");\n        // invalid hex: should return input as-is\n        assert_eq!(sig_to_file_name(\"0xnotahex\").as_str(), \"0xnotahex\");\n        // non-hex non-signature: should return input as-is\n        assert_eq!(sig_to_file_name(\"not_a_sig_or_hex\").as_str(), \"not_a_sig_or_hex\");\n    }\n}\n"
  },
  {
    "path": "crates/script-sequence/src/transaction.rs",
    "content": "use alloy_network::Network;\nuse alloy_primitives::{Address, B256, Bytes};\nuse foundry_common::TransactionMaybeSigned;\nuse revm_inspectors::tracing::types::CallKind;\nuse serde::{Deserialize, Serialize};\n\n#[derive(Clone, Debug, Default, Serialize, Deserialize)]\n#[serde(rename_all = \"camelCase\")]\npub struct AdditionalContract {\n    #[serde(rename = \"transactionType\")]\n    pub opcode: CallKind,\n    pub contract_name: Option<String>,\n    pub address: Address,\n    pub init_code: Bytes,\n}\n\n#[derive(Clone, Debug, Serialize, Deserialize)]\n#[serde(\n    rename_all = \"camelCase\",\n    bound(\n        serialize = \"N::TransactionRequest: Serialize, N::TxEnvelope: Serialize\",\n        deserialize = \"N::TransactionRequest: for<'de2> Deserialize<'de2>, N::TxEnvelope: for<'de2> Deserialize<'de2>\"\n    )\n)]\npub struct TransactionWithMetadata<N: Network> {\n    pub hash: Option<B256>,\n    #[serde(rename = \"transactionType\")]\n    pub opcode: CallKind,\n    #[serde(default = \"default_string\")]\n    pub contract_name: Option<String>,\n    #[serde(default = \"default_address\")]\n    pub contract_address: Option<Address>,\n    #[serde(default = \"default_string\")]\n    pub function: Option<String>,\n    #[serde(default = \"default_vec_of_strings\")]\n    pub arguments: Option<Vec<String>>,\n    #[serde(skip)]\n    pub rpc: String,\n    pub transaction: TransactionMaybeSigned<N>,\n    #[serde(default)]\n    pub additional_contracts: Vec<AdditionalContract>,\n    #[serde(default)]\n    pub is_fixed_gas_limit: bool,\n}\n\nfn default_string() -> Option<String> {\n    Some(String::new())\n}\n\nfn default_address() -> Option<Address> {\n    Some(Address::ZERO)\n}\n\nfn default_vec_of_strings() -> Option<Vec<String>> {\n    Some(vec![])\n}\n\nimpl<N: Network> TransactionWithMetadata<N> {\n    pub fn from_tx_request(transaction: TransactionMaybeSigned<N>) -> Self {\n        Self {\n            transaction,\n            hash: Default::default(),\n            opcode: Default::default(),\n            contract_name: Default::default(),\n            contract_address: Default::default(),\n            function: Default::default(),\n            arguments: Default::default(),\n            is_fixed_gas_limit: Default::default(),\n            additional_contracts: Default::default(),\n            rpc: Default::default(),\n        }\n    }\n\n    pub fn tx(&self) -> &TransactionMaybeSigned<N> {\n        &self.transaction\n    }\n\n    pub fn tx_mut(&mut self) -> &mut TransactionMaybeSigned<N> {\n        &mut self.transaction\n    }\n\n    pub fn is_create2(&self) -> bool {\n        self.opcode == CallKind::Create2\n    }\n}\n"
  },
  {
    "path": "crates/sol-macro-gen/Cargo.toml",
    "content": "[package]\nname = \"forge-sol-macro-gen\"\ndescription = \"Contains types and methods for generating rust bindings using sol!\"\npublish = false\n\nversion.workspace = true\nedition.workspace = true\nrust-version.workspace = true\nauthors.workspace = true\nlicense.workspace = true\nhomepage.workspace = true\nrepository.workspace = true\n\n[lints]\nworkspace = true\n\n[dependencies]\nalloy-sol-macro-input.workspace = true\nalloy-sol-macro-expander = { workspace = true, features = [\"json\"] }\nfoundry-common.workspace = true\n\nproc-macro2.workspace = true\nquote.workspace = true\nsyn.workspace = true\nprettyplease.workspace = true\n\neyre.workspace = true\n\nheck.workspace = true\n"
  },
  {
    "path": "crates/sol-macro-gen/src/lib.rs",
    "content": "//! This crate contains the logic for Rust bindings generating from Solidity contracts\n#![cfg_attr(not(test), warn(unused_crate_dependencies))]\n\npub mod sol_macro_gen;\n\npub use sol_macro_gen::*;\n"
  },
  {
    "path": "crates/sol-macro-gen/src/sol_macro_gen.rs",
    "content": "//! SolMacroGen and MultiSolMacroGen\n//!\n//! This type encapsulates the logic for expansion of a Rust TokenStream from Solidity tokens. It\n//! uses the `expand` method from `alloy_sol_macro_expander` underneath.\n//!\n//! It holds info such as `path` to the ABI file, `name` of the file and the rust binding being\n//! generated, and lastly the `expansion` itself, i.e the Rust binding for the provided ABI.\n//!\n//! It contains methods to read the json abi, generate rust bindings from the abi and ultimately\n//! write the bindings to a crate or modules.\n\nuse alloy_sol_macro_expander::expand::expand;\nuse alloy_sol_macro_input::{SolInput, SolInputKind};\nuse eyre::{Context, OptionExt, Result};\nuse foundry_common::fs;\nuse proc_macro2::{Span, TokenStream};\nuse std::{\n    fmt::Write,\n    path::{Path, PathBuf},\n    str::FromStr,\n};\n\nuse heck::ToSnakeCase;\n\npub struct SolMacroGen {\n    pub path: PathBuf,\n    pub name: String,\n    pub expansion: Option<TokenStream>,\n}\n\nimpl SolMacroGen {\n    pub fn new(path: PathBuf, name: String) -> Self {\n        Self { path, name, expansion: None }\n    }\n\n    pub fn get_sol_input(&self) -> Result<SolInput> {\n        let path = self.path.to_string_lossy().into_owned();\n        let name = proc_macro2::Ident::new(&self.name, Span::call_site());\n        let tokens = quote::quote! {\n            #[sol(ignore_unlinked)]\n            #name,\n            #path\n        };\n\n        let sol_input: SolInput = syn::parse2(tokens).wrap_err(\"failed to parse input\")?;\n\n        Ok(sol_input)\n    }\n}\n\npub struct MultiSolMacroGen {\n    pub instances: Vec<SolMacroGen>,\n}\n\nimpl MultiSolMacroGen {\n    pub fn new(instances: Vec<SolMacroGen>) -> Self {\n        Self { instances }\n    }\n\n    pub fn populate_expansion(&mut self, bindings_path: &Path) -> Result<()> {\n        for instance in &mut self.instances {\n            let path = bindings_path.join(format!(\"{}.rs\", instance.name.to_snake_case()));\n            let expansion = fs::read_to_string(path).wrap_err(\"Failed to read file\")?;\n\n            let tokens = TokenStream::from_str(&expansion)\n                .map_err(|e| eyre::eyre!(\"Failed to parse TokenStream: {e}\"))?;\n            instance.expansion = Some(tokens);\n        }\n        Ok(())\n    }\n\n    pub fn generate_bindings(&mut self, all_derives: bool) -> Result<()> {\n        for instance in &mut self.instances {\n            Self::generate_binding(instance, all_derives).wrap_err_with(|| {\n                format!(\n                    \"failed to generate bindings for {}:{}\",\n                    instance.path.display(),\n                    instance.name\n                )\n            })?;\n        }\n\n        Ok(())\n    }\n\n    fn generate_binding(instance: &mut SolMacroGen, all_derives: bool) -> Result<()> {\n        let input = instance.get_sol_input()?.normalize_json()?;\n        let SolInput { attrs: _, path: _, kind } = input;\n\n        let tokens = match kind {\n            SolInputKind::Sol(mut file) => {\n                let sol_attr: syn::Attribute = if all_derives {\n                    syn::parse_quote! {\n                            #[sol(rpc, alloy_sol_types = alloy::sol_types, alloy_contract =\n                    alloy::contract, all_derives = true, extra_derives(serde::Serialize,\n                    serde::Deserialize))]     }\n                } else {\n                    syn::parse_quote! {\n                            #[sol(rpc, alloy_sol_types = alloy::sol_types, alloy_contract =\n                    alloy::contract)]     }\n                };\n                file.attrs.push(sol_attr);\n                expand(file).wrap_err(\"failed to expand\")?\n            }\n            _ => unreachable!(),\n        };\n\n        instance.expansion = Some(tokens);\n        Ok(())\n    }\n\n    #[allow(clippy::too_many_arguments)]\n    pub fn write_to_crate(\n        &mut self,\n        name: &str,\n        version: &str,\n        description: &str,\n        license: &str,\n        bindings_path: &Path,\n        single_file: bool,\n        alloy_version: Option<String>,\n        alloy_rev: Option<String>,\n        all_derives: bool,\n    ) -> Result<()> {\n        self.generate_bindings(all_derives)?;\n\n        let src = bindings_path.join(\"src\");\n        fs::create_dir_all(&src)?;\n\n        // Write Cargo.toml\n        let cargo_toml_path = bindings_path.join(\"Cargo.toml\");\n        let mut toml_contents = format!(\n            r#\"[package]\nname = \"{name}\"\nversion = \"{version}\"\nedition = \"2021\"\n\"#\n        );\n\n        if !description.is_empty() {\n            toml_contents.push_str(&format!(\"description = \\\"{description}\\\"\\n\"));\n        }\n\n        if !license.is_empty() {\n            let formatted_licenses: Vec<String> =\n                license.split(',').map(Self::parse_license_alias).collect();\n\n            let formatted_license = formatted_licenses.join(\" OR \");\n            toml_contents.push_str(&format!(\"license = \\\"{formatted_license}\\\"\\n\"));\n        }\n\n        toml_contents.push_str(\"\\n[dependencies]\\n\");\n\n        let alloy_dep = Self::get_alloy_dep(alloy_version, alloy_rev);\n        write!(toml_contents, \"{alloy_dep}\")?;\n\n        if all_derives {\n            let serde_dep = r#\"serde = { version = \"1.0\", features = [\"derive\"] }\"#;\n            write!(toml_contents, \"\\n{serde_dep}\")?;\n        }\n\n        fs::write(cargo_toml_path, toml_contents).wrap_err(\"Failed to write Cargo.toml\")?;\n\n        let mut lib_contents = String::new();\n        write!(\n            &mut lib_contents,\n            r#\"#![allow(unused_imports, unused_attributes, clippy::all, rustdoc::all)]\n        //! This module contains the sol! generated bindings for solidity contracts.\n        //! This is autogenerated code.\n        //! Do not manually edit these files.\n        //! These files may be overwritten by the codegen system at any time.\n        \"#\n        )?;\n\n        // Write src\n        let parse_error = |name: &str| {\n            format!(\"failed to parse generated tokens as an AST for {name};\\nthis is likely a bug\")\n        };\n        for instance in &self.instances {\n            let contents = instance.expansion.as_ref().unwrap();\n\n            let name = instance.name.to_snake_case();\n            let path = src.join(format!(\"{name}.rs\"));\n            let file = syn::parse2(contents.clone())\n                .wrap_err_with(|| parse_error(&format!(\"{}:{}\", path.display(), name)))?;\n            let contents = prettyplease::unparse(&file);\n            if single_file {\n                write!(&mut lib_contents, \"{contents}\")?;\n            } else {\n                fs::write(path, contents).wrap_err(\"failed to write to file\")?;\n                write_mod_name(&mut lib_contents, &name)?;\n            }\n        }\n\n        let lib_path = src.join(\"lib.rs\");\n        let lib_file = syn::parse_file(&lib_contents).wrap_err_with(|| parse_error(\"lib.rs\"))?;\n        let lib_contents = prettyplease::unparse(&lib_file);\n        fs::write(lib_path, lib_contents).wrap_err(\"Failed to write lib.rs\")?;\n\n        Ok(())\n    }\n\n    /// Attempts to detect the appropriate license.\n    pub fn parse_license_alias(license: &str) -> String {\n        match license.trim().to_lowercase().as_str() {\n            \"mit\" => \"MIT\".to_string(),\n            \"apache\" | \"apache2\" | \"apache20\" | \"apache2.0\" => \"Apache-2.0\".to_string(),\n            \"gpl\" | \"gpl3\" => \"GPL-3.0\".to_string(),\n            \"lgpl\" | \"lgpl3\" => \"LGPL-3.0\".to_string(),\n            \"agpl\" | \"agpl3\" => \"AGPL-3.0\".to_string(),\n            \"bsd\" | \"bsd3\" => \"BSD-3-Clause\".to_string(),\n            \"bsd2\" => \"BSD-2-Clause\".to_string(),\n            \"mpl\" | \"mpl2\" => \"MPL-2.0\".to_string(),\n            \"isc\" => \"ISC\".to_string(),\n            \"unlicense\" => \"Unlicense\".to_string(),\n            _ => license.trim().to_string(),\n        }\n    }\n\n    pub fn write_to_module(\n        &mut self,\n        bindings_path: &Path,\n        single_file: bool,\n        all_derives: bool,\n    ) -> Result<()> {\n        self.generate_bindings(all_derives)?;\n\n        fs::create_dir_all(bindings_path)?;\n\n        let mut mod_contents =\n            r#\"#![allow(unused_imports, unused_attributes, clippy::all, rustdoc::all)]\n        //! This module contains the sol! generated bindings for solidity contracts.\n        //! This is autogenerated code.\n        //! Do not manually edit these files.\n        //! These files may be overwritten by the codegen system at any time.\n        \"#\n            .to_string();\n\n        for instance in &self.instances {\n            let name = instance.name.to_snake_case();\n            if !single_file {\n                // Module\n                write_mod_name(&mut mod_contents, &name)?;\n                let mut contents = String::new();\n\n                write!(contents, \"{}\", instance.expansion.as_ref().unwrap())?;\n                let file = syn::parse_file(&contents)?;\n\n                let contents = prettyplease::unparse(&file);\n                fs::write(bindings_path.join(format!(\"{name}.rs\")), contents)\n                    .wrap_err(\"Failed to write file\")?;\n            } else {\n                // Single File\n                let mut contents = String::new();\n                write!(contents, \"{}\\n\\n\", instance.expansion.as_ref().unwrap())?;\n                write!(mod_contents, \"{contents}\")?;\n            }\n        }\n\n        let mod_path = bindings_path.join(\"mod.rs\");\n        let mod_file = syn::parse_file(&mod_contents)?;\n        let mod_contents = prettyplease::unparse(&mod_file);\n\n        fs::write(mod_path, mod_contents).wrap_err(\"Failed to write mod.rs\")?;\n\n        Ok(())\n    }\n\n    /// Checks that the generated bindings are up to date with the latest version of\n    /// `sol!`.\n    ///\n    /// Returns `Ok(())` if the generated bindings are up to date, otherwise it returns\n    /// `Err(_)`.\n    #[expect(clippy::too_many_arguments)]\n    pub fn check_consistency(\n        &self,\n        name: &str,\n        version: &str,\n        crate_path: &Path,\n        single_file: bool,\n        check_cargo_toml: bool,\n        is_mod: bool,\n        alloy_version: Option<String>,\n        alloy_rev: Option<String>,\n    ) -> Result<()> {\n        if check_cargo_toml && !is_mod {\n            self.check_cargo_toml(name, version, crate_path, alloy_version, alloy_rev)?;\n        }\n\n        let mut super_contents = String::new();\n        write!(\n            &mut super_contents,\n            r#\"#![allow(unused_imports, unused_attributes, clippy::all, rustdoc::all)]\n            //! This module contains the sol! generated bindings for solidity contracts.\n            //! This is autogenerated code.\n            //! Do not manually edit these files.\n            //! These files may be overwritten by the codegen system at any time.\n            \"#\n        )?;\n        if !single_file {\n            for instance in &self.instances {\n                let name = instance.name.to_snake_case();\n                let path = if is_mod {\n                    crate_path.join(format!(\"{name}.rs\"))\n                } else {\n                    crate_path.join(format!(\"src/{name}.rs\"))\n                };\n                let tokens = instance\n                    .expansion\n                    .as_ref()\n                    .ok_or_eyre(format!(\"TokenStream for {path:?} does not exist\"))?\n                    .to_string();\n\n                self.check_file_contents(&path, &tokens)?;\n                write_mod_name(&mut super_contents, &name)?;\n            }\n\n            let super_path =\n                if is_mod { crate_path.join(\"mod.rs\") } else { crate_path.join(\"src/lib.rs\") };\n            self.check_file_contents(&super_path, &super_contents)?;\n        }\n\n        Ok(())\n    }\n\n    fn check_file_contents(&self, file_path: &Path, expected_contents: &str) -> Result<()> {\n        eyre::ensure!(file_path.is_file(), \"{} is not a file\", file_path.display());\n        let file_contents = &fs::read_to_string(file_path).wrap_err(\"Failed to read file\")?;\n\n        // Format both\n        let file_contents = syn::parse_file(file_contents)?;\n        let formatted_file = prettyplease::unparse(&file_contents);\n\n        let expected_contents = syn::parse_file(expected_contents)?;\n        let formatted_exp = prettyplease::unparse(&expected_contents);\n\n        eyre::ensure!(\n            formatted_file == formatted_exp,\n            \"File contents do not match expected contents for {file_path:?}\"\n        );\n        Ok(())\n    }\n\n    fn check_cargo_toml(\n        &self,\n        name: &str,\n        version: &str,\n        crate_path: &Path,\n        alloy_version: Option<String>,\n        alloy_rev: Option<String>,\n    ) -> Result<()> {\n        eyre::ensure!(crate_path.is_dir(), \"Crate path must be a directory\");\n\n        let cargo_toml_path = crate_path.join(\"Cargo.toml\");\n\n        eyre::ensure!(cargo_toml_path.is_file(), \"Cargo.toml must exist\");\n        let cargo_toml_contents =\n            fs::read_to_string(cargo_toml_path).wrap_err(\"Failed to read Cargo.toml\")?;\n\n        let name_check = format!(\"name = \\\"{name}\\\"\");\n        let version_check = format!(\"version = \\\"{version}\\\"\");\n        let alloy_dep_check = Self::get_alloy_dep(alloy_version, alloy_rev);\n        let toml_consistent = cargo_toml_contents.contains(&name_check)\n            && cargo_toml_contents.contains(&version_check)\n            && cargo_toml_contents.contains(&alloy_dep_check);\n        eyre::ensure!(\n            toml_consistent,\n            r#\"The contents of Cargo.toml do not match the expected output of the latest `sol!` version.\n                This indicates that the existing bindings are outdated and need to be generated again.\"#\n        );\n\n        Ok(())\n    }\n\n    /// Returns the `alloy` dependency string for the Cargo.toml file.\n    /// If `alloy_version` is provided, it will use that version from crates.io.\n    /// If `alloy_rev` is provided, it will use that revision from the GitHub repository.\n    fn get_alloy_dep(alloy_version: Option<String>, alloy_rev: Option<String>) -> String {\n        if let Some(alloy_version) = alloy_version {\n            format!(\n                r#\"alloy = {{ version = \"{alloy_version}\", features = [\"sol-types\", \"contract\"] }}\"#,\n            )\n        } else if let Some(alloy_rev) = alloy_rev {\n            format!(\n                r#\"alloy = {{ git = \"https://github.com/alloy-rs/alloy\", rev = \"{alloy_rev}\", features = [\"sol-types\", \"contract\"] }}\"#,\n            )\n        } else {\n            r#\"alloy = { version = \"1.0\", features = [\"sol-types\", \"contract\"] }\"#.to_string()\n        }\n    }\n}\n\nfn write_mod_name(contents: &mut String, name: &str) -> Result<()> {\n    if syn::parse_str::<syn::Ident>(name).is_ok() {\n        write!(contents, \"pub mod {name};\")?;\n    } else {\n        write!(contents, \"pub mod r#{name};\")?;\n    }\n    Ok(())\n}\n"
  },
  {
    "path": "crates/test-utils/Cargo.toml",
    "content": "[package]\nname = \"foundry-test-utils\"\ndescription = \"Foundry testing utilities\"\npublish = false\n\nversion.workspace = true\nedition.workspace = true\nrust-version.workspace = true\nauthors.workspace = true\nlicense.workspace = true\nhomepage.workspace = true\nrepository.workspace = true\n\n[lints]\nworkspace = true\n\n[dependencies]\nfoundry-block-explorers.workspace = true\nfoundry-common.workspace = true\nfoundry-compilers = { workspace = true, features = [\"project-util\"] }\nfoundry-config.workspace = true\n\nalloy-chains.workspace = true\nalloy-primitives.workspace = true\nalloy-provider.workspace = true\n\neyre.workspace = true\nfd-lock = \"4.0\"\nparking_lot.workspace = true\nregex.workspace = true\nserde_json.workspace = true\ntracing.workspace = true\ntracing-subscriber = { workspace = true, features = [\"env-filter\"] }\nrand.workspace = true\nsnapbox.workspace = true\ntempfile.workspace = true\nui_test = \"0.30.4\"\nreqwest.workspace = true\nsvm.workspace = true\n\n# Pinned dependencies. See /Cargo.toml.\n[target.'cfg(any())'.dependencies]\nidna_adapter.workspace = true\n\n[dev-dependencies]\ntokio.workspace = true\n"
  },
  {
    "path": "crates/test-utils/src/etherscan.rs",
    "content": "//! Etherscan utilities for tests.\n\nuse alloy_chains::Chain;\nuse alloy_primitives::Address;\nuse eyre::Result;\nuse foundry_block_explorers::Client;\nuse foundry_common::{compile::etherscan_project, flatten};\nuse std::str::FromStr;\n\n/// Fetches the source code of a verified contract from Etherscan, flattens it, and returns it.\n///\n/// This provides the same functionality as `cast source --flatten` but using the library directly,\n/// avoiding the need to shell out to the `cast` binary.\npub async fn fetch_etherscan_source_flattened(\n    address: &str,\n    etherscan_api_key: &str,\n    chain: Chain,\n) -> Result<String> {\n    let client = Client::builder().chain(chain)?.with_api_key(etherscan_api_key).build()?;\n\n    let address = Address::from_str(address)?;\n    let metadata = client.contract_source_code(address).await?;\n    let Some(metadata) = metadata.items.first() else {\n        eyre::bail!(\"Empty contract source code for {address}\")\n    };\n\n    let tmp = tempfile::tempdir()?;\n    let project = etherscan_project(metadata, tmp.path())?;\n    let target_path = project.find_contract_path(&metadata.contract_name)?;\n\n    flatten(project, &target_path)\n}\n"
  },
  {
    "path": "crates/test-utils/src/ext.rs",
    "content": "use crate::prj::{TestCommand, TestProject, clone_remote, setup_forge};\nuse foundry_compilers::PathStyle;\nuse std::process::Command;\n\n/// External test builder\n#[derive(Clone, Debug)]\n#[must_use = \"ExtTester does nothing unless you `run` it\"]\npub struct ExtTester {\n    pub org: &'static str,\n    pub name: &'static str,\n    pub rev: &'static str,\n    pub style: PathStyle,\n    pub fork_block: Option<u64>,\n    pub args: Vec<String>,\n    pub envs: Vec<(String, String)>,\n    pub install_commands: Vec<Vec<String>>,\n    pub verbosity: String,\n}\n\nimpl ExtTester {\n    /// Creates a new external test builder.\n    pub fn new(org: &'static str, name: &'static str, rev: &'static str) -> Self {\n        Self {\n            org,\n            name,\n            rev,\n            style: PathStyle::Dapptools,\n            fork_block: None,\n            args: vec![],\n            envs: vec![],\n            install_commands: vec![],\n            verbosity: \"-vvv\".to_string(),\n        }\n    }\n\n    /// Sets the path style.\n    pub fn style(mut self, style: PathStyle) -> Self {\n        self.style = style;\n        self\n    }\n\n    /// Sets the fork block.\n    pub fn fork_block(mut self, fork_block: u64) -> Self {\n        self.fork_block = Some(fork_block);\n        self\n    }\n\n    /// Adds an argument to the forge command.\n    pub fn arg(mut self, arg: impl Into<String>) -> Self {\n        self.args.push(arg.into());\n        self\n    }\n\n    /// Adds multiple arguments to the forge command.\n    pub fn args<I, A>(mut self, args: I) -> Self\n    where\n        I: IntoIterator<Item = A>,\n        A: Into<String>,\n    {\n        self.args.extend(args.into_iter().map(Into::into));\n        self\n    }\n\n    /// Sets the verbosity\n    pub fn verbosity(mut self, verbosity: usize) -> Self {\n        self.verbosity = format!(\"-{}\", \"v\".repeat(verbosity));\n        self\n    }\n\n    /// Adds an environment variable to the forge command.\n    pub fn env(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {\n        self.envs.push((key.into(), value.into()));\n        self\n    }\n\n    /// Adds multiple environment variables to the forge command.\n    pub fn envs<I, K, V>(mut self, envs: I) -> Self\n    where\n        I: IntoIterator<Item = (K, V)>,\n        K: Into<String>,\n        V: Into<String>,\n    {\n        self.envs.extend(envs.into_iter().map(|(k, v)| (k.into(), v.into())));\n        self\n    }\n\n    /// Adds a command to run after the project is cloned.\n    ///\n    /// Note that the command is run in the project's root directory, and it won't fail the test if\n    /// it fails.\n    pub fn install_command(mut self, command: &[&str]) -> Self {\n        self.install_commands.push(command.iter().map(|s| s.to_string()).collect());\n        self\n    }\n\n    pub fn setup_forge_prj(&self, recursive: bool) -> (TestProject, TestCommand) {\n        let (prj, mut test_cmd) = setup_forge(self.name, self.style.clone());\n\n        // Export vyper and forge in test command - workaround for snekmate venom tests.\n        if let Some(vyper) = &prj.inner.project().compiler.vyper {\n            let vyper_dir = vyper.path.parent().expect(\"vyper path should have a parent\");\n            let forge_bin = prj.forge_path();\n            let forge_dir = forge_bin.parent().expect(\"forge path should have a parent\");\n\n            let existing_path = std::env::var_os(\"PATH\").unwrap_or_default();\n            let mut new_paths = vec![vyper_dir.to_path_buf(), forge_dir.to_path_buf()];\n            new_paths.extend(std::env::split_paths(&existing_path));\n\n            let joined_path = std::env::join_paths(new_paths).expect(\"failed to join PATH\");\n            test_cmd.env(\"PATH\", joined_path);\n        }\n\n        // Wipe the default structure.\n        prj.wipe();\n\n        // Clone the external repository.\n        let repo_url = format!(\"https://github.com/{}/{}.git\", self.org, self.name);\n        let root = prj.root().to_str().unwrap();\n        clone_remote(&repo_url, root, recursive);\n\n        // Checkout the revision.\n        if self.rev.is_empty() {\n            let mut git = Command::new(\"git\");\n            git.current_dir(root).args([\"log\", \"-n\", \"1\"]);\n            test_debug!(\"$ {git:?}\");\n            let output = git.output().unwrap();\n            if !output.status.success() {\n                panic!(\"git log failed: {output:?}\");\n            }\n            let stdout = String::from_utf8(output.stdout).unwrap();\n            let commit = stdout.lines().next().unwrap().split_whitespace().nth(1).unwrap();\n            panic!(\"pin to latest commit: {commit}\");\n        } else {\n            let mut git = Command::new(\"git\");\n            git.current_dir(root).args([\"checkout\", self.rev]);\n            test_debug!(\"$ {git:?}\");\n            let status = git.status().unwrap();\n            if !status.success() {\n                panic!(\"git checkout failed: {status}\");\n            }\n        }\n\n        (prj, test_cmd)\n    }\n\n    pub fn run_install_commands(&self, root: &str) {\n        for install_command in &self.install_commands {\n            let mut install_cmd = Command::new(&install_command[0]);\n            install_cmd.args(&install_command[1..]).current_dir(root);\n            test_debug!(\"cd {root}; {install_cmd:?}\");\n            match install_cmd.status() {\n                Ok(s) => {\n                    test_debug!(\"\\n\\n{install_cmd:?}: {s}\");\n                    if s.success() {\n                        break;\n                    }\n                }\n                Err(e) => {\n                    eprintln!(\"\\n\\n{install_cmd:?}: {e}\");\n                }\n            }\n        }\n    }\n\n    /// Runs the test.\n    pub fn run(&self) {\n        let (prj, mut test_cmd) = self.setup_forge_prj(true);\n\n        // Run installation command.\n        self.run_install_commands(prj.root().to_str().unwrap());\n\n        // Run the tests.\n        test_cmd.arg(\"test\");\n        test_cmd.args(&self.args);\n        test_cmd.args([\"--fuzz-runs=32\", \"--ffi\", &self.verbosity]);\n\n        test_cmd.envs(self.envs.iter().map(|(k, v)| (k, v)));\n        if let Some(fork_block) = self.fork_block {\n            test_cmd.env(\"FOUNDRY_ETH_RPC_URL\", crate::rpc::next_http_archive_rpc_url());\n            test_cmd.env(\"FOUNDRY_FORK_BLOCK_NUMBER\", fork_block.to_string());\n        }\n        test_cmd.env(\"FOUNDRY_INVARIANT_DEPTH\", \"15\");\n        test_cmd.env(\"FOUNDRY_ALLOW_INTERNAL_EXPECT_REVERT\", \"true\");\n\n        test_cmd.assert_success();\n    }\n}\n"
  },
  {
    "path": "crates/test-utils/src/fd_lock.rs",
    "content": "//! File locking utilities.\n\nuse crate::util::pretty_err;\nuse std::{\n    fs::{File, OpenOptions},\n    path::Path,\n};\n\npub use fd_lock::*;\n\n/// Creates a new lock file at the given path.\npub fn new_lock(lock_path: impl AsRef<Path>) -> RwLock<File> {\n    fn new_lock(lock_path: &Path) -> RwLock<File> {\n        let lock_file = pretty_err(\n            lock_path,\n            OpenOptions::new().read(true).write(true).create(true).truncate(false).open(lock_path),\n        );\n        RwLock::new(lock_file)\n    }\n    new_lock(lock_path.as_ref())\n}\n\npub(crate) const LOCK_TOKEN: &[u8] = b\"1\";\n\npub(crate) fn lock_exists(lock_path: &Path) -> bool {\n    std::fs::read(lock_path).is_ok_and(|b| b == LOCK_TOKEN)\n}\n"
  },
  {
    "path": "crates/test-utils/src/filter.rs",
    "content": "use foundry_common::TestFilter;\nuse regex::Regex;\nuse std::path::Path;\n\n#[derive(Clone, Debug)]\npub struct Filter {\n    test_regex: Regex,\n    contract_regex: Regex,\n    path_regex: Regex,\n    exclude_tests: Option<Regex>,\n    exclude_contracts: Option<Regex>,\n    exclude_paths: Option<Regex>,\n}\n\nimpl Filter {\n    pub fn new(test_pattern: &str, contract_pattern: &str, path_pattern: &str) -> Self {\n        Self {\n            test_regex: Regex::new(test_pattern)\n                .unwrap_or_else(|_| panic!(\"Failed to parse test pattern: `{test_pattern}`\")),\n            contract_regex: Regex::new(contract_pattern).unwrap_or_else(|_| {\n                panic!(\"Failed to parse contract pattern: `{contract_pattern}`\")\n            }),\n            path_regex: Regex::new(path_pattern)\n                .unwrap_or_else(|_| panic!(\"Failed to parse path pattern: `{path_pattern}`\")),\n            exclude_tests: None,\n            exclude_contracts: None,\n            exclude_paths: None,\n        }\n    }\n\n    pub fn contract(contract_pattern: &str) -> Self {\n        Self::new(\".*\", contract_pattern, \".*\")\n    }\n\n    pub fn path(path_pattern: &str) -> Self {\n        Self::new(\".*\", \".*\", path_pattern)\n    }\n\n    /// All tests to also exclude\n    ///\n    /// This is a workaround since regex does not support negative look aheads\n    pub fn exclude_tests(mut self, pattern: &str) -> Self {\n        self.exclude_tests = Some(Regex::new(pattern).unwrap());\n        self\n    }\n\n    /// All contracts to also exclude\n    ///\n    /// This is a workaround since regex does not support negative look aheads\n    pub fn exclude_contracts(mut self, pattern: &str) -> Self {\n        self.exclude_contracts = Some(Regex::new(pattern).unwrap());\n        self\n    }\n\n    /// All paths to also exclude\n    ///\n    /// This is a workaround since regex does not support negative look aheads\n    pub fn exclude_paths(mut self, pattern: &str) -> Self {\n        self.exclude_paths = Some(Regex::new(pattern).unwrap());\n        self\n    }\n\n    pub fn matches_all() -> Self {\n        Self {\n            test_regex: Regex::new(\".*\").unwrap(),\n            contract_regex: Regex::new(\".*\").unwrap(),\n            path_regex: Regex::new(\".*\").unwrap(),\n            exclude_tests: None,\n            exclude_contracts: None,\n            exclude_paths: None,\n        }\n    }\n}\n\nimpl TestFilter for Filter {\n    fn matches_test(&self, test_signature: &str) -> bool {\n        if let Some(exclude) = &self.exclude_tests\n            && exclude.is_match(test_signature)\n        {\n            return false;\n        }\n        self.test_regex.is_match(test_signature)\n    }\n\n    fn matches_contract(&self, contract_name: &str) -> bool {\n        if let Some(exclude) = &self.exclude_contracts\n            && exclude.is_match(contract_name)\n        {\n            return false;\n        }\n\n        self.contract_regex.is_match(contract_name)\n    }\n\n    fn matches_path(&self, path: &Path) -> bool {\n        let Some(path) = path.to_str() else {\n            return false;\n        };\n\n        if let Some(exclude) = &self.exclude_paths\n            && exclude.is_match(path)\n        {\n            return false;\n        }\n        self.path_regex.is_match(path)\n    }\n}\n"
  },
  {
    "path": "crates/test-utils/src/lib.rs",
    "content": "//! # foundry-test-utils\n//!\n//! Internal Foundry testing utilities.\n\n#![cfg_attr(not(test), warn(unused_crate_dependencies))]\n#![cfg_attr(docsrs, feature(doc_cfg))]\n// Shouldn't use sh_* macros here, as they don't get captured by the test runner.\n#![allow(clippy::disallowed_macros)]\n\n#[macro_use]\nextern crate tracing;\n\n// Macros useful for testing.\n#[macro_use]\nmod macros;\n\npub mod etherscan;\npub mod rpc;\n\npub mod fd_lock;\n\nmod filter;\npub use filter::Filter;\n\nmod ext;\npub use ext::ExtTester;\n\nmod prj;\npub use prj::{TestCommand, TestProject};\n\n// Utilities for making it easier to handle tests.\npub mod util;\n\nmod script;\npub use script::{ScriptOutcome, ScriptTester};\n\npub mod ui_runner;\n\n// re-exports for convenience\npub use foundry_compilers;\n\npub use snapbox::{self, assert_data_eq, file, str};\n\n/// Initializes tracing for tests.\npub fn init_tracing() {\n    use std::sync::Once;\n    static ONCE: Once = Once::new();\n    ONCE.call_once(|| {\n        if std::env::var_os(\"RUST_BACKTRACE\").is_none() {\n            unsafe { std::env::set_var(\"RUST_BACKTRACE\", \"1\") };\n        }\n        let _ = tracing_subscriber::FmtSubscriber::builder()\n            .with_env_filter(env_filter())\n            .with_test_writer()\n            .try_init();\n        let _ = ui_test::color_eyre::install();\n    });\n}\n\nfn env_filter() -> tracing_subscriber::EnvFilter {\n    const DEFAULT_DIRECTIVES: &[&str] = &include!(\"../../cli/src/utils/default_directives.txt\");\n    let mut filter = tracing_subscriber::EnvFilter::builder()\n        .with_default_directive(\"foundry_test_utils=debug\".parse().unwrap())\n        .from_env_lossy();\n    for &directive in DEFAULT_DIRECTIVES {\n        filter = filter.add_directive(directive.parse().unwrap());\n    }\n    filter\n}\n\npub fn test_debug(args: std::fmt::Arguments<'_>) {\n    init_tracing();\n    debug!(\"{args}\");\n}\n\npub fn test_trace(args: std::fmt::Arguments<'_>) {\n    init_tracing();\n    trace!(\"{args}\");\n}\n"
  },
  {
    "path": "crates/test-utils/src/macros.rs",
    "content": "/// A macro to generate a new integration test case\n///\n/// The `forgetest!` macro's first argument is the name of the test, the second argument is a\n/// closure to configure and execute the test. The `TestProject` provides utility functions to setup\n/// the project's workspace. The `TestCommand` is a wrapper around the actual `forge` executable\n/// that this then executed with the configured command arguments.\n#[macro_export]\nmacro_rules! forgetest {\n    ($(#[$attr:meta])* $test:ident, |$prj:ident, $cmd:ident| $e:expr) => {\n        $crate::forgetest!($(#[$attr])* $test, $crate::foundry_compilers::PathStyle::Dapptools, |$prj, $cmd| $e);\n    };\n    ($(#[$attr:meta])* $test:ident, $style:expr, |$prj:ident, $cmd:ident| $e:expr) => {\n        #[expect(clippy::disallowed_macros)]\n        #[test]\n        $(#[$attr])*\n        fn $test() {\n            let (mut $prj, mut $cmd) = $crate::util::setup_forge(stringify!($test), $style);\n            $e\n        }\n    };\n}\n\n#[macro_export]\nmacro_rules! forgetest_async {\n    ($(#[$attr:meta])* $test:ident, |$prj:ident, $cmd:ident| $e:expr) => {\n        $crate::forgetest_async!($(#[$attr])* $test, $crate::foundry_compilers::PathStyle::Dapptools, |$prj, $cmd| $e);\n    };\n    ($(#[$attr:meta])* $test:ident, $style:expr, |$prj:ident, $cmd:ident| $e:expr) => {\n        #[expect(clippy::disallowed_macros)]\n        #[tokio::test(flavor = \"multi_thread\")]\n        $(#[$attr])*\n        async fn $test() {\n            let (mut $prj, mut $cmd) = $crate::util::setup_forge(stringify!($test), $style);\n            $e;\n            return (); // Works around weird method resolution in `$e` due to `#[tokio::test]`.\n        }\n    };\n}\n\n#[macro_export]\nmacro_rules! casttest {\n    ($(#[$attr:meta])* $test:ident, $($async:ident)? |$prj:ident, $cmd:ident| $e:expr) => {\n        $crate::casttest!($(#[$attr])* $test, $crate::foundry_compilers::PathStyle::Dapptools, $($async)? |$prj, $cmd| $e);\n    };\n    ($(#[$attr:meta])* $test:ident, $style:expr, |$prj:ident, $cmd:ident| $e:expr) => {\n        #[expect(clippy::disallowed_macros)]\n        #[test]\n        $(#[$attr])*\n        fn $test() {\n            let (mut $prj, mut $cmd) = $crate::util::setup_cast(stringify!($test), $style);\n            $e\n        }\n    };\n    ($(#[$attr:meta])* $test:ident, $style:expr, async |$prj:ident, $cmd:ident| $e:expr) => {\n        #[expect(clippy::disallowed_macros)]\n        #[tokio::test(flavor = \"multi_thread\")]\n        $(#[$attr])*\n        async fn $test() {\n            let (mut $prj, mut $cmd) = $crate::util::setup_cast(stringify!($test), $style);\n            $e;\n            return (); // Works around weird method resolution in `$e` due to `#[tokio::test]`.\n        }\n    };\n}\n\n/// Same as `forgetest` but returns an already initialized project workspace (`forge init --empty`).\n#[macro_export]\nmacro_rules! forgetest_init {\n    ($(#[$attr:meta])* $test:ident, |$prj:ident, $cmd:ident| $e:expr) => {\n        $crate::forgetest_init!($(#[$attr])* $test, $crate::foundry_compilers::PathStyle::Dapptools, |$prj, $cmd| $e);\n    };\n    ($(#[$attr:meta])* $test:ident, $style:expr, |$prj:ident, $cmd:ident| $e:expr) => {\n        #[test]\n        $(#[$attr])*\n        fn $test() {\n            let (mut $prj, mut $cmd) = $crate::util::setup_forge(stringify!($test), $style);\n            $crate::util::initialize($prj.root());\n            $e\n        }\n    };\n}\n\n/// Setup forge soldeer\n#[macro_export]\nmacro_rules! forgesoldeer {\n    ($(#[$attr:meta])* $test:ident, |$prj:ident, $cmd:ident| $e:expr) => {\n        $crate::forgesoldeer!($(#[$attr])* $test, $crate::foundry_compilers::PathStyle::Dapptools, |$prj, $cmd| $e);\n    };\n    ($(#[$attr:meta])* $test:ident, $style:expr, |$prj:ident, $cmd:ident| $e:expr) => {\n        #[expect(clippy::disallowed_macros)]\n        #[test]\n        $(#[$attr])*\n        fn $test() {\n            let (mut $prj, mut $cmd) = $crate::util::setup_forge(stringify!($test), $style);\n            $crate::util::initialize($prj.root());\n            $e\n        }\n    };\n}\n\n#[macro_export]\nmacro_rules! test_debug {\n    ($($args:tt)*) => {\n        $crate::test_debug(format_args!($($args)*))\n    }\n}\n\n#[macro_export]\nmacro_rules! test_trace {\n    ($($args:tt)*) => {\n        $crate::test_trace(format_args!($($args)*))\n    }\n}\n"
  },
  {
    "path": "crates/test-utils/src/prj.rs",
    "content": "use crate::{init_tracing, rpc::rpc_endpoints};\nuse eyre::{Result, WrapErr};\nuse foundry_compilers::{\n    ArtifactOutput, ConfigurableArtifacts, PathStyle, ProjectPathsConfig, artifacts::Contract,\n    cache::CompilerCache, compilers::multi::MultiCompiler, project_util::TempProject,\n    solc::SolcSettings,\n};\nuse foundry_config::Config;\nuse parking_lot::Mutex;\nuse regex::Regex;\nuse snapbox::{Data, IntoData, assert_data_eq, cmd::OutputAssert};\nuse std::{\n    env,\n    ffi::OsStr,\n    fs::{self, File},\n    io::{BufWriter, Write},\n    path::{Path, PathBuf},\n    process::{Command, Output, Stdio},\n    sync::{\n        Arc, LazyLock,\n        atomic::{AtomicUsize, Ordering},\n    },\n};\n\nuse crate::util::{SOLC_VERSION, copy_dir_filtered, pretty_err};\n\nstatic CURRENT_DIR_LOCK: LazyLock<Mutex<()>> = LazyLock::new(|| Mutex::new(()));\n\n/// Global test identifier.\nstatic NEXT_ID: AtomicUsize = AtomicUsize::new(0);\n\n/// Clones a remote repository into the specified directory. Panics if the command fails.\npub fn clone_remote(repo_url: &str, target_dir: &str, recursive: bool) {\n    let mut cmd = Command::new(\"git\");\n    cmd.args([\"clone\"]);\n    if recursive {\n        cmd.args([\"--recursive\", \"--shallow-submodules\"]);\n    } else {\n        cmd.args([\"--depth=1\", \"--no-checkout\", \"--filter=blob:none\", \"--no-recurse-submodules\"]);\n    }\n    cmd.args([repo_url, target_dir]);\n    test_debug!(\"{cmd:?}\");\n    let status = cmd.status().unwrap();\n    if !status.success() {\n        panic!(\"git clone failed: {status}\");\n    }\n}\n\n/// Setup an empty test project and return a command pointing to the forge\n/// executable whose CWD is set to the project's root.\n///\n/// The name given will be used to create the directory. Generally, it should\n/// correspond to the test name.\n#[track_caller]\npub fn setup_forge(name: &str, style: PathStyle) -> (TestProject, TestCommand) {\n    setup_forge_project(TestProject::new(name, style))\n}\n\npub fn setup_forge_project(test: TestProject) -> (TestProject, TestCommand) {\n    let cmd = test.forge_command();\n    (test, cmd)\n}\n\n/// How to initialize a remote git project\n#[derive(Clone, Debug)]\npub struct RemoteProject {\n    id: String,\n    run_build: bool,\n    run_commands: Vec<Vec<String>>,\n    path_style: PathStyle,\n}\n\nimpl RemoteProject {\n    pub fn new(id: impl Into<String>) -> Self {\n        Self {\n            id: id.into(),\n            run_build: true,\n            run_commands: vec![],\n            path_style: PathStyle::Dapptools,\n        }\n    }\n\n    /// Whether to run `forge build`\n    pub fn set_build(mut self, run_build: bool) -> Self {\n        self.run_build = run_build;\n        self\n    }\n\n    /// Configures the project's pathstyle\n    pub fn path_style(mut self, path_style: PathStyle) -> Self {\n        self.path_style = path_style;\n        self\n    }\n\n    /// Add another command to run after cloning\n    pub fn cmd(mut self, cmd: impl IntoIterator<Item = impl Into<String>>) -> Self {\n        self.run_commands.push(cmd.into_iter().map(Into::into).collect());\n        self\n    }\n}\n\nimpl<T: Into<String>> From<T> for RemoteProject {\n    fn from(id: T) -> Self {\n        Self::new(id)\n    }\n}\n\n/// Setups a new local forge project by cloning and initializing the `RemoteProject`\n///\n/// This will\n///   1. clone the prj, like \"transmissions1/solmate\"\n///   2. run `forge build`, if configured\n///   3. run additional commands\n///\n/// # Panics\n///\n/// If anything goes wrong during, checkout, build, or other commands are unsuccessful\npub fn setup_forge_remote(prj: impl Into<RemoteProject>) -> (TestProject, TestCommand) {\n    try_setup_forge_remote(prj).unwrap()\n}\n\n/// Same as `setup_forge_remote` but not panicking\npub fn try_setup_forge_remote(\n    config: impl Into<RemoteProject>,\n) -> Result<(TestProject, TestCommand)> {\n    let config = config.into();\n    let mut tmp = TempProject::checkout(&config.id).wrap_err(\"failed to checkout project\")?;\n    tmp.project_mut().paths = config.path_style.paths(tmp.root())?;\n\n    let prj = TestProject::with_project(tmp);\n    if config.run_build {\n        let mut cmd = prj.forge_command();\n        cmd.arg(\"build\").assert_success();\n    }\n    for addon in config.run_commands {\n        debug_assert!(!addon.is_empty());\n        let mut cmd = Command::new(&addon[0]);\n        if addon.len() > 1 {\n            cmd.args(&addon[1..]);\n        }\n        let status = cmd\n            .current_dir(prj.root())\n            .stdout(Stdio::null())\n            .stderr(Stdio::null())\n            .status()\n            .wrap_err_with(|| format!(\"Failed to execute {addon:?}\"))?;\n        eyre::ensure!(status.success(), \"Failed to execute command {:?}\", addon);\n    }\n\n    let cmd = prj.forge_command();\n    Ok((prj, cmd))\n}\n\npub fn setup_cast(name: &str, style: PathStyle) -> (TestProject, TestCommand) {\n    setup_cast_project(TestProject::new(name, style))\n}\n\npub fn setup_cast_project(test: TestProject) -> (TestProject, TestCommand) {\n    let cmd = test.cast_command();\n    (test, cmd)\n}\n\n/// `TestProject` represents a temporary project to run tests against.\n///\n/// Test projects are created from a global atomic counter to avoid duplicates.\n#[derive(Clone, Debug)]\npub struct TestProject<\n    T: ArtifactOutput<CompilerContract = Contract> + Default = ConfigurableArtifacts,\n> {\n    /// The directory in which this test executable is running.\n    exe_root: PathBuf,\n    /// The project in which the test should run.\n    pub(crate) inner: Arc<TempProject<MultiCompiler, T>>,\n}\n\nimpl TestProject {\n    /// Create a new test project with the given name. The name\n    /// does not need to be distinct for each invocation, but should correspond\n    /// to a logical grouping of tests.\n    pub fn new(name: &str, style: PathStyle) -> Self {\n        let id = NEXT_ID.fetch_add(1, Ordering::SeqCst);\n        let project = pretty_err(name, TempProject::with_style(&format!(\"{name}-{id}\"), style));\n        Self::with_project(project)\n    }\n\n    pub fn with_project(project: TempProject) -> Self {\n        init_tracing();\n        let this = env::current_exe().unwrap();\n        let exe_root = canonicalize(this.parent().expect(\"executable's directory\"));\n        Self { exe_root, inner: Arc::new(project) }\n    }\n\n    /// Returns the root path of the project's workspace.\n    pub fn root(&self) -> &Path {\n        self.inner.root()\n    }\n\n    /// Returns the paths config.\n    pub fn paths(&self) -> &ProjectPathsConfig {\n        self.inner.paths()\n    }\n\n    /// Returns the path to the project's `foundry.toml` file.\n    pub fn config(&self) -> PathBuf {\n        self.root().join(Config::FILE_NAME)\n    }\n\n    /// Returns the path to the project's cache file.\n    pub fn cache(&self) -> &PathBuf {\n        &self.paths().cache\n    }\n\n    /// Returns the path to the project's artifacts directory.\n    pub fn artifacts(&self) -> &PathBuf {\n        &self.paths().artifacts\n    }\n\n    /// Removes the project's cache and artifacts directory.\n    pub fn clear(&self) {\n        self.clear_cache();\n        self.clear_artifacts();\n    }\n\n    /// Removes this project's cache file.\n    pub fn clear_cache(&self) {\n        let _ = fs::remove_file(self.cache());\n    }\n\n    /// Removes this project's artifacts directory.\n    pub fn clear_artifacts(&self) {\n        let _ = fs::remove_dir_all(self.artifacts());\n    }\n\n    /// Removes the entire cache directory (including fuzz, invariant, and test-failures caches).\n    pub fn clear_cache_dir(&self) {\n        let _ = fs::remove_dir_all(self.root().join(\"cache\"));\n    }\n\n    /// Updates the project's config with the given function.\n    pub fn update_config(&self, f: impl FnOnce(&mut Config)) {\n        self._update_config(Box::new(f));\n    }\n\n    fn _update_config(&self, f: Box<dyn FnOnce(&mut Config) + '_>) {\n        let mut config = self\n            .config()\n            .exists()\n            .then_some(())\n            .and_then(|()| Config::load_with_root(self.root()).ok())\n            .unwrap_or_default();\n        config.remappings.clear();\n        f(&mut config);\n        self.write_config(config);\n    }\n\n    /// Writes the given config as toml to `foundry.toml`.\n    #[doc(hidden)] // Prefer `update_config`.\n    pub fn write_config(&self, config: Config) {\n        let file = self.config();\n        pretty_err(&file, fs::write(&file, config.to_string_pretty().unwrap()));\n    }\n\n    /// Writes [`rpc_endpoints`] to the project's config.\n    pub fn add_rpc_endpoints(&self) {\n        self.update_config(|config| {\n            config.rpc_endpoints = rpc_endpoints();\n        });\n    }\n\n    /// Adds a source file to the project.\n    pub fn add_source(&self, name: &str, contents: &str) -> PathBuf {\n        self.inner.add_source(name, Self::add_source_prelude(contents)).unwrap()\n    }\n\n    /// Adds a source file to the project. Prefer using `add_source` instead.\n    pub fn add_raw_source(&self, name: &str, contents: &str) -> PathBuf {\n        self.inner.add_source(name, contents).unwrap()\n    }\n\n    /// Adds a script file to the project.\n    pub fn add_script(&self, name: &str, contents: &str) -> PathBuf {\n        self.inner.add_script(name, Self::add_source_prelude(contents)).unwrap()\n    }\n\n    /// Adds a script file to the project. Prefer using `add_script` instead.\n    pub fn add_raw_script(&self, name: &str, contents: &str) -> PathBuf {\n        self.inner.add_script(name, contents).unwrap()\n    }\n\n    /// Adds a test file to the project.\n    pub fn add_test(&self, name: &str, contents: &str) -> PathBuf {\n        self.inner.add_test(name, Self::add_source_prelude(contents)).unwrap()\n    }\n\n    /// Adds a test file to the project. Prefer using `add_test` instead.\n    pub fn add_raw_test(&self, name: &str, contents: &str) -> PathBuf {\n        self.inner.add_test(name, contents).unwrap()\n    }\n\n    /// Adds a library file to the project.\n    pub fn add_lib(&self, name: &str, contents: &str) -> PathBuf {\n        self.inner.add_lib(name, Self::add_source_prelude(contents)).unwrap()\n    }\n\n    /// Adds a library file to the project. Prefer using `add_lib` instead.\n    pub fn add_raw_lib(&self, name: &str, contents: &str) -> PathBuf {\n        self.inner.add_lib(name, contents).unwrap()\n    }\n\n    fn add_source_prelude(s: &str) -> String {\n        let mut s = s.to_string();\n        if !s.contains(\"pragma solidity\") {\n            s = format!(\"pragma solidity ={SOLC_VERSION};\\n{s}\");\n        }\n        if !s.contains(\"// SPDX\") {\n            s = format!(\"// SPDX-License-Identifier: MIT OR Apache-2.0\\n{s}\");\n        }\n        s\n    }\n\n    /// Asserts that the `<root>/foundry.toml` file exists.\n    #[track_caller]\n    pub fn assert_config_exists(&self) {\n        assert!(self.config().exists());\n    }\n\n    /// Asserts that the `<root>/cache/sol-files-cache.json` file exists.\n    #[track_caller]\n    pub fn assert_cache_exists(&self) {\n        assert!(self.cache().exists());\n    }\n\n    /// Asserts that the `<root>/out` file exists.\n    #[track_caller]\n    pub fn assert_artifacts_dir_exists(&self) {\n        assert!(self.paths().artifacts.exists());\n    }\n\n    /// Creates all project dirs and ensure they were created\n    #[track_caller]\n    pub fn assert_create_dirs_exists(&self) {\n        self.paths().create_all().unwrap_or_else(|_| panic!(\"Failed to create project paths\"));\n        CompilerCache::<SolcSettings>::default()\n            .write(&self.paths().cache)\n            .expect(\"Failed to create cache\");\n        self.assert_all_paths_exist();\n    }\n\n    /// Ensures that the given layout exists\n    #[track_caller]\n    pub fn assert_style_paths_exist(&self, style: PathStyle) {\n        let paths = style.paths(&self.paths().root).unwrap();\n        config_paths_exist(&paths, self.inner.project().cached);\n    }\n\n    /// Copies the project's root directory to the given target, excluding build artifacts.\n    #[track_caller]\n    pub fn copy_to(&self, target: impl AsRef<Path>) {\n        let target = target.as_ref();\n        pretty_err(target, fs::create_dir_all(target));\n        pretty_err(target, copy_dir_filtered(self.root(), target));\n    }\n\n    /// Creates a file with contents `contents` in the test project's directory. The\n    /// file will be deleted when the project is dropped.\n    pub fn create_file(&self, path: impl AsRef<Path>, contents: &str) -> PathBuf {\n        let path = path.as_ref();\n        if !path.is_relative() {\n            panic!(\"create_file(): file path is absolute\");\n        }\n        let path = self.root().join(path);\n        if let Some(parent) = path.parent() {\n            pretty_err(parent, std::fs::create_dir_all(parent));\n        }\n        let file = pretty_err(&path, File::create(&path));\n        let mut writer = BufWriter::new(file);\n        pretty_err(&path, writer.write_all(contents.as_bytes()));\n        path\n    }\n\n    /// Adds DSTest as a source under \"test.sol\"\n    pub fn insert_ds_test(&self) -> PathBuf {\n        self.add_source(\"test.sol\", include_str!(\"../../../testdata/utils/DSTest.sol\"))\n    }\n\n    /// Adds custom test utils under the \"test/utils\" directory.\n    pub fn insert_utils(&self) {\n        self.add_test(\"utils/DSTest.sol\", include_str!(\"../../../testdata/utils/DSTest.sol\"));\n        self.add_test(\"utils/Test.sol\", include_str!(\"../../../testdata/utils/Test.sol\"));\n        self.add_test(\"utils/Vm.sol\", include_str!(\"../../../testdata/utils/Vm.sol\"));\n        self.add_test(\"utils/console.sol\", include_str!(\"../../../testdata/utils/console.sol\"));\n    }\n\n    /// Adds `console.sol` as a source under \"console.sol\"\n    pub fn insert_console(&self) -> PathBuf {\n        let s = include_str!(\"../../../testdata/utils/console.sol\");\n        self.add_source(\"console.sol\", s)\n    }\n\n    /// Adds `Vm.sol` as a source under \"Vm.sol\"\n    pub fn insert_vm(&self) -> PathBuf {\n        let s = include_str!(\"../../../testdata/utils/Vm.sol\");\n        self.add_source(\"Vm.sol\", s)\n    }\n\n    /// Asserts all project paths exist. These are:\n    /// - sources\n    /// - artifacts\n    /// - libs\n    /// - cache\n    pub fn assert_all_paths_exist(&self) {\n        let paths = self.paths();\n        config_paths_exist(paths, self.inner.project().cached);\n    }\n\n    /// Asserts that the artifacts dir and cache don't exist\n    pub fn assert_cleaned(&self) {\n        let paths = self.paths();\n        assert!(!paths.cache.exists());\n        assert!(!paths.artifacts.exists());\n    }\n\n    /// Creates a new command that is set to use the forge executable for this project\n    #[track_caller]\n    pub fn forge_command(&self) -> TestCommand {\n        let cmd = self.forge_bin();\n        let _lock = CURRENT_DIR_LOCK.lock();\n        TestCommand {\n            project: self.clone(),\n            cmd,\n            current_dir_lock: None,\n            saved_cwd: pretty_err(\"<current dir>\", std::env::current_dir()),\n            stdin: None,\n            redact_output: true,\n        }\n    }\n\n    /// Creates a new command that is set to use the cast executable for this project\n    pub fn cast_command(&self) -> TestCommand {\n        let mut cmd = self.cast_bin();\n        cmd.current_dir(self.inner.root());\n        let _lock = CURRENT_DIR_LOCK.lock();\n        TestCommand {\n            project: self.clone(),\n            cmd,\n            current_dir_lock: None,\n            saved_cwd: pretty_err(\"<current dir>\", std::env::current_dir()),\n            stdin: None,\n            redact_output: true,\n        }\n    }\n\n    /// Returns the path to the forge executable.\n    pub fn forge_bin(&self) -> Command {\n        let mut cmd = Command::new(self.forge_path());\n        cmd.current_dir(self.inner.root());\n        // Disable color output for comparisons; can be overridden with `--color always`.\n        cmd.env(\"NO_COLOR\", \"1\");\n        cmd\n    }\n\n    pub(crate) fn forge_path(&self) -> PathBuf {\n        canonicalize(self.exe_root.join(format!(\"../forge{}\", env::consts::EXE_SUFFIX)))\n    }\n\n    /// Returns the path to the cast executable.\n    pub fn cast_bin(&self) -> Command {\n        let cast = canonicalize(self.exe_root.join(format!(\"../cast{}\", env::consts::EXE_SUFFIX)));\n        let mut cmd = Command::new(cast);\n        // disable color output for comparisons\n        cmd.env(\"NO_COLOR\", \"1\");\n        cmd\n    }\n\n    /// Returns the `Config` as spit out by `forge config`\n    pub fn config_from_output<I, A>(&self, args: I) -> Config\n    where\n        I: IntoIterator<Item = A>,\n        A: AsRef<OsStr>,\n    {\n        let mut cmd = self.forge_bin();\n        cmd.arg(\"config\").arg(\"--root\").arg(self.root()).args(args).arg(\"--json\");\n        let output = cmd.output().unwrap();\n        let c = lossy_string(&output.stdout);\n        let config: Config = serde_json::from_str(c.as_ref()).unwrap();\n        config.sanitized()\n    }\n\n    /// Removes all files and dirs inside the project's root dir\n    pub fn wipe(&self) {\n        pretty_err(self.root(), fs::remove_dir_all(self.root()));\n        pretty_err(self.root(), fs::create_dir_all(self.root()));\n    }\n\n    /// Removes all contract files from `src`, `test`, `script`\n    pub fn wipe_contracts(&self) {\n        fn rm_create(path: &Path) {\n            pretty_err(path, fs::remove_dir_all(path));\n            pretty_err(path, fs::create_dir(path));\n        }\n        rm_create(&self.paths().sources);\n        rm_create(&self.paths().tests);\n        rm_create(&self.paths().scripts);\n    }\n\n    /// Initializes the default contracts (Counter.sol, Counter.t.sol, Counter.s.sol).\n    ///\n    /// This is useful for tests that need the default contracts created by `forge init`.\n    /// Most tests should not need this method, as the default behavior is to create an empty\n    /// project.\n    pub fn initialize_default_contracts(&self) {\n        self.add_raw_source(\n            \"Counter.sol\",\n            include_str!(\"../../forge/assets/solidity/CounterTemplate.sol\"),\n        );\n        self.add_raw_test(\n            \"Counter.t.sol\",\n            include_str!(\"../../forge/assets/solidity/CounterTemplate.t.sol\"),\n        );\n        self.add_raw_script(\n            \"Counter.s.sol\",\n            include_str!(\"../../forge/assets/solidity/CounterTemplate.s.sol\"),\n        );\n    }\n}\n\nfn config_paths_exist(paths: &ProjectPathsConfig, cached: bool) {\n    if cached {\n        assert!(paths.cache.exists());\n    }\n    assert!(paths.sources.exists());\n    assert!(paths.artifacts.exists());\n    paths.libraries.iter().for_each(|lib| assert!(lib.exists()));\n}\n\n/// A simple wrapper around a Command with some conveniences.\npub struct TestCommand {\n    saved_cwd: PathBuf,\n    /// The project used to launch this command.\n    project: TestProject,\n    /// The actual command we use to control the process.\n    cmd: Command,\n    // initial: Command,\n    current_dir_lock: Option<parking_lot::MutexGuard<'static, ()>>,\n    stdin: Option<Vec<u8>>,\n    /// If true, command output is redacted.\n    redact_output: bool,\n}\n\nimpl TestCommand {\n    /// Returns a mutable reference to the underlying command.\n    pub fn cmd(&mut self) -> &mut Command {\n        &mut self.cmd\n    }\n\n    /// Replaces the underlying command.\n    pub fn set_cmd(&mut self, cmd: Command) -> &mut Self {\n        self.cmd = cmd;\n        self\n    }\n\n    /// Resets the command to the default `forge` command.\n    pub fn forge_fuse(&mut self) -> &mut Self {\n        self.set_cmd(self.project.forge_bin())\n    }\n\n    /// Resets the command to the default `cast` command.\n    pub fn cast_fuse(&mut self) -> &mut Self {\n        self.set_cmd(self.project.cast_bin())\n    }\n\n    /// Sets the current working directory.\n    pub fn set_current_dir(&mut self, p: impl AsRef<Path>) {\n        drop(self.current_dir_lock.take());\n        let lock = CURRENT_DIR_LOCK.lock();\n        self.current_dir_lock = Some(lock);\n        let p = p.as_ref();\n        pretty_err(p, std::env::set_current_dir(p));\n    }\n\n    /// Add an argument to pass to the command.\n    pub fn arg<A: AsRef<OsStr>>(&mut self, arg: A) -> &mut Self {\n        self.cmd.arg(arg);\n        self\n    }\n\n    /// Add any number of arguments to the command.\n    pub fn args<I, A>(&mut self, args: I) -> &mut Self\n    where\n        I: IntoIterator<Item = A>,\n        A: AsRef<OsStr>,\n    {\n        self.cmd.args(args);\n        self\n    }\n\n    /// Set the stdin bytes for the next command.\n    pub fn stdin(&mut self, stdin: impl Into<Vec<u8>>) -> &mut Self {\n        self.stdin = Some(stdin.into());\n        self\n    }\n\n    /// Convenience function to add `--root project.root()` argument\n    pub fn root_arg(&mut self) -> &mut Self {\n        let root = self.project.root().to_path_buf();\n        self.arg(\"--root\").arg(root)\n    }\n\n    /// Set the environment variable `k` to value `v` for the command.\n    pub fn env(&mut self, k: impl AsRef<OsStr>, v: impl AsRef<OsStr>) {\n        self.cmd.env(k, v);\n    }\n\n    /// Set the environment variable `k` to value `v` for the command.\n    pub fn envs<I, K, V>(&mut self, envs: I)\n    where\n        I: IntoIterator<Item = (K, V)>,\n        K: AsRef<OsStr>,\n        V: AsRef<OsStr>,\n    {\n        self.cmd.envs(envs);\n    }\n\n    /// Unsets the environment variable `k` for the command.\n    pub fn unset_env(&mut self, k: impl AsRef<OsStr>) {\n        self.cmd.env_remove(k);\n    }\n\n    /// Set the working directory for this command.\n    ///\n    /// Note that this does not need to be called normally, since the creation\n    /// of this TestCommand causes its working directory to be set to the\n    /// test's directory automatically.\n    pub fn current_dir<P: AsRef<Path>>(&mut self, dir: P) -> &mut Self {\n        self.cmd.current_dir(dir);\n        self\n    }\n\n    /// Returns the `Config` as spit out by `forge config`\n    #[track_caller]\n    pub fn config(&mut self) -> Config {\n        self.cmd.args([\"config\", \"--json\"]);\n        let output = self.assert().success().get_output().stdout_lossy();\n        self.forge_fuse();\n        serde_json::from_str(output.as_ref()).unwrap()\n    }\n\n    /// Runs `git init` inside the project's dir\n    #[track_caller]\n    pub fn git_init(&self) {\n        let mut cmd = Command::new(\"git\");\n        cmd.arg(\"init\").current_dir(self.project.root());\n        let output = OutputAssert::new(cmd.output().unwrap());\n        output.success();\n    }\n\n    /// Runs `git submodule status` inside the project's dir\n    #[track_caller]\n    pub fn git_submodule_status(&self) -> Output {\n        let mut cmd = Command::new(\"git\");\n        cmd.arg(\"submodule\").arg(\"status\").current_dir(self.project.root());\n        cmd.output().unwrap()\n    }\n\n    /// Runs `git add .` inside the project's dir\n    #[track_caller]\n    pub fn git_add(&self) {\n        let mut cmd = Command::new(\"git\");\n        cmd.current_dir(self.project.root());\n        cmd.arg(\"add\").arg(\".\");\n        let output = OutputAssert::new(cmd.output().unwrap());\n        output.success();\n    }\n\n    /// Runs `git commit .` inside the project's dir\n    #[track_caller]\n    pub fn git_commit(&self, msg: &str) {\n        let mut cmd = Command::new(\"git\");\n        cmd.current_dir(self.project.root());\n        cmd.arg(\"commit\").arg(\"-m\").arg(msg);\n        let output = OutputAssert::new(cmd.output().unwrap());\n        output.success();\n    }\n\n    /// Runs the command, returning a [`snapbox`] object to assert the command output.\n    #[track_caller]\n    pub fn assert_with(&mut self, f: &[RegexRedaction]) -> OutputAssert {\n        let assert = OutputAssert::new(self.execute());\n        if self.redact_output {\n            let mut redactions = test_redactions();\n            insert_redactions(f, &mut redactions);\n            return assert.with_assert(\n                snapbox::Assert::new()\n                    .action_env(snapbox::assert::DEFAULT_ACTION_ENV)\n                    .redact_with(redactions),\n            );\n        }\n        assert\n    }\n\n    /// Runs the command, returning a [`snapbox`] object to assert the command output.\n    #[track_caller]\n    pub fn assert(&mut self) -> OutputAssert {\n        self.assert_with(&[])\n    }\n\n    /// Runs the command and asserts that it resulted in success.\n    #[track_caller]\n    pub fn assert_success(&mut self) -> OutputAssert {\n        self.assert().success()\n    }\n\n    /// Runs the command and asserts that it resulted in success, with expected JSON data.\n    #[track_caller]\n    pub fn assert_json_stdout(&mut self, expected: impl IntoData) {\n        let expected = expected.is(snapbox::data::DataFormat::Json).unordered();\n        let stdout = self.assert_success().get_output().stdout.clone();\n        let actual = stdout.into_data().is(snapbox::data::DataFormat::Json).unordered();\n        assert_data_eq!(actual, expected);\n    }\n\n    /// Runs the command and asserts that it resulted in the expected outcome and JSON data.\n    #[track_caller]\n    pub fn assert_json_stderr(&mut self, success: bool, expected: impl IntoData) {\n        let expected = expected.is(snapbox::data::DataFormat::Json).unordered();\n        let stderr = if success { self.assert_success() } else { self.assert_failure() }\n            .get_output()\n            .stderr\n            .clone();\n        let actual = stderr.into_data().is(snapbox::data::DataFormat::Json).unordered();\n        assert_data_eq!(actual, expected);\n    }\n\n    /// Runs the command and asserts that it **succeeded** nothing was printed to stdout.\n    #[track_caller]\n    pub fn assert_empty_stdout(&mut self) {\n        self.assert_success().stdout_eq(Data::new());\n    }\n\n    /// Runs the command and asserts that it failed.\n    #[track_caller]\n    pub fn assert_failure(&mut self) -> OutputAssert {\n        self.assert().failure()\n    }\n\n    /// Runs the command and asserts that the exit code is `expected`.\n    #[track_caller]\n    pub fn assert_code(&mut self, expected: i32) -> OutputAssert {\n        self.assert().code(expected)\n    }\n\n    /// Runs the command and asserts that it **failed** nothing was printed to stderr.\n    #[track_caller]\n    pub fn assert_empty_stderr(&mut self) {\n        self.assert_failure().stderr_eq(Data::new());\n    }\n\n    /// Runs the command with a temporary file argument and asserts that the contents of the file\n    /// match the given data.\n    #[track_caller]\n    pub fn assert_file(&mut self, data: impl IntoData) {\n        self.assert_file_with(|this, path| _ = this.arg(path).assert_success(), data);\n    }\n\n    /// Creates a temporary file, passes it to `f`, then asserts that the contents of the file match\n    /// the given data.\n    #[track_caller]\n    pub fn assert_file_with(&mut self, f: impl FnOnce(&mut Self, &Path), data: impl IntoData) {\n        let file = tempfile::NamedTempFile::new().expect(\"couldn't create temporary file\");\n        f(self, file.path());\n        assert_data_eq!(Data::read_from(file.path(), None), data);\n    }\n\n    /// Does not apply [`snapbox`] redactions to the command output.\n    pub fn with_no_redact(&mut self) -> &mut Self {\n        self.redact_output = false;\n        self\n    }\n\n    /// Executes command, applies stdin function and returns output\n    #[track_caller]\n    pub fn execute(&mut self) -> Output {\n        self.try_execute().unwrap()\n    }\n\n    #[track_caller]\n    pub fn try_execute(&mut self) -> std::io::Result<Output> {\n        test_debug!(\"executing {:?}\", self.cmd);\n        let mut child =\n            self.cmd.stdout(Stdio::piped()).stderr(Stdio::piped()).stdin(Stdio::piped()).spawn()?;\n        if let Some(bytes) = self.stdin.take() {\n            child.stdin.take().unwrap().write_all(&bytes)?;\n        }\n        let output = child.wait_with_output()?;\n        test_debug!(\"exited with {}\", output.status);\n        test_trace!(\"\\n--- stdout ---\\n{}\\n--- /stdout ---\", output.stdout_lossy());\n        test_trace!(\"\\n--- stderr ---\\n{}\\n--- /stderr ---\", output.stderr_lossy());\n        Ok(output)\n    }\n}\n\nimpl Drop for TestCommand {\n    fn drop(&mut self) {\n        let _lock = self.current_dir_lock.take().unwrap_or_else(|| CURRENT_DIR_LOCK.lock());\n        if self.saved_cwd.exists() {\n            let _ = std::env::set_current_dir(&self.saved_cwd);\n        }\n    }\n}\n\nfn test_redactions() -> snapbox::Redactions {\n    static REDACTIONS: LazyLock<snapbox::Redactions> = LazyLock::new(|| {\n        make_redactions(&[\n            (\"[SOLC_VERSION]\", r\"Solc( version)? \\d+.\\d+.\\d+\"),\n            (\"[ELAPSED]\", r\"(finished )?in \\d+(\\.\\d+)?\\w?s( \\(.*?s CPU time\\))?\"),\n            (\"[GAS]\", r\"[Gg]as( used)?: \\d+\"),\n            (\"[GAS_COST]\", r\"[Gg]as cost\\s*\\(\\d+\\)\"),\n            (\"[GAS_LIMIT]\", r\"[Gg]as limit\\s*\\(\\d+\\)\"),\n            (\"[AVG_GAS]\", r\"μ: \\d+, ~: \\d+\"),\n            (\"[FILE]\", r\"(-->|╭▸).*\\.sol\"),\n            (\"[FILE]\", r\"Location(.|\\n)*\\.rs(.|\\n)*Backtrace\"),\n            (\"[COMPILING_FILES]\", r\"Compiling \\d+ files?\"),\n            (\"[TX_HASH]\", r\"Transaction hash: 0x[0-9A-Fa-f]{64}\"),\n            (\"[ADDRESS]\", r\"Address: +0x[0-9A-Fa-f]{40}\"),\n            (\"[PUBLIC_KEY]\", r\"Public key: +0x[0-9A-Fa-f]{128}\"),\n            (\"[PRIVATE_KEY]\", r\"Private key: +0x[0-9A-Fa-f]{64}\"),\n            (\"[UPDATING_DEPENDENCIES]\", r\"Updating dependencies in .*\"),\n            (\"[SAVED_TRANSACTIONS]\", r\"Transactions saved to: .*\\.json\"),\n            (\"[SAVED_SENSITIVE_VALUES]\", r\"Sensitive values saved to: .*\\.json\"),\n            (\"[ESTIMATED_GAS_PRICE]\", r\"Estimated gas price:\\s*(\\d+(\\.\\d+)?)\\s*gwei\"),\n            (\"[ESTIMATED_TOTAL_GAS_USED]\", r\"Estimated total gas used for script: \\d+\"),\n            (\n                \"[ESTIMATED_AMOUNT_REQUIRED]\",\n                r\"Estimated amount required:\\s*(\\d+(\\.\\d+)?)\\s*[A-Z]{3}\",\n            ),\n            (\"[SEED]\", r\"Fuzz seed: 0x[0-9A-Fa-f]+\"),\n        ])\n    });\n    REDACTIONS.clone()\n}\n\n/// A tuple of a placeholder and a regex replacement string.\npub type RegexRedaction = (&'static str, &'static str);\n\n/// Creates a [`snapbox`] redactions object from a list of regex redactions.\nfn make_redactions(redactions: &[RegexRedaction]) -> snapbox::Redactions {\n    let mut r = snapbox::Redactions::new();\n    insert_redactions(redactions, &mut r);\n    r\n}\n\nfn insert_redactions(redactions: &[RegexRedaction], r: &mut snapbox::Redactions) {\n    for &(placeholder, re) in redactions {\n        r.insert(placeholder, Regex::new(re).expect(re)).expect(re);\n    }\n}\n\n/// Extension trait for [`Output`].\npub trait OutputExt {\n    /// Returns the stdout as lossy string\n    fn stdout_lossy(&self) -> String;\n\n    /// Returns the stderr as lossy string\n    fn stderr_lossy(&self) -> String;\n}\n\nimpl OutputExt for Output {\n    fn stdout_lossy(&self) -> String {\n        lossy_string(&self.stdout)\n    }\n\n    fn stderr_lossy(&self) -> String {\n        lossy_string(&self.stderr)\n    }\n}\n\npub fn lossy_string(bytes: &[u8]) -> String {\n    String::from_utf8_lossy(bytes).replace(\"\\r\\n\", \"\\n\")\n}\n\nfn canonicalize(path: impl AsRef<Path>) -> PathBuf {\n    foundry_common::fs::canonicalize_path(path.as_ref())\n        .unwrap_or_else(|_| path.as_ref().to_path_buf())\n}\n"
  },
  {
    "path": "crates/test-utils/src/rpc.rs",
    "content": "//! RPC API keys utilities.\n\nuse foundry_config::{\n    NamedChain::{\n        self, Arbitrum, Base, BinanceSmartChainTestnet, Celo, Mainnet, Optimism, Polygon, Sepolia,\n    },\n    RpcEndpointUrl, RpcEndpoints,\n};\nuse rand::seq::SliceRandom;\nuse std::{\n    env,\n    sync::{\n        LazyLock,\n        atomic::{AtomicUsize, Ordering},\n    },\n};\n\nmacro_rules! shuffled_list {\n    ($name:ident, $e:expr $(,)?) => {\n        static $name: LazyLock<ShuffledList<&'static str>> =\n            LazyLock::new(|| ShuffledList::new($e));\n    };\n}\n\nstruct ShuffledList<T> {\n    list: Vec<T>,\n    index: AtomicUsize,\n}\n\nimpl<T> ShuffledList<T> {\n    fn new(mut list: Vec<T>) -> Self {\n        assert!(!list.is_empty());\n        list.shuffle(&mut rand::rng());\n        Self { list, index: AtomicUsize::new(0) }\n    }\n\n    fn next(&self) -> &T {\n        let index = self.index.fetch_add(1, Ordering::Relaxed);\n        &self.list[index % self.list.len()]\n    }\n}\n\nshuffled_list!(\n    HTTP_ARCHIVE_DOMAINS,\n    vec![\n        //\n        \"ethereum.reth.rs/rpc\",\n    ],\n);\nshuffled_list!(\n    HTTP_DOMAINS,\n    vec![\n        //\n        \"ethereum.reth.rs/rpc\",\n    ],\n);\nshuffled_list!(\n    WS_ARCHIVE_DOMAINS,\n    vec![\n        //\n        \"ethereum.reth.rs/ws\",\n    ],\n);\nshuffled_list!(\n    WS_DOMAINS,\n    vec![\n        //\n        \"ethereum.reth.rs/ws\",\n    ],\n);\n\n// List of general purpose DRPC keys to rotate through\nshuffled_list!(\n    DRPC_KEYS,\n    vec![\n        \"Agc9NK9-6UzYh-vQDDM80Tv0A5UnBkUR8I3qssvAG40d\",\n        \"AjUPUPonSEInt2CZ_7A-ai3hMyxxBlsR8I4EssvAG40d\",\n    ],\n);\n\n// List of etherscan keys.\nshuffled_list!(\n    ETHERSCAN_KEYS,\n    vec![\n        \"MCAUM7WPE9XP5UQMZPCKIBUJHPM1C24FP6\",\n        \"JW6RWCG2C5QF8TANH4KC7AYIF1CX7RB5D1\",\n        \"ZSMDY6BI2H55MBE3G9CUUQT4XYUDBB6ZSK\",\n        \"4FYHTY429IXYMJNS4TITKDMUKW5QRYDX61\",\n        \"QYKNT5RHASZ7PGQE68FNQWH99IXVTVVD2I\",\n        \"VXMQ117UN58Y4RHWUB8K1UGCEA7UQEWK55\",\n        \"C7I2G4JTA5EPYS42Z8IZFEIMQNI5GXIJEV\",\n        \"A15KZUMZXXCK1P25Y1VP1WGIVBBHIZDS74\",\n        \"3IA6ASNQXN8WKN7PNFX7T72S9YG56X9FPG\",\n    ],\n);\n\n/// the RPC endpoints used during tests\npub fn rpc_endpoints() -> RpcEndpoints {\n    RpcEndpoints::new([\n        (\"mainnet\", RpcEndpointUrl::Url(next_http_archive_rpc_url())),\n        (\"mainnet2\", RpcEndpointUrl::Url(next_http_archive_rpc_url())),\n        (\"sepolia\", RpcEndpointUrl::Url(next_rpc_endpoint(NamedChain::Sepolia))),\n        (\"optimism\", RpcEndpointUrl::Url(next_rpc_endpoint(NamedChain::Optimism))),\n        (\"arbitrum\", RpcEndpointUrl::Url(next_rpc_endpoint(NamedChain::Arbitrum))),\n        (\"polygon\", RpcEndpointUrl::Url(next_rpc_endpoint(NamedChain::Polygon))),\n        (\"bsc\", RpcEndpointUrl::Url(next_rpc_endpoint(NamedChain::BinanceSmartChain))),\n        (\"avaxTestnet\", RpcEndpointUrl::Url(\"https://api.avax-test.network/ext/bc/C/rpc\".into())),\n        (\"moonbeam\", RpcEndpointUrl::Url(\"https://moonbeam-rpc.publicnode.com\".into())),\n        (\"polkadotTestnet\", RpcEndpointUrl::Url(\"https://eth-rpc-testnet.polkadot.io\".into())),\n        (\"kusama\", RpcEndpointUrl::Url(\"https://eth-rpc-kusama.polkadot.io\".into())),\n        (\"polkadot\", RpcEndpointUrl::Url(\"https://eth-rpc.polkadot.io\".into())),\n        (\"rpcEnvAlias\", RpcEndpointUrl::Env(\"${RPC_ENV_ALIAS}\".into())),\n    ])\n}\n\n/// Returns the next _mainnet_ rpc URL in inline\n///\n/// This will rotate all available rpc endpoints\npub fn next_http_rpc_endpoint() -> String {\n    next_rpc_endpoint(NamedChain::Mainnet)\n}\n\n/// Returns the next _mainnet_ rpc URL in inline\n///\n/// This will rotate all available rpc endpoints\npub fn next_ws_rpc_endpoint() -> String {\n    next_ws_endpoint(NamedChain::Mainnet)\n}\n\n/// Returns the next HTTP RPC URL.\npub fn next_rpc_endpoint(chain: NamedChain) -> String {\n    next_url(false, chain)\n}\n\n/// Returns the next WS RPC URL.\npub fn next_ws_endpoint(chain: NamedChain) -> String {\n    next_url(true, chain)\n}\n\n/// Returns an HTTP URL that has access to archive state\npub fn next_http_archive_rpc_url() -> String {\n    next_archive_url(false)\n}\n\n/// Returns a websocket URL that has access to archive state\npub fn next_ws_archive_rpc_url() -> String {\n    next_archive_url(true)\n}\n\n/// Returns a URL that has access to archive state.\nfn next_archive_url(is_ws: bool) -> String {\n    let domain = if is_ws { &WS_ARCHIVE_DOMAINS } else { &HTTP_ARCHIVE_DOMAINS }.next();\n    let url = if is_ws { format!(\"wss://{domain}\") } else { format!(\"https://{domain}\") };\n    test_debug!(\"next_archive_url(is_ws={is_ws}) = {}\", debug_url(&url));\n    url\n}\n\n/// Returns the next etherscan api key.\npub fn next_etherscan_api_key() -> String {\n    let mut key = env::var(\"ETHERSCAN_KEY\").unwrap_or_default();\n    if key.is_empty() {\n        key = ETHERSCAN_KEYS.next().to_string();\n    }\n    test_debug!(\"next_etherscan_api_key() = {}...\", &key[..6]);\n    key\n}\n\nfn next_url(is_ws: bool, chain: NamedChain) -> String {\n    let url = next_url_inner(is_ws, chain);\n    test_debug!(\"next_url(is_ws={is_ws}, chain={chain:?}) = {}\", debug_url(&url));\n    url\n}\n\nfn next_url_inner(is_ws: bool, chain: NamedChain) -> String {\n    if matches!(chain, Base) {\n        return \"https://mainnet.base.org\".to_string();\n    }\n\n    if matches!(chain, Optimism) {\n        return \"https://mainnet.optimism.io\".to_string();\n    }\n\n    if matches!(chain, BinanceSmartChainTestnet) {\n        return \"https://bsc-testnet-rpc.publicnode.com\".to_string();\n    }\n\n    if matches!(chain, Celo) {\n        return \"https://celo.drpc.org\".to_string();\n    }\n\n    if matches!(chain, Sepolia) {\n        let rpc_url = env::var(\"ETH_SEPOLIA_RPC\").unwrap_or_default();\n        if !rpc_url.is_empty() {\n            return rpc_url;\n        }\n    }\n\n    if matches!(chain, Arbitrum) {\n        let rpc_url = env::var(\"ARBITRUM_RPC\").unwrap_or_default();\n        if !rpc_url.is_empty() {\n            return rpc_url;\n        }\n    }\n\n    let reth_works = true;\n    let domain = if reth_works && matches!(chain, Mainnet) {\n        *(if is_ws { &WS_DOMAINS } else { &HTTP_DOMAINS }).next()\n    } else {\n        // DRPC for other networks used in tests.\n        let key = DRPC_KEYS.next();\n        let network = match chain {\n            Mainnet => \"ethereum\",\n            Polygon => \"polygon\",\n            Arbitrum => \"arbitrum\",\n            Sepolia => \"sepolia\",\n            _ => \"\",\n        };\n        &format!(\"lb.drpc.org/ogrpc?network={network}&dkey={key}\")\n    };\n\n    if is_ws { format!(\"wss://{domain}\") } else { format!(\"https://{domain}\") }\n}\n\n/// Basic redaction for debugging RPC URLs.\nfn debug_url(url: &str) -> impl std::fmt::Display + '_ {\n    let url = reqwest::Url::parse(url).unwrap();\n    format!(\n        \"{scheme}://{host}{path}\",\n        scheme = url.scheme(),\n        host = url.host_str().unwrap(),\n        path = url.path().get(..8).unwrap_or(url.path()),\n    )\n}\n\n#[cfg(test)]\n#[expect(clippy::disallowed_macros)]\nmod tests {\n    use super::*;\n    use alloy_primitives::address;\n    use foundry_config::Chain;\n\n    #[tokio::test]\n    #[ignore = \"run manually\"]\n    async fn test_etherscan_keys() {\n        let address = address!(\"0xdAC17F958D2ee523a2206206994597C13D831ec7\");\n        let mut first_abi = None;\n        let mut failed = Vec::new();\n        for (i, &key) in ETHERSCAN_KEYS.list.iter().enumerate() {\n            println!(\"trying key {i} ({key})\");\n\n            let client = foundry_block_explorers::Client::builder()\n                .chain(Chain::mainnet())\n                .unwrap()\n                .with_api_key(key)\n                .build()\n                .unwrap();\n\n            let mut fail = |e: &str| {\n                eprintln!(\"key {i} ({key}) failed: {e}\");\n                failed.push(key);\n            };\n\n            let abi = match client.contract_abi(address).await {\n                Ok(abi) => abi,\n                Err(e) => {\n                    fail(&e.to_string());\n                    continue;\n                }\n            };\n\n            if let Some(first_abi) = &first_abi {\n                if abi != *first_abi {\n                    fail(\"abi mismatch\");\n                }\n            } else {\n                first_abi = Some(abi);\n            }\n        }\n        if !failed.is_empty() {\n            panic!(\"failed keys: {failed:#?}\");\n        }\n    }\n}\n"
  },
  {
    "path": "crates/test-utils/src/script.rs",
    "content": "use crate::{TestCommand, init_tracing, util::lossy_string};\nuse alloy_primitives::{Address, address};\nuse alloy_provider::Provider;\nuse eyre::Result;\nuse foundry_common::provider::{RetryProvider, get_http_provider};\nuse std::{\n    collections::BTreeMap,\n    fs,\n    path::{Path, PathBuf},\n};\n\nconst BROADCAST_TEST_PATH: &str = \"src/Broadcast.t.sol\";\nconst TESTDATA: &str = concat!(env!(\"CARGO_MANIFEST_DIR\"), \"/../../testdata\");\n\nfn init_script_cmd(\n    cmd: &mut TestCommand,\n    project_root: &Path,\n    target_contract: &str,\n    endpoint: Option<&str>,\n) {\n    cmd.forge_fuse();\n    cmd.set_current_dir(project_root);\n\n    cmd.args([\"script\", target_contract, \"--root\", project_root.to_str().unwrap(), \"-vvvvv\"]);\n\n    if let Some(rpc_url) = endpoint {\n        cmd.args([\"--fork-url\", rpc_url]);\n    }\n}\n/// A helper struct to test forge script scenarios\npub struct ScriptTester {\n    pub accounts_pub: Vec<Address>,\n    pub accounts_priv: Vec<String>,\n    pub provider: Option<RetryProvider>,\n    pub nonces: BTreeMap<u32, u64>,\n    pub address_nonces: BTreeMap<Address, u64>,\n    pub cmd: TestCommand,\n    pub project_root: PathBuf,\n    pub target_contract: String,\n    pub endpoint: Option<String>,\n}\n\nimpl ScriptTester {\n    /// Creates a new instance of a Tester for the given contract\n    pub fn new(\n        mut cmd: TestCommand,\n        endpoint: Option<&str>,\n        project_root: &Path,\n        target_contract: &str,\n    ) -> Self {\n        init_tracing();\n        Self::copy_testdata(project_root).unwrap();\n        init_script_cmd(&mut cmd, project_root, target_contract, endpoint);\n\n        let mut provider = None;\n        if let Some(endpoint) = endpoint {\n            provider = Some(get_http_provider(endpoint))\n        }\n\n        Self {\n            accounts_pub: vec![\n                address!(\"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266\"),\n                address!(\"0x70997970C51812dc3A010C7d01b50e0d17dc79C8\"),\n                address!(\"0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC\"),\n            ],\n            accounts_priv: vec![\n                \"ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80\".to_string(),\n                \"59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d\".to_string(),\n                \"5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a\".to_string(),\n            ],\n            provider,\n            nonces: BTreeMap::default(),\n            address_nonces: BTreeMap::default(),\n            cmd,\n            project_root: project_root.to_path_buf(),\n            target_contract: target_contract.to_string(),\n            endpoint: endpoint.map(|s| s.to_string()),\n        }\n    }\n\n    /// Creates a new instance of a Tester for the `broadcast` test at the given `project_root` by\n    /// configuring the `TestCommand` with script\n    pub fn new_broadcast(cmd: TestCommand, endpoint: &str, project_root: &Path) -> Self {\n        let target_contract = project_root.join(BROADCAST_TEST_PATH).to_string_lossy().to_string();\n\n        // copy the broadcast test\n        fs::copy(\n            Self::testdata_path().join(\"default/cheats/Broadcast.t.sol\"),\n            project_root.join(BROADCAST_TEST_PATH),\n        )\n        .expect(\"Failed to initialize broadcast contract\");\n\n        Self::new(cmd, Some(endpoint), project_root, &target_contract)\n    }\n\n    /// Creates a new instance of a Tester for the `broadcast` test at the given `project_root` by\n    /// configuring the `TestCommand` with script without an endpoint\n    pub fn new_broadcast_without_endpoint(cmd: TestCommand, project_root: &Path) -> Self {\n        let target_contract = project_root.join(BROADCAST_TEST_PATH).to_string_lossy().to_string();\n\n        // copy the broadcast test\n        let testdata = Self::testdata_path();\n        fs::copy(\n            testdata.join(\"default/cheats/Broadcast.t.sol\"),\n            project_root.join(BROADCAST_TEST_PATH),\n        )\n        .expect(\"Failed to initialize broadcast contract\");\n\n        Self::new(cmd, None, project_root, &target_contract)\n    }\n\n    /// Returns the path to the dir that contains testdata\n    fn testdata_path() -> &'static Path {\n        Path::new(TESTDATA)\n    }\n\n    /// Initialises the test contracts by copying them into the workspace\n    fn copy_testdata(root: &Path) -> Result<()> {\n        let testdata = Self::testdata_path();\n        let from_dir = testdata.join(\"utils\");\n        let to_dir = root.join(\"utils\");\n        fs::create_dir_all(&to_dir)?;\n        for entry in fs::read_dir(&from_dir)? {\n            let file = &entry?.path();\n            let name = file.file_name().unwrap();\n            fs::copy(file, to_dir.join(name))?;\n        }\n        Ok(())\n    }\n\n    pub async fn load_private_keys(&mut self, keys_indexes: &[u32]) -> &mut Self {\n        for &index in keys_indexes {\n            self.cmd.args([\"--private-keys\", &self.accounts_priv[index as usize]]);\n\n            if let Some(provider) = &self.provider {\n                let nonce = provider\n                    .get_transaction_count(self.accounts_pub[index as usize])\n                    .await\n                    .unwrap();\n                self.nonces.insert(index, nonce);\n            }\n        }\n        self\n    }\n\n    pub async fn load_addresses(&mut self, addresses: &[Address]) -> &mut Self {\n        for &address in addresses {\n            let nonce =\n                self.provider.as_ref().unwrap().get_transaction_count(address).await.unwrap();\n            self.address_nonces.insert(address, nonce);\n        }\n        self\n    }\n\n    pub fn add_deployer(&mut self, index: u32) -> &mut Self {\n        self.sender(self.accounts_pub[index as usize])\n    }\n\n    /// Adds given address as sender\n    pub fn sender(&mut self, addr: Address) -> &mut Self {\n        self.args(&[\"--sender\", &addr.to_string()])\n    }\n\n    pub fn add_sig(&mut self, contract_name: &str, sig: &str) -> &mut Self {\n        self.args(&[\"--tc\", contract_name, \"--sig\", sig])\n    }\n\n    pub fn add_create2_deployer(&mut self, create2_deployer: Address) -> &mut Self {\n        self.args(&[\"--create2-deployer\", &create2_deployer.to_string()])\n    }\n\n    /// Adds the `--unlocked` flag\n    pub fn unlocked(&mut self) -> &mut Self {\n        self.arg(\"--unlocked\")\n    }\n\n    pub fn simulate(&mut self, expected: ScriptOutcome) -> &mut Self {\n        self.run(expected)\n    }\n\n    pub fn broadcast(&mut self, expected: ScriptOutcome) -> &mut Self {\n        self.arg(\"--broadcast\").run(expected)\n    }\n\n    pub fn resume(&mut self, expected: ScriptOutcome) -> &mut Self {\n        self.arg(\"--resume\").run(expected)\n    }\n\n    /// `[(private_key_slot, expected increment)]`\n    pub async fn assert_nonce_increment(&mut self, keys_indexes: &[(u32, u32)]) -> &mut Self {\n        for &(private_key_slot, expected_increment) in keys_indexes {\n            let addr = self.accounts_pub[private_key_slot as usize];\n            let nonce = self.provider.as_ref().unwrap().get_transaction_count(addr).await.unwrap();\n            let prev_nonce = self.nonces.get(&private_key_slot).unwrap();\n\n            assert_eq!(\n                nonce,\n                (*prev_nonce + expected_increment as u64),\n                \"nonce not incremented correctly for {addr}: \\\n                 {prev_nonce} + {expected_increment} != {nonce}\"\n            );\n        }\n        self\n    }\n\n    /// In Vec<(address, expected increment)>\n    pub async fn assert_nonce_increment_addresses(\n        &mut self,\n        address_indexes: &[(Address, u32)],\n    ) -> &mut Self {\n        for (address, expected_increment) in address_indexes {\n            let nonce =\n                self.provider.as_ref().unwrap().get_transaction_count(*address).await.unwrap();\n            let prev_nonce = self.address_nonces.get(address).unwrap();\n\n            assert_eq!(nonce, *prev_nonce + *expected_increment as u64);\n        }\n        self\n    }\n\n    pub fn run(&mut self, expected: ScriptOutcome) -> &mut Self {\n        let out = self.cmd.execute();\n        let (stdout, stderr) = (lossy_string(&out.stdout), lossy_string(&out.stderr));\n\n        trace!(target: \"tests\", \"STDOUT\\n{stdout}\\n\\nSTDERR\\n{stderr}\");\n\n        if !stdout.contains(expected.as_str()) && !stderr.contains(expected.as_str()) {\n            panic!(\n                \"--STDOUT--\\n{stdout}\\n\\n--STDERR--\\n{stderr}\\n\\n--EXPECTED--\\n{:?} not found in stdout or stderr\",\n                expected.as_str()\n            );\n        }\n\n        self\n    }\n\n    pub fn slow(&mut self) -> &mut Self {\n        self.arg(\"--slow\")\n    }\n\n    pub fn arg(&mut self, arg: &str) -> &mut Self {\n        self.cmd.arg(arg);\n        self\n    }\n\n    pub fn args(&mut self, args: &[&str]) -> &mut Self {\n        self.cmd.args(args);\n        self\n    }\n\n    pub fn clear(&mut self) {\n        init_script_cmd(\n            &mut self.cmd,\n            &self.project_root,\n            &self.target_contract,\n            self.endpoint.as_deref(),\n        );\n        self.nonces.clear();\n        self.address_nonces.clear();\n    }\n}\n\n/// Various `forge` script results\n#[derive(Debug)]\npub enum ScriptOutcome {\n    OkNoEndpoint,\n    OkSimulation,\n    OkBroadcast,\n    WarnSpecifyDeployer,\n    MissingSender,\n    MissingWallet,\n    StaticCallNotAllowed,\n    ScriptFailed,\n    UnsupportedLibraries,\n    ErrorSelectForkOnBroadcast,\n    OkRun,\n}\n\nimpl ScriptOutcome {\n    pub fn as_str(&self) -> &'static str {\n        match self {\n            Self::OkNoEndpoint => \"If you wish to simulate on-chain transactions pass a RPC URL.\",\n            Self::OkSimulation => \"SIMULATION COMPLETE. To broadcast these\",\n            Self::OkBroadcast => \"ONCHAIN EXECUTION COMPLETE & SUCCESSFUL\",\n            Self::WarnSpecifyDeployer => {\n                \"Warning: You have more than one deployer who could predeploy libraries. Using `--sender` instead.\"\n            }\n            Self::MissingSender => {\n                \"You seem to be using Foundry's default sender. Be sure to set your own --sender\"\n            }\n            Self::MissingWallet => \"No associated wallet\",\n            Self::StaticCallNotAllowed => {\n                \"staticcall`s are not allowed after `broadcast`; use `startBroadcast` instead\"\n            }\n            Self::ScriptFailed => \"script failed: \",\n            Self::UnsupportedLibraries => {\n                \"Multi chain deployment does not support library linking at the moment.\"\n            }\n            Self::ErrorSelectForkOnBroadcast => \"cannot select forks during a broadcast\",\n            Self::OkRun => \"Script ran successfully\",\n        }\n    }\n\n    pub fn is_err(&self) -> bool {\n        match self {\n            Self::OkNoEndpoint\n            | Self::OkSimulation\n            | Self::OkBroadcast\n            | Self::WarnSpecifyDeployer\n            | Self::OkRun => false,\n            Self::MissingSender\n            | Self::MissingWallet\n            | Self::StaticCallNotAllowed\n            | Self::UnsupportedLibraries\n            | Self::ErrorSelectForkOnBroadcast\n            | Self::ScriptFailed => true,\n        }\n    }\n}\n"
  },
  {
    "path": "crates/test-utils/src/ui_runner.rs",
    "content": "use std::path::Path;\nuse ui_test::{\n    spanned::Spanned,\n    status_emitter::{Gha, StatusEmitter},\n};\n\n/// Test runner based on `ui_test`. Adapted from `https://github.com/paradigmxyz/solar/blob/main/tools/tester/src/lib.rs`.\npub fn run_tests<'a>(cmd: &str, cmd_path: &'a Path, testdata: &'a Path) -> eyre::Result<()> {\n    ui_test::color_eyre::install()?;\n\n    let mut args = ui_test::Args::test()?;\n\n    // Fast path for `--list`, invoked by `cargo-nextest`.\n    {\n        let mut dummy_config = ui_test::Config::dummy();\n        dummy_config.with_args(&args);\n        if ui_test::nextest::emulate(&mut vec![dummy_config]) {\n            return Ok(());\n        }\n    }\n\n    // Condense output if not explicitly requested.\n    let requested_pretty = || std::env::args().any(|x| x.contains(\"--format\"));\n    if matches!(args.format, ui_test::Format::Pretty) && !requested_pretty() {\n        args.format = ui_test::Format::Terse;\n    }\n\n    let config = config(cmd, cmd_path, &args, testdata);\n\n    let text_emitter: Box<dyn StatusEmitter> = args.format.into();\n    let gha_emitter = Gha { name: \"Foundry Lint UI\".to_string(), group: true };\n    let status_emitter = (text_emitter, gha_emitter);\n\n    // run tests on all .sol files\n    ui_test::run_tests_generic(\n        vec![config],\n        move |path, _config| Some(path.extension().is_some_and(|ext| ext == \"sol\")),\n        per_file_config,\n        status_emitter,\n    )?;\n\n    Ok(())\n}\n\nfn config<'a>(\n    cmd: &str,\n    cmd_path: &'a Path,\n    args: &ui_test::Args,\n    testdata: &'a Path,\n) -> ui_test::Config {\n    let root = testdata.parent().unwrap();\n    assert!(\n        testdata.exists(),\n        \"testdata directory does not exist: {};\\n\\\n         you may need to initialize submodules: `git submodule update --init --checkout`\",\n        testdata.display()\n    );\n\n    let mut config = ui_test::Config {\n        host: Some(get_host().to_string()),\n        target: None,\n        root_dir: testdata.into(),\n        program: ui_test::CommandBuilder {\n            program: cmd_path.into(),\n            args: {\n                let args = vec![cmd, \"--json\", \"--root\", testdata.to_str().expect(\"invalid root\")];\n                args.into_iter().map(Into::into).collect()\n            },\n            out_dir_flag: None,\n            input_file_flag: None,\n            envs: vec![(\"FOUNDRY_LINT_UI_TESTING\".into(), Some(\"1\".into()))],\n            cfg_flag: None,\n        },\n        output_conflict_handling: ui_test::error_on_output_conflict,\n        bless_command: Some(\"cargo test -p forge --test ui -- --bless\".into()),\n        out_dir: root.join(\"target\").join(\"ui\"),\n        comment_start: \"//\",\n        diagnostic_extractor: ui_test::diagnostics::rustc::rustc_diagnostics_extractor,\n        ..ui_test::Config::dummy()\n    };\n\n    macro_rules! register_custom_flags {\n        ($($ty:ty),* $(,)?) => {\n            $(\n                config.custom_comments.insert(<$ty>::NAME, <$ty>::parse);\n                if let Some(default) = <$ty>::DEFAULT {\n                    config.comment_defaults.base().add_custom(<$ty>::NAME, default);\n                }\n            )*\n        };\n    }\n    register_custom_flags![];\n\n    config.comment_defaults.base().exit_status = None.into();\n    config.comment_defaults.base().require_annotations = Spanned::dummy(true).into();\n    config.comment_defaults.base().require_annotations_for_level =\n        Spanned::dummy(ui_test::diagnostics::Level::Warn).into();\n\n    let filters = [\n        (ui_test::Match::PathBackslash, b\"/\".to_vec()),\n        #[cfg(windows)]\n        (ui_test::Match::Exact(vec![b'\\r']), b\"\".to_vec()),\n        #[cfg(windows)]\n        (ui_test::Match::Exact(br\"\\\\?\\\".to_vec()), b\"\".to_vec()),\n        (root.into(), b\"ROOT\".to_vec()),\n    ];\n    config.comment_defaults.base().normalize_stderr.extend(filters.iter().cloned());\n    config.comment_defaults.base().normalize_stdout.extend(filters);\n\n    let filters: &[(&str, &str)] = &[\n        // Erase line and column info.\n        (r\"\\.(\\w+):[0-9]+:[0-9]+(: [0-9]+:[0-9]+)?\", \".$1:LL:CC\"),\n    ];\n    for &(pattern, replacement) in filters {\n        config.filter(pattern, replacement);\n    }\n\n    let stdout_filters: &[(&str, &str)] =\n        &[(&env!(\"CARGO_PKG_VERSION\").replace(\".\", r\"\\.\"), \"VERSION\")];\n    for &(pattern, replacement) in stdout_filters {\n        config.stdout_filter(pattern, replacement);\n    }\n    let stderr_filters: &[(&str, &str)] = &[];\n    for &(pattern, replacement) in stderr_filters {\n        config.stderr_filter(pattern, replacement);\n    }\n\n    config.with_args(args);\n    config\n}\n\nfn per_file_config(config: &mut ui_test::Config, file: &Spanned<Vec<u8>>) {\n    let Ok(src) = std::str::from_utf8(&file.content) else {\n        return;\n    };\n\n    assert_eq!(config.comment_start, \"//\");\n    let has_annotations = src.contains(\"//~\");\n    config.comment_defaults.base().require_annotations = Spanned::dummy(has_annotations).into();\n    let code = if has_annotations && src.contains(\"ERROR:\") { 1 } else { 0 };\n    config.comment_defaults.base().exit_status = Spanned::dummy(code).into();\n}\n\nfn get_host() -> &'static str {\n    static CACHE: std::sync::OnceLock<String> = std::sync::OnceLock::new();\n    CACHE.get_or_init(|| {\n        let mut config = ui_test::Config::dummy();\n        config.program = ui_test::CommandBuilder::rustc();\n        config.fill_host_and_target().unwrap();\n        config.host.unwrap()\n    })\n}\n"
  },
  {
    "path": "crates/test-utils/src/util.rs",
    "content": "use foundry_compilers::{Project, ProjectCompileOutput, Vyper, utils::RuntimeOrHandle};\nuse foundry_config::Config;\nuse std::{\n    env,\n    fs::{self, File},\n    io::{Read, Seek, Write},\n    path::{Path, PathBuf},\n    process::Command,\n    sync::LazyLock,\n};\n\n/// Directories to skip when copying project directories.\n/// These are build artifacts and runtime-generated files that should not be copied to temp\n/// workspaces.\nconst SKIP_DIRS: &[&str] = &[\"out\", \"cache\", \"broadcast\"];\n\npub use crate::{ext::*, prj::*};\n\n/// The commit of forge-std to use.\npub const FORGE_STD_REVISION: &str = include_str!(\"../../../testdata/forge-std-rev\");\n\n/// Global default template path. Contains the global template project from which all other\n/// temp projects are initialized. See [`initialize()`] for more info.\nstatic TEMPLATE_PATH: LazyLock<PathBuf> =\n    LazyLock::new(|| env::temp_dir().join(\"foundry-forge-test-template\"));\n\n/// Global default template lock. If its contents are not exactly `\"1\"`, the global template will\n/// be re-initialized. See [`initialize()`] for more info.\nstatic TEMPLATE_LOCK: LazyLock<PathBuf> =\n    LazyLock::new(|| env::temp_dir().join(\"foundry-forge-test-template.lock\"));\n\n/// The default Solc version used when compiling tests.\npub const SOLC_VERSION: &str = \"0.8.33\";\n\n/// Another Solc version used when compiling tests.\n///\n/// Necessary to avoid downloading multiple versions.\npub const OTHER_SOLC_VERSION: &str = \"0.8.26\";\n\n/// Initializes a project with `forge init` at the given path from a template directory.\n///\n/// This should be called after an empty project is created like in\n/// [some of this crate's macros](crate::forgetest_init).\n///\n/// ## Note\n///\n/// This doesn't always run `forge init`, instead opting to copy an already-initialized template\n/// project from a global template path. This is done to speed up tests.\n///\n/// This used to use a `static` `Lazy`, but this approach does not with `cargo-nextest` because it\n/// runs each test in a separate process. Instead, we use a global lock file to ensure that only one\n/// test can initialize the template at a time.\n///\n/// This sets the project's solc version to the [`SOLC_VERSION`].\npub fn initialize(target: &Path) {\n    test_debug!(\"initializing {}\", target.display());\n\n    let tpath = TEMPLATE_PATH.as_path();\n    pretty_err(tpath, fs::create_dir_all(tpath));\n\n    // Initialize the global template if necessary.\n    let mut lock = crate::fd_lock::new_lock(TEMPLATE_LOCK.as_path());\n    let mut _read = lock.read().unwrap();\n    if !crate::fd_lock::lock_exists(TEMPLATE_LOCK.as_path()) {\n        // We are the first to acquire the lock:\n        // - initialize a new empty temp project;\n        // - run `forge init`;\n        // - run `forge build`;\n        // - copy it over to the global template;\n        // Ideally we would be able to initialize a temp project directly in the global template,\n        // but `TempProject` does not currently allow this: https://github.com/foundry-rs/compilers/issues/22\n\n        // Release the read lock and acquire a write lock, initializing the lock file.\n        drop(_read);\n        let mut write = lock.write().unwrap();\n\n        let mut data = Vec::new();\n        write.read_to_end(&mut data).unwrap();\n        if data != crate::fd_lock::LOCK_TOKEN {\n            // Initialize and build.\n            let (prj, mut cmd) = setup_forge(\"template\", foundry_compilers::PathStyle::Dapptools);\n            test_debug!(\"- initializing template dir in {}\", prj.root().display());\n\n            cmd.args([\"init\", \"--force\", \"--empty\"]).assert_success();\n            prj.write_config(Config {\n                solc: Some(foundry_config::SolcReq::Version(SOLC_VERSION.parse().unwrap())),\n                ..Default::default()\n            });\n\n            // Checkout forge-std.\n            let output = Command::new(\"git\")\n                .current_dir(prj.root().join(\"lib/forge-std\"))\n                .args([\"checkout\", FORGE_STD_REVISION])\n                .output()\n                .expect(\"failed to checkout forge-std\");\n            assert!(output.status.success(), \"{output:#?}\");\n\n            // Build the project.\n            cmd.forge_fuse().arg(\"build\").assert_success();\n\n            // Remove the existing template, if any.\n            let _ = fs::remove_dir_all(tpath);\n\n            // Copy the template to the global template path, excluding build artifacts.\n            pretty_err(tpath, copy_dir_filtered(prj.root(), tpath));\n\n            // Update lockfile to mark that template is initialized.\n            write.set_len(0).unwrap();\n            write.seek(std::io::SeekFrom::Start(0)).unwrap();\n            write.write_all(crate::fd_lock::LOCK_TOKEN).unwrap();\n        }\n\n        // Release the write lock and acquire a new read lock.\n        drop(write);\n        _read = lock.read().unwrap();\n    }\n\n    test_debug!(\"- copying template dir from {}\", tpath.display());\n    pretty_err(target, fs::create_dir_all(target));\n    pretty_err(target, copy_dir_filtered(tpath, target));\n}\n\n/// Compile the project with a lock for the cache.\npub fn get_compiled(project: &mut Project) -> ProjectCompileOutput {\n    let lock_file_path = project.sources_path().join(\".lock\");\n    // We need to use a file lock because `cargo-nextest` runs tests in different processes.\n    // This is similar to `initialize`, see its comments for more details.\n    let mut lock = crate::fd_lock::new_lock(&lock_file_path);\n    let read = lock.read().unwrap();\n    let out;\n\n    let mut write = None;\n    if !project.cache_path().exists() || !crate::fd_lock::lock_exists(&lock_file_path) {\n        drop(read);\n        write = Some(lock.write().unwrap());\n        test_debug!(\"cache miss for {}\", lock_file_path.display());\n    } else {\n        test_debug!(\"cache hit for {}\", lock_file_path.display());\n    }\n\n    if project.compiler.vyper.is_none() {\n        project.compiler.vyper = Some(get_vyper());\n    }\n\n    test_debug!(\"compiling {}\", lock_file_path.display());\n    out = project.compile().unwrap();\n    test_debug!(\"compiled {}\", lock_file_path.display());\n\n    if out.has_compiler_errors() {\n        panic!(\"Compiled with errors:\\n{out}\");\n    }\n\n    if let Some(write) = &mut write {\n        write.write_all(crate::fd_lock::LOCK_TOKEN).unwrap();\n    }\n\n    out\n}\n\n/// Installs Vyper if it's not already present.\npub fn get_vyper() -> Vyper {\n    static VYPER: LazyLock<PathBuf> = LazyLock::new(|| std::env::temp_dir().join(\"vyper\"));\n\n    if let Ok(vyper) = Vyper::new(\"vyper\") {\n        return vyper;\n    }\n    if let Ok(vyper) = Vyper::new(&*VYPER) {\n        return vyper;\n    }\n    return RuntimeOrHandle::new().block_on(install());\n\n    async fn install() -> Vyper {\n        #[cfg(target_family = \"unix\")]\n        use std::{fs::Permissions, os::unix::fs::PermissionsExt};\n\n        let path = VYPER.as_path();\n        let mut file = File::create(path).unwrap();\n        if let Err(e) = file.try_lock() {\n            if let fs::TryLockError::WouldBlock = e {\n                file.lock().unwrap();\n                assert!(path.exists());\n                return Vyper::new(path).unwrap();\n            }\n            file.lock().unwrap();\n        }\n\n        let suffix = match svm::platform() {\n            svm::Platform::MacOsAarch64 => \"darwin\",\n            svm::Platform::LinuxAmd64 => \"linux\",\n            svm::Platform::WindowsAmd64 => \"windows.exe\",\n            platform => panic!(\n                \"unsupported platform {platform:?} for installing vyper, \\\n                 install it manually and add it to $PATH\"\n            ),\n        };\n        let url = format!(\n            \"https://github.com/vyperlang/vyper/releases/download/v0.4.3/vyper.0.4.3+commit.bff19ea2.{suffix}\"\n        );\n\n        test_debug!(\"downloading vyper from {url}\");\n        let res = reqwest::Client::builder().build().unwrap().get(url).send().await.unwrap();\n\n        assert!(res.status().is_success());\n\n        let bytes = res.bytes().await.unwrap();\n\n        file.write_all(&bytes).unwrap();\n\n        #[cfg(target_family = \"unix\")]\n        file.set_permissions(Permissions::from_mode(0o755)).unwrap();\n\n        Vyper::new(path).unwrap()\n    }\n}\n\n#[track_caller]\npub fn pretty_err<T, E: std::error::Error>(path: impl AsRef<Path>, res: Result<T, E>) -> T {\n    match res {\n        Ok(t) => t,\n        Err(err) => panic!(\"{}: {err}\", path.as_ref().display()),\n    }\n}\n\npub fn read_string(path: impl AsRef<Path>) -> String {\n    let path = path.as_ref();\n    pretty_err(path, std::fs::read_to_string(path))\n}\n\n/// Copies the directory at `src` to `dst`, skipping build artifact directories.\n///\n/// This is similar to `foundry_compilers::project_util::copy_dir`, but skips directories\n/// like `out/`, `cache/`, and `broadcast/` which are build artifacts that should not be\n/// copied to temporary test workspaces.\npub fn copy_dir_filtered(src: &Path, dst: &Path) -> std::io::Result<()> {\n    fs::create_dir_all(dst)?;\n    copy_dir_filtered_inner(src, dst, true)\n}\n\nfn copy_dir_filtered_inner(src: &Path, dst: &Path, is_root: bool) -> std::io::Result<()> {\n    for entry in fs::read_dir(src)? {\n        let entry = entry?;\n        let ty = entry.file_type()?;\n        let src_path = entry.path();\n        let dst_path = dst.join(entry.file_name());\n\n        if ty.is_dir() {\n            // Skip build artifact directories at the root level\n            if is_root\n                && let Some(name) = entry.file_name().to_str()\n                && SKIP_DIRS.contains(&name)\n            {\n                continue;\n            }\n            fs::create_dir_all(&dst_path)?;\n            copy_dir_filtered_inner(&src_path, &dst_path, false)?;\n        } else {\n            fs::copy(&src_path, &dst_path)?;\n        }\n    }\n    Ok(())\n}\n"
  },
  {
    "path": "crates/verify/Cargo.toml",
    "content": "[package]\nname = \"forge-verify\"\ndescription = \"Contract verification tools\"\n\nversion.workspace = true\nedition.workspace = true\nrust-version.workspace = true\nauthors.workspace = true\nlicense.workspace = true\nhomepage.workspace = true\nrepository.workspace = true\n\n[lints]\nworkspace = true\n\n[dependencies]\nfoundry-config.workspace = true\nfoundry-cli.workspace = true\nfoundry-common.workspace = true\nfoundry-evm.workspace = true\nfoundry-evm-networks.workspace = true\nserde_json.workspace = true\nalloy-consensus.workspace = true\nalloy-json-abi.workspace = true\nalloy-primitives.workspace = true\nalloy-rpc-types = { workspace = true, features = [\"eth\", \"trace\"] }\nalloy-dyn-abi.workspace = true\nserde.workspace = true\neyre.workspace = true\nalloy-provider = { workspace = true, features = [\"trace-api\"] }\ntracing.workspace = true\nfoundry-compilers.workspace = true\nfoundry-block-explorers = { workspace = true, features = [\"foundry-compilers\"] }\nrevm.workspace = true\nalloy-evm = { workspace = true, features = [\"rpc\"] }\n\nclap = { version = \"4\", features = [\"derive\", \"env\", \"unicode\", \"wrap_help\"] }\nreqwest = { workspace = true, features = [\"json\"] }\nasync-trait.workspace = true\nfutures.workspace = true\nsemver.workspace = true\nregex = { workspace = true, default-features = false }\nyansi.workspace = true\nitertools.workspace = true\nurl.workspace = true\n\n[dev-dependencies]\ntokio = { workspace = true, features = [\"macros\"] }\nfoundry-test-utils.workspace = true\ntempfile.workspace = true\n"
  },
  {
    "path": "crates/verify/src/bytecode.rs",
    "content": "//! The `forge verify-bytecode` command.\nuse crate::{\n    etherscan::EtherscanVerificationProvider,\n    utils::{\n        BytecodeType, JsonResult, check_and_encode_args, check_explorer_args, configure_env_block,\n        maybe_predeploy_contract,\n    },\n    verify::VerifierArgs,\n};\nuse alloy_consensus::BlockHeader;\nuse alloy_evm::{FromRecoveredTx, rpc::TryIntoTxEnv};\nuse alloy_primitives::{Address, Bytes, TxKind, U256, hex};\nuse alloy_provider::{\n    Provider,\n    ext::TraceApi,\n    network::{\n        AnyTxEnvelope, TransactionBuilder, TransactionResponse, primitives::BlockTransactions,\n    },\n};\nuse alloy_rpc_types::{\n    BlockId, BlockNumberOrTag, TransactionInput, TransactionRequest, TransactionTrait,\n    trace::parity::{Action, CreateAction, CreateOutput, TraceOutput},\n};\nuse clap::{Parser, ValueHint};\nuse eyre::{Context, OptionExt, Result};\nuse foundry_cli::{\n    opts::EtherscanOpts,\n    utils::{self, LoadConfig, read_constructor_args_file},\n};\nuse foundry_common::{SYSTEM_TRANSACTION_TYPE, is_known_system_sender, shell};\nuse foundry_compilers::{artifacts::EvmVersion, info::ContractInfo};\nuse foundry_config::{Config, figment, impl_figment_convert};\nuse foundry_evm::{constants::DEFAULT_CREATE2_DEPLOYER, executors::EvmError};\nuse revm::{context::TxEnv, state::AccountInfo};\nuse std::path::PathBuf;\n\nimpl_figment_convert!(VerifyBytecodeArgs);\n\n/// CLI arguments for `forge verify-bytecode`.\n#[derive(Clone, Debug, Parser)]\npub struct VerifyBytecodeArgs {\n    /// The address of the contract to verify.\n    pub address: Address,\n\n    /// The contract identifier in the form `<path>:<contractname>`.\n    pub contract: ContractInfo,\n\n    /// The block at which the bytecode should be verified.\n    #[arg(long, value_name = \"BLOCK\")]\n    pub block: Option<BlockId>,\n\n    /// The constructor args to generate the creation code.\n    #[arg(\n        long,\n        num_args(1..),\n        conflicts_with_all = &[\"constructor_args_path\", \"encoded_constructor_args\"],\n        value_name = \"ARGS\",\n    )]\n    pub constructor_args: Option<Vec<String>>,\n\n    /// The ABI-encoded constructor arguments.\n    #[arg(\n        long,\n        conflicts_with_all = &[\"constructor_args_path\", \"constructor_args\"],\n        value_name = \"HEX\",\n    )]\n    pub encoded_constructor_args: Option<String>,\n\n    /// The path to a file containing the constructor arguments.\n    #[arg(\n        long,\n        value_hint = ValueHint::FilePath,\n        value_name = \"PATH\",\n        conflicts_with_all = &[\"constructor_args\", \"encoded_constructor_args\"]\n    )]\n    pub constructor_args_path: Option<PathBuf>,\n\n    /// The rpc url to use for verification.\n    #[arg(short = 'r', long, value_name = \"RPC_URL\", env = \"ETH_RPC_URL\")]\n    pub rpc_url: Option<String>,\n\n    /// Etherscan options.\n    #[command(flatten)]\n    pub etherscan: EtherscanOpts,\n\n    /// Verifier options.\n    #[command(flatten)]\n    pub verifier: VerifierArgs,\n\n    /// The project's root path.\n    ///\n    /// By default root of the Git repository, if in one,\n    /// or the current working directory.\n    #[arg(long, value_hint = ValueHint::DirPath, value_name = \"PATH\")]\n    pub root: Option<PathBuf>,\n\n    /// Ignore verification for creation or runtime bytecode.\n    #[arg(long, value_name = \"BYTECODE_TYPE\")]\n    pub ignore: Option<BytecodeType>,\n}\n\nimpl figment::Provider for VerifyBytecodeArgs {\n    fn metadata(&self) -> figment::Metadata {\n        figment::Metadata::named(\"Verify Bytecode Provider\")\n    }\n\n    fn data(\n        &self,\n    ) -> Result<figment::value::Map<figment::Profile, figment::value::Dict>, figment::Error> {\n        let mut dict = self.etherscan.dict();\n\n        if let Some(api_key) = &self.verifier.verifier_api_key {\n            dict.insert(\"etherscan_api_key\".into(), api_key.as_str().into());\n        }\n\n        if let Some(block) = &self.block {\n            dict.insert(\"block\".into(), figment::value::Value::serialize(block)?);\n        }\n        if let Some(rpc_url) = &self.rpc_url {\n            dict.insert(\"eth_rpc_url\".into(), rpc_url.to_string().into());\n        }\n\n        Ok(figment::value::Map::from([(Config::selected_profile(), dict)]))\n    }\n}\n\nimpl VerifyBytecodeArgs {\n    /// Run the `verify-bytecode` command to verify the bytecode onchain against the locally built\n    /// bytecode.\n    pub async fn run(mut self) -> Result<()> {\n        // Setup\n        let config = self.load_config()?;\n        let provider = utils::get_provider(&config)?;\n\n        // If chain is not set, we try to get it from the RPC.\n        // If RPC is not set, the default chain is used.\n        let chain = match config.get_rpc_url() {\n            Some(_) => utils::get_chain(config.chain, &provider).await?,\n            None => config.chain.unwrap_or_default(),\n        };\n\n        // Set Etherscan options.\n        self.etherscan.chain = Some(chain);\n        self.etherscan.key = config.get_etherscan_config_with_chain(Some(chain))?.map(|c| c.key);\n\n        // Etherscan client\n        let etherscan =\n            EtherscanVerificationProvider.client(&self.etherscan, &self.verifier, &config)?;\n\n        // Get the bytecode at the address, bailing if it doesn't exist.\n        let code = provider.get_code_at(self.address).await?;\n        if code.is_empty() {\n            eyre::bail!(\"No bytecode found at address {}\", self.address);\n        }\n\n        if !shell::is_json() {\n            sh_println!(\n                \"Verifying bytecode for contract {} at address {}\",\n                self.contract.name,\n                self.address\n            )?;\n        }\n\n        let mut json_results: Vec<JsonResult> = vec![];\n\n        // Get creation tx hash.\n        let creation_data = etherscan.contract_creation_data(self.address).await;\n\n        // Check if contract is a predeploy\n        let (creation_data, maybe_predeploy) = maybe_predeploy_contract(creation_data)?;\n\n        trace!(maybe_predeploy = ?maybe_predeploy);\n\n        // Get the constructor args using `source_code` endpoint.\n        let source_code = etherscan.contract_source_code(self.address).await?;\n\n        // Check if the contract name matches.\n        let name = source_code.items.first().map(|item| item.contract_name.to_owned());\n        if name.as_ref() != Some(&self.contract.name) {\n            eyre::bail!(\"Contract name mismatch\");\n        }\n\n        // Obtain Etherscan compilation metadata.\n        let etherscan_metadata = source_code.items.first().unwrap();\n\n        // Obtain local artifact\n        let artifact = crate::utils::build_project(&self, &config)?;\n\n        // Get local bytecode (creation code)\n        let local_bytecode = artifact\n            .bytecode\n            .as_ref()\n            .and_then(|b| b.to_owned().into_bytes())\n            .ok_or_eyre(\"Unlinked bytecode is not supported for verification\")?;\n\n        // Get and encode user provided constructor args\n        let provided_constructor_args = if let Some(path) = self.constructor_args_path.to_owned() {\n            // Read from file\n            Some(read_constructor_args_file(path)?)\n        } else {\n            self.constructor_args.to_owned()\n        }\n        .map(|args| check_and_encode_args(&artifact, args))\n        .transpose()?\n        .or(self.encoded_constructor_args.to_owned().map(hex::decode).transpose()?);\n\n        let mut constructor_args = if let Some(provided) = provided_constructor_args {\n            provided.into()\n        } else {\n            // If no constructor args were provided, try to retrieve them from the explorer.\n            check_explorer_args(source_code.clone())?\n        };\n\n        // This fails only when the contract expects constructor args but NONE were provided OR\n        // retrieved from explorer (in case of predeploys).\n        crate::utils::check_args_len(&artifact, &constructor_args)?;\n\n        if maybe_predeploy {\n            if !shell::is_json() {\n                sh_warn!(\n                    \"Attempting to verify predeployed contract at {:?}. Ignoring creation code verification.\",\n                    self.address\n                )?;\n            }\n\n            // Append constructor args to the local_bytecode.\n            trace!(%constructor_args);\n            let mut local_bytecode_vec = local_bytecode.to_vec();\n            local_bytecode_vec.extend_from_slice(&constructor_args);\n\n            // Deploy at genesis\n            let gen_blk_num = 0_u64;\n            let (mut fork_config, evm_opts) = config.clone().load_config_and_evm_opts()?;\n            let (mut evm_env, _, mut executor) = crate::utils::get_tracing_executor(\n                &mut fork_config,\n                gen_blk_num,\n                etherscan_metadata.evm_version()?.unwrap_or(EvmVersion::default()),\n                evm_opts,\n            )\n            .await?;\n\n            evm_env.block_env.number = U256::ZERO;\n            let genesis_block = provider.get_block(gen_blk_num.into()).full().await?;\n\n            // Setup genesis tx_env and evm_evm.\n            let deployer = Address::with_last_byte(0x1);\n            let mut gen_tx_req = TransactionRequest::default()\n                .with_from(deployer)\n                .with_input(Bytes::from(local_bytecode_vec))\n                .into_create();\n\n            if let Some(ref block) = genesis_block {\n                configure_env_block(&mut evm_env, block, config.networks);\n                gen_tx_req.max_fee_per_gas = block.header.base_fee_per_gas().map(|g| g as u128);\n                gen_tx_req.gas = Some(block.header.gas_limit());\n                gen_tx_req.gas_price = block.header.base_fee_per_gas().map(|g| g as u128);\n            }\n\n            let kind = gen_tx_req.kind();\n            let tx_env = gen_tx_req.try_into_tx_env(&evm_env)?;\n\n            // Seed deployer account with funds\n            let account_info = AccountInfo {\n                balance: U256::from(100 * 10_u128.pow(18)),\n                nonce: 0,\n                ..Default::default()\n            };\n            executor.backend_mut().insert_account_info(deployer, account_info);\n\n            let fork_address = crate::utils::deploy_contract(\n                &mut executor,\n                &evm_env,\n                &tx_env,\n                config.evm_spec_id(),\n                kind,\n            )?;\n\n            // Compare runtime bytecode\n            let (deployed_bytecode, onchain_runtime_code) = crate::utils::get_runtime_codes(\n                &mut executor,\n                &provider,\n                self.address,\n                fork_address,\n                None,\n            )\n            .await?;\n\n            let match_type = crate::utils::match_bytecodes(\n                deployed_bytecode.original_byte_slice(),\n                &onchain_runtime_code,\n                &constructor_args,\n                true,\n                config.bytecode_hash,\n            );\n\n            crate::utils::print_result(\n                match_type,\n                BytecodeType::Runtime,\n                &mut json_results,\n                etherscan_metadata,\n                &config,\n            );\n\n            if shell::is_json() {\n                sh_println!(\"{}\", serde_json::to_string(&json_results)?)?;\n            }\n\n            return Ok(());\n        }\n\n        // We can unwrap directly as maybe_predeploy is false\n        let creation_data = creation_data.unwrap();\n        // Get transaction and receipt.\n        trace!(creation_tx_hash = ?creation_data.transaction_hash);\n        let transaction = provider\n            .get_transaction_by_hash(creation_data.transaction_hash)\n            .await\n            .or_else(|e| eyre::bail!(\"Couldn't fetch transaction from RPC: {:?}\", e))?\n            .ok_or_else(|| {\n                eyre::eyre!(\"Transaction not found for hash {}\", creation_data.transaction_hash)\n            })?;\n        let tx_hash = transaction.tx_hash();\n        let receipt = provider\n            .get_transaction_receipt(creation_data.transaction_hash)\n            .await\n            .or_else(|e| eyre::bail!(\"Couldn't fetch transaction receipt from RPC: {:?}\", e))?;\n        let receipt = if let Some(receipt) = receipt {\n            receipt\n        } else {\n            eyre::bail!(\n                \"Receipt not found for transaction hash {}\",\n                creation_data.transaction_hash\n            );\n        };\n\n        let creation_block = transaction.block_number;\n        let mut transaction: TransactionRequest = match transaction.inner.inner.inner() {\n            AnyTxEnvelope::Ethereum(tx) => tx.clone().into(),\n            AnyTxEnvelope::Unknown(_) => unreachable!(\"Unknown transaction type\"),\n        };\n\n        // Extract creation code from creation tx input.\n        let maybe_creation_code = if receipt.to.is_none()\n            && receipt.contract_address == Some(self.address)\n        {\n            match &transaction.input.input {\n                Some(input) => &input[..],\n                None => unreachable!(\"creation tx input is None\"),\n            }\n        } else if receipt.to == Some(DEFAULT_CREATE2_DEPLOYER) {\n            match &transaction.input.input {\n                Some(input) => &input[32..],\n                None => unreachable!(\"creation tx input is None\"),\n            }\n        } else {\n            // Try to get creation bytecode from tx trace.\n            let traces = provider\n                .trace_transaction(creation_data.transaction_hash)\n                .await\n                .unwrap_or_default();\n\n            let creation_bytecode =\n                traces.iter().find_map(|trace| match (&trace.trace.result, &trace.trace.action) {\n                    (\n                        Some(TraceOutput::Create(CreateOutput { address, .. })),\n                        Action::Create(CreateAction { init, .. }),\n                    ) if *address == self.address => Some(init.clone()),\n                    _ => None,\n                });\n\n            &creation_bytecode.ok_or_else(|| {\n                eyre::eyre!(\n                    \"Could not extract the creation code for contract at address {}\",\n                    self.address\n                )\n            })?\n        };\n\n        // In some cases, Etherscan will return incorrect constructor arguments. If this\n        // happens, try extracting arguments ourselves.\n        if !maybe_creation_code.ends_with(&constructor_args) {\n            trace!(\"mismatch of constructor args with etherscan\");\n            // If local bytecode is longer than on-chain one, this is probably not a match.\n            if maybe_creation_code.len() >= local_bytecode.len() {\n                constructor_args =\n                    Bytes::copy_from_slice(&maybe_creation_code[local_bytecode.len()..]);\n                trace!(\n                    target: \"forge::verify\",\n                    \"setting constructor args to latest {} bytes of bytecode\",\n                    constructor_args.len()\n                );\n            }\n        }\n\n        // Append constructor args to the local_bytecode.\n        trace!(%constructor_args);\n        let mut local_bytecode_vec = local_bytecode.to_vec();\n        local_bytecode_vec.extend_from_slice(&constructor_args);\n\n        trace!(ignore = ?self.ignore);\n        // Check if `--ignore` is set to `creation`.\n        if !self.ignore.is_some_and(|b| b.is_creation()) {\n            // Compare creation code with locally built bytecode and `maybe_creation_code`.\n            let match_type = crate::utils::match_bytecodes(\n                local_bytecode_vec.as_slice(),\n                maybe_creation_code,\n                &constructor_args,\n                false,\n                config.bytecode_hash,\n            );\n\n            crate::utils::print_result(\n                match_type,\n                BytecodeType::Creation,\n                &mut json_results,\n                etherscan_metadata,\n                &config,\n            );\n\n            // If the creation code does not match, the runtime also won't match. Hence return.\n            if match_type.is_none() {\n                crate::utils::print_result(\n                    None,\n                    BytecodeType::Runtime,\n                    &mut json_results,\n                    etherscan_metadata,\n                    &config,\n                );\n                if shell::is_json() {\n                    sh_println!(\"{}\", serde_json::to_string(&json_results)?)?;\n                }\n                return Ok(());\n            }\n        }\n\n        if !self.ignore.is_some_and(|b| b.is_runtime()) {\n            // Get contract creation block.\n            let simulation_block = match self.block {\n                Some(BlockId::Number(BlockNumberOrTag::Number(block))) => block,\n                Some(_) => eyre::bail!(\"Invalid block number\"),\n                None => {\n                    creation_block.ok_or_else(|| {\n                        eyre::eyre!(\"Failed to get block number of the contract creation tx, specify using the --block flag\")\n                    })?\n                }\n            };\n\n            // Fork the chain at `simulation_block`.\n            let (mut fork_config, evm_opts) = config.clone().load_config_and_evm_opts()?;\n            let (mut evm_env, mut tx_env, mut executor) = crate::utils::get_tracing_executor(\n                &mut fork_config,\n                simulation_block - 1, // env.fork_block_number\n                etherscan_metadata.evm_version()?.unwrap_or(EvmVersion::default()),\n                evm_opts,\n            )\n            .await?;\n            evm_env.block_env.number = U256::from(simulation_block);\n            let block = provider.get_block(simulation_block.into()).full().await?;\n\n            // Workaround for the NonceTooHigh issue as we're not simulating prior txs of the same\n            // block.\n            let prev_block_id = BlockId::number(simulation_block - 1);\n\n            // Use `transaction.from` instead of `creation_data.contract_creator` to resolve\n            // blockscout creation data discrepancy in case of CREATE2.\n            let prev_block_nonce = provider\n                .get_transaction_count(transaction.from.unwrap())\n                .block_id(prev_block_id)\n                .await?;\n            transaction.set_nonce(prev_block_nonce);\n\n            if let Some(ref block) = block {\n                configure_env_block(&mut evm_env, block, config.networks);\n\n                let BlockTransactions::Full(ref txs) = block.transactions else {\n                    return Err(eyre::eyre!(\"Could not get block txs\"));\n                };\n\n                // Replay txes in block until the contract creation one.\n                for tx in txs {\n                    trace!(\"replay tx::: {}\", tx.tx_hash());\n                    if is_known_system_sender(tx.from())\n                        || tx.transaction_type() == Some(SYSTEM_TRANSACTION_TYPE)\n                    {\n                        continue;\n                    }\n                    if tx.tx_hash() == tx_hash {\n                        break;\n                    }\n\n                    if let Some(tx_envelope) = tx.as_envelope() {\n                        tx_env = TxEnv::from_recovered_tx(tx_envelope, tx.from());\n                    }\n\n                    if let TxKind::Call(_) = tx.inner.kind() {\n                        executor.transact_with_env(evm_env.clone(), tx_env.clone()).wrap_err_with(\n                            || {\n                                format!(\n                                    \"Failed to execute transaction: {:?} in block {}\",\n                                    tx.tx_hash(),\n                                    evm_env.block_env.number\n                                )\n                            },\n                        )?;\n                    } else if let Err(error) =\n                        executor.deploy_with_env(evm_env.clone(), tx_env.clone(), None)\n                    {\n                        match error {\n                            // Reverted transactions should be skipped\n                            EvmError::Execution(_) => (),\n                            error => {\n                                return Err(error).wrap_err_with(|| {\n                                    format!(\n                                        \"Failed to deploy transaction: {:?} in block {}\",\n                                        tx.tx_hash(),\n                                        evm_env.block_env.number\n                                    )\n                                });\n                            }\n                        }\n                    }\n                }\n            }\n\n            // Replace the `input` with local creation code in the creation tx.\n            if let Some(TxKind::Call(to)) = transaction.kind() {\n                if to == DEFAULT_CREATE2_DEPLOYER {\n                    let mut input = transaction.input.input.unwrap()[..32].to_vec(); // Salt\n                    input.extend_from_slice(&local_bytecode_vec);\n                    transaction.input = TransactionInput::both(Bytes::from(input));\n\n                    // Deploy default CREATE2 deployer\n                    executor.deploy_create2_deployer()?;\n                }\n            } else {\n                transaction.input = TransactionInput::both(Bytes::from(local_bytecode_vec));\n            }\n\n            let kind = transaction.kind();\n            tx_env = transaction.try_into_tx_env(&evm_env)?;\n\n            let fork_address = crate::utils::deploy_contract(\n                &mut executor,\n                &evm_env,\n                &tx_env,\n                config.evm_spec_id(),\n                kind,\n            )?;\n\n            // State committed using deploy_with_env, now get the runtime bytecode from the db.\n            let (fork_runtime_code, onchain_runtime_code) = crate::utils::get_runtime_codes(\n                &mut executor,\n                &provider,\n                self.address,\n                fork_address,\n                Some(simulation_block),\n            )\n            .await?;\n\n            // Compare the onchain runtime bytecode with the runtime code from the fork.\n            let match_type = crate::utils::match_bytecodes(\n                fork_runtime_code.original_byte_slice(),\n                &onchain_runtime_code,\n                &constructor_args,\n                true,\n                config.bytecode_hash,\n            );\n\n            crate::utils::print_result(\n                match_type,\n                BytecodeType::Runtime,\n                &mut json_results,\n                etherscan_metadata,\n                &config,\n            );\n        }\n\n        if shell::is_json() {\n            sh_println!(\"{}\", serde_json::to_string(&json_results)?)?;\n        }\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "crates/verify/src/etherscan/flatten.rs",
    "content": "use super::{EtherscanSourceProvider, VerifyArgs};\nuse crate::provider::VerificationContext;\nuse eyre::Result;\nuse foundry_block_explorers::verify::CodeFormat;\nuse foundry_common::flatten;\nuse foundry_compilers::{\n    AggregatedCompilerOutput,\n    artifacts::{BytecodeHash, Source, Sources},\n    buildinfo::RawBuildInfo,\n    compilers::{\n        Compiler, CompilerInput,\n        solc::{SolcCompiler, SolcLanguage, SolcVersionedInput},\n    },\n    solc::Solc,\n};\nuse semver::{BuildMetadata, Version};\nuse std::path::Path;\n\n#[derive(Debug)]\npub struct EtherscanFlattenedSource;\nimpl EtherscanSourceProvider for EtherscanFlattenedSource {\n    fn source(\n        &self,\n        args: &VerifyArgs,\n        context: &VerificationContext,\n    ) -> Result<(String, String, CodeFormat)> {\n        let metadata = context.project.settings.solc.metadata.as_ref();\n        let bch = metadata.and_then(|m| m.bytecode_hash).unwrap_or_default();\n\n        eyre::ensure!(\n            bch == BytecodeHash::Ipfs,\n            \"When using flattened source, bytecodeHash must be set to ipfs because Etherscan uses IPFS in its Compiler Settings when re-compiling your code. BytecodeHash is currently: {}. Hint: Set the bytecodeHash key in your foundry.toml :)\",\n            bch,\n        );\n\n        let flattened_source = flatten(context.project.clone(), &context.target_path)?;\n        if !args.force {\n            // solc dry run of flattened code\n            self.check_flattened(\n                flattened_source.clone(),\n                &context.compiler_version,\n                &context.target_path,\n            )\n            .map_err(|err| {\n                eyre::eyre!(\n                    \"Failed to compile the flattened code locally: `{}`\\\n            To skip this solc dry, have a look at the `--force` flag of this command.\",\n                    err\n                )\n            })?;\n        }\n\n        Ok((flattened_source, context.target_name.clone(), CodeFormat::SingleFile))\n    }\n}\n\nimpl EtherscanFlattenedSource {\n    /// Attempts to compile the flattened content locally with the compiler version.\n    ///\n    /// This expects the completely flattened content and will try to compile it using the\n    /// provided compiler. If the compiler is missing it will be installed.\n    ///\n    /// # Errors\n    ///\n    /// If it failed to install a missing solc compiler\n    ///\n    /// # Exits\n    ///\n    /// If the solc compiler output contains errors, this could either be due to a bug in the\n    /// flattening code or could to conflict in the flattened code, for example if there are\n    /// multiple interfaces with the same name.\n    fn check_flattened(\n        &self,\n        content: impl Into<String>,\n        version: &Version,\n        contract_path: &Path,\n    ) -> Result<()> {\n        let version = strip_build_meta(version.clone());\n        let solc = Solc::find_or_install(&version)?;\n\n        let input = SolcVersionedInput::build(\n            Sources::from([(\"contract.sol\".into(), Source::new(content))]),\n            Default::default(),\n            SolcLanguage::Solidity,\n            version.clone(),\n        );\n\n        let out = SolcCompiler::Specific(solc).compile(&input)?;\n        if out.errors.iter().any(|e| e.is_error()) {\n            let mut o = AggregatedCompilerOutput::<SolcCompiler>::default();\n            o.extend(version, RawBuildInfo::new(&input, &out, false)?, \"default\", out);\n            let diags = o.diagnostics(&[], &[], Default::default());\n\n            eyre::bail!(\n                \"\\\nFailed to compile the flattened code locally.\nThis could be a bug, please inspect the output of `forge flatten {}` and report an issue.\nTo skip this solc dry, pass `--force`.\nDiagnostics: {diags}\",\n                contract_path.display()\n            );\n        }\n\n        Ok(())\n    }\n}\n\n/// Strips [BuildMetadata] from the [Version]\n///\n/// **Note:** this is only for local compilation as a dry run, therefore this will return a\n/// sanitized variant of the specific version so that it can be installed. This is merely\n/// intended to ensure the flattened code can be compiled without errors.\nfn strip_build_meta(version: Version) -> Version {\n    if version.build != BuildMetadata::EMPTY {\n        Version::new(version.major, version.minor, version.patch)\n    } else {\n        version\n    }\n}\n"
  },
  {
    "path": "crates/verify/src/etherscan/mod.rs",
    "content": "use crate::{\n    VerifierArgs,\n    provider::{VerificationContext, VerificationProvider},\n    retry::RETRY_CHECK_ON_VERIFY,\n    utils::ensure_solc_build_metadata,\n    verify::{ContractLanguage, VerifyArgs, VerifyCheckArgs},\n};\nuse alloy_json_abi::Function;\nuse alloy_primitives::hex;\nuse alloy_provider::Provider;\nuse alloy_rpc_types::TransactionTrait;\nuse eyre::{Context, OptionExt, Result, eyre};\nuse foundry_block_explorers::{\n    Client,\n    errors::EtherscanError,\n    verify::{CodeFormat, VerifyContract},\n};\nuse foundry_cli::{\n    opts::EtherscanOpts,\n    utils::{LoadConfig, get_provider, read_constructor_args_file},\n};\nuse foundry_common::{abi::encode_function_args, retry::RetryError};\nuse foundry_compilers::{Artifact, artifacts::BytecodeObject};\nuse foundry_config::Config;\nuse foundry_evm::constants::DEFAULT_CREATE2_DEPLOYER;\nuse regex::Regex;\nuse semver::BuildMetadata;\nuse std::{fmt::Debug, sync::LazyLock};\n\nmod flatten;\n\nmod standard_json;\n\npub static RE_BUILD_COMMIT: LazyLock<Regex> =\n    LazyLock::new(|| Regex::new(r\"(?P<commit>commit\\.[0-9,a-f]{8})\").unwrap());\n\n#[derive(Clone, Debug, Default)]\n#[non_exhaustive]\npub struct EtherscanVerificationProvider;\n\n/// The contract source provider for [EtherscanVerificationProvider]\n///\n/// Returns source, contract_name and the source [CodeFormat]\ntrait EtherscanSourceProvider: Send + Sync + Debug {\n    fn source(\n        &self,\n        args: &VerifyArgs,\n        context: &VerificationContext,\n    ) -> Result<(String, String, CodeFormat)>;\n}\n\n#[async_trait::async_trait]\nimpl VerificationProvider for EtherscanVerificationProvider {\n    async fn preflight_verify_check(\n        &mut self,\n        args: VerifyArgs,\n        context: VerificationContext,\n    ) -> Result<()> {\n        let _ = self.prepare_verify_request(&args, &context).await?;\n        Ok(())\n    }\n\n    async fn verify(&mut self, args: VerifyArgs, context: VerificationContext) -> Result<()> {\n        let (etherscan, verify_args) = self.prepare_verify_request(&args, &context).await?;\n\n        if !args.skip_is_verified_check\n            && self.is_contract_verified(&etherscan, &verify_args).await?\n        {\n            sh_println!(\n                \"\\nContract [{}] {:?} is already verified. Skipping verification.\",\n                verify_args.contract_name,\n                verify_args.address.to_checksum(None)\n            )?;\n\n            return Ok(());\n        }\n\n        trace!(?verify_args, \"submitting verification request\");\n\n        let resp = args\n            .retry\n            .into_retry()\n            .run_async(|| async {\n                sh_println!(\n                    \"\\nSubmitting verification for [{}] {}.\",\n                    verify_args.contract_name,\n                    verify_args.address\n                )?;\n                let resp = etherscan\n                    .submit_contract_verification(&verify_args)\n                    .await\n                    .wrap_err_with(|| {\n                        // valid json\n                        let args = serde_json::to_string(&verify_args).unwrap();\n                        format!(\"Failed to submit contract verification, payload:\\n{args}\")\n                    })?;\n\n                trace!(?resp, \"Received verification response\");\n\n                if resp.status == \"0\" {\n                    if resp.result == \"Contract source code already verified\"\n                        // specific for blockscout response\n                        || resp.result == \"Smart-contract already verified.\"\n                    {\n                        return Ok(None);\n                    }\n\n                    if resp.result.starts_with(\"Unable to locate ContractCode at\")\n                        || resp.result.starts_with(\"The address is not a smart contract\")\n                        || resp.result.starts_with(\"Address is not a smart-contract\")\n                    {\n                        warn!(\"{}\", resp.result);\n                        return Err(eyre!(\"Could not detect deployment: {}\", resp.result));\n                    }\n\n                    sh_err!(\n                        \"Encountered an error verifying this contract:\\nResponse: `{}`\\nDetails:\n                        `{}`\",\n                        resp.message,\n                        resp.result\n                    )?;\n                    warn!(\"Failed verify submission: {:?}\", resp);\n                    std::process::exit(1);\n                }\n\n                Ok(Some(resp))\n            })\n            .await?;\n\n        if let Some(resp) = resp {\n            sh_println!(\n                \"Submitted contract for verification:\\n\\tResponse: `{}`\\n\\tGUID: `{}`\\n\\tURL: {}\",\n                resp.message,\n                resp.result,\n                etherscan.address_url(args.address)\n            )?;\n\n            if args.watch {\n                let check_args = VerifyCheckArgs {\n                    id: resp.result,\n                    etherscan: args.etherscan,\n                    retry: RETRY_CHECK_ON_VERIFY,\n                    verifier: args.verifier,\n                };\n                return self.check(check_args).await;\n            }\n        } else {\n            sh_println!(\"Contract source code already verified\")?;\n        }\n\n        Ok(())\n    }\n\n    /// Executes the command to check verification status on Etherscan\n    async fn check(&self, args: VerifyCheckArgs) -> Result<()> {\n        let config = args.load_config()?;\n        let etherscan = self.client(&args.etherscan, &args.verifier, &config)?;\n        args.retry\n            .into_retry()\n            .run_async_until_break(|| async {\n                let resp = etherscan\n                    .check_contract_verification_status(args.id.clone())\n                    .await\n                    .wrap_err(\"Failed to request verification status\")\n                    .map_err(RetryError::Retry)?;\n\n                trace!(?resp, \"Received verification response\");\n\n                let _ = sh_println!(\n                    \"Contract verification status:\\nResponse: `{}`\\nDetails: `{}`\",\n                    resp.message,\n                    resp.result\n                );\n\n                if resp.result == \"Pending in queue\"\n                    || resp.result.starts_with(\"Error: contract does not exist\")\n                {\n                    return Err(RetryError::Retry(eyre!(\"Verification is still pending...\")));\n                }\n\n                if resp.result == \"Unable to verify\" {\n                    return Err(RetryError::Retry(eyre!(\"Unable to verify.\")));\n                }\n\n                if resp.result == \"Already Verified\" {\n                    let _ = sh_println!(\"Contract source code already verified\");\n                    return Ok(());\n                }\n\n                if resp.status == \"0\" {\n                    return Err(RetryError::Break(eyre!(\n                        \"Contract verification failed:\\nStatus: `{}`\\nResult: `{}`\",\n                        resp.status,\n                        resp.result\n                    )));\n                }\n\n                if resp.result == \"Pass - Verified\" {\n                    let _ = sh_println!(\"Contract successfully verified\");\n                }\n\n                Ok(())\n            })\n            .await\n            .wrap_err(\"Checking verification result failed\")\n    }\n}\n\nimpl EtherscanVerificationProvider {\n    /// Create a source provider\n    fn source_provider(&self, args: &VerifyArgs) -> Box<dyn EtherscanSourceProvider> {\n        if args.flatten {\n            Box::new(flatten::EtherscanFlattenedSource)\n        } else {\n            Box::new(standard_json::EtherscanStandardJsonSource)\n        }\n    }\n\n    /// Configures the API request to the Etherscan API using the given [`VerifyArgs`].\n    async fn prepare_verify_request(\n        &mut self,\n        args: &VerifyArgs,\n        context: &VerificationContext,\n    ) -> Result<(Client, VerifyContract)> {\n        let config = args.load_config()?;\n        let etherscan = self.client(&args.etherscan, &args.verifier, &config)?;\n        let verify_args = self.create_verify_request(args, context).await?;\n\n        Ok((etherscan, verify_args))\n    }\n\n    /// Queries the Etherscan API to verify if the contract is already verified.\n    async fn is_contract_verified(\n        &self,\n        etherscan: &Client,\n        verify_contract: &VerifyContract,\n    ) -> Result<bool> {\n        let check = etherscan.contract_abi(verify_contract.address).await;\n\n        if let Err(err) = check {\n            return match err {\n                EtherscanError::ContractCodeNotVerified(_) => Ok(false),\n                error => Err(error).wrap_err_with(|| {\n                    format!(\"Failed to obtain contract ABI for {}\", verify_contract.address)\n                }),\n            };\n        }\n\n        Ok(true)\n    }\n\n    /// Create an Etherscan client.\n    pub(crate) fn client(\n        &self,\n        etherscan_opts: &EtherscanOpts,\n        verifier_args: &VerifierArgs,\n        config: &Config,\n    ) -> Result<Client> {\n        let chain = etherscan_opts.chain.unwrap_or_default();\n        let etherscan_key = etherscan_opts.key();\n        let verifier_type = &verifier_args.verifier;\n        let verifier_url = verifier_args.verifier_url.as_deref();\n\n        // Verifier is etherscan if explicitly set or if no verifier set (default sourcify) but\n        // API key passed.\n        let is_etherscan = verifier_type.is_etherscan()\n            || (verifier_type.is_sourcify() && etherscan_key.is_some());\n        let etherscan_config = config.get_etherscan_config_with_chain(Some(chain))?;\n\n        let api_url =\n            verifier_url.or_else(|| etherscan_config.as_ref().map(|c| c.api_url.as_str()));\n        let base_url = etherscan_config\n            .as_ref()\n            .and_then(|c| c.browser_url.as_deref())\n            .or_else(|| chain.etherscan_urls().map(|(_, url)| url));\n        let etherscan_key =\n            etherscan_key.or_else(|| etherscan_config.as_ref().map(|c| c.key.clone()));\n\n        let mut builder = Client::builder();\n\n        builder = if let Some(api_url) = api_url {\n            // we don't want any trailing slashes because this can cause cloudflare issues: <https://github.com/foundry-rs/foundry/pull/6079>\n            let api_url = api_url.trim_end_matches('/');\n            let base_url = if !is_etherscan {\n                // If verifier is not Etherscan then set base url as api url without /api suffix.\n                api_url.strip_suffix(\"/api\").unwrap_or(api_url)\n            } else {\n                base_url.unwrap_or(api_url)\n            };\n            builder.with_api_url(api_url)?.with_url(base_url)?\n        } else {\n            builder.chain(chain)?\n        };\n\n        builder\n            .with_api_key(etherscan_key.unwrap_or_default())\n            .build()\n            .wrap_err(\"Failed to create Etherscan client\")\n    }\n\n    /// Creates the `VerifyContract` Etherscan request in order to verify the contract\n    ///\n    /// If `--flatten` is set to `true` then this will send with [`CodeFormat::SingleFile`]\n    /// otherwise this will use the [`CodeFormat::StandardJsonInput`]\n    pub async fn create_verify_request(\n        &mut self,\n        args: &VerifyArgs,\n        context: &VerificationContext,\n    ) -> Result<VerifyContract> {\n        let (source, contract_name, code_format) =\n            self.source_provider(args).source(args, context)?;\n\n        let lang = args.detect_language(context);\n\n        let mut compiler_version = context.compiler_version.clone();\n        compiler_version.build = match RE_BUILD_COMMIT.captures(compiler_version.build.as_str()) {\n            Some(cap) => BuildMetadata::new(cap.name(\"commit\").unwrap().as_str())?,\n            _ => BuildMetadata::EMPTY,\n        };\n\n        let compiler_version = if matches!(lang, ContractLanguage::Vyper) {\n            format!(\"vyper:{}\", compiler_version.to_string().split('+').next().unwrap_or(\"0.0.0\"))\n        } else {\n            format!(\"v{}\", ensure_solc_build_metadata(context.compiler_version.clone()).await?)\n        };\n\n        let constructor_args = self.constructor_args(args, context).await?;\n        let mut verify_args =\n            VerifyContract::new(args.address, contract_name, source, compiler_version)\n                .constructor_arguments(constructor_args)\n                .code_format(code_format);\n\n        if args.via_ir {\n            // we explicitly set this __undocumented__ argument to true if provided by the user,\n            // though this info is also available in the compiler settings of the standard json\n            // object if standard json is used\n            // unclear how Etherscan interprets this field in standard-json mode\n            verify_args = verify_args.via_ir(true);\n        }\n\n        if code_format == CodeFormat::SingleFile {\n            verify_args = if let Some(optimizations) = args.num_of_optimizations {\n                verify_args.optimized().runs(optimizations as u32)\n            } else if context.config.optimizer == Some(true) {\n                verify_args\n                    .optimized()\n                    .runs(context.config.optimizer_runs.unwrap_or(200).try_into()?)\n            } else {\n                verify_args.not_optimized()\n            };\n        }\n\n        if code_format == CodeFormat::VyperJson {\n            verify_args =\n                if args.num_of_optimizations.is_some() || context.config.optimizer == Some(true) {\n                    verify_args.optimized().runs(1)\n                } else {\n                    verify_args.not_optimized().runs(0)\n                }\n        }\n\n        Ok(verify_args)\n    }\n\n    /// Return the optional encoded constructor arguments. If the path to\n    /// constructor arguments was provided, read them and encode. Otherwise,\n    /// return whatever was set in the [VerifyArgs] args.\n    async fn constructor_args(\n        &mut self,\n        args: &VerifyArgs,\n        context: &VerificationContext,\n    ) -> Result<Option<String>> {\n        if let Some(ref constructor_args_path) = args.constructor_args_path {\n            let abi = context.get_target_abi()?;\n            let constructor = abi\n                .constructor()\n                .ok_or_else(|| eyre!(\"Can't retrieve constructor info from artifact ABI.\"))?;\n            let func = Function {\n                name: \"constructor\".to_string(),\n                inputs: constructor.inputs.clone(),\n                outputs: vec![],\n                state_mutability: alloy_json_abi::StateMutability::NonPayable,\n            };\n            let encoded_args = encode_function_args(\n                &func,\n                read_constructor_args_file(constructor_args_path.to_path_buf())?,\n            )?;\n            let encoded_args = hex::encode(encoded_args);\n            return Ok(Some(encoded_args[8..].into()));\n        }\n        if args.guess_constructor_args {\n            return Ok(Some(self.guess_constructor_args(args, context).await?));\n        }\n\n        Ok(args.constructor_args.clone())\n    }\n\n    /// Uses Etherscan API to fetch contract creation transaction.\n    /// If transaction is a create transaction or a invocation of default CREATE2 deployer, tries to\n    /// match provided creation code with local bytecode of the target contract.\n    /// If bytecode match, returns latest bytes of on-chain creation code as constructor arguments.\n    async fn guess_constructor_args(\n        &mut self,\n        args: &VerifyArgs,\n        context: &VerificationContext,\n    ) -> Result<String> {\n        let provider = get_provider(&context.config)?;\n        let client = self.client(&args.etherscan, &args.verifier, &context.config)?;\n\n        let creation_data = client.contract_creation_data(args.address).await?;\n        let transaction = provider\n            .get_transaction_by_hash(creation_data.transaction_hash)\n            .await?\n            .ok_or_eyre(\"Transaction not found\")?;\n        let receipt = provider\n            .get_transaction_receipt(creation_data.transaction_hash)\n            .await?\n            .ok_or_eyre(\"Couldn't fetch transaction receipt from RPC\")?;\n\n        let maybe_creation_code = if receipt.contract_address == Some(args.address) {\n            transaction.input()\n        } else if transaction.to() == Some(DEFAULT_CREATE2_DEPLOYER) {\n            &transaction.input()[32..]\n        } else {\n            eyre::bail!(\n                \"Fetching of constructor arguments is not supported for contracts created by contracts\"\n            )\n        };\n\n        let output = context.project.compile_file(&context.target_path)?;\n        let artifact = output\n            .find(&context.target_path, &context.target_name)\n            .ok_or_eyre(\"Contract artifact wasn't found locally\")?;\n        let bytecode = artifact\n            .get_bytecode_object()\n            .ok_or_eyre(\"Contract artifact does not contain bytecode\")?;\n\n        let bytecode = match bytecode.as_ref() {\n            BytecodeObject::Bytecode(bytes) => Ok(bytes),\n            BytecodeObject::Unlinked(_) => {\n                Err(eyre!(\"You have to provide correct libraries to use --guess-constructor-args\"))\n            }\n        }?;\n\n        if maybe_creation_code.starts_with(bytecode) {\n            let constructor_args = &maybe_creation_code[bytecode.len()..];\n            let constructor_args = hex::encode(constructor_args);\n            sh_println!(\"Identified constructor arguments: {constructor_args}\")?;\n            Ok(constructor_args)\n        } else {\n            eyre::bail!(\"Local bytecode doesn't match on-chain bytecode\")\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use crate::provider::VerificationProviderType;\n    use clap::Parser;\n    use foundry_common::fs;\n    use foundry_test_utils::{forgetest_async, str};\n    use tempfile::tempdir;\n\n    #[test]\n    fn can_extract_etherscan_verify_config() {\n        let temp = tempdir().unwrap();\n        let root = temp.path();\n\n        let config = r#\"\n                [profile.default]\n\n                [etherscan]\n                amoy = { key = \"dummykey\", chain = 80002, url = \"https://amoy.polygonscan.com/\" }\n            \"#;\n\n        let toml_file = root.join(Config::FILE_NAME);\n        fs::write(toml_file, config).unwrap();\n\n        let args: VerifyArgs = VerifyArgs::parse_from([\n            \"foundry-cli\",\n            \"0xd8509bee9c9bf012282ad33aba0d87241baf5064\",\n            \"src/Counter.sol:Counter\",\n            \"--chain\",\n            \"amoy\",\n            \"--root\",\n            root.as_os_str().to_str().unwrap(),\n        ]);\n\n        let config = args.load_config().unwrap();\n\n        let etherscan = EtherscanVerificationProvider::default();\n        let client = etherscan.client(&args.etherscan, &args.verifier, &config).unwrap();\n        // Custom URL from foundry.toml should be used\n        assert_eq!(client.etherscan_api_url().as_str(), \"https://amoy.polygonscan.com/\");\n\n        assert!(format!(\"{client:?}\").contains(\"dummykey\"));\n\n        let args: VerifyArgs = VerifyArgs::parse_from([\n            \"foundry-cli\",\n            \"0xd8509bee9c9bf012282ad33aba0d87241baf5064\",\n            \"src/Counter.sol:Counter\",\n            \"--chain\",\n            \"amoy\",\n            \"--verifier-url\",\n            \"https://verifier-url.com/\",\n            \"--root\",\n            root.as_os_str().to_str().unwrap(),\n        ]);\n\n        let config = args.load_config().unwrap();\n\n        let etherscan = EtherscanVerificationProvider::default();\n        let client = etherscan.client(&args.etherscan, &args.verifier, &config).unwrap();\n        assert_eq!(client.etherscan_api_url().as_str(), \"https://verifier-url.com/\");\n        assert!(format!(\"{client:?}\").contains(\"dummykey\"));\n    }\n\n    #[test]\n    fn can_extract_etherscan_v2_verify_config() {\n        let temp = tempdir().unwrap();\n        let root = temp.path();\n\n        let config = r#\"\n                [profile.default]\n\n                [etherscan]\n                amoy = { key = \"dummykey\", chain = 80002, url = \"https://amoy.polygonscan.com/\" }\n            \"#;\n\n        let toml_file = root.join(Config::FILE_NAME);\n        fs::write(toml_file, config).unwrap();\n\n        let args: VerifyArgs = VerifyArgs::parse_from([\n            \"foundry-cli\",\n            \"0xd8509bee9c9bf012282ad33aba0d87241baf5064\",\n            \"src/Counter.sol:Counter\",\n            \"--verifier\",\n            \"etherscan\",\n            \"--chain\",\n            \"amoy\",\n            \"--root\",\n            root.as_os_str().to_str().unwrap(),\n        ]);\n\n        let config = args.load_config().unwrap();\n\n        let etherscan = EtherscanVerificationProvider::default();\n\n        let client = etherscan.client(&args.etherscan, &args.verifier, &config).unwrap();\n\n        // Custom URL from foundry.toml should be used\n        assert_eq!(client.etherscan_api_url().as_str(), \"https://amoy.polygonscan.com/\");\n        assert!(format!(\"{client:?}\").contains(\"dummykey\"));\n\n        let args: VerifyArgs = VerifyArgs::parse_from([\n            \"foundry-cli\",\n            \"0xd8509bee9c9bf012282ad33aba0d87241baf5064\",\n            \"src/Counter.sol:Counter\",\n            \"--verifier\",\n            \"etherscan\",\n            \"--chain\",\n            \"amoy\",\n            \"--verifier-url\",\n            \"https://verifier-url.com/\",\n            \"--root\",\n            root.as_os_str().to_str().unwrap(),\n        ]);\n\n        let config = args.load_config().unwrap();\n\n        assert_eq!(args.verifier.verifier, VerificationProviderType::Etherscan);\n\n        let etherscan = EtherscanVerificationProvider::default();\n        let client = etherscan.client(&args.etherscan, &args.verifier, &config).unwrap();\n        assert_eq!(client.etherscan_api_url().as_str(), \"https://verifier-url.com/\");\n        assert!(format!(\"{client:?}\").contains(\"dummykey\"));\n    }\n\n    #[tokio::test(flavor = \"multi_thread\")]\n    async fn fails_on_disabled_cache_and_missing_info() {\n        let temp = tempdir().unwrap();\n        let root = temp.path();\n        let root_path = root.as_os_str().to_str().unwrap();\n\n        let config = r\"\n                [profile.default]\n                cache = false\n            \";\n\n        let toml_file = root.join(Config::FILE_NAME);\n        fs::write(toml_file, config).unwrap();\n\n        let address = \"0xd8509bee9c9bf012282ad33aba0d87241baf5064\";\n        let contract_name = \"Counter\";\n        let src_dir = \"src\";\n        fs::create_dir_all(root.join(src_dir)).unwrap();\n        let contract_path = format!(\"{src_dir}/Counter.sol\");\n        fs::write(root.join(&contract_path), \"\").unwrap();\n\n        // No compiler argument\n        let args = VerifyArgs::parse_from([\n            \"foundry-cli\",\n            address,\n            &format!(\"{contract_path}:{contract_name}\"),\n            \"--root\",\n            root_path,\n        ]);\n        let result = args.resolve_context().await;\n        assert!(result.is_err());\n        assert_eq!(\n            result.unwrap_err().to_string(),\n            \"If cache is disabled, compiler version must be either provided with `--compiler-version` option or set in foundry.toml\"\n        );\n    }\n\n    forgetest_async!(respects_path_for_duplicate, |prj, cmd| {\n        prj.add_source(\"Counter1\", \"contract Counter {}\");\n        prj.add_source(\"Counter2\", \"contract Counter {}\");\n\n        cmd.args([\"build\", \"--force\"]).assert_success().stdout_eq(str![[r#\"\n[COMPILING_FILES] with [SOLC_VERSION]\n...\n[SOLC_VERSION] [ELAPSED]\nCompiler run successful!\n\n\"#]]);\n\n        let args = VerifyArgs::parse_from([\n            \"foundry-cli\",\n            \"0x0000000000000000000000000000000000000000\",\n            \"src/Counter1.sol:Counter\",\n            \"--root\",\n            &prj.root().to_string_lossy(),\n        ]);\n        let context = args.resolve_context().await.unwrap();\n\n        let mut etherscan = EtherscanVerificationProvider::default();\n        etherscan.preflight_verify_check(args, context).await.unwrap();\n    });\n}\n"
  },
  {
    "path": "crates/verify/src/etherscan/standard_json.rs",
    "content": "use super::{EtherscanSourceProvider, VerifyArgs};\nuse crate::{provider::VerificationContext, verify::ContractLanguage};\nuse eyre::{Context, Result};\nuse foundry_block_explorers::verify::CodeFormat;\n\n#[derive(Debug)]\npub struct EtherscanStandardJsonSource;\nimpl EtherscanSourceProvider for EtherscanStandardJsonSource {\n    fn source(\n        &self,\n        args: &VerifyArgs,\n        context: &VerificationContext,\n    ) -> Result<(String, String, CodeFormat)> {\n        let lang = args.detect_language(context);\n\n        let code_format = match lang {\n            ContractLanguage::Solidity => CodeFormat::StandardJsonInput,\n            ContractLanguage::Vyper => CodeFormat::VyperJson,\n        };\n\n        let source = match lang {\n            ContractLanguage::Solidity => {\n                let input = context.get_solc_standard_json_input()?;\n                serde_json::to_string(&input).wrap_err(\"Failed to parse standard json input\")?\n            }\n            ContractLanguage::Vyper => {\n                let input = context.get_vyper_standard_json_input()?;\n                serde_json::to_string(&input).wrap_err(\"Failed to parse vyper json input\")?\n            }\n        };\n\n        trace!(target: \"forge::verify\", standard_json=source, \"determined standard json input\");\n\n        let name = format!(\n            \"{}:{}\",\n            context\n                .target_path\n                .strip_prefix(context.project.root())\n                .unwrap_or(context.target_path.as_path())\n                .display(),\n            context.target_name.clone()\n        );\n        Ok((source, name, code_format))\n    }\n}\n"
  },
  {
    "path": "crates/verify/src/lib.rs",
    "content": "//! Smart contract verification.\n\n#![cfg_attr(not(test), warn(unused_crate_dependencies))]\n#![cfg_attr(docsrs, feature(doc_cfg))]\n\n#[macro_use]\nextern crate foundry_common;\n\n#[macro_use]\nextern crate tracing;\n\nmod etherscan;\n\npub mod provider;\n\npub mod bytecode;\npub use bytecode::VerifyBytecodeArgs;\n\npub mod retry;\npub use retry::RetryArgs;\n\npub mod sourcify;\n\npub mod verify;\npub use verify::{VerifierArgs, VerifyArgs, VerifyCheckArgs};\n\nmod types;\n\nmod utils;\n"
  },
  {
    "path": "crates/verify/src/provider.rs",
    "content": "use crate::{\n    etherscan::EtherscanVerificationProvider,\n    sourcify::SourcifyVerificationProvider,\n    verify::{VerifyArgs, VerifyCheckArgs},\n};\nuse alloy_json_abi::JsonAbi;\nuse async_trait::async_trait;\nuse eyre::{Context, OptionExt, Result};\nuse foundry_common::compile::ProjectCompiler;\nuse foundry_compilers::{\n    Project,\n    artifacts::{\n        Source, StandardJsonCompilerInput, output_selection::OutputSelection, vyper::VyperInput,\n    },\n    compilers::solc::SolcCompiler,\n    multi::MultiCompilerSettings,\n    solc::{Solc, SolcLanguage},\n};\nuse foundry_config::{Chain, Config, EtherscanConfigError};\nuse semver::Version;\nuse std::{\n    fmt,\n    path::{Path, PathBuf},\n    str::FromStr,\n};\n\n/// Container with data required for contract verification.\n#[derive(Debug, Clone)]\npub struct VerificationContext {\n    pub config: Config,\n    pub project: Project,\n    pub target_path: PathBuf,\n    pub target_name: String,\n    pub compiler_version: Version,\n    pub compiler_settings: MultiCompilerSettings,\n}\n\nimpl VerificationContext {\n    pub fn new(\n        target_path: PathBuf,\n        target_name: String,\n        compiler_version: Version,\n        config: Config,\n        compiler_settings: MultiCompilerSettings,\n    ) -> Result<Self> {\n        let mut project = config.project()?;\n        project.no_artifacts = true;\n\n        let solc = Solc::find_or_install(&compiler_version)?;\n        project.compiler.solc = Some(SolcCompiler::Specific(solc));\n\n        Ok(Self { config, project, target_name, target_path, compiler_version, compiler_settings })\n    }\n\n    pub fn get_solc_standard_json_input(&self) -> Result<StandardJsonCompilerInput> {\n        let mut input: StandardJsonCompilerInput = self\n            .project\n            .standard_json_input(&self.target_path)\n            .wrap_err(\"Failed to get standard json input\")?\n            .normalize_evm_version(&self.compiler_version);\n\n        let mut settings = self.compiler_settings.solc.settings.clone();\n        settings.libraries.libs = input\n            .settings\n            .libraries\n            .libs\n            .into_iter()\n            .map(|(f, libs)| {\n                (f.strip_prefix(self.project.root()).unwrap_or(&f).to_path_buf(), libs)\n            })\n            .collect();\n\n        settings.remappings = input.settings.remappings;\n        settings.sanitize(&self.compiler_version, SolcLanguage::Solidity);\n        input.settings = settings;\n\n        Ok(input)\n    }\n\n    /// Creates Vyper standard JSON input for verification.\n    pub fn get_vyper_standard_json_input(&self) -> Result<VyperInput> {\n        let path = Path::new(&self.target_path);\n        let sources = Source::read_all_from(path, &[\"vy\", \"vyi\"])?;\n        Ok(VyperInput::new(sources, self.compiler_settings.vyper.clone(), &self.compiler_version))\n    }\n\n    /// Compiles target contract requesting only ABI and returns it.\n    pub fn get_target_abi(&self) -> Result<JsonAbi> {\n        let mut project = self.project.clone();\n        project.update_output_selection(|selection| {\n            *selection = OutputSelection::common_output_selection([\"abi\".to_string()]);\n        });\n\n        let output = ProjectCompiler::new()\n            .quiet(true)\n            .files([self.target_path.clone()])\n            .compile(&project)?;\n\n        let artifact = output\n            .find(&self.target_path, &self.target_name)\n            .ok_or_eyre(\"failed to find target artifact when compiling for abi\")?;\n\n        artifact.abi.clone().ok_or_eyre(\"target artifact does not have an ABI\")\n    }\n}\n\n/// An abstraction for various verification providers such as etherscan, sourcify, blockscout\n#[async_trait]\npub trait VerificationProvider {\n    /// This should ensure the verify request can be prepared successfully.\n    ///\n    /// Caution: Implementers must ensure that this _never_ sends the actual verify request\n    /// `[VerificationProvider::verify]`, instead this is supposed to evaluate whether the given\n    /// [`VerifyArgs`] are valid to begin with. This should prevent situations where there's a\n    /// contract deployment that's executed before the verify request and the subsequent verify task\n    /// fails due to misconfiguration.\n    async fn preflight_verify_check(\n        &mut self,\n        args: VerifyArgs,\n        context: VerificationContext,\n    ) -> Result<()>;\n\n    /// Sends the actual verify request for the targeted contract.\n    async fn verify(&mut self, args: VerifyArgs, context: VerificationContext) -> Result<()>;\n\n    /// Checks whether the contract is verified.\n    async fn check(&self, args: VerifyCheckArgs) -> Result<()>;\n}\n\nimpl FromStr for VerificationProviderType {\n    type Err = String;\n\n    fn from_str(s: &str) -> Result<Self, Self::Err> {\n        match s {\n            \"e\" | \"etherscan\" => Ok(Self::Etherscan),\n            \"s\" | \"sourcify\" => Ok(Self::Sourcify),\n            \"b\" | \"blockscout\" => Ok(Self::Blockscout),\n            \"o\" | \"oklink\" => Ok(Self::Oklink),\n            \"c\" | \"custom\" => Ok(Self::Custom),\n            _ => Err(format!(\"Unknown provider: {s}\")),\n        }\n    }\n}\n\nimpl fmt::Display for VerificationProviderType {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        match self {\n            Self::Etherscan => {\n                write!(f, \"etherscan\")?;\n            }\n            Self::Sourcify => {\n                write!(f, \"sourcify\")?;\n            }\n            Self::Blockscout => {\n                write!(f, \"blockscout\")?;\n            }\n            Self::Oklink => {\n                write!(f, \"oklink\")?;\n            }\n            Self::Custom => {\n                write!(f, \"custom\")?;\n            }\n        };\n        Ok(())\n    }\n}\n\n#[derive(Clone, Debug, Default, PartialEq, Eq, clap::ValueEnum)]\npub enum VerificationProviderType {\n    Etherscan,\n    #[default]\n    Sourcify,\n    Blockscout,\n    Oklink,\n    /// Custom verification provider, requires compatibility with the Etherscan API.\n    Custom,\n}\n\nimpl VerificationProviderType {\n    /// Returns the corresponding `VerificationProvider` for the key\n    pub fn client(\n        &self,\n        key: Option<&str>,\n        chain: Option<Chain>,\n        has_url: bool,\n    ) -> Result<Box<dyn VerificationProvider>> {\n        let has_key = key.as_ref().is_some_and(|k| !k.is_empty());\n        // 1. If no verifier or `--verifier sourcify` is set and no API key provided, use Sourcify.\n        if !has_key && self.is_sourcify() {\n            sh_println!(\n                \"Attempting to verify on Sourcify. Pass the --etherscan-api-key <API_KEY> to verify on Etherscan, \\\n            or use the --verifier flag to verify on another provider.\"\n            )?;\n            return Ok(Box::<SourcifyVerificationProvider>::default());\n        }\n\n        // 2. If `--verifier etherscan` is explicitly set, check if chain is supported and\n        // enforce the API key requirement.\n        if self.is_etherscan() {\n            if let Some(chain) = chain\n                && chain.etherscan_urls().is_none()\n                && !has_url\n            {\n                eyre::bail!(EtherscanConfigError::UnknownChain(\n                    \"when using Etherscan verifier\".to_string(),\n                    chain\n                ))\n            }\n            if !has_key {\n                eyre::bail!(\"ETHERSCAN_API_KEY must be set to use Etherscan as a verifier\")\n            }\n            return Ok(Box::<EtherscanVerificationProvider>::default());\n        }\n\n        // 3. If `--verifier blockscout | oklink | custom` is explicitly set, use the chosen\n        //    verifier and make sure an URL was specified.\n        if matches!(self, Self::Blockscout | Self::Oklink | Self::Custom) {\n            if !has_url {\n                eyre::bail!(\"No verifier URL specified for verifier {}\", self);\n            }\n            return Ok(Box::<EtherscanVerificationProvider>::default());\n        }\n\n        // 4. If no `--verifier` is specified but `ETHERSCAN_API_KEY` is set, default to Etherscan.\n        if has_key {\n            return Ok(Box::<EtherscanVerificationProvider>::default());\n        }\n\n        // 5. If no valid provider is specified, bail.\n        eyre::bail!(\n            \"No valid verification provider specified. Pass the --verifier flag to specify a provider or set the ETHERSCAN_API_KEY environment variable to use Etherscan as a verifier.\"\n        )\n    }\n\n    pub fn is_sourcify(&self) -> bool {\n        matches!(self, Self::Sourcify)\n    }\n\n    pub fn is_etherscan(&self) -> bool {\n        matches!(self, Self::Etherscan)\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn etherscan_allows_unknown_chain_with_verifier_url() {\n        let chain = Chain::from(3658348u64);\n        let res = VerificationProviderType::Etherscan.client(Some(\"key\"), Some(chain), true);\n        assert!(res.is_ok());\n    }\n\n    #[test]\n    fn etherscan_rejects_unknown_chain_without_verifier_url() {\n        let chain = Chain::from(3658348u64);\n        let res = VerificationProviderType::Etherscan.client(Some(\"key\"), Some(chain), false);\n        match res {\n            Ok(_) => panic!(\"expected unknown-chain error\"),\n            Err(err) => {\n                assert!(err.to_string().contains(\"No known Etherscan API URL\"));\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "crates/verify/src/retry.rs",
    "content": "use clap::{Parser, builder::RangedU64ValueParser};\nuse foundry_common::retry::Retry;\nuse std::time::Duration;\n\n/// Retry config used when waiting for verification\npub const RETRY_CHECK_ON_VERIFY: RetryArgs = RetryArgs { retries: 8, delay: 15 };\n\n/// Retry config used when waiting for a created contract\npub const RETRY_VERIFY_ON_CREATE: RetryArgs = RetryArgs { retries: 15, delay: 5 };\n\n/// Retry arguments for contract verification.\n#[derive(Clone, Copy, Debug, Parser)]\n#[command(about = \"Allows to use retry arguments for contract verification\")] // override doc\npub struct RetryArgs {\n    /// Number of attempts for retrying verification.\n    #[arg(\n        long,\n        value_parser = RangedU64ValueParser::<u32>::new().range(1..),\n        default_value = \"5\",\n    )]\n    pub retries: u32,\n\n    /// Optional delay to apply in between verification attempts, in seconds.\n    #[arg(\n        long,\n        value_parser = RangedU64ValueParser::<u32>::new().range(0..=180),\n        default_value = \"5\",\n    )]\n    pub delay: u32,\n}\n\nimpl Default for RetryArgs {\n    fn default() -> Self {\n        RETRY_VERIFY_ON_CREATE\n    }\n}\n\nimpl RetryArgs {\n    /// Converts the arguments into a `Retry` instance.\n    pub fn into_retry(self) -> Retry {\n        Retry::new(self.retries, Duration::from_secs(self.delay as u64))\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_cli() {\n        let args = RetryArgs::parse_from([\"foundry-cli\", \"--retries\", \"10\"]);\n        assert_eq!(args.retries, 10);\n        assert_eq!(args.delay, 5);\n\n        let args = RetryArgs::parse_from([\"foundry-cli\", \"--delay\", \"10\"]);\n        assert_eq!(args.retries, 5);\n        assert_eq!(args.delay, 10);\n\n        let args = RetryArgs::parse_from([\"foundry-cli\", \"--retries\", \"10\", \"--delay\", \"10\"]);\n        assert_eq!(args.retries, 10);\n        assert_eq!(args.delay, 10);\n    }\n}\n"
  },
  {
    "path": "crates/verify/src/sourcify.rs",
    "content": "use crate::{\n    provider::{VerificationContext, VerificationProvider},\n    retry::RETRY_CHECK_ON_VERIFY,\n    utils::ensure_solc_build_metadata,\n    verify::{ContractLanguage, VerifyArgs, VerifyCheckArgs},\n};\nuse alloy_primitives::Address;\nuse async_trait::async_trait;\nuse eyre::{Context, Result, eyre};\nuse foundry_common::retry::RetryError;\nuse futures::FutureExt;\nuse reqwest::StatusCode;\nuse serde::{Deserialize, Serialize};\nuse url::Url;\n\npub static SOURCIFY_URL: &str = \"https://sourcify.dev/server/\";\n\n/// The type that can verify a contract on `sourcify`\n#[derive(Clone, Debug, Default)]\n#[non_exhaustive]\npub struct SourcifyVerificationProvider;\n\n#[async_trait]\nimpl VerificationProvider for SourcifyVerificationProvider {\n    async fn preflight_verify_check(\n        &mut self,\n        args: VerifyArgs,\n        context: VerificationContext,\n    ) -> Result<()> {\n        let _ = self.prepare_verify_request(&args, &context).await?;\n        Ok(())\n    }\n\n    async fn verify(&mut self, args: VerifyArgs, context: VerificationContext) -> Result<()> {\n        let body = self.prepare_verify_request(&args, &context).await?;\n        let chain_id = args.etherscan.chain.unwrap_or_default().id();\n\n        if !args.skip_is_verified_check && self.is_contract_verified(&args).await? {\n            sh_println!(\n                \"\\nContract [{}] {:?} is already verified. Skipping verification.\",\n                context.target_name,\n                args.address.to_string()\n            )?;\n\n            return Ok(());\n        }\n\n        trace!(\"submitting verification request {:?}\", body);\n\n        let client = reqwest::Client::new();\n        let url =\n            Self::get_verify_url(args.verifier.verifier_url.as_deref(), chain_id, args.address);\n\n        let resp = args\n            .retry\n            .into_retry()\n            .run_async(|| {\n                async {\n                    sh_println!(\n                        \"\\nSubmitting verification for [{}] {:?}.\",\n                        context.target_name,\n                        args.address.to_string()\n                    )?;\n                    let response = client\n                        .post(&url)\n                        .header(\"Content-Type\", \"application/json\")\n                        .body(serde_json::to_string(&body)?)\n                        .send()\n                        .await?;\n\n                    let status = response.status();\n                    match status {\n                        StatusCode::CONFLICT => {\n                            sh_println!(\"Contract source code already fully verified\")?;\n                            Ok(None)\n                        }\n                        StatusCode::ACCEPTED => {\n                            let text = response.text().await?;\n                            let verify_response: SourcifyVerificationResponse =\n                                serde_json::from_str(&text)\n                                    .wrap_err(\"Failed to parse Sourcify verification response\")?;\n                            Ok(Some(verify_response))\n                        }\n                        _ => {\n                            let error: serde_json::Value = response.json().await?;\n                            eyre::bail!(\n                                \"Sourcify verification request for address ({}) \\\n                            failed with status code {status}\\n\\\n                            Details: {error:#}\",\n                                args.address,\n                            );\n                        }\n                    }\n                }\n                .boxed()\n            })\n            .await?;\n\n        if let Some(resp) = resp {\n            let job_url = Self::get_job_status_url(\n                args.verifier.verifier_url.as_deref(),\n                resp.verification_id.clone(),\n            );\n            sh_println!(\n                \"Submitted contract for verification:\\n\\tVerification Job ID: `{}`\\n\\tURL: {}\",\n                resp.verification_id,\n                job_url\n            )?;\n\n            if args.watch {\n                let check_args = VerifyCheckArgs {\n                    id: resp.verification_id,\n                    etherscan: args.etherscan,\n                    retry: RETRY_CHECK_ON_VERIFY,\n                    verifier: args.verifier,\n                };\n                return self.check(check_args).await;\n            }\n        }\n\n        Ok(())\n    }\n\n    async fn check(&self, args: VerifyCheckArgs) -> Result<()> {\n        let url = Self::get_job_status_url(args.verifier.verifier_url.as_deref(), args.id.clone());\n\n        args.retry\n            .into_retry()\n            .run_async_until_break(|| async {\n                let response = reqwest::get(&url)\n                    .await\n                    .wrap_err(\"Failed to request verification status\")\n                    .map_err(RetryError::Retry)?;\n\n                if response.status() == StatusCode::NOT_FOUND {\n                    return Err(RetryError::Break(eyre!(\n                        \"No verification job found for ID {}\",\n                        args.id\n                    )));\n                }\n\n                if !response.status().is_success() {\n                    return Err(RetryError::Retry(eyre!(\n                        \"Failed to request verification status with status code {}\",\n                        response.status()\n                    )));\n                }\n\n                let job_response: SourcifyJobResponse = response\n                    .json()\n                    .await\n                    .wrap_err(\"Failed to parse job response\")\n                    .map_err(RetryError::Retry)?;\n\n                if !job_response.is_job_completed {\n                    return Err(RetryError::Retry(eyre!(\"Verification is still pending...\")));\n                }\n\n                if let Some(error) = job_response.error {\n                    if error.custom_code == \"already_verified\" {\n                        let _ = sh_println!(\"Contract source code already verified\");\n                        return Ok(());\n                    }\n\n                    return Err(RetryError::Break(eyre!(\n                        \"Verification job failed:\\nError Code: `{}`\\nMessage: `{}`\",\n                        error.custom_code,\n                        error.message\n                    )));\n                }\n\n                if let Some(contract_status) = job_response.contract.match_status {\n                    let _ = sh_println!(\n                        \"Contract successfully verified:\\nStatus: `{}`\",\n                        contract_status,\n                    );\n                }\n                Ok(())\n            })\n            .await\n            .wrap_err(\"Checking verification result failed\")\n    }\n}\n\nimpl SourcifyVerificationProvider {\n    fn get_base_url(verifier_url: Option<&str>) -> Url {\n        // note(onbjerg): a little ugly but makes this infallible as we guarantee `SOURCIFY_URL` to\n        // be well formatted\n        Url::parse(verifier_url.unwrap_or(SOURCIFY_URL))\n            .unwrap_or_else(|_| Url::parse(SOURCIFY_URL).unwrap())\n    }\n\n    fn get_verify_url(\n        verifier_url: Option<&str>,\n        chain_id: u64,\n        contract_address: Address,\n    ) -> String {\n        let base_url = Self::get_base_url(verifier_url);\n        format!(\"{base_url}v2/verify/{chain_id}/{contract_address}\")\n    }\n\n    fn get_job_status_url(verifier_url: Option<&str>, job_id: String) -> String {\n        let base_url = Self::get_base_url(verifier_url);\n        format!(\"{base_url}v2/verify/{job_id}\")\n    }\n\n    fn get_lookup_url(\n        verifier_url: Option<&str>,\n        chain_id: u64,\n        contract_address: Address,\n    ) -> String {\n        let base_url = Self::get_base_url(verifier_url);\n        format!(\"{base_url}v2/contract/{chain_id}/{contract_address}\")\n    }\n\n    /// Configures the API request to the sourcify API using the given [`VerifyArgs`].\n    async fn prepare_verify_request(\n        &self,\n        args: &VerifyArgs,\n        context: &VerificationContext,\n    ) -> Result<SourcifyVerifyRequest> {\n        let lang = args.detect_language(context);\n        let contract_identifier = format!(\n            \"{}:{}\",\n            context\n                .target_path\n                .strip_prefix(context.project.root())\n                .unwrap_or(context.target_path.as_path())\n                .display(),\n            context.target_name\n        );\n        let creation_transaction_hash = args.creation_transaction_hash.map(|h| h.to_string());\n\n        match lang {\n            ContractLanguage::Solidity => {\n                let input = context.get_solc_standard_json_input()?;\n\n                let std_json_input = serde_json::to_value(&input)\n                    .wrap_err(\"Failed to serialize standard json input\")?;\n                let compiler_version =\n                    ensure_solc_build_metadata(context.compiler_version.clone()).await?.to_string();\n\n                Ok(SourcifyVerifyRequest {\n                    std_json_input,\n                    compiler_version,\n                    contract_identifier,\n                    creation_transaction_hash,\n                })\n            }\n            ContractLanguage::Vyper => {\n                let input = context.get_vyper_standard_json_input()?;\n                let std_json_input = serde_json::to_value(&input)\n                    .wrap_err(\"Failed to serialize vyper json input\")?;\n\n                let compiler_version = context.compiler_version.to_string();\n\n                Ok(SourcifyVerifyRequest {\n                    std_json_input,\n                    compiler_version,\n                    contract_identifier,\n                    creation_transaction_hash,\n                })\n            }\n        }\n    }\n\n    async fn is_contract_verified(&self, args: &VerifyArgs) -> Result<bool> {\n        let chain_id = args.etherscan.chain.unwrap_or_default().id();\n        let url =\n            Self::get_lookup_url(args.verifier.verifier_url.as_deref(), chain_id, args.address);\n\n        match reqwest::get(&url).await {\n            Ok(response) => {\n                if response.status().is_success() {\n                    let contract_response: SourcifyContractResponse =\n                        response.json().await.wrap_err(\"Failed to parse contract response\")?;\n\n                    let creation_exact = contract_response\n                        .creation_match\n                        .as_ref()\n                        .map(|s| s == \"exact_match\")\n                        .unwrap_or(false);\n\n                    let runtime_exact = contract_response\n                        .runtime_match\n                        .as_ref()\n                        .map(|s| s == \"exact_match\")\n                        .unwrap_or(false);\n\n                    Ok(creation_exact && runtime_exact)\n                } else {\n                    Ok(false)\n                }\n            }\n            Err(error) => Err(error).wrap_err_with(|| {\n                format!(\"Failed to query verification status for {}\", args.address)\n            }),\n        }\n    }\n}\n\n#[derive(Debug, Serialize)]\n#[serde(rename_all = \"camelCase\")]\npub struct SourcifyVerifyRequest {\n    std_json_input: serde_json::Value,\n    compiler_version: String,\n    contract_identifier: String,\n    #[serde(skip_serializing_if = \"Option::is_none\")]\n    creation_transaction_hash: Option<String>,\n}\n\n#[derive(Debug, Deserialize)]\n#[serde(rename_all = \"camelCase\")]\npub struct SourcifyVerificationResponse {\n    verification_id: String,\n}\n\n#[derive(Debug, Deserialize)]\n#[serde(rename_all = \"camelCase\")]\npub struct SourcifyJobResponse {\n    is_job_completed: bool,\n    contract: SourcifyContractResponse,\n    error: Option<SourcifyErrorResponse>,\n}\n\n#[derive(Debug, Deserialize)]\n#[serde(rename_all = \"camelCase\")]\npub struct SourcifyContractResponse {\n    #[serde(rename = \"match\")]\n    match_status: Option<String>,\n    creation_match: Option<String>,\n    runtime_match: Option<String>,\n}\n\n#[derive(Debug, Deserialize)]\n#[serde(rename_all = \"camelCase\")]\npub struct SourcifyErrorResponse {\n    custom_code: String,\n    message: String,\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use clap::Parser;\n    use foundry_test_utils::forgetest_async;\n\n    forgetest_async!(creates_correct_verify_request_body, |prj, _cmd| {\n        prj.add_source(\"Counter\", \"contract Counter {}\");\n\n        let args = VerifyArgs::parse_from([\n            \"foundry-cli\",\n            \"0xd8509bee9c9bf012282ad33aba0d87241baf5064\",\n            \"src/Counter.sol:Counter\",\n            \"--compiler-version\",\n            \"0.8.19\",\n            \"--root\",\n            &prj.root().to_string_lossy(),\n        ]);\n\n        let context = args.resolve_context().await.unwrap();\n        let provider = SourcifyVerificationProvider::default();\n        let request = provider.prepare_verify_request(&args, &context).await.unwrap();\n\n        assert_eq!(request.compiler_version, \"0.8.19+commit.7dd6d404\");\n        assert_eq!(request.contract_identifier, \"src/Counter.sol:Counter\");\n        assert!(request.creation_transaction_hash.is_none());\n\n        assert!(request.std_json_input.is_object());\n        let json_obj = request.std_json_input.as_object().unwrap();\n        assert!(json_obj.contains_key(\"sources\"));\n        assert!(json_obj.contains_key(\"settings\"));\n\n        let sources = json_obj.get(\"sources\").unwrap().as_object().unwrap();\n        assert!(sources.contains_key(\"src/Counter.sol\"));\n        let counter_source = sources.get(\"src/Counter.sol\").unwrap().as_object().unwrap();\n        let content = counter_source.get(\"content\").unwrap().as_str().unwrap();\n        assert!(content.contains(\"contract Counter {}\"));\n    });\n}\n"
  },
  {
    "path": "crates/verify/src/types.rs",
    "content": "use eyre::Result;\nuse serde::{Deserialize, Serialize};\nuse std::{fmt, str::FromStr};\n\n/// Enum to represent the type of verification: `full` or `partial`.\n/// Ref: <https://docs.sourcify.dev/docs/full-vs-partial-match/>\n#[derive(Debug, Clone, clap::ValueEnum, Default, PartialEq, Eq, Serialize, Deserialize, Copy)]\npub enum VerificationType {\n    #[default]\n    #[serde(rename = \"full\")]\n    Full,\n    #[serde(rename = \"partial\")]\n    Partial,\n}\n\nimpl FromStr for VerificationType {\n    type Err = eyre::Error;\n\n    fn from_str(s: &str) -> Result<Self> {\n        match s {\n            \"full\" => Ok(Self::Full),\n            \"partial\" => Ok(Self::Partial),\n            _ => eyre::bail!(\"Invalid verification type\"),\n        }\n    }\n}\n\nimpl fmt::Display for VerificationType {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        match self {\n            Self::Full => write!(f, \"full\"),\n            Self::Partial => write!(f, \"partial\"),\n        }\n    }\n}\n"
  },
  {
    "path": "crates/verify/src/utils.rs",
    "content": "use crate::{bytecode::VerifyBytecodeArgs, types::VerificationType};\nuse alloy_dyn_abi::DynSolValue;\nuse alloy_evm::EvmEnv;\nuse alloy_primitives::{Address, Bytes, TxKind};\nuse alloy_provider::{\n    Provider,\n    network::{AnyNetwork, AnyRpcBlock},\n};\nuse alloy_rpc_types::BlockId;\nuse clap::ValueEnum;\nuse eyre::{OptionExt, Result};\nuse foundry_block_explorers::{\n    contract::{ContractCreationData, ContractMetadata, Metadata},\n    errors::EtherscanError,\n    utils::lookup_compiler_version,\n};\nuse foundry_common::{abi::encode_args, compile::ProjectCompiler, ignore_metadata_hash, shell};\nuse foundry_compilers::artifacts::{BytecodeHash, CompactContractBytecode, EvmVersion};\nuse foundry_config::Config;\nuse foundry_evm::{\n    constants::DEFAULT_CREATE2_DEPLOYER,\n    core::decode::RevertDecoder,\n    executors::TracingExecutor,\n    opts::EvmOpts,\n    traces::TraceMode,\n    utils::{apply_chain_and_block_specific_env_changes, block_env_from_header},\n};\nuse foundry_evm_networks::NetworkConfigs;\nuse reqwest::Url;\nuse revm::{bytecode::Bytecode, context::TxEnv, database::Database, primitives::hardfork::SpecId};\nuse semver::{BuildMetadata, Version};\nuse serde::{Deserialize, Serialize};\nuse yansi::Paint;\n\n/// Enum to represent the type of bytecode being verified\n#[derive(Debug, Serialize, Deserialize, Clone, Copy, ValueEnum)]\npub enum BytecodeType {\n    #[serde(rename = \"creation\")]\n    Creation,\n    #[serde(rename = \"runtime\")]\n    Runtime,\n}\n\nimpl BytecodeType {\n    /// Check if the bytecode type is creation\n    pub fn is_creation(&self) -> bool {\n        matches!(self, Self::Creation)\n    }\n\n    /// Check if the bytecode type is runtime\n    pub fn is_runtime(&self) -> bool {\n        matches!(self, Self::Runtime)\n    }\n}\n\n#[derive(Debug, Serialize, Deserialize)]\npub struct JsonResult {\n    pub bytecode_type: BytecodeType,\n    pub match_type: Option<VerificationType>,\n    #[serde(skip_serializing_if = \"Option::is_none\")]\n    pub message: Option<String>,\n}\n\npub fn match_bytecodes(\n    local_bytecode: &[u8],\n    bytecode: &[u8],\n    constructor_args: &[u8],\n    is_runtime: bool,\n    bytecode_hash: BytecodeHash,\n) -> Option<VerificationType> {\n    // 1. Try full match\n    if local_bytecode == bytecode {\n        // If the bytecode_hash = 'none' in Config. Then it's always a partial match according to\n        // sourcify definitions. Ref: https://docs.sourcify.dev/docs/full-vs-partial-match/.\n        if bytecode_hash == BytecodeHash::None {\n            return Some(VerificationType::Partial);\n        }\n\n        Some(VerificationType::Full)\n    } else {\n        is_partial_match(local_bytecode, bytecode, constructor_args, is_runtime)\n            .then_some(VerificationType::Partial)\n    }\n}\n\npub fn build_project(\n    args: &VerifyBytecodeArgs,\n    config: &Config,\n) -> Result<CompactContractBytecode> {\n    let project = config.project()?;\n    let compiler = ProjectCompiler::new();\n\n    let mut output = compiler.compile(&project)?;\n\n    let artifact = output\n        .remove_contract(&args.contract)\n        .ok_or_eyre(\"Build Error: Contract artifact not found locally\")?;\n\n    Ok(artifact.into_contract_bytecode())\n}\n\npub fn print_result(\n    res: Option<VerificationType>,\n    bytecode_type: BytecodeType,\n    json_results: &mut Vec<JsonResult>,\n    etherscan_config: &Metadata,\n    config: &Config,\n) {\n    if let Some(res) = res {\n        if !shell::is_json() {\n            let _ = sh_println!(\n                \"{} with status {}\",\n                format!(\"{bytecode_type:?} code matched\").green().bold(),\n                res.green().bold()\n            );\n        } else {\n            let json_res = JsonResult { bytecode_type, match_type: Some(res), message: None };\n            json_results.push(json_res);\n        }\n    } else if !shell::is_json() {\n        let _ = sh_err!(\n            \"{bytecode_type:?} code did not match - this may be due to varying compiler settings\"\n        );\n        let mismatches = find_mismatch_in_settings(etherscan_config, config);\n        for mismatch in mismatches {\n            let _ = sh_eprintln!(\"{}\", mismatch.red().bold());\n        }\n    } else {\n        let json_res = JsonResult {\n            bytecode_type,\n            match_type: res,\n            message: Some(format!(\n                \"{bytecode_type:?} code did not match - this may be due to varying compiler settings\"\n            )),\n        };\n        json_results.push(json_res);\n    }\n}\n\nfn is_partial_match(\n    mut local_bytecode: &[u8],\n    mut bytecode: &[u8],\n    constructor_args: &[u8],\n    is_runtime: bool,\n) -> bool {\n    // 1. Check length of constructor args\n    if constructor_args.is_empty() || is_runtime {\n        // Assume metadata is at the end of the bytecode\n        return try_extract_and_compare_bytecode(local_bytecode, bytecode);\n    }\n\n    // If not runtime, extract constructor args from the end of the bytecode\n    bytecode = &bytecode[..bytecode.len() - constructor_args.len()];\n    local_bytecode = &local_bytecode[..local_bytecode.len() - constructor_args.len()];\n\n    try_extract_and_compare_bytecode(local_bytecode, bytecode)\n}\n\nfn try_extract_and_compare_bytecode(mut local_bytecode: &[u8], mut bytecode: &[u8]) -> bool {\n    local_bytecode = ignore_metadata_hash(local_bytecode);\n    bytecode = ignore_metadata_hash(bytecode);\n\n    // Now compare the local code and bytecode\n    local_bytecode == bytecode\n}\n\nfn find_mismatch_in_settings(\n    etherscan_settings: &Metadata,\n    local_settings: &Config,\n) -> Vec<String> {\n    let mut mismatches: Vec<String> = vec![];\n    if etherscan_settings.evm_version != local_settings.evm_version.to_string().to_lowercase() {\n        let str = format!(\n            \"EVM version mismatch: local={}, onchain={}\",\n            local_settings.evm_version, etherscan_settings.evm_version\n        );\n        mismatches.push(str);\n    }\n    let local_optimizer: u64 = if local_settings.optimizer == Some(true) { 1 } else { 0 };\n    if etherscan_settings.optimization_used != local_optimizer {\n        let str = format!(\n            \"Optimizer mismatch: local={}, onchain={}\",\n            local_settings.optimizer.unwrap_or(false),\n            etherscan_settings.optimization_used\n        );\n        mismatches.push(str);\n    }\n    if local_settings.optimizer_runs.is_some_and(|runs| etherscan_settings.runs != runs as u64)\n        || (local_settings.optimizer_runs.is_none() && etherscan_settings.runs > 0)\n    {\n        let str = format!(\n            \"Optimizer runs mismatch: local={}, onchain={}\",\n            local_settings.optimizer_runs.map_or(\"unknown\".to_string(), |runs| runs.to_string()),\n            etherscan_settings.runs\n        );\n        mismatches.push(str);\n    }\n\n    mismatches\n}\n\npub fn maybe_predeploy_contract(\n    creation_data: Result<ContractCreationData, EtherscanError>,\n) -> Result<(Option<ContractCreationData>, bool), eyre::ErrReport> {\n    let mut maybe_predeploy = false;\n    match creation_data {\n        Ok(creation_data) => Ok((Some(creation_data), maybe_predeploy)),\n        // Ref: https://explorer.mode.network/api?module=contract&action=getcontractcreation&contractaddresses=0xC0d3c0d3c0D3c0d3C0D3c0D3C0d3C0D3C0D30010\n        Err(EtherscanError::EmptyResult { status, message })\n            if status == \"1\" && message == \"OK\" =>\n        {\n            maybe_predeploy = true;\n            Ok((None, maybe_predeploy))\n        }\n        // Ref: https://api.basescan.org/api?module=contract&action=getcontractcreation&contractaddresses=0xC0d3c0d3c0D3c0d3C0D3c0D3C0d3C0D3C0D30010&apiKey=YourAPIKey\n        Err(EtherscanError::Serde { error: _, content }) if content.contains(\"GENESIS\") => {\n            maybe_predeploy = true;\n            Ok((None, maybe_predeploy))\n        }\n        Err(e) => eyre::bail!(\"Error fetching creation data from verifier-url: {:?}\", e),\n    }\n}\n\npub fn check_and_encode_args(\n    artifact: &CompactContractBytecode,\n    args: Vec<String>,\n) -> Result<Vec<u8>, eyre::ErrReport> {\n    if let Some(constructor) = artifact.abi.as_ref().and_then(|abi| abi.constructor()) {\n        if constructor.inputs.len() != args.len() {\n            eyre::bail!(\n                \"Mismatch of constructor arguments length. Expected {}, got {}\",\n                constructor.inputs.len(),\n                args.len()\n            );\n        }\n        encode_args(&constructor.inputs, &args).map(|args| DynSolValue::Tuple(args).abi_encode())\n    } else {\n        Ok(Vec::new())\n    }\n}\n\npub fn check_explorer_args(source_code: ContractMetadata) -> Result<Bytes, eyre::ErrReport> {\n    if let Some(args) = source_code.items.first() {\n        Ok(args.constructor_arguments.clone())\n    } else {\n        eyre::bail!(\"No constructor arguments found from block explorer\");\n    }\n}\n\npub fn check_args_len(\n    artifact: &CompactContractBytecode,\n    args: &Bytes,\n) -> Result<(), eyre::ErrReport> {\n    if let Some(constructor) = artifact.abi.as_ref().and_then(|abi| abi.constructor())\n        && !constructor.inputs.is_empty()\n        && args.is_empty()\n    {\n        eyre::bail!(\n            \"Contract expects {} constructor argument(s), but none were provided\",\n            constructor.inputs.len()\n        );\n    }\n    Ok(())\n}\n\npub async fn get_tracing_executor(\n    fork_config: &mut Config,\n    fork_blk_num: u64,\n    evm_version: EvmVersion,\n    evm_opts: EvmOpts,\n) -> Result<(EvmEnv, TxEnv, TracingExecutor)> {\n    fork_config.fork_block_number = Some(fork_blk_num);\n    fork_config.evm_version = evm_version;\n\n    let create2_deployer = evm_opts.create2_deployer;\n    let (evm_env, tx_env, fork, _chain, networks) =\n        TracingExecutor::get_fork_material(fork_config, evm_opts).await?;\n\n    let executor = TracingExecutor::new(\n        (evm_env.clone(), tx_env.clone()),\n        fork,\n        Some(fork_config.evm_version),\n        TraceMode::Call,\n        networks,\n        create2_deployer,\n        None,\n    )?;\n\n    Ok((evm_env, tx_env, executor))\n}\n\npub fn configure_env_block(evm_env: &mut EvmEnv, block: &AnyRpcBlock, config: NetworkConfigs) {\n    let number = evm_env.block_env.number;\n    evm_env.block_env = block_env_from_header(&block.header);\n    evm_env.block_env.number = number;\n    apply_chain_and_block_specific_env_changes::<AnyNetwork>(evm_env, block, config);\n}\n\npub fn deploy_contract(\n    executor: &mut TracingExecutor,\n    evm_env: &EvmEnv,\n    tx_env: &TxEnv,\n    spec_id: SpecId,\n    to: Option<TxKind>,\n) -> Result<Address, eyre::ErrReport> {\n    let mut evm_env = evm_env.clone();\n    evm_env.cfg_env.set_spec(spec_id);\n\n    if to.is_some_and(|to| to.is_call()) {\n        let TxKind::Call(to) = to.unwrap() else { unreachable!() };\n        if to != DEFAULT_CREATE2_DEPLOYER {\n            eyre::bail!(\n                \"Transaction `to` address is not the default create2 deployer i.e the tx is not a contract creation tx.\"\n            );\n        }\n        let result = executor.transact_with_env(evm_env, tx_env.clone())?;\n\n        trace!(transact_result = ?result.exit_reason);\n\n        if result.reverted {\n            let decoded_reason = if result.result.is_empty() {\n                String::new()\n            } else {\n                format!(\": {}\", RevertDecoder::default().decode(&result.result, result.exit_reason))\n            };\n            eyre::bail!(\n                \"Failed to deploy contract via CREATE2 on fork at block{decoded_reason}.\\n\\\n                This typically happens when your local bytecode differs from what was actually deployed.\\n\\\n                Common causes:\\n\\\n                - Your contract source is not at the same commit used during deployment\\n\\\n                - Cached build artifacts are stale (try `forge clean && forge build`)\\n\\\n                - Compiler settings (optimizer, evm_version, via_ir) don't match the deployment\"\n            );\n        }\n\n        if result.result.len() != 20 {\n            eyre::bail!(\n                \"Failed to deploy contract via CREATE2 on fork at block: deployer returned {} bytes instead of 20.\\n\\\n                This may indicate a bytecode mismatch - ensure your source code matches the deployed contract.\",\n                result.result.len()\n            );\n        }\n\n        Ok(Address::from_slice(&result.result))\n    } else {\n        let deploy_result = executor.deploy_with_env(evm_env, tx_env.clone(), None)?;\n        trace!(deploy_result = ?deploy_result.raw.exit_reason);\n        Ok(deploy_result.address)\n    }\n}\n\npub async fn get_runtime_codes(\n    executor: &mut TracingExecutor,\n    provider: &impl Provider<AnyNetwork>,\n    address: Address,\n    fork_address: Address,\n    block: Option<u64>,\n) -> Result<(Bytecode, Bytes)> {\n    let fork_runtime_code = executor\n        .backend_mut()\n        .basic(fork_address)?\n        .ok_or_else(|| {\n            eyre::eyre!(\n                \"Failed to get runtime code for contract deployed on fork at address {}\",\n                fork_address\n            )\n        })?\n        .code\n        .ok_or_else(|| {\n            eyre::eyre!(\n                \"Bytecode does not exist for contract deployed on fork at address {}\",\n                fork_address\n            )\n        })?;\n\n    let block_id = block.map_or_else(BlockId::latest, BlockId::number);\n    let onchain_runtime_code = provider.get_code_at(address).block_id(block_id).await?;\n\n    Ok((fork_runtime_code, onchain_runtime_code))\n}\n\n/// Returns `true` if the URL only consists of host.\n///\n/// This is used to check user input url for missing /api path\npub fn is_host_only(url: &Url) -> bool {\n    matches!(url.path(), \"/\" | \"\")\n}\n\n/// Given any solc [Version] return a [Version] with build metadata\n///\n/// # Example\n///\n/// ```ignore\n/// use semver::{BuildMetadata, Version};\n/// let version = Version::new(1, 2, 3);\n/// let version = ensure_solc_build_metadata(version).await?;\n/// assert_ne!(version.build, BuildMetadata::EMPTY);\n/// ```\npub async fn ensure_solc_build_metadata(version: Version) -> Result<Version> {\n    if version.build != BuildMetadata::EMPTY {\n        Ok(version)\n    } else {\n        Ok(lookup_compiler_version(&version).await?)\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_host_only() {\n        assert!(!is_host_only(&Url::parse(\"https://blockscout.net/api\").unwrap()));\n        assert!(is_host_only(&Url::parse(\"https://blockscout.net/\").unwrap()));\n        assert!(is_host_only(&Url::parse(\"https://blockscout.net\").unwrap()));\n    }\n}\n"
  },
  {
    "path": "crates/verify/src/verify.rs",
    "content": "//! The `forge verify-bytecode` command.\n\nuse crate::{\n    RetryArgs,\n    etherscan::EtherscanVerificationProvider,\n    provider::{VerificationContext, VerificationProvider, VerificationProviderType},\n    utils::is_host_only,\n};\nuse alloy_primitives::{Address, TxHash, map::HashSet};\nuse alloy_provider::Provider;\nuse clap::{Parser, ValueEnum, ValueHint};\nuse eyre::Result;\nuse foundry_cli::{\n    opts::{EtherscanOpts, RpcOpts},\n    utils::{self, LoadConfig},\n};\nuse foundry_common::{ContractsByArtifact, compile::ProjectCompiler};\nuse foundry_compilers::{artifacts::EvmVersion, compilers::solc::Solc, info::ContractInfo};\nuse foundry_config::{\n    Chain, Config, SolcReq, figment, impl_figment_convert, impl_figment_convert_cast,\n};\nuse itertools::Itertools;\nuse reqwest::Url;\nuse semver::BuildMetadata;\nuse std::path::PathBuf;\n\n/// The programming language used for smart contract development.\n///\n/// This enum represents the supported contract languages for verification.\n#[derive(Copy, Clone, Debug, Eq, PartialEq, ValueEnum)]\npub enum ContractLanguage {\n    /// Solidity programming language\n    Solidity,\n    /// Vyper programming language  \n    Vyper,\n}\n\n/// Verification provider arguments\n#[derive(Clone, Debug, Parser)]\npub struct VerifierArgs {\n    /// The contract verification provider to use.\n    #[arg(long, help_heading = \"Verifier options\", default_value = \"sourcify\", value_enum)]\n    pub verifier: VerificationProviderType,\n\n    /// The verifier API KEY, if using a custom provider.\n    #[arg(long, help_heading = \"Verifier options\", env = \"VERIFIER_API_KEY\")]\n    pub verifier_api_key: Option<String>,\n\n    /// The verifier URL, if using a custom provider.\n    #[arg(long, help_heading = \"Verifier options\", env = \"VERIFIER_URL\")]\n    pub verifier_url: Option<String>,\n}\n\nimpl Default for VerifierArgs {\n    fn default() -> Self {\n        Self {\n            verifier: VerificationProviderType::Sourcify,\n            verifier_api_key: None,\n            verifier_url: None,\n        }\n    }\n}\n\n/// CLI arguments for `forge verify-contract`.\n#[derive(Clone, Debug, Parser)]\npub struct VerifyArgs {\n    /// The address of the contract to verify.\n    pub address: Address,\n\n    /// The contract identifier in the form `<path>:<contractname>`.\n    pub contract: Option<ContractInfo>,\n\n    /// The ABI-encoded constructor arguments. Only for Etherscan.\n    #[arg(\n        long,\n        conflicts_with = \"constructor_args_path\",\n        value_name = \"ARGS\",\n        visible_alias = \"encoded-constructor-args\"\n    )]\n    pub constructor_args: Option<String>,\n\n    /// The path to a file containing the constructor arguments.\n    #[arg(long, value_hint = ValueHint::FilePath, value_name = \"PATH\")]\n    pub constructor_args_path: Option<PathBuf>,\n\n    /// Try to extract constructor arguments from on-chain creation code.\n    #[arg(long)]\n    pub guess_constructor_args: bool,\n\n    /// The hash of the transaction which created the contract. Optional for Sourcify.\n    #[arg(long)]\n    pub creation_transaction_hash: Option<TxHash>,\n\n    /// The `solc` version to use to build the smart contract.\n    #[arg(long, value_name = \"VERSION\")]\n    pub compiler_version: Option<String>,\n\n    /// The compilation profile to use to build the smart contract.\n    #[arg(long, value_name = \"PROFILE_NAME\")]\n    pub compilation_profile: Option<String>,\n\n    /// The number of optimization runs used to build the smart contract.\n    #[arg(long, visible_alias = \"optimizer-runs\", value_name = \"NUM\")]\n    pub num_of_optimizations: Option<usize>,\n\n    /// Flatten the source code before verifying.\n    #[arg(long)]\n    pub flatten: bool,\n\n    /// Do not compile the flattened smart contract before verifying (if --flatten is passed).\n    #[arg(short, long)]\n    pub force: bool,\n\n    /// Do not check if the contract is already verified before verifying.\n    #[arg(long)]\n    pub skip_is_verified_check: bool,\n\n    /// Wait for verification result after submission.\n    #[arg(long)]\n    pub watch: bool,\n\n    /// Set pre-linked libraries.\n    #[arg(long, help_heading = \"Linker options\", env = \"DAPP_LIBRARIES\")]\n    pub libraries: Vec<String>,\n\n    /// The project's root path.\n    ///\n    /// By default root of the Git repository, if in one,\n    /// or the current working directory.\n    #[arg(long, value_hint = ValueHint::DirPath, value_name = \"PATH\")]\n    pub root: Option<PathBuf>,\n\n    /// Prints the standard json compiler input.\n    ///\n    /// The standard json compiler input can be used to manually submit contract verification in\n    /// the browser.\n    #[arg(long, conflicts_with = \"flatten\")]\n    pub show_standard_json_input: bool,\n\n    /// Use the Yul intermediate representation compilation pipeline.\n    #[arg(long)]\n    pub via_ir: bool,\n\n    /// The EVM version to use.\n    ///\n    /// Overrides the version specified in the config.\n    #[arg(long)]\n    pub evm_version: Option<EvmVersion>,\n\n    /// Do not auto-detect the `solc` version.\n    #[arg(long, help_heading = \"Compiler options\")]\n    pub no_auto_detect: bool,\n\n    /// Specify the solc version, or a path to a local solc, to build with.\n    ///\n    /// Valid values are in the format `x.y.z`, `solc:x.y.z` or `path/to/solc`.\n    #[arg(long = \"use\", help_heading = \"Compiler options\", value_name = \"SOLC_VERSION\")]\n    pub use_solc: Option<String>,\n\n    #[command(flatten)]\n    pub etherscan: EtherscanOpts,\n\n    #[command(flatten)]\n    pub rpc: RpcOpts,\n\n    #[command(flatten)]\n    pub retry: RetryArgs,\n\n    #[command(flatten)]\n    pub verifier: VerifierArgs,\n\n    /// The contract language (`solidity` or `vyper`).\n    ///\n    /// Defaults to `solidity` if none provided.\n    #[arg(long, value_enum)]\n    pub language: Option<ContractLanguage>,\n}\n\nimpl_figment_convert!(VerifyArgs);\n\nimpl figment::Provider for VerifyArgs {\n    fn metadata(&self) -> figment::Metadata {\n        figment::Metadata::named(\"Verify Provider\")\n    }\n\n    fn data(\n        &self,\n    ) -> Result<figment::value::Map<figment::Profile, figment::value::Dict>, figment::Error> {\n        let mut dict = self.etherscan.dict();\n        dict.extend(self.rpc.dict());\n\n        if let Some(root) = self.root.as_ref() {\n            dict.insert(\"root\".to_string(), figment::value::Value::serialize(root)?);\n        }\n        if let Some(optimizer_runs) = self.num_of_optimizations {\n            dict.insert(\"optimizer\".to_string(), figment::value::Value::serialize(true)?);\n            dict.insert(\n                \"optimizer_runs\".to_string(),\n                figment::value::Value::serialize(optimizer_runs)?,\n            );\n        }\n        if let Some(evm_version) = self.evm_version {\n            dict.insert(\"evm_version\".to_string(), figment::value::Value::serialize(evm_version)?);\n        }\n        if self.via_ir {\n            dict.insert(\"via_ir\".to_string(), figment::value::Value::serialize(self.via_ir)?);\n        }\n\n        if self.no_auto_detect {\n            dict.insert(\"auto_detect_solc\".to_string(), figment::value::Value::serialize(false)?);\n        }\n\n        if let Some(ref solc) = self.use_solc {\n            let solc = solc.trim_start_matches(\"solc:\");\n            dict.insert(\"solc\".to_string(), figment::value::Value::serialize(solc)?);\n        }\n\n        if let Some(api_key) = &self.verifier.verifier_api_key {\n            dict.insert(\"etherscan_api_key\".into(), api_key.as_str().into());\n        }\n\n        Ok(figment::value::Map::from([(Config::selected_profile(), dict)]))\n    }\n}\n\nimpl VerifyArgs {\n    /// Run the verify command to submit the contract's source code for verification on etherscan\n    pub async fn run(mut self) -> Result<()> {\n        let config = self.load_config()?;\n\n        if self.guess_constructor_args && config.get_rpc_url().is_none() {\n            eyre::bail!(\n                \"You have to provide a valid RPC URL to use --guess-constructor-args feature\"\n            )\n        }\n\n        // If chain is not set, we try to get it from the RPC.\n        // If RPC is not set, the default chain is used.\n        let chain = match config.get_rpc_url() {\n            Some(_) => {\n                let provider = utils::get_provider(&config)?;\n                utils::get_chain(config.chain, provider).await?\n            }\n            None => config.chain.unwrap_or_default(),\n        };\n\n        let context = self.resolve_context().await?;\n\n        // Set Etherscan options.\n        self.etherscan.chain = Some(chain);\n        self.etherscan.key = config.get_etherscan_config_with_chain(Some(chain))?.map(|c| c.key);\n\n        // For chains with Sourcify-compatible APIs, use the chain's URL from etherscan_urls\n        if self.verifier.verifier.is_sourcify()\n            && self.verifier.verifier_url.is_none()\n            && let Some(url) = sourcify_api_url(chain)\n        {\n            self.verifier.verifier_url = Some(url);\n        }\n\n        if self.show_standard_json_input {\n            let args = EtherscanVerificationProvider::default()\n                .create_verify_request(&self, &context)\n                .await?;\n            sh_println!(\"{}\", args.source)?;\n            return Ok(());\n        }\n\n        let verifier_url = self.verifier.verifier_url.clone();\n        sh_println!(\"Start verifying contract `{}` deployed on {chain}\", self.address)?;\n        if let Some(version) = &self.evm_version {\n            sh_println!(\"EVM version: {version}\")?;\n        }\n        if let Some(version) = &self.compiler_version {\n            sh_println!(\"Compiler version: {version}\")?;\n        }\n        if let Some(optimizations) = &self.num_of_optimizations {\n            sh_println!(\"Optimizations:    {optimizations}\")?\n        }\n        if let Some(args) = &self.constructor_args\n            && !args.is_empty()\n        {\n            sh_println!(\"Constructor args: {args}\")?\n        }\n        self.verifier.verifier.client(self.etherscan.key().as_deref(), self.etherscan.chain, self.verifier.verifier_url.is_some())?.verify(self, context).await.map_err(|err| {\n            if let Some(verifier_url) = verifier_url {\n                 match Url::parse(&verifier_url) {\n                    Ok(url) if is_host_only(&url) => {\n                        return err.wrap_err(format!(\n                            \"Provided URL `{verifier_url}` is host only.\\n Did you mean to use the API endpoint`{verifier_url}/api` ?\"\n                        ))\n                    }\n                    Err(url_err) => {\n                        return err.wrap_err(format!(\n                            \"Invalid URL {verifier_url} provided: {url_err}\"\n                        ))\n                    }\n                    _ => {}\n                }\n            }\n\n            err\n        })\n    }\n\n    /// Returns the configured verification provider\n    pub fn verification_provider(&self) -> Result<Box<dyn VerificationProvider>> {\n        self.verifier.verifier.client(\n            self.etherscan.key().as_deref(),\n            self.etherscan.chain,\n            self.verifier.verifier_url.is_some(),\n        )\n    }\n\n    /// Resolves [VerificationContext] object either from entered contract name or by trying to\n    /// match bytecode located at given address.\n    pub async fn resolve_context(&self) -> Result<VerificationContext> {\n        let mut config = self.load_config()?;\n        config.libraries.extend(self.libraries.clone());\n\n        let project = config.project()?;\n\n        if let Some(ref contract) = self.contract {\n            let contract_path = if let Some(ref path) = contract.path {\n                project.root().join(PathBuf::from(path))\n            } else {\n                project.find_contract_path(&contract.name)?\n            };\n\n            let cache = project.read_cache_file().ok();\n\n            let mut version = if let Some(ref version) = self.compiler_version {\n                version.trim_start_matches('v').parse()?\n            } else if let Some(ref solc) = config.solc {\n                match solc {\n                    SolcReq::Version(version) => version.to_owned(),\n                    SolcReq::Local(solc) => Solc::new(solc)?.version,\n                }\n            } else if let Some(entry) =\n                cache.as_ref().and_then(|cache| cache.files.get(&contract_path).cloned())\n            {\n                let unique_versions = entry\n                    .artifacts\n                    .get(&contract.name)\n                    .map(|artifacts| artifacts.keys().collect::<HashSet<_>>())\n                    .unwrap_or_default();\n\n                if unique_versions.is_empty() {\n                    eyre::bail!(\n                        \"No matching artifact found for {}. This could be due to:\\n\\\n                        - Compiler version mismatch - the contract was compiled with a different Solidity version than what's being used for verification\",\n                        contract.name\n                    );\n                } else if unique_versions.len() > 1 {\n                    warn!(\n                        \"Ambiguous compiler versions found in cache: {}\",\n                        unique_versions.iter().join(\", \")\n                    );\n                    eyre::bail!(\n                        \"Compiler version has to be set in `foundry.toml`. If the project was not deployed with foundry, specify the version through `--compiler-version` flag.\"\n                    )\n                }\n\n                unique_versions.into_iter().next().unwrap().to_owned()\n            } else {\n                eyre::bail!(\n                    \"If cache is disabled, compiler version must be either provided with `--compiler-version` option or set in foundry.toml\"\n                )\n            };\n\n            let settings = if let Some(profile) = &self.compilation_profile {\n                if profile == \"default\" {\n                    &project.settings\n                } else if let Some(settings) = project.additional_settings.get(profile.as_str()) {\n                    settings\n                } else {\n                    eyre::bail!(\"Unknown compilation profile: {}\", profile)\n                }\n            } else if let Some((cache, entry)) = cache\n                .as_ref()\n                .and_then(|cache| Some((cache, cache.files.get(&contract_path)?.clone())))\n            {\n                let profiles = entry\n                    .artifacts\n                    .get(&contract.name)\n                    .and_then(|artifacts| {\n                        let mut cached_artifacts = artifacts.get(&version);\n                        // If we try to verify with specific build version and no cached artifacts\n                        // found, then check if we have artifacts cached for same version but\n                        // without any build metadata.\n                        // This could happen when artifacts are built / cached\n                        // with a version like `0.8.20` but verify is using a compiler-version arg\n                        // as `0.8.20+commit.a1b79de6`.\n                        // See <https://github.com/foundry-rs/foundry/issues/9510>.\n                        if cached_artifacts.is_none() && version.build != BuildMetadata::EMPTY {\n                            version.build = BuildMetadata::EMPTY;\n                            cached_artifacts = artifacts.get(&version);\n                        }\n                        cached_artifacts\n                    })\n                    .map(|artifacts| artifacts.keys().collect::<HashSet<_>>())\n                    .unwrap_or_default();\n\n                if profiles.is_empty() {\n                    eyre::bail!(\n                        \"No matching artifact found for {} with compiler version {}. This could be due to:\\n\\\n                        - Compiler version mismatch - the contract was compiled with a different Solidity version\",\n                        contract.name,\n                        version\n                    );\n                } else if profiles.len() > 1 {\n                    eyre::bail!(\n                        \"Ambiguous compilation profiles found in cache: {}, please specify the profile through `--compilation-profile` flag\",\n                        profiles.iter().join(\", \")\n                    )\n                }\n\n                let profile = profiles.into_iter().next().unwrap().to_owned();\n                cache.profiles.get(&profile).expect(\"must be present\")\n            } else if project.additional_settings.is_empty() {\n                &project.settings\n            } else {\n                eyre::bail!(\n                    \"If cache is disabled, compilation profile must be provided with `--compilation-profile` option or set in foundry.toml\"\n                )\n            };\n\n            VerificationContext::new(\n                contract_path,\n                contract.name.clone(),\n                version,\n                config,\n                settings.clone(),\n            )\n        } else {\n            if config.get_rpc_url().is_none() {\n                eyre::bail!(\"You have to provide a contract name or a valid RPC URL\")\n            }\n            let provider = utils::get_provider(&config)?;\n            let code = provider.get_code_at(self.address).await?;\n\n            let output = ProjectCompiler::new().compile(&project)?;\n            let contracts = ContractsByArtifact::new(\n                output.artifact_ids().map(|(id, artifact)| (id, artifact.clone().into())),\n            );\n\n            let Some((artifact_id, _)) = contracts.find_by_deployed_code_exact(&code) else {\n                eyre::bail!(format!(\n                    \"Bytecode at {} does not match any local contracts\",\n                    self.address\n                ))\n            };\n\n            let settings = project\n                .settings_profiles()\n                .find_map(|(name, settings)| {\n                    (name == artifact_id.profile.as_str()).then_some(settings)\n                })\n                .expect(\"must be present\");\n\n            VerificationContext::new(\n                artifact_id.source.clone(),\n                artifact_id.name.split('.').next().unwrap().to_owned(),\n                artifact_id.version.clone(),\n                config,\n                settings.clone(),\n            )\n        }\n    }\n\n    /// Detects the language for verification from source file extension, if none provided.\n    pub fn detect_language(&self, ctx: &VerificationContext) -> ContractLanguage {\n        self.language.unwrap_or_else(|| {\n            match ctx.target_path.extension().and_then(|e| e.to_str()) {\n                Some(\"vy\") => ContractLanguage::Vyper,\n                _ => ContractLanguage::Solidity,\n            }\n        })\n    }\n}\n\n/// Check verification status arguments\n#[derive(Clone, Debug, Parser)]\npub struct VerifyCheckArgs {\n    /// The verification ID.\n    ///\n    /// For Etherscan - Submission GUID.\n    ///\n    /// For Sourcify - Verification Job ID.\n    pub id: String,\n\n    #[command(flatten)]\n    pub retry: RetryArgs,\n\n    #[command(flatten)]\n    pub etherscan: EtherscanOpts,\n\n    #[command(flatten)]\n    pub verifier: VerifierArgs,\n}\n\nimpl_figment_convert_cast!(VerifyCheckArgs);\n\nimpl VerifyCheckArgs {\n    /// Run the verify command to submit the contract's source code for verification on etherscan\n    pub async fn run(self) -> Result<()> {\n        sh_println!(\n            \"Checking verification status on {}\",\n            self.etherscan.chain.unwrap_or_default()\n        )?;\n        self.verifier\n            .verifier\n            .client(\n                self.etherscan.key().as_deref(),\n                self.etherscan.chain,\n                self.verifier.verifier_url.is_some(),\n            )?\n            .check(self)\n            .await\n    }\n}\n\nimpl figment::Provider for VerifyCheckArgs {\n    fn metadata(&self) -> figment::Metadata {\n        figment::Metadata::named(\"Verify Check Provider\")\n    }\n\n    fn data(\n        &self,\n    ) -> Result<figment::value::Map<figment::Profile, figment::value::Dict>, figment::Error> {\n        let mut dict = self.etherscan.dict();\n        if let Some(api_key) = &self.etherscan.key {\n            dict.insert(\"etherscan_api_key\".into(), api_key.as_str().into());\n        }\n\n        Ok(figment::value::Map::from([(Config::selected_profile(), dict)]))\n    }\n}\n\n/// Returns the Sourcify-compatible API URL for chains that have one registered in `etherscan_urls`.\n///\n/// Some chains register their Sourcify-compatible verification API under `etherscan_urls` in\n/// alloy-chains. This function returns the properly formatted URL for such chains.\nfn sourcify_api_url(chain: Chain) -> Option<String> {\n    if chain.is_custom_sourcify() {\n        chain.etherscan_urls().map(|(api_url, _)| {\n            let api_url = api_url.trim_end_matches('/');\n            format!(\"{api_url}/\")\n        })\n    } else {\n        None\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn can_parse_verify_contract() {\n        let args: VerifyArgs = VerifyArgs::parse_from([\n            \"foundry-cli\",\n            \"0x0000000000000000000000000000000000000000\",\n            \"src/Domains.sol:Domains\",\n            \"--via-ir\",\n        ]);\n        assert!(args.via_ir);\n    }\n\n    #[test]\n    fn can_parse_new_compiler_flags() {\n        let args: VerifyArgs = VerifyArgs::parse_from([\n            \"foundry-cli\",\n            \"0x0000000000000000000000000000000000000000\",\n            \"src/Domains.sol:Domains\",\n            \"--no-auto-detect\",\n            \"--use\",\n            \"0.8.23\",\n        ]);\n        assert!(args.no_auto_detect);\n        assert_eq!(args.use_solc.as_deref(), Some(\"0.8.23\"));\n    }\n}\n"
  },
  {
    "path": "crates/wallets/Cargo.toml",
    "content": "[package]\nname = \"foundry-wallets\"\n\nversion.workspace = true\nedition.workspace = true\nrust-version.workspace = true\nauthors.workspace = true\nlicense.workspace = true\nhomepage.workspace = true\nrepository.workspace = true\n\n[lints]\nworkspace = true\n\n[dependencies]\nfoundry-config.workspace = true\n\nalloy-primitives.workspace = true\nalloy-signer = { workspace = true, features = [\"eip712\"] }\nalloy-signer-local = { workspace = true, features = [\"mnemonic\", \"keystore\"] }\nalloy-signer-ledger = { workspace = true, features = [\"eip712\"] }\nalloy-signer-trezor.workspace = true\nalloy-network.workspace = true\nalloy-consensus.workspace = true\nalloy-sol-types.workspace = true\nalloy-dyn-abi.workspace = true\n\n# browser wallet\naxum.workspace = true\nfoundry-common.workspace = true\nserde_json.workspace = true\ntokio = { workspace = true, features = [\"macros\"] }\nuuid.workspace = true\nwebbrowser = \"1.0.6\"\n\n# aws-kms\nalloy-signer-aws = { workspace = true, features = [\"eip712\"], optional = true }\naws-config = { version = \"1\", default-features = true, optional = true }\n\n# gcp-kms\nalloy-signer-gcp = { workspace = true, features = [\"eip712\"], optional = true }\n\n# turnkey\nalloy-signer-turnkey = { workspace = true, features = [\"eip712\"], optional = true }\n\nasync-trait.workspace = true\nclap = { version = \"4\", features = [\"derive\", \"env\", \"unicode\", \"wrap_help\"] }\nderive_builder = \"0.20\"\neyre.workspace = true\nrpassword = \"7\"\nserde.workspace = true\nthiserror.workspace = true\ntower.workspace = true\ntower-http = { workspace = true, features = [\"cors\", \"set-header\"] }\ntracing.workspace = true\neth-keystore = \"0.5.0\"\n\n[dev-dependencies]\nreqwest = { workspace = true, features = [\"json\"] }\n\n[features]\naws-kms = [\"dep:alloy-signer-aws\", \"dep:aws-config\"]\ngcp-kms = [\"dep:alloy-signer-gcp\"]\nturnkey = [\"dep:alloy-signer-turnkey\"]\n"
  },
  {
    "path": "crates/wallets/src/error.rs",
    "content": "use alloy_primitives::hex::FromHexError;\nuse alloy_signer::k256::ecdsa;\nuse alloy_signer_ledger::LedgerError;\nuse alloy_signer_local::LocalSignerError;\nuse alloy_signer_trezor::TrezorError;\n\n#[cfg(feature = \"aws-kms\")]\nuse alloy_signer_aws::AwsSignerError;\n\n#[cfg(feature = \"gcp-kms\")]\nuse alloy_signer_gcp::GcpSignerError;\n\n#[cfg(feature = \"turnkey\")]\nuse alloy_signer_turnkey::TurnkeySignerError;\n\nuse crate::wallet_browser::error::BrowserWalletError;\n\n#[derive(Debug, thiserror::Error)]\npub enum PrivateKeyError {\n    #[error(\"Failed to create wallet from private key. Private key is invalid hex: {0}\")]\n    InvalidHex(#[from] FromHexError),\n    #[error(\n        \"Failed to create wallet from private key. Invalid private key. But env var {0} exists. Is the `$` anchor missing?\"\n    )]\n    ExistsAsEnvVar(String),\n}\n\n#[derive(Debug, thiserror::Error)]\npub enum WalletSignerError {\n    #[error(transparent)]\n    Local(#[from] LocalSignerError),\n    #[error(\"Failed to decrypt keystore: incorrect password\")]\n    IncorrectKeystorePassword,\n    #[error(transparent)]\n    Ledger(#[from] LedgerError),\n    #[error(transparent)]\n    Trezor(#[from] TrezorError),\n    #[error(transparent)]\n    #[cfg(feature = \"aws-kms\")]\n    Aws(#[from] Box<AwsSignerError>),\n    #[error(transparent)]\n    #[cfg(feature = \"gcp-kms\")]\n    Gcp(#[from] Box<GcpSignerError>),\n    #[error(transparent)]\n    #[cfg(feature = \"turnkey\")]\n    Turnkey(#[from] TurnkeySignerError),\n    #[error(transparent)]\n    Browser(#[from] BrowserWalletError),\n    #[error(transparent)]\n    Io(#[from] std::io::Error),\n    #[error(transparent)]\n    InvalidHex(#[from] FromHexError),\n    #[error(transparent)]\n    Ecdsa(#[from] ecdsa::Error),\n    #[error(\"foundry was not built with support for {0} signer\")]\n    UnsupportedSigner(&'static str),\n}\n\nimpl WalletSignerError {\n    pub fn aws_unsupported() -> Self {\n        Self::UnsupportedSigner(\"AWS KMS\")\n    }\n\n    pub fn gcp_unsupported() -> Self {\n        Self::UnsupportedSigner(\"Google Cloud KMS\")\n    }\n\n    pub fn turnkey_unsupported() -> Self {\n        Self::UnsupportedSigner(\"Turnkey\")\n    }\n\n    pub fn browser_unsupported() -> Self {\n        Self::UnsupportedSigner(\"Browser Wallet\")\n    }\n}\n"
  },
  {
    "path": "crates/wallets/src/lib.rs",
    "content": "//! # foundry-wallets\n//!\n//! Utilities for working with multiple signers.\n\n#![cfg_attr(not(test), warn(unused_crate_dependencies))]\n#![cfg_attr(docsrs, feature(doc_cfg))]\n\n#[macro_use]\nextern crate foundry_common;\n\n#[macro_use]\nextern crate tracing;\n\npub mod error;\npub mod opts;\npub mod signer;\npub mod utils;\npub mod wallet_browser;\npub mod wallet_multi;\npub mod wallet_raw;\n\npub use opts::WalletOpts;\npub use signer::{PendingSigner, WalletSigner};\npub use wallet_browser::opts::BrowserWalletOpts;\npub use wallet_multi::MultiWalletOpts;\npub use wallet_raw::RawWalletOpts;\n\n#[cfg(feature = \"aws-kms\")]\nuse aws_config as _;\n"
  },
  {
    "path": "crates/wallets/src/opts.rs",
    "content": "use crate::{signer::WalletSigner, utils, wallet_raw::RawWalletOpts};\nuse alloy_primitives::Address;\nuse clap::Parser;\nuse eyre::Result;\nuse serde::Serialize;\n\n/// The wallet options can either be:\n/// 1. Raw (via private key / mnemonic file, see `RawWallet`)\n/// 2. Keystore (via file path)\n/// 3. Ledger\n/// 4. Trezor\n/// 5. AWS KMS\n/// 6. Google Cloud KMS\n/// 7. Turnkey\n/// 8. Browser wallet\n#[derive(Clone, Debug, Default, Serialize, Parser)]\n#[command(next_help_heading = \"Wallet options\", about = None, long_about = None)]\npub struct WalletOpts {\n    /// The sender account.\n    #[arg(\n        long,\n        short,\n        value_name = \"ADDRESS\",\n        help_heading = \"Wallet options - raw\",\n        env = \"ETH_FROM\"\n    )]\n    pub from: Option<Address>,\n\n    #[command(flatten)]\n    pub raw: RawWalletOpts,\n\n    /// Use the keystore in the given folder or file.\n    #[arg(\n        long = \"keystore\",\n        help_heading = \"Wallet options - keystore\",\n        value_name = \"PATH\",\n        env = \"ETH_KEYSTORE\"\n    )]\n    pub keystore_path: Option<String>,\n\n    /// Use a keystore from the default keystores folder (~/.foundry/keystores) by its filename\n    #[arg(\n        long = \"account\",\n        help_heading = \"Wallet options - keystore\",\n        value_name = \"ACCOUNT_NAME\",\n        env = \"ETH_KEYSTORE_ACCOUNT\",\n        conflicts_with = \"keystore_path\"\n    )]\n    pub keystore_account_name: Option<String>,\n\n    /// The keystore password.\n    ///\n    /// Used with --keystore.\n    #[arg(\n        long = \"password\",\n        help_heading = \"Wallet options - keystore\",\n        requires = \"keystore_path\",\n        value_name = \"PASSWORD\"\n    )]\n    pub keystore_password: Option<String>,\n\n    /// The keystore password file path.\n    ///\n    /// Used with --keystore.\n    #[arg(\n        long = \"password-file\",\n        help_heading = \"Wallet options - keystore\",\n        requires = \"keystore_path\",\n        value_name = \"PASSWORD_FILE\",\n        env = \"ETH_PASSWORD\"\n    )]\n    pub keystore_password_file: Option<String>,\n\n    /// Use a Ledger hardware wallet.\n    #[arg(long, short, help_heading = \"Wallet options - hardware wallet\")]\n    pub ledger: bool,\n\n    /// Use a Trezor hardware wallet.\n    #[arg(long, short, help_heading = \"Wallet options - hardware wallet\")]\n    pub trezor: bool,\n\n    /// Use AWS Key Management Service.\n    ///\n    /// Ensure the AWS_KMS_KEY_ID environment variable is set.\n    #[arg(long, help_heading = \"Wallet options - remote\", hide = !cfg!(feature = \"aws-kms\"))]\n    pub aws: bool,\n\n    /// Use Google Cloud Key Management Service.\n    ///\n    /// Ensure the following environment variables are set: GCP_PROJECT_ID, GCP_LOCATION,\n    /// GCP_KEY_RING, GCP_KEY_NAME, GCP_KEY_VERSION.\n    ///\n    /// See: <https://cloud.google.com/kms/docs>\n    #[arg(long, help_heading = \"Wallet options - remote\", hide = !cfg!(feature = \"gcp-kms\"))]\n    pub gcp: bool,\n\n    /// Use Turnkey.\n    ///\n    /// Ensure the following environment variables are set: TURNKEY_API_PRIVATE_KEY,\n    /// TURNKEY_ORGANIZATION_ID, TURNKEY_ADDRESS.\n    ///\n    /// See: <https://docs.turnkey.com/getting-started/quickstart>\n    #[arg(long, help_heading = \"Wallet options - remote\", hide = !cfg!(feature = \"turnkey\"))]\n    pub turnkey: bool,\n}\n\nimpl WalletOpts {\n    pub async fn signer(&self) -> Result<WalletSigner> {\n        trace!(\"start finding signer\");\n\n        let get_env = |key: &str| {\n            std::env::var(key)\n                .map_err(|_| eyre::eyre!(\"{key} environment variable is required for signer\"))\n        };\n\n        let signer = if self.ledger {\n            utils::create_ledger_signer(self.raw.hd_path.as_deref(), self.raw.mnemonic_index)\n                .await?\n        } else if self.trezor {\n            utils::create_trezor_signer(self.raw.hd_path.as_deref(), self.raw.mnemonic_index)\n                .await?\n        } else if self.aws {\n            let key_id = get_env(\"AWS_KMS_KEY_ID\")?;\n            WalletSigner::from_aws(key_id).await?\n        } else if self.gcp {\n            let project_id = get_env(\"GCP_PROJECT_ID\")?;\n            let location = get_env(\"GCP_LOCATION\")?;\n            let keyring = get_env(\"GCP_KEY_RING\")?;\n            let key_name = get_env(\"GCP_KEY_NAME\")?;\n            let key_version = get_env(\"GCP_KEY_VERSION\")?\n                .parse()\n                .map_err(|_| eyre::eyre!(\"GCP_KEY_VERSION could not be parsed into u64\"))?;\n            WalletSigner::from_gcp(project_id, location, keyring, key_name, key_version).await?\n        } else if self.turnkey {\n            let api_private_key = get_env(\"TURNKEY_API_PRIVATE_KEY\")?;\n            let organization_id = get_env(\"TURNKEY_ORGANIZATION_ID\")?;\n            let address_str = get_env(\"TURNKEY_ADDRESS\")?;\n            let address = address_str.parse().map_err(|_| {\n                eyre::eyre!(\"TURNKEY_ADDRESS could not be parsed as an Ethereum address\")\n            })?;\n            WalletSigner::from_turnkey(api_private_key, organization_id, address)?\n        } else if let Some(raw_wallet) = self.raw.signer()? {\n            raw_wallet\n        } else if let Some(path) = utils::maybe_get_keystore_path(\n            self.keystore_path.as_deref(),\n            self.keystore_account_name.as_deref(),\n        )? {\n            let (maybe_signer, maybe_pending) = utils::create_keystore_signer(\n                &path,\n                self.keystore_password.as_deref(),\n                self.keystore_password_file.as_deref(),\n            )?;\n            if let Some(pending) = maybe_pending {\n                pending.unlock()?\n            } else if let Some(signer) = maybe_signer {\n                signer\n            } else {\n                unreachable!()\n            }\n        } else {\n            eyre::bail!(\n                \"\\\nError accessing local wallet. Did you pass a keystore, hardware wallet, private key or mnemonic?\n\nRun the command with --help flag for more information or use the corresponding CLI\nflag to set your key via:\n\n--keystore\n--interactive\n--private-key\n--mnemonic-path\n--aws\n--gcp\n--turnkey\n--trezor\n--ledger\n--browser\n\nAlternatively, when using the `cast send` or `cast mktx` commands with a local node\nor RPC that has unlocked accounts, the --unlocked or --ethsign flags can be used,\nrespectively. The sender address can be specified by setting the `ETH_FROM` environment\nvariable to the desired unlocked account address, or by providing the address directly\nusing the --from flag.\"\n            )\n        };\n\n        Ok(signer)\n    }\n}\n\nimpl From<RawWalletOpts> for WalletOpts {\n    fn from(options: RawWalletOpts) -> Self {\n        Self { raw: options, ..Default::default() }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use alloy_signer::Signer;\n    use std::{path::Path, str::FromStr};\n\n    #[tokio::test]\n    async fn find_keystore() {\n        let keystore =\n            Path::new(concat!(env!(\"CARGO_MANIFEST_DIR\"), \"/../cast/tests/fixtures/keystore\"));\n        let keystore_file = keystore\n            .join(\"UTC--2022-12-20T10-30-43.591916000Z--ec554aeafe75601aaab43bd4621a22284db566c2\");\n        let password_file = keystore.join(\"password-ec554\");\n        let wallet: WalletOpts = WalletOpts::parse_from([\n            \"foundry-cli\",\n            \"--from\",\n            \"560d246fcddc9ea98a8b032c9a2f474efb493c28\",\n            \"--keystore\",\n            keystore_file.to_str().unwrap(),\n            \"--password-file\",\n            password_file.to_str().unwrap(),\n        ]);\n        let signer = wallet.signer().await.unwrap();\n        assert_eq!(\n            signer.address(),\n            Address::from_str(\"ec554aeafe75601aaab43bd4621a22284db566c2\").unwrap()\n        );\n    }\n\n    #[tokio::test]\n    async fn illformed_private_key_generates_user_friendly_error() {\n        let wallet = WalletOpts {\n            raw: RawWalletOpts {\n                interactive: false,\n                private_key: Some(\"123\".to_string()),\n                mnemonic: None,\n                mnemonic_passphrase: None,\n                hd_path: None,\n                mnemonic_index: 0,\n            },\n            from: None,\n            keystore_path: None,\n            keystore_account_name: None,\n            keystore_password: None,\n            keystore_password_file: None,\n            ledger: false,\n            trezor: false,\n            aws: false,\n            gcp: false,\n            turnkey: false,\n        };\n        match wallet.signer().await {\n            Ok(_) => {\n                panic!(\"illformed private key shouldn't decode\")\n            }\n            Err(x) => {\n                assert!(\n                    x.to_string().contains(\"Failed to decode private key\"),\n                    \"Error message is not user-friendly\"\n                );\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "crates/wallets/src/signer.rs",
    "content": "use crate::error::WalletSignerError;\nuse alloy_consensus::SignableTransaction;\nuse alloy_dyn_abi::TypedData;\nuse alloy_network::TxSigner;\nuse alloy_primitives::{Address, B256, ChainId, Signature, hex};\nuse alloy_signer::Signer;\nuse alloy_signer_ledger::{HDPath as LedgerHDPath, LedgerSigner};\nuse alloy_signer_local::{MnemonicBuilder, PrivateKeySigner, coins_bip39::English};\nuse alloy_signer_trezor::{HDPath as TrezorHDPath, TrezorSigner};\nuse alloy_sol_types::{Eip712Domain, SolStruct};\nuse async_trait::async_trait;\nuse std::{collections::HashSet, path::PathBuf};\nuse tracing::warn;\n\n#[cfg(feature = \"aws-kms\")]\nuse alloy_signer_aws::{AwsSigner, aws_config::BehaviorVersion, aws_sdk_kms::Client as AwsClient};\n\n#[cfg(feature = \"gcp-kms\")]\nuse alloy_signer_gcp::{\n    GcpKeyRingRef, GcpSigner, GcpSignerError, KeySpecifier,\n    gcloud_sdk::{\n        GoogleApi,\n        google::cloud::kms::v1::key_management_service_client::KeyManagementServiceClient,\n    },\n};\n\n#[cfg(feature = \"turnkey\")]\nuse alloy_signer_turnkey::TurnkeySigner;\n\npub type Result<T> = std::result::Result<T, WalletSignerError>;\n\n/// Wrapper enum around different signers.\n#[derive(Debug)]\npub enum WalletSigner {\n    /// Wrapper around local wallet. e.g. private key, mnemonic\n    Local(PrivateKeySigner),\n    /// Wrapper around Ledger signer.\n    Ledger(LedgerSigner),\n    /// Wrapper around Trezor signer.\n    Trezor(TrezorSigner),\n    /// Wrapper around AWS KMS signer.\n    #[cfg(feature = \"aws-kms\")]\n    Aws(AwsSigner),\n    /// Wrapper around Google Cloud KMS signer.\n    #[cfg(feature = \"gcp-kms\")]\n    Gcp(GcpSigner),\n    /// Wrapper around Turnkey signer.\n    #[cfg(feature = \"turnkey\")]\n    Turnkey(TurnkeySigner),\n}\n\nimpl WalletSigner {\n    pub async fn from_ledger_path(path: LedgerHDPath) -> Result<Self> {\n        let ledger = LedgerSigner::new(path, None).await?;\n        Ok(Self::Ledger(ledger))\n    }\n\n    pub async fn from_trezor_path(path: TrezorHDPath) -> Result<Self> {\n        let trezor = TrezorSigner::new(path, None).await?;\n        Ok(Self::Trezor(trezor))\n    }\n\n    pub async fn from_aws(key_id: String) -> Result<Self> {\n        #[cfg(feature = \"aws-kms\")]\n        {\n            let config =\n                alloy_signer_aws::aws_config::load_defaults(BehaviorVersion::latest()).await;\n            let client = AwsClient::new(&config);\n\n            Ok(Self::Aws(\n                AwsSigner::new(client, key_id, None)\n                    .await\n                    .map_err(|e| WalletSignerError::Aws(Box::new(e)))?,\n            ))\n        }\n\n        #[cfg(not(feature = \"aws-kms\"))]\n        {\n            let _ = key_id;\n            Err(WalletSignerError::aws_unsupported())\n        }\n    }\n\n    pub async fn from_gcp(\n        project_id: String,\n        location: String,\n        keyring: String,\n        key_name: String,\n        key_version: u64,\n    ) -> Result<Self> {\n        #[cfg(feature = \"gcp-kms\")]\n        {\n            let keyring = GcpKeyRingRef::new(&project_id, &location, &keyring);\n            let client = match GoogleApi::from_function(\n                KeyManagementServiceClient::new,\n                \"https://cloudkms.googleapis.com\",\n                None,\n            )\n            .await\n            {\n                Ok(c) => c,\n                Err(e) => {\n                    return Err(WalletSignerError::Gcp(Box::new(GcpSignerError::GoogleKmsError(\n                        e,\n                    ))));\n                }\n            };\n\n            let specifier = KeySpecifier::new(keyring, &key_name, key_version);\n\n            Ok(Self::Gcp(\n                GcpSigner::new(client, specifier, None)\n                    .await\n                    .map_err(|e| WalletSignerError::Gcp(Box::new(e)))?,\n            ))\n        }\n\n        #[cfg(not(feature = \"gcp-kms\"))]\n        {\n            let _ = project_id;\n            let _ = location;\n            let _ = keyring;\n            let _ = key_name;\n            let _ = key_version;\n            Err(WalletSignerError::gcp_unsupported())\n        }\n    }\n\n    pub fn from_turnkey(\n        api_private_key: String,\n        organization_id: String,\n        address: Address,\n    ) -> Result<Self> {\n        #[cfg(feature = \"turnkey\")]\n        {\n            Ok(Self::Turnkey(TurnkeySigner::from_api_key(\n                &api_private_key,\n                organization_id,\n                address,\n                None,\n            )?))\n        }\n\n        #[cfg(not(feature = \"turnkey\"))]\n        {\n            let _ = api_private_key;\n            let _ = organization_id;\n            let _ = address;\n            Err(WalletSignerError::turnkey_unsupported())\n        }\n    }\n\n    pub fn from_private_key(private_key: &B256) -> Result<Self> {\n        Ok(Self::Local(PrivateKeySigner::from_bytes(private_key)?))\n    }\n\n    /// Returns a list of addresses available to use with current signer\n    ///\n    /// - for Ledger and Trezor signers the number of addresses to retrieve is specified as argument\n    /// - the result for Ledger signers includes addresses available for both LedgerLive and Legacy\n    ///   derivation paths\n    /// - for Local and AWS signers the result contains a single address\n    /// - errors when retrieving addresses are logged but do not prevent returning available\n    ///   addresses\n    pub async fn available_senders(&self, max: usize) -> Result<Vec<Address>> {\n        let mut senders = HashSet::new();\n\n        match self {\n            Self::Local(local) => {\n                senders.insert(local.address());\n            }\n            Self::Ledger(ledger) => {\n                // Try LedgerLive derivation path\n                for i in 0..max {\n                    match ledger.get_address_with_path(&LedgerHDPath::LedgerLive(i)).await {\n                        Ok(address) => {\n                            senders.insert(address);\n                        }\n                        Err(e) => {\n                            warn!(\"Failed to get Ledger address at index {i} (LedgerLive): {e}\");\n                        }\n                    }\n                }\n                // Try Legacy derivation path\n                for i in 0..max {\n                    match ledger.get_address_with_path(&LedgerHDPath::Legacy(i)).await {\n                        Ok(address) => {\n                            senders.insert(address);\n                        }\n                        Err(e) => {\n                            warn!(\"Failed to get Ledger address at index {i} (Legacy): {e}\");\n                        }\n                    }\n                }\n            }\n            Self::Trezor(trezor) => {\n                for i in 0..max {\n                    match trezor.get_address_with_path(&TrezorHDPath::TrezorLive(i)).await {\n                        Ok(address) => {\n                            senders.insert(address);\n                        }\n                        Err(e) => {\n                            warn!(\"Failed to get Trezor address at index {i} (TrezorLive): {e}\",);\n                        }\n                    }\n                }\n            }\n            #[cfg(feature = \"aws-kms\")]\n            Self::Aws(aws) => {\n                senders.insert(alloy_signer::Signer::address(aws));\n            }\n            #[cfg(feature = \"gcp-kms\")]\n            Self::Gcp(gcp) => {\n                senders.insert(alloy_signer::Signer::address(gcp));\n            }\n            #[cfg(feature = \"turnkey\")]\n            Self::Turnkey(turnkey) => {\n                senders.insert(alloy_signer::Signer::address(turnkey));\n            }\n        }\n        Ok(senders.into_iter().collect())\n    }\n\n    pub fn from_mnemonic(\n        mnemonic: &str,\n        passphrase: Option<&str>,\n        derivation_path: Option<&str>,\n        index: u32,\n    ) -> Result<Self> {\n        let mut builder = MnemonicBuilder::<English>::default().phrase(mnemonic);\n\n        if let Some(passphrase) = passphrase {\n            builder = builder.password(passphrase)\n        }\n\n        builder = if let Some(hd_path) = derivation_path {\n            builder.derivation_path(hd_path)?\n        } else {\n            builder.index(index)?\n        };\n\n        Ok(Self::Local(builder.build()?))\n    }\n}\n\nmacro_rules! delegate {\n    ($s:ident, $inner:ident => $e:expr) => {\n        match $s {\n            Self::Local($inner) => $e,\n            Self::Ledger($inner) => $e,\n            Self::Trezor($inner) => $e,\n            #[cfg(feature = \"aws-kms\")]\n            Self::Aws($inner) => $e,\n            #[cfg(feature = \"gcp-kms\")]\n            Self::Gcp($inner) => $e,\n            #[cfg(feature = \"turnkey\")]\n            Self::Turnkey($inner) => $e,\n        }\n    };\n}\n\n#[async_trait]\nimpl Signer for WalletSigner {\n    /// Signs the given hash.\n    async fn sign_hash(&self, hash: &B256) -> alloy_signer::Result<Signature> {\n        delegate!(self, inner => inner.sign_hash(hash)).await\n    }\n\n    async fn sign_message(&self, message: &[u8]) -> alloy_signer::Result<Signature> {\n        delegate!(self, inner => inner.sign_message(message)).await\n    }\n\n    fn address(&self) -> Address {\n        delegate!(self, inner => alloy_signer::Signer::address(inner))\n    }\n\n    fn chain_id(&self) -> Option<ChainId> {\n        delegate!(self, inner => inner.chain_id())\n    }\n\n    fn set_chain_id(&mut self, chain_id: Option<ChainId>) {\n        delegate!(self, inner => inner.set_chain_id(chain_id))\n    }\n\n    async fn sign_typed_data<T: SolStruct + Send + Sync>(\n        &self,\n        payload: &T,\n        domain: &Eip712Domain,\n    ) -> alloy_signer::Result<Signature>\n    where\n        Self: Sized,\n    {\n        delegate!(self, inner => inner.sign_typed_data(payload, domain)).await\n    }\n\n    async fn sign_dynamic_typed_data(\n        &self,\n        payload: &TypedData,\n    ) -> alloy_signer::Result<Signature> {\n        delegate!(self, inner => inner.sign_dynamic_typed_data(payload)).await\n    }\n}\n\n#[async_trait]\nimpl TxSigner<Signature> for WalletSigner {\n    fn address(&self) -> Address {\n        Signer::address(self)\n    }\n\n    async fn sign_transaction(\n        &self,\n        tx: &mut dyn SignableTransaction<Signature>,\n    ) -> alloy_signer::Result<Signature> {\n        delegate!(self, inner => TxSigner::sign_transaction(inner, tx)).await\n    }\n}\n\n/// Signers that require user action to be obtained.\n#[derive(Debug, Clone)]\npub enum PendingSigner {\n    Keystore(PathBuf),\n    Interactive,\n}\n\nimpl PendingSigner {\n    pub fn unlock(self) -> Result<WalletSigner> {\n        match self {\n            Self::Keystore(path) => {\n                let password = rpassword::prompt_password(\"Enter keystore password:\")?;\n                match PrivateKeySigner::decrypt_keystore(path, password) {\n                    Ok(signer) => Ok(WalletSigner::Local(signer)),\n                    Err(e) => match e {\n                        // Catch the `MacMismatch` error, which indicates an incorrect password and\n                        // return a more user-friendly `IncorrectKeystorePassword`.\n                        alloy_signer_local::LocalSignerError::EthKeystoreError(\n                            eth_keystore::KeystoreError::MacMismatch,\n                        ) => Err(WalletSignerError::IncorrectKeystorePassword),\n                        _ => Err(WalletSignerError::Local(e)),\n                    },\n                }\n            }\n            Self::Interactive => {\n                let private_key = rpassword::prompt_password(\"Enter private key:\")?;\n                Ok(WalletSigner::from_private_key(&hex::FromHex::from_hex(private_key)?)?)\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "crates/wallets/src/utils.rs",
    "content": "use crate::{PendingSigner, WalletSigner, error::PrivateKeyError};\nuse alloy_primitives::{B256, hex::FromHex};\nuse alloy_signer_ledger::HDPath as LedgerHDPath;\nuse alloy_signer_local::PrivateKeySigner;\nuse alloy_signer_trezor::HDPath as TrezorHDPath;\nuse eyre::{Context, Result};\nuse foundry_config::Config;\nuse std::{\n    fs,\n    path::{Path, PathBuf},\n};\n\nfn ensure_pk_not_env(pk: &str) -> Result<()> {\n    if !pk.starts_with(\"0x\") && std::env::var(pk).is_ok() {\n        return Err(PrivateKeyError::ExistsAsEnvVar(pk.to_string()).into());\n    }\n    Ok(())\n}\n\n/// Validates and sanitizes user inputs, returning configured [WalletSigner].\npub fn create_private_key_signer(private_key_str: &str) -> Result<WalletSigner> {\n    let Ok(private_key) = B256::from_hex(private_key_str) else {\n        ensure_pk_not_env(private_key_str)?;\n        eyre::bail!(\"Failed to decode private key\")\n    };\n    match PrivateKeySigner::from_bytes(&private_key) {\n        Ok(pk) => Ok(WalletSigner::Local(pk)),\n        Err(err) => {\n            ensure_pk_not_env(private_key_str)?;\n            eyre::bail!(\"Failed to create wallet from private key: {err}\")\n        }\n    }\n}\n\n/// Creates [WalletSigner] instance from given mnemonic parameters.\n///\n/// Mnemonic can be either a file path or a mnemonic phrase.\npub fn create_mnemonic_signer(\n    mnemonic: &str,\n    passphrase: Option<&str>,\n    hd_path: Option<&str>,\n    index: u32,\n) -> Result<WalletSigner> {\n    let mnemonic = if Path::new(mnemonic).is_file() {\n        fs::read_to_string(mnemonic)?\n    } else {\n        mnemonic.to_owned()\n    };\n    let mnemonic = mnemonic.split_whitespace().collect::<Vec<_>>().join(\" \");\n\n    Ok(WalletSigner::from_mnemonic(&mnemonic, passphrase, hd_path, index)?)\n}\n\n/// Creates [WalletSigner] instance from given Ledger parameters.\npub async fn create_ledger_signer(\n    hd_path: Option<&str>,\n    mnemonic_index: u32,\n) -> Result<WalletSigner> {\n    let derivation = if let Some(hd_path) = hd_path {\n        LedgerHDPath::Other(hd_path.to_owned())\n    } else {\n        LedgerHDPath::LedgerLive(mnemonic_index as usize)\n    };\n\n    WalletSigner::from_ledger_path(derivation).await.wrap_err_with(|| {\n        \"\\\nCould not connect to Ledger device.\nMake sure it's connected and unlocked, with no other desktop wallet apps open.\"\n    })\n}\n\n/// Creates [WalletSigner] instance from given Trezor parameters.\npub async fn create_trezor_signer(\n    hd_path: Option<&str>,\n    mnemonic_index: u32,\n) -> Result<WalletSigner> {\n    let derivation = if let Some(hd_path) = hd_path {\n        TrezorHDPath::Other(hd_path.to_owned())\n    } else {\n        TrezorHDPath::TrezorLive(mnemonic_index as usize)\n    };\n\n    WalletSigner::from_trezor_path(derivation).await.wrap_err_with(|| {\n        \"\\\nCould not connect to Trezor device.\nMake sure it's connected and unlocked, with no other conflicting desktop wallet apps open.\"\n    })\n}\n\npub fn maybe_get_keystore_path(\n    maybe_path: Option<&str>,\n    maybe_name: Option<&str>,\n) -> Result<Option<PathBuf>> {\n    let default_keystore_dir = Config::foundry_keystores_dir()\n        .ok_or_else(|| eyre::eyre!(\"Could not find the default keystore directory.\"))?;\n    Ok(maybe_path\n        .map(PathBuf::from)\n        .or_else(|| maybe_name.map(|name| default_keystore_dir.join(name))))\n}\n\n/// Creates keystore signer from given parameters.\n///\n/// If correct password or password file is provided, the keystore is decrypted and a [WalletSigner]\n/// is returned.\n///\n/// Otherwise, a [PendingSigner] is returned, which can be used to unlock the keystore later,\n/// prompting user for password.\npub fn create_keystore_signer(\n    path: &PathBuf,\n    maybe_password: Option<&str>,\n    maybe_password_file: Option<&str>,\n) -> Result<(Option<WalletSigner>, Option<PendingSigner>)> {\n    if !path.exists() {\n        eyre::bail!(\"Keystore file `{path:?}` does not exist\")\n    }\n\n    if path.is_dir() {\n        eyre::bail!(\n            \"Keystore path `{path:?}` is a directory. Please specify the keystore file directly.\"\n        )\n    }\n\n    let password = match (maybe_password, maybe_password_file) {\n        (Some(password), _) => Ok(Some(password.to_string())),\n        (_, Some(password_file)) => {\n            let password_file = Path::new(password_file);\n            if !password_file.is_file() {\n                Err(eyre::eyre!(\"Keystore password file `{password_file:?}` does not exist\"))\n            } else {\n                Ok(Some(\n                    fs::read_to_string(password_file)\n                        .wrap_err_with(|| {\n                            format!(\"Failed to read keystore password file at {password_file:?}\")\n                        })?\n                        .trim_end()\n                        .to_string(),\n                ))\n            }\n        }\n        (None, None) => Ok(None),\n    }?;\n\n    if let Some(password) = password {\n        let wallet = PrivateKeySigner::decrypt_keystore(path, password)\n            .wrap_err_with(|| format!(\"Failed to decrypt keystore {path:?}\"))?;\n        Ok((Some(WalletSigner::Local(wallet)), None))\n    } else {\n        Ok((None, Some(PendingSigner::Keystore(path.clone()))))\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn parse_private_key_signer() {\n        let pk = B256::random();\n        let pk_str = pk.to_string();\n        assert!(create_private_key_signer(&pk_str).is_ok());\n        // skip 0x\n        assert!(create_private_key_signer(&pk_str[2..]).is_ok());\n    }\n}\n"
  },
  {
    "path": "crates/wallets/src/wallet_browser/app/assets/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <link rel=\"icon\" type=\"image/png\" href=\"/logo.png\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title>Foundry</title>\n    <script type=\"module\" crossorigin src=\"/main.js\"></script>\n    <link rel=\"stylesheet\" crossorigin href=\"/styles.css\">\n  </head>\n  <body>\n    <div id=\"root\"></div>\n  </body>\n</html>\n"
  },
  {
    "path": "crates/wallets/src/wallet_browser/app/assets/main.js",
    "content": "var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,t)=>()=>(e&&(t=e(e=0)),t),s=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports),c=e=>{let n={};for(var r in e)t(n,r,{get:e[r],enumerable:!0});return n},l=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},u=(n,r,a)=>(a=n==null?{}:e(i(n)),l(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n)),d=s((e=>{var t=Symbol.for(`react.transitional.element`),n=Symbol.for(`react.portal`),r=Symbol.for(`react.fragment`),i=Symbol.for(`react.strict_mode`),a=Symbol.for(`react.profiler`),o=Symbol.for(`react.consumer`),s=Symbol.for(`react.context`),c=Symbol.for(`react.forward_ref`),l=Symbol.for(`react.suspense`),u=Symbol.for(`react.memo`),d=Symbol.for(`react.lazy`),f=Symbol.for(`react.activity`),p=Symbol.iterator;function m(e){return typeof e!=`object`||!e?null:(e=p&&e[p]||e[`@@iterator`],typeof e==`function`?e:null)}var h={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},g=Object.assign,_={};function v(e,t,n){this.props=e,this.context=t,this.refs=_,this.updater=n||h}v.prototype.isReactComponent={},v.prototype.setState=function(e,t){if(typeof e!=`object`&&typeof e!=`function`&&e!=null)throw Error(`takes an object of state variables to update or a function which returns an object of state variables.`);this.updater.enqueueSetState(this,e,t,`setState`)},v.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,`forceUpdate`)};function y(){}y.prototype=v.prototype;function b(e,t,n){this.props=e,this.context=t,this.refs=_,this.updater=n||h}var x=b.prototype=new y;x.constructor=b,g(x,v.prototype),x.isPureReactComponent=!0;var S=Array.isArray;function C(){}var w={H:null,A:null,T:null,S:null},ee=Object.prototype.hasOwnProperty;function te(e,n,r){var i=r.ref;return{$$typeof:t,type:e,key:n,ref:i===void 0?null:i,props:r}}function ne(e,t){return te(e.type,t,e.props)}function re(e){return typeof e==`object`&&!!e&&e.$$typeof===t}function ie(e){var t={\"=\":`=0`,\":\":`=2`};return`$`+e.replace(/[=:]/g,function(e){return t[e]})}var ae=/\\/+/g;function oe(e,t){return typeof e==`object`&&e&&e.key!=null?ie(``+e.key):t.toString(36)}function se(e){switch(e.status){case`fulfilled`:return e.value;case`rejected`:throw e.reason;default:switch(typeof e.status==`string`?e.then(C,C):(e.status=`pending`,e.then(function(t){e.status===`pending`&&(e.status=`fulfilled`,e.value=t)},function(t){e.status===`pending`&&(e.status=`rejected`,e.reason=t)})),e.status){case`fulfilled`:return e.value;case`rejected`:throw e.reason}}throw e}function ce(e,r,i,a,o){var s=typeof e;(s===`undefined`||s===`boolean`)&&(e=null);var c=!1;if(e===null)c=!0;else switch(s){case`bigint`:case`string`:case`number`:c=!0;break;case`object`:switch(e.$$typeof){case t:case n:c=!0;break;case d:return c=e._init,ce(c(e._payload),r,i,a,o)}}if(c)return o=o(e),c=a===``?`.`+oe(e,0):a,S(o)?(i=``,c!=null&&(i=c.replace(ae,`$&/`)+`/`),ce(o,r,i,``,function(e){return e})):o!=null&&(re(o)&&(o=ne(o,i+(o.key==null||e&&e.key===o.key?``:(``+o.key).replace(ae,`$&/`)+`/`)+c)),r.push(o)),1;c=0;var l=a===``?`.`:a+`:`;if(S(e))for(var u=0;u<e.length;u++)a=e[u],s=l+oe(a,u),c+=ce(a,r,i,s,o);else if(u=m(e),typeof u==`function`)for(e=u.call(e),u=0;!(a=e.next()).done;)a=a.value,s=l+oe(a,u++),c+=ce(a,r,i,s,o);else if(s===`object`){if(typeof e.then==`function`)return ce(se(e),r,i,a,o);throw r=String(e),Error(`Objects are not valid as a React child (found: `+(r===`[object Object]`?`object with keys {`+Object.keys(e).join(`, `)+`}`:r)+`). If you meant to render a collection of children, use an array instead.`)}return c}function le(e,t,n){if(e==null)return e;var r=[],i=0;return ce(e,r,``,``,function(e){return t.call(n,e,i++)}),r}function ue(e){if(e._status===-1){var t=e._result;t=t(),t.then(function(t){(e._status===0||e._status===-1)&&(e._status=1,e._result=t)},function(t){(e._status===0||e._status===-1)&&(e._status=2,e._result=t)}),e._status===-1&&(e._status=0,e._result=t)}if(e._status===1)return e._result.default;throw e._result}var T=typeof reportError==`function`?reportError:function(e){if(typeof window==`object`&&typeof window.ErrorEvent==`function`){var t=new window.ErrorEvent(`error`,{bubbles:!0,cancelable:!0,message:typeof e==`object`&&e&&typeof e.message==`string`?String(e.message):String(e),error:e});if(!window.dispatchEvent(t))return}else if(typeof process==`object`&&typeof process.emit==`function`){process.emit(`uncaughtException`,e);return}console.error(e)},de={map:le,forEach:function(e,t,n){le(e,function(){t.apply(this,arguments)},n)},count:function(e){var t=0;return le(e,function(){t++}),t},toArray:function(e){return le(e,function(e){return e})||[]},only:function(e){if(!re(e))throw Error(`React.Children.only expected to receive a single React element child.`);return e}};e.Activity=f,e.Children=de,e.Component=v,e.Fragment=r,e.Profiler=a,e.PureComponent=b,e.StrictMode=i,e.Suspense=l,e.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE=w,e.__COMPILER_RUNTIME={__proto__:null,c:function(e){return w.H.useMemoCache(e)}},e.cache=function(e){return function(){return e.apply(null,arguments)}},e.cacheSignal=function(){return null},e.cloneElement=function(e,t,n){if(e==null)throw Error(`The argument must be a React element, but you passed `+e+`.`);var r=g({},e.props),i=e.key;if(t!=null)for(a in t.key!==void 0&&(i=``+t.key),t)!ee.call(t,a)||a===`key`||a===`__self`||a===`__source`||a===`ref`&&t.ref===void 0||(r[a]=t[a]);var a=arguments.length-2;if(a===1)r.children=n;else if(1<a){for(var o=Array(a),s=0;s<a;s++)o[s]=arguments[s+2];r.children=o}return te(e.type,i,r)},e.createContext=function(e){return e={$$typeof:s,_currentValue:e,_currentValue2:e,_threadCount:0,Provider:null,Consumer:null},e.Provider=e,e.Consumer={$$typeof:o,_context:e},e},e.createElement=function(e,t,n){var r,i={},a=null;if(t!=null)for(r in t.key!==void 0&&(a=``+t.key),t)ee.call(t,r)&&r!==`key`&&r!==`__self`&&r!==`__source`&&(i[r]=t[r]);var o=arguments.length-2;if(o===1)i.children=n;else if(1<o){for(var s=Array(o),c=0;c<o;c++)s[c]=arguments[c+2];i.children=s}if(e&&e.defaultProps)for(r in o=e.defaultProps,o)i[r]===void 0&&(i[r]=o[r]);return te(e,a,i)},e.createRef=function(){return{current:null}},e.forwardRef=function(e){return{$$typeof:c,render:e}},e.isValidElement=re,e.lazy=function(e){return{$$typeof:d,_payload:{_status:-1,_result:e},_init:ue}},e.memo=function(e,t){return{$$typeof:u,type:e,compare:t===void 0?null:t}},e.startTransition=function(e){var t=w.T,n={};w.T=n;try{var r=e(),i=w.S;i!==null&&i(n,r),typeof r==`object`&&r&&typeof r.then==`function`&&r.then(C,T)}catch(e){T(e)}finally{t!==null&&n.types!==null&&(t.types=n.types),w.T=t}},e.unstable_useCacheRefresh=function(){return w.H.useCacheRefresh()},e.use=function(e){return w.H.use(e)},e.useActionState=function(e,t,n){return w.H.useActionState(e,t,n)},e.useCallback=function(e,t){return w.H.useCallback(e,t)},e.useContext=function(e){return w.H.useContext(e)},e.useDebugValue=function(){},e.useDeferredValue=function(e,t){return w.H.useDeferredValue(e,t)},e.useEffect=function(e,t){return w.H.useEffect(e,t)},e.useEffectEvent=function(e){return w.H.useEffectEvent(e)},e.useId=function(){return w.H.useId()},e.useImperativeHandle=function(e,t,n){return w.H.useImperativeHandle(e,t,n)},e.useInsertionEffect=function(e,t){return w.H.useInsertionEffect(e,t)},e.useLayoutEffect=function(e,t){return w.H.useLayoutEffect(e,t)},e.useMemo=function(e,t){return w.H.useMemo(e,t)},e.useOptimistic=function(e,t){return w.H.useOptimistic(e,t)},e.useReducer=function(e,t,n){return w.H.useReducer(e,t,n)},e.useRef=function(e){return w.H.useRef(e)},e.useState=function(e){return w.H.useState(e)},e.useSyncExternalStore=function(e,t,n){return w.H.useSyncExternalStore(e,t,n)},e.useTransition=function(){return w.H.useTransition()},e.version=`19.2.0`})),f=s(((e,t)=>{t.exports=d()})),p=s((e=>{function t(e,t){var n=e.length;e.push(t);a:for(;0<n;){var r=n-1>>>1,a=e[r];if(0<i(a,t))e[r]=t,e[n]=a,n=r;else break a}}function n(e){return e.length===0?null:e[0]}function r(e){if(e.length===0)return null;var t=e[0],n=e.pop();if(n!==t){e[0]=n;a:for(var r=0,a=e.length,o=a>>>1;r<o;){var s=2*(r+1)-1,c=e[s],l=s+1,u=e[l];if(0>i(c,n))l<a&&0>i(u,c)?(e[r]=u,e[l]=n,r=l):(e[r]=c,e[s]=n,r=s);else if(l<a&&0>i(u,n))e[r]=u,e[l]=n,r=l;else break a}}return t}function i(e,t){var n=e.sortIndex-t.sortIndex;return n===0?e.id-t.id:n}if(e.unstable_now=void 0,typeof performance==`object`&&typeof performance.now==`function`){var a=performance;e.unstable_now=function(){return a.now()}}else{var o=Date,s=o.now();e.unstable_now=function(){return o.now()-s}}var c=[],l=[],u=1,d=null,f=3,p=!1,m=!1,h=!1,g=!1,_=typeof setTimeout==`function`?setTimeout:null,v=typeof clearTimeout==`function`?clearTimeout:null,y=typeof setImmediate<`u`?setImmediate:null;function b(e){for(var i=n(l);i!==null;){if(i.callback===null)r(l);else if(i.startTime<=e)r(l),i.sortIndex=i.expirationTime,t(c,i);else break;i=n(l)}}function x(e){if(h=!1,b(e),!m)if(n(c)!==null)m=!0,S||(S=!0,re());else{var t=n(l);t!==null&&oe(x,t.startTime-e)}}var S=!1,C=-1,w=5,ee=-1;function te(){return g?!0:!(e.unstable_now()-ee<w)}function ne(){if(g=!1,S){var t=e.unstable_now();ee=t;var i=!0;try{a:{m=!1,h&&(h=!1,v(C),C=-1),p=!0;var a=f;try{b:{for(b(t),d=n(c);d!==null&&!(d.expirationTime>t&&te());){var o=d.callback;if(typeof o==`function`){d.callback=null,f=d.priorityLevel;var s=o(d.expirationTime<=t);if(t=e.unstable_now(),typeof s==`function`){d.callback=s,b(t),i=!0;break b}d===n(c)&&r(c),b(t)}else r(c);d=n(c)}if(d!==null)i=!0;else{var u=n(l);u!==null&&oe(x,u.startTime-t),i=!1}}break a}finally{d=null,f=a,p=!1}i=void 0}}finally{i?re():S=!1}}}var re;if(typeof y==`function`)re=function(){y(ne)};else if(typeof MessageChannel<`u`){var ie=new MessageChannel,ae=ie.port2;ie.port1.onmessage=ne,re=function(){ae.postMessage(null)}}else re=function(){_(ne,0)};function oe(t,n){C=_(function(){t(e.unstable_now())},n)}e.unstable_IdlePriority=5,e.unstable_ImmediatePriority=1,e.unstable_LowPriority=4,e.unstable_NormalPriority=3,e.unstable_Profiling=null,e.unstable_UserBlockingPriority=2,e.unstable_cancelCallback=function(e){e.callback=null},e.unstable_forceFrameRate=function(e){0>e||125<e?console.error(`forceFrameRate takes a positive int between 0 and 125, forcing frame rates higher than 125 fps is not supported`):w=0<e?Math.floor(1e3/e):5},e.unstable_getCurrentPriorityLevel=function(){return f},e.unstable_next=function(e){switch(f){case 1:case 2:case 3:var t=3;break;default:t=f}var n=f;f=t;try{return e()}finally{f=n}},e.unstable_requestPaint=function(){g=!0},e.unstable_runWithPriority=function(e,t){switch(e){case 1:case 2:case 3:case 4:case 5:break;default:e=3}var n=f;f=e;try{return t()}finally{f=n}},e.unstable_scheduleCallback=function(r,i,a){var o=e.unstable_now();switch(typeof a==`object`&&a?(a=a.delay,a=typeof a==`number`&&0<a?o+a:o):a=o,r){case 1:var s=-1;break;case 2:s=250;break;case 5:s=1073741823;break;case 4:s=1e4;break;default:s=5e3}return s=a+s,r={id:u++,callback:i,priorityLevel:r,startTime:a,expirationTime:s,sortIndex:-1},a>o?(r.sortIndex=a,t(l,r),n(c)===null&&r===n(l)&&(h?(v(C),C=-1):h=!0,oe(x,a-o))):(r.sortIndex=s,t(c,r),m||p||(m=!0,S||(S=!0,re()))),r},e.unstable_shouldYield=te,e.unstable_wrapCallback=function(e){var t=f;return function(){var n=f;f=t;try{return e.apply(this,arguments)}finally{f=n}}}})),m=s(((e,t)=>{t.exports=p()})),h=s((e=>{var t=f();function n(e){var t=`https://react.dev/errors/`+e;if(1<arguments.length){t+=`?args[]=`+encodeURIComponent(arguments[1]);for(var n=2;n<arguments.length;n++)t+=`&args[]=`+encodeURIComponent(arguments[n])}return`Minified React error #`+e+`; visit `+t+` for the full message or use the non-minified dev environment for full errors and additional helpful warnings.`}function r(){}var i={d:{f:r,r:function(){throw Error(n(522))},D:r,C:r,L:r,m:r,X:r,S:r,M:r},p:0,findDOMNode:null},a=Symbol.for(`react.portal`);function o(e,t,n){var r=3<arguments.length&&arguments[3]!==void 0?arguments[3]:null;return{$$typeof:a,key:r==null?null:``+r,children:e,containerInfo:t,implementation:n}}var s=t.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE;function c(e,t){if(e===`font`)return``;if(typeof t==`string`)return t===`use-credentials`?t:``}e.__DOM_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE=i,e.createPortal=function(e,t){var r=2<arguments.length&&arguments[2]!==void 0?arguments[2]:null;if(!t||t.nodeType!==1&&t.nodeType!==9&&t.nodeType!==11)throw Error(n(299));return o(e,t,null,r)},e.flushSync=function(e){var t=s.T,n=i.p;try{if(s.T=null,i.p=2,e)return e()}finally{s.T=t,i.p=n,i.d.f()}},e.preconnect=function(e,t){typeof e==`string`&&(t?(t=t.crossOrigin,t=typeof t==`string`?t===`use-credentials`?t:``:void 0):t=null,i.d.C(e,t))},e.prefetchDNS=function(e){typeof e==`string`&&i.d.D(e)},e.preinit=function(e,t){if(typeof e==`string`&&t&&typeof t.as==`string`){var n=t.as,r=c(n,t.crossOrigin),a=typeof t.integrity==`string`?t.integrity:void 0,o=typeof t.fetchPriority==`string`?t.fetchPriority:void 0;n===`style`?i.d.S(e,typeof t.precedence==`string`?t.precedence:void 0,{crossOrigin:r,integrity:a,fetchPriority:o}):n===`script`&&i.d.X(e,{crossOrigin:r,integrity:a,fetchPriority:o,nonce:typeof t.nonce==`string`?t.nonce:void 0})}},e.preinitModule=function(e,t){if(typeof e==`string`)if(typeof t==`object`&&t){if(t.as==null||t.as===`script`){var n=c(t.as,t.crossOrigin);i.d.M(e,{crossOrigin:n,integrity:typeof t.integrity==`string`?t.integrity:void 0,nonce:typeof t.nonce==`string`?t.nonce:void 0})}}else t??i.d.M(e)},e.preload=function(e,t){if(typeof e==`string`&&typeof t==`object`&&t&&typeof t.as==`string`){var n=t.as,r=c(n,t.crossOrigin);i.d.L(e,n,{crossOrigin:r,integrity:typeof t.integrity==`string`?t.integrity:void 0,nonce:typeof t.nonce==`string`?t.nonce:void 0,type:typeof t.type==`string`?t.type:void 0,fetchPriority:typeof t.fetchPriority==`string`?t.fetchPriority:void 0,referrerPolicy:typeof t.referrerPolicy==`string`?t.referrerPolicy:void 0,imageSrcSet:typeof t.imageSrcSet==`string`?t.imageSrcSet:void 0,imageSizes:typeof t.imageSizes==`string`?t.imageSizes:void 0,media:typeof t.media==`string`?t.media:void 0})}},e.preloadModule=function(e,t){if(typeof e==`string`)if(t){var n=c(t.as,t.crossOrigin);i.d.m(e,{as:typeof t.as==`string`&&t.as!==`script`?t.as:void 0,crossOrigin:n,integrity:typeof t.integrity==`string`?t.integrity:void 0})}else i.d.m(e)},e.requestFormReset=function(e){i.d.r(e)},e.unstable_batchedUpdates=function(e,t){return e(t)},e.useFormState=function(e,t,n){return s.H.useFormState(e,t,n)},e.useFormStatus=function(){return s.H.useHostTransitionStatus()},e.version=`19.2.0`})),g=s(((e,t)=>{function n(){if(!(typeof __REACT_DEVTOOLS_GLOBAL_HOOK__>`u`||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!=`function`))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(n)}catch(e){console.error(e)}}n(),t.exports=h()})),_=s((e=>{var t=m(),n=f(),r=g();function i(e){var t=`https://react.dev/errors/`+e;if(1<arguments.length){t+=`?args[]=`+encodeURIComponent(arguments[1]);for(var n=2;n<arguments.length;n++)t+=`&args[]=`+encodeURIComponent(arguments[n])}return`Minified React error #`+e+`; visit `+t+` for the full message or use the non-minified dev environment for full errors and additional helpful warnings.`}function a(e){return!(!e||e.nodeType!==1&&e.nodeType!==9&&e.nodeType!==11)}function o(e){var t=e,n=e;if(e.alternate)for(;t.return;)t=t.return;else{e=t;do t=e,t.flags&4098&&(n=t.return),e=t.return;while(e)}return t.tag===3?n:null}function s(e){if(e.tag===13){var t=e.memoizedState;if(t===null&&(e=e.alternate,e!==null&&(t=e.memoizedState)),t!==null)return t.dehydrated}return null}function c(e){if(e.tag===31){var t=e.memoizedState;if(t===null&&(e=e.alternate,e!==null&&(t=e.memoizedState)),t!==null)return t.dehydrated}return null}function l(e){if(o(e)!==e)throw Error(i(188))}function u(e){var t=e.alternate;if(!t){if(t=o(e),t===null)throw Error(i(188));return t===e?e:null}for(var n=e,r=t;;){var a=n.return;if(a===null)break;var s=a.alternate;if(s===null){if(r=a.return,r!==null){n=r;continue}break}if(a.child===s.child){for(s=a.child;s;){if(s===n)return l(a),e;if(s===r)return l(a),t;s=s.sibling}throw Error(i(188))}if(n.return!==r.return)n=a,r=s;else{for(var c=!1,u=a.child;u;){if(u===n){c=!0,n=a,r=s;break}if(u===r){c=!0,r=a,n=s;break}u=u.sibling}if(!c){for(u=s.child;u;){if(u===n){c=!0,n=s,r=a;break}if(u===r){c=!0,r=s,n=a;break}u=u.sibling}if(!c)throw Error(i(189))}}if(n.alternate!==r)throw Error(i(190))}if(n.tag!==3)throw Error(i(188));return n.stateNode.current===n?e:t}function d(e){var t=e.tag;if(t===5||t===26||t===27||t===6)return e;for(e=e.child;e!==null;){if(t=d(e),t!==null)return t;e=e.sibling}return null}var p=Object.assign,h=Symbol.for(`react.element`),_=Symbol.for(`react.transitional.element`),v=Symbol.for(`react.portal`),y=Symbol.for(`react.fragment`),b=Symbol.for(`react.strict_mode`),x=Symbol.for(`react.profiler`),S=Symbol.for(`react.consumer`),C=Symbol.for(`react.context`),w=Symbol.for(`react.forward_ref`),ee=Symbol.for(`react.suspense`),te=Symbol.for(`react.suspense_list`),ne=Symbol.for(`react.memo`),re=Symbol.for(`react.lazy`),ie=Symbol.for(`react.activity`),ae=Symbol.for(`react.memo_cache_sentinel`),oe=Symbol.iterator;function se(e){return typeof e!=`object`||!e?null:(e=oe&&e[oe]||e[`@@iterator`],typeof e==`function`?e:null)}var ce=Symbol.for(`react.client.reference`);function le(e){if(e==null)return null;if(typeof e==`function`)return e.$$typeof===ce?null:e.displayName||e.name||null;if(typeof e==`string`)return e;switch(e){case y:return`Fragment`;case x:return`Profiler`;case b:return`StrictMode`;case ee:return`Suspense`;case te:return`SuspenseList`;case ie:return`Activity`}if(typeof e==`object`)switch(e.$$typeof){case v:return`Portal`;case C:return e.displayName||`Context`;case S:return(e._context.displayName||`Context`)+`.Consumer`;case w:var t=e.render;return e=e.displayName,e||=(e=t.displayName||t.name||``,e===``?`ForwardRef`:`ForwardRef(`+e+`)`),e;case ne:return t=e.displayName||null,t===null?le(e.type)||`Memo`:t;case re:t=e._payload,e=e._init;try{return le(e(t))}catch{}}return null}var ue=Array.isArray,T=n.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,de=r.__DOM_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,fe={pending:!1,data:null,method:null,action:null},pe=[],me=-1;function he(e){return{current:e}}function ge(e){0>me||(e.current=pe[me],pe[me]=null,me--)}function _e(e,t){me++,pe[me]=e.current,e.current=t}var ve=he(null),ye=he(null),be=he(null),xe=he(null);function Se(e,t){switch(_e(be,t),_e(ye,e),_e(ve,null),t.nodeType){case 9:case 11:e=(e=t.documentElement)&&(e=e.namespaceURI)?Sf(e):0;break;default:if(e=t.tagName,t=t.namespaceURI)t=Sf(t),e=Cf(t,e);else switch(e){case`svg`:e=1;break;case`math`:e=2;break;default:e=0}}ge(ve),_e(ve,e)}function Ce(){ge(ve),ge(ye),ge(be)}function we(e){e.memoizedState!==null&&_e(xe,e);var t=ve.current,n=Cf(t,e.type);t!==n&&(_e(ye,e),_e(ve,n))}function Te(e){ye.current===e&&(ge(ve),ge(ye)),xe.current===e&&(ge(xe),jp._currentValue=fe)}var Ee,De;function Oe(e){if(Ee===void 0)try{throw Error()}catch(e){var t=e.stack.trim().match(/\\n( *(at )?)/);Ee=t&&t[1]||``,De=-1<e.stack.indexOf(`\n    at`)?` (<anonymous>)`:-1<e.stack.indexOf(`@`)?`@unknown:0:0`:``}return`\n`+Ee+e+De}var ke=!1;function Ae(e,t){if(!e||ke)return``;ke=!0;var n=Error.prepareStackTrace;Error.prepareStackTrace=void 0;try{var r={DetermineComponentFrameRoot:function(){try{if(t){var n=function(){throw Error()};if(Object.defineProperty(n.prototype,`props`,{set:function(){throw Error()}}),typeof Reflect==`object`&&Reflect.construct){try{Reflect.construct(n,[])}catch(e){var r=e}Reflect.construct(e,[],n)}else{try{n.call()}catch(e){r=e}e.call(n.prototype)}}else{try{throw Error()}catch(e){r=e}(n=e())&&typeof n.catch==`function`&&n.catch(function(){})}}catch(e){if(e&&r&&typeof e.stack==`string`)return[e.stack,r.stack]}return[null,null]}};r.DetermineComponentFrameRoot.displayName=`DetermineComponentFrameRoot`;var i=Object.getOwnPropertyDescriptor(r.DetermineComponentFrameRoot,`name`);i&&i.configurable&&Object.defineProperty(r.DetermineComponentFrameRoot,`name`,{value:`DetermineComponentFrameRoot`});var a=r.DetermineComponentFrameRoot(),o=a[0],s=a[1];if(o&&s){var c=o.split(`\n`),l=s.split(`\n`);for(i=r=0;r<c.length&&!c[r].includes(`DetermineComponentFrameRoot`);)r++;for(;i<l.length&&!l[i].includes(`DetermineComponentFrameRoot`);)i++;if(r===c.length||i===l.length)for(r=c.length-1,i=l.length-1;1<=r&&0<=i&&c[r]!==l[i];)i--;for(;1<=r&&0<=i;r--,i--)if(c[r]!==l[i]){if(r!==1||i!==1)do if(r--,i--,0>i||c[r]!==l[i]){var u=`\n`+c[r].replace(` at new `,` at `);return e.displayName&&u.includes(`<anonymous>`)&&(u=u.replace(`<anonymous>`,e.displayName)),u}while(1<=r&&0<=i);break}}}finally{ke=!1,Error.prepareStackTrace=n}return(n=e?e.displayName||e.name:``)?Oe(n):``}function je(e,t){switch(e.tag){case 26:case 27:case 5:return Oe(e.type);case 16:return Oe(`Lazy`);case 13:return e.child!==t&&t!==null?Oe(`Suspense Fallback`):Oe(`Suspense`);case 19:return Oe(`SuspenseList`);case 0:case 15:return Ae(e.type,!1);case 11:return Ae(e.type.render,!1);case 1:return Ae(e.type,!0);case 31:return Oe(`Activity`);default:return``}}function Me(e){try{var t=``,n=null;do t+=je(e,n),n=e,e=e.return;while(e);return t}catch(e){return`\nError generating stack: `+e.message+`\n`+e.stack}}var Ne=Object.prototype.hasOwnProperty,Pe=t.unstable_scheduleCallback,Fe=t.unstable_cancelCallback,Ie=t.unstable_shouldYield,Le=t.unstable_requestPaint,Re=t.unstable_now,ze=t.unstable_getCurrentPriorityLevel,Be=t.unstable_ImmediatePriority,Ve=t.unstable_UserBlockingPriority,He=t.unstable_NormalPriority,Ue=t.unstable_LowPriority,We=t.unstable_IdlePriority,Ge=t.log,Ke=t.unstable_setDisableYieldValue,qe=null,Je=null;function Ye(e){if(typeof Ge==`function`&&Ke(e),Je&&typeof Je.setStrictMode==`function`)try{Je.setStrictMode(qe,e)}catch{}}var Xe=Math.clz32?Math.clz32:$e,Ze=Math.log,Qe=Math.LN2;function $e(e){return e>>>=0,e===0?32:31-(Ze(e)/Qe|0)|0}var et=256,tt=262144,nt=4194304;function rt(e){var t=e&42;if(t!==0)return t;switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:return 64;case 128:return 128;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:return e&261888;case 262144:case 524288:case 1048576:case 2097152:return e&3932160;case 4194304:case 8388608:case 16777216:case 33554432:return e&62914560;case 67108864:return 67108864;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 0;default:return e}}function it(e,t,n){var r=e.pendingLanes;if(r===0)return 0;var i=0,a=e.suspendedLanes,o=e.pingedLanes;e=e.warmLanes;var s=r&134217727;return s===0?(s=r&~a,s===0?o===0?n||(n=r&~e,n!==0&&(i=rt(n))):i=rt(o):i=rt(s)):(r=s&~a,r===0?(o&=s,o===0?n||(n=s&~e,n!==0&&(i=rt(n))):i=rt(o)):i=rt(r)),i===0?0:t!==0&&t!==i&&(t&a)===0&&(a=i&-i,n=t&-t,a>=n||a===32&&n&4194048)?t:i}function at(e,t){return(e.pendingLanes&~(e.suspendedLanes&~e.pingedLanes)&t)===0}function ot(e,t){switch(e){case 1:case 2:case 4:case 8:case 64:return t+250;case 16:case 32:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return t+5e3;case 4194304:case 8388608:case 16777216:case 33554432:return-1;case 67108864:case 134217728:case 268435456:case 536870912:case 1073741824:return-1;default:return-1}}function st(){var e=nt;return nt<<=1,!(nt&62914560)&&(nt=4194304),e}function ct(e){for(var t=[],n=0;31>n;n++)t.push(e);return t}function lt(e,t){e.pendingLanes|=t,t!==268435456&&(e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0)}function ut(e,t,n,r,i,a){var o=e.pendingLanes;e.pendingLanes=n,e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0,e.expiredLanes&=n,e.entangledLanes&=n,e.errorRecoveryDisabledLanes&=n,e.shellSuspendCounter=0;var s=e.entanglements,c=e.expirationTimes,l=e.hiddenUpdates;for(n=o&~n;0<n;){var u=31-Xe(n),d=1<<u;s[u]=0,c[u]=-1;var f=l[u];if(f!==null)for(l[u]=null,u=0;u<f.length;u++){var p=f[u];p!==null&&(p.lane&=-536870913)}n&=~d}r!==0&&dt(e,r,0),a!==0&&i===0&&e.tag!==0&&(e.suspendedLanes|=a&~(o&~t))}function dt(e,t,n){e.pendingLanes|=t,e.suspendedLanes&=~t;var r=31-Xe(t);e.entangledLanes|=t,e.entanglements[r]=e.entanglements[r]|1073741824|n&261930}function ft(e,t){var n=e.entangledLanes|=t;for(e=e.entanglements;n;){var r=31-Xe(n),i=1<<r;i&t|e[r]&t&&(e[r]|=t),n&=~i}}function pt(e,t){var n=t&-t;return n=n&42?1:mt(n),(n&(e.suspendedLanes|t))===0?n:0}function mt(e){switch(e){case 2:e=1;break;case 8:e=4;break;case 32:e=16;break;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:case 4194304:case 8388608:case 16777216:case 33554432:e=128;break;case 268435456:e=134217728;break;default:e=0}return e}function ht(e){return e&=-e,2<e?8<e?e&134217727?32:268435456:8:2}function gt(){var e=de.p;return e===0?(e=window.event,e===void 0?32:qp(e.type)):e}function _t(e,t){var n=de.p;try{return de.p=e,t()}finally{de.p=n}}var vt=Math.random().toString(36).slice(2),yt=`__reactFiber$`+vt,bt=`__reactProps$`+vt,xt=`__reactContainer$`+vt,St=`__reactEvents$`+vt,Ct=`__reactListeners$`+vt,wt=`__reactHandles$`+vt,Tt=`__reactResources$`+vt,Et=`__reactMarker$`+vt;function Dt(e){delete e[yt],delete e[bt],delete e[St],delete e[Ct],delete e[wt]}function Ot(e){var t=e[yt];if(t)return t;for(var n=e.parentNode;n;){if(t=n[xt]||n[yt]){if(n=t.alternate,t.child!==null||n!==null&&n.child!==null)for(e=Wf(e);e!==null;){if(n=e[yt])return n;e=Wf(e)}return t}e=n,n=e.parentNode}return null}function E(e){if(e=e[yt]||e[xt]){var t=e.tag;if(t===5||t===6||t===13||t===31||t===26||t===27||t===3)return e}return null}function kt(e){var t=e.tag;if(t===5||t===26||t===27||t===6)return e.stateNode;throw Error(i(33))}function At(e){var t=e[Tt];return t||=e[Tt]={hoistableStyles:new Map,hoistableScripts:new Map},t}function jt(e){e[Et]=!0}var Mt=new Set,Nt={};function Pt(e,t){Ft(e,t),Ft(e+`Capture`,t)}function Ft(e,t){for(Nt[e]=t,e=0;e<t.length;e++)Mt.add(t[e])}var It=RegExp(`^[:A-Z_a-z\\\\u00C0-\\\\u00D6\\\\u00D8-\\\\u00F6\\\\u00F8-\\\\u02FF\\\\u0370-\\\\u037D\\\\u037F-\\\\u1FFF\\\\u200C-\\\\u200D\\\\u2070-\\\\u218F\\\\u2C00-\\\\u2FEF\\\\u3001-\\\\uD7FF\\\\uF900-\\\\uFDCF\\\\uFDF0-\\\\uFFFD][:A-Z_a-z\\\\u00C0-\\\\u00D6\\\\u00D8-\\\\u00F6\\\\u00F8-\\\\u02FF\\\\u0370-\\\\u037D\\\\u037F-\\\\u1FFF\\\\u200C-\\\\u200D\\\\u2070-\\\\u218F\\\\u2C00-\\\\u2FEF\\\\u3001-\\\\uD7FF\\\\uF900-\\\\uFDCF\\\\uFDF0-\\\\uFFFD\\\\-.0-9\\\\u00B7\\\\u0300-\\\\u036F\\\\u203F-\\\\u2040]*$`),Lt={},Rt={};function zt(e){return Ne.call(Rt,e)?!0:Ne.call(Lt,e)?!1:It.test(e)?Rt[e]=!0:(Lt[e]=!0,!1)}function Bt(e,t,n){if(zt(t))if(n===null)e.removeAttribute(t);else{switch(typeof n){case`undefined`:case`function`:case`symbol`:e.removeAttribute(t);return;case`boolean`:var r=t.toLowerCase().slice(0,5);if(r!==`data-`&&r!==`aria-`){e.removeAttribute(t);return}}e.setAttribute(t,``+n)}}function D(e,t,n){if(n===null)e.removeAttribute(t);else{switch(typeof n){case`undefined`:case`function`:case`symbol`:case`boolean`:e.removeAttribute(t);return}e.setAttribute(t,``+n)}}function O(e,t,n,r){if(r===null)e.removeAttribute(n);else{switch(typeof r){case`undefined`:case`function`:case`symbol`:case`boolean`:e.removeAttribute(n);return}e.setAttributeNS(t,n,``+r)}}function Vt(e){switch(typeof e){case`bigint`:case`boolean`:case`number`:case`string`:case`undefined`:return e;case`object`:return e;default:return``}}function Ht(e){var t=e.type;return(e=e.nodeName)&&e.toLowerCase()===`input`&&(t===`checkbox`||t===`radio`)}function Ut(e,t,n){var r=Object.getOwnPropertyDescriptor(e.constructor.prototype,t);if(!e.hasOwnProperty(t)&&r!==void 0&&typeof r.get==`function`&&typeof r.set==`function`){var i=r.get,a=r.set;return Object.defineProperty(e,t,{configurable:!0,get:function(){return i.call(this)},set:function(e){n=``+e,a.call(this,e)}}),Object.defineProperty(e,t,{enumerable:r.enumerable}),{getValue:function(){return n},setValue:function(e){n=``+e},stopTracking:function(){e._valueTracker=null,delete e[t]}}}}function Wt(e){if(!e._valueTracker){var t=Ht(e)?`checked`:`value`;e._valueTracker=Ut(e,t,``+e[t])}}function Gt(e){if(!e)return!1;var t=e._valueTracker;if(!t)return!0;var n=t.getValue(),r=``;return e&&(r=Ht(e)?e.checked?`true`:`false`:e.value),e=r,e===n?!1:(t.setValue(e),!0)}function Kt(e){if(e||=typeof document<`u`?document:void 0,e===void 0)return null;try{return e.activeElement||e.body}catch{return e.body}}var qt=/[\\n\"\\\\]/g;function Jt(e){return e.replace(qt,function(e){return`\\\\`+e.charCodeAt(0).toString(16)+` `})}function Yt(e,t,n,r,i,a,o,s){e.name=``,o!=null&&typeof o!=`function`&&typeof o!=`symbol`&&typeof o!=`boolean`?e.type=o:e.removeAttribute(`type`),t==null?o!==`submit`&&o!==`reset`||e.removeAttribute(`value`):o===`number`?(t===0&&e.value===``||e.value!=t)&&(e.value=``+Vt(t)):e.value!==``+Vt(t)&&(e.value=``+Vt(t)),t==null?n==null?r!=null&&e.removeAttribute(`value`):Zt(e,o,Vt(n)):Zt(e,o,Vt(t)),i==null&&a!=null&&(e.defaultChecked=!!a),i!=null&&(e.checked=i&&typeof i!=`function`&&typeof i!=`symbol`),s!=null&&typeof s!=`function`&&typeof s!=`symbol`&&typeof s!=`boolean`?e.name=``+Vt(s):e.removeAttribute(`name`)}function Xt(e,t,n,r,i,a,o,s){if(a!=null&&typeof a!=`function`&&typeof a!=`symbol`&&typeof a!=`boolean`&&(e.type=a),t!=null||n!=null){if(!(a!==`submit`&&a!==`reset`||t!=null)){Wt(e);return}n=n==null?``:``+Vt(n),t=t==null?n:``+Vt(t),s||t===e.value||(e.value=t),e.defaultValue=t}r??=i,r=typeof r!=`function`&&typeof r!=`symbol`&&!!r,e.checked=s?e.checked:!!r,e.defaultChecked=!!r,o!=null&&typeof o!=`function`&&typeof o!=`symbol`&&typeof o!=`boolean`&&(e.name=o),Wt(e)}function Zt(e,t,n){t===`number`&&Kt(e.ownerDocument)===e||e.defaultValue===``+n||(e.defaultValue=``+n)}function Qt(e,t,n,r){if(e=e.options,t){t={};for(var i=0;i<n.length;i++)t[`$`+n[i]]=!0;for(n=0;n<e.length;n++)i=t.hasOwnProperty(`$`+e[n].value),e[n].selected!==i&&(e[n].selected=i),i&&r&&(e[n].defaultSelected=!0)}else{for(n=``+Vt(n),t=null,i=0;i<e.length;i++){if(e[i].value===n){e[i].selected=!0,r&&(e[i].defaultSelected=!0);return}t!==null||e[i].disabled||(t=e[i])}t!==null&&(t.selected=!0)}}function $t(e,t,n){if(t!=null&&(t=``+Vt(t),t!==e.value&&(e.value=t),n==null)){e.defaultValue!==t&&(e.defaultValue=t);return}e.defaultValue=n==null?``:``+Vt(n)}function en(e,t,n,r){if(t==null){if(r!=null){if(n!=null)throw Error(i(92));if(ue(r)){if(1<r.length)throw Error(i(93));r=r[0]}n=r}n??=``,t=n}n=Vt(t),e.defaultValue=n,r=e.textContent,r===n&&r!==``&&r!==null&&(e.value=r),Wt(e)}function tn(e,t){if(t){var n=e.firstChild;if(n&&n===e.lastChild&&n.nodeType===3){n.nodeValue=t;return}}e.textContent=t}var nn=new Set(`animationIterationCount aspectRatio borderImageOutset borderImageSlice borderImageWidth boxFlex boxFlexGroup boxOrdinalGroup columnCount columns flex flexGrow flexPositive flexShrink flexNegative flexOrder gridArea gridRow gridRowEnd gridRowSpan gridRowStart gridColumn gridColumnEnd gridColumnSpan gridColumnStart fontWeight lineClamp lineHeight opacity order orphans scale tabSize widows zIndex zoom fillOpacity floodOpacity stopOpacity strokeDasharray strokeDashoffset strokeMiterlimit strokeOpacity strokeWidth MozAnimationIterationCount MozBoxFlex MozBoxFlexGroup MozLineClamp msAnimationIterationCount msFlex msZoom msFlexGrow msFlexNegative msFlexOrder msFlexPositive msFlexShrink msGridColumn msGridColumnSpan msGridRow msGridRowSpan WebkitAnimationIterationCount WebkitBoxFlex WebKitBoxFlexGroup WebkitBoxOrdinalGroup WebkitColumnCount WebkitColumns WebkitFlex WebkitFlexGrow WebkitFlexPositive WebkitFlexShrink WebkitLineClamp`.split(` `));function rn(e,t,n){var r=t.indexOf(`--`)===0;n==null||typeof n==`boolean`||n===``?r?e.setProperty(t,``):t===`float`?e.cssFloat=``:e[t]=``:r?e.setProperty(t,n):typeof n!=`number`||n===0||nn.has(t)?t===`float`?e.cssFloat=n:e[t]=(``+n).trim():e[t]=n+`px`}function an(e,t,n){if(t!=null&&typeof t!=`object`)throw Error(i(62));if(e=e.style,n!=null){for(var r in n)!n.hasOwnProperty(r)||t!=null&&t.hasOwnProperty(r)||(r.indexOf(`--`)===0?e.setProperty(r,``):r===`float`?e.cssFloat=``:e[r]=``);for(var a in t)r=t[a],t.hasOwnProperty(a)&&n[a]!==r&&rn(e,a,r)}else for(var o in t)t.hasOwnProperty(o)&&rn(e,o,t[o])}function on(e){if(e.indexOf(`-`)===-1)return!1;switch(e){case`annotation-xml`:case`color-profile`:case`font-face`:case`font-face-src`:case`font-face-uri`:case`font-face-format`:case`font-face-name`:case`missing-glyph`:return!1;default:return!0}}var sn=new Map([[`acceptCharset`,`accept-charset`],[`htmlFor`,`for`],[`httpEquiv`,`http-equiv`],[`crossOrigin`,`crossorigin`],[`accentHeight`,`accent-height`],[`alignmentBaseline`,`alignment-baseline`],[`arabicForm`,`arabic-form`],[`baselineShift`,`baseline-shift`],[`capHeight`,`cap-height`],[`clipPath`,`clip-path`],[`clipRule`,`clip-rule`],[`colorInterpolation`,`color-interpolation`],[`colorInterpolationFilters`,`color-interpolation-filters`],[`colorProfile`,`color-profile`],[`colorRendering`,`color-rendering`],[`dominantBaseline`,`dominant-baseline`],[`enableBackground`,`enable-background`],[`fillOpacity`,`fill-opacity`],[`fillRule`,`fill-rule`],[`floodColor`,`flood-color`],[`floodOpacity`,`flood-opacity`],[`fontFamily`,`font-family`],[`fontSize`,`font-size`],[`fontSizeAdjust`,`font-size-adjust`],[`fontStretch`,`font-stretch`],[`fontStyle`,`font-style`],[`fontVariant`,`font-variant`],[`fontWeight`,`font-weight`],[`glyphName`,`glyph-name`],[`glyphOrientationHorizontal`,`glyph-orientation-horizontal`],[`glyphOrientationVertical`,`glyph-orientation-vertical`],[`horizAdvX`,`horiz-adv-x`],[`horizOriginX`,`horiz-origin-x`],[`imageRendering`,`image-rendering`],[`letterSpacing`,`letter-spacing`],[`lightingColor`,`lighting-color`],[`markerEnd`,`marker-end`],[`markerMid`,`marker-mid`],[`markerStart`,`marker-start`],[`overlinePosition`,`overline-position`],[`overlineThickness`,`overline-thickness`],[`paintOrder`,`paint-order`],[`panose-1`,`panose-1`],[`pointerEvents`,`pointer-events`],[`renderingIntent`,`rendering-intent`],[`shapeRendering`,`shape-rendering`],[`stopColor`,`stop-color`],[`stopOpacity`,`stop-opacity`],[`strikethroughPosition`,`strikethrough-position`],[`strikethroughThickness`,`strikethrough-thickness`],[`strokeDasharray`,`stroke-dasharray`],[`strokeDashoffset`,`stroke-dashoffset`],[`strokeLinecap`,`stroke-linecap`],[`strokeLinejoin`,`stroke-linejoin`],[`strokeMiterlimit`,`stroke-miterlimit`],[`strokeOpacity`,`stroke-opacity`],[`strokeWidth`,`stroke-width`],[`textAnchor`,`text-anchor`],[`textDecoration`,`text-decoration`],[`textRendering`,`text-rendering`],[`transformOrigin`,`transform-origin`],[`underlinePosition`,`underline-position`],[`underlineThickness`,`underline-thickness`],[`unicodeBidi`,`unicode-bidi`],[`unicodeRange`,`unicode-range`],[`unitsPerEm`,`units-per-em`],[`vAlphabetic`,`v-alphabetic`],[`vHanging`,`v-hanging`],[`vIdeographic`,`v-ideographic`],[`vMathematical`,`v-mathematical`],[`vectorEffect`,`vector-effect`],[`vertAdvY`,`vert-adv-y`],[`vertOriginX`,`vert-origin-x`],[`vertOriginY`,`vert-origin-y`],[`wordSpacing`,`word-spacing`],[`writingMode`,`writing-mode`],[`xmlnsXlink`,`xmlns:xlink`],[`xHeight`,`x-height`]]),cn=/^[\\u0000-\\u001F ]*j[\\r\\n\\t]*a[\\r\\n\\t]*v[\\r\\n\\t]*a[\\r\\n\\t]*s[\\r\\n\\t]*c[\\r\\n\\t]*r[\\r\\n\\t]*i[\\r\\n\\t]*p[\\r\\n\\t]*t[\\r\\n\\t]*:/i;function ln(e){return cn.test(``+e)?`javascript:throw new Error('React has blocked a javascript: URL as a security precaution.')`:e}function un(){}var dn=null;function fn(e){return e=e.target||e.srcElement||window,e.correspondingUseElement&&(e=e.correspondingUseElement),e.nodeType===3?e.parentNode:e}var pn=null,mn=null;function hn(e){var t=E(e);if(t&&(e=t.stateNode)){var n=e[bt]||null;a:switch(e=t.stateNode,t.type){case`input`:if(Yt(e,n.value,n.defaultValue,n.defaultValue,n.checked,n.defaultChecked,n.type,n.name),t=n.name,n.type===`radio`&&t!=null){for(n=e;n.parentNode;)n=n.parentNode;for(n=n.querySelectorAll(`input[name=\"`+Jt(``+t)+`\"][type=\"radio\"]`),t=0;t<n.length;t++){var r=n[t];if(r!==e&&r.form===e.form){var a=r[bt]||null;if(!a)throw Error(i(90));Yt(r,a.value,a.defaultValue,a.defaultValue,a.checked,a.defaultChecked,a.type,a.name)}}for(t=0;t<n.length;t++)r=n[t],r.form===e.form&&Gt(r)}break a;case`textarea`:$t(e,n.value,n.defaultValue);break a;case`select`:t=n.value,t!=null&&Qt(e,!!n.multiple,t,!1)}}}var gn=!1;function _n(e,t,n){if(gn)return e(t,n);gn=!0;try{return e(t)}finally{if(gn=!1,(pn!==null||mn!==null)&&(Xu(),pn&&(t=pn,e=mn,mn=pn=null,hn(t),e)))for(t=0;t<e.length;t++)hn(e[t])}}function vn(e,t){var n=e.stateNode;if(n===null)return null;var r=n[bt]||null;if(r===null)return null;n=r[t];a:switch(t){case`onClick`:case`onClickCapture`:case`onDoubleClick`:case`onDoubleClickCapture`:case`onMouseDown`:case`onMouseDownCapture`:case`onMouseMove`:case`onMouseMoveCapture`:case`onMouseUp`:case`onMouseUpCapture`:case`onMouseEnter`:(r=!r.disabled)||(e=e.type,r=!(e===`button`||e===`input`||e===`select`||e===`textarea`)),e=!r;break a;default:e=!1}if(e)return null;if(n&&typeof n!=`function`)throw Error(i(231,t,typeof n));return n}var yn=!(typeof window>`u`||window.document===void 0||window.document.createElement===void 0),bn=!1;if(yn)try{var xn={};Object.defineProperty(xn,`passive`,{get:function(){bn=!0}}),window.addEventListener(`test`,xn,xn),window.removeEventListener(`test`,xn,xn)}catch{bn=!1}var Sn=null,Cn=null,wn=null;function Tn(){if(wn)return wn;var e,t=Cn,n=t.length,r,i=`value`in Sn?Sn.value:Sn.textContent,a=i.length;for(e=0;e<n&&t[e]===i[e];e++);var o=n-e;for(r=1;r<=o&&t[n-r]===i[a-r];r++);return wn=i.slice(e,1<r?1-r:void 0)}function En(e){var t=e.keyCode;return`charCode`in e?(e=e.charCode,e===0&&t===13&&(e=13)):e=t,e===10&&(e=13),32<=e||e===13?e:0}function Dn(){return!0}function On(){return!1}function kn(e){function t(t,n,r,i,a){for(var o in this._reactName=t,this._targetInst=r,this.type=n,this.nativeEvent=i,this.target=a,this.currentTarget=null,e)e.hasOwnProperty(o)&&(t=e[o],this[o]=t?t(i):i[o]);return this.isDefaultPrevented=(i.defaultPrevented==null?!1===i.returnValue:i.defaultPrevented)?Dn:On,this.isPropagationStopped=On,this}return p(t.prototype,{preventDefault:function(){this.defaultPrevented=!0;var e=this.nativeEvent;e&&(e.preventDefault?e.preventDefault():typeof e.returnValue!=`unknown`&&(e.returnValue=!1),this.isDefaultPrevented=Dn)},stopPropagation:function(){var e=this.nativeEvent;e&&(e.stopPropagation?e.stopPropagation():typeof e.cancelBubble!=`unknown`&&(e.cancelBubble=!0),this.isPropagationStopped=Dn)},persist:function(){},isPersistent:Dn}),t}var An={eventPhase:0,bubbles:0,cancelable:0,timeStamp:function(e){return e.timeStamp||Date.now()},defaultPrevented:0,isTrusted:0},k=kn(An),jn=p({},An,{view:0,detail:0}),Mn=kn(jn),Nn,A,Pn,Fn=p({},jn,{screenX:0,screenY:0,clientX:0,clientY:0,pageX:0,pageY:0,ctrlKey:0,shiftKey:0,altKey:0,metaKey:0,getModifierState:Zn,button:0,buttons:0,relatedTarget:function(e){return e.relatedTarget===void 0?e.fromElement===e.srcElement?e.toElement:e.fromElement:e.relatedTarget},movementX:function(e){return`movementX`in e?e.movementX:(e!==Pn&&(Pn&&e.type===`mousemove`?(Nn=e.screenX-Pn.screenX,A=e.screenY-Pn.screenY):A=Nn=0,Pn=e),Nn)},movementY:function(e){return`movementY`in e?e.movementY:A}}),In=kn(Fn),Ln=p({},Fn,{dataTransfer:0}),Rn=kn(Ln),zn=p({},jn,{relatedTarget:0}),Bn=kn(zn),Vn=p({},An,{animationName:0,elapsedTime:0,pseudoElement:0}),Hn=kn(Vn),Un=p({},An,{clipboardData:function(e){return`clipboardData`in e?e.clipboardData:window.clipboardData}}),Wn=kn(Un),Gn=p({},An,{data:0}),Kn=kn(Gn),qn={Esc:`Escape`,Spacebar:` `,Left:`ArrowLeft`,Up:`ArrowUp`,Right:`ArrowRight`,Down:`ArrowDown`,Del:`Delete`,Win:`OS`,Menu:`ContextMenu`,Apps:`ContextMenu`,Scroll:`ScrollLock`,MozPrintableKey:`Unidentified`},Jn={8:`Backspace`,9:`Tab`,12:`Clear`,13:`Enter`,16:`Shift`,17:`Control`,18:`Alt`,19:`Pause`,20:`CapsLock`,27:`Escape`,32:` `,33:`PageUp`,34:`PageDown`,35:`End`,36:`Home`,37:`ArrowLeft`,38:`ArrowUp`,39:`ArrowRight`,40:`ArrowDown`,45:`Insert`,46:`Delete`,112:`F1`,113:`F2`,114:`F3`,115:`F4`,116:`F5`,117:`F6`,118:`F7`,119:`F8`,120:`F9`,121:`F10`,122:`F11`,123:`F12`,144:`NumLock`,145:`ScrollLock`,224:`Meta`},Yn={Alt:`altKey`,Control:`ctrlKey`,Meta:`metaKey`,Shift:`shiftKey`};function Xn(e){var t=this.nativeEvent;return t.getModifierState?t.getModifierState(e):(e=Yn[e])?!!t[e]:!1}function Zn(){return Xn}var Qn=p({},jn,{key:function(e){if(e.key){var t=qn[e.key]||e.key;if(t!==`Unidentified`)return t}return e.type===`keypress`?(e=En(e),e===13?`Enter`:String.fromCharCode(e)):e.type===`keydown`||e.type===`keyup`?Jn[e.keyCode]||`Unidentified`:``},code:0,location:0,ctrlKey:0,shiftKey:0,altKey:0,metaKey:0,repeat:0,locale:0,getModifierState:Zn,charCode:function(e){return e.type===`keypress`?En(e):0},keyCode:function(e){return e.type===`keydown`||e.type===`keyup`?e.keyCode:0},which:function(e){return e.type===`keypress`?En(e):e.type===`keydown`||e.type===`keyup`?e.keyCode:0}}),$n=kn(Qn),er=p({},Fn,{pointerId:0,width:0,height:0,pressure:0,tangentialPressure:0,tiltX:0,tiltY:0,twist:0,pointerType:0,isPrimary:0}),tr=kn(er),nr=p({},jn,{touches:0,targetTouches:0,changedTouches:0,altKey:0,metaKey:0,ctrlKey:0,shiftKey:0,getModifierState:Zn}),rr=kn(nr),ir=p({},An,{propertyName:0,elapsedTime:0,pseudoElement:0}),ar=kn(ir),or=p({},Fn,{deltaX:function(e){return`deltaX`in e?e.deltaX:`wheelDeltaX`in e?-e.wheelDeltaX:0},deltaY:function(e){return`deltaY`in e?e.deltaY:`wheelDeltaY`in e?-e.wheelDeltaY:`wheelDelta`in e?-e.wheelDelta:0},deltaZ:0,deltaMode:0}),sr=kn(or),cr=p({},An,{newState:0,oldState:0}),lr=kn(cr),ur=[9,13,27,32],dr=yn&&`CompositionEvent`in window,fr=null;yn&&`documentMode`in document&&(fr=document.documentMode);var pr=yn&&`TextEvent`in window&&!fr,mr=yn&&(!dr||fr&&8<fr&&11>=fr),hr=` `,gr=!1;function _r(e,t){switch(e){case`keyup`:return ur.indexOf(t.keyCode)!==-1;case`keydown`:return t.keyCode!==229;case`keypress`:case`mousedown`:case`focusout`:return!0;default:return!1}}function vr(e){return e=e.detail,typeof e==`object`&&`data`in e?e.data:null}var yr=!1;function br(e,t){switch(e){case`compositionend`:return vr(t);case`keypress`:return t.which===32?(gr=!0,hr):null;case`textInput`:return e=t.data,e===hr&&gr?null:e;default:return null}}function xr(e,t){if(yr)return e===`compositionend`||!dr&&_r(e,t)?(e=Tn(),wn=Cn=Sn=null,yr=!1,e):null;switch(e){case`paste`:return null;case`keypress`:if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1<t.char.length)return t.char;if(t.which)return String.fromCharCode(t.which)}return null;case`compositionend`:return mr&&t.locale!==`ko`?null:t.data;default:return null}}var Sr={color:!0,date:!0,datetime:!0,\"datetime-local\":!0,email:!0,month:!0,number:!0,password:!0,range:!0,search:!0,tel:!0,text:!0,time:!0,url:!0,week:!0};function Cr(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t===`input`?!!Sr[e.type]:t===`textarea`}function wr(e,t,n,r){pn?mn?mn.push(r):mn=[r]:pn=r,t=af(t,`onChange`),0<t.length&&(n=new k(`onChange`,`change`,null,n,r),e.push({event:n,listeners:t}))}var Tr=null,Er=null;function Dr(e){Zd(e,0)}function Or(e){var t=kt(e);if(Gt(t))return e}function kr(e,t){if(e===`change`)return t}var Ar=!1;if(yn){var jr;if(yn){var Mr=`oninput`in document;if(!Mr){var Nr=document.createElement(`div`);Nr.setAttribute(`oninput`,`return;`),Mr=typeof Nr.oninput==`function`}jr=Mr}else jr=!1;Ar=jr&&(!document.documentMode||9<document.documentMode)}function Pr(){Tr&&(Tr.detachEvent(`onpropertychange`,Fr),Er=Tr=null)}function Fr(e){if(e.propertyName===`value`&&Or(Er)){var t=[];wr(t,Er,e,fn(e)),_n(Dr,t)}}function Ir(e,t,n){e===`focusin`?(Pr(),Tr=t,Er=n,Tr.attachEvent(`onpropertychange`,Fr)):e===`focusout`&&Pr()}function Lr(e){if(e===`selectionchange`||e===`keyup`||e===`keydown`)return Or(Er)}function Rr(e,t){if(e===`click`)return Or(t)}function zr(e,t){if(e===`input`||e===`change`)return Or(t)}function Br(e,t){return e===t&&(e!==0||1/e==1/t)||e!==e&&t!==t}var Vr=typeof Object.is==`function`?Object.is:Br;function Hr(e,t){if(Vr(e,t))return!0;if(typeof e!=`object`||!e||typeof t!=`object`||!t)return!1;var n=Object.keys(e),r=Object.keys(t);if(n.length!==r.length)return!1;for(r=0;r<n.length;r++){var i=n[r];if(!Ne.call(t,i)||!Vr(e[i],t[i]))return!1}return!0}function Ur(e){for(;e&&e.firstChild;)e=e.firstChild;return e}function Wr(e,t){var n=Ur(e);e=0;for(var r;n;){if(n.nodeType===3){if(r=e+n.textContent.length,e<=t&&r>=t)return{node:n,offset:t-e};e=r}a:{for(;n;){if(n.nextSibling){n=n.nextSibling;break a}n=n.parentNode}n=void 0}n=Ur(n)}}function Gr(e,t){return e&&t?e===t?!0:e&&e.nodeType===3?!1:t&&t.nodeType===3?Gr(e,t.parentNode):`contains`in e?e.contains(t):e.compareDocumentPosition?!!(e.compareDocumentPosition(t)&16):!1:!1}function Kr(e){e=e!=null&&e.ownerDocument!=null&&e.ownerDocument.defaultView!=null?e.ownerDocument.defaultView:window;for(var t=Kt(e.document);t instanceof e.HTMLIFrameElement;){try{var n=typeof t.contentWindow.location.href==`string`}catch{n=!1}if(n)e=t.contentWindow;else break;t=Kt(e.document)}return t}function qr(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&(t===`input`&&(e.type===`text`||e.type===`search`||e.type===`tel`||e.type===`url`||e.type===`password`)||t===`textarea`||e.contentEditable===`true`)}var Jr=yn&&`documentMode`in document&&11>=document.documentMode,Yr=null,Xr=null,Zr=null,Qr=!1;function $r(e,t,n){var r=n.window===n?n.document:n.nodeType===9?n:n.ownerDocument;Qr||Yr==null||Yr!==Kt(r)||(r=Yr,`selectionStart`in r&&qr(r)?r={start:r.selectionStart,end:r.selectionEnd}:(r=(r.ownerDocument&&r.ownerDocument.defaultView||window).getSelection(),r={anchorNode:r.anchorNode,anchorOffset:r.anchorOffset,focusNode:r.focusNode,focusOffset:r.focusOffset}),Zr&&Hr(Zr,r)||(Zr=r,r=af(Xr,`onSelect`),0<r.length&&(t=new k(`onSelect`,`select`,null,t,n),e.push({event:t,listeners:r}),t.target=Yr)))}function ei(e,t){var n={};return n[e.toLowerCase()]=t.toLowerCase(),n[`Webkit`+e]=`webkit`+t,n[`Moz`+e]=`moz`+t,n}var ti={animationend:ei(`Animation`,`AnimationEnd`),animationiteration:ei(`Animation`,`AnimationIteration`),animationstart:ei(`Animation`,`AnimationStart`),transitionrun:ei(`Transition`,`TransitionRun`),transitionstart:ei(`Transition`,`TransitionStart`),transitioncancel:ei(`Transition`,`TransitionCancel`),transitionend:ei(`Transition`,`TransitionEnd`)},ni={},ri={};yn&&(ri=document.createElement(`div`).style,`AnimationEvent`in window||(delete ti.animationend.animation,delete ti.animationiteration.animation,delete ti.animationstart.animation),`TransitionEvent`in window||delete ti.transitionend.transition);function ii(e){if(ni[e])return ni[e];if(!ti[e])return e;var t=ti[e],n;for(n in t)if(t.hasOwnProperty(n)&&n in ri)return ni[e]=t[n];return e}var ai=ii(`animationend`),oi=ii(`animationiteration`),si=ii(`animationstart`),ci=ii(`transitionrun`),li=ii(`transitionstart`),ui=ii(`transitioncancel`),di=ii(`transitionend`),fi=new Map,pi=`abort auxClick beforeToggle cancel canPlay canPlayThrough click close contextMenu copy cut drag dragEnd dragEnter dragExit dragLeave dragOver dragStart drop durationChange emptied encrypted ended error gotPointerCapture input invalid keyDown keyPress keyUp load loadedData loadedMetadata loadStart lostPointerCapture mouseDown mouseMove mouseOut mouseOver mouseUp paste pause play playing pointerCancel pointerDown pointerMove pointerOut pointerOver pointerUp progress rateChange reset resize seeked seeking stalled submit suspend timeUpdate touchCancel touchEnd touchStart volumeChange scroll toggle touchMove waiting wheel`.split(` `);pi.push(`scrollEnd`);function mi(e,t){fi.set(e,t),Pt(t,[e])}var hi=typeof reportError==`function`?reportError:function(e){if(typeof window==`object`&&typeof window.ErrorEvent==`function`){var t=new window.ErrorEvent(`error`,{bubbles:!0,cancelable:!0,message:typeof e==`object`&&e&&typeof e.message==`string`?String(e.message):String(e),error:e});if(!window.dispatchEvent(t))return}else if(typeof process==`object`&&typeof process.emit==`function`){process.emit(`uncaughtException`,e);return}console.error(e)},gi=[],_i=0,vi=0;function yi(){for(var e=_i,t=vi=_i=0;t<e;){var n=gi[t];gi[t++]=null;var r=gi[t];gi[t++]=null;var i=gi[t];gi[t++]=null;var a=gi[t];if(gi[t++]=null,r!==null&&i!==null){var o=r.pending;o===null?i.next=i:(i.next=o.next,o.next=i),r.pending=i}a!==0&&Ci(n,i,a)}}function bi(e,t,n,r){gi[_i++]=e,gi[_i++]=t,gi[_i++]=n,gi[_i++]=r,vi|=r,e.lanes|=r,e=e.alternate,e!==null&&(e.lanes|=r)}function xi(e,t,n,r){return bi(e,t,n,r),wi(e)}function Si(e,t){return bi(e,null,null,t),wi(e)}function Ci(e,t,n){e.lanes|=n;var r=e.alternate;r!==null&&(r.lanes|=n);for(var i=!1,a=e.return;a!==null;)a.childLanes|=n,r=a.alternate,r!==null&&(r.childLanes|=n),a.tag===22&&(e=a.stateNode,e===null||e._visibility&1||(i=!0)),e=a,a=a.return;return e.tag===3?(a=e.stateNode,i&&t!==null&&(i=31-Xe(n),e=a.hiddenUpdates,r=e[i],r===null?e[i]=[t]:r.push(t),t.lane=n|536870912),a):null}function wi(e){if(50<Vu)throw Vu=0,Hu=null,Error(i(185));for(var t=e.return;t!==null;)e=t,t=e.return;return e.tag===3?e.stateNode:null}var Ti={};function Ei(e,t,n,r){this.tag=e,this.key=n,this.sibling=this.child=this.return=this.stateNode=this.type=this.elementType=null,this.index=0,this.refCleanup=this.ref=null,this.pendingProps=t,this.dependencies=this.memoizedState=this.updateQueue=this.memoizedProps=null,this.mode=r,this.subtreeFlags=this.flags=0,this.deletions=null,this.childLanes=this.lanes=0,this.alternate=null}function Di(e,t,n,r){return new Ei(e,t,n,r)}function Oi(e){return e=e.prototype,!(!e||!e.isReactComponent)}function ki(e,t){var n=e.alternate;return n===null?(n=Di(e.tag,t,e.key,e.mode),n.elementType=e.elementType,n.type=e.type,n.stateNode=e.stateNode,n.alternate=e,e.alternate=n):(n.pendingProps=t,n.type=e.type,n.flags=0,n.subtreeFlags=0,n.deletions=null),n.flags=e.flags&65011712,n.childLanes=e.childLanes,n.lanes=e.lanes,n.child=e.child,n.memoizedProps=e.memoizedProps,n.memoizedState=e.memoizedState,n.updateQueue=e.updateQueue,t=e.dependencies,n.dependencies=t===null?null:{lanes:t.lanes,firstContext:t.firstContext},n.sibling=e.sibling,n.index=e.index,n.ref=e.ref,n.refCleanup=e.refCleanup,n}function Ai(e,t){e.flags&=65011714;var n=e.alternate;return n===null?(e.childLanes=0,e.lanes=t,e.child=null,e.subtreeFlags=0,e.memoizedProps=null,e.memoizedState=null,e.updateQueue=null,e.dependencies=null,e.stateNode=null):(e.childLanes=n.childLanes,e.lanes=n.lanes,e.child=n.child,e.subtreeFlags=0,e.deletions=null,e.memoizedProps=n.memoizedProps,e.memoizedState=n.memoizedState,e.updateQueue=n.updateQueue,e.type=n.type,t=n.dependencies,e.dependencies=t===null?null:{lanes:t.lanes,firstContext:t.firstContext}),e}function ji(e,t,n,r,a,o){var s=0;if(r=e,typeof e==`function`)Oi(e)&&(s=1);else if(typeof e==`string`)s=Sp(e,n,ve.current)?26:e===`html`||e===`head`||e===`body`?27:5;else a:switch(e){case ie:return e=Di(31,n,t,a),e.elementType=ie,e.lanes=o,e;case y:return Mi(n.children,a,o,t);case b:s=8,a|=24;break;case x:return e=Di(12,n,t,a|2),e.elementType=x,e.lanes=o,e;case ee:return e=Di(13,n,t,a),e.elementType=ee,e.lanes=o,e;case te:return e=Di(19,n,t,a),e.elementType=te,e.lanes=o,e;default:if(typeof e==`object`&&e)switch(e.$$typeof){case C:s=10;break a;case S:s=9;break a;case w:s=11;break a;case ne:s=14;break a;case re:s=16,r=null;break a}s=29,n=Error(i(130,e===null?`null`:typeof e,``)),r=null}return t=Di(s,n,t,a),t.elementType=e,t.type=r,t.lanes=o,t}function Mi(e,t,n,r){return e=Di(7,e,r,t),e.lanes=n,e}function Ni(e,t,n){return e=Di(6,e,null,t),e.lanes=n,e}function Pi(e){var t=Di(18,null,null,0);return t.stateNode=e,t}function Fi(e,t,n){return t=Di(4,e.children===null?[]:e.children,e.key,t),t.lanes=n,t.stateNode={containerInfo:e.containerInfo,pendingChildren:null,implementation:e.implementation},t}var Ii=new WeakMap;function Li(e,t){if(typeof e==`object`&&e){var n=Ii.get(e);return n===void 0?(t={value:e,source:t,stack:Me(t)},Ii.set(e,t),t):n}return{value:e,source:t,stack:Me(t)}}var Ri=[],zi=0,Bi=null,Vi=0,Hi=[],Ui=0,Wi=null,Gi=1,Ki=``;function qi(e,t){Ri[zi++]=Vi,Ri[zi++]=Bi,Bi=e,Vi=t}function Ji(e,t,n){Hi[Ui++]=Gi,Hi[Ui++]=Ki,Hi[Ui++]=Wi,Wi=e;var r=Gi;e=Ki;var i=32-Xe(r)-1;r&=~(1<<i),n+=1;var a=32-Xe(t)+i;if(30<a){var o=i-i%5;a=(r&(1<<o)-1).toString(32),r>>=o,i-=o,Gi=1<<32-Xe(t)+i|n<<i|r,Ki=a+e}else Gi=1<<a|n<<i|r,Ki=e}function Yi(e){e.return!==null&&(qi(e,1),Ji(e,1,0))}function Xi(e){for(;e===Bi;)Bi=Ri[--zi],Ri[zi]=null,Vi=Ri[--zi],Ri[zi]=null;for(;e===Wi;)Wi=Hi[--Ui],Hi[Ui]=null,Ki=Hi[--Ui],Hi[Ui]=null,Gi=Hi[--Ui],Hi[Ui]=null}function Zi(e,t){Hi[Ui++]=Gi,Hi[Ui++]=Ki,Hi[Ui++]=Wi,Gi=t.id,Ki=t.overflow,Wi=e}var Qi=null,$i=null,ea=!1,ta=null,na=!1,ra=Error(i(519));function ia(e){var t=Error(i(418,1<arguments.length&&arguments[1]!==void 0&&arguments[1]?`text`:`HTML`,``));throw ua(Li(t,e)),ra}function aa(e){var t=e.stateNode,n=e.type,r=e.memoizedProps;switch(t[yt]=e,t[bt]=r,n){case`dialog`:F(`cancel`,t),F(`close`,t);break;case`iframe`:case`object`:case`embed`:F(`load`,t);break;case`video`:case`audio`:for(n=0;n<Yd.length;n++)F(Yd[n],t);break;case`source`:F(`error`,t);break;case`img`:case`image`:case`link`:F(`error`,t),F(`load`,t);break;case`details`:F(`toggle`,t);break;case`input`:F(`invalid`,t),Xt(t,r.value,r.defaultValue,r.checked,r.defaultChecked,r.type,r.name,!0);break;case`select`:F(`invalid`,t);break;case`textarea`:F(`invalid`,t),en(t,r.value,r.defaultValue,r.children)}n=r.children,typeof n!=`string`&&typeof n!=`number`&&typeof n!=`bigint`||t.textContent===``+n||!0===r.suppressHydrationWarning||ff(t.textContent,n)?(r.popover!=null&&(F(`beforetoggle`,t),F(`toggle`,t)),r.onScroll!=null&&F(`scroll`,t),r.onScrollEnd!=null&&F(`scrollend`,t),r.onClick!=null&&(t.onclick=un),t=!0):t=!1,t||ia(e,!0)}function oa(e){for(Qi=e.return;Qi;)switch(Qi.tag){case 5:case 31:case 13:na=!1;return;case 27:case 3:na=!0;return;default:Qi=Qi.return}}function sa(e){if(e!==Qi)return!1;if(!ea)return oa(e),ea=!0,!1;var t=e.tag,n;if((n=t!==3&&t!==27)&&((n=t===5)&&(n=e.type,n=!(n!==`form`&&n!==`button`)||wf(e.type,e.memoizedProps)),n=!n),n&&$i&&ia(e),oa(e),t===13){if(e=e.memoizedState,e=e===null?null:e.dehydrated,!e)throw Error(i(317));$i=Uf(e)}else if(t===31){if(e=e.memoizedState,e=e===null?null:e.dehydrated,!e)throw Error(i(317));$i=Uf(e)}else t===27?(t=$i,Mf(e.type)?(e=I,I=null,$i=e):$i=t):$i=Qi?Hf(e.stateNode.nextSibling):null;return!0}function ca(){$i=Qi=null,ea=!1}function la(){var e=ta;return e!==null&&(Du===null?Du=e:Du.push.apply(Du,e),ta=null),e}function ua(e){ta===null?ta=[e]:ta.push(e)}var da=he(null),fa=null,pa=null;function ma(e,t,n){_e(da,t._currentValue),t._currentValue=n}function ha(e){e._currentValue=da.current,ge(da)}function ga(e,t,n){for(;e!==null;){var r=e.alternate;if((e.childLanes&t)===t?r!==null&&(r.childLanes&t)!==t&&(r.childLanes|=t):(e.childLanes|=t,r!==null&&(r.childLanes|=t)),e===n)break;e=e.return}}function _a(e,t,n,r){var a=e.child;for(a!==null&&(a.return=e);a!==null;){var o=a.dependencies;if(o!==null){var s=a.child;o=o.firstContext;a:for(;o!==null;){var c=o;o=a;for(var l=0;l<t.length;l++)if(c.context===t[l]){o.lanes|=n,c=o.alternate,c!==null&&(c.lanes|=n),ga(o.return,n,e),r||(s=null);break a}o=c.next}}else if(a.tag===18){if(s=a.return,s===null)throw Error(i(341));s.lanes|=n,o=s.alternate,o!==null&&(o.lanes|=n),ga(s,n,e),s=null}else s=a.child;if(s!==null)s.return=a;else for(s=a;s!==null;){if(s===e){s=null;break}if(a=s.sibling,a!==null){a.return=s.return,s=a;break}s=s.return}a=s}}function va(e,t,n,r){e=null;for(var a=t,o=!1;a!==null;){if(!o){if(a.flags&524288)o=!0;else if(a.flags&262144)break}if(a.tag===10){var s=a.alternate;if(s===null)throw Error(i(387));if(s=s.memoizedProps,s!==null){var c=a.type;Vr(a.pendingProps.value,s.value)||(e===null?e=[c]:e.push(c))}}else if(a===xe.current){if(s=a.alternate,s===null)throw Error(i(387));s.memoizedState.memoizedState!==a.memoizedState.memoizedState&&(e===null?e=[jp]:e.push(jp))}a=a.return}e!==null&&_a(t,e,n,r),t.flags|=262144}function ya(e){for(e=e.firstContext;e!==null;){if(!Vr(e.context._currentValue,e.memoizedValue))return!0;e=e.next}return!1}function ba(e){fa=e,pa=null,e=e.dependencies,e!==null&&(e.firstContext=null)}function xa(e){return Ca(fa,e)}function Sa(e,t){return fa===null&&ba(e),Ca(e,t)}function Ca(e,t){var n=t._currentValue;if(t={context:t,memoizedValue:n,next:null},pa===null){if(e===null)throw Error(i(308));pa=t,e.dependencies={lanes:0,firstContext:t},e.flags|=524288}else pa=pa.next=t;return n}var wa=typeof AbortController<`u`?AbortController:function(){var e=[],t=this.signal={aborted:!1,addEventListener:function(t,n){e.push(n)}};this.abort=function(){t.aborted=!0,e.forEach(function(e){return e()})}},Ta=t.unstable_scheduleCallback,Ea=t.unstable_NormalPriority,Da={$$typeof:C,Consumer:null,Provider:null,_currentValue:null,_currentValue2:null,_threadCount:0};function Oa(){return{controller:new wa,data:new Map,refCount:0}}function ka(e){e.refCount--,e.refCount===0&&Ta(Ea,function(){e.controller.abort()})}var Aa=null,ja=0,Ma=0,Na=null;function Pa(e,t){if(Aa===null){var n=Aa=[];ja=0,Ma=Hd(),Na={status:`pending`,value:void 0,then:function(e){n.push(e)}}}return ja++,t.then(Fa,Fa),t}function Fa(){if(--ja===0&&Aa!==null){Na!==null&&(Na.status=`fulfilled`);var e=Aa;Aa=null,Ma=0,Na=null;for(var t=0;t<e.length;t++)(0,e[t])()}}function Ia(e,t){var n=[],r={status:`pending`,value:null,reason:null,then:function(e){n.push(e)}};return e.then(function(){r.status=`fulfilled`,r.value=t;for(var e=0;e<n.length;e++)(0,n[e])(t)},function(e){for(r.status=`rejected`,r.reason=e,e=0;e<n.length;e++)(0,n[e])(void 0)}),r}var La=T.S;T.S=function(e,t){Au=Re(),typeof t==`object`&&t&&typeof t.then==`function`&&Pa(e,t),La!==null&&La(e,t)};var Ra=he(null);function za(){var e=Ra.current;return e===null?pu.pooledCache:e}function Ba(e,t){t===null?_e(Ra,Ra.current):_e(Ra,t.pool)}function Va(){var e=za();return e===null?null:{parent:Da._currentValue,pool:e}}var Ha=Error(i(460)),Ua=Error(i(474)),Wa=Error(i(542)),Ga={then:function(){}};function Ka(e){return e=e.status,e===`fulfilled`||e===`rejected`}function qa(e,t,n){switch(n=e[n],n===void 0?e.push(t):n!==t&&(t.then(un,un),t=n),t.status){case`fulfilled`:return t.value;case`rejected`:throw e=t.reason,Za(e),e;default:if(typeof t.status==`string`)t.then(un,un);else{if(e=pu,e!==null&&100<e.shellSuspendCounter)throw Error(i(482));e=t,e.status=`pending`,e.then(function(e){if(t.status===`pending`){var n=t;n.status=`fulfilled`,n.value=e}},function(e){if(t.status===`pending`){var n=t;n.status=`rejected`,n.reason=e}})}switch(t.status){case`fulfilled`:return t.value;case`rejected`:throw e=t.reason,Za(e),e}throw Ya=t,Ha}}function Ja(e){try{var t=e._init;return t(e._payload)}catch(e){throw typeof e==`object`&&e&&typeof e.then==`function`?(Ya=e,Ha):e}}var Ya=null;function Xa(){if(Ya===null)throw Error(i(459));var e=Ya;return Ya=null,e}function Za(e){if(e===Ha||e===Wa)throw Error(i(483))}var Qa=null,$a=0;function eo(e){var t=$a;return $a+=1,Qa===null&&(Qa=[]),qa(Qa,e,t)}function to(e,t){t=t.props.ref,e.ref=t===void 0?null:t}function no(e,t){throw t.$$typeof===h?Error(i(525)):(e=Object.prototype.toString.call(t),Error(i(31,e===`[object Object]`?`object with keys {`+Object.keys(t).join(`, `)+`}`:e)))}function ro(e){function t(t,n){if(e){var r=t.deletions;r===null?(t.deletions=[n],t.flags|=16):r.push(n)}}function n(n,r){if(!e)return null;for(;r!==null;)t(n,r),r=r.sibling;return null}function r(e){for(var t=new Map;e!==null;)e.key===null?t.set(e.index,e):t.set(e.key,e),e=e.sibling;return t}function a(e,t){return e=ki(e,t),e.index=0,e.sibling=null,e}function o(t,n,r){return t.index=r,e?(r=t.alternate,r===null?(t.flags|=67108866,n):(r=r.index,r<n?(t.flags|=67108866,n):r)):(t.flags|=1048576,n)}function s(t){return e&&t.alternate===null&&(t.flags|=67108866),t}function c(e,t,n,r){return t===null||t.tag!==6?(t=Ni(n,e.mode,r),t.return=e,t):(t=a(t,n),t.return=e,t)}function l(e,t,n,r){var i=n.type;return i===y?d(e,t,n.props.children,r,n.key):t!==null&&(t.elementType===i||typeof i==`object`&&i&&i.$$typeof===re&&Ja(i)===t.type)?(t=a(t,n.props),to(t,n),t.return=e,t):(t=ji(n.type,n.key,n.props,null,e.mode,r),to(t,n),t.return=e,t)}function u(e,t,n,r){return t===null||t.tag!==4||t.stateNode.containerInfo!==n.containerInfo||t.stateNode.implementation!==n.implementation?(t=Fi(n,e.mode,r),t.return=e,t):(t=a(t,n.children||[]),t.return=e,t)}function d(e,t,n,r,i){return t===null||t.tag!==7?(t=Mi(n,e.mode,r,i),t.return=e,t):(t=a(t,n),t.return=e,t)}function f(e,t,n){if(typeof t==`string`&&t!==``||typeof t==`number`||typeof t==`bigint`)return t=Ni(``+t,e.mode,n),t.return=e,t;if(typeof t==`object`&&t){switch(t.$$typeof){case _:return n=ji(t.type,t.key,t.props,null,e.mode,n),to(n,t),n.return=e,n;case v:return t=Fi(t,e.mode,n),t.return=e,t;case re:return t=Ja(t),f(e,t,n)}if(ue(t)||se(t))return t=Mi(t,e.mode,n,null),t.return=e,t;if(typeof t.then==`function`)return f(e,eo(t),n);if(t.$$typeof===C)return f(e,Sa(e,t),n);no(e,t)}return null}function p(e,t,n,r){var i=t===null?null:t.key;if(typeof n==`string`&&n!==``||typeof n==`number`||typeof n==`bigint`)return i===null?c(e,t,``+n,r):null;if(typeof n==`object`&&n){switch(n.$$typeof){case _:return n.key===i?l(e,t,n,r):null;case v:return n.key===i?u(e,t,n,r):null;case re:return n=Ja(n),p(e,t,n,r)}if(ue(n)||se(n))return i===null?d(e,t,n,r,null):null;if(typeof n.then==`function`)return p(e,t,eo(n),r);if(n.$$typeof===C)return p(e,t,Sa(e,n),r);no(e,n)}return null}function m(e,t,n,r,i){if(typeof r==`string`&&r!==``||typeof r==`number`||typeof r==`bigint`)return e=e.get(n)||null,c(t,e,``+r,i);if(typeof r==`object`&&r){switch(r.$$typeof){case _:return e=e.get(r.key===null?n:r.key)||null,l(t,e,r,i);case v:return e=e.get(r.key===null?n:r.key)||null,u(t,e,r,i);case re:return r=Ja(r),m(e,t,n,r,i)}if(ue(r)||se(r))return e=e.get(n)||null,d(t,e,r,i,null);if(typeof r.then==`function`)return m(e,t,n,eo(r),i);if(r.$$typeof===C)return m(e,t,n,Sa(t,r),i);no(t,r)}return null}function h(i,a,s,c){for(var l=null,u=null,d=a,h=a=0,g=null;d!==null&&h<s.length;h++){d.index>h?(g=d,d=null):g=d.sibling;var _=p(i,d,s[h],c);if(_===null){d===null&&(d=g);break}e&&d&&_.alternate===null&&t(i,d),a=o(_,a,h),u===null?l=_:u.sibling=_,u=_,d=g}if(h===s.length)return n(i,d),ea&&qi(i,h),l;if(d===null){for(;h<s.length;h++)d=f(i,s[h],c),d!==null&&(a=o(d,a,h),u===null?l=d:u.sibling=d,u=d);return ea&&qi(i,h),l}for(d=r(d);h<s.length;h++)g=m(d,i,h,s[h],c),g!==null&&(e&&g.alternate!==null&&d.delete(g.key===null?h:g.key),a=o(g,a,h),u===null?l=g:u.sibling=g,u=g);return e&&d.forEach(function(e){return t(i,e)}),ea&&qi(i,h),l}function g(a,s,c,l){if(c==null)throw Error(i(151));for(var u=null,d=null,h=s,g=s=0,_=null,v=c.next();h!==null&&!v.done;g++,v=c.next()){h.index>g?(_=h,h=null):_=h.sibling;var y=p(a,h,v.value,l);if(y===null){h===null&&(h=_);break}e&&h&&y.alternate===null&&t(a,h),s=o(y,s,g),d===null?u=y:d.sibling=y,d=y,h=_}if(v.done)return n(a,h),ea&&qi(a,g),u;if(h===null){for(;!v.done;g++,v=c.next())v=f(a,v.value,l),v!==null&&(s=o(v,s,g),d===null?u=v:d.sibling=v,d=v);return ea&&qi(a,g),u}for(h=r(h);!v.done;g++,v=c.next())v=m(h,a,g,v.value,l),v!==null&&(e&&v.alternate!==null&&h.delete(v.key===null?g:v.key),s=o(v,s,g),d===null?u=v:d.sibling=v,d=v);return e&&h.forEach(function(e){return t(a,e)}),ea&&qi(a,g),u}function b(e,r,o,c){if(typeof o==`object`&&o&&o.type===y&&o.key===null&&(o=o.props.children),typeof o==`object`&&o){switch(o.$$typeof){case _:a:{for(var l=o.key;r!==null;){if(r.key===l){if(l=o.type,l===y){if(r.tag===7){n(e,r.sibling),c=a(r,o.props.children),c.return=e,e=c;break a}}else if(r.elementType===l||typeof l==`object`&&l&&l.$$typeof===re&&Ja(l)===r.type){n(e,r.sibling),c=a(r,o.props),to(c,o),c.return=e,e=c;break a}n(e,r);break}else t(e,r);r=r.sibling}o.type===y?(c=Mi(o.props.children,e.mode,c,o.key),c.return=e,e=c):(c=ji(o.type,o.key,o.props,null,e.mode,c),to(c,o),c.return=e,e=c)}return s(e);case v:a:{for(l=o.key;r!==null;){if(r.key===l)if(r.tag===4&&r.stateNode.containerInfo===o.containerInfo&&r.stateNode.implementation===o.implementation){n(e,r.sibling),c=a(r,o.children||[]),c.return=e,e=c;break a}else{n(e,r);break}else t(e,r);r=r.sibling}c=Fi(o,e.mode,c),c.return=e,e=c}return s(e);case re:return o=Ja(o),b(e,r,o,c)}if(ue(o))return h(e,r,o,c);if(se(o)){if(l=se(o),typeof l!=`function`)throw Error(i(150));return o=l.call(o),g(e,r,o,c)}if(typeof o.then==`function`)return b(e,r,eo(o),c);if(o.$$typeof===C)return b(e,r,Sa(e,o),c);no(e,o)}return typeof o==`string`&&o!==``||typeof o==`number`||typeof o==`bigint`?(o=``+o,r!==null&&r.tag===6?(n(e,r.sibling),c=a(r,o),c.return=e,e=c):(n(e,r),c=Ni(o,e.mode,c),c.return=e,e=c),s(e)):n(e,r)}return function(e,t,n,r){try{$a=0;var i=b(e,t,n,r);return Qa=null,i}catch(t){if(t===Ha||t===Wa)throw t;var a=Di(29,t,null,e.mode);return a.lanes=r,a.return=e,a}}}var io=ro(!0),ao=ro(!1),oo=!1;function so(e){e.updateQueue={baseState:e.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,lanes:0,hiddenCallbacks:null},callbacks:null}}function co(e,t){e=e.updateQueue,t.updateQueue===e&&(t.updateQueue={baseState:e.baseState,firstBaseUpdate:e.firstBaseUpdate,lastBaseUpdate:e.lastBaseUpdate,shared:e.shared,callbacks:null})}function lo(e){return{lane:e,tag:0,payload:null,callback:null,next:null}}function uo(e,t,n){var r=e.updateQueue;if(r===null)return null;if(r=r.shared,fu&2){var i=r.pending;return i===null?t.next=t:(t.next=i.next,i.next=t),r.pending=t,t=wi(e),Ci(e,null,n),t}return bi(e,r,t,n),wi(e)}function fo(e,t,n){if(t=t.updateQueue,t!==null&&(t=t.shared,n&4194048)){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,ft(e,n)}}function po(e,t){var n=e.updateQueue,r=e.alternate;if(r!==null&&(r=r.updateQueue,n===r)){var i=null,a=null;if(n=n.firstBaseUpdate,n!==null){do{var o={lane:n.lane,tag:n.tag,payload:n.payload,callback:null,next:null};a===null?i=a=o:a=a.next=o,n=n.next}while(n!==null);a===null?i=a=t:a=a.next=t}else i=a=t;n={baseState:r.baseState,firstBaseUpdate:i,lastBaseUpdate:a,shared:r.shared,callbacks:r.callbacks},e.updateQueue=n;return}e=n.lastBaseUpdate,e===null?n.firstBaseUpdate=t:e.next=t,n.lastBaseUpdate=t}var mo=!1;function ho(){if(mo){var e=Na;if(e!==null)throw e}}function go(e,t,n,r){mo=!1;var i=e.updateQueue;oo=!1;var a=i.firstBaseUpdate,o=i.lastBaseUpdate,s=i.shared.pending;if(s!==null){i.shared.pending=null;var c=s,l=c.next;c.next=null,o===null?a=l:o.next=l,o=c;var u=e.alternate;u!==null&&(u=u.updateQueue,s=u.lastBaseUpdate,s!==o&&(s===null?u.firstBaseUpdate=l:s.next=l,u.lastBaseUpdate=c))}if(a!==null){var d=i.baseState;o=0,u=l=c=null,s=a;do{var f=s.lane&-536870913,m=f!==s.lane;if(m?(N&f)===f:(r&f)===f){f!==0&&f===Ma&&(mo=!0),u!==null&&(u=u.next={lane:0,tag:s.tag,payload:s.payload,callback:null,next:null});a:{var h=e,g=s;f=t;var _=n;switch(g.tag){case 1:if(h=g.payload,typeof h==`function`){d=h.call(_,d,f);break a}d=h;break a;case 3:h.flags=h.flags&-65537|128;case 0:if(h=g.payload,f=typeof h==`function`?h.call(_,d,f):h,f==null)break a;d=p({},d,f);break a;case 2:oo=!0}}f=s.callback,f!==null&&(e.flags|=64,m&&(e.flags|=8192),m=i.callbacks,m===null?i.callbacks=[f]:m.push(f))}else m={lane:f,tag:s.tag,payload:s.payload,callback:s.callback,next:null},u===null?(l=u=m,c=d):u=u.next=m,o|=f;if(s=s.next,s===null){if(s=i.shared.pending,s===null)break;m=s,s=m.next,m.next=null,i.lastBaseUpdate=m,i.shared.pending=null}}while(1);u===null&&(c=d),i.baseState=c,i.firstBaseUpdate=l,i.lastBaseUpdate=u,a===null&&(i.shared.lanes=0),xu|=o,e.lanes=o,e.memoizedState=d}}function _o(e,t){if(typeof e!=`function`)throw Error(i(191,e));e.call(t)}function vo(e,t){var n=e.callbacks;if(n!==null)for(e.callbacks=null,e=0;e<n.length;e++)_o(n[e],t)}var yo=he(null),bo=he(0);function xo(e,t){e=yu,_e(bo,e),_e(yo,t),yu=e|t.baseLanes}function So(){_e(bo,yu),_e(yo,yo.current)}function Co(){yu=bo.current,ge(yo),ge(bo)}var wo=he(null),To=null;function Eo(e){var t=e.alternate;_e(jo,jo.current&1),_e(wo,e),To===null&&(t===null||yo.current!==null||t.memoizedState!==null)&&(To=e)}function Do(e){_e(jo,jo.current),_e(wo,e),To===null&&(To=e)}function Oo(e){e.tag===22?(_e(jo,jo.current),_e(wo,e),To===null&&(To=e)):ko(e)}function ko(){_e(jo,jo.current),_e(wo,wo.current)}function Ao(e){ge(wo),To===e&&(To=null),ge(jo)}var jo=he(0);function Mo(e){for(var t=e;t!==null;){if(t.tag===13){var n=t.memoizedState;if(n!==null&&(n=n.dehydrated,n===null||zf(n)||Bf(n)))return t}else if(t.tag===19&&(t.memoizedProps.revealOrder===`forwards`||t.memoizedProps.revealOrder===`backwards`||t.memoizedProps.revealOrder===`unstable_legacy-backwards`||t.memoizedProps.revealOrder===`together`)){if(t.flags&128)return t}else if(t.child!==null){t.child.return=t,t=t.child;continue}if(t===e)break;for(;t.sibling===null;){if(t.return===null||t.return===e)return null;t=t.return}t.sibling.return=t.return,t=t.sibling}return null}var No=0,j=null,Po=null,Fo=null,Io=!1,Lo=!1,Ro=!1,zo=0,Bo=0,Vo=null,Ho=0;function Uo(){throw Error(i(321))}function Wo(e,t){if(t===null)return!1;for(var n=0;n<t.length&&n<e.length;n++)if(!Vr(e[n],t[n]))return!1;return!0}function Go(e,t,n,r,i,a){return No=a,j=t,t.memoizedState=null,t.updateQueue=null,t.lanes=0,T.H=e===null||e.memoizedState===null?uc:dc,Ro=!1,a=n(r,i),Ro=!1,Lo&&(a=qo(t,n,r,i)),Ko(e),a}function Ko(e){T.H=lc;var t=Po!==null&&Po.next!==null;if(No=0,Fo=Po=j=null,Io=!1,Bo=0,Vo=null,t)throw Error(i(300));e===null||Oc||(e=e.dependencies,e!==null&&ya(e)&&(Oc=!0))}function qo(e,t,n,r){j=e;var a=0;do{if(Lo&&(Vo=null),Bo=0,Lo=!1,25<=a)throw Error(i(301));if(a+=1,Fo=Po=null,e.updateQueue!=null){var o=e.updateQueue;o.lastEffect=null,o.events=null,o.stores=null,o.memoCache!=null&&(o.memoCache.index=0)}T.H=fc,o=t(n,r)}while(Lo);return o}function Jo(){var e=T.H,t=e.useState()[0];return t=typeof t.then==`function`?ts(t):t,e=e.useState()[0],(Po===null?null:Po.memoizedState)!==e&&(j.flags|=1024),t}function Yo(){var e=zo!==0;return zo=0,e}function Xo(e,t,n){t.updateQueue=e.updateQueue,t.flags&=-2053,e.lanes&=~n}function Zo(e){if(Io){for(e=e.memoizedState;e!==null;){var t=e.queue;t!==null&&(t.pending=null),e=e.next}Io=!1}No=0,Fo=Po=j=null,Lo=!1,Bo=zo=0,Vo=null}function Qo(){var e={memoizedState:null,baseState:null,baseQueue:null,queue:null,next:null};return Fo===null?j.memoizedState=Fo=e:Fo=Fo.next=e,Fo}function $o(){if(Po===null){var e=j.alternate;e=e===null?null:e.memoizedState}else e=Po.next;var t=Fo===null?j.memoizedState:Fo.next;if(t!==null)Fo=t,Po=e;else{if(e===null)throw j.alternate===null?Error(i(467)):Error(i(310));Po=e,e={memoizedState:Po.memoizedState,baseState:Po.baseState,baseQueue:Po.baseQueue,queue:Po.queue,next:null},Fo===null?j.memoizedState=Fo=e:Fo=Fo.next=e}return Fo}function es(){return{lastEffect:null,events:null,stores:null,memoCache:null}}function ts(e){var t=Bo;return Bo+=1,Vo===null&&(Vo=[]),e=qa(Vo,e,t),t=j,(Fo===null?t.memoizedState:Fo.next)===null&&(t=t.alternate,T.H=t===null||t.memoizedState===null?uc:dc),e}function ns(e){if(typeof e==`object`&&e){if(typeof e.then==`function`)return ts(e);if(e.$$typeof===C)return xa(e)}throw Error(i(438,String(e)))}function rs(e){var t=null,n=j.updateQueue;if(n!==null&&(t=n.memoCache),t==null){var r=j.alternate;r!==null&&(r=r.updateQueue,r!==null&&(r=r.memoCache,r!=null&&(t={data:r.data.map(function(e){return e.slice()}),index:0})))}if(t??={data:[],index:0},n===null&&(n=es(),j.updateQueue=n),n.memoCache=t,n=t.data[t.index],n===void 0)for(n=t.data[t.index]=Array(e),r=0;r<e;r++)n[r]=ae;return t.index++,n}function os(e,t){return typeof t==`function`?t(e):t}function ss(e){var t=$o();return cs(t,Po,e)}function cs(e,t,n){var r=e.queue;if(r===null)throw Error(i(311));r.lastRenderedReducer=n;var a=e.baseQueue,o=r.pending;if(o!==null){if(a!==null){var s=a.next;a.next=o.next,o.next=s}t.baseQueue=a=o,r.pending=null}if(o=e.baseState,a===null)e.memoizedState=o;else{t=a.next;var c=s=null,l=null,u=t,d=!1;do{var f=u.lane&-536870913;if(f===u.lane?(No&f)===f:(N&f)===f){var p=u.revertLane;if(p===0)l!==null&&(l=l.next={lane:0,revertLane:0,gesture:null,action:u.action,hasEagerState:u.hasEagerState,eagerState:u.eagerState,next:null}),f===Ma&&(d=!0);else if((No&p)===p){u=u.next,p===Ma&&(d=!0);continue}else f={lane:0,revertLane:u.revertLane,gesture:null,action:u.action,hasEagerState:u.hasEagerState,eagerState:u.eagerState,next:null},l===null?(c=l=f,s=o):l=l.next=f,j.lanes|=p,xu|=p;f=u.action,Ro&&n(o,f),o=u.hasEagerState?u.eagerState:n(o,f)}else p={lane:f,revertLane:u.revertLane,gesture:u.gesture,action:u.action,hasEagerState:u.hasEagerState,eagerState:u.eagerState,next:null},l===null?(c=l=p,s=o):l=l.next=p,j.lanes|=f,xu|=f;u=u.next}while(u!==null&&u!==t);if(l===null?s=o:l.next=c,!Vr(o,e.memoizedState)&&(Oc=!0,d&&(n=Na,n!==null)))throw n;e.memoizedState=o,e.baseState=s,e.baseQueue=l,r.lastRenderedState=o}return a===null&&(r.lanes=0),[e.memoizedState,r.dispatch]}function ls(e){var t=$o(),n=t.queue;if(n===null)throw Error(i(311));n.lastRenderedReducer=e;var r=n.dispatch,a=n.pending,o=t.memoizedState;if(a!==null){n.pending=null;var s=a=a.next;do o=e(o,s.action),s=s.next;while(s!==a);Vr(o,t.memoizedState)||(Oc=!0),t.memoizedState=o,t.baseQueue===null&&(t.baseState=o),n.lastRenderedState=o}return[o,r]}function us(e,t,n){var r=j,a=$o(),o=ea;if(o){if(n===void 0)throw Error(i(407));n=n()}else n=t();var s=!Vr((Po||a).memoizedState,n);if(s&&(a.memoizedState=n,Oc=!0),a=a.queue,Fs(ps.bind(null,r,a,e),[e]),a.getSnapshot!==t||s||Fo!==null&&Fo.memoizedState.tag&1){if(r.flags|=2048,As(9,{destroy:void 0},fs.bind(null,r,a,n,t),null),pu===null)throw Error(i(349));o||No&127||ds(r,t,n)}return n}function ds(e,t,n){e.flags|=16384,e={getSnapshot:t,value:n},t=j.updateQueue,t===null?(t=es(),j.updateQueue=t,t.stores=[e]):(n=t.stores,n===null?t.stores=[e]:n.push(e))}function fs(e,t,n,r){t.value=n,t.getSnapshot=r,ms(t)&&hs(e)}function ps(e,t,n){return n(function(){ms(t)&&hs(e)})}function ms(e){var t=e.getSnapshot;e=e.value;try{var n=t();return!Vr(e,n)}catch{return!0}}function hs(e){var t=Si(e,2);t!==null&&Gu(t,e,2)}function gs(e){var t=Qo();if(typeof e==`function`){var n=e;if(e=n(),Ro){Ye(!0);try{n()}finally{Ye(!1)}}}return t.memoizedState=t.baseState=e,t.queue={pending:null,lanes:0,dispatch:null,lastRenderedReducer:os,lastRenderedState:e},t}function _s(e,t,n,r){return e.baseState=n,cs(e,Po,typeof r==`function`?r:os)}function vs(e,t,n,r,a){if(oc(e))throw Error(i(485));if(e=t.action,e!==null){var o={payload:a,action:e,next:null,isTransition:!0,status:`pending`,value:null,reason:null,listeners:[],then:function(e){o.listeners.push(e)}};T.T===null?o.isTransition=!1:n(!0),r(o),n=t.pending,n===null?(o.next=t.pending=o,ys(t,o)):(o.next=n.next,t.pending=n.next=o)}}function ys(e,t){var n=t.action,r=t.payload,i=e.state;if(t.isTransition){var a=T.T,o={};T.T=o;try{var s=n(i,r),c=T.S;c!==null&&c(o,s),bs(e,t,s)}catch(n){Ss(e,t,n)}finally{a!==null&&o.types!==null&&(a.types=o.types),T.T=a}}else try{a=n(i,r),bs(e,t,a)}catch(n){Ss(e,t,n)}}function bs(e,t,n){typeof n==`object`&&n&&typeof n.then==`function`?n.then(function(n){xs(e,t,n)},function(n){return Ss(e,t,n)}):xs(e,t,n)}function xs(e,t,n){t.status=`fulfilled`,t.value=n,Cs(t),e.state=n,t=e.pending,t!==null&&(n=t.next,n===t?e.pending=null:(n=n.next,t.next=n,ys(e,n)))}function Ss(e,t,n){var r=e.pending;if(e.pending=null,r!==null){r=r.next;do t.status=`rejected`,t.reason=n,Cs(t),t=t.next;while(t!==r)}e.action=null}function Cs(e){e=e.listeners;for(var t=0;t<e.length;t++)(0,e[t])()}function ws(e,t){return t}function Ts(e,t){if(ea){var n=pu.formState;if(n!==null){a:{var r=j;if(ea){if($i){b:{for(var i=$i,a=na;i.nodeType!==8;){if(!a){i=null;break b}if(i=Hf(i.nextSibling),i===null){i=null;break b}}a=i.data,i=a===`F!`||a===`F`?i:null}if(i){$i=Hf(i.nextSibling),r=i.data===`F!`;break a}}ia(r)}r=!1}r&&(t=n[0])}}return n=Qo(),n.memoizedState=n.baseState=t,r={pending:null,lanes:0,dispatch:null,lastRenderedReducer:ws,lastRenderedState:t},n.queue=r,n=rc.bind(null,j,r),r.dispatch=n,r=gs(!1),a=ac.bind(null,j,!1,r.queue),r=Qo(),i={state:t,dispatch:null,action:e,pending:null},r.queue=i,n=vs.bind(null,j,i,a,n),i.dispatch=n,r.memoizedState=e,[t,n,!1]}function Es(e){var t=$o();return Ds(t,Po,e)}function Ds(e,t,n){if(t=cs(e,t,ws)[0],e=ss(os)[0],typeof t==`object`&&t&&typeof t.then==`function`)try{var r=ts(t)}catch(e){throw e===Ha?Wa:e}else r=t;t=$o();var i=t.queue,a=i.dispatch;return n!==t.memoizedState&&(j.flags|=2048,As(9,{destroy:void 0},Os.bind(null,i,n),null)),[r,a,e]}function Os(e,t){e.action=t}function ks(e){var t=$o(),n=Po;if(n!==null)return Ds(t,n,e);$o(),t=t.memoizedState,n=$o();var r=n.queue.dispatch;return n.memoizedState=e,[t,r,!1]}function As(e,t,n,r){return e={tag:e,create:n,deps:r,inst:t,next:null},t=j.updateQueue,t===null&&(t=es(),j.updateQueue=t),n=t.lastEffect,n===null?t.lastEffect=e.next=e:(r=n.next,n.next=e,e.next=r,t.lastEffect=e),e}function js(){return $o().memoizedState}function Ms(e,t,n,r){var i=Qo();j.flags|=e,i.memoizedState=As(1|t,{destroy:void 0},n,r===void 0?null:r)}function Ns(e,t,n,r){var i=$o();r=r===void 0?null:r;var a=i.memoizedState.inst;Po!==null&&r!==null&&Wo(r,Po.memoizedState.deps)?i.memoizedState=As(t,a,n,r):(j.flags|=e,i.memoizedState=As(1|t,a,n,r))}function Ps(e,t){Ms(8390656,8,e,t)}function Fs(e,t){Ns(2048,8,e,t)}function Is(e){j.flags|=4;var t=j.updateQueue;if(t===null)t=es(),j.updateQueue=t,t.events=[e];else{var n=t.events;n===null?t.events=[e]:n.push(e)}}function Ls(e){var t=$o().memoizedState;return Is({ref:t,nextImpl:e}),function(){if(fu&2)throw Error(i(440));return t.impl.apply(void 0,arguments)}}function Rs(e,t){return Ns(4,2,e,t)}function zs(e,t){return Ns(4,4,e,t)}function Bs(e,t){if(typeof t==`function`){e=e();var n=t(e);return function(){typeof n==`function`?n():t(null)}}if(t!=null)return e=e(),t.current=e,function(){t.current=null}}function Vs(e,t,n){n=n==null?null:n.concat([e]),Ns(4,4,Bs.bind(null,t,e),n)}function Hs(){}function Us(e,t){var n=$o();t=t===void 0?null:t;var r=n.memoizedState;return t!==null&&Wo(t,r[1])?r[0]:(n.memoizedState=[e,t],e)}function Ws(e,t){var n=$o();t=t===void 0?null:t;var r=n.memoizedState;if(t!==null&&Wo(t,r[1]))return r[0];if(r=e(),Ro){Ye(!0);try{e()}finally{Ye(!1)}}return n.memoizedState=[r,t],r}function Gs(e,t,n){return n===void 0||No&1073741824&&!(N&261930)?e.memoizedState=t:(e.memoizedState=n,e=Wu(),j.lanes|=e,xu|=e,n)}function Ks(e,t,n,r){return Vr(n,t)?n:yo.current===null?!(No&42)||No&1073741824&&!(N&261930)?(Oc=!0,e.memoizedState=n):(e=Wu(),j.lanes|=e,xu|=e,t):(e=Gs(e,n,r),Vr(e,t)||(Oc=!0),e)}function qs(e,t,n,r,i){var a=de.p;de.p=a!==0&&8>a?a:8;var o=T.T,s={};T.T=s,ac(e,!1,t,n);try{var c=i(),l=T.S;if(l!==null&&l(s,c),typeof c==`object`&&c&&typeof c.then==`function`){var u=Ia(c,r);ic(e,t,u,Uu(e))}else ic(e,t,r,Uu(e))}catch(n){ic(e,t,{then:function(){},status:`rejected`,reason:n},Uu())}finally{de.p=a,o!==null&&s.types!==null&&(o.types=s.types),T.T=o}}function Js(){}function Ys(e,t,n,r){if(e.tag!==5)throw Error(i(476));var a=Xs(e).queue;qs(e,a,t,fe,n===null?Js:function(){return Zs(e),n(r)})}function Xs(e){var t=e.memoizedState;if(t!==null)return t;t={memoizedState:fe,baseState:fe,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:os,lastRenderedState:fe},next:null};var n={};return t.next={memoizedState:n,baseState:n,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:os,lastRenderedState:n},next:null},e.memoizedState=t,e=e.alternate,e!==null&&(e.memoizedState=t),t}function Zs(e){var t=Xs(e);t.next===null&&(t=e.alternate.memoizedState),ic(e,t.next.queue,{},Uu())}function Qs(){return xa(jp)}function $s(){return $o().memoizedState}function ec(){return $o().memoizedState}function tc(e){for(var t=e.return;t!==null;){switch(t.tag){case 24:case 3:var n=Uu();e=lo(n);var r=uo(t,e,n);r!==null&&(Gu(r,t,n),fo(r,t,n)),t={cache:Oa()},e.payload=t;return}t=t.return}}function nc(e,t,n){var r=Uu();n={lane:r,revertLane:0,gesture:null,action:n,hasEagerState:!1,eagerState:null,next:null},oc(e)?sc(t,n):(n=xi(e,t,n,r),n!==null&&(Gu(n,e,r),cc(n,t,r)))}function rc(e,t,n){var r=Uu();ic(e,t,n,r)}function ic(e,t,n,r){var i={lane:r,revertLane:0,gesture:null,action:n,hasEagerState:!1,eagerState:null,next:null};if(oc(e))sc(t,i);else{var a=e.alternate;if(e.lanes===0&&(a===null||a.lanes===0)&&(a=t.lastRenderedReducer,a!==null))try{var o=t.lastRenderedState,s=a(o,n);if(i.hasEagerState=!0,i.eagerState=s,Vr(s,o))return bi(e,t,i,0),pu===null&&yi(),!1}catch{}if(n=xi(e,t,i,r),n!==null)return Gu(n,e,r),cc(n,t,r),!0}return!1}function ac(e,t,n,r){if(r={lane:2,revertLane:Hd(),gesture:null,action:r,hasEagerState:!1,eagerState:null,next:null},oc(e)){if(t)throw Error(i(479))}else t=xi(e,n,r,2),t!==null&&Gu(t,e,2)}function oc(e){var t=e.alternate;return e===j||t!==null&&t===j}function sc(e,t){Lo=Io=!0;var n=e.pending;n===null?t.next=t:(t.next=n.next,n.next=t),e.pending=t}function cc(e,t,n){if(n&4194048){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,ft(e,n)}}var lc={readContext:xa,use:ns,useCallback:Uo,useContext:Uo,useEffect:Uo,useImperativeHandle:Uo,useLayoutEffect:Uo,useInsertionEffect:Uo,useMemo:Uo,useReducer:Uo,useRef:Uo,useState:Uo,useDebugValue:Uo,useDeferredValue:Uo,useTransition:Uo,useSyncExternalStore:Uo,useId:Uo,useHostTransitionStatus:Uo,useFormState:Uo,useActionState:Uo,useOptimistic:Uo,useMemoCache:Uo,useCacheRefresh:Uo};lc.useEffectEvent=Uo;var uc={readContext:xa,use:ns,useCallback:function(e,t){return Qo().memoizedState=[e,t===void 0?null:t],e},useContext:xa,useEffect:Ps,useImperativeHandle:function(e,t,n){n=n==null?null:n.concat([e]),Ms(4194308,4,Bs.bind(null,t,e),n)},useLayoutEffect:function(e,t){return Ms(4194308,4,e,t)},useInsertionEffect:function(e,t){Ms(4,2,e,t)},useMemo:function(e,t){var n=Qo();t=t===void 0?null:t;var r=e();if(Ro){Ye(!0);try{e()}finally{Ye(!1)}}return n.memoizedState=[r,t],r},useReducer:function(e,t,n){var r=Qo();if(n!==void 0){var i=n(t);if(Ro){Ye(!0);try{n(t)}finally{Ye(!1)}}}else i=t;return r.memoizedState=r.baseState=i,e={pending:null,lanes:0,dispatch:null,lastRenderedReducer:e,lastRenderedState:i},r.queue=e,e=e.dispatch=nc.bind(null,j,e),[r.memoizedState,e]},useRef:function(e){var t=Qo();return e={current:e},t.memoizedState=e},useState:function(e){e=gs(e);var t=e.queue,n=rc.bind(null,j,t);return t.dispatch=n,[e.memoizedState,n]},useDebugValue:Hs,useDeferredValue:function(e,t){var n=Qo();return Gs(n,e,t)},useTransition:function(){var e=gs(!1);return e=qs.bind(null,j,e.queue,!0,!1),Qo().memoizedState=e,[!1,e]},useSyncExternalStore:function(e,t,n){var r=j,a=Qo();if(ea){if(n===void 0)throw Error(i(407));n=n()}else{if(n=t(),pu===null)throw Error(i(349));N&127||ds(r,t,n)}a.memoizedState=n;var o={value:n,getSnapshot:t};return a.queue=o,Ps(ps.bind(null,r,o,e),[e]),r.flags|=2048,As(9,{destroy:void 0},fs.bind(null,r,o,n,t),null),n},useId:function(){var e=Qo(),t=pu.identifierPrefix;if(ea){var n=Ki,r=Gi;n=(r&~(1<<32-Xe(r)-1)).toString(32)+n,t=`_`+t+`R_`+n,n=zo++,0<n&&(t+=`H`+n.toString(32)),t+=`_`}else n=Ho++,t=`_`+t+`r_`+n.toString(32)+`_`;return e.memoizedState=t},useHostTransitionStatus:Qs,useFormState:Ts,useActionState:Ts,useOptimistic:function(e){var t=Qo();t.memoizedState=t.baseState=e;var n={pending:null,lanes:0,dispatch:null,lastRenderedReducer:null,lastRenderedState:null};return t.queue=n,t=ac.bind(null,j,!0,n),n.dispatch=t,[e,t]},useMemoCache:rs,useCacheRefresh:function(){return Qo().memoizedState=tc.bind(null,j)},useEffectEvent:function(e){var t=Qo(),n={impl:e};return t.memoizedState=n,function(){if(fu&2)throw Error(i(440));return n.impl.apply(void 0,arguments)}}},dc={readContext:xa,use:ns,useCallback:Us,useContext:xa,useEffect:Fs,useImperativeHandle:Vs,useInsertionEffect:Rs,useLayoutEffect:zs,useMemo:Ws,useReducer:ss,useRef:js,useState:function(){return ss(os)},useDebugValue:Hs,useDeferredValue:function(e,t){var n=$o();return Ks(n,Po.memoizedState,e,t)},useTransition:function(){var e=ss(os)[0],t=$o().memoizedState;return[typeof e==`boolean`?e:ts(e),t]},useSyncExternalStore:us,useId:$s,useHostTransitionStatus:Qs,useFormState:Es,useActionState:Es,useOptimistic:function(e,t){var n=$o();return _s(n,Po,e,t)},useMemoCache:rs,useCacheRefresh:ec};dc.useEffectEvent=Ls;var fc={readContext:xa,use:ns,useCallback:Us,useContext:xa,useEffect:Fs,useImperativeHandle:Vs,useInsertionEffect:Rs,useLayoutEffect:zs,useMemo:Ws,useReducer:ls,useRef:js,useState:function(){return ls(os)},useDebugValue:Hs,useDeferredValue:function(e,t){var n=$o();return Po===null?Gs(n,e,t):Ks(n,Po.memoizedState,e,t)},useTransition:function(){var e=ls(os)[0],t=$o().memoizedState;return[typeof e==`boolean`?e:ts(e),t]},useSyncExternalStore:us,useId:$s,useHostTransitionStatus:Qs,useFormState:ks,useActionState:ks,useOptimistic:function(e,t){var n=$o();return Po===null?(n.baseState=e,[e,n.queue.dispatch]):_s(n,Po,e,t)},useMemoCache:rs,useCacheRefresh:ec};fc.useEffectEvent=Ls;function pc(e,t,n,r){t=e.memoizedState,n=n(r,t),n=n==null?t:p({},t,n),e.memoizedState=n,e.lanes===0&&(e.updateQueue.baseState=n)}var mc={enqueueSetState:function(e,t,n){e=e._reactInternals;var r=Uu(),i=lo(r);i.payload=t,n!=null&&(i.callback=n),t=uo(e,i,r),t!==null&&(Gu(t,e,r),fo(t,e,r))},enqueueReplaceState:function(e,t,n){e=e._reactInternals;var r=Uu(),i=lo(r);i.tag=1,i.payload=t,n!=null&&(i.callback=n),t=uo(e,i,r),t!==null&&(Gu(t,e,r),fo(t,e,r))},enqueueForceUpdate:function(e,t){e=e._reactInternals;var n=Uu(),r=lo(n);r.tag=2,t!=null&&(r.callback=t),t=uo(e,r,n),t!==null&&(Gu(t,e,n),fo(t,e,n))}};function hc(e,t,n,r,i,a,o){return e=e.stateNode,typeof e.shouldComponentUpdate==`function`?e.shouldComponentUpdate(r,a,o):t.prototype&&t.prototype.isPureReactComponent?!Hr(n,r)||!Hr(i,a):!0}function gc(e,t,n,r){e=t.state,typeof t.componentWillReceiveProps==`function`&&t.componentWillReceiveProps(n,r),typeof t.UNSAFE_componentWillReceiveProps==`function`&&t.UNSAFE_componentWillReceiveProps(n,r),t.state!==e&&mc.enqueueReplaceState(t,t.state,null)}function _c(e,t){var n=t;if(`ref`in t)for(var r in n={},t)r!==`ref`&&(n[r]=t[r]);if(e=e.defaultProps)for(var i in n===t&&(n=p({},n)),e)n[i]===void 0&&(n[i]=e[i]);return n}function vc(e){hi(e)}function yc(e){console.error(e)}function bc(e){hi(e)}function xc(e,t){try{var n=e.onUncaughtError;n(t.value,{componentStack:t.stack})}catch(e){setTimeout(function(){throw e})}}function Sc(e,t,n){try{var r=e.onCaughtError;r(n.value,{componentStack:n.stack,errorBoundary:t.tag===1?t.stateNode:null})}catch(e){setTimeout(function(){throw e})}}function Cc(e,t,n){return n=lo(n),n.tag=3,n.payload={element:null},n.callback=function(){xc(e,t)},n}function wc(e){return e=lo(e),e.tag=3,e}function Tc(e,t,n,r){var i=n.type.getDerivedStateFromError;if(typeof i==`function`){var a=r.value;e.payload=function(){return i(a)},e.callback=function(){Sc(t,n,r)}}var o=n.stateNode;o!==null&&typeof o.componentDidCatch==`function`&&(e.callback=function(){Sc(t,n,r),typeof i!=`function`&&(Nu===null?Nu=new Set([this]):Nu.add(this));var e=r.stack;this.componentDidCatch(r.value,{componentStack:e===null?``:e})})}function Ec(e,t,n,r,a){if(n.flags|=32768,typeof r==`object`&&r&&typeof r.then==`function`){if(t=n.alternate,t!==null&&va(t,n,a,!0),n=wo.current,n!==null){switch(n.tag){case 31:case 13:return To===null?rd():n.alternate===null&&bu===0&&(bu=3),n.flags&=-257,n.flags|=65536,n.lanes=a,r===Ga?n.flags|=16384:(t=n.updateQueue,t===null?n.updateQueue=new Set([r]):t.add(r),Sd(e,r,a)),!1;case 22:return n.flags|=65536,r===Ga?n.flags|=16384:(t=n.updateQueue,t===null?(t={transitions:null,markerInstances:null,retryQueue:new Set([r])},n.updateQueue=t):(n=t.retryQueue,n===null?t.retryQueue=new Set([r]):n.add(r)),Sd(e,r,a)),!1}throw Error(i(435,n.tag))}return Sd(e,r,a),rd(),!1}if(ea)return t=wo.current,t===null?(r!==ra&&(t=Error(i(423),{cause:r}),ua(Li(t,n))),e=e.current.alternate,e.flags|=65536,a&=-a,e.lanes|=a,r=Li(r,n),a=Cc(e.stateNode,r,a),po(e,a),bu!==4&&(bu=2)):(!(t.flags&65536)&&(t.flags|=256),t.flags|=65536,t.lanes=a,r!==ra&&(e=Error(i(422),{cause:r}),ua(Li(e,n)))),!1;var o=Error(i(520),{cause:r});if(o=Li(o,n),Eu===null?Eu=[o]:Eu.push(o),bu!==4&&(bu=2),t===null)return!0;r=Li(r,n),n=t;do{switch(n.tag){case 3:return n.flags|=65536,e=a&-a,n.lanes|=e,e=Cc(n.stateNode,r,e),po(n,e),!1;case 1:if(t=n.type,o=n.stateNode,!(n.flags&128)&&(typeof t.getDerivedStateFromError==`function`||o!==null&&typeof o.componentDidCatch==`function`&&(Nu===null||!Nu.has(o))))return n.flags|=65536,a&=-a,n.lanes|=a,a=wc(a),Tc(a,e,n,r),po(n,a),!1}n=n.return}while(n!==null);return!1}var Dc=Error(i(461)),Oc=!1;function kc(e,t,n,r){t.child=e===null?ao(t,null,n,r):io(t,e.child,n,r)}function Ac(e,t,n,r,i){n=n.render;var a=t.ref;if(`ref`in r){var o={};for(var s in r)s!==`ref`&&(o[s]=r[s])}else o=r;return ba(t),r=Go(e,t,n,o,a,i),s=Yo(),e!==null&&!Oc?(Xo(e,t,i),el(e,t,i)):(ea&&s&&Yi(t),t.flags|=1,kc(e,t,r,i),t.child)}function jc(e,t,n,r,i){if(e===null){var a=n.type;return typeof a==`function`&&!Oi(a)&&a.defaultProps===void 0&&n.compare===null?(t.tag=15,t.type=a,Mc(e,t,a,r,i)):(e=ji(n.type,null,r,t,t.mode,i),e.ref=t.ref,e.return=t,t.child=e)}if(a=e.child,!tl(e,i)){var o=a.memoizedProps;if(n=n.compare,n=n===null?Hr:n,n(o,r)&&e.ref===t.ref)return el(e,t,i)}return t.flags|=1,e=ki(a,r),e.ref=t.ref,e.return=t,t.child=e}function Mc(e,t,n,r,i){if(e!==null){var a=e.memoizedProps;if(Hr(a,r)&&e.ref===t.ref)if(Oc=!1,t.pendingProps=r=a,tl(e,i))e.flags&131072&&(Oc=!0);else return t.lanes=e.lanes,el(e,t,i)}return Bc(e,t,n,r,i)}function Nc(e,t,n,r){var i=r.children,a=e===null?null:e.memoizedState;if(e===null&&t.stateNode===null&&(t.stateNode={_visibility:1,_pendingMarkers:null,_retryCache:null,_transitions:null}),r.mode===`hidden`){if(t.flags&128){if(a=a===null?n:a.baseLanes|n,e!==null){for(r=t.child=e.child,i=0;r!==null;)i=i|r.lanes|r.childLanes,r=r.sibling;r=i&~a}else r=0,t.child=null;return Fc(e,t,a,n,r)}if(n&536870912)t.memoizedState={baseLanes:0,cachePool:null},e!==null&&Ba(t,a===null?null:a.cachePool),a===null?So():xo(t,a),Oo(t);else return r=t.lanes=536870912,Fc(e,t,a===null?n:a.baseLanes|n,n,r)}else a===null?(e!==null&&Ba(t,null),So(),ko(t)):(Ba(t,a.cachePool),xo(t,a),ko(t),t.memoizedState=null);return kc(e,t,i,n),t.child}function Pc(e,t){return e!==null&&e.tag===22||t.stateNode!==null||(t.stateNode={_visibility:1,_pendingMarkers:null,_retryCache:null,_transitions:null}),t.sibling}function Fc(e,t,n,r,i){var a=za();return a=a===null?null:{parent:Da._currentValue,pool:a},t.memoizedState={baseLanes:n,cachePool:a},e!==null&&Ba(t,null),So(),Oo(t),e!==null&&va(e,t,r,!0),t.childLanes=i,null}function Ic(e,t){return t=Yc({mode:t.mode,children:t.children},e.mode),t.ref=e.ref,e.child=t,t.return=e,t}function Lc(e,t,n){return io(t,e.child,null,n),e=Ic(t,t.pendingProps),e.flags|=2,Ao(t),t.memoizedState=null,e}function Rc(e,t,n){var r=t.pendingProps,a=(t.flags&128)!=0;if(t.flags&=-129,e===null){if(ea){if(r.mode===`hidden`)return e=Ic(t,r),t.lanes=536870912,Pc(null,e);if(Do(t),(e=$i)?(e=Rf(e,na),e=e!==null&&e.data===`&`?e:null,e!==null&&(t.memoizedState={dehydrated:e,treeContext:Wi===null?null:{id:Gi,overflow:Ki},retryLane:536870912,hydrationErrors:null},n=Pi(e),n.return=t,t.child=n,Qi=t,$i=null)):e=null,e===null)throw ia(t);return t.lanes=536870912,null}return Ic(t,r)}var o=e.memoizedState;if(o!==null){var s=o.dehydrated;if(Do(t),a)if(t.flags&256)t.flags&=-257,t=Lc(e,t,n);else if(t.memoizedState!==null)t.child=e.child,t.flags|=128,t=null;else throw Error(i(558));else if(Oc||va(e,t,n,!1),a=(n&e.childLanes)!==0,Oc||a){if(r=pu,r!==null&&(s=pt(r,n),s!==0&&s!==o.retryLane))throw o.retryLane=s,Si(e,s),Gu(r,e,s),Dc;rd(),t=Lc(e,t,n)}else e=o.treeContext,$i=Hf(s.nextSibling),Qi=t,ea=!0,ta=null,na=!1,e!==null&&Zi(t,e),t=Ic(t,r),t.flags|=4096;return t}return e=ki(e.child,{mode:r.mode,children:r.children}),e.ref=t.ref,t.child=e,e.return=t,e}function zc(e,t){var n=t.ref;if(n===null)e!==null&&e.ref!==null&&(t.flags|=4194816);else{if(typeof n!=`function`&&typeof n!=`object`)throw Error(i(284));(e===null||e.ref!==n)&&(t.flags|=4194816)}}function Bc(e,t,n,r,i){return ba(t),n=Go(e,t,n,r,void 0,i),r=Yo(),e!==null&&!Oc?(Xo(e,t,i),el(e,t,i)):(ea&&r&&Yi(t),t.flags|=1,kc(e,t,n,i),t.child)}function Vc(e,t,n,r,i,a){return ba(t),t.updateQueue=null,n=qo(t,r,n,i),Ko(e),r=Yo(),e!==null&&!Oc?(Xo(e,t,a),el(e,t,a)):(ea&&r&&Yi(t),t.flags|=1,kc(e,t,n,a),t.child)}function Hc(e,t,n,r,i){if(ba(t),t.stateNode===null){var a=Ti,o=n.contextType;typeof o==`object`&&o&&(a=xa(o)),a=new n(r,a),t.memoizedState=a.state!==null&&a.state!==void 0?a.state:null,a.updater=mc,t.stateNode=a,a._reactInternals=t,a=t.stateNode,a.props=r,a.state=t.memoizedState,a.refs={},so(t),o=n.contextType,a.context=typeof o==`object`&&o?xa(o):Ti,a.state=t.memoizedState,o=n.getDerivedStateFromProps,typeof o==`function`&&(pc(t,n,o,r),a.state=t.memoizedState),typeof n.getDerivedStateFromProps==`function`||typeof a.getSnapshotBeforeUpdate==`function`||typeof a.UNSAFE_componentWillMount!=`function`&&typeof a.componentWillMount!=`function`||(o=a.state,typeof a.componentWillMount==`function`&&a.componentWillMount(),typeof a.UNSAFE_componentWillMount==`function`&&a.UNSAFE_componentWillMount(),o!==a.state&&mc.enqueueReplaceState(a,a.state,null),go(t,r,a,i),ho(),a.state=t.memoizedState),typeof a.componentDidMount==`function`&&(t.flags|=4194308),r=!0}else if(e===null){a=t.stateNode;var s=t.memoizedProps,c=_c(n,s);a.props=c;var l=a.context,u=n.contextType;o=Ti,typeof u==`object`&&u&&(o=xa(u));var d=n.getDerivedStateFromProps;u=typeof d==`function`||typeof a.getSnapshotBeforeUpdate==`function`,s=t.pendingProps!==s,u||typeof a.UNSAFE_componentWillReceiveProps!=`function`&&typeof a.componentWillReceiveProps!=`function`||(s||l!==o)&&gc(t,a,r,o),oo=!1;var f=t.memoizedState;a.state=f,go(t,r,a,i),ho(),l=t.memoizedState,s||f!==l||oo?(typeof d==`function`&&(pc(t,n,d,r),l=t.memoizedState),(c=oo||hc(t,n,c,r,f,l,o))?(u||typeof a.UNSAFE_componentWillMount!=`function`&&typeof a.componentWillMount!=`function`||(typeof a.componentWillMount==`function`&&a.componentWillMount(),typeof a.UNSAFE_componentWillMount==`function`&&a.UNSAFE_componentWillMount()),typeof a.componentDidMount==`function`&&(t.flags|=4194308)):(typeof a.componentDidMount==`function`&&(t.flags|=4194308),t.memoizedProps=r,t.memoizedState=l),a.props=r,a.state=l,a.context=o,r=c):(typeof a.componentDidMount==`function`&&(t.flags|=4194308),r=!1)}else{a=t.stateNode,co(e,t),o=t.memoizedProps,u=_c(n,o),a.props=u,d=t.pendingProps,f=a.context,l=n.contextType,c=Ti,typeof l==`object`&&l&&(c=xa(l)),s=n.getDerivedStateFromProps,(l=typeof s==`function`||typeof a.getSnapshotBeforeUpdate==`function`)||typeof a.UNSAFE_componentWillReceiveProps!=`function`&&typeof a.componentWillReceiveProps!=`function`||(o!==d||f!==c)&&gc(t,a,r,c),oo=!1,f=t.memoizedState,a.state=f,go(t,r,a,i),ho();var p=t.memoizedState;o!==d||f!==p||oo||e!==null&&e.dependencies!==null&&ya(e.dependencies)?(typeof s==`function`&&(pc(t,n,s,r),p=t.memoizedState),(u=oo||hc(t,n,u,r,f,p,c)||e!==null&&e.dependencies!==null&&ya(e.dependencies))?(l||typeof a.UNSAFE_componentWillUpdate!=`function`&&typeof a.componentWillUpdate!=`function`||(typeof a.componentWillUpdate==`function`&&a.componentWillUpdate(r,p,c),typeof a.UNSAFE_componentWillUpdate==`function`&&a.UNSAFE_componentWillUpdate(r,p,c)),typeof a.componentDidUpdate==`function`&&(t.flags|=4),typeof a.getSnapshotBeforeUpdate==`function`&&(t.flags|=1024)):(typeof a.componentDidUpdate!=`function`||o===e.memoizedProps&&f===e.memoizedState||(t.flags|=4),typeof a.getSnapshotBeforeUpdate!=`function`||o===e.memoizedProps&&f===e.memoizedState||(t.flags|=1024),t.memoizedProps=r,t.memoizedState=p),a.props=r,a.state=p,a.context=c,r=u):(typeof a.componentDidUpdate!=`function`||o===e.memoizedProps&&f===e.memoizedState||(t.flags|=4),typeof a.getSnapshotBeforeUpdate!=`function`||o===e.memoizedProps&&f===e.memoizedState||(t.flags|=1024),r=!1)}return a=r,zc(e,t),r=(t.flags&128)!=0,a||r?(a=t.stateNode,n=r&&typeof n.getDerivedStateFromError!=`function`?null:a.render(),t.flags|=1,e!==null&&r?(t.child=io(t,e.child,null,i),t.child=io(t,null,n,i)):kc(e,t,n,i),t.memoizedState=a.state,e=t.child):e=el(e,t,i),e}function Uc(e,t,n,r){return ca(),t.flags|=256,kc(e,t,n,r),t.child}var Wc={dehydrated:null,treeContext:null,retryLane:0,hydrationErrors:null};function Gc(e){return{baseLanes:e,cachePool:Va()}}function Kc(e,t,n){return e=e===null?0:e.childLanes&~n,t&&(e|=wu),e}function qc(e,t,n){var r=t.pendingProps,a=!1,o=(t.flags&128)!=0,s;if((s=o)||(s=e!==null&&e.memoizedState===null?!1:(jo.current&2)!=0),s&&(a=!0,t.flags&=-129),s=(t.flags&32)!=0,t.flags&=-33,e===null){if(ea){if(a?Eo(t):ko(t),(e=$i)?(e=Rf(e,na),e=e!==null&&e.data!==`&`?e:null,e!==null&&(t.memoizedState={dehydrated:e,treeContext:Wi===null?null:{id:Gi,overflow:Ki},retryLane:536870912,hydrationErrors:null},n=Pi(e),n.return=t,t.child=n,Qi=t,$i=null)):e=null,e===null)throw ia(t);return Bf(e)?t.lanes=32:t.lanes=536870912,null}var c=r.children;return r=r.fallback,a?(ko(t),a=t.mode,c=Yc({mode:`hidden`,children:c},a),r=Mi(r,a,n,null),c.return=t,r.return=t,c.sibling=r,t.child=c,r=t.child,r.memoizedState=Gc(n),r.childLanes=Kc(e,s,n),t.memoizedState=Wc,Pc(null,r)):(Eo(t),Jc(t,c))}var l=e.memoizedState;if(l!==null&&(c=l.dehydrated,c!==null)){if(o)t.flags&256?(Eo(t),t.flags&=-257,t=Xc(e,t,n)):t.memoizedState===null?(ko(t),c=r.fallback,a=t.mode,r=Yc({mode:`visible`,children:r.children},a),c=Mi(c,a,n,null),c.flags|=2,r.return=t,c.return=t,r.sibling=c,t.child=r,io(t,e.child,null,n),r=t.child,r.memoizedState=Gc(n),r.childLanes=Kc(e,s,n),t.memoizedState=Wc,t=Pc(null,r)):(ko(t),t.child=e.child,t.flags|=128,t=null);else if(Eo(t),Bf(c)){if(s=c.nextSibling&&c.nextSibling.dataset,s)var u=s.dgst;s=u,r=Error(i(419)),r.stack=``,r.digest=s,ua({value:r,source:null,stack:null}),t=Xc(e,t,n)}else if(Oc||va(e,t,n,!1),s=(n&e.childLanes)!==0,Oc||s){if(s=pu,s!==null&&(r=pt(s,n),r!==0&&r!==l.retryLane))throw l.retryLane=r,Si(e,r),Gu(s,e,r),Dc;zf(c)||rd(),t=Xc(e,t,n)}else zf(c)?(t.flags|=192,t.child=e.child,t=null):(e=l.treeContext,$i=Hf(c.nextSibling),Qi=t,ea=!0,ta=null,na=!1,e!==null&&Zi(t,e),t=Jc(t,r.children),t.flags|=4096);return t}return a?(ko(t),c=r.fallback,a=t.mode,l=e.child,u=l.sibling,r=ki(l,{mode:`hidden`,children:r.children}),r.subtreeFlags=l.subtreeFlags&65011712,u===null?(c=Mi(c,a,n,null),c.flags|=2):c=ki(u,c),c.return=t,r.return=t,r.sibling=c,t.child=r,Pc(null,r),r=t.child,c=e.child.memoizedState,c===null?c=Gc(n):(a=c.cachePool,a===null?a=Va():(l=Da._currentValue,a=a.parent===l?a:{parent:l,pool:l}),c={baseLanes:c.baseLanes|n,cachePool:a}),r.memoizedState=c,r.childLanes=Kc(e,s,n),t.memoizedState=Wc,Pc(e.child,r)):(Eo(t),n=e.child,e=n.sibling,n=ki(n,{mode:`visible`,children:r.children}),n.return=t,n.sibling=null,e!==null&&(s=t.deletions,s===null?(t.deletions=[e],t.flags|=16):s.push(e)),t.child=n,t.memoizedState=null,n)}function Jc(e,t){return t=Yc({mode:`visible`,children:t},e.mode),t.return=e,e.child=t}function Yc(e,t){return e=Di(22,e,null,t),e.lanes=0,e}function Xc(e,t,n){return io(t,e.child,null,n),e=Jc(t,t.pendingProps.children),e.flags|=2,t.memoizedState=null,e}function Zc(e,t,n){e.lanes|=t;var r=e.alternate;r!==null&&(r.lanes|=t),ga(e.return,t,n)}function Qc(e,t,n,r,i,a){var o=e.memoizedState;o===null?e.memoizedState={isBackwards:t,rendering:null,renderingStartTime:0,last:r,tail:n,tailMode:i,treeForkCount:a}:(o.isBackwards=t,o.rendering=null,o.renderingStartTime=0,o.last=r,o.tail=n,o.tailMode=i,o.treeForkCount=a)}function $c(e,t,n){var r=t.pendingProps,i=r.revealOrder,a=r.tail;r=r.children;var o=jo.current,s=(o&2)!=0;if(s?(o=o&1|2,t.flags|=128):o&=1,_e(jo,o),kc(e,t,r,n),r=ea?Vi:0,!s&&e!==null&&e.flags&128)a:for(e=t.child;e!==null;){if(e.tag===13)e.memoizedState!==null&&Zc(e,n,t);else if(e.tag===19)Zc(e,n,t);else if(e.child!==null){e.child.return=e,e=e.child;continue}if(e===t)break a;for(;e.sibling===null;){if(e.return===null||e.return===t)break a;e=e.return}e.sibling.return=e.return,e=e.sibling}switch(i){case`forwards`:for(n=t.child,i=null;n!==null;)e=n.alternate,e!==null&&Mo(e)===null&&(i=n),n=n.sibling;n=i,n===null?(i=t.child,t.child=null):(i=n.sibling,n.sibling=null),Qc(t,!1,i,n,a,r);break;case`backwards`:case`unstable_legacy-backwards`:for(n=null,i=t.child,t.child=null;i!==null;){if(e=i.alternate,e!==null&&Mo(e)===null){t.child=i;break}e=i.sibling,i.sibling=n,n=i,i=e}Qc(t,!0,n,null,a,r);break;case`together`:Qc(t,!1,null,null,void 0,r);break;default:t.memoizedState=null}return t.child}function el(e,t,n){if(e!==null&&(t.dependencies=e.dependencies),xu|=t.lanes,(n&t.childLanes)===0)if(e!==null){if(va(e,t,n,!1),(n&t.childLanes)===0)return null}else return null;if(e!==null&&t.child!==e.child)throw Error(i(153));if(t.child!==null){for(e=t.child,n=ki(e,e.pendingProps),t.child=n,n.return=t;e.sibling!==null;)e=e.sibling,n=n.sibling=ki(e,e.pendingProps),n.return=t;n.sibling=null}return t.child}function tl(e,t){return(e.lanes&t)===0?(e=e.dependencies,!!(e!==null&&ya(e))):!0}function nl(e,t,n){switch(t.tag){case 3:Se(t,t.stateNode.containerInfo),ma(t,Da,e.memoizedState.cache),ca();break;case 27:case 5:we(t);break;case 4:Se(t,t.stateNode.containerInfo);break;case 10:ma(t,t.type,t.memoizedProps.value);break;case 31:if(t.memoizedState!==null)return t.flags|=128,Do(t),null;break;case 13:var r=t.memoizedState;if(r!==null)return r.dehydrated===null?(n&t.child.childLanes)===0?(Eo(t),e=el(e,t,n),e===null?null:e.sibling):qc(e,t,n):(Eo(t),t.flags|=128,null);Eo(t);break;case 19:var i=(e.flags&128)!=0;if(r=(n&t.childLanes)!==0,r||=(va(e,t,n,!1),(n&t.childLanes)!==0),i){if(r)return $c(e,t,n);t.flags|=128}if(i=t.memoizedState,i!==null&&(i.rendering=null,i.tail=null,i.lastEffect=null),_e(jo,jo.current),r)break;return null;case 22:return t.lanes=0,Nc(e,t,n,t.pendingProps);case 24:ma(t,Da,e.memoizedState.cache)}return el(e,t,n)}function rl(e,t,n){if(e!==null)if(e.memoizedProps!==t.pendingProps)Oc=!0;else{if(!tl(e,n)&&!(t.flags&128))return Oc=!1,nl(e,t,n);Oc=!!(e.flags&131072)}else Oc=!1,ea&&t.flags&1048576&&Ji(t,Vi,t.index);switch(t.lanes=0,t.tag){case 16:a:{var r=t.pendingProps;if(e=Ja(t.elementType),t.type=e,typeof e==`function`)Oi(e)?(r=_c(e,r),t.tag=1,t=Hc(null,t,e,r,n)):(t.tag=0,t=Bc(null,t,e,r,n));else{if(e!=null){var a=e.$$typeof;if(a===w){t.tag=11,t=Ac(null,t,e,r,n);break a}else if(a===ne){t.tag=14,t=jc(null,t,e,r,n);break a}}throw t=le(e)||e,Error(i(306,t,``))}}return t;case 0:return Bc(e,t,t.type,t.pendingProps,n);case 1:return r=t.type,a=_c(r,t.pendingProps),Hc(e,t,r,a,n);case 3:a:{if(Se(t,t.stateNode.containerInfo),e===null)throw Error(i(387));r=t.pendingProps;var o=t.memoizedState;a=o.element,co(e,t),go(t,r,null,n);var s=t.memoizedState;if(r=s.cache,ma(t,Da,r),r!==o.cache&&_a(t,[Da],n,!0),ho(),r=s.element,o.isDehydrated)if(o={element:r,isDehydrated:!1,cache:s.cache},t.updateQueue.baseState=o,t.memoizedState=o,t.flags&256){t=Uc(e,t,r,n);break a}else if(r!==a){a=Li(Error(i(424)),t),ua(a),t=Uc(e,t,r,n);break a}else{switch(e=t.stateNode.containerInfo,e.nodeType){case 9:e=e.body;break;default:e=e.nodeName===`HTML`?e.ownerDocument.body:e}for($i=Hf(e.firstChild),Qi=t,ea=!0,ta=null,na=!0,n=ao(t,null,r,n),t.child=n;n;)n.flags=n.flags&-3|4096,n=n.sibling}else{if(ca(),r===a){t=el(e,t,n);break a}kc(e,t,r,n)}t=t.child}return t;case 26:return zc(e,t),e===null?(n=cp(t.type,null,t.pendingProps,null))?t.memoizedState=n:ea||(n=t.type,e=t.pendingProps,r=xf(be.current).createElement(n),r[yt]=t,r[bt]=e,hf(r,n,e),jt(r),t.stateNode=r):t.memoizedState=cp(t.type,e.memoizedProps,t.pendingProps,e.memoizedState),null;case 27:return we(t),e===null&&ea&&(r=t.stateNode=Gf(t.type,t.pendingProps,be.current),Qi=t,na=!0,a=$i,Mf(t.type)?(I=a,$i=Hf(r.firstChild)):$i=a),kc(e,t,t.pendingProps.children,n),zc(e,t),e===null&&(t.flags|=4194304),t.child;case 5:return e===null&&ea&&((a=r=$i)&&(r=If(r,t.type,t.pendingProps,na),r===null?a=!1:(t.stateNode=r,Qi=t,$i=Hf(r.firstChild),na=!1,a=!0)),a||ia(t)),we(t),a=t.type,o=t.pendingProps,s=e===null?null:e.memoizedProps,r=o.children,wf(a,o)?r=null:s!==null&&wf(a,s)&&(t.flags|=32),t.memoizedState!==null&&(a=Go(e,t,Jo,null,null,n),jp._currentValue=a),zc(e,t),kc(e,t,r,n),t.child;case 6:return e===null&&ea&&((e=n=$i)&&(n=Lf(n,t.pendingProps,na),n===null?e=!1:(t.stateNode=n,Qi=t,$i=null,e=!0)),e||ia(t)),null;case 13:return qc(e,t,n);case 4:return Se(t,t.stateNode.containerInfo),r=t.pendingProps,e===null?t.child=io(t,null,r,n):kc(e,t,r,n),t.child;case 11:return Ac(e,t,t.type,t.pendingProps,n);case 7:return kc(e,t,t.pendingProps,n),t.child;case 8:return kc(e,t,t.pendingProps.children,n),t.child;case 12:return kc(e,t,t.pendingProps.children,n),t.child;case 10:return r=t.pendingProps,ma(t,t.type,r.value),kc(e,t,r.children,n),t.child;case 9:return a=t.type._context,r=t.pendingProps.children,ba(t),a=xa(a),r=r(a),t.flags|=1,kc(e,t,r,n),t.child;case 14:return jc(e,t,t.type,t.pendingProps,n);case 15:return Mc(e,t,t.type,t.pendingProps,n);case 19:return $c(e,t,n);case 31:return Rc(e,t,n);case 22:return Nc(e,t,n,t.pendingProps);case 24:return ba(t),r=xa(Da),e===null?(a=za(),a===null&&(a=pu,o=Oa(),a.pooledCache=o,o.refCount++,o!==null&&(a.pooledCacheLanes|=n),a=o),t.memoizedState={parent:r,cache:a},so(t),ma(t,Da,a)):((e.lanes&n)!==0&&(co(e,t),go(t,null,null,n),ho()),a=e.memoizedState,o=t.memoizedState,a.parent===r?(r=o.cache,ma(t,Da,r),r!==a.cache&&_a(t,[Da],n,!0)):(a={parent:r,cache:r},t.memoizedState=a,t.lanes===0&&(t.memoizedState=t.updateQueue.baseState=a),ma(t,Da,r))),kc(e,t,t.pendingProps.children,n),t.child;case 29:throw t.pendingProps}throw Error(i(156,t.tag))}function il(e){e.flags|=4}function al(e,t,n,r,i){if((t=(e.mode&32)!=0)&&(t=!1),t){if(e.flags|=16777216,(i&335544128)===i)if(e.stateNode.complete)e.flags|=8192;else if(ed())e.flags|=8192;else throw Ya=Ga,Ua}else e.flags&=-16777217}function ol(e,t){if(t.type!==`stylesheet`||t.state.loading&4)e.flags&=-16777217;else if(e.flags|=16777216,!Cp(t))if(ed())e.flags|=8192;else throw Ya=Ga,Ua}function sl(e,t){t!==null&&(e.flags|=4),e.flags&16384&&(t=e.tag===22?536870912:st(),e.lanes|=t,Tu|=t)}function cl(e,t){if(!ea)switch(e.tailMode){case`hidden`:t=e.tail;for(var n=null;t!==null;)t.alternate!==null&&(n=t),t=t.sibling;n===null?e.tail=null:n.sibling=null;break;case`collapsed`:n=e.tail;for(var r=null;n!==null;)n.alternate!==null&&(r=n),n=n.sibling;r===null?t||e.tail===null?e.tail=null:e.tail.sibling=null:r.sibling=null}}function ll(e){var t=e.alternate!==null&&e.alternate.child===e.child,n=0,r=0;if(t)for(var i=e.child;i!==null;)n|=i.lanes|i.childLanes,r|=i.subtreeFlags&65011712,r|=i.flags&65011712,i.return=e,i=i.sibling;else for(i=e.child;i!==null;)n|=i.lanes|i.childLanes,r|=i.subtreeFlags,r|=i.flags,i.return=e,i=i.sibling;return e.subtreeFlags|=r,e.childLanes=n,t}function ul(e,t,n){var r=t.pendingProps;switch(Xi(t),t.tag){case 16:case 15:case 0:case 11:case 7:case 8:case 12:case 9:case 14:return ll(t),null;case 1:return ll(t),null;case 3:return n=t.stateNode,r=null,e!==null&&(r=e.memoizedState.cache),t.memoizedState.cache!==r&&(t.flags|=2048),ha(Da),Ce(),n.pendingContext&&=(n.context=n.pendingContext,null),(e===null||e.child===null)&&(sa(t)?il(t):e===null||e.memoizedState.isDehydrated&&!(t.flags&256)||(t.flags|=1024,la())),ll(t),null;case 26:var a=t.type,o=t.memoizedState;return e===null?(il(t),o===null?(ll(t),al(t,a,null,r,n)):(ll(t),ol(t,o))):o?o===e.memoizedState?(ll(t),t.flags&=-16777217):(il(t),ll(t),ol(t,o)):(e=e.memoizedProps,e!==r&&il(t),ll(t),al(t,a,e,r,n)),null;case 27:if(Te(t),n=be.current,a=t.type,e!==null&&t.stateNode!=null)e.memoizedProps!==r&&il(t);else{if(!r){if(t.stateNode===null)throw Error(i(166));return ll(t),null}e=ve.current,sa(t)?aa(t,e):(e=Gf(a,r,n),t.stateNode=e,il(t))}return ll(t),null;case 5:if(Te(t),a=t.type,e!==null&&t.stateNode!=null)e.memoizedProps!==r&&il(t);else{if(!r){if(t.stateNode===null)throw Error(i(166));return ll(t),null}if(o=ve.current,sa(t))aa(t,o);else{var s=xf(be.current);switch(o){case 1:o=s.createElementNS(`http://www.w3.org/2000/svg`,a);break;case 2:o=s.createElementNS(`http://www.w3.org/1998/Math/MathML`,a);break;default:switch(a){case`svg`:o=s.createElementNS(`http://www.w3.org/2000/svg`,a);break;case`math`:o=s.createElementNS(`http://www.w3.org/1998/Math/MathML`,a);break;case`script`:o=s.createElement(`div`),o.innerHTML=`<script><\\/script>`,o=o.removeChild(o.firstChild);break;case`select`:o=typeof r.is==`string`?s.createElement(`select`,{is:r.is}):s.createElement(`select`),r.multiple?o.multiple=!0:r.size&&(o.size=r.size);break;default:o=typeof r.is==`string`?s.createElement(a,{is:r.is}):s.createElement(a)}}o[yt]=t,o[bt]=r;a:for(s=t.child;s!==null;){if(s.tag===5||s.tag===6)o.appendChild(s.stateNode);else if(s.tag!==4&&s.tag!==27&&s.child!==null){s.child.return=s,s=s.child;continue}if(s===t)break a;for(;s.sibling===null;){if(s.return===null||s.return===t)break a;s=s.return}s.sibling.return=s.return,s=s.sibling}t.stateNode=o;a:switch(hf(o,a,r),a){case`button`:case`input`:case`select`:case`textarea`:r=!!r.autoFocus;break a;case`img`:r=!0;break a;default:r=!1}r&&il(t)}}return ll(t),al(t,t.type,e===null?null:e.memoizedProps,t.pendingProps,n),null;case 6:if(e&&t.stateNode!=null)e.memoizedProps!==r&&il(t);else{if(typeof r!=`string`&&t.stateNode===null)throw Error(i(166));if(e=be.current,sa(t)){if(e=t.stateNode,n=t.memoizedProps,r=null,a=Qi,a!==null)switch(a.tag){case 27:case 5:r=a.memoizedProps}e[yt]=t,e=!!(e.nodeValue===n||r!==null&&!0===r.suppressHydrationWarning||ff(e.nodeValue,n)),e||ia(t,!0)}else e=xf(e).createTextNode(r),e[yt]=t,t.stateNode=e}return ll(t),null;case 31:if(n=t.memoizedState,e===null||e.memoizedState!==null){if(r=sa(t),n!==null){if(e===null){if(!r)throw Error(i(318));if(e=t.memoizedState,e=e===null?null:e.dehydrated,!e)throw Error(i(557));e[yt]=t}else ca(),!(t.flags&128)&&(t.memoizedState=null),t.flags|=4;ll(t),e=!1}else n=la(),e!==null&&e.memoizedState!==null&&(e.memoizedState.hydrationErrors=n),e=!0;if(!e)return t.flags&256?(Ao(t),t):(Ao(t),null);if(t.flags&128)throw Error(i(558))}return ll(t),null;case 13:if(r=t.memoizedState,e===null||e.memoizedState!==null&&e.memoizedState.dehydrated!==null){if(a=sa(t),r!==null&&r.dehydrated!==null){if(e===null){if(!a)throw Error(i(318));if(a=t.memoizedState,a=a===null?null:a.dehydrated,!a)throw Error(i(317));a[yt]=t}else ca(),!(t.flags&128)&&(t.memoizedState=null),t.flags|=4;ll(t),a=!1}else a=la(),e!==null&&e.memoizedState!==null&&(e.memoizedState.hydrationErrors=a),a=!0;if(!a)return t.flags&256?(Ao(t),t):(Ao(t),null)}return Ao(t),t.flags&128?(t.lanes=n,t):(n=r!==null,e=e!==null&&e.memoizedState!==null,n&&(r=t.child,a=null,r.alternate!==null&&r.alternate.memoizedState!==null&&r.alternate.memoizedState.cachePool!==null&&(a=r.alternate.memoizedState.cachePool.pool),o=null,r.memoizedState!==null&&r.memoizedState.cachePool!==null&&(o=r.memoizedState.cachePool.pool),o!==a&&(r.flags|=2048)),n!==e&&n&&(t.child.flags|=8192),sl(t,t.updateQueue),ll(t),null);case 4:return Ce(),e===null&&ef(t.stateNode.containerInfo),ll(t),null;case 10:return ha(t.type),ll(t),null;case 19:if(ge(jo),r=t.memoizedState,r===null)return ll(t),null;if(a=(t.flags&128)!=0,o=r.rendering,o===null)if(a)cl(r,!1);else{if(bu!==0||e!==null&&e.flags&128)for(e=t.child;e!==null;){if(o=Mo(e),o!==null){for(t.flags|=128,cl(r,!1),e=o.updateQueue,t.updateQueue=e,sl(t,e),t.subtreeFlags=0,e=n,n=t.child;n!==null;)Ai(n,e),n=n.sibling;return _e(jo,jo.current&1|2),ea&&qi(t,r.treeForkCount),t.child}e=e.sibling}r.tail!==null&&Re()>ju&&(t.flags|=128,a=!0,cl(r,!1),t.lanes=4194304)}else{if(!a)if(e=Mo(o),e!==null){if(t.flags|=128,a=!0,e=e.updateQueue,t.updateQueue=e,sl(t,e),cl(r,!0),r.tail===null&&r.tailMode===`hidden`&&!o.alternate&&!ea)return ll(t),null}else 2*Re()-r.renderingStartTime>ju&&n!==536870912&&(t.flags|=128,a=!0,cl(r,!1),t.lanes=4194304);r.isBackwards?(o.sibling=t.child,t.child=o):(e=r.last,e===null?t.child=o:e.sibling=o,r.last=o)}return r.tail===null?(ll(t),null):(e=r.tail,r.rendering=e,r.tail=e.sibling,r.renderingStartTime=Re(),e.sibling=null,n=jo.current,_e(jo,a?n&1|2:n&1),ea&&qi(t,r.treeForkCount),e);case 22:case 23:return Ao(t),Co(),r=t.memoizedState!==null,e===null?r&&(t.flags|=8192):e.memoizedState!==null!==r&&(t.flags|=8192),r?n&536870912&&!(t.flags&128)&&(ll(t),t.subtreeFlags&6&&(t.flags|=8192)):ll(t),n=t.updateQueue,n!==null&&sl(t,n.retryQueue),n=null,e!==null&&e.memoizedState!==null&&e.memoizedState.cachePool!==null&&(n=e.memoizedState.cachePool.pool),r=null,t.memoizedState!==null&&t.memoizedState.cachePool!==null&&(r=t.memoizedState.cachePool.pool),r!==n&&(t.flags|=2048),e!==null&&ge(Ra),null;case 24:return n=null,e!==null&&(n=e.memoizedState.cache),t.memoizedState.cache!==n&&(t.flags|=2048),ha(Da),ll(t),null;case 25:return null;case 30:return null}throw Error(i(156,t.tag))}function dl(e,t){switch(Xi(t),t.tag){case 1:return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 3:return ha(Da),Ce(),e=t.flags,e&65536&&!(e&128)?(t.flags=e&-65537|128,t):null;case 26:case 27:case 5:return Te(t),null;case 31:if(t.memoizedState!==null){if(Ao(t),t.alternate===null)throw Error(i(340));ca()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 13:if(Ao(t),e=t.memoizedState,e!==null&&e.dehydrated!==null){if(t.alternate===null)throw Error(i(340));ca()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 19:return ge(jo),null;case 4:return Ce(),null;case 10:return ha(t.type),null;case 22:case 23:return Ao(t),Co(),e!==null&&ge(Ra),e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 24:return ha(Da),null;case 25:return null;default:return null}}function fl(e,t){switch(Xi(t),t.tag){case 3:ha(Da),Ce();break;case 26:case 27:case 5:Te(t);break;case 4:Ce();break;case 31:t.memoizedState!==null&&Ao(t);break;case 13:Ao(t);break;case 19:ge(jo);break;case 10:ha(t.type);break;case 22:case 23:Ao(t),Co(),e!==null&&ge(Ra);break;case 24:ha(Da)}}function pl(e,t){try{var n=t.updateQueue,r=n===null?null:n.lastEffect;if(r!==null){var i=r.next;n=i;do{if((n.tag&e)===e){r=void 0;var a=n.create,o=n.inst;r=a(),o.destroy=r}n=n.next}while(n!==i)}}catch(e){xd(t,t.return,e)}}function ml(e,t,n){try{var r=t.updateQueue,i=r===null?null:r.lastEffect;if(i!==null){var a=i.next;r=a;do{if((r.tag&e)===e){var o=r.inst,s=o.destroy;if(s!==void 0){o.destroy=void 0,i=t;var c=n,l=s;try{l()}catch(e){xd(i,c,e)}}}r=r.next}while(r!==a)}}catch(e){xd(t,t.return,e)}}function hl(e){var t=e.updateQueue;if(t!==null){var n=e.stateNode;try{vo(t,n)}catch(t){xd(e,e.return,t)}}}function gl(e,t,n){n.props=_c(e.type,e.memoizedProps),n.state=e.memoizedState;try{n.componentWillUnmount()}catch(n){xd(e,t,n)}}function _l(e,t){try{var n=e.ref;if(n!==null){switch(e.tag){case 26:case 27:case 5:var r=e.stateNode;break;case 30:r=e.stateNode;break;default:r=e.stateNode}typeof n==`function`?e.refCleanup=n(r):n.current=r}}catch(n){xd(e,t,n)}}function vl(e,t){var n=e.ref,r=e.refCleanup;if(n!==null)if(typeof r==`function`)try{r()}catch(n){xd(e,t,n)}finally{e.refCleanup=null,e=e.alternate,e!=null&&(e.refCleanup=null)}else if(typeof n==`function`)try{n(null)}catch(n){xd(e,t,n)}else n.current=null}function yl(e){var t=e.type,n=e.memoizedProps,r=e.stateNode;try{a:switch(t){case`button`:case`input`:case`select`:case`textarea`:n.autoFocus&&r.focus();break a;case`img`:n.src?r.src=n.src:n.srcSet&&(r.srcset=n.srcSet)}}catch(t){xd(e,e.return,t)}}function bl(e,t,n){try{var r=e.stateNode;gf(r,e.type,n,t),r[bt]=t}catch(t){xd(e,e.return,t)}}function xl(e){return e.tag===5||e.tag===3||e.tag===26||e.tag===27&&Mf(e.type)||e.tag===4}function Sl(e){a:for(;;){for(;e.sibling===null;){if(e.return===null||xl(e.return))return null;e=e.return}for(e.sibling.return=e.return,e=e.sibling;e.tag!==5&&e.tag!==6&&e.tag!==18;){if(e.tag===27&&Mf(e.type)||e.flags&2||e.child===null||e.tag===4)continue a;e.child.return=e,e=e.child}if(!(e.flags&2))return e.stateNode}}function Cl(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?(n.nodeType===9?n.body:n.nodeName===`HTML`?n.ownerDocument.body:n).insertBefore(e,t):(t=n.nodeType===9?n.body:n.nodeName===`HTML`?n.ownerDocument.body:n,t.appendChild(e),n=n._reactRootContainer,n!=null||t.onclick!==null||(t.onclick=un));else if(r!==4&&(r===27&&Mf(e.type)&&(n=e.stateNode,t=null),e=e.child,e!==null))for(Cl(e,t,n),e=e.sibling;e!==null;)Cl(e,t,n),e=e.sibling}function wl(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?n.insertBefore(e,t):n.appendChild(e);else if(r!==4&&(r===27&&Mf(e.type)&&(n=e.stateNode),e=e.child,e!==null))for(wl(e,t,n),e=e.sibling;e!==null;)wl(e,t,n),e=e.sibling}function Tl(e){var t=e.stateNode,n=e.memoizedProps;try{for(var r=e.type,i=t.attributes;i.length;)t.removeAttributeNode(i[0]);hf(t,r,n),t[yt]=e,t[bt]=n}catch(t){xd(e,e.return,t)}}var El=!1,Dl=!1,Ol=!1,kl=typeof WeakSet==`function`?WeakSet:Set,Al=null;function jl(e,t){if(e=e.containerInfo,yf=Bp,e=Kr(e),qr(e)){if(`selectionStart`in e)var n={start:e.selectionStart,end:e.selectionEnd};else a:{n=(n=e.ownerDocument)&&n.defaultView||window;var r=n.getSelection&&n.getSelection();if(r&&r.rangeCount!==0){n=r.anchorNode;var a=r.anchorOffset,o=r.focusNode;r=r.focusOffset;try{n.nodeType,o.nodeType}catch{n=null;break a}var s=0,c=-1,l=-1,u=0,d=0,f=e,p=null;b:for(;;){for(var m;f!==n||a!==0&&f.nodeType!==3||(c=s+a),f!==o||r!==0&&f.nodeType!==3||(l=s+r),f.nodeType===3&&(s+=f.nodeValue.length),(m=f.firstChild)!==null;)p=f,f=m;for(;;){if(f===e)break b;if(p===n&&++u===a&&(c=s),p===o&&++d===r&&(l=s),(m=f.nextSibling)!==null)break;f=p,p=f.parentNode}f=m}n=c===-1||l===-1?null:{start:c,end:l}}else n=null}n||={start:0,end:0}}else n=null;for(bf={focusedElem:e,selectionRange:n},Bp=!1,Al=t;Al!==null;)if(t=Al,e=t.child,t.subtreeFlags&1028&&e!==null)e.return=t,Al=e;else for(;Al!==null;){switch(t=Al,o=t.alternate,e=t.flags,t.tag){case 0:if(e&4&&(e=t.updateQueue,e=e===null?null:e.events,e!==null))for(n=0;n<e.length;n++)a=e[n],a.ref.impl=a.nextImpl;break;case 11:case 15:break;case 1:if(e&1024&&o!==null){e=void 0,n=t,a=o.memoizedProps,o=o.memoizedState,r=n.stateNode;try{var h=_c(n.type,a);e=r.getSnapshotBeforeUpdate(h,o),r.__reactInternalSnapshotBeforeUpdate=e}catch(e){xd(n,n.return,e)}}break;case 3:if(e&1024){if(e=t.stateNode.containerInfo,n=e.nodeType,n===9)Ff(e);else if(n===1)switch(e.nodeName){case`HEAD`:case`HTML`:case`BODY`:Ff(e);break;default:e.textContent=``}}break;case 5:case 26:case 27:case 6:case 4:case 17:break;default:if(e&1024)throw Error(i(163))}if(e=t.sibling,e!==null){e.return=t.return,Al=e;break}Al=t.return}}function Ml(e,t,n){var r=n.flags;switch(n.tag){case 0:case 11:case 15:ql(e,n),r&4&&pl(5,n);break;case 1:if(ql(e,n),r&4)if(e=n.stateNode,t===null)try{e.componentDidMount()}catch(e){xd(n,n.return,e)}else{var i=_c(n.type,t.memoizedProps);t=t.memoizedState;try{e.componentDidUpdate(i,t,e.__reactInternalSnapshotBeforeUpdate)}catch(e){xd(n,n.return,e)}}r&64&&hl(n),r&512&&_l(n,n.return);break;case 3:if(ql(e,n),r&64&&(e=n.updateQueue,e!==null)){if(t=null,n.child!==null)switch(n.child.tag){case 27:case 5:t=n.child.stateNode;break;case 1:t=n.child.stateNode}try{vo(e,t)}catch(e){xd(n,n.return,e)}}break;case 27:t===null&&r&4&&Tl(n);case 26:case 5:ql(e,n),t===null&&r&4&&yl(n),r&512&&_l(n,n.return);break;case 12:ql(e,n);break;case 31:ql(e,n),r&4&&Rl(e,n);break;case 13:ql(e,n),r&4&&zl(e,n),r&64&&(e=n.memoizedState,e!==null&&(e=e.dehydrated,e!==null&&(n=Td.bind(null,n),Vf(e,n))));break;case 22:if(r=n.memoizedState!==null||El,!r){t=t!==null&&t.memoizedState!==null||Dl,i=El;var a=Dl;El=r,(Dl=t)&&!a?Yl(e,n,(n.subtreeFlags&8772)!=0):ql(e,n),El=i,Dl=a}break;case 30:break;default:ql(e,n)}}function Nl(e){var t=e.alternate;t!==null&&(e.alternate=null,Nl(t)),e.child=null,e.deletions=null,e.sibling=null,e.tag===5&&(t=e.stateNode,t!==null&&Dt(t)),e.stateNode=null,e.return=null,e.dependencies=null,e.memoizedProps=null,e.memoizedState=null,e.pendingProps=null,e.stateNode=null,e.updateQueue=null}var Pl=null,Fl=!1;function Il(e,t,n){for(n=n.child;n!==null;)Ll(e,t,n),n=n.sibling}function Ll(e,t,n){if(Je&&typeof Je.onCommitFiberUnmount==`function`)try{Je.onCommitFiberUnmount(qe,n)}catch{}switch(n.tag){case 26:Dl||vl(n,t),Il(e,t,n),n.memoizedState?n.memoizedState.count--:n.stateNode&&(n=n.stateNode,n.parentNode.removeChild(n));break;case 27:Dl||vl(n,t);var r=Pl,i=Fl;Mf(n.type)&&(Pl=n.stateNode,Fl=!1),Il(e,t,n),Kf(n.stateNode),Pl=r,Fl=i;break;case 5:Dl||vl(n,t);case 6:if(r=Pl,i=Fl,Pl=null,Il(e,t,n),Pl=r,Fl=i,Pl!==null)if(Fl)try{(Pl.nodeType===9?Pl.body:Pl.nodeName===`HTML`?Pl.ownerDocument.body:Pl).removeChild(n.stateNode)}catch(e){xd(n,t,e)}else try{Pl.removeChild(n.stateNode)}catch(e){xd(n,t,e)}break;case 18:Pl!==null&&(Fl?(e=Pl,Nf(e.nodeType===9?e.body:e.nodeName===`HTML`?e.ownerDocument.body:e,n.stateNode),fm(e)):Nf(Pl,n.stateNode));break;case 4:r=Pl,i=Fl,Pl=n.stateNode.containerInfo,Fl=!0,Il(e,t,n),Pl=r,Fl=i;break;case 0:case 11:case 14:case 15:ml(2,n,t),Dl||ml(4,n,t),Il(e,t,n);break;case 1:Dl||(vl(n,t),r=n.stateNode,typeof r.componentWillUnmount==`function`&&gl(n,t,r)),Il(e,t,n);break;case 21:Il(e,t,n);break;case 22:Dl=(r=Dl)||n.memoizedState!==null,Il(e,t,n),Dl=r;break;default:Il(e,t,n)}}function Rl(e,t){if(t.memoizedState===null&&(e=t.alternate,e!==null&&(e=e.memoizedState,e!==null))){e=e.dehydrated;try{fm(e)}catch(e){xd(t,t.return,e)}}}function zl(e,t){if(t.memoizedState===null&&(e=t.alternate,e!==null&&(e=e.memoizedState,e!==null&&(e=e.dehydrated,e!==null))))try{fm(e)}catch(e){xd(t,t.return,e)}}function Bl(e){switch(e.tag){case 31:case 13:case 19:var t=e.stateNode;return t===null&&(t=e.stateNode=new kl),t;case 22:return e=e.stateNode,t=e._retryCache,t===null&&(t=e._retryCache=new kl),t;default:throw Error(i(435,e.tag))}}function Vl(e,t){var n=Bl(e);t.forEach(function(t){if(!n.has(t)){n.add(t);var r=Ed.bind(null,e,t);t.then(r,r)}})}function Hl(e,t){var n=t.deletions;if(n!==null)for(var r=0;r<n.length;r++){var a=n[r],o=e,s=t,c=s;a:for(;c!==null;){switch(c.tag){case 27:if(Mf(c.type)){Pl=c.stateNode,Fl=!1;break a}break;case 5:Pl=c.stateNode,Fl=!1;break a;case 3:case 4:Pl=c.stateNode.containerInfo,Fl=!0;break a}c=c.return}if(Pl===null)throw Error(i(160));Ll(o,s,a),Pl=null,Fl=!1,o=a.alternate,o!==null&&(o.return=null),a.return=null}if(t.subtreeFlags&13886)for(t=t.child;t!==null;)Wl(t,e),t=t.sibling}var Ul=null;function Wl(e,t){var n=e.alternate,r=e.flags;switch(e.tag){case 0:case 11:case 14:case 15:Hl(t,e),Gl(e),r&4&&(ml(3,e,e.return),pl(3,e),ml(5,e,e.return));break;case 1:Hl(t,e),Gl(e),r&512&&(Dl||n===null||vl(n,n.return)),r&64&&El&&(e=e.updateQueue,e!==null&&(r=e.callbacks,r!==null&&(n=e.shared.hiddenCallbacks,e.shared.hiddenCallbacks=n===null?r:n.concat(r))));break;case 26:var a=Ul;if(Hl(t,e),Gl(e),r&512&&(Dl||n===null||vl(n,n.return)),r&4){var o=n===null?null:n.memoizedState;if(r=e.memoizedState,n===null)if(r===null)if(e.stateNode===null){a:{r=e.type,n=e.memoizedProps,a=a.ownerDocument||a;b:switch(r){case`title`:o=a.getElementsByTagName(`title`)[0],(!o||o[Et]||o[yt]||o.namespaceURI===`http://www.w3.org/2000/svg`||o.hasAttribute(`itemprop`))&&(o=a.createElement(r),a.head.insertBefore(o,a.querySelector(`head > title`))),hf(o,r,n),o[yt]=e,jt(o),r=o;break a;case`link`:var s=bp(`link`,`href`,a).get(r+(n.href||``));if(s){for(var c=0;c<s.length;c++)if(o=s[c],o.getAttribute(`href`)===(n.href==null||n.href===``?null:n.href)&&o.getAttribute(`rel`)===(n.rel==null?null:n.rel)&&o.getAttribute(`title`)===(n.title==null?null:n.title)&&o.getAttribute(`crossorigin`)===(n.crossOrigin==null?null:n.crossOrigin)){s.splice(c,1);break b}}o=a.createElement(r),hf(o,r,n),a.head.appendChild(o);break;case`meta`:if(s=bp(`meta`,`content`,a).get(r+(n.content||``))){for(c=0;c<s.length;c++)if(o=s[c],o.getAttribute(`content`)===(n.content==null?null:``+n.content)&&o.getAttribute(`name`)===(n.name==null?null:n.name)&&o.getAttribute(`property`)===(n.property==null?null:n.property)&&o.getAttribute(`http-equiv`)===(n.httpEquiv==null?null:n.httpEquiv)&&o.getAttribute(`charset`)===(n.charSet==null?null:n.charSet)){s.splice(c,1);break b}}o=a.createElement(r),hf(o,r,n),a.head.appendChild(o);break;default:throw Error(i(468,r))}o[yt]=e,jt(o),r=o}e.stateNode=r}else xp(a,e.type,e.stateNode);else e.stateNode=hp(a,r,e.memoizedProps);else o===r?r===null&&e.stateNode!==null&&bl(e,e.memoizedProps,n.memoizedProps):(o===null?n.stateNode!==null&&(n=n.stateNode,n.parentNode.removeChild(n)):o.count--,r===null?xp(a,e.type,e.stateNode):hp(a,r,e.memoizedProps))}break;case 27:Hl(t,e),Gl(e),r&512&&(Dl||n===null||vl(n,n.return)),n!==null&&r&4&&bl(e,e.memoizedProps,n.memoizedProps);break;case 5:if(Hl(t,e),Gl(e),r&512&&(Dl||n===null||vl(n,n.return)),e.flags&32){a=e.stateNode;try{tn(a,``)}catch(t){xd(e,e.return,t)}}r&4&&e.stateNode!=null&&(a=e.memoizedProps,bl(e,a,n===null?a:n.memoizedProps)),r&1024&&(Ol=!0);break;case 6:if(Hl(t,e),Gl(e),r&4){if(e.stateNode===null)throw Error(i(162));r=e.memoizedProps,n=e.stateNode;try{n.nodeValue=r}catch(t){xd(e,e.return,t)}}break;case 3:if(yp=null,a=Ul,Ul=Yf(t.containerInfo),Hl(t,e),Ul=a,Gl(e),r&4&&n!==null&&n.memoizedState.isDehydrated)try{fm(t.containerInfo)}catch(t){xd(e,e.return,t)}Ol&&(Ol=!1,Kl(e));break;case 4:r=Ul,Ul=Yf(e.stateNode.containerInfo),Hl(t,e),Gl(e),Ul=r;break;case 12:Hl(t,e),Gl(e);break;case 31:Hl(t,e),Gl(e),r&4&&(r=e.updateQueue,r!==null&&(e.updateQueue=null,Vl(e,r)));break;case 13:Hl(t,e),Gl(e),e.child.flags&8192&&e.memoizedState!==null!=(n!==null&&n.memoizedState!==null)&&(ku=Re()),r&4&&(r=e.updateQueue,r!==null&&(e.updateQueue=null,Vl(e,r)));break;case 22:a=e.memoizedState!==null;var l=n!==null&&n.memoizedState!==null,u=El,d=Dl;if(El=u||a,Dl=d||l,Hl(t,e),Dl=d,El=u,Gl(e),r&8192)a:for(t=e.stateNode,t._visibility=a?t._visibility&-2:t._visibility|1,a&&(n===null||l||El||Dl||Jl(e)),n=null,t=e;;){if(t.tag===5||t.tag===26){if(n===null){l=n=t;try{if(o=l.stateNode,a)s=o.style,typeof s.setProperty==`function`?s.setProperty(`display`,`none`,`important`):s.display=`none`;else{c=l.stateNode;var f=l.memoizedProps.style,p=f!=null&&f.hasOwnProperty(`display`)?f.display:null;c.style.display=p==null||typeof p==`boolean`?``:(``+p).trim()}}catch(e){xd(l,l.return,e)}}}else if(t.tag===6){if(n===null){l=t;try{l.stateNode.nodeValue=a?``:l.memoizedProps}catch(e){xd(l,l.return,e)}}}else if(t.tag===18){if(n===null){l=t;try{var m=l.stateNode;a?Pf(m,!0):Pf(l.stateNode,!1)}catch(e){xd(l,l.return,e)}}}else if((t.tag!==22&&t.tag!==23||t.memoizedState===null||t===e)&&t.child!==null){t.child.return=t,t=t.child;continue}if(t===e)break a;for(;t.sibling===null;){if(t.return===null||t.return===e)break a;n===t&&(n=null),t=t.return}n===t&&(n=null),t.sibling.return=t.return,t=t.sibling}r&4&&(r=e.updateQueue,r!==null&&(n=r.retryQueue,n!==null&&(r.retryQueue=null,Vl(e,n))));break;case 19:Hl(t,e),Gl(e),r&4&&(r=e.updateQueue,r!==null&&(e.updateQueue=null,Vl(e,r)));break;case 30:break;case 21:break;default:Hl(t,e),Gl(e)}}function Gl(e){var t=e.flags;if(t&2){try{for(var n,r=e.return;r!==null;){if(xl(r)){n=r;break}r=r.return}if(n==null)throw Error(i(160));switch(n.tag){case 27:var a=n.stateNode,o=Sl(e);wl(e,o,a);break;case 5:var s=n.stateNode;n.flags&32&&(tn(s,``),n.flags&=-33);var c=Sl(e);wl(e,c,s);break;case 3:case 4:var l=n.stateNode.containerInfo,u=Sl(e);Cl(e,u,l);break;default:throw Error(i(161))}}catch(t){xd(e,e.return,t)}e.flags&=-3}t&4096&&(e.flags&=-4097)}function Kl(e){if(e.subtreeFlags&1024)for(e=e.child;e!==null;){var t=e;Kl(t),t.tag===5&&t.flags&1024&&t.stateNode.reset(),e=e.sibling}}function ql(e,t){if(t.subtreeFlags&8772)for(t=t.child;t!==null;)Ml(e,t.alternate,t),t=t.sibling}function Jl(e){for(e=e.child;e!==null;){var t=e;switch(t.tag){case 0:case 11:case 14:case 15:ml(4,t,t.return),Jl(t);break;case 1:vl(t,t.return);var n=t.stateNode;typeof n.componentWillUnmount==`function`&&gl(t,t.return,n),Jl(t);break;case 27:Kf(t.stateNode);case 26:case 5:vl(t,t.return),Jl(t);break;case 22:t.memoizedState===null&&Jl(t);break;case 30:Jl(t);break;default:Jl(t)}e=e.sibling}}function Yl(e,t,n){for(n&&=(t.subtreeFlags&8772)!=0,t=t.child;t!==null;){var r=t.alternate,i=e,a=t,o=a.flags;switch(a.tag){case 0:case 11:case 15:Yl(i,a,n),pl(4,a);break;case 1:if(Yl(i,a,n),r=a,i=r.stateNode,typeof i.componentDidMount==`function`)try{i.componentDidMount()}catch(e){xd(r,r.return,e)}if(r=a,i=r.updateQueue,i!==null){var s=r.stateNode;try{var c=i.shared.hiddenCallbacks;if(c!==null)for(i.shared.hiddenCallbacks=null,i=0;i<c.length;i++)_o(c[i],s)}catch(e){xd(r,r.return,e)}}n&&o&64&&hl(a),_l(a,a.return);break;case 27:Tl(a);case 26:case 5:Yl(i,a,n),n&&r===null&&o&4&&yl(a),_l(a,a.return);break;case 12:Yl(i,a,n);break;case 31:Yl(i,a,n),n&&o&4&&Rl(i,a);break;case 13:Yl(i,a,n),n&&o&4&&zl(i,a);break;case 22:a.memoizedState===null&&Yl(i,a,n),_l(a,a.return);break;case 30:break;default:Yl(i,a,n)}t=t.sibling}}function Xl(e,t){var n=null;e!==null&&e.memoizedState!==null&&e.memoizedState.cachePool!==null&&(n=e.memoizedState.cachePool.pool),e=null,t.memoizedState!==null&&t.memoizedState.cachePool!==null&&(e=t.memoizedState.cachePool.pool),e!==n&&(e!=null&&e.refCount++,n!=null&&ka(n))}function Zl(e,t){e=null,t.alternate!==null&&(e=t.alternate.memoizedState.cache),t=t.memoizedState.cache,t!==e&&(t.refCount++,e!=null&&ka(e))}function Ql(e,t,n,r){if(t.subtreeFlags&10256)for(t=t.child;t!==null;)$l(e,t,n,r),t=t.sibling}function $l(e,t,n,r){var i=t.flags;switch(t.tag){case 0:case 11:case 15:Ql(e,t,n,r),i&2048&&pl(9,t);break;case 1:Ql(e,t,n,r);break;case 3:Ql(e,t,n,r),i&2048&&(e=null,t.alternate!==null&&(e=t.alternate.memoizedState.cache),t=t.memoizedState.cache,t!==e&&(t.refCount++,e!=null&&ka(e)));break;case 12:if(i&2048){Ql(e,t,n,r),e=t.stateNode;try{var a=t.memoizedProps,o=a.id,s=a.onPostCommit;typeof s==`function`&&s(o,t.alternate===null?`mount`:`update`,e.passiveEffectDuration,-0)}catch(e){xd(t,t.return,e)}}else Ql(e,t,n,r);break;case 31:Ql(e,t,n,r);break;case 13:Ql(e,t,n,r);break;case 23:break;case 22:a=t.stateNode,o=t.alternate,t.memoizedState===null?a._visibility&2?Ql(e,t,n,r):(a._visibility|=2,eu(e,t,n,r,(t.subtreeFlags&10256)!=0||!1)):a._visibility&2?Ql(e,t,n,r):tu(e,t),i&2048&&Xl(o,t);break;case 24:Ql(e,t,n,r),i&2048&&Zl(t.alternate,t);break;default:Ql(e,t,n,r)}}function eu(e,t,n,r,i){for(i&&=(t.subtreeFlags&10256)!=0||!1,t=t.child;t!==null;){var a=e,o=t,s=n,c=r,l=o.flags;switch(o.tag){case 0:case 11:case 15:eu(a,o,s,c,i),pl(8,o);break;case 23:break;case 22:var u=o.stateNode;o.memoizedState===null?(u._visibility|=2,eu(a,o,s,c,i)):u._visibility&2?eu(a,o,s,c,i):tu(a,o),i&&l&2048&&Xl(o.alternate,o);break;case 24:eu(a,o,s,c,i),i&&l&2048&&Zl(o.alternate,o);break;default:eu(a,o,s,c,i)}t=t.sibling}}function tu(e,t){if(t.subtreeFlags&10256)for(t=t.child;t!==null;){var n=e,r=t,i=r.flags;switch(r.tag){case 22:tu(n,r),i&2048&&Xl(r.alternate,r);break;case 24:tu(n,r),i&2048&&Zl(r.alternate,r);break;default:tu(n,r)}t=t.sibling}}var nu=8192;function ru(e,t,n){if(e.subtreeFlags&nu)for(e=e.child;e!==null;)iu(e,t,n),e=e.sibling}function iu(e,t,n){switch(e.tag){case 26:ru(e,t,n),e.flags&nu&&e.memoizedState!==null&&wp(n,Ul,e.memoizedState,e.memoizedProps);break;case 5:ru(e,t,n);break;case 3:case 4:var r=Ul;Ul=Yf(e.stateNode.containerInfo),ru(e,t,n),Ul=r;break;case 22:e.memoizedState===null&&(r=e.alternate,r!==null&&r.memoizedState!==null?(r=nu,nu=16777216,ru(e,t,n),nu=r):ru(e,t,n));break;default:ru(e,t,n)}}function au(e){var t=e.alternate;if(t!==null&&(e=t.child,e!==null)){t.child=null;do t=e.sibling,e.sibling=null,e=t;while(e!==null)}}function ou(e){var t=e.deletions;if(e.flags&16){if(t!==null)for(var n=0;n<t.length;n++){var r=t[n];Al=r,lu(r,e)}au(e)}if(e.subtreeFlags&10256)for(e=e.child;e!==null;)su(e),e=e.sibling}function su(e){switch(e.tag){case 0:case 11:case 15:ou(e),e.flags&2048&&ml(9,e,e.return);break;case 3:ou(e);break;case 12:ou(e);break;case 22:var t=e.stateNode;e.memoizedState!==null&&t._visibility&2&&(e.return===null||e.return.tag!==13)?(t._visibility&=-3,cu(e)):ou(e);break;default:ou(e)}}function cu(e){var t=e.deletions;if(e.flags&16){if(t!==null)for(var n=0;n<t.length;n++){var r=t[n];Al=r,lu(r,e)}au(e)}for(e=e.child;e!==null;){switch(t=e,t.tag){case 0:case 11:case 15:ml(8,t,t.return),cu(t);break;case 22:n=t.stateNode,n._visibility&2&&(n._visibility&=-3,cu(t));break;default:cu(t)}e=e.sibling}}function lu(e,t){for(;Al!==null;){var n=Al;switch(n.tag){case 0:case 11:case 15:ml(8,n,t);break;case 23:case 22:if(n.memoizedState!==null&&n.memoizedState.cachePool!==null){var r=n.memoizedState.cachePool.pool;r!=null&&r.refCount++}break;case 24:ka(n.memoizedState.cache)}if(r=n.child,r!==null)r.return=n,Al=r;else a:for(n=e;Al!==null;){r=Al;var i=r.sibling,a=r.return;if(Nl(r),r===n){Al=null;break a}if(i!==null){i.return=a,Al=i;break a}Al=a}}}var uu={getCacheForType:function(e){var t=xa(Da),n=t.data.get(e);return n===void 0&&(n=e(),t.data.set(e,n)),n},cacheSignal:function(){return xa(Da).controller.signal}},du=typeof WeakMap==`function`?WeakMap:Map,fu=0,pu=null,M=null,N=0,mu=0,hu=null,gu=!1,_u=!1,vu=!1,yu=0,bu=0,xu=0,Su=0,Cu=0,wu=0,Tu=0,Eu=null,Du=null,Ou=!1,ku=0,Au=0,ju=1/0,Mu=null,Nu=null,Pu=0,Fu=null,Iu=null,Lu=0,Ru=0,zu=null,Bu=null,Vu=0,Hu=null;function Uu(){return fu&2&&N!==0?N&-N:T.T===null?gt():Hd()}function Wu(){if(wu===0)if(!(N&536870912)||ea){var e=tt;tt<<=1,!(tt&3932160)&&(tt=262144),wu=e}else wu=536870912;return e=wo.current,e!==null&&(e.flags|=32),wu}function Gu(e,t,n){(e===pu&&(mu===2||mu===9)||e.cancelPendingCommit!==null)&&(Qu(e,0),Yu(e,N,wu,!1)),lt(e,n),(!(fu&2)||e!==pu)&&(e===pu&&(!(fu&2)&&(Su|=n),bu===4&&Yu(e,N,wu,!1)),Pd(e))}function Ku(e,t,n){if(fu&6)throw Error(i(327));var r=!n&&(t&127)==0&&(t&e.expiredLanes)===0||at(e,t),a=r?od(e,t):id(e,t,!0),o=r;do{if(a===0){_u&&!r&&Yu(e,t,0,!1);break}else{if(n=e.current.alternate,o&&!Ju(n)){a=id(e,t,!1),o=!1;continue}if(a===2){if(o=t,e.errorRecoveryDisabledLanes&o)var s=0;else s=e.pendingLanes&-536870913,s=s===0?s&536870912?536870912:0:s;if(s!==0){t=s;a:{var c=e;a=Eu;var l=c.current.memoizedState.isDehydrated;if(l&&(Qu(c,s).flags|=256),s=id(c,s,!1),s!==2){if(vu&&!l){c.errorRecoveryDisabledLanes|=o,Su|=o,a=4;break a}o=Du,Du=a,o!==null&&(Du===null?Du=o:Du.push.apply(Du,o))}a=s}if(o=!1,a!==2)continue}}if(a===1){Qu(e,0),Yu(e,t,0,!0);break}a:{switch(r=e,o=a,o){case 0:case 1:throw Error(i(345));case 4:if((t&4194048)!==t)break;case 6:Yu(r,t,wu,!gu);break a;case 2:Du=null;break;case 3:case 5:break;default:throw Error(i(329))}if((t&62914560)===t&&(a=ku+300-Re(),10<a)){if(Yu(r,t,wu,!gu),it(r,0,!0)!==0)break a;Lu=t,r.timeoutHandle=Df(qu.bind(null,r,n,Du,Mu,Ou,t,wu,Su,Tu,gu,o,`Throttled`,-0,0),a);break a}qu(r,n,Du,Mu,Ou,t,wu,Su,Tu,gu,o,null,-0,0)}}break}while(1);Pd(e)}function qu(e,t,n,r,i,a,o,s,c,l,u,d,f,p){if(e.timeoutHandle=-1,d=t.subtreeFlags,d&8192||(d&16785408)==16785408){d={stylesheets:null,count:0,imgCount:0,imgBytes:0,suspenseyImages:[],waitingForImages:!0,waitingForViewTransition:!1,unsuspend:un},iu(t,a,d);var m=(a&62914560)===a?ku-Re():(a&4194048)===a?Au-Re():0;if(m=Ep(d,m),m!==null){Lu=a,e.cancelPendingCommit=m(pd.bind(null,e,t,a,n,r,i,o,s,c,u,d,null,f,p)),Yu(e,a,o,!l);return}}pd(e,t,a,n,r,i,o,s,c)}function Ju(e){for(var t=e;;){var n=t.tag;if((n===0||n===11||n===15)&&t.flags&16384&&(n=t.updateQueue,n!==null&&(n=n.stores,n!==null)))for(var r=0;r<n.length;r++){var i=n[r],a=i.getSnapshot;i=i.value;try{if(!Vr(a(),i))return!1}catch{return!1}}if(n=t.child,t.subtreeFlags&16384&&n!==null)n.return=t,t=n;else{if(t===e)break;for(;t.sibling===null;){if(t.return===null||t.return===e)return!0;t=t.return}t.sibling.return=t.return,t=t.sibling}}return!0}function Yu(e,t,n,r){t&=~Cu,t&=~Su,e.suspendedLanes|=t,e.pingedLanes&=~t,r&&(e.warmLanes|=t),r=e.expirationTimes;for(var i=t;0<i;){var a=31-Xe(i),o=1<<a;r[a]=-1,i&=~o}n!==0&&dt(e,n,t)}function Xu(){return fu&6?!0:(Fd(0,!1),!1)}function Zu(){if(M!==null){if(mu===0)var e=M.return;else e=M,pa=fa=null,Zo(e),Qa=null,$a=0,e=M;for(;e!==null;)fl(e.alternate,e),e=e.return;M=null}}function Qu(e,t){var n=e.timeoutHandle;n!==-1&&(e.timeoutHandle=-1,Of(n)),n=e.cancelPendingCommit,n!==null&&(e.cancelPendingCommit=null,n()),Lu=0,Zu(),pu=e,M=n=ki(e.current,null),N=t,mu=0,hu=null,gu=!1,_u=at(e,t),vu=!1,Tu=wu=Cu=Su=xu=bu=0,Du=Eu=null,Ou=!1,t&8&&(t|=t&32);var r=e.entangledLanes;if(r!==0)for(e=e.entanglements,r&=t;0<r;){var i=31-Xe(r),a=1<<i;t|=e[i],r&=~a}return yu=t,yi(),n}function $u(e,t){j=null,T.H=lc,t===Ha||t===Wa?(t=Xa(),mu=3):t===Ua?(t=Xa(),mu=4):mu=t===Dc?8:typeof t==`object`&&t&&typeof t.then==`function`?6:1,hu=t,M===null&&(bu=1,xc(e,Li(t,e.current)))}function ed(){var e=wo.current;return e===null?!0:(N&4194048)===N?To===null:(N&62914560)===N||N&536870912?e===To:!1}function td(){var e=T.H;return T.H=lc,e===null?lc:e}function nd(){var e=T.A;return T.A=uu,e}function rd(){bu=4,gu||(N&4194048)!==N&&wo.current!==null||(_u=!0),!(xu&134217727)&&!(Su&134217727)||pu===null||Yu(pu,N,wu,!1)}function id(e,t,n){var r=fu;fu|=2;var i=td(),a=nd();(pu!==e||N!==t)&&(Mu=null,Qu(e,t)),t=!1;var o=bu;a:do try{if(mu!==0&&M!==null){var s=M,c=hu;switch(mu){case 8:Zu(),o=6;break a;case 3:case 2:case 9:case 6:wo.current===null&&(t=!0);var l=mu;if(mu=0,hu=null,ud(e,s,c,l),n&&_u){o=0;break a}break;default:l=mu,mu=0,hu=null,ud(e,s,c,l)}}ad(),o=bu;break}catch(t){$u(e,t)}while(1);return t&&e.shellSuspendCounter++,pa=fa=null,fu=r,T.H=i,T.A=a,M===null&&(pu=null,N=0,yi()),o}function ad(){for(;M!==null;)cd(M)}function od(e,t){var n=fu;fu|=2;var r=td(),a=nd();pu!==e||N!==t?(Mu=null,ju=Re()+500,Qu(e,t)):_u=at(e,t);a:do try{if(mu!==0&&M!==null){t=M;var o=hu;b:switch(mu){case 1:mu=0,hu=null,ud(e,t,o,1);break;case 2:case 9:if(Ka(o)){mu=0,hu=null,ld(t);break}t=function(){mu!==2&&mu!==9||pu!==e||(mu=7),Pd(e)},o.then(t,t);break a;case 3:mu=7;break a;case 4:mu=5;break a;case 7:Ka(o)?(mu=0,hu=null,ld(t)):(mu=0,hu=null,ud(e,t,o,7));break;case 5:var s=null;switch(M.tag){case 26:s=M.memoizedState;case 5:case 27:var c=M;if(s?Cp(s):c.stateNode.complete){mu=0,hu=null;var l=c.sibling;if(l!==null)M=l;else{var u=c.return;u===null?M=null:(M=u,dd(u))}break b}}mu=0,hu=null,ud(e,t,o,5);break;case 6:mu=0,hu=null,ud(e,t,o,6);break;case 8:Zu(),bu=6;break a;default:throw Error(i(462))}}sd();break}catch(t){$u(e,t)}while(1);return pa=fa=null,T.H=r,T.A=a,fu=n,M===null?(pu=null,N=0,yi(),bu):0}function sd(){for(;M!==null&&!Ie();)cd(M)}function cd(e){var t=rl(e.alternate,e,yu);e.memoizedProps=e.pendingProps,t===null?dd(e):M=t}function ld(e){var t=e,n=t.alternate;switch(t.tag){case 15:case 0:t=Vc(n,t,t.pendingProps,t.type,void 0,N);break;case 11:t=Vc(n,t,t.pendingProps,t.type.render,t.ref,N);break;case 5:Zo(t);default:fl(n,t),t=M=Ai(t,yu),t=rl(n,t,yu)}e.memoizedProps=e.pendingProps,t===null?dd(e):M=t}function ud(e,t,n,r){pa=fa=null,Zo(t),Qa=null,$a=0;var i=t.return;try{if(Ec(e,i,t,n,N)){bu=1,xc(e,Li(n,e.current)),M=null;return}}catch(t){if(i!==null)throw M=i,t;bu=1,xc(e,Li(n,e.current)),M=null;return}t.flags&32768?(ea||r===1?e=!0:_u||N&536870912?e=!1:(gu=e=!0,(r===2||r===9||r===3||r===6)&&(r=wo.current,r!==null&&r.tag===13&&(r.flags|=16384))),fd(t,e)):dd(t)}function dd(e){var t=e;do{if(t.flags&32768){fd(t,gu);return}e=t.return;var n=ul(t.alternate,t,yu);if(n!==null){M=n;return}if(t=t.sibling,t!==null){M=t;return}M=t=e}while(t!==null);bu===0&&(bu=5)}function fd(e,t){do{var n=dl(e.alternate,e);if(n!==null){n.flags&=32767,M=n;return}if(n=e.return,n!==null&&(n.flags|=32768,n.subtreeFlags=0,n.deletions=null),!t&&(e=e.sibling,e!==null)){M=e;return}M=e=n}while(e!==null);bu=6,M=null}function pd(e,t,n,r,a,o,s,c,l){e.cancelPendingCommit=null;do vd();while(Pu!==0);if(fu&6)throw Error(i(327));if(t!==null){if(t===e.current)throw Error(i(177));if(o=t.lanes|t.childLanes,o|=vi,ut(e,n,o,s,c,l),e===pu&&(M=pu=null,N=0),Iu=t,Fu=e,Lu=n,Ru=o,zu=a,Bu=r,t.subtreeFlags&10256||t.flags&10256?(e.callbackNode=null,e.callbackPriority=0,Dd(He,function(){return yd(),null})):(e.callbackNode=null,e.callbackPriority=0),r=(t.flags&13878)!=0,t.subtreeFlags&13878||r){r=T.T,T.T=null,a=de.p,de.p=2,s=fu,fu|=4;try{jl(e,t,n)}finally{fu=s,de.p=a,T.T=r}}Pu=1,md(),hd(),gd()}}function md(){if(Pu===1){Pu=0;var e=Fu,t=Iu,n=(t.flags&13878)!=0;if(t.subtreeFlags&13878||n){n=T.T,T.T=null;var r=de.p;de.p=2;var i=fu;fu|=4;try{Wl(t,e);var a=bf,o=Kr(e.containerInfo),s=a.focusedElem,c=a.selectionRange;if(o!==s&&s&&s.ownerDocument&&Gr(s.ownerDocument.documentElement,s)){if(c!==null&&qr(s)){var l=c.start,u=c.end;if(u===void 0&&(u=l),`selectionStart`in s)s.selectionStart=l,s.selectionEnd=Math.min(u,s.value.length);else{var d=s.ownerDocument||document,f=d&&d.defaultView||window;if(f.getSelection){var p=f.getSelection(),m=s.textContent.length,h=Math.min(c.start,m),g=c.end===void 0?h:Math.min(c.end,m);!p.extend&&h>g&&(o=g,g=h,h=o);var _=Wr(s,h),v=Wr(s,g);if(_&&v&&(p.rangeCount!==1||p.anchorNode!==_.node||p.anchorOffset!==_.offset||p.focusNode!==v.node||p.focusOffset!==v.offset)){var y=d.createRange();y.setStart(_.node,_.offset),p.removeAllRanges(),h>g?(p.addRange(y),p.extend(v.node,v.offset)):(y.setEnd(v.node,v.offset),p.addRange(y))}}}}for(d=[],p=s;p=p.parentNode;)p.nodeType===1&&d.push({element:p,left:p.scrollLeft,top:p.scrollTop});for(typeof s.focus==`function`&&s.focus(),s=0;s<d.length;s++){var b=d[s];b.element.scrollLeft=b.left,b.element.scrollTop=b.top}}Bp=!!yf,bf=yf=null}finally{fu=i,de.p=r,T.T=n}}e.current=t,Pu=2}}function hd(){if(Pu===2){Pu=0;var e=Fu,t=Iu,n=(t.flags&8772)!=0;if(t.subtreeFlags&8772||n){n=T.T,T.T=null;var r=de.p;de.p=2;var i=fu;fu|=4;try{Ml(e,t.alternate,t)}finally{fu=i,de.p=r,T.T=n}}Pu=3}}function gd(){if(Pu===4||Pu===3){Pu=0,Le();var e=Fu,t=Iu,n=Lu,r=Bu;t.subtreeFlags&10256||t.flags&10256?Pu=5:(Pu=0,Iu=Fu=null,_d(e,e.pendingLanes));var i=e.pendingLanes;if(i===0&&(Nu=null),ht(n),t=t.stateNode,Je&&typeof Je.onCommitFiberRoot==`function`)try{Je.onCommitFiberRoot(qe,t,void 0,(t.current.flags&128)==128)}catch{}if(r!==null){t=T.T,i=de.p,de.p=2,T.T=null;try{for(var a=e.onRecoverableError,o=0;o<r.length;o++){var s=r[o];a(s.value,{componentStack:s.stack})}}finally{T.T=t,de.p=i}}Lu&3&&vd(),Pd(e),i=e.pendingLanes,n&261930&&i&42?e===Hu?Vu++:(Vu=0,Hu=e):Vu=0,Fd(0,!1)}}function _d(e,t){(e.pooledCacheLanes&=t)===0&&(t=e.pooledCache,t!=null&&(e.pooledCache=null,ka(t)))}function vd(){return md(),hd(),gd(),yd()}function yd(){if(Pu!==5)return!1;var e=Fu,t=Ru;Ru=0;var n=ht(Lu),r=T.T,a=de.p;try{de.p=32>n?32:n,T.T=null,n=zu,zu=null;var o=Fu,s=Lu;if(Pu=0,Iu=Fu=null,Lu=0,fu&6)throw Error(i(331));var c=fu;if(fu|=4,su(o.current),$l(o,o.current,s,n),fu=c,Fd(0,!1),Je&&typeof Je.onPostCommitFiberRoot==`function`)try{Je.onPostCommitFiberRoot(qe,o)}catch{}return!0}finally{de.p=a,T.T=r,_d(e,t)}}function bd(e,t,n){t=Li(n,t),t=Cc(e.stateNode,t,2),e=uo(e,t,2),e!==null&&(lt(e,2),Pd(e))}function xd(e,t,n){if(e.tag===3)bd(e,e,n);else for(;t!==null;){if(t.tag===3){bd(t,e,n);break}else if(t.tag===1){var r=t.stateNode;if(typeof t.type.getDerivedStateFromError==`function`||typeof r.componentDidCatch==`function`&&(Nu===null||!Nu.has(r))){e=Li(n,e),n=wc(2),r=uo(t,n,2),r!==null&&(Tc(n,r,t,e),lt(r,2),Pd(r));break}}t=t.return}}function Sd(e,t,n){var r=e.pingCache;if(r===null){r=e.pingCache=new du;var i=new Set;r.set(t,i)}else i=r.get(t),i===void 0&&(i=new Set,r.set(t,i));i.has(n)||(vu=!0,i.add(n),e=Cd.bind(null,e,t,n),t.then(e,e))}function Cd(e,t,n){var r=e.pingCache;r!==null&&r.delete(t),e.pingedLanes|=e.suspendedLanes&n,e.warmLanes&=~n,pu===e&&(N&n)===n&&(bu===4||bu===3&&(N&62914560)===N&&300>Re()-ku?!(fu&2)&&Qu(e,0):Cu|=n,Tu===N&&(Tu=0)),Pd(e)}function wd(e,t){t===0&&(t=st()),e=Si(e,t),e!==null&&(lt(e,t),Pd(e))}function Td(e){var t=e.memoizedState,n=0;t!==null&&(n=t.retryLane),wd(e,n)}function Ed(e,t){var n=0;switch(e.tag){case 31:case 13:var r=e.stateNode,a=e.memoizedState;a!==null&&(n=a.retryLane);break;case 19:r=e.stateNode;break;case 22:r=e.stateNode._retryCache;break;default:throw Error(i(314))}r!==null&&r.delete(t),wd(e,n)}function Dd(e,t){return Pe(e,t)}var Od=null,kd=null,Ad=!1,jd=!1,Md=!1,Nd=0;function Pd(e){e!==kd&&e.next===null&&(kd===null?Od=kd=e:kd=kd.next=e),jd=!0,Ad||(Ad=!0,Vd())}function Fd(e,t){if(!Md&&jd){Md=!0;do for(var n=!1,r=Od;r!==null;){if(!t)if(e!==0){var i=r.pendingLanes;if(i===0)var a=0;else{var o=r.suspendedLanes,s=r.pingedLanes;a=(1<<31-Xe(42|e)+1)-1,a&=i&~(o&~s),a=a&201326741?a&201326741|1:a?a|2:0}a!==0&&(n=!0,Bd(r,a))}else a=N,a=it(r,r===pu?a:0,r.cancelPendingCommit!==null||r.timeoutHandle!==-1),!(a&3)||at(r,a)||(n=!0,Bd(r,a));r=r.next}while(n);Md=!1}}function Id(){Ld()}function Ld(){jd=Ad=!1;var e=0;Nd!==0&&Ef()&&(e=Nd);for(var t=Re(),n=null,r=Od;r!==null;){var i=r.next,a=Rd(r,t);a===0?(r.next=null,n===null?Od=i:n.next=i,i===null&&(kd=n)):(n=r,(e!==0||a&3)&&(jd=!0)),r=i}Pu!==0&&Pu!==5||Fd(e,!1),Nd!==0&&(Nd=0)}function Rd(e,t){for(var n=e.suspendedLanes,r=e.pingedLanes,i=e.expirationTimes,a=e.pendingLanes&-62914561;0<a;){var o=31-Xe(a),s=1<<o,c=i[o];c===-1?((s&n)===0||(s&r)!==0)&&(i[o]=ot(s,t)):c<=t&&(e.expiredLanes|=s),a&=~s}if(t=pu,n=N,n=it(e,e===t?n:0,e.cancelPendingCommit!==null||e.timeoutHandle!==-1),r=e.callbackNode,n===0||e===t&&(mu===2||mu===9)||e.cancelPendingCommit!==null)return r!==null&&r!==null&&Fe(r),e.callbackNode=null,e.callbackPriority=0;if(!(n&3)||at(e,n)){if(t=n&-n,t===e.callbackPriority)return t;switch(r!==null&&Fe(r),ht(n)){case 2:case 8:n=Ve;break;case 32:n=He;break;case 268435456:n=We;break;default:n=He}return r=zd.bind(null,e),n=Pe(n,r),e.callbackPriority=t,e.callbackNode=n,t}return r!==null&&r!==null&&Fe(r),e.callbackPriority=2,e.callbackNode=null,2}function zd(e,t){if(Pu!==0&&Pu!==5)return e.callbackNode=null,e.callbackPriority=0,null;var n=e.callbackNode;if(vd()&&e.callbackNode!==n)return null;var r=N;return r=it(e,e===pu?r:0,e.cancelPendingCommit!==null||e.timeoutHandle!==-1),r===0?null:(Ku(e,r,t),Rd(e,Re()),e.callbackNode!=null&&e.callbackNode===n?zd.bind(null,e):null)}function Bd(e,t){if(vd())return null;Ku(e,t,!0)}function Vd(){Af(function(){fu&6?Pe(Be,Id):Ld()})}function Hd(){if(Nd===0){var e=Ma;e===0&&(e=et,et<<=1,!(et&261888)&&(et=256)),Nd=e}return Nd}function Ud(e){return e==null||typeof e==`symbol`||typeof e==`boolean`?null:typeof e==`function`?e:ln(``+e)}function Wd(e,t){var n=t.ownerDocument.createElement(`input`);return n.name=t.name,n.value=t.value,e.id&&n.setAttribute(`form`,e.id),t.parentNode.insertBefore(n,t),e=new FormData(e),n.parentNode.removeChild(n),e}function Gd(e,t,n,r,i){if(t===`submit`&&n&&n.stateNode===i){var a=Ud((i[bt]||null).action),o=r.submitter;o&&(t=(t=o[bt]||null)?Ud(t.formAction):o.getAttribute(`formAction`),t!==null&&(a=t,o=null));var s=new k(`action`,`action`,null,r,i);e.push({event:s,listeners:[{instance:null,listener:function(){if(r.defaultPrevented){if(Nd!==0){var e=o?Wd(i,o):new FormData(i);Ys(n,{pending:!0,data:e,method:i.method,action:a},null,e)}}else typeof a==`function`&&(s.preventDefault(),e=o?Wd(i,o):new FormData(i),Ys(n,{pending:!0,data:e,method:i.method,action:a},a,e))},currentTarget:i}]})}}for(var Kd=0;Kd<pi.length;Kd++){var qd=pi[Kd],P=qd.toLowerCase(),Jd=qd[0].toUpperCase()+qd.slice(1);mi(P,`on`+Jd)}mi(ai,`onAnimationEnd`),mi(oi,`onAnimationIteration`),mi(si,`onAnimationStart`),mi(`dblclick`,`onDoubleClick`),mi(`focusin`,`onFocus`),mi(`focusout`,`onBlur`),mi(ci,`onTransitionRun`),mi(li,`onTransitionStart`),mi(ui,`onTransitionCancel`),mi(di,`onTransitionEnd`),Ft(`onMouseEnter`,[`mouseout`,`mouseover`]),Ft(`onMouseLeave`,[`mouseout`,`mouseover`]),Ft(`onPointerEnter`,[`pointerout`,`pointerover`]),Ft(`onPointerLeave`,[`pointerout`,`pointerover`]),Pt(`onChange`,`change click focusin focusout input keydown keyup selectionchange`.split(` `)),Pt(`onSelect`,`focusout contextmenu dragend focusin keydown keyup mousedown mouseup selectionchange`.split(` `)),Pt(`onBeforeInput`,[`compositionend`,`keypress`,`textInput`,`paste`]),Pt(`onCompositionEnd`,`compositionend focusout keydown keypress keyup mousedown`.split(` `)),Pt(`onCompositionStart`,`compositionstart focusout keydown keypress keyup mousedown`.split(` `)),Pt(`onCompositionUpdate`,`compositionupdate focusout keydown keypress keyup mousedown`.split(` `));var Yd=`abort canplay canplaythrough durationchange emptied encrypted ended error loadeddata loadedmetadata loadstart pause play playing progress ratechange resize seeked seeking stalled suspend timeupdate volumechange waiting`.split(` `),Xd=new Set(`beforetoggle cancel close invalid load scroll scrollend toggle`.split(` `).concat(Yd));function Zd(e,t){t=(t&4)!=0;for(var n=0;n<e.length;n++){var r=e[n],i=r.event;r=r.listeners;a:{var a=void 0;if(t)for(var o=r.length-1;0<=o;o--){var s=r[o],c=s.instance,l=s.currentTarget;if(s=s.listener,c!==a&&i.isPropagationStopped())break a;a=s,i.currentTarget=l;try{a(i)}catch(e){hi(e)}i.currentTarget=null,a=c}else for(o=0;o<r.length;o++){if(s=r[o],c=s.instance,l=s.currentTarget,s=s.listener,c!==a&&i.isPropagationStopped())break a;a=s,i.currentTarget=l;try{a(i)}catch(e){hi(e)}i.currentTarget=null,a=c}}}}function F(e,t){var n=t[St];n===void 0&&(n=t[St]=new Set);var r=e+`__bubble`;n.has(r)||(tf(t,e,2,!1),n.add(r))}function Qd(e,t,n){var r=0;t&&(r|=4),tf(n,e,r,t)}var $d=`_reactListening`+Math.random().toString(36).slice(2);function ef(e){if(!e[$d]){e[$d]=!0,Mt.forEach(function(t){t!==`selectionchange`&&(Xd.has(t)||Qd(t,!1,e),Qd(t,!0,e))});var t=e.nodeType===9?e:e.ownerDocument;t===null||t[$d]||(t[$d]=!0,Qd(`selectionchange`,!1,t))}}function tf(e,t,n,r){switch(qp(t)){case 2:var i=Vp;break;case 8:i=Hp;break;default:i=Up}n=i.bind(null,t,n,e),i=void 0,!bn||t!==`touchstart`&&t!==`touchmove`&&t!==`wheel`||(i=!0),r?i===void 0?e.addEventListener(t,n,!0):e.addEventListener(t,n,{capture:!0,passive:i}):i===void 0?e.addEventListener(t,n,!1):e.addEventListener(t,n,{passive:i})}function nf(e,t,n,r,i){var a=r;if(!(t&1)&&!(t&2)&&r!==null)a:for(;;){if(r===null)return;var s=r.tag;if(s===3||s===4){var c=r.stateNode.containerInfo;if(c===i)break;if(s===4)for(s=r.return;s!==null;){var l=s.tag;if((l===3||l===4)&&s.stateNode.containerInfo===i)return;s=s.return}for(;c!==null;){if(s=Ot(c),s===null)return;if(l=s.tag,l===5||l===6||l===26||l===27){r=a=s;continue a}c=c.parentNode}}r=r.return}_n(function(){var r=a,i=fn(n),s=[];a:{var c=fi.get(e);if(c!==void 0){var l=k,u=e;switch(e){case`keypress`:if(En(n)===0)break a;case`keydown`:case`keyup`:l=$n;break;case`focusin`:u=`focus`,l=Bn;break;case`focusout`:u=`blur`,l=Bn;break;case`beforeblur`:case`afterblur`:l=Bn;break;case`click`:if(n.button===2)break a;case`auxclick`:case`dblclick`:case`mousedown`:case`mousemove`:case`mouseup`:case`mouseout`:case`mouseover`:case`contextmenu`:l=In;break;case`drag`:case`dragend`:case`dragenter`:case`dragexit`:case`dragleave`:case`dragover`:case`dragstart`:case`drop`:l=Rn;break;case`touchcancel`:case`touchend`:case`touchmove`:case`touchstart`:l=rr;break;case ai:case oi:case si:l=Hn;break;case di:l=ar;break;case`scroll`:case`scrollend`:l=Mn;break;case`wheel`:l=sr;break;case`copy`:case`cut`:case`paste`:l=Wn;break;case`gotpointercapture`:case`lostpointercapture`:case`pointercancel`:case`pointerdown`:case`pointermove`:case`pointerout`:case`pointerover`:case`pointerup`:l=tr;break;case`toggle`:case`beforetoggle`:l=lr}var d=(t&4)!=0,f=!d&&(e===`scroll`||e===`scrollend`),p=d?c===null?null:c+`Capture`:c;d=[];for(var m=r,h;m!==null;){var g=m;if(h=g.stateNode,g=g.tag,g!==5&&g!==26&&g!==27||h===null||p===null||(g=vn(m,p),g!=null&&d.push(rf(m,g,h))),f)break;m=m.return}0<d.length&&(c=new l(c,u,null,n,i),s.push({event:c,listeners:d}))}}if(!(t&7)){a:{if(c=e===`mouseover`||e===`pointerover`,l=e===`mouseout`||e===`pointerout`,c&&n!==dn&&(u=n.relatedTarget||n.fromElement)&&(Ot(u)||u[xt]))break a;if((l||c)&&(c=i.window===i?i:(c=i.ownerDocument)?c.defaultView||c.parentWindow:window,l?(u=n.relatedTarget||n.toElement,l=r,u=u?Ot(u):null,u!==null&&(f=o(u),d=u.tag,u!==f||d!==5&&d!==27&&d!==6)&&(u=null)):(l=null,u=r),l!==u)){if(d=In,g=`onMouseLeave`,p=`onMouseEnter`,m=`mouse`,(e===`pointerout`||e===`pointerover`)&&(d=tr,g=`onPointerLeave`,p=`onPointerEnter`,m=`pointer`),f=l==null?c:kt(l),h=u==null?c:kt(u),c=new d(g,m+`leave`,l,n,i),c.target=f,c.relatedTarget=h,g=null,Ot(i)===r&&(d=new d(p,m+`enter`,u,n,i),d.target=h,d.relatedTarget=f,g=d),f=g,l&&u)b:{for(d=sf,p=l,m=u,h=0,g=p;g;g=d(g))h++;g=0;for(var _=m;_;_=d(_))g++;for(;0<h-g;)p=d(p),h--;for(;0<g-h;)m=d(m),g--;for(;h--;){if(p===m||m!==null&&p===m.alternate){d=p;break b}p=d(p),m=d(m)}d=null}else d=null;l!==null&&cf(s,c,l,d,!1),u!==null&&f!==null&&cf(s,f,u,d,!0)}}a:{if(c=r?kt(r):window,l=c.nodeName&&c.nodeName.toLowerCase(),l===`select`||l===`input`&&c.type===`file`)var v=kr;else if(Cr(c))if(Ar)v=zr;else{v=Lr;var y=Ir}else l=c.nodeName,!l||l.toLowerCase()!==`input`||c.type!==`checkbox`&&c.type!==`radio`?r&&on(r.elementType)&&(v=kr):v=Rr;if(v&&=v(e,r)){wr(s,v,n,i);break a}y&&y(e,c,r),e===`focusout`&&r&&c.type===`number`&&r.memoizedProps.value!=null&&Zt(c,`number`,c.value)}switch(y=r?kt(r):window,e){case`focusin`:(Cr(y)||y.contentEditable===`true`)&&(Yr=y,Xr=r,Zr=null);break;case`focusout`:Zr=Xr=Yr=null;break;case`mousedown`:Qr=!0;break;case`contextmenu`:case`mouseup`:case`dragend`:Qr=!1,$r(s,n,i);break;case`selectionchange`:if(Jr)break;case`keydown`:case`keyup`:$r(s,n,i)}var b;if(dr)b:{switch(e){case`compositionstart`:var x=`onCompositionStart`;break b;case`compositionend`:x=`onCompositionEnd`;break b;case`compositionupdate`:x=`onCompositionUpdate`;break b}x=void 0}else yr?_r(e,n)&&(x=`onCompositionEnd`):e===`keydown`&&n.keyCode===229&&(x=`onCompositionStart`);x&&(mr&&n.locale!==`ko`&&(yr||x!==`onCompositionStart`?x===`onCompositionEnd`&&yr&&(b=Tn()):(Sn=i,Cn=`value`in Sn?Sn.value:Sn.textContent,yr=!0)),y=af(r,x),0<y.length&&(x=new Kn(x,e,null,n,i),s.push({event:x,listeners:y}),b?x.data=b:(b=vr(n),b!==null&&(x.data=b)))),(b=pr?br(e,n):xr(e,n))&&(x=af(r,`onBeforeInput`),0<x.length&&(y=new Kn(`onBeforeInput`,`beforeinput`,null,n,i),s.push({event:y,listeners:x}),y.data=b)),Gd(s,e,r,n,i)}Zd(s,t)})}function rf(e,t,n){return{instance:e,listener:t,currentTarget:n}}function af(e,t){for(var n=t+`Capture`,r=[];e!==null;){var i=e,a=i.stateNode;if(i=i.tag,i!==5&&i!==26&&i!==27||a===null||(i=vn(e,n),i!=null&&r.unshift(rf(e,i,a)),i=vn(e,t),i!=null&&r.push(rf(e,i,a))),e.tag===3)return r;e=e.return}return[]}function sf(e){if(e===null)return null;do e=e.return;while(e&&e.tag!==5&&e.tag!==27);return e||null}function cf(e,t,n,r,i){for(var a=t._reactName,o=[];n!==null&&n!==r;){var s=n,c=s.alternate,l=s.stateNode;if(s=s.tag,c!==null&&c===r)break;s!==5&&s!==26&&s!==27||l===null||(c=l,i?(l=vn(n,a),l!=null&&o.unshift(rf(n,l,c))):i||(l=vn(n,a),l!=null&&o.push(rf(n,l,c)))),n=n.return}o.length!==0&&e.push({event:t,listeners:o})}var lf=/\\r\\n?/g,uf=/\\u0000|\\uFFFD/g;function df(e){return(typeof e==`string`?e:``+e).replace(lf,`\n`).replace(uf,``)}function ff(e,t){return t=df(t),df(e)===t}function pf(e,t,n,r,a,o){switch(n){case`children`:typeof r==`string`?t===`body`||t===`textarea`&&r===``||tn(e,r):(typeof r==`number`||typeof r==`bigint`)&&t!==`body`&&tn(e,``+r);break;case`className`:D(e,`class`,r);break;case`tabIndex`:D(e,`tabindex`,r);break;case`dir`:case`role`:case`viewBox`:case`width`:case`height`:D(e,n,r);break;case`style`:an(e,r,o);break;case`data`:if(t!==`object`){D(e,`data`,r);break}case`src`:case`href`:if(r===``&&(t!==`a`||n!==`href`)){e.removeAttribute(n);break}if(r==null||typeof r==`function`||typeof r==`symbol`||typeof r==`boolean`){e.removeAttribute(n);break}r=ln(``+r),e.setAttribute(n,r);break;case`action`:case`formAction`:if(typeof r==`function`){e.setAttribute(n,`javascript:throw new Error('A React form was unexpectedly submitted. If you called form.submit() manually, consider using form.requestSubmit() instead. If you\\\\'re trying to use event.stopPropagation() in a submit event handler, consider also calling event.preventDefault().')`);break}else typeof o==`function`&&(n===`formAction`?(t!==`input`&&pf(e,t,`name`,a.name,a,null),pf(e,t,`formEncType`,a.formEncType,a,null),pf(e,t,`formMethod`,a.formMethod,a,null),pf(e,t,`formTarget`,a.formTarget,a,null)):(pf(e,t,`encType`,a.encType,a,null),pf(e,t,`method`,a.method,a,null),pf(e,t,`target`,a.target,a,null)));if(r==null||typeof r==`symbol`||typeof r==`boolean`){e.removeAttribute(n);break}r=ln(``+r),e.setAttribute(n,r);break;case`onClick`:r!=null&&(e.onclick=un);break;case`onScroll`:r!=null&&F(`scroll`,e);break;case`onScrollEnd`:r!=null&&F(`scrollend`,e);break;case`dangerouslySetInnerHTML`:if(r!=null){if(typeof r!=`object`||!(`__html`in r))throw Error(i(61));if(n=r.__html,n!=null){if(a.children!=null)throw Error(i(60));e.innerHTML=n}}break;case`multiple`:e.multiple=r&&typeof r!=`function`&&typeof r!=`symbol`;break;case`muted`:e.muted=r&&typeof r!=`function`&&typeof r!=`symbol`;break;case`suppressContentEditableWarning`:case`suppressHydrationWarning`:case`defaultValue`:case`defaultChecked`:case`innerHTML`:case`ref`:break;case`autoFocus`:break;case`xlinkHref`:if(r==null||typeof r==`function`||typeof r==`boolean`||typeof r==`symbol`){e.removeAttribute(`xlink:href`);break}n=ln(``+r),e.setAttributeNS(`http://www.w3.org/1999/xlink`,`xlink:href`,n);break;case`contentEditable`:case`spellCheck`:case`draggable`:case`value`:case`autoReverse`:case`externalResourcesRequired`:case`focusable`:case`preserveAlpha`:r!=null&&typeof r!=`function`&&typeof r!=`symbol`?e.setAttribute(n,``+r):e.removeAttribute(n);break;case`inert`:case`allowFullScreen`:case`async`:case`autoPlay`:case`controls`:case`default`:case`defer`:case`disabled`:case`disablePictureInPicture`:case`disableRemotePlayback`:case`formNoValidate`:case`hidden`:case`loop`:case`noModule`:case`noValidate`:case`open`:case`playsInline`:case`readOnly`:case`required`:case`reversed`:case`scoped`:case`seamless`:case`itemScope`:r&&typeof r!=`function`&&typeof r!=`symbol`?e.setAttribute(n,``):e.removeAttribute(n);break;case`capture`:case`download`:!0===r?e.setAttribute(n,``):!1!==r&&r!=null&&typeof r!=`function`&&typeof r!=`symbol`?e.setAttribute(n,r):e.removeAttribute(n);break;case`cols`:case`rows`:case`size`:case`span`:r!=null&&typeof r!=`function`&&typeof r!=`symbol`&&!isNaN(r)&&1<=r?e.setAttribute(n,r):e.removeAttribute(n);break;case`rowSpan`:case`start`:r==null||typeof r==`function`||typeof r==`symbol`||isNaN(r)?e.removeAttribute(n):e.setAttribute(n,r);break;case`popover`:F(`beforetoggle`,e),F(`toggle`,e),Bt(e,`popover`,r);break;case`xlinkActuate`:O(e,`http://www.w3.org/1999/xlink`,`xlink:actuate`,r);break;case`xlinkArcrole`:O(e,`http://www.w3.org/1999/xlink`,`xlink:arcrole`,r);break;case`xlinkRole`:O(e,`http://www.w3.org/1999/xlink`,`xlink:role`,r);break;case`xlinkShow`:O(e,`http://www.w3.org/1999/xlink`,`xlink:show`,r);break;case`xlinkTitle`:O(e,`http://www.w3.org/1999/xlink`,`xlink:title`,r);break;case`xlinkType`:O(e,`http://www.w3.org/1999/xlink`,`xlink:type`,r);break;case`xmlBase`:O(e,`http://www.w3.org/XML/1998/namespace`,`xml:base`,r);break;case`xmlLang`:O(e,`http://www.w3.org/XML/1998/namespace`,`xml:lang`,r);break;case`xmlSpace`:O(e,`http://www.w3.org/XML/1998/namespace`,`xml:space`,r);break;case`is`:Bt(e,`is`,r);break;case`innerText`:case`textContent`:break;default:(!(2<n.length)||n[0]!==`o`&&n[0]!==`O`||n[1]!==`n`&&n[1]!==`N`)&&(n=sn.get(n)||n,Bt(e,n,r))}}function mf(e,t,n,r,a,o){switch(n){case`style`:an(e,r,o);break;case`dangerouslySetInnerHTML`:if(r!=null){if(typeof r!=`object`||!(`__html`in r))throw Error(i(61));if(n=r.__html,n!=null){if(a.children!=null)throw Error(i(60));e.innerHTML=n}}break;case`children`:typeof r==`string`?tn(e,r):(typeof r==`number`||typeof r==`bigint`)&&tn(e,``+r);break;case`onScroll`:r!=null&&F(`scroll`,e);break;case`onScrollEnd`:r!=null&&F(`scrollend`,e);break;case`onClick`:r!=null&&(e.onclick=un);break;case`suppressContentEditableWarning`:case`suppressHydrationWarning`:case`innerHTML`:case`ref`:break;case`innerText`:case`textContent`:break;default:if(!Nt.hasOwnProperty(n))a:{if(n[0]===`o`&&n[1]===`n`&&(a=n.endsWith(`Capture`),t=n.slice(2,a?n.length-7:void 0),o=e[bt]||null,o=o==null?null:o[n],typeof o==`function`&&e.removeEventListener(t,o,a),typeof r==`function`)){typeof o!=`function`&&o!==null&&(n in e?e[n]=null:e.hasAttribute(n)&&e.removeAttribute(n)),e.addEventListener(t,r,a);break a}n in e?e[n]=r:!0===r?e.setAttribute(n,``):Bt(e,n,r)}}}function hf(e,t,n){switch(t){case`div`:case`span`:case`svg`:case`path`:case`a`:case`g`:case`p`:case`li`:break;case`img`:F(`error`,e),F(`load`,e);var r=!1,a=!1,o;for(o in n)if(n.hasOwnProperty(o)){var s=n[o];if(s!=null)switch(o){case`src`:r=!0;break;case`srcSet`:a=!0;break;case`children`:case`dangerouslySetInnerHTML`:throw Error(i(137,t));default:pf(e,t,o,s,n,null)}}a&&pf(e,t,`srcSet`,n.srcSet,n,null),r&&pf(e,t,`src`,n.src,n,null);return;case`input`:F(`invalid`,e);var c=o=s=a=null,l=null,u=null;for(r in n)if(n.hasOwnProperty(r)){var d=n[r];if(d!=null)switch(r){case`name`:a=d;break;case`type`:s=d;break;case`checked`:l=d;break;case`defaultChecked`:u=d;break;case`value`:o=d;break;case`defaultValue`:c=d;break;case`children`:case`dangerouslySetInnerHTML`:if(d!=null)throw Error(i(137,t));break;default:pf(e,t,r,d,n,null)}}Xt(e,o,c,l,u,s,a,!1);return;case`select`:for(a in F(`invalid`,e),r=s=o=null,n)if(n.hasOwnProperty(a)&&(c=n[a],c!=null))switch(a){case`value`:o=c;break;case`defaultValue`:s=c;break;case`multiple`:r=c;default:pf(e,t,a,c,n,null)}t=o,n=s,e.multiple=!!r,t==null?n!=null&&Qt(e,!!r,n,!0):Qt(e,!!r,t,!1);return;case`textarea`:for(s in F(`invalid`,e),o=a=r=null,n)if(n.hasOwnProperty(s)&&(c=n[s],c!=null))switch(s){case`value`:r=c;break;case`defaultValue`:a=c;break;case`children`:o=c;break;case`dangerouslySetInnerHTML`:if(c!=null)throw Error(i(91));break;default:pf(e,t,s,c,n,null)}en(e,r,a,o);return;case`option`:for(l in n)if(n.hasOwnProperty(l)&&(r=n[l],r!=null))switch(l){case`selected`:e.selected=r&&typeof r!=`function`&&typeof r!=`symbol`;break;default:pf(e,t,l,r,n,null)}return;case`dialog`:F(`beforetoggle`,e),F(`toggle`,e),F(`cancel`,e),F(`close`,e);break;case`iframe`:case`object`:F(`load`,e);break;case`video`:case`audio`:for(r=0;r<Yd.length;r++)F(Yd[r],e);break;case`image`:F(`error`,e),F(`load`,e);break;case`details`:F(`toggle`,e);break;case`embed`:case`source`:case`link`:F(`error`,e),F(`load`,e);case`area`:case`base`:case`br`:case`col`:case`hr`:case`keygen`:case`meta`:case`param`:case`track`:case`wbr`:case`menuitem`:for(u in n)if(n.hasOwnProperty(u)&&(r=n[u],r!=null))switch(u){case`children`:case`dangerouslySetInnerHTML`:throw Error(i(137,t));default:pf(e,t,u,r,n,null)}return;default:if(on(t)){for(d in n)n.hasOwnProperty(d)&&(r=n[d],r!==void 0&&mf(e,t,d,r,n,void 0));return}}for(c in n)n.hasOwnProperty(c)&&(r=n[c],r!=null&&pf(e,t,c,r,n,null))}function gf(e,t,n,r){switch(t){case`div`:case`span`:case`svg`:case`path`:case`a`:case`g`:case`p`:case`li`:break;case`input`:var a=null,o=null,s=null,c=null,l=null,u=null,d=null;for(m in n){var f=n[m];if(n.hasOwnProperty(m)&&f!=null)switch(m){case`checked`:break;case`value`:break;case`defaultValue`:l=f;default:r.hasOwnProperty(m)||pf(e,t,m,null,r,f)}}for(var p in r){var m=r[p];if(f=n[p],r.hasOwnProperty(p)&&(m!=null||f!=null))switch(p){case`type`:o=m;break;case`name`:a=m;break;case`checked`:u=m;break;case`defaultChecked`:d=m;break;case`value`:s=m;break;case`defaultValue`:c=m;break;case`children`:case`dangerouslySetInnerHTML`:if(m!=null)throw Error(i(137,t));break;default:m!==f&&pf(e,t,p,m,r,f)}}Yt(e,s,c,l,u,d,o,a);return;case`select`:for(o in m=s=c=p=null,n)if(l=n[o],n.hasOwnProperty(o)&&l!=null)switch(o){case`value`:break;case`multiple`:m=l;default:r.hasOwnProperty(o)||pf(e,t,o,null,r,l)}for(a in r)if(o=r[a],l=n[a],r.hasOwnProperty(a)&&(o!=null||l!=null))switch(a){case`value`:p=o;break;case`defaultValue`:c=o;break;case`multiple`:s=o;default:o!==l&&pf(e,t,a,o,r,l)}t=c,n=s,r=m,p==null?!!r!=!!n&&(t==null?Qt(e,!!n,n?[]:``,!1):Qt(e,!!n,t,!0)):Qt(e,!!n,p,!1);return;case`textarea`:for(c in m=p=null,n)if(a=n[c],n.hasOwnProperty(c)&&a!=null&&!r.hasOwnProperty(c))switch(c){case`value`:break;case`children`:break;default:pf(e,t,c,null,r,a)}for(s in r)if(a=r[s],o=n[s],r.hasOwnProperty(s)&&(a!=null||o!=null))switch(s){case`value`:p=a;break;case`defaultValue`:m=a;break;case`children`:break;case`dangerouslySetInnerHTML`:if(a!=null)throw Error(i(91));break;default:a!==o&&pf(e,t,s,a,r,o)}$t(e,p,m);return;case`option`:for(var h in n)if(p=n[h],n.hasOwnProperty(h)&&p!=null&&!r.hasOwnProperty(h))switch(h){case`selected`:e.selected=!1;break;default:pf(e,t,h,null,r,p)}for(l in r)if(p=r[l],m=n[l],r.hasOwnProperty(l)&&p!==m&&(p!=null||m!=null))switch(l){case`selected`:e.selected=p&&typeof p!=`function`&&typeof p!=`symbol`;break;default:pf(e,t,l,p,r,m)}return;case`img`:case`link`:case`area`:case`base`:case`br`:case`col`:case`embed`:case`hr`:case`keygen`:case`meta`:case`param`:case`source`:case`track`:case`wbr`:case`menuitem`:for(var g in n)p=n[g],n.hasOwnProperty(g)&&p!=null&&!r.hasOwnProperty(g)&&pf(e,t,g,null,r,p);for(u in r)if(p=r[u],m=n[u],r.hasOwnProperty(u)&&p!==m&&(p!=null||m!=null))switch(u){case`children`:case`dangerouslySetInnerHTML`:if(p!=null)throw Error(i(137,t));break;default:pf(e,t,u,p,r,m)}return;default:if(on(t)){for(var _ in n)p=n[_],n.hasOwnProperty(_)&&p!==void 0&&!r.hasOwnProperty(_)&&mf(e,t,_,void 0,r,p);for(d in r)p=r[d],m=n[d],!r.hasOwnProperty(d)||p===m||p===void 0&&m===void 0||mf(e,t,d,p,r,m);return}}for(var v in n)p=n[v],n.hasOwnProperty(v)&&p!=null&&!r.hasOwnProperty(v)&&pf(e,t,v,null,r,p);for(f in r)p=r[f],m=n[f],!r.hasOwnProperty(f)||p===m||p==null&&m==null||pf(e,t,f,p,r,m)}function _f(e){switch(e){case`css`:case`script`:case`font`:case`img`:case`image`:case`input`:case`link`:return!0;default:return!1}}function vf(){if(typeof performance.getEntriesByType==`function`){for(var e=0,t=0,n=performance.getEntriesByType(`resource`),r=0;r<n.length;r++){var i=n[r],a=i.transferSize,o=i.initiatorType,s=i.duration;if(a&&s&&_f(o)){for(o=0,s=i.responseEnd,r+=1;r<n.length;r++){var c=n[r],l=c.startTime;if(l>s)break;var u=c.transferSize,d=c.initiatorType;u&&_f(d)&&(c=c.responseEnd,o+=u*(c<s?1:(s-l)/(c-l)))}if(--r,t+=8*(a+o)/(i.duration/1e3),e++,10<e)break}}if(0<e)return t/e/1e6}return navigator.connection&&(e=navigator.connection.downlink,typeof e==`number`)?e:5}var yf=null,bf=null;function xf(e){return e.nodeType===9?e:e.ownerDocument}function Sf(e){switch(e){case`http://www.w3.org/2000/svg`:return 1;case`http://www.w3.org/1998/Math/MathML`:return 2;default:return 0}}function Cf(e,t){if(e===0)switch(t){case`svg`:return 1;case`math`:return 2;default:return 0}return e===1&&t===`foreignObject`?0:e}function wf(e,t){return e===`textarea`||e===`noscript`||typeof t.children==`string`||typeof t.children==`number`||typeof t.children==`bigint`||typeof t.dangerouslySetInnerHTML==`object`&&t.dangerouslySetInnerHTML!==null&&t.dangerouslySetInnerHTML.__html!=null}var Tf=null;function Ef(){var e=window.event;return e&&e.type===`popstate`?e===Tf?!1:(Tf=e,!0):(Tf=null,!1)}var Df=typeof setTimeout==`function`?setTimeout:void 0,Of=typeof clearTimeout==`function`?clearTimeout:void 0,kf=typeof Promise==`function`?Promise:void 0,Af=typeof queueMicrotask==`function`?queueMicrotask:kf===void 0?Df:function(e){return kf.resolve(null).then(e).catch(jf)};function jf(e){setTimeout(function(){throw e})}function Mf(e){return e===`head`}function Nf(e,t){var n=t,r=0;do{var i=n.nextSibling;if(e.removeChild(n),i&&i.nodeType===8)if(n=i.data,n===`/$`||n===`/&`){if(r===0){e.removeChild(i),fm(t);return}r--}else if(n===`$`||n===`$?`||n===`$~`||n===`$!`||n===`&`)r++;else if(n===`html`)Kf(e.ownerDocument.documentElement);else if(n===`head`){n=e.ownerDocument.head,Kf(n);for(var a=n.firstChild;a;){var o=a.nextSibling,s=a.nodeName;a[Et]||s===`SCRIPT`||s===`STYLE`||s===`LINK`&&a.rel.toLowerCase()===`stylesheet`||n.removeChild(a),a=o}}else n===`body`&&Kf(e.ownerDocument.body);n=i}while(n);fm(t)}function Pf(e,t){var n=e;e=0;do{var r=n.nextSibling;if(n.nodeType===1?t?(n._stashedDisplay=n.style.display,n.style.display=`none`):(n.style.display=n._stashedDisplay||``,n.getAttribute(`style`)===``&&n.removeAttribute(`style`)):n.nodeType===3&&(t?(n._stashedText=n.nodeValue,n.nodeValue=``):n.nodeValue=n._stashedText||``),r&&r.nodeType===8)if(n=r.data,n===`/$`){if(e===0)break;e--}else n!==`$`&&n!==`$?`&&n!==`$~`&&n!==`$!`||e++;n=r}while(n)}function Ff(e){var t=e.firstChild;for(t&&t.nodeType===10&&(t=t.nextSibling);t;){var n=t;switch(t=t.nextSibling,n.nodeName){case`HTML`:case`HEAD`:case`BODY`:Ff(n),Dt(n);continue;case`SCRIPT`:case`STYLE`:continue;case`LINK`:if(n.rel.toLowerCase()===`stylesheet`)continue}e.removeChild(n)}}function If(e,t,n,r){for(;e.nodeType===1;){var i=n;if(e.nodeName.toLowerCase()!==t.toLowerCase()){if(!r&&(e.nodeName!==`INPUT`||e.type!==`hidden`))break}else if(r){if(!e[Et])switch(t){case`meta`:if(!e.hasAttribute(`itemprop`))break;return e;case`link`:if(a=e.getAttribute(`rel`),a===`stylesheet`&&e.hasAttribute(`data-precedence`)||a!==i.rel||e.getAttribute(`href`)!==(i.href==null||i.href===``?null:i.href)||e.getAttribute(`crossorigin`)!==(i.crossOrigin==null?null:i.crossOrigin)||e.getAttribute(`title`)!==(i.title==null?null:i.title))break;return e;case`style`:if(e.hasAttribute(`data-precedence`))break;return e;case`script`:if(a=e.getAttribute(`src`),(a!==(i.src==null?null:i.src)||e.getAttribute(`type`)!==(i.type==null?null:i.type)||e.getAttribute(`crossorigin`)!==(i.crossOrigin==null?null:i.crossOrigin))&&a&&e.hasAttribute(`async`)&&!e.hasAttribute(`itemprop`))break;return e;default:return e}}else if(t===`input`&&e.type===`hidden`){var a=i.name==null?null:``+i.name;if(i.type===`hidden`&&e.getAttribute(`name`)===a)return e}else return e;if(e=Hf(e.nextSibling),e===null)break}return null}function Lf(e,t,n){if(t===``)return null;for(;e.nodeType!==3;)if((e.nodeType!==1||e.nodeName!==`INPUT`||e.type!==`hidden`)&&!n||(e=Hf(e.nextSibling),e===null))return null;return e}function Rf(e,t){for(;e.nodeType!==8;)if((e.nodeType!==1||e.nodeName!==`INPUT`||e.type!==`hidden`)&&!t||(e=Hf(e.nextSibling),e===null))return null;return e}function zf(e){return e.data===`$?`||e.data===`$~`}function Bf(e){return e.data===`$!`||e.data===`$?`&&e.ownerDocument.readyState!==`loading`}function Vf(e,t){var n=e.ownerDocument;if(e.data===`$~`)e._reactRetry=t;else if(e.data!==`$?`||n.readyState!==`loading`)t();else{var r=function(){t(),n.removeEventListener(`DOMContentLoaded`,r)};n.addEventListener(`DOMContentLoaded`,r),e._reactRetry=r}}function Hf(e){for(;e!=null;e=e.nextSibling){var t=e.nodeType;if(t===1||t===3)break;if(t===8){if(t=e.data,t===`$`||t===`$!`||t===`$?`||t===`$~`||t===`&`||t===`F!`||t===`F`)break;if(t===`/$`||t===`/&`)return null}}return e}var I=null;function Uf(e){e=e.nextSibling;for(var t=0;e;){if(e.nodeType===8){var n=e.data;if(n===`/$`||n===`/&`){if(t===0)return Hf(e.nextSibling);t--}else n!==`$`&&n!==`$!`&&n!==`$?`&&n!==`$~`&&n!==`&`||t++}e=e.nextSibling}return null}function Wf(e){e=e.previousSibling;for(var t=0;e;){if(e.nodeType===8){var n=e.data;if(n===`$`||n===`$!`||n===`$?`||n===`$~`||n===`&`){if(t===0)return e;t--}else n!==`/$`&&n!==`/&`||t++}e=e.previousSibling}return null}function Gf(e,t,n){switch(t=xf(n),e){case`html`:if(e=t.documentElement,!e)throw Error(i(452));return e;case`head`:if(e=t.head,!e)throw Error(i(453));return e;case`body`:if(e=t.body,!e)throw Error(i(454));return e;default:throw Error(i(451))}}function Kf(e){for(var t=e.attributes;t.length;)e.removeAttributeNode(t[0]);Dt(e)}var qf=new Map,Jf=new Set;function Yf(e){return typeof e.getRootNode==`function`?e.getRootNode():e.nodeType===9?e:e.ownerDocument}var Xf=de.d;de.d={f:Zf,r:Qf,D:tp,C:np,L:rp,m:ip,X:op,S:ap,M:sp};function Zf(){var e=Xf.f(),t=Xu();return e||t}function Qf(e){var t=E(e);t!==null&&t.tag===5&&t.type===`form`?Zs(t):Xf.r(e)}var $f=typeof document>`u`?null:document;function ep(e,t,n){var r=$f;if(r&&typeof t==`string`&&t){var i=Jt(t);i=`link[rel=\"`+e+`\"][href=\"`+i+`\"]`,typeof n==`string`&&(i+=`[crossorigin=\"`+n+`\"]`),Jf.has(i)||(Jf.add(i),e={rel:e,crossOrigin:n,href:t},r.querySelector(i)===null&&(t=r.createElement(`link`),hf(t,`link`,e),jt(t),r.head.appendChild(t)))}}function tp(e){Xf.D(e),ep(`dns-prefetch`,e,null)}function np(e,t){Xf.C(e,t),ep(`preconnect`,e,t)}function rp(e,t,n){Xf.L(e,t,n);var r=$f;if(r&&e&&t){var i=`link[rel=\"preload\"][as=\"`+Jt(t)+`\"]`;t===`image`&&n&&n.imageSrcSet?(i+=`[imagesrcset=\"`+Jt(n.imageSrcSet)+`\"]`,typeof n.imageSizes==`string`&&(i+=`[imagesizes=\"`+Jt(n.imageSizes)+`\"]`)):i+=`[href=\"`+Jt(e)+`\"]`;var a=i;switch(t){case`style`:a=lp(e);break;case`script`:a=pp(e)}qf.has(a)||(e=p({rel:`preload`,href:t===`image`&&n&&n.imageSrcSet?void 0:e,as:t},n),qf.set(a,e),r.querySelector(i)!==null||t===`style`&&r.querySelector(up(a))||t===`script`&&r.querySelector(mp(a))||(t=r.createElement(`link`),hf(t,`link`,e),jt(t),r.head.appendChild(t)))}}function ip(e,t){Xf.m(e,t);var n=$f;if(n&&e){var r=t&&typeof t.as==`string`?t.as:`script`,i=`link[rel=\"modulepreload\"][as=\"`+Jt(r)+`\"][href=\"`+Jt(e)+`\"]`,a=i;switch(r){case`audioworklet`:case`paintworklet`:case`serviceworker`:case`sharedworker`:case`worker`:case`script`:a=pp(e)}if(!qf.has(a)&&(e=p({rel:`modulepreload`,href:e},t),qf.set(a,e),n.querySelector(i)===null)){switch(r){case`audioworklet`:case`paintworklet`:case`serviceworker`:case`sharedworker`:case`worker`:case`script`:if(n.querySelector(mp(a)))return}r=n.createElement(`link`),hf(r,`link`,e),jt(r),n.head.appendChild(r)}}}function ap(e,t,n){Xf.S(e,t,n);var r=$f;if(r&&e){var i=At(r).hoistableStyles,a=lp(e);t||=`default`;var o=i.get(a);if(!o){var s={loading:0,preload:null};if(o=r.querySelector(up(a)))s.loading=5;else{e=p({rel:`stylesheet`,href:e,\"data-precedence\":t},n),(n=qf.get(a))&&_p(e,n);var c=o=r.createElement(`link`);jt(c),hf(c,`link`,e),c._p=new Promise(function(e,t){c.onload=e,c.onerror=t}),c.addEventListener(`load`,function(){s.loading|=1}),c.addEventListener(`error`,function(){s.loading|=2}),s.loading|=4,gp(o,t,r)}o={type:`stylesheet`,instance:o,count:1,state:s},i.set(a,o)}}}function op(e,t){Xf.X(e,t);var n=$f;if(n&&e){var r=At(n).hoistableScripts,i=pp(e),a=r.get(i);a||(a=n.querySelector(mp(i)),a||(e=p({src:e,async:!0},t),(t=qf.get(i))&&vp(e,t),a=n.createElement(`script`),jt(a),hf(a,`link`,e),n.head.appendChild(a)),a={type:`script`,instance:a,count:1,state:null},r.set(i,a))}}function sp(e,t){Xf.M(e,t);var n=$f;if(n&&e){var r=At(n).hoistableScripts,i=pp(e),a=r.get(i);a||(a=n.querySelector(mp(i)),a||(e=p({src:e,async:!0,type:`module`},t),(t=qf.get(i))&&vp(e,t),a=n.createElement(`script`),jt(a),hf(a,`link`,e),n.head.appendChild(a)),a={type:`script`,instance:a,count:1,state:null},r.set(i,a))}}function cp(e,t,n,r){var a=(a=be.current)?Yf(a):null;if(!a)throw Error(i(446));switch(e){case`meta`:case`title`:return null;case`style`:return typeof n.precedence==`string`&&typeof n.href==`string`?(t=lp(n.href),n=At(a).hoistableStyles,r=n.get(t),r||(r={type:`style`,instance:null,count:0,state:null},n.set(t,r)),r):{type:`void`,instance:null,count:0,state:null};case`link`:if(n.rel===`stylesheet`&&typeof n.href==`string`&&typeof n.precedence==`string`){e=lp(n.href);var o=At(a).hoistableStyles,s=o.get(e);if(s||(a=a.ownerDocument||a,s={type:`stylesheet`,instance:null,count:0,state:{loading:0,preload:null}},o.set(e,s),(o=a.querySelector(up(e)))&&!o._p&&(s.instance=o,s.state.loading=5),qf.has(e)||(n={rel:`preload`,as:`style`,href:n.href,crossOrigin:n.crossOrigin,integrity:n.integrity,media:n.media,hrefLang:n.hrefLang,referrerPolicy:n.referrerPolicy},qf.set(e,n),o||fp(a,e,n,s.state))),t&&r===null)throw Error(i(528,``));return s}if(t&&r!==null)throw Error(i(529,``));return null;case`script`:return t=n.async,n=n.src,typeof n==`string`&&t&&typeof t!=`function`&&typeof t!=`symbol`?(t=pp(n),n=At(a).hoistableScripts,r=n.get(t),r||(r={type:`script`,instance:null,count:0,state:null},n.set(t,r)),r):{type:`void`,instance:null,count:0,state:null};default:throw Error(i(444,e))}}function lp(e){return`href=\"`+Jt(e)+`\"`}function up(e){return`link[rel=\"stylesheet\"][`+e+`]`}function dp(e){return p({},e,{\"data-precedence\":e.precedence,precedence:null})}function fp(e,t,n,r){e.querySelector(`link[rel=\"preload\"][as=\"style\"][`+t+`]`)?r.loading=1:(t=e.createElement(`link`),r.preload=t,t.addEventListener(`load`,function(){return r.loading|=1}),t.addEventListener(`error`,function(){return r.loading|=2}),hf(t,`link`,n),jt(t),e.head.appendChild(t))}function pp(e){return`[src=\"`+Jt(e)+`\"]`}function mp(e){return`script[async]`+e}function hp(e,t,n){if(t.count++,t.instance===null)switch(t.type){case`style`:var r=e.querySelector(`style[data-href~=\"`+Jt(n.href)+`\"]`);if(r)return t.instance=r,jt(r),r;var a=p({},n,{\"data-href\":n.href,\"data-precedence\":n.precedence,href:null,precedence:null});return r=(e.ownerDocument||e).createElement(`style`),jt(r),hf(r,`style`,a),gp(r,n.precedence,e),t.instance=r;case`stylesheet`:a=lp(n.href);var o=e.querySelector(up(a));if(o)return t.state.loading|=4,t.instance=o,jt(o),o;r=dp(n),(a=qf.get(a))&&_p(r,a),o=(e.ownerDocument||e).createElement(`link`),jt(o);var s=o;return s._p=new Promise(function(e,t){s.onload=e,s.onerror=t}),hf(o,`link`,r),t.state.loading|=4,gp(o,n.precedence,e),t.instance=o;case`script`:return o=pp(n.src),(a=e.querySelector(mp(o)))?(t.instance=a,jt(a),a):(r=n,(a=qf.get(o))&&(r=p({},n),vp(r,a)),e=e.ownerDocument||e,a=e.createElement(`script`),jt(a),hf(a,`link`,r),e.head.appendChild(a),t.instance=a);case`void`:return null;default:throw Error(i(443,t.type))}else t.type===`stylesheet`&&!(t.state.loading&4)&&(r=t.instance,t.state.loading|=4,gp(r,n.precedence,e));return t.instance}function gp(e,t,n){for(var r=n.querySelectorAll(`link[rel=\"stylesheet\"][data-precedence],style[data-precedence]`),i=r.length?r[r.length-1]:null,a=i,o=0;o<r.length;o++){var s=r[o];if(s.dataset.precedence===t)a=s;else if(a!==i)break}a?a.parentNode.insertBefore(e,a.nextSibling):(t=n.nodeType===9?n.head:n,t.insertBefore(e,t.firstChild))}function _p(e,t){e.crossOrigin??=t.crossOrigin,e.referrerPolicy??=t.referrerPolicy,e.title??=t.title}function vp(e,t){e.crossOrigin??=t.crossOrigin,e.referrerPolicy??=t.referrerPolicy,e.integrity??=t.integrity}var yp=null;function bp(e,t,n){if(yp===null){var r=new Map,i=yp=new Map;i.set(n,r)}else i=yp,r=i.get(n),r||(r=new Map,i.set(n,r));if(r.has(e))return r;for(r.set(e,null),n=n.getElementsByTagName(e),i=0;i<n.length;i++){var a=n[i];if(!(a[Et]||a[yt]||e===`link`&&a.getAttribute(`rel`)===`stylesheet`)&&a.namespaceURI!==`http://www.w3.org/2000/svg`){var o=a.getAttribute(t)||``;o=e+o;var s=r.get(o);s?s.push(a):r.set(o,[a])}}return r}function xp(e,t,n){e=e.ownerDocument||e,e.head.insertBefore(n,t===`title`?e.querySelector(`head > title`):null)}function Sp(e,t,n){if(n===1||t.itemProp!=null)return!1;switch(e){case`meta`:case`title`:return!0;case`style`:if(typeof t.precedence!=`string`||typeof t.href!=`string`||t.href===``)break;return!0;case`link`:if(typeof t.rel!=`string`||typeof t.href!=`string`||t.href===``||t.onLoad||t.onError)break;switch(t.rel){case`stylesheet`:return e=t.disabled,typeof t.precedence==`string`&&e==null;default:return!0}case`script`:if(t.async&&typeof t.async!=`function`&&typeof t.async!=`symbol`&&!t.onLoad&&!t.onError&&t.src&&typeof t.src==`string`)return!0}return!1}function Cp(e){return!(e.type===`stylesheet`&&!(e.state.loading&3))}function wp(e,t,n,r){if(n.type===`stylesheet`&&(typeof r.media!=`string`||!1!==matchMedia(r.media).matches)&&!(n.state.loading&4)){if(n.instance===null){var i=lp(r.href),a=t.querySelector(up(i));if(a){t=a._p,typeof t==`object`&&t&&typeof t.then==`function`&&(e.count++,e=Dp.bind(e),t.then(e,e)),n.state.loading|=4,n.instance=a,jt(a);return}a=t.ownerDocument||t,r=dp(r),(i=qf.get(i))&&_p(r,i),a=a.createElement(`link`),jt(a);var o=a;o._p=new Promise(function(e,t){o.onload=e,o.onerror=t}),hf(a,`link`,r),n.instance=a}e.stylesheets===null&&(e.stylesheets=new Map),e.stylesheets.set(n,t),(t=n.state.preload)&&!(n.state.loading&3)&&(e.count++,n=Dp.bind(e),t.addEventListener(`load`,n),t.addEventListener(`error`,n))}}var Tp=0;function Ep(e,t){return e.stylesheets&&e.count===0&&kp(e,e.stylesheets),0<e.count||0<e.imgCount?function(n){var r=setTimeout(function(){if(e.stylesheets&&kp(e,e.stylesheets),e.unsuspend){var t=e.unsuspend;e.unsuspend=null,t()}},6e4+t);0<e.imgBytes&&Tp===0&&(Tp=62500*vf());var i=setTimeout(function(){if(e.waitingForImages=!1,e.count===0&&(e.stylesheets&&kp(e,e.stylesheets),e.unsuspend)){var t=e.unsuspend;e.unsuspend=null,t()}},(e.imgBytes>Tp?50:800)+t);return e.unsuspend=n,function(){e.unsuspend=null,clearTimeout(r),clearTimeout(i)}}:null}function Dp(){if(this.count--,this.count===0&&(this.imgCount===0||!this.waitingForImages)){if(this.stylesheets)kp(this,this.stylesheets);else if(this.unsuspend){var e=this.unsuspend;this.unsuspend=null,e()}}}var Op=null;function kp(e,t){e.stylesheets=null,e.unsuspend!==null&&(e.count++,Op=new Map,t.forEach(Ap,e),Op=null,Dp.call(e))}function Ap(e,t){if(!(t.state.loading&4)){var n=Op.get(e);if(n)var r=n.get(null);else{n=new Map,Op.set(e,n);for(var i=e.querySelectorAll(`link[data-precedence],style[data-precedence]`),a=0;a<i.length;a++){var o=i[a];(o.nodeName===`LINK`||o.getAttribute(`media`)!==`not all`)&&(n.set(o.dataset.precedence,o),r=o)}r&&n.set(null,r)}i=t.instance,o=i.getAttribute(`data-precedence`),a=n.get(o)||r,a===r&&n.set(null,i),n.set(o,i),this.count++,r=Dp.bind(this),i.addEventListener(`load`,r),i.addEventListener(`error`,r),a?a.parentNode.insertBefore(i,a.nextSibling):(e=e.nodeType===9?e.head:e,e.insertBefore(i,e.firstChild)),t.state.loading|=4}}var jp={$$typeof:C,Provider:null,Consumer:null,_currentValue:fe,_currentValue2:fe,_threadCount:0};function Mp(e,t,n,r,i,a,o,s,c){this.tag=1,this.containerInfo=e,this.pingCache=this.current=this.pendingChildren=null,this.timeoutHandle=-1,this.callbackNode=this.next=this.pendingContext=this.context=this.cancelPendingCommit=null,this.callbackPriority=0,this.expirationTimes=ct(-1),this.entangledLanes=this.shellSuspendCounter=this.errorRecoveryDisabledLanes=this.expiredLanes=this.warmLanes=this.pingedLanes=this.suspendedLanes=this.pendingLanes=0,this.entanglements=ct(0),this.hiddenUpdates=ct(null),this.identifierPrefix=r,this.onUncaughtError=i,this.onCaughtError=a,this.onRecoverableError=o,this.pooledCache=null,this.pooledCacheLanes=0,this.formState=c,this.incompleteTransitions=new Map}function Np(e,t,n,r,i,a,o,s,c,l,u,d){return e=new Mp(e,t,n,o,c,l,u,d,s),t=1,!0===a&&(t|=24),a=Di(3,null,null,t),e.current=a,a.stateNode=e,t=Oa(),t.refCount++,e.pooledCache=t,t.refCount++,a.memoizedState={element:r,isDehydrated:n,cache:t},so(a),e}function Pp(e){return e?(e=Ti,e):Ti}function Fp(e,t,n,r,i,a){i=Pp(i),r.context===null?r.context=i:r.pendingContext=i,r=lo(t),r.payload={element:n},a=a===void 0?null:a,a!==null&&(r.callback=a),n=uo(e,r,t),n!==null&&(Gu(n,e,t),fo(n,e,t))}function Ip(e,t){if(e=e.memoizedState,e!==null&&e.dehydrated!==null){var n=e.retryLane;e.retryLane=n!==0&&n<t?n:t}}function Lp(e,t){Ip(e,t),(e=e.alternate)&&Ip(e,t)}function Rp(e){if(e.tag===13||e.tag===31){var t=Si(e,67108864);t!==null&&Gu(t,e,67108864),Lp(e,67108864)}}function zp(e){if(e.tag===13||e.tag===31){var t=Uu();t=mt(t);var n=Si(e,t);n!==null&&Gu(n,e,t),Lp(e,t)}}var Bp=!0;function Vp(e,t,n,r){var i=T.T;T.T=null;var a=de.p;try{de.p=2,Up(e,t,n,r)}finally{de.p=a,T.T=i}}function Hp(e,t,n,r){var i=T.T;T.T=null;var a=de.p;try{de.p=8,Up(e,t,n,r)}finally{de.p=a,T.T=i}}function Up(e,t,n,r){if(Bp){var i=Wp(r);if(i===null)nf(e,t,r,Gp,n),nm(e,r);else if(im(i,e,t,n,r))r.stopPropagation();else if(nm(e,r),t&4&&-1<tm.indexOf(e)){for(;i!==null;){var a=E(i);if(a!==null)switch(a.tag){case 3:if(a=a.stateNode,a.current.memoizedState.isDehydrated){var o=rt(a.pendingLanes);if(o!==0){var s=a;for(s.pendingLanes|=2,s.entangledLanes|=2;o;){var c=1<<31-Xe(o);s.entanglements[1]|=c,o&=~c}Pd(a),!(fu&6)&&(ju=Re()+500,Fd(0,!1))}}break;case 31:case 13:s=Si(a,2),s!==null&&Gu(s,a,2),Xu(),Lp(a,2)}if(a=Wp(r),a===null&&nf(e,t,r,Gp,n),a===i)break;i=a}i!==null&&r.stopPropagation()}else nf(e,t,r,null,n)}}function Wp(e){return e=fn(e),Kp(e)}var Gp=null;function Kp(e){if(Gp=null,e=Ot(e),e!==null){var t=o(e);if(t===null)e=null;else{var n=t.tag;if(n===13){if(e=s(t),e!==null)return e;e=null}else if(n===31){if(e=c(t),e!==null)return e;e=null}else if(n===3){if(t.stateNode.current.memoizedState.isDehydrated)return t.tag===3?t.stateNode.containerInfo:null;e=null}else t!==e&&(e=null)}}return Gp=e,null}function qp(e){switch(e){case`beforetoggle`:case`cancel`:case`click`:case`close`:case`contextmenu`:case`copy`:case`cut`:case`auxclick`:case`dblclick`:case`dragend`:case`dragstart`:case`drop`:case`focusin`:case`focusout`:case`input`:case`invalid`:case`keydown`:case`keypress`:case`keyup`:case`mousedown`:case`mouseup`:case`paste`:case`pause`:case`play`:case`pointercancel`:case`pointerdown`:case`pointerup`:case`ratechange`:case`reset`:case`resize`:case`seeked`:case`submit`:case`toggle`:case`touchcancel`:case`touchend`:case`touchstart`:case`volumechange`:case`change`:case`selectionchange`:case`textInput`:case`compositionstart`:case`compositionend`:case`compositionupdate`:case`beforeblur`:case`afterblur`:case`beforeinput`:case`blur`:case`fullscreenchange`:case`focus`:case`hashchange`:case`popstate`:case`select`:case`selectstart`:return 2;case`drag`:case`dragenter`:case`dragexit`:case`dragleave`:case`dragover`:case`mousemove`:case`mouseout`:case`mouseover`:case`pointermove`:case`pointerout`:case`pointerover`:case`scroll`:case`touchmove`:case`wheel`:case`mouseenter`:case`mouseleave`:case`pointerenter`:case`pointerleave`:return 8;case`message`:switch(ze()){case Be:return 2;case Ve:return 8;case He:case Ue:return 32;case We:return 268435456;default:return 32}default:return 32}}var Jp=!1,Yp=null,Xp=null,Zp=null,Qp=new Map,$p=new Map,em=[],tm=`mousedown mouseup touchcancel touchend touchstart auxclick dblclick pointercancel pointerdown pointerup dragend dragstart drop compositionend compositionstart keydown keypress keyup input textInput copy cut paste click change contextmenu reset`.split(` `);function nm(e,t){switch(e){case`focusin`:case`focusout`:Yp=null;break;case`dragenter`:case`dragleave`:Xp=null;break;case`mouseover`:case`mouseout`:Zp=null;break;case`pointerover`:case`pointerout`:Qp.delete(t.pointerId);break;case`gotpointercapture`:case`lostpointercapture`:$p.delete(t.pointerId)}}function rm(e,t,n,r,i,a){return e===null||e.nativeEvent!==a?(e={blockedOn:t,domEventName:n,eventSystemFlags:r,nativeEvent:a,targetContainers:[i]},t!==null&&(t=E(t),t!==null&&Rp(t)),e):(e.eventSystemFlags|=r,t=e.targetContainers,i!==null&&t.indexOf(i)===-1&&t.push(i),e)}function im(e,t,n,r,i){switch(t){case`focusin`:return Yp=rm(Yp,e,t,n,r,i),!0;case`dragenter`:return Xp=rm(Xp,e,t,n,r,i),!0;case`mouseover`:return Zp=rm(Zp,e,t,n,r,i),!0;case`pointerover`:var a=i.pointerId;return Qp.set(a,rm(Qp.get(a)||null,e,t,n,r,i)),!0;case`gotpointercapture`:return a=i.pointerId,$p.set(a,rm($p.get(a)||null,e,t,n,r,i)),!0}return!1}function am(e){var t=Ot(e.target);if(t!==null){var n=o(t);if(n!==null){if(t=n.tag,t===13){if(t=s(n),t!==null){e.blockedOn=t,_t(e.priority,function(){zp(n)});return}}else if(t===31){if(t=c(n),t!==null){e.blockedOn=t,_t(e.priority,function(){zp(n)});return}}else if(t===3&&n.stateNode.current.memoizedState.isDehydrated){e.blockedOn=n.tag===3?n.stateNode.containerInfo:null;return}}}e.blockedOn=null}function om(e){if(e.blockedOn!==null)return!1;for(var t=e.targetContainers;0<t.length;){var n=Wp(e.nativeEvent);if(n===null){n=e.nativeEvent;var r=new n.constructor(n.type,n);dn=r,n.target.dispatchEvent(r),dn=null}else return t=E(n),t!==null&&Rp(t),e.blockedOn=n,!1;t.shift()}return!0}function sm(e,t,n){om(e)&&n.delete(t)}function cm(){Jp=!1,Yp!==null&&om(Yp)&&(Yp=null),Xp!==null&&om(Xp)&&(Xp=null),Zp!==null&&om(Zp)&&(Zp=null),Qp.forEach(sm),$p.forEach(sm)}function lm(e,n){e.blockedOn===n&&(e.blockedOn=null,Jp||(Jp=!0,t.unstable_scheduleCallback(t.unstable_NormalPriority,cm)))}var um=null;function dm(e){um!==e&&(um=e,t.unstable_scheduleCallback(t.unstable_NormalPriority,function(){um===e&&(um=null);for(var t=0;t<e.length;t+=3){var n=e[t],r=e[t+1],i=e[t+2];if(typeof r!=`function`){if(Kp(r||n)===null)continue;break}var a=E(n);a!==null&&(e.splice(t,3),t-=3,Ys(a,{pending:!0,data:i,method:n.method,action:r},r,i))}}))}function fm(e){function t(t){return lm(t,e)}Yp!==null&&lm(Yp,e),Xp!==null&&lm(Xp,e),Zp!==null&&lm(Zp,e),Qp.forEach(t),$p.forEach(t);for(var n=0;n<em.length;n++){var r=em[n];r.blockedOn===e&&(r.blockedOn=null)}for(;0<em.length&&(n=em[0],n.blockedOn===null);)am(n),n.blockedOn===null&&em.shift();if(n=(e.ownerDocument||e).$$reactFormReplay,n!=null)for(r=0;r<n.length;r+=3){var i=n[r],a=n[r+1],o=i[bt]||null;if(typeof a==`function`)o||dm(n);else if(o){var s=null;if(a&&a.hasAttribute(`formAction`)){if(i=a,o=a[bt]||null)s=o.formAction;else if(Kp(i)!==null)continue}else s=o.action;typeof s==`function`?n[r+1]=s:(n.splice(r,3),r-=3),dm(n)}}}function pm(){function e(e){e.canIntercept&&e.info===`react-transition`&&e.intercept({handler:function(){return new Promise(function(e){return i=e})},focusReset:`manual`,scroll:`manual`})}function t(){i!==null&&(i(),i=null),r||setTimeout(n,20)}function n(){if(!r&&!navigation.transition){var e=navigation.currentEntry;e&&e.url!=null&&navigation.navigate(e.url,{state:e.getState(),info:`react-transition`,history:`replace`})}}if(typeof navigation==`object`){var r=!1,i=null;return navigation.addEventListener(`navigate`,e),navigation.addEventListener(`navigatesuccess`,t),navigation.addEventListener(`navigateerror`,t),setTimeout(n,100),function(){r=!0,navigation.removeEventListener(`navigate`,e),navigation.removeEventListener(`navigatesuccess`,t),navigation.removeEventListener(`navigateerror`,t),i!==null&&(i(),i=null)}}}function mm(e){this._internalRoot=e}hm.prototype.render=mm.prototype.render=function(e){var t=this._internalRoot;if(t===null)throw Error(i(409));var n=t.current,r=Uu();Fp(n,r,e,t,null,null)},hm.prototype.unmount=mm.prototype.unmount=function(){var e=this._internalRoot;if(e!==null){this._internalRoot=null;var t=e.containerInfo;Fp(e.current,2,null,e,null,null),Xu(),t[xt]=null}};function hm(e){this._internalRoot=e}hm.prototype.unstable_scheduleHydration=function(e){if(e){var t=gt();e={blockedOn:null,target:e,priority:t};for(var n=0;n<em.length&&t!==0&&t<em[n].priority;n++);em.splice(n,0,e),n===0&&am(e)}};var gm=n.version;if(gm!==`19.2.0`)throw Error(i(527,gm,`19.2.0`));de.findDOMNode=function(e){var t=e._reactInternals;if(t===void 0)throw typeof e.render==`function`?Error(i(188)):(e=Object.keys(e).join(`,`),Error(i(268,e)));return e=u(t),e=e===null?null:d(e),e=e===null?null:e.stateNode,e};var _m={bundleType:0,version:`19.2.0`,rendererPackageName:`react-dom`,currentDispatcherRef:T,reconcilerVersion:`19.2.0`};if(typeof __REACT_DEVTOOLS_GLOBAL_HOOK__<`u`){var vm=__REACT_DEVTOOLS_GLOBAL_HOOK__;if(!vm.isDisabled&&vm.supportsFiber)try{qe=vm.inject(_m),Je=vm}catch{}}e.createRoot=function(e,t){if(!a(e))throw Error(i(299));var n=!1,r=``,o=vc,s=yc,c=bc;return t!=null&&(!0===t.unstable_strictMode&&(n=!0),t.identifierPrefix!==void 0&&(r=t.identifierPrefix),t.onUncaughtError!==void 0&&(o=t.onUncaughtError),t.onCaughtError!==void 0&&(s=t.onCaughtError),t.onRecoverableError!==void 0&&(c=t.onRecoverableError)),t=Np(e,1,!1,null,null,n,r,null,o,s,c,pm),e[xt]=t.current,ef(e),new mm(t)}})),v=u(s(((e,t)=>{function n(){if(!(typeof __REACT_DEVTOOLS_GLOBAL_HOOK__>`u`||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!=`function`))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(n)}catch(e){console.error(e)}}n(),t.exports=_()}))()),y=u(f()),b,x=o((()=>{b=`1.1.0`})),S,C=o((()=>{x(),S=class e extends Error{constructor(t,n={}){let r=n.cause instanceof e?n.cause.details:n.cause?.message?n.cause.message:n.details,i=n.cause instanceof e&&n.cause.docsPath||n.docsPath,a=[t||`An error occurred.`,``,...n.metaMessages?[...n.metaMessages,``]:[],...i?[`Docs: https://abitype.dev${i}`]:[],...r?[`Details: ${r}`]:[],`Version: abitype@${b}`].join(`\n`);super(a),Object.defineProperty(this,`details`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`docsPath`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`metaMessages`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`shortMessage`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`AbiTypeError`}),n.cause&&(this.cause=n.cause),this.details=r,this.docsPath=i,this.metaMessages=n.metaMessages,this.shortMessage=t}}}));function w(e,t){return e.exec(t)?.groups}var ee,te,ne,re=o((()=>{ee=/^bytes([1-9]|1[0-9]|2[0-9]|3[0-2])?$/,te=/^u?int(8|16|24|32|40|48|56|64|72|80|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256)?$/,ne=/^\\(.+?\\).*?$/}));function ie(e){let t=e.type;if(ae.test(e.type)&&`components`in e){t=`(`;let n=e.components.length;for(let r=0;r<n;r++){let i=e.components[r];t+=ie(i),r<n-1&&(t+=`, `)}let r=w(ae,e.type);return t+=`)${r?.array??``}`,ie({...e,type:t})}return`indexed`in e&&e.indexed&&(t=`${t} indexed`),e.name?`${t} ${e.name}`:t}var ae,oe=o((()=>{re(),ae=/^tuple(?<array>(\\[(\\d*)\\])*)$/}));function se(e){let t=``,n=e.length;for(let r=0;r<n;r++){let i=e[r];t+=ie(i),r!==n-1&&(t+=`, `)}return t}var ce=o((()=>{oe()}));function le(e){return e.type===`function`?`function ${e.name}(${se(e.inputs)})${e.stateMutability&&e.stateMutability!==`nonpayable`?` ${e.stateMutability}`:``}${e.outputs?.length?` returns (${se(e.outputs)})`:``}`:e.type===`event`?`event ${e.name}(${se(e.inputs)})`:e.type===`error`?`error ${e.name}(${se(e.inputs)})`:e.type===`constructor`?`constructor(${se(e.inputs)})${e.stateMutability===`payable`?` payable`:``}`:e.type===`fallback`?`fallback() external${e.stateMutability===`payable`?` payable`:``}`:`receive() external payable`}var ue=o((()=>{ce()}));function T(e){return Ce.test(e)}function de(e){return w(Ce,e)}function fe(e){return we.test(e)}function pe(e){return w(we,e)}function me(e){return Te.test(e)}function he(e){return w(Te,e)}function ge(e){return Ee.test(e)}function _e(e){return w(Ee,e)}function ve(e){return De.test(e)}function ye(e){return w(De,e)}function be(e){return Oe.test(e)}function xe(e){return w(Oe,e)}function Se(e){return ke.test(e)}var Ce,we,Te,Ee,De,Oe,ke,Ae,je,Me,Ne=o((()=>{re(),Ce=/^error (?<name>[a-zA-Z$_][a-zA-Z0-9$_]*)\\((?<parameters>.*?)\\)$/,we=/^event (?<name>[a-zA-Z$_][a-zA-Z0-9$_]*)\\((?<parameters>.*?)\\)$/,Te=/^function (?<name>[a-zA-Z$_][a-zA-Z0-9$_]*)\\((?<parameters>.*?)\\)(?: (?<scope>external|public{1}))?(?: (?<stateMutability>pure|view|nonpayable|payable{1}))?(?: returns\\s?\\((?<returns>.*?)\\))?$/,Ee=/^struct (?<name>[a-zA-Z$_][a-zA-Z0-9$_]*) \\{(?<properties>.*?)\\}$/,De=/^constructor\\((?<parameters>.*?)\\)(?:\\s(?<stateMutability>payable{1}))?$/,Oe=/^fallback\\(\\) external(?:\\s(?<stateMutability>payable{1}))?$/,ke=/^receive\\(\\) external payable$/,Ae=new Set([`memory`,`indexed`,`storage`,`calldata`]),je=new Set([`indexed`]),Me=new Set([`calldata`,`memory`,`storage`])})),Pe,Fe,Ie,Le=o((()=>{C(),Pe=class extends S{constructor({signature:e}){super(`Failed to parse ABI item.`,{details:`parseAbiItem(${JSON.stringify(e,null,2)})`,docsPath:`/api/human#parseabiitem-1`}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`InvalidAbiItemError`})}},Fe=class extends S{constructor({type:e}){super(`Unknown type.`,{metaMessages:[`Type \"${e}\" is not a valid ABI type. Perhaps you forgot to include a struct signature?`]}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`UnknownTypeError`})}},Ie=class extends S{constructor({type:e}){super(`Unknown type.`,{metaMessages:[`Type \"${e}\" is not a valid ABI type.`]}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`UnknownSolidityTypeError`})}}})),Re,ze,Be,Ve,He,Ue,We=o((()=>{C(),Re=class extends S{constructor({params:e}){super(`Failed to parse ABI parameters.`,{details:`parseAbiParameters(${JSON.stringify(e,null,2)})`,docsPath:`/api/human#parseabiparameters-1`}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`InvalidAbiParametersError`})}},ze=class extends S{constructor({param:e}){super(`Invalid ABI parameter.`,{details:e}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`InvalidParameterError`})}},Be=class extends S{constructor({param:e,name:t}){super(`Invalid ABI parameter.`,{details:e,metaMessages:[`\"${t}\" is a protected Solidity keyword. More info: https://docs.soliditylang.org/en/latest/cheatsheet.html`]}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`SolidityProtectedKeywordError`})}},Ve=class extends S{constructor({param:e,type:t,modifier:n}){super(`Invalid ABI parameter.`,{details:e,metaMessages:[`Modifier \"${n}\" not allowed${t?` in \"${t}\" type`:``}.`]}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`InvalidModifierError`})}},He=class extends S{constructor({param:e,type:t,modifier:n}){super(`Invalid ABI parameter.`,{details:e,metaMessages:[`Modifier \"${n}\" not allowed${t?` in \"${t}\" type`:``}.`,`Data location can only be specified for array, struct, or mapping types, but \"${n}\" was given.`]}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`InvalidFunctionModifierError`})}},Ue=class extends S{constructor({abiParameter:e}){super(`Invalid ABI parameter.`,{details:JSON.stringify(e,null,2),metaMessages:[`ABI parameter type is invalid.`]}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`InvalidAbiTypeParameterError`})}}})),Ge,Ke,qe,Je=o((()=>{C(),Ge=class extends S{constructor({signature:e,type:t}){super(`Invalid ${t} signature.`,{details:e}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`InvalidSignatureError`})}},Ke=class extends S{constructor({signature:e}){super(`Unknown signature.`,{details:e}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`UnknownSignatureError`})}},qe=class extends S{constructor({signature:e}){super(`Invalid struct signature.`,{details:e,metaMessages:[`No properties exist.`]}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`InvalidStructSignatureError`})}}})),Ye,Xe=o((()=>{C(),Ye=class extends S{constructor({type:e}){super(`Circular reference detected.`,{metaMessages:[`Struct \"${e}\" is a circular reference.`]}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`CircularReferenceError`})}}})),Ze,Qe=o((()=>{C(),Ze=class extends S{constructor({current:e,depth:t}){super(`Unbalanced parentheses.`,{metaMessages:[`\"${e.trim()}\" has too many ${t>0?`opening`:`closing`} parentheses.`],details:`Depth \"${t}\"`}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`InvalidParenthesisError`})}}}));function $e(e,t,n){let r=``;if(n)for(let e of Object.entries(n)){if(!e)continue;let t=``;for(let n of e[1])t+=`[${n.type}${n.name?`:${n.name}`:``}]`;r+=`(${e[0]}{${t}})`}return t?`${t}:${e}${r}`:e}var et,tt=o((()=>{et=new Map([[`address`,{type:`address`}],[`bool`,{type:`bool`}],[`bytes`,{type:`bytes`}],[`bytes32`,{type:`bytes32`}],[`int`,{type:`int256`}],[`int256`,{type:`int256`}],[`string`,{type:`string`}],[`uint`,{type:`uint256`}],[`uint8`,{type:`uint8`}],[`uint16`,{type:`uint16`}],[`uint24`,{type:`uint24`}],[`uint32`,{type:`uint32`}],[`uint64`,{type:`uint64`}],[`uint96`,{type:`uint96`}],[`uint112`,{type:`uint112`}],[`uint160`,{type:`uint160`}],[`uint192`,{type:`uint192`}],[`uint256`,{type:`uint256`}],[`address owner`,{type:`address`,name:`owner`}],[`address to`,{type:`address`,name:`to`}],[`bool approved`,{type:`bool`,name:`approved`}],[`bytes _data`,{type:`bytes`,name:`_data`}],[`bytes data`,{type:`bytes`,name:`data`}],[`bytes signature`,{type:`bytes`,name:`signature`}],[`bytes32 hash`,{type:`bytes32`,name:`hash`}],[`bytes32 r`,{type:`bytes32`,name:`r`}],[`bytes32 root`,{type:`bytes32`,name:`root`}],[`bytes32 s`,{type:`bytes32`,name:`s`}],[`string name`,{type:`string`,name:`name`}],[`string symbol`,{type:`string`,name:`symbol`}],[`string tokenURI`,{type:`string`,name:`tokenURI`}],[`uint tokenId`,{type:`uint256`,name:`tokenId`}],[`uint8 v`,{type:`uint8`,name:`v`}],[`uint256 balance`,{type:`uint256`,name:`balance`}],[`uint256 tokenId`,{type:`uint256`,name:`tokenId`}],[`uint256 value`,{type:`uint256`,name:`value`}],[`event:address indexed from`,{type:`address`,name:`from`,indexed:!0}],[`event:address indexed to`,{type:`address`,name:`to`,indexed:!0}],[`event:uint indexed tokenId`,{type:`uint256`,name:`tokenId`,indexed:!0}],[`event:uint256 indexed tokenId`,{type:`uint256`,name:`tokenId`,indexed:!0}]])}));function nt(e,t={}){if(me(e))return rt(e,t);if(fe(e))return it(e,t);if(T(e))return at(e,t);if(ve(e))return ot(e,t);if(be(e))return st(e);if(Se(e))return{type:`receive`,stateMutability:`payable`};throw new Ke({signature:e})}function rt(e,t={}){let n=he(e);if(!n)throw new Ge({signature:e,type:`function`});let r=lt(n.parameters),i=[],a=r.length;for(let e=0;e<a;e++)i.push(ct(r[e],{modifiers:Me,structs:t,type:`function`}));let o=[];if(n.returns){let e=lt(n.returns),r=e.length;for(let n=0;n<r;n++)o.push(ct(e[n],{modifiers:Me,structs:t,type:`function`}))}return{name:n.name,type:`function`,stateMutability:n.stateMutability??`nonpayable`,inputs:i,outputs:o}}function it(e,t={}){let n=pe(e);if(!n)throw new Ge({signature:e,type:`event`});let r=lt(n.parameters),i=[],a=r.length;for(let e=0;e<a;e++)i.push(ct(r[e],{modifiers:je,structs:t,type:`event`}));return{name:n.name,type:`event`,inputs:i}}function at(e,t={}){let n=de(e);if(!n)throw new Ge({signature:e,type:`error`});let r=lt(n.parameters),i=[],a=r.length;for(let e=0;e<a;e++)i.push(ct(r[e],{structs:t,type:`error`}));return{name:n.name,type:`error`,inputs:i}}function ot(e,t={}){let n=ye(e);if(!n)throw new Ge({signature:e,type:`constructor`});let r=lt(n.parameters),i=[],a=r.length;for(let e=0;e<a;e++)i.push(ct(r[e],{structs:t,type:`constructor`}));return{type:`constructor`,stateMutability:n.stateMutability??`nonpayable`,inputs:i}}function st(e){let t=xe(e);if(!t)throw new Ge({signature:e,type:`fallback`});return{type:`fallback`,stateMutability:t.stateMutability??`nonpayable`}}function ct(e,t){let n=$e(e,t?.type,t?.structs);if(et.has(n))return et.get(n);let r=ne.test(e),i=w(r?mt:pt,e);if(!i)throw new ze({param:e});if(i.name&&dt(i.name))throw new Be({param:e,name:i.name});let a=i.name?{name:i.name}:{},o=i.modifier===`indexed`?{indexed:!0}:{},s=t?.structs??{},c,l={};if(r){c=`tuple`;let e=lt(i.type),t=[],n=e.length;for(let r=0;r<n;r++)t.push(ct(e[r],{structs:s}));l={components:t}}else if(i.type in s)c=`tuple`,l={components:s[i.type]};else if(ht.test(i.type))c=`${i.type}256`;else if(i.type===`address payable`)c=`address`;else if(c=i.type,t?.type!==`struct`&&!ut(c))throw new Ie({type:c});if(i.modifier){if(!t?.modifiers?.has?.(i.modifier))throw new Ve({param:e,type:t?.type,modifier:i.modifier});if(Me.has(i.modifier)&&!ft(c,!!i.array))throw new He({param:e,type:t?.type,modifier:i.modifier})}let u={type:`${c}${i.array??``}`,...a,...o,...l};return et.set(n,u),u}function lt(e,t=[],n=``,r=0){let i=e.trim().length;for(let a=0;a<i;a++){let i=e[a],o=e.slice(a+1);switch(i){case`,`:return r===0?lt(o,[...t,n.trim()]):lt(o,t,`${n}${i}`,r);case`(`:return lt(o,t,`${n}${i}`,r+1);case`)`:return lt(o,t,`${n}${i}`,r-1);default:return lt(o,t,`${n}${i}`,r)}}if(n===``)return t;if(r!==0)throw new Ze({current:n,depth:r});return t.push(n.trim()),t}function ut(e){return e===`address`||e===`bool`||e===`function`||e===`string`||ee.test(e)||te.test(e)}function dt(e){return e===`address`||e===`bool`||e===`function`||e===`string`||e===`tuple`||ee.test(e)||te.test(e)||gt.test(e)}function ft(e,t){return t||e===`bytes`||e===`string`||e===`tuple`}var pt,mt,ht,gt,_t=o((()=>{re(),Le(),We(),Je(),Qe(),tt(),Ne(),pt=/^(?<type>[a-zA-Z$_][a-zA-Z0-9$_]*(?:\\spayable)?)(?<array>(?:\\[\\d*?\\])+?)?(?:\\s(?<modifier>calldata|indexed|memory|storage{1}))?(?:\\s(?<name>[a-zA-Z$_][a-zA-Z0-9$_]*))?$/,mt=/^\\((?<type>.+?)\\)(?<array>(?:\\[\\d*?\\])+?)?(?:\\s(?<modifier>calldata|indexed|memory|storage{1}))?(?:\\s(?<name>[a-zA-Z$_][a-zA-Z0-9$_]*))?$/,ht=/^u?int$/,gt=/^(?:after|alias|anonymous|apply|auto|byte|calldata|case|catch|constant|copyof|default|defined|error|event|external|false|final|function|immutable|implements|in|indexed|inline|internal|let|mapping|match|memory|mutable|null|of|override|partial|private|promise|public|pure|reference|relocatable|return|returns|sizeof|static|storage|struct|super|supports|switch|this|true|try|typedef|typeof|var|view|virtual)$/}));function vt(e){let t={},n=e.length;for(let r=0;r<n;r++){let n=e[r];if(!ge(n))continue;let i=_e(n);if(!i)throw new Ge({signature:n,type:`struct`});let a=i.properties.split(`;`),o=[],s=a.length;for(let e=0;e<s;e++){let t=a[e].trim();if(!t)continue;let n=ct(t,{type:`struct`});o.push(n)}if(!o.length)throw new qe({signature:n});t[i.name]=o}let r={},i=Object.entries(t),a=i.length;for(let e=0;e<a;e++){let[n,a]=i[e];r[n]=yt(a,t)}return r}function yt(e,t,n=new Set){let r=[],i=e.length;for(let a=0;a<i;a++){let i=e[a];if(ne.test(i.type))r.push(i);else{let e=w(bt,i.type);if(!e?.type)throw new Ue({abiParameter:i});let{array:a,type:o}=e;if(o in t){if(n.has(o))throw new Ye({type:o});r.push({...i,type:`tuple${a??``}`,components:yt(t[o]??[],t,new Set([...n,o]))})}else if(ut(o))r.push(i);else throw new Fe({type:o})}}return r}var bt,xt=o((()=>{re(),Le(),We(),Je(),Xe(),Ne(),_t(),bt=/^(?<type>[a-zA-Z$_][a-zA-Z0-9$_]*)(?<array>(?:\\[\\d*?\\])+?)?$/}));function St(e){let t=vt(e),n=[],r=e.length;for(let i=0;i<r;i++){let r=e[i];ge(r)||n.push(nt(r,t))}return n}var Ct=o((()=>{Ne(),xt(),_t()}));function wt(e){let t;if(typeof e==`string`)t=nt(e);else{let n=vt(e),r=e.length;for(let i=0;i<r;i++){let r=e[i];if(!ge(r)){t=nt(r,n);break}}}if(!t)throw new Pe({signature:e});return t}var Tt=o((()=>{Le(),Ne(),xt(),_t()}));function Et(e){let t=[];if(typeof e==`string`){let n=lt(e),r=n.length;for(let e=0;e<r;e++)t.push(ct(n[e],{modifiers:Ae}))}else{let n=vt(e),r=e.length;for(let i=0;i<r;i++){let r=e[i];if(ge(r))continue;let a=lt(r),o=a.length;for(let e=0;e<o;e++)t.push(ct(a[e],{modifiers:Ae,structs:n}))}}if(t.length===0)throw new Re({params:e});return t}var Dt=o((()=>{We(),Ne(),xt(),_t()})),Ot=o((()=>{ue(),ce(),Ct(),Tt(),Dt()}));function E(e,t,n){let r=e[t.name];if(typeof r==`function`)return r;let i=e[n];return typeof i==`function`?i:n=>t(e,n)}function kt(e,{includeName:t=!1}={}){if(e.type!==`function`&&e.type!==`event`&&e.type!==`error`)throw new on(e.type);return`${e.name}(${At(e.inputs,{includeName:t})})`}function At(e,{includeName:t=!1}={}){return e?e.map(e=>jt(e,{includeName:t})).join(t?`, `:`,`):``}function jt(e,{includeName:t}){return e.type.startsWith(`tuple`)?`(${At(e.components,{includeName:t})})${e.type.slice(5)}`:e.type+(t&&e.name?` ${e.name}`:``)}var Mt=o((()=>{sn()}));function Nt(e,{strict:t=!0}={}){return!e||typeof e!=`string`?!1:t?/^0x[0-9a-fA-F]*$/.test(e):e.startsWith(`0x`)}var Pt=o((()=>{}));function Ft(e){return Nt(e,{strict:!1})?Math.ceil((e.length-2)/2):e.length}var It=o((()=>{Pt()})),Lt,Rt=o((()=>{Lt=`2.38.3`}));function zt(e,t){return t?.(e)?e:e&&typeof e==`object`&&`cause`in e&&e.cause!==void 0?zt(e.cause,t):t?null:e}var Bt,D,O=o((()=>{Rt(),Bt={getDocsUrl:({docsBaseUrl:e,docsPath:t=``,docsSlug:n})=>t?`${e??`https://viem.sh`}${t}${n?`#${n}`:``}`:void 0,version:`viem@${Lt}`},D=class e extends Error{constructor(t,n={}){let r=(()=>n.cause instanceof e?n.cause.details:n.cause?.message?n.cause.message:n.details)(),i=(()=>n.cause instanceof e&&n.cause.docsPath||n.docsPath)(),a=Bt.getDocsUrl?.({...n,docsPath:i}),o=[t||`An error occurred.`,``,...n.metaMessages?[...n.metaMessages,``]:[],...a?[`Docs: ${a}`]:[],...r?[`Details: ${r}`]:[],...Bt.version?[`Version: ${Bt.version}`]:[]].join(`\n`);super(o,n.cause?{cause:n.cause}:void 0),Object.defineProperty(this,`details`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`docsPath`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`metaMessages`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`shortMessage`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`version`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`BaseError`}),this.details=r,this.docsPath=i,this.metaMessages=n.metaMessages,this.name=n.name??this.name,this.shortMessage=t,this.version=Lt}walk(e){return zt(this,e)}}})),Vt,Ht,Ut,Wt,Gt,Kt,qt,Jt,Yt,Xt,Zt,Qt,$t,en,tn,nn,rn,an,on,sn=o((()=>{Mt(),It(),O(),Vt=class extends D{constructor({docsPath:e}){super([`A constructor was not found on the ABI.`,`Make sure you are using the correct ABI and that the constructor exists on it.`].join(`\n`),{docsPath:e,name:`AbiConstructorNotFoundError`})}},Ht=class extends D{constructor({docsPath:e}){super([\"Constructor arguments were provided (`args`), but a constructor parameters (`inputs`) were not found on the ABI.\",\"Make sure you are using the correct ABI, and that the `inputs` attribute on the constructor exists.\"].join(`\n`),{docsPath:e,name:`AbiConstructorParamsNotFoundError`})}},Ut=class extends D{constructor({data:e,params:t,size:n}){super([`Data size of ${n} bytes is too small for given parameters.`].join(`\n`),{metaMessages:[`Params: (${At(t,{includeName:!0})})`,`Data:   ${e} (${n} bytes)`],name:`AbiDecodingDataSizeTooSmallError`}),Object.defineProperty(this,`data`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`params`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`size`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.data=e,this.params=t,this.size=n}},Wt=class extends D{constructor(){super(`Cannot decode zero data (\"0x\") with ABI parameters.`,{name:`AbiDecodingZeroDataError`})}},Gt=class extends D{constructor({expectedLength:e,givenLength:t,type:n}){super([`ABI encoding array length mismatch for type ${n}.`,`Expected length: ${e}`,`Given length: ${t}`].join(`\n`),{name:`AbiEncodingArrayLengthMismatchError`})}},Kt=class extends D{constructor({expectedSize:e,value:t}){super(`Size of bytes \"${t}\" (bytes${Ft(t)}) does not match expected size (bytes${e}).`,{name:`AbiEncodingBytesSizeMismatchError`})}},qt=class extends D{constructor({expectedLength:e,givenLength:t}){super([`ABI encoding params/values length mismatch.`,`Expected length (params): ${e}`,`Given length (values): ${t}`].join(`\n`),{name:`AbiEncodingLengthMismatchError`})}},Jt=class extends D{constructor(e,{docsPath:t}){super([`Arguments (\\`args\\`) were provided to \"${e}\", but \"${e}\" on the ABI does not contain any parameters (\\`inputs\\`).`,`Cannot encode error result without knowing what the parameter types are.`,`Make sure you are using the correct ABI and that the inputs exist on it.`].join(`\n`),{docsPath:t,name:`AbiErrorInputsNotFoundError`})}},Yt=class extends D{constructor(e,{docsPath:t}={}){super([`Error ${e?`\"${e}\" `:``}not found on ABI.`,`Make sure you are using the correct ABI and that the error exists on it.`].join(`\n`),{docsPath:t,name:`AbiErrorNotFoundError`})}},Xt=class extends D{constructor(e,{docsPath:t}){super([`Encoded error signature \"${e}\" not found on ABI.`,`Make sure you are using the correct ABI and that the error exists on it.`,`You can look up the decoded signature here: https://openchain.xyz/signatures?query=${e}.`].join(`\n`),{docsPath:t,name:`AbiErrorSignatureNotFoundError`}),Object.defineProperty(this,`signature`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.signature=e}},Zt=class extends D{constructor(e,{docsPath:t}={}){super([`Function ${e?`\"${e}\" `:``}not found on ABI.`,`Make sure you are using the correct ABI and that the function exists on it.`].join(`\n`),{docsPath:t,name:`AbiFunctionNotFoundError`})}},Qt=class extends D{constructor(e,{docsPath:t}){super([`Function \"${e}\" does not contain any \\`outputs\\` on ABI.`,`Cannot decode function result without knowing what the parameter types are.`,`Make sure you are using the correct ABI and that the function exists on it.`].join(`\n`),{docsPath:t,name:`AbiFunctionOutputsNotFoundError`})}},$t=class extends D{constructor(e,{docsPath:t}){super([`Encoded function signature \"${e}\" not found on ABI.`,`Make sure you are using the correct ABI and that the function exists on it.`,`You can look up the signature here: https://openchain.xyz/signatures?query=${e}.`].join(`\n`),{docsPath:t,name:`AbiFunctionSignatureNotFoundError`})}},en=class extends D{constructor(e,t){super(`Found ambiguous types in overloaded ABI items.`,{metaMessages:[`\\`${e.type}\\` in \\`${kt(e.abiItem)}\\`, and`,`\\`${t.type}\\` in \\`${kt(t.abiItem)}\\``,``,`These types encode differently and cannot be distinguished at runtime.`,`Remove one of the ambiguous items in the ABI.`],name:`AbiItemAmbiguityError`})}},tn=class extends D{constructor({expectedSize:e,givenSize:t}){super(`Expected bytes${e}, got bytes${t}.`,{name:`BytesSizeMismatchError`})}},nn=class extends D{constructor(e,{docsPath:t}){super([`Type \"${e}\" is not a valid encoding type.`,`Please provide a valid ABI type.`].join(`\n`),{docsPath:t,name:`InvalidAbiEncodingType`})}},rn=class extends D{constructor(e,{docsPath:t}){super([`Type \"${e}\" is not a valid decoding type.`,`Please provide a valid ABI type.`].join(`\n`),{docsPath:t,name:`InvalidAbiDecodingType`})}},an=class extends D{constructor(e){super([`Value \"${e}\" is not a valid array.`].join(`\n`),{name:`InvalidArrayError`})}},on=class extends D{constructor(e){super([`\"${e}\" is not a valid definition type.`,`Valid types: \"function\", \"event\", \"error\"`].join(`\n`),{name:`InvalidDefinitionTypeError`})}}})),cn,ln,un,dn=o((()=>{O(),cn=class extends D{constructor({offset:e,position:t,size:n}){super(`Slice ${t===`start`?`starting`:`ending`} at offset \"${e}\" is out-of-bounds (size: ${n}).`,{name:`SliceOffsetOutOfBoundsError`})}},ln=class extends D{constructor({size:e,targetSize:t,type:n}){super(`${n.charAt(0).toUpperCase()}${n.slice(1).toLowerCase()} size (${e}) exceeds padding size (${t}).`,{name:`SizeExceedsPaddingSizeError`})}},un=class extends D{constructor({size:e,targetSize:t,type:n}){super(`${n.charAt(0).toUpperCase()}${n.slice(1).toLowerCase()} is expected to be ${t} ${n} long, but is ${e} ${n} long.`,{name:`InvalidBytesLengthError`})}}}));function fn(e,{dir:t,size:n=32}={}){return typeof e==`string`?pn(e,{dir:t,size:n}):mn(e,{dir:t,size:n})}function pn(e,{dir:t,size:n=32}={}){if(n===null)return e;let r=e.replace(`0x`,``);if(r.length>n*2)throw new ln({size:Math.ceil(r.length/2),targetSize:n,type:`hex`});return`0x${r[t===`right`?`padEnd`:`padStart`](n*2,`0`)}`}function mn(e,{dir:t,size:n=32}={}){if(n===null)return e;if(e.length>n)throw new ln({size:e.length,targetSize:n,type:`bytes`});let r=new Uint8Array(n);for(let i=0;i<n;i++){let a=t===`right`;r[a?i:n-i-1]=e[a?i:e.length-i-1]}return r}var hn=o((()=>{dn()})),gn,_n,vn,yn,bn=o((()=>{O(),gn=class extends D{constructor({max:e,min:t,signed:n,size:r,value:i}){super(`Number \"${i}\" is not in safe ${r?`${r*8}-bit ${n?`signed`:`unsigned`} `:``}integer range ${e?`(${t} to ${e})`:`(above ${t})`}`,{name:`IntegerOutOfRangeError`})}},_n=class extends D{constructor(e){super(`Bytes value \"${e}\" is not a valid boolean. The bytes array must contain a single byte of either a 0 or 1 value.`,{name:`InvalidBytesBooleanError`})}},vn=class extends D{constructor(e){super(`Hex value \"${e}\" is not a valid boolean. The hex value must be \"0x0\" (false) or \"0x1\" (true).`,{name:`InvalidHexBooleanError`})}},yn=class extends D{constructor({givenSize:e,maxSize:t}){super(`Size cannot exceed ${t} bytes. Given size: ${e} bytes.`,{name:`SizeOverflowError`})}}}));function xn(e,{dir:t=`left`}={}){let n=typeof e==`string`?e.replace(`0x`,``):e,r=0;for(let e=0;e<n.length-1&&n[t===`left`?e:n.length-e-1].toString()===`0`;e++)r++;return n=t===`left`?n.slice(r):n.slice(0,n.length-r),typeof e==`string`?(n.length===1&&t===`right`&&(n=`${n}0`),`0x${n.length%2==1?`0${n}`:n}`):n}var Sn=o((()=>{}));function Cn(e,{size:t}){if(Ft(e)>t)throw new yn({givenSize:Ft(e),maxSize:t})}function wn(e,t={}){let{signed:n}=t;t.size&&Cn(e,{size:t.size});let r=BigInt(e);if(!n)return r;let i=(e.length-2)/2,a=(1n<<BigInt(i)*8n-1n)-1n;return r<=a?r:r-BigInt(`0x${`f`.padStart(i*2,`f`)}`)-1n}function Tn(e,t={}){let n=e;if(t.size&&(Cn(n,{size:t.size}),n=xn(n)),xn(n)===`0x00`)return!1;if(xn(n)===`0x01`)return!0;throw new vn(n)}function En(e,t={}){return Number(wn(e,t))}var Dn=o((()=>{bn(),It(),Sn()}));function On(e,t={}){return typeof e==`number`||typeof e==`bigint`?k(e,t):typeof e==`string`?jn(e,t):typeof e==`boolean`?kn(e,t):An(e,t)}function kn(e,t={}){let n=`0x${Number(e)}`;return typeof t.size==`number`?(Cn(n,{size:t.size}),fn(n,{size:t.size})):n}function An(e,t={}){let n=``;for(let t=0;t<e.length;t++)n+=Mn[e[t]];let r=`0x${n}`;return typeof t.size==`number`?(Cn(r,{size:t.size}),fn(r,{dir:`right`,size:t.size})):r}function k(e,t={}){let{signed:n,size:r}=t,i=BigInt(e),a;r?a=n?(1n<<BigInt(r)*8n-1n)-1n:2n**(BigInt(r)*8n)-1n:typeof e==`number`&&(a=BigInt(2**53-1));let o=typeof a==`bigint`&&n?-a-1n:0;if(a&&i>a||i<o){let t=typeof e==`bigint`?`n`:``;throw new gn({max:a?`${a}${t}`:void 0,min:`${o}${t}`,signed:n,size:r,value:`${e}${t}`})}let s=`0x${(n&&i<0?(1n<<BigInt(r*8))+BigInt(i):i).toString(16)}`;return r?fn(s,{size:r}):s}function jn(e,t={}){let n=Nn.encode(e);return An(n,t)}var Mn,Nn,A=o((()=>{bn(),hn(),Dn(),Mn=Array.from({length:256},(e,t)=>t.toString(16).padStart(2,`0`)),Nn=new TextEncoder}));function Pn(e,t={}){return typeof e==`number`||typeof e==`bigint`?Rn(e,t):typeof e==`boolean`?Fn(e,t):Nt(e)?Ln(e,t):zn(e,t)}function Fn(e,t={}){let n=new Uint8Array(1);return n[0]=Number(e),typeof t.size==`number`?(Cn(n,{size:t.size}),fn(n,{size:t.size})):n}function In(e){if(e>=Vn.zero&&e<=Vn.nine)return e-Vn.zero;if(e>=Vn.A&&e<=Vn.F)return e-(Vn.A-10);if(e>=Vn.a&&e<=Vn.f)return e-(Vn.a-10)}function Ln(e,t={}){let n=e;t.size&&(Cn(n,{size:t.size}),n=fn(n,{dir:`right`,size:t.size}));let r=n.slice(2);r.length%2&&(r=`0${r}`);let i=r.length/2,a=new Uint8Array(i);for(let e=0,t=0;e<i;e++){let n=In(r.charCodeAt(t++)),i=In(r.charCodeAt(t++));if(n===void 0||i===void 0)throw new D(`Invalid byte sequence (\"${r[t-2]}${r[t-1]}\" in \"${r}\").`);a[e]=n*16+i}return a}function Rn(e,t){let n=k(e,t);return Ln(n)}function zn(e,t={}){let n=Bn.encode(e);return typeof t.size==`number`?(Cn(n,{size:t.size}),fn(n,{dir:`right`,size:t.size})):n}var Bn,Vn,Hn=o((()=>{O(),Pt(),hn(),Dn(),A(),Bn=new TextEncoder,Vn={zero:48,nine:57,A:65,F:70,a:97,f:102}}));function Un(e,t=!1){return t?{h:Number(e&Kn),l:Number(e>>qn&Kn)}:{h:Number(e>>qn&Kn)|0,l:Number(e&Kn)|0}}function Wn(e,t=!1){let n=e.length,r=new Uint32Array(n),i=new Uint32Array(n);for(let a=0;a<n;a++){let{h:n,l:o}=Un(e[a],t);[r[a],i[a]]=[n,o]}return[r,i]}function Gn(e,t,n,r){let i=(t>>>0)+(r>>>0);return{h:e+n+(i/2**32|0)|0,l:i|0}}var Kn,qn,Jn,Yn,Xn,Zn,Qn,$n,er,tr,nr,rr,ir,ar,or,sr,cr,lr,ur=o((()=>{Kn=BigInt(2**32-1),qn=BigInt(32),Jn=(e,t,n)=>e>>>n,Yn=(e,t,n)=>e<<32-n|t>>>n,Xn=(e,t,n)=>e>>>n|t<<32-n,Zn=(e,t,n)=>e<<32-n|t>>>n,Qn=(e,t,n)=>e<<64-n|t>>>n-32,$n=(e,t,n)=>e>>>n-32|t<<64-n,er=(e,t,n)=>e<<n|t>>>32-n,tr=(e,t,n)=>t<<n|e>>>32-n,nr=(e,t,n)=>t<<n-32|e>>>64-n,rr=(e,t,n)=>e<<n-32|t>>>64-n,ir=(e,t,n)=>(e>>>0)+(t>>>0)+(n>>>0),ar=(e,t,n,r)=>t+n+r+(e/2**32|0)|0,or=(e,t,n,r)=>(e>>>0)+(t>>>0)+(n>>>0)+(r>>>0),sr=(e,t,n,r,i)=>t+n+r+i+(e/2**32|0)|0,cr=(e,t,n,r,i)=>(e>>>0)+(t>>>0)+(n>>>0)+(r>>>0)+(i>>>0),lr=(e,t,n,r,i,a)=>t+n+r+i+a+(e/2**32|0)|0})),dr,fr=o((()=>{dr=typeof globalThis==`object`&&`crypto`in globalThis?globalThis.crypto:void 0}));function pr(e){return e instanceof Uint8Array||ArrayBuffer.isView(e)&&e.constructor.name===`Uint8Array`}function mr(e){if(!Number.isSafeInteger(e)||e<0)throw Error(`positive integer expected, got `+e)}function hr(e,...t){if(!pr(e))throw Error(`Uint8Array expected`);if(t.length>0&&!t.includes(e.length))throw Error(`Uint8Array expected of length `+t+`, got length=`+e.length)}function gr(e){if(typeof e!=`function`||typeof e.create!=`function`)throw Error(`Hash should be wrapped by utils.createHasher`);mr(e.outputLen),mr(e.blockLen)}function _r(e,t=!0){if(e.destroyed)throw Error(`Hash instance has been destroyed`);if(t&&e.finished)throw Error(`Hash#digest() has already been called`)}function vr(e,t){hr(e);let n=t.outputLen;if(e.length<n)throw Error(`digestInto() expects output buffer of length at least `+n)}function yr(e){return new Uint32Array(e.buffer,e.byteOffset,Math.floor(e.byteLength/4))}function br(...e){for(let t=0;t<e.length;t++)e[t].fill(0)}function xr(e){return new DataView(e.buffer,e.byteOffset,e.byteLength)}function Sr(e,t){return e<<32-t|e>>>t}function Cr(e){return e<<24&4278190080|e<<8&16711680|e>>>8&65280|e>>>24&255}function wr(e){for(let t=0;t<e.length;t++)e[t]=Cr(e[t]);return e}function Tr(e){if(typeof e!=`string`)throw Error(`string expected`);return new Uint8Array(new TextEncoder().encode(e))}function Er(e){return typeof e==`string`&&(e=Tr(e)),hr(e),e}function Dr(...e){let t=0;for(let n=0;n<e.length;n++){let r=e[n];hr(r),t+=r.length}let n=new Uint8Array(t);for(let t=0,r=0;t<e.length;t++){let i=e[t];n.set(i,r),r+=i.length}return n}function Or(e){let t=t=>e().update(Er(t)).digest(),n=e();return t.outputLen=n.outputLen,t.blockLen=n.blockLen,t.create=()=>e(),t}function kr(e=32){if(dr&&typeof dr.getRandomValues==`function`)return dr.getRandomValues(new Uint8Array(e));if(dr&&typeof dr.randomBytes==`function`)return Uint8Array.from(dr.randomBytes(e));throw Error(`crypto.getRandomValues must be defined`)}var Ar,jr,Mr,Nr=o((()=>{fr(),Ar=(()=>new Uint8Array(new Uint32Array([287454020]).buffer)[0]===68)(),jr=Ar?e=>e:wr,Mr=class{}}));function Pr(e,t=24){let n=new Uint32Array(10);for(let r=24-t;r<24;r++){for(let t=0;t<10;t++)n[t]=e[t]^e[t+10]^e[t+20]^e[t+30]^e[t+40];for(let t=0;t<10;t+=2){let r=(t+8)%10,i=(t+2)%10,a=n[i],o=n[i+1],s=qr(a,o,1)^n[r],c=Jr(a,o,1)^n[r+1];for(let n=0;n<50;n+=10)e[t+n]^=s,e[t+n+1]^=c}let t=e[2],i=e[3];for(let n=0;n<24;n++){let r=Hr[n],a=qr(t,i,r),o=Jr(t,i,r),s=Vr[n];t=e[s],i=e[s+1],e[s]=a,e[s+1]=o}for(let t=0;t<50;t+=10){for(let r=0;r<10;r++)n[r]=e[t+r];for(let r=0;r<10;r++)e[t+r]^=~n[(r+2)%10]&n[(r+4)%10]}e[0]^=Gr[r],e[1]^=Kr[r]}br(n)}var Fr,Ir,Lr,Rr,zr,Br,Vr,Hr,Ur,Wr,Gr,Kr,qr,Jr,Yr,Xr,Zr,Qr=o((()=>{ur(),Nr(),Fr=BigInt(0),Ir=BigInt(1),Lr=BigInt(2),Rr=BigInt(7),zr=BigInt(256),Br=BigInt(113),Vr=[],Hr=[],Ur=[];for(let e=0,t=Ir,n=1,r=0;e<24;e++){[n,r]=[r,(2*n+3*r)%5],Vr.push(2*(5*r+n)),Hr.push((e+1)*(e+2)/2%64);let i=Fr;for(let e=0;e<7;e++)t=(t<<Ir^(t>>Rr)*Br)%zr,t&Lr&&(i^=Ir<<(Ir<<BigInt(e))-Ir);Ur.push(i)}Wr=Wn(Ur,!0),Gr=Wr[0],Kr=Wr[1],qr=(e,t,n)=>n>32?nr(e,t,n):er(e,t,n),Jr=(e,t,n)=>n>32?rr(e,t,n):tr(e,t,n),Yr=class e extends Mr{constructor(e,t,n,r=!1,i=24){if(super(),this.pos=0,this.posOut=0,this.finished=!1,this.destroyed=!1,this.enableXOF=!1,this.blockLen=e,this.suffix=t,this.outputLen=n,this.enableXOF=r,this.rounds=i,mr(n),!(0<e&&e<200))throw Error(`only keccak-f1600 function is supported`);this.state=new Uint8Array(200),this.state32=yr(this.state)}clone(){return this._cloneInto()}keccak(){jr(this.state32),Pr(this.state32,this.rounds),jr(this.state32),this.posOut=0,this.pos=0}update(e){_r(this),e=Er(e),hr(e);let{blockLen:t,state:n}=this,r=e.length;for(let i=0;i<r;){let a=Math.min(t-this.pos,r-i);for(let t=0;t<a;t++)n[this.pos++]^=e[i++];this.pos===t&&this.keccak()}return this}finish(){if(this.finished)return;this.finished=!0;let{state:e,suffix:t,pos:n,blockLen:r}=this;e[n]^=t,t&128&&n===r-1&&this.keccak(),e[r-1]^=128,this.keccak()}writeInto(e){_r(this,!1),hr(e),this.finish();let t=this.state,{blockLen:n}=this;for(let r=0,i=e.length;r<i;){this.posOut>=n&&this.keccak();let a=Math.min(n-this.posOut,i-r);e.set(t.subarray(this.posOut,this.posOut+a),r),this.posOut+=a,r+=a}return e}xofInto(e){if(!this.enableXOF)throw Error(`XOF is not possible for this instance`);return this.writeInto(e)}xof(e){return mr(e),this.xofInto(new Uint8Array(e))}digestInto(e){if(vr(e,this),this.finished)throw Error(`digest() was already called`);return this.writeInto(e),this.destroy(),e}digest(){return this.digestInto(new Uint8Array(this.outputLen))}destroy(){this.destroyed=!0,br(this.state)}_cloneInto(t){let{blockLen:n,suffix:r,outputLen:i,rounds:a,enableXOF:o}=this;return t||=new e(n,r,i,o,a),t.state32.set(this.state32),t.pos=this.pos,t.posOut=this.posOut,t.finished=this.finished,t.rounds=a,t.suffix=r,t.outputLen=i,t.enableXOF=o,t.destroyed=this.destroyed,t}},Xr=(e,t,n)=>Or(()=>new Yr(t,e,n)),Zr=(()=>Xr(1,136,256/8))()}));function $r(e,t){let n=t||`hex`,r=Zr(Nt(e,{strict:!1})?Pn(e):e);return n===`bytes`?r:On(r)}var ei=o((()=>{Qr(),Pt(),Hn(),A()}));function ti(e){return ni(e)}var ni,ri=o((()=>{Hn(),ei(),ni=e=>$r(Pn(e))}));function ii(e){let t=!0,n=``,r=0,i=``,a=!1;for(let o=0;o<e.length;o++){let s=e[o];if([`(`,`)`,`,`].includes(s)&&(t=!0),s===`(`&&r++,s===`)`&&r--,t){if(r===0){if(s===` `&&[`event`,`function`,``].includes(i))i=``;else if(i+=s,s===`)`){a=!0;break}continue}if(s===` `){e[o-1]!==`,`&&n!==`,`&&n!==`,(`&&(n=``,t=!1);continue}i+=s,n+=s}}if(!a)throw new D(`Unable to normalize signature.`);return i}var ai=o((()=>{O()})),oi,si=o((()=>{Ot(),ai(),oi=e=>{let t=(()=>typeof e==`string`?e:le(e))();return ii(t)}}));function ci(e){return ti(oi(e))}var li=o((()=>{ri(),si()})),ui,di=o((()=>{li(),ui=ci})),fi,pi=o((()=>{O(),fi=class extends D{constructor({address:e}){super(`Address \"${e}\" is invalid.`,{metaMessages:[`- Address must be a hex value of 20 bytes (40 hex characters).`,`- Address must match its checksum counterpart.`],name:`InvalidAddressError`})}}})),mi,hi=o((()=>{mi=class extends Map{constructor(e){super(),Object.defineProperty(this,`maxSize`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.maxSize=e}get(e){let t=super.get(e);return super.has(e)&&t!==void 0&&(this.delete(e),super.set(e,t)),t}set(e,t){if(super.set(e,t),this.maxSize&&this.size>this.maxSize){let e=this.keys().next().value;e&&this.delete(e)}return this}}}));function gi(e,t){if(vi.has(`${e}.${t}`))return vi.get(`${e}.${t}`);let n=t?`${t}${e.toLowerCase()}`:e.substring(2).toLowerCase(),r=$r(zn(n),`bytes`),i=(t?n.substring(`${t}0x`.length):n).split(``);for(let e=0;e<40;e+=2)r[e>>1]>>4>=8&&i[e]&&(i[e]=i[e].toUpperCase()),(r[e>>1]&15)>=8&&i[e+1]&&(i[e+1]=i[e+1].toUpperCase());let a=`0x${i.join(``)}`;return vi.set(`${e}.${t}`,a),a}function _i(e,t){if(!bi(e,{strict:!1}))throw new fi({address:e});return gi(e,t)}var vi,yi=o((()=>{pi(),Hn(),ei(),hi(),Ci(),vi=new mi(8192)}));function bi(e,t){let{strict:n=!0}=t??{},r=`${e}.${n}`;if(Si.has(r))return Si.get(r);let i=(()=>xi.test(e)?e.toLowerCase()===e?!0:n?gi(e)===e:!0:!1)();return Si.set(r,i),i}var xi,Si,Ci=o((()=>{hi(),yi(),xi=/^0x[a-fA-F0-9]{40}$/,Si=new mi(8192)}));function wi(e){return typeof e[0]==`string`?Ei(e):Ti(e)}function Ti(e){let t=0;for(let n of e)t+=n.length;let n=new Uint8Array(t),r=0;for(let t of e)n.set(t,r),r+=t.length;return n}function Ei(e){return`0x${e.reduce((e,t)=>e+t.replace(`0x`,``),``)}`}var Di=o((()=>{}));function Oi(e,t,n,{strict:r}={}){return Nt(e,{strict:!1})?Mi(e,t,n,{strict:r}):ji(e,t,n,{strict:r})}function ki(e,t){if(typeof t==`number`&&t>0&&t>Ft(e)-1)throw new cn({offset:t,position:`start`,size:Ft(e)})}function Ai(e,t,n){if(typeof t==`number`&&typeof n==`number`&&Ft(e)!==n-t)throw new cn({offset:n,position:`end`,size:Ft(e)})}function ji(e,t,n,{strict:r}={}){ki(e,t);let i=e.slice(t,n);return r&&Ai(i,t,n),i}function Mi(e,t,n,{strict:r}={}){ki(e,t);let i=`0x${e.replace(`0x`,``).slice((t??0)*2,(n??e.length)*2)}`;return r&&Ai(i,t,n),i}var Ni=o((()=>{dn(),Pt(),It()})),Pi,Fi,Ii=o((()=>{Pi=/^bytes([1-9]|1[0-9]|2[0-9]|3[0-2])?$/,Fi=/^(u?int)(8|16|24|32|40|48|56|64|72|80|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256)?$/}));function Li(e,t){if(e.length!==t.length)throw new qt({expectedLength:e.length,givenLength:t.length});let n=Ri({params:e,values:t}),r=Bi(n);return r.length===0?`0x`:r}function Ri({params:e,values:t}){let n=[];for(let r=0;r<e.length;r++)n.push(zi({param:e[r],value:t[r]}));return n}function zi({param:e,value:t}){let n=Ji(e.type);if(n){let[r,i]=n;return Hi(t,{length:r,param:{...e,type:i}})}if(e.type===`tuple`)return qi(t,{param:e});if(e.type===`address`)return Vi(t);if(e.type===`bool`)return Wi(t);if(e.type.startsWith(`uint`)||e.type.startsWith(`int`)){let n=e.type.startsWith(`int`),[,,r=`256`]=Fi.exec(e.type)??[];return Gi(t,{signed:n,size:Number(r)})}if(e.type.startsWith(`bytes`))return Ui(t,{param:e});if(e.type===`string`)return Ki(t);throw new nn(e.type,{docsPath:`/docs/contract/encodeAbiParameters`})}function Bi(e){let t=0;for(let n=0;n<e.length;n++){let{dynamic:r,encoded:i}=e[n];r?t+=32:t+=Ft(i)}let n=[],r=[],i=0;for(let a=0;a<e.length;a++){let{dynamic:o,encoded:s}=e[a];o?(n.push(k(t+i,{size:32})),r.push(s),i+=Ft(s)):n.push(s)}return wi([...n,...r])}function Vi(e){if(!bi(e))throw new fi({address:e});return{dynamic:!1,encoded:pn(e.toLowerCase())}}function Hi(e,{length:t,param:n}){let r=t===null;if(!Array.isArray(e))throw new an(e);if(!r&&e.length!==t)throw new Gt({expectedLength:t,givenLength:e.length,type:`${n.type}[${t}]`});let i=!1,a=[];for(let t=0;t<e.length;t++){let r=zi({param:n,value:e[t]});r.dynamic&&(i=!0),a.push(r)}if(r||i){let e=Bi(a);if(r){let t=k(a.length,{size:32});return{dynamic:!0,encoded:a.length>0?wi([t,e]):t}}if(i)return{dynamic:!0,encoded:e}}return{dynamic:!1,encoded:wi(a.map(({encoded:e})=>e))}}function Ui(e,{param:t}){let[,n]=t.type.split(`bytes`),r=Ft(e);if(!n){let t=e;return r%32!=0&&(t=pn(t,{dir:`right`,size:Math.ceil((e.length-2)/2/32)*32})),{dynamic:!0,encoded:wi([pn(k(r,{size:32})),t])}}if(r!==Number.parseInt(n,10))throw new Kt({expectedSize:Number.parseInt(n,10),value:e});return{dynamic:!1,encoded:pn(e,{dir:`right`})}}function Wi(e){if(typeof e!=`boolean`)throw new D(`Invalid boolean value: \"${e}\" (type: ${typeof e}). Expected: \\`true\\` or \\`false\\`.`);return{dynamic:!1,encoded:pn(kn(e))}}function Gi(e,{signed:t,size:n=256}){if(typeof n==`number`){let r=2n**(BigInt(n)-(t?1n:0n))-1n,i=t?-r-1n:0n;if(e>r||e<i)throw new gn({max:r.toString(),min:i.toString(),signed:t,size:n/8,value:e.toString()})}return{dynamic:!1,encoded:k(e,{size:32,signed:t})}}function Ki(e){let t=jn(e),n=Math.ceil(Ft(t)/32),r=[];for(let e=0;e<n;e++)r.push(pn(Oi(t,e*32,(e+1)*32),{dir:`right`}));return{dynamic:!0,encoded:wi([pn(k(Ft(t),{size:32})),...r])}}function qi(e,{param:t}){let n=!1,r=[];for(let i=0;i<t.components.length;i++){let a=t.components[i],o=Array.isArray(e)?i:a.name,s=zi({param:a,value:e[o]});r.push(s),s.dynamic&&(n=!0)}return{dynamic:n,encoded:n?Bi(r):wi(r.map(({encoded:e})=>e))}}function Ji(e){let t=e.match(/^(.*)\\[(\\d+)?\\]$/);return t?[t[2]?Number(t[2]):null,t[1]]:void 0}var Yi=o((()=>{sn(),pi(),O(),bn(),Ci(),Di(),hn(),It(),Ni(),A(),Ii()})),Xi,Zi=o((()=>{Ni(),li(),Xi=e=>Oi(ci(e),0,4)}));function Qi(e){let{abi:t,args:n=[],name:r}=e,i=Nt(r,{strict:!1}),a=t.filter(e=>i?e.type===`function`?Xi(e)===r:e.type===`event`?ui(e)===r:!1:`name`in e&&e.name===r);if(a.length===0)return;if(a.length===1)return a[0];let o;for(let e of a)if(`inputs`in e){if(!n||n.length===0){if(!e.inputs||e.inputs.length===0)return e;continue}if(e.inputs&&e.inputs.length!==0&&e.inputs.length===n.length&&n.every((t,n)=>{let r=`inputs`in e&&e.inputs[n];return r?$i(t,r):!1})){if(o&&`inputs`in o&&o.inputs){let t=ea(e.inputs,o.inputs,n);if(t)throw new en({abiItem:e,type:t[0]},{abiItem:o,type:t[1]})}o=e}}return o||a[0]}function $i(e,t){let n=typeof e,r=t.type;switch(r){case`address`:return bi(e,{strict:!1});case`bool`:return n===`boolean`;case`function`:return n===`string`;case`string`:return n===`string`;default:return r===`tuple`&&`components`in t?Object.values(t.components).every((t,n)=>$i(Object.values(e)[n],t)):/^u?int(8|16|24|32|40|48|56|64|72|80|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256)?$/.test(r)?n===`number`||n===`bigint`:/^bytes([1-9]|1[0-9]|2[0-9]|3[0-2])?$/.test(r)?n===`string`||e instanceof Uint8Array:/[a-z]+[1-9]{0,3}(\\[[0-9]{0,}\\])+$/.test(r)?Array.isArray(e)&&e.every(e=>$i(e,{...t,type:r.replace(/(\\[[0-9]{0,}\\])$/,``)})):!1}}function ea(e,t,n){for(let r in e){let i=e[r],a=t[r];if(i.type===`tuple`&&a.type===`tuple`&&`components`in i&&`components`in a)return ea(i.components,a.components,n[r]);let o=[i.type,a.type];if((()=>o.includes(`address`)&&o.includes(`bytes20`)?!0:o.includes(`address`)&&o.includes(`string`)||o.includes(`address`)&&o.includes(`bytes`)?bi(n[r],{strict:!1}):!1)())return o}}var ta=o((()=>{sn(),Pt(),Ci(),di(),Zi()}));function na(e){return typeof e==`string`?{address:e,type:`json-rpc`}:e}var ra=o((()=>{}));function ia(e){let{abi:t,args:n,functionName:r}=e,i=t[0];if(r){let e=Qi({abi:t,args:n,name:r});if(!e)throw new Zt(r,{docsPath:aa});i=e}if(i.type!==`function`)throw new Zt(void 0,{docsPath:aa});return{abi:[i],functionName:Xi(kt(i))}}var aa,oa=o((()=>{sn(),Zi(),Mt(),ta(),aa=`/docs/contract/encodeFunctionData`}));function sa(e){let{args:t}=e,{abi:n,functionName:r}=(()=>e.abi.length===1&&e.functionName?.startsWith(`0x`)?e:ia(e))(),i=n[0],a=r,o=`inputs`in i&&i.inputs?Li(i.inputs,t??[]):void 0;return Ei([a,o??`0x`])}var ca=o((()=>{Di(),Yi(),oa()})),la,ua,da,fa=o((()=>{la={1:\"An `assert` condition failed.\",17:`Arithmetic operation resulted in underflow or overflow.`,18:\"Division or modulo by zero (e.g. `5 / 0` or `23 % 0`).\",33:`Attempted to convert to an invalid type.`,34:`Attempted to access a storage byte array that is incorrectly encoded.`,49:\"Performed `.pop()` on an empty array\",50:`Array index is out of bounds.`,65:`Allocated too much memory or created an array which is too large.`,81:`Attempted to call a zero-initialized variable of internal function type.`},ua={inputs:[{name:`message`,type:`string`}],name:`Error`,type:`error`},da={inputs:[{name:`reason`,type:`uint256`}],name:`Panic`,type:`error`}})),pa,ma,ha,ga=o((()=>{O(),pa=class extends D{constructor({offset:e}){super(`Offset \\`${e}\\` cannot be negative.`,{name:`NegativeOffsetError`})}},ma=class extends D{constructor({length:e,position:t}){super(`Position \\`${t}\\` is out of bounds (\\`0 < position < ${e}\\`).`,{name:`PositionOutOfBoundsError`})}},ha=class extends D{constructor({count:e,limit:t}){super(`Recursive read limit of \\`${t}\\` exceeded (recursive read count: \\`${e}\\`).`,{name:`RecursiveReadLimitExceededError`})}}}));function _a(e,{recursiveReadLimit:t=8192}={}){let n=Object.create(va);return n.bytes=e,n.dataView=new DataView(e.buffer,e.byteOffset,e.byteLength),n.positionReadCount=new Map,n.recursiveReadLimit=t,n}var va,ya=o((()=>{ga(),va={bytes:new Uint8Array,dataView:new DataView(new ArrayBuffer(0)),position:0,positionReadCount:new Map,recursiveReadCount:0,recursiveReadLimit:1/0,assertReadLimit(){if(this.recursiveReadCount>=this.recursiveReadLimit)throw new ha({count:this.recursiveReadCount+1,limit:this.recursiveReadLimit})},assertPosition(e){if(e<0||e>this.bytes.length-1)throw new ma({length:this.bytes.length,position:e})},decrementPosition(e){if(e<0)throw new pa({offset:e});let t=this.position-e;this.assertPosition(t),this.position=t},getReadCount(e){return this.positionReadCount.get(e||this.position)||0},incrementPosition(e){if(e<0)throw new pa({offset:e});let t=this.position+e;this.assertPosition(t),this.position=t},inspectByte(e){let t=e??this.position;return this.assertPosition(t),this.bytes[t]},inspectBytes(e,t){let n=t??this.position;return this.assertPosition(n+e-1),this.bytes.subarray(n,n+e)},inspectUint8(e){let t=e??this.position;return this.assertPosition(t),this.bytes[t]},inspectUint16(e){let t=e??this.position;return this.assertPosition(t+1),this.dataView.getUint16(t)},inspectUint24(e){let t=e??this.position;return this.assertPosition(t+2),(this.dataView.getUint16(t)<<8)+this.dataView.getUint8(t+2)},inspectUint32(e){let t=e??this.position;return this.assertPosition(t+3),this.dataView.getUint32(t)},pushByte(e){this.assertPosition(this.position),this.bytes[this.position]=e,this.position++},pushBytes(e){this.assertPosition(this.position+e.length-1),this.bytes.set(e,this.position),this.position+=e.length},pushUint8(e){this.assertPosition(this.position),this.bytes[this.position]=e,this.position++},pushUint16(e){this.assertPosition(this.position+1),this.dataView.setUint16(this.position,e),this.position+=2},pushUint24(e){this.assertPosition(this.position+2),this.dataView.setUint16(this.position,e>>8),this.dataView.setUint8(this.position+2,e&255),this.position+=3},pushUint32(e){this.assertPosition(this.position+3),this.dataView.setUint32(this.position,e),this.position+=4},readByte(){this.assertReadLimit(),this._touch();let e=this.inspectByte();return this.position++,e},readBytes(e,t){this.assertReadLimit(),this._touch();let n=this.inspectBytes(e);return this.position+=t??e,n},readUint8(){this.assertReadLimit(),this._touch();let e=this.inspectUint8();return this.position+=1,e},readUint16(){this.assertReadLimit(),this._touch();let e=this.inspectUint16();return this.position+=2,e},readUint24(){this.assertReadLimit(),this._touch();let e=this.inspectUint24();return this.position+=3,e},readUint32(){this.assertReadLimit(),this._touch();let e=this.inspectUint32();return this.position+=4,e},get remaining(){return this.bytes.length-this.position},setPosition(e){let t=this.position;return this.assertPosition(e),this.position=e,()=>this.position=t},_touch(){if(this.recursiveReadLimit===1/0)return;let e=this.getReadCount();this.positionReadCount.set(this.position,e+1),e>0&&this.recursiveReadCount++}}}));function ba(e,t={}){t.size!==void 0&&Cn(e,{size:t.size});let n=An(e,t);return wn(n,t)}function xa(e,t={}){let n=e;if(t.size!==void 0&&(Cn(n,{size:t.size}),n=xn(n)),n.length>1||n[0]>1)throw new _n(n);return!!n[0]}function Sa(e,t={}){t.size!==void 0&&Cn(e,{size:t.size});let n=An(e,t);return En(n,t)}function Ca(e,t={}){let n=e;return t.size!==void 0&&(Cn(n,{size:t.size}),n=xn(n,{dir:`right`})),new TextDecoder().decode(n)}var wa=o((()=>{bn(),Sn(),Dn(),A()}));function Ta(e,t){let n=typeof t==`string`?Ln(t):t,r=_a(n);if(Ft(n)===0&&e.length>0)throw new Wt;if(Ft(t)&&Ft(t)<32)throw new Ut({data:typeof t==`string`?t:An(t),params:e,size:Ft(t)});let i=0,a=[];for(let t=0;t<e.length;++t){let n=e[t];r.setPosition(i);let[o,s]=Ea(r,n,{staticPosition:0});i+=s,a.push(o)}return a}function Ea(e,t,{staticPosition:n}){let r=Ji(t.type);if(r){let[i,a]=r;return Oa(e,{...t,type:a},{length:i,staticPosition:n})}if(t.type===`tuple`)return Ma(e,t,{staticPosition:n});if(t.type===`address`)return Da(e);if(t.type===`bool`)return ka(e);if(t.type.startsWith(`bytes`))return Aa(e,t,{staticPosition:n});if(t.type.startsWith(`uint`)||t.type.startsWith(`int`))return ja(e,t);if(t.type===`string`)return Na(e,{staticPosition:n});throw new rn(t.type,{docsPath:`/docs/contract/decodeAbiParameters`})}function Da(e){let t=e.readBytes(32);return[gi(An(ji(t,-20))),32]}function Oa(e,t,{length:n,staticPosition:r}){if(!n){let n=Sa(e.readBytes(Ia)),i=r+n,a=i+Fa;e.setPosition(i);let o=Sa(e.readBytes(Fa)),s=Pa(t),c=0,l=[];for(let n=0;n<o;++n){e.setPosition(a+(s?n*32:c));let[r,i]=Ea(e,t,{staticPosition:a});c+=i,l.push(r)}return e.setPosition(r+32),[l,32]}if(Pa(t)){let i=Sa(e.readBytes(Ia)),a=r+i,o=[];for(let r=0;r<n;++r){e.setPosition(a+r*32);let[n]=Ea(e,t,{staticPosition:a});o.push(n)}return e.setPosition(r+32),[o,32]}let i=0,a=[];for(let o=0;o<n;++o){let[n,o]=Ea(e,t,{staticPosition:r+i});i+=o,a.push(n)}return[a,i]}function ka(e){return[xa(e.readBytes(32),{size:32}),32]}function Aa(e,t,{staticPosition:n}){let[r,i]=t.type.split(`bytes`);if(!i){let t=Sa(e.readBytes(32));e.setPosition(n+t);let r=Sa(e.readBytes(32));if(r===0)return e.setPosition(n+32),[`0x`,32];let i=e.readBytes(r);return e.setPosition(n+32),[An(i),32]}return[An(e.readBytes(Number.parseInt(i,10),32)),32]}function ja(e,t){let n=t.type.startsWith(`int`),r=Number.parseInt(t.type.split(`int`)[1]||`256`,10),i=e.readBytes(32);return[r>48?ba(i,{signed:n}):Sa(i,{signed:n}),32]}function Ma(e,t,{staticPosition:n}){let r=t.components.length===0||t.components.some(({name:e})=>!e),i=r?[]:{},a=0;if(Pa(t)){let o=Sa(e.readBytes(Ia)),s=n+o;for(let n=0;n<t.components.length;++n){let o=t.components[n];e.setPosition(s+a);let[c,l]=Ea(e,o,{staticPosition:s});a+=l,i[r?n:o?.name]=c}return e.setPosition(n+32),[i,32]}for(let o=0;o<t.components.length;++o){let s=t.components[o],[c,l]=Ea(e,s,{staticPosition:n});i[r?o:s?.name]=c,a+=l}return[i,a]}function Na(e,{staticPosition:t}){let n=Sa(e.readBytes(32)),r=t+n;e.setPosition(r);let i=Sa(e.readBytes(32));if(i===0)return e.setPosition(t+32),[``,32];let a=e.readBytes(i,32),o=Ca(xn(a));return e.setPosition(t+32),[o,32]}function Pa(e){let{type:t}=e;if(t===`string`||t===`bytes`||t.endsWith(`[]`))return!0;if(t===`tuple`)return e.components?.some(Pa);let n=Ji(e.type);return!!(n&&Pa({...e,type:n[1]}))}var Fa,Ia,La=o((()=>{sn(),yi(),ya(),It(),Ni(),Sn(),wa(),Hn(),A(),Yi(),Fa=32,Ia=32}));function Ra(e){let{abi:t,data:n}=e,r=Oi(n,0,4);if(r===`0x`)throw new Wt;let i=[...t||[],ua,da].find(e=>e.type===`error`&&r===Xi(kt(e)));if(!i)throw new Xt(r,{docsPath:`/docs/contract/decodeErrorResult`});return{abiItem:i,args:`inputs`in i&&i.inputs&&i.inputs.length>0?Ta(i.inputs,Oi(n,4)):void 0,errorName:i.name}}var za=o((()=>{fa(),sn(),Ni(),Zi(),La(),Mt()})),Ba,Va=o((()=>{Ba=(e,t,n)=>JSON.stringify(e,(e,n)=>{let r=typeof n==`bigint`?n.toString():n;return typeof t==`function`?t(e,r):r},n)}));function Ha({abiItem:e,args:t,includeFunctionName:n=!0,includeName:r=!1}){if(`name`in e&&`inputs`in e&&e.inputs)return`${n?e.name:``}(${e.inputs.map((e,n)=>`${r&&e.name?`${e.name}: `:``}${typeof t[n]==`object`?Ba(t[n]):t[n]}`).join(`, `)})`}var Ua=o((()=>{Va()})),Wa,Ga,Ka=o((()=>{Wa={gwei:9,wei:18},Ga={ether:-9,wei:9}}));function qa(e,t){let n=e.toString(),r=n.startsWith(`-`);r&&(n=n.slice(1)),n=n.padStart(t,`0`);let[i,a]=[n.slice(0,n.length-t),n.slice(n.length-t)];return a=a.replace(/(0+)$/,``),`${r?`-`:``}${i||`0`}${a?`.${a}`:``}`}var Ja=o((()=>{}));function Ya(e,t=`wei`){return qa(e,Wa[t])}var Xa=o((()=>{Ka(),Ja()}));function Za(e,t=`wei`){return qa(e,Ga[t])}var Qa=o((()=>{Ka(),Ja()}));function $a(e){return e.reduce((e,{slot:t,value:n})=>`${e}        ${t}: ${n}\\n`,``)}function eo(e){return e.reduce((e,{address:t,...n})=>{let r=`${e}    ${t}:\\n`;return n.nonce&&(r+=`      nonce: ${n.nonce}\\n`),n.balance&&(r+=`      balance: ${n.balance}\\n`),n.code&&(r+=`      code: ${n.code}\\n`),n.state&&(r+=`      state:\n`,r+=$a(n.state)),n.stateDiff&&(r+=`      stateDiff:\n`,r+=$a(n.stateDiff)),r},`  State Override:\n`).slice(0,-1)}var to,no,ro=o((()=>{O(),to=class extends D{constructor({address:e}){super(`State for account \"${e}\" is set multiple times.`,{name:`AccountStateConflictError`})}},no=class extends D{constructor(){super(`state and stateDiff are set on the same account.`,{name:`StateAssignmentConflictError`})}}}));function io(e){let t=Object.entries(e).map(([e,t])=>t===void 0||t===!1?null:[e,t]).filter(Boolean),n=t.reduce((e,[t])=>Math.max(e,t.length),0);return t.map(([e,t])=>`  ${`${e}:`.padEnd(n+1)}  ${t}`).join(`\n`)}var ao,oo,so,co,lo,uo,fo,po,mo,ho=o((()=>{Xa(),Qa(),O(),ao=class extends D{constructor(){super([\"Cannot specify both a `gasPrice` and a `maxFeePerGas`/`maxPriorityFeePerGas`.\",\"Use `maxFeePerGas`/`maxPriorityFeePerGas` for EIP-1559 compatible networks, and `gasPrice` for others.\"].join(`\n`),{name:`FeeConflictError`})}},oo=class extends D{constructor({v:e}){super(`Invalid \\`v\\` value \"${e}\". Expected 27 or 28.`,{name:`InvalidLegacyVError`})}},so=class extends D{constructor({transaction:e}){super(`Cannot infer a transaction type from provided transaction.`,{metaMessages:[`Provided Transaction:`,`{`,io(e),`}`,``,`To infer the type, either provide:`,\"- a `type` to the Transaction, or\",\"- an EIP-1559 Transaction with `maxFeePerGas`, or\",\"- an EIP-2930 Transaction with `gasPrice` & `accessList`, or\",\"- an EIP-4844 Transaction with `blobs`, `blobVersionedHashes`, `sidecars`, or\",\"- an EIP-7702 Transaction with `authorizationList`, or\",\"- a Legacy Transaction with `gasPrice`\"],name:`InvalidSerializableTransactionError`})}},co=class extends D{constructor({storageKey:e}){super(`Size for storage key \"${e}\" is invalid. Expected 32 bytes. Got ${Math.floor((e.length-2)/2)} bytes.`,{name:`InvalidStorageKeySizeError`})}},lo=class extends D{constructor(e,{account:t,docsPath:n,chain:r,data:i,gas:a,gasPrice:o,maxFeePerGas:s,maxPriorityFeePerGas:c,nonce:l,to:u,value:d}){let f=io({chain:r&&`${r?.name} (id: ${r?.id})`,from:t?.address,to:u,value:d!==void 0&&`${Ya(d)} ${r?.nativeCurrency?.symbol||`ETH`}`,data:i,gas:a,gasPrice:o!==void 0&&`${Za(o)} gwei`,maxFeePerGas:s!==void 0&&`${Za(s)} gwei`,maxPriorityFeePerGas:c!==void 0&&`${Za(c)} gwei`,nonce:l});super(e.shortMessage,{cause:e,docsPath:n,metaMessages:[...e.metaMessages?[...e.metaMessages,` `]:[],`Request Arguments:`,f].filter(Boolean),name:`TransactionExecutionError`}),Object.defineProperty(this,`cause`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.cause=e}},uo=class extends D{constructor({blockHash:e,blockNumber:t,blockTag:n,hash:r,index:i}){let a=`Transaction`;n&&i!==void 0&&(a=`Transaction at block time \"${n}\" at index \"${i}\"`),e&&i!==void 0&&(a=`Transaction at block hash \"${e}\" at index \"${i}\"`),t&&i!==void 0&&(a=`Transaction at block number \"${t}\" at index \"${i}\"`),r&&(a=`Transaction with hash \"${r}\"`),super(`${a} could not be found.`,{name:`TransactionNotFoundError`})}},fo=class extends D{constructor({hash:e}){super(`Transaction receipt with hash \"${e}\" could not be found. The Transaction may not be processed on a block yet.`,{name:`TransactionReceiptNotFoundError`})}},po=class extends D{constructor({receipt:e}){super(`Transaction with hash \"${e.transactionHash}\" reverted.`,{metaMessages:[`The receipt marked the transaction as \"reverted\". This could mean that the function on the contract you are trying to call threw an error.`,` `,`You can attempt to extract the revert reason by:`,\"- calling the `simulateContract` or `simulateCalls` Action with the `abi` and `functionName` of the contract\",\"- using the `call` Action with raw `data`\"],name:`TransactionReceiptRevertedError`}),Object.defineProperty(this,`receipt`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.receipt=e}},mo=class extends D{constructor({hash:e}){super(`Timed out while waiting for transaction with hash \"${e}\" to be confirmed.`,{name:`WaitForTransactionReceiptTimeoutError`})}}})),go,_o,vo=o((()=>{go=e=>e,_o=e=>e})),yo,bo,xo,So,Co,wo,To=o((()=>{ra(),fa(),za(),Mt(),Ua(),ta(),Xa(),Qa(),sn(),O(),ro(),ho(),vo(),yo=class extends D{constructor(e,{account:t,docsPath:n,chain:r,data:i,gas:a,gasPrice:o,maxFeePerGas:s,maxPriorityFeePerGas:c,nonce:l,to:u,value:d,stateOverride:f}){let p=t?na(t):void 0,m=io({from:p?.address,to:u,value:d!==void 0&&`${Ya(d)} ${r?.nativeCurrency?.symbol||`ETH`}`,data:i,gas:a,gasPrice:o!==void 0&&`${Za(o)} gwei`,maxFeePerGas:s!==void 0&&`${Za(s)} gwei`,maxPriorityFeePerGas:c!==void 0&&`${Za(c)} gwei`,nonce:l});f&&(m+=`\\n${eo(f)}`),super(e.shortMessage,{cause:e,docsPath:n,metaMessages:[...e.metaMessages?[...e.metaMessages,` `]:[],`Raw Call Arguments:`,m].filter(Boolean),name:`CallExecutionError`}),Object.defineProperty(this,`cause`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.cause=e}},bo=class extends D{constructor(e,{abi:t,args:n,contractAddress:r,docsPath:i,functionName:a,sender:o}){let s=Qi({abi:t,args:n,name:a}),c=s?Ha({abiItem:s,args:n,includeFunctionName:!1,includeName:!1}):void 0,l=s?kt(s,{includeName:!0}):void 0,u=io({address:r&&go(r),function:l,args:c&&c!==`()`&&`${[...Array(a?.length??0).keys()].map(()=>` `).join(``)}${c}`,sender:o});super(e.shortMessage||`An unknown error occurred while executing the contract function \"${a}\".`,{cause:e,docsPath:i,metaMessages:[...e.metaMessages?[...e.metaMessages,` `]:[],u&&`Contract Call:`,u].filter(Boolean),name:`ContractFunctionExecutionError`}),Object.defineProperty(this,`abi`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`args`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`cause`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`contractAddress`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`formattedArgs`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`functionName`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`sender`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.abi=t,this.args=n,this.cause=e,this.contractAddress=r,this.functionName=a,this.sender=o}},xo=class extends D{constructor({abi:e,data:t,functionName:n,message:r}){let i,a,o,s;if(t&&t!==`0x`)try{a=Ra({abi:e,data:t});let{abiItem:n,errorName:r,args:i}=a;if(r===`Error`)s=i[0];else if(r===`Panic`){let[e]=i;s=la[e]}else{let e=n?kt(n,{includeName:!0}):void 0,t=n&&i?Ha({abiItem:n,args:i,includeFunctionName:!1,includeName:!1}):void 0;o=[e?`Error: ${e}`:``,t&&t!==`()`?`       ${[...Array(r?.length??0).keys()].map(()=>` `).join(``)}${t}`:``]}}catch(e){i=e}else r&&(s=r);let c;i instanceof Xt&&(c=i.signature,o=[`Unable to decode signature \"${c}\" as it was not found on the provided ABI.`,`Make sure you are using the correct ABI and that the error exists on it.`,`You can look up the decoded signature here: https://openchain.xyz/signatures?query=${c}.`]),super(s&&s!==`execution reverted`||c?[`The contract function \"${n}\" reverted with the following ${c?`signature`:`reason`}:`,s||c].join(`\n`):`The contract function \"${n}\" reverted.`,{cause:i,metaMessages:o,name:`ContractFunctionRevertedError`}),Object.defineProperty(this,`data`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`raw`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`reason`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`signature`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.data=a,this.raw=t,this.reason=s,this.signature=c}},So=class extends D{constructor({functionName:e}){super(`The contract function \"${e}\" returned no data (\"0x\").`,{metaMessages:[`This could be due to any of the following:`,`  - The contract does not have the function \"${e}\",`,`  - The parameters passed to the contract function may be invalid, or`,`  - The address is not a contract.`],name:`ContractFunctionZeroDataError`})}},Co=class extends D{constructor({factory:e}){super(`Deployment for counterfactual contract call failed${e?` for factory \"${e}\".`:``}`,{metaMessages:[`Please ensure:`,\"- The `factory` is a valid contract deployment factory (ie. Create2 Factory, ERC-4337 Factory, etc).\",\"- The `factoryData` is a valid encoded function call for contract deployment function on the factory.\"],name:`CounterfactualDeploymentFailedError`})}},wo=class extends D{constructor({data:e,message:t}){super(t||``,{name:`RawContractError`}),Object.defineProperty(this,`code`,{enumerable:!0,configurable:!0,writable:!0,value:3}),Object.defineProperty(this,`data`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.data=e}}})),Eo,Do,Oo,ko=o((()=>{Va(),O(),vo(),Eo=class extends D{constructor({body:e,cause:t,details:n,headers:r,status:i,url:a}){super(`HTTP request failed.`,{cause:t,details:n,metaMessages:[i&&`Status: ${i}`,`URL: ${_o(a)}`,e&&`Request body: ${Ba(e)}`].filter(Boolean),name:`HttpRequestError`}),Object.defineProperty(this,`body`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`headers`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`status`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`url`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.body=e,this.headers=r,this.status=i,this.url=a}},Do=class extends D{constructor({body:e,error:t,url:n}){super(`RPC Request failed.`,{cause:t,details:t.message,metaMessages:[`URL: ${_o(n)}`,`Request body: ${Ba(e)}`],name:`RpcRequestError`}),Object.defineProperty(this,`code`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`data`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.code=t.code,this.data=t.data}},Oo=class extends D{constructor({body:e,url:t}){super(`The request took too long to respond.`,{details:`The request timed out.`,metaMessages:[`URL: ${_o(t)}`,`Request body: ${Ba(e)}`],name:`TimeoutError`})}}})),Ao,jo,Mo,No,j,Po,Fo,Io,Lo,Ro,zo,Bo,Vo,Ho,Uo,Wo,Go,Ko,qo,Jo,Yo,Xo,Zo,Qo,$o,es,ts,ns,rs,os=o((()=>{O(),ko(),Ao=-1,jo=class extends D{constructor(e,{code:t,docsPath:n,metaMessages:r,name:i,shortMessage:a}){super(a,{cause:e,docsPath:n,metaMessages:r||e?.metaMessages,name:i||`RpcError`}),Object.defineProperty(this,`code`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.name=i||e.name,this.code=e instanceof Do?e.code:t??Ao}},Mo=class extends jo{constructor(e,t){super(e,t),Object.defineProperty(this,`data`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.data=t.data}},No=class e extends jo{constructor(t){super(t,{code:e.code,name:`ParseRpcError`,shortMessage:`Invalid JSON was received by the server. An error occurred on the server while parsing the JSON text.`})}},Object.defineProperty(No,`code`,{enumerable:!0,configurable:!0,writable:!0,value:-32700}),j=class e extends jo{constructor(t){super(t,{code:e.code,name:`InvalidRequestRpcError`,shortMessage:`JSON is not a valid request object.`})}},Object.defineProperty(j,`code`,{enumerable:!0,configurable:!0,writable:!0,value:-32600}),Po=class e extends jo{constructor(t,{method:n}={}){super(t,{code:e.code,name:`MethodNotFoundRpcError`,shortMessage:`The method${n?` \"${n}\"`:``} does not exist / is not available.`})}},Object.defineProperty(Po,`code`,{enumerable:!0,configurable:!0,writable:!0,value:-32601}),Fo=class e extends jo{constructor(t){super(t,{code:e.code,name:`InvalidParamsRpcError`,shortMessage:[`Invalid parameters were provided to the RPC method.`,`Double check you have provided the correct parameters.`].join(`\n`)})}},Object.defineProperty(Fo,`code`,{enumerable:!0,configurable:!0,writable:!0,value:-32602}),Io=class e extends jo{constructor(t){super(t,{code:e.code,name:`InternalRpcError`,shortMessage:`An internal error was received.`})}},Object.defineProperty(Io,`code`,{enumerable:!0,configurable:!0,writable:!0,value:-32603}),Lo=class e extends jo{constructor(t){super(t,{code:e.code,name:`InvalidInputRpcError`,shortMessage:[`Missing or invalid parameters.`,`Double check you have provided the correct parameters.`].join(`\n`)})}},Object.defineProperty(Lo,`code`,{enumerable:!0,configurable:!0,writable:!0,value:-32e3}),Ro=class e extends jo{constructor(t){super(t,{code:e.code,name:`ResourceNotFoundRpcError`,shortMessage:`Requested resource not found.`}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`ResourceNotFoundRpcError`})}},Object.defineProperty(Ro,`code`,{enumerable:!0,configurable:!0,writable:!0,value:-32001}),zo=class e extends jo{constructor(t){super(t,{code:e.code,name:`ResourceUnavailableRpcError`,shortMessage:`Requested resource not available.`})}},Object.defineProperty(zo,`code`,{enumerable:!0,configurable:!0,writable:!0,value:-32002}),Bo=class e extends jo{constructor(t){super(t,{code:e.code,name:`TransactionRejectedRpcError`,shortMessage:`Transaction creation failed.`})}},Object.defineProperty(Bo,`code`,{enumerable:!0,configurable:!0,writable:!0,value:-32003}),Vo=class e extends jo{constructor(t,{method:n}={}){super(t,{code:e.code,name:`MethodNotSupportedRpcError`,shortMessage:`Method${n?` \"${n}\"`:``} is not supported.`})}},Object.defineProperty(Vo,`code`,{enumerable:!0,configurable:!0,writable:!0,value:-32004}),Ho=class e extends jo{constructor(t){super(t,{code:e.code,name:`LimitExceededRpcError`,shortMessage:`Request exceeds defined limit.`})}},Object.defineProperty(Ho,`code`,{enumerable:!0,configurable:!0,writable:!0,value:-32005}),Uo=class e extends jo{constructor(t){super(t,{code:e.code,name:`JsonRpcVersionUnsupportedError`,shortMessage:`Version of JSON-RPC protocol is not supported.`})}},Object.defineProperty(Uo,`code`,{enumerable:!0,configurable:!0,writable:!0,value:-32006}),Wo=class e extends Mo{constructor(t){super(t,{code:e.code,name:`UserRejectedRequestError`,shortMessage:`User rejected the request.`})}},Object.defineProperty(Wo,`code`,{enumerable:!0,configurable:!0,writable:!0,value:4001}),Go=class e extends Mo{constructor(t){super(t,{code:e.code,name:`UnauthorizedProviderError`,shortMessage:`The requested method and/or account has not been authorized by the user.`})}},Object.defineProperty(Go,`code`,{enumerable:!0,configurable:!0,writable:!0,value:4100}),Ko=class e extends Mo{constructor(t,{method:n}={}){super(t,{code:e.code,name:`UnsupportedProviderMethodError`,shortMessage:`The Provider does not support the requested method${n?` \" ${n}\"`:``}.`})}},Object.defineProperty(Ko,`code`,{enumerable:!0,configurable:!0,writable:!0,value:4200}),qo=class e extends Mo{constructor(t){super(t,{code:e.code,name:`ProviderDisconnectedError`,shortMessage:`The Provider is disconnected from all chains.`})}},Object.defineProperty(qo,`code`,{enumerable:!0,configurable:!0,writable:!0,value:4900}),Jo=class e extends Mo{constructor(t){super(t,{code:e.code,name:`ChainDisconnectedError`,shortMessage:`The Provider is not connected to the requested chain.`})}},Object.defineProperty(Jo,`code`,{enumerable:!0,configurable:!0,writable:!0,value:4901}),Yo=class e extends Mo{constructor(t){super(t,{code:e.code,name:`SwitchChainError`,shortMessage:`An error occurred when attempting to switch chain.`})}},Object.defineProperty(Yo,`code`,{enumerable:!0,configurable:!0,writable:!0,value:4902}),Xo=class e extends Mo{constructor(t){super(t,{code:e.code,name:`UnsupportedNonOptionalCapabilityError`,shortMessage:`This Wallet does not support a capability that was not marked as optional.`})}},Object.defineProperty(Xo,`code`,{enumerable:!0,configurable:!0,writable:!0,value:5700}),Zo=class e extends Mo{constructor(t){super(t,{code:e.code,name:`UnsupportedChainIdError`,shortMessage:`This Wallet does not support the requested chain ID.`})}},Object.defineProperty(Zo,`code`,{enumerable:!0,configurable:!0,writable:!0,value:5710}),Qo=class e extends Mo{constructor(t){super(t,{code:e.code,name:`DuplicateIdError`,shortMessage:`There is already a bundle submitted with this ID.`})}},Object.defineProperty(Qo,`code`,{enumerable:!0,configurable:!0,writable:!0,value:5720}),$o=class e extends Mo{constructor(t){super(t,{code:e.code,name:`UnknownBundleIdError`,shortMessage:`This bundle id is unknown / has not been submitted`})}},Object.defineProperty($o,`code`,{enumerable:!0,configurable:!0,writable:!0,value:5730}),es=class e extends Mo{constructor(t){super(t,{code:e.code,name:`BundleTooLargeError`,shortMessage:`The call bundle is too large for the Wallet to process.`})}},Object.defineProperty(es,`code`,{enumerable:!0,configurable:!0,writable:!0,value:5740}),ts=class e extends Mo{constructor(t){super(t,{code:e.code,name:`AtomicReadyWalletRejectedUpgradeError`,shortMessage:`The Wallet can support atomicity after an upgrade, but the user rejected the upgrade.`})}},Object.defineProperty(ts,`code`,{enumerable:!0,configurable:!0,writable:!0,value:5750}),ns=class e extends Mo{constructor(t){super(t,{code:e.code,name:`AtomicityNotSupportedError`,shortMessage:`The wallet does not support atomic execution but the request requires it.`})}},Object.defineProperty(ns,`code`,{enumerable:!0,configurable:!0,writable:!0,value:5760}),rs=class extends jo{constructor(e){super(e,{name:`UnknownRpcError`,shortMessage:`An unknown RPC error occurred.`})}}}));sn(),O(),To(),ko(),os();var ss=3;function cs(e,{abi:t,address:n,args:r,docsPath:i,functionName:a,sender:o}){let s=e instanceof wo?e:e instanceof D?e.walk(e=>`data`in e)||e.walk():{},{code:c,data:l,details:u,message:d,shortMessage:f}=s,p=(()=>e instanceof Wt?new So({functionName:a}):[ss,Io.code].includes(c)&&(l||u||d||f)?new xo({abi:t,data:typeof l==`object`?l.data:l,functionName:a,message:s instanceof Do?u:f??d}):e)();return new bo(p,{abi:t,args:r,contractAddress:n,docsPath:i,functionName:a,sender:o})}yi(),ei();function ls(e){let t=$r(`0x${e.substring(4)}`).substring(26);return gi(`0x${t}`)}var us,ds,fs,ps,ms=o((()=>{us=(function(){let e=typeof document<`u`&&document.createElement(`link`).relList;return e&&e.supports&&e.supports(`modulepreload`)?`modulepreload`:`preload`})(),ds=function(e){return`/`+e},fs={},ps=function(e,t,n){let r=Promise.resolve();if(t&&t.length>0){let e=document.getElementsByTagName(`link`),i=document.querySelector(`meta[property=csp-nonce]`),a=i?.nonce||i?.getAttribute(`nonce`);function o(e){return Promise.all(e.map(e=>Promise.resolve(e).then(e=>({status:`fulfilled`,value:e}),e=>({status:`rejected`,reason:e}))))}r=o(t.map(t=>{if(t=ds(t,n),t in fs)return;fs[t]=!0;let r=t.endsWith(`.css`),i=r?`[rel=\"stylesheet\"]`:``;if(n)for(let n=e.length-1;n>=0;n--){let i=e[n];if(i.href===t&&(!r||i.rel===`stylesheet`))return}else if(document.querySelector(`link[href=\"${t}\"]${i}`))return;let o=document.createElement(`link`);if(o.rel=r?`stylesheet`:us,r||(o.as=`script`),o.crossOrigin=``,o.href=t,a&&o.setAttribute(`nonce`,a),document.head.appendChild(o),r)return new Promise((e,n)=>{o.addEventListener(`load`,e),o.addEventListener(`error`,()=>n(Error(`Unable to preload CSS for ${t}`)))})}))}function i(e){let t=new Event(`vite:preloadError`,{cancelable:!0});if(t.payload=e,window.dispatchEvent(t),!t.defaultPrevented)throw e}return r.then(t=>{for(let e of t||[])e.status===`rejected`&&i(e.reason);return e().catch(i)})}}));function hs(e,t,n,r){if(typeof e.setBigUint64==`function`)return e.setBigUint64(t,n,r);let i=BigInt(32),a=BigInt(4294967295),o=Number(n>>i&a),s=Number(n&a),c=r?4:0,l=r?0:4;e.setUint32(t+c,o,r),e.setUint32(t+l,s,r)}function gs(e,t,n){return e&t^~e&n}function _s(e,t,n){return e&t^e&n^t&n}var vs,ys,bs,xs,Ss=o((()=>{Nr(),vs=class extends Mr{constructor(e,t,n,r){super(),this.finished=!1,this.length=0,this.pos=0,this.destroyed=!1,this.blockLen=e,this.outputLen=t,this.padOffset=n,this.isLE=r,this.buffer=new Uint8Array(e),this.view=xr(this.buffer)}update(e){_r(this),e=Er(e),hr(e);let{view:t,buffer:n,blockLen:r}=this,i=e.length;for(let a=0;a<i;){let o=Math.min(r-this.pos,i-a);if(o===r){let t=xr(e);for(;r<=i-a;a+=r)this.process(t,a);continue}n.set(e.subarray(a,a+o),this.pos),this.pos+=o,a+=o,this.pos===r&&(this.process(t,0),this.pos=0)}return this.length+=e.length,this.roundClean(),this}digestInto(e){_r(this),vr(e,this),this.finished=!0;let{buffer:t,view:n,blockLen:r,isLE:i}=this,{pos:a}=this;t[a++]=128,br(this.buffer.subarray(a)),this.padOffset>r-a&&(this.process(n,0),a=0);for(let e=a;e<r;e++)t[e]=0;hs(n,r-8,BigInt(this.length*8),i),this.process(n,0);let o=xr(e),s=this.outputLen;if(s%4)throw Error(`_sha2: outputLen should be aligned to 32bit`);let c=s/4,l=this.get();if(c>l.length)throw Error(`_sha2: outputLen bigger than state`);for(let e=0;e<c;e++)o.setUint32(4*e,l[e],i)}digest(){let{buffer:e,outputLen:t}=this;this.digestInto(e);let n=e.slice(0,t);return this.destroy(),n}_cloneInto(e){e||=new this.constructor,e.set(...this.get());let{blockLen:t,buffer:n,length:r,finished:i,destroyed:a,pos:o}=this;return e.destroyed=a,e.finished=i,e.length=r,e.pos=o,r%t&&e.buffer.set(n),e}clone(){return this._cloneInto()}},ys=Uint32Array.from([1779033703,3144134277,1013904242,2773480762,1359893119,2600822924,528734635,1541459225]),bs=Uint32Array.from([3418070365,3238371032,1654270250,914150663,2438529370,812702999,355462360,4144912697,1731405415,4290775857,2394180231,1750603025,3675008525,1694076839,1203062813,3204075428]),xs=Uint32Array.from([1779033703,4089235720,3144134277,2227873595,1013904242,4271175723,2773480762,1595750129,1359893119,2917565137,2600822924,725511199,528734635,4215389547,1541459225,327033209])})),Cs,ws,Ts,Es,Ds,Os,ks,As,js,Ms,Ns,Ps,Fs,Is=o((()=>{Ss(),ur(),Nr(),Cs=Uint32Array.from([1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298]),ws=new Uint32Array(64),Ts=class extends vs{constructor(e=32){super(64,e,8,!1),this.A=ys[0]|0,this.B=ys[1]|0,this.C=ys[2]|0,this.D=ys[3]|0,this.E=ys[4]|0,this.F=ys[5]|0,this.G=ys[6]|0,this.H=ys[7]|0}get(){let{A:e,B:t,C:n,D:r,E:i,F:a,G:o,H:s}=this;return[e,t,n,r,i,a,o,s]}set(e,t,n,r,i,a,o,s){this.A=e|0,this.B=t|0,this.C=n|0,this.D=r|0,this.E=i|0,this.F=a|0,this.G=o|0,this.H=s|0}process(e,t){for(let n=0;n<16;n++,t+=4)ws[n]=e.getUint32(t,!1);for(let e=16;e<64;e++){let t=ws[e-15],n=ws[e-2],r=Sr(t,7)^Sr(t,18)^t>>>3;ws[e]=(Sr(n,17)^Sr(n,19)^n>>>10)+ws[e-7]+r+ws[e-16]|0}let{A:n,B:r,C:i,D:a,E:o,F:s,G:c,H:l}=this;for(let e=0;e<64;e++){let t=Sr(o,6)^Sr(o,11)^Sr(o,25),u=l+t+gs(o,s,c)+Cs[e]+ws[e]|0,d=(Sr(n,2)^Sr(n,13)^Sr(n,22))+_s(n,r,i)|0;l=c,c=s,s=o,o=a+u|0,a=i,i=r,r=n,n=u+d|0}n=n+this.A|0,r=r+this.B|0,i=i+this.C|0,a=a+this.D|0,o=o+this.E|0,s=s+this.F|0,c=c+this.G|0,l=l+this.H|0,this.set(n,r,i,a,o,s,c,l)}roundClean(){br(ws)}destroy(){this.set(0,0,0,0,0,0,0,0),br(this.buffer)}},Es=(()=>Wn(`0x428a2f98d728ae22.0x7137449123ef65cd.0xb5c0fbcfec4d3b2f.0xe9b5dba58189dbbc.0x3956c25bf348b538.0x59f111f1b605d019.0x923f82a4af194f9b.0xab1c5ed5da6d8118.0xd807aa98a3030242.0x12835b0145706fbe.0x243185be4ee4b28c.0x550c7dc3d5ffb4e2.0x72be5d74f27b896f.0x80deb1fe3b1696b1.0x9bdc06a725c71235.0xc19bf174cf692694.0xe49b69c19ef14ad2.0xefbe4786384f25e3.0x0fc19dc68b8cd5b5.0x240ca1cc77ac9c65.0x2de92c6f592b0275.0x4a7484aa6ea6e483.0x5cb0a9dcbd41fbd4.0x76f988da831153b5.0x983e5152ee66dfab.0xa831c66d2db43210.0xb00327c898fb213f.0xbf597fc7beef0ee4.0xc6e00bf33da88fc2.0xd5a79147930aa725.0x06ca6351e003826f.0x142929670a0e6e70.0x27b70a8546d22ffc.0x2e1b21385c26c926.0x4d2c6dfc5ac42aed.0x53380d139d95b3df.0x650a73548baf63de.0x766a0abb3c77b2a8.0x81c2c92e47edaee6.0x92722c851482353b.0xa2bfe8a14cf10364.0xa81a664bbc423001.0xc24b8b70d0f89791.0xc76c51a30654be30.0xd192e819d6ef5218.0xd69906245565a910.0xf40e35855771202a.0x106aa07032bbd1b8.0x19a4c116b8d2d0c8.0x1e376c085141ab53.0x2748774cdf8eeb99.0x34b0bcb5e19b48a8.0x391c0cb3c5c95a63.0x4ed8aa4ae3418acb.0x5b9cca4f7763e373.0x682e6ff3d6b2b8a3.0x748f82ee5defb2fc.0x78a5636f43172f60.0x84c87814a1f0ab72.0x8cc702081a6439ec.0x90befffa23631e28.0xa4506cebde82bde9.0xbef9a3f7b2c67915.0xc67178f2e372532b.0xca273eceea26619c.0xd186b8c721c0c207.0xeada7dd6cde0eb1e.0xf57d4f7fee6ed178.0x06f067aa72176fba.0x0a637dc5a2c898a6.0x113f9804bef90dae.0x1b710b35131c471b.0x28db77f523047d84.0x32caab7b40c72493.0x3c9ebe0a15c9bebc.0x431d67c49c100d4c.0x4cc5d4becb3e42b6.0x597f299cfc657e2a.0x5fcb6fab3ad6faec.0x6c44198c4a475817`.split(`.`).map(e=>BigInt(e))))(),Ds=(()=>Es[0])(),Os=(()=>Es[1])(),ks=new Uint32Array(80),As=new Uint32Array(80),js=class extends vs{constructor(e=64){super(128,e,16,!1),this.Ah=xs[0]|0,this.Al=xs[1]|0,this.Bh=xs[2]|0,this.Bl=xs[3]|0,this.Ch=xs[4]|0,this.Cl=xs[5]|0,this.Dh=xs[6]|0,this.Dl=xs[7]|0,this.Eh=xs[8]|0,this.El=xs[9]|0,this.Fh=xs[10]|0,this.Fl=xs[11]|0,this.Gh=xs[12]|0,this.Gl=xs[13]|0,this.Hh=xs[14]|0,this.Hl=xs[15]|0}get(){let{Ah:e,Al:t,Bh:n,Bl:r,Ch:i,Cl:a,Dh:o,Dl:s,Eh:c,El:l,Fh:u,Fl:d,Gh:f,Gl:p,Hh:m,Hl:h}=this;return[e,t,n,r,i,a,o,s,c,l,u,d,f,p,m,h]}set(e,t,n,r,i,a,o,s,c,l,u,d,f,p,m,h){this.Ah=e|0,this.Al=t|0,this.Bh=n|0,this.Bl=r|0,this.Ch=i|0,this.Cl=a|0,this.Dh=o|0,this.Dl=s|0,this.Eh=c|0,this.El=l|0,this.Fh=u|0,this.Fl=d|0,this.Gh=f|0,this.Gl=p|0,this.Hh=m|0,this.Hl=h|0}process(e,t){for(let n=0;n<16;n++,t+=4)ks[n]=e.getUint32(t),As[n]=e.getUint32(t+=4);for(let e=16;e<80;e++){let t=ks[e-15]|0,n=As[e-15]|0,r=Xn(t,n,1)^Xn(t,n,8)^Jn(t,n,7),i=Zn(t,n,1)^Zn(t,n,8)^Yn(t,n,7),a=ks[e-2]|0,o=As[e-2]|0,s=Xn(a,o,19)^Qn(a,o,61)^Jn(a,o,6),c=Zn(a,o,19)^$n(a,o,61)^Yn(a,o,6),l=or(i,c,As[e-7],As[e-16]);ks[e]=sr(l,r,s,ks[e-7],ks[e-16])|0,As[e]=l|0}let{Ah:n,Al:r,Bh:i,Bl:a,Ch:o,Cl:s,Dh:c,Dl:l,Eh:u,El:d,Fh:f,Fl:p,Gh:m,Gl:h,Hh:g,Hl:_}=this;for(let e=0;e<80;e++){let t=Xn(u,d,14)^Xn(u,d,18)^Qn(u,d,41),v=Zn(u,d,14)^Zn(u,d,18)^$n(u,d,41),y=u&f^~u&m,b=d&p^~d&h,x=cr(_,v,b,Os[e],As[e]),S=lr(x,g,t,y,Ds[e],ks[e]),C=x|0,w=Xn(n,r,28)^Qn(n,r,34)^Qn(n,r,39),ee=Zn(n,r,28)^$n(n,r,34)^$n(n,r,39),te=n&i^n&o^i&o,ne=r&a^r&s^a&s;g=m|0,_=h|0,m=f|0,h=p|0,f=u|0,p=d|0,{h:u,l:d}=Gn(c|0,l|0,S|0,C|0),c=o|0,l=s|0,o=i|0,s=a|0,i=n|0,a=r|0;let re=ir(C,ee,ne);n=ar(re,S,w,te),r=re|0}({h:n,l:r}=Gn(this.Ah|0,this.Al|0,n|0,r|0)),{h:i,l:a}=Gn(this.Bh|0,this.Bl|0,i|0,a|0),{h:o,l:s}=Gn(this.Ch|0,this.Cl|0,o|0,s|0),{h:c,l}=Gn(this.Dh|0,this.Dl|0,c|0,l|0),{h:u,l:d}=Gn(this.Eh|0,this.El|0,u|0,d|0),{h:f,l:p}=Gn(this.Fh|0,this.Fl|0,f|0,p|0),{h:m,l:h}=Gn(this.Gh|0,this.Gl|0,m|0,h|0),{h:g,l:_}=Gn(this.Hh|0,this.Hl|0,g|0,_|0),this.set(n,r,i,a,o,s,c,l,u,d,f,p,m,h,g,_)}roundClean(){br(ks,As)}destroy(){br(this.buffer),this.set(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)}},Ms=class extends js{constructor(){super(48),this.Ah=bs[0]|0,this.Al=bs[1]|0,this.Bh=bs[2]|0,this.Bl=bs[3]|0,this.Ch=bs[4]|0,this.Cl=bs[5]|0,this.Dh=bs[6]|0,this.Dl=bs[7]|0,this.Eh=bs[8]|0,this.El=bs[9]|0,this.Fh=bs[10]|0,this.Fl=bs[11]|0,this.Gh=bs[12]|0,this.Gl=bs[13]|0,this.Hh=bs[14]|0,this.Hl=bs[15]|0}},Ns=Or(()=>new Ts),Ps=Or(()=>new js),Fs=Or(()=>new Ms)})),Ls,Rs,zs=o((()=>{Nr(),Ls=class extends Mr{constructor(e,t){super(),this.finished=!1,this.destroyed=!1,gr(e);let n=Er(t);if(this.iHash=e.create(),typeof this.iHash.update!=`function`)throw Error(`Expected instance of class which extends utils.Hash`);this.blockLen=this.iHash.blockLen,this.outputLen=this.iHash.outputLen;let r=this.blockLen,i=new Uint8Array(r);i.set(n.length>r?e.create().update(n).digest():n);for(let e=0;e<i.length;e++)i[e]^=54;this.iHash.update(i),this.oHash=e.create();for(let e=0;e<i.length;e++)i[e]^=106;this.oHash.update(i),br(i)}update(e){return _r(this),this.iHash.update(e),this}digestInto(e){_r(this),hr(e,this.outputLen),this.finished=!0,this.iHash.digestInto(e),this.oHash.update(e),this.oHash.digestInto(e),this.destroy()}digest(){let e=new Uint8Array(this.oHash.outputLen);return this.digestInto(e),e}_cloneInto(e){e||=Object.create(Object.getPrototypeOf(this),{});let{oHash:t,iHash:n,finished:r,destroyed:i,blockLen:a,outputLen:o}=this;return e=e,e.finished=r,e.destroyed=i,e.blockLen=a,e.outputLen=o,e.oHash=t._cloneInto(e.oHash),e.iHash=n._cloneInto(e.iHash),e}clone(){return this._cloneInto()}destroy(){this.destroyed=!0,this.oHash.destroy(),this.iHash.destroy()}},Rs=(e,t,n)=>new Ls(e,t).update(n).digest(),Rs.create=(e,t)=>new Ls(e,t)}));function Bs(e){return e instanceof Uint8Array||ArrayBuffer.isView(e)&&e.constructor.name===`Uint8Array`}function Vs(e){if(!Bs(e))throw Error(`Uint8Array expected`)}function Hs(e,t){if(typeof t!=`boolean`)throw Error(e+` boolean expected, got `+t)}function Us(e){let t=e.toString(16);return t.length&1?`0`+t:t}function Ws(e){if(typeof e!=`string`)throw Error(`hex string expected, got `+typeof e);return e===``?sc:BigInt(`0x`+e)}function Gs(e){if(Vs(e),lc)return e.toHex();let t=``;for(let n=0;n<e.length;n++)t+=uc[e[n]];return t}function Ks(e){if(e>=dc._0&&e<=dc._9)return e-dc._0;if(e>=dc.A&&e<=dc.F)return e-(dc.A-10);if(e>=dc.a&&e<=dc.f)return e-(dc.a-10)}function qs(e){if(typeof e!=`string`)throw Error(`hex string expected, got `+typeof e);if(lc)return Uint8Array.fromHex(e);let t=e.length,n=t/2;if(t%2)throw Error(`hex string expected, got unpadded hex of length `+t);let r=new Uint8Array(n);for(let t=0,i=0;t<n;t++,i+=2){let n=Ks(e.charCodeAt(i)),a=Ks(e.charCodeAt(i+1));if(n===void 0||a===void 0){let t=e[i]+e[i+1];throw Error(`hex string expected, got non-hex character \"`+t+`\" at index `+i)}r[t]=n*16+a}return r}function Js(e){return Ws(Gs(e))}function Ys(e){return Vs(e),Ws(Gs(Uint8Array.from(e).reverse()))}function Xs(e,t){return qs(e.toString(16).padStart(t*2,`0`))}function Zs(e,t){return Xs(e,t).reverse()}function Qs(e,t,n){let r;if(typeof t==`string`)try{r=qs(t)}catch(t){throw Error(e+` must be hex string or Uint8Array, cause: `+t)}else if(Bs(t))r=Uint8Array.from(t);else throw Error(e+` must be hex string or Uint8Array`);let i=r.length;if(typeof n==`number`&&i!==n)throw Error(e+` of length `+n+` expected, got `+i);return r}function $s(...e){let t=0;for(let n=0;n<e.length;n++){let r=e[n];Vs(r),t+=r.length}let n=new Uint8Array(t);for(let t=0,r=0;t<e.length;t++){let i=e[t];n.set(i,r),r+=i.length}return n}function ec(e){if(typeof e!=`string`)throw Error(`string expected`);return new Uint8Array(new TextEncoder().encode(e))}function tc(e,t,n){return fc(e)&&fc(t)&&fc(n)&&t<=e&&e<n}function nc(e,t,n,r){if(!tc(t,n,r))throw Error(`expected valid `+e+`: `+n+` <= n < `+r+`, got `+t)}function rc(e){let t;for(t=0;e>sc;e>>=cc,t+=1);return t}function ic(e,t,n){if(typeof e!=`number`||e<2)throw Error(`hashLen must be a number`);if(typeof t!=`number`||t<2)throw Error(`qByteLen must be a number`);if(typeof n!=`function`)throw Error(`hmacFn must be a function`);let r=mc(e),i=mc(e),a=0,o=()=>{r.fill(1),i.fill(0),a=0},s=(...e)=>n(i,r,...e),c=(e=mc(0))=>{i=s(hc([0]),e),r=s(),e.length!==0&&(i=s(hc([1]),e),r=s())},l=()=>{if(a++>=1e3)throw Error(`drbg: tried 1000 values`);let e=0,n=[];for(;e<t;){r=s();let t=r.slice();n.push(t),e+=r.length}return $s(...n)};return(e,t)=>{o(),c(e);let n;for(;!(n=t(l()));)c();return o(),n}}function ac(e,t,n={}){let r=(t,n,r)=>{let i=gc[n];if(typeof i!=`function`)throw Error(`invalid validator function`);let a=e[t];if(!(r&&a===void 0)&&!i(a,e))throw Error(`param `+String(t)+` is invalid. Expected `+n+`, got `+a)};for(let[e,n]of Object.entries(t))r(e,n,!1);for(let[e,t]of Object.entries(n))r(e,t,!0);return e}function oc(e){let t=new WeakMap;return(n,...r)=>{let i=t.get(n);if(i!==void 0)return i;let a=e(n,...r);return t.set(n,a),a}}var sc,cc,lc,uc,dc,fc,pc,mc,hc,gc,_c=o((()=>{sc=BigInt(0),cc=BigInt(1),lc=typeof Uint8Array.from([]).toHex==`function`&&typeof Uint8Array.fromHex==`function`,uc=Array.from({length:256},(e,t)=>t.toString(16).padStart(2,`0`)),dc={_0:48,_9:57,A:65,F:70,a:97,f:102},fc=e=>typeof e==`bigint`&&sc<=e,pc=e=>(cc<<BigInt(e))-cc,mc=e=>new Uint8Array(e),hc=e=>Uint8Array.from(e),gc={bigint:e=>typeof e==`bigint`,function:e=>typeof e==`function`,boolean:e=>typeof e==`boolean`,string:e=>typeof e==`string`,stringOrUint8Array:e=>typeof e==`string`||Bs(e),isSafeInteger:e=>Number.isSafeInteger(e),array:e=>Array.isArray(e),field:(e,t)=>t.Fp.isValid(e),hash:e=>typeof e==`function`&&Number.isSafeInteger(e.outputLen)}}));function vc(e,t){let n=e%t;return n>=Pc?n:t+n}function yc(e,t,n){let r=e;for(;t-- >Pc;)r*=r,r%=n;return r}function bc(e,t){if(e===Pc)throw Error(`invert: expected non-zero number`);if(t<=Pc)throw Error(`invert: expected positive modulus, got `+t);let n=vc(e,t),r=t,i=Pc,a=Fc,o=Fc,s=Pc;for(;n!==Pc;){let e=r/n,t=r%n,c=i-o*e,l=a-s*e;r=n,n=t,i=o,a=s,o=c,s=l}if(r!==Fc)throw Error(`invert: does not exist`);return vc(i,t)}function xc(e,t){let n=(e.ORDER+Fc)/Rc,r=e.pow(t,n);if(!e.eql(e.sqr(r),t))throw Error(`Cannot find square root`);return r}function Sc(e,t){let n=(e.ORDER-zc)/Bc,r=e.mul(t,Ic),i=e.pow(r,n),a=e.mul(t,i),o=e.mul(e.mul(a,Ic),i),s=e.mul(a,e.sub(o,e.ONE));if(!e.eql(e.sqr(s),t))throw Error(`Cannot find square root`);return s}function Cc(e){if(e<BigInt(3))throw Error(`sqrt is not defined for small field`);let t=e-Fc,n=0;for(;t%Ic===Pc;)t/=Ic,n++;let r=Ic,i=Ac(e);for(;Oc(i,r)===1;)if(r++>1e3)throw Error(`Cannot find square root: probably non-prime P`);if(n===1)return xc;let a=i.pow(r,t),o=(t+Fc)/Ic;return function(e,r){if(e.is0(r))return r;if(Oc(e,r)!==1)throw Error(`Cannot find square root`);let i=n,s=e.mul(e.ONE,a),c=e.pow(r,t),l=e.pow(r,o);for(;!e.eql(c,e.ONE);){if(e.is0(c))return e.ZERO;let t=1,n=e.sqr(c);for(;!e.eql(n,e.ONE);)if(t++,n=e.sqr(n),t===i)throw Error(`Cannot find square root`);let r=Fc<<BigInt(i-t-1),a=e.pow(s,r);i=t,s=e.sqr(a),c=e.mul(c,s),l=e.mul(l,a)}return l}}function wc(e){return e%Rc===Lc?xc:e%Bc===zc?Sc:Cc(e)}function Tc(e){let t=Vc.reduce((e,t)=>(e[t]=`function`,e),{ORDER:`bigint`,MASK:`bigint`,BYTES:`isSafeInteger`,BITS:`isSafeInteger`});return ac(e,t)}function Ec(e,t,n){if(n<Pc)throw Error(`invalid exponent, negatives unsupported`);if(n===Pc)return e.ONE;if(n===Fc)return t;let r=e.ONE,i=t;for(;n>Pc;)n&Fc&&(r=e.mul(r,i)),i=e.sqr(i),n>>=Fc;return r}function Dc(e,t,n=!1){let r=Array(t.length).fill(n?e.ZERO:void 0),i=t.reduce((t,n,i)=>e.is0(n)?t:(r[i]=t,e.mul(t,n)),e.ONE),a=e.inv(i);return t.reduceRight((t,n,i)=>e.is0(n)?t:(r[i]=e.mul(t,r[i]),e.mul(t,n)),a),r}function Oc(e,t){let n=(e.ORDER-Fc)/Ic,r=e.pow(t,n),i=e.eql(r,e.ONE),a=e.eql(r,e.ZERO),o=e.eql(r,e.neg(e.ONE));if(!i&&!a&&!o)throw Error(`invalid Legendre symbol result`);return i?1:a?0:-1}function kc(e,t){t!==void 0&&mr(t);let n=t===void 0?e.toString(2).length:t,r=Math.ceil(n/8);return{nBitLength:n,nByteLength:r}}function Ac(e,t,n=!1,r={}){if(e<=Pc)throw Error(`invalid field: expected ORDER > 0, got `+e);let{nBitLength:i,nByteLength:a}=kc(e,t);if(a>2048)throw Error(`invalid field: expected ORDER of <= 2048 bytes`);let o,s=Object.freeze({ORDER:e,isLE:n,BITS:i,BYTES:a,MASK:pc(i),ZERO:Pc,ONE:Fc,create:t=>vc(t,e),isValid:t=>{if(typeof t!=`bigint`)throw Error(`invalid field element: expected bigint, got `+typeof t);return Pc<=t&&t<e},is0:e=>e===Pc,isOdd:e=>(e&Fc)===Fc,neg:t=>vc(-t,e),eql:(e,t)=>e===t,sqr:t=>vc(t*t,e),add:(t,n)=>vc(t+n,e),sub:(t,n)=>vc(t-n,e),mul:(t,n)=>vc(t*n,e),pow:(e,t)=>Ec(s,e,t),div:(t,n)=>vc(t*bc(n,e),e),sqrN:e=>e*e,addN:(e,t)=>e+t,subN:(e,t)=>e-t,mulN:(e,t)=>e*t,inv:t=>bc(t,e),sqrt:r.sqrt||(t=>(o||=wc(e),o(s,t))),toBytes:e=>n?Zs(e,a):Xs(e,a),fromBytes:e=>{if(e.length!==a)throw Error(`Field.fromBytes: expected `+a+` bytes, got `+e.length);return n?Ys(e):Js(e)},invertBatch:e=>Dc(s,e),cmov:(e,t,n)=>n?t:e});return Object.freeze(s)}function jc(e){if(typeof e!=`bigint`)throw Error(`field order must be bigint`);let t=e.toString(2).length;return Math.ceil(t/8)}function Mc(e){let t=jc(e);return t+Math.ceil(t/2)}function Nc(e,t,n=!1){let r=e.length,i=jc(t),a=Mc(t);if(r<16||r<a||r>1024)throw Error(`expected `+a+`-1024 bytes of input, got `+r);let o=n?Ys(e):Js(e),s=vc(o,t-Fc)+Fc;return n?Zs(s,i):Xs(s,i)}var Pc,Fc,Ic,Lc,Rc,zc,Bc,Vc,Hc=o((()=>{Nr(),_c(),Pc=BigInt(0),Fc=BigInt(1),Ic=BigInt(2),Lc=BigInt(3),Rc=BigInt(4),zc=BigInt(5),Bc=BigInt(8),Vc=[`create`,`isValid`,`is0`,`neg`,`inv`,`sqrt`,`sqr`,`eql`,`add`,`sub`,`mul`,`pow`,`div`,`addN`,`subN`,`mulN`,`sqrN`]}));function Uc(e,t){let n=t.negate();return e?n:t}function Wc(e,t){if(!Number.isSafeInteger(e)||e<=0||e>t)throw Error(`invalid window size, expected [1..`+t+`], got W=`+e)}function Gc(e,t){Wc(e,t);let n=Math.ceil(t/e)+1,r=2**(e-1),i=2**e,a=pc(e),o=BigInt(e);return{windows:n,windowSize:r,mask:a,maxNumber:i,shiftBy:o}}function Kc(e,t,n){let{windowSize:r,mask:i,maxNumber:a,shiftBy:o}=n,s=Number(e&i),c=e>>o;s>r&&(s-=a,c+=el);let l=t*r,u=l+Math.abs(s)-1,d=s===0,f=s<0,p=t%2!=0;return{nextN:c,offset:u,isZero:d,isNeg:f,isNegF:p,offsetF:l}}function qc(e,t){if(!Array.isArray(e))throw Error(`array expected`);e.forEach((e,n)=>{if(!(e instanceof t))throw Error(`invalid point at index `+n)})}function Jc(e,t){if(!Array.isArray(e))throw Error(`array of scalars expected`);e.forEach((e,n)=>{if(!t.isValid(e))throw Error(`invalid scalar at index `+n)})}function Yc(e){return nl.get(e)||1}function Xc(e,t){return{constTimeNegate:Uc,hasPrecomputes(e){return Yc(e)!==1},unsafeLadder(t,n,r=e.ZERO){let i=t;for(;n>$c;)n&el&&(r=r.add(i)),i=i.double(),n>>=el;return r},precomputeWindow(e,n){let{windows:r,windowSize:i}=Gc(n,t),a=[],o=e,s=o;for(let e=0;e<r;e++){s=o,a.push(s);for(let e=1;e<i;e++)s=s.add(o),a.push(s);o=s.double()}return a},wNAF(n,r,i){let a=e.ZERO,o=e.BASE,s=Gc(n,t);for(let e=0;e<s.windows;e++){let{nextN:t,offset:n,isZero:c,isNeg:l,isNegF:u,offsetF:d}=Kc(i,e,s);i=t,c?o=o.add(Uc(u,r[d])):a=a.add(Uc(l,r[n]))}return{p:a,f:o}},wNAFUnsafe(n,r,i,a=e.ZERO){let o=Gc(n,t);for(let e=0;e<o.windows&&i!==$c;e++){let{nextN:t,offset:n,isZero:s,isNeg:c}=Kc(i,e,o);if(i=t,!s){let e=r[n];a=a.add(c?e.negate():e)}}return a},getPrecomputes(e,t,n){let r=tl.get(t);return r||(r=this.precomputeWindow(t,e),e!==1&&tl.set(t,n(r))),r},wNAFCached(e,t,n){let r=Yc(e);return this.wNAF(r,this.getPrecomputes(r,e,n),t)},wNAFCachedUnsafe(e,t,n,r){let i=Yc(e);return i===1?this.unsafeLadder(e,t,r):this.wNAFUnsafe(i,this.getPrecomputes(i,e,n),t,r)},setWindowSize(e,n){Wc(n,t),nl.set(e,n),tl.delete(e)}}}function Zc(e,t,n,r){qc(n,e),Jc(r,t);let i=n.length,a=r.length;if(i!==a)throw Error(`arrays of points and scalars must have equal length`);let o=e.ZERO,s=rc(BigInt(i)),c=1;s>12?c=s-3:s>4?c=s-2:s>0&&(c=2);let l=pc(c),u=Array(Number(l)+1).fill(o),d=Math.floor((t.BITS-1)/c)*c,f=o;for(let e=d;e>=0;e-=c){u.fill(o);for(let t=0;t<a;t++){let i=r[t],a=Number(i>>BigInt(e)&l);u[a]=u[a].add(n[t])}let t=o;for(let e=u.length-1,n=o;e>0;e--)n=n.add(u[e]),t=t.add(n);if(f=f.add(t),e!==0)for(let e=0;e<c;e++)f=f.double()}return f}function Qc(e){return Tc(e.Fp),ac(e,{n:`bigint`,h:`bigint`,Gx:`field`,Gy:`field`},{nBitLength:`isSafeInteger`,nByteLength:`isSafeInteger`}),Object.freeze({...kc(e.n,e.nBitLength),...e,p:e.Fp.ORDER})}var $c,el,tl,nl,rl=o((()=>{Hc(),_c(),$c=BigInt(0),el=BigInt(1),tl=new WeakMap,nl=new WeakMap}));function il(e){e.lowS!==void 0&&Hs(`lowS`,e.lowS),e.prehash!==void 0&&Hs(`prehash`,e.prehash)}function al(e){let t=Qc(e);ac(t,{a:`field`,b:`field`},{allowInfinityPoint:`boolean`,allowedPrivateKeyLengths:`array`,clearCofactor:`function`,fromBytes:`function`,isTorsionFree:`function`,toBytes:`function`,wrapPrivateKey:`boolean`});let{endo:n,Fp:r,a:i}=t;if(n){if(!r.eql(i,r.ZERO))throw Error(`invalid endo: CURVE.a must be 0`);if(typeof n!=`object`||typeof n.beta!=`bigint`||typeof n.splitScalar!=`function`)throw Error(`invalid endo: expected \"beta\": bigint and \"splitScalar\": function`)}return Object.freeze({...t})}function ol(e,t){return Gs(Xs(e,t))}function sl(e){let t=al(e),{Fp:n}=t,r=Ac(t.n,t.nBitLength),i=t.toBytes||((e,t,r)=>{let i=t.toAffine();return $s(Uint8Array.from([4]),n.toBytes(i.x),n.toBytes(i.y))}),a=t.fromBytes||(e=>{let t=e.subarray(1),r=n.fromBytes(t.subarray(0,n.BYTES)),i=n.fromBytes(t.subarray(n.BYTES,2*n.BYTES));return{x:r,y:i}});function o(e){let{a:r,b:i}=t,a=n.sqr(e),o=n.mul(a,e);return n.add(n.add(o,n.mul(e,r)),i)}function s(e,t){let r=n.sqr(t),i=o(e);return n.eql(r,i)}if(!s(t.Gx,t.Gy))throw Error(`bad curve params: generator point`);let c=n.mul(n.pow(t.a,_l),vl),l=n.mul(n.sqr(t.b),BigInt(27));if(n.is0(n.add(c,l)))throw Error(`bad curve params: a or b`);function u(e){return tc(e,hl,t.n)}function d(e){let{allowedPrivateKeyLengths:n,nByteLength:r,wrapPrivateKey:i,n:a}=t;if(n&&typeof e!=`bigint`){if(Bs(e)&&(e=Gs(e)),typeof e!=`string`||!n.includes(e.length))throw Error(`invalid private key`);e=e.padStart(r*2,`0`)}let o;try{o=typeof e==`bigint`?e:Js(Qs(`private key`,e,r))}catch{throw Error(`invalid private key, expected hex or `+r+` bytes, got `+typeof e)}return i&&(o=vc(o,a)),nc(`private key`,o,hl,a),o}function f(e){if(!(e instanceof h))throw Error(`ProjectivePoint expected`)}let p=oc((e,t)=>{let{px:r,py:i,pz:a}=e;if(n.eql(a,n.ONE))return{x:r,y:i};let o=e.is0();t??=o?n.ONE:n.inv(a);let s=n.mul(r,t),c=n.mul(i,t),l=n.mul(a,t);if(o)return{x:n.ZERO,y:n.ZERO};if(!n.eql(l,n.ONE))throw Error(`invZ was invalid`);return{x:s,y:c}}),m=oc(e=>{if(e.is0()){if(t.allowInfinityPoint&&!n.is0(e.py))return;throw Error(`bad point: ZERO`)}let{x:r,y:i}=e.toAffine();if(!n.isValid(r)||!n.isValid(i))throw Error(`bad point: x or y not FE`);if(!s(r,i))throw Error(`bad point: equation left != right`);if(!e.isTorsionFree())throw Error(`bad point: not in prime-order subgroup`);return!0});class h{constructor(e,t,r){if(e==null||!n.isValid(e))throw Error(`x required`);if(t==null||!n.isValid(t)||n.is0(t))throw Error(`y required`);if(r==null||!n.isValid(r))throw Error(`z required`);this.px=e,this.py=t,this.pz=r,Object.freeze(this)}static fromAffine(e){let{x:t,y:r}=e||{};if(!e||!n.isValid(t)||!n.isValid(r))throw Error(`invalid affine point`);if(e instanceof h)throw Error(`projective point not allowed`);let i=e=>n.eql(e,n.ZERO);return i(t)&&i(r)?h.ZERO:new h(t,r,n.ONE)}get x(){return this.toAffine().x}get y(){return this.toAffine().y}static normalizeZ(e){let t=Dc(n,e.map(e=>e.pz));return e.map((e,n)=>e.toAffine(t[n])).map(h.fromAffine)}static fromHex(e){let t=h.fromAffine(a(Qs(`pointHex`,e)));return t.assertValidity(),t}static fromPrivateKey(e){return h.BASE.multiply(d(e))}static msm(e,t){return Zc(h,r,e,t)}_setWindowSize(e){v.setWindowSize(this,e)}assertValidity(){m(this)}hasEvenY(){let{y:e}=this.toAffine();if(n.isOdd)return!n.isOdd(e);throw Error(`Field doesn't support isOdd`)}equals(e){f(e);let{px:t,py:r,pz:i}=this,{px:a,py:o,pz:s}=e,c=n.eql(n.mul(t,s),n.mul(a,i)),l=n.eql(n.mul(r,s),n.mul(o,i));return c&&l}negate(){return new h(this.px,n.neg(this.py),this.pz)}double(){let{a:e,b:r}=t,i=n.mul(r,_l),{px:a,py:o,pz:s}=this,c=n.ZERO,l=n.ZERO,u=n.ZERO,d=n.mul(a,a),f=n.mul(o,o),p=n.mul(s,s),m=n.mul(a,o);return m=n.add(m,m),u=n.mul(a,s),u=n.add(u,u),c=n.mul(e,u),l=n.mul(i,p),l=n.add(c,l),c=n.sub(f,l),l=n.add(f,l),l=n.mul(c,l),c=n.mul(m,c),u=n.mul(i,u),p=n.mul(e,p),m=n.sub(d,p),m=n.mul(e,m),m=n.add(m,u),u=n.add(d,d),d=n.add(u,d),d=n.add(d,p),d=n.mul(d,m),l=n.add(l,d),p=n.mul(o,s),p=n.add(p,p),d=n.mul(p,m),c=n.sub(c,d),u=n.mul(p,f),u=n.add(u,u),u=n.add(u,u),new h(c,l,u)}add(e){f(e);let{px:r,py:i,pz:a}=this,{px:o,py:s,pz:c}=e,l=n.ZERO,u=n.ZERO,d=n.ZERO,p=t.a,m=n.mul(t.b,_l),g=n.mul(r,o),_=n.mul(i,s),v=n.mul(a,c),y=n.add(r,i),b=n.add(o,s);y=n.mul(y,b),b=n.add(g,_),y=n.sub(y,b),b=n.add(r,a);let x=n.add(o,c);return b=n.mul(b,x),x=n.add(g,v),b=n.sub(b,x),x=n.add(i,a),l=n.add(s,c),x=n.mul(x,l),l=n.add(_,v),x=n.sub(x,l),d=n.mul(p,b),l=n.mul(m,v),d=n.add(l,d),l=n.sub(_,d),d=n.add(_,d),u=n.mul(l,d),_=n.add(g,g),_=n.add(_,g),v=n.mul(p,v),b=n.mul(m,b),_=n.add(_,v),v=n.sub(g,v),v=n.mul(p,v),b=n.add(b,v),g=n.mul(_,b),u=n.add(u,g),g=n.mul(x,b),l=n.mul(y,l),l=n.sub(l,g),g=n.mul(y,_),d=n.mul(x,d),d=n.add(d,g),new h(l,u,d)}subtract(e){return this.add(e.negate())}is0(){return this.equals(h.ZERO)}wNAF(e){return v.wNAFCached(this,e,h.normalizeZ)}multiplyUnsafe(e){let{endo:r,n:i}=t;nc(`scalar`,e,ml,i);let a=h.ZERO;if(e===ml)return a;if(this.is0()||e===hl)return this;if(!r||v.hasPrecomputes(this))return v.wNAFCachedUnsafe(this,e,h.normalizeZ);let{k1neg:o,k1:s,k2neg:c,k2:l}=r.splitScalar(e),u=a,d=a,f=this;for(;s>ml||l>ml;)s&hl&&(u=u.add(f)),l&hl&&(d=d.add(f)),f=f.double(),s>>=hl,l>>=hl;return o&&(u=u.negate()),c&&(d=d.negate()),d=new h(n.mul(d.px,r.beta),d.py,d.pz),u.add(d)}multiply(e){let{endo:r,n:i}=t;nc(`scalar`,e,hl,i);let a,o;if(r){let{k1neg:t,k1:i,k2neg:s,k2:c}=r.splitScalar(e),{p:l,f:u}=this.wNAF(i),{p:d,f}=this.wNAF(c);l=v.constTimeNegate(t,l),d=v.constTimeNegate(s,d),d=new h(n.mul(d.px,r.beta),d.py,d.pz),a=l.add(d),o=u.add(f)}else{let{p:t,f:n}=this.wNAF(e);a=t,o=n}return h.normalizeZ([a,o])[0]}multiplyAndAddUnsafe(e,t,n){let r=h.BASE,i=(e,t)=>t===ml||t===hl||!e.equals(r)?e.multiplyUnsafe(t):e.multiply(t),a=i(this,t).add(i(e,n));return a.is0()?void 0:a}toAffine(e){return p(this,e)}isTorsionFree(){let{h:e,isTorsionFree:n}=t;if(e===hl)return!0;if(n)return n(h,this);throw Error(`isTorsionFree() has not been declared for the elliptic curve`)}clearCofactor(){let{h:e,clearCofactor:n}=t;return e===hl?this:n?n(h,this):this.multiplyUnsafe(t.h)}toRawBytes(e=!0){return Hs(`isCompressed`,e),this.assertValidity(),i(h,this,e)}toHex(e=!0){return Hs(`isCompressed`,e),Gs(this.toRawBytes(e))}}h.BASE=new h(t.Gx,t.Gy,n.ONE),h.ZERO=new h(n.ZERO,n.ONE,n.ZERO);let{endo:g,nBitLength:_}=t,v=Xc(h,g?Math.ceil(_/2):_);return{CURVE:t,ProjectivePoint:h,normPrivateKeyToScalar:d,weierstrassEquation:o,isWithinCurveOrder:u}}function cl(e){let t=Qc(e);return ac(t,{hash:`hash`,hmac:`function`,randomBytes:`function`},{bits2int:`function`,bits2int_modN:`function`,lowS:`boolean`}),Object.freeze({lowS:!0,...t})}function ll(e){let t=cl(e),{Fp:n,n:r,nByteLength:i,nBitLength:a}=t,o=n.BYTES+1,s=2*n.BYTES+1;function c(e){return vc(e,r)}function l(e){return bc(e,r)}let{ProjectivePoint:u,normPrivateKeyToScalar:d,weierstrassEquation:f,isWithinCurveOrder:p}=sl({...t,toBytes(e,t,r){let i=t.toAffine(),a=n.toBytes(i.x),o=$s;return Hs(`isCompressed`,r),r?o(Uint8Array.from([t.hasEvenY()?2:3]),a):o(Uint8Array.from([4]),a,n.toBytes(i.y))},fromBytes(e){let t=e.length,r=e[0],i=e.subarray(1);if(t===o&&(r===2||r===3)){let e=Js(i);if(!tc(e,hl,n.ORDER))throw Error(`Point is not on curve`);let t=f(e),a;try{a=n.sqrt(t)}catch(e){let t=e instanceof Error?`: `+e.message:``;throw Error(`Point is not on curve`+t)}let o=(a&hl)===hl;return(r&1)==1!==o&&(a=n.neg(a)),{x:e,y:a}}else if(t===s&&r===4){let e=n.fromBytes(i.subarray(0,n.BYTES)),t=n.fromBytes(i.subarray(n.BYTES,2*n.BYTES));return{x:e,y:t}}else{let e=o,n=s;throw Error(`invalid Point, expected length of `+e+`, or uncompressed `+n+`, got `+t)}}});function m(e){let t=r>>hl;return e>t}function h(e){return m(e)?c(-e):e}let g=(e,t,n)=>Js(e.slice(t,n));class _{constructor(e,t,n){nc(`r`,e,hl,r),nc(`s`,t,hl,r),this.r=e,this.s=t,n!=null&&(this.recovery=n),Object.freeze(this)}static fromCompact(e){let t=i;return e=Qs(`compactSignature`,e,t*2),new _(g(e,0,t),g(e,t,2*t))}static fromDER(e){let{r:t,s:n}=pl.toSig(Qs(`DER`,e));return new _(t,n)}assertValidity(){}addRecoveryBit(e){return new _(this.r,this.s,e)}recoverPublicKey(e){let{r,s:i,recovery:a}=this,o=C(Qs(`msgHash`,e));if(a==null||![0,1,2,3].includes(a))throw Error(`recovery id invalid`);let s=a===2||a===3?r+t.n:r;if(s>=n.ORDER)throw Error(`recovery id 2 or 3 invalid`);let d=a&1?`03`:`02`,f=u.fromHex(d+ol(s,n.BYTES)),p=l(s),m=c(-o*p),h=c(i*p),g=u.BASE.multiplyAndAddUnsafe(f,m,h);if(!g)throw Error(`point at infinify`);return g.assertValidity(),g}hasHighS(){return m(this.s)}normalizeS(){return this.hasHighS()?new _(this.r,c(-this.s),this.recovery):this}toDERRawBytes(){return qs(this.toDERHex())}toDERHex(){return pl.hexFromSig(this)}toCompactRawBytes(){return qs(this.toCompactHex())}toCompactHex(){let e=i;return ol(this.r,e)+ol(this.s,e)}}let v={isValidPrivateKey(e){try{return d(e),!0}catch{return!1}},normPrivateKeyToScalar:d,randomPrivateKey:()=>{let e=Mc(t.n);return Nc(t.randomBytes(e),t.n)},precompute(e=8,t=u.BASE){return t._setWindowSize(e),t.multiply(BigInt(3)),t}};function y(e,t=!0){return u.fromPrivateKey(e).toRawBytes(t)}function b(e){if(typeof e==`bigint`)return!1;if(e instanceof u)return!0;let r=Qs(`key`,e).length,a=n.BYTES,o=a+1,s=2*a+1;if(!(t.allowedPrivateKeyLengths||i===o))return r===o||r===s}function x(e,t,n=!0){if(b(e)===!0)throw Error(`first arg must be private key`);if(b(t)===!1)throw Error(`second arg must be public key`);return u.fromHex(t).multiply(d(e)).toRawBytes(n)}let S=t.bits2int||function(e){if(e.length>8192)throw Error(`input is too large`);let t=Js(e),n=e.length*8-a;return n>0?t>>BigInt(n):t},C=t.bits2int_modN||function(e){return c(S(e))},w=pc(a);function ee(e){return nc(`num < 2^`+a,e,ml,w),Xs(e,i)}function te(e,r,i=ne){if([`recovered`,`canonical`].some(e=>e in i))throw Error(`sign() legacy options not supported`);let{hash:a,randomBytes:o}=t,{lowS:s,prehash:f,extraEntropy:g}=i;s??=!0,e=Qs(`msgHash`,e),il(i),f&&(e=Qs(`prehashed msgHash`,a(e)));let v=C(e),y=d(r),b=[ee(y),ee(v)];if(g!=null&&g!==!1){let e=g===!0?o(n.BYTES):g;b.push(Qs(`extraEntropy`,e))}let x=$s(...b),w=v;function te(e){let t=S(e);if(!p(t))return;let n=l(t),r=u.BASE.multiply(t).toAffine(),i=c(r.x);if(i===ml)return;let a=c(n*c(w+i*y));if(a===ml)return;let o=(r.x===i?0:2)|Number(r.y&hl),d=a;return s&&m(a)&&(d=h(a),o^=1),new _(i,d,o)}return{seed:x,k2sig:te}}let ne={lowS:t.lowS,prehash:!1},re={lowS:t.lowS,prehash:!1};function ie(e,n,r=ne){let{seed:i,k2sig:a}=te(e,n,r),o=t;return ic(o.hash.outputLen,o.nByteLength,o.hmac)(i,a)}u.BASE._setWindowSize(8);function ae(e,n,r,i=re){let a=e;n=Qs(`msgHash`,n),r=Qs(`publicKey`,r);let{lowS:o,prehash:s,format:d}=i;if(il(i),`strict`in i)throw Error(`options.strict was renamed to lowS`);if(d!==void 0&&d!==`compact`&&d!==`der`)throw Error(`format must be compact or der`);let f=typeof a==`string`||Bs(a),p=!f&&!d&&typeof a==`object`&&!!a&&typeof a.r==`bigint`&&typeof a.s==`bigint`;if(!f&&!p)throw Error(`invalid signature, expected Uint8Array, hex string or Signature instance`);let m,h;try{if(p&&(m=new _(a.r,a.s)),f){try{d!==`compact`&&(m=_.fromDER(a))}catch(e){if(!(e instanceof pl.Err))throw e}!m&&d!==`der`&&(m=_.fromCompact(a))}h=u.fromHex(r)}catch{return!1}if(!m||o&&m.hasHighS())return!1;s&&(n=t.hash(n));let{r:g,s:v}=m,y=C(n),b=l(v),x=c(y*b),S=c(g*b),w=u.BASE.multiplyAndAddUnsafe(h,x,S)?.toAffine();return w?c(w.x)===g:!1}return{CURVE:t,getPublicKey:y,getSharedSecret:x,sign:ie,verify:ae,ProjectivePoint:u,Signature:_,utils:v}}function ul(e,t){let n=e.ORDER,r=ml;for(let e=n-hl;e%gl===ml;e/=gl)r+=hl;let i=r,a=gl<<i-hl-hl,o=a*gl,s=(n-hl)/o,c=(s-hl)/gl,l=o-hl,u=a,d=e.pow(t,s),f=e.pow(t,(s+hl)/gl),p=(t,n)=>{let r=d,a=e.pow(n,l),o=e.sqr(a);o=e.mul(o,n);let s=e.mul(t,o);s=e.pow(s,c),s=e.mul(s,a),a=e.mul(s,n),o=e.mul(s,t);let p=e.mul(o,a);s=e.pow(p,u);let m=e.eql(s,e.ONE);a=e.mul(o,f),s=e.mul(p,r),o=e.cmov(a,o,m),p=e.cmov(s,p,m);for(let t=i;t>hl;t--){let n=t-gl;n=gl<<n-hl;let i=e.pow(p,n),s=e.eql(i,e.ONE);a=e.mul(o,r),r=e.mul(r,r),i=e.mul(p,r),o=e.cmov(a,o,s),p=e.cmov(i,p,s)}return{isValid:m,value:o}};if(e.ORDER%vl===_l){let n=(e.ORDER-_l)/vl,r=e.sqrt(e.neg(t));p=(t,i)=>{let a=e.sqr(i),o=e.mul(t,i);a=e.mul(a,o);let s=e.pow(a,n);s=e.mul(s,o);let c=e.mul(s,r),l=e.mul(e.sqr(s),i),u=e.eql(l,t),d=e.cmov(c,s,u);return{isValid:u,value:d}}}return p}function dl(e,t){if(Tc(e),!e.isValid(t.A)||!e.isValid(t.B)||!e.isValid(t.Z))throw Error(`mapToCurveSimpleSWU: invalid opts`);let n=ul(e,t.Z);if(!e.isOdd)throw Error(`Fp.isOdd is not implemented!`);return r=>{let i,a,o,s,c,l,u,d;i=e.sqr(r),i=e.mul(i,t.Z),a=e.sqr(i),a=e.add(a,i),o=e.add(a,e.ONE),o=e.mul(o,t.B),s=e.cmov(t.Z,e.neg(a),!e.eql(a,e.ZERO)),s=e.mul(s,t.A),a=e.sqr(o),l=e.sqr(s),c=e.mul(l,t.A),a=e.add(a,c),a=e.mul(a,o),l=e.mul(l,s),c=e.mul(l,t.B),a=e.add(a,c),u=e.mul(i,o);let{isValid:f,value:p}=n(a,l);d=e.mul(i,r),d=e.mul(d,p),u=e.cmov(u,o,f),d=e.cmov(d,p,f);let m=e.isOdd(r)===e.isOdd(d);d=e.cmov(e.neg(d),d,m);let h=Dc(e,[s],!0)[0];return u=e.mul(u,h),{x:u,y:d}}}var fl,pl,ml,hl,gl,_l,vl,yl=o((()=>{rl(),Hc(),_c(),fl=class extends Error{constructor(e=``){super(e)}},pl={Err:fl,_tlv:{encode:(e,t)=>{let{Err:n}=pl;if(e<0||e>256)throw new n(`tlv.encode: wrong tag`);if(t.length&1)throw new n(`tlv.encode: unpadded data`);let r=t.length/2,i=Us(r);if(i.length/2&128)throw new n(`tlv.encode: long form length too big`);let a=r>127?Us(i.length/2|128):``;return Us(e)+a+i+t},decode(e,t){let{Err:n}=pl,r=0;if(e<0||e>256)throw new n(`tlv.encode: wrong tag`);if(t.length<2||t[r++]!==e)throw new n(`tlv.decode: wrong tlv`);let i=t[r++],a=!!(i&128),o=0;if(!a)o=i;else{let e=i&127;if(!e)throw new n(`tlv.decode(long): indefinite length not supported`);if(e>4)throw new n(`tlv.decode(long): byte length is too big`);let a=t.subarray(r,r+e);if(a.length!==e)throw new n(`tlv.decode: length bytes not complete`);if(a[0]===0)throw new n(`tlv.decode(long): zero leftmost byte`);for(let e of a)o=o<<8|e;if(r+=e,o<128)throw new n(`tlv.decode(long): not minimal encoding`)}let s=t.subarray(r,r+o);if(s.length!==o)throw new n(`tlv.decode: wrong value length`);return{v:s,l:t.subarray(r+o)}}},_int:{encode(e){let{Err:t}=pl;if(e<ml)throw new t(`integer: negative integers are not allowed`);let n=Us(e);if(Number.parseInt(n[0],16)&8&&(n=`00`+n),n.length&1)throw new t(`unexpected DER parsing assertion: unpadded hex`);return n},decode(e){let{Err:t}=pl;if(e[0]&128)throw new t(`invalid signature integer: negative`);if(e[0]===0&&!(e[1]&128))throw new t(`invalid signature integer: unnecessary leading zero`);return Js(e)}},toSig(e){let{Err:t,_int:n,_tlv:r}=pl,i=Qs(`signature`,e),{v:a,l:o}=r.decode(48,i);if(o.length)throw new t(`invalid signature: left bytes after parsing`);let{v:s,l:c}=r.decode(2,a),{v:l,l:u}=r.decode(2,c);if(u.length)throw new t(`invalid signature: left bytes after parsing`);return{r:n.decode(s),s:n.decode(l)}},hexFromSig(e){let{_tlv:t,_int:n}=pl,r=t.encode(2,n.encode(e.r)),i=t.encode(2,n.encode(e.s)),a=r+i;return t.encode(48,a)}},ml=BigInt(0),hl=BigInt(1),gl=BigInt(2),_l=BigInt(3),vl=BigInt(4)}));function bl(e){return{hash:e,hmac:(t,...n)=>Rs(e,t,Dr(...n)),randomBytes:kr}}function xl(e,t){let n=t=>ll({...e,...bl(t)});return{...n(t),create:n}}var Sl=o((()=>{zs(),Nr(),yl()}));function Cl(e,t){if(Tl(e),Tl(t),e<0||e>=1<<8*t)throw Error(`invalid I2OSP input: `+e);let n=Array.from({length:t}).fill(0);for(let r=t-1;r>=0;r--)n[r]=e&255,e>>>=8;return new Uint8Array(n)}function wl(e,t){let n=new Uint8Array(e.length);for(let r=0;r<e.length;r++)n[r]=e[r]^t[r];return n}function Tl(e){if(!Number.isSafeInteger(e))throw Error(`number expected`)}function El(e,t,n,r){Vs(e),Vs(t),Tl(n),t.length>255&&(t=r($s(ec(`H2C-OVERSIZE-DST-`),t)));let{outputLen:i,blockLen:a}=r,o=Math.ceil(n/i);if(n>65535||o>255)throw Error(`expand_message_xmd: invalid lenInBytes`);let s=$s(t,Cl(t.length,1)),c=Cl(0,a),l=Cl(n,2),u=Array(o),d=r($s(c,e,l,Cl(0,1),s));u[0]=r($s(d,Cl(1,1),s));for(let e=1;e<=o;e++){let t=[wl(d,u[e-1]),Cl(e+1,1),s];u[e]=r($s(...t))}return $s(...u).slice(0,n)}function Dl(e,t,n,r,i){if(Vs(e),Vs(t),Tl(n),t.length>255){let e=Math.ceil(2*r/8);t=i.create({dkLen:e}).update(ec(`H2C-OVERSIZE-DST-`)).update(t).digest()}if(n>65535||t.length>255)throw Error(`expand_message_xof: invalid lenInBytes`);return i.create({dkLen:n}).update(e).update(Cl(n,2)).update(t).update(Cl(t.length,1)).digest()}function Ol(e,t,n){ac(n,{DST:`stringOrUint8Array`,p:`bigint`,m:`isSafeInteger`,k:`isSafeInteger`,hash:`hash`});let{p:r,k:i,m:a,hash:o,expand:s,DST:c}=n;Vs(e),Tl(t);let l=typeof c==`string`?ec(c):c,u=r.toString(2).length,d=Math.ceil((u+i)/8),f=t*a*d,p;if(s===`xmd`)p=El(e,l,f,o);else if(s===`xof`)p=Dl(e,l,f,i,o);else if(s===`_internal_pass`)p=e;else throw Error(`expand must be \"xmd\" or \"xof\"`);let m=Array(t);for(let e=0;e<t;e++){let t=Array(a);for(let n=0;n<a;n++){let i=d*(n+e*a),o=p.subarray(i,i+d);t[n]=vc(jl(o),r)}m[e]=t}return m}function kl(e,t){let n=t.map(e=>Array.from(e).reverse());return(t,r)=>{let[i,a,o,s]=n.map(n=>n.reduce((n,r)=>e.add(e.mul(n,t),r))),[c,l]=Dc(e,[a,s],!0);return t=e.mul(i,c),r=e.mul(r,e.mul(o,l)),{x:t,y:r}}}function Al(e,t,n){if(typeof t!=`function`)throw Error(`mapToCurve() must be defined`);function r(n){return e.fromAffine(t(n))}function i(t){let n=t.clearCofactor();return n.equals(e.ZERO)?e.ZERO:(n.assertValidity(),n)}return{defaults:n,hashToCurve(e,t){let a=Ol(e,2,{...n,DST:n.DST,...t}),o=r(a[0]),s=r(a[1]);return i(o.add(s))},encodeToCurve(e,t){let a=Ol(e,1,{...n,DST:n.encodeDST,...t});return i(r(a[0]))},mapToCurve(e){if(!Array.isArray(e))throw Error(`expected array of bigints`);for(let t of e)if(typeof t!=`bigint`)throw Error(`expected array of bigints`);return i(r(e))}}}var jl,Ml=o((()=>{Hc(),_c(),jl=Js})),Nl=c({encodeToCurve:()=>lu,hashToCurve:()=>cu,schnorr:()=>iu,secp256k1:()=>Yl,secp256k1_hasher:()=>su});function Pl(e){let t=Hl,n=BigInt(3),r=BigInt(6),i=BigInt(11),a=BigInt(22),o=BigInt(23),s=BigInt(44),c=BigInt(88),l=e*e*e%t,u=l*l*e%t,d=yc(u,n,t)*u%t,f=yc(d,n,t)*u%t,p=yc(f,Kl,t)*l%t,m=yc(p,i,t)*p%t,h=yc(m,a,t)*m%t,g=yc(h,s,t)*h%t,_=yc(g,c,t)*g%t,v=yc(_,s,t)*h%t,y=yc(v,n,t)*u%t,b=yc(y,o,t)*m%t,x=yc(b,r,t)*l%t,S=yc(x,Kl,t);if(!Jl.eql(Jl.sqr(S),e))throw Error(`Cannot find square root`);return S}function Fl(e,...t){let n=Xl[e];if(n===void 0){let t=Ns(Uint8Array.from(e,e=>e.charCodeAt(0)));n=$s(t,t),Xl[e]=n}return Ns($s(n,...t))}function Il(e){let t=Yl.utils.normPrivateKeyToScalar(e),n=tu.fromPrivateKey(t);return{scalar:n.hasEvenY()?t:eu(-t),bytes:Zl(n)}}function Ll(e){nc(`x`,e,Gl,Hl);let t=$l(e*e),n=$l(t*e+BigInt(7)),r=Pl(n);r%Kl!==Wl&&(r=$l(-r));let i=new tu(e,r,Gl);return i.assertValidity(),i}function Rl(...e){return eu(ru(Fl(`BIP0340/challenge`,...e)))}function zl(e){return Il(e).bytes}function Bl(e,t,n=kr(32)){let r=Qs(`message`,e),{bytes:i,scalar:a}=Il(t),o=Qs(`auxRand`,n,32),s=Ql(a^ru(Fl(`BIP0340/aux`,o))),c=Fl(`BIP0340/nonce`,s,i,r),l=eu(ru(c));if(l===Wl)throw Error(`sign failed: k is zero`);let{bytes:u,scalar:d}=Il(l),f=Rl(u,i,r),p=new Uint8Array(64);if(p.set(u,0),p.set(Ql(eu(d+f*a)),32),!Vl(p,r,i))throw Error(`sign: Invalid signature produced`);return p}function Vl(e,t,n){let r=Qs(`signature`,e,64),i=Qs(`message`,t),a=Qs(`publicKey`,n,32);try{let e=Ll(ru(a)),t=ru(r.subarray(0,32));if(!tc(t,Gl,Hl))return!1;let n=ru(r.subarray(32,64));if(!tc(n,Gl,Ul))return!1;let o=Rl(Ql(t),Zl(e),i),s=nu(e,n,eu(-o));return!(!s||!s.hasEvenY()||s.toAffine().x!==t)}catch{return!1}}var Hl,Ul,Wl,Gl,Kl,ql,Jl,Yl,Xl,Zl,Ql,$l,eu,tu,nu,ru,iu,au,ou,su,cu,lu,uu=o((()=>{Is(),Nr(),Sl(),Ml(),Hc(),_c(),yl(),Hl=BigInt(`0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f`),Ul=BigInt(`0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141`),Wl=BigInt(0),Gl=BigInt(1),Kl=BigInt(2),ql=(e,t)=>(e+t/Kl)/t,Jl=Ac(Hl,void 0,void 0,{sqrt:Pl}),Yl=xl({a:Wl,b:BigInt(7),Fp:Jl,n:Ul,Gx:BigInt(`55066263022277343669578718895168534326250603453777594175500187360389116729240`),Gy:BigInt(`32670510020758816978083085130507043184471273380659243275938904335757337482424`),h:BigInt(1),lowS:!0,endo:{beta:BigInt(`0x7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee`),splitScalar:e=>{let t=Ul,n=BigInt(`0x3086d221a7d46bcde86c90e49284eb15`),r=-Gl*BigInt(`0xe4437ed6010e88286f547fa90abfe4c3`),i=BigInt(`0x114ca50f7a8e2f3f657c1108d9d44cfd8`),a=n,o=BigInt(`0x100000000000000000000000000000000`),s=ql(a*e,t),c=ql(-r*e,t),l=vc(e-s*n-c*i,t),u=vc(-s*r-c*a,t),d=l>o,f=u>o;if(d&&(l=t-l),f&&(u=t-u),l>o||u>o)throw Error(`splitScalar: Endomorphism failed, k=`+e);return{k1neg:d,k1:l,k2neg:f,k2:u}}}},Ns),Xl={},Zl=e=>e.toRawBytes(!0).slice(1),Ql=e=>Xs(e,32),$l=e=>vc(e,Hl),eu=e=>vc(e,Ul),tu=(()=>Yl.ProjectivePoint)(),nu=(e,t,n)=>tu.BASE.multiplyAndAddUnsafe(e,t,n),ru=Js,iu=(()=>({getPublicKey:zl,sign:Bl,verify:Vl,utils:{randomPrivateKey:Yl.utils.randomPrivateKey,lift_x:Ll,pointToBytes:Zl,numberToBytesBE:Xs,bytesToNumberBE:Js,taggedHash:Fl,mod:vc}}))(),au=(()=>kl(Jl,[[`0x8e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38daaaaa8c7`,`0x7d3d4c80bc321d5b9f315cea7fd44c5d595d2fc0bf63b92dfff1044f17c6581`,`0x534c328d23f234e6e2a413deca25caece4506144037c40314ecbd0b53d9dd262`,`0x8e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38e38daaaaa88c`],[`0xd35771193d94918a9ca34ccbb7b640dd86cd409542f8487d9fe6b745781eb49b`,`0xedadc6f64383dc1df7c4b2d51b54225406d36b641f5e41bbc52a56612a8c6d14`,`0x0000000000000000000000000000000000000000000000000000000000000001`],[`0x4bda12f684bda12f684bda12f684bda12f684bda12f684bda12f684b8e38e23c`,`0xc75e0c32d5cb7c0fa9d0a54b12a0a6d5647ab046d686da6fdffc90fc201d71a3`,`0x29a6194691f91a73715209ef6512e576722830a201be2018a765e85a9ecee931`,`0x2f684bda12f684bda12f684bda12f684bda12f684bda12f684bda12f38e38d84`],[`0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffff93b`,`0x7a06534bb8bdb49fd5e9e6632722c2989467c1bfc8e8d978dfb425d2685c2573`,`0x6484aa716545ca2cf3a70c3fa8fe337e0a3d21162f0d6299a7bf8192bfd2a76f`,`0x0000000000000000000000000000000000000000000000000000000000000001`]].map(e=>e.map(e=>BigInt(e)))))(),ou=(()=>dl(Jl,{A:BigInt(`0x3f8731abdd661adca08a5558f0f5d272e953d363cb6f0e5d405447c01a444533`),B:BigInt(`1771`),Z:Jl.create(BigInt(`-11`))}))(),su=(()=>Al(Yl.ProjectivePoint,e=>{let{x:t,y:n}=ou(Jl.create(e[0]));return au(t,n)},{DST:`secp256k1_XMD:SHA-256_SSWU_RO_`,encodeDST:`secp256k1_XMD:SHA-256_SSWU_NU_`,p:Jl.ORDER,m:1,k:128,expand:`xmd`,hash:Ns}))(),cu=(()=>su.hashToCurve)(),lu=(()=>su.encodeToCurve)()}));Pt(),It(),Dn(),A(),ms();async function du({hash:e,signature:t}){let n=Nt(e)?e:On(e),{secp256k1:r}=await ps(async()=>{let{secp256k1:e}=await Promise.resolve().then(()=>(uu(),Nl));return{secp256k1:e}},void 0);return`0x${(()=>{if(typeof t==`object`&&`r`in t&&`s`in t){let{r:e,s:n,v:i,yParity:a}=t,o=fu(Number(a??i));return new r.Signature(wn(e),wn(n)).addRecoveryBit(o)}let e=Nt(t)?t:On(t);if(Ft(e)!==65)throw Error(`invalid signature length`);let n=En(`0x${e.slice(130)}`),i=fu(n);return r.Signature.fromCompact(e.substring(2,130)).addRecoveryBit(i)})().recoverPublicKey(n.substring(2)).toHex(!1)}`}function fu(e){if(e===0||e===1)return e;if(e===27)return 0;if(e===28)return 1;throw Error(`Invalid yParityOrV value`)}async function pu({hash:e,signature:t}){return ls(await du({hash:e,signature:t}))}O(),ya(),Hn(),A();function M(e,t=`hex`){let n=N(e),r=_a(new Uint8Array(n.length));return n.encode(r),t===`hex`?An(r.bytes):r.bytes}function N(e){return Array.isArray(e)?mu(e.map(e=>N(e))):hu(e)}function mu(e){let t=e.reduce((e,t)=>e+t.length,0),n=gu(t);return{length:(()=>t<=55?1+t:1+n+t)(),encode(r){t<=55?r.pushByte(192+t):(r.pushByte(247+n),n===1?r.pushUint8(t):n===2?r.pushUint16(t):n===3?r.pushUint24(t):r.pushUint32(t));for(let{encode:t}of e)t(r)}}}function hu(e){let t=typeof e==`string`?Ln(e):e,n=gu(t.length);return{length:(()=>t.length===1&&t[0]<128?1:t.length<=55?1+t.length:1+n+t.length)(),encode(e){t.length===1&&t[0]<128?e.pushBytes(t):t.length<=55?(e.pushByte(128+t.length),e.pushBytes(t)):(e.pushByte(183+n),n===1?e.pushUint8(t.length):n===2?e.pushUint16(t.length):n===3?e.pushUint24(t.length):e.pushUint32(t.length),e.pushBytes(t))}}}function gu(e){if(e<2**8)return 1;if(e<2**16)return 2;if(e<2**24)return 3;if(e<2**32)return 4;throw new D(`Length is too large.`)}Di(),Hn(),A(),ei();function _u(e){let{chainId:t,nonce:n,to:r}=e,i=e.contractAddress??e.address,a=$r(Ei([`0x05`,M([t?k(t):`0x`,i,n?k(n):`0x`])]));return r===`bytes`?Ln(a):a}async function vu(e){let{authorization:t,signature:n}=e;return pu({hash:_u(t),signature:n??t})}Xa(),Qa(),O(),ho();var yu=class extends D{constructor(e,{account:t,docsPath:n,chain:r,data:i,gas:a,gasPrice:o,maxFeePerGas:s,maxPriorityFeePerGas:c,nonce:l,to:u,value:d}){let f=io({from:t?.address,to:u,value:d!==void 0&&`${Ya(d)} ${r?.nativeCurrency?.symbol||`ETH`}`,data:i,gas:a,gasPrice:o!==void 0&&`${Za(o)} gwei`,maxFeePerGas:s!==void 0&&`${Za(s)} gwei`,maxPriorityFeePerGas:c!==void 0&&`${Za(c)} gwei`,nonce:l});super(e.shortMessage,{cause:e,docsPath:n,metaMessages:[...e.metaMessages?[...e.metaMessages,` `]:[],`Estimate Gas Arguments:`,f].filter(Boolean),name:`EstimateGasExecutionError`}),Object.defineProperty(this,`cause`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.cause=e}},bu,xu,Su,Cu,wu,Tu,Eu,Du,Ou,ku,Au,ju,Mu=o((()=>{Qa(),O(),bu=class extends D{constructor({cause:e,message:t}={}){let n=t?.replace(`execution reverted: `,``)?.replace(`execution reverted`,``);super(`Execution reverted ${n?`with reason: ${n}`:`for an unknown reason`}.`,{cause:e,name:`ExecutionRevertedError`})}},Object.defineProperty(bu,`code`,{enumerable:!0,configurable:!0,writable:!0,value:3}),Object.defineProperty(bu,`nodeMessage`,{enumerable:!0,configurable:!0,writable:!0,value:/execution reverted/}),xu=class extends D{constructor({cause:e,maxFeePerGas:t}={}){super(`The fee cap (\\`maxFeePerGas\\`${t?` = ${Za(t)} gwei`:``}) cannot be higher than the maximum allowed value (2^256-1).`,{cause:e,name:`FeeCapTooHighError`})}},Object.defineProperty(xu,`nodeMessage`,{enumerable:!0,configurable:!0,writable:!0,value:/max fee per gas higher than 2\\^256-1|fee cap higher than 2\\^256-1/}),Su=class extends D{constructor({cause:e,maxFeePerGas:t}={}){super(`The fee cap (\\`maxFeePerGas\\`${t?` = ${Za(t)}`:``} gwei) cannot be lower than the block base fee.`,{cause:e,name:`FeeCapTooLowError`})}},Object.defineProperty(Su,`nodeMessage`,{enumerable:!0,configurable:!0,writable:!0,value:/max fee per gas less than block base fee|fee cap less than block base fee|transaction is outdated/}),Cu=class extends D{constructor({cause:e,nonce:t}={}){super(`Nonce provided for the transaction ${t?`(${t}) `:``}is higher than the next one expected.`,{cause:e,name:`NonceTooHighError`})}},Object.defineProperty(Cu,`nodeMessage`,{enumerable:!0,configurable:!0,writable:!0,value:/nonce too high/}),wu=class extends D{constructor({cause:e,nonce:t}={}){super([`Nonce provided for the transaction ${t?`(${t}) `:``}is lower than the current nonce of the account.`,\"Try increasing the nonce or find the latest nonce with `getTransactionCount`.\"].join(`\n`),{cause:e,name:`NonceTooLowError`})}},Object.defineProperty(wu,`nodeMessage`,{enumerable:!0,configurable:!0,writable:!0,value:/nonce too low|transaction already imported|already known/}),Tu=class extends D{constructor({cause:e,nonce:t}={}){super(`Nonce provided for the transaction ${t?`(${t}) `:``}exceeds the maximum allowed nonce.`,{cause:e,name:`NonceMaxValueError`})}},Object.defineProperty(Tu,`nodeMessage`,{enumerable:!0,configurable:!0,writable:!0,value:/nonce has max value/}),Eu=class extends D{constructor({cause:e}={}){super([`The total cost (gas * gas fee + value) of executing this transaction exceeds the balance of the account.`].join(`\n`),{cause:e,metaMessages:[`This error could arise when the account does not have enough funds to:`,` - pay for the total gas fee,`,` - pay for the value to send.`,` `,\"The cost of the transaction is calculated as `gas * gas fee + value`, where:\",\" - `gas` is the amount of gas needed for transaction to execute,\",\" - `gas fee` is the gas fee,\",\" - `value` is the amount of ether to send to the recipient.\"],name:`InsufficientFundsError`})}},Object.defineProperty(Eu,`nodeMessage`,{enumerable:!0,configurable:!0,writable:!0,value:/insufficient funds|exceeds transaction sender account balance/}),Du=class extends D{constructor({cause:e,gas:t}={}){super(`The amount of gas ${t?`(${t}) `:``}provided for the transaction exceeds the limit allowed for the block.`,{cause:e,name:`IntrinsicGasTooHighError`})}},Object.defineProperty(Du,`nodeMessage`,{enumerable:!0,configurable:!0,writable:!0,value:/intrinsic gas too high|gas limit reached/}),Ou=class extends D{constructor({cause:e,gas:t}={}){super(`The amount of gas ${t?`(${t}) `:``}provided for the transaction is too low.`,{cause:e,name:`IntrinsicGasTooLowError`})}},Object.defineProperty(Ou,`nodeMessage`,{enumerable:!0,configurable:!0,writable:!0,value:/intrinsic gas too low/}),ku=class extends D{constructor({cause:e}){super(`The transaction type is not supported for this chain.`,{cause:e,name:`TransactionTypeNotSupportedError`})}},Object.defineProperty(ku,`nodeMessage`,{enumerable:!0,configurable:!0,writable:!0,value:/transaction type not valid/}),Au=class extends D{constructor({cause:e,maxPriorityFeePerGas:t,maxFeePerGas:n}={}){super([`The provided tip (\\`maxPriorityFeePerGas\\`${t?` = ${Za(t)} gwei`:``}) cannot be higher than the fee cap (\\`maxFeePerGas\\`${n?` = ${Za(n)} gwei`:``}).`].join(`\n`),{cause:e,name:`TipAboveFeeCapError`})}},Object.defineProperty(Au,`nodeMessage`,{enumerable:!0,configurable:!0,writable:!0,value:/max priority fee per gas higher than max fee per gas|tip higher than fee cap/}),ju=class extends D{constructor({cause:e}){super(`An error occurred while executing: ${e?.shortMessage}`,{cause:e,name:`UnknownNodeError`})}}}));function Nu(e,t){let n=(e.details||``).toLowerCase(),r=e instanceof D?e.walk(e=>e?.code===bu.code):e;return r instanceof D?new bu({cause:e,message:r.details}):bu.nodeMessage.test(n)?new bu({cause:e,message:e.details}):xu.nodeMessage.test(n)?new xu({cause:e,maxFeePerGas:t?.maxFeePerGas}):Su.nodeMessage.test(n)?new Su({cause:e,maxFeePerGas:t?.maxFeePerGas}):Cu.nodeMessage.test(n)?new Cu({cause:e,nonce:t?.nonce}):wu.nodeMessage.test(n)?new wu({cause:e,nonce:t?.nonce}):Tu.nodeMessage.test(n)?new Tu({cause:e,nonce:t?.nonce}):Eu.nodeMessage.test(n)?new Eu({cause:e}):Du.nodeMessage.test(n)?new Du({cause:e,gas:t?.gas}):Ou.nodeMessage.test(n)?new Ou({cause:e,gas:t?.gas}):ku.nodeMessage.test(n)?new ku({cause:e}):Au.nodeMessage.test(n)?new Au({cause:e,maxFeePerGas:t?.maxFeePerGas,maxPriorityFeePerGas:t?.maxPriorityFeePerGas}):new ju({cause:e})}var Pu=o((()=>{O(),Mu()}));Mu(),Pu();function Fu(e,{docsPath:t,...n}){let r=(()=>{let t=Nu(e,n);return t instanceof ju?e:t})();return new yu(r,{docsPath:t,...n})}function Iu(e,{format:t}){if(!t)return{};let n={};function r(t){let i=Object.keys(t);for(let a of i)a in e&&(n[a]=e[a]),t[a]&&typeof t[a]==`object`&&!Array.isArray(t[a])&&r(t[a])}let i=t(e||{});return r(i),n}var Lu=o((()=>{}));function Ru(e,t){return({exclude:n,format:r})=>({exclude:n,format:(e,i)=>{let a=t(e,i);if(n)for(let e of n)delete a[e];return{...a,...r(e,i)}},type:e})}var zu=o((()=>{}));function Bu(e,t){let n={};return e.authorizationList!==void 0&&(n.authorizationList=Vu(e.authorizationList)),e.accessList!==void 0&&(n.accessList=e.accessList),e.blobVersionedHashes!==void 0&&(n.blobVersionedHashes=e.blobVersionedHashes),e.blobs!==void 0&&(typeof e.blobs[0]==`string`?n.blobs=e.blobs:n.blobs=e.blobs.map(e=>An(e))),e.data!==void 0&&(n.data=e.data),e.from!==void 0&&(n.from=e.from),e.gas!==void 0&&(n.gas=k(e.gas)),e.gasPrice!==void 0&&(n.gasPrice=k(e.gasPrice)),e.maxFeePerBlobGas!==void 0&&(n.maxFeePerBlobGas=k(e.maxFeePerBlobGas)),e.maxFeePerGas!==void 0&&(n.maxFeePerGas=k(e.maxFeePerGas)),e.maxPriorityFeePerGas!==void 0&&(n.maxPriorityFeePerGas=k(e.maxPriorityFeePerGas)),e.nonce!==void 0&&(n.nonce=k(e.nonce)),e.to!==void 0&&(n.to=e.to),e.type!==void 0&&(n.type=Hu[e.type]),e.value!==void 0&&(n.value=k(e.value)),n}function Vu(e){return e.map(e=>({address:e.address,r:e.r?k(BigInt(e.r)):e.r,s:e.s?k(BigInt(e.s)):e.s,chainId:k(e.chainId),nonce:k(e.nonce),...e.yParity===void 0?{}:{yParity:k(e.yParity)},...e.v!==void 0&&e.yParity===void 0?{v:k(e.v)}:{}}))}var Hu,Uu,Wu=o((()=>{A(),zu(),Hu={legacy:`0x0`,eip2930:`0x1`,eip1559:`0x2`,eip4844:`0x3`,eip7702:`0x4`},Uu=Ru(`transactionRequest`,Bu)}));function Gu(e){if(!(!e||e.length===0))return e.reduce((e,{slot:t,value:n})=>{if(t.length!==66)throw new un({size:t.length,targetSize:66,type:`hex`});if(n.length!==66)throw new un({size:n.length,targetSize:66,type:`hex`});return e[t]=n,e},{})}function Ku(e){let{balance:t,nonce:n,state:r,stateDiff:i,code:a}=e,o={};if(a!==void 0&&(o.code=a),t!==void 0&&(o.balance=k(t)),n!==void 0&&(o.nonce=k(n)),r!==void 0&&(o.state=Gu(r)),i!==void 0){if(o.state)throw new no;o.stateDiff=Gu(i)}return o}function qu(e){if(!e)return;let t={};for(let{address:n,...r}of e){if(!bi(n,{strict:!1}))throw new fi({address:n});if(t[n])throw new to({address:n});t[n]=Ku(r)}return t}var Ju=o((()=>{pi(),dn(),ro(),Ci(),A()})),Yu,Xu,Zu=o((()=>{2n**(8n-1n)-1n,2n**(16n-1n)-1n,2n**(24n-1n)-1n,2n**(32n-1n)-1n,2n**(40n-1n)-1n,2n**(48n-1n)-1n,2n**(56n-1n)-1n,2n**(64n-1n)-1n,2n**(72n-1n)-1n,2n**(80n-1n)-1n,2n**(88n-1n)-1n,2n**(96n-1n)-1n,2n**(104n-1n)-1n,2n**(112n-1n)-1n,2n**(120n-1n)-1n,2n**(128n-1n)-1n,2n**(136n-1n)-1n,2n**(144n-1n)-1n,2n**(152n-1n)-1n,2n**(160n-1n)-1n,2n**(168n-1n)-1n,2n**(176n-1n)-1n,2n**(184n-1n)-1n,2n**(192n-1n)-1n,2n**(200n-1n)-1n,2n**(208n-1n)-1n,2n**(216n-1n)-1n,2n**(224n-1n)-1n,2n**(232n-1n)-1n,2n**(240n-1n)-1n,2n**(248n-1n)-1n,2n**(256n-1n)-1n,-(2n**(8n-1n)),-(2n**(16n-1n)),-(2n**(24n-1n)),-(2n**(32n-1n)),-(2n**(40n-1n)),-(2n**(48n-1n)),-(2n**(56n-1n)),-(2n**(64n-1n)),-(2n**(72n-1n)),-(2n**(80n-1n)),-(2n**(88n-1n)),-(2n**(96n-1n)),-(2n**(104n-1n)),-(2n**(112n-1n)),-(2n**(120n-1n)),-(2n**(128n-1n)),-(2n**(136n-1n)),-(2n**(144n-1n)),-(2n**(152n-1n)),-(2n**(160n-1n)),-(2n**(168n-1n)),-(2n**(176n-1n)),-(2n**(184n-1n)),-(2n**(192n-1n)),-(2n**(200n-1n)),-(2n**(208n-1n)),-(2n**(216n-1n)),-(2n**(224n-1n)),-(2n**(232n-1n)),-(2n**(240n-1n)),-(2n**(248n-1n)),-(2n**(256n-1n)),Yu=2n**16n-1n,Xu=2n**256n-1n}));function Qu(e){let{account:t,gasPrice:n,maxFeePerGas:r,maxPriorityFeePerGas:i,to:a}=e,o=t?na(t):void 0;if(o&&!bi(o.address))throw new fi({address:o.address});if(a&&!bi(a))throw new fi({address:a});if(n!==void 0&&(r!==void 0||i!==void 0))throw new ao;if(r&&r>Xu)throw new xu({maxFeePerGas:r});if(i&&r&&i>r)throw new Au({maxFeePerGas:r,maxPriorityFeePerGas:i})}var $u=o((()=>{ra(),Zu(),pi(),Mu(),ho(),Ci()}));Qa(),O();var ed=class extends D{constructor(){super(\"`baseFeeMultiplier` must be greater than 1.\",{name:`BaseFeeScalarError`})}},td=class extends D{constructor(){super(`Chain does not support EIP-1559 fees.`,{name:`Eip1559FeesNotSupportedError`})}},nd=class extends D{constructor({maxPriorityFeePerGas:e}){super(`\\`maxFeePerGas\\` cannot be less than the \\`maxPriorityFeePerGas\\` (${Za(e)} gwei).`,{name:`MaxFeePerGasTooLowError`})}};O();var rd=class extends D{constructor({blockHash:e,blockNumber:t}){let n=`Block`;e&&(n=`Block at hash \"${e}\"`),t&&(n=`Block at number \"${t}\"`),super(`${n} could not be found.`,{name:`BlockNotFoundError`})}};Dn(),zu();const id={\"0x0\":`legacy`,\"0x1\":`eip2930`,\"0x2\":`eip1559`,\"0x3\":`eip4844`,\"0x4\":`eip7702`};function ad(e,t){let n={...e,blockHash:e.blockHash?e.blockHash:null,blockNumber:e.blockNumber?BigInt(e.blockNumber):null,chainId:e.chainId?En(e.chainId):void 0,gas:e.gas?BigInt(e.gas):void 0,gasPrice:e.gasPrice?BigInt(e.gasPrice):void 0,maxFeePerBlobGas:e.maxFeePerBlobGas?BigInt(e.maxFeePerBlobGas):void 0,maxFeePerGas:e.maxFeePerGas?BigInt(e.maxFeePerGas):void 0,maxPriorityFeePerGas:e.maxPriorityFeePerGas?BigInt(e.maxPriorityFeePerGas):void 0,nonce:e.nonce?En(e.nonce):void 0,to:e.to?e.to:null,transactionIndex:e.transactionIndex?Number(e.transactionIndex):null,type:e.type?id[e.type]:void 0,typeHex:e.type?e.type:void 0,value:e.value?BigInt(e.value):void 0,v:e.v?BigInt(e.v):void 0};return e.authorizationList&&(n.authorizationList=sd(e.authorizationList)),n.yParity=(()=>{if(e.yParity)return Number(e.yParity);if(typeof n.v==`bigint`){if(n.v===0n||n.v===27n)return 0;if(n.v===1n||n.v===28n)return 1;if(n.v>=35n)return n.v%2n==0n?1:0}})(),n.type===`legacy`&&(delete n.accessList,delete n.maxFeePerBlobGas,delete n.maxFeePerGas,delete n.maxPriorityFeePerGas,delete n.yParity),n.type===`eip2930`&&(delete n.maxFeePerBlobGas,delete n.maxFeePerGas,delete n.maxPriorityFeePerGas),n.type===`eip1559`&&delete n.maxFeePerBlobGas,n}const od=Ru(`transaction`,ad);function sd(e){return e.map(e=>({address:e.address,chainId:Number(e.chainId),nonce:Number(e.nonce),r:e.r,s:e.s,yParity:Number(e.yParity)}))}zu();function cd(e,t){let n=(e.transactions??[]).map(e=>typeof e==`string`?e:ad(e));return{...e,baseFeePerGas:e.baseFeePerGas?BigInt(e.baseFeePerGas):null,blobGasUsed:e.blobGasUsed?BigInt(e.blobGasUsed):void 0,difficulty:e.difficulty?BigInt(e.difficulty):void 0,excessBlobGas:e.excessBlobGas?BigInt(e.excessBlobGas):void 0,gasLimit:e.gasLimit?BigInt(e.gasLimit):void 0,gasUsed:e.gasUsed?BigInt(e.gasUsed):void 0,hash:e.hash?e.hash:null,logsBloom:e.logsBloom?e.logsBloom:null,nonce:e.nonce?e.nonce:null,number:e.number?BigInt(e.number):null,size:e.size?BigInt(e.size):void 0,timestamp:e.timestamp?BigInt(e.timestamp):void 0,transactions:n,totalDifficulty:e.totalDifficulty?BigInt(e.totalDifficulty):null}}const ld=Ru(`block`,cd);A();async function ud(e,{blockHash:t,blockNumber:n,blockTag:r=e.experimental_blockTag??`latest`,includeTransactions:i}={}){let a=i??!1,o=n===void 0?void 0:k(n),s=null;if(s=t?await e.request({method:`eth_getBlockByHash`,params:[t,a]},{dedupe:!0}):await e.request({method:`eth_getBlockByNumber`,params:[o||r,a]},{dedupe:!!o}),!s)throw new rd({blockHash:t,blockNumber:n});return(e.chain?.formatters?.block?.format||cd)(s,`getBlock`)}async function dd(e){let t=await e.request({method:`eth_gasPrice`});return BigInt(t)}Dn();async function fd(e,t){let{block:n,chain:r=e.chain,request:i}=t||{};try{let t=r?.fees?.maxPriorityFeePerGas??r?.fees?.defaultPriorityFee;if(typeof t==`function`){let r=n||await E(e,ud,`getBlock`)({}),a=await t({block:r,client:e,request:i});if(a===null)throw Error();return a}if(t!==void 0)return t;let a=await e.request({method:`eth_maxPriorityFeePerGas`});return wn(a)}catch{let[t,r]=await Promise.all([n?Promise.resolve(n):E(e,ud,`getBlock`)({}),E(e,dd,`getGasPrice`)({})]);if(typeof t.baseFeePerGas!=`bigint`)throw new td;let i=r-t.baseFeePerGas;return i<0n?0n:i}}async function pd(e,t){let{block:n,chain:r=e.chain,request:i,type:a=`eip1559`}=t||{},o=await(async()=>typeof r?.fees?.baseFeeMultiplier==`function`?r.fees.baseFeeMultiplier({block:n,client:e,request:i}):r?.fees?.baseFeeMultiplier??1.2)();if(o<1)throw new ed;let s=10**(o.toString().split(`.`)[1]?.length??0),c=e=>e*BigInt(Math.ceil(o*s))/BigInt(s),l=n||await E(e,ud,`getBlock`)({});if(typeof r?.fees?.estimateFeesPerGas==`function`){let t=await r.fees.estimateFeesPerGas({block:n,client:e,multiply:c,request:i,type:a});if(t!==null)return t}if(a===`eip1559`){if(typeof l.baseFeePerGas!=`bigint`)throw new td;let t=typeof i?.maxPriorityFeePerGas==`bigint`?i.maxPriorityFeePerGas:await fd(e,{block:l,chain:r,request:i}),n=c(l.baseFeePerGas);return{maxFeePerGas:i?.maxFeePerGas??n+t,maxPriorityFeePerGas:t}}return{gasPrice:i?.gasPrice??c(await E(e,dd,`getGasPrice`)({}))}}Dn(),A();async function md(e,{address:t,blockTag:n=`latest`,blockNumber:r}){let i=await e.request({method:`eth_getTransactionCount`,params:[t,typeof r==`bigint`?k(r):n]},{dedupe:!!r});return En(i)}Wu(),Hn(),A();function hd(e){let{kzg:t}=e,n=e.to??(typeof e.blobs[0]==`string`?`hex`:`bytes`),r=typeof e.blobs[0]==`string`?e.blobs.map(e=>Ln(e)):e.blobs,i=[];for(let e of r)i.push(Uint8Array.from(t.blobToKzgCommitment(e)));return n===`bytes`?i:i.map(e=>An(e))}Hn(),A();function gd(e){let{kzg:t}=e,n=e.to??(typeof e.blobs[0]==`string`?`hex`:`bytes`),r=typeof e.blobs[0]==`string`?e.blobs.map(e=>Ln(e)):e.blobs,i=typeof e.commitments[0]==`string`?e.commitments.map(e=>Ln(e)):e.commitments,a=[];for(let e=0;e<r.length;e++){let n=r[e],o=i[e];a.push(Uint8Array.from(t.computeBlobKzgProof(n,o)))}return n===`bytes`?a:a.map(e=>An(e))}Is();const _d=Ns;Pt(),Hn(),A();function vd(e,t){let n=t||`hex`,r=_d(Nt(e,{strict:!1})?Pn(e):e);return n===`bytes`?r:On(r)}A();function yd(e){let{commitment:t,version:n=1}=e,r=e.to??(typeof t==`string`?`hex`:`bytes`),i=vd(t,`bytes`);return i.set([n],0),r===`bytes`?i:An(i)}function bd(e){let{commitments:t,version:n}=e,r=e.to??(typeof t[0]==`string`?`hex`:`bytes`),i=[];for(let e of t)i.push(yd({commitment:e,to:r,version:n}));return i}var xd=6;const Sd=4096,Cd=32*Sd,wd=Cd*xd-1-1*Sd*xd;O();var Td=class extends D{constructor({maxSize:e,size:t}){super(`Blob size is too large.`,{metaMessages:[`Max: ${e} bytes`,`Given: ${t} bytes`],name:`BlobSizeTooLargeError`})}},Ed=class extends D{constructor(){super(`Blob data must not be empty.`,{name:`EmptyBlobError`})}},Dd=class extends D{constructor({hash:e,size:t}){super(`Versioned hash \"${e}\" size is invalid.`,{metaMessages:[`Expected: 32`,`Received: ${t}`],name:`InvalidVersionedHashSizeError`})}},Od=class extends D{constructor({hash:e,version:t}){super(`Versioned hash \"${e}\" version is invalid.`,{metaMessages:[`Expected: 1`,`Received: ${t}`],name:`InvalidVersionedHashVersionError`})}};ya(),It(),Hn(),A();function kd(e){let t=e.to??(typeof e.data==`string`?`hex`:`bytes`),n=typeof e.data==`string`?Ln(e.data):e.data,r=Ft(n);if(!r)throw new Ed;if(r>761855)throw new Td({maxSize:wd,size:r});let i=[],a=!0,o=0;for(;a;){let e=_a(new Uint8Array(Cd)),t=0;for(;t<Sd;){let r=n.slice(o,o+31);if(e.pushByte(0),e.pushBytes(r),r.length<31){e.pushByte(128),a=!1;break}t++,o+=31}i.push(e)}return t===`bytes`?i.map(e=>e.bytes):i.map(e=>An(e.bytes))}function Ad(e){let{data:t,kzg:n,to:r}=e,i=e.blobs??kd({data:t,to:r}),a=e.commitments??hd({blobs:i,kzg:n,to:r}),o=e.proofs??gd({blobs:i,commitments:a,kzg:n,to:r}),s=[];for(let e=0;e<i.length;e++)s.push({blob:i[e],commitment:a[e],proof:o[e]});return s}ho();function jd(e){if(e.type)return e.type;if(e.authorizationList!==void 0)return`eip7702`;if(e.blobs!==void 0||e.blobVersionedHashes!==void 0||e.maxFeePerBlobGas!==void 0||e.sidecars!==void 0)return`eip4844`;if(e.maxFeePerGas!==void 0||e.maxPriorityFeePerGas!==void 0)return`eip1559`;if(e.gasPrice!==void 0)return e.accessList===void 0?`legacy`:`eip2930`;throw new so({transaction:e})}Dn();async function Md(e){let t=await e.request({method:`eth_chainId`},{dedupe:!0});return En(t)}ra(),$u();const Nd=[`blobVersionedHashes`,`chainId`,`fees`,`gas`,`nonce`,`type`],Pd=new Map;async function Fd(e,t){let{account:n=e.account,blobs:r,chain:i,gas:a,kzg:o,nonce:s,nonceManager:c,parameters:l=Nd,type:u}=t,d=n&&na(n),f={...t,...d?{from:d?.address}:{}},p;async function m(){return p||(p=await E(e,ud,`getBlock`)({blockTag:`latest`}),p)}let h;async function g(){return h||(i?i.id:t.chainId===void 0?(h=await E(e,Md,`getChainId`)({}),h):t.chainId)}if(l.includes(`nonce`)&&s===void 0&&d)if(c){let t=await g();f.nonce=await c.consume({address:d.address,chainId:t,client:e})}else f.nonce=await E(e,md,`getTransactionCount`)({address:d.address,blockTag:`pending`});if((l.includes(`blobVersionedHashes`)||l.includes(`sidecars`))&&r&&o){let e=hd({blobs:r,kzg:o});if(l.includes(`blobVersionedHashes`)&&(f.blobVersionedHashes=bd({commitments:e,to:`hex`})),l.includes(`sidecars`)){let t=gd({blobs:r,commitments:e,kzg:o});f.sidecars=Ad({blobs:r,commitments:e,proofs:t,to:`hex`})}}if(l.includes(`chainId`)&&(f.chainId=await g()),(l.includes(`fees`)||l.includes(`type`))&&u===void 0)try{f.type=jd(f)}catch{let t=Pd.get(e.uid);t===void 0&&(t=typeof(await m())?.baseFeePerGas==`bigint`,Pd.set(e.uid,t)),f.type=t?`eip1559`:`legacy`}if(l.includes(`fees`))if(f.type!==`legacy`&&f.type!==`eip2930`){if(f.maxFeePerGas===void 0||f.maxPriorityFeePerGas===void 0){let n=await m(),{maxFeePerGas:r,maxPriorityFeePerGas:a}=await pd(e,{block:n,chain:i,request:f});if(t.maxPriorityFeePerGas===void 0&&t.maxFeePerGas&&t.maxFeePerGas<a)throw new nd({maxPriorityFeePerGas:a});f.maxPriorityFeePerGas=a,f.maxFeePerGas=r}}else{if(t.maxFeePerGas!==void 0||t.maxPriorityFeePerGas!==void 0)throw new td;if(t.gasPrice===void 0){let t=await m(),{gasPrice:n}=await pd(e,{block:t,chain:i,request:f,type:`legacy`});f.gasPrice=n}}return l.includes(`gas`)&&a===void 0&&(f.gas=await E(e,Id,`estimateGas`)({...f,account:d&&{address:d.address,type:`json-rpc`}})),Qu(f),delete f.parameters,f}ra(),O(),A(),Lu(),Ju(),$u();async function Id(e,t){let{account:n=e.account}=t,r=n?na(n):void 0;try{let{accessList:n,authorizationList:i,blobs:a,blobVersionedHashes:o,blockNumber:s,blockTag:c,data:l,gas:u,gasPrice:d,maxFeePerBlobGas:f,maxFeePerGas:p,maxPriorityFeePerGas:m,nonce:h,value:g,stateOverride:_,...v}=await Fd(e,{...t,parameters:r?.type===`local`?void 0:[`blobVersionedHashes`]}),y=(typeof s==`bigint`?k(s):void 0)||c,b=qu(_),x=await(async()=>{if(v.to)return v.to;if(i&&i.length>0)return await vu({authorization:i[0]}).catch(()=>{throw new D(\"`to` is required. Could not infer from `authorizationList`\")})})();Qu(t);let S=e.chain?.formatters?.transactionRequest?.format,C=(S||Bu)({...Iu(v,{format:S}),from:r?.address,accessList:n,authorizationList:i,blobs:a,blobVersionedHashes:o,data:l,gas:u,gasPrice:d,maxFeePerBlobGas:f,maxFeePerGas:p,maxPriorityFeePerGas:m,nonce:h,to:x,value:g},`estimateGas`);return BigInt(await e.request({method:`eth_estimateGas`,params:b?[C,y??e.experimental_blockTag??`latest`,b]:y?[C,y]:[C]}))}catch(n){throw Fu(n,{...t,account:r,chain:e.chain})}}function Ld(e,t){if(!bi(e,{strict:!1}))throw new fi({address:e});if(!bi(t,{strict:!1}))throw new fi({address:t});return e.toLowerCase()===t.toLowerCase()}var Rd=o((()=>{pi(),Ci()}));function zd(e,{args:t,eventName:n}={}){return{...e,blockHash:e.blockHash?e.blockHash:null,blockNumber:e.blockNumber?BigInt(e.blockNumber):null,logIndex:e.logIndex?Number(e.logIndex):null,transactionHash:e.transactionHash?e.transactionHash:null,transactionIndex:e.transactionIndex?Number(e.transactionIndex):null,...n?{args:t,eventName:n}:{}}}function Bd(e){let{abi:t,args:n,functionName:r,data:i}=e,a=t[0];if(r){let e=Qi({abi:t,args:n,name:r});if(!e)throw new Zt(r,{docsPath:Vd});a=e}if(a.type!==`function`)throw new Zt(void 0,{docsPath:Vd});if(!a.outputs)throw new Qt(a.name,{docsPath:Vd});let o=Ta(a.outputs,i);if(o&&o.length>1)return o;if(o&&o.length===1)return o[0]}var Vd,Hd=o((()=>{sn(),La(),ta(),Vd=`/docs/contract/decodeFunctionResult`})),Ud,Wd=o((()=>{Ud=`0.1.1`}));function Gd(){return Ud}var Kd=o((()=>{Wd()}));function qd(e,t){return t?.(e)?e:e&&typeof e==`object`&&`cause`in e&&e.cause?qd(e.cause,t):t?null:e}var P,Jd=o((()=>{Kd(),P=class e extends Error{constructor(t,n={}){let r=(()=>{if(n.cause instanceof e){if(n.cause.details)return n.cause.details;if(n.cause.shortMessage)return n.cause.shortMessage}return n.cause&&`details`in n.cause&&typeof n.cause.details==`string`?n.cause.details:n.cause?.message?n.cause.message:n.details})(),i=(()=>n.cause instanceof e&&n.cause.docsPath||n.docsPath)(),a=`https://oxlib.sh${i??``}`,o=[t||`An error occurred.`,...n.metaMessages?[``,...n.metaMessages]:[],...r||i?[``,r?`Details: ${r}`:void 0,i?`See: ${a}`:void 0]:[]].filter(e=>typeof e==`string`).join(`\n`);super(o,n.cause?{cause:n.cause}:void 0),Object.defineProperty(this,`details`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`docs`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`docsPath`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`shortMessage`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`cause`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`BaseError`}),Object.defineProperty(this,`version`,{enumerable:!0,configurable:!0,writable:!0,value:`ox@${Gd()}`}),this.cause=n.cause,this.details=r,this.docs=a,this.docsPath=i,this.shortMessage=t}walk(e){return qd(this,e)}}}));function Yd(e,t){if(bf(e)>t)throw new Pf({givenSize:bf(e),maxSize:t})}function Xd(e,t){if(typeof t==`number`&&t>0&&t>bf(e)-1)throw new Ff({offset:t,position:`start`,size:bf(e)})}function Zd(e,t,n){if(typeof t==`number`&&typeof n==`number`&&bf(e)!==n-t)throw new Ff({offset:n,position:`end`,size:bf(e)})}function F(e){if(e>=ef.zero&&e<=ef.nine)return e-ef.zero;if(e>=ef.A&&e<=ef.F)return e-(ef.A-10);if(e>=ef.a&&e<=ef.f)return e-(ef.a-10)}function Qd(e,t={}){let{dir:n,size:r=32}=t;if(r===0)return e;if(e.length>r)throw new If({size:e.length,targetSize:r,type:`Bytes`});let i=new Uint8Array(r);for(let t=0;t<r;t++){let a=n===`right`;i[a?t:r-t-1]=e[a?t:e.length-t-1]}return i}function $d(e,t={}){let{dir:n=`left`}=t,r=e,i=0;for(let e=0;e<r.length-1&&r[n===`left`?e:r.length-e-1].toString()===`0`;e++)i++;return r=n===`left`?r.slice(i):r.slice(0,r.length-i),r}var ef,tf=o((()=>{Lf(),ef={zero:48,nine:57,A:65,F:70,a:97,f:102}}));function nf(e,t){if(qf(e)>t)throw new rp({givenSize:qf(e),maxSize:t})}function rf(e,t){if(typeof t==`number`&&t>0&&t>qf(e)-1)throw new ip({offset:t,position:`start`,size:qf(e)})}function af(e,t,n){if(typeof t==`number`&&typeof n==`number`&&qf(e)!==n-t)throw new ip({offset:n,position:`end`,size:qf(e)})}function sf(e,t={}){let{dir:n,size:r=32}=t;if(r===0)return e;let i=e.replace(`0x`,``);if(i.length>r*2)throw new ap({size:Math.ceil(i.length/2),targetSize:r,type:`Hex`});return`0x${i[n===`right`?`padEnd`:`padStart`](r*2,`0`)}`}function cf(e,t={}){let{dir:n=`left`}=t,r=e.replace(`0x`,``),i=0;for(let e=0;e<r.length-1&&r[n===`left`?e:r.length-e-1].toString()===`0`;e++)i++;return r=n===`left`?r.slice(i):r.slice(0,r.length-i),r===`0`?`0x`:n===`right`&&r.length%2==1?`0x${r}0`:`0x${r}`}var lf=o((()=>{op()}));function uf(e,t){return JSON.parse(e,(e,n)=>{let r=n;return typeof r==`string`&&r.endsWith(ff)?BigInt(r.slice(0,-9)):typeof t==`function`?t(e,r):r})}function df(e,t,n){return JSON.stringify(e,(e,n)=>typeof t==`function`?t(e,n):typeof n==`bigint`?n.toString()+ff:n,n)}var ff,pf=o((()=>{ff=`#__bigint`}));function mf(e){if(!(e instanceof Uint8Array)&&(!e||typeof e!=`object`||!(`BYTES_PER_ELEMENT`in e)||e.BYTES_PER_ELEMENT!==1||e.constructor.name!==`Uint8Array`))throw new Nf(e)}function hf(e){return e instanceof Uint8Array?e:typeof e==`string`?_f(e):gf(e)}function gf(e){return e instanceof Uint8Array?e:new Uint8Array(e)}function _f(e,t={}){let{size:n}=t,r=e;n&&(nf(e,n),r=Gf(e,n));let i=r.slice(2);i.length%2&&(i=`0${i}`);let a=i.length/2,o=new Uint8Array(a);for(let e=0,t=0;e<a;e++){let n=F(i.charCodeAt(t++)),r=F(i.charCodeAt(t++));if(n===void 0||r===void 0)throw new P(`Invalid byte sequence (\"${i[t-2]}${i[t-1]}\" in \"${i}\").`);o[e]=n*16+r}return o}function vf(e,t={}){let{size:n}=t,r=jf.encode(e);return typeof n==`number`?(Yd(r,n),yf(r,n)):r}function yf(e,t){return Qd(e,{dir:`right`,size:t})}function bf(e){return e.length}function xf(e,t,n,r={}){let{strict:i}=r;Xd(e,t);let a=e.slice(t,n);return i&&Zd(a,t,n),a}function Sf(e,t={}){let{size:n}=t;n!==void 0&&Yd(e,n);let r=Hf(e,t);return Yf(r,t)}function Cf(e,t={}){let{size:n}=t,r=e;if(n!==void 0&&(Yd(r,n),r=Df(r)),r.length>1||r[0]>1)throw new Mf(r);return!!r[0]}function wf(e,t={}){return Hf(e,t)}function Tf(e,t={}){let{size:n}=t;n!==void 0&&Yd(e,n);let r=Hf(e,t);return Xf(r,t)}function Ef(e,t={}){let{size:n}=t,r=e;return n!==void 0&&(Yd(r,n),r=Of(r)),Af.decode(r)}function Df(e){return $d(e,{dir:`left`})}function Of(e){return $d(e,{dir:`right`})}function kf(e){try{return mf(e),!0}catch{return!1}}var Af,jf,Mf,Nf,Pf,Ff,If,Lf=o((()=>{Jd(),op(),tf(),lf(),pf(),Af=new TextDecoder,jf=new TextEncoder,Mf=class extends P{constructor(e){super(`Bytes value \\`${e}\\` is not a valid boolean.`,{metaMessages:[\"The bytes array must contain a single byte of either a `0` or `1` value.\"]}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Bytes.InvalidBytesBooleanError`})}},Nf=class extends P{constructor(e){super(`Value \\`${typeof e==`object`?df(e):e}\\` of type \\`${typeof e}\\` is an invalid Bytes value.`,{metaMessages:[\"Bytes values must be of type `Bytes`.\"]}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Bytes.InvalidBytesTypeError`})}},Pf=class extends P{constructor({givenSize:e,maxSize:t}){super(`Size cannot exceed \\`${t}\\` bytes. Given size: \\`${e}\\` bytes.`),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Bytes.SizeOverflowError`})}},Ff=class extends P{constructor({offset:e,position:t,size:n}){super(`Slice ${t===`start`?`starting`:`ending`} at offset \\`${e}\\` is out-of-bounds (size: \\`${n}\\`).`),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Bytes.SliceOffsetOutOfBoundsError`})}},If=class extends P{constructor({size:e,targetSize:t,type:n}){super(`${n.charAt(0).toUpperCase()}${n.slice(1).toLowerCase()} size (\\`${e}\\`) exceeds padding size (\\`${t}\\`).`),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Bytes.SizeExceedsPaddingSizeError`})}}}));function Rf(e,t={}){let{strict:n=!1}=t;if(!e||typeof e!=`string`)throw new tp(e);if(n&&!/^0x[0-9a-fA-F]*$/.test(e)||!e.startsWith(`0x`))throw new np(e)}function zf(...e){return`0x${e.reduce((e,t)=>e+t.replace(`0x`,``),``)}`}function Bf(e){return e instanceof Uint8Array?Hf(e):Array.isArray(e)?Hf(new Uint8Array(e)):e}function Vf(e,t={}){let n=`0x${Number(e)}`;return typeof t.size==`number`?(nf(n,t.size),Wf(n,t.size)):n}function Hf(e,t={}){let n=``;for(let t=0;t<e.length;t++)n+=$f[e[t]];let r=`0x${n}`;return typeof t.size==`number`?(nf(r,t.size),Gf(r,t.size)):r}function I(e,t={}){let{signed:n,size:r}=t,i=BigInt(e),a;r?a=n?(1n<<BigInt(r)*8n-1n)-1n:2n**(BigInt(r)*8n)-1n:typeof e==`number`&&(a=BigInt(2**53-1));let o=typeof a==`bigint`&&n?-a-1n:0;if(a&&i>a||i<o){let t=typeof e==`bigint`?`n`:``;throw new ep({max:a?`${a}${t}`:void 0,min:`${o}${t}`,signed:n,size:r,value:`${e}${t}`})}let s=`0x${(n&&i<0?(1n<<BigInt(r*8))+BigInt(i):i).toString(16)}`;return r?Wf(s,r):s}function Uf(e,t={}){return Hf(Qf.encode(e),t)}function Wf(e,t){return sf(e,{dir:`left`,size:t})}function Gf(e,t){return sf(e,{dir:`right`,size:t})}function Kf(e,t,n,r={}){let{strict:i}=r;rf(e,t);let a=`0x${e.replace(`0x`,``).slice((t??0)*2,(n??e.length)*2)}`;return i&&af(a,t,n),a}function qf(e){return Math.ceil((e.length-2)/2)}function Jf(e){return cf(e,{dir:`left`})}function Yf(e,t={}){let{signed:n}=t;t.size&&nf(e,t.size);let r=BigInt(e);if(!n)return r;let i=(e.length-2)/2,a=(1n<<BigInt(i)*8n)-1n,o=a>>1n;return r<=o?r:r-a-1n}function Xf(e,t={}){let{signed:n,size:r}=t;return!n&&!r?Number(e):Number(Yf(e,t))}function Zf(e,t={}){let{strict:n=!1}=t;try{return Rf(e,{strict:n}),!0}catch{return!1}}var Qf,$f,ep,tp,np,rp,ip,ap,op=o((()=>{Jd(),lf(),pf(),Qf=new TextEncoder,$f=Array.from({length:256},(e,t)=>t.toString(16).padStart(2,`0`)),ep=class extends P{constructor({max:e,min:t,signed:n,size:r,value:i}){super(`Number \\`${i}\\` is not in safe${r?` ${r*8}-bit`:``}${n?` signed`:` unsigned`} integer range ${e?`(\\`${t}\\` to \\`${e}\\`)`:`(above \\`${t}\\`)`}`),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Hex.IntegerOutOfRangeError`})}},tp=class extends P{constructor(e){super(`Value \\`${typeof e==`object`?df(e):e}\\` of type \\`${typeof e}\\` is an invalid hex type.`,{metaMessages:['Hex types must be represented as `\"0x${string}\"`.']}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Hex.InvalidHexTypeError`})}},np=class extends P{constructor(e){super(`Value \\`${e}\\` is an invalid hex value.`,{metaMessages:['Hex values must start with `\"0x\"` and contain only hexadecimal characters (0-9, a-f, A-F).']}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Hex.InvalidHexValueError`})}},rp=class extends P{constructor({givenSize:e,maxSize:t}){super(`Size cannot exceed \\`${t}\\` bytes. Given size: \\`${e}\\` bytes.`),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Hex.SizeOverflowError`})}},ip=class extends P{constructor({offset:e,position:t,size:n}){super(`Slice ${t===`start`?`starting`:`ending`} at offset \\`${e}\\` is out-of-bounds (size: \\`${n}\\`).`),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Hex.SliceOffsetOutOfBoundsError`})}},ap=class extends P{constructor({size:e,targetSize:t,type:n}){super(`${n.charAt(0).toUpperCase()}${n.slice(1).toLowerCase()} size (\\`${e}\\`) exceeds padding size (\\`${t}\\`).`),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Hex.SizeExceedsPaddingSizeError`})}}}));function sp(e){return{address:e.address,amount:I(e.amount),index:I(e.index),validatorIndex:I(e.validatorIndex)}}var cp=o((()=>{op()}));function lp(e){return{...typeof e.baseFeePerGas==`bigint`&&{baseFeePerGas:I(e.baseFeePerGas)},...typeof e.blobBaseFee==`bigint`&&{blobBaseFee:I(e.blobBaseFee)},...typeof e.feeRecipient==`string`&&{feeRecipient:e.feeRecipient},...typeof e.gasLimit==`bigint`&&{gasLimit:I(e.gasLimit)},...typeof e.number==`bigint`&&{number:I(e.number)},...typeof e.prevRandao==`bigint`&&{prevRandao:I(e.prevRandao)},...typeof e.time==`bigint`&&{time:I(e.time)},...e.withdrawals&&{withdrawals:e.withdrawals.map(sp)}}}var up=o((()=>{op(),cp()})),dp,fp,pp,mp,hp,gp=o((()=>{dp=[{inputs:[{components:[{name:`target`,type:`address`},{name:`allowFailure`,type:`bool`},{name:`callData`,type:`bytes`}],name:`calls`,type:`tuple[]`}],name:`aggregate3`,outputs:[{components:[{name:`success`,type:`bool`},{name:`returnData`,type:`bytes`}],name:`returnData`,type:`tuple[]`}],stateMutability:`view`,type:`function`},{inputs:[],name:`getCurrentBlockTimestamp`,outputs:[{internalType:`uint256`,name:`timestamp`,type:`uint256`}],stateMutability:`view`,type:`function`}],fp=[{name:`query`,type:`function`,stateMutability:`view`,inputs:[{type:`tuple[]`,name:`queries`,components:[{type:`address`,name:`sender`},{type:`string[]`,name:`urls`},{type:`bytes`,name:`data`}]}],outputs:[{type:`bool[]`,name:`failures`},{type:`bytes[]`,name:`responses`}]},{name:`HttpError`,type:`error`,inputs:[{type:`uint16`,name:`status`},{type:`string`,name:`message`}]}],pp=[{inputs:[{name:`dns`,type:`bytes`}],name:`DNSDecodingFailed`,type:`error`},{inputs:[{name:`ens`,type:`string`}],name:`DNSEncodingFailed`,type:`error`},{inputs:[],name:`EmptyAddress`,type:`error`},{inputs:[{name:`status`,type:`uint16`},{name:`message`,type:`string`}],name:`HttpError`,type:`error`},{inputs:[],name:`InvalidBatchGatewayResponse`,type:`error`},{inputs:[{name:`errorData`,type:`bytes`}],name:`ResolverError`,type:`error`},{inputs:[{name:`name`,type:`bytes`},{name:`resolver`,type:`address`}],name:`ResolverNotContract`,type:`error`},{inputs:[{name:`name`,type:`bytes`}],name:`ResolverNotFound`,type:`error`},{inputs:[{name:`primary`,type:`string`},{name:`primaryAddress`,type:`bytes`}],name:`ReverseAddressMismatch`,type:`error`},{inputs:[{internalType:`bytes4`,name:`selector`,type:`bytes4`}],name:`UnsupportedResolverProfile`,type:`error`}],[...pp],[...pp],mp=[{name:`isValidSignature`,type:`function`,stateMutability:`view`,inputs:[{name:`hash`,type:`bytes32`},{name:`signature`,type:`bytes`}],outputs:[{name:``,type:`bytes4`}]}],hp=[{inputs:[{name:`_signer`,type:`address`},{name:`_hash`,type:`bytes32`},{name:`_signature`,type:`bytes`}],stateMutability:`nonpayable`,type:`constructor`},{inputs:[{name:`_signer`,type:`address`},{name:`_hash`,type:`bytes32`},{name:`_signature`,type:`bytes`}],outputs:[{type:`bool`}],stateMutability:`nonpayable`,type:`function`,name:`isValidSig`}]})),_p=o((()=>{})),vp,yp,bp,xp,Sp=o((()=>{vp=`0x608060405234801561001057600080fd5b5060405161018e38038061018e83398101604081905261002f91610124565b6000808351602085016000f59050803b61004857600080fd5b6000808351602085016000855af16040513d6000823e81610067573d81fd5b3d81f35b634e487b7160e01b600052604160045260246000fd5b600082601f83011261009257600080fd5b81516001600160401b038111156100ab576100ab61006b565b604051601f8201601f19908116603f011681016001600160401b03811182821017156100d9576100d961006b565b6040528181528382016020018510156100f157600080fd5b60005b82811015610110576020818601810151838301820152016100f4565b506000918101602001919091529392505050565b6000806040838503121561013757600080fd5b82516001600160401b0381111561014d57600080fd5b61015985828601610081565b602085015190935090506001600160401b0381111561017757600080fd5b61018385828601610081565b915050925092905056fe`,yp=`0x608060405234801561001057600080fd5b506040516102c03803806102c083398101604081905261002f916101e6565b836001600160a01b03163b6000036100e457600080836001600160a01b03168360405161005c9190610270565b6000604051808303816000865af19150503d8060008114610099576040519150601f19603f3d011682016040523d82523d6000602084013e61009e565b606091505b50915091508115806100b857506001600160a01b0386163b155b156100e1578060405163101bb98d60e01b81526004016100d8919061028c565b60405180910390fd5b50505b6000808451602086016000885af16040513d6000823e81610103573d81fd5b3d81f35b80516001600160a01b038116811461011e57600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60005b8381101561015457818101518382015260200161013c565b50506000910152565b600082601f83011261016e57600080fd5b81516001600160401b0381111561018757610187610123565b604051601f8201601f19908116603f011681016001600160401b03811182821017156101b5576101b5610123565b6040528181528382016020018510156101cd57600080fd5b6101de826020830160208701610139565b949350505050565b600080600080608085870312156101fc57600080fd5b61020585610107565b60208601519094506001600160401b0381111561022157600080fd5b61022d8782880161015d565b93505061023c60408601610107565b60608601519092506001600160401b0381111561025857600080fd5b6102648782880161015d565b91505092959194509250565b60008251610282818460208701610139565b9190910192915050565b60208152600082518060208401526102ab816040850160208701610139565b601f01601f1916919091016040019291505056fe`,bp=`0x608060405234801561001057600080fd5b5060405161069438038061069483398101604081905261002f9161051e565b600061003c848484610048565b9050806000526001601ff35b60007f64926492649264926492649264926492649264926492649264926492649264926100748361040c565b036101e7576000606080848060200190518101906100929190610577565b60405192955090935091506000906001600160a01b038516906100b69085906105dd565b6000604051808303816000865af19150503d80600081146100f3576040519150601f19603f3d011682016040523d82523d6000602084013e6100f8565b606091505b50509050876001600160a01b03163b60000361016057806101605760405162461bcd60e51b815260206004820152601e60248201527f5369676e617475726556616c696461746f723a206465706c6f796d656e74000060448201526064015b60405180910390fd5b604051630b135d3f60e11b808252906001600160a01b038a1690631626ba7e90610190908b9087906004016105f9565b602060405180830381865afa1580156101ad573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101d19190610633565b6001600160e01b03191614945050505050610405565b6001600160a01b0384163b1561027a57604051630b135d3f60e11b808252906001600160a01b03861690631626ba7e9061022790879087906004016105f9565b602060405180830381865afa158015610244573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102689190610633565b6001600160e01b031916149050610405565b81516041146102df5760405162461bcd60e51b815260206004820152603a602482015260008051602061067483398151915260448201527f3a20696e76616c6964207369676e6174757265206c656e6774680000000000006064820152608401610157565b6102e7610425565b5060208201516040808401518451859392600091859190811061030c5761030c61065d565b016020015160f81c9050601b811480159061032b57508060ff16601c14155b1561038c5760405162461bcd60e51b815260206004820152603b602482015260008051602061067483398151915260448201527f3a20696e76616c6964207369676e617475726520762076616c756500000000006064820152608401610157565b60408051600081526020810180835289905260ff83169181019190915260608101849052608081018390526001600160a01b0389169060019060a0016020604051602081039080840390855afa1580156103ea573d6000803e3d6000fd5b505050602060405103516001600160a01b0316149450505050505b9392505050565b600060208251101561041d57600080fd5b508051015190565b60405180606001604052806003906020820280368337509192915050565b6001600160a01b038116811461045857600080fd5b50565b634e487b7160e01b600052604160045260246000fd5b60005b8381101561048c578181015183820152602001610474565b50506000910152565b600082601f8301126104a657600080fd5b81516001600160401b038111156104bf576104bf61045b565b604051601f8201601f19908116603f011681016001600160401b03811182821017156104ed576104ed61045b565b60405281815283820160200185101561050557600080fd5b610516826020830160208701610471565b949350505050565b60008060006060848603121561053357600080fd5b835161053e81610443565b6020850151604086015191945092506001600160401b0381111561056157600080fd5b61056d86828701610495565b9150509250925092565b60008060006060848603121561058c57600080fd5b835161059781610443565b60208501519093506001600160401b038111156105b357600080fd5b6105bf86828701610495565b604086015190935090506001600160401b0381111561056157600080fd5b600082516105ef818460208701610471565b9190910192915050565b828152604060208201526000825180604084015261061e816060850160208701610471565b601f01601f1916919091016060019392505050565b60006020828403121561064557600080fd5b81516001600160e01b03198116811461040557600080fd5b634e487b7160e01b600052603260045260246000fdfe5369676e617475726556616c696461746f72237265636f7665725369676e6572`,xp=`0x608060405234801561001057600080fd5b506115b9806100206000396000f3fe6080604052600436106100f35760003560e01c80634d2301cc1161008a578063a8b0574e11610059578063a8b0574e14610325578063bce38bd714610350578063c3077fa914610380578063ee82ac5e146103b2576100f3565b80634d2301cc1461026257806372425d9d1461029f57806382ad56cb146102ca57806386d516e8146102fa576100f3565b80633408e470116100c65780633408e470146101af578063399542e9146101da5780633e64a6961461020c57806342cbb15c14610237576100f3565b80630f28c97d146100f8578063174dea7114610123578063252dba421461015357806327e86d6e14610184575b600080fd5b34801561010457600080fd5b5061010d6103ef565b60405161011a9190610c0a565b60405180910390f35b61013d60048036038101906101389190610c94565b6103f7565b60405161014a9190610e94565b60405180910390f35b61016d60048036038101906101689190610f0c565b610615565b60405161017b92919061101b565b60405180910390f35b34801561019057600080fd5b506101996107ab565b6040516101a69190611064565b60405180910390f35b3480156101bb57600080fd5b506101c46107b7565b6040516101d19190610c0a565b60405180910390f35b6101f460048036038101906101ef91906110ab565b6107bf565b6040516102039392919061110b565b60405180910390f35b34801561021857600080fd5b506102216107e1565b60405161022e9190610c0a565b60405180910390f35b34801561024357600080fd5b5061024c6107e9565b6040516102599190610c0a565b60405180910390f35b34801561026e57600080fd5b50610289600480360381019061028491906111a7565b6107f1565b6040516102969190610c0a565b60405180910390f35b3480156102ab57600080fd5b506102b4610812565b6040516102c19190610c0a565b60405180910390f35b6102e460048036038101906102df919061122a565b61081a565b6040516102f19190610e94565b60405180910390f35b34801561030657600080fd5b5061030f6109e4565b60405161031c9190610c0a565b60405180910390f35b34801561033157600080fd5b5061033a6109ec565b6040516103479190611286565b60405180910390f35b61036a600480360381019061036591906110ab565b6109f4565b6040516103779190610e94565b60405180910390f35b61039a60048036038101906103959190610f0c565b610ba6565b6040516103a99392919061110b565b60405180910390f35b3480156103be57600080fd5b506103d960048036038101906103d491906112cd565b610bca565b6040516103e69190611064565b60405180910390f35b600042905090565b60606000808484905090508067ffffffffffffffff81111561041c5761041b6112fa565b5b60405190808252806020026020018201604052801561045557816020015b610442610bd5565b81526020019060019003908161043a5790505b5092503660005b828110156105c957600085828151811061047957610478611329565b5b6020026020010151905087878381811061049657610495611329565b5b90506020028101906104a89190611367565b925060008360400135905080860195508360000160208101906104cb91906111a7565b73ffffffffffffffffffffffffffffffffffffffff16818580606001906104f2919061138f565b604051610500929190611431565b60006040518083038185875af1925050503d806000811461053d576040519150601f19603f3d011682016040523d82523d6000602084013e610542565b606091505b5083600001846020018290528215151515815250505081516020850135176105bc577f08c379a000000000000000000000000000000000000000000000000000000000600052602060045260176024527f4d756c746963616c6c333a2063616c6c206661696c656400000000000000000060445260846000fd5b826001019250505061045c565b5082341461060c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610603906114a7565b60405180910390fd5b50505092915050565b6000606043915060008484905090508067ffffffffffffffff81111561063e5761063d6112fa565b5b60405190808252806020026020018201604052801561067157816020015b606081526020019060019003908161065c5790505b5091503660005b828110156107a157600087878381811061069557610694611329565b5b90506020028101906106a791906114c7565b92508260000160208101906106bc91906111a7565b73ffffffffffffffffffffffffffffffffffffffff168380602001906106e2919061138f565b6040516106f0929190611431565b6000604051808303816000865af19150503d806000811461072d576040519150601f19603f3d011682016040523d82523d6000602084013e610732565b606091505b5086848151811061074657610745611329565b5b60200260200101819052819250505080610795576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161078c9061153b565b60405180910390fd5b81600101915050610678565b5050509250929050565b60006001430340905090565b600046905090565b6000806060439250434091506107d68686866109f4565b905093509350939050565b600048905090565b600043905090565b60008173ffffffffffffffffffffffffffffffffffffffff16319050919050565b600044905090565b606060008383905090508067ffffffffffffffff81111561083e5761083d6112fa565b5b60405190808252806020026020018201604052801561087757816020015b610864610bd5565b81526020019060019003908161085c5790505b5091503660005b828110156109db57600084828151811061089b5761089a611329565b5b602002602001015190508686838181106108b8576108b7611329565b5b90506020028101906108ca919061155b565b92508260000160208101906108df91906111a7565b73ffffffffffffffffffffffffffffffffffffffff16838060400190610905919061138f565b604051610913929190611431565b6000604051808303816000865af19150503d8060008114610950576040519150601f19603f3d011682016040523d82523d6000602084013e610955565b606091505b5082600001836020018290528215151515815250505080516020840135176109cf577f08c379a000000000000000000000000000000000000000000000000000000000600052602060045260176024527f4d756c746963616c6c333a2063616c6c206661696c656400000000000000000060445260646000fd5b8160010191505061087e565b50505092915050565b600045905090565b600041905090565b606060008383905090508067ffffffffffffffff811115610a1857610a176112fa565b5b604051908082528060200260200182016040528015610a5157816020015b610a3e610bd5565b815260200190600190039081610a365790505b5091503660005b82811015610b9c576000848281518110610a7557610a74611329565b5b60200260200101519050868683818110610a9257610a91611329565b5b9050602002810190610aa491906114c7565b9250826000016020810190610ab991906111a7565b73ffffffffffffffffffffffffffffffffffffffff16838060200190610adf919061138f565b604051610aed929190611431565b6000604051808303816000865af19150503d8060008114610b2a576040519150601f19603f3d011682016040523d82523d6000602084013e610b2f565b606091505b508260000183602001829052821515151581525050508715610b90578060000151610b8f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b869061153b565b60405180910390fd5b5b81600101915050610a58565b5050509392505050565b6000806060610bb7600186866107bf565b8093508194508295505050509250925092565b600081409050919050565b6040518060400160405280600015158152602001606081525090565b6000819050919050565b610c0481610bf1565b82525050565b6000602082019050610c1f6000830184610bfb565b92915050565b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b60008083601f840112610c5457610c53610c2f565b5b8235905067ffffffffffffffff811115610c7157610c70610c34565b5b602083019150836020820283011115610c8d57610c8c610c39565b5b9250929050565b60008060208385031215610cab57610caa610c25565b5b600083013567ffffffffffffffff811115610cc957610cc8610c2a565b5b610cd585828601610c3e565b92509250509250929050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b60008115159050919050565b610d2281610d0d565b82525050565b600081519050919050565b600082825260208201905092915050565b60005b83811015610d62578082015181840152602081019050610d47565b83811115610d71576000848401525b50505050565b6000601f19601f8301169050919050565b6000610d9382610d28565b610d9d8185610d33565b9350610dad818560208601610d44565b610db681610d77565b840191505092915050565b6000604083016000830151610dd96000860182610d19565b5060208301518482036020860152610df18282610d88565b9150508091505092915050565b6000610e0a8383610dc1565b905092915050565b6000602082019050919050565b6000610e2a82610ce1565b610e348185610cec565b935083602082028501610e4685610cfd565b8060005b85811015610e825784840389528151610e638582610dfe565b9450610e6e83610e12565b925060208a01995050600181019050610e4a565b50829750879550505050505092915050565b60006020820190508181036000830152610eae8184610e1f565b905092915050565b60008083601f840112610ecc57610ecb610c2f565b5b8235905067ffffffffffffffff811115610ee957610ee8610c34565b5b602083019150836020820283011115610f0557610f04610c39565b5b9250929050565b60008060208385031215610f2357610f22610c25565b5b600083013567ffffffffffffffff811115610f4157610f40610c2a565b5b610f4d85828601610eb6565b92509250509250929050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b6000610f918383610d88565b905092915050565b6000602082019050919050565b6000610fb182610f59565b610fbb8185610f64565b935083602082028501610fcd85610f75565b8060005b858110156110095784840389528151610fea8582610f85565b9450610ff583610f99565b925060208a01995050600181019050610fd1565b50829750879550505050505092915050565b60006040820190506110306000830185610bfb565b81810360208301526110428184610fa6565b90509392505050565b6000819050919050565b61105e8161104b565b82525050565b60006020820190506110796000830184611055565b92915050565b61108881610d0d565b811461109357600080fd5b50565b6000813590506110a58161107f565b92915050565b6000806000604084860312156110c4576110c3610c25565b5b60006110d286828701611096565b935050602084013567ffffffffffffffff8111156110f3576110f2610c2a565b5b6110ff86828701610eb6565b92509250509250925092565b60006060820190506111206000830186610bfb565b61112d6020830185611055565b818103604083015261113f8184610e1f565b9050949350505050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061117482611149565b9050919050565b61118481611169565b811461118f57600080fd5b50565b6000813590506111a18161117b565b92915050565b6000602082840312156111bd576111bc610c25565b5b60006111cb84828501611192565b91505092915050565b60008083601f8401126111ea576111e9610c2f565b5b8235905067ffffffffffffffff81111561120757611206610c34565b5b60208301915083602082028301111561122357611222610c39565b5b9250929050565b6000806020838503121561124157611240610c25565b5b600083013567ffffffffffffffff81111561125f5761125e610c2a565b5b61126b858286016111d4565b92509250509250929050565b61128081611169565b82525050565b600060208201905061129b6000830184611277565b92915050565b6112aa81610bf1565b81146112b557600080fd5b50565b6000813590506112c7816112a1565b92915050565b6000602082840312156112e3576112e2610c25565b5b60006112f1848285016112b8565b91505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600080fd5b600080fd5b600080fd5b60008235600160800383360303811261138357611382611358565b5b80830191505092915050565b600080833560016020038436030381126113ac576113ab611358565b5b80840192508235915067ffffffffffffffff8211156113ce576113cd61135d565b5b6020830192506001820236038313156113ea576113e9611362565b5b509250929050565b600081905092915050565b82818337600083830152505050565b600061141883856113f2565b93506114258385846113fd565b82840190509392505050565b600061143e82848661140c565b91508190509392505050565b600082825260208201905092915050565b7f4d756c746963616c6c333a2076616c7565206d69736d61746368000000000000600082015250565b6000611491601a8361144a565b915061149c8261145b565b602082019050919050565b600060208201905081810360008301526114c081611484565b9050919050565b6000823560016040038336030381126114e3576114e2611358565b5b80830191505092915050565b7f4d756c746963616c6c333a2063616c6c206661696c6564000000000000000000600082015250565b600061152560178361144a565b9150611530826114ef565b602082019050919050565b6000602082019050818103600083015261155481611518565b9050919050565b60008235600160600383360303811261157757611576611358565b5b8083019150509291505056fea264697066735822122020c1bc9aacf8e4a6507193432a895a8e77094f45a1395583f07b24e860ef06cd64736f6c634300080c0033`})),Cp,wp,Tp,Ep,Dp,Op=o((()=>{O(),Cp=class extends D{constructor({blockNumber:e,chain:t,contract:n}){super(`Chain \"${t.name}\" does not support contract \"${n.name}\".`,{metaMessages:[`This could be due to any of the following:`,...e&&n.blockCreated&&n.blockCreated>e?[`- The contract \"${n.name}\" was not deployed until block ${n.blockCreated} (current block ${e}).`]:[`- The chain does not have the contract \"${n.name}\" configured.`]],name:`ChainDoesNotSupportContract`})}},wp=class extends D{constructor({chain:e,currentChainId:t}){super(`The current chain of the wallet (id: ${t}) does not match the target chain for the transaction (id: ${e.id} – ${e.name}).`,{metaMessages:[`Current Chain ID:  ${t}`,`Expected Chain ID: ${e.id} – ${e.name}`],name:`ChainMismatchError`})}},Tp=class extends D{constructor(){super([`No chain was provided to the request.`,\"Please provide a chain with the `chain` argument on the Action, or by supplying a `chain` to WalletClient.\"].join(`\n`),{name:`ChainNotFoundError`})}},Ep=class extends D{constructor(){super(`No chain was provided to the Client.`,{name:`ClientChainNotConfiguredError`})}},Dp=class extends D{constructor({chainId:e}){super(typeof e==`number`?`Chain ID \"${e}\" is invalid.`:`Chain ID is invalid.`,{name:`InvalidChainIdError`})}}}));function kp(e){let{abi:t,args:n,bytecode:r}=e;if(!n||n.length===0)return r;let i=t.find(e=>`type`in e&&e.type===`constructor`);if(!i)throw new Vt({docsPath:Ap});if(!(`inputs`in i)||!i.inputs||i.inputs.length===0)throw new Ht({docsPath:Ap});let a=Li(i.inputs,n);return Ei([r,a])}var Ap,jp=o((()=>{sn(),Di(),Yi(),Ap=`/docs/contract/encodeDeployData`}));function Mp({blockNumber:e,chain:t,contract:n}){let r=t?.contracts?.[n];if(!r)throw new Cp({chain:t,contract:{name:n}});if(e&&r.blockCreated&&r.blockCreated>e)throw new Cp({blockNumber:e,chain:t,contract:{name:n,blockCreated:r.blockCreated}});return r.address}var Np=o((()=>{Op()}));function Pp(e,{docsPath:t,...n}){let r=(()=>{let t=Nu(e,n);return t instanceof ju?e:t})();return new yo(r,{docsPath:t,...n})}var Fp=o((()=>{To(),Mu(),Pu()}));function Ip(){let e=()=>void 0,t=()=>void 0;return{promise:new Promise((n,r)=>{e=n,t=r}),resolve:e,reject:t}}var Lp=o((()=>{}));function Rp({fn:e,id:t,shouldSplitBatch:n,wait:r=0,sort:i}){let a=async()=>{let t=c();o();let n=t.map(({args:e})=>e);n.length!==0&&e(n).then(e=>{i&&Array.isArray(e)&&e.sort(i);for(let n=0;n<t.length;n++){let{resolve:r}=t[n];r?.([e[n],e])}}).catch(e=>{for(let n=0;n<t.length;n++){let{reject:r}=t[n];r?.(e)}})},o=()=>zp.delete(t),s=()=>c().map(({args:e})=>e),c=()=>zp.get(t)||[],l=e=>zp.set(t,[...c(),e]);return{flush:o,async schedule(e){let{promise:t,resolve:i,reject:o}=Ip();return n?.([...s(),e])&&a(),c().length>0?(l({args:e,resolve:i,reject:o}),t):(l({args:e,resolve:i,reject:o}),setTimeout(a,r),t)}}}var zp,Bp=o((()=>{Lp(),zp=new Map})),Vp,Hp,Up,Wp=o((()=>{Va(),O(),vo(),Vp=class extends D{constructor({callbackSelector:e,cause:t,data:n,extraData:r,sender:i,urls:a}){super(t.shortMessage||`An error occurred while fetching for an offchain result.`,{cause:t,metaMessages:[...t.metaMessages||[],t.metaMessages?.length?``:[],`Offchain Gateway Call:`,a&&[`  Gateway URL(s):`,...a.map(e=>`    ${_o(e)}`)],`  Sender: ${i}`,`  Data: ${n}`,`  Callback selector: ${e}`,`  Extra data: ${r}`].flat(),name:`OffchainLookupError`})}},Hp=class extends D{constructor({result:e,url:t}){super(`Offchain gateway response is malformed. Response data must be a hex value.`,{metaMessages:[`Gateway URL: ${_o(t)}`,`Response: ${Ba(e)}`],name:`OffchainLookupResponseMalformedError`})}},Up=class extends D{constructor({sender:e,to:t}){super(\"Reverted sender address does not match target contract address (`to`).\",{metaMessages:[`Contract address: ${t}`,`OffchainLookup sender address: ${e}`],name:`OffchainLookupSenderMismatchError`})}}}));function Gp(e){let{abi:t,data:n}=e,r=Oi(n,0,4),i=t.find(e=>e.type===`function`&&r===Xi(kt(e)));if(!i)throw new $t(r,{docsPath:`/docs/contract/decodeFunctionData`});return{functionName:i.name,args:`inputs`in i&&i.inputs&&i.inputs.length>0?Ta(i.inputs,Oi(n,4)):void 0}}var Kp=o((()=>{sn(),Ni(),Zi(),La(),Mt()}));function qp(e){let{abi:t,errorName:n,args:r}=e,i=t[0];if(n){let e=Qi({abi:t,args:r,name:n});if(!e)throw new Yt(n,{docsPath:Jp});i=e}if(i.type!==`error`)throw new Yt(void 0,{docsPath:Jp});let a=kt(i),o=Xi(a),s=`0x`;if(r&&r.length>0){if(!i.inputs)throw new Jt(i.name,{docsPath:Jp});s=Li(i.inputs,r)}return Ei([o,s])}var Jp,Yp=o((()=>{sn(),Di(),Zi(),Yi(),Mt(),ta(),Jp=`/docs/contract/encodeErrorResult`}));function Xp(e){let{abi:t,functionName:n,result:r}=e,i=t[0];if(n){let e=Qi({abi:t,name:n});if(!e)throw new Zt(n,{docsPath:Zp});i=e}if(i.type!==`function`)throw new Zt(void 0,{docsPath:Zp});if(!i.outputs)throw new Qt(i.name,{docsPath:Zp});let a=(()=>{if(i.outputs.length===0)return[];if(i.outputs.length===1)return[r];if(Array.isArray(r))return r;throw new an(r)})();return Li(i.outputs,a)}var Zp,Qp=o((()=>{sn(),Yi(),ta(),Zp=`/docs/contract/encodeFunctionResult`}));async function $p(e){let{data:t,ccipRequest:n}=e,{args:[r]}=Gp({abi:fp,data:t}),i=[],a=[];return await Promise.all(r.map(async(e,t)=>{try{a[t]=e.urls.includes(`x-batch-gateway:true`)?await $p({data:e.data,ccipRequest:n}):await n(e),i[t]=!1}catch(e){i[t]=!0,a[t]=em(e)}})),Xp({abi:fp,functionName:`query`,result:[i,a]})}function em(e){return e.name===`HttpRequestError`&&e.status?qp({abi:fp,errorName:`HttpError`,args:[e.status,e.shortMessage]}):qp({abi:[ua],errorName:`Error`,args:[`shortMessage`in e?e.shortMessage:e.message]})}var tm=o((()=>{gp(),fa(),Kp(),Yp(),Qp()})),nm=c({ccipRequest:()=>im,offchainLookup:()=>rm,offchainLookupAbiItem:()=>om,offchainLookupSignature:()=>am});async function rm(e,{blockNumber:t,blockTag:n,data:r,to:i}){let{args:a}=Ra({data:r,abi:[om]}),[o,s,c,l,u]=a,{ccipRead:d}=e,f=d&&typeof d?.request==`function`?d.request:im;try{if(!Ld(i,o))throw new Up({sender:o,to:i});let r=s.includes(`x-batch-gateway:true`)?await $p({data:c,ccipRequest:f}):await f({data:c,sender:o,urls:s}),{data:a}=await cm(e,{blockNumber:t,blockTag:n,data:wi([l,Li([{type:`bytes`},{type:`bytes`}],[r,u])]),to:i});return a}catch(e){throw new Vp({callbackSelector:l,cause:e,data:r,extraData:u,sender:o,urls:s})}}async function im({data:e,sender:t,urls:n}){let r=Error(`An unknown error occurred.`);for(let i=0;i<n.length;i++){let a=n[i],o=a.includes(`{data}`)?`GET`:`POST`,s=o===`POST`?{data:e,sender:t}:void 0,c=o===`POST`?{\"Content-Type\":`application/json`}:{};try{let n=await fetch(a.replace(`{sender}`,t.toLowerCase()).replace(`{data}`,e),{body:JSON.stringify(s),headers:c,method:o}),i;if(i=n.headers.get(`Content-Type`)?.startsWith(`application/json`)?(await n.json()).data:await n.text(),!n.ok){r=new Eo({body:s,details:i?.error?Ba(i.error):n.statusText,headers:n.headers,status:n.status,url:a});continue}if(!Nt(i)){r=new Hp({result:i,url:a});continue}return i}catch(e){r=new Eo({body:s,details:e.message,url:a})}}throw r}var am,om,sm=o((()=>{mm(),Wp(),ko(),za(),Yi(),Rd(),Di(),Pt(),tm(),Va(),am=`0x556f1830`,om={name:`OffchainLookup`,type:`error`,inputs:[{name:`sender`,type:`address`},{name:`urls`,type:`string[]`},{name:`callData`,type:`bytes`},{name:`callbackFunction`,type:`bytes4`},{name:`extraData`,type:`bytes`}]}}));async function cm(e,t){let{account:n=e.account,authorizationList:r,batch:i=!!e.batch?.multicall,blockNumber:a,blockTag:o=e.experimental_blockTag??`latest`,accessList:s,blobs:c,blockOverrides:l,code:u,data:d,factory:f,factoryData:p,gas:m,gasPrice:h,maxFeePerBlobGas:g,maxFeePerGas:_,maxPriorityFeePerGas:v,nonce:y,to:b,value:x,stateOverride:S,...C}=t,w=n?na(n):void 0;if(u&&(f||p))throw new D(\"Cannot provide both `code` & `factory`/`factoryData` as parameters.\");if(u&&b)throw new D(\"Cannot provide both `code` & `to` as parameters.\");let ee=u&&d,te=f&&p&&b&&d,ne=ee||te,re=(()=>ee?dm({code:u,data:d}):te?fm({data:d,factory:f,factoryData:p,to:b}):d)();try{Qu(t);let n=(typeof a==`bigint`?k(a):void 0)||o,u=l?lp(l):void 0,d=qu(S),f=e.chain?.formatters?.transactionRequest?.format,p=(f||Bu)({...Iu(C,{format:f}),from:w?.address,accessList:s,authorizationList:r,blobs:c,data:re,gas:m,gasPrice:h,maxFeePerBlobGas:g,maxFeePerGas:_,maxPriorityFeePerGas:v,nonce:y,to:ne?void 0:b,value:x},`call`);if(i&&lm({request:p})&&!d&&!u)try{return await um(e,{...p,blockNumber:a,blockTag:o})}catch(e){if(!(e instanceof Ep)&&!(e instanceof Cp))throw e}let ee=(()=>{let e=[p,n];return d&&u?[...e,d,u]:d?[...e,d]:u?[...e,{},u]:e})(),te=await e.request({method:`eth_call`,params:ee});return te===`0x`?{data:void 0}:{data:te}}catch(n){let r=pm(n),{offchainLookup:i,offchainLookupSignature:a}=await ps(async()=>{let{offchainLookup:e,offchainLookupSignature:t}=await Promise.resolve().then(()=>(sm(),nm));return{offchainLookup:e,offchainLookupSignature:t}},void 0);if(e.ccipRead!==!1&&r?.slice(0,10)===a&&b)return{data:await i(e,{data:r,to:b})};throw ne&&r?.slice(0,10)===`0x101bb98d`?new Co({factory:f}):Pp(n,{...t,account:w,chain:e.chain})}}function lm({request:e}){let{data:t,to:n,...r}=e;return!(!t||t.startsWith(`0x82ad56cb`)||!n||Object.values(r).filter(e=>e!==void 0).length>0)}async function um(e,t){let{batchSize:n=1024,deployless:r=!1,wait:i=0}=typeof e.batch?.multicall==`object`?e.batch.multicall:{},{blockNumber:a,blockTag:o=e.experimental_blockTag??`latest`,data:s,to:c}=t,l=(()=>{if(r)return null;if(t.multicallAddress)return t.multicallAddress;if(e.chain)return Mp({blockNumber:a,chain:e.chain,contract:`multicall3`});throw new Ep})(),u=(typeof a==`bigint`?k(a):void 0)||o,{schedule:d}=Rp({id:`${e.uid}.${u}`,wait:i,shouldSplitBatch(e){return e.reduce((e,{data:t})=>e+(t.length-2),0)>n*2},fn:async t=>{let n=t.map(e=>({allowFailure:!0,callData:e.data,target:e.to})),r=sa({abi:dp,args:[n],functionName:`aggregate3`}),i=await e.request({method:`eth_call`,params:[{...l===null?{data:dm({code:xp,data:r})}:{to:l,data:r}},u]});return Bd({abi:dp,args:[n],functionName:`aggregate3`,data:i||`0x`})}}),[{returnData:f,success:p}]=await d({data:s,to:c});if(!p)throw new wo({data:f});return f===`0x`?{data:void 0}:{data:f}}function dm(e){let{code:t,data:n}=e;return kp({abi:St([`constructor(bytes, bytes)`]),bytecode:vp,args:[t,n]})}function fm(e){let{data:t,factory:n,factoryData:r,to:i}=e;return kp({abi:St([`constructor(address, bytes, address, bytes)`]),bytecode:yp,args:[i,t,n,r]})}function pm(e){if(!(e instanceof D))return;let t=e.walk();return typeof t?.data==`object`?t.data?.data:t.data}var mm=o((()=>{Ot(),up(),ra(),gp(),_p(),Sp(),O(),Op(),To(),Hd(),jp(),ca(),Np(),A(),Fp(),Lu(),Wu(),Bp(),Ju(),$u(),ms()}));Hd(),ca(),mm();async function hm(e,t){let{abi:n,address:r,args:i,functionName:a,...o}=t,s=sa({abi:n,args:i,functionName:a});try{let{data:t}=await E(e,cm,`call`)({...o,data:s,to:r});return Bd({abi:n,args:i,functionName:a,data:t||`0x`})}catch(e){throw cs(e,{abi:n,address:r,args:i,docsPath:`/docs/contract/readContract`,functionName:a})}}const gm=new Map,_m=new Map;var vm=0;function ym(e,t,n){let r=++vm,i=()=>gm.get(e)||[],a=()=>{let t=i();gm.set(e,t.filter(e=>e.id!==r))},o=()=>{let t=i();if(!t.some(e=>e.id===r))return;let n=_m.get(e);if(t.length===1&&n){let e=n();e instanceof Promise&&e.catch(()=>{})}a()},s=i();if(gm.set(e,[...s,{id:r,fns:t}]),s&&s.length>0)return o;let c={};for(let e in t)c[e]=((...t)=>{let n=i();if(n.length!==0)for(let r of n)r.fns[e]?.(...t)});let l=n(c);return typeof l==`function`&&_m.set(e,l),o}async function bm(e){return new Promise(t=>setTimeout(t,e))}function xm(e,{emitOnBegin:t,initialWaitTime:n,interval:r}){let i=!0,a=()=>i=!1;return(async()=>{let o;t&&(o=await e({unpoll:a}));let s=await n?.(o)??r;await bm(s);let c=async()=>{i&&(await e({unpoll:a}),await bm(r),c())};c()})(),a}const Sm=new Map,Cm=new Map;function wm(e){let t=(e,t)=>({clear:()=>t.delete(e),get:()=>t.get(e),set:n=>t.set(e,n)}),n=t(e,Sm),r=t(e,Cm);return{clear:()=>{n.clear(),r.clear()},promise:n,response:r}}async function Tm(e,{cacheKey:t,cacheTime:n=1/0}){let r=wm(t),i=r.response.get();if(i&&n>0&&Date.now()-i.created.getTime()<n)return i.data;let a=r.promise.get();a||(a=e(),r.promise.set(a));try{let e=await a;return r.response.set({created:new Date,data:e}),e}finally{r.promise.clear()}}var Em=e=>`blockNumber.${e}`;async function Dm(e,{cacheTime:t=e.cacheTime}={}){let n=await Tm(()=>e.request({method:`eth_blockNumber`}),{cacheKey:Em(e.uid),cacheTime:t});return BigInt(n)}O();var Om=class extends D{constructor({docsPath:e}={}){super([`Could not find an Account to execute with this Action.`,\"Please provide an Account with the `account` argument on the Action, or by supplying an `account` to the Client.\"].join(`\n`),{docsPath:e,docsSlug:`account`,name:`AccountNotFoundError`})}},km=class extends D{constructor({docsPath:e,metaMessages:t,type:n}){super(`Account type \"${n}\" is not supported.`,{docsPath:e,metaMessages:t,name:`AccountTypeNotSupportedError`})}};Op();function Am({chain:e,currentChainId:t}){if(!e)throw new Tp;if(t!==e.id)throw new wp({chain:e,currentChainId:t})}Mu(),ho(),Pu();function jm(e,{docsPath:t,...n}){let r=(()=>{let t=Nu(e,n);return t instanceof ju?e:t})();return new lo(r,{docsPath:t,...n})}async function Mm(e,{serializedTransaction:t}){return e.request({method:`eth_sendRawTransaction`,params:[t]},{retryCount:0})}ra(),O(),Lu(),Wu(),hi(),$u();var Nm=new mi(128);async function Pm(e,t){let{account:n=e.account,chain:r=e.chain,accessList:i,authorizationList:a,blobs:o,data:s,gas:c,gasPrice:l,maxFeePerBlobGas:u,maxFeePerGas:d,maxPriorityFeePerGas:f,nonce:p,type:m,value:h,...g}=t;if(n===void 0)throw new Om({docsPath:`/docs/actions/wallet/sendTransaction`});let _=n?na(n):null;try{Qu(t);let n=await(async()=>{if(t.to)return t.to;if(t.to!==null&&a&&a.length>0)return await vu({authorization:a[0]}).catch(()=>{throw new D(\"`to` is required. Could not infer from `authorizationList`.\")})})();if(_?.type===`json-rpc`||_===null){let t;r!==null&&(t=await E(e,Md,`getChainId`)({}),Am({currentChainId:t,chain:r}));let v=e.chain?.formatters?.transactionRequest?.format,y=(v||Bu)({...Iu(g,{format:v}),accessList:i,authorizationList:a,blobs:o,chainId:t,data:s,from:_?.address,gas:c,gasPrice:l,maxFeePerBlobGas:u,maxFeePerGas:d,maxPriorityFeePerGas:f,nonce:p,to:n,type:m,value:h},`sendTransaction`),b=Nm.get(e.uid),x=b?`wallet_sendTransaction`:`eth_sendTransaction`;try{return await e.request({method:x,params:[y]},{retryCount:0})}catch(t){if(b===!1)throw t;let n=t;if(n.name===`InvalidInputRpcError`||n.name===`InvalidParamsRpcError`||n.name===`MethodNotFoundRpcError`||n.name===`MethodNotSupportedRpcError`)return await e.request({method:`wallet_sendTransaction`,params:[y]},{retryCount:0}).then(t=>(Nm.set(e.uid,!0),t)).catch(t=>{let r=t;throw r.name===`MethodNotFoundRpcError`||r.name===`MethodNotSupportedRpcError`?(Nm.set(e.uid,!1),n):r});throw n}}if(_?.type===`local`){let t=await E(e,Fd,`prepareTransactionRequest`)({account:_,accessList:i,authorizationList:a,blobs:o,chain:r,data:s,gas:c,gasPrice:l,maxFeePerBlobGas:u,maxFeePerGas:d,maxPriorityFeePerGas:f,nonce:p,nonceManager:_.nonceManager,parameters:[...Nd,`sidecars`],type:m,value:h,...g,to:n}),v=r?.serializers?.transaction,y=await _.signTransaction(t,{serializer:v});return await E(e,Mm,`sendRawTransaction`)({serializedTransaction:y})}throw _?.type===`smart`?new km({metaMessages:[\"Consider using the `sendUserOperation` Action instead.\"],docsPath:`/docs/actions/bundler/sendUserOperation`,type:`smart`}):new km({docsPath:`/docs/actions/wallet/sendTransaction`,type:_?.type})}catch(e){throw e instanceof km?e:jm(e,{...t,account:_,chain:t.chain||void 0})}}ra(),ca();async function Fm(e,t){return Fm.internal(e,Pm,`sendTransaction`,t)}(function(e){async function t(e,t,n,r){let{abi:i,account:a=e.account,address:o,args:s,dataSuffix:c,functionName:l,...u}=r;if(a===void 0)throw new Om({docsPath:`/docs/contract/writeContract`});let d=a?na(a):null,f=sa({abi:i,args:s,functionName:l});try{return await E(e,t,n)({data:`${f}${c?c.replace(`0x`,``):``}`,to:o,account:d,...u})}catch(e){throw cs(e,{abi:i,address:o,args:s,docsPath:`/docs/contract/writeContract`,functionName:l,sender:d?.address})}}e.internal=t})(Fm||={}),O();var Im=class extends D{constructor(e){super(`Call bundle failed with status: ${e.statusCode}`,{name:`BundleFailedError`}),Object.defineProperty(this,`result`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.result=e}};function Lm(e,{delay:t=100,retryCount:n=2,shouldRetry:r=()=>!0}={}){return new Promise((i,a)=>{let o=async({count:s=0}={})=>{let c=async({error:e})=>{let n=typeof t==`function`?t({count:s,error:e}):t;n&&await bm(n),o({count:s+1})};try{let t=await e();i(t)}catch(e){if(s<n&&await r({count:s,error:e}))return c({error:e});a(e)}};o()})}Dn(),zu();const Rm={\"0x0\":`reverted`,\"0x1\":`success`};function zm(e,t){let n={...e,blockNumber:e.blockNumber?BigInt(e.blockNumber):null,contractAddress:e.contractAddress?e.contractAddress:null,cumulativeGasUsed:e.cumulativeGasUsed?BigInt(e.cumulativeGasUsed):null,effectiveGasPrice:e.effectiveGasPrice?BigInt(e.effectiveGasPrice):null,gasUsed:e.gasUsed?BigInt(e.gasUsed):null,logs:e.logs?e.logs.map(e=>zd(e)):null,to:e.to?e.to:null,transactionIndex:e.transactionIndex?En(e.transactionIndex):null,status:e.status?Rm[e.status]:null,type:e.type?id[e.type]||e.type:null};return e.blobGasPrice&&(n.blobGasPrice=BigInt(e.blobGasPrice)),e.blobGasUsed&&(n.blobGasUsed=BigInt(e.blobGasUsed)),n}const Bm=Ru(`transactionReceipt`,zm);ra(),O(),os(),ca(),Di(),Dn(),A();const Vm=k(0,{size:32});async function Hm(e,t){let{account:n=e.account,capabilities:r,chain:i=e.chain,experimental_fallback:a,experimental_fallbackDelay:o=32,forceAtomic:s=!1,id:c,version:l=`2.0.0`}=t,u=n?na(n):null,d=t.calls.map(e=>{let t=e,n=t.abi?sa({abi:t.abi,functionName:t.functionName,args:t.args}):t.data;return{data:t.dataSuffix&&n?wi([n,t.dataSuffix]):n,to:t.to,value:t.value?k(t.value):void 0}});try{let t=await e.request({method:`wallet_sendCalls`,params:[{atomicRequired:s,calls:d,capabilities:r,chainId:k(i.id),from:u?.address,id:c,version:l}]},{retryCount:0});return typeof t==`string`?{id:t}:t}catch(n){let c=n;if(a&&(c.name===`MethodNotFoundRpcError`||c.name===`MethodNotSupportedRpcError`||c.name===`UnknownRpcError`||c.details.toLowerCase().includes(`does not exist / is not available`)||c.details.toLowerCase().includes(`missing or invalid. request()`)||c.details.toLowerCase().includes(`did not match any variant of untagged enum`)||c.details.toLowerCase().includes(`account upgraded to unsupported contract`)||c.details.toLowerCase().includes(`eip-7702 not supported`)||c.details.toLowerCase().includes(`unsupported wc_ method`)||c.details.toLowerCase().includes(`feature toggled misconfigured`)||c.details.toLowerCase().includes(`jsonrpcengine: response has no error or result for request`))){if(r&&Object.values(r).some(e=>!e.optional)){let e=\"non-optional `capabilities` are not supported on fallback to `eth_sendTransaction`.\";throw new Xo(new D(e,{details:e}))}if(s&&d.length>1){let e=\"`forceAtomic` is not supported on fallback to `eth_sendTransaction`.\";throw new ns(new D(e,{details:e}))}let t=[];for(let n of d){let r=Pm(e,{account:u,chain:i,data:n.data,to:n.to,value:n.value?wn(n.value):void 0});t.push(r),o>0&&await new Promise(e=>setTimeout(e,o))}let n=await Promise.allSettled(t);if(n.every(e=>e.status===`rejected`))throw n[0].reason;let a=n.map(e=>e.status===`fulfilled`?e.value:Vm);return{id:wi([...a,k(i.id,{size:32}),`0x5792579257925792579257925792579257925792579257925792579257925792`])}}throw jm(n,{...t,account:u,chain:t.chain})}}Ni(),Sn(),Dn();async function Um(e,t){async function n(t){if(t.endsWith(`5792579257925792579257925792579257925792579257925792579257925792`)){let n=xn(Mi(t,-64,-32)),r=Mi(t,0,-64).slice(2).match(/.{1,64}/g),i=await Promise.all(r.map(t=>Vm.slice(2)===t?void 0:e.request({method:`eth_getTransactionReceipt`,params:[`0x${t}`]},{dedupe:!0}))),a=(()=>i.some(e=>e===null)?100:i.every(e=>e?.status===`0x1`)?200:i.every(e=>e?.status===`0x0`)?500:600)();return{atomic:!1,chainId:En(n),receipts:i.filter(Boolean),status:a,version:`2.0.0`}}return e.request({method:`wallet_getCallsStatus`,params:[t]})}let{atomic:r=!1,chainId:i,receipts:a,version:o=`2.0.0`,...s}=await n(t.id),[c,l]=(()=>{let e=s.status;return e>=100&&e<200?[`pending`,e]:e>=200&&e<300?[`success`,e]:e>=300&&e<700?[`failure`,e]:e===`CONFIRMED`?[`success`,200]:e===`PENDING`?[`pending`,100]:[void 0,e]})();return{...s,atomic:r,chainId:i?En(i):void 0,receipts:a?.map(e=>({...e,blockNumber:wn(e.blockNumber),gasUsed:wn(e.gasUsed),status:Rm[e.status]}))??[],statusCode:l,status:c,version:o}}O(),Lp(),Va();async function Wm(e,t){let{id:n,pollingInterval:r=e.pollingInterval,status:i=({statusCode:e})=>e===200||e>=300,retryCount:a=4,retryDelay:o=({count:e})=>~~(1<<e)*200,timeout:s=6e4,throwOnFailure:c=!1}=t,l=Ba([`waitForCallsStatus`,e.uid,n]),{promise:u,resolve:d,reject:f}=Ip(),p,m=ym(l,{resolve:d,reject:f},t=>{let s=xm(async()=>{let r=e=>{clearTimeout(p),s(),e(),m()};try{let s=await Lm(async()=>{let t=await E(e,Um,`getCallsStatus`)({id:n});if(c&&t.status===`failure`)throw new Im(t);return t},{retryCount:a,delay:o});if(!i(s))return;r(()=>t.resolve(s))}catch(e){r(()=>t.reject(e))}},{interval:r,emitOnBegin:!0});return s});return p=s?setTimeout(()=>{m(),clearTimeout(p),f(new Gm({id:n}))},s):void 0,await u}var Gm=class extends D{constructor({id:e}){super(`Timed out while waiting for call bundle with id \"${e}\" to be confirmed.`,{name:`WaitForCallsStatusTimeoutError`})}},Km=256,qm=Km,Jm;function Ym(e=11){if(!Jm||qm+e>Km*2){Jm=``,qm=0;for(let e=0;e<Km;e++)Jm+=(256+Math.random()*256|0).toString(16).substring(1)}return Jm.substring(qm,qm+++e)}ra();function Xm(e){let{batch:t,chain:n,ccipRead:r,key:i=`base`,name:a=`Base Client`,type:o=`base`}=e,s=e.experimental_blockTag??(typeof n?.experimental_preconfirmationTime==`number`?`pending`:void 0),c=n?.blockTime??12e3,l=Math.min(Math.max(Math.floor(c/2),500),4e3),u=e.pollingInterval??l,d=e.cacheTime??u,f=e.account?na(e.account):void 0,{config:p,request:m,value:h}=e.transport({chain:n,pollingInterval:u}),g={...p,...h},_={account:f,batch:t,cacheTime:d,ccipRead:r,chain:n,key:i,name:a,pollingInterval:u,request:m,transport:g,type:o,uid:Ym(),...s?{experimental_blockTag:s}:{}};function v(e){return t=>{let n=t(e);for(let e in _)delete n[e];let r={...e,...n};return Object.assign(r,{extend:v(r)})}}return Object.assign(_,{extend:v(_)})}A();async function Zm(e,{address:t,blockNumber:n,blockTag:r=`latest`}){let i=n===void 0?void 0:k(n),a=await e.request({method:`eth_getCode`,params:[t,i||r]},{dedupe:!!i});if(a!==`0x`)return a}O();var Qm=class extends D{constructor({address:e}){super(`No EIP-712 domain found on contract \"${e}\".`,{metaMessages:[`Ensure that:`,`- The contract is deployed at the address \"${e}\".`,\"- `eip712Domain()` function exists on the contract.\",\"- `eip712Domain()` function matches signature to ERC-5267 specification.\"],name:`Eip712DomainNotFoundError`})}};async function $m(e,t){let{address:n,factory:r,factoryData:i}=t;try{let[t,a,o,s,c,l,u]=await E(e,hm,`readContract`)({abi:eh,address:n,functionName:`eip712Domain`,factory:r,factoryData:i});return{domain:{name:a,version:o,chainId:Number(s),verifyingContract:c,salt:l},extensions:u,fields:t}}catch(e){let t=e;throw t.name===`ContractFunctionExecutionError`&&t.cause.name===`ContractFunctionZeroDataError`?new Qm({address:n}):t}}var eh=[{inputs:[],name:`eip712Domain`,outputs:[{name:`fields`,type:`bytes1`},{name:`name`,type:`string`},{name:`version`,type:`string`},{name:`chainId`,type:`uint256`},{name:`verifyingContract`,type:`address`},{name:`salt`,type:`bytes32`},{name:`extensions`,type:`uint256[]`}],stateMutability:`view`,type:`function`}];Zu(),pi(),O(),Op(),Mu(),Ci(),It(),Ni(),Dn();function th(e){let{authorizationList:t}=e;if(t)for(let e of t){let{chainId:t}=e,n=e.address;if(!bi(n))throw new fi({address:n});if(t<0)throw new Dp({chainId:t})}rh(e)}function nh(e){let{blobVersionedHashes:t}=e;if(t){if(t.length===0)throw new Ed;for(let e of t){let t=Ft(e),n=En(Oi(e,0,1));if(t!==32)throw new Dd({hash:e,size:t});if(n!==1)throw new Od({hash:e,version:n})}}rh(e)}function rh(e){let{chainId:t,maxPriorityFeePerGas:n,maxFeePerGas:r,to:i}=e;if(t<=0)throw new Dp({chainId:t});if(i&&!bi(i))throw new fi({address:i});if(r&&r>Xu)throw new xu({maxFeePerGas:r});if(n&&r&&n>r)throw new Au({maxFeePerGas:r,maxPriorityFeePerGas:n})}function ih(e){let{chainId:t,maxPriorityFeePerGas:n,gasPrice:r,maxFeePerGas:i,to:a}=e;if(t<=0)throw new Dp({chainId:t});if(a&&!bi(a))throw new fi({address:a});if(n||i)throw new D(\"`maxFeePerGas`/`maxPriorityFeePerGas` is not a valid EIP-2930 Transaction attribute.\");if(r&&r>Xu)throw new xu({maxFeePerGas:r})}function ah(e){let{chainId:t,maxPriorityFeePerGas:n,gasPrice:r,maxFeePerGas:i,to:a}=e;if(a&&!bi(a))throw new fi({address:a});if(t!==void 0&&t<=0)throw new Dp({chainId:t});if(n||i)throw new D(\"`maxFeePerGas`/`maxPriorityFeePerGas` is not a valid Legacy Transaction attribute.\");if(r&&r>Xu)throw new xu({maxFeePerGas:r})}pi(),ho(),Ci();function oh(e){if(!e||e.length===0)return[];let t=[];for(let n=0;n<e.length;n++){let{address:r,storageKeys:i}=e[n];for(let e=0;e<i.length;e++)if(i[e].length-2!=64)throw new co({storageKey:i[e]});if(!bi(r,{strict:!1}))throw new fi({address:r});t.push([r,i])}return t}ho(),Di(),Sn(),A();function sh(e,t){let n=jd(e);return n===`eip1559`?uh(e,t):n===`eip2930`?dh(e,t):n===`eip4844`?lh(e,t):n===`eip7702`?ch(e,t):fh(e,t)}function ch(e,t){let{authorizationList:n,chainId:r,gas:i,nonce:a,to:o,value:s,maxFeePerGas:c,maxPriorityFeePerGas:l,accessList:u,data:d}=e;th(e);let f=oh(u),p=mh(n);return Ei([`0x04`,M([k(r),a?k(a):`0x`,l?k(l):`0x`,c?k(c):`0x`,i?k(i):`0x`,o??`0x`,s?k(s):`0x`,d??`0x`,f,p,...ph(e,t)])])}function lh(e,t){let{chainId:n,gas:r,nonce:i,to:a,value:o,maxFeePerBlobGas:s,maxFeePerGas:c,maxPriorityFeePerGas:l,accessList:u,data:d}=e;nh(e);let f=e.blobVersionedHashes,p=e.sidecars;if(e.blobs&&(f===void 0||p===void 0)){let t=typeof e.blobs[0]==`string`?e.blobs:e.blobs.map(e=>An(e)),n=e.kzg,r=hd({blobs:t,kzg:n});if(f===void 0&&(f=bd({commitments:r})),p===void 0){let e=gd({blobs:t,commitments:r,kzg:n});p=Ad({blobs:t,commitments:r,proofs:e})}}let m=oh(u),h=[k(n),i?k(i):`0x`,l?k(l):`0x`,c?k(c):`0x`,r?k(r):`0x`,a??`0x`,o?k(o):`0x`,d??`0x`,m,s?k(s):`0x`,f??[],...ph(e,t)],g=[],_=[],v=[];if(p)for(let e=0;e<p.length;e++){let{blob:t,commitment:n,proof:r}=p[e];g.push(t),_.push(n),v.push(r)}return Ei([`0x03`,M(p?[h,g,_,v]:h)])}function uh(e,t){let{chainId:n,gas:r,nonce:i,to:a,value:o,maxFeePerGas:s,maxPriorityFeePerGas:c,accessList:l,data:u}=e;rh(e);let d=oh(l),f=[k(n),i?k(i):`0x`,c?k(c):`0x`,s?k(s):`0x`,r?k(r):`0x`,a??`0x`,o?k(o):`0x`,u??`0x`,d,...ph(e,t)];return Ei([`0x02`,M(f)])}function dh(e,t){let{chainId:n,gas:r,data:i,nonce:a,to:o,value:s,accessList:c,gasPrice:l}=e;ih(e);let u=oh(c),d=[k(n),a?k(a):`0x`,l?k(l):`0x`,r?k(r):`0x`,o??`0x`,s?k(s):`0x`,i??`0x`,u,...ph(e,t)];return Ei([`0x01`,M(d)])}function fh(e,t){let{chainId:n=0,gas:r,data:i,nonce:a,to:o,value:s,gasPrice:c}=e;ah(e);let l=[a?k(a):`0x`,c?k(c):`0x`,r?k(r):`0x`,o??`0x`,s?k(s):`0x`,i??`0x`];if(t){let e=(()=>{if(t.v>=35n)return(t.v-35n)/2n>0?t.v:27n+(t.v===35n?0n:1n);if(n>0)return BigInt(n*2)+BigInt(35n+t.v-27n);let e=27n+(t.v===27n?0n:1n);if(t.v!==e)throw new oo({v:t.v});return e})(),r=xn(t.r),i=xn(t.s);l=[...l,k(e),r===`0x00`?`0x`:r,i===`0x00`?`0x`:i]}else n>0&&(l=[...l,k(n),`0x`,`0x`]);return M(l)}function ph(e,t){let n=t??e,{v:r,yParity:i}=n;if(n.r===void 0||n.s===void 0||r===void 0&&i===void 0)return[];let a=xn(n.r),o=xn(n.s);return[(()=>typeof i==`number`?i?k(1):`0x`:r===0n?`0x`:r===1n?k(1):r===27n?`0x`:k(1))(),a===`0x00`?`0x`:a,o===`0x00`?`0x`:o]}A();function mh(e){if(!e||e.length===0)return[];let t=[];for(let n of e){let{chainId:e,nonce:r,...i}=n,a=n.address;t.push([e?On(e):`0x`,a,r?On(r):`0x`,...ph({},i)])}return t}yi(),Rd();async function hh({address:e,authorization:t,signature:n}){return Ld(_i(e),await vu({authorization:t,signature:n}))}hi();const gh=new mi(8192);function _h(e,{enabled:t=!0,id:n}){if(!t||!n)return e();if(gh.get(n))return gh.get(n);let r=e().finally(()=>gh.delete(n));return gh.set(n,r),r}O(),ko(),os(),A(),Va();function vh(e,t={}){return async(n,r={})=>{let{dedupe:i=!1,methods:a,retryDelay:o=150,retryCount:s=3,uid:c}={...t,...r},{method:l}=n;if(a?.exclude?.includes(l)||a?.include&&!a.include.includes(l))throw new Vo(Error(`method not supported`),{method:l});let u=i?jn(`${c}.${Ba(n)}`):void 0;return _h(()=>Lm(async()=>{try{return await e(n)}catch(e){let t=e;switch(t.code){case No.code:throw new No(t);case j.code:throw new j(t);case Po.code:throw new Po(t,{method:n.method});case Fo.code:throw new Fo(t);case Io.code:throw new Io(t);case Lo.code:throw new Lo(t);case Ro.code:throw new Ro(t);case zo.code:throw new zo(t);case Bo.code:throw new Bo(t);case Vo.code:throw new Vo(t,{method:n.method});case Ho.code:throw new Ho(t);case Uo.code:throw new Uo(t);case Wo.code:throw new Wo(t);case Go.code:throw new Go(t);case Ko.code:throw new Ko(t);case qo.code:throw new qo(t);case Jo.code:throw new Jo(t);case Yo.code:throw new Yo(t);case Xo.code:throw new Xo(t);case Zo.code:throw new Zo(t);case Qo.code:throw new Qo(t);case $o.code:throw new $o(t);case es.code:throw new es(t);case ts.code:throw new ts(t);case ns.code:throw new ns(t);case 5e3:throw new Wo(t);default:throw e instanceof D?e:new rs(t)}}},{delay:({count:e,error:t})=>{if(t&&t instanceof Eo){let e=t?.headers?.get(`Retry-After`);if(e?.match(/\\d/))return Number.parseInt(e,10)*1e3}return~~(1<<e)*o},retryCount:s,shouldRetry:({error:e})=>yh(e)}),{enabled:i,id:u})}}function yh(e){return`code`in e&&typeof e.code==`number`?e.code===-1||e.code===Ho.code||e.code===Io.code:e instanceof Eo&&e.status?e.status===403||e.status===408||e.status===413||e.status===429||e.status===500||e.status===502||e.status===503||e.status===504:!0}function L(e){return{formatters:void 0,fees:void 0,serializers:void 0,...e}}function bh(e,{errorInstance:t=Error(`timed out`),timeout:n,signal:r}){return new Promise((i,a)=>{(async()=>{let o;try{let s=new AbortController;n>0&&(o=setTimeout(()=>{r?s.abort():a(t)},n)),i(await e({signal:s?.signal||null}))}catch(e){e?.name===`AbortError`&&a(t),a(e)}finally{clearTimeout(o)}})()})}function xh(){return{current:0,take(){return this.current++},reset(){this.current=0}}}const Sh=xh();ko(),Va();function Ch(e,t={}){return{async request(n){let{body:r,fetchFn:i=t.fetchFn??fetch,onRequest:a=t.onRequest,onResponse:o=t.onResponse,timeout:s=t.timeout??1e4}=n,c={...t.fetchOptions??{},...n.fetchOptions??{}},{headers:l,method:u,signal:d}=c;try{let t=await bh(async({signal:t})=>{let n={...c,body:Ba(Array.isArray(r)?r.map(e=>({jsonrpc:`2.0`,id:e.id??Sh.take(),...e})):{jsonrpc:`2.0`,id:r.id??Sh.take(),...r}),headers:{\"Content-Type\":`application/json`,...l},method:u||`POST`,signal:d||(s>0?t:null)},o=new Request(e,n),f=await a?.(o,n)??{...n,url:e};return await i(f.url??e,f)},{errorInstance:new Oo({body:r,url:e}),timeout:s,signal:!0});o&&await o(t);let n;if(t.headers.get(`Content-Type`)?.startsWith(`application/json`))n=await t.json();else{n=await t.text();try{n=JSON.parse(n||`{}`)}catch(e){if(t.ok)throw e;n={error:n}}}if(!t.ok)throw new Eo({body:r,details:Ba(n.error)||t.statusText,headers:t.headers,status:t.status,url:e});return n}catch(t){throw t instanceof Eo||t instanceof Oo?t:new Eo({body:r,cause:t,url:e})}}}}Di(),It(),A();function wh(e){let t=(()=>typeof e==`string`?jn(e):typeof e.raw==`string`?e.raw:An(e.raw))(),n=jn(`\u0019Ethereum Signed Message:\n${Ft(t)}`);return wi([n,t])}ei();function Th(e,t){return $r(wh(e),t)}Va(),O();var Eh=class extends D{constructor({domain:e}){super(`Invalid domain \"${Ba(e)}\".`,{metaMessages:[`Must be a valid EIP-712 domain.`]})}},Dh=class extends D{constructor({primaryType:e,types:t}){super(`Invalid primary type \\`${e}\\` must be one of \\`${JSON.stringify(Object.keys(t))}\\`.`,{docsPath:`/api/glossary/Errors#typeddatainvalidprimarytypeerror`,metaMessages:[\"Check that the primary type is a key in `types`.\"]})}},Oh=class extends D{constructor({type:e}){super(`Struct type \"${e}\" is invalid.`,{metaMessages:[`Struct type must not be a Solidity type.`],name:`InvalidStructTypeError`})}};sn(),pi(),Ci(),It(),A(),Ii(),Va();function kh(e){let{domain:t,message:n,primaryType:r,types:i}=e,a=(e,t)=>{let n={...t};for(let t of e){let{name:e,type:r}=t;r===`address`&&(n[e]=n[e].toLowerCase())}return n},o=(()=>!i.EIP712Domain||!t?{}:a(i.EIP712Domain,t))(),s=(()=>{if(r!==`EIP712Domain`)return a(i[r],n)})();return Ba({domain:o,message:s,primaryType:r,types:i})}function Ah(e){let{domain:t,message:n,primaryType:r,types:i}=e,a=(e,t)=>{for(let n of e){let{name:e,type:r}=n,o=t[e],s=r.match(Fi);if(s&&(typeof o==`number`||typeof o==`bigint`)){let[e,t,n]=s;k(o,{signed:t===`int`,size:Number.parseInt(n,10)/8})}if(r===`address`&&typeof o==`string`&&!bi(o))throw new fi({address:o});let c=r.match(Pi);if(c){let[e,t]=c;if(t&&Ft(o)!==Number.parseInt(t,10))throw new tn({expectedSize:Number.parseInt(t,10),givenSize:Ft(o)})}let l=i[r];l&&(Mh(r),a(l,o))}};if(i.EIP712Domain&&t){if(typeof t!=`object`)throw new Eh({domain:t});a(i.EIP712Domain,t)}if(r!==`EIP712Domain`)if(i[r])a(i[r],n);else throw new Dh({primaryType:r,types:i})}function jh({domain:e}){return[typeof e?.name==`string`&&{name:`name`,type:`string`},e?.version&&{name:`version`,type:`string`},(typeof e?.chainId==`number`||typeof e?.chainId==`bigint`)&&{name:`chainId`,type:`uint256`},e?.verifyingContract&&{name:`verifyingContract`,type:`address`},e?.salt&&{name:`salt`,type:`bytes32`}].filter(Boolean)}function Mh(e){if(e===`address`||e===`bool`||e===`string`||e.startsWith(`bytes`)||e.startsWith(`uint`)||e.startsWith(`int`))throw new Oh({type:e})}Yi(),Di(),A(),ei();function Nh(e){let{domain:t={},message:n,primaryType:r}=e,i={EIP712Domain:jh({domain:t}),...e.types};Ah({domain:t,message:n,primaryType:r,types:i});let a=[`0x1901`];return t&&a.push(Ph({domain:t,types:i})),r!==`EIP712Domain`&&a.push(Fh({data:n,primaryType:r,types:i})),$r(wi(a))}function Ph({domain:e,types:t}){return Fh({data:e,primaryType:`EIP712Domain`,types:t})}function Fh({data:e,primaryType:t,types:n}){let r=Ih({data:e,primaryType:t,types:n});return $r(r)}function Ih({data:e,primaryType:t,types:n}){let r=[{type:`bytes32`}],i=[Lh({primaryType:t,types:n})];for(let a of n[t]){let[t,o]=Bh({types:n,name:a.name,type:a.type,value:e[a.name]});r.push(t),i.push(o)}return Li(r,i)}function Lh({primaryType:e,types:t}){let n=On(Rh({primaryType:e,types:t}));return $r(n)}function Rh({primaryType:e,types:t}){let n=``,r=zh({primaryType:e,types:t});r.delete(e);let i=[e,...Array.from(r).sort()];for(let e of i)n+=`${e}(${t[e].map(({name:e,type:t})=>`${t} ${e}`).join(`,`)})`;return n}function zh({primaryType:e,types:t},n=new Set){let r=e.match(/^\\w*/u)?.[0];if(n.has(r)||t[r]===void 0)return n;n.add(r);for(let e of t[r])zh({primaryType:e.type,types:t},n);return n}function Bh({types:e,name:t,type:n,value:r}){if(e[n]!==void 0)return[{type:`bytes32`},$r(Ih({data:r,primaryType:n,types:e}))];if(n===`bytes`)return r=`0x${(r.length%2?`0`:``)+r.slice(2)}`,[{type:`bytes32`},$r(r)];if(n===`string`)return[{type:`bytes32`},$r(On(r))];if(n.lastIndexOf(`]`)===n.length-1){let i=n.slice(0,n.lastIndexOf(`[`)),a=r.map(n=>Bh({name:t,type:i,types:e,value:n}));return[{type:`bytes32`},$r(Li(a.map(([e])=>e),a.map(([,e])=>e)))]}return[{type:n},r]}const Vh={checksum:new class extends Map{constructor(e){super(),Object.defineProperty(this,`maxSize`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.maxSize=e}get(e){let t=super.get(e);return super.has(e)&&t!==void 0&&(this.delete(e),super.set(e,t)),t}set(e,t){if(super.set(e,t),this.maxSize&&this.size>this.maxSize){let e=this.keys().next().value;e&&this.delete(e)}return this}}(8192)}.checksum;Qr(),Lf(),op();function Hh(e,t={}){let{as:n=typeof e==`string`?`Hex`:`Bytes`}=t,r=Zr(hf(e));return n===`Bytes`?r:Hf(r)}function Uh(e,t={}){let{as:n=typeof e==`string`?`Hex`:`Bytes`}=t,r=_d(hf(e));return n===`Bytes`?r:Hf(r)}Lf(),Jd(),op(),pf();function Wh(e,t={}){let{compressed:n}=t,{prefix:r,x:i,y:a}=e;if(n===!1||typeof i==`bigint`&&typeof a==`bigint`){if(r!==4)throw new Xh({prefix:r,cause:new Qh});return}if(n===!0||typeof i==`bigint`&&a===void 0){if(r!==3&&r!==2)throw new Xh({prefix:r,cause:new Zh});return}throw new Yh({publicKey:e})}function Gh(e){let t=(()=>{if(Zf(e))return qh(e);if(kf(e))return Kh(e);let{prefix:t,x:n,y:r}=e;return typeof n==`bigint`&&typeof r==`bigint`?{prefix:t??4,x:n,y:r}:{prefix:t,x:n}})();return Wh(t),t}function Kh(e){return qh(Hf(e))}function qh(e){if(e.length!==132&&e.length!==130&&e.length!==68)throw new $h({publicKey:e});if(e.length===130){let t=BigInt(Kf(e,0,32)),n=BigInt(Kf(e,32,64));return{prefix:4,x:t,y:n}}if(e.length===132){let t=Number(Kf(e,0,1)),n=BigInt(Kf(e,1,33)),r=BigInt(Kf(e,33,65));return{prefix:t,x:n,y:r}}let t=Number(Kf(e,0,1)),n=BigInt(Kf(e,1,33));return{prefix:t,x:n}}function Jh(e,t={}){Wh(e);let{prefix:n,x:r,y:i}=e,{includePrefix:a=!0}=t;return zf(a?I(n,{size:1}):`0x`,I(r,{size:32}),typeof i==`bigint`?I(i,{size:32}):`0x`)}var Yh=class extends P{constructor({publicKey:e}){super(`Value \\`${df(e)}\\` is not a valid public key.`,{metaMessages:[`Public key must contain:`,\"- an `x` and `prefix` value (compressed)\",\"- an `x`, `y`, and `prefix` value (uncompressed)\"]}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`PublicKey.InvalidError`})}},Xh=class extends P{constructor({prefix:e,cause:t}){super(`Prefix \"${e}\" is invalid.`,{cause:t}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`PublicKey.InvalidPrefixError`})}},Zh=class extends P{constructor(){super(`Prefix must be 2 or 3 for compressed public keys.`),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`PublicKey.InvalidCompressedPrefixError`})}},Qh=class extends P{constructor(){super(`Prefix must be 4 for uncompressed public keys.`),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`PublicKey.InvalidUncompressedPrefixError`})}},$h=class extends P{constructor({publicKey:e}){super(`Value \\`${e}\\` is an invalid public key size.`,{metaMessages:[`Expected: 33 bytes (compressed + prefix), 64 bytes (uncompressed) or 65 bytes (uncompressed + prefix).`,`Received ${qf(Bf(e))} bytes.`]}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`PublicKey.InvalidSerializedSizeError`})}};Lf(),Jd();var eg=/^0x[a-fA-F0-9]{40}$/;function tg(e,t={}){let{strict:n=!0}=t;if(!eg.test(e))throw new sg({address:e,cause:new cg});if(n){if(e.toLowerCase()===e)return;if(ng(e)!==e)throw new sg({address:e,cause:new lg})}}function ng(e){if(Vh.has(e))return Vh.get(e);tg(e,{strict:!1});let t=e.substring(2).toLowerCase(),n=Hh(vf(t),{as:`Bytes`}),r=t.split(``);for(let e=0;e<40;e+=2)n[e>>1]>>4>=8&&r[e]&&(r[e]=r[e].toUpperCase()),(n[e>>1]&15)>=8&&r[e+1]&&(r[e+1]=r[e+1].toUpperCase());let i=`0x${r.join(``)}`;return Vh.set(e,i),i}function rg(e,t={}){let{checksum:n=!1}=t;return tg(e),n?ng(e):e}function ig(e,t={}){let n=Hh(`0x${Jh(e).slice(4)}`).substring(26);return rg(`0x${n}`,t)}function ag(e,t){return tg(e,{strict:!1}),tg(t,{strict:!1}),e.toLowerCase()===t.toLowerCase()}function og(e,t={}){let{strict:n=!0}=t??{};try{return tg(e,{strict:n}),!0}catch{return!1}}var sg=class extends P{constructor({address:e,cause:t}){super(`Address \"${e}\" is invalid.`,{cause:t}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Address.InvalidAddressError`})}},cg=class extends P{constructor(){super(`Address is not a 20 byte (40 hexadecimal character) value.`),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Address.InvalidInputError`})}},lg=class extends P{constructor(){super(`Address does not match its checksum counterpart.`),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Address.InvalidChecksumError`})}};const ug=/^(.*)\\[([0-9]*)\\]$/,dg=/^bytes([1-9]|1[0-9]|2[0-9]|3[0-2])?$/,fg=/^(u?int)(8|16|24|32|40|48|56|64|72|80|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256)?$/;2n**(8n-1n)-1n,2n**(16n-1n)-1n,2n**(24n-1n)-1n,2n**(32n-1n)-1n,2n**(40n-1n)-1n,2n**(48n-1n)-1n,2n**(56n-1n)-1n,2n**(64n-1n)-1n,2n**(72n-1n)-1n,2n**(80n-1n)-1n,2n**(88n-1n)-1n,2n**(96n-1n)-1n,2n**(104n-1n)-1n,2n**(112n-1n)-1n,2n**(120n-1n)-1n,2n**(128n-1n)-1n,2n**(136n-1n)-1n,2n**(144n-1n)-1n,2n**(152n-1n)-1n,2n**(160n-1n)-1n,2n**(168n-1n)-1n,2n**(176n-1n)-1n,2n**(184n-1n)-1n,2n**(192n-1n)-1n,2n**(200n-1n)-1n,2n**(208n-1n)-1n,2n**(216n-1n)-1n,2n**(224n-1n)-1n,2n**(232n-1n)-1n,2n**(240n-1n)-1n,2n**(248n-1n)-1n,2n**(256n-1n)-1n,-(2n**(8n-1n)),-(2n**(16n-1n)),-(2n**(24n-1n)),-(2n**(32n-1n)),-(2n**(40n-1n)),-(2n**(48n-1n)),-(2n**(56n-1n)),-(2n**(64n-1n)),-(2n**(72n-1n)),-(2n**(80n-1n)),-(2n**(88n-1n)),-(2n**(96n-1n)),-(2n**(104n-1n)),-(2n**(112n-1n)),-(2n**(120n-1n)),-(2n**(128n-1n)),-(2n**(136n-1n)),-(2n**(144n-1n)),-(2n**(152n-1n)),-(2n**(160n-1n)),-(2n**(168n-1n)),-(2n**(176n-1n)),-(2n**(184n-1n)),-(2n**(192n-1n)),-(2n**(200n-1n)),-(2n**(208n-1n)),-(2n**(216n-1n)),-(2n**(224n-1n)),-(2n**(232n-1n)),-(2n**(240n-1n)),-(2n**(248n-1n)),-(2n**(256n-1n));const pg=2n**256n-1n;Lf(),Jd(),op();function mg(e,t,n){let{checksumAddress:r,staticPosition:i}=n,a=Pg(t.type);if(a){let[n,o]=a;return vg(e,{...t,type:o},{checksumAddress:r,length:n,staticPosition:i})}if(t.type===`tuple`)return Sg(e,t,{checksumAddress:r,staticPosition:i});if(t.type===`address`)return _g(e,{checksum:r});if(t.type===`bool`)return yg(e);if(t.type.startsWith(`bytes`))return bg(e,t,{staticPosition:i});if(t.type.startsWith(`uint`)||t.type.startsWith(`int`))return xg(e,t);if(t.type===`string`)return Cg(e,{staticPosition:i});throw new Zg(t.type)}var hg=32,gg=32;function _g(e,t={}){let{checksum:n=!1}=t,r=e.readBytes(32);return[(e=>n?ng(e):e)(Hf(xf(r,-20))),32]}function vg(e,t,n){let{checksumAddress:r,length:i,staticPosition:a}=n;if(!i){let n=Tf(e.readBytes(gg)),i=a+n,o=i+hg;e.setPosition(i);let s=Tf(e.readBytes(hg)),c=Fg(t),l=0,u=[];for(let n=0;n<s;++n){e.setPosition(o+(c?n*32:l));let[i,a]=mg(e,t,{checksumAddress:r,staticPosition:o});l+=a,u.push(i)}return e.setPosition(a+32),[u,32]}if(Fg(t)){let n=Tf(e.readBytes(gg)),o=a+n,s=[];for(let n=0;n<i;++n){e.setPosition(o+n*32);let[i]=mg(e,t,{checksumAddress:r,staticPosition:o});s.push(i)}return e.setPosition(a+32),[s,32]}let o=0,s=[];for(let n=0;n<i;++n){let[n,i]=mg(e,t,{checksumAddress:r,staticPosition:a+o});o+=i,s.push(n)}return[s,o]}function yg(e){return[Cf(e.readBytes(32),{size:32}),32]}function bg(e,t,{staticPosition:n}){let[r,i]=t.type.split(`bytes`);if(!i){let t=Tf(e.readBytes(32));e.setPosition(n+t);let r=Tf(e.readBytes(32));if(r===0)return e.setPosition(n+32),[`0x`,32];let i=e.readBytes(r);return e.setPosition(n+32),[Hf(i),32]}return[Hf(e.readBytes(Number.parseInt(i,10),32)),32]}function xg(e,t){let n=t.type.startsWith(`int`),r=Number.parseInt(t.type.split(`int`)[1]||`256`,10),i=e.readBytes(32);return[r>48?Sf(i,{signed:n}):Tf(i,{signed:n}),32]}function Sg(e,t,n){let{checksumAddress:r,staticPosition:i}=n,a=t.components.length===0||t.components.some(({name:e})=>!e),o=a?[]:{},s=0;if(Fg(t)){let n=Tf(e.readBytes(gg)),c=i+n;for(let n=0;n<t.components.length;++n){let i=t.components[n];e.setPosition(c+s);let[l,u]=mg(e,i,{checksumAddress:r,staticPosition:c});s+=u,o[a?n:i?.name]=l}return e.setPosition(i+32),[o,32]}for(let n=0;n<t.components.length;++n){let c=t.components[n],[l,u]=mg(e,c,{checksumAddress:r,staticPosition:i});o[a?n:c?.name]=l,s+=u}return[o,s]}function Cg(e,{staticPosition:t}){let n=Tf(e.readBytes(32)),r=t+n;e.setPosition(r);let i=Tf(e.readBytes(32));if(i===0)return e.setPosition(t+32),[``,32];let a=e.readBytes(i,32),o=Ef(Df(a));return e.setPosition(t+32),[o,32]}function wg({checksumAddress:e,parameters:t,values:n}){let r=[];for(let i=0;i<t.length;i++)r.push(Tg({checksumAddress:e,parameter:t[i],value:n[i]}));return r}function Tg({checksumAddress:e=!1,parameter:t,value:n}){let r=t,i=Pg(r.type);if(i){let[t,a]=i;return Og(n,{checksumAddress:e,length:t,parameter:{...r,type:a}})}if(r.type===`tuple`)return Ng(n,{checksumAddress:e,parameter:r});if(r.type===`address`)return Dg(n,{checksum:e});if(r.type===`bool`)return Ag(n);if(r.type.startsWith(`uint`)||r.type.startsWith(`int`)){let e=r.type.startsWith(`int`),[,,t=`256`]=fg.exec(r.type)??[];return jg(n,{signed:e,size:Number(t)})}if(r.type.startsWith(`bytes`))return kg(n,{type:r.type});if(r.type===`string`)return Mg(n);throw new Zg(r.type)}function Eg(e){let t=0;for(let n=0;n<e.length;n++){let{dynamic:r,encoded:i}=e[n];r?t+=32:t+=qf(i)}let n=[],r=[],i=0;for(let a=0;a<e.length;a++){let{dynamic:o,encoded:s}=e[a];o?(n.push(I(t+i,{size:32})),r.push(s),i+=qf(s)):n.push(s)}return zf(...n,...r)}function Dg(e,t){let{checksum:n=!1}=t;return tg(e,{strict:n}),{dynamic:!1,encoded:Wf(e.toLowerCase())}}function Og(e,t){let{checksumAddress:n,length:r,parameter:i}=t,a=r===null;if(!Array.isArray(e))throw new Xg(e);if(!a&&e.length!==r)throw new qg({expectedLength:r,givenLength:e.length,type:`${i.type}[${r}]`});let o=!1,s=[];for(let t=0;t<e.length;t++){let r=Tg({checksumAddress:n,parameter:i,value:e[t]});r.dynamic&&(o=!0),s.push(r)}if(a||o){let e=Eg(s);if(a){let t=I(s.length,{size:32});return{dynamic:!0,encoded:s.length>0?zf(t,e):t}}if(o)return{dynamic:!0,encoded:e}}return{dynamic:!1,encoded:zf(...s.map(({encoded:e})=>e))}}function kg(e,{type:t}){let[,n]=t.split(`bytes`),r=qf(e);if(!n){let t=e;return r%32!=0&&(t=Gf(t,Math.ceil((e.length-2)/2/32)*32)),{dynamic:!0,encoded:zf(Wf(I(r,{size:32})),t)}}if(r!==Number.parseInt(n,10))throw new Jg({expectedSize:Number.parseInt(n,10),value:e});return{dynamic:!1,encoded:Gf(e)}}function Ag(e){if(typeof e!=`boolean`)throw new P(`Invalid boolean value: \"${e}\" (type: ${typeof e}). Expected: \\`true\\` or \\`false\\`.`);return{dynamic:!1,encoded:Wf(Vf(e))}}function jg(e,{signed:t,size:n}){if(typeof n==`number`){let r=2n**(BigInt(n)-(t?1n:0n))-1n,i=t?-r-1n:0n;if(e>r||e<i)throw new ep({max:r.toString(),min:i.toString(),signed:t,size:n/8,value:e.toString()})}return{dynamic:!1,encoded:I(e,{size:32,signed:t})}}function Mg(e){let t=Uf(e),n=Math.ceil(qf(t)/32),r=[];for(let e=0;e<n;e++)r.push(Gf(Kf(t,e*32,(e+1)*32)));return{dynamic:!0,encoded:zf(Gf(I(qf(t),{size:32})),...r)}}function Ng(e,t){let{checksumAddress:n,parameter:r}=t,i=!1,a=[];for(let t=0;t<r.components.length;t++){let o=r.components[t],s=Array.isArray(e)?t:o.name,c=Tg({checksumAddress:n,parameter:o,value:e[s]});a.push(c),c.dynamic&&(i=!0)}return{dynamic:i,encoded:i?Eg(a):zf(...a.map(({encoded:e})=>e))}}function Pg(e){let t=e.match(/^(.*)\\[(\\d+)?\\]$/);return t?[t[2]?Number(t[2]):null,t[1]]:void 0}function Fg(e){let{type:t}=e;if(t===`string`||t===`bytes`||t.endsWith(`[]`))return!0;if(t===`tuple`)return e.components?.some(Fg);let n=Pg(e.type);return!!(n&&Fg({...e,type:n[1]}))}Jd();var Ig={bytes:new Uint8Array,dataView:new DataView(new ArrayBuffer(0)),position:0,positionReadCount:new Map,recursiveReadCount:0,recursiveReadLimit:1/0,assertReadLimit(){if(this.recursiveReadCount>=this.recursiveReadLimit)throw new Bg({count:this.recursiveReadCount+1,limit:this.recursiveReadLimit})},assertPosition(e){if(e<0||e>this.bytes.length-1)throw new zg({length:this.bytes.length,position:e})},decrementPosition(e){if(e<0)throw new Rg({offset:e});let t=this.position-e;this.assertPosition(t),this.position=t},getReadCount(e){return this.positionReadCount.get(e||this.position)||0},incrementPosition(e){if(e<0)throw new Rg({offset:e});let t=this.position+e;this.assertPosition(t),this.position=t},inspectByte(e){let t=e??this.position;return this.assertPosition(t),this.bytes[t]},inspectBytes(e,t){let n=t??this.position;return this.assertPosition(n+e-1),this.bytes.subarray(n,n+e)},inspectUint8(e){let t=e??this.position;return this.assertPosition(t),this.bytes[t]},inspectUint16(e){let t=e??this.position;return this.assertPosition(t+1),this.dataView.getUint16(t)},inspectUint24(e){let t=e??this.position;return this.assertPosition(t+2),(this.dataView.getUint16(t)<<8)+this.dataView.getUint8(t+2)},inspectUint32(e){let t=e??this.position;return this.assertPosition(t+3),this.dataView.getUint32(t)},pushByte(e){this.assertPosition(this.position),this.bytes[this.position]=e,this.position++},pushBytes(e){this.assertPosition(this.position+e.length-1),this.bytes.set(e,this.position),this.position+=e.length},pushUint8(e){this.assertPosition(this.position),this.bytes[this.position]=e,this.position++},pushUint16(e){this.assertPosition(this.position+1),this.dataView.setUint16(this.position,e),this.position+=2},pushUint24(e){this.assertPosition(this.position+2),this.dataView.setUint16(this.position,e>>8),this.dataView.setUint8(this.position+2,e&255),this.position+=3},pushUint32(e){this.assertPosition(this.position+3),this.dataView.setUint32(this.position,e),this.position+=4},readByte(){this.assertReadLimit(),this._touch();let e=this.inspectByte();return this.position++,e},readBytes(e,t){this.assertReadLimit(),this._touch();let n=this.inspectBytes(e);return this.position+=t??e,n},readUint8(){this.assertReadLimit(),this._touch();let e=this.inspectUint8();return this.position+=1,e},readUint16(){this.assertReadLimit(),this._touch();let e=this.inspectUint16();return this.position+=2,e},readUint24(){this.assertReadLimit(),this._touch();let e=this.inspectUint24();return this.position+=3,e},readUint32(){this.assertReadLimit(),this._touch();let e=this.inspectUint32();return this.position+=4,e},get remaining(){return this.bytes.length-this.position},setPosition(e){let t=this.position;return this.assertPosition(e),this.position=e,()=>this.position=t},_touch(){if(this.recursiveReadLimit===1/0)return;let e=this.getReadCount();this.positionReadCount.set(this.position,e+1),e>0&&this.recursiveReadCount++}};function Lg(e,{recursiveReadLimit:t=8192}={}){let n=Object.create(Ig);return n.bytes=e,n.dataView=new DataView(e.buffer,e.byteOffset,e.byteLength),n.positionReadCount=new Map,n.recursiveReadLimit=t,n}var Rg=class extends P{constructor({offset:e}){super(`Offset \\`${e}\\` cannot be negative.`),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Cursor.NegativeOffsetError`})}},zg=class extends P{constructor({length:e,position:t}){super(`Position \\`${t}\\` is out of bounds (\\`0 < position < ${e}\\`).`),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Cursor.PositionOutOfBoundsError`})}},Bg=class extends P{constructor({count:e,limit:t}){super(`Recursive read limit of \\`${t}\\` exceeded (recursive read count: \\`${e}\\`).`),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Cursor.RecursiveReadLimitExceededError`})}};Ot(),Lf(),Jd(),op();function Vg(e,t,n={}){let{as:r=`Array`,checksumAddress:i=!1}=n,a=typeof t==`string`?_f(t):t,o=Lg(a);if(bf(a)===0&&e.length>0)throw new Kg;if(bf(a)&&bf(a)<32)throw new Gg({data:typeof t==`string`?t:Hf(t),parameters:e,size:bf(a)});let s=0,c=r===`Array`?[]:{};for(let t=0;t<e.length;++t){let n=e[t];o.setPosition(s);let[a,l]=mg(o,n,{checksumAddress:i,staticPosition:0});s+=l,r===`Array`?c.push(a):c[n.name??t]=a}return c}function Hg(e,t,n){let{checksumAddress:r=!1}=n??{};if(e.length!==t.length)throw new Yg({expectedLength:e.length,givenLength:t.length});let i=wg({checksumAddress:r,parameters:e,values:t}),a=Eg(i);return a.length===0?`0x`:a}function Ug(e,t){if(e.length!==t.length)throw new Yg({expectedLength:e.length,givenLength:t.length});let n=[];for(let r=0;r<e.length;r++){let i=e[r],a=t[r];n.push(Ug.encode(i,a))}return zf(...n)}(function(e){function t(e,n,r=!1){if(e===`address`){let e=n;return tg(e),Wf(e.toLowerCase(),r?32:0)}if(e===`string`)return Uf(n);if(e===`bytes`)return n;if(e===`bool`)return Wf(Vf(n),r?32:1);let i=e.match(fg);if(i){let[e,t,a=`256`]=i,o=Number.parseInt(a,10)/8;return I(n,{size:r?32:o,signed:t===`int`})}let a=e.match(dg);if(a){let[e,t]=a;if(Number.parseInt(t,10)!==(n.length-2)/2)throw new Jg({expectedSize:Number.parseInt(t,10),value:n});return Gf(n,r?32:0)}let o=e.match(ug);if(o&&Array.isArray(n)){let[e,r]=o,i=[];for(let e=0;e<n.length;e++)i.push(t(r,n[e],!0));return i.length===0?`0x`:zf(...i)}throw new Zg(e)}e.encode=t})(Ug||={});function Wg(e){return Array.isArray(e)&&typeof e[0]==`string`||typeof e==`string`?Et(e):e}var Gg=class extends P{constructor({data:e,parameters:t,size:n}){super(`Data size of ${n} bytes is too small for given parameters.`,{metaMessages:[`Params: (${se(t)})`,`Data:   ${e} (${n} bytes)`]}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`AbiParameters.DataSizeTooSmallError`})}},Kg=class extends P{constructor(){super(`Cannot decode zero data (\"0x\") with ABI parameters.`),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`AbiParameters.ZeroDataError`})}},qg=class extends P{constructor({expectedLength:e,givenLength:t,type:n}){super(`Array length mismatch for type \\`${n}\\`. Expected: \\`${e}\\`. Given: \\`${t}\\`.`),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`AbiParameters.ArrayLengthMismatchError`})}},Jg=class extends P{constructor({expectedSize:e,value:t}){super(`Size of bytes \"${t}\" (bytes${qf(t)}) does not match expected size (bytes${e}).`),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`AbiParameters.BytesSizeMismatchError`})}},Yg=class extends P{constructor({expectedLength:e,givenLength:t}){super([`ABI encoding parameters/values length mismatch.`,`Expected length (parameters): ${e}`,`Given length (values): ${t}`].join(`\n`)),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`AbiParameters.LengthMismatchError`})}},Xg=class extends P{constructor(e){super(`Value \\`${e}\\` is not a valid array.`),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`AbiParameters.InvalidArrayError`})}},Zg=class extends P{constructor(e){super(`Type \\`${e}\\` is not a valid ABI Type.`),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`AbiParameters.InvalidTypeError`})}};Lf(),Jd(),op();function Qg(e,t){let{as:n}=t,r=e_(e),i=Lg(new Uint8Array(r.length));return r.encode(i),n===`Hex`?Hf(i.bytes):i.bytes}function $g(e,t={}){let{as:n=`Hex`}=t;return Qg(e,{as:n})}function e_(e){return Array.isArray(e)?t_(e.map(e=>e_(e))):n_(e)}function t_(e){let t=e.reduce((e,t)=>e+t.length,0),n=r_(t);return{length:(()=>t<=55?1+t:1+n+t)(),encode(r){t<=55?r.pushByte(192+t):(r.pushByte(247+n),n===1?r.pushUint8(t):n===2?r.pushUint16(t):n===3?r.pushUint24(t):r.pushUint32(t));for(let{encode:t}of e)t(r)}}}function n_(e){let t=typeof e==`string`?_f(e):e,n=r_(t.length);return{length:(()=>t.length===1&&t[0]<128?1:t.length<=55?1+t.length:1+n+t.length)(),encode(e){t.length===1&&t[0]<128?e.pushBytes(t):t.length<=55?(e.pushByte(128+t.length),e.pushBytes(t)):(e.pushByte(183+n),n===1?e.pushUint8(t.length):n===2?e.pushUint16(t.length):n===3?e.pushUint24(t.length):e.pushUint32(t.length),e.pushBytes(t))}}}function r_(e){if(e<2**8)return 1;if(e<2**16)return 2;if(e<2**24)return 3;if(e<2**32)return 4;throw new P(`Length is too large.`)}Jd(),op(),pf();function i_(e,t={}){let{recovered:n}=t;if(e.r===void 0||e.s===void 0||n&&e.yParity===void 0)throw new g_({signature:e});if(e.r<0n||e.r>pg)throw new __({value:e.r});if(e.s<0n||e.s>pg)throw new v_({value:e.s});if(typeof e.yParity==`number`&&e.yParity!==0&&e.yParity!==1)throw new y_({value:e.yParity})}function a_(e){return o_(Hf(e))}function o_(e){if(e.length!==130&&e.length!==132)throw new h_({signature:e});let t=BigInt(Kf(e,0,32)),n=BigInt(Kf(e,32,64)),r=(()=>{let t=Number(`0x${e.slice(130)}`);if(!Number.isNaN(t))try{return p_(t)}catch{throw new y_({value:t})}})();return r===void 0?{r:t,s:n}:{r:t,s:n,yParity:r}}function s_(e){if(e.r!==void 0&&e.s!==void 0)return c_(e)}function c_(e){let t=(()=>typeof e==`string`?o_(e):e instanceof Uint8Array?a_(e):typeof e.r==`string`?u_(e):e.v?l_(e):{r:e.r,s:e.s,...e.yParity===void 0?{}:{yParity:e.yParity}})();return i_(t),t}function l_(e){return{r:e.r,s:e.s,yParity:p_(e.v)}}function u_(e){let t=(()=>{let t=e.v?Number(e.v):void 0,n=e.yParity?Number(e.yParity):void 0;if(typeof t==`number`&&typeof n!=`number`&&(n=p_(t)),typeof n!=`number`)throw new y_({value:e.yParity});return n})();return{r:BigInt(e.r),s:BigInt(e.s),yParity:t}}function d_(e){i_(e);let t=e.r,n=e.s;return zf(I(t,{size:32}),I(n,{size:32}),typeof e.yParity==`number`?I(m_(e.yParity),{size:1}):`0x`)}function f_(e){let{r:t,s:n,yParity:r}=e;return[r?`0x01`:`0x`,t===0n?`0x`:Jf(I(t)),n===0n?`0x`:Jf(I(n))]}function p_(e){if(e===0||e===27)return 0;if(e===1||e===28)return 1;if(e>=35)return e%2==0?1:0;throw new b_({value:e})}function m_(e){if(e===0)return 27;if(e===1)return 28;throw new y_({value:e})}var h_=class extends P{constructor({signature:e}){super(`Value \\`${e}\\` is an invalid signature size.`,{metaMessages:[`Expected: 64 bytes or 65 bytes.`,`Received ${qf(Bf(e))} bytes.`]}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Signature.InvalidSerializedSizeError`})}},g_=class extends P{constructor({signature:e}){super(`Signature \\`${df(e)}\\` is missing either an \\`r\\`, \\`s\\`, or \\`yParity\\` property.`),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Signature.MissingPropertiesError`})}},__=class extends P{constructor({value:e}){super(`Value \\`${e}\\` is an invalid r value. r must be a positive integer less than 2^256.`),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Signature.InvalidRError`})}},v_=class extends P{constructor({value:e}){super(`Value \\`${e}\\` is an invalid s value. s must be a positive integer less than 2^256.`),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Signature.InvalidSError`})}},y_=class extends P{constructor({value:e}){super(`Value \\`${e}\\` is an invalid y-parity value. Y-parity must be 0 or 1.`),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Signature.InvalidYParityError`})}},b_=class extends P{constructor({value:e}){super(`Value \\`${e}\\` is an invalid v value. v must be 27, 28 or >=35.`),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Signature.InvalidVError`})}};op();function x_(e,t={}){return typeof e.chainId==`string`?S_(e):{...e,...t.signature}}function S_(e){let{address:t,chainId:n,nonce:r}=e,i=s_(e);return{address:t,chainId:Number(n),nonce:BigInt(r),...i}}function C_(e){return w_(e,{presign:!0})}function w_(e,t={}){let{presign:n}=t;return Hh(zf(`0x05`,$g(T_(n?{address:e.address,chainId:e.chainId,nonce:e.nonce}:e))))}function T_(e){let{address:t,chainId:n,nonce:r}=e,i=s_(e);return[n?I(n):`0x`,t,r?I(r):`0x`,...i?f_(i):[]]}uu(),Lf(),op();function E_(e){let{privateKey:t}=e,n=Yl.ProjectivePoint.fromPrivateKey(Bf(t).slice(2));return Gh(n)}function D_(e={}){let{as:t=`Hex`}=e,n=Yl.utils.randomPrivateKey();return t===`Hex`?Hf(n):n}function O_(e){return ig(k_(e))}function k_(e){let{payload:t,signature:n}=e,{r,s:i,yParity:a}=n,o=new Yl.Signature(BigInt(r),BigInt(i)).addRecoveryBit(a).recoverPublicKey(Bf(t).substring(2));return Gh(o)}function A_(e){let{extraEntropy:t=!1,hash:n,payload:r,privateKey:i}=e,{r:a,s:o,recovery:s}=Yl.sign(hf(r),hf(i),{extraEntropy:typeof t==`boolean`?t:Bf(t).slice(2),lowS:!0,...n?{prehash:!0}:{}});return{r:a,s:o,yParity:s}}Jd(),op();const j_=Wg(`(uint256 chainId, address delegation, uint256 nonce, uint8 yParity, uint256 r, uint256 s), address to, bytes data`);function M_(e){if(typeof e==`string`){if(Kf(e,-32)!==`0x8010801080108010801080108010801080108010801080108010801080108010`)throw new I_(e)}else i_(e.authorization)}function N_(e){M_(e);let t=Xf(Kf(e,-64,-32)),n=Kf(e,-t-64,-64),r=Kf(e,0,-t-64),[i,a,o]=Vg(j_,n);return{authorization:x_({address:i.delegation,chainId:Number(i.chainId),nonce:i.nonce,yParity:i.yParity,r:i.r,s:i.s}),signature:r,...o&&o!==`0x`?{data:o,to:a}:{}}}function P_(e){let{data:t,signature:n}=e;M_(e);let r=O_({payload:C_(e.authorization),signature:c_(e.authorization)}),i=Hg(j_,[{...e.authorization,delegation:e.authorization.address,chainId:BigInt(e.authorization.chainId)},e.to??r,t??`0x`]),a=I(qf(i),{size:32});return zf(n,i,a,`0x8010801080108010801080108010801080108010801080108010801080108010`)}function F_(e){try{return M_(e),!0}catch{return!1}}var I_=class extends P{constructor(e){super(`Value \\`${e}\\` is an invalid ERC-8010 wrapped signature.`),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`SignatureErc8010.InvalidWrappedSignatureError`})}};ho(),A();async function L_(e,{blockHash:t,blockNumber:n,blockTag:r,hash:i,index:a}){let o=r||`latest`,s=n===void 0?void 0:k(n),c=null;if(i?c=await e.request({method:`eth_getTransactionByHash`,params:[i]},{dedupe:!0}):t?c=await e.request({method:`eth_getTransactionByBlockHashAndIndex`,params:[t,k(a)]},{dedupe:!0}):(s||o)&&(c=await e.request({method:`eth_getTransactionByBlockNumberAndIndex`,params:[s||o,k(a)]},{dedupe:!!s})),!c)throw new uo({blockHash:t,blockNumber:n,blockTag:o,hash:i,index:a});return(e.chain?.formatters?.transaction?.format||ad)(c,`getTransaction`)}ho();async function R_(e,{hash:t}){let n=await e.request({method:`eth_getTransactionReceipt`,params:[t]},{dedupe:!0});if(!n)throw new fo({hash:t});return(e.chain?.formatters?.transactionReceipt?.format||zm)(n,`getTransactionReceipt`)}Jd();function z_(e){let t=!0,n=``,r=0,i=``,a=!1;for(let o=0;o<e.length;o++){let s=e[o];if([`(`,`)`,`,`].includes(s)&&(t=!0),s===`(`&&r++,s===`)`&&r--,t){if(r===0){if(s===` `&&[`event`,`function`,`error`,``].includes(i))i=``;else if(i+=s,s===`)`){a=!0;break}continue}if(s===` `){e[o-1]!==`,`&&n!==`,`&&n!==`,(`&&(n=``,t=!1);continue}i+=s,n+=s}}if(!a)throw new P(`Unable to normalize signature.`);return i}function B_(e,t){let n=typeof e,r=t.type;switch(r){case`address`:return og(e,{strict:!1});case`bool`:return n===`boolean`;case`function`:return n===`string`;case`string`:return n===`string`;default:return r===`tuple`&&`components`in t?Object.values(t.components).every((t,n)=>B_(Object.values(e)[n],t)):/^u?int(8|16|24|32|40|48|56|64|72|80|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256)?$/.test(r)?n===`number`||n===`bigint`:/^bytes([1-9]|1[0-9]|2[0-9]|3[0-2])?$/.test(r)?n===`string`||e instanceof Uint8Array:/[a-z]+[1-9]{0,3}(\\[[0-9]{0,}\\])+$/.test(r)?Array.isArray(e)&&e.every(e=>B_(e,{...t,type:r.replace(/(\\[[0-9]{0,}\\])$/,``)})):!1}}function V_(e,t,n){for(let r in e){let i=e[r],a=t[r];if(i.type===`tuple`&&a.type===`tuple`&&`components`in i&&`components`in a)return V_(i.components,a.components,n[r]);let o=[i.type,a.type];if((()=>o.includes(`address`)&&o.includes(`bytes20`)?!0:o.includes(`address`)&&o.includes(`string`)||o.includes(`address`)&&o.includes(`bytes`)?og(n[r],{strict:!1}):!1)())return o}}Ot(),Jd(),op();function H_(e,t={}){let{prepare:n=!0}=t,r=(()=>Array.isArray(e)||typeof e==`string`?wt(e):e)();return{...r,...n?{hash:K_(r)}:{}}}function U_(e,t,n){let{args:r=[],prepare:i=!0}=n??{},a=Zf(t,{strict:!1}),o=e.filter(e=>a?e.type===`function`||e.type===`error`?W_(e)===Kf(t,0,4):e.type===`event`?K_(e)===t:!1:`name`in e&&e.name===t);if(o.length===0)throw new J_({name:t});if(o.length===1)return{...o[0],...i?{hash:K_(o[0])}:{}};let s;for(let e of o)if(`inputs`in e){if(!r||r.length===0){if(!e.inputs||e.inputs.length===0)return{...e,...i?{hash:K_(e)}:{}};continue}if(e.inputs&&e.inputs.length!==0&&e.inputs.length===r.length&&r.every((t,n)=>{let r=`inputs`in e&&e.inputs[n];return r?B_(t,r):!1})){if(s&&`inputs`in s&&s.inputs){let t=V_(e.inputs,s.inputs,r);if(t)throw new q_({abiItem:e,type:t[0]},{abiItem:s,type:t[1]})}s=e}}let c=(()=>{if(s)return s;let[e,...t]=o;return{...e,overloads:t}})();if(!c)throw new J_({name:t});return{...c,...i?{hash:K_(c)}:{}}}function W_(...e){let t=(()=>{if(Array.isArray(e[0])){let[t,n]=e;return U_(t,n)}return e[0]})();return Kf(K_(t),0,4)}function G_(...e){let t=(()=>{if(Array.isArray(e[0])){let[t,n]=e;return U_(t,n)}return e[0]})(),n=(()=>typeof t==`string`?t:le(t))();return z_(n)}function K_(...e){let t=(()=>{if(Array.isArray(e[0])){let[t,n]=e;return U_(t,n)}return e[0]})();return typeof t!=`string`&&`hash`in t&&t.hash?t.hash:Hh(Uf(G_(t)))}var q_=class extends P{constructor(e,t){super(`Found ambiguous types in overloaded ABI Items.`,{metaMessages:[`\\`${e.type}\\` in \\`${z_(le(e.abiItem))}\\`, and`,`\\`${t.type}\\` in \\`${z_(le(t.abiItem))}\\``,``,`These types encode differently and cannot be distinguished at runtime.`,`Remove one of the ambiguous items in the ABI.`]}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`AbiItem.AmbiguityError`})}},J_=class extends P{constructor({name:e,data:t,type:n=`item`}){let r=(()=>e?` with name \"${e}\"`:t?` with data \"${t}\"`:``)();super(`ABI ${n}${r} not found.`),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`AbiItem.NotFoundError`})}};op();function Y_(...e){let[t,n=[]]=(()=>{if(Array.isArray(e[0])){let[t,n,r]=e;return[X_(t,n,{args:r}),r]}let[t,n]=e;return[t,n]})(),{overloads:r}=t,i=r?X_([t,...r],t.name,{args:n}):t,a=Z_(i),o=n.length>0?Hg(i.inputs,n):void 0;return o?zf(a,o):a}function X_(e,t,n){let r=U_(e,t,n);if(r.type!==`function`)throw new J_({name:t,type:`function`});return r}function Z_(e){return W_(e)}const Q_=`0x0000000000000000000000000000000000000000`;Jd(),op();function $_(e){if(Kf(e,-32)!==`0x6492649264926492649264926492649264926492649264926492649264926492`)throw new nv(e)}function ev(e){let{data:t,signature:n,to:r}=e;return zf(Hg(Wg(`address, bytes, bytes`),[r,t,n]),`0x6492649264926492649264926492649264926492649264926492649264926492`)}function tv(e){try{return $_(e),!0}catch{return!1}}var nv=class extends P{constructor(e){super(`Value \\`${e}\\` is an invalid ERC-6492 wrapped signature.`),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`SignatureErc6492.InvalidWrappedSignatureError`})}};uu(),Dn(),Hn();function rv({r:e,s:t,to:n=`hex`,v:r,yParity:i}){let a=(()=>{if(i===0||i===1)return i;if(r&&(r===27n||r===28n||r>=35n))return r%2n==0n?1:0;throw Error(\"Invalid `v` or `yParity` value\")})(),o=`0x${new Yl.Signature(wn(e),wn(t)).toCompactHex()}${a===0?`1b`:`1c`}`;return n===`hex`?o:Ln(o)}gp(),Sp(),To(),jp(),ca(),yi(),Rd(),Di(),Pt(),Dn(),A(),mm();async function iv(e,t){let{address:n,hash:r,erc6492VerifierAddress:i=t.universalSignatureVerifierAddress??e.chain?.contracts?.erc6492Verifier?.address,multicallAddress:a=t.multicallAddress??e.chain?.contracts?.multicall3?.address}=t,o=(()=>{let e=t.signature;return Nt(e)?e:typeof e==`object`&&`r`in e&&`s`in e?rv(e):An(e)})();try{return F_(o)?await av(e,{...t,multicallAddress:a,signature:o}):await ov(e,{...t,verifierAddress:i,signature:o})}catch(e){try{if(Ld(_i(n),await pu({hash:r,signature:o})))return!0}catch{}if(e instanceof cv)return!1;throw e}}async function av(e,t){let{address:n,blockNumber:r,blockTag:i,hash:a,multicallAddress:o}=t,{authorization:s,data:c,signature:l,to:u}=N_(t.signature);if(await Zm(e,{address:n,blockNumber:r,blockTag:i})===Ei([`0xef0100`,s.address]))return await sv(e,{address:n,blockNumber:r,blockTag:i,hash:a,signature:l});let d={address:s.address,chainId:Number(s.chainId),nonce:Number(s.nonce),r:k(s.r,{size:32}),s:k(s.s,{size:32}),yParity:s.yParity};if(!await hh({address:n,authorization:d}))throw new cv;let f=await E(e,hm,`readContract`)({...o?{address:o}:{code:xp},authorizationList:[d],abi:dp,blockNumber:r,blockTag:`pending`,functionName:`aggregate3`,args:[[...c?[{allowFailure:!0,target:u??n,callData:c}]:[],{allowFailure:!0,target:n,callData:sa({abi:mp,functionName:`isValidSignature`,args:[a,l]})}]]});if((f[f.length-1]?.returnData)?.startsWith(`0x1626ba7e`))return!0;throw new cv}async function ov(e,t){let{address:n,factory:r,factoryData:i,hash:a,signature:o,verifierAddress:s,...c}=t,l=await(async()=>!r&&!i||tv(o)?o:ev({data:i,signature:o,to:r}))(),u=s?{to:s,data:sa({abi:hp,functionName:`isValidSig`,args:[n,a,l]}),...c}:{data:kp({abi:hp,args:[n,a,l],bytecode:bp}),...c},{data:d}=await E(e,cm,`call`)(u).catch(e=>{throw e instanceof yo?new cv:e});if(Tn(d??`0x0`))return!0;throw new cv}async function sv(e,t){let{address:n,blockNumber:r,blockTag:i,hash:a,signature:o}=t;if((await E(e,hm,`readContract`)({address:n,abi:mp,args:[a,o],blockNumber:r,blockTag:i,functionName:`isValidSignature`}).catch(e=>{throw e instanceof bo?new cv:e})).startsWith(`0x1626ba7e`))return!0;throw new cv}var cv=class extends Error{};Dn(),Va();function lv(e,{emitOnBegin:t=!1,emitMissed:n=!1,onBlockNumber:r,onError:i,poll:a,pollingInterval:o=e.pollingInterval}){let s=(()=>a===void 0?!(e.transport.type===`webSocket`||e.transport.type===`ipc`||e.transport.type===`fallback`&&(e.transport.transports[0].config.type===`webSocket`||e.transport.transports[0].config.type===`ipc`)):a)(),c;return s?(()=>{let a=Ba([`watchBlockNumber`,e.uid,t,n,o]);return ym(a,{onBlockNumber:r,onError:i},r=>xm(async()=>{try{let t=await E(e,Dm,`getBlockNumber`)({cacheTime:0});if(c!==void 0){if(t===c)return;if(t-c>1&&n)for(let e=c+1n;e<t;e++)r.onBlockNumber(e,c),c=e}(c===void 0||t>c)&&(r.onBlockNumber(t,c),c=t)}catch(e){r.onError?.(e)}},{emitOnBegin:t,interval:o}))})():(()=>{let a=Ba([`watchBlockNumber`,e.uid,t,n]);return ym(a,{onBlockNumber:r,onError:i},t=>{let n=!0,r=()=>n=!1;return(async()=>{try{let{unsubscribe:i}=await(()=>{if(e.transport.type===`fallback`){let t=e.transport.transports.find(e=>e.config.type===`webSocket`||e.config.type===`ipc`);return t?t.value:e.transport}return e.transport})().subscribe({params:[`newHeads`],onData(e){if(!n)return;let r=wn(e.result?.number);t.onBlockNumber(r,c),c=r},onError(e){t.onError?.(e)}});r=i,n||r()}catch(e){i?.(e)}})(),()=>r()})})()}ho(),Lp(),Va();async function uv(e,t){let{checkReplacement:n=!0,confirmations:r=1,hash:i,onReplaced:a,retryCount:o=6,retryDelay:s=({count:e})=>~~(1<<e)*200,timeout:c=18e4}=t,l=Ba([`waitForTransactionReceipt`,e.uid,i]),u=(()=>t.pollingInterval?t.pollingInterval:e.chain?.experimental_preconfirmationTime?e.chain.experimental_preconfirmationTime:e.pollingInterval)(),d,f,p,m=!1,h,g,{promise:_,resolve:v,reject:y}=Ip(),b=c?setTimeout(()=>{g?.(),h?.(),y(new mo({hash:i}))},c):void 0;return h=ym(l,{onReplaced:a,resolve:v,reject:y},async t=>{if(p=await E(e,R_,`getTransactionReceipt`)({hash:i}).catch(()=>void 0),p&&r<=1){clearTimeout(b),t.resolve(p),h?.();return}g=E(e,lv,`watchBlockNumber`)({emitMissed:!0,emitOnBegin:!0,poll:!0,pollingInterval:u,async onBlockNumber(a){let c=e=>{clearTimeout(b),g?.(),e(),h?.()},l=a;if(!m)try{if(p){if(r>1&&(!p.blockNumber||l-p.blockNumber+1n<r))return;c(()=>t.resolve(p));return}if(n&&!d&&(m=!0,await Lm(async()=>{d=await E(e,L_,`getTransaction`)({hash:i}),d.blockNumber&&(l=d.blockNumber)},{delay:s,retryCount:o}),m=!1),p=await E(e,R_,`getTransactionReceipt`)({hash:i}),r>1&&(!p.blockNumber||l-p.blockNumber+1n<r))return;c(()=>t.resolve(p))}catch(n){if(n instanceof uo||n instanceof fo){if(!d){m=!1;return}try{f=d,m=!0;let n=await Lm(()=>E(e,ud,`getBlock`)({blockNumber:l,includeTransactions:!0}),{delay:s,retryCount:o,shouldRetry:({error:e})=>e instanceof rd});m=!1;let i=n.transactions.find(({from:e,nonce:t})=>e===f.from&&t===f.nonce);if(!i||(p=await E(e,R_,`getTransactionReceipt`)({hash:i.hash}),r>1&&(!p.blockNumber||l-p.blockNumber+1n<r)))return;let a=`replaced`;i.to===f.to&&i.value===f.value&&i.input===f.input?a=`repriced`:i.from===i.to&&i.value===0n&&(a=`cancelled`),c(()=>{t.onReplaced?.({reason:a,replacedTransaction:f,transaction:i,transactionReceipt:p}),t.resolve(p)})}catch(e){c(()=>t.reject(e))}}else c(()=>t.reject(n))}}})}),_}ho();async function dv(e,{serializedTransaction:t,throwOnReceiptRevert:n,timeout:r}){let i=await e.request({method:`eth_sendRawTransactionSync`,params:r?[t,k(r)]:[t]},{retryCount:0}),a=(e.chain?.formatters?.transactionReceipt?.format||zm)(i);if(a.status===`reverted`&&n)throw new po({receipt:a});return a}A();async function fv(e,{chain:t}){let{id:n,name:r,nativeCurrency:i,rpcUrls:a,blockExplorers:o}=t;await e.request({method:`wallet_addEthereumChain`,params:[{chainId:k(n),chainName:r,nativeCurrency:i,rpcUrls:a.default.http,blockExplorerUrls:o?Object.values(o).map(({url:e})=>e):void 0}]},{dedupe:!0,retryCount:0})}jp();function pv(e,t){let{abi:n,args:r,bytecode:i,...a}=t,o=kp({abi:n,args:r,bytecode:i});return Pm(e,{...a,...a.authorizationList?{to:null}:{},data:o})}yi();async function mv(e){return e.account?.type===`local`?[e.account.address]:(await e.request({method:`eth_accounts`},{dedupe:!0})).map(e=>gi(e))}ra(),A();async function hv(e,t={}){let{account:n=e.account,chainId:r}=t,i=n?na(n):void 0,a=r?[i?.address,[k(r)]]:[i?.address],o=await e.request({method:`wallet_getCapabilities`,params:a}),s={};for(let[e,t]of Object.entries(o)){s[Number(e)]={};for(let[n,r]of Object.entries(t))n===`addSubAccount`&&(n=`unstable_addSubAccount`),s[Number(e)][n]=r}return typeof r==`number`?s[r]:s}async function gv(e){return await e.request({method:`wallet_getPermissions`},{dedupe:!0})}ra(),Rd();async function _v(e,t){let{account:n=e.account,chainId:r,nonce:i}=t;if(!n)throw new Om({docsPath:`/docs/eip7702/prepareAuthorization`});let a=na(n),o=(()=>{if(t.executor)return t.executor===`self`?t.executor:na(t.executor)})(),s={address:t.contractAddress??t.address,chainId:r,nonce:i};return s.chainId===void 0&&(s.chainId=e.chain?.id??await E(e,Md,`getChainId`)({})),s.nonce===void 0&&(s.nonce=await E(e,md,`getTransactionCount`)({address:a.address,blockTag:`pending`}),(o===`self`||o?.address&&Ld(o.address,a.address))&&(s.nonce+=1)),s}yi();async function vv(e){return(await e.request({method:`eth_requestAccounts`},{dedupe:!0,retryCount:0})).map(e=>_i(e))}async function yv(e,t){return e.request({method:`wallet_requestPermissions`,params:[t]},{retryCount:0})}async function bv(e,t){let{chain:n=e.chain}=t,r=t.timeout??Math.max((n?.blockTime??0)*3,5e3),i=await Hm(e,t);return await Wm(e,{...t,id:i.id,timeout:r})}ra(),O(),ho(),Lu(),Wu(),hi(),$u();var xv=new mi(128);async function Sv(e,t){let{account:n=e.account,chain:r=e.chain,accessList:i,authorizationList:a,blobs:o,data:s,gas:c,gasPrice:l,maxFeePerBlobGas:u,maxFeePerGas:d,maxPriorityFeePerGas:f,nonce:p,pollingInterval:m,throwOnReceiptRevert:h,type:g,value:_,...v}=t,y=t.timeout??Math.max((r?.blockTime??0)*3,5e3);if(n===void 0)throw new Om({docsPath:`/docs/actions/wallet/sendTransactionSync`});let b=n?na(n):null;try{Qu(t);let n=await(async()=>{if(t.to)return t.to;if(t.to!==null&&a&&a.length>0)return await vu({authorization:a[0]}).catch(()=>{throw new D(\"`to` is required. Could not infer from `authorizationList`.\")})})();if(b?.type===`json-rpc`||b===null){let t;r!==null&&(t=await E(e,Md,`getChainId`)({}),Am({currentChainId:t,chain:r}));let x=e.chain?.formatters?.transactionRequest?.format,S=(x||Bu)({...Iu(v,{format:x}),accessList:i,authorizationList:a,blobs:o,chainId:t,data:s,from:b?.address,gas:c,gasPrice:l,maxFeePerBlobGas:u,maxFeePerGas:d,maxPriorityFeePerGas:f,nonce:p,to:n,type:g,value:_},`sendTransaction`),C=xv.get(e.uid),w=C?`wallet_sendTransaction`:`eth_sendTransaction`,ee=await(async()=>{try{return await e.request({method:w,params:[S]},{retryCount:0})}catch(t){if(C===!1)throw t;let n=t;if(n.name===`InvalidInputRpcError`||n.name===`InvalidParamsRpcError`||n.name===`MethodNotFoundRpcError`||n.name===`MethodNotSupportedRpcError`)return await e.request({method:`wallet_sendTransaction`,params:[S]},{retryCount:0}).then(t=>(xv.set(e.uid,!0),t)).catch(t=>{let r=t;throw r.name===`MethodNotFoundRpcError`||r.name===`MethodNotSupportedRpcError`?(xv.set(e.uid,!1),n):r});throw n}})(),te=await E(e,uv,`waitForTransactionReceipt`)({checkReplacement:!1,hash:ee,pollingInterval:m,timeout:y});if(h&&te.status===`reverted`)throw new po({receipt:te});return te}if(b?.type===`local`){let t=await E(e,Fd,`prepareTransactionRequest`)({account:b,accessList:i,authorizationList:a,blobs:o,chain:r,data:s,gas:c,gasPrice:l,maxFeePerBlobGas:u,maxFeePerGas:d,maxPriorityFeePerGas:f,nonce:p,nonceManager:b.nonceManager,parameters:[...Nd,`sidecars`],type:g,value:_,...v,to:n}),m=r?.serializers?.transaction,y=await b.signTransaction(t,{serializer:m});return await E(e,dv,`sendRawTransactionSync`)({serializedTransaction:y,throwOnReceiptRevert:h})}throw b?.type===`smart`?new km({metaMessages:[\"Consider using the `sendUserOperation` Action instead.\"],docsPath:`/docs/actions/bundler/sendUserOperation`,type:`smart`}):new km({docsPath:`/docs/actions/wallet/sendTransactionSync`,type:b?.type})}catch(e){throw e instanceof km?e:jm(e,{...t,account:b,chain:t.chain||void 0})}}async function Cv(e,t){let{id:n}=t;await e.request({method:`wallet_showCallsStatus`,params:[n]})}ra();async function wv(e,t){let{account:n=e.account}=t;if(!n)throw new Om({docsPath:`/docs/eip7702/signAuthorization`});let r=na(n);if(!r.signAuthorization)throw new km({docsPath:`/docs/eip7702/signAuthorization`,metaMessages:[\"The `signAuthorization` Action does not support JSON-RPC Accounts.\"],type:r.type});let i=await _v(e,t);return r.signAuthorization(i)}ra(),A();async function Tv(e,{account:t=e.account,message:n}){if(!t)throw new Om({docsPath:`/docs/actions/wallet/signMessage`});let r=na(t);if(r.signMessage)return r.signMessage({message:n});let i=(()=>typeof n==`string`?jn(n):n.raw instanceof Uint8Array?On(n.raw):n.raw)();return e.request({method:`personal_sign`,params:[i,r.address]},{retryCount:0})}ra(),A(),Wu(),$u();async function Ev(e,t){let{account:n=e.account,chain:r=e.chain,...i}=t;if(!n)throw new Om({docsPath:`/docs/actions/wallet/signTransaction`});let a=na(n);Qu({account:a,...t});let o=await E(e,Md,`getChainId`)({});r!==null&&Am({currentChainId:o,chain:r});let s=(r?.formatters||e.chain?.formatters)?.transactionRequest?.format||Bu;return a.signTransaction?a.signTransaction({...i,chainId:o},{serializer:e.chain?.serializers?.transaction}):await e.request({method:`eth_signTransaction`,params:[{...s(i,`signTransaction`),chainId:k(o),from:a.address}]},{retryCount:0})}ra();async function Dv(e,t){let{account:n=e.account,domain:r,message:i,primaryType:a}=t;if(!n)throw new Om({docsPath:`/docs/actions/wallet/signTypedData`});let o=na(n),s={EIP712Domain:jh({domain:r}),...t.types};if(Ah({domain:r,message:i,primaryType:a,types:s}),o.signTypedData)return o.signTypedData({domain:r,message:i,primaryType:a,types:s});let c=kh({domain:r,message:i,primaryType:a,types:s});return e.request({method:`eth_signTypedData_v4`,params:[o.address,c]},{retryCount:0})}A();async function Ov(e,{id:t}){await e.request({method:`wallet_switchEthereumChain`,params:[{chainId:k(t)}]},{retryCount:0})}async function kv(e,t){return await e.request({method:`wallet_watchAsset`,params:t},{retryCount:0})}async function Av(e,t){return Fm.internal(e,Sv,`sendTransactionSync`,t)}function jv(e){return{addChain:t=>fv(e,t),deployContract:t=>pv(e,t),getAddresses:()=>mv(e),getCallsStatus:t=>Um(e,t),getCapabilities:t=>hv(e,t),getChainId:()=>Md(e),getPermissions:()=>gv(e),prepareAuthorization:t=>_v(e,t),prepareTransactionRequest:t=>Fd(e,t),requestAddresses:()=>vv(e),requestPermissions:t=>yv(e,t),sendCalls:t=>Hm(e,t),sendCallsSync:t=>bv(e,t),sendRawTransaction:t=>Mm(e,t),sendRawTransactionSync:t=>dv(e,t),sendTransaction:t=>Pm(e,t),sendTransactionSync:t=>Sv(e,t),showCallsStatus:t=>Cv(e,t),signAuthorization:t=>wv(e,t),signMessage:t=>Tv(e,t),signTransaction:t=>Ev(e,t),signTypedData:t=>Dv(e,t),switchChain:t=>Ov(e,t),waitForCallsStatus:t=>Wm(e,t),watchAsset:t=>kv(e,t),writeContract:t=>Fm(e,t),writeContractSync:t=>Av(e,t)}}function Mv(e){let{key:t=`wallet`,name:n=`Wallet Client`,transport:r}=e;return Xm({...e,key:t,name:n,transport:r,type:`walletClient`}).extend(jv)}function Nv({key:e,methods:t,name:n,request:r,retryCount:i=3,retryDelay:a=150,timeout:o,type:s},c){let l=Ym();return{config:{key:e,methods:t,name:n,request:r,retryCount:i,retryDelay:a,timeout:o,type:s},request:vh(r,{methods:t,retryCount:i,retryDelay:a,uid:l}),value:c}}function Pv(e,t={}){let{key:n=`custom`,methods:r,name:i=`Custom Provider`,retryDelay:a}=t;return({retryCount:o})=>Nv({key:n,methods:r,name:i,request:e.request.bind(e),retryCount:t.retryCount??o,retryDelay:a,type:`custom`})}Mu(),os();function Fv(e,t={}){let{key:n=`fallback`,name:r=`Fallback`,rank:i=!1,shouldThrow:a=Iv,retryCount:o,retryDelay:s}=t;return(({chain:t,pollingInterval:c=4e3,timeout:l,...u})=>{let d=e,f=()=>{},p=Nv({key:n,name:r,async request({method:e,params:n}){let r,i=async(o=0)=>{let s=d[o]({...u,chain:t,retryCount:0,timeout:l});try{let t=await s.request({method:e,params:n});return f({method:e,params:n,response:t,transport:s,status:`success`}),t}catch(c){if(f({error:c,method:e,params:n,transport:s,status:`error`}),a(c)||o===d.length-1||(r??=d.slice(o+1).some(n=>{let{include:r,exclude:i}=n({chain:t}).config.methods||{};return r?r.includes(e):i?!i.includes(e):!0}),!r))throw c;return i(o+1)}};return i()},retryCount:o,retryDelay:s,type:`fallback`},{onResponse:e=>f=e,transports:d.map(e=>e({chain:t,retryCount:0}))});if(i){let e=typeof i==`object`?i:{};Lv({chain:t,interval:e.interval??c,onTransports:e=>d=e,ping:e.ping,sampleCount:e.sampleCount,timeout:e.timeout,transports:d,weights:e.weights})}return p})}function Iv(e){return!!(`code`in e&&typeof e.code==`number`&&(e.code===Bo.code||e.code===Wo.code||bu.nodeMessage.test(e.message)||e.code===5e3))}function Lv({chain:e,interval:t=4e3,onTransports:n,ping:r,sampleCount:i=10,timeout:a=1e3,transports:o,weights:s={}}){let{stability:c=.7,latency:l=.3}=s,u=[],d=async()=>{let s=await Promise.all(o.map(async t=>{let n=t({chain:e,retryCount:0,timeout:a}),i=Date.now(),o,s;try{await(r?r({transport:n}):n.request({method:`net_listening`})),s=1}catch{s=0}finally{o=Date.now()}return{latency:o-i,success:s}}));u.push(s),u.length>i&&u.shift();let f=Math.max(...u.map(e=>Math.max(...e.map(({latency:e})=>e)))),p=o.map((e,t)=>{let n=u.map(e=>e[t].latency),r=1-n.reduce((e,t)=>e+t,0)/n.length/f,i=u.map(e=>e[t].success),a=i.reduce((e,t)=>e+t,0)/i.length;return a===0?[0,t]:[l*r+c*a,t]}).sort((e,t)=>t[0]-e[0]);n(p.map(([,e])=>o[e])),await bm(t),d()};d()}O();var Rv=class extends D{constructor(){super(`No URL was provided to the Transport. Please provide a valid RPC URL to the Transport.`,{docsPath:`/docs/clients/intro`,name:`UrlRequiredError`})}};ko(),Bp();function zv(e,t={}){let{batch:n,fetchFn:r,fetchOptions:i,key:a=`http`,methods:o,name:s=`HTTP JSON-RPC`,onFetchRequest:c,onFetchResponse:l,retryDelay:u,raw:d}=t;return({chain:f,retryCount:p,timeout:m})=>{let{batchSize:h=1e3,wait:g=0}=typeof n==`object`?n:{},_=t.retryCount??p,v=m??t.timeout??1e4,y=e||f?.rpcUrls.default.http[0];if(!y)throw new Rv;let b=Ch(y,{fetchFn:r,fetchOptions:i,onRequest:c,onResponse:l,timeout:v});return Nv({key:a,methods:o,name:s,async request({method:e,params:t}){let r={method:e,params:t},{schedule:i}=Rp({id:y,wait:g,shouldSplitBatch(e){return e.length>h},fn:e=>b.request({body:e}),sort:(e,t)=>e.id-t.id}),[{error:a,result:o}]=await(async e=>n?i(e):[await b.request({body:e})])(r);if(d)return{error:a,result:o};if(a)throw new Do({body:r,error:a,url:y});return o},retryCount:_,retryDelay:u,timeout:v,type:`http`},{fetchOptions:i,url:y})}}const Bv=L({id:16600,name:`0G Newton Testnet`,nativeCurrency:{name:`A0GI`,symbol:`A0GI`,decimals:18},rpcUrls:{default:{http:[`https://evmrpc-testnet.0g.ai`]}},blockExplorers:{default:{name:`0G BlockChain Explorer`,url:`https://chainscan-newton.0g.ai`}},testnet:!0}),Vv=L({id:16601,name:`0G Galileo Testnet`,nativeCurrency:{name:`A0GI`,symbol:`A0GI`,decimals:18},rpcUrls:{default:{http:[`https://evmrpc-testnet.0g.ai`]}},blockExplorers:{default:{name:`0G BlockChain Explorer`,url:`https://chainscan-galileo.0g.ai`}},testnet:!0}),Hv=L({id:16661,name:`0G Mainnet`,nativeCurrency:{name:`0G`,symbol:`0G`,decimals:18},rpcUrls:{default:{http:[`https://evmrpc.0g.ai`]}},blockExplorers:{default:{name:`0G BlockChain Explorer`,url:`https://chainscan.0g.ai`}},testnet:!1}),Uv=L({id:995,name:`5ireChain`,nativeCurrency:{name:`5ire Token`,symbol:`5IRE`,decimals:18},rpcUrls:{default:{http:[`https://rpc.5ire.network`]}},blockExplorers:{default:{name:`5ireChain Mainnet Explorer`,url:`https://5irescan.io/`}},testnet:!1}),Wv=L({id:179,name:`ABEY Mainnet`,nativeCurrency:{name:`ABEY`,symbol:`ABEY`,decimals:18},rpcUrls:{default:{http:[`https://rpc.abeychain.com`]}},blockExplorers:{default:{name:`Abey Scan`,url:`https://abeyscan.com`}},testnet:!1});Zu();const Gv=50000n,Kv=Yu*32n;Dn(),Hn(),A(),Wu();const qv={block:ld({format(e){let t=e.transactions?.map(e=>{if(typeof e==`string`)return e;let t=qv.transaction?.format(e);return t.typeHex===`0x71`?t.type=`eip712`:t.typeHex===`0xff`&&(t.type=`priority`),t});return{l1BatchNumber:e.l1BatchNumber?wn(e.l1BatchNumber):null,l1BatchTimestamp:e.l1BatchTimestamp?wn(e.l1BatchTimestamp):null,transactions:t}}}),transaction:od({format(e){let t={};return e.type===`0x71`?t.type=`eip712`:e.type===`0xff`&&(t.type=`priority`),{...t,l1BatchNumber:e.l1BatchNumber?wn(e.l1BatchNumber):null,l1BatchTxIndex:e.l1BatchTxIndex?wn(e.l1BatchTxIndex):null}}}),transactionReceipt:Bm({format(e){return{l1BatchNumber:e.l1BatchNumber?wn(e.l1BatchNumber):null,l1BatchTxIndex:e.l1BatchTxIndex?wn(e.l1BatchTxIndex):null,logs:e.logs.map(e=>({...zd(e),l1BatchNumber:e.l1BatchNumber?wn(e.l1BatchNumber):null,transactionLogIndex:En(e.transactionLogIndex),logType:e.logType})),l2ToL1Logs:e.l2ToL1Logs.map(e=>({blockNumber:wn(e.blockHash),blockHash:e.blockHash,l1BatchNumber:e.l1BatchNumber?wn(e.l1BatchNumber):null,transactionIndex:wn(e.transactionIndex),shardId:wn(e.shardId),isService:e.isService,sender:e.sender,key:e.key,value:e.value,transactionHash:e.transactionHash,logIndex:wn(e.logIndex)}))}}}),transactionRequest:Uu({exclude:[`customSignature`,`factoryDeps`,`gasPerPubdata`,`paymaster`,`paymasterInput`],format(e){return e.gasPerPubdata||e.paymaster&&e.paymasterInput||e.factoryDeps||e.customSignature?{eip712Meta:{...e.gasPerPubdata?{gasPerPubdata:On(e.gasPerPubdata)}:{gasPerPubdata:On(Gv)},...e.paymaster&&e.paymasterInput?{paymasterParams:{paymaster:e.paymaster,paymasterInput:Array.from(Ln(e.paymasterInput))}}:{},...e.factoryDeps?{factoryDeps:e.factoryDeps.map(e=>Array.from(Ln(e)))}:{},...e.customSignature?{customSignature:Array.from(Ln(e.customSignature))}:{}},type:`0x71`}:{}}})};O();var Jv=class extends D{constructor(){super([`Transaction is not an EIP712 transaction.`,``,`Transaction must:`,'  - include `type: \"eip712\"`',\"  - include one of the following: `customSignature`, `paymaster`, `paymasterInput`, `gasPerPubdata`, `factoryDeps`\"].join(`\n`),{name:`InvalidEip712TransactionError`})}};function Yv(e){return!!(e.type===`eip712`||`customSignature`in e&&e.customSignature||`paymaster`in e&&e.paymaster||`paymasterInput`in e&&e.paymasterInput||`gasPerPubdata`in e&&typeof e.gasPerPubdata==`bigint`||`factoryDeps`in e&&e.factoryDeps)}pi(),O(),Op(),Ci();function Xv(e){let{chainId:t,to:n,from:r,paymaster:i,paymasterInput:a}=e;if(!Yv(e))throw new Jv;if(!t||t<=0)throw new Dp({chainId:t});if(n&&!bi(n))throw new fi({address:n});if(r&&!bi(r))throw new fi({address:r});if(i&&!bi(i))throw new fi({address:i});if(i&&!a)throw new D(\"`paymasterInput` must be provided when `paymaster` is defined\");if(!i&&a)throw new D(\"`paymaster` must be provided when `paymasterInput` is defined\")}Di(),A();function Zv(e,t){return Yv(e)?$v(e):sh(e,t)}const Qv={transaction:Zv};function $v(e){let{chainId:t,gas:n,nonce:r,to:i,from:a,value:o,maxFeePerGas:s,maxPriorityFeePerGas:c,customSignature:l,factoryDeps:u,paymaster:d,paymasterInput:f,gasPerPubdata:p,data:m}=e;Xv(e);let h=[r?On(r):`0x`,c?On(c):`0x`,s?On(s):`0x`,n?On(n):`0x`,i??`0x`,o?On(o):`0x`,m??`0x`,On(t),On(``),On(``),On(t),a??`0x`,On(p||Gv),u??[],l??`0x`,d&&f?[d,f]:[]];return Ei([`0x71`,M(h)])}O();var ey=class extends D{constructor({givenLength:e,maxBytecodeSize:t}){super(`Bytecode cannot be longer than ${t} bytes. Given length: ${e}`,{name:`BytecodeLengthExceedsMaxSizeError`})}},ty=class extends D{constructor({givenLengthInWords:e}){super(`Bytecode length in 32-byte words must be odd. Given length in words: ${e}`,{name:`BytecodeLengthInWordsMustBeOddError`})}},ny=class extends D{constructor({givenLength:e}){super(`The bytecode length in bytes must be divisible by 32. Given length: ${e}`,{name:`BytecodeLengthMustBeDivisibleBy32Error`})}};hn(),Hn();function ry(e){let t=Pn(e);if(t.length%32!=0)throw new ny({givenLength:t.length});if(t.length>Kv)throw new ey({givenLength:t.length,maxBytecodeSize:Kv});let n=vd(t),r=Pn(n),i=t.length/32;if(i%2==0)throw new ty({givenLengthInWords:i});let a=Pn(i),o=fn(a,{size:2}),s=new Uint8Array([1,0]);return r.set(s,0),r.set(o,2),r}A();const iy=e=>{Xv(e);let t=ay(e);return{domain:{name:`zkSync`,version:`2`,chainId:e.chainId},types:{Transaction:[{name:`txType`,type:`uint256`},{name:`from`,type:`uint256`},{name:`to`,type:`uint256`},{name:`gasLimit`,type:`uint256`},{name:`gasPerPubdataByteLimit`,type:`uint256`},{name:`maxFeePerGas`,type:`uint256`},{name:`maxPriorityFeePerGas`,type:`uint256`},{name:`paymaster`,type:`uint256`},{name:`nonce`,type:`uint256`},{name:`value`,type:`uint256`},{name:`data`,type:`bytes`},{name:`factoryDeps`,type:`bytes32[]`},{name:`paymasterInput`,type:`bytes`}]},primaryType:`Transaction`,message:t}};function ay(e){let{gas:t,nonce:n,to:r,from:i,value:a,maxFeePerGas:o,maxPriorityFeePerGas:s,factoryDeps:c,paymaster:l,paymasterInput:u,gasPerPubdata:d,data:f}=e;return{txType:113n,from:BigInt(i),to:r?BigInt(r):0n,gasLimit:t??0n,gasPerPubdataByteLimit:d??50000n,maxFeePerGas:o??0n,maxPriorityFeePerGas:s??0n,paymaster:l?BigInt(l):0n,nonce:n?BigInt(n):0n,value:a??0n,data:f??`0x`,factoryDeps:c?.map(e=>On(ry(e)))??[],paymasterInput:u||`0x`}}const oy={blockTime:1e3,formatters:qv,serializers:Qv,custom:{getEip712Domain:iy}},sy=L({...oy,id:2741,name:`Abstract`,nativeCurrency:{decimals:18,name:`ETH`,symbol:`ETH`},rpcUrls:{default:{http:[`https://api.mainnet.abs.xyz`],webSocket:[`wss://api.mainnet.abs.xyz/ws`]}},blockExplorers:{default:{name:`Etherscan`,url:`https://abscan.org`},native:{name:`Abstract Explorer`,url:`https://explorer.mainnet.abs.xyz`}},contracts:{multicall3:{address:`0xAa4De41dba0Ca5dCBb288b7cC6b708F3aaC759E7`,blockCreated:5288},erc6492Verifier:{address:`0xfB688330379976DA81eB64Fe4BF50d7401763B9C`,blockCreated:5263}}}),cy=L({...oy,id:11124,name:`Abstract Testnet`,nativeCurrency:{decimals:18,name:`ETH`,symbol:`ETH`},rpcUrls:{default:{http:[`https://api.testnet.abs.xyz`]}},blockExplorers:{default:{name:`Etherscan`,url:`https://sepolia.abscan.org`},native:{name:`Abstract Explorer`,url:`https://explorer.testnet.abs.xyz`}},testnet:!0,contracts:{multicall3:{address:`0xF9cda624FBC7e059355ce98a31693d299FACd963`,blockCreated:358349},erc6492Verifier:{address:`0xfB688330379976DA81eB64Fe4BF50d7401763B9C`,blockCreated:431682}}}),ly=L({id:787,name:`Acala`,network:`acala`,nativeCurrency:{name:`Acala`,symbol:`ACA`,decimals:18},rpcUrls:{default:{http:[`https://eth-rpc-acala.aca-api.network`],webSocket:[`wss://eth-rpc-acala.aca-api.network`]}},blockExplorers:{default:{name:`Acala Blockscout`,url:`https://blockscout.acala.network`,apiUrl:`https://blockscout.acala.network/api`}},testnet:!1}),uy=L({id:47,name:`Acria IntelliChain`,nativeCurrency:{decimals:18,name:`ACRIA`,symbol:`ACRIA`},rpcUrls:{default:{http:[`https://aic.acria.ai`]}},blockExplorers:{default:{name:`Acria Explorer`,url:`https://explorer.acria.ai`}},testnet:!1}),dy=L({id:1215,name:`ADF Chain`,nativeCurrency:{name:`ADDFILL`,symbol:`ADF`,decimals:18},rpcUrls:{default:{http:[`https://mainnet.adftechnology.com`]}},blockExplorers:{default:{name:`ADF Mainnet Explorer`,url:`https://explorer.adftechnology.com`}},testnet:!1}),fy=L({id:9990,name:`Agung Network`,nativeCurrency:{decimals:18,name:`Agung`,symbol:`AGNG`},rpcUrls:{default:{http:[`https://wss-async.agung.peaq.network`],webSocket:[`wss://wss-async.agung.peaq.network`]}},blockExplorers:{default:{name:`Subscan`,url:`https://agung-testnet.subscan.io`}},testnet:!0}),py=L({id:168,name:`AIOZ Network`,nativeCurrency:{decimals:18,name:`AIOZ`,symbol:`AIOZ`},rpcUrls:{default:{http:[`https://eth-dataseed.aioz.network`]}},blockExplorers:{default:{name:`AIOZ Explorer`,url:`https://explorer.aioz.network`}},testnet:!1}),my=L({id:41455,name:`Aleph Zero`,nativeCurrency:{name:`Aleph Zero`,symbol:`AZERO`,decimals:18},rpcUrls:{default:{http:[`https://rpc.alephzero.raas.gelato.cloud`]}},blockExplorers:{default:{name:`Aleph Zero EVM Explorer`,url:`https://evm-explorer.alephzero.org`,apiUrl:`https://evm-explorer.alephzero.org/api`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:4603377}}}),hy=L({id:2039,name:`Aleph Zero Testnet`,nativeCurrency:{name:`TZERO`,symbol:`TZERO`,decimals:18},rpcUrls:{default:{http:[`https://rpc.alephzero-testnet.gelato.digital`],webSocket:[`wss://ws.alephzero-testnet.gelato.digital`]}},blockExplorers:{default:{name:`Aleph Zero EVM Testnet explorer`,url:`https://evm-explorer-testnet.alephzero.org`,apiUrl:`https://evm-explorer-testnet.alephzero.org/api`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:2861745}},testnet:!0}),gy=L({id:10241024,name:`AlienX Mainnet`,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://rpc.alienxchain.io/http`]}},blockExplorers:{default:{name:`AlienX Explorer`,url:`https://explorer.alienxchain.io`}},testnet:!1}),_y=L({id:10241025,name:`ALIENX Hal Testnet`,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://hal-rpc.alienxchain.io/http`]}},blockExplorers:{default:{name:`AlienX Explorer`,url:`https://hal-explorer.alienxchain.io`}},testnet:!0}),vy={gasPriceOracle:{address:`0x420000000000000000000000000000000000000F`},l1Block:{address:`0x4200000000000000000000000000000000000015`},l2CrossDomainMessenger:{address:`0x4200000000000000000000000000000000000007`},l2Erc721Bridge:{address:`0x4200000000000000000000000000000000000014`},l2StandardBridge:{address:`0x4200000000000000000000000000000000000010`},l2ToL1MessagePasser:{address:`0x4200000000000000000000000000000000000016`}};Dn();const yy={block:ld({format(e){return{transactions:e.transactions?.map(e=>{if(typeof e==`string`)return e;let t=ad(e);return t.typeHex===`0x7e`&&(t.isSystemTx=e.isSystemTx,t.mint=e.mint?wn(e.mint):void 0,t.sourceHash=e.sourceHash,t.type=`deposit`),t}),stateRoot:e.stateRoot}}}),transaction:od({format(e){let t={};return e.type===`0x7e`&&(t.isSystemTx=e.isSystemTx,t.mint=e.mint?wn(e.mint):void 0,t.sourceHash=e.sourceHash,t.type=`deposit`),t}}),transactionReceipt:Bm({format(e){return{l1GasPrice:e.l1GasPrice?wn(e.l1GasPrice):null,l1GasUsed:e.l1GasUsed?wn(e.l1GasUsed):null,l1Fee:e.l1Fee?wn(e.l1Fee):null,l1FeeScalar:e.l1FeeScalar?Number(e.l1FeeScalar):null}}})};pi(),Ci(),Di(),A();function by(e,t){return Cy(e)?Sy(e):sh(e,t)}const xy={transaction:by};function Sy(e){wy(e);let{sourceHash:t,data:n,from:r,gas:i,isSystemTx:a,mint:o,to:s,value:c}=e,l=[t,r,s??`0x`,o?On(o):`0x`,c?On(c):`0x`,i?On(i):`0x`,a?`0x1`:`0x`,n??`0x`];return Ei([`0x7e`,M(l)])}function Cy(e){return e.type===`deposit`||e.sourceHash!==void 0}function wy(e){let{from:t,to:n}=e;if(t&&!bi(t))throw new fi({address:t});if(n&&!bi(n))throw new fi({address:n})}const R={blockTime:2e3,contracts:vy,formatters:yy,serializers:xy};var Ty=1;const Ey=L({...R,id:888888888,name:`Ancient8`,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://rpc.ancient8.gg`]}},blockExplorers:{default:{name:`Ancient8 explorer`,url:`https://scan.ancient8.gg`,apiUrl:`https://scan.ancient8.gg/api`}},contracts:{...R.contracts,l2OutputOracle:{[Ty]:{address:`0xB09DC08428C8b4EFB4ff9C0827386CDF34277996`}},portal:{[Ty]:{address:`0x639F2AECE398Aa76b07e59eF6abe2cFe32bacb68`,blockCreated:19070571}},l1StandardBridge:{[Ty]:{address:`0xd5e3eDf5b68135D559D572E26bF863FBC1950033`,blockCreated:19070571}}},sourceId:Ty});var Dy=11155111;const Oy=L({...R,id:28122024,name:`Ancient8 Testnet`,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://rpcv2-testnet.ancient8.gg`]}},blockExplorers:{default:{name:`Ancient8 Celestia Testnet explorer`,url:`https://scanv2-testnet.ancient8.gg`,apiUrl:`https://scanv2-testnet.ancient8.gg/api`}},contracts:{...R.contracts,l2OutputOracle:{[Dy]:{address:`0x942fD5017c0F60575930D8574Eaca13BEcD6e1bB`}},portal:{[Dy]:{address:`0xfa1d9E26A6aCD7b22115D27572c1221B9803c960`,blockCreated:4972908}},l1StandardBridge:{[Dy]:{address:`0xF6Bc0146d3c74D48306e79Ae134A260E418C9335`,blockCreated:4972908}}},sourceId:Dy}),ky=L({id:31337,name:`Anvil`,nativeCurrency:{decimals:18,name:`Ether`,symbol:`ETH`},rpcUrls:{default:{http:[`http://127.0.0.1:8545`],webSocket:[`ws://127.0.0.1:8545`]}}}),Ay=L({id:33139,name:`Ape Chain`,nativeCurrency:{name:`ApeCoin`,symbol:`APE`,decimals:18},rpcUrls:{default:{http:[`https://rpc.apechain.com/http`],webSocket:[`wss://rpc.apechain.com/ws`]}},blockExplorers:{default:{name:`Apescan`,url:`https://apescan.io`,apiUrl:`https://api.apescan.io/api`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:20889}},sourceId:42161}),jy=L({id:3993,name:`APEX Testnet`,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://rpc-testnet.apexlayer.xyz`]}},blockExplorers:{default:{name:`Blockscout`,url:`https://exp-testnet.apexlayer.xyz`,apiUrl:`https://exp-testnet.apexlayer.xyz/api`}},contracts:{multicall3:{address:`0xf7642be33a6b18D16a995657adb5a68CD0438aE2`,blockCreated:283775}},testnet:!0}),My=L({id:42161,name:`Arbitrum One`,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},blockTime:250,rpcUrls:{default:{http:[`https://arb1.arbitrum.io/rpc`]}},blockExplorers:{default:{name:`Arbiscan`,url:`https://arbiscan.io`,apiUrl:`https://api.arbiscan.io/api`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:7654707}}}),Ny=L({id:421613,name:`Arbitrum Goerli`,nativeCurrency:{name:`Arbitrum Goerli Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://goerli-rollup.arbitrum.io/rpc`]}},blockExplorers:{default:{name:`Arbiscan`,url:`https://goerli.arbiscan.io`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:88114}},testnet:!0}),Py=L({id:42170,name:`Arbitrum Nova`,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://nova.arbitrum.io/rpc`]}},blockExplorers:{default:{name:`Arbiscan`,url:`https://nova.arbiscan.io`,apiUrl:`https://api-nova.arbiscan.io/api`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:1746963}}}),Fy=L({id:421614,name:`Arbitrum Sepolia`,blockTime:250,nativeCurrency:{name:`Arbitrum Sepolia Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://sepolia-rollup.arbitrum.io/rpc`]}},blockExplorers:{default:{name:`Arbiscan`,url:`https://sepolia.arbiscan.io`,apiUrl:`https://api-sepolia.arbiscan.io/api`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:81930}},testnet:!0}),Iy=L({id:7897,name:`Arena-Z`,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://rpc.arena-z.gg`]}},blockExplorers:{default:{name:`Arena-Z Explorer`,url:`https://explorer.arena-z.gg`,apiUrl:`https://explorer.arena-z.gg`}}}),Ly=L({id:463,name:`Areon Network`,nativeCurrency:{decimals:18,name:`AREA`,symbol:`AREA`},rpcUrls:{default:{http:[`https://mainnet-rpc.areon.network`],webSocket:[`wss://mainnet-ws.areon.network`]}},blockExplorers:{default:{name:`Areonscan`,url:`https://areonscan.com`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:353286}},testnet:!1}),Ry=L({id:462,name:`Areon Network Testnet`,nativeCurrency:{decimals:18,name:`TAREA`,symbol:`TAREA`},rpcUrls:{default:{http:[`https://testnet-rpc.areon.network`],webSocket:[`wss://testnet-ws.areon.network`]}},blockExplorers:{default:{name:`Areonscan`,url:`https://areonscan.com`}},testnet:!0}),zy=L({id:463,name:`Areum`,nativeCurrency:{decimals:18,name:`AREA`,symbol:`AREA`},rpcUrls:{default:{http:[`https://mainnet-rpc.areum.network`],webSocket:[`wss://mainnet-ws.areum.network`]}},blockExplorers:{default:{name:`Areum Explorer`,url:`https://explorer.areum.network`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:353286}},testnet:!1}),By=L({id:11822,name:`Artela Testnet`,nativeCurrency:{name:`ART`,symbol:`ART`,decimals:18},rpcUrls:{default:{http:[`https://betanet-rpc1.artela.network`]}},blockExplorers:{default:{name:`Artela`,url:`https://betanet-scan.artela.network`,apiUrl:`https://betanet-scan.artela.network/api`}},contracts:{multicall3:{address:`0xd07c8635f76e8745Ee7092fbb6e8fbc5FeF09DD7`,blockCreated:7001871}},testnet:!0}),Vy=L({id:10242,name:`Arthera`,nativeCurrency:{name:`Arthera`,symbol:`AA`,decimals:18},rpcUrls:{default:{http:[`https://rpc.arthera.net`]}},blockExplorers:{default:{name:`Arthera EVM Explorer`,url:`https://explorer.arthera.net`,apiUrl:`https://explorer.arthera.net/api`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:4502791}}}),Hy=L({id:10243,name:`Arthera Testnet`,nativeCurrency:{name:`Arthera`,symbol:`AA`,decimals:18},rpcUrls:{default:{http:[`https://rpc-test.arthera.net`]}},blockExplorers:{default:{name:`Arthera EVM Explorer`,url:`https://explorer-test.arthera.net`,apiUrl:`https://explorer-test.arthera.net/api`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:22051}}}),Uy=L({id:42420,name:`AssetChain Mainnet`,nativeCurrency:{decimals:18,name:`Real World Asset`,symbol:`RWA`},rpcUrls:{default:{http:[`https://mainnet-rpc.assetchain.org`]}},blockExplorers:{default:{name:`Asset Chain Explorer`,url:`https://scan.assetchain.org`,apiUrl:`https://scan.assetchain.org/api`}},testnet:!1,contracts:{}}),Wy=L({id:42421,name:`AssetChain Testnet`,nativeCurrency:{decimals:18,name:`Real World Asset`,symbol:`RWA`},rpcUrls:{default:{http:[`https://enugu-rpc.assetchain.org`]}},blockExplorers:{default:{name:`Asset Chain Testnet Explorer`,url:`https://scan-testnet.assetchain.org`,apiUrl:`https://scan-testnet.assetchain.org/api`}},testnet:!0,contracts:{multicall3:{address:`0x989F832D35988cb5e3eB001Fa2Fe789469EC31Ea`,blockCreated:17177}}}),Gy=L({id:592,name:`Astar`,network:`astar-mainnet`,nativeCurrency:{name:`Astar`,symbol:`ASTR`,decimals:18},rpcUrls:{default:{http:[`https://astar.api.onfinality.io/public`]}},blockExplorers:{default:{name:`Astar Subscan`,url:`https://astar.subscan.io`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:761794}},testnet:!1}),Ky=L({id:3776,name:`Astar zkEVM`,network:`AstarZkEVM`,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://rpc-zkevm.astar.network`]}},blockExplorers:{default:{name:`Astar zkEVM Explorer`,url:`https://astar-zkevm.explorer.startale.com`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:93528}},testnet:!1}),qy=L({id:6038361,name:`Astar zkEVM Testnet zKyoto`,network:`zKyoto`,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://rpc.startale.com/zkyoto`]}},blockExplorers:{default:{name:`zKyoto Explorer`,url:`https://zkyoto.explorer.startale.com`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:196153}},testnet:!0}),Jy=L({id:2340,name:`Atleta Olympia`,nativeCurrency:{decimals:18,name:`Atla`,symbol:`ATLA`},rpcUrls:{default:{http:[`https://testnet-rpc.atleta.network:9944`,`https://testnet-rpc.atleta.network`],ws:[`wss://testnet-rpc.atleta.network:9944`]}},blockExplorers:{default:{name:`Atleta Olympia Explorer`,url:`https://blockscout.atleta.network`,apiUrl:`https://blockscout.atleta.network/api`}},contracts:{multicall3:{address:`0x1472ec6392180fb84F345d2455bCC75B26577115`,blockCreated:1076473}},testnet:!0}),Yy=L({id:1313161554,name:`Aurora`,nativeCurrency:{decimals:18,name:`Ether`,symbol:`ETH`},rpcUrls:{default:{http:[`https://mainnet.aurora.dev`]}},blockExplorers:{default:{name:`Aurorascan`,url:`https://aurorascan.dev`,apiUrl:`https://aurorascan.dev/api`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:62907816}}}),Xy=L({id:1313161555,name:`Aurora Testnet`,nativeCurrency:{decimals:18,name:`Ether`,symbol:`ETH`},rpcUrls:{default:{http:[`https://testnet.aurora.dev`]}},blockExplorers:{default:{name:`Aurorascan`,url:`https://testnet.aurorascan.dev`,apiUrl:`https://testnet.aurorascan.dev/api`}},testnet:!0}),Zy=L({id:205205,name:`Auroria Testnet`,network:`auroria`,nativeCurrency:{name:`Auroria Stratis`,symbol:`tSTRAX`,decimals:18},rpcUrls:{default:{http:[`https://auroria.rpc.stratisevm.com`]}},blockExplorers:{default:{name:`Auroria Testnet Explorer`,url:`https://auroria.explorer.stratisevm.com`}},testnet:!0}),Qy=L({id:785,name:`Autheo Testnet`,nativeCurrency:{decimals:18,name:`Autheo`,symbol:`THEO`},rpcUrls:{default:{http:[`https://testnet-rpc1.autheo.com`,`https://testnet-rpc2.autheo.com`]}},blockExplorers:{default:{name:`Autheo Testnet Block Explorer`,url:`https://testnet-explorer.autheo.com/`}}}),$y=L({id:43114,name:`Avalanche`,blockTime:1700,nativeCurrency:{decimals:18,name:`Avalanche`,symbol:`AVAX`},rpcUrls:{default:{http:[`https://api.avax.network/ext/bc/C/rpc`]}},blockExplorers:{default:{name:`SnowTrace`,url:`https://snowtrace.io`,apiUrl:`https://api.snowtrace.io`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:11907934}}}),eb=L({id:43113,name:`Avalanche Fuji`,nativeCurrency:{decimals:18,name:`Avalanche Fuji`,symbol:`AVAX`},rpcUrls:{default:{http:[`https://api.avax-test.network/ext/bc/C/rpc`]}},blockExplorers:{default:{name:`SnowTrace`,url:`https://testnet.snowtrace.io`,apiUrl:`https://api-testnet.snowtrace.io`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:7096959}},testnet:!0}),tb=L({id:8333,name:`B3`,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://mainnet-rpc.b3.fun/http`]}},blockExplorers:{default:{name:`Blockscout`,url:`https://explorer.b3.fun`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:0}},sourceId:8453}),nb=L({id:1993,name:`B3 Sepolia`,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://sepolia.b3.fun/http`]}},blockExplorers:{default:{name:`Blockscout`,url:`https://sepolia.explorer.b3.fun`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:0}},testnet:!0,sourceId:168587773}),rb=L({id:5165,network:`bahamut`,name:`Bahamut`,nativeCurrency:{name:`Fasttoken`,symbol:`FTN`,decimals:18},rpcUrls:{default:{http:[`https://rpc1.bahamut.io`,`https://bahamut-rpc.publicnode.com`,`https://rpc2.bahamut.io`],webSocket:[`wss://ws1.sahara.bahamutchain.com`,`wss://bahamut-rpc.publicnode.com`,`wss://ws2.sahara.bahamutchain.com`]}},blockExplorers:{default:{name:`Ftnscan`,url:`https://www.ftnscan.com`,apiUrl:`https://www.ftnscan.com/api`}}});var ib=1;const ab=L({...R,id:8453,name:`Base`,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://mainnet.base.org`]}},blockExplorers:{default:{name:`Basescan`,url:`https://basescan.org`,apiUrl:`https://api.basescan.org/api`}},contracts:{...R.contracts,disputeGameFactory:{[ib]:{address:`0x43edB88C4B80fDD2AdFF2412A7BebF9dF42cB40e`}},l2OutputOracle:{[ib]:{address:`0x56315b90c40730925ec5485cf004d835058518A0`}},multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:5022},portal:{[ib]:{address:`0x49048044D57e1C92A77f79988d21Fa8fAF74E97e`,blockCreated:17482143}},l1StandardBridge:{[ib]:{address:`0x3154Cf16ccdb4C6d922629664174b904d80F2C35`,blockCreated:17482143}}},sourceId:ib}),ob=L({...ab,experimental_preconfirmationTime:200,rpcUrls:{default:{http:[`https://mainnet-preconf.base.org`]}}}),sb=L({id:123420001114,name:`Basecamp Testnet`,nativeCurrency:{decimals:18,name:`Camp`,symbol:`CAMP`},rpcUrls:{default:{http:[`https://rpc.basecamp.t.raas.gelato.cloud`]}},blockExplorers:{default:{name:`basecamp`,url:`https://basecamp.cloud.blockscout.com`}},testnet:!0});var cb=5;const lb=L({...R,id:84531,name:`Base Goerli`,nativeCurrency:{name:`Goerli Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://goerli.base.org`]}},blockExplorers:{default:{name:`Basescan`,url:`https://goerli.basescan.org`,apiUrl:`https://goerli.basescan.org/api`}},contracts:{...R.contracts,l2OutputOracle:{[cb]:{address:`0x2A35891ff30313CcFa6CE88dcf3858bb075A2298`}},multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:1376988},portal:{[cb]:{address:`0xe93c8cD0D409341205A592f8c4Ac1A5fe5585cfA`}},l1StandardBridge:{[cb]:{address:`0xfA6D8Ee5BE770F84FC001D098C4bD604Fe01284a`}}},testnet:!0,sourceId:cb});var ub=11155111;const db=L({...R,id:84532,network:`base-sepolia`,name:`Base Sepolia`,nativeCurrency:{name:`Sepolia Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://sepolia.base.org`]}},blockExplorers:{default:{name:`Basescan`,url:`https://sepolia.basescan.org`,apiUrl:`https://api-sepolia.basescan.org/api`}},contracts:{...R.contracts,disputeGameFactory:{[ub]:{address:`0xd6E6dBf4F7EA0ac412fD8b65ED297e64BB7a06E1`}},l2OutputOracle:{[ub]:{address:`0x84457ca9D0163FbC4bbfe4Dfbb20ba46e48DF254`}},portal:{[ub]:{address:`0x49f53e41452c74589e85ca1677426ba426459e85`,blockCreated:4446677}},l1StandardBridge:{[ub]:{address:`0xfd0Bf71F60660E2f608ed56e1659C450eB113120`,blockCreated:4446677}},multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:1059647}},testnet:!0,sourceId:ub}),fb=L({...db,experimental_preconfirmationTime:200,rpcUrls:{default:{http:[`https://sepolia-preconf.base.org`]}}}),pb=L({id:4337,name:`Beam`,network:`beam`,nativeCurrency:{decimals:18,name:`Beam`,symbol:`BEAM`},rpcUrls:{default:{http:[`https://build.onbeam.com/rpc`],webSocket:[`wss://build.onbeam.com/ws`]}},blockExplorers:{default:{name:`Beam Explorer`,url:`https://subnets.avax.network/beam`}},contracts:{multicall3:{address:`0x4956f15efdc3dc16645e90cc356eafa65ffc65ec`,blockCreated:1}}}),mb=L({id:13337,name:`Beam Testnet`,network:`beam`,nativeCurrency:{decimals:18,name:`Beam`,symbol:`BEAM`},rpcUrls:{default:{http:[`https://build.onbeam.com/rpc/testnet`],webSocket:[`wss://build.onbeam.com/ws/testnet`]}},blockExplorers:{default:{name:`Beam Explorer`,url:`https://subnets-test.avax.network/beam`}},contracts:{multicall3:{address:`0x9bf49b704ee2a095b95c1f2d4eb9010510c41c9e`,blockCreated:3}},testnet:!0}),hb=L({id:641230,name:`Bear Network Chain Mainnet`,nativeCurrency:{decimals:18,name:`BearNetworkChain`,symbol:`BRNKC`},rpcUrls:{default:{http:[`https://brnkc-mainnet.bearnetwork.net`]}},blockExplorers:{default:{name:`BrnkScan`,url:`https://brnkscan.bearnetwork.net`,apiUrl:`https://brnkscan.bearnetwork.net/api`}}}),gb=L({id:751230,name:`Bear Network Chain Testnet`,nativeCurrency:{decimals:18,name:`tBRNKC`,symbol:`tBRNKC`},rpcUrls:{default:{http:[`https://brnkc-test.bearnetwork.net`]}},blockExplorers:{default:{name:`BrnkTestScan`,url:`https://brnktest-scan.bearnetwork.net`,apiUrl:`https://brnktest-scan.bearnetwork.net/api`}},testnet:!0}),_b=L({id:80094,name:`Berachain`,blockTime:2e3,nativeCurrency:{decimals:18,name:`BERA Token`,symbol:`BERA`},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:0},ensRegistry:{address:`0x5b22280886a2f5e09a49bea7e320eab0e5320e28`,blockCreated:877007},ensUniversalResolver:{address:`0x4D41762915F83c76EcaF6776d9b08076aA32b492`,blockCreated:9310021}},rpcUrls:{default:{http:[`https://rpc.berachain.com`]}},blockExplorers:{default:{name:`Berascan`,url:`https://berascan.com`}},ensTlds:[`.bera`],testnet:!1}),vb=L({id:80069,blockTime:2e3,name:`Berachain Bepolia`,nativeCurrency:{decimals:18,name:`BERA Token`,symbol:`BERA`},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:0}},rpcUrls:{default:{http:[`https://bepolia.rpc.berachain.com`]}},blockExplorers:{default:{name:`Berascan`,url:`https://bepolia.beratrail.io`}},testnet:!0}),yb=L({id:80085,name:`Berachain Artio`,nativeCurrency:{decimals:18,name:`BERA Token`,symbol:`BERA`},rpcUrls:{default:{http:[`https://artio.rpc.berachain.com`]}},blockExplorers:{default:{name:`Berachain`,url:`https://artio.beratrail.io`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:866924}},testnet:!0}),bb=L({id:80084,name:`Berachain bArtio`,nativeCurrency:{decimals:18,name:`BERA Token`,symbol:`BERA`},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:109269},ensRegistry:{address:`0xB0eef18971290b333450586D33dcA6cE122651D2`,blockCreated:7736794},ensUniversalResolver:{address:`0x41692Ef1EA0C79E6b73077E4A67572D2BDbD7057`,blockCreated:7736795}},ensTlds:[`.bera`],rpcUrls:{default:{http:[`https://bartio.rpc.berachain.com`]}},blockExplorers:{default:{name:`Berachain bArtio Beratrail`,url:`https://bartio.beratrail.io`}},testnet:!0}),xb=L({id:11501,name:`BEVM Mainnet`,nativeCurrency:{name:`Bitcoin`,symbol:`BTC`,decimals:18},rpcUrls:{default:{http:[`https://rpc-mainnet-1.bevm.io`]}},blockExplorers:{default:{name:`Bevmscan`,url:`https://scan-mainnet.bevm.io`,apiUrl:`https://scan-mainnet-api.bevm.io/api`}}}),Sb=L({id:3068,name:`Bifrost Mainnet`,nativeCurrency:{name:`BFC`,symbol:`BFC`,decimals:18},rpcUrls:{default:{http:[`https://public-01.mainnet.bifrostnetwork.com/rpc`]}},blockExplorers:{default:{name:`Bifrost Blockscout`,url:`https://explorer.mainnet.bifrostnetwork.com`}},testnet:!1}),Cb=L({id:53456,name:`BirdLayer`,nativeCurrency:{decimals:18,name:`Ether`,symbol:`ETH`},rpcUrls:{default:{http:[`https://rpc.birdlayer.xyz`,`https://rpc1.birdlayer.xyz`],webSocket:[`wss://rpc.birdlayer.xyz/ws`]}},blockExplorers:{default:{name:`BirdLayer Explorer`,url:`https://scan.birdlayer.xyz`}}}),wb=L({id:32520,name:`Bitgert Mainnet`,nativeCurrency:{decimals:18,name:`Brise`,symbol:`Brise`},rpcUrls:{default:{http:[`https://rpc-bitgert.icecreamswap.com`]}},blockExplorers:{default:{name:`Bitgert Scan`,url:`https://brisescan.com`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:2118034}},testnet:!1}),Tb=L({id:96,name:`KUB Mainnet`,nativeCurrency:{name:`KUB Coin`,symbol:`KUB`,decimals:18},rpcUrls:{default:{http:[`https://rpc.bitkubchain.io`]}},blockExplorers:{default:{name:`KUB Chain Mainnet Explorer`,url:`https://www.bkcscan.com`,apiUrl:`https://www.bkcscan.com/api`}}}),Eb=L({id:25925,name:`Bitkub Testnet`,network:`Bitkub Testnet`,nativeCurrency:{name:`Bitkub Test`,symbol:`tKUB`,decimals:18},rpcUrls:{default:{http:[`https://rpc-testnet.bitkubchain.io`]}},blockExplorers:{default:{name:`Bitkub Chain Testnet Explorer`,url:`https://testnet.bkcscan.com`,apiUrl:`https://testnet.bkcscan.com/api`}},testnet:!0}),Db=L({id:200901,name:`Bitlayer Mainnet`,nativeCurrency:{name:`BTC`,symbol:`BTC`,decimals:18},rpcUrls:{default:{http:[`https://rpc.bitlayer.org`],webSocket:[`wss://ws.bitlayer.org`]}},blockExplorers:{default:{name:`bitlayer mainnet scan`,url:`https://www.btrscan.com`}},contracts:{multicall3:{address:`0x5B256fE9e993902eCe49D138a5b1162cBb529474`,blockCreated:2421963}}}),Ob=L({id:200810,name:`Bitlayer Testnet`,nativeCurrency:{name:`BTC`,symbol:`BTC`,decimals:18},rpcUrls:{default:{http:[`https://testnet-rpc.bitlayer.org`],webSocket:[`wss://testnet-ws.bitlayer.org`]}},blockExplorers:{default:{name:`bitlayer testnet scan`,url:`https://testnet.btrscan.com`}},contracts:{multicall3:{address:`0x5B256fE9e993902eCe49D138a5b1162cBb529474`,blockCreated:4135671}},testnet:!0}),kb=L({id:7171,name:`Bitrock Mainnet`,nativeCurrency:{name:`BROCK`,symbol:`BROCK`,decimals:18},rpcUrls:{default:{http:[`https://brockrpc.io`]}},blockExplorers:{default:{name:`Bitrock Explorer`,url:`https://explorer.bit-rock.io`}},testnet:!1}),Ab=L({id:199,name:`BitTorrent`,network:`bittorrent-chain-mainnet`,nativeCurrency:{name:`BitTorrent`,symbol:`BTT`,decimals:18},rpcUrls:{default:{http:[`https://rpc.bittorrentchain.io`]}},blockExplorers:{default:{name:`Bttcscan`,url:`https://bttcscan.com`,apiUrl:`https://api.bttcscan.com/api`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:31078552}}}),jb=L({id:1028,name:`BitTorrent Chain Testnet`,network:`bittorrent-chain-testnet`,nativeCurrency:{name:`BitTorrent`,symbol:`BTT`,decimals:18},rpcUrls:{default:{http:[`https://testrpc.bittorrentchain.io`]}},blockExplorers:{default:{name:`Bttcscan`,url:`https://testnet.bttcscan.com`,apiUrl:`https://testnet.bttcscan.com/api`}},testnet:!0});var Mb=1;const Nb=L({...R,id:81457,name:`Blast`,nativeCurrency:{decimals:18,name:`Ether`,symbol:`ETH`},rpcUrls:{default:{http:[`https://rpc.blast.io`]}},blockExplorers:{default:{name:`Blastscan`,url:`https://blastscan.io`,apiUrl:`https://api.blastscan.io/api`}},contracts:{...R.contracts,multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:212929},l2OutputOracle:{[Mb]:{address:`0x826D1B0D4111Ad9146Eb8941D7Ca2B6a44215c76`,blockCreated:19300358}},portal:{[Mb]:{address:`0x0Ec68c5B10F21EFFb74f2A5C61DFe6b08C0Db6Cb`,blockCreated:19300357}},l1StandardBridge:{[Mb]:{address:`0x697402166Fbf2F22E970df8a6486Ef171dbfc524`,blockCreated:19300360}}},sourceId:Mb}),Pb=L({id:168587773,name:`Blast Sepolia`,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://sepolia.blast.io`]}},blockExplorers:{default:{name:`Blastscan`,url:`https://sepolia.blastscan.io`,apiUrl:`https://api-sepolia.blastscan.io/api`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:756690}},testnet:!0,sourceId:11155111});var Fb=1;const Ib=L({...R,id:60808,name:`BOB`,nativeCurrency:{decimals:18,name:`ETH`,symbol:`ETH`},rpcUrls:{default:{http:[`https://rpc.gobob.xyz`],webSocket:[`wss://rpc.gobob.xyz`]}},blockExplorers:{default:{name:`BOB Explorer`,url:`https://explorer.gobob.xyz`}},contracts:{...R.contracts,multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:23131},l2OutputOracle:{[Fb]:{address:`0xdDa53E23f8a32640b04D7256e651C1db98dB11C1`,blockCreated:4462615}},portal:{[Fb]:{address:`0x8AdeE124447435fE03e3CD24dF3f4cAE32E65a3E`,blockCreated:4462615}}},sourceId:Fb}),Lb=L({id:288,name:`Boba Network`,nativeCurrency:{decimals:18,name:`Ether`,symbol:`ETH`},rpcUrls:{default:{http:[`https://mainnet.boba.network`]}},blockExplorers:{default:{name:`BOBAScan`,url:`https://bobascan.com`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:446859}}}),Rb=L({id:28882,name:`Boba Sepolia`,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://sepolia.boba.network`]}},blockExplorers:{default:{name:`BOBAScan`,url:`https://testnet.bobascan.com`}},testnet:!0});var zb=11155111;const Bb=L({...R,id:808813,name:`BOB Sepolia`,nativeCurrency:{decimals:18,name:`ETH`,symbol:`ETH`},rpcUrls:{default:{http:[`https://bob-sepolia.rpc.gobob.xyz`],webSocket:[`wss://bob-sepolia.rpc.gobob.xyz`]}},blockExplorers:{default:{name:`BOB Sepolia Explorer`,url:`https://bob-sepolia.explorer.gobob.xyz`}},contracts:{...R.contracts,multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:35677},l2OutputOracle:{[zb]:{address:`0x14D0069452b4AE2b250B395b8adAb771E4267d2f`,blockCreated:4462615}},portal:{[zb]:{address:`0x867B1Aa872b9C8cB5E9F7755feDC45BB24Ad0ae4`,blockCreated:4462615}}},testnet:!0,sourceId:zb}),Vb=L({id:11100,name:`Bool Beta Mainnet`,nativeCurrency:{decimals:18,name:`BOL`,symbol:`BOL`},rpcUrls:{default:{http:[`https://beta-rpc-node-http.bool.network`]}},blockExplorers:{default:{name:`BoolScan`,url:`https://beta-mainnet.boolscan.com/`}},testnet:!1}),Hb=L({id:3637,name:`Botanix`,nativeCurrency:{name:`Bitcoin`,symbol:`BTC`,decimals:18},rpcUrls:{default:{http:[`https://rpc.botanixlabs.com`],webSocket:[`wss://rpc.botanixlabs.com/ws`]}},blockExplorers:{default:{name:`Botanixscan`,url:`https://botanixscan.io`}}}),Ub=L({id:3636,name:`Botanix Testnet`,nativeCurrency:{name:`Bitcoin`,symbol:`BTC`,decimals:18},rpcUrls:{default:{http:[`https://node.botanixlabs.dev`]}},blockExplorers:{default:{name:`Botanix Testnet Explorer`,url:`https://testnet.botanixscan.io`}},testnet:!0}),Wb=L({id:6001,name:`BounceBit Mainnet`,nativeCurrency:{name:`BounceBit`,symbol:`BB`,decimals:18},rpcUrls:{default:{http:[`https://fullnode-mainnet.bouncebitapi.com`]}},blockExplorers:{default:{name:`BB Scan`,url:`https://bbscan.io`}},testnet:!1}),Gb=L({id:6e3,name:`BounceBit Testnet`,nativeCurrency:{name:`BounceBit`,symbol:`BB`,decimals:18},rpcUrls:{default:{http:[`https://fullnode-testnet.bouncebitapi.com`]}},blockExplorers:{default:{name:`BB Scan`,url:`https://testnet.bbscan.io`}},testnet:!0}),Kb=L({id:1039,name:`Bronos`,nativeCurrency:{decimals:18,name:`BRO`,symbol:`BRO`},rpcUrls:{default:{http:[`https://evm.bronos.org`]}},blockExplorers:{default:{name:`BronoScan`,url:`https://broscan.bronos.org`}}}),qb=L({id:1038,name:`Bronos Testnet`,nativeCurrency:{decimals:18,name:`Bronos Coin`,symbol:`tBRO`},rpcUrls:{default:{http:[`https://evm-testnet.bronos.org`]}},blockExplorers:{default:{name:`BronoScan`,url:`https://tbroscan.bronos.org`}},testnet:!0}),Jb=L({id:56,name:`BNB Smart Chain`,blockTime:750,nativeCurrency:{decimals:18,name:`BNB`,symbol:`BNB`},rpcUrls:{default:{http:[`https://56.rpc.thirdweb.com`]}},blockExplorers:{default:{name:`BscScan`,url:`https://bscscan.com`,apiUrl:`https://api.bscscan.com/api`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:15921452}}}),Yb=L({id:1017,name:`BNB Greenfield Chain`,nativeCurrency:{decimals:18,name:`BNB`,symbol:`BNB`},rpcUrls:{default:{http:[`https://greenfield-chain.bnbchain.org`]}},blockExplorers:{default:{name:`BNB Greenfield Mainnet Scan`,url:`https://greenfieldscan.com`}},testnet:!1}),Xb=L({id:97,name:`BNB Smart Chain Testnet`,nativeCurrency:{decimals:18,name:`BNB`,symbol:`tBNB`},rpcUrls:{default:{http:[`https://data-seed-prebsc-1-s1.bnbchain.org:8545`]}},blockExplorers:{default:{name:`BscScan`,url:`https://testnet.bscscan.com`,apiUrl:`https://api-testnet.bscscan.com/api`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:17422483}},testnet:!0}),Zb=L({id:223,name:`B2`,nativeCurrency:{name:`Bitcoin`,symbol:`BTC`,decimals:18},rpcUrls:{default:{http:[`https://rpc.bsquared.network`]}},blockExplorers:{default:{name:`blockscout`,url:`https://explorer.bsquared.network`}}}),Qb=L({id:1123,name:`B2 Testnet`,nativeCurrency:{name:`Bitcoin`,symbol:`BTC`,decimals:18},rpcUrls:{default:{http:[`https://testnet-rpc.bsquared.network`]}},blockExplorers:{default:{name:`blockscout`,url:`https://testnet-explorer.bsquared.network`}},testnet:!0}),$b=L({id:200901,name:`Bitlayer`,nativeCurrency:{name:`Bitcoin`,symbol:`BTC`,decimals:18},rpcUrls:{default:{http:[`https://rpc.bitlayer.org`,`https://rpc.bitlayer-rpc.com`],webSocket:[`wss://ws.bitlayer.org`,`wss://ws.bitlayer-rpc.com`]}},blockExplorers:{default:{name:`Bitlayer(BTR) Scan`,url:`https://www.btrscan.com`}}}),ex=L({id:200810,name:`Bitlayer Testnet`,nativeCurrency:{name:`Bitcoin`,symbol:`BTC`,decimals:18},rpcUrls:{default:{http:[`https://testnet-rpc.bitlayer.org`],webSocket:[`wss://testnet-ws.bitlayer.org`,`wss://testnet-ws.bitlayer-rpc.com`]}},blockExplorers:{default:{name:`Bitlayer(BTR) Scan`,url:`https://testnet.btrscan.com`}},testnet:!0}),tx=L({id:4999,name:`BlackFort Exchange Network`,nativeCurrency:{name:`BlackFort Token`,symbol:`BXN`,decimals:18},rpcUrls:{default:{http:[`https://mainnet.blackfort.network/rpc`]}},blockExplorers:{default:{name:`Blockscout`,url:`https://explorer.blackfort.network`,apiUrl:`https://explorer.blackfort.network/api`}}}),nx=L({id:4777,name:`BlackFort Exchange Network Testnet`,nativeCurrency:{name:`BlackFort Testnet Token`,symbol:`TBXN`,decimals:18},rpcUrls:{default:{http:[`https://testnet.blackfort.network/rpc`]}},blockExplorers:{default:{name:`Blockscout`,url:`https://testnet-explorer.blackfort.network`,apiUrl:`https://testnet-explorer.blackfort.network/api`}},testnet:!0}),rx=L({id:13370,name:`Cannon`,nativeCurrency:{decimals:18,name:`Ether`,symbol:`ETH`},rpcUrls:{default:{http:[`http://127.0.0.1:8545`]}}}),ix=L({id:7700,name:`Canto`,nativeCurrency:{decimals:18,name:`Canto`,symbol:`CANTO`},rpcUrls:{default:{http:[`https://canto.gravitychain.io`]}},blockExplorers:{default:{name:`Tuber.Build (Blockscout)`,url:`https://tuber.build`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:2905789}}}),ax={estimateFeesPerGas:async e=>{if(!e.request?.feeCurrency)return null;let[t,n]=await Promise.all([ox(e.client,e.request.feeCurrency),sx(e.client,e.request.feeCurrency)]);return{maxFeePerGas:e.multiply(t-n)+n,maxPriorityFeePerGas:n}}};async function ox(e,t){let n=await e.request({method:`eth_gasPrice`,params:[t]});return BigInt(n)}async function sx(e,t){let n=await e.request({method:`eth_maxPriorityFeePerGas`,params:[t]});return BigInt(n)}Sn();function cx(e){return e===0||e===0n||e==null||e===`0`||e===``||typeof e==`string`&&(xn(e).toLowerCase()===`0x`||xn(e).toLowerCase()===`0x00`)}function lx(e){return!cx(e)}function ux(e){return e.maxFeePerGas!==void 0&&e.maxPriorityFeePerGas!==void 0}function dx(e){return e.type===`cip64`?!0:ux(e)&&lx(e.feeCurrency)}Dn(),Wu();const fx={block:ld({format(e){return{transactions:e.transactions?.map(e=>typeof e==`string`?e:{...ad(e),...e.gatewayFee?{gatewayFee:wn(e.gatewayFee),gatewayFeeRecipient:e.gatewayFeeRecipient}:{},feeCurrency:e.feeCurrency})}}}),transaction:od({format(e){if(e.type===`0x7e`)return{isSystemTx:e.isSystemTx,mint:e.mint?wn(e.mint):void 0,sourceHash:e.sourceHash,type:`deposit`};let t={feeCurrency:e.feeCurrency};return e.type===`0x7b`?t.type=`cip64`:(e.type===`0x7c`&&(t.type=`cip42`),t.gatewayFee=e.gatewayFee?wn(e.gatewayFee):null,t.gatewayFeeRecipient=e.gatewayFeeRecipient),t}}),transactionRequest:Uu({format(e){let t={};return e.feeCurrency&&(t.feeCurrency=e.feeCurrency),dx(e)&&(t.type=`0x7b`),t}})};Zu(),pi(),O(),Op(),Mu(),Ci(),Di(),A();function px(e,t){return dx(e)?hx(e,t):by(e,t)}const mx={transaction:px};function hx(e,t){_x(e);let{chainId:n,gas:r,nonce:i,to:a,value:o,maxFeePerGas:s,maxPriorityFeePerGas:c,accessList:l,feeCurrency:u,data:d}=e,f=[On(n),i?On(i):`0x`,c?On(c):`0x`,s?On(s):`0x`,r?On(r):`0x`,a??`0x`,o?On(o):`0x`,d??`0x`,oh(l),u,...ph(e,t)];return Ei([`0x7b`,M(f)])}var gx=Xu;function _x(e){let{chainId:t,maxPriorityFeePerGas:n,gasPrice:r,maxFeePerGas:i,to:a,feeCurrency:o}=e;if(t<=0)throw new Dp({chainId:t});if(a&&!bi(a))throw new fi({address:a});if(r)throw new D(\"`gasPrice` is not a valid CIP-64 Transaction attribute.\");if(lx(i)&&i>gx)throw new xu({maxFeePerGas:i});if(lx(n)&&lx(i)&&n>i)throw new Au({maxFeePerGas:i,maxPriorityFeePerGas:n});if(lx(o)&&!bi(o))throw new D(\"`feeCurrency` MUST be a token address for CIP-64 transactions.\");if(cx(o))throw new D(\"`feeCurrency` must be provided for CIP-64 transactions.\")}const vx={blockTime:1e3,contracts:vy,formatters:fx,serializers:mx,fees:ax},yx=L({...vx,id:42220,name:`Celo`,nativeCurrency:{decimals:18,name:`CELO`,symbol:`CELO`},rpcUrls:{default:{http:[`https://forno.celo.org`]}},blockExplorers:{default:{name:`Celo Explorer`,url:`https://celoscan.io`,apiUrl:`https://api.celoscan.io/api`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:13112599}},testnet:!1});var bx=17e3;const xx=L({...vx,id:44787,name:`Alfajores`,nativeCurrency:{decimals:18,name:`CELO`,symbol:`A-CELO`},rpcUrls:{default:{http:[`https://alfajores-forno.celo-testnet.org`]}},blockExplorers:{default:{name:`Celo Alfajores Explorer`,url:`https://celo-alfajores.blockscout.com`,apiUrl:`https://celo-alfajores.blockscout.com/api`}},contracts:{...vx.contracts,multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:14569001},portal:{[bx]:{address:`0x82527353927d8D069b3B452904c942dA149BA381`,blockCreated:2411324}},disputeGameFactory:{[bx]:{address:`0xE28AAdcd9883746c0e5068F58f9ea06027b214cb`,blockCreated:2411324}},l2OutputOracle:{[bx]:{address:`0x4a2635e9e4f6e45817b1D402ac4904c1d1752438`,blockCreated:2411324}},l1StandardBridge:{[bx]:{address:`0xD1B0E0581973c9eB7f886967A606b9441A897037`,blockCreated:2411324}}},testnet:!0});var Sx=11155111;const Cx=L({...vx,id:11142220,name:`Celo Sepolia Testnet`,nativeCurrency:{decimals:18,name:`CELO`,symbol:`S-CELO`},rpcUrls:{default:{http:[`https://forno.celo-sepolia.celo-testnet.org`]}},blockExplorers:{default:{name:`Celo Sepolia Explorer`,url:`https://celo-sepolia.blockscout.com/`,apiUrl:`https://celo-sepolia.blockscout.com/api`}},contracts:{...vx.contracts,multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:1},portal:{[Sx]:{address:`0x44ae3d41a335a7d05eb533029917aad35662dcc2`,blockCreated:8825790}},disputeGameFactory:{[Sx]:{address:`0x57c45d82d1a995f1e135b8d7edc0a6bb5211cfaa`,blockCreated:8825790}},l1StandardBridge:{[Sx]:{address:`0xec18a3c30131a0db4246e785355fbc16e2eaf408`,blockCreated:8825790}}},testnet:!0}),wx=L({id:5858,name:`Chang Chain Foundation Mainnet`,nativeCurrency:{decimals:18,name:`CTH`,symbol:`CTH`},rpcUrls:{default:{http:[`https://rpc.cthscan.com`]}},blockExplorers:{default:{name:`Chang Chain explorer`,url:`https://cthscan.com`}}}),Tx=L({id:88888,name:`Chiliz Chain`,network:`chiliz-chain`,nativeCurrency:{decimals:18,name:`CHZ`,symbol:`CHZ`},rpcUrls:{default:{http:[`https://rpc.chiliz.com`]}},blockExplorers:{default:{name:`Chiliz Explorer`,url:`https://scan.chiliz.com`,apiUrl:`https://scan.chiliz.com/api`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:8080847}}}),Ex=L({id:2882,name:`Chips Network`,network:`CHIPS`,nativeCurrency:{decimals:18,name:`IOTA`,symbol:`IOTA`},rpcUrls:{default:{http:[`https://node.chips.ooo/wasp/api/v1/chains/iota1pp3d3mnap3ufmgqnjsnw344sqmf5svjh26y2khnmc89sv6788y3r207a8fn/evm`]}}}),Dx=L({id:5115,name:`Citrea Testnet`,nativeCurrency:{name:`cBTC`,symbol:`cBTC`,decimals:18},rpcUrls:{default:{http:[`https://rpc.testnet.citrea.xyz`]}},blockExplorers:{default:{name:`Citrea Explorer`,url:`https://explorer.testnet.citrea.xyz`,apiUrl:`https://explorer.testnet.citrea.xyz/api`}},testnet:!0}),Ox=L({id:61,name:`Ethereum Classic`,nativeCurrency:{decimals:18,name:`ETC`,symbol:`ETC`},rpcUrls:{default:{http:[`https://etc.rivet.link`]}},blockExplorers:{default:{name:`Blockscout`,url:`https://blockscout.com/etc/mainnet`}}}),kx=L({id:112,name:`Coinbit Mainnet`,nativeCurrency:{name:`GIDR`,symbol:`GIDR`,decimals:18},rpcUrls:{default:{http:[`https://coinbit-rpc-mainnet.chain.sbcrypto.app`]}},blockExplorers:{default:{name:`Coinbit Explorer`,url:`https://coinbit-explorer.chain.sbcrypto.app`}},testnet:!1}),Ax=L({id:52,name:`CoinEx Mainnet`,nativeCurrency:{name:`cet`,symbol:`cet`,decimals:18},rpcUrls:{default:{http:[`https://rpc.coinex.net`]}},blockExplorers:{default:{name:`CoinEx Explorer`,url:`https://www.coinex.net`}},testnet:!1}),jx=L({id:1030,name:`Conflux eSpace`,nativeCurrency:{name:`Conflux`,symbol:`CFX`,decimals:18},rpcUrls:{default:{http:[`https://evm.confluxrpc.com`],webSocket:[`wss://evm.confluxrpc.com/ws`]}},blockExplorers:{default:{name:`ConfluxScan`,url:`https://evm.confluxscan.org`}},contracts:{multicall3:{address:`0xEFf0078910f638cd81996cc117bccD3eDf2B072F`,blockCreated:68602935}}}),Mx=L({id:71,name:`Conflux eSpace Testnet`,network:`cfx-espace-testnet`,testnet:!0,nativeCurrency:{name:`Conflux`,symbol:`CFX`,decimals:18},rpcUrls:{default:{http:[`https://evmtestnet.confluxrpc.com`],webSocket:[`wss://evmtestnet.confluxrpc.com/ws`]}},blockExplorers:{default:{name:`ConfluxScan`,url:`https://evmtestnet.confluxscan.org`}},contracts:{multicall3:{address:`0xEFf0078910f638cd81996cc117bccD3eDf2B072F`,blockCreated:117499050}}}),Nx=L({id:1116,name:`Core Dao`,nativeCurrency:{decimals:18,name:`Core`,symbol:`CORE`},rpcUrls:{default:{http:[`https://rpc.coredao.org`]}},blockExplorers:{default:{name:`CoreDao`,url:`https://scan.coredao.org`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:11907934}},testnet:!1}),Px=L({id:1115,name:`Core Testnet`,nativeCurrency:{decimals:18,name:`tCore`,symbol:`TCORE`},rpcUrls:{default:{http:[`https://rpc.test.btcs.network`]}},blockExplorers:{default:{name:`Core Testnet`,url:`https://scan.test.btcs.network`,apiUrl:`https://api.test.btcs.network/api`}},contracts:{multicall3:{address:`0xCcddF20A1932537123C2E48Bd8e00b108B8f7569`,blockCreated:29350509}},testnet:!0}),Fx=L({id:1114,name:`Core Testnet2`,nativeCurrency:{decimals:18,name:`tCore2`,symbol:`TCORE2`},rpcUrls:{default:{http:[`https://rpc.test2.btcs.network`]}},blockExplorers:{default:{name:`Core Testnet2`,url:`https://scan.test2.btcs.network`,apiUrl:`https://api.test2.btcs.network/api`}},contracts:{multicall3:{address:`0x3CB285ff3Cd5C7C7e570b1E7DE3De17A0f985e56`,blockCreated:3838600}},testnet:!0}),Ix=L({id:21e6,name:`Corn`,nativeCurrency:{decimals:18,name:`Bitcorn`,symbol:`BTCN`},rpcUrls:{default:{http:[`https://21000000.rpc.thirdweb.com`]}},blockExplorers:{default:{name:`Corn Explorer`,url:`https://cornscan.io`,apiUrl:`https://api.routescan.io/v2/network/mainnet/evm/21000000/etherscan/api`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:3228}},sourceId:1}),Lx=L({id:21000001,name:`Corn Testnet`,nativeCurrency:{decimals:18,name:`Bitcorn`,symbol:`BTCN`},rpcUrls:{default:{http:[`https://21000001.rpc.thirdweb.com`]}},blockExplorers:{default:{name:`Corn Testnet Explorer`,url:`https://testnet.cornscan.io`,apiUrl:`https://api.routescan.io/v2/network/testnet/evm/21000001/etherscan/api`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:4886}},testnet:!0,sourceId:11155111}),Rx=L({id:44,name:`Crab Network`,nativeCurrency:{decimals:18,name:`Crab Network Native Token`,symbol:`CRAB`},rpcUrls:{default:{http:[`https://crab-rpc.darwinia.network`],webSocket:[`wss://crab-rpc.darwinia.network`]}},blockExplorers:{default:{name:`Blockscout`,url:`https://crab-scan.darwinia.network`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:3032593}}}),zx=L({id:66665,name:`Creator`,nativeCurrency:{decimals:18,name:`Ether`,symbol:`ETH`},rpcUrls:{default:{http:[`https://rpc.creatorchain.io`]}},blockExplorers:{default:{name:`Explorer`,url:`https://explorer.creatorchain.io`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`}},testnet:!0}),Bx=L({id:102032,name:`Creditcoin Devnet`,nativeCurrency:{name:`Devnet CTC`,symbol:`devCTC`,decimals:18},rpcUrls:{default:{http:[`https://rpc.cc3-devnet.creditcoin.network`],webSocket:[`wss://rpc.cc3-devnet.creditcoin.network/ws`]}},blockExplorers:{default:{name:`Blockscout`,url:`https://creditcoin-devnet.blockscout.com`,apiUrl:`https://creditcoin3-dev.subscan.io`}},testnet:!0}),Vx=L({id:102030,name:`Creditcoin`,nativeCurrency:{name:`Creditcoin`,symbol:`CTC`,decimals:18},rpcUrls:{default:{http:[`https://mainnet3.creditcoin.network`],webSocket:[`wss://mainnet3.creditcoin.network`]}},blockExplorers:{default:{name:`Blockscout`,url:`https://creditcoin.blockscout.com`,apiUrl:`https://creditcoin.blockscout.com/api`}},testnet:!1}),Hx=L({id:102031,name:`Creditcoin Testnet`,nativeCurrency:{name:`Creditcoin Testnet`,symbol:`tCTC`,decimals:18},rpcUrls:{default:{http:[`https://rpc.cc3-testnet.creditcoin.network`],webSocket:[`wss://rpc.cc3-testnet.creditcoin.network`]}},blockExplorers:{default:{name:`Blockscout`,url:`https://creditcoin-testnet.blockscout.com`,apiUrl:`https://creditcoin-testnet.blockscout.com/api`}},testnet:!0}),Ux=L({id:25,name:`Cronos Mainnet`,nativeCurrency:{decimals:18,name:`Cronos`,symbol:`CRO`},rpcUrls:{default:{http:[`https://evm.cronos.org`]}},blockExplorers:{default:{name:`Cronos Explorer`,url:`https://explorer.cronos.org`,apiUrl:`https://explorer-api.cronos.org/mainnet/api`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:1963112}}}),Wx=L({id:338,name:`Cronos Testnet`,nativeCurrency:{decimals:18,name:`CRO`,symbol:`tCRO`},rpcUrls:{default:{http:[`https://evm-t3.cronos.org`]}},blockExplorers:{default:{name:`Cronos Explorer (Testnet)`,url:`https://explorer.cronos.org/testnet`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:10191251}},testnet:!0}),Gx=L({id:388,name:`Cronos zkEVM Mainnet`,nativeCurrency:{decimals:18,name:`Cronos zkEVM CRO`,symbol:`zkCRO`},rpcUrls:{default:{http:[`https://mainnet.zkevm.cronos.org`]}},blockExplorers:{default:{name:`Cronos zkEVM (Mainnet) Chain Explorer`,url:`https://explorer.zkevm.cronos.org`}},contracts:{multicall3:{address:`0x06f4487d7c4a5983d2660db965cc6d2565e4cfaa`,blockCreated:72}}}),Kx=L({id:282,name:`Cronos zkEVM Testnet`,nativeCurrency:{decimals:18,name:`Cronos zkEVM Test Coin`,symbol:`zkTCRO`},rpcUrls:{default:{http:[`https://testnet.zkevm.cronos.org`]}},blockExplorers:{default:{name:`Cronos zkEVM Testnet Explorer`,url:`https://explorer.zkevm.cronos.org/testnet`}},testnet:!0}),qx=L({id:3737,name:`Crossbell`,nativeCurrency:{decimals:18,name:`CSB`,symbol:`CSB`},rpcUrls:{default:{http:[`https://rpc.crossbell.io`]}},blockExplorers:{default:{name:`CrossScan`,url:`https://scan.crossbell.io`,apiUrl:`https://scan.crossbell.io/api`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:38246031}}}),Jx=L({id:4158,name:`CrossFi Mainnet`,nativeCurrency:{decimals:18,name:`CrossFi`,symbol:`XFI`},rpcUrls:{default:{http:[`https://rpc.mainnet.ms`]}},blockExplorers:{default:{name:`CrossFi Blockchain Explorer`,url:`https://xfiscan.com`}},testnet:!1}),Yx=L({id:33111,name:`Curtis`,nativeCurrency:{name:`ApeCoin`,symbol:`APE`,decimals:18},rpcUrls:{default:{http:[`https://rpc.curtis.apechain.com`]}},blockExplorers:{default:{name:`Curtis Explorer`,url:`https://explorer.curtis.apechain.com`}},testnet:!0}),Xx=L({id:7560,name:`Cyber`,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://cyber.alt.technology`]}},blockExplorers:{default:{name:`Blockscout`,url:`https://cyberscan.co`,apiUrl:`https://cyberscan.co/api`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:0}}}),Zx=L({id:111557560,name:`Cyber Testnet`,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://cyber-testnet.alt.technology`]}},blockExplorers:{default:{name:`Blockscout`,url:`https://testnet.cyberscan.co`,apiUrl:`https://testnet.cyberscan.co/api`}},contracts:{multicall3:{address:`0xffc391F0018269d4758AEA1a144772E8FB99545E`,blockCreated:304545}},testnet:!0}),Qx=L({id:824,name:`Daily Network Mainnet`,nativeCurrency:{decimals:18,name:`Daily`,symbol:`DLY`},rpcUrls:{default:{http:[`https://rpc.mainnet.dailycrypto.net`]}},blockExplorers:{default:{name:`Daily Mainnet Explorer`,url:`https://explorer.mainnet.dailycrypto.net`}},testnet:!1}),$x=L({id:825,name:`Daily Network Testnet`,nativeCurrency:{decimals:18,name:`Daily`,symbol:`DLY`},rpcUrls:{default:{http:[`https://rpc.testnet.dailycrypto.net`]}},blockExplorers:{default:{name:`Daily Testnet Explorer`,url:`https://explorer.testnet.dailycrypto.net`}},testnet:!0}),eS=L({id:46,name:`Darwinia Network`,nativeCurrency:{decimals:18,name:`RING`,symbol:`RING`},rpcUrls:{default:{http:[`https://rpc.darwinia.network`],webSocket:[`wss://rpc.darwinia.network`]}},blockExplorers:{default:{name:`Explorer`,url:`https://explorer.darwinia.network`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:69420}}}),tS=L({id:20240603,name:`DBK chain`,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://rpc.mainnet.dbkchain.io`]}},blockExplorers:{default:{name:`DBK Chain Explorer`,url:`https://scan.dbkchain.io`}},testnet:!1}),nS=L({...R,id:0x9a697f88076c8,name:`Dchain`,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://dchain-2716446429837000-1.jsonrpc.sagarpc.io`]}},blockExplorers:{default:{name:`Dchain Explorer`,url:`https://dchain-2716446429837000-1.sagaexplorer.io`,apiUrl:`https://api-dchain-2716446429837000-1.sagaexplorer.io/api`}},contracts:{...R.contracts}}),rS=L({...R,id:0x9a379ba03cf10,name:`Dchain Testnet`,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://dchaintestnet-2713017997578000-1.jsonrpc.testnet.sagarpc.io`]}},blockExplorers:{default:{name:`Dchain Explorer`,url:`https://dchaintestnet-2713017997578000-1.testnet.sagaexplorer.io`,apiUrl:`https://api-dchaintestnet-2713017997578000-1.testnet.sagaexplorer.io/api`}},contracts:{...R.contracts}}),iS=L({id:1130,network:`defichain-evm`,name:`DeFiChain EVM Mainnet`,nativeCurrency:{name:`DeFiChain`,symbol:`DFI`,decimals:18},rpcUrls:{default:{http:[`https://eth.mainnet.ocean.jellyfishsdk.com`]}},blockExplorers:{default:{name:`DeFiScan`,url:`https://meta.defiscan.live`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:137852}}}),aS=L({id:1131,network:`defichain-evm-testnet`,name:`DeFiChain EVM Testnet`,nativeCurrency:{name:`DeFiChain`,symbol:`DFI`,decimals:18},rpcUrls:{default:{http:[`https://eth.testnet.ocean.jellyfishsdk.com`]}},blockExplorers:{default:{name:`DeFiScan`,url:`https://meta.defiscan.live/?network=TestNet`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:156462}},testnet:!0}),oS=L({id:666666666,name:`Degen`,nativeCurrency:{decimals:18,name:`Degen`,symbol:`DEGEN`},rpcUrls:{default:{http:[`https://rpc.degen.tips`],webSocket:[`wss://rpc.degen.tips`]}},blockExplorers:{default:{name:`Degen Chain Explorer`,url:`https://explorer.degen.tips`,apiUrl:`https://explorer.degen.tips/api/v2`}}}),sS=L({id:53935,name:`DFK Chain`,nativeCurrency:{decimals:18,name:`Jewel`,symbol:`JEWEL`},rpcUrls:{default:{http:[`https://subnets.avax.network/defi-kingdoms/dfk-chain/rpc`]}},blockExplorers:{default:{name:`DFKSubnetScan`,url:`https://subnets.avax.network/defi-kingdoms`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:14790551}}}),cS=L({id:15,name:`Diode Prenet`,nativeCurrency:{decimals:18,name:`DIODE`,symbol:`DIODE`},rpcUrls:{default:{http:[`https://prenet.diode.io:8443`],webSocket:[`wss://prenet.diode.io:8443/ws`]}},blockExplorers:{default:{name:`Diode Explorer`,url:`https://diode.io/prenet`}},testnet:!1}),lS=L({id:513100,name:`DisChain`,nativeCurrency:{decimals:18,name:`DIS`,symbol:`DIS`},rpcUrls:{default:{http:[`https://rpc.dischain.xyz`]}},blockExplorers:{default:{name:`DisChain Explorer`,url:`https://www.oklink.com/dis`}}}),uS=L({id:53457,name:`DODOchain Testnet`,nativeCurrency:{decimals:18,name:`DODO`,symbol:`DODO`},rpcUrls:{default:{http:[`https://dodochain-testnet.alt.technology`],webSocket:[`wss://dodochain-testnet.alt.technology/ws`]}},blockExplorers:{default:{name:`DODOchain Testnet (Sepolia) Explorer`,url:`https://testnet-scan.dodochain.com`}},testnet:!0}),dS=L({id:2e3,name:`Dogechain`,nativeCurrency:{decimals:18,name:`Wrapped Dogecoin`,symbol:`WDOGE`},rpcUrls:{default:{http:[`https://rpc.dogechain.dog`]}},blockExplorers:{default:{name:`DogeChainExplorer`,url:`https://explorer.dogechain.dog`,apiUrl:`https://explorer.dogechain.dog/api`}},contracts:{multicall3:{address:`0x68a8609a60a008EFA633dfdec592c03B030cC508`,blockCreated:25384031}}}),fS=L({id:97476,name:`Doma Testnet`,nativeCurrency:{decimals:18,name:`Ether`,symbol:`ETH`},rpcUrls:{default:{http:[`https://rpc-testnet.doma.xyz`]}},blockExplorers:{default:{name:`Doma Testnet Explorer`,url:`https://explorer-testnet.doma.xyz`}},testnet:!0}),pS=L({id:42026,name:`Donatuz`,nativeCurrency:{decimals:18,name:`Ether`,symbol:`ETH`},rpcUrls:{default:{http:[`https://rpc.donatuz.com`]}},blockExplorers:{default:{name:`Donatuz Explorer`,url:`https://explorer.donatuz.com`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:0}}}),mS=L({id:7979,name:`DOS Chain`,nativeCurrency:{decimals:18,name:`DOS Chain`,symbol:`DOS`},rpcUrls:{default:{http:[`https://main.doschain.com`]}},blockExplorers:{default:{name:`DOS Chain Explorer`,url:`https://doscan.io`,apiUrl:`https://api.doscan.io`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:161908}}}),hS=L({id:3939,name:`DOS Chain Testnet`,nativeCurrency:{decimals:18,name:`DOS Chain Testnet`,symbol:`DOS`},rpcUrls:{default:{http:[`https://test.doschain.com`]}},blockExplorers:{default:{name:`DOS Chain Testnet Explorer`,url:`https://test.doscan.io`,apiUrl:`https://api-test.doscan.io`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:69623}},testnet:!0}),gS=L({id:23451,name:`DreyerX Mainnet`,nativeCurrency:{name:`DreyerX`,symbol:`DRX`,decimals:18},rpcUrls:{default:{http:[`https://rpc.dreyerx.com`]}},blockExplorers:{default:{name:`DreyerX Scan`,url:`https://scan.dreyerx.com`}}}),_S=L({id:23452,name:`DreyerX Testnet`,nativeCurrency:{name:`DreyerX`,symbol:`DRX`,decimals:18},rpcUrls:{default:{http:[`http://testnet-rpc.dreyerx.com`]}},blockExplorers:{default:{name:`DreyerX Testnet Scan`,url:`https://testnet-scan.dreyerx.com`}},testnet:!0}),vS=L({id:555888,name:`DustBoy IoT`,nativeCurrency:{name:`Ether`,symbol:`DST`,decimals:18},rpcUrls:{default:{http:[`https://dustboy-rpc.jibl2.com`]}},blockExplorers:{default:{name:`Blockscout`,url:`https://dustboy.jibl2.com`,apiUrl:`https://dustboy.jibl2.com/api`}},contracts:{multicall3:{address:`0xFFD34aa2C62B2D52E00A361e466C229788f4eD6a`,blockCreated:526569}},testnet:!1}),yS=L({id:1100,name:`Dymension`,nativeCurrency:{name:`DYM`,symbol:`DYM`,decimals:18},rpcUrls:{default:{http:[`https://dymension-evm-rpc.publicnode.com`],webSocket:[`wss://dymension-evm-rpc.publicnode.com`]}},blockExplorers:{default:{name:`Dym FYI`,url:`https://dym.fyi`}},testnet:!1}),bS=L({id:5424,name:`edeXa`,nativeCurrency:{name:`edeXa`,symbol:`EDX`,decimals:18},rpcUrls:{default:{http:[`https://rpc.edexa.network`]}},blockExplorers:{default:{name:`edeXa Explorer`,url:`https://explorer.edexa.network`,apiUrl:`https://explorer.edexa.network/api/v2`}}}),xS=L({id:1995,name:`edeXa Testnet`,nativeCurrency:{name:`edeXa`,symbol:`tEDX`,decimals:18},rpcUrls:{default:{http:[`https://rpc.testnet.edexa.network`]}},blockExplorers:{default:{name:`edeXa Testnet Explorer`,url:`https://explorer.testnet.edexa.network`,apiUrl:`https://explorer.testnet.edexa.network/api/v2`}},testnet:!0}),SS=L({id:2026,name:`Edgeless Network`,nativeCurrency:{name:`Edgeless Wrapped ETH`,symbol:`EwETH`,decimals:18},rpcUrls:{default:{http:[`https://rpc.edgeless.network/http`],webSocket:[`wss://rpc.edgeless.network/ws`]}},blockExplorers:{default:{name:`Edgeless Explorer`,url:`https://explorer.edgeless.network`}}}),CS=L({id:202,name:`Edgeless Testnet`,nativeCurrency:{name:`Edgeless Wrapped ETH`,symbol:`EwETH`,decimals:18},rpcUrls:{default:{http:[`https://edgeless-testnet.rpc.caldera.xyz/http`],webSocket:[`wss://edgeless-testnet.rpc.caldera.xyz/ws`]}},blockExplorers:{default:{name:`Edgeless Testnet Explorer`,url:`https://testnet.explorer.edgeless.network`}}}),wS=L({id:2021,name:`Edgeware EdgeEVM Mainnet`,nativeCurrency:{decimals:18,name:`Edgeware`,symbol:`EDG`},rpcUrls:{default:{http:[`https://edgeware-evm.jelliedowl.net`]}},blockExplorers:{default:{name:`Edgscan by Bharathcoorg`,url:`https://edgscan.live`,apiUrl:`https://edgscan.live/api`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:18117872}}}),TS=L({id:2022,name:`Beresheet BereEVM Testnet`,nativeCurrency:{decimals:18,name:`Testnet EDG`,symbol:`tEDG`},rpcUrls:{default:{http:[`https://beresheet-evm.jelliedowl.net`]}},blockExplorers:{default:{name:`Edgscan by Bharathcoorg`,url:`https://testnet.edgscan.live`,apiUrl:`https://testnet.edgscan.live/api`}}}),ES=L({id:41923,name:`EDU Chain`,nativeCurrency:{decimals:18,name:`EDU`,symbol:`EDU`},rpcUrls:{default:{http:[`https://rpc.edu-chain.raas.gelato.cloud`]}},blockExplorers:{default:{name:`EDU Chain Explorer`,url:`https://educhain.blockscout.com/`}},testnet:!1}),DS=L({id:656476,name:`EDU Chain Testnet`,nativeCurrency:{decimals:18,name:`EDU`,symbol:`EDU`},rpcUrls:{default:{http:[`https://rpc.open-campus-codex.gelato.digital/`],webSocket:[`wss://ws.open-campus-codex.gelato.digital`]}},blockExplorers:{default:{name:`EDU Chain Testnet Explorer`,url:`https://opencampus-codex.blockscout.com`,apiUrl:`https://opencampus-codex.blockscout.com/api`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:15514133}},testnet:!0}),OS=L({id:1994,name:`Ekta`,nativeCurrency:{decimals:18,name:`EKTA`,symbol:`EKTA`},rpcUrls:{default:{http:[`https://main.ekta.io`]}},blockExplorers:{default:{name:`Ektascan`,url:`https://ektascan.io`,apiUrl:`https://ektascan.io/api`}}}),kS=L({id:1004,name:`Ekta Testnet`,nativeCurrency:{decimals:18,name:`EKTA`,symbol:`EKTA`},rpcUrls:{default:{http:[`https://test.ekta.io:8545`]}},blockExplorers:{default:{name:`Test Ektascan`,url:`https://test.ektascan.io`,apiUrl:`https://test.ektascan.io/api`}},testnet:!0}),AS=L({id:20,name:`Elastos Smart Chain`,nativeCurrency:{name:`ELA`,symbol:`ELA`,decimals:18},rpcUrls:{default:{http:[`https://api2.elastos.io/eth`]}},blockExplorers:{default:{name:`Elastos Explorer`,url:`https://esc.elastos.io`}},testnet:!1}),jS=L({id:21,name:`Elastos Smart Chain Testnet`,nativeCurrency:{name:`tELA`,symbol:`tELA`,decimals:18},rpcUrls:{default:{http:[`https://api-testnet.elastos.io/eth`]}},blockExplorers:{default:{name:`Elastos Explorer`,url:`https://esc-testnet.elastos.io`}},testnet:!0}),MS=L({id:52014,name:`Electroneum Mainnet`,nativeCurrency:{name:`ETN`,symbol:`ETN`,decimals:18},rpcUrls:{default:{http:[`https://rpc.electroneum.com`]}},blockExplorers:{default:{name:`Electroneum Block Explorer`,url:`https://blockexplorer.electroneum.com`}},testnet:!1}),NS=L({id:5201420,name:`Electroneum Testnet`,nativeCurrency:{name:`ETN`,symbol:`ETN`,decimals:18},rpcUrls:{default:{http:[`https://testnet-rpc.electroneum.com`]}},blockExplorers:{default:{name:`Electroneum Block Explorer`,url:`https://blockexplorer.thesecurityteam.rocks`}},testnet:!0}),PS=L({...R,id:1338,name:`Elysium Testnet`,nativeCurrency:{decimals:18,name:`LAVA`,symbol:`LAVA`},rpcUrls:{default:{http:[`https://elysium-test-rpc.vulcanforged.com`]}},blockExplorers:{default:{name:`Elysium testnet explorer`,url:`https://elysium-explorer.vulcanforged.com`}},testnet:!0}),FS=L({id:246,name:`Energy Mainnet`,nativeCurrency:{name:`EWT`,symbol:`EWT`,decimals:18},rpcUrls:{default:{http:[`https://rpc.energyweb.org`]}},blockExplorers:{default:{name:`EnergyWeb Explorer`,url:`https://explorer.energyweb.org`}},testnet:!1}),IS=L({id:173,name:`ENI Mainnet`,nativeCurrency:{decimals:18,name:`ENI`,symbol:`ENI`},rpcUrls:{default:{http:[`https://rpc.eniac.network`]}},blockExplorers:{default:{name:`ENI Explorer`,url:`https://scan.eniac.network`}},testnet:!1}),LS=L({id:6912115,name:`ENI Testnet`,nativeCurrency:{decimals:18,name:`ENI Testnet Token`,symbol:`ENI`},rpcUrls:{default:{http:[`https://rpc-testnet.eniac.network`]}},blockExplorers:{default:{name:`ENI Testnet Explorer`,url:`https://scan-testnet.eniac.network`}},testnet:!0}),RS=L({id:119,name:`ENULS Mainnet`,nativeCurrency:{decimals:18,name:`NULS`,symbol:`NULS`},rpcUrls:{default:{http:[`https://evmapi2.nuls.io`]}},blockExplorers:{default:{name:`ENULS Explorer`,url:`https://evmscan.nuls.io`}},testnet:!1}),zS=L({id:7332,name:`Horizen EON`,nativeCurrency:{decimals:18,name:`ZEN`,symbol:`ZEN`},rpcUrls:{default:{http:[`https://eon-rpc.horizenlabs.io/ethv1`]}},blockExplorers:{default:{name:`EON Explorer`,url:`https://eon-explorer.horizenlabs.io`}},contracts:{}}),BS=L({id:17777,name:`EOS EVM`,nativeCurrency:{decimals:18,name:`EOS`,symbol:`EOS`},rpcUrls:{default:{http:[`https://api.evm.eosnetwork.com`]}},blockExplorers:{default:{name:`EOS EVM Explorer`,url:`https://explorer.evm.eosnetwork.com`,apiUrl:`https://explorer.evm.eosnetwork.com/api`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:7943933}}}),VS=L({id:15557,name:`EOS EVM Testnet`,nativeCurrency:{decimals:18,name:`EOS`,symbol:`EOS`},rpcUrls:{default:{http:[`https://api.testnet.evm.eosnetwork.com`]}},blockExplorers:{default:{name:`EOS EVM Testnet Explorer`,url:`https://explorer.testnet.evm.eosnetwork.com`,apiUrl:`https://explorer.testnet.evm.eosnetwork.com/api`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:9067940}},testnet:!0}),HS=L({id:140,name:`Eteria`,nativeCurrency:{name:`Eteria`,symbol:`ERA`,decimals:18},rpcUrls:{default:{http:[`https://mainnet.eteria.io/v1`]}},blockExplorers:{default:{name:`Eteria Explorer`,url:`https://explorer.eteria.io`,apiUrl:`https://explorer.eteria.io/api`}}}),US=L({id:42793,name:`Etherlink`,blockTime:4830,nativeCurrency:{decimals:18,name:`Tez`,symbol:`XTZ`},rpcUrls:{default:{http:[`https://node.mainnet.etherlink.com`]}},blockExplorers:{default:{name:`Etherlink`,url:`https://explorer.etherlink.com`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:33899}}}),WS=L({id:128123,name:`Etherlink Testnet`,nativeCurrency:{decimals:18,name:`Tez`,symbol:`XTZ`},rpcUrls:{default:{http:[`https://node.ghostnet.etherlink.com`]}},blockExplorers:{default:{name:`Etherlink Testnet`,url:`https://testnet.explorer.etherlink.com`}},testnet:!0}),GS=L({id:183,name:`Ethernity`,nativeCurrency:{decimals:18,name:`Ether`,symbol:`ETH`},rpcUrls:{default:{http:[`https://mainnet.ethernitychain.io`]}},blockExplorers:{default:{name:`Ethernity Explorer`,url:`https://ernscan.io`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:0}},testnet:!1}),KS=L({id:20256789,name:`ETP Mainnet`,nativeCurrency:{decimals:18,name:`ETP Chain Native Token`,symbol:`ETP`},rpcUrls:{default:{http:[`https://rpc.etpscan.xyz`]}},blockExplorers:{default:{name:`ETP Scan`,url:`https://etpscan.xyz`}}}),qS=L({id:9001,name:`Evmos`,nativeCurrency:{decimals:18,name:`Evmos`,symbol:`EVMOS`},rpcUrls:{default:{http:[`https://eth.bd.evmos.org:8545`]}},blockExplorers:{default:{name:`Evmos Block Explorer`,url:`https://escan.live`}}}),JS=L({id:9e3,name:`Evmos Testnet`,nativeCurrency:{decimals:18,name:`Evmos`,symbol:`EVMOS`},rpcUrls:{default:{http:[`https://eth.bd.evmos.dev:8545`]}},blockExplorers:{default:{name:`Evmos Testnet Block Explorer`,url:`https://evm.evmos.dev/`}}}),YS=L({id:22052002,name:`Excelon Mainnet`,network:`XLON`,nativeCurrency:{decimals:18,name:`Excelon`,symbol:`xlon`},rpcUrls:{default:{http:[`https://edgewallet1.xlon.org`]}},blockExplorers:{default:{name:`Excelon explorer`,url:`https://explorer.excelon.io`}}}),XS=L({id:2,name:`Expanse Network`,nativeCurrency:{decimals:18,name:`EXP`,symbol:`EXP`},rpcUrls:{default:{http:[`https://node.expanse.tech`]}},blockExplorers:{default:{name:`Expanse Explorer`,url:`https://explorer.expanse.tech`}},testnet:!1}),ZS=L({id:7200,name:`exSat Network`,nativeCurrency:{decimals:18,name:`BTC`,symbol:`BTC`},rpcUrls:{default:{http:[`https://evm.exsat.network`]}},blockExplorers:{default:{name:`exSat Explorer`,url:`https://scan.exsat.network`,apiUrl:`https://scan.exsat.network/api`}}}),QS=L({id:839999,name:`exSat Testnet`,nativeCurrency:{decimals:18,name:`BTC`,symbol:`BTC`},rpcUrls:{default:{http:[`https://evm-tst3.exsat.network`]}},blockExplorers:{default:{name:`exSat Explorer`,url:`https://scan-testnet.exsat.network`,apiUrl:`https://scan-testnet.exsat.network/api`}}}),$S=L({id:250,name:`Fantom`,nativeCurrency:{decimals:18,name:`Fantom`,symbol:`FTM`},rpcUrls:{default:{http:[`https://250.rpc.thirdweb.com`]}},blockExplorers:{default:{name:`FTMScan`,url:`https://ftmscan.com`,apiUrl:`https://api.ftmscan.com/api`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:33001987}}}),eC=L({id:64240,name:`Fantom Sonic Open Testnet`,network:`fantom-sonic-testnet`,nativeCurrency:{decimals:18,name:`Fantom`,symbol:`FTM`},rpcUrls:{default:{http:[`https://rpcapi.sonic.fantom.network`]}},blockExplorers:{default:{name:`Fantom Sonic Open Testnet Explorer`,url:`https://public-sonic.fantom.network`}},testnet:!0}),tC=L({id:4002,name:`Fantom Testnet`,nativeCurrency:{decimals:18,name:`Fantom`,symbol:`FTM`},rpcUrls:{default:{http:[`https://rpc.testnet.fantom.network`]}},blockExplorers:{default:{name:`FTMScan`,url:`https://testnet.ftmscan.com`,apiUrl:`https://testnet.ftmscan.com/api`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:8328688}},testnet:!0}),nC=L({id:12306,name:`Fibo Chain`,nativeCurrency:{decimals:18,name:`fibo`,symbol:`FIBO`},rpcUrls:{default:{http:[`https://network.hzroc.art`]}},blockExplorers:{default:{name:`FiboScan`,url:`https://scan.fibochain.org`}}}),rC=L({id:314,name:`Filecoin Mainnet`,nativeCurrency:{decimals:18,name:`filecoin`,symbol:`FIL`},rpcUrls:{default:{http:[`https://api.node.glif.io/rpc/v1`]}},blockExplorers:{default:{name:`Filfox`,url:`https://filfox.info/en`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:3328594}}}),iC=L({id:314159,name:`Filecoin Calibration`,nativeCurrency:{decimals:18,name:`testnet filecoin`,symbol:`tFIL`},rpcUrls:{default:{http:[`https://api.calibration.node.glif.io/rpc/v1`]}},blockExplorers:{default:{name:`Filscan`,url:`https://calibration.filscan.io`}},testnet:!0}),aC=L({id:3141,name:`Filecoin Hyperspace`,nativeCurrency:{decimals:18,name:`testnet filecoin`,symbol:`tFIL`},rpcUrls:{default:{http:[`https://api.hyperspace.node.glif.io/rpc/v1`]}},blockExplorers:{default:{name:`Filfox`,url:`https://hyperspace.filfox.info/en`}},testnet:!0}),oC=L({id:253368190,name:`Flame`,network:`flame`,nativeCurrency:{symbol:`TIA`,name:`TIA`,decimals:18},rpcUrls:{default:{http:[`https://rpc.flame.astria.org`],webSocket:[`wss://ws.flame.astria.org`]}},blockExplorers:{default:{name:`Flame Explorer`,url:`https://explorer.flame.astria.org`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:6829148}}}),sC=L({id:14,name:`Flare Mainnet`,nativeCurrency:{decimals:18,name:`Flare`,symbol:`FLR`},rpcUrls:{default:{http:[`https://flare-api.flare.network/ext/C/rpc`]}},blockExplorers:{default:{name:`Flare Explorer`,url:`https://flare-explorer.flare.network`,apiUrl:`https://flare-explorer.flare.network/api`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:3002461}}}),cC=L({id:114,name:`Flare Testnet Coston2`,nativeCurrency:{decimals:18,name:`Coston2 Flare`,symbol:`C2FLR`},rpcUrls:{default:{http:[`https://coston2-api.flare.network/ext/C/rpc`]}},blockExplorers:{default:{name:`Coston2 Explorer`,url:`https://coston2-explorer.flare.network`,apiUrl:`https://coston2-explorer.flare.network/api`}},testnet:!0}),lC=L({id:747,name:`Flow EVM Mainnet`,nativeCurrency:{decimals:18,name:`Flow`,symbol:`FLOW`},rpcUrls:{default:{http:[`https://mainnet.evm.nodes.onflow.org`]}},blockExplorers:{default:{name:`Mainnet Explorer`,url:`https://evm.flowscan.io`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:6205}},blockTime:800}),uC=L({id:646,name:`Flow EVM Previewnet`,nativeCurrency:{decimals:18,name:`Flow`,symbol:`FLOW`},rpcUrls:{default:{http:[`https://previewnet.evm.nodes.onflow.org`]}},blockExplorers:{default:{name:`Previewnet Explorer`,url:`https://previewnet.flowdiver.io`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:6205}}}),dC=L({id:545,name:`Flow EVM Testnet`,nativeCurrency:{decimals:18,name:`Flow`,symbol:`FLOW`},rpcUrls:{default:{http:[`https://testnet.evm.nodes.onflow.org`]}},blockExplorers:{default:{name:`Flow Diver`,url:`https://evm-testnet.flowscan.io`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:137518}},testnet:!0,blockTime:800}),fC=L({id:9999999,name:`Fluence`,nativeCurrency:{name:`FLT`,symbol:`FLT`,decimals:18},rpcUrls:{default:{http:[`https://rpc.mainnet.fluence.dev`],webSocket:[`wss://ws.mainnet.fluence.dev`]}},blockExplorers:{default:{name:`Blockscout`,url:`https://blockscout.mainnet.fluence.dev`,apiUrl:`https://blockscout.mainnet.fluence.dev/api`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:207583}}}),pC=L({id:123420000220,name:`Fluence Stage`,nativeCurrency:{name:`tFLT`,symbol:`tFLT`,decimals:18},rpcUrls:{default:{http:[`https://rpc.stage.fluence.dev`],webSocket:[`wss://ws.stage.fluence.dev`]}},blockExplorers:{default:{name:`Blockscout`,url:`https://blockscout.stage.fluence.dev`,apiUrl:`https://blockscout.stage.fluence.dev/api`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:83227}},testnet:!0}),mC=L({id:52164803,name:`Fluence Testnet`,nativeCurrency:{name:`tFLT`,symbol:`tFLT`,decimals:18},rpcUrls:{default:{http:[`https://rpc.testnet.fluence.dev`],webSocket:[`wss://ws.testnet.fluence.dev`]}},blockExplorers:{default:{name:`Blockscout`,url:`https://blockscout.testnet.fluence.dev`,apiUrl:`https://blockscout.testnet.fluence.dev/api`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:96424}},testnet:!0}),hC=L({id:20993,name:`Fluent Testnet`,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://rpc.dev.gblend.xyz`]}},blockExplorers:{default:{name:`Fluent Explorer`,url:`https://blockscout.dev.gblend.xyz`}},testnet:!0});var gC=1;const _C=L({id:478,name:`Form Network`,nativeCurrency:{decimals:18,name:`Ethereum`,symbol:`ETH`},rpcUrls:{default:{http:[`https://rpc.form.network/http`],webSocket:[`wss://rpc.form.network/ws`]}},blockExplorers:{default:{name:`Form Explorer`,url:`https://explorer.form.network`}},contracts:{...R.contracts,addressManager:{[gC]:{address:`0x15c249E46A2F924C2dB3A1560CF86729bAD1f07B`}},l1CrossDomainMessenger:{[gC]:{address:`0xF333158DCCad1dF6C3F0a3aEe8BC31fA94d9eD5c`}},l2OutputOracle:{[gC]:{address:`0x4ccAAF69F41c5810cA875183648B577CaCf1F67E`}},portal:{[gC]:{address:`0x4E259Ee5F4136408908160dD32295A5031Fa426F`}},l1StandardBridge:{[gC]:{address:`0xdc20aA63D3DE59574E065957190D8f24e0F7B8Ba`}},multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`}},sourceId:gC}),vC=L({id:984122,name:`Forma`,network:`forma`,nativeCurrency:{symbol:`TIA`,name:`TIA`,decimals:18},rpcUrls:{default:{http:[`https://rpc.forma.art`],webSocket:[`wss://ws.forma.art`]}},blockExplorers:{default:{name:`Forma Explorer`,url:`https://explorer.forma.art`}},contracts:{multicall3:{address:`0xd53C6FFB123F7349A32980F87faeD8FfDc9ef079`,blockCreated:252705}}});var yC=11155111;const bC=L({id:132902,name:`Form Testnet`,nativeCurrency:{decimals:18,name:`Ethereum`,symbol:`ETH`},rpcUrls:{default:{http:[`https://sepolia-rpc.form.network/http`],webSocket:[`wss://sepolia-rpc.form.network/ws`]}},blockExplorers:{default:{name:`Form Testnet Explorer`,url:`https://sepolia-explorer.form.network`}},contracts:{...R.contracts,addressManager:{[yC]:{address:`0xd5C38fa934f7fd7477D4800F4f38a1c5BFdF1373`}},l1CrossDomainMessenger:{[yC]:{address:`0x37A68565c4BE9700b3E3Ec60cC4416cAC3052FAa`}},l2OutputOracle:{[yC]:{address:`0x9eA2239E65a59EC9C7F1ED4C116dD58Da71Fc1e2`}},portal:{[yC]:{address:`0x60377e3cE15dF4CCA24c4beF076b60314240b032`}},l1StandardBridge:{[yC]:{address:`0xD4531f633942b2725896F47cD2aFd260b44Ab1F7`}},multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`}},testnet:!0,sourceId:yC}),xC=L({id:80931,name:`Forta Chain`,nativeCurrency:{symbol:`FORT`,name:`FORT`,decimals:18},rpcUrls:{default:{http:[`https://rpc-forta-chain-8gj1qndmfc.t.conduit.xyz`]}},blockExplorers:{default:{name:`Forta Explorer`,url:`https://explorer.forta.org`}}}),SC=L({id:31337,name:`Foundry`,nativeCurrency:{decimals:18,name:`Ether`,symbol:`ETH`},rpcUrls:{default:{http:[`http://127.0.0.1:8545`],webSocket:[`ws://127.0.0.1:8545`]}}});var CC=1;const wC=L({...R,id:252,name:`Fraxtal`,nativeCurrency:{name:`Frax`,symbol:`FRAX`,decimals:18},rpcUrls:{default:{http:[`https://rpc.frax.com`]}},blockExplorers:{default:{name:`fraxscan`,url:`https://fraxscan.com`,apiUrl:`https://api.fraxscan.com/api`}},contracts:{...R.contracts,l2OutputOracle:{[CC]:{address:`0x66CC916Ed5C6C2FA97014f7D1cD141528Ae171e4`}},multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`},portal:{[CC]:{address:`0x36cb65c1967A0Fb0EEE11569C51C2f2aA1Ca6f6D`,blockCreated:19135323}},l1StandardBridge:{[CC]:{address:`0x34C0bD5877A5Ee7099D0f5688D65F4bB9158BDE2`,blockCreated:19135323}}},sourceId:CC});var TC=17e3;const EC=L({...R,id:2522,name:`Fraxtal Testnet`,nativeCurrency:{name:`Frax`,symbol:`FRAX`,decimals:18},rpcUrls:{default:{http:[`https://rpc.testnet.frax.com`]}},blockExplorers:{default:{name:`fraxscan testnet`,url:`https://holesky.fraxscan.com`,apiUrl:`https://api-holesky.fraxscan.com/api`}},contracts:{...R.contracts,l2OutputOracle:{[TC]:{address:`0x715EA64DA13F4d0831ece4Ad3E8c1aa013167F32`}},multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`},portal:{[TC]:{address:`0xB9c64BfA498d5b9a8398Ed6f46eb76d90dE5505d`,blockCreated:318416}},l1StandardBridge:{[TC]:{address:`0x0BaafC217162f64930909aD9f2B27125121d6332`,blockCreated:318416}}},sourceId:TC});var DC=1;const OC=L({...R,id:33979,name:`Funki`,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://rpc-mainnet.funkichain.com`]}},blockExplorers:{default:{name:`Funki Mainnet Explorer`,url:`https://funkiscan.io`}},contracts:{...R.contracts},sourceId:DC});var kC=11155111;const AC=L({...R,id:3397901,network:`funkiSepolia`,name:`Funki Sepolia Sandbox`,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://funki-testnet.alt.technology`]}},blockExplorers:{default:{name:`Funki Sepolia Sandbox Explorer`,url:`https://sepolia-sandbox.funkichain.com/`}},testnet:!0,contracts:{...R.contracts,multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:1620204}},sourceId:kC}),jC=L({id:122,name:`Fuse`,nativeCurrency:{name:`Fuse`,symbol:`FUSE`,decimals:18},rpcUrls:{default:{http:[`https://rpc.fuse.io`]}},blockExplorers:{default:{name:`Fuse Explorer`,url:`https://explorer.fuse.io`,apiUrl:`https://explorer.fuse.io/api`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:16146628}}}),MC=L({id:123,name:`Fuse Sparknet`,nativeCurrency:{name:`Spark`,symbol:`SPARK`,decimals:18},rpcUrls:{default:{http:[`https://rpc.fusespark.io`]}},blockExplorers:{default:{name:`Sparkent Explorer`,url:`https://explorer.fusespark.io`,apiUrl:`https://explorer.fusespark.io/api`}}}),NC=L({id:32659,name:`Fusion Mainnet`,nativeCurrency:{name:`Fusion`,symbol:`FSN`,decimals:18},rpcUrls:{default:{http:[`https://mainnet.fusionnetwork.io`],webSocket:[`wss://mainnet.fusionnetwork.io`]}},blockExplorers:{default:{name:`FSNscan`,url:`https://fsnscan.com`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:10441605}},testnet:!1}),PC=L({id:46688,name:`Fusion Testnet`,nativeCurrency:{name:`Fusion`,symbol:`FSN`,decimals:18},rpcUrls:{default:{http:[`https://testnet.fusionnetwork.io`],webSocket:[`wss://testnet.fusionnetwork.io`]}},blockExplorers:{default:{name:`FSNscan`,url:`https://testnet.fsnscan.com`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:10428309}},testnet:!0});var FC=17e3;const IC=L({...R,name:`Garnet Testnet`,testnet:!0,id:17069,sourceId:FC,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://rpc.garnetchain.com`],webSocket:[`wss://rpc.garnetchain.com`]}},blockExplorers:{default:{name:`Blockscout`,url:`https://explorer.garnetchain.com`}},contracts:{...R.contracts,multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`},portal:{[FC]:{address:`0x57ee40586fbE286AfC75E67cb69511A6D9aF5909`,blockCreated:1274684}},l2OutputOracle:{[FC]:{address:`0xCb8E7AC561b8EF04F2a15865e9fbc0766FEF569B`,blockCreated:1274684}},l1StandardBridge:{[FC]:{address:`0x09bcDd311FE398F80a78BE37E489f5D440DB95DE`,blockCreated:1274684}}}}),LC=L({id:63157,name:`Geist Mainnet`,nativeCurrency:{decimals:18,name:`Aavegotchi GHST Token`,symbol:`GHST`},rpcUrls:{default:{http:[`https://geist-mainnet.g.alchemy.com/public`]}},blockExplorers:{default:{name:`Blockscout`,url:`https://geist-mainnet.explorer.alchemy.com`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:660735}}}),RC=L({id:16507,name:`Genesys Mainnet`,nativeCurrency:{decimals:18,name:`GSYS`,symbol:`GSYS`},rpcUrls:{default:{http:[`https://rpc.genesys.network`]}},blockExplorers:{default:{name:`Genesys Explorer`,url:`https://gchainexplorer.genesys.network`}},testnet:!1});var zC=11155111;const BC=L({...R,id:91342,network:`giwa-sepolia`,name:`GIWA Sepolia`,nativeCurrency:{name:`Sepolia Ether`,symbol:`ETH`,decimals:18},blockTime:1e3,rpcUrls:{default:{http:[`https://sepolia-rpc.giwa.io`]}},blockExplorers:{default:{name:`Blockscout`,url:`https://sepolia-explorer.giwa.io`,apiUrl:`https://sepolia-explorer.giwa.io/api`}},contracts:{...R.contracts,multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:0},disputeGameFactory:{[zC]:{address:`0x37347caB2afaa49B776372279143D71ad1f354F6`}},portal:{[zC]:{address:`0x956962C34687A954e611A83619ABaA37Ce6bC78A`}},l1StandardBridge:{[zC]:{address:`0x77b2ffc0F57598cAe1DB76cb398059cF5d10A7E7`}}},testnet:!0,sourceId:zC}),VC=L({id:251,name:`Glide L1 Protocol XP`,nativeCurrency:{name:`GLXP`,symbol:`GLXP`,decimals:18},rpcUrls:{default:{http:[`https://rpc-api.glideprotocol.xyz/l1-rpc`],webSocket:[`wss://rpc-api.glideprotocol.xyz/l1-rpc`]}},blockExplorers:{default:{name:`Glide Protocol Explore`,url:`https://blockchain-explorer.glideprotocol.xyz`}},testnet:!1}),HC=L({id:253,name:`Glide L2 Protocol XP`,nativeCurrency:{name:`GLXP`,symbol:`GLXP`,decimals:18},rpcUrls:{default:{http:[`https://rpc-api.glideprotocol.xyz/l2-rpc`],webSocket:[`wss://rpc-api.glideprotocol.xyz/l2-rpc`]}},blockExplorers:{default:{name:`Glide Protocol Explore`,url:`https://blockchain-explorer.glideprotocol.xyz`}},testnet:!1}),UC=L({id:100,name:`Gnosis`,nativeCurrency:{decimals:18,name:`xDAI`,symbol:`XDAI`},blockTime:5e3,rpcUrls:{default:{http:[`https://rpc.gnosischain.com`],webSocket:[`wss://rpc.gnosischain.com/wss`]}},blockExplorers:{default:{name:`Gnosisscan`,url:`https://gnosisscan.io`,apiUrl:`https://api.gnosisscan.io/api`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:21022491}}}),WC=L({id:10200,name:`Gnosis Chiado`,nativeCurrency:{decimals:18,name:`Gnosis`,symbol:`xDAI`},blockTime:5e3,rpcUrls:{default:{http:[`https://rpc.chiadochain.net`],webSocket:[`wss://rpc.chiadochain.net/wss`]}},blockExplorers:{default:{name:`Blockscout`,url:`https://blockscout.chiadochain.net`,apiUrl:`https://blockscout.chiadochain.net/api`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:4967313}},testnet:!0}),GC=L({id:2345,name:`GOAT`,nativeCurrency:{decimals:18,name:`Bitcoin`,symbol:`BTC`},rpcUrls:{default:{http:[`https://rpc.goat.network`]}},blockExplorers:{default:{name:`Goat Explorer`,url:`https://explorer.goat.network`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:0}}}),KC=L({id:1663,name:`Horizen Gobi Testnet`,nativeCurrency:{decimals:18,name:`Test ZEN`,symbol:`tZEN`},rpcUrls:{default:{http:[`https://gobi-testnet.horizenlabs.io/ethv1`]}},blockExplorers:{default:{name:`Gobi Explorer`,url:`https://gobi-explorer.horizen.io`}},contracts:{},testnet:!0}),qC=L({id:60,name:`GoChain`,nativeCurrency:{decimals:18,name:`GO`,symbol:`GO`},rpcUrls:{default:{http:[`https://rpc.gochain.io`]}},blockExplorers:{default:{name:`GoChain Explorer`,url:`https://explorer.gochain.io`}},testnet:!1}),JC=L({id:71402,name:`Godwoken Mainnet`,nativeCurrency:{decimals:18,name:`pCKB`,symbol:`pCKB`},rpcUrls:{default:{http:[`https://v1.mainnet.godwoken.io/rpc`]}},blockExplorers:{default:{name:`GW Scan`,url:`https://v1.gwscan.com`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:15034}},testnet:!1}),YC=L({id:5,name:`Goerli`,nativeCurrency:{name:`Goerli Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://5.rpc.thirdweb.com`]}},blockExplorers:{default:{name:`Etherscan`,url:`https://goerli.etherscan.io`,apiUrl:`https://api-goerli.etherscan.io/api`}},contracts:{ensRegistry:{address:`0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e`},ensUniversalResolver:{address:`0xfc4AC75C46C914aF5892d6d3eFFcebD7917293F1`,blockCreated:10339206},multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:6507670}},testnet:!0}),XC=L({id:440017,name:`Graphite Network`,nativeCurrency:{name:`Graphite`,symbol:`@G`,decimals:18},rpcUrls:{default:{http:[`https://anon-entrypoint-1.atgraphite.com`],webSocket:[`wss://ws-anon-entrypoint-1.atgraphite.com`]}},blockExplorers:{default:{name:`Graphite Spectre`,url:`https://main.atgraphite.com`,apiUrl:`https://api.main.atgraphite.com/api`}},testnet:!1}),ZC=L({id:54170,name:`Graphite Network Testnet`,nativeCurrency:{name:`Graphite`,symbol:`@G`,decimals:18},rpcUrls:{default:{http:[`https://anon-entrypoint-test-1.atgraphite.com`],webSocket:[`wss://ws-anon-entrypoint-test-1.atgraphite.com`]}},blockExplorers:{default:{name:`Graphite Testnet Spectre`,url:`https://test.atgraphite.com`,apiUrl:`https://api.test.atgraphite.com/api`}},testnet:!0}),QC=L({id:1625,name:`Gravity Alpha Mainnet`,nativeCurrency:{name:`G`,symbol:`G`,decimals:18},rpcUrls:{default:{http:[`https://rpc.gravity.xyz`]}},blockExplorers:{default:{name:`Gravity Explorer`,url:`https://explorer.gravity.xyz`,apiUrl:`https://explorer.gravity.xyz/api`}},contracts:{multicall3:{address:`0xf8ac4BEB2F75d2cFFb588c63251347fdD629B92c`,blockCreated:16851}}}),$C=L({id:43419,name:`Gunz Mainnet`,nativeCurrency:{name:`GUN`,symbol:`GUN`,decimals:18},rpcUrls:{default:{http:[`https://rpc.gunzchain.io/ext/bc/2M47TxWHGnhNtq6pM5zPXdATBtuqubxn5EPFgFmEawCQr9WFML/rpc`]}},blockExplorers:{default:{name:`Gunz Explorer`,url:`https://gunzscan.io/`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:70502}}}),ew=L({id:260,name:`Guru Network Mainnet`,nativeCurrency:{name:`GURU Token`,symbol:`GURU`,decimals:18},rpcUrls:{default:{http:[`https://rpc-main.gurunetwork.ai`,`https://rpc.gurunetwork.ai/archive/260`]}},blockExplorers:{default:{name:`Guruscan`,url:`https://scan.gurunetwork.ai`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:271691}},testnet:!1}),tw=L({id:261,name:`Guru Network Testnet`,nativeCurrency:{name:`tGURU Token`,symbol:`tGURU`,decimals:18},rpcUrls:{default:{http:[`https://rpc-test.gurunetwork.ai`,`https://rpc.gurunetwork.ai/archive/261`]}},blockExplorers:{default:{name:`Guruscan`,url:`https://sepolia.gurunetwork.ai`}},testnet:!0}),nw=L({id:5112,name:`Ham`,nativeCurrency:{decimals:18,name:`Ham`,symbol:`ETH`},rpcUrls:{default:{http:[`https://rpc.ham.fun`],webSocket:[`wss://rpc.ham.fun`]}},blockExplorers:{default:{name:`Ham Chain Explorer`,url:`https://explorer.ham.fun`,apiUrl:`https://explorer.ham.fun/api/v2`}}}),rw=L({id:216,name:`Happychain Testnet`,nativeCurrency:{symbol:`HAPPY`,name:`HAPPY`,decimals:18},rpcUrls:{default:{http:[`https://rpc.testnet.happy.tech/http`],webSocket:[`wss://rpc.testnet.happy.tech/ws`]}},blockExplorers:{default:{name:`Happy Chain Testnet Explorer`,url:`https://explorer.testnet.happy.tech`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:1}},testnet:!0}),iw=L({id:11235,name:`HAQQ Mainnet`,nativeCurrency:{decimals:18,name:`Islamic Coin`,symbol:`ISLM`},rpcUrls:{default:{http:[`https://rpc.eth.haqq.network`]}},blockExplorers:{default:{name:`HAQQ Explorer`,url:`https://explorer.haqq.network`,apiUrl:`https://explorer.haqq.network/api`}}}),aw=L({id:54211,name:`HAQQ Testedge 2`,nativeCurrency:{decimals:18,name:`Islamic Coin`,symbol:`ISLMT`},rpcUrls:{default:{http:[`https://rpc.eth.testedge2.haqq.network`]}},blockExplorers:{default:{name:`HAQQ Explorer`,url:`https://explorer.testedge2.haqq.network`,apiUrl:`https://explorer.testedge2.haqq.network/api`}}}),ow=L({id:31337,name:`Hardhat`,nativeCurrency:{decimals:18,name:`Ether`,symbol:`ETH`},rpcUrls:{default:{http:[`http://127.0.0.1:8545`]}}}),sw=L({id:16666e5,name:`Harmony One`,nativeCurrency:{name:`Harmony`,symbol:`ONE`,decimals:18},rpcUrls:{default:{http:[`https://1666600000.rpc.thirdweb.com`]}},blockExplorers:{default:{name:`Harmony Explorer`,url:`https://explorer.harmony.one`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:24185753}}}),cw=L({id:177,name:`HashKey Chain`,nativeCurrency:{decimals:18,name:`HashKey EcoPoints`,symbol:`HSK`},rpcUrls:{default:{http:[`https://mainnet.hsk.xyz`]}},blockExplorers:{default:{name:`HashKey Chain Explorer`,url:`https://hashkey.blockscout.com`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:0}}}),lw=L({id:133,name:`HashKey Chain Testnet`,nativeCurrency:{decimals:18,name:`HashKey EcoPoints`,symbol:`HSK`},rpcUrls:{default:{http:[`https://hashkeychain-testnet.alt.technology`]}},blockExplorers:{default:{name:`HashKey Chain Explorer`,url:`https://hashkeychain-testnet-explorer.alt.technology`}},testnet:!0}),uw=L({id:1523903251,name:`Haust Network Testnet`,nativeCurrency:{decimals:18,name:`HAUST`,symbol:`HAUST`},rpcUrls:{default:{http:[`https://rpc-testnet.haust.app`]}},blockExplorers:{default:{name:`Haust Network Testnet Explorer`,url:`https://explorer-testnet.haust.app`}},testnet:!0}),dw=L({id:295,name:`Hedera Mainnet`,network:`hedera-mainnet`,nativeCurrency:{symbol:`HBAR`,name:`HBAR`,decimals:18},rpcUrls:{default:{http:[`https://mainnet.hashio.io/api`]}},blockExplorers:{default:{name:`Hashscan`,url:`https://hashscan.io/mainnet`}},testnet:!1}),fw=L({id:297,name:`Hedera Previewnet`,network:`hedera-previewnet`,nativeCurrency:{symbol:`HBAR`,name:`HBAR`,decimals:18},rpcUrls:{default:{http:[`https://previewnet.hashio.io/api`]}},blockExplorers:{default:{name:`Hashscan`,url:`https://hashscan.io/previewnet`}},testnet:!0}),pw=L({id:296,name:`Hedera Testnet`,network:`hedera-testnet`,nativeCurrency:{symbol:`HBAR`,name:`HBAR`,decimals:18},rpcUrls:{default:{http:[`https://testnet.hashio.io/api`]}},blockExplorers:{default:{name:`Hashscan`,url:`https://hashscan.io/testnet`}},testnet:!0}),mw=L({id:8668,name:`Hela Mainnet`,nativeCurrency:{name:`HLUSD`,symbol:`HLUSD`,decimals:18},rpcUrls:{default:{http:[`https://mainnet-rpc.helachain.com`]}},blockExplorers:{default:{name:`Hela explorer`,url:`https://mainnet-blockexplorer.helachain.com`}},testnet:!1}),hw=L({id:43111,name:`Hemi`,network:`Hemi`,blockTime:12e3,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://rpc.hemi.network/rpc`]}},blockExplorers:{default:{name:`blockscout`,url:`https://explorer.hemi.xyz`}},testnet:!1}),gw=L({id:743111,name:`Hemi Sepolia`,network:`Hemi Sepolia`,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://testnet.rpc.hemi.network/rpc`]}},blockExplorers:{default:{name:`Hemi Sepolia explorer`,url:`https://testnet.explorer.hemi.xyz`}},testnet:!0}),_w=L({id:17e3,name:`Holesky`,nativeCurrency:{name:`Holesky Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://ethereum-holesky-rpc.publicnode.com`]}},blockExplorers:{default:{name:`Etherscan`,url:`https://holesky.etherscan.io`,apiUrl:`https://api-holesky.etherscan.io/api`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:77},ensUniversalResolver:{address:`0xeeeeeeee14d718c2b47d9923deab1335e144eeee`,blockCreated:4295055}},testnet:!0}),vw=L({id:560048,name:`Hoodi`,nativeCurrency:{name:`Hoodi Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://rpc.hoodi.ethpandaops.io`]}},blockExplorers:{default:{name:`Etherscan`,url:`https://hoodi.etherscan.io`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:2589}},testnet:!0}),yw=L({id:269,name:`High Performance Blockchain`,nativeCurrency:{name:`HPB`,symbol:`HPB`,decimals:18},rpcUrls:{default:{http:[`https://hpbnode.com`]}},blockExplorers:{default:{name:`hpbScan`,url:`https://hscan.org`}},testnet:!1}),bw=L({id:12323,name:`Huddle01 dRTC Chain`,nativeCurrency:{name:`Ethereum`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://huddle01.calderachain.xyz/http`],webSocket:[`wss://huddle01.calderachain.xyz/ws`]}},blockExplorers:{default:{name:`Huddle01 Caldera Explorer`,url:`https://huddle01.calderaexplorer.xyz`,apiUrl:`https://huddle01.calderaexplorer.xyz/api`}},sourceId:42161}),xw=L({id:2524852,name:`Huddle01 dRTC Chain Testnet`,nativeCurrency:{name:`Ethereum`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://huddle-testnet.rpc.caldera.xyz/http`],webSocket:[`wss://huddle-testnet.rpc.caldera.xyz/ws`]}},blockExplorers:{default:{name:`Huddle01 Caldera Explorer`,url:`https://huddle-testnet.explorer.caldera.xyz`,apiUrl:`https://huddle-testnet.explorer.caldera.xyz/api`}},sourceId:421614}),Sw=L({id:6985385,name:`Humanity`,nativeCurrency:{name:`H`,symbol:`H`,decimals:18},rpcUrls:{default:{http:[`https://humanity-mainnet.g.alchemy.com/public`]}},blockExplorers:{default:{name:`Humanity Mainnet Explorer`,url:`https://humanity-mainnet.explorer.alchemy.com`,apiUrl:`https://humanity-mainnet.explorer.alchemy.com/api`}},testnet:!1}),Cw=L({id:7080969,name:`Humanity Testnet`,nativeCurrency:{name:`tHP`,symbol:`tHP`,decimals:18},rpcUrls:{default:{http:[`https://rpc.testnet.humanity.org`]}},blockExplorers:{default:{name:`Humanity Testnet Explorer`,url:`https://humanity-testnet.explorer.alchemy.com`,apiUrl:`https://humanity-testnet.explorer.alchemy.com/api`}},testnet:!0}),ww=L({id:5234,name:`Humanode`,nativeCurrency:{name:`HMND`,symbol:`HMND`,decimals:18},rpcUrls:{default:{http:[`https://explorer-rpc-http.mainnet.stages.humanode.io`],webSocket:[`wss://explorer-rpc-ws.mainnet.stages.humanode.io`]}},blockExplorers:{default:{name:`Subscan`,url:`https://humanode.subscan.io`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:4413097}}}),Tw=L({id:14853,name:`Humanode Testnet 5`,nativeCurrency:{name:`HMND`,symbol:`HMND`,decimals:18},rpcUrls:{default:{http:[`https://explorer-rpc-http.testnet5.stages.humanode.io`],webSocket:[`wss://explorer-rpc-ws.testnet5.stages.humanode.io`]}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`}}}),Ew=L({id:2911,name:`HYCHAIN`,nativeCurrency:{name:`HYTOPIA`,symbol:`TOPIA`,decimals:18},rpcUrls:{default:{http:[`https://rpc.hychain.com/http`]}},blockExplorers:{default:{name:`HYCHAIN Explorer`,url:`https://explorer.hychain.com`}},testnet:!1}),Dw=L({id:29112,name:`HYCHAIN Testnet`,nativeCurrency:{name:`HYTOPIA`,symbol:`TOPIA`,decimals:18},rpcUrls:{default:{http:[`https://rpc.hychain.com/http`]}},blockExplorers:{default:{name:`HYCHAIN Explorer`,url:`https://testnet-rpc.hychain.com/http`}},testnet:!0}),Ow=L({id:998,name:`Hyperliquid EVM Testnet`,nativeCurrency:{name:`HYPE`,symbol:`HYPE`,decimals:18},rpcUrls:{default:{http:[`https://rpc.hyperliquid-testnet.xyz/evm`]}},testnet:!0}),kw=L({id:73115,name:`ICB Network`,nativeCurrency:{decimals:18,name:`ICB Native Token`,symbol:`ICBX`},rpcUrls:{default:{http:[`https://rpc1-mainnet.icbnetwork.info`]}},blockExplorers:{default:{name:`ICB Explorer`,url:`https://icbscan.io`,apiUrl:`https://icbscan.io/api`}},testnet:!1}),Aw=L({id:74,name:`IDChain Mainnet`,nativeCurrency:{decimals:18,name:`EIDI`,symbol:`EIDI`},rpcUrls:{default:{http:[`https://idchain.one/rpc`],webSocket:[`wss://idchain.one/ws`]}},blockExplorers:{default:{name:`IDChain Explorer`,url:`https://explorer.idchain.one`}},testnet:!1}),jw=L({id:13371,name:`Immutable zkEVM`,nativeCurrency:{decimals:18,name:`Immutable Coin`,symbol:`IMX`},rpcUrls:{default:{http:[`https://rpc.immutable.com`]}},blockExplorers:{default:{name:`Immutable Explorer`,url:`https://explorer.immutable.com`,apiUrl:`https://explorer.immutable.com/api`}},contracts:{multicall3:{address:`0x236bdA4589e44e6850f5aC6a74BfCa398a86c6c0`,blockCreated:4335972}}}),Mw=L({id:13473,name:`Immutable zkEVM Testnet`,nativeCurrency:{decimals:18,name:`Immutable Coin`,symbol:`IMX`},rpcUrls:{default:{http:[`https://rpc.testnet.immutable.com`]}},blockExplorers:{default:{name:`Immutable Testnet Explorer`,url:`https://explorer.testnet.immutable.com/`}},contracts:{multicall3:{address:`0x2CC787Ed364600B0222361C4188308Fa8E68bA60`,blockCreated:5977391}},testnet:!0}),Nw=L({id:2525,name:`inEVM Mainnet`,nativeCurrency:{decimals:18,name:`Injective`,symbol:`INJ`},rpcUrls:{default:{http:[`https://mainnet.rpc.inevm.com/http`]}},blockExplorers:{default:{name:`inEVM Explorer`,url:`https://inevm.calderaexplorer.xyz`,apiUrl:`https://inevm.calderaexplorer.xyz/api/v2`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:118606}}}),Pw=L({id:7233,name:`InitVerse Mainnet`,nativeCurrency:{decimals:18,name:`InitVerse`,symbol:`INI`},rpcUrls:{default:{http:[`https://rpc-mainnet.inichain.com`]}},blockExplorers:{default:{name:`InitVerseScan`,url:`https://www.iniscan.com`,apiUrl:`https://explorer-api.inichain.com/api`}},contracts:{multicall3:{address:`0x83466BE48A067115FFF91f7b892Ed1726d032e47`,blockCreated:2318}}}),Fw=L({id:7234,name:`InitVerse Genesis Testnet`,nativeCurrency:{decimals:18,name:`InitVerse`,symbol:`INI`},rpcUrls:{default:{http:[`https://rpc-testnet.inichain.com`]}},blockExplorers:{default:{name:`InitVerseGenesisScan`,url:`https://genesis-testnet.iniscan.com`,apiUrl:`https://explorer-testnet-api.inichain.com/api`}},contracts:{multicall3:{address:`0x0cF32CBDd6c437331EA4f85ed2d881A5379B5a6F`,blockCreated:16361}},testnet:!0}),Iw=L({id:1776,name:`Injective`,nativeCurrency:{decimals:18,name:`Injective`,symbol:`INJ`},rpcUrls:{default:{http:[`https://sentry.evm-rpc.injective.network`],webSocket:[`wss://sentry.evm-ws.injective.network`]}},blockExplorers:{default:{name:`Injective Explorer`,url:`https://blockscout.injective.network`,apiUrl:`https://blockscout.injective.network/api`}},testnet:!1}),Lw=L({id:1439,name:`Injective Testnet`,nativeCurrency:{decimals:18,name:`Injective`,symbol:`INJ`},rpcUrls:{default:{http:[`https://k8s.testnet.json-rpc.injective.network`],webSocket:[`wss://k8s.testnet.ws.injective.network`]}},blockExplorers:{default:{name:`Injective Explorer`,url:`https://testnet.blockscout.injective.network`,apiUrl:`https://testnet.blockscout.injective.network/api`}},testnet:!0});var Rw=1;const zw=L({...R,id:57073,name:`Ink`,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://rpc-gel.inkonchain.com`,`https://rpc-qnd.inkonchain.com`],webSocket:[`wss://rpc-gel.inkonchain.com`,`wss://rpc-qnd.inkonchain.com`]}},blockExplorers:{default:{name:`Blockscout`,url:`https://explorer.inkonchain.com`,apiUrl:`https://explorer.inkonchain.com/api/v2`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:0},...R.contracts,disputeGameFactory:{[Rw]:{address:`0x10d7b35078d3baabb96dd45a9143b94be65b12cd`}},portal:{[Rw]:{address:`0x5d66c1782664115999c47c9fa5cd031f495d3e4f`}},l1StandardBridge:{[Rw]:{address:`0x88ff1e5b602916615391f55854588efcbb7663f0`}}},testnet:!1,sourceId:Rw});var Bw=11155111;const Vw=L({...R,id:763373,name:`Ink Sepolia`,nativeCurrency:{name:`Sepolia Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://rpc-gel-sepolia.inkonchain.com`]}},blockExplorers:{default:{name:`Blockscout`,url:`https://explorer-sepolia.inkonchain.com/`,apiUrl:`https://explorer-sepolia.inkonchain.com/api/v2`}},contracts:{...R.contracts,multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:0},disputeGameFactory:{[Bw]:{address:`0x860e626c700af381133d9f4af31412a2d1db3d5d`}},portal:{[Bw]:{address:`0x5c1d29c6c9c8b0800692acc95d700bcb4966a1d7`}},l1StandardBridge:{[Bw]:{address:`0x33f60714bbd74d62b66d79213c348614de51901c`}}},testnet:!0,sourceId:Bw}),Hw=L({id:8822,name:`IOTA EVM`,network:`iotaevm`,nativeCurrency:{decimals:18,name:`IOTA`,symbol:`IOTA`},rpcUrls:{default:{http:[`https://json-rpc.evm.iotaledger.net`],webSocket:[`wss://ws.json-rpc.evm.iotaledger.net`]}},blockExplorers:{default:{name:`Explorer`,url:`https://explorer.evm.iota.org`,apiUrl:`https://explorer.evm.iota.org/api`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:25022}}}),Uw=L({id:1075,name:`IOTA EVM Testnet`,network:`iotaevm-testnet`,nativeCurrency:{decimals:18,name:`IOTA`,symbol:`IOTA`},rpcUrls:{default:{http:[`https://json-rpc.evm.testnet.iotaledger.net`],webSocket:[`wss://ws.json-rpc.evm.testnet.iotaledger.net`]}},blockExplorers:{default:{name:`Explorer`,url:`https://explorer.evm.testnet.iotaledger.net`,apiUrl:`https://explorer.evm.testnet.iotaledger.net/api`}},testnet:!0}),Ww=L({id:4689,name:`IoTeX`,nativeCurrency:{decimals:18,name:`IoTeX`,symbol:`IOTX`},rpcUrls:{default:{http:[`https://babel-api.mainnet.iotex.io`],webSocket:[`wss://babel-api.mainnet.iotex.io`]}},blockExplorers:{default:{name:`IoTeXScan`,url:`https://iotexscan.io`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:22163670}}}),Gw=L({id:4690,name:`IoTeX Testnet`,nativeCurrency:{decimals:18,name:`IoTeX`,symbol:`IOTX`},rpcUrls:{default:{http:[`https://babel-api.testnet.iotex.io`],webSocket:[`wss://babel-api.testnet.iotex.io`]}},blockExplorers:{default:{name:`IoTeXScan`,url:`https://testnet.iotexscan.io`}},contracts:{multicall3:{address:`0xb5cecD6894c6f473Ec726A176f1512399A2e355d`,blockCreated:24347592}},testnet:!0}),Kw=L({id:8017,name:`iSunCoin Mainnet`,nativeCurrency:{decimals:18,name:`ISC`,symbol:`ISC`},rpcUrls:{default:{http:[`https://mainnet.isuncoin.com`]}},blockExplorers:{default:{name:`iSunCoin Explorer`,url:`https://baifa.io/app/chains/8017`}}}),qw=L({id:8899,name:`JB Chain`,network:`jbc`,nativeCurrency:{name:`JBC`,symbol:`JBC`,decimals:18},rpcUrls:{default:{http:[`https://rpc-l1.jibchain.net`]}},blockExplorers:{default:{name:`Blockscout`,url:`https://exp-l1.jibchain.net`,apiUrl:`https://exp-l1.jibchain.net/api`}},contracts:{multicall3:{address:`0xc0C8C486D1466C57Efe13C2bf000d4c56F47CBdC`,blockCreated:2299048}},testnet:!1}),Jw=L({id:88991,name:`Jibchain Testnet`,nativeCurrency:{name:`tJBC`,symbol:`tJBC`,decimals:18},rpcUrls:{default:{http:[`https://rpc.testnet.jibchain.net`]}},blockExplorers:{default:{name:`Blockscout`,url:`https://exp.testnet.jibchain.net`,apiUrl:`https://exp.testnet.jibchain.net/api`}},contracts:{multicall3:{address:`0xa1a858ad9041B4741e620355a3F96B3c78e70ecE`,blockCreated:32848}},testnet:!0}),Yw=L({id:81,name:`Japan Open Chain Mainnet`,nativeCurrency:{decimals:18,name:`Japan Open Chain Token`,symbol:`JOC`},rpcUrls:{default:{http:[`https://rpc-1.japanopenchain.org:8545`,`https://rpc-2.japanopenchain.org:8545`,`https://rpc-3.japanopenchain.org`]}},blockExplorers:{default:{name:`Block Explorer`,url:`https://explorer.japanopenchain.org`}},testnet:!1}),Xw=L({id:10081,name:`Japan Open Chain Testnet`,nativeCurrency:{decimals:18,name:`Japan Open Chain Testnet Token`,symbol:`JOCT`},rpcUrls:{default:{http:[`https://rpc-1.testnet.japanopenchain.org:8545`,`https://rpc-2.testnet.japanopenchain.org:8545`,`https://rpc-3.testnet.japanopenchain.org`]}},blockExplorers:{default:{name:`Testnet Block Explorer`,url:`https://explorer.testnet.japanopenchain.org`}},testnet:!0}),Zw=L({id:5734951,name:`Jovay Mainnet`,nativeCurrency:{decimals:18,name:`Ether`,symbol:`ETH`},rpcUrls:{default:{http:[`https://api.zan.top/public/jovay-mainnet`]}},blockExplorers:{default:{name:`Jovay Explorer`,url:`https://explorer.jovay.io`}},testnet:!1}),Qw=L({id:2019775,name:`Jovay Sepolia Testnet`,nativeCurrency:{decimals:18,name:`Ether`,symbol:`ETH`},rpcUrls:{default:{http:[`https://api.zan.top/public/jovay-testnet`]}},blockExplorers:{default:{name:`Jovay Testnet Explorer`,url:`https://sepolia-explorer.jovay.io/l2`}},testnet:!0}),$w=L({id:45003,name:`Juneo JUNE-Chain`,nativeCurrency:{decimals:18,name:`JUNE-Chain`,symbol:`JUNE`},rpcUrls:{default:{http:[`https://rpc.juneo-mainnet.network/ext/bc/JUNE/rpc`]}},blockExplorers:{default:{name:`Juneo Scan`,url:`https://juneoscan.io/chain/2`,apiUrl:`https://juneoscan.io/chain/2/api`}}}),eT=L({id:45013,name:`Juneo BCH1-Chain`,nativeCurrency:{decimals:18,name:`Juneo BCH1-Chain`,symbol:`BCH1`},rpcUrls:{default:{http:[`https://rpc.juneo-mainnet.network/ext/bc/BCH1/rpc`]}},blockExplorers:{default:{name:`Juneo Scan`,url:`https://juneoscan.io/chain/12`,apiUrl:`https://juneoscan.io/chain/12/api`}}}),tT=L({id:45004,name:`Juneo DAI1-Chain`,nativeCurrency:{decimals:18,name:`Juneo DAI1-Chain`,symbol:`DAI1`},rpcUrls:{default:{http:[`https://rpc.juneo-mainnet.network/ext/bc/DAI1/rpc`]}},blockExplorers:{default:{name:`Juneo Scan`,url:`https://juneoscan.io/chain/5`,apiUrl:`https://juneoscan.io/chain/5/api`}}}),nT=L({id:45010,name:`Juneo DOGE1-Chain`,nativeCurrency:{decimals:18,name:`Juneo DOGE1-Chain`,symbol:`DOGE1`},rpcUrls:{default:{http:[`https://rpc.juneo-mainnet.network/ext/bc/DOGE1/rpc`]}},blockExplorers:{default:{name:`Juneo Scan`,url:`https://juneoscan.io/chain/10`,apiUrl:`https://juneoscan.io/chain/10/api`}}}),rT=L({id:45011,name:`Juneo EUR1-Chain`,nativeCurrency:{decimals:18,name:`Juneo EUR1-Chain`,symbol:`EUR1`},rpcUrls:{default:{http:[`https://rpc.juneo-mainnet.network/ext/bc/EUR1/rpc`]}},blockExplorers:{default:{name:`Juneo Scan`,url:`https://juneoscan.io/chain/6`,apiUrl:`https://juneoscan.io/chain/6/api`}}}),iT=L({id:45008,name:`Juneo GLD1-Chain`,nativeCurrency:{decimals:18,name:`Juneo GLD1-Chain`,symbol:`GLD1`},rpcUrls:{default:{http:[`https://rpc.juneo-mainnet.network/ext/bc/GLD1/rpc`]}},blockExplorers:{default:{name:`Juneo Scan`,url:`https://juneoscan.io/chain/8`,apiUrl:`https://juneoscan.io/chain/8/api`}}}),aT=L({id:45014,name:`Juneo LINK1-Chain`,nativeCurrency:{decimals:18,name:`Juneo LINK1-Chain`,symbol:`LINK1`},rpcUrls:{default:{http:[`https://rpc.juneo-mainnet.network/ext/bc/LINK1/rpc`]}},blockExplorers:{default:{name:`Juneo Scan`,url:`https://juneoscan.io/chain/13`,apiUrl:`https://juneoscan.io/chain/13/api`}}}),oT=L({id:45009,name:`Juneo LTC1-Chain`,nativeCurrency:{decimals:18,name:`Juneo LTC1-Chain`,symbol:`LTC1`},rpcUrls:{default:{http:[`https://rpc.juneo-mainnet.network/ext/bc/LTC1/rpc`]}},blockExplorers:{default:{name:`Juneo Scan`,url:`https://juneoscan.io/chain/11`,apiUrl:`https://juneoscan.io/chain/11/api`}}}),sT=L({id:45007,name:`Juneo mBTC1-Chain`,nativeCurrency:{decimals:18,name:`Juneo mBTC1-Chain`,symbol:`mBTC1`},rpcUrls:{default:{http:[`https://rpc.juneo-mainnet.network/ext/bc/mBTC1/rpc`]}},blockExplorers:{default:{name:`Juneo Scan`,url:`https://juneoscan.io/chain/9`,apiUrl:`https://juneoscan.io/chain/9/api`}}}),cT=L({id:45012,name:`Juneo SGD1-Chain`,nativeCurrency:{decimals:18,name:`Juneo SGD1-Chain`,symbol:`SGD1`},rpcUrls:{default:{http:[`https://rpc.juneo-mainnet.network/ext/bc/SGD1/rpc`]}},blockExplorers:{default:{name:`Juneo Scan`,url:`https://juneoscan.io/chain/7`,apiUrl:`https://juneoscan.io/chain/7/api`}}}),lT=L({id:101003,name:`Socotra JUNE-Chain`,nativeCurrency:{decimals:18,name:`Socotra JUNE-Chain`,symbol:`JUNE`},rpcUrls:{default:{http:[`https://rpc.socotra-testnet.network/ext/bc/JUNE/rpc`]}},blockExplorers:{default:{name:`Juneo Scan`,url:`https://socotra.juneoscan.io/chain/2`,apiUrl:`https://socotra.juneoscan.io/chain/2/api`}},testnet:!0}),uT=L({id:45006,name:`Juneo USD1-Chain`,nativeCurrency:{decimals:18,name:`Juneo USD1-Chain`,symbol:`USD1`},rpcUrls:{default:{http:[`https://rpc.juneo-mainnet.network/ext/bc/USD1/rpc`]}},blockExplorers:{default:{name:`Juneo Scan`,url:`https://juneoscan.io/chain/4`,apiUrl:`https://juneoscan.io/chain/4/api`}}}),dT=L({id:45005,name:`Juneo USDT1-Chain`,nativeCurrency:{decimals:18,name:`Juneo USDT1-Chain`,symbol:`USDT1`},rpcUrls:{default:{http:[`https://rpc.juneo-mainnet.network/ext/bc/USDT1/rpc`]}},blockExplorers:{default:{name:`Juneo Scan`,url:`https://juneoscan.io/chain/3`,apiUrl:`https://juneoscan.io/chain/3/api`}}}),fT=L({id:8217,name:`Kaia`,nativeCurrency:{decimals:18,name:`Kaia`,symbol:`KAIA`},rpcUrls:{default:{http:[`https://public-en.node.kaia.io`]}},blockExplorers:{default:{name:`KaiaScan`,url:`https://kaiascan.io`,apiUrl:`https://api-cypress.klaytnscope.com/api`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:96002415}}}),pT=L({id:1001,name:`Kairos Testnet`,network:`kairos`,nativeCurrency:{decimals:18,name:`Kairos KAIA`,symbol:`KAIA`},rpcUrls:{default:{http:[`https://public-en-kairos.node.kaia.io`]}},blockExplorers:{default:{name:`KaiaScan`,url:`https://kairos.kaiascan.io`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:123390593}},testnet:!0}),mT=L({id:1802203764,name:`Kakarot Sepolia`,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://sepolia-rpc.kakarot.org`]}},blockExplorers:{default:{name:`Kakarot Scan`,url:`https://sepolia.kakarotscan.org`}},testnet:!0}),hT=L({id:920637907288165,name:`Kakarot Starknet Sepolia`,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://sepolia-rpc.kakarot.org`]}},blockExplorers:{default:{name:`Kakarot Scan`,url:`https://sepolia.kakarotscan.org`}},testnet:!0}),gT=L({id:24,name:`KardiaChain Mainnet`,nativeCurrency:{name:`KAI`,symbol:`KAI`,decimals:18},rpcUrls:{default:{http:[`https://rpc.kardiachain.io`]}},blockExplorers:{default:{name:`KardiaChain Explorer`,url:`https://explorer.kardiachain.io`}},testnet:!1}),_T=L({id:686,name:`Karura`,network:`karura`,nativeCurrency:{name:`Karura`,symbol:`KAR`,decimals:18},rpcUrls:{default:{http:[`https://eth-rpc-karura.aca-api.network`],webSocket:[`wss://eth-rpc-karura.aca-api.network`]}},blockExplorers:{default:{name:`Karura Blockscout`,url:`https://blockscout.karura.network`,apiUrl:`https://blockscout.karura.network/api`}},testnet:!1}),vT=L({id:747474,name:`Katana`,network:`katana`,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://rpc.katana.network`]}},blockExplorers:{default:{name:`katana explorer`,url:`https://explorer.katanarpc.com`}},testnet:!1}),yT=L({id:2222,name:`Kava EVM`,network:`kava-mainnet`,nativeCurrency:{name:`Kava`,symbol:`KAVA`,decimals:18},rpcUrls:{default:{http:[`https://evm.kava.io`]}},blockExplorers:{default:{name:`Kava EVM Explorer`,url:`https://kavascan.com`,apiUrl:`https://kavascan.com/api`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:3661165}},testnet:!1}),bT=L({id:2221,name:`Kava EVM Testnet`,network:`kava-testnet`,nativeCurrency:{name:`Kava`,symbol:`KAVA`,decimals:18},rpcUrls:{default:{http:[`https://evm.testnet.kava.io`]}},blockExplorers:{default:{name:`Kava EVM Testnet Explorer`,url:`https://testnet.kavascan.com/`,apiUrl:`https://testnet.kavascan.com/api`}},contracts:{multicall3:{address:`0xDf1D724A7166261eEB015418fe8c7679BBEa7fd6`,blockCreated:7242179}},testnet:!0}),xT=L({id:321,name:`KCC Mainnet`,network:`KCC Mainnet`,nativeCurrency:{decimals:18,name:`KCS`,symbol:`KCS`},rpcUrls:{default:{http:[`https://kcc-rpc.com`]}},blockExplorers:{default:{name:`KCC Explorer`,url:`https://explorer.kcc.io`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:11760430}},testnet:!1}),ST=L({id:1336,name:`Kii Testnet Oro`,network:`kii-testnet-oro`,nativeCurrency:{name:`Kii`,symbol:`KII`,decimals:18},rpcUrls:{default:{http:[`https://json-rpc.uno.sentry.testnet.v3.kiivalidator.com`]}},blockExplorers:{default:{name:`KiiExplorer`,url:`https://explorer.kiichain.io/testnet`}},testnet:!0}),CT=L({id:7887,name:`Kinto Mainnet`,network:`Kinto Mainnet`,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://rpc.kinto.xyz/http`]}},blockExplorers:{default:{name:`Kinto Explorer`,url:`https://explorer.kinto.xyz`}},testnet:!1}),wT=L({id:8217,name:`Klaytn`,nativeCurrency:{decimals:18,name:`Klaytn`,symbol:`KLAY`},rpcUrls:{default:{http:[`https://public-en-cypress.klaytn.net`]}},blockExplorers:{default:{name:`KlaytnScope`,url:`https://scope.klaytn.com`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:96002415}}}),TT=L({id:1001,name:`Klaytn Baobab Testnet`,network:`klaytn-baobab`,nativeCurrency:{decimals:18,name:`Baobab Klaytn`,symbol:`KLAY`},rpcUrls:{default:{http:[`https://public-en-baobab.klaytn.net`]}},blockExplorers:{default:{name:`KlaytnScope`,url:`https://baobab.klaytnscope.com`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:123390593}},testnet:!0}),ET=L({id:701,name:`Koi Network`,nativeCurrency:{decimals:18,name:`Koi Network Native Token`,symbol:`KRING`},rpcUrls:{default:{http:[`https://koi-rpc.darwinia.network`],webSocket:[`wss://koi-rpc.darwinia.network`]}},blockExplorers:{default:{name:`Blockscout`,url:`https://koi-scan.darwinia.network`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:180001}},testnet:!0}),DT=L({id:255,name:`Kroma`,nativeCurrency:{name:`ETH`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://api.kroma.network`]}},blockExplorers:{default:{name:`Kroma Explorer`,url:`https://blockscout.kroma.network`,apiUrl:`https://blockscout.kroma.network/api`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:16054868}},testnet:!1}),OT=L({id:2358,name:`Kroma Sepolia`,nativeCurrency:{name:`Sepolia Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://api.sepolia.kroma.network`]}},blockExplorers:{default:{name:`Kroma Sepolia Explorer`,url:`https://blockscout.sepolia.kroma.network`,apiUrl:`https://blockscout.sepolia.kroma.network/api`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:8900914}},testnet:!0}),kT=L({id:12324,name:`L3X Protocol`,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://rpc-mainnet.l3x.com`],webSocket:[`wss://rpc-mainnet.l3x.com`]}},blockExplorers:{default:{name:`L3X Mainnet Explorer`,url:`https://explorer.l3x.com`,apiUrl:`https://explorer.l3x.com/api/v2`}},testnet:!1}),AT=L({id:12325,name:`L3X Protocol Testnet`,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://rpc-testnet.l3x.com`],webSocket:[`wss://rpc-testnet.l3x.com`]}},blockExplorers:{default:{name:`L3X Testnet Explorer`,url:`https://explorer-testnet.l3x.com`,apiUrl:`https://explorer-testnet.l3x.com/api/v2`}},testnet:!0}),jT=L({id:360890,name:`LAVITA Mainnet`,nativeCurrency:{name:`vTFUEL`,symbol:`vTFUEL`,decimals:18},rpcUrls:{default:{http:[`https://tsub360890-eth-rpc.thetatoken.org/rpc`]}},blockExplorers:{default:{name:`LAVITA Explorer`,url:`https://tsub360890-explorer.thetatoken.org`}},testnet:!1}),MT=L({id:232,name:`Lens`,nativeCurrency:{name:`GHO`,symbol:`GHO`,decimals:18},rpcUrls:{default:{http:[`https://rpc.lens.xyz`]}},blockExplorers:{default:{name:`Lens Block Explorer`,url:`https://explorer.lens.xyz`,apiUrl:`https://explorer.lens.xyz/api`}}}),NT=L({id:37111,name:`Lens Testnet`,nativeCurrency:{name:`GRASS`,symbol:`GRASS`,decimals:18},rpcUrls:{default:{http:[`https://rpc.testnet.lens.dev`],webSocket:[`wss://rpc.testnet.lens.dev/ws`]}},blockExplorers:{default:{name:`Lens Block Explorer`,url:`https://block-explorer.testnet.lens.dev`,apiUrl:`https://block-explorer-api.staging.lens.dev/api`}},testnet:!0}),PT=L({id:21363,name:`Lestnet`,nativeCurrency:{name:`Lestnet Ether`,symbol:`LETH`,decimals:18},rpcUrls:{default:{http:[`https://service.lestnet.org`]}},blockExplorers:{default:{name:`Lestnet Explorer`,url:`https://explore.lestnet.org`}},testnet:!0}),FT=L({id:1891,name:`LightLink Pegasus Testnet`,network:`lightlink-pegasus`,nativeCurrency:{decimals:18,name:`Ether`,symbol:`ETH`},rpcUrls:{default:{http:[`https://replicator.pegasus.lightlink.io/rpc/v1`]}},blockExplorers:{default:{name:`LightLink Pegasus Explorer`,url:`https://pegasus.lightlink.io`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:127188532}},testnet:!0}),IT=L({id:1890,name:`LightLink Phoenix Mainnet`,network:`lightlink-phoenix`,nativeCurrency:{decimals:18,name:`Ether`,symbol:`ETH`},rpcUrls:{default:{http:[`https://replicator.phoenix.lightlink.io/rpc/v1`]}},blockExplorers:{default:{name:`LightLink Phoenix Explorer`,url:`https://phoenix.lightlink.io`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:125499184}},testnet:!1});ra(),A(),Fp(),Lu(),Wu(),$u();async function LT(e,t){let{account:n=e.account}=t;if(!n)throw new Om;let r=na(n);try{let{accessList:n,blockNumber:i,blockTag:a,data:o,gas:s,gasPrice:c,maxFeePerGas:l,maxPriorityFeePerGas:u,nonce:d,to:f,value:p,...m}=t,h=(typeof i==`bigint`?k(i):void 0)||a;Qu(t);let g=e.chain?.formatters?.transactionRequest?.format,_=(g||Bu)({...Iu(m,{format:g}),from:r?.address,accessList:n,data:o,gas:s,gasPrice:c,maxFeePerGas:l,maxPriorityFeePerGas:u,nonce:d,to:f,value:p},`estimateGas`),{baseFeePerGas:v,gasLimit:y,priorityFeePerGas:b}=await e.request({method:`linea_estimateGas`,params:h?[_,h]:[_]});return{baseFeePerGas:BigInt(v),gasLimit:BigInt(y),priorityFeePerGas:BigInt(b)}}catch(n){throw Pp(n,{...t,account:r,chain:e.chain})}}const RT={fees:{estimateFeesPerGas:zT,async maxPriorityFeePerGas({block:e,client:t,request:n}){let r=await zT({block:e,client:t,multiply:e=>e,request:n,type:`eip1559`});return r?.maxPriorityFeePerGas?r.maxPriorityFeePerGas:null}}};async function zT({client:e,multiply:t,request:n,type:r}){try{let i=await LT(e,{...n,account:n?.account}),{priorityFeePerGas:a}=i,o=t(BigInt(i.baseFeePerGas))+a;return r===`legacy`?{gasPrice:o}:{maxFeePerGas:o,maxPriorityFeePerGas:a}}catch{return null}}const BT=L({...RT,id:59144,name:`Linea Mainnet`,blockTime:2e3,nativeCurrency:{name:`Linea Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://rpc.linea.build`],webSocket:[`wss://rpc.linea.build`]}},blockExplorers:{default:{name:`Etherscan`,url:`https://lineascan.build`,apiUrl:`https://api.lineascan.build/api`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:42},ensRegistry:{address:`0x50130b669B28C339991d8676FA73CF122a121267`,blockCreated:6682888},ensUniversalResolver:{address:`0x4D41762915F83c76EcaF6776d9b08076aA32b492`,blockCreated:22222151}},ensTlds:[`.linea.eth`],testnet:!1}),VT=L({id:59140,name:`Linea Goerli Testnet`,nativeCurrency:{name:`Linea Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://rpc.goerli.linea.build`],webSocket:[`wss://rpc.goerli.linea.build`]}},blockExplorers:{default:{name:`Etherscan`,url:`https://goerli.lineascan.build`,apiUrl:`https://api-goerli.lineascan.build/api`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:498623}},testnet:!0}),HT=L({...RT,id:59141,name:`Linea Sepolia Testnet`,nativeCurrency:{name:`Linea Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://rpc.sepolia.linea.build`],webSocket:[`wss://rpc.sepolia.linea.build`]}},blockExplorers:{default:{name:`Etherscan`,url:`https://sepolia.lineascan.build`,apiUrl:`https://api-sepolia.lineascan.build/api`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:227427},ensRegistry:{address:`0x5B2636F0f2137B4aE722C01dd5122D7d3e9541f7`,blockCreated:2395094},ensUniversalResolver:{address:`0x4D41762915F83c76EcaF6776d9b08076aA32b492`,blockCreated:17168484}},ensTlds:[`.linea.eth`],testnet:!0}),UT=L({id:59140,name:`Linea Goerli Testnet`,nativeCurrency:{name:`Linea Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://rpc.goerli.linea.build`],webSocket:[`wss://rpc.goerli.linea.build`]}},blockExplorers:{default:{name:`Etherscan`,url:`https://goerli.lineascan.build`,apiUrl:`https://goerli.lineascan.build/api`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:498623}},testnet:!0});var WT=1;const GT=L({...R,id:1135,name:`Lisk`,network:`lisk`,nativeCurrency:{decimals:18,name:`Ether`,symbol:`ETH`},rpcUrls:{default:{http:[`https://rpc.api.lisk.com`]}},blockExplorers:{default:{name:`Blockscout`,url:`https://blockscout.lisk.com`,apiUrl:`https://blockscout.lisk.com/api`}},contracts:{...R.contracts,multicall3:{address:`0xA9d71E1dd7ca26F26e656E66d6AA81ed7f745bf0`},l2OutputOracle:{[WT]:{address:`0x113cB99283AF242Da0A0C54347667edF531Aa7d6`}},portal:{[WT]:{address:`0x26dB93F8b8b4f7016240af62F7730979d353f9A7`}},l1StandardBridge:{[WT]:{address:`0x2658723Bf70c7667De6B25F99fcce13A16D25d08`}}},sourceId:WT});var KT=11155111;const qT=L({...R,id:4202,network:`lisk-sepolia`,name:`Lisk Sepolia`,nativeCurrency:{name:`Sepolia Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://rpc.sepolia-api.lisk.com`]}},blockExplorers:{default:{name:`Blockscout`,url:`https://sepolia-blockscout.lisk.com`,apiUrl:`https://sepolia-blockscout.lisk.com/api`}},contracts:{...R.contracts,l2OutputOracle:{[KT]:{address:`0xA0E35F56C318DE1bD5D9ca6A94Fe7e37C5663348`}},multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`},portal:{[KT]:{address:`0xe3d90F21490686Ec7eF37BE788E02dfC12787264`}},l1StandardBridge:{[KT]:{address:`0x1Fb30e446eA791cd1f011675E5F3f5311b70faF5`}}},testnet:!0,sourceId:KT}),JT=L({id:9496,name:`Load Alphanet`,nativeCurrency:{name:`Testnet LOAD`,symbol:`tLOAD`,decimals:18},rpcUrls:{default:{http:[`https://alphanet.load.network`]}},blockExplorers:{default:{name:`Load Alphanet Explorer`,url:`https://explorer.load.network`}},testnet:!0}),YT=L({id:1337,name:`Localhost`,nativeCurrency:{decimals:18,name:`Ether`,symbol:`ETH`},rpcUrls:{default:{http:[`http://127.0.0.1:8545`]}}}),XT=L({id:15551,name:`LoopNetwork Mainnet`,nativeCurrency:{name:`LOOP`,symbol:`LOOP`,decimals:18},rpcUrls:{default:{http:[`https://api.mainnetloop.com`]}},blockExplorers:{default:{name:`LoopNetwork Blockchain Explorer`,url:`https://explorer.mainnetloop.com/`}},testnet:!1}),ZT=L({id:42,network:`lukso`,name:`LUKSO`,nativeCurrency:{name:`LUKSO`,symbol:`LYX`,decimals:18},rpcUrls:{default:{http:[`https://rpc.mainnet.lukso.network`],webSocket:[`wss://ws-rpc.mainnet.lukso.network`]}},blockExplorers:{default:{name:`LUKSO Mainnet Explorer`,url:`https://explorer.execution.mainnet.lukso.network`,apiUrl:`https://api.explorer.execution.mainnet.lukso.network/api`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:468183}}}),QT=L({id:4201,name:`LUKSO Testnet`,nativeCurrency:{decimals:18,name:`LUKSO Testnet`,symbol:`LYXt`},rpcUrls:{default:{http:[`https://rpc.testnet.lukso.network`],webSocket:[`wss://ws-rpc.testnet.lukso.network`]}},blockExplorers:{default:{name:`LUKSO Testnet Explorer`,url:`https://explorer.execution.testnet.lukso.network`,apiUrl:`https://api.explorer.execution.testnet.lukso.network/api`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:605348}},testnet:!0}),$T=L({id:994873017,name:`Lumia Mainnet`,network:`LumiaMainnet`,nativeCurrency:{name:`Lumia`,symbol:`LUMIA`,decimals:18},rpcUrls:{default:{http:[`https://mainnet-rpc.lumia.org`]}},blockExplorers:{default:{name:`Lumia Explorer`,url:`https://explorer.lumia.org/`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:3975939}},testnet:!1}),eE=L({id:1952959480,name:`Lumia Testnet`,network:`LumiaTestnet`,nativeCurrency:{name:`Lumia`,symbol:`LUMIA`,decimals:18},rpcUrls:{default:{http:[`https://testnet-rpc.lumia.org`]}},blockExplorers:{default:{name:`Lumia Testnet Explorer`,url:`https://testnet-explorer.lumia.org/`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:2235063}},testnet:!0}),tE=L({id:96370,name:`Lumoz`,nativeCurrency:{decimals:18,name:`Lumoz Token`,symbol:`MOZ`},rpcUrls:{default:{http:[`https://rpc.lumoz.org`]}},blockExplorers:{default:{name:`Lumoz Scan`,url:`https://scan.lumoz.info`}},testnet:!1}),nE=L({id:105363,name:`Lumoz Testnet`,nativeCurrency:{decimals:18,name:`Lumoz Testnet Token`,symbol:`MOZ`},rpcUrls:{default:{http:[`https://testnet-rpc.lumoz.org`]}},testnet:!0}),rE=L({id:721,name:`Lycan`,nativeCurrency:{decimals:18,name:`Lycan`,symbol:`LYC`},rpcUrls:{default:{http:[`https://rpc.lycanchain.com`,`https://us-east.lycanchain.com`,`https://us-west.lycanchain.com`,`https://eu-north.lycanchain.com`,`https://eu-west.lycanchain.com`,`https://asia-southeast.lycanchain.com`],webSocket:[`wss://rpc.lycanchain.com`,`wss://us-east.lycanchain.com`,`wss://us-west.lycanchain.com`,`wss://eu-north.lycanchain.com`,`wss://eu-west.lycanchain.com`,`wss://asia-southeast.lycanchain.com`]}},blockExplorers:{default:{name:`Lycan Explorer`,url:`https://explorer.lycanchain.com`}}}),iE=L({id:957,name:`Lyra Chain`,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://rpc.lyra.finance`]}},blockExplorers:{default:{name:`Lyra Explorer`,url:`https://explorer.lyra.finance`,apiUrl:`https://explorer.lyra.finance/api/v2`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:1935198}}}),aE=L({id:1,name:`Ethereum`,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},blockTime:12e3,rpcUrls:{default:{http:[`https://eth.merkle.io`]}},blockExplorers:{default:{name:`Etherscan`,url:`https://etherscan.io`,apiUrl:`https://api.etherscan.io/api`}},contracts:{ensUniversalResolver:{address:`0xeeeeeeee14d718c2b47d9923deab1335e144eeee`,blockCreated:23085558},multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:14353601}}}),oE=L({id:595,name:`Mandala TC9`,network:`mandala`,nativeCurrency:{name:`Mandala`,symbol:`mACA`,decimals:18},rpcUrls:{default:{http:[`https://eth-rpc-tc9.aca-staging.network`],webSocket:[`wss://eth-rpc-tc9.aca-staging.network`]}},blockExplorers:{default:{name:`Mandala Blockscout`,url:`https://blockscout.mandala.aca-staging.network`,apiUrl:`https://blockscout.mandala.aca-staging.network/api`}},testnet:!0}),sE=L({id:169,name:`Manta Pacific Mainnet`,network:`manta`,nativeCurrency:{decimals:18,name:`ETH`,symbol:`ETH`},rpcUrls:{default:{http:[`https://pacific-rpc.manta.network/http`]}},blockExplorers:{default:{name:`Manta Explorer`,url:`https://pacific-explorer.manta.network`,apiUrl:`https://pacific-explorer.manta.network/api`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:332890}}}),cE=L({id:3441006,name:`Manta Pacific Sepolia Testnet`,network:`manta-sepolia`,nativeCurrency:{decimals:18,name:`ETH`,symbol:`ETH`},rpcUrls:{default:{http:[`https://pacific-rpc.sepolia-testnet.manta.network/http`]}},blockExplorers:{default:{name:`Manta Sepolia Testnet Explorer`,url:`https://pacific-explorer.sepolia-testnet.manta.network`,apiUrl:`https://pacific-explorer.sepolia-testnet.manta.network/api`}},contracts:{multicall3:{address:`0xca54918f7B525C8df894668846506767412b53E3`,blockCreated:479584}},testnet:!0}),lE=L({id:3441005,name:`Manta Pacific Testnet`,network:`manta-testnet`,nativeCurrency:{decimals:18,name:`ETH`,symbol:`ETH`},rpcUrls:{default:{http:[`https://manta-testnet.calderachain.xyz/http`]}},blockExplorers:{default:{name:`Manta Testnet Explorer`,url:`https://pacific-explorer.testnet.manta.network`,apiUrl:`https://pacific-explorer.testnet.manta.network/api`}},contracts:{multicall3:{address:`0x211B1643b95Fe76f11eD8880EE810ABD9A4cf56C`,blockCreated:419915}},testnet:!0}),uE=L({id:5e3,name:`Mantle`,nativeCurrency:{decimals:18,name:`MNT`,symbol:`MNT`},rpcUrls:{default:{http:[`https://rpc.mantle.xyz`]}},blockExplorers:{default:{name:`Mantle Explorer`,url:`https://mantlescan.xyz/`,apiUrl:`https://api.mantlescan.xyz/api`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:304717}}}),dE=L({id:5003,name:`Mantle Sepolia Testnet`,nativeCurrency:{decimals:18,name:`MNT`,symbol:`MNT`},rpcUrls:{default:{http:[`https://rpc.sepolia.mantle.xyz`]}},blockExplorers:{default:{name:`Mantle Testnet Explorer`,url:`https://explorer.sepolia.mantle.xyz/`,apiUrl:`https://explorer.sepolia.mantle.xyz/api`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:4584012}},testnet:!0}),fE=L({id:5001,name:`Mantle Testnet`,nativeCurrency:{decimals:18,name:`MNT`,symbol:`MNT`},rpcUrls:{default:{http:[`https://rpc.testnet.mantle.xyz`]}},blockExplorers:{default:{name:`Mantle Testnet Explorer`,url:`https://explorer.testnet.mantle.xyz`,apiUrl:`https://explorer.testnet.mantle.xyz/api`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:561333}},testnet:!0}),pE=L({id:5887,name:`MANTRA DuKong EVM Testnet`,nativeCurrency:{decimals:18,name:`OM`,symbol:`OM`},rpcUrls:{default:{http:[`https://evm.dukong.mantrachain.io`]}},blockExplorers:{default:{name:`MANTRAScan`,url:`https://mantrascan.io/dukong`}},testnet:!0}),mE=L({id:5888,name:`MANTRA EVM`,nativeCurrency:{decimals:18,name:`OM`,symbol:`OM`},rpcUrls:{default:{http:[`https://evm.mantrachain.io`],webSocket:[`https://evm.mantrachain.io/ws`]}},blockExplorers:{default:{name:`MANTRA Scan`,url:`https://mantrascan.io/mainnet`}}}),hE=L({id:22776,name:`MAP Protocol`,nativeCurrency:{decimals:18,name:`MAPO`,symbol:`MAPO`},rpcUrls:{default:{http:[`https://rpc.maplabs.io`]}},blockExplorers:{default:{name:`MAPO Scan`,url:`https://maposcan.io`}},testnet:!1}),gE=L({id:698,name:`Matchain`,nativeCurrency:{name:`BNB`,symbol:`BNB`,decimals:18},rpcUrls:{default:{http:[`https://rpc.matchain.io`]}},blockExplorers:{default:{name:`Matchain Scan`,url:`https://matchscan.io`}}}),_E=L({id:699,name:`Matchain Testnet`,nativeCurrency:{name:`BNB`,symbol:`BNB`,decimals:18},rpcUrls:{default:{http:[`https://testnet-rpc.matchain.io`]}},blockExplorers:{default:{name:`Matchain Scan`,url:`https://testnet.matchscan.io`}},testnet:!0}),vE=L({id:29548,name:`MCH Verse`,nativeCurrency:{name:`Oasys`,symbol:`OAS`,decimals:18},rpcUrls:{default:{http:[`https://rpc.oasys.mycryptoheroes.net`]}},blockExplorers:{default:{name:`MCH Verse Explorer`,url:`https://explorer.oasys.mycryptoheroes.net`,apiUrl:`https://explorer.oasys.mycryptoheroes.net/api`}},testnet:!1}),yE=L({id:6342,blockTime:1e3,name:`MegaETH Testnet`,nativeCurrency:{name:`MegaETH Testnet Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://carrot.megaeth.com/rpc`],webSocket:[`wss://carrot.megaeth.com/ws`]}},blockExplorers:{default:{name:`MegaETH Testnet Explorer`,url:`https://www.megaexplorer.xyz/`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`}},testnet:!0}),bE=L({id:7078815900,name:`Mekong Pectra Devnet`,nativeCurrency:{name:`eth`,symbol:`eth`,decimals:18},rpcUrls:{default:{http:[`https://rpc.mekong.ethpandaops.io`]}},blockExplorers:{default:{name:`Block Explorer`,url:`https://explorer.mekong.ethpandaops.io`}},testnet:!0}),xE=L({id:333000333,name:`Meld`,nativeCurrency:{decimals:18,name:`Meld`,symbol:`MELD`},rpcUrls:{default:{http:[`https://rpc-1.meld.com`]}},blockExplorers:{default:{name:`MELDscan`,url:`https://meldscan.io`}},contracts:{multicall3:{address:`0x769ee5a8e82c15c1b6e358f62ac8eb6e3abe8dc5`,blockCreated:360069}}}),SE=L({id:4352,name:`MemeCore`,nativeCurrency:{decimals:18,name:`M`,symbol:`M`},rpcUrls:{default:{http:[`https://rpc.memecore.net`],webSocket:[`wss://ws.memecore.net`]}},blockExplorers:{default:{name:`MemeCore Explorer`,url:`https://memecorescan.io`,apiUrl:`https://api.memecorescan.io/api`},okx:{name:`MemeCore Explorer`,url:`https://web3.okx.com/explorer/memecore`},memecore:{name:`MemeCore Explorer`,url:`https://blockscout.memecore.com`,apiUrl:`https://blockscout.memecore.com/api`}}}),CE=L({id:43521,name:`Formicarium`,nativeCurrency:{decimals:18,name:`M`,symbol:`M`},rpcUrls:{default:{http:[`https://rpc.formicarium.memecore.net`],webSocket:[`wss://ws.formicarium.memecore.net`]}},blockExplorers:{default:{name:`MemeCore Testnet Explorer`,url:`https://formicarium.memecorescan.io`},okx:{name:`MemeCore Testnet Explorer`,url:`https://web3.okx.com/explorer/formicarium-testnet`},memecore:{name:`MemeCore Testnet Explorer`,url:`https://formicarium.blockscout.memecore.com`,apiUrl:`https://formicarium.blockscout.memecore.com/api`}},testnet:!0}),wE=L({id:4200,name:`Merlin`,nativeCurrency:{name:`BTC`,symbol:`BTC`,decimals:18},rpcUrls:{default:{http:[`https://rpc.merlinchain.io`]}},blockExplorers:{default:{name:`blockscout`,url:`https://scan.merlinchain.io`,apiUrl:`https://scan.merlinchain.io/api`}}}),TE=L({id:4203,name:`Merlin Erigon Testnet`,nativeCurrency:{name:`BTC`,symbol:`BTC`,decimals:18},rpcUrls:{default:{http:[`https://testnet-erigon-rpc.merlinchain.io`]}},blockExplorers:{default:{name:`blockscout`,url:`https://testnet-erigon-scan.merlinchain.io`,apiUrl:`https://testnet-erigon-scan.merlinchain.io/api`}},testnet:!0}),EE=L({id:571,name:`MetaChain Mainnet`,nativeCurrency:{name:`Metatime Coin`,symbol:`MTC`,decimals:18},rpcUrls:{default:{http:[`https://rpc.metatime.com`]}},blockExplorers:{default:{name:`MetaExplorer`,url:`https://explorer.metatime.com`}},contracts:{multicall3:{address:`0x0000000000000000000000000000000000003001`,blockCreated:0}}}),DE=L({id:1453,name:`MetaChain Istanbul`,nativeCurrency:{name:`Metatime Coin`,symbol:`MTC`,decimals:18},rpcUrls:{default:{http:[`https://istanbul-rpc.metachain.dev`]}},blockExplorers:{default:{name:`MetaExplorer`,url:`https://istanbul-explorer.metachain.dev`}},contracts:{multicall3:{address:`0x0000000000000000000000000000000000003001`,blockCreated:0}},testnet:!0}),OE=L({id:11,name:`Metadium Network`,nativeCurrency:{decimals:18,name:`META`,symbol:`META`},rpcUrls:{default:{http:[`https://api.metadium.com/prod`]}},blockExplorers:{default:{name:`Metadium Explorer`,url:`https://explorer.metadium.com`}},testnet:!1});var kE=1;const AE=L({...R,id:1750,name:`Metal L2`,nativeCurrency:{decimals:18,name:`Ether`,symbol:`ETH`},rpcUrls:{default:{http:[`https://rpc.metall2.com`],webSocket:[`wss://rpc.metall2.com`]}},blockExplorers:{default:{name:`Explorer`,url:`https://explorer.metall2.com`,apiUrl:`https://explorer.metall2.com/api`}},contracts:{...R.contracts,l2OutputOracle:{[kE]:{address:`0x3B1F7aDa0Fcc26B13515af752Dd07fB1CAc11426`}},multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:0},portal:{[kE]:{address:`0x3F37aBdE2C6b5B2ed6F8045787Df1ED1E3753956`}},l1StandardBridge:{[kE]:{address:`0x6d0f65D59b55B0FEC5d2d15365154DcADC140BF3`}}},sourceId:kE}),jE=L({id:82,name:`Meter`,nativeCurrency:{decimals:18,name:`MTR`,symbol:`MTR`},rpcUrls:{default:{http:[`https://rpc.meter.io`]}},blockExplorers:{default:{name:`MeterScan`,url:`https://scan.meter.io`}}}),ME=L({id:83,name:`Meter Testnet`,nativeCurrency:{decimals:18,name:`MTR`,symbol:`MTR`},rpcUrls:{default:{http:[`https://rpctest.meter.io`]}},blockExplorers:{default:{name:`MeterTestnetScan`,url:`https://scan-warringstakes.meter.io`}}}),NE=L({id:1088,name:`Metis`,nativeCurrency:{decimals:18,name:`Metis`,symbol:`METIS`},rpcUrls:{default:{http:[`https://metis.rpc.hypersync.xyz`,`https://metis-pokt.nodies.app`,`https://api.blockeden.xyz/metis/67nCBdZQSH9z3YqDDjdm`,`https://metis-andromeda.rpc.thirdweb.com`,`https://metis-andromeda.gateway.tenderly.co`,`https://metis.api.onfinality.io/public`,`https://andromeda.metis.io/?owner=1088`,`https://metis-mainnet.public.blastapi.io`],webSocket:[`wss://metis-rpc.publicnode.com`,`wss://metis.drpc.org`]}},blockExplorers:{default:{name:`Metis Explorer`,url:`https://explorer.metis.io`,apiUrl:`https://api.routescan.io/v2/network/mainnet/evm/1088/etherscan/api`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:2338552}}}),PE=L({id:599,name:`Metis Goerli`,nativeCurrency:{decimals:18,name:`Metis Goerli`,symbol:`METIS`},rpcUrls:{default:{http:[`https://goerli.gateway.metisdevops.link`]}},blockExplorers:{default:{name:`Metis Goerli Explorer`,url:`https://goerli.explorer.metisdevops.link`,apiUrl:`https://goerli.explorer.metisdevops.link/api`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:1006207}}}),FE=L({id:59902,name:`Metis Sepolia`,nativeCurrency:{decimals:18,name:`Test Metis`,symbol:`tMETIS`},rpcUrls:{default:{http:[`https://sepolia.metisdevops.link`,`https://metis-sepolia-rpc.publicnode.com`,`https://metis-sepolia.gateway.tenderly.co`],webSocket:[`wss://metis-sepolia-rpc.publicnode.com`]}},blockExplorers:{default:{name:`Metis Sepolia Explorer`,url:`https://sepolia-explorer.metisdevops.link`,apiUrl:`https://sepolia-explorer.metisdevops.link/api-docs`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:224185}}}),IE=L({id:7518,name:`MEVerse Chain Mainnet`,nativeCurrency:{decimals:18,name:`MEVerse`,symbol:`MEV`},rpcUrls:{default:{http:[`https://rpc.meversemainnet.io`]}},blockExplorers:{default:{name:`Explorer`,url:`https://www.meversescan.io`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:86881340}}}),LE=L({id:4759,name:`MEVerse Chain Testnet`,nativeCurrency:{decimals:18,name:`MEVerse`,symbol:`MEV`},rpcUrls:{default:{http:[`https://rpc.meversetestnet.io`]}},blockExplorers:{default:{name:`Explorer`,url:`https://testnet.meversescan.io/`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:64371115}},testnet:!0}),RE=L({id:185,name:`Mint Mainnet`,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://rpc.mintchain.io`]}},blockExplorers:{default:{name:`Mintchain explorer`,url:`https://explorer.mintchain.io`}},testnet:!1}),zE=L({id:1686,name:`Mint Sepolia Testnet`,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://testnet-rpc.mintchain.io`]}},blockExplorers:{default:{name:`Mintchain Testnet explorer`,url:`https://testnet-explorer.mintchain.io`}},testnet:!0}),BE=L({id:124832,name:`Mitosis Testnet`,nativeCurrency:{name:`MITO`,symbol:`MITO`,decimals:18},rpcUrls:{default:{http:[`https://rpc.testnet.mitosis.org`]}},blockExplorers:{default:{name:`Mitosis testnet explorer`,url:`https://testnet.mitosiscan.xyz`}},testnet:!0});var VE=1;const HE=L({...R,id:34443,name:`Mode Mainnet`,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://mainnet.mode.network`]}},blockExplorers:{default:{name:`Modescan`,url:`https://modescan.io`}},contracts:{...R.contracts,multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:2465882},l2OutputOracle:{[VE]:{address:`0x4317ba146D4933D889518a3e5E11Fe7a53199b04`}},portal:{[VE]:{address:`0x8B34b14c7c7123459Cf3076b8Cb929BE097d0C07`}},l1StandardBridge:{[VE]:{address:`0x735aDBbE72226BD52e818E7181953f42E3b0FF21`}}},sourceId:VE});var UE=11155111;const WE=L({...R,id:919,name:`Mode Testnet`,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://sepolia.mode.network`]}},blockExplorers:{default:{name:`Blockscout`,url:`https://sepolia.explorer.mode.network`,apiUrl:`https://sepolia.explorer.mode.network/api`}},contracts:{...R.contracts,l2OutputOracle:{[UE]:{address:`0x2634BD65ba27AB63811c74A63118ACb312701Bfa`,blockCreated:3778393}},portal:{[UE]:{address:`0x320e1580effF37E008F1C92700d1eBa47c1B23fD`,blockCreated:3778395}},l1StandardBridge:{[UE]:{address:`0xbC5C679879B2965296756CD959C3C739769995E2`,blockCreated:3778392}},multicall3:{address:`0xBAba8373113Fb7a68f195deF18732e01aF8eDfCF`,blockCreated:3019007}},testnet:!0,sourceId:UE}),GE=L({id:10143,name:`Monad Testnet`,blockTime:400,nativeCurrency:{name:`Testnet MON Token`,symbol:`MON`,decimals:18},rpcUrls:{default:{http:[`https://testnet-rpc.monad.xyz`]}},blockExplorers:{default:{name:`Monad Testnet explorer`,url:`https://testnet.monadexplorer.com`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:251449}},testnet:!0}),KE=L({id:1287,name:`Moonbase Alpha`,nativeCurrency:{decimals:18,name:`DEV`,symbol:`DEV`},rpcUrls:{default:{http:[`https://rpc.api.moonbase.moonbeam.network`],webSocket:[`wss://wss.api.moonbase.moonbeam.network`]}},blockExplorers:{default:{name:`Moonscan`,url:`https://moonbase.moonscan.io`,apiUrl:`https://moonbase.moonscan.io/api`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:1850686}},testnet:!0}),qE=L({id:1284,name:`Moonbeam`,nativeCurrency:{decimals:18,name:`GLMR`,symbol:`GLMR`},rpcUrls:{default:{http:[`https://moonbeam.public.blastapi.io`],webSocket:[`wss://moonbeam.public.blastapi.io`]}},blockExplorers:{default:{name:`Moonscan`,url:`https://moonscan.io`,apiUrl:`https://api-moonbeam.moonscan.io/api`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:609002}},testnet:!1}),JE=L({id:1281,name:`Moonbeam Development Node`,nativeCurrency:{decimals:18,name:`DEV`,symbol:`DEV`},rpcUrls:{default:{http:[`http://127.0.0.1:9944`],webSocket:[`wss://127.0.0.1:9944`]}}}),YE=L({id:1285,name:`Moonriver`,nativeCurrency:{decimals:18,name:`MOVR`,symbol:`MOVR`},rpcUrls:{default:{http:[`https://moonriver.public.blastapi.io`],webSocket:[`wss://moonriver.public.blastapi.io`]}},blockExplorers:{default:{name:`Moonscan`,url:`https://moonriver.moonscan.io`,apiUrl:`https://api-moonriver.moonscan.io/api`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:1597904}},testnet:!1}),XE=L({id:2818,name:`Morph`,nativeCurrency:{decimals:18,name:`Ether`,symbol:`ETH`},rpcUrls:{default:{http:[`https://rpc.morphl2.io`],webSocket:[`wss://rpc.morphl2.io:8443`]}},blockExplorers:{default:{name:`Morph Explorer`,url:`https://explorer.morphl2.io`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:3654913}},testnet:!1}),ZE=L({id:2810,name:`Morph Holesky`,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://rpc-quicknode-holesky.morphl2.io`],webSocket:[`wss://rpc-quicknode-holesky.morphl2.io`]}},blockExplorers:{default:{name:`Morph Holesky Explorer`,url:`https://explorer-holesky.morphl2.io`,apiUrl:`https://explorer-api-holesky.morphl2.io/api?`}},testnet:!0}),QE=L({id:2710,name:`Morph Sepolia`,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://rpc-testnet.morphl2.io`]}},blockExplorers:{default:{name:`Morph Testnet Explorer`,url:`https://explorer-testnet.morphl2.io`,apiUrl:`https://explorer-api-testnet.morphl2.io/api`}},testnet:!0}),$E=L({id:5551,name:`Nahmii 2 Mainnet`,nativeCurrency:{decimals:18,name:`ETH`,symbol:`ETH`},rpcUrls:{default:{http:[`https://l2.nahmii.io`]}},blockExplorers:{default:{name:`Nahmii 2 Explorer`,url:`https://explorer.n2.nahmii.io`}},testnet:!1}),eD=L({id:22222,name:`Nautilus Mainnet`,nativeCurrency:{name:`ZBC`,symbol:`ZBC`,decimals:9},rpcUrls:{default:{http:[`https://api.nautilus.nautchain.xyz`]}},blockExplorers:{default:{name:`NautScan`,url:`https://nautscan.com`}}}),tD=L({id:397,name:`NEAR Protocol`,nativeCurrency:{decimals:18,name:`NEAR`,symbol:`NEAR`},rpcUrls:{default:{http:[`https://eth-rpc.mainnet.near.org`]}},blockExplorers:{default:{name:`NEAR Explorer`,url:`https://eth-explorer.near.org`}},testnet:!1}),nD=L({id:398,name:`NEAR Protocol Testnet`,nativeCurrency:{decimals:18,name:`NEAR`,symbol:`NEAR`},rpcUrls:{default:{http:[`https://eth-rpc.testnet.near.org`]}},blockExplorers:{default:{name:`NEAR Explorer`,url:`https://eth-explorer-testnet.near.org`}},testnet:!0}),rD=L({id:245022926,name:`Neon EVM DevNet`,nativeCurrency:{name:`NEON`,symbol:`NEON`,decimals:18},rpcUrls:{default:{http:[`https://devnet.neonevm.org`]}},blockExplorers:{default:{name:`Neonscan`,url:`https://devnet.neonscan.org`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:205206112}},testnet:!0}),iD=L({id:245022934,network:`neonMainnet`,name:`Neon EVM MainNet`,nativeCurrency:{name:`NEON`,symbol:`NEON`,decimals:18},rpcUrls:{default:{http:[`https://neon-proxy-mainnet.solana.p2p.org`]}},blockExplorers:{default:{name:`Neonscan`,url:`https://neonscan.org`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:206545524}},testnet:!1}),aD=L({id:47763,name:`Neo X Mainnet`,nativeCurrency:{name:`Gas`,symbol:`GAS`,decimals:18},rpcUrls:{default:{http:[`https://mainnet-1.rpc.banelabs.org`,`https://mainnet-2.rpc.banelabs.org`]}},blockExplorers:{default:{name:`Neo X - Explorer`,url:`https://xexplorer.neo.org`}},testnet:!1}),oD=L({id:12227332,name:`Neo X Testnet T4`,nativeCurrency:{name:`Gas`,symbol:`GAS`,decimals:18},rpcUrls:{default:{http:[`https://testnet.rpc.banelabs.org/`]}},blockExplorers:{default:{name:`neox-scan`,url:`https://xt4scan.ngd.network`}},testnet:!0}),sD=L({id:1012,name:`Newton`,nativeCurrency:{name:`Newton`,symbol:`NEW`,decimals:18},rpcUrls:{default:{http:[`https://global.rpc.mainnet.newtonproject.org`]}},blockExplorers:{default:{name:`NewFi explorer`,url:`https://explorer.newtonproject.org/`}},testnet:!1}),cD=L({id:4242,name:`Nexi`,nativeCurrency:{name:`Nexi`,symbol:`NEXI`,decimals:18},rpcUrls:{default:{http:[`https://rpc.chain.nexi.technology`]}},blockExplorers:{default:{name:`NexiScan`,url:`https://www.nexiscan.com`,apiUrl:`https://www.nexiscan.com/api`}},contracts:{multicall3:{address:`0x0277A46Cc69A57eE3A6C8c158bA874832F718B8E`,blockCreated:25770160}}}),lD=L({id:240,name:`Nexilix Smart Chain`,nativeCurrency:{decimals:18,name:`Nexilix`,symbol:`NEXILIX`},rpcUrls:{default:{http:[`https://rpcurl.pos.nexilix.com`]}},blockExplorers:{default:{name:`NexilixScan`,url:`https://scan.nexilix.com`}},contracts:{multicall3:{address:`0x58381c8e2BF9d0C2C4259cA14BdA9Afe02831244`,blockCreated:74448}}}),uD=L({id:6900,name:`Nibiru`,nativeCurrency:{decimals:18,name:`NIBI`,symbol:`NIBI`},rpcUrls:{default:{http:[`https://evm-rpc.nibiru.fi`]}},blockExplorers:{default:{name:`NibiScan`,url:`https://nibiscan.io`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:19587573}}}),dD=L({id:200024,name:`Nitrograph Testnet`,testnet:!0,rpcUrls:{default:{http:[`https://rpc-testnet.nitrograph.foundation`]}},nativeCurrency:{name:`Nitro`,symbol:`NOS`,decimals:18},blockExplorers:{default:{url:`https://explorer-testnet.nitrograph.foundation`,name:`Nitrograph Explorer`}}}),fD=L({id:4090,network:`oasis-testnet`,name:`Oasis Testnet`,nativeCurrency:{name:`Fasttoken`,symbol:`FTN`,decimals:18},rpcUrls:{default:{http:[`https://rpc1.oasis.bahamutchain.com`]}},blockExplorers:{default:{name:`Ftnscan`,url:`https://oasis.ftnscan.com`,apiUrl:`https://oasis.ftnscan.com/api`}},testnet:!0}),pD=L({id:248,name:`Oasys`,nativeCurrency:{name:`Oasys`,symbol:`OAS`,decimals:18},rpcUrls:{default:{http:[`https://rpc.mainnet.oasys.games`]}},blockExplorers:{default:{name:`OasysScan`,url:`https://scan.oasys.games`,apiUrl:`https://scan.oasys.games/api`}}}),mD=L({id:911867,name:`Odyssey Testnet`,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://odyssey.ithaca.xyz`]}},blockExplorers:{default:{name:`Odyssey Explorer`,url:`https://odyssey-explorer.ithaca.xyz`,apiUrl:`https://odyssey-explorer.ithaca.xyz/api`}},testnet:!0}),hD=L({id:66,name:`OKC`,nativeCurrency:{decimals:18,name:`OKT`,symbol:`OKT`},rpcUrls:{default:{http:[`https://exchainrpc.okex.org`]}},blockExplorers:{default:{name:`oklink`,url:`https://www.oklink.com/okc`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:10364792}}}),gD=L({id:311,name:`Omax Mainnet`,nativeCurrency:{decimals:18,name:`OMAX`,symbol:`OMAX`},rpcUrls:{default:{http:[`https://mainapi.omaxray.com`]}},blockExplorers:{default:{name:`Omax Explorer`,url:`https://omaxscan.com`}},testnet:!1}),_D=L({id:166,name:`Omni`,nativeCurrency:{name:`Omni`,symbol:`OMNI`,decimals:18},rpcUrls:{default:{http:[`https://mainnet.omni.network`],webSocket:[`wss://mainnet.omni.network`]}},blockExplorers:{default:{name:`OmniScan`,url:`https://omniscan.network`}},testnet:!1}),vD=L({id:164,name:`Omni Omega`,nativeCurrency:{name:`Omni`,symbol:`OMNI`,decimals:18},rpcUrls:{default:{http:[`https://omega.omni.network`],webSocket:[`wss://omega.omni.network`]}},blockExplorers:{default:{name:`Omega OmniScan`,url:`https://omega.omniscan.network/`}},testnet:!0}),yD=L({id:309075,name:`One World Chain Mainnet`,nativeCurrency:{decimals:18,name:`OWCT`,symbol:`OWCT`},rpcUrls:{default:{http:[`https://mainnet-rpc.oneworldchain.org`]}},blockExplorers:{default:{name:`One World Explorer`,url:`https://mainnet.oneworldchain.org`}},testnet:!1}),bD=L({id:9700,name:`OORT MainnetDev`,nativeCurrency:{decimals:18,name:`OORT`,symbol:`OORT`},rpcUrls:{default:{http:[`https://dev-rpc.oortech.com`]}},blockExplorers:{default:{name:`OORT MainnetDev Explorer`,url:`https://dev-scan.oortech.com`}}});var xD=56;const SD=L({id:204,name:`opBNB`,nativeCurrency:{name:`BNB`,symbol:`BNB`,decimals:18},rpcUrls:{default:{http:[`https://opbnb-mainnet-rpc.bnbchain.org`]}},blockExplorers:{default:{name:`opBNB (BSCScan)`,url:`https://opbnb.bscscan.com`,apiUrl:`https://api-opbnb.bscscan.com/api`}},contracts:{...R.contracts,multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:512881},l2OutputOracle:{[xD]:{address:`0x153CAB79f4767E2ff862C94aa49573294B13D169`}},portal:{[xD]:{address:`0x1876EA7702C0ad0C6A2ae6036DE7733edfBca519`}},l1StandardBridge:{[xD]:{address:`0xF05F0e4362859c3331Cb9395CBC201E3Fa6757Ea`}}},sourceId:xD});var CD=97;const wD=L({id:5611,name:`opBNB Testnet`,nativeCurrency:{decimals:18,name:`tBNB`,symbol:`tBNB`},rpcUrls:{default:{http:[`https://opbnb-testnet-rpc.bnbchain.org`]}},blockExplorers:{default:{name:`opbnbscan`,url:`https://testnet.opbnbscan.com`}},contracts:{...R.contracts,multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:3705108},l2OutputOracle:{[CD]:{address:`0xFf2394Bb843012562f4349C6632a0EcB92fC8810`}},portal:{[CD]:{address:`0x4386C8ABf2009aC0c263462Da568DD9d46e52a31`}},l1StandardBridge:{[CD]:{address:`0x677311Fd2cCc511Bbc0f581E8d9a07B033D5E840`}}},testnet:!0,sourceId:CD}),TD=L({id:1612,name:`OpenLedger`,nativeCurrency:{name:`Open`,symbol:`OPEN`,decimals:18},rpcUrls:{default:{http:[`https://rpc.openledger.xyz`]}},blockExplorers:{default:{name:`OpenLedger Explorer`,url:`https://scan.openledger.xyz`}},testnet:!1});var ED=1;const DD=L({...R,id:10,name:`OP Mainnet`,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://mainnet.optimism.io`]}},blockExplorers:{default:{name:`Optimism Explorer`,url:`https://optimistic.etherscan.io`,apiUrl:`https://api-optimistic.etherscan.io/api`}},contracts:{...R.contracts,disputeGameFactory:{[ED]:{address:`0xe5965Ab5962eDc7477C8520243A95517CD252fA9`}},l2OutputOracle:{[ED]:{address:`0xdfe97868233d1aa22e815a266982f2cf17685a27`}},multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:4286263},portal:{[ED]:{address:`0xbEb5Fc579115071764c7423A4f12eDde41f106Ed`}},l1StandardBridge:{[ED]:{address:`0x99C9fc46f92E8a1c0deC1b1747d010903E884bE1`}}},sourceId:ED});var OD=5;const kD=L({...R,id:420,name:`Optimism Goerli`,nativeCurrency:{name:`Goerli Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://goerli.optimism.io`]}},blockExplorers:{default:{name:`Etherscan`,url:`https://goerli-optimism.etherscan.io`,apiUrl:`https://goerli-optimism.etherscan.io/api`}},contracts:{...R.contracts,l2OutputOracle:{[OD]:{address:`0xE6Dfba0953616Bacab0c9A8ecb3a9BBa77FC15c0`}},multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:49461},portal:{[OD]:{address:`0x5b47E1A08Ea6d985D6649300584e6722Ec4B1383`}},l1StandardBridge:{[OD]:{address:`0x636Af16bf2f682dD3109e60102b8E1A089FedAa8`}}},testnet:!0,sourceId:OD});var AD=11155111;const jD=L({...R,id:11155420,name:`OP Sepolia`,nativeCurrency:{name:`Sepolia Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://sepolia.optimism.io`]}},blockExplorers:{default:{name:`Blockscout`,url:`https://optimism-sepolia.blockscout.com`,apiUrl:`https://optimism-sepolia.blockscout.com/api`}},contracts:{...R.contracts,disputeGameFactory:{[AD]:{address:`0x05F9613aDB30026FFd634f38e5C4dFd30a197Fa1`}},l2OutputOracle:{[AD]:{address:`0x90E9c4f8a994a250F6aEfd61CAFb4F2e895D458F`}},multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:1620204},portal:{[AD]:{address:`0x16Fc5058F25648194471939df75CF27A2fdC48BC`}},l1StandardBridge:{[AD]:{address:`0xFBb0621E0B23b5478B630BD55a5f21f67730B0F1`}}},testnet:!0,sourceId:AD}),MD=L({id:62050,name:`Optopia`,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://rpc-mainnet.optopia.ai`]}},blockExplorers:{default:{name:`Optopia Explorer`,url:`https://scan.optopia.ai`}},testnet:!1}),ND=L({id:62049,name:`Optopia Testnet`,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://rpc-testnet.optopia.ai`]}},blockExplorers:{default:{name:`Optopia Explorer`,url:`https://scan-testnet.optopia.ai`}},testnet:!0}),PD=L({id:291,name:`Orderly`,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://rpc.orderly.network`]}},blockExplorers:{default:{name:`Orderly Explorer`,url:`https://explorer.orderly.network`}},testnet:!1}),FD=L({id:4460,name:`Orderly Sepolia`,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://l2-orderly-l2-4460-sepolia-8tc3sd7dvy.t.conduit.xyz`]}},blockExplorers:{default:{name:`Orderly Explorer`,url:`https://explorerl2new-orderly-l2-4460-sepolia-8tc3sd7dvy.t.conduit.xyz`}},testnet:!0}),ID=L({id:41144114,name:`Otim Devnet`,nativeCurrency:{decimals:18,name:`ETH`,symbol:`ETH`},rpcUrls:{default:{http:[`http://devnet.otim.xyz`]}},contracts:{batchInvoker:{address:`0x5FbDB2315678afecb367f032d93F642f64180aa3`}}}),LD=L({id:11297108109,name:`Palm`,nativeCurrency:{decimals:18,name:`PALM`,symbol:`PALM`},rpcUrls:{default:{http:[`https://palm-mainnet.public.blastapi.io`],webSocket:[`wss://palm-mainnet.public.blastapi.io`]}},blockExplorers:{default:{name:`Chainlens`,url:`https://palm.chainlens.com`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:15429248}}}),RD=L({id:11297108099,name:`Palm Testnet`,nativeCurrency:{decimals:18,name:`PALM`,symbol:`PALM`},rpcUrls:{default:{http:[`https://palm-mainnet.public.blastapi.io`],webSocket:[`wss://palm-mainnet.public.blastapi.io`]}},blockExplorers:{default:{name:`Chainlens`,url:`https://palm.chainlens.com`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:15429248}},testnet:!0}),zD=L({id:3338,name:`Peaq`,nativeCurrency:{decimals:18,name:`peaq`,symbol:`PEAQ`},rpcUrls:{default:{http:[`https://quicknode1.peaq.xyz`,`https://quicknode2.peaq.xyz`,`https://quicknode3.peaq.xyz`],webSocket:[`wss://quicknode1.peaq.xyz`,`wss://quicknode2.peaq.xyz`,`wss://quicknode3.peaq.xyz`]}},blockExplorers:{default:{name:`Subscan`,url:`https://peaq.subscan.io`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:3566354}}});var BD=1;const VD=L({id:424,network:`pgn`,name:`PGN`,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://rpc.publicgoods.network`]}},blockExplorers:{default:{name:`PGN Explorer`,url:`https://explorer.publicgoods.network`,apiUrl:`https://explorer.publicgoods.network/api`}},contracts:{l2OutputOracle:{[BD]:{address:`0x9E6204F750cD866b299594e2aC9eA824E2e5f95c`}},multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:3380209},portal:{[BD]:{address:`0xb26Fd985c5959bBB382BAFdD0b879E149e48116c`}},l1StandardBridge:{[BD]:{address:`0xD0204B9527C1bA7bD765Fa5CCD9355d38338272b`}}},formatters:yy,sourceId:BD});var HD=11155111;const UD=L({id:58008,network:`pgn-testnet`,name:`PGN `,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://sepolia.publicgoods.network`]}},blockExplorers:{default:{name:`PGN Testnet Explorer`,url:`https://explorer.sepolia.publicgoods.network`,apiUrl:`https://explorer.sepolia.publicgoods.network/api`}},contracts:{l2OutputOracle:{[HD]:{address:`0xD5bAc3152ffC25318F848B3DD5dA6C85171BaEEe`}},portal:{[HD]:{address:`0xF04BdD5353Bb0EFF6CA60CfcC78594278eBfE179`}},l1StandardBridge:{[HD]:{address:`0xFaE6abCAF30D23e233AC7faF747F2fC3a5a6Bfa3`}},multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:3754925}},formatters:yy,sourceId:HD,testnet:!0}),WD=L({id:13381,name:`Phoenix Blockchain`,nativeCurrency:{name:`Phoenix`,symbol:`PHX`,decimals:18},rpcUrls:{default:{http:[`https://rpc.phoenixplorer.com`]}},blockExplorers:{default:{name:`Phoenixplorer`,url:`https://phoenixplorer.com`,apiUrl:`https://phoenixplorer.com/api`}},contracts:{multicall3:{address:`0x498cF757a575cFF2c2Ed9f532f56Efa797f86442`,blockCreated:5620192}}}),GD=L({id:7070,name:`Planq Mainnet`,nativeCurrency:{decimals:18,name:`PLQ`,symbol:`PLQ`},rpcUrls:{default:{http:[`https://planq-rpc.nodies.app`,`https://evm-rpc.planq.network`,`https://jsonrpc.planq.nodestake.top`]}},blockExplorers:{default:{name:`Planq Explorer`,url:`https://evm.planq.network`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:8470015}},testnet:!1}),KD=L({id:9745,name:`Plasma`,blockTime:1e3,nativeCurrency:{name:`Plasma`,symbol:`XPL`,decimals:18},rpcUrls:{default:{http:[`https://rpc.plasma.to`]}},blockExplorers:{default:{name:`PlasmaScan`,url:`https://plasmascan.to`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:0}}}),qD=L({id:9747,name:`Plasma Devnet`,nativeCurrency:{name:`Devnet Plasma`,symbol:`XPL`,decimals:18},rpcUrls:{default:{http:[`https://devnet-rpc.plasma.to`]}},testnet:!0,contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:0}}}),JD=L({id:9746,name:`Plasma Testnet`,nativeCurrency:{name:`Testnet Plasma`,symbol:`XPL`,decimals:18},rpcUrls:{default:{http:[`https://testnet-rpc.plasma.to`]}},blockExplorers:{default:{name:`RouteScan`,url:`https://testnet.plasmascan.to`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:0}},testnet:!0}),YD=L({...oy,id:1612127,name:`PlayFi Albireo Testnet`,network:`albireo`,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://albireo-rpc.playfi.ai`],webSocket:[`wss://albireo-rpc-ws.playfi.ai/ws`]}},blockExplorers:{default:{name:`PlayFi Albireo Explorer`,url:`https://albireo-explorer.playfi.ai`}},contracts:{multicall3:{address:`0xF9cda624FBC7e059355ce98a31693d299FACd963`}},testnet:!0}),XD=L({id:242,name:`Plinga`,nativeCurrency:{name:`Plinga`,symbol:`PLINGA`,decimals:18},rpcUrls:{default:{http:[`https://rpcurl.mainnet.plgchain.com`]}},blockExplorers:{default:{name:`Plgscan`,url:`https://www.plgscan.com`}},contracts:{multicall3:{address:`0x0989576160f2e7092908BB9479631b901060b6e4`,blockCreated:204489}}}),ZD=L({id:98865,name:`Plume (Legacy)`,nativeCurrency:{name:`Plume Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://rpc.plumenetwork.xyz`],webSocket:[`wss://rpc.plumenetwork.xyz`]}},blockExplorers:{default:{name:`Blockscout`,url:`https://explorer.plumenetwork.xyz`,apiUrl:`https://explorer.plumenetwork.xyz/api`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:48577}},sourceId:1}),QD=L({id:98864,name:`Plume Devnet (Legacy)`,nativeCurrency:{name:`Plume Sepolia Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://test-rpc.plumenetwork.xyz`],webSocket:[`wss://test-rpc.plumenetwork.xyz`]}},blockExplorers:{default:{name:`Blockscout`,url:`https://test-explorer.plumenetwork.xyz`,apiUrl:`https://test-explorer.plumenetwork.xyz/api`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:481948}},testnet:!0,sourceId:11155111}),$D=L({id:98866,name:`Plume`,nativeCurrency:{name:`Plume`,symbol:`PLUME`,decimals:18},rpcUrls:{default:{http:[`https://rpc.plume.org`],webSocket:[`wss://rpc.plume.org`]}},blockExplorers:{default:{name:`Blockscout`,url:`https://explorer.plume.org`,apiUrl:`https://explorer.plume.org/api`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:39679}},sourceId:1}),eO=L({id:98867,name:`Plume Testnet`,nativeCurrency:{name:`Plume`,symbol:`PLUME`,decimals:18},rpcUrls:{default:{http:[`https://testnet-rpc.plume.org`],webSocket:[`wss://testnet-rpc.plume.org`]}},blockExplorers:{default:{name:`Blockscout`,url:`https://testnet-explorer.plume.org`,apiUrl:`https://testnet-explorer.plume.org/api`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:199712}},testnet:!0,sourceId:11155111}),tO=L({id:161221135,name:`Plume Testnet (Legacy)`,nativeCurrency:{name:`Plume Sepolia Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://testnet-rpc.plumenetwork.xyz/http`],webSocket:[`wss://testnet-rpc.plumenetwork.xyz/ws`]}},blockExplorers:{default:{name:`Blockscout`,url:`https://testnet-explorer.plumenetwork.xyz`,apiUrl:`https://testnet-explorer.plumenetwork.xyz/api`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:6022332}},testnet:!0,sourceId:11155111}),nO=L({id:631571,name:`Polter Testnet`,nativeCurrency:{decimals:18,name:`Polter GHST`,symbol:`GHST`},rpcUrls:{default:{http:[`https://geist-polter.g.alchemy.com/public`]}},blockExplorers:{default:{name:`Blockscout`,url:`https://polter-testnet.explorer.alchemy.com`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:11245}},testnet:!0}),rO=L({id:137,name:`Polygon`,blockTime:2e3,nativeCurrency:{name:`POL`,symbol:`POL`,decimals:18},rpcUrls:{default:{http:[`https://polygon-rpc.com`]}},blockExplorers:{default:{name:`PolygonScan`,url:`https://polygonscan.com`,apiUrl:`https://api.polygonscan.com/api`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:25770160}}}),iO=L({id:80002,name:`Polygon Amoy`,nativeCurrency:{name:`POL`,symbol:`POL`,decimals:18},rpcUrls:{default:{http:[`https://rpc-amoy.polygon.technology`]}},blockExplorers:{default:{name:`PolygonScan`,url:`https://amoy.polygonscan.com`,apiUrl:`https://api-amoy.polygonscan.com/api`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:3127388}},testnet:!0}),aO=L({id:80001,name:`Polygon Mumbai`,nativeCurrency:{name:`MATIC`,symbol:`MATIC`,decimals:18},rpcUrls:{default:{http:[`https://80001.rpc.thirdweb.com`]}},blockExplorers:{default:{name:`PolygonScan`,url:`https://mumbai.polygonscan.com`,apiUrl:`https://api-testnet.polygonscan.com/api`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:25770160}},testnet:!0}),oO=L({id:1101,name:`Polygon zkEVM`,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://zkevm-rpc.com`]}},blockExplorers:{default:{name:`PolygonScan`,url:`https://zkevm.polygonscan.com`,apiUrl:`https://api-zkevm.polygonscan.com/api`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:57746}}}),sO=L({id:2442,name:`Polygon zkEVM Cardona`,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://rpc.cardona.zkevm-rpc.com`]}},blockExplorers:{default:{name:`PolygonScan`,url:`https://cardona-zkevm.polygonscan.com`,apiUrl:`https://cardona-zkevm.polygonscan.com/api`}},testnet:!0,contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:114091}}}),cO=L({id:1442,name:`Polygon zkEVM Testnet`,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://rpc.public.zkevm-test.net`]}},blockExplorers:{default:{name:`PolygonScan`,url:`https://testnet-zkevm.polygonscan.com`,apiUrl:`https://testnet-zkevm.polygonscan.com/api`}},testnet:!0,contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:525686}}}),lO=L({id:8008,name:`Polynomial`,nativeCurrency:{decimals:18,name:`Ether`,symbol:`ETH`},rpcUrls:{default:{http:[`https://rpc.polynomial.fi`]}},blockExplorers:{default:{name:`Polynomial Scan`,url:`https://polynomialscan.io`}},testnet:!1,contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`}}}),uO=L({id:80008,name:`Polynomia Sepolia`,nativeCurrency:{decimals:18,name:`Ether`,symbol:`ETH`},rpcUrls:{default:{http:[`https://rpc.sepolia.polynomial.fi`]}},blockExplorers:{default:{name:`Polynomial Scan`,url:`https://sepolia.polynomialscan.io`}},testnet:!0,contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`}}}),dO=L({id:23023,name:`PremiumBlock Testnet`,nativeCurrency:{name:`Premium Block`,symbol:`PBLK`,decimals:18},rpcUrls:{default:{http:[`https://rpc.premiumblock.org`]}},blockExplorers:{default:{name:`PremiumBlocks Explorer`,url:`https://scan.premiumblock.org`}},testnet:!0}),fO=L({id:369,name:`PulseChain`,nativeCurrency:{name:`Pulse`,symbol:`PLS`,decimals:18},testnet:!1,blockTime:1e4,rpcUrls:{default:{http:[`https://rpc.pulsechain.com`],webSocket:[`wss://ws.pulsechain.com`]}},blockExplorers:{default:{name:`PulseScan`,url:`https://ipfs.scan.pulsechain.com`,apiUrl:`https://api.scan.pulsechain.com/api`}},contracts:{ensRegistry:{address:`0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e`},multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:14353601}}}),pO=L({id:943,name:`PulseChain V4`,testnet:!0,nativeCurrency:{name:`V4 Pulse`,symbol:`v4PLS`,decimals:18},blockTime:1e4,rpcUrls:{default:{http:[`https://rpc.v4.testnet.pulsechain.com`],webSocket:[`wss://ws.v4.testnet.pulsechain.com`]}},blockExplorers:{default:{name:`PulseScan`,url:`https://scan.v4.testnet.pulsechain.com`,apiUrl:`https://scan.v4.testnet.pulsechain.com/api`}},contracts:{ensRegistry:{address:`0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e`},multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:14353601}}}),mO=L({id:490092,name:`Pumpfi Testnet`,nativeCurrency:{decimals:18,name:`PMPT`,symbol:`PMPT`},rpcUrls:{default:{http:[`https://rpc1testnet.pumpfi.me`]}},blockExplorers:{default:{name:`Pumpfi Testnet Scan`,url:`https://testnetscan.pumpfi.me`}},testnet:!0});var hO=11155111;const gO=L({...R,name:`Pyrope Testnet`,testnet:!0,id:695569,sourceId:hO,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://rpc.pyropechain.com`],webSocket:[`wss://rpc.pyropechain.com`]}},blockExplorers:{default:{name:`Blockscout`,url:`https://pyrope.blockscout.com`}},contracts:{...R.contracts,l1StandardBridge:{[hO]:{address:`0xC24932c31D9621aE9e792576152B7ef010cFC2F8`}}}}),_O=L({id:766,name:`QL1`,nativeCurrency:{decimals:18,name:`QOM`,symbol:`QOM`},rpcUrls:{default:{http:[`https://rpc.qom.one`]}},blockExplorers:{default:{name:`Ql1 Explorer`,url:`https://scan.qom.one`}},contracts:{multicall3:{address:`0x7A52370716ea730585884F5BDB0f6E60C39b8C64`}},testnet:!1}),vO=L({id:35441,name:`Q Mainnet`,nativeCurrency:{decimals:18,name:`Q`,symbol:`Q`},rpcUrls:{default:{http:[`https://rpc.q.org`]}},blockExplorers:{default:{name:`Q Mainnet Explorer`,url:`https://explorer.q.org`,apiUrl:`https://explorer.q.org/api`}}}),yO=L({id:35443,name:`Q Testnet`,nativeCurrency:{decimals:18,name:`Q`,symbol:`Q`},rpcUrls:{default:{http:[`https://rpc.qtestnet.org`]}},blockExplorers:{default:{name:`Q Testnet Explorer`,url:`https://explorer.qtestnet.org`,apiUrl:`https://explorer.qtestnet.org/api`}},testnet:!0}),bO=L({id:111188,name:`re.al`,nativeCurrency:{name:`reETH`,decimals:18,symbol:`reETH`},rpcUrls:{default:{http:[`https://rpc.realforreal.gelato.digital`]}},blockExplorers:{default:{name:`re.al Explorer`,url:`https://explorer.re.al`,apiUrl:`https://explorer.re.al/api/v2`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:695}}}),xO=L({id:151,name:`Redbelly Network Mainnet`,nativeCurrency:{name:`Redbelly Native Coin`,symbol:`RBNT`,decimals:18},rpcUrls:{default:{http:[`https://governors.mainnet.redbelly.network`]}},blockExplorers:{default:{name:`Routescan`,url:`https://redbelly.routescan.io`,apiUrl:`https://api.routescan.io/v2/network/mainnet/evm/151/etherscan/api`}},testnet:!1}),SO=L({id:153,name:`Redbelly Network Testnet`,nativeCurrency:{name:`Redbelly Native Coin`,symbol:`RBNT`,decimals:18},rpcUrls:{default:{http:[`https://governors.testnet.redbelly.network`]}},blockExplorers:{default:{name:`Routescan`,url:`https://redbelly.testnet.routescan.io`,apiUrl:`https://api.routescan.io/v2/network/testnet/evm/153_2/etherscan/api`}},testnet:!0}),CO=L({id:50342,name:`Reddio`,nativeCurrency:{name:`Reddio`,symbol:`RED`,decimals:18},rpcUrls:{default:{http:[`https://mainnet.reddio.com/rpc`]}},blockExplorers:{default:{name:`Blockscout`,url:`https://reddio.cloud.blockscout.com`,apiUrl:`https://reddio.cloud.blockscout.com/api`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:848849}},testnet:!1}),wO=L({id:50341,name:`Reddio Sepolia`,nativeCurrency:{name:`Reddio`,symbol:`RED`,decimals:18},rpcUrls:{default:{http:[`https://reddio-dev.reddio.com`]}},blockExplorers:{default:{name:`Reddioscan`,url:`https://reddio-devnet.l2scan.co`,apiUrl:`https://reddio-devnet.l2scan.co/api`}},testnet:!0});var TO=1;const EO=L({...R,name:`Redstone`,id:690,sourceId:TO,nativeCurrency:{decimals:18,name:`Ether`,symbol:`ETH`},rpcUrls:{default:{http:[`https://rpc.redstonechain.com`],webSocket:[`wss://rpc.redstonechain.com`]}},blockExplorers:{default:{name:`Blockscout`,url:`https://explorer.redstone.xyz`}},contracts:{...R.contracts,multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`},portal:{[TO]:{address:`0xC7bCb0e8839a28A1cFadd1CF716de9016CdA51ae`,blockCreated:19578329}},l2OutputOracle:{[TO]:{address:`0xa426A052f657AEEefc298b3B5c35a470e4739d69`,blockCreated:19578337}},l1StandardBridge:{[TO]:{address:`0xc473ca7E02af24c129c2eEf51F2aDf0411c1Df69`,blockCreated:19578331}}}}),DO=L({id:47805,name:`REI Mainnet`,nativeCurrency:{decimals:18,name:`REI`,symbol:`REI`},rpcUrls:{default:{http:[`https://rpc.rei.network`],webSocket:[`wss://rpc.rei.network`]}},blockExplorers:{default:{name:`REI Scan`,url:`https://scan.rei.network`}},testnet:!1}),OO=L({id:1729,name:`Reya Network`,nativeCurrency:{decimals:18,name:`Ether`,symbol:`ETH`},rpcUrls:{default:{http:[`https://rpc.reya.network`],webSocket:[`wss://ws.reya.network`]}},blockExplorers:{default:{name:`Reya Network Explorer`,url:`https://explorer.reya.network`}},testnet:!1}),kO=L({id:11155931,name:`RISE Testnet`,nativeCurrency:{name:`RISE Testnet Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://testnet.riselabs.xyz`],webSocket:[`wss://testnet.riselabs.xyz/ws`]}},blockExplorers:{default:{name:`Blockscout`,url:`https://explorer.testnet.riselabs.xyz/`,apiUrl:`https://explorer.testnet.riselabs.xyz/api`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`}},testnet:!0}),AO=L({id:753,name:`Rivalz`,nativeCurrency:{decimals:18,name:`Ether`,symbol:`ETH`},rpcUrls:{default:{http:[`https://rivalz.calderachain.xyz/http`]}},blockExplorers:{default:{name:`Rivalz Caldera Explorer`,url:`https://rivalz.calderaexplorer.xyz`}},testnet:!1}),jO=L({id:570,name:`Rollux Mainnet`,nativeCurrency:{decimals:18,name:`Syscoin`,symbol:`SYS`},rpcUrls:{default:{http:[`https://rpc.rollux.com`],webSocket:[`wss://rpc.rollux.com/wss`]}},blockExplorers:{default:{name:`RolluxExplorer`,url:`https://explorer.rollux.com`,apiUrl:`https://explorer.rollux.com/api`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:119222}}}),MO=L({id:57e3,name:`Rollux Testnet`,nativeCurrency:{decimals:18,name:`Syscoin`,symbol:`SYS`},rpcUrls:{default:{http:[`https://rpc-tanenbaum.rollux.com/`],webSocket:[`wss://rpc-tanenbaum.rollux.com/wss`]}},blockExplorers:{default:{name:`RolluxTestnetExplorer`,url:`https://rollux.tanenbaum.io`,apiUrl:`https://rollux.tanenbaum.io/api`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:1813675}}}),NO=L({id:2020,name:`Ronin`,nativeCurrency:{name:`RON`,symbol:`RON`,decimals:18},rpcUrls:{default:{http:[`https://api.roninchain.com/rpc`]}},blockExplorers:{default:{name:`Ronin Explorer`,url:`https://app.roninchain.com`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:26023535}}}),PO=L({id:7668,name:`The Root Network`,nativeCurrency:{decimals:18,name:`XRP`,symbol:`XRP`},rpcUrls:{default:{http:[`https://root.rootnet.live/archive`],webSocket:[`wss://root.rootnet.live/archive/ws`]}},blockExplorers:{default:{name:`Rootscan`,url:`https://rootscan.io`}},contracts:{multicall3:{address:`0xc9C2E2429AeC354916c476B30d729deDdC94988d`,blockCreated:9218338}}}),FO=L({id:7672,name:`The Root Network - Porcini`,nativeCurrency:{decimals:18,name:`XRP`,symbol:`XRP`},rpcUrls:{default:{http:[`https://porcini.rootnet.app/archive`],webSocket:[`wss://porcini.rootnet.app/archive/ws`]}},blockExplorers:{default:{name:`Rootscan`,url:`https://porcini.rootscan.io`}},contracts:{multicall3:{address:`0xc9C2E2429AeC354916c476B30d729deDdC94988d`,blockCreated:10555692}},testnet:!0}),IO=L({id:30,name:`Rootstock Mainnet`,network:`rootstock`,nativeCurrency:{decimals:18,name:`Rootstock Bitcoin`,symbol:`RBTC`},rpcUrls:{default:{http:[`https://public-node.rsk.co`]}},blockExplorers:{default:{name:`RSK Explorer`,url:`https://explorer.rsk.co`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:4249540}}}),LO=L({id:31,name:`Rootstock Testnet`,network:`rootstock`,nativeCurrency:{decimals:18,name:`Rootstock Bitcoin`,symbol:`tRBTC`},rpcUrls:{default:{http:[`https://public-node.testnet.rsk.co`]}},blockExplorers:{default:{name:`RSK Explorer`,url:`https://explorer.testnet.rootstock.io`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:2771150}},testnet:!0});var RO=1;const zO=L({...R,id:12553,name:`RSS3 VSL Mainnet`,nativeCurrency:{name:`RSS3`,symbol:`RSS3`,decimals:18},rpcUrls:{default:{http:[`https://rpc.rss3.io`]}},blockExplorers:{default:{name:`RSS3 VSL Mainnet Scan`,url:`https://scan.rss3.io`,apiUrl:`https://scan.rss3.io/api`}},contracts:{...R.contracts,l2OutputOracle:{[RO]:{address:`0xE6f24d2C32B3109B18ed33cF08eFb490b1e09C10`}},multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:14193},portal:{[RO]:{address:`0x6A12432491bbbE8d3babf75F759766774C778Db4`,blockCreated:19387057}},l1StandardBridge:{[RO]:{address:`0x4cbab69108Aa72151EDa5A3c164eA86845f18438`}}},sourceId:RO});var BO=11155111;const VO=L({...R,id:2331,name:`RSS3 VSL Sepolia Testnet`,nativeCurrency:{name:`RSS3`,symbol:`RSS3`,decimals:18},rpcUrls:{default:{http:[`https://rpc.testnet.rss3.io`]}},blockExplorers:{default:{name:`RSS3 VSL Sepolia Testnet Scan`,url:`https://scan.testnet.rss3.io`,apiUrl:`https://scan.testnet.rss3.io/api`}},contracts:{...R.contracts,l2OutputOracle:{[BO]:{address:`0xDb5c46C3Eaa6Ed6aE8b2379785DF7dd029C0dC81`}},multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:55697},portal:{[BO]:{address:`0xcBD77E8E1E7F06B25baDe67142cdE82652Da7b57`,blockCreated:5345035}},l1StandardBridge:{[BO]:{address:`0xdDD29bb63B0839FB1cE0eE439Ff027738595D07B`}}},testnet:!0,sourceId:BO}),HO=L({id:7225878,name:`Saakuru Mainnet`,nativeCurrency:{name:`OAS`,symbol:`OAS`,decimals:18},rpcUrls:{default:{http:[`https://rpc.saakuru.network`]}},blockExplorers:{default:{name:`Saakuru Explorer`,url:`https://explorer.saakuru.network`}},testnet:!1}),UO=L({id:5464,name:`Saga`,network:`saga`,nativeCurrency:{decimals:18,name:`gas`,symbol:`GAS`},rpcUrls:{default:{http:[`https://sagaevm.jsonrpc.sagarpc.io`]}},blockExplorers:{default:{name:`Saga Explorer`,url:`https://sagaevm.sagaexplorer.io`}},contracts:{multicall3:{address:`0x864DDc9B50B9A0dF676d826c9B9EDe9F8913a160`,blockCreated:467530}}}),WO=L({id:2021,name:`Saigon Testnet`,nativeCurrency:{name:`RON`,symbol:`RON`,decimals:18},rpcUrls:{default:{http:[`https://saigon-testnet.roninchain.com/rpc`]}},blockExplorers:{default:{name:`Saigon Explorer`,url:`https://saigon-app.roninchain.com`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:18736871}},testnet:!0}),GO=L({id:1996,name:`Sanko`,nativeCurrency:{name:`DMT`,symbol:`DMT`,decimals:18},rpcUrls:{default:{http:[`https://mainnet.sanko.xyz`]}},blockExplorers:{default:{name:`Sanko Explorer`,url:`https://explorer.sanko.xyz`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:37}},testnet:!1}),KO=L({id:23294,name:`Oasis Sapphire`,network:`sapphire`,nativeCurrency:{name:`Sapphire Rose`,symbol:`ROSE`,decimals:18},rpcUrls:{default:{http:[`https://sapphire.oasis.io`],webSocket:[`wss://sapphire.oasis.io/ws`]}},blockExplorers:{default:{name:`Oasis Explorer`,url:`https://explorer.oasis.io/mainnet/sapphire`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:734531}}}),qO=L({id:23295,name:`Oasis Sapphire Testnet`,network:`sapphire-testnet`,nativeCurrency:{name:`Sapphire Test Rose`,symbol:`TEST`,decimals:18},rpcUrls:{default:{http:[`https://testnet.sapphire.oasis.dev`],webSocket:[`wss://testnet.sapphire.oasis.dev/ws`]}},blockExplorers:{default:{name:`Oasis Explorer`,url:`https://explorer.oasis.io/testnet/sapphire`}},testnet:!0}),JO=L({id:3109,name:`SatoshiVM Alpha Mainnet`,nativeCurrency:{name:`BTC`,symbol:`BTC`,decimals:18},rpcUrls:{default:{http:[`https://alpha-rpc-node-http.svmscan.io`]}},blockExplorers:{default:{name:`blockscout`,url:`https://svmscan.io`,apiUrl:`https://svmscan.io/api`}}}),YO=L({id:3110,name:`SatoshiVM Testnet`,nativeCurrency:{name:`BTC`,symbol:`BTC`,decimals:18},rpcUrls:{default:{http:[`https://test-rpc-node-http.svmscan.io`]}},blockExplorers:{default:{name:`blockscout`,url:`https://testnet.svmscan.io`,apiUrl:`https://testnet.svmscan.io/api`}},testnet:!0}),XO=L({id:534352,name:`Scroll`,blockTime:3e3,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://rpc.scroll.io`],webSocket:[`wss://wss-rpc.scroll.io/ws`]}},blockExplorers:{default:{name:`Scrollscan`,url:`https://scrollscan.com`,apiUrl:`https://api.scrollscan.com/api`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:14}},testnet:!1}),ZO=L({id:534351,name:`Scroll Sepolia`,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://sepolia-rpc.scroll.io`]}},blockExplorers:{default:{name:`Scrollscan`,url:`https://sepolia.scrollscan.com`,apiUrl:`https://api-sepolia.scrollscan.com/api`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:9473}},testnet:!0}),QO=L({id:1329,name:`Sei Network`,nativeCurrency:{name:`Sei`,symbol:`SEI`,decimals:18},rpcUrls:{default:{http:[`https://evm-rpc.sei-apis.com/`],webSocket:[`wss://evm-ws.sei-apis.com/`]}},blockExplorers:{default:{name:`Seitrace`,url:`https://seitrace.com`,apiUrl:`https://seitrace.com/pacific-1/api`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`}}}),$O=L({id:713715,name:`Sei Devnet`,nativeCurrency:{name:`Sei`,symbol:`SEI`,decimals:18},rpcUrls:{default:{http:[`https://evm-rpc-arctic-1.sei-apis.com`]}},blockExplorers:{default:{name:`Seitrace`,url:`https://seitrace.com`}},testnet:!0}),ek=L({id:5124,name:`Seismic Devnet`,nativeCurrency:{name:`Seismic Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://node-2.seismicdev.net/rpc`]}},blockExplorers:{default:{name:`Seismic Devnet Explorer`,url:`https://explorer-2.seismicdev.net`}},testnet:!0}),tk=L({id:1328,name:`Sei Testnet`,nativeCurrency:{name:`Sei`,symbol:`SEI`,decimals:18},rpcUrls:{default:{http:[`https://evm-rpc-testnet.sei-apis.com`],webSocket:[`wss://evm-ws-testnet.sei-apis.com`]}},blockExplorers:{default:{name:`Seitrace`,url:`https://seitrace.com`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:98697651}},testnet:!0}),nk=L({id:11155111,name:`Sepolia`,nativeCurrency:{name:`Sepolia Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://sepolia.drpc.org`]}},blockExplorers:{default:{name:`Etherscan`,url:`https://sepolia.etherscan.io`,apiUrl:`https://api-sepolia.etherscan.io/api`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:751532},ensUniversalResolver:{address:`0xeeeeeeee14d718c2b47d9923deab1335e144eeee`,blockCreated:8928790}},testnet:!0});var rk=1;const ik=L({...R,id:360,name:`Shape`,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://mainnet.shape.network`]}},blockExplorers:{default:{name:`shapescan`,url:`https://shapescan.xyz`,apiUrl:`https://shapescan.xyz/api`}},contracts:{...R.contracts,l2OutputOracle:{[rk]:{address:`0x6Ef8c69CfE4635d866e3E02732068022c06e724D`,blockCreated:20369940}},multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:1},portal:{[rk]:{address:`0xEB06fFa16011B5628BaB98E29776361c83741dd3`,blockCreated:20369933}},l1StandardBridge:{[rk]:{address:`0x62Edd5f4930Ea92dCa3fB81689bDD9b9d076b57B`,blockCreated:20369935}}},sourceId:rk});var ak=11155111;const ok=L({...R,id:11011,name:`Shape Sepolia Testnet`,nativeCurrency:{name:`Sepolia Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://sepolia.shape.network`]}},blockExplorers:{default:{name:`blockscout`,url:`https://explorer-sepolia.shape.network/`,apiUrl:`https://explorer-sepolia.shape.network/api/v2`}},contracts:{...R.contracts,multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:1}},testnet:!0,sourceId:ak}),sk=L({id:8118,name:`Shardeum`,nativeCurrency:{name:`Shardeum`,symbol:`SHM`,decimals:18},rpcUrls:{default:{http:[`https://api.shardeum.org`]}},blockExplorers:{default:{name:`Shardeum Explorer`,url:`https://explorer.shardeum.org`}},testnet:!1}),ck=L({id:8082,name:`Shardeum Sphinx`,nativeCurrency:{name:`SHARDEUM`,symbol:`SHM`,decimals:18},rpcUrls:{default:{http:[`https://sphinx.shardeum.org`]}},blockExplorers:{default:{name:`Shardeum Explorer`,url:`https://explorer-sphinx.shardeum.org`}},testnet:!0}),lk=L({id:109,name:`Shibarium`,network:`shibarium`,nativeCurrency:{name:`Bone`,symbol:`BONE`,decimals:18},rpcUrls:{default:{http:[`https://rpc.shibrpc.com`]}},blockExplorers:{default:{name:`Blockscout`,url:`https://shibariumscan.io`}},contracts:{multicall3:{address:`0x864Bf681ADD6052395188A89101A1B37d3B4C961`,blockCreated:265900}}}),uk=L({id:157,name:`Puppynet Shibarium`,nativeCurrency:{decimals:18,name:`Bone`,symbol:`BONE`},rpcUrls:{default:{http:[`https://puppynet.shibrpc.com`]}},blockExplorers:{default:{name:`Blockscout`,url:`https://puppyscan.shib.io`,apiUrl:`https://puppyscan.shib.io/api`}},contracts:{multicall3:{address:`0xA4029b74FBA366c926eDFA7Dd10B21C621170a4c`,blockCreated:3035769}},testnet:!0}),dk=L({id:336,name:`Shiden`,nativeCurrency:{decimals:18,name:`SDN`,symbol:`SDN`},rpcUrls:{default:{http:[`https://shiden.public.blastapi.io`],webSocket:[`wss://shiden-rpc.dwellir.com`]}},blockExplorers:{default:{name:`Shiden Scan`,url:`https://shiden.subscan.io`}},testnet:!1}),fk=L({id:148,name:`Shimmer`,network:`shimmer`,nativeCurrency:{decimals:18,name:`Shimmer`,symbol:`SMR`},rpcUrls:{default:{http:[`https://json-rpc.evm.shimmer.network`]}},blockExplorers:{default:{name:`Shimmer Network Explorer`,url:`https://explorer.evm.shimmer.network`,apiUrl:`https://explorer.evm.shimmer.network/api`}}}),pk=L({id:1073,name:`Shimmer Testnet`,network:`shimmer-testnet`,nativeCurrency:{decimals:18,name:`Shimmer`,symbol:`SMR`},rpcUrls:{default:{http:[`https://json-rpc.evm.testnet.shimmer.network`]}},blockExplorers:{default:{name:`Shimmer Network Explorer`,url:`https://explorer.evm.testnet.shimmer.network`,apiUrl:`https://explorer.evm.testnet.shimmer.network/api`}},testnet:!0}),mk=L({id:97453,name:`Sidra Chain`,nativeCurrency:{decimals:18,name:`Sidra Digital Asset`,symbol:`SDA`},rpcUrls:{default:{http:[`https://node.sidrachain.com`]}},blockExplorers:{default:{name:`Sidra Chain Explorer`,url:`https://ledger.sidrachain.com`}}}),hk=L({id:2355,name:`Silicon zkEVM`,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://rpc.silicon.network`,`https://silicon-mainnet.nodeinfra.com`]}},blockExplorers:{default:{name:`SiliconScope`,url:`https://scope.silicon.network`}}}),gk=L({id:1722641160,name:`Silicon Sepolia zkEVM`,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://rpc-sepolia.silicon.network`,`https://silicon-testnet.nodeinfra.com`]}},blockExplorers:{default:{name:`SiliconSepoliaScope`,url:`https://scope-sepolia.silicon.network`}},testnet:!0}),_k=L({id:98,name:`Six Protocol`,nativeCurrency:{decimals:18,name:`SIX`,symbol:`SIX`},rpcUrls:{default:{http:[`https://sixnet-rpc-evm.sixprotocol.net`]}},blockExplorers:{default:{name:`Six Protocol Scan`,url:`https://sixscan.io/sixnet`}},testnet:!1}),vk=L({id:391845894,name:`SKALE | Block Brawlers`,nativeCurrency:{name:`BRAWL`,symbol:`BRAWL`,decimals:18},rpcUrls:{default:{http:[`https://mainnet.skalenodes.com/v1/frayed-decent-antares`],webSocket:[`wss://mainnet.skalenodes.com/v1/ws/frayed-decent-antares`]}},blockExplorers:{default:{name:`SKALE Explorer`,url:`https://frayed-decent-antares.explorer.mainnet.skalenodes.com`}},contracts:{}}),yk=L({id:1564830818,name:`SKALE Calypso Hub`,nativeCurrency:{name:`sFUEL`,symbol:`sFUEL`,decimals:18},rpcUrls:{default:{http:[`https://mainnet.skalenodes.com/v1/honorable-steel-rasalhague`],webSocket:[`wss://mainnet.skalenodes.com/v1/ws/honorable-steel-rasalhague`]}},blockExplorers:{default:{name:`SKALE Explorer`,url:`https://honorable-steel-rasalhague.explorer.mainnet.skalenodes.com`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:3107626}}}),bk=L({id:974399131,name:`SKALE Calypso Testnet`,nativeCurrency:{name:`sFUEL`,symbol:`sFUEL`,decimals:18},rpcUrls:{default:{http:[`https://testnet.skalenodes.com/v1/giant-half-dual-testnet`],webSocket:[`wss://testnet.skalenodes.com/v1/ws/giant-half-dual-testnet`]}},blockExplorers:{default:{name:`SKALE Explorer`,url:`https://giant-half-dual-testnet.explorer.testnet.skalenodes.com`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:103220}},testnet:!0}),xk=L({id:1026062157,name:`SKALE | CryptoBlades`,nativeCurrency:{name:`sFUEL`,symbol:`sFUEL`,decimals:18},rpcUrls:{default:{http:[`https://mainnet.skalenodes.com/v1/affectionate-immediate-pollux`],webSocket:[`wss://mainnet.skalenodes.com/v1/ws/affectionate-immediate-pollux`]}},blockExplorers:{default:{name:`SKALE Explorer`,url:`https://affectionate-immediate-pollux.explorer.mainnet.skalenodes.com`}},contracts:{}}),Sk=L({id:1032942172,name:`SKALE | Crypto Colosseum`,nativeCurrency:{name:`sFUEL`,symbol:`sFUEL`,decimals:18},rpcUrls:{default:{http:[`https://mainnet.skalenodes.com/v1/haunting-devoted-deneb`],webSocket:[`wss://mainnet.skalenodes.com/v1/ws/haunting-devoted-deneb`]}},blockExplorers:{default:{name:`SKALE Explorer`,url:`https://haunting-devoted-deneb.explorer.mainnet.skalenodes.com`}},contracts:{}}),Ck=L({id:2046399126,name:`SKALE Europa Hub`,nativeCurrency:{name:`sFUEL`,symbol:`sFUEL`,decimals:18},rpcUrls:{default:{http:[`https://mainnet.skalenodes.com/v1/elated-tan-skat`],webSocket:[`wss://mainnet.skalenodes.com/v1/ws/elated-tan-skat`]}},blockExplorers:{default:{name:`SKALE Explorer`,url:`https://elated-tan-skat.explorer.mainnet.skalenodes.com`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:3113495}}}),wk=L({id:1444673419,name:`SKALE Europa Testnet`,nativeCurrency:{name:`sFUEL`,symbol:`sFUEL`,decimals:18},rpcUrls:{default:{http:[`https://testnet.skalenodes.com/v1/juicy-low-small-testnet`],webSocket:[`wss://testnet.skalenodes.com/v1/ws/juicy-low-small-testnet`]}},blockExplorers:{default:{name:`SKALE Explorer`,url:`https://juicy-low-small-testnet.explorer.testnet.skalenodes.com`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:110858}},testnet:!0}),Tk=L({id:2139927552,name:`Exorde Network`,nativeCurrency:{name:`sFUEL`,symbol:`sFUEL`,decimals:18},rpcUrls:{default:{http:[`https://mainnet.skalenodes.com/v1/light-vast-diphda`],webSocket:[`wss://mainnet.skalenodes.com/v1/ws/light-vast-diphda`]}},blockExplorers:{default:{name:`SKALE Explorer`,url:`https://light-vast-diphda.explorer.mainnet.skalenodes.com`}},contracts:{}}),Ek=L({id:1273227453,name:`SKALE | Human Protocol`,nativeCurrency:{name:`sFUEL`,symbol:`sFUEL`,decimals:18},rpcUrls:{default:{http:[`https://mainnet.skalenodes.com/v1/wan-red-ain`],webSocket:[`wss://mainnet.skalenodes.com/v1/ws/wan-red-ain`]}},blockExplorers:{default:{name:`SKALE Explorer`,url:`https://wan-red-ain.explorer.mainnet.skalenodes.com`}},contracts:{}}),Dk=L({id:1482601649,name:`SKALE Nebula Hub`,nativeCurrency:{name:`sFUEL`,symbol:`sFUEL`,decimals:18},rpcUrls:{default:{http:[`https://mainnet.skalenodes.com/v1/green-giddy-denebola`],webSocket:[`wss://mainnet.skalenodes.com/v1/ws/green-giddy-denebola`]}},blockExplorers:{default:{name:`SKALE Explorer`,url:`https://green-giddy-denebola.explorer.mainnet.skalenodes.com`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:2372986}}}),Ok=L({id:37084624,name:`SKALE Nebula Testnet`,nativeCurrency:{name:`sFUEL`,symbol:`sFUEL`,decimals:18},rpcUrls:{default:{http:[`https://testnet.skalenodes.com/v1/lanky-ill-funny-testnet`],webSocket:[`wss://testnet.skalenodes.com/v1/ws/lanky-ill-funny-testnet`]}},blockExplorers:{default:{name:`SKALE Explorer`,url:`https://lanky-ill-funny-testnet.explorer.testnet.skalenodes.com`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:105141}},testnet:!0}),kk=L({id:278611351,name:`SKALE | Razor Network`,nativeCurrency:{name:`sFUEL`,symbol:`sFUEL`,decimals:18},rpcUrls:{default:{http:[`https://mainnet.skalenodes.com/v1/turbulent-unique-scheat`],webSocket:[`wss://mainnet.skalenodes.com/v1/ws/turbulent-unique-scheat`]}},blockExplorers:{default:{name:`SKALE Explorer`,url:`https://turbulent-unique-scheat.explorer.mainnet.skalenodes.com`}},contracts:{}}),Ak=L({id:1350216234,name:`SKALE Titan Hub`,nativeCurrency:{name:`sFUEL`,symbol:`sFUEL`,decimals:18},rpcUrls:{default:{http:[`https://mainnet.skalenodes.com/v1/parallel-stormy-spica`],webSocket:[`wss://mainnet.skalenodes.com/v1/ws/parallel-stormy-spica`]}},blockExplorers:{default:{name:`SKALE Explorer`,url:`https://parallel-stormy-spica.explorer.mainnet.skalenodes.com`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:2076458}}}),jk=L({id:1020352220,name:`SKALE Titan Testnet`,nativeCurrency:{name:`sFUEL`,symbol:`sFUEL`,decimals:18},rpcUrls:{default:{http:[`https://testnet.skalenodes.com/v1/aware-fake-trim-testnet`],webSocket:[`wss://testnet.skalenodes.com/v1/ws/aware-fake-trim-testnet`]}},blockExplorers:{default:{name:`SKALE Explorer`,url:`https://aware-fake-trim-testnet.explorer.testnet.skalenodes.com`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:104072}},testnet:!0}),Mk=L({id:984123,name:`Forma Sketchpad`,network:`sketchpad`,nativeCurrency:{symbol:`TIA`,name:`TIA`,decimals:18},rpcUrls:{default:{http:[`https://rpc.sketchpad-1.forma.art`],webSocket:[`wss://ws.sketchpad-1.forma.art`]}},blockExplorers:{default:{name:`Sketchpad Explorer`,url:`https://explorer.sketchpad-1.forma.art`}},testnet:!0});var Nk=1;const Pk=L({...R,id:2192,network:`snaxchain-mainnet`,name:`SnaxChain`,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://mainnet.snaxchain.io`]}},blockExplorers:{default:{name:`Snax Explorer`,url:`https://explorer.snaxchain.io`,apiUrl:`https://explorer.snaxchain.io/api`}},contracts:{...R.contracts,disputeGameFactory:{[Nk]:{address:`0x472562Fcf26D6b2793f8E0b0fB660ba0E5e08A46`}},l2OutputOracle:{[Nk]:{address:`0x2172e492Fc807F5d5645D0E3543f139ECF539294`}},multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`},portal:{[Nk]:{address:`0x79f446D024d74D0Bb6E699C131c703463c5D65E9`}},l1StandardBridge:{[Nk]:{address:`0x6534Bdb6b5c060d3e6aa833433333135eFE8E0aA`}}},sourceId:Nk});var Fk=11155111;const Ik=L({...R,id:13001,network:`snaxchain-testnet`,name:`SnaxChain Testnet`,nativeCurrency:{name:`Sepolia Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://testnet.snaxchain.io`]}},blockExplorers:{default:{name:`Snax Explorer`,url:`https://testnet-explorer.snaxchain.io`,apiUrl:`https://testnet-explorer.snaxchain.io/api`}},contracts:{...R.contracts,disputeGameFactory:{[Fk]:{address:`0x206a75d89d45F146C54020F132FF93bEDD09f55E`}},l2OutputOracle:{[Fk]:{address:`0x60e3A368a4cdCEf85ffB964e372726F56A46221e`}},multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`},portal:{[Fk]:{address:`0xb5afdd0E8dDF081Ef90e8A3e0c7b5798e66E954E`}},l1StandardBridge:{[Fk]:{address:`0xbd37E1a59D4C00C9A46F75018dffd84061bC5f74`}}},testnet:!0,sourceId:Fk}),Lk=L({id:50312,name:`Somnia Testnet`,nativeCurrency:{name:`STT`,symbol:`STT`,decimals:18},rpcUrls:{default:{http:[`https://dream-rpc.somnia.network`]}},blockExplorers:{default:{name:`Somnia Testnet Explorer`,url:`https://shannon-explorer.somnia.network/`,apiUrl:`https://shannon-explorer.somnia.network/api`}},contracts:{multicall3:{address:`0x841b8199E6d3Db3C6f264f6C2bd8848b3cA64223`,blockCreated:71314235}},testnet:!0});var Rk=1;const zk=L({...R,id:1868,name:`Soneium Mainnet`,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://rpc.soneium.org`]}},blockExplorers:{default:{name:`Blockscout`,url:`https://soneium.blockscout.com`,apiUrl:`https://soneium.blockscout.com/api`}},contracts:{...R.contracts,disputeGameFactory:{[Rk]:{address:`0x512a3d2c7a43bd9261d2b8e8c9c70d4bd4d503c0`}},l2OutputOracle:{[Rk]:{address:`0x0000000000000000000000000000000000000000`}},portal:{[Rk]:{address:`0x88e529a6ccd302c948689cd5156c83d4614fae92`,blockCreated:7061266}},l1StandardBridge:{[Rk]:{address:`0xeb9bf100225c214efc3e7c651ebbadcf85177607`,blockCreated:7061266}},multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:1}},sourceId:Rk});var Bk=11155111;const Vk=L({...R,id:1946,name:`Soneium Minato Testnet`,nativeCurrency:{name:`Sepolia Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://rpc.minato.soneium.org`]}},blockExplorers:{default:{name:`Blockscout`,url:`https://soneium-minato.blockscout.com`,apiUrl:`https://soneium-minato.blockscout.com/api`}},contracts:{...R.contracts,disputeGameFactory:{[Bk]:{address:`0xB3Ad2c38E6e0640d7ce6aA952AB3A60E81bf7a01`}},l2OutputOracle:{[Bk]:{address:`0x710e5286C746eC38beeB7538d0146f60D27be343`}},portal:{[Bk]:{address:`0x65ea1489741A5D72fFdD8e6485B216bBdcC15Af3`,blockCreated:6466136}},l1StandardBridge:{[Bk]:{address:`0x5f5a404A5edabcDD80DB05E8e54A78c9EBF000C2`,blockCreated:6466136}},multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:1}},testnet:!0,sourceId:Bk}),Hk=L({id:19,name:`Songbird Canary-Network`,nativeCurrency:{decimals:18,name:`Songbird`,symbol:`SGB`},rpcUrls:{default:{http:[`https://songbird-api.flare.network/ext/C/rpc`]}},blockExplorers:{default:{name:`Songbird Explorer`,url:`https://songbird-explorer.flare.network`,apiUrl:`https://songbird-explorer.flare.network/api`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:13382504}}}),Uk=L({id:16,name:`Songbird Testnet Coston`,nativeCurrency:{decimals:18,name:`Coston Flare`,symbol:`CFLR`},rpcUrls:{default:{http:[`https://coston-api.flare.network/ext/C/rpc`]}},blockExplorers:{default:{name:`Coston Explorer`,url:`https://coston-explorer.flare.network`,apiUrl:`https://coston-explorer.flare.network/api`}},testnet:!0}),Wk=L({id:146,name:`Sonic`,blockTime:630,nativeCurrency:{decimals:18,name:`Sonic`,symbol:`S`},rpcUrls:{default:{http:[`https://rpc.soniclabs.com`]}},blockExplorers:{default:{name:`Sonic Explorer`,url:`https://sonicscan.org`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:60}},testnet:!1}),Gk=L({id:57054,name:`Sonic Blaze Testnet`,nativeCurrency:{decimals:18,name:`Sonic`,symbol:`S`},rpcUrls:{default:{http:[`https://rpc.blaze.soniclabs.com`]}},blockExplorers:{default:{name:`Sonic Blaze Testnet Explorer`,url:`https://testnet.sonicscan.org`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:1100}},testnet:!0}),Kk=L({id:64165,name:`Sonic Testnet`,nativeCurrency:{decimals:18,name:`Sonic`,symbol:`S`},rpcUrls:{default:{http:[`https://rpc.testnet.soniclabs.com`]}},blockExplorers:{default:{name:`Sonic Testnet Explorer`,url:`https://testnet.soniclabs.com/`}},testnet:!0}),qk=L({...oy,id:50104,name:`Sophon`,nativeCurrency:{decimals:18,name:`Sophon`,symbol:`SOPH`},rpcUrls:{default:{http:[`https://rpc.sophon.xyz`],webSocket:[`wss://rpc.sophon.xyz/ws`]}},blockExplorers:{default:{name:`Sophon Block Explorer`,url:`https://explorer.sophon.xyz`}},contracts:{multicall3:{address:`0x5f4867441d2416cA88B1b3fd38f21811680CD2C8`,blockCreated:116}},testnet:!1}),Jk=L({...oy,id:531050104,name:`Sophon Testnet`,nativeCurrency:{decimals:18,name:`Sophon`,symbol:`SOPH`},rpcUrls:{default:{http:[`https://rpc.testnet.sophon.xyz`],webSocket:[`wss://rpc.testnet.sophon.xyz/ws`]}},blockExplorers:{default:{name:`Sophon Block Explorer`,url:`https://explorer.testnet.sophon.xyz`}},contracts:{multicall3:{address:`0x83c04d112adedA2C6D9037bb6ecb42E7f0b108Af`,blockCreated:15642}},testnet:!0}),Yk=L({id:100021,name:`Sova`,nativeCurrency:{decimals:18,name:`Ether`,symbol:`ETH`},rpcUrls:{default:{http:[`https://rpc.sova.io`]}},blockExplorers:{default:{name:`Sova Block Explorer`,url:`hhttps://explorer.sova.io`}},testnet:!1}),Xk=L({id:120893,name:`Sova Network Sepolia`,nativeCurrency:{decimals:18,name:`Sepolia Ether`,symbol:`ETH`},rpcUrls:{default:{http:[`https://rpc.testnet.sova.io`]}},blockExplorers:{default:{name:`Sova Sepolia Explorer`,url:`https://explorer.testnet.sova.io`}},testnet:!0}),Zk=L({id:88882,name:`Chiliz Spicy Testnet`,network:`chiliz-spicy-Testnet`,nativeCurrency:{decimals:18,name:`CHZ`,symbol:`CHZ`},rpcUrls:{default:{http:[`https://spicy-rpc.chiliz.com`,`https://chiliz-spicy-rpc.publicnode.com`],webSocket:[`wss://spicy-rpc-ws.chiliz.com`,`wss://chiliz-spicy-rpc.publicnode.com`]}},blockExplorers:{default:{name:`Chiliz Explorer`,url:`http://spicy-explorer.chiliz.com`,apiUrl:`http://spicy-explorer.chiliz.com/api`}},testnet:!0}),Qk=L({...RT,id:1660990954,name:`Status Network Sepolia`,nativeCurrency:{decimals:18,name:`Ether`,symbol:`ETH`},rpcUrls:{default:{http:[`https://public.sepolia.rpc.status.network`],webSocket:[`wss://public.sepolia.rpc.status.network/ws`]}},blockExplorers:{default:{name:`Blockscout`,url:`https://sepoliascan.status.network`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:1578364}},testnet:!0}),$k=L({id:1234,name:`Step Network`,nativeCurrency:{name:`FITFI`,symbol:`FITFI`,decimals:18},rpcUrls:{default:{http:[`https://rpc.step.network`]}},blockExplorers:{default:{name:`Step Scan`,url:`https://stepscan.io`}},testnet:!1}),eA=L({id:1514,name:`Story`,nativeCurrency:{decimals:18,name:`IP Token`,symbol:`IP`},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:340998},ensRegistry:{address:`0x5dc881dda4e4a8d312be3544ad13118d1a04cb17`,blockCreated:648924},ensUniversalResolver:{address:`0xddfb18888a9466688235887dec2a10c4f5effee9`,blockCreated:649114}},rpcUrls:{default:{http:[`https://mainnet.storyrpc.io`]}},blockExplorers:{default:{name:`Story explorer`,url:`https://storyscan.io`,apiUrl:`https://storyscan.io/api/v2`}},ensTlds:[`.ip`],testnet:!1}),tA=L({id:1315,name:`Story Aeneid`,network:`story-aeneid`,nativeCurrency:{decimals:18,name:`IP`,symbol:`IP`},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:1792},ensRegistry:{address:`0x5dC881dDA4e4a8d312be3544AD13118D1a04Cb17`,blockCreated:1322033},ensUniversalResolver:{address:`0x6D3B3F99177FB2A5de7F9E928a9BD807bF7b5BAD`,blockCreated:1322097}},rpcUrls:{default:{http:[`https://aeneid.storyrpc.io`]}},blockExplorers:{default:{name:`Story Aeneid Explorer`,url:`https://aeneid.storyscan.io`,apiUrl:`https://aeneid.storyscan.io/api/v2`}},ensTlds:[`.ip`],testnet:!0}),nA=L({id:1516,name:`Story Odyssey`,nativeCurrency:{decimals:18,name:`IP`,symbol:`IP`},rpcUrls:{default:{http:[`https://rpc.odyssey.storyrpc.io`]}},blockExplorers:{default:{name:`Story Odyssey Explorer`,url:`https://odyssey.storyscan.xyz`}},testnet:!0}),rA=L({id:1513,name:`Story Testnet`,nativeCurrency:{decimals:18,name:`IP`,symbol:`IP`},rpcUrls:{default:{http:[`https://testnet.storyrpc.io`]}},blockExplorers:{default:{name:`Story Testnet Explorer`,url:`https://testnet.storyscan.xyz`}},testnet:!0}),iA=L({id:105105,name:`Stratis Mainnet`,network:`stratis`,nativeCurrency:{name:`Stratis`,symbol:`STRAX`,decimals:18},rpcUrls:{default:{http:[`https://rpc.stratisevm.com`]}},blockExplorers:{default:{name:`Stratis Explorer`,url:`https://explorer.stratisevm.com`}}}),aA=L({id:8866,name:`SuperLumio`,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://mainnet.lumio.io`]}},blockExplorers:{default:{name:`Lumio explorer`,url:`https://explorer.lumio.io`}},testnet:!1}),oA=L({id:55244,name:`Superposition`,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://rpc.superposition.so`]}},blockExplorers:{default:{name:`Superposition Explorer`,url:`https://explorer.superposition.so`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:39}},testnet:!1});var sA=1;const cA=L({...R,id:5330,name:`Superseed`,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://mainnet.superseed.xyz`]}},blockExplorers:{default:{name:`Superseed Explorer`,url:`https://explorer.superseed.xyz`,apiUrl:`https://explorer.superseed.xyz/api/v2`}},contracts:{...R.contracts,disputeGameFactory:{[sA]:{address:`0x8b097CF1f9BbD9cbFD0DD561858a1FCbC8857Be0`,blockCreated:20737481}},l2OutputOracle:{[sA]:{address:`0x693A0F8854F458D282DE3C5b69E8eE5EEE8aA949`,blockCreated:20737481}},portal:{[sA]:{address:`0x2c2150aa5c75A24fB93d4fD2F2a895D618054f07`,blockCreated:20737481}},l1StandardBridge:{[sA]:{address:`0x8b0576E39F1233679109F9b40cFcC2a7E0901Ede`,blockCreated:20737481}},multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`}},sourceId:sA});var lA=11155111;const uA=L({...R,id:53302,name:`Superseed Sepolia`,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://sepolia.superseed.xyz`]}},blockExplorers:{default:{name:`Superseed Sepolia Explorer`,url:`https://sepolia-explorer.superseed.xyz`,apiUrl:`https://sepolia-explorer.superseed.xyz/api/v2`}},contracts:{...R.contracts,multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`},portal:{[lA]:{address:`0x7A0db8C51432d2C3eb4e8f360a2EeB26FF2809fB`,blockCreated:5523438}},l1StandardBridge:{[lA]:{address:`0x2B227A603fAAdB3De0ED050b63ADD232B5f2c28C`,blockCreated:5523442}}},testnet:!0,sourceId:lA}),dA=L({id:763375,name:`Surge Testnet`,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://l2-rpc.hoodi.surge.wtf`],webSocket:[`wss://l2-ws.hoodi.surge.wtf`]}},blockExplorers:{default:{name:`Surge Testnet Blockscout`,url:`https://explorer.hoodi.surge.wtf`}},testnet:!0}),fA=L({id:254,name:`Swan Chain Mainnet`,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://mainnet-rpc.swanchain.org`]}},blockExplorers:{default:{name:`Swan Explorer`,url:`https://swanscan.io`}},testnet:!1}),pA=L({id:20241133,name:`Swan Proxima Testnet`,nativeCurrency:{name:`Swan Ether`,symbol:`sETH`,decimals:18},rpcUrls:{default:{http:[`https://rpc-proxima.swanchain.io`]}},blockExplorers:{default:{name:`Swan Explorer`,url:`https://proxima-explorer.swanchain.io`}},testnet:!0}),mA=L({id:2024,name:`Swan Saturn Testnet`,nativeCurrency:{name:`Swan Ether`,symbol:`sETH`,decimals:18},rpcUrls:{default:{http:[`https://saturn-rpc.swanchain.io`]}},blockExplorers:{default:{name:`Swan Explorer`,url:`https://saturn-explorer.swanchain.io`}},testnet:!0}),hA=L({...R,id:1923,name:`Swellchain`,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://swell-mainnet.alt.technology`]}},blockExplorers:{default:{name:`Swell Explorer`,url:`https://explorer.swellnetwork.io`,apiUrl:`https://explorer.swellnetwork.io/api`}},contracts:{...R.contracts,multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:1}}}),gA=L({...R,id:1924,name:`Swellchain Testnet`,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://swell-testnet.alt.technology`]}},blockExplorers:{default:{name:`Swellchain Testnet Explorer`,url:`https://swell-testnet-explorer.alt.technology`,apiUrl:`https://swell-testnet-explorer.alt.technology/api`}},contracts:{...R.contracts,multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:1}}}),_A=L({id:94,name:`SwissDLT Mainnet`,nativeCurrency:{decimals:18,name:`BCTS`,symbol:`BCTS`},rpcUrls:{default:{http:[`https://rpc.swissdlt.ch`]}},blockExplorers:{default:{name:`SwissDLT Explorer`,url:`https://explorer.swissdlt.ch`}},testnet:!1}),vA=L({id:57,name:`Syscoin Mainnet`,nativeCurrency:{decimals:18,name:`Syscoin`,symbol:`SYS`},rpcUrls:{default:{http:[`https://rpc.syscoin.org`],webSocket:[`wss://rpc.syscoin.org/wss`]}},blockExplorers:{default:{name:`SyscoinExplorer`,url:`https://explorer.syscoin.org`,apiUrl:`https://explorer.syscoin.org/api`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:287139}}}),yA=L({id:5700,name:`Syscoin Tanenbaum Testnet`,nativeCurrency:{decimals:18,name:`Syscoin`,symbol:`SYS`},rpcUrls:{default:{http:[`https://rpc.tanenbaum.io`],webSocket:[`wss://rpc.tanenbaum.io/wss`]}},blockExplorers:{default:{name:`SyscoinTestnetExplorer`,url:`https://tanenbaum.io`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:271288}}}),bA=L({id:239,name:`TAC`,nativeCurrency:{name:`TAC`,symbol:`TAC`,decimals:18},rpcUrls:{default:{http:[`https://rpc.ankr.com/tac`]}},blockExplorers:{default:{name:`Blockscout`,url:`https://tac.blockscout.com`,apiUrl:`https://tac.blockscout.com/api`},native:{name:`TAC Explorer`,url:`https://explorer.tac.build`,apiUrl:`https://explorer.tac.build/api`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:0}}}),xA=L({id:2391,name:`TAC SPB Testnet`,nativeCurrency:{name:`TAC`,symbol:`TAC`,decimals:18},rpcUrls:{default:{http:[`https://spb.rpc.tac.build`]}},blockExplorers:{default:{name:`TAC`,url:`https://spb.explorer.tac.build`,apiUrl:`https://spb.explorer.tac.build/api`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:471429}},testnet:!0}),SA=L({id:167e3,name:`Taiko Mainnet`,nativeCurrency:{decimals:18,name:`Ether`,symbol:`ETH`},rpcUrls:{default:{http:[`https://rpc.mainnet.taiko.xyz`],webSocket:[`wss://ws.mainnet.taiko.xyz`]}},blockExplorers:{default:{name:`Taikoscan`,url:`https://taikoscan.io`,apiUrl:`https://api.taikoscan.io/api`}},contracts:{multicall3:{address:`0xcb2436774C3e191c85056d248EF4260ce5f27A9D`}}}),CA=L({id:167009,name:`Taiko Hekla L2`,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://rpc.hekla.taiko.xyz`]}},blockExplorers:{default:{name:`Taikoscan`,url:`https://hekla.taikoscan.network`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:59757}},testnet:!0}),wA=L({id:167007,name:`Taiko Jolnir (Alpha-5 Testnet)`,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://rpc.jolnir.taiko.xyz`]}},blockExplorers:{default:{name:`blockscout`,url:`https://explorer.jolnir.taiko.xyz`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:732706}},testnet:!0}),TA=L({id:167008,name:`Taiko Katla (Alpha-6 Testnet)`,network:`tko-katla`,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://rpc.katla.taiko.xyz`]}},blockExplorers:{default:{name:`blockscout`,url:`https://explorer.katla.taiko.xyz`}}}),EA=L({id:167005,name:`Taiko (Alpha-3 Testnet)`,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://rpc.test.taiko.xyz`]}},blockExplorers:{default:{name:`blockscout`,url:`https://explorer.test.taiko.xyz`}}}),DA=L({id:841,name:`Taraxa Mainnet`,nativeCurrency:{name:`Tara`,symbol:`TARA`,decimals:18},rpcUrls:{default:{http:[`https://rpc.mainnet.taraxa.io`]}},blockExplorers:{default:{name:`Taraxa Explorer`,url:`https://explorer.mainnet.taraxa.io`}}}),OA=L({id:842,name:`Taraxa Testnet`,nativeCurrency:{name:`Tara`,symbol:`TARA`,decimals:18},rpcUrls:{default:{http:[`https://rpc.testnet.taraxa.io`]}},blockExplorers:{default:{name:`Taraxa Explorer`,url:`https://explorer.testnet.taraxa.io`}},testnet:!0}),kA=L({id:10218,name:`Tea Sepolia`,nativeCurrency:{name:`Sepolia Tea`,symbol:`TEA`,decimals:18},rpcUrls:{default:{http:[`https://tea-sepolia.g.alchemy.com/public`]}},blockExplorers:{default:{name:`Tea Sepolia Explorer`,url:`https://sepolia.tea.xyz`}},testnet:!0}),AA=L({id:2017,name:`Telcoin Adiri Testnet`,nativeCurrency:{name:`Telcoin`,symbol:`TEL`,decimals:18},rpcUrls:{default:{http:[`https://rpc.telcoin.network`]}},blockExplorers:{default:{name:`telscan`,url:`https://telscan.io`}},testnet:!0}),jA=L({id:40,name:`Telos`,nativeCurrency:{decimals:18,name:`Telos`,symbol:`TLOS`},rpcUrls:{default:{http:[`https://rpc.telos.net`]}},blockExplorers:{default:{name:`Teloscan`,url:`https://www.teloscan.io/`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:246530709}}}),MA=L({id:41,name:`Telos`,nativeCurrency:{decimals:18,name:`Telos`,symbol:`TLOS`},rpcUrls:{default:{http:[`https://rpc.testnet.telos.net`]}},blockExplorers:{default:{name:`Teloscan (testnet)`,url:`https://testnet.teloscan.io/`}},testnet:!0}),NA=L({id:1559,name:`Tenet`,network:`tenet-mainnet`,nativeCurrency:{name:`TENET`,symbol:`TENET`,decimals:18},rpcUrls:{default:{http:[`https://rpc.tenet.org`]}},blockExplorers:{default:{name:`TenetScan Mainnet`,url:`https://tenetscan.io`,apiUrl:`https://tenetscan.io/api`}},testnet:!1}),PA=L({id:752025,name:`Ternoa`,nativeCurrency:{name:`Capsule Coin`,symbol:`CAPS`,decimals:18},rpcUrls:{default:{http:[`https://rpc-mainnet.zkevm.ternoa.network`]}},blockExplorers:{default:{name:`Ternoa Explorer`,url:`https://explorer-mainnet.zkevm.ternoa.network`}},testnet:!1}),FA=L({id:7,name:`ThaiChain`,nativeCurrency:{name:`TCH`,symbol:`TCH`,decimals:18},rpcUrls:{default:{http:[`https://rpc.thaichain.org`]}},blockExplorers:{default:{name:`Blockscout`,url:`https://exp.thaichain.org`,apiUrl:`https://exp.thaichain.org/api`}},contracts:{multicall3:{address:`0x0DaD6130e832c21719C5CE3bae93454E16A84826`,blockCreated:4806386}},testnet:!1}),IA=L({id:8428,name:`THAT Mainnet`,nativeCurrency:{name:`THAT`,symbol:`THAT`,decimals:18},rpcUrls:{default:{http:[`https://api.thatchain.io/mainnet`]}},blockExplorers:{default:{name:`Blockscout`,url:`https://that.blockscout.com`}},testnet:!1}),LA=L({id:361,name:`Theta Mainnet`,nativeCurrency:{name:`TFUEL`,symbol:`TFUEL`,decimals:18},rpcUrls:{default:{http:[`https://eth-rpc-api.thetatoken.org/rpc`]}},blockExplorers:{default:{name:`Theta Explorer`,url:`https://explorer.thetatoken.org`}},testnet:!1}),RA=L({id:365,name:`Theta Testnet`,nativeCurrency:{name:`TFUEL`,symbol:`TFUEL`,decimals:18},rpcUrls:{default:{http:[`https://eth-rpc-api-testnet.thetatoken.org/rpc`]}},blockExplorers:{default:{name:`Theta Explorer`,url:`https://testnet-explorer.thetatoken.org`}},testnet:!0}),zA=L({id:108,name:`ThunderCore Mainnet`,nativeCurrency:{name:`TT`,symbol:`TT`,decimals:18},rpcUrls:{default:{http:[`https://mainnet-rpc.thundercore.com`]}},blockExplorers:{default:{name:`ThunderCore Explorer`,url:`https://explorer-mainnet.thundercore.com`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:0}},testnet:!1}),BA=L({id:997,name:`5ireChain Thunder Testnet`,nativeCurrency:{name:`5ire Token`,symbol:`5IRE`,decimals:18},rpcUrls:{default:{http:[`https://rpc.testnet.5ire.network`]}},blockExplorers:{default:{name:`5ireChain Thunder Explorer`,url:`https://testnet.5irescan.io/`}},testnet:!0}),VA=L({id:62092,name:`TikTrix Testnet`,nativeCurrency:{name:`tTTX`,symbol:`tTTX`,decimals:18},rpcUrls:{default:{http:[`https://tiktrix-rpc.xyz`]}},blockExplorers:{default:{name:`TikTrix Testnet Explorer`,url:`https://tiktrix.xyz`}},testnet:!0}),HA=L({id:6969,name:`Tomb Mainnet`,nativeCurrency:{name:`TOMB`,symbol:`TOMB`,decimals:18},rpcUrls:{default:{http:[`https://rpc.tombchain.com`]}},blockExplorers:{default:{name:`Tomb Explorer`,url:`https://tombscout.com`}},testnet:!1}),UA=L({...oy,id:61166,name:`Treasure`,nativeCurrency:{decimals:18,name:`MAGIC`,symbol:`MAGIC`},rpcUrls:{default:{http:[`https://rpc.treasure.lol`],webSocket:[`wss://rpc.treasure.lol/ws`]}},blockExplorers:{default:{name:`Treasure Block Explorer`,url:`https://treasurescan.io`}},contracts:{multicall3:{address:`0x2e29fe39496a56856D8698bD43e1dF4D0CE6266a`,blockCreated:101}},testnet:!1}),WA=L({...oy,id:978658,name:`Treasure Topaz Testnet`,nativeCurrency:{decimals:18,name:`MAGIC`,symbol:`MAGIC`},rpcUrls:{default:{http:[`https://rpc.topaz.treasure.lol`],webSocket:[`wss://rpc.topaz.treasure.lol/ws`]}},blockExplorers:{default:{name:`Treasure Topaz Block Explorer`,url:`https://topaz.treasurescan.io`}},contracts:{multicall3:{address:`0xF9cda624FBC7e059355ce98a31693d299FACd963`,blockCreated:108112}},testnet:!0}),GA=L({id:728126428,name:`Tron`,nativeCurrency:{name:`TRON`,symbol:`TRX`,decimals:6},rpcUrls:{default:{http:[`https://api.trongrid.io/jsonrpc`]}},blockExplorers:{default:{name:`Tronscan`,url:`https://tronscan.org`,apiUrl:`https://apilist.tronscanapi.com/api`}}}),KA=L({id:3448148188,name:`Tron Nile`,nativeCurrency:{name:`TRON`,symbol:`TRX`,decimals:6},rpcUrls:{default:{http:[`https://nile.trongrid.io/jsonrpc`]}},blockExplorers:{default:{name:`Tronscan`,url:`https://nile.tronscan.org`}},testnet:!0}),qA=L({id:2494104990,name:`Tron Shasta`,nativeCurrency:{name:`TRON`,symbol:`TRX`,decimals:6},rpcUrls:{default:{http:[`https://api.shasta.trongrid.io/jsonrpc`]}},blockExplorers:{default:{name:`Tronscan`,url:`https://shasta.tronscan.org`}},testnet:!0}),JA=L({id:8,name:`Ubiq Mainnet`,nativeCurrency:{name:`UBQ`,symbol:`UBQ`,decimals:18},rpcUrls:{default:{http:[`https://pyrus2.ubiqscan.io`]}},blockExplorers:{default:{name:`Ubiq Scan`,url:`https://ubiqscan.io`}},testnet:!1}),YA=L({id:19991,name:`Ultra EVM`,nativeCurrency:{decimals:18,name:`Ultra Token`,symbol:`UOS`},rpcUrls:{default:{http:[`https://evm.ultra.eosusa.io`]}},blockExplorers:{default:{name:`Ultra EVM Explorer`,url:`https://evmexplorer.ultra.io`}}}),XA=L({id:18881,name:`Ultra EVM Testnet`,nativeCurrency:{decimals:18,name:`Ultra Token`,symbol:`UOS`},rpcUrls:{default:{http:[`https://evm.test.ultra.eosusa.io`]}},blockExplorers:{default:{name:`Ultra EVM Testnet Explorer`,url:`https://evmexplorer.testnet.ultra.io`}},testnet:!0}),ZA=L({id:1231,name:`Ultron Mainnet`,nativeCurrency:{name:`ULX`,symbol:`ULX`,decimals:18},rpcUrls:{default:{http:[`https://ultron-rpc.net`]}},blockExplorers:{default:{name:`Ultron Scan`,url:`https://ulxscan.com`}},testnet:!1}),QA=L({id:1230,name:`Ultron Testnet`,nativeCurrency:{name:`ULX`,symbol:`ULX`,decimals:18},rpcUrls:{default:{http:[`https://ultron-dev.io`]}},blockExplorers:{default:{name:`Ultron Scan`,url:`https://explorer.ultron-dev.io`}},testnet:!0});var $A=1;const ej=L({...R,id:130,name:`Unichain`,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},blockTime:1e3,rpcUrls:{default:{http:[`https://mainnet.unichain.org/`]}},blockExplorers:{default:{name:`Uniscan`,url:`https://uniscan.xyz`,apiUrl:`https://api.uniscan.xyz/api`}},contracts:{...R.contracts,multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:0},disputeGameFactory:{[$A]:{address:`0x2F12d621a16e2d3285929C9996f478508951dFe4`}},portal:{[$A]:{address:`0x0bd48f6B86a26D3a217d0Fa6FfE2B491B956A7a2`}},l1StandardBridge:{[$A]:{address:`0x81014F44b0a345033bB2b3B21C7a1A308B35fEeA`}}},sourceId:$A});var tj=11155111;const nj=L({...R,id:1301,name:`Unichain Sepolia`,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},blockTime:1e3,rpcUrls:{default:{http:[`https://sepolia.unichain.org`]}},blockExplorers:{default:{name:`Uniscan`,url:`https://sepolia.uniscan.xyz`,apiUrl:`https://api-sepolia.uniscan.xyz/api`}},contracts:{...R.contracts,multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:0},portal:{[tj]:{address:`0x0d83dab629f0e0F9d36c0Cbc89B69a489f0751bD`}},l1StandardBridge:{[tj]:{address:`0xea58fcA6849d79EAd1f26608855c2D6407d54Ce2`}},disputeGameFactory:{[tj]:{address:`0xeff73e5aa3B9AEC32c659Aa3E00444d20a84394b`}}},testnet:!0,sourceId:tj}),rj=L({id:8880,name:`Unique Mainnet`,nativeCurrency:{decimals:18,name:`UNQ`,symbol:`UNQ`},rpcUrls:{default:{http:[`https://rpc.unique.network`]}},blockExplorers:{default:{name:`Unique Subscan`,url:`https://unique.subscan.io/`}}}),ij=L({id:8882,name:`Opal Testnet`,nativeCurrency:{decimals:18,name:`OPL`,symbol:`OPL`},rpcUrls:{default:{http:[`https://rpc-opal.unique.network`]}},blockExplorers:{default:{name:`Opal Subscan`,url:`https://opal.subscan.io/`}},testnet:!0}),aj=L({id:8881,name:`Quartz Mainnet`,nativeCurrency:{decimals:18,name:`QTZ`,symbol:`QTZ`},rpcUrls:{default:{http:[`https://rpc-quartz.unique.network`]}},blockExplorers:{default:{name:`Quartz Subscan`,url:`https://quartz.subscan.io/`}}}),oj=L({id:18233,name:`Unreal`,nativeCurrency:{name:`reETH`,decimals:18,symbol:`reETH`},rpcUrls:{default:{http:[`https://rpc.unreal-orbit.gelato.digital`]}},blockExplorers:{default:{name:`Unreal Explorer`,url:`https://unreal.blockscout.com`,apiUrl:`https://unreal.blockscout.com/api/v2`}},testnet:!0,contracts:{multicall3:{address:`0x8b6B0e60D8CD84898Ea8b981065A12F876eA5677`,blockCreated:1745}}}),sj=L({id:1480,name:`Vana`,blockTime:6e3,nativeCurrency:{decimals:18,name:`Vana`,symbol:`VANA`},rpcUrls:{default:{http:[`https://rpc.vana.org/`]}},blockExplorers:{default:{name:`Vana Block Explorer`,url:`https://vanascan.io`,apiUrl:`https://vanascan.io/api`}},contracts:{multicall3:{address:`0xD8d2dFca27E8797fd779F8547166A2d3B29d360E`,blockCreated:716763}}}),cj=L({id:14800,name:`Vana Moksha Testnet`,blockTime:6e3,nativeCurrency:{decimals:18,name:`Vana`,symbol:`VANA`},rpcUrls:{default:{http:[`https://rpc.moksha.vana.org`]}},blockExplorers:{default:{name:`Vana Moksha Testnet`,url:`https://moksha.vanascan.io`,apiUrl:`https://moksha.vanascan.io/api`}},contracts:{multicall3:{address:`0xD8d2dFca27E8797fd779F8547166A2d3B29d360E`,blockCreated:732283}},testnet:!0}),lj=L({id:2040,name:`Vanar Mainnet`,nativeCurrency:{name:`VANRY`,symbol:`VANRY`,decimals:18},rpcUrls:{default:{http:[`https://rpc.vanarchain.com`]}},blockExplorers:{default:{name:`Vanar Mainnet Explorer`,url:`https://explorer.vanarchain.com/`}},testnet:!1}),uj=L({id:100009,name:`Vechain`,nativeCurrency:{name:`VeChain`,symbol:`VET`,decimals:18},rpcUrls:{default:{http:[`https://mainnet.vechain.org`]}},blockExplorers:{default:{name:`Vechain Explorer`,url:`https://explore.vechain.org`},vechainStats:{name:`Vechain Stats`,url:`https://vechainstats.com`}}}),dj=L({id:106,name:`Velas EVM Mainnet`,nativeCurrency:{name:`VLX`,symbol:`VLX`,decimals:18},rpcUrls:{default:{http:[`https://evmexplorer.velas.com/rpc`]}},blockExplorers:{default:{name:`Velas Explorer`,url:`https://evmexplorer.velas.com`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:55883577}},testnet:!1}),fj=L({id:88,name:`Viction`,nativeCurrency:{name:`Viction`,symbol:`VIC`,decimals:18},rpcUrls:{default:{http:[`https://rpc.viction.xyz`]}},blockExplorers:{default:{name:`VIC Scan`,url:`https://vicscan.xyz`}},testnet:!1}),pj=L({id:89,name:`Viction Testnet`,nativeCurrency:{name:`Viction`,symbol:`VIC`,decimals:18},rpcUrls:{default:{http:[`https://rpc-testnet.viction.xyz`]}},blockExplorers:{default:{name:`VIC Scan`,url:`https://testnet.vicscan.xyz`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:12170179}},testnet:!0}),mj=L({id:888888,name:`Vision`,nativeCurrency:{name:`VISION`,symbol:`VS`,decimals:18},rpcUrls:{default:{http:[`https://infragrid.v.network/ethereum/compatible`]}},blockExplorers:{default:{name:`Vision Scan`,url:`https://visionscan.org`}},testnet:!1}),hj=L({id:666666,name:`Vision Testnet`,nativeCurrency:{name:`VISION`,symbol:`VS`,decimals:18},rpcUrls:{default:{http:[`https://vpioneer.infragrid.v.network/ethereum/compatible`]}},blockExplorers:{default:{name:`Vision Scan`,url:`https://visionscan.org/?chain=vpioneer`}},testnet:!0}),gj=L({id:888,name:`Wanchain`,nativeCurrency:{name:`WANCHAIN`,symbol:`WAN`,decimals:18},rpcUrls:{default:{http:[`https://gwan-ssl.wandevs.org:56891`,`https://gwan2-ssl.wandevs.org`]}},blockExplorers:{default:{name:`WanScan`,url:`https://wanscan.org`}},contracts:{multicall3:{address:`0xcDF6A1566e78EB4594c86Fe73Fcdc82429e97fbB`,blockCreated:25312390}}}),_j=L({id:999,name:`Wanchain Testnet`,nativeCurrency:{name:`WANCHAIN`,symbol:`WANt`,decimals:18},rpcUrls:{default:{http:[`https://gwan-ssl.wandevs.org:46891`]}},blockExplorers:{default:{name:`WanScanTest`,url:`https://wanscan.org`}},contracts:{multicall3:{address:`0x11c89bF4496c39FB80535Ffb4c92715839CC5324`,blockCreated:24743448}},testnet:!0}),vj=L({id:9496,name:`WeaveVM Alphanet`,nativeCurrency:{name:`Testnet WeaveVM`,symbol:`tWVM`,decimals:18},rpcUrls:{default:{http:[`https://testnet-rpc.wvm.dev`]}},blockExplorers:{default:{name:`WeaveVM Alphanet Explorer`,url:`https://explorer.wvm.dev`}},testnet:!0}),yj=L({id:1111,name:`WEMIX`,network:`wemix-mainnet`,nativeCurrency:{name:`WEMIX`,symbol:`WEMIX`,decimals:18},rpcUrls:{default:{http:[`https://api.wemix.com`]}},blockExplorers:{default:{name:`wemixExplorer`,url:`https://explorer.wemix.com`}}}),bj=L({id:1112,name:`WEMIX Testnet`,network:`wemix-testnet`,nativeCurrency:{name:`WEMIX`,symbol:`tWEMIX`,decimals:18},rpcUrls:{default:{http:[`https://api.test.wemix.com`]}},blockExplorers:{default:{name:`wemixExplorer`,url:`https://testnet.wemixscan.com`,apiUrl:`https://testnet.wemixscan.com/api`}},testnet:!0}),xj=L({id:420420421,name:`Westend Asset Hub`,nativeCurrency:{decimals:18,name:`Westies`,symbol:`WND`},rpcUrls:{default:{http:[`https://westend-asset-hub-eth-rpc.polkadot.io`]}},blockExplorers:{default:{name:`subscan`,url:`https://westend-asset-hub-eth-explorer.parity.io`}},testnet:!0}),Sj=L({testnet:!1,name:`Whitechain`,blockExplorers:{default:{name:`Whitechain Explorer`,url:`https://explorer.whitechain.io`}},id:1875,rpcUrls:{default:{http:[`https://rpc.whitechain.io`]}},nativeCurrency:{decimals:18,name:`WhiteBIT Coin`,symbol:`WBT`},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:25212237}}}),Cj=L({testnet:!0,name:`Whitechain Testnet`,blockExplorers:{default:{name:`Whitechain Explorer`,url:`https://testnet.whitechain.io`}},id:2625,rpcUrls:{default:{http:[`https://rpc-testnet.whitechain.io`]}},nativeCurrency:{decimals:18,name:`WhiteBIT Coin`,symbol:`WBT`}}),wj=L({id:42070,name:`WMC Testnet`,nativeCurrency:{name:`WMTx`,symbol:`WMTx`,decimals:18},rpcUrls:{default:{http:[`https://rpc-testnet-base.worldmobile.net`]}},blockExplorers:{default:{name:`WMC Explorer`,url:`https://explorer2-base-testnet.worldmobile.net`}},testnet:!0});var Tj=1;const Ej=L({...R,id:480,name:`World Chain`,network:`worldchain`,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://worldchain-mainnet.g.alchemy.com/public`]}},blockExplorers:{default:{name:`Worldscan`,url:`https://worldscan.org`,apiUrl:`https://api.worldscan.org/api`},blockscout:{name:`Blockscout`,url:`https://worldchain-mainnet.explorer.alchemy.com`,apiUrl:`https://worldchain-mainnet.explorer.alchemy.com/api`}},contracts:{...R.contracts,multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:0},disputeGameFactory:{[Tj]:{address:`0x069c4c579671f8c120b1327a73217D01Ea2EC5ea`}},l2OutputOracle:{[Tj]:{address:`0x19A6d1E9034596196295CF148509796978343c5D`}},portal:{[Tj]:{address:`0xd5ec14a83B7d95BE1E2Ac12523e2dEE12Cbeea6C`}},l1StandardBridge:{[Tj]:{address:`0x470458C91978D2d929704489Ad730DC3E3001113`}}},testnet:!1,sourceId:Tj});var Dj=11155111;const Oj=L({...R,id:4801,name:`World Chain Sepolia`,network:`worldchain-sepolia`,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://worldchain-sepolia.g.alchemy.com/public`]}},blockExplorers:{default:{name:`Worldscan Sepolia`,url:`https://sepolia.worldscan.org`,apiUrl:`https://api-sepolia.worldscan.org/api`},blockscout:{name:`Blockscout`,url:`https://worldchain-sepolia.explorer.alchemy.com`,apiUrl:`https://worldchain-sepolia.explorer.alchemy.com/api`}},contracts:{...R.contracts,multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:0},disputeGameFactory:{[Dj]:{address:`0x8Ec1111f67Dad6b6A93B3F42DfBC92D81c98449A`}},l2OutputOracle:{[Dj]:{address:`0xc8886f8BAb6Eaeb215aDB5f1c686BF699248300e`}},portal:{[Dj]:{address:`0xFf6EBa109271fe6d4237EeeD4bAb1dD9A77dD1A4`}},l1StandardBridge:{[Dj]:{address:`0xd7DF54b3989855eb66497301a4aAEc33Dbb3F8DE`}}},testnet:!0,sourceId:Dj}),kj=L({id:103,name:`WorldLand Mainnet`,nativeCurrency:{decimals:18,name:`WLC`,symbol:`WLC`},rpcUrls:{default:{http:[`https://seoul.worldland.foundation`]}},blockExplorers:{default:{name:`WorldLand Scan`,url:`https://scan.worldland.foundation`}},testnet:!1}),Aj=L({id:660279,name:`Xai Mainnet`,nativeCurrency:{name:`Xai`,symbol:`XAI`,decimals:18},rpcUrls:{default:{http:[`https://xai-chain.net/rpc`]}},blockExplorers:{default:{name:`Blockscout`,url:`https://explorer.xai-chain.net`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:222549}},testnet:!1}),jj=L({id:37714555429,name:`Xai Testnet`,nativeCurrency:{name:`sXai`,symbol:`sXAI`,decimals:18},rpcUrls:{default:{http:[`https://testnet-v2.xai-chain.net/rpc`]}},blockExplorers:{default:{name:`Blockscout`,url:`https://testnet-explorer-v2.xai-chain.net`}},testnet:!0}),Mj=L({id:50,name:`XDC Network`,nativeCurrency:{decimals:18,name:`XDC`,symbol:`XDC`},rpcUrls:{default:{http:[`https://rpc.xdcrpc.com`]}},blockExplorers:{default:{name:`XDCScan`,url:`https://xdcscan.com`}},contracts:{multicall3:{address:`0x0B1795ccA8E4eC4df02346a082df54D437F8D9aF`,blockCreated:75884020}}}),Nj=L({id:51,name:`Apothem Network`,nativeCurrency:{decimals:18,name:`TXDC`,symbol:`TXDC`},rpcUrls:{default:{http:[`https://erpc.apothem.network`]}},blockExplorers:{default:{name:`XDCScan`,url:`https://testnet.xdcscan.com`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:59765389}}}),Pj=L({id:196,name:`X Layer Mainnet`,nativeCurrency:{decimals:18,name:`OKB`,symbol:`OKB`},rpcUrls:{default:{http:[`https://rpc.xlayer.tech`]}},blockExplorers:{default:{name:`OKLink`,url:`https://www.oklink.com/xlayer`,apiUrl:`https://www.oklink.com/api/v5/explorer/xlayer/api`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:47416}}}),Fj=L({id:195,name:`X1 Testnet`,nativeCurrency:{decimals:18,name:`OKB`,symbol:`OKB`},rpcUrls:{default:{http:[`https://xlayertestrpc.okx.com`]}},blockExplorers:{default:{name:`OKLink`,url:`https://www.oklink.com/xlayer-test`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:624344}},testnet:!0}),Ij=L({id:20250217,name:`Xphere Mainnet`,nativeCurrency:{decimals:18,name:`XP`,symbol:`XP`},rpcUrls:{default:{http:[`https://en-bkk.x-phere.com`]}},blockExplorers:{default:{name:`Xphere Tamsa Explorer`,url:`https://xp.tamsa.io`}},testnet:!1}),Lj=L({id:1998991,name:`Xphere Testnet`,nativeCurrency:{decimals:18,name:`XPT`,symbol:`XPT`},rpcUrls:{default:{http:[`http://testnet.x-phere.com`]}},blockExplorers:{default:{name:`Xphere Tamsa Explorer`,url:`https://xpt.tamsa.io`}},testnet:!0}),Rj=L({id:273,name:`XR One`,nativeCurrency:{decimals:18,name:`XR1`,symbol:`XR1`},rpcUrls:{default:{http:[`https://xr1.calderachain.xyz/http`],webSocket:[`wss://xr1.calderachain.xyz/ws`]}},blockExplorers:{default:{name:`Blockscout`,url:`https://xr1.calderaexplorer.xyz`}},testnet:!1}),zj=L({id:1440002,name:`XRPL EVM Devnet`,nativeCurrency:{name:`XRP`,symbol:`XRP`,decimals:18},rpcUrls:{default:{http:[`https://rpc.xrplevm.org/`]},public:{http:[`https://rpc.xrplevm.org/`]}},blockExplorers:{default:{name:`XRPLEVM Devnet Explorer`,url:`https://explorer.xrplevm.org/`}},contracts:{multicall3:{address:`0x82Cc144D7d0AD4B1c27cb41420e82b82Ad6e9B31`,blockCreated:15237286}},testnet:!0}),Bj=L({id:1449e3,name:`XRPL EVM Testnet`,nativeCurrency:{name:`XRP`,symbol:`XRP`,decimals:18},rpcUrls:{default:{http:[`https://rpc.testnet.xrplevm.org`]}},blockExplorers:{default:{name:`blockscout`,url:`https://explorer.testnet.xrplevm.org`,apiUrl:`https://explorer.testnet.xrplevm.org/api/v2`}},contracts:{multicall3:{address:`0x82Cc144D7d0AD4B1c27cb41420e82b82Ad6e9B31`,blockCreated:492302}},testnet:!0}),Vj=L({id:2730,name:`XR Sepolia`,nativeCurrency:{decimals:18,name:`tXR`,symbol:`tXR`},rpcUrls:{default:{http:[`https://xr-sepolia-testnet.rpc.caldera.xyz/http`]}},blockExplorers:{default:{name:`Blockscout`,url:`https://xr-sepolia-testnet.explorer.caldera.xyz`}},testnet:!0}),Hj=L({id:50005,name:`Yooldo Verse`,nativeCurrency:{name:`OAS`,symbol:`OAS`,decimals:18},rpcUrls:{default:{http:[`https://rpc.yooldo-verse.xyz`]}},blockExplorers:{default:{name:`Yooldo Verse Explorer`,url:`https://explorer.yooldo-verse.xyz`}}}),Uj=L({id:50006,name:`Yooldo Verse Testnet`,nativeCurrency:{name:`OAS`,symbol:`OAS`,decimals:18},rpcUrls:{default:{http:[`https://rpc.testnet.yooldo-verse.xyz`]}},blockExplorers:{default:{name:`Yooldo Verse Testnet Explorer`,url:`https://explorer.testnet.yooldo-verse.xyz`}},testnet:!0}),Wj=L({id:8408,name:`ZenChain Testnet`,nativeCurrency:{decimals:18,name:`ZTC`,symbol:`ZTC`},rpcUrls:{default:{http:[`https://zenchain-testnet.api.onfinality.io/public`],webSocket:[`wss://zenchain-testnet.api.onfinality.io/public-ws`]}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:230019}},blockExplorers:{default:{name:`Zentrace`,url:`https://zentrace.io`}},testnet:!0}),Gj=L({id:383414847825,name:`Zeniq Mainnet`,nativeCurrency:{name:`ZENIQ`,symbol:`ZENIQ`,decimals:18},rpcUrls:{default:{http:[`https://api.zeniq.network`]}},blockExplorers:{default:{name:`Zeniq Explorer`,url:`https://zeniqscan.com`}},testnet:!1}),Kj=L({id:543210,name:`Zero Network`,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://rpc.zerion.io/v1/zero`]}},blockExplorers:{default:{name:`Zero Network Explorer`,url:`https://explorer.zero.network`}},testnet:!1}),qj=L({id:7e3,name:`ZetaChain`,nativeCurrency:{decimals:18,name:`Zeta`,symbol:`ZETA`},rpcUrls:{default:{http:[`https://zetachain-evm.blockpi.network/v1/rpc/public`]}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:1632781}},blockExplorers:{default:{name:`ZetaScan`,url:`https://zetascan.com`}},testnet:!1}),Jj=L({id:7001,name:`ZetaChain Athens Testnet`,nativeCurrency:{decimals:18,name:`Zeta`,symbol:`aZETA`},rpcUrls:{default:{http:[`https://zetachain-athens-evm.blockpi.network/v1/rpc/public`]}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:2715217}},blockExplorers:{default:{name:`ZetaScan`,url:`https://testnet.zetascan.com`}},testnet:!0}),Yj=L({id:1337803,name:`Zhejiang`,nativeCurrency:{name:`Zhejiang Ether`,symbol:`ZhejETH`,decimals:18},rpcUrls:{default:{http:[`https://rpc.zhejiang.ethpandaops.io`]}},blockExplorers:{default:{name:`Beaconchain`,url:`https://zhejiang.beaconcha.in`}},testnet:!0}),Xj=L({id:32769,name:`Zilliqa`,network:`zilliqa`,nativeCurrency:{name:`Zilliqa`,symbol:`ZIL`,decimals:18},rpcUrls:{default:{http:[`https://api.zilliqa.com`]}},blockExplorers:{default:{name:`Ethernal`,url:`https://evmx.zilliqa.com`}},testnet:!1}),Zj=L({id:33101,name:`Zilliqa Testnet`,network:`zilliqa-testnet`,nativeCurrency:{name:`Zilliqa`,symbol:`ZIL`,decimals:18},rpcUrls:{default:{http:[`https://dev-api.zilliqa.com`]}},blockExplorers:{default:{name:`Ethernal`,url:`https://evmx.testnet.zilliqa.com`}},testnet:!0});var Qj=1;const $j=L({...R,id:48900,name:`Zircuit Mainnet`,nativeCurrency:{decimals:18,name:`Ether`,symbol:`ETH`},rpcUrls:{default:{http:[`https://mainnet.zircuit.com`,`https://zircuit1-mainnet.liquify.com`,`https://zircuit1-mainnet.p2pify.com`,`https://zircuit-mainnet.drpc.org`]}},blockExplorers:{default:{name:`Zircuit Explorer`,url:`https://explorer.zircuit.com`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`},l2OutputOracle:{[Qj]:{address:`0x92Ef6Af472b39F1b363da45E35530c24619245A4`}},portal:{[Qj]:{address:`0x17bfAfA932d2e23Bd9B909Fd5B4D2e2a27043fb1`}},l1StandardBridge:{[Qj]:{address:`0x386B76D9cA5F5Fb150B6BFB35CF5379B22B26dd8`}}},testnet:!1});var eM=11155111;const tM=L({...R,id:48898,name:`Zircuit Garfield Testnet`,nativeCurrency:{name:`ETH`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://garfield-testnet.zircuit.com/`]}},blockExplorers:{default:{name:`Zircuit Garfield Testnet Explorer`,url:`https://explorer.garfield-testnet.zircuit.com`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`},l2OutputOracle:{[eM]:{address:`0xd69D3AC5CA686cCF94b258291772bc520FEAf211`}},portal:{[eM]:{address:`0x4E21A71Ac3F7607Da5c06153A17B1DD20E702c21`}},l1StandardBridge:{[eM]:{address:`0x87a7E2bCA9E35BA49282E832a28A6023904460D8`}}},testnet:!0});var nM=11155111;const rM=L({...R,id:48899,name:`Zircuit Testnet`,nativeCurrency:{name:`ETH`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://testnet.zircuit.com`,`https://zircuit1-testnet.p2pify.com`,`https://zircuit1-testnet.liquify.com`]}},blockExplorers:{default:{name:`Zircuit Testnet Explorer`,url:`https://explorer.testnet.zircuit.com`}},contracts:{multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:6040287},l2OutputOracle:{[nM]:{address:`0x740C2dac453aEf7140809F80b72bf0e647af8148`}},portal:{[nM]:{address:`0x787f1C8c5924178689E0560a43D848bF8E54b23e`}},l1StandardBridge:{[nM]:{address:`0x0545c5fe980098C16fcD0eCB5E79753afa6d9af9`}}},testnet:!0}),iM=L({id:42766,name:`ZKFair Mainnet`,network:`zkfair-mainnet`,nativeCurrency:{decimals:18,name:`USD Coin`,symbol:`USDC`},rpcUrls:{default:{http:[`https://rpc.zkfair.io`]}},blockExplorers:{default:{name:`zkFair Explorer`,url:`https://scan.zkfair.io`,apiUrl:`https://scan.zkfair.io/api`}},contracts:{multicall3:{address:`0xca11bde05977b3631167028862be2a173976ca11`,blockCreated:6090959}},testnet:!1}),aM=L({id:43851,name:`ZKFair Testnet`,network:`zkfair-testnet`,nativeCurrency:{decimals:18,name:`USD Coin`,symbol:`USDC`},rpcUrls:{default:{http:[`https://testnet-rpc.zkfair.io`]}},blockExplorers:{default:{name:`zkFair Explorer`,url:`https://testnet-scan.zkfair.io`}},testnet:!0}),oM=L({id:810180,name:`zkLink Nova`,nativeCurrency:{decimals:18,name:`ETH`,symbol:`ETH`},rpcUrls:{default:{http:[`https://rpc.zklink.io`]}},blockExplorers:{default:{name:`zkLink Nova Block Explorer`,url:`https://explorer.zklink.io`}}}),sM=L({id:810181,name:`zkLink Nova Sepolia Testnet`,nativeCurrency:{decimals:18,name:`ETH`,symbol:`ETH`},rpcUrls:{default:{http:[`https://sepolia.rpc.zklink.io`]}},blockExplorers:{default:{name:`zkLink Nova Block Explorer`,url:`https://sepolia.explorer.zklink.io`}}}),cM=L({...oy,id:324,name:`ZKsync Era`,network:`zksync-era`,nativeCurrency:{decimals:18,name:`Ether`,symbol:`ETH`},rpcUrls:{default:{http:[`https://mainnet.era.zksync.io`],webSocket:[`wss://mainnet.era.zksync.io/ws`]}},blockExplorers:{default:{name:`Etherscan`,url:`https://era.zksync.network/`,apiUrl:`https://api-era.zksync.network/api`},native:{name:`ZKsync Explorer`,url:`https://explorer.zksync.io/`,apiUrl:`https://block-explorer-api.mainnet.zksync.io/api`}},contracts:{multicall3:{address:`0xF9cda624FBC7e059355ce98a31693d299FACd963`},erc6492Verifier:{address:`0xfB688330379976DA81eB64Fe4BF50d7401763B9C`,blockCreated:45659388}}}),lM=L({...oy,id:260,name:`ZKsync InMemory Node`,network:`zksync-in-memory-node`,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`http://localhost:8011`]}},testnet:!0}),uM=L({...oy,id:272,name:`ZKsync CLI Local Custom Hyperchain`,nativeCurrency:{name:`BAT`,symbol:`BAT`,decimals:18},rpcUrls:{default:{http:[`http://localhost:15200`],webSocket:[`ws://localhost:15201`]}},blockExplorers:{default:{name:`ZKsync explorer`,url:`http://localhost:15005/`,apiUrl:`http://localhost:15005/api`}},testnet:!0}),dM=L({...oy,id:270,name:`ZKsync CLI Local Hyperchain`,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`http://localhost:15100`],webSocket:[`ws://localhost:15101`]}},blockExplorers:{default:{name:`ZKsync explorer`,url:`http://localhost:15005/`,apiUrl:`http://localhost:15005/api`}},testnet:!0}),fM=L({id:9,name:`ZKsync CLI Local Hyperchain L1`,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`http://localhost:15045`]}},blockExplorers:{default:{name:`Blockscout`,url:`http://localhost:15001/`,apiUrl:`http://localhost:15001/api/v2`}},testnet:!0}),pM=L({...oy,id:270,name:`ZKsync CLI Local Node`,network:`zksync-cli-local-node`,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`http://localhost:3050`]}},testnet:!0}),mM=L({...oy,id:300,name:`ZKsync Sepolia Testnet`,network:`zksync-sepolia-testnet`,nativeCurrency:{name:`Ether`,symbol:`ETH`,decimals:18},rpcUrls:{default:{http:[`https://sepolia.era.zksync.dev`],webSocket:[`wss://sepolia.era.zksync.dev/ws`]}},blockExplorers:{default:{name:`Etherscan`,url:`https://sepolia-era.zksync.network/`,apiUrl:`https://api-sepolia-era.zksync.network/api`},native:{name:`ZKsync Explorer`,url:`https://sepolia.explorer.zksync.io/`,blockExplorerApi:`https://block-explorer-api.sepolia.zksync.dev/api`}},contracts:{multicall3:{address:`0xF9cda624FBC7e059355ce98a31693d299FACd963`},erc6492Verifier:{address:`0xfB688330379976DA81eB64Fe4BF50d7401763B9C`,blockCreated:3855712}},testnet:!0});var hM=1;const gM=L({...R,id:7777777,name:`Zora`,nativeCurrency:{decimals:18,name:`Ether`,symbol:`ETH`},rpcUrls:{default:{http:[`https://rpc.zora.energy`],webSocket:[`wss://rpc.zora.energy`]}},blockExplorers:{default:{name:`Explorer`,url:`https://explorer.zora.energy`,apiUrl:`https://explorer.zora.energy/api`}},contracts:{...R.contracts,l2OutputOracle:{[hM]:{address:`0x9E6204F750cD866b299594e2aC9eA824E2e5f95c`}},multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:5882},portal:{[hM]:{address:`0x1a0ad011913A150f69f6A19DF447A0CfD9551054`}},l1StandardBridge:{[hM]:{address:`0x3e2Ea9B92B7E48A52296fD261dc26fd995284631`}}},sourceId:hM});var _M=11155111;const vM=L({...R,id:999999999,name:`Zora Sepolia`,network:`zora-sepolia`,nativeCurrency:{decimals:18,name:`Zora Sepolia`,symbol:`ETH`},rpcUrls:{default:{http:[`https://sepolia.rpc.zora.energy`],webSocket:[`wss://sepolia.rpc.zora.energy`]}},blockExplorers:{default:{name:`Zora Sepolia Explorer`,url:`https://sepolia.explorer.zora.energy/`,apiUrl:`https://sepolia.explorer.zora.energy/api`}},contracts:{...R.contracts,l2OutputOracle:{[_M]:{address:`0x2615B481Bd3E5A1C0C7Ca3Da1bdc663E8615Ade9`}},multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:83160},portal:{[_M]:{address:`0xeffE2C6cA9Ab797D418f0D91eA60807713f3536f`}},l1StandardBridge:{[_M]:{address:`0x5376f1D543dcbB5BD416c56C189e4cB7399fCcCB`}}},sourceId:_M,testnet:!0});var yM=5;const bM=L({...R,id:999,name:`Zora Goerli Testnet`,nativeCurrency:{decimals:18,name:`Zora Goerli`,symbol:`ETH`},rpcUrls:{default:{http:[`https://testnet.rpc.zora.energy`],webSocket:[`wss://testnet.rpc.zora.energy`]}},blockExplorers:{default:{name:`Explorer`,url:`https://testnet.explorer.zora.energy`,apiUrl:`https://testnet.explorer.zora.energy/api`}},contracts:{...R.contracts,multicall3:{address:`0xcA11bde05977b3631167028862bE2a173976CA11`,blockCreated:189123},portal:{[yM]:{address:`0xDb9F51790365e7dc196e7D072728df39Be958ACe`}}},sourceId:yM,testnet:!0});var xM=c({abey:()=>Wv,abstract:()=>sy,abstractTestnet:()=>cy,acala:()=>ly,acria:()=>uy,adf:()=>dy,agungTestnet:()=>fy,aioz:()=>py,alephZero:()=>my,alephZeroTestnet:()=>hy,alienx:()=>gy,alienxHalTestnet:()=>_y,ancient8:()=>Ey,ancient8Sepolia:()=>Oy,anvil:()=>ky,apeChain:()=>Ay,apexTestnet:()=>jy,arbitrum:()=>My,arbitrumGoerli:()=>Ny,arbitrumNova:()=>Py,arbitrumSepolia:()=>Fy,arenaz:()=>Iy,areonNetwork:()=>Ly,areonNetworkTestnet:()=>Ry,areum:()=>zy,artelaTestnet:()=>By,arthera:()=>Vy,artheraTestnet:()=>Hy,assetChain:()=>Uy,assetChainTestnet:()=>Wy,astar:()=>Gy,astarZkEVM:()=>Ky,astarZkyoto:()=>qy,atletaOlympia:()=>Jy,aurora:()=>Yy,auroraTestnet:()=>Xy,auroria:()=>Zy,autheoTestnet:()=>Qy,avalanche:()=>$y,avalancheFuji:()=>eb,b3:()=>tb,b3Sepolia:()=>nb,bahamut:()=>rb,base:()=>ab,baseGoerli:()=>lb,basePreconf:()=>ob,baseSepolia:()=>db,baseSepoliaPreconf:()=>fb,basecampTestnet:()=>sb,beam:()=>pb,beamTestnet:()=>mb,bearNetworkChainMainnet:()=>hb,bearNetworkChainTestnet:()=>gb,berachain:()=>_b,berachainBepolia:()=>vb,berachainTestnet:()=>yb,berachainTestnetbArtio:()=>bb,bevmMainnet:()=>xb,bifrost:()=>Sb,birdlayer:()=>Cb,bitTorrent:()=>Ab,bitTorrentTestnet:()=>jb,bitgert:()=>wb,bitkub:()=>Tb,bitkubTestnet:()=>Eb,bitlayer:()=>Db,bitlayerTestnet:()=>Ob,bitrock:()=>kb,blast:()=>Nb,blastSepolia:()=>Pb,bob:()=>Ib,bobSepolia:()=>Bb,boba:()=>Lb,bobaSepolia:()=>Rb,boolBetaMainnet:()=>Vb,botanix:()=>Hb,botanixTestnet:()=>Ub,bounceBit:()=>Wb,bounceBitTestnet:()=>Gb,bronos:()=>Kb,bronosTestnet:()=>qb,bsc:()=>Jb,bscGreenfield:()=>Yb,bscTestnet:()=>Xb,bsquared:()=>Zb,bsquaredTestnet:()=>Qb,btr:()=>$b,btrTestnet:()=>ex,bxn:()=>tx,bxnTestnet:()=>nx,cannon:()=>rx,canto:()=>ix,celo:()=>yx,celoAlfajores:()=>xx,celoSepolia:()=>Cx,chang:()=>wx,chiliz:()=>Tx,chips:()=>Ex,citreaTestnet:()=>Dx,classic:()=>Ox,coinbit:()=>kx,coinex:()=>Ax,confluxESpace:()=>jx,confluxESpaceTestnet:()=>Mx,coreDao:()=>Nx,coreTestnet1:()=>Px,coreTestnet2:()=>Fx,corn:()=>Ix,cornTestnet:()=>Lx,crab:()=>Rx,creatorTestnet:()=>zx,creditCoin3Devnet:()=>Bx,creditCoin3Mainnet:()=>Vx,creditCoin3Testnet:()=>Hx,cronos:()=>Ux,cronosTestnet:()=>Wx,cronoszkEVM:()=>Gx,cronoszkEVMTestnet:()=>Kx,crossbell:()=>qx,crossfi:()=>Jx,curtis:()=>Yx,cyber:()=>Xx,cyberTestnet:()=>Zx,dailyNetwork:()=>Qx,dailyNetworkTestnet:()=>$x,darwinia:()=>eS,dbkchain:()=>tS,dchain:()=>nS,dchainTestnet:()=>rS,defichainEvm:()=>iS,defichainEvmTestnet:()=>aS,degen:()=>oS,dfk:()=>sS,diode:()=>cS,disChain:()=>lS,dodochainTestnet:()=>uS,dogechain:()=>dS,domaTestnet:()=>fS,donatuz:()=>pS,dosChain:()=>mS,dosChainTestnet:()=>hS,dreyerxMainnet:()=>gS,dreyerxTestnet:()=>_S,dustboyIoT:()=>vS,dymension:()=>yS,edexa:()=>bS,edexaTestnet:()=>xS,edgeless:()=>SS,edgelessTestnet:()=>CS,edgeware:()=>wS,edgewareTestnet:()=>TS,eduChain:()=>ES,eduChainTestnet:()=>DS,ekta:()=>OS,ektaTestnet:()=>kS,elastos:()=>AS,elastosTestnet:()=>jS,electroneum:()=>MS,electroneumTestnet:()=>NS,elysiumTestnet:()=>PS,energy:()=>FS,eni:()=>IS,eniTestnet:()=>LS,enuls:()=>RS,eon:()=>zS,eos:()=>BS,eosTestnet:()=>VS,eteria:()=>HS,etherlink:()=>US,etherlinkTestnet:()=>WS,ethernity:()=>GS,etp:()=>KS,evmos:()=>qS,evmosTestnet:()=>JS,excelonMainnet:()=>YS,expanse:()=>XS,exsat:()=>ZS,exsatTestnet:()=>QS,fantom:()=>$S,fantomSonicTestnet:()=>eC,fantomTestnet:()=>tC,fibo:()=>nC,filecoin:()=>rC,filecoinCalibration:()=>iC,filecoinHyperspace:()=>aC,fireChain:()=>Uv,flame:()=>oC,flare:()=>sC,flareTestnet:()=>cC,flowMainnet:()=>lC,flowPreviewnet:()=>uC,flowTestnet:()=>dC,fluence:()=>fC,fluenceStage:()=>pC,fluenceTestnet:()=>mC,fluentTestnet:()=>hC,form:()=>_C,formTestnet:()=>bC,forma:()=>vC,formicarium:()=>CE,forta:()=>xC,foundry:()=>SC,fraxtal:()=>wC,fraxtalTestnet:()=>EC,funkiMainnet:()=>OC,funkiSepolia:()=>AC,fuse:()=>jC,fuseSparknet:()=>MC,fusion:()=>NC,fusionTestnet:()=>PC,garnet:()=>IC,geist:()=>LC,genesys:()=>RC,giwaSepolia:()=>BC,glideL1Protocol:()=>VC,glideL2Protocol:()=>HC,gnosis:()=>UC,gnosisChiado:()=>WC,goChain:()=>qC,goat:()=>GC,gobi:()=>KC,godwoken:()=>JC,goerli:()=>YC,graphite:()=>XC,graphiteTestnet:()=>ZC,gravity:()=>QC,gunz:()=>$C,guruNetwork:()=>ew,guruTestnet:()=>tw,ham:()=>nw,happychainTestnet:()=>rw,haqqMainnet:()=>iw,haqqTestedge2:()=>aw,hardhat:()=>ow,harmonyOne:()=>sw,hashkey:()=>cw,hashkeyTestnet:()=>lw,haustTestnet:()=>uw,hedera:()=>dw,hederaPreviewnet:()=>fw,hederaTestnet:()=>pw,hela:()=>mw,hemi:()=>hw,hemiSepolia:()=>gw,holesky:()=>_w,hoodi:()=>vw,hpb:()=>yw,huddle01Mainnet:()=>bw,huddle01Testnet:()=>xw,humanity:()=>Sw,humanityTestnet:()=>Cw,humanode:()=>ww,humanodeTestnet5:()=>Tw,hychain:()=>Ew,hychainTestnet:()=>Dw,hyperliquidEvmTestnet:()=>Ow,iSunCoin:()=>Kw,icbNetwork:()=>kw,idchain:()=>Aw,immutableZkEvm:()=>jw,immutableZkEvmTestnet:()=>Mw,inEVM:()=>Nw,initVerse:()=>Pw,initVerseGenesis:()=>Fw,injective:()=>Iw,injectiveTestnet:()=>Lw,ink:()=>zw,inkSepolia:()=>Vw,iota:()=>Hw,iotaTestnet:()=>Uw,iotex:()=>Ww,iotexTestnet:()=>Gw,jbc:()=>qw,jbcTestnet:()=>Jw,jocMainnet:()=>Yw,jocTestnet:()=>Xw,jovay:()=>Zw,jovaySepolia:()=>Qw,juneo:()=>$w,juneoBCH1Chain:()=>eT,juneoDAI1Chain:()=>tT,juneoDOGE1Chain:()=>nT,juneoEUR1Chain:()=>rT,juneoGLD1Chain:()=>iT,juneoLINK1Chain:()=>aT,juneoLTC1Chain:()=>oT,juneoSGD1Chain:()=>cT,juneoSocotraTestnet:()=>lT,juneoUSD1Chain:()=>uT,juneoUSDT1Chain:()=>dT,juneomBTC1Chain:()=>sT,kaia:()=>fT,kairos:()=>pT,kakarotSepolia:()=>mT,kakarotStarknetSepolia:()=>hT,kardiaChain:()=>gT,karura:()=>_T,katana:()=>vT,kava:()=>yT,kavaTestnet:()=>bT,kcc:()=>xT,kiiTestnetOro:()=>ST,kinto:()=>CT,klaytn:()=>wT,klaytnBaobab:()=>TT,koi:()=>ET,kroma:()=>DT,kromaSepolia:()=>OT,l3x:()=>kT,l3xTestnet:()=>AT,lavita:()=>jT,lens:()=>MT,lensTestnet:()=>NT,lestnet:()=>PT,lightlinkPegasus:()=>FT,lightlinkPhoenix:()=>IT,linea:()=>BT,lineaGoerli:()=>VT,lineaSepolia:()=>HT,lineaTestnet:()=>UT,lisk:()=>GT,liskSepolia:()=>qT,loadAlphanet:()=>JT,localhost:()=>YT,loop:()=>XT,lukso:()=>ZT,luksoTestnet:()=>QT,lumiaMainnet:()=>$T,lumiaTestnet:()=>eE,lumoz:()=>tE,lumozTestnet:()=>nE,lycan:()=>rE,lyra:()=>iE,mainnet:()=>aE,mandala:()=>oE,manta:()=>sE,mantaSepoliaTestnet:()=>cE,mantaTestnet:()=>lE,mantle:()=>uE,mantleSepoliaTestnet:()=>dE,mantleTestnet:()=>fE,mantraDuKongEVMTestnet:()=>pE,mantraEVM:()=>mE,mapProtocol:()=>hE,matchain:()=>gE,matchainTestnet:()=>_E,mchVerse:()=>vE,megaethTestnet:()=>yE,mekong:()=>bE,meld:()=>xE,memecore:()=>SE,merlin:()=>wE,merlinErigonTestnet:()=>TE,metachain:()=>EE,metachainIstanbul:()=>DE,metadium:()=>OE,metalL2:()=>AE,meter:()=>jE,meterTestnet:()=>ME,metis:()=>NE,metisGoerli:()=>PE,metisSepolia:()=>FE,mev:()=>IE,mevTestnet:()=>LE,mint:()=>RE,mintSepoliaTestnet:()=>zE,mitosisTestnet:()=>BE,mode:()=>HE,modeTestnet:()=>WE,monadTestnet:()=>GE,moonbaseAlpha:()=>KE,moonbeam:()=>qE,moonbeamDev:()=>JE,moonriver:()=>YE,morph:()=>XE,morphHolesky:()=>ZE,morphSepolia:()=>QE,nahmii:()=>$E,nautilus:()=>eD,near:()=>tD,nearTestnet:()=>nD,neonDevnet:()=>rD,neonMainnet:()=>iD,neoxMainnet:()=>aD,neoxT4:()=>oD,newton:()=>sD,nexi:()=>cD,nexilix:()=>lD,nibiru:()=>uD,nitrographTestnet:()=>dD,oasisTestnet:()=>fD,oasys:()=>pD,odysseyTestnet:()=>mD,okc:()=>hD,omax:()=>gD,omni:()=>_D,omniOmega:()=>vD,oneWorld:()=>yD,oortMainnetDev:()=>bD,opBNB:()=>SD,opBNBTestnet:()=>wD,openledger:()=>TD,optimism:()=>DD,optimismGoerli:()=>kD,optimismSepolia:()=>jD,optopia:()=>MD,optopiaTestnet:()=>ND,orderly:()=>PD,orderlySepolia:()=>FD,otimDevnet:()=>ID,palm:()=>LD,palmTestnet:()=>RD,peaq:()=>zD,pgn:()=>VD,pgnTestnet:()=>UD,phoenix:()=>WD,planq:()=>GD,plasma:()=>KD,plasmaDevnet:()=>qD,plasmaTestnet:()=>JD,playfiAlbireo:()=>YD,plinga:()=>XD,plume:()=>ZD,plumeDevnet:()=>QD,plumeMainnet:()=>$D,plumeSepolia:()=>eO,plumeTestnet:()=>tO,polterTestnet:()=>nO,polygon:()=>rO,polygonAmoy:()=>iO,polygonMumbai:()=>aO,polygonZkEvm:()=>oO,polygonZkEvmCardona:()=>sO,polygonZkEvmTestnet:()=>cO,polynomial:()=>lO,polynomialSepolia:()=>uO,premiumBlockTestnet:()=>dO,pulsechain:()=>fO,pulsechainV4:()=>pO,pumpfiTestnet:()=>mO,pyrope:()=>gO,qMainnet:()=>vO,qTestnet:()=>yO,ql1:()=>_O,real:()=>bO,redbellyMainnet:()=>xO,redbellyTestnet:()=>SO,reddio:()=>CO,reddioSepolia:()=>wO,redstone:()=>EO,rei:()=>DO,reyaNetwork:()=>OO,riseTestnet:()=>kO,rivalz:()=>AO,rollux:()=>jO,rolluxTestnet:()=>MO,ronin:()=>NO,root:()=>PO,rootPorcini:()=>FO,rootstock:()=>IO,rootstockTestnet:()=>LO,rss3:()=>zO,rss3Sepolia:()=>VO,saakuru:()=>HO,saga:()=>UO,saigon:()=>WO,sanko:()=>GO,sapphire:()=>KO,sapphireTestnet:()=>qO,satoshiVM:()=>JO,satoshiVMTestnet:()=>YO,scroll:()=>XO,scrollSepolia:()=>ZO,sei:()=>QO,seiDevnet:()=>$O,seiTestnet:()=>tk,seismicDevnet:()=>ek,sepolia:()=>nk,shape:()=>ik,shapeSepolia:()=>ok,shardeum:()=>sk,shardeumSphinx:()=>ck,shibarium:()=>lk,shibariumTestnet:()=>uk,shiden:()=>dk,shimmer:()=>fk,shimmerTestnet:()=>pk,sidraChain:()=>mk,silicon:()=>hk,siliconSepolia:()=>gk,sixProtocol:()=>_k,skaleBlockBrawlers:()=>vk,skaleCalypso:()=>yk,skaleCalypsoTestnet:()=>bk,skaleCryptoBlades:()=>xk,skaleCryptoColosseum:()=>Sk,skaleEuropa:()=>Ck,skaleEuropaTestnet:()=>wk,skaleExorde:()=>Tk,skaleHumanProtocol:()=>Ek,skaleNebula:()=>Dk,skaleNebulaTestnet:()=>Ok,skaleRazor:()=>kk,skaleTitan:()=>Ak,skaleTitanTestnet:()=>jk,sketchpad:()=>Mk,snax:()=>Pk,snaxTestnet:()=>Ik,somniaTestnet:()=>Lk,soneium:()=>zk,soneiumMinato:()=>Vk,songbird:()=>Hk,songbirdTestnet:()=>Uk,sonic:()=>Wk,sonicBlazeTestnet:()=>Gk,sonicTestnet:()=>Kk,sophon:()=>qk,sophonTestnet:()=>Jk,sova:()=>Yk,sovaSepolia:()=>Xk,spicy:()=>Zk,statusNetworkSepolia:()=>Qk,statusSepolia:()=>Qk,step:()=>$k,story:()=>eA,storyAeneid:()=>tA,storyOdyssey:()=>nA,storyTestnet:()=>rA,stratis:()=>iA,superlumio:()=>aA,superposition:()=>oA,superseed:()=>cA,superseedSepolia:()=>uA,surgeTestnet:()=>dA,swan:()=>fA,swanProximaTestnet:()=>pA,swanSaturnTestnet:()=>mA,swellchain:()=>hA,swellchainTestnet:()=>gA,swissdlt:()=>_A,syscoin:()=>vA,syscoinTestnet:()=>yA,tac:()=>bA,tacSPB:()=>xA,taiko:()=>SA,taikoHekla:()=>CA,taikoJolnir:()=>wA,taikoKatla:()=>TA,taikoTestnetSepolia:()=>EA,taraxa:()=>DA,taraxaTestnet:()=>OA,teaSepolia:()=>kA,telcoinTestnet:()=>AA,telos:()=>jA,telosTestnet:()=>MA,tenet:()=>NA,ternoa:()=>PA,thaiChain:()=>FA,that:()=>IA,theta:()=>LA,thetaTestnet:()=>RA,thunderCore:()=>zA,thunderTestnet:()=>BA,tiktrixTestnet:()=>VA,tomb:()=>HA,treasure:()=>UA,treasureTopaz:()=>WA,tron:()=>GA,tronNile:()=>KA,tronShasta:()=>qA,ubiq:()=>JA,ultra:()=>YA,ultraTestnet:()=>XA,ultron:()=>ZA,ultronTestnet:()=>QA,unichain:()=>ej,unichainSepolia:()=>nj,unique:()=>rj,uniqueOpal:()=>ij,uniqueQuartz:()=>aj,unreal:()=>oj,vana:()=>sj,vanaMoksha:()=>cj,vanar:()=>lj,vechain:()=>uj,velas:()=>dj,viction:()=>fj,victionTestnet:()=>pj,vision:()=>mj,visionTestnet:()=>hj,wanchain:()=>gj,wanchainTestnet:()=>_j,weaveVMAlphanet:()=>vj,wemix:()=>yj,wemixTestnet:()=>bj,westendAssetHub:()=>xj,whitechain:()=>Sj,whitechainTestnet:()=>Cj,wmcTestnet:()=>wj,worldLand:()=>kj,worldchain:()=>Ej,worldchainSepolia:()=>Oj,x1Testnet:()=>Fj,xLayer:()=>Pj,xLayerTestnet:()=>Fj,xai:()=>Aj,xaiTestnet:()=>jj,xdc:()=>Mj,xdcTestnet:()=>Nj,xphereMainnet:()=>Ij,xphereTestnet:()=>Lj,xrOne:()=>Rj,xrSepolia:()=>Vj,xrplevmDevnet:()=>zj,xrplevmTestnet:()=>Bj,yooldoVerse:()=>Hj,yooldoVerseTestnet:()=>Uj,zenchainTestnet:()=>Wj,zeniq:()=>Gj,zeroG:()=>Bv,zeroGGalileoTestnet:()=>Vv,zeroGMainnet:()=>Hv,zeroNetwork:()=>Kj,zetachain:()=>qj,zetachainAthensTestnet:()=>Jj,zhejiang:()=>Yj,zilliqa:()=>Xj,zilliqaTestnet:()=>Zj,zircuit:()=>$j,zircuitGarfieldTestnet:()=>tM,zircuitTestnet:()=>rM,zkFair:()=>iM,zkFairTestnet:()=>aM,zkLinkNova:()=>oM,zkLinkNovaSepoliaTestnet:()=>sM,zkSync:()=>cM,zkSyncInMemoryNode:()=>lM,zkSyncLocalNode:()=>pM,zkSyncSepoliaTestnet:()=>mM,zksync:()=>cM,zksyncInMemoryNode:()=>lM,zksyncLocalCustomHyperchain:()=>uM,zksyncLocalHyperchain:()=>dM,zksyncLocalHyperchainL1:()=>fM,zksyncLocalNode:()=>pM,zksyncSepoliaTestnet:()=>mM,zora:()=>gM,zoraSepolia:()=>vM,zoraTestnet:()=>bM}),SM=c({arbitrum:()=>My,arbitrumSepolia:()=>Fy,base:()=>ab,baseSepolia:()=>db,berachain:()=>_b,berachainBepolia:()=>vb,bsc:()=>Jb,celo:()=>yx,gnosis:()=>UC,hoodi:()=>vw,katana:()=>vT,mainnet:()=>aE,optimism:()=>DD,optimismSepolia:()=>jD,polygon:()=>rO,sepolia:()=>nk});const CM=[ab,...Object.values(SM).filter(e=>e&&e.id!==ab.id)],wM=ky;({...wM}),{...wM};var TM=u(s(((e,t)=>{var n=Object.prototype.hasOwnProperty,r=`~`;function i(){}Object.create&&(i.prototype=Object.create(null),new i().__proto__||(r=!1));function a(e,t,n){this.fn=e,this.context=t,this.once=n||!1}function o(e,t,n,i,o){if(typeof n!=`function`)throw TypeError(`The listener must be a function`);var s=new a(n,i||e,o),c=r?r+t:t;return e._events[c]?e._events[c].fn?e._events[c]=[e._events[c],s]:e._events[c].push(s):(e._events[c]=s,e._eventsCount++),e}function s(e,t){--e._eventsCount===0?e._events=new i:delete e._events[t]}function c(){this._events=new i,this._eventsCount=0}c.prototype.eventNames=function(){var e=[],t,i;if(this._eventsCount===0)return e;for(i in t=this._events)n.call(t,i)&&e.push(r?i.slice(1):i);return Object.getOwnPropertySymbols?e.concat(Object.getOwnPropertySymbols(t)):e},c.prototype.listeners=function(e){var t=r?r+e:e,n=this._events[t];if(!n)return[];if(n.fn)return[n.fn];for(var i=0,a=n.length,o=Array(a);i<a;i++)o[i]=n[i].fn;return o},c.prototype.listenerCount=function(e){var t=r?r+e:e,n=this._events[t];return n?n.fn?1:n.length:0},c.prototype.emit=function(e,t,n,i,a,o){var s=r?r+e:e;if(!this._events[s])return!1;var c=this._events[s],l=arguments.length,u,d;if(c.fn){switch(c.once&&this.removeListener(e,c.fn,void 0,!0),l){case 1:return c.fn.call(c.context),!0;case 2:return c.fn.call(c.context,t),!0;case 3:return c.fn.call(c.context,t,n),!0;case 4:return c.fn.call(c.context,t,n,i),!0;case 5:return c.fn.call(c.context,t,n,i,a),!0;case 6:return c.fn.call(c.context,t,n,i,a,o),!0}for(d=1,u=Array(l-1);d<l;d++)u[d-1]=arguments[d];c.fn.apply(c.context,u)}else{var f=c.length,p;for(d=0;d<f;d++)switch(c[d].once&&this.removeListener(e,c[d].fn,void 0,!0),l){case 1:c[d].fn.call(c[d].context);break;case 2:c[d].fn.call(c[d].context,t);break;case 3:c[d].fn.call(c[d].context,t,n);break;case 4:c[d].fn.call(c[d].context,t,n,i);break;default:if(!u)for(p=1,u=Array(l-1);p<l;p++)u[p-1]=arguments[p];c[d].fn.apply(c[d].context,u)}}return!0},c.prototype.on=function(e,t,n){return o(this,e,t,n,!1)},c.prototype.once=function(e,t,n){return o(this,e,t,n,!0)},c.prototype.removeListener=function(e,t,n,i){var a=r?r+e:e;if(!this._events[a])return this;if(!t)return s(this,a),this;var o=this._events[a];if(o.fn)o.fn===t&&(!i||o.once)&&(!n||o.context===n)&&s(this,a);else{for(var c=0,l=[],u=o.length;c<u;c++)(o[c].fn!==t||i&&!o[c].once||n&&o[c].context!==n)&&l.push(o[c]);l.length?this._events[a]=l.length===1?l[0]:l:s(this,a)}return this},c.prototype.removeAllListeners=function(e){var t;return e?(t=r?r+e:e,this._events[t]&&s(this,t)):(this._events=new i,this._eventsCount=0),this},c.prototype.off=c.prototype.removeListener,c.prototype.addListener=c.prototype.on,c.prefixed=r,c.EventEmitter=c,t!==void 0&&(t.exports=c)}))(),1);function EM(e,t={}){let{raw:n=!1}=t,r=e;if(n)return e;if(r.error)throw DM(r.error);return r.result}function DM(e){let t=e;if(t instanceof Error&&!(`code`in t))return new zM({cause:t,data:t,message:t.message,stack:t.stack});let{code:n}=t;return n===zM.code?new zM(t):n===kM.code?new kM(t):n===RM.code?new RM(t):n===IM.code?new IM(t):n===PM.code?new PM(t):n===LM.code?new LM(t):n===NM.code?new NM(t):n===BM.code?new BM(t):n===AM.code?new AM(t):n===jM.code?new jM(t):n===MM.code?new MM(t):n===FM.code?new FM(t):new zM({cause:t instanceof Error?t:void 0,data:t,message:t.message,stack:t instanceof Error?t.stack:void 0})}var OM=class extends Error{constructor(e){let{cause:t,code:n,message:r,data:i,stack:a}=e;super(r,{cause:t}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`RpcResponse.BaseError`}),Object.defineProperty(this,`cause`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`stack`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`code`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`data`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.cause=t,this.code=n,this.data=i,this.stack=a??``}},kM=class e extends OM{constructor(t={}){super({code:e.code,data:t.data,message:t.message??`Missing or invalid parameters.`}),Object.defineProperty(this,`code`,{enumerable:!0,configurable:!0,writable:!0,value:-32e3}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`RpcResponse.InvalidInputError`})}};Object.defineProperty(kM,`code`,{enumerable:!0,configurable:!0,writable:!0,value:-32e3});var AM=class e extends OM{constructor(t={}){super({code:e.code,data:t.data,message:t.message??`Requested resource not found.`}),Object.defineProperty(this,`code`,{enumerable:!0,configurable:!0,writable:!0,value:-32001}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`RpcResponse.ResourceNotFoundError`})}};Object.defineProperty(AM,`code`,{enumerable:!0,configurable:!0,writable:!0,value:-32001});var jM=class e extends OM{constructor(t={}){super({code:e.code,data:t.data,message:t.message??`Requested resource not available.`}),Object.defineProperty(this,`code`,{enumerable:!0,configurable:!0,writable:!0,value:-32002}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`RpcResponse.ResourceUnavailableError`})}};Object.defineProperty(jM,`code`,{enumerable:!0,configurable:!0,writable:!0,value:-32002});var MM=class e extends OM{constructor(t={}){super({code:e.code,data:t.data,message:t.message??`Transaction creation failed.`}),Object.defineProperty(this,`code`,{enumerable:!0,configurable:!0,writable:!0,value:-32003}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`RpcResponse.TransactionRejectedError`})}};Object.defineProperty(MM,`code`,{enumerable:!0,configurable:!0,writable:!0,value:-32003});var NM=class e extends OM{constructor(t={}){super({code:e.code,data:t.data,message:t.message??`Method is not implemented.`}),Object.defineProperty(this,`code`,{enumerable:!0,configurable:!0,writable:!0,value:-32004}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`RpcResponse.MethodNotSupportedError`})}};Object.defineProperty(NM,`code`,{enumerable:!0,configurable:!0,writable:!0,value:-32004});var PM=class e extends OM{constructor(t={}){super({code:e.code,data:t.data,message:t.message??`Rate limit exceeded.`}),Object.defineProperty(this,`code`,{enumerable:!0,configurable:!0,writable:!0,value:-32005}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`RpcResponse.LimitExceededError`})}};Object.defineProperty(PM,`code`,{enumerable:!0,configurable:!0,writable:!0,value:-32005});var FM=class e extends OM{constructor(t={}){super({code:e.code,data:t.data,message:t.message??`JSON-RPC version not supported.`}),Object.defineProperty(this,`code`,{enumerable:!0,configurable:!0,writable:!0,value:-32006}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`RpcResponse.VersionNotSupportedError`})}};Object.defineProperty(FM,`code`,{enumerable:!0,configurable:!0,writable:!0,value:-32006});var IM=class e extends OM{constructor(t={}){super({code:e.code,data:t.data,message:t.message??`Input is not a valid JSON-RPC request.`}),Object.defineProperty(this,`code`,{enumerable:!0,configurable:!0,writable:!0,value:-32600}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`RpcResponse.InvalidRequestError`})}};Object.defineProperty(IM,`code`,{enumerable:!0,configurable:!0,writable:!0,value:-32600});var LM=class e extends OM{constructor(t={}){super({code:e.code,data:t.data,message:t.message??`Method does not exist.`}),Object.defineProperty(this,`code`,{enumerable:!0,configurable:!0,writable:!0,value:-32601}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`RpcResponse.MethodNotFoundError`})}};Object.defineProperty(LM,`code`,{enumerable:!0,configurable:!0,writable:!0,value:-32601});var RM=class e extends OM{constructor(t={}){super({code:e.code,data:t.data,message:t.message??`Invalid method parameters.`}),Object.defineProperty(this,`code`,{enumerable:!0,configurable:!0,writable:!0,value:-32602}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`RpcResponse.InvalidParamsError`})}};Object.defineProperty(RM,`code`,{enumerable:!0,configurable:!0,writable:!0,value:-32602});var zM=class e extends OM{constructor(t={}){super({cause:t.cause,code:e.code,data:t.data,message:t.message??`Internal JSON-RPC error.`,stack:t.stack}),Object.defineProperty(this,`code`,{enumerable:!0,configurable:!0,writable:!0,value:-32603}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`RpcResponse.InternalError`})}};Object.defineProperty(zM,`code`,{enumerable:!0,configurable:!0,writable:!0,value:-32603});var BM=class e extends OM{constructor(t={}){super({code:e.code,data:t.data,message:t.message??`Failed to parse JSON-RPC response.`}),Object.defineProperty(this,`code`,{enumerable:!0,configurable:!0,writable:!0,value:-32700}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`RpcResponse.ParseError`})}};Object.defineProperty(BM,`code`,{enumerable:!0,configurable:!0,writable:!0,value:-32700}),Jd();var VM=class extends Error{constructor(e,t){super(t),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`ProviderRpcError`}),Object.defineProperty(this,`code`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`details`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.code=e,this.details=t}},HM=class extends VM{constructor({message:e=`The user rejected the request.`}={}){super(4001,e),Object.defineProperty(this,`code`,{enumerable:!0,configurable:!0,writable:!0,value:4001}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Provider.UserRejectedRequestError`})}};Object.defineProperty(HM,`code`,{enumerable:!0,configurable:!0,writable:!0,value:4001});var UM=class extends VM{constructor({message:e=`The requested method and/or account has not been authorized by the user.`}={}){super(4100,e),Object.defineProperty(this,`code`,{enumerable:!0,configurable:!0,writable:!0,value:4100}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Provider.UnauthorizedError`})}};Object.defineProperty(UM,`code`,{enumerable:!0,configurable:!0,writable:!0,value:4100});var WM=class extends VM{constructor({message:e=`The provider does not support the requested method.`}={}){super(4200,e),Object.defineProperty(this,`code`,{enumerable:!0,configurable:!0,writable:!0,value:4200}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Provider.UnsupportedMethodError`})}};Object.defineProperty(WM,`code`,{enumerable:!0,configurable:!0,writable:!0,value:4200});var GM=class extends VM{constructor({message:e=`The provider is disconnected from all chains.`}={}){super(4900,e),Object.defineProperty(this,`code`,{enumerable:!0,configurable:!0,writable:!0,value:4900}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Provider.DisconnectedError`})}};Object.defineProperty(GM,`code`,{enumerable:!0,configurable:!0,writable:!0,value:4900});var KM=class extends VM{constructor({message:e=`The provider is not connected to the requested chain.`}={}){super(4901,e),Object.defineProperty(this,`code`,{enumerable:!0,configurable:!0,writable:!0,value:4901}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Provider.ChainDisconnectedError`})}};Object.defineProperty(KM,`code`,{enumerable:!0,configurable:!0,writable:!0,value:4901});var qM=class extends VM{constructor({message:e=`An error occurred when attempting to switch chain.`}={}){super(4902,e),Object.defineProperty(this,`code`,{enumerable:!0,configurable:!0,writable:!0,value:4902}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Provider.SwitchChainError`})}};Object.defineProperty(qM,`code`,{enumerable:!0,configurable:!0,writable:!0,value:4902});var JM=class extends VM{constructor({message:e=`This Wallet does not support a capability that was not marked as optional.`}={}){super(5700,e),Object.defineProperty(this,`code`,{enumerable:!0,configurable:!0,writable:!0,value:5700}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Provider.UnsupportedNonOptionalCapabilityError`})}};Object.defineProperty(JM,`code`,{enumerable:!0,configurable:!0,writable:!0,value:5700});var YM=class extends VM{constructor({message:e=`This Wallet does not support the requested chain ID.`}={}){super(5710,e),Object.defineProperty(this,`code`,{enumerable:!0,configurable:!0,writable:!0,value:5710}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Provider.UnsupportedChainIdError`})}};Object.defineProperty(YM,`code`,{enumerable:!0,configurable:!0,writable:!0,value:5710});var XM=class extends VM{constructor({message:e=`There is already a bundle submitted with this ID.`}={}){super(5720,e),Object.defineProperty(this,`code`,{enumerable:!0,configurable:!0,writable:!0,value:5720}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Provider.DuplicateIdError`})}};Object.defineProperty(XM,`code`,{enumerable:!0,configurable:!0,writable:!0,value:5720});var ZM=class extends VM{constructor({message:e=`This bundle id is unknown / has not been submitted.`}={}){super(5730,e),Object.defineProperty(this,`code`,{enumerable:!0,configurable:!0,writable:!0,value:5730}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Provider.UnknownBundleIdError`})}};Object.defineProperty(ZM,`code`,{enumerable:!0,configurable:!0,writable:!0,value:5730});var QM=class extends VM{constructor({message:e=`The call bundle is too large for the Wallet to process.`}={}){super(5740,e),Object.defineProperty(this,`code`,{enumerable:!0,configurable:!0,writable:!0,value:5740}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Provider.BundleTooLargeError`})}};Object.defineProperty(QM,`code`,{enumerable:!0,configurable:!0,writable:!0,value:5740});var $M=class extends VM{constructor({message:e=`The Wallet can support atomicity after an upgrade, but the user rejected the upgrade.`}={}){super(5750,e),Object.defineProperty(this,`code`,{enumerable:!0,configurable:!0,writable:!0,value:5750}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Provider.AtomicReadyWalletRejectedUpgradeError`})}};Object.defineProperty($M,`code`,{enumerable:!0,configurable:!0,writable:!0,value:5750});var eN=class extends VM{constructor({message:e=`The wallet does not support atomic execution but the request requires it.`}={}){super(5760,e),Object.defineProperty(this,`code`,{enumerable:!0,configurable:!0,writable:!0,value:5760}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Provider.AtomicityNotSupportedError`})}};Object.defineProperty(eN,`code`,{enumerable:!0,configurable:!0,writable:!0,value:5760});function tN(){let e=new TM.default;return{get eventNames(){return e.eventNames.bind(e)},get listenerCount(){return e.listenerCount.bind(e)},get listeners(){return e.listeners.bind(e)},addListener:e.addListener.bind(e),emit:e.emit.bind(e),off:e.off.bind(e),on:e.on.bind(e),once:e.once.bind(e),removeAllListeners:e.removeAllListeners.bind(e),removeListener:e.removeListener.bind(e)}}function nN(e,t={}){let{includeEvents:n=!0}=t;if(!e)throw new iN;return{...n?{on:e.on?.bind(e),removeListener:e.removeListener?.bind(e)}:{},async request(t){try{let n=await e.request(t);return n&&typeof n==`object`&&`jsonrpc`in n?EM(n):n}catch(e){throw rN(e)}}}}function rN(e){let t=DM(e);if(t instanceof zM){if(!t.data)return t;let{code:e}=t.data;if(e===GM.code)return new GM(t);if(e===KM.code)return new KM(t);if(e===HM.code)return new HM(t);if(e===UM.code)return new UM(t);if(e===WM.code)return new WM(t);if(e===qM.code)return new qM(t);if(e===$M.code)return new $M(t);if(e===eN.code)return new eN(t);if(e===QM.code)return new QM(t);if(e===ZM.code)return new ZM(t);if(e===XM.code)return new XM(t);if(e===YM.code)return new YM(t);if(e===JM.code)return new JM(t)}return t}var iN=class extends P{constructor(){super(\"`provider` is undefined.\"),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Provider.IsUndefinedError`})}};const aN=()=>`IntersectionObserver`in window&&`IntersectionObserverEntry`in window&&`intersectionRatio`in IntersectionObserverEntry.prototype&&`isVisible`in IntersectionObserverEntry.prototype;function oN(e={}){let{prefix:t=`[Porto]`}=e,n=new Set;return{error:cN(console.error,{prefix:t}),errorOnce:cN(console.error,{memo:n,prefix:t}),log:cN(console.log,{prefix:t}),logOnce:cN(console.log,{memo:n,prefix:t}),warn:cN(console.warn,{prefix:t}),warnOnce:cN(console.warn,{memo:n,prefix:t})}}const sN=oN();function cN(e,t={}){let{memo:n,prefix:r}=t;return(...t)=>{let i=t.join(` `);n?.has(i)||(n?.add(i),e(`${r} ${i}`))}}function lN(){let e=navigator.userAgent.toLowerCase();return e.includes(`safari`)&&!e.includes(`chrome`)}function uN(){let e=navigator.userAgent.toLowerCase();return(e.includes(`firefox`)||e.includes(`fxios`))&&!e.includes(`seamonkey`)}function dN(){return window.navigator?.userAgentData?.mobile?!0:navigator.maxTouchPoints>1||/(android|bb\\d+|meego).+mobile|avantgo|bada\\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(navigator.userAgent)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw-(n|u)|c55\\/|capi|ccwa|cdm-|cell|chtm|cldc|cmd-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc-s|devi|dica|dmob|do(c|p)o|ds(12|-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(-|_)|g1 u|g560|gene|gf-5|g-mo|go(\\.w|od)|gr(ad|un)|haie|hcit|hd-(m|p|t)|hei-|hi(pt|ta)|hp( i|ip)|hs-c|ht(c(-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i-(20|go|ma)|i230|iac( |-|\\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\\/)|klon|kpt |kwc-|kyo(c|k)|le(no|xi)|lg( g|\\/(k|l|u)|50|54|-[a-w])|libw|lynx|m1-w|m3ga|m50\\/|ma(te|ui|xo)|mc(01|21|ca)|m-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|-([1-8]|c))|phil|pire|pl(ay|uc)|pn-2|po(ck|rt|se)|prox|psio|pt-g|qa-a|qc(07|12|21|32|60|-[2-7]|i-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h-|oo|p-)|sdk\\/|se(c(-|0|1)|47|mc|nd|ri)|sgh-|shar|sie(-|m)|sk-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h-|v-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl-|tdg-|tel(i|m)|tim-|t-mo|to(pl|sh)|ts(70|m-|m3|m5)|tx-9|up(\\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas-|your|zeto|zte-/i.test(navigator.userAgent.slice(0,4))}function fN(){let e=()=>void 0,t=()=>void 0;return{promise:new Promise((n,r)=>{e=n,t=r}),reject:t,resolve:e}}function pN(e){if(Array.isArray(e))return e.map(pN);if(typeof e==`function`)return;if(typeof e!=`object`||!e)return e;if(Object.getPrototypeOf(e)!==Object.prototype)try{return structuredClone(e)}catch{return}let t={};for(let[n,r]of Object.entries(e))t[n]=pN(r);return t}function mN(e,t){let n=[],r=new Set;for(let i of e){let e=t(i);r.has(e)||(r.add(e),n.push(i))}return n}function hN(){return typeof globalThis<`u`&&`crypto`in globalThis?globalThis.crypto.randomUUID():crypto.randomUUID()}function gN(e,{enabled:t=!0,id:n}){if(!t||!n)return e();if(gN.cache.get(n))return gN.cache.get(n);let r=e().finally(()=>gN.cache.delete(n));return gN.cache.set(n,r),r}(function(e){e.cache=new Map})(gN||={});function _N(e){return e}function vN(e,t={}){let{targetOrigin:n}=t,r=new Map;return _N({destroy(){for(let t of r.values())e.removeEventListener(`message`,t)},on(t,i,a){function o(e){e.data.topic===t&&(a&&e.data.id!==a||n&&e.origin!==n||i(e.data.payload,e))}return e.addEventListener(`message`,o),r.set(t,o),()=>e.removeEventListener(`message`,o)},async send(t,r,i){let a=hN();return e.postMessage(pN({id:a,payload:r,topic:t}),i??n??`*`),{id:a,payload:r,topic:t}},async sendAsync(e,t,n){let{id:r}=await this.send(e,t,n);return new Promise(t=>this.on(e,t,r))}})}function yN(e){let{from:t,to:n,waitForReady:r=!1}=e,i=!1,a=fN();t.on(`ready`,a.resolve);let o=_N({destroy(){t.destroy(),n.destroy(),i&&a.reject()},on(e,n,r){return t.on(e,n,r)},async send(e,t){return i=!0,r&&await a.promise.finally(()=>i=!1),n.send(e,t)},async sendAsync(e,t){return i=!0,r&&await a.promise.finally(()=>i=!1),n.sendAsync(e,t)}});return{...o,ready(e){o.send(`ready`,e)},waitForReady(){return a.promise}}}const bN={local:`http://localhost:5175/dialog/`,prod:`https://id.porto.sh/dialog`,stg:`https://stg.id.porto.sh/dialog`};function xN(e){return e}function SN(e={}){let{skipProtocolCheck:t,skipUnsupported:n}=e,r=e=>!n&&lN()&&e?.some(e=>[`wallet_connect`,`eth_requestAccounts`].includes(e.method));return typeof window>`u`?wN():xN({name:`iframe`,setup(e){let{host:n,internal:i,theme:a,themeController:o}=e,{store:s}=i,c=CN().setup(e),l=!1,u=new URL(n),d=document.createElement(`dialog`);d.dataset.porto=``,d.setAttribute(`role`,`dialog`),d.setAttribute(`aria-closed`,`true`),d.setAttribute(`aria-label`,`Porto Wallet`),d.setAttribute(`hidden`,`until-found`),Object.assign(d.style,{background:`transparent`,border:`0`,outline:`0`,padding:`0`,position:`fixed`}),document.body.appendChild(d);let f=document.createElement(`iframe`);f.setAttribute(`data-testid`,`porto`);let p=[`payment`,`publickey-credentials-get ${u.origin}`,`publickey-credentials-create ${u.origin}`];uN()||p.push(`clipboard-write`),f.setAttribute(`allow`,p.join(`; `)),f.setAttribute(`tabindex`,`0`),f.setAttribute(`sandbox`,`allow-forms allow-scripts allow-same-origin allow-popups allow-popups-to-escape-sandbox`),f.setAttribute(`src`,AN(n)),f.setAttribute(`title`,`Porto`),Object.assign(f.style,{backgroundColor:`transparent`,border:`0`,colorScheme:`light dark`,height:`100%`,left:`0`,position:`fixed`,top:`0`,width:`100%`});let m=document.createElement(`style`);m.innerHTML=`\n        dialog[data-porto]::backdrop {\n          background: transparent!important;\n        }\n      `,d.appendChild(m),d.appendChild(f);let h=yN({from:vN(window,{targetOrigin:u.origin}),to:vN(f.contentWindow,{targetOrigin:u.origin}),waitForReady:!0});o?._setup(h,!0);let g=window.matchMedia(`(max-width: 460px)`),_=()=>{h.send(`__internal`,{type:`resize`,width:g.matches?460:461})};g.addEventListener(`change`,_),h.on(`ready`,t=>{let n=e.internal.store.getState().chainIds.filter(e=>t.chainIds.includes(e));n.length===0&&(n=t.chainIds),s.setState(e=>({...e,chainIds:n})),h.send(`__internal`,{chainIds:n,mode:`iframe`,referrer:DN(),theme:a,type:`init`}),_()}),h.on(`rpc-response`,e=>{r([e._request])&&(f.src=f.src),kN(s,e)}),h.on(`__internal`,e=>{e.type===`switch`&&e.mode===`popup`&&(c.open(),c.syncRequests(s.getState().requestQueue))});let v=null,y=null,b=()=>ON(s),x=e=>{e.key===`Escape`&&ON(s)},S=new MutationObserver(e=>{for(let t of e){if(t.type!==`attributes`)continue;let e=t.attributeName;e&&e===`inert`&&d.removeAttribute(e)}});S.observe(d,{attributeOldValue:!0,attributes:!0});let C=!1,w=()=>{C&&(C=!1,d.removeEventListener(`click`,b),document.removeEventListener(`keydown`,x),d.style.pointerEvents=`none`,y?.focus(),y=null,Object.assign(document.body.style,v??``),document.body.style.overflow=v?.overflow??``)},ee=()=>{C||(C=!0,d.addEventListener(`click`,b),document.addEventListener(`keydown`,x),f.focus(),d.style.pointerEvents=`auto`,v=Object.assign({},document.body.style),document.body.style.overflow=`hidden`)},te=!1,ne=()=>{te||(te=!0,document.activeElement instanceof HTMLElement&&(y=document.activeElement),d.removeAttribute(`hidden`),d.removeAttribute(`aria-closed`),d.showModal())},re=()=>{if(te){te=!1,d.setAttribute(`hidden`,`true`),d.setAttribute(`aria-closed`,`true`),d.close();for(let e of d.parentNode?Array.from(d.parentNode.children):[])e!==d&&e.hasAttribute(`inert`)&&e.removeAttribute(`inert`)}};return{close(){c.close(),l=!1,h.send(`__internal`,{mode:`iframe`,referrer:DN(),type:`init`}),re(),w()},destroy(){c.close(),l=!1,w(),re(),c.destroy(),h.destroy(),d.remove(),S.disconnect(),g.removeEventListener(`change`,_)},open(){l||(l=!0,ne(),ee(),h.send(`__internal`,{mode:`iframe`,referrer:DN(),type:`init`}))},async secure(){let{trustedHosts:e}=await h.waitForReady(),n=(()=>{if(t)return!0;let e=window.location.protocol.startsWith(`https`);return e||sN.warnOnce(`Detected insecure protocol (HTTP).`,`\\n\\nThe Porto iframe is not supported on HTTP origins (${window.location.origin})`,`due to lack of WebAuthn support.`,`See https://porto.sh/sdk#secure-origins-https for more information.`),e})(),r=aN(),i=!!e?.includes(window.location.hostname),a=!!(r||i);return a||sN.warnOnce([`Warning: Browser does not support IntersectionObserver v2 or host \"${u.hostname}\" is not trusted by Porto.`,`This may result in the dialog falling back to a popup.`,``,`Add \"${u.hostname}\" to the trusted hosts list to enable iframe dialog: https://github.com/ithacaxyz/porto/edit/main/src/trusted-hosts.ts`].join(`\n`)),{frame:a,host:i,protocol:n}},async syncRequests(e){let{methodPolicies:t}=await h.waitForReady(),n=await this.secure(),i=e?.every(e=>t?.find(t=>t.method===e.request.method)?.modes?.headless===!0),a=r(e.map(e=>e.request));if(!i&&(a||!n.protocol||!n.frame))c.syncRequests(e);else{let n=e.some(e=>EN(e.request,{methodPolicies:t,targetOrigin:u.origin}));!l&&n&&this.open(),h.send(`rpc-requests`,e)}}}},supportsHeadless:!0})}function CN(e={}){if(typeof window>`u`)return wN();let{type:t=`auto`,size:n=TN}=e;return xN({name:`popup`,setup(e){let{host:r,internal:i,themeController:a}=e,{store:o}=i,s=new URL(r),c=null,l=t===`page`||t===`auto`&&dN()?`page`:`popup`;function u(){c&&ON(o)}let d=(()=>{let e=setInterval(()=>{c?.closed&&ON(o)},100);return()=>clearInterval(e)})(),f;return a?._setup(null,!0),{close(){c&&=(c.close(),null)},destroy(){this.close(),window.removeEventListener(`focus`,u),f?.destroy(),d()},open(){if(l===`popup`){let e=(window.innerWidth-n.width)/2+window.screenX,t=window.screenY+100;c=window.open(AN(r),`_blank`,`width=${n.width},height=${n.height},left=${e},top=${t}`)}else c=window.open(AN(r),`_blank`);if(!c)throw Error(`Failed to open popup`);f=yN({from:vN(window,{targetOrigin:s.origin}),to:vN(c,{targetOrigin:s.origin}),waitForReady:!0}),a?._setup(f,!1),f.send(`__internal`,{mode:l===`page`?`page`:`popup`,referrer:DN(),theme:a?.getTheme()??e.theme,type:`init`}),f.on(`rpc-response`,e=>kN(o,e)),window.removeEventListener(`focus`,u),window.addEventListener(`focus`,u)},async secure(){return{frame:!0,host:!0,protocol:!0}},async syncRequests(e){e.some(e=>EN(e.request))&&((!c||c.closed)&&this.open(),c?.focus()),f?.send(`rpc-requests`,e)}}},supportsHeadless:!1})}function wN(){return xN({name:`noop`,setup(){return{close(){},destroy(){},open(){},async secure(){return{frame:!0,host:!0,protocol:!0}},async syncRequests(){}}},supportsHeadless:!0})}const TN={height:282,width:360};function EN(e,t={}){let{methodPolicies:n,targetOrigin:r}=t,i=n?.find(t=>t.method===e.method);return i&&i.modes?.headless?!!(typeof i.modes.headless==`object`&&i.modes.headless.sameOrigin&&r!==window.location.origin):!0}function DN(){return{icon:(()=>{let e=document.querySelector(`link[rel=\"icon\"][media=\"(prefers-color-scheme: dark)\"]`)?.href,t=document.querySelector(`link[rel=\"icon\"][media=\"(prefers-color-scheme: light)\"]`)?.href??document.querySelector(`link[rel=\"icon\"]`)?.href;return e&&t&&e!==t?{dark:e,light:t}:window.matchMedia(`(prefers-color-scheme: dark)`).matches?e:t})(),title:document.title}}function ON(e){e.setState(e=>({...e,requestQueue:e.requestQueue.map(e=>({account:e.account,error:new HM,request:e.request,status:`error`}))}))}function kN(e,t){e.setState(e=>({...e,requestQueue:e.requestQueue.map(e=>e.request.id===t.id?t.error?{account:e.account,error:t.error,request:e.request,status:`error`}:{account:e.account,request:e.request,result:t.result,status:`success`}:e)}))}function AN(e){let t=new URL(e),n=new URLSearchParams(window.location.search);for(let[e,r]of n.entries())e.startsWith(`porto.`)&&t.searchParams.set(e.slice(6),r);return t.toString()}function jN(e){let t=new CustomEvent(`eip6963:announceProvider`,{detail:Object.freeze(e)});window.dispatchEvent(t);let n=()=>window.dispatchEvent(t);return window.addEventListener(`eip6963:requestProvider`,n),()=>window.removeEventListener(`eip6963:requestProvider`,n)}Object.freeze({status:`aborted`});function z(e,t,n){function r(n,r){var i;for(let a in Object.defineProperty(n,`_zod`,{value:n._zod??{},enumerable:!1}),(i=n._zod).traits??(i.traits=new Set),n._zod.traits.add(e),t(n,r),o.prototype)a in n||Object.defineProperty(n,a,{value:o.prototype[a].bind(n)});n._zod.constr=o,n._zod.def=r}let i=n?.Parent??Object;class a extends i{}Object.defineProperty(a,`name`,{value:e});function o(e){var t;let i=n?.Parent?new a:this;r(i,e),(t=i._zod).deferred??(t.deferred=[]);for(let e of i._zod.deferred)e();return i}return Object.defineProperty(o,`init`,{value:r}),Object.defineProperty(o,Symbol.hasInstance,{value:t=>n?.Parent&&t instanceof n.Parent?!0:t?._zod?.traits?.has(e)}),Object.defineProperty(o,`name`,{value:e}),o}var MN=class extends Error{constructor(){super(`Encountered Promise during synchronous parse. Use .parseAsync() instead.`)}};const NN={};function PN(e){return e&&Object.assign(NN,e),NN}function FN(e,t){return typeof t==`bigint`?t.toString():t}function IN(e){return{get value(){{let t=e();return Object.defineProperty(this,`value`,{value:t}),t}throw Error(`cached value already set`)}}}function LN(e){return e==null}function RN(e){let t=e.startsWith(`^`)?1:0,n=e.endsWith(`$`)?e.length-1:e.length;return e.slice(t,n)}var zN=Symbol(`evaluating`);function BN(e,t,n){let r;Object.defineProperty(e,t,{get(){if(r!==zN)return r===void 0&&(r=zN,r=n()),r},set(n){Object.defineProperty(e,t,{value:n})},configurable:!0})}function VN(e,t,n){Object.defineProperty(e,t,{value:n,writable:!0,enumerable:!0,configurable:!0})}function HN(...e){let t={};for(let n of e){let e=Object.getOwnPropertyDescriptors(n);Object.assign(t,e)}return Object.defineProperties({},t)}const UN=`captureStackTrace`in Error?Error.captureStackTrace:(...e)=>{};function WN(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function GN(e){if(WN(e)===!1)return!1;let t=e.constructor;if(t===void 0)return!0;let n=t.prototype;return!(WN(n)===!1||Object.prototype.hasOwnProperty.call(n,`isPrototypeOf`)===!1)}const KN=new Set([`string`,`number`,`bigint`,`boolean`,`symbol`,`undefined`]);function qN(e){return e.replace(/[.*+?^${}()|[\\]\\\\]/g,`\\\\$&`)}function JN(e,t,n){let r=new e._zod.constr(t??e._zod.def);return(!t||n?.parent)&&(r._zod.parent=e),r}function YN(e){let t=e;if(!t)return{};if(typeof t==`string`)return{error:()=>t};if(t?.message!==void 0){if(t?.error!==void 0)throw Error(\"Cannot specify both `message` and `error` params\");t.error=t.message}return delete t.message,typeof t.error==`string`?{...t,error:()=>t.error}:t}function XN(e){return Object.keys(e).filter(t=>e[t]._zod.optin===`optional`&&e[t]._zod.optout===`optional`)}-Number.MAX_VALUE,Number.MAX_VALUE;function ZN(e,t){let n=e._zod.def,r=HN(e._zod.def,{get shape(){let e={};for(let r in t){if(!(r in n.shape))throw Error(`Unrecognized key: \"${r}\"`);t[r]&&(e[r]=n.shape[r])}return VN(this,`shape`,e),e},checks:[]});return JN(e,r)}function QN(e,t){let n=e._zod.def,r=HN(e._zod.def,{get shape(){let r={...e._zod.def.shape};for(let e in t){if(!(e in n.shape))throw Error(`Unrecognized key: \"${e}\"`);t[e]&&delete r[e]}return VN(this,`shape`,r),r},checks:[]});return JN(e,r)}function $N(e,t,n){let r=HN(t._zod.def,{get shape(){let r=t._zod.def.shape,i={...r};if(n)for(let t in n){if(!(t in r))throw Error(`Unrecognized key: \"${t}\"`);n[t]&&(i[t]=e?new e({type:`optional`,innerType:r[t]}):r[t])}else for(let t in r)i[t]=e?new e({type:`optional`,innerType:r[t]}):r[t];return VN(this,`shape`,i),i},checks:[]});return JN(t,r)}function eP(e,t=0){if(e.aborted===!0)return!0;for(let n=t;n<e.issues.length;n++)if(e.issues[n]?.continue!==!0)return!0;return!1}function tP(e,t){return t.map(t=>{var n;return(n=t).path??(n.path=[]),t.path.unshift(e),t})}function nP(e){return typeof e==`string`?e:e?.message}function rP(e,t,n){let r={...e,path:e.path??[]};return e.message||(r.message=nP(e.inst?._zod.def?.error?.(e))??nP(t?.error?.(e))??nP(n.customError?.(e))??nP(n.localeError?.(e))??`Invalid input`),delete r.inst,delete r.continue,t?.reportInput||delete r.input,r}function iP(e){return Array.isArray(e)?`array`:typeof e==`string`?`string`:`unknown`}var aP=(e,t)=>{e.name=`$ZodError`,Object.defineProperty(e,`_zod`,{value:e._zod,enumerable:!1}),Object.defineProperty(e,`issues`,{value:t,enumerable:!1}),e.message=JSON.stringify(t,FN,2),Object.defineProperty(e,`toString`,{value:()=>e.message,enumerable:!1})};const oP=z(`$ZodError`,aP),sP=z(`$ZodError`,aP,{Parent:Error}),cP=e=>(t,n,r,i)=>{let a=r?Object.assign(r,{async:!1}):{async:!1},o=t._zod.run({value:n,issues:[]},a);if(o instanceof Promise)throw new MN;if(o.issues.length){let t=new(i?.Err??e)(o.issues.map(e=>rP(e,a,PN())));throw UN(t,i?.callee),t}return o.value},lP=cP(sP),uP=(e=>async(t,n,r,i)=>{let a=r?Object.assign(r,{async:!0}):{async:!0},o=t._zod.run({value:n,issues:[]},a);if(o instanceof Promise&&(o=await o),o.issues.length){let t=new(i?.Err??e)(o.issues.map(e=>rP(e,a,PN())));throw UN(t,i?.callee),t}return o.value})(sP),dP=(e=>(t,n,r)=>{let i=r?{...r,async:!1}:{async:!1},a=t._zod.run({value:n,issues:[]},i);if(a instanceof Promise)throw new MN;return a.issues.length?{success:!1,error:new(e??oP)(a.issues.map(e=>rP(e,i,PN())))}:{success:!0,data:a.value}})(sP),fP=(e=>async(t,n,r)=>{let i=r?Object.assign(r,{async:!0}):{async:!0},a=t._zod.run({value:n,issues:[]},i);return a instanceof Promise&&(a=await a),a.issues.length?{success:!1,error:new e(a.issues.map(e=>rP(e,i,PN())))}:{success:!0,data:a.value}})(sP),pP=(e=>(t,n,r)=>{let i=r?Object.assign(r,{direction:`backward`}):{direction:`backward`};return cP(e)(t,n,i)})(sP),mP=(e=>(t,n,r)=>cP(e)(t,n,r))(sP),hP=e=>{let t=e?`[\\\\s\\\\S]{${e?.minimum??0},${e?.maximum??``}}`:`[\\\\s\\\\S]*`;return RegExp(`^${t}$`)},gP=/^-?\\d+n?$/,_P=/^-?\\d+(?:\\.\\d+)?/,vP=/^(?:true|false)$/i;var yP=/^null$/i,bP=/^undefined$/i;const xP=z(`$ZodCheck`,(e,t)=>{var n;e._zod??={},e._zod.def=t,(n=e._zod).onattach??(n.onattach=[])});var SP={number:`number`,bigint:`bigint`,object:`date`};const CP=z(`$ZodCheckGreaterThan`,(e,t)=>{xP.init(e,t);let n=SP[typeof t.value];e._zod.onattach.push(e=>{let n=e._zod.bag,r=(t.inclusive?n.minimum:n.exclusiveMinimum)??-1/0;t.value>r&&(t.inclusive?n.minimum=t.value:n.exclusiveMinimum=t.value)}),e._zod.check=r=>{(t.inclusive?r.value>=t.value:r.value>t.value)||r.issues.push({origin:n,code:`too_small`,minimum:t.value,input:r.value,inclusive:t.inclusive,inst:e,continue:!t.abort})}}),wP=z(`$ZodCheckMinLength`,(e,t)=>{var n;xP.init(e,t),(n=e._zod.def).when??(n.when=e=>{let t=e.value;return!LN(t)&&t.length!==void 0}),e._zod.onattach.push(e=>{let n=e._zod.bag.minimum??-1/0;t.minimum>n&&(e._zod.bag.minimum=t.minimum)}),e._zod.check=n=>{let r=n.value;if(r.length>=t.minimum)return;let i=iP(r);n.issues.push({origin:i,code:`too_small`,minimum:t.minimum,inclusive:!0,input:r,inst:e,continue:!t.abort})}}),TP=z(`$ZodCheckStringFormat`,(e,t)=>{var n,r;xP.init(e,t),e._zod.onattach.push(e=>{let n=e._zod.bag;n.format=t.format,t.pattern&&(n.patterns??=new Set,n.patterns.add(t.pattern))}),t.pattern?(n=e._zod).check??(n.check=n=>{t.pattern.lastIndex=0,!t.pattern.test(n.value)&&n.issues.push({origin:`string`,code:`invalid_format`,format:t.format,input:n.value,...t.pattern?{pattern:t.pattern.toString()}:{},inst:e,continue:!t.abort})}):(r=e._zod).check??(r.check=()=>{})}),EP=z(`$ZodCheckRegex`,(e,t)=>{TP.init(e,t),e._zod.check=n=>{t.pattern.lastIndex=0,!t.pattern.test(n.value)&&n.issues.push({origin:`string`,code:`invalid_format`,format:`regex`,input:n.value,pattern:t.pattern.toString(),inst:e,continue:!t.abort})}}),DP={major:4,minor:1,patch:12},OP=z(`$ZodType`,(e,t)=>{var n;e??={},e._zod.def=t,e._zod.bag=e._zod.bag||{},e._zod.version=DP;let r=[...e._zod.def.checks??[]];e._zod.traits.has(`$ZodCheck`)&&r.unshift(e);for(let t of r)for(let n of t._zod.onattach)n(e);if(r.length===0)(n=e._zod).deferred??(n.deferred=[]),e._zod.deferred?.push(()=>{e._zod.run=e._zod.parse});else{let t=(e,t,n)=>{let r=eP(e),i;for(let a of t){if(a._zod.def.when){if(!a._zod.def.when(e))continue}else if(r)continue;let t=e.issues.length,o=a._zod.check(e);if(o instanceof Promise&&n?.async===!1)throw new MN;if(i||o instanceof Promise)i=(i??Promise.resolve()).then(async()=>{await o,e.issues.length!==t&&(r||=eP(e,t))});else{if(e.issues.length===t)continue;r||=eP(e,t)}}return i?i.then(()=>e):e},n=(n,i,a)=>{if(eP(n))return n.aborted=!0,n;let o=t(i,r,a);if(o instanceof Promise){if(a.async===!1)throw new MN;return o.then(t=>e._zod.parse(t,a))}return e._zod.parse(o,a)};e._zod.run=(i,a)=>{if(a.skipChecks)return e._zod.parse(i,a);if(a.direction===`backward`){let t=e._zod.parse({value:i.value,issues:[]},{...a,skipChecks:!0});return t instanceof Promise?t.then(e=>n(e,i,a)):n(t,i,a)}let o=e._zod.parse(i,a);if(o instanceof Promise){if(a.async===!1)throw new MN;return o.then(e=>t(e,r,a))}return t(o,r,a)}}e[`~standard`]={validate:t=>{try{let n=dP(e,t);return n.success?{value:n.data}:{issues:n.error?.issues}}catch{return fP(e,t).then(e=>e.success?{value:e.data}:{issues:e.error?.issues})}},vendor:`zod`,version:1}}),kP=z(`$ZodString`,(e,t)=>{OP.init(e,t),e._zod.pattern=[...e?._zod.bag?.patterns??[]].pop()??hP(e._zod.bag),e._zod.parse=(n,r)=>{if(t.coerce)try{n.value=String(n.value)}catch{}return typeof n.value==`string`||n.issues.push({expected:`string`,code:`invalid_type`,input:n.value,inst:e}),n}}),AP=z(`$ZodNumber`,(e,t)=>{OP.init(e,t),e._zod.pattern=e._zod.bag.pattern??_P,e._zod.parse=(n,r)=>{if(t.coerce)try{n.value=Number(n.value)}catch{}let i=n.value;if(typeof i==`number`&&!Number.isNaN(i)&&Number.isFinite(i))return n;let a=typeof i==`number`?Number.isNaN(i)?`NaN`:Number.isFinite(i)?void 0:`Infinity`:void 0;return n.issues.push({expected:`number`,code:`invalid_type`,input:i,inst:e,...a?{received:a}:{}}),n}}),jP=z(`$ZodBoolean`,(e,t)=>{OP.init(e,t),e._zod.pattern=vP,e._zod.parse=(n,r)=>{if(t.coerce)try{n.value=!!n.value}catch{}let i=n.value;return typeof i==`boolean`||n.issues.push({expected:`boolean`,code:`invalid_type`,input:i,inst:e}),n}}),MP=z(`$ZodBigInt`,(e,t)=>{OP.init(e,t),e._zod.pattern=gP,e._zod.parse=(n,r)=>{if(t.coerce)try{n.value=BigInt(n.value)}catch{}return typeof n.value==`bigint`||n.issues.push({expected:`bigint`,code:`invalid_type`,input:n.value,inst:e}),n}}),NP=z(`$ZodUndefined`,(e,t)=>{OP.init(e,t),e._zod.pattern=bP,e._zod.values=new Set([void 0]),e._zod.optin=`optional`,e._zod.optout=`optional`,e._zod.parse=(t,n)=>{let r=t.value;return r===void 0||t.issues.push({expected:`undefined`,code:`invalid_type`,input:r,inst:e}),t}}),PP=z(`$ZodNull`,(e,t)=>{OP.init(e,t),e._zod.pattern=yP,e._zod.values=new Set([null]),e._zod.parse=(t,n)=>{let r=t.value;return r===null||t.issues.push({expected:`null`,code:`invalid_type`,input:r,inst:e}),t}}),FP=z(`$ZodAny`,(e,t)=>{OP.init(e,t),e._zod.parse=e=>e}),IP=z(`$ZodUnknown`,(e,t)=>{OP.init(e,t),e._zod.parse=e=>e}),LP=z(`$ZodDate`,(e,t)=>{OP.init(e,t),e._zod.parse=(n,r)=>{if(t.coerce)try{n.value=new Date(n.value)}catch{}let i=n.value,a=i instanceof Date;return a&&!Number.isNaN(i.getTime())||n.issues.push({expected:`date`,code:`invalid_type`,input:i,...a?{received:`Invalid Date`}:{},inst:e}),n}});function RP(e,t,n){e.issues.length&&t.issues.push(...tP(n,e.issues)),t.value[n]=e.value}const zP=z(`$ZodArray`,(e,t)=>{OP.init(e,t),e._zod.parse=(n,r)=>{let i=n.value;if(!Array.isArray(i))return n.issues.push({expected:`array`,code:`invalid_type`,input:i,inst:e}),n;n.value=Array(i.length);let a=[];for(let e=0;e<i.length;e++){let o=i[e],s=t.element._zod.run({value:o,issues:[]},r);s instanceof Promise?a.push(s.then(t=>RP(t,n,e))):RP(s,n,e)}return a.length?Promise.all(a).then(()=>n):n}});function BP(e,t,n,r){e.issues.length&&t.issues.push(...tP(n,e.issues)),e.value===void 0?n in r&&(t.value[n]=void 0):t.value[n]=e.value}function VP(e){let t=Object.keys(e.shape);for(let n of t)if(!e.shape?.[n]?._zod?.traits?.has(`$ZodType`))throw Error(`Invalid element at key \"${n}\": expected a Zod schema`);let n=XN(e.shape);return{...e,keys:t,keySet:new Set(t),numKeys:t.length,optionalKeys:new Set(n)}}function HP(e,t,n,r,i,a){let o=[],s=i.keySet,c=i.catchall._zod,l=c.def.type;for(let i of Object.keys(t)){if(s.has(i))continue;if(l===`never`){o.push(i);continue}let a=c.run({value:t[i],issues:[]},r);a instanceof Promise?e.push(a.then(e=>BP(e,n,i,t))):BP(a,n,i,t)}return o.length&&n.issues.push({code:`unrecognized_keys`,keys:o,input:t,inst:a}),e.length?Promise.all(e).then(()=>n):n}const UP=z(`$ZodObject`,(e,t)=>{if(OP.init(e,t),!Object.getOwnPropertyDescriptor(t,`shape`)?.get){let e=t.shape;Object.defineProperty(t,`shape`,{get:()=>{let n={...e};return Object.defineProperty(t,`shape`,{value:n}),n}})}let n=IN(()=>VP(t));BN(e._zod,`propValues`,()=>{let e=t.shape,n={};for(let t in e){let r=e[t]._zod;if(r.values){n[t]??(n[t]=new Set);for(let e of r.values)n[t].add(e)}}return n});let r=WN,i=t.catchall,a;e._zod.parse=(t,o)=>{a??=n.value;let s=t.value;if(!r(s))return t.issues.push({expected:`object`,code:`invalid_type`,input:s,inst:e}),t;t.value={};let c=[],l=a.shape;for(let e of a.keys){let n=l[e]._zod.run({value:s[e],issues:[]},o);n instanceof Promise?c.push(n.then(n=>BP(n,t,e,s))):BP(n,t,e,s)}return i?HP(c,s,t,o,n.value,e):c.length?Promise.all(c).then(()=>t):t}});function WP(e,t,n,r){for(let n of e)if(n.issues.length===0)return t.value=n.value,t;let i=e.filter(e=>!eP(e));return i.length===1?(t.value=i[0].value,i[0]):(t.issues.push({code:`invalid_union`,input:t.value,inst:n,errors:e.map(e=>e.issues.map(e=>rP(e,r,PN())))}),t)}const GP=z(`$ZodUnion`,(e,t)=>{OP.init(e,t),BN(e._zod,`optin`,()=>t.options.some(e=>e._zod.optin===`optional`)?`optional`:void 0),BN(e._zod,`optout`,()=>t.options.some(e=>e._zod.optout===`optional`)?`optional`:void 0),BN(e._zod,`values`,()=>{if(t.options.every(e=>e._zod.values))return new Set(t.options.flatMap(e=>Array.from(e._zod.values)))}),BN(e._zod,`pattern`,()=>{if(t.options.every(e=>e._zod.pattern)){let e=t.options.map(e=>e._zod.pattern);return RegExp(`^(${e.map(e=>RN(e.source)).join(`|`)})$`)}});let n=t.options.length===1,r=t.options[0]._zod.run;e._zod.parse=(i,a)=>{if(n)return r(i,a);let o=!1,s=[];for(let e of t.options){let t=e._zod.run({value:i.value,issues:[]},a);if(t instanceof Promise)s.push(t),o=!0;else{if(t.issues.length===0)return t;s.push(t)}}return o?Promise.all(s).then(t=>WP(t,i,e,a)):WP(s,i,e,a)}}),KP=z(`$ZodDiscriminatedUnion`,(e,t)=>{GP.init(e,t);let n=e._zod.parse;BN(e._zod,`propValues`,()=>{let e={};for(let n of t.options){let r=n._zod.propValues;if(!r||Object.keys(r).length===0)throw Error(`Invalid discriminated union option at index \"${t.options.indexOf(n)}\"`);for(let[t,n]of Object.entries(r)){e[t]||(e[t]=new Set);for(let r of n)e[t].add(r)}}return e});let r=IN(()=>{let e=t.options,n=new Map;for(let r of e){let e=r._zod.propValues?.[t.discriminator];if(!e||e.size===0)throw Error(`Invalid discriminated union option at index \"${t.options.indexOf(r)}\"`);for(let t of e){if(n.has(t))throw Error(`Duplicate discriminator value \"${String(t)}\"`);n.set(t,r)}}return n});e._zod.parse=(i,a)=>{let o=i.value;if(!WN(o))return i.issues.push({code:`invalid_type`,expected:`object`,input:o,inst:e}),i;let s=r.value.get(o?.[t.discriminator]);return s?s._zod.run(i,a):t.unionFallback?n(i,a):(i.issues.push({code:`invalid_union`,errors:[],note:`No matching discriminator`,discriminator:t.discriminator,input:o,path:[t.discriminator],inst:e}),i)}}),qP=z(`$ZodTuple`,(e,t)=>{OP.init(e,t);let n=t.items,r=n.length-[...n].reverse().findIndex(e=>e._zod.optin!==`optional`);e._zod.parse=(i,a)=>{let o=i.value;if(!Array.isArray(o))return i.issues.push({input:o,inst:e,expected:`tuple`,code:`invalid_type`}),i;i.value=[];let s=[];if(!t.rest){let t=o.length>n.length,a=o.length<r-1;if(t||a)return i.issues.push({...t?{code:`too_big`,maximum:n.length}:{code:`too_small`,minimum:n.length},input:o,inst:e,origin:`array`}),i}let c=-1;for(let e of n){if(c++,c>=o.length&&c>=r)continue;let t=e._zod.run({value:o[c],issues:[]},a);t instanceof Promise?s.push(t.then(e=>JP(e,i,c))):JP(t,i,c)}if(t.rest){let e=o.slice(n.length);for(let n of e){c++;let e=t.rest._zod.run({value:n,issues:[]},a);e instanceof Promise?s.push(e.then(e=>JP(e,i,c))):JP(e,i,c)}}return s.length?Promise.all(s).then(()=>i):i}});function JP(e,t,n){e.issues.length&&t.issues.push(...tP(n,e.issues)),t.value[n]=e.value}const YP=z(`$ZodRecord`,(e,t)=>{OP.init(e,t),e._zod.parse=(n,r)=>{let i=n.value;if(!GN(i))return n.issues.push({expected:`record`,code:`invalid_type`,input:i,inst:e}),n;let a=[];if(t.keyType._zod.values){let o=t.keyType._zod.values;n.value={};for(let e of o)if(typeof e==`string`||typeof e==`number`||typeof e==`symbol`){let o=t.valueType._zod.run({value:i[e],issues:[]},r);o instanceof Promise?a.push(o.then(t=>{t.issues.length&&n.issues.push(...tP(e,t.issues)),n.value[e]=t.value})):(o.issues.length&&n.issues.push(...tP(e,o.issues)),n.value[e]=o.value)}let s;for(let e in i)o.has(e)||(s??=[],s.push(e));s&&s.length>0&&n.issues.push({code:`unrecognized_keys`,input:i,inst:e,keys:s})}else{n.value={};for(let o of Reflect.ownKeys(i)){if(o===`__proto__`)continue;let s=t.keyType._zod.run({value:o,issues:[]},r);if(s instanceof Promise)throw Error(`Async schemas not supported in object keys currently`);if(s.issues.length){n.issues.push({code:`invalid_key`,origin:`record`,issues:s.issues.map(e=>rP(e,r,PN())),input:o,path:[o],inst:e}),n.value[s.value]=s.value;continue}let c=t.valueType._zod.run({value:i[o],issues:[]},r);c instanceof Promise?a.push(c.then(e=>{e.issues.length&&n.issues.push(...tP(o,e.issues)),n.value[s.value]=e.value})):(c.issues.length&&n.issues.push(...tP(o,c.issues)),n.value[s.value]=c.value)}}return a.length?Promise.all(a).then(()=>n):n}}),XP=z(`$ZodLiteral`,(e,t)=>{if(OP.init(e,t),t.values.length===0)throw Error(`Cannot create literal schema with no valid values`);e._zod.values=new Set(t.values),e._zod.pattern=RegExp(`^(${t.values.map(e=>typeof e==`string`?qN(e):e?qN(e.toString()):String(e)).join(`|`)})$`),e._zod.parse=(n,r)=>{let i=n.value;return e._zod.values.has(i)||n.issues.push({code:`invalid_value`,values:t.values,input:i,inst:e}),n}});function ZP(e,t){return e.issues.length&&t===void 0?{issues:[],value:void 0}:e}const QP=z(`$ZodOptional`,(e,t)=>{OP.init(e,t),e._zod.optin=`optional`,e._zod.optout=`optional`,BN(e._zod,`values`,()=>t.innerType._zod.values?new Set([...t.innerType._zod.values,void 0]):void 0),BN(e._zod,`pattern`,()=>{let e=t.innerType._zod.pattern;return e?RegExp(`^(${RN(e.source)})?$`):void 0}),e._zod.parse=(e,n)=>{if(t.innerType._zod.optin===`optional`){let r=t.innerType._zod.run(e,n);return r instanceof Promise?r.then(t=>ZP(t,e.value)):ZP(r,e.value)}return e.value===void 0?e:t.innerType._zod.run(e,n)}}),$P=z(`$ZodNullable`,(e,t)=>{OP.init(e,t),BN(e._zod,`optin`,()=>t.innerType._zod.optin),BN(e._zod,`optout`,()=>t.innerType._zod.optout),BN(e._zod,`pattern`,()=>{let e=t.innerType._zod.pattern;return e?RegExp(`^(${RN(e.source)}|null)$`):void 0}),BN(e._zod,`values`,()=>t.innerType._zod.values?new Set([...t.innerType._zod.values,null]):void 0),e._zod.parse=(e,n)=>e.value===null?e:t.innerType._zod.run(e,n)}),eF=z(`$ZodPipe`,(e,t)=>{OP.init(e,t),BN(e._zod,`values`,()=>t.in._zod.values),BN(e._zod,`optin`,()=>t.in._zod.optin),BN(e._zod,`optout`,()=>t.out._zod.optout),BN(e._zod,`propValues`,()=>t.in._zod.propValues),e._zod.parse=(e,n)=>{if(n.direction===`backward`){let r=t.out._zod.run(e,n);return r instanceof Promise?r.then(e=>tF(e,t.in,n)):tF(r,t.in,n)}let r=t.in._zod.run(e,n);return r instanceof Promise?r.then(e=>tF(e,t.out,n)):tF(r,t.out,n)}});function tF(e,t,n){return e.issues.length?(e.aborted=!0,e):t._zod.run({value:e.value,issues:e.issues},n)}const nF=z(`$ZodCodec`,(e,t)=>{OP.init(e,t),BN(e._zod,`values`,()=>t.in._zod.values),BN(e._zod,`optin`,()=>t.in._zod.optin),BN(e._zod,`optout`,()=>t.out._zod.optout),BN(e._zod,`propValues`,()=>t.in._zod.propValues),e._zod.parse=(e,n)=>{if((n.direction||`forward`)===`forward`){let r=t.in._zod.run(e,n);return r instanceof Promise?r.then(e=>rF(e,t,n)):rF(r,t,n)}else{let r=t.out._zod.run(e,n);return r instanceof Promise?r.then(e=>rF(e,t,n)):rF(r,t,n)}}});function rF(e,t,n){if(e.issues.length)return e.aborted=!0,e;if((n.direction||`forward`)===`forward`){let r=t.transform(e.value,e);return r instanceof Promise?r.then(r=>iF(e,r,t.out,n)):iF(e,r,t.out,n)}else{let r=t.reverseTransform(e.value,e);return r instanceof Promise?r.then(r=>iF(e,r,t.in,n)):iF(e,r,t.in,n)}}function iF(e,t,n,r){return e.issues.length?(e.aborted=!0,e):n._zod.run({value:t,issues:e.issues},r)}const aF=z(`$ZodReadonly`,(e,t)=>{OP.init(e,t),BN(e._zod,`propValues`,()=>t.innerType._zod.propValues),BN(e._zod,`values`,()=>t.innerType._zod.values),BN(e._zod,`optin`,()=>t.innerType._zod.optin),BN(e._zod,`optout`,()=>t.innerType._zod.optout),e._zod.parse=(e,n)=>{if(n.direction===`backward`)return t.innerType._zod.run(e,n);let r=t.innerType._zod.run(e,n);return r instanceof Promise?r.then(oF):oF(r)}});function oF(e){return e.value=Object.freeze(e.value),e}const sF=z(`$ZodTemplateLiteral`,(e,t)=>{OP.init(e,t);let n=[];for(let e of t.parts)if(typeof e==`object`&&e){if(!e._zod.pattern)throw Error(`Invalid template literal part, no pattern found: ${[...e._zod.traits].shift()}`);let t=e._zod.pattern instanceof RegExp?e._zod.pattern.source:e._zod.pattern;if(!t)throw Error(`Invalid template literal part: ${e._zod.traits}`);let r=t.startsWith(`^`)?1:0,i=t.endsWith(`$`)?t.length-1:t.length;n.push(t.slice(r,i))}else if(e===null||KN.has(typeof e))n.push(qN(`${e}`));else throw Error(`Invalid template literal part: ${e}`);e._zod.pattern=RegExp(`^${n.join(``)}$`),e._zod.parse=(n,r)=>typeof n.value==`string`?(e._zod.pattern.lastIndex=0,e._zod.pattern.test(n.value)||n.issues.push({input:n.value,inst:e,code:`invalid_format`,format:t.format??`template_literal`,pattern:e._zod.pattern.source}),n):(n.issues.push({input:n.value,inst:e,expected:`template_literal`,code:`invalid_type`}),n)});function cF(e,t){return new e({type:`string`,...YN(t)})}function lF(e,t){return new e({type:`number`,checks:[],...YN(t)})}function uF(e,t){return new e({type:`boolean`,...YN(t)})}function dF(e,t){return new e({type:`bigint`,...YN(t)})}function fF(e,t){return new e({type:`undefined`,...YN(t)})}function pF(e,t){return new e({type:`null`,...YN(t)})}function mF(e){return new e({type:`any`})}function hF(e){return new e({type:`unknown`})}function gF(e,t){return new e({type:`date`,...YN(t)})}function _F(e,t){return new CP({check:`greater_than`,...YN(t),value:e,inclusive:!0})}function vF(e,t){return new wP({check:`min_length`,...YN(t),minimum:e})}function yF(e,t){return new EP({check:`string_format`,format:`regex`,...YN(t),pattern:e})}const bF=z(`ZodMiniType`,(e,t)=>{if(!e._zod)throw Error(`Uninitialized schema in ZodMiniType.`);OP.init(e,t),e.def=t,e.type=t.type,e.parse=(t,n)=>lP(e,t,n,{callee:e.parse}),e.safeParse=(t,n)=>dP(e,t,n),e.parseAsync=async(t,n)=>uP(e,t,n,{callee:e.parseAsync}),e.safeParseAsync=async(t,n)=>fP(e,t,n),e.check=(...n)=>e.clone({...t,checks:[...t.checks??[],...n.map(e=>typeof e==`function`?{_zod:{check:e,def:{check:`custom`},onattach:[]}}:e)]}),e.clone=(t,n)=>JN(e,t,n),e.brand=()=>e,e.register=((t,n)=>(t.add(e,n),e))}),xF=z(`ZodMiniString`,(e,t)=>{kP.init(e,t),bF.init(e,t)});function B(e){return cF(xF,e)}const SF=z(`ZodMiniNumber`,(e,t)=>{AP.init(e,t),bF.init(e,t)});function V(e){return lF(SF,e)}const CF=z(`ZodMiniBoolean`,(e,t)=>{jP.init(e,t),bF.init(e,t)});function wF(e){return uF(CF,e)}const TF=z(`ZodMiniBigInt`,(e,t)=>{MP.init(e,t),bF.init(e,t)});function EF(e){return dF(TF,e)}const DF=z(`ZodMiniUndefined`,(e,t)=>{NP.init(e,t),bF.init(e,t)});function OF(e){return fF(DF,e)}const kF=z(`ZodMiniNull`,(e,t)=>{PP.init(e,t),bF.init(e,t)});function AF(e){return pF(kF,e)}const jF=z(`ZodMiniAny`,(e,t)=>{FP.init(e,t),bF.init(e,t)});function MF(){return mF(jF)}const NF=z(`ZodMiniUnknown`,(e,t)=>{IP.init(e,t),bF.init(e,t)});function PF(){return hF(NF)}const FF=z(`ZodMiniDate`,(e,t)=>{LP.init(e,t),bF.init(e,t)});function IF(e){return gF(FF,e)}const LF=z(`ZodMiniArray`,(e,t)=>{zP.init(e,t),bF.init(e,t)});function H(e,t){return new LF({type:`array`,element:e,...YN(t)})}const RF=z(`ZodMiniObject`,(e,t)=>{UP.init(e,t),bF.init(e,t),BN(e,`shape`,()=>t.shape)});function U(e,t){let n={type:`object`,shape:e??{},...YN(t)};return new RF(n)}function zF(e,t){return ZN(e,t)}function BF(e,t){return QN(e,t)}function VF(e,t){return $N(YF,e,t)}const HF=z(`ZodMiniUnion`,(e,t)=>{GP.init(e,t),bF.init(e,t)});function W(e,t){return new HF({type:`union`,options:e,...YN(t)})}const UF=z(`ZodMiniDiscriminatedUnion`,(e,t)=>{KP.init(e,t),bF.init(e,t)});function WF(e,t,n){return new UF({type:`union`,options:t,discriminator:e,...YN(n)})}const GF=z(`ZodMiniTuple`,(e,t)=>{qP.init(e,t),bF.init(e,t)});function G(e,t,n){let r=t instanceof OP;return new GF({type:`tuple`,items:e,rest:r?t:null,...YN(r?n:t)})}const KF=z(`ZodMiniRecord`,(e,t)=>{YP.init(e,t),bF.init(e,t)});function qF(e,t,n){return new KF({type:`record`,keyType:e,valueType:t,...YN(n)})}const JF=z(`ZodMiniLiteral`,(e,t)=>{XP.init(e,t),bF.init(e,t)});function K(e,t){return new JF({type:`literal`,values:Array.isArray(e)?e:[e],...YN(t)})}const YF=z(`ZodMiniOptional`,(e,t)=>{QP.init(e,t),bF.init(e,t)});function q(e){return new YF({type:`optional`,innerType:e})}const XF=z(`ZodMiniNullable`,(e,t)=>{$P.init(e,t),bF.init(e,t)});function ZF(e){return new XF({type:`nullable`,innerType:e})}function QF(e){return q(ZF(e))}const $F=z(`ZodMiniPipe`,(e,t)=>{eF.init(e,t),bF.init(e,t)}),eI=z(`ZodMiniCodec`,(e,t)=>{$F.init(e,t),nF.init(e,t)});function tI(e,t,n){return new eI({type:`pipe`,in:e,out:t,transform:n.decode,reverseTransform:n.encode})}const nI=z(`ZodMiniReadonly`,(e,t)=>{aF.init(e,t),bF.init(e,t)});function J(e){return new nI({type:`readonly`,innerType:e})}const rI=z(`ZodMiniTemplateLiteral`,(e,t)=>{sF.init(e,t),bF.init(e,t)});function iI(e,t){return new rI({type:`template_literal`,parts:e,...YN(t)})}Lf(),Jd(),op(),pf();function aI(e){let{domain:t,message:n,primaryType:r,types:i}=e,a=(e,t)=>{for(let n of e){let{name:e,type:r}=n,o=t[e],s=r.match(fg);if(s&&(typeof o==`number`||typeof o==`bigint`)){let[,e,t]=s;I(o,{signed:e===`int`,size:Number.parseInt(t??``,10)/8})}if(r===`address`&&typeof o==`string`&&!og(o))throw new sg({address:o,cause:new cg});let c=r.match(dg);if(c){let[,e]=c;if(e&&qf(o)!==Number.parseInt(e,10))throw new fI({expectedSize:Number.parseInt(e,10),givenSize:qf(o)})}let l=i[r];l&&(bI(r),a(l,o))}};if(i.EIP712Domain&&t){if(typeof t!=`object`)throw new pI({domain:t});a(i.EIP712Domain,t)}if(r!==`EIP712Domain`)if(i[r])a(i[r],n);else throw new mI({primaryType:r,types:i})}function oI(e){let{domain:t={},message:n,primaryType:r}=e,i={EIP712Domain:cI(t),...e.types};aI({domain:t,message:n,primaryType:r,types:i});let a=[`0x19`,`0x01`];return t&&a.push(uI({domain:t,types:i})),r!==`EIP712Domain`&&a.push(dI({data:n,primaryType:r,types:i})),zf(...a)}function sI(e){let{primaryType:t,types:n}=e,r=``,i=yI({primaryType:t,types:n});i.delete(t);let a=[t,...Array.from(i).sort()];for(let e of a)r+=`${e}(${(n[e]??[]).map(({name:e,type:t})=>`${t} ${e}`).join(`,`)})`;return r}function cI(e){return[typeof e?.name==`string`&&{name:`name`,type:`string`},e?.version&&{name:`version`,type:`string`},(typeof e?.chainId==`number`||typeof e?.chainId==`bigint`)&&{name:`chainId`,type:`uint256`},e?.verifyingContract&&{name:`verifyingContract`,type:`address`},e?.salt&&{name:`salt`,type:`bytes32`}].filter(Boolean)}function lI(e){return Hh(oI(e))}function uI(e){let{domain:t,types:n}=e;return dI({data:t,primaryType:`EIP712Domain`,types:{...n,EIP712Domain:n?.EIP712Domain||cI(t)}})}function dI(e){let{data:t,primaryType:n,types:r}=e,i=gI({data:t,primaryType:n,types:r});return Hh(i)}var fI=class extends P{constructor({expectedSize:e,givenSize:t}){super(`Expected bytes${e}, got bytes${t}.`),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`TypedData.BytesSizeMismatchError`})}},pI=class extends P{constructor({domain:e}){super(`Invalid domain \"${df(e)}\".`,{metaMessages:[`Must be a valid EIP-712 domain.`]}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`TypedData.InvalidDomainError`})}},mI=class extends P{constructor({primaryType:e,types:t}){super(`Invalid primary type \\`${e}\\` must be one of \\`${JSON.stringify(Object.keys(t))}\\`.`,{metaMessages:[\"Check that the primary type is a key in `types`.\"]}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`TypedData.InvalidPrimaryTypeError`})}},hI=class extends P{constructor({type:e}){super(`Struct type \"${e}\" is invalid.`,{metaMessages:[`Struct type must not be a Solidity type.`]}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`TypedData.InvalidStructTypeError`})}};function gI(e){let{data:t,primaryType:n,types:r}=e,i=[{type:`bytes32`}],a=[_I({primaryType:n,types:r})];for(let e of r[n]??[]){let[n,o]=vI({types:r,name:e.name,type:e.type,value:t[e.name]});i.push(n),a.push(o)}return Hg(i,a)}function _I(e){let{primaryType:t,types:n}=e,r=Uf(sI({primaryType:t,types:n}));return Hh(r)}function vI(e){let{types:t,name:n,type:r,value:i}=e;if(t[r]!==void 0)return[{type:`bytes32`},Hh(gI({data:i,primaryType:r,types:t}))];if(r===`bytes`)return i=`0x${(i.length%2?`0`:``)+i.slice(2)}`,[{type:`bytes32`},Hh(i,{as:`Hex`})];if(r===`string`)return[{type:`bytes32`},Hh(vf(i),{as:`Hex`})];if(r.lastIndexOf(`]`)===r.length-1){let e=r.slice(0,r.lastIndexOf(`[`)),a=i.map(r=>vI({name:n,type:e,types:t,value:r}));return[{type:`bytes32`},Hh(Hg(a.map(([e])=>e),a.map(([,e])=>e)))]}return[{type:r},i]}function yI(e,t=new Set){let{primaryType:n,types:r}=e,i=n.match(/^\\w*/u)?.[0];if(t.has(i)||r[i]===void 0)return t;t.add(i);for(let e of r[i])yI({primaryType:e.type,types:r},t);return t}function bI(e){if(e===`address`||e===`bool`||e===`string`||e.startsWith(`bytes`)||e.startsWith(`uint`)||e.startsWith(`int`))throw new hI({type:e})}pi(),Ci();function xI(e){if(typeof e==`string`){if(!bi(e,{strict:!1}))throw new fi({address:e});return{address:e,type:`json-rpc`}}if(!bi(e.address,{strict:!1}))throw new fi({address:e.address});return{address:e.address,nonceManager:e.nonceManager,sign:e.sign,signAuthorization:e.signAuthorization,signMessage:e.signMessage,signTransaction:e.signTransaction,signTypedData:e.signTypedData,source:`custom`,type:`local`}}Is(),Sl(),Hc();var SI=Ac(BigInt(`0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff`)),CI=SI.create(BigInt(`-3`)),wI=BigInt(`0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b`);const TI=xl({a:CI,b:wI,Fp:SI,n:BigInt(`0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551`),Gx:BigInt(`0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296`),Gy:BigInt(`0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5`),h:BigInt(1),lowS:!1},Ns);var EI=Ac(BigInt(`0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000ffffffff`)),DI=EI.create(BigInt(`-3`)),OI=BigInt(`0xb3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aef`);xl({a:DI,b:OI,Fp:EI,n:BigInt(`0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52973`),Gx:BigInt(`0xaa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7`),Gy:BigInt(`0x3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f`),h:BigInt(1),lowS:!1},Fs);var kI=Ac(BigInt(`0x1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff`)),AI=kI.create(BigInt(`-3`)),jI=BigInt(`0x0051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef109e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00`);xl({a:AI,b:jI,Fp:kI,n:BigInt(`0x01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386409`),Gx:BigInt(`0x00c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66`),Gy:BigInt(`0x011839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650`),h:BigInt(1),lowS:!1,allowedPrivateKeyLengths:[130,131,132]},Ps);const MI=TI,NI=TI;Lf(),op();function PI(e){let{privateKey:t}=e,n=NI.ProjectivePoint.fromPrivateKey(typeof t==`string`?t.slice(2):Hf(t).slice(2));return Gh(n)}function FI(e={}){let{as:t=`Hex`}=e,n=NI.utils.randomPrivateKey();return t===`Hex`?Hf(n):n}function II(e){let{extraEntropy:t=!1,hash:n,payload:r,privateKey:i}=e,{r:a,s:o,recovery:s}=NI.sign(r instanceof Uint8Array?r:_f(r),i instanceof Uint8Array?i:_f(i),{extraEntropy:typeof t==`boolean`?t:Bf(t).slice(2),lowS:!0,...n?{prehash:!0}:{}});return{r:a,s:o,yParity:s}}Jd();function LI(e,t=0){if(!/^(-?)([0-9]*)\\.?([0-9]*)$/.test(e))throw new RI({value:e});let[n=``,r=`0`]=e.split(`.`),i=n.startsWith(`-`);if(i&&(n=n.slice(1)),r=r.replace(/(0+)$/,``),t===0)Math.round(Number(`.${r}`))===1&&(n=`${BigInt(n)+1n}`),r=``;else if(r.length>t){let[e,i,a]=[r.slice(0,t-1),r.slice(t-1,t),r.slice(t)],o=Math.round(Number(`${i}.${a}`));r=o>9?`${BigInt(e)+BigInt(1)}0`.padStart(e.length+1,`0`):`${e}${o}`,r.length>t&&(r=r.slice(1),n=`${BigInt(n)+1n}`),r=r.slice(0,t)}else r=r.padEnd(t,`0`);return BigInt(`${i?`-`:``}${n}${r}`)}var RI=class extends P{constructor({value:e}){super(`Value \\`${e}\\` is not a valid decimal number.`),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Value.InvalidDecimalNumberError`})}};Lf();var zI=new TextEncoder,BI=new TextDecoder,VI=Object.fromEntries(Array.from(`ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/`).map((e,t)=>[t,e.charCodeAt(0)])),HI={...Object.fromEntries(Array.from(`ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/`).map((e,t)=>[e.charCodeAt(0),t])),61:0,45:62,95:63};function UI(e,t={}){let{pad:n=!0,url:r=!1}=t,i=new Uint8Array(Math.ceil(e.length/3)*4);for(let t=0,n=0;n<e.length;t+=4,n+=3){let r=(e[n]<<16)+(e[n+1]<<8)+(e[n+2]|0);i[t]=VI[r>>18],i[t+1]=VI[r>>12&63],i[t+2]=VI[r>>6&63],i[t+3]=VI[r&63]}let a=e.length%3,o=Math.floor(e.length/3)*4+(a&&a+1),s=BI.decode(new Uint8Array(i.buffer,0,o));return n&&a===1&&(s+=`==`),n&&a===2&&(s+=`=`),r&&(s=s.replaceAll(`+`,`-`).replaceAll(`/`,`_`)),s}function WI(e,t={}){return UI(_f(e),t)}function GI(e){let t=e.replace(/=+$/,``),n=t.length,r=new Uint8Array(n+3);zI.encodeInto(t+`===`,r);for(let e=0,n=0;e<t.length;e+=4,n+=3){let t=(HI[r[e]]<<18)+(HI[r[e+1]]<<12)+(HI[r[e+2]]<<6)+HI[r[e+3]];r[n]=t>>16,r[n+1]=t>>8&255,r[n+2]=t&255}let i=(n>>2)*3+(n%4&&n%4-1);return new Uint8Array(r.buffer,0,i)}op();function KI(e){let t=e[4]===0?5:4,n=t+32,r=e[n+2]===0?n+3:n+2,i=BigInt(Hf(e.slice(t,n))),a=BigInt(Hf(e.slice(r)));return{r:i,s:a>MI.CURVE.n/2n?MI.CURVE.n-a:a}}async function qI(e){try{let t=e.getPublicKey();if(!t)throw new nL;let n=new Uint8Array(t),r=await crypto.subtle.importKey(`spki`,new Uint8Array(n),{name:`ECDSA`,namedCurve:`P-256`,hash:`SHA-256`},!0,[`verify`]),i=new Uint8Array(await crypto.subtle.exportKey(`raw`,r));return Gh(i)}catch(t){if(t.message!==`Permission denied to access object`)throw t;let n=new Uint8Array(e.attestationObject),r=e=>{let t=new Uint8Array([e,88,32]);for(let e=0;e<n.length-t.length;e++)if(t.every((t,r)=>n[e+r]===t))return e+t.length;throw new nL},i=r(33),a=r(34);return Gh(new Uint8Array([4,...n.slice(i,i+32),...n.slice(a,a+32)]))}}Lf(),Jd(),op();const JI=Uint8Array.from([105,171,180,181,160,222,75,198,42,42,32,31,141,37,186,233]);async function YI(e){let{createFn:t=window.navigator.credentials.create.bind(window.navigator.credentials),...n}=e,r=QI(n);try{let e=await t(r);if(!e)throw new nL;let n=e.response,i=await qI(n);return{id:e.id,publicKey:i,raw:e}}catch(e){throw new nL({cause:e})}}function XI(e={}){let{flag:t=5,rpId:n=window.location.hostname,signCount:r=0}=e,i=Uh(Uf(n)),a=I(t,{size:1}),o=I(r,{size:4});return zf(i,a,o)}function ZI(e){let{challenge:t,crossOrigin:n=!1,extraClientData:r,origin:i=window.location.origin}=e;return JSON.stringify({type:`webauthn.get`,challenge:WI(t,{url:!0,pad:!1}),origin:i,crossOrigin:n,...r})}function QI(e){let{attestation:t=`none`,authenticatorSelection:n={residentKey:`preferred`,requireResidentKey:!1,userVerification:`required`},challenge:r=JI,excludeCredentialIds:i,extensions:a,name:o,rp:s={id:window.location.hostname,name:window.document.title},user:c}=e,l=c?.name??o;return{publicKey:{attestation:t,authenticatorSelection:n,challenge:r,...i?{excludeCredentials:i?.map(e=>({id:GI(e),type:`public-key`}))}:{},pubKeyCredParams:[{type:`public-key`,alg:-7}],...a&&{extensions:a},rp:s,user:{id:c?.id??Hh(vf(l),{as:`Bytes`}),name:l,displayName:c?.displayName??l}}}}function $I(e){let{credentialId:t,challenge:n,extensions:r,rpId:i=window.location.hostname,userVerification:a=`required`}=e;return{publicKey:{...t?{allowCredentials:Array.isArray(t)?t.map(e=>({id:GI(e),type:`public-key`})):[{id:GI(t),type:`public-key`}]}:{},challenge:_f(n),...r&&{extensions:r},rpId:i,userVerification:a}}}function eL(e){let{challenge:t,crossOrigin:n,extraClientData:r,flag:i,origin:a,rpId:o,signCount:s,userVerification:c=`required`}=e,l=XI({flag:i,rpId:o,signCount:s}),u=ZI({challenge:t,crossOrigin:n,extraClientData:r,origin:a}),d=Uh(Uf(u)),f=u.indexOf(`\"challenge\"`),p=u.indexOf(`\"type\"`),m={authenticatorData:l,clientDataJSON:u,challengeIndex:f,typeIndex:p,userVerificationRequired:c===`required`},h=zf(l,d);return{metadata:m,payload:h}}async function tL(e){let{getFn:t=window.navigator.credentials.get.bind(window.navigator.credentials),...n}=e,r=$I(n);try{let e=await t(r);if(!e)throw new rL;let n=e.response,i=String.fromCharCode(...new Uint8Array(n.clientDataJSON)),a=i.indexOf(`\"challenge\"`),o=i.indexOf(`\"type\"`),s=KI(new Uint8Array(n.signature));return{metadata:{authenticatorData:Hf(new Uint8Array(n.authenticatorData)),clientDataJSON:i,challengeIndex:a,typeIndex:o,userVerificationRequired:r.publicKey.userVerification===`required`},signature:s,raw:e}}catch(e){throw new rL({cause:e})}}var nL=class extends P{constructor({cause:e}={}){super(`Failed to create credential.`,{cause:e}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`WebAuthnP256.CredentialCreationFailedError`})}},rL=class extends P{constructor({cause:e}={}){super(`Failed to request credential.`,{cause:e}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`WebAuthnP256.CredentialRequestFailedError`})}};Lf();async function iL(e={}){let{extractable:t=!1}=e,n=await globalThis.crypto.subtle.generateKey({name:`ECDSA`,namedCurve:`P-256`},t,[`sign`,`verify`]),r=await globalThis.crypto.subtle.exportKey(`raw`,n.publicKey),i=Gh(new Uint8Array(r));return{privateKey:n.privateKey,publicKey:i}}async function aL(e){let{payload:t,privateKey:n}=e,r=await globalThis.crypto.subtle.sign({name:`ECDSA`,hash:`SHA-256`},n,hf(t)),i=gf(new Uint8Array(r)),a=Sf(xf(i,0,32)),o=Sf(xf(i,32,64));return o>MI.CURVE.n/2n&&(o=MI.CURVE.n-o),{r:a,s:o}}const oL=`0x32323232`;Lf(),op(),pf();const sL={p256:`p256`,secp256k1:`secp256k1`,webauthnp256:`webauthn-p256`},cL={admin:`admin`,normal:`session`},lL={0:`minute`,1:`hour`,2:`day`,3:`week`,4:`month`,5:`year`},uL={address:`secp256k1`,p256:`p256`,secp256k1:`secp256k1`,\"webauthn-p256\":`webauthnp256`},dL={admin:`admin`,session:`normal`},fL={address:2,p256:0,secp256k1:2,\"webauthn-p256\":1},pL={day:2,hour:1,minute:0,month:4,week:3,year:5};function mL(e={}){let t=FI();return yL({...e,privateKey:t})}async function hL(e){let{createFn:t,label:n,rpId:r,userId:i}=e,a=await YI({authenticatorSelection:{requireResidentKey:!0,residentKey:`required`,userVerification:`required`},createFn:t,extensions:{credProps:!0},rp:r?{id:r,name:r}:void 0,user:{displayName:n,id:new Uint8Array(i??vf(n)),name:n}});return xL({...e,credential:{id:a.id,publicKey:a.publicKey},id:i?wf(i):Jh(a.publicKey,{includePrefix:!1})})}function gL(e={}){let t=FI();return SL({...e,privateKey:t})}async function _L(e={}){let t=await iL();return CL({...e,keyPair:t})}function vL(e,t={}){let{chainId:n=e.chainId}=t,{expiry:r=0,id:i,prehash:a=!1,role:o=`admin`,type:s}=e,c=(()=>{let t=e.publicKey;return t===`0x`?t:s===`secp256k1`||s===`address`?qf(t)===20||Yf(Kf(t,0,12))===0n?Kf(t,-20):ig(qh(t)):t})();return{...e,chainId:n,expiry:r,hash:wL({publicKey:c,type:s}),id:(i??c).toLowerCase(),prehash:a,publicKey:c.toLowerCase(),role:o,type:s}}function yL(e){let{chainId:t,expiry:n,feeToken:r,permissions:i,privateKey:a,role:o}=e,s=Jh(PI({privateKey:a}),{includePrefix:!1});return vL({chainId:t,expiry:n,feeToken:r,permissions:i,privateKey(){return a},publicKey:s,role:o,type:`p256`})}function bL(e,t){let{chainId:n}=t,{publicKey:r}=e,i=qf(r)===20||Yf(Kf(r,0,12))===0n,a={};for(let t of e.permissions)t.type===`call`&&(a.calls??=[],a.calls.push({signature:t.selector,to:t.to===`0x3232323232323232323232323232323232323232`?void 0:t.to})),t.type===`spend`&&(a.spend??=[],a.spend.push({limit:t.limit,period:t.period,token:t.token}));return vL({chainId:n,expiry:e.expiry,permissions:a,publicKey:e.publicKey,role:cL[e.role],type:i?`address`:sL[e.type]})}function xL(e){let{credential:t,id:n,rpId:r}=e,i=Jh(t.publicKey,{includePrefix:!1});return vL({chainId:e.chainId,expiry:e.expiry??0,feeToken:e.feeToken,id:n,permissions:e.permissions,privateKey:{credential:t,rpId:r},publicKey:i,role:e.role,type:`webauthn-p256`})}function SL(e){let{privateKey:t}=e,n=Jh(PI({privateKey:t}),{includePrefix:!1});return vL({chainId:e.chainId,expiry:e.expiry??0,feeToken:e.feeToken,permissions:e.permissions,privateKey:{privateKey(){return t}},publicKey:n,role:e.role,type:`webauthn-p256`})}function CL(e){let{chainId:t,expiry:n,feeToken:r,keyPair:i,permissions:a,role:o}=e,{privateKey:s}=i,c=Jh(i.publicKey,{includePrefix:!1});return vL({chainId:t,expiry:n,feeToken:r,permissions:a,prehash:!0,privateKey:s,publicKey:c,role:o,type:`p256`})}function wL(e){let{type:t}=e,n=TL(e.publicKey);return Hh(Hg([{type:`uint8`},{type:`bytes32`}],[fL[t],Hh(n)]))}function TL(e){return qf(e)<32?Wf(e,32):e}async function EL(e,t){let{address:n,storage:r,webAuthn:i,wrap:a=!0}=t,{privateKey:o,publicKey:s,type:c}=e;if(!o)throw Error(`Key does not have a private key to sign with.\n\nKey:\n`+df(e,null,2));let l=(()=>n?lI({domain:{verifyingContract:n},message:{digest:t.payload},primaryType:`ERC1271Sign`,types:{ERC1271Sign:[{name:`digest`,type:`bytes32`}]}}):t.payload)(),[u,d]=await(async()=>{if(c===`p256`){let{privateKey:t}=e;if(typeof t==`function`)return[d_(II({payload:l,privateKey:t()})),!1];if(t instanceof CryptoKey)return[d_(await aL({payload:l,privateKey:t})),!0]}if(c===`secp256k1`)return[d_(A_({payload:l,privateKey:o()})),!1];if(c===`webauthn-p256`){if(o.privateKey){let{payload:e,metadata:t}=eL({challenge:l,origin:`https://ithaca.xyz`,rpId:`ithaca.xyz`}),{r:n,s:r}=II({hash:!0,payload:e,privateKey:o.privateKey()});return[AL({metadata:t,signature:{r:n,s:r}}),!1]}let{credential:t,rpId:n}=o,a=`porto.webauthnVerified.${e.hash}`,s=Date.now(),c=!0;if(r){let e=await r.getItem(a);c=!e||s-e>6e5}let{signature:{r:u,s:d},raw:f,metadata:p}=await tL({challenge:l,credentialId:t.id,getFn:i?.getFn,rpId:n,userVerification:c?`required`:`preferred`}),m=f.response;if(!m?.userHandle)throw Error(`No user handle in response`,{cause:{response:m}});let h=wf(new Uint8Array(m.userHandle));if(e.id&&og(e.id)&&!ag(e.id,h))throw Error(`supplied webauthn key \"${e.id}\" does not match signature webauthn key \"${h}\"`,{cause:{id:h,key:e}});return c&&r&&await r.setItem(a,s),[AL({metadata:p,signature:{r:u,s:d}}),!1]}throw Error(`Key type \"${c}\" is not supported.\\n\\nKey:\\n`+df(e,null,2))})();return a?jL(u,{keyType:c,prehash:d,publicKey:s}):u}function DL(e,t={}){let{expiry:n=0,prehash:r=!1,publicKey:i,role:a=`admin`,type:o}=e,{feeTokens:s,orchestrator:c}=t,l=Object.entries(OL(e,{feeTokens:s})).map(([e,t])=>{if(e===`calls`)return t.map(({signature:e,to:t})=>({selector:(()=>e?Zf(e)?e:Z_(e):oL)(),to:t??`0x3232323232323232323232323232323232323232`,type:`call`}));if(e!==`feeToken`){if(e===`spend`)return t.map(({limit:e,period:t,token:n})=>({limit:e,period:t,token:n,type:`spend`}));throw Error(`Invalid permission type \"${e}\".`)}}).flat().filter(Boolean);return e.role===`session`&&c&&l.push({selector:oL,to:c,type:`call`}),{expiry:n,permissions:l??[],prehash:r,publicKey:TL(i),role:dL[a],type:uL[o]}}function OL(e,t){let{permissions:n}=e,r=n?.calls?[...n.calls]:[],i=n?.spend?[...n.spend]:[],a=t.feeTokens?.filter(e=>e.feeToken);if(a&&a.length>0){let t=kL(e,{feeTokens:a});if(t){let e=-1,n=pL.year;for(let r=0;r<i.length;r++){let a=i[r];if(a.token&&ag(t.address,a.token)){e=r;break}if(!a.token&&t.address===`0x0000000000000000000000000000000000000000`){e=r;break}let o=pL[a.period];o<n&&(n=o)}e===-1?typeof n==`number`&&i.unshift({limit:t.value,period:lL[n],token:t.address}):(i[e]={...i[e],limit:i[e].limit+t.value},i.unshift(i.splice(e,1)[0]))}}return{...n,calls:r,spend:i}}function kL(e,t){let{feeTokens:n}=t;if(!e.feeToken)return;let r=n.find(t=>e.feeToken.symbol===t.symbol?!0:!e.feeToken.symbol||e.feeToken.symbol===`native`?t.address===Q_:!1);if(!r)return;let i=LI(e.feeToken.limit,r.decimals);return{...r,value:i}}function AL(e){let{metadata:t,signature:n}=e;return Hg(Wg([`struct WebAuthnAuth { bytes authenticatorData; string clientDataJSON; uint256 challengeIndex; uint256 typeIndex; bytes32 r; bytes32 s; }`,`WebAuthnAuth auth`]),[{authenticatorData:t.authenticatorData,challengeIndex:BigInt(t.challengeIndex),clientDataJSON:t.clientDataJSON,r:I(n.r,{size:32}),s:I(n.s,{size:32}),typeIndex:BigInt(t.typeIndex)}])}function jL(e,t){let{keyType:n,prehash:r=!1,publicKey:i}=t,a=wL({publicKey:i,type:n});return Ug([`bytes`,`bytes32`,`bool`],[e,a,r])}function ML(e){let t=typeof e==`string`?{address:e}:e,n=t.sign?`privateKey`:`porto`,{address:r,sign:i,signMessage:a,signTransaction:o,signTypedData:s,type:c}=xI({address:t.address,sign({hash:e}){if(n===`porto`)throw Error(\"`sign` not supported on porto accounts.\");if(!t.sign)throw Error(\"`sign` not supported.\");return t.sign({hash:e})},signMessage({message:e}){return this.sign({hash:Th(e)})},signTransaction(){throw Error(\"`signTransaction` not supported on porto accounts.\")},signTypedData(e){return this.sign({hash:Nh(e)})}});return{address:r,keys:t.keys??void 0,sign:i,signMessage:a,signTransaction:o,signTypedData:s,source:n,type:c}}function NL(e,t={}){let{keys:n}=t,r=ig(E_({privateKey:e}));return ML({address:r,keys:n,async sign({hash:t}){return d_(A_({payload:t,privateKey:e}))},source:`privateKey`})}function PL(e,t={}){let{key:n,role:r}=t;if(n!==null){if(typeof n==`object`)return n;if(e.keys&&e.keys.length>0)return typeof n==`number`?e.keys[n]:e.keys.find(e=>e.privateKey&&(!r||e.role===r))}}async function FL(e,t){let{storage:n,replaySafe:r=!0,wrap:i=!0,webAuthn:a}=t,o=PL(e,t),s=(()=>r?lI({domain:{verifyingContract:e.address},message:{digest:t.payload},primaryType:`ERC1271Sign`,types:{ERC1271Sign:[{name:`digest`,type:`bytes32`}]}}):t.payload)(),c=(()=>o?({hash:e})=>EL(o,{address:null,payload:e,storage:n,webAuthn:a,wrap:i}):e.source===`privateKey`?e.sign:void 0)();if(!c)throw Error(`cannot find key to sign with.`);return await c({hash:s})}op();function IL(e,t={}){return H_(e,t)}function LL(e,t,n){if(t===`Error`)return zL;if(t===`Panic`)return BL;if(Zf(t,{strict:!1})){let e=Kf(t,0,4);if(e===`0x08c379a0`)return zL;if(e===`0x4e487b71`)return BL}let r=U_(e,t,n);if(r.type!==`error`)throw new J_({name:t,type:`error`});return r}function RL(e){return W_(e)}const zL=IL({inputs:[{name:`message`,type:`string`}],name:`Error`,type:`error`}),BL=IL({inputs:[{name:`reason`,type:`uint8`}],name:`Panic`,type:`error`});O();var VL=class extends D{constructor(){super(`Function is not recognized.`,{metaMessages:[`This could be due to any of the following:`,`  - The contract does not have the function,`,`  - The address is not a contract.`],name:`FunctionSelectorNotRecognizedError`})}};za();function HL(e,t){let n=e.walk(e=>`data`in e);if(!n?.data)return e;if(n.data===RL(IL(`error FnSelectorNotRecognized()`)))return new VL;let r=null;for(let e of t.calls){let t=e;if(t.abi)try{if(!Ra({abi:t.abi,data:n.data}))continue;r=t}catch{}}return r?cs(n,{abi:r.abi,address:r.to,args:r.args,functionName:r.functionName}):e}Jd(),op();const Y=()=>iI([`0x`,B()],{message:`Needs string in format ^0x[A-Fa-f0-9]{40}$.`}),X=()=>iI([`0x`,B()],{message:`Needs string in format ^0x[A-Fa-f0-9]+$.`}),Z=()=>tI(X(),V(),{decode:e=>Xf(e),encode:e=>I(e)}),Q=()=>tI(X(),EF({message:`Required bigint`}),{decode:e=>Yf(e),encode:e=>I(e)});function UL(e){return W(e)}var WL=class extends P{constructor(){super(...arguments),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Schema.ValidationError`})}};function GL(e){let t=e,n=`Validation failed with ${t.issues.length} error${t.issues.length===1?``:`s`}:`;n+=`\n`;for(let e of t.issues)e&&(n+=`\n`,n+=KL(e));return new WL(n)}function KL(e,t=0){let n=qL(e.path),r=`- ${n?`${n}: `:``}`,i=`  `.repeat(t+1),a=r;switch(e.code){case`invalid_type`:{let t=e.expected,n=e.input?JL(e):`undefined`;a+=`Expected ${t}. ${e.message===`Invalid input`?``:e.message}`,n!==`undefined`&&(a+=`but received ${n}`);break}case`too_big`:{let t=e.maximum,n=e.inclusive??!0;e.exact??!1?a+=`${e.origin} must be exactly ${t}`:a+=`${e.origin} must be ${n?`at most`:`less than`} ${t}`;break}case`too_small`:{let t=e.minimum,n=e.inclusive??!0;e.exact??!1?a+=`${e.origin} must be exactly ${t}`:a+=`${e.origin} must be ${n?`at least`:`greater than`} ${t}`;break}case`invalid_format`:switch(e.format){case`regex`:a+=`Must match pattern: ${e.pattern}`;break;case`starts_with`:a+=`Must start with \"${e.prefix}\"`;break;case`ends_with`:a+=`Must end with \"${e.suffix}\"`;break;case`includes`:a+=`Must include \"${e.includes}\"`;break;case`template_literal`:a+=`Must match pattern: ${e.pattern}`;break;default:a+=`Invalid ${e.format} format`}break;case`not_multiple_of`:a+=`Number must be a multiple of ${e.divisor}`;break;case`unrecognized_keys`:{let t=e.keys.map(e=>`\"${e}\"`).join(`, `);a+=`Unrecognized key${e.keys.length>1?`s`:``}: ${t}`;break}case`invalid_union`:{let n=e.errors&&e.errors.length>0;a+=`Invalid union value.`,n&&e.errors.forEach(e=>{e.length>0&&e.forEach(e=>{a+=`\n`,a+=i,a+=KL(e,t+1)})});break}case`invalid_key`:a+=`Invalid ${e.origin} key`,e.issues&&e.issues.length>0&&e.issues.forEach(e=>{a+=`\n`,a+=i,a+=KL(e,t+1)});break;case`invalid_element`:a+=`Invalid ${e.origin} element at key \"${e.key}\"`,e.issues&&e.issues.length>0&&e.issues.forEach(e=>{a+=`\n`,a+=i,a+=KL(e,t+1)});break;case`invalid_value`:{let t=e.values.map(e=>JSON.stringify(e)).join(`, `);e.values.length>1?a+=`Expected one of: ${t}`:a+=`Expected ${t}`;break}case`custom`:a+=e.message||`Custom validation failed`;break;default:a+=e.message||`Validation failed`}return a}function qL(e){return e.length===0?``:\"at `\"+e.map((e,t)=>typeof e==`number`?`[${e}]`:typeof e==`symbol`?`[${e.toString()}]`:/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(e)&&t>0?`.${e}`:t===0&&/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(e)?e:`[\"${e}\"]`).join(``)+\"`\"}function JL(e){let t=e.input;if(t===void 0)return`undefined`;if(t===null)return`null`;let n=typeof t;return n===`object`?Array.isArray(t)?`array`:t instanceof Date?`date`:t instanceof Map?`map`:t instanceof Set?`set`:`object`:n}const YL=U({selector:X(),to:Y(),type:K(`call`)}),XL=U({limit:Q(),period:W([K(`minute`),K(`hour`),K(`day`),K(`week`),K(`month`),K(`year`)]),token:q(W([Y(),AF()])),type:K(`spend`)}),ZL=W([YL,XL]),QL=U({expiry:Z(),prehash:q(wF()),publicKey:X(),role:W([K(`admin`),K(`normal`)]),type:W([K(`p256`),K(`secp256k1`),K(`webauthnp256`)])}),$L=U({...QL.shape,permissions:J(H(ZL))});var eR;(function(e){e.AssetDiffAsset=W([U({address:q(W([Y(),AF()])),decimals:q(W([V(),AF()])),direction:W([K(`incoming`),K(`outgoing`)]),fiat:q(U({currency:B(),value:tI(B(),V(),{decode:e=>Number(e),encode:e=>String(e)})})),name:q(W([B(),AF()])),symbol:B(),type:K(`erc20`),value:Q()}),U({address:q(W([Y(),AF()])),direction:W([K(`incoming`),K(`outgoing`)]),fiat:q(U({currency:B(),value:tI(B(),V(),{decode:e=>Number(e),encode:e=>String(e)})})),name:q(W([B(),AF()])),symbol:B(),type:K(`erc721`),uri:B(),value:Q()}),U({address:AF(),decimals:q(W([V(),AF()])),direction:W([K(`incoming`),K(`outgoing`)]),fiat:q(U({currency:B(),value:tI(B(),V(),{decode:e=>Number(e),encode:e=>String(e)})})),symbol:B(),type:AF(),value:Q()})]),e.Response=qF(X(),J(H(J(G([Y(),J(H(e.AssetDiffAsset))])))))})(eR||={});var tR;(function(e){e.Request=J(H($L)),e.Response=J(H(U({...$L.shape,hash:X()})))})(tR||={});var nR;(function(e){e.Response=qF(X(),U({currency:B(),value:B()}))})(nR||={});var rR;(function(e){e.Request=U({feePayer:q(Y()),feeToken:q(Y()),nonce:q(Q())})})(rR||={});var iR;(function(e){e.Request=J(H(U({address:Y(),value:Q()})))})(iR||={});var aR;(function(e){e.Request=J(H(U({hash:X()}))),e.Response=J(H(U({hash:X()})))})(aR||={});const oR=U({eoa:Y(),executionData:X(),nonce:X(),signature:X()}),sR=U({...oR.shape,chainId:Z()}),cR=W([U({combinedGas:Q(),encodedFundTransfers:J(H(X())),encodedPreCalls:J(H(X())),eoa:Y(),executionData:X(),expiry:Q(),funder:Y(),funderSignature:X(),isMultichain:wF(),nonce:Q(),payer:Y(),paymentAmount:Q(),paymentMaxAmount:Q(),paymentRecipient:Y(),paymentSignature:X(),paymentToken:Y(),settler:Y(),settlerContext:X(),signature:X(),supportedAccountImplementation:Y()}),U({combinedGas:Q(),encodedFundTransfers:J(H(X())),encodedPreCalls:J(H(X())),eoa:Y(),executionData:X(),expiry:Q(),funder:Y(),funderSignature:X(),isMultichain:wF(),nonce:Q(),payer:Y(),paymentRecipient:Y(),paymentSignature:X(),paymentToken:Y(),prePaymentAmount:Q(),prePaymentMaxAmount:Q(),settler:Y(),settlerContext:X(),signature:X(),supportedAccountImplementation:Y(),totalPaymentAmount:Q(),totalPaymentMaxAmount:Q()})]);U({eoa:Y(),executionData:X(),nonce:Q()});const lR=U({address:W([Y(),AF()]),decimals:q(V()),deficit:Q(),fiat:q(U({currency:B(),value:B()})),name:q(B()),required:Q(),symbol:q(B())}),uR=U({additionalAuthorization:QF(U({address:Y(),chainId:Z(),nonce:Z(),r:X(),s:X(),yParity:Z()})),assetDeficits:q(H(lR)),authorizationAddress:q(W([Y(),AF()])),chainId:Z(),ethPrice:Q(),extraPayment:Q(),feeTokenDeficit:Q(),intent:cR,nativeFeeEstimate:U({maxFeePerGas:Q(),maxPriorityFeePerGas:Q()}),orchestrator:Y(),paymentTokenDecimals:V(),txGas:Q()}),dR=U({multiChainRoot:q(W([X(),AF()])),quotes:J(H(uR)).check(vF(1)),ttl:V()}),fR=U({...dR.shape,hash:X(),r:X(),s:X(),v:q(X()),yParity:q(X())}),pR=U({address:Y(),decimals:V(),feeToken:q(wF()),interop:q(wF()),nativeRate:q(Q()),symbol:B(),uid:B()}),mR=B().check(yF(/^[A-Z0-9]+$/));var hR=U({address:Y(),chainId:Z(),nonce:Z()}),gR=U({...hR.shape,r:X(),s:X(),yParity:Z()}),_R=U({data:q(X()),to:Y(),value:q(Q())}),vR;(function(e){e.Parameters=U({address:Y(),secret:B()}),e.Request=U({method:K(`account_getOnrampContactInfo`),params:J(G([e.Parameters]))}),e.Response=U({email:q(B()),phone:q(B()),phoneVerifiedAt:q(V())})})(vR||={});var yR;(function(e){e.Parameters=U({address:Y()}),e.Request=U({method:K(`account_onrampStatus`),params:J(G([e.Parameters]))}),e.Response=U({email:q(V()),phone:q(V())})})(yR||={});var bR;(function(e){e.Parameters=U({phone:B(),walletAddress:Y()}),e.Request=U({method:K(`account_resendVerifyPhone`),params:J(G([e.Parameters]))}),e.Response=AF()})(bR||={});var xR;(function(e){e.Parameters=U({email:B().check(yF(/^.*@.*$/)),walletAddress:Y()}),e.Request=U({method:K(`account_setEmail`),params:J(G([e.Parameters]))}),e.Response=AF()})(xR||={});var SR;(function(e){e.Parameters=U({phone:B(),walletAddress:Y()}),e.Request=U({method:K(`account_setPhone`),params:J(G([e.Parameters]))}),e.Response=AF()})(SR||={});var CR;(function(e){e.Parameters=U({chainId:Z(),email:B(),signature:X(),token:B(),walletAddress:Y()}),e.Request=U({method:K(`account_verifyEmail`),params:J(G([e.Parameters]))}),e.Response=AF()})(CR||={});var wR;(function(e){e.Parameters=U({code:B(),phone:B(),walletAddress:Y()}),e.Request=U({method:K(`account_verifyPhone`),params:J(G([e.Parameters]))}),e.Response=AF()})(wR||={});var TR;(function(e){e.Request=U({method:K(`health`),params:OF()}),e.Response=U({quoteSigner:Y(),status:B(),version:B()})})(TR||={});var ER;(function(e){e.Parameters=U({address:Y(),chainId:Z(),tokenAddress:Y(),value:Q()}),e.Request=U({method:K(`wallet_addFaucetFunds`),params:J(G([e.Parameters]))}),e.Response=U({message:q(B()),transactionHash:X()})})(ER||={});var DR;(function(e){e.Parameters=U({chainId:Z(),id:X()}),e.Request=U({method:K(`wallet_getAccounts`),params:J(G([e.Parameters]))}),e.Response=J(H(U({address:Y(),keys:tR.Response})))})(DR||={});var OR;(function(e){e.Parameters=U({address:Y()}),e.Request=U({method:K(`wallet_getAuthorization`),params:J(G([e.Parameters]))}),e.Response=U({authorization:gR,data:X(),to:Y()})})(OR||={});var kR;(function(e){e.Request=U({method:K(`wallet_getCapabilities`),params:q(G([J(H(V()))]))});let t=U({address:Y(),version:q(W([B(),AF()]))});e.Response=qF(X(),U({contracts:U({accountImplementation:t,accountProxy:t,legacyAccountImplementations:J(H(t)),legacyOrchestrators:J(H(W([U({orchestrator:t,simulator:t}),t]))),orchestrator:t,simulator:t}),fees:U({quoteConfig:U({constantRate:q(W([V(),AF()])),gas:q(U({intentBuffer:q(V()),txBuffer:q(V())})),rateTtl:V(),ttl:V()}),recipient:Y(),tokens:J(H(pR))})}))})(kR||={});var AR;(function(e){let t=W([K(`native`),K(`erc20`),K(`erc721`),B()]);e.Parameters=U({account:Y(),assetFilter:q(qF(X(),J(H(U({address:W([Y(),K(`native`)]),type:t}))))),assetTypeFilter:q(J(H(t))),chainFilter:q(J(H(Z())))}),e.Request=U({method:K(`wallet_getAssets`),params:J(G([e.Parameters]))}),e.Price=U({currency:B(),value:tI(B(),V(),{decode:e=>Number(e),encode:e=>String(e)})}),e.Response=qF(B(),J(H(UL([U({address:Y(),balance:Q(),metadata:ZF(U({decimals:V(),fiat:QF(e.Price),name:B(),symbol:B()})),type:K(`erc20`)}),U({address:ZF(K(`native`)),balance:Q(),metadata:ZF(U({decimals:V(),fiat:QF(e.Price),name:q(B()),symbol:q(B())})),type:K(`native`)})]))))})(AR||={});var jR;(function(e){e.Request=U({method:K(`wallet_getCallsStatus`),params:J(G([X()]))}),e.Response=U({id:B(),receipts:q(J(H(U({blockHash:X(),blockNumber:Z(),chainId:Z(),gasUsed:Z(),logs:J(H(U({address:Y(),data:X(),topics:J(H(X()))}))),status:X(),transactionHash:X()})))),status:V()})})(jR||={});var MR;(function(e){e.Parameters=U({address:Y(),chainIds:q(J(H(Z())))}),e.Request=U({method:K(`wallet_getKeys`),params:J(G([e.Parameters]))}),e.Response=qF(X(),tR.Response)})(MR||={});var NR;(function(e){e.Capabilities=U({authorizeKeys:q(tR.Request),meta:rR.Request,preCall:q(wF()),preCalls:q(J(H(oR))),requiredFunds:q(iR.Request),revokeKeys:q(aR.Request)}),e.ResponseCapabilities=U({assetDiffs:q(eR.Response),authorizeKeys:QF(tR.Response),feePayerDigest:q(X()),feeSignature:q(X()),feeTotals:q(nR.Response),revokeKeys:QF(aR.Response)}),e.Parameters=U({calls:J(H(_R)),capabilities:e.Capabilities,chainId:Z(),from:q(Y()),key:q(U({prehash:wF(),publicKey:X(),type:QL.shape.type}))}),e.Request=U({method:K(`wallet_prepareCalls`),params:J(G([e.Parameters]))}),e.Response=U({capabilities:e.ResponseCapabilities,context:U({preCall:q(VF(sR)),quote:q(VF(fR))}),digest:X(),key:QF(U({prehash:wF(),publicKey:X(),type:QL.shape.type})),signature:X(),typedData:U({domain:W([U({chainId:W([Z(),V()]),name:B(),verifyingContract:Y(),version:B()}),U({})]),message:qF(B(),PF()),primaryType:B(),types:qF(B(),PF())})})})(NR||={});var PR;(function(e){e.Capabilities=U({authorizeKeys:tR.Request}),e.Parameters=U({address:Y(),capabilities:e.Capabilities,chainId:q(V()),delegation:Y()}),e.Request=U({method:K(`wallet_prepareUpgradeAccount`),params:J(G([e.Parameters]))}),e.Response=U({capabilities:e.Capabilities,chainId:Z(),context:U({address:Y(),authorization:hR,chainId:Z(),preCall:oR}),digests:U({auth:X(),exec:X()}),typedData:U({domain:W([U({chainId:W([Z(),V()]),name:B(),verifyingContract:Y(),version:B()}),U({})]),message:qF(B(),PF()),primaryType:B(),types:qF(B(),PF())})})})(PR||={});var FR;(function(e){e.Request=U({method:K(`wallet_feeTokens`),params:q(OF())}),e.Response=qF(X(),J(H(U({address:Y(),decimals:V(),nativeRate:q(Q()),symbol:B()}))))})(FR||={});var IR;(function(e){e.Parameters=U({capabilities:q(U({feeSignature:q(X())})),context:U({preCall:q(VF(sR)),quote:q(VF(fR))}),key:q(U({prehash:wF(),publicKey:X(),type:QL.shape.type})),signature:X()}),e.Request=U({method:K(`wallet_sendPreparedCalls`),params:J(G([e.Parameters]))}),e.Response=U({id:X()})})(IR||={});var LR;(function(e){e.Parameters=U({context:U({address:Y(),authorization:hR,chainId:Z(),preCall:oR}),signatures:U({auth:X(),exec:X()})}),e.Request=U({method:K(`wallet_upgradeAccount`),params:J(G([e.Parameters]))}),e.Response=OF()})(LR||={});var RR;(function(e){e.Parameters=U({address:X(),chainId:Z(),digest:X(),signature:X()}),e.Request=U({method:K(`wallet_verifySignature`),params:J(G([e.Parameters]))}),e.Response=U({proof:QF(U({account:Y(),initPreCall:QF(oR),keyHash:X()})),valid:wF()})})(RR||={}),Jd(),op();async function zR(e,t){try{let n=`wallet_getAuthorization`,r=await Tm(()=>e.request({method:n,params:[pP(OR.Parameters,t)]}),{cacheKey:`${e.uid}.${n}.${t.address}`});return mP(OR.Response,r)}catch(e){throw tz(e),e}}async function BR(e,t={}){let n=(()=>{if(t.chainId)return[t.chainId];if(t.chainIds!==`all`)return t.chainIds?t.chainIds:[e.chain.id]})();try{let r=`wallet_getCapabilities`,i=await Tm(()=>e.request({method:r,params:n?[n]:void 0},{retryCount:0}),{cacheKey:`${e.uid}.${r}.${n?.join(`,`)}`}),a=(()=>t.raw?i:mP(kR.Response,i))();return t.chainIds?a:Object.values(a)[0]}catch(e){throw tz(e),e}}async function VR(e,t){let{account:n,assetFilter:r,assetTypeFilter:i,chainFilter:a}=t;try{let t=await e.request({method:`wallet_getAssets`,params:[pP(AR.Parameters,{account:n,assetFilter:r,assetTypeFilter:i,chainFilter:a})]}),o=mP(AR.Response,t),s=Object.entries(o).reduce((e,[t,n])=>(e[Xf(t)]=n,e),{}),c={};for(let e of Object.values(s))for(let t of e){let e=JSON.stringify(t.metadata);c[e]={...t,balance:t.balance+(c[e]?.balance??0n)}}return{...s,0:Object.values(c)}}catch(e){throw tz(e),e}}async function HR(e,t){let{id:n}=t;try{let t=await e.request({method:`wallet_getCallsStatus`,params:[n]});return mP(jR.Response,t)}catch(e){throw tz(e),e}}async function UR(e,t){let{address:n,chainIds:r}=t;try{let t=await e.request({method:`wallet_getKeys`,params:[pP(MR.Parameters,{address:n,chainIds:r})]});return mP(MR.Response,t)}catch(e){throw tz(e),e}}async function WR(e){let t=`health`,n=await Tm(()=>e.request({method:t}),{cacheKey:`${e.uid}.${t}`});return mP(TR.Response,n)}async function GR(e,t){let{address:n,capabilities:r,chain:i=e.chain,key:a}=t,o=t.calls.map(e=>({data:e.abi?Y_(X_(e.abi,e.functionName),e.args):e.data??`0x`,to:e.to,value:e.value??0n}));try{let t=await e.request({method:`wallet_prepareCalls`,params:[pP(NR.Parameters,{calls:o,capabilities:{...r,meta:{...r?.meta}},chainId:i?.id,from:n,key:a?{prehash:a.prehash,publicKey:a.publicKey,type:a.type}:void 0})]},{retryCount:0});return Object.assign(mP(NR.Response,t),{_raw:t})}catch(e){throw tz(e),$R(e,{calls:t.calls}),e}}async function KR(e,t){let{address:n,chain:r=e.chain,delegation:i,...a}=t;try{let t=await e.request({method:`wallet_prepareUpgradeAccount`,params:[pP(PR.Parameters,pN({address:n,capabilities:a,chainId:r?.id,delegation:i}))]},{retryCount:0});return mP(PR.Response,t)}catch(e){throw tz(e),$R(e),e}}async function qR(e,t){let{capabilities:n,context:r,key:i,signature:a}=t;try{let t=await e.request({method:`wallet_sendPreparedCalls`,params:[pP(IR.Parameters,{capabilities:n,context:{preCall:r.preCall,quote:r.quote},key:i?{prehash:i.prehash,publicKey:i.publicKey,type:i.type}:void 0,signature:a})]},{retryCount:0});return mP(IR.Response,t)}catch(e){throw tz(e),$R(e),e}}async function JR(e,t){let{email:n,walletAddress:r}=t;try{let t=await e.request({method:`account_setEmail`,params:[pP(xR.Parameters,{email:n,walletAddress:r})]},{retryCount:0});return mP(xR.Response,t)}catch(e){throw tz(e),$R(e),e}}async function YR(e,t){let{context:n,signatures:r}=t;try{await e.request({method:`wallet_upgradeAccount`,params:[pP(LR.Parameters,{context:n,signatures:r})]},{retryCount:0})}catch(e){throw tz(e),$R(e),e}}async function XR(e,t){let{chainId:n,email:r,signature:i,token:a,walletAddress:o}=t;try{let t=await e.request({method:`account_verifyEmail`,params:[pP(CR.Parameters,{chainId:n,email:r,signature:i,token:a,walletAddress:o})]},{retryCount:0});return mP(CR.Response,t)}catch(e){throw tz(e),$R(e),e}}async function ZR(e,t){let{signature:n}=t,{signature:r,capabilities:{feeSignature:i,...a},...o}=t.response,s=ez({capabilities:a,...o}),c=Hh(Uf(JSON.stringify(s))),l=O_({payload:c,signature:o_(n)}),{quoteSigner:u}=await WR(e);return l===u}async function QR(e,t){let{address:n,chain:r=e.chain,digest:i,signature:a}=t;try{async function t(){return{proof:null,valid:await iv(e,{address:n,hash:i,signature:a})}}let o=await(async()=>{let o=await e.request({method:`wallet_verifySignature`,params:[pP(RR.Parameters,{address:n,chainId:r?.id,digest:i,signature:a})]},{retryCount:0}).catch(t);return o.valid?o:t()})();return mP(RR.Response,o)}catch(e){throw tz(e),e}}function $R(e,{calls:t}={}){if(!(e instanceof D))return;let n=e=>{try{if(e.name===`ContractFunctionExecutionError`){let t=e.cause.name===`ContractFunctionRevertedError`?e.cause.data:void 0;if(t)return LL([t.abiItem],t.errorName)}let t=e.walk(e=>!(e instanceof Error)&&e.code===3);if(!t)return;let{data:n,message:r}=t;return n===`0xd0d5039b`?IL(`error Unauthorized()`):{inputs:[],name:(r??n).split(`(`)[0],type:`error`}}catch{return}},r=HL(e,{calls:t??[]}),i=n(r);if(!(r===e&&!i))throw new nz(Object.assign(r,{abiError:i}))}function ez(e){if(typeof e==`object`&&e){if(Array.isArray(e))return e.map(ez);let t={};for(let n of Object.keys(e).sort())t[n]=ez(e[n]);return t}return e}function tz(e){if(e.name===`$ZodError`)throw GL(e)}var nz=class extends P{constructor(e){super(`An error occurred while executing calls.`,{cause:e,metaMessages:[e.abiError&&`Reason: `+e.abiError.name].filter(Boolean)}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Rpc.ExecutionError`}),Object.defineProperty(this,`abiError`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.abiError=e.abiError}};const rz={anvil:{http:`http://localhost:9119`},prod:{http:`https://rpc.porto.sh`},stg:{http:`https://stg-rpc.porto.sh`}};function iz(e){return t=>{let n=e.public(t),r=e.relay(t);return Nv({key:iz.type,name:`Relay Proxy`,async request({method:e,params:t},i){return az(e)?r.request({method:e,params:t},i):n.request({method:e,params:t},i)},type:iz.type})}}(function(e){e.type=`relayProxy`})(iz||={});function az(e){return!!(e.startsWith(`wallet_`)||e.startsWith(`account_`)||e===`health`)}pf();var oz=new Map;function sz(e,t={}){let{config:n,id:r,store:i}=e._internal,{chains:a,relay:o}=n,s=i.getState(),c=t.chainId??s.chainIds[0],l=a.find(e=>e.id===c);if(!l)throw Error([`Could not find a compatible Porto chain on the given chain configuration.`,``,`Provided chains: [${a.map(e=>`${e.name} (id: ${e.id})`).join(`, `)}]`,`Needed chain (id): ${c}`,`Please add this chain (id) to your chain configuration.`].join(`\n`));let u=iz({public:n.transports[l.id]??Fv(l.rpcUrls.default.http.map(e=>zv(e))),relay:o}),d=[r,df(l)].filter(Boolean).join(`:`);if(oz.has(d))return oz.get(d);let f=Xm({...t,chain:l,pollingInterval:1e3,transport:u});return oz.set(d,f),f}const cz=U({chainId:q(Z()),expiry:Z(),hash:X(),id:X(),prehash:q(wF()),publicKey:X(),role:W([K(`admin`),K(`session`)]),type:W([K(`address`),K(`p256`),K(`secp256k1`),K(`webauthn-p256`)])}),lz=J(H(UL([U({signature:B(),to:Y()}),U({signature:B()}),U({to:Y()})])).check(vF(1))),uz=U({limit:W([iI([V(),`.`,V()]),iI([V()])]).check(yF(/^\\d+(\\.\\d+)?$/)),symbol:q(W([K(`native`),mR]))}),dz=U({addresses:J(H(Y()))}),fz=J(H(U({limit:Q(),period:W([K(`minute`),K(`hour`),K(`day`),K(`week`),K(`month`),K(`year`)]),token:q(Y())}))),pz=U({calls:q(lz),signatureVerification:q(dz),spend:q(fz)}),mz=U({...cz.shape,feeToken:q(ZF(uz)),permissions:q(pz)}),hz=U({address:Y(),chainId:q(Z()),expiry:V(),id:X(),key:zF(cz,{publicKey:!0,type:!0}),permissions:U({calls:lz,signatureVerification:q(dz),spend:q(fz)})}),gz=U({address:q(Y()),chainId:q(Z()),expiry:V().check(_F(1)),feeToken:ZF(uz),key:q(zF(cz,{publicKey:!0,type:!0})),permissions:U({calls:lz,signatureVerification:q(dz),spend:q(fz)})}),_z=hz;function vz(e,t){let{chainId:n,expiry:r,permissions:i,id:a,publicKey:o,type:s}=e,{address:c}=t;return{address:c,chainId:n,expiry:r,id:a,key:{publicKey:o,type:s},permissions:i??{}}}function yz(e){let{chainId:t,expiry:n,key:r}=e;return vL({chainId:t,expiry:n,permissions:e.permissions??{},publicKey:r.publicKey,role:`session`,type:r.type})}var bz;(function(e){e.GetCapabilitiesResponse=U({status:W([K(`supported`),K(`unsupported`)])})})(bz||={});var xz;(function(e){e.Request=W([wF(),U({chainId:q(Z()),label:q(B())})])})(xz||={});var Sz;(function(e){e.Request=UL([U({chainId:q(V()),domain:q(B()),expirationTime:q(IF()),issuedAt:q(IF()),nonce:B(),notBefore:q(IF()),requestId:q(B()),resources:q(J(H(B()))),scheme:q(B()),statement:q(B()),uri:q(B()),version:q(K(`1`))}),U({authUrl:W([B(),U({logout:B(),nonce:B(),verify:B()})]),chainId:q(Z()),domain:q(B()),expirationTime:q(IF()),issuedAt:q(IF()),notBefore:q(IF()),requestId:q(B()),resources:q(J(H(B()))),scheme:q(B()),statement:q(B()),uri:q(B()),version:q(K(`1`))})]),e.Response=U({message:B(),signature:X(),token:q(B())})})(Sz||={});var Cz;(function(e){e.GetCapabilitiesResponse=U({supported:wF(),tokens:J(H(pR))}),e.Request=W([mR,Y()])})(Cz||={});var wz;(function(e){e.Request=gz})(wz||={});var Tz;(function(e){e.GetCapabilitiesResponse=U({supported:wF()})})(Tz||={});var Ez;(function(e){e.GetCapabilitiesResponse=U({supported:wF()}),e.Request=U({id:q(W([X(),AF()]))}),e.Response=J(H(hz))})(Ez||={});var Dz;(function(e){e.Request=J(H(U({context:PF(),signature:X()}))),e.Response=e.Request})(Dz||={});var Oz;(function(e){e.Request=B()})(Oz||={});var kz;(function(e){e.GetCapabilitiesResponse=U({supported:wF(),tokens:J(H(pR))}),e.Request=J(H(UL([U({address:Y(),value:Q()}),U({symbol:mR,value:W([iI([V(),`.`,V()]),iI([V()])]).check(yF(/^\\d+(\\.\\d+)?$/))})])))})(kz||={});var Az=U({...zF(cz,{id:!0,publicKey:!0,type:!0}).shape,credentialId:q(B()),privateKey:q(MF())}),jz;(function(e){e.Parameters=U({address:Y(),secret:B()}),e.Request=U({method:K(`account_getOnrampContactInfo`),params:J(G([e.Parameters]))}),e.Response=U({email:q(B()),phone:q(B()),phoneVerifiedAt:q(V())})})(jz||={});var Mz;(function(e){e.Parameters=U({address:Y()}),e.Request=U({method:K(`account_onrampStatus`),params:J(G([e.Parameters]))}),e.Response=U({email:q(V()),phone:q(V())})})(Mz||={});var Nz;(function(e){e.Parameters=U({email:B(),walletAddress:Y()}),e.Request=U({method:K(`account_resendVerifyPhone`),params:J(G([e.Parameters]))}),e.Response=AF()})(Nz||={});var Pz;(function(e){e.Parameters=U({email:B(),walletAddress:Y()}),e.Request=U({method:K(`account_setEmail`),params:J(G([e.Parameters]))}),e.Response=AF()})(Pz||={});var Fz;(function(e){e.Parameters=U({email:B(),walletAddress:Y()}),e.Request=U({method:K(`account_setPhone`),params:J(G([e.Parameters]))}),e.Response=AF()})(Fz||={});var Iz;(function(e){e.Parameters=U({chainId:Z(),email:B(),token:B(),walletAddress:Y()}),e.Request=U({method:K(`account_verifyEmail`),params:J(G([e.Parameters]))}),e.Response=AF()})(Iz||={});var Lz;(function(e){e.Parameters=U({code:B(),phone:B(),walletAddress:Y()}),e.Request=U({method:K(`account_verifyPhone`),params:J(G([e.Parameters]))}),e.Response=AF()})(Lz||={});var Rz;(function(e){e.Parameters=U({address:q(Y()),chainId:q(Z()),token:q(Y()),value:q(B())}),e.Request=U({method:K(`wallet_addFunds`),params:J(G([e.Parameters]))}),e.Response=U({id:X()})})(Rz||={});var zz;(function(e){e.Request=U({method:K(`eth_accounts`),params:q(PF())}),e.Response=J(H(Y()))})(zz||={});var Bz;(function(e){e.Request=U({method:K(`eth_chainId`),params:q(PF())}),e.Response=X()})(Bz||={});var Vz;(function(e){e.Request=U({method:K(`eth_requestAccounts`),params:q(PF())}),e.Response=J(H(Y()))})(Vz||={});var Hz;(function(e){e.Request=U({method:K(`eth_sendTransaction`),params:J(G([U({capabilities:q(U({feeToken:q(Cz.Request),merchantUrl:q(Oz.Request),preCalls:q(Dz.Request)})),chainId:q(Z()),data:q(X()),from:q(Y()),to:Y(),value:q(Q())})]))}),e.Response=X()})(Hz||={});var Uz;(function(e){e.Request=U({method:K(`eth_signTypedData_v4`),params:J(G([Y(),B()]))}),e.Response=X()})(Uz||={});var Wz;(function(e){e.Parameters=U({address:q(Y()),chainId:q(Z())}),e.Request=U({method:K(`wallet_getAdmins`),params:q(J(G([e.Parameters])))}),e.Key=Az,e.Response=U({address:Y(),chainId:Z(),keys:J(H(e.Key))})})(Wz||={});var Gz;(function(e){e.Capabilities=U({feeToken:q(Cz.Request)}),e.Parameters=U({address:q(Y()),capabilities:q(e.Capabilities),chainId:q(Z()),key:zF(cz,{publicKey:!0,type:!0})}),e.Request=U({method:K(`wallet_grantAdmin`),params:J(G([e.Parameters]))}),e.Response=U({address:Y(),chainId:Z(),key:Wz.Key})})(Gz||={});var Kz;(function(e){e.Parameters=gz,e.Request=U({method:K(`wallet_grantPermissions`),params:J(G([e.Parameters]))}),e.ResponseCapabilities=U({preCalls:q(Dz.Response)}),e.Response=U({...hz.shape,capabilities:q(MF())})})(Kz||={});var qz;(function(e){e.Parameters=U({address:q(Y())}),e.Request=U({method:K(`wallet_getAccountVersion`),params:q(J(G([e.Parameters])))}),e.Response=U({current:B(),latest:B()})})(qz||={});var Jz;(function(e){e.Parameters=U({address:q(Y()),chainIds:q(J(H(Z())))}),e.Request=U({method:K(`wallet_getPermissions`),params:q(J(G([e.Parameters])))}),e.Response=Ez.Response})(Jz||={});var Yz;(function(e){e.Capabilities=U({feeToken:q(Cz.Request)}),e.Parameters=U({address:q(Y()),capabilities:q(e.Capabilities),chainId:q(Z()),id:X()}),e.Request=U({method:K(`wallet_revokeAdmin`),params:J(G([e.Parameters]))}),e.Response=void 0})(Yz||={});var Xz;(function(e){e.Capabilities=U({feeToken:q(Cz.Request)}),e.Parameters=U({address:q(Y()),capabilities:q(e.Capabilities),id:X()}),e.Request=U({method:K(`wallet_revokePermissions`),params:J(G([e.Parameters]))}),e.Response=void 0})(Xz||={});var Zz;(function(e){e.Request=U({method:K(`wallet_switchEthereumChain`),params:J(G([U({chainId:X()})]))})})(Zz||={});var Qz;(function(e){e.Parameters=U({context:PF(),signatures:U({auth:X(),exec:X()})}),e.Request=U({method:K(`wallet_upgradeAccount`),params:J(G([e.Parameters]))}),e.ResponseCapabilities=U({admins:q(J(H(Wz.Key))),permissions:q(Ez.Response)}),e.Response=U({address:Y(),capabilities:q(e.ResponseCapabilities)})})(Qz||={});var $z;(function(e){e.Request=U({method:K(`personal_sign`),params:J(G([X(),Y()]))}),e.Response=X()})($z||={});var eB;(function(e){e.Request=U({method:K(`porto_ping`),params:q(OF())}),e.Response=K(`pong`)})(eB||={});var tB;(function(e){e.Capabilities=U({createAccount:q(xz.Request),email:q(wF()),grantAdmins:q(J(H(zF(cz,{publicKey:!0,type:!0})))),grantPermissions:q(wz.Request),preCalls:q(Dz.Request),selectAccount:q(W([wF(),U({address:Y(),key:q(U({credentialId:q(B()),publicKey:X()}))})])),signInWithEthereum:q(Sz.Request)}),e.Parameters=U({capabilities:q(e.Capabilities),chainIds:q(J(H(Z())))}),e.Request=U({method:K(`wallet_connect`),params:q(J(G([e.Parameters])))}),e.ResponseCapabilities=U({admins:q(J(H(U({...zF(cz,{id:!0,publicKey:!0,type:!0}).shape,credentialId:q(B())})))),permissions:q(Ez.Response),preCalls:q(Dz.Response),signInWithEthereum:q(Sz.Response)}),e.Response=U({accounts:J(H(U({address:Y(),capabilities:q(e.ResponseCapabilities)}))),chainIds:J(H(Z()))})})(tB||={});var nB;(function(e){e.Request=U({method:K(`wallet_disconnect`),params:q(PF())}),e.Response=void 0})(nB||={});var rB;(function(e){e.Parameters=AR.Parameters,e.Request=AR.Request,e.Response=AR.Response})(rB||={});var iB;(function(e){e.Request=U({method:K(`wallet_getCallsStatus`),params:G([X()])}),e.Response=U({atomic:wF(),chainId:Z(),id:B(),receipts:q(J(H(U({blockHash:X(),blockNumber:X(),gasUsed:X(),logs:J(H(U({address:Y(),data:X(),topics:J(H(X()))}))),status:X(),transactionHash:X()})))),status:V(),version:B()})})(iB||={});var aB;(function(e){e.Request=U({method:K(`wallet_getCapabilities`),params:q(W([J(G([W([X(),OF()])])),J(G([W([X(),OF()]),J(H(Z()))]))]))}),e.Response=qF(X(),U({atomic:bz.GetCapabilitiesResponse,feeToken:Cz.GetCapabilitiesResponse,merchant:Tz.GetCapabilitiesResponse,permissions:Ez.GetCapabilitiesResponse,requiredFunds:kz.GetCapabilitiesResponse}))})(aB||={});var oB;(function(e){e.Parameters=U({address:Y(),chainIds:q(J(H(Z())))}),e.Request=U({method:K(`wallet_getKeys`),params:J(G([e.Parameters]))}),e.Response=J(H(mz))})(oB||={});var sB;(function(e){e.Capabilities=U({feeToken:q(Cz.Request),merchantUrl:q(Oz.Request),permissions:q(Ez.Request),preCalls:q(Dz.Request),requiredFunds:q(kz.Request)}),e.Parameters=U({calls:J(H(U({data:q(X()),to:Y(),value:q(Q())}))),capabilities:q(e.Capabilities),chainId:q(Z()),from:q(Y()),key:q(zF(cz,{prehash:!0,publicKey:!0,type:!0})),version:q(B())}),e.Request=U({method:K(`wallet_prepareCalls`),params:J(G([e.Parameters]))}),e.Response=U({capabilities:q(U({...NR.ResponseCapabilities.shape,quote:q(fR)})),chainId:X(),context:U({account:U({address:Y()}),calls:e.Parameters.shape.calls,nonce:Q(),quote:q(VF(fR))}),digest:X(),key:zF(cz,{prehash:!0,publicKey:!0,type:!0}),typedData:U({domain:W([U({chainId:Z(),name:B(),verifyingContract:Y(),version:B()}),U({})]),message:qF(B(),PF()),primaryType:B(),types:qF(B(),PF())})})})(sB||={});var cB;(function(e){e.Capabilities=U({...tB.Capabilities.shape,label:q(B())}),e.Parameters=U({address:Y(),capabilities:q(e.Capabilities),chainId:q(Z())}),e.Request=U({method:K(`wallet_prepareUpgradeAccount`),params:J(G([e.Parameters]))}),e.Response=U({context:PF(),digests:U({auth:X(),exec:X()})})})(cB||={});var lB;(function(e){e.Capabilities=sB.Capabilities,e.Request=U({method:K(`wallet_sendCalls`),params:J(G([BF(sB.Parameters,{key:!0})]))}),e.Response=U({id:X()})})(lB||={});var uB;(function(e){e.Parameters=U({capabilities:sB.Response.shape.capabilities,chainId:X(),context:sB.Response.shape.context,key:sB.Response.shape.key,signature:X()}),e.Request=U({method:K(`wallet_sendPreparedCalls`),params:J(G([e.Parameters]))}),e.Response=J(H(U({capabilities:q(qF(B(),PF())),id:X()})))})(uB||={});var dB;(function(e){e.Parameters=U({address:Y(),chainId:q(Z()),digest:X(),signature:X()}),e.Request=U({method:K(`wallet_verifySignature`),params:J(G([e.Parameters]))}),e.Response=U({address:Y(),chainId:Z(),proof:q(PF()),valid:wF()})})(dB||={});const fB=WF(`method`,[Iz.Request,Rz.Request,zz.Request,Bz.Request,Vz.Request,Hz.Request,Uz.Request,qz.Request,Wz.Request,Jz.Request,Gz.Request,Kz.Request,cB.Request,Yz.Request,Xz.Request,Qz.Request,$z.Request,eB.Request,tB.Request,nB.Request,rB.Request,iB.Request,aB.Request,oB.Request,sB.Request,lB.Request,uB.Request,Zz.Request,dB.Request]);function pB(e,t){let n=dP(e,t);if(n.error){let e=n.error.issues.at(0);throw e?.code===`invalid_union`&&e.note===`No matching discriminator`?new NM:new RM(GL(n.error))}return{...t,_decoded:n.data}}async function mB(e){e.persist.hasHydrated()||await new Promise(t=>{e.persist.onFinishHydration(()=>t(!0)),setTimeout(()=>t(!0),100)})}function hB(e){if(e)return e.startsWith(`/`)?`${window.location.origin}${e}`:e}op(),pf();function gB(e){let{config:t,getMode:n,id:r,store:i}=e,{announceProvider:a}=t;function o(e={}){let a=s(),o=e.request??pB(fB,{method:`wallet_getCapabilities`,params:e.chainIds?[void 0,e.chainIds]:void 0});return Tm(()=>n().actions.getCapabilities({chainIds:e.chainIds,internal:{client:a,config:t,request:o,store:i}}),{cacheKey:`getCapabilities.${r}.${e.chainIds?.join(`,`)}`})}function s(t){let n=typeof t==`string`?Xf(t):t;return sz({_internal:e},{chainId:n})}let c=new Map,l=[],u=tN(),d=nN({...u,async request(e){await mB(i);let r=[`eth_accounts`,`eth_chainId`,`eth_requestAccounts`,`wallet_getAssets`,`wallet_getCapabilities`,`wallet_getKeys`,`wallet_getPermissions`,`wallet_getAccountVersion`,`wallet_connect`].includes(e.method);return gN(async()=>{let r;try{r=pB(fB,e)}catch(t){let n=t;if(!(n instanceof NM))throw n;if(e.method.startsWith(`wallet_`))throw new WM;return s().request(e)}let a=i.getState();switch(r.method){case`account_verifyEmail`:{if(a.accounts.length===0)throw new GM;let[e]=r._decoded.params,{chainId:o,email:c,token:l,walletAddress:u}=e,d=s(o);if(o&&o!==d.chain.id)throw new KM;let f=u?a.accounts.find(e=>ag(e.address,u)):a.accounts[0];if(!f)throw new UM;return await n().actions.verifyEmail({account:f,chainId:o,email:c,internal:{client:d,config:t,request:r,store:i},token:l,walletAddress:u})}case`wallet_addFunds`:{if(a.accounts.length===0)throw new GM;let{address:e,value:o,token:c}=r.params[0]??{},l=e?a.accounts.find(t=>ag(t.address,e)):a.accounts[0];if(!l)throw new UM;let d=s(),f=await n().actions.addFunds({address:l.address,internal:{client:d,config:t,request:r,store:i},token:c,value:o});return u.emit(`message`,{data:null,type:`assetsChanged`}),f}case`eth_accounts`:if(a.accounts.length===0)throw new GM;return a.accounts.map(bB);case`eth_chainId`:return I(a.chainIds[0]);case`eth_requestAccounts`:{if(a.accounts.length>0&&c.get(`eth_requestAccounts`))return a.accounts.map(bB);let e=s(),{accounts:o}=await n().actions.loadAccounts({internal:{client:e,config:t,request:r,store:i}});return i.setState(e=>({...e,accounts:o})),u.emit(`connect`,{chainId:I(e.chain.id)}),c.set(`eth_requestAccounts`,!0),setTimeout(()=>c.delete(`eth_requestAccounts`),1e3),o.map(bB)}case`eth_sendTransaction`:{if(a.accounts.length===0)throw new GM;let[{capabilities:e,chainId:o,data:c=`0x`,from:l,to:u,value:d}]=r._decoded.params,f=s(o);if(o&&o!==f.chain.id)throw new KM;let p=l?a.accounts.find(e=>ag(e.address,l)):a.accounts[0];if(!p)throw new UM;let{id:m}=await n().actions.sendCalls({account:p,asTxHash:!0,calls:[{data:c,to:u,value:d}],chainId:f.chain.id,internal:{client:f,config:t,request:r,store:i},merchantUrl:hB(t.merchantUrl??e?.merchantUrl)});return m}case`eth_signTypedData_v4`:{if(a.accounts.length===0)throw new GM;let[e,o]=r._decoded.params,c=a.accounts.find(t=>ag(t.address,e));if(!c)throw new UM;let l=s();return await n().actions.signTypedData({account:c,data:o,internal:{client:l,config:t,request:r,store:i}})}case`wallet_grantAdmin`:{if(a.accounts.length===0)throw new GM;let[{address:e,capabilities:o,chainId:c,key:l}]=r._decoded.params??[{}],d=e?a.accounts.find(t=>ag(t.address,e)):a.accounts[0];if(!d)throw new UM;let f=s(c);if(vB([...d.keys??[]])?.some(e=>e.publicKey?.toLowerCase()===l.publicKey.toLowerCase()))throw new RM({message:`Key already granted as admin.`});let{key:p}=await n().actions.grantAdmin({account:d,feeToken:o?.feeToken,internal:{client:f,config:t,request:r,store:i},key:l});i.setState(e=>{let t=e.accounts.findIndex(e=>d?ag(e.address,d.address):!0);return t===-1?e:{...e,accounts:e.accounts.map((e,n)=>n===t?{...e,keys:[...e.keys??[],p]}:e)}});let m=vB([...d.keys??[],p]);return u.emit(`message`,{data:null,type:`adminsChanged`}),pP(Gz.Response,{address:d.address,chainId:f.chain.id,key:m.at(-1)})}case`wallet_grantPermissions`:{if(a.accounts.length===0)throw new GM;let[{address:e,chainId:o,...c}]=r._decoded.params??[{}],l=e?a.accounts.find(t=>ag(t.address,e)):a.accounts[0];if(!l)throw new UM;let d=s(o),{key:f}=await n().actions.grantPermissions({account:l,internal:{client:d,config:t,request:r,store:i},permissions:c});return i.setState(e=>{let t=e.accounts.findIndex(e=>l?ag(e.address,l.address):!0);return t===-1?e:{...e,accounts:e.accounts.map((e,n)=>n===t?{...e,keys:[...e.keys??[],f]}:e)}}),u.emit(`message`,{data:null,type:`permissionsChanged`}),pP(Kz.Response,{...vz(f,{address:l.address})})}case`wallet_getAdmins`:{if(a.accounts.length===0)throw new GM;let[{address:e,chainId:o}]=r._decoded.params??[{}],c=e?a.accounts.find(t=>ag(t.address,e)):a.accounts[0];if(!c)throw new UM;let l=s(o),u=await n().actions.getKeys({account:c,internal:{client:l,config:t,request:r,store:i}}),d=vB(u);return pP(Wz.Response,{address:c.address,chainId:l.chain.id,keys:d})}case`wallet_prepareUpgradeAccount`:{let[{address:e,capabilities:a,chainId:o}]=r._decoded.params??[{}],{email:c,label:u,grantPermissions:d}=a??{},f=s(o),{context:p,digests:m}=await n().actions.prepareUpgradeAccount({address:e,email:c,internal:{client:f,config:t,request:r,store:i},label:u,permissions:d});return l.push(p.account),{context:p,digests:m}}case`wallet_getAccountVersion`:{if(a.accounts.length===0)throw new GM;let[{address:e}]=r._decoded.params??[{}],o=e?a.accounts.find(t=>ag(t.address,e)):a.accounts[0];if(!o)throw new UM;let c=s(),{current:l,latest:u}=await n().actions.getAccountVersion({address:o.address,internal:{client:c,config:t,request:r,store:i}});return{current:l,latest:u}}case`wallet_getKeys`:{if(a.accounts.length===0)throw new GM;let[{address:e,chainIds:o}]=r._decoded.params??[{}],c=a.accounts.find(t=>ag(t.address,e));if(!c)throw new UM;let l=s(),u=await n().actions.getKeys({account:c,chainIds:o,internal:{client:l,config:t,request:r,store:i}});return pP(oB.Response,u)}case`wallet_getPermissions`:{if(a.accounts.length===0)throw new GM;let[{address:e,chainIds:o}]=r._decoded.params??[{}],c=e?a.accounts.find(t=>ag(t.address,e)):a.accounts[0];if(!c)throw new UM;let l=s(),u=await n().actions.getKeys({account:c,chainIds:o,internal:{client:l,config:t,request:r,store:i}});return yB(u,{address:c.address})}case`wallet_revokeAdmin`:{if(a.accounts.length===0)throw new GM;let[{address:e,capabilities:o,id:c}]=r._decoded.params,l=e?a.accounts.find(t=>ag(t.address,e)):a.accounts[0];if(!l)throw new UM;let d=s();await n().actions.revokeAdmin({account:l,feeToken:o?.feeToken,id:c,internal:{client:d,config:t,request:r,store:i}});let f=l.keys?.filter(e=>e.id.toLowerCase()!==c.toLowerCase());i.setState(e=>({...e,accounts:e.accounts.map(e=>ag(e.address,l.address)?{...e,keys:f}:e)})),u.emit(`message`,{data:null,type:`adminsChanged`});return}case`wallet_revokePermissions`:{if(a.accounts.length===0)throw new GM;let[{address:e,capabilities:o,id:c}]=r._decoded.params,l=e?a.accounts.find(t=>ag(t.address,e)):a.accounts[0];if(!l)throw new UM;let d=s();await n().actions.revokePermissions({account:l,feeToken:o?.feeToken,id:c,internal:{client:d,config:t,request:r,store:i}});let f=l.keys?.filter(e=>e.id.toLowerCase()!==c.toLowerCase());i.setState(e=>({...e,accounts:e.accounts.map(e=>ag(e.address,l.address)?{...e,keys:f}:e)})),u.emit(`message`,{data:null,type:`permissionsChanged`});return}case`wallet_upgradeAccount`:{let[{context:e,signatures:a}]=r._decoded.params??[{}],o=s(),c=l.find(t=>ag(t.address,e.account.address));if(!c)throw new UM;let{account:d}=await n().actions.upgradeAccount({account:c,context:e,internal:{client:o,config:t,request:r,store:i},signatures:a}),f=vB(d.keys??[]),p=yB(d.keys??[],{address:d.address});return i.setState(e=>({...e,accounts:[d]})),u.emit(`connect`,{chainId:I(o.chain.id)}),{address:d.address,capabilities:{admins:f,...p.length>0?{permissions:p}:{}}}}case`porto_ping`:return`pong`;case`personal_sign`:{if(a.accounts.length===0)throw new GM;let[e,o]=r._decoded.params,c=a.accounts.find(e=>ag(e.address,o));if(!c)throw new UM;let l=s();return await n().actions.signPersonalMessage({account:c,data:e,internal:{client:l,config:t,request:r,store:i}})}case`wallet_connect`:{let[{capabilities:e,chainIds:o}]=r._decoded.params??[{}],c=s(o?.[0]),l=c.chain.id,{createAccount:d,email:f,grantAdmins:p,grantPermissions:m,selectAccount:h,signInWithEthereum:g}=e??{},_={client:c,config:t,request:r,store:i},{accounts:v}=await(async()=>{if(f||d){let{label:e=void 0}=typeof d==`object`?d:{},{account:t}=await n().actions.createAccount({admins:p,email:f,internal:_,label:e,permissions:m,signInWithEthereum:g});return{accounts:[t]}}let e=a.accounts[0],{address:t,key:r}=(()=>{if(h)return typeof h==`object`?h:{address:void 0,key:void 0};for(let t of e?.keys??[])if(t.type===`webauthn-p256`&&t.role===`admin`)return{address:e?.address,key:{credentialId:t.credentialId??t.privateKey?.credential?.id,publicKey:t.publicKey}};return{address:void 0,key:void 0}})(),i={internal:_,permissions:m,signInWithEthereum:g};try{return await n().actions.loadAccounts({address:t,key:r,...i})}catch(e){if(e instanceof HM)throw e;if(t&&r)return await n().actions.loadAccounts(i);throw e}})();i.setState(e=>({...e,accounts:v}));let y=[l,...i.getState().chainIds.filter(e=>e!==l)];return u.emit(`connect`,{chainId:I(y[0])}),{accounts:v.map(e=>({address:bB(e),capabilities:{admins:e.keys?vB(e.keys):[],permissions:e.keys?yB(e.keys,{address:e.address}):[],...e.signInWithEthereum&&{signInWithEthereum:e.signInWithEthereum}}})),chainIds:y.map(e=>I(e))}}case`wallet_disconnect`:{let e=s();await n().actions.disconnect?.({internal:{client:e,config:t,request:r,store:i}}),i.setState(e=>({...e,accounts:[]})),u.emit(`disconnect`,new GM);return}case`wallet_getAssets`:{let[e]=r._decoded.params??[],{account:a,chainFilter:o,assetFilter:c,assetTypeFilter:l}=e,u=s(),d=await n().actions.getAssets({account:a,assetFilter:c,assetTypeFilter:l,chainFilter:o,internal:{client:u,config:t,request:r,store:i}}),f=Object.entries(d).reduce((e,[t,n])=>(e[I(Number(t))]=n,e),{});return pP(rB.Response,f)}case`wallet_getCallsStatus`:{let[e]=r._decoded.params??[],a=s();return await n().actions.getCallsStatus({id:e,internal:{client:a,config:t,request:r,store:i}})}case`wallet_getCapabilities`:{let[e,t]=r.params??[];return await o({chainIds:t,request:r})}case`wallet_prepareCalls`:{let[e]=r._decoded.params,{calls:o,capabilities:c,chainId:l,key:u,from:d}=e,f=s(l),p=d??a.accounts[0];if(!p)throw new UM;if(l&&l!==f.chain.id)throw new KM;let{digest:m,...h}=await n().actions.prepareCalls({account:ML(p),calls:o,feeToken:c?.feeToken,internal:{client:f,config:t,request:r,store:i},key:u,merchantUrl:hB(t.merchantUrl??c?.merchantUrl),requiredFunds:c?.requiredFunds});return pP(sB.Response,{capabilities:h.capabilities,chainId:I(h.chainId??f.chain.id),context:{...h.context,account:{address:h.account.address},calls:h.context.calls??[],nonce:h.context.nonce??0n},digest:m,key:h.key,typedData:h.typedData})}case`wallet_sendPreparedCalls`:{let[e]=r._decoded.params,{chainId:a,context:o,key:c,signature:l}=e,{account:u}=e.context,d=s(a);if(a&&Xf(a)!==d.chain.id)throw new KM;return[{id:await n().actions.sendPreparedCalls({account:ML(u),context:o,internal:{client:d,config:t,request:r,store:i},key:c,signature:l})}]}case`wallet_sendCalls`:{if(a.accounts.length===0)throw new GM;let[e]=r._decoded.params,{calls:o,capabilities:c,chainId:l,from:u}=e,d=s(l);if(l&&l!==d.chain.id)throw new KM;let f=u?a.accounts.find(e=>ag(e.address,u)):a.accounts[0];if(!f)throw new UM;let{id:p}=await n().actions.sendCalls({account:f,calls:o,chainId:d.chain.id,feeToken:c?.feeToken,internal:{client:d,config:t,request:r,store:i},merchantUrl:hB(t.merchantUrl??c?.merchantUrl),permissionsId:c?.permissions?.id,requiredFunds:c?.requiredFunds});return{id:p}}case`wallet_switchEthereumChain`:{let[e]=r._decoded.params,{chainId:a}=e,o=Xf(a);if(!t.chains.find(e=>e.id===o))throw new YM;let c=s(a);await n().actions.switchChain?.({chainId:c.chain.id,internal:{client:c,config:t,request:r,store:i}}),i.setState(e=>({...e,chainIds:[o,...e.chainIds.filter(e=>e!==o)]}));return}case`wallet_verifySignature`:{let[e]=r._decoded.params,{address:t,chainId:n,digest:i,signature:a}=e,o=s(n);return{...await QR(o,{address:t,digest:i,signature:a}),address:t,chainId:I(o.chain.id)}}}},{enabled:r,id:df(e)})}});function f(){let e=()=>{},t=()=>{};mB(i).then(()=>{o().catch(()=>{}),e(),e=i.subscribe(e=>e.accounts,e=>{u.emit(`accountsChanged`,e.map(bB))},{equalityFn:(e,t)=>e.every((e,n)=>e.address===t[n]?.address)}),t(),t=i.subscribe(e=>e.chainIds[0],(e,t)=>{e!==t&&u.emit(`chainChanged`,I(e))})});let n=_B(d,a);return()=>{e(),t(),n()}}let p=f();return Object.assign(d,{_internal:{destroy:p}})}function _B(e,t){if(!t||typeof window>`u`||!window.dispatchEvent)return()=>{};let{icon:n=`data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDIyIiBoZWlnaHQ9IjQyMiIgdmlld0JveD0iMCAwIDQyMiA0MjIiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSI0MjIiIGhlaWdodD0iNDIyIiBmaWxsPSJibGFjayIvPgo8ZyBjbGlwLXBhdGg9InVybCgjY2xpcDBfMV8xNSkiPgo8cGF0aCBkPSJNODEgMjg2LjM2NkM4MSAyODAuODkzIDg1LjQ1MDUgMjc2LjQ1NSA5MC45NDA0IDI3Ni40NTVIMzI5LjUxMUMzMzUuMDAxIDI3Ni40NTUgMzM5LjQ1MiAyODAuODkzIDMzOS40NTIgMjg2LjM2NlYzMDYuMTg4QzMzOS40NTIgMzExLjY2MiAzMzUuMDAxIDMxNi4wOTkgMzI5LjUxMSAzMTYuMDk5SDkwLjk0MDRDODUuNDUwNSAzMTYuMDk5IDgxIDMxMS42NjIgODEgMzA2LjE4OFYyODYuMzY2WiIgZmlsbD0id2hpdGUiIGZpbGwtb3BhY2l0eT0iMC41Ii8+CjxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBkPSJNOTAuOTQwNCAyMzQuODI4Qzg1LjQ1MDUgMjM0LjgyOCA4MSAyMzkuMjY2IDgxIDI0NC43MzlWMjcxLjUzMUM4My44NDMyIDI2OS42MzMgODcuMjYyMiAyNjguNTI2IDkwLjk0MDQgMjY4LjUyNkgzMjkuNTExQzMzMy4xODggMjY4LjUyNiAzMzYuNjA4IDI2OS42MzMgMzM5LjQ1MiAyNzEuNTMxVjI0NC43MzlDMzM5LjQ1MiAyMzkuMjY2IDMzNS4wMDEgMjM0LjgyOCAzMjkuNTExIDIzNC44MjhIOTAuOTQwNFpNMzM5LjQ1MiAyODYuMzY2QzMzOS40NTIgMjgwLjg5MyAzMzUuMDAxIDI3Ni40NTUgMzI5LjUxMSAyNzYuNDU1SDkwLjk0MDRDODUuNDUwNSAyNzYuNDU1IDgxIDI4MC44OTMgODEgMjg2LjM2NlYzMDYuMTlDODEgMzExLjY2NCA4NS40NTA1IDMxNi4xMDEgOTAuOTQwNCAzMTYuMTAxSDMyOS41MTFDMzM1LjAwMSAzMTYuMTAxIDMzOS40NTIgMzExLjY2NCAzMzkuNDUyIDMwNi4xOVYyODYuMzY2WiIgZmlsbD0id2hpdGUiIGZpbGwtb3BhY2l0eT0iMC41Ii8+CjxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBkPSJNOTAuOTQwNCAxOTMuMjAxQzg1LjQ1MDUgMTkzLjIwMSA4MSAxOTcuNjM4IDgxIDIwMy4xMTJWMjI5LjkwM0M4My44NDMyIDIyOC4wMDYgODcuMjYyMiAyMjYuODk5IDkwLjk0MDQgMjI2Ljg5OUgzMjkuNTExQzMzMy4xODggMjI2Ljg5OSAzMzYuNjA4IDIyOC4wMDYgMzM5LjQ1MiAyMjkuOTAzVjIwMy4xMTJDMzM5LjQ1MiAxOTcuNjM4IDMzNS4wMDEgMTkzLjIwMSAzMjkuNTExIDE5My4yMDFIOTAuOTQwNFpNMzM5LjQ1MiAyNDQuNzM5QzMzOS40NTIgMjM5LjI2NSAzMzUuMDAxIDIzNC44MjggMzI5LjUxMSAyMzQuODI4SDkwLjk0MDRDODUuNDUwNSAyMzQuODI4IDgxIDIzOS4yNjUgODEgMjQ0LjczOVYyNzEuNTNDODEuMjE3NSAyNzEuMzg1IDgxLjQzODMgMjcxLjI0NSA4MS42NjI0IDI3MS4xMDlDODMuODMyNSAyNjkuNzk0IDg2LjMwNTQgMjY4LjkyNyA4OC45NTIzIDI2OC42MzVDODkuNjA1MSAyNjguNTYzIDkwLjI2ODQgMjY4LjUyNiA5MC45NDA0IDI2OC41MjZIMzI5LjUxMUMzMzAuMTgzIDI2OC41MjYgMzMwLjg0NiAyNjguNTYzIDMzMS40OTggMjY4LjYzNUMzMzQuNDE5IDI2OC45NTcgMzM3LjEyOCAyNjkuOTggMzM5LjQ1MiAyNzEuNTNWMjQ0LjczOVpNMzM5LjQ1MiAyODYuMzY2QzMzOS40NTIgMjgxLjAyMSAzMzUuMjA2IDI3Ni42NjMgMzI5Ljg5MyAyNzYuNDYyQzMyOS43NjcgMjc2LjQ1NyAzMjkuNjQgMjc2LjQ1NSAzMjkuNTExIDI3Ni40NTVIOTAuOTQwNEM4NS40NTA1IDI3Ni40NTUgODEgMjgwLjg5MyA4MSAyODYuMzY2VjMwNi4xODhDODEgMzExLjY2MiA4NS40NTA1IDMxNi4xMDEgOTAuOTQwNCAzMTYuMTAxSDMyOS41MTFDMzM1LjAwMSAzMTYuMTAxIDMzOS40NTIgMzExLjY2MiAzMzkuNDUyIDMwNi4xODhWMjg2LjM2NloiIGZpbGw9IndoaXRlIiBmaWxsLW9wYWNpdHk9IjAuNSIvPgo8cGF0aCBvcGFjaXR5PSIwLjMiIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBkPSJNOTguMDE0NiAxMDRDODguNjE3NyAxMDQgODEgMTExLjU5NSA4MSAxMjAuOTY1VjE4OC4yNzZDODMuODQzMiAxODYuMzc5IDg3LjI2MjIgMTg1LjI3MiA5MC45NDA0IDE4NS4yNzJIMzI5LjUxMUMzMzMuMTg4IDE4NS4yNzIgMzM2LjYwOCAxODYuMzc5IDMzOS40NTIgMTg4LjI3NlYxMjAuOTY1QzMzOS40NTIgMTExLjU5NSAzMzEuODMzIDEwNCAzMjIuNDM3IDEwNEg5OC4wMTQ2Wk0zMzkuNDUyIDIwMy4xMTJDMzM5LjQ1MiAxOTcuNjM4IDMzNS4wMDEgMTkzLjIwMSAzMjkuNTExIDE5My4yMDFIOTAuOTQwNEM4NS40NTA1IDE5My4yMDEgODEgMTk3LjYzOCA4MSAyMDMuMTEyVjIyOS45MDNDODEuMjE3NSAyMjkuNzU4IDgxLjQzODMgMjI5LjYxOCA4MS42NjI0IDIyOS40ODJDODMuODMyNSAyMjguMTY3IDg2LjMwNTQgMjI3LjMgODguOTUyMyAyMjcuMDA4Qzg5LjYwNTEgMjI2LjkzNiA5MC4yNjg0IDIyNi44OTkgOTAuOTQwNCAyMjYuODk5SDMyOS41MTFDMzMwLjE4MyAyMjYuODk5IDMzMC44NDYgMjI2LjkzNiAzMzEuNDk4IDIyNy4wMDhDMzM0LjQxOSAyMjcuMzMgMzM3LjEyOCAyMjguMzUyIDMzOS40NTIgMjI5LjkwM1YyMDMuMTEyWk0zMzkuNDUyIDI0NC43MzlDMzM5LjQ1MiAyMzkuMzkzIDMzNS4yMDYgMjM1LjAzNiAzMjkuODkzIDIzNC44MzVDMzI5Ljc2NyAyMzQuODMgMzI5LjY0IDIzNC44MjggMzI5LjUxMSAyMzQuODI4SDkwLjk0MDRDODUuNDUwNSAyMzQuODI4IDgxIDIzOS4yNjUgODEgMjQ0LjczOVYyNzEuNTNMODEuMDcwNyAyNzEuNDgzQzgxLjI2NTMgMjcxLjM1NSA4MS40NjI1IDI3MS4yMyA4MS42NjI0IDI3MS4xMDlDODEuOTA4MyAyNzAuOTYgODIuMTU4MSAyNzAuODE3IDgyLjQxMTcgMjcwLjY3OUM4NC4zOTUzIDI2OS42MDUgODYuNjA1NCAyNjguODk0IDg4Ljk1MjMgMjY4LjYzNUM4OS4wMDUyIDI2OC42MjkgODkuMDU4IDI2OC42MjQgODkuMTExIDI2OC42MThDODkuNzEyNSAyNjguNTU3IDkwLjMyMjggMjY4LjUyNiA5MC45NDA0IDI2OC41MjZIMzI5LjUxMUMzMjkuNzM4IDI2OC41MjYgMzI5Ljk2NSAyNjguNTMgMzMwLjE5MiAyNjguNTM5QzMzMC42MzEgMjY4LjU1NSAzMzEuMDY3IDI2OC41ODcgMzMxLjQ5OCAyNjguNjM1QzMzNC40MTkgMjY4Ljk1NyAzMzcuMTI4IDI2OS45OCAzMzkuNDUyIDI3MS41M1YyNDQuNzM5Wk0zMzkuNDUyIDI4Ni4zNjZDMzM5LjQ1MiAyODEuMDIxIDMzNS4yMDYgMjc2LjY2MyAzMjkuODkzIDI3Ni40NjJMMzI5Ljg2NSAyNzYuNDYxQzMyOS43NDggMjc2LjQ1NyAzMjkuNjI5IDI3Ni40NTUgMzI5LjUxMSAyNzYuNDU1SDkwLjk0MDRDODUuNDUwNSAyNzYuNDU1IDgxIDI4MC44OTMgODEgMjg2LjM2NlYzMDYuMTg4QzgxIDMxMS42NjIgODUuNDUwNSAzMTYuMTAxIDkwLjk0MDQgMzE2LjEwMUgzMjkuNTExQzMzNS4wMDEgMzE2LjEwMSAzMzkuNDUyIDMxMS42NjIgMzM5LjQ1MiAzMDYuMTg4VjI4Ni4zNjZaIiBmaWxsPSJ3aGl0ZSIvPgo8cGF0aCBkPSJNMjY5Ljg2OCAxMzEuNzUyQzI2OS44NjggMTI2LjI3OCAyNzQuMzE4IDEyMS44NCAyNzkuODA4IDEyMS44NEgzMTEuNjE4QzMxNy4xMDggMTIxLjg0IDMyMS41NTggMTI2LjI3OCAzMjEuNTU4IDEzMS43NTJWMTYxLjQ4NUMzMjEuNTU4IDE2Ni45NTkgMzE3LjEwOCAxNzEuMzk2IDMxMS42MTggMTcxLjM5NkgyNzkuODA4QzI3NC4zMTggMTcxLjM5NiAyNjkuODY4IDE2Ni45NTkgMjY5Ljg2OCAxNjEuNDg1VjEzMS43NTJaIiBmaWxsPSJ3aGl0ZSIvPgo8L2c+CjxkZWZzPgo8Y2xpcFBhdGggaWQ9ImNsaXAwXzFfMTUiPgo8cmVjdCB3aWR0aD0iMjU5IiBoZWlnaHQ9IjIxMyIgZmlsbD0id2hpdGUiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDgxIDEwNCkiLz4KPC9jbGlwUGF0aD4KPC9kZWZzPgo8L3N2Zz4K`,name:r=`Porto`,rdns:i=`xyz.ithaca.porto`}=typeof t==`object`?t:{};return jN({info:{icon:n,name:r,rdns:i,uuid:hN()},provider:e})}function vB(e){return e.map(e=>{if(e.role===`admin`)try{return pP(Wz.Key,{id:e.id??e.publicKey,publicKey:e.publicKey,type:e.type,...e.type===`webauthn-p256`?{credentialId:e.privateKey?.credential?.id,privateKey:{credential:{id:e.privateKey?.credential?.id},rpId:e.privateKey?.rpId}}:{}})}catch{return}}).filter(Boolean)}function yB(e,{address:t}){return e.map(e=>{if(e.chainId&&e.role===`session`&&!(e.expiry>0&&e.expiry<BigInt(Math.floor(Date.now()/1e3))))try{return pP(_z,vz(e,{address:t}))}catch{return}}).filter(Boolean)}function bB(e){return _i(e.address)}op();function xB(e){return{...e,setup:e.setup??(()=>()=>{})}}async function SB(e){let{account:t,calls:n,permissionsId:r}=e;if(r!==void 0){if(r===null)return;let e=t.keys?.find(e=>e.publicKey===r&&e.privateKey);if(!e)throw Error(`permission (id: ${r}) does not exist.`);return e}let i=t.keys?.find(e=>!e.privateKey||e.role!==`session`||e.expiry<BigInt(Math.floor(Date.now()/1e3))?!1:!!n.every(t=>e.permissions?.calls?.some(e=>{if(e.to&&e.to!==t.to)return!1;if(e.signature){if(!t.data)return!1;let n=Kf(t.data,0,4);if(Zf(e.signature))return e.signature===n;if(W_(e.signature)!==n)return!1}return!0}))),a=t.keys?.find(e=>e.role===`admin`&&e.privateKey);return i??a}function CB(e={}){let t=e.id??0;return{prepare(e){return wB({id:t++,...e})},get id(){return t}}}function wB(e){return{...e,jsonrpc:`2.0`}}function TB(){return null}const EB=gz;function DB(e){let{expiry:t,feeToken:n,permissions:r,publicKey:i,type:a}=e;return{expiry:t,feeToken:n??null,key:{publicKey:i,type:a},permissions:r??{}}}async function OB(e,t={}){if(!e)return;let n=t.chainId??e.chainId,r=e.expiry??0,i=e.feeToken,a=OL(e,{feeTokens:t.feeTokens}),o={chainId:n,expiry:r,feeToken:i,permissions:a,role:`session`};if(e?.key)return vL({...o,publicKey:e.key.publicKey,type:e.key.type??`secp256k1`});if(typeof globalThis.crypto?.subtle?.generateKey==`function`)try{return await _L(o)}catch(e){if(!kB(e))throw e}return mL(o)}function kB(e){if(!(e instanceof Error))return!1;let t=e.message?.toLowerCase()??``;return e.name===`TypeError`||e.name===`ReferenceError`||t.includes(`subtle`)||t.includes(`generatekey`)}Jd();const AB=/^([a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\\.)+[a-zA-Z]{2,}(:[0-9]{1,5})?$/,jB=/^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(:[0-9]{1,5})?$/,MB=/^localhost(:[0-9]{1,5})?$/,NB=/^[a-zA-Z0-9]{8,}$/,PB=/^([a-zA-Z][a-zA-Z0-9+-.]*)$/,FB=/^(?:(?<scheme>[a-zA-Z][a-zA-Z0-9+-.]*):\\/\\/)?(?<domain>[a-zA-Z0-9+-.]*(?::[0-9]{1,5})?) (?:wants you to sign in with your Ethereum account:\\n)(?<address>0x[a-fA-F0-9]{40})\\n\\n(?:(?<statement>.*)\\n\\n)?/,IB=/(?:URI: (?<uri>.+))\\n(?:Version: (?<version>.+))\\n(?:Chain ID: (?<chainId>\\d+))\\n(?:Nonce: (?<nonce>[a-zA-Z0-9]+))\\n(?:Issued At: (?<issuedAt>.+))(?:\\nExpiration Time: (?<expirationTime>.+))?(?:\\nNot Before: (?<notBefore>.+))?(?:\\nRequest ID: (?<requestId>.+))?/;function LB(e){let{chainId:t,domain:n,expirationTime:r,issuedAt:i=new Date,nonce:a,notBefore:o,requestId:s,resources:c,scheme:l,uri:u,version:d}=e;{if(t!==Math.floor(t))throw new VB({field:`chainId`,metaMessages:[`- Chain ID must be a EIP-155 chain ID.`,`- See https://eips.ethereum.org/EIPS/eip-155`,``,`Provided value: ${t}`]});if(!(AB.test(n)||jB.test(n)||MB.test(n)))throw new VB({field:`domain`,metaMessages:[`- Domain must be an RFC 3986 authority.`,`- See https://www.rfc-editor.org/rfc/rfc3986`,``,`Provided value: ${n}`]});if(!NB.test(a))throw new VB({field:`nonce`,metaMessages:[`- Nonce must be at least 8 characters.`,`- Nonce must be alphanumeric.`,``,`Provided value: ${a}`]});if(!RB(u))throw new VB({field:`uri`,metaMessages:[`- URI must be a RFC 3986 URI referring to the resource that is the subject of the signing.`,`- See https://www.rfc-editor.org/rfc/rfc3986`,``,`Provided value: ${u}`]});if(d!==`1`)throw new VB({field:`version`,metaMessages:[`- Version must be '1'.`,``,`Provided value: ${d}`]});if(l&&!PB.test(l))throw new VB({field:`scheme`,metaMessages:[`- Scheme must be an RFC 3986 URI scheme.`,`- See https://www.rfc-editor.org/rfc/rfc3986#section-3.1`,``,`Provided value: ${l}`]});let r=e.statement;if(r?.includes(`\n`))throw new VB({field:`statement`,metaMessages:[`- Statement must not include '\\\\n'.`,``,`Provided value: ${r}`]})}let f=rg(e.address,{checksum:!0}),p=(()=>l?`${l}://${n}`:n)(),m=(()=>e.statement?`${e.statement}\\n`:``)(),h=`${p} wants you to sign in with your Ethereum account:\\n${f}\\n\\n${m}`,g=`URI: ${u}\\nVersion: ${d}\\nChain ID: ${t}\\nNonce: ${a}\\nIssued At: ${i.toISOString()}`;if(r&&(g+=`\\nExpiration Time: ${r.toISOString()}`),o&&(g+=`\\nNot Before: ${o.toISOString()}`),s&&(g+=`\\nRequest ID: ${s}`),c){let e=`\nResources:`;for(let t of c){if(!RB(t))throw new VB({field:`resources`,metaMessages:[`- Every resource must be a RFC 3986 URI.`,`- See https://www.rfc-editor.org/rfc/rfc3986`,``,`Provided value: ${t}`]});e+=`\\n- ${t}`}g+=e}return`${h}\\n${g}`}function RB(e){if(/[^a-z0-9:/?#[\\]@!$&'()*+,;=.\\-_~%]/i.test(e)||/%[^0-9a-f]/i.test(e)||/%[0-9a-f](:?[^0-9a-f]|$)/i.test(e))return!1;let t=zB(e),n=t[1],r=t[2],i=t[3],a=t[4],o=t[5];if(!(n?.length&&i&&i.length>=0))return!1;if(r?.length){if(!(i.length===0||/^\\//.test(i)))return!1}else if(/^\\/\\//.test(i))return!1;if(!/^[a-z][a-z0-9+\\-.]*$/.test(n.toLowerCase()))return!1;let s=``;return s+=`${n}:`,r?.length&&(s+=`//${r}`),s+=i,a?.length&&(s+=`?${a}`),o?.length&&(s+=`#${o}`),s}function zB(e){return e.match(/(?:([^:/?#]+):)?(?:\\/\\/([^/?#]*))?([^?#]*)(?:\\?([^#]*))?(?:#(.*))?/)}function BB(e){let{scheme:t,statement:n,...r}=e.match(FB)?.groups??{},{chainId:i,expirationTime:a,issuedAt:o,notBefore:s,requestId:c,...l}=e.match(IB)?.groups??{},u=e.split(`Resources:`)[1]?.split(`\n- `).slice(1);return{...r,...l,...i?{chainId:Number(i)}:{},...a?{expirationTime:new Date(a)}:{},...o?{issuedAt:new Date(o)}:{},...s?{notBefore:new Date(s)}:{},...c?{requestId:c}:{},...u?{resources:u}:{},...t?{scheme:t}:{},...n?{statement:n}:{}}}var VB=class extends P{constructor(e){let{field:t,metaMessages:n}=e;super(`Invalid Sign-In with Ethereum message field \"${t}\".`,{metaMessages:n}),Object.defineProperty(this,`name`,{enumerable:!0,configurable:!0,writable:!0,value:`Siwe.InvalidMessageFieldError`})}};async function HB(e){let{address:t,authUrl:n,message:r,signature:i,publicKey:a}=e,{chainId:o}=BB(r);return await fetch(n.verify,{body:JSON.stringify({address:t,chainId:o,message:r,signature:i,walletAddress:t,...a&&{publicKey:a}}),credentials:`include`,headers:{\"Content-Type\":`application/json`},method:`POST`}).then(e=>e.json())}async function UB(e,t,n){let{chainId:r=e.chain?.id,domain:i,uri:a,resources:o,version:s=`1`}=t,{address:c}=n,l=t.authUrl?WB(t.authUrl):void 0;if(!r)throw Error(\"`chainId` is required.\");if(!i)throw Error(\"`domain` is required.\");if(!t.nonce&&!l?.nonce)throw Error(\"`nonce` or `authUrl.nonce` is required.\");if(!a)throw Error(\"`uri` is required.\");let u=await(async()=>{if(t.nonce)return t.nonce;if(!l?.nonce)throw Error(\"`nonce` or `authUrl.nonce` is required.\");let e=await(await fetch(l.nonce,{body:JSON.stringify({address:c,chainId:r,walletAddress:c}),headers:{\"Content-Type\":`application/json`},method:`POST`})).json().catch(()=>void 0);if(!e?.nonce)throw Error(\"`nonce` or `authUrl.nonce` is required.\");return e.nonce})();return LB({...t,address:n.address,chainId:r,domain:i,nonce:u,resources:o,uri:a,version:s})}function WB(e,t=``){if(!e)return;let n=(()=>{if(typeof e==`string`){let t=e.replace(/\\/$/,``);return{logout:t+`/logout`,nonce:t+`/nonce`,verify:t+`/verify`}}return e})();return{logout:GB(n.logout,t),nonce:GB(n.nonce,t),verify:GB(n.verify,t)}}function GB(e,t){return!t||!e.startsWith(`/`)?e:t+e}op();function KB(e){let t=Bf(e);return zf(`0x19`,Uf(`Ethereum Signed Message:\n`+qf(t)),t)}function qB(e){return Hh(KB(e))}async function JB(e,t){let{account:n=e.account}=t,r=n?ML(n):void 0;if(!r)throw Error(`account is required.`);let{domain:{name:i,version:a}}=await $m(e,{address:r.address});if(!e.chain)throw Error(`client.chain is required`);return{chainId:e.chain.id,name:i,verifyingContract:r.address,version:a}}async function YB(e,t){let{account:n=e.account,chainIds:r}=t,i=n?ML(n):void 0;if(!i)throw Error(`account is required.`);let a=await UR(e,{address:i.address,chainIds:r});return Object.entries(a).flatMap(([e,t])=>t.map(t=>bL(t,{chainId:Number(e)})))}async function XB(e,t){let{account:n=e.account,calls:r,chain:i=e.chain,feePayer:a,merchantUrl:o,nonce:s,preCalls:c,requiredFunds:l,revokeKeys:u}=t,d=n?ML(n):void 0,f=t.key??(d?PL(d,{role:`admin`}):void 0),p=t.authorizeKeys?.some(e=>e.role===`session`),{contracts:m,fees:{tokens:h}}=await BR(e,{chainId:i?.id}),g=p?m.orchestrator.address:void 0,_=(t.authorizeKeys??[]).map(e=>DL(e,{feeTokens:h,orchestrator:g})),v=(()=>t.feeToken?t.feeToken:f?.permissions?.spend?.[0]?.token)(),y=typeof c==`boolean`?c:!1,b=typeof c==`object`?c.map(({context:e,signature:t})=>({...e.preCall,signature:t})):void 0,x={address:d?.address,calls:r??[],capabilities:{authorizeKeys:_,meta:{feePayer:a,feeToken:v,nonce:s},preCall:y,preCalls:b,requiredFunds:l,revokeKeys:u?.map(e=>({hash:e.hash}))},chain:i,key:f?DL(f,{feeTokens:h}):void 0},S=await(async()=>{if(o){let t=Xm({chain:e.chain,transport:zv(o)});return await GR(t,x).catch(t=>(console.error(t),GR(e,x)))}return await GR(e,x)})(),{capabilities:C,context:w,digest:ee,signature:te,typedData:ne}=S;if(o&&!await ZR(e,{response:S._raw,signature:te}))throw Error(`cannot verify integrity of \\`wallet_prepareCalls\\` response from ${o}`);return{capabilities:{...C,quote:w.quote},context:w,digest:ee,key:f,typedData:ne}}async function ZB(e,t){let{address:n,authorizeKeys:r,chain:i=e.chain}=t;if(!i)throw Error(`chain is required.`);let{contracts:a,fees:{tokens:o}}=await BR(e,{chainId:i.id}),s=t.delegation??a.accountProxy.address,c=r.some(e=>e.role===`session`)?a.orchestrator.address:void 0,l=r.map(e=>{let t=e.role===`session`?e.permissions:{};return DL({...e,permissions:t},{feeTokens:o,orchestrator:c})}),{capabilities:u,chainId:d,context:f,digests:p,typedData:m}=await KR(e,{address:n,authorizeKeys:l,chain:i,delegation:s}),h=ML({address:n,keys:r});return{capabilities:u,chainId:d,context:{...f,account:h},digests:p,typedData:m}}async function QB(e,t){let{account:n=e.account,chain:r=e.chain,webAuthn:i}=t;if(!r)throw Error(\"`chain` is required.\");let a=n?ML(n):void 0;if(!a)throw Error(\"`account` is required.\");let o=t.key??PL(a,t);if(!o&&!a.sign)throw Error(\"`key` or `account` with `sign` is required\");let s=await Promise.all((t.preCalls??[]).map(async n=>{if(n.signature)return n;let{authorizeKeys:o,key:s,calls:c,revokeKeys:l}=n,{context:u,digest:d}=await XB(e,{account:a,authorizeKeys:o,calls:c,chain:r,feeToken:t.feeToken,key:s,preCalls:!0,revokeKeys:l}),f=await EL(s,{address:null,payload:d,webAuthn:i});return{context:u,signature:f}})),{capabilities:c,context:l,digest:u}=await XB(e,{...t,account:a,chain:r,key:o,preCalls:s}),d=await(async()=>o?await EL(o,{address:null,payload:u,webAuthn:i,wrap:!1}):await a.sign({hash:u}))();return await $B(e,{capabilities:c.feeSignature?{feeSignature:c.feeSignature}:void 0,context:l,key:o,signature:d})}async function $B(e,t){let{capabilities:n,context:r,key:i,signature:a}=t;return await qR(e,{capabilities:n,context:r,key:i?DL(i):void 0,signature:a})}async function eV(e,t){let{email:n,walletAddress:r}=t;return await JR(e,{email:n,walletAddress:r})}async function tV(e,t){if(t.account){let{account:n}=t,r=[...n.keys??[],...t.authorizeKeys??[]].filter((e,t,n)=>n.findIndex(t=>t.id===e.id)===t),{digests:i,...a}=await ZB(e,{...t,address:n.address,authorizeKeys:r}),o={auth:await n.sign({hash:i.auth}),exec:await n.sign({hash:i.exec})};return await tV(e,{...a,signatures:o})}let{context:n,signatures:r}=t,i=ML(n.account);return await YR(e,{context:n,signatures:r}),i}async function nV(e,t){let{chainId:n,email:r,signature:i,token:a,walletAddress:o}=t;return await XR(e,{chainId:n,email:r,signature:i,token:a,walletAddress:o})}async function rV(e,t){let{address:n}=t,{authorization:r,data:i,to:a}=await zR(e,{address:n});return P_({authorization:{...r,nonce:BigInt(r.nonce),r:BigInt(r.r),s:BigInt(r.s)},data:i,signature:t.signature,to:a})}function iV(e,t){let{tokens:n}=t,r=n.filter(e=>e.interop);return e.map(e=>{if(e.address)return e;let t=r.find(t=>t.symbol===e.symbol);if(!t)throw Error(`interop token not found: ${e.symbol}`);return{address:t.address,value:LI(e.value,t.decimals)}})}async function aV(e,t){let{chain:n=e.chain}=t??{};return await BR(e,{chainId:n?.id}).then(e=>e.fees.tokens)}async function oV(e,t){let{addressOrSymbol:n}=t;return(await aV(e,t)).find(oV.predicate(n))}(function(e){function t(e){return t=>e?og(e)?ag(t.address,e):e===`native`?t.address===Q_:e===t.symbol:!1}e.predicate=t})(oV||={});async function sV(e,t){let{chain:n=e.chain,store:r}=t??{},i=r?.getState()??{},a=t?.addressOrSymbol??i.feeToken;return(await aV(e,{chain:n}).then(e=>e.filter(e=>e.feeToken)))?.find(e=>a?a===`native`&&e.address===`0x0000000000000000000000000000000000000000`||og(a)&&ag(e.address,a)?!0:a===e.symbol:!1)}Lf(),op(),pf();function cV(e={}){let t=e,{mock:n,multichain:r=!0,webAuthn:i}=t,a,o,s=(()=>{if(t.keystoreHost!==`self`&&!(typeof window<`u`&&window.location?.hostname===`localhost`))return t.keystoreHost})();return xB({actions:{async addFunds(){throw new WM},async createAccount(e){let{admins:t,email:r,label:o,permissions:c,internal:l,signInWithEthereum:u}=e,{client:d}=l,f=NL(D_()),p=await aV(d),m=n?gL():await hL({createFn:i?.createFn,label:o||`${f.address.slice(0,8)}\\u2026${f.address.slice(-6)}`,rpId:s,userId:hf(f.address)}),h=await OB(c,{chainId:d.chain.id,feeTokens:p}),g=t?.map(e=>vL(e)),_=await tV(d,{account:f,authorizeKeys:[m,...g??[],...h?[h]:[]]});a=f.address,r&&o&&await eV(d,{email:o,walletAddress:_.address});let v=await(async()=>{if(!u)return;let e=await UB(d,u,{address:_.address}),t=await FL(f,{payload:qB(Uf(e))}),n=await rV(d,{address:_.address,signature:t});return{message:e,signature:n}})();return{account:{..._,signInWithEthereum:v}}},async getAccountVersion(e){let{address:t,internal:n}=e,{client:r}=n,{contracts:i}=await BR(r),{accountImplementation:a}=i,o=await JB(r,{account:ML(a)}).then(e=>e.version),s=await JB(r,{account:t}).then(e=>e.version).catch(()=>o);if(!s||!o)throw Error(`version not found.`);return{current:s,latest:o}},async getAssets(e){let{account:t,chainFilter:n,assetFilter:r,assetTypeFilter:i,internal:a}=e,{client:o}=a;return await VR(o,{account:t,assetFilter:r,assetTypeFilter:i,chainFilter:n})},async getCallsStatus(e){let{id:t,internal:n}=e,{client:r}=n,i=await HR(r,{id:t});return{atomic:!0,chainId:I(r.chain.id),id:t,receipts:i.receipts?.map(e=>({blockHash:e.blockHash,blockNumber:I(e.blockNumber),gasUsed:I(e.gasUsed),logs:e.logs,status:e.status,transactionHash:e.transactionHash})),status:i.status,version:`1.0`}},async getCapabilities(e){let{chainIds:t,internal:n}=e,{client:i}=n,a={atomic:{status:`supported`},atomicBatch:{supported:!0},feeToken:{supported:!0,tokens:[]},merchant:{supported:!0},permissions:{supported:!0},requiredFunds:{supported:!!r,tokens:[]}},o=await BR(i,{chainIds:t?t.map(e=>Xf(e)):`all`,raw:!0});return Object.entries(o).reduce((e,[t,n])=>({...e,[t]:{...a,...n,feeToken:{supported:!0,tokens:n.fees.tokens},requiredFunds:{supported:!!r,tokens:r?n.fees.tokens.filter(e=>e.interop):[]}}}),{})},async getKeys(e){let{account:t,chainIds:n,internal:r}=e,{client:i}=r,a=await YB(i,{account:t,chainIds:n});return mN([...a,...t.keys??[]],e=>e.publicKey)},async grantAdmin(e){let{account:t,internal:n}=e,{client:r}=n,a=vL(e.key,{chainId:r.chain.id}),o=await sV(r,{addressOrSymbol:e.feeToken,store:n.store}),{id:s}=await QB(r,{account:t,authorizeKeys:[a],feeToken:o?.address,webAuthn:i});return await Wm(r,{id:s,pollingInterval:500}),{key:a}},async grantPermissions(e){let{account:t,internal:n,permissions:r}=e,{client:i}=n,a=await aV(i),o=await OB(r,{chainId:i.chain.id,feeTokens:a});if(!o)throw Error(`key to authorize not found.`);let s=t.keys?.find(e=>e.role===`admin`&&e.privateKey);if(!s)throw Error(`admin key not found.`);let{context:c,digest:l}=await XB(i,{account:t,authorizeKeys:[o],key:s,preCalls:!0}),u=await EL(s,{address:null,payload:l});return await $B(i,{context:c,key:s,signature:u}),{key:o}},async loadAccounts(e){let{internal:t,permissions:r,signInWithEthereum:o}=e,{client:c}=t,l=await aV(c),u=await OB(r,{chainId:c.chain.id,feeTokens:l}),{digest:d,digestType:f,message:p}=await(async()=>{if(o&&e.address){let t=await UB(c,o,{address:e.address});return{context:void 0,digest:qB(Uf(t)),digestType:`siwe`,message:t}}return{context:void 0,digest:`0x`,message:void 0}})(),{address:m,credentialId:h,webAuthnSignature:g}=await(async()=>{if(n){if(!a)throw Error(`address_internal not found.`);return{address:a,credentialId:void 0}}if(e.address&&e.key)return{address:e.address,credentialId:e.key.credentialId};let t=await tL({challenge:d,getFn:i?.getFn,rpId:s}),r=t.raw.response,o=wf(new Uint8Array(r.userHandle)),c=t.raw.id;return{address:o,credentialId:c,webAuthnSignature:t}})(),_=await YB(c,{account:m,chainIds:[c.chain.id]}),v=ML({address:m,keys:[..._,...u?[u]:[]].map((e,t)=>t===0&&e.type===`webauthn-p256`?xL({...e,credential:{id:h,publicKey:qh(e.publicKey)},id:m,rpId:s}):e)}),y=PL(v,{role:`admin`}),b=await(async()=>{if(d!==`0x`)return g?jL(AL(g),{keyType:`webauthn-p256`,publicKey:y.publicKey}):await EL(y,{address:v.address,payload:d})})();if(u){let{context:e,digest:t}=await XB(c,{account:v,authorizeKeys:[u],preCalls:!0}),n=await EL(y,{address:null,payload:t});await $B(c,{context:e,key:y,signature:n})}let x=await(async()=>{if(o){if(f===`siwe`&&p&&b){let e=await rV(c,{address:v.address,signature:b});return{message:p,signature:e}}{let e=await UB(c,o,{address:v.address}),t=await FL(v,{payload:qB(Uf(e)),role:`admin`}),n=await rV(c,{address:v.address,signature:t});return{message:e,signature:n}}}})();return{accounts:[{...v,signInWithEthereum:x}]}},async prepareCalls(e){let{account:t,calls:n,internal:i,merchantUrl:a}=e,{client:o}=i,s=e.key??await SB({account:t,calls:n});if(!s)throw Error(`cannot find authorized key to sign with.`);let[c,l]=await Promise.all([aV(o),sV(o,{addressOrSymbol:e.feeToken,store:i.store})]),u=iV(e.requiredFunds??[],{tokens:c}),{capabilities:d,context:f,digest:p,typedData:m}=await XB(o,{account:t,calls:n,feeToken:l?.address,key:s,merchantUrl:a,requiredFunds:r?u:void 0}),h=f.quote?.quotes??[],g=h[h.length-1];return{account:t,capabilities:{...d,quote:f.quote},chainId:o.chain.id,context:{...f,account:t,calls:n,nonce:g?.intent.nonce},digest:p,key:s,typedData:m}},async prepareUpgradeAccount(e){let{address:t,email:r,label:a,internal:c,permissions:l}=e,{client:u}=c,[d,f]=await Promise.all([aV(u),sV(u,{store:c.store})]),p=n?gL():await hL({createFn:i?.createFn,label:a||`${t.slice(0,8)}\\u2026${t.slice(-6)}`,rpId:s,userId:hf(t)}),m=await OB(l,{chainId:u.chain.id,feeTokens:d}),{context:h,digests:g}=await ZB(u,{address:t,authorizeKeys:[p,...m?[m]:[]],feeToken:f?.address});return r&&(o=a),{context:h,digests:g}},async revokeAdmin(e){let{account:t,id:n,internal:r}=e,{client:a}=r,o=t.keys?.find(e=>e.id===n);if(o){if(o.type===`webauthn-p256`&&t.keys?.filter(e=>e.type===`webauthn-p256`).length===1)throw Error(`revoke the only WebAuthn key left.`);try{let n=await sV(a,{addressOrSymbol:e.feeToken,store:r.store}),{id:s}=await QB(a,{account:t,feeToken:n?.address,revokeKeys:[o],webAuthn:i});await Wm(a,{id:s})}catch(e){let t=e;if(t.name===`Rpc.ExecutionError`&&t.abiError?.name===`KeyDoesNotExist`)return;throw e}}},async revokePermissions(e){let{account:t,id:n,internal:r}=e,{client:a}=r,o=t.keys?.find(e=>e.id===n);if(o){if(o.role===`admin`)throw Error(`cannot revoke admins.`);try{let n=await sV(a,{addressOrSymbol:e.feeToken,store:r.store}),{id:s}=await QB(a,{account:t,feeToken:n?.address,revokeKeys:[o],webAuthn:i});await Wm(a,{id:s})}catch(e){let t=e;if(t.name===`Rpc.ExecutionError`&&t.abiError?.name===`KeyDoesNotExist`)return;throw e}}},async sendCalls(e){let{account:t,asTxHash:n,calls:a,chainId:o,internal:s,merchantUrl:c}=e,{client:l}=s,u=await SB({account:t,calls:a,permissionsId:e.permissionsId}),[d,f]=await Promise.all([aV(l),sV(l,{addressOrSymbol:e.feeToken,store:s.store})]),p=iV(e.requiredFunds??[],{tokens:d}),m=await QB(l,{account:t,calls:a,feeToken:f?.address,key:u,merchantUrl:c,requiredFunds:r?p:void 0,webAuthn:i,...o?{chain:{id:o}}:{}});if(n){let{id:e,receipts:t,status:n}=await Wm(l,{id:m.id,pollingInterval:500});if(!t?.[0])throw n===`success`?new ZM({message:`Call bundle with id: `+e+` not found.`}):new MM({message:`Transaction failed under call bundle id: `+e+`.`});return{id:t[0].transactionHash}}return m},async sendPreparedCalls(e){let{context:t,key:n,internal:r,signature:i}=e,{client:a}=r,{id:o}=await $B(a,{context:t,key:n,signature:i});return o},async signPersonalMessage(e){let{account:t,data:n,internal:r}=e,{client:a}=r,o=t.keys?.find(e=>e.role===`admin`&&e.privateKey);if(!o)throw Error(`cannot find admin key to sign with.`);let s=await FL(t,{key:o,payload:qB(n),webAuthn:i});return rV(a,{address:t.address,signature:s})},async signTypedData(e){let{account:t,internal:n}=e,{client:r}=n,a=t.keys?.find(e=>e.role===`admin`&&e.privateKey);if(!a)throw Error(`cannot find admin key to sign with.`);let o=uf(e.data),s=o.domain?.name===`Orchestrator`,c=await FL(t,{key:a,payload:lI(o),replaySafe:!s,webAuthn:i});return s?c:rV(r,{address:t.address,signature:c})},async upgradeAccount(e){let{account:t,context:n,internal:r,signatures:i}=e,{client:a}=r;return await tV(a,{context:n,signatures:i}),o&&await eV(a,{email:o,walletAddress:t.address}),{account:t}},async verifyEmail(e){let{account:t,chainId:n,email:r,token:a,internal:o,walletAddress:s}=e,{client:c}=o,l=t.keys?.find(e=>e.role===`admin`&&e.privateKey);if(!l)throw Error(`cannot find admin key to sign with.`);let u=await FL(t,{key:l,payload:Hh(Uf(`${r}${a}`)),webAuthn:i});return await nV(c,{chainId:n,email:r,signature:u,token:a,walletAddress:s})}},config:e,name:`rpc`})}op();function lV(e={}){let{fallback:t=cV(),host:n=bN.prod,renderer:r=SN(),theme:i,themeController:a}=e,o=new Set,s=CB();function c(e){return nN({async request(t){let n=s.prepare(t);return e.setState(e=>{let t=e.accounts[0],r=t?.keys?.find(e=>e.role===`admin`&&e.type===`webauthn-p256`);return{...e,requestQueue:[...e.requestQueue,{account:t?{address:t.address,key:r?{credentialId:r?.credentialId,publicKey:r.publicKey}:void 0}:void 0,request:n,status:`pending`}]}}),new Promise((t,r)=>{let i=a=>{let s=a.find(e=>e.request.id===n.id);if(!s&&a.length===0){o.delete(i),r(new HM);return}s&&(s.status!==`success`&&s.status!==`error`||(o.delete(i),s.status===`success`?t(s.result):r(rN(s.error)),e.setState(e=>({...e,requestQueue:e.requestQueue.filter(e=>e.request.id!==n.id)}))))};o.add(i)})}},{schema:TB()})}return xB({actions:{async addFunds(e){let{internal:t}=e,{request:n,store:r}=t;if(n.method!==`wallet_addFunds`)throw Error(`Cannot add funds for method: `+n.method);return await c(r).request(n)},async createAccount(e){let{internal:t}=e,{client:n,config:r,request:i,store:a}=t,{storage:o}=r,s=c(a);return{account:await(async()=>{if(i.method===`wallet_connect`){let[{capabilities:e,chainIds:t}]=i._decoded.params??[{}],a=dV(e?.signInWithEthereum?.authUrl??r.authUrl,{storage:o}),c=i.params?.[0]?.capabilities?.signInWithEthereum,l=await OB(e?.grantPermissions,{chainId:n.chain.id}),u=l?pP(EB,DB(l)):void 0,{accounts:d}=await s.request({...i,params:[{capabilities:{...i.params?.[0]?.capabilities,grantPermissions:u,signInWithEthereum:a||c?{...c,authUrl:a}:void 0},chainIds:t?.map(e=>I(e))}]}),[f]=d;if(!f)throw Error(`no account found.`);let p=f.capabilities?.admins?.map(e=>vL(e,{chainId:n.chain.id})).filter(Boolean),m=f.capabilities?.permissions?.map(e=>{try{let t=yz(mP(_z,e));return t.id===l?.id?{...t,...l,permissions:t.permissions}:t}catch{return}}).filter(Boolean),h=await(async()=>{if(!f.capabilities?.signInWithEthereum)return;let{message:e,signature:t}=f.capabilities.signInWithEthereum;if(!a)return{message:e,signature:t};let{token:n}=await HB({address:f.address,authUrl:a,message:e,publicKey:f.capabilities?.admins?.[0]?.publicKey,signature:t});return{message:e,signature:t,token:n}})();return{...ML({address:f.address,keys:[...p??[],...m??[]]}),signInWithEthereum:h}}throw Error(`Account creation not supported on method: ${i.method}`)})()}},async disconnect(e){let{internal:t}=e,{config:n}=t,{storage:r}=n,i=await r.getItem(`porto.authUrl`)||void 0,a=dV(n.authUrl??i,{storage:r});a&&await fetch(a.logout,{credentials:`include`,method:`POST`}).catch(()=>{})},async getAccountVersion(e){let{internal:n}=e,{store:i,request:a}=n;if(a.method!==`wallet_getAccountVersion`)throw Error(`Cannot get version for method: `+a.method);return r.supportsHeadless?await c(i).request(a):t.actions.getAccountVersion(e)},async getAssets(e){let{internal:n}=e,{store:i,request:a}=n;if(a.method!==`wallet_getAssets`)throw Error(`Cannot get assets for method: `+a.method);if(!r.supportsHeadless)return t.actions.getAssets(e);let o=await c(i).request(a);return mP(rB.Response,o)},async getCallsStatus(e){let{internal:n}=e,{store:i,request:a}=n;if(a.method!==`wallet_getCallsStatus`)throw Error(`Cannot get status for method: `+a.method);return r.supportsHeadless?await c(i).request(a):t.actions.getCallsStatus(e)},async getCapabilities(e){let{internal:n}=e,{store:i,request:a}=n;if(a.method!==`wallet_getCapabilities`)throw Error(`Cannot get capabilities for method: `+a.method);return r.supportsHeadless?await c(i).request(a):t.actions.getCapabilities(e)},async getKeys(e){let{account:n,chainIds:i,internal:a}=e,{store:o}=a,s=await(async()=>{if(!r.supportsHeadless)return t.actions.getKeys(e);let a=await c(o).request({method:`wallet_getKeys`,params:[pP(oB.Parameters,{address:n.address,chainIds:i})]});return mP(oB.Response,a)})();return mN([...s,...n.keys??[]],e=>e.publicKey)},async grantAdmin(e){let{internal:t}=e,{request:n,store:r}=t;if(n.method!==`wallet_grantAdmin`)throw Error(`Cannot authorize admin for method: `+n.method);let[i]=n._decoded.params,a=vL(i.key);if(!a)throw Error(`no key found.`);let o=await uV(t,e);return await c(r).request({method:`wallet_grantAdmin`,params:[{...n.params?.[0],capabilities:{...n.params?.[0]?.capabilities,feeToken:o}}]}),{key:a}},async grantPermissions(e){let{internal:t}=e,{client:n,request:r,store:i}=t;if(r.method!==`wallet_grantPermissions`)throw Error(`Cannot grant permissions for method: `+r.method);let[{address:a,...o}]=r._decoded.params,s=await OB(o,{chainId:n.chain.id});if(!s)throw Error(`no key found.`);let l=pP(EB,DB(s));return await c(i).request({method:`wallet_grantPermissions`,params:[l]}),{key:s}},async loadAccounts(e){let{internal:t}=e,{client:n,config:r,store:i}=t,{storage:a}=r,o=c(i),s=t.request;if(s.method!==`wallet_connect`&&s.method!==`eth_requestAccounts`)throw Error(`Cannot load accounts for method: `+s.method);return{accounts:await(async()=>{let[e]=s._decoded.params??[],{capabilities:t}=e??{},i=dV(t?.signInWithEthereum?.authUrl??r.authUrl,{storage:a}),c=s.params?.[0]?.capabilities?.signInWithEthereum,l=await OB(t?.grantPermissions,{chainId:n.chain.id}),u=l?pP(EB,DB(l)):void 0,{accounts:d}=await o.request({method:`wallet_connect`,params:[{...s.params?.[0],capabilities:{...s.params?.[0]?.capabilities,grantPermissions:u,signInWithEthereum:i||c?{...c,authUrl:i}:void 0}}]});return Promise.all(d.map(async e=>{let t=e.capabilities?.admins?.map(e=>vL(e)).filter(Boolean),n=e.capabilities?.permissions?.map(e=>{try{let t=yz(mP(_z,e));return t.id===l?.id?{...t,...l,permissions:t.permissions}:t}catch{return}}).filter(Boolean),r=await(async()=>{if(!e.capabilities?.signInWithEthereum)return;let{message:t,signature:n}=e.capabilities.signInWithEthereum;if(!i)return{message:t,signature:n};let{token:r}=await HB({address:e.address,authUrl:i,message:t,publicKey:e.capabilities?.admins?.[0]?.publicKey,signature:n});return{message:t,signature:n,token:r}})();return{...ML({address:e.address,keys:[...t??[],...n??[]]}),signInWithEthereum:r}}))})()}},async prepareCalls(e){let{account:n,internal:i}=e,{store:a,request:o}=i;if(o.method!==`wallet_prepareCalls`)throw Error(`Cannot prepare calls for method: `+o.method);if(!r.supportsHeadless)return t.actions.prepareCalls(e);let s=await uV(i,e),l=c(a),u=mP(sB.Response,await l.request({...o,params:[{...o.params?.[0],capabilities:{...o.params?.[0]?.capabilities,feeToken:s}}]}));return{account:n,chainId:Number(u.chainId),context:u.context,digest:u.digest,key:u.key,typedData:u.typedData}},async prepareUpgradeAccount(e){let{internal:n}=e,{client:i,store:a,request:o}=n;if(o.method!==`wallet_prepareUpgradeAccount`)throw Error(`Cannot prepare upgrade for method: `+o.method);if(!r.supportsHeadless)return t.actions.prepareUpgradeAccount(e);let[{capabilities:s}]=o._decoded.params??[{}],l=await OB(s?.grantPermissions,{chainId:i.chain.id}),u=l?pP(EB,DB(l)):void 0,{context:d,digests:f}=await c(a).request({...o,params:[{...o.params?.[0],capabilities:{...o.params?.[0]?.capabilities,grantPermissions:u}}]}),p=d.account.keys?.map(e=>e.id===l?.id?{...e,...l}:e);return{context:{...d,account:{...d.account,keys:p}},digests:f}},async revokeAdmin(e){let{account:t,id:n,internal:r}=e,{store:i,request:a}=r;if(a.method!==`wallet_revokeAdmin`)throw Error(`Cannot revoke admin for method: `+a.method);let o=t.keys?.find(e=>e.id===n);if(!o)return;if(o.type===`webauthn-p256`&&t.keys?.filter(e=>e.type===`webauthn-p256`).length===1)throw Error(`revoke the only WebAuthn key left.`);let s=await uV(r,e);return await c(i).request({...a,params:[{...a.params?.[0],capabilities:{...a.params?.[0]?.capabilities,feeToken:s}}]})},async revokePermissions(e){let{account:t,id:n,internal:r}=e,{store:i,request:a}=r;if(a.method!==`wallet_revokePermissions`)throw Error(`Cannot revoke permissions for method: `+a.method);let o=t.keys?.find(e=>e.id===n);if(o){if(o.role===`admin`)throw Error(`cannot revoke permissions.`);return await c(i).request(a)}},async sendCalls(e){let{account:n,asTxHash:i,calls:a,chainId:o,internal:s,merchantUrl:l,requiredFunds:u}=e,{client:d,store:f,request:p}=s,m=c(f),h=await uV(s,e),g=await SB({account:n,calls:a,permissionsId:e.permissionsId});if(g&&g.role===`session`){if(!r.supportsHeadless)return t.actions.sendCalls(e);try{let e=await m.request(pP(sB.Request,{method:`wallet_prepareCalls`,params:[{calls:a,capabilities:{...p._decoded.method===`wallet_sendCalls`?p._decoded.params?.[0]?.capabilities:void 0,feeToken:h,merchantUrl:l,requiredFunds:u},chainId:o,from:n.address,key:g}]})),t=e.capabilities?.quote?.quotes??[];if(t.some((e,n)=>n===t.length-1&&t.length>1?!1:Yf(e.feeTokenDeficit)>0n))throw Error(`insufficient funds`);let r=await EL(g,{address:null,payload:e.digest,wrap:!1}),s=(await m.request({method:`wallet_sendPreparedCalls`,params:[{...e,signature:r}]}))[0];if(!s)throw Error(`id not found`);if(i){let{id:e,receipts:t,status:n}=await Wm(d,{id:s.id,pollingInterval:500});if(!t?.[0])throw n===`success`?new ZM({message:`Call bundle with id: `+e+` not found.`}):new MM({message:`Transaction failed under call bundle id: `+e+`.`});return{id:t[0].transactionHash}}return s}catch{}}if(p.method===`eth_sendTransaction`)return{id:await m.request({...p,params:[{...p.params?.[0],capabilities:{feeToken:h,merchantUrl:l},...o?{chainId:I(o)}:{}}]})};if(p.method===`wallet_sendCalls`)return await m.request({method:`wallet_sendCalls`,params:[{...p.params?.[0],capabilities:{...p.params?.[0]?.capabilities,feeToken:h,merchantUrl:l},...o?{chainId:I(o)}:{}}]});throw Error(`Cannot execute for method: `+p.method)},async sendPreparedCalls(e){let{internal:n}=e,{store:i,request:a}=n;if(a.method!==`wallet_sendPreparedCalls`)throw Error(`Cannot send prepared calls for method: `+a.method);if(!r.supportsHeadless)return t.actions.sendPreparedCalls(e);let o=(await c(i).request(a))[0]?.id;if(!o)throw Error(`id not found`);return o},async signPersonalMessage(e){let{internal:t}=e,{store:n,request:r}=t;if(r.method!==`personal_sign`)throw Error(`Cannot sign personal message for method: `+r.method);return await c(n).request(r)},async signTypedData(e){let{internal:t}=e,{store:n,request:r}=t;if(r.method!==`eth_signTypedData_v4`)throw Error(`Cannot sign typed data for method: `+r.method);return await c(n).request(r)},async switchChain(e){let{internal:t}=e,{store:n,request:i}=t;if(i.method!==`wallet_switchEthereumChain`)throw Error(`Cannot switch chain for method: `+i.method);if(r.supportsHeadless)return await c(n).request(i)},async upgradeAccount(e){let{account:t,internal:n}=e,{store:r,request:i}=n;if(i.method!==`wallet_upgradeAccount`)throw Error(`Cannot upgrade account for method: `+i.method);return await c(r).request(i),{account:t}},async verifyEmail(e){let{internal:t}=e,{request:n,store:r}=t;if(n.method!==`account_verifyEmail`)throw Error(`Cannot verify email for method: `+n.method);return await c(r).request(n)}},config:e,name:`dialog`,setup(e){let{internal:t}=e,{store:s}=t,c=r.setup({host:n,internal:t,theme:i,themeController:a}),l=s.subscribe(e=>e.requestQueue,e=>{for(let t of o)t(e);let t=e.map(e=>e.status===`pending`?e:void 0).filter(Boolean);c.syncRequests(t).catch(()=>{}),t.length===0&&c.close()});return()=>{l(),c.destroy()}}})}async function uV(e,t){let{config:{feeToken:n}}=e,{feeToken:r}=t??{};return r??n}function dV(e,{storage:t}){if(!e)return;let n=WB(e,typeof window<`u`?window.location.origin:void 0);return n&&t.setItem(`porto.authUrl`,n),n}var fV=new Map,pV=e=>{let t=fV.get(e);return t?Object.fromEntries(Object.entries(t.stores).map(([e,t])=>[e,t.getState()])):{}},mV=(e,t,n)=>{if(e===void 0)return{type:`untracked`,connection:t.connect(n)};let r=fV.get(n.name);if(r)return{type:`tracked`,store:e,...r};let i={connection:t.connect(n),stores:{}};return fV.set(n.name,i),{type:`tracked`,store:e,...i}},hV=(e,t)=>{if(t===void 0)return;let n=fV.get(e);n&&(delete n.stores[t],Object.keys(n.stores).length===0&&fV.delete(e))},gV=e=>{if(!e)return;let t=e.split(`\n`),n=t.findIndex(e=>e.includes(`api.setState`));if(n<0)return;let r=t[n+1]?.trim()||``;return/.+ (.+) .+/.exec(r)?.[1]},_V=(e,t={})=>(n,r,i)=>{let{enabled:a,anonymousActionType:o,store:s,...c}=t,l;try{l=(a??!1)&&window.__REDUX_DEVTOOLS_EXTENSION__}catch{}if(!l)return e(n,r,i);let{connection:u,...d}=mV(s,l,c),f=!0;i.setState=((e,t,a)=>{let l=n(e,t);if(!f)return l;let d=a===void 0?{type:o||gV(Error().stack)||`anonymous`}:typeof a==`string`?{type:a}:a;return s===void 0?(u?.send(d,r()),l):(u?.send({...d,type:`${s}/${d.type}`},{...pV(c.name),[s]:i.getState()}),l)}),i.devtools={cleanup:()=>{u&&typeof u.unsubscribe==`function`&&u.unsubscribe(),hV(c.name,s)}};let p=(...e)=>{let t=f;f=!1,n(...e),f=t},m=e(i.setState,r,i);if(d.type===`untracked`?u?.init(m):(d.stores[d.store]=i,u?.init(Object.fromEntries(Object.entries(d.stores).map(([e,t])=>[e,e===d.store?m:t.getState()])))),i.dispatchFromDevtools&&typeof i.dispatch==`function`){let e=i.dispatch;i.dispatch=(...t)=>{e(...t)}}return u.subscribe(e=>{switch(e.type){case`ACTION`:if(typeof e.payload!=`string`){console.error(`[zustand devtools middleware] Unsupported action format`);return}return vV(e.payload,e=>{if(e.type===`__setState`){if(s===void 0){p(e.state);return}Object.keys(e.state).length!==1&&console.error(`\n                    [zustand devtools middleware] Unsupported __setState action format.\n                    When using 'store' option in devtools(), the 'state' should have only one key, which is a value of 'store' that was passed in devtools(),\n                    and value of this only key should be a state object. Example: { \"type\": \"__setState\", \"state\": { \"abc123Store\": { \"foo\": \"bar\" } } }\n                    `);let t=e.state[s];if(t==null)return;JSON.stringify(i.getState())!==JSON.stringify(t)&&p(t);return}i.dispatchFromDevtools&&typeof i.dispatch==`function`&&i.dispatch(e)});case`DISPATCH`:switch(e.payload.type){case`RESET`:return p(m),s===void 0?u?.init(i.getState()):u?.init(pV(c.name));case`COMMIT`:if(s===void 0){u?.init(i.getState());return}return u?.init(pV(c.name));case`ROLLBACK`:return vV(e.state,e=>{if(s===void 0){p(e),u?.init(i.getState());return}p(e[s]),u?.init(pV(c.name))});case`JUMP_TO_STATE`:case`JUMP_TO_ACTION`:return vV(e.state,e=>{if(s===void 0){p(e);return}JSON.stringify(i.getState())!==JSON.stringify(e[s])&&p(e[s])});case`IMPORT_STATE`:{let{nextLiftedState:t}=e.payload,n=t.computedStates.slice(-1)[0]?.state;if(!n)return;p(s===void 0?n:n[s]),u?.send(null,t);return}case`PAUSE_RECORDING`:return f=!f}return}}),m},vV=(e,t)=>{let n;try{n=JSON.parse(e)}catch(e){console.error(`[zustand devtools middleware] Could not parse the received json`,e)}n!==void 0&&t(n)},yV=e=>(t,n,r)=>{let i=r.subscribe;return r.subscribe=((e,t,n)=>{let a=e;if(t){let i=n?.equalityFn||Object.is,o=e(r.getState());a=n=>{let r=e(n);if(!i(o,r)){let e=o;t(o=r,e)}},n?.fireImmediately&&t(o,o)}return i(a)}),e(t,n,r)};function bV(e,t){let n;try{n=e()}catch{return}return{getItem:e=>{let r=e=>e===null?null:JSON.parse(e,t?.reviver),i=n.getItem(e)??null;return i instanceof Promise?i.then(r):r(i)},setItem:(e,r)=>n.setItem(e,JSON.stringify(r,t?.replacer)),removeItem:e=>n.removeItem(e)}}var xV=e=>t=>{try{let n=e(t);return n instanceof Promise?n:{then(e){return xV(e)(n)},catch(e){return this}}}catch(e){return{then(e){return this},catch(t){return xV(t)(e)}}}},SV=(e,t)=>(n,r,i)=>{let a={storage:bV(()=>localStorage),partialize:e=>e,version:0,merge:(e,t)=>({...t,...e}),...t},o=!1,s=new Set,c=new Set,l=a.storage;if(!l)return e((...e)=>{console.warn(`[zustand persist middleware] Unable to update item '${a.name}', the given storage is currently unavailable.`),n(...e)},r,i);let u=()=>{let e=a.partialize({...r()});return l.setItem(a.name,{state:e,version:a.version})},d=i.setState;i.setState=(e,t)=>(d(e,t),u());let f=e((...e)=>(n(...e),u()),r,i);i.getInitialState=()=>f;let p,m=()=>{if(!l)return;o=!1,s.forEach(e=>e(r()??f));let e=a.onRehydrateStorage?.call(a,r()??f)||void 0;return xV(l.getItem.bind(l))(a.name).then(e=>{if(e)if(typeof e.version==`number`&&e.version!==a.version){if(a.migrate){let t=a.migrate(e.state,e.version);return t instanceof Promise?t.then(e=>[!0,e]):[!0,t]}console.error(`State loaded from storage couldn't be migrated since no migrate function was provided`)}else return[!1,e.state];return[!1,void 0]}).then(e=>{let[t,i]=e;if(p=a.merge(i,r()??f),n(p,!0),t)return u()}).then(()=>{e?.(p,void 0),p=r(),o=!0,c.forEach(e=>e(p))}).catch(t=>{e?.(void 0,t)})};return i.persist={setOptions:e=>{a={...a,...e},e.storage&&(l=e.storage)},clearStorage:()=>{l?.removeItem(a.name)},getOptions:()=>a,rehydrate:()=>m(),hasHydrated:()=>o,onHydrate:e=>(s.add(e),()=>{s.delete(e)}),onFinishHydration:e=>(c.add(e),()=>{c.delete(e)})},a.skipHydration||m(),p||f},CV=e=>{let t,n=new Set,r=(e,r)=>{let i=typeof e==`function`?e(t):e;if(!Object.is(i,t)){let e=t;t=r??(typeof i!=`object`||!i)?i:Object.assign({},t,i),n.forEach(n=>n(t,e))}},i=()=>t,a={setState:r,getState:i,getInitialState:()=>o,subscribe:e=>(n.add(e),()=>n.delete(e))},o=t=e(r,i,a);return a},wV=(e=>e?CV(e):CV);function TV(e){return new Promise((t,n)=>{e.oncomplete=e.onsuccess=()=>t(e.result),e.onabort=e.onerror=()=>n(e.error)})}function EV(e,t){let n,r=()=>{if(n)return n;let r=indexedDB.open(e);return r.onupgradeneeded=()=>r.result.createObjectStore(t),n=TV(r),n.then(e=>{e.onclose=()=>n=void 0},()=>{}),n};return(e,n)=>r().then(r=>n(r.transaction(t,e).objectStore(t)))}var DV;function OV(){return DV||=EV(`keyval-store`,`keyval`),DV}function kV(e,t=OV()){return t(`readonly`,t=>TV(t.get(e)))}function AV(e,t,n=OV()){return n(`readwrite`,n=>(n.put(t,e),TV(n.transaction)))}function jV(e,t=OV()){return t(`readwrite`,t=>(t.delete(e),TV(t.transaction)))}function MV(e){return e}function NV(){let e=typeof indexedDB<`u`?EV(`porto`,`store`):void 0;return MV({async getItem(t){let n=await kV(t,e);return n===null?null:n},async removeItem(t){await jV(t,e)},async setItem(t,n){await AV(t,pN(n),e)},sizeLimit:1024*1024*50})}function PV(){let e=new Map;return MV({getItem(t){return e.get(t)??null},removeItem(t){e.delete(t)},setItem(t,n){e.set(t,n)},sizeLimit:1/0})}var FV=typeof window<`u`&&typeof document<`u`;const IV={announceProvider:!0,chains:CM,mode:FV?lV({host:bN.prod}):cV(),relay:zv(rz.prod.http),storage:FV&&typeof indexedDB<`u`?NV():PV(),storageKey:`porto.store`};function LV(e={}){let t=e.chains??IV.chains,n=Object.fromEntries(t.map(t=>[t.id,e.transports?.[t.id]??zv()])),r={announceProvider:e.announceProvider??IV.announceProvider,authUrl:e.authUrl,chains:t,feeToken:e.feeToken,merchantUrl:e.merchantUrl,mode:e.mode??IV.mode,relay:e.relay??IV.relay,storage:e.storage??IV.storage,storageKey:e.storageKey??IV.storageKey,transports:n},i=wV(_V(yV(SV(e=>({accounts:[],chainIds:r.chains.map(e=>e.id),feeToken:r.feeToken,requestQueue:[]}),{merge(e,t){let n=e,i=r.chains.find(e=>e.id===n.chainIds[0])?.id??r.chains[0].id,a=[i,...r.chains.map(e=>e.id).filter(e=>e!==i)];return{...t,...n,chainIds:a}},name:r.storageKey,partialize:e=>({accounts:e.accounts.map(e=>pN(e)),chainIds:e.chainIds}),storage:r.storage,version:5})))),a=r.mode,o={config:r,getMode(){return a},id:hN(),setMode(e){return c?.(),a=e,c=e.setup({internal:o}),c},store:i},s=gB(o),c=a===null?()=>{}:a.setup({internal:o});return{_internal:o,config:r,destroy(){c(),s._internal.destroy()},provider:s}}const RV=Object.freeze(Object.values(xM)),zV=e=>RV.find(t=>t.id===e);var BV=e=>{if(typeof e==`number`)return Number.isFinite(e)?e:void 0;if(typeof e!=`string`)return;let t=e.trim();if(/^0x[0-9a-fA-F]+$/.test(t)){let e=Number.parseInt(t,16);return Number.isNaN(e)?void 0:e}if(/^\\d+$/.test(t)){let e=Number.parseInt(t,10);return Number.isNaN(e)?void 0:e}};const VV=(e,t,n)=>{let r=BV(e);t(r),n(r==null?void 0:zV(r))},HV=async(e,t=`GET`,n)=>{let r={\"Content-Type\":`application/json`},i=typeof window<`u`?window.__SESSION_TOKEN__:void 0;i&&(r[`X-Session-Token`]=i);let a=await fetch(`http://127.0.0.1:9545${e}`,{method:t,headers:r,body:n===void 0?void 0:JSON.stringify(n)});if(!a.ok)throw Error(`API request failed: ${a.status} ${a.statusText}`);try{return await a.json()}catch{throw Error(`Invalid JSON response`)}},UV=e=>JSON.stringify(e,(e,t)=>typeof t==`bigint`?t.toString():t,2),WV=e=>{if(e==null)return UV(e);if(typeof e==`object`&&e&&`message`in e&&typeof e.message==`string`){let t=e;try{let n=JSON.parse(t.message);return UV({...e,message:n})}catch{return UV(e)}}return UV(e)},GV=e=>!!e&&e.status===`ok`;var KV=s((e=>{var t=Symbol.for(`react.transitional.element`),n=Symbol.for(`react.fragment`);function r(e,n,r){var i=null;if(r!==void 0&&(i=``+r),n.key!==void 0&&(i=``+n.key),`key`in n)for(var a in r={},n)a!==`key`&&(r[a]=n[a]);else r=n;return n=r.ref,{$$typeof:t,type:e,key:i,ref:n===void 0?null:n,props:r}}e.Fragment=n,e.jsx=r,e.jsxs=r})),$=u(s(((e,t)=>{t.exports=KV()}))());function qV(){(0,y.useEffect)(()=>{window.__PORTO__||(window.__PORTO__=LV())},[]);let[e,t]=(0,y.useState)([]),[n,r]=(0,y.useState)(!1),[i,a]=(0,y.useState)(null),[o,s]=(0,y.useState)(null),[c,l]=(0,y.useState)(null),u=e.find(e=>e.info.uuid===c)??null,[d,f]=(0,y.useState)(),[p,m]=(0,y.useState)(),[h,g]=(0,y.useState)(),[_,v]=(0,y.useState)(null),[b,x]=(0,y.useState)(null),[S,C]=(0,y.useState)(null),w=(0,y.useRef)(null),ee=(0,y.useRef)(null),te=(0,y.useRef)(null),ne=async()=>{if(!u||n)return;let e=await u.provider.request({method:`eth_requestAccounts`});f(e?.[0]??void 0);try{let e=await u.provider.request({method:`eth_chainId`});VV(e,m,g)}catch{m(void 0),g(void 0)}},re=async()=>{if(!(!d||p==null)){try{await HV(`/api/connection`,`POST`,[d,p])}catch{return}r(!0)}},ie=async()=>{if(!u||!o)return;let{id:e,signType:t,request:n}=o,r=n.address,i=n.message;try{let n;switch(t){case`PersonalSign`:n=await u.provider.request({method:`personal_sign`,params:[i,r]});break;case`SignTypedDataV4`:n=await u.provider.request({method:`eth_signTypedData_v4`,params:[r,i]});break;default:throw Error(`Unsupported signType: ${t}`)}await HV(`/api/signing/response`,`POST`,{id:e,signature:n,error:null}),C(n),s(null)}catch(t){let n=typeof t==`object`&&t&&`message`in t&&typeof t.message==`string`?t.message:String(t);try{await HV(`/api/signing/response`,`POST`,{id:e,signature:null,error:n})}catch{}C(null),s(null)}},ae=async()=>{if(!u||!i?.request)return;let e=Mv({transport:Pv(u.provider),chain:h});try{let{from:t,input:n,to:r,...a}=i.request,o=await e.sendTransaction({...a,account:t||(await e.getAddresses())[0],...n?{data:n}:{},...r?{to:r}:{},chain:h});x(o),await HV(`/api/transaction/response`,`POST`,{id:i.id,hash:o,error:null});let s=await uv(e,{hash:o});v(s)}catch(e){let t=typeof e==`object`&&e&&`message`in e&&typeof e.message==`string`?e.message:String(e);console.error(`send failed:`,t);try{await HV(`/api/transaction/response`,`POST`,{id:i.id,hash:null,error:t})}catch{}}},oe=(0,y.useCallback)(()=>{w.current&&=(window.clearInterval(w.current),null),ee.current&&=(window.clearInterval(ee.current),null),a(null),s(null),x(null),v(null),f(void 0),m(void 0),g(void 0),r(!1),HV(`/api/connection`,`POST`,null)},[]);return(0,y.useEffect)(()=>{te.current&&c&&te.current!==c&&oe(),te.current=c},[c,oe]),(0,y.useEffect)(()=>{e.length===1&&!u&&l(e[0].info.uuid)},[e,u]),(0,y.useEffect)(()=>{let e=e=>{let{info:n,provider:r}=e.detail;t(e=>e.some(e=>e.info.uuid===n.uuid)?e:[...e,{info:n,provider:r}])};return window.addEventListener(`eip6963:announceProvider`,e),window.dispatchEvent(new Event(`eip6963:requestProvider`)),()=>window.removeEventListener(`eip6963:announceProvider`,e)},[]),(0,y.useEffect)(()=>{if(!u)return;let e=e=>{n||f(e[0]??void 0)},t=e=>{n||VV(e,m,g)};return u.provider.on?.(`accountsChanged`,e),u.provider.on?.(`chainChanged`,t),()=>{u.provider.removeListener?.(`accountsChanged`,e),u.provider.removeListener?.(`chainChanged`,t)}},[u,n]),(0,y.useEffect)(()=>{if(!n||i||o)return;let e=!0,t=window.setInterval(async()=>{if(e)try{let n=await HV(`/api/transaction/request`);GV(n)&&(window.clearInterval(t),e&&a(n.data))}catch{}},1e3);return w.current=t,()=>{e=!1,window.clearInterval(t),w.current===t&&(w.current=null)}},[n,i,o]),(0,y.useEffect)(()=>{if(!n||o||i)return;let e=!0,t=window.setInterval(async()=>{if(e)try{let n=await HV(`/api/signing/request`);GV(n)&&(window.clearInterval(t),e&&s(n.data))}catch{}},1e3);return ee.current=t,()=>{e=!1,window.clearInterval(t),ee.current===t&&(ee.current=null)}},[n,o,i]),(0,$.jsx)(`div`,{className:`wrapper`,children:(0,$.jsxs)(`div`,{className:`container`,children:[(0,$.jsx)(`div`,{className:`notice`,children:`Browser wallet is still in early development. Use with caution!`}),(0,$.jsx)(`img`,{className:`banner`,src:`banner.png`,alt:`Foundry Browser Wallet`}),e.length>1&&(0,$.jsx)(`div`,{className:`wallet-selector`,children:(0,$.jsx)(`label`,{children:(0,$.jsxs)(`select`,{value:c??``,onChange:e=>l(e.target.value||null),disabled:n,children:[(0,$.jsx)(`option`,{value:``,disabled:!0,children:`Select wallet…`}),e.map(({info:e})=>(0,$.jsxs)(`option`,{value:e.uuid,children:[e.name,` (`,e.rdns,`)`]},e.uuid))]})})}),e.length===0&&(0,$.jsx)(`p`,{children:`No wallets found.`}),u&&!d&&(0,$.jsx)(`button`,{type:`button`,className:`wallet-connect`,onClick:ne,disabled:n,children:`Connect Wallet`}),u&&d&&!n&&(0,$.jsx)(`button`,{type:`button`,className:`wallet-confirm`,onClick:re,disabled:!d||p==null,children:`Confirm Connection`}),u&&d&&(0,$.jsxs)($.Fragment,{children:[(0,$.jsx)(`div`,{className:`section-title`,children:`Connected`}),(0,$.jsx)(`pre`,{className:`box`,children:`\\\naccount: ${d}\nchain:   ${h?`${h.name} (${p})`:p??`unknown`}\nrpc:     ${h?.rpcUrls?.default?.http?.[0]??h?.rpcUrls?.public?.http?.[0]??`unknown`}`})]}),u&&d&&n&&!i&&!o&&!b&&!S&&(0,$.jsxs)($.Fragment,{children:[(0,$.jsx)(`div`,{className:`section-title`,children:`Transaction To Sign`}),(0,$.jsx)(`div`,{className:`box`,children:(0,$.jsx)(`pre`,{children:`No pending transaction or signing request`})})]}),u&&d&&n&&!b&&i&&(0,$.jsxs)($.Fragment,{children:[(0,$.jsx)(`div`,{className:`section-title`,children:`Transaction to Sign & Send`}),(0,$.jsx)(`div`,{className:`box`,children:(0,$.jsx)(`pre`,{children:UV(i.request)})}),(0,$.jsx)(`button`,{type:`button`,className:`wallet-send`,onClick:ae,children:`Sign & Send`})]}),u&&d&&n&&!i&&o&&(0,$.jsxs)($.Fragment,{children:[(0,$.jsx)(`div`,{className:`section-title`,children:`Message / Data to Sign`}),(0,$.jsx)(`div`,{className:`box`,children:(0,$.jsx)(`pre`,{children:WV(o.request)})}),(0,$.jsx)(`button`,{type:`button`,className:`wallet-send`,onClick:ie,children:`Sign`})]}),u&&d&&b&&(0,$.jsxs)($.Fragment,{children:[(0,$.jsx)(`div`,{className:`section-title`,children:`Transaction Hash`}),(0,$.jsx)(`pre`,{className:`box`,children:b}),(0,$.jsxs)(`div`,{children:[(0,$.jsx)(`div`,{className:`section-title`,children:`Receipt`}),(0,$.jsx)(`pre`,{className:`box`,children:_?UV(_):`Waiting for receipt...`})]})]}),u&&d&&n&&S&&(0,$.jsxs)($.Fragment,{children:[(0,$.jsx)(`div`,{className:`section-title`,children:`Signature Result`}),(0,$.jsx)(`pre`,{className:`box`,children:S})]})]})})}var JV=document.getElementById(`root`);if(JV)(0,v.createRoot)(JV).render((0,$.jsx)(y.StrictMode,{children:(0,$.jsx)(qV,{})}));else throw Error(`Root element with id \"root\" not found`);"
  },
  {
    "path": "crates/wallets/src/wallet_browser/app/assets/styles.css",
    "content": "*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;-webkit-tap-highlight-color:transparent;font-family:ui-sans-serif,system-ui,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;line-height:1.5}body{-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;color:inherit;letter-spacing:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;color:inherit;letter-spacing:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none}html,body,#root{color:#f8f8f8;background-color:#13151b;width:100%;height:100%;font-family:system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif}button{color:#f8f8f8;cursor:pointer;background-color:#3a3f51;border:1px solid #e1e4e8;border-radius:4px;padding:8px 12px}button:hover{background-color:#50566e}select{color:#f8f8f8;cursor:pointer;background-color:#1e2026;border:1px solid #e1e4e8;border-radius:8px;margin-bottom:16px;padding:8px}option{color:#f8f8f8;background-color:#1e2026}pre{white-space:pre-wrap;word-break:break-all;overflow-wrap:anywhere}.wrapper{flex-direction:column;justify-content:center;align-items:center;min-height:100vh;padding:24px;display:flex}.container{background-color:#3b3b3b;border-radius:8px;flex-direction:column;align-items:flex-start;max-width:600px;padding:16px;display:flex}.notice{color:#333;text-align:center;background-color:#fc0;border-radius:8px;width:100%;margin-bottom:16px;padding:8px;font-size:13px;font-weight:700}.banner{border-radius:8px;width:100%;height:auto}.wallet-selector,.wallet-connect,.wallet-send,.wallet-confirm{align-self:center;margin-top:16px}.title,.section-title{color:#f8f8f8}.title{margin-bottom:24px;font-size:36px}.section-title{margin-bottom:16px;font-size:24px}.box{border:1px solid #e1e4e8;border-radius:8px;margin-bottom:16px;padding:8px 12px;font-size:13px}\n/*$vite$:1*/"
  },
  {
    "path": "crates/wallets/src/wallet_browser/app/mod.rs",
    "content": "pub(crate) mod contents {\n    pub const INDEX_HTML: &str = include_str!(\"assets/index.html\");\n    pub const STYLES_CSS: &str = include_str!(\"assets/styles.css\");\n    pub const MAIN_JS: &str = include_str!(\"assets/main.js\");\n    pub const BANNER_PNG: &[u8] = include_bytes!(\"assets/banner.png\");\n    pub const LOGO_PNG: &[u8] = include_bytes!(\"assets/logo.png\");\n}\n"
  },
  {
    "path": "crates/wallets/src/wallet_browser/error.rs",
    "content": "use alloy_signer::Error as SignerError;\n\n#[derive(Debug, thiserror::Error)]\npub enum BrowserWalletError {\n    #[error(\"{operation} request timed out\")]\n    Timeout { operation: &'static str },\n\n    #[error(\"{operation} rejected: {reason}\")]\n    Rejected { operation: &'static str, reason: String },\n\n    #[error(\"Wallet not connected\")]\n    NotConnected,\n\n    #[error(\"Server error: {0}\")]\n    ServerError(String),\n}\n\nimpl From<BrowserWalletError> for SignerError {\n    fn from(err: BrowserWalletError) -> Self {\n        Self::other(err)\n    }\n}\n\nimpl From<SignerError> for BrowserWalletError {\n    fn from(err: SignerError) -> Self {\n        Self::ServerError(err.to_string())\n    }\n}\n"
  },
  {
    "path": "crates/wallets/src/wallet_browser/handlers.rs",
    "content": "use std::sync::Arc;\n\nuse alloy_network::Network;\nuse axum::{\n    Json,\n    extract::State,\n    http::{\n        HeaderMap, HeaderValue,\n        header::{CACHE_CONTROL, CONTENT_TYPE, EXPIRES, PRAGMA},\n    },\n    response::Html,\n};\n\nuse crate::wallet_browser::{\n    app::contents,\n    state::BrowserWalletState,\n    types::{\n        BrowserApiResponse, BrowserSignRequest, BrowserSignResponse, BrowserTransactionRequest,\n        BrowserTransactionResponse, Connection,\n    },\n};\n\n/// Serve index.html\npub(crate) async fn serve_index() -> impl axum::response::IntoResponse {\n    let mut headers = HeaderMap::new();\n    headers.insert(CONTENT_TYPE, HeaderValue::from_static(\"text/html; charset=utf-8\"));\n    headers.insert(\n        CACHE_CONTROL,\n        HeaderValue::from_static(\"no-store, no-cache, must-revalidate, max-age=0\"),\n    );\n    headers.insert(PRAGMA, HeaderValue::from_static(\"no-cache\"));\n    headers.insert(EXPIRES, HeaderValue::from_static(\"0\"));\n    (headers, Html(contents::INDEX_HTML))\n}\n\n/// Serve styles.css\npub(crate) async fn serve_css() -> impl axum::response::IntoResponse {\n    let mut headers = HeaderMap::new();\n    headers.insert(CONTENT_TYPE, HeaderValue::from_static(\"text/css; charset=utf-8\"));\n    headers.insert(\n        CACHE_CONTROL,\n        HeaderValue::from_static(\"no-store, no-cache, must-revalidate, max-age=0\"),\n    );\n    headers.insert(PRAGMA, HeaderValue::from_static(\"no-cache\"));\n    headers.insert(EXPIRES, HeaderValue::from_static(\"0\"));\n    (headers, contents::STYLES_CSS)\n}\n\n/// Serve main.js with injected session token.\npub(crate) async fn serve_js<N: Network>(\n    State(state): State<Arc<BrowserWalletState<N>>>,\n) -> impl axum::response::IntoResponse {\n    let token = state.session_token();\n    let js = format!(\"window.__SESSION_TOKEN__ = \\\"{}\\\";\\n{}\", token, contents::MAIN_JS);\n\n    let mut headers = HeaderMap::new();\n    headers.insert(CONTENT_TYPE, HeaderValue::from_static(\"application/javascript; charset=utf-8\"));\n    headers.insert(\n        CACHE_CONTROL,\n        HeaderValue::from_static(\"no-store, no-cache, must-revalidate, max-age=0\"),\n    );\n    headers.insert(PRAGMA, HeaderValue::from_static(\"no-cache\"));\n    headers.insert(EXPIRES, HeaderValue::from_static(\"0\"));\n    (headers, js)\n}\n\n/// Serve banner.png\npub(crate) async fn serve_banner_png() -> impl axum::response::IntoResponse {\n    let mut headers = HeaderMap::new();\n    headers.insert(CONTENT_TYPE, HeaderValue::from_static(\"image/png\"));\n    headers.insert(CACHE_CONTROL, HeaderValue::from_static(\"public, max-age=31536000, immutable\"));\n    (headers, contents::BANNER_PNG)\n}\n\n/// Serve logo.png\npub(crate) async fn serve_logo_png() -> impl axum::response::IntoResponse {\n    let mut headers = HeaderMap::new();\n    headers.insert(CONTENT_TYPE, HeaderValue::from_static(\"image/png\"));\n    headers.insert(CACHE_CONTROL, HeaderValue::from_static(\"public, max-age=31536000, immutable\"));\n    (headers, contents::LOGO_PNG)\n}\n\n/// Get the next pending transaction request.\n/// Route: GET /api/transaction/request\npub(crate) async fn get_next_transaction_request<N: Network>(\n    State(state): State<Arc<BrowserWalletState<N>>>,\n) -> Json<BrowserApiResponse<BrowserTransactionRequest<N>>> {\n    match state.read_next_transaction_request().await {\n        Some(tx) => Json(BrowserApiResponse::with_data(tx)),\n        None => Json(BrowserApiResponse::error(\"No pending transaction request\")),\n    }\n}\n\n/// Post a transaction response (signed or error).\n/// Route: POST /api/transaction/response\npub(crate) async fn post_transaction_response<N: Network>(\n    State(state): State<Arc<BrowserWalletState<N>>>,\n    Json(body): Json<BrowserTransactionResponse>,\n) -> Json<BrowserApiResponse> {\n    // Ensure that the transaction request exists.\n    if !state.has_transaction_request(&body.id).await {\n        return Json(BrowserApiResponse::error(\"Unknown transaction id\"));\n    }\n\n    // Ensure that exactly one of hash or error is provided.\n    match (&body.hash, &body.error) {\n        (None, None) => {\n            return Json(BrowserApiResponse::error(\"Either hash or error must be provided\"));\n        }\n        (Some(_), Some(_)) => {\n            return Json(BrowserApiResponse::error(\"Only one of hash or error can be provided\"));\n        }\n        _ => {}\n    }\n\n    // Validate transaction hash if provided.\n    if let Some(hash) = &body.hash {\n        // Check for all-zero hash\n        if hash.is_zero() {\n            return Json(BrowserApiResponse::error(\"Invalid (zero) transaction hash\"));\n        }\n\n        // Sanity check: ensure the hash is exactly 32 bytes\n        if hash.as_slice().len() != 32 {\n            return Json(BrowserApiResponse::error(\n                \"Malformed transaction hash (expected 32 bytes)\",\n            ));\n        }\n    }\n\n    state.add_transaction_response(body).await;\n\n    Json(BrowserApiResponse::ok())\n}\n\n/// Get the next pending signing request.\n/// Route: GET /api/signing/request\npub(crate) async fn get_next_signing_request<N: Network>(\n    State(state): State<Arc<BrowserWalletState<N>>>,\n) -> Json<BrowserApiResponse<BrowserSignRequest>> {\n    match state.read_next_signing_request().await {\n        Some(req) => Json(BrowserApiResponse::with_data(req)),\n        None => Json(BrowserApiResponse::error(\"No pending signing request\")),\n    }\n}\n\n/// Post a signing response (signature or error).\n/// Route: POST /api/signing/response\npub(crate) async fn post_signing_response<N: Network>(\n    State(state): State<Arc<BrowserWalletState<N>>>,\n    Json(body): Json<BrowserSignResponse>,\n) -> Json<BrowserApiResponse> {\n    // Ensure that the signing request exists.\n    if !state.has_signing_request(&body.id).await {\n        return Json(BrowserApiResponse::error(\"Unknown signing request id\"));\n    }\n\n    // Ensure that exactly one of signature or error is provided.\n    match (&body.signature, &body.error) {\n        (None, None) => {\n            return Json(BrowserApiResponse::error(\"Either signature or error must be provided\"));\n        }\n        (Some(_), Some(_)) => {\n            return Json(BrowserApiResponse::error(\n                \"Only one of signature or error can be provided\",\n            ));\n        }\n        _ => {}\n    }\n\n    state.add_signing_response(body).await;\n\n    Json(BrowserApiResponse::ok())\n}\n\n/// Get current connection information.\n/// Route: GET /api/connection\npub(crate) async fn get_connection_info<N: Network>(\n    State(state): State<Arc<BrowserWalletState<N>>>,\n) -> Json<BrowserApiResponse<Option<Connection>>> {\n    let connection = state.get_connection().await;\n\n    Json(BrowserApiResponse::with_data(connection))\n}\n\n/// Post connection update (connect or disconnect).\n/// Route: POST /api/connection\npub(crate) async fn post_connection_update<N: Network>(\n    State(state): State<Arc<BrowserWalletState<N>>>,\n    Json(body): Json<Option<Connection>>,\n) -> Json<BrowserApiResponse> {\n    state.set_connection(body).await;\n\n    Json(BrowserApiResponse::ok())\n}\n"
  },
  {
    "path": "crates/wallets/src/wallet_browser/mod.rs",
    "content": "pub mod error;\npub mod opts;\npub mod server;\npub mod signer;\npub mod state;\n\nmod app;\nmod handlers;\nmod queue;\nmod router;\nmod types;\n\n#[cfg(test)]\nmod tests {\n    use std::time::Duration;\n\n    use alloy_network::{Ethereum, Network, TransactionBuilder};\n    use alloy_primitives::{Address, Bytes, TxHash, TxKind, U256, address};\n    use axum::http::{HeaderMap, HeaderValue};\n    use tokio::task::JoinHandle;\n    use uuid::Uuid;\n\n    use crate::wallet_browser::{\n        error::BrowserWalletError,\n        server::BrowserWalletServer,\n        types::{\n            BrowserApiResponse, BrowserSignRequest, BrowserSignResponse, BrowserTransactionRequest,\n            BrowserTransactionResponse, Connection, SignRequest, SignType,\n        },\n    };\n\n    const ALICE: Address = address!(\"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266\");\n    const BOB: Address = address!(\"0x70997970C51812dc3A010C7d01b50e0d17dc79C8\");\n\n    const DEFAULT_TIMEOUT: Duration = Duration::from_secs(1);\n    const DEFAULT_DEVELOPMENT: bool = false;\n\n    #[tokio::test]\n    async fn test_setup_server() {\n        let mut server = create_server::<Ethereum>();\n        let client = client_with_token(&server);\n\n        // Check initial state\n        assert!(!server.is_connected().await);\n        assert!(!server.open_browser());\n        assert!(server.timeout() == DEFAULT_TIMEOUT);\n\n        // Start server\n        server.start().await.unwrap();\n\n        // Check that the transaction request queue is empty\n        check_transaction_request_queue_empty(&client, &server).await;\n\n        // Stop server\n        server.stop().await.unwrap();\n    }\n\n    #[tokio::test]\n    async fn test_connect_disconnect_wallet() {\n        let mut server = create_server::<Ethereum>();\n        let client = client_with_token(&server);\n        server.start().await.unwrap();\n\n        // Check that the transaction request queue is empty\n        check_transaction_request_queue_empty(&client, &server).await;\n\n        // Connect Alice's wallet\n        connect_wallet(&client, &server, Connection::new(ALICE, 1)).await;\n\n        // Check connection state\n        let Connection { address, chain_id } =\n            server.get_connection().await.expect(\"expected an active wallet connection\");\n        assert_eq!(address, ALICE);\n        assert_eq!(chain_id, 1);\n\n        // Disconnect wallet\n        disconnect_wallet(&client, &server).await;\n\n        // Check disconnected state\n        assert!(!server.is_connected().await);\n\n        // Connect Bob's wallet\n        connect_wallet(&client, &server, Connection::new(BOB, 42)).await;\n\n        // Check connection state\n        let Connection { address, chain_id } =\n            server.get_connection().await.expect(\"expected an active wallet connection\");\n        assert_eq!(address, BOB);\n        assert_eq!(chain_id, 42);\n\n        // Stop server\n        server.stop().await.unwrap();\n    }\n\n    #[tokio::test]\n    async fn test_switch_wallet() {\n        let mut server = create_server::<Ethereum>();\n        let client = client_with_token(&server);\n        server.start().await.unwrap();\n\n        // Connect Alice, assert connected\n        connect_wallet(&client, &server, Connection::new(ALICE, 1)).await;\n        let Connection { address, chain_id } =\n            server.get_connection().await.expect(\"expected an active wallet connection\");\n        assert_eq!(address, ALICE);\n        assert_eq!(chain_id, 1);\n\n        // Connect Bob, assert switched\n        connect_wallet(&client, &server, Connection::new(BOB, 42)).await;\n        let Connection { address, chain_id } =\n            server.get_connection().await.expect(\"expected an active wallet connection\");\n        assert_eq!(address, BOB);\n        assert_eq!(chain_id, 42);\n\n        server.stop().await.unwrap();\n    }\n\n    #[tokio::test]\n    async fn test_transaction_response_both_hash_and_error_rejected() {\n        let mut server = create_server::<Ethereum>();\n        let client = client_with_token(&server);\n        server.start().await.unwrap();\n        connect_wallet(&client, &server, Connection::new(ALICE, 1)).await;\n\n        // Enqueue a tx\n        let (tx_request_id, tx_request) = create_browser_transaction_request();\n        let _handle = wait_for_transaction_signing(&server, tx_request).await;\n        check_transaction_request_content(&client, &server, tx_request_id).await;\n\n        // Wallet posts both hash and error -> should be rejected\n        let resp = client\n            .post(format!(\"http://localhost:{}/api/transaction/response\", server.port()))\n            .json(&BrowserTransactionResponse {\n                id: tx_request_id,\n                hash: Some(TxHash::random()),\n                error: Some(\"should not have both\".into()),\n            })\n            .send()\n            .await\n            .unwrap()\n            .error_for_status()\n            .unwrap();\n\n        let api: BrowserApiResponse<()> = resp.json().await.unwrap();\n        match api {\n            BrowserApiResponse::Error { message } => {\n                assert_eq!(message, \"Only one of hash or error can be provided\");\n            }\n            _ => panic!(\"expected error response\"),\n        }\n    }\n\n    #[tokio::test]\n    async fn test_transaction_response_neither_hash_nor_error_rejected() {\n        let mut server = create_server::<Ethereum>();\n        let client = client_with_token(&server);\n        server.start().await.unwrap();\n        connect_wallet(&client, &server, Connection::new(ALICE, 1)).await;\n\n        let (tx_request_id, tx_request) = create_browser_transaction_request();\n        let _handle = wait_for_transaction_signing(&server, tx_request).await;\n        check_transaction_request_content(&client, &server, tx_request_id).await;\n\n        // Neither hash nor error -> rejected\n        let resp = client\n            .post(format!(\"http://localhost:{}/api/transaction/response\", server.port()))\n            .json(&BrowserTransactionResponse { id: tx_request_id, hash: None, error: None })\n            .send()\n            .await\n            .unwrap()\n            .error_for_status()\n            .unwrap();\n\n        let api: BrowserApiResponse<()> = resp.json().await.unwrap();\n        match api {\n            BrowserApiResponse::Error { message } => {\n                assert_eq!(message, \"Either hash or error must be provided\");\n            }\n            _ => panic!(\"expected error response\"),\n        }\n    }\n\n    #[tokio::test]\n    async fn test_transaction_response_zero_hash_rejected() {\n        let mut server = create_server::<Ethereum>();\n        let client = client_with_token(&server);\n        server.start().await.unwrap();\n        connect_wallet(&client, &server, Connection::new(ALICE, 1)).await;\n\n        let (tx_request_id, tx_request) = create_browser_transaction_request();\n        let _handle = wait_for_transaction_signing(&server, tx_request).await;\n        check_transaction_request_content(&client, &server, tx_request_id).await;\n\n        // Zero hash -> rejected\n        let zero = TxHash::new([0u8; 32]);\n        let resp = client\n            .post(format!(\"http://localhost:{}/api/transaction/response\", server.port()))\n            .json(&BrowserTransactionResponse { id: tx_request_id, hash: Some(zero), error: None })\n            .send()\n            .await\n            .unwrap()\n            .error_for_status()\n            .unwrap();\n\n        let api: BrowserApiResponse<()> = resp.json().await.unwrap();\n        match api {\n            BrowserApiResponse::Error { message } => {\n                // Message text per your handler; adjust if you use a different string.\n                assert!(\n                    message.contains(\"Invalid\") || message.contains(\"Malformed\"),\n                    \"unexpected message: {message}\"\n                );\n            }\n            _ => panic!(\"expected error response\"),\n        }\n    }\n\n    #[tokio::test]\n    async fn test_send_transaction_client_accept() {\n        let mut server = create_server::<Ethereum>();\n        let client = client_with_token(&server);\n        server.start().await.unwrap();\n        connect_wallet(&client, &server, Connection::new(ALICE, 1)).await;\n\n        let (tx_request_id, tx_request) = create_browser_transaction_request();\n        let handle = wait_for_transaction_signing(&server, tx_request).await;\n        check_transaction_request_content(&client, &server, tx_request_id).await;\n\n        // Simulate the wallet accepting and signing the tx\n        let resp = client\n            .post(format!(\"http://localhost:{}/api/transaction/response\", server.port()))\n            .json(&BrowserTransactionResponse {\n                id: tx_request_id,\n                hash: Some(TxHash::random()),\n                error: None,\n            })\n            .send()\n            .await\n            .unwrap()\n            .error_for_status()\n            .unwrap();\n        assert_eq!(resp.status(), reqwest::StatusCode::OK);\n\n        // The join handle should now return the tx hash\n        let res = handle.await.expect(\"task panicked\");\n        match res {\n            Ok(hash) => {\n                assert!(hash != TxHash::new([0; 32]));\n            }\n            other => panic!(\"expected success, got {other:?}\"),\n        }\n    }\n\n    #[tokio::test]\n    async fn test_send_transaction_client_not_requested() {\n        let mut server = create_server::<Ethereum>();\n        let client = client_with_token(&server);\n        server.start().await.unwrap();\n        connect_wallet(&client, &server, Connection::new(ALICE, 1)).await;\n\n        // Create a random transaction response without a matching request\n        let tx_request_id = Uuid::new_v4();\n\n        // Simulate the wallet sending a response for an unknown request\n        let resp = client\n            .post(format!(\"http://localhost:{}/api/transaction/response\", server.port()))\n            .json(&BrowserTransactionResponse {\n                id: tx_request_id,\n                hash: Some(TxHash::random()),\n                error: None,\n            })\n            .send()\n            .await\n            .unwrap()\n            .error_for_status()\n            .unwrap();\n\n        assert_eq!(resp.status(), reqwest::StatusCode::OK);\n\n        // Assert that no transaction without a matching request is accepted\n        let api: BrowserApiResponse<()> = resp.json().await.unwrap();\n        match api {\n            BrowserApiResponse::Error { message } => {\n                assert_eq!(message, \"Unknown transaction id\");\n            }\n            _ => panic!(\"expected error response\"),\n        }\n    }\n\n    #[tokio::test]\n    async fn test_send_transaction_invalid_response_format() {\n        let mut server = create_server::<Ethereum>();\n        let client = client_with_token(&server);\n        server.start().await.unwrap();\n        connect_wallet(&client, &server, Connection::new(ALICE, 1)).await;\n\n        // Simulate the wallet sending a response with an invalid UUID\n        let resp = client\n            .post(format!(\"http://localhost:{}/api/transaction/response\", server.port()))\n            .body(\n                r#\"{\n                \"id\": \"invalid-uuid\",\n                \"hash\": \"invalid-hash\",\n                \"error\": null\n            }\"#,\n            )\n            .header(\"Content-Type\", \"application/json\")\n            .send()\n            .await\n            .unwrap();\n\n        // The server should respond with a 422 Unprocessable Entity status\n        assert_eq!(resp.status(), reqwest::StatusCode::UNPROCESSABLE_ENTITY);\n    }\n\n    #[tokio::test]\n    async fn test_send_transaction_client_reject() {\n        let mut server = create_server::<Ethereum>();\n        let client = client_with_token(&server);\n        server.start().await.unwrap();\n        connect_wallet(&client, &server, Connection::new(ALICE, 1)).await;\n\n        // Create a browser transaction request\n        let (tx_request_id, tx_request) = create_browser_transaction_request();\n\n        // Spawn the transaction signing flow in the background\n        let handle = wait_for_transaction_signing(&server, tx_request).await;\n\n        // Check transaction request\n        check_transaction_request_content(&client, &server, tx_request_id).await;\n\n        // Simulate the wallet rejecting the tx\n        let resp = client\n            .post(format!(\"http://localhost:{}/api/transaction/response\", server.port()))\n            .json(&BrowserTransactionResponse {\n                id: tx_request_id,\n                hash: None,\n                error: Some(\"User rejected the transaction\".into()),\n            })\n            .send()\n            .await\n            .unwrap()\n            .error_for_status()\n            .unwrap();\n        assert_eq!(resp.status(), reqwest::StatusCode::OK);\n\n        // The join handle should now return a rejection error\n        let res = handle.await.expect(\"task panicked\");\n        match res {\n            Err(BrowserWalletError::Rejected { operation, reason }) => {\n                assert_eq!(operation, \"Transaction\");\n                assert_eq!(reason, \"User rejected the transaction\");\n            }\n            other => panic!(\"expected rejection, got {other:?}\"),\n        }\n    }\n\n    #[tokio::test]\n    async fn test_send_multiple_transaction_requests() {\n        let mut server = create_server::<Ethereum>();\n        let client = client_with_token(&server);\n        server.start().await.unwrap();\n        connect_wallet(&client, &server, Connection::new(ALICE, 1)).await;\n\n        // Create multiple browser transaction requests\n        let (tx_request_id1, tx_request1) = create_browser_transaction_request();\n        let (tx_request_id2, tx_request2) = create_different_browser_transaction_request();\n\n        // Spawn signing flows for both transactions concurrently\n        let handle1 = wait_for_transaction_signing(&server, tx_request1.clone()).await;\n        let handle2 = wait_for_transaction_signing(&server, tx_request2.clone()).await;\n\n        // Check first transaction request\n        {\n            let resp = client\n                .get(format!(\"http://localhost:{}/api/transaction/request\", server.port()))\n                .send()\n                .await\n                .unwrap();\n\n            let BrowserApiResponse::Ok(pending_tx) = resp\n                .json::<BrowserApiResponse<BrowserTransactionRequest<Ethereum>>>()\n                .await\n                .unwrap()\n            else {\n                panic!(\"expected BrowserApiResponse::Ok with a pending transaction\");\n            };\n\n            assert_eq!(\n                pending_tx.id, tx_request_id1,\n                \"expected the first transaction to be at the front of the queue\"\n            );\n            assert_eq!(pending_tx.request.from, tx_request1.request.from);\n            assert_eq!(pending_tx.request.to, tx_request1.request.to);\n            assert_eq!(pending_tx.request.value, tx_request1.request.value);\n        }\n\n        // Simulate the wallet accepting and signing the first transaction\n        let resp1 = client\n            .post(format!(\"http://localhost:{}/api/transaction/response\", server.port()))\n            .json(&BrowserTransactionResponse {\n                id: tx_request_id1,\n                hash: Some(TxHash::random()),\n                error: None,\n            })\n            .send()\n            .await\n            .unwrap()\n            .error_for_status()\n            .unwrap();\n        assert_eq!(resp1.status(), reqwest::StatusCode::OK);\n\n        let res1 = handle1.await.expect(\"first signing flow panicked\");\n        match res1 {\n            Ok(hash) => assert!(!hash.is_zero(), \"first tx hash should not be zero\"),\n            other => panic!(\"expected success, got {other:?}\"),\n        }\n\n        // Check second transaction request\n        {\n            let resp = client\n                .get(format!(\"http://localhost:{}/api/transaction/request\", server.port()))\n                .send()\n                .await\n                .unwrap();\n\n            let BrowserApiResponse::Ok(pending_tx) = resp\n                .json::<BrowserApiResponse<BrowserTransactionRequest<Ethereum>>>()\n                .await\n                .unwrap()\n            else {\n                panic!(\"expected BrowserApiResponse::Ok with a pending transaction\");\n            };\n\n            assert_eq!(\n                pending_tx.id, tx_request_id2,\n                \"expected the second transaction to be pending after the first one completed\"\n            );\n            assert_eq!(pending_tx.request.from, tx_request2.request.from);\n            assert_eq!(pending_tx.request.to, tx_request2.request.to);\n            assert_eq!(pending_tx.request.value, tx_request2.request.value);\n        }\n\n        // Simulate the wallet rejecting the second transaction\n        let resp2 = client\n            .post(format!(\"http://localhost:{}/api/transaction/response\", server.port()))\n            .json(&BrowserTransactionResponse {\n                id: tx_request_id2,\n                hash: None,\n                error: Some(\"User rejected the transaction\".into()),\n            })\n            .send()\n            .await\n            .unwrap()\n            .error_for_status()\n            .unwrap();\n        assert_eq!(resp2.status(), reqwest::StatusCode::OK);\n\n        let res2 = handle2.await.expect(\"second signing flow panicked\");\n        match res2 {\n            Err(BrowserWalletError::Rejected { operation, reason }) => {\n                assert_eq!(operation, \"Transaction\");\n                assert_eq!(reason, \"User rejected the transaction\");\n            }\n            other => panic!(\"expected BrowserWalletError::Rejected, got {other:?}\"),\n        }\n\n        check_transaction_request_queue_empty(&client, &server).await;\n\n        server.stop().await.unwrap();\n    }\n\n    #[tokio::test]\n    async fn test_send_sign_response_both_signature_and_error_rejected() {\n        let mut server = create_server::<Ethereum>();\n        let client = client_with_token(&server);\n        server.start().await.unwrap();\n        connect_wallet(&client, &server, Connection::new(ALICE, 1)).await;\n\n        let (sign_request_id, sign_request) = create_browser_sign_request();\n        let _handle = wait_for_message_signing(&server, sign_request).await;\n        check_sign_request_content(&client, &server, sign_request_id).await;\n\n        // Both signature and error -> should be rejected\n        let resp = client\n            .post(format!(\"http://localhost:{}/api/signing/response\", server.port()))\n            .json(&BrowserSignResponse {\n                id: sign_request_id,\n                signature: Some(Bytes::from(\"Hello World\")),\n                error: Some(\"Should not have both\".into()),\n            })\n            .send()\n            .await\n            .unwrap()\n            .error_for_status()\n            .unwrap();\n\n        let api: BrowserApiResponse<()> = resp.json().await.unwrap();\n        match api {\n            BrowserApiResponse::Error { message } => {\n                assert_eq!(message, \"Only one of signature or error can be provided\");\n            }\n            _ => panic!(\"expected error response\"),\n        }\n    }\n\n    #[tokio::test]\n    async fn test_send_sign_response_neither_hash_nor_error_rejected() {\n        let mut server = create_server::<Ethereum>();\n        let client = client_with_token(&server);\n        server.start().await.unwrap();\n        connect_wallet(&client, &server, Connection::new(ALICE, 1)).await;\n\n        let (sign_request_id, sign_request) = create_browser_sign_request();\n        let _handle = wait_for_message_signing(&server, sign_request).await;\n        check_sign_request_content(&client, &server, sign_request_id).await;\n\n        // Neither signature nor error -> rejected\n        let resp = client\n            .post(format!(\"http://localhost:{}/api/signing/response\", server.port()))\n            .json(&BrowserSignResponse { id: sign_request_id, signature: None, error: None })\n            .send()\n            .await\n            .unwrap()\n            .error_for_status()\n            .unwrap();\n\n        let api: BrowserApiResponse<()> = resp.json().await.unwrap();\n        match api {\n            BrowserApiResponse::Error { message } => {\n                assert_eq!(message, \"Either signature or error must be provided\");\n            }\n            _ => panic!(\"expected error response\"),\n        }\n    }\n\n    #[tokio::test]\n    async fn test_send_sign_client_accept() {\n        let mut server = create_server::<Ethereum>();\n        let client = client_with_token(&server);\n        server.start().await.unwrap();\n        connect_wallet(&client, &server, Connection::new(ALICE, 1)).await;\n\n        let (sign_request_id, sign_request) = create_browser_sign_request();\n        let handle = wait_for_message_signing(&server, sign_request).await;\n        check_sign_request_content(&client, &server, sign_request_id).await;\n\n        // Simulate the wallet accepting and signing the message\n        let resp = client\n            .post(format!(\"http://localhost:{}/api/signing/response\", server.port()))\n            .json(&BrowserSignResponse {\n                id: sign_request_id,\n                signature: Some(Bytes::from(\"FakeSignature\")),\n                error: None,\n            })\n            .send()\n            .await\n            .unwrap()\n            .error_for_status()\n            .unwrap();\n        assert_eq!(resp.status(), reqwest::StatusCode::OK);\n\n        // The join handle should now return the signature\n        let res = handle.await.expect(\"task panicked\");\n        match res {\n            Ok(signature) => {\n                assert_eq!(signature, Bytes::from(\"FakeSignature\"));\n            }\n            other => panic!(\"expected success, got {other:?}\"),\n        }\n    }\n\n    #[tokio::test]\n    async fn test_send_sign_client_not_requested() {\n        let mut server = create_server::<Ethereum>();\n        let client = client_with_token(&server);\n        server.start().await.unwrap();\n        connect_wallet(&client, &server, Connection::new(ALICE, 1)).await;\n\n        // Create a random signing response without a matching request\n        let sign_request_id = Uuid::new_v4();\n\n        // Simulate the wallet sending a response for an unknown request\n        let resp = client\n            .post(format!(\"http://localhost:{}/api/signing/response\", server.port()))\n            .json(&BrowserSignResponse {\n                id: sign_request_id,\n                signature: Some(Bytes::from(\"FakeSignature\")),\n                error: None,\n            })\n            .send()\n            .await\n            .unwrap()\n            .error_for_status()\n            .unwrap();\n\n        assert_eq!(resp.status(), reqwest::StatusCode::OK);\n\n        // Assert that no signing response without a matching request is accepted\n        let api: BrowserApiResponse<()> = resp.json().await.unwrap();\n        match api {\n            BrowserApiResponse::Error { message } => {\n                assert_eq!(message, \"Unknown signing request id\");\n            }\n            _ => panic!(\"expected error response\"),\n        }\n    }\n\n    #[tokio::test]\n    async fn test_send_sign_invalid_response_format() {\n        let mut server = create_server::<Ethereum>();\n        let client = client_with_token(&server);\n        server.start().await.unwrap();\n        connect_wallet(&client, &server, Connection::new(ALICE, 1)).await;\n\n        // Simulate the wallet sending a response with an invalid UUID\n        let resp = client\n            .post(format!(\"http://localhost:{}/api/signing/response\", server.port()))\n            .body(\n                r#\"{\n                \"id\": \"invalid-uuid\",\n                \"signature\": \"invalid-signature\",\n                \"error\": null\n            }\"#,\n            )\n            .header(\"Content-Type\", \"application/json\")\n            .send()\n            .await\n            .unwrap();\n\n        // The server should respond with a 422 Unprocessable Entity status\n        assert_eq!(resp.status(), reqwest::StatusCode::UNPROCESSABLE_ENTITY);\n    }\n\n    #[tokio::test]\n    async fn test_send_sign_client_reject() {\n        let mut server = create_server::<Ethereum>();\n        let client = client_with_token(&server);\n        server.start().await.unwrap();\n        connect_wallet(&client, &server, Connection::new(ALICE, 1)).await;\n\n        let (sign_request_id, sign_request) = create_browser_sign_request();\n        let handle = wait_for_message_signing(&server, sign_request).await;\n        check_sign_request_content(&client, &server, sign_request_id).await;\n\n        // Simulate the wallet rejecting the signing request\n        let resp = client\n            .post(format!(\"http://localhost:{}/api/signing/response\", server.port()))\n            .json(&BrowserSignResponse {\n                id: sign_request_id,\n                signature: None,\n                error: Some(\"User rejected the signing request\".into()),\n            })\n            .send()\n            .await\n            .unwrap()\n            .error_for_status()\n            .unwrap();\n        assert_eq!(resp.status(), reqwest::StatusCode::OK);\n\n        // The join handle should now return a rejection error\n        let res = handle.await.expect(\"task panicked\");\n        match res {\n            Err(BrowserWalletError::Rejected { operation, reason }) => {\n                assert_eq!(operation, \"Signing\");\n                assert_eq!(reason, \"User rejected the signing request\");\n            }\n            other => panic!(\"expected rejection, got {other:?}\"),\n        }\n    }\n\n    #[tokio::test]\n    async fn test_send_multiple_sign_requests() {\n        let mut server = create_server::<Ethereum>();\n        let client = client_with_token(&server);\n        server.start().await.unwrap();\n        connect_wallet(&client, &server, Connection::new(ALICE, 1)).await;\n\n        // Create multiple browser sign requests\n        let (sign_request_id1, sign_request1) = create_browser_sign_request();\n        let (sign_request_id2, sign_request2) = create_different_browser_sign_request();\n\n        // Spawn signing flows for both sign requests concurrently\n        let handle1 = wait_for_message_signing(&server, sign_request1.clone()).await;\n        let handle2 = wait_for_message_signing(&server, sign_request2.clone()).await;\n\n        // Check first sign request\n        {\n            let resp = client\n                .get(format!(\"http://localhost:{}/api/signing/request\", server.port()))\n                .send()\n                .await\n                .unwrap();\n\n            let BrowserApiResponse::Ok(pending_sign) =\n                resp.json::<BrowserApiResponse<BrowserSignRequest>>().await.unwrap()\n            else {\n                panic!(\"expected BrowserApiResponse::Ok with a pending sign request\");\n            };\n\n            assert_eq!(pending_sign.id, sign_request_id1);\n            assert_eq!(pending_sign.sign_type, sign_request1.sign_type);\n            assert_eq!(pending_sign.request.address, sign_request1.request.address);\n            assert_eq!(pending_sign.request.message, sign_request1.request.message);\n        }\n\n        // Simulate the wallet accepting and signing the first sign request\n        let resp1 = client\n            .post(format!(\"http://localhost:{}/api/signing/response\", server.port()))\n            .json(&BrowserSignResponse {\n                id: sign_request_id1,\n                signature: Some(Bytes::from(\"Signature1\")),\n                error: None,\n            })\n            .send()\n            .await\n            .unwrap()\n            .error_for_status()\n            .unwrap();\n        assert_eq!(resp1.status(), reqwest::StatusCode::OK);\n\n        let res1 = handle1.await.expect(\"first signing flow panicked\");\n        match res1 {\n            Ok(signature) => assert_eq!(signature, Bytes::from(\"Signature1\")),\n            other => panic!(\"expected success, got {other:?}\"),\n        }\n\n        // Check second sign request\n        {\n            let resp = client\n                .get(format!(\"http://localhost:{}/api/signing/request\", server.port()))\n                .send()\n                .await\n                .unwrap();\n\n            let BrowserApiResponse::Ok(pending_sign) =\n                resp.json::<BrowserApiResponse<BrowserSignRequest>>().await.unwrap()\n            else {\n                panic!(\"expected BrowserApiResponse::Ok with a pending sign request\");\n            };\n\n            assert_eq!(pending_sign.id, sign_request_id2,);\n            assert_eq!(pending_sign.sign_type, sign_request2.sign_type);\n            assert_eq!(pending_sign.request.address, sign_request2.request.address);\n            assert_eq!(pending_sign.request.message, sign_request2.request.message);\n        }\n\n        // Simulate the wallet rejecting the second sign request\n        let resp2 = client\n            .post(format!(\"http://localhost:{}/api/signing/response\", server.port()))\n            .json(&BrowserSignResponse {\n                id: sign_request_id2,\n                signature: None,\n                error: Some(\"User rejected the signing request\".into()),\n            })\n            .send()\n            .await\n            .unwrap()\n            .error_for_status()\n            .unwrap();\n        assert_eq!(resp2.status(), reqwest::StatusCode::OK);\n\n        let res2 = handle2.await.expect(\"second signing flow panicked\");\n        match res2 {\n            Err(BrowserWalletError::Rejected { operation, reason }) => {\n                assert_eq!(operation, \"Signing\");\n                assert_eq!(reason, \"User rejected the signing request\");\n            }\n            other => panic!(\"expected BrowserWalletError::Rejected, got {other:?}\"),\n        }\n\n        check_sign_request_queue_empty(&client, &server).await;\n\n        server.stop().await.unwrap();\n    }\n\n    /// Helper to create a default browser wallet server.\n    fn create_server<N: Network>() -> BrowserWalletServer<N> {\n        BrowserWalletServer::new(0, false, DEFAULT_TIMEOUT, DEFAULT_DEVELOPMENT)\n    }\n\n    /// Helper to create a reqwest client with the session token header.\n    fn client_with_token<N: Network>(server: &BrowserWalletServer<N>) -> reqwest::Client {\n        let mut headers = HeaderMap::new();\n        headers.insert(\"X-Session-Token\", HeaderValue::from_str(server.session_token()).unwrap());\n        reqwest::Client::builder().default_headers(headers).build().unwrap()\n    }\n\n    /// Helper to connect a wallet to the server.\n    async fn connect_wallet<N: Network>(\n        client: &reqwest::Client,\n        server: &BrowserWalletServer<N>,\n        connection: Connection,\n    ) {\n        let resp = client\n            .post(format!(\"http://localhost:{}/api/connection\", server.port()))\n            .json(&connection)\n            .send();\n        assert!(resp.await.is_ok());\n    }\n\n    /// Helper to disconnect a wallet from the server.\n    async fn disconnect_wallet<N: Network>(\n        client: &reqwest::Client,\n        server: &BrowserWalletServer<N>,\n    ) {\n        let resp = client\n            .post(format!(\"http://localhost:{}/api/connection\", server.port()))\n            .json(&Option::<Connection>::None)\n            .send();\n        assert!(resp.await.is_ok());\n    }\n\n    /// Spawn the transaction signing flow in the background and return the join handle.\n    async fn wait_for_transaction_signing<N: Network>(\n        server: &BrowserWalletServer<N>,\n        tx_request: BrowserTransactionRequest<N>,\n    ) -> JoinHandle<Result<TxHash, BrowserWalletError>> {\n        // Spawn the signing flow in the background\n        let browser_server = server.clone();\n        let join_handle =\n            tokio::spawn(async move { browser_server.request_transaction(tx_request).await });\n        tokio::task::yield_now().await;\n        tokio::time::sleep(Duration::from_millis(100)).await;\n\n        join_handle\n    }\n\n    /// Spawn the message signing flow in the background and return the join handle.\n    async fn wait_for_message_signing<N: Network>(\n        server: &BrowserWalletServer<N>,\n        sign_request: BrowserSignRequest,\n    ) -> JoinHandle<Result<Bytes, BrowserWalletError>> {\n        // Spawn the signing flow in the background\n        let browser_server = server.clone();\n        let join_handle =\n            tokio::spawn(async move { browser_server.request_signing(sign_request).await });\n        tokio::task::yield_now().await;\n        tokio::time::sleep(Duration::from_millis(100)).await;\n\n        join_handle\n    }\n\n    /// Create a simple browser transaction request.\n    fn create_browser_transaction_request<N: Network>() -> (Uuid, BrowserTransactionRequest<N>) {\n        let id = Uuid::new_v4();\n        let request = N::TransactionRequest::default()\n            .with_from(ALICE)\n            .with_to(BOB)\n            .with_value(U256::from(1000));\n        let tx = BrowserTransactionRequest { id, request };\n        (id, tx)\n    }\n\n    /// Create a different browser transaction request (from the first one).\n    fn create_different_browser_transaction_request<N: Network>()\n    -> (Uuid, BrowserTransactionRequest<N>) {\n        let id = Uuid::new_v4();\n        let request = N::TransactionRequest::default()\n            .with_from(BOB)\n            .with_to(ALICE)\n            .with_value(U256::from(2000));\n        let tx = BrowserTransactionRequest { id, request };\n        (id, tx)\n    }\n\n    /// Create a simple browser sign request.\n    fn create_browser_sign_request() -> (Uuid, BrowserSignRequest) {\n        let id = Uuid::new_v4();\n        let req = BrowserSignRequest {\n            id,\n            sign_type: SignType::PersonalSign,\n            request: SignRequest { message: \"Hello, world!\".into(), address: ALICE },\n        };\n        (id, req)\n    }\n\n    /// Create a different browser sign request (from the first one).\n    fn create_different_browser_sign_request() -> (Uuid, BrowserSignRequest) {\n        let id = Uuid::new_v4();\n        let req = BrowserSignRequest {\n            id,\n            sign_type: SignType::SignTypedDataV4,\n            request: SignRequest { message: \"Different message\".into(), address: BOB },\n        };\n        (id, req)\n    }\n\n    /// Check that the transaction request queue is empty, if not panic.\n    async fn check_transaction_request_queue_empty<N: Network>(\n        client: &reqwest::Client,\n        server: &BrowserWalletServer<N>,\n    ) {\n        let resp = client\n            .get(format!(\"http://localhost:{}/api/transaction/request\", server.port()))\n            .send()\n            .await\n            .unwrap();\n\n        let BrowserApiResponse::Error { message } =\n            resp.json::<BrowserApiResponse<BrowserTransactionRequest<N>>>().await.unwrap()\n        else {\n            panic!(\"expected BrowserApiResponse::Error (no pending transaction), but got Ok\");\n        };\n\n        assert_eq!(message, \"No pending transaction request\");\n    }\n\n    /// Check that the transaction request matches the expected request ID and fields.\n    async fn check_transaction_request_content<N: Network>(\n        client: &reqwest::Client,\n        server: &BrowserWalletServer<N>,\n        tx_request_id: Uuid,\n    ) {\n        let resp = client\n            .get(format!(\"http://localhost:{}/api/transaction/request\", server.port()))\n            .send()\n            .await\n            .unwrap();\n\n        let BrowserApiResponse::Ok(pending_tx) =\n            resp.json::<BrowserApiResponse<BrowserTransactionRequest<N>>>().await.unwrap()\n        else {\n            panic!(\"expected BrowserApiResponse::Ok with a pending transaction\");\n        };\n\n        assert_eq!(pending_tx.id, tx_request_id);\n        assert_eq!(pending_tx.request.from(), Some(ALICE));\n        assert_eq!(pending_tx.request.kind(), Some(TxKind::Call(BOB)));\n        assert_eq!(pending_tx.request.value(), Some(U256::from(1000)));\n    }\n\n    /// Check that the sign request queue is empty, if not panic.\n    async fn check_sign_request_queue_empty<N: Network>(\n        client: &reqwest::Client,\n        server: &BrowserWalletServer<N>,\n    ) {\n        let resp = client\n            .get(format!(\"http://localhost:{}/api/signing/request\", server.port()))\n            .send()\n            .await\n            .unwrap();\n\n        let BrowserApiResponse::Error { message } =\n            resp.json::<BrowserApiResponse<BrowserSignRequest>>().await.unwrap()\n        else {\n            panic!(\"expected BrowserApiResponse::Error (no pending signing request), but got Ok\");\n        };\n\n        assert_eq!(message, \"No pending signing request\");\n    }\n\n    /// Check that the sign request matches the expected request ID and fields.\n    async fn check_sign_request_content<N: Network>(\n        client: &reqwest::Client,\n        server: &BrowserWalletServer<N>,\n        sign_request_id: Uuid,\n    ) {\n        let resp = client\n            .get(format!(\"http://localhost:{}/api/signing/request\", server.port()))\n            .send()\n            .await\n            .unwrap();\n\n        let BrowserApiResponse::Ok(pending_req) =\n            resp.json::<BrowserApiResponse<BrowserSignRequest>>().await.unwrap()\n        else {\n            panic!(\"expected BrowserApiResponse::Ok with a pending signing request\");\n        };\n\n        assert_eq!(pending_req.id, sign_request_id);\n        assert_eq!(pending_req.sign_type, SignType::PersonalSign);\n        assert_eq!(pending_req.request.address, ALICE);\n        assert_eq!(pending_req.request.message, \"Hello, world!\");\n    }\n}\n"
  },
  {
    "path": "crates/wallets/src/wallet_browser/opts.rs",
    "content": "use std::time::Duration;\n\nuse alloy_network::Network;\nuse clap::Parser;\nuse eyre::Result;\nuse serde::Serialize;\n\nuse crate::wallet_browser::signer::BrowserSigner;\n\n/// Browser wallet options\n#[derive(Clone, Debug, Default, Serialize, Parser)]\n#[command(next_help_heading = \"Browser wallet options\")]\npub struct BrowserWalletOpts {\n    /// Use a browser wallet.\n    #[arg(long, help_heading = \"\")]\n    pub browser: bool,\n\n    /// Port for the browser wallet server.\n    #[arg(long, value_name = \"PORT\", default_value = \"9545\", requires = \"browser\")]\n    pub browser_port: u16,\n\n    /// Whether to open the browser for wallet connection.\n    #[arg(long, default_value_t = false, requires = \"browser\")]\n    pub browser_disable_open: bool,\n\n    /// Enable development mode for the browser wallet.\n    /// This relaxes certain security features for local development.\n    ///\n    /// **WARNING**: This should only be used in a development environment.\n    #[arg(long, hide = true)]\n    pub browser_development: bool,\n}\n\nimpl BrowserWalletOpts {\n    pub async fn run<N: Network>(&self) -> Result<Option<BrowserSigner<N>>> {\n        Ok(if self.browser {\n            Some(\n                BrowserSigner::new(\n                    self.browser_port,\n                    !self.browser_disable_open,\n                    Duration::from_secs(300),\n                    self.browser_development,\n                )\n                .await?,\n            )\n        } else {\n            None\n        })\n    }\n}\n"
  },
  {
    "path": "crates/wallets/src/wallet_browser/queue.rs",
    "content": "use std::collections::{HashMap, VecDeque};\n\nuse alloy_network::Network;\nuse uuid::Uuid;\n\nuse crate::wallet_browser::types::{BrowserSignRequest, BrowserTransactionRequest};\n\n#[derive(Debug)]\npub(crate) struct RequestQueue<Req, Res> {\n    /// Pending requests from CLI to browser\n    requests: VecDeque<Req>,\n    /// Responses from browser indexed by request ID\n    responses: HashMap<Uuid, Res>,\n}\n\nimpl<Req, Res> Default for RequestQueue<Req, Res> {\n    fn default() -> Self {\n        Self::new()\n    }\n}\n\nimpl<Req, Res> RequestQueue<Req, Res> {\n    /// Create a new request queue.\n    pub fn new() -> Self {\n        Self { requests: VecDeque::new(), responses: HashMap::new() }\n    }\n\n    /// Add a new request to the queue.\n    pub fn add_request(&mut self, request: Req) {\n        self.requests.push_back(request);\n    }\n\n    /// Check if the queue contains any pending requests matching the given ID.\n    pub fn has_request(&self, id: &Uuid) -> bool\n    where\n        Req: HasId,\n    {\n        self.requests.iter().any(|r| r.id() == id)\n    }\n\n    /// Read the next request from the queue without removing it.\n    pub fn read_request(&self) -> Option<&Req> {\n        self.requests.front()\n    }\n\n    /// Remove a request by its ID.\n    pub fn remove_request(&mut self, id: &Uuid) -> Option<Req>\n    where\n        Req: HasId,\n    {\n        if let Some(pos) = self.requests.iter().position(|r| r.id() == id) {\n            self.requests.remove(pos)\n        } else {\n            None\n        }\n    }\n\n    /// Add a response to the queue.\n    pub fn add_response(&mut self, id: Uuid, response: Res) {\n        self.responses.insert(id, response);\n    }\n\n    /// Get a response by its ID, removing it from the queue.\n    pub fn get_response(&mut self, id: &Uuid) -> Option<Res> {\n        self.responses.remove(id)\n    }\n}\n\npub(crate) trait HasId {\n    fn id(&self) -> &Uuid;\n}\n\nimpl<N: Network> HasId for BrowserTransactionRequest<N> {\n    fn id(&self) -> &Uuid {\n        &self.id\n    }\n}\n\nimpl HasId for BrowserSignRequest {\n    fn id(&self) -> &Uuid {\n        &self.id\n    }\n}\n"
  },
  {
    "path": "crates/wallets/src/wallet_browser/router.rs",
    "content": "use std::sync::Arc;\n\nuse alloy_network::Network;\nuse axum::{\n    Router,\n    extract::{Request, State},\n    http::{HeaderValue, Method, StatusCode, header},\n    middleware::{self, Next},\n    response::Response,\n    routing::{get, post},\n};\nuse tower::ServiceBuilder;\nuse tower_http::{cors::CorsLayer, set_header::SetResponseHeaderLayer};\n\nuse crate::wallet_browser::{handlers, state::BrowserWalletState};\n\npub async fn build_router<N: Network>(state: Arc<BrowserWalletState<N>>, port: u16) -> Router {\n    let api = Router::new()\n        .route(\"/transaction/request\", get(handlers::get_next_transaction_request))\n        .route(\"/transaction/response\", post(handlers::post_transaction_response))\n        .route(\"/signing/request\", get(handlers::get_next_signing_request))\n        .route(\"/signing/response\", post(handlers::post_signing_response))\n        .route(\"/connection\", get(handlers::get_connection_info))\n        .route(\"/connection\", post(handlers::post_connection_update))\n        .route_layer(middleware::from_fn_with_state(state.clone(), require_session_token))\n        .with_state(state.clone());\n\n    let mut origins = vec![format!(\"http://127.0.0.1:{port}\").parse().unwrap()];\n\n    // Allow default port of 5173 in development mode.\n    if state.is_development() {\n        origins.push(\"https://localhost:5173\".to_string().parse().unwrap());\n    }\n\n    let security_headers = ServiceBuilder::new()\n        .layer(SetResponseHeaderLayer::if_not_present(\n            header::CONTENT_SECURITY_POLICY,\n            HeaderValue::from_static(concat!(\n                \"default-src 'none'; \",\n                \"object-src 'none'; \",\n                \"base-uri 'none'; \",\n                \"frame-ancestors 'none'; \",\n                \"img-src 'self'; \",\n                \"font-src 'none'; \",\n                \"connect-src 'self' https: http: wss: ws:;\",\n                \"style-src 'self'; \",\n                \"script-src 'self'; \",\n                \"form-action 'none'; \",\n                \"worker-src 'none'; \",\n                \"frame-src https://id.porto.sh;\"\n            )),\n        ))\n        .layer(SetResponseHeaderLayer::if_not_present(\n            header::REFERRER_POLICY,\n            HeaderValue::from_static(\"no-referrer\"),\n        ))\n        .layer(SetResponseHeaderLayer::if_not_present(\n            header::X_CONTENT_TYPE_OPTIONS,\n            HeaderValue::from_static(\"nosniff\"),\n        ))\n        .layer(\n            CorsLayer::new()\n                .allow_origin(origins)\n                .allow_methods([Method::GET, Method::POST, Method::OPTIONS])\n                .allow_headers([header::CONTENT_TYPE])\n                .allow_credentials(false),\n        );\n\n    Router::new()\n        .route(\"/\", get(handlers::serve_index))\n        .route(\"/styles.css\", get(handlers::serve_css))\n        .route(\"/main.js\", get(handlers::serve_js))\n        .route(\"/banner.png\", get(handlers::serve_banner_png))\n        .route(\"/logo.png\", get(handlers::serve_logo_png))\n        .nest(\"/api\", api)\n        .layer(security_headers)\n        .with_state(state)\n}\n\nasync fn require_session_token<N: Network>(\n    State(state): State<Arc<BrowserWalletState<N>>>,\n    req: Request,\n    next: Next,\n) -> Result<Response, StatusCode> {\n    if req.method() == Method::OPTIONS {\n        return Ok(next.run(req).await);\n    }\n\n    // In development mode, skip session token check.\n    if state.is_development() {\n        return Ok(next.run(req).await);\n    }\n\n    let expected = state.session_token();\n    let provided = req\n        .headers()\n        .get(\"X-Session-Token\")\n        .and_then(|v| v.to_str().ok())\n        .ok_or(StatusCode::FORBIDDEN)?;\n\n    if provided != expected {\n        return Err(StatusCode::FORBIDDEN);\n    }\n\n    Ok(next.run(req).await)\n}\n"
  },
  {
    "path": "crates/wallets/src/wallet_browser/server.rs",
    "content": "use std::{\n    net::SocketAddr,\n    sync::Arc,\n    time::{Duration, Instant},\n};\n\nuse alloy_dyn_abi::TypedData;\nuse alloy_network::Network;\nuse alloy_primitives::{Address, Bytes, TxHash};\nuse tokio::{\n    net::TcpListener,\n    sync::{Mutex, oneshot},\n};\nuse uuid::Uuid;\n\nuse crate::wallet_browser::{\n    error::BrowserWalletError,\n    router::build_router,\n    state::BrowserWalletState,\n    types::{\n        BrowserSignRequest, BrowserSignTypedDataRequest, BrowserTransactionRequest, Connection,\n        SignRequest, SignType,\n    },\n};\n\n/// Browser wallet server.\n#[derive(Debug, Clone)]\npub struct BrowserWalletServer<N: Network> {\n    port: u16,\n    state: Arc<BrowserWalletState<N>>,\n    shutdown_tx: Option<Arc<Mutex<Option<oneshot::Sender<()>>>>>,\n    open_browser: bool,\n    timeout: Duration,\n}\n\nimpl<N: Network> BrowserWalletServer<N> {\n    /// Create a new browser wallet server.\n    pub fn new(port: u16, open_browser: bool, timeout: Duration, development: bool) -> Self {\n        Self {\n            port,\n            state: Arc::new(BrowserWalletState::new(Uuid::new_v4().to_string(), development)),\n            shutdown_tx: None,\n            open_browser,\n            timeout,\n        }\n    }\n\n    /// Start the server and open browser.\n    pub async fn start(&mut self) -> Result<(), BrowserWalletError> {\n        let router = build_router(self.state.clone(), self.port).await;\n\n        let addr = SocketAddr::from(([127, 0, 0, 1], self.port));\n        let listener = TcpListener::bind(addr)\n            .await\n            .map_err(|e| BrowserWalletError::ServerError(e.to_string()))?;\n        self.port = listener.local_addr().unwrap().port();\n\n        let (shutdown_tx, shutdown_rx) = oneshot::channel();\n        self.shutdown_tx = Some(Arc::new(Mutex::new(Some(shutdown_tx))));\n\n        tokio::spawn(async move {\n            let server = axum::serve(listener, router);\n            let _ = server\n                .with_graceful_shutdown(async {\n                    let _ = shutdown_rx.await;\n                })\n                .await;\n        });\n\n        if self.open_browser {\n            webbrowser::open(&format!(\"http://127.0.0.1:{}\", self.port)).map_err(|e| {\n                BrowserWalletError::ServerError(format!(\"Failed to open browser: {e}\"))\n            })?;\n        }\n\n        Ok(())\n    }\n\n    /// Stop the server.\n    pub async fn stop(&mut self) -> Result<(), BrowserWalletError> {\n        if let Some(shutdown_arc) = self.shutdown_tx.take()\n            && let Some(tx) = shutdown_arc.lock().await.take()\n        {\n            let _ = tx.send(());\n        }\n        Ok(())\n    }\n\n    /// Get the server port.\n    pub fn port(&self) -> u16 {\n        self.port\n    }\n\n    /// Check if the browser should be opened.\n    pub fn open_browser(&self) -> bool {\n        self.open_browser\n    }\n\n    /// Get the timeout duration.\n    pub fn timeout(&self) -> Duration {\n        self.timeout\n    }\n\n    /// Get the session token.\n    pub fn session_token(&self) -> &str {\n        self.state.session_token()\n    }\n\n    /// Check if a wallet is connected.\n    pub async fn is_connected(&self) -> bool {\n        self.state.is_connected().await\n    }\n\n    /// Get current wallet connection.\n    pub async fn get_connection(&self) -> Option<Connection> {\n        self.state.get_connection().await\n    }\n\n    /// Request a transaction to be signed and sent via the browser wallet.\n    pub async fn request_transaction(\n        &self,\n        request: BrowserTransactionRequest<N>,\n    ) -> Result<TxHash, BrowserWalletError> {\n        if !self.is_connected().await {\n            return Err(BrowserWalletError::NotConnected);\n        }\n\n        let tx_id = request.id;\n\n        self.state.add_transaction_request(request).await;\n\n        let start = Instant::now();\n\n        loop {\n            if let Some(response) = self.state.get_transaction_response(&tx_id).await {\n                if let Some(hash) = response.hash {\n                    return Ok(hash);\n                } else if let Some(error) = response.error {\n                    return Err(BrowserWalletError::Rejected {\n                        operation: \"Transaction\",\n                        reason: error,\n                    });\n                } else {\n                    return Err(BrowserWalletError::ServerError(\n                        \"Transaction response missing both hash and error\".to_string(),\n                    ));\n                }\n            }\n\n            if start.elapsed() > self.timeout {\n                self.state.remove_transaction_request(&tx_id).await;\n                return Err(BrowserWalletError::Timeout { operation: \"Transaction\" });\n            }\n\n            tokio::time::sleep(Duration::from_millis(100)).await;\n        }\n    }\n\n    /// Request a message to be signed via the browser wallet.\n    pub async fn request_signing(\n        &self,\n        request: BrowserSignRequest,\n    ) -> Result<Bytes, BrowserWalletError> {\n        if !self.is_connected().await {\n            return Err(BrowserWalletError::NotConnected);\n        }\n\n        let tx_id = request.id;\n\n        self.state.add_signing_request(request).await;\n\n        let start = Instant::now();\n\n        loop {\n            if let Some(response) = self.state.get_signing_response(&tx_id).await {\n                if let Some(signature) = response.signature {\n                    return Ok(signature);\n                } else if let Some(error) = response.error {\n                    return Err(BrowserWalletError::Rejected {\n                        operation: \"Signing\",\n                        reason: error,\n                    });\n                } else {\n                    return Err(BrowserWalletError::ServerError(\n                        \"Signing response missing both signature and error\".to_string(),\n                    ));\n                }\n            }\n\n            if start.elapsed() > self.timeout {\n                self.state.remove_signing_request(&tx_id).await;\n                return Err(BrowserWalletError::Timeout { operation: \"Signing\" });\n            }\n\n            tokio::time::sleep(Duration::from_millis(100)).await;\n        }\n    }\n\n    /// Request EIP-712 typed data signing via the browser wallet.\n    pub async fn request_typed_data_signing(\n        &self,\n        address: Address,\n        typed_data: TypedData,\n    ) -> Result<Bytes, BrowserWalletError> {\n        let request = BrowserSignTypedDataRequest { id: Uuid::new_v4(), address, typed_data };\n\n        let sign_request = BrowserSignRequest {\n            id: request.id,\n            sign_type: SignType::SignTypedDataV4,\n            request: SignRequest {\n                message: serde_json::to_string(&request.typed_data).map_err(|e| {\n                    BrowserWalletError::ServerError(format!(\"Failed to serialize typed data: {e}\"))\n                })?,\n                address: request.address,\n            },\n        };\n\n        self.request_signing(sign_request).await\n    }\n}\n"
  },
  {
    "path": "crates/wallets/src/wallet_browser/signer.rs",
    "content": "use std::{\n    sync::Arc,\n    time::{Duration, Instant},\n};\n\nuse alloy_network::{Network, TransactionBuilder};\nuse alloy_primitives::{Address, B256, ChainId};\nuse alloy_signer::Result;\nuse tokio::sync::Mutex;\nuse uuid::Uuid;\n\nuse crate::wallet_browser::{\n    server::BrowserWalletServer,\n    types::{BrowserTransactionRequest, Connection},\n};\n\n#[derive(Clone, Debug)]\npub struct BrowserSigner<N: Network> {\n    server: Arc<Mutex<BrowserWalletServer<N>>>,\n    address: Address,\n    chain_id: ChainId,\n}\n\nimpl<N: Network> BrowserSigner<N> {\n    pub async fn new(\n        port: u16,\n        open_browser: bool,\n        timeout: Duration,\n        development: bool,\n    ) -> Result<Self> {\n        let mut server = BrowserWalletServer::new(port, open_browser, timeout, development);\n\n        server.start().await.map_err(alloy_signer::Error::other)?;\n\n        let _ = sh_warn!(\"Browser wallet is still in early development. Use with caution!\");\n        let _ = sh_println!(\"Opening browser for wallet connection...\");\n        let _ = sh_println!(\"Waiting for wallet connection...\");\n\n        let start = Instant::now();\n\n        loop {\n            if let Some(Connection { address, chain_id }) = server.get_connection().await {\n                let _ = sh_println!(\"Wallet connected: {}\", address);\n                let _ = sh_println!(\"Chain ID: {}\", chain_id);\n\n                return Ok(Self { server: Arc::new(Mutex::new(server)), address, chain_id });\n            }\n\n            if start.elapsed() > timeout {\n                return Err(alloy_signer::Error::other(\"Wallet connection timeout\"));\n            }\n\n            tokio::time::sleep(Duration::from_secs(1)).await;\n        }\n    }\n\n    /// Send a transaction through the browser wallet.\n    pub async fn send_transaction_via_browser(\n        &self,\n        tx_request: N::TransactionRequest,\n    ) -> Result<B256> {\n        if let Some(from) = tx_request.from()\n            && from != self.address\n        {\n            return Err(alloy_signer::Error::other(\n                \"Transaction `from` address does not match connected wallet address\",\n            ));\n        }\n\n        if let Some(chain_id) = tx_request.chain_id()\n            && chain_id != self.chain_id\n        {\n            return Err(alloy_signer::Error::other(\n                \"Transaction `chainId` does not match connected wallet chain ID\",\n            ));\n        }\n\n        let request = BrowserTransactionRequest { id: Uuid::new_v4(), request: tx_request };\n\n        let server = self.server.lock().await;\n        let tx_hash =\n            server.request_transaction(request).await.map_err(alloy_signer::Error::other)?;\n\n        tokio::time::sleep(Duration::from_millis(500)).await;\n\n        Ok(tx_hash)\n    }\n\n    pub fn address(&self) -> Address {\n        self.address\n    }\n}\n\nimpl<N: Network> Drop for BrowserSigner<N> {\n    fn drop(&mut self) {\n        let server = self.server.clone();\n\n        tokio::spawn(async move {\n            let mut server = server.lock().await;\n            let _ = server.stop().await;\n        });\n    }\n}\n"
  },
  {
    "path": "crates/wallets/src/wallet_browser/state.rs",
    "content": "use std::sync::Arc;\n\nuse alloy_network::Network;\nuse tokio::sync::{Mutex, RwLock};\nuse uuid::Uuid;\n\nuse crate::wallet_browser::{\n    queue::RequestQueue,\n    types::{\n        BrowserSignRequest, BrowserSignResponse, BrowserTransactionRequest,\n        BrowserTransactionResponse, Connection,\n    },\n};\n\n#[derive(Debug, Clone)]\npub(crate) struct BrowserWalletState<N: Network> {\n    /// Current information about the wallet connection.\n    connection: Arc<RwLock<Option<Connection>>>,\n    /// Request/response queue for transactions.\n    transactions:\n        Arc<Mutex<RequestQueue<BrowserTransactionRequest<N>, BrowserTransactionResponse>>>,\n    /// Request/response queue for signings.\n    signings: Arc<Mutex<RequestQueue<BrowserSignRequest, BrowserSignResponse>>>,\n    /// Unique session token for the wallet browser instance.\n    /// The CSP on the served page prevents this token from being loaded by other origins.\n    session_token: String,\n    /// If true, the server is running in development mode.\n    /// This relaxes certain security restrictions for local development.\n    ///\n    /// **WARNING**: This should only be used in a development environment.\n    development: bool,\n}\n\nimpl<N: Network> BrowserWalletState<N> {\n    /// Create a new browser wallet state.\n    pub fn new(session_token: String, development: bool) -> Self {\n        Self {\n            connection: Arc::new(RwLock::new(None)),\n            transactions: Arc::new(Mutex::new(RequestQueue::new())),\n            signings: Arc::new(Mutex::new(RequestQueue::new())),\n            session_token,\n            development,\n        }\n    }\n\n    /// Get the session token.\n    pub fn session_token(&self) -> &str {\n        &self.session_token\n    }\n\n    /// Check if in development mode.\n    /// This relaxes certain security restrictions for local development.\n    ///\n    /// **WARNING**: This should only be used in a development environment.\n    pub fn is_development(&self) -> bool {\n        self.development\n    }\n\n    /// Check if wallet is connected.\n    pub async fn is_connected(&self) -> bool {\n        self.connection.read().await.is_some()\n    }\n\n    /// Get current connection information.\n    pub async fn get_connection(&self) -> Option<Connection> {\n        *self.connection.read().await\n    }\n\n    /// Set connection information.\n    pub async fn set_connection(&self, connection: Option<Connection>) {\n        *self.connection.write().await = connection;\n    }\n\n    /// Add a transaction request.\n    pub async fn add_transaction_request(&self, request: BrowserTransactionRequest<N>) {\n        self.transactions.lock().await.add_request(request);\n    }\n\n    /// Check if a transaction request exists.\n    pub async fn has_transaction_request(&self, id: &Uuid) -> bool {\n        self.transactions.lock().await.has_request(id)\n    }\n\n    /// Read the next transaction request.\n    pub async fn read_next_transaction_request(&self) -> Option<BrowserTransactionRequest<N>> {\n        self.transactions.lock().await.read_request().cloned()\n    }\n\n    // Remove a transaction request.\n    pub async fn remove_transaction_request(&self, id: &Uuid) {\n        self.transactions.lock().await.remove_request(id);\n    }\n\n    /// Add transaction response.\n    pub async fn add_transaction_response(&self, response: BrowserTransactionResponse) {\n        let id = response.id;\n        let mut transactions = self.transactions.lock().await;\n        transactions.add_response(id, response);\n        transactions.remove_request(&id);\n    }\n\n    /// Get transaction response, removing it from the queue.\n    pub async fn get_transaction_response(&self, id: &Uuid) -> Option<BrowserTransactionResponse> {\n        self.transactions.lock().await.get_response(id)\n    }\n\n    /// Add a signing request.\n    pub async fn add_signing_request(&self, request: BrowserSignRequest) {\n        self.signings.lock().await.add_request(request);\n    }\n\n    /// Check if a signing request exists.\n    pub async fn has_signing_request(&self, id: &Uuid) -> bool {\n        self.signings.lock().await.has_request(id)\n    }\n\n    /// Read the next signing request.\n    pub async fn read_next_signing_request(&self) -> Option<BrowserSignRequest> {\n        self.signings.lock().await.read_request().cloned()\n    }\n\n    /// Remove a signing request.\n    pub async fn remove_signing_request(&self, id: &Uuid) {\n        self.signings.lock().await.remove_request(id);\n    }\n\n    /// Add signing response.\n    pub async fn add_signing_response(&self, response: BrowserSignResponse) {\n        let id = response.id;\n        let mut signings = self.signings.lock().await;\n        signings.add_response(id, response);\n        signings.remove_request(&id);\n    }\n\n    /// Get signing response, removing it from the queue.\n    pub async fn get_signing_response(&self, id: &Uuid) -> Option<BrowserSignResponse> {\n        self.signings.lock().await.get_response(id)\n    }\n}\n"
  },
  {
    "path": "crates/wallets/src/wallet_browser/types.rs",
    "content": "use alloy_dyn_abi::TypedData;\nuse alloy_network::Network;\nuse alloy_primitives::{Address, Bytes, ChainId, TxHash};\nuse serde::{Deserialize, Serialize};\nuse uuid::Uuid;\n\n/// Response format for API endpoints.\n/// - `Ok(T)` serializes as: {\"status\":\"ok\",\"data\": ...}\n/// - `Ok(())` serializes as: {\"status\":\"ok\"}  (no data key)\n/// - `Error { message }` as: {\"status\":\"error\",\"message\":\"...\"}\n#[derive(Serialize, Deserialize, Debug)]\n#[serde(tag = \"status\", content = \"data\", rename_all = \"lowercase\")]\npub(crate) enum BrowserApiResponse<T = ()> {\n    Ok(T),\n    Error { message: String },\n}\n\nimpl BrowserApiResponse<()> {\n    /// Create a successful response with no data.\n    pub fn ok() -> Self {\n        Self::Ok(())\n    }\n}\n\nimpl<T> BrowserApiResponse<T> {\n    /// Create a successful response with the given data.\n    pub fn with_data(data: T) -> Self {\n        Self::Ok(data)\n    }\n\n    /// Create an error response with the given message.\n    pub fn error(msg: impl Into<String>) -> Self {\n        Self::Error { message: msg.into() }\n    }\n}\n\n/// Represents a transaction request sent to the browser wallet.\n#[derive(Debug, Clone, Serialize, Deserialize)]\n#[serde(deny_unknown_fields)]\npub struct BrowserTransactionRequest<N: Network> {\n    /// The unique identifier for the transaction.\n    pub id: Uuid,\n    /// The transaction request details.\n    pub request: N::TransactionRequest,\n}\n\n/// Represents a transaction response sent from the browser wallet.\n#[derive(Debug, Clone, Serialize, Deserialize)]\n#[serde(deny_unknown_fields)]\npub(crate) struct BrowserTransactionResponse {\n    /// The unique identifier for the transaction, must match the request ID sent earlier.\n    pub id: Uuid,\n    /// The transaction hash if the transaction was successful.\n    pub hash: Option<TxHash>,\n    /// The error message if the transaction failed.\n    pub error: Option<String>,\n}\n\n#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]\n#[serde(deny_unknown_fields)]\npub enum SignType {\n    /// Standard personal sign: `eth_sign` / `personal_sign`\n    PersonalSign,\n    /// EIP-712 typed data sign: `eth_signTypedData_v4`\n    SignTypedDataV4,\n}\n\n#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]\n#[serde(deny_unknown_fields)]\npub struct SignRequest {\n    /// The message to be signed.\n    pub message: String,\n    /// The address that should sign the message.\n    pub address: Address,\n}\n\n/// Represents a signing request sent to the browser wallet.\n#[derive(Debug, Clone, Serialize, Deserialize)]\n#[serde(deny_unknown_fields, rename_all = \"camelCase\")]\npub struct BrowserSignRequest {\n    /// The unique identifier for the signing request.\n    pub id: Uuid,\n    /// The type of signing operation.\n    pub sign_type: SignType,\n    /// The sign request details.\n    pub request: SignRequest,\n}\n\n/// Represents a typed data signing request sent to the browser wallet.\n#[derive(Debug, Clone, Serialize, Deserialize)]\n#[serde(deny_unknown_fields, rename_all = \"camelCase\")]\npub struct BrowserSignTypedDataRequest {\n    /// The unique identifier for the signing request.\n    pub id: Uuid,\n    /// The address that should sign the typed data.\n    pub address: Address,\n    /// The typed data to be signed.\n    pub typed_data: TypedData,\n}\n\n/// Represents a signing response sent from the browser wallet.\n#[derive(Debug, Clone, Serialize, Deserialize)]\n#[serde(deny_unknown_fields)]\npub(crate) struct BrowserSignResponse {\n    /// The unique identifier for the signing request, must match the request ID sent earlier.\n    pub id: Uuid,\n    /// The signature if the signing was successful.\n    pub signature: Option<Bytes>,\n    /// The error message if the signing failed.\n    pub error: Option<String>,\n}\n\n/// Represents an active connection to a browser wallet.\n#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]\npub struct Connection {\n    /// The address of the connected wallet.\n    pub address: Address,\n    /// The chain ID of the connected wallet.\n    pub chain_id: ChainId,\n}\n\nimpl Connection {\n    /// Create a new connection instance.\n    pub fn new(address: Address, chain_id: ChainId) -> Self {\n        Self { address, chain_id }\n    }\n}\n"
  },
  {
    "path": "crates/wallets/src/wallet_multi/mod.rs",
    "content": "use crate::{\n    BrowserWalletOpts,\n    signer::{PendingSigner, WalletSigner},\n    utils,\n    wallet_browser::signer::BrowserSigner,\n};\nuse alloy_network::Network;\nuse alloy_primitives::map::AddressHashMap;\nuse alloy_signer::Signer;\nuse clap::Parser;\nuse derive_builder::Builder;\nuse eyre::Result;\nuse foundry_config::Config;\nuse serde::Serialize;\nuse std::path::PathBuf;\n\n/// Container for multiple wallets.\n#[derive(Debug, Default)]\npub struct MultiWallet {\n    /// Vector of wallets that require an action to be unlocked.\n    /// Those are lazily unlocked on the first access of the signers.\n    pending_signers: Vec<PendingSigner>,\n    /// Contains unlocked signers.\n    signers: AddressHashMap<WalletSigner>,\n}\n\nimpl MultiWallet {\n    pub fn new(pending_signers: Vec<PendingSigner>, signers: Vec<WalletSigner>) -> Self {\n        let signers = signers.into_iter().map(|signer| (signer.address(), signer)).collect();\n        Self { pending_signers, signers }\n    }\n\n    fn maybe_unlock_pending(&mut self) -> Result<()> {\n        for pending in self.pending_signers.drain(..) {\n            let signer = pending.unlock()?;\n            self.signers.insert(signer.address(), signer);\n        }\n        Ok(())\n    }\n\n    pub fn signers(&mut self) -> Result<&AddressHashMap<WalletSigner>> {\n        self.maybe_unlock_pending()?;\n        Ok(&self.signers)\n    }\n\n    pub fn into_signers(mut self) -> Result<AddressHashMap<WalletSigner>> {\n        self.maybe_unlock_pending()?;\n        Ok(self.signers)\n    }\n\n    pub fn add_signer(&mut self, signer: WalletSigner) {\n        self.signers.insert(signer.address(), signer);\n    }\n}\n\n/// A macro that initializes multiple wallets\n///\n/// Should be used with a [`MultiWallet`] instance\nmacro_rules! create_hw_wallets {\n    ($self:ident, $create_signer:expr, $signers:ident) => {\n        let mut $signers = vec![];\n\n        if let Some(hd_paths) = &$self.hd_paths {\n            for path in hd_paths {\n                let hw = $create_signer(Some(path), 0).await?;\n                $signers.push(hw);\n            }\n        }\n\n        if let Some(mnemonic_indexes) = &$self.mnemonic_indexes {\n            for index in mnemonic_indexes {\n                let hw = $create_signer(None, *index).await?;\n                $signers.push(hw);\n            }\n        }\n\n        if $signers.is_empty() {\n            let hw = $create_signer(None, 0).await?;\n            $signers.push(hw);\n        }\n    };\n}\n\n/// The wallet options can either be:\n/// 1. Ledger\n/// 2. Trezor\n/// 3. Mnemonics (via file path)\n/// 4. Keystores (via file path)\n/// 5. Private Keys (cleartext in CLI)\n/// 6. Private Keys (interactively via secure prompt)\n/// 7. AWS KMS\n/// 8. Turnkey\n#[derive(Builder, Clone, Debug, Default, Serialize, Parser)]\n#[command(next_help_heading = \"Wallet options\", about = None, long_about = None)]\npub struct MultiWalletOpts {\n    /// Open an interactive prompt to enter your private key.\n    ///\n    /// Takes a value for the number of keys to enter.\n    #[arg(long, help_heading = \"Wallet options - raw\", default_value = \"0\", value_name = \"NUM\")]\n    pub interactives: u32,\n\n    /// Open an interactive prompt to enter your private key.\n    #[arg(long, short, help_heading = \"Wallet options - raw\", conflicts_with = \"interactives\")]\n    pub interactive: bool,\n\n    /// Use the provided private keys.\n    #[arg(long, help_heading = \"Wallet options - raw\", value_name = \"RAW_PRIVATE_KEYS\")]\n    #[builder(default = \"None\")]\n    pub private_keys: Option<Vec<String>>,\n\n    /// Use the provided private key.\n    #[arg(\n        long,\n        help_heading = \"Wallet options - raw\",\n        conflicts_with = \"private_keys\",\n        value_name = \"RAW_PRIVATE_KEY\"\n    )]\n    #[builder(default = \"None\")]\n    pub private_key: Option<String>,\n\n    /// Use the mnemonic phrases of mnemonic files at the specified paths.\n    #[arg(long, alias = \"mnemonic-paths\", help_heading = \"Wallet options - raw\")]\n    #[builder(default = \"None\")]\n    pub mnemonics: Option<Vec<String>>,\n\n    /// Use a BIP39 passphrases for the mnemonic.\n    #[arg(long, help_heading = \"Wallet options - raw\", value_name = \"PASSPHRASE\")]\n    #[builder(default = \"None\")]\n    pub mnemonic_passphrases: Option<Vec<String>>,\n\n    /// The wallet derivation path.\n    ///\n    /// Works with both --mnemonic-path and hardware wallets.\n    #[arg(\n        long = \"mnemonic-derivation-paths\",\n        alias = \"hd-paths\",\n        help_heading = \"Wallet options - raw\",\n        value_name = \"PATH\"\n    )]\n    #[builder(default = \"None\")]\n    pub hd_paths: Option<Vec<String>>,\n\n    /// Use the private key from the given mnemonic index.\n    ///\n    /// Can be used with --mnemonics, --ledger, --aws and --trezor.\n    #[arg(\n        long,\n        conflicts_with = \"hd_paths\",\n        help_heading = \"Wallet options - raw\",\n        default_value = \"0\",\n        value_name = \"INDEXES\"\n    )]\n    pub mnemonic_indexes: Option<Vec<u32>>,\n\n    /// Use the keystore by its filename in the given folder.\n    #[arg(\n        long = \"keystore\",\n        visible_alias = \"keystores\",\n        help_heading = \"Wallet options - keystore\",\n        value_name = \"PATHS\",\n        env = \"ETH_KEYSTORE\"\n    )]\n    #[builder(default = \"None\")]\n    pub keystore_paths: Option<Vec<String>>,\n\n    /// Use a keystore from the default keystores folder (~/.foundry/keystores) by its filename.\n    #[arg(\n        long = \"account\",\n        visible_alias = \"accounts\",\n        help_heading = \"Wallet options - keystore\",\n        value_name = \"ACCOUNT_NAMES\",\n        env = \"ETH_KEYSTORE_ACCOUNT\",\n        conflicts_with = \"keystore_paths\"\n    )]\n    #[builder(default = \"None\")]\n    pub keystore_account_names: Option<Vec<String>>,\n\n    /// The keystore password.\n    ///\n    /// Used with --keystore.\n    #[arg(\n        long = \"password\",\n        help_heading = \"Wallet options - keystore\",\n        requires = \"keystore_paths\",\n        value_name = \"PASSWORDS\"\n    )]\n    #[builder(default = \"None\")]\n    pub keystore_passwords: Option<Vec<String>>,\n\n    /// The keystore password file path.\n    ///\n    /// Used with --keystore.\n    #[arg(\n        long = \"password-file\",\n        help_heading = \"Wallet options - keystore\",\n        requires = \"keystore_paths\",\n        value_name = \"PATHS\",\n        env = \"ETH_PASSWORD\"\n    )]\n    #[builder(default = \"None\")]\n    pub keystore_password_files: Option<Vec<String>>,\n\n    /// Use a Ledger hardware wallet.\n    #[arg(long, short, help_heading = \"Wallet options - hardware wallet\")]\n    pub ledger: bool,\n\n    /// Use a Trezor hardware wallet.\n    #[arg(long, short, help_heading = \"Wallet options - hardware wallet\")]\n    pub trezor: bool,\n\n    /// Use AWS Key Management Service.\n    ///\n    /// Ensure either one of AWS_KMS_KEY_IDS (comma-separated) or AWS_KMS_KEY_ID environment\n    /// variables are set.\n    #[arg(long, help_heading = \"Wallet options - remote\", hide = !cfg!(feature = \"aws-kms\"))]\n    pub aws: bool,\n\n    /// Use Google Cloud Key Management Service.\n    ///\n    /// Ensure the following environment variables are set: GCP_PROJECT_ID, GCP_LOCATION,\n    /// GCP_KEY_RING, GCP_KEY_NAME, GCP_KEY_VERSION.\n    ///\n    /// See: <https://cloud.google.com/kms/docs>\n    #[arg(long, help_heading = \"Wallet options - remote\", hide = !cfg!(feature = \"gcp-kms\"))]\n    pub gcp: bool,\n\n    /// Use Turnkey.\n    ///\n    /// Ensure the following environment variables are set: TURNKEY_API_PRIVATE_KEY,\n    /// TURNKEY_ORGANIZATION_ID, TURNKEY_ADDRESS.\n    ///\n    /// See: <https://docs.turnkey.com/getting-started/quickstart>\n    #[arg(long, help_heading = \"Wallet options - remote\", hide = !cfg!(feature = \"turnkey\"))]\n    pub turnkey: bool,\n\n    /// Browser wallet options\n    #[command(flatten)]\n    pub browser: BrowserWalletOpts,\n}\n\nimpl MultiWalletOpts {\n    /// Returns [MultiWallet] container configured with provided options.\n    pub async fn get_multi_wallet(&self) -> Result<MultiWallet> {\n        let mut pending = Vec::new();\n        let mut signers: Vec<WalletSigner> = Vec::new();\n\n        if let Some(ledgers) = self.ledgers().await? {\n            signers.extend(ledgers);\n        }\n        if let Some(trezors) = self.trezors().await? {\n            signers.extend(trezors);\n        }\n        if let Some(aws_signers) = self.aws_signers().await? {\n            signers.extend(aws_signers);\n        }\n        if let Some(gcp_signer) = self.gcp_signers().await? {\n            signers.extend(gcp_signer);\n        }\n        if let Some(turnkey_signers) = self.turnkey_signers()? {\n            signers.extend(turnkey_signers);\n        }\n        if let Some((pending_keystores, unlocked)) = self.keystores()? {\n            pending.extend(pending_keystores);\n            signers.extend(unlocked);\n        }\n        if let Some(pks) = self.private_keys()? {\n            signers.extend(pks);\n        }\n        if let Some(mnemonics) = self.mnemonics()? {\n            signers.extend(mnemonics);\n        }\n        if self.interactive {\n            pending.push(PendingSigner::Interactive);\n        }\n        if self.interactives > 0 {\n            pending.extend(std::iter::repeat_n(\n                PendingSigner::Interactive,\n                self.interactives as usize,\n            ));\n        }\n\n        Ok(MultiWallet::new(pending, signers))\n    }\n\n    pub fn private_keys(&self) -> Result<Option<Vec<WalletSigner>>> {\n        let mut pks = vec![];\n        if let Some(private_key) = &self.private_key {\n            pks.push(private_key);\n        }\n        if let Some(private_keys) = &self.private_keys {\n            for pk in private_keys {\n                pks.push(pk);\n            }\n        }\n        if !pks.is_empty() {\n            let wallets = pks\n                .into_iter()\n                .map(|pk| utils::create_private_key_signer(pk))\n                .collect::<Result<Vec<_>>>()?;\n            Ok(Some(wallets))\n        } else {\n            Ok(None)\n        }\n    }\n\n    fn keystore_paths(&self) -> Result<Option<Vec<PathBuf>>> {\n        if let Some(keystore_paths) = &self.keystore_paths {\n            return Ok(Some(keystore_paths.iter().map(PathBuf::from).collect()));\n        }\n        if let Some(keystore_account_names) = &self.keystore_account_names {\n            let default_keystore_dir = Config::foundry_keystores_dir()\n                .ok_or_else(|| eyre::eyre!(\"Could not find the default keystore directory.\"))?;\n            return Ok(Some(\n                keystore_account_names\n                    .iter()\n                    .map(|keystore_name| default_keystore_dir.join(keystore_name))\n                    .collect(),\n            ));\n        }\n        Ok(None)\n    }\n\n    /// Returns all wallets read from the provided keystores arguments\n    ///\n    /// Returns `Ok(None)` if no keystore provided.\n    pub fn keystores(&self) -> Result<Option<(Vec<PendingSigner>, Vec<WalletSigner>)>> {\n        if let Some(keystore_paths) = self.keystore_paths()? {\n            let mut pending = Vec::new();\n            let mut signers = Vec::new();\n\n            let mut passwords_iter =\n                self.keystore_passwords.iter().flat_map(|passwords| passwords.iter());\n\n            let mut password_files_iter = self\n                .keystore_password_files\n                .iter()\n                .flat_map(|password_files| password_files.iter());\n\n            for path in &keystore_paths {\n                let (maybe_signer, maybe_pending) = utils::create_keystore_signer(\n                    path,\n                    passwords_iter.next().map(|password| password.as_str()),\n                    password_files_iter.next().map(|password_file| password_file.as_str()),\n                )?;\n                if let Some(pending_signer) = maybe_pending {\n                    pending.push(pending_signer);\n                } else if let Some(signer) = maybe_signer {\n                    signers.push(signer);\n                }\n            }\n            return Ok(Some((pending, signers)));\n        }\n        Ok(None)\n    }\n\n    pub fn mnemonics(&self) -> Result<Option<Vec<WalletSigner>>> {\n        if let Some(ref mnemonics) = self.mnemonics {\n            let mut wallets = vec![];\n\n            let mut hd_paths_iter =\n                self.hd_paths.iter().flat_map(|paths| paths.iter().map(String::as_str));\n\n            let mut passphrases_iter = self\n                .mnemonic_passphrases\n                .iter()\n                .flat_map(|passphrases| passphrases.iter().map(String::as_str));\n\n            let mut indexes_iter =\n                self.mnemonic_indexes.iter().flat_map(|indexes| indexes.iter().copied());\n\n            for mnemonic in mnemonics {\n                let wallet = utils::create_mnemonic_signer(\n                    mnemonic,\n                    passphrases_iter.next(),\n                    hd_paths_iter.next(),\n                    indexes_iter.next().unwrap_or(0),\n                )?;\n                wallets.push(wallet);\n            }\n            return Ok(Some(wallets));\n        }\n        Ok(None)\n    }\n\n    pub async fn ledgers(&self) -> Result<Option<Vec<WalletSigner>>> {\n        if self.ledger {\n            let mut args = self.clone();\n\n            if let Some(paths) = &args.hd_paths {\n                if paths.len() > 1 {\n                    eyre::bail!(\"Ledger only supports one signer.\");\n                }\n                args.mnemonic_indexes = None;\n            }\n\n            create_hw_wallets!(args, utils::create_ledger_signer, wallets);\n            return Ok(Some(wallets));\n        }\n        Ok(None)\n    }\n\n    pub async fn trezors(&self) -> Result<Option<Vec<WalletSigner>>> {\n        if self.trezor {\n            let mut args = self.clone();\n\n            if args.hd_paths.is_some() {\n                args.mnemonic_indexes = None;\n            }\n\n            create_hw_wallets!(args, utils::create_trezor_signer, wallets);\n            return Ok(Some(wallets));\n        }\n        Ok(None)\n    }\n\n    pub async fn aws_signers(&self) -> Result<Option<Vec<WalletSigner>>> {\n        #[cfg(feature = \"aws-kms\")]\n        if self.aws {\n            let mut wallets = vec![];\n            let aws_keys = std::env::var(\"AWS_KMS_KEY_IDS\")\n                .or(std::env::var(\"AWS_KMS_KEY_ID\"))?\n                .split(',')\n                .map(|k| k.to_string())\n                .collect::<Vec<_>>();\n\n            for key in aws_keys {\n                let aws_signer = WalletSigner::from_aws(key).await?;\n                wallets.push(aws_signer)\n            }\n\n            return Ok(Some(wallets));\n        }\n\n        Ok(None)\n    }\n\n    /// Returns a list of GCP signers if the GCP flag is set.\n    ///\n    /// The GCP signers are created from the following environment variables:\n    /// - GCP_PROJECT_ID: The GCP project ID. e.g. `my-project-123456`.\n    /// - GCP_LOCATION: The GCP location. e.g. `us-central1`.\n    /// - GCP_KEY_RING: The GCP key ring name. e.g. `my-key-ring`.\n    /// - GCP_KEY_NAME: The GCP key name. e.g. `my-key`.\n    /// - GCP_KEY_VERSION: The GCP key version. e.g. `1`.\n    ///\n    /// For more information on GCP KMS, see the [official documentation](https://cloud.google.com/kms/docs).\n    pub async fn gcp_signers(&self) -> Result<Option<Vec<WalletSigner>>> {\n        #[cfg(feature = \"gcp-kms\")]\n        if self.gcp {\n            let mut wallets = vec![];\n\n            let project_id = std::env::var(\"GCP_PROJECT_ID\")?;\n            let location = std::env::var(\"GCP_LOCATION\")?;\n            let key_ring = std::env::var(\"GCP_KEY_RING\")?;\n            let key_name = std::env::var(\"GCP_KEY_NAME\")?;\n            let key_version = std::env::var(\"GCP_KEY_VERSION\")?;\n\n            let gcp_signer = WalletSigner::from_gcp(\n                project_id,\n                location,\n                key_ring,\n                key_name,\n                key_version.parse()?,\n            )\n            .await?;\n            wallets.push(gcp_signer);\n\n            return Ok(Some(wallets));\n        }\n\n        Ok(None)\n    }\n\n    pub fn turnkey_signers(&self) -> Result<Option<Vec<WalletSigner>>> {\n        #[cfg(feature = \"turnkey\")]\n        if self.turnkey {\n            let api_private_key = std::env::var(\"TURNKEY_API_PRIVATE_KEY\")?;\n            let organization_id = std::env::var(\"TURNKEY_ORGANIZATION_ID\")?;\n            let address = std::env::var(\"TURNKEY_ADDRESS\")?.parse()?;\n\n            let signer = WalletSigner::from_turnkey(api_private_key, organization_id, address)?;\n            return Ok(Some(vec![signer]));\n        }\n\n        Ok(None)\n    }\n\n    /// Returns the Turnkey address if `--turnkey` flag is set and `TURNKEY_ADDRESS` is available.\n    pub fn turnkey_address(&self) -> Option<alloy_primitives::Address> {\n        #[cfg(feature = \"turnkey\")]\n        if self.turnkey {\n            return std::env::var(\"TURNKEY_ADDRESS\").ok().and_then(|addr| addr.parse().ok());\n        }\n\n        None\n    }\n\n    /// Launches and returns the Browser signer if `--browser` flag is set\n    pub async fn browser_signer<N: Network>(&self) -> Result<Option<BrowserSigner<N>>> {\n        self.browser.run().await\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use alloy_primitives::address;\n    use std::path::Path;\n\n    #[test]\n    fn parse_keystore_args() {\n        let args: MultiWalletOpts =\n            MultiWalletOpts::parse_from([\"foundry-cli\", \"--keystores\", \"my/keystore/path\"]);\n        assert_eq!(args.keystore_paths, Some(vec![\"my/keystore/path\".to_string()]));\n\n        unsafe {\n            std::env::set_var(\"ETH_KEYSTORE\", \"MY_KEYSTORE\");\n        }\n        let args: MultiWalletOpts = MultiWalletOpts::parse_from([\"foundry-cli\"]);\n        assert_eq!(args.keystore_paths, Some(vec![\"MY_KEYSTORE\".to_string()]));\n\n        unsafe {\n            std::env::remove_var(\"ETH_KEYSTORE\");\n        }\n    }\n\n    #[test]\n    fn parse_keystore_password_file() {\n        let keystore =\n            Path::new(concat!(env!(\"CARGO_MANIFEST_DIR\"), \"/../cast/tests/fixtures/keystore\"));\n        let keystore_file = keystore\n            .join(\"UTC--2022-12-20T10-30-43.591916000Z--ec554aeafe75601aaab43bd4621a22284db566c2\");\n\n        let keystore_password_file = keystore.join(\"password-ec554\").into_os_string();\n\n        let args: MultiWalletOpts = MultiWalletOpts::parse_from([\n            \"foundry-cli\",\n            \"--keystores\",\n            keystore_file.to_str().unwrap(),\n            \"--password-file\",\n            keystore_password_file.to_str().unwrap(),\n        ]);\n        assert_eq!(\n            args.keystore_password_files,\n            Some(vec![keystore_password_file.to_str().unwrap().to_string()])\n        );\n\n        let (_, unlocked) = args.keystores().unwrap().unwrap();\n        assert_eq!(unlocked.len(), 1);\n        assert_eq!(unlocked[0].address(), address!(\"0xec554aeafe75601aaab43bd4621a22284db566c2\"));\n    }\n\n    // https://github.com/foundry-rs/foundry/issues/12916\n    #[test]\n    #[cfg(feature = \"turnkey\")]\n    fn turnkey_address_returns_address_when_flag_set() {\n        let args: MultiWalletOpts = MultiWalletOpts::parse_from([\"foundry-cli\", \"--turnkey\"]);\n        assert!(args.turnkey);\n\n        unsafe {\n            std::env::set_var(\"TURNKEY_ADDRESS\", \"0x1234567890123456789012345678901234567890\");\n        }\n\n        let addr = args.turnkey_address();\n        assert_eq!(addr, Some(address!(\"0x1234567890123456789012345678901234567890\")));\n\n        unsafe {\n            std::env::remove_var(\"TURNKEY_ADDRESS\");\n        }\n    }\n\n    #[test]\n    fn turnkey_address_returns_none_when_flag_not_set() {\n        let args: MultiWalletOpts = MultiWalletOpts::parse_from([\"foundry-cli\"]);\n        assert!(!args.turnkey);\n\n        unsafe {\n            std::env::set_var(\"TURNKEY_ADDRESS\", \"0x1234567890123456789012345678901234567890\");\n        }\n\n        let addr = args.turnkey_address();\n        assert_eq!(addr, None);\n\n        unsafe {\n            std::env::remove_var(\"TURNKEY_ADDRESS\");\n        }\n    }\n\n    // https://github.com/foundry-rs/foundry/issues/5179\n    #[test]\n    fn should_not_require_the_mnemonics_flag_with_mnemonic_indexes() {\n        let wallet_options = vec![\n            (\"ledger\", \"--mnemonic-indexes\", 1),\n            (\"trezor\", \"--mnemonic-indexes\", 2),\n            (\"aws\", \"--mnemonic-indexes\", 10),\n            (\"turnkey\", \"--mnemonic-indexes\", 11),\n        ];\n\n        for test_case in wallet_options {\n            let args: MultiWalletOpts = MultiWalletOpts::parse_from([\n                \"foundry-cli\",\n                &format!(\"--{}\", test_case.0),\n                test_case.1,\n                &test_case.2.to_string(),\n            ]);\n\n            match test_case.0 {\n                \"ledger\" => assert!(args.ledger),\n                \"trezor\" => assert!(args.trezor),\n                \"aws\" => assert!(args.aws),\n                \"turnkey\" => assert!(args.turnkey),\n                _ => panic!(\"Should have matched one of the previous wallet options\"),\n            }\n\n            assert_eq!(\n                args.mnemonic_indexes.expect(\"--mnemonic-indexes should have been set\")[0],\n                test_case.2\n            )\n        }\n    }\n}\n"
  },
  {
    "path": "crates/wallets/src/wallet_raw/mod.rs",
    "content": "use crate::{PendingSigner, WalletSigner, utils};\nuse clap::Parser;\nuse eyre::Result;\nuse serde::Serialize;\n\n/// A wrapper for the raw data options for `Wallet`, extracted to also be used standalone.\n/// The raw wallet options can either be:\n/// 1. Private Key (cleartext in CLI)\n/// 2. Private Key (interactively via secure prompt)\n/// 3. Mnemonic (via file path)\n#[derive(Clone, Debug, Default, Serialize, Parser)]\n#[command(next_help_heading = \"Wallet options - raw\", about = None, long_about = None)]\npub struct RawWalletOpts {\n    /// Open an interactive prompt to enter your private key.\n    #[arg(long, short)]\n    pub interactive: bool,\n\n    /// Use the provided private key.\n    #[arg(long, value_name = \"RAW_PRIVATE_KEY\")]\n    pub private_key: Option<String>,\n\n    /// Use the mnemonic phrase of mnemonic file at the specified path.\n    #[arg(long, alias = \"mnemonic-path\")]\n    pub mnemonic: Option<String>,\n\n    /// Use a BIP39 passphrase for the mnemonic.\n    #[arg(long, value_name = \"PASSPHRASE\")]\n    pub mnemonic_passphrase: Option<String>,\n\n    /// The wallet derivation path.\n    ///\n    /// Works with both --mnemonic-path and hardware wallets.\n    #[arg(long = \"mnemonic-derivation-path\", alias = \"hd-path\", value_name = \"PATH\")]\n    pub hd_path: Option<String>,\n\n    /// Use the private key from the given mnemonic index.\n    ///\n    /// Used with --mnemonic-path.\n    #[arg(long, conflicts_with = \"hd_path\", default_value_t = 0, value_name = \"INDEX\")]\n    pub mnemonic_index: u32,\n}\n\nimpl RawWalletOpts {\n    /// Returns signer configured by provided parameters.\n    pub fn signer(&self) -> Result<Option<WalletSigner>> {\n        if self.interactive {\n            return Ok(Some(PendingSigner::Interactive.unlock()?));\n        }\n        if let Some(private_key) = &self.private_key {\n            return Ok(Some(utils::create_private_key_signer(private_key)?));\n        }\n        if let Some(mnemonic) = &self.mnemonic {\n            return Ok(Some(utils::create_mnemonic_signer(\n                mnemonic,\n                self.mnemonic_passphrase.as_deref(),\n                self.hd_path.as_deref(),\n                self.mnemonic_index,\n            )?));\n        }\n        Ok(None)\n    }\n}\n"
  },
  {
    "path": "deny.toml",
    "content": "# This section is considered when running `cargo deny check advisories`\n# More documentation for the advisories section can be found here:\n# https://embarkstudios.github.io/cargo-deny/checks/advisories/cfg.html\n[advisories]\nversion = 2\nyanked = \"warn\"\nignore = [\n    # https://rustsec.org/advisories/RUSTSEC-2024-0436 paste! is unmaintained\n    \"RUSTSEC-2024-0436\",\n    # https://rustsec.org/advisories/RUSTSEC-2025-0141 bincode is unmaintained\n    \"RUSTSEC-2025-0141\",\n]\n\n# This section is considered when running `cargo deny check bans`.\n# More documentation about the 'bans' section can be found here:\n# https://embarkstudios.github.io/cargo-deny/checks/bans/cfg.html\n[bans]\n# Lint level for when multiple versions of the same crate are detected\nmultiple-versions = \"allow\"\n# Lint level for when a crate version requirement is `*`\nwildcards = \"allow\"\nhighlight = \"all\"\n# List of crates to deny\ndeny = [{ name = \"openssl\" }]\n# Certain crates/versions that will be skipped when doing duplicate detection.\nskip = []\n# Similarly to `skip` allows you to skip certain crates during duplicate\n# detection. Unlike skip, it also includes the entire tree of transitive\n# dependencies starting at the specified crate, up to a certain depth, which is\n# by default infinite\nskip-tree = []\n\n[licenses]\nversion = 2\nconfidence-threshold = 0.8\n\n# List of explicitly allowed licenses\n# See https://spdx.org/licenses/ for list of possible licenses\n# [possible values: any SPDX 3.7 short identifier (+ optional exception)].\nallow = [\n    \"0BSD\",\n    \"Apache-2.0 WITH LLVM-exception\",\n    \"Apache-2.0\",\n    \"BSD-2-Clause\",\n    \"BSD-3-Clause\",\n    \"BSL-1.0\",\n    \"CC0-1.0\",\n    \"CDDL-1.0\",\n    \"CDLA-Permissive-2.0\",\n    \"ISC\",\n    \"MIT\",\n    \"MPL-2.0\",\n    \"OpenSSL\",\n    \"Unicode-3.0\",\n    \"Unlicense\",\n    \"WTFPL\",\n    \"Zlib\",\n]\n\n# Allow 1 or more licenses on a per-crate basis, so that particular licenses\n# aren't accepted for every possible crate as with the normal allow list\nexceptions = [\n    # CC0 is a permissive license but somewhat unclear status for source code\n    # so we prefer to not have dependencies using it\n    # https://tldrlegal.com/license/creative-commons-cc0-1.0-universal\n    { allow = [\"CC0-1.0\"], name = \"trezor-client\" },\n    { allow = [\"CC0-1.0\"], name = \"notify\" },\n    { allow = [\"CC0-1.0\"], name = \"dunce\" },\n    { allow = [\"CC0-1.0\"], name = \"aurora-engine-modexp\" },\n    # Rendered mdBook HTML source code includes attribution as required by CC-BY-4.0\n    { allow = [\"CC-BY-4.0\", \"MIT\"], name = \"font-awesome-as-a-crate\" },\n]\n# copyleft = \"deny\"\n\n# See note in unicode-ident's readme!\n[[licenses.clarify]]\nname = \"unicode-ident\"\nversion = \"*\"\nexpression = \"(MIT OR Apache-2.0) AND Unicode-DFS-2016\"\nlicense-files = [{ path = \"LICENSE-UNICODE\", hash = 0x3fb01745 }]\n\n[[licenses.clarify]]\nname = \"ring\"\nversion = \"*\"\nexpression = \"OpenSSL\"\nlicense-files = [{ path = \"LICENSE\", hash = 0xbd0eed23 }]\n\n# This section is considered when running `cargo deny check sources`.\n# More documentation about the 'sources' section can be found here:\n# https://embarkstudios.github.io/cargo-deny/checks/sources/cfg.html\n[sources]\n# Lint level for what to happen when a crate from a crate registry that is not\n# in the allow list is encountered\nunknown-registry = \"warn\"\n# Lint level for what to happen when a crate from a git repository that is not\n# in the allow list is encountered\nunknown-git = \"deny\"\nallow-git = [\n    \"https://github.com/alloy-rs/alloy\",\n    \"https://github.com/alloy-rs/evm\",\n    \"https://github.com/foundry-rs/compilers\",\n    \"https://github.com/foundry-rs/foundry-fork-db\",\n    \"https://github.com/foundry-rs/optimism\",\n    \"https://github.com/paradigmxyz/revm-inspectors\",\n    \"https://github.com/paradigmxyz/solar\",\n    \"https://github.com/bluealloy/revm\",\n    # Only for tests.\n    \"https://github.com/rust-cli/rexpect\",\n    # Tempo\n    \"https://github.com/tempoxyz/tempo\",\n    # Transitive dependency of Tempo\n    \"https://github.com/paradigmxyz/reth\",\n]\n"
  },
  {
    "path": "docs/dev/README.md",
    "content": "# Developer Docs\n\nThe Foundry project is organized as a regular [Cargo workspace][cargo-workspace].\n\n## Installation requirements\n\n- [Rust](https://rustup.rs/)\n- Make\n\nWe use `cargo-nextest` as test runner (both locally and in the [CI](#ci)):\n\n- [Nextest](https://nexte.st/docs/installation/pre-built-binaries/#with-cargo-binstall)\n\n## Recommended\n\nIf you are working in VSCode, we recommend you install the [rust-analyzer](https://rust-analyzer.github.io/) extension, and use the following VSCode user settings:\n\n```json\n\"editor.formatOnSave\": true,\n\"rust-analyzer.rustfmt.extraArgs\": [\"+nightly\"],\n\"[rust]\": {\n  \"editor.defaultFormatter\": \"rust-lang.rust-analyzer\"\n}\n```\n\nNote that we use Rust's latest `nightly` for formatting. If you see `;` being inserted by your code editor it is a good indication you are on `stable`.\n\n## Getting started\n\nBuild the project.\n\n```sh\n$ make build\n```\n\nRun all tests.\n\n```sh\n$ make test\n```\n\nRun all tests and linters in preparation for a PR.\n\n```sh\n$ make pr\n```\n\n## Contents\n\n- [Architecture](./architecture.md)\n- [Cheatcodes](./cheatcodes.md)\n- [Debugging](./debugging.md)\n- [Scripting](./scripting.md)\n- [Custom Network Features](./networks.md)\n\n_Note: This is incomplete and possibly outdated_\n\n## Getting in Touch\n\nSee also [Getting Help](../../README.md#getting-help)\n\n## Issue Labels\n\nWhenever a ticket is initially opened a [`T-needs-triage`](https://github.com/foundry-rs/foundry/issues?q=is%3Aissue+is%3Aopen+label%3AT-needs-triage) label is assigned. This means that a member has yet to correctly label it.\n\nIf this is your first time contributing have a look at our [`first-issue`](https://github.com/foundry-rs/foundry/issues?q=is%3Aissue+is%3Aopen+label%3A%22first+issue%22) tickets. These are tickets we think are a good way to get familiar with the codebase.\n\nWe classify the tickets in two major categories: [`T-feature`](https://github.com/foundry-rs/foundry/issues?q=is%3Aissue+is%3Aopen+label%3AT-feature) and [`T-bug`](https://github.com/foundry-rs/foundry/issues?q=is%3Aissue+is%3Aopen+label%3AT-bug). Additional labels are usually applied to help categorize the ticket for future reference.\n\nWe also make use of [`T-meta`](https://github.com/foundry-rs/foundry/issues?q=is%3Aissue+is%3Aopen+label%3AT-meta) aggregation tickets. These tickets are tickets to collect related features and bugs.\n\nWe also have [`T-discuss`](https://github.com/foundry-rs/foundry/issues?q=is%3Aissue+is%3Aopen+label%3AT-to-discuss) tickets that require further discussion before proceeding on an implementation. Feel free to jump into the conversation!\n\n## CI\n\nWe use GitHub Actions for continuous integration (CI).\n\nWe use [cargo-nextest][nextest] as the test runner.\n\nIf `make test` passes locally, that's a good sign that CI will be green as well.\n\n## Release Features\n\nNightly/stable release builds derive their enabled functionality from the shared `RUST_FEATURES` environment variable in `.github/workflows/release.yml` and `.github/workflows/docker-publish.yml`. Keep that list aligned with the default `FEATURES` value in the root `Makefile` so published artifacts expose the same CLI surface area (wallet backends, allocators, tracers, etc.) as local builds.\n\n[foundry-book]: https://book.getfoundry.sh\n[cargo-workspace]: https://doc.rust-lang.org/book/ch14-03-cargo-workspaces.html\n[nextest]: https://nexte.st/\n"
  },
  {
    "path": "docs/dev/architecture.md",
    "content": "# Architecture\n\nThis document describes the high-level architecture of Foundry.\n\n### `evm/`\n\nFoundry's EVM tooling. This is built around [`revm`](https://github.com/bluealloy/revm) and has additional\nimplementation of:\n\n- [cheatcodes](./cheatcodes.md) a set of solidity calls dedicated to testing which can manipulate the environment in which the execution is run\n\n### `config/`\n\nIncludes all of Foundry's settings and how to get them\n\n### `cli/`\n\nThe core `forge` and `cast` cli implementation. Includes all subcommands.\n"
  },
  {
    "path": "docs/dev/cheatcodes.md",
    "content": "# Cheatcodes\n\nFoundry's EVM support is mainly dedicated to testing and exploration, it features a set of cheatcodes which can\nmanipulate the environment in which the execution is run.\n\nMost of the time, simply testing your smart contracts outputs isn't enough. To manipulate the state of the EVM, as well\nas test for specific reverts and events, Foundry is shipped with a set of cheatcodes.\n\n## [`revm::Inspector`](https://docs.rs/revm/latest/revm/trait.Inspector.html)\n\nTo understand how cheatcodes are implemented, we first need to look at [`revm::Inspector`](https://docs.rs/revm/latest/revm/trait.Inspector.html),\na trait that provides a set of callbacks to be notified at certain stages of EVM execution.\n\nFor example, [`Inspector::call`](https://docs.rs/revm/latest/revm/trait.Inspector.html#method.call)\nis called when the EVM is about to execute a call and is provided with the call's inputs and the\ncurrent state of the EVM.\n\n## [Foundry inspectors](../../crates/evm/evm/src/inspectors/)\n\nThe [`evm`](../../crates/evm/evm/) crate has a variety of inspectors for different use cases, such as\n\n- coverage\n- tracing\n- debugger\n- logging\n\n## [Cheatcode inspector](../../crates/cheatcodes/src/inspector.rs)\n\nThe concept of cheatcodes and cheatcode inspector is very simple.\n\nCheatcodes are calls to a specific address, the cheatcode handler address, defined as\n`address(uint160(uint256(keccak256(\"hevm cheat code\"))))` (`0x7109709ECfa91a80626fF3989D68f67F5b1DD12D`).\n\nIn Solidity, this can be initialized as `Vm constant vm = Vm(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D);`,\nbut generally this is inherited from `forge-std/Test.sol`.\n\nSince cheatcodes are bound to a constant address, the cheatcode inspector listens for that address:\n\n```rust\nimpl Inspector for Cheatcodes {\n    fn call(&mut self, ...) -> ... {\n        if call.contract == CHEATCODE_ADDRESS {\n            // intercepted cheatcode call\n            // --snip--\n        }\n    }\n}\n```\n\nWhen a call to a cheatcode is intercepted we try to decode the calldata into a known cheatcode.\n\nRust bindings for the cheatcode interface are generated via the [Alloy](https://github.com/alloy-rs) [`sol!`](https://docs.rs/alloy-sol-macro/latest/alloy_sol_macro/macro.sol.html) macro.\n\nIf a call was successfully decoded into the `VmCalls` enum that the `sol!` macro generates, the\nlast step is a large `match` over the decoded function call structs, which serves as the\nimplementation handler for the cheatcode. This is also automatically generated, in part, by the\n`sol!` macro, through the use of a custom internal derive procedural macro.\n\n## Cheatcodes implementation\n\nAll the cheatcodes are defined in a large [`sol!`] macro call in [`cheatcodes/spec/src/vm.rs`]:\n\n```rust\nsol! {\n#[derive(Cheatcode)]\ninterface Vm {\n    //  ======== Types ========\n\n    /// Error thrown by a cheatcode.\n    error CheatcodeError(string message);\n\n    // ...\n\n    // ======== EVM ========\n\n    /// Gets the address for a given private key.\n    #[cheatcode(group = Evm, safety = Safe)]\n    function addr(uint256 privateKey) external pure returns (address keyAddr);\n\n    /// Gets the nonce of an account.\n    #[cheatcode(group = Evm, safety = Safe)]\n    function getNonce(address account) external view returns (uint64 nonce);\n\n    // ...\n}\n}\n```\n\nThis, combined with the use of an internal [`Cheatcode` derive macro](#cheatcode-derive-macro),\nallows us to generate both the Rust definitions and the JSON specification of the cheatcodes.\n\nCheatcodes are manually implemented through the [`Cheatcode` trait](#cheatcode-trait), which is\ncalled in the [`Cheatcodes` inspector](#cheatcode-inspector) implementation.\n\n### [`sol!`]\n\nGenerates the raw Rust bindings for the cheatcodes, as well as lets us specify custom attributes\nindividually for each item, such as functions and structs, or for entire interfaces.\n\nThe way bindings are generated and extra information can be found in the [`sol!`] documentation.\n\nWe leverage this macro to apply the [`Cheatcode` derive macro](#cheatcode-derive-macro) on the `Vm` interface.\n\n### [`Cheatcode`](../../crates/macros/src/cheatcodes.rs) derive macro\n\nThis is derived once on the `Vm` interface declaration, which recursively applies it to all of the\ninterface's items, as well as the `sol!`-generated items, such as the `VmCalls` enum.\n\nThis macro performs extra checks on functions and structs at compile time to make sure they are\ndocumented and have named parameters, and generates a macro which is later used to implement the\n`match { ... }` function that is to be used to dispatch the cheatcode implementations after a call is\ndecoded.\n\nThe latter is what fails compilation when adding a new cheatcode, and is fixed by implementing the\n[`Cheatcode` trait](#cheatcode-trait) to the newly-generated function call struct(s).\n\nThe `Cheatcode` derive macro also parses the `#[cheatcode(...)]` attributes on functions, which are\nused to specify additional properties of the JSON interface.\n\nThese are all the attributes that can be specified on cheatcode functions:\n\n- `#[cheatcode(group = <ident>)]`: The group that the cheatcode belongs to. Required.\n- `#[cheatcode(status = <ident>)]`: The current status of the cheatcode. E.g. whether it is stable or experimental, etc. Defaults to `Stable`.\n- `#[cheatcode(safety = <ident>)]`: Whether the cheatcode is safe to use inside of scripts. E.g. it does not change state in an unexpected way. Defaults to the group's safety if unspecified. If the group is ambiguous, then it must be specified manually.\n\nMultiple attributes can be specified by separating them with commas, e.g. `#[cheatcode(group = Evm, status = Experimental)]`.\n\n### `Cheatcode` trait\n\nThis trait defines the interface that all cheatcode implementations must implement.\nThere are three methods that can be implemented:\n\n| Method | Purpose | When to use |\n|--------|---------|-------------|\n| `apply` | Pure cheatcodes that don't need EVM data access | For simple state manipulations |\n| `apply_stateful` | Cheatcodes that need EVM data access | For operations requiring current EVM state |\n| `apply_full` | Cheatcodes that need EVM executor access | For operations requiring recursive EVM calls |\n\nOnly one of these methods can be implemented.\n\nThis trait is implemented manually for each cheatcode in the [`foundry-cheatcodes`](../../crates/cheatcodes/)\ncrate on the `sol!`-generated function call structs.\n\n### [JSON interface](../../crates/cheatcodes/assets/cheatcodes.json)\n\nThe [JSON interface](../../crates/cheatcodes/assets/cheatcodes.json) and [schema](../../crates/cheatcodes/assets/cheatcodes.schema.json)\nare automatically generated from the [`sol!` macro call](#sol) by running `cargo cheats`.\n\nThe initial execution of this command, following the addition of a new cheat code, will result in an\nupdate to the JSON files, which is expected to fail. This failure is necessary for the CI system to\ndetect that changes have occurred. Subsequent executions should pass, confirming the successful\nupdate of the files.\n\n### Adding a new cheatcode\n\n1. Add its Solidity definition(s) in [`cheatcodes/spec/src/vm.rs`]. Ensure that all structs and functions are documented, and that all function parameters are named. This will initially fail to compile because of the automatically generated `match { ... }` expression. This is expected, and will be fixed in the next step\n2. Implement the cheatcode in [`cheatcodes`] in its category's respective module. Follow the existing implementations as a guide.\n3. If a struct, enum, error, or event was added to `Vm`, update [`spec::Cheatcodes::new`]\n4. Update the JSON interface by running `cargo cheats` twice. This is expected to fail the first time that this is run after adding a new cheatcode; see [JSON interface](#json-interface)\n5. Write an integration test for the cheatcode in [`testdata/default/cheats/`]\n\n[`sol!`]: https://docs.rs/alloy-sol-macro/latest/alloy_sol_macro/macro.sol.html\n[`cheatcodes/spec/src/vm.rs`]: ../../crates/cheatcodes/spec/src/vm.rs\n[`cheatcodes`]: ../../crates/cheatcodes/\n[`spec::Cheatcodes::new`]: ../../crates/cheatcodes/spec/src/lib.rs#L74\n[`testdata/cheats/`]: ../../testdata/default/cheats/\n"
  },
  {
    "path": "docs/dev/debugging.md",
    "content": "# Debugging\n\nThis is a working document intended to outline some commands contributors can use to debug various parts of Foundry.\n\n## Logs\n\nAll crates use [tracing](https://docs.rs/tracing/latest/tracing/) for logging. A console formatter is installed in each binary (`cast`, `forge`, `anvil`).\n\nBy setting `RUST_LOG=<filter>` you can get a lot more info out of Forge and Cast. For example, running Forge with `RUST_LOG=forge` will emit all logs from the `forge` package, same for Cast with `RUST_LOG=cast`.\n\nThe most basic valid filter is a log level, of which these are valid:\n\n- `error`\n- `warn`\n- `info`\n- `debug`\n- `trace`\n\nFilters are explained in detail in the [`tracing-subscriber` crate docs](https://docs.rs/tracing-subscriber).\n\nYou can also use the `dbg!` macro from Rust's standard library.\n"
  },
  {
    "path": "docs/dev/lintrules.md",
    "content": "# Linter (`lint`)\n\nSolidity linter for identifying potential errors, vulnerabilities, gas optimizations, and style guide violations.\nIt helps enforce best practices and improve code quality within Foundry projects.\n\n## Architecture\n\nThe `forge-lint` system operates by analyzing Solidity source code through a dual-pass system:\n\n1. **Parsing**: Solidity source files are parsed into an Abstract Syntax Tree (AST) using `solar`. This AST represents the syntactic structure of the code.\n2. **HIR Generation**: The AST is then lowered into a High-level Intermediate Representation (HIR) that includes type information and semantic analysis.\n3. **Early Lint Passes**: The `EarlyLintVisitor` traverses the AST, invoking registered \"early lint passes\" (`EarlyLintPass` implementations) for syntax-level checks.\n4. **Late Lint Passes**: The `LateLintVisitor` traverses the HIR, invoking registered \"late lint passes\" (`LateLintPass` implementations) for semantic analysis.\n5. **Emitting Diagnostics**: If a lint pass identifies a violation, it uses the `LintContext` to emit a diagnostic (either `warning` or `note`) that pinpoints the issue. Lints can also provide code fix suggestions through the `Suggestion` API, which integrates with solar's diagnostic system to support different applicability levels.\n\n### Key Components\n\n- **`Linter` Trait**: Defines a generic interface for linters. `SolidityLinter` is the concrete implementation tailored for Solidity.\n- **`Lint` Trait & `SolLint` Struct**:\n  - `Lint`: A trait that defines the essential properties of a lint rule, such as its unique ID, severity, description, and an optional help message/URL.\n  - `SolLint`: A struct implementing the `Lint` trait, used to hold the metadata for each specific Solidity lint rule.\n- **`EarlyLintPass<'ast>` Trait**: Lints that operate directly on AST nodes implement this trait. It contains methods (like `check_expr`, `check_item_function`, etc.) called by the AST visitor.\n- **`LateLintPass<'hir>` Trait**: Lints that require type information and semantic analysis implement this trait. It contains methods (like `check_contract`, `check_function`, etc.) called by the HIR visitor.\n- **`LintContext<'s>`**: Provides contextual information to lint passes during execution, such as access to the session for emitting diagnostics and methods for emitting suggestions.\n- **`EarlyLintVisitor<'a, 's, 'ast>`**: The visitor that traverses the AST and dispatches checks to the registered `EarlyLintPass` instances.\n- **`LateLintVisitor<'a, 's, 'hir>`**: The visitor that traverses the HIR and dispatches checks to the registered `LateLintPass` instances.\n- **`Suggestion` Struct**: Represents code fix suggestions with different kinds (fix or example) and applicability levels, integrated with solar's diagnostic system.\n\n## Developing a new lint rule\n\nWe recommend you start by writing out some Solidity code that you want to trigger a lint in [`crates/lint/testdata`](https://github.com/foundry-rs/foundry/tree/master/crates/lint/testdata). Name the file after your lint rule.\n\nNext, choose whether you want an [early or late lint pass](#choosing-between-early-and-late-passes). If your lint is early, you can use use [Solar](https://github.com/paradigmxyz/solar) to dump the AST and find the patterns you need to match on in your lint code using `solar -Zdump=ast crates/lint/testdata/<file.sol>`. If your lint is late, you can use `solar -Zdump=hir crates/lint/testdata/<file.sol>`.\n\n1. Specify an issue that is being addressed in the PR description.\n2. In your PR:\n\n- Create a static `SolLint` instance using the `declare_forge_lint!` to define its metadata.\n  ```rust\n  declare_forge_lint!(\n      MIXED_CASE_FUNCTION,                      // The Rust identifier for this SolLint static\n      Severity::Info,                           // The default severity of the lint\n      \"mixed-case-function\",                    // A unique string ID for configuration/CLI\n      \"function names should use mixedCase\"     // A brief description\n  );\n  // Note: The macro automatically generates a help link to the Foundry book\n  ```\n\n- Register the pass struct and the lint using `register_lints!` in the `mod.rs` of its corresponding severity category. Specify the pass type (`early`, `late`, or both). Note that a single pass can handle multiple lints:\n  ```rust\n  register_lints!(\n    (PascalCaseStruct, early, (PASCAL_CASE_STRUCT)),\n    (MixedCaseVariable, early, (MIXED_CASE_VARIABLE)),\n    (MixedCaseFunction, early, (MIXED_CASE_FUNCTION)),\n    (ScreamingSnakeCase, early, (SCREAMING_SNAKE_CASE_CONSTANT, SCREAMING_SNAKE_CASE_IMMUTABLE)),\n    (AsmKeccak256, late, (ASM_KECCAK256))\n  );\n  // The macro automatically generates the pass structs and helper functions\n  ```\n\n- Implement the appropriate trait logic (`EarlyLintPass` or `LateLintPass`) for your lint. Do it in a new file within the relevant severity module (e.g., `src/sol/med/my_new_lint.rs`).\n\n### Choosing Between Early and Late Passes\n\n- **Use `EarlyLintPass`** for:\n  - Syntax-level checks (naming conventions, formatting)\n  - Simple pattern matching that doesn't require type information\n  - Lints that can be determined from the AST alone\n\n- **Use `LateLintPass`** for:\n  - Semantic analysis requiring type information\n  - Cross-reference checks between different parts of the code\n  - Complex patterns that need to understand the actual behavior\n  - Avoiding false positives through type-aware analysis\n\n### Providing Code Fix Suggestions\n\nLints can provide actionable code fix suggestions using the `emit_with_suggestion` method. The `Suggestion` API integrates with solar's diagnostic system and supports different applicability levels:\n\n```rust\nuse solar::interface::diagnostics::Applicability;\n\n// Example: Suggesting a machine-applicable fix\ncx.emit_with_suggestion(\n    lint,\n    node.span,\n    Suggestion::fix(\n        corrected_name,\n        Applicability::MachineApplicable,\n    )\n    .with_desc(\"consider using\")\n);\n\n// Example: Suggesting a fix with a specific span\ncx.emit_with_suggestion(\n    lint,\n    node.span,\n    Suggestion::fix(\n        optimized_code,\n        Applicability::MaybeIncorrect,\n    )\n    .with_desc(\"use inline assembly for gas optimization\")\n    .with_span(replacement_span)\n);\n\n// Example: Providing an example (non-applicable suggestion)\ncx.emit_with_suggestion(\n    lint,\n    node.span,\n    Suggestion::example(\"some example\")\n);\n```\n\n**Applicability Levels:**\n- `MachineApplicable`: The suggestion can be applied automatically with high confidence\n- `MaybeIncorrect`: The suggestion might not be correct in all cases and should be reviewed\n- `HasPlaceholders`: The suggestion contains placeholders that need to be filled in\n- `Unspecified`: No applicability specified\n\n3. Add comprehensive tests in `lint/testdata/`:\n   - Create `MyNewLint.sol` with various examples (triggering and non-triggering cases, edge cases).\n   - If your test requires imports, add those files under `lint/testdata/auxiliary/` so that the ui runner doesn't lint them.\n   - Generate the corresponding blessed file with the expected output.\n\n### Testing a lint rule\n\nTests are located in the `lint/testdata/` directory. A test for a lint rule involves:\n\n- A Solidity source file with various code snippets, some of which are expected to trigger the lint. Expected diagnostics must be indicated with either `//~WARN: description` or `//~NOTE: description` on the relevant line.\n- corresponding `.stderr` (blessed) file which contains the exact diagnostic output the linter is expected to produce for that source file.\n\nThe testing framework runs the linter on the `.sol` file and compares its standard error output against the content of the `.stderr` file to ensure correctness.\n\n- Run the following command to trigger the ui test runner:\n  ```sh\n  // using the default cargo cmd for running tests\n  cargo test -p forge --test ui\n\n  // using nextest\n  cargo nextest run -p forge test ui\n  ```\n\n- If you need to generate / bless (re-generate) the output files:\n  ```sh\n  // using the default cargo cmd for running tests\n  cargo bless-lints\n  ```\n"
  },
  {
    "path": "docs/dev/networks.md",
    "content": "# Custom Network Features\n\nFoundry's `anvil`, `forge` and `cast` tools can be customized with specific network features (currently with custom \nprecompiles, with planned support for custom transaction types).\n\nFor supporting custom features of a network, please check out documentation and examples within [`evm-networks`](../../crates/evm/networks) crate.\n"
  },
  {
    "path": "docs/dev/scripting.md",
    "content": "# Scripting\n\n- [Scripting](#scripting)\n  - [High level overview](#high-level-overview)\n    - [Notes](#notes)\n  - [Script Execution](#script-execution)\n  - [Nonce Management](#nonce-management)\n\n## High level overview\n\n```mermaid\ngraph TD;\n    ScriptArgs::run_script-->ScriptArgs::compile;\n    ScriptArgs::compile-->A{ScriptArgs::execute};\n    A-- \"(resume || verify) && !broadcast\" -->B{ScriptArgs::resume_deployment};\n    A-- \"broadcast\" -->ScriptArgs::handle_broadcastable_transactions;\n\n    B-- multi-chain --> MultiChainSequence::load\n    B-- single-chain --> ScriptArgs::resume_single_deployment\n    ScriptArgs::resume_single_deployment--> ScriptSequence::load\n    ScriptSequence::load--> receipts::wait_for_pending\n    receipts::wait_for_pending -- resume --> ScriptArgs::send_transactions\n\n    MultiChainSequence::load --> ScriptArgs::multi_chain_deployment\n\n    ScriptArgs::multi_chain_deployment-- \"resume[..]\" --> receipts::wait_for_pending\n    ScriptArgs::multi_chain_deployment-- \"resume[..]\" --> ScriptArgs::send_transactions\n    ScriptArgs::multi_chain_deployment-- \"broadcast[..]\" --> ScriptArgs::send_transactions\n\n    ScriptArgs::send_transactions--verify-->ScriptArgs::verify_contracts\n\n\n    ScriptArgs::handle_broadcastable_transactions-->ScriptConfig::collect_rpcs;\n    ScriptConfig::collect_rpcs-->ScriptArgs::create_script_sequences\n    ScriptArgs::create_script_sequences--\"[..]\"-->C{Skip onchain simulation};\n    C--yes-->D{\"How many sequences?\"};\n    C--no-->ScriptArgs::fills_transactions_with_gas;\n    ScriptArgs::fills_transactions_with_gas-->ScriptArgs::onchain_simulation;\n    ScriptArgs::onchain_simulation-->D;\n\n    D--\"+1 seq\"-->MultiChainSequence::new\n    D--\"1 seq\"-->ScriptSequence::new\n\n    MultiChainSequence::new-->ScriptArgs::multi_chain_deployment\n    ScriptSequence::new-->ScriptArgs::single_deployment\n    ScriptArgs::single_deployment-->ScriptArgs::send_transactions\n```\n\n### Notes\n\n1. `[..]` - concurrently executed\n\n2. The bit below does not actually influence the state initially defined by `--broadcast`. It only happens because there might be private keys declared inside the script that need to be collected again. `--resume` only resumes **publishing** the transactions, nothing more!\n\n```mermaid\ngraph TD;\nScriptArgs::execute-- \"(resume || verify) && !broadcast\" -->ScriptArgs::resume_deployment;\n```\n\n3. `ScriptArgs::execute` executes the script, while `ScriptArgs::onchain_simulation` only executes the broadcastable transactions collected by `ScriptArgs::execute`.\n\n## Script Execution\n\n```mermaid\ngraph TD;\nsubgraph ScriptArgs::execute\na[*]-->ScriptArgs::prepare_runner\nsubgraph ::prepare_runner\nScriptArgs::prepare_runner--fork_url-->Backend::spawn;\nScriptArgs::prepare_runner-->Backend::spawn;\nend\nBackend::spawn-->\nScriptRunner-->ScriptRunner::setup;\nsubgraph ::setup\nScriptRunner::setup--libraries-->Executor::deploy;\nScriptRunner::setup--ScriptContract-->Executor::deploy;\nExecutor::deploy--\"setUp()\"-->Executor::call_committing;\nend\nsubgraph ::script\nExecutor::call_committing-->ScriptRunner::script;\nScriptRunner::script--\"run()\"-->Executor::call;\nend\nend\nExecutor::call-. BroadcastableTransactions .->ScriptArgs::handle_broadcastable_transactions;\n```\n\n## Nonce Management\n\nDuring the first execution stage on `forge script`, foundry has to adjust the nonce from the sender to make sure the execution and state are as close as possible to its on-chain representation.\n\nMaking sure that `msg.sender` is our signer when calling `setUp()` and `run()` and that its nonce is correct (decreased by one on each call) when calling `vm.broadcast` to create a contract.\n\nWe skip this, if the user hasn't set a sender and they're using the `Config::DEFAULT_SENDER`.\n\n```mermaid\ngraph TD\n\n    ScriptRunner::setup-->default_foundry_caller-deployScript;\n    default_foundry_caller-deployScript-->user_sender-deployLibs;\n    user_sender-deployLibs-->Contract.setUp;\n    Contract.setUp-->A0{Executor::call};\n    A0-->vm.broadcast;\n    A0-->vm.startBroadcast;\n    A0-->vm.getNonce;\n\n    vm.broadcast--> A{cheatcode.corrected_nonce}\n    vm.startBroadcast-->A\n    vm.getNonce-->A\n\n    A--true-->continue_setUp;\n    A--false-->B[sender_nonce=-1];\n    B-->C[cheatcode.corrected_nonce=true];\n    C-->continue_setUp;\n    continue_setUp-->end_setUp;\n    end_setUp-->D{cheatcode.corrected_nonce}\n    D--true-->E[cheatcode.corrected_nonce=false];\n    D--false-->F[sender_nonce=initial_nonce+predeployed_libraries_count];\n    E-->ScriptRunner::script;\n    F-->ScriptRunner::script;\n    ScriptRunner::script-->Contract.run;\n    Contract.run-->G{Executor::call};\n    G-->H[vm.broadcast];\n    G-->I[vm.startBroadcast];\n    G-->J[vm.getNonce];\n\n    H--> K{cheatcode.corrected_nonce}\n    I-->K\n    J-->K\n\n    K--true-->continue_run;\n    K--false-->L[sender_nonce=-1];\n    L-->M[cheatcode.corrected_nonce=true];\n    M-->continue_run;\n    continue_run-->end_run;\n```\n"
  },
  {
    "path": "dprint.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/dprint/dprint/refs/heads/main/website/src/assets/schemas/v0.json\",\n  \"indentWidth\": 2,\n  \"useTabs\": false,\n  \"excludes\": [\n    \"!dprint.json\",\n    \"!npm/**/*.{json,md,toml}\",\n    \"!npm/**/*.{js,cjs,mjs,d.ts,d.cts,d.mts,ts,tsx,jsx}\",\n    \"**/_\",\n    \"**/abi\",\n    \"**/build\",\n    \"**/target\",\n    \"**/test/**\",\n    \"**/*.min.*\",\n    \"**/dist/**\",\n    \"testdata/**\",\n    \"**/tests/**\",\n    \"node_modules\",\n    \"changelog.json\",\n    \"**/test-data/**\",\n    \"**/cheatcodes/**\",\n    \"**/node_modules/**\",\n    \".github/scripts/**\",\n    \".github/ISSUE_TEMPLATE/**\"\n  ],\n  \"plugins\": [\n    \"https://plugins.dprint.dev/toml-0.7.0.wasm\",\n    \"https://plugins.dprint.dev/json-0.21.0.wasm\",\n    \"https://plugins.dprint.dev/markdown-0.20.0.wasm\",\n    \"https://plugins.dprint.dev/dockerfile-0.3.3.wasm\",\n    \"https://plugins.dprint.dev/typescript-0.95.11.wasm\",\n    \"https://plugins.dprint.dev/g-plane/pretty_yaml-v0.5.1.wasm\"\n  ],\n  \"markdown\": {\n    \"lineWidth\": 100,\n    \"textWrap\": \"maintain\"\n  },\n  \"toml\": {\n    \"lineWidth\": 100\n  },\n  \"json\": {\n    \"lineWidth\": 1,\n    \"indentWidth\": 2,\n    \"useTabs\": false,\n    \"trailingCommas\": \"never\",\n    \"preferSingleLine\": false,\n    \"array.preferSingleLine\": false\n  },\n  \"typescript\": {\n    \"useTabs\": false,\n    \"semiColons\": \"asi\",\n    \"quoteProps\": \"asNeeded\",\n    \"useBraces\": \"preferNone\",\n    \"trailingCommas\": \"never\",\n    \"quoteStyle\": \"alwaysSingle\",\n    \"arrowFunction.useParentheses\": \"preferNone\",\n    \"exportDeclaration.sortTypeOnlyExports\": \"none\",\n    \"importDeclaration.sortTypeOnlyImports\": \"none\"\n  }\n}\n"
  },
  {
    "path": "flake.nix",
    "content": "{\n  inputs = {\n    nixpkgs.url = \"github:NixOS/nixpkgs/nixpkgs-unstable\";\n    fenix = {\n      url = \"github:nix-community/fenix\";\n      inputs.nixpkgs.follows = \"nixpkgs\";\n    };\n  };\n\n  outputs = { self, nixpkgs, fenix }:\n    let eachSystem = nixpkgs.lib.genAttrs nixpkgs.lib.systems.flakeExposed;\n    in {\n      devShells = eachSystem (system:\n        let\n          pkgs = import nixpkgs {\n            inherit system;\n            overlays = [ fenix.overlays.default ];\n          };\n\n          lib = pkgs.lib;\n          toolchain = fenix.packages.${system}.stable.withComponents [\n            \"rustc\"\n            \"cargo\"\n            \"rust-std\"\n            \"clippy-preview\"\n            \"rust-analyzer-preview\"\n            \"rust-src\"\n          ];\n          nightlyToolchain = fenix.packages.${system}.latest.withComponents [\n            \"rustfmt-preview\"\n          ];\n        in\n        {\n          default = pkgs.mkShell {\n            nativeBuildInputs = with pkgs; [\n              pkg-config\n              toolchain\n              nightlyToolchain\n\n              # test dependencies\n              solc\n              vyper\n              dprint\n              nodejs\n            ];\n\n            packages = with pkgs; [ rust-analyzer-unwrapped ];\n\n            # Remove the hardening added by nix to fix jmalloc compilation error.\n            # More info: https://github.com/tikv/jemallocator/issues/108\n            hardeningDisable = [ \"fortify\" ];\n\n            # Environment variables\n            RUST_SRC_PATH = \"${toolchain}/lib/rustlib/src/rust/library\";\n            LD_LIBRARY_PATH = lib.makeLibraryPath [ pkgs.libusb1 ];\n            CFLAGS = \"-DJEMALLOC_STRERROR_R_RETURNS_CHAR_WITH_GNU_SOURCE\";\n          };\n        });\n    };\n}\n"
  },
  {
    "path": "foundryup/README.md",
    "content": "# `foundryup`\n\nUpdate or revert to a specific Foundry branch with ease.\n\n`foundryup` supports installing and managing multiple versions.\n\n## Installing\n\n```sh\ncurl -L https://foundry.paradigm.xyz | bash\n```\n\n## Usage\n\nTo install the **nightly** version:\n\n```sh\nfoundryup\n```\n\nTo **install** a specific **version** (in this case the `nightly` version):\n\n```sh\nfoundryup --install nightly\n```\n\nTo **list** all **versions** installed:\n\n```sh\nfoundryup --list\n```\n\nTo switch between different versions and **use**:\n\n```sh\nfoundryup --use nightly-00efa0d5965269149f374ba142fb1c3c7edd6c94\n```\n\nTo install a specific **branch** (in this case the `release/0.1.0` branch's latest commit):\n\n```sh\nfoundryup --branch release/0.1.0\n```\n\nTo install a **fork's main branch** (in this case `transmissions11/foundry`'s main branch):\n\n```sh\nfoundryup --repo transmissions11/foundry\n```\n\nTo install a **specific branch in a fork** (in this case the `patch-10` branch's latest commit in `transmissions11/foundry`):\n\n```sh\nfoundryup --repo transmissions11/foundry --branch patch-10\n```\n\nTo install from a **specific Pull Request**:\n\n```sh\nfoundryup --pr 1071\n```\n\nTo install from a **specific commit**:\n\n```sh\nfoundryup -C 94bfdb2\n```\n\nTo install a local directory or repository (e.g. one located at `~/git/foundry`, assuming you're in the home directory)\n\n#### Note: --branch, --repo, and --version flags are ignored during local installations.\n\n```sh\nfoundryup --path ./git/foundry\n```\n\n---\n\n**Tip**: All flags have a single character shorthand equivalent! You can use `-i` instead of `--install`, etc.\n\n---\n\n## Uninstalling\n\nFoundry contains everything in a `.foundry` directory, usually located in `/home/<user>/.foundry/` on Linux, `/Users/<user>/.foundry/` on MacOS and `C:\\Users\\<user>\\.foundry` on Windows where `<user>` is your username.\n\nTo uninstall Foundry remove the `.foundry` directory.\n\n#### Warning ⚠️: .foundry directory can contain keystores. Make sure to backup any keystores you want to keep.\n\nRemove Foundry from PATH:\n\n- Optionally Foundry can be removed from editing shell configuration file (`.bashrc`, `.zshrc`, etc.). To do so remove the line that adds Foundry to PATH:\n\n```sh\nexport PATH=\"$PATH:/home/user/.foundry/bin\"\n```\n"
  },
  {
    "path": "foundryup/foundryup",
    "content": "#!/usr/bin/env bash\nset -eo pipefail\n\n# NOTE: if you make modifications to this script, please increment the version number.\n# WARNING: the SemVer pattern: major.minor.patch must be followed as we use it to determine if the script is up to date.\nFOUNDRYUP_INSTALLER_VERSION=\"1.6.1\"\n\nBASE_DIR=${XDG_CONFIG_HOME:-$HOME}\nFOUNDRY_DIR=${FOUNDRY_DIR:-\"$BASE_DIR/.foundry\"}\nFOUNDRY_VERSIONS_DIR=\"$FOUNDRY_DIR/versions\"\nFOUNDRY_BIN_DIR=\"$FOUNDRY_DIR/bin\"\nFOUNDRY_MAN_DIR=\"$FOUNDRY_DIR/share/man/man1\"\nFOUNDRY_BIN_URL=\"https://raw.githubusercontent.com/foundry-rs/foundry/HEAD/foundryup/foundryup\"\nFOUNDRY_BIN_PATH=\"$FOUNDRY_BIN_DIR/foundryup\"\nFOUNDRYUP_JOBS=\"\"\nFOUNDRYUP_IGNORE_VERIFICATION=false\n\nBINS=(forge cast anvil chisel)\nHASH_NAMES=()\nHASH_VALUES=()\n\nexport RUSTFLAGS=\"${RUSTFLAGS:--C target-cpu=native}\"\n\nmain() {\n  need_cmd git\n  need_cmd curl\n\n  while [[ -n $1 ]]; do\n    case $1 in\n      --)               shift; break;;\n\n      -v|--version)     shift; version;;\n      -U|--update)      shift; update;;\n      -r|--repo)        shift; FOUNDRYUP_REPO=$1;;\n      -b|--branch)      shift; FOUNDRYUP_BRANCH=$1;;\n      -i|--install)     shift; FOUNDRYUP_VERSION=$1;;\n      -l|--list)        shift; list;;\n      -u|--use)         shift; FOUNDRYUP_VERSION=$1; use;;\n      -p|--path)        shift; FOUNDRYUP_LOCAL_REPO=$1;;\n      -P|--pr)          shift; FOUNDRYUP_PR=$1;;\n      -C|--commit)      shift; FOUNDRYUP_COMMIT=$1;;\n      -j|--jobs)        shift; FOUNDRYUP_JOBS=$1;;\n      -n|--network)     shift; FOUNDRYUP_NETWORK=$1;;\n      -f|--force)       FOUNDRYUP_IGNORE_VERIFICATION=true;;\n      --arch)           shift; FOUNDRYUP_ARCH=$1;;\n      --platform)       shift; FOUNDRYUP_PLATFORM=$1;;\n      -h|--help)\n        usage\n        exit 0\n        ;;\n      *)\n        warn \"unknown option: $1\"\n        usage\n        exit 1\n    esac; shift\n  done\n\n  CARGO_BUILD_ARGS=(--release)\n\n  if [ -n \"$FOUNDRYUP_JOBS\" ]; then\n    CARGO_BUILD_ARGS+=(--jobs \"$FOUNDRYUP_JOBS\")\n  fi\n\n  # Print the banner after successfully parsing args\n  banner\n\n  # Check if the foundryup installer is up to date, warn the user if not\n  check_installer_up_to_date\n\n  if [ -n \"$FOUNDRYUP_PR\" ]; then\n    if [ -z \"$FOUNDRYUP_BRANCH\" ]; then\n      FOUNDRYUP_BRANCH=\"refs/pull/$FOUNDRYUP_PR/head\"\n    else\n      err \"can't use --pr and --branch at the same time\"\n    fi\n  fi\n\n  check_bins_in_use\n\n  # Installs foundry from a local repository if --path parameter is provided\n  if [[ -n \"$FOUNDRYUP_LOCAL_REPO\" ]]; then\n    need_cmd cargo\n\n    # Ignore branches/versions as we do not want to modify local git state\n    if [ -n \"$FOUNDRYUP_REPO\" ] || [ -n \"$FOUNDRYUP_BRANCH\" ] || [ -n \"$FOUNDRYUP_VERSION\" ]; then\n      warn \"--branch, --install, --use, and --repo arguments are ignored during local install\"\n    fi\n\n    # Enter local repo and build\n    say \"installing from $FOUNDRYUP_LOCAL_REPO\"\n    cd \"$FOUNDRYUP_LOCAL_REPO\"\n    ensure cargo build --bins \"${CARGO_BUILD_ARGS[@]}\"\n\n    for bin in \"${BINS[@]}\"; do\n      # Remove prior installations if they exist\n      rm -f \"$FOUNDRY_BIN_DIR/$bin\"\n      # Symlink from local repo binaries to bin dir\n      ensure ln -s \"$PWD/target/release/$bin\" \"$FOUNDRY_BIN_DIR/$bin\"\n    done\n\n    say \"done\"\n    exit 0\n  fi\n\n  # If Tempo network is set, use the Tempo fork of Foundry\n  if [[ \"$FOUNDRYUP_NETWORK\" == \"tempo\" ]]; then\n    FOUNDRYUP_REPO=\"tempoxyz/tempo-foundry\"\n  else\n  # Default to Foundry repo\n    FOUNDRYUP_REPO=${FOUNDRYUP_REPO:-foundry-rs/foundry}\n  fi\n\n  # Install by downloading binaries\n  if [[ \"$FOUNDRYUP_REPO\" == \"foundry-rs/foundry\" && -z \"$FOUNDRYUP_BRANCH\" && -z \"$FOUNDRYUP_COMMIT\" ]]; then\n    FOUNDRYUP_VERSION=${FOUNDRYUP_VERSION:-stable}\n    FOUNDRYUP_TAG=$FOUNDRYUP_VERSION\n\n    # Normalize versions (handle channels, versions without v prefix)\n    if [[ \"$FOUNDRYUP_VERSION\" =~ ^nightly ]]; then\n      FOUNDRYUP_VERSION=\"nightly\"\n    elif [[ \"$FOUNDRYUP_VERSION\" == [[:digit:]]* ]]; then\n      # Add v prefix\n      FOUNDRYUP_VERSION=\"v${FOUNDRYUP_VERSION}\"\n      FOUNDRYUP_TAG=\"${FOUNDRYUP_VERSION}\"\n    fi\n\n    say \"installing foundry (version ${FOUNDRYUP_VERSION}, tag ${FOUNDRYUP_TAG})\"\n\n    # Detect platform and architecture.\n    detect_platform_arch\n\n    # Compute the URL of the release tarball in the Foundry repository.\n    RELEASE_URL=\"https://github.com/${FOUNDRYUP_REPO}/releases/download/${FOUNDRYUP_TAG}/\"\n    ATTESTATION_URL=\"${RELEASE_URL}foundry_${FOUNDRYUP_VERSION}_${PLATFORM}_${ARCHITECTURE}.attestation.txt\"\n    BIN_ARCHIVE_URL=\"${RELEASE_URL}foundry_${FOUNDRYUP_VERSION}_${PLATFORM}_${ARCHITECTURE}.$EXT\"\n    MAN_TARBALL_URL=\"${RELEASE_URL}foundry_man_${FOUNDRYUP_VERSION}.tar.gz\"\n\n    ensure mkdir -p \"$FOUNDRY_VERSIONS_DIR\"\n\n    # If `--force` is set, skip the SHA verification.\n    if [ \"$FOUNDRYUP_IGNORE_VERIFICATION\" = false ]; then\n      # Check if the version is already installed by downloading the attestation file.\n      say \"checking if forge, cast, anvil, and chisel for $FOUNDRYUP_TAG version are already installed\"\n\n      # Create a temporary directory to store the attestation link and artifact.\n      tmp_dir=\"$(mktemp -d 2>/dev/null)\" || err \"failed to create temp dir\"\n      tmp=\"$tmp_dir/attestation.txt\"\n      ensure download \"$ATTESTATION_URL\" \"$tmp\"\n      \n      # Read the first line of the attestation file to get the artifact link.\n      # The first line should contain the link to the attestation artifact.\n      attestation_artifact_link=\"$(head -n1 \"$tmp\" | tr -d '\\r')\"\n      attestation_missing=false\n\n      # If the attestation artifact link is empty or the file contains 'Not Found',\n      # we consider the attestation missing and skip the SHA verification.\n      if [ -z \"$attestation_artifact_link\" ] || grep -q 'Not Found' \"$tmp\"; then\n        attestation_missing=true\n      fi\n\n      # Clean up the temporary attestation file.\n      rm -f \"$tmp\"\n\n      if $attestation_missing; then\n        say \"no attestation found for this release, skipping SHA verification\"\n      else\n        say \"found attestation for $FOUNDRYUP_TAG version, downloading attestation artifact, checking...\"\n\n        # Download the attestation artifact JSON file.\n        tmp=\"$tmp_dir/foundry-attestation.sigstore.json\"\n        ensure download \"${attestation_artifact_link}/download\" \"$tmp\"\n\n        # Extract the payload from the JSON file.\n        payload_b64=$(awk '/\"payload\":/ {gsub(/[\",]/, \"\", $2); print $2; exit}' \"$tmp\")\n        payload_json=$(printf '%s' \"$payload_b64\" | base64 -d 2>/dev/null || printf '%s' \"$payload_b64\" | base64 -D)\n\n\n        # Extract the names and hashes from the payload JSON.\n        # The payload is expected to be a JSON array of objects with \"name\" and \"sha256\" fields.\n        while read -r name_line && read -r sha_line; do\n          name=$(echo \"$name_line\" | sed -nE 's/.*\"name\"[[:space:]]*:[[:space:]]*\"([^\"]+)\".*/\\1/p')\n          sha=$(echo \"$sha_line\"  | sed -nE 's/.*\"sha256\"[[:space:]]*:[[:space:]]*\"([^\"]+)\".*/\\1/p')\n          if [ -n \"$name\" ] && [ -n \"$sha\" ]; then\n            HASH_NAMES+=(\"$name\")\n            HASH_VALUES+=(\"$sha\")\n          fi\n        done < <(echo \"$payload_json\" | tr '{}' '\\n' | grep -E '\"name\"|sha256')\n\n        # Clean up the temporary attestation artifact.\n        # The hashes are now stored in the HASHES associative array.\n        rm -f \"$tmp\"\n\n        # Check if the binaries are already installed and match the expected hashes.\n        # If they do, skip the download.\n        version_dir=\"$FOUNDRY_VERSIONS_DIR/$FOUNDRYUP_TAG\"\n        all_match=true\n        for bin in \"${BINS[@]}\"; do\n          expected=\"\"\n          for i in \"${!HASH_NAMES[@]}\"; do\n            if [ \"${HASH_NAMES[$i]}\" = \"$bin\" ] || [ \"${HASH_NAMES[$i]}\" = \"$bin.exe\" ]; then\n              expected=\"${HASH_VALUES[$i]}\"\n              break\n            fi\n          done\n\n          path=\"$version_dir/$bin\"\n\n          if [ -z \"$expected\" ] || [ ! -x \"$path\" ]; then\n            all_match=false\n            break\n          fi\n\n          actual=$(compute_sha256 \"$path\")\n          if [ \"$actual\" != \"$expected\" ]; then\n            all_match=false\n            break\n          fi\n        done\n\n        if $all_match; then\n          say \"version $FOUNDRYUP_TAG already installed and verified, activating...\"\n          FOUNDRYUP_VERSION=$FOUNDRYUP_TAG\n          use\n          say \"done!\"\n          exit 0\n        fi\n      fi\n\n      # If we reach here, we need to download the binaries.\n      say \"binaries not found or do not match expected hashes, downloading new binaries\"\n    fi\n\n    # Download and extract the binaries archive\n    say \"downloading forge, cast, anvil, and chisel for $FOUNDRYUP_TAG version\"\n    if [ \"$PLATFORM\" = \"win32\" ]; then\n      tmp=\"$(mktemp -d 2>/dev/null)\" || err \"failed to create temp dir\"\n      tmp=\"$tmp/foundry.zip\"\n      ensure download \"$BIN_ARCHIVE_URL\" \"$tmp\"\n      ensure unzip \"$tmp\" -d \"$FOUNDRY_VERSIONS_DIR/$FOUNDRYUP_TAG\"\n      rm -f \"$tmp\"\n    else\n      tmp=\"$(mktemp -d 2>/dev/null)\" || err \"failed to create temp dir\"\n      tmp=\"$tmp/foundry.tar.gz\"\n      ensure download \"$BIN_ARCHIVE_URL\" \"$tmp\"\n      # Make sure it's a valid tar archive.\n      ensure tar tf \"$tmp\" 1> /dev/null\n      ensure mkdir -p \"$FOUNDRY_VERSIONS_DIR/$FOUNDRYUP_TAG\"\n      ensure tar -C \"$FOUNDRY_VERSIONS_DIR/$FOUNDRYUP_TAG\" -xvf \"$tmp\"\n      rm -f \"$tmp\"\n    fi\n\n    # Optionally download the manuals\n    if check_cmd tar; then\n      say \"downloading manpages\"\n      mkdir -p \"$FOUNDRY_MAN_DIR\"\n      if ! download \"$MAN_TARBALL_URL\" | tar -xzC \"$FOUNDRY_MAN_DIR\"; then\n        warn \"skipping manpage download: unavailable or invalid archive\"\n      fi\n    else\n      say 'skipping manpage download: missing \"tar\"'\n    fi\n    \n    if [ \"$FOUNDRYUP_IGNORE_VERIFICATION\" = true ]; then\n      say \"skipped SHA verification for downloaded binaries due to --force flag\"\n    else\n      # Verify the downloaded binaries against the attestation file.\n      # If the attestation file was not found or is empty, we skip the verification.\n      if $attestation_missing; then\n        say \"no attestation found for these binaries, skipping SHA verification for downloaded binaries\"\n      else\n        say \"verifying downloaded binaries against the attestation file\"\n\n        failed=false\n        for bin in \"${BINS[@]}\"; do\n          expected=\"\"\n          for i in \"${!HASH_NAMES[@]}\"; do\n            if [ \"${HASH_NAMES[$i]}\" = \"$bin\" ] || [ \"${HASH_NAMES[$i]}\" = \"$bin.exe\" ]; then\n              expected=\"${HASH_VALUES[$i]}\"\n              break\n            fi\n          done\n\n          path=\"$FOUNDRY_VERSIONS_DIR/$FOUNDRYUP_TAG/$bin\"\n\n          if [ -z \"$expected\" ]; then\n            say \"no expected hash for $bin\"\n            failed=true\n            continue\n          fi\n\n          if [ ! -x \"$path\" ]; then\n            say \"binary $bin not found at $path\"\n            failed=true\n            continue\n          fi\n\n          actual=$(compute_sha256 \"$path\")\n          if [ \"$actual\" != \"$expected\" ]; then\n            say \"$bin hash verification failed:\"\n            say \"  expected: $expected\"\n            say \"  actual:   $actual\"\n            failed=true\n          else\n            say \"$bin verified ✓\"\n          fi\n        done\n\n        if $failed; then\n          err \"one or more binaries failed post-installation verification\"\n        fi\n      fi\n    fi\n\n    # Use newly installed version.\n    FOUNDRYUP_VERSION=$FOUNDRYUP_TAG\n    use\n\n    say \"done!\"\n  # Install from Tempo's fork of Foundry if --network tempo is set\n  elif [[ \"$FOUNDRYUP_NETWORK\" == \"tempo\" ]]; then\n    FOUNDRYUP_VERSION=${FOUNDRYUP_VERSION:-nightly}\n    FOUNDRYUP_TAG=\"${FOUNDRYUP_VERSION}\"\n\n    say \"installing tempo-foundry (version ${FOUNDRYUP_VERSION}, tag ${FOUNDRYUP_TAG})\"\n\n    # Detect platform and architecture.\n    detect_platform_arch\n\n    # Compute the URL of the release tarball in the Tempo Foundry repository.\n    RELEASE_URL=\"https://github.com/${FOUNDRYUP_REPO}/releases/download/${FOUNDRYUP_TAG}/\"\n    BIN_ARCHIVE_URL=\"${RELEASE_URL}foundry_${FOUNDRYUP_VERSION}_${PLATFORM}_${ARCHITECTURE}.$EXT\"\n    MAN_TARBALL_URL=\"${RELEASE_URL}foundry_man_${FOUNDRYUP_VERSION}.tar.gz\"\n\n    ensure mkdir -p \"$FOUNDRY_VERSIONS_DIR\"\n\n    # Download and extract the binaries archive\n    say \"downloading forge, cast, anvil, and chisel for $FOUNDRYUP_TAG version\"\n    if [ \"$PLATFORM\" = \"win32\" ]; then\n      tmp=\"$(mktemp -d 2>/dev/null)\" || err \"failed to create temp dir\"\n      tmp=\"$tmp/foundry.zip\"\n      ensure download \"$BIN_ARCHIVE_URL\" \"$tmp\"\n      ensure unzip \"$tmp\" -d \"$FOUNDRY_VERSIONS_DIR/$FOUNDRYUP_TAG\"\n      rm -f \"$tmp\"\n    else\n      tmp=\"$(mktemp -d 2>/dev/null)\" || err \"failed to create temp dir\"\n      tmp=\"$tmp/foundry.tar.gz\"\n      ensure download \"$BIN_ARCHIVE_URL\" \"$tmp\"\n      # Make sure it's a valid tar archive.\n      ensure tar tf \"$tmp\" 1> /dev/null\n      ensure mkdir -p \"$FOUNDRY_VERSIONS_DIR/$FOUNDRYUP_TAG\"\n      ensure tar -C \"$FOUNDRY_VERSIONS_DIR/$FOUNDRYUP_TAG\" -xvf \"$tmp\"\n      rm -f \"$tmp\"\n    fi\n\n    # Optionally download the manuals\n    if check_cmd tar; then\n      say \"downloading manpages\"\n      mkdir -p \"$FOUNDRY_MAN_DIR\"\n      if ! download \"$MAN_TARBALL_URL\" | tar -xzC \"$FOUNDRY_MAN_DIR\"; then\n        warn \"skipping manpage download: unavailable or invalid archive\"\n      fi\n    else\n      say 'skipping manpage download: missing \"tar\"'\n    fi\n\n    # Use newly installed version.\n    FOUNDRYUP_VERSION=$FOUNDRYUP_TAG\n    use\n\n    say \"done!\"\n  # Install by cloning the repo with the provided branch/tag\n  else\n    need_cmd cargo\n    FOUNDRYUP_BRANCH=${FOUNDRYUP_BRANCH:-master}\n    REPO_PATH=\"$FOUNDRY_DIR/$FOUNDRYUP_REPO\"\n    AUTHOR=\"$(echo \"$FOUNDRYUP_REPO\" | cut -d'/' -f1 -)\"\n\n    # If repo path does not exist, grab the author from the repo, make a directory in .foundry, cd to it and clone.\n    if [ ! -d \"$REPO_PATH\" ]; then\n      ensure mkdir -p \"$FOUNDRY_DIR/$AUTHOR\"\n      cd \"$FOUNDRY_DIR/$AUTHOR\"\n      ensure git clone \"https://github.com/$FOUNDRYUP_REPO\"\n    fi\n\n    # Force checkout, discarding any local changes\n    cd \"$REPO_PATH\"\n    ensure git fetch origin \"${FOUNDRYUP_BRANCH}:remotes/origin/${FOUNDRYUP_BRANCH}\"\n    ensure git checkout \"origin/${FOUNDRYUP_BRANCH}\"\n\n    # Create custom version based on the install method, e.g.:\n    # - foundry-rs-commit-c22c4cc96b0535cd989ee94b79da1b19d236b8db\n    # - foundry-rs-pr-1\n    # - foundry-rs-branch-chore-bump-forge-std\n    if [ -n \"$FOUNDRYUP_COMMIT\" ]; then\n      # If set, checkout specific commit from branch\n      ensure git checkout \"$FOUNDRYUP_COMMIT\"\n      FOUNDRYUP_VERSION=$AUTHOR-commit-$FOUNDRYUP_COMMIT\n    elif [ -n \"$FOUNDRYUP_PR\" ]; then\n     FOUNDRYUP_VERSION=$AUTHOR-pr-$FOUNDRYUP_PR\n    else\n      if [ -n \"$FOUNDRYUP_BRANCH\" ]; then\n        NORMALIZED_BRANCH=\"$(echo \"$FOUNDRYUP_BRANCH\" | tr / -)\"\n        FOUNDRYUP_VERSION=$AUTHOR-branch-$NORMALIZED_BRANCH\n      fi\n    fi\n    say \"installing version $FOUNDRYUP_VERSION\"\n\n    # Build the repo.\n    ensure cargo build --bins \"${CARGO_BUILD_ARGS[@]}\"\n    # Create foundry custom version directory.\n    ensure mkdir -p \"$FOUNDRY_VERSIONS_DIR/$FOUNDRYUP_VERSION\"\n    for bin in \"${BINS[@]}\"; do\n      for try_path in target/release/$bin target/release/$bin.exe; do\n        if [ -f \"$try_path\" ]; then\n          mv -f \"$try_path\" \"$FOUNDRY_VERSIONS_DIR/$FOUNDRYUP_VERSION\"\n        fi\n      done\n    done\n\n    # Use newly built version.\n    use\n\n    # If help2man is installed, use it to add Foundry man pages.\n    if check_cmd help2man; then\n      for bin in \"${BINS[@]}\"; do\n        help2man -N \"$FOUNDRY_BIN_DIR/$bin\" > \"$FOUNDRY_MAN_DIR/$bin.1\"\n      done\n    fi\n\n    say \"done\"\n  fi\n}\n\nusage() {\n  cat 1>&2 <<EOF\nThe installer for Foundry.\n\nUpdate or revert to a specific Foundry version with ease.\n\nBy default, the latest stable version is installed from built binaries.\n\nUSAGE:\n    foundryup <OPTIONS>\n\nOPTIONS:\n    -h, --help      Print help information\n    -v, --version   Print the version of foundryup\n    -U, --update    Update foundryup to the latest version\n    -i, --install   Install a specific version from built binaries\n    -l, --list      List versions installed from built binaries\n    -u, --use       Use a specific installed version from built binaries\n    -b, --branch    Build and install a specific branch\n    -P, --pr        Build and install a specific Pull Request\n    -C, --commit    Build and install a specific commit\n    -r, --repo      Build and install from a remote GitHub repo (uses default branch if no other options are set)\n    -p, --path      Build and install a local repository\n    -j, --jobs      Number of CPUs to use for building Foundry (default: all CPUs)\n    -f, --force     Skip SHA verification for downloaded binaries (INSECURE - use with caution)\n    -n, --network   Install binaries for a specific network (e.g., tempo)\n    --arch          Install a specific architecture (supports amd64 and arm64)\n    --platform      Install a specific platform (supports win32, linux, darwin and alpine)\nEOF\n}\n\nversion() {\n  say \"$FOUNDRYUP_INSTALLER_VERSION\"\n  exit 0\n}\n\nupdate() {\n  say \"updating foundryup...\"\n\n  current_version=\"$FOUNDRYUP_INSTALLER_VERSION\"\n\n  # Download the new version.\n  tmp_file=\"$(mktemp)\"\n  ensure download \"$FOUNDRY_BIN_URL\" \"$tmp_file\"\n\n  # Extract new version from downloaded file.\n  new_version=$(grep -Eo 'FOUNDRYUP_INSTALLER_VERSION=\"[0-9]+\\.[0-9]+\\.[0-9]+\"' \"$tmp_file\" | cut -d'\"' -f2)\n\n  # If the new version could not be determined, exit gracefully.\n  # This prevents from upgrading to an empty or invalid version.\n  if [ -z \"$new_version\" ]; then\n    warn \"could not determine new foundryup version. Exiting.\"\n    rm -f \"$tmp_file\"\n    exit 0\n  fi\n\n  # If the new version is not greater than the current version, skip the update.\n  # This is to prevent downgrades or unnecessary updates.\n  if ! version_gt \"$new_version\" \"$current_version\"; then\n    say \"foundryup is already up to date (installed: $current_version, remote: $new_version).\"\n    rm -f \"$tmp_file\"\n    exit 0\n  fi\n\n  # Overwrite existing foundryup\n  ensure mv \"$tmp_file\" \"$FOUNDRY_BIN_PATH\"\n  ensure chmod +x \"$FOUNDRY_BIN_PATH\"\n\n  say \"successfully updated foundryup: $current_version → $new_version\"\n  exit 0\n}\n\nlist() {\n  if [ -d \"$FOUNDRY_VERSIONS_DIR\" ]; then\n    for VERSION in $FOUNDRY_VERSIONS_DIR/*; do\n      say \"${VERSION##*/}\"\n      for bin in \"${BINS[@]}\"; do\n        bin_path=\"$VERSION/$bin\"\n        say \"- $(ensure \"$bin_path\" -V)\"\n      done\n      printf \"\\n\"\n    done\n  else\n    for bin in \"${BINS[@]}\"; do\n      bin_path=\"$FOUNDRY_BIN_DIR/$bin\"\n      say \"- $(ensure \"$bin_path\" -V)\"\n    done\n  fi\n  exit 0\n}\n\nuse() {\n  [ -z \"$FOUNDRYUP_VERSION\" ] && err \"no version provided\"\n  FOUNDRY_VERSION_DIR=\"$FOUNDRY_VERSIONS_DIR/$FOUNDRYUP_VERSION\"\n  if [ -d \"$FOUNDRY_VERSION_DIR\" ]; then\n\n    check_bins_in_use\n\n    for bin in \"${BINS[@]}\"; do\n      bin_path=\"$FOUNDRY_BIN_DIR/$bin\"\n      cp \"$FOUNDRY_VERSION_DIR/$bin\" \"$bin_path\"\n      # Print usage msg\n      say \"use - $(ensure \"$bin_path\" -V)\"\n\n      # Check if the default path of the binary is not in FOUNDRY_BIN_DIR\n      which_path=\"$(command -v \"$bin\" || true)\"\n      if [ -n \"$which_path\" ] && [ \"$which_path\" != \"$bin_path\" ]; then\n        warn \"\"\n        cat 1>&2 <<EOF\nThere are multiple binaries with the name '$bin' present in your 'PATH'.\nThis may be the result of installing '$bin' using another method,\nlike Cargo or other package managers.\nYou may need to run 'rm $which_path' or move '$FOUNDRY_BIN_DIR'\nin your 'PATH' to allow the newly installed version to take precedence!\n\nEOF\n      fi\n    done\n    exit 0\n  else\n    err \"version $FOUNDRYUP_VERSION not installed\"\n  fi\n}\n\nsay() {\n  printf \"foundryup: %s\\n\" \"$1\"\n}\n\nwarn() {\n  say \"warning: ${1}\" >&2\n}\n\nerr() {\n  say \"$1\" >&2\n  exit 1\n}\n\ntolower() {\n  echo \"$1\" | awk '{print tolower($0)}'\n}\n\ncompute_sha256() {\n  if check_cmd sha256sum; then\n    # Use sed to strip leading backslash (sha256sum on Windows/Git Bash outputs \\ prefix for binary files)\n    sha256sum \"$1\" | cut -d' ' -f1 | sed 's/^\\\\//'\n  else\n    shasum -a 256 \"$1\" | awk '{print $1}'\n  fi\n}\n\nneed_cmd() {\n  if ! check_cmd \"$1\"; then\n    err \"need '$1' (command not found)\"\n  fi\n}\n\ncheck_cmd() {\n  command -v \"$1\" &>/dev/null\n}\n\ndetect_platform_arch() {\n  uname_s=$(uname -s)\n  PLATFORM=$(tolower \"${FOUNDRYUP_PLATFORM:-$uname_s}\")\n  EXT=\"tar.gz\"\n  case $PLATFORM in\n    linux|alpine) ;;\n    darwin|mac*)\n      PLATFORM=\"darwin\"\n      ;;\n    mingw*|win*)\n      EXT=\"zip\"\n      PLATFORM=\"win32\"\n      ;;\n    *)\n      err \"unsupported platform: $PLATFORM\"\n      ;;\n  esac\n\n  uname_m=$(uname -m)\n  ARCHITECTURE=$(tolower \"${FOUNDRYUP_ARCH:-$uname_m}\")\n  if [ \"${ARCHITECTURE}\" = \"x86_64\" ]; then\n    # Redirect stderr to /dev/null to avoid printing errors if non Rosetta.\n    if [ \"$(sysctl -n sysctl.proc_translated 2>/dev/null)\" = \"1\" ]; then\n      ARCHITECTURE=\"arm64\" # Rosetta.\n    else\n      ARCHITECTURE=\"amd64\" # Intel.\n    fi\n  elif [ \"${ARCHITECTURE}\" = \"arm64\" ] ||[ \"${ARCHITECTURE}\" = \"aarch64\" ] ; then\n    ARCHITECTURE=\"arm64\" # Arm.\n  else\n    ARCHITECTURE=\"amd64\" # Amd.\n  fi\n}\n\ncheck_installer_up_to_date() {\n  say \"checking if foundryup is up to date...\"\n\n  if check_cmd curl; then\n    remote_version=$(curl -fsSL \"$FOUNDRY_BIN_URL\" | grep -Eo 'FOUNDRYUP_INSTALLER_VERSION=\"[0-9]+\\.[0-9]+\\.[0-9]+\"' | cut -d'\"' -f2)\n  else\n    remote_version=$(wget -qO- \"$FOUNDRY_BIN_URL\" | grep -Eo 'FOUNDRYUP_INSTALLER_VERSION=\"[0-9]+\\.[0-9]+\\.[0-9]+\"' | cut -d'\"' -f2)\n  fi\n\n  if [ -z \"$remote_version\" ]; then\n    warn \"Could not determine remote foundryup version. Skipping version check.\"\n    return 0\n  fi\n\n  if version_gt \"$remote_version\" \"$FOUNDRYUP_INSTALLER_VERSION\"; then\n    printf '\nYour installation of foundryup is out of date.\n\nInstalled: %s → Latest: %s\n\nTo update, run:\n\n  foundryup --update\n\nUpdating is highly recommended as it gives you access to the latest features and bug fixes.\n\n' \"$FOUNDRYUP_INSTALLER_VERSION\" \"$remote_version\" >&2\n  else\n    say \"foundryup is up to date.\"\n  fi\n}\n\n# Compares two version strings in the format \"major.minor.patch\".\n# Returns 0 if $1 is greater than $2, 1 if $1 is less than $2, and 1 if they are equal.\n#\n# Assumes that the version strings are well-formed and contain three numeric components separated by dots.\n#\n# Example: version_gt \"1.2.3\" \"1.2.4\"\n#          returns 1 (1.2.3 < 1.2.4)\n#          version_gt \"1.2.3\" \"1.2.3\"\n#          returns 1 (1.2.3 == 1.2.3)\n#          version_gt \"1.2.4\" \"1.2.3\"\n#          returns 0 (1.2.4 > 1.2.3)\nversion_gt() {\n  [ \"$1\" = \"$2\" ] && return 1\n\n  IFS=. read -r major1 minor1 patch1 <<EOF\n$1\nEOF\n  IFS=. read -r major2 minor2 patch2 <<EOF\n$2\nEOF\n\n  [ \"$major1\" -gt \"$major2\" ] && return 0\n  [ \"$major1\" -lt \"$major2\" ] && return 1\n  [ \"$minor1\" -gt \"$minor2\" ] && return 0\n  [ \"$minor1\" -lt \"$minor2\" ] && return 1\n  [ \"$patch1\" -gt \"$patch2\" ] && return 0\n  [ \"$patch1\" -lt \"$patch2\" ] && return 1\n\n  return 1\n}\n\ncheck_bins_in_use() {\n  if check_cmd pgrep; then\n    for bin in \"${BINS[@]}\"; do\n      if pgrep -x \"$bin\" >/dev/null; then\n        err \"Error: '$bin' is currently running. Please stop the process and try again.\"\n      fi\n    done\n  else\n    warn \"Make sure no foundry process is running during the install process!\"\n  fi\n}\n\n# Run a command that should never fail. If the command fails execution\n# will immediately terminate with an error showing the failing command.\nensure() {\n  if ! \"$@\"; then err \"command failed: $*\"; fi\n}\n\n# Downloads $1 into $2 or stdout\ndownload() {\n  if [ -n \"$2\" ]; then\n    # output into $2\n    if check_cmd curl; then\n      curl -#o \"$2\" -L \"$1\"\n    else\n      wget --show-progress -qO \"$2\" \"$1\"\n    fi\n  else\n    # output to stdout\n    if check_cmd curl; then\n      curl -#L \"$1\"\n    else\n      wget --show-progress -qO- \"$1\"\n    fi\n  fi\n}\n\n# Banner prompt for Foundry\nbanner() {\n  printf '\n\n.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx\n\n ╔═╗ ╔═╗ ╦ ╦ ╔╗╔ ╔╦╗ ╦═╗ ╦ ╦         Portable and modular toolkit\n ╠╣  ║ ║ ║ ║ ║║║  ║║ ╠╦╝ ╚╦╝    for Ethereum Application Development\n ╚   ╚═╝ ╚═╝ ╝╚╝ ═╩╝ ╩╚═  ╩                 written in Rust.\n\n.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx\n\nRepo       : https://github.com/foundry-rs/foundry\nBook       : https://book.getfoundry.sh/\nChat       : https://t.me/foundry_rs/\nSupport    : https://t.me/foundry_support/\nContribute : https://github.com/foundry-rs/foundry/blob/HEAD/CONTRIBUTING.md\n\n.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx.xOx\n\n'\n}\n\n\nmain \"$@\"\n"
  },
  {
    "path": "foundryup/install",
    "content": "#!/usr/bin/env bash\nset -eo pipefail\n\necho \"Installing foundryup...\"\n\nBASE_DIR=\"${XDG_CONFIG_HOME:-$HOME}\"\nFOUNDRY_DIR=\"${FOUNDRY_DIR:-\"$BASE_DIR/.foundry\"}\"\nFOUNDRY_BIN_DIR=\"$FOUNDRY_DIR/bin\"\nFOUNDRY_MAN_DIR=\"$FOUNDRY_DIR/share/man/man1\"\n\nBIN_URL=\"https://raw.githubusercontent.com/foundry-rs/foundry/HEAD/foundryup/foundryup\"\nBIN_PATH=\"$FOUNDRY_BIN_DIR/foundryup\"\n\n# Create the .foundry bin directory and foundryup binary if it doesn't exist.\nmkdir -p \"$FOUNDRY_BIN_DIR\"\ncurl -sSf -L \"$BIN_URL\" -o \"$BIN_PATH\"\nchmod +x \"$BIN_PATH\"\n\n# Create the man directory for future man files if it doesn't exist.\nmkdir -p \"$FOUNDRY_MAN_DIR\"\n\n# Store the correct profile file (i.e. .profile for bash or .zshenv for ZSH).\ncase $SHELL in\n*/zsh)\n    PROFILE=\"${ZDOTDIR-\"$HOME\"}/.zshenv\"\n    PREF_SHELL=zsh\n    ;;\n*/bash)\n    PROFILE=$HOME/.bashrc\n    PREF_SHELL=bash\n    ;;\n*/fish)\n    PROFILE=$HOME/.config/fish/config.fish\n    PREF_SHELL=fish\n    ;;\n*/ash)\n    PROFILE=$HOME/.profile\n    PREF_SHELL=ash\n    ;;\n*)\n    echo \"foundryup: could not detect shell, manually add ${FOUNDRY_BIN_DIR} to your PATH.\"\n    exit 1\nesac\n\n# Only add foundryup if it isn't already in PATH.\nif [[ \":$PATH:\" != *\":${FOUNDRY_BIN_DIR}:\"* ]]; then\n    # Add the foundryup directory to the path and ensure the old PATH variables remain.\n    # If the shell is fish, echo fish_add_path instead of export.\n    if [[ \"$PREF_SHELL\" == \"fish\" ]]; then\n        echo >> \"$PROFILE\" && echo \"fish_add_path -a \\\"$FOUNDRY_BIN_DIR\\\"\" >> \"$PROFILE\"\n    else\n        echo >> \"$PROFILE\" && echo \"export PATH=\\\"\\$PATH:$FOUNDRY_BIN_DIR\\\"\" >> \"$PROFILE\"\n    fi\nfi\n\n# Warn MacOS users that they may need to manually install libusb via Homebrew:\nif [[ \"$OSTYPE\" =~ ^darwin ]] && [[ ! -f /usr/local/opt/libusb/lib/libusb-1.0.0.dylib ]] && [[ ! -f /opt/homebrew/opt/libusb/lib/libusb-1.0.0.dylib ]]; then\n    echo && echo \"warning: libusb not found. You may need to install it manually on MacOS via Homebrew (brew install libusb).\"\nfi\n\necho\necho \"Detected your preferred shell is $PREF_SHELL and added foundryup to PATH.\"\necho \"Run 'source $PROFILE' or start a new terminal session to use foundryup.\"\necho \"Then, simply run 'foundryup' to install Foundry.\"\n"
  },
  {
    "path": "npm/.gitignore",
    "content": "# dependencies (bun install)\nnode_modules\n\n# output\nout\ndist\n*.tgz\n\n# code coverage\ncoverage\n*.lcov\n\n# logs\nlogs\n_.log\nreport.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json\n\n# dotenv environment variable files\n.env\n.env.development.local\n.env.test.local\n.env.production.local\n.env.local\n\n# caches\n.eslintcache\n.cache\n*.tsbuildinfo\n\n# IntelliJ based IDEs\n.idea\n\n# Finder (MacOS) folder config\n.DS_Store\n\nforge/*/bin/forge\nanvil/*/bin/anvil\ncast/*/bin/cast\nchisel/*/bin/chisel\n@foundry-rs/*/bin/\n_\n"
  },
  {
    "path": "npm/@foundry-rs/anvil/README.md",
    "content": "# [Anvil](https://getfoundry.sh/anvil)\n\nAnvil is a fast local Ethereum development node.\nThe anvil binary can be used both within and outside of a Foundry project.\n\n## Usage\n\n### One-off commands\n\nExample\n\n```sh\nnpx --yes @foundry-rs/anvil@nightly\n```\n\nMore generally\n\n```sh\nnpx --yes @foundry-rs/anvil@<version|nightly> [args...]\n```\n\n### Install then use\n\nlocally to your project\n\n```sh\nnpm add @foundry-rs/anvil@nightly\nnpx anvil [args...]\n```\n\nglobally\n\n```sh\nnpm add --global @foundry-rs/anvil@nightly\nanvil [args...]\n```\n\n---\n\nAlso works with `deno`, `bun`, and `pnpm`:\n\n```sh\ndeno run --quiet --allow-all npm:@foundry-rs/anvil@nightly [args...]\n```\n\n```sh\nbun x @foundry-rs/anvil@nightly [args...]\n```\n\n```sh\npnpm dlx --silent @foundry-rs/anvil@nightly [args...]\n```\n"
  },
  {
    "path": "npm/@foundry-rs/anvil/package.json",
    "content": "{\n  \"name\": \"@foundry-rs/anvil\",\n  \"version\": \"0.0.0\",\n  \"type\": \"module\",\n  \"homepage\": \"https://getfoundry.sh/anvil\",\n  \"description\": \"Anvil is a fast local Ethereum development node\",\n  \"bin\": {\n    \"anvil\": \"./bin.mjs\"\n  },\n  \"files\": [\n    \"bin\",\n    \"dist\"\n  ],\n  \"scripts\": {\n    \"postinstall\": \"TARGET_TOOL=anvil node ./dist/postinstall.mjs\"\n  },\n  \"optionalDependencies\": {\n    \"@foundry-rs/anvil-darwin-arm64\": \"0.0.0\",\n    \"@foundry-rs/anvil-darwin-amd64\": \"0.0.0\",\n    \"@foundry-rs/anvil-linux-arm64\": \"0.0.0\",\n    \"@foundry-rs/anvil-linux-amd64\": \"0.0.0\",\n    \"@foundry-rs/anvil-win32-amd64\": \"0.0.0\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"provenance\": true,\n    \"registry\": \"https://registry.npmjs.org\"\n  },\n  \"keywords\": [\n    \"foundry\",\n    \"testing\",\n    \"ethereum\",\n    \"solidity\",\n    \"blockchain\",\n    \"smart-contracts\"\n  ],\n  \"license\": \"MIT OR Apache-2.0\",\n  \"repository\": {\n    \"directory\": \"npm\",\n    \"url\": \"https://github.com/foundry-rs/foundry\"\n  }\n}\n"
  },
  {
    "path": "npm/@foundry-rs/cast/README.md",
    "content": "# [Cast](https://getfoundry.sh/cast)\n\nCast is a Swiss Army knife for interacting with Ethereum applications from the command line.\nYou can make smart contract calls, send transactions, or retrieve any type of chain data - all from your command-line!\nThe cast binary can be used both within and outside of a Foundry project.\n\n## Usage\n\n### One-off commands\n\nExample\n\n```sh\nnpx --yes @foundry-rs/cast@nightly block-number\n```\n\nMore generally\n\n```sh\nnpx --yes @foundry-rs/cast@<version|nightly> <command> [args...]\n```\n\n### Install then use\n\nlocally to your project\n\n```sh\nnpm add @foundry-rs/cast@nightly\nnpx cast <command> [args...]\n```\n\nglobally\n\n```sh\nnpm add --global @foundry-rs/cast@nightly\ncast <command> [args...]\n```\n\n---\n\nAlso works with `deno`, `bun`, and `pnpm`:\n\n```sh\ndeno run --quiet --allow-all npm:@foundry-rs/cast@nightly <command> [args...]\n```\n\n```sh\nbun x @foundry-rs/cast@nightly <command> [args...]\n```\n\n```sh\npnpm dlx --silent @foundry-rs/cast@nightly <command> [args...]\n```\n"
  },
  {
    "path": "npm/@foundry-rs/cast/package.json",
    "content": "{\n  \"name\": \"@foundry-rs/cast\",\n  \"version\": \"0.0.0\",\n  \"type\": \"module\",\n  \"homepage\": \"https://getfoundry.sh/cast\",\n  \"description\": \"Swiss Army knife for interacting with Ethereum applications from the command line\",\n  \"bin\": {\n    \"cast\": \"./bin.mjs\"\n  },\n  \"files\": [\n    \"bin\",\n    \"dist\"\n  ],\n  \"scripts\": {\n    \"postinstall\": \"TARGET_TOOL=cast node ./dist/postinstall.mjs\"\n  },\n  \"optionalDependencies\": {\n    \"@foundry-rs/cast-darwin-arm64\": \"0.0.0\",\n    \"@foundry-rs/cast-darwin-amd64\": \"0.0.0\",\n    \"@foundry-rs/cast-linux-arm64\": \"0.0.0\",\n    \"@foundry-rs/cast-linux-amd64\": \"0.0.0\",\n    \"@foundry-rs/cast-win32-amd64\": \"0.0.0\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"provenance\": true,\n    \"registry\": \"https://registry.npmjs.org\"\n  },\n  \"keywords\": [\n    \"foundry\",\n    \"testing\",\n    \"ethereum\",\n    \"solidity\",\n    \"blockchain\",\n    \"smart-contracts\"\n  ],\n  \"license\": \"MIT OR Apache-2.0\",\n  \"repository\": {\n    \"directory\": \"npm\",\n    \"url\": \"https://github.com/foundry-rs/foundry\"\n  }\n}\n"
  },
  {
    "path": "npm/@foundry-rs/chisel/README.md",
    "content": "# [Chisel](https://getfoundry.sh/chisel)\n\nChisel is a fast, utilitarian, and verbose Solidity REPL.\nThe chisel binary can be used both within and outside of a Foundry project.\n\n## Usage\n\n### One-off commands\n\nExample\n\n```sh\nnpx --yes @foundry-rs/chisel@nightly\n```\n\nMore generally\n\n```sh\nnpx --yes @foundry-rs/chisel@<version|nightly> [args...]\n```\n\n### Install then use\n\nlocally to your project\n\n```sh\nnpm add @foundry-rs/chisel@nightly\nnpx chisel [args...]\n```\n\nglobally\n\n```sh\nnpm add --global @foundry-rs/chisel@nightly\nchisel [args...]\n```\n\n---\n\nAlso works with `deno`, `bun`, and `pnpm`:\n\n```sh\ndeno run --quiet --allow-all npm:@foundry-rs/chisel@nightly [args...]\n```\n\n```sh\nbun x @foundry-rs/chisel@nightly [args...]\n```\n\n```sh\npnpm dlx --silent @foundry-rs/chisel@nightly [args...]\n```\n"
  },
  {
    "path": "npm/@foundry-rs/chisel/package.json",
    "content": "{\n  \"name\": \"@foundry-rs/chisel\",\n  \"version\": \"0.0.0\",\n  \"type\": \"module\",\n  \"homepage\": \"https://getfoundry.sh/chisel\",\n  \"description\": \"Chisel is a fast, utilitarian, and verbose Solidity REPL\",\n  \"bin\": {\n    \"chisel\": \"./bin.mjs\"\n  },\n  \"files\": [\n    \"bin\",\n    \"dist\"\n  ],\n  \"scripts\": {\n    \"postinstall\": \"TARGET_TOOL=chisel node ./dist/postinstall.mjs\"\n  },\n  \"optionalDependencies\": {\n    \"@foundry-rs/chisel-darwin-arm64\": \"0.0.0\",\n    \"@foundry-rs/chisel-darwin-amd64\": \"0.0.0\",\n    \"@foundry-rs/chisel-linux-arm64\": \"0.0.0\",\n    \"@foundry-rs/chisel-linux-amd64\": \"0.0.0\",\n    \"@foundry-rs/chisel-win32-amd64\": \"0.0.0\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"provenance\": true,\n    \"registry\": \"https://registry.npmjs.org\"\n  },\n  \"keywords\": [\n    \"foundry\",\n    \"testing\",\n    \"ethereum\",\n    \"solidity\",\n    \"blockchain\",\n    \"smart-contracts\"\n  ],\n  \"license\": \"MIT OR Apache-2.0\",\n  \"repository\": {\n    \"directory\": \"npm\",\n    \"url\": \"https://github.com/foundry-rs/foundry\"\n  }\n}\n"
  },
  {
    "path": "npm/@foundry-rs/forge/README.md",
    "content": "# [Forge](https://getfoundry.sh/forge)\n\nForge is a command-line tool that ships with Foundry. Forge tests, builds, and deploys your smart contracts.\nThe forge binary can be used both within and outside of a Foundry project.\n\n## Usage\n\n### One-off commands\n\nExample\n\n```sh\nnpx --yes @foundry-rs/forge@nightly init\n```\n\nMore generally\n\n```sh\nnpx --yes @foundry-rs/forge@<version|nightly> <command> [args...]\n```\n\n### Install then use\n\nlocally to your project\n\n```sh\nnpm add @foundry-rs/forge@nightly\nnpx forge <command> [args...]\n```\n\nglobally\n\n```sh\nnpm add --global @foundry-rs/forge@nightly\nforge <command> [args...]\n```\n\n---\n\nAlso works with `deno`, `bun`, and `pnpm`:\n\n```sh\ndeno run --quiet --allow-all npm:@foundry-rs/forge@nightly <command> [args...]\n```\n\n```sh\nbun x @foundry-rs/forge@nightly <command> [args...]\n```\n\n```sh\npnpm dlx --silent @foundry-rs/forge@nightly <command> [args...]\n```\n"
  },
  {
    "path": "npm/@foundry-rs/forge/package.json",
    "content": "{\n  \"name\": \"@foundry-rs/forge\",\n  \"version\": \"0.0.0\",\n  \"type\": \"module\",\n  \"homepage\": \"https://getfoundry.sh/forge\",\n  \"description\": \"Fast and flexible Ethereum testing framework\",\n  \"bin\": {\n    \"forge\": \"./bin.mjs\"\n  },\n  \"files\": [\n    \"bin\",\n    \"dist\"\n  ],\n  \"scripts\": {\n    \"postinstall\": \"TARGET_TOOL=forge node ./dist/postinstall.mjs\"\n  },\n  \"optionalDependencies\": {\n    \"@foundry-rs/forge-darwin-arm64\": \"0.0.0\",\n    \"@foundry-rs/forge-darwin-amd64\": \"0.0.0\",\n    \"@foundry-rs/forge-linux-arm64\": \"0.0.0\",\n    \"@foundry-rs/forge-linux-amd64\": \"0.0.0\",\n    \"@foundry-rs/forge-win32-amd64\": \"0.0.0\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"provenance\": true,\n    \"registry\": \"https://registry.npmjs.org\"\n  },\n  \"keywords\": [\n    \"foundry\",\n    \"testing\",\n    \"ethereum\",\n    \"solidity\",\n    \"blockchain\",\n    \"smart-contracts\"\n  ],\n  \"license\": \"MIT OR Apache-2.0\",\n  \"repository\": {\n    \"directory\": \"npm\",\n    \"url\": \"https://github.com/foundry-rs/foundry\"\n  }\n}\n"
  },
  {
    "path": "npm/README.md",
    "content": "# `@foundry-rs` npm Packages\n\nThis directory contains npm publisher and installer scripts for `forge`, `cast`, `anvil`, and `chisel` and per-arch packages for each:\n\n- [`@foundry-rs/forge`](https://npm.im/@foundry-rs/forge):\n  - `@foundry-rs/forge-darwin-arm64`\n  - `@foundry-rs/forge-darwin-amd64`\n  - `@foundry-rs/forge-linux-arm64`\n  - `@foundry-rs/forge-linux-amd64`\n  - `@foundry-rs/forge-win32-amd64`\n\n- [`@foundry-rs/cast`](https://npm.im/@foundry-rs/cast):\n  - `@foundry-rs/cast-darwin-arm64`\n  - `@foundry-rs/cast-darwin-amd64`\n  - `@foundry-rs/cast-linux-arm64`\n  - `@foundry-rs/cast-linux-amd64`\n  - `@foundry-rs/cast-win32-amd64`\n\n- [`@foundry-rs/anvil`](https://npm.im/@foundry-rs/anvil):\n  - `@foundry-rs/anvil-darwin-arm64`\n  - `@foundry-rs/anvil-darwin-amd64`\n  - `@foundry-rs/anvil-linux-arm64`\n  - `@foundry-rs/anvil-linux-amd64`\n  - `@foundry-rs/anvil-win32-amd64`\n\n- [`@foundry-rs/chisel`](https://npm.im/@foundry-rs/chisel):\n  - `@foundry-rs/chisel-darwin-arm64`\n  - `@foundry-rs/chisel-darwin-amd64`\n  - `@foundry-rs/chisel-linux-arm64`\n  - `@foundry-rs/chisel-linux-amd64`\n  - `@foundry-rs/chisel-win32-amd64`\n"
  },
  {
    "path": "npm/bunfig.toml",
    "content": "telemetry = false\n\nrun.bun = true\n\n[install]\nauto = \"auto\"\n\n[install.scopes]\n\"@foundry-rs\" = { url = \"$NPM_REGISTRY_URL\", username = \"$NPM_USERNAME\" }\n\nlogLevel = \"debug\"\n"
  },
  {
    "path": "npm/env.d.ts",
    "content": "interface ImportMetaEnv {\n  readonly CI: string\n  readonly NPM_TOKEN: string\n  readonly BUN_AUTH_TOKEN: string\n\n  readonly NODE_ENV: 'development' | 'production'\n\n  readonly PROVENANCE: 'true' | 'false'\n\n  TARGET_TOOL: 'forge' | 'cast' | 'anvil' | 'chisel'\n\n  // release.yml#jobs:release:strategy:matrix:include:-|target\n  readonly TARGET:\n    | 'x86_64-unknown-linux-gnu'\n    | 'x86_64-unknown-linux-musl'\n    | 'aarch64-unknown-linux-gnu'\n    | 'aarch64-unknown-linux-musl'\n    | 'x86_64-apple-darwin'\n    | 'aarch64-apple-darwin'\n    | 'x86_64-pc-windows-msvc'\n  // <release.yml#jobs:release:strategy:matrix:include:-|arch>\n  readonly ARCH: 'amd64' | 'arm64' | 'aarch64'\n  readonly IS_NIGHTLY: 'true' | 'false'\n  // `${(env.IS_NIGHTLY == 'true' && 'nightly') || needs.prepare.outputs.tag_name}`\n  readonly VERSION_NAME: string\n  // release.yml#jobs:release:strategy:matrix:include:-|platform\n  readonly PLATFORM_NAME: 'linux' | 'darwin' | 'win32'\n  // `debug` / `release` / `maxperf` / `dist`\n  readonly PROFILE: 'debug' | 'release' | 'maxperf' | 'dist'\n\n  // Used for local testing/development only\n  readonly REGISTRY_URL: string\n  readonly ALLOW_NO_INTEGRITY: 'true' | 'false'\n}\n\ndeclare namespace NodeJS {\n  interface ProcessEnv extends ImportMetaEnv {}\n}\n\ninterface ImportMeta {\n  readonly env: ImportMetaEnv\n}\n\ndeclare namespace Bun {\n  interface Env extends ImportMetaEnv {}\n}\n"
  },
  {
    "path": "npm/package.json",
    "content": "{\n  \"private\": true,\n  \"type\": \"module\",\n  \"imports\": {\n    \"#*\": \"./src/*\",\n    \"#scripts/*\": \"./scripts/*\",\n    \"#package.json\": \"./package.json\"\n  },\n  \"dependencies\": {\n    \"@types/bun\": \"^1.3.1\",\n    \"@types/node\": \"^24.9.1\",\n    \"bun\": \"^1.3.1\",\n    \"typescript\": \"^5.9.3\"\n  },\n  \"license\": \"MIT OR Apache-2.0\",\n  \"$schema\": \"https://json.schemastore.org/package.json\"\n}\n"
  },
  {
    "path": "npm/scripts/check.sh",
    "content": "#!/usr/bin/env bash\n\nset -eou pipefail\n\n# Ensure we're in the npm directory\nSCRIPT_DIR=\"$(cd \"$(dirname \"${BASH_SOURCE[0]}\")\" && pwd)\"\nNPM_DIR=\"$(cd \"$SCRIPT_DIR/..\" && pwd)\"\ncd \"$NPM_DIR\" || exit 1\n\n# Colors for output\nRED='\\033[0;31m'\nGREEN='\\033[0;32m'\nYELLOW='\\033[1;33m'\nBLUE='\\033[0;34m'\nNC='\\033[0m' # No Color\n\ntools=(cast anvil forge chisel)\n\n# Detect current platform\nif [[ \"$(uname)\" == \"Darwin\" ]]; then\n  if [[ \"$(uname -m)\" == \"arm64\" ]]; then\n    TARGET=\"aarch64-apple-darwin\"\n    PLATFORM=\"darwin\"\n    ARCH=\"arm64\"\n  else\n    TARGET=\"x86_64-apple-darwin\"\n    PLATFORM=\"darwin\"\n    ARCH=\"amd64\"\n  fi\nelif [[ \"$(uname)\" == \"Linux\" ]]; then\n  if [[ \"$(uname -m)\" == \"aarch64\" ]]; then\n    TARGET=\"aarch64-unknown-linux-gnu\"\n    PLATFORM=\"linux\"\n    ARCH=\"arm64\"\n  else\n    TARGET=\"x86_64-unknown-linux-gnu\"\n    PLATFORM=\"linux\"\n    ARCH=\"amd64\"\n  fi\nelse\n  echo -e \"${RED}Unsupported platform: $(uname)${NC}\"\n  exit 1\nfi\n\n# Check if we're in CI and can use artifacts\nUSE_ARTIFACTS=false\nif [[ -n \"${CI:-}\" ]] && [[ -n \"${ARTIFACT_DIR:-}\" ]] && [[ -n \"${RELEASE_VERSION:-}\" ]]; then\n  USE_ARTIFACTS=true\n  echo -e \"${BLUE}=== Foundry npm Package Check (CI Mode) ===${NC}\"\n  echo -e \"${BLUE}Using artifacts from: ${ARTIFACT_DIR}${NC}\"\n  echo -e \"${BLUE}Release version: ${RELEASE_VERSION}${NC}\"\nelse\n  echo -e \"${BLUE}=== Foundry npm Package Check (Local Mode) ===${NC}\"\n  echo -e \"${BLUE}Platform: ${PLATFORM}${NC}\"\n  echo -e \"${BLUE}Architecture: ${ARCH}${NC}\"\n  echo -e \"${BLUE}Target: ${TARGET}${NC}\"\nfi\necho \"\"\n\n# Determine total step count and current step\nTOTAL_STEPS=$([[ \"$USE_ARTIFACTS\" == \"true\" ]] && echo \"5\" || echo \"6\")\n\n# Step 1: Build binaries or stage from artifacts\nif [[ \"$USE_ARTIFACTS\" == \"true\" ]]; then\n  echo -e \"${YELLOW}[1/${TOTAL_STEPS}] Staging packages from artifacts…${NC}\"\n  for tool in \"${tools[@]}\"; do\n    echo -e \"  Staging ${tool} from artifacts…\"\n    bun ./scripts/stage-from-artifact.mjs \\\n      --tool \"$tool\" \\\n      --platform \"$PLATFORM\" \\\n      --arch \"$ARCH\" \\\n      --release-version \"$RELEASE_VERSION\" \\\n      --artifact-dir \"$ARTIFACT_DIR\" || {\n      echo -e \"${RED}Failed to stage ${tool} from artifacts${NC}\"\n      exit 1\n    }\n  done\n  echo -e \"${GREEN}✓ All packages staged from artifacts${NC}\"\nelse\n  echo -e \"${YELLOW}[1/${TOTAL_STEPS}] Building tools…${NC}\"\n  for tool in \"${tools[@]}\"; do\n    echo -e \"  Building ${tool}…\"\n    cargo build \\\n      --package \"$tool\" \\\n      --target \"$TARGET\" \\\n      --release || {\n      echo -e \"${RED}Failed to build ${tool}${NC}\"\n      exit 1\n    }\n  done\n  echo -e \"${GREEN}✓ All tools built successfully${NC}\"\nfi\necho \"\"\n\n# Step 2: Stage platform-specific packages (if not using artifacts)\nif [[ \"$USE_ARTIFACTS\" == \"false\" ]]; then\n  echo -e \"${YELLOW}[2/${TOTAL_STEPS}] Staging platform-specific packages…${NC}\"\n  for tool in \"${tools[@]}\"; do\n    echo -e \"  Staging ${tool}…\"\n    BIN_PATH=\"../target/${TARGET}/release/${tool}\"\n    if [[ \"$PLATFORM\" == \"win32\" ]]; then\n      BIN_PATH=\"../target/${TARGET}/release/${tool}.exe\"\n    fi\n    \n    if [[ ! -f \"$BIN_PATH\" ]]; then\n      echo -e \"${RED}Binary not found: ${BIN_PATH}${NC}\"\n      exit 1\n    fi\n    \n    PLATFORM_NAME=\"$PLATFORM\" ARCH=\"$ARCH\" bun ./scripts/prepublish.mjs \\\n      --tool \"$tool\" --bin-path \"$BIN_PATH\" || {\n      echo -e \"${RED}Failed to stage ${tool}${NC}\"\n      exit 1\n    }\n  done\n  echo -e \"${GREEN}✓ All platform-specific packages staged${NC}\"\n  echo \"\"\nfi\n\n# Step 2/3: Verify platform-specific packages\nSTEP_NUM=$([[ \"$USE_ARTIFACTS\" == \"true\" ]] && echo \"2\" || echo \"3\")\necho -e \"${YELLOW}[${STEP_NUM}/${TOTAL_STEPS}] Verifying platform-specific packages…${NC}\"\nfor tool in \"${tools[@]}\"; do\n  PACKAGE_DIR=\"@foundry-rs/${tool}-${PLATFORM}-${ARCH}\"\n  BIN_NAME=\"${tool}\"\n  if [[ \"$PLATFORM\" == \"win32\" ]]; then\n    BIN_NAME=\"${tool}.exe\"\n  fi\n  \n  PACKAGE_JSON=\"${PACKAGE_DIR}/package.json\"\n  BIN_FILE=\"${PACKAGE_DIR}/bin/${BIN_NAME}\"\n  \n  if [[ ! -f \"$PACKAGE_JSON\" ]]; then\n    echo -e \"${RED}Missing package.json: ${PACKAGE_JSON}${NC}\"\n    exit 1\n  fi\n  \n  if [[ ! -f \"$BIN_FILE\" ]]; then\n    echo -e \"${RED}Missing binary: ${BIN_FILE}${NC}\"\n    exit 1\n  fi\n  \n  if [[ \"$PLATFORM\" != \"win32\" ]] && [[ ! -x \"$BIN_FILE\" ]]; then\n    echo -e \"${RED}Binary not executable: ${BIN_FILE}${NC}\"\n    exit 1\n  fi\n  \n  # Validate package.json structure\n  if ! bun -e \"\n    const pkg = JSON.parse(await Bun.file('${PACKAGE_JSON}').text());\n    if (!pkg.name || !pkg.bin || !pkg.bin['${tool}']) {\n      console.error('Invalid package.json structure');\n      process.exit(1);\n    }\n  \"; then\n    echo -e \"${RED}Invalid package.json: ${PACKAGE_JSON}${NC}\"\n    exit 1\n  fi\n  \n  echo -e \"  ✓ ${tool}-${PLATFORM}-${ARCH}\"\ndone\necho -e \"${GREEN}✓ All platform-specific packages verified${NC}\"\necho \"\"\n\n# Step 3/4: Prepare meta packages\nSTEP_NUM=$([[ \"$USE_ARTIFACTS\" == \"true\" ]] && echo \"3\" || echo \"4\")\necho -e \"${YELLOW}[${STEP_NUM}/${TOTAL_STEPS}] Preparing meta packages…${NC}\"\n# Use RELEASE_VERSION if available, otherwise a dummy version for testing\nTEST_VERSION=\"${RELEASE_VERSION:-0.0.0-test}\"\nfor tool in \"${tools[@]}\"; do\n  echo -e \"  Preparing ${tool} meta package…\"\n  RELEASE_VERSION=\"$TEST_VERSION\" bun ./scripts/publish-meta.mjs --tool \"$tool\" --release-version \"$TEST_VERSION\" || {\n    echo -e \"${RED}Failed to prepare ${tool} meta package${NC}\"\n    exit 1\n  }\ndone\necho -e \"${GREEN}✓ All meta packages prepared${NC}\"\necho \"\"\n\n# Step 4/5: Verify meta packages\nSTEP_NUM=$([[ \"$USE_ARTIFACTS\" == \"true\" ]] && echo \"4\" || echo \"5\")\necho -e \"${YELLOW}[${STEP_NUM}/${TOTAL_STEPS}] Verifying meta packages…${NC}\"\nfor tool in \"${tools[@]}\"; do\n  META_DIR=\"@foundry-rs/${tool}\"\n  PACKAGE_JSON=\"${META_DIR}/package.json\"\n  BIN_MJS=\"${META_DIR}/bin.mjs\"\n  CONST_MJS=\"${META_DIR}/const.mjs\"\n  POSTINSTALL_MJS=\"${META_DIR}/postinstall.mjs\"\n  \n  if [[ ! -f \"$PACKAGE_JSON\" ]]; then\n    echo -e \"${RED}Missing package.json: ${PACKAGE_JSON}${NC}\"\n    exit 1\n  fi\n  \n  if [[ ! -f \"$BIN_MJS\" ]]; then\n    echo -e \"${RED}Missing bin.mjs: ${BIN_MJS}${NC}\"\n    exit 1\n  fi\n  \n  if [[ ! -f \"$CONST_MJS\" ]]; then\n    echo -e \"${RED}Missing const.mjs: ${CONST_MJS}${NC}\"\n    exit 1\n  fi\n  \n  if [[ ! -f \"$POSTINSTALL_MJS\" ]]; then\n    echo -e \"${RED}Missing postinstall.mjs: ${POSTINSTALL_MJS}${NC}\"\n    exit 1\n  fi\n  \n  # Verify import map points to const.mjs\n  if ! bun -e \"\n    const pkg = JSON.parse(await Bun.file('${PACKAGE_JSON}').text());\n    if (pkg.imports?.['#const.mjs'] !== './const.mjs') {\n      console.error('Invalid import map: #const.mjs should point to ./const.mjs');\n      console.error('Found:', pkg.imports?.['#const.mjs']);\n      process.exit(1);\n    }\n    if (pkg.bin?.['${tool}'] !== './bin.mjs') {\n      console.error('Invalid bin entry');\n      process.exit(1);\n    }\n  \"; then\n    echo -e \"${RED}Invalid package.json structure for ${tool}${NC}\"\n    exit 1\n  fi\n  \n  # Verify bin.mjs can import from const.mjs\n  CONST_ABS_PATH=\"$(cd \"$META_DIR\" && pwd)/const.mjs\"\n  if ! bun -e \"\n    try {\n      // Try to import const.mjs to verify it exports correctly\n      const constModule = await import('${CONST_ABS_PATH}');\n      const required = ['BINARY_NAME', 'colors', 'KNOWN_TOOLS', 'PLATFORM_SPECIFIC_PACKAGE_NAME', 'resolveTargetTool'];\n      for (const name of required) {\n        if (!(name in constModule)) {\n          console.error(\\`Missing export: \\${name}\\`);\n          process.exit(1);\n        }\n      }\n    } catch (error) {\n      console.error('Failed to import const.mjs:', error.message);\n      process.exit(1);\n    }\n  \"; then\n    echo -e \"${RED}Failed to validate const.mjs exports for ${tool}${NC}\"\n    exit 1\n  fi\n  \n  echo -e \"  ✓ ${tool}\"\ndone\necho -e \"${GREEN}✓ All meta packages verified${NC}\"\necho \"\"\n\n# Step 5/6: Test package packing\nSTEP_NUM=$([[ \"$USE_ARTIFACTS\" == \"true\" ]] && echo \"5\" || echo \"6\")\necho -e \"${YELLOW}[${STEP_NUM}/${TOTAL_STEPS}] Testing package packing…${NC}\"\nfor tool in \"${tools[@]}\"; do\n  META_DIR=\"@foundry-rs/${tool}\"\n  echo -e \"  Packing ${tool}…\"\n  \n  # Test that we can pack the meta package\n  ORIG_DIR=$(pwd)\n  cd \"$META_DIR\" || exit 1\n  \n  # Try to pack and capture output\n  PACK_OUTPUT=$(bun pm pack 2>&1)\n  PACK_EXIT=$?\n  \n  # Clean up any generated .tgz files\n  rm -f -- *.tgz\n  \n  cd \"$ORIG_DIR\" || exit 1\n  \n  if [[ $PACK_EXIT -ne 0 ]]; then\n    echo -e \"${RED}Failed to pack ${tool}${NC}\"\n    echo \"$PACK_OUTPUT\"\n    exit 1\n  fi\n  \n  echo -e \"  ✓ ${tool}\"\ndone\necho -e \"${GREEN}✓ All packages can be packed${NC}\"\necho \"\"\n\necho -e \"${GREEN}=== All checks passed! ===${NC}\"\necho -e \"${BLUE}Ready to publish${NC}\""
  },
  {
    "path": "npm/scripts/prepublish.mjs",
    "content": "#!/usr/bin/env bun\n\nimport * as NodeFS from 'node:fs'\nimport * as NodePath from 'node:path'\nimport * as NodeUtil from 'node:util'\n\nimport { colors, KNOWN_TOOLS, resolveTargetTool } from '#const.mjs'\nimport { generateBinaryPackageJson } from '../src/generate-package-json.mjs'\n\n/**\n * @typedef {import('#const.mjs').Arch} Arch\n * @typedef {import('#const.mjs').Platform} Platform\n * @typedef {import('#const.mjs').Profile} Profile\n * @typedef {import('#const.mjs').Tool} Tool\n */\n\n/**\n * @typedef {{\n *   tool: Tool\n *   platform: Platform\n *   arch: Arch\n *   binaryPath: string\n * }} ResolvedInputs\n */\n\n/**\n * @typedef {{\n *   tool: Tool\n *   platform: Platform\n *   arch: Arch\n *   profile: Profile\n *   cliCandidates: Array<string | undefined>\n * }} ResolveBinaryPathOptions\n */\n\n/**\n * @typedef {{\n *   tool: Tool\n *   platform: Platform\n *   arch: Arch\n *   profile: Profile\n * }} FallbackSearchOptions\n */\n\nconst PLATFORM_MAP = /** @type {const} */ (/** @type {Record<Platform, Platform>} */ ({\n  linux: 'linux',\n  darwin: 'darwin',\n  win32: 'win32'\n}))\n\nconst TARGET_MAP = /** @type {const} */ (/** @type {Record<`${Arch}-${Platform}`, string>} */ ({\n  'amd64-linux': 'x86_64-unknown-linux-gnu',\n  'arm64-linux': 'aarch64-unknown-linux-gnu',\n  'amd64-darwin': 'x86_64-apple-darwin',\n  'arm64-darwin': 'aarch64-apple-darwin',\n  'amd64-win32': 'x86_64-pc-windows-msvc'\n}))\n\nconst PRESERVE = new Set(['package.json', 'README.md'])\nconst GENERIC_BIN_ENV_KEYS = [\n  'BIN_PATH',\n  'bin_path',\n  'BIN',\n  'BINARY_PATH',\n  'binary_path',\n  'TARGET_BIN_PATH',\n  'target_bin_path',\n  'TARGET_BINARY_PATH',\n  'target_binary_path'\n]\n\nconst TOOL_ENV_KEYS = /** @type {Record<Tool, readonly string[]>} */ ({\n  forge: ['forge_bin_path', 'FORGE_BIN_PATH'],\n  cast: ['cast_bin_path', 'CAST_BIN_PATH'],\n  anvil: ['anvil_bin_path', 'ANVIL_BIN_PATH'],\n  chisel: ['chisel_bin_path', 'CHISEL_BIN_PATH']\n})\n\nmain().catch(error => {\n  console.error(colors.red, error)\n  process.exit(1)\n})\n\n/**\n * Orchestrates package preparation for the current platform/tool pair.\n * @returns {Promise<void>}\n */\nasync function main() {\n  const { tool, platform, arch, binaryPath } = resolveInputs()\n  const packagePath = NodePath.join(process.cwd(), '@foundry-rs', `${tool}-${platform}-${arch}`)\n\n  await NodeFS.promises.mkdir(packagePath, { recursive: true, mode: 0o755 })\n  console.info(colors.green, `Ensured package directory at ${packagePath}`, colors.reset)\n\n  await generateBinaryPackageJson({ tool, platform, arch, packagePath })\n  await cleanPackageDirectory(packagePath)\n  await copyBinary({ source: binaryPath, tool, packagePath, platform })\n\n  console.info(colors.green, 'Binary copy completed successfully!', colors.reset)\n}\n\n/**\n * Collects CLI/env inputs, normalises them, and resolves the binary path.\n * @returns {ResolvedInputs}\n */\nfunction resolveInputs() {\n  const parsed = NodeUtil.parseArgs({\n    args: Bun.argv.slice(2),\n    allowPositionals: true,\n    options: {\n      tool: { type: 'string' },\n      binary: { type: 'string' },\n      bin: { type: 'string' },\n      'bin-path': { type: 'string' },\n      'binary-path': { type: 'string' }\n    },\n    strict: true\n  })\n\n  const platformEnv = Bun.env.PLATFORM_NAME || ''\n  const archEnv = Bun.env.ARCH || ''\n\n  const platform = PLATFORM_MAP[platformEnv]\n  const arch = archEnv === 'aarch64' ? 'arm64' : archEnv\n\n  if (!platform || (arch !== 'amd64' && arch !== 'arm64'))\n    throw new Error(`Invalid platform or architecture: platform=${platformEnv}, arch=${archEnv}`)\n\n  const tool = resolveTool([\n    parsed.values.tool,\n    parsed.positionals[0],\n    Bun.env.TARGET_TOOL,\n    Bun.env.TOOL,\n    Bun.env.BINARY_TOOL\n  ])\n\n  const profile = Bun.env.NODE_ENV === 'production' ? 'release' : Bun.env.PROFILE || 'release'\n  const binaryPath = resolveBinaryPath({\n    tool,\n    platform,\n    arch,\n    profile,\n    cliCandidates: [\n      parsed.values.binary,\n      parsed.values.bin,\n      parsed.values['bin-path'],\n      parsed.values['binary-path'],\n      parsed.positionals[1]\n    ]\n  })\n\n  return { tool, platform, arch, binaryPath }\n}\n\n/**\n * Picks the first candidate that resolves to a known tool.\n * @param {Array<string | undefined>} candidates\n * @returns {Tool}\n */\nfunction resolveTool(candidates) {\n  for (const candidate of candidates) {\n    if (typeof candidate !== 'string' || candidate.trim() === '') continue\n    try {\n      return resolveTargetTool(candidate)\n    } catch {\n      // try the next candidate\n    }\n  }\n\n  throw new Error(`Tool not specified. Provide --tool=<${KNOWN_TOOLS.join('|')}> or set TARGET_TOOL.`)\n}\n\n/**\n * Resolves the filesystem path to the tool binary, honouring CLI/env overrides.\n * @param {ResolveBinaryPathOptions} options\n * @returns {string}\n */\nfunction resolveBinaryPath({ tool, platform, arch, profile, cliCandidates }) {\n  const envCandidates = [\n    ...GENERIC_BIN_ENV_KEYS,\n    ...(TOOL_ENV_KEYS[tool] ?? [])\n  ].map(readEnv)\n\n  for (const candidate of [...cliCandidates, ...envCandidates]) {\n    if (typeof candidate === 'string' && candidate.trim())\n      return NodePath.resolve(candidate.trim())\n  }\n\n  return findBinaryFallback({ tool, platform, arch, profile })\n}\n\n/**\n * Searches the local Cargo build artefacts for the requested binary as a fallback.\n * @param {FallbackSearchOptions} options\n * @returns {string}\n */\nfunction findBinaryFallback({ tool, platform, arch, profile }) {\n  const targetDir = TARGET_MAP[`${arch}-${platform}`]\n  const binaryName = platform === 'win32' ? `${tool}.exe` : tool\n  const searchOrder = []\n\n  if (targetDir)\n    searchOrder.push(NodePath.join(process.cwd(), '..', 'target', targetDir, profile, binaryName))\n\n  searchOrder.push(\n    NodePath.join(process.cwd(), '..', 'target', profile, binaryName),\n    NodePath.join(process.cwd(), '..', 'target', 'release', binaryName)\n  )\n\n  for (const candidate of searchOrder)\n    if (candidate && NodeFS.existsSync(candidate)) return candidate\n\n  throw new Error(`Source binary for ${tool} not found. Looked in: ${searchOrder.join(', ')}`)\n}\n\n/**\n * Removes previously staged files while preserving metadata such as README/package.json.\n * @param {string} packagePath\n * @returns {Promise<void>}\n */\nasync function cleanPackageDirectory(packagePath) {\n  const items = await NodeFS.promises.readdir(packagePath).catch(() => [])\n\n  for (const item of items) {\n    if (PRESERVE.has(item)) continue\n    NodeFS.rmSync(NodePath.join(packagePath, item), { recursive: true, force: true })\n  }\n\n  console.info(colors.green, 'Cleaned up package directory', colors.reset)\n}\n\n/**\n * Copies the tool binary into the package directory.\n * @param {{ source: string; tool: Tool; packagePath: string; platform: Platform }} parameters\n * @returns {Promise<void>}\n */\nasync function copyBinary({ source, tool, packagePath, platform }) {\n  if (!(await Bun.file(source).exists()))\n    throw new Error(`Source binary not found at ${source}`)\n\n  const binaryName = platform === 'win32' ? `${tool}.exe` : tool\n  const targetDir = NodePath.join(packagePath, 'bin')\n\n  NodeFS.mkdirSync(targetDir, { recursive: true })\n\n  const targetPath = NodePath.join(targetDir, binaryName)\n  console.info(colors.green, `Copying ${source} to ${targetPath}`, colors.reset)\n\n  await Bun.write(targetPath, Bun.file(source))\n\n  if (platform !== 'win32')\n    NodeFS.chmodSync(targetPath, 0o755)\n}\n\n/**\n * Reads an environment variable, falling back across case variants.\n * @param {string | undefined} key\n * @returns {string | undefined}\n */\nfunction readEnv(key) {\n  if (!key) return undefined\n  return Bun.env[key] ?? Bun.env[key.toUpperCase()] ?? Bun.env[key.toLowerCase()]\n}\n"
  },
  {
    "path": "npm/scripts/publish-meta.mjs",
    "content": "#!/usr/bin/env bun\n\nimport * as NodeFS from 'node:fs/promises'\nimport * as NodePath from 'node:path'\nimport * as NodeUtil from 'node:util'\n\nimport { colors, KNOWN_TOOLS } from '#const.mjs'\n\n/**\n * @typedef {import('#const.mjs').Tool} Tool\n */\n\nmain().catch(error => {\n  console.error(colors.red, error)\n  console.error(colors.reset)\n  process.exit(1)\n})\n\n/**\n * Publish each meta package (`@foundry-rs/<tool>`) to npm.\n * @returns {Promise<void>}\n */\nasync function main() {\n  const { tools, releaseVersion } = resolveArgs()\n\n  for (const tool of tools) {\n    await prepareMetaPackage(tool)\n    const packageDir = NodePath.join('@foundry-rs', tool)\n    console.info(colors.green, `Publishing meta package ${packageDir}`, colors.reset)\n\n    const result = await Bun\n      .$`bun ./scripts/publish.mjs ${packageDir}`\n      .cwd(NodePath.resolve(import.meta.dir, '..'))\n      .env({\n        ...process.env,\n        TARGET_TOOL: tool,\n        TOOL: tool,\n        RELEASE_VERSION: releaseVersion,\n        VERSION_NAME: releaseVersion\n      })\n      .nothrow()\n\n    if (result.exitCode !== 0) {\n      const stderr = typeof result.stderr === 'string' ? result.stderr : result.stderr?.toString('utf8')\n      const stdout = typeof result.stdout === 'string' ? result.stdout : result.stdout?.toString('utf8')\n      throw new Error(stderr || stdout || `Failed to publish ${packageDir}`)\n    }\n  }\n}\n\n/**\n * Resolve CLI arguments and defaults.\n * @returns {{ tools: Tool[]; releaseVersion: string }}\n */\nfunction resolveArgs() {\n  const { values, positionals } = NodeUtil.parseArgs({\n    args: Bun.argv.slice(2),\n    allowPositionals: true,\n    options: {\n      tool: { type: 'string', multiple: true },\n      tools: { type: 'string', multiple: true },\n      'release-version': { type: 'string' },\n      release: { type: 'string' }\n    },\n    strict: true\n  })\n\n  const releaseCandidate = values['release-version']\n    || values.release\n    || process.env.RELEASE_VERSION\n    || process.env.VERSION_NAME\n    || ''\n\n  const releaseVersion = releaseCandidate.trim()\n  if (!releaseVersion)\n    throw new Error('Missing required RELEASE_VERSION')\n\n  const explicitTools = [...(values.tool ?? []), ...(values.tools ?? []), ...positionals]\n\n  const selected = explicitTools.length ? explicitTools : KNOWN_TOOLS\n  const tools = /** @type {Tool[]} */ (selected.map(candidate => {\n    const trimmed = candidate.trim()\n    if (!trimmed) return undefined\n    const maybeTool = /** @type {Tool} */ (trimmed)\n    if (!KNOWN_TOOLS.includes(maybeTool))\n      throw new Error(`Unsupported tool: ${candidate}`)\n    return maybeTool\n  }).filter(Boolean))\n\n  return { tools, releaseVersion }\n}\n\n/**\n * Ensure the meta package directory contains the runtime files.\n * @param {Tool} tool\n * @returns {Promise<void>}\n */\nasync function prepareMetaPackage(tool) {\n  const npmDir = NodePath.resolve(import.meta.dir, '..')\n  const sourceDir = NodePath.join(npmDir, 'src')\n  const metaDir = NodePath.join(npmDir, '@foundry-rs', tool)\n  await NodeFS.rm(NodePath.join(metaDir, 'dist'), { recursive: true, force: true })\n\n  const postinstallPath = NodePath.join(metaDir, 'postinstall.mjs')\n  const buildResult = await Bun\n    .$`bun build ${NodePath.join(sourceDir, 'install.mjs')} --format esm --outfile ${postinstallPath} --target node`\n    .cwd(npmDir)\n    .nothrow()\n\n  if (buildResult.exitCode !== 0) {\n    const stderr = typeof buildResult.stderr === 'string'\n      ? buildResult.stderr\n      : buildResult.stderr?.toString('utf8')\n    const stdout = typeof buildResult.stdout === 'string'\n      ? buildResult.stdout\n      : buildResult.stdout?.toString('utf8')\n    throw new Error(stderr || stdout || 'Failed to build postinstall script')\n  }\n\n  const binSource = await NodeFS.readFile(NodePath.join(sourceDir, 'bin.mjs'), 'utf8')\n  await NodeFS.writeFile(NodePath.join(metaDir, 'bin.mjs'), binSource)\n\n  const constSource = await NodeFS.readFile(NodePath.join(sourceDir, 'const.mjs'), 'utf8')\n  await NodeFS.writeFile(NodePath.join(metaDir, 'const.mjs'), constSource)\n\n  const packageJsonPath = NodePath.join(metaDir, 'package.json')\n  const pkg = JSON.parse(await NodeFS.readFile(packageJsonPath, 'utf8'))\n  pkg.imports = { ...(pkg.imports || {}), '#const.mjs': './const.mjs' }\n  pkg.scripts = { ...(pkg.scripts || {}), postinstall: `TARGET_TOOL=${tool} node ./postinstall.mjs` }\n\n  const files = new Set([...(pkg.files ?? [])])\n  files.delete('dist')\n  files.delete('bin')\n  files.add('bin.mjs')\n  files.add('const.mjs')\n  files.add('postinstall.mjs')\n  pkg.files = Array.from(files)\n\n  await NodeFS.writeFile(packageJsonPath, JSON.stringify(pkg, null, 2) + '\\n')\n}\n"
  },
  {
    "path": "npm/scripts/publish.mjs",
    "content": "#!/usr/bin/env bun\n\nimport * as NodeFS from 'node:fs'\nimport * as NodePath from 'node:path'\n\nimport { colors } from '#const.mjs'\n\nconst REGISTRY_URL = Bun.env.NPM_REGISTRY_URL || 'https://registry.npmjs.org'\n\nconst NPM_TOKEN = Bun.env.NPM_TOKEN\nif (!NPM_TOKEN) throw new Error('NPM_TOKEN is required')\n\nmain().catch(error => {\n  console.error(error)\n  process.exit(1)\n})\n\nasync function main() {\n  const npmToken = Bun.env.NPM_TOKEN\n  if (!npmToken) throw new Error('NPM_TOKEN is required')\n\n  const inputPath = Bun.argv[2]\n  if (!inputPath) throw new Error('Package path is required')\n  const packagePath = NodePath.resolve(inputPath)\n  console.info(colors.green, 'Package path:', packagePath)\n\n  const publishVersion = getPublishVersion()\n  console.info(colors.green, 'Publish version:', publishVersion)\n  if (!publishVersion) throw new Error('Publish version is required')\n\n  if (await isMetaPackage(packagePath))\n    await updateOptionalDependencies(packagePath, publishVersion)\n\n  await setPackageVersion(packagePath, publishVersion)\n  const packedFile = await packPackage(packagePath)\n  await publishPackage(packagePath, packedFile, publishVersion)\n}\n\n/**\n * @returns {string}\n */\nfunction getPublishVersion() {\n  const maybeVersion = (Bun.env.VERSION_NAME || '').replace(/^v/, '')\n  if (maybeVersion && Bun.semver.satisfies(maybeVersion, maybeVersion)) return maybeVersion\n\n  const bump = (Bun.env.BUMP_VERSION || '').replace(/^v/, '')\n  if (bump && (!!bump && Bun.semver.satisfies(bump, bump))) return bump\n\n  const releaseVersion = (Bun.env.RELEASE_VERSION || '').replace(/^v/, '')\n  const isNightly = releaseVersion.toLowerCase() === 'nightly' || Bun.env.IS_NIGHTLY === 'true'\n\n  const cargoToml = NodeFS.readFileSync(\n    NodePath.join(import.meta.dirname, '..', '..', 'Cargo.toml'),\n    'utf-8'\n  )\n\n  const versionMatch = cargoToml.match(/^version\\s*=\\s*\"([^\"]+)\"/m)\n  if (!versionMatch) throw new Error('Version not found in Cargo.toml')\n\n  const [, base] = versionMatch\n  if (!base) throw new Error('Version not found in Cargo.toml')\n  if (!isNightly) return base\n\n  const date = new Date()\n  const y = date.getUTCFullYear()\n  const m = String(date.getUTCMonth() + 1).padStart(2, '0')\n  const d = String(date.getUTCDate()).padStart(2, '0')\n  const yyyymmdd = `${y}${m}${d}`\n  const sha = (Bun.env.GITHUB_SHA || '').slice(0, 7)\n  const suffix = sha ? `nightly.${yyyymmdd}.${sha}` : `nightly.${yyyymmdd}`\n  return `${base}-${suffix}`\n}\n\n/**\n * @param {string} packagePath\n * @param {string} version\n * @returns {Promise<void>}\n */\nasync function updateOptionalDependencies(packagePath, version) {\n  const packageJsonPath = NodePath.join(packagePath, 'package.json')\n  const packageJson = JSON.parse(NodeFS.readFileSync(packageJsonPath, 'utf-8'))\n\n  if (packageJson.optionalDependencies) {\n    Object.keys(packageJson.optionalDependencies).forEach(key => {\n      packageJson.optionalDependencies[key] = version\n    })\n\n    await Bun.write(packageJsonPath, JSON.stringify(packageJson, null, 2))\n  }\n}\n\n/**\n * @param {string} packagePath\n * @returns {Promise<boolean>}\n */\nasync function isMetaPackage(packagePath) {\n  try {\n    const packageJsonPath = NodePath.join(packagePath, 'package.json')\n    const packageJson = JSON.parse(NodeFS.readFileSync(packageJsonPath, 'utf-8'))\n    return ['@foundry-rs/forge', '@foundry-rs/cast', '@foundry-rs/anvil', '@foundry-rs/chisel'].includes(\n      packageJson?.name\n    )\n  } catch {\n    return false\n  }\n}\n\n/**\n * @param {string} packagePath\n * @param {string} version\n * @returns {Promise<void>}\n */\nasync function setPackageVersion(packagePath, version) {\n  console.info(colors.green, 'Setting package version:', version)\n  const result = await Bun.$`npm version ${version} --allow-same-version --no-git-tag-version`\n    .cwd(packagePath)\n    .env({\n      ...Bun.env,\n      ...process.env,\n      NPM_TOKEN\n    })\n    .quiet()\n    .nothrow()\n\n  if (result.exitCode !== 0)\n    throw new Error(`Failed to set version: ${result.stderr}`)\n}\n\n/**\n * @param {string} packagePath\n * @returns {Promise<string>}\n */\nasync function packPackage(packagePath) {\n  let packedFile = ''\n\n  for await (const line of Bun.$`bun pm pack`.cwd(packagePath).lines())\n    if (line.endsWith('.tgz')) packedFile = line\n\n  if (!packedFile) throw new Error('Failed to pack package')\n  return packedFile\n}\n\n/**\n * @param {string} packagePath\n * @param {string} packedFile\n * @param {string} version\n * @returns {Promise<void>}\n */\nasync function publishPackage(packagePath, packedFile, version) {\n  const tag = /-nightly(\\.|$)/.test(version) ? 'nightly' : 'latest'\n  const result = await Bun\n    .$`npm publish ./${packedFile} --access=public --registry=${REGISTRY_URL} --tag=${tag} --provenance=${\n    Bun.env.PROVENANCE || 'true'\n  }`\n    .cwd(packagePath)\n    .nothrow()\n\n  if (result.exitCode !== 0)\n    throw new Error(`Publish failed: ${result.stderr}`)\n}\n"
  },
  {
    "path": "npm/scripts/stage-from-artifact.mjs",
    "content": "#!/usr/bin/env bun\n\nimport * as NodeFS from 'node:fs/promises'\nimport * as NodeOS from 'node:os'\nimport * as NodePath from 'node:path'\nimport * as NodeUtil from 'node:util'\n\nimport { colors } from '#const.mjs'\n\n/**\n * @typedef {import('#const.mjs').Tool} Tool\n * @typedef {import('#const.mjs').Platform} Platform\n * @typedef {import('#const.mjs').Arch} Arch\n */\n\nconst RELEASE_ARTIFACT_PREFIX = 'foundry'\n\nmain().catch(error => {\n  console.error(colors.red, error)\n  console.error(colors.reset)\n  process.exit(1)\n})\n\n/**\n * Entry point: locate the platform-specific artifact, extract the binary,\n * and delegate to prepublish to stage it into the package directory.\n * @returns {Promise<void>}\n */\nasync function main() {\n  const { tool, platform, arch, releaseVersion, artifactDir } = resolveArgs()\n\n  const artifactPrefix = NodePath.join(\n    artifactDir,\n    `${RELEASE_ARTIFACT_PREFIX}_${releaseVersion}_${platform}_${arch}`\n  )\n\n  const archivePath = await chooseArchive(artifactPrefix)\n  const extractionDir = await extractArchive(archivePath)\n\n  try {\n    const binaryPath = await resolveExtractedBinary({ tool, platform, extractionDir })\n    await stagePackage({ tool, platform, arch, binaryPath })\n  } finally {\n    await NodeFS.rm(extractionDir, { recursive: true, force: true })\n  }\n}\n\n/**\n * Parse CLI arguments/environment.\n * @returns {{ tool: Tool; platform: Platform; arch: Arch; releaseVersion: string; artifactDir: string }}\n */\nfunction resolveArgs() {\n  const { values } = NodeUtil.parseArgs({\n    args: Bun.argv.slice(2),\n    options: {\n      tool: { type: 'string' },\n      platform: { type: 'string' },\n      arch: { type: 'string' },\n      release: { type: 'string' },\n      'release-version': { type: 'string' },\n      artifacts: { type: 'string' },\n      'artifact-dir': { type: 'string' }\n    },\n    strict: true\n  })\n\n  const tool = requireValue(values.tool || process.env.TARGET_TOOL, 'tool')\n  const platform = requireValue(values.platform || process.env.PLATFORM_NAME, 'platform')\n  const arch = requireValue(values.arch || process.env.ARCH, 'arch')\n  const releaseVersion = requireValue(\n    values.release || values['release-version'] || process.env.RELEASE_VERSION,\n    'release version'\n  )\n  const artifactDir = requireValue(\n    values.artifacts || values['artifact-dir'] || process.env.ARTIFACT_DIR,\n    'artifact directory'\n  )\n\n  return /** @type {{ tool: Tool; platform: Platform; arch: Arch; releaseVersion: string; artifactDir: string }} */ ({\n    tool: /** @type {Tool} */ (tool),\n    platform: /** @type {Platform} */ (platform),\n    arch: /** @type {Arch} */ (arch),\n    releaseVersion,\n    artifactDir: NodePath.resolve(artifactDir)\n  })\n}\n\n/**\n * @param {string | undefined} value\n * @param {string} name\n * @returns {string}\n */\nfunction requireValue(value, name) {\n  if (typeof value === 'string' && value.trim()) return value.trim()\n  throw new Error(`Missing required ${name}`)\n}\n\n/**\n * Determine which archive variant exists for the given artifact prefix.\n * @param {string} prefix\n * @returns {Promise<string>}\n */\nasync function chooseArchive(prefix) {\n  const tarPath = `${prefix}.tar.gz`\n  const zipPath = `${prefix}.zip`\n\n  if (await pathExists(tarPath)) return tarPath\n  if (await pathExists(zipPath)) return zipPath\n\n  throw new Error(`No release artifact found for prefix ${prefix}`)\n}\n\n/**\n * @param {string} filePath\n * @returns {Promise<boolean>}\n */\nasync function pathExists(filePath) {\n  try {\n    await NodeFS.access(filePath)\n    return true\n  } catch {\n    return false\n  }\n}\n\n/**\n * Extract the archive into a temporary directory.\n * @param {string} archivePath\n * @returns {Promise<string>}\n */\nasync function extractArchive(archivePath) {\n  const tempDir = await NodeFS.mkdtemp(NodePath.join(NodeOS.tmpdir(), 'foundry-npm-'))\n  const command = archivePath.endsWith('.zip')\n    ? Bun.$`unzip -o ${archivePath} -d ${tempDir}`\n    : Bun.$`tar -xzf ${archivePath} -C ${tempDir}`\n\n  const result = await command\n    .env(process.env)\n    .nothrow()\n\n  if (result.exitCode !== 0) {\n    const stderr = typeof result.stderr === 'string'\n      ? result.stderr\n      : result.stderr?.toString('utf8')\n    const stdout = typeof result.stdout === 'string'\n      ? result.stdout\n      : result.stdout?.toString('utf8')\n    throw new Error(`Failed to extract ${archivePath}: ${stderr || stdout || 'unknown error'}`)\n  }\n\n  return tempDir\n}\n\n/**\n * Locate the expected binary within the extraction directory.\n * @param {{ tool: Tool; platform: Platform; extractionDir: string }} options\n * @returns {Promise<string>}\n */\nasync function resolveExtractedBinary({ tool, platform, extractionDir }) {\n  const binaryName = platform === 'win32' ? `${tool}.exe` : tool\n  const candidate = NodePath.join(extractionDir, binaryName)\n\n  if (await pathExists(candidate)) return candidate\n\n  throw new Error(`Binary ${binaryName} not found in ${extractionDir}`)\n}\n\n/**\n * Delegate to prepublish to stage the extracted binary into the package dir.\n * @param {{ tool: Tool; platform: Platform; arch: Arch; binaryPath: string }} options\n * @returns {Promise<void>}\n */\nasync function stagePackage({ tool, platform, arch, binaryPath }) {\n  console.info(colors.green, `Staging ${tool} (${platform}/${arch}) from ${binaryPath}`, colors.reset)\n\n  const subprocess = Bun\n    .$`bun ./scripts/prepublish.mjs --tool ${tool} --binary ${binaryPath}`\n    .cwd(NodePath.resolve(import.meta.dir, '..'))\n    .env({\n      ...process.env,\n      TARGET_TOOL: tool,\n      TOOL: tool,\n      PLATFORM_NAME: platform,\n      ARCH: arch\n    })\n\n  const result = await subprocess.nothrow()\n  if (result.exitCode !== 0) {\n    const stderr = typeof result.stderr === 'string'\n      ? result.stderr\n      : result.stderr?.toString('utf8')\n    throw new Error(stderr || `Failed to stage package for ${tool}`)\n  }\n}\n"
  },
  {
    "path": "npm/src/bin.mjs",
    "content": "#!/usr/bin/env node\n\nimport { BINARY_NAME, colors, KNOWN_TOOLS, PLATFORM_SPECIFIC_PACKAGE_NAME, resolveTargetTool } from '#const.mjs'\nimport * as NodeChildProcess from 'node:child_process'\nimport * as NodeFS from 'node:fs'\nimport * as NodeModule from 'node:module'\nimport * as NodePath from 'node:path'\nimport { fileURLToPath } from 'node:url'\n\n/**\n * @typedef {import('#const.mjs').Tool} Tool\n */\n\nconst require = NodeModule.createRequire(import.meta.url)\nconst __dirname = NodePath.dirname(fileURLToPath(import.meta.url))\n\nconst targetTool = resolveTool()\nprocess.env.TARGET_TOOL ??= targetTool\n\nconst binaryName = BINARY_NAME(targetTool)\nconst platformPackage = PLATFORM_SPECIFIC_PACKAGE_NAME(targetTool)\n\nif (!platformPackage) {\n  console.error(colors.red, 'Platform not supported!')\n  console.error(colors.reset)\n  console.error(colors.yellow, `Platform: ${process.platform}, Architecture: ${process.arch}`)\n  console.error(colors.reset)\n  process.exit(1)\n}\n\nconst child = NodeChildProcess.spawn(\n  selectBinaryPath(),\n  process.argv.slice(2),\n  { stdio: 'inherit' }\n)\n\n/**\n * @type {Record<'SIGINT' | 'SIGTERM', () => void>}\n */\nconst signalHandlers = {\n  SIGINT: () => forwardSignal('SIGINT'),\n  SIGTERM: () => forwardSignal('SIGTERM')\n}\n\nfor (const [signal, handler] of Object.entries(signalHandlers))\n  process.on(signal, handler)\n\n/**\n * Determines which tool wrapper is executing.\n * @returns {Tool}\n */\nfunction resolveTool() {\n  const candidates = [\n    process.env.TARGET_TOOL,\n    toolFromPackageName(process.env.npm_package_name),\n    toolFromLocalPackage(),\n    toolFromPath()\n  ]\n\n  for (const candidate of candidates) {\n    if (!candidate) continue\n    try {\n      return resolveTargetTool(candidate)\n    } catch {\n      // try next\n    }\n  }\n\n  throw new Error('TARGET_TOOL must be set to one of: ' + KNOWN_TOOLS.join(', '))\n}\n\n/**\n * Attempts to read the tool name from the nearest package.json.\n * @returns {Tool | undefined}\n */\nfunction toolFromLocalPackage() {\n  try {\n    const packageJsonPath = NodePath.join(__dirname, 'package.json')\n    if (!NodeFS.existsSync(packageJsonPath)) return undefined\n    const pkg = require(packageJsonPath)\n    return toolFromPackageName(pkg?.name)\n  } catch {\n    return undefined\n  }\n}\n\n/**\n * Extracts the tool name from an @foundry-rs scoped package identifier.\n * @param {unknown} name\n * @returns {Tool | undefined}\n */\nfunction toolFromPackageName(name) {\n  if (typeof name !== 'string') return undefined\n  const match = name.match(/^@foundry-rs\\/(forge|cast|anvil|chisel)(?:$|-)/)\n  return match ? /** @type {Tool} */ (match[1]) : undefined\n}\n\n/**\n * Walks up the directory tree to infer the tool name from the folder structure.\n * @returns {Tool | undefined}\n */\nfunction toolFromPath() {\n  const segments = NodePath.resolve(__dirname).split(NodePath.sep)\n  for (let i = segments.length - 1; i >= 0; i--) {\n    const candidate = segments[i]\n    if (isTool(candidate)) return candidate\n  }\n  return undefined\n}\n\n/**\n * Type guard verifying a candidate string is a known tool.\n * @param {string | undefined} candidate\n * @returns {candidate is Tool}\n */\nfunction isTool(candidate) {\n  if (typeof candidate !== 'string') return false\n  return KNOWN_TOOLS.includes(/** @type {Tool} */ (candidate))\n}\n\n/**\n * Determines the executable file path for the current platform.\n * @returns {string}\n */\nfunction selectBinaryPath() {\n  try {\n    const candidate = require.resolve(`${platformPackage}/bin/${binaryName}`)\n    if (NodeFS.existsSync(candidate)) return candidate\n  } catch {\n    // fall through to dist/ binary\n  }\n\n  return NodePath.join(__dirname, '..', 'dist', binaryName)\n}\n\n/**\n * Forwards a received signal to the child process, then re-emits it locally to\n * preserve Node.js default exit semantics.\n * @param {'SIGINT' | 'SIGTERM'} signal\n */\nfunction forwardSignal(signal) {\n  try {\n    if (!child.killed)\n      child.kill(signal)\n  } catch (error) {\n    if (!error || (typeof error === 'object' && 'code' in error && error.code !== 'ESRCH'))\n      throw error\n  }\n\n  process.off(signal, signalHandlers[signal])\n  process.kill(process.pid, signal)\n}\n"
  },
  {
    "path": "npm/src/const.mjs",
    "content": "import * as NodePath from 'node:path'\n\n/**\n * @typedef {'amd64' | 'arm64'} Arch\n * @typedef {'linux' | 'darwin' | 'win32'} Platform\n * @typedef {'forge' | 'cast' | 'anvil' | 'chisel'} Tool\n * @typedef {'debug' | 'release' | 'maxperf' | 'dist'} Profile\n */\n\n/** @type {readonly Tool[]} */\nexport const KNOWN_TOOLS = Object.freeze(['forge', 'cast', 'anvil', 'chisel'])\n\nconst TOOL_SET = new Set(KNOWN_TOOLS)\n\n/**\n * @param {string | undefined} [raw]\n * @returns {Tool}\n *\n * could be process.argv[2]\n */\nexport function resolveTargetTool(raw = process.env.TARGET_TOOL || process.argv[2]) {\n  const value = typeof raw === 'string' ? raw.trim() : ''\n  if (!value)\n    throw new Error('TARGET_TOOL must be set to one of: ' + KNOWN_TOOLS.join(', '))\n  if (value !== NodePath.basename(value) || value.includes('..') || value.includes('/') || value.includes('\\\\'))\n    throw new Error('TARGET_TOOL contains invalid path segments')\n  // @ts-expect-error _\n  if (!TOOL_SET.has(value))\n    throw new Error(`TARGET_TOOL \"${value}\" is not supported. Expected: ${KNOWN_TOOLS.join(', ')}`)\n  return /** @type {Tool} */ (value)\n}\n\nexport function getRegistryUrl() {\n  // Prefer npm's configured registry (works with Verdaccio and custom registries)\n  // Fallback to REGISTRY_URL for tests/dev, then npmjs\n  return (\n    process.env.npm_config_registry\n    || process.env.REGISTRY_URL\n    || 'https://registry.npmjs.org'\n  )\n}\n\n/**\n * @param {Tool} tool\n * @returns {Record<Platform, Record<string, string>>}\n */\nexport const BINARY_DISTRIBUTION_PACKAGES = tool => ({\n  darwin: {\n    x64: `@foundry-rs/${tool}-darwin-amd64`,\n    arm64: `@foundry-rs/${tool}-darwin-arm64`\n  },\n  linux: {\n    x64: `@foundry-rs/${tool}-linux-amd64`,\n    arm64: `@foundry-rs/${tool}-linux-arm64`\n  },\n  win32: {\n    x64: `@foundry-rs/${tool}-win32-amd64`\n  }\n})\n\n/**\n * @param {Tool} tool\n * @returns {string}\n */\nexport const BINARY_NAME = tool => process.platform === 'win32' ? `${tool}.exe` : tool\n\n/**\n * @param {Tool} tool\n * @returns {string | undefined}\n */\nexport const PLATFORM_SPECIFIC_PACKAGE_NAME = tool => {\n  // @ts-ignore\n  const platformPackages = BINARY_DISTRIBUTION_PACKAGES(tool)[process.platform]\n  if (!platformPackages) return undefined\n  return platformPackages?.[process.arch]\n}\n\nexport const colors = {\n  red: '\\x1b[31m',\n  green: '\\x1b[32m',\n  yellow: '\\x1b[33m',\n  blue: '\\x1b[34m',\n  magenta: '\\x1b[35m',\n  cyan: '\\x1b[36m',\n  white: '\\x1b[37m',\n  reset: '\\x1b[0m'\n}\n"
  },
  {
    "path": "npm/src/generate-package-json.mjs",
    "content": "#!/usr/bin/env bun\n\nimport * as NodeFS from 'node:fs/promises'\nimport * as NodePath from 'node:path'\nimport * as NodeUtil from 'node:util'\n\nimport { colors } from '#const.mjs'\n\n/**\n * @typedef {import('#const.mjs').Tool} Tool\n * @typedef {import('#const.mjs').Arch} Arch\n * @typedef {import('#const.mjs').Platform} Platform\n * @typedef {{\n *  tool: Tool\n *  platform: Platform\n *  arch: Arch\n *  packagePath: string\n * }} GenerateOptions\n */\n\nconst TOOL_META = /** @type {const} */ (/** @type {Record<Tool, { homepage: string; description: string }>} */ ({\n  forge: {\n    homepage: 'https://getfoundry.sh/forge',\n    description: 'Fast and flexible Ethereum testing framework'\n  },\n  cast: {\n    homepage: 'https://getfoundry.sh/cast',\n    description: 'Swiss Army knife for interacting with Ethereum applications from the command line'\n  },\n  anvil: {\n    homepage: 'https://getfoundry.sh/anvil',\n    description: 'Anvil is a fast local Ethereum development node'\n  },\n  chisel: {\n    homepage: 'https://getfoundry.sh/chisel',\n    description: 'Chisel is a fast, utilitarian, and verbose Solidity REPL'\n  }\n}))\n\n/**\n * @param {GenerateOptions} options\n * @returns {Promise<void>}\n */\nexport async function generateBinaryPackageJson({\n  tool,\n  platform,\n  arch,\n  packagePath\n}) {\n  const packageJsonPath = NodePath.join(packagePath, 'package.json')\n\n  const cpu = arch === 'amd64' ? 'x64' : 'arm64'\n  const isWindows = platform === 'win32'\n  const binName = isWindows ? `${tool}.exe` : tool\n  const humanPlatform = platform === 'darwin' ? 'macOS' : platform === 'win32' ? 'Windows' : 'Linux'\n  const { homepage, description } = TOOL_META[tool]\n\n  const pkg = {\n    name: `@foundry-rs/${tool}-${platform}-${arch}`,\n    version: '0.0.0',\n    type: 'module',\n    homepage,\n    description: `${description} (${humanPlatform} ${cpu})`,\n    bin: { [tool]: `./bin/${binName}` },\n    os: [platform],\n    cpu: [cpu],\n    files: ['bin'],\n    engines: { node: '>=20' },\n    license: 'MIT OR Apache-2.0',\n    repository: {\n      directory: 'npm',\n      url: 'https://github.com/foundry-rs/foundry'\n    },\n    keywords: ['foundry', 'testing', 'ethereum', 'solidity', 'blockchain', 'smart-contracts'],\n    publishConfig: { provenance: true }\n  }\n\n  await Bun.write(packageJsonPath, JSON.stringify(pkg, null, 2))\n  console.info(colors.green, `Wrote ${NodePath.relative(process.cwd(), packageJsonPath)}`, colors.reset)\n}\n\n// CLI entrypoint so CI can call directly if desired\nif (import.meta.main) {\n  const { values } = NodeUtil.parseArgs({\n    args: Bun.argv,\n    options: {\n      tool: { type: 'string', default: Bun.env.TARGET_TOOL },\n      platform: { type: 'string' },\n      arch: { type: 'string' },\n      out: { type: 'string' }\n    },\n    strict: true\n  })\n\n  const tool = /** @type {Tool} */ (String(values.tool || Bun.env.TARGET_TOOL))\n  const platform = /** @type {Platform} */ (values.platform || Bun.env.PLATFORM_NAME)\n  const arch = /** @type {Arch} */ (values.arch || Bun.env.ARCH)\n  const out = /** @type {string} */ (values.out || '')\n\n  if (!platform || !arch)\n    throw new Error('platform and arch are required (flags or env PLATFORM_NAME/ARCH)')\n  if (!out)\n    throw new Error('out is required (path to per-arch package directory)')\n\n  // Ensure the directory exists\n  await NodeFS.mkdir(out, { recursive: true })\n  await generateBinaryPackageJson({ tool, platform, arch, packagePath: out })\n}\n"
  },
  {
    "path": "npm/src/install.mjs",
    "content": "#!/usr/bin/env node\n\nimport * as NodeCrypto from 'node:crypto'\nimport * as NodeFS from 'node:fs'\nimport * as NodeHttp from 'node:http'\nimport * as NodeHttps from 'node:https'\nimport * as NodeModule from 'node:module'\nimport * as NodePath from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport * as NodeZlib from 'node:zlib'\n\nimport { BINARY_NAME, colors, getRegistryUrl, PLATFORM_SPECIFIC_PACKAGE_NAME, resolveTargetTool } from './const.mjs'\n\nconst __dirname = NodePath.dirname(fileURLToPath(import.meta.url))\nconst targetTool = resolveTargetTool()\nconst binaryName = BINARY_NAME(targetTool)\nconst fallbackBinaryPath = NodePath.join(__dirname, binaryName)\nconst platformSpecificPackageName = PLATFORM_SPECIFIC_PACKAGE_NAME(targetTool)\n\nconst expectedTarEntryPath = `package/bin/${binaryName}`\n\nif (NodePath.relative(__dirname, fallbackBinaryPath).startsWith('..'))\n  throw new Error('Resolved binary path escapes package directory')\n\nif (!platformSpecificPackageName) throw new Error('Platform not supported!')\n\nconst require = NodeModule.createRequire(import.meta.url)\n\n/**\n * Enforce HTTPS except for localhost, unless explicitly allowed\n * @param {string} urlString\n * @param {string} purpose\n * @returns {void}\n */\nfunction ensureSecureUrl(urlString, purpose) {\n  try {\n    const url = new URL(urlString)\n    if (url.protocol === 'http:') {\n      const allowInsecure = process.env.ALLOW_INSECURE_REGISTRY === 'true'\n      if (\n        // Accept typical localhost variants by default\n        !['localhost', '127.0.0.1', '::1'].includes(url.hostname)\n        && !allowInsecure\n      ) {\n        throw new Error(\n          `Refusing to use insecure HTTP for ${purpose}: ${urlString}. `\n            + `Set ALLOW_INSECURE_REGISTRY=true to override (not recommended).`\n        )\n      }\n    }\n  } catch {\n    // If parsing fails, the request will fail so no need to do anything here\n  }\n}\n\nconst MAX_REDIRECTS = 10\nconst REQUEST_TIMEOUT = 30_000 // 30s\nconst MAX_METADATA_BYTES = 5 * 1024 * 1024 // 5 MiB\nconst MAX_TARBALL_BYTES = 200 * 1024 * 1024 // 200 MiB\nconst MAX_BINARY_BYTES = 500 * 1024 * 1024 // 500 MiB\n\n/**\n * @param {string} url\n * @param {{\n *  parentSignal?: AbortSignal\n *  redirectDepth?: number\n *  visited?: Set<string>\n *  maxBytes?: number\n *  collect?: boolean\n *  onChunk?: (chunk: Buffer, response: import('node:http').IncomingMessage) => void\n * } | undefined} options\n * @returns {Promise<Buffer | undefined>}\n */\nexport function makeRequest(url, options = {}) {\n  const {\n    parentSignal,\n    redirectDepth = 0,\n    visited = new Set(),\n    maxBytes,\n    collect = true,\n    onChunk\n  } = options\n\n  if (redirectDepth > MAX_REDIRECTS) throw new Error('Maximum redirect depth exceeded')\n\n  if (visited.has(url)) throw new Error('Circular redirect detected')\n  visited.add(url)\n\n  ensureSecureUrl(url, 'HTTP request')\n\n  const controller = new AbortController()\n  const timer = setTimeout(() => controller.abort(), REQUEST_TIMEOUT)\n  const signal = parentSignal\n    ? AbortSignal.any([parentSignal, controller.signal])\n    : controller.signal\n\n  return new Promise((resolve, reject) => {\n    const client = url.startsWith('https:') ? NodeHttps : NodeHttp\n    const request = client.get(url, { signal }, response => {\n      /**\n       * @param {Error | null} error\n       * @param {Buffer<ArrayBufferLike> | undefined} value\n       */\n      const finish = (error, value = undefined) => {\n        clearTimeout(timer)\n        if (error) reject(error)\n        else resolve(value)\n      }\n\n      if (\n        response?.statusCode\n        && response.statusCode >= 200\n        && response.statusCode < 300\n      ) {\n        let totalBytes = 0\n        /** @type {Array<Buffer> | undefined} */\n        const chunks = collect ? [] : undefined\n\n        response.on('data', chunk => {\n          totalBytes += chunk.length\n          if (maxBytes && totalBytes > maxBytes) {\n            response.destroy(new Error('Response exceeded maximum allowed size'))\n            return\n          }\n\n          if (chunks) chunks.push(chunk)\n\n          if (onChunk) {\n            try {\n              onChunk(chunk, response)\n            } catch (error) {\n              response.destroy(\n                error instanceof Error ? error : new Error(`Error occurred: ${error}`)\n              )\n            }\n          }\n        })\n\n        response.on('end', () => {\n          finish(null, chunks ? Buffer.concat(chunks) : undefined)\n        })\n\n        response.on('error', finish)\n      } else if (\n        response?.statusCode\n        && response.statusCode >= 300\n        && response.statusCode < 400\n        && response.headers.location\n      ) {\n        clearTimeout(timer)\n        const nextUrl = new URL(response.headers.location, url).href\n\n        return makeRequest(nextUrl, {\n          parentSignal: signal,\n          redirectDepth: redirectDepth + 1,\n          visited,\n          maxBytes,\n          collect,\n          onChunk\n        }).then(resolve, reject)\n      } else {\n        finish(\n          new Error(\n            `Package registry responded with status code ${\n              response?.statusCode ?? '(none)'\n            } when downloading the package.`\n          )\n        )\n      }\n    })\n\n    request.on('error', error => {\n      clearTimeout(timer)\n      reject(error)\n    })\n  })\n}\n\n/**\n * Tar archives are organized in 512 byte blocks.\n * Blocks can either be header blocks or data blocks.\n * Header blocks contain file names of the archive in the first 100 bytes, terminated by a null byte.\n * The size of a file is contained in bytes 124-135 of a header block and in octal format.\n * The following blocks will be data blocks containing the file.\n * @param {Buffer<ArrayBufferLike>} tarballBuffer\n * @param {string} filepath\n * @returns {Buffer<ArrayBufferLike>}\n */\nfunction extractFileFromTarball(tarballBuffer, filepath) {\n  let offset = 0\n  while (offset < tarballBuffer.length) {\n    const header = tarballBuffer.subarray(offset, offset + 512)\n    offset += 512\n\n    const fileName = header.toString('utf-8', 0, 100).replace(/\\0.*/g, '')\n    const fileSize = Number.parseInt(\n      header.toString('utf-8', 124, 136).replace(/\\0.*/g, ''),\n      8\n    )\n\n    if (fileName === filepath) {\n      if (!Number.isFinite(fileSize) || Number.isNaN(fileSize) || fileSize < 0)\n        throw new Error(`Invalid size for ${filepath} in tarball`)\n      if (fileSize > MAX_BINARY_BYTES)\n        throw new Error(`Binary size for ${filepath} exceeds maximum allowed threshold`)\n      return tarballBuffer.subarray(offset, offset + fileSize)\n    }\n\n    // Clamp offset to the upper multiple of 512\n    offset = (offset + fileSize + 511) & ~511\n  }\n  throw new Error(`File ${filepath} not found in tarball`)\n}\n\nasync function downloadBinaryFromRegistry() {\n  if (!platformSpecificPackageName)\n    throw new Error('Platform-specific package name is not defined')\n\n  const registryUrl = getRegistryUrl().replace(/\\/$/, '')\n  ensureSecureUrl(registryUrl, 'registry URL')\n\n  // Scoped package names should be percent-encoded\n  const encodedName = platformSpecificPackageName.startsWith('@')\n    ? encodeURIComponent(platformSpecificPackageName)\n    : platformSpecificPackageName\n\n  // Determine which version to fetch: prefer the version pinned in optionalDependencies\n  /** @type {string | undefined} */\n  let desiredVersion\n  try {\n    const pkgJsonPath = NodePath.join(__dirname, '..', 'package.json')\n    const pkgJson = JSON.parse(NodeFS.readFileSync(pkgJsonPath, 'utf8'))\n    desiredVersion = pkgJson?.optionalDependencies[platformSpecificPackageName]\n      || pkgJson?.version\n  } catch {}\n\n  // Fetch metadata for the platform-specific package\n  const metaUrl = `${registryUrl}/${encodedName}`\n  const metaBuffer = await makeRequest(metaUrl, { maxBytes: MAX_METADATA_BYTES })\n  if (!metaBuffer)\n    throw new Error('Failed to download package metadata')\n  const metadata = JSON.parse(metaBuffer.toString('utf8'))\n\n  const version = desiredVersion || metadata?.['dist-tags']?.latest\n  const versionMeta = metadata?.versions?.[version]\n  const dist = versionMeta?.dist\n  if (!dist?.tarball) {\n    throw new Error(\n      `Could not find tarball for ${platformSpecificPackageName}@${version} from ${metaUrl}`\n    )\n  }\n\n  // Guard tarball URL scheme\n  ensureSecureUrl(dist.tarball, 'tarball URL')\n\n  console.info(\n    colors.green,\n    'Downloading binary from:\\n',\n    dist.tarball,\n    '\\n',\n    colors.reset\n  )\n\n  /**\n   * Download the tarball of the right binary distribution package\n   * Verify integrity: prefer SRI integrity (sha512/sha256/sha1),\n   * fallback to legacy dist.shasum (sha1 hex). Fail if neither unless explicitly allowed.\n   */\n  const integrity = typeof dist.integrity === 'string' ? dist.integrity : ''\n  const sriMatch = integrity.match(/^([a-z0-9]+)-([A-Za-z0-9+/=]+)$/i)\n  const allowedSRIAlgorithms = new Set(['sha512', 'sha256', 'sha1'])\n  const sriAlgo = sriMatch && allowedSRIAlgorithms.has(sriMatch[1].toLowerCase())\n    ? sriMatch[1].toLowerCase()\n    : undefined\n  const expectedSri = sriAlgo ? sriMatch?.[2] : undefined\n  const sriHasher = sriAlgo ? NodeCrypto.createHash(sriAlgo) : undefined\n\n  const expectedSha1Hex = typeof dist.shasum === 'string' && dist.shasum.length === 40\n    ? dist.shasum.toLowerCase()\n    : undefined\n  const sha1Hasher = expectedSha1Hex ? NodeCrypto.createHash('sha1') : undefined\n\n  const tarballDownloadBuffer = await makeRequest(dist.tarball, {\n    maxBytes: MAX_TARBALL_BYTES,\n    onChunk: chunk => {\n      sriHasher?.update(chunk)\n      sha1Hasher?.update(chunk)\n    }\n  })\n\n  if (!tarballDownloadBuffer)\n    throw new Error('Failed to download tarball contents')\n\n  let verified = false\n\n  if (sriHasher && expectedSri) {\n    const actual = sriHasher.digest('base64')\n    if (expectedSri !== actual) {\n      throw new Error(\n        `Downloaded tarball failed integrity check (${sriAlgo} mismatch)`\n      )\n    }\n    verified = true\n  }\n\n  if (!verified && sha1Hasher && expectedSha1Hex) {\n    const actualSha1Hex = sha1Hasher.digest('hex')\n    if (expectedSha1Hex !== actualSha1Hex) {\n      throw new Error(\n        'Downloaded tarball failed integrity check (sha1 shasum mismatch)'\n      )\n    }\n    verified = true\n  }\n\n  if (!verified) {\n    const allowNoIntegrity = process.env.ALLOW_NO_INTEGRITY === 'true'\n      || process.env.ALLOW_UNVERIFIED_TARBALL === 'true'\n    if (!allowNoIntegrity) {\n      throw new Error(\n        'No integrity metadata found for downloaded tarball. '\n          + 'Set ALLOW_NO_INTEGRITY=true to bypass (not recommended).'\n      )\n    }\n    console.warn(\n      colors.yellow,\n      'Warning: proceeding without integrity verification (explicitly allowed).',\n      colors.reset\n    )\n  }\n\n  // Unpack and write binary\n  const tarballBuffer = NodeZlib.gunzipSync(tarballDownloadBuffer)\n\n  NodeFS.writeFileSync(\n    fallbackBinaryPath,\n    extractFileFromTarball(tarballBuffer, expectedTarEntryPath),\n    { mode: 0o755 } // Make binary file executable\n  )\n}\n\nfunction isPlatformSpecificPackageInstalled() {\n  try {\n    // Resolving will fail if the optionalDependency was not installed\n    require.resolve(`${platformSpecificPackageName}/bin/${binaryName}`)\n    return true\n  } catch {\n    return false\n  }\n}\n\n// Skip downloading the binary if it was already installed via optionalDependencies\nif (!isPlatformSpecificPackageInstalled()) {\n  console.log('Platform specific package not found. Will manually download binary.')\n  downloadBinaryFromRegistry().catch(error => {\n    console.error(colors.red, 'Failed to download binary:', error, colors.reset)\n    process.exitCode = 1\n  })\n} else {\n  console.log(\n    'Platform specific package already installed. Skipping manual download.'\n  )\n}\n"
  },
  {
    "path": "npm/tsconfig.json",
    "content": "{\n  \"schema\": \"https://json.schemastore.org/tsconfig.json\",\n  \"compilerOptions\": {\n    \"strict\": true,\n    \"baseUrl\": \".\",\n    \"noEmit\": true,\n    \"allowJs\": true,\n    \"checkJs\": true,\n    \"lib\": [\n      \"ESNext\"\n    ],\n    \"target\": \"ESNext\",\n    \"module\": \"ESNext\",\n    \"skipLibCheck\": true,\n    \"alwaysStrict\": true,\n    \"esModuleInterop\": true,\n    \"isolatedModules\": true,\n    \"strictNullChecks\": true,\n    \"resolveJsonModule\": true,\n    \"verbatimModuleSyntax\": true,\n    \"moduleResolution\": \"Bundler\",\n    \"useDefineForClassFields\": true,\n    \"noUncheckedIndexedAccess\": true,\n    \"resolvePackageJsonImports\": true,\n    \"resolvePackageJsonExports\": true,\n    \"useUnknownInCatchVariables\": true,\n    \"allowImportingTsExtensions\": true,\n    \"noFallthroughCasesInSwitch\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"types\": [\n      \"bun\",\n      \"node\"\n    ]\n  },\n  \"exclude\": [\n    \"dist\",\n    \"**/_/**\",\n    \"node_modules\"\n  ],\n  \"include\": [\n    \"./src/**/*\",\n    \"./src/*.mjs\",\n    \"./scripts/**/*\",\n    \"./scripts/*.mjs\"\n  ],\n  \"files\": [\n    \"env.d.ts\",\n    \"package.json\"\n  ]\n}\n"
  },
  {
    "path": "rustfmt.toml",
    "content": "reorder_imports = true\nuse_field_init_shorthand = true\nuse_small_heuristics = \"Max\"\n\n# Nightly\nmax_width = 100\ncomment_width = 100\nimports_granularity = \"Crate\"\nwrap_comments = true\nformat_code_in_doc_comments = true\ndoc_comment_code_block_width = 100\nformat_macro_matchers = true\n"
  },
  {
    "path": "testdata/.gitignore",
    "content": "# Compiler files\ncache/\nout/\n.lock\n"
  },
  {
    "path": "testdata/README.md",
    "content": "## Foundry Tests\n\nA test suite that tests different aspects of Foundry.\n\n### Structure\n\n-   [`core`](default/core): Tests for fundamental aspects of Foundry\n-   [`logs`](default/logs): Tests for Foundry logging capabilities\n-   [`cheats`](default/cheats): Tests for Foundry cheatcodes\n-   [`fuzz`](default/fuzz): Tests for the Foundry fuzzer\n-   [`trace`](default/trace): Tests for the Foundry tracer\n-   [`fork`](default/fork): Tests for Foundry forking capabilities\n"
  },
  {
    "path": "testdata/default/cheats/AccessList.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\n/// forge-config: default.isolate = true\ncontract AccessListIsolatedTest is Test {\n    function test_access_list() public {\n        Write anotherWrite = new Write();\n        Write write = new Write();\n\n        uint256 initial = gasleft();\n        write.setNumber(1);\n        assertEq(initial - gasleft(), 26762);\n\n        // set access list to anotherWrite address, hence becoming more expensive\n        Vm.AccessListItem[] memory accessList = new Vm.AccessListItem[](1);\n        bytes32[] memory readKeys = new bytes32[](0);\n        accessList[0] = Vm.AccessListItem(address(anotherWrite), readKeys);\n        vm.accessList(accessList);\n\n        uint256 initial1 = gasleft();\n        write.setNumber(2);\n        assertEq(initial1 - gasleft(), 29162);\n\n        uint256 initial2 = gasleft();\n        write.setNumber(3);\n        assertEq(initial2 - gasleft(), 29162);\n\n        // reset access list, should take same gas as before setting\n        vm.noAccessList();\n        uint256 initial4 = gasleft();\n        write.setNumber(4);\n        assertEq(initial4 - gasleft(), 26762);\n\n        uint256 initial5 = gasleft();\n        write.setNumber(5);\n        assertEq(initial5 - gasleft(), 26762);\n\n        vm.accessList(accessList);\n        uint256 initial6 = gasleft();\n        write.setNumber(6);\n        assertEq(initial6 - gasleft(), 29162);\n    }\n}\n\ncontract Write {\n    uint256 public number = 10;\n\n    function setNumber(uint256 _number) external {\n        number = _number;\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/Addr.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract AddrTest is Test {\n    /// forge-config: default.allow_internal_expect_revert = true\n    function testRevertIfPkZero() public {\n        vm.expectRevert(\"vm.addr: private key cannot be 0\");\n        vm.addr(0);\n    }\n\n    function testAddr() public {\n        uint256 pk = 77814517325470205911140941194401928579557062014761831930645393041380819009408;\n        address expected = 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266;\n\n        assertEq(vm.addr(pk), expected, \"expected address did not match\");\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/ArbitraryStorage.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract Counter {\n    uint256 public a;\n    address public b;\n    int8 public c;\n    address[] public owners;\n\n    function setA(uint256 _a) public {\n        a = _a;\n    }\n\n    function setB(address _b) public {\n        b = _b;\n    }\n\n    function getOwner(uint256 pos) public view returns (address) {\n        return owners[pos];\n    }\n\n    function setOwner(uint256 pos, address owner) public {\n        owners[pos] = owner;\n    }\n}\n\n/// forge-config: default.fuzz.seed = \"100\"\ncontract CounterArbitraryStorageWithSeedTest is Test {\n    function test_fresh_storage() public {\n        uint256 index = 55;\n        Counter counter = new Counter();\n        vm.setArbitraryStorage(address(counter));\n        // Next call would fail with array out of bounds without arbitrary storage.\n        address owner = counter.getOwner(index);\n        // Subsequent calls should retrieve same value\n        assertEq(counter.getOwner(index), owner);\n        // Change slot and make sure new value retrieved\n        counter.setOwner(index, address(111));\n        assertEq(counter.getOwner(index), address(111));\n    }\n\n    function test_arbitrary_storage_warm() public {\n        Counter counter = new Counter();\n        vm.setArbitraryStorage(address(counter));\n        assertGt(counter.a(), 0);\n        counter.setA(0);\n        // This should remain 0 if explicitly set.\n        assertEq(counter.a(), 0);\n        counter.setA(11);\n        assertEq(counter.a(), 11);\n    }\n\n    function test_arbitrary_storage_multiple_read_writes() public {\n        Counter counter = new Counter();\n        vm.setArbitraryStorage(address(counter));\n        uint256 slot1 = vm.randomUint(0, 100);\n        uint256 slot2 = vm.randomUint(0, 100);\n        require(slot1 != slot2, \"random positions should be different\");\n        address alice = counter.owners(slot1);\n        address bob = counter.owners(slot2);\n        require(alice != bob, \"random storage values should be different\");\n        counter.setOwner(slot1, bob);\n        counter.setOwner(slot2, alice);\n        assertEq(alice, counter.owners(slot2));\n        assertEq(bob, counter.owners(slot1));\n    }\n}\n\ncontract AContract {\n    uint256[] public a;\n    address[] public b;\n    int8[] public c;\n    bytes32[] public d;\n}\n\n/// forge-config: default.fuzz.seed = \"100\"\ncontract AContractArbitraryStorageWithSeedTest is Test {\n    function test_arbitrary_storage_with_seed() public {\n        AContract target = new AContract();\n        vm.setArbitraryStorage(address(target));\n        assertEq(target.a(11), 112807530564575719000382171275495171195982096112439764207649185248041477080234);\n        assertEq(target.b(22), 0x9dce87df97C81f2529877E8127b4b8c13E4b2b31);\n        assertEq(target.c(33), 85);\n        assertEq(target.d(44), 0x6ceda712fc9d694d72afeea6c44d370b789a18e1a3d640068c11069e421d25f6);\n    }\n}\n\ncontract SymbolicStore {\n    uint256 public testNumber = 1337; // slot 0\n\n    constructor() {}\n}\n\n/// forge-config: default.fuzz.seed = \"100\"\ncontract SymbolicStorageWithSeedTest is Test {\n    function test_SymbolicStorage() public {\n        uint256 slot = vm.randomUint(0, 100);\n        address addr = 0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8;\n        vm.setArbitraryStorage(addr);\n        bytes32 value = vm.load(addr, bytes32(slot));\n        assertEq(uint256(value), 112807530564575719000382171275495171195982096112439764207649185248041477080234);\n        // Load slot again and make sure we get same value.\n        bytes32 value1 = vm.load(addr, bytes32(slot));\n        assertEq(uint256(value), uint256(value1));\n    }\n\n    function test_SymbolicStorage1() public {\n        uint256 slot = vm.randomUint(0, 100);\n        SymbolicStore myStore = new SymbolicStore();\n        vm.setArbitraryStorage(address(myStore));\n        bytes32 value = vm.load(address(myStore), bytes32(uint256(slot)));\n        assertEq(uint256(value), 112807530564575719000382171275495171195982096112439764207649185248041477080234);\n    }\n\n    function testEmptyInitialStorage(uint256 slot) public {\n        bytes32 storage_value = vm.load(address(vm), bytes32(slot));\n        assertEq(uint256(storage_value), 0);\n    }\n}\n\n// <https://github.com/foundry-rs/foundry/issues/10084>\n/// forge-config: default.fuzz.seed = \"100\"\ncontract ArbitraryStorageOverwriteWithSeedTest is Test {\n    uint256 _value;\n\n    function testArbitraryStorageFalse(uint256 value) public {\n        _value = value;\n        vm.setArbitraryStorage(address(this), false);\n        assertEq(_value, value);\n    }\n\n    function testArbitraryStorageTrue(uint256 value) public {\n        _value = value;\n        vm.setArbitraryStorage(address(this), true);\n        assertTrue(_value != value);\n    }\n\n    function testArbitraryStorageFalse_setAfter(uint256 value) public {\n        vm.setArbitraryStorage(address(this), false);\n        _value = value;\n        assertEq(_value, value);\n    }\n\n    function testArbitraryStorageTrue_setAfter(uint256 value) public {\n        vm.setArbitraryStorage(address(this), true);\n        _value = value;\n        assertEq(_value, value);\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/Assert.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract AssertionsTest is Test {\n    string constant errorMessage = \"User provided message\";\n    uint256 constant maxDecimals = 77;\n\n    function _abs(int256 a) internal pure returns (uint256) {\n        // Required or it will fail when `a = type(int256).min`\n        if (a == type(int256).min) {\n            return uint256(type(int256).max) + 1;\n        }\n\n        return uint256(a > 0 ? a : -a);\n    }\n\n    function _getDelta(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a > b ? a - b : b - a;\n    }\n\n    function _getDelta(int256 a, int256 b) internal pure returns (uint256) {\n        // a and b are of the same sign\n        // this works thanks to two's complement, the left-most bit is the sign bit\n        if ((a ^ b) > -1) {\n            return _getDelta(_abs(a), _abs(b));\n        }\n\n        // a and b are of opposite signs\n        return _abs(a) + _abs(b);\n    }\n\n    function _prefixDecWithZeroes(string memory intPart, string memory decimalPart, uint256 decimals)\n        internal\n        returns (string memory)\n    {\n        while (bytes(decimalPart).length < decimals) {\n            decimalPart = string.concat(\"0\", decimalPart);\n        }\n\n        return string.concat(intPart, \".\", decimalPart);\n    }\n\n    function _formatWithDecimals(uint256 value, uint256 decimals) internal returns (string memory) {\n        string memory intPart = vm.toString(value / (10 ** decimals));\n        string memory decimalPart = vm.toString(value % (10 ** decimals));\n\n        return _prefixDecWithZeroes(intPart, decimalPart, decimals);\n    }\n\n    function _formatWithDecimals(int256 value, uint256 decimals) internal returns (string memory) {\n        string memory formatted = _formatWithDecimals(_abs(value), decimals);\n        if (value < 0) {\n            formatted = string.concat(\"-\", formatted);\n        }\n\n        return formatted;\n    }\n\n    function testFuzzAssertEqNotEq(uint256 left, uint256 right, uint256 decimals) public {\n        vm.assume(left != right);\n        vm.assume(decimals <= maxDecimals);\n\n        vm.assertEq(left, left);\n        vm.assertEq(right, right);\n        vm.assertNotEq(left, right);\n        vm.assertNotEq(right, left);\n\n        vm._expectCheatcodeRevert(\n            bytes(string.concat(errorMessage, \": \", vm.toString(left), \" != \", vm.toString(right)))\n        );\n        vm.assertEq(left, right, errorMessage);\n\n        vm._expectCheatcodeRevert(\n            bytes(string.concat(errorMessage, \": \", vm.toString(left), \" == \", vm.toString(left)))\n        );\n        vm.assertNotEq(left, left, errorMessage);\n\n        vm._expectCheatcodeRevert(\n            bytes(\n                string.concat(\n                    \"assertion failed: \",\n                    _formatWithDecimals(left, decimals),\n                    \" != \",\n                    _formatWithDecimals(right, decimals)\n                )\n            )\n        );\n        vm.assertEqDecimal(left, right, decimals);\n\n        vm._expectCheatcodeRevert(\n            bytes(\n                string.concat(\n                    \"assertion failed: \",\n                    _formatWithDecimals(left, decimals),\n                    \" == \",\n                    _formatWithDecimals(left, decimals)\n                )\n            )\n        );\n        vm.assertNotEqDecimal(left, left, decimals);\n    }\n\n    function testFuzzAssertEqNotEq(int256 left, int256 right, uint256 decimals) public {\n        vm.assume(left != right);\n        vm.assume(decimals <= maxDecimals);\n\n        vm.assertEq(left, left);\n        vm.assertEq(right, right);\n        vm.assertNotEq(left, right);\n        vm.assertNotEq(right, left);\n\n        vm._expectCheatcodeRevert(\n            bytes(string.concat(errorMessage, \": \", vm.toString(left), \" != \", vm.toString(right)))\n        );\n        vm.assertEq(left, right, errorMessage);\n\n        vm._expectCheatcodeRevert(\n            bytes(string.concat(errorMessage, \": \", vm.toString(left), \" == \", vm.toString(left)))\n        );\n        vm.assertNotEq(left, left, errorMessage);\n\n        vm._expectCheatcodeRevert(\n            bytes(\n                string.concat(\n                    errorMessage,\n                    \": \",\n                    _formatWithDecimals(left, decimals),\n                    \" != \",\n                    _formatWithDecimals(right, decimals)\n                )\n            )\n        );\n        vm.assertEqDecimal(left, right, decimals, errorMessage);\n\n        vm._expectCheatcodeRevert(\n            bytes(\n                string.concat(\n                    errorMessage, \": \", _formatWithDecimals(left, decimals), \" == \", _formatWithDecimals(left, decimals)\n                )\n            )\n        );\n        vm.assertNotEqDecimal(left, left, decimals, errorMessage);\n    }\n\n    function testFuzzAssertEqNotEq(bool left, bool right) public {\n        vm.assume(left != right);\n\n        vm.assertEq(left, left);\n        vm.assertEq(right, right);\n        vm.assertNotEq(left, right);\n        vm.assertNotEq(right, left);\n\n        vm._expectCheatcodeRevert(\n            bytes(string.concat(errorMessage, \": \", vm.toString(left), \" != \", vm.toString(right)))\n        );\n        vm.assertEq(left, right, errorMessage);\n\n        vm._expectCheatcodeRevert(\n            bytes(string.concat(errorMessage, \": \", vm.toString(left), \" == \", vm.toString(left)))\n        );\n        vm.assertNotEq(left, left, errorMessage);\n    }\n\n    function testFuzzAssertEqNotEq(address left, address right) public {\n        vm.assume(left != right);\n\n        vm.assertEq(left, left);\n        vm.assertEq(right, right);\n        vm.assertNotEq(left, right);\n        vm.assertNotEq(right, left);\n\n        vm._expectCheatcodeRevert(\n            bytes(string.concat(errorMessage, \": \", vm.toString(left), \" != \", vm.toString(right)))\n        );\n        vm.assertEq(left, right, errorMessage);\n\n        vm._expectCheatcodeRevert(\n            bytes(string.concat(errorMessage, \": \", vm.toString(left), \" == \", vm.toString(left)))\n        );\n        vm.assertNotEq(left, left, errorMessage);\n    }\n\n    function testFuzzAssertEqNotEq(bytes32 left, bytes32 right) public {\n        vm.assume(left != right);\n\n        vm.assertEq(left, left);\n        vm.assertEq(right, right);\n        vm.assertNotEq(left, right);\n        vm.assertNotEq(right, left);\n\n        vm._expectCheatcodeRevert(\n            bytes(string.concat(errorMessage, \": \", vm.toString(left), \" != \", vm.toString(right)))\n        );\n        vm.assertEq(left, right, errorMessage);\n\n        vm._expectCheatcodeRevert(\n            bytes(string.concat(errorMessage, \": \", vm.toString(left), \" == \", vm.toString(left)))\n        );\n        vm.assertNotEq(left, left, errorMessage);\n    }\n\n    function testFuzzAssertEqNotEq(string memory left, string memory right) public {\n        vm.assume(keccak256(abi.encodePacked(left)) != keccak256(abi.encodePacked(right)));\n\n        vm.assertEq(left, left);\n        vm.assertEq(right, right);\n        vm.assertNotEq(left, right);\n        vm.assertNotEq(right, left);\n\n        vm._expectCheatcodeRevert(bytes(string.concat(errorMessage, \": \", left, \" != \", right)));\n        vm.assertEq(left, right, errorMessage);\n\n        vm._expectCheatcodeRevert(bytes(string.concat(errorMessage, \": \", left, \" == \", left)));\n        vm.assertNotEq(left, left, errorMessage);\n    }\n\n    function testFuzzAssertEqNotEq(bytes memory left, bytes memory right) public {\n        vm.assume(keccak256(left) != keccak256(right));\n\n        vm.assertEq(left, left);\n        vm.assertEq(right, right);\n        vm.assertNotEq(left, right);\n        vm.assertNotEq(right, left);\n\n        vm._expectCheatcodeRevert(\n            bytes(string.concat(errorMessage, \": \", vm.toString(left), \" != \", vm.toString(right)))\n        );\n        vm.assertEq(left, right, errorMessage);\n\n        vm._expectCheatcodeRevert(\n            bytes(string.concat(errorMessage, \": \", vm.toString(left), \" == \", vm.toString(left)))\n        );\n        vm.assertNotEq(left, left, errorMessage);\n    }\n\n    function testFuzzAssertGtLt(uint256 left, uint256 right, uint256 decimals) public {\n        vm.assume(left < right);\n        vm.assume(decimals <= maxDecimals);\n\n        vm.assertGt(right, left);\n        vm.assertLt(left, right);\n\n        vm._expectCheatcodeRevert(\n            bytes(string.concat(errorMessage, \": \", vm.toString(left), \" <= \", vm.toString(right)))\n        );\n        vm.assertGt(left, right, errorMessage);\n\n        vm._expectCheatcodeRevert(\n            bytes(string.concat(errorMessage, \": \", vm.toString(right), \" <= \", vm.toString(right)))\n        );\n        vm.assertGt(right, right, errorMessage);\n\n        vm._expectCheatcodeRevert(\n            bytes(string.concat(errorMessage, \": \", vm.toString(left), \" >= \", vm.toString(left)))\n        );\n        vm.assertLt(left, left, errorMessage);\n\n        vm._expectCheatcodeRevert(\n            bytes(string.concat(errorMessage, \": \", vm.toString(right), \" >= \", vm.toString(left)))\n        );\n        vm.assertLt(right, left, errorMessage);\n\n        vm._expectCheatcodeRevert(\n            bytes(\n                string.concat(\n                    \"assertion failed: \",\n                    _formatWithDecimals(left, decimals),\n                    \" <= \",\n                    _formatWithDecimals(right, decimals)\n                )\n            )\n        );\n        vm.assertGtDecimal(left, right, decimals);\n\n        vm._expectCheatcodeRevert(\n            bytes(\n                string.concat(\n                    \"assertion failed: \",\n                    _formatWithDecimals(right, decimals),\n                    \" <= \",\n                    _formatWithDecimals(right, decimals)\n                )\n            )\n        );\n        vm.assertGtDecimal(right, right, decimals);\n\n        vm._expectCheatcodeRevert(\n            bytes(\n                string.concat(\n                    \"assertion failed: \",\n                    _formatWithDecimals(left, decimals),\n                    \" >= \",\n                    _formatWithDecimals(left, decimals)\n                )\n            )\n        );\n        vm.assertLtDecimal(left, left, decimals);\n\n        vm._expectCheatcodeRevert(\n            bytes(\n                string.concat(\n                    \"assertion failed: \",\n                    _formatWithDecimals(right, decimals),\n                    \" >= \",\n                    _formatWithDecimals(left, decimals)\n                )\n            )\n        );\n        vm.assertLtDecimal(right, left, decimals);\n    }\n\n    function testFuzzAssertGtLt(int256 left, int256 right, uint256 decimals) public {\n        vm.assume(left < right);\n        vm.assume(decimals <= maxDecimals);\n\n        vm.assertGt(right, left);\n        vm.assertLt(left, right);\n\n        vm._expectCheatcodeRevert(\n            bytes(string.concat(errorMessage, \": \", vm.toString(left), \" <= \", vm.toString(right)))\n        );\n        vm.assertGt(left, right, errorMessage);\n\n        vm._expectCheatcodeRevert(\n            bytes(string.concat(errorMessage, \": \", vm.toString(right), \" <= \", vm.toString(right)))\n        );\n        vm.assertGt(right, right, errorMessage);\n\n        vm._expectCheatcodeRevert(\n            bytes(string.concat(errorMessage, \": \", vm.toString(left), \" >= \", vm.toString(left)))\n        );\n        vm.assertLt(left, left, errorMessage);\n\n        vm._expectCheatcodeRevert(\n            bytes(string.concat(errorMessage, \": \", vm.toString(right), \" >= \", vm.toString(left)))\n        );\n        vm.assertLt(right, left, errorMessage);\n\n        vm._expectCheatcodeRevert(\n            bytes(\n                string.concat(\n                    \"assertion failed: \",\n                    _formatWithDecimals(left, decimals),\n                    \" <= \",\n                    _formatWithDecimals(right, decimals)\n                )\n            )\n        );\n        vm.assertGtDecimal(left, right, decimals);\n\n        vm._expectCheatcodeRevert(\n            bytes(\n                string.concat(\n                    \"assertion failed: \",\n                    _formatWithDecimals(right, decimals),\n                    \" <= \",\n                    _formatWithDecimals(right, decimals)\n                )\n            )\n        );\n        vm.assertGtDecimal(right, right, decimals);\n\n        vm._expectCheatcodeRevert(\n            bytes(\n                string.concat(\n                    \"assertion failed: \",\n                    _formatWithDecimals(left, decimals),\n                    \" >= \",\n                    _formatWithDecimals(left, decimals)\n                )\n            )\n        );\n        vm.assertLtDecimal(left, left, decimals);\n\n        vm._expectCheatcodeRevert(\n            bytes(\n                string.concat(\n                    \"assertion failed: \",\n                    _formatWithDecimals(right, decimals),\n                    \" >= \",\n                    _formatWithDecimals(left, decimals)\n                )\n            )\n        );\n        vm.assertLtDecimal(right, left, decimals);\n    }\n\n    function testFuzzAssertGeLe(uint256 left, uint256 right, uint256 decimals) public {\n        vm.assume(left < right);\n        vm.assume(decimals <= maxDecimals);\n\n        vm.assertGe(left, left);\n        vm.assertLe(left, left);\n        vm.assertGe(right, right);\n        vm.assertLe(right, right);\n        vm.assertGe(right, left);\n        vm.assertLe(left, right);\n\n        vm._expectCheatcodeRevert(\n            bytes(string.concat(errorMessage, \": \", vm.toString(left), \" < \", vm.toString(right)))\n        );\n        vm.assertGe(left, right, errorMessage);\n\n        vm._expectCheatcodeRevert(\n            bytes(string.concat(errorMessage, \": \", vm.toString(right), \" > \", vm.toString(left)))\n        );\n        vm.assertLe(right, left, errorMessage);\n\n        vm._expectCheatcodeRevert(\n            bytes(\n                string.concat(\n                    \"assertion failed: \",\n                    _formatWithDecimals(left, decimals),\n                    \" < \",\n                    _formatWithDecimals(right, decimals)\n                )\n            )\n        );\n        vm.assertGeDecimal(left, right, decimals);\n\n        vm._expectCheatcodeRevert(\n            bytes(\n                string.concat(\n                    \"assertion failed: \",\n                    _formatWithDecimals(right, decimals),\n                    \" > \",\n                    _formatWithDecimals(left, decimals)\n                )\n            )\n        );\n        vm.assertLeDecimal(right, left, decimals);\n    }\n\n    function testFuzzAssertGeLe(int256 left, int256 right, uint256 decimals) public {\n        vm.assume(left < right);\n        vm.assume(decimals <= maxDecimals);\n\n        vm.assertGe(left, left);\n        vm.assertLe(left, left);\n        vm.assertGe(right, right);\n        vm.assertLe(right, right);\n        vm.assertGe(right, left);\n        vm.assertLe(left, right);\n\n        vm._expectCheatcodeRevert(\n            bytes(string.concat(errorMessage, \": \", vm.toString(left), \" < \", vm.toString(right)))\n        );\n        vm.assertGe(left, right, errorMessage);\n\n        vm._expectCheatcodeRevert(\n            bytes(string.concat(errorMessage, \": \", vm.toString(right), \" > \", vm.toString(left)))\n        );\n        vm.assertLe(right, left, errorMessage);\n\n        vm._expectCheatcodeRevert(\n            bytes(\n                string.concat(\n                    \"assertion failed: \",\n                    _formatWithDecimals(left, decimals),\n                    \" < \",\n                    _formatWithDecimals(right, decimals)\n                )\n            )\n        );\n        vm.assertGeDecimal(left, right, decimals);\n\n        vm._expectCheatcodeRevert(\n            bytes(\n                string.concat(\n                    \"assertion failed: \",\n                    _formatWithDecimals(right, decimals),\n                    \" > \",\n                    _formatWithDecimals(left, decimals)\n                )\n            )\n        );\n        vm.assertLeDecimal(right, left, decimals);\n    }\n\n    function testFuzzAssertApproxEqAbs(uint256 left, uint256 right, uint256 decimals) public {\n        uint256 delta = _getDelta(right, left);\n        vm.assume(decimals <= maxDecimals);\n\n        vm.assertApproxEqAbs(left, right, delta);\n\n        if (delta > 0) {\n            vm._expectCheatcodeRevert(\n                bytes(\n                    string.concat(\n                        errorMessage,\n                        \": \",\n                        vm.toString(left),\n                        \" !~= \",\n                        vm.toString(right),\n                        \" (max delta: \",\n                        vm.toString(delta - 1),\n                        \", real delta: \",\n                        vm.toString(delta),\n                        \")\"\n                    )\n                )\n            );\n            vm.assertApproxEqAbs(left, right, delta - 1, errorMessage);\n\n            vm._expectCheatcodeRevert(\n                bytes(\n                    string.concat(\n                        \"assertion failed: \",\n                        _formatWithDecimals(left, decimals),\n                        \" !~= \",\n                        _formatWithDecimals(right, decimals),\n                        \" (max delta: \",\n                        _formatWithDecimals(delta - 1, decimals),\n                        \", real delta: \",\n                        _formatWithDecimals(delta, decimals),\n                        \")\"\n                    )\n                )\n            );\n            vm.assertApproxEqAbsDecimal(left, right, delta - 1, decimals);\n        }\n    }\n\n    function testFuzzAssertApproxEqAbs(int256 left, int256 right, uint256 decimals) public {\n        uint256 delta = _getDelta(right, left);\n        vm.assume(decimals <= maxDecimals);\n\n        vm.assertApproxEqAbs(left, right, delta);\n\n        if (delta > 0) {\n            vm._expectCheatcodeRevert(\n                bytes(\n                    string.concat(\n                        errorMessage,\n                        \": \",\n                        vm.toString(left),\n                        \" !~= \",\n                        vm.toString(right),\n                        \" (max delta: \",\n                        vm.toString(delta - 1),\n                        \", real delta: \",\n                        vm.toString(delta),\n                        \")\"\n                    )\n                )\n            );\n            vm.assertApproxEqAbs(left, right, delta - 1, errorMessage);\n\n            vm._expectCheatcodeRevert(\n                bytes(\n                    string.concat(\n                        \"assertion failed: \",\n                        _formatWithDecimals(left, decimals),\n                        \" !~= \",\n                        _formatWithDecimals(right, decimals),\n                        \" (max delta: \",\n                        _formatWithDecimals(delta - 1, decimals),\n                        \", real delta: \",\n                        _formatWithDecimals(delta, decimals),\n                        \")\"\n                    )\n                )\n            );\n            vm.assertApproxEqAbsDecimal(left, right, delta - 1, decimals);\n        }\n    }\n\n    function testFuzzAssertApproxEqRel(uint256 left, uint256 right, uint256 decimals) public {\n        vm.assume(right != 0);\n        uint256 delta = _getDelta(right, left);\n        vm.assume(delta < type(uint256).max / (10 ** 18));\n        vm.assume(decimals <= maxDecimals);\n\n        uint256 percentDelta = delta * (10 ** 18) / right;\n\n        vm.assertApproxEqRel(left, right, percentDelta);\n\n        if (percentDelta > 0) {\n            vm._expectCheatcodeRevert(\n                bytes(\n                    string.concat(\n                        errorMessage,\n                        \": \",\n                        vm.toString(left),\n                        \" !~= \",\n                        vm.toString(right),\n                        \" (max delta: \",\n                        _formatWithDecimals(percentDelta - 1, 16),\n                        \"%, real delta: \",\n                        _formatWithDecimals(percentDelta, 16),\n                        \"%)\"\n                    )\n                )\n            );\n            vm.assertApproxEqRel(left, right, percentDelta - 1, errorMessage);\n\n            vm._expectCheatcodeRevert(\n                bytes(\n                    string.concat(\n                        \"assertion failed: \",\n                        _formatWithDecimals(left, decimals),\n                        \" !~= \",\n                        _formatWithDecimals(right, decimals),\n                        \" (max delta: \",\n                        _formatWithDecimals(percentDelta - 1, 16),\n                        \"%, real delta: \",\n                        _formatWithDecimals(percentDelta, 16),\n                        \"%)\"\n                    )\n                )\n            );\n            vm.assertApproxEqRelDecimal(left, right, percentDelta - 1, decimals);\n        }\n    }\n\n    function testFuzzAssertApproxEqRel(int256 left, int256 right, uint256 decimals) public {\n        vm.assume(left < right);\n        vm.assume(right != 0);\n        uint256 delta = _getDelta(right, left);\n        vm.assume(delta < type(uint256).max / (10 ** 18));\n        vm.assume(decimals <= maxDecimals);\n\n        uint256 percentDelta = delta * (10 ** 18) / _abs(right);\n\n        vm.assertApproxEqRel(left, right, percentDelta);\n\n        if (percentDelta > 0) {\n            vm._expectCheatcodeRevert(\n                bytes(\n                    string.concat(\n                        errorMessage,\n                        \": \",\n                        vm.toString(left),\n                        \" !~= \",\n                        vm.toString(right),\n                        \" (max delta: \",\n                        _formatWithDecimals(percentDelta - 1, 16),\n                        \"%, real delta: \",\n                        _formatWithDecimals(percentDelta, 16),\n                        \"%)\"\n                    )\n                )\n            );\n            vm.assertApproxEqRel(left, right, percentDelta - 1, errorMessage);\n\n            vm._expectCheatcodeRevert(\n                bytes(\n                    string.concat(\n                        \"assertion failed: \",\n                        _formatWithDecimals(left, decimals),\n                        \" !~= \",\n                        _formatWithDecimals(right, decimals),\n                        \" (max delta: \",\n                        _formatWithDecimals(percentDelta - 1, 16),\n                        \"%, real delta: \",\n                        _formatWithDecimals(percentDelta, 16),\n                        \"%)\"\n                    )\n                )\n            );\n            vm.assertApproxEqRelDecimal(left, right, percentDelta - 1, decimals);\n        }\n    }\n\n    function testAssertEqNotEqArrays() public {\n        {\n            uint256[] memory arr1 = new uint256[](1);\n            arr1[0] = 1;\n            uint256[] memory arr2 = new uint256[](2);\n            arr2[0] = 1;\n            arr2[1] = 2;\n\n            vm.assertEq(arr1, arr1);\n            vm.assertEq(arr2, arr2);\n            vm.assertNotEq(arr1, arr2);\n\n            vm._expectCheatcodeRevert(bytes(\"assertion failed: [1] != [1, 2]\"));\n            vm.assertEq(arr1, arr2);\n\n            vm._expectCheatcodeRevert(bytes(string.concat(\"assertion failed: [1, 2] == [1, 2]\")));\n            vm.assertNotEq(arr2, arr2);\n        }\n        {\n            int256[] memory arr1 = new int256[](2);\n            int256[] memory arr2 = new int256[](1);\n            arr1[0] = 5;\n            arr2[0] = type(int256).max;\n\n            vm.assertEq(arr1, arr1);\n            vm.assertEq(arr2, arr2);\n            vm.assertNotEq(arr1, arr2);\n\n            vm._expectCheatcodeRevert(bytes(string.concat(errorMessage, \": [5, 0] != [\", vm.toString(arr2[0]), \"]\")));\n            vm.assertEq(arr1, arr2, errorMessage);\n\n            vm._expectCheatcodeRevert(bytes(string.concat(\"assertion failed: [5, 0] == [5, 0]\")));\n            vm.assertNotEq(arr1, arr1);\n        }\n        {\n            bool[] memory arr1 = new bool[](2);\n            bool[] memory arr2 = new bool[](2);\n            arr1[0] = true;\n            arr2[1] = true;\n\n            vm.assertEq(arr1, arr1);\n            vm.assertEq(arr2, arr2);\n            vm.assertNotEq(arr1, arr2);\n\n            vm._expectCheatcodeRevert(bytes(string.concat(errorMessage, \": [true, false] != [false, true]\")));\n            vm.assertEq(arr1, arr2, errorMessage);\n\n            vm._expectCheatcodeRevert(bytes(string(\"assertion failed: [true, false] == [true, false]\")));\n            vm.assertNotEq(arr1, arr1);\n        }\n        {\n            address[] memory arr1 = new address[](1);\n            address[] memory arr2 = new address[](0);\n\n            vm.assertEq(arr1, arr1);\n            vm.assertEq(arr2, arr2);\n            vm.assertNotEq(arr1, arr2);\n\n            vm._expectCheatcodeRevert(bytes(string.concat(errorMessage, \": [\", vm.toString(arr1[0]), \"] != []\")));\n            vm.assertEq(arr1, arr2, errorMessage);\n\n            vm._expectCheatcodeRevert(bytes(string(\"assertion failed: [] == []\")));\n            vm.assertNotEq(arr2, arr2);\n        }\n        {\n            bytes32[] memory arr1 = new bytes32[](1);\n            bytes32[] memory arr2 = new bytes32[](1);\n            arr1[0] = bytes32(uint256(1));\n\n            vm.assertEq(arr1, arr1);\n            vm.assertEq(arr2, arr2);\n            vm.assertNotEq(arr1, arr2);\n\n            vm._expectCheatcodeRevert(\n                bytes(string.concat(errorMessage, \": [\", vm.toString(arr1[0]), \"] != [\", vm.toString(arr2[0]), \"]\"))\n            );\n            vm.assertEq(arr1, arr2, errorMessage);\n\n            vm._expectCheatcodeRevert(\n                bytes(string.concat(\"assertion failed: [\", vm.toString(arr2[0]), \"] == [\", vm.toString(arr2[0]), \"]\"))\n            );\n            vm.assertNotEq(arr2, arr2);\n        }\n        {\n            string[] memory arr1 = new string[](1);\n            string[] memory arr2 = new string[](3);\n\n            arr1[0] = \"foo\";\n            arr2[2] = \"bar\";\n\n            vm.assertEq(arr1, arr1);\n            vm.assertEq(arr2, arr2);\n            vm.assertNotEq(arr1, arr2);\n\n            vm._expectCheatcodeRevert(bytes(\"assertion failed: [foo] != [, , bar]\"));\n            vm.assertEq(arr1, arr2);\n\n            vm._expectCheatcodeRevert(bytes(string.concat(errorMessage, \": [foo] == [foo]\")));\n            vm.assertNotEq(arr1, arr1, errorMessage);\n        }\n        {\n            bytes[] memory arr1 = new bytes[](1);\n            bytes[] memory arr2 = new bytes[](2);\n\n            arr1[0] = hex\"1111\";\n            arr2[1] = hex\"1234\";\n\n            vm.assertEq(arr1, arr1);\n            vm.assertEq(arr2, arr2);\n            vm.assertNotEq(arr1, arr2);\n\n            vm._expectCheatcodeRevert(bytes(\"assertion failed: [0x1111] != [0x, 0x1234]\"));\n            vm.assertEq(arr1, arr2);\n\n            vm._expectCheatcodeRevert(bytes(string.concat(errorMessage, \": [0x1111] == [0x1111]\")));\n            vm.assertNotEq(arr1, arr1, errorMessage);\n        }\n    }\n\n    function testAssertBool() public {\n        vm.assertTrue(true);\n        vm.assertFalse(false);\n\n        vm._expectCheatcodeRevert(bytes(\"assertion failed\"));\n        vm.assertTrue(false);\n\n        vm._expectCheatcodeRevert(bytes(errorMessage));\n        vm.assertTrue(false, errorMessage);\n\n        vm._expectCheatcodeRevert(bytes(\"assertion failed\"));\n        vm.assertFalse(true);\n\n        vm._expectCheatcodeRevert(bytes(errorMessage));\n        vm.assertFalse(true, errorMessage);\n    }\n\n    function testAssertApproxEqRel() public {\n        vm._expectCheatcodeRevert(\n            bytes(string.concat(errorMessage, \": 1 !~= 0 (max delta: 0.0000000000000000%, real delta: undefined)\"))\n        );\n        vm.assertApproxEqRel(int256(1), int256(0), 0, errorMessage);\n\n        vm._expectCheatcodeRevert(\n            bytes(\"assertion failed: 1 !~= 0 (max delta: 0.0000000000000000%, real delta: undefined)\")\n        );\n        vm.assertApproxEqRel(uint256(1), uint256(0), uint256(0));\n\n        vm._expectCheatcodeRevert(bytes(\"assertion failed: overflow in delta calculation\"));\n        vm.assertApproxEqRel(type(uint256).max, 1, 1);\n\n        vm.assertApproxEqRel(type(int256).min, type(int256).max, 2e18);\n        vm.assertApproxEqRel(uint256(0), type(uint256).max, 1e18);\n        vm.assertApproxEqRel(uint256(0), uint256(0), uint256(0));\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/Assume.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract AssumeTest is Test {\n    function testAssume(uint8 x) public {\n        vm.assume(x < 2 ** 7);\n        assertTrue(x < 2 ** 7, \"did not discard inputs\");\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/AssumeNoRevert.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract ReverterB {\n    /// @notice has same error selectors as contract below to test the `reverter` param\n    error MyRevert();\n    error SpecialRevertWithData(uint256 x);\n\n    function revertIf2(uint256 x) public pure returns (bool) {\n        if (x == 2) {\n            revert MyRevert();\n        }\n        return true;\n    }\n\n    function revertWithData() public pure returns (bool) {\n        revert SpecialRevertWithData(2);\n    }\n}\n\ncontract Reverter {\n    error MyRevert();\n    error RevertWithData(uint256 x);\n    error UnusedError();\n\n    ReverterB public immutable subReverter;\n\n    constructor() {\n        subReverter = new ReverterB();\n    }\n\n    function myFunction() public pure returns (bool) {\n        revert MyRevert();\n    }\n\n    function revertIf2(uint256 value) public pure returns (bool) {\n        if (value == 2) {\n            revert MyRevert();\n        }\n        return true;\n    }\n\n    function revertWithDataIf2(uint256 value) public pure returns (bool) {\n        if (value == 2) {\n            revert RevertWithData(2);\n        }\n        return true;\n    }\n\n    function twoPossibleReverts(uint256 x) public pure returns (bool) {\n        if (x == 2) {\n            revert MyRevert();\n        } else if (x == 3) {\n            revert RevertWithData(3);\n        }\n        return true;\n    }\n}\n\ncontract ReverterTest is Test {\n    Reverter reverter;\n\n    function setUp() public {\n        reverter = new Reverter();\n    }\n\n    /// @dev Test that `assumeNoRevert` anticipates and correctly rejects a specific error selector\n    function testAssumeSelector(uint256 x) public view {\n        vm.assumeNoRevert(\n            Vm.PotentialRevert({\n                revertData: abi.encodeWithSelector(Reverter.MyRevert.selector),\n                partialMatch: false,\n                reverter: address(0)\n            })\n        );\n        reverter.revertIf2(x);\n    }\n\n    /// @dev Test that `assumeNoRevert` anticipates and correctly rejects a specific error selector and data\n    function testAssumeWithDataSingle(uint256 x) public view {\n        vm.assumeNoRevert(\n            Vm.PotentialRevert({\n                revertData: abi.encodeWithSelector(Reverter.RevertWithData.selector, 2),\n                partialMatch: false,\n                reverter: address(0)\n            })\n        );\n        reverter.revertWithDataIf2(x);\n    }\n\n    /// @dev Test that `assumeNoRevert` anticipates and correctly rejects a specific error selector with any extra data (ie providing selector allows for arbitrary extra data)\n    function testAssumeWithDataPartial(uint256 x) public view {\n        vm.assumeNoRevert(\n            Vm.PotentialRevert({\n                revertData: abi.encodeWithSelector(Reverter.RevertWithData.selector),\n                partialMatch: true,\n                reverter: address(0)\n            })\n        );\n        reverter.revertWithDataIf2(x);\n    }\n\n    /// @dev Test that `assumeNoRevert` assumptions are not cleared after a cheatcode call\n    function testAssumeNotClearedAfterCheatcodeCall(uint256 x) public {\n        vm.assumeNoRevert(\n            Vm.PotentialRevert({\n                revertData: abi.encodeWithSelector(Reverter.MyRevert.selector),\n                partialMatch: false,\n                reverter: address(0)\n            })\n        );\n        vm.warp(block.timestamp + 1000);\n        reverter.revertIf2(x);\n    }\n\n    /// @dev Test that `assumeNoRevert` correctly rejects two different error selectors\n    function testMultipleAssumesPasses(uint256 x) public view {\n        Vm.PotentialRevert[] memory revertData = new Vm.PotentialRevert[](2);\n        revertData[0] = Vm.PotentialRevert({\n            revertData: abi.encodeWithSelector(Reverter.MyRevert.selector),\n            partialMatch: false,\n            reverter: address(reverter)\n        });\n        revertData[1] = Vm.PotentialRevert({\n            revertData: abi.encodeWithSelector(Reverter.RevertWithData.selector, 3),\n            partialMatch: false,\n            reverter: address(reverter)\n        });\n        vm.assumeNoRevert(revertData);\n        reverter.twoPossibleReverts(x);\n    }\n\n    /// @dev Test that `assumeNoRevert` correctly interacts with itself when partially matching on the error selector\n    function testMultipleAssumes_Partial(uint256 x) public view {\n        Vm.PotentialRevert[] memory revertData = new Vm.PotentialRevert[](2);\n        revertData[0] = Vm.PotentialRevert({\n            revertData: abi.encodeWithSelector(Reverter.RevertWithData.selector),\n            partialMatch: true,\n            reverter: address(reverter)\n        });\n        revertData[1] = Vm.PotentialRevert({\n            revertData: abi.encodeWithSelector(Reverter.MyRevert.selector),\n            partialMatch: false,\n            reverter: address(reverter)\n        });\n        vm.assumeNoRevert(revertData);\n        reverter.twoPossibleReverts(x);\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/AttachBlob.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.25;\n\nimport \"utils/Test.sol\";\n\ncontract Counter {\n    uint256 public counter;\n\n    function increment() public {\n        counter++;\n    }\n}\n\ncontract AttachBlobTest is Test {\n    uint256 bobPk = 0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d;\n    address bob = 0x70997970C51812dc3A010C7d01b50e0d17dc79C8;\n\n    Counter public counter;\n\n    function setUp() public {\n        counter = new Counter();\n    }\n\n    function testAttachBlob() public {\n        bytes memory blob = abi.encode(\"Blob the Builder\");\n        vm.attachBlob(blob);\n\n        vm.broadcast(bobPk);\n        counter.increment();\n    }\n\n    function testAttachBlobWithCreateTx() public {\n        bytes memory blob = abi.encode(\"Blob the Builder\");\n        vm.attachBlob(blob);\n\n        vm.broadcast(bobPk);\n        new Counter();\n\n        // blob is attached with this tx instead\n        vm.broadcast(bobPk);\n        counter.increment();\n    }\n\n    /// forge-config: default.allow_internal_expect_revert = true\n    function testRevertAttachBlobWithDelegation() public {\n        bytes memory blob = abi.encode(\"Blob the Builder\");\n        vm.attachBlob(blob);\n        vm.signAndAttachDelegation(address(0), bobPk);\n\n        vm.broadcast(bobPk);\n        vm.expectRevert(\"both delegation and blob are active; `attachBlob` and `attachDelegation` are not compatible\");\n        counter.increment();\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/AttachDelegation.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity 0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract AttachDelegationTest is Test {\n    event ExecutedBy(uint256 id);\n\n    uint256 alice_pk = 0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d;\n    address payable alice = payable(0x70997970C51812dc3A010C7d01b50e0d17dc79C8);\n    uint256 bob_pk = 0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a;\n    address bob = 0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC;\n\n    SimpleDelegateContract implementation;\n    SimpleDelegateContract implementation2;\n    ERC20 token;\n\n    function setUp() public {\n        implementation = new SimpleDelegateContract(1);\n        implementation2 = new SimpleDelegateContract(2);\n        token = new ERC20(alice);\n    }\n\n    function testCallSingleAttachDelegation() public {\n        Vm.SignedDelegation memory signedDelegation = vm.signDelegation(address(implementation), alice_pk);\n        SimpleDelegateContract.Call[] memory calls = new SimpleDelegateContract.Call[](1);\n        bytes memory data = abi.encodeCall(ERC20.mint, (100, bob));\n        calls[0] = SimpleDelegateContract.Call({to: address(token), data: data, value: 0});\n        // executing as bob to make clear that we don't need to execute the tx as alice\n        vm.broadcast(bob_pk);\n        vm.attachDelegation(signedDelegation);\n\n        bytes memory code = address(alice).code;\n        require(code.length > 0, \"no code written to alice\");\n        SimpleDelegateContract(alice).execute(calls);\n\n        assertEq(token.balanceOf(bob), 100);\n    }\n\n    function testCallSingleAttachCrossChainDelegation() public {\n        Vm.SignedDelegation memory signedDelegation = vm.signDelegation(address(implementation), alice_pk, true);\n        SimpleDelegateContract.Call[] memory calls = new SimpleDelegateContract.Call[](1);\n        bytes memory data = abi.encodeCall(ERC20.mint, (100, bob));\n        calls[0] = SimpleDelegateContract.Call({to: address(token), data: data, value: 0});\n        // executing as bob to make clear that we don't need to execute the tx as alice\n        vm.broadcast(bob_pk);\n        vm.attachDelegation(signedDelegation, true);\n\n        bytes memory code = address(alice).code;\n        require(code.length > 0, \"no code written to alice\");\n        SimpleDelegateContract(alice).execute(calls);\n\n        assertEq(token.balanceOf(bob), 100);\n    }\n\n    /// forge-config: default.allow_internal_expect_revert = true\n    function testCallSingleAttachDelegationWithNonce() public {\n        Vm.SignedDelegation memory signedDelegation = vm.signDelegation(address(implementation), alice_pk, 11);\n        vm.broadcast(bob_pk);\n        vm._expectCheatcodeRevert(\"vm.attachDelegation: invalid nonce\");\n        vm.attachDelegation(signedDelegation);\n\n        signedDelegation = vm.signDelegation(address(implementation), alice_pk, 0);\n        vm.attachDelegation(signedDelegation);\n    }\n\n    function testMultiCallAttachDelegation() public {\n        Vm.SignedDelegation memory signedDelegation = vm.signDelegation(address(implementation), alice_pk);\n        vm.broadcast(bob_pk);\n        vm.attachDelegation(signedDelegation);\n\n        SimpleDelegateContract.Call[] memory calls = new SimpleDelegateContract.Call[](2);\n        calls[0] =\n            SimpleDelegateContract.Call({to: address(token), data: abi.encodeCall(ERC20.mint, (50, bob)), value: 0});\n        calls[1] = SimpleDelegateContract.Call({\n            to: address(token), data: abi.encodeCall(ERC20.mint, (50, address(this))), value: 0\n        });\n\n        SimpleDelegateContract(alice).execute(calls);\n\n        assertEq(token.balanceOf(bob), 50);\n        assertEq(token.balanceOf(address(this)), 50);\n    }\n\n    function testMultiCallAttachCrossChainDelegation() public {\n        Vm.SignedDelegation memory signedDelegation = vm.signDelegation(address(implementation), alice_pk, true);\n        vm.broadcast(bob_pk);\n        vm.attachDelegation(signedDelegation, true);\n\n        SimpleDelegateContract.Call[] memory calls = new SimpleDelegateContract.Call[](2);\n        calls[0] =\n            SimpleDelegateContract.Call({to: address(token), data: abi.encodeCall(ERC20.mint, (50, bob)), value: 0});\n        calls[1] = SimpleDelegateContract.Call({\n            to: address(token), data: abi.encodeCall(ERC20.mint, (50, address(this))), value: 0\n        });\n\n        SimpleDelegateContract(alice).execute(calls);\n\n        assertEq(token.balanceOf(bob), 50);\n        assertEq(token.balanceOf(address(this)), 50);\n    }\n\n    function testSwitchAttachDelegation() public {\n        Vm.SignedDelegation memory signedDelegation = vm.signDelegation(address(implementation), alice_pk);\n\n        SimpleDelegateContract.Call[] memory calls = new SimpleDelegateContract.Call[](1);\n        bytes memory data = abi.encodeCall(ERC20.mint, (100, bob));\n        calls[0] = SimpleDelegateContract.Call({to: address(token), data: data, value: 0});\n\n        vm.broadcast(bob_pk);\n        vm.attachDelegation(signedDelegation);\n\n        vm.expectEmit(true, true, true, true);\n        emit ExecutedBy(1);\n        SimpleDelegateContract(alice).execute(calls);\n\n        // switch to implementation2\n        Vm.SignedDelegation memory signedDelegation2 = vm.signDelegation(address(implementation2), alice_pk);\n        vm.broadcast(bob_pk);\n        vm.attachDelegation(signedDelegation2);\n\n        vm.expectEmit(true, true, true, true);\n        emit ExecutedBy(2);\n        SimpleDelegateContract(alice).execute(calls);\n\n        // verify final state\n        assertEq(token.balanceOf(bob), 200);\n    }\n\n    /// forge-config: default.allow_internal_expect_revert = true\n    function testAttachDelegationRevertInvalidSignature() public {\n        Vm.SignedDelegation memory signedDelegation = vm.signDelegation(address(implementation), alice_pk);\n        // change v from 1 to 0\n        signedDelegation.v = (signedDelegation.v + 1) % 2;\n        vm.attachDelegation(signedDelegation);\n\n        SimpleDelegateContract.Call[] memory calls = new SimpleDelegateContract.Call[](1);\n        bytes memory data = abi.encodeCall(ERC20.mint, (100, bob));\n        calls[0] = SimpleDelegateContract.Call({to: address(token), data: data, value: 0});\n\n        vm.broadcast(alice_pk);\n        // empty revert because no bytecode was set to Alice's account\n        vm.expectRevert();\n        SimpleDelegateContract(alice).execute(calls);\n    }\n\n    function testAttachDelegationRevertsAfterNonceChange() public {\n        Vm.SignedDelegation memory signedDelegation = vm.signDelegation(address(implementation), alice_pk);\n\n        vm.broadcast(alice_pk);\n        // send tx to increment alice's nonce\n        token.mint(1, bob);\n\n        vm._expectCheatcodeRevert(\"vm.attachDelegation: invalid nonce\");\n        vm.attachDelegation(signedDelegation);\n    }\n\n    function testCallSingleSignAndAttachDelegation() public {\n        SimpleDelegateContract.Call[] memory calls = new SimpleDelegateContract.Call[](1);\n        bytes memory data = abi.encodeCall(ERC20.mint, (100, bob));\n        calls[0] = SimpleDelegateContract.Call({to: address(token), data: data, value: 0});\n        vm.signAndAttachDelegation(address(implementation), alice_pk);\n        bytes memory code = address(alice).code;\n        require(code.length > 0, \"no code written to alice\");\n        vm.broadcast(bob_pk);\n        SimpleDelegateContract(alice).execute(calls);\n\n        assertEq(token.balanceOf(bob), 100);\n    }\n\n    function testCallSingleSignAndAttachCrossChainDelegation() public {\n        SimpleDelegateContract.Call[] memory calls = new SimpleDelegateContract.Call[](1);\n        bytes memory data = abi.encodeCall(ERC20.mint, (100, bob));\n        calls[0] = SimpleDelegateContract.Call({to: address(token), data: data, value: 0});\n        vm.signAndAttachDelegation(address(implementation), alice_pk, true);\n        bytes memory code = address(alice).code;\n        require(code.length > 0, \"no code written to alice\");\n        vm.broadcast(bob_pk);\n        SimpleDelegateContract(alice).execute(calls);\n\n        assertEq(token.balanceOf(bob), 100);\n    }\n\n    /// forge-config: default.allow_internal_expect_revert = true\n    function testCallSingleSignAndAttachDelegationWithNonce() public {\n        vm._expectCheatcodeRevert(\"vm.signAndAttachDelegation: invalid nonce\");\n        vm.signAndAttachDelegation(address(implementation), alice_pk, 11);\n\n        vm.signAndAttachDelegation(address(implementation), alice_pk, 0);\n    }\n\n    function testMultipleDelegationsOnTransaction() public {\n        vm.signAndAttachDelegation(address(implementation), alice_pk);\n        vm.signAndAttachDelegation(address(implementation2), bob_pk);\n        SimpleDelegateContract.Call[] memory calls = new SimpleDelegateContract.Call[](2);\n        calls[0] = SimpleDelegateContract.Call({\n            to: address(token), data: abi.encodeCall(ERC20.mint, (50, address(this))), value: 0\n        });\n        calls[1] =\n            SimpleDelegateContract.Call({to: address(token), data: abi.encodeCall(ERC20.mint, (50, alice)), value: 0});\n        vm.broadcast(bob_pk);\n        SimpleDelegateContract(alice).execute(calls);\n\n        assertEq(token.balanceOf(address(this)), 50);\n        assertEq(token.balanceOf(alice), 50);\n\n        vm._expectCheatcodeRevert(\"vm.signAndAttachDelegation: invalid nonce\");\n        vm.signAndAttachDelegation(address(implementation), alice_pk, 1);\n        vm.signAndAttachDelegation(address(implementation), alice_pk, 0);\n        vm.signAndAttachDelegation(address(implementation2), bob_pk, 2);\n    }\n}\n\ncontract SimpleDelegateContract {\n    event Executed(address indexed to, uint256 value, bytes data);\n    event ExecutedBy(uint256 id);\n\n    struct Call {\n        bytes data;\n        address to;\n        uint256 value;\n    }\n\n    uint256 public immutable id;\n\n    constructor(uint256 _id) {\n        id = _id;\n    }\n\n    function execute(Call[] memory calls) external payable {\n        for (uint256 i = 0; i < calls.length; i++) {\n            Call memory call = calls[i];\n            (bool success, bytes memory result) = call.to.call{value: call.value}(call.data);\n            require(success, string(result));\n            emit Executed(call.to, call.value, call.data);\n            emit ExecutedBy(id);\n        }\n    }\n\n    receive() external payable {}\n}\n\ncontract ERC20 {\n    address public minter;\n    mapping(address => uint256) private _balances;\n\n    constructor(address _minter) {\n        minter = _minter;\n    }\n\n    function mint(uint256 amount, address to) public {\n        _mint(to, amount);\n    }\n\n    function balanceOf(address account) public view returns (uint256) {\n        return _balances[account];\n    }\n\n    function _mint(address account, uint256 amount) internal {\n        require(msg.sender == minter, \"ERC20: msg.sender is not minter\");\n        require(account != address(0), \"ERC20: mint to the zero address\");\n        unchecked {\n            _balances[account] += amount;\n        }\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/Bank.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract CoinbaseTest is Test {\n    function testCoinbase() public {\n        vm.coinbase(0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8);\n        assertEq(block.coinbase, 0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8, \"coinbase failed\");\n    }\n\n    function testCoinbaseFuzzed(address who) public {\n        vm.coinbase(who);\n        assertEq(block.coinbase, who, \"coinbase failed\");\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/Base64.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract Base64Test is Test {\n    function test_toBase64() public {\n        bytes memory input = hex\"00112233445566778899aabbccddeeff\";\n        string memory expected = \"ABEiM0RVZneImaq7zN3u/w==\";\n        string memory actual = vm.toBase64(input);\n        assertEq(actual, expected);\n    }\n\n    function test_toBase64URL() public {\n        bytes memory input = hex\"00112233445566778899aabbccddeeff\";\n        string memory expected = \"ABEiM0RVZneImaq7zN3u_w==\";\n        string memory actual = vm.toBase64URL(input);\n        assertEq(actual, expected);\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/BlobBaseFee.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.25;\n\nimport \"utils/Test.sol\";\n\ncontract BlobBaseFeeTest is Test {\n    function test_blob_base_fee() public {\n        vm.blobBaseFee(6969);\n        assertEq(vm.getBlobBaseFee(), 6969);\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/Blobhashes.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.25;\n\nimport \"utils/Test.sol\";\n\ncontract BlobhashesTest is Test {\n    function testSetAndGetBlobhashes() public {\n        bytes32[] memory blobhashes = new bytes32[](2);\n        blobhashes[0] = bytes32(0x0000000000000000000000000000000000000000000000000000000000000001);\n        blobhashes[1] = bytes32(0x0000000000000000000000000000000000000000000000000000000000000002);\n        vm.blobhashes(blobhashes);\n\n        bytes32[] memory gotBlobhashes = vm.getBlobhashes();\n        assertEq(gotBlobhashes[0], blobhashes[0]);\n        assertEq(gotBlobhashes[1], blobhashes[1]);\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/Broadcast.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport {Test as ForgeTest} from \"utils/Test.sol\";\n\nlibrary F {\n    function t2() public pure returns (uint256) {\n        return 1;\n    }\n}\n\ncontract Test is ForgeTest {\n    uint256 public changed = 0;\n\n    function t(uint256 a) public returns (uint256) {\n        uint256 b = 0;\n        for (uint256 i; i < a; i++) {\n            b += F.t2();\n        }\n        emit log_string(\"here\");\n        return b;\n    }\n\n    function inc() public {\n        changed += 1;\n    }\n\n    function multiple_arguments(uint256 a, address b, uint256[] memory c) public returns (uint256) {}\n\n    function echoSender() public view returns (address) {\n        return msg.sender;\n    }\n}\n\ncontract BroadcastTest is ForgeTest {\n    // 1st anvil account\n    address public ACCOUNT_A = 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266;\n    // 2nd anvil account\n    address public ACCOUNT_B = 0x70997970C51812dc3A010C7d01b50e0d17dc79C8;\n\n    function deploy() public {\n        vm.broadcast(ACCOUNT_A);\n        Test test = new Test();\n\n        // this wont generate tx to sign\n        uint256 b = test.t(4);\n\n        // this will\n        vm.broadcast(ACCOUNT_B);\n        test.t(2);\n    }\n\n    function deployPrivateKey() public {\n        string memory mnemonic = \"test test test test test test test test test test test junk\";\n\n        uint256 privateKey = vm.deriveKey(mnemonic, 3);\n        assertEq(privateKey, 0x7c852118294e51e653712a81e05800f419141751be58f605c371e15141b007a6);\n\n        vm.broadcast(privateKey);\n        Test test = new Test();\n\n        vm.startBroadcast(privateKey);\n        Test test2 = new Test();\n        vm.stopBroadcast();\n    }\n\n    function deployRememberKey() public {\n        string memory mnemonic = \"test test test test test test test test test test test junk\";\n\n        uint256 privateKey = vm.deriveKey(mnemonic, 3);\n        assertEq(privateKey, 0x7c852118294e51e653712a81e05800f419141751be58f605c371e15141b007a6);\n\n        address thisAddress = vm.rememberKey(privateKey);\n        assertEq(thisAddress, 0x90F79bf6EB2c4f870365E785982E1f101E93b906);\n\n        vm.broadcast(thisAddress);\n        Test test = new Test();\n    }\n\n    function deployRememberKeyResume() public {\n        vm.broadcast(ACCOUNT_A);\n        Test test = new Test();\n\n        string memory mnemonic = \"test test test test test test test test test test test junk\";\n\n        uint256 privateKey = vm.deriveKey(mnemonic, 3);\n        address thisAddress = vm.rememberKey(privateKey);\n\n        vm.broadcast(thisAddress);\n        Test test2 = new Test();\n    }\n\n    function deployOther() public {\n        vm.startBroadcast(ACCOUNT_A);\n        Test tmptest = new Test();\n        Test test = new Test();\n\n        // won't trigger a transaction: staticcall\n        test.changed();\n\n        // won't trigger a transaction: staticcall\n        require(test.echoSender() == ACCOUNT_A);\n\n        // will trigger a transaction\n        test.t(1);\n\n        // will trigger a transaction\n        test.inc();\n\n        vm.stopBroadcast();\n\n        vm.broadcast(ACCOUNT_B);\n        Test tmptest2 = new Test();\n\n        vm.broadcast(ACCOUNT_B);\n        // will trigger a transaction\n        test.t(2);\n\n        vm.broadcast(ACCOUNT_B);\n        // will trigger a transaction from B\n        payable(ACCOUNT_A).transfer(2);\n\n        vm.broadcast(ACCOUNT_B);\n        // will trigger a transaction\n        test.inc();\n\n        assert(test.changed() == 2);\n    }\n\n    function deployPanics() public {\n        vm.broadcast(address(0x1337));\n        Test test = new Test();\n\n        // This panics because this would cause an additional relinking that isnt conceptually correct\n        // from a solidity standpoint. Basically, this contract `BroadcastTest`, injects the code of\n        // `Test` *into* its code. So it isn't reasonable to break solidity to our will of having *two*\n        // versions of `Test` based on the sender/linker.\n        vm.broadcast(address(0x1338));\n        new Test();\n\n        vm.broadcast(address(0x1338));\n        test.t(0);\n    }\n\n    function deployNoArgs() public {\n        vm.startBroadcast();\n        Test test1 = new Test();\n\n        Test test2 = new Test();\n        vm.stopBroadcast();\n    }\n\n    /// forge-config: default.allow_internal_expect_revert = true\n    // function testRevertIfNoBroadcast() public {\n    //     vm.expectRevert();\n    //     vm.stopBroadcast();\n    // }\n}\n\ncontract NoLink is ForgeTest {\n    function t(uint256 a) public returns (uint256) {\n        uint256 b = 0;\n        for (uint256 i; i < a; i++) {\n            b += i;\n        }\n        emit log_string(\"here\");\n        return b;\n    }\n\n    function view_me() public pure returns (uint256) {\n        return 1337;\n    }\n}\n\ninterface INoLink {\n    function t(uint256 a) external returns (uint256);\n}\n\ncontract BroadcastTestNoLinking is ForgeTest {\n    // ganache-cli -d 1st\n    address public ACCOUNT_A = 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266;\n\n    // ganache-cli -d 2nd\n    address public ACCOUNT_B = 0x70997970C51812dc3A010C7d01b50e0d17dc79C8;\n\n    function deployDoesntPanic() public {\n        vm.broadcast(address(ACCOUNT_A));\n        NoLink test = new NoLink();\n\n        vm.broadcast(address(ACCOUNT_B));\n        new NoLink();\n\n        vm.broadcast(address(ACCOUNT_B));\n        test.t(0);\n    }\n\n    function deployMany() public {\n        assert(vm.getNonce(msg.sender) == 0);\n\n        vm.startBroadcast();\n\n        for (uint256 i; i < 25; i++) {\n            NoLink test9 = new NoLink();\n        }\n\n        vm.stopBroadcast();\n    }\n\n    function deployCreate2() public {\n        vm.startBroadcast();\n        NoLink test_c2 = new NoLink{salt: bytes32(uint256(1337))}();\n        assert(test_c2.view_me() == 1337);\n        NoLink test2 = new NoLink();\n        vm.stopBroadcast();\n    }\n\n    function deployCreate2(address deployer) public {\n        vm.startBroadcast();\n        bytes32 salt = bytes32(uint256(1338));\n        NoLink test_c2 = new NoLink{salt: salt}();\n        assert(test_c2.view_me() == 1337);\n\n        address expectedAddress = address(\n            uint160(\n                uint256(\n                    keccak256(\n                        abi.encodePacked(\n                            bytes1(0xff),\n                            deployer,\n                            salt,\n                            keccak256(abi.encodePacked(type(NoLink).creationCode, abi.encode()))\n                        )\n                    )\n                )\n            )\n        );\n        require(address(test_c2) == expectedAddress, \"Create2 address mismatch\");\n\n        NoLink test2 = new NoLink();\n        vm.stopBroadcast();\n    }\n\n    function errorStaticCall() public {\n        vm.broadcast();\n        NoLink test11 = new NoLink();\n\n        vm.broadcast();\n        test11.view_me();\n    }\n}\n\ncontract BroadcastMix is ForgeTest {\n    // ganache-cli -d 1st\n    address public ACCOUNT_A = 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266;\n\n    // ganache-cli -d 2nd\n    address public ACCOUNT_B = 0x70997970C51812dc3A010C7d01b50e0d17dc79C8;\n\n    function more() internal {\n        vm.broadcast();\n        NoLink test11 = new NoLink();\n    }\n\n    function deployMix() public {\n        address user = msg.sender;\n        assert(user == address(0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266));\n\n        NoLink no = new NoLink();\n\n        vm.startBroadcast();\n        NoLink test1 = new NoLink();\n        test1.t(2);\n        NoLink test2 = new NoLink();\n        test2.t(2);\n        vm.stopBroadcast();\n\n        vm.startBroadcast(user);\n        NoLink test3 = new NoLink();\n        NoLink test4 = new NoLink();\n        test4.t(2);\n        vm.stopBroadcast();\n\n        vm.broadcast();\n        test4.t(2);\n\n        vm.broadcast();\n        NoLink test5 = new NoLink();\n\n        vm.broadcast();\n        INoLink test6 = INoLink(address(new NoLink()));\n\n        vm.broadcast();\n        NoLink test7 = new NoLink();\n\n        vm.broadcast(user);\n        NoLink test8 = new NoLink();\n\n        vm.broadcast();\n        NoLink test9 = new NoLink();\n\n        vm.broadcast(user);\n        NoLink test10 = new NoLink();\n\n        more();\n    }\n}\n\ncontract BroadcastTestSetup is ForgeTest {\n    function setUp() public {\n        // It predeployed a library first\n        assert(vm.getNonce(msg.sender) == 1);\n\n        vm.broadcast();\n        Test t = new Test();\n\n        vm.broadcast();\n        t.t(2);\n    }\n\n    function run() public {\n        vm.broadcast();\n        new NoLink();\n\n        vm.broadcast();\n        Test t = new Test();\n\n        vm.broadcast();\n        t.t(3);\n    }\n}\n\ncontract BroadcastTestLog is ForgeTest {\n    function run() public {\n        uint256[] memory arr = new uint256[](2);\n        arr[0] = 3;\n        arr[1] = 4;\n\n        vm.startBroadcast();\n        {\n            Test c1 = new Test();\n            Test c2 = new Test{salt: bytes32(uint256(1337))}();\n\n            c1.multiple_arguments(1, address(0x1337), arr);\n            c1.inc();\n            c2.t(1);\n\n            payable(address(0x1337)).transfer(0.0001 ether);\n        }\n        vm.stopBroadcast();\n    }\n}\n\ncontract TestInitialBalance is ForgeTest {\n    function runCustomSender() public {\n        // Make sure we're testing a different caller than the default one.\n        assert(msg.sender != address(0x00a329c0648769A73afAc7F9381E08FB43dBEA72));\n\n        // NodeConfig::test() sets the balance of the address used in this ForgeTest to 100 ether.\n        assert(msg.sender.balance == 100 ether);\n\n        vm.broadcast();\n        new NoLink();\n    }\n\n    function runDefaultSender() public {\n        // Make sure we're testing with the default caller.\n        assert(msg.sender == address(0x1804c8AB1F12E6bbf3894d4083f33e07309d1f38));\n\n        assert(msg.sender.balance == type(uint256).max);\n\n        vm.broadcast();\n        new NoLink();\n    }\n}\n\ncontract MultiChainBroadcastNoLink is ForgeTest {\n    // ganache-cli -d 1st\n    address public ACCOUNT_A = 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266;\n\n    // ganache-cli -d 2nd\n    address public ACCOUNT_B = 0x70997970C51812dc3A010C7d01b50e0d17dc79C8;\n\n    function deploy(string memory sforkA, string memory sforkB) public {\n        uint256 forkA = vm.createFork(sforkA);\n        uint256 forkB = vm.createFork(sforkB);\n\n        vm.selectFork(forkA);\n        vm.broadcast(address(ACCOUNT_A));\n        new NoLink();\n        vm.broadcast(address(ACCOUNT_B));\n        new NoLink();\n        vm.selectFork(forkB);\n        vm.startBroadcast(address(ACCOUNT_B));\n        new NoLink();\n        new NoLink();\n        new NoLink();\n        vm.stopBroadcast();\n        vm.startBroadcast(address(ACCOUNT_A));\n        new NoLink();\n        new NoLink();\n    }\n\n    function deployError(string memory sforkA, string memory sforkB) public {\n        uint256 forkA = vm.createFork(sforkA);\n        uint256 forkB = vm.createFork(sforkB);\n\n        vm.selectFork(forkA);\n        vm.broadcast(address(ACCOUNT_A));\n        new NoLink();\n        vm.startBroadcast(address(ACCOUNT_B));\n        new NoLink();\n\n        vm.selectFork(forkB);\n        vm.broadcast(address(ACCOUNT_B));\n        new NoLink();\n    }\n}\n\ncontract MultiChainBroadcastLink is ForgeTest {\n    // ganache-cli -d 1st\n    address public ACCOUNT_A = 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266;\n\n    // ganache-cli -d 2nd\n    address public ACCOUNT_B = 0x70997970C51812dc3A010C7d01b50e0d17dc79C8;\n\n    function deploy(string memory sforkA, string memory sforkB) public {\n        uint256 forkA = vm.createFork(sforkA);\n        uint256 forkB = vm.createFork(sforkB);\n\n        vm.selectFork(forkA);\n        vm.broadcast(address(ACCOUNT_B));\n        new Test();\n\n        vm.selectFork(forkB);\n        vm.broadcast(address(ACCOUNT_B));\n        new Test();\n    }\n}\n\ncontract BroadcastEmptySetUp is ForgeTest {\n    function setUp() public {}\n\n    function run() public {\n        vm.broadcast();\n        new Test();\n    }\n}\n\ncontract ContractA {\n    uint256 var1;\n\n    constructor(address script_caller) {\n        require(msg.sender == script_caller);\n        require(tx.origin == script_caller);\n    }\n\n    function method(address script_caller) public {\n        require(msg.sender == script_caller);\n        require(tx.origin == script_caller);\n    }\n}\n\ncontract ContractB {\n    uint256 var2;\n\n    constructor(address script_caller) {\n        require(address(0x1337) != script_caller);\n        require(msg.sender == address(0x1337));\n        require(tx.origin == address(0x1337));\n    }\n\n    function method(address script_caller) public {\n        require(address(0x1337) != script_caller);\n        require(msg.sender == address(0x1337));\n        require(tx.origin == address(0x1337));\n    }\n}\n\ncontract CheckOverrides is ForgeTest {\n    function run() external {\n        // `script_caller` can be set by `--private-key ...` or `--sender ...`\n        // Otherwise it will take the default value of 0x1804c8AB1F12E6bbf3894d4083f33e07309d1f38\n        address script_caller = msg.sender;\n        require(script_caller == 0x1804c8AB1F12E6bbf3894d4083f33e07309d1f38);\n        require(tx.origin == script_caller);\n\n        // startBroadcast(script_caller)\n        vm.startBroadcast();\n        require(tx.origin == script_caller);\n        require(msg.sender == script_caller);\n\n        ContractA a = new ContractA(script_caller);\n        require(tx.origin == script_caller);\n        require(msg.sender == script_caller);\n\n        a.method(script_caller);\n        require(tx.origin == script_caller);\n        require(msg.sender == script_caller);\n\n        vm.stopBroadcast();\n\n        // startBroadcast(msg.sender)\n        vm.startBroadcast(address(0x1337));\n        require(tx.origin == script_caller);\n        require(msg.sender == script_caller);\n        require(msg.sender != address(0x1337));\n\n        ContractB b = new ContractB(script_caller);\n        require(tx.origin == script_caller);\n        require(msg.sender == script_caller);\n\n        b.method(script_caller);\n        require(tx.origin == script_caller);\n        require(msg.sender == script_caller);\n\n        vm.stopBroadcast();\n    }\n}\n\ncontract Child {}\n\ncontract Parent {\n    constructor() {\n        new Child();\n    }\n}\n\ncontract ScriptAdditionalContracts is ForgeTest {\n    function run() external {\n        vm.startBroadcast();\n        new Parent();\n    }\n}\n\ncontract SignatureTester {\n    address public immutable owner;\n\n    constructor() {\n        owner = msg.sender;\n    }\n\n    function verifySignature(bytes32 digest, uint8 v, bytes32 r, bytes32 s) public view {\n        require(ecrecover(digest, v, r, s) == owner, \"Invalid signature\");\n    }\n}\n\ncontract ScriptSign is ForgeTest {\n    bytes32 digest = keccak256(\"something\");\n\n    function run() external {\n        vm.startBroadcast();\n        (uint8 v, bytes32 r, bytes32 s) = vm.sign(digest);\n\n        SignatureTester tester = new SignatureTester();\n        (, address caller,) = vm.readCallers();\n        assertEq(tester.owner(), caller);\n        tester.verifySignature(digest, v, r, s);\n    }\n\n    function run(address sender) external {\n        vm._expectCheatcodeRevert(bytes(\"could not determine signer\"));\n        vm.sign(digest);\n\n        (uint8 v, bytes32 r, bytes32 s) = vm.sign(sender, digest);\n        address actual = ecrecover(digest, v, r, s);\n\n        assertEq(actual, sender);\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/BroadcastRawTransaction.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract BroadcastRawTransactionTest is Test {\n    function test_revert_not_a_tx() public {\n        vm._expectCheatcodeRevert(\"failed to decode RLP-encoded transaction: unexpected string\");\n        vm.broadcastRawTransaction(hex\"0102\");\n    }\n\n    function test_revert_missing_signature() public {\n        vm._expectCheatcodeRevert(\"failed to decode RLP-encoded transaction: Unexpected type flag\");\n        vm.broadcastRawTransaction(hex\"dd806483030d40940993863c19b0defb183ca2b502db7d1b331ded757b80\");\n    }\n\n    function test_revert_wrong_chainid() public {\n        vm._expectCheatcodeRevert(\"transaction validation error: invalid chain ID\");\n        vm.broadcastRawTransaction(\n            hex\"f860806483030d40946fd0a0cff9a87adf51695b40b4fa267855a8f4c6118025a03ebeabbcfe43c2c982e99b376b5fb6e765059d7f215533c8751218cac99bbd80a00a56cf5c382442466770a756e81272d06005c9e90fb8dbc5b53af499d5aca856\"\n        );\n    }\n\n    function test_execute_signed_tx() public {\n        vm.fee(1);\n        vm.chainId(1);\n\n        address from = 0x5316812db67073C4d4af8BB3000C5B86c2877e94;\n        address to = 0x6Fd0A0CFF9A87aDF51695b40b4fA267855a8F4c6;\n\n        uint256 balance = 1 ether;\n        uint256 amountSent = 17;\n\n        vm.deal(address(from), balance);\n        assertEq(address(from).balance, balance);\n        assertEq(address(to).balance, 0);\n\n        /*\n        Signed transaction:\n        TransactionRequest { from: Some(0x5316812db67073c4d4af8bb3000c5b86c2877e94), to: Some(Address(0x6fd0a0cff9a87adf51695b40b4fa267855a8f4c6)), gas: Some(200000), gas_price: Some(100), value: Some(17), data: None, nonce: Some(0), chain_id: Some(1) }\n        */\n        vm.broadcastRawTransaction(\n            hex\"f860806483030d40946fd0a0cff9a87adf51695b40b4fa267855a8f4c6118025a03ebeabbcfe43c2c982e99b376b5fb6e765059d7f215533c8751218cac99bbd80a00a56cf5c382442466770a756e81272d06005c9e90fb8dbc5b53af499d5aca856\"\n        );\n\n        uint256 gasPrice = 100;\n        assertEq(address(from).balance, balance - (gasPrice * 21_000) - amountSent);\n        assertEq(address(to).balance, amountSent);\n    }\n\n    function test_execute_signed_tx2() public {\n        vm.fee(1);\n        vm.chainId(1);\n\n        address from = 0x5316812db67073C4d4af8BB3000C5B86c2877e94;\n        address to = 0x6Fd0A0CFF9A87aDF51695b40b4fA267855a8F4c6;\n        address random = address(uint160(uint256(keccak256(abi.encodePacked(\"random\")))));\n\n        uint256 balance = 1 ether;\n        uint256 amountSent = 17;\n\n        vm.deal(address(from), balance);\n        assertEq(address(from).balance, balance);\n        assertEq(address(to).balance, 0);\n\n        /*\n        Signed transaction:\n        TransactionRequest { from: Some(0x5316812db67073c4d4af8bb3000c5b86c2877e94), to: Some(Address(0x6fd0a0cff9a87adf51695b40b4fa267855a8f4c6)), gas: Some(200000), gas_price: Some(100), value: Some(17), data: None, nonce: Some(0), chain_id: Some(1) }\n        */\n        vm.broadcastRawTransaction(\n            hex\"f860806483030d40946fd0a0cff9a87adf51695b40b4fa267855a8f4c6118025a03ebeabbcfe43c2c982e99b376b5fb6e765059d7f215533c8751218cac99bbd80a00a56cf5c382442466770a756e81272d06005c9e90fb8dbc5b53af499d5aca856\"\n        );\n\n        uint256 gasPrice = 100;\n        assertEq(address(from).balance, balance - (gasPrice * 21_000) - amountSent);\n        assertEq(address(to).balance, amountSent);\n        assertEq(address(random).balance, 0);\n\n        uint256 value = 5;\n\n        vm.prank(to);\n        (bool success,) = random.call{value: value}(\"\");\n        require(success);\n        assertEq(address(to).balance, amountSent - value);\n        assertEq(address(random).balance, value);\n    }\n\n    // this test is to make sure that the journaledstate is correctly handled\n    // i ran into an issue where the test would fail after running `broadcastRawTransaction`\n    // because there was an issue in the journaledstate\n    function test_execute_signed_tx_with_revert() public {\n        vm.fee(1);\n        vm.chainId(1);\n\n        address from = 0x5316812db67073C4d4af8BB3000C5B86c2877e94;\n        address to = 0x6Fd0A0CFF9A87aDF51695b40b4fA267855a8F4c6;\n\n        uint256 balance = 1 ether;\n        uint256 amountSent = 17;\n\n        vm.deal(address(from), balance);\n        assertEq(address(from).balance, balance);\n        assertEq(address(to).balance, 0);\n\n        /*\n        Signed transaction:\n        TransactionRequest { from: Some(0x5316812db67073c4d4af8bb3000c5b86c2877e94), to: Some(Address(0x6fd0a0cff9a87adf51695b40b4fa267855a8f4c6)), gas: Some(200000), gas_price: Some(100), value: Some(17), data: None, nonce: Some(0), chain_id: Some(1) }\n        */\n        vm.broadcastRawTransaction(\n            hex\"f860806483030d40946fd0a0cff9a87adf51695b40b4fa267855a8f4c6118025a03ebeabbcfe43c2c982e99b376b5fb6e765059d7f215533c8751218cac99bbd80a00a56cf5c382442466770a756e81272d06005c9e90fb8dbc5b53af499d5aca856\"\n        );\n\n        uint256 gasPrice = 100;\n        assertEq(address(from).balance, balance - (gasPrice * 21_000) - amountSent);\n        assertEq(address(to).balance, amountSent);\n\n        vm._expectCheatcodeRevert();\n        vm.assertFalse(true);\n    }\n\n    function test_execute_multiple_signed_tx() public {\n        vm.fee(1);\n        vm.chainId(1);\n\n        address alice = 0x7ED31830602f9F7419307235c0610Fb262AA0375;\n        address bob = 0x70CF146aB98ffD5dE24e75dd7423F16181Da8E13;\n        address charlie = 0xae0900Cf97f8C233c64F7089cEC7d5457215BB8d;\n\n        // this is the runtime code of \"MyERC20\" (see below)\n        // this is equivalent to:\n        // type(MyERC20).runtimeCode\n        bytes memory code =\n            hex\"608060405234801561001057600080fd5b50600436106100625760003560e01c8063095ea7b31461006757806323b872dd1461008f57806370a08231146100a257806394bf804d146100d9578063a9059cbb146100ee578063dd62ed3e14610101575b600080fd5b61007a61007536600461051d565b61013a565b60405190151581526020015b60405180910390f35b61007a61009d366004610547565b610152565b6100cb6100b0366004610583565b6001600160a01b031660009081526020819052604090205490565b604051908152602001610086565b6100ec6100e73660046105a5565b610176565b005b61007a6100fc36600461051d565b610184565b6100cb61010f3660046105d1565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b600033610148818585610192565b5060019392505050565b600033610160858285610286565b61016b858585610318565b506001949350505050565b6101808183610489565b5050565b600033610148818585610318565b6001600160a01b0383166101f95760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b60648201526084015b60405180910390fd5b6001600160a01b03821661025a5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b60648201526084016101f0565b6001600160a01b0392831660009081526001602090815260408083209490951682529290925291902055565b6001600160a01b03838116600090815260016020908152604080832093861683529290522054600019811461031257818110156103055760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e636500000060448201526064016101f0565b6103128484848403610192565b50505050565b6001600160a01b03831661037c5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b60648201526084016101f0565b6001600160a01b0382166103de5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b60648201526084016101f0565b6001600160a01b038316600090815260208190526040902054818110156104565760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b60648201526084016101f0565b6001600160a01b039384166000908152602081905260408082209284900390925592909316825291902080549091019055565b6001600160a01b0382166104df5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016101f0565b6001600160a01b03909116600090815260208190526040902080549091019055565b80356001600160a01b038116811461051857600080fd5b919050565b6000806040838503121561053057600080fd5b61053983610501565b946020939093013593505050565b60008060006060848603121561055c57600080fd5b61056584610501565b925061057360208501610501565b9150604084013590509250925092565b60006020828403121561059557600080fd5b61059e82610501565b9392505050565b600080604083850312156105b857600080fd5b823591506105c860208401610501565b90509250929050565b600080604083850312156105e457600080fd5b6105ed83610501565b91506105c86020840161050156fea2646970667358221220e1fee5cd1c5bbf066a9ce9228e1baf7e7fcb77b5050506c7d614aaf8608b42e364736f6c63430008110033\";\n\n        // this is equivalent to:\n        // MyERC20 token = new MyERC20{ salt: bytes32(uint256(1)) }();\n        // address: 0x5bf11839f61ef5cceeaf1f4153e44df5d02825f7\n        MyERC20 token = MyERC20(address(uint160(uint256(keccak256(abi.encodePacked(\"mytoken\"))))));\n        vm.etch(address(token), code);\n\n        token.mint(100, alice);\n\n        assertEq(token.balanceOf(alice), 100);\n        assertEq(token.balanceOf(bob), 0);\n        assertEq(token.balanceOf(charlie), 0);\n\n        vm.deal(alice, 10 ether);\n\n        /*\n        Signed transaction:\n        {\n            from: '0x7ED31830602f9F7419307235c0610Fb262AA0375',\n            to: '0x5bF11839F61EF5ccEEaf1F4153e44df5D02825f7',\n            value: 0,\n            data: '0x095ea7b300000000000000000000000070cf146ab98ffd5de24e75dd7423f16181da8e130000000000000000000000000000000000000000000000000000000000000032',\n            nonce: 0,\n            gasPrice: 100,\n            gasLimit: 200000,\n            chainId: 1\n        }\n        */\n        // this would be equivalent to using those cheatcodes:\n        // vm.prank(alice);\n        // token.approve(bob, 50);\n        vm.broadcastRawTransaction(\n            hex\"f8a5806483030d40945bf11839f61ef5cceeaf1f4153e44df5d02825f780b844095ea7b300000000000000000000000070cf146ab98ffd5de24e75dd7423f16181da8e13000000000000000000000000000000000000000000000000000000000000003225a0e25b9ef561d9a413b21755cc0e4bb6e80f2a88a8a52305690956130d612074dfa07bfd418bc2ad3c3f435fa531cdcdc64887f64ed3fb0d347d6b0086e320ad4eb1\"\n        );\n\n        assertEq(token.allowance(alice, bob), 50);\n\n        vm.deal(bob, 1 ether);\n        vm.prank(bob);\n        token.transferFrom(alice, charlie, 20);\n\n        assertEq(token.balanceOf(bob), 0);\n        assertEq(token.balanceOf(charlie), 20);\n\n        vm.deal(charlie, 1 ether);\n\n        /*\n        Signed transaction:\n        {\n            from: '0xae0900Cf97f8C233c64F7089cEC7d5457215BB8d',\n            to: '0x5bF11839F61EF5ccEEaf1F4153e44df5D02825f7',\n            value: 0,\n            data: '0xa9059cbb00000000000000000000000070cf146ab98ffd5de24e75dd7423f16181da8e130000000000000000000000000000000000000000000000000000000000000005',\n            nonce: 0,\n            gasPrice: 100,\n            gasLimit: 200000,\n            chainId: 1\n        }\n        */\n        // this would be equivalent to using those cheatcodes:\n        // vm.prank(charlie);\n        // token.transfer(bob, 5);\n        vm.broadcastRawTransaction(\n            hex\"f8a5806483030d40945bf11839f61ef5cceeaf1f4153e44df5d02825f780b844a9059cbb00000000000000000000000070cf146ab98ffd5de24e75dd7423f16181da8e13000000000000000000000000000000000000000000000000000000000000000525a0941562f519e33dfe5b44ebc2b799686cebeaeacd617dd89e393620b380797da2a0447dfd38d9444ccd571b000482c81674733761753430c81ee6669e9542c266a1\"\n        );\n\n        assertEq(token.balanceOf(alice), 80);\n        assertEq(token.balanceOf(bob), 5);\n        assertEq(token.balanceOf(charlie), 15);\n    }\n}\n\ncontract MyERC20 {\n    mapping(address => uint256) private _balances;\n    mapping(address => mapping(address => uint256)) private _allowances;\n\n    function mint(uint256 amount, address to) public {\n        _mint(to, amount);\n    }\n\n    function balanceOf(address account) public view returns (uint256) {\n        return _balances[account];\n    }\n\n    function transfer(address to, uint256 amount) public returns (bool) {\n        address owner = msg.sender;\n        _transfer(owner, to, amount);\n        return true;\n    }\n\n    function allowance(address owner, address spender) public view returns (uint256) {\n        return _allowances[owner][spender];\n    }\n\n    function approve(address spender, uint256 amount) public returns (bool) {\n        address owner = msg.sender;\n        _approve(owner, spender, amount);\n        return true;\n    }\n\n    function transferFrom(address from, address to, uint256 amount) public returns (bool) {\n        address spender = msg.sender;\n        _spendAllowance(from, spender, amount);\n        _transfer(from, to, amount);\n        return true;\n    }\n\n    function _transfer(address from, address to, uint256 amount) internal {\n        require(from != address(0), \"ERC20: transfer from the zero address\");\n        require(to != address(0), \"ERC20: transfer to the zero address\");\n\n        uint256 fromBalance = _balances[from];\n        require(fromBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n        unchecked {\n            _balances[from] = fromBalance - amount;\n            _balances[to] += amount;\n        }\n    }\n\n    function _mint(address account, uint256 amount) internal {\n        require(account != address(0), \"ERC20: mint to the zero address\");\n        unchecked {\n            _balances[account] += amount;\n        }\n    }\n\n    function _approve(address owner, address spender, uint256 amount) internal {\n        require(owner != address(0), \"ERC20: approve from the zero address\");\n        require(spender != address(0), \"ERC20: approve to the zero address\");\n        _allowances[owner][spender] = amount;\n    }\n\n    function _spendAllowance(address owner, address spender, uint256 amount) internal {\n        uint256 currentAllowance = allowance(owner, spender);\n        if (currentAllowance != type(uint256).max) {\n            require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n            unchecked {\n                _approve(owner, spender, currentAllowance - amount);\n            }\n        }\n    }\n}\n\ncontract ScriptBroadcastRawTransactionBroadcast is Test {\n    function runSignedTxBroadcast() public {\n        uint256 pk_to = 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80;\n        vm.startBroadcast(pk_to);\n\n        address from = 0x73E1A965542AFA4B412467761b1CED8A764E1D3B;\n        address to = 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266;\n        address random = address(uint160(uint256(keccak256(abi.encodePacked(\"random\")))));\n\n        assert(address(from).balance == 1 ether);\n        assert(address(to).balance == 1 ether);\n        assert(address(random).balance == 0);\n\n        /*\n            TransactionRequest {\n                from: Some(\n                    0x73e1a965542afa4b412467761b1ced8a764e1d3b,\n                ),\n                to: Some(\n                    Address(\n                        0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266,\n                    ),\n                ),\n                gas: Some(\n                    200000,\n                ),\n                gas_price: Some(\n                    10000000000,\n                ),\n                value: Some(\n                    1234,\n                ),\n                data: None,\n                nonce: Some(\n                    0,\n                ),\n                chain_id: Some(\n                    31337,\n                ),\n            }\n        */\n        vm.broadcastRawTransaction(\n            hex\"f869808502540be40083030d4094f39fd6e51aad88f6f4ce6ab8827279cfffb922668204d28082f4f6a061ce3c0f4280cb79c1eb0060a9a491cca1ba48ed32f141e3421ccb60c9dbe444a07fcd35cbec5f81427ac20f60484f4da9d00f59652f5053cd13ee90b992e94ab3\"\n        );\n\n        uint256 value = 34;\n        (bool success,) = random.call{value: value}(\"\");\n        require(success);\n\n        vm.stopBroadcast();\n\n        uint256 gasPrice = 10 * 1e9;\n        assert(address(from).balance == 1 ether - (gasPrice * 21_000) - 1234);\n        assert(address(to).balance == 1 ether + 1234 - value);\n        assert(address(random).balance == value);\n    }\n\n    function runDeployCreate2Deployer() public {\n        vm.startBroadcast();\n        vm.broadcastRawTransaction(\n            hex\"f8a58085174876e800830186a08080b853604580600e600039806000f350fe7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf31ba02222222222222222222222222222222222222222222222222222222222222222a02222222222222222222222222222222222222222222222222222222222222222\"\n        );\n        vm.stopBroadcast();\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/ChainId.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract ChainIdTest is Test {\n    function testChainId() public {\n        uint256 newChainId = 99;\n        vm.chainId(newChainId);\n        assertEq(newChainId, block.chainid);\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/CloneAccount.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract Source {\n    uint256 public a;\n    address public b;\n    uint256[3] public c;\n    bool public d;\n\n    constructor() {\n        a = 100;\n        b = address(111);\n        c[0] = 222;\n        c[1] = 333;\n        c[2] = 444;\n        d = true;\n    }\n}\n\ncontract CloneAccountTest is Test {\n    address clone = address(777);\n\n    function setUp() public {\n        Source src = new Source();\n        vm.deal(address(src), 0.123 ether);\n        vm.cloneAccount(address(src), clone);\n    }\n\n    function test_clone_account() public {\n        // Check clone balance.\n        assertEq(clone.balance, 0.123 ether);\n        // Check clone storage.\n        assertEq(Source(clone).a(), 100);\n        assertEq(Source(clone).b(), address(111));\n        assertEq(Source(clone).c(0), 222);\n        assertEq(Source(clone).c(1), 333);\n        assertEq(Source(clone).c(2), 444);\n        assertEq(Source(clone).d(), true);\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/Cool.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract CoolTest is Test {\n    uint256 public slot0 = 1;\n\n    function testCool_SLOAD_normal() public {\n        uint256 startGas;\n        uint256 endGas;\n        uint256 val;\n        uint256 beforeCoolGas;\n        uint256 noCoolGas;\n\n        startGas = gasleft();\n        val = slot0;\n        endGas = gasleft();\n        beforeCoolGas = startGas - endGas;\n\n        startGas = gasleft();\n        val = slot0;\n        endGas = gasleft();\n        noCoolGas = startGas - endGas;\n\n        assertGt(beforeCoolGas, noCoolGas);\n    }\n\n    function testCool_SLOAD() public {\n        uint256 startGas;\n        uint256 endGas;\n        uint256 val;\n        uint256 beforeCoolGas;\n        uint256 afterCoolGas;\n        uint256 noCoolGas;\n\n        startGas = gasleft();\n        val = slot0;\n        endGas = gasleft();\n        beforeCoolGas = startGas - endGas;\n\n        vm.cool(address(this));\n\n        startGas = gasleft();\n        val = slot0;\n        endGas = gasleft();\n        afterCoolGas = startGas - endGas;\n\n        assertEq(beforeCoolGas, afterCoolGas);\n\n        startGas = gasleft();\n        val = slot0;\n        endGas = gasleft();\n        noCoolGas = startGas - endGas;\n\n        assertGt(beforeCoolGas, noCoolGas);\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/CopyStorage.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract Counter {\n    uint256 public a;\n    address public b;\n    int256[] public c;\n\n    function setA(uint256 _a) public {\n        a = _a;\n    }\n\n    function setB(address _b) public {\n        b = _b;\n    }\n}\n\n/// forge-config: default.fuzz.seed = \"100\"\ncontract CounterWithSeedTest is Test {\n    Counter public counter;\n    Counter public counter1;\n\n    function test_copy_storage() public {\n        counter = new Counter();\n        counter.setA(1000);\n        counter.setB(address(27));\n        counter1 = new Counter();\n        counter1.setA(11);\n        counter1.setB(address(50));\n\n        assertEq(counter.a(), 1000);\n        assertEq(counter.b(), address(27));\n        assertEq(counter1.a(), 11);\n        assertEq(counter1.b(), address(50));\n        vm.copyStorage(address(counter), address(counter1));\n        assertEq(counter.a(), 1000);\n        assertEq(counter.b(), address(27));\n        assertEq(counter1.a(), 1000);\n        assertEq(counter1.b(), address(27));\n    }\n\n    function test_copy_storage_from_arbitrary() public {\n        counter = new Counter();\n        counter1 = new Counter();\n        vm.setArbitraryStorage(address(counter));\n        vm.copyStorage(address(counter), address(counter1));\n\n        // Make sure untouched storage has same values.\n        assertEq(counter.a(), counter1.a());\n        assertEq(counter.b(), counter1.b());\n        assertEq(counter.c(33), counter1.c(33));\n\n        // Change storage in source storage contract and make sure copy is not changed.\n        counter.setA(1000);\n        counter1.setB(address(50));\n        assertEq(counter.a(), 1000);\n        assertEq(counter1.a(), 67350900536747027229585709178274816969402970928486983076982664581925078789474);\n        assertEq(counter.b(), 0x5A61ACa23C478d83A72425c386Eb5dB083FBd0e4);\n        assertEq(counter1.b(), address(50));\n    }\n}\n\ncontract CopyStorageContract {\n    uint256 public x;\n}\n\ncontract CopyStorageTest is Test {\n    CopyStorageContract csc_1;\n    CopyStorageContract csc_2;\n    CopyStorageContract csc_3;\n\n    function _storeUInt256(address contractAddress, uint256 slot, uint256 value) internal {\n        vm.store(contractAddress, bytes32(slot), bytes32(value));\n    }\n\n    function setUp() public {\n        csc_1 = new CopyStorageContract();\n        csc_2 = new CopyStorageContract();\n        csc_3 = new CopyStorageContract();\n    }\n\n    function test_copy_storage() public {\n        // Make the storage of first contract symbolic\n        vm.setArbitraryStorage(address(csc_1));\n        // and explicitly put a constrained symbolic value into the slot for `x`\n        uint256 x_1 = vm.randomUint();\n        _storeUInt256(address(csc_1), 0, x_1);\n        // `x` of second contract is uninitialized\n        assert(csc_2.x() == 0);\n        // Copy storage from first to second contract\n        vm.copyStorage(address(csc_1), address(csc_2));\n        // `x` of second contract is now the `x` of the first\n        assert(csc_2.x() == x_1);\n    }\n\n    function test_copy_storage_same_values_on_load() public {\n        // Make the storage of first contract symbolic\n        vm.setArbitraryStorage(address(csc_1));\n        vm.copyStorage(address(csc_1), address(csc_2));\n        uint256 slot1 = vm.randomUint(0, 100);\n        uint256 slot2 = vm.randomUint(0, 100);\n        bytes32 value1 = vm.load(address(csc_1), bytes32(slot1));\n        bytes32 value2 = vm.load(address(csc_1), bytes32(slot2));\n\n        bytes32 value3 = vm.load(address(csc_2), bytes32(slot1));\n        bytes32 value4 = vm.load(address(csc_2), bytes32(slot2));\n\n        // Check storage values are the same for both source and target contracts.\n        assertEq(value1, value3);\n        assertEq(value2, value4);\n    }\n\n    function test_copy_storage_consistent_values() public {\n        // Make the storage of first contract symbolic.\n        vm.setArbitraryStorage(address(csc_1));\n        // Copy arbitrary storage to 2 contracts.\n        vm.copyStorage(address(csc_1), address(csc_2));\n        vm.copyStorage(address(csc_1), address(csc_3));\n        uint256 slot1 = vm.randomUint(0, 100);\n        uint256 slot2 = vm.randomUint(0, 100);\n\n        // Load slot 1 from 1st copied contract and slot2 from symbolic contract.\n        bytes32 value3 = vm.load(address(csc_2), bytes32(slot1));\n        bytes32 value2 = vm.load(address(csc_1), bytes32(slot2));\n\n        bytes32 value1 = vm.load(address(csc_1), bytes32(slot1));\n        bytes32 value4 = vm.load(address(csc_2), bytes32(slot2));\n\n        // Make sure same values for both copied and symbolic contract.\n        assertEq(value3, value1);\n        assertEq(value2, value4);\n\n        uint256 x_1 = vm.randomUint();\n        // Change slot1 of 1st copied contract.\n        _storeUInt256(address(csc_2), slot1, x_1);\n        value3 = vm.load(address(csc_2), bytes32(slot1));\n        bytes32 value5 = vm.load(address(csc_3), bytes32(slot1));\n        // Make sure value for 1st contract copied is different than symbolic contract value.\n        assert(value3 != value1);\n        // Make sure same values for 2nd contract copied and symbolic contract.\n        assertEq(value5, value1);\n\n        uint256 x_2 = vm.randomUint();\n        // Change slot2 of symbolic contract.\n        _storeUInt256(address(csc_1), slot2, x_2);\n        value2 = vm.load(address(csc_1), bytes32(slot2));\n        bytes32 value6 = vm.load(address(csc_3), bytes32(slot2));\n        // Make sure value for symbolic contract value is different than 1st contract copied.\n        assert(value2 != value4);\n        // Make sure value for symbolic contract value is different than 2nd contract copied.\n        assert(value2 != value6);\n        assertEq(value4, value6);\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/CurrentFilePath.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract CurrentFilePathTest is Test {\n    function testCurrentFilePath() public {\n        string memory filePath = vm.currentFilePath();\n        // The path should be relative to the project root and point to this test file.\n        assertEq(normalizePath(filePath), \"default/cheats/CurrentFilePath.t.sol\");\n    }\n\n    function testCurrentFilePathIsNotEmpty() public {\n        string memory filePath = vm.currentFilePath();\n        assertTrue(bytes(filePath).length > 0, \"currentFilePath() should not return an empty string\");\n    }\n\n    function normalizePath(string memory path) internal pure returns (string memory) {\n        return vm.replace(path, \"\\\\\", \"/\");\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/Deal.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract DealTest is Test {\n    function testDeal(uint256 amount) public {\n        address target = address(10);\n        assertEq(target.balance, 0, \"initial balance incorrect\");\n\n        // Give half the amount\n        vm.deal(target, amount / 2);\n        assertEq(target.balance, amount / 2, \"half balance is incorrect\");\n\n        // Give the entire amount to check that deal is not additive\n        vm.deal(target, amount);\n        assertEq(target.balance, amount, \"deal did not overwrite balance\");\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/DeployCode.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract TestContract {}\n\ncontract TestContractWithArgs {\n    uint256 public a;\n    uint256 public b;\n\n    constructor(uint256 _a, uint256 _b) {\n        a = _a;\n        b = _b;\n    }\n}\n\ncontract TestPayableContract {\n    uint256 public a;\n\n    constructor() payable {\n        a = msg.value;\n    }\n}\n\ncontract TestPayableContractWithArgs {\n    uint256 public a;\n    uint256 public b;\n    uint256 public c;\n\n    constructor(uint256 _a, uint256 _b) payable {\n        a = _a;\n        b = _b;\n        c = msg.value;\n    }\n}\n\ncontract DeployCodeTest is Test {\n    address public constant overrideAddress = 0x0000000000000000000000000000000000000064;\n\n    event Payload(address sender, address target, bytes data);\n\n    function testDeployCode() public {\n        address addrDefault = address(new TestContract());\n        address addrDeployCode = vm.deployCode(\"cheats/DeployCode.t.sol:TestContract\");\n\n        assertEq(addrDefault.code, addrDeployCode.code);\n    }\n\n    function testDeployCodeWithArgs() public {\n        address withNew = address(new TestContractWithArgs(1, 2));\n        TestContractWithArgs withDeployCode =\n            TestContractWithArgs(vm.deployCode(\"cheats/DeployCode.t.sol:TestContractWithArgs\", abi.encode(3, 4)));\n\n        assertEq(withNew.code, address(withDeployCode).code);\n        assertEq(withDeployCode.a(), 3);\n        assertEq(withDeployCode.b(), 4);\n    }\n\n    function testDeployCodeWithPayableConstructorAndArgs() public {\n        address withNew = address(new TestPayableContractWithArgs(1, 2));\n        TestPayableContractWithArgs withDeployCode = TestPayableContractWithArgs(\n            vm.deployCode(\"cheats/DeployCode.t.sol:TestPayableContractWithArgs\", abi.encode(3, 4), 101)\n        );\n\n        assertEq(withNew.code, address(withDeployCode).code);\n        assertEq(withDeployCode.a(), 3);\n        assertEq(withDeployCode.b(), 4);\n        assertEq(withDeployCode.c(), 101);\n    }\n\n    function testDeployCodeWithPayableConstructor() public {\n        address withNew = address(new TestPayableContract());\n        TestPayableContract withDeployCode =\n            TestPayableContract(vm.deployCode(\"cheats/DeployCode.t.sol:TestPayableContract\", 111));\n\n        assertEq(withNew.code, address(withDeployCode).code);\n        assertEq(withDeployCode.a(), 111);\n    }\n\n    function testDeployCodeWithSalt() public {\n        address addrDefault = address(new TestContract());\n        address addrDeployCode = vm.deployCode(\"cheats/DeployCode.t.sol:TestContract\", bytes32(\"salt\"));\n\n        assertEq(addrDefault.code, addrDeployCode.code);\n    }\n\n    function testDeployCodeWithArgsAndSalt() public {\n        address withNew = address(new TestContractWithArgs(1, 2));\n        TestContractWithArgs withDeployCode = TestContractWithArgs(\n            vm.deployCode(\"cheats/DeployCode.t.sol:TestContractWithArgs\", abi.encode(3, 4), bytes32(\"salt\"))\n        );\n\n        assertEq(withNew.code, address(withDeployCode).code);\n        assertEq(withDeployCode.a(), 3);\n        assertEq(withDeployCode.b(), 4);\n    }\n\n    function testDeployCodeWithPayableConstructorAndSalt() public {\n        address withNew = address(new TestPayableContract());\n        TestPayableContract withDeployCode =\n            TestPayableContract(vm.deployCode(\"cheats/DeployCode.t.sol:TestPayableContract\", 111, bytes32(\"salt\")));\n\n        assertEq(withNew.code, address(withDeployCode).code);\n        assertEq(withDeployCode.a(), 111);\n    }\n\n    function testDeployCodeWithPayableConstructorAndArgsAndSalt() public {\n        address withNew = address(new TestPayableContractWithArgs(1, 2));\n        TestPayableContractWithArgs withDeployCode = TestPayableContractWithArgs(\n            vm.deployCode(\"cheats/DeployCode.t.sol:TestPayableContractWithArgs\", abi.encode(3, 4), 101, bytes32(\"salt\"))\n        );\n\n        assertEq(withNew.code, address(withDeployCode).code);\n        assertEq(withDeployCode.a(), 3);\n        assertEq(withDeployCode.b(), 4);\n        assertEq(withDeployCode.c(), 101);\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/Derive.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract DeriveTest is Test {\n    function testDerive() public {\n        string memory mnemonic = \"test test test test test test test test test test test junk\";\n\n        uint256 privateKey = vm.deriveKey(mnemonic, 0);\n        assertEq(privateKey, 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80);\n\n        uint256 privateKeyDerivationPathChanged = vm.deriveKey(mnemonic, \"m/44'/60'/0'/1/\", 0);\n        assertEq(privateKeyDerivationPathChanged, 0x6abb89895f93b02c1b9470db0fa675297f6cca832a5fc66d5dfd7661a42b37be);\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/Ed25519.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract Ed25519Test is Test {\n    function testCreateEd25519Key() public {\n        bytes32 salt = bytes32(uint256(1));\n        (bytes32 publicKey, bytes32 privateKey) = vm.createEd25519Key(salt);\n        assertTrue(publicKey != bytes32(0), \"public key should not be zero\");\n        assertEq(privateKey, salt, \"private key should equal salt\");\n    }\n\n    function testCreateEd25519KeyDeterministic() public {\n        bytes32 salt = bytes32(uint256(42));\n        (bytes32 pub1, bytes32 priv1) = vm.createEd25519Key(salt);\n        (bytes32 pub2, bytes32 priv2) = vm.createEd25519Key(salt);\n        assertEq(pub1, pub2, \"same salt should produce same public key\");\n        assertEq(priv1, priv2, \"same salt should produce same private key\");\n    }\n\n    function testCreateEd25519KeyDifferentSalts() public {\n        bytes32 salt1 = bytes32(uint256(1));\n        bytes32 salt2 = bytes32(uint256(2));\n        (bytes32 pub1,) = vm.createEd25519Key(salt1);\n        (bytes32 pub2,) = vm.createEd25519Key(salt2);\n        assertTrue(pub1 != pub2, \"different salts should produce different public keys\");\n    }\n\n    function testPublicKeyEd25519() public {\n        bytes32 salt = bytes32(uint256(123));\n        (bytes32 expectedPub, bytes32 privateKey) = vm.createEd25519Key(salt);\n        bytes32 derivedPub = vm.publicKeyEd25519(privateKey);\n        assertEq(derivedPub, expectedPub, \"derived public key should match created one\");\n    }\n\n    function testSignAndVerifyEd25519() public {\n        bytes32 salt = bytes32(uint256(0xdeadbeef));\n        (bytes32 publicKey, bytes32 privateKey) = vm.createEd25519Key(salt);\n\n        bytes memory namespace = \"test.namespace\";\n        bytes memory message = \"hello world\";\n\n        bytes memory signature = vm.signEd25519(namespace, message, privateKey);\n        assertEq(signature.length, 64, \"signature should be 64 bytes\");\n\n        bool valid = vm.verifyEd25519(signature, namespace, message, publicKey);\n        assertTrue(valid, \"signature should be valid\");\n    }\n\n    function testVerifyEd25519WrongMessage() public {\n        bytes32 salt = bytes32(uint256(0xdeadbeef));\n        (bytes32 publicKey, bytes32 privateKey) = vm.createEd25519Key(salt);\n\n        bytes memory namespace = \"ns\";\n        bytes memory signature = vm.signEd25519(namespace, \"correct message\", privateKey);\n\n        bool valid = vm.verifyEd25519(signature, namespace, \"wrong message\", publicKey);\n        vm.assertFalse(valid, \"signature should not verify with wrong message\");\n    }\n\n    function testVerifyEd25519NamespaceSeparation() public {\n        bytes32 salt = bytes32(uint256(0xdeadbeef));\n        (bytes32 publicKey, bytes32 privateKey) = vm.createEd25519Key(salt);\n\n        bytes memory message = \"message\";\n        bytes memory signature = vm.signEd25519(\"namespace.a\", message, privateKey);\n\n        bool valid = vm.verifyEd25519(signature, \"namespace.b\", message, publicKey);\n        vm.assertFalse(valid, \"signature should not verify with different namespace\");\n\n        valid = vm.verifyEd25519(signature, \"namespace.a\", message, publicKey);\n        assertTrue(valid, \"signature should verify with correct namespace\");\n    }\n\n    function testVerifyEd25519InvalidSignature() public {\n        bytes32 salt = bytes32(uint256(0xdeadbeef));\n        (bytes32 publicKey,) = vm.createEd25519Key(salt);\n\n        bytes memory invalidSig = new bytes(64);\n        bool valid = vm.verifyEd25519(invalidSig, \"ns\", \"msg\", publicKey);\n        vm.assertFalse(valid, \"zero signature should not verify\");\n    }\n\n    function testVerifyEd25519WrongSignatureLength() public {\n        bytes32 salt = bytes32(uint256(0xdeadbeef));\n        (bytes32 publicKey,) = vm.createEd25519Key(salt);\n\n        bytes memory shortSig = new bytes(32);\n        bool valid = vm.verifyEd25519(shortSig, \"ns\", \"msg\", publicKey);\n        vm.assertFalse(valid, \"short signature should not verify\");\n    }\n\n    function testSignEd25519Deterministic() public {\n        bytes32 salt = bytes32(uint256(0xdeadbeef));\n        (, bytes32 privateKey) = vm.createEd25519Key(salt);\n\n        bytes memory namespace = \"ns\";\n        bytes memory message = \"msg\";\n\n        bytes memory sig1 = vm.signEd25519(namespace, message, privateKey);\n        bytes memory sig2 = vm.signEd25519(namespace, message, privateKey);\n        assertEq(sig1, sig2, \"same inputs should produce same signature\");\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/EnsNamehash.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract EnsNamehashTest is Test {\n    function testEnsNamehash() public {\n        assertEq(vm.ensNamehash(\"\"), 0x0000000000000000000000000000000000000000000000000000000000000000);\n        assertEq(vm.ensNamehash(\"eth\"), 0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae);\n        assertEq(vm.ensNamehash(\"foo.eth\"), 0xde9b09fd7c5f901e23a3f19fecc54828e9c848539801e86591bd9801b019f84f);\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/Env.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract EnvTest is Test {\n    function testSetEnv() public {\n        string memory key = \"_foundryCheatcodeSetEnvTestKey\";\n        string memory val = \"_foundryCheatcodeSetEnvTestVal\";\n        vm.setEnv(key, val);\n    }\n\n    function testEnvExists() public {\n        string memory key = \"_foundryCheatcodeEnvExistsTestKey\";\n        string memory val = \"_foundryCheatcodeEnvExistsTestVal\";\n        vm.setEnv(key, val);\n        require(vm.envExists(key), \"envExists failed\");\n        require(!vm.envExists(\"nonexistent\"), \"envExists failed\");\n    }\n\n    uint256 constant numEnvBoolTests = 2;\n\n    function testEnvBool() public {\n        string memory key = \"_foundryCheatcodeEnvBoolTestKey\";\n        string[numEnvBoolTests] memory values = [\"true\", \"false\"];\n        bool[numEnvBoolTests] memory expected = [true, false];\n        for (uint256 i = 0; i < numEnvBoolTests; ++i) {\n            vm.setEnv(key, values[i]);\n            bool output = vm.envBool(key);\n            require(output == expected[i], \"envBool failed\");\n        }\n    }\n\n    uint256 constant numEnvUintTests = 6;\n\n    function testEnvUint() public {\n        string memory key = \"_foundryCheatcodeEnvUintTestKey\";\n        string[numEnvUintTests] memory values = [\n            \"0\",\n            \"115792089237316195423570985008687907853269984665640564039457584007913129639935\",\n            \"0x01\",\n            \"0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80\",\n            \"0x0000000000000000000000000000000000000000000000000000000000000000\",\n            \"0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\"\n        ];\n        uint256[numEnvUintTests] memory expected = [\n            type(uint256).min,\n            type(uint256).max,\n            1,\n            77814517325470205911140941194401928579557062014761831930645393041380819009408,\n            type(uint256).min,\n            type(uint256).max\n        ];\n        for (uint256 i = 0; i < numEnvUintTests; ++i) {\n            vm.setEnv(key, values[i]);\n            uint256 output = vm.envUint(key);\n            require(output == expected[i], \"envUint failed\");\n        }\n    }\n\n    uint256 constant numEnvIntTests = 4;\n\n    function testEnvInt() public {\n        string memory key = \"_foundryCheatcodeEnvIntTestKey\";\n        string[numEnvIntTests] memory values = [\n            \"-57896044618658097711785492504343953926634992332820282019728792003956564819968\",\n            \"57896044618658097711785492504343953926634992332820282019728792003956564819967\",\n            \"-0x8000000000000000000000000000000000000000000000000000000000000000\",\n            \"0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\"\n        ];\n        int256[numEnvIntTests] memory expected =\n            [type(int256).min, type(int256).max, type(int256).min, type(int256).max];\n        for (uint256 i = 0; i < numEnvIntTests; ++i) {\n            vm.setEnv(key, values[i]);\n            int256 output = vm.envInt(key);\n            require(output == expected[i], \"envInt failed\");\n        }\n    }\n\n    uint256 constant numEnvAddressTests = 2;\n\n    function testEnvAddress() public {\n        string memory key = \"_foundryCheatcodeEnvAddressTestKey\";\n        string[numEnvAddressTests] memory values =\n            [\"0x7109709ECfa91a80626fF3989D68f67F5b1DD12D\", \"0x0000000000000000000000000000000000000000\"];\n        address[numEnvAddressTests] memory expected =\n            [0x7109709ECfa91a80626fF3989D68f67F5b1DD12D, 0x0000000000000000000000000000000000000000];\n        for (uint256 i = 0; i < numEnvAddressTests; ++i) {\n            vm.setEnv(key, values[i]);\n            address output = vm.envAddress(key);\n            require(output == expected[i], \"envAddress failed\");\n        }\n    }\n\n    uint256 constant numEnvBytes32Tests = 2;\n\n    function testEnvBytes32() public {\n        string memory key = \"_foundryCheatcodeEnvBytes32TestKey\";\n        string[numEnvBytes32Tests] memory values = [\n            \"0x463df98a03418e6196421718c1b96779a6d4f0bcff1702a9e8f2323bb49f6811\",\n            \"0x0000000000000000000000000000000000000000000000000000000000000000\"\n        ];\n        bytes32[numEnvBytes32Tests] memory expected = [\n            bytes32(0x463df98a03418e6196421718c1b96779a6d4f0bcff1702a9e8f2323bb49f6811),\n            bytes32(0x0000000000000000000000000000000000000000000000000000000000000000)\n        ];\n        for (uint256 i = 0; i < numEnvBytes32Tests; ++i) {\n            vm.setEnv(key, values[i]);\n            bytes32 output = vm.envBytes32(key);\n            require(output == expected[i], \"envBytes32 failed\");\n        }\n    }\n\n    uint256 constant numEnvStringTests = 2;\n\n    function testEnvString() public {\n        string memory key = \"_foundryCheatcodeEnvStringTestKey\";\n        string[numEnvStringTests] memory values = [\"hello, world!\", \"0x7109709ECfa91a80626fF3989D68f67F5b1DD12D\"];\n        string[numEnvStringTests] memory expected = [\"hello, world!\", \"0x7109709ECfa91a80626fF3989D68f67F5b1DD12D\"];\n        for (uint256 i = 0; i < numEnvStringTests; ++i) {\n            vm.setEnv(key, values[i]);\n            string memory output = vm.envString(key);\n            assertEq(output, expected[i], \"envString failed\");\n        }\n    }\n\n    uint256 constant numEnvBytesTests = 2;\n\n    function testEnvBytes() public {\n        string memory key = \"_foundryCheatcodeEnvBytesTestKey\";\n        string[numEnvBytesTests] memory values = [\"0x7109709ECfa91a80626fF3989D68f67F5b1DD12D\", \"0x00\"];\n        bytes[] memory expected = new bytes[](numEnvBytesTests);\n        expected[0] = hex\"7109709ECfa91a80626fF3989D68f67F5b1DD12D\";\n        expected[1] = hex\"00\";\n        for (uint256 i = 0; i < numEnvBytesTests; ++i) {\n            vm.setEnv(key, values[i]);\n            bytes memory output = vm.envBytes(key);\n            require(\n                keccak256(abi.encodePacked((output))) == keccak256(abi.encodePacked((expected[i]))), \"envBytes failed\"\n            );\n        }\n    }\n\n    function testEnvBoolArr() public {\n        string memory key = \"_foundryCheatcodeEnvBoolArrTestKey\";\n        string memory value = \"true, false\";\n        bool[numEnvBoolTests] memory expected = [true, false];\n\n        vm.setEnv(key, value);\n        string memory delimiter = \",\";\n        bool[] memory output = vm.envBool(key, delimiter);\n        require(keccak256(abi.encodePacked((output))) == keccak256(abi.encodePacked((expected))), \"envBoolArr failed\");\n    }\n\n    function testEnvUintArr() public {\n        string memory key = \"_foundryCheatcodeEnvUintArrTestKey\";\n        string memory value = \"0,\" \"115792089237316195423570985008687907853269984665640564039457584007913129639935,\"\n            \"0x0000000000000000000000000000000000000000000000000000000000000000,\"\n            \"0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\";\n        uint256[4] memory expected = [type(uint256).min, type(uint256).max, type(uint256).min, type(uint256).max];\n\n        vm.setEnv(key, value);\n        string memory delimiter = \",\";\n        uint256[] memory output = vm.envUint(key, delimiter);\n        require(keccak256(abi.encodePacked((output))) == keccak256(abi.encodePacked((expected))), \"envUintArr failed\");\n    }\n\n    function testEnvIntArr() public {\n        string memory key = \"_foundryCheatcodeEnvIntArrTestKey\";\n        string memory value = \"-57896044618658097711785492504343953926634992332820282019728792003956564819968,\"\n            \"57896044618658097711785492504343953926634992332820282019728792003956564819967,\"\n            \"-0x8000000000000000000000000000000000000000000000000000000000000000,\"\n            \"0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\";\n        int256[4] memory expected = [type(int256).min, type(int256).max, type(int256).min, type(int256).max];\n\n        vm.setEnv(key, value);\n        string memory delimiter = \",\";\n        int256[] memory output = vm.envInt(key, delimiter);\n        require(keccak256(abi.encodePacked((output))) == keccak256(abi.encodePacked((expected))), \"envIntArr failed\");\n    }\n\n    function testEnvAddressArr() public {\n        string memory key = \"_foundryCheatcodeEnvAddressArrTestKey\";\n        string memory value = \"0x7109709ECfa91a80626fF3989D68f67F5b1DD12D,\" \"0x0000000000000000000000000000000000000000\";\n        address[2] memory expected =\n            [0x7109709ECfa91a80626fF3989D68f67F5b1DD12D, 0x0000000000000000000000000000000000000000];\n\n        vm.setEnv(key, value);\n        string memory delimiter = \",\";\n        address[] memory output = vm.envAddress(key, delimiter);\n        require(\n            keccak256(abi.encodePacked((output))) == keccak256(abi.encodePacked((expected))), \"envAddressArr failed\"\n        );\n    }\n\n    function testEnvBytes32Arr() public {\n        string memory key = \"_foundryCheatcodeEnvBytes32ArrTestKey\";\n        string memory value = \"0x463df98a03418e6196421718c1b96779a6d4f0bcff1702a9e8f2323bb49f6811,\"\n            \"0x0000000000000000000000000000000000000000000000000000000000000000\";\n        bytes32[2] memory expected = [\n            bytes32(0x463df98a03418e6196421718c1b96779a6d4f0bcff1702a9e8f2323bb49f6811),\n            bytes32(0x0000000000000000000000000000000000000000000000000000000000000000)\n        ];\n\n        vm.setEnv(key, value);\n        string memory delimiter = \",\";\n        bytes32[] memory output = vm.envBytes32(key, delimiter);\n        require(\n            keccak256(abi.encodePacked((output))) == keccak256(abi.encodePacked((expected))), \"envBytes32Arr failed\"\n        );\n    }\n\n    function testEnvStringArr() public {\n        string memory key = \"_foundryCheatcodeEnvStringArrTestKey\";\n        string memory value = \"hello, world!|\" \"0x7109709ECfa91a80626fF3989D68f67F5b1DD12D\";\n        string[2] memory expected = [\"hello, world!\", \"0x7109709ECfa91a80626fF3989D68f67F5b1DD12D\"];\n\n        vm.setEnv(key, value);\n        string memory delimiter = \"|\";\n        string[] memory output = vm.envString(key, delimiter);\n        for (uint256 i = 0; i < expected.length; ++i) {\n            require(\n                keccak256(abi.encodePacked((output[i]))) == keccak256(abi.encodePacked((expected[i]))),\n                \"envStringArr failed\"\n            );\n        }\n    }\n\n    function testEnvBytesArr() public {\n        string memory key = \"_foundryCheatcodeEnvBytesArrTestKey\";\n        string memory value = \"0x7109709ECfa91a80626fF3989D68f67F5b1DD12D,\" \"0x00\";\n        bytes[] memory expected = new bytes[](numEnvBytesTests);\n        expected[0] = hex\"7109709ECfa91a80626fF3989D68f67F5b1DD12D\";\n        expected[1] = hex\"00\";\n\n        vm.setEnv(key, value);\n        string memory delimiter = \",\";\n        bytes[] memory output = vm.envBytes(key, delimiter);\n        for (uint256 i = 0; i < expected.length; ++i) {\n            require(\n                keccak256(abi.encodePacked((output[i]))) == keccak256(abi.encodePacked((expected[i]))),\n                \"envBytesArr failed\"\n            );\n        }\n    }\n\n    function testEnvBoolEmptyArr() public {\n        string memory key = \"_foundryCheatcodeEnvBoolEmptyArrTestKey\";\n        string memory value = \"\";\n        bool[] memory expected = new bool[](0);\n\n        vm.setEnv(key, value);\n        string memory delimiter = \",\";\n        bool[] memory output = vm.envBool(key, delimiter);\n        require(\n            keccak256(abi.encodePacked((output))) == keccak256(abi.encodePacked((expected))), \"envBoolEmptyArr failed\"\n        );\n    }\n\n    function testEnvUintEmptyArr() public {\n        string memory key = \"_foundryCheatcodeEnvUintEmptyArrTestKey\";\n        string memory value = \"\";\n        uint256[] memory expected = new uint256[](0);\n\n        vm.setEnv(key, value);\n        string memory delimiter = \",\";\n        uint256[] memory output = vm.envUint(key, delimiter);\n        require(\n            keccak256(abi.encodePacked((output))) == keccak256(abi.encodePacked((expected))), \"envUintEmptyArr failed\"\n        );\n    }\n\n    function testEnvIntEmptyArr() public {\n        string memory key = \"_foundryCheatcodeEnvIntEmptyArrTestKey\";\n        string memory value = \"\";\n        int256[] memory expected = new int256[](0);\n\n        vm.setEnv(key, value);\n        string memory delimiter = \",\";\n        int256[] memory output = vm.envInt(key, delimiter);\n        require(\n            keccak256(abi.encodePacked((output))) == keccak256(abi.encodePacked((expected))), \"envIntEmptyArr failed\"\n        );\n    }\n\n    function testEnvAddressEmptyArr() public {\n        string memory key = \"_foundryCheatcodeEnvAddressEmptyArrTestKey\";\n        string memory value = \"\";\n        address[] memory expected = new address[](0);\n\n        vm.setEnv(key, value);\n        string memory delimiter = \",\";\n        address[] memory output = vm.envAddress(key, delimiter);\n        require(\n            keccak256(abi.encodePacked((output))) == keccak256(abi.encodePacked((expected))),\n            \"envAddressEmptyArr failed\"\n        );\n    }\n\n    function testEnvBytes32EmptyArr() public {\n        string memory key = \"_foundryCheatcodeEnvBytes32EmptyArrTestKey\";\n        string memory value = \"\";\n        bytes32[] memory expected = new bytes32[](0);\n\n        vm.setEnv(key, value);\n        string memory delimiter = \",\";\n        bytes32[] memory output = vm.envBytes32(key, delimiter);\n        require(\n            keccak256(abi.encodePacked((output))) == keccak256(abi.encodePacked((expected))),\n            \"envBytes32EmptyArr failed\"\n        );\n    }\n\n    function testEnvStringEmptyArr() public {\n        string memory key = \"_foundryCheatcodeEnvStringEmptyArrTestKey\";\n        string memory value = \"\";\n        string[] memory expected = new string[](0);\n\n        vm.setEnv(key, value);\n        string memory delimiter = \"|\";\n        string[] memory output = vm.envString(key, delimiter);\n        for (uint256 i = 0; i < expected.length; ++i) {\n            require(\n                keccak256(abi.encodePacked((output[i]))) == keccak256(abi.encodePacked((expected[i]))),\n                \"envStringEmptyArr failed\"\n            );\n        }\n    }\n\n    function testEnvBytesEmptyArr() public {\n        string memory key = \"_foundryCheatcodeEnvBytesEmptyArrTestKey\";\n        string memory value = \"\";\n        bytes[] memory expected = new bytes[](0);\n\n        vm.setEnv(key, value);\n        string memory delimiter = \",\";\n        bytes[] memory output = vm.envBytes(key, delimiter);\n        for (uint256 i = 0; i < expected.length; ++i) {\n            require(\n                keccak256(abi.encodePacked((output[i]))) == keccak256(abi.encodePacked((expected[i]))),\n                \"envBytesEmptyArr failed\"\n            );\n        }\n    }\n\n    function testEnvOrBoolKey() public {\n        string memory key = \"_foundryCheatcodeEnvOrBoolTestKey\";\n        string[numEnvBoolTests] memory values = [\"true\", \"false\"];\n        bool[numEnvBoolTests] memory expected = [true, false];\n        for (uint256 i = 0; i < numEnvBoolTests; ++i) {\n            vm.setEnv(key, values[i]);\n            bool output = vm.envOr(key, expected[i]);\n            require(output == expected[i], \"envOrBoolKey failed\");\n        }\n    }\n\n    function testEnvOrBoolDefault() public {\n        string memory key = \"_foundryCheatcodeEnvOrBoolTestDefault\";\n        bool[numEnvBoolTests] memory expected = [true, false];\n        for (uint256 i = 0; i < numEnvBoolTests; ++i) {\n            bool output = vm.envOr(key, expected[i]);\n            require(output == expected[i], \"envOrBoolDefault failed\");\n        }\n    }\n\n    function testEnvOrUintKey() public {\n        string memory key = \"_foundryCheatcodeEnvOrUintTestKey\";\n        string[numEnvUintTests] memory values = [\n            \"0\",\n            \"115792089237316195423570985008687907853269984665640564039457584007913129639935\",\n            \"0x01\",\n            \"0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80\",\n            \"0x0000000000000000000000000000000000000000000000000000000000000000\",\n            \"0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\"\n        ];\n        uint256[numEnvUintTests] memory expected = [\n            type(uint256).min,\n            type(uint256).max,\n            1,\n            77814517325470205911140941194401928579557062014761831930645393041380819009408,\n            type(uint256).min,\n            type(uint256).max\n        ];\n        for (uint256 i = 0; i < numEnvUintTests; ++i) {\n            vm.setEnv(key, values[i]);\n            uint256 output = vm.envOr(key, expected[i]);\n            require(output == expected[i], \"envOrUintKey failed\");\n        }\n    }\n\n    function testEnvOrUintDefault() public {\n        string memory key = \"_foundryCheatcodeEnvOrUintTestDefault\";\n        uint256[numEnvUintTests] memory expected = [\n            type(uint256).min,\n            type(uint256).max,\n            1,\n            77814517325470205911140941194401928579557062014761831930645393041380819009408,\n            type(uint256).min,\n            type(uint256).max\n        ];\n        for (uint256 i = 0; i < numEnvUintTests; ++i) {\n            uint256 output = vm.envOr(key, expected[i]);\n            require(output == expected[i], \"envOrUintDefault failed\");\n        }\n    }\n\n    function testEnvOrIntKey() public {\n        string memory key = \"_foundryCheatcodeEnvOrIntTestKey\";\n        string[numEnvIntTests] memory values = [\n            \"-57896044618658097711785492504343953926634992332820282019728792003956564819968\",\n            \"57896044618658097711785492504343953926634992332820282019728792003956564819967\",\n            \"-0x8000000000000000000000000000000000000000000000000000000000000000\",\n            \"0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\"\n        ];\n        int256[numEnvIntTests] memory expected =\n            [type(int256).min, type(int256).max, type(int256).min, type(int256).max];\n        for (uint256 i = 0; i < numEnvIntTests; ++i) {\n            vm.setEnv(key, values[i]);\n            int256 output = vm.envOr(key, expected[i]);\n            require(output == expected[i], \"envOrIntKey failed\");\n        }\n    }\n\n    function testEnvOrIntDefault() public {\n        string memory key = \"_foundryCheatcodeEnvOrIntTestDefault\";\n        int256[numEnvIntTests] memory expected =\n            [type(int256).min, type(int256).max, type(int256).min, type(int256).max];\n        for (uint256 i = 0; i < numEnvIntTests; ++i) {\n            int256 output = vm.envOr(key, expected[i]);\n            require(output == expected[i], \"envOrIntDefault failed\");\n        }\n    }\n\n    function testEnvOrAddressKey() public {\n        string memory key = \"_foundryCheatcodeEnvOrAddressTestKey\";\n        string[numEnvAddressTests] memory values =\n            [\"0x7109709ECfa91a80626fF3989D68f67F5b1DD12D\", \"0x0000000000000000000000000000000000000000\"];\n        address[numEnvAddressTests] memory expected =\n            [0x7109709ECfa91a80626fF3989D68f67F5b1DD12D, 0x0000000000000000000000000000000000000000];\n        for (uint256 i = 0; i < numEnvAddressTests; ++i) {\n            vm.setEnv(key, values[i]);\n            address output = vm.envOr(key, expected[i]);\n            require(output == expected[i], \"envOrAddressKey failed\");\n        }\n    }\n\n    function testEnvOrAddressDefault() public {\n        string memory key = \"_foundryCheatcodeEnvOrAddressTestDefault\";\n        address[numEnvAddressTests] memory expected =\n            [0x7109709ECfa91a80626fF3989D68f67F5b1DD12D, 0x0000000000000000000000000000000000000000];\n        for (uint256 i = 0; i < numEnvAddressTests; ++i) {\n            address output = vm.envOr(key, expected[i]);\n            require(output == expected[i], \"envOrAddressDefault failed\");\n        }\n    }\n\n    function testEnvOrBytes32Key() public {\n        string memory key = \"_foundryCheatcodeEnvOrBytes32TestKey\";\n        string[numEnvBytes32Tests] memory values = [\n            \"0x463df98a03418e6196421718c1b96779a6d4f0bcff1702a9e8f2323bb49f6811\",\n            \"0x0000000000000000000000000000000000000000000000000000000000000000\"\n        ];\n        bytes32[numEnvBytes32Tests] memory expected = [\n            bytes32(0x463df98a03418e6196421718c1b96779a6d4f0bcff1702a9e8f2323bb49f6811),\n            bytes32(0x0000000000000000000000000000000000000000000000000000000000000000)\n        ];\n        for (uint256 i = 0; i < numEnvBytes32Tests; ++i) {\n            vm.setEnv(key, values[i]);\n            bytes32 output = vm.envOr(key, expected[i]);\n            require(output == expected[i], \"envOrBytes32Key failed\");\n        }\n    }\n\n    function testEnvOrBytes32Default() public {\n        string memory key = \"_foundryCheatcodeEnvOrBytes32TestDefault\";\n        bytes32[numEnvBytes32Tests] memory expected = [\n            bytes32(0x463df98a03418e6196421718c1b96779a6d4f0bcff1702a9e8f2323bb49f6811),\n            bytes32(0x0000000000000000000000000000000000000000000000000000000000000000)\n        ];\n        for (uint256 i = 0; i < numEnvBytes32Tests; ++i) {\n            bytes32 output = vm.envOr(key, expected[i]);\n            require(output == expected[i], \"envOrBytes32Default failed\");\n        }\n    }\n\n    function testEnvOrStringKey() public {\n        string memory key = \"_foundryCheatcodeEnvOrStringTestKey\";\n        string[numEnvStringTests] memory values = [\"hello, world!\", \"0x7109709ECfa91a80626fF3989D68f67F5b1DD12D\"];\n        string[numEnvStringTests] memory expected = [\"hello, world!\", \"0x7109709ECfa91a80626fF3989D68f67F5b1DD12D\"];\n        for (uint256 i = 0; i < numEnvStringTests; ++i) {\n            vm.setEnv(key, values[i]);\n            string memory output = vm.envOr(key, expected[i]);\n            assertEq(output, expected[i], \"envOrStringKey failed\");\n        }\n    }\n\n    function testEnvOrStringDefault() public {\n        string memory key = \"_foundryCheatcodeEnvOrStringTestDefault\";\n        string[numEnvStringTests] memory expected = [\"hello, world!\", \"0x7109709ECfa91a80626fF3989D68f67F5b1DD12D\"];\n        for (uint256 i = 0; i < numEnvStringTests; ++i) {\n            string memory output = vm.envOr(key, expected[i]);\n            assertEq(output, expected[i], \"envOrStringDefault failed\");\n        }\n    }\n\n    function testEnvOrBytesKey() public {\n        string memory key = \"_foundryCheatcodeEnvOrBytesTestKey\";\n        string[numEnvBytesTests] memory values = [\"0x7109709ECfa91a80626fF3989D68f67F5b1DD12D\", \"0x00\"];\n        bytes[] memory expected = new bytes[](numEnvBytesTests);\n        expected[0] = hex\"7109709ECfa91a80626fF3989D68f67F5b1DD12D\";\n        expected[1] = hex\"00\";\n        for (uint256 i = 0; i < numEnvBytesTests; ++i) {\n            vm.setEnv(key, values[i]);\n            bytes memory output = vm.envOr(key, expected[i]);\n            require(\n                keccak256(abi.encodePacked((output))) == keccak256(abi.encodePacked((expected[i]))),\n                \"envOrBytesKey failed\"\n            );\n        }\n    }\n\n    function testEnvOrBytesDefault() public {\n        string memory key = \"_foundryCheatcodeEnvOrBytesTestDefault\";\n        bytes[] memory expected = new bytes[](numEnvBytesTests);\n        expected[0] = hex\"7109709ECfa91a80626fF3989D68f67F5b1DD12D\";\n        expected[1] = hex\"00\";\n        for (uint256 i = 0; i < numEnvBytesTests; ++i) {\n            bytes memory output = vm.envOr(key, expected[i]);\n            require(\n                keccak256(abi.encodePacked((output))) == keccak256(abi.encodePacked((expected[i]))),\n                \"envOrBytesDefault failed\"\n            );\n        }\n    }\n\n    function testEnvOrBoolArrKey() public {\n        string memory key = \"_foundryCheatcodeEnvBoolWithDefaultBoolArrTestKey\";\n        string memory value = \"true, false\";\n        bool[numEnvBoolTests] memory expected = [true, false];\n        bool[] memory defaultValues = new bool[](numEnvBoolTests);\n        defaultValues[0] = true;\n        defaultValues[1] = false;\n\n        vm.setEnv(key, value);\n        string memory delimiter = \",\";\n        bool[] memory output = vm.envOr(key, delimiter, defaultValues);\n        require(\n            keccak256(abi.encodePacked((output))) == keccak256(abi.encodePacked((expected))), \"envOrBoolArrKey failed\"\n        );\n    }\n\n    function testEnvOrBoolArrDefault() public {\n        string memory key = \"_foundryCheatcodeEnvBoolWithDefaultBoolArrTestDefault\";\n        string memory value = \"true, false\";\n        bool[numEnvBoolTests] memory expected = [true, false];\n        bool[] memory defaultValues = new bool[](numEnvBoolTests);\n        defaultValues[0] = true;\n        defaultValues[1] = false;\n\n        string memory delimiter = \",\";\n        bool[] memory output = vm.envOr(key, delimiter, defaultValues);\n        require(\n            keccak256(abi.encodePacked((output))) == keccak256(abi.encodePacked((expected))),\n            \"envOrBoolArrDefault failed\"\n        );\n    }\n\n    function testEnvOrUintArrKey() public {\n        string memory key = \"_foundryCheatcodeEnvOrUintArrTestKey\";\n        string memory value = \"0,\" \"115792089237316195423570985008687907853269984665640564039457584007913129639935,\"\n            \"0x0000000000000000000000000000000000000000000000000000000000000000,\"\n            \"0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\";\n        uint256[4] memory expected = [type(uint256).min, type(uint256).max, type(uint256).min, type(uint256).max];\n        uint256[] memory defaultValues = new uint256[](4);\n        defaultValues[0] = type(uint256).min;\n        defaultValues[1] = type(uint256).max;\n        defaultValues[2] = type(uint256).min;\n        defaultValues[3] = type(uint256).max;\n\n        vm.setEnv(key, value);\n        string memory delimiter = \",\";\n        uint256[] memory output = vm.envOr(key, delimiter, defaultValues);\n        require(\n            keccak256(abi.encodePacked((output))) == keccak256(abi.encodePacked((expected))), \"envOrUintArrKey failed\"\n        );\n    }\n\n    function testEnvOrUintArrDefault() public {\n        string memory key = \"_foundryCheatcodeEnvOrUintArrTestDefault\";\n        string memory value = \"0,\" \"115792089237316195423570985008687907853269984665640564039457584007913129639935,\"\n            \"0x0000000000000000000000000000000000000000000000000000000000000000,\"\n            \"0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\";\n        uint256[4] memory expected = [type(uint256).min, type(uint256).max, type(uint256).min, type(uint256).max];\n        uint256[] memory defaultValues = new uint256[](4);\n        defaultValues[0] = type(uint256).min;\n        defaultValues[1] = type(uint256).max;\n        defaultValues[2] = type(uint256).min;\n        defaultValues[3] = type(uint256).max;\n\n        string memory delimiter = \",\";\n        uint256[] memory output = vm.envOr(key, delimiter, defaultValues);\n        require(\n            keccak256(abi.encodePacked((output))) == keccak256(abi.encodePacked((expected))),\n            \"envOrUintArrDefault failed\"\n        );\n    }\n\n    function testEnvOrIntArrKey() public {\n        string memory key = \"_foundryCheatcodeEnvOrIntArrTestKey\";\n        string memory value = \"-57896044618658097711785492504343953926634992332820282019728792003956564819968,\"\n            \"57896044618658097711785492504343953926634992332820282019728792003956564819967,\"\n            \"-0x8000000000000000000000000000000000000000000000000000000000000000,\"\n            \"0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\";\n        int256[4] memory expected = [type(int256).min, type(int256).max, type(int256).min, type(int256).max];\n        int256[] memory defaultValues = new int256[](4);\n        defaultValues[0] = type(int256).min;\n        defaultValues[1] = type(int256).max;\n        defaultValues[2] = type(int256).min;\n        defaultValues[3] = type(int256).max;\n\n        vm.setEnv(key, value);\n        string memory delimiter = \",\";\n        int256[] memory output = vm.envOr(key, delimiter, defaultValues);\n        require(\n            keccak256(abi.encodePacked((output))) == keccak256(abi.encodePacked((expected))), \"envOrIntArrKey failed\"\n        );\n    }\n\n    function testEnvOrIntArrDefault() public {\n        string memory key = \"_foundryCheatcodeEnvOrIntArrTestDefault\";\n        string memory value = \"-57896044618658097711785492504343953926634992332820282019728792003956564819968,\"\n            \"57896044618658097711785492504343953926634992332820282019728792003956564819967,\"\n            \"-0x8000000000000000000000000000000000000000000000000000000000000000,\"\n            \"0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\";\n        int256[4] memory expected = [type(int256).min, type(int256).max, type(int256).min, type(int256).max];\n        int256[] memory defaultValues = new int256[](4);\n        defaultValues[0] = type(int256).min;\n        defaultValues[1] = type(int256).max;\n        defaultValues[2] = type(int256).min;\n        defaultValues[3] = type(int256).max;\n\n        string memory delimiter = \",\";\n        int256[] memory output = vm.envOr(key, delimiter, defaultValues);\n        require(\n            keccak256(abi.encodePacked((output))) == keccak256(abi.encodePacked((expected))),\n            \"envOrIntArrDefault failed\"\n        );\n    }\n\n    function testEnvOrAddressArrKey() public {\n        string memory key = \"_foundryCheatcodeEnvOrAddressArrTestKey\";\n        string memory value = \"0x7109709ECfa91a80626fF3989D68f67F5b1DD12D,\" \"0x0000000000000000000000000000000000000000\";\n        address[2] memory expected =\n            [0x7109709ECfa91a80626fF3989D68f67F5b1DD12D, 0x0000000000000000000000000000000000000000];\n        address[] memory defaultValues = new address[](2);\n        defaultValues[0] = 0x7109709ECfa91a80626fF3989D68f67F5b1DD12D;\n        defaultValues[1] = 0x0000000000000000000000000000000000000000;\n\n        vm.setEnv(key, value);\n        string memory delimiter = \",\";\n        address[] memory output = vm.envOr(key, delimiter, defaultValues);\n        require(\n            keccak256(abi.encodePacked((output))) == keccak256(abi.encodePacked((expected))),\n            \"envOrAddressArrKey failed\"\n        );\n    }\n\n    function testEnvOrAddressArrDefault() public {\n        string memory key = \"_foundryCheatcodeEnvOrAddressArrTestDefault\";\n        string memory value = \"0x7109709ECfa91a80626fF3989D68f67F5b1DD12D,\" \"0x0000000000000000000000000000000000000000\";\n        address[2] memory expected =\n            [0x7109709ECfa91a80626fF3989D68f67F5b1DD12D, 0x0000000000000000000000000000000000000000];\n        address[] memory defaultValues = new address[](2);\n        defaultValues[0] = 0x7109709ECfa91a80626fF3989D68f67F5b1DD12D;\n        defaultValues[1] = 0x0000000000000000000000000000000000000000;\n\n        string memory delimiter = \",\";\n        address[] memory output = vm.envOr(key, delimiter, defaultValues);\n        require(\n            keccak256(abi.encodePacked((output))) == keccak256(abi.encodePacked((expected))),\n            \"envOrAddressArrDefault failed\"\n        );\n    }\n\n    function testEnvOrBytes32ArrKey() public {\n        string memory key = \"_foundryCheatcodeEnvOrBytes32ArrTestKey\";\n        string memory value = \"0x463df98a03418e6196421718c1b96779a6d4f0bcff1702a9e8f2323bb49f6811,\"\n            \"0x0000000000000000000000000000000000000000000000000000000000000000\";\n        bytes32[2] memory expected = [\n            bytes32(0x463df98a03418e6196421718c1b96779a6d4f0bcff1702a9e8f2323bb49f6811),\n            bytes32(0x0000000000000000000000000000000000000000000000000000000000000000)\n        ];\n        bytes32[] memory defaultValues = new bytes32[](2);\n        defaultValues[0] = bytes32(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D000000000000000000000000);\n        defaultValues[1] = bytes32(0x0000000000000000000000000000000000000000000000000000000000000000);\n\n        vm.setEnv(key, value);\n        string memory delimiter = \",\";\n        bytes32[] memory output = vm.envOr(key, delimiter, defaultValues);\n        require(\n            keccak256(abi.encodePacked((output))) == keccak256(abi.encodePacked((expected))),\n            \"envOrBytes32ArrKey failed\"\n        );\n    }\n\n    function testEnvOrBytes32ArrDefault() public {\n        string memory key = \"_foundryCheatcodeEnvOrBytes32ArrTestDefault\";\n        string memory value = \"0x463df98a03418e6196421718c1b96779a6d4f0bcff1702a9e8f2323bb49f6811,\"\n            \"0x0000000000000000000000000000000000000000000000000000000000000000\";\n        bytes32[2] memory expected = [\n            bytes32(0x463df98a03418e6196421718c1b96779a6d4f0bcff1702a9e8f2323bb49f6811),\n            bytes32(0x0000000000000000000000000000000000000000000000000000000000000000)\n        ];\n        bytes32[] memory defaultValues = new bytes32[](2);\n        defaultValues[0] = bytes32(0x463df98a03418e6196421718c1b96779a6d4f0bcff1702a9e8f2323bb49f6811);\n        defaultValues[1] = bytes32(0x0000000000000000000000000000000000000000000000000000000000000000);\n\n        string memory delimiter = \",\";\n        bytes32[] memory output = vm.envOr(key, delimiter, defaultValues);\n        require(\n            keccak256(abi.encodePacked((output))) == keccak256(abi.encodePacked((expected))),\n            \"envOrBytes32ArrDefault failed\"\n        );\n    }\n\n    function testEnvOrStringArrKey() public {\n        string memory key = \"_foundryCheatcodeEnvOrStringArrTestKey\";\n        string memory value = \"hello, world!|\" \"0x7109709ECfa91a80626fF3989D68f67F5b1DD12D\";\n        string[2] memory expected = [\"hello, world!\", \"0x7109709ECfa91a80626fF3989D68f67F5b1DD12D\"];\n        string[] memory defaultValues = new string[](2);\n        defaultValues[0] = \"hello, world!\";\n        defaultValues[1] = \"0x7109709ECfa91a80626fF3989D68f67F5b1DD12D\";\n\n        vm.setEnv(key, value);\n        string memory delimiter = \"|\";\n        string[] memory output = vm.envOr(key, delimiter, defaultValues);\n        for (uint256 i = 0; i < expected.length; ++i) {\n            require(\n                keccak256(abi.encodePacked((output[i]))) == keccak256(abi.encodePacked((expected[i]))),\n                \"envOrStringArrKey failed\"\n            );\n        }\n    }\n\n    function testEnvOrStringArrDefault() public {\n        string memory key = \"_foundryCheatcodeEnvOrStringArrTestDefault\";\n        string memory value = \"hello, world!|\" \"0x7109709ECfa91a80626fF3989D68f67F5b1DD12D\";\n        string[2] memory expected = [\"hello, world!\", \"0x7109709ECfa91a80626fF3989D68f67F5b1DD12D\"];\n        string[] memory defaultValues = new string[](2);\n        defaultValues[0] = \"hello, world!\";\n        defaultValues[1] = \"0x7109709ECfa91a80626fF3989D68f67F5b1DD12D\";\n\n        string memory delimiter = \"|\";\n        string[] memory output = vm.envOr(key, delimiter, defaultValues);\n        for (uint256 i = 0; i < expected.length; ++i) {\n            require(\n                keccak256(abi.encodePacked((output[i]))) == keccak256(abi.encodePacked((expected[i]))),\n                \"envOrStringArrDefault failed\"\n            );\n        }\n    }\n\n    function testEnvOrBytesArrKey() public {\n        string memory key = \"_foundryCheatcodeEnvOrBytesArrTestKey\";\n        string memory value = \"0x7109709ECfa91a80626fF3989D68f67F5b1DD12D,\" \"0x00\";\n        bytes[] memory expected = new bytes[](2);\n        expected[0] = hex\"7109709ECfa91a80626fF3989D68f67F5b1DD12D\";\n        expected[1] = hex\"00\";\n\n        vm.setEnv(key, value);\n        string memory delimiter = \",\";\n        bytes[] memory output = vm.envOr(key, delimiter, expected);\n        for (uint256 i = 0; i < expected.length; ++i) {\n            require(\n                keccak256(abi.encodePacked((output[i]))) == keccak256(abi.encodePacked((expected[i]))),\n                \"envOrBytesArrKey failed\"\n            );\n        }\n    }\n\n    function testEnvOrBytesArrDefault() public {\n        string memory key = \"_foundryCheatcodeEnvOrBytesArrTestDefault\";\n        string memory value = \"0x463df98a03418e6196421718c1b96779a6d4f0bcff1702a9e8f2323bb49f6811,\" \"0x00\";\n        bytes[] memory expected = new bytes[](2);\n        expected[0] = hex\"463df98a03418e6196421718c1b96779a6d4f0bcff1702a9e8f2323bb49f6811\";\n        expected[1] = hex\"00\";\n\n        string memory delimiter = \",\";\n        bytes[] memory output = vm.envOr(key, delimiter, expected);\n        for (uint256 i = 0; i < expected.length; ++i) {\n            require(\n                keccak256(abi.encodePacked((output[i]))) == keccak256(abi.encodePacked((expected[i]))),\n                \"envOrBytesArrDefault failed\"\n            );\n        }\n    }\n\n    function testEnvOrBoolEmptyArrKey() public {\n        string memory key = \"_foundryCheatcodeEnvBoolWithDefaultBoolEmptyArrTestKey\";\n        string memory value = \"\";\n        bool[] memory expected = new bool[](0);\n        bool[] memory defaultValues = new bool[](0);\n\n        vm.setEnv(key, value);\n        string memory delimiter = \",\";\n        bool[] memory output = vm.envOr(key, delimiter, defaultValues);\n        require(\n            keccak256(abi.encodePacked((output))) == keccak256(abi.encodePacked((expected))),\n            \"envOrBoolEmptyArrKey failed\"\n        );\n    }\n\n    function testEnvOrBoolEmptyArrDefault() public {\n        string memory key = \"_foundryCheatcodeEnvBoolWithDefaultBoolEmptyArrTestDefault\";\n        string memory value = \"\";\n        bool[] memory expected = new bool[](0);\n        bool[] memory defaultValues = new bool[](0);\n\n        string memory delimiter = \",\";\n        bool[] memory output = vm.envOr(key, delimiter, defaultValues);\n        require(\n            keccak256(abi.encodePacked((output))) == keccak256(abi.encodePacked((expected))),\n            \"envOrBoolEmptyArrDefault failed\"\n        );\n    }\n\n    function testEnvOrUintEmptyArrKey() public {\n        string memory key = \"_foundryCheatcodeEnvOrUintEmptyArrTestKey\";\n        string memory value = \"\";\n        uint256[] memory expected = new uint256[](0);\n        uint256[] memory defaultValues = new uint256[](0);\n\n        vm.setEnv(key, value);\n        string memory delimiter = \",\";\n        uint256[] memory output = vm.envOr(key, delimiter, defaultValues);\n        require(\n            keccak256(abi.encodePacked((output))) == keccak256(abi.encodePacked((expected))),\n            \"envOrUintEmptyArrKey failed\"\n        );\n    }\n\n    function testEnvOrUintEmptyArrDefault() public {\n        string memory key = \"_foundryCheatcodeEnvOrUintEmptyArrTestDefault\";\n        string memory value = \"\";\n        uint256[] memory expected = new uint256[](0);\n        uint256[] memory defaultValues = new uint256[](0);\n\n        string memory delimiter = \",\";\n        uint256[] memory output = vm.envOr(key, delimiter, defaultValues);\n        require(\n            keccak256(abi.encodePacked((output))) == keccak256(abi.encodePacked((expected))),\n            \"envOrUintEmptyArrDefault failed\"\n        );\n    }\n\n    function testEnvOrIntEmptyArrKey() public {\n        string memory key = \"_foundryCheatcodeEnvOrIntEmptyArrTestKey\";\n        string memory value = \"\";\n        int256[] memory expected = new int256[](0);\n        int256[] memory defaultValues = new int256[](0);\n\n        vm.setEnv(key, value);\n        string memory delimiter = \",\";\n        int256[] memory output = vm.envOr(key, delimiter, defaultValues);\n        require(\n            keccak256(abi.encodePacked((output))) == keccak256(abi.encodePacked((expected))),\n            \"envOrIntEmptyArrKey failed\"\n        );\n    }\n\n    function testEnvOrIntEmptyArrDefault() public {\n        string memory key = \"_foundryCheatcodeEnvOrIntEmptyArrTestDefault\";\n        string memory value = \"\";\n        int256[] memory expected = new int256[](0);\n        int256[] memory defaultValues = new int256[](0);\n\n        string memory delimiter = \",\";\n        int256[] memory output = vm.envOr(key, delimiter, defaultValues);\n        require(\n            keccak256(abi.encodePacked((output))) == keccak256(abi.encodePacked((expected))),\n            \"envOrIntEmptyArrDefault failed\"\n        );\n    }\n\n    function testEnvOrAddressEmptyArrKey() public {\n        string memory key = \"_foundryCheatcodeEnvOrAddressEmptyArrTestKey\";\n        string memory value = \"\";\n        address[] memory expected = new address[](0);\n        address[] memory defaultValues = new address[](0);\n\n        vm.setEnv(key, value);\n        string memory delimiter = \",\";\n        address[] memory output = vm.envOr(key, delimiter, defaultValues);\n        require(\n            keccak256(abi.encodePacked((output))) == keccak256(abi.encodePacked((expected))),\n            \"envOrAddressEmptyArrKey failed\"\n        );\n    }\n\n    function testEnvOrAddressEmptyArrDefault() public {\n        string memory key = \"_foundryCheatcodeEnvOrAddressEmptyArrTestDefault\";\n        string memory value = \"\";\n        address[] memory expected = new address[](0);\n        address[] memory defaultValues = new address[](0);\n\n        string memory delimiter = \",\";\n        address[] memory output = vm.envOr(key, delimiter, defaultValues);\n        require(\n            keccak256(abi.encodePacked((output))) == keccak256(abi.encodePacked((expected))),\n            \"envOrAddressEmptyArrDefault failed\"\n        );\n    }\n\n    function testEnvOrBytes32EmptyArrKey() public {\n        string memory key = \"_foundryCheatcodeEnvOrBytes32EmptyArrTestKey\";\n        string memory value = \"\";\n        bytes32[] memory expected = new bytes32[](0);\n        bytes32[] memory defaultValues = new bytes32[](0);\n\n        vm.setEnv(key, value);\n        string memory delimiter = \",\";\n        bytes32[] memory output = vm.envOr(key, delimiter, defaultValues);\n        require(\n            keccak256(abi.encodePacked((output))) == keccak256(abi.encodePacked((expected))),\n            \"envOrBytes32EmptyArrKey failed\"\n        );\n    }\n\n    function testEnvOrBytes32EmptyArrDefault() public {\n        string memory key = \"_foundryCheatcodeEnvOrBytes32EmptyArrTestDefault\";\n        string memory value = \"\";\n        bytes32[] memory expected = new bytes32[](0);\n        bytes32[] memory defaultValues = new bytes32[](0);\n\n        string memory delimiter = \",\";\n        bytes32[] memory output = vm.envOr(key, delimiter, defaultValues);\n        require(\n            keccak256(abi.encodePacked((output))) == keccak256(abi.encodePacked((expected))),\n            \"envOrBytes32EmptyArrDefault failed\"\n        );\n    }\n\n    function testEnvOrStringEmptyArrKey() public {\n        string memory key = \"_foundryCheatcodeEnvOrStringEmptyArrTestKey\";\n        string memory value = \"\";\n        string[] memory expected = new string[](0);\n        string[] memory defaultValues = new string[](0);\n\n        vm.setEnv(key, value);\n        string memory delimiter = \"|\";\n        string[] memory output = vm.envOr(key, delimiter, defaultValues);\n        for (uint256 i = 0; i < expected.length; ++i) {\n            require(\n                keccak256(abi.encodePacked((output[i]))) == keccak256(abi.encodePacked((expected[i]))),\n                \"envOrStringEmptyArrKey failed\"\n            );\n        }\n    }\n\n    function testEnvOrStringEmptyArrDefault() public {\n        string memory key = \"_foundryCheatcodeEnvOrStringEmptyArrTestDefault\";\n        string memory value = \"\";\n        string[] memory expected = new string[](0);\n        string[] memory defaultValues = new string[](0);\n\n        string memory delimiter = \"|\";\n        string[] memory output = vm.envOr(key, delimiter, defaultValues);\n        for (uint256 i = 0; i < expected.length; ++i) {\n            require(\n                keccak256(abi.encodePacked((output[i]))) == keccak256(abi.encodePacked((expected[i]))),\n                \"envOrStringEmptyArrDefault failed\"\n            );\n        }\n    }\n\n    function testEnvWithDefaultBytesEmptyArrKey() public {\n        string memory key = \"_foundryCheatcodeEnvWithDefaultBytesEmptyArrTestKey\";\n        string memory value = \"\";\n        bytes[] memory expected = new bytes[](0);\n        bytes[] memory defaultValues = new bytes[](0);\n\n        vm.setEnv(key, value);\n        string memory delimiter = \",\";\n        bytes[] memory output = vm.envOr(key, delimiter, expected);\n        for (uint256 i = 0; i < expected.length; ++i) {\n            require(\n                keccak256(abi.encodePacked((output[i]))) == keccak256(abi.encodePacked((expected[i]))),\n                \"envWithDefaultBytesEmptyArrKey failed\"\n            );\n        }\n    }\n\n    function testEnvWithDefaultBytesEmptyArrDefault() public {\n        string memory key = \"_foundryCheatcodeEnvWithDefaultBytesEmptyArrTestDefault\";\n        string memory value = \"\";\n        bytes[] memory expected = new bytes[](0);\n        bytes[] memory defaultValues = new bytes[](0);\n\n        string memory delimiter = \",\";\n        bytes[] memory output = vm.envOr(key, delimiter, expected);\n        for (uint256 i = 0; i < expected.length; ++i) {\n            require(\n                keccak256(abi.encodePacked((output[i]))) == keccak256(abi.encodePacked((expected[i]))),\n                \"envWithDefaultBytesEmptyArrDefault failed\"\n            );\n        }\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/Etch.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract EtchTest is Test {\n    function testEtch() public {\n        address target = address(7070707);\n        bytes memory code = hex\"1010\";\n        vm.etch(target, code);\n        assertEq(string(code), string(target.code));\n    }\n\n    function testEtchNotAvailableOnPrecompiles() public {\n        address target = address(1);\n        bytes memory code = hex\"1010\";\n        vm._expectCheatcodeRevert(\"cannot use precompile 0x0000000000000000000000000000000000000001 as an argument\");\n        vm.etch(target, code);\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/ExecuteTransaction.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract ExecuteTransactionTest is Test {\n    function test_revert_not_a_tx() public {\n        vm._expectCheatcodeRevert(\"failed to decode RLP-encoded transaction: unexpected string\");\n        vm.executeTransaction(hex\"0102\");\n    }\n\n    function test_execute_legacy_transfer() public {\n        vm.fee(1);\n        vm.chainId(1);\n\n        address from = 0x5316812db67073C4d4af8BB3000C5B86c2877e94;\n        address to = 0x6Fd0A0CFF9A87aDF51695b40b4fA267855a8F4c6;\n\n        uint256 balance = 1 ether;\n        uint256 amountSent = 17;\n\n        vm.deal(address(from), balance);\n        assertEq(address(from).balance, balance);\n        assertEq(address(to).balance, 0);\n\n        /*\n        Legacy signed transaction (type 0):\n        { from: 0x5316812db67073c4d4af8bb3000c5b86c2877e94, to: 0x6fd0a0cff9a87adf51695b40b4fa267855a8f4c6, gas: 200000, gasPrice: 100, value: 17, nonce: 0, chainId: 1 }\n        */\n        vm.executeTransaction(\n            hex\"f860806483030d40946fd0a0cff9a87adf51695b40b4fa267855a8f4c6118025a03ebeabbcfe43c2c982e99b376b5fb6e765059d7f215533c8751218cac99bbd80a00a56cf5c382442466770a756e81272d06005c9e90fb8dbc5b53af499d5aca856\"\n        );\n\n        // Gas price is set to 0 in isolated execution, so no gas cost deducted.\n        assertEq(address(from).balance, balance - amountSent);\n        assertEq(address(to).balance, amountSent);\n    }\n\n    function test_execute_eip1559_transfer() public {\n        vm.chainId(1);\n\n        address from = 0x70997970C51812dc3A010C7d01b50e0d17dc79C8;\n        address to = 0x6Fd0A0CFF9A87aDF51695b40b4fA267855a8F4c6;\n\n        uint256 balance = 1 ether;\n        uint256 amountSent = 42;\n\n        vm.deal(from, balance);\n        assertEq(from.balance, balance);\n        assertEq(to.balance, 0);\n\n        /*\n        EIP-1559 signed transaction (type 2):\n        { from: 0x70997970C51812dc3A010C7d01b50e0d17dc79C8, to: 0x6fd0a0cff9a87adf51695b40b4fa267855a8f4c6, gas: 21000, maxFeePerGas: 100, maxPriorityFeePerGas: 10, value: 42, nonce: 0, chainId: 1 }\n        */\n        vm.executeTransaction(\n            hex\"02f86201800a64825208946fd0a0cff9a87adf51695b40b4fa267855a8f4c62a80c080a03447a5bb5068bea134c052824759b5dd973aefcf745d0d67a6e2ee6543571f2ca05f3ee9f04a4d3cbc883f5a8b68cb6149fbc47083bb7f4abf644df780f2f11638\"\n        );\n\n        // Gas price is set to 0 in isolated execution, so no gas cost deducted.\n        assertEq(from.balance, balance - amountSent);\n        assertEq(to.balance, amountSent);\n    }\n\n    function test_execute_erc20_transfer() public {\n        vm.fee(1);\n        vm.chainId(1);\n\n        address alice = 0x7ED31830602f9F7419307235c0610Fb262AA0375;\n        address bob = 0x70CF146aB98ffD5dE24e75dd7423F16181Da8E13;\n        address charlie = 0xae0900Cf97f8C233c64F7089cEC7d5457215BB8d;\n\n        bytes memory code =\n            hex\"608060405234801561001057600080fd5b50600436106100625760003560e01c8063095ea7b31461006757806323b872dd1461008f57806370a08231146100a257806394bf804d146100d9578063a9059cbb146100ee578063dd62ed3e14610101575b600080fd5b61007a61007536600461051d565b61013a565b60405190151581526020015b60405180910390f35b61007a61009d366004610547565b610152565b6100cb6100b0366004610583565b6001600160a01b031660009081526020819052604090205490565b604051908152602001610086565b6100ec6100e73660046105a5565b610176565b005b61007a6100fc36600461051d565b610184565b6100cb61010f3660046105d1565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b600033610148818585610192565b5060019392505050565b600033610160858285610286565b61016b858585610318565b506001949350505050565b6101808183610489565b5050565b600033610148818585610318565b6001600160a01b0383166101f95760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b60648201526084015b60405180910390fd5b6001600160a01b03821661025a5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b60648201526084016101f0565b6001600160a01b0392831660009081526001602090815260408083209490951682529290925291902055565b6001600160a01b03838116600090815260016020908152604080832093861683529290522054600019811461031257818110156103055760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e636500000060448201526064016101f0565b6103128484848403610192565b50505050565b6001600160a01b03831661037c5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b60648201526084016101f0565b6001600160a01b0382166103de5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b60648201526084016101f0565b6001600160a01b038316600090815260208190526040902054818110156104565760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b60648201526084016101f0565b6001600160a01b039384166000908152602081905260408082209284900390925592909316825291902080549091019055565b6001600160a01b0382166104df5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016101f0565b6001600160a01b03909116600090815260208190526040902080549091019055565b80356001600160a01b038116811461051857600080fd5b919050565b6000806040838503121561053057600080fd5b61053983610501565b946020939093013593505050565b60008060006060848603121561055c57600080fd5b61056584610501565b925061057360208501610501565b9150604084013590509250925092565b60006020828403121561059557600080fd5b61059e82610501565b9392505050565b600080604083850312156105b857600080fd5b823591506105c860208401610501565b90509250929050565b600080604083850312156105e457600080fd5b6105ed83610501565b91506105c86020840161050156fea2646970667358221220e1fee5cd1c5bbf066a9ce9228e1baf7e7fcb77b5050506c7d614aaf8608b42e364736f6c63430008110033\";\n\n        MyERC20 token = MyERC20(address(uint160(uint256(keccak256(abi.encodePacked(\"mytoken\"))))));\n        vm.etch(address(token), code);\n\n        token.mint(100, alice);\n\n        assertEq(token.balanceOf(alice), 100);\n        assertEq(token.balanceOf(bob), 0);\n        assertEq(token.balanceOf(charlie), 0);\n\n        vm.deal(alice, 10 ether);\n\n        /*\n        Signed transaction:\n        {\n            from: '0x7ED31830602f9F7419307235c0610Fb262AA0375',\n            to: '0x5bF11839F61EF5ccEEaf1F4153e44df5D02825f7',\n            value: 0,\n            data: '0x095ea7b300000000000000000000000070cf146ab98ffd5de24e75dd7423f16181da8e130000000000000000000000000000000000000000000000000000000000000032',\n            nonce: 0,\n            gasPrice: 100,\n            gasLimit: 200000,\n            chainId: 1\n        }\n        */\n        // alice approves bob for 50 tokens\n        vm.executeTransaction(\n            hex\"f8a5806483030d40945bf11839f61ef5cceeaf1f4153e44df5d02825f780b844095ea7b300000000000000000000000070cf146ab98ffd5de24e75dd7423f16181da8e13000000000000000000000000000000000000000000000000000000000000003225a0e25b9ef561d9a413b21755cc0e4bb6e80f2a88a8a52305690956130d612074dfa07bfd418bc2ad3c3f435fa531cdcdc64887f64ed3fb0d347d6b0086e320ad4eb1\"\n        );\n\n        assertEq(token.allowance(alice, bob), 50);\n\n        // Use the allowance via a normal prank call.\n        vm.deal(bob, 1 ether);\n        vm.prank(bob);\n        token.transferFrom(alice, charlie, 20);\n\n        assertEq(token.balanceOf(alice), 80);\n        assertEq(token.balanceOf(bob), 0);\n        assertEq(token.balanceOf(charlie), 20);\n    }\n\n    // Verify state isolation: operations after executeTransaction should work correctly.\n    function test_execute_then_interact() public {\n        vm.fee(1);\n        vm.chainId(1);\n\n        address from = 0x5316812db67073C4d4af8BB3000C5B86c2877e94;\n        address to = 0x6Fd0A0CFF9A87aDF51695b40b4fA267855a8F4c6;\n        address random = address(uint160(uint256(keccak256(abi.encodePacked(\"random\")))));\n\n        uint256 balance = 1 ether;\n\n        vm.deal(address(from), balance);\n\n        vm.executeTransaction(\n            hex\"f860806483030d40946fd0a0cff9a87adf51695b40b4fa267855a8f4c6118025a03ebeabbcfe43c2c982e99b376b5fb6e765059d7f215533c8751218cac99bbd80a00a56cf5c382442466770a756e81272d06005c9e90fb8dbc5b53af499d5aca856\"\n        );\n\n        assertEq(address(to).balance, 17);\n\n        // Interact with the state after executeTransaction.\n        uint256 value = 5;\n        vm.prank(to);\n        (bool success,) = random.call{value: value}(\"\");\n        require(success);\n        assertEq(address(to).balance, 17 - value);\n        assertEq(address(random).balance, value);\n    }\n}\n\ncontract MyERC20 {\n    mapping(address => uint256) private _balances;\n    mapping(address => mapping(address => uint256)) private _allowances;\n\n    function mint(uint256 amount, address to) public {\n        _mint(to, amount);\n    }\n\n    function balanceOf(address account) public view returns (uint256) {\n        return _balances[account];\n    }\n\n    function transfer(address to, uint256 amount) public returns (bool) {\n        address owner = msg.sender;\n        _transfer(owner, to, amount);\n        return true;\n    }\n\n    function allowance(address owner, address spender) public view returns (uint256) {\n        return _allowances[owner][spender];\n    }\n\n    function approve(address spender, uint256 amount) public returns (bool) {\n        address owner = msg.sender;\n        _approve(owner, spender, amount);\n        return true;\n    }\n\n    function transferFrom(address from, address to, uint256 amount) public returns (bool) {\n        address spender = msg.sender;\n        _spendAllowance(from, spender, amount);\n        _transfer(from, to, amount);\n        return true;\n    }\n\n    function _transfer(address from, address to, uint256 amount) internal {\n        require(from != address(0), \"ERC20: transfer from the zero address\");\n        require(to != address(0), \"ERC20: transfer to the zero address\");\n\n        uint256 fromBalance = _balances[from];\n        require(fromBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n        unchecked {\n            _balances[from] = fromBalance - amount;\n            _balances[to] += amount;\n        }\n    }\n\n    function _mint(address account, uint256 amount) internal {\n        require(account != address(0), \"ERC20: mint to the zero address\");\n        unchecked {\n            _balances[account] += amount;\n        }\n    }\n\n    function _approve(address owner, address spender, uint256 amount) internal {\n        require(owner != address(0), \"ERC20: approve from the zero address\");\n        require(spender != address(0), \"ERC20: approve to the zero address\");\n        _allowances[owner][spender] = amount;\n    }\n\n    function _spendAllowance(address owner, address spender, uint256 amount) internal {\n        uint256 currentAllowance = allowance(owner, spender);\n        if (currentAllowance != type(uint256).max) {\n            require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n            unchecked {\n                _approve(owner, spender, currentAllowance - amount);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/ExpectCall.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract Contract {\n    function numberA() public pure returns (uint256) {\n        return 1;\n    }\n\n    function numberB() public pure returns (uint256) {\n        return 2;\n    }\n\n    function add(uint256 a, uint256 b) public pure returns (uint256) {\n        return a + b;\n    }\n\n    function pay(uint256 a) public payable returns (uint256) {\n        return a;\n    }\n}\n\ncontract NestedContract {\n    Contract private inner;\n\n    constructor(Contract _inner) {\n        inner = _inner;\n    }\n\n    function sum() public view returns (uint256) {\n        return inner.numberA() + inner.numberB();\n    }\n\n    function forwardPay() public payable returns (uint256) {\n        return inner.pay{gas: 50_000, value: 1}(1);\n    }\n\n    function addHardGasLimit() public view returns (uint256) {\n        return inner.add{gas: 50_000}(1, 1);\n    }\n\n    function hello() public pure returns (string memory) {\n        return \"hi\";\n    }\n\n    function sumInPlace(uint256 a, uint256 b) public view returns (uint256) {\n        return a + b + 42;\n    }\n}\n\ncontract SimpleCall {\n    function call() public {}\n}\n\ncontract ProxyWithDelegateCall {\n    function delegateCall(SimpleCall simpleCall) public {\n        (bool success,) = address(simpleCall).delegatecall(abi.encodeWithSignature(\"call()\"));\n        require(success, \"delegatecall failed\");\n    }\n}\n\ncontract ExpectCallTest is Test {\n    function exposed_callTargetNTimes(Contract target, uint256 a, uint256 b, uint256 times) public {\n        for (uint256 i = 0; i < times; i++) {\n            target.add(a, b);\n        }\n    }\n\n    function exposed_expectCallWithValue(Contract target, uint256 value, uint256 amount) public {\n        target.pay{value: value}(amount);\n    }\n\n    function testExpectCallWithData() public {\n        Contract target = new Contract();\n        vm.expectCall(address(target), abi.encodeWithSelector(target.add.selector, 1, 2));\n        this.exposed_callTargetNTimes(target, 1, 2, 1);\n    }\n\n    function testExpectMultipleCallsWithData() public {\n        Contract target = new Contract();\n        vm.expectCall(address(target), abi.encodeWithSelector(target.add.selector, 1, 2));\n        // Even though we expect one call, we're using additive behavior, so getting more than one call is okay.\n        this.exposed_callTargetNTimes(target, 1, 2, 2);\n    }\n\n    function testExpectMultipleCallsWithDataAdditive() public {\n        Contract target = new Contract();\n        vm.expectCall(address(target), abi.encodeWithSelector(target.add.selector, 1, 2));\n        vm.expectCall(address(target), abi.encodeWithSelector(target.add.selector, 1, 2));\n        this.exposed_callTargetNTimes(target, 1, 2, 2);\n    }\n\n    function testExpectMultipleCallsWithDataAdditiveLowerBound() public {\n        Contract target = new Contract();\n        vm.expectCall(address(target), abi.encodeWithSelector(target.add.selector, 1, 2));\n        vm.expectCall(address(target), abi.encodeWithSelector(target.add.selector, 1, 2));\n        this.exposed_callTargetNTimes(target, 1, 2, 3);\n    }\n\n    function testExpectInnerCall() public {\n        Contract inner = new Contract();\n        NestedContract target = new NestedContract(inner);\n        vm.expectCall(address(inner), abi.encodeWithSelector(inner.numberB.selector));\n        this.exposed_expectInnerCall(target);\n    }\n\n    function exposed_expectInnerCall(NestedContract target) public {\n        target.sum();\n    }\n\n    function exposed_failExpectInnerCall(NestedContract target) public {\n        // this function does not call inner\n        target.hello();\n    }\n\n    // We should be able to match whichever function is called inside of the next call.\n    // Even multiple functions.\n    function testExpectCallMultipleFunctions() public {\n        Contract inner = new Contract();\n        NestedContract target = new NestedContract(inner);\n\n        vm.expectCall(address(target), abi.encodeWithSelector(target.forwardPay.selector));\n        vm.expectCall(address(inner), abi.encodeWithSelector(inner.pay.selector));\n        this.exposed_forwardPay(target);\n    }\n\n    // We should also be able to match multiple functions that happen one after another,\n    // but inside the next call.\n    function testExpectCallMultipleFunctionsFlattened() public {\n        Contract inner = new Contract();\n        NestedContract target = new NestedContract(inner);\n\n        vm.expectCall(address(target), abi.encodeWithSelector(target.sumInPlace.selector));\n        vm.expectCall(address(inner), abi.encodeWithSelector(inner.add.selector));\n        this.exposed_expectCallMultipleFunctionsFlattened(target, inner);\n    }\n\n    function exposed_expectCallMultipleFunctionsFlattened(NestedContract target, Contract inner) public {\n        target.sumInPlace(1, 1);\n        inner.add(1, 1);\n    }\n\n    function testExpectSelectorCall() public {\n        Contract target = new Contract();\n        vm.expectCall(address(target), abi.encodeWithSelector(target.add.selector));\n        this.exposed_callTargetNTimes(target, 5, 5, 1);\n    }\n\n    function testExpectCallWithValue() public {\n        Contract target = new Contract();\n        vm.expectCall(address(target), 1, abi.encodeWithSelector(target.pay.selector, 2));\n        this.exposed_expectCallWithValue(target, 1, 2);\n    }\n\n    function testExpectCallWithValueWithoutParameters() public {\n        Contract target = new Contract();\n        vm.expectCall(address(target), 3, abi.encodeWithSelector(target.pay.selector));\n        this.exposed_expectCallWithValue(target, 3, 100);\n    }\n\n    function testExpectCallWithValueAndGas() public {\n        Contract inner = new Contract();\n        NestedContract target = new NestedContract(inner);\n        vm.expectCall(address(inner), 1, 50_000, abi.encodeWithSelector(inner.pay.selector, 1));\n        this.exposed_forwardPay(target);\n    }\n\n    function exposed_forwardPay(NestedContract target) public {\n        target.forwardPay{value: 1}();\n    }\n\n    function testExpectCallWithNoValueAndGas() public {\n        Contract inner = new Contract();\n        NestedContract target = new NestedContract(inner);\n        vm.expectCall(address(inner), 0, 50_000, abi.encodeWithSelector(inner.add.selector, 1, 1));\n        this.exposed_addHardGasLimit(target);\n    }\n\n    function exposed_addHardGasLimit(NestedContract target) public {\n        target.addHardGasLimit();\n    }\n\n    function testExpectCallWithValueAndMinGas() public {\n        Contract inner = new Contract();\n        NestedContract target = new NestedContract(inner);\n        vm.expectCallMinGas(address(inner), 1, 50_000, abi.encodeWithSelector(inner.pay.selector, 1));\n        this.exposed_forwardPay(target);\n    }\n\n    function testExpectCallWithNoValueAndMinGas() public {\n        Contract inner = new Contract();\n        NestedContract target = new NestedContract(inner);\n        vm.expectCallMinGas(address(inner), 0, 25_000, abi.encodeWithSelector(inner.add.selector, 1, 1));\n        this.exposed_addHardGasLimit(target);\n    }\n\n    /// Ensure expectCall works for Proxy DelegateCalls. Ref: <https://github.com/foundry-rs/foundry/issues/8015>\n    function testExpectCallForProxyDelegateCall() public {\n        ProxyWithDelegateCall proxyWithDelegateCall = new ProxyWithDelegateCall();\n        SimpleCall simpleCall = new SimpleCall();\n        vm.expectCall(address(simpleCall), abi.encodeWithSignature(\"call()\"));\n        proxyWithDelegateCall.delegateCall(simpleCall);\n    }\n}\n\ncontract ExpectCallCountTest is Test {\n    function testExpectCallCountWithData() public {\n        Contract target = new Contract();\n        vm.expectCall(address(target), abi.encodeWithSelector(Contract.add.selector, 1, 2), 3);\n        this.exposed_expectCallCountWithData(target);\n    }\n\n    function exposed_expectCallCountWithData(Contract target) public {\n        target.add(1, 2);\n        target.add(1, 2);\n        target.add(1, 2);\n    }\n\n    function testExpectZeroCallCountAssert() public {\n        Contract target = new Contract();\n        vm.expectCall(address(target), abi.encodeWithSelector(target.add.selector, 1, 2), 0);\n        target.add(3, 3);\n    }\n\n    function testExpectCountInnerCall() public {\n        Contract inner = new Contract();\n        NestedContract target = new NestedContract(inner);\n        vm.expectCall(address(inner), abi.encodeWithSelector(inner.numberB.selector), 1);\n        target.sum();\n    }\n\n    function testExpectCountInnerAndOuterCalls() public {\n        Contract inner = new Contract();\n        NestedContract target = new NestedContract(inner);\n        vm.expectCall(address(inner), abi.encodeWithSelector(inner.numberB.selector), 2);\n        this.exposed_expectCountInnerAndOuterCalls(inner, target);\n    }\n\n    function exposed_expectCountInnerAndOuterCalls(Contract inner, NestedContract target) public {\n        inner.numberB();\n        target.sum();\n    }\n\n    function exposed_pay(Contract target, uint256 value, uint256 amount) public payable {\n        target.pay{value: value}(amount);\n    }\n\n    function testExpectCallCountWithValue() public {\n        Contract target = new Contract();\n        vm.expectCall(address(target), 1, abi.encodeWithSelector(target.pay.selector, 2), 1);\n        this.exposed_pay{value: 1}(target, 1, 2);\n    }\n\n    function testExpectZeroCallCountValue() public {\n        Contract target = new Contract();\n        vm.expectCall(address(target), 1, abi.encodeWithSelector(target.pay.selector, 2), 0);\n        this.exposed_pay{value: 2}(target, 2, 2);\n    }\n\n    function testExpectCallCountWithValueWithoutParameters() public {\n        Contract target = new Contract();\n        vm.expectCall(address(target), 3, abi.encodeWithSelector(target.pay.selector), 3);\n        this.exposed_expectCallCountWithValueWithoutParameters(target);\n    }\n\n    function exposed_expectCallCountWithValueWithoutParameters(Contract target) public {\n        target.pay{value: 3}(100);\n        target.pay{value: 3}(100);\n        target.pay{value: 3}(100);\n    }\n\n    function testExpectCallCountWithValueAndGas() public {\n        Contract inner = new Contract();\n        NestedContract target = new NestedContract(inner);\n        vm.expectCall(address(inner), 1, 50_000, abi.encodeWithSelector(inner.pay.selector, 1), 2);\n        this.exposed_expectCallCountWithValueAndGas(target);\n    }\n\n    function exposed_expectCallCountWithValueAndGas(NestedContract target) public {\n        target.forwardPay{value: 1}();\n        target.forwardPay{value: 1}();\n    }\n\n    function exposed_addHardGasLimit(NestedContract target, uint256 times) public {\n        for (uint256 i = 0; i < times; i++) {\n            target.addHardGasLimit();\n        }\n    }\n\n    function testExpectCallCountWithNoValueAndGas() public {\n        Contract inner = new Contract();\n        NestedContract target = new NestedContract(inner);\n        vm.expectCall(address(inner), 0, 50_000, abi.encodeWithSelector(inner.add.selector, 1, 1), 1);\n        this.exposed_addHardGasLimit(target, 1);\n    }\n\n    function testExpectZeroCallCountWithNoValueAndWrongGas() public {\n        Contract inner = new Contract();\n        NestedContract target = new NestedContract(inner);\n        vm.expectCall(address(inner), 0, 25_000, abi.encodeWithSelector(inner.add.selector, 1, 1), 0);\n        this.exposed_addHardGasLimit(target, 1);\n    }\n\n    function testExpectCallCountWithValueAndMinGas() public {\n        Contract inner = new Contract();\n        NestedContract target = new NestedContract(inner);\n        vm.expectCallMinGas(address(inner), 1, 50_000, abi.encodeWithSelector(inner.pay.selector, 1), 1);\n        this.exposed_forwardPay(target);\n    }\n\n    function exposed_forwardPay(NestedContract target) public {\n        target.forwardPay{value: 1}();\n    }\n\n    function testExpectCallCountWithNoValueAndMinGas() public {\n        Contract inner = new Contract();\n        NestedContract target = new NestedContract(inner);\n        vm.expectCallMinGas(address(inner), 0, 25_000, abi.encodeWithSelector(inner.add.selector, 1, 1), 2);\n        this.exposed_addHardGasLimit(target, 2);\n    }\n\n    function testExpectCallZeroCountWithNoValueAndWrongMinGas() public {\n        Contract inner = new Contract();\n        NestedContract target = new NestedContract(inner);\n        vm.expectCallMinGas(address(inner), 0, 50_001, abi.encodeWithSelector(inner.add.selector, 1, 1), 0);\n        this.exposed_addHardGasLimit(target, 1);\n    }\n}\n\ncontract ExpectCallMixedTest is Test {\n    function exposed_callTargetNTimes(Contract target, uint256 a, uint256 b, uint256 times) public {\n        for (uint256 i = 0; i < times; i++) {\n            target.add(1, 2);\n        }\n    }\n\n    function testExpectMatchPartialAndFull() public {\n        Contract target = new Contract();\n        vm.expectCall(address(target), abi.encodeWithSelector(target.add.selector), 2);\n        // Even if a partial match is specified, you should still be able to look for full matches\n        // as one does not override the other.\n        vm.expectCall(address(target), abi.encodeWithSelector(target.add.selector, 1, 2));\n        this.exposed_expectMatchPartialAndFull(target);\n    }\n\n    function exposed_expectMatchPartialAndFull(Contract target) public {\n        target.add(1, 2);\n        target.add(1, 2);\n    }\n\n    function testExpectMatchPartialAndFullFlipped() public {\n        Contract target = new Contract();\n        vm.expectCall(address(target), abi.encodeWithSelector(target.add.selector));\n        // Even if a partial match is specified, you should still be able to look for full matches\n        // as one does not override the other.\n        vm.expectCall(address(target), abi.encodeWithSelector(target.add.selector, 1, 2), 2);\n        this.exposed_expectMatchPartialAndFullFlipped(target);\n    }\n\n    function exposed_expectMatchPartialAndFullFlipped(Contract target) public {\n        target.add(1, 2);\n        target.add(1, 2);\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/ExpectCreate.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract Contract {\n    function add(uint256 a, uint256 b) public pure returns (uint256) {\n        return a + b;\n    }\n}\n\ncontract ContractDeployer {\n    function deployContract() public {\n        new Contract();\n    }\n\n    function deployContractCreate2() public {\n        new Contract{salt: \"foo\"}();\n    }\n}\n\ncontract ExpectCreateTest is Test {\n    bytes bytecode = vm.getDeployedCode(\"cheats/ExpectCreate.t.sol:Contract\");\n\n    function testExpectCreate() public {\n        vm.expectCreate(bytecode, address(this));\n        new Contract();\n    }\n\n    function testExpectCreate2() public {\n        vm.expectCreate2(bytecode, address(this));\n        new Contract{salt: \"foo\"}();\n    }\n\n    function testExpectNestedCreate() public {\n        ContractDeployer foo = new ContractDeployer();\n        vm.expectCreate(bytecode, address(foo));\n        vm.expectCreate2(bytecode, address(foo));\n        foo.deployContract();\n        foo.deployContractCreate2();\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/ExpectEmit.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract Emitter {\n    uint256 public thing;\n\n    event Something(uint256 indexed topic1, uint256 indexed topic2, uint256 indexed topic3, uint256 data);\n    event A(uint256 indexed topic1);\n    event B(uint256 indexed topic1);\n    event C(uint256 indexed topic1);\n    event D(uint256 indexed topic1);\n    event E(uint256 indexed topic1);\n\n    /// This event has 0 indexed topics, but the one in our tests\n    /// has exactly one indexed topic. Even though both of these\n    /// events have the same topic 0, they are different and should\n    /// be non-comparable.\n    ///\n    /// Ref: issue #760\n    event SomethingElse(uint256 data);\n\n    event SomethingNonIndexed(uint256 data);\n\n    function emitEvent(uint256 topic1, uint256 topic2, uint256 topic3, uint256 data) public {\n        emit Something(topic1, topic2, topic3, data);\n    }\n\n    function emitNEvents(uint256 topic1, uint256 topic2, uint256 topic3, uint256 data, uint256 n) public {\n        for (uint256 i = 0; i < n; i++) {\n            emit Something(topic1, topic2, topic3, data);\n        }\n    }\n\n    function emitMultiple(\n        uint256[2] memory topic1,\n        uint256[2] memory topic2,\n        uint256[2] memory topic3,\n        uint256[2] memory data\n    ) public {\n        emit Something(topic1[0], topic2[0], topic3[0], data[0]);\n        emit Something(topic1[1], topic2[1], topic3[1], data[1]);\n    }\n\n    function emitAndNest() public {\n        emit Something(1, 2, 3, 4);\n        emitNested(Emitter(address(this)), 1, 2, 3, 4);\n    }\n\n    function emitOutOfExactOrder() public {\n        emit SomethingNonIndexed(1);\n        emit Something(1, 2, 3, 4);\n        emit Something(1, 2, 3, 4);\n        emit Something(1, 2, 3, 4);\n    }\n\n    function emitNested(Emitter inner, uint256 topic1, uint256 topic2, uint256 topic3, uint256 data) public {\n        inner.emitEvent(topic1, topic2, topic3, data);\n    }\n\n    function getVar() public view returns (uint256) {\n        return 1;\n    }\n\n    /// Used to test matching of consecutive different events,\n    /// even if they're not emitted right after the other.\n    function emitWindow() public {\n        emit A(1);\n        emit B(2);\n        emit C(3);\n        emit D(4);\n        emit E(5);\n    }\n\n    function emitNestedWindow() public {\n        emit A(1);\n        emit C(3);\n        emit E(5);\n        this.emitWindow();\n    }\n\n    // Used to test matching of consecutive different events\n    // split across subtree calls.\n    function emitSplitWindow() public {\n        this.emitWindow();\n        this.emitWindow();\n    }\n\n    function emitWindowAndOnTest(ExpectEmitTest t) public {\n        this.emitWindow();\n        t.emitLocal();\n    }\n\n    /// Ref: issue #1214\n    function doesNothing() public pure {}\n\n    function changeThing(uint256 num) public {\n        thing = num;\n    }\n\n    /// Ref: issue #760\n    function emitSomethingElse(uint256 data) public {\n        emit SomethingElse(data);\n    }\n}\n\n/// Emulates `Emitter` in #760\ncontract LowLevelCaller {\n    function f() external {\n        (bool success,) = address(this).call(abi.encodeWithSignature(\"g()\"));\n        require(success, \"call failed\");\n    }\n\n    function g() public {}\n}\n\ncontract ExpectEmitTest is Test {\n    Emitter emitter;\n\n    event Something(uint256 indexed topic1, uint256 indexed topic2, uint256 indexed topic3, uint256 data);\n\n    event SomethingElse(uint256 indexed topic1);\n\n    event SomethingNonIndexed(uint256 data);\n\n    event A(uint256 indexed topic1);\n    event B(uint256 indexed topic1);\n    event C(uint256 indexed topic1);\n    event D(uint256 indexed topic1);\n    event E(uint256 indexed topic1);\n\n    function setUp() public {\n        emitter = new Emitter();\n    }\n\n    function emitLocal() public {\n        emit A(1);\n    }\n\n    /// The topics that are not checked are altered to be incorrect\n    /// compared to the reference.\n    function testExpectEmit(\n        bool checkTopic1,\n        bool checkTopic2,\n        bool checkTopic3,\n        bool checkData,\n        uint128 topic1,\n        uint128 topic2,\n        uint128 topic3,\n        uint128 data\n    ) public {\n        uint256 transformedTopic1 = checkTopic1 ? uint256(topic1) : uint256(topic1) + 1;\n        uint256 transformedTopic2 = checkTopic2 ? uint256(topic2) : uint256(topic2) + 1;\n        uint256 transformedTopic3 = checkTopic3 ? uint256(topic3) : uint256(topic3) + 1;\n        uint256 transformedData = checkData ? uint256(data) : uint256(data) + 1;\n\n        vm.expectEmit(checkTopic1, checkTopic2, checkTopic3, checkData);\n\n        emit Something(topic1, topic2, topic3, data);\n        emitter.emitEvent(transformedTopic1, transformedTopic2, transformedTopic3, transformedData);\n    }\n\n    /// The topics that are checked are altered to be incorrect\n    /// compared to the reference.\n    function testExpectEmitNested(\n        bool checkTopic1,\n        bool checkTopic2,\n        bool checkTopic3,\n        bool checkData,\n        uint128 topic1,\n        uint128 topic2,\n        uint128 topic3,\n        uint128 data\n    ) public {\n        Emitter inner = new Emitter();\n\n        uint256 transformedTopic1 = checkTopic1 ? uint256(topic1) : uint256(topic1) + 1;\n        uint256 transformedTopic2 = checkTopic2 ? uint256(topic2) : uint256(topic2) + 1;\n        uint256 transformedTopic3 = checkTopic3 ? uint256(topic3) : uint256(topic3) + 1;\n        uint256 transformedData = checkData ? uint256(data) : uint256(data) + 1;\n\n        vm.expectEmit(checkTopic1, checkTopic2, checkTopic3, checkData);\n\n        emit Something(topic1, topic2, topic3, data);\n        emitter.emitNested(inner, transformedTopic1, transformedTopic2, transformedTopic3, transformedData);\n    }\n\n    function testExpectEmitMultiple() public {\n        vm.expectEmit();\n        emit Something(1, 2, 3, 4);\n        vm.expectEmit();\n        emit Something(5, 6, 7, 8);\n\n        emitter.emitMultiple(\n            [uint256(1), uint256(5)], [uint256(2), uint256(6)], [uint256(3), uint256(7)], [uint256(4), uint256(8)]\n        );\n    }\n\n    function testExpectedEmitMultipleNested() public {\n        vm.expectEmit();\n        emit Something(1, 2, 3, 4);\n        vm.expectEmit();\n        emit Something(1, 2, 3, 4);\n\n        emitter.emitAndNest();\n    }\n\n    function testExpectEmitMultipleWithArgs() public {\n        vm.expectEmit(true, true, true, true);\n        emit Something(1, 2, 3, 4);\n        vm.expectEmit(true, true, true, true);\n        emit Something(5, 6, 7, 8);\n\n        emitter.emitMultiple(\n            [uint256(1), uint256(5)], [uint256(2), uint256(6)], [uint256(3), uint256(7)], [uint256(4), uint256(8)]\n        );\n    }\n\n    function testExpectEmitCanMatchWithoutExactOrder() public {\n        vm.expectEmit(true, true, true, true);\n        emit Something(1, 2, 3, 4);\n        vm.expectEmit(true, true, true, true);\n        emit Something(1, 2, 3, 4);\n\n        emitter.emitOutOfExactOrder();\n    }\n\n    function testExpectEmitCanMatchWithoutExactOrder2() public {\n        vm.expectEmit(true, true, true, true);\n        emit SomethingNonIndexed(1);\n        vm.expectEmit(true, true, true, true);\n        emit Something(1, 2, 3, 4);\n\n        emitter.emitOutOfExactOrder();\n    }\n\n    function testExpectEmitAddress() public {\n        vm.expectEmit(address(emitter));\n        emit Something(1, 2, 3, 4);\n\n        emitter.emitEvent(1, 2, 3, 4);\n    }\n\n    function testExpectEmitAddressWithArgs() public {\n        vm.expectEmit(true, true, true, true, address(emitter));\n        emit Something(1, 2, 3, 4);\n\n        emitter.emitEvent(1, 2, 3, 4);\n    }\n\n    function testCanDoStaticCall() public {\n        vm.expectEmit(true, true, true, true);\n        emit Something(emitter.getVar(), 2, 3, 4);\n\n        emitter.emitEvent(1, 2, 3, 4);\n    }\n\n    /// Tests for additive behavior.\n    // As long as we match the event we want in order, it doesn't matter which events are emitted afterwards.\n    function testAdditiveBehavior() public {\n        vm.expectEmit(true, true, true, true, address(emitter));\n        emit Something(1, 2, 3, 4);\n\n        emitter.emitMultiple(\n            [uint256(1), uint256(5)], [uint256(2), uint256(6)], [uint256(3), uint256(7)], [uint256(4), uint256(8)]\n        );\n    }\n\n    /// emitWindow() emits events A, B, C, D, E.\n    /// We should be able to match [A, B, C, D, E] in the correct order.\n    function testCanMatchConsecutiveEvents() public {\n        vm.expectEmit(true, false, false, true);\n        emit A(1);\n        vm.expectEmit(true, false, false, true);\n        emit B(2);\n        vm.expectEmit(true, false, false, true);\n        emit C(3);\n        vm.expectEmit(true, false, false, true);\n        emit D(4);\n        vm.expectEmit(true, false, false, true);\n        emit E(5);\n\n        emitter.emitWindow();\n    }\n\n    /// emitWindow() emits events A, B, C, D, E.\n    /// We should be able to match [A, C, E], as they're in the right order,\n    /// even if they're not consecutive.\n    function testCanMatchConsecutiveEventsSkipped() public {\n        vm.expectEmit(true, false, false, true);\n        emit A(1);\n        vm.expectEmit(true, false, false, true);\n        emit C(3);\n        vm.expectEmit(true, false, false, true);\n        emit E(5);\n\n        emitter.emitWindow();\n    }\n\n    /// emitWindow() emits events A, B, C, D, E.\n    /// We should be able to match [C, E], as they're in the right order,\n    /// even if they're not consecutive.\n    function testCanMatchConsecutiveEventsSkipped2() public {\n        vm.expectEmit(true, false, false, true);\n        emit C(3);\n        vm.expectEmit(true, false, false, true);\n        emit E(5);\n\n        emitter.emitWindow();\n    }\n\n    /// emitWindow() emits events A, B, C, D, E.\n    /// We should be able to match [C], as it's contained in the events emitted,\n    /// even if we don't match the previous or following ones.\n    function testCanMatchSingleEventFromConsecutive() public {\n        vm.expectEmit(true, false, false, true);\n        emit C(3);\n\n        emitter.emitWindow();\n    }\n\n    /// emitWindowNested() emits events A, C, E, A, B, C, D, E, the last 5 on an external call.\n    /// We should be able to match the whole event sequence in order no matter if the events\n    /// were emitted deeper into the call tree.\n    function testCanMatchConsecutiveNestedEvents() public {\n        vm.expectEmit(true, false, false, true);\n        emit A(1);\n        vm.expectEmit(true, false, false, true);\n        emit C(3);\n        vm.expectEmit(true, false, false, true);\n        emit E(5);\n        vm.expectEmit(true, false, false, true);\n        emit A(1);\n        vm.expectEmit(true, false, false, true);\n        emit B(2);\n        vm.expectEmit(true, false, false, true);\n        emit C(3);\n        vm.expectEmit(true, false, false, true);\n        emit D(4);\n        vm.expectEmit(true, false, false, true);\n        emit E(5);\n\n        emitter.emitNestedWindow();\n    }\n\n    /// emitSplitWindow() emits events [[A, B, C, D, E], [A, B, C, D, E]]. Essentially, in an external call,\n    /// it emits the sequence of events twice at the same depth.\n    /// We should be able to match [A, A, B, C, D, E] as it's all in the next call, no matter\n    /// if they're emitted on subcalls at the same depth (but with correct ordering).\n    function testCanMatchConsecutiveSubtreeEvents() public {\n        vm.expectEmit(true, false, false, true);\n        emit A(1);\n        vm.expectEmit(true, false, false, true);\n        emit A(1);\n        vm.expectEmit(true, false, false, true);\n        emit B(2);\n        vm.expectEmit(true, false, false, true);\n        emit C(3);\n        vm.expectEmit(true, false, false, true);\n        emit D(4);\n        vm.expectEmit(true, false, false, true);\n        emit E(5);\n\n        emitter.emitSplitWindow();\n    }\n\n    /// emitWindowNested() emits events A, C, E, A, B, C, D, E, the last 5 on an external call.\n    /// We should be able to match [A, C, E, A, C, E] in that order, as these are emitted twice.\n    function testCanMatchRepeatedEvents() public {\n        vm.expectEmit(true, false, false, true);\n        emit A(1);\n        vm.expectEmit(true, false, false, true);\n        emit C(3);\n        vm.expectEmit(true, false, false, true);\n        emit E(5);\n        vm.expectEmit(true, false, false, true);\n        emit A(1);\n        vm.expectEmit(true, false, false, true);\n        emit C(3);\n        vm.expectEmit(true, false, false, true);\n        emit E(5);\n\n        emitter.emitNestedWindow();\n    }\n\n    /// emitWindowAndOnTest emits [[A, B, C, D, E], [A]]. The interesting bit is that the\n    /// second call that emits [A] is on this same contract. We should still be able to match\n    /// [A, A] as the call made to this contract is still external.\n    function testEmitWindowAndOnTest() public {\n        vm.expectEmit(true, false, false, true);\n        emit A(1);\n        vm.expectEmit(true, false, false, true);\n        emit A(1);\n        emitter.emitWindowAndOnTest(this);\n    }\n\n    /// This test will fail if we check that all expected logs were emitted\n    /// after every call from the same depth as the call that invoked the cheatcode.\n    ///\n    /// Expected emits should only be checked when the call from which the cheatcode\n    /// was invoked ends.\n    ///\n    /// Ref: issue #1214\n    /// NOTE: This is now invalid behavior.\n    // function testExpectEmitIsCheckedWhenCurrentCallTerminates() public {\n    //     vm.expectEmit(true, true, true, true);\n    //     emitter.doesNothing();\n    //     emit Something(1, 2, 3, 4);\n    //\n    //     // This should fail since `SomethingElse` in the test\n    //     // and in the `Emitter` contract have differing\n    //     // amounts of indexed topics.\n    //     emitter.emitEvent(1, 2, 3, 4);\n    // }\n}\n\ncontract ExpectEmitCountTest is Test {\n    Emitter emitter;\n\n    event Something(uint256 indexed topic1, uint256 indexed topic2, uint256 indexed topic3, uint256 data);\n\n    function setUp() public {\n        emitter = new Emitter();\n    }\n\n    function testCountNoEmit() public {\n        vm.expectEmit(0);\n        emit Something(1, 2, 3, 4);\n        emitter.doesNothing();\n    }\n\n    function testCountNEmits() public {\n        uint64 count = 2;\n        vm.expectEmit(count);\n        emit Something(1, 2, 3, 4);\n        emitter.emitNEvents(1, 2, 3, 4, count);\n    }\n\n    function testCountMoreEmits() public {\n        uint64 count = 2;\n        vm.expectEmit(count);\n        emit Something(1, 2, 3, 4);\n        emitter.emitNEvents(1, 2, 3, 4, count + 1);\n    }\n\n    /// Test zero emits from a specific address (emitter).\n    function testCountNoEmitFromAddress() public {\n        vm.expectEmit(address(emitter), 0);\n        emit Something(1, 2, 3, 4);\n        emitter.doesNothing();\n    }\n\n    function testCountEmitsFromAddress() public {\n        uint64 count = 2;\n        vm.expectEmit(address(emitter), count);\n        emit Something(1, 2, 3, 4);\n        emitter.emitNEvents(1, 2, 3, 4, count);\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/ExpectRevert.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract Reverter {\n    error CustomError();\n\n    function revertWithMessage(string memory message) public pure {\n        revert(message);\n    }\n\n    function doNotRevert() public pure {}\n\n    function panic() public pure returns (uint256) {\n        return uint256(100) - uint256(101);\n    }\n\n    function revertWithCustomError() public pure {\n        revert CustomError();\n    }\n\n    function nestedRevert(Reverter inner, string memory message) public pure {\n        inner.revertWithMessage(message);\n    }\n\n    function callThenRevert(Dummy dummy, string memory message) public pure {\n        dummy.callMe();\n        revert(message);\n    }\n\n    function callThenNoRevert(Dummy dummy) public pure {\n        dummy.callMe();\n    }\n\n    function revertWithoutReason() public pure {\n        revert();\n    }\n}\n\ncontract ConstructorReverter {\n    constructor(string memory message) {\n        revert(message);\n    }\n}\n\n/// Used to ensure that the dummy data from `vm.expectRevert`\n/// is large enough to decode big structs.\n///\n/// The struct is based on issue #2454\nstruct LargeDummyStruct {\n    address a;\n    uint256 b;\n    bool c;\n    address d;\n    address e;\n    string f;\n    address[8] g;\n    address h;\n    uint256 i;\n}\n\ncontract Dummy {\n    function callMe() public pure returns (string memory) {\n        return \"thanks for calling\";\n    }\n\n    function largeReturnType() public pure returns (LargeDummyStruct memory) {\n        revert(\"reverted with large return type\");\n    }\n}\n\ncontract ExpectRevertTest is Test {\n    function shouldRevert() internal {\n        revert();\n    }\n\n    function testExpectRevertString() public {\n        Reverter reverter = new Reverter();\n        vm.expectRevert(\"revert\");\n        reverter.revertWithMessage(\"revert\");\n    }\n\n    function testExpectRevertWithEncodedErrorPrefix() public {\n        Reverter reverter = new Reverter();\n        vm.expectRevert(abi.encodeWithSignature(\"Error(string)\", \"my revert reason\"));\n        reverter.revertWithMessage(\"my revert reason\");\n\n        vm.expectRevert(abi.encodeWithSignature(\"Error(string)\", \"A\"));\n        reverter.revertWithMessage(\"A\");\n\n        vm.expectRevert(abi.encodeWithSignature(\"Error(string)\", \"revert: A\"));\n        reverter.revertWithMessage(\"revert: A\");\n    }\n\n    function testExpectRevertConstructor() public {\n        vm.expectRevert(\"constructor revert\");\n        new ConstructorReverter(\"constructor revert\");\n    }\n\n    function testExpectRevertBuiltin() public {\n        Reverter reverter = new Reverter();\n        vm.expectRevert(abi.encodeWithSignature(\"Panic(uint256)\", 0x11));\n        reverter.panic();\n    }\n\n    function testExpectRevertCustomError() public {\n        Reverter reverter = new Reverter();\n        vm.expectRevert(abi.encodePacked(Reverter.CustomError.selector));\n        reverter.revertWithCustomError();\n    }\n\n    function testExpectRevertNested() public {\n        Reverter reverter = new Reverter();\n        Reverter inner = new Reverter();\n        vm.expectRevert(\"nested revert\");\n        reverter.nestedRevert(inner, \"nested revert\");\n    }\n\n    function testExpectRevertCallsThenReverts() public {\n        Reverter reverter = new Reverter();\n        Dummy dummy = new Dummy();\n        vm.expectRevert(\"called a function and then reverted\");\n        reverter.callThenRevert(dummy, \"called a function and then reverted\");\n    }\n\n    function testDummyReturnDataForBigType() public {\n        Dummy dummy = new Dummy();\n        vm.expectRevert(\"reverted with large return type\");\n        dummy.largeReturnType();\n    }\n\n    function testExpectRevertNoReason() public {\n        Reverter reverter = new Reverter();\n        vm.expectRevert(bytes(\"\"));\n        reverter.revertWithoutReason();\n    }\n\n    function testExpectRevertAnyRevert() public {\n        vm.expectRevert();\n        new ConstructorReverter(\"hello this is a revert message\");\n\n        Reverter reverter = new Reverter();\n        vm.expectRevert();\n        reverter.revertWithMessage(\"this is also a revert message\");\n\n        vm.expectRevert();\n        reverter.panic();\n\n        vm.expectRevert();\n        reverter.revertWithCustomError();\n\n        Reverter reverter2 = new Reverter();\n        vm.expectRevert();\n        reverter.nestedRevert(reverter2, \"this too is a revert message\");\n\n        Dummy dummy = new Dummy();\n        vm.expectRevert();\n        reverter.callThenRevert(dummy, \"revert message 4 i ran out of synonims for also\");\n\n        vm.expectRevert();\n        reverter.revertWithoutReason();\n    }\n\n    function testexpectCheatcodeRevert() public {\n        vm._expectCheatcodeRevert('JSON value at \".a\" is not an object');\n        vm.parseJsonKeys('{\"a\": \"b\"}', \".a\");\n    }\n}\n\ncontract AContract {\n    BContract bContract;\n    CContract cContract;\n\n    constructor(BContract _bContract, CContract _cContract) {\n        bContract = _bContract;\n        cContract = _cContract;\n    }\n\n    function callAndRevert() public pure {\n        require(1 > 2, \"Reverted by AContract\");\n    }\n\n    function callAndRevertInBContract() public {\n        bContract.callAndRevert();\n    }\n\n    function callAndRevertInCContract() public {\n        cContract.callAndRevert();\n    }\n\n    function callAndRevertInCContractThroughBContract() public {\n        bContract.callAndRevertInCContract();\n    }\n\n    function createDContract() public {\n        new DContract();\n    }\n\n    function createDContractThroughBContract() public {\n        bContract.createDContract();\n    }\n\n    function createDContractThroughCContract() public {\n        cContract.createDContract();\n    }\n\n    function doNotRevert() public {}\n}\n\ncontract BContract {\n    CContract cContract;\n\n    constructor(CContract _cContract) {\n        cContract = _cContract;\n    }\n\n    function callAndRevert() public pure {\n        require(1 > 2, \"Reverted by BContract\");\n    }\n\n    function callAndRevertInCContract() public {\n        this.doNotRevert();\n        cContract.doNotRevert();\n        cContract.callAndRevert();\n    }\n\n    function createDContract() public {\n        this.doNotRevert();\n        cContract.doNotRevert();\n        new DContract();\n    }\n\n    function createDContractThroughCContract() public {\n        this.doNotRevert();\n        cContract.doNotRevert();\n        cContract.createDContract();\n    }\n\n    function doNotRevert() public {}\n}\n\ncontract CContract {\n    error CContractError(string reason);\n\n    function callAndRevert() public pure {\n        revert CContractError(\"Reverted by CContract\");\n    }\n\n    function createDContract() public {\n        new DContract();\n    }\n\n    function doNotRevert() public {}\n}\n\ncontract DContract {\n    constructor() {\n        require(1 > 2, \"Reverted by DContract\");\n    }\n}\n\ncontract ExpectRevertWithReverterTest is Test {\n    error CContractError(string reason);\n\n    AContract aContract;\n    BContract bContract;\n    CContract cContract;\n\n    function setUp() public {\n        cContract = new CContract();\n        bContract = new BContract(cContract);\n        aContract = new AContract(bContract, cContract);\n    }\n\n    function testExpectRevertsWithReverter() public {\n        // Test expect revert with reverter at first call.\n        vm.expectRevert(address(aContract));\n        aContract.callAndRevert();\n        // Test expect revert with reverter at second subcall.\n        vm.expectRevert(address(bContract));\n        aContract.callAndRevertInBContract();\n        // Test expect revert with partial data match and reverter at third subcall.\n        vm.expectPartialRevert(CContractError.selector, address(cContract));\n        aContract.callAndRevertInCContractThroughBContract();\n        // Test expect revert with exact data match and reverter at second subcall.\n        vm.expectRevert(abi.encodeWithSelector(CContractError.selector, \"Reverted by CContract\"), address(cContract));\n        aContract.callAndRevertInCContract();\n    }\n\n    function testExpectRevertsWithReverterInConstructor() public {\n        // Test expect revert with reverter when constructor reverts.\n        vm.expectRevert(abi.encodePacked(\"Reverted by DContract\"), address(cContract));\n        cContract.createDContract();\n\n        vm.expectRevert(address(bContract));\n        bContract.createDContract();\n        vm.expectRevert(address(cContract));\n        bContract.createDContractThroughCContract();\n\n        vm.expectRevert(address(aContract));\n        aContract.createDContract();\n        vm.expectRevert(address(bContract));\n        aContract.createDContractThroughBContract();\n        vm.expectRevert(address(cContract));\n        aContract.createDContractThroughCContract();\n    }\n}\n\ncontract ExpectRevertCount is Test {\n    function testRevertCountAny() public {\n        uint64 count = 3;\n        Reverter reverter = new Reverter();\n        vm.expectRevert(count);\n        reverter.revertWithMessage(\"revert\");\n        reverter.revertWithMessage(\"revert2\");\n        reverter.revertWithMessage(\"revert3\");\n\n        vm.expectRevert(\"revert\");\n        reverter.revertWithMessage(\"revert\");\n    }\n\n    function testNoRevert() public {\n        uint64 count = 0;\n        Reverter reverter = new Reverter();\n        vm.expectRevert(count);\n        reverter.doNotRevert();\n    }\n\n    function testRevertCountSpecific() public {\n        uint64 count = 2;\n        Reverter reverter = new Reverter();\n        vm.expectRevert(\"revert\", count);\n        reverter.revertWithMessage(\"revert\");\n        reverter.revertWithMessage(\"revert\");\n    }\n\n    function testNoRevertSpecific() public {\n        uint64 count = 0;\n        Reverter reverter = new Reverter();\n        vm.expectRevert(\"revert\", count);\n        reverter.doNotRevert();\n    }\n\n    function testRevertCountWithConstructor() public {\n        uint64 count = 1;\n        vm.expectRevert(\"constructor revert\", count);\n        new ConstructorReverter(\"constructor revert\");\n    }\n\n    function testNoRevertWithConstructor() public {\n        uint64 count = 0;\n        vm.expectRevert(\"constructor revert\", count);\n        new CContract();\n    }\n\n    function testRevertCountNestedSpecific() public {\n        uint64 count = 2;\n        Reverter reverter = new Reverter();\n        Reverter inner = new Reverter();\n\n        vm.expectRevert(\"nested revert\", count);\n        reverter.revertWithMessage(\"nested revert\");\n        reverter.nestedRevert(inner, \"nested revert\");\n\n        vm.expectRevert(\"nested revert\", count);\n        reverter.nestedRevert(inner, \"nested revert\");\n        reverter.nestedRevert(inner, \"nested revert\");\n    }\n\n    function testRevertCountCallsThenReverts() public {\n        uint64 count = 2;\n        Reverter reverter = new Reverter();\n        Dummy dummy = new Dummy();\n\n        vm.expectRevert(\"called a function and then reverted\", count);\n        reverter.callThenRevert(dummy, \"called a function and then reverted\");\n        reverter.callThenRevert(dummy, \"called a function and then reverted\");\n    }\n\n    function testNoRevertCall() public {\n        uint64 count = 0;\n        Reverter reverter = new Reverter();\n        Dummy dummy = new Dummy();\n\n        vm.expectRevert(\"called a function and then reverted\", count);\n        reverter.callThenNoRevert(dummy);\n    }\n}\n\ncontract ExpectRevertCountWithReverter is Test {\n    function testRevertCountWithReverter() public {\n        uint64 count = 2;\n        Reverter reverter = new Reverter();\n        vm.expectRevert(address(reverter), count);\n        reverter.revertWithMessage(\"revert\");\n        reverter.revertWithMessage(\"revert\");\n    }\n\n    function testNoRevertWithReverter() public {\n        uint64 count = 0;\n        Reverter reverter = new Reverter();\n        vm.expectRevert(address(reverter), count);\n        reverter.doNotRevert();\n    }\n\n    function testReverterCountWithData() public {\n        uint64 count = 2;\n        Reverter reverter = new Reverter();\n        vm.expectRevert(\"revert\", address(reverter), count);\n        reverter.revertWithMessage(\"revert\");\n        reverter.revertWithMessage(\"revert\");\n    }\n}\n\ncontract ExpectRevertPrecompileTest is Test {\n    /// Test that vm.expectRevert works when the next external call targets a\n    /// precompile address directly. Precompile calls don't create an interpreter\n    /// frame (no `initialize_interp`), so depth tracking must account for them.\n    function testExpectRevertDirectPrecompileCall() public {\n        // BLAKE2F precompile (0x09) expects exactly 213 bytes of input.\n        // Calling it with invalid input reverts.\n        vm.expectRevert();\n        address(0x09).call(hex\"00\");\n    }\n}\n\ncontract ExpectRevertWithErrorTest is Test {\n    /// Ref: <https://github.com/foundry-rs/foundry/issues/12511>\n    function test_f() external {\n        bytes memory v = abi.encodeWithSignature(\"Error(string)\", \"\");\n        vm.expectRevert(v);\n        this.f(v);\n\n        bytes memory v1 = abi.encodeWithSignature(\"Error(string)\", unicode\"🙀\");\n        vm.expectRevert(v1);\n        this.f(v1);\n    }\n\n    function f(bytes memory v) external pure {\n        assembly {\n            revert(add(v, 32), mload(v))\n        }\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/Fee.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract FeeTest is Test {\n    function testFee() public {\n        vm.fee(10);\n        assertEq(block.basefee, 10, \"fee failed\");\n    }\n\n    function testFeeFuzzed(uint64 fee) public {\n        vm.fee(fee);\n        assertEq(block.basefee, fee, \"fee failed\");\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/Ffi.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract FfiTest is Test {\n    function testFfi() public {\n        string[] memory inputs = new string[](3);\n        inputs[0] = \"bash\";\n        inputs[1] = \"-c\";\n        inputs[2] =\n            \"echo -n 0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000966666920776f726b730000000000000000000000000000000000000000000000\";\n\n        bytes memory res = vm.ffi(inputs);\n        (string memory output) = abi.decode(res, (string));\n        assertEq(output, \"ffi works\", \"ffi failed\");\n    }\n\n    function testFfiString() public {\n        string[] memory inputs = new string[](3);\n        inputs[0] = \"echo\";\n        inputs[1] = \"-n\";\n        inputs[2] = \"gm\";\n\n        bytes memory res = vm.ffi(inputs);\n        assertEq(string(res), \"gm\");\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/Fork.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ninterface IWETH {\n    function deposit() external payable;\n    function balanceOf(address) external view returns (uint256);\n}\n\ncontract ForkTest is Test {\n    address constant WETH_TOKEN_ADDR = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;\n    uint256 constant mainblock = 14_608_400;\n\n    IWETH WETH = IWETH(WETH_TOKEN_ADDR);\n\n    uint256 forkA;\n    uint256 forkB;\n\n    uint256 testValue;\n\n    // this will create two _different_ forks during setup\n    function setUp() public {\n        forkA = vm.createFork(\"mainnet\", mainblock);\n        forkB = vm.createFork(\"mainnet2\", mainblock - 1);\n        testValue = 999;\n    }\n\n    // ensures forks use different ids\n    function testForkIdDiffer() public {\n        assert(forkA != forkB);\n    }\n\n    // ensures we can create and select in one step\n    function testCreateSelect() public {\n        uint256 fork = vm.createSelectFork(\"mainnet\");\n        assertEq(fork, vm.activeFork());\n    }\n\n    // ensures forks use different ids\n    function testCanSwitchForks() public {\n        vm.selectFork(forkA);\n        vm.selectFork(forkB);\n        vm.selectFork(forkB);\n        vm.selectFork(forkA);\n    }\n\n    function testForksHaveSeparatedStorage() public {\n        vm.selectFork(forkA);\n        // read state from forkA\n        assert(WETH.balanceOf(0x0000000000000000000000000000000000000000) != 1);\n\n        vm.selectFork(forkB);\n        // read state from forkB\n        uint256 forkBbalance = WETH.balanceOf(0x0000000000000000000000000000000000000000);\n        assert(forkBbalance != 1);\n\n        vm.selectFork(forkA);\n\n        // modify state\n        bytes32 value = bytes32(uint256(1));\n        // \"0x3617319a054d772f909f7c479a2cebe5066e836a939412e32403c99029b92eff\" is the slot storing the balance of zero address for the weth contract\n        // `cast index address uint 0x0000000000000000000000000000000000000000 3`\n        bytes32 zero_address_balance_slot = 0x3617319a054d772f909f7c479a2cebe5066e836a939412e32403c99029b92eff;\n        vm.store(WETH_TOKEN_ADDR, zero_address_balance_slot, value);\n        assertEq(\n            WETH.balanceOf(0x0000000000000000000000000000000000000000),\n            1,\n            \"Cheatcode did not change value at the storage slot.\"\n        );\n\n        // switch forks and ensure the balance on forkB remains untouched\n        vm.selectFork(forkB);\n        assert(forkBbalance != 1);\n        // balance of forkB is untouched\n        assertEq(\n            WETH.balanceOf(0x0000000000000000000000000000000000000000),\n            forkBbalance,\n            \"Cheatcode did not change value at the storage slot.\"\n        );\n    }\n\n    function testCanShareDataAcrossSwaps() public {\n        assertEq(testValue, 999);\n\n        uint256 val = 300;\n        vm.selectFork(forkA);\n        assertEq(val, 300);\n\n        testValue = 100;\n\n        vm.selectFork(forkB);\n        assertEq(val, 300);\n        assertEq(testValue, 100);\n\n        val = 99;\n        testValue = 300;\n\n        vm.selectFork(forkA);\n        assertEq(val, 99);\n        assertEq(testValue, 300);\n    }\n\n    // ensures forks use different ids\n    function testCanChangeChainId() public {\n        vm.selectFork(forkA);\n        uint256 newChainId = 1337;\n        vm.chainId(newChainId);\n        uint256 expected = block.chainid;\n        assertEq(newChainId, expected);\n    }\n\n    // ensures forks change chain ids automatically\n    function testCanAutoUpdateChainId() public {\n        vm.createSelectFork(\"sepolia\");\n        assertEq(block.chainid, 11155111);\n    }\n\n    // ensures forks storage is cached at block\n    function testStorageCaching() public {\n        vm.createSelectFork(\"mainnet\", 19800000);\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/Fork2.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\nstruct MyStruct {\n    uint256 value;\n}\n\ncontract MyContract {\n    uint256 forkId;\n    bytes32 blockHash;\n\n    constructor(uint256 _forkId) {\n        forkId = _forkId;\n        blockHash = blockhash(block.number - 1);\n    }\n\n    function ensureForkId(uint256 _forkId) public view {\n        require(forkId == _forkId, \"ForkId does not match\");\n    }\n\n    function ensureBlockHash() public view {\n        require(blockhash(block.number - 1) == blockHash, \"Block Hash does not match\");\n    }\n}\n\ncontract ForkTest is Test {\n    uint256 mainnetFork;\n    uint256 optimismFork;\n\n    // this will create two _different_ forks during setup\n    function setUp() public {\n        mainnetFork = vm.createFork(\"mainnet\");\n        optimismFork = vm.createFork(\"optimism\");\n    }\n\n    // ensures forks use different ids\n    function testForkIdDiffer() public {\n        assert(mainnetFork != optimismFork);\n    }\n\n    // ensures forks use different ids\n    function testCanSwitchForks() public {\n        vm.selectFork(mainnetFork);\n        assertEq(mainnetFork, vm.activeFork());\n        vm.selectFork(optimismFork);\n        assertEq(optimismFork, vm.activeFork());\n        vm.selectFork(optimismFork);\n        assertEq(optimismFork, vm.activeFork());\n        vm.selectFork(mainnetFork);\n        assertEq(mainnetFork, vm.activeFork());\n    }\n\n    function testCanCreateSelect() public {\n        uint256 anotherFork = vm.createSelectFork(\"mainnet\");\n        assertEq(anotherFork, vm.activeFork());\n    }\n\n    // ensures forks have different block hashes\n    function testBlockNumbersMismatch() public {\n        vm.selectFork(mainnetFork);\n        uint256 num = block.number;\n        bytes32 mainHash = blockhash(block.number - 1);\n        vm.selectFork(optimismFork);\n        uint256 num2 = block.number;\n        bytes32 optimismHash = blockhash(block.number - 1);\n        assert(mainHash != optimismHash);\n    }\n\n    // test that we can switch between forks, and \"roll\" blocks\n    function testCanRollFork() public {\n        vm.selectFork(mainnetFork);\n        uint256 otherMain = vm.createFork(\"mainnet\", block.number - 1);\n        vm.selectFork(otherMain);\n        uint256 mainBlock = block.number;\n\n        uint256 forkedBlock = 14608400;\n        uint256 otherFork = vm.createFork(\"mainnet\", forkedBlock);\n        vm.selectFork(otherFork);\n        assertEq(block.number, forkedBlock);\n\n        vm.rollFork(forkedBlock + 1);\n        assertEq(block.number, forkedBlock + 1);\n\n        // can also roll by id\n        vm.rollFork(otherMain, mainBlock + 1);\n        assertEq(block.number, forkedBlock + 1);\n\n        vm.selectFork(otherMain);\n        assertEq(block.number, mainBlock + 1);\n    }\n\n    // test that we can \"roll\" blocks until a transaction\n    function testCanRollForkUntilTransaction() public {\n        // block to run transactions from\n        uint256 blockNumber = 16261704;\n\n        // fork until previous block\n        uint256 fork = vm.createSelectFork(\"mainnet\", blockNumber - 1);\n\n        // block transactions in order: https://beaconcha.in/block/16261704#transactions\n        // run transactions from current block until tx\n        bytes32 transaction = 0x67cbad73764049e228495a3f90144aab4a37cb4b5fd697dffc234aa5ed811ace;\n\n        // account that sends ether in 2 transaction before tx\n        address account = 0xAe45a8240147E6179ec7c9f92c5A18F9a97B3fCA;\n\n        assertEq(account.balance, 275780074926400862972);\n\n        // transfer: 0.00275 ether (0.00095 + 0.0018)\n        // transaction 1: https://etherscan.io/tx/0xc51739580cf4cd2155cb171afa56ce314168eee3b5d59faefc3ceb9cacee46da\n        // transaction 2: https://etherscan.io/tx/0x3777bf87e91bcbb0f976f1df47a7678cea6d6e29996894293a6d1fad80233c28\n        uint256 transferAmount = 950391156965212 + 1822824618180000;\n        uint256 newBalance = account.balance - transferAmount;\n\n        // execute transactions in block until tx\n        vm.rollFork(transaction);\n\n        // balance must be less than newBalance due to gas spent\n        assert(account.balance < newBalance);\n    }\n\n    /// checks that marking as persistent works\n    function testMarkPersistent() public {\n        assert(vm.isPersistent(address(this)));\n\n        vm.selectFork(mainnetFork);\n\n        DummyContract dummy = new DummyContract();\n        assert(!vm.isPersistent(address(dummy)));\n\n        uint256 expectedValue = 99;\n        dummy.set(expectedValue);\n\n        vm.selectFork(optimismFork);\n\n        vm.selectFork(mainnetFork);\n        assertEq(dummy.val(), expectedValue);\n        vm.makePersistent(address(dummy));\n        assert(vm.isPersistent(address(dummy)));\n\n        vm.selectFork(optimismFork);\n        // the account is now marked as persistent and the contract is persistent across swaps\n        dummy.hello();\n        assertEq(dummy.val(), expectedValue);\n    }\n\n    /// forge-config: default.allow_internal_expect_revert = true\n    function testNonExistingContractRevert() public {\n        vm.selectFork(mainnetFork);\n        DummyContract dummy = new DummyContract();\n\n        // this will succeed since `dummy` is deployed on the currently active fork\n        string memory message = dummy.hello();\n\n        address dummyAddress = address(dummy);\n\n        vm.selectFork(optimismFork);\n        assertEq(dummyAddress, address(dummy));\n\n        // this will revert since `dummy` does not exists on the currently active fork\n        vm.expectRevert();\n        dummy.noop();\n    }\n\n    struct EthGetLogsJsonParseable {\n        bytes32 blockHash;\n        bytes blockNumber; // Should be uint256, but is returned from RPC in 0x... format\n        bytes32 data; // Should be bytes, but in our particular example is bytes32\n        address emitter;\n        bytes logIndex; // Should be uint256, but is returned from RPC in 0x... format\n        bool removed;\n        bytes32[] topics;\n        bytes32 transactionHash;\n        bytes transactionIndex; // Should be uint256, but is returned from RPC in 0x... format\n    }\n\n    function testEthGetLogs() public {\n        vm.selectFork(mainnetFork);\n        address weth = address(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);\n        bytes32 withdrawalTopic = 0x7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65;\n        uint256 blockNumber = 17623835;\n\n        string memory path = \"fixtures/Rpc/eth_getLogs.json\";\n        string memory file = vm.readFile(path);\n        bytes memory parsed = vm.parseJson(file);\n        EthGetLogsJsonParseable[] memory fixtureLogs = abi.decode(parsed, (EthGetLogsJsonParseable[]));\n\n        bytes32[] memory topics = new bytes32[](1);\n        topics[0] = withdrawalTopic;\n        Vm.EthGetLogs[] memory logs = vm.eth_getLogs(blockNumber, blockNumber, weth, topics);\n        assertEq(logs.length, 3);\n\n        for (uint256 i = 0; i < logs.length; i++) {\n            Vm.EthGetLogs memory log = logs[i];\n            assertEq(log.emitter, fixtureLogs[i].emitter);\n\n            string memory i_str;\n            if (i == 0) i_str = \"0\";\n            if (i == 1) i_str = \"1\";\n            if (i == 2) i_str = \"2\";\n\n            assertEq(log.blockNumber, vm.parseJsonUint(file, string.concat(\"[\", i_str, \"].blockNumber\")));\n            assertEq(log.logIndex, vm.parseJsonUint(file, string.concat(\"[\", i_str, \"].logIndex\")));\n            assertEq(log.transactionIndex, vm.parseJsonUint(file, string.concat(\"[\", i_str, \"].transactionIndex\")));\n\n            assertEq(log.blockHash, fixtureLogs[i].blockHash);\n            assertEq(log.removed, fixtureLogs[i].removed);\n            assertEq(log.transactionHash, fixtureLogs[i].transactionHash);\n\n            // In this specific example, the log.data is bytes32\n            assertEq(bytes32(log.data), fixtureLogs[i].data);\n            assertEq(log.topics.length, 2);\n            assertEq(log.topics[0], withdrawalTopic);\n            assertEq(log.topics[1], fixtureLogs[i].topics[1]);\n        }\n    }\n\n    function testRpc() public {\n        // balance at block <https://etherscan.io/block/18332681>\n        vm.selectFork(mainnetFork);\n        string memory path = \"fixtures/Rpc/balance_params.json\";\n        string memory file = vm.readFile(path);\n        bytes memory result = vm.rpc(\"eth_getBalance\", file);\n        assertEq(hex\"10b7c11bcb51e6\", result);\n    }\n\n    function testRpcWithUrl() public {\n        bytes memory result = vm.rpc(\"mainnet\", \"eth_blockNumber\", \"[]\");\n        uint256 decodedResult = vm.parseUint(vm.toString(result));\n        assertGt(decodedResult, 20_000_000);\n    }\n\n    // <https://github.com/foundry-rs/foundry/issues/7858>\n    function testRpcTransactionByHash() public {\n        string memory param = string.concat('[\"0xe1a0fba63292976050b2fbf4379a1901691355ed138784b4e0d1854b4cf9193e\"]');\n        vm.rpc(\"sepolia\", \"eth_getTransactionByHash\", param);\n    }\n}\n\ncontract DummyContract {\n    uint256 public val;\n\n    function noop() external pure {}\n\n    function hello() external view returns (string memory) {\n        return \"hello\";\n    }\n\n    function set(uint256 _val) public {\n        val = _val;\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/Fs.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract FsTest is Test {\n    bytes constant FOUNDRY_TOML_ACCESS_ERR = \"access to foundry.toml is not allowed\";\n    bytes constant FOUNDRY_READ_ERR = \"the path /etc/hosts is not allowed to be accessed for read operations\";\n    bytes constant FOUNDRY_READ_DIR_ERR = \"the path /etc is not allowed to be accessed for read operations\";\n    bytes constant FOUNDRY_WRITE_ERR = \"the path /etc/hosts is not allowed to be accessed for write operations\";\n\n    function assertEntry(Vm.DirEntry memory entry, uint64 depth, bool dir) private {\n        assertEq(entry.errorMessage, \"\");\n        assertEq(entry.depth, depth);\n        assertEq(entry.isDir, dir);\n        assertEq(entry.isSymlink, false);\n    }\n\n    function testReadFile() public {\n        string memory path = \"fixtures/File/read.txt\";\n\n        assertEq(vm.readFile(path), \"hello readable world\\nthis is the second line!\");\n\n        vm._expectCheatcodeRevert(FOUNDRY_READ_ERR);\n        vm.readFile(\"/etc/hosts\");\n\n        vm._expectCheatcodeRevert(FOUNDRY_READ_ERR);\n        vm.readFileBinary(\"/etc/hosts\");\n    }\n\n    function testReadLine() public {\n        string memory path = \"fixtures/File/read.txt\";\n\n        assertEq(vm.readLine(path), \"hello readable world\");\n        assertEq(vm.readLine(path), \"this is the second line!\");\n        assertEq(vm.readLine(path), \"\");\n\n        vm._expectCheatcodeRevert(FOUNDRY_READ_ERR);\n        vm.readLine(\"/etc/hosts\");\n    }\n\n    function testWriteFile() public {\n        string memory path = \"fixtures/File/ignored/write_file.txt\";\n        string memory data = \"hello writable world\";\n        vm.writeFile(path, data);\n\n        assertEq(vm.readFile(path), data);\n\n        vm.removeFile(path);\n\n        vm._expectCheatcodeRevert(FOUNDRY_WRITE_ERR);\n        vm.writeFile(\"/etc/hosts\", \"malicious stuff\");\n        vm._expectCheatcodeRevert(FOUNDRY_WRITE_ERR);\n        vm.writeFileBinary(\"/etc/hosts\", \"malicious stuff\");\n    }\n\n    function testCopyFile() public {\n        string memory from = \"fixtures/File/read.txt\";\n        string memory to = \"fixtures/File/ignored/copy.txt\";\n        uint64 copied = vm.copyFile(from, to);\n        assertEq(vm.fsMetadata(to).length, uint256(copied));\n        assertEq(vm.readFile(from), vm.readFile(to));\n        vm.removeFile(to);\n    }\n\n    function testWriteLine() public {\n        string memory path = \"fixtures/File/ignored/write_line.txt\";\n\n        string memory line1 = \"first line\";\n        vm.writeLine(path, line1);\n\n        string memory line2 = \"second line\";\n        vm.writeLine(path, line2);\n\n        assertEq(vm.readFile(path), string.concat(line1, \"\\n\", line2, \"\\n\"));\n\n        vm.removeFile(path);\n\n        vm._expectCheatcodeRevert(FOUNDRY_WRITE_ERR);\n        vm.writeLine(\"/etc/hosts\", \"malicious stuff\");\n    }\n\n    function testCloseFile() public {\n        string memory path = \"fixtures/File/read.txt\";\n\n        assertEq(vm.readLine(path), \"hello readable world\");\n        vm.closeFile(path);\n        assertEq(vm.readLine(path), \"hello readable world\");\n    }\n\n    function testRemoveFile() public {\n        string memory path = \"fixtures/File/ignored/remove_file.txt\";\n        string memory data = \"hello writable world\";\n\n        vm.writeFile(path, data);\n        assertEq(vm.readLine(path), data);\n\n        vm.removeFile(path);\n        vm.writeLine(path, data);\n        assertEq(vm.readLine(path), data);\n\n        vm.removeFile(path);\n\n        vm._expectCheatcodeRevert(FOUNDRY_WRITE_ERR);\n        vm.removeFile(\"/etc/hosts\");\n    }\n\n    function testWriteLineFoundrytoml() public {\n        string memory root = vm.projectRoot();\n        string memory foundryToml = string.concat(root, \"/\", \"foundry.toml\");\n\n        vm._expectCheatcodeRevert();\n        vm.writeLine(foundryToml, \"\\nffi = true\\n\");\n\n        vm._expectCheatcodeRevert();\n        vm.writeLine(\"foundry.toml\", \"\\nffi = true\\n\");\n\n        vm._expectCheatcodeRevert();\n        vm.writeLine(\"./foundry.toml\", \"\\nffi = true\\n\");\n\n        vm._expectCheatcodeRevert();\n        vm.writeLine(\"./Foundry.toml\", \"\\nffi = true\\n\");\n    }\n\n    function testWriteFoundrytoml() public {\n        string memory root = vm.projectRoot();\n        string memory foundryToml = string.concat(root, \"/\", \"foundry.toml\");\n\n        vm._expectCheatcodeRevert();\n        vm.writeFile(foundryToml, \"\\nffi = true\\n\");\n\n        vm._expectCheatcodeRevert();\n        vm.writeFile(\"foundry.toml\", \"\\nffi = true\\n\");\n\n        vm._expectCheatcodeRevert();\n        vm.writeFile(\"./foundry.toml\", \"\\nffi = true\\n\");\n\n        vm._expectCheatcodeRevert();\n        vm.writeFile(\"./Foundry.toml\", \"\\nffi = true\\n\");\n    }\n\n    function testReadDir() public {\n        string memory path = \"fixtures/Dir\";\n\n        {\n            Vm.DirEntry[] memory entries = vm.readDir(path);\n            assertEq(entries.length, 2);\n            assertEntry(entries[0], 1, false);\n            assertEntry(entries[1], 1, true);\n\n            Vm.DirEntry[] memory entries2 = vm.readDir(path, 1);\n            assertEq(entries2.length, 2);\n            assertEq(entries[0].path, entries2[0].path);\n            assertEq(entries[1].path, entries2[1].path);\n\n            string memory contents = vm.readFile(entries[0].path);\n            assertEq(contents, unicode\"Wow! 😀\");\n        }\n\n        {\n            Vm.DirEntry[] memory entries = vm.readDir(path, 2);\n            assertEq(entries.length, 4);\n            assertEntry(entries[2], 2, false);\n            assertEntry(entries[3], 2, true);\n        }\n\n        {\n            Vm.DirEntry[] memory entries = vm.readDir(path, 3);\n            assertEq(entries.length, 5);\n            assertEntry(entries[4], 3, false);\n        }\n\n        vm._expectCheatcodeRevert(FOUNDRY_READ_DIR_ERR);\n        vm.readDir(\"/etc\");\n    }\n\n    function testCreateRemoveDir() public {\n        string memory path = \"fixtures/Dir/remove_dir\";\n        string memory child = string.concat(path, \"/child\");\n\n        vm.createDir(path, false);\n        assertEq(vm.fsMetadata(path).isDir, true);\n\n        vm.removeDir(path, false);\n        vm._expectCheatcodeRevert();\n        vm.fsMetadata(path);\n\n        // reverts because not recursive\n        vm._expectCheatcodeRevert();\n        vm.createDir(child, false);\n\n        vm.createDir(child, true);\n        assertEq(vm.fsMetadata(child).isDir, true);\n\n        // deleted both, recursively\n        vm.removeDir(path, true);\n        vm._expectCheatcodeRevert();\n        vm.fsMetadata(path);\n        vm._expectCheatcodeRevert();\n        vm.fsMetadata(child);\n    }\n\n    function testFsMetadata() public {\n        Vm.FsMetadata memory metadata = vm.fsMetadata(\"fixtures/File\");\n        assertEq(metadata.isDir, true);\n        assertEq(metadata.isSymlink, false);\n        assertEq(metadata.readOnly, false);\n        // These fields aren't available on all platforms, default to zero\n        // assertGt(metadata.length, 0);\n        // assertGt(metadata.modified, 0);\n        // assertGt(metadata.accessed, 0);\n        // assertGt(metadata.created, 0);\n\n        metadata = vm.fsMetadata(\"fixtures/File/read.txt\");\n        assertEq(metadata.isDir, false);\n        assertEq(metadata.isSymlink, false);\n        // This test will fail on windows if we compared to 45, as windows\n        // ends files with both line feed and carriage return, unlike\n        // unix which only uses the first one.\n        assertTrue(metadata.length == 45 || metadata.length == 46);\n\n        metadata = vm.fsMetadata(\"fixtures/File/symlink\");\n        assertEq(metadata.isDir, false);\n        // TODO: symlinks are canonicalized away in `ensure_path_allowed`\n        // assertEq(metadata.isSymlink, true);\n\n        vm._expectCheatcodeRevert();\n        vm.fsMetadata(\"../not-found\");\n\n        vm._expectCheatcodeRevert(FOUNDRY_READ_ERR);\n        vm.fsMetadata(\"/etc/hosts\");\n    }\n\n    function testExists() public {\n        string memory validFilePath = \"fixtures/File/read.txt\";\n        assertTrue(vm.exists(validFilePath));\n        assertTrue(vm.exists(validFilePath));\n\n        string memory validDirPath = \"fixtures/File\";\n        assertTrue(vm.exists(validDirPath));\n        assertTrue(vm.exists(validDirPath));\n\n        string memory invalidPath = \"fixtures/File/invalidfile.txt\";\n        assertTrue(vm.exists(invalidPath) == false);\n        assertTrue(vm.exists(invalidPath) == false);\n    }\n\n    function testIsFile() public {\n        string memory validFilePath = \"fixtures/File/read.txt\";\n        assertTrue(vm.isFile(validFilePath));\n        assertTrue(vm.isFile(validFilePath));\n\n        string memory invalidFilePath = \"fixtures/File/invalidfile.txt\";\n        assertTrue(vm.isFile(invalidFilePath) == false);\n        assertTrue(vm.isFile(invalidFilePath) == false);\n\n        string memory dirPath = \"fixtures/File\";\n        assertTrue(vm.isFile(dirPath) == false);\n        assertTrue(vm.isFile(dirPath) == false);\n    }\n\n    function testIsDir() public {\n        string memory validDirPath = \"fixtures/File\";\n        assertTrue(vm.isDir(validDirPath));\n        assertTrue(vm.isDir(validDirPath));\n\n        string memory invalidDirPath = \"fixtures/InvalidDir\";\n        assertTrue(vm.isDir(invalidDirPath) == false);\n        assertTrue(vm.isDir(invalidDirPath) == false);\n\n        string memory filePath = \"fixtures/File/read.txt\";\n        assertTrue(vm.isDir(filePath) == false);\n        assertTrue(vm.isDir(filePath) == false);\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/GasMetering.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract B {\n    function a() public returns (uint256) {\n        return 100;\n    }\n}\n\ncontract GasMeteringTest is Test {\n    function testGasMetering() public {\n        uint256 gas_start = gasleft();\n\n        consumeGas();\n\n        uint256 gas_end_normal = gas_start - gasleft();\n\n        vm.pauseGasMetering();\n        uint256 gas_start_not_metered = gasleft();\n\n        consumeGas();\n\n        uint256 gas_end_not_metered = gas_start_not_metered - gasleft();\n        vm.resumeGasMetering();\n\n        uint256 gas_start_metered = gasleft();\n\n        consumeGas();\n\n        uint256 gas_end_resume_metered = gas_start_metered - gasleft();\n\n        assertEq(gas_end_normal, gas_end_resume_metered);\n        assertEq(gas_end_not_metered, 0);\n    }\n\n    function testGasMeteringExternal() public {\n        B b = new B();\n\n        uint256 gas_start = gasleft();\n\n        b.a();\n\n        uint256 gas_end_normal = gas_start - gasleft();\n\n        vm.pauseGasMetering();\n        uint256 gas_start_not_metered = gasleft();\n\n        b.a();\n\n        uint256 gas_end_not_metered = gas_start_not_metered - gasleft();\n        vm.resumeGasMetering();\n\n        uint256 gas_start_metered = gasleft();\n\n        b.a();\n\n        uint256 gas_end_resume_metered = gas_start_metered - gasleft();\n\n        assertEq(gas_end_normal, gas_end_resume_metered);\n        assertEq(gas_end_not_metered, 0);\n    }\n\n    function testGasMeteringContractCreate() public {\n        vm.pauseGasMetering();\n        uint256 gas_start_not_metered = gasleft();\n\n        B b = new B();\n\n        uint256 gas_end_not_metered = gas_start_not_metered - gasleft();\n        vm.resumeGasMetering();\n\n        assertEq(gas_end_not_metered, 0);\n    }\n\n    function consumeGas() internal returns (uint256 x) {\n        for (uint256 i; i < 10000; i++) {\n            x += i;\n        }\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/GetArtifactPath.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity =0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract DummyForGetArtifactPath {}\n\ncontract GetArtifactPathTest is Test {\n    function testGetArtifactPathByCode() public {\n        bytes memory dummyCreationCode = type(DummyForGetArtifactPath).creationCode;\n\n        string memory path = vm.getArtifactPathByCode(dummyCreationCode);\n        assertTrue(vm.contains(path, \"/out/GetArtifactPath.t.sol/DummyForGetArtifactPath.json\"));\n    }\n\n    function testGetArtifactPathByDeployedCode() public {\n        DummyForGetArtifactPath dummy = new DummyForGetArtifactPath();\n        bytes memory dummyRuntimeCode = address(dummy).code;\n\n        string memory path = vm.getArtifactPathByDeployedCode(dummyRuntimeCode);\n        assertTrue(vm.contains(path, \"/out/GetArtifactPath.t.sol/DummyForGetArtifactPath.json\"));\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/GetBlockTimestamp.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract GetBlockTimestampTest is Test {\n    function testGetTimestamp() public {\n        uint256 timestamp = vm.getBlockTimestamp();\n        assertEq(timestamp, 1, \"timestamp should be 1\");\n    }\n\n    function testGetTimestampWithWarp() public {\n        assertEq(vm.getBlockTimestamp(), 1, \"timestamp should be 1\");\n        vm.warp(10);\n        assertEq(vm.getBlockTimestamp(), 10, \"warp failed\");\n    }\n\n    function testGetTimestampWithWarpFuzzed(uint32 jump) public {\n        uint256 pre = vm.getBlockTimestamp();\n        vm.warp(pre + jump);\n        assertEq(vm.getBlockTimestamp(), pre + jump, \"warp failed\");\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/GetChain.t.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.13;\n\nimport \"utils/Test.sol\";\n\ncontract GetChainTest is Test {\n    function testGetMainnet() public {\n        // Test mainnet\n        Vm.Chain memory mainnet = vm.getChain(\"mainnet\");\n        assertEq(mainnet.name, \"mainnet\");\n        assertEq(mainnet.chainId, 1);\n        assertEq(mainnet.chainAlias, \"mainnet\");\n    }\n\n    function testGetSepolia() public {\n        // Test Sepolia\n        Vm.Chain memory sepolia = vm.getChain(\"sepolia\");\n        assertEq(sepolia.name, \"sepolia\");\n        assertEq(sepolia.chainId, 11155111);\n        assertEq(sepolia.chainAlias, \"sepolia\");\n    }\n\n    function testGetOptimism() public {\n        // Test Optimism\n        Vm.Chain memory optimism = vm.getChain(\"optimism\");\n        assertEq(optimism.name, \"optimism\");\n        assertEq(optimism.chainId, 10);\n        assertEq(optimism.chainAlias, \"optimism\");\n    }\n\n    function testGetByChainId() public {\n        // Test getting a chain by its ID\n        vm._expectCheatcodeRevert(\"invalid chain alias:\");\n        Vm.Chain memory arbitrum = vm.getChain(\"42161222\");\n    }\n\n    function testEmptyAlias() public {\n        // Test empty string\n        vm._expectCheatcodeRevert(\"invalid chain alias:\");\n        vm.getChain(\"\");\n    }\n\n    function testInvalidAlias() public {\n        // Test invalid alias\n        vm._expectCheatcodeRevert(\"invalid chain alias: nonexistent_chain\");\n        vm.getChain(\"nonexistent_chain\");\n    }\n\n    // Tests for the numeric chainId version of getChain\n\n    function testGetMainnetById() public {\n        // Test mainnet using chain ID\n        Vm.Chain memory mainnet = vm.getChain(1);\n        assertEq(mainnet.name, \"mainnet\");\n        assertEq(mainnet.chainId, 1);\n        assertEq(mainnet.chainAlias, \"mainnet\");\n    }\n\n    function testGetSepoliaById() public {\n        // Test Sepolia using chain ID\n        Vm.Chain memory sepolia = vm.getChain(11155111);\n        assertEq(sepolia.name, \"sepolia\");\n        assertEq(sepolia.chainId, 11155111);\n        assertEq(sepolia.chainAlias, \"sepolia\");\n    }\n\n    function testGetOptimismById() public {\n        // Test Optimism using chain ID\n        Vm.Chain memory optimism = vm.getChain(10);\n        assertEq(optimism.name, \"optimism\");\n        assertEq(optimism.chainId, 10);\n        assertEq(optimism.chainAlias, \"optimism\");\n    }\n\n    function testGetBerachainById() public {\n        // Test Berachain using chain ID\n        Vm.Chain memory bera = vm.getChain(80094);\n        assertEq(bera.name, \"berachain\");\n        assertEq(bera.chainId, 80094);\n        // No rpc url configured, chain alias is the chain id.\n        assertEq(bera.chainAlias, \"80094\");\n    }\n\n    function testGetArbitrumById() public {\n        // Test Arbitrum using chain ID\n        Vm.Chain memory arbitrum = vm.getChain(42161);\n        assertEq(arbitrum.name, \"arbitrum\");\n        assertEq(arbitrum.chainId, 42161);\n        assertEq(arbitrum.chainAlias, \"arbitrum\");\n    }\n\n    function testInvalidChainId() public {\n        // Test invalid chain ID (using a value that's unlikely to be a valid chain)\n        vm._expectCheatcodeRevert(\"invalid chain alias: 12345678\");\n        vm.getChain(12345678);\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/GetCode.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity =0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract TestContract {}\n\ncontract TestContractGetCode {}\n\ncontract GetCodeTest is Test {\n    function testGetCode() public {\n        bytes memory fullPath = vm.getCode(\"fixtures/GetCode/WorkingContract.json\");\n        //bytes memory fileOnly = vm.getCode(\"WorkingContract.sol\");\n        //bytes memory fileAndContractName = vm.getCode(\"WorkingContract.sol:WorkingContract\");\n\n        string memory expected = string(\n            bytes(\n                hex\"6080604052348015600f57600080fd5b50607c8061001e6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063d1efd30d14602d575b600080fd5b6034602a81565b60405190815260200160405180910390f3fea26469706673582212206740fcc626175d58a151da7fbfca1775ea4d3ababf7f3168347dab89488f6a4264736f6c634300080a0033\"\n            )\n        );\n        assertEq(string(fullPath), expected, \"code for full path was incorrect\");\n        // TODO: Disabled until we figure out a way to get these variants of the\n        // cheatcode working during automated tests\n        //assertEq(\n        //    string(fileOnly),\n        //    expected,\n        //    \"code for file name only was incorrect\"\n        //);\n        //assertEq(\n        //    string(fileAndContractName),\n        //    expected,\n        //    \"code for full path was incorrect\"\n        //);\n    }\n\n    function testGetCodeHardhatArtifact() public {\n        bytes memory fullPath = vm.getCode(\"fixtures/GetCode/HardhatWorkingContract.json\");\n\n        string memory expected = string(\n            bytes(\n                hex\"608060405234801561001057600080fd5b5060b28061001f6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063d1efd30d14602d575b600080fd5b60336047565b604051603e91906059565b60405180910390f35b602a81565b6053816072565b82525050565b6000602082019050606c6000830184604c565b92915050565b600081905091905056fea26469706673582212202a44b7c3c3e248a5736aa9345986f7114ee9e00d36ea034566db99648a17870564736f6c63430008040033\"\n            )\n        );\n        assertEq(string(fullPath), expected, \"code for full path was incorrect\");\n    }\n\n    // TODO: Huff uses its own ABI.\n    /*\n    function testGetCodeHuffArtifact() public {\n        string memory path = \"fixtures/GetCode/HuffWorkingContract.json\";\n        bytes memory bytecode = vm.getCode(path);\n        string memory expected = string(\n            bytes(\n                hex\"602d8060093d393df33d3560e01c63d1efd30d14610012573d3dfd5b6f656d6f2e6574682077757a206865726560801b3d523d6020f3\"\n            )\n        );\n        assertEq(string(bytecode), expected, \"code for path was incorrect\");\n\n        // deploy the contract from the bytecode\n        address deployed;\n        assembly {\n            deployed := create(0, add(bytecode, 0x20), mload(bytecode))\n        }\n        // get the deployed code using the cheatcode\n        bytes memory deployedCode = vm.getDeployedCode(path);\n        // compare the loaded code to the actual deployed code\n        assertEq(string(deployedCode), string(deployed.code), \"deployedCode for path was incorrect\");\n    }\n    */\n\n    /// forge-config: default.allow_internal_expect_revert = true\n    function testRevertIfGetUnlinked() public {\n        vm.skip(true, \"artifacts are always linked now\");\n        vm.expectRevert(\"vm.getCode: no matching artifact found\");\n        vm.getCode(\"UnlinkedContract.sol\");\n    }\n\n    function testWithVersion() public {\n        bytes memory code = vm.getCode(\"cheats/GetCode.t.sol:TestContract:0.8.18\");\n        assertEq(type(TestContract).creationCode, code);\n\n        vm._expectCheatcodeRevert(\"no matching artifact found\");\n        vm.getCode(\"cheats/GetCode.t.sol:TestContract:0.8.19\");\n    }\n\n    function testByName() public {\n        bytes memory code = vm.getCode(\"TestContractGetCode\");\n        assertEq(type(TestContractGetCode).creationCode, code);\n    }\n\n    function testByNameAndVersion() public {\n        bytes memory code = vm.getCode(\"TestContractGetCode:0.8.18\");\n        assertEq(type(TestContractGetCode).creationCode, code);\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/GetDeployedCode.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity =0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract TestContract {}\n\ncontract GetDeployedCodeTest is Test {\n    address public constant overrideAddress = 0x0000000000000000000000000000000000000064;\n\n    event Payload(address sender, address target, bytes data);\n\n    function testGetCode() public {\n        bytes memory fullPath = vm.getDeployedCode(\"fixtures/GetCode/Override.json\");\n        string memory expected = string(\n            bytes(\n                hex\"60806040526004361061001e5760003560e01c806340e04f5e14610023575b600080fd5b610036610031366004610091565b610048565b60405190815260200160405180910390f35b60007fda9986ad4da7abb3f55b2d1f2009ab6ee50c5ad054092c04464c112acc4bc1103385858560405161007f9493929190610122565b60405180910390a15060009392505050565b6000806000604084860312156100a657600080fd5b83356001600160a01b03811681146100bd57600080fd5b9250602084013567ffffffffffffffff808211156100da57600080fd5b818601915086601f8301126100ee57600080fd5b8135818111156100fd57600080fd5b87602082850101111561010f57600080fd5b6020830194508093505050509250925092565b6001600160a01b0385811682528416602082015260606040820181905281018290526000828460808401376000608084840101526080601f19601f85011683010190509594505050505056fea26469706673582212202b0ba0fa4073d6f681bb1f99f0529e44583f2dc612a629f3ff0564eaa7257d1f64736f6c63430008110033\"\n            )\n        );\n        assertEq(string(fullPath), expected, \"deployed code for full path was incorrect\");\n    }\n\n    // this will set the deployed bytecode of the stateless contract to the `overrideAddress` and call the function that emits an event that will be `expectEmitted`\n    function testCanEtchStatelessOverride() public {\n        bytes memory code = vm.getDeployedCode(\"fixtures/GetCode/Override.json\");\n        vm.etch(overrideAddress, code);\n        assertEq(\n            overrideAddress.code,\n            hex\"60806040526004361061001e5760003560e01c806340e04f5e14610023575b600080fd5b610036610031366004610091565b610048565b60405190815260200160405180910390f35b60007fda9986ad4da7abb3f55b2d1f2009ab6ee50c5ad054092c04464c112acc4bc1103385858560405161007f9493929190610122565b60405180910390a15060009392505050565b6000806000604084860312156100a657600080fd5b83356001600160a01b03811681146100bd57600080fd5b9250602084013567ffffffffffffffff808211156100da57600080fd5b818601915086601f8301126100ee57600080fd5b8135818111156100fd57600080fd5b87602082850101111561010f57600080fd5b6020830194508093505050509250925092565b6001600160a01b0385811682528416602082015260606040820181905281018290526000828460808401376000608084840101526080601f19601f85011683010190509594505050505056fea26469706673582212202b0ba0fa4073d6f681bb1f99f0529e44583f2dc612a629f3ff0564eaa7257d1f64736f6c63430008110033\"\n        );\n\n        Override over = Override(overrideAddress);\n\n        vm.expectEmit(true, false, false, true);\n        emit Payload(address(this), address(0), \"hello\");\n        over.emitPayload(address(0), \"hello\");\n    }\n\n    function testWithVersion() public {\n        TestContract test = new TestContract();\n        bytes memory code = vm.getDeployedCode(\"cheats/GetDeployedCode.t.sol:TestContract:0.8.18\");\n\n        assertEq(address(test).code, code);\n\n        vm._expectCheatcodeRevert(\"no matching artifact found\");\n        vm.getDeployedCode(\"cheats/GetDeployedCode.t.sol:TestContract:0.8.19\");\n    }\n}\n\ninterface Override {\n    function emitPayload(address target, bytes calldata message) external payable returns (uint256);\n}\n"
  },
  {
    "path": "testdata/default/cheats/GetFoundryVersion.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract GetFoundryVersionTest is Test {\n    function testGetFoundryVersion() public view {\n        // (e.g. 0.3.0-nightly+3cb96bde9b.1737036656.debug)\n        string memory fullVersionString = vm.getFoundryVersion();\n\n        // Step 1: Split the version at \"+\"\n        string[] memory plusSplit = vm.split(fullVersionString, \"+\");\n        require(plusSplit.length == 2, \"Invalid version format: Missing '+' separator\");\n\n        // Step 2: Extract parts\n        string memory semanticVersion = plusSplit[0]; // \"0.3.0-dev\"\n        string memory metadata = plusSplit[1]; // \"34389e7850.1737037814.debug\"\n\n        // Step 3: Further split metadata by \".\"\n        string[] memory metadataComponents = vm.split(metadata, \".\");\n        require(metadataComponents.length == 3, \"Invalid version format: Metadata should have 3 components\");\n\n        // Step 4: Extract values\n        string memory commitHash = metadataComponents[0]; // \"34389e7850\"\n        string memory timestamp = metadataComponents[1]; // \"1737037814\"\n        string memory buildType = metadataComponents[2]; // \"debug\"\n\n        // Validate semantic version (e.g., \"0.3.0-stable\" or \"0.3.0-nightly\")\n        require(bytes(semanticVersion).length > 0, \"Semantic version is empty\");\n\n        // Validate commit hash (should be exactly 10 characters)\n        require(bytes(commitHash).length == 10, \"Invalid commit hash length\");\n\n        // Validate UNIX timestamp (numeric)\n        uint256 buildUnixTimestamp = vm.parseUint(timestamp);\n        uint256 minimumAcceptableTimestamp = 1700000000; // Adjust as needed\n        require(buildUnixTimestamp >= minimumAcceptableTimestamp, \"Build timestamp is too old\");\n\n        // Validate build profile (e.g., \"debug\" or \"release\")\n        require(bytes(buildType).length > 0, \"Build type is empty\");\n    }\n\n    function testFoundryVersionCmp() public {\n        // Should return -1 if current version is less than argument\n        assertEq(vm.foundryVersionCmp(\"99.0.0\"), -1);\n\n        // (e.g. 0.3.0-nightly+3cb96bde9b.1737036656.debug)\n        string memory fullVersionString = vm.getFoundryVersion();\n\n        // Step 1: Split the version at \"+\"\n        string[] memory plusSplit = vm.split(fullVersionString, \"+\");\n        require(plusSplit.length == 2, \"Invalid version format: Missing '+' separator\");\n\n        // Step 2: Extract parts\n        string memory semanticVersion = plusSplit[0]; // \"0.3.0-dev\"\n        string[] memory semanticSplit = vm.split(semanticVersion, \"-\");\n\n        semanticVersion = semanticSplit[0]; // \"0.3.0\"\n        // Should return 0 if current version is equal to argument\n        assertEq(vm.foundryVersionCmp(semanticVersion), 0);\n\n        // Should return 1 if current version is greater than argument\n        assertEq(vm.foundryVersionCmp(\"0.0.1\"), 1);\n    }\n\n    function testFoundryVersionAtLeast() public {\n        // Should return false for future versions\n        assertEq(vm.foundryVersionAtLeast(\"99.0.0\"), false);\n\n        // (e.g. 0.3.0-nightly+3cb96bde9b.1737036656.debug)\n        string memory fullVersionString = vm.getFoundryVersion();\n\n        // Step 1: Split the version at \"+\"\n        string[] memory plusSplit = vm.split(fullVersionString, \"+\");\n        require(plusSplit.length == 2, \"Invalid version format: Missing '+' separator\");\n\n        // Step 2: Extract parts\n        string memory semanticVersion = plusSplit[0]; // \"0.3.0-dev\"\n        string[] memory semanticSplit = vm.split(semanticVersion, \"-\");\n\n        semanticVersion = semanticSplit[0]; // \"0.3.0\"\n        assertTrue(vm.foundryVersionAtLeast(semanticVersion));\n\n        // Should return true for past versions\n        assertTrue(vm.foundryVersionAtLeast(\"0.2.0\"));\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/GetLabel.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract GetLabelTest is Test {\n    function testGetLabel() public {\n        // Label an address.\n        vm.label(address(1), \"Sir Address the 1st\");\n\n        // Retrieve the label and check it.\n        string memory label = vm.getLabel(address(1));\n        assertEq(label, \"Sir Address the 1st\");\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/GetNonce.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract Foo {}\n\ncontract GetNonceTest is Test {\n    function testGetNonce() public {\n        uint64 nonce1 = vm.getNonce(address(this));\n        new Foo();\n        new Foo();\n        uint64 nonce2 = vm.getNonce(address(this));\n        assertEq(nonce1 + 2, nonce2);\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/GetRawBlockHeader.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract GetRawBlockHeaderTest is Test {\n    function testGetRawBlockHeaderWithFork() public {\n        vm.createSelectFork(\"mainnet\");\n        assertEq(\n            keccak256(vm.getRawBlockHeader(22985278)),\n            // `cast keccak256 $(cast block 22985278 --raw)`\n            0x492419d85d2817f50577807a287742fbdcaae00ce89f2ea885e419ee4493b00f\n        );\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/GetStorageSlots.t.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract StorageContract {\n    // Simple variables - 1 slot each\n    uint256 public value; // Slot 0\n    address public owner; // Slot 1\n\n    // Fixed array - 3 consecutive slots\n    uint256[3] public numbers; // Slots 2, 3, 4\n\n    // Bytes variables\n    bytes public shortBytes; // Slot 5 (less than 32 bytes)\n    mapping(address => uint256) public balances; // Slot 6 Inserted in between to make sure we can still properly identify the bytes\n    bytes public longBytes; // Slot 7 (32+ bytes, will use multiple slots)\n\n    // String variables\n    string public shortString; // Slot 8 (less than 32 bytes)\n    string public longString; // Slot 9 (32+ bytes, will use multiple slots)\n\n    function setShortBytes(bytes memory _data) public {\n        shortBytes = _data;\n    }\n\n    function setLongBytes(bytes memory _data) public {\n        longBytes = _data;\n    }\n\n    function setShortString(string memory _str) public {\n        shortString = _str;\n    }\n\n    function setLongString(string memory _str) public {\n        longString = _str;\n    }\n\n    function setNumbers(uint256 a, uint256 b, uint256 c) public {\n        numbers[0] = a;\n        numbers[1] = b;\n        numbers[2] = c;\n    }\n}\n\ncontract GetStorageSlotsTest is Test {\n    StorageContract storageContract;\n\n    function setUp() public {\n        storageContract = new StorageContract();\n    }\n\n    function testGetStorageSlots() public {\n        // Test 1: Simple variable\n        uint256[] memory slots = vm.getStorageSlots(address(storageContract), \"value\");\n        assertEq(slots.length, 1);\n        assertEq(slots[0], 0);\n\n        // Test 2: Fixed array (should return 3 consecutive slots)\n        slots = vm.getStorageSlots(address(storageContract), \"numbers\");\n        assertEq(slots.length, 3);\n        assertEq(slots[0], 2);\n        assertEq(slots[1], 3);\n        assertEq(slots[2], 4);\n\n        // Test 3: Short bytes (less than 32 bytes)\n        storageContract.setShortBytes(hex\"deadbeef\");\n        slots = vm.getStorageSlots(address(storageContract), \"shortBytes\");\n        assertEq(slots.length, 1);\n        assertEq(slots[0], 5);\n\n        // Test 4: Long bytes (100 bytes = 4 slots needed)\n        bytes memory longData = new bytes(100);\n        for (uint256 i = 0; i < 100; i++) {\n            longData[i] = bytes1(uint8(i));\n        }\n        storageContract.setLongBytes(longData);\n\n        slots = vm.getStorageSlots(address(storageContract), \"longBytes\");\n        // Should return 5 slots: 1 base slot + 4 data slots\n        assertEq(slots.length, 5);\n        assertEq(slots[0], 7); // Base slot\n\n        // Data slots start at keccak256(base_slot)\n        uint256 dataStart = uint256(keccak256(abi.encode(uint256(7))));\n        assertEq(slots[1], dataStart);\n        assertEq(slots[2], dataStart + 1);\n        assertEq(slots[3], dataStart + 2);\n        assertEq(slots[4], dataStart + 3);\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/Json.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\nlibrary JsonStructs {\n    address constant HEVM_ADDRESS = address(bytes20(uint160(uint256(keccak256(\"hevm cheat code\")))));\n    Vm constant vm = Vm(HEVM_ADDRESS);\n\n    // forge eip712 testdata/default/cheats/Json.t.sol -R 'cheats=testdata/cheats' -R 'ds-test=testdata/lib/ds-test/src' | grep ^FlatJson\n    string constant schema_FlatJson =\n        \"FlatJson(uint256 a,int24[][] arr,string str,bytes b,address addr,bytes32 fixedBytes)\";\n\n    // forge eip712 testdata/default/cheats/Json.t.sol -R 'cheats=testdata/cheats' -R 'ds-test=testdata/lib/ds-test/src' | grep ^NestedJson\n    string constant schema_NestedJson =\n        \"NestedJson(FlatJson[] members,AnotherFlatJson inner,string name)AnotherFlatJson(bytes4 fixedBytes)FlatJson(uint256 a,int24[][] arr,string str,bytes b,address addr,bytes32 fixedBytes)\";\n\n    function deserializeFlatJson(string memory json) internal pure returns (ParseJsonTest.FlatJson memory) {\n        return abi.decode(vm.parseJsonType(json, schema_FlatJson), (ParseJsonTest.FlatJson));\n    }\n\n    function deserializeFlatJson(string memory json, string memory path)\n        internal\n        pure\n        returns (ParseJsonTest.FlatJson memory)\n    {\n        return abi.decode(vm.parseJsonType(json, path, schema_FlatJson), (ParseJsonTest.FlatJson));\n    }\n\n    function deserializeFlatJsonArray(string memory json, string memory path)\n        internal\n        pure\n        returns (ParseJsonTest.FlatJson[] memory)\n    {\n        return abi.decode(vm.parseJsonTypeArray(json, path, schema_FlatJson), (ParseJsonTest.FlatJson[]));\n    }\n\n    function deserializeNestedJson(string memory json) internal pure returns (ParseJsonTest.NestedJson memory) {\n        return abi.decode(vm.parseJsonType(json, schema_NestedJson), (ParseJsonTest.NestedJson));\n    }\n\n    function deserializeNestedJson(string memory json, string memory path)\n        internal\n        pure\n        returns (ParseJsonTest.NestedJson memory)\n    {\n        return abi.decode(vm.parseJsonType(json, path, schema_NestedJson), (ParseJsonTest.NestedJson));\n    }\n\n    function deserializeNestedJsonArray(string memory json, string memory path)\n        internal\n        pure\n        returns (ParseJsonTest.NestedJson[] memory)\n    {\n        return abi.decode(vm.parseJsonType(json, path, schema_NestedJson), (ParseJsonTest.NestedJson[]));\n    }\n\n    function serialize(ParseJsonTest.FlatJson memory instance) internal pure returns (string memory) {\n        return vm.serializeJsonType(schema_FlatJson, abi.encode(instance));\n    }\n\n    function serialize(ParseJsonTest.NestedJson memory instance) internal pure returns (string memory) {\n        return vm.serializeJsonType(schema_NestedJson, abi.encode(instance));\n    }\n}\n\ncontract ParseJsonTest is Test {\n    using JsonStructs for *;\n\n    struct FlatJson {\n        uint256 a;\n        int24[][] arr;\n        string str;\n        bytes b;\n        address addr;\n        bytes32 fixedBytes;\n    }\n\n    struct AnotherFlatJson {\n        bytes4 fixedBytes;\n    }\n\n    struct NestedJson {\n        FlatJson[] members;\n        AnotherFlatJson inner;\n        string name;\n    }\n\n    string json;\n\n    function setUp() public {\n        string memory path = \"fixtures/Json/test.json\";\n        json = vm.readFile(path);\n    }\n\n    function test_basicString() public {\n        bytes memory data = vm.parseJson(json, \".basicString\");\n        string memory decodedData = abi.decode(data, (string));\n        assertEq(\"hai\", decodedData);\n    }\n\n    function test_null() public {\n        bytes memory data = vm.parseJson(json, \".null\");\n        bytes memory decodedData = abi.decode(data, (bytes));\n        assertEq(new bytes(0), decodedData);\n    }\n\n    function test_stringArray() public {\n        bytes memory data = vm.parseJson(json, \".stringArray\");\n        string[] memory decodedData = abi.decode(data, (string[]));\n        assertEq(\"hai\", decodedData[0]);\n        assertEq(\"there\", decodedData[1]);\n    }\n\n    function test_address() public {\n        bytes memory data = vm.parseJson(json, \".address\");\n        address decodedData = abi.decode(data, (address));\n        assertEq(0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266, decodedData);\n    }\n\n    function test_addressArray() public {\n        bytes memory data = vm.parseJson(json, \".addressArray\");\n        address[] memory decodedData = abi.decode(data, (address[]));\n        assertEq(0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266, decodedData[0]);\n        assertEq(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D, decodedData[1]);\n    }\n\n    function test_H160ButNotaddress() public {\n        string memory data = abi.decode(vm.parseJson(json, \".H160NotAddress\"), (string));\n        assertEq(\"0000000000000000000000000000000000001337\", data);\n    }\n\n    function test_bool() public {\n        bytes memory data = vm.parseJson(json, \".boolTrue\");\n        bool decodedData = abi.decode(data, (bool));\n        assertTrue(decodedData);\n\n        data = vm.parseJson(json, \".boolFalse\");\n        decodedData = abi.decode(data, (bool));\n        assertTrue(!decodedData);\n    }\n\n    function test_boolArray() public {\n        bytes memory data = vm.parseJson(json, \".boolArray\");\n        bool[] memory decodedData = abi.decode(data, (bool[]));\n        assertTrue(decodedData[0]);\n        assertTrue(!decodedData[1]);\n    }\n\n    function test_uintArray() public {\n        bytes memory data = vm.parseJson(json, \".uintArray\");\n        uint256[] memory decodedData = abi.decode(data, (uint256[]));\n        assertEq(42, decodedData[0]);\n        assertEq(43, decodedData[1]);\n    }\n\n    // Object keys are sorted alphabetically, regardless of input.\n    struct Whole {\n        string str;\n        string[] strArray;\n        uint256[] uintArray;\n    }\n\n    function test_wholeObject() public {\n        // we need to make the path relative to the crate that's running tests for it (forge crate)\n        string memory path = \"fixtures/Json/whole_json.json\";\n        console.log(path);\n        json = vm.readFile(path);\n        bytes memory data = vm.parseJson(json);\n        Whole memory whole = abi.decode(data, (Whole));\n        assertEq(whole.str, \"hai\");\n        assertEq(whole.uintArray[0], 42);\n        assertEq(whole.uintArray[1], 43);\n        assertEq(whole.strArray[0], \"hai\");\n        assertEq(whole.strArray[1], \"there\");\n    }\n\n    function test_coercionRevert() public {\n        vm._expectCheatcodeRevert(\"expected uint256, found JSON object\");\n        vm.parseJsonUint(json, \".nestedObject\");\n    }\n\n    function test_coercionUint() public {\n        uint256 number = vm.parseJsonUint(json, \".uintHex\");\n        assertEq(number, 1231232);\n        number = vm.parseJsonUint(json, \".uintString\");\n        assertEq(number, 115792089237316195423570985008687907853269984665640564039457584007913129639935);\n        number = vm.parseJsonUint(json, \".uintNumber\");\n        assertEq(number, 115792089237316195423570985008687907853269984665640564039457584007913129639935);\n        uint256[] memory numbers = vm.parseJsonUintArray(json, \".uintArray\");\n        assertEq(numbers[0], 42);\n        assertEq(numbers[1], 43);\n        numbers = vm.parseJsonUintArray(json, \".uintStringArray\");\n        assertEq(numbers[0], 1231232);\n        assertEq(numbers[1], 1231232);\n        assertEq(numbers[2], 1231232);\n    }\n\n    function test_coercionInt() public {\n        int256 number = vm.parseJsonInt(json, \".intNumber\");\n        assertEq(number, -12);\n        number = vm.parseJsonInt(json, \".intString\");\n        assertEq(number, -12);\n        number = vm.parseJsonInt(json, \".intHex\");\n        assertEq(number, -12);\n    }\n\n    function test_coercionBool() public {\n        bool boolean = vm.parseJsonBool(json, \".boolTrue\");\n        assertTrue(boolean);\n        bool boolFalse = vm.parseJsonBool(json, \".boolFalse\");\n        assertTrue(!boolFalse);\n        boolean = vm.parseJsonBool(json, \".boolString\");\n        assertEq(boolean, true);\n        bool[] memory booleans = vm.parseJsonBoolArray(json, \".boolArray\");\n        assertTrue(booleans[0]);\n        assertTrue(!booleans[1]);\n        booleans = vm.parseJsonBoolArray(json, \".boolStringArray\");\n        assertTrue(booleans[0]);\n        assertTrue(!booleans[1]);\n    }\n\n    function test_coercionBytes() public {\n        bytes memory bytes_ = vm.parseJsonBytes(json, \".bytesString\");\n        assertEq(bytes_, hex\"01\");\n\n        bytes[] memory bytesArray = vm.parseJsonBytesArray(json, \".bytesStringArray\");\n        assertEq(bytesArray[0], hex\"01\");\n        assertEq(bytesArray[1], hex\"02\");\n    }\n\n    struct Nested {\n        uint256 number;\n        string str;\n    }\n\n    function test_nestedObject() public {\n        bytes memory data = vm.parseJson(json, \".nestedObject\");\n        Nested memory nested = abi.decode(data, (Nested));\n        assertEq(nested.number, 115792089237316195423570985008687907853269984665640564039457584007913129639935);\n        assertEq(nested.str, \"NEST\");\n    }\n\n    function test_advancedJsonPath() public {\n        bytes memory data = vm.parseJson(json, \".advancedJsonPath[*].id\");\n        uint256[] memory numbers = abi.decode(data, (uint256[]));\n        assertEq(numbers[0], 1);\n        assertEq(numbers[1], 2);\n    }\n\n    function test_canonicalizePath() public {\n        bytes memory data = vm.parseJson(json, \"$.basicString\");\n        string memory decodedData = abi.decode(data, (string));\n        assertEq(\"hai\", decodedData);\n    }\n\n    function test_nonExistentKey() public {\n        bytes memory data = vm.parseJson(json, \".thisKeyDoesNotExist\");\n        assertEq(0, data.length);\n    }\n\n    function test_parseJsonKeys() public {\n        string memory jsonString =\n            '{\"some_key_to_value\": \"some_value\", \"some_key_to_array\": [1, 2, 3], \"some_key_to_object\": {\"key1\": \"value1\", \"key2\": 2}}';\n\n        string[] memory keys = vm.parseJsonKeys(jsonString, \"$\");\n        string[] memory expected = new string[](3);\n        expected[0] = \"some_key_to_value\";\n        expected[1] = \"some_key_to_array\";\n        expected[2] = \"some_key_to_object\";\n        assertEq(abi.encode(keys), abi.encode(expected));\n\n        keys = vm.parseJsonKeys(jsonString, \".some_key_to_object\");\n        expected = new string[](2);\n        expected[0] = \"key1\";\n        expected[1] = \"key2\";\n        assertEq(abi.encode(keys), abi.encode(expected));\n\n        vm._expectCheatcodeRevert(\"JSON value at \\\".some_key_to_array\\\" is not an object\");\n        vm.parseJsonKeys(jsonString, \".some_key_to_array\");\n\n        vm._expectCheatcodeRevert(\"JSON value at \\\".some_key_to_value\\\" is not an object\");\n        vm.parseJsonKeys(jsonString, \".some_key_to_value\");\n\n        vm._expectCheatcodeRevert(\"key \\\".*\\\" must return exactly one JSON object\");\n        vm.parseJsonKeys(jsonString, \".*\");\n    }\n\n    // forge eip712 testdata/default/cheats/Json.t.sol -R 'cheats=testdata/cheats' -R 'ds-test=testdata/lib/ds-test/src' | grep ^FlatJson\n    string constant schema_FlatJson =\n        \"FlatJson(uint256 a,int24[][] arr,string str,bytes b,address addr,bytes32 fixedBytes)\";\n\n    // forge eip712 testdata/default/cheats/Json.t.sol -R 'cheats=testdata/cheats' -R 'ds-test=testdata/lib/ds-test/src' | grep ^NestedJson\n    string constant schema_NestedJson =\n        \"NestedJson(FlatJson[] members,AnotherFlatJson inner,string name)AnotherFlatJson(bytes4 fixedBytes)FlatJson(uint256 a,int24[][] arr,string str,bytes b,address addr,bytes32 fixedBytes)\";\n\n    function test_parseJsonType() public {\n        string memory readJson = vm.readFile(\"fixtures/Json/nested_json_struct.json\");\n        NestedJson memory data = readJson.deserializeNestedJson();\n        assertEq(data.members.length, 2);\n\n        FlatJson memory expected = FlatJson({\n            a: 200,\n            arr: new int24[][](0),\n            str: \"some other string\",\n            b: hex\"0000000000000000000000000000000000000000\",\n            addr: 0x167D91deaEEE3021161502873d3bcc6291081648,\n            fixedBytes: 0xed1c7beb1f00feaaaec5636950d6edb25a8d4fedc8deb2711287b64c4d27719d\n        });\n\n        assertEq(keccak256(abi.encode(data.members[1])), keccak256(abi.encode(expected)));\n        assertEq(bytes32(data.inner.fixedBytes), bytes32(bytes4(0x12345678)));\n\n        FlatJson[] memory members = JsonStructs.deserializeFlatJsonArray(readJson, \".members\");\n\n        assertEq(keccak256(abi.encode(members)), keccak256(abi.encode(data.members)));\n    }\n\n    function test_parseJsonType_roundtrip() public {\n        string memory readJson = vm.readFile(\"fixtures/Json/nested_json_struct.json\");\n        NestedJson memory data = readJson.deserializeNestedJson();\n        string memory serialized = data.serialize();\n        NestedJson memory deserialized = serialized.deserializeNestedJson();\n        assertEq(keccak256(abi.encode(data)), keccak256(abi.encode(deserialized)));\n    }\n}\n\ncontract WriteJsonTest is Test {\n    string json1;\n    string json2;\n\n    function setUp() public {\n        json1 = \"example\";\n        json2 = \"example2\";\n    }\n\n    function test_serializeJson() public {\n        vm.serializeUint(json1, \"key1\", uint256(254));\n        vm.serializeBool(json1, \"boolean\", true);\n        vm.serializeInt(json2, \"key2\", -234);\n        vm.serializeUint(json2, \"deploy\", uint256(254));\n        vm.serializeUintToHex(json2, \"hexUint\", uint256(255));\n        string memory data = vm.serializeBool(json2, \"boolean\", true);\n        vm.serializeString(json2, \"json1\", data);\n        emit log(data);\n    }\n\n    function test_serializeArray() public {\n        bool[] memory data1 = new bool[](3);\n        data1[0] = true;\n        data1[2] = false;\n        vm.serializeBool(json1, \"array1\", data1);\n\n        address[] memory data2 = new address[](3);\n        data2[0] = address(0xBEEEF);\n        data2[2] = vm.addr(123);\n        vm.serializeAddress(json1, \"array2\", data2);\n\n        bytes[] memory data3 = new bytes[](3);\n        data3[0] = bytes(\"123\");\n        data3[2] = bytes(\"fpovhpgjaiosfjhapiufpsdf\");\n        string memory finalJson = vm.serializeBytes(json1, \"array3\", data3);\n\n        string memory path = \"fixtures/Json/write_test_array.json\";\n        vm.writeJson(finalJson, path);\n\n        string memory json = vm.readFile(path);\n        bytes memory rawData = vm.parseJson(json, \".array1\");\n        bool[] memory parsedData1 = new bool[](3);\n        parsedData1 = abi.decode(rawData, (bool[]));\n        assertEq(parsedData1[0], data1[0]);\n        assertEq(parsedData1[1], data1[1]);\n        assertEq(parsedData1[2], data1[2]);\n\n        rawData = vm.parseJson(json, \".array2\");\n        address[] memory parsedData2 = new address[](3);\n        parsedData2 = abi.decode(rawData, (address[]));\n        assertEq(parsedData2[0], data2[0]);\n        assertEq(parsedData2[1], data2[1]);\n        assertEq(parsedData2[2], data2[2]);\n\n        rawData = vm.parseJson(json, \".array3\");\n        bytes[] memory parsedData3 = new bytes[](3);\n        parsedData3 = abi.decode(rawData, (bytes[]));\n        assertEq(parsedData3[0], data3[0]);\n        assertEq(parsedData3[1], data3[1]);\n        assertEq(parsedData3[2], data3[2]);\n        vm.removeFile(path);\n    }\n\n    // The serializeJson cheatcode was added to support assigning an existing json string to an object key.\n    // Github issue: https://github.com/foundry-rs/foundry/issues/5745\n    function test_serializeRootObject() public {\n        string memory serialized = vm.serializeJson(json1, '{\"foo\": \"bar\"}');\n        assertEq(serialized, '{\"foo\": \"bar\"}');\n        serialized = vm.serializeBool(json1, \"boolean\", true);\n        assertEq(vm.parseJsonString(serialized, \".foo\"), \"bar\");\n        assertEq(vm.parseJsonBool(serialized, \".boolean\"), true);\n\n        string memory overwritten = vm.serializeJson(json1, '{\"value\": 123}');\n        assertEq(overwritten, '{\"value\": 123}');\n    }\n\n    struct simpleJson {\n        uint256 a;\n        string b;\n    }\n\n    struct notSimpleJson {\n        uint256 a;\n        string b;\n        simpleJson c;\n    }\n\n    function test_serializeNotSimpleJson() public {\n        string memory json3 = \"json3\";\n        string memory path = \"fixtures/Json/write_complex_test.json\";\n        vm.serializeUint(json3, \"a\", uint256(123));\n        string memory semiFinal = vm.serializeString(json3, \"b\", \"test\");\n        string memory finalJson = vm.serializeString(json3, \"c\", semiFinal);\n        console.log(finalJson);\n        vm.writeJson(finalJson, path);\n        string memory json = vm.readFile(path);\n        bytes memory data = vm.parseJson(json);\n        notSimpleJson memory decodedData = abi.decode(data, (notSimpleJson));\n    }\n\n    function test_retrieveEntireJson() public {\n        string memory path = \"fixtures/Json/write_complex_test.json\";\n        string memory json = vm.readFile(path);\n        bytes memory data = vm.parseJson(json, \".\");\n        notSimpleJson memory decodedData = abi.decode(data, (notSimpleJson));\n        console.log(decodedData.a);\n        assertEq(decodedData.a, 123);\n    }\n\n    function test_checkKeyExistsJson() public {\n        string memory path = \"fixtures/Json/write_complex_test.json\";\n        string memory json = vm.readFile(path);\n        bool exists = vm.keyExistsJson(json, \".a\");\n        assertTrue(exists);\n\n        // TODO: issue deprecation warning\n        exists = vm.keyExists(json, \".a\");\n        assertTrue(exists);\n    }\n\n    function test_checkKeyDoesNotExistJson() public {\n        string memory path = \"fixtures/Json/write_complex_test.json\";\n        string memory json = vm.readFile(path);\n        bool exists = vm.keyExistsJson(json, \".d\");\n        assertTrue(!exists);\n\n        // TODO: issue deprecation warning\n        exists = vm.keyExists(json, \".d\");\n        assertTrue(!exists);\n    }\n\n    function test_writeJson() public {\n        string memory json3 = \"json3\";\n        string memory path = \"fixtures/Json/write_test.json\";\n        vm.serializeUint(json3, \"a\", uint256(123));\n        string memory finalJson = vm.serializeString(json3, \"b\", \"test\");\n        vm.writeJson(finalJson, path);\n\n        string memory json = vm.readFile(path);\n        bytes memory data = vm.parseJson(json);\n        simpleJson memory decodedData = abi.decode(data, (simpleJson));\n        assertEq(decodedData.a, 123);\n        assertEq(decodedData.b, \"test\");\n\n        // write json3 to key b\n        vm.writeJson(finalJson, path, \".b\");\n        // read again\n        json = vm.readFile(path);\n        data = vm.parseJson(json, \".b\");\n        decodedData = abi.decode(data, (simpleJson));\n        assertEq(decodedData.a, 123);\n        assertEq(decodedData.b, \"test\");\n\n        // replace a single value to key b\n        address ex = address(0xBEEF);\n        vm.writeJson(vm.toString(ex), path, \".b\");\n        json = vm.readFile(path);\n        data = vm.parseJson(json, \".b\");\n        address decodedAddress = abi.decode(data, (address));\n        assertEq(decodedAddress, ex);\n    }\n\n    function test_writeJson_createKeys() public {\n        string memory path = \"fixtures/Json/write_test.json\";\n        string memory json = vm.readFile(path);\n\n        bool exists = vm.keyExistsJson(json, \".parent\");\n        assertTrue(!exists);\n        exists = vm.keyExistsJson(json, \".parent.child\");\n        assertTrue(!exists);\n        exists = vm.keyExistsJson(json, \".parent.child.value\");\n        assertTrue(!exists);\n\n        // Write to nested path, creating intermediate keys\n        vm.writeJson(vm.toString(uint256(42)), path, \".parent.child.value\");\n\n        // Verify the value was written and intermediate keys were created\n        json = vm.readFile(path);\n        uint256 value = abi.decode(vm.parseJson(json, \".parent.child.value\"), (uint256));\n        assertEq(value, 42);\n\n        // Clean up the test file by removing the parent key we added\n        vm.removeFile(path);\n        vm.writeJson(\"{\\\"a\\\": 123, \\\"b\\\": \\\"0x000000000000000000000000000000000000bEEF\\\"}\", path);\n    }\n\n    function test_writeJson_createFile() public {\n        string memory path = \"fixtures/Json/write_test_nonexistent.json\";\n\n        // Write to a file that does not exist using the 3-arg overload\n        vm.writeJson(vm.toString(uint256(99)), path, \".x.y\");\n\n        // Verify the file was created with the correct content\n        string memory json = vm.readFile(path);\n        uint256 value = abi.decode(vm.parseJson(json, \".x.y\"), (uint256));\n        assertEq(value, 99);\n\n        // Clean up\n        vm.removeFile(path);\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/Label.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract LabelTest is Test {\n    function testLabel() public {\n        vm.label(address(1), \"Sir Address the 1st\");\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/Load.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract Storage {\n    uint256 slot0 = 10;\n}\n\ncontract LoadTest is Test {\n    uint256 slot0 = 20;\n    Storage store;\n\n    function setUp() public {\n        store = new Storage();\n    }\n\n    function testLoadOwnStorage() public {\n        uint256 slot;\n        assembly {\n            slot := slot0.slot\n        }\n        uint256 val = uint256(vm.load(address(this), bytes32(slot)));\n        assertEq(val, 20, \"load failed\");\n    }\n\n    function testLoadNotAvailableOnPrecompiles() public {\n        vm._expectCheatcodeRevert(\"cannot use precompile 0x0000000000000000000000000000000000000001 as an argument\");\n        vm.load(address(1), bytes32(0));\n    }\n\n    function testLoadOtherStorage() public {\n        uint256 val = uint256(vm.load(address(store), bytes32(0)));\n        assertEq(val, 10, \"load failed\");\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/Mapping.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract RecordMapping {\n    int256 length;\n    mapping(address => int256) data;\n    mapping(int256 => mapping(int256 => int256)) nestedData;\n\n    function setData(address addr, int256 value) public {\n        data[addr] = value;\n    }\n\n    function setNestedData(int256 i, int256 j) public {\n        nestedData[i][j] = i * j;\n    }\n}\n\ncontract RecordMappingTest is Test {\n    function testRecordMapping() public {\n        RecordMapping target = new RecordMapping();\n\n        // Start recording\n        vm.startMappingRecording();\n\n        // Verify Records\n        target.setData(address(this), 100);\n        target.setNestedData(99, 10);\n        target.setNestedData(98, 10);\n        bool found;\n        bytes32 key;\n        bytes32 parent;\n\n        bytes32 dataSlot = bytes32(uint256(1));\n        bytes32 nestDataSlot = bytes32(uint256(2));\n        assertEq(uint256(vm.getMappingLength(address(target), dataSlot)), 1, \"number of data is incorrect\");\n        assertEq(uint256(vm.getMappingLength(address(this), dataSlot)), 0, \"number of data is incorrect\");\n        assertEq(uint256(vm.getMappingLength(address(target), nestDataSlot)), 2, \"number of nestedData is incorrect\");\n\n        bytes32 dataValueSlot = vm.getMappingSlotAt(address(target), dataSlot, 0);\n        (found, key, parent) = vm.getMappingKeyAndParentOf(address(target), dataValueSlot);\n        assert(found);\n        assertEq(address(uint160(uint256(key))), address(this), \"key of data[i] is incorrect\");\n        assertEq(parent, dataSlot, \"parent of data[i] is incorrect\");\n        assertGt(uint256(dataValueSlot), 0);\n        assertEq(uint256(vm.load(address(target), dataValueSlot)), 100);\n\n        for (uint256 k; k < vm.getMappingLength(address(target), nestDataSlot); k++) {\n            bytes32 subSlot = vm.getMappingSlotAt(address(target), nestDataSlot, k);\n            (found, key, parent) = vm.getMappingKeyAndParentOf(address(target), subSlot);\n            uint256 i = uint256(key);\n            assertEq(parent, nestDataSlot, \"parent of nestedData[i][j] is incorrect\");\n            assertEq(uint256(vm.getMappingLength(address(target), subSlot)), 1, \"number of nestedData[i] is incorrect\");\n            bytes32 leafSlot = vm.getMappingSlotAt(address(target), subSlot, 0);\n            (found, key, parent) = vm.getMappingKeyAndParentOf(address(target), leafSlot);\n            uint256 j = uint256(key);\n            assertEq(parent, subSlot, \"parent of nestedData[i][j] is incorrect\");\n            assertEq(j, 10);\n            assertEq(uint256(vm.load(address(target), leafSlot)), i * j, \"value of nestedData[i][j] is incorrect\");\n        }\n        vm.stopMappingRecording();\n        assertEq(uint256(vm.getMappingLength(address(target), dataSlot)), 0, \"number of data is incorrect\");\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/MemSafety.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract MemSafetyTest is Test {\n    ////////////////////////////////////////////////////////////////\n    //                           MSTORE                           //\n    ////////////////////////////////////////////////////////////////\n\n    /// @dev Tests that writing to memory within the range given to `expectSafeMemory`\n    ///      will not cause the test to fail while using the `MSTORE` opcode.\n    function testExpectSafeMemory_MSTORE() public {\n        // Allow memory writes in the range of [0x80, 0xA0) within this context\n        vm.expectSafeMemory(0x80, 0xA0);\n\n        // Write to memory within the range using `MSTORE`\n        assembly {\n            mstore(0x80, 0xc0ffee)\n        }\n    }\n\n    /// @dev Tests that writing to memory within the ranges given to `expectSafeMemory`\n    ///      will not cause the test to fail while using the `MSTORE` opcode.\n    function testExpectSafeMemory_multiRange_MSTORE() public {\n        // Allow memory writes in the range of [0x80, 0x100) and [0x120, 0x140) within this context\n        vm.expectSafeMemory(0x80, 0x100);\n        vm.expectSafeMemory(0x120, 0x140);\n\n        // Write to memory within the range using `MSTORE`\n        assembly {\n            mstore(0x80, 0xc0ffee)\n            mstore(0x120, 0xbadf00d)\n        }\n    }\n\n    ////////////////////////////////////////////////////////////////\n    //                          MSTORE8                           //\n    ////////////////////////////////////////////////////////////////\n\n    /// @dev Tests that writing to memory within the range given to `expectSafeMemory`\n    ///      will not cause the test to fail while using the `MSTORE8` opcode.\n    function testExpectSafeMemory_MSTORE8() public {\n        // Allow memory writes in the range of [0x80, 0x81) within this context\n        vm.expectSafeMemory(0x80, 0x81);\n\n        // Write to memory within the range using `MSTORE8`\n        assembly {\n            mstore8(0x80, 0xFF)\n        }\n    }\n\n    /// @dev Tests that writing to memory within the ranges given to `expectSafeMemory`\n    ///      will not cause the test to fail while using the `MSTORE8` opcode.\n    function testExpectSafeMemory_multiRange_MSTORE8() public {\n        // Allow memory writes in the range of [0x80, 0x100) and [0x120, 0x121) within this context\n        vm.expectSafeMemory(0x80, 0x100);\n        vm.expectSafeMemory(0x120, 0x121);\n\n        // Write to memory within the range using `MSTORE8`\n        assembly {\n            mstore8(0x80, 0xFF)\n            mstore8(0x120, 0xFF)\n        }\n    }\n\n    ////////////////////////////////////////////////////////////////\n    //                        CALLDATACOPY                        //\n    ////////////////////////////////////////////////////////////////\n\n    /// @dev Tests that writing to memory within of the range given to `expectSafeMemory`\n    ///      will not cause the test to fail while using the `CALLDATACOPY` opcode.\n    function testExpectSafeMemory_CALLDATACOPY(uint256 _x) public {\n        // Allow memory writes in the range of [0x80, 0xA0) within this context\n        vm.expectSafeMemory(0x80, 0xA0);\n\n        // Write to memory within the range using `CALLDATACOPY`\n        assembly {\n            calldatacopy(0x80, 0x04, 0x20)\n        }\n    }\n\n    ////////////////////////////////////////////////////////////////\n    //                          CODECOPY                          //\n    ////////////////////////////////////////////////////////////////\n\n    /// @dev Tests that writing to memory within of the range given to `expectSafeMemory`\n    ///      will not cause the test to fail while using the `CODECOPY` opcode.\n    function testExpectSafeMemory_CODECOPY() public {\n        // Allow memory writes in the range of [0x80, 0xA0) within this context\n        vm.expectSafeMemory(0x80, 0xA0);\n\n        // Write to memory within the range using `CODECOPY`\n        assembly {\n            let size := extcodesize(address())\n            codecopy(0x80, 0x00, 0x20)\n        }\n    }\n\n    ////////////////////////////////////////////////////////////////\n    //                       RETURNDATACOPY                       //\n    ////////////////////////////////////////////////////////////////\n\n    /// @dev Tests that writing to memory within of the range given to `expectSafeMemory`\n    ///      will not cause the test to fail while using the `RETURNDATACOPY` opcode.\n    function testExpectSafeMemory_RETURNDATACOPY() public {\n        // Create a new SubContext contract\n        SubContext sc = new SubContext();\n\n        // Create a payload to call `giveReturndata` on the SubContext contract\n        bytes memory payload = abi.encodeWithSelector(SubContext.giveReturndata.selector);\n\n        // Allow memory writes in the range of [0x80, 0x100) within this context\n        vm.expectSafeMemory(0x80, 0x100);\n\n        // Create a new SubContext contract and call `giveReturndata` on it.\n        _doCallReturnData(address(sc), payload, 0x80, 0x60);\n\n        // Write to memory within the range using `RETURNDATACOPY`\n        assembly {\n            returndatacopy(0x80, 0x00, 0x60)\n        }\n    }\n\n    ////////////////////////////////////////////////////////////////\n    //                        EXTCODECOPY                         //\n    ////////////////////////////////////////////////////////////////\n\n    /// @dev Tests that writing to memory within of the range given to `expectSafeMemory`\n    ///      will not cause the test to fail while using the `EXTCODECOPY` opcode.\n    function testExpectSafeMemory_EXTCODECOPY() public {\n        // Allow memory writes in the range of [0x80, 0xA0) within this context\n        vm.expectSafeMemory(0x80, 0xA0);\n\n        // Write to memory within the range using `EXTCODECOPY`\n        assembly {\n            let size := extcodesize(address())\n            extcodecopy(address(), 0x80, 0x00, 0x20)\n        }\n    }\n\n    ////////////////////////////////////////////////////////////////\n    //                            CALL                            //\n    ////////////////////////////////////////////////////////////////\n\n    /// @dev Tests that writing to memory within of the range given to `expectSafeMemory`\n    ///      will not cause the test to fail while using the `CALL` opcode.\n    function testExpectSafeMemory_CALL() public {\n        // Create a new SubContext contract\n        SubContext sc = new SubContext();\n\n        // Create a payload to call `giveReturndata` on the SubContext contract\n        bytes memory payload = abi.encodeWithSelector(SubContext.giveReturndata.selector);\n\n        // Allow memory writes in the range of [0x80, 0x100) within this context\n        vm.expectSafeMemory(0x80, 0x100);\n\n        // Create a new SubContext contract and call `giveReturndata` on it.\n        _doCallReturnData(address(sc), payload, 0x80, 0x60);\n    }\n\n    ////////////////////////////////////////////////////////////////\n    //                          CALLCODE                          //\n    ////////////////////////////////////////////////////////////////\n\n    /// @dev Tests that writing to memory within of the range given to `expectSafeMemory`\n    ///      will not cause the test to fail while using the `CALLCODE` opcode.\n    function testExpectSafeMemory_CALLCODE() public {\n        // Create a new SubContext contract\n        SubContext sc = new SubContext();\n\n        // Create a payload to call `giveReturndata` on the SubContext contract\n        bytes memory payload = abi.encodeWithSelector(SubContext.giveReturndata.selector);\n\n        // Allow memory writes in the range of [0x80, 0x100) within this context\n        vm.expectSafeMemory(0x80, 0x100);\n\n        // Create a new SubContext contract and call `giveReturndata` on it.\n        _doCallCodeReturnData(address(sc), payload, 0x80, 0x60);\n    }\n\n    ////////////////////////////////////////////////////////////////\n    //                         STATICCALL                         //\n    ////////////////////////////////////////////////////////////////\n\n    /// @dev Tests that writing to memory within of the range given to `expectSafeMemory`\n    ///      will not cause the test to fail while using the `STATICCALL` opcode.\n    function testExpectSafeMemory_STATICCALL() public {\n        // Create a new SubContext contract\n        SubContext sc = new SubContext();\n\n        // Create a payload to call `giveReturndata` on the SubContext contract\n        bytes memory payload = abi.encodeWithSelector(SubContext.giveReturndata.selector);\n\n        // Allow memory writes in the range of [0x80, 0x100) within this context\n        vm.expectSafeMemory(0x80, 0x100);\n\n        // Create a new SubContext contract and call `giveReturndata` on it.\n        _doStaticCallReturnData(address(sc), payload, 0x80, 0x60);\n    }\n\n    ////////////////////////////////////////////////////////////////\n    //                        DELEGATECALL                        //\n    ////////////////////////////////////////////////////////////////\n\n    /// @dev Tests that writing to memory within of the range given to `expectSafeMemory`\n    ///      will not cause the test to fail while using the `DELEGATECALL` opcode.\n    function testExpectSafeMemory_DELEGATECALL() public {\n        // Create a new SubContext contract\n        SubContext sc = new SubContext();\n\n        // Create a payload to call `giveReturndata` on the SubContext contract\n        bytes memory payload = abi.encodeWithSelector(SubContext.giveReturndata.selector);\n\n        // Allow memory writes in the range of [0x80, 0x100) within this context\n        vm.expectSafeMemory(0x80, 0x100);\n\n        // Create a new SubContext contract and call `giveReturndata` on it.\n        _doDelegateCallReturnData(address(sc), payload, 0x80, 0x60);\n    }\n\n    ////////////////////////////////////////////////////////////////\n    //                   MLOAD (Read Expansion)                   //\n    ////////////////////////////////////////////////////////////////\n\n    /// @dev Tests that expanding memory within the range given to `expectSafeMemory`\n    ///      will not cause the test to fail while using the `MLOAD` opcode.\n    function testExpectSafeMemory_MLOAD() public {\n        vm.expectSafeMemory(0x80, 0x120);\n\n        // This should not revert. Ugly hack to make sure the mload isn't optimized\n        // out.\n        uint256 a;\n        assembly {\n            a := mload(0x100)\n        }\n        uint256 b = a + 1;\n    }\n\n    /// @dev Tests that expanding memory outside of the range given to `expectSafeMemory`\n    ///      will cause the test to fail while using the `MLOAD` opcode.\n    /// forge-config: default.allow_internal_expect_revert = true\n    function testExpectSafeMemory_MLOAD_REVERT() public {\n        vm.expectSafeMemory(0x80, 0x100);\n\n        vm.expectRevert();\n\n        // This should revert. Ugly hack to make sure the mload isn't optimized\n        // out.\n        uint256 a;\n        assembly {\n            a := mload(0x100)\n        }\n        uint256 b = a + 1;\n    }\n\n    ////////////////////////////////////////////////////////////////\n    //                   SHA3 (Read Expansion)                    //\n    ////////////////////////////////////////////////////////////////\n\n    /// @dev Tests that expanding memory within the range given to `expectSafeMemory`\n    ///      will not cause the test to fail while using the `SHA3` opcode.\n    function testExpectSafeMemory_SHA3() public {\n        vm.expectSafeMemory(0x80, 0x120);\n\n        // This should not revert. Ugly hack to make sure the sha3 isn't optimized\n        // out.\n        uint256 a;\n        assembly {\n            a := keccak256(0x100, 0x20)\n        }\n        uint256 b = a + 1;\n    }\n\n    ////////////////////////////////////////////////////////////////\n    //                 LOG(0-4) (Read Expansion)                  //\n    ////////////////////////////////////////////////////////////////\n\n    // Note: We only test LOG0 here because the other LOG opcodes have the offset\n    //       and size arguments in the same position on the stack as LOG0.\n\n    /// @dev Tests that expanding memory within the range given to `expectSafeMemory`\n    ///      will not cause the test to fail while using the `LOG0` opcode.\n    function testExpectSafeMemory_LOG0() public {\n        vm.expectSafeMemory(0x80, 0x120);\n\n        // This should not revert.\n        assembly {\n            log0(0x100, 0x20)\n        }\n    }\n\n    /// @dev Tests that expanding memory outside of the range given to `expectSafeMemory`\n    ///      will cause the test to fail while using the `LOG0` opcode.\n    /// forge-config: default.allow_internal_expect_revert = true\n    function testExpectSafeMemory_LOG0_REVERT() public {\n        vm.expectSafeMemory(0x80, 0x100);\n        vm.expectRevert();\n        // This should revert.\n        assembly {\n            log0(0x100, 0x20)\n        }\n    }\n\n    ////////////////////////////////////////////////////////////////\n    //              CREATE/CREATE2 (Read Expansion)               //\n    ////////////////////////////////////////////////////////////////\n\n    /// @dev Tests that expanding memory within the range given to `expectSafeMemory`\n    ///      will not cause the test to fail while using the `CREATE` opcode.\n    function testExpectSafeMemory_CREATE() public {\n        vm.expectSafeMemory(0x80, 0x120);\n\n        // This should not revert.\n        assembly {\n            pop(create(0, 0x100, 0x20))\n        }\n    }\n\n    /// @dev Tests that expanding memory within the range given to `expectSafeMemory`\n    ///      will not cause the test to fail while using the `CREATE2` opcode.\n    function testExpectSafeMemory_CREATE2() public {\n        vm.expectSafeMemory(0x80, 0x120);\n\n        // This should not revert.\n        assembly {\n            pop(create2(0, 0x100, 0x20, 0x00))\n        }\n    }\n\n    ////////////////////////////////////////////////////////////////\n    //               RETURN/REVERT (Read Expansion)               //\n    ////////////////////////////////////////////////////////////////\n\n    /// @dev Tests that expanding memory within the range given to `expectSafeMemory`\n    ///      will not cause the test to fail while using the `RETURN` opcode.\n    function testExpectSafeMemory_RETURN() public {\n        vm.expectSafeMemory(0x80, 0x120);\n\n        // This should not revert.\n        assembly {\n            return(0x100, 0x20)\n        }\n    }\n\n    /// @dev Tests that expanding memory within the range given to `expectSafeMemory`\n    ///      will not cause the test to fail while using the `REVERT` opcode.\n    function testExpectSafeMemory_REVERT() public {\n        // Create a new SubContext contract\n        SubContext sc = new SubContext();\n\n        // Create a payload to call `doRevert` on the SubContext contract\n        bytes memory payload = abi.encodeWithSelector(SubContext.doRevert.selector, 0x100, 0x20);\n\n        // Expect memory in the range of [0x00, 0x120] to be safe in the next subcontext\n        vm.expectSafeMemoryCall(0x00, 0x120);\n\n        // Call `doRevert` on the SubContext contract and ensure it did revert with zero\n        // data.\n        _doCallReturnData(address(sc), payload, 0x200, 0x20);\n        assembly {\n            if iszero(eq(keccak256(0x60, 0x20), keccak256(0x200, returndatasize()))) { revert(0x00, 0x00) }\n        }\n    }\n\n    ////////////////////////////////////////////////////////////////\n    //                    Context Depth Tests                     //\n    ////////////////////////////////////////////////////////////////\n\n    /// @dev Tests that the `expectSafeMemory` cheatcode respects context depth while\n    ///      using the `MSTORE` opcode.\n    function testExpectSafeMemory_MSTORE_respectsDepth() public {\n        // Create a new SubContext contract\n        SubContext sc = new SubContext();\n        // Create a payload to call `doMstore8` on the SubContext contract\n        bytes memory payload = abi.encodeWithSelector(SubContext.doMstore8.selector, 0x120, 0xc0ffee);\n\n        // Allow memory writes in the range of [0x80, 0x100) within this context\n        vm.expectSafeMemory(0x80, 0x100);\n\n        // Should not revert- the `expectSafeMemory` cheatcode operates at a\n        // per-depth level.\n        _doCall(address(sc), payload);\n    }\n\n    /// @dev Tests that the `expectSafeMemory` cheatcode respects context depth while\n    ///      using the `MSTORE8` opcode.\n    function testExpectSafeMemory_MSTORE8_respectsDepth() public {\n        // Create a new SubContext contract\n        SubContext sc = new SubContext();\n        // Create a payload to call `doMstore8` on the SubContext contract\n        bytes memory payload = abi.encodeWithSelector(SubContext.doMstore8.selector, 0x120, 0xFF);\n\n        // Allow memory writes in the range of [0x80, 0x100) within this context\n        vm.expectSafeMemory(0x80, 0x100);\n\n        // Should not revert- the `expectSafeMemory` cheatcode operates at a\n        // per-depth level.\n        _doCall(address(sc), payload);\n    }\n\n    ////////////////////////////////////////////////////////////////\n    //              `expectSafeMemoryCall` cheatcode              //\n    ////////////////////////////////////////////////////////////////\n\n    /// @dev Tests that the `expectSafeMemoryCall` cheatcode works as expected.\n    function testExpectSafeMemoryCall() public {\n        // Create a new SubContext contract\n        SubContext sc = new SubContext();\n        // Create a payload to call `doMstore8` on the SubContext contract\n        bytes memory payload = abi.encodeWithSelector(SubContext.doMstore.selector, 0x80, 0xc0ffee);\n\n        // Allow memory writes in the range of [0x80, 0xA0) within the next created subcontext\n        vm.expectSafeMemoryCall(0x80, 0xA0);\n\n        // Should not revert- the memory write in this subcontext is within the allowed range.\n        _doCall(address(sc), payload);\n    }\n\n    ////////////////////////////////////////////////////////////////\n    //              `stopExpectSafeMemory` cheatcode              //\n    ////////////////////////////////////////////////////////////////\n\n    /// @dev Tests that the `stopExpectSafeMemory` cheatcode works as expected.\n    function testStopExpectSafeMemory() public {\n        uint64 initPtr;\n        assembly {\n            initPtr := mload(0x40)\n        }\n\n        vm.expectSafeMemory(initPtr, initPtr + 0x20);\n        assembly {\n            // write to allowed range\n            mstore(initPtr, 0x01)\n        }\n\n        vm.stopExpectSafeMemory();\n\n        assembly {\n            // write outside allowed range, this should be fine\n            mstore(add(initPtr, 0x20), 0x01)\n        }\n    }\n\n    /// @dev Tests that the `stopExpectSafeMemory` cheatcode can still be called if the free memory pointer was\n    ///      updated to the exclusive upper boundary during execution.\n    function testStopExpectSafeMemory_freeMemUpdate() public {\n        uint64 initPtr;\n        assembly {\n            initPtr := mload(0x40)\n        }\n\n        vm.expectSafeMemory(initPtr, initPtr + 0x20);\n        assembly {\n            // write outside of allowed range, this should revert\n            mstore(initPtr, 0x01)\n            mstore(0x40, add(initPtr, 0x20))\n        }\n\n        vm.stopExpectSafeMemory();\n    }\n\n    ////////////////////////////////////////////////////////////////\n    //                          HELPERS                           //\n    ////////////////////////////////////////////////////////////////\n\n    /// @dev Performs a call without copying any returndata.\n    function _doCall(address _target, bytes memory _payload) internal returns (bool _success) {\n        assembly {\n            _success := call(gas(), _target, 0x00, add(_payload, 0x20), mload(_payload), 0x00, 0x00)\n        }\n    }\n\n    /// @dev Performs a call and copies returndata to memory.\n    function _doCallReturnData(address _target, bytes memory _payload, uint256 returnDataDest, uint256 returnDataSize)\n        internal\n    {\n        assembly {\n            pop(call(gas(), _target, 0x00, add(_payload, 0x20), mload(_payload), returnDataDest, returnDataSize))\n        }\n    }\n\n    /// @dev Performs a staticcall and copies returndata to memory.\n    function _doStaticCallReturnData(\n        address _target,\n        bytes memory _payload,\n        uint256 returnDataDest,\n        uint256 returnDataSize\n    ) internal {\n        assembly {\n            pop(staticcall(gas(), _target, add(_payload, 0x20), mload(_payload), returnDataDest, returnDataSize))\n        }\n    }\n\n    /// @dev Performs a delegatecall and copies returndata to memory.\n    function _doDelegateCallReturnData(\n        address _target,\n        bytes memory _payload,\n        uint256 returnDataDest,\n        uint256 returnDataSize\n    ) internal {\n        assembly {\n            pop(delegatecall(gas(), _target, add(_payload, 0x20), mload(_payload), returnDataDest, returnDataSize))\n        }\n    }\n\n    /// @dev Performs a callcode and copies returndata to memory.\n    function _doCallCodeReturnData(\n        address _target,\n        bytes memory _payload,\n        uint256 returnDataDest,\n        uint256 returnDataSize\n    ) internal {\n        assembly {\n            pop(callcode(gas(), _target, 0x00, add(_payload, 0x20), mload(_payload), returnDataDest, returnDataSize))\n        }\n    }\n}\n\n/// @dev A simple contract for testing the `expectSafeMemory` & `expectSafeMemoryCall` cheatcodes.\ncontract SubContext {\n    function doMstore(uint256 offset, uint256 val) external {\n        assembly {\n            mstore(offset, val)\n        }\n    }\n\n    function doMstore8(uint256 offset, uint8 val) external {\n        assembly {\n            mstore8(offset, val)\n        }\n    }\n\n    function giveReturndata() external view returns (bytes memory _returndata) {\n        return hex\"7dc4acc68d77c9c85b5cb0f53ab9ceea175f7964390758e4409013ce80643f84\";\n    }\n\n    function doRevert(uint256 offset, uint256 size) external {\n        assembly {\n            revert(offset, size)\n        }\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/MockCall.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract Mock {\n    uint256 state = 0;\n\n    function numberA() public pure returns (uint256) {\n        return 1;\n    }\n\n    function numberB() public pure returns (uint256) {\n        return 2;\n    }\n\n    function add(uint256 a, uint256 b) public pure returns (uint256) {\n        return a + b;\n    }\n\n    function pay(uint256 a) public payable returns (uint256) {\n        return a;\n    }\n\n    function noReturnValue() public {\n        // Does nothing of value, but also ensures that Solidity will 100%\n        // generate an `extcodesize` check.\n        state += 1;\n    }\n}\n\ncontract NestedMock {\n    Mock private inner;\n\n    constructor(Mock _inner) {\n        inner = _inner;\n    }\n\n    function sum() public view returns (uint256) {\n        return inner.numberA() + inner.numberB();\n    }\n}\n\ncontract NestedMockDelegateCall {\n    Mock private inner;\n\n    constructor(Mock _inner) {\n        inner = _inner;\n    }\n\n    function sum() public returns (uint256) {\n        (, bytes memory dataA) = address(inner).delegatecall(abi.encodeWithSelector(Mock.numberA.selector));\n        (, bytes memory dataB) = address(inner).delegatecall(abi.encodeWithSelector(Mock.numberB.selector));\n        return abi.decode(dataA, (uint256)) + abi.decode(dataB, (uint256));\n    }\n}\n\ncontract MockCallTest is Test {\n    function testMockGetters() public {\n        Mock target = new Mock();\n\n        // pre-mock\n        assertEq(target.numberA(), 1);\n        assertEq(target.numberB(), 2);\n\n        vm.mockCall(address(target), abi.encodeWithSelector(target.numberB.selector), abi.encode(10));\n\n        // post-mock\n        assertEq(target.numberA(), 1);\n        assertEq(target.numberB(), 10);\n    }\n\n    function testMockNested() public {\n        Mock inner = new Mock();\n        NestedMock target = new NestedMock(inner);\n\n        // pre-mock\n        assertEq(target.sum(), 3);\n\n        vm.mockCall(address(inner), abi.encodeWithSelector(inner.numberB.selector), abi.encode(9));\n\n        // post-mock\n        assertEq(target.sum(), 10);\n    }\n\n    // Ref: https://github.com/foundry-rs/foundry/issues/8066\n    function testMockNestedDelegate() public {\n        Mock inner = new Mock();\n        NestedMockDelegateCall target = new NestedMockDelegateCall(inner);\n\n        assertEq(target.sum(), 3);\n\n        vm.mockCall(address(inner), abi.encodeWithSelector(inner.numberB.selector), abi.encode(9));\n\n        assertEq(target.sum(), 10);\n    }\n\n    function testMockSelector() public {\n        Mock target = new Mock();\n        assertEq(target.add(5, 5), 10);\n\n        vm.mockCall(address(target), abi.encodeWithSelector(target.add.selector), abi.encode(11));\n\n        assertEq(target.add(5, 5), 11);\n    }\n\n    function testMockCalldata() public {\n        Mock target = new Mock();\n        assertEq(target.add(5, 5), 10);\n        assertEq(target.add(6, 4), 10);\n\n        vm.mockCall(address(target), abi.encodeWithSelector(target.add.selector, 5, 5), abi.encode(11));\n\n        assertEq(target.add(5, 5), 11);\n        assertEq(target.add(6, 4), 10);\n    }\n\n    function testClearMockedCalls() public {\n        Mock target = new Mock();\n\n        vm.mockCall(address(target), abi.encodeWithSelector(target.numberB.selector), abi.encode(10));\n\n        assertEq(target.numberA(), 1);\n        assertEq(target.numberB(), 10);\n\n        vm.clearMockedCalls();\n\n        assertEq(target.numberA(), 1);\n        assertEq(target.numberB(), 2);\n    }\n\n    function testMockCallMultiplePartialMatch() public {\n        Mock mock = new Mock();\n\n        vm.mockCall(address(mock), abi.encodeWithSelector(mock.add.selector), abi.encode(10));\n        vm.mockCall(address(mock), abi.encodeWithSelector(mock.add.selector, 2), abi.encode(20));\n        vm.mockCall(address(mock), abi.encodeWithSelector(mock.add.selector, 2, 3), abi.encode(30));\n\n        assertEq(mock.add(1, 2), 10);\n        assertEq(mock.add(2, 2), 20);\n        assertEq(mock.add(2, 3), 30);\n    }\n\n    function testMockCallWithValue() public {\n        Mock mock = new Mock();\n\n        vm.mockCall(address(mock), 10, abi.encodeWithSelector(mock.pay.selector), abi.encode(10));\n\n        assertEq(mock.pay{value: 10}(1), 10);\n        assertEq(mock.pay(1), 1);\n\n        for (uint256 i = 0; i < 100; i++) {\n            vm.mockCall(address(mock), i, abi.encodeWithSelector(mock.pay.selector), abi.encode(i * 2));\n        }\n\n        assertEq(mock.pay(1), 0);\n        assertEq(mock.pay{value: 10}(1), 20);\n        assertEq(mock.pay{value: 50}(1), 100);\n    }\n\n    function testMockCallWithValueCalldataPrecedence() public {\n        Mock mock = new Mock();\n\n        vm.mockCall(address(mock), 10, abi.encodeWithSelector(mock.pay.selector), abi.encode(10));\n        vm.mockCall(address(mock), abi.encodeWithSelector(mock.pay.selector, 2), abi.encode(2));\n\n        assertEq(mock.pay{value: 10}(1), 10);\n        assertEq(mock.pay{value: 10}(2), 2);\n        assertEq(mock.pay(2), 2);\n    }\n\n    function testMockCallEmptyAccount() public {\n        Mock mock = Mock(address(100));\n\n        vm.mockCall(address(mock), abi.encodeWithSelector(mock.add.selector), abi.encode(10));\n        vm.mockCall(address(mock), mock.noReturnValue.selector, abi.encode());\n\n        assertEq(mock.add(1, 2), 10);\n        mock.noReturnValue();\n    }\n}\n\ncontract MockCallRevertTest is Test {\n    error TestError(bytes msg);\n\n    bytes constant ERROR_MESSAGE = \"ERROR_MESSAGE\";\n\n    function testMockGettersRevert() public {\n        Mock target = new Mock();\n\n        // pre-mock\n        assertEq(target.numberA(), 1);\n        assertEq(target.numberB(), 2);\n\n        vm.mockCallRevert(address(target), target.numberB.selector, ERROR_MESSAGE);\n\n        // post-mock\n        assertEq(target.numberA(), 1);\n        try target.numberB() {\n            revert();\n        } catch (bytes memory err) {\n            require(keccak256(err) == keccak256(ERROR_MESSAGE));\n        }\n    }\n\n    function testMockRevertWithCustomError() public {\n        Mock target = new Mock();\n\n        assertEq(target.numberA(), 1);\n        assertEq(target.numberB(), 2);\n\n        bytes memory customError = abi.encodeWithSelector(TestError.selector, ERROR_MESSAGE);\n\n        vm.mockCallRevert(address(target), abi.encodeWithSelector(target.numberB.selector), customError);\n\n        assertEq(target.numberA(), 1);\n        try target.numberB() {\n            revert();\n        } catch (bytes memory err) {\n            require(keccak256(err) == keccak256(customError));\n        }\n    }\n\n    function testMockNestedRevert() public {\n        Mock inner = new Mock();\n        NestedMock target = new NestedMock(inner);\n\n        assertEq(target.sum(), 3);\n\n        vm.mockCallRevert(address(inner), abi.encodeWithSelector(inner.numberB.selector), ERROR_MESSAGE);\n\n        try target.sum() {\n            revert();\n        } catch (bytes memory err) {\n            require(keccak256(err) == keccak256(ERROR_MESSAGE));\n        }\n    }\n\n    function testMockCalldataRevert() public {\n        Mock target = new Mock();\n        assertEq(target.add(5, 5), 10);\n        assertEq(target.add(6, 4), 10);\n\n        vm.mockCallRevert(address(target), abi.encodeWithSelector(target.add.selector, 5, 5), ERROR_MESSAGE);\n\n        assertEq(target.add(6, 4), 10);\n\n        try target.add(5, 5) {\n            revert();\n        } catch (bytes memory err) {\n            require(keccak256(err) == keccak256(ERROR_MESSAGE));\n        }\n    }\n\n    function testClearMockRevertedCalls() public {\n        Mock target = new Mock();\n\n        vm.mockCallRevert(address(target), abi.encodeWithSelector(target.numberB.selector), ERROR_MESSAGE);\n\n        vm.clearMockedCalls();\n\n        assertEq(target.numberA(), 1);\n        assertEq(target.numberB(), 2);\n    }\n\n    function testMockCallRevertPartialMatch() public {\n        Mock mock = new Mock();\n\n        vm.mockCallRevert(address(mock), abi.encodeWithSelector(mock.add.selector, 2), ERROR_MESSAGE);\n\n        assertEq(mock.add(1, 2), 3);\n\n        try mock.add(2, 3) {\n            revert();\n        } catch (bytes memory err) {\n            require(keccak256(err) == keccak256(ERROR_MESSAGE));\n        }\n    }\n\n    function testMockCallRevertWithValue() public {\n        Mock mock = new Mock();\n\n        vm.mockCallRevert(address(mock), 10, abi.encodeWithSelector(mock.pay.selector), ERROR_MESSAGE);\n\n        assertEq(mock.pay(1), 1);\n        assertEq(mock.pay(2), 2);\n\n        try mock.pay{value: 10}(1) {\n            revert();\n        } catch (bytes memory err) {\n            require(keccak256(err) == keccak256(ERROR_MESSAGE));\n        }\n    }\n\n    function testMockCallResetsMockCallRevert() public {\n        Mock mock = new Mock();\n\n        vm.mockCallRevert(address(mock), abi.encodeWithSelector(mock.add.selector), ERROR_MESSAGE);\n\n        vm.mockCall(address(mock), abi.encodeWithSelector(mock.add.selector), abi.encode(5));\n        assertEq(mock.add(2, 3), 5);\n    }\n\n    function testMockCallRevertResetsMockCall() public {\n        Mock mock = new Mock();\n\n        vm.mockCall(address(mock), abi.encodeWithSelector(mock.add.selector), abi.encode(5));\n        assertEq(mock.add(2, 3), 5);\n\n        vm.mockCallRevert(address(mock), abi.encodeWithSelector(mock.add.selector), ERROR_MESSAGE);\n\n        try mock.add(2, 3) {\n            revert();\n        } catch (bytes memory err) {\n            require(keccak256(err) == keccak256(ERROR_MESSAGE));\n        }\n    }\n\n    function testMockCallRevertWithCall() public {\n        Mock mock = new Mock();\n\n        bytes memory customError = abi.encodeWithSelector(TestError.selector, ERROR_MESSAGE);\n\n        vm.mockCallRevert(address(mock), abi.encodeWithSelector(mock.add.selector), customError);\n\n        (bool success, bytes memory data) = address(mock).call(abi.encodeWithSelector(Mock.add.selector, 2, 3));\n        assertEq(success, false);\n        assertEq(data, customError);\n    }\n\n    function testMockCallEmptyAccount() public {\n        Mock mock = Mock(address(100));\n\n        vm.mockCallRevert(address(mock), abi.encodeWithSelector(mock.add.selector), ERROR_MESSAGE);\n\n        try mock.add(2, 3) {\n            revert();\n        } catch (bytes memory err) {\n            require(keccak256(err) == keccak256(ERROR_MESSAGE));\n        }\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/MockCalls.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract MockCallsTest is Test {\n    function testMockCallsLastShouldPersist() public {\n        address mockUser = vm.addr(vm.randomUint());\n        address mockErc20 = vm.addr(vm.randomUint());\n        bytes memory data = abi.encodeWithSignature(\"balanceOf(address)\", mockUser);\n        bytes[] memory mocks = new bytes[](2);\n        mocks[0] = abi.encode(2 ether);\n        mocks[1] = abi.encode(7.219 ether);\n        vm.mockCalls(mockErc20, data, mocks);\n        (, bytes memory ret1) = mockErc20.call(data);\n        assertEq(abi.decode(ret1, (uint256)), 2 ether);\n        (, bytes memory ret2) = mockErc20.call(data);\n        assertEq(abi.decode(ret2, (uint256)), 7.219 ether);\n        (, bytes memory ret3) = mockErc20.call(data);\n        assertEq(abi.decode(ret3, (uint256)), 7.219 ether);\n    }\n\n    function testMockCallsWithValue() public {\n        address mockUser = vm.addr(vm.randomUint());\n        address mockErc20 = vm.addr(vm.randomUint());\n        bytes memory data = abi.encodeWithSignature(\"balanceOf(address)\", mockUser);\n        bytes[] memory mocks = new bytes[](3);\n        mocks[0] = abi.encode(2 ether);\n        mocks[1] = abi.encode(1 ether);\n        mocks[2] = abi.encode(6.423 ether);\n        vm.mockCalls(mockErc20, 1 ether, data, mocks);\n        (, bytes memory ret1) = mockErc20.call{value: 1 ether}(data);\n        assertEq(abi.decode(ret1, (uint256)), 2 ether);\n        (, bytes memory ret2) = mockErc20.call{value: 1 ether}(data);\n        assertEq(abi.decode(ret2, (uint256)), 1 ether);\n        (, bytes memory ret3) = mockErc20.call{value: 1 ether}(data);\n        assertEq(abi.decode(ret3, (uint256)), 6.423 ether);\n    }\n\n    function testMockCalls() public {\n        address mockUser = vm.addr(vm.randomUint());\n        address mockErc20 = vm.addr(vm.randomUint());\n        bytes memory data = abi.encodeWithSignature(\"balanceOf(address)\", mockUser);\n        bytes[] memory mocks = new bytes[](3);\n        mocks[0] = abi.encode(2 ether);\n        mocks[1] = abi.encode(1 ether);\n        mocks[2] = abi.encode(6.423 ether);\n        vm.mockCalls(mockErc20, data, mocks);\n        (, bytes memory ret1) = mockErc20.call(data);\n        assertEq(abi.decode(ret1, (uint256)), 2 ether);\n        (, bytes memory ret2) = mockErc20.call(data);\n        assertEq(abi.decode(ret2, (uint256)), 1 ether);\n        (, bytes memory ret3) = mockErc20.call(data);\n        assertEq(abi.decode(ret3, (uint256)), 6.423 ether);\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/MockFunction.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ninterface IMockFunctionContract {\n    function a() external view returns (uint256);\n    function mocked_function() external;\n    function mocked_args_function(uint256 x) external;\n}\n\ncontract MockFunctionContract is IMockFunctionContract {\n    uint256 public a;\n\n    function mocked_function() public {\n        a = 321;\n    }\n\n    function mocked_args_function(uint256 x) public {\n        a = 321 + x;\n    }\n}\n\ncontract ModelMockFunctionContract is IMockFunctionContract {\n    uint256 public a;\n\n    function mocked_function() public {\n        a = 123;\n    }\n\n    function mocked_args_function(uint256 x) public {\n        a = 123 + x;\n    }\n}\n\ncontract Proxy {\n    address immutable impl;\n\n    constructor(address impl_) {\n        impl = impl_;\n    }\n\n    fallback() external {\n        _delegate(impl);\n    }\n\n    // code from https://github.com/OpenZeppelin/openzeppelin-contracts/blob/239795bea728c8dca4deb6c66856dd58a6991112/contracts/proxy/Proxy.sol#L22-L45\n    function _delegate(address implementation) internal virtual {\n        assembly {\n            // Copy msg.data. We take full control of memory in this inline assembly\n            // block because it will not return to Solidity code. We overwrite the\n            // Solidity scratch pad at memory position 0.\n            calldatacopy(0x00, 0x00, calldatasize())\n\n            // Call the implementation.\n            // out and outsize are 0 because we don't know the size yet.\n            let result := delegatecall(gas(), implementation, 0x00, calldatasize(), 0x00, 0x00)\n\n            // Copy the returned data.\n            returndatacopy(0x00, 0x00, returndatasize())\n\n            switch result\n            // delegatecall returns 0 on error.\n            case 0 {\n                revert(0x00, returndatasize())\n            }\n            default {\n                return(0x00, returndatasize())\n            }\n        }\n    }\n}\n\ncontract MockFunctionTest is Test {\n    MockFunctionContract my_contract;\n    ModelMockFunctionContract model_contract;\n    IMockFunctionContract my_proxy;\n\n    function setUp() public {\n        my_contract = new MockFunctionContract();\n        model_contract = new ModelMockFunctionContract();\n        my_proxy = IMockFunctionContract(address(new Proxy(address(my_contract))));\n    }\n\n    function test_mock_function() public {\n        vm.mockFunction(\n            address(my_contract),\n            address(model_contract),\n            abi.encodeWithSelector(MockFunctionContract.mocked_function.selector)\n        );\n        my_contract.mocked_function();\n        assertEq(my_contract.a(), 123);\n    }\n\n    function test_mock_function_concrete_args() public {\n        vm.mockFunction(\n            address(my_contract),\n            address(model_contract),\n            abi.encodeWithSelector(MockFunctionContract.mocked_args_function.selector, 456)\n        );\n        my_contract.mocked_args_function(456);\n        assertEq(my_contract.a(), 123 + 456);\n        my_contract.mocked_args_function(567);\n        assertEq(my_contract.a(), 321 + 567);\n    }\n\n    function test_mock_function_all_args() public {\n        vm.mockFunction(\n            address(my_contract),\n            address(model_contract),\n            abi.encodeWithSelector(MockFunctionContract.mocked_args_function.selector)\n        );\n        my_contract.mocked_args_function(678);\n        assertEq(my_contract.a(), 123 + 678);\n        my_contract.mocked_args_function(789);\n        assertEq(my_contract.a(), 123 + 789);\n    }\n\n    function test_mock_function_via_proxy() public {\n        vm.mockFunction(\n            address(my_proxy),\n            address(model_contract),\n            abi.encodeWithSelector(MockFunctionContract.mocked_function.selector)\n        );\n        my_proxy.mocked_function();\n        assertEq(my_proxy.a(), 123, \"mocked function should be called via proxy\");\n\n        // reset mock\n        vm.mockFunction(\n            address(my_proxy), address(my_proxy), abi.encodeWithSelector(MockFunctionContract.mocked_function.selector)\n        );\n        my_proxy.mocked_function();\n        assertEq(my_proxy.a(), 321, \"after reset, original function should be called\");\n    }\n\n    function test_mock_function_via_proxy_concrete_args() public {\n        vm.mockFunction(\n            address(my_proxy),\n            address(model_contract),\n            abi.encodeWithSelector(MockFunctionContract.mocked_args_function.selector, 100)\n        );\n        my_proxy.mocked_args_function(100);\n        assertEq(my_proxy.a(), 123 + 100, \"mocked args function should be called via proxy\");\n        my_proxy.mocked_args_function(200);\n        assertEq(my_proxy.a(), 321 + 200, \"original args function should be called for different args\");\n\n        // reset mock\n        vm.mockFunction(\n            address(my_proxy),\n            address(my_proxy),\n            abi.encodeWithSelector(MockFunctionContract.mocked_args_function.selector, 100)\n        );\n        my_proxy.mocked_args_function(100);\n        assertEq(my_proxy.a(), 321 + 100, \"after reset, original args function should be called\");\n        my_proxy.mocked_args_function(200);\n        assertEq(my_proxy.a(), 321 + 200, \"original args function should be called for different args\");\n    }\n\n    function test_mock_function_via_proxy_all_args() public {\n        vm.mockFunction(\n            address(my_proxy),\n            address(model_contract),\n            abi.encodeWithSelector(MockFunctionContract.mocked_args_function.selector)\n        );\n        my_proxy.mocked_args_function(300);\n        assertEq(my_proxy.a(), 123 + 300, \"mocked args function should be called via proxy\");\n        my_proxy.mocked_args_function(400);\n        assertEq(my_proxy.a(), 123 + 400, \"mocked args function should be called via proxy\");\n\n        // reset mock\n        vm.mockFunction(\n            address(my_proxy),\n            address(my_proxy),\n            abi.encodeWithSelector(MockFunctionContract.mocked_args_function.selector)\n        );\n        my_proxy.mocked_args_function(300);\n        assertEq(my_proxy.a(), 321 + 300, \"after reset, original args function should be called\");\n        my_proxy.mocked_args_function(400);\n        assertEq(my_proxy.a(), 321 + 400, \"after reset, original args function should be called\");\n    }\n\n    function test_mock_function_via_impl() public {\n        vm.mockFunction(\n            address(my_contract),\n            address(model_contract),\n            abi.encodeWithSelector(MockFunctionContract.mocked_function.selector)\n        );\n        my_proxy.mocked_function();\n        assertEq(my_proxy.a(), 123, \"mocked function should be called via impl address\");\n\n        // reset mock\n        vm.mockFunction(\n            address(my_contract),\n            address(my_contract),\n            abi.encodeWithSelector(MockFunctionContract.mocked_function.selector)\n        );\n        my_proxy.mocked_function();\n        assertEq(my_proxy.a(), 321, \"after reset, original function should be called\");\n    }\n\n    function test_mock_function_via_impl_concrete_args() public {\n        vm.mockFunction(\n            address(my_contract),\n            address(model_contract),\n            abi.encodeWithSelector(MockFunctionContract.mocked_args_function.selector, 200)\n        );\n        my_proxy.mocked_args_function(200);\n        assertEq(my_proxy.a(), 123 + 200, \"mocked args function should be called via impl address\");\n        my_proxy.mocked_args_function(300);\n        assertEq(my_proxy.a(), 321 + 300, \"original args function should be called for different args\");\n\n        // reset mock\n        vm.mockFunction(\n            address(my_contract),\n            address(my_contract),\n            abi.encodeWithSelector(MockFunctionContract.mocked_args_function.selector, 200)\n        );\n        my_proxy.mocked_args_function(200);\n        assertEq(my_proxy.a(), 321 + 200, \"after reset, original args function should be called\");\n        my_proxy.mocked_args_function(300);\n        assertEq(my_proxy.a(), 321 + 300, \"original args function should be called for different args\");\n    }\n\n    function test_mock_function_via_impl_all_args() public {\n        vm.mockFunction(\n            address(my_contract),\n            address(model_contract),\n            abi.encodeWithSelector(MockFunctionContract.mocked_args_function.selector)\n        );\n        my_proxy.mocked_args_function(400);\n        assertEq(my_proxy.a(), 123 + 400, \"mocked args function should be called via impl address\");\n        my_proxy.mocked_args_function(500);\n        assertEq(my_proxy.a(), 123 + 500, \"mocked args function should be called via impl address\");\n\n        // reset mock\n        vm.mockFunction(\n            address(my_contract),\n            address(my_contract),\n            abi.encodeWithSelector(MockFunctionContract.mocked_args_function.selector)\n        );\n        my_proxy.mocked_args_function(400);\n        assertEq(my_proxy.a(), 321 + 400, \"after reset, original args function should be called\");\n        my_proxy.mocked_args_function(500);\n        assertEq(my_proxy.a(), 321 + 500, \"after reset, original args function should be called\");\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/Nonce.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract Counter {\n    uint256 public count;\n\n    function increment() public {\n        count += 1;\n    }\n}\n\n/// forge-config: default.isolate = true\ncontract NonceIsolatedTest is Test {\n    function testIncrementNonce() public {\n        address bob = address(14);\n        vm.startPrank(bob);\n        Counter counter = new Counter();\n        assertEq(vm.getNonce(bob), 1);\n        counter.increment();\n        assertEq(vm.getNonce(bob), 2);\n        new Counter();\n        assertEq(vm.getNonce(bob), 3);\n        counter.increment();\n        assertEq(vm.getNonce(bob), 4);\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/Parse.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract ParseTest is Test {\n    function testParseBytes() public {\n        bytes memory testBytes = hex\"7109709ECfa91a80626fF3989D68f67F5b1DD12D\";\n\n        string memory stringBytes = \"0x7109709ECfa91a80626fF3989D68f67F5b1DD12D\";\n        assertEq(testBytes, vm.parseBytes(stringBytes));\n\n        stringBytes = \"7109709ECfa91a80626fF3989D68f67F5b1DD12D\";\n        assertEq(testBytes, vm.parseBytes(stringBytes));\n    }\n\n    function testParseBytesFuzzed(bytes memory testBytes) public {\n        string memory stringBytes = vm.toString(testBytes);\n        assertEq(testBytes, vm.parseBytes(stringBytes));\n    }\n\n    function testParseAddress() public {\n        address testAddress = 0x7109709ECfa91a80626fF3989D68f67F5b1DD12D;\n\n        string memory stringAddress = \"0x7109709ECfa91a80626fF3989D68f67F5b1DD12D\";\n        assertEq(testAddress, vm.parseAddress(stringAddress));\n\n        stringAddress = \"7109709ECfa91a80626fF3989D68f67F5b1DD12D\";\n        assertEq(testAddress, vm.parseAddress(stringAddress));\n    }\n\n    function testParseAddressFuzzed(address testAddress) public {\n        string memory stringAddress = vm.toString(testAddress);\n        assertEq(testAddress, vm.parseAddress(stringAddress));\n    }\n\n    function testParseUint() public {\n        uint256 testUint256 = 420;\n\n        string memory stringUint256 = \"420\";\n        assertEq(testUint256, vm.parseUint(stringUint256));\n    }\n\n    function testParseUintStringBytes() public {\n        uint256 testUint256 = 420;\n\n        string memory stringUint256 = \"0x1A4\";\n        assertEq(testUint256, vm.parseUint(stringUint256));\n    }\n\n    function testParseUintBytes() public {\n        uint256 testUint256 = 420;\n        bytes memory testBytes = hex\"01A4\";\n        string memory stringUint256 = vm.toString(testBytes);\n        assertEq(testUint256, vm.parseUint(stringUint256));\n    }\n\n    function testParseUintFuzzed(uint256 testUint256) public {\n        string memory stringUint256 = vm.toString(testUint256);\n        assertEq(testUint256, vm.parseUint(stringUint256));\n    }\n\n    function testParseInt() public {\n        int256 testInt256 = 420;\n\n        string memory stringInt256 = \"420\";\n        assertEq(testInt256, vm.parseInt(stringInt256));\n    }\n\n    function testParseIntFuzzed(int256 testInt256) public {\n        string memory stringInt256 = vm.toString(testInt256);\n        assertEq(testInt256, vm.parseInt(stringInt256));\n    }\n\n    function testParseBytes32() public {\n        bytes32 testBytes = \"test\";\n\n        string memory stringBytes = \"7465737400000000000000000000000000000000000000000000000000000000\";\n        assertEq(testBytes, vm.parseBytes32(stringBytes));\n\n        stringBytes = \"0x7465737400000000000000000000000000000000000000000000000000000000\";\n        assertEq(testBytes, vm.parseBytes32(stringBytes));\n    }\n\n    function testParseBytes32Fuzzed(bytes32 testBytes) public {\n        string memory stringBytes = vm.toString(testBytes);\n        assertEq(testBytes, vm.parseBytes32(stringBytes));\n    }\n\n    function testParseBool() public {\n        bool testBool = true;\n\n        string memory stringBool = \"true\";\n        assertEq(testBool, vm.parseBool(stringBool));\n    }\n\n    function testParseBoolFuzzed(bool testBool) public {\n        string memory stringBool = vm.toString(testBool);\n        assertEq(testBool, vm.parseBool(stringBool));\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/Prank.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract Victim {\n    function assertCallerAndOrigin(\n        address expectedSender,\n        string memory senderMessage,\n        address expectedOrigin,\n        string memory originMessage\n    ) public view {\n        require(msg.sender == expectedSender, senderMessage);\n        require(tx.origin == expectedOrigin, originMessage);\n    }\n}\n\ncontract ConstructorVictim is Victim {\n    constructor(\n        address expectedSender,\n        string memory senderMessage,\n        address expectedOrigin,\n        string memory originMessage\n    ) {\n        require(msg.sender == expectedSender, senderMessage);\n        require(tx.origin == expectedOrigin, originMessage);\n    }\n}\n\ncontract NestedVictim {\n    Victim innerVictim;\n\n    constructor(Victim victim) {\n        innerVictim = victim;\n    }\n\n    function assertCallerAndOrigin(\n        address expectedSender,\n        string memory senderMessage,\n        address expectedOrigin,\n        string memory originMessage\n    ) public view {\n        require(msg.sender == expectedSender, senderMessage);\n        require(tx.origin == expectedOrigin, originMessage);\n        innerVictim.assertCallerAndOrigin(\n            address(this),\n            \"msg.sender was incorrectly set for nested victim\",\n            expectedOrigin,\n            \"tx.origin was incorrectly set for nested victim\"\n        );\n    }\n}\n\ncontract NestedPranker {\n    Vm constant vm = Vm(address(bytes20(uint160(uint256(keccak256(\"hevm cheat code\"))))));\n\n    address newSender;\n    address newOrigin;\n    address oldOrigin;\n\n    constructor(address _newSender, address _newOrigin) {\n        newSender = _newSender;\n        newOrigin = _newOrigin;\n        oldOrigin = tx.origin;\n    }\n\n    function incompletePrank() public {\n        vm.startPrank(newSender, newOrigin);\n    }\n\n    function completePrank(NestedVictim victim) public {\n        victim.assertCallerAndOrigin(\n            newSender, \"msg.sender was not set in nested prank\", newOrigin, \"tx.origin was not set in nested prank\"\n        );\n        vm.stopPrank();\n\n        // Ensure we cleaned up correctly\n        victim.assertCallerAndOrigin(\n            address(this),\n            \"msg.sender was not cleaned up in nested prank\",\n            oldOrigin,\n            \"tx.origin was not cleaned up in nested prank\"\n        );\n    }\n}\n\ncontract ImplementationTest {\n    uint256 public num;\n    address public sender;\n\n    function assertCorrectCaller(address expectedSender) public {\n        require(msg.sender == expectedSender);\n    }\n\n    function assertCorrectOrigin(address expectedOrigin) public {\n        require(tx.origin == expectedOrigin);\n    }\n\n    function setNum(uint256 _num) public {\n        num = _num;\n    }\n}\n\ncontract ProxyTest {\n    uint256 public num;\n    address public sender;\n}\n\ncontract PrankTest is Test {\n    function testPrankDelegateCallPrank2() public {\n        ProxyTest proxy = new ProxyTest();\n        ImplementationTest impl = new ImplementationTest();\n        vm.prank(address(proxy), true);\n\n        // Assert correct `msg.sender`\n        (bool success,) =\n            address(impl).delegatecall(abi.encodeWithSignature(\"assertCorrectCaller(address)\", address(proxy)));\n        require(success, \"prank2: delegate call failed assertCorrectCaller\");\n\n        // Assert storage updates\n        uint256 num = 42;\n        vm.prank(address(proxy), true);\n        (bool successTwo,) = address(impl).delegatecall(abi.encodeWithSignature(\"setNum(uint256)\", num));\n        require(successTwo, \"prank2: delegate call failed setNum\");\n        require(proxy.num() == num, \"prank2: proxy's storage was not set correctly\");\n        vm.stopPrank();\n    }\n\n    function testPrankDelegateCallStartPrank2() public {\n        ProxyTest proxy = new ProxyTest();\n        ImplementationTest impl = new ImplementationTest();\n        vm.startPrank(address(proxy), true);\n\n        // Assert correct `msg.sender`\n        (bool success,) =\n            address(impl).delegatecall(abi.encodeWithSignature(\"assertCorrectCaller(address)\", address(proxy)));\n        require(success, \"startPrank2: delegate call failed assertCorrectCaller\");\n\n        // Assert storage updates\n        uint256 num = 42;\n        (bool successTwo,) = address(impl).delegatecall(abi.encodeWithSignature(\"setNum(uint256)\", num));\n        require(successTwo, \"startPrank2: delegate call failed setNum\");\n        require(proxy.num() == num, \"startPrank2: proxy's storage was not set correctly\");\n        vm.stopPrank();\n    }\n\n    function testPrankDelegateCallPrank3(address origin) public {\n        ProxyTest proxy = new ProxyTest();\n        ImplementationTest impl = new ImplementationTest();\n        vm.prank(address(proxy), origin, true);\n\n        // Assert correct `msg.sender`\n        (bool success,) =\n            address(impl).delegatecall(abi.encodeWithSignature(\"assertCorrectCaller(address)\", address(proxy)));\n        require(success, \"prank3: delegate call failed assertCorrectCaller\");\n\n        // Assert correct `tx.origin`\n        vm.prank(address(proxy), origin, true);\n        (bool successTwo,) = address(impl).delegatecall(abi.encodeWithSignature(\"assertCorrectOrigin(address)\", origin));\n        require(successTwo, \"prank3: delegate call failed assertCorrectOrigin\");\n\n        // Assert storage updates\n        uint256 num = 42;\n        vm.prank(address(proxy), address(origin), true);\n        (bool successThree,) = address(impl).delegatecall(abi.encodeWithSignature(\"setNum(uint256)\", num));\n        require(successThree, \"prank3: delegate call failed setNum\");\n        require(proxy.num() == num, \"prank3: proxy's storage was not set correctly\");\n        vm.stopPrank();\n    }\n\n    function testPrankDelegateCallStartPrank3(address origin) public {\n        ProxyTest proxy = new ProxyTest();\n        ImplementationTest impl = new ImplementationTest();\n        vm.startPrank(address(proxy), origin, true);\n\n        // Assert correct `msg.sender`\n        (bool success,) =\n            address(impl).delegatecall(abi.encodeWithSignature(\"assertCorrectCaller(address)\", address(proxy)));\n        require(success, \"startPrank3: delegate call failed assertCorrectCaller\");\n\n        // Assert correct `tx.origin`\n        (bool successTwo,) = address(impl).delegatecall(abi.encodeWithSignature(\"assertCorrectOrigin(address)\", origin));\n        require(successTwo, \"startPrank3: delegate call failed assertCorrectOrigin\");\n\n        // Assert storage updates\n        uint256 num = 42;\n        (bool successThree,) = address(impl).delegatecall(abi.encodeWithSignature(\"setNum(uint256)\", num));\n        require(successThree, \"startPrank3: delegate call failed setNum\");\n        require(proxy.num() == num, \"startPrank3: proxy's storage was not set correctly\");\n        vm.stopPrank();\n    }\n\n    /// forge-config: default.allow_internal_expect_revert = true\n    function testRevertIfPrankDelegateCalltoEOA() public {\n        uint256 privateKey = uint256(keccak256(abi.encodePacked(\"alice\")));\n        address alice = vm.addr(privateKey);\n        ImplementationTest impl = new ImplementationTest();\n        vm.expectRevert(\"vm.prank: cannot `prank` delegate call from an EOA\");\n        vm.prank(alice, true);\n        // Should fail when EOA pranked with delegatecall.\n        (bool success,) = address(impl).delegatecall(abi.encodeWithSignature(\"assertCorrectCaller(address)\", alice));\n        require(success, \"delegate call failed\");\n    }\n\n    function testPrankSender(address sender) public {\n        // Perform the prank\n        Victim victim = new Victim();\n        vm.prank(sender);\n        victim.assertCallerAndOrigin(\n            sender, \"msg.sender was not set during prank\", tx.origin, \"tx.origin invariant failed\"\n        );\n\n        // Ensure we cleaned up correctly\n        victim.assertCallerAndOrigin(\n            address(this), \"msg.sender was not cleaned up\", tx.origin, \"tx.origin invariant failed\"\n        );\n    }\n\n    function testPrankOrigin(address sender, address origin) public {\n        address oldOrigin = tx.origin;\n\n        // Perform the prank\n        Victim victim = new Victim();\n        vm.prank(sender, origin);\n        victim.assertCallerAndOrigin(\n            sender, \"msg.sender was not set during prank\", origin, \"tx.origin was not set during prank\"\n        );\n\n        // Ensure we cleaned up correctly\n        victim.assertCallerAndOrigin(\n            address(this), \"msg.sender was not cleaned up\", oldOrigin, \"tx.origin was not cleaned up\"\n        );\n    }\n\n    function testPrank1AfterPrank0(address sender, address origin) public {\n        // Perform the prank\n        address oldOrigin = tx.origin;\n        Victim victim = new Victim();\n        vm.prank(sender);\n        victim.assertCallerAndOrigin(\n            sender, \"msg.sender was not set during prank\", oldOrigin, \"tx.origin was not set during prank\"\n        );\n\n        // Ensure we cleaned up correctly\n        victim.assertCallerAndOrigin(\n            address(this), \"msg.sender was not cleaned up\", oldOrigin, \"tx.origin invariant failed\"\n        );\n\n        // Overwrite the prank\n        vm.prank(sender, origin);\n        victim.assertCallerAndOrigin(\n            sender, \"msg.sender was not set during prank\", origin, \"tx.origin invariant failed\"\n        );\n\n        // Ensure we cleaned up correctly\n        victim.assertCallerAndOrigin(\n            address(this), \"msg.sender was not cleaned up\", oldOrigin, \"tx.origin invariant failed\"\n        );\n    }\n\n    function testPrank0AfterPrank1(address sender, address origin) public {\n        // Perform the prank\n        address oldOrigin = tx.origin;\n        Victim victim = new Victim();\n        vm.prank(sender, origin);\n        victim.assertCallerAndOrigin(\n            sender, \"msg.sender was not set during prank\", origin, \"tx.origin was not set during prank\"\n        );\n\n        // Ensure we cleaned up correctly\n        victim.assertCallerAndOrigin(\n            address(this), \"msg.sender was not cleaned up\", oldOrigin, \"tx.origin invariant failed\"\n        );\n\n        // Overwrite the prank\n        vm.prank(sender);\n        victim.assertCallerAndOrigin(\n            sender, \"msg.sender was not set during prank\", oldOrigin, \"tx.origin invariant failed\"\n        );\n\n        // Ensure we cleaned up correctly\n        victim.assertCallerAndOrigin(\n            address(this), \"msg.sender was not cleaned up\", oldOrigin, \"tx.origin invariant failed\"\n        );\n    }\n\n    function testStartPrank0AfterPrank1(address sender, address origin) public {\n        // Perform the prank\n        address oldOrigin = tx.origin;\n        Victim victim = new Victim();\n        vm.startPrank(sender, origin);\n        victim.assertCallerAndOrigin(\n            sender, \"msg.sender was not set during prank\", origin, \"tx.origin was not set during prank\"\n        );\n\n        // Overwrite the prank\n        vm.startPrank(sender);\n        victim.assertCallerAndOrigin(\n            sender, \"msg.sender was not set during prank\", oldOrigin, \"tx.origin invariant failed\"\n        );\n\n        vm.stopPrank();\n        // Ensure we cleaned up correctly after stopping the prank\n        victim.assertCallerAndOrigin(\n            address(this), \"msg.sender was not cleaned up\", oldOrigin, \"tx.origin invariant failed\"\n        );\n    }\n\n    function testStartPrank1AfterStartPrank0(address sender, address origin) public {\n        // Perform the prank\n        address oldOrigin = tx.origin;\n        Victim victim = new Victim();\n        vm.startPrank(sender);\n        victim.assertCallerAndOrigin(\n            sender, \"msg.sender was not set during prank\", oldOrigin, \"tx.origin was set during prank incorrectly\"\n        );\n\n        // Ensure prank is still up as startPrank covers multiple calls\n        victim.assertCallerAndOrigin(\n            sender, \"msg.sender was cleaned up incorrectly\", oldOrigin, \"tx.origin invariant failed\"\n        );\n\n        // Overwrite the prank\n        vm.startPrank(sender, origin);\n        victim.assertCallerAndOrigin(sender, \"msg.sender was not set during prank\", origin, \"tx.origin was not set\");\n\n        // Ensure prank is still up as startPrank covers multiple calls\n        victim.assertCallerAndOrigin(\n            sender, \"msg.sender was cleaned up incorrectly\", origin, \"tx.origin invariant failed\"\n        );\n\n        vm.stopPrank();\n        // Ensure everything is back to normal after stopPrank\n        victim.assertCallerAndOrigin(\n            address(this), \"msg.sender was not cleaned up\", oldOrigin, \"tx.origin invariant failed\"\n        );\n    }\n\n    /// forge-config: default.allow_internal_expect_revert = true\n    function testRevertIfOverwriteUnusedPrank(address sender, address origin) public {\n        // Set the prank, but not use it\n        address oldOrigin = tx.origin;\n        Victim victim = new Victim();\n        vm.startPrank(sender, origin);\n        // try to overwrite the prank. This should fail.\n        vm.expectRevert(\"vm.startPrank: cannot overwrite a prank until it is applied at least once\");\n        vm.startPrank(address(this), origin);\n    }\n\n    /// forge-config: default.allow_internal_expect_revert = true\n    function testRevertIfOverwriteUnusedPrankAfterSuccessfulPrank(address sender, address origin) public {\n        // Set the prank, but not use it\n        address oldOrigin = tx.origin;\n        Victim victim = new Victim();\n        vm.startPrank(sender, origin);\n        victim.assertCallerAndOrigin(\n            sender, \"msg.sender was not set during prank\", origin, \"tx.origin was set during prank incorrectly\"\n        );\n        vm.startPrank(address(this), origin);\n        // try to overwrite the prank. This should fail.\n        vm.expectRevert(\"vm.startPrank: cannot overwrite a prank until it is applied at least once\");\n        vm.startPrank(sender, origin);\n    }\n\n    function testStartPrank0AfterStartPrank1(address sender, address origin) public {\n        // Perform the prank\n        address oldOrigin = tx.origin;\n        Victim victim = new Victim();\n        vm.startPrank(sender, origin);\n        victim.assertCallerAndOrigin(\n            sender, \"msg.sender was not set during prank\", origin, \"tx.origin was not set during prank\"\n        );\n\n        // Ensure prank is still ongoing as we haven't called stopPrank\n        victim.assertCallerAndOrigin(\n            sender, \"msg.sender was cleaned up incorrectly\", origin, \"tx.origin was cleaned up incorrectly\"\n        );\n\n        // Overwrite the prank\n        vm.startPrank(sender);\n        victim.assertCallerAndOrigin(\n            sender, \"msg.sender was not set during prank\", oldOrigin, \"tx.origin was not reset correctly\"\n        );\n\n        vm.stopPrank();\n        // Ensure we cleaned up correctly\n        victim.assertCallerAndOrigin(\n            address(this), \"msg.sender was not cleaned up\", oldOrigin, \"tx.origin invariant failed\"\n        );\n    }\n\n    function testPrankConstructorSender(address sender) public {\n        vm.prank(sender);\n        ConstructorVictim victim = new ConstructorVictim(\n            sender, \"msg.sender was not set during prank\", tx.origin, \"tx.origin invariant failed\"\n        );\n\n        // Ensure we cleaned up correctly\n        victim.assertCallerAndOrigin(\n            address(this), \"msg.sender was not cleaned up\", tx.origin, \"tx.origin invariant failed\"\n        );\n    }\n\n    function testPrankConstructorOrigin(address sender, address origin) public {\n        // Perform the prank\n        vm.prank(sender, origin);\n        ConstructorVictim victim = new ConstructorVictim(\n            sender, \"msg.sender was not set during prank\", origin, \"tx.origin was not set during prank\"\n        );\n\n        // Ensure we cleaned up correctly\n        victim.assertCallerAndOrigin(\n            address(this), \"msg.sender was not cleaned up\", tx.origin, \"tx.origin was not cleaned up\"\n        );\n    }\n\n    function testPrankStartStop(address sender, address origin) public {\n        address oldOrigin = tx.origin;\n\n        // Perform the prank\n        Victim victim = new Victim();\n        vm.startPrank(sender, origin);\n        victim.assertCallerAndOrigin(\n            sender, \"msg.sender was not set during prank\", origin, \"tx.origin was not set during prank\"\n        );\n        victim.assertCallerAndOrigin(\n            sender,\n            \"msg.sender was not set during prank (call 2)\",\n            origin,\n            \"tx.origin was not set during prank (call 2)\"\n        );\n        vm.stopPrank();\n\n        // Ensure we cleaned up correctly\n        victim.assertCallerAndOrigin(\n            address(this), \"msg.sender was not cleaned up\", oldOrigin, \"tx.origin was not cleaned up\"\n        );\n    }\n\n    function testPrankStartStopConstructor(address sender, address origin) public {\n        // Perform the prank\n        vm.startPrank(sender, origin);\n        ConstructorVictim victim = new ConstructorVictim(\n            sender, \"msg.sender was not set during prank\", origin, \"tx.origin was not set during prank\"\n        );\n        new ConstructorVictim(\n            sender,\n            \"msg.sender was not set during prank (call 2)\",\n            origin,\n            \"tx.origin was not set during prank (call 2)\"\n        );\n        vm.stopPrank();\n\n        // Ensure we cleaned up correctly\n        victim.assertCallerAndOrigin(\n            address(this), \"msg.sender was not cleaned up\", tx.origin, \"tx.origin was not cleaned up\"\n        );\n    }\n\n    /// This test checks that depth is working correctly with respect\n    /// to the `startPrank` and `stopPrank` cheatcodes.\n    ///\n    /// The nested pranker calls `startPrank` but does not call\n    /// `stopPrank` at first.\n    ///\n    /// Then, we call our victim from the main test: this call\n    /// should NOT have altered `msg.sender` or `tx.origin`.\n    ///\n    /// Then, the nested pranker will complete their prank: this call\n    /// SHOULD have altered `msg.sender` and `tx.origin`.\n    ///\n    /// Each call to the victim calls yet another victim. The expected\n    /// behavior for this call is that `tx.origin` is altered when\n    /// the nested pranker calls, otherwise not. In both cases,\n    /// `msg.sender` should be the address of the first victim.\n    ///\n    /// Success case:\n    ///\n    /// ┌────┐          ┌───────┐     ┌──────┐ ┌──────┐               ┌────────────┐\n    /// │Test│          │Pranker│     │Vm│ │Victim│               │Inner Victim│\n    /// └─┬──┘          └───┬───┘     └──┬───┘ └──┬───┘               └─────┬──────┘\n    ///   │                 │            │        │                         │\n    ///   │incompletePrank()│            │        │                         │\n    ///   │────────────────>│            │        │                         │\n    ///   │                 │            │        │                         │\n    ///   │                 │startPrank()│        │                         │\n    ///   │                 │───────────>│        │                         │\n    ///   │                 │            │        │                         │\n    ///   │         should not be pranked│        │                         │\n    ///   │──────────────────────────────────────>│                         │\n    ///   │                 │            │        │                         │\n    ///   │                 │            │        │  should not be pranked  │\n    ///   │                 │            │        │────────────────────────>│\n    ///   │                 │            │        │                         │\n    ///   │ completePrank() │            │        │                         │\n    ///   │────────────────>│            │        │                         │\n    ///   │                 │            │        │                         │\n    ///   │                 │  should be pranked  │                         │\n    ///   │                 │────────────────────>│                         │\n    ///   │                 │            │        │                         │\n    ///   │                 │            │        │only tx.origin is pranked│\n    ///   │                 │            │        │────────────────────────>│\n    ///   │                 │            │        │                         │\n    ///   │                 │stopPrank() │        │                         │\n    ///   │                 │───────────>│        │                         │\n    ///   │                 │            │        │                         │\n    ///   │                 │should not be pranked│                         │\n    ///   │                 │────────────────────>│                         │\n    ///   │                 │            │        │                         │\n    ///   │                 │            │        │  should not be pranked  │\n    ///   │                 │            │        │────────────────────────>│\n    /// ┌─┴──┐          ┌───┴───┐     ┌──┴───┐ ┌──┴───┐               ┌─────┴──────┐\n    /// │Test│          │Pranker│     │Vm│ │Victim│               │Inner Victim│\n    /// └────┘          └───────┘     └──────┘ └──────┘               └────────────┘\n    /// If this behavior is incorrectly implemented then the victim\n    /// will be pranked the first time it is called.\n    function testPrankComplex(address sender, address origin) public {\n        address oldOrigin = tx.origin;\n\n        NestedPranker pranker = new NestedPranker(sender, origin);\n        Victim innerVictim = new Victim();\n        NestedVictim victim = new NestedVictim(innerVictim);\n\n        pranker.incompletePrank();\n        victim.assertCallerAndOrigin(\n            address(this),\n            \"msg.sender was altered at an incorrect depth\",\n            oldOrigin,\n            \"tx.origin was altered at an incorrect depth\"\n        );\n\n        pranker.completePrank(victim);\n    }\n\n    /// Checks that `tx.origin` is set for all subcalls of a `prank`.\n    ///\n    /// Ref: issue #1210\n    function testTxOriginInNestedPrank(address sender, address origin) public {\n        address oldSender = msg.sender;\n        address oldOrigin = tx.origin;\n\n        Victim innerVictim = new Victim();\n        NestedVictim victim = new NestedVictim(innerVictim);\n\n        vm.prank(sender, origin);\n        victim.assertCallerAndOrigin(\n            sender, \"msg.sender was not set correctly\", origin, \"tx.origin was not set correctly\"\n        );\n    }\n}\n\ncontract Issue9990 is Test {\n    function testDelegatePrank() external {\n        A a = new A();\n        vm.etch(address(0x11111), hex\"11\");\n        vm.startPrank(address(0x11111), true);\n        (bool success,) = address(a).delegatecall(abi.encodeWithSelector(A.foo.selector));\n        require(success, \"MyTest: error calling foo on A\");\n        vm.stopPrank();\n    }\n}\n\n// Contracts for DELEGATECALL test case: testDelegatePrank\ncontract A {\n    function foo() external {\n        require(address(0x11111) == msg.sender, \"wrong msg.sender in A\");\n        require(address(0x11111) == address(this), \"wrong address(this) in A\");\n        B b = new B();\n        (bool success,) = address(b).call(abi.encodeWithSelector(B.bar.selector));\n        require(success, \"A: error calling B.bar\");\n    }\n}\n\ncontract B {\n    function bar() external {\n        require(address(0x11111) == msg.sender, \"wrong msg.sender in B\");\n        require(0x769A6A5f81bD725e4302751162A7cb30482A222d == address(this), \"wrong address(this) in B\");\n        C c = new C();\n        (bool success,) = address(c).delegatecall(abi.encodeWithSelector(C.bar.selector));\n        require(success, \"B: error calling C.bar\");\n    }\n}\n\ncontract C {\n    function bar() external view {\n        require(address(0x11111) == msg.sender, \"wrong msg.sender in C\");\n        require(0x769A6A5f81bD725e4302751162A7cb30482A222d == address(this), \"wrong address(this) in C\");\n    }\n}\n\ncontract Counter {\n    uint256 number;\n\n    function increment() external {\n        number++;\n    }\n}\n\ncontract Issue10528 is Test {\n    function testStartPrankOnContractCreation() external {\n        vm.startPrank(address(0x22222));\n        Counter counter = new Counter();\n\n        vm.startPrank(address(0x11111));\n        counter.increment();\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/Prevrandao.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract PrevrandaoTest is Test {\n    function testPrevrandao() public {\n        assertEq(block.prevrandao, 0);\n        vm.prevrandao(uint256(10));\n        assertEq(block.prevrandao, 10, \"prevrandao cheatcode failed\");\n    }\n\n    function testPrevrandaoFuzzed(uint256 newPrevrandao) public {\n        vm.assume(newPrevrandao != block.prevrandao);\n        assertEq(block.prevrandao, 0);\n        vm.prevrandao(newPrevrandao);\n        assertEq(block.prevrandao, newPrevrandao);\n    }\n\n    function testPrevrandaoSnapshotFuzzed(uint256 newPrevrandao) public {\n        vm.assume(newPrevrandao != block.prevrandao);\n        uint256 oldPrevrandao = block.prevrandao;\n        uint256 snapshotId = vm.snapshotState();\n\n        vm.prevrandao(newPrevrandao);\n        assertEq(block.prevrandao, newPrevrandao);\n\n        assert(vm.revertToState(snapshotId));\n        assertEq(block.prevrandao, oldPrevrandao);\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/ProjectRoot.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract ProjectRootTest is Test {\n    bytes public manifestDirBytes;\n\n    function testProjectRoot() public {\n        // .../crates/forge\n        string memory manifestDir = vm.envOr(\"CARGO_MANIFEST_DIR\", string(\"\"));\n        if (bytes(manifestDir).length == 0) {\n            vm.skip(true, \"CARGO_MANIFEST_DIR environment variable is not set\");\n        }\n        manifestDirBytes = bytes(manifestDir);\n\n        for (uint256 i = 0; i < 7; i++) {\n            manifestDirBytes.pop();\n        }\n        // replace \"forge\" suffix with \"testdata\" suffix to get expected project root from manifest dir\n        bytes memory expectedRootSuffix = bytes(\"testd\");\n        for (uint256 i = 1; i < 6; i++) {\n            manifestDirBytes[manifestDirBytes.length - i] = expectedRootSuffix[expectedRootSuffix.length - i];\n        }\n        bytes memory expectedRootDir = abi.encodePacked(manifestDirBytes, \"ata\");\n\n        assertEq(normalizePath(vm.projectRoot()), normalizePath(string(expectedRootDir)));\n    }\n\n    function normalizePath(string memory path) internal pure returns (string memory) {\n        return vm.replace(path, \"\\\\\", \"/\");\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/Prompt.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\n// All `prompt` functions should revert in CI and testing environments either\n// with a timeout or because no terminal is available.\ncontract PromptTest is Test {\n    function testPrompt_revertNotATerminal() public {\n        checkTty();\n\n        vm._expectCheatcodeRevert();\n        vm.prompt(\"test\");\n\n        vm._expectCheatcodeRevert();\n        vm.promptSecret(\"test\");\n\n        vm._expectCheatcodeRevert();\n        uint256 test = vm.promptSecretUint(\"test\");\n    }\n\n    function testPrompt_Address() public {\n        checkTty();\n\n        vm._expectCheatcodeRevert();\n        address test = vm.promptAddress(\"test\");\n    }\n\n    function testPrompt_Uint() public {\n        checkTty();\n\n        vm._expectCheatcodeRevert();\n        uint256 test = vm.promptUint(\"test\");\n    }\n\n    function checkTty() internal {\n        if (!vm.envOr(\"CI\", false)) {\n            vm.skip(true, \"min timeout is 1s, don't test it\");\n        }\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/RandomAddress.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract RandomAddress is Test {\n    function testRandomAddress() public {\n        vm.randomAddress();\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/RandomBytes.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract RandomBytes is Test {\n    function testRandomBytes4() public {\n        vm.randomBytes4();\n    }\n\n    function testRandomBytes8() public {\n        vm.randomBytes8();\n    }\n\n    function testFillrandomBytes() public view {\n        uint256 len = 16;\n        vm.randomBytes(len);\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/RandomCheatcodes.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract RandomCheatcodesTest is Test {\n    int128 constant min = -170141183460469231731687303715884105728;\n    int128 constant max = 170141183460469231731687303715884105727;\n\n    function test_int128() public {\n        vm._expectCheatcodeRevert(\"vm.randomInt: number of bits cannot exceed 256\");\n        int256 val = vm.randomInt(type(uint256).max);\n\n        val = vm.randomInt(128);\n        assertGe(val, min);\n        assertLe(val, max);\n    }\n\n    /// forge-config: default.allow_internal_expect_revert = true\n    function testReverttIf_int128() public {\n        int256 val = vm.randomInt(128);\n        vm.expectRevert(\"Error: a > b not satisfied [int]\");\n        require(val > max, \"Error: a > b not satisfied [int]\");\n    }\n\n    function test_address() public {\n        address fresh_address = vm.randomAddress();\n        assert(fresh_address != address(this));\n        assert(fresh_address != address(vm));\n    }\n\n    function test_randomUintLimit() public {\n        vm._expectCheatcodeRevert(\"vm.randomUint: number of bits cannot exceed 256\");\n        uint256 val = vm.randomUint(type(uint256).max);\n    }\n\n    function test_randomUints(uint256 x) public {\n        x = vm.randomUint(0, 256);\n        uint256 freshUint = vm.randomUint(x);\n\n        assert(0 <= freshUint);\n        if (x == 256) {\n            assert(freshUint <= type(uint256).max);\n        } else {\n            assert(freshUint <= 2 ** x - 1);\n        }\n    }\n\n    function test_randomSymbolicWord() public {\n        uint256 freshUint192 = vm.randomUint(192);\n\n        assert(0 <= freshUint192);\n        assert(freshUint192 <= type(uint192).max);\n    }\n}\n\ncontract RandomBytesTest is Test {\n    bytes1 local_byte;\n    bytes local_bytes;\n\n    function manip_symbolic_bytes(bytes memory b) public {\n        uint256 middle = b.length / 2;\n        b[middle] = hex\"aa\";\n    }\n\n    function test_symbolic_bytes_revert() public {\n        vm._expectCheatcodeRevert();\n        bytes memory val = vm.randomBytes(type(uint256).max);\n    }\n\n    function test_symbolic_bytes_1() public {\n        uint256 length = uint256(vm.randomUint(1, type(uint8).max));\n        bytes memory fresh_bytes = vm.randomBytes(length);\n        uint256 index = uint256(vm.randomUint(1));\n\n        local_byte = fresh_bytes[index];\n        assertEq(fresh_bytes[index], local_byte);\n    }\n\n    function test_symbolic_bytes_2() public {\n        uint256 length = uint256(vm.randomUint(1, type(uint8).max));\n        bytes memory fresh_bytes = vm.randomBytes(length);\n\n        local_bytes = fresh_bytes;\n        assertEq(fresh_bytes, local_bytes);\n    }\n\n    function test_symbolic_bytes_3() public {\n        uint256 length = uint256(vm.randomUint(1, type(uint8).max));\n        bytes memory fresh_bytes = vm.randomBytes(length);\n\n        manip_symbolic_bytes(fresh_bytes);\n        assertEq(hex\"aa\", fresh_bytes[length / 2]);\n    }\n\n    function test_symbolic_bytes_length(uint8 l) public {\n        vm.assume(0 < l);\n        bytes memory fresh_bytes = vm.randomBytes(l);\n        assertEq(fresh_bytes.length, l);\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/RandomUint.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract RandomUint is Test {\n    function testRandomUint() public {\n        vm.randomUint();\n    }\n\n    function testRandomUintRangeOverflow() public {\n        vm.randomUint(0, uint256(int256(-1)));\n    }\n\n    function testRandomUintSame(uint256 val) public {\n        uint256 rand = vm.randomUint(val, val);\n        assertTrue(rand == val);\n    }\n\n    function testRandomUintRange(uint256 min, uint256 max) public {\n        vm.assume(max >= min);\n        uint256 rand = vm.randomUint(min, max);\n        assertTrue(rand >= min, \"rand >= min\");\n        assertTrue(rand <= max, \"rand <= max\");\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/ReadCallers.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract Target {\n    function consumeNewCaller() external {}\n}\n\ncontract ReadCallersTest is Test {\n    function testReadCallersWithNoActivePrankOrBroadcast() public {\n        address expectedSender = msg.sender;\n        address expectedTxOrigin = tx.origin;\n\n        (Vm.CallerMode mode, address newSender, address newOrigin) = vm.readCallers();\n\n        assertEq(uint256(mode), uint256(Vm.CallerMode.None));\n        assertEq(newSender, expectedSender);\n        assertEq(newOrigin, expectedTxOrigin);\n    }\n\n    // Prank Tests\n    function testReadCallersWithActivePrankForMsgSender(address sender) public {\n        vm.prank(sender);\n        address expectedTxOrigin = tx.origin;\n\n        (Vm.CallerMode mode, address newSender, address newOrigin) = vm.readCallers();\n\n        assertEq(uint256(mode), uint256(Vm.CallerMode.Prank));\n        assertEq(newSender, sender);\n        assertEq(newOrigin, expectedTxOrigin);\n    }\n\n    function testReadCallersWithActivePrankForMsgSenderAndTxOrigin(address sender, address origin) public {\n        vm.prank(sender, origin);\n\n        (Vm.CallerMode mode, address newSender, address newOrigin) = vm.readCallers();\n\n        assertEq(uint256(mode), uint256(Vm.CallerMode.Prank));\n        assertEq(newSender, sender);\n        assertEq(newOrigin, origin);\n    }\n\n    function testReadCallersAfterConsumingMsgSenderPrank(address sender) public {\n        Target target = new Target();\n        address expectedSender = msg.sender;\n        address expectedTxOrigin = tx.origin;\n\n        vm.prank(sender);\n\n        target.consumeNewCaller();\n        (Vm.CallerMode mode, address newSender, address newOrigin) = vm.readCallers();\n\n        assertEq(uint256(mode), uint256(Vm.CallerMode.None));\n        assertEq(newSender, expectedSender);\n        assertEq(newOrigin, expectedTxOrigin);\n    }\n\n    function testReadCallersAfterConsumingMsgSenderAndTxOriginPrank(address sender, address origin) public {\n        Target target = new Target();\n        address expectedSender = msg.sender;\n        address expectedTxOrigin = tx.origin;\n\n        vm.prank(sender, origin);\n\n        target.consumeNewCaller();\n        (Vm.CallerMode mode, address newSender, address newOrigin) = vm.readCallers();\n\n        assertEq(uint256(mode), uint256(Vm.CallerMode.None));\n        assertEq(newSender, expectedSender);\n        assertEq(newOrigin, expectedTxOrigin);\n    }\n\n    function testReadCallersWithActiveRecurrentMsgSenderPrank(address sender) public {\n        address expectedTxOrigin = tx.origin;\n        Target target = new Target();\n        vm.startPrank(sender);\n\n        for (uint256 i = 0; i < 5; i++) {\n            target.consumeNewCaller();\n            (Vm.CallerMode mode, address newSender, address newOrigin) = vm.readCallers();\n\n            assertEq(uint256(mode), uint256(Vm.CallerMode.RecurrentPrank));\n            assertEq(newSender, sender);\n            assertEq(newOrigin, expectedTxOrigin);\n        }\n    }\n\n    function testReadCallersWithActiveRecurrentMsgSenderAndTxOriginPrank(address sender, address origin) public {\n        Target target = new Target();\n        vm.startPrank(sender, origin);\n\n        for (uint256 i = 0; i < 5; i++) {\n            target.consumeNewCaller();\n            (Vm.CallerMode mode, address newSender, address newOrigin) = vm.readCallers();\n\n            assertEq(uint256(mode), uint256(Vm.CallerMode.RecurrentPrank));\n            assertEq(newSender, sender);\n            assertEq(newOrigin, origin);\n        }\n    }\n\n    function testReadCallersAfterStoppingRecurrentMsgSenderPrank(address sender) public {\n        address expectedSender = msg.sender;\n        address expectedTxOrigin = tx.origin;\n        vm.startPrank(sender);\n\n        vm.stopPrank();\n\n        (Vm.CallerMode mode, address newSender, address newOrigin) = vm.readCallers();\n\n        assertEq(uint256(mode), uint256(Vm.CallerMode.None));\n        assertEq(newSender, expectedSender);\n        assertEq(newOrigin, expectedTxOrigin);\n    }\n\n    function testReadCallersAfterStoppingRecurrentMsgSenderAndTxOriginPrank(address sender, address origin) public {\n        address expectedSender = msg.sender;\n        address expectedTxOrigin = tx.origin;\n        vm.startPrank(sender, origin);\n\n        vm.stopPrank();\n\n        (Vm.CallerMode mode, address newSender, address newOrigin) = vm.readCallers();\n\n        assertEq(uint256(mode), uint256(Vm.CallerMode.None));\n        assertEq(newSender, expectedSender);\n        assertEq(newOrigin, expectedTxOrigin);\n    }\n\n    // Broadcast Tests\n    function testReadCallersWithActiveBroadcast(address sender) public {\n        vm.broadcast(sender);\n\n        (Vm.CallerMode mode, address newSender, address newOrigin) = vm.readCallers();\n\n        assertEq(uint256(mode), uint256(Vm.CallerMode.Broadcast));\n        assertEq(newSender, sender);\n        assertEq(newOrigin, sender);\n    }\n\n    function testReadCallersAfterConsumingBroadcast(address sender) public {\n        Target target = new Target();\n        address expectedSender = msg.sender;\n        address expectedTxOrigin = tx.origin;\n\n        vm.broadcast(sender);\n\n        target.consumeNewCaller();\n        (Vm.CallerMode mode, address newSender, address newOrigin) = vm.readCallers();\n\n        assertEq(uint256(mode), uint256(Vm.CallerMode.None));\n        assertEq(newSender, expectedSender);\n        assertEq(newOrigin, expectedTxOrigin);\n    }\n\n    function testReadCallersWithActiveRecurrentBroadcast(address sender) public {\n        Target target = new Target();\n        vm.startBroadcast(sender);\n\n        for (uint256 i = 0; i < 5; i++) {\n            target.consumeNewCaller();\n            (Vm.CallerMode mode, address newSender, address newOrigin) = vm.readCallers();\n\n            assertEq(uint256(mode), uint256(Vm.CallerMode.RecurrentBroadcast));\n            assertEq(newSender, sender);\n            assertEq(newOrigin, sender);\n        }\n    }\n\n    function testReadCallersAfterStoppingRecurrentBroadcast(address sender) public {\n        address expectedSender = msg.sender;\n        address expectedTxOrigin = tx.origin;\n        vm.startBroadcast(sender);\n\n        vm.stopBroadcast();\n\n        (Vm.CallerMode mode, address newSender, address newOrigin) = vm.readCallers();\n\n        assertEq(uint256(mode), uint256(Vm.CallerMode.None));\n        assertEq(newSender, expectedSender);\n        assertEq(newOrigin, expectedTxOrigin);\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/Record.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract RecordAccess {\n    function record() public returns (NestedRecordAccess) {\n        assembly {\n            sstore(1, add(sload(1), 1))\n        }\n\n        NestedRecordAccess inner = new NestedRecordAccess();\n        inner.record();\n\n        return inner;\n    }\n}\n\ncontract NestedRecordAccess {\n    function record() public {\n        assembly {\n            sstore(2, add(sload(2), 1))\n        }\n    }\n}\n\ncontract RecordTest is Test {\n    function testRecordAccess() public {\n        RecordAccess target = new RecordAccess();\n\n        // Start recording\n        vm.record();\n        NestedRecordAccess inner = target.record();\n\n        // Verify Records\n        (bytes32[] memory reads, bytes32[] memory writes) = vm.accesses(address(target));\n        (bytes32[] memory innerReads, bytes32[] memory innerWrites) = vm.accesses(address(inner));\n\n        assertEq(reads.length, 2, \"number of reads is incorrect\");\n        assertEq(reads[0], bytes32(uint256(1)), \"key for read 0 is incorrect\");\n        assertEq(reads[1], bytes32(uint256(1)), \"key for read 1 is incorrect\");\n\n        assertEq(writes.length, 1, \"number of writes is incorrect\");\n        assertEq(writes[0], bytes32(uint256(1)), \"key for write is incorrect\");\n\n        assertEq(innerReads.length, 2, \"number of nested reads is incorrect\");\n        assertEq(innerReads[0], bytes32(uint256(2)), \"key for nested read 0 is incorrect\");\n        assertEq(innerReads[1], bytes32(uint256(2)), \"key for nested read 1 is incorrect\");\n\n        assertEq(innerWrites.length, 1, \"number of nested writes is incorrect\");\n        assertEq(innerWrites[0], bytes32(uint256(2)), \"key for nested write is incorrect\");\n    }\n\n    function testStopRecordAccess() public {\n        RecordAccess target = new RecordAccess();\n\n        // Start recording\n        vm.record();\n        NestedRecordAccess inner = target.record();\n\n        // Verify Records\n        (bytes32[] memory reads, bytes32[] memory writes) = vm.accesses(address(target));\n\n        assertEq(reads.length, 2, \"number of reads is incorrect\");\n        assertEq(reads[0], bytes32(uint256(1)), \"key for read 0 is incorrect\");\n        assertEq(reads[1], bytes32(uint256(1)), \"key for read 1 is incorrect\");\n\n        assertEq(writes.length, 1, \"number of writes is incorrect\");\n        assertEq(writes[0], bytes32(uint256(1)), \"key for write is incorrect\");\n\n        vm.stopRecord();\n        inner = target.record();\n\n        // Verify that there are no new Records\n        (reads, writes) = vm.accesses(address(target));\n\n        assertEq(reads.length, 2, \"number of reads is incorrect\");\n        assertEq(reads[0], bytes32(uint256(1)), \"key for read 0 is incorrect\");\n        assertEq(reads[1], bytes32(uint256(1)), \"key for read 1 is incorrect\");\n\n        assertEq(writes.length, 1, \"number of writes is incorrect\");\n        assertEq(writes[0], bytes32(uint256(1)), \"key for write is incorrect\");\n\n        vm.record();\n        vm.stopRecord();\n\n        // verify reset all records\n        (reads, writes) = vm.accesses(address(target));\n\n        assertEq(reads.length, 0, \"number of reads is incorrect\");\n        assertEq(writes.length, 0, \"number of writes is incorrect\");\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/RecordAccountAccesses.t.sol",
    "content": "// SPDX-License-Identifier: Unlicense\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\n/// @notice Helper contract with a construction that makes a call to itself then\n///         optionally reverts if zero-length data is passed\ncontract SelfCaller {\n    constructor(bytes memory) payable {\n        assembly {\n            // call self to test that the cheatcode correctly reports the\n            // account as initialized even when there is no code at the\n            // contract address\n            pop(call(gas(), address(), div(callvalue(), 10), 0, 0, 0, 0))\n            if eq(calldataload(0x04), 1) { revert(0, 0) }\n        }\n    }\n}\n\n/// @notice Helper contract with a constructor that stores a value in storage\n///         and then optionally reverts.\ncontract ConstructorStorer {\n    constructor(bool shouldRevert) {\n        assembly {\n            sstore(0x00, 0x01)\n            if shouldRevert { revert(0, 0) }\n        }\n    }\n}\n\n/// @notice Helper contract that calls itself from the run method\ncontract Doer {\n    uint256[10] spacer;\n    mapping(bytes32 key => uint256 value) slots;\n\n    function run() public payable {\n        slots[bytes32(\"doer 1\")]++;\n        this.doStuff{value: msg.value / 10}();\n    }\n\n    function doStuff() external payable {\n        slots[bytes32(\"doer 2\")]++;\n    }\n}\n\n/// @notice Helper contract that selfdestructs to a target address within its\n///         constructor\ncontract SelfDestructor {\n    constructor(address target) payable {\n        selfdestruct(payable(target));\n    }\n}\n\n/// @notice Helper contract that calls a Doer from the run method\ncontract Create2or {\n    function create2(bytes32 salt, bytes memory initcode) external payable returns (address result) {\n        assembly {\n            result := create2(callvalue(), add(initcode, 0x20), mload(initcode), salt)\n        }\n    }\n}\n\n/// @notice Helper contract that calls a Doer from the run method and then\n///         reverts\ncontract Reverter {\n    Doer immutable doer;\n    mapping(bytes32 key => uint256 value) slots;\n\n    constructor(Doer _doer) {\n        doer = _doer;\n    }\n\n    function run() public payable {\n        slots[bytes32(\"reverter\")]++;\n        doer.run{value: msg.value / 10}();\n        revert();\n    }\n}\n\n/// @notice Helper contract that calls a Doer from the run method\ncontract Succeeder {\n    Doer immutable doer;\n    mapping(bytes32 key => uint256 value) slots;\n\n    constructor(Doer _doer) {\n        doer = _doer;\n    }\n\n    function run() public payable {\n        slots[bytes32(\"succeeder\")]++;\n        doer.run{value: msg.value / 10}();\n    }\n}\n\n/// @notice Helper contract that calls a Reverter and Succeeder from the run\n///         method\ncontract NestedRunner {\n    Doer public immutable doer;\n    Reverter public immutable reverter;\n    Succeeder public immutable succeeder;\n    mapping(bytes32 key => uint256 value) slots;\n\n    constructor() {\n        doer = new Doer();\n        reverter = new Reverter(doer);\n        succeeder = new Succeeder(doer);\n    }\n\n    function run(bool shouldRevert) public payable {\n        slots[bytes32(\"runner\")]++;\n        try reverter.run{value: msg.value / 10}() {\n            if (shouldRevert) {\n                revert();\n            }\n        } catch {}\n        succeeder.run{value: msg.value / 10}();\n        if (shouldRevert) {\n            revert();\n        }\n    }\n}\n\n/// Helper contract that uses all three EXT* opcodes on a given address\ncontract ExtChecker {\n    function checkExts(address a) external returns (bytes memory out) {\n        assembly {\n            mstore(out, mul(0x20, 4))\n            mstore(add(out, 0x20), extcodesize(a))\n            mstore(add(out, 0x40), extcodehash(a))\n            extcodecopy(a, 0, 0x60, 0x20)\n            mstore(add(out, 0x80), balance(a))\n        }\n    }\n}\n\n/// @notice Helper contract that writes to storage in a nested call\ncontract NestedStorer {\n    mapping(bytes32 key => uint256 value) slots;\n\n    constructor() {}\n\n    function run() public payable {\n        slots[bytes32(\"nested_storer 1\")]++;\n        this.run2();\n        slots[bytes32(\"nested_storer 2\")]++;\n    }\n\n    function run2() external payable {\n        slots[bytes32(\"nested_storer 3\")]++;\n        slots[bytes32(\"nested_storer 4\")]++;\n    }\n}\n\n/// @notice Helper contract that directly reads from and writes to storage\ncontract StorageAccessor {\n    function read(bytes32 slot) public view returns (bytes32 value) {\n        assembly {\n            value := sload(slot)\n        }\n    }\n\n    function write(bytes32 slot, bytes32 value) public {\n        assembly {\n            sstore(slot, value)\n        }\n    }\n}\n\n/// @notice Proxy contract\ncontract Proxy {\n    bytes32 public constant IMPL_ADDR = bytes32(uint256(keccak256(\"ekans implementation\")));\n\n    constructor(address _delegate) {\n        bytes32 impl = IMPL_ADDR;\n        assembly {\n            sstore(impl, _delegate)\n        }\n    }\n\n    receive() external payable {\n        doProxyCall();\n    }\n\n    fallback() external payable {\n        doProxyCall();\n    }\n\n    function doProxyCall() internal {\n        address _target;\n        bytes32 impl = IMPL_ADDR;\n        assembly {\n            _target := sload(impl)\n            calldatacopy(0x0, 0x0, calldatasize())\n            let result := delegatecall(gas(), _target, 0x0, calldatasize(), 0x0, 0)\n            returndatacopy(0x0, 0x0, returndatasize())\n            switch result\n            case 0 { revert(0, 0) }\n            default { return(0, returndatasize()) }\n        }\n    }\n}\n\n/// @notice Test that the cheatcode correctly records account accesses\ncontract RecordAccountAccessesTest is Test {\n    NestedRunner runner;\n    NestedStorer nestedStorer;\n    Create2or create2or;\n    StorageAccessor test1;\n    StorageAccessor test2;\n    ExtChecker extChecker;\n\n    function setUp() public {\n        runner = new NestedRunner();\n        nestedStorer = new NestedStorer();\n        create2or = new Create2or();\n        test1 = new StorageAccessor();\n        test2 = new StorageAccessor();\n        extChecker = new ExtChecker();\n    }\n\n    function testStorageAccessDelegateCall() public {\n        StorageAccessor one = test1;\n        Proxy proxy = new Proxy(address(one));\n\n        vm.startStateDiffRecording();\n        (bool success,) = address(proxy).call(abi.encodeCall(StorageAccessor.read, bytes32(uint256(1234))));\n        require(success, \"call failed\");\n        Vm.AccountAccess[] memory called = filterExtcodesizeForLegacyTests(vm.stopAndReturnStateDiff());\n\n        assertEq(called.length, 2, \"incorrect length\");\n\n        assertEq(toUint(called[0].kind), toUint(Vm.AccountAccessKind.Call), \"incorrect kind\");\n        assertEq(called[0].accessor, address(this));\n        assertEq(called[0].account, address(proxy));\n\n        assertEq(toUint(called[1].kind), toUint(Vm.AccountAccessKind.DelegateCall), \"incorrect kind\");\n        assertEq(called[1].account, address(one), \"incorrect account\");\n        assertEq(called[1].accessor, address(this), \"incorrect accessor\");\n        assertEq(\n            called[1].storageAccesses[0],\n            Vm.StorageAccess({\n                account: address(proxy),\n                slot: bytes32(uint256(1234)),\n                isWrite: false,\n                previousValue: bytes32(uint256(0)),\n                newValue: bytes32(uint256(0)),\n                reverted: false\n            })\n        );\n    }\n\n    /// @notice Test normal, non-nested storage accesses\n    function testStorageAccesses() public {\n        StorageAccessor one = test1;\n        StorageAccessor two = test2;\n        vm.startStateDiffRecording();\n\n        one.read(bytes32(uint256(1234)));\n        one.write(bytes32(uint256(1235)), bytes32(uint256(5678)));\n        two.write(bytes32(uint256(5678)), bytes32(uint256(123469)));\n        two.write(bytes32(uint256(5678)), bytes32(uint256(1234)));\n\n        string memory diffs = vm.getStateDiff();\n        assertEq(\n            \"0x5991A2dF15A8F6A256D3Ec51E99254Cd3fb576A9\\ncontract: default/cheats/RecordAccountAccesses.t.sol:StorageAccessor\\n- state diff:\\n@ 0x00000000000000000000000000000000000000000000000000000000000004d3: 0x0000000000000000000000000000000000000000000000000000000000000000 \\xE2\\x86\\x92 0x000000000000000000000000000000000000000000000000000000000000162e\\n\\n0xc7183455a4C133Ae270771860664b6B7ec320bB1\\ncontract: default/cheats/RecordAccountAccesses.t.sol:StorageAccessor\\n- state diff:\\n@ 0x000000000000000000000000000000000000000000000000000000000000162e: 0x0000000000000000000000000000000000000000000000000000000000000000 \\xE2\\x86\\x92 0x00000000000000000000000000000000000000000000000000000000000004d2\\n\\n\",\n            diffs\n        );\n        string memory diffsJson = vm.getStateDiffJson();\n        assertEq(\n            '{\"0x5991a2df15a8f6a256d3ec51e99254cd3fb576a9\":{\"label\":null,\"contract\":\"default/cheats/RecordAccountAccesses.t.sol:StorageAccessor\",\"balanceDiff\":null,\"nonceDiff\":null,\"stateDiff\":{\"0x00000000000000000000000000000000000000000000000000000000000004d3\":{\"previousValue\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"newValue\":\"0x000000000000000000000000000000000000000000000000000000000000162e\"}}},\"0xc7183455a4c133ae270771860664b6b7ec320bb1\":{\"label\":null,\"contract\":\"default/cheats/RecordAccountAccesses.t.sol:StorageAccessor\",\"balanceDiff\":null,\"nonceDiff\":null,\"stateDiff\":{\"0x000000000000000000000000000000000000000000000000000000000000162e\":{\"previousValue\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"newValue\":\"0x00000000000000000000000000000000000000000000000000000000000004d2\"}}}}',\n            diffsJson\n        );\n        Vm.AccountAccess[] memory called = filterExtcodesizeForLegacyTests(vm.stopAndReturnStateDiff());\n        assertEq(called.length, 4, \"incorrect length\");\n\n        assertEq(called[0].storageAccesses.length, 1, \"incorrect storage length\");\n        Vm.StorageAccess memory access = called[0].storageAccesses[0];\n        assertEq(\n            access,\n            Vm.StorageAccess({\n                account: address(one),\n                slot: bytes32(uint256(1234)),\n                isWrite: false,\n                previousValue: bytes32(uint256(0)),\n                newValue: bytes32(uint256(0)),\n                reverted: false\n            })\n        );\n\n        assertEq(called[1].storageAccesses.length, 1, \"incorrect storage length\");\n        access = called[1].storageAccesses[0];\n        assertEq(\n            access,\n            Vm.StorageAccess({\n                account: address(one),\n                slot: bytes32(uint256(1235)),\n                isWrite: true,\n                previousValue: bytes32(uint256(0)),\n                newValue: bytes32(uint256(5678)),\n                reverted: false\n            })\n        );\n\n        assertEq(called[2].storageAccesses.length, 1, \"incorrect storage length\");\n        access = called[2].storageAccesses[0];\n        assertEq(\n            access,\n            Vm.StorageAccess({\n                account: address(two),\n                slot: bytes32(uint256(5678)),\n                isWrite: true,\n                previousValue: bytes32(uint256(0)),\n                newValue: bytes32(uint256(123469)),\n                reverted: false\n            })\n        );\n\n        assertEq(called[3].storageAccesses.length, 1, \"incorrect storage length\");\n        access = called[3].storageAccesses[0];\n        assertEq(\n            access,\n            Vm.StorageAccess({\n                account: address(two),\n                slot: bytes32(uint256(5678)),\n                isWrite: true,\n                previousValue: bytes32(uint256(123469)),\n                newValue: bytes32(uint256(1234)),\n                reverted: false\n            })\n        );\n    }\n\n    /// @notice Test that basic account accesses are correctly recorded\n    function testRecordAccountAccesses() public {\n        vm.startStateDiffRecording();\n\n        (bool succ,) = address(1234).call(\"\");\n        (succ,) = address(5678).call{value: 1 ether}(\"\");\n        (succ,) = address(123469).call(\"hello world\");\n        (succ,) = address(5678).call(\"\");\n        // contract calls to self in constructor\n        SelfCaller caller = new SelfCaller{value: 2 ether}(\"hello2 world2\");\n\n        string memory callerAddress = vm.toString(address(caller));\n        string memory expectedStateDiff =\n            \"0x000000000000000000000000000000000000162e\\n- balance diff: 0 \\xE2\\x86\\x92 1000000000000000000\\n\\n\";\n        expectedStateDiff = string.concat(expectedStateDiff, callerAddress);\n        expectedStateDiff =\n            string.concat(expectedStateDiff, \"\\ncontract: default/cheats/RecordAccountAccesses.t.sol:SelfCaller\");\n        expectedStateDiff = string.concat(\n            expectedStateDiff,\n            \"\\n- balance diff: 0 \\xE2\\x86\\x92 2000000000000000000\\n- nonce diff: 0 \\xE2\\x86\\x92 1\\n\\n\"\n        );\n        assertEq(expectedStateDiff, vm.getStateDiff());\n\n        Vm.AccountAccess[] memory called = filterExtcodesizeForLegacyTests(vm.stopAndReturnStateDiff());\n        assertEq(called.length, 6);\n        assertEq(\n            called[0],\n            Vm.AccountAccess({\n                chainInfo: Vm.ChainInfo({forkId: 0, chainId: 0}),\n                accessor: address(this),\n                account: address(1234),\n                kind: Vm.AccountAccessKind.Call,\n                initialized: false,\n                oldBalance: 0,\n                newBalance: 0,\n                oldNonce: 0,\n                newNonce: 0,\n                deployedCode: hex\"\",\n                value: 0,\n                data: \"\",\n                reverted: false,\n                storageAccesses: new Vm.StorageAccess[](0),\n                depth: 0\n            })\n        );\n\n        assertEq(\n            called[1],\n            Vm.AccountAccess({\n                chainInfo: Vm.ChainInfo({forkId: 0, chainId: 0}),\n                accessor: address(this),\n                account: address(5678),\n                kind: Vm.AccountAccessKind.Call,\n                initialized: false,\n                oldBalance: 0,\n                newBalance: 1 ether,\n                oldNonce: 0,\n                newNonce: 0,\n                deployedCode: hex\"\",\n                value: 1 ether,\n                data: \"\",\n                reverted: false,\n                storageAccesses: new Vm.StorageAccess[](0),\n                depth: 1\n            })\n        );\n        assertEq(\n            called[2],\n            Vm.AccountAccess({\n                chainInfo: Vm.ChainInfo({forkId: 0, chainId: 0}),\n                accessor: address(this),\n                account: address(123469),\n                kind: Vm.AccountAccessKind.Call,\n                initialized: false,\n                oldBalance: 0,\n                newBalance: 0,\n                oldNonce: 0,\n                newNonce: 0,\n                deployedCode: hex\"\",\n                value: 0,\n                data: \"hello world\",\n                reverted: false,\n                storageAccesses: new Vm.StorageAccess[](0),\n                depth: 2\n            })\n        );\n        assertEq(\n            called[3],\n            Vm.AccountAccess({\n                chainInfo: Vm.ChainInfo({forkId: 0, chainId: 0}),\n                accessor: address(this),\n                account: address(5678),\n                kind: Vm.AccountAccessKind.Call,\n                initialized: true,\n                oldBalance: 1 ether,\n                newBalance: 1 ether,\n                oldNonce: 0,\n                newNonce: 0,\n                deployedCode: hex\"\",\n                value: 0,\n                data: \"\",\n                reverted: false,\n                storageAccesses: new Vm.StorageAccess[](0),\n                depth: 3\n            })\n        );\n        assertEq(\n            called[4],\n            Vm.AccountAccess({\n                chainInfo: Vm.ChainInfo({forkId: 0, chainId: 0}),\n                accessor: address(this),\n                account: address(caller),\n                kind: Vm.AccountAccessKind.Create,\n                initialized: true,\n                oldBalance: 0,\n                newBalance: 2 ether,\n                oldNonce: 0,\n                newNonce: 1,\n                deployedCode: address(caller).code,\n                value: 2 ether,\n                data: abi.encodePacked(type(SelfCaller).creationCode, abi.encode(\"hello2 world2\")),\n                reverted: false,\n                storageAccesses: new Vm.StorageAccess[](0),\n                depth: 3\n            })\n        );\n        assertEq(\n            called[5],\n            Vm.AccountAccess({\n                chainInfo: Vm.ChainInfo({forkId: 0, chainId: 0}),\n                accessor: address(caller),\n                account: address(caller),\n                kind: Vm.AccountAccessKind.Call,\n                initialized: true,\n                oldBalance: 2 ether,\n                newBalance: 2 ether,\n                oldNonce: 0,\n                newNonce: 0,\n                deployedCode: hex\"\",\n                value: 0.2 ether,\n                data: \"\",\n                reverted: false,\n                storageAccesses: new Vm.StorageAccess[](0),\n                depth: 3\n            })\n        );\n    }\n\n    /// @notice Test that account accesses are correctly recorded when a call\n    ///         reverts\n    function testRevertingCall() public {\n        uint256 initBalance = address(this).balance;\n        vm.startStateDiffRecording();\n        try this.revertingCall{value: 1 ether}(address(1234), \"\") {} catch {}\n        assertEq(\n            \"0x00000000000000000000000000000000000004d2\\n- balance diff: 0 \\xE2\\x86\\x92 100000000000000000\\n\\n\",\n            vm.getStateDiff()\n        );\n        assertEq(\n            '{\"0x00000000000000000000000000000000000004d2\":{\"label\":null,\"contract\":null,\"balanceDiff\":{\"previousValue\":\"0x0\",\"newValue\":\"0x16345785d8a0000\"},\"nonceDiff\":null,\"stateDiff\":{}}}',\n            vm.getStateDiffJson()\n        );\n        Vm.AccountAccess[] memory called = filterExtcodesizeForLegacyTests(vm.stopAndReturnStateDiff());\n        assertEq(called.length, 2);\n        assertEq(\n            called[0],\n            Vm.AccountAccess({\n                chainInfo: Vm.ChainInfo({forkId: 0, chainId: 0}),\n                accessor: address(this),\n                account: address(this),\n                kind: Vm.AccountAccessKind.Call,\n                initialized: true,\n                oldBalance: initBalance,\n                newBalance: initBalance,\n                oldNonce: 0,\n                newNonce: 0,\n                deployedCode: hex\"\",\n                value: 1 ether,\n                data: abi.encodeCall(this.revertingCall, (address(1234), \"\")),\n                reverted: true,\n                storageAccesses: new Vm.StorageAccess[](0),\n                depth: 0\n            })\n        );\n        assertEq(\n            called[1],\n            Vm.AccountAccess({\n                chainInfo: Vm.ChainInfo({forkId: 0, chainId: 0}),\n                accessor: address(this),\n                account: address(1234),\n                kind: Vm.AccountAccessKind.Call,\n                initialized: false,\n                oldBalance: 0,\n                newBalance: 0.1 ether,\n                oldNonce: 0,\n                newNonce: 0,\n                deployedCode: hex\"\",\n                value: 0.1 ether,\n                data: \"\",\n                reverted: true,\n                storageAccesses: new Vm.StorageAccess[](0),\n                depth: 1\n            })\n        );\n    }\n\n    /// @notice Test that nested account accesses are correctly recorded\n    function testNested() public {\n        vm.startStateDiffRecording();\n        runNested(false, false);\n    }\n\n    /// @notice Test that nested account accesses are correctly recorded when\n    ///         the first call reverts\n    function testNested_Revert() public {\n        vm.startStateDiffRecording();\n        runNested(true, false);\n    }\n\n    /// @notice Helper function to test nested account accesses\n    /// @param shouldRevert Whether the first call should revert\n    function runNested(bool shouldRevert, bool expectFirstCall) public {\n        try runner.run{value: 1 ether}(shouldRevert) {} catch {}\n        Vm.AccountAccess[] memory called = filterExtcodesizeForLegacyTests(vm.stopAndReturnStateDiff());\n        assertEq(called.length, 7 + toUint(expectFirstCall), \"incorrect length\");\n\n        uint64 startingIndex = uint64(toUint(expectFirstCall));\n        if (expectFirstCall) {\n            assertEq(\n                called[0],\n                Vm.AccountAccess({\n                    chainInfo: Vm.ChainInfo({forkId: 0, chainId: 0}),\n                    accessor: address(this),\n                    account: address(1234),\n                    kind: Vm.AccountAccessKind.Call,\n                    oldBalance: 0,\n                    newBalance: 0,\n                    oldNonce: 0,\n                    newNonce: 0,\n                    deployedCode: \"\",\n                    initialized: false,\n                    value: 0,\n                    data: \"\",\n                    reverted: false,\n                    storageAccesses: new Vm.StorageAccess[](0),\n                    depth: startingIndex\n                })\n            );\n        }\n\n        assertEq(called[startingIndex].storageAccesses.length, 2, \"incorrect length\");\n        assertIncrementEq(\n            called[startingIndex].storageAccesses[0],\n            called[startingIndex].storageAccesses[1],\n            Vm.StorageAccess({\n                account: address(runner),\n                slot: keccak256(abi.encodePacked(bytes32(\"runner\"), bytes32(0))),\n                isWrite: true,\n                previousValue: bytes32(uint256(0)),\n                newValue: bytes32(uint256(1)),\n                reverted: shouldRevert\n            })\n        );\n        assertEq(\n            called[startingIndex],\n            Vm.AccountAccess({\n                chainInfo: Vm.ChainInfo({forkId: 0, chainId: 0}),\n                accessor: address(this),\n                account: address(runner),\n                kind: Vm.AccountAccessKind.Call,\n                oldBalance: 0,\n                newBalance: shouldRevert ? 0 : 0.9 ether,\n                oldNonce: 0,\n                newNonce: 0,\n                deployedCode: \"\",\n                initialized: true,\n                value: 1 ether,\n                data: abi.encodeCall(NestedRunner.run, (shouldRevert)),\n                reverted: shouldRevert,\n                storageAccesses: new Vm.StorageAccess[](0),\n                depth: startingIndex\n            }),\n            false\n        );\n\n        assertEq(called[startingIndex + 1].storageAccesses.length, 2, \"incorrect length\");\n        assertIncrementEq(\n            called[startingIndex + 1].storageAccesses[0],\n            called[startingIndex + 1].storageAccesses[1],\n            Vm.StorageAccess({\n                account: address(runner.reverter()),\n                slot: keccak256(abi.encodePacked(bytes32(\"reverter\"), bytes32(0))),\n                isWrite: true,\n                previousValue: bytes32(uint256(0)),\n                newValue: bytes32(uint256(1)),\n                reverted: true\n            })\n        );\n        assertEq(\n            called[startingIndex + 1],\n            Vm.AccountAccess({\n                chainInfo: Vm.ChainInfo({forkId: 0, chainId: 0}),\n                accessor: address(runner),\n                account: address(runner.reverter()),\n                kind: Vm.AccountAccessKind.Call,\n                oldBalance: 0,\n                newBalance: 0,\n                oldNonce: 0,\n                newNonce: 0,\n                deployedCode: \"\",\n                initialized: true,\n                value: 0.1 ether,\n                data: abi.encodeCall(Reverter.run, ()),\n                reverted: true,\n                storageAccesses: new Vm.StorageAccess[](0),\n                depth: startingIndex + 1\n            }),\n            false\n        );\n\n        assertEq(called[startingIndex + 2].storageAccesses.length, 2, \"incorrect length\");\n        assertIncrementEq(\n            called[startingIndex + 2].storageAccesses[0],\n            called[startingIndex + 2].storageAccesses[1],\n            Vm.StorageAccess({\n                account: address(runner.doer()),\n                slot: keccak256(abi.encodePacked(bytes32(\"doer 1\"), uint256(10))),\n                isWrite: true,\n                previousValue: bytes32(uint256(0)),\n                newValue: bytes32(uint256(1)),\n                reverted: true\n            })\n        );\n        assertEq(\n            called[startingIndex + 2],\n            Vm.AccountAccess({\n                chainInfo: Vm.ChainInfo({forkId: 0, chainId: 0}),\n                accessor: address(runner.reverter()),\n                account: address(runner.doer()),\n                kind: Vm.AccountAccessKind.Call,\n                oldBalance: 0,\n                newBalance: 0.01 ether,\n                oldNonce: 0,\n                newNonce: 0,\n                deployedCode: \"\",\n                initialized: true,\n                value: 0.01 ether,\n                data: abi.encodeCall(Doer.run, ()),\n                reverted: true,\n                storageAccesses: new Vm.StorageAccess[](0),\n                depth: startingIndex + 2\n            }),\n            false\n        );\n\n        assertEq(called[startingIndex + 3].storageAccesses.length, 2, \"incorrect length\");\n        assertIncrementEq(\n            called[startingIndex + 3].storageAccesses[0],\n            called[startingIndex + 3].storageAccesses[1],\n            Vm.StorageAccess({\n                account: address(runner.doer()),\n                slot: keccak256(abi.encodePacked(bytes32(\"doer 2\"), uint256(10))),\n                isWrite: true,\n                previousValue: bytes32(uint256(0)),\n                newValue: bytes32(uint256(1)),\n                reverted: true\n            })\n        );\n        assertEq(\n            called[startingIndex + 3],\n            Vm.AccountAccess({\n                chainInfo: Vm.ChainInfo({forkId: 0, chainId: 0}),\n                accessor: address(runner.doer()),\n                account: address(runner.doer()),\n                kind: Vm.AccountAccessKind.Call,\n                oldBalance: 0.01 ether,\n                newBalance: 0.01 ether,\n                oldNonce: 0,\n                newNonce: 0,\n                deployedCode: \"\",\n                initialized: true,\n                value: 0.001 ether,\n                data: abi.encodeCall(Doer.doStuff, ()),\n                reverted: true,\n                storageAccesses: new Vm.StorageAccess[](0),\n                depth: startingIndex + 3\n            }),\n            false\n        );\n\n        assertEq(called[startingIndex + 4].storageAccesses.length, 2, \"incorrect length\");\n        assertIncrementEq(\n            called[startingIndex + 4].storageAccesses[0],\n            called[startingIndex + 4].storageAccesses[1],\n            Vm.StorageAccess({\n                account: address(runner.succeeder()),\n                slot: keccak256(abi.encodePacked(bytes32(\"succeeder\"), uint256(0))),\n                isWrite: true,\n                previousValue: bytes32(uint256(0)),\n                newValue: bytes32(uint256(1)),\n                reverted: shouldRevert\n            })\n        );\n        assertEq(\n            called[startingIndex + 4],\n            Vm.AccountAccess({\n                chainInfo: Vm.ChainInfo({forkId: 0, chainId: 0}),\n                accessor: address(runner),\n                account: address(runner.succeeder()),\n                kind: Vm.AccountAccessKind.Call,\n                oldBalance: 0,\n                newBalance: 0.09 ether,\n                oldNonce: 0,\n                newNonce: 0,\n                deployedCode: \"\",\n                initialized: true,\n                value: 0.1 ether,\n                data: abi.encodeCall(Succeeder.run, ()),\n                reverted: shouldRevert,\n                storageAccesses: new Vm.StorageAccess[](0),\n                depth: startingIndex + 4\n            }),\n            false\n        );\n\n        assertEq(called[startingIndex + 5].storageAccesses.length, 2, \"incorrect length\");\n        assertIncrementEq(\n            called[startingIndex + 5].storageAccesses[0],\n            called[startingIndex + 5].storageAccesses[1],\n            Vm.StorageAccess({\n                account: address(runner.doer()),\n                slot: keccak256(abi.encodePacked(bytes32(\"doer 1\"), uint256(10))),\n                isWrite: true,\n                previousValue: bytes32(uint256(0)),\n                newValue: bytes32(uint256(1)),\n                reverted: shouldRevert\n            })\n        );\n        assertEq(\n            called[startingIndex + 5],\n            Vm.AccountAccess({\n                chainInfo: Vm.ChainInfo({forkId: 0, chainId: 0}),\n                accessor: address(runner.succeeder()),\n                account: address(runner.doer()),\n                kind: Vm.AccountAccessKind.Call,\n                oldBalance: 0,\n                newBalance: 0.01 ether,\n                oldNonce: 0,\n                newNonce: 0,\n                deployedCode: \"\",\n                initialized: true,\n                value: 0.01 ether,\n                data: abi.encodeCall(Doer.run, ()),\n                reverted: shouldRevert,\n                storageAccesses: new Vm.StorageAccess[](0),\n                depth: startingIndex + 5\n            }),\n            false\n        );\n\n        assertEq(called[startingIndex + 3].storageAccesses.length, 2, \"incorrect length\");\n        assertIncrementEq(\n            called[startingIndex + 6].storageAccesses[0],\n            called[startingIndex + 6].storageAccesses[1],\n            Vm.StorageAccess({\n                account: address(runner.doer()),\n                slot: keccak256(abi.encodePacked(bytes32(\"doer 2\"), uint256(10))),\n                isWrite: true,\n                previousValue: bytes32(uint256(0)),\n                newValue: bytes32(uint256(1)),\n                reverted: shouldRevert\n            })\n        );\n        assertEq(\n            called[startingIndex + 6],\n            Vm.AccountAccess({\n                chainInfo: Vm.ChainInfo({forkId: 0, chainId: 0}),\n                accessor: address(runner.doer()),\n                account: address(runner.doer()),\n                kind: Vm.AccountAccessKind.Call,\n                oldBalance: 0.01 ether,\n                newBalance: 0.01 ether,\n                oldNonce: 0,\n                newNonce: 0,\n                deployedCode: \"\",\n                initialized: true,\n                value: 0.001 ether,\n                data: abi.encodeCall(Doer.doStuff, ()),\n                reverted: shouldRevert,\n                storageAccesses: new Vm.StorageAccess[](0),\n                depth: startingIndex + 6\n            }),\n            false\n        );\n    }\n\n    function testNestedStorage() public {\n        vm.startStateDiffRecording();\n        nestedStorer.run();\n        vm.label(address(nestedStorer), \"NestedStorer\");\n        assertEq(\n            \"0x2e234DAe75C793f67A35089C9d99245E1C58470b\\nlabel: NestedStorer\\ncontract: default/cheats/RecordAccountAccesses.t.sol:NestedStorer\\n- state diff:\\n@ 0x4566fa0cd03218c55bba914d793f5e6b9113172c1f684bb5f464c08c867e8977: 0x0000000000000000000000000000000000000000000000000000000000000000 \\xE2\\x86\\x92 0x0000000000000000000000000000000000000000000000000000000000000001\\n@ 0xbf57896b60daefa2c41de2feffecfc11debd98ea8c913a5170f60e53959ac00a: 0x0000000000000000000000000000000000000000000000000000000000000000 \\xE2\\x86\\x92 0x0000000000000000000000000000000000000000000000000000000000000001\\n@ 0xc664893a982d78bbeab379feef216ff517b7ea73626b280723be1ace370364cd: 0x0000000000000000000000000000000000000000000000000000000000000000 \\xE2\\x86\\x92 0x0000000000000000000000000000000000000000000000000000000000000001\\n@ 0xdc5330afa9872081253545dca3f448752688ff1b098b38c1abe4c4cdff4b0b0e: 0x0000000000000000000000000000000000000000000000000000000000000000 \\xE2\\x86\\x92 0x0000000000000000000000000000000000000000000000000000000000000001\\n\\n\",\n            vm.getStateDiff()\n        );\n        assertEq(\n            '{\"0x2e234dae75c793f67a35089c9d99245e1c58470b\":{\"label\":\"NestedStorer\",\"contract\":\"default/cheats/RecordAccountAccesses.t.sol:NestedStorer\",\"balanceDiff\":null,\"nonceDiff\":null,\"stateDiff\":{\"0x4566fa0cd03218c55bba914d793f5e6b9113172c1f684bb5f464c08c867e8977\":{\"previousValue\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"newValue\":\"0x0000000000000000000000000000000000000000000000000000000000000001\"},\"0xbf57896b60daefa2c41de2feffecfc11debd98ea8c913a5170f60e53959ac00a\":{\"previousValue\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"newValue\":\"0x0000000000000000000000000000000000000000000000000000000000000001\"},\"0xc664893a982d78bbeab379feef216ff517b7ea73626b280723be1ace370364cd\":{\"previousValue\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"newValue\":\"0x0000000000000000000000000000000000000000000000000000000000000001\"},\"0xdc5330afa9872081253545dca3f448752688ff1b098b38c1abe4c4cdff4b0b0e\":{\"previousValue\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"newValue\":\"0x0000000000000000000000000000000000000000000000000000000000000001\"}}}}',\n            vm.getStateDiffJson()\n        );\n        Vm.AccountAccess[] memory called = filterExtcodesizeForLegacyTests(vm.stopAndReturnStateDiff());\n        assertEq(called.length, 3, \"incorrect account access length\");\n\n        assertEq(called[0].storageAccesses.length, 2, \"incorrect run storage length\");\n        assertIncrementEq(\n            called[0].storageAccesses[0],\n            called[0].storageAccesses[1],\n            Vm.StorageAccess({\n                account: address(nestedStorer),\n                slot: keccak256(abi.encodePacked(bytes32(\"nested_storer 1\"), bytes32(0))),\n                isWrite: true,\n                previousValue: bytes32(uint256(0)),\n                newValue: bytes32(uint256(1)),\n                reverted: false\n            })\n        );\n        assertEq(\n            called[0],\n            Vm.AccountAccess({\n                chainInfo: Vm.ChainInfo({forkId: 0, chainId: 0}),\n                accessor: address(this),\n                account: address(nestedStorer),\n                kind: Vm.AccountAccessKind.Call,\n                oldBalance: 0,\n                newBalance: 0,\n                oldNonce: 0,\n                newNonce: 0,\n                deployedCode: \"\",\n                initialized: true,\n                value: 0,\n                data: abi.encodeCall(NestedStorer.run, ()),\n                reverted: false,\n                storageAccesses: new Vm.StorageAccess[](0),\n                depth: 0\n            }),\n            false\n        );\n\n        assertEq(called[1].storageAccesses.length, 4, \"incorrect run2 storage length\");\n        assertIncrementEq(\n            called[1].storageAccesses[0],\n            called[1].storageAccesses[1],\n            Vm.StorageAccess({\n                account: address(nestedStorer),\n                slot: keccak256(abi.encodePacked(bytes32(\"nested_storer 3\"), bytes32(0))),\n                isWrite: true,\n                previousValue: bytes32(uint256(0)),\n                newValue: bytes32(uint256(1)),\n                reverted: false\n            })\n        );\n        assertIncrementEq(\n            called[1].storageAccesses[2],\n            called[1].storageAccesses[3],\n            Vm.StorageAccess({\n                account: address(nestedStorer),\n                slot: keccak256(abi.encodePacked(bytes32(\"nested_storer 4\"), bytes32(0))),\n                isWrite: true,\n                previousValue: bytes32(uint256(0)),\n                newValue: bytes32(uint256(1)),\n                reverted: false\n            })\n        );\n        assertEq(\n            called[1],\n            Vm.AccountAccess({\n                chainInfo: Vm.ChainInfo({forkId: 0, chainId: 0}),\n                accessor: address(nestedStorer),\n                account: address(nestedStorer),\n                kind: Vm.AccountAccessKind.Call,\n                oldBalance: 0,\n                newBalance: 0,\n                oldNonce: 0,\n                newNonce: 0,\n                deployedCode: \"\",\n                initialized: true,\n                value: 0,\n                data: abi.encodeCall(NestedStorer.run2, ()),\n                reverted: false,\n                storageAccesses: new Vm.StorageAccess[](0),\n                depth: 1\n            }),\n            false\n        );\n\n        assertEq(called[2].storageAccesses.length, 2, \"incorrect resume storage length\");\n        assertIncrementEq(\n            called[2].storageAccesses[0],\n            called[2].storageAccesses[1],\n            Vm.StorageAccess({\n                account: address(nestedStorer),\n                slot: keccak256(abi.encodePacked(bytes32(\"nested_storer 2\"), bytes32(0))),\n                isWrite: true,\n                previousValue: bytes32(uint256(0)),\n                newValue: bytes32(uint256(1)),\n                reverted: false\n            })\n        );\n        assertEq(\n            called[2],\n            Vm.AccountAccess({\n                chainInfo: Vm.ChainInfo({forkId: 0, chainId: 0}),\n                accessor: address(this),\n                account: address(nestedStorer),\n                kind: Vm.AccountAccessKind.Resume,\n                oldBalance: 0,\n                newBalance: 0,\n                oldNonce: 0,\n                newNonce: 0,\n                deployedCode: \"\",\n                initialized: true,\n                value: 0,\n                data: \"\",\n                reverted: false,\n                storageAccesses: new Vm.StorageAccess[](0),\n                depth: 2\n            }),\n            false\n        );\n    }\n\n    /// @notice Test that constructor account and storage accesses are recorded, including reverts\n    function testConstructorStorage() public {\n        vm.startStateDiffRecording();\n        address storer = address(new ConstructorStorer(false));\n        try create2or.create2(bytes32(0), abi.encodePacked(type(ConstructorStorer).creationCode, abi.encode(true))) {}\n            catch {}\n        bytes memory creationCode = abi.encodePacked(type(ConstructorStorer).creationCode, abi.encode(true));\n        address hypotheticalStorer = deriveCreate2Address(address(create2or), bytes32(0), keccak256(creationCode));\n\n        Vm.AccountAccess[] memory called = filterExtcodesizeForLegacyTests(vm.stopAndReturnStateDiff());\n        assertEq(called.length, 3, \"incorrect account access length\");\n        assertEq(toUint(called[0].kind), toUint(Vm.AccountAccessKind.Create), \"incorrect kind\");\n        assertEq(toUint(called[1].kind), toUint(Vm.AccountAccessKind.Call), \"incorrect kind\");\n        assertEq(toUint(called[2].kind), toUint(Vm.AccountAccessKind.Create), \"incorrect kind\");\n\n        assertEq(called[0].storageAccesses.length, 1, \"incorrect storage access length\");\n        Vm.StorageAccess[] memory storageAccesses = new Vm.StorageAccess[](1);\n        storageAccesses[0] = Vm.StorageAccess({\n            account: storer,\n            slot: bytes32(uint256(0)),\n            isWrite: true,\n            previousValue: bytes32(uint256(0)),\n            newValue: bytes32(uint256(1)),\n            reverted: false\n        });\n        assertEq(\n            called[0],\n            Vm.AccountAccess({\n                chainInfo: Vm.ChainInfo({forkId: 0, chainId: 0}),\n                accessor: address(this),\n                account: address(storer),\n                kind: Vm.AccountAccessKind.Create,\n                oldBalance: 0,\n                newBalance: 0,\n                oldNonce: 0,\n                newNonce: 1,\n                deployedCode: storer.code,\n                initialized: true,\n                value: 0,\n                data: abi.encodePacked(type(ConstructorStorer).creationCode, abi.encode(false)),\n                reverted: false,\n                storageAccesses: storageAccesses,\n                depth: 0\n            })\n        );\n\n        assertEq(called[1].storageAccesses.length, 0, \"incorrect storage access length\");\n        assertEq(\n            called[1],\n            Vm.AccountAccess({\n                chainInfo: Vm.ChainInfo({forkId: 0, chainId: 0}),\n                accessor: address(this),\n                account: address(create2or),\n                kind: Vm.AccountAccessKind.Call,\n                oldBalance: 0,\n                newBalance: 0,\n                oldNonce: 0,\n                newNonce: 0,\n                deployedCode: \"\",\n                initialized: true,\n                value: 0,\n                data: abi.encodeCall(\n                    Create2or.create2,\n                    (bytes32(0), abi.encodePacked(type(ConstructorStorer).creationCode, abi.encode(true)))\n                ),\n                reverted: false,\n                storageAccesses: new Vm.StorageAccess[](0),\n                depth: 1\n            })\n        );\n\n        assertEq(called[2].storageAccesses.length, 1, \"incorrect storage access length\");\n        storageAccesses = new Vm.StorageAccess[](1);\n        storageAccesses[0] = Vm.StorageAccess({\n            account: hypotheticalStorer,\n            slot: bytes32(uint256(0)),\n            isWrite: true,\n            previousValue: bytes32(uint256(0)),\n            newValue: bytes32(uint256(1)),\n            reverted: true\n        });\n        assertEq(\n            called[2],\n            Vm.AccountAccess({\n                chainInfo: Vm.ChainInfo({forkId: 0, chainId: 0}),\n                accessor: address(create2or),\n                account: hypotheticalStorer,\n                kind: Vm.AccountAccessKind.Create,\n                oldBalance: 0,\n                newBalance: 0,\n                oldNonce: 0,\n                newNonce: 1,\n                deployedCode: address(hypotheticalStorer).code,\n                initialized: true,\n                value: 0,\n                data: creationCode,\n                reverted: true,\n                storageAccesses: storageAccesses,\n                depth: 2\n            })\n        );\n    }\n\n    /// @notice Test that account accesses are correctly recorded when the\n    ///         recording is started from a lower depth than they are\n    ///         retrieved\n    function testNested_LowerDepth() public {\n        this.startRecordingFromLowerDepth();\n        runNested(false, true);\n    }\n\n    /// @notice Test that account accesses are correctly recorded when\n    ///         the first call reverts the and recording is started from\n    ///         a lower depth than they are retrieved.\n    function testNested_LowerDepth_Revert() public {\n        this.startRecordingFromLowerDepth();\n        runNested(true, true);\n    }\n\n    /// @notice Test that constructor calls and calls made within a constructor\n    ///         are correctly recorded, even if it reverts\n    function testCreateRevert() public {\n        vm.startStateDiffRecording();\n        bytes memory creationCode = abi.encodePacked(type(SelfCaller).creationCode, abi.encode(\"\"));\n        try create2or.create2(bytes32(0), creationCode) {} catch {}\n        address hypotheticalAddress = deriveCreate2Address(address(create2or), bytes32(0), keccak256(creationCode));\n\n        Vm.AccountAccess[] memory called = filterExtcodesizeForLegacyTests(vm.stopAndReturnStateDiff());\n        assertEq(called.length, 3, \"incorrect length\");\n        assertEq(\n            called[1],\n            Vm.AccountAccess({\n                chainInfo: Vm.ChainInfo({forkId: 0, chainId: 0}),\n                accessor: address(create2or),\n                account: hypotheticalAddress,\n                kind: Vm.AccountAccessKind.Create,\n                oldBalance: 0,\n                newBalance: 0,\n                oldNonce: 0,\n                newNonce: 1,\n                deployedCode: address(hypotheticalAddress).code,\n                initialized: true,\n                value: 0,\n                data: creationCode,\n                reverted: false,\n                storageAccesses: new Vm.StorageAccess[](0),\n                depth: 1\n            })\n        );\n        assertEq(\n            called[2],\n            Vm.AccountAccess({\n                chainInfo: Vm.ChainInfo({forkId: 0, chainId: 0}),\n                accessor: hypotheticalAddress,\n                account: hypotheticalAddress,\n                kind: Vm.AccountAccessKind.Call,\n                oldBalance: 0,\n                newBalance: 0,\n                oldNonce: 0,\n                newNonce: 0,\n                deployedCode: hex\"\",\n                initialized: true,\n                value: 0,\n                data: \"\",\n                reverted: false,\n                storageAccesses: new Vm.StorageAccess[](0),\n                depth: 2\n            })\n        );\n    }\n\n    /// @notice It is important to test SELFDESTRUCT behavior as long as there\n    ///         are public networks that support the opcode, regardless of whether\n    ///         or not Ethereum mainnet does.\n    function testSelfDestruct() public {\n        uint256 startingBalance = address(this).balance;\n        this.startRecordingFromLowerDepth();\n        address a = address(new SelfDestructor{value: 1 ether}(address(this)));\n        address b = address(new SelfDestructor{value: 1 ether}(address(bytes20(\"doesn't exist yet\"))));\n        Vm.AccountAccess[] memory called = filterExtcodesizeForLegacyTests(vm.stopAndReturnStateDiff());\n        assertEq(called.length, 5, \"incorrect length\");\n        assertEq(\n            called[1],\n            Vm.AccountAccess({\n                chainInfo: Vm.ChainInfo({forkId: 0, chainId: 0}),\n                accessor: address(this),\n                account: a,\n                kind: Vm.AccountAccessKind.Create,\n                oldBalance: 0,\n                newBalance: 0,\n                oldNonce: 0,\n                newNonce: 1,\n                deployedCode: \"\",\n                initialized: true,\n                value: 1 ether,\n                data: abi.encodePacked(type(SelfDestructor).creationCode, abi.encode(address(this))),\n                reverted: false,\n                storageAccesses: new Vm.StorageAccess[](0),\n                depth: 1\n            })\n        );\n        assertEq(\n            called[2],\n            Vm.AccountAccess({\n                chainInfo: Vm.ChainInfo({forkId: 0, chainId: 0}),\n                accessor: address(a),\n                account: address(this),\n                kind: Vm.AccountAccessKind.SelfDestruct,\n                oldBalance: startingBalance - 1 ether,\n                newBalance: startingBalance,\n                oldNonce: 0,\n                newNonce: 0,\n                deployedCode: \"\",\n                initialized: true,\n                value: 1 ether,\n                data: \"\",\n                reverted: false,\n                storageAccesses: new Vm.StorageAccess[](0),\n                depth: 2\n            })\n        );\n        assertEq(\n            called[3],\n            Vm.AccountAccess({\n                chainInfo: Vm.ChainInfo({forkId: 0, chainId: 0}),\n                accessor: address(this),\n                account: b,\n                kind: Vm.AccountAccessKind.Create,\n                oldBalance: 0,\n                newBalance: 0,\n                oldNonce: 0,\n                newNonce: 1,\n                deployedCode: \"\",\n                initialized: true,\n                value: 1 ether,\n                data: abi.encodePacked(\n                    type(SelfDestructor).creationCode, abi.encode(address(bytes20(\"doesn't exist yet\")))\n                ),\n                reverted: false,\n                storageAccesses: new Vm.StorageAccess[](0),\n                depth: 3\n            })\n        );\n        assertEq(\n            called[4],\n            Vm.AccountAccess({\n                chainInfo: Vm.ChainInfo({forkId: 0, chainId: 0}),\n                accessor: address(b),\n                account: address(bytes20(\"doesn't exist yet\")),\n                kind: Vm.AccountAccessKind.SelfDestruct,\n                oldBalance: 0,\n                newBalance: 1 ether,\n                oldNonce: 0,\n                newNonce: 0,\n                deployedCode: hex\"\",\n                initialized: false,\n                value: 1 ether,\n                data: \"\",\n                reverted: false,\n                storageAccesses: new Vm.StorageAccess[](0),\n                depth: 4\n            })\n        );\n    }\n\n    /// @notice Asserts interaction between broadcast and recording cheatcodes\n    function testIssue6514() public {\n        vm.startStateDiffRecording();\n        vm.startBroadcast();\n\n        StorageAccessor a = new StorageAccessor();\n\n        vm.stopBroadcast();\n        Vm.AccountAccess[] memory called = filterExtcodesizeForLegacyTests(vm.stopAndReturnStateDiff());\n        assertEq(called.length, 1, \"incorrect length\");\n        assertEq(toUint(called[0].kind), toUint(Vm.AccountAccessKind.Create));\n        assertEq(called[0].account, address(a));\n    }\n\n    /// @notice Test that EXT* opcodes are recorded as account accesses\n    function testExtOpcodes() public {\n        vm.startStateDiffRecording();\n        extChecker.checkExts(address(1234));\n        Vm.AccountAccess[] memory called = vm.stopAndReturnStateDiff();\n        assertEq(called.length, 5, \"incorrect length\");\n        // call to extChecker\n        assertEq(toUint(called[0].kind), toUint(Vm.AccountAccessKind.Call));\n        // extChecker checks\n        assertEq(toUint(called[1].kind), toUint(Vm.AccountAccessKind.Extcodesize));\n        assertEq(toUint(called[2].kind), toUint(Vm.AccountAccessKind.Extcodehash));\n        assertEq(toUint(called[3].kind), toUint(Vm.AccountAccessKind.Extcodecopy));\n        assertEq(toUint(called[4].kind), toUint(Vm.AccountAccessKind.Balance));\n    }\n\n    /**\n     * @notice Filter out extcodesize account accesses for legacy tests written before\n     *         EXT* opcodes were supported.\n     */\n    function filterExtcodesizeForLegacyTests(Vm.AccountAccess[] memory inArr)\n        internal\n        pure\n        returns (Vm.AccountAccess[] memory out)\n    {\n        // allocate max length for out array\n        out = new Vm.AccountAccess[](inArr.length);\n        // track end size\n        uint256 size;\n        for (uint256 i = 0; i < inArr.length; ++i) {\n            // only append if not extcodesize\n            if (inArr[i].kind != Vm.AccountAccessKind.Extcodesize) {\n                out[size] = inArr[i];\n                ++size;\n            }\n        }\n        // manually truncate out array\n        assembly {\n            mstore(out, size)\n        }\n    }\n\n    function startRecordingFromLowerDepth() external {\n        vm.startStateDiffRecording();\n        assembly {\n            pop(call(gas(), 1234, 0, 0, 0, 0, 0))\n        }\n    }\n\n    function revertingCall(address target, bytes memory data) external payable {\n        assembly {\n            pop(call(gas(), target, div(callvalue(), 10), add(data, 0x20), mload(data), 0, 0))\n        }\n        revert();\n    }\n\n    /// Asserts that the given account access is a resume of the given parent\n    function assertResumeEq(Vm.AccountAccess memory actual, Vm.AccountAccess memory expected) internal {\n        assertEq(\n            actual,\n            Vm.AccountAccess({\n                chainInfo: Vm.ChainInfo({forkId: 0, chainId: 0}),\n                accessor: expected.accessor,\n                account: expected.account,\n                kind: Vm.AccountAccessKind.Resume,\n                oldBalance: 0,\n                newBalance: 0,\n                oldNonce: 0,\n                newNonce: 0,\n                deployedCode: \"\",\n                initialized: expected.initialized,\n                value: 0,\n                data: \"\",\n                reverted: expected.reverted,\n                storageAccesses: new Vm.StorageAccess[](0),\n                depth: 0\n            }),\n            false\n        );\n    }\n\n    function assertIncrementEq(\n        Vm.StorageAccess memory read,\n        Vm.StorageAccess memory write,\n        Vm.StorageAccess memory expected\n    ) internal {\n        assertEq(\n            read,\n            Vm.StorageAccess({\n                account: expected.account,\n                slot: expected.slot,\n                isWrite: false,\n                previousValue: expected.previousValue,\n                newValue: expected.previousValue,\n                reverted: expected.reverted\n            })\n        );\n        assertEq(\n            write,\n            Vm.StorageAccess({\n                account: expected.account,\n                slot: expected.slot,\n                isWrite: true,\n                previousValue: expected.previousValue,\n                newValue: expected.newValue,\n                reverted: expected.reverted\n            })\n        );\n    }\n\n    function assertEq(Vm.AccountAccess memory actualAccess, Vm.AccountAccess memory expectedAccess) internal {\n        assertEq(actualAccess, expectedAccess, true);\n    }\n\n    function assertEq(Vm.AccountAccess memory actualAccess, Vm.AccountAccess memory expectedAccess, bool checkStorage)\n        internal\n    {\n        assertEq(toUint(actualAccess.kind), toUint(expectedAccess.kind), \"incorrect kind\");\n        assertEq(actualAccess.account, expectedAccess.account, \"incorrect account\");\n        assertEq(actualAccess.accessor, expectedAccess.accessor, \"incorrect accessor\");\n        assertEq(toUint(actualAccess.initialized), toUint(expectedAccess.initialized), \"incorrect initialized\");\n        assertEq(actualAccess.oldBalance, expectedAccess.oldBalance, \"incorrect oldBalance\");\n        assertEq(actualAccess.newBalance, expectedAccess.newBalance, \"incorrect newBalance\");\n        assertEq(actualAccess.deployedCode, expectedAccess.deployedCode, \"incorrect deployedCode\");\n        assertEq(actualAccess.value, expectedAccess.value, \"incorrect value\");\n        assertEq(actualAccess.data, expectedAccess.data, \"incorrect data\");\n        assertEq(toUint(actualAccess.reverted), toUint(expectedAccess.reverted), \"incorrect reverted\");\n        if (checkStorage) {\n            assertEq(\n                actualAccess.storageAccesses.length,\n                expectedAccess.storageAccesses.length,\n                \"incorrect storageAccesses length\"\n            );\n            for (uint256 i = 0; i < actualAccess.storageAccesses.length; i++) {\n                assertEq(actualAccess.storageAccesses[i], expectedAccess.storageAccesses[i]);\n            }\n        }\n    }\n\n    function assertEq(Vm.StorageAccess memory actual, Vm.StorageAccess memory expected) internal {\n        assertEq(actual.account, expected.account, \"incorrect storageAccess account\");\n        assertEq(actual.slot, expected.slot, \"incorrect storageAccess slot\");\n        assertEq(toUint(actual.isWrite), toUint(expected.isWrite), \"incorrect storageAccess isWrite\");\n        assertEq(actual.previousValue, expected.previousValue, \"incorrect storageAccess previousValue\");\n        assertEq(actual.newValue, expected.newValue, \"incorrect storageAccess newValue\");\n        assertEq(toUint(actual.reverted), toUint(expected.reverted), \"incorrect storageAccess reverted\");\n    }\n\n    function toUint(Vm.AccountAccessKind kind) internal pure returns (uint256 value) {\n        assembly {\n            value := and(kind, 0xff)\n        }\n    }\n\n    function toUint(bool a) internal pure returns (uint256) {\n        return a ? 1 : 0;\n    }\n\n    function deriveCreate2Address(address deployer, bytes32 salt, bytes32 codeHash) internal pure returns (address) {\n        return address(uint160(uint256(keccak256(abi.encodePacked(bytes1(0xff), deployer, salt, codeHash)))));\n    }\n\n    /// @notice Simple test for getStorageAccesses() cheatcode\n    function testGetStorageAccesses() public {\n        StorageAccessor accessor = test1;\n\n        // Start recording to enable storage access tracking\n        vm.startStateDiffRecording();\n\n        // Perform a read operation\n        accessor.read(bytes32(uint256(789)));\n\n        // Perform a write operation\n        accessor.write(bytes32(uint256(123)), bytes32(uint256(456)));\n\n        // Perform another read operation after the write\n        accessor.read(bytes32(uint256(123)));\n\n        // Get all storage accesses\n        Vm.StorageAccess[] memory accesses = vm.getStorageAccesses();\n\n        // Check we have 3 storage accesses (2 reads + 1 write)\n        assertEq(accesses.length, 3, \"should have 3 storage accesses\");\n\n        // Check the first read access\n        assertEq(accesses[0].account, address(accessor));\n        assertEq(accesses[0].slot, bytes32(uint256(789)));\n        assertEq(accesses[0].isWrite, false);\n        assertEq(accesses[0].previousValue, bytes32(uint256(0)));\n        assertEq(accesses[0].newValue, bytes32(uint256(0)));\n        assertEq(accesses[0].reverted, false);\n\n        // Check the write access\n        assertEq(accesses[1].account, address(accessor));\n        assertEq(accesses[1].slot, bytes32(uint256(123)));\n        assertEq(accesses[1].isWrite, true);\n        assertEq(accesses[1].previousValue, bytes32(uint256(0)));\n        assertEq(accesses[1].newValue, bytes32(uint256(456)));\n        assertEq(accesses[1].reverted, false);\n\n        // Check the second read access (reading the value we just wrote)\n        assertEq(accesses[2].account, address(accessor));\n        assertEq(accesses[2].slot, bytes32(uint256(123)));\n        assertEq(accesses[2].isWrite, false);\n        assertEq(accesses[2].previousValue, bytes32(uint256(456)));\n        assertEq(accesses[2].newValue, bytes32(uint256(456)));\n        assertEq(accesses[2].reverted, false);\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/RecordDebugTrace.t.sol",
    "content": "// SPDX-License-Identifier: Unlicense\npragma solidity 0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract MStoreAndMLoadCaller {\n    uint256 public constant expectedValueInMemory = 999;\n\n    uint256 public memPtr; // the memory pointer being used\n\n    function storeAndLoadValueFromMemory() public returns (uint256) {\n        uint256 mPtr;\n        assembly {\n            mPtr := mload(0x40) // load free pointer\n            mstore(mPtr, expectedValueInMemory)\n            mstore(0x40, add(mPtr, 0x20))\n        }\n\n        // record & expose the memory pointer location\n        memPtr = mPtr;\n\n        uint256 result = 123;\n        assembly {\n            // override with `expectedValueInMemory`\n            result := mload(mPtr)\n        }\n        return result;\n    }\n}\n\ncontract FirstLayer {\n    SecondLayer secondLayer;\n\n    constructor(SecondLayer _secondLayer) {\n        secondLayer = _secondLayer;\n    }\n\n    function callSecondLayer() public view returns (uint256) {\n        return secondLayer.endHere();\n    }\n}\n\ncontract SecondLayer {\n    uint256 public constant endNumber = 123;\n\n    function endHere() public view returns (uint256) {\n        return endNumber;\n    }\n}\n\ncontract OutOfGas {\n    uint256 dummyVal = 0;\n\n    function consumeGas() public {\n        dummyVal += 1;\n    }\n\n    function triggerOOG() public {\n        bytes memory encodedFunctionCall = abi.encodeWithSignature(\"consumeGas()\", \"\");\n        uint256 notEnoughGas = 50;\n        (bool success,) = address(this).call{gas: notEnoughGas}(encodedFunctionCall);\n        require(!success, \"it should error out of gas\");\n    }\n}\n\ncontract RecordDebugTraceTest is Test {\n    /**\n     * The goal of this test is to ensure the debug steps provide the correct OPCODE with its stack\n     * and memory input used. The test checke MSTORE and MLOAD and ensure it records the expected\n     * stack and memory inputs.\n     */\n    function testDebugTraceCanRecordOpcodeWithStackAndMemoryData() public {\n        MStoreAndMLoadCaller testContract = new MStoreAndMLoadCaller();\n\n        vm.startDebugTraceRecording();\n\n        uint256 val = testContract.storeAndLoadValueFromMemory();\n        assertTrue(val == testContract.expectedValueInMemory());\n\n        Vm.DebugStep[] memory steps = vm.stopAndReturnDebugTraceRecording();\n\n        bool mstoreCalled = false;\n        bool mloadCalled = false;\n\n        for (uint256 i = 0; i < steps.length; i++) {\n            Vm.DebugStep memory step = steps[i];\n            if (\n                step.opcode == 0x52 /*MSTORE*/\n                    && step.stack[0] == testContract.memPtr() // MSTORE offset\n                    && step.stack[1] == testContract.expectedValueInMemory() // MSTORE val\n            ) {\n                mstoreCalled = true;\n            }\n\n            if (\n                step.opcode == 0x51 /*MLOAD*/\n                    && step.stack[0] == testContract.memPtr() // MLOAD offset\n                    && step.memoryInput.length == 32 // MLOAD should always load 32 bytes\n                    && uint256(bytes32(step.memoryInput)) == testContract.expectedValueInMemory() // MLOAD value\n            ) {\n                mloadCalled = true;\n            }\n        }\n\n        assertTrue(mstoreCalled);\n        assertTrue(mloadCalled);\n    }\n\n    /**\n     * This test tests that the cheatcode can correctly record the depth of the debug steps.\n     * This is test by test -> FirstLayer -> SecondLayer and check that the\n     * depth of the FirstLayer and SecondLayer are all as expected.\n     */\n    function testDebugTraceCanRecordDepth() public {\n        SecondLayer second = new SecondLayer();\n        FirstLayer first = new FirstLayer(second);\n\n        vm.startDebugTraceRecording();\n\n        first.callSecondLayer();\n\n        Vm.DebugStep[] memory steps = vm.stopAndReturnDebugTraceRecording();\n\n        bool goToDepthTwo = false;\n        bool goToDepthThree = false;\n        for (uint256 i = 0; i < steps.length; i++) {\n            Vm.DebugStep memory step = steps[i];\n\n            if (step.depth == 2) {\n                assertTrue(step.contractAddr == address(first), \"must be first layer on depth 2\");\n                goToDepthTwo = true;\n            }\n\n            if (step.depth == 3) {\n                assertTrue(step.contractAddr == address(second), \"must be second layer on depth 3\");\n                goToDepthThree = true;\n            }\n        }\n        assertTrue(goToDepthTwo && goToDepthThree, \"must have been to both first and second layer\");\n    }\n\n    /**\n     * The goal of this test is to ensure it can return expected `isOutOfGas` flag.\n     * It is tested with out of gas result here.\n     */\n    function testDebugTraceCanRecordOutOfGas() public {\n        OutOfGas testContract = new OutOfGas();\n\n        vm.startDebugTraceRecording();\n\n        testContract.triggerOOG();\n\n        Vm.DebugStep[] memory steps = vm.stopAndReturnDebugTraceRecording();\n\n        bool isOOG = false;\n        for (uint256 i = 0; i < steps.length; i++) {\n            Vm.DebugStep memory step = steps[i];\n\n            if (step.isOutOfGas) {\n                isOOG = true;\n            }\n        }\n        assertTrue(isOOG, \"should OOG\");\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/RecordLogs.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract Emitter {\n    event LogAnonymous(bytes data) anonymous;\n\n    event LogTopic0(bytes data);\n\n    event LogTopic1(uint256 indexed topic1, bytes data);\n\n    event LogTopic12(uint256 indexed topic1, uint256 indexed topic2, bytes data);\n\n    event LogTopic123(uint256 indexed topic1, uint256 indexed topic2, uint256 indexed topic3, bytes data);\n\n    function emitAnonymousEvent(bytes memory data) public {\n        emit LogAnonymous(data);\n    }\n\n    function emitEvent(bytes memory data) public {\n        emit LogTopic0(data);\n    }\n\n    function emitEvent(uint256 topic1, bytes memory data) public {\n        emit LogTopic1(topic1, data);\n    }\n\n    function emitEvent(uint256 topic1, uint256 topic2, bytes memory data) public {\n        emit LogTopic12(topic1, topic2, data);\n    }\n\n    function emitEvent(uint256 topic1, uint256 topic2, uint256 topic3, bytes memory data) public {\n        emit LogTopic123(topic1, topic2, topic3, data);\n    }\n}\n\ncontract Emitterv2 {\n    Emitter emitter = new Emitter();\n\n    function emitEvent(uint256 topic1, uint256 topic2, uint256 topic3, bytes memory data) public {\n        emitter.emitEvent(topic1, topic2, topic3, data);\n    }\n\n    function getEmitterAddr() public view returns (address) {\n        return address(emitter);\n    }\n}\n\ncontract RecordLogsTest is Test {\n    Emitter emitter;\n    bytes32 internal seedTestData = keccak256(abi.encodePacked(\"Some data\"));\n\n    // Used on testRecordOnEmitDifferentDepths()\n    event LogTopic(uint256 indexed topic1, bytes data);\n\n    function setUp() public {\n        emitter = new Emitter();\n    }\n\n    function generateTestData(uint8 n) internal returns (bytes memory) {\n        bytes memory output = new bytes(n);\n\n        for (uint8 i = 0; i < n; i++) {\n            output[i] = seedTestData[i % 32];\n            if (i % 32 == 31) {\n                seedTestData = keccak256(abi.encodePacked(seedTestData));\n            }\n        }\n\n        return output;\n    }\n\n    function testRecordOffGetsNothing() public {\n        emitter.emitEvent(1, 2, 3, generateTestData(48));\n        Vm.Log[] memory entries = vm.getRecordedLogs();\n\n        assertEq(entries.length, 0);\n    }\n\n    function testRecordOnNoLogs() public {\n        vm.recordLogs();\n        Vm.Log[] memory entries = vm.getRecordedLogs();\n\n        assertEq(entries.length, 0);\n    }\n\n    function testRecordOnSingleLog() public {\n        bytes memory testData = \"Event Data in String\";\n\n        vm.recordLogs();\n        emitter.emitEvent(1, 2, 3, testData);\n        Vm.Log[] memory entries = vm.getRecordedLogs();\n\n        assertEq(entries.length, 1);\n        assertEq(entries[0].topics.length, 4);\n        assertEq(entries[0].topics[0], keccak256(\"LogTopic123(uint256,uint256,uint256,bytes)\"));\n        assertEq(entries[0].topics[1], bytes32(uint256(1)));\n        assertEq(entries[0].topics[2], bytes32(uint256(2)));\n        assertEq(entries[0].topics[3], bytes32(uint256(3)));\n        assertEq(abi.decode(entries[0].data, (string)), string(testData));\n        assertEq(entries[0].emitter, address(emitter));\n    }\n\n    // TODO\n    // This crashes on decoding!\n    //   The application panicked (crashed).\n    //   Message:  index out of bounds: the len is 0 but the index is 0\n    //   Location: <local-dir>/evm/src/trace/decoder.rs:299\n    function NOtestRecordOnAnonymousEvent() public {\n        bytes memory testData = generateTestData(48);\n\n        vm.recordLogs();\n        emitter.emitAnonymousEvent(testData);\n        Vm.Log[] memory entries = vm.getRecordedLogs();\n\n        assertEq(entries.length, 1);\n    }\n\n    function testRecordOnSingleLogTopic0() public {\n        bytes memory testData = generateTestData(48);\n\n        vm.recordLogs();\n        emitter.emitEvent(testData);\n        Vm.Log[] memory entries = vm.getRecordedLogs();\n\n        assertEq(entries.length, 1);\n        assertEq(entries[0].topics.length, 1);\n        assertEq(entries[0].topics[0], keccak256(\"LogTopic0(bytes)\"));\n        // While not a proper string, this conversion allows the comparison.\n        assertEq(abi.decode(entries[0].data, (string)), string(testData));\n        assertEq(entries[0].emitter, address(emitter));\n    }\n\n    function testEmitRecordEmit() public {\n        bytes memory testData0 = generateTestData(32);\n        emitter.emitEvent(1, 2, testData0);\n\n        vm.recordLogs();\n        bytes memory testData1 = generateTestData(16);\n        emitter.emitEvent(3, testData1);\n        Vm.Log[] memory entries = vm.getRecordedLogs();\n\n        assertEq(entries.length, 1);\n        assertEq(entries[0].topics.length, 2);\n        assertEq(entries[0].topics[0], keccak256(\"LogTopic1(uint256,bytes)\"));\n        assertEq(entries[0].topics[1], bytes32(uint256(3)));\n        assertEq(abi.decode(entries[0].data, (string)), string(testData1));\n        assertEq(entries[0].emitter, address(emitter));\n    }\n\n    function testRecordOnEmitDifferentDepths() public {\n        vm.recordLogs();\n\n        bytes memory testData0 = generateTestData(16);\n        emit LogTopic(1, testData0);\n\n        bytes memory testData1 = generateTestData(20);\n        emitter.emitEvent(2, 3, testData1);\n\n        bytes memory testData2 = generateTestData(24);\n        Emitterv2 emitter2 = new Emitterv2();\n        emitter2.emitEvent(4, 5, 6, testData2);\n\n        Vm.Log[] memory entries = vm.getRecordedLogs();\n\n        assertEq(entries.length, 3);\n\n        assertEq(entries[0].topics.length, 2);\n        assertEq(entries[0].topics[0], keccak256(\"LogTopic(uint256,bytes)\"));\n        assertEq(entries[0].topics[1], bytes32(uint256(1)));\n        assertEq(abi.decode(entries[0].data, (string)), string(testData0));\n        assertEq(entries[0].emitter, address(this));\n\n        assertEq(entries[1].topics.length, 3);\n        assertEq(entries[1].topics[0], keccak256(\"LogTopic12(uint256,uint256,bytes)\"));\n        assertEq(entries[1].topics[1], bytes32(uint256(2)));\n        assertEq(entries[1].topics[2], bytes32(uint256(3)));\n        assertEq(abi.decode(entries[1].data, (string)), string(testData1));\n        assertEq(entries[1].emitter, address(emitter));\n\n        assertEq(entries[2].topics.length, 4);\n        assertEq(entries[2].topics[0], keccak256(\"LogTopic123(uint256,uint256,uint256,bytes)\"));\n        assertEq(entries[2].topics[1], bytes32(uint256(4)));\n        assertEq(entries[2].topics[2], bytes32(uint256(5)));\n        assertEq(entries[2].topics[3], bytes32(uint256(6)));\n        assertEq(abi.decode(entries[2].data, (string)), string(testData2));\n        assertEq(entries[2].emitter, emitter2.getEmitterAddr());\n    }\n\n    function testRecordedLogsJson() public {\n        bytes memory testData = \"Event Data in String\";\n\n        vm.recordLogs();\n        emitter.emitEvent(1, 2, 3, testData);\n        string memory logsJson = vm.getRecordedLogsJson();\n\n        // Verify JSON structure and values\n        assertGt(bytes(logsJson).length, 0);\n\n        // Verify emitter address\n        string memory emitterAddr = vm.parseJsonString(logsJson, \"[0].emitter\");\n        assertEq(vm.parseAddress(emitterAddr), address(emitter));\n\n        // Verify topics - first topic is event signature\n        string[] memory topics = vm.parseJsonStringArray(logsJson, \"[0].topics\");\n        assertEq(topics.length, 4);\n        assertEq(vm.parseBytes32(topics[0]), keccak256(\"LogTopic123(uint256,uint256,uint256,bytes)\"));\n        assertEq(vm.parseBytes32(topics[1]), bytes32(uint256(1)));\n        assertEq(vm.parseBytes32(topics[2]), bytes32(uint256(2)));\n        assertEq(vm.parseBytes32(topics[3]), bytes32(uint256(3)));\n\n        // Verify data is hex-encoded\n        string memory data = vm.parseJsonString(logsJson, \"[0].data\");\n        assertGt(bytes(data).length, 2); // At least \"0x\"\n    }\n\n    function testRecordedLogsJsonEmpty() public {\n        vm.recordLogs();\n        string memory logsJson = vm.getRecordedLogsJson();\n\n        // Empty array\n        assertEq(logsJson, \"[]\");\n    }\n\n    function testRecordsConsumednAsRead() public {\n        Vm.Log[] memory entries;\n\n        emitter.emitEvent(1, generateTestData(16));\n\n        // hit record now\n        vm.recordLogs();\n\n        entries = vm.getRecordedLogs();\n        assertEq(entries.length, 0);\n\n        // emit after calling .getRecordedLogs()\n        emitter.emitEvent(2, 3, generateTestData(24));\n\n        entries = vm.getRecordedLogs();\n        assertEq(entries.length, 1);\n        assertEq(entries[0].topics.length, 3);\n        assertEq(entries[0].emitter, address(emitter));\n\n        // let's emit two more!\n        emitter.emitEvent(4, 5, 6, generateTestData(20));\n        emitter.emitEvent(generateTestData(32));\n\n        entries = vm.getRecordedLogs();\n        assertEq(entries.length, 2);\n        assertEq(entries[0].topics.length, 4);\n        assertEq(entries[1].topics.length, 1);\n        assertEq(entries[0].emitter, address(emitter));\n        assertEq(entries[1].emitter, address(emitter));\n\n        // the last one\n        emitter.emitEvent(7, 8, 9, generateTestData(24));\n\n        entries = vm.getRecordedLogs();\n        assertEq(entries.length, 1);\n        assertEq(entries[0].topics.length, 4);\n        assertEq(entries[0].emitter, address(emitter));\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/Remember.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract RememberTest is Test {\n    function testRememberKey() public {\n        string memory mnemonic = \"test test test test test test test test test test test junk\";\n\n        uint256 privateKey = vm.deriveKey(mnemonic, 0);\n        assertEq(privateKey, 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80);\n\n        address thisAddress = vm.rememberKey(privateKey);\n        assertEq(thisAddress, 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266);\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/ResetNonce.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract Foo {\n    function f() external view returns (uint256) {\n        return 1;\n    }\n}\n\ncontract ResetNonce is Test {\n    Foo public fooContract;\n    address barEOA;\n\n    function setUp() public {\n        fooContract = new Foo();\n        barEOA = address(0x42);\n    }\n\n    function testResetNonceContract() public {\n        vm.setNonce(address(fooContract), 10);\n\n        // makes sure working correctly after mutating nonce.\n        fooContract.f();\n        assertEq(vm.getNonce(address(fooContract)), 10);\n        fooContract.f();\n\n        // now make sure that it is reset after calling the cheatcode.\n        vm.resetNonce(address(fooContract));\n        assertEq(vm.getNonce(address(fooContract)), 1);\n        fooContract.f();\n    }\n\n    function testResetNonceEOA() public {\n        vm.setNonce(address(barEOA), 10);\n        assertEq(vm.getNonce(address(barEOA)), 10);\n        vm.resetNonce(address(barEOA));\n        assertEq(vm.getNonce(address(barEOA)), 0);\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/Rlp.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract Rlp is Test {\n    function testToRlp() public {\n        bytes[] memory data = new bytes[](2);\n        data[0] = hex\"01\";\n        data[1] = hex\"02\";\n\n        bytes memory rlp = vm.toRlp(data);\n\n        // Assert the expected RLP encoding for [0x01, 0x02]\n        // 0xc2 = list with 2 bytes total length\n        // 0x01 = first byte\n        // 0x02 = second byte\n        assertEq(rlp, hex\"c20102\");\n    }\n\n    function testFromRlp() public {\n        // RLP encoded [0x01, 0x02]\n        bytes memory rlp = hex\"c20102\";\n\n        bytes[] memory decoded = vm.fromRlp(rlp);\n        assertEq(decoded.length, 2);\n        assertEq(decoded[0], hex\"01\");\n        assertEq(decoded[1], hex\"02\");\n    }\n\n    function testRoundTrip() public {\n        bytes[] memory original = new bytes[](3);\n        original[0] = hex\"deadbeef\";\n        original[1] = hex\"cafebabe\";\n        original[2] = hex\"01020304\";\n\n        bytes memory rlp = vm.toRlp(original);\n        bytes[] memory decoded = vm.fromRlp(rlp);\n\n        assertEq(decoded.length, original.length);\n        for (uint256 i = 0; i < original.length; i++) {\n            assertEq(decoded[i], original[i]);\n        }\n    }\n\n    function testDecodeBlockHeader() public {\n        // cast block 23270177  --raw\n        bytes memory blockHeader =\n            hex\"f9027da01581f4448b16694d5a728161cd65f8c80b88f5352a6f5bd2d2315b970582958da01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794dadb0d80178819f2319190d340ce9a924f783711a010d2afa5dabcf2dbfe3aa82b758427938e07880bd6fef3c82c404d0dd7c3f0f3a0f81230c715a462c827898bf2e337982907a7af90e5be20f911785bda05dab93ca0740f11bc75cf25e40d78d892d2e03083eaa573e5b4c26913fcc1b833db854c94b9010085f734fb06ea8fe377abbcb2e27f9ac99751ba817dc327327db101fd76f964ed0b7ca161f148fc165b9e5b575dc7473f17f4b8ebbf4a7b02b3e1e642197f27b2af54680834449abaf833619ac7d18afb50b19d5f6944dca0dc952edfdd9837573783c339ee6a36353ce6e536eaaf29fcd569c426091d4e24568dc353347f98c74fb6f8c91d68d358467c437563f66566377fe6c3f9e8301dbeb5fc7e7adee7a85ef5f8fa905cedbaf26601e21ba91646cac4034601e51d889d49739ee6990943a6a41927660f68e1f50b9f9209ee29551a7dae478d88e0547eefc83334ea770bb6fbac620fc47479c2c59389622bf32f55e36a75e56a5fc47c38bf8ef211fc0e8084016313218402af50e883fc53b78468b5ea9b974275696c6465724e657420284e65746865726d696e6429a0580ca94e91c0e7aef26ffb0c86f6ae48ef40df6dd1629f203a1930e0ce0be9d188000000000000000084479c1e2aa00345740e1b79edb2fbb3a20220e1a497ea9bb82aaba7dc7a881f7f3cae8a8ea38080a06675ad2a40134499a753924a04b75898ae09efc6fba6b3d7a506203042cb7611a0e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\";\n\n        bytes[] memory decoded = vm.fromRlp(blockHeader);\n\n        // Verify key fields against known values from block 23270177\n        assertEq(decoded.length, 21);\n        assertEq(decoded[0], hex\"1581f4448b16694d5a728161cd65f8c80b88f5352a6f5bd2d2315b970582958d\", \"parentHash\");\n        assertEq(decoded[1], hex\"1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347\", \"uncleHash\");\n        assertEq(decoded[2], hex\"dadb0d80178819f2319190d340ce9a924f783711\", \"coinbase\");\n        assertEq(decoded[3], hex\"10d2afa5dabcf2dbfe3aa82b758427938e07880bd6fef3c82c404d0dd7c3f0f3\", \"stateRoot\");\n        assertEq(decoded[4], hex\"f81230c715a462c827898bf2e337982907a7af90e5be20f911785bda05dab93c\", \"transactionsRoot\");\n        assertEq(decoded[5], hex\"740f11bc75cf25e40d78d892d2e03083eaa573e5b4c26913fcc1b833db854c94\", \"receiptsRoot\");\n\n        {\n            // Verify logsBloom (256 bytes)\n            bytes memory logsBloom = decoded[6];\n            assertEq(logsBloom.length, 256, \"logsBloom length\");\n            _checkLogsBloom(logsBloom, 0, 0x85f734fb06ea8fe377abbcb2e27f9ac99751ba817dc327327db101fd76f964ed);\n            _checkLogsBloom(logsBloom, 1, 0x0b7ca161f148fc165b9e5b575dc7473f17f4b8ebbf4a7b02b3e1e642197f27b2);\n            _checkLogsBloom(logsBloom, 2, 0xaf54680834449abaf833619ac7d18afb50b19d5f6944dca0dc952edfdd983757);\n            _checkLogsBloom(logsBloom, 3, 0x3783c339ee6a36353ce6e536eaaf29fcd569c426091d4e24568dc353347f98c7);\n            _checkLogsBloom(logsBloom, 4, 0x4fb6f8c91d68d358467c437563f66566377fe6c3f9e8301dbeb5fc7e7adee7a8);\n            _checkLogsBloom(logsBloom, 5, 0x5ef5f8fa905cedbaf26601e21ba91646cac4034601e51d889d49739ee6990943);\n            _checkLogsBloom(logsBloom, 6, 0xa6a41927660f68e1f50b9f9209ee29551a7dae478d88e0547eefc83334ea770b);\n            _checkLogsBloom(logsBloom, 7, 0xb6fbac620fc47479c2c59389622bf32f55e36a75e56a5fc47c38bf8ef211fc0e);\n        }\n\n        assertEq(decoded[7], hex\"\", \"difficulty\");\n        assertEq(decoded[8], hex\"01631321\", \"number\");\n        assertEq(decoded[9], hex\"02af50e8\", \"gasLimit\");\n        assertEq(decoded[10], hex\"fc53b7\", \"gasUsed\");\n        assertEq(decoded[11], hex\"68b5ea9b\", \"timestamp\");\n        assertEq(decoded[12], hex\"4275696c6465724e657420284e65746865726d696e6429\", \"extraData\");\n        assertEq(decoded[13], hex\"580ca94e91c0e7aef26ffb0c86f6ae48ef40df6dd1629f203a1930e0ce0be9d1\", \"mixHash\");\n        assertEq(decoded[14], hex\"0000000000000000\", \"nonce\");\n        assertEq(decoded[15], hex\"479c1e2a\", \"baseFee\");\n        assertEq(decoded[16], hex\"0345740e1b79edb2fbb3a20220e1a497ea9bb82aaba7dc7a881f7f3cae8a8ea3\", \"withdrawalsHash\");\n        assertEq(decoded[17], hex\"\", \"blobGasUsed\");\n        assertEq(decoded[18], hex\"\", \"excessBlobGas\");\n        assertEq(decoded[19], hex\"6675ad2a40134499a753924a04b75898ae09efc6fba6b3d7a506203042cb7611\", \"parentBeaconRoot\");\n        assertEq(decoded[20], hex\"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\", \"requestsHash\");\n    }\n\n    function _checkLogsBloom(bytes memory data, uint256 n, uint256 expected) internal {\n        uint256 offset = (n + 1) * 32;\n        bytes32 result;\n        assembly {\n            result := mload(add(data, offset))\n        }\n\n        assertEq(result, bytes32(expected), string.concat(\"logsBloom[\", vm.toString(n), \"]\"));\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/Roll.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract RollTest is Test {\n    function testRoll() public {\n        vm.roll(10);\n        assertEq(block.number, 10, \"roll failed\");\n    }\n\n    function testRollFuzzed(uint32 jump) public {\n        uint256 pre = block.number;\n        vm.roll(block.number + jump);\n        assertEq(block.number, pre + jump, \"roll failed\");\n    }\n\n    function testRollHash() public {\n        assertEq(blockhash(block.number), 0x0, \"initial block hash is incorrect\");\n\n        vm.roll(5);\n        bytes32 hash = blockhash(5);\n        assertTrue(blockhash(4) != 0x0, \"new block hash is incorrect\");\n\n        vm.roll(10);\n        assertTrue(blockhash(5) != blockhash(10), \"block hash collision\");\n\n        vm.roll(5);\n        assertEq(blockhash(5), hash, \"block 5 changed hash\");\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/RpcUrls.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract RpcUrlTest is Test {\n    // returns the correct url\n    function testCanGetRpcUrl() public {\n        string memory url = vm.rpcUrl(\"mainnet\");\n        assertTrue(bytes(url).length != 0);\n    }\n\n    // returns an error if env alias does not exist\n    function testRevertsOnMissingEnv() public {\n        vm._expectCheatcodeRevert(\"invalid rpc url: rpcUrlEnv\");\n        string memory url = vm.rpcUrl(\"rpcUrlEnv\");\n    }\n\n    // can set env and return correct url\n    function testCanSetAndGetURLAndAllUrls() public {\n        // this will fail because alias is not set\n        vm._expectCheatcodeRevert(\"environment variable `RPC_ENV_ALIAS` not found\");\n        string[2][] memory _urls = vm.rpcUrls();\n\n        string memory url = vm.rpcUrl(\"mainnet\");\n        vm.setEnv(\"RPC_ENV_ALIAS\", url);\n        string memory envUrl = vm.rpcUrl(\"rpcEnvAlias\");\n        assertEq(url, envUrl);\n\n        string[2][] memory allUrls = vm.rpcUrls();\n        assertGe(allUrls.length, 2);\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/Seed.t.sol",
    "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract SeedTest is Test {\n    function testSeedAffectsRandom() public {\n        // Use a known seed\n        uint256 seed = 123456789;\n        vm.setSeed(seed);\n\n        // Call a foundry cheatcode to get a random value (this depends on the integration)\n        uint256 rand1 = uint256(vm.randomUint());\n\n        // Reset the seed and verify the result is the same\n        vm.setSeed(seed);\n        uint256 rand2 = uint256(vm.randomUint());\n\n        uint256 rand3 = uint256(vm.randomUint());\n        // If the seed is the same, the random value must be equal\n        assertEq(rand1, rand2);\n        assertTrue(rand1 != rand3);\n    }\n\n    function testSeedChangesRandom() public {\n        // Use one seed\n        vm.setSeed(1);\n        uint256 randA = uint256(vm.randomUint());\n\n        // Use a different seed\n        vm.setSeed(2);\n        uint256 randB = uint256(vm.randomUint());\n\n        // Values must be different\n        assertTrue(randA != randB, \"Random value must be different if seed is different\");\n    }\n\n    function testSeedAffectsShuffle() public {\n        // Use a known seed\n        uint256 seed = 123456789;\n        vm.setSeed(seed);\n\n        // Create two identical arrays\n        uint256[] memory array1 = new uint256[](5);\n        uint256[] memory array2 = new uint256[](5);\n        for (uint256 i = 0; i < 5; i++) {\n            array1[i] = i;\n            array2[i] = i;\n        }\n\n        // Shuffle both arrays with the same seed\n        array1 = vm.shuffle(array1);\n        vm.setSeed(seed); // Reset the seed to get the same shuffle pattern\n        array2 = vm.shuffle(array2);\n\n        // Compare elements - they should be identical after shuffle\n        for (uint256 i = 0; i < array1.length; i++) {\n            assertEq(array1[i], array2[i], \"Arrays should be identical with same seed\");\n        }\n    }\n\n    function testDifferentSeedsProduceDifferentShuffles() public {\n        // Create the initial array\n        uint256[] memory array1 = new uint256[](5);\n        uint256[] memory array2 = new uint256[](5);\n        for (uint256 i = 0; i < 5; i++) {\n            array1[i] = i;\n            array2[i] = i;\n        }\n\n        // Use first seed\n        vm.setSeed(1);\n        array1 = vm.shuffle(array1);\n\n        // Use second seed\n        vm.setSeed(2);\n        array2 = vm.shuffle(array2);\n\n        // Arrays should be different (we'll check at least one difference exists)\n        bool foundDifference = false;\n        for (uint256 i = 0; i < array1.length; i++) {\n            if (array1[i] != array2[i]) {\n                foundDifference = true;\n                break;\n            }\n        }\n        assertTrue(foundDifference, \"Arrays should be different with different seeds\");\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/SetBlockhash.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract SetBlockhash is Test {\n    function testSetBlockhash() public {\n        bytes32 blockHash = 0x1234567890123456789012345678901234567890123456789012345678901234;\n        vm.setBlockhash(block.number - 1, blockHash);\n        bytes32 expected = blockhash(block.number - 1);\n        assertEq(blockHash, expected);\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/SetNonce.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract Foo {\n    function f() external view returns (uint256) {\n        return 1;\n    }\n}\n\ncontract SetNonceTest is Test {\n    Foo public foo;\n\n    function setUp() public {\n        foo = new Foo();\n    }\n\n    function testSetNonce() public {\n        vm.setNonce(address(foo), 10);\n        // makes sure working correctly after mutating nonce.\n        foo.f();\n        assertEq(vm.getNonce(address(foo)), 10);\n        foo.f();\n    }\n\n    /// forge-config: default.allow_internal_expect_revert = true\n    function testRevertIfInvalidNonce() public {\n        vm.setNonce(address(foo), 10);\n        // set lower nonce should fail\n        vm.expectRevert(\n            \"vm.setNonce: new nonce (5) must be strictly equal to or higher than the account's current nonce (10)\"\n        );\n        vm.setNonce(address(foo), 5);\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/SetNonceUnsafe.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract Foo {\n    function f() external view returns (uint256) {\n        return 1;\n    }\n}\n\ncontract SetNonceTest is Test {\n    Foo public foo;\n\n    function setUp() public {\n        foo = new Foo();\n    }\n\n    function testSetNonceUnsafe() public {\n        vm.setNonceUnsafe(address(foo), 10);\n        // makes sure working correctly after mutating nonce.\n        foo.f();\n        assertEq(vm.getNonce(address(foo)), 10);\n        foo.f();\n    }\n\n    function testDoesNotFailDecreasingNonce() public {\n        vm.setNonce(address(foo), 10);\n        vm.setNonceUnsafe(address(foo), 5);\n        assertEq(vm.getNonce(address(foo)), 5);\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/Setup.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract Victim {\n    function assertSender(address sender) external {\n        require(msg.sender == sender, \"sender was not pranked\");\n    }\n}\n\ncontract VmSetupTest is Test {\n    Victim victim;\n\n    function setUp() public {\n        victim = new Victim();\n\n        vm.warp(10);\n        vm.chainId(99);\n        vm.roll(100);\n        vm.fee(1000);\n        vm.prevrandao(uint256(10000));\n        vm.startPrank(address(1337));\n    }\n\n    function testCheatEnvironment() public {\n        assertEq(block.timestamp, 10, \"block timestamp was not persisted from setup\");\n        assertEq(block.number, 100, \"block number was not persisted from setup\");\n        assertEq(block.basefee, 1000, \"basefee was not persisted from setup\");\n        assertEq(block.prevrandao, 10000, \"prevrandao was not persisted from setup\");\n        assertEq(block.chainid, 99, \"chainid was not persisted from setup\");\n        victim.assertSender(address(1337));\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/Shuffle.t.sol",
    "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract ShuffleTest is Test {\n    function testDeterministicShuffle() public {\n        // Use a known seed\n        uint256 seed = 123456789;\n        vm.setSeed(seed);\n\n        // Create two identical arrays\n        uint256[] memory array1 = new uint256[](5);\n        uint256[] memory array2 = new uint256[](5);\n        for (uint256 i = 0; i < 5; i++) {\n            array1[i] = i;\n            array2[i] = i;\n        }\n\n        // Shuffle both arrays with the same seed\n        array1 = vm.shuffle(array1);\n        vm.setSeed(seed); // Reset the seed to get the same shuffle pattern\n        array2 = vm.shuffle(array2);\n\n        // Compare elements - they should be identical after shuffle\n        for (uint256 i = 0; i < array1.length; i++) {\n            assertEq(array1[i], array2[i], \"Arrays should be identical with same seed\");\n        }\n    }\n\n    function testDifferentSeedsProduceDifferentShuffles() public {\n        // Create the initial array\n        uint256[] memory array1 = new uint256[](5);\n        uint256[] memory array2 = new uint256[](5);\n        for (uint256 i = 0; i < 5; i++) {\n            array1[i] = i;\n            array2[i] = i;\n        }\n\n        // Use first seed\n        vm.setSeed(1);\n        array1 = vm.shuffle(array1);\n\n        // Use second seed\n        vm.setSeed(2);\n        array2 = vm.shuffle(array2);\n\n        // Arrays should be different (we'll check at least one difference exists)\n        bool foundDifference = false;\n        for (uint256 i = 0; i < array1.length; i++) {\n            if (array1[i] != array2[i]) {\n                foundDifference = true;\n                break;\n            }\n        }\n        assertTrue(foundDifference, \"Arrays should be different with different seeds\");\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/Sign.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract SignTest is Test {\n    function testSignDigest(uint248 pk, bytes32 digest) public {\n        vm.assume(pk != 0);\n\n        (uint8 v, bytes32 r, bytes32 s) = vm.sign(pk, digest);\n        address expected = vm.addr(pk);\n        address actual = ecrecover(digest, v, r, s);\n        assertEq(actual, expected, \"digest signer did not match\");\n    }\n\n    function testSignCompactDigest(uint248 pk, bytes32 digest) public {\n        vm.assume(pk != 0);\n\n        (bytes32 r, bytes32 vs) = vm.signCompact(pk, digest);\n\n        // Extract `s` from `vs`.\n        // Shift left by 1 bit to clear the leftmost bit, then shift right by 1 bit to restore the original position.\n        // This effectively clears the leftmost bit of `vs`, giving us `s`.\n        bytes32 s = bytes32((uint256(vs) << 1) >> 1);\n\n        // Extract `v` from `vs`.\n        // We shift `vs` right by 255 bits to isolate the leftmost bit.\n        // Converting this to uint8 gives us the parity bit (0 or 1).\n        // Adding 27 converts this parity bit to the correct `v` value (27 or 28).\n        uint8 v = uint8(uint256(vs) >> 255) + 27;\n\n        address expected = vm.addr(pk);\n        address actual = ecrecover(digest, v, r, s);\n        assertEq(actual, expected, \"digest signer did not match\");\n    }\n\n    function testSignMessage(uint248 pk, bytes memory message) public {\n        testSignDigest(pk, keccak256(message));\n    }\n\n    function testSignCompactMessage(uint248 pk, bytes memory message) public {\n        testSignCompactDigest(pk, keccak256(message));\n    }\n\n    /// secp256k1 subgroup order n\n    function _secp256k1Order() internal pure returns (uint256) {\n        return 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141;\n    }\n\n    function testsignWithNonceUnsafeDigestDifferentNonces(uint248 pk, bytes32 digest) public {\n        vm.assume(pk != 0);\n        uint256 n1 = 123;\n        uint256 n2 = 456;\n        vm.assume(n1 != 0 && n2 != 0 && n1 != n2);\n        (uint8 v1, bytes32 r1, bytes32 s1) = vm.signWithNonceUnsafe(pk, digest, n1);\n        (uint8 v2, bytes32 r2, bytes32 s2) = vm.signWithNonceUnsafe(pk, digest, n2);\n        assertTrue(r1 != r2 || s1 != s2, \"signatures should differ for different nonces\");\n        address expected = vm.addr(pk);\n        assertEq(ecrecover(digest, v1, r1, s1), expected, \"recover for nonce n1 failed\");\n        assertEq(ecrecover(digest, v2, r2, s2), expected, \"recover for nonce n2 failed\");\n    }\n\n    function testsignWithNonceUnsafeDigestSameNonceDeterministic(uint248 pk, bytes32 digest) public {\n        vm.assume(pk != 0);\n        uint256 n = 777;\n        vm.assume(n != 0);\n        (uint8 v1, bytes32 r1, bytes32 s1) = vm.signWithNonceUnsafe(pk, digest, n);\n        (uint8 v2, bytes32 r2, bytes32 s2) = vm.signWithNonceUnsafe(pk, digest, n);\n        assertEq(v1, v2, \"v should match\");\n        assertEq(r1, r2, \"r should match\");\n        assertEq(s1, s2, \"s should match\");\n        address expected = vm.addr(pk);\n        assertEq(ecrecover(digest, v1, r1, s1), expected, \"recover failed\");\n    }\n\n    function testsignWithNonceUnsafeInvalidNoncesRevert() public {\n        uint256 pk = 1;\n        bytes32 digest = 0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb;\n        (bool ok, bytes memory data) =\n            HEVM_ADDRESS.call(abi.encodeWithSelector(Vm.signWithNonceUnsafe.selector, pk, digest, 0));\n        assertTrue(!ok, \"expected revert on nonce=0\");\n        assertEq(_revertString(data), \"vm.signWithNonceUnsafe: nonce cannot be 0\");\n        uint256 n = _secp256k1Order();\n        (ok, data) = HEVM_ADDRESS.call(abi.encodeWithSelector(Vm.signWithNonceUnsafe.selector, pk, digest, n));\n        assertTrue(!ok, \"expected revert on nonce >= n\");\n        assertEq(_revertString(data), \"vm.signWithNonceUnsafe: invalid nonce scalar\");\n    }\n\n    /// Decode revert payload\n    /// by stripping the 4-byte selector and ABI-decoding the tail as `string`.\n    function _revertString(bytes memory data) internal pure returns (string memory) {\n        if (data.length < 4) return \"\";\n        // copy data[4:] into a new bytes\n        bytes memory tail = new bytes(data.length - 4);\n        for (uint256 i = 0; i < tail.length; i++) {\n            tail[i] = data[i + 4];\n        }\n        return abi.decode(tail, (string));\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/SignP256.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract SignTest is Test {\n    function testSignP256() public {\n        bytes32 pk = hex\"A8568B74282DCC66FF70F10B4CE5CC7B391282F5381BBB4F4D8DD96974B16E6B\";\n        bytes32 digest = hex\"54705ba3baafdbdfba8c5f9a70f7a89bee98d906b53e31074da7baecdc0da9ad\";\n\n        (bytes32 r, bytes32 s) = vm.signP256(uint256(pk), digest);\n        assertEq(r, hex\"7C11C3641B19E7822DB644CBF76ED0420A013928C2FD3E36D8EF983B103BDFE1\");\n        assertEq(s, hex\"317D89879868D484810D4E508A96109F8C87617B7BE9337411348D7B786F945F\");\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/Skip.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract SkipTest is Test {\n    function testSkip() public {\n        vm.skip(true);\n        revert(\"Should not reach this revert\");\n    }\n\n    /// forge-config: default.allow_internal_expect_revert = true\n    function testRevertIfNotSkip() public {\n        vm.skip(false);\n        vm.expectRevert(\"This test should fail\");\n        revert(\"This test should fail\");\n    }\n\n    function testFuzzSkip(uint256 x) public {\n        vm.skip(true);\n        revert(\"Should not reach revert\");\n    }\n\n    /// forge-config: default.allow_internal_expect_revert = true\n    function testRevertIfFuzzSkip(uint256 x) public {\n        vm.skip(false);\n        vm.expectRevert(\"This test should fail\");\n        revert(\"This test should fail\");\n    }\n\n    function statefulFuzzSkip() public {\n        vm.skip(true);\n        require(true == false, \"Test should not reach invariant\");\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/Sleep.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract SleepTest is Test {\n    function testSleep() public {\n        uint256 milliseconds = 1234;\n\n        string[] memory inputs = new string[](2);\n        inputs[0] = \"date\";\n        // OS X does not support precision more than 1 second\n        inputs[1] = \"+%s000\";\n\n        bytes memory res = vm.ffi(inputs);\n        uint256 start = vm.parseUint(string(res));\n\n        vm.sleep(milliseconds);\n\n        res = vm.ffi(inputs);\n        uint256 end = vm.parseUint(string(res));\n\n        // Limit precision to 1000 ms\n        assertGe(end - start, milliseconds / 1000 * 1000, \"sleep failed\");\n    }\n\n    /// forge-config: default.fuzz.runs = 2\n    function testSleepFuzzed(uint256 _milliseconds) public {\n        // Limit sleep time to 2 seconds to decrease test time\n        uint256 milliseconds = _milliseconds % 2000;\n\n        string[] memory inputs = new string[](2);\n        inputs[0] = \"date\";\n        // OS X does not support precision more than 1 second\n        inputs[1] = \"+%s000\";\n\n        bytes memory res = vm.ffi(inputs);\n        uint256 start = vm.parseUint(string(res));\n\n        vm.sleep(milliseconds);\n\n        res = vm.ffi(inputs);\n        uint256 end = vm.parseUint(string(res));\n\n        // Limit precision to 1000 ms\n        assertGe(end - start, milliseconds / 1000 * 1000, \"sleep failed\");\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/Sort.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract SortTest is Test {\n    function testSortCheatcode() public {\n        uint256[] memory numbers = new uint256[](3);\n        numbers[0] = 3;\n        numbers[1] = 1;\n        numbers[2] = 2;\n\n        uint256[] memory sortedNumbers = vm.sort(numbers);\n\n        assertEq(sortedNumbers[0], 1);\n        assertEq(sortedNumbers[1], 2);\n        assertEq(sortedNumbers[2], 3);\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/StateDiffBytesString.t.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract BytesStringStorage {\n    // Short string (less than 32 bytes)\n    string public shortString; // Slot 0\n\n    // Long string (32 bytes or more)\n    string public longString; // Slot 1\n\n    // Short bytes\n    bytes public shortBytes; // Slot 2\n\n    // Long bytes\n    bytes public longBytes; // Slot 3\n\n    // Fixed size bytes\n    bytes32 public fixedBytes; // Slot 4\n\n    // Mapping with string values\n    mapping(address => string) public userNames; // Slot 5\n\n    function setShortString(string memory _value) public {\n        shortString = _value;\n    }\n\n    function setLongString(string memory _value) public {\n        longString = _value;\n    }\n\n    function setShortBytes(bytes memory _value) public {\n        shortBytes = _value;\n    }\n\n    function setLongBytes(bytes memory _value) public {\n        longBytes = _value;\n    }\n\n    function setFixedBytes(bytes32 _value) public {\n        fixedBytes = _value;\n    }\n\n    function setUserName(address user, string memory name) public {\n        userNames[user] = name;\n    }\n}\n\ncontract StateDiffBytesStringTest is Test {\n    BytesStringStorage bytesStringStorage;\n\n    function setUp() public {\n        bytesStringStorage = new BytesStringStorage();\n    }\n\n    function testLongStringStorage() public {\n        // Start recording state diffs\n        vm.startStateDiffRecording();\n\n        // Set a long string (32 bytes or more)\n        string memory longStr =\n            \"This is a very long string that exceeds 32 bytes and will be stored differently in Solidity storage\";\n        bytesStringStorage.setLongString(longStr);\n\n        // Get the state diff as string\n        string memory stateDiff = vm.getStateDiff();\n        emit log_string(\"State diff for long string:\");\n        emit log_string(stateDiff);\n\n        // Get the state diff as JSON\n        string memory stateDiffJson = vm.getStateDiffJson();\n        emit log_string(\"State diff JSON for long string:\");\n        emit log_string(stateDiffJson);\n\n        // Verify the JSON contains expected fields\n        assertTrue(vm.contains(stateDiffJson, '\"label\":\"longString\"'));\n        assertTrue(vm.contains(stateDiffJson, '\"type\":\"string\"'));\n\n        // For long strings, we should see multiple slots being accessed\n        // The main slot (slot 1) contains the length\n        // The data slots start at keccak256(1)\n\n        // Stop recording\n        Vm.AccountAccess[] memory accesses = vm.stopAndReturnStateDiff();\n        assertTrue(accesses.length > 0);\n\n        // Verify storage accesses\n        uint256 writeCount = 0;\n        for (uint256 i = 0; i < accesses.length; i++) {\n            if (accesses[i].account == address(bytesStringStorage)) {\n                for (uint256 j = 0; j < accesses[i].storageAccesses.length; j++) {\n                    if (accesses[i].storageAccesses[j].isWrite) {\n                        writeCount++;\n                    }\n                }\n            }\n        }\n        // Long string should write to multiple slots (main slot + data slots)\n        assertTrue(writeCount >= 2);\n    }\n\n    function testShortBytesStorage() public {\n        // Start recording state diffs\n        vm.startStateDiffRecording();\n\n        // Set short bytes (less than 32 bytes)\n        bytes memory shortData = hex\"deadbeef\";\n        bytesStringStorage.setShortBytes(shortData);\n\n        // Get the state diff as JSON\n        string memory stateDiffJson = vm.getStateDiffJson();\n        emit log_string(\"State diff JSON for short bytes:\");\n        emit log_string(stateDiffJson);\n\n        // Verify the JSON contains expected fields\n        assertTrue(vm.contains(stateDiffJson, '\"label\":\"shortBytes\"'));\n        assertTrue(vm.contains(stateDiffJson, '\"type\":\"bytes\"'));\n        assertTrue(vm.contains(stateDiffJson, '\"decoded\":'));\n\n        // Check the decoded bytes value\n        assertTrue(vm.contains(stateDiffJson, '\"newValue\":\"0xdeadbeef\"'));\n\n        // Stop recording\n        vm.stopAndReturnStateDiff();\n    }\n\n    function testLongBytesStorage() public {\n        // Start recording state diffs\n        vm.startStateDiffRecording();\n\n        // Set long bytes (32 bytes or more)\n        bytes memory longData = new bytes(100);\n        for (uint256 i = 0; i < 100; i++) {\n            longData[i] = bytes1(uint8(i));\n        }\n        bytesStringStorage.setLongBytes(longData);\n\n        // Get the state diff as JSON\n        string memory stateDiffJson = vm.getStateDiffJson();\n        emit log_string(\"State diff JSON for long bytes:\");\n        emit log_string(stateDiffJson);\n\n        // Verify the JSON contains expected fields\n        assertTrue(vm.contains(stateDiffJson, '\"label\":\"longBytes\"'));\n        assertTrue(vm.contains(stateDiffJson, '\"type\":\"bytes\"'));\n\n        // Stop recording\n        Vm.AccountAccess[] memory accesses = vm.stopAndReturnStateDiff();\n\n        // Verify multiple slots were written (main slot + data slots)\n        uint256 writeCount = 0;\n        for (uint256 i = 0; i < accesses.length; i++) {\n            if (accesses[i].account == address(bytesStringStorage)) {\n                writeCount += accesses[i].storageAccesses.length;\n            }\n        }\n        assertTrue(writeCount >= 2);\n    }\n\n    function testFixedBytesStorage() public {\n        // Start recording state diffs\n        vm.startStateDiffRecording();\n\n        // Set fixed bytes32\n        bytes32 fixedData = keccak256(\"test data\");\n        bytesStringStorage.setFixedBytes(fixedData);\n\n        // Get the state diff as JSON\n        string memory stateDiffJson = vm.getStateDiffJson();\n        emit log_string(\"State diff JSON for fixed bytes:\");\n        emit log_string(stateDiffJson);\n\n        // Verify the JSON contains expected fields\n        assertTrue(vm.contains(stateDiffJson, '\"label\":\"fixedBytes\"'));\n        assertTrue(vm.contains(stateDiffJson, '\"type\":\"bytes32\"'));\n        assertTrue(vm.contains(stateDiffJson, '\"decoded\":'));\n\n        // Stop recording\n        vm.stopAndReturnStateDiff();\n    }\n\n    function testMultipleBytesStringChanges() public {\n        // Start recording state diffs\n        vm.startStateDiffRecording();\n\n        // Make multiple changes\n        bytesStringStorage.setShortString(\"Short\");\n        bytesStringStorage.setLongString(\"This is a long string that will use multiple storage slots for data\");\n        bytesStringStorage.setShortBytes(hex\"1234\");\n        bytesStringStorage.setFixedBytes(bytes32(uint256(0xdeadbeef)));\n\n        // Get the state diff as string\n        string memory stateDiff = vm.getStateDiff();\n        emit log_string(\"State diff for multiple changes:\");\n        emit log_string(stateDiff);\n\n        // Get the state diff as JSON\n        string memory stateDiffJson = vm.getStateDiffJson();\n        emit log_string(\"State diff JSON for multiple changes:\");\n        emit log_string(stateDiffJson);\n\n        // Verify all fields are properly labeled\n        assertTrue(vm.contains(stateDiffJson, '\"label\":\"shortString\"'));\n        assertTrue(vm.contains(stateDiffJson, '\"label\":\"longString\"'));\n        assertTrue(vm.contains(stateDiffJson, '\"label\":\"shortBytes\"'));\n        assertTrue(vm.contains(stateDiffJson, '\"label\":\"fixedBytes\"'));\n\n        // Verify types are correct\n        assertTrue(vm.contains(stateDiffJson, '\"type\":\"string\"'));\n        assertTrue(vm.contains(stateDiffJson, '\"type\":\"bytes\"'));\n        assertTrue(vm.contains(stateDiffJson, '\"type\":\"bytes32\"'));\n\n        // Stop recording\n        vm.stopAndReturnStateDiff();\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/StateDiffMappings.t.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract MappingStorage {\n    // Simple mappings only\n    mapping(address => uint256) public balances; // Slot 0\n    mapping(uint256 => address) public owners; // Slot 1\n    mapping(bytes32 => bool) public flags; // Slot 2\n    // Nested mapping\n    mapping(address => mapping(address => uint256)) public allowances; // Slot 3\n\n    function setBalance(address account, uint256 amount) public {\n        balances[account] = amount;\n    }\n\n    function setOwner(uint256 tokenId, address owner) public {\n        owners[tokenId] = owner;\n    }\n\n    function setFlag(bytes32 key, bool value) public {\n        flags[key] = value;\n    }\n\n    function setAllowance(address owner, address spender, uint256 amount) public {\n        allowances[owner][spender] = amount;\n    }\n}\n\ncontract StateDiffMappingsTest is Test {\n    MappingStorage public mappingStorage;\n\n    function setUp() public {\n        mappingStorage = new MappingStorage();\n    }\n\n    function testSimpleMappingStateDiff() public {\n        // Start recording state diffs\n        vm.startStateDiffRecording();\n\n        // Modify a simple mapping\n        address testAccount = address(0x1234);\n        mappingStorage.setBalance(testAccount, 1000 ether);\n\n        // Test the text format output\n        string memory stateDiffText = vm.getStateDiff();\n        emit log_string(\"State diff text format:\");\n        emit log_string(stateDiffText);\n\n        // Verify text format contains the mapping label\n        assertTrue(vm.contains(stateDiffText, \"balances[0x0000000000000000000000000000000000001234]\"));\n\n        // Verify text format contains the value type\n        assertTrue(vm.contains(stateDiffText, \"uint256\"));\n\n        // Verify text format contains decoded values (shown with arrow)\n        assertTrue(vm.contains(stateDiffText, \": 0\"));\n        assertTrue(vm.contains(stateDiffText, \"1000000000000000000000\"));\n\n        // Test JSON format output\n        string memory json = vm.getStateDiffJson();\n        emit log_string(\"State diff JSON (simple mapping):\");\n        emit log_string(json);\n\n        // The JSON should contain the decoded mapping slot with proper label\n        assertTrue(vm.contains(json, '\"label\":\"balances[0x0000000000000000000000000000000000001234]\"'));\n\n        // Check the type is correctly identified\n        assertTrue(vm.contains(json, '\"type\":\"mapping(address => uint256)\"'));\n\n        // Check decoded values\n        assertTrue(vm.contains(json, '\"decoded\":{\"previousValue\":\"0\",\"newValue\":\"1000000000000000000000\"}'));\n\n        // Check that the key field is present for simple mapping\n        assertTrue(vm.contains(json, '\"key\":\"0x0000000000000000000000000000000000001234\"'));\n\n        // Stop recording and verify we have account accesses\n        Vm.AccountAccess[] memory accesses = vm.stopAndReturnStateDiff();\n        assertTrue(accesses.length > 0);\n\n        // The AccountAccess structure contains information about storage changes\n        // but the label and decoded values are only available in the string/JSON outputs\n        // We've already verified those above\n    }\n\n    function testMappingWithDifferentKeyTypes() public {\n        // Start recording state diffs\n        vm.startStateDiffRecording();\n\n        // Test uint256 key\n        mappingStorage.setOwner(12345, address(0x7777));\n\n        // Test bytes32 key\n        bytes32 flagKey = keccak256(\"test_flag\");\n        mappingStorage.setFlag(flagKey, true);\n\n        // Test text format output first\n        string memory stateDiffText = vm.getStateDiff();\n        emit log_string(\"State diff text format (different key types):\");\n        emit log_string(stateDiffText);\n\n        // Verify text format contains decoded values for uint256 key\n        assertTrue(vm.contains(stateDiffText, \"owners[12345]\"));\n        assertTrue(vm.contains(stateDiffText, \"address): 0x0000000000000000000000000000000000000000\"));\n        assertTrue(vm.contains(stateDiffText, \"0x0000000000000000000000000000000000007777\"));\n\n        // Verify text format contains decoded values for bytes32 key\n        assertTrue(vm.contains(stateDiffText, \"bool): false\"));\n        assertTrue(vm.contains(stateDiffText, \"true\"));\n\n        // Get state diff JSON\n        string memory json = vm.getStateDiffJson();\n\n        // Debug: log the JSON for inspection\n        emit log_string(\"State diff JSON (different key types):\");\n        emit log_string(json);\n\n        // Check uint256 key mapping\n        assertTrue(vm.contains(json, '\"label\":\"owners[12345]\"'));\n        assertTrue(vm.contains(json, '\"type\":\"mapping(uint256 => address)\"'));\n        assertTrue(\n            vm.contains(\n                json,\n                '\"decoded\":{\"previousValue\":\"0x0000000000000000000000000000000000000000\",\"newValue\":\"0x0000000000000000000000000000000000007777\"}'\n            )\n        );\n\n        // Check bytes32 key mapping - the key will be shown as hex\n        assertTrue(vm.contains(json, '\"label\":\"flags['));\n        assertTrue(vm.contains(json, '\"type\":\"mapping(bytes32 => bool)\"'));\n        assertTrue(vm.contains(json, '\"decoded\":{\"previousValue\":\"false\",\"newValue\":\"true\"}'));\n\n        // Check that the key field is present for uint256 key mapping\n        assertTrue(vm.contains(json, '\"key\":\"12345\"'));\n\n        // Stop recording\n        vm.stopAndReturnStateDiff();\n    }\n\n    function testNestedMappingStateDiff() public {\n        // Start recording state diffs\n        vm.startStateDiffRecording();\n\n        // Test case 1: owner1 -> spender1\n        address owner1 = address(0x1111);\n        address spender1 = address(0x2222);\n        mappingStorage.setAllowance(owner1, spender1, 500 ether);\n\n        // Test case 2: same owner (owner1) -> different spender (spender2)\n        address spender2 = address(0x3333);\n        mappingStorage.setAllowance(owner1, spender2, 750 ether);\n\n        // Test case 3: different owner (owner2) -> different spender (spender3)\n        address owner2 = address(0x4444);\n        address spender3 = address(0x5555);\n        mappingStorage.setAllowance(owner2, spender3, 1000 ether);\n\n        // Test text format output\n        string memory stateDiffText = vm.getStateDiff();\n        emit log_string(\"State diff text format (nested mappings):\");\n        emit log_string(stateDiffText);\n\n        // Verify text format contains nested mapping labels\n        assertTrue(\n            vm.contains(\n                stateDiffText,\n                \"allowances[0x0000000000000000000000000000000000001111][0x0000000000000000000000000000000000002222]\"\n            )\n        );\n        assertTrue(\n            vm.contains(\n                stateDiffText,\n                \"allowances[0x0000000000000000000000000000000000001111][0x0000000000000000000000000000000000003333]\"\n            )\n        );\n        // The text format shows the value type (uint256) not the full mapping type\n        assertTrue(vm.contains(stateDiffText, \"uint256): 0\"));\n\n        // Verify text format contains decoded values for nested mappings\n        assertTrue(vm.contains(stateDiffText, \"500000000000000000000\"));\n        assertTrue(vm.contains(stateDiffText, \"750000000000000000000\"));\n        assertTrue(vm.contains(stateDiffText, \"1000000000000000000000\"));\n\n        // Test JSON format output\n        string memory json = vm.getStateDiffJson();\n        emit log_string(\"State diff JSON (nested mapping - multiple entries):\");\n        emit log_string(json);\n\n        // Check that all three nested mapping entries are correctly decoded\n\n        // Entry 1: owner1 -> spender1\n        assertTrue(\n            vm.contains(\n                json,\n                '\"label\":\"allowances[0x0000000000000000000000000000000000001111][0x0000000000000000000000000000000000002222]\"'\n            )\n        );\n        assertTrue(vm.contains(json, '\"newValue\":\"500000000000000000000\"'));\n\n        // Entry 2: owner1 -> spender2 (same owner, different spender)\n        assertTrue(\n            vm.contains(\n                json,\n                '\"label\":\"allowances[0x0000000000000000000000000000000000001111][0x0000000000000000000000000000000000003333]\"'\n            )\n        );\n        assertTrue(vm.contains(json, '\"newValue\":\"750000000000000000000\"'));\n\n        // Entry 3: owner2 -> spender3 (different owner)\n        assertTrue(\n            vm.contains(\n                json,\n                '\"label\":\"allowances[0x0000000000000000000000000000000000004444][0x0000000000000000000000000000000000005555]\"'\n            )\n        );\n        assertTrue(vm.contains(json, '\"newValue\":\"1000000000000000000000\"'));\n\n        // Check the type is correctly identified for all entries\n        assertTrue(vm.contains(json, '\"type\":\"mapping(address => mapping(address => uint256))\"'));\n\n        // Check that the keys field is present for nested mappings\n        assertTrue(\n            vm.contains(\n                json,\n                '\"keys\":[\"0x0000000000000000000000000000000000001111\",\"0x0000000000000000000000000000000000002222\"]'\n            )\n        );\n\n        assertTrue(\n            vm.contains(\n                json,\n                '\"keys\":[\"0x0000000000000000000000000000000000001111\",\"0x0000000000000000000000000000000000003333\"]'\n            )\n        );\n\n        assertTrue(\n            vm.contains(\n                json,\n                '\"keys\":[\"0x0000000000000000000000000000000000004444\",\"0x0000000000000000000000000000000000005555\"]'\n            )\n        );\n\n        // Stop recording\n        vm.stopAndReturnStateDiff();\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/StateDiffStorageLayout.t.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract SimpleStorage {\n    uint256 public value; // Slot 0\n    address public owner; // Slot 1\n    uint256[3] public values; // Slots 2, 3, 4\n\n    constructor() {\n        owner = msg.sender;\n    }\n\n    function setValue(uint256 _value) public {\n        value = _value;\n    }\n\n    function setOwner(address _owner) public {\n        owner = _owner;\n    }\n\n    function setValues(uint256 a, uint256 b, uint256 c) public {\n        values[0] = a;\n        values[1] = b;\n        values[2] = c;\n    }\n}\n\ncontract VariousArrays {\n    // Different array types to test\n    uint256[3] public numbers; // Slots 0, 1, 2\n    address[2] public addresses; // Slots 3, 4\n    bool[5] public flags; // Slot 5 (packed)\n    bytes32[2] public hashes; // Slots 6, 7\n\n    function setNumbers(uint256 a, uint256 b, uint256 c) public {\n        numbers[0] = a;\n        numbers[1] = b;\n        numbers[2] = c;\n    }\n\n    function setAddresses(address a, address b) public {\n        addresses[0] = a;\n        addresses[1] = b;\n    }\n\n    function setFlags(bool a, bool b, bool c, bool d, bool e) public {\n        flags[0] = a;\n        flags[1] = b;\n        flags[2] = c;\n        flags[3] = d;\n        flags[4] = e;\n    }\n\n    function setHashes(bytes32 a, bytes32 b) public {\n        hashes[0] = a;\n        hashes[1] = b;\n    }\n}\n\ncontract TwoDArrayStorage {\n    // 2D array: 2 arrays of 3 uint256 elements each\n    // Total slots: 6 (slots 0-5)\n    // [0][0] at slot 0, [0][1] at slot 1, [0][2] at slot 2\n    // [1][0] at slot 3, [1][1] at slot 4, [1][2] at slot 5\n    uint256[3][2] public matrix;\n\n    // Another 2D array starting at slot 6\n    // 3 arrays of 2 addresses each\n    // Total slots: 6 (slots 6-11)\n    address[2][3] public addresses2D;\n\n    // Mixed size 2D array starting at slot 12\n    // 4 arrays of 2 bytes32 each\n    // Total slots: 8 (slots 12-19)\n    bytes32[2][4] public data2D;\n\n    function setMatrix(uint256[3] memory row0, uint256[3] memory row1) public {\n        matrix[0] = row0;\n        matrix[1] = row1;\n    }\n\n    function setMatrixElement(uint256 i, uint256 j, uint256 value) public {\n        matrix[i][j] = value;\n    }\n\n    function setAddresses2D(address[2] memory row0, address[2] memory row1, address[2] memory row2) public {\n        addresses2D[0] = row0;\n        addresses2D[1] = row1;\n        addresses2D[2] = row2;\n    }\n\n    function setData2D(uint256 i, uint256 j, bytes32 value) public {\n        data2D[i][j] = value;\n    }\n}\n\ncontract StateDiffStorageLayoutTest is Test {\n    SimpleStorage simpleStorage;\n    VariousArrays variousArrays;\n    TwoDArrayStorage twoDArrayStorage;\n\n    function setUp() public {\n        simpleStorage = new SimpleStorage();\n        variousArrays = new VariousArrays();\n        twoDArrayStorage = new TwoDArrayStorage();\n    }\n\n    function testSimpleStorageLayout() public {\n        // Start recording state diffs\n        vm.startStateDiffRecording();\n\n        // Modify storage slots with known positions\n        simpleStorage.setValue(42); // Modifies slot 0 (value)\n        simpleStorage.setOwner(address(this)); // Modifies slot 1 (owner)\n        simpleStorage.setValues(100, 200, 300); // Modifies slots 2, 3, 4 (values array)\n\n        // Get the state diff as string\n        string memory stateDiff = vm.getStateDiff();\n\n        // Get the state diff as JSON and verify it contains the expected structure\n        string memory stateDiffJson = vm.getStateDiffJson();\n\n        // The JSON should contain storage layout info for all slots\n        // We check the JSON contains expected substrings for the labels and types\n        assertTrue(vm.contains(stateDiffJson, '\"label\":\"value\"'));\n        assertTrue(vm.contains(stateDiffJson, '\"label\":\"owner\"'));\n        assertTrue(vm.contains(stateDiffJson, '\"label\":\"values[0]\"'));\n        assertTrue(vm.contains(stateDiffJson, '\"label\":\"values[1]\"'));\n        assertTrue(vm.contains(stateDiffJson, '\"label\":\"values[2]\"'));\n\n        assertTrue(vm.contains(stateDiffJson, '\"type\":\"uint256\"'));\n        assertTrue(vm.contains(stateDiffJson, '\"type\":\"address\"'));\n        assertTrue(vm.contains(stateDiffJson, '\"type\":\"uint256[3]\"'));\n\n        // Check for decoded values\n        assertTrue(vm.contains(stateDiffJson, '\"decoded\":'));\n\n        // Check specific decoded values within the decoded object\n        // The value 42 should be decoded in the first slot\n        assertTrue(vm.contains(stateDiffJson, '\"decoded\":{\"previousValue\":\"0\",\"newValue\":\"42\"}'));\n\n        // Check that array values are decoded properly (they will have separate decoded objects)\n        assertTrue(vm.contains(stateDiffJson, '\"newValue\":\"100\"'));\n        assertTrue(vm.contains(stateDiffJson, '\"newValue\":\"200\"'));\n        assertTrue(vm.contains(stateDiffJson, '\"newValue\":\"300\"'));\n\n        // Stop recording and verify we get the expected account accesses\n        Vm.AccountAccess[] memory accesses = vm.stopAndReturnStateDiff();\n        assertTrue(accesses.length >= 3);\n\n        // Verify storage accesses for SimpleStorage\n        bool foundValueSlot = false;\n        bool foundOwnerSlot = false;\n        bool foundValuesSlot0 = false;\n        bool foundValuesSlot1 = false;\n        bool foundValuesSlot2 = false;\n\n        for (uint256 i = 0; i < accesses.length; i++) {\n            if (accesses[i].account == address(simpleStorage)) {\n                for (uint256 j = 0; j < accesses[i].storageAccesses.length; j++) {\n                    bytes32 slot = accesses[i].storageAccesses[j].slot;\n                    if (slot == bytes32(uint256(0))) foundValueSlot = true;\n                    if (slot == bytes32(uint256(1))) foundOwnerSlot = true;\n                    if (slot == bytes32(uint256(2))) foundValuesSlot0 = true;\n                    if (slot == bytes32(uint256(3))) foundValuesSlot1 = true;\n                    if (slot == bytes32(uint256(4))) foundValuesSlot2 = true;\n                }\n            }\n        }\n\n        assertTrue(foundValueSlot);\n        assertTrue(foundOwnerSlot);\n        assertTrue(foundValuesSlot0);\n        assertTrue(foundValuesSlot1);\n        assertTrue(foundValuesSlot2);\n    }\n\n    function testVariousArrayTypes() public {\n        // Start recording state diffs\n        vm.startStateDiffRecording();\n\n        // Modify different array types\n        variousArrays.setNumbers(100, 200, 300);\n        variousArrays.setAddresses(address(0x1), address(0x2));\n        variousArrays.setFlags(true, false, true, false, true);\n        variousArrays.setHashes(keccak256(\"test1\"), keccak256(\"test2\"));\n\n        // Get the state diff as JSON\n        string memory stateDiffJson = vm.getStateDiffJson();\n\n        // Verify all array types are properly labeled with indices\n        assertTrue(vm.contains(stateDiffJson, '\"label\":\"numbers[0]\"'));\n        assertTrue(vm.contains(stateDiffJson, '\"label\":\"numbers[1]\"'));\n        assertTrue(vm.contains(stateDiffJson, '\"label\":\"numbers[2]\"'));\n\n        assertTrue(vm.contains(stateDiffJson, '\"label\":\"addresses[0]\"'));\n        assertTrue(vm.contains(stateDiffJson, '\"label\":\"addresses[1]\"'));\n\n        assertTrue(vm.contains(stateDiffJson, '\"label\":\"flags[0]\"'));\n\n        assertTrue(vm.contains(stateDiffJson, '\"label\":\"hashes[0]\"'));\n        assertTrue(vm.contains(stateDiffJson, '\"label\":\"hashes[1]\"'));\n\n        // Verify types are correctly identified\n        assertTrue(vm.contains(stateDiffJson, '\"type\":\"uint256[3]\"'));\n        assertTrue(vm.contains(stateDiffJson, '\"type\":\"address[2]\"'));\n        assertTrue(vm.contains(stateDiffJson, '\"type\":\"bool[5]\"'));\n        assertTrue(vm.contains(stateDiffJson, '\"type\":\"bytes32[2]\"'));\n\n        // Check decoded values\n        assertTrue(vm.contains(stateDiffJson, '\"decoded\":'));\n        // Check addresses are decoded as raw hex strings\n        assertTrue(vm.contains(stateDiffJson, '\"newValue\":\"0x0000000000000000000000000000000000000001\"'));\n        assertTrue(vm.contains(stateDiffJson, '\"newValue\":\"0x0000000000000000000000000000000000000002\"'));\n\n        // Stop recording and verify account accesses\n        Vm.AccountAccess[] memory accesses = vm.stopAndReturnStateDiff();\n        assertTrue(accesses.length > 0);\n    }\n\n    function testStateDiffJsonFormat() public {\n        // Start recording state diffs\n        vm.startStateDiffRecording();\n\n        // Make a simple change to verify JSON format\n        simpleStorage.setValue(123);\n\n        // Get the JSON and verify it's properly formatted\n        string memory stateDiffJson = vm.getStateDiffJson();\n\n        // Check JSON structure contains expected fields\n        assertTrue(vm.contains(stateDiffJson, '\"previousValue\":'));\n        assertTrue(vm.contains(stateDiffJson, '\"newValue\":'));\n        assertTrue(vm.contains(stateDiffJson, '\"label\":'));\n        assertTrue(vm.contains(stateDiffJson, '\"type\":'));\n        assertTrue(vm.contains(stateDiffJson, '\"offset\":'));\n        assertTrue(vm.contains(stateDiffJson, '\"slot\":'));\n\n        vm.stopAndReturnStateDiff();\n    }\n\n    function test2DArrayStorageLayout() public {\n        // Start recording state diffs\n        vm.startStateDiffRecording();\n\n        // Set matrix values\n        // matrix[0][0] = 100, matrix[0][1] = 101, matrix[0][2] = 102\n        // matrix[1][0] = 200, matrix[1][1] = 201, matrix[1][2] = 202\n        uint256[3] memory row0 = [uint256(100), 101, 102];\n        uint256[3] memory row1 = [uint256(200), 201, 202];\n        twoDArrayStorage.setMatrix(row0, row1);\n\n        // Get the state diff and check labels\n        string memory stateDiffJson = vm.getStateDiffJson();\n\n        // Verify the labels for 2D array elements\n        assertTrue(vm.contains(stateDiffJson, '\"label\":\"matrix[0][0]\"'));\n        assertTrue(vm.contains(stateDiffJson, '\"label\":\"matrix[0][1]\"'));\n        assertTrue(vm.contains(stateDiffJson, '\"label\":\"matrix[0][2]\"'));\n        assertTrue(vm.contains(stateDiffJson, '\"label\":\"matrix[1][0]\"'));\n        assertTrue(vm.contains(stateDiffJson, '\"label\":\"matrix[1][1]\"'));\n        assertTrue(vm.contains(stateDiffJson, '\"label\":\"matrix[1][2]\"'));\n\n        // Check that we have the right type\n        assertTrue(vm.contains(stateDiffJson, '\"type\":\"uint256[3][2]\"'));\n\n        // Check decoded values for 2D arrays\n        assertTrue(vm.contains(stateDiffJson, '\"decoded\":'));\n        assertTrue(vm.contains(stateDiffJson, '\"newValue\":\"100\"'));\n        assertTrue(vm.contains(stateDiffJson, '\"newValue\":\"101\"'));\n        assertTrue(vm.contains(stateDiffJson, '\"newValue\":\"102\"'));\n        assertTrue(vm.contains(stateDiffJson, '\"newValue\":\"200\"'));\n        assertTrue(vm.contains(stateDiffJson, '\"newValue\":\"201\"'));\n        assertTrue(vm.contains(stateDiffJson, '\"newValue\":\"202\"'));\n\n        vm.stopAndReturnStateDiff();\n    }\n\n    function testMixed2DArrays() public {\n        vm.startStateDiffRecording();\n\n        // Test address 2D array\n        address[2] memory addrRow0 = [address(0x1), address(0x2)];\n        address[2] memory addrRow1 = [address(0x3), address(0x4)];\n        address[2] memory addrRow2 = [address(0x5), address(0x6)];\n        twoDArrayStorage.setAddresses2D(addrRow0, addrRow1, addrRow2);\n\n        // Test bytes32 2D array\n        twoDArrayStorage.setData2D(0, 0, keccak256(\"data00\"));\n        twoDArrayStorage.setData2D(0, 1, keccak256(\"data01\"));\n        twoDArrayStorage.setData2D(1, 0, keccak256(\"data10\"));\n        twoDArrayStorage.setData2D(1, 1, keccak256(\"data11\"));\n\n        string memory stateDiffJson = vm.getStateDiffJson();\n\n        // Check for proper types\n        assertTrue(vm.contains(stateDiffJson, '\"type\":\"address[2][3]\"'));\n        assertTrue(vm.contains(stateDiffJson, '\"type\":\"bytes32[2][4]\"'));\n\n        // Verify address 2D array labels\n        assertTrue(vm.contains(stateDiffJson, '\"label\":\"addresses2D[0][0]\"'));\n        assertTrue(vm.contains(stateDiffJson, '\"label\":\"addresses2D[0][1]\"'));\n        assertTrue(vm.contains(stateDiffJson, '\"label\":\"addresses2D[1][0]\"'));\n        assertTrue(vm.contains(stateDiffJson, '\"label\":\"addresses2D[2][1]\"'));\n\n        // Verify data 2D array labels\n        assertTrue(vm.contains(stateDiffJson, '\"label\":\"data2D[0][0]\"'));\n        assertTrue(vm.contains(stateDiffJson, '\"label\":\"data2D[0][1]\"'));\n        assertTrue(vm.contains(stateDiffJson, '\"label\":\"data2D[1][0]\"'));\n        assertTrue(vm.contains(stateDiffJson, '\"label\":\"data2D[1][1]\"'));\n\n        vm.stopAndReturnStateDiff();\n    }\n\n    function testStateDiffDecodedValues() public {\n        // Start recording state diffs\n        vm.startStateDiffRecording();\n\n        // Make changes to create state diffs with decoded values\n        simpleStorage.setValue(42); // uint256 value\n        simpleStorage.setOwner(address(0xBEEF)); // address value\n        simpleStorage.setValues(100, 200, 300); // array values\n\n        // Get the state diff as string (not JSON)\n        string memory stateDiff = vm.getStateDiff();\n\n        // Test that decoded values are shown in the string format\n        // The output uses Unicode arrow →\n        // For uint256 values, should show decoded value \"42\"\n        assertTrue(vm.contains(stateDiff, unicode\"0 → 42\"));\n\n        // For addresses, should show decoded address format\n        assertTrue(vm.contains(stateDiff, \"0x000000000000000000000000000000000000bEEF\"));\n\n        // For array elements, should show decoded values\n        assertTrue(vm.contains(stateDiff, unicode\"0 → 100\"));\n        assertTrue(vm.contains(stateDiff, unicode\"0 → 200\"));\n        assertTrue(vm.contains(stateDiff, unicode\"0 → 300\"));\n\n        vm.stopAndReturnStateDiff();\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/StateDiffStructTest.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity 0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract DiffTest {\n    // slot 0\n    struct TestStruct {\n        uint128 a;\n        uint128 b;\n    }\n\n    // Multi-slot struct (spans 3 slots)\n    struct MultiSlotStruct {\n        uint256 value1; // slot 1\n        address addr; // slot 2 (takes 20 bytes, but uses full slot)\n        uint256 value2; // slot 3\n    }\n\n    // Nested struct with MultiSlotStruct as inner\n    struct NestedStruct {\n        MultiSlotStruct inner; // slots 4-6 (spans 3 slots)\n        uint256 value; // slot 7\n        address owner; // slot 8\n    }\n\n    TestStruct internal testStruct;\n    MultiSlotStruct internal multiSlotStruct;\n    NestedStruct internal nestedStruct;\n\n    function setStruct(uint128 a, uint128 b) public {\n        testStruct.a = a;\n        testStruct.b = b;\n    }\n\n    function setMultiSlotStruct(uint256 v1, address a, uint256 v2) public {\n        multiSlotStruct.value1 = v1;\n        multiSlotStruct.addr = a;\n        multiSlotStruct.value2 = v2;\n    }\n\n    function setNestedStruct(uint256 v1, address a, uint256 v2, uint256 v, address o) public {\n        nestedStruct.inner.value1 = v1;\n        nestedStruct.inner.addr = a;\n        nestedStruct.inner.value2 = v2;\n        nestedStruct.value = v;\n        nestedStruct.owner = o;\n    }\n}\n\ncontract StateDiffStructTest is Test {\n    DiffTest internal test;\n\n    function setUp() public {\n        test = new DiffTest();\n    }\n\n    function testStruct() public {\n        // Start recording state diffs\n        vm.startStateDiffRecording();\n\n        // Set struct values: a=1, b=2\n        test.setStruct(1, 2);\n\n        // Get the state diff as JSON\n        string memory stateDiffJson = vm.getStateDiffJson();\n\n        // Debug: log the JSON for inspection\n        emit log_string(\"State diff JSON (testdata):\");\n        emit log_string(stateDiffJson);\n\n        // Check that the struct is properly labeled\n        assertTrue(vm.contains(stateDiffJson, '\"label\":\"testStruct\"'));\n\n        // Check that the type is correctly identified as a struct\n        assertTrue(vm.contains(stateDiffJson, '\"type\":\"struct DiffTest.TestStruct\"'));\n\n        // Check for members field - structs have members with individual decoded values\n        assertTrue(vm.contains(stateDiffJson, '\"members\":'));\n\n        // Check that member 'a' is properly decoded\n        assertTrue(vm.contains(stateDiffJson, '\"label\":\"a\"'));\n        assertTrue(vm.contains(stateDiffJson, '\"type\":\"uint128\"'));\n\n        // Check that member 'b' is properly decoded\n        assertTrue(vm.contains(stateDiffJson, '\"label\":\"b\"'));\n\n        // The members should have decoded values\n        // Check specific decoded values for each member in the members array\n        // Member 'a' at offset 0 should have previous value 0 and new value 1\n        assertTrue(\n            vm.contains(\n                stateDiffJson,\n                '{\"label\":\"a\",\"type\":\"uint128\",\"offset\":0,\"slot\":\"0\",\"decoded\":{\"previousValue\":\"0\",\"newValue\":\"1\"}}'\n            )\n        );\n\n        // Member 'b' at offset 16 should have previous value 0 and new value 2\n        assertTrue(\n            vm.contains(\n                stateDiffJson,\n                '{\"label\":\"b\",\"type\":\"uint128\",\"offset\":16,\"slot\":\"0\",\"decoded\":{\"previousValue\":\"0\",\"newValue\":\"2\"}}'\n            )\n        );\n\n        // Verify the raw storage values are correct\n        // The storage layout packs uint128 a at offset 0 and uint128 b at offset 16\n        // So the value 0x0000000000000000000200000000000000000000000000000001 represents:\n        // - First 16 bytes (a): 0x0000000000000000000000000000000001 = 1\n        // - Last 16 bytes (b):  0x0000000000000000000000000000000002 = 2\n        assertTrue(vm.contains(stateDiffJson, '\"0x0000000000000000000000000000000200000000000000000000000000000001\"'));\n\n        // Stop recording and verify we get the expected account accesses\n        Vm.AccountAccess[] memory accesses = vm.stopAndReturnStateDiff();\n        assertTrue(accesses.length > 0);\n\n        // Find the storage access for our struct\n        bool foundStructAccess = false;\n        for (uint256 i = 0; i < accesses.length; i++) {\n            if (accesses[i].account == address(test)) {\n                for (uint256 j = 0; j < accesses[i].storageAccesses.length; j++) {\n                    Vm.StorageAccess memory access = accesses[i].storageAccesses[j];\n                    if (access.slot == bytes32(uint256(0)) && access.isWrite) {\n                        foundStructAccess = true;\n                        // Verify the storage values\n                        assertEq(access.previousValue, bytes32(uint256(0)));\n                        assertEq(\n                            access.newValue, bytes32(uint256(0x0000000000000000000200000000000000000000000000000001))\n                        );\n                    }\n                }\n            }\n        }\n\n        assertTrue(foundStructAccess);\n    }\n\n    function testMultiSlotStruct() public {\n        // Start recording state diffs\n        vm.startStateDiffRecording();\n\n        // Set multi-slot struct values\n        test.setMultiSlotStruct(\n            123456789, // value1\n            address(0xdEaDbEeF), // addr\n            987654321 // value2\n        );\n\n        // Get the state diff as JSON\n        string memory stateDiffJson = vm.getStateDiffJson();\n\n        // Debug: log the JSON for inspection\n        emit log_string(\"State diff JSON:\");\n        emit log_string(stateDiffJson);\n\n        // Check that the struct's first member is properly labeled\n        assertTrue(vm.contains(stateDiffJson, '\"label\":\"multiSlotStruct.value1\"'));\n\n        // For multi-slot structs, the base slot now shows the first member's type\n        // The struct type itself is not shown since we decode the first member directly\n\n        // Multi-slot structs don't have members field in the base slot\n        // Instead, each member appears as a separate slot entry with dotted labels\n\n        // Check that each member slot is properly labeled\n        // Note: slot 1 now shows multiSlotStruct.value1 since it's the first member\n        assertTrue(vm.contains(stateDiffJson, '\"label\":\"multiSlotStruct.value1\"'));\n        assertTrue(vm.contains(stateDiffJson, '\"label\":\"multiSlotStruct.addr\"'));\n        assertTrue(vm.contains(stateDiffJson, '\"label\":\"multiSlotStruct.value2\"'));\n\n        // Check member types\n        assertTrue(vm.contains(stateDiffJson, '\"type\":\"uint256\"'));\n        assertTrue(vm.contains(stateDiffJson, '\"type\":\"address\"'));\n\n        // Check that value1 is properly decoded from slot 1\n        assertTrue(vm.contains(stateDiffJson, '\"decoded\":{\"previousValue\":\"0\",\"newValue\":\"123456789\"}'));\n\n        // Also verify the raw hex value\n        assertTrue(vm.contains(stateDiffJson, \"0x00000000000000000000000000000000000000000000000000000000075bcd15\"));\n\n        // Slot 2 should have the address decoded\n        assertTrue(\n            vm.contains(\n                stateDiffJson,\n                '\"decoded\":{\"previousValue\":\"0x0000000000000000000000000000000000000000\",\"newValue\":\"0x00000000000000000000000000000000DeaDBeef\"}'\n            )\n        );\n\n        // Slot 3 should have value2 decoded\n        assertTrue(vm.contains(stateDiffJson, '\"decoded\":{\"previousValue\":\"0\",\"newValue\":\"987654321\"}'));\n\n        // Stop recording\n        vm.stopAndReturnStateDiff();\n    }\n\n    function testNestedStruct() public {\n        // Start recording state diffs\n        vm.startStateDiffRecording();\n\n        // Set nested struct values - now with MultiSlotStruct as inner\n        test.setNestedStruct(\n            111111111, // inner.value1\n            address(0xCAFE), // inner.addr\n            222222222, // inner.value2\n            333333333, // value\n            address(0xBEEF) // owner\n        );\n\n        // Get the state diff as JSON\n        string memory stateDiffJson = vm.getStateDiffJson();\n\n        // Debug: log the JSON for inspection\n        emit log_string(\"State diff JSON (testdata):\");\n        emit log_string(stateDiffJson);\n\n        assertTrue(\n            vm.contains(\n                stateDiffJson,\n                '\"label\":\"nestedStruct.inner.value1\",\"type\":\"uint256\",\"offset\":0,\"slot\":\"4\",\"decoded\":{\"previousValue\":\"0\",\"newValue\":\"111111111\"}'\n            )\n        );\n\n        assertTrue(\n            vm.contains(\n                stateDiffJson,\n                '\"label\":\"nestedStruct.inner.addr\",\"type\":\"address\",\"offset\":0,\"slot\":\"5\",\"decoded\":{\"previousValue\":\"0x0000000000000000000000000000000000000000\",\"newValue\":\"0x000000000000000000000000000000000000cafE\"}'\n            )\n        );\n\n        assertTrue(\n            vm.contains(\n                stateDiffJson,\n                '\"label\":\"nestedStruct.inner.value2\",\"type\":\"uint256\",\"offset\":0,\"slot\":\"6\",\"decoded\":{\"previousValue\":\"0\",\"newValue\":\"222222222\"}'\n            )\n        );\n\n        assertTrue(vm.contains(stateDiffJson, \"0x00000000000000000000000000000000000000000000000000000000069f6bc7\"));\n\n        assertTrue(\n            vm.contains(\n                stateDiffJson,\n                '\"label\":\"nestedStruct.value\",\"type\":\"uint256\",\"offset\":0,\"slot\":\"7\",\"decoded\":{\"previousValue\":\"0\",\"newValue\":\"333333333\"}'\n            )\n        );\n\n        assertTrue(\n            vm.contains(\n                stateDiffJson,\n                '\"label\":\"nestedStruct.owner\",\"type\":\"address\",\"offset\":0,\"slot\":\"8\",\"decoded\":{\"previousValue\":\"0x0000000000000000000000000000000000000000\",\"newValue\":\"0x000000000000000000000000000000000000bEEF\"}'\n            )\n        );\n\n        // Stop recording\n        vm.stopAndReturnStateDiff();\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/StateSnapshots.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\nstruct Storage {\n    uint256 slot0;\n    uint256 slot1;\n}\n\ncontract StateSnapshotTest is Test {\n    Storage store;\n\n    function setUp() public {\n        store.slot0 = 10;\n        store.slot1 = 20;\n    }\n\n    function testStateSnapshot() public {\n        uint256 snapshotId = vm.snapshotState();\n        store.slot0 = 300;\n        store.slot1 = 400;\n\n        assertEq(store.slot0, 300);\n        assertEq(store.slot1, 400);\n\n        vm.revertToState(snapshotId);\n        assertEq(store.slot0, 10, \"snapshot revert for slot 0 unsuccessful\");\n        assertEq(store.slot1, 20, \"snapshot revert for slot 1 unsuccessful\");\n    }\n\n    function testStateSnapshotRevertDelete() public {\n        uint256 snapshotId = vm.snapshotState();\n        store.slot0 = 300;\n        store.slot1 = 400;\n\n        assertEq(store.slot0, 300);\n        assertEq(store.slot1, 400);\n\n        vm.revertToStateAndDelete(snapshotId);\n        assertEq(store.slot0, 10, \"snapshot revert for slot 0 unsuccessful\");\n        assertEq(store.slot1, 20, \"snapshot revert for slot 1 unsuccessful\");\n        // nothing to revert to anymore\n        assert(!vm.revertToState(snapshotId));\n    }\n\n    function testStateSnapshotDelete() public {\n        uint256 snapshotId = vm.snapshotState();\n        store.slot0 = 300;\n        store.slot1 = 400;\n\n        vm.deleteStateSnapshot(snapshotId);\n        // nothing to revert to anymore\n        assert(!vm.revertToState(snapshotId));\n    }\n\n    function testStateSnapshotDeleteAll() public {\n        uint256 snapshotId = vm.snapshotState();\n        store.slot0 = 300;\n        store.slot1 = 400;\n\n        vm.deleteStateSnapshots();\n        // nothing to revert to anymore\n        assert(!vm.revertToState(snapshotId));\n    }\n\n    // <https://github.com/foundry-rs/foundry/issues/6411>\n    function testStateSnapshotsMany() public {\n        uint256 snapshotId;\n        for (uint256 c = 0; c < 10; c++) {\n            for (uint256 cc = 0; cc < 10; cc++) {\n                snapshotId = vm.snapshotState();\n                vm.revertToStateAndDelete(snapshotId);\n                assert(!vm.revertToState(snapshotId));\n            }\n        }\n    }\n\n    // tests that snapshots can also revert changes to `block`\n    function testBlockValues() public {\n        uint256 num = block.number;\n        uint256 time = block.timestamp;\n        uint256 prevrandao = block.prevrandao;\n\n        uint256 snapshotId = vm.snapshotState();\n\n        vm.warp(1337);\n        assertEq(block.timestamp, 1337);\n\n        vm.roll(99);\n        assertEq(block.number, 99);\n\n        vm.prevrandao(uint256(123));\n        assertEq(block.prevrandao, 123);\n\n        assert(vm.revertToState(snapshotId));\n\n        assertEq(block.number, num, \"snapshot revert for block.number unsuccessful\");\n        assertEq(block.timestamp, time, \"snapshot revert for block.timestamp unsuccessful\");\n        assertEq(block.prevrandao, prevrandao, \"snapshot revert for block.prevrandao unsuccessful\");\n    }\n}\n\n// TODO: remove this test suite once `snapshot*` has been deprecated in favor of `snapshotState*`.\ncontract DeprecatedStateSnapshotTest is Test {\n    Storage store;\n\n    function setUp() public {\n        store.slot0 = 10;\n        store.slot1 = 20;\n    }\n\n    function testSnapshotState() public {\n        uint256 snapshotId = vm.snapshot();\n        store.slot0 = 300;\n        store.slot1 = 400;\n\n        assertEq(store.slot0, 300);\n        assertEq(store.slot1, 400);\n\n        vm.revertTo(snapshotId);\n        assertEq(store.slot0, 10, \"snapshot revert for slot 0 unsuccessful\");\n        assertEq(store.slot1, 20, \"snapshot revert for slot 1 unsuccessful\");\n    }\n\n    function testSnapshotStateRevertDelete() public {\n        uint256 snapshotId = vm.snapshot();\n        store.slot0 = 300;\n        store.slot1 = 400;\n\n        assertEq(store.slot0, 300);\n        assertEq(store.slot1, 400);\n\n        vm.revertToAndDelete(snapshotId);\n        assertEq(store.slot0, 10, \"snapshot revert for slot 0 unsuccessful\");\n        assertEq(store.slot1, 20, \"snapshot revert for slot 1 unsuccessful\");\n        // nothing to revert to anymore\n        assert(!vm.revertTo(snapshotId));\n    }\n\n    function testSnapshotStateDelete() public {\n        uint256 snapshotId = vm.snapshot();\n        store.slot0 = 300;\n        store.slot1 = 400;\n\n        vm.deleteSnapshot(snapshotId);\n        // nothing to revert to anymore\n        assert(!vm.revertTo(snapshotId));\n    }\n\n    function testSnapshotStateDeleteAll() public {\n        uint256 snapshotId = vm.snapshot();\n        store.slot0 = 300;\n        store.slot1 = 400;\n\n        vm.deleteSnapshots();\n        // nothing to revert to anymore\n        assert(!vm.revertTo(snapshotId));\n    }\n\n    // <https://github.com/foundry-rs/foundry/issues/6411>\n    function testSnapshotStatesMany() public {\n        uint256 snapshotId;\n        for (uint256 c = 0; c < 10; c++) {\n            for (uint256 cc = 0; cc < 10; cc++) {\n                snapshotId = vm.snapshot();\n                vm.revertToAndDelete(snapshotId);\n                assert(!vm.revertTo(snapshotId));\n            }\n        }\n    }\n\n    // tests that snapshots can also revert changes to `block`\n    function testBlockValues() public {\n        uint256 num = block.number;\n        uint256 time = block.timestamp;\n        uint256 prevrandao = block.prevrandao;\n\n        uint256 snapshotId = vm.snapshot();\n\n        vm.warp(1337);\n        assertEq(block.timestamp, 1337);\n\n        vm.roll(99);\n        assertEq(block.number, 99);\n\n        vm.prevrandao(uint256(123));\n        assertEq(block.prevrandao, 123);\n\n        assert(vm.revertTo(snapshotId));\n\n        assertEq(block.number, num, \"snapshot revert for block.number unsuccessful\");\n        assertEq(block.timestamp, time, \"snapshot revert for block.timestamp unsuccessful\");\n        assertEq(block.prevrandao, prevrandao, \"snapshot revert for block.prevrandao unsuccessful\");\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/StorageSlotState.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract StorageSlotStateTest is Test {\n    function test_gas_two_reads() public {\n        Read read = new Read();\n        read.number();\n        uint256 initial = gasleft();\n        read.number();\n        assert(initial - gasleft() >= 614);\n    }\n\n    function test_gas_mark_warm() public {\n        Read read = new Read();\n        vm.warmSlot(address(read), bytes32(0));\n        uint256 initial = gasleft();\n        read.number();\n        assert(initial - gasleft() >= 614);\n    }\n\n    function test_gas_mark_cold() public {\n        Read read = new Read();\n        read.number();\n        vm.coolSlot(address(read), bytes32(0));\n        uint256 initial = gasleft();\n        read.number();\n        assert(initial - gasleft() >= 2614);\n    }\n}\n\ncontract Read {\n    uint256 public number = 10;\n}\n"
  },
  {
    "path": "testdata/default/cheats/Store.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract Storage {\n    uint256 public slot0 = 10;\n    uint256 public slot1 = 20;\n}\n\ncontract StoreTest is Test {\n    Storage store;\n\n    function setUp() public {\n        store = new Storage();\n    }\n\n    function testStore() public {\n        assertEq(store.slot0(), 10, \"initial value for slot 0 is incorrect\");\n        assertEq(store.slot1(), 20, \"initial value for slot 1 is incorrect\");\n\n        vm.store(address(store), bytes32(0), bytes32(uint256(1)));\n        assertEq(store.slot0(), 1, \"store failed\");\n        assertEq(store.slot1(), 20, \"store failed\");\n    }\n\n    function testStoreNotAvailableOnPrecompiles() public {\n        assertEq(store.slot0(), 10, \"initial value for slot 0 is incorrect\");\n        assertEq(store.slot1(), 20, \"initial value for slot 1 is incorrect\");\n\n        vm._expectCheatcodeRevert(\"cannot use precompile 0x0000000000000000000000000000000000000001 as an argument\");\n        vm.store(address(1), bytes32(0), bytes32(uint256(1)));\n    }\n\n    function testStoreFuzzed(uint256 slot0, uint256 slot1) public {\n        assertEq(store.slot0(), 10, \"initial value for slot 0 is incorrect\");\n        assertEq(store.slot1(), 20, \"initial value for slot 1 is incorrect\");\n\n        vm.store(address(store), bytes32(0), bytes32(slot0));\n        vm.store(address(store), bytes32(uint256(1)), bytes32(slot1));\n        assertEq(store.slot0(), slot0, \"store failed\");\n        assertEq(store.slot1(), slot1, \"store failed\");\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/StringUtils.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract StringManipulationTest is Test {\n    function testToLowercase() public {\n        string memory original = \"Hello World\";\n        string memory lowercased = vm.toLowercase(original);\n        assertEq(\"hello world\", lowercased);\n    }\n\n    function testToUppercase() public {\n        string memory original = \"Hello World\";\n        string memory uppercased = vm.toUppercase(original);\n        assertEq(\"HELLO WORLD\", uppercased);\n    }\n\n    function testTrim() public {\n        string memory original = \"   Hello World   \";\n        string memory trimmed = vm.trim(original);\n        assertEq(\"Hello World\", trimmed);\n    }\n\n    function testReplace() public {\n        string memory original = \"Hello World\";\n        string memory replaced = vm.replace(original, \"World\", \"Reth\");\n        assertEq(\"Hello Reth\", replaced);\n    }\n\n    function testSplit() public {\n        string memory original = \"Hello,World,Reth\";\n        string[] memory splitResult = vm.split(original, \",\");\n        assertEq(3, splitResult.length);\n        assertEq(\"Hello\", splitResult[0]);\n        assertEq(\"World\", splitResult[1]);\n        assertEq(\"Reth\", splitResult[2]);\n    }\n\n    function testIndexOf() public {\n        string memory input = \"Hello, World!\";\n        string memory key1 = \"Hello,\";\n        string memory key2 = \"World!\";\n        string memory key3 = \"\";\n        string memory key4 = \"foundry\";\n        assertEq(vm.indexOf(input, key1), 0);\n        assertEq(vm.indexOf(input, key2), 7);\n        assertEq(vm.indexOf(input, key3), 0);\n        assertEq(vm.indexOf(input, key4), type(uint256).max);\n    }\n\n    function testContains() public {\n        string memory subject = \"this is a test\";\n        assert(vm.contains(subject, \"test\"));\n        assert(!vm.contains(subject, \"foundry\"));\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/ToString.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract ToStringTest is Test {\n    function testAddressToString() public {\n        address testAddress = 0x7109709ECfa91a80626fF3989D68f67F5b1DD12D;\n        string memory stringAddress = vm.toString(testAddress);\n        assertEq(\"0x7109709ECfa91a80626fF3989D68f67F5b1DD12D\", stringAddress);\n    }\n\n    function testBytes32ToString() public {\n        bytes32 testBytes = \"test\";\n        string memory stringBytes = vm.toString(testBytes);\n        assertEq(\"0x7465737400000000000000000000000000000000000000000000000000000000\", stringBytes);\n    }\n\n    function testBoolToString() public {\n        bool testBool = true;\n        string memory stringBool = vm.toString(testBool);\n        assertEq(\"true\", stringBool);\n    }\n\n    function testBytesToString() public {\n        bytes memory testBytes = hex\"7109709ECfa91a80626fF3989D68f67F5b1DD12D\";\n        string memory stringBytes = vm.toString(testBytes);\n        assertEq(\"0x7109709ecfa91a80626ff3989d68f67f5b1dd12d\", stringBytes);\n    }\n\n    function testUintToString() public {\n        uint256 testUint = 420;\n        string memory stringUint = vm.toString(testUint);\n        assertEq(\"420\", stringUint);\n    }\n\n    function testIntToString() public {\n        int256 testInt = 420;\n        string memory stringInt = vm.toString(testInt);\n        assertEq(\"420\", stringInt);\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/Toml.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\nlibrary TomlStructs {\n    address constant HEVM_ADDRESS = address(bytes20(uint160(uint256(keccak256(\"hevm cheat code\")))));\n    Vm constant vm = Vm(HEVM_ADDRESS);\n\n    // forge eip712 testdata/default/cheats/Toml.t.sol -R 'cheats=testdata/cheats' -R 'ds-test=testdata/lib/ds-test/src' | grep ^FlatToml\n    string constant schema_FlatToml =\n        \"FlatToml(uint256 a,int24[][] arr,string str,bytes b,address addr,bytes32 fixedBytes)\";\n\n    // forge eip712 testdata/default/cheats/Toml.t.sol -R 'cheats=testdata/cheats' -R 'ds-test=testdata/lib/ds-test/src' | grep ^NestedToml\n    string constant schema_NestedToml =\n        \"NestedToml(FlatToml[] members,AnotherFlatToml inner,string name)AnotherFlatToml(bytes4 fixedBytes)FlatToml(uint256 a,int24[][] arr,string str,bytes b,address addr,bytes32 fixedBytes)\";\n\n    function deserializeFlatToml(string memory toml) internal pure returns (ParseTomlTest.FlatToml memory) {\n        return abi.decode(vm.parseTomlType(toml, schema_FlatToml), (ParseTomlTest.FlatToml));\n    }\n\n    function deserializeFlatToml(string memory toml, string memory path)\n        internal\n        pure\n        returns (ParseTomlTest.FlatToml memory)\n    {\n        return abi.decode(vm.parseTomlType(toml, path, schema_FlatToml), (ParseTomlTest.FlatToml));\n    }\n\n    function deserializeFlatTomlArray(string memory toml, string memory path)\n        internal\n        pure\n        returns (ParseTomlTest.FlatToml[] memory)\n    {\n        return abi.decode(vm.parseTomlTypeArray(toml, path, schema_FlatToml), (ParseTomlTest.FlatToml[]));\n    }\n\n    function deserializeNestedToml(string memory toml) internal pure returns (ParseTomlTest.NestedToml memory) {\n        return abi.decode(vm.parseTomlType(toml, schema_NestedToml), (ParseTomlTest.NestedToml));\n    }\n\n    function deserializeNestedToml(string memory toml, string memory path)\n        internal\n        pure\n        returns (ParseTomlTest.NestedToml memory)\n    {\n        return abi.decode(vm.parseTomlType(toml, path, schema_NestedToml), (ParseTomlTest.NestedToml));\n    }\n\n    function deserializeNestedTomlArray(string memory toml, string memory path)\n        internal\n        pure\n        returns (ParseTomlTest.NestedToml[] memory)\n    {\n        return abi.decode(vm.parseTomlType(toml, path, schema_NestedToml), (ParseTomlTest.NestedToml[]));\n    }\n}\n\ncontract ParseTomlTest is Test {\n    using TomlStructs for *;\n\n    struct FlatToml {\n        uint256 a;\n        int24[][] arr;\n        string str;\n        bytes b;\n        address addr;\n        bytes32 fixedBytes;\n    }\n\n    struct AnotherFlatToml {\n        bytes4 fixedBytes;\n    }\n\n    struct NestedToml {\n        FlatToml[] members;\n        AnotherFlatToml inner;\n        string name;\n    }\n\n    string toml;\n\n    function setUp() public {\n        string memory path = \"fixtures/Toml/test.toml\";\n        toml = vm.readFile(path);\n    }\n\n    function test_basicString() public {\n        bytes memory data = vm.parseToml(toml, \".basicString\");\n        string memory decodedData = abi.decode(data, (string));\n        assertEq(\"hai\", decodedData);\n    }\n\n    function test_nullString() public {\n        bytes memory data = vm.parseToml(toml, \".nullString\");\n        string memory decodedData = abi.decode(data, (string));\n        assertEq(\"\", decodedData);\n    }\n\n    function test_stringMultiline() public {\n        bytes memory data = vm.parseToml(toml, \".multilineString\");\n        string memory decodedData = abi.decode(data, (string));\n        assertEq(\"hai\\nthere\\n\", decodedData);\n    }\n\n    function test_stringArray() public {\n        bytes memory data = vm.parseToml(toml, \".stringArray\");\n        string[] memory decodedData = abi.decode(data, (string[]));\n        assertEq(\"hai\", decodedData[0]);\n        assertEq(\"there\", decodedData[1]);\n    }\n\n    function test_address() public {\n        bytes memory data = vm.parseToml(toml, \".address\");\n        address decodedData = abi.decode(data, (address));\n        assertEq(0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266, decodedData);\n    }\n\n    function test_addressArray() public {\n        bytes memory data = vm.parseToml(toml, \".addressArray\");\n        address[] memory decodedData = abi.decode(data, (address[]));\n        assertEq(0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266, decodedData[0]);\n        assertEq(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D, decodedData[1]);\n    }\n\n    function test_H160ButNotaddress() public {\n        string memory data = abi.decode(vm.parseToml(toml, \".H160NotAddress\"), (string));\n        assertEq(\"0000000000000000000000000000000000001337\", data);\n    }\n\n    function test_bool() public {\n        bytes memory data = vm.parseToml(toml, \".boolTrue\");\n        bool decodedData = abi.decode(data, (bool));\n        assertTrue(decodedData);\n\n        data = vm.parseToml(toml, \".boolFalse\");\n        decodedData = abi.decode(data, (bool));\n        assertTrue(!decodedData);\n    }\n\n    function test_boolArray() public {\n        bytes memory data = vm.parseToml(toml, \".boolArray\");\n        bool[] memory decodedData = abi.decode(data, (bool[]));\n        assertTrue(decodedData[0]);\n        assertTrue(!decodedData[1]);\n    }\n\n    function test_dateTime() public {\n        bytes memory data = vm.parseToml(toml, \".datetime\");\n        string memory decodedData = abi.decode(data, (string));\n        assertEq(decodedData, \"2021-08-10T14:48:00Z\");\n    }\n\n    function test_dateTimeArray() public {\n        bytes memory data = vm.parseToml(toml, \".datetimeArray\");\n        string[] memory decodedData = abi.decode(data, (string[]));\n        assertEq(decodedData[0], \"2021-08-10T14:48:00Z\");\n        assertEq(decodedData[1], \"2021-08-10T14:48:00Z\");\n    }\n\n    function test_uintArray() public {\n        bytes memory data = vm.parseToml(toml, \".uintArray\");\n        uint256[] memory decodedData = abi.decode(data, (uint256[]));\n        assertEq(42, decodedData[0]);\n        assertEq(43, decodedData[1]);\n    }\n\n    // Object keys are sorted alphabetically, regardless of input.\n    struct Whole {\n        string str;\n        string[] strArray;\n        uint256[] uintArray;\n    }\n\n    function test_wholeToml() public {\n        // we need to make the path relative to the crate that's running tests for it (forge crate)\n        string memory path = \"fixtures/Toml/whole_toml.toml\";\n        console.log(path);\n        toml = vm.readFile(path);\n        bytes memory data = vm.parseToml(toml);\n        Whole memory whole = abi.decode(data, (Whole));\n        assertEq(whole.str, \"hai\");\n        assertEq(whole.strArray[0], \"hai\");\n        assertEq(whole.strArray[1], \"there\");\n        assertEq(whole.uintArray[0], 42);\n        assertEq(whole.uintArray[1], 43);\n    }\n\n    function test_coercionRevert() public {\n        vm._expectCheatcodeRevert(\"expected uint256, found JSON object\");\n        vm.parseTomlUint(toml, \".nestedObject\");\n    }\n\n    function test_coercionUint() public {\n        uint256 number = vm.parseTomlUint(toml, \".uintNumber\");\n        assertEq(number, 9223372036854775807); // TOML is limited to 64-bit integers\n        number = vm.parseTomlUint(toml, \".uintString\");\n        assertEq(number, 115792089237316195423570985008687907853269984665640564039457584007913129639935);\n        number = vm.parseTomlUint(toml, \".uintHex\");\n        assertEq(number, 1231232);\n        uint256[] memory numbers = vm.parseTomlUintArray(toml, \".uintArray\");\n        assertEq(numbers[0], 42);\n        assertEq(numbers[1], 43);\n        numbers = vm.parseTomlUintArray(toml, \".uintStringArray\");\n        assertEq(numbers[0], 1231232);\n        assertEq(numbers[1], 1231232);\n        assertEq(numbers[2], 1231232);\n    }\n\n    function test_coercionInt() public {\n        int256 number = vm.parseTomlInt(toml, \".intNumber\");\n        assertEq(number, -12);\n        number = vm.parseTomlInt(toml, \".intString\");\n        assertEq(number, -12);\n        number = vm.parseTomlInt(toml, \".intHex\");\n        assertEq(number, -12);\n    }\n\n    function test_coercionBool() public {\n        bool boolean = vm.parseTomlBool(toml, \".boolTrue\");\n        assertTrue(boolean);\n        bool boolFalse = vm.parseTomlBool(toml, \".boolFalse\");\n        assertTrue(!boolFalse);\n        boolean = vm.parseTomlBool(toml, \".boolString\");\n        assertEq(boolean, true);\n        bool[] memory booleans = vm.parseTomlBoolArray(toml, \".boolArray\");\n        assertTrue(booleans[0]);\n        assertTrue(!booleans[1]);\n        booleans = vm.parseTomlBoolArray(toml, \".boolStringArray\");\n        assertTrue(booleans[0]);\n        assertTrue(!booleans[1]);\n    }\n\n    function test_coercionBytes() public {\n        bytes memory bytes_ = vm.parseTomlBytes(toml, \".bytesString\");\n        assertEq(bytes_, hex\"01\");\n\n        bytes[] memory bytesArray = vm.parseTomlBytesArray(toml, \".bytesStringArray\");\n        assertEq(bytesArray[0], hex\"01\");\n        assertEq(bytesArray[1], hex\"02\");\n    }\n\n    struct NestedStruct {\n        uint256 number;\n        string str;\n    }\n\n    function test_nestedObject() public {\n        bytes memory data = vm.parseToml(toml, \".nestedObject\");\n        NestedStruct memory nested = abi.decode(data, (NestedStruct));\n        assertEq(nested.number, 9223372036854775807); // TOML is limited to 64-bit integers\n        assertEq(nested.str, \"NEST\");\n    }\n\n    function test_advancedTomlPath() public {\n        bytes memory data = vm.parseToml(toml, \".advancedTomlPath[*].id\");\n        uint256[] memory numbers = abi.decode(data, (uint256[]));\n        assertEq(numbers[0], 1);\n        assertEq(numbers[1], 2);\n    }\n\n    function test_canonicalizePath() public {\n        bytes memory data = vm.parseToml(toml, \"$.basicString\");\n        string memory decodedData = abi.decode(data, (string));\n        assertEq(\"hai\", decodedData);\n    }\n\n    function test_nonExistentKey() public {\n        bytes memory data = vm.parseToml(toml, \".thisKeyDoesNotExist\");\n        assertEq(0, data.length);\n    }\n\n    function test_parseTomlKeys() public {\n        string memory tomlString =\n            \"some_key_to_value = \\\"some_value\\\"\\n some_key_to_array = [1, 2, 3]\\n [some_key_to_object]\\n key1 = \\\"value1\\\"\\n key2 = 2\";\n\n        string[] memory keys = vm.parseTomlKeys(tomlString, \"$\");\n        string[] memory expected = new string[](3);\n        expected[0] = \"some_key_to_value\";\n        expected[1] = \"some_key_to_array\";\n        expected[2] = \"some_key_to_object\";\n        assertEq(abi.encode(keys), abi.encode(expected));\n\n        keys = vm.parseTomlKeys(tomlString, \".some_key_to_object\");\n        expected = new string[](2);\n        expected[0] = \"key1\";\n        expected[1] = \"key2\";\n        assertEq(abi.encode(keys), abi.encode(expected));\n\n        vm._expectCheatcodeRevert(\"JSON value at \\\".some_key_to_array\\\" is not an object\");\n        vm.parseTomlKeys(tomlString, \".some_key_to_array\");\n\n        vm._expectCheatcodeRevert(\"JSON value at \\\".some_key_to_value\\\" is not an object\");\n        vm.parseTomlKeys(tomlString, \".some_key_to_value\");\n\n        vm._expectCheatcodeRevert(\"key \\\".*\\\" must return exactly one JSON object\");\n        vm.parseTomlKeys(tomlString, \".*\");\n    }\n\n    // forge eip712 testdata/default/cheats/Toml.t.sol -R 'cheats=testdata/cheats' -R 'ds-test=testdata/lib/ds-test/src' | grep ^FlatToml\n    string constant schema_FlatToml =\n        \"FlatToml(uint256 a,int24[][] arr,string str,bytes b,address addr,bytes32 fixedBytes)\";\n\n    // forge eip712 testdata/default/cheats/Toml.t.sol -R 'cheats=testdata/cheats' -R 'ds-test=testdata/lib/ds-test/src' | grep ^NestedToml\n    string constant schema_NestedToml =\n        \"NestedToml(FlatToml[] members,AnotherFlatToml inner,string name)AnotherFlatToml(bytes4 fixedBytes)FlatToml(uint256 a,int24[][] arr,string str,bytes b,address addr,bytes32 fixedBytes)\";\n\n    function test_parseTomlType() public {\n        string memory readToml = vm.readFile(\"fixtures/Toml/nested_toml_struct.toml\");\n        NestedToml memory data = readToml.deserializeNestedToml();\n        assertEq(data.members.length, 2);\n\n        FlatToml memory expected = FlatToml({\n            a: 200,\n            arr: new int24[][](0),\n            str: \"some other string\",\n            b: hex\"0000000000000000000000000000000000000000\",\n            addr: 0x167D91deaEEE3021161502873d3bcc6291081648,\n            fixedBytes: 0xed1c7beb1f00feaaaec5636950d6edb25a8d4fedc8deb2711287b64c4d27719d\n        });\n\n        assertEq(keccak256(abi.encode(data.members[1])), keccak256(abi.encode(expected)));\n        assertEq(bytes32(data.inner.fixedBytes), bytes32(bytes4(0x12345678)));\n\n        FlatToml[] memory members = TomlStructs.deserializeFlatTomlArray(readToml, \".members\");\n\n        assertEq(keccak256(abi.encode(members)), keccak256(abi.encode(data.members)));\n    }\n\n    function test_floatNaN() public {\n        bytes memory data = vm.parseToml(toml, \".nanFloat\");\n        string memory decodedData = abi.decode(data, (string));\n        assertEq(\"NaN\", decodedData);\n    }\n\n    function test_floatInf() public {\n        bytes memory data = vm.parseToml(toml, \".infFloat\");\n        string memory decodedData = abi.decode(data, (string));\n        assertEq(\"inf\", decodedData);\n    }\n\n    function test_floatNegInf() public {\n        bytes memory data = vm.parseToml(toml, \".neginfFloat\");\n        string memory decodedData = abi.decode(data, (string));\n        assertEq(\"-inf\", decodedData);\n    }\n}\n\ncontract WriteTomlTest is Test {\n    string json1;\n    string json2;\n\n    function setUp() public {\n        json1 = \"example\";\n        json2 = \"example2\";\n    }\n\n    struct simpleStruct {\n        uint256 a;\n        string b;\n    }\n\n    struct nestedStruct {\n        uint256 a;\n        string b;\n        simpleStruct c;\n    }\n\n    function test_serializeNestedStructToml() public {\n        string memory json3 = \"json3\";\n        string memory path = \"fixtures/Toml/write_complex_test.toml\";\n        vm.serializeUint(json3, \"a\", uint256(123));\n        string memory semiFinal = vm.serializeString(json3, \"b\", \"test\");\n        string memory finalJson = vm.serializeString(json3, \"c\", semiFinal);\n        console.log(finalJson);\n        vm.writeToml(finalJson, path);\n        string memory toml = vm.readFile(path);\n        bytes memory data = vm.parseToml(toml);\n        nestedStruct memory decodedData = abi.decode(data, (nestedStruct));\n        console.log(decodedData.a);\n        assertEq(decodedData.a, 123);\n    }\n\n    function test_retrieveEntireToml() public {\n        string memory path = \"fixtures/Toml/write_complex_test.toml\";\n        string memory toml = vm.readFile(path);\n        bytes memory data = vm.parseToml(toml, \".\");\n        nestedStruct memory decodedData = abi.decode(data, (nestedStruct));\n        console.log(decodedData.a);\n        assertEq(decodedData.a, 123);\n    }\n\n    function test_checkKeyExists() public {\n        string memory path = \"fixtures/Toml/write_complex_test.toml\";\n        string memory toml = vm.readFile(path);\n        bool exists = vm.keyExistsToml(toml, \".a\");\n        assertTrue(exists);\n    }\n\n    function test_checkKeyDoesNotExist() public {\n        string memory path = \"fixtures/Toml/write_complex_test.toml\";\n        string memory toml = vm.readFile(path);\n        bool exists = vm.keyExistsToml(toml, \".d\");\n        assertTrue(!exists);\n    }\n\n    function test_writeToml() public {\n        string memory json3 = \"json3\";\n        string memory path = \"fixtures/Toml/write_test.toml\";\n        vm.serializeUint(json3, \"a\", uint256(123));\n        string memory finalJson = vm.serializeString(json3, \"b\", \"test\");\n        vm.writeToml(finalJson, path);\n\n        string memory toml = vm.readFile(path);\n        bytes memory data = vm.parseToml(toml);\n        simpleStruct memory decodedData = abi.decode(data, (simpleStruct));\n        assertEq(decodedData.a, 123);\n        assertEq(decodedData.b, \"test\");\n\n        // write json3 to key b\n        vm.writeToml(finalJson, path, \".b\");\n        // read again\n        toml = vm.readFile(path);\n        data = vm.parseToml(toml, \".b\");\n        decodedData = abi.decode(data, (simpleStruct));\n        assertEq(decodedData.a, 123);\n        assertEq(decodedData.b, \"test\");\n\n        // replace a single value to key b\n        address ex = address(0xBEEF);\n        vm.writeToml(vm.toString(ex), path, \".b\");\n        toml = vm.readFile(path);\n        data = vm.parseToml(toml, \".b\");\n        address decodedAddress = abi.decode(data, (address));\n        assertEq(decodedAddress, ex);\n    }\n\n    function test_writeToml_createKeys() public {\n        string memory path = \"fixtures/Toml/write_test.toml\";\n        string memory toml = vm.readFile(path);\n\n        bool exists = vm.keyExistsToml(toml, \".parent\");\n        assertTrue(!exists);\n        exists = vm.keyExistsToml(toml, \".parent.child\");\n        assertTrue(!exists);\n        exists = vm.keyExistsToml(toml, \".parent.child.value\");\n        assertTrue(!exists);\n\n        // Write to nested path, creating intermediate keys\n        vm.writeToml(vm.toString(uint256(42)), path, \".parent.child.value\");\n\n        // Verify the value was written and intermediate keys were created\n        toml = vm.readFile(path);\n        uint256 value = abi.decode(vm.parseToml(toml, \".parent.child.value\"), (uint256));\n        assertEq(value, 42);\n\n        // Clean up the test file by removing the parent key we added\n        vm.removeFile(path);\n        vm.writeToml(\"{\\\"a\\\": 123, \\\"b\\\": \\\"0x000000000000000000000000000000000000bEEF\\\"}\", path);\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/Travel.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract ChainIdTest is Test {\n    function testChainId() public {\n        vm.chainId(10);\n        assertEq(block.chainid, 10, \"chainId switch failed\");\n    }\n\n    function testChainIdFuzzed(uint64 chainId) public {\n        vm.chainId(chainId);\n        assertEq(block.chainid, chainId, \"chainId switch failed\");\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/TryFfi.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity >=0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract TryFfiTest is Test {\n    function testTryFfi() public {\n        string[] memory inputs = new string[](3);\n        inputs[0] = \"bash\";\n        inputs[1] = \"-c\";\n        inputs[2] =\n            \"echo -n 0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000966666920776f726b730000000000000000000000000000000000000000000000\";\n\n        Vm.FfiResult memory f = vm.tryFfi(inputs);\n        (string memory output) = abi.decode(f.stdout, (string));\n        assertEq(output, \"ffi works\", \"ffi failed\");\n        assertEq(f.exitCode, 0, \"ffi failed\");\n    }\n\n    function testTryFfiFail() public {\n        string[] memory inputs = new string[](2);\n        inputs[0] = \"ls\";\n        inputs[1] = \"wad\";\n\n        Vm.FfiResult memory f = vm.tryFfi(inputs);\n        assertTrue(f.exitCode != 0);\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/UnixTime.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract UnixTimeTest is Test {\n    // This is really wide because CI sucks.\n    uint256 constant errMargin = 1000;\n\n    function testUnixTimeAgainstDate() public {\n        string[] memory inputs = new string[](2);\n        inputs[0] = \"date\";\n        // OS X does not support precision more than 1 second.\n        inputs[1] = \"+%s000\";\n\n        bytes memory res = vm.ffi(inputs);\n        uint256 date = vm.parseUint(string(res));\n\n        // Limit precision to 1000 ms.\n        uint256 time = vm.unixTime() / 1000 * 1000;\n\n        vm.assertApproxEqAbs(date, time, errMargin, \".unixTime() is inaccurate vs date\");\n    }\n\n    function testUnixTime() public {\n        uint256 sleepTime = 2000;\n\n        uint256 start = vm.unixTime();\n        vm.sleep(sleepTime);\n        uint256 end = vm.unixTime();\n        uint256 interval = end - start;\n\n        vm.assertApproxEqAbs(interval, sleepTime, errMargin, \".unixTime() is inaccurate\");\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/Wallet.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract Foo {}\n\ncontract WalletTest is Test {\n    uint256 internal constant Q = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141;\n    uint256 private constant UINT256_MAX =\n        115792089237316195423570985008687907853269984665640564039457584007913129639935;\n\n    function addressOf(uint256 x, uint256 y) internal pure returns (address) {\n        return address(uint160(uint256(keccak256(abi.encode(x, y)))));\n    }\n\n    function bound(uint256 x, uint256 min, uint256 max) internal pure virtual returns (uint256 result) {\n        require(min <= max, \"min needs to be less than max\");\n        // If x is between min and max, return x directly. This is to ensure that dictionary values\n        // do not get shifted if the min is nonzero. More info: https://github.com/foundry-rs/forge-std/issues/188\n        if (x >= min && x <= max) return x;\n\n        uint256 size = max - min + 1;\n\n        // If the value is 0, 1, 2, 3, wrap that to min, min+1, min+2, min+3. Similarly for the UINT256_MAX side.\n        // This helps ensure coverage of the min/max values.\n        if (x <= 3 && size > x) return min + x;\n        if (x >= UINT256_MAX - 3 && size > UINT256_MAX - x) return max - (UINT256_MAX - x);\n\n        // Otherwise, wrap x into the range [min, max], i.e. the range is inclusive.\n        if (x > max) {\n            uint256 diff = x - max;\n            uint256 rem = diff % size;\n            if (rem == 0) return max;\n            result = min + rem - 1;\n        } else if (x < min) {\n            uint256 diff = min - x;\n            uint256 rem = diff % size;\n            if (rem == 0) return min;\n            result = max - rem + 1;\n        }\n    }\n\n    function testCreateWalletStringPrivAndLabel() public {\n        bytes memory privKey = \"this is a priv key\";\n        Vm.Wallet memory wallet = vm.createWallet(string(privKey));\n\n        // check wallet.addr against recovered address using private key\n        address expectedAddr = vm.addr(wallet.privateKey);\n        assertEq(expectedAddr, wallet.addr);\n\n        // check wallet.addr against recovered address using x and y coordinates\n        expectedAddr = addressOf(wallet.publicKeyX, wallet.publicKeyY);\n        assertEq(expectedAddr, wallet.addr);\n\n        string memory label = vm.getLabel(wallet.addr);\n        assertEq(label, string(privKey), \"labelled address != wallet.addr\");\n    }\n\n    function testCreateWalletPrivKeyNoLabel(uint256 pkSeed) public {\n        uint256 pk = bound(pkSeed, 1, Q - 1);\n\n        Vm.Wallet memory wallet = vm.createWallet(pk);\n\n        // check wallet.addr against recovered address using private key\n        address expectedAddr = vm.addr(wallet.privateKey);\n        assertEq(expectedAddr, wallet.addr);\n\n        // check wallet.addr against recovered address using x and y coordinates\n        expectedAddr = addressOf(wallet.publicKeyX, wallet.publicKeyY);\n        assertEq(expectedAddr, wallet.addr);\n    }\n\n    function testCreateWalletPrivKeyWithLabel(uint256 pkSeed) public {\n        string memory label = \"labelled wallet\";\n\n        uint256 pk = bound(pkSeed, 1, Q - 1);\n\n        Vm.Wallet memory wallet = vm.createWallet(pk, label);\n\n        // check wallet.addr against recovered address using private key\n        address expectedAddr = vm.addr(wallet.privateKey);\n        assertEq(expectedAddr, wallet.addr);\n\n        // check wallet.addr against recovered address using x and y coordinates\n        expectedAddr = addressOf(wallet.publicKeyX, wallet.publicKeyY);\n        assertEq(expectedAddr, wallet.addr);\n\n        string memory expectedLabel = vm.getLabel(wallet.addr);\n        assertEq(expectedLabel, label, \"labelled address != wallet.addr\");\n    }\n\n    function testSignWithWalletDigest(uint256 pkSeed, bytes32 digest) public {\n        uint256 pk = bound(pkSeed, 1, Q - 1);\n\n        Vm.Wallet memory wallet = vm.createWallet(pk);\n\n        (uint8 v, bytes32 r, bytes32 s) = vm.sign(wallet, digest);\n\n        address recovered = ecrecover(digest, v, r, s);\n        assertEq(recovered, wallet.addr);\n    }\n\n    function testSignCompactWithWalletDigest(uint256 pkSeed, bytes32 digest) public {\n        uint256 pk = bound(pkSeed, 1, Q - 1);\n\n        Vm.Wallet memory wallet = vm.createWallet(pk);\n\n        (bytes32 r, bytes32 vs) = vm.signCompact(wallet, digest);\n\n        // Extract `s` from `vs`.\n        // Shift left by 1 bit to clear the leftmost bit, then shift right by 1 bit to restore the original position.\n        // This effectively clears the leftmost bit of `vs`, giving us `s`.\n        bytes32 s = bytes32((uint256(vs) << 1) >> 1);\n\n        // Extract `v` from `vs`.\n        // We shift `vs` right by 255 bits to isolate the leftmost bit.\n        // Converting this to uint8 gives us the parity bit (0 or 1).\n        // Adding 27 converts this parity bit to the correct `v` value (27 or 28).\n        uint8 v = uint8(uint256(vs) >> 255) + 27;\n\n        address recovered = ecrecover(digest, v, r, s);\n        assertEq(recovered, wallet.addr);\n    }\n\n    function testSignWithWalletMessage(uint256 pkSeed, bytes memory message) public {\n        testSignWithWalletDigest(pkSeed, keccak256(message));\n    }\n\n    function testSignCompactWithWalletMessage(uint256 pkSeed, bytes memory message) public {\n        testSignCompactWithWalletDigest(pkSeed, keccak256(message));\n    }\n\n    function testGetNonceWallet(uint256 pkSeed) public {\n        uint256 pk = bound(pkSeed, 1, Q - 1);\n\n        Vm.Wallet memory wallet = vm.createWallet(pk);\n\n        uint64 nonce1 = vm.getNonce(wallet);\n\n        vm.startPrank(wallet.addr);\n        new Foo();\n        new Foo();\n        vm.stopPrank();\n\n        uint64 nonce2 = vm.getNonce(wallet);\n        assertEq(nonce1 + 2, nonce2);\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/Warp.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract WarpTest is Test {\n    function testWarp() public {\n        vm.warp(10);\n        assertEq(vm.getBlockTimestamp(), 10, \"warp failed\");\n    }\n\n    function testWarpFuzzed(uint32 jump) public {\n        uint256 pre = vm.getBlockTimestamp();\n        vm.warp(vm.getBlockTimestamp() + jump);\n        assertEq(vm.getBlockTimestamp(), pre + jump, \"warp failed\");\n    }\n\n    function testWarp2() public {\n        assertEq(vm.getBlockTimestamp(), 1);\n        vm.warp(100);\n        assertEq(vm.getBlockTimestamp(), 100);\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/dumpState.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract SimpleContract {\n    constructor() {\n        assembly {\n            sstore(1, 2)\n        }\n    }\n}\n\ncontract DumpStateTest is Test {\n    function testDumpStateCheatAccount() public {\n        // Path to temporary file that is deleted after the test\n        string memory path = string.concat(vm.projectRoot(), \"/fixtures/Json/test_dump_state_cheat.json\");\n\n        // Define some values to set in the state using cheatcodes\n        address target = address(1001);\n        bytes memory bytecode = hex\"11223344\";\n        uint256 balance = 1.2 ether;\n        uint64 nonce = 45;\n\n        vm.etch(target, bytecode);\n        vm.deal(target, balance);\n        vm.setNonce(target, nonce);\n        vm.store(target, bytes32(uint256(0x20)), bytes32(uint256(0x40)));\n        vm.store(target, bytes32(uint256(0x40)), bytes32(uint256(0x60)));\n\n        // Write the state to disk\n        vm.dumpState(path);\n\n        string memory json = vm.readFile(path);\n        string[] memory keys = vm.parseJsonKeys(json, \"\");\n        assertEq(keys.length, 1);\n\n        string memory key = keys[0];\n        assertEq(nonce, vm.parseJsonUint(json, string.concat(\".\", key, \".nonce\")));\n        assertEq(balance, vm.parseJsonUint(json, string.concat(\".\", key, \".balance\")));\n        assertEq(bytecode, vm.parseJsonBytes(json, string.concat(\".\", key, \".code\")));\n\n        string[] memory slots = vm.parseJsonKeys(json, string.concat(\".\", key, \".storage\"));\n        assertEq(slots.length, 2);\n\n        assertEq(\n            bytes32(uint256(0x40)),\n            vm.parseJsonBytes32(json, string.concat(\".\", key, \".storage.\", vm.toString(bytes32(uint256(0x20)))))\n        );\n        assertEq(\n            bytes32(uint256(0x60)),\n            vm.parseJsonBytes32(json, string.concat(\".\", key, \".storage.\", vm.toString(bytes32(uint256(0x40)))))\n        );\n\n        vm.removeFile(path);\n    }\n\n    function testDumpStateMultipleAccounts() public {\n        string memory path = string.concat(vm.projectRoot(), \"/fixtures/Json/test_dump_state_multiple_accounts.json\");\n\n        vm.setNonce(address(0x100), 1);\n        vm.deal(address(0x200), 1 ether);\n        vm.setNonce(address(0x300), 1);\n        vm.store(address(0x300), bytes32(uint256(1)), bytes32(uint256(2)));\n        vm.etch(address(0x400), hex\"af\");\n\n        vm.dumpState(path);\n\n        string memory json = vm.readFile(path);\n        string[] memory keys = vm.parseJsonKeys(json, \"\");\n        assertEq(keys.length, 4);\n\n        assertEq(4, vm.parseJsonKeys(json, string.concat(\".\", vm.toString(address(0x100)))).length);\n        assertEq(1, vm.parseJsonUint(json, string.concat(\".\", vm.toString(address(0x100)), \".nonce\")));\n        assertEq(0, vm.parseJsonUint(json, string.concat(\".\", vm.toString(address(0x100)), \".balance\")));\n        assertEq(hex\"\", vm.parseJsonBytes(json, string.concat(\".\", vm.toString(address(0x100)), \".code\")));\n        assertEq(0, vm.parseJsonKeys(json, string.concat(\".\", vm.toString(address(0x100)), \".storage\")).length);\n\n        assertEq(4, vm.parseJsonKeys(json, string.concat(\".\", vm.toString(address(0x200)))).length);\n        assertEq(0, vm.parseJsonUint(json, string.concat(\".\", vm.toString(address(0x200)), \".nonce\")));\n        assertEq(1 ether, vm.parseJsonUint(json, string.concat(\".\", vm.toString(address(0x200)), \".balance\")));\n        assertEq(hex\"\", vm.parseJsonBytes(json, string.concat(\".\", vm.toString(address(0x200)), \".code\")));\n        assertEq(0, vm.parseJsonKeys(json, string.concat(\".\", vm.toString(address(0x200)), \".storage\")).length);\n\n        assertEq(4, vm.parseJsonKeys(json, string.concat(\".\", vm.toString(address(0x300)))).length);\n        assertEq(1, vm.parseJsonUint(json, string.concat(\".\", vm.toString(address(0x300)), \".nonce\")));\n        assertEq(0, vm.parseJsonUint(json, string.concat(\".\", vm.toString(address(0x300)), \".balance\")));\n        assertEq(hex\"\", vm.parseJsonBytes(json, string.concat(\".\", vm.toString(address(0x300)), \".code\")));\n        assertEq(1, vm.parseJsonKeys(json, string.concat(\".\", vm.toString(address(0x300)), \".storage\")).length);\n        assertEq(\n            2,\n            vm.parseJsonUint(\n                json, string.concat(\".\", vm.toString(address(0x300)), \".storage.\", vm.toString(bytes32(uint256(1))))\n            )\n        );\n\n        assertEq(4, vm.parseJsonKeys(json, string.concat(\".\", vm.toString(address(0x400)))).length);\n        assertEq(0, vm.parseJsonUint(json, string.concat(\".\", vm.toString(address(0x400)), \".nonce\")));\n        assertEq(0, vm.parseJsonUint(json, string.concat(\".\", vm.toString(address(0x400)), \".balance\")));\n        assertEq(hex\"af\", vm.parseJsonBytes(json, string.concat(\".\", vm.toString(address(0x400)), \".code\")));\n        assertEq(0, vm.parseJsonKeys(json, string.concat(\".\", vm.toString(address(0x400)), \".storage\")).length);\n\n        vm.removeFile(path);\n    }\n\n    function testDumpStateDeployment() public {\n        string memory path = string.concat(vm.projectRoot(), \"/fixtures/Json/test_dump_state_deployment.json\");\n\n        SimpleContract s = new SimpleContract();\n        vm.dumpState(path);\n\n        string memory json = vm.readFile(path);\n        string[] memory keys = vm.parseJsonKeys(json, \"\");\n        assertEq(keys.length, 1);\n        assertEq(address(s), vm.parseAddress(keys[0]));\n        assertEq(1, vm.parseJsonKeys(json, string.concat(\".\", keys[0], \".storage\")).length);\n        assertEq(2, vm.parseJsonUint(json, string.concat(\".\", keys[0], \".storage.\", vm.toString(bytes32(uint256(1))))));\n\n        vm.removeFile(path);\n    }\n\n    function testDumpStateEmptyAccount() public {\n        string memory path = string.concat(vm.projectRoot(), \"/fixtures/Json/test_dump_state_empty_account.json\");\n\n        SimpleContract s = new SimpleContract();\n        vm.etch(address(s), hex\"\");\n        vm.resetNonce(address(s));\n\n        vm.dumpState(path);\n        string memory json = vm.readFile(path);\n        string[] memory keys = vm.parseJsonKeys(json, \"\");\n        assertEq(keys.length, 0);\n\n        vm.removeFile(path);\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/getBlockNumber.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract GetBlockNumberTest is Test {\n    function testGetBlockNumber() public {\n        uint256 height = vm.getBlockNumber();\n        assertEq(height, uint256(block.number), \"height should be equal to block.number\");\n    }\n\n    function testGetBlockNumberWithRoll() public {\n        vm.roll(10);\n        assertEq(vm.getBlockNumber(), 10, \"could not get correct block height after roll\");\n    }\n\n    function testGetBlockNumberWithRollFuzzed(uint32 jump) public {\n        uint256 pre = vm.getBlockNumber();\n        vm.roll(pre + jump);\n        assertEq(vm.getBlockNumber(), pre + jump, \"could not get correct block height after roll\");\n    }\n}\n"
  },
  {
    "path": "testdata/default/cheats/loadAllocs.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract LoadAllocsTest is Test {\n    address constant ALLOCD = address(0x420);\n    address constant ALLOCD_B = address(0x421);\n\n    uint256 snapshotId;\n    string allocsPath;\n\n    function setUp() public {\n        allocsPath = string.concat(vm.projectRoot(), \"/fixtures/Json/test_allocs.json\");\n\n        // Snapshot the state; We'll restore it in each test that loads allocs inline.\n        snapshotId = vm.snapshotState();\n\n        // Load the allocs file.\n        vm.loadAllocs(allocsPath);\n    }\n\n    /// @dev Checks that the `loadAllocs` cheatcode persists account info if called in `setUp`\n    function testLoadAllocsStaticSetup() public {\n        // Balance should be `0xabcd`\n        assertEq(ALLOCD.balance, 0xabcd);\n\n        // Code should be a simple store / return, returning `0x42`\n        (bool success, bytes memory rd) = ALLOCD.staticcall(\"\");\n        assertTrue(success);\n        uint256 ret = abi.decode(rd, (uint256));\n        assertEq(ret, 0x42);\n\n        // Storage should have been set in slot 0x1, equal to `0xbeef`\n        assertEq(uint256(vm.load(ALLOCD, bytes32(uint256(0x10 << 248)))), 0xbeef);\n    }\n\n    /// @dev Checks that the `loadAllocs` cheatcode persists account info if called inline\n    function testLoadAllocsStatic() public {\n        // Restore the state snapshot prior to the allocs file being loaded.\n        vm.revertToState(snapshotId);\n\n        // Load the allocs file\n        vm.loadAllocs(allocsPath);\n\n        // Balance should be `0xabcd`\n        assertEq(ALLOCD.balance, 0xabcd);\n\n        // Code should be a simple store / return, returning `0x42`\n        (bool success, bytes memory rd) = ALLOCD.staticcall(\"\");\n        assertTrue(success);\n        uint256 ret = abi.decode(rd, (uint256));\n        assertEq(ret, 0x42);\n\n        // Storage should have been set in slot 0x1, equal to `0xbeef`\n        assertEq(uint256(vm.load(ALLOCD, bytes32(uint256(0x10 << 248)))), 0xbeef);\n    }\n\n    /// @dev Checks that the `loadAllocs` cheatcode overrides existing account information (if present)\n    function testLoadAllocsOverride() public {\n        // Restore the state snapshot prior to the allocs file being loaded.\n        vm.revertToState(snapshotId);\n\n        // Populate the alloc'd account's code.\n        vm.etch(ALLOCD, hex\"FF\");\n        assertEq(ALLOCD.code, hex\"FF\");\n\n        // Store something in the alloc'd storage slot.\n        bytes32 slot = bytes32(uint256(0x10 << 248));\n        vm.store(ALLOCD, slot, bytes32(uint256(0xBADC0DE)));\n        assertEq(uint256(vm.load(ALLOCD, slot)), 0xBADC0DE);\n\n        // Populate balance.\n        vm.deal(ALLOCD, 0x1234);\n        assertEq(ALLOCD.balance, 0x1234);\n\n        vm.loadAllocs(allocsPath);\n\n        // Info should have changed.\n        assertTrue(keccak256(ALLOCD.code) != keccak256(hex\"FF\"));\n        assertEq(uint256(vm.load(ALLOCD, slot)), 0xbeef);\n        assertEq(ALLOCD.balance, 0xabcd);\n    }\n\n    /// @dev Checks that the `loadAllocs` cheatcode does not override existing account information if there is no data\n    ///      within the allocs/genesis file for the account field (i.e., partial overrides)\n    function testLoadAllocsPartialOverride() public {\n        // Restore the state snapshot prior to the allocs file being loaded.\n        vm.revertToState(snapshotId);\n\n        // Populate the alloc'd account's code.\n        vm.etch(ALLOCD_B, hex\"FF\");\n        assertEq(ALLOCD_B.code, hex\"FF\");\n\n        // Populate balance.\n        vm.deal(ALLOCD_B, 0x1234);\n        assertEq(ALLOCD_B.balance, 0x1234);\n\n        vm.loadAllocs(allocsPath);\n\n        assertEq(ALLOCD_B.code, hex\"FF\");\n        assertEq(ALLOCD_B.balance, 0);\n    }\n}\n"
  },
  {
    "path": "testdata/default/core/Abstract.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\ncontract TestFixture {\n    function something() public pure returns (string memory) {\n        return \"something\";\n    }\n}\n\nabstract contract AbstractTestBase {\n    TestFixture fixture;\n\n    function testSomething() public {\n        fixture.something();\n    }\n}\n\ncontract AbstractTest is AbstractTestBase {\n    function setUp() public {\n        fixture = new TestFixture();\n    }\n}\n"
  },
  {
    "path": "testdata/default/core/BadSigAfterInvariant.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract BadSigAfterInvariant is Test {\n    function afterinvariant() public {}\n\n    function testShouldPassWithWarning() public {\n        assert(true);\n    }\n}\n"
  },
  {
    "path": "testdata/default/core/ContractEnvironment.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract ContractEnvironmentTest is Test {\n    function chainId() internal view returns (uint256 id) {\n        assembly {\n            id := chainid()\n        }\n    }\n\n    function testAddresses() public {\n        assertEq(msg.sender, 0x1804c8AB1F12E6bbf3894d4083f33e07309d1f38, \"sender account is incorrect\");\n        assertEq(tx.origin, 0x1804c8AB1F12E6bbf3894d4083f33e07309d1f38, \"origin account is incorrect\");\n        assertEq(address(this), 0x7FA9385bE102ac3EAc297483Dd6233D62b3e1496, \"test contract address is incorrect\");\n    }\n\n    function testEnvironment() public {\n        assertEq(chainId(), 31337, \"chainid is incorrect\");\n        assertEq(block.number, 1, \"block number is incorrect\");\n        assertEq(blockhash(block.number), 0x0, \"blockhash is incorrect\");\n        assertEq(block.coinbase, 0x0000000000000000000000000000000000000000, \"coinbase is incorrect\");\n        assertEq(block.timestamp, 1, \"timestamp is incorrect\");\n        assertEq(block.prevrandao, 0, \"prevrandao is incorrect\");\n    }\n}\n"
  },
  {
    "path": "testdata/default/core/Reverting.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract RevertingTest is Test {\n    /// forge-config: default.allow_internal_expect_revert = true\n    function testRevert() public {\n        vm.expectRevert(\"should revert here\");\n        require(false, \"should revert here\");\n    }\n}\n"
  },
  {
    "path": "testdata/default/core/SetupConsistency.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract SetupConsistencyCheck is Test {\n    uint256 two;\n    uint256 four;\n    uint256 result;\n\n    function setUp() public {\n        two = 2;\n        four = 4;\n        result = 0;\n    }\n\n    function testAdd() public {\n        assertEq(result, 0);\n        result = two + four;\n        assertEq(result, 6);\n    }\n\n    function testMultiply() public {\n        assertEq(result, 0);\n        result = two * four;\n        assertEq(result, 8);\n    }\n}\n"
  },
  {
    "path": "testdata/default/fork/DssExecLib.sol",
    "content": "/**\n * Submitted for verification at Etherscan.io on 2021-09-16\n */\n\n// SPDX-License-Identifier: AGPL-3.0-or-later\n//\n// DssExecLib.sol -- MakerDAO Executive Spellcrafting Library\n//\n// Copyright (C) 2020 Maker Ecosystem Growth Holdings, Inc.\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <https://www.gnu.org/licenses/>.\npragma solidity >=0.6.12 <0.7.0;\n\npragma experimental ABIEncoderV2;\n\nstruct CollateralOpts {\n    bytes32 ilk;\n    address gem;\n    address join;\n    address clip;\n    address calc;\n    address pip;\n    bool isLiquidatable;\n    bool isOSM;\n    bool whitelistOSM;\n    uint256 ilkDebtCeiling;\n    uint256 minVaultAmount;\n    uint256 maxLiquidationAmount;\n    uint256 liquidationPenalty;\n    uint256 ilkStabilityFee;\n    uint256 startingPriceFactor;\n    uint256 breakerTolerance;\n    uint256 auctionDuration;\n    uint256 permittedDrop;\n    uint256 liquidationRatio;\n    uint256 kprFlatReward;\n    uint256 kprPctReward;\n}\n\ninterface Initializable {\n    function init(bytes32) external;\n}\n\ninterface Authorizable {\n    function rely(address) external;\n    function deny(address) external;\n}\n\ninterface Fileable {\n    function file(bytes32, address) external;\n    function file(bytes32, uint256) external;\n    function file(bytes32, bytes32, uint256) external;\n    function file(bytes32, bytes32, address) external;\n}\n\ninterface Drippable {\n    function drip() external returns (uint256);\n    function drip(bytes32) external returns (uint256);\n}\n\ninterface Pricing {\n    function poke(bytes32) external;\n}\n\ninterface ERC20 {\n    function decimals() external returns (uint8);\n}\n\ninterface DssVat {\n    function hope(address) external;\n    function nope(address) external;\n    function ilks(bytes32) external returns (uint256 Art, uint256 rate, uint256 spot, uint256 line, uint256 dust);\n    function Line() external view returns (uint256);\n    function suck(address, address, uint256) external;\n}\n\ninterface ClipLike {\n    function vat() external returns (address);\n    function dog() external returns (address);\n    function spotter() external view returns (address);\n    function calc() external view returns (address);\n    function ilk() external returns (bytes32);\n}\n\ninterface JoinLike {\n    function vat() external returns (address);\n    function ilk() external returns (bytes32);\n    function gem() external returns (address);\n    function dec() external returns (uint256);\n    function join(address, uint256) external;\n    function exit(address, uint256) external;\n}\n\n// Includes Median and OSM functions\ninterface OracleLike {\n    function src() external view returns (address);\n    function lift(address[] calldata) external;\n    function drop(address[] calldata) external;\n    function setBar(uint256) external;\n    function kiss(address) external;\n    function diss(address) external;\n    function kiss(address[] calldata) external;\n    function diss(address[] calldata) external;\n    function orb0() external view returns (address);\n    function orb1() external view returns (address);\n}\n\ninterface MomLike {\n    function setOsm(bytes32, address) external;\n    function setPriceTolerance(address, uint256) external;\n}\n\ninterface RegistryLike {\n    function add(address) external;\n    function xlip(bytes32) external view returns (address);\n}\n\n// https://github.com/makerdao/dss-chain-log\ninterface ChainlogLike {\n    function setVersion(string calldata) external;\n    function setIPFS(string calldata) external;\n    function setSha256sum(string calldata) external;\n    function getAddress(bytes32) external view returns (address);\n    function setAddress(bytes32, address) external;\n    function removeAddress(bytes32) external;\n}\n\ninterface IAMLike {\n    function ilks(bytes32) external view returns (uint256, uint256, uint48, uint48, uint48);\n    function setIlk(bytes32, uint256, uint256, uint256) external;\n    function remIlk(bytes32) external;\n    function exec(bytes32) external returns (uint256);\n}\n\ninterface LerpFactoryLike {\n    function newLerp(\n        bytes32 name_,\n        address target_,\n        bytes32 what_,\n        uint256 startTime_,\n        uint256 start_,\n        uint256 end_,\n        uint256 duration_\n    ) external returns (address);\n    function newIlkLerp(\n        bytes32 name_,\n        address target_,\n        bytes32 ilk_,\n        bytes32 what_,\n        uint256 startTime_,\n        uint256 start_,\n        uint256 end_,\n        uint256 duration_\n    ) external returns (address);\n}\n\ninterface LerpLike {\n    function tick() external;\n}\n\nlibrary DssExecLib {\n    /**\n     *\n     */\n    /**\n     * Constants **\n     */\n    /**\n     *\n     */\n    address public constant LOG = 0xdA0Ab1e0017DEbCd72Be8599041a2aa3bA7e740F;\n\n    uint256 internal constant WAD = 10 ** 18;\n    uint256 internal constant RAY = 10 ** 27;\n    uint256 internal constant RAD = 10 ** 45;\n    uint256 internal constant THOUSAND = 10 ** 3;\n    uint256 internal constant MILLION = 10 ** 6;\n\n    uint256 internal constant BPS_ONE_PCT = 100;\n    uint256 internal constant BPS_ONE_HUNDRED_PCT = 100 * BPS_ONE_PCT;\n    uint256 internal constant RATES_ONE_HUNDRED_PCT = 1000000021979553151239153027;\n\n    /**\n     *\n     */\n    /**\n     * Math Functions **\n     */\n    /**\n     *\n     */\n    function add(uint256 x, uint256 y) internal pure returns (uint256 z) {\n        require((z = x + y) >= x);\n    }\n\n    function sub(uint256 x, uint256 y) internal pure returns (uint256 z) {\n        require((z = x - y) <= x);\n    }\n\n    function mul(uint256 x, uint256 y) internal pure returns (uint256 z) {\n        require(y == 0 || (z = x * y) / y == x);\n    }\n\n    function wmul(uint256 x, uint256 y) internal pure returns (uint256 z) {\n        z = add(mul(x, y), WAD / 2) / WAD;\n    }\n\n    function rmul(uint256 x, uint256 y) internal pure returns (uint256 z) {\n        z = add(mul(x, y), RAY / 2) / RAY;\n    }\n\n    function wdiv(uint256 x, uint256 y) internal pure returns (uint256 z) {\n        z = add(mul(x, WAD), y / 2) / y;\n    }\n\n    function rdiv(uint256 x, uint256 y) internal pure returns (uint256 z) {\n        z = add(mul(x, RAY), y / 2) / y;\n    }\n\n    /**\n     *\n     */\n    /**\n     * Core Address Helpers **\n     */\n    /**\n     *\n     */\n    function dai() public view returns (address) {\n        return getChangelogAddress(\"MCD_DAI\");\n    }\n\n    function mkr() public view returns (address) {\n        return getChangelogAddress(\"MCD_GOV\");\n    }\n\n    function vat() public view returns (address) {\n        return getChangelogAddress(\"MCD_VAT\");\n    }\n\n    function cat() public view returns (address) {\n        return getChangelogAddress(\"MCD_CAT\");\n    }\n\n    function dog() public view returns (address) {\n        return getChangelogAddress(\"MCD_DOG\");\n    }\n\n    function jug() public view returns (address) {\n        return getChangelogAddress(\"MCD_JUG\");\n    }\n\n    function pot() public view returns (address) {\n        return getChangelogAddress(\"MCD_POT\");\n    }\n\n    function vow() public view returns (address) {\n        return getChangelogAddress(\"MCD_VOW\");\n    }\n\n    function end() public view returns (address) {\n        return getChangelogAddress(\"MCD_END\");\n    }\n\n    function esm() public view returns (address) {\n        return getChangelogAddress(\"MCD_ESM\");\n    }\n\n    function reg() public view returns (address) {\n        return getChangelogAddress(\"ILK_REGISTRY\");\n    }\n\n    function spotter() public view returns (address) {\n        return getChangelogAddress(\"MCD_SPOT\");\n    }\n\n    function flap() public view returns (address) {\n        return getChangelogAddress(\"MCD_FLAP\");\n    }\n\n    function flop() public view returns (address) {\n        return getChangelogAddress(\"MCD_FLOP\");\n    }\n\n    function osmMom() public view returns (address) {\n        return getChangelogAddress(\"OSM_MOM\");\n    }\n\n    function govGuard() public view returns (address) {\n        return getChangelogAddress(\"GOV_GUARD\");\n    }\n\n    function flipperMom() public view returns (address) {\n        return getChangelogAddress(\"FLIPPER_MOM\");\n    }\n\n    function clipperMom() public view returns (address) {\n        return getChangelogAddress(\"CLIPPER_MOM\");\n    }\n\n    function pauseProxy() public view returns (address) {\n        return getChangelogAddress(\"MCD_PAUSE_PROXY\");\n    }\n\n    function autoLine() public view returns (address) {\n        return getChangelogAddress(\"MCD_IAM_AUTO_LINE\");\n    }\n\n    function daiJoin() public view returns (address) {\n        return getChangelogAddress(\"MCD_JOIN_DAI\");\n    }\n\n    function lerpFab() public view returns (address) {\n        return getChangelogAddress(\"LERP_FAB\");\n    }\n\n    function clip(bytes32 _ilk) public view returns (address _clip) {\n        _clip = RegistryLike(reg()).xlip(_ilk);\n    }\n\n    function flip(bytes32 _ilk) public view returns (address _flip) {\n        _flip = RegistryLike(reg()).xlip(_ilk);\n    }\n\n    function calc(bytes32 _ilk) public view returns (address _calc) {\n        _calc = ClipLike(clip(_ilk)).calc();\n    }\n\n    function getChangelogAddress(bytes32 _key) public view returns (address) {\n        return ChainlogLike(LOG).getAddress(_key);\n    }\n\n    /**\n     *\n     */\n    /**\n     * Changelog Management **\n     */\n    /**\n     *\n     */\n    /**\n     * @dev Set an address in the MCD on-chain changelog.\n     * @param _key Access key for the address (e.g. \"MCD_VAT\")\n     * @param _val The address associated with the _key\n     */\n    function setChangelogAddress(bytes32 _key, address _val) public {\n        ChainlogLike(LOG).setAddress(_key, _val);\n    }\n\n    /**\n     * @dev Set version in the MCD on-chain changelog.\n     * @param _version Changelog version (e.g. \"1.1.2\")\n     */\n    function setChangelogVersion(string memory _version) public {\n        ChainlogLike(LOG).setVersion(_version);\n    }\n    /**\n     * @dev Set IPFS hash of IPFS changelog in MCD on-chain changelog.\n     * @param _ipfsHash IPFS hash (e.g. \"QmefQMseb3AiTapiAKKexdKHig8wroKuZbmLtPLv4u2YwW\")\n     */\n\n    function setChangelogIPFS(string memory _ipfsHash) public {\n        ChainlogLike(LOG).setIPFS(_ipfsHash);\n    }\n    /**\n     * @dev Set SHA256 hash in MCD on-chain changelog.\n     * @param _SHA256Sum SHA256 hash (e.g. \"e42dc9d043a57705f3f097099e6b2de4230bca9a020c797508da079f9079e35b\")\n     */\n\n    function setChangelogSHA256(string memory _SHA256Sum) public {\n        ChainlogLike(LOG).setSha256sum(_SHA256Sum);\n    }\n\n    /**\n     *\n     */\n    /**\n     * Authorizations **\n     */\n    /**\n     *\n     */\n    /**\n     * @dev Give an address authorization to perform auth actions on the contract.\n     * @param _base   The address of the contract where the authorization will be set\n     * @param _ward   Address to be authorized\n     */\n    function authorize(address _base, address _ward) public {\n        Authorizable(_base).rely(_ward);\n    }\n    /**\n     * @dev Revoke contract authorization from an address.\n     * @param _base   The address of the contract where the authorization will be revoked\n     * @param _ward   Address to be deauthorized\n     */\n\n    function deauthorize(address _base, address _ward) public {\n        Authorizable(_base).deny(_ward);\n    }\n    /**\n     * @dev Delegate vat authority to the specified address.\n     * @param _usr Address to be authorized\n     */\n\n    function delegateVat(address _usr) public {\n        DssVat(vat()).hope(_usr);\n    }\n    /**\n     * @dev Revoke vat authority to the specified address.\n     * @param _usr Address to be deauthorized\n     */\n\n    function undelegateVat(address _usr) public {\n        DssVat(vat()).nope(_usr);\n    }\n\n    /**\n     *\n     */\n    /**\n     * OfficeHours Management **\n     */\n    /**\n     *\n     */\n\n    /**\n     * @dev Returns true if a time is within office hours range\n     * @param _ts           The timestamp to check, usually block.timestamp\n     * @param _officeHours  true if office hours is enabled.\n     * @return              true if time is in castable range\n     */\n    function canCast(uint40 _ts, bool _officeHours) public pure returns (bool) {\n        if (_officeHours) {\n            uint256 day = (_ts / 1 days + 3) % 7;\n            if (day >= 5) {\n                return false;\n            } // Can only be cast on a weekday\n            uint256 hour = _ts / 1 hours % 24;\n            if (hour < 14 || hour >= 21) {\n                return false;\n            } // Outside office hours\n        }\n        return true;\n    }\n\n    /**\n     * @dev Calculate the next available cast time in epoch seconds\n     * @param _eta          The scheduled time of the spell plus the pause delay\n     * @param _ts           The current timestamp, usually block.timestamp\n     * @param _officeHours  true if office hours is enabled.\n     * @return castTime     The next available cast timestamp\n     */\n    function nextCastTime(uint40 _eta, uint40 _ts, bool _officeHours) public pure returns (uint256 castTime) {\n        require(_eta != 0); // \"DssExecLib/invalid eta\"\n        require(_ts != 0); // \"DssExecLib/invalid ts\"\n        castTime = _ts > _eta ? _ts : _eta; // Any day at XX:YY\n\n        if (_officeHours) {\n            uint256 day = (castTime / 1 days + 3) % 7;\n            uint256 hour = castTime / 1 hours % 24;\n            uint256 minute = castTime / 1 minutes % 60;\n            uint256 second = castTime % 60;\n\n            if (day >= 5) {\n                castTime += (6 - day) * 1 days; // Go to Sunday XX:YY\n                castTime += (24 - hour + 14) * 1 hours; // Go to 14:YY UTC Monday\n                castTime -= minute * 1 minutes + second; // Go to 14:00 UTC\n            } else {\n                if (hour >= 21) {\n                    if (day == 4) {\n                        castTime += 2 days;\n                    } // If Friday, fast forward to Sunday XX:YY\n                    castTime += (24 - hour + 14) * 1 hours; // Go to 14:YY UTC next day\n                    castTime -= minute * 1 minutes + second; // Go to 14:00 UTC\n                } else if (hour < 14) {\n                    castTime += (14 - hour) * 1 hours; // Go to 14:YY UTC same day\n                    castTime -= minute * 1 minutes + second; // Go to 14:00 UTC\n                }\n            }\n        }\n    }\n\n    /**\n     *\n     */\n    /**\n     * Accumulating Rates **\n     */\n    /**\n     *\n     */\n    /**\n     * @dev Update rate accumulation for the Dai Savings Rate (DSR).\n     */\n    function accumulateDSR() public {\n        Drippable(pot()).drip();\n    }\n    /**\n     * @dev Update rate accumulation for the stability fees of a given collateral type.\n     * @param _ilk   Collateral type\n     */\n\n    function accumulateCollateralStabilityFees(bytes32 _ilk) public {\n        Drippable(jug()).drip(_ilk);\n    }\n\n    /**\n     *\n     */\n    /**\n     * Price Updates **\n     */\n    /**\n     *\n     */\n    /**\n     * @dev Update price of a given collateral type.\n     * @param _ilk   Collateral type\n     */\n    function updateCollateralPrice(bytes32 _ilk) public {\n        Pricing(spotter()).poke(_ilk);\n    }\n\n    /**\n     *\n     */\n    /**\n     * System Configuration **\n     */\n    /**\n     *\n     */\n    /**\n     * @dev Set a contract in another contract, defining the relationship (ex. set a new Calc contract in Clip)\n     * @param _base   The address of the contract where the new contract address will be filed\n     * @param _what   Name of contract to file\n     * @param _addr   Address of contract to file\n     */\n    function setContract(address _base, bytes32 _what, address _addr) public {\n        Fileable(_base).file(_what, _addr);\n    }\n    /**\n     * @dev Set a contract in another contract, defining the relationship (ex. set a new Calc contract in a Clip)\n     * @param _base   The address of the contract where the new contract address will be filed\n     * @param _ilk    Collateral type\n     * @param _what   Name of contract to file\n     * @param _addr   Address of contract to file\n     */\n\n    function setContract(address _base, bytes32 _ilk, bytes32 _what, address _addr) public {\n        Fileable(_base).file(_ilk, _what, _addr);\n    }\n    /**\n     * @dev Set a value in a contract, via a governance authorized File pattern.\n     * @param _base   The address of the contract where the new contract address will be filed\n     * @param _what   Name of tag for the value (e.x. \"Line\")\n     * @param _amt    The value to set or update\n     */\n\n    function setValue(address _base, bytes32 _what, uint256 _amt) public {\n        Fileable(_base).file(_what, _amt);\n    }\n    /**\n     * @dev Set an ilk-specific value in a contract, via a governance authorized File pattern.\n     * @param _base   The address of the contract where the new value will be filed\n     * @param _ilk    Collateral type\n     * @param _what   Name of tag for the value (e.x. \"Line\")\n     * @param _amt    The value to set or update\n     */\n\n    function setValue(address _base, bytes32 _ilk, bytes32 _what, uint256 _amt) public {\n        Fileable(_base).file(_ilk, _what, _amt);\n    }\n\n    /**\n     *\n     */\n    /**\n     * System Risk Parameters **\n     */\n    /**\n     *\n     */\n    // function setGlobalDebtCeiling(uint256 _amount) public { setGlobalDebtCeiling(vat(), _amount); }\n    /**\n     * @dev Set the global debt ceiling. Amount will be converted to the correct internal precision.\n     * @param _amount The amount to set in DAI (ex. 10m DAI amount == 10000000)\n     */\n    function setGlobalDebtCeiling(uint256 _amount) public {\n        require(_amount < WAD); // \"LibDssExec/incorrect-global-Line-precision\"\n        setValue(vat(), \"Line\", _amount * RAD);\n    }\n    /**\n     * @dev Increase the global debt ceiling by a specific amount. Amount will be converted to the correct internal precision.\n     * @param _amount The amount to add in DAI (ex. 10m DAI amount == 10000000)\n     */\n\n    function increaseGlobalDebtCeiling(uint256 _amount) public {\n        require(_amount < WAD); // \"LibDssExec/incorrect-Line-increase-precision\"\n        address _vat = vat();\n        setValue(_vat, \"Line\", add(DssVat(_vat).Line(), _amount * RAD));\n    }\n    /**\n     * @dev Decrease the global debt ceiling by a specific amount. Amount will be converted to the correct internal precision.\n     * @param _amount The amount to reduce in DAI (ex. 10m DAI amount == 10000000)\n     */\n\n    function decreaseGlobalDebtCeiling(uint256 _amount) public {\n        require(_amount < WAD); // \"LibDssExec/incorrect-Line-decrease-precision\"\n        address _vat = vat();\n        setValue(_vat, \"Line\", sub(DssVat(_vat).Line(), _amount * RAD));\n    }\n    /**\n     * @dev Set the Dai Savings Rate. See: docs/rates.txt\n     * @param _rate   The accumulated rate (ex. 4% => 1000000001243680656318820312)\n     * @param _doDrip `true` to accumulate interest owed\n     */\n\n    function setDSR(uint256 _rate, bool _doDrip) public {\n        require((_rate >= RAY) && (_rate <= RATES_ONE_HUNDRED_PCT)); // \"LibDssExec/dsr-out-of-bounds\"\n        if (_doDrip) {\n            Drippable(pot()).drip();\n        }\n        setValue(pot(), \"dsr\", _rate);\n    }\n    /**\n     * @dev Set the DAI amount for system surplus auctions. Amount will be converted to the correct internal precision.\n     * @param _amount The amount to set in DAI (ex. 10m DAI amount == 10000000)\n     */\n\n    function setSurplusAuctionAmount(uint256 _amount) public {\n        require(_amount < WAD); // \"LibDssExec/incorrect-vow-bump-precision\"\n        setValue(vow(), \"bump\", _amount * RAD);\n    }\n    /**\n     * @dev Set the DAI amount for system surplus buffer, must be exceeded before surplus auctions start. Amount will be converted to the correct internal precision.\n     * @param _amount The amount to set in DAI (ex. 10m DAI amount == 10000000)\n     */\n\n    function setSurplusBuffer(uint256 _amount) public {\n        require(_amount < WAD); // \"LibDssExec/incorrect-vow-hump-precision\"\n        setValue(vow(), \"hump\", _amount * RAD);\n    }\n    /**\n     * @dev Set minimum bid increase for surplus auctions. Amount will be converted to the correct internal precision.\n     * @dev Equation used for conversion is (1 + pct / 10,000) * WAD\n     * @param _pct_bps The pct, in basis points, to set in integer form (x100). (ex. 5% = 5 * 100 = 500)\n     */\n\n    function setMinSurplusAuctionBidIncrease(uint256 _pct_bps) public {\n        require(_pct_bps < BPS_ONE_HUNDRED_PCT); // \"LibDssExec/incorrect-flap-beg-precision\"\n        setValue(flap(), \"beg\", add(WAD, wdiv(_pct_bps, BPS_ONE_HUNDRED_PCT)));\n    }\n    /**\n     * @dev Set bid duration for surplus auctions.\n     * @param _duration Amount of time for bids. (in seconds)\n     */\n\n    function setSurplusAuctionBidDuration(uint256 _duration) public {\n        setValue(flap(), \"ttl\", _duration);\n    }\n    /**\n     * @dev Set total auction duration for surplus auctions.\n     * @param _duration Amount of time for auctions. (in seconds)\n     */\n\n    function setSurplusAuctionDuration(uint256 _duration) public {\n        setValue(flap(), \"tau\", _duration);\n    }\n    /**\n     * @dev Set the number of seconds that pass before system debt is auctioned for MKR tokens.\n     * @param _duration Duration in seconds\n     */\n\n    function setDebtAuctionDelay(uint256 _duration) public {\n        setValue(vow(), \"wait\", _duration);\n    }\n    /**\n     * @dev Set the DAI amount for system debt to be covered by each debt auction. Amount will be converted to the correct internal precision.\n     * @param _amount The amount to set in DAI (ex. 10m DAI amount == 10000000)\n     */\n\n    function setDebtAuctionDAIAmount(uint256 _amount) public {\n        require(_amount < WAD); // \"LibDssExec/incorrect-vow-sump-precision\"\n        setValue(vow(), \"sump\", _amount * RAD);\n    }\n    /**\n     * @dev Set the starting MKR amount to be auctioned off to cover system debt in debt auctions. Amount will be converted to the correct internal precision.\n     * @param _amount The amount to set in MKR (ex. 250 MKR amount == 250)\n     */\n\n    function setDebtAuctionMKRAmount(uint256 _amount) public {\n        require(_amount < WAD); // \"LibDssExec/incorrect-vow-dump-precision\"\n        setValue(vow(), \"dump\", _amount * WAD);\n    }\n    /**\n     * @dev Set minimum bid increase for debt auctions. Amount will be converted to the correct internal precision.\n     * @dev Equation used for conversion is (1 + pct / 10,000) * WAD\n     * @param _pct_bps    The pct, in basis points, to set in integer form (x100). (ex. 5% = 5 * 100 = 500)\n     */\n\n    function setMinDebtAuctionBidIncrease(uint256 _pct_bps) public {\n        require(_pct_bps < BPS_ONE_HUNDRED_PCT); // \"LibDssExec/incorrect-flap-beg-precision\"\n        setValue(flop(), \"beg\", add(WAD, wdiv(_pct_bps, BPS_ONE_HUNDRED_PCT)));\n    }\n    /**\n     * @dev Set bid duration for debt auctions.\n     * @param _duration Amount of time for bids.\n     */\n\n    function setDebtAuctionBidDuration(uint256 _duration) public {\n        setValue(flop(), \"ttl\", _duration);\n    }\n    /**\n     * @dev Set total auction duration for debt auctions.\n     * @param _duration Amount of time for auctions.\n     */\n\n    function setDebtAuctionDuration(uint256 _duration) public {\n        setValue(flop(), \"tau\", _duration);\n    }\n    /**\n     * @dev Set the rate of increasing amount of MKR out for auction during debt auctions. Amount will be converted to the correct internal precision.\n     * @dev MKR amount is increased by this rate every \"tick\" (if auction duration has passed and no one has bid on the MKR)\n     * @dev Equation used for conversion is (1 + pct / 10,000) * WAD\n     * @param _pct_bps    The pct, in basis points, to set in integer form (x100). (ex. 5% = 5 * 100 = 500)\n     */\n\n    function setDebtAuctionMKRIncreaseRate(uint256 _pct_bps) public {\n        setValue(flop(), \"pad\", add(WAD, wdiv(_pct_bps, BPS_ONE_HUNDRED_PCT)));\n    }\n    /**\n     * @dev Set the maximum total DAI amount that can be out for liquidation in the system at any point. Amount will be converted to the correct internal precision.\n     * @param _amount The amount to set in DAI (ex. 250,000 DAI amount == 250000)\n     */\n\n    function setMaxTotalDAILiquidationAmount(uint256 _amount) public {\n        require(_amount < WAD); // \"LibDssExec/incorrect-dog-Hole-precision\"\n        setValue(dog(), \"Hole\", _amount * RAD);\n    }\n    /**\n     * @dev (LIQ 1.2) Set the maximum total DAI amount that can be out for liquidation in the system at any point. Amount will be converted to the correct internal precision.\n     * @param _amount The amount to set in DAI (ex. 250,000 DAI amount == 250000)\n     */\n\n    function setMaxTotalDAILiquidationAmountLEGACY(uint256 _amount) public {\n        require(_amount < WAD); // \"LibDssExec/incorrect-cat-box-amount\"\n        setValue(cat(), \"box\", _amount * RAD);\n    }\n    /**\n     * @dev Set the duration of time that has to pass during emergency shutdown before collateral can start being claimed by DAI holders.\n     * @param _duration Time in seconds to set for ES processing time\n     */\n\n    function setEmergencyShutdownProcessingTime(uint256 _duration) public {\n        setValue(end(), \"wait\", _duration);\n    }\n    /**\n     * @dev Set the global stability fee (is not typically used, currently is 0).\n     * Many of the settings that change weekly rely on the rate accumulator\n     * described at https://docs.makerdao.com/smart-contract-modules/rates-module\n     * To check this yourself, use the following rate calculation (example 8%):\n     *\n     * $ bc -l <<< 'scale=27; e( l(1.08)/(60 * 60 * 24 * 365) )'\n     *\n     * A table of rates can also be found at:\n     * https://ipfs.io/ipfs/QmefQMseb3AiTapiAKKexdKHig8wroKuZbmLtPLv4u2YwW\n     * @param _rate   The accumulated rate (ex. 4% => 1000000001243680656318820312)\n     */\n\n    function setGlobalStabilityFee(uint256 _rate) public {\n        require((_rate >= RAY) && (_rate <= RATES_ONE_HUNDRED_PCT)); // \"LibDssExec/global-stability-fee-out-of-bounds\"\n        setValue(jug(), \"base\", _rate);\n    }\n    /**\n     * @dev Set the value of DAI in the reference asset (e.g. $1 per DAI). Value will be converted to the correct internal precision.\n     * @dev Equation used for conversion is value * RAY / 1000\n     * @param _value The value to set as integer (x1000) (ex. $1.025 == 1025)\n     */\n\n    function setDAIReferenceValue(uint256 _value) public {\n        require(_value < WAD); // \"LibDssExec/incorrect-par-precision\"\n        setValue(spotter(), \"par\", rdiv(_value, 1000));\n    }\n\n    /**\n     *\n     */\n    /**\n     * Collateral Management **\n     */\n    /**\n     *\n     */\n    /**\n     * @dev Set a collateral debt ceiling. Amount will be converted to the correct internal precision.\n     * @param _ilk    The ilk to update (ex. bytes32(\"ETH-A\"))\n     * @param _amount The amount to set in DAI (ex. 10m DAI amount == 10000000)\n     */\n    function setIlkDebtCeiling(bytes32 _ilk, uint256 _amount) public {\n        require(_amount < WAD); // \"LibDssExec/incorrect-ilk-line-precision\"\n        setValue(vat(), _ilk, \"line\", _amount * RAD);\n    }\n    /**\n     * @dev Increase a collateral debt ceiling. Amount will be converted to the correct internal precision.\n     * @param _ilk    The ilk to update (ex. bytes32(\"ETH-A\"))\n     * @param _amount The amount to increase in DAI (ex. 10m DAI amount == 10000000)\n     * @param _global If true, increases the global debt ceiling by _amount\n     */\n\n    function increaseIlkDebtCeiling(bytes32 _ilk, uint256 _amount, bool _global) public {\n        require(_amount < WAD); // \"LibDssExec/incorrect-ilk-line-precision\"\n        address _vat = vat();\n        (,,, uint256 line_,) = DssVat(_vat).ilks(_ilk);\n        setValue(_vat, _ilk, \"line\", add(line_, _amount * RAD));\n        if (_global) {\n            increaseGlobalDebtCeiling(_amount);\n        }\n    }\n    /**\n     * @dev Decrease a collateral debt ceiling. Amount will be converted to the correct internal precision.\n     * @param _ilk    The ilk to update (ex. bytes32(\"ETH-A\"))\n     * @param _amount The amount to decrease in DAI (ex. 10m DAI amount == 10000000)\n     * @param _global If true, decreases the global debt ceiling by _amount\n     */\n\n    function decreaseIlkDebtCeiling(bytes32 _ilk, uint256 _amount, bool _global) public {\n        require(_amount < WAD); // \"LibDssExec/incorrect-ilk-line-precision\"\n        address _vat = vat();\n        (,,, uint256 line_,) = DssVat(_vat).ilks(_ilk);\n        setValue(_vat, _ilk, \"line\", sub(line_, _amount * RAD));\n        if (_global) {\n            decreaseGlobalDebtCeiling(_amount);\n        }\n    }\n    /**\n     * @dev Set the parameters for an ilk in the \"MCD_IAM_AUTO_LINE\" auto-line\n     * @param _ilk    The ilk to update (ex. bytes32(\"ETH-A\"))\n     * @param _amount The Maximum value (ex. 100m DAI amount == 100000000)\n     * @param _gap    The amount of Dai per step (ex. 5m Dai == 5000000)\n     * @param _ttl    The amount of time (in seconds)\n     */\n\n    function setIlkAutoLineParameters(bytes32 _ilk, uint256 _amount, uint256 _gap, uint256 _ttl) public {\n        require(_amount < WAD); // \"LibDssExec/incorrect-auto-line-amount-precision\"\n        require(_gap < WAD); // \"LibDssExec/incorrect-auto-line-gap-precision\"\n        IAMLike(autoLine()).setIlk(_ilk, _amount * RAD, _gap * RAD, _ttl);\n    }\n    /**\n     * @dev Set the debt ceiling for an ilk in the \"MCD_IAM_AUTO_LINE\" auto-line without updating the time values\n     * @param _ilk    The ilk to update (ex. bytes32(\"ETH-A\"))\n     * @param _amount The Maximum value (ex. 100m DAI amount == 100000000)\n     */\n\n    function setIlkAutoLineDebtCeiling(bytes32 _ilk, uint256 _amount) public {\n        address _autoLine = autoLine();\n        (, uint256 gap, uint48 ttl,,) = IAMLike(_autoLine).ilks(_ilk);\n        require(gap != 0 && ttl != 0); // \"LibDssExec/auto-line-not-configured\"\n        IAMLike(_autoLine).setIlk(_ilk, _amount * RAD, uint256(gap), uint256(ttl));\n    }\n    /**\n     * @dev Remove an ilk in the \"MCD_IAM_AUTO_LINE\" auto-line\n     * @param _ilk    The ilk to remove (ex. bytes32(\"ETH-A\"))\n     */\n\n    function removeIlkFromAutoLine(bytes32 _ilk) public {\n        IAMLike(autoLine()).remIlk(_ilk);\n    }\n    /**\n     * @dev Set a collateral minimum vault amount. Amount will be converted to the correct internal precision.\n     * @param _ilk    The ilk to update (ex. bytes32(\"ETH-A\"))\n     * @param _amount The amount to set in DAI (ex. 10m DAI amount == 10000000)\n     */\n\n    function setIlkMinVaultAmount(bytes32 _ilk, uint256 _amount) public {\n        require(_amount < WAD); // \"LibDssExec/incorrect-ilk-dust-precision\"\n        setValue(vat(), _ilk, \"dust\", _amount * RAD);\n        (bool ok,) = clip(_ilk).call(abi.encodeWithSignature(\"upchost()\"));\n        ok;\n    }\n    /**\n     * @dev Set a collateral liquidation penalty. Amount will be converted to the correct internal precision.\n     * @dev Equation used for conversion is (1 + pct / 10,000) * WAD\n     * @param _ilk    The ilk to update (ex. bytes32(\"ETH-A\"))\n     * @param _pct_bps    The pct, in basis points, to set in integer form (x100). (ex. 10.25% = 10.25 * 100 = 1025)\n     */\n\n    function setIlkLiquidationPenalty(bytes32 _ilk, uint256 _pct_bps) public {\n        require(_pct_bps < BPS_ONE_HUNDRED_PCT); // \"LibDssExec/incorrect-ilk-chop-precision\"\n        setValue(dog(), _ilk, \"chop\", add(WAD, wdiv(_pct_bps, BPS_ONE_HUNDRED_PCT)));\n        (bool ok,) = clip(_ilk).call(abi.encodeWithSignature(\"upchost()\"));\n        ok;\n    }\n    /**\n     * @dev Set max DAI amount for liquidation per vault for collateral. Amount will be converted to the correct internal precision.\n     * @param _ilk    The ilk to update (ex. bytes32(\"ETH-A\"))\n     * @param _amount The amount to set in DAI (ex. 10m DAI amount == 10000000)\n     */\n\n    function setIlkMaxLiquidationAmount(bytes32 _ilk, uint256 _amount) public {\n        require(_amount < WAD); // \"LibDssExec/incorrect-ilk-hole-precision\"\n        setValue(dog(), _ilk, \"hole\", _amount * RAD);\n    }\n    /**\n     * @dev Set a collateral liquidation ratio. Amount will be converted to the correct internal precision.\n     * @dev Equation used for conversion is pct * RAY / 10,000\n     * @param _ilk    The ilk to update (ex. bytes32(\"ETH-A\"))\n     * @param _pct_bps    The pct, in basis points, to set in integer form (x100). (ex. 150% = 150 * 100 = 15000)\n     */\n\n    function setIlkLiquidationRatio(bytes32 _ilk, uint256 _pct_bps) public {\n        require(_pct_bps < 10 * BPS_ONE_HUNDRED_PCT); // \"LibDssExec/incorrect-ilk-mat-precision\" // Fails if pct >= 1000%\n        require(_pct_bps >= BPS_ONE_HUNDRED_PCT); // the liquidation ratio has to be bigger or equal to 100%\n        setValue(spotter(), _ilk, \"mat\", rdiv(_pct_bps, BPS_ONE_HUNDRED_PCT));\n    }\n    /**\n     * @dev Set an auction starting multiplier. Amount will be converted to the correct internal precision.\n     * @dev Equation used for conversion is pct * RAY / 10,000\n     * @param _ilk      The ilk to update (ex. bytes32(\"ETH-A\"))\n     * @param _pct_bps  The pct, in basis points, to set in integer form (x100). (ex. 1.3x starting multiplier = 130% = 13000)\n     */\n\n    function setStartingPriceMultiplicativeFactor(bytes32 _ilk, uint256 _pct_bps) public {\n        require(_pct_bps < 10 * BPS_ONE_HUNDRED_PCT); // \"LibDssExec/incorrect-ilk-mat-precision\" // Fails if gt 10x\n        require(_pct_bps >= BPS_ONE_HUNDRED_PCT); // fail if start price is less than OSM price\n        setValue(clip(_ilk), \"buf\", rdiv(_pct_bps, BPS_ONE_HUNDRED_PCT));\n    }\n\n    /**\n     * @dev Set the amount of time before an auction resets.\n     * @param _ilk      The ilk to update (ex. bytes32(\"ETH-A\"))\n     * @param _duration Amount of time before auction resets (in seconds).\n     */\n    function setAuctionTimeBeforeReset(bytes32 _ilk, uint256 _duration) public {\n        setValue(clip(_ilk), \"tail\", _duration);\n    }\n\n    /**\n     * @dev Percentage drop permitted before auction reset\n     * @param _ilk     The ilk to update (ex. bytes32(\"ETH-A\"))\n     * @param _pct_bps The pct, in basis points, of drop to permit (x100).\n     */\n    function setAuctionPermittedDrop(bytes32 _ilk, uint256 _pct_bps) public {\n        require(_pct_bps < BPS_ONE_HUNDRED_PCT); // \"LibDssExec/incorrect-clip-cusp-value\"\n        setValue(clip(_ilk), \"cusp\", rdiv(_pct_bps, BPS_ONE_HUNDRED_PCT));\n    }\n\n    /**\n     * @dev Percentage of tab to suck from vow to incentivize keepers. Amount will be converted to the correct internal precision.\n     * @param _ilk     The ilk to update (ex. bytes32(\"ETH-A\"))\n     * @param _pct_bps The pct, in basis points, of the tab to suck. (0.01% == 1)\n     */\n    function setKeeperIncentivePercent(bytes32 _ilk, uint256 _pct_bps) public {\n        require(_pct_bps < BPS_ONE_HUNDRED_PCT); // \"LibDssExec/incorrect-clip-chip-precision\"\n        setValue(clip(_ilk), \"chip\", wdiv(_pct_bps, BPS_ONE_HUNDRED_PCT));\n    }\n\n    /**\n     * @dev Set max DAI amount for flat rate keeper incentive. Amount will be converted to the correct internal precision.\n     * @param _ilk    The ilk to update (ex. bytes32(\"ETH-A\"))\n     * @param _amount The amount to set in DAI (ex. 1000 DAI amount == 1000)\n     */\n    function setKeeperIncentiveFlatRate(bytes32 _ilk, uint256 _amount) public {\n        require(_amount < WAD); // \"LibDssExec/incorrect-clip-tip-precision\"\n        setValue(clip(_ilk), \"tip\", _amount * RAD);\n    }\n\n    /**\n     * @dev Sets the circuit breaker price tolerance in the clipper mom.\n     * This is somewhat counter-intuitive,\n     * to accept a 25% price drop, use a value of 75%\n     * @param _clip    The clipper to set the tolerance for\n     * @param _pct_bps The pct, in basis points, to set in integer form (x100). (ex. 5% = 5 * 100 = 500)\n     */\n    function setLiquidationBreakerPriceTolerance(address _clip, uint256 _pct_bps) public {\n        require(_pct_bps < BPS_ONE_HUNDRED_PCT); // \"LibDssExec/incorrect-clippermom-price-tolerance\"\n        MomLike(clipperMom()).setPriceTolerance(_clip, rdiv(_pct_bps, BPS_ONE_HUNDRED_PCT));\n    }\n\n    /**\n     * @dev Set the stability fee for a given ilk.\n     * Many of the settings that change weekly rely on the rate accumulator\n     * described at https://docs.makerdao.com/smart-contract-modules/rates-module\n     * To check this yourself, use the following rate calculation (example 8%):\n     *\n     * $ bc -l <<< 'scale=27; e( l(1.08)/(60 * 60 * 24 * 365) )'\n     *\n     * A table of rates can also be found at:\n     * https://ipfs.io/ipfs/QmefQMseb3AiTapiAKKexdKHig8wroKuZbmLtPLv4u2YwW\n     *\n     * @param _ilk    The ilk to update (ex. bytes32(\"ETH-A\") )\n     * @param _rate   The accumulated rate (ex. 4% => 1000000001243680656318820312)\n     * @param _doDrip `true` to accumulate stability fees for the collateral\n     */\n    function setIlkStabilityFee(bytes32 _ilk, uint256 _rate, bool _doDrip) public {\n        require((_rate >= RAY) && (_rate <= RATES_ONE_HUNDRED_PCT)); // \"LibDssExec/ilk-stability-fee-out-of-bounds\"\n        address _jug = jug();\n        if (_doDrip) {\n            Drippable(_jug).drip(_ilk);\n        }\n\n        setValue(_jug, _ilk, \"duty\", _rate);\n    }\n\n    /**\n     *\n     */\n    /**\n     * Abacus Management **\n     */\n    /**\n     *\n     */\n\n    /**\n     * @dev Set the number of seconds from the start when the auction reaches zero price.\n     * @dev Abacus:LinearDecrease only.\n     * @param _calc     The address of the LinearDecrease pricing contract\n     * @param _duration Amount of time for auctions.\n     */\n    function setLinearDecrease(address _calc, uint256 _duration) public {\n        setValue(_calc, \"tau\", _duration);\n    }\n\n    /**\n     * @dev Set the number of seconds for each price step.\n     * @dev Abacus:StairstepExponentialDecrease only.\n     * @param _calc     The address of the StairstepExponentialDecrease pricing contract\n     * @param _duration Length of time between price drops [seconds]\n     * @param _pct_bps Per-step multiplicative factor in basis points. (ex. 99% == 9900)\n     */\n    function setStairstepExponentialDecrease(address _calc, uint256 _duration, uint256 _pct_bps) public {\n        require(_pct_bps < BPS_ONE_HUNDRED_PCT); // DssExecLib/cut-too-high\n        setValue(_calc, \"cut\", rdiv(_pct_bps, BPS_ONE_HUNDRED_PCT));\n        setValue(_calc, \"step\", _duration);\n    }\n    /**\n     * @dev Set the number of seconds for each price step. (99% cut = 1% price drop per step)\n     * Amounts will be converted to the correct internal precision.\n     * @dev Abacus:ExponentialDecrease only\n     * @param _calc     The address of the ExponentialDecrease pricing contract\n     * @param _pct_bps Per-step multiplicative factor in basis points. (ex. 99% == 9900)\n     */\n\n    function setExponentialDecrease(address _calc, uint256 _pct_bps) public {\n        require(_pct_bps < BPS_ONE_HUNDRED_PCT); // DssExecLib/cut-too-high\n        setValue(_calc, \"cut\", rdiv(_pct_bps, BPS_ONE_HUNDRED_PCT));\n    }\n\n    /**\n     *\n     */\n    /**\n     * Oracle Management **\n     */\n    /**\n     *\n     */\n    /**\n     * @dev Allows an oracle to read prices from its source feeds\n     * @param _oracle  An OSM or LP oracle contract\n     */\n    function whitelistOracleMedians(address _oracle) public {\n        (bool ok, bytes memory data) = _oracle.call(abi.encodeWithSignature(\"orb0()\"));\n        if (ok) {\n            // Token is an LP oracle\n            address median0 = abi.decode(data, (address));\n            addReaderToWhitelistCall(median0, _oracle);\n            addReaderToWhitelistCall(OracleLike(_oracle).orb1(), _oracle);\n        } else {\n            // Standard OSM\n            addReaderToWhitelistCall(OracleLike(_oracle).src(), _oracle);\n        }\n    }\n    /**\n     * @dev Adds an address to the OSM or Median's reader whitelist, allowing the address to read prices.\n     * @param _oracle        Oracle Security Module (OSM) or Median core contract address\n     * @param _reader     Address to add to whitelist\n     */\n\n    function addReaderToWhitelist(address _oracle, address _reader) public {\n        OracleLike(_oracle).kiss(_reader);\n    }\n    /**\n     * @dev Removes an address to the OSM or Median's reader whitelist, disallowing the address to read prices.\n     * @param _oracle     Oracle Security Module (OSM) or Median core contract address\n     * @param _reader     Address to remove from whitelist\n     */\n\n    function removeReaderFromWhitelist(address _oracle, address _reader) public {\n        OracleLike(_oracle).diss(_reader);\n    }\n    /**\n     * @dev Adds an address to the OSM or Median's reader whitelist, allowing the address to read prices.\n     * @param _oracle  OSM or Median core contract address\n     * @param _reader  Address to add to whitelist\n     */\n\n    function addReaderToWhitelistCall(address _oracle, address _reader) public {\n        (bool ok,) = _oracle.call(abi.encodeWithSignature(\"kiss(address)\", _reader));\n        ok;\n    }\n    /**\n     * @dev Removes an address to the OSM or Median's reader whitelist, disallowing the address to read prices.\n     * @param _oracle  Oracle Security Module (OSM) or Median core contract address\n     * @param _reader  Address to remove from whitelist\n     */\n\n    function removeReaderFromWhitelistCall(address _oracle, address _reader) public {\n        (bool ok,) = _oracle.call(abi.encodeWithSignature(\"diss(address)\", _reader));\n        ok;\n    }\n    /**\n     * @dev Sets the minimum number of valid messages from whitelisted oracle feeds needed to update median price.\n     * @param _median     Median core contract address\n     * @param _minQuorum  Minimum number of valid messages from whitelisted oracle feeds needed to update median price (NOTE: MUST BE ODD NUMBER)\n     */\n\n    function setMedianWritersQuorum(address _median, uint256 _minQuorum) public {\n        OracleLike(_median).setBar(_minQuorum);\n    }\n    /**\n     * @dev Add OSM address to OSM mom, allowing it to be frozen by governance.\n     * @param _osm        Oracle Security Module (OSM) core contract address\n     * @param _ilk        Collateral type using OSM\n     */\n\n    function allowOSMFreeze(address _osm, bytes32 _ilk) public {\n        MomLike(osmMom()).setOsm(_ilk, _osm);\n    }\n\n    /**\n     *\n     */\n    /**\n     * Collateral Onboarding **\n     */\n    /**\n     *\n     */\n\n    /**\n     * @dev Performs basic functions and sanity checks to add a new collateral type to the MCD system\n     * @param _ilk      Collateral type key code [Ex. \"ETH-A\"]\n     * @param _gem      Address of token contract\n     * @param _join     Address of join adapter\n     * @param _clip     Address of liquidation agent\n     * @param _calc     Address of the pricing function\n     * @param _pip      Address of price feed\n     */\n    function addCollateralBase(bytes32 _ilk, address _gem, address _join, address _clip, address _calc, address _pip)\n        public\n    {\n        // Sanity checks\n        address _vat = vat();\n        address _dog = dog();\n        address _spotter = spotter();\n        require(JoinLike(_join).vat() == _vat); // \"join-vat-not-match\"\n        require(JoinLike(_join).ilk() == _ilk); // \"join-ilk-not-match\"\n        require(JoinLike(_join).gem() == _gem); // \"join-gem-not-match\"\n        require(JoinLike(_join).dec() == ERC20(_gem).decimals()); // \"join-dec-not-match\"\n        require(ClipLike(_clip).vat() == _vat); // \"clip-vat-not-match\"\n        require(ClipLike(_clip).dog() == _dog); // \"clip-dog-not-match\"\n        require(ClipLike(_clip).ilk() == _ilk); // \"clip-ilk-not-match\"\n        require(ClipLike(_clip).spotter() == _spotter); // \"clip-ilk-not-match\"\n\n        // Set the token PIP in the Spotter\n        setContract(spotter(), _ilk, \"pip\", _pip);\n\n        // Set the ilk Clipper in the Dog\n        setContract(_dog, _ilk, \"clip\", _clip);\n        // Set vow in the clip\n        setContract(_clip, \"vow\", vow());\n        // Set the pricing function for the Clipper\n        setContract(_clip, \"calc\", _calc);\n\n        // Init ilk in Vat & Jug\n        Initializable(_vat).init(_ilk); // Vat\n        Initializable(jug()).init(_ilk); // Jug\n\n        // Allow ilk Join to modify Vat registry\n        authorize(_vat, _join);\n        // Allow ilk Join to suck dai for keepers\n        authorize(_vat, _clip);\n        // Allow the ilk Clipper to reduce the Dog hole on deal()\n        authorize(_dog, _clip);\n        // Allow Dog to kick auctions in ilk Clipper\n        authorize(_clip, _dog);\n        // Allow End to yank auctions in ilk Clipper\n        authorize(_clip, end());\n        // Authorize the ESM to execute in the clipper\n        authorize(_clip, esm());\n\n        // Add new ilk to the IlkRegistry\n        RegistryLike(reg()).add(_join);\n    }\n\n    // Complete collateral onboarding logic.\n    function addNewCollateral(CollateralOpts memory co) public {\n        // Add the collateral to the system.\n        addCollateralBase(co.ilk, co.gem, co.join, co.clip, co.calc, co.pip);\n        address clipperMom_ = clipperMom();\n\n        if (!co.isLiquidatable) {\n            // Disallow Dog to kick auctions in ilk Clipper\n            setValue(co.clip, \"stopped\", 3);\n        } else {\n            // Grant ClipperMom access to the ilk Clipper\n            authorize(co.clip, clipperMom_);\n        }\n\n        if (co.isOSM) {\n            // If pip == OSM\n            // Allow OsmMom to access to the TOKEN OSM\n            authorize(co.pip, osmMom());\n            if (co.whitelistOSM) {\n                // If median is src in OSM\n                // Whitelist OSM to read the Median data (only necessary if it is the first time the token is being added to an ilk)\n                whitelistOracleMedians(co.pip);\n            }\n            // Whitelist Spotter to read the OSM data (only necessary if it is the first time the token is being added to an ilk)\n            addReaderToWhitelist(co.pip, spotter());\n            // Whitelist Clipper on pip\n            addReaderToWhitelist(co.pip, co.clip);\n            // Allow the clippermom to access the feed\n            addReaderToWhitelist(co.pip, clipperMom_);\n            // Whitelist End to read the OSM data (only necessary if it is the first time the token is being added to an ilk)\n            addReaderToWhitelist(co.pip, end());\n            // Set TOKEN OSM in the OsmMom for new ilk\n            allowOSMFreeze(co.pip, co.ilk);\n        }\n        // Increase the global debt ceiling by the ilk ceiling\n        increaseGlobalDebtCeiling(co.ilkDebtCeiling);\n        // Set the ilk debt ceiling\n        setIlkDebtCeiling(co.ilk, co.ilkDebtCeiling);\n        // Set the ilk dust\n        setIlkMinVaultAmount(co.ilk, co.minVaultAmount);\n        // Set the hole size\n        setIlkMaxLiquidationAmount(co.ilk, co.maxLiquidationAmount);\n        // Set the ilk liquidation penalty\n        setIlkLiquidationPenalty(co.ilk, co.liquidationPenalty);\n\n        // Set the ilk stability fee\n        setIlkStabilityFee(co.ilk, co.ilkStabilityFee, true);\n\n        // Set the auction starting price multiplier\n        setStartingPriceMultiplicativeFactor(co.ilk, co.startingPriceFactor);\n\n        // Set the amount of time before an auction resets.\n        setAuctionTimeBeforeReset(co.ilk, co.auctionDuration);\n\n        // Set the allowed auction drop percentage before reset\n        setAuctionPermittedDrop(co.ilk, co.permittedDrop);\n\n        // Set the ilk min collateralization ratio\n        setIlkLiquidationRatio(co.ilk, co.liquidationRatio);\n\n        // Set the price tolerance in the liquidation circuit breaker\n        setLiquidationBreakerPriceTolerance(co.clip, co.breakerTolerance);\n\n        // Set a flat rate for the keeper reward\n        setKeeperIncentiveFlatRate(co.ilk, co.kprFlatReward);\n\n        // Set the percentage of liquidation as keeper award\n        setKeeperIncentivePercent(co.ilk, co.kprPctReward);\n\n        // Update ilk spot value in Vat\n        updateCollateralPrice(co.ilk);\n    }\n\n    /**\n     *\n     */\n    /**\n     * Payment **\n     */\n    /**\n     *\n     */\n    /**\n     * @dev Send a payment in ERC20 DAI from the surplus buffer.\n     * @param _target The target address to send the DAI to.\n     * @param _amount The amount to send in DAI (ex. 10m DAI amount == 10000000)\n     */\n    function sendPaymentFromSurplusBuffer(address _target, uint256 _amount) public {\n        require(_amount < WAD); // \"LibDssExec/incorrect-ilk-line-precision\"\n        DssVat(vat()).suck(vow(), address(this), _amount * RAD);\n        JoinLike(daiJoin()).exit(_target, _amount * WAD);\n    }\n\n    /**\n     *\n     */\n    /**\n     * Misc **\n     */\n    /**\n     *\n     */\n    /**\n     * @dev Initiate linear interpolation on an administrative value over time.\n     * @param _name        The label for this lerp instance\n     * @param _target      The target contract\n     * @param _what        The target parameter to adjust\n     * @param _startTime   The time for this lerp\n     * @param _start       The start value for the target parameter\n     * @param _end         The end value for the target parameter\n     * @param _duration    The duration of the interpolation\n     */\n    function linearInterpolation(\n        bytes32 _name,\n        address _target,\n        bytes32 _what,\n        uint256 _startTime,\n        uint256 _start,\n        uint256 _end,\n        uint256 _duration\n    ) public returns (address) {\n        address lerp = LerpFactoryLike(lerpFab()).newLerp(_name, _target, _what, _startTime, _start, _end, _duration);\n        Authorizable(_target).rely(lerp);\n        LerpLike(lerp).tick();\n        return lerp;\n    }\n    /**\n     * @dev Initiate linear interpolation on an administrative value over time.\n     * @param _name        The label for this lerp instance\n     * @param _target      The target contract\n     * @param _ilk         The ilk to target\n     * @param _what        The target parameter to adjust\n     * @param _startTime   The time for this lerp\n     * @param _start       The start value for the target parameter\n     * @param _end         The end value for the target parameter\n     * @param _duration    The duration of the interpolation\n     */\n\n    function linearInterpolation(\n        bytes32 _name,\n        address _target,\n        bytes32 _ilk,\n        bytes32 _what,\n        uint256 _startTime,\n        uint256 _start,\n        uint256 _end,\n        uint256 _duration\n    ) public returns (address) {\n        address lerp = LerpFactoryLike(lerpFab())\n            .newIlkLerp(_name, _target, _ilk, _what, _startTime, _start, _end, _duration);\n        Authorizable(_target).rely(lerp);\n        LerpLike(lerp).tick();\n        return lerp;\n    }\n}\n"
  },
  {
    "path": "testdata/default/fork/ForkSame_1.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract ForkTest is Test {\n    address constant WETH_TOKEN_ADDR = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;\n    uint256 forkA;\n\n    // this will create two _different_ forks during setup\n    function setUp() public {\n        forkA = vm.createFork(\"mainnet\", 15_977_624);\n    }\n\n    function testDummy() public {\n        uint256 balance = WETH_TOKEN_ADDR.balance;\n    }\n}\n"
  },
  {
    "path": "testdata/default/fork/ForkSame_2.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract ForkTest is Test {\n    address constant WETH_TOKEN_ADDR = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;\n    uint256 forkA;\n\n    // this will create two _different_ forks during setup\n    function setUp() public {\n        forkA = vm.createFork(\"mainnet\", 15_977_624);\n    }\n\n    function testDummy() public {\n        uint256 balance = WETH_TOKEN_ADDR.balance;\n    }\n}\n"
  },
  {
    "path": "testdata/default/fork/LaunchFork.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.6.12;\n\nimport \"utils/Test.sol\";\nimport \"./DssExecLib.sol\";\n\ninterface IWETH {\n    function deposit() external payable;\n    function balanceOf(address) external view returns (uint256);\n}\n\n// A minimal contract. We test if it is deployed correctly\ncontract DummyContract {\n    address public deployer;\n\n    constructor() public {\n        deployer = msg.sender;\n    }\n}\n\nabstract contract ForkTest is Test {\n    address constant DAI_TOKEN_ADDR = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\n    address constant WETH_TOKEN_ADDR = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;\n\n    // checks that we can retrieve the fork we launched with\n    function testActiveFork() public {\n        uint256 activeFork = vm.activeFork();\n        // launch fork has id `0`\n        assertEq(activeFork, 0);\n    }\n\n    function testReadState() public {\n        ERC20 DAI = ERC20(DAI_TOKEN_ADDR);\n        assertEq(uint256(DAI.decimals()), uint256(18), \"Failed to read DAI token decimals.\");\n    }\n\n    function testDeployContract() public {\n        DummyContract dummy = new DummyContract();\n        uint256 size;\n        address DummyAddress = address(dummy);\n        assembly {\n            size := extcodesize(DummyAddress)\n        }\n        assertGt(size, 0, \"Deploying dummy contract failed. Deployed size of zero\");\n        assertEq(dummy.deployer(), address(this), \"Calling the Dummy contract failed to return expected value\");\n    }\n\n    function testCheatcode() public {\n        IWETH WETH = IWETH(WETH_TOKEN_ADDR);\n        bytes32 value = bytes32(uint256(1));\n        // \"0x3617319a054d772f909f7c479a2cebe5066e836a939412e32403c99029b92eff\" is the slot storing the balance of zero address for the weth contract\n        // `cast index address uint 0x0000000000000000000000000000000000000000 3`\n        bytes32 zero_address_balance_slot = 0x3617319a054d772f909f7c479a2cebe5066e836a939412e32403c99029b92eff;\n        vm.store(WETH_TOKEN_ADDR, zero_address_balance_slot, value);\n        assertEq(\n            WETH.balanceOf(0x0000000000000000000000000000000000000000),\n            1,\n            \"Cheatcode did not change value at the storage slot.\"\n        );\n    }\n\n    function testPredeployedLibrary() public {\n        assertEq(DssExecLib.dai(), DAI_TOKEN_ADDR, \"Failed to read state from predeployed library\");\n    }\n\n    function testDepositWeth() public {\n        IWETH WETH = IWETH(WETH_TOKEN_ADDR);\n        uint256 current = WETH.balanceOf(address(this));\n        WETH.deposit{value: 1000}();\n        assertEq(WETH.balanceOf(address(this)) - current, 1000, \"WETH balance is not equal to deposited amount.\");\n    }\n}\n\ncontract ForkTestHttp is ForkTest {\n    function setUp() public {\n        vm.createSelectFork(\"mainnet\");\n    }\n}\n"
  },
  {
    "path": "testdata/default/fs/Disabled.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\n// No permissions: all FS operations should revert.\n\n/// forge-config: default.fs_permissions = []\ncontract DisabledAccessTest is Test {\n    function testReadFile() public {\n        string memory path = \"fixtures/File/read.txt\";\n        vm._expectCheatcodeRevert();\n        vm.readFile(path);\n\n        vm._expectCheatcodeRevert();\n        vm.readFileBinary(path);\n    }\n\n    function testReadLine() public {\n        string memory path = \"fixtures/File/read.txt\";\n        vm._expectCheatcodeRevert();\n        vm.readLine(path);\n    }\n\n    function testWriteFile() public {\n        string memory path = \"fixtures/File/ignored/write_file.txt\";\n        string memory data = \"hello writable world\";\n\n        vm._expectCheatcodeRevert();\n        vm.writeFile(path, data);\n\n        vm._expectCheatcodeRevert();\n        vm.writeFileBinary(path, bytes(data));\n    }\n\n    function testWriteLine() public {\n        string memory path = \"fixtures/File/ignored/write_file.txt\";\n        string memory data = \"hello writable world\";\n\n        vm._expectCheatcodeRevert();\n        vm.writeLine(path, data);\n    }\n\n    function testRemoveFile() public {\n        string memory path = \"fixtures/File/ignored/write_file.txt\";\n\n        vm._expectCheatcodeRevert();\n        vm.removeFile(path);\n    }\n}\n"
  },
  {
    "path": "testdata/default/fs/ReadOnly.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\n// Default permissions: only read FS operations should succeed.\n\n/// forge-config: default.fs_permissions = [{ access = \"read\", path = \"./fixtures\"}]\ncontract ReadOnlyAccessTest is Test {\n    function testReadFile() public {\n        string memory path = \"fixtures/File/read.txt\";\n        vm.readFile(path);\n\n        vm.readFileBinary(path);\n    }\n\n    function testReadLine() public {\n        string memory path = \"fixtures/File/read.txt\";\n        vm.readLine(path);\n    }\n\n    function testWriteFile() public {\n        string memory path = \"fixtures/File/ignored/write_file.txt\";\n        string memory data = \"hello writable world\";\n\n        vm._expectCheatcodeRevert();\n        vm.writeFile(path, data);\n\n        vm._expectCheatcodeRevert();\n        vm.writeFileBinary(path, bytes(data));\n    }\n\n    function testWriteLine() public {\n        string memory path = \"fixtures/File/ignored/write_file.txt\";\n        string memory data = \"hello writable world\";\n\n        vm._expectCheatcodeRevert();\n        vm.writeLine(path, data);\n    }\n\n    function testRemoveFile() public {\n        string memory path = \"fixtures/File/ignored/write_file.txt\";\n\n        vm._expectCheatcodeRevert();\n        vm.removeFile(path);\n    }\n}\n"
  },
  {
    "path": "testdata/default/inline/FuzzInlineConf.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract FuzzInlineConf is Test {\n    /**\n     * forge-config: default.fuzz.runs = 1024\n     * forge-config: default.fuzz.max-test-rejects = 500\n     */\n    function testInlineConfFuzz(uint8 x) public {\n        require(true, \"this is not going to revert\");\n    }\n}\n\n/// forge-config: default.fuzz.runs = 10\ncontract FuzzInlineConf2 is Test {\n    /// forge-config: default.fuzz.runs = 1\n    function testInlineConfFuzz1(uint8 x) public {\n        require(true, \"this is not going to revert\");\n    }\n\n    function testInlineConfFuzz2(uint8 x) public {\n        require(true, \"this is not going to revert\");\n    }\n}\n"
  },
  {
    "path": "testdata/default/inline/InvariantInlineConf.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract InvariantBreaker {\n    bool public flag0 = true;\n    bool public flag1 = true;\n\n    function set0(int256 val) public returns (bool) {\n        if (val % 100 == 0) {\n            flag0 = false;\n        }\n        return flag0;\n    }\n\n    function set1(int256 val) public returns (bool) {\n        if (val % 10 == 0 && !flag0) {\n            flag1 = false;\n        }\n        return flag1;\n    }\n}\n\ncontract InvariantInlineConf is Test {\n    InvariantBreaker inv;\n\n    function setUp() public {\n        inv = new InvariantBreaker();\n    }\n\n    /// forge-config: default.invariant.runs = 333\n    /// forge-config: default.invariant.depth = 32\n    /// forge-config: default.invariant.fail-on-revert = false\n    /// forge-config: default.invariant.call-override = true\n    function invariant_neverFalse() public {\n        require(true, \"this is not going to revert\");\n    }\n}\n\ncontract InvariantInlineConf2 is Test {\n    InvariantBreaker inv;\n\n    function setUp() public {\n        inv = new InvariantBreaker();\n    }\n\n    /// forge-config: default.invariant.runs = 42\n    function invariant_neverFalse() public {\n        require(true, \"this is not going to revert\");\n    }\n}\n"
  },
  {
    "path": "testdata/default/linking/cycle/Cycle.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nlibrary Foo {\n    function foo() external {\n        Bar.bar();\n    }\n\n    function flum() external {}\n}\n\nlibrary Bar {\n    function bar() external {\n        Foo.flum();\n    }\n}\n"
  },
  {
    "path": "testdata/default/linking/duplicate/Duplicate.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\n// Linking scenario: contract has many dependencies, some of which appear to the linker\n// more than once.\n//\n// Each library should only have its address computed once\n\nlibrary A {\n    function increment(uint256 number, uint256 number2) external pure returns (uint256) {\n        return number + number2;\n    }\n}\n\nlibrary B {\n    function subtract(uint256 number) external pure returns (uint256) {\n        return number - 1;\n    }\n}\n\nlibrary C {\n    function double(uint256 number) external pure returns (uint256) {\n        return A.increment(number, 0) + A.increment(number, 0);\n    }\n}\n\nlibrary D {\n    function half(uint256 number) external pure returns (uint256) {\n        return number / 2;\n    }\n\n    function sub2(uint256 number) external pure returns (uint256) {\n        return B.subtract(number);\n    }\n}\n\nlibrary E {\n    function pow(uint256 number, uint256 exponent) external pure returns (uint256) {\n        return number ** exponent;\n    }\n\n    function quadruple(uint256 number) external pure returns (uint256) {\n        return C.double(number) + C.double(number);\n    }\n}\n\ncontract LibraryConsumer {\n    uint256 public number;\n\n    function setNumber(uint256 newNumber) public {\n        number = newNumber;\n    }\n\n    function increment() public {\n        number++;\n    }\n\n    function add(uint256 num) external returns (uint256) {\n        number = num;\n        return A.increment(num, 1);\n    }\n\n    function sub(uint256 num) external returns (uint256) {\n        number = num;\n        return B.subtract(num);\n    }\n\n    function mul(uint256 num) external returns (uint256) {\n        number = num;\n        return C.double(num);\n    }\n\n    function div(uint256 num) external returns (uint256) {\n        number = num;\n        return D.half(num);\n    }\n\n    function pow(uint256 num, uint256 exponent) external returns (uint256) {\n        number = num;\n        return E.pow(num, exponent);\n    }\n\n    function sub2(uint256 num) external returns (uint256) {\n        number = num;\n        return D.sub2(num);\n    }\n\n    function quadruple(uint256 num) external returns (uint256) {\n        number = num;\n        return E.quadruple(num);\n    }\n}\n\ncontract DuplicateLibraryLinkingTest is Test {\n    LibraryConsumer consumer;\n\n    function setUp() public {\n        consumer = new LibraryConsumer();\n    }\n\n    function testA() public {\n        assertEq(consumer.add(1), 2, \"library call failed\");\n    }\n\n    function testB() public {\n        consumer.setNumber(1);\n        assertEq(consumer.sub(1), 0, \"library call failed\");\n    }\n\n    function testC() public {\n        consumer.setNumber(2);\n        assertEq(consumer.mul(2), 4, \"library call failed\");\n    }\n\n    function testD() public {\n        consumer.setNumber(2);\n        assertEq(consumer.div(2), 1, \"library call failed\");\n    }\n\n    function testE() public {\n        consumer.setNumber(2);\n        assertEq(consumer.quadruple(2), 8, \"library call failed\");\n    }\n}\n"
  },
  {
    "path": "testdata/default/linking/nested/Nested.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\n// Linking scenario: contract with a library that depends on a library\n\nlibrary Lib {\n    function plus100(uint256 a) public pure returns (uint256) {\n        return a + 100;\n    }\n}\n\nlibrary NestedLib {\n    function nestedPlus100Plus1(uint256 a) public pure returns (uint256) {\n        return Lib.plus100(a) + 1;\n    }\n}\n\ncontract LibraryConsumer {\n    function consume(uint256 a) public pure returns (uint256) {\n        return Lib.plus100(a);\n    }\n\n    function consumeNested(uint256 a) public pure returns (uint256) {\n        return NestedLib.nestedPlus100Plus1(a);\n    }\n}\n\ncontract NestedLibraryLinkingTest is Test {\n    LibraryConsumer consumer;\n\n    function setUp() public {\n        consumer = new LibraryConsumer();\n    }\n\n    function testDirect() public {\n        assertEq(consumer.consume(1), 101, \"library call failed\");\n    }\n\n    function testNested() public {\n        assertEq(consumer.consumeNested(1), 102, \"nested library call failed\");\n    }\n}\n"
  },
  {
    "path": "testdata/default/linking/samefile_union/Libs.sol",
    "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.18;\n\nlibrary LInit {\n    function f() external view returns (uint256) {\n        return block.number;\n    }\n}\n\nlibrary LRun {\n    function g() external view returns (uint256) {\n        return block.timestamp;\n    }\n}\n"
  },
  {
    "path": "testdata/default/linking/samefile_union/SameFileUnion.t.sol",
    "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.18;\n\nimport \"./Libs.sol\";\n\ncontract UsesBoth {\n    uint256 public x;\n\n    constructor() {\n        // used only in creation bytecode\n        x = LInit.f();\n    }\n\n    function y() external view returns (uint256) {\n        // used only in deployed bytecode\n        return LRun.g();\n    }\n}\n"
  },
  {
    "path": "testdata/default/linking/simple/Simple.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\n// Linking scenario: contract with one library\n\nlibrary Lib {\n    function plus100(uint256 a) public pure returns (uint256) {\n        return a + 100;\n    }\n}\n\ncontract LibraryConsumer {\n    function consume(uint256 a) public pure returns (uint256) {\n        return Lib.plus100(a);\n    }\n}\n\ncontract SimpleLibraryLinkingTest is Test {\n    LibraryConsumer consumer;\n\n    function setUp() public {\n        consumer = new LibraryConsumer();\n    }\n\n    function testCall() public {\n        assertEq(consumer.consume(1), 101, \"library call failed\");\n    }\n}\n"
  },
  {
    "path": "testdata/default/repros/Issue10302.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract A {\n    function foo() public pure returns (bool) {\n        return true;\n    }\n}\n\ncontract Issue10302Test is Test {\n    function testDelegateFails() external {\n        vm.createSelectFork(\"sepolia\");\n        A a = new A();\n        vm.startPrank(0x0fe884546476dDd290eC46318785046ef68a0BA9, true);\n        (bool success,) = address(a).delegatecall(abi.encodeWithSelector(A.foo.selector));\n        vm.stopPrank();\n        require(success, \"Delegate call should succeed\");\n    }\n\n    function testDelegatePassesWhenBalanceSetToZero() external {\n        vm.createSelectFork(\"sepolia\");\n        A a = new A();\n        vm.startPrank(0x0fe884546476dDd290eC46318785046ef68a0BA9, true);\n        vm.deal(0x0fe884546476dDd290eC46318785046ef68a0BA9, 0 ether);\n        (bool success,) = address(a).delegatecall(abi.encodeWithSelector(A.foo.selector));\n        vm.stopPrank();\n        require(success, \"Delegate call should succeed\");\n    }\n\n    function testDelegateCallSucceeds() external {\n        vm.createSelectFork(\"sepolia\");\n        A a = new A();\n        vm.startPrank(0xd363339eE47775888Df411A163c586a8BdEA9dbf, true);\n        (bool success,) = address(a).delegatecall(abi.encodeWithSelector(A.foo.selector));\n        vm.stopPrank();\n        require(success, \"Delegate call should succeed\");\n    }\n\n    function testDelegateFailsWhenBalanceGtZero() external {\n        vm.createSelectFork(\"sepolia\");\n        A a = new A();\n        vm.startPrank(0xd363339eE47775888Df411A163c586a8BdEA9dbf, true);\n        vm.deal(0xd363339eE47775888Df411A163c586a8BdEA9dbf, 1 ether);\n        (bool success,) = address(a).delegatecall(abi.encodeWithSelector(A.foo.selector));\n        vm.stopPrank();\n        require(success, \"Delegate call should succeed\");\n    }\n}\n"
  },
  {
    "path": "testdata/default/repros/Issue10477.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract SimpleDelegate {\n    function call(address target, bytes memory data) external returns (bool callResult, bytes memory callData) {\n        (callResult, callData) = target.call(data);\n    }\n}\n\ncontract Counter {\n    uint256 public value = 0;\n\n    function increment() external {\n        value++;\n    }\n}\n\ncontract Issue10477Test is Test {\n    address payable ALICE_ADDRESS = payable(0x70997970C51812dc3A010C7d01b50e0d17dc79C8);\n    uint256 constant ALICE_PK = 0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d;\n\n    function test_reset_delegate_indicator() public {\n        SimpleDelegate delegate = new SimpleDelegate();\n        Counter counter = new Counter();\n\n        vm.startBroadcast(ALICE_PK);\n        vm.signAndAttachDelegation(address(delegate), ALICE_PK);\n        assertTrue(ALICE_ADDRESS.code.length > 0);\n\n        (bool callResult, bytes memory callData) =\n            SimpleDelegate(ALICE_ADDRESS).call(address(counter), abi.encodeCall(Counter.increment, ()));\n\n        assertTrue(callResult);\n        assertTrue(callData.length == 0);\n\n        vm.signAndAttachDelegation(address(0), ALICE_PK);\n\n        // Expected to succeed here\n        assertTrue(ALICE_ADDRESS.code.length == 0);\n        assertTrue(ALICE_ADDRESS.codehash == 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470);\n\n        vm.stopBroadcast();\n    }\n}\n"
  },
  {
    "path": "testdata/default/repros/Issue10527.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract A {\n    event Event1();\n    event Event2();\n\n    function foo() public {\n        emit Event1();\n    }\n\n    function bar() public {\n        emit Event2();\n    }\n}\n\ncontract Issue10527Test is Test {\n    event Event1();\n    event Event2();\n\n    A a;\n\n    function setUp() public {\n        a = new A();\n    }\n\n    function test_foo_Event1() public {\n        vm.expectEmit(address(a));\n        emit Event1();\n\n        a.foo();\n    }\n\n    function test_foo_Event2() public {\n        vm.expectEmit({emitter: address(a), count: 0});\n        emit Event2();\n\n        a.foo();\n    }\n}\n"
  },
  {
    "path": "testdata/default/repros/Issue10552.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract Counter {\n    uint256 public number;\n    uint256 public anotherNumber;\n\n    function setNumber(uint256 newNumber) public {\n        number = newNumber;\n    }\n\n    function setAnotherNumber(uint256 newNumber) public {\n        anotherNumber = newNumber;\n    }\n\n    function increment() public {\n        number++;\n    }\n}\n\ncontract Issue10552Test is Test {\n    Counter public counter;\n    uint256 mainnetId;\n    uint256 opId;\n\n    function setUp() public {\n        counter = new Counter();\n        counter.setNumber(10);\n        vm.makePersistent(address(counter));\n\n        mainnetId = vm.createFork(\"mainnet\");\n        opId = vm.createFork(\"optimism\");\n\n        vm.selectFork(mainnetId);\n        counter.setNumber(100);\n        counter.increment();\n        assertEq(counter.number(), 101);\n\n        counter.increment();\n        assertEq(counter.number(), 102);\n    }\n\n    function test_change_fork_states() public {\n        vm.selectFork(opId);\n        counter.increment();\n        // should account state changes from mainnet fork\n        // without fix for <https://github.com/foundry-rs/foundry/issues/10552> this test was failing with 11 (initial setNumber(10) + one increment) != 103\n        assertEq(counter.number(), 103);\n        counter.setAnotherNumber(11);\n        assertEq(counter.anotherNumber(), 11);\n\n        vm.selectFork(mainnetId);\n        counter.increment();\n        assertEq(counter.number(), 104);\n        assertEq(counter.anotherNumber(), 11);\n    }\n}\n"
  },
  {
    "path": "testdata/default/repros/Issue10586.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract Target is Test {\n    function setChainId() public {\n        vm.chainId(123);\n    }\n}\n\ncontract Issue10586Test is Test {\n    Target public target;\n\n    function setUp() public {\n        target = new Target();\n    }\n\n    function runTest() internal {\n        // By default, the chainId is 31337 during testing.\n        assertEq(block.chainid, 31337);\n\n        // Call external function to set the chainId to 123.\n        target.setChainId();\n\n        // The chainId is set to 123 in the block.\n        assertEq(block.chainid, 123);\n\n        // Set the chainId to 100.\n        vm.chainId(100);\n\n        // The chainId is set to 100 in the block.\n        assertEq(block.chainid, 100);\n\n        // Call the external function again, which will set the chainId to 123.\n        target.setChainId();\n\n        // The last call to chainId() will be the one that is set\n        // in the block, so it should be 123.\n        assertEq(block.chainid, 123);\n    }\n\n    function testGetChainIdAfterSet() public {\n        runTest();\n    }\n\n    /// forge-config: default.isolate = true\n    function testGetChainIdAfterSetIsolated() public {\n        // Previous test failed with the following error:\n        //\n        // [FAIL: EvmError: Revert] testGetChainIdAfterSetIsolated() (gas: 30322)\n        // Traces:\n        // [208460] DefaultTestContract::setUp()\n        //     ├─ [170920] → new Target@0xCe71065D4017F316EC606Fe4422e11eB2c47c246\n        //     │   └─ ← [Return] 743 bytes of code\n        //     └─ ← [Stop]\n        //\n        // [30322] DefaultTestContract::testGetChainIdAfterSetIsolated()\n        //     ├─ [24037] Target::setChainId()\n        //     │   ├─ [0] VM::chainId(123)\n        //     │   │   └─ ← [Return]\n        //     │   └─ ← [Stop]\n        //     ├─ [0] VM::chainId(100)\n        //     │   └─ ← [Return]\n        //     ├─ [0] Target::setChainId()\n        //     │   └─ ← [Revert] EvmError: Revert\n        //     └─ ← [Revert] EvmError: Revert\n        //\n        // Suite result: FAILED. 1 passed; 1 failed; 0 skipped; finished in 2.89ms (1.79ms CPU time)\n\n        runTest();\n    }\n}\n"
  },
  {
    "path": "testdata/default/repros/Issue10957.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\n// https://github.com/foundry-rs/foundry/issues/10957\ncontract Issue10957Test is Test {\n    function testCreateSelectForkBlockNumber() public {\n        // Transaction hash from mainnet <https://etherscan.io/tx/0x2e175897d19307c664815129720c8ac3581da6cb92e4cce923996dd59fbb6ffc>\n        bytes32 txHash = 0x2e175897d19307c664815129720c8ac3581da6cb92e4cce923996dd59fbb6ffc;\n\n        // Expected block number for this transaction\n        uint256 expectedBlockNumber = 22875105;\n\n        // Create fork at the transaction\n        uint256 forkId = vm.createSelectFork(\"mainnet\", txHash);\n\n        // Get the current block number\n        uint256 currentBlock = vm.getBlockNumber();\n\n        // The fork should be at the transaction's block, not one block behind\n        assertEq(currentBlock, expectedBlockNumber, \"Fork should be at the transaction's block number\");\n    }\n}\n"
  },
  {
    "path": "testdata/default/repros/Issue11353.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.24;\n\nimport \"utils/Test.sol\";\n\ncontract Blobhash {\n    function getIndices(uint256[] calldata blobIndices) public view returns (bytes32[] memory) {\n        bytes32[] memory blobHashes = new bytes32[](blobIndices.length);\n        for (uint256 i = 0; i < blobIndices.length; i++) {\n            uint256 blobIndex = blobIndices[i];\n            bytes32 blobHash = blobhash(blobIndex);\n            require(blobHash != 0, \"blob not found\");\n            blobHashes[i] = blobHash;\n        }\n        return blobHashes;\n    }\n}\n\n// https://github.com/foundry-rs/foundry/issues/11353\ncontract Issue11353Test is Test {\n    Blobhash public blobhashContract;\n\n    function setUp() public {\n        blobhashContract = new Blobhash();\n    }\n\n    function test_blobhashes() public {\n        uint256[] memory blobIndices = new uint256[](1);\n        blobIndices[0] = 0;\n\n        bytes32[] memory blobHashes = new bytes32[](1);\n        blobHashes[0] = keccak256(abi.encode(0));\n        vm.blobhashes(blobHashes);\n\n        vm.assertEq(blobhashContract.getIndices(blobIndices), blobHashes);\n    }\n}\n"
  },
  {
    "path": "testdata/default/repros/Issue11616.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.24;\n\nimport \"utils/Test.sol\";\n\ncontract Emit {\n    event A();\n    event B();\n\n    function emitB() public {\n        emit B();\n    }\n}\n\ncontract Issue11616Test is Test {\n    Emit public e;\n\n    function setUp() public {\n        e = new Emit();\n    }\n\n    function test_emitNotOk() public {\n        vm.expectEmit({count: 0});\n        emit Emit.A();\n        vm.expectEmit();\n        emit Emit.B();\n        e.emitB();\n    }\n}\n"
  },
  {
    "path": "testdata/default/repros/Issue12075.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\n// https://github.com/foundry-rs/foundry/issues/12075\ncontract Issue12075Test is Test {\n    address payable internal ALICE = payable(address(0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266));\n    address payable internal BOB = payable(address(0x70997970C51812dc3A010C7d01b50e0d17dc79C8));\n\n    Target internal target;\n\n    function setUp() public virtual {\n        target = new Target();\n\n        vm.deal({account: ALICE, newBalance: 100 ether});\n        vm.startPrank(ALICE);\n    }\n\n    function test_NativeTransfer() public {\n        BOB.transfer(1 ether);\n        assertEq(BOB.balance, 1 ether);\n    }\n\n    function test_PayableFunction() public {\n        target.hit{value: 1 wei}();\n    }\n}\n\ncontract Target {\n    function hit() public payable {}\n}\n"
  },
  {
    "path": "testdata/default/repros/Issue2623.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\n// https://github.com/foundry-rs/foundry/issues/2623\ncontract Issue2623Test is Test {\n    function testRollFork() public {\n        uint256 fork = vm.createFork(\"mainnet\", 10);\n        vm.selectFork(fork);\n\n        assertEq(block.number, 10);\n        assertEq(block.timestamp, 1438270128);\n\n        vm.rollFork(11);\n\n        assertEq(block.number, 11);\n        assertEq(block.timestamp, 1438270136);\n    }\n}\n"
  },
  {
    "path": "testdata/default/repros/Issue2629.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\n// https://github.com/foundry-rs/foundry/issues/2629\ncontract Issue2629Test is Test {\n    function testSelectFork() public {\n        address coinbase = 0x0193d941b50d91BE6567c7eE1C0Fe7AF498b4137;\n\n        uint256 f1 = vm.createSelectFork(\"mainnet\", 9);\n        vm.selectFork(f1);\n\n        assertEq(block.number, 9);\n        assertEq(coinbase.balance, 11250000000000000000);\n\n        uint256 f2 = vm.createFork(\"mainnet\", 10);\n        vm.selectFork(f2);\n\n        assertEq(block.number, 10);\n        assertEq(coinbase.balance, 16250000000000000000);\n    }\n}\n"
  },
  {
    "path": "testdata/default/repros/Issue2723.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\n// https://github.com/foundry-rs/foundry/issues/2723\ncontract Issue2723Test is Test {\n    function testRollFork() public {\n        address coinbase = 0x0193d941b50d91BE6567c7eE1C0Fe7AF498b4137;\n\n        vm.createSelectFork(\"mainnet\", 9);\n\n        assertEq(block.number, 9);\n        assertEq(coinbase.balance, 11250000000000000000);\n\n        vm.rollFork(10);\n\n        assertEq(block.number, 10);\n        assertEq(coinbase.balance, 16250000000000000000);\n    }\n}\n"
  },
  {
    "path": "testdata/default/repros/Issue2898.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\n// https://github.com/foundry-rs/foundry/issues/2898\ncontract Issue2898Test is Test {\n    address private constant BRIDGE = address(10);\n    address private constant BENEFICIARY = address(11);\n\n    function setUp() public {\n        vm.deal(BRIDGE, 100);\n        vm.deal(BENEFICIARY, 99);\n\n        vm.setNonce(BRIDGE, 10);\n    }\n\n    function testDealBalance() public {\n        assertEq(BRIDGE.balance, 100);\n        assertEq(BENEFICIARY.balance, 99);\n    }\n\n    function testSetNonce() public {\n        assertEq(vm.getNonce(BRIDGE), 10);\n    }\n}\n"
  },
  {
    "path": "testdata/default/repros/Issue2956.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\n// https://github.com/foundry-rs/foundry/issues/2956\ncontract Issue2956Test is Test {\n    uint256 fork1;\n    uint256 fork2;\n\n    function setUp() public {\n        fork1 = vm.createFork(\"sepolia\", 5565573);\n        fork2 = vm.createFork(\"avaxTestnet\", 12880747);\n    }\n\n    function testForkNonce() public {\n        address user = address(0xF0959944122fb1ed4CfaBA645eA06EED30427BAA);\n\n        assertEq(vm.getNonce(user), 0);\n        vm.prank(user);\n        new Counter();\n\n        vm.selectFork(fork2);\n        assertEq(vm.getNonce(user), 3);\n        vm.prank(user);\n        new Counter();\n\n        vm.selectFork(fork1);\n        assertEq(vm.getNonce(user), 1);\n        vm.prank(user);\n        new Counter();\n    }\n}\n\ncontract Counter {}\n"
  },
  {
    "path": "testdata/default/repros/Issue2984.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\n// https://github.com/foundry-rs/foundry/issues/2984\ncontract Issue2984Test is Test {\n    uint256 fork;\n    uint256 snapshot;\n\n    function setUp() public {\n        fork = vm.createSelectFork(\"avaxTestnet\", 12880747);\n        snapshot = vm.snapshotState();\n    }\n\n    function testForkRevertSnapshot() public {\n        vm.revertToState(snapshot);\n    }\n\n    function testForkSelectSnapshot() public {\n        uint256 fork2 = vm.createSelectFork(\"avaxTestnet\", 12880749);\n    }\n}\n"
  },
  {
    "path": "testdata/default/repros/Issue3077.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\n// https://github.com/foundry-rs/foundry/issues/3077\nabstract contract ZeroState is Test {\n    // deployer and users\n    address public deployer = vm.addr(1);\n    Token aaveToken;\n    uint256 public mainnetFork;\n\n    function setUp() public virtual {\n        vm.startPrank(deployer);\n        mainnetFork = vm.createFork(\"mainnet\");\n        vm.selectFork(mainnetFork);\n        vm.rollFork(block.number - 20);\n        // deploy tokens\n        aaveToken = new Token();\n        vm.makePersistent(address(aaveToken));\n        vm.stopPrank();\n    }\n}\n\nabstract contract rollfork is ZeroState {\n    function setUp() public virtual override {\n        super.setUp();\n        vm.rollFork(block.number + 1);\n        aaveToken.balanceOf(deployer);\n    }\n}\n\ncontract testing is rollfork {\n    function testFork() public {\n        emit log_uint(block.number);\n    }\n}\n\ncontract Token {\n    mapping(address => uint256) private _balances;\n\n    function balanceOf(address account) public view returns (uint256) {\n        return _balances[account];\n    }\n}\n"
  },
  {
    "path": "testdata/default/repros/Issue3110.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\n// https://github.com/foundry-rs/foundry/issues/3110\nabstract contract ZeroState is Test {\n    // deployer and users\n    address public deployer = vm.addr(1);\n    Token aaveToken;\n    uint256 public mainnetFork;\n\n    function setUp() public virtual {\n        vm.label(deployer, \"Deployer\");\n\n        vm.startPrank(deployer);\n        mainnetFork = vm.createFork(\"mainnet\");\n        vm.selectFork(mainnetFork);\n\n        vm.rollFork(block.number - 20);\n\n        // deploy tokens\n        aaveToken = new Token();\n        vm.makePersistent(address(aaveToken));\n        vm.stopPrank();\n    }\n}\n\nabstract contract TestSate is ZeroState {\n    function setUp() public virtual override {\n        super.setUp();\n        aaveToken.balanceOf(deployer);\n    }\n}\n\ncontract TestFork is TestSate {\n    function testFork() public {\n        vm.rollFork(block.number + 1);\n        emit log_uint(aaveToken.balanceOf(deployer));\n    }\n}\n\ncontract Token {\n    mapping(address => uint256) private _balances;\n\n    function balanceOf(address account) public view returns (uint256) {\n        return _balances[account];\n    }\n}\n"
  },
  {
    "path": "testdata/default/repros/Issue3119.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\n// https://github.com/foundry-rs/foundry/issues/3119\ncontract Issue3119Test is Test {\n    address public owner = vm.addr(1);\n    address public alice = vm.addr(2);\n\n    function testRollFork() public {\n        uint256 fork = vm.createFork(\"mainnet\");\n        vm.selectFork(fork);\n\n        FortressSwap fortressSwap = new FortressSwap(address(owner));\n        vm.prank(owner);\n        fortressSwap.updateOwner(alice);\n    }\n}\n\ncontract FortressSwap {\n    address owner;\n\n    constructor(address _owner) {\n        owner = _owner;\n    }\n\n    function updateOwner(address new_owner) public {\n        require(msg.sender == owner, \"must be owner\");\n        owner = new_owner;\n    }\n}\n"
  },
  {
    "path": "testdata/default/repros/Issue3190.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\n// https://github.com/foundry-rs/foundry/issues/3190\ncontract Issue3190Test is Test {\n    function setUp() public {\n        vm.chainId(99);\n        assertEq(99, block.chainid);\n    }\n\n    function testChainId() public {\n        assertEq(99, block.chainid);\n        vm.chainId(100);\n        assertEq(100, block.chainid);\n    }\n}\n"
  },
  {
    "path": "testdata/default/repros/Issue3192.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\n// https://github.com/foundry-rs/foundry/issues/3192\ncontract Issue3192Test is Test {\n    uint256 fork1;\n    uint256 fork2;\n\n    function setUp() public {\n        fork1 = vm.createFork(\"mainnet\", 7475589);\n        fork2 = vm.createFork(\"mainnet\", 12880747);\n        vm.selectFork(fork1);\n    }\n\n    function testForkSwapSelect() public {\n        assertEq(fork1, vm.activeFork());\n        vm.selectFork(fork2);\n    }\n}\n"
  },
  {
    "path": "testdata/default/repros/Issue3220.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\n// https://github.com/foundry-rs/foundry/issues/3220\ncontract Issue3220Test is Test {\n    IssueRepro repro;\n\n    uint256 fork1;\n    uint256 fork2;\n    uint256 counter;\n\n    function setUp() public {\n        fork1 = vm.createFork(\"mainnet\", 7475589);\n        vm.selectFork(fork1);\n        fork2 = vm.createFork(\"mainnet\", 12880747);\n    }\n\n    function testForkRevert() public {\n        vm.selectFork(fork2);\n\n        repro = new IssueRepro();\n\n        vm.selectFork(fork1);\n\n        // do a bunch of work to increase the revm checkpoint counter\n        for (uint256 i = 0; i < 10; i++) {\n            mockCount();\n        }\n\n        vm.selectFork(fork2);\n\n        vm.expectRevert(\"This fails\");\n        repro.doRevert();\n    }\n\n    function mockCount() public {\n        counter += 1;\n    }\n}\n\ncontract IssueRepro {\n    function doRevert() external {\n        revert(\"This fails\");\n    }\n}\n"
  },
  {
    "path": "testdata/default/repros/Issue3221.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\n// https://github.com/foundry-rs/foundry/issues/3221\ncontract Issue3221Test is Test {\n    uint256 fork1;\n    uint256 fork2;\n\n    function setUp() public {\n        fork1 = vm.createFork(\"sepolia\", 5565573);\n        fork2 = vm.createFork(\"avaxTestnet\", 12880747);\n    }\n\n    function testForkNonce() public {\n        address user = address(0xF0959944122fb1ed4CfaBA645eA06EED30427BAA);\n\n        // Loads but doesn't touch\n        assertEq(vm.getNonce(user), 0);\n\n        vm.selectFork(fork2);\n        assertEq(vm.getNonce(user), 3);\n        vm.prank(user);\n        new Counter();\n\n        vm.selectFork(fork1);\n        assertEq(vm.getNonce(user), 1);\n        vm.prank(user);\n        new Counter();\n    }\n}\n\ncontract Counter {}\n"
  },
  {
    "path": "testdata/default/repros/Issue3223.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\n// https://github.com/foundry-rs/foundry/issues/3223\n/// forge-config: default.sender = \"0xF0959944122fb1ed4CfaBA645eA06EED30427BAA\"\ncontract Issue3223Test is Test {\n    uint256 fork1;\n    uint256 fork2;\n\n    function setUp() public {\n        fork1 = vm.createFork(\"sepolia\", 2362365);\n        fork2 = vm.createFork(\"avaxTestnet\", 12880747);\n    }\n\n    function testForkNonce() public {\n        address user = address(0xF0959944122fb1ed4CfaBA645eA06EED30427BAA);\n        assertEq(user, msg.sender);\n\n        vm.selectFork(fork2);\n        assertEq(vm.getNonce(user), 3);\n        vm.prank(user);\n        new Counter();\n\n        vm.selectFork(fork1);\n        assertEq(vm.getNonce(user), 1);\n    }\n}\n\ncontract Counter {}\n"
  },
  {
    "path": "testdata/default/repros/Issue3653.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\n// https://github.com/foundry-rs/foundry/issues/3653\ncontract Issue3653Test is Test {\n    uint256 fork;\n    Token token;\n\n    constructor() {\n        fork = vm.createSelectFork(\"mainnet\", 1000000);\n        token = new Token();\n        vm.makePersistent(address(token));\n    }\n\n    function testDummy() public {\n        assertEq(block.number, 1000000);\n    }\n}\n\ncontract Token {}\n"
  },
  {
    "path": "testdata/default/repros/Issue3661.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\n// https://github.com/foundry-rs/foundry/issues/3661\ncontract Issue3661Test is Test {\n    address sender;\n\n    function setUp() public {\n        sender = msg.sender;\n    }\n\n    function testSameSender() public {\n        assert(sender == msg.sender);\n    }\n}\n"
  },
  {
    "path": "testdata/default/repros/Issue3674.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\n// https://github.com/foundry-rs/foundry/issues/3674\n/// forge-config: default.sender = \"0xF0959944122fb1ed4CfaBA645eA06EED30427BAA\"\ncontract Issue3674Test is Test {\n    function testNonceCreateSelect() public {\n        vm.createSelectFork(\"sepolia\");\n\n        vm.createSelectFork(\"avaxTestnet\");\n        assertTrue(vm.getNonce(msg.sender) > 0x17);\n    }\n}\n"
  },
  {
    "path": "testdata/default/repros/Issue3685.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\n// https://github.com/foundry-rs/foundry/issues/3685\ncontract Issue3685Test is Test {\n    Actor a;\n    Actor b;\n\n    function setUp() public {\n        a = new Actor();\n        b = new Actor();\n        vm.deal(address(a), 1 ether);\n    }\n\n    // should not end up with 0 balance\n    function test_wrong_balance() public {\n        console.log(\"should be 1 ether       \", address(a).balance);\n        vm.expectRevert(bytes(\"rev\"));\n        a.spendFail(b);\n        console.log(\"should still be 1 ether \", address(a).balance);\n        a.spendSuccess(b); // panics here if back_and_forth() is called before\n    }\n    // panics\n\n    function test_panic() public {\n        back_and_forth();\n        test_wrong_balance();\n    }\n\n    function back_and_forth() internal {\n        a.spendSuccess(b);\n        b.spendSuccess(a);\n    }\n}\n\ncontract Actor {\n    function spendSuccess(Actor a) public {\n        a.receiveSuccess{value: 1 ether}();\n    }\n\n    function spendFail(Actor a) public {\n        a.receiveFail{value: 1 ether}();\n    }\n\n    function receiveFail() public payable {\n        revert(\"rev\");\n    }\n\n    function receiveSuccess() public payable {}\n}\n"
  },
  {
    "path": "testdata/default/repros/Issue3703.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\n// https://github.com/foundry-rs/foundry/issues/3703\ncontract Issue3703Test is Test {\n    function setUp() public {\n        vm.skip(true, \"flaky polygon RPCs\");\n\n        uint256 fork =\n            vm.createSelectFork(\"polygon\", bytes32(0xbed0c8c1b9ff8bf0452979d170c52893bb8954f18a904aa5bcbd0f709be050b9));\n    }\n\n    function poolState(address poolAddr, uint256 expectedSqrtPriceX96, uint256 expectedLiquidity) private {\n        IUniswapV3Pool pool = IUniswapV3Pool(poolAddr);\n\n        (uint256 actualSqrtPriceX96,,,,,,) = pool.slot0();\n        uint256 actualLiquidity = pool.liquidity();\n\n        assertEq(expectedSqrtPriceX96, actualSqrtPriceX96);\n        assertEq(expectedLiquidity, actualLiquidity);\n    }\n\n    function testStatePool1() public {\n        poolState(0x847b64f9d3A95e977D157866447a5C0A5dFa0Ee5, 1076133273204200901840477866344, 1221531661829);\n    }\n}\n\ninterface IUniswapV3Pool {\n    function slot0()\n        external\n        view\n        returns (\n            uint160 sqrtPriceX96,\n            int24 tick,\n            uint16 observationIndex,\n            uint16 observationCardinality,\n            uint16 observationCardinalityNext,\n            uint8 feeProtocol,\n            bool unlocked\n        );\n\n    function liquidity() external view returns (uint128);\n}\n"
  },
  {
    "path": "testdata/default/repros/Issue3708.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\n// https://github.com/foundry-rs/foundry/issues/3708\ncontract Issue3708Test is Test {\n    // https://optimistic.etherscan.io/address/0x4e59b44847b379578588920ca78fbf26c0b4956c#code\n    address constant CREATE2_DEPLOYER = 0x4e59b44847b379578588920cA78FbF26c0B4956C;\n\n    function setUp() public {\n        uint256 forkId = vm.createSelectFork(\"optimism\");\n\n        bytes memory code =\n            hex\"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf3\";\n        assertEq(CREATE2_DEPLOYER.code, code);\n    }\n\n    function test_deployer() public {\n        bytes memory code =\n            hex\"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf3\";\n        assertEq(CREATE2_DEPLOYER.code, code);\n    }\n}\n"
  },
  {
    "path": "testdata/default/repros/Issue3753.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\n// https://github.com/foundry-rs/foundry/issues/3753\ncontract Issue3753Test is Test {\n    function test_repro() public {\n        bool res;\n        assembly {\n            res := staticcall(gas(), 4, 0, 0, 0, 0)\n        }\n        vm.expectRevert(\"require\");\n        this.revert_require();\n    }\n\n    function revert_require() public {\n        revert(\"require\");\n    }\n}\n"
  },
  {
    "path": "testdata/default/repros/Issue3792.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/DSTest.sol\";\nimport \"utils/Vm.sol\";\n\ncontract Config {\n    address public test = 0xcBa28b38103307Ec8dA98377ffF9816C164f9AFa;\n}\n\ncontract TestSetup is Config, DSTest {\n    Vm constant vm = Vm(HEVM_ADDRESS);\n\n    // More context: the inheritance order causes the _failed flag\n    // that is usually checked on snapshots to be shifted.\n    // We now check for keccak256(\"failed\") on the hevm address.\n    // This test should succeed.\n    function testSnapshotStorageShift() public {\n        uint256 snapshotId = vm.snapshotState();\n\n        vm.prank(test);\n\n        vm.revertToState(snapshotId);\n    }\n}\n"
  },
  {
    "path": "testdata/default/repros/Issue4232.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\n// https://github.com/foundry-rs/foundry/issues/4232\ncontract Issue4232Test is Test {\n    function testFork() public {\n        // Smoke test, worked previously as well\n        vm.createSelectFork(\"sepolia\", 7215400);\n        vm.assertFalse(block.prevrandao == 0);\n\n        // Would previously fail with:\n        // [FAIL: backend: failed while inspecting; header validation error: `prevrandao` not set; `prevrandao` not set; ] setUp() (gas: 0)\n        //\n        // Related fix:\n        // Moonbeam | Moonbase | Moonriver | MoonbeamDev => {\n        //     if env.block.prevrandao.is_none() {\n        //         // <https://github.com/foundry-rs/foundry/issues/4232>\n        //         env.block.prevrandao = Some(B256::random());\n        //     }\n        // }\n        //\n        // Note: public RPC node used for `moonbeam` discards state quickly so we need to fork against the latest block\n        vm.createSelectFork(\"moonbeam\");\n        vm.assertFalse(block.prevrandao == 0);\n    }\n}\n"
  },
  {
    "path": "testdata/default/repros/Issue4402.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\n// https://github.com/foundry-rs/foundry/issues/4402\ncontract Issue4402Test is Test {\n    function testReadNonEmptyArray() public {\n        string memory path = \"fixtures/Json/Issue4402.json\";\n        string memory json = vm.readFile(path);\n        address[] memory tokens = vm.parseJsonAddressArray(json, \".tokens\");\n        assertEq(tokens.length, 1);\n\n        path = \"fixtures/Toml/Issue4402.toml\";\n        string memory toml = vm.readFile(path);\n        tokens = vm.parseTomlAddressArray(toml, \".tokens\");\n        assertEq(tokens.length, 1);\n    }\n\n    function testReadEmptyArray() public {\n        string memory path = \"fixtures/Json/Issue4402.json\";\n        string memory json = vm.readFile(path);\n\n        // Every one of these used to causes panic\n        address[] memory emptyAddressArray = vm.parseJsonAddressArray(json, \".empty\");\n        bool[] memory emptyBoolArray = vm.parseJsonBoolArray(json, \".empty\");\n        bytes[] memory emptyBytesArray = vm.parseJsonBytesArray(json, \".empty\");\n        bytes32[] memory emptyBytes32Array = vm.parseJsonBytes32Array(json, \".empty\");\n        string[] memory emptyStringArray = vm.parseJsonStringArray(json, \".empty\");\n        int256[] memory emptyIntArray = vm.parseJsonIntArray(json, \".empty\");\n        uint256[] memory emptyUintArray = vm.parseJsonUintArray(json, \".empty\");\n\n        assertEq(emptyAddressArray.length, 0);\n        assertEq(emptyBoolArray.length, 0);\n        assertEq(emptyBytesArray.length, 0);\n        assertEq(emptyBytes32Array.length, 0);\n        assertEq(emptyStringArray.length, 0);\n        assertEq(emptyIntArray.length, 0);\n        assertEq(emptyUintArray.length, 0);\n\n        path = \"fixtures/Toml/Issue4402.toml\";\n        string memory toml = vm.readFile(path);\n\n        // Every one of these used to causes panic\n        emptyAddressArray = vm.parseTomlAddressArray(toml, \".empty\");\n        emptyBoolArray = vm.parseTomlBoolArray(toml, \".empty\");\n        emptyBytesArray = vm.parseTomlBytesArray(toml, \".empty\");\n        emptyBytes32Array = vm.parseTomlBytes32Array(toml, \".empty\");\n        emptyStringArray = vm.parseTomlStringArray(toml, \".empty\");\n        emptyIntArray = vm.parseTomlIntArray(toml, \".empty\");\n        emptyUintArray = vm.parseTomlUintArray(toml, \".empty\");\n\n        assertEq(emptyAddressArray.length, 0);\n        assertEq(emptyBoolArray.length, 0);\n        assertEq(emptyBytesArray.length, 0);\n        assertEq(emptyBytes32Array.length, 0);\n        assertEq(emptyStringArray.length, 0);\n        assertEq(emptyIntArray.length, 0);\n        assertEq(emptyUintArray.length, 0);\n    }\n}\n"
  },
  {
    "path": "testdata/default/repros/Issue4586.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\n// https://github.com/foundry-rs/foundry/issues/4586\ncontract Issue4586Test is Test {\n    uint256 constant initialBlock = 16730733;\n\n    InvariantHandler handler;\n\n    function setUp() public {\n        vm.createSelectFork(\"mainnet\", initialBlock);\n        handler = new InvariantHandler();\n    }\n\n    function test_rollForkHandlerContract() public {\n        assertEq(block.number, initialBlock);\n        handler.rollFork();\n        assertEq(block.number, initialBlock + 1);\n    }\n\n    function test_rollForkTestContract() public {\n        assertEq(block.number, initialBlock);\n        vm.rollFork(block.number + 1);\n        assertEq(block.number, initialBlock + 1);\n    }\n}\n\ncontract InvariantHandler {\n    Vm constant vm = Vm(address(bytes20(uint160(uint256(keccak256(\"hevm cheat code\"))))));\n\n    uint256 public calledRollFork;\n\n    function rollFork() public {\n        vm.rollFork(block.number + 1);\n        calledRollFork += 1;\n    }\n}\n"
  },
  {
    "path": "testdata/default/repros/Issue4630.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\n// https://github.com/foundry-rs/foundry/issues/4630\ncontract Issue4630Test is Test {\n    function testExistingValue() public {\n        string memory path = \"fixtures/Json/Issue4630.json\";\n        string memory json = vm.readFile(path);\n        uint256 val = vm.parseJsonUint(json, \".local.prop1\");\n        assertEq(val, 10);\n    }\n\n    function testMissingValue() public {\n        string memory path = \"fixtures/Json/Issue4630.json\";\n        string memory json = vm.readFile(path);\n        vm._expectCheatcodeRevert();\n        vm.parseJsonUint(json, \".localempty.prop1\");\n    }\n}\n"
  },
  {
    "path": "testdata/default/repros/Issue4640.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\n// https://github.com/foundry-rs/foundry/issues/4640\ncontract Issue4640Test is Test {\n    function testArbitrumBlockNumber() public {\n        // <https://arbiscan.io/block/394276729>\n        vm.createSelectFork(\"arbitrum\", 394276729);\n        // L1 block number\n        assertEq(block.number, 23675778);\n    }\n}\n"
  },
  {
    "path": "testdata/default/repros/Issue5038.t.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\nstruct Value {\n    uint256 value;\n}\n\n// https://github.com/foundry-rs/foundry/issues/5038\ncontract Issue5038Test is Test {\n    function testParseMaxUint64() public {\n        string memory json = '{\"value\": 18446744073709551615}';\n        bytes memory parsed = vm.parseJson(json);\n        Value memory data = abi.decode(parsed, (Value));\n        assertEq(data.value, 18446744073709551615);\n    }\n\n    function testParse18446744073709551616000() public {\n        string memory json = '{\"value\": 18446744073709551616000}';\n        bytes memory parsed = vm.parseJson(json);\n        Value memory data = abi.decode(parsed, (Value));\n        assertEq(data.value, 18446744073709551616000);\n    }\n\n    function testParse1e19() public {\n        string memory json = '{\"value\": 10000000000000000000}';\n        bytes memory parsed = vm.parseJson(json);\n        Value memory data = abi.decode(parsed, (Value));\n        assertEq(data.value, 10000000000000000000);\n    }\n\n    function test_parse_1e20() public {\n        string memory json = '{\"value\": 100000000000000000000}';\n        bytes memory parsed = vm.parseJson(json);\n        Value memory data = abi.decode(parsed, (Value));\n        assertEq(data.value, 100000000000000000000);\n    }\n\n    function testParse1e21() public {\n        string memory json = '{\"value\": 1000000000000000000000}';\n        bytes memory parsed = vm.parseJson(json);\n        Value memory data = abi.decode(parsed, (Value));\n        assertEq(data.value, 1000000000000000000000);\n    }\n\n    function testParse1e42() public {\n        string memory json = '{\"value\": 1000000000000000000000000000000000000000000}';\n        bytes memory parsed = vm.parseJson(json);\n        Value memory data = abi.decode(parsed, (Value));\n        assertEq(data.value, 1000000000000000000000000000000000000000000);\n    }\n\n    function testParse1e42plusOne() public {\n        string memory json = '{\"value\": 1000000000000000000000000000000000000000001}';\n        bytes memory parsed = vm.parseJson(json);\n        Value memory data = abi.decode(parsed, (Value));\n        assertEq(data.value, 1000000000000000000000000000000000000000001);\n    }\n\n    function testParse1e43plus5() public {\n        string memory json = '{\"value\": 10000000000000000000000000000000000000000005}';\n        bytes memory parsed = vm.parseJson(json);\n        Value memory data = abi.decode(parsed, (Value));\n        assertEq(data.value, 10000000000000000000000000000000000000000005);\n    }\n\n    function testParse1e76() public {\n        string memory json = '{\"value\": 10000000000000000000000000000000000000000000000000000000000000000000000000000}';\n        bytes memory parsed = vm.parseJson(json);\n        Value memory data = abi.decode(parsed, (Value));\n        assertEq(data.value, 10000000000000000000000000000000000000000000000000000000000000000000000000000);\n    }\n\n    function testParse1e76Plus10() public {\n        string memory json = '{\"value\": 10000000000000000000000000000000000000000000000000000000000000000000000000010}';\n        bytes memory parsed = vm.parseJson(json);\n        Value memory data = abi.decode(parsed, (Value));\n        assertEq(data.value, 10000000000000000000000000000000000000000000000000000000000000000000000000010);\n    }\n\n    function testParseMinUint256() public {\n        string memory json = '{\"value\": -57896044618658097711785492504343953926634992332820282019728792003956564819968}';\n        bytes memory parsed = vm.parseJson(json);\n        Value memory data = abi.decode(parsed, (Value));\n\n        assertEq(int256(data.value), -57896044618658097711785492504343953926634992332820282019728792003956564819968);\n    }\n\n    function testParseMaxUint256() public {\n        string memory json = '{\"value\": 115792089237316195423570985008687907853269984665640564039457584007913129639935}';\n        bytes memory parsed = vm.parseJson(json);\n        Value memory data = abi.decode(parsed, (Value));\n        assertEq(data.value, 115792089237316195423570985008687907853269984665640564039457584007913129639935);\n    }\n}\n"
  },
  {
    "path": "testdata/default/repros/Issue5529.t.sol",
    "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.13;\n\nimport \"utils/Test.sol\";\n\ncontract Counter {\n    uint256 public number;\n\n    function setNumber(uint256 newNumber) public {\n        number = newNumber;\n    }\n\n    function increment() public {\n        number++;\n    }\n}\n\n/// forge-config: default.always_use_create_2_factory = true\ncontract Issue5529Test is Test {\n    Counter public counter;\n    address public constant default_create2_factory = 0x4e59b44847b379578588920cA78FbF26c0B4956C;\n\n    function testCreate2FactoryUsedInTests() public {\n        run();\n    }\n\n    function testCreate2FactoryUsedWhenPranking() public {\n        vm.startPrank(address(1234));\n        run();\n    }\n\n    function run() private {\n        address a = vm.computeCreate2Address(0, keccak256(type(Counter).creationCode), address(default_create2_factory));\n        address b = address(new Counter{salt: 0}());\n        require(a == b, \"create2 address mismatch\");\n    }\n}\n"
  },
  {
    "path": "testdata/default/repros/Issue5739.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ninterface IERC20 {\n    function totalSupply() external view returns (uint256 supply);\n}\n\n// https://github.com/foundry-rs/foundry/issues/5739\ncontract Issue5739Test is Test {\n    IERC20 dai;\n\n    function setUp() public {\n        vm.createSelectFork(\"mainnet\", 19000000);\n        dai = IERC20(0x6B175474E89094C44Da98b954EedeAC495271d0F);\n    }\n\n    function testRollForkStateUpdated() public {\n        // dai not persistent so state should be updated between rolls\n        assertEq(dai.totalSupply(), 3723031040751006502480211083);\n        vm.rollFork(19925849);\n        assertEq(dai.totalSupply(), 3320242279303699674318705475);\n    }\n\n    function testRollForkStatePersisted() public {\n        // make dai persistent so state is preserved between rolls\n        vm.makePersistent(address(dai));\n        assertEq(dai.totalSupply(), 3723031040751006502480211083);\n        vm.rollFork(19925849);\n        assertEq(dai.totalSupply(), 3723031040751006502480211083);\n    }\n}\n"
  },
  {
    "path": "testdata/default/repros/Issue5808.t.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\n// https://github.com/foundry-rs/foundry/issues/5808\ncontract Issue5808Test is Test {\n    function testReadInt() public {\n        string memory str1 = '[\"ffffffff\",\"00000010\"]';\n        vm._expectCheatcodeRevert();\n        int256[] memory ints1 = vm.parseJsonIntArray(str1, \"\");\n\n        string memory str2 = '[\"0xffffffff\",\"0x00000010\"]';\n        int256[] memory ints2 = vm.parseJsonIntArray(str2, \"\");\n        assertEq(ints2[0], 0xffffffff);\n        assertEq(ints2[1], 16);\n    }\n}\n"
  },
  {
    "path": "testdata/default/repros/Issue5929.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\n// https://github.com/foundry-rs/foundry/issues/5929\ncontract Issue5929Test is Test {\n    function test_transact_not_working() public {\n        vm.createSelectFork(\"mainnet\", 21134547);\n        // https://etherscan.io/tx/0x96a129768ec66fd7d65114bf182f4e173bf0b73a44219adaf71f01381a3d0143\n        vm.transact(hex\"7dcff74771babf9c23363c4228e55a27f50224d4596b1ba6608b0b45712f94ba\");\n    }\n}\n"
  },
  {
    "path": "testdata/default/repros/Issue5935.t.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract SimpleStorage {\n    uint256 public value;\n\n    function set(uint256 _value) external {\n        value = _value;\n    }\n}\n\ncontract Issue5935Test is Test {\n    function testFork() public {\n        uint256 forkId1 = vm.createFork(\"mainnet\", 18234083);\n        uint256 forkId2 = vm.createFork(\"mainnet\", 18234083);\n        vm.selectFork(forkId1);\n        SimpleStorage myContract = new SimpleStorage();\n        myContract.set(42);\n        vm.selectFork(forkId2);\n        SimpleStorage myContract2 = new SimpleStorage();\n        assertEq(myContract2.value(), 0);\n\n        vm.selectFork(forkId1);\n        assertEq(myContract.value(), 42);\n    }\n}\n"
  },
  {
    "path": "testdata/default/repros/Issue5948.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\n// https://github.com/foundry-rs/foundry/issues/5948\ncontract Issue5948Test is Test {\n    /// forge-config: default.fuzz.runs = 2\n    function testSleepFuzzed(uint256 _milliseconds) public {\n        // Limit sleep time to 2 seconds to decrease test time\n        uint256 milliseconds = _milliseconds % 2000;\n\n        string[] memory inputs = new string[](2);\n        inputs[0] = \"date\";\n        // OS X does not support precision more than 1 second\n        inputs[1] = \"+%s000\";\n\n        bytes memory res = vm.ffi(inputs);\n        uint256 start = vm.parseUint(string(res));\n\n        vm.sleep(milliseconds);\n\n        res = vm.ffi(inputs);\n        uint256 end = vm.parseUint(string(res));\n\n        // Limit precision to 1000 ms\n        assertGe(end - start, milliseconds / 1000 * 1000, \"sleep failed\");\n    }\n}\n"
  },
  {
    "path": "testdata/default/repros/Issue6006.t.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\n// https://github.com/foundry-rs/foundry/issues/6006\ncontract Issue6066Test is Test {\n    function test_parse_11e20_sci() public {\n        string memory json = '{\"value\": 1.1e20}';\n        bytes memory parsed = vm.parseJson(json);\n        Value memory data = abi.decode(parsed, (Value));\n        assertEq(data.value, 1.1e20);\n    }\n\n    function test_parse_22e20_sci() public {\n        string memory json = '{\"value\": 2.2e20}';\n        bytes memory parsed = vm.parseJson(json);\n        Value memory data = abi.decode(parsed, (Value));\n        assertEq(data.value, 2.2e20);\n    }\n\n    function test_parse_2e_sci() public {\n        string memory json = '{\"value\": 2e10}';\n        bytes memory parsed = vm.parseJson(json);\n        Value memory data = abi.decode(parsed, (Value));\n        assertEq(data.value, 2e10);\n    }\n}\n\nstruct Value {\n    uint256 value;\n}\n"
  },
  {
    "path": "testdata/default/repros/Issue6032.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\n// https://github.com/foundry-rs/foundry/issues/6032\ncontract Issue6032Test is Test {\n    function testEtchFork() public {\n        // Deploy initial contract\n        Counter counter = new Counter();\n        counter.setNumber(42);\n\n        address counterAddress = address(counter);\n        // Enter the fork\n        vm.createSelectFork(\"mainnet\");\n        assert(counterAddress.code.length > 0);\n        // `Counter` is not deployed on the fork, which is expected.\n\n        // Etch the contract into the fork.\n        bytes memory code = vm.getDeployedCode(\"Issue6032.t.sol:CounterEtched\");\n        vm.etch(counterAddress, code);\n        //  `Counter` is now deployed on the fork.\n        assert(counterAddress.code.length > 0);\n\n        // Now we can etch the code, but state will remain.\n        CounterEtched counterEtched = CounterEtched(counterAddress);\n        assertEq(counterEtched.numberHalf(), 21);\n    }\n}\n\ncontract Counter {\n    uint256 public number;\n\n    function setNumber(uint256 newNumber) public {\n        number = newNumber;\n    }\n}\n\ncontract CounterEtched {\n    uint256 public number;\n\n    function numberHalf() public view returns (uint256) {\n        return number / 2;\n    }\n}\n"
  },
  {
    "path": "testdata/default/repros/Issue6070.t.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\n// https://github.com/foundry-rs/foundry/issues/6070\ncontract Issue6066Test is Test {\n    function testNonPrefixed() public {\n        vm.setEnv(\"__FOUNDRY_ISSUE_6066\", \"abcd\");\n        vm._expectCheatcodeRevert(\n            \"failed parsing $__FOUNDRY_ISSUE_6066 as type `uint256`: missing hex prefix (\\\"0x\\\") for hex string\"\n        );\n        uint256 x = vm.envUint(\"__FOUNDRY_ISSUE_6066\");\n    }\n}\n"
  },
  {
    "path": "testdata/default/repros/Issue6115.t.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract Counter {\n    uint256 public number;\n\n    function setNumber(uint256 newNumber) public {\n        number = newNumber;\n    }\n\n    function increment() public {\n        number++;\n    }\n}\n\n// https://github.com/foundry-rs/foundry/issues/6115\ncontract Issue6115Test is Test {\n    Counter public counter;\n\n    function setUp() public {\n        counter = new Counter();\n        counter.setNumber(0);\n    }\n\n    // We should be able to fuzz bytes4\n    function testFuzz_SetNumber(uint256 x, bytes4 test) public {\n        counter.setNumber(x);\n        assertEq(counter.number(), x);\n    }\n\n    // We should be able to fuzz bytes8\n    function testFuzz_SetNumber2(uint256 x, bytes8 test) public {\n        counter.setNumber(x);\n        assertEq(counter.number(), x);\n    }\n\n    // We should be able to fuzz bytes12\n    function testFuzz_SetNumber3(uint256 x, bytes12 test) public {\n        counter.setNumber(x);\n        assertEq(counter.number(), x);\n    }\n}\n"
  },
  {
    "path": "testdata/default/repros/Issue6180.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\n// https://github.com/foundry-rs/foundry/issues/6180\ncontract Issue6180Test is Test {\n    function test_timebug() external {\n        uint256 start = block.timestamp;\n        uint256 count = 4;\n        uint256 duration = 15;\n        for (uint256 i; i < count; i++) {\n            vm.warp(block.timestamp + duration);\n        }\n\n        uint256 end = block.timestamp;\n        assertEq(end, start + count * duration);\n        assertEq(end - start, count * duration);\n    }\n}\n"
  },
  {
    "path": "testdata/default/repros/Issue6293.t.sol",
    "content": "// SPDX-License-Identifier: Unlicense\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\n// https://github.com/foundry-rs/foundry/issues/6293\ncontract Issue6293Test is Test {\n    constructor() {\n        require(address(this).balance > 0);\n        (bool success,) = payable(address(1)).call{value: 1}(\"\");\n        require(success, \"call failed\");\n    }\n\n    function test() public {\n        assertGt(address(this).balance, 0);\n    }\n}\n"
  },
  {
    "path": "testdata/default/repros/Issue6437.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\n// https://github.com/foundry-rs/foundry/issues/6437\ncontract Issue6437Test is Test {\n    function test0() public {\n        string memory json = \"[]\";\n        address[] memory arr = vm.parseJsonAddressArray(json, \"$\");\n        assertEq(arr.length, 0);\n    }\n\n    function test1() public {\n        string memory json = \"[\\\"0x1111111111111111111111111111111111111111\\\"]\";\n        address[] memory arr = vm.parseJsonAddressArray(json, \"$\");\n        assertEq(arr.length, 1);\n        assertEq(arr[0], 0x1111111111111111111111111111111111111111);\n    }\n\n    function test2() public {\n        string memory json =\n            \"[\\\"0x1111111111111111111111111111111111111111\\\",\\\"0x2222222222222222222222222222222222222222\\\"]\";\n        address[] memory arr = vm.parseJsonAddressArray(json, \"$\");\n        assertEq(arr.length, 2);\n        assertEq(arr[0], 0x1111111111111111111111111111111111111111);\n        assertEq(arr[1], 0x2222222222222222222222222222222222222222);\n    }\n}\n"
  },
  {
    "path": "testdata/default/repros/Issue6538.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\n// https://github.com/foundry-rs/foundry/issues/6538\ncontract Issue6538Test is Test {\n    function test_transact() public {\n        bytes32 lastHash = 0x4b70ca8c5a0990b43df3064372d424d46efa41dfaab961754b86c5afb2df4f61;\n        vm.createSelectFork(\"mainnet\", lastHash);\n        bytes32 txhash = 0x7dcff74771babf9c23363c4228e55a27f50224d4596b1ba6608b0b45712f94ba;\n        vm.transact(txhash);\n    }\n}\n"
  },
  {
    "path": "testdata/default/repros/Issue6554.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\n// https://github.com/foundry-rs/foundry/issues/6554\ncontract Issue6554Test is Test {\n    function testPermissions() public {\n        vm.writeFile(\"./out/Issue6554.t.sol/cachedFile.txt\", \"cached data\");\n        string memory content = vm.readFile(\"./out/Issue6554.t.sol/cachedFile.txt\");\n        assertEq(content, \"cached data\");\n    }\n}\n"
  },
  {
    "path": "testdata/default/repros/Issue6616.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\n// https://github.com/foundry-rs/foundry/issues/6616\ncontract Issue6616Test is Test {\n    function testCreateForkRollLatestBlock() public {\n        vm.createSelectFork(\"mainnet\");\n        uint256 startBlock = block.number;\n        // this will create new forks and exit once a new latest block is found\n        for (uint256 i; i < 10; i++) {\n            vm.sleep(5000);\n            vm.createSelectFork(\"mainnet\");\n            if (block.number > startBlock) break;\n        }\n        assertGt(block.number, startBlock);\n    }\n}\n"
  },
  {
    "path": "testdata/default/repros/Issue6634.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract Box {\n    uint256 public number;\n\n    constructor(uint256 _number) {\n        number = _number;\n    }\n}\n\n// https://github.com/foundry-rs/foundry/issues/6634\n/// forge-config: default.always_use_create_2_factory = true\ncontract Issue6634Test is Test {\n    function test_Create2FactoryCallRecordedInStandardTest() public {\n        address CREATE2_DEPLOYER = 0x4e59b44847b379578588920cA78FbF26c0B4956C;\n\n        vm.startStateDiffRecording();\n        Box a = new Box{salt: 0}(1);\n\n        Vm.AccountAccess[] memory called = vm.stopAndReturnStateDiff();\n        address addr = vm.computeCreate2Address(\n            0, keccak256(abi.encodePacked(type(Box).creationCode, uint256(1))), address(CREATE2_DEPLOYER)\n        );\n        assertEq(addr, called[1].account, \"state diff contract address is not correct\");\n        assertEq(address(a), called[1].account, \"returned address is not correct\");\n\n        assertEq(called.length, 2, \"incorrect length\");\n        assertEq(uint256(called[0].kind), uint256(Vm.AccountAccessKind.Call), \"first AccountAccess is incorrect kind\");\n        assertEq(called[0].account, CREATE2_DEPLOYER, \"first AccountAccess account is incorrect\");\n        assertEq(called[0].accessor, address(this), \"first AccountAccess accessor is incorrect\");\n        assertEq(\n            uint256(called[1].kind), uint256(Vm.AccountAccessKind.Create), \"second AccountAccess is incorrect kind\"\n        );\n        assertEq(called[1].accessor, CREATE2_DEPLOYER, \"second AccountAccess accessor is incorrect\");\n        assertEq(called[1].account, address(a), \"second AccountAccess account is incorrect\");\n    }\n\n    function test_Create2FactoryCallRecordedWhenPranking() public {\n        address CREATE2_DEPLOYER = 0x4e59b44847b379578588920cA78FbF26c0B4956C;\n        address accessor = address(0x5555);\n\n        vm.startPrank(accessor);\n        vm.startStateDiffRecording();\n        Box a = new Box{salt: 0}(1);\n\n        Vm.AccountAccess[] memory called = vm.stopAndReturnStateDiff();\n        address addr = vm.computeCreate2Address(\n            0, keccak256(abi.encodePacked(type(Box).creationCode, uint256(1))), address(CREATE2_DEPLOYER)\n        );\n        assertEq(addr, called[1].account, \"state diff contract address is not correct\");\n        assertEq(address(a), called[1].account, \"returned address is not correct\");\n\n        assertEq(called.length, 2, \"incorrect length\");\n        assertEq(uint256(called[0].kind), uint256(Vm.AccountAccessKind.Call), \"first AccountAccess is incorrect kind\");\n        assertEq(called[0].account, CREATE2_DEPLOYER, \"first AccountAccess account is incorrect\");\n        assertEq(called[0].accessor, accessor, \"first AccountAccess accessor is incorrect\");\n        assertEq(\n            uint256(called[1].kind), uint256(Vm.AccountAccessKind.Create), \"second AccountAccess is incorrect kind\"\n        );\n        assertEq(called[1].accessor, CREATE2_DEPLOYER, \"second AccountAccess accessor is incorrect\");\n        assertEq(called[1].account, address(a), \"second AccountAccess account is incorrect\");\n    }\n\n    function test_Create2FactoryCallRecordedWhenBroadcasting() public {\n        address CREATE2_DEPLOYER = 0x4e59b44847b379578588920cA78FbF26c0B4956C;\n        address accessor = address(0x5555);\n\n        vm.startBroadcast(accessor);\n        vm.startStateDiffRecording();\n        Box a = new Box{salt: 0}(1);\n\n        Vm.AccountAccess[] memory called = vm.stopAndReturnStateDiff();\n        address addr = vm.computeCreate2Address(\n            0, keccak256(abi.encodePacked(type(Box).creationCode, uint256(1))), address(CREATE2_DEPLOYER)\n        );\n        assertEq(addr, called[1].account, \"state diff contract address is not correct\");\n        assertEq(address(a), called[1].account, \"returned address is not correct\");\n\n        assertEq(called.length, 2, \"incorrect length\");\n        assertEq(uint256(called[0].kind), uint256(Vm.AccountAccessKind.Call), \"first AccountAccess is incorrect kind\");\n        assertEq(called[0].account, CREATE2_DEPLOYER, \"first AccountAccess account is incorrect\");\n        assertEq(called[0].accessor, accessor, \"first AccountAccess accessor is incorrect\");\n        assertEq(\n            uint256(called[1].kind), uint256(Vm.AccountAccessKind.Create), \"second AccountAccess is incorrect kind\"\n        );\n        assertEq(called[1].accessor, CREATE2_DEPLOYER, \"second AccountAccess accessor is incorrect\");\n        assertEq(called[1].account, address(a), \"second AccountAccess account is incorrect\");\n    }\n}\n"
  },
  {
    "path": "testdata/default/repros/Issue6643.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract Counter {\n    event TestEvent(uint256 n);\n    event AnotherTestEvent(uint256 n);\n\n    constructor() {\n        emit TestEvent(1);\n    }\n\n    function f() external {\n        emit TestEvent(2);\n    }\n\n    function g() external {\n        emit AnotherTestEvent(1);\n        this.f();\n        emit AnotherTestEvent(2);\n    }\n}\n\n// https://github.com/foundry-rs/foundry/issues/6643\ncontract Issue6643Test is Test {\n    Counter public counter;\n\n    event TestEvent(uint256 n);\n    event AnotherTestEvent(uint256 n);\n\n    function setUp() public {\n        counter = new Counter();\n    }\n\n    function test_Bug1() public {\n        // part1\n        vm.expectEmit();\n        emit TestEvent(1);\n        new Counter();\n        // part2\n        vm.expectEmit();\n        emit TestEvent(2);\n        counter.f();\n        // part3\n        vm.expectEmit();\n        emit AnotherTestEvent(1);\n        vm.expectEmit();\n        emit TestEvent(2);\n        vm.expectEmit();\n        emit AnotherTestEvent(2);\n        counter.g();\n    }\n\n    function test_Bug2() public {\n        vm.expectEmit();\n        emit TestEvent(1);\n        new Counter();\n        vm.expectEmit();\n        emit TestEvent(1);\n        new Counter();\n    }\n}\n"
  },
  {
    "path": "testdata/default/repros/Issue6759.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\n// https://github.com/foundry-rs/foundry/issues/6759\ncontract Issue6759Test is Test {\n    function testCreateMulti() public {\n        uint256 fork1 = vm.createFork(\"mainnet\", 10);\n        uint256 fork2 = vm.createFork(\"mainnet\", 10);\n        uint256 fork3 = vm.createFork(\"mainnet\", 10);\n        assert(fork1 != fork2);\n        assert(fork1 != fork3);\n        assert(fork2 != fork3);\n    }\n}\n"
  },
  {
    "path": "testdata/default/repros/Issue6966.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\n// https://github.com/foundry-rs/foundry/issues/6966\n// See also https://github.com/RustCrypto/elliptic-curves/issues/988#issuecomment-1817681013\ncontract Issue6966Test is Test {\n    function testEcrecover() public {\n        bytes32 h = 0x0000000000000000000000000000000000000000000000000000000000000000;\n        uint8 v = 27;\n        bytes32 r = bytes32(0xf87fff3202dfeae34ce9cb8151ce2e176bee02a937baac6de85c4ea03d6a6618);\n        bytes32 s = bytes32(0xedf9ab5c7d3ec1df1c2b48600ab0a35f586e069e9a69c6cdeebc99920128d1a5);\n        assert(ecrecover(h, v, r, s) != address(0));\n    }\n}\n"
  },
  {
    "path": "testdata/default/repros/Issue7238.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract Reverter {\n    function doNotRevert() public {}\n\n    function revertWithMessage(string calldata message) public {\n        revert(message);\n    }\n}\n\n// https://github.com/foundry-rs/foundry/issues/7238\ncontract Issue7238Test is Test {\n    function testExpectRevertString() public {\n        Reverter reverter = new Reverter();\n        vm.expectRevert(\"revert\");\n        reverter.revertWithMessage(\"revert\");\n    }\n\n    // FAIL\n    /// forge-config: default.allow_internal_expect_revert = true\n    function testShouldFailCheatcodeRevert() public {\n        // This expectRevert is hanging, as the next cheatcode call is ignored.\n        vm.expectRevert();\n        vm.fsMetadata(\"something/something\"); // try to go to some non-existent path to cause a revert\n    }\n\n    /// forge-config: default.allow_internal_expect_revert = true\n    function testShouldFailEarlyRevert() public {\n        vm.expectRevert();\n        revert_();\n    }\n\n    function revert_() internal {\n        revert();\n    }\n}\n"
  },
  {
    "path": "testdata/default/repros/Issue7457.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ninterface ITarget {\n    event AnonymousEventEmpty() anonymous;\n    event AnonymousEventNonIndexed(uint256 a) anonymous;\n\n    event DifferentAnonymousEventEmpty() anonymous;\n    event DifferentAnonymousEventNonIndexed(string a) anonymous;\n\n    event AnonymousEventWith1Topic(uint256 indexed a, uint256 b) anonymous;\n    event AnonymousEventWith2Topics(uint256 indexed a, uint256 indexed b, uint256 c) anonymous;\n    event AnonymousEventWith3Topics(uint256 indexed a, uint256 indexed b, uint256 indexed c, uint256 d) anonymous;\n    event AnonymousEventWith4Topics(\n        uint256 indexed a, uint256 indexed b, uint256 indexed c, uint256 indexed d, uint256 e\n    ) anonymous;\n}\n\ncontract Target is ITarget {\n    function emitAnonymousEventEmpty() external {\n        emit AnonymousEventEmpty();\n    }\n\n    function emitAnonymousEventNonIndexed(uint256 a) external {\n        emit AnonymousEventNonIndexed(a);\n    }\n\n    function emitAnonymousEventWith1Topic(uint256 a, uint256 b) external {\n        emit AnonymousEventWith1Topic(a, b);\n    }\n\n    function emitAnonymousEventWith2Topics(uint256 a, uint256 b, uint256 c) external {\n        emit AnonymousEventWith2Topics(a, b, c);\n    }\n\n    function emitAnonymousEventWith3Topics(uint256 a, uint256 b, uint256 c, uint256 d) external {\n        emit AnonymousEventWith3Topics(a, b, c, d);\n    }\n\n    function emitAnonymousEventWith4Topics(uint256 a, uint256 b, uint256 c, uint256 d, uint256 e) external {\n        emit AnonymousEventWith4Topics(a, b, c, d, e);\n    }\n}\n\n// https://github.com/foundry-rs/foundry/issues/7457\ncontract Issue7457Test is Test, ITarget {\n    Target public target;\n\n    function setUp() external {\n        target = new Target();\n    }\n\n    function testEmitEvent() public {\n        vm.expectEmitAnonymous(false, false, false, false, true);\n        emit AnonymousEventEmpty();\n        target.emitAnonymousEventEmpty();\n    }\n\n    /// forge-config: default.allow_internal_expect_revert = true\n    function testEmitEventNonIndexedReverts() public {\n        vm.expectEmit(false, false, false, true);\n        vm.expectRevert(\"use vm.expectEmitAnonymous to match anonymous events\");\n        emit AnonymousEventNonIndexed(1);\n    }\n\n    function testEmitEventNonIndexed() public {\n        vm.expectEmitAnonymous(false, false, false, false, true);\n        emit AnonymousEventNonIndexed(1);\n        target.emitAnonymousEventNonIndexed(1);\n    }\n\n    function testEmitEventWith1Topic() public {\n        vm.expectEmitAnonymous(true, false, false, false, true);\n        emit AnonymousEventWith1Topic(1, 2);\n        target.emitAnonymousEventWith1Topic(1, 2);\n    }\n\n    function testEmitEventWith2Topics() public {\n        vm.expectEmitAnonymous(true, true, false, false, true);\n        emit AnonymousEventWith2Topics(1, 2, 3);\n        target.emitAnonymousEventWith2Topics(1, 2, 3);\n    }\n\n    function testEmitEventWith3Topics() public {\n        vm.expectEmitAnonymous(true, true, true, false, true);\n        emit AnonymousEventWith3Topics(1, 2, 3, 4);\n        target.emitAnonymousEventWith3Topics(1, 2, 3, 4);\n    }\n\n    function testEmitEventWith4Topics() public {\n        vm.expectEmitAnonymous(true, true, true, true, true);\n        emit AnonymousEventWith4Topics(1, 2, 3, 4, 5);\n        target.emitAnonymousEventWith4Topics(1, 2, 3, 4, 5);\n    }\n}\n"
  },
  {
    "path": "testdata/default/repros/Issue7481.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\n// https://github.com/foundry-rs/foundry/issues/7481\n// This test ensures that we don't panic\ncontract Issue7481Test is Test {\n    /// forge-config: default.allow_internal_expect_revert = true\n    function testRevertTransact() public {\n        vm.expectRevert(\"vm.createSelectFork: invalid rpc url: mainnet\");\n        vm.createSelectFork(\"mainnet\", 19514903);\n\n        // Transfer some funds to sender of tx being transacted to ensure that it appears in journaled state\n        (bool success,) = payable(address(0x5C60cD7a3D50877Bfebd484750FBeb245D936dAD)).call{value: 1}(\"\");\n        console.log(success);\n        vm.transact(0xccfd66fc409a633a99b5b75b0e9a2040fcf562d03d9bee3fefc1a5c0eb49c999);\n\n        // Revert the current call to ensure that revm can revert state journal\n        vm.expectRevert();\n        revert(\"HERE\");\n    }\n}\n"
  },
  {
    "path": "testdata/default/repros/Issue8004.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract NonPersistentHelper is Test {\n    uint256 public curState;\n\n    function createSelectFork() external {\n        vm.createSelectFork(\"mainnet\");\n        curState += 1;\n    }\n\n    function createSelectForkAtBlock() external {\n        vm.createSelectFork(\"mainnet\", 19000000);\n        curState += 1;\n    }\n\n    function createSelectForkAtTx() external {\n        vm.createSelectFork(\n            \"mainnet\", vm.parseBytes32(\"0xb5c978f15d01fcc9b4d78967e8189e35ecc21ff4e78315ea5d616f3467003c84\")\n        );\n        curState += 1;\n    }\n\n    function selectFork(uint256 forkId) external {\n        vm.selectFork(forkId);\n        curState += 1;\n    }\n\n    function rollForkAtBlock() external {\n        vm.rollFork(19000000);\n        curState += 1;\n    }\n\n    function rollForkIdAtBlock(uint256 forkId) external {\n        vm.rollFork(forkId, 19000000);\n        curState += 1;\n    }\n}\n\n// https://github.com/foundry-rs/foundry/issues/8004\ncontract Issue8004CreateSelectForkTest is Test {\n    NonPersistentHelper helper;\n\n    function setUp() public {\n        helper = new NonPersistentHelper();\n    }\n\n    function testNonPersistentHelperCreateFork() external {\n        helper.createSelectFork();\n        assertEq(helper.curState(), 1);\n    }\n\n    function testNonPersistentHelperCreateForkAtBlock() external {\n        helper.createSelectForkAtBlock();\n        assertEq(helper.curState(), 1);\n    }\n\n    function testNonPersistentHelperCreateForkAtTx() external {\n        helper.createSelectForkAtBlock();\n        assertEq(helper.curState(), 1);\n    }\n\n    function testNonPersistentHelperSelectFork() external {\n        uint256 forkId = vm.createFork(\"mainnet\");\n        helper.selectFork(forkId);\n        assertEq(helper.curState(), 1);\n    }\n}\n\ncontract Issue8004RollForkTest is Test {\n    NonPersistentHelper helper;\n    uint256 forkId;\n\n    function setUp() public {\n        forkId = vm.createSelectFork(\"mainnet\");\n        helper = new NonPersistentHelper();\n    }\n\n    function testNonPersistentHelperRollForkAtBlock() external {\n        helper.rollForkAtBlock();\n        assertEq(helper.curState(), 1);\n    }\n\n    function testNonPersistentHelperRollForkIdAtBlock() external {\n        helper.rollForkIdAtBlock(forkId);\n        assertEq(helper.curState(), 1);\n    }\n}\n"
  },
  {
    "path": "testdata/default/repros/Issue8006.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ninterface IERC20 {\n    function totalSupply() external view returns (uint256 supply);\n}\n\ncontract Mock {\n    function totalSupply() external view returns (uint256 supply) {\n        return 1;\n    }\n}\n\n// https://github.com/foundry-rs/foundry/issues/8006\ncontract Issue8006Test is Test {\n    IERC20 dai;\n    bytes32 transaction = 0xb23f389b26eb6f95c08e275ec2c360ab3990169492ff0d3e7b7233a3f81d299f;\n\n    function setUp() public {\n        vm.createSelectFork(\"mainnet\", 21134541);\n        dai = IERC20(0x6B175474E89094C44Da98b954EedeAC495271d0F);\n    }\n\n    function testRollForkEtchNotCalled() public {\n        // dai not persistent so should not call mock code\n        vm.etch(address(dai), address(new Mock()).code);\n        assertEq(dai.totalSupply(), 1);\n        vm.rollFork(transaction);\n        assertEq(dai.totalSupply(), 3324657947511778619416491233);\n    }\n\n    function testRollForkEtchCalled() public {\n        // make dai persistent so mock code is preserved\n        vm.etch(address(dai), address(new Mock()).code);\n        vm.makePersistent(address(dai));\n        assertEq(dai.totalSupply(), 1);\n        vm.rollFork(transaction);\n        assertEq(dai.totalSupply(), 1);\n    }\n}\n"
  },
  {
    "path": "testdata/default/repros/Issue8168.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\n// https://github.com/foundry-rs/foundry/issues/8168\ncontract Issue8168Test is Test {\n    function testForkWarpRollPreserved() public {\n        uint256 fork1 = vm.createFork(\"mainnet\");\n        uint256 fork2 = vm.createFork(\"mainnet\");\n\n        vm.selectFork(fork1);\n        uint256 initial_fork1_number = block.number;\n        uint256 initial_fork1_ts = block.timestamp;\n        vm.warp(block.timestamp + 1000);\n        vm.roll(block.number + 100);\n        assertEq(block.timestamp, initial_fork1_ts + 1000);\n        assertEq(block.number, initial_fork1_number + 100);\n\n        vm.selectFork(fork2);\n        uint256 initial_fork2_number = block.number;\n        uint256 initial_fork2_ts = block.timestamp;\n        vm.warp(block.timestamp + 2000);\n        vm.roll(block.number + 200);\n        assertEq(block.timestamp, initial_fork2_ts + 2000);\n        assertEq(block.number, initial_fork2_number + 200);\n\n        vm.selectFork(fork1);\n        assertEq(block.timestamp, initial_fork1_ts + 1000);\n        assertEq(block.number, initial_fork1_number + 100);\n\n        vm.selectFork(fork2);\n        assertEq(block.timestamp, initial_fork2_ts + 2000);\n        assertEq(block.number, initial_fork2_number + 200);\n    }\n}\n"
  },
  {
    "path": "testdata/default/repros/Issue8277.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\n// https://github.com/foundry-rs/foundry/issues/8277\ncontract Issue8277Test is Test {\n    struct MyJson {\n        string s;\n    }\n\n    function test_hexprefixednonhexstring() public {\n        {\n            bytes memory b = vm.parseJson(\"{\\\"a\\\": \\\"0x834629f473876e5f0d3d9d269af3dabcb0d7d520-identifier-0\\\"}\");\n            MyJson memory decoded = abi.decode(b, (MyJson));\n            assertEq(decoded.s, \"0x834629f473876e5f0d3d9d269af3dabcb0d7d520-identifier-0\");\n        }\n\n        {\n            bytes memory b = vm.parseJson(\"{\\\"b\\\": \\\"0xBTC\\\"}\");\n            MyJson memory decoded = abi.decode(b, (MyJson));\n            assertEq(decoded.s, \"0xBTC\");\n        }\n    }\n}\n"
  },
  {
    "path": "testdata/default/repros/Issue8287.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\n// https://github.com/foundry-rs/foundry/issues/8287\ncontract Issue8287Test is Test {\n    function testRpcBalance() public {\n        uint256 f2 = vm.createSelectFork(\"mainnet\", 10);\n        bytes memory data = vm.rpc(\"eth_getBalance\", \"[\\\"0x551e7784778ef8e048e495df49f2614f84a4f1dc\\\",\\\"0x0\\\"]\");\n        string memory m = vm.toString(data);\n        assertEq(m, \"0x2086ac351052600000\");\n    }\n\n    function testRpcStorage() public {\n        uint256 f2 = vm.createSelectFork(\"mainnet\", 10);\n        bytes memory data = vm.rpc(\n            \"eth_getStorageAt\",\n            \"[\\\"0x551e7784778ef8e048e495df49f2614f84a4f1dc\\\",\\\"0x40BdB4497614bAe1A67061EE20AAdE3c2067AC9e\\\",\\\"0x0\\\"]\"\n        );\n        string memory m = vm.toString(data);\n        assertEq(m, \"0x0000000000000000000000000000000000000000000000000000000000000000\");\n    }\n}\n"
  },
  {
    "path": "testdata/default/repros/Issue8566.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\n// https://github.com/foundry-rs/foundry/issues/8566\ncontract Issue8566Test is Test {\n    function testParseJsonUint() public {\n        string memory json =\n            \"{ \\\"1284\\\": { \\\"addRewardInfo\\\": { \\\"amount\\\": 74258.225772486694040708e18, \\\"rewardPerSec\\\": 0.03069536448928848133e20 } } }\";\n\n        assertEq(74258225772486694040708, vm.parseJsonUint(json, \".1284.addRewardInfo.amount\"));\n        assertEq(3069536448928848133, vm.parseJsonUint(json, \".1284.addRewardInfo.rewardPerSec\"));\n    }\n}\n"
  },
  {
    "path": "testdata/default/repros/Issue8639.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\nlibrary ExternalLibrary {\n    function doWork(uint256 a) public returns (uint256) {\n        return a++;\n    }\n}\n\ncontract Counter {\n    uint256 public number;\n\n    function setNumber(uint256 newNumber) public {\n        ExternalLibrary.doWork(1);\n    }\n\n    function increment() public {}\n}\n\n// https://github.com/foundry-rs/foundry/issues/8639\ncontract Issue8639Test is Test {\n    Counter counter;\n\n    function setUp() public {\n        counter = new Counter();\n    }\n\n    /// forge-config: default.fuzz.runs = 1000\n    /// forge-config: default.fuzz.seed = \"100\"\n    function test_external_library_address(address test) public {\n        require(test != address(ExternalLibrary));\n    }\n}\n\ncontract Issue8639AnotherTest is Test {\n    /// forge-config: default.fuzz.runs = 1000\n    /// forge-config: default.fuzz.seed = \"100\"\n    function test_another_external_library_address(address test) public {\n        require(test != address(ExternalLibrary));\n    }\n}\n"
  },
  {
    "path": "testdata/default/repros/Issue8971.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract Counter {\n    uint256 public number;\n\n    function increment() public {\n        number++;\n    }\n}\n\n/// @notice Test is mostly related to --isolate. Ensures that state is not affected by reverted\n/// call to handler.\ncontract Handler {\n    bool public locked;\n    Counter public counter = new Counter();\n\n    function doNothing() public {}\n\n    function doSomething() public {\n        locked = true;\n        counter.increment();\n        this.doRevert();\n    }\n\n    function doRevert() public {\n        revert();\n    }\n}\n\n/// forge-config: default.isolate = true\ncontract Invariant is Test {\n    Handler h;\n\n    function setUp() public {\n        h = new Handler();\n    }\n\n    function targetContracts() public view returns (address[] memory contracts) {\n        contracts = new address[](1);\n        contracts[0] = address(h);\n    }\n\n    function invariant_unchanged() public {\n        assertEq(h.locked(), false);\n        assertEq(h.counter().number(), 0);\n    }\n}\n"
  },
  {
    "path": "testdata/default/repros/Issue9643.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract Mock {\n    uint256 private counter;\n\n    function setCounter(uint256 _counter) external {\n        counter = _counter;\n    }\n}\n\ncontract DelegateProxy {\n    address internal implementation;\n\n    constructor(address mock) {\n        implementation = mock;\n    }\n\n    fallback() external payable {\n        address addr = implementation;\n\n        assembly {\n            calldatacopy(0, 0, calldatasize())\n            let result := delegatecall(gas(), addr, 0, calldatasize(), 0, 0)\n            returndatacopy(0, 0, returndatasize())\n            switch result\n            case 0 { revert(0, returndatasize()) }\n            default { return(0, returndatasize()) }\n        }\n    }\n}\n\ncontract Issue9643Test is Test {\n    function test_storage_json_diff() public {\n        vm.startStateDiffRecording();\n        Mock proxied = Mock(address(new DelegateProxy(address(new Mock()))));\n        proxied.setCounter(42);\n        string memory rawDiff = vm.getStateDiffJson();\n        assertEq(\n            '{\"0x2e234dae75c793f67a35089c9d99245e1c58470b\":{\"label\":null,\"contract\":\"default/repros/Issue9643.t.sol:DelegateProxy\",\"balanceDiff\":null,\"nonceDiff\":{\"previousValue\":0,\"newValue\":1},\"stateDiff\":{\"0x0000000000000000000000000000000000000000000000000000000000000000\":{\"previousValue\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"newValue\":\"0x000000000000000000000000000000000000000000000000000000000000002a\",\"label\":\"implementation\",\"type\":\"address\",\"offset\":0,\"slot\":\"0\",\"decoded\":{\"previousValue\":\"0x0000000000000000000000000000000000000000\",\"newValue\":\"0x000000000000000000000000000000000000002A\"}}}},\"0x5615deb798bb3e4dfa0139dfa1b3d433cc23b72f\":{\"label\":null,\"contract\":\"default/repros/Issue9643.t.sol:Mock\",\"balanceDiff\":null,\"nonceDiff\":{\"previousValue\":0,\"newValue\":1},\"stateDiff\":{}}}',\n            rawDiff\n        );\n    }\n}\n"
  },
  {
    "path": "testdata/default/spec/ShanghaiCompat.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract ShanghaiCompat is Test {\n    function testPush0() public {\n        address target = address(uint160(uint256(0xc4f3)));\n\n        bytes memory bytecode = hex\"365f5f37365ff3\";\n        // 36 CALLDATASIZE\n        // 5F PUSH0\n        // 5F PUSH0\n        // 37 CALLDATACOPY -> copies calldata at mem[0..calldatasize]\n\n        // 36 CALLDATASIZE\n        // 5F PUSH0\n        // F3 RETURN -> returns mem[0..calldatasize]\n\n        vm.etch(target, bytecode);\n\n        (bool success, bytes memory result) = target.call(bytes(\"hello PUSH0\"));\n        assertTrue(success);\n        assertEq(string(result), \"hello PUSH0\");\n    }\n}\n"
  },
  {
    "path": "testdata/default/vyper/CounterTest.vy",
    "content": "from src import ICounter\n\ninterface Vm:\n    def deployCode(artifact_name: String[1024], args: Bytes[1024] = b\"\") -> address: nonpayable\n\nvm: constant(Vm) = Vm(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D)\ncounter: ICounter\n\n@external\ndef setUp():\n    self.counter = ICounter(extcall vm.deployCode(\"src/Counter.vy\"))\n\n@external\ndef test_increment():\n    extcall self.counter.increment()\n    assert staticcall self.counter.number() == 1\n"
  },
  {
    "path": "testdata/etherscan/0x044b75f554b886A065b9567891e45c79542d7357/creation_data.json",
    "content": "{\"contractAddress\":\"0x044b75f554b886a065b9567891e45c79542d7357\",\"contractCreator\":\"0xf87bc5535602077d340806d71f805ea9907a843d\",\"txHash\":\"0x9a89d2f5528bf07661e92f3f78a3311396f11f15da19e3ec4d880be1ad1a4bec\"}"
  },
  {
    "path": "testdata/etherscan/0x044b75f554b886A065b9567891e45c79542d7357/metadata.json",
    "content": "[{\"SourceCode\":{\"language\":\"Solidity\",\"sources\":{\"contracts/InputStream.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\n\\npragma solidity 0.8.10;\\n\\nlibrary InputStream {\\n  function createStream(bytes memory data) internal pure returns (uint256 stream) {\\n    assembly {\\n      stream := mload(0x40)\\n      mstore(0x40, add(stream, 64))\\n      mstore(stream, data)\\n      let length := mload(data)\\n      mstore(add(stream, 32), add(data, length))\\n    }\\n  }\\n\\n  function isNotEmpty(uint256 stream) internal pure returns (bool) {\\n    uint256 pos;\\n    uint256 finish;\\n    assembly {\\n      pos := mload(stream)\\n      finish := mload(add(stream, 32))\\n    }\\n    return pos < finish;\\n  }\\n\\n  function readUint8(uint256 stream) internal pure returns (uint8 res) {\\n    assembly {\\n      let pos := mload(stream)\\n      pos := add(pos, 1)\\n      res := mload(pos)\\n      mstore(stream, pos)\\n    }\\n  }\\n\\n  function readUint16(uint256 stream) internal pure returns (uint16 res) {\\n    assembly {\\n      let pos := mload(stream)\\n      pos := add(pos, 2)\\n      res := mload(pos)\\n      mstore(stream, pos)\\n    }\\n  }\\n\\n  function readUint32(uint256 stream) internal pure returns (uint32 res) {\\n    assembly {\\n      let pos := mload(stream)\\n      pos := add(pos, 4)\\n      res := mload(pos)\\n      mstore(stream, pos)\\n    }\\n  }\\n\\n  function readUint(uint256 stream) internal pure returns (uint256 res) {\\n    assembly {\\n      let pos := mload(stream)\\n      pos := add(pos, 32)\\n      res := mload(pos)\\n      mstore(stream, pos)\\n    }\\n  }\\n\\n  function readAddress(uint256 stream) internal pure returns (address res) {\\n    assembly {\\n      let pos := mload(stream)\\n      pos := add(pos, 20)\\n      res := mload(pos)\\n      mstore(stream, pos)\\n    }\\n  }\\n\\n  function readBytes(uint256 stream) internal pure returns (bytes memory res) {\\n    assembly {\\n      let pos := mload(stream)\\n      res := add(pos, 32)\\n      let length := mload(res)\\n      mstore(stream, add(res, length))\\n    }\\n  }\\n}\\n\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../extensions/draft-IERC20Permit.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n    using Address for address;\\n\\n    function safeTransfer(\\n        IERC20 token,\\n        address to,\\n        uint256 value\\n    ) internal {\\n        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n    }\\n\\n    function safeTransferFrom(\\n        IERC20 token,\\n        address from,\\n        address to,\\n        uint256 value\\n    ) internal {\\n        _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n    }\\n\\n    /**\\n     * @dev Deprecated. This function has issues similar to the ones found in\\n     * {IERC20-approve}, and its usage is discouraged.\\n     *\\n     * Whenever possible, use {safeIncreaseAllowance} and\\n     * {safeDecreaseAllowance} instead.\\n     */\\n    function safeApprove(\\n        IERC20 token,\\n        address spender,\\n        uint256 value\\n    ) internal {\\n        // safeApprove should only be called when setting an initial allowance,\\n        // or when resetting it to zero. To increase and decrease it, use\\n        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n        require(\\n            (value == 0) || (token.allowance(address(this), spender) == 0),\\n            \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n        );\\n        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n    }\\n\\n    function safeIncreaseAllowance(\\n        IERC20 token,\\n        address spender,\\n        uint256 value\\n    ) internal {\\n        uint256 newAllowance = token.allowance(address(this), spender) + value;\\n        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n    }\\n\\n    function safeDecreaseAllowance(\\n        IERC20 token,\\n        address spender,\\n        uint256 value\\n    ) internal {\\n        unchecked {\\n            uint256 oldAllowance = token.allowance(address(this), spender);\\n            require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n            uint256 newAllowance = oldAllowance - value;\\n            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n        }\\n    }\\n\\n    function safePermit(\\n        IERC20Permit token,\\n        address owner,\\n        address spender,\\n        uint256 value,\\n        uint256 deadline,\\n        uint8 v,\\n        bytes32 r,\\n        bytes32 s\\n    ) internal {\\n        uint256 nonceBefore = token.nonces(owner);\\n        token.permit(owner, spender, value, deadline, v, r, s);\\n        uint256 nonceAfter = token.nonces(owner);\\n        require(nonceAfter == nonceBefore + 1, \\\"SafeERC20: permit did not succeed\\\");\\n    }\\n\\n    /**\\n     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n     * on the return value: the return value is optional (but if data is returned, it must not be false).\\n     * @param token The token targeted by the call.\\n     * @param data The call data (encoded using abi.encode or one of its variants).\\n     */\\n    function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n        // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\\n        // the target address contains contract code and also asserts for success in the low-level call.\\n\\n        bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n        if (returndata.length > 0) {\\n            // Return data is optional\\n            require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n        }\\n    }\\n}\\n\"},\"interfaces/IBentoBoxMinimal.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\n\\npragma solidity >=0.8.0;\\n\\nstruct Rebase {\\n    uint128 elastic;\\n    uint128 base;\\n}\\n\\nstruct StrategyData {\\n    uint64 strategyStartDate;\\n    uint64 targetPercentage;\\n    uint128 balance; // the balance of the strategy that BentoBox thinks is in there\\n}\\n\\n/// @notice A rebasing library\\nlibrary RebaseLibrary {\\n    /// @notice Calculates the base value in relationship to `elastic` and `total`.\\n    function toBase(Rebase memory total, uint256 elastic) internal pure returns (uint256 base) {\\n        if (total.elastic == 0) {\\n            base = elastic;\\n        } else {\\n            base = (elastic * total.base) / total.elastic;\\n        }\\n    }\\n\\n    /// @notice Calculates the elastic value in relationship to `base` and `total`.\\n    function toElastic(Rebase memory total, uint256 base) internal pure returns (uint256 elastic) {\\n        if (total.base == 0) {\\n            elastic = base;\\n        } else {\\n            elastic = (base * total.elastic) / total.base;\\n        }\\n    }\\n}\\n\\n/// @notice Minimal BentoBox vault interface.\\n/// @dev `token` is aliased as `address` from `IERC20` for simplicity.\\ninterface IBentoBoxMinimal {\\n    /// @notice Balance per ERC-20 token per account in shares.\\n    function balanceOf(address, address) external view returns (uint256);\\n\\n    /// @dev Helper function to represent an `amount` of `token` in shares.\\n    /// @param token The ERC-20 token.\\n    /// @param amount The `token` amount.\\n    /// @param roundUp If the result `share` should be rounded up.\\n    /// @return share The token amount represented in shares.\\n    function toShare(\\n        address token,\\n        uint256 amount,\\n        bool roundUp\\n    ) external view returns (uint256 share);\\n\\n    /// @dev Helper function to represent shares back into the `token` amount.\\n    /// @param token The ERC-20 token.\\n    /// @param share The amount of shares.\\n    /// @param roundUp If the result should be rounded up.\\n    /// @return amount The share amount back into native representation.\\n    function toAmount(\\n        address token,\\n        uint256 share,\\n        bool roundUp\\n    ) external view returns (uint256 amount);\\n\\n    /// @notice Registers this contract so that users can approve it for BentoBox.\\n    function registerProtocol() external;\\n\\n    /// @notice Deposit an amount of `token` represented in either `amount` or `share`.\\n    /// @param token The ERC-20 token to deposit.\\n    /// @param from which account to pull the tokens.\\n    /// @param to which account to push the tokens.\\n    /// @param amount Token amount in native representation to deposit.\\n    /// @param share Token amount represented in shares to deposit. Takes precedence over `amount`.\\n    /// @return amountOut The amount deposited.\\n    /// @return shareOut The deposited amount represented in shares.\\n    function deposit(\\n        address token,\\n        address from,\\n        address to,\\n        uint256 amount,\\n        uint256 share\\n    ) external payable returns (uint256 amountOut, uint256 shareOut);\\n\\n    /// @notice Withdraws an amount of `token` from a user account.\\n    /// @param token_ The ERC-20 token to withdraw.\\n    /// @param from which user to pull the tokens.\\n    /// @param to which user to push the tokens.\\n    /// @param amount of tokens. Either one of `amount` or `share` needs to be supplied.\\n    /// @param share Like above, but `share` takes precedence over `amount`.\\n    function withdraw(\\n        address token_,\\n        address from,\\n        address to,\\n        uint256 amount,\\n        uint256 share\\n    ) external returns (uint256 amountOut, uint256 shareOut);\\n\\n    /// @notice Transfer shares from a user account to another one.\\n    /// @param token The ERC-20 token to transfer.\\n    /// @param from which user to pull the tokens.\\n    /// @param to which user to push the tokens.\\n    /// @param share The amount of `token` in shares.\\n    function transfer(\\n        address token,\\n        address from,\\n        address to,\\n        uint256 share\\n    ) external;\\n\\n    /// @dev Reads the Rebase `totals`from storage for a given token\\n    function totals(address token) external view returns (Rebase memory total);\\n\\n    function strategyData(address token) external view returns (StrategyData memory total);\\n\\n    /// @dev Approves users' BentoBox assets to a \\\"master\\\" contract.\\n    function setMasterContractApproval(\\n        address user,\\n        address masterContract,\\n        bool approved,\\n        uint8 v,\\n        bytes32 r,\\n        bytes32 s\\n    ) external;\\n\\n    function harvest(\\n        address token,\\n        bool balance,\\n        uint256 maxChangeAmount\\n    ) external;\\n}\\n\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n    /**\\n     * @dev Returns true if `account` is a contract.\\n     *\\n     * [IMPORTANT]\\n     * ====\\n     * It is unsafe to assume that an address for which this function returns\\n     * false is an externally-owned account (EOA) and not a contract.\\n     *\\n     * Among others, `isContract` will return false for the following\\n     * types of addresses:\\n     *\\n     *  - an externally-owned account\\n     *  - a contract in construction\\n     *  - an address where a contract will be created\\n     *  - an address where a contract lived, but was destroyed\\n     * ====\\n     *\\n     * [IMPORTANT]\\n     * ====\\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n     *\\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n     * constructor.\\n     * ====\\n     */\\n    function isContract(address account) internal view returns (bool) {\\n        // This method relies on extcodesize/address.code.length, which returns 0\\n        // for contracts in construction, since the code is only stored at the end\\n        // of the constructor execution.\\n\\n        return account.code.length > 0;\\n    }\\n\\n    /**\\n     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n     * `recipient`, forwarding all available gas and reverting on errors.\\n     *\\n     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n     * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n     * imposed by `transfer`, making them unable to receive funds via\\n     * `transfer`. {sendValue} removes this limitation.\\n     *\\n     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n     *\\n     * IMPORTANT: because control is transferred to `recipient`, care must be\\n     * taken to not create reentrancy vulnerabilities. Consider using\\n     * {ReentrancyGuard} or the\\n     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n     */\\n    function sendValue(address payable recipient, uint256 amount) internal {\\n        require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n        (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n        require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n    }\\n\\n    /**\\n     * @dev Performs a Solidity function call using a low level `call`. A\\n     * plain `call` is an unsafe replacement for a function call: use this\\n     * function instead.\\n     *\\n     * If `target` reverts with a revert reason, it is bubbled up by this\\n     * function (like regular Solidity function calls).\\n     *\\n     * Returns the raw returned data. To convert to the expected return value,\\n     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n     *\\n     * Requirements:\\n     *\\n     * - `target` must be a contract.\\n     * - calling `target` with `data` must not revert.\\n     *\\n     * _Available since v3.1._\\n     */\\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n        return functionCallWithValue(target, data, 0, \\\"Address: low-level call failed\\\");\\n    }\\n\\n    /**\\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n     * `errorMessage` as a fallback revert reason when `target` reverts.\\n     *\\n     * _Available since v3.1._\\n     */\\n    function functionCall(\\n        address target,\\n        bytes memory data,\\n        string memory errorMessage\\n    ) internal returns (bytes memory) {\\n        return functionCallWithValue(target, data, 0, errorMessage);\\n    }\\n\\n    /**\\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n     * but also transferring `value` wei to `target`.\\n     *\\n     * Requirements:\\n     *\\n     * - the calling contract must have an ETH balance of at least `value`.\\n     * - the called Solidity function must be `payable`.\\n     *\\n     * _Available since v3.1._\\n     */\\n    function functionCallWithValue(\\n        address target,\\n        bytes memory data,\\n        uint256 value\\n    ) internal returns (bytes memory) {\\n        return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n    }\\n\\n    /**\\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\\n     *\\n     * _Available since v3.1._\\n     */\\n    function functionCallWithValue(\\n        address target,\\n        bytes memory data,\\n        uint256 value,\\n        string memory errorMessage\\n    ) internal returns (bytes memory) {\\n        require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\\n        return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n    }\\n\\n    /**\\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n     * but performing a static call.\\n     *\\n     * _Available since v3.3._\\n     */\\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n        return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n    }\\n\\n    /**\\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n     * but performing a static call.\\n     *\\n     * _Available since v3.3._\\n     */\\n    function functionStaticCall(\\n        address target,\\n        bytes memory data,\\n        string memory errorMessage\\n    ) internal view returns (bytes memory) {\\n        (bool success, bytes memory returndata) = target.staticcall(data);\\n        return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n    }\\n\\n    /**\\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n     * but performing a delegate call.\\n     *\\n     * _Available since v3.4._\\n     */\\n    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n        return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n    }\\n\\n    /**\\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n     * but performing a delegate call.\\n     *\\n     * _Available since v3.4._\\n     */\\n    function functionDelegateCall(\\n        address target,\\n        bytes memory data,\\n        string memory errorMessage\\n    ) internal returns (bytes memory) {\\n        (bool success, bytes memory returndata) = target.delegatecall(data);\\n        return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n    }\\n\\n    /**\\n     * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\\n     * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\\n     *\\n     * _Available since v4.8._\\n     */\\n    function verifyCallResultFromTarget(\\n        address target,\\n        bool success,\\n        bytes memory returndata,\\n        string memory errorMessage\\n    ) internal view returns (bytes memory) {\\n        if (success) {\\n            if (returndata.length == 0) {\\n                // only check isContract if the call was successful and the return data is empty\\n                // otherwise we already know that it was a contract\\n                require(isContract(target), \\\"Address: call to non-contract\\\");\\n            }\\n            return returndata;\\n        } else {\\n            _revert(returndata, errorMessage);\\n        }\\n    }\\n\\n    /**\\n     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\\n     * revert reason or using the provided one.\\n     *\\n     * _Available since v4.3._\\n     */\\n    function verifyCallResult(\\n        bool success,\\n        bytes memory returndata,\\n        string memory errorMessage\\n    ) internal pure returns (bytes memory) {\\n        if (success) {\\n            return returndata;\\n        } else {\\n            _revert(returndata, errorMessage);\\n        }\\n    }\\n\\n    function _revert(bytes memory returndata, string memory errorMessage) private pure {\\n        // Look for revert reason and bubble it up if present\\n        if (returndata.length > 0) {\\n            // The easiest way to bubble the revert reason is using memory via assembly\\n            /// @solidity memory-safe-assembly\\n            assembly {\\n                let returndata_size := mload(returndata)\\n                revert(add(32, returndata), returndata_size)\\n            }\\n        } else {\\n            revert(errorMessage);\\n        }\\n    }\\n}\\n\"},\"interfaces/IPool.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-or-later\\n\\npragma solidity >=0.5.0;\\npragma experimental ABIEncoderV2;\\n\\n/// @notice Trident pool interface.\\ninterface IPool {\\n    /// @notice Executes a swap from one token to another.\\n    /// @dev The input tokens must've already been sent to the pool.\\n    /// @param data ABI-encoded params that the pool requires.\\n    /// @return finalAmountOut The amount of output tokens that were sent to the user.\\n    function swap(bytes calldata data) external returns (uint256 finalAmountOut);\\n\\n    /// @notice Executes a swap from one token to another with a callback.\\n    /// @dev This function allows borrowing the output tokens and sending the input tokens in the callback.\\n    /// @param data ABI-encoded params that the pool requires.\\n    /// @return finalAmountOut The amount of output tokens that were sent to the user.\\n    function flashSwap(bytes calldata data) external returns (uint256 finalAmountOut);\\n\\n    /// @notice Mints liquidity tokens.\\n    /// @param data ABI-encoded params that the pool requires.\\n    /// @return liquidity The amount of liquidity tokens that were minted for the user.\\n    function mint(bytes calldata data) external returns (uint256 liquidity);\\n\\n    /// @notice Burns liquidity tokens.\\n    /// @dev The input LP tokens must've already been sent to the pool.\\n    /// @param data ABI-encoded params that the pool requires.\\n    /// @return withdrawnAmounts The amount of various output tokens that were sent to the user.\\n    function burn(bytes calldata data) external returns (TokenAmount[] memory withdrawnAmounts);\\n\\n    /// @notice Burns liquidity tokens for a single output token.\\n    /// @dev The input LP tokens must've already been sent to the pool.\\n    /// @param data ABI-encoded params that the pool requires.\\n    /// @return amountOut The amount of output tokens that were sent to the user.\\n    function burnSingle(bytes calldata data) external returns (uint256 amountOut);\\n\\n    /// @return A unique identifier for the pool type.\\n    function poolIdentifier() external pure returns (bytes32);\\n\\n    /// @return An array of tokens supported by the pool.\\n    function getAssets() external view returns (address[] memory);\\n\\n    /// @notice Simulates a trade and returns the expected output.\\n    /// @dev The pool does not need to include a trade simulator directly in itself - it can use a library.\\n    /// @param data ABI-encoded params that the pool requires.\\n    /// @return finalAmountOut The amount of output tokens that will be sent to the user if the trade is executed.\\n    function getAmountOut(bytes calldata data) external view returns (uint256 finalAmountOut);\\n\\n    /// @notice Simulates a trade and returns the expected output.\\n    /// @dev The pool does not need to include a trade simulator directly in itself - it can use a library.\\n    /// @param data ABI-encoded params that the pool requires.\\n    /// @return finalAmountIn The amount of input tokens that are required from the user if the trade is executed.\\n    function getAmountIn(bytes calldata data) external view returns (uint256 finalAmountIn);\\n\\n    /// @dev This event must be emitted on all swaps.\\n    event Swap(address indexed recipient, address indexed tokenIn, address indexed tokenOut, uint256 amountIn, uint256 amountOut);\\n\\n    /// @dev This struct frames output tokens for burns.\\n    struct TokenAmount {\\n        address token;\\n        uint256 amount;\\n    }\\n}\\n\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n    /**\\n     * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n     * another (`to`).\\n     *\\n     * Note that `value` may be zero.\\n     */\\n    event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n    /**\\n     * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n     * a call to {approve}. `value` is the new allowance.\\n     */\\n    event Approval(address indexed owner, address indexed spender, uint256 value);\\n\\n    /**\\n     * @dev Returns the amount of tokens in existence.\\n     */\\n    function totalSupply() external view returns (uint256);\\n\\n    /**\\n     * @dev Returns the amount of tokens owned by `account`.\\n     */\\n    function balanceOf(address account) external view returns (uint256);\\n\\n    /**\\n     * @dev Moves `amount` tokens from the caller's account to `to`.\\n     *\\n     * Returns a boolean value indicating whether the operation succeeded.\\n     *\\n     * Emits a {Transfer} event.\\n     */\\n    function transfer(address to, uint256 amount) external returns (bool);\\n\\n    /**\\n     * @dev Returns the remaining number of tokens that `spender` will be\\n     * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n     * zero by default.\\n     *\\n     * This value changes when {approve} or {transferFrom} are called.\\n     */\\n    function allowance(address owner, address spender) external view returns (uint256);\\n\\n    /**\\n     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n     *\\n     * Returns a boolean value indicating whether the operation succeeded.\\n     *\\n     * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n     * that someone may use both the old and the new allowance by unfortunate\\n     * transaction ordering. One possible solution to mitigate this race\\n     * condition is to first reduce the spender's allowance to 0 and set the\\n     * desired value afterwards:\\n     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n     *\\n     * Emits an {Approval} event.\\n     */\\n    function approve(address spender, uint256 amount) external returns (bool);\\n\\n    /**\\n     * @dev Moves `amount` tokens from `from` to `to` using the\\n     * allowance mechanism. `amount` is then deducted from the caller's\\n     * allowance.\\n     *\\n     * Returns a boolean value indicating whether the operation succeeded.\\n     *\\n     * Emits a {Transfer} event.\\n     */\\n    function transferFrom(\\n        address from,\\n        address to,\\n        uint256 amount\\n    ) external returns (bool);\\n}\\n\"},\"contracts/RouteProcessor2.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\n\\npragma solidity 0.8.10;\\n\\nimport '../interfaces/IUniswapV2Pair.sol';\\nimport '../interfaces/IUniswapV3Pool.sol';\\nimport '../interfaces/ITridentCLPool.sol';\\nimport '../interfaces/IBentoBoxMinimal.sol';\\nimport '../interfaces/IPool.sol';\\nimport '../interfaces/IWETH.sol';\\nimport './InputStream.sol';\\nimport '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';\\n\\naddress constant NATIVE_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\\naddress constant IMPOSSIBLE_POOL_ADDRESS = 0x0000000000000000000000000000000000000001;\\n\\n/// @dev The minimum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MIN_TICK)\\nuint160 constant MIN_SQRT_RATIO = 4295128739;\\n/// @dev The maximum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MAX_TICK)\\nuint160 constant MAX_SQRT_RATIO = 1461446703485210103287273052203988822378723970342;\\n\\n/// @title A route processor for the Sushi Aggregator\\n/// @author Ilya Lyalin\\ncontract RouteProcessor2 {\\n  using SafeERC20 for IERC20;\\n  using InputStream for uint256;\\n\\n  IBentoBoxMinimal public immutable bentoBox;\\n  address private lastCalledPool;\\n\\n  uint private unlocked = 1;\\n  modifier lock() {\\n      require(unlocked == 1, 'RouteProcessor is locked');\\n      unlocked = 2;\\n      _;\\n      unlocked = 1;\\n  }\\n\\n  constructor(address _bentoBox) {\\n    bentoBox = IBentoBoxMinimal(_bentoBox);\\n    lastCalledPool = IMPOSSIBLE_POOL_ADDRESS;\\n  }\\n\\n  /// @notice For native unwrapping\\n  receive() external payable {}\\n\\n  /// @notice Processes the route generated off-chain. Has a lock\\n  /// @param tokenIn Address of the input token\\n  /// @param amountIn Amount of the input token\\n  /// @param tokenOut Address of the output token\\n  /// @param amountOutMin Minimum amount of the output token\\n  /// @return amountOut Actual amount of the output token\\n  function processRoute(\\n    address tokenIn,\\n    uint256 amountIn,\\n    address tokenOut,\\n    uint256 amountOutMin,\\n    address to,\\n    bytes memory route\\n  ) external payable lock returns (uint256 amountOut) {\\n    return processRouteInternal(tokenIn, amountIn, tokenOut, amountOutMin, to, route);\\n  }\\n\\n  /// @notice Transfers some value to <transferValueTo> and then processes the route\\n  /// @param transferValueTo Address where the value should be transferred\\n  /// @param amountValueTransfer How much value to transfer\\n  /// @param tokenIn Address of the input token\\n  /// @param amountIn Amount of the input token\\n  /// @param tokenOut Address of the output token\\n  /// @param amountOutMin Minimum amount of the output token\\n  /// @return amountOut Actual amount of the output token\\n  function transferValueAndprocessRoute(\\n    address payable transferValueTo,\\n    uint256 amountValueTransfer,\\n    address tokenIn,\\n    uint256 amountIn,\\n    address tokenOut,\\n    uint256 amountOutMin,\\n    address to,\\n    bytes memory route\\n  ) external payable lock returns (uint256 amountOut) {\\n    (bool success, bytes memory returnBytes) = transferValueTo.call{value: amountValueTransfer}('');\\n    require(success, string(abi.encodePacked(returnBytes)));\\n    return processRouteInternal(tokenIn, amountIn, tokenOut, amountOutMin, to, route);\\n  }\\n\\n  /// @notice Processes the route generated off-chain\\n  /// @param tokenIn Address of the input token\\n  /// @param amountIn Amount of the input token\\n  /// @param tokenOut Address of the output token\\n  /// @param amountOutMin Minimum amount of the output token\\n  /// @return amountOut Actual amount of the output token\\n  function processRouteInternal(\\n    address tokenIn,\\n    uint256 amountIn,\\n    address tokenOut,\\n    uint256 amountOutMin,\\n    address to,\\n    bytes memory route\\n  ) private returns (uint256 amountOut) {\\n    uint256 balanceInInitial = tokenIn == NATIVE_ADDRESS ? address(this).balance : IERC20(tokenIn).balanceOf(msg.sender);\\n    uint256 balanceOutInitial = tokenOut == NATIVE_ADDRESS ? address(to).balance : IERC20(tokenOut).balanceOf(to);\\n\\n    uint256 stream = InputStream.createStream(route);\\n    while (stream.isNotEmpty()) {\\n      uint8 commandCode = stream.readUint8();\\n      if (commandCode == 1) processMyERC20(stream);\\n      else if (commandCode == 2) processUserERC20(stream, amountIn);\\n      else if (commandCode == 3) processNative(stream);\\n      else if (commandCode == 4) processOnePool(stream);\\n      else if (commandCode == 5) processInsideBento(stream);\\n      else revert('RouteProcessor: Unknown command code');\\n    }\\n\\n    uint256 balanceInFinal = tokenIn == NATIVE_ADDRESS ? address(this).balance : IERC20(tokenIn).balanceOf(msg.sender);\\n    require(balanceInFinal + amountIn >= balanceInInitial, 'RouteProcessor: Minimal imput balance violation');\\n\\n    uint256 balanceOutFinal = tokenOut == NATIVE_ADDRESS ? address(to).balance : IERC20(tokenOut).balanceOf(to);\\n    require(balanceOutFinal >= balanceOutInitial + amountOutMin, 'RouteProcessor: Minimal ouput balance violation');\\n\\n    amountOut = balanceOutFinal - balanceOutInitial;\\n  }\\n\\n  /// @notice Processes native coin: call swap for all pools that swap from native coin\\n  /// @param stream Streamed process program\\n  function processNative(uint256 stream) private {\\n    uint256 amountTotal = address(this).balance;\\n    distributeAndSwap(stream, address(this), NATIVE_ADDRESS, amountTotal);\\n  }\\n\\n  /// @notice Processes ERC20 token from this contract balance:\\n  /// @notice Call swap for all pools that swap from this token\\n  /// @param stream Streamed process program\\n  function processMyERC20(uint256 stream) private {\\n    address token = stream.readAddress();\\n    uint256 amountTotal = IERC20(token).balanceOf(address(this));\\n    unchecked {\\n      if (amountTotal > 0) amountTotal -= 1;     // slot undrain protection\\n    }\\n    distributeAndSwap(stream, address(this), token, amountTotal);\\n  }\\n  \\n  /// @notice Processes ERC20 token from msg.sender balance:\\n  /// @notice Call swap for all pools that swap from this token\\n  /// @param stream Streamed process program\\n  /// @param amountTotal Amount of tokens to take from msg.sender\\n  function processUserERC20(uint256 stream, uint256 amountTotal) private {\\n    address token = stream.readAddress();\\n    distributeAndSwap(stream, msg.sender, token, amountTotal);\\n  }\\n\\n  /// @notice Distributes amountTotal to several pools according to their shares and calls swap for each pool\\n  /// @param stream Streamed process program\\n  /// @param from Where to take liquidity for swap\\n  /// @param tokenIn Input token\\n  /// @param amountTotal Total amount of tokenIn for swaps \\n  function distributeAndSwap(uint256 stream, address from, address tokenIn, uint256 amountTotal) private {\\n    uint8 num = stream.readUint8();\\n    unchecked {\\n      for (uint256 i = 0; i < num; ++i) {\\n        uint16 share = stream.readUint16();\\n        uint256 amount = (amountTotal * share) / 65535;\\n        amountTotal -= amount;\\n        swap(stream, from, tokenIn, amount);\\n      }\\n    }\\n  }\\n\\n  /// @notice Processes ERC20 token for cases when the token has only one output pool\\n  /// @notice In this case liquidity is already at pool balance. This is an optimization\\n  /// @notice Call swap for all pools that swap from this token\\n  /// @param stream Streamed process program\\n  function processOnePool(uint256 stream) private {\\n    address token = stream.readAddress();\\n    swap(stream, address(this), token, 0);\\n  }\\n\\n  /// @notice Processes Bento tokens \\n  /// @notice Call swap for all pools that swap from this token\\n  /// @param stream Streamed process program\\n  function processInsideBento(uint256 stream) private {\\n    address token = stream.readAddress();\\n    uint8 num = stream.readUint8();\\n\\n    uint256 amountTotal = bentoBox.balanceOf(token, address(this));\\n    unchecked {\\n      if (amountTotal > 0) amountTotal -= 1;     // slot undrain protection\\n      for (uint256 i = 0; i < num; ++i) {\\n        uint16 share = stream.readUint16();\\n        uint256 amount = (amountTotal * share) / 65535;\\n        amountTotal -= amount;\\n        swap(stream, address(this), token, amount);\\n      }\\n    }\\n  }\\n\\n  /// @notice Makes swap\\n  /// @param stream Streamed process program\\n  /// @param from Where to take liquidity for swap\\n  /// @param tokenIn Input token\\n  /// @param amountIn Amount of tokenIn to take for swap\\n  function swap(uint256 stream, address from, address tokenIn, uint256 amountIn) private {\\n    uint8 poolType = stream.readUint8();\\n    if (poolType == 0) swapUniV2(stream, from, tokenIn, amountIn);\\n    else if (poolType == 1) swapUniV3(stream, from, tokenIn, amountIn);\\n    else if (poolType == 2) wrapNative(stream, from, tokenIn, amountIn);\\n    else if (poolType == 3) bentoBridge(stream, from, tokenIn, amountIn);\\n    else if (poolType == 4) swapTrident(stream, from, tokenIn, amountIn);\\n    else if (poolType == 5) swapTridentCL(stream, from, tokenIn, amountIn);\\n    else revert('RouteProcessor: Unknown pool type');\\n  }\\n\\n  /// @notice Wraps/unwraps native token\\n  /// @param stream [direction & fake, recipient, wrapToken?]\\n  /// @param from Where to take liquidity for swap\\n  /// @param tokenIn Input token\\n  /// @param amountIn Amount of tokenIn to take for swap\\n  function wrapNative(uint256 stream, address from, address tokenIn, uint256 amountIn) private {\\n    uint8 directionAndFake = stream.readUint8();\\n    address to = stream.readAddress();\\n\\n    if (directionAndFake & 1 == 1) {  // wrap native\\n      address wrapToken = stream.readAddress();\\n      if (directionAndFake & 2 == 0) IWETH(wrapToken).deposit{value: amountIn}();\\n      if (to != address(this)) IERC20(wrapToken).safeTransfer(to, amountIn);\\n    } else { // unwrap native\\n      if (directionAndFake & 2 == 0) {\\n        if (from != address(this)) IERC20(tokenIn).safeTransferFrom(from, address(this), amountIn);\\n        IWETH(tokenIn).withdraw(amountIn);\\n      }\\n      payable(to).transfer(address(this).balance);\\n    }\\n  }\\n\\n  /// @notice Bridge/unbridge tokens to/from Bento\\n  /// @param stream [direction, recipient]\\n  /// @param from Where to take liquidity for swap\\n  /// @param tokenIn Input token\\n  /// @param amountIn Amount of tokenIn to take for swap\\n  function bentoBridge(uint256 stream, address from, address tokenIn, uint256 amountIn) private {\\n    uint8 direction = stream.readUint8();\\n    address to = stream.readAddress();\\n\\n    if (direction > 0) {  // outside to Bento\\n      // deposit to arbitrary recipient is possible only from address(bentoBox)\\n      if (amountIn != 0) {\\n        if (from == address(this)) IERC20(tokenIn).safeTransfer(address(bentoBox), amountIn);\\n        else IERC20(tokenIn).safeTransferFrom(from, address(bentoBox), amountIn);\\n      } else {\\n        // tokens already are at address(bentoBox)\\n        amountIn = IERC20(tokenIn).balanceOf(address(bentoBox)) +\\n        bentoBox.strategyData(tokenIn).balance -\\n        bentoBox.totals(tokenIn).elastic;\\n      }\\n      bentoBox.deposit(tokenIn, address(bentoBox), to, amountIn, 0);\\n    } else { // Bento to outside\\n      if (amountIn > 0) {\\n        bentoBox.transfer(tokenIn, from, address(this), amountIn);\\n      } else amountIn = bentoBox.balanceOf(tokenIn, address(this));\\n      bentoBox.withdraw(tokenIn, address(this), to, 0, amountIn);\\n    }\\n  }\\n\\n  /// @notice UniswapV2 pool swap\\n  /// @param stream [pool, direction, recipient]\\n  /// @param from Where to take liquidity for swap\\n  /// @param tokenIn Input token\\n  /// @param amountIn Amount of tokenIn to take for swap\\n  function swapUniV2(uint256 stream, address from, address tokenIn, uint256 amountIn) private {\\n    address pool = stream.readAddress();\\n    uint8 direction = stream.readUint8();\\n    address to = stream.readAddress();\\n\\n    (uint256 r0, uint256 r1, ) = IUniswapV2Pair(pool).getReserves();\\n    require(r0 > 0 && r1 > 0, 'Wrong pool reserves');\\n    (uint256 reserveIn, uint256 reserveOut) = direction == 1 ? (r0, r1) : (r1, r0);\\n\\n    if (amountIn != 0) {\\n      if (from == address(this)) IERC20(tokenIn).safeTransfer(pool, amountIn);\\n      else IERC20(tokenIn).safeTransferFrom(from, pool, amountIn);\\n    } else amountIn = IERC20(tokenIn).balanceOf(pool) - reserveIn;  // tokens already were transferred\\n\\n    uint256 amountInWithFee = amountIn * 997;\\n    uint256 amountOut = (amountInWithFee * reserveOut) / (reserveIn * 1000 + amountInWithFee);\\n    (uint256 amount0Out, uint256 amount1Out) = direction == 1 ? (uint256(0), amountOut) : (amountOut, uint256(0));\\n    IUniswapV2Pair(pool).swap(amount0Out, amount1Out, to, new bytes(0));\\n  }\\n\\n  /// @notice Trident pool swap\\n  /// @param stream [pool, swapData]\\n  /// @param from Where to take liquidity for swap\\n  /// @param tokenIn Input token\\n  /// @param amountIn Amount of tokenIn to take for swap\\n  function swapTrident(uint256 stream, address from, address tokenIn, uint256 amountIn) private {\\n    address pool = stream.readAddress();\\n    bytes memory swapData = stream.readBytes();\\n\\n    if (amountIn != 0) {\\n      bentoBox.transfer(tokenIn, from, pool, amountIn);\\n    }\\n    \\n    IPool(pool).swap(swapData);\\n  }\\n\\n  /// @notice UniswapV3 pool swap\\n  /// @param stream [pool, direction, recipient]\\n  /// @param from Where to take liquidity for swap\\n  /// @param tokenIn Input token\\n  /// @param amountIn Amount of tokenIn to take for swap\\n  function swapUniV3(uint256 stream, address from, address tokenIn, uint256 amountIn) private {\\n    address pool = stream.readAddress();\\n    bool zeroForOne = stream.readUint8() > 0;\\n    address recipient = stream.readAddress();\\n\\n    lastCalledPool = pool;\\n    IUniswapV3Pool(pool).swap(\\n      recipient,\\n      zeroForOne,\\n      int256(amountIn),\\n      zeroForOne ? MIN_SQRT_RATIO + 1 : MAX_SQRT_RATIO - 1,\\n      abi.encode(tokenIn, from)\\n    );\\n    require(lastCalledPool == IMPOSSIBLE_POOL_ADDRESS, 'RouteProcessor.swapUniV3: unexpected'); // Just to be sure\\n  }\\n\\n  /// @notice Called to `msg.sender` after executing a swap via IUniswapV3Pool#swap.\\n  /// @dev In the implementation you must pay the pool tokens owed for the swap.\\n  /// The caller of this method must be checked to be a UniswapV3Pool deployed by the canonical UniswapV3Factory.\\n  /// amount0Delta and amount1Delta can both be 0 if no tokens were swapped.\\n  /// @param amount0Delta The amount of token0 that was sent (negative) or must be received (positive) by the pool by\\n  /// the end of the swap. If positive, the callback must send that amount of token0 to the pool.\\n  /// @param amount1Delta The amount of token1 that was sent (negative) or must be received (positive) by the pool by\\n  /// the end of the swap. If positive, the callback must send that amount of token1 to the pool.\\n  /// @param data Any data passed through by the caller via the IUniswapV3PoolActions#swap call\\n  function uniswapV3SwapCallback(\\n    int256 amount0Delta,\\n    int256 amount1Delta,\\n    bytes calldata data\\n  ) external {\\n    require(msg.sender == lastCalledPool, 'RouteProcessor.uniswapV3SwapCallback: call from unknown source');\\n    lastCalledPool = IMPOSSIBLE_POOL_ADDRESS;\\n    (address tokenIn, address from) = abi.decode(data, (address, address));\\n    int256 amount = amount0Delta > 0 ? amount0Delta : amount1Delta;\\n    require(amount > 0, 'RouteProcessor.uniswapV3SwapCallback: not positive amount');\\n\\n    if (from == address(this)) IERC20(tokenIn).safeTransfer(msg.sender, uint256(amount));\\n     else IERC20(tokenIn).safeTransferFrom(from, msg.sender, uint256(amount));\\n  }\\n\\n  /// @notice TridentCL pool swap\\n  /// @param stream [pool, direction, recipient]\\n  /// @param from Where to take liquidity for swap\\n  /// @param tokenIn Input token\\n  /// @param amountIn Amount of tokenIn to take for swap\\n  function swapTridentCL(uint256 stream, address from, address tokenIn, uint256 amountIn) private {\\n    address pool = stream.readAddress();\\n    bool zeroForOne = stream.readUint8() > 0;\\n    address recipient = stream.readAddress();\\n\\n    lastCalledPool = pool;\\n    ITridentCLPool(pool).swap(\\n      recipient,\\n      zeroForOne,\\n      int256(amountIn),\\n      zeroForOne ? MIN_SQRT_RATIO + 1 : MAX_SQRT_RATIO - 1,\\n      false,\\n      abi.encode(tokenIn, from)\\n    );\\n    require(lastCalledPool == IMPOSSIBLE_POOL_ADDRESS, 'RouteProcessor.swapTridentCL: unexpected'); // Just to be sure\\n  }\\n\\n  /// @notice Called to `msg.sender` after executing a swap via ITridentCLPool#swap.\\n  /// @dev In the implementation you must pay the pool tokens owed for the swap.\\n  /// The caller of this method must be checked to be a TridentCLPool deployed by the canonical TridentCLFactory.\\n  /// amount0Delta and amount1Delta can both be 0 if no tokens were swapped.\\n  /// @param amount0Delta The amount of token0 that was sent (negative) or must be received (positive) by the pool by\\n  /// the end of the swap. If positive, the callback must send that amount of token0 to the pool.\\n  /// @param amount1Delta The amount of token1 that was sent (negative) or must be received (positive) by the pool by\\n  /// the end of the swap. If positive, the callback must send that amount of token1 to the pool.\\n  /// @param data Any data passed through by the caller via the ITridentCLPoolActions#swap call\\n  function tridentCLSwapCallback(\\n    int256 amount0Delta,\\n    int256 amount1Delta,\\n    bytes calldata data\\n  ) external {\\n    require(msg.sender == lastCalledPool, 'RouteProcessor.TridentCLSwapCallback: call from unknown source');\\n    lastCalledPool = IMPOSSIBLE_POOL_ADDRESS;\\n    (address tokenIn, address from) = abi.decode(data, (address, address));\\n    int256 amount = amount0Delta > 0 ? amount0Delta : amount1Delta;\\n    require(amount > 0, 'RouteProcessor.TridentCLSwapCallback: not positive amount');\\n\\n    if (from == address(this)) IERC20(tokenIn).safeTransfer(msg.sender, uint256(amount));\\n     else IERC20(tokenIn).safeTransferFrom(from, msg.sender, uint256(amount));\\n  }\\n}\\n\"},\"interfaces/ITridentCLPool.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-or-later\\n\\npragma solidity 0.8.10;\\n\\ninterface ITridentCLPool {\\n  function token0() external returns (address);\\n  function token1() external returns (address);\\n\\n  function swap(\\n    address recipient,\\n    bool zeroForOne,\\n    int256 amountSpecified,\\n    uint160 sqrtPriceLimitX96,\\n    bool unwrapBento,\\n    bytes calldata data\\n  ) external returns (int256 amount0, int256 amount1);\\n}\\n\"},\"@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\\n *\\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\\n * need to send a transaction, and thus is not required to hold Ether at all.\\n */\\ninterface IERC20Permit {\\n    /**\\n     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\\n     * given ``owner``'s signed approval.\\n     *\\n     * IMPORTANT: The same issues {IERC20-approve} has related to transaction\\n     * ordering also apply here.\\n     *\\n     * Emits an {Approval} event.\\n     *\\n     * Requirements:\\n     *\\n     * - `spender` cannot be the zero address.\\n     * - `deadline` must be a timestamp in the future.\\n     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\\n     * over the EIP712-formatted function arguments.\\n     * - the signature must use ``owner``'s current nonce (see {nonces}).\\n     *\\n     * For more information on the signature format, see the\\n     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\\n     * section].\\n     */\\n    function permit(\\n        address owner,\\n        address spender,\\n        uint256 value,\\n        uint256 deadline,\\n        uint8 v,\\n        bytes32 r,\\n        bytes32 s\\n    ) external;\\n\\n    /**\\n     * @dev Returns the current nonce for `owner`. This value must be\\n     * included whenever a signature is generated for {permit}.\\n     *\\n     * Every successful call to {permit} increases ``owner``'s nonce by one. This\\n     * prevents a signature from being used multiple times.\\n     */\\n    function nonces(address owner) external view returns (uint256);\\n\\n    /**\\n     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\\n     */\\n    // solhint-disable-next-line func-name-mixedcase\\n    function DOMAIN_SEPARATOR() external view returns (bytes32);\\n}\\n\"},\"interfaces/IUniswapV2Pair.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0\\n\\npragma solidity >=0.5.0;\\n\\ninterface IUniswapV2Pair {\\n    event Approval(address indexed owner, address indexed spender, uint value);\\n    event Transfer(address indexed from, address indexed to, uint value);\\n\\n    function name() external pure returns (string memory);\\n    function symbol() external pure returns (string memory);\\n    function decimals() external pure returns (uint8);\\n    function totalSupply() external view returns (uint);\\n    function balanceOf(address owner) external view returns (uint);\\n    function allowance(address owner, address spender) external view returns (uint);\\n\\n    function approve(address spender, uint value) external returns (bool);\\n    function transfer(address to, uint value) external returns (bool);\\n    function transferFrom(address from, address to, uint value) external returns (bool);\\n\\n    function DOMAIN_SEPARATOR() external view returns (bytes32);\\n    function PERMIT_TYPEHASH() external pure returns (bytes32);\\n    function nonces(address owner) external view returns (uint);\\n\\n    function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external;\\n\\n    event Mint(address indexed sender, uint amount0, uint amount1);\\n    event Burn(address indexed sender, uint amount0, uint amount1, address indexed to);\\n    event Swap(\\n        address indexed sender,\\n        uint amount0In,\\n        uint amount1In,\\n        uint amount0Out,\\n        uint amount1Out,\\n        address indexed to\\n    );\\n    event Sync(uint112 reserve0, uint112 reserve1);\\n\\n    function MINIMUM_LIQUIDITY() external pure returns (uint);\\n    function factory() external view returns (address);\\n    function token0() external view returns (address);\\n    function token1() external view returns (address);\\n    function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);\\n    function price0CumulativeLast() external view returns (uint);\\n    function price1CumulativeLast() external view returns (uint);\\n    function kLast() external view returns (uint);\\n\\n    function mint(address to) external returns (uint liquidity);\\n    function burn(address to) external returns (uint amount0, uint amount1);\\n    function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external;\\n    function skim(address to) external;\\n    function sync() external;\\n\\n    function initialize(address, address) external;\\n}\"},\"interfaces/IUniswapV3Pool.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-or-later\\n\\npragma solidity 0.8.10;\\n\\ninterface IUniswapV3Pool {\\n  function token0() external returns (address);\\n  function token1() external returns (address);\\n\\n  function swap(\\n    address recipient,\\n    bool zeroForOne,\\n    int256 amountSpecified,\\n    uint160 sqrtPriceLimitX96,\\n    bytes calldata data\\n  ) external returns (int256 amount0, int256 amount1);\\n}\\n\"},\"interfaces/IWETH.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-or-later\\n\\npragma solidity 0.8.10;\\n\\ninterface IWETH {\\n  function deposit() external payable;\\n\\n  function transfer(address to, uint256 value) external returns (bool);\\n\\n  function withdraw(uint256) external;\\n}\\n\"}},\"settings\":{\"optimizer\":{\"enabled\":true,\"runs\":10000000},\"outputSelection\":{\"*\":{\"*\":[\"evm.bytecode\",\"evm.deployedBytecode\",\"devdoc\",\"userdoc\",\"metadata\",\"abi\"]}},\"metadata\":{\"useLiteralContent\":true},\"libraries\":{}}},\"ABI\":\"[{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"_bentoBox\\\",\\\"type\\\":\\\"address\\\"}],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"constructor\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"bentoBox\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"contract IBentoBoxMinimal\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"address\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"tokenIn\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"amountIn\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"tokenOut\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"amountOutMin\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"to\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"bytes\\\",\\\"name\\\":\\\"route\\\",\\\"type\\\":\\\"bytes\\\"}],\\\"name\\\":\\\"processRoute\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"amountOut\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"payable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address payable\\\",\\\"name\\\":\\\"transferValueTo\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"amountValueTransfer\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"tokenIn\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"amountIn\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"tokenOut\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"amountOutMin\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"to\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"bytes\\\",\\\"name\\\":\\\"route\\\",\\\"type\\\":\\\"bytes\\\"}],\\\"name\\\":\\\"transferValueAndprocessRoute\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"amountOut\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"payable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"int256\\\",\\\"name\\\":\\\"amount0Delta\\\",\\\"type\\\":\\\"int256\\\"},{\\\"internalType\\\":\\\"int256\\\",\\\"name\\\":\\\"amount1Delta\\\",\\\"type\\\":\\\"int256\\\"},{\\\"internalType\\\":\\\"bytes\\\",\\\"name\\\":\\\"data\\\",\\\"type\\\":\\\"bytes\\\"}],\\\"name\\\":\\\"tridentCLSwapCallback\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"int256\\\",\\\"name\\\":\\\"amount0Delta\\\",\\\"type\\\":\\\"int256\\\"},{\\\"internalType\\\":\\\"int256\\\",\\\"name\\\":\\\"amount1Delta\\\",\\\"type\\\":\\\"int256\\\"},{\\\"internalType\\\":\\\"bytes\\\",\\\"name\\\":\\\"data\\\",\\\"type\\\":\\\"bytes\\\"}],\\\"name\\\":\\\"uniswapV3SwapCallback\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"stateMutability\\\":\\\"payable\\\",\\\"type\\\":\\\"receive\\\"}]\",\"ContractName\":\"RouteProcessor2\",\"CompilerVersion\":\"v0.8.10+commit.fc410830\",\"OptimizationUsed\":1,\"Runs\":10000000,\"ConstructorArguments\":\"0x000000000000000000000000f5bce5077908a1b7370b9ae04adc565ebd643966\",\"EVMVersion\":\"Default\",\"Library\":\"\",\"LicenseType\":\"\",\"Proxy\":0,\"SwarmSource\":\"\"}]"
  },
  {
    "path": "testdata/etherscan/0x35Fb958109b70799a8f9Bc2a8b1Ee4cC62034193/creation_data.json",
    "content": "{\"contractAddress\":\"0x35fb958109b70799a8f9bc2a8b1ee4cc62034193\",\"contractCreator\":\"0x3e32324277e96b69750bc6f7c4ba27e122413e07\",\"txHash\":\"0x41e3517f8262b55e1eb1707ba0760b603a70e89ea4a86eff56072fcc80c3d0a1\"}"
  },
  {
    "path": "testdata/etherscan/0x35Fb958109b70799a8f9Bc2a8b1Ee4cC62034193/metadata.json",
    "content": "[{\"SourceCode\":\"/**\\r\\n *Submitted for verification at Etherscan.io on 2022-02-19\\r\\n*/\\r\\n\\r\\n/**\\r\\n *Submitted for verification at Etherscan.io on 2022-02-18\\r\\n*/\\r\\n\\r\\n/**\\r\\n *Submitted for verification at Etherscan.io on 2022-02-14\\r\\n*/\\r\\n\\r\\n/**\\r\\n *Submitted for verification at Etherscan.io on 2022-02-10\\r\\n*/\\r\\n\\r\\n/**\\r\\n *Submitted for verification at Etherscan.io on 2022-02-09\\r\\n*/\\r\\n\\r\\n/**\\r\\n *Submitted for verification at Etherscan.io on 2022-02-08\\r\\n*/\\r\\n\\r\\n/**\\r\\n *Submitted for verification at Etherscan.io on 2022-02-05\\r\\n*/\\r\\n\\r\\n/**\\r\\n *Submitted for verification at Etherscan.io on 2022-01-22\\r\\n*/\\r\\n\\r\\n// SPDX-License-Identifier: UNLICENSED\\r\\n/*\\r\\nmade by cty0312\\r\\n2022.01.22\\r\\n**/\\r\\n\\r\\npragma solidity >=0.7.0 <0.9.0;\\r\\n\\r\\nlibrary StringsUpgradeable {\\r\\n    bytes16 private constant _HEX_SYMBOLS = \\\"0123456789abcdef\\\";\\r\\n\\r\\n    /**\\r\\n     * @dev Converts a `uint256` to its ASCII `string` decimal representation.\\r\\n     */\\r\\n    function toString(uint256 value) internal pure returns (string memory) {\\r\\n        // Inspired by OraclizeAPI's implementation - MIT licence\\r\\n        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\\r\\n\\r\\n        if (value == 0) {\\r\\n            return \\\"0\\\";\\r\\n        }\\r\\n        uint256 temp = value;\\r\\n        uint256 digits;\\r\\n        while (temp != 0) {\\r\\n            digits++;\\r\\n            temp /= 10;\\r\\n        }\\r\\n        bytes memory buffer = new bytes(digits);\\r\\n        while (value != 0) {\\r\\n            digits -= 1;\\r\\n            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\\r\\n            value /= 10;\\r\\n        }\\r\\n        return string(buffer);\\r\\n    }\\r\\n\\r\\n    /**\\r\\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\\r\\n     */\\r\\n    function toHexString(uint256 value) internal pure returns (string memory) {\\r\\n        if (value == 0) {\\r\\n            return \\\"0x00\\\";\\r\\n        }\\r\\n        uint256 temp = value;\\r\\n        uint256 length = 0;\\r\\n        while (temp != 0) {\\r\\n            length++;\\r\\n            temp >>= 8;\\r\\n        }\\r\\n        return toHexString(value, length);\\r\\n    }\\r\\n\\r\\n    /**\\r\\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\\r\\n     */\\r\\n    function toHexString(uint256 value, uint256 length)\\r\\n        internal\\r\\n        pure\\r\\n        returns (string memory)\\r\\n    {\\r\\n        bytes memory buffer = new bytes(2 * length + 2);\\r\\n        buffer[0] = \\\"0\\\";\\r\\n        buffer[1] = \\\"x\\\";\\r\\n        for (uint256 i = 2 * length + 1; i > 1; --i) {\\r\\n            buffer[i] = _HEX_SYMBOLS[value & 0xf];\\r\\n            value >>= 4;\\r\\n        }\\r\\n        require(value == 0, \\\"Strings: hex length insufficient\\\");\\r\\n        return string(buffer);\\r\\n    }\\r\\n}\\r\\n\\r\\nlibrary AddressUpgradeable {\\r\\n    /**\\r\\n     * @dev Returns true if `account` is a contract.\\r\\n     *\\r\\n     * [IMPORTANT]\\r\\n     * ====\\r\\n     * It is unsafe to assume that an address for which this function returns\\r\\n     * false is an externally-owned account (EOA) and not a contract.\\r\\n     *\\r\\n     * Among others, `isContract` will return false for the following\\r\\n     * types of addresses:\\r\\n     *\\r\\n     *  - an externally-owned account\\r\\n     *  - a contract in construction\\r\\n     *  - an address where a contract will be created\\r\\n     *  - an address where a contract lived, but was destroyed\\r\\n     * ====\\r\\n     */\\r\\n    function isContract(address account) internal view returns (bool) {\\r\\n        // This method relies on extcodesize, which returns 0 for contracts in\\r\\n        // construction, since the code is only stored at the end of the\\r\\n        // constructor execution.\\r\\n\\r\\n        uint256 size;\\r\\n        assembly {\\r\\n            size := extcodesize(account)\\r\\n        }\\r\\n        return size > 0;\\r\\n    }\\r\\n\\r\\n    /**\\r\\n     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\r\\n     * `recipient`, forwarding all available gas and reverting on errors.\\r\\n     *\\r\\n     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\r\\n     * of certain opcodes, possibly making contracts go over the 2300 gas limit\\r\\n     * imposed by `transfer`, making them unable to receive funds via\\r\\n     * `transfer`. {sendValue} removes this limitation.\\r\\n     *\\r\\n     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\r\\n     *\\r\\n     * IMPORTANT: because control is transferred to `recipient`, care must be\\r\\n     * taken to not create reentrancy vulnerabilities. Consider using\\r\\n     * {ReentrancyGuard} or the\\r\\n     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\r\\n     */\\r\\n    function sendValue(address payable recipient, uint256 amount) internal {\\r\\n        require(\\r\\n            address(this).balance >= amount,\\r\\n            \\\"Address: insufficient balance\\\"\\r\\n        );\\r\\n\\r\\n        (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\r\\n        require(\\r\\n            success,\\r\\n            \\\"Address: unable to send value, recipient may have reverted\\\"\\r\\n        );\\r\\n    }\\r\\n\\r\\n    /**\\r\\n     * @dev Performs a Solidity function call using a low level `call`. A\\r\\n     * plain `call` is an unsafe replacement for a function call: use this\\r\\n     * function instead.\\r\\n     *\\r\\n     * If `target` reverts with a revert reason, it is bubbled up by this\\r\\n     * function (like regular Solidity function calls).\\r\\n     *\\r\\n     * Returns the raw returned data. To convert to the expected return value,\\r\\n     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\r\\n     *\\r\\n     * Requirements:\\r\\n     *\\r\\n     * - `target` must be a contract.\\r\\n     * - calling `target` with `data` must not revert.\\r\\n     *\\r\\n     * _Available since v3.1._\\r\\n     */\\r\\n    function functionCall(address target, bytes memory data)\\r\\n        internal\\r\\n        returns (bytes memory)\\r\\n    {\\r\\n        return functionCall(target, data, \\\"Address: low-level call failed\\\");\\r\\n    }\\r\\n\\r\\n    /**\\r\\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\r\\n     * `errorMessage` as a fallback revert reason when `target` reverts.\\r\\n     *\\r\\n     * _Available since v3.1._\\r\\n     */\\r\\n    function functionCall(\\r\\n        address target,\\r\\n        bytes memory data,\\r\\n        string memory errorMessage\\r\\n    ) internal returns (bytes memory) {\\r\\n        return functionCallWithValue(target, data, 0, errorMessage);\\r\\n    }\\r\\n\\r\\n    /**\\r\\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\r\\n     * but also transferring `value` wei to `target`.\\r\\n     *\\r\\n     * Requirements:\\r\\n     *\\r\\n     * - the calling contract must have an ETH balance of at least `value`.\\r\\n     * - the called Solidity function must be `payable`.\\r\\n     *\\r\\n     * _Available since v3.1._\\r\\n     */\\r\\n    function functionCallWithValue(\\r\\n        address target,\\r\\n        bytes memory data,\\r\\n        uint256 value\\r\\n    ) internal returns (bytes memory) {\\r\\n        return\\r\\n            functionCallWithValue(\\r\\n                target,\\r\\n                data,\\r\\n                value,\\r\\n                \\\"Address: low-level call with value failed\\\"\\r\\n            );\\r\\n    }\\r\\n\\r\\n    /**\\r\\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\r\\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\\r\\n     *\\r\\n     * _Available since v3.1._\\r\\n     */\\r\\n    function functionCallWithValue(\\r\\n        address target,\\r\\n        bytes memory data,\\r\\n        uint256 value,\\r\\n        string memory errorMessage\\r\\n    ) internal returns (bytes memory) {\\r\\n        require(\\r\\n            address(this).balance >= value,\\r\\n            \\\"Address: insufficient balance for call\\\"\\r\\n        );\\r\\n        require(isContract(target), \\\"Address: call to non-contract\\\");\\r\\n\\r\\n        (bool success, bytes memory returndata) = target.call{value: value}(\\r\\n            data\\r\\n        );\\r\\n        return verifyCallResult(success, returndata, errorMessage);\\r\\n    }\\r\\n\\r\\n    /**\\r\\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\r\\n     * but performing a static call.\\r\\n     *\\r\\n     * _Available since v3.3._\\r\\n     */\\r\\n    function functionStaticCall(address target, bytes memory data)\\r\\n        internal\\r\\n        view\\r\\n        returns (bytes memory)\\r\\n    {\\r\\n        return\\r\\n            functionStaticCall(\\r\\n                target,\\r\\n                data,\\r\\n                \\\"Address: low-level static call failed\\\"\\r\\n            );\\r\\n    }\\r\\n\\r\\n    /**\\r\\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\r\\n     * but performing a static call.\\r\\n     *\\r\\n     * _Available since v3.3._\\r\\n     */\\r\\n    function functionStaticCall(\\r\\n        address target,\\r\\n        bytes memory data,\\r\\n        string memory errorMessage\\r\\n    ) internal view returns (bytes memory) {\\r\\n        require(isContract(target), \\\"Address: static call to non-contract\\\");\\r\\n\\r\\n        (bool success, bytes memory returndata) = target.staticcall(data);\\r\\n        return verifyCallResult(success, returndata, errorMessage);\\r\\n    }\\r\\n\\r\\n    /**\\r\\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\r\\n     * revert reason using the provided one.\\r\\n     *\\r\\n     * _Available since v4.3._\\r\\n     */\\r\\n    function verifyCallResult(\\r\\n        bool success,\\r\\n        bytes memory returndata,\\r\\n        string memory errorMessage\\r\\n    ) internal pure returns (bytes memory) {\\r\\n        if (success) {\\r\\n            return returndata;\\r\\n        } else {\\r\\n            // Look for revert reason and bubble it up if present\\r\\n            if (returndata.length > 0) {\\r\\n                // The easiest way to bubble the revert reason is using memory via assembly\\r\\n\\r\\n                assembly {\\r\\n                    let returndata_size := mload(returndata)\\r\\n                    revert(add(32, returndata), returndata_size)\\r\\n                }\\r\\n            } else {\\r\\n                revert(errorMessage);\\r\\n            }\\r\\n        }\\r\\n    }\\r\\n}\\r\\n\\r\\nlibrary SafeMathUpgradeable {\\r\\n    /**\\r\\n     * @dev Returns the addition of two unsigned integers, reverting on\\r\\n     * overflow.\\r\\n     *\\r\\n     * Counterpart to Solidity's `+` operator.\\r\\n     *\\r\\n     * Requirements:\\r\\n     *\\r\\n     * - Addition cannot overflow.\\r\\n     */\\r\\n    function add(uint256 a, uint256 b) internal pure returns (uint256) {\\r\\n        uint256 c = a + b;\\r\\n        require(c >= a, \\\"SafeMath: addition overflow\\\");\\r\\n\\r\\n        return c;\\r\\n    }\\r\\n\\r\\n    /**\\r\\n     * @dev Returns the subtraction of two unsigned integers, reverting on\\r\\n     * overflow (when the result is negative).\\r\\n     *\\r\\n     * Counterpart to Solidity's `-` operator.\\r\\n     *\\r\\n     * Requirements:\\r\\n     *\\r\\n     * - Subtraction cannot overflow.\\r\\n     */\\r\\n    function sub(uint256 a, uint256 b) internal pure returns (uint256) {\\r\\n        return sub(a, b, \\\"SafeMath: subtraction overflow\\\");\\r\\n    }\\r\\n\\r\\n    /**\\r\\n     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\\r\\n     * overflow (when the result is negative).\\r\\n     *\\r\\n     * Counterpart to Solidity's `-` operator.\\r\\n     *\\r\\n     * Requirements:\\r\\n     *\\r\\n     * - Subtraction cannot overflow.\\r\\n     */\\r\\n    function sub(\\r\\n        uint256 a,\\r\\n        uint256 b,\\r\\n        string memory errorMessage\\r\\n    ) internal pure returns (uint256) {\\r\\n        require(b <= a, errorMessage);\\r\\n        uint256 c = a - b;\\r\\n\\r\\n        return c;\\r\\n    }\\r\\n\\r\\n    /**\\r\\n     * @dev Returns the multiplication of two unsigned integers, reverting on\\r\\n     * overflow.\\r\\n     *\\r\\n     * Counterpart to Solidity's `*` operator.\\r\\n     *\\r\\n     * Requirements:\\r\\n     *\\r\\n     * - Multiplication cannot overflow.\\r\\n     */\\r\\n    function mul(uint256 a, uint256 b) internal pure returns (uint256) {\\r\\n        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\\r\\n        // benefit is lost if 'b' is also tested.\\r\\n        // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\\r\\n        if (a == 0) {\\r\\n            return 0;\\r\\n        }\\r\\n\\r\\n        uint256 c = a * b;\\r\\n        require(c / a == b, \\\"SafeMath: multiplication overflow\\\");\\r\\n\\r\\n        return c;\\r\\n    }\\r\\n\\r\\n    /**\\r\\n     * @dev Returns the integer division of two unsigned integers. Reverts on\\r\\n     * division by zero. The result is rounded towards zero.\\r\\n     *\\r\\n     * Counterpart to Solidity's `/` operator. Note: this function uses a\\r\\n     * `revert` opcode (which leaves remaining gas untouched) while Solidity\\r\\n     * uses an invalid opcode to revert (consuming all remaining gas).\\r\\n     *\\r\\n     * Requirements:\\r\\n     *\\r\\n     * - The divisor cannot be zero.\\r\\n     */\\r\\n    function div(uint256 a, uint256 b) internal pure returns (uint256) {\\r\\n        return div(a, b, \\\"SafeMath: division by zero\\\");\\r\\n    }\\r\\n\\r\\n    /**\\r\\n     * @dev Returns the integer division of two unsigned integers. Reverts with custom message on\\r\\n     * division by zero. The result is rounded towards zero.\\r\\n     *\\r\\n     * Counterpart to Solidity's `/` operator. Note: this function uses a\\r\\n     * `revert` opcode (which leaves remaining gas untouched) while Solidity\\r\\n     * uses an invalid opcode to revert (consuming all remaining gas).\\r\\n     *\\r\\n     * Requirements:\\r\\n     *\\r\\n     * - The divisor cannot be zero.\\r\\n     */\\r\\n    function div(\\r\\n        uint256 a,\\r\\n        uint256 b,\\r\\n        string memory errorMessage\\r\\n    ) internal pure returns (uint256) {\\r\\n        require(b > 0, errorMessage);\\r\\n        uint256 c = a / b;\\r\\n        // assert(a == b * c + a % b); // There is no case in which this doesn't hold\\r\\n\\r\\n        return c;\\r\\n    }\\r\\n\\r\\n    /**\\r\\n     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\r\\n     * Reverts when dividing by zero.\\r\\n     *\\r\\n     * Counterpart to Solidity's `%` operator. This function uses a `revert`\\r\\n     * opcode (which leaves remaining gas untouched) while Solidity uses an\\r\\n     * invalid opcode to revert (consuming all remaining gas).\\r\\n     *\\r\\n     * Requirements:\\r\\n     *\\r\\n     * - The divisor cannot be zero.\\r\\n     */\\r\\n    function mod(uint256 a, uint256 b) internal pure returns (uint256) {\\r\\n        return mod(a, b, \\\"SafeMath: modulo by zero\\\");\\r\\n    }\\r\\n\\r\\n    /**\\r\\n     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\r\\n     * Reverts with custom message when dividing by zero.\\r\\n     *\\r\\n     * Counterpart to Solidity's `%` operator. This function uses a `revert`\\r\\n     * opcode (which leaves remaining gas untouched) while Solidity uses an\\r\\n     * invalid opcode to revert (consuming all remaining gas).\\r\\n     *\\r\\n     * Requirements:\\r\\n     *\\r\\n     * - The divisor cannot be zero.\\r\\n     */\\r\\n    function mod(\\r\\n        uint256 a,\\r\\n        uint256 b,\\r\\n        string memory errorMessage\\r\\n    ) internal pure returns (uint256) {\\r\\n        require(b != 0, errorMessage);\\r\\n        return a % b;\\r\\n    }\\r\\n}\\r\\n\\r\\nabstract contract Initializable {\\r\\n    /**\\r\\n     * @dev Indicates that the contract has been initialized.\\r\\n     */\\r\\n    bool private _initialized;\\r\\n\\r\\n    /**\\r\\n     * @dev Indicates that the contract is in the process of being initialized.\\r\\n     */\\r\\n    bool private _initializing;\\r\\n\\r\\n    /**\\r\\n     * @dev Modifier to protect an initializer function from being invoked twice.\\r\\n     */\\r\\n    modifier initializer() {\\r\\n        // If the contract is initializing we ignore whether _initialized is set in order to support multiple\\r\\n        // inheritance patterns, but we only do this in the context of a constructor, because in other contexts the\\r\\n        // contract may have been reentered.\\r\\n        require(\\r\\n            _initializing ? _isConstructor() : !_initialized,\\r\\n            \\\"Initializable: contract is already initialized\\\"\\r\\n        );\\r\\n\\r\\n        bool isTopLevelCall = !_initializing;\\r\\n        if (isTopLevelCall) {\\r\\n            _initializing = true;\\r\\n            _initialized = true;\\r\\n        }\\r\\n\\r\\n        _;\\r\\n\\r\\n        if (isTopLevelCall) {\\r\\n            _initializing = false;\\r\\n        }\\r\\n    }\\r\\n\\r\\n    /**\\r\\n     * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the\\r\\n     * {initializer} modifier, directly or indirectly.\\r\\n     */\\r\\n    modifier onlyInitializing() {\\r\\n        require(_initializing, \\\"Initializable: contract is not initializing\\\");\\r\\n        _;\\r\\n    }\\r\\n\\r\\n    function _isConstructor() private view returns (bool) {\\r\\n        return !AddressUpgradeable.isContract(address(this));\\r\\n    }\\r\\n}\\r\\n\\r\\nabstract contract ContextUpgradeable is Initializable {\\r\\n    function __Context_init() internal onlyInitializing {\\r\\n        __Context_init_unchained();\\r\\n    }\\r\\n\\r\\n    function __Context_init_unchained() internal onlyInitializing {}\\r\\n\\r\\n    function _msgSender() internal view virtual returns (address) {\\r\\n        return msg.sender;\\r\\n    }\\r\\n\\r\\n    function _msgData() internal view virtual returns (bytes calldata) {\\r\\n        return msg.data;\\r\\n    }\\r\\n\\r\\n    uint256[50] private __gap;\\r\\n}\\r\\n\\r\\nabstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {\\r\\n    address private _owner;\\r\\n\\r\\n    event OwnershipTransferred(\\r\\n        address indexed previousOwner,\\r\\n        address indexed newOwner\\r\\n    );\\r\\n\\r\\n    /**\\r\\n     * @dev Initializes the contract setting the deployer as the initial owner.\\r\\n     */\\r\\n    function __Ownable_init() internal onlyInitializing {\\r\\n        __Context_init_unchained();\\r\\n        __Ownable_init_unchained();\\r\\n    }\\r\\n\\r\\n    function __Ownable_init_unchained() internal onlyInitializing {\\r\\n        _transferOwnership(_msgSender());\\r\\n    }\\r\\n\\r\\n    /**\\r\\n     * @dev Returns the address of the current owner.\\r\\n     */\\r\\n    function owner() public view virtual returns (address) {\\r\\n        return _owner;\\r\\n    }\\r\\n\\r\\n    /**\\r\\n     * @dev Throws if called by any account other than the owner.\\r\\n     */\\r\\n    modifier onlyOwner() {\\r\\n        require(owner() == _msgSender(), \\\"Ownable: caller is not the owner\\\");\\r\\n        _;\\r\\n    }\\r\\n\\r\\n    /**\\r\\n     * @dev Leaves the contract without owner. It will not be possible to call\\r\\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\\r\\n     *\\r\\n     * NOTE: Renouncing ownership will leave the contract without an owner,\\r\\n     * thereby removing any functionality that is only available to the owner.\\r\\n     */\\r\\n    function renounceOwnership() public virtual onlyOwner {\\r\\n        _transferOwnership(address(0));\\r\\n    }\\r\\n\\r\\n    /**\\r\\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\\r\\n     * Can only be called by the current owner.\\r\\n     */\\r\\n    function transferOwnership(address newOwner) public virtual onlyOwner {\\r\\n        require(\\r\\n            newOwner != address(0),\\r\\n            \\\"Ownable: new owner is the zero address\\\"\\r\\n        );\\r\\n        _transferOwnership(newOwner);\\r\\n    }\\r\\n\\r\\n    /**\\r\\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\\r\\n     * Internal function without access restriction.\\r\\n     */\\r\\n    function _transferOwnership(address newOwner) internal virtual {\\r\\n        address oldOwner = _owner;\\r\\n        _owner = newOwner;\\r\\n        emit OwnershipTransferred(oldOwner, newOwner);\\r\\n    }\\r\\n\\r\\n    uint256[49] private __gap;\\r\\n}\\r\\n\\r\\ninterface IERC165Upgradeable {\\r\\n    /**\\r\\n     * @dev Returns true if this contract implements the interface defined by\\r\\n     * `interfaceId`. See the corresponding\\r\\n     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\\r\\n     * to learn more about how these ids are created.\\r\\n     *\\r\\n     * This function call must use less than 30 000 gas.\\r\\n     */\\r\\n    function supportsInterface(bytes4 interfaceId) external view returns (bool);\\r\\n}\\r\\n\\r\\ninterface IERC721Upgradeable is IERC165Upgradeable {\\r\\n    /**\\r\\n     * @dev Emitted when `tokenId` token is transferred from `from` to `to`.\\r\\n     */\\r\\n    event Transfer(\\r\\n        address indexed from,\\r\\n        address indexed to,\\r\\n        uint256 indexed tokenId\\r\\n    );\\r\\n\\r\\n    /**\\r\\n     * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.\\r\\n     */\\r\\n    event Approval(\\r\\n        address indexed owner,\\r\\n        address indexed approved,\\r\\n        uint256 indexed tokenId\\r\\n    );\\r\\n\\r\\n    /**\\r\\n     * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.\\r\\n     */\\r\\n    event ApprovalForAll(\\r\\n        address indexed owner,\\r\\n        address indexed operator,\\r\\n        bool approved\\r\\n    );\\r\\n\\r\\n    /**\\r\\n     * @dev Returns the number of tokens in ``owner``'s account.\\r\\n     */\\r\\n    function balanceOf(address owner) external view returns (uint256 balance);\\r\\n\\r\\n    /**\\r\\n     * @dev Returns the owner of the `tokenId` token.\\r\\n     *\\r\\n     * Requirements:\\r\\n     *\\r\\n     * - `tokenId` must exist.\\r\\n     */\\r\\n    function ownerOf(uint256 tokenId) external view returns (address owner);\\r\\n\\r\\n    /**\\r\\n     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients\\r\\n     * are aware of the ERC721 protocol to prevent tokens from being forever locked.\\r\\n     *\\r\\n     * Requirements:\\r\\n     *\\r\\n     * - `from` cannot be the zero address.\\r\\n     * - `to` cannot be the zero address.\\r\\n     * - `tokenId` token must exist and be owned by `from`.\\r\\n     * - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}.\\r\\n     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\\r\\n     *\\r\\n     * Emits a {Transfer} event.\\r\\n     */\\r\\n    function safeTransferFrom(\\r\\n        address from,\\r\\n        address to,\\r\\n        uint256 tokenId\\r\\n    ) external;\\r\\n\\r\\n    /**\\r\\n     * @dev Transfers `tokenId` token from `from` to `to`.\\r\\n     *\\r\\n     * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.\\r\\n     *\\r\\n     * Requirements:\\r\\n     *\\r\\n     * - `from` cannot be the zero address.\\r\\n     * - `to` cannot be the zero address.\\r\\n     * - `tokenId` token must be owned by `from`.\\r\\n     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\\r\\n     *\\r\\n     * Emits a {Transfer} event.\\r\\n     */\\r\\n    function transferFrom(\\r\\n        address from,\\r\\n        address to,\\r\\n        uint256 tokenId\\r\\n    ) external;\\r\\n\\r\\n    /**\\r\\n     * @dev Gives permission to `to` to transfer `tokenId` token to another account.\\r\\n     * The approval is cleared when the token is transferred.\\r\\n     *\\r\\n     * Only a single account can be approved at a time, so approving the zero address clears previous approvals.\\r\\n     *\\r\\n     * Requirements:\\r\\n     *\\r\\n     * - The caller must own the token or be an approved operator.\\r\\n     * - `tokenId` must exist.\\r\\n     *\\r\\n     * Emits an {Approval} event.\\r\\n     */\\r\\n    function approve(address to, uint256 tokenId) external;\\r\\n\\r\\n    /**\\r\\n     * @dev Returns the account approved for `tokenId` token.\\r\\n     *\\r\\n     * Requirements:\\r\\n     *\\r\\n     * - `tokenId` must exist.\\r\\n     */\\r\\n    function getApproved(uint256 tokenId)\\r\\n        external\\r\\n        view\\r\\n        returns (address operator);\\r\\n\\r\\n    /**\\r\\n     * @dev Approve or remove `operator` as an operator for the caller.\\r\\n     * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.\\r\\n     *\\r\\n     * Requirements:\\r\\n     *\\r\\n     * - The `operator` cannot be the caller.\\r\\n     *\\r\\n     * Emits an {ApprovalForAll} event.\\r\\n     */\\r\\n    function setApprovalForAll(address operator, bool _approved) external;\\r\\n\\r\\n    /**\\r\\n     * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.\\r\\n     *\\r\\n     * See {setApprovalForAll}\\r\\n     */\\r\\n    function isApprovedForAll(address owner, address operator)\\r\\n        external\\r\\n        view\\r\\n        returns (bool);\\r\\n\\r\\n    /**\\r\\n     * @dev Safely transfers `tokenId` token from `from` to `to`.\\r\\n     *\\r\\n     * Requirements:\\r\\n     *\\r\\n     * - `from` cannot be the zero address.\\r\\n     * - `to` cannot be the zero address.\\r\\n     * - `tokenId` token must exist and be owned by `from`.\\r\\n     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\\r\\n     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\\r\\n     *\\r\\n     * Emits a {Transfer} event.\\r\\n     */\\r\\n    function safeTransferFrom(\\r\\n        address from,\\r\\n        address to,\\r\\n        uint256 tokenId,\\r\\n        bytes calldata data\\r\\n    ) external;\\r\\n}\\r\\n\\r\\ninterface IERC20Upgradeable {\\r\\n    /**\\r\\n     * @dev Returns the amount of tokens in existence.\\r\\n     */\\r\\n    function totalSupply() external view returns (uint256);\\r\\n\\r\\n    /**\\r\\n     * @dev Returns the amount of tokens owned by `account`.\\r\\n     */\\r\\n    function balanceOf(address account) external view returns (uint256);\\r\\n\\r\\n    /**\\r\\n     * @dev Moves `amount` tokens from the caller's account to `recipient`.\\r\\n     *\\r\\n     * Returns a boolean value indicating whether the operation succeeded.\\r\\n     *\\r\\n     * Emits a {Transfer} event.\\r\\n     */\\r\\n    function transfer(address recipient, uint256 amount)\\r\\n        external\\r\\n        returns (bool);\\r\\n\\r\\n    /**\\r\\n     * @dev Returns the remaining number of tokens that `spender` will be\\r\\n     * allowed to spend on behalf of `owner` through {transferFrom}. This is\\r\\n     * zero by default.\\r\\n     *\\r\\n     * This value changes when {approve} or {transferFrom} are called.\\r\\n     */\\r\\n    function allowance(address owner, address spender)\\r\\n        external\\r\\n        view\\r\\n        returns (uint256);\\r\\n\\r\\n    /**\\r\\n     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\r\\n     *\\r\\n     * Returns a boolean value indicating whether the operation succeeded.\\r\\n     *\\r\\n     * IMPORTANT: Beware that changing an allowance with this method brings the risk\\r\\n     * that someone may use both the old and the new allowance by unfortunate\\r\\n     * transaction ordering. One possible solution to mitigate this race\\r\\n     * condition is to first reduce the spender's allowance to 0 and set the\\r\\n     * desired value afterwards:\\r\\n     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\r\\n     *\\r\\n     * Emits an {Approval} event.\\r\\n     */\\r\\n    function approve(address spender, uint256 amount) external returns (bool);\\r\\n\\r\\n    /**\\r\\n     * @dev Moves `amount` tokens from `sender` to `recipient` using the\\r\\n     * allowance mechanism. `amount` is then deducted from the caller's\\r\\n     * allowance.\\r\\n     *\\r\\n     * Returns a boolean value indicating whether the operation succeeded.\\r\\n     *\\r\\n     * Emits a {Transfer} event.\\r\\n     */\\r\\n    function transferFrom(\\r\\n        address sender,\\r\\n        address recipient,\\r\\n        uint256 amount\\r\\n    ) external returns (bool);\\r\\n\\r\\n\\r\\n    function mintToken(address _address, uint256 _amount) external;\\r\\n    /**\\r\\n     * @dev Emitted when `value` tokens are moved from one account (`from`) to\\r\\n     * another (`to`).\\r\\n     *\\r\\n     * Note that `value` may be zero.\\r\\n     */\\r\\n    event Transfer(address indexed from, address indexed to, uint256 value);\\r\\n\\r\\n    /**\\r\\n     * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\r\\n     * a call to {approve}. `value` is the new allowance.\\r\\n     */\\r\\n    event Approval(\\r\\n        address indexed owner,\\r\\n        address indexed spender,\\r\\n        uint256 value\\r\\n    );\\r\\n}\\r\\n\\r\\ninterface IUniswapV2Factory {\\r\\n    event PairCreated(\\r\\n        address indexed token0,\\r\\n        address indexed token1,\\r\\n        address pair,\\r\\n        uint256\\r\\n    );\\r\\n\\r\\n    function feeTo() external view returns (address);\\r\\n\\r\\n    function feeToSetter() external view returns (address);\\r\\n\\r\\n    function getPair(address tokenA, address tokenB)\\r\\n        external\\r\\n        view\\r\\n        returns (address pair);\\r\\n\\r\\n    function allPairs(uint256) external view returns (address pair);\\r\\n\\r\\n    function allPairsLength() external view returns (uint256);\\r\\n\\r\\n    function createPair(address tokenA, address tokenB)\\r\\n        external\\r\\n        returns (address pair);\\r\\n\\r\\n    function setFeeTo(address) external;\\r\\n\\r\\n    function setFeeToSetter(address) external;\\r\\n}\\r\\n\\r\\ninterface IUniswapV2Pair {\\r\\n    event Approval(\\r\\n        address indexed owner,\\r\\n        address indexed spender,\\r\\n        uint256 value\\r\\n    );\\r\\n    event Transfer(address indexed from, address indexed to, uint256 value);\\r\\n\\r\\n    function name() external pure returns (string memory);\\r\\n\\r\\n    function symbol() external pure returns (string memory);\\r\\n\\r\\n    function decimals() external pure returns (uint8);\\r\\n\\r\\n    function totalSupply() external view returns (uint256);\\r\\n\\r\\n    function balanceOf(address owner) external view returns (uint256);\\r\\n\\r\\n    function allowance(address owner, address spender)\\r\\n        external\\r\\n        view\\r\\n        returns (uint256);\\r\\n\\r\\n    function approve(address spender, uint256 value) external returns (bool);\\r\\n\\r\\n    function transfer(address to, uint256 value) external returns (bool);\\r\\n\\r\\n    function transferFrom(\\r\\n        address from,\\r\\n        address to,\\r\\n        uint256 value\\r\\n    ) external returns (bool);\\r\\n\\r\\n    function DOMAIN_SEPARATOR() external view returns (bytes32);\\r\\n\\r\\n    function PERMIT_TYPEHASH() external pure returns (bytes32);\\r\\n\\r\\n    function nonces(address owner) external view returns (uint256);\\r\\n\\r\\n    function permit(\\r\\n        address owner,\\r\\n        address spender,\\r\\n        uint256 value,\\r\\n        uint256 deadline,\\r\\n        uint8 v,\\r\\n        bytes32 r,\\r\\n        bytes32 s\\r\\n    ) external;\\r\\n\\r\\n    event Mint(address indexed sender, uint256 amount0, uint256 amount1);\\r\\n    event Burn(\\r\\n        address indexed sender,\\r\\n        uint256 amount0,\\r\\n        uint256 amount1,\\r\\n        address indexed to\\r\\n    );\\r\\n    event Swap(\\r\\n        address indexed sender,\\r\\n        uint256 amount0In,\\r\\n        uint256 amount1In,\\r\\n        uint256 amount0Out,\\r\\n        uint256 amount1Out,\\r\\n        address indexed to\\r\\n    );\\r\\n    event Sync(uint112 reserve0, uint112 reserve1);\\r\\n\\r\\n    function MINIMUM_LIQUIDITY() external pure returns (uint256);\\r\\n\\r\\n    function factory() external view returns (address);\\r\\n\\r\\n    function token0() external view returns (address);\\r\\n\\r\\n    function token1() external view returns (address);\\r\\n\\r\\n    function getReserves()\\r\\n        external\\r\\n        view\\r\\n        returns (\\r\\n            uint112 reserve0,\\r\\n            uint112 reserve1,\\r\\n            uint32 blockTimestampLast\\r\\n        );\\r\\n\\r\\n    function price0CumulativeLast() external view returns (uint256);\\r\\n\\r\\n    function price1CumulativeLast() external view returns (uint256);\\r\\n\\r\\n    function kLast() external view returns (uint256);\\r\\n\\r\\n    function mint(address to) external returns (uint256 liquidity);\\r\\n\\r\\n    function burn(address to)\\r\\n        external\\r\\n        returns (uint256 amount0, uint256 amount1);\\r\\n\\r\\n    function swap(\\r\\n        uint256 amount0Out,\\r\\n        uint256 amount1Out,\\r\\n        address to,\\r\\n        bytes calldata data\\r\\n    ) external;\\r\\n\\r\\n    function skim(address to) external;\\r\\n\\r\\n    function sync() external;\\r\\n\\r\\n    function initialize(address, address) external;\\r\\n}\\r\\n\\r\\ninterface IUniswapV2Router01 {\\r\\n    function factory() external pure returns (address);\\r\\n\\r\\n    function WETH() external pure returns (address);\\r\\n\\r\\n    function addLiquidity(\\r\\n        address tokenA,\\r\\n        address tokenB,\\r\\n        uint256 amountADesired,\\r\\n        uint256 amountBDesired,\\r\\n        uint256 amountAMin,\\r\\n        uint256 amountBMin,\\r\\n        address to,\\r\\n        uint256 deadline\\r\\n    )\\r\\n        external\\r\\n        returns (\\r\\n            uint256 amountA,\\r\\n            uint256 amountB,\\r\\n            uint256 liquidity\\r\\n        );\\r\\n\\r\\n    function addLiquidityETH(\\r\\n        address token,\\r\\n        uint256 amountTokenDesired,\\r\\n        uint256 amountTokenMin,\\r\\n        uint256 amountETHMin,\\r\\n        address to,\\r\\n        uint256 deadline\\r\\n    )\\r\\n        external\\r\\n        payable\\r\\n        returns (\\r\\n            uint256 amountToken,\\r\\n            uint256 amountETH,\\r\\n            uint256 liquidity\\r\\n        );\\r\\n\\r\\n    function removeLiquidity(\\r\\n        address tokenA,\\r\\n        address tokenB,\\r\\n        uint256 liquidity,\\r\\n        uint256 amountAMin,\\r\\n        uint256 amountBMin,\\r\\n        address to,\\r\\n        uint256 deadline\\r\\n    ) external returns (uint256 amountA, uint256 amountB);\\r\\n\\r\\n    function removeLiquidityETH(\\r\\n        address token,\\r\\n        uint256 liquidity,\\r\\n        uint256 amountTokenMin,\\r\\n        uint256 amountETHMin,\\r\\n        address to,\\r\\n        uint256 deadline\\r\\n    ) external returns (uint256 amountToken, uint256 amountETH);\\r\\n\\r\\n    function removeLiquidityWithPermit(\\r\\n        address tokenA,\\r\\n        address tokenB,\\r\\n        uint256 liquidity,\\r\\n        uint256 amountAMin,\\r\\n        uint256 amountBMin,\\r\\n        address to,\\r\\n        uint256 deadline,\\r\\n        bool approveMax,\\r\\n        uint8 v,\\r\\n        bytes32 r,\\r\\n        bytes32 s\\r\\n    ) external returns (uint256 amountA, uint256 amountB);\\r\\n\\r\\n    function removeLiquidityETHWithPermit(\\r\\n        address token,\\r\\n        uint256 liquidity,\\r\\n        uint256 amountTokenMin,\\r\\n        uint256 amountETHMin,\\r\\n        address to,\\r\\n        uint256 deadline,\\r\\n        bool approveMax,\\r\\n        uint8 v,\\r\\n        bytes32 r,\\r\\n        bytes32 s\\r\\n    ) external returns (uint256 amountToken, uint256 amountETH);\\r\\n\\r\\n    function swapExactTokensForTokens(\\r\\n        uint256 amountIn,\\r\\n        uint256 amountOutMin,\\r\\n        address[] calldata path,\\r\\n        address to,\\r\\n        uint256 deadline\\r\\n    ) external returns (uint256[] memory amounts);\\r\\n\\r\\n    function swapTokensForExactTokens(\\r\\n        uint256 amountOut,\\r\\n        uint256 amountInMax,\\r\\n        address[] calldata path,\\r\\n        address to,\\r\\n        uint256 deadline\\r\\n    ) external returns (uint256[] memory amounts);\\r\\n\\r\\n    function swapExactETHForTokens(\\r\\n        uint256 amountOutMin,\\r\\n        address[] calldata path,\\r\\n        address to,\\r\\n        uint256 deadline\\r\\n    ) external payable returns (uint256[] memory amounts);\\r\\n\\r\\n    function swapTokensForExactETH(\\r\\n        uint256 amountOut,\\r\\n        uint256 amountInMax,\\r\\n        address[] calldata path,\\r\\n        address to,\\r\\n        uint256 deadline\\r\\n    ) external returns (uint256[] memory amounts);\\r\\n\\r\\n    function swapExactTokensForETH(\\r\\n        uint256 amountIn,\\r\\n        uint256 amountOutMin,\\r\\n        address[] calldata path,\\r\\n        address to,\\r\\n        uint256 deadline\\r\\n    ) external returns (uint256[] memory amounts);\\r\\n\\r\\n    function swapETHForExactTokens(\\r\\n        uint256 amountOut,\\r\\n        address[] calldata path,\\r\\n        address to,\\r\\n        uint256 deadline\\r\\n    ) external payable returns (uint256[] memory amounts);\\r\\n\\r\\n    function quote(\\r\\n        uint256 amountA,\\r\\n        uint256 reserveA,\\r\\n        uint256 reserveB\\r\\n    ) external pure returns (uint256 amountB);\\r\\n\\r\\n    function getAmountOut(\\r\\n        uint256 amountIn,\\r\\n        uint256 reserveIn,\\r\\n        uint256 reserveOut\\r\\n    ) external pure returns (uint256 amountOut);\\r\\n\\r\\n    function getAmountIn(\\r\\n        uint256 amountOut,\\r\\n        uint256 reserveIn,\\r\\n        uint256 reserveOut\\r\\n    ) external pure returns (uint256 amountIn);\\r\\n\\r\\n    function getAmountsOut(uint256 amountIn, address[] calldata path)\\r\\n        external\\r\\n        view\\r\\n        returns (uint256[] memory amounts);\\r\\n\\r\\n    function getAmountsIn(uint256 amountOut, address[] calldata path)\\r\\n        external\\r\\n        view\\r\\n        returns (uint256[] memory amounts);\\r\\n}\\r\\n\\r\\ninterface IUniswapV2Router is IUniswapV2Router01 {\\r\\n    function removeLiquidityETHSupportingFeeOnTransferTokens(\\r\\n        address token,\\r\\n        uint256 liquidity,\\r\\n        uint256 amountTokenMin,\\r\\n        uint256 amountETHMin,\\r\\n        address to,\\r\\n        uint256 deadline\\r\\n    ) external returns (uint256 amountETH);\\r\\n\\r\\n    function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(\\r\\n        address token,\\r\\n        uint256 liquidity,\\r\\n        uint256 amountTokenMin,\\r\\n        uint256 amountETHMin,\\r\\n        address to,\\r\\n        uint256 deadline,\\r\\n        bool approveMax,\\r\\n        uint8 v,\\r\\n        bytes32 r,\\r\\n        bytes32 s\\r\\n    ) external returns (uint256 amountETH);\\r\\n\\r\\n    function swapExactTokensForTokensSupportingFeeOnTransferTokens(\\r\\n        uint256 amountIn,\\r\\n        uint256 amountOutMin,\\r\\n        address[] calldata path,\\r\\n        address to,\\r\\n        uint256 deadline\\r\\n    ) external;\\r\\n\\r\\n    function swapExactETHForTokensSupportingFeeOnTransferTokens(\\r\\n        uint256 amountOutMin,\\r\\n        address[] calldata path,\\r\\n        address to,\\r\\n        uint256 deadline\\r\\n    ) external payable;\\r\\n\\r\\n    function swapExactTokensForETHSupportingFeeOnTransferTokens(\\r\\n        uint256 amountIn,\\r\\n        uint256 amountOutMin,\\r\\n        address[] calldata path,\\r\\n        address to,\\r\\n        uint256 deadline\\r\\n    ) external;\\r\\n}\\r\\n\\r\\ninterface IERC20MetadataUpgradeable is IERC20Upgradeable {\\r\\n    /**\\r\\n     * @dev Returns the name of the token.\\r\\n     */\\r\\n    function name() external view returns (string memory);\\r\\n\\r\\n    /**\\r\\n     * @dev Returns the symbol of the token.\\r\\n     */\\r\\n    function symbol() external view returns (string memory);\\r\\n\\r\\n    /**\\r\\n     * @dev Returns the decimals places of the token.\\r\\n     */\\r\\n    function decimals() external view returns (uint8);\\r\\n}\\r\\n\\r\\nabstract contract ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20Upgradeable, IERC20MetadataUpgradeable {\\r\\n    using SafeMathUpgradeable for uint256;\\r\\n\\r\\n    mapping(address => uint256) private _balances;\\r\\n\\r\\n    mapping(address => mapping(address => uint256)) private _allowances;\\r\\n\\r\\n    uint256 private _totalSupply;\\r\\n\\r\\n    string private _name;\\r\\n    string private _symbol;\\r\\n\\r\\n    /**\\r\\n     * @dev Sets the values for {name} and {symbol}.\\r\\n     *\\r\\n     * The default value of {decimals} is 18. To select a different value for\\r\\n     * {decimals} you should overload it.\\r\\n     *\\r\\n     * All two of these values are immutable: they can only be set once during\\r\\n     * construction.\\r\\n     */\\r\\n    function __ERC20_init(string memory name_, string memory symbol_) internal onlyInitializing {\\r\\n        __ERC20_init_unchained(name_, symbol_);\\r\\n    }\\r\\n\\r\\n    function __ERC20_init_unchained(string memory name_, string memory symbol_) internal onlyInitializing {\\r\\n        _name = name_;\\r\\n        _symbol = symbol_;\\r\\n    }\\r\\n\\r\\n    /**\\r\\n     * @dev Returns the name of the token.\\r\\n     */\\r\\n    function name() public view virtual override returns (string memory) {\\r\\n        return _name;\\r\\n    }\\r\\n\\r\\n    /**\\r\\n     * @dev Returns the symbol of the token, usually a shorter version of the\\r\\n     * name.\\r\\n     */\\r\\n    function symbol() public view virtual override returns (string memory) {\\r\\n        return _symbol;\\r\\n    }\\r\\n\\r\\n    /**\\r\\n     * @dev Returns the number of decimals used to get its user representation.\\r\\n     * For example, if `decimals` equals `2`, a balance of `505` tokens should\\r\\n     * be displayed to a user as `5.05` (`505 / 10 ** 2`).\\r\\n     *\\r\\n     * Tokens usually opt for a value of 18, imitating the relationship between\\r\\n     * Ether and Wei. This is the value {ERC20} uses, unless this function is\\r\\n     * overridden;\\r\\n     *\\r\\n     * NOTE: This information is only used for _display_ purposes: it in\\r\\n     * no way affects any of the arithmetic of the contract, including\\r\\n     * {IERC20-balanceOf} and {IERC20-transfer}.\\r\\n     */\\r\\n    function decimals() public view virtual override returns (uint8) {\\r\\n        return 18;\\r\\n    }\\r\\n\\r\\n    /**\\r\\n     * @dev See {IERC20-totalSupply}.\\r\\n     */\\r\\n    function totalSupply() public view virtual override returns (uint256) {\\r\\n        return _totalSupply;\\r\\n    }\\r\\n\\r\\n    /**\\r\\n     * @dev See {IERC20-balanceOf}.\\r\\n     */\\r\\n    function balanceOf(address account) public view virtual override returns (uint256) {\\r\\n        return _balances[account];\\r\\n    }\\r\\n\\r\\n    /**\\r\\n     * @dev See {IERC20-transfer}.\\r\\n     *\\r\\n     * Requirements:\\r\\n     *\\r\\n     * - `to` cannot be the zero address.\\r\\n     * - the caller must have a balance of at least `amount`.\\r\\n     */\\r\\n    function transfer(address to, uint256 amount) public virtual override returns (bool) {\\r\\n        address owner = _msgSender();\\r\\n        _transfer(owner, to, amount);\\r\\n        return true;\\r\\n    }\\r\\n\\r\\n    /**\\r\\n     * @dev See {IERC20-allowance}.\\r\\n     */\\r\\n    function allowance(address owner, address spender) public view virtual override returns (uint256) {\\r\\n        return _allowances[owner][spender];\\r\\n    }\\r\\n\\r\\n    /**\\r\\n     * @dev See {IERC20-approve}.\\r\\n     *\\r\\n     * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\\r\\n     * `transferFrom`. This is semantically equivalent to an infinite approval.\\r\\n     *\\r\\n     * Requirements:\\r\\n     *\\r\\n     * - `spender` cannot be the zero address.\\r\\n     */\\r\\n    function approve(address spender, uint256 amount) public virtual override returns (bool) {\\r\\n        address owner = _msgSender();\\r\\n        _approve(owner, spender, amount);\\r\\n        return true;\\r\\n    }\\r\\n\\r\\n    /**\\r\\n     * @dev See {IERC20-transferFrom}.\\r\\n     *\\r\\n     * Emits an {Approval} event indicating the updated allowance. This is not\\r\\n     * required by the EIP. See the note at the beginning of {ERC20}.\\r\\n     *\\r\\n     * NOTE: Does not update the allowance if the current allowance\\r\\n     * is the maximum `uint256`.\\r\\n     *\\r\\n     * Requirements:\\r\\n     *\\r\\n     * - `from` and `to` cannot be the zero address.\\r\\n     * - `from` must have a balance of at least `amount`.\\r\\n     * - the caller must have allowance for ``from``'s tokens of at least\\r\\n     * `amount`.\\r\\n     */\\r\\n    function transferFrom(\\r\\n        address from,\\r\\n        address to,\\r\\n        uint256 amount\\r\\n    ) public virtual override returns (bool) {\\r\\n        address spender = _msgSender();\\r\\n        _spendAllowance(from, spender, amount);\\r\\n        _transfer(from, to, amount);\\r\\n        return true;\\r\\n    }\\r\\n\\r\\n    /**\\r\\n     * @dev Atomically increases the allowance granted to `spender` by the caller.\\r\\n     *\\r\\n     * This is an alternative to {approve} that can be used as a mitigation for\\r\\n     * problems described in {IERC20-approve}.\\r\\n     *\\r\\n     * Emits an {Approval} event indicating the updated allowance.\\r\\n     *\\r\\n     * Requirements:\\r\\n     *\\r\\n     * - `spender` cannot be the zero address.\\r\\n     */\\r\\n    function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\\r\\n        address owner = _msgSender();\\r\\n        _approve(owner, spender, _allowances[owner][spender] + addedValue);\\r\\n        return true;\\r\\n    }\\r\\n\\r\\n    /**\\r\\n     * @dev Atomically decreases the allowance granted to `spender` by the caller.\\r\\n     *\\r\\n     * This is an alternative to {approve} that can be used as a mitigation for\\r\\n     * problems described in {IERC20-approve}.\\r\\n     *\\r\\n     * Emits an {Approval} event indicating the updated allowance.\\r\\n     *\\r\\n     * Requirements:\\r\\n     *\\r\\n     * - `spender` cannot be the zero address.\\r\\n     * - `spender` must have allowance for the caller of at least\\r\\n     * `subtractedValue`.\\r\\n     */\\r\\n    function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\\r\\n        address owner = _msgSender();\\r\\n        uint256 currentAllowance = _allowances[owner][spender];\\r\\n        require(currentAllowance >= subtractedValue, \\\"ERC20: decreased allowance below zero\\\");\\r\\n        unchecked {\\r\\n            _approve(owner, spender, currentAllowance - subtractedValue);\\r\\n        }\\r\\n\\r\\n        return true;\\r\\n    }\\r\\n\\r\\n    /**\\r\\n     * @dev Moves `amount` of tokens from `sender` to `recipient`.\\r\\n     *\\r\\n     * This internal function is equivalent to {transfer}, and can be used to\\r\\n     * e.g. implement automatic token fees, slashing mechanisms, etc.\\r\\n     *\\r\\n     * Emits a {Transfer} event.\\r\\n     *\\r\\n     * Requirements:\\r\\n     *\\r\\n     * - `from` cannot be the zero address.\\r\\n     * - `to` cannot be the zero address.\\r\\n     * - `from` must have a balance of at least `amount`.\\r\\n     */\\r\\n    function _transfer(\\r\\n        address from,\\r\\n        address to,\\r\\n        uint256 amount\\r\\n    ) internal virtual {\\r\\n        require(from != address(0), \\\"ERC20: transfer from the zero address\\\");\\r\\n        require(to != address(0), \\\"ERC20: transfer to the zero address\\\");\\r\\n\\r\\n        _beforeTokenTransfer(from, to, amount);\\r\\n\\r\\n        uint256 fromBalance = _balances[from];\\r\\n        require(fromBalance >= amount, \\\"ERC20: transfer amount exceeds balance\\\");\\r\\n        unchecked {\\r\\n            _balances[from] = fromBalance - amount;\\r\\n        }\\r\\n        _balances[to] += amount;\\r\\n\\r\\n        emit Transfer(from, to, amount);\\r\\n\\r\\n        _afterTokenTransfer(from, to, amount);\\r\\n    }\\r\\n\\r\\n    /** @dev Creates `amount` tokens and assigns them to `account`, increasing\\r\\n     * the total supply.\\r\\n     *\\r\\n     * Emits a {Transfer} event with `from` set to the zero address.\\r\\n     *\\r\\n     * Requirements:\\r\\n     *\\r\\n     * - `account` cannot be the zero address.\\r\\n     */\\r\\n    function _mint(address account, uint256 amount) internal virtual {\\r\\n        require(account != address(0), \\\"ERC20: mint to the zero address\\\");\\r\\n\\r\\n        _beforeTokenTransfer(address(0), account, amount);\\r\\n\\r\\n        _totalSupply += amount;\\r\\n        _balances[account] += amount;\\r\\n        emit Transfer(address(0), account, amount);\\r\\n\\r\\n        _afterTokenTransfer(address(0), account, amount);\\r\\n    }\\r\\n\\r\\n    /**\\r\\n     * @dev Destroys `amount` tokens from `account`, reducing the\\r\\n     * total supply.\\r\\n     *\\r\\n     * Emits a {Transfer} event with `to` set to the zero address.\\r\\n     *\\r\\n     * Requirements:\\r\\n     *\\r\\n     * - `account` cannot be the zero address.\\r\\n     * - `account` must have at least `amount` tokens.\\r\\n     */\\r\\n    function _burn(uint256 amount) public virtual {\\r\\n        // require(_balances[msg.sender] >= amount,'insufficient balance!');\\r\\n\\r\\n        // _beforeTokenTransfer(msg.sender, address(0x000000000000000000000000000000000000dEaD), amount);\\r\\n\\r\\n        // _balances[msg.sender] = _balances[msg.sender].sub(amount, \\\"ERC20: burn amount exceeds balance\\\");\\r\\n        // _totalSupply = _totalSupply.sub(amount);\\r\\n        // emit Transfer(msg.sender, address(0x000000000000000000000000000000000000dEaD), amount);\\r\\n    }\\r\\n\\r\\n    /**\\r\\n     * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\\r\\n     *\\r\\n     * This internal function is equivalent to `approve`, and can be used to\\r\\n     * e.g. set automatic allowances for certain subsystems, etc.\\r\\n     *\\r\\n     * Emits an {Approval} event.\\r\\n     *\\r\\n     * Requirements:\\r\\n     *\\r\\n     * - `owner` cannot be the zero address.\\r\\n     * - `spender` cannot be the zero address.\\r\\n     */\\r\\n    function _approve(\\r\\n        address owner,\\r\\n        address spender,\\r\\n        uint256 amount\\r\\n    ) internal virtual {\\r\\n        require(owner != address(0), \\\"ERC20: approve from the zero address\\\");\\r\\n        require(spender != address(0), \\\"ERC20: approve to the zero address\\\");\\r\\n\\r\\n        _allowances[owner][spender] = amount;\\r\\n        emit Approval(owner, spender, amount);\\r\\n    }\\r\\n\\r\\n    /**\\r\\n     * @dev Spend `amount` form the allowance of `owner` toward `spender`.\\r\\n     *\\r\\n     * Does not update the allowance amount in case of infinite allowance.\\r\\n     * Revert if not enough allowance is available.\\r\\n     *\\r\\n     * Might emit an {Approval} event.\\r\\n     */\\r\\n    function _spendAllowance(\\r\\n        address owner,\\r\\n        address spender,\\r\\n        uint256 amount\\r\\n    ) internal virtual {\\r\\n        uint256 currentAllowance = allowance(owner, spender);\\r\\n        if (currentAllowance != type(uint256).max) {\\r\\n            require(currentAllowance >= amount, \\\"ERC20: insufficient allowance\\\");\\r\\n            unchecked {\\r\\n                _approve(owner, spender, currentAllowance - amount);\\r\\n            }\\r\\n        }\\r\\n    }\\r\\n\\r\\n    /**\\r\\n     * @dev Hook that is called before any transfer of tokens. This includes\\r\\n     * minting and burning.\\r\\n     *\\r\\n     * Calling conditions:\\r\\n     *\\r\\n     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\r\\n     * will be transferred to `to`.\\r\\n     * - when `from` is zero, `amount` tokens will be minted for `to`.\\r\\n     * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\\r\\n     * - `from` and `to` are never both zero.\\r\\n     *\\r\\n     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\r\\n     */\\r\\n    function _beforeTokenTransfer(\\r\\n        address from,\\r\\n        address to,\\r\\n        uint256 amount\\r\\n    ) internal virtual {}\\r\\n\\r\\n    /**\\r\\n     * @dev Hook that is called after any transfer of tokens. This includes\\r\\n     * minting and burning.\\r\\n     *\\r\\n     * Calling conditions:\\r\\n     *\\r\\n     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\r\\n     * has been transferred to `to`.\\r\\n     * - when `from` is zero, `amount` tokens have been minted for `to`.\\r\\n     * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\\r\\n     * - `from` and `to` are never both zero.\\r\\n     *\\r\\n     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\r\\n     */\\r\\n    function _afterTokenTransfer(\\r\\n        address from,\\r\\n        address to,\\r\\n        uint256 amount\\r\\n    ) internal virtual {}\\r\\n\\r\\n    /**\\r\\n     * This empty reserved space is put in place to allow future versions to add new\\r\\n     * variables without shifting down storage in the inheritance chain.\\r\\n     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\\r\\n     */\\r\\n    uint256[45] private __gap;\\r\\n}\\r\\n\\r\\ncontract BearXNFTStaking is OwnableUpgradeable {\\r\\n    using SafeMathUpgradeable for uint256;\\r\\n    using AddressUpgradeable for address;\\r\\n\\r\\n    //-------------constant value------------------//\\r\\n    address private UNISWAP_V2_ROUTER;\\r\\n    address private WETH;\\r\\n    uint256 DURATION_FOR_REWARDS;\\r\\n    uint256 DURATION_FOR_STOP_REWARDS;\\r\\n\\r\\n    address public BearXNFTAddress;\\r\\n    address public ROOTxTokenAddress;\\r\\n    address public SROOTxTokenAddress;\\r\\n    uint256 public totalStakes;\\r\\n\\r\\n    uint256 public MaxSROOTXrate;\\r\\n    uint256 public MinSROOTXrate;\\r\\n    uint256 public MaxRate;\\r\\n    uint256 public MinRate;\\r\\n    uint256 public maxprovision;\\r\\n    uint256 public RateValue;\\r\\n    uint256 public SROOTRateValue;\\r\\n\\r\\n    struct stakingInfo {\\r\\n        uint256 nft_id;\\r\\n        uint256 stakedDate;\\r\\n        uint256 claimedDate_SROOT;\\r\\n        uint256 claimedDate_WETH;\\r\\n        uint256 claimedDate_ROOTX;\\r\\n    }\\r\\n\\r\\n    mapping(address => stakingInfo[]) internal stakes;\\r\\n    address[] internal stakers;\\r\\n    uint256 public RootX_Store;\\r\\n\\r\\n    // 1.29 update\\r\\n    mapping(address => bool) internal m_stakers;\\r\\n    bool ismaptransfered;\\r\\n\\r\\n    // 2.15 update\\r\\n    bool public islocked;\\r\\n\\r\\n    function initialize() public initializer{\\r\\n        __Ownable_init();\\r\\n        UNISWAP_V2_ROUTER = 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D;\\r\\n        WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;\\r\\n        DURATION_FOR_REWARDS = 1 days;\\r\\n        DURATION_FOR_STOP_REWARDS = 3650 days;\\r\\n        BearXNFTAddress = 0xE22e1e620dffb03065CD77dB0162249c0c91bf01;\\r\\n        ROOTxTokenAddress = 0xd718Ad25285d65eF4D79262a6CD3AEA6A8e01023;\\r\\n        SROOTxTokenAddress = 0x99CFDf48d0ba4885A73786148A2f89d86c702170;\\r\\n        totalStakes = 0; \\r\\n        MaxSROOTXrate = 100*10**18;\\r\\n        MinSROOTXrate = 50*10**18;\\r\\n        MaxRate = 11050*10**18;\\r\\n        MinRate = 500*10**18;   \\r\\n        maxprovision = 3000;\\r\\n        RateValue = ((MaxRate - MinRate) / maxprovision);\\r\\n        SROOTRateValue = (( MaxSROOTXrate - MinSROOTXrate ) / maxprovision);\\r\\n        RootX_Store=0;\\r\\n        ismaptransfered = false;\\r\\n    }\\r\\n    // 1.29 update\\r\\n    function transferStakers() public {\\r\\n        if(!ismaptransfered) {\\r\\n            for(uint256 i=0; i<stakers.length;i++) {\\r\\n                m_stakers[stakers[i]] = true;\\r\\n            }\\r\\n        }\\r\\n        else{\\r\\n            ismaptransfered = true;\\r\\n        }\\r\\n    }\\r\\n\\r\\n    function getAmountOutMin(\\r\\n        address _tokenIn,\\r\\n        address _tokenOut,\\r\\n        uint256 _amountIn\\r\\n    ) internal view returns (uint256) {\\r\\n        address[] memory path;\\r\\n\\r\\n        path = new address[](2);\\r\\n        path[0] = _tokenIn;\\r\\n        path[1] = _tokenOut;\\r\\n\\r\\n        // same length as path\\r\\n        uint256[] memory amountOutMins = IUniswapV2Router(UNISWAP_V2_ROUTER)\\r\\n            .getAmountsOut(_amountIn, path);\\r\\n\\r\\n        return amountOutMins[path.length - 1];\\r\\n    }\\r\\n\\r\\n    function setBearXNFTAddress(address _addr) external onlyOwner {\\r\\n        require(BearXNFTAddress.isContract(), \\\"Address is not contract\\\");\\r\\n        BearXNFTAddress = _addr;\\r\\n    }\\r\\n\\r\\n    function setROOTxTokenAddress(address _addr) external onlyOwner {\\r\\n        require(ROOTxTokenAddress.isContract(), \\\"Address is not contract\\\");\\r\\n        ROOTxTokenAddress = _addr;\\r\\n    }\\r\\n\\r\\n    function setSROOTxTokenAddress(address _addr) external onlyOwner {\\r\\n        require(SROOTxTokenAddress.isContract(), \\\"Address is not contract\\\");\\r\\n        SROOTxTokenAddress = _addr;\\r\\n    }\\r\\n\\r\\n    function getAPR() public view returns (uint256) {\\r\\n        uint256 A = MaxSROOTXrate * (1 + (1 * MaxRate) / 100);\\r\\n        uint256 temp = A - MaxSROOTXrate;\\r\\n        \\r\\n        uint256 APR = ((temp / MaxSROOTXrate) / 1) * 1 * 100;\\r\\n        return APR;\\r\\n    }\\r\\n\\r\\n    // 2.1 update\\r\\n    function get_APR() public view returns(uint256) {\\r\\n        uint256 APR = MaxRate;\\r\\n        return APR;\\r\\n    }\\r\\n\\r\\n    // function isStaker(address _addr) public view returns (bool, uint256) {\\r\\n    //     for (uint256 i = 0; i < stakers.length; i += 1) {\\r\\n    //         if (_addr == stakers[i]) return (true, i);\\r\\n    //     }\\r\\n\\r\\n    //     return (false, 0);\\r\\n    // }\\r\\n\\r\\n    // 1.29 update\\r\\n    function is_m_Staker(address _address) public view returns(bool, address) {\\r\\n        if(m_stakers[_address] == true) {\\r\\n            return (true, _address);\\r\\n        } else {\\r\\n            return (false, 0x0000000000000000000000000000000000000000);\\r\\n        }\\r\\n    }\\r\\n\\r\\n    function addStaker(address _addr) internal {\\r\\n        // (bool _isStaker, ) = isStaker(_addr);\\r\\n        // (bool _isStaker, address _address) = is_m_Staker(_addr);\\r\\n        m_stakers[_addr] = true;\\r\\n    }\\r\\n\\r\\n    function removeStaker(address _addr) internal {\\r\\n        // (bool _isStaker, uint256 i) = isStaker(_addr);\\r\\n        // if (_isStaker) {\\r\\n        //     stakers[i] = stakers[stakers.length - 1];\\r\\n        //     stakers.pop();\\r\\n        // }\\r\\n\\r\\n        (bool _isStaker, address _address) = is_m_Staker(_addr);\\r\\n        if(_isStaker) {\\r\\n            delete m_stakers[_address];\\r\\n        }\\r\\n    }\\r\\n\\r\\n    function stakeOf(address _addr) public view returns (uint256[] memory) {\\r\\n        uint256[] memory _iids = new uint256[](stakes[_addr].length);\\r\\n        for (uint256 i = 0; i < stakes[_addr].length; i++) {\\r\\n            _iids[i] = stakes[_addr][i].nft_id;\\r\\n        }\\r\\n        return _iids;\\r\\n    }\\r\\n\\r\\n    function createStake(uint256[] memory _ids) external {\\r\\n        (RootX_Store,,) = claimOf(msg.sender);\\r\\n\\r\\n        for (uint256 i = 0; i < _ids.length; i++) {\\r\\n            _createStake(_ids[i], msg.sender);\\r\\n        }\\r\\n    \\r\\n    }\\r\\n\\r\\n    function _createStake(uint256 _id, address _addr) internal {\\r\\n        if (MaxRate >= MinRate) {\\r\\n            // MaxRate -= RateValue;\\r\\n            MaxSROOTXrate -= SROOTRateValue;\\r\\n            // 2.1 updated\\r\\n            MaxRate = MaxRate.sub(10*(10**18));\\r\\n        }\\r\\n        require(\\r\\n            IERC721Upgradeable(BearXNFTAddress).ownerOf(_id) == _addr,\\r\\n            \\\"You are not a owner of the nft\\\"\\r\\n        );\\r\\n        require(\\r\\n            IERC721Upgradeable(BearXNFTAddress).isApprovedForAll(msg.sender, address(this)) ==\\r\\n                true,\\r\\n            \\\"You should approve nft to the staking contract\\\"\\r\\n        );\\r\\n        IERC721Upgradeable(BearXNFTAddress).transferFrom(\\r\\n            _addr,\\r\\n            address(this),\\r\\n            _id\\r\\n        );\\r\\n        // (bool _isStaker, ) = isStaker(_addr);\\r\\n        (bool _isStaker, ) = is_m_Staker(_addr);\\r\\n        stakingInfo memory sInfo = stakingInfo(\\r\\n            _id,\\r\\n            block.timestamp,\\r\\n            block.timestamp,\\r\\n            block.timestamp,\\r\\n            block.timestamp\\r\\n        );\\r\\n        totalStakes = totalStakes.add(1);\\r\\n        stakes[_addr].push(sInfo);\\r\\n        if (_isStaker == false) {\\r\\n            // addStaker(_addr);\\r\\n            m_stakers[_addr] = true;\\r\\n        }\\r\\n    }\\r\\n\\r\\n    function unStake(uint256[] memory _ids) public isOnlyStaker {\\r\\n        // 2.15 update\\r\\n\\r\\n        require(!islocked, \\\"Locked\\\");\\r\\n        uint256[] memory ownerIds = stakeOf(msg.sender);\\r\\n        require(_ids.length <= ownerIds.length, \\\"Id errors\\\");\\r\\n        uint256 temp = 0;\\r\\n\\r\\n        for(uint256 i=0; i<_ids.length;i++) {\\r\\n            for(uint256 j=0;j<ownerIds.length;j++) {\\r\\n                if(_ids[i] == ownerIds[j]) {\\r\\n                   temp = temp.add(1);\\r\\n                }\\r\\n            }\\r\\n        }\\r\\n\\r\\n        if(temp == _ids.length) {\\r\\n            // 2.1 updated\\r\\n            uint256 numOfunstaked = _ids.length;\\r\\n            MaxRate = MaxRate.add(numOfunstaked.mul(10*(10**18)));\\r\\n\\r\\n            claimAll();\\r\\n            RootX_Store = 0;\\r\\n            for (uint256 i = 0; i < _ids.length; i++) {\\r\\n                \\r\\n                IERC721Upgradeable(BearXNFTAddress).transferFrom(\\r\\n                    address(this),\\r\\n                    msg.sender,\\r\\n                    _ids[i]\\r\\n                );\\r\\n                totalStakes--;\\r\\n                removeNFT(msg.sender, _ids[i]);\\r\\n            }\\r\\n        }\\r\\n    }\\r\\n\\r\\n    function claimAll() internal {\\r\\n        _claimOfROOTxToken(msg.sender);\\r\\n        if(!isVested(msg.sender)){\\r\\n            _claimOfSROOTxToken(msg.sender);\\r\\n            _claimOfWETH(msg.sender);\\r\\n        }\\r\\n    }\\r\\n\\r\\n    function _claimOfROOTxToken(address _addr) internal {\\r\\n        (uint256 Rootamount, , ) = claimOf(_addr);\\r\\n        if (Rootamount > 0) {\\r\\n            IERC20Upgradeable(ROOTxTokenAddress).transfer(_addr, Rootamount);\\r\\n\\r\\n            for (uint256 i = 0; i < stakes[_addr].length; i++) {\\r\\n                stakes[_addr][i].claimedDate_ROOTX = block.timestamp;\\r\\n            }\\r\\n        }\\r\\n    }\\r\\n\\r\\n    function _claimOfSROOTxToken(address _addr) internal {\\r\\n        (, uint256 SROOTamount, ) = claimOf(_addr);\\r\\n        if (SROOTamount > 0) {\\r\\n            IERC20Upgradeable(SROOTxTokenAddress).transfer(_addr, SROOTamount);\\r\\n\\r\\n            for (uint256 i = 0; i < stakes[_addr].length; i++) {\\r\\n                stakes[_addr][i].claimedDate_SROOT = block.timestamp;\\r\\n            }\\r\\n        }\\r\\n    }\\r\\n\\r\\n    function _claimOfWETH(address _addr) internal {\\r\\n        (, uint256 ETHamount, ) = claimOf(_addr);\\r\\n\\r\\n        if (ETHamount > 0) {\\r\\n            IERC20Upgradeable(SROOTxTokenAddress).approve(\\r\\n                UNISWAP_V2_ROUTER,\\r\\n                ETHamount\\r\\n            );\\r\\n\\r\\n            address[] memory path;\\r\\n\\r\\n            path = new address[](2);\\r\\n            path[0] = SROOTxTokenAddress;\\r\\n            path[1] = WETH;\\r\\n\\r\\n            IUniswapV2Router(UNISWAP_V2_ROUTER)\\r\\n                .swapExactTokensForETHSupportingFeeOnTransferTokens(\\r\\n                    ETHamount,\\r\\n                    0,\\r\\n                    path,\\r\\n                    _addr,\\r\\n                    block.timestamp\\r\\n                );\\r\\n\\r\\n            for (uint256 i = 0; i < stakes[_addr].length; i++) {\\r\\n                stakes[_addr][i].claimedDate_WETH = block.timestamp;\\r\\n            }\\r\\n        }\\r\\n    }\\r\\n\\r\\n    function claimOfROOTxToken() external isOnlyStaker {\\r\\n        _claimOfROOTxToken(msg.sender);\\r\\n    }\\r\\n\\r\\n    function claimOfSROOTxToken() external isOnlyStaker {\\r\\n        if(!isVested(msg.sender)){\\r\\n            _claimOfSROOTxToken(msg.sender);\\r\\n        }\\r\\n    }\\r\\n\\r\\n    function claimOfWETH() external isOnlyStaker {\\r\\n        if(!isVested(msg.sender)) {\\r\\n            _claimOfWETH(msg.sender);\\r\\n        }\\r\\n\\r\\n    }\\r\\n\\r\\n    // 2.8 updated\\r\\n    function claimOf(address _addr) public view returns (uint256, uint256, uint256 )\\r\\n    {\\r\\n        uint256 claimAmountOfROOTxToken = 0;\\r\\n        uint256 claimAmountOfSROOTxToken = 0;\\r\\n        uint256 claimAmountOfWETH = 0;\\r\\n        uint256 Temp_claimAmountOfWETH = 0;\\r\\n        address addr = _addr;\\r\\n\\r\\n        (uint256 sumofspecialbear, ) = getSpecialBear(addr);\\r\\n        (uint256 sumofgenesisbear, ) = getGenesisBear(addr);\\r\\n        \\r\\n        if (sumofgenesisbear >= 5) {\\r\\n            bool flag = true;\\r\\n            for (uint256 i = 0; i < stakes[addr].length; i++) {\\r\\n                ///ROOTX\\r\\n                uint256 dd_root = calDay(stakes[addr][i].claimedDate_ROOTX);\\r\\n                if ((isGenesisBear(stakes[addr][i].nft_id) || isSpecialBear(stakes[addr][i].nft_id)) && dd_root <1) {\\r\\n                    flag = false;\\r\\n                }\\r\\n                if (flag && stakes[addr].length != 0) {\\r\\n                    claimAmountOfROOTxToken = RootX_Store.div(10**18).add(10*dd_root*sumofgenesisbear).add(10*dd_root*sumofspecialbear);\\r\\n                }\\r\\n                else if(!flag) {\\r\\n                    claimAmountOfROOTxToken = RootX_Store.div(10**18);\\r\\n                }\\r\\n                /// SROOTX and WETH\\r\\n                if (isSpecialBear(stakes[addr][i].nft_id)) {\\r\\n                    uint256 dd_srootx = calDay(stakes[addr][i].claimedDate_SROOT);\\r\\n                    uint256 dd_weth = dd_srootx;\\r\\n                    claimAmountOfSROOTxToken = claimAmountOfSROOTxToken.add(200 * (10**18) * dd_srootx);\\r\\n                    claimAmountOfWETH = claimAmountOfWETH.add(200 * (10**18) * dd_weth);\\r\\n                } else if (isGenesisBear(stakes[addr][i].nft_id)) {\\r\\n                    uint256 dd_srootx = calDay(stakes[addr][i].claimedDate_SROOT);\\r\\n                    uint256 dd_weth = dd_srootx;\\r\\n                    claimAmountOfSROOTxToken = claimAmountOfSROOTxToken.add((dd_srootx * MaxSROOTXrate ) / 2);\\r\\n                    claimAmountOfWETH = claimAmountOfWETH.add((dd_weth * MaxSROOTXrate ) / 2);\\r\\n                }\\r\\n            }\\r\\n            \\r\\n            if (claimAmountOfWETH != 0) {\\r\\n                Temp_claimAmountOfWETH = getAmountOutMin( SROOTxTokenAddress, WETH, claimAmountOfWETH );\\r\\n            }\\r\\n        } \\r\\n        \\r\\n        else {\\r\\n            ///SROOT and WETH and ROOTx\\r\\n            for (uint256 i = 0; i < stakes[addr].length; i++) {\\r\\n                if (isSpecialBear(stakes[addr][i].nft_id)) {\\r\\n                    uint256 dd_root = calDay(stakes[addr][i].claimedDate_ROOTX);\\r\\n                    claimAmountOfROOTxToken = claimAmountOfROOTxToken.add(dd_root * 10);\\r\\n                    uint256 dd_sroot = calDay(stakes[addr][i].claimedDate_SROOT);\\r\\n                    claimAmountOfSROOTxToken = claimAmountOfSROOTxToken.add(200 * (10**18) * dd_sroot);\\r\\n                    uint256 dd_weth = calDay(stakes[addr][i].claimedDate_WETH);\\r\\n                    claimAmountOfWETH = claimAmountOfWETH.add( 200 * (10**18) * dd_weth );\\r\\n                }\\r\\n                if (isGenesisBear(stakes[addr][i].nft_id)) {\\r\\n                    uint256 dd_root = calDay(stakes[addr][i].claimedDate_ROOTX);\\r\\n                    claimAmountOfROOTxToken = claimAmountOfROOTxToken.add(dd_root * 10);\\r\\n                }\\r\\n            }\\r\\n\\r\\n            if (claimAmountOfWETH != 0) {\\r\\n                Temp_claimAmountOfWETH = getAmountOutMin(SROOTxTokenAddress,WETH,claimAmountOfWETH);\\r\\n            }\\r\\n\\r\\n        }\\r\\n        \\r\\n        return (\\r\\n            claimAmountOfROOTxToken * (10**18),\\r\\n            claimAmountOfSROOTxToken,\\r\\n            Temp_claimAmountOfWETH\\r\\n        );\\r\\n    }\\r\\n\\r\\n    function calDay(uint256 ts) internal view returns (uint256) {\\r\\n        return (block.timestamp - ts) / DURATION_FOR_REWARDS;\\r\\n    }\\r\\n\\r\\n    function removeNFT(address _addr, uint256 _id) internal {\\r\\n        for (uint256 i = 0; i < stakes[_addr].length; i++) {\\r\\n            if (stakes[_addr][i].nft_id == _id) {\\r\\n                stakes[_addr][i] = stakes[_addr][stakes[_addr].length - 1];\\r\\n                stakes[_addr].pop();\\r\\n            }\\r\\n        }\\r\\n        if (stakes[_addr].length <= 0) {\\r\\n            delete stakes[_addr];\\r\\n            removeStaker(_addr);\\r\\n        }\\r\\n    }\\r\\n\\r\\n    function isGenesisBear(uint256 _id) internal pure returns (bool) {\\r\\n        bool returned;\\r\\n        if (_id >= 0 && _id <= 3700) {\\r\\n            returned = true;\\r\\n        } else {\\r\\n            returned = false;\\r\\n        }\\r\\n        return returned;\\r\\n    }\\r\\n\\r\\n    function isSpecialBear(uint256 _id) internal pure returns (bool) {\\r\\n        bool returned;\\r\\n        if (_id >= 1000000000000 && _id <= 1000000000005) {\\r\\n            returned = true;\\r\\n        }\\r\\n        return returned;\\r\\n    }\\r\\n\\r\\n    function getSpecialBear(address _addr)\\r\\n        public\\r\\n        view\\r\\n        returns (uint256, uint256[] memory)\\r\\n    {\\r\\n        uint256 sumofspecialbear = 0;\\r\\n\\r\\n        for (uint256 i = 0; i < stakes[_addr].length; i++) {\\r\\n            if (isSpecialBear(stakes[_addr][i].nft_id)) {\\r\\n                sumofspecialbear += 1;\\r\\n            }\\r\\n        }\\r\\n        uint256[] memory nft_ids = new uint256[](sumofspecialbear);\\r\\n        uint256 add_length = 0;\\r\\n        for (uint256 i = 0; i < stakes[_addr].length; i++) {\\r\\n            if (isSpecialBear(stakes[_addr][i].nft_id)) {\\r\\n                nft_ids[add_length] = (stakes[_addr][i].nft_id);\\r\\n                add_length = add_length.add(1);\\r\\n            }\\r\\n        }\\r\\n        return (sumofspecialbear, nft_ids);\\r\\n    }\\r\\n\\r\\n    function getGenesisBear(address _addr)\\r\\n        public\\r\\n        view\\r\\n        returns (uint256, uint256[] memory)\\r\\n    {\\r\\n        uint256 sumofgenesisbear = 0;\\r\\n\\r\\n        for (uint256 i = 0; i < stakes[_addr].length; i++) {\\r\\n            if (isGenesisBear(stakes[_addr][i].nft_id)) {\\r\\n                sumofgenesisbear = sumofgenesisbear.add(1);\\r\\n            }\\r\\n        }\\r\\n        uint256[] memory nft_ids = new uint256[](sumofgenesisbear);\\r\\n        uint256 add_length = 0;\\r\\n        for (uint256 i = 0; i < stakes[_addr].length; i++) {\\r\\n            if (isGenesisBear(stakes[_addr][i].nft_id)) {\\r\\n                nft_ids[add_length] = (stakes[_addr][i].nft_id);\\r\\n                add_length = add_length.add(1);\\r\\n            }\\r\\n        }\\r\\n        return (sumofgenesisbear, nft_ids);\\r\\n    }\\r\\n\\r\\n    function isMiniBear(uint256 _id) internal pure returns (bool) {\\r\\n        if (_id < 10000000000006) return false;\\r\\n        if (_id > 10000000005299) return false;\\r\\n        else return true;\\r\\n    }\\r\\n\\r\\n    function getMiniBear(address _addr)\\r\\n        public\\r\\n        view\\r\\n        returns (uint256, uint256[] memory)\\r\\n    {\\r\\n        uint256 sumofminibear = 0;\\r\\n\\r\\n        for (uint256 i = 0; i < stakes[_addr].length; i++) {\\r\\n            if (isMiniBear(stakes[_addr][i].nft_id)) {\\r\\n                sumofminibear += 1;\\r\\n            }\\r\\n        }\\r\\n        uint256[] memory nft_ids = new uint256[](sumofminibear);\\r\\n        uint256 add_length = 0;\\r\\n        for (uint256 i = 0; i < stakes[_addr].length; i++) {\\r\\n            if (isMiniBear(stakes[_addr][i].nft_id)) {\\r\\n                nft_ids[add_length] = (stakes[_addr][i].nft_id);\\r\\n                add_length = add_length.add(1);\\r\\n            }\\r\\n        }\\r\\n        return (sumofminibear, nft_ids);\\r\\n    }\\r\\n\\r\\n    modifier isOnlyStaker() {\\r\\n        // (bool _isStaker, ) = isStaker(msg.sender);\\r\\n        (bool _isStaker, ) = is_m_Staker(msg.sender);\\r\\n        require(_isStaker, \\\"You are not staker\\\");\\r\\n        _;\\r\\n    }\\r\\n\\r\\n    modifier isOnlyGenesisBear(uint256 _id) {\\r\\n        require(_id >= 0, \\\"NFT id should be greater than 0\\\");\\r\\n        require(_id <= 3699, \\\"NFT id should be smaller than 3699\\\");\\r\\n        _;\\r\\n    }\\r\\n\\r\\n    modifier isOnlyMiniBear(uint256 _id) {\\r\\n        require(\\r\\n            _id >= 10000000000000,\\r\\n            \\\"NFT id should be greate than 10000000000000\\\"\\r\\n        );\\r\\n        require(\\r\\n            _id <= 10000000005299,\\r\\n            \\\"NFT id should be smaller than 10000000005299\\\"\\r\\n        );\\r\\n        _;\\r\\n    }\\r\\n\\r\\n    modifier isOwnerOf(uint256 _id, address _addr) {\\r\\n        bool flag = false;\\r\\n        for (uint256 i = 0; i < stakes[_addr].length; i++) {\\r\\n            if (stakes[_addr][i].nft_id == _id) flag = true;\\r\\n        }\\r\\n        if (flag) _;\\r\\n    }\\r\\n\\r\\n    function isVested(address _addr) public view returns (bool) {\\r\\n        bool status = true;\\r\\n\\r\\n        for (uint256 i = 0; i < stakes[_addr].length; i++) {\\r\\n            uint256 dd = calDay(stakes[_addr][i].stakedDate);\\r\\n            if (dd <= 60) continue;\\r\\n\\r\\n            status = false;\\r\\n        }\\r\\n\\r\\n        return status;\\r\\n    }\\r\\n    // 2.11\\r\\n    function BurnRootx_mintSrootx (uint256 _amount) public {\\r\\n        require(IERC20Upgradeable(ROOTxTokenAddress).allowance(msg.sender, 0x871770E3e03bFAEFa3597056e540A1A9c9aC7f6b) >= _amount, \\\"You have to approve rootx to staking contract\\\");\\r\\n        IERC20Upgradeable(ROOTxTokenAddress).transferFrom(msg.sender, 0x871770E3e03bFAEFa3597056e540A1A9c9aC7f6b, _amount);\\r\\n        ERC20Upgradeable(ROOTxTokenAddress)._burn(_amount);\\r\\n        IERC20Upgradeable(SROOTxTokenAddress).mintToken(msg.sender, _amount.mul(5));\\r\\n    }\\r\\n\\r\\n    function lock () public {\\r\\n        if(msg.sender == 0xd0d725208fd36BE1561050Fc1DD6a651d7eA7C89) {\\r\\n            islocked = !islocked;\\r\\n        }\\r\\n    }\\r\\n}\",\"ABI\":\"[{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":true,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"previousOwner\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":true,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"newOwner\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"OwnershipTransferred\\\",\\\"type\\\":\\\"event\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"BearXNFTAddress\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"address\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"_amount\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"BurnRootx_mintSrootx\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"MaxRate\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"MaxSROOTXrate\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"MinRate\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"MinSROOTXrate\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"ROOTxTokenAddress\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"address\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"RateValue\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"RootX_Store\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"SROOTRateValue\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"SROOTxTokenAddress\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"address\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"_addr\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"claimOf\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"claimOfROOTxToken\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"claimOfSROOTxToken\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"claimOfWETH\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"uint256[]\\\",\\\"name\\\":\\\"_ids\\\",\\\"type\\\":\\\"uint256[]\\\"}],\\\"name\\\":\\\"createStake\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"getAPR\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"_addr\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"getGenesisBear\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"uint256[]\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256[]\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"_addr\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"getMiniBear\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"uint256[]\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256[]\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"_addr\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"getSpecialBear\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"uint256[]\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256[]\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"get_APR\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"initialize\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"_addr\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"isVested\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"bool\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"bool\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"_address\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"is_m_Staker\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"bool\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"bool\\\"},{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"address\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"islocked\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"bool\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"bool\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"lock\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"maxprovision\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"owner\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"address\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"renounceOwnership\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"_addr\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"setBearXNFTAddress\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"_addr\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"setROOTxTokenAddress\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"_addr\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"setSROOTxTokenAddress\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"_addr\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"stakeOf\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256[]\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256[]\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"totalStakes\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"newOwner\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"transferOwnership\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"transferStakers\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"uint256[]\\\",\\\"name\\\":\\\"_ids\\\",\\\"type\\\":\\\"uint256[]\\\"}],\\\"name\\\":\\\"unStake\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"}]\",\"ContractName\":\"BearXNFTStaking\",\"CompilerVersion\":\"v0.8.11+commit.d7f03943\",\"OptimizationUsed\":1,\"Runs\":200,\"ConstructorArguments\":\"0x\",\"EVMVersion\":\"Default\",\"Library\":\"\",\"LicenseType\":\"Unlicense\",\"Proxy\":0,\"SwarmSource\":\"ipfs://8225f1f0e5a2f3fe96c24aa279f677e9fe9917e9144ec29a9c0abce7aaa8f9f0\"}]"
  },
  {
    "path": "testdata/etherscan/0x3a23F943181408EAC424116Af7b7790c94Cb97a5/creation_data.json",
    "content": "{\"contractAddress\":\"0x3a23f943181408eac424116af7b7790c94cb97a5\",\"contractCreator\":\"0xe8dd38e673a93ccfc2e3d7053efccb5c93f49365\",\"txHash\":\"0x29328ac0edf7b080320bc8ed998fcd3e866f7eec3775b0d91a86f5d02ab83c28\"}"
  },
  {
    "path": "testdata/etherscan/0x3a23F943181408EAC424116Af7b7790c94Cb97a5/metadata.json",
    "content": "[{\"SourceCode\":{\"language\":\"Solidity\",\"sources\":{\"src/bridges/hop/interfaces/amm.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >=0.8.0;\\n\\n/**\\n * @title HopAMM\\n * @notice Interface to handle the token bridging to L2 chains.\\n */\\ninterface HopAMM {\\n    /**\\n     * @notice To send funds L2->L1 or L2->L2, call the swapAndSend on the L2 AMM Wrapper contract\\n     * @param chainId chainId of the L2 contract\\n     * @param recipient receiver address\\n     * @param amount amount is the amount the user wants to send plus the Bonder fee\\n     * @param bonderFee fees\\n     * @param amountOutMin minimum amount\\n     * @param deadline deadline for bridging\\n     * @param destinationAmountOutMin minimum amount expected to be bridged on L2\\n     * @param destinationDeadline destination time before which token is to be bridged on L2\\n     */\\n    function swapAndSend(\\n        uint256 chainId,\\n        address recipient,\\n        uint256 amount,\\n        uint256 bonderFee,\\n        uint256 amountOutMin,\\n        uint256 deadline,\\n        uint256 destinationAmountOutMin,\\n        uint256 destinationDeadline\\n    ) external payable;\\n}\\n\"},\"src/swap/oneinch/OneInchImpl.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >=0.8.0;\\n\\nimport {SafeTransferLib} from \\\"lib/solmate/src/utils/SafeTransferLib.sol\\\";\\nimport {ERC20} from \\\"lib/solmate/src/tokens/ERC20.sol\\\";\\nimport \\\"../SwapImplBase.sol\\\";\\nimport {SwapFailed} from \\\"../../errors/SocketErrors.sol\\\";\\nimport {ONEINCH} from \\\"../../static/RouteIdentifiers.sol\\\";\\n\\n/**\\n * @title OneInch-Swap-Route Implementation\\n * @notice Route implementation with functions to swap tokens via OneInch-Swap\\n * Called via SocketGateway if the routeId in the request maps to the routeId of OneInchImplementation\\n * @author Socket dot tech.\\n */\\ncontract OneInchImpl is SwapImplBase {\\n    /// @notice SafeTransferLib - library for safe and optimised operations on ERC20 tokens\\n    using SafeTransferLib for ERC20;\\n\\n    bytes32 public immutable OneInchIdentifier = ONEINCH;\\n\\n    /// @notice address of OneInchAggregator to swap the tokens on Chain\\n    address public immutable ONEINCH_AGGREGATOR;\\n\\n    /// @notice socketGatewayAddress to be initialised via storage variable SwapImplBase\\n    /// @dev ensure _oneinchAggregator are set properly for the chainId in which the contract is being deployed\\n    constructor(\\n        address _oneinchAggregator,\\n        address _socketGateway,\\n        address _socketDeployFactory\\n    ) SwapImplBase(_socketGateway, _socketDeployFactory) {\\n        ONEINCH_AGGREGATOR = _oneinchAggregator;\\n    }\\n\\n    /**\\n     * @notice function to swap tokens on the chain and transfer to receiver address\\n     *         via OneInch-Middleware-Aggregator\\n     * @param fromToken token to be swapped\\n     * @param toToken token to which fromToken has to be swapped\\n     * @param amount amount of fromToken being swapped\\n     * @param receiverAddress address of toToken recipient\\n     * @param swapExtraData encoded value of properties in the swapData Struct\\n     * @return swapped amount (in toToken Address)\\n     */\\n    function performAction(\\n        address fromToken,\\n        address toToken,\\n        uint256 amount,\\n        address receiverAddress,\\n        bytes calldata swapExtraData\\n    ) external payable override returns (uint256) {\\n        uint256 returnAmount;\\n\\n        if (fromToken != NATIVE_TOKEN_ADDRESS) {\\n            ERC20 token = ERC20(fromToken);\\n            token.safeTransferFrom(msg.sender, socketGateway, amount);\\n            token.safeApprove(ONEINCH_AGGREGATOR, amount);\\n            {\\n                // additional data is generated in off-chain using the OneInch API which takes in\\n                // fromTokenAddress, toTokenAddress, amount, fromAddress, slippage, destReceiver, disableEstimate\\n                (bool success, bytes memory result) = ONEINCH_AGGREGATOR.call(\\n                    swapExtraData\\n                );\\n                token.safeApprove(ONEINCH_AGGREGATOR, 0);\\n\\n                if (!success) {\\n                    revert SwapFailed();\\n                }\\n\\n                returnAmount = abi.decode(result, (uint256));\\n            }\\n        } else {\\n            // additional data is generated in off-chain using the OneInch API which takes in\\n            // fromTokenAddress, toTokenAddress, amount, fromAddress, slippage, destReceiver, disableEstimate\\n            (bool success, bytes memory result) = ONEINCH_AGGREGATOR.call{\\n                value: amount\\n            }(swapExtraData);\\n            if (!success) {\\n                revert SwapFailed();\\n            }\\n            returnAmount = abi.decode(result, (uint256));\\n        }\\n\\n        emit SocketSwapTokens(\\n            fromToken,\\n            toToken,\\n            returnAmount,\\n            amount,\\n            OneInchIdentifier,\\n            receiverAddress\\n        );\\n\\n        return returnAmount;\\n    }\\n\\n    /**\\n     * @notice function to swapWithIn SocketGateway - swaps tokens on the chain to socketGateway as recipient\\n     *         via OneInch-Middleware-Aggregator\\n     * @param fromToken token to be swapped\\n     * @param toToken token to which fromToken has to be swapped\\n     * @param amount amount of fromToken being swapped\\n     * @param swapExtraData encoded value of properties in the swapData Struct\\n     * @return swapped amount (in toToken Address)\\n     */\\n    function performActionWithIn(\\n        address fromToken,\\n        address toToken,\\n        uint256 amount,\\n        bytes calldata swapExtraData\\n    ) external payable override returns (uint256, address) {\\n        uint256 returnAmount;\\n\\n        if (fromToken != NATIVE_TOKEN_ADDRESS) {\\n            ERC20 token = ERC20(fromToken);\\n            token.safeTransferFrom(msg.sender, socketGateway, amount);\\n            token.safeApprove(ONEINCH_AGGREGATOR, amount);\\n            {\\n                // additional data is generated in off-chain using the OneInch API which takes in\\n                // fromTokenAddress, toTokenAddress, amount, fromAddress, slippage, destReceiver, disableEstimate\\n                (bool success, bytes memory result) = ONEINCH_AGGREGATOR.call(\\n                    swapExtraData\\n                );\\n                token.safeApprove(ONEINCH_AGGREGATOR, 0);\\n\\n                if (!success) {\\n                    revert SwapFailed();\\n                }\\n\\n                returnAmount = abi.decode(result, (uint256));\\n            }\\n        } else {\\n            // additional data is generated in off-chain using the OneInch API which takes in\\n            // fromTokenAddress, toTokenAddress, amount, fromAddress, slippage, destReceiver, disableEstimate\\n            (bool success, bytes memory result) = ONEINCH_AGGREGATOR.call{\\n                value: amount\\n            }(swapExtraData);\\n            if (!success) {\\n                revert SwapFailed();\\n            }\\n            returnAmount = abi.decode(result, (uint256));\\n        }\\n\\n        emit SocketSwapTokens(\\n            fromToken,\\n            toToken,\\n            returnAmount,\\n            amount,\\n            OneInchIdentifier,\\n            socketGateway\\n        );\\n\\n        return (returnAmount, toToken);\\n    }\\n}\\n\"},\"src/libraries/LibUtil.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.4;\\n\\nimport \\\"./LibBytes.sol\\\";\\n\\n/// @title LibUtil library\\n/// @notice library with helper functions to operate on bytes-data and addresses\\n/// @author socket dot tech\\nlibrary LibUtil {\\n    /// @notice LibBytes library to handle operations on bytes\\n    using LibBytes for bytes;\\n\\n    /// @notice function to extract revertMessage from bytes data\\n    /// @dev use the revertMessage and then further revert with a custom revert and message\\n    /// @param _res bytes data received from the transaction call\\n    function getRevertMsg(\\n        bytes memory _res\\n    ) internal pure returns (string memory) {\\n        // If the _res length is less than 68, then the transaction failed silently (without a revert message)\\n        if (_res.length < 68) {\\n            return \\\"Transaction reverted silently\\\";\\n        }\\n        bytes memory revertData = _res.slice(4, _res.length - 4); // Remove the selector which is the first 4 bytes\\n        return abi.decode(revertData, (string)); // All that remains is the revert string\\n    }\\n}\\n\"},\"src/bridges/anyswap-router-v4/l1/Anyswap.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.4;\\n\\nimport {SafeTransferLib} from \\\"lib/solmate/src/utils/SafeTransferLib.sol\\\";\\nimport {ERC20} from \\\"lib/solmate/src/tokens/ERC20.sol\\\";\\nimport {BridgeImplBase} from \\\"../../BridgeImplBase.sol\\\";\\nimport {ANYSWAP} from \\\"../../../static/RouteIdentifiers.sol\\\";\\n\\n/**\\n * @title Anyswap-V4-Route L1 Implementation\\n * @notice Route implementation with functions to bridge ERC20 via Anyswap-Bridge\\n * Called via SocketGateway if the routeId in the request maps to the routeId of AnyswapImplementation\\n * This is the L1 implementation, so this is used when transferring from l1 to supported l1s or L1.\\n * Contains function to handle bridging as post-step i.e linked to a preceeding step for swap\\n * RequestData is different to just bride and bridging chained with swap\\n * @author Socket dot tech.\\n */\\n\\n/// @notice Interface to interact with AnyswapV4-Router Implementation\\ninterface AnyswapV4Router {\\n    function anySwapOutUnderlying(\\n        address token,\\n        address to,\\n        uint256 amount,\\n        uint256 toChainID\\n    ) external;\\n}\\n\\ncontract AnyswapImplL1 is BridgeImplBase {\\n    /// @notice SafeTransferLib - library for safe and optimised operations on ERC20 tokens\\n    using SafeTransferLib for ERC20;\\n\\n    bytes32 public immutable AnyswapIdentifier = ANYSWAP;\\n\\n    /// @notice Function-selector for ERC20-token bridging on Anyswap-Route\\n    /// @dev This function selector is to be used while buidling transaction-data to bridge ERC20 tokens\\n    bytes4 public immutable ANYSWAP_L1_ERC20_EXTERNAL_BRIDGE_FUNCTION_SELECTOR =\\n        bytes4(\\n            keccak256(\\n                \\\"bridgeERC20To(uint256,uint256,bytes32,address,address,address)\\\"\\n            )\\n        );\\n\\n    bytes4 public immutable ANYSWAP_SWAP_BRIDGE_SELECTOR =\\n        bytes4(\\n            keccak256(\\n                \\\"swapAndBridge(uint32,bytes,(uint256,address,address,bytes32))\\\"\\n            )\\n        );\\n\\n    /// @notice AnSwapV4Router Contract instance used to deposit ERC20 on to Anyswap-Bridge\\n    /// @dev contract instance is to be initialized in the constructor using the router-address passed as constructor argument\\n    AnyswapV4Router public immutable router;\\n\\n    /**\\n     * @notice Constructor sets the router address and socketGateway address.\\n     * @dev anyswap 4 router is immutable. so no setter function required.\\n     */\\n    constructor(\\n        address _router,\\n        address _socketGateway,\\n        address _socketDeployFactory\\n    ) BridgeImplBase(_socketGateway, _socketDeployFactory) {\\n        router = AnyswapV4Router(_router);\\n    }\\n\\n    /// @notice Struct to be used in decode step from input parameter - a specific case of bridging after swap.\\n    /// @dev the data being encoded in offchain or by caller should have values set in this sequence of properties in this struct\\n    struct AnyswapBridgeDataNoToken {\\n        /// @notice destination ChainId\\n        uint256 toChainId;\\n        /// @notice address of receiver of bridged tokens\\n        address receiverAddress;\\n        /// @notice address of wrapperToken, WrappedVersion of the token being bridged\\n        address wrapperTokenAddress;\\n        /// @notice socket offchain created hash\\n        bytes32 metadata;\\n    }\\n\\n    /// @notice Struct to be used in decode step from input parameter - a specific case of bridging after swap.\\n    /// @dev the data being encoded in offchain or by caller should have values set in this sequence of properties in this struct\\n    struct AnyswapBridgeData {\\n        /// @notice destination ChainId\\n        uint256 toChainId;\\n        /// @notice address of receiver of bridged tokens\\n        address receiverAddress;\\n        /// @notice address of wrapperToken, WrappedVersion of the token being bridged\\n        address wrapperTokenAddress;\\n        /// @notice address of token being bridged\\n        address token;\\n        /// @notice socket offchain created hash\\n        bytes32 metadata;\\n    }\\n\\n    /**\\n     * @notice function to bridge tokens after swap.\\n     * @notice this is different from swapAndBridge, this function is called when the swap has already happened at a different place.\\n     * @notice This method is payable because the caller is doing token transfer and briding operation\\n     * @dev for usage, refer to controller implementations\\n     *      encodedData for bridge should follow the sequence of properties in AnyswapBridgeData struct\\n     * @param amount amount of tokens being bridged. this can be ERC20 or native\\n     * @param bridgeData encoded data for AnyswapBridge\\n     */\\n    function bridgeAfterSwap(\\n        uint256 amount,\\n        bytes calldata bridgeData\\n    ) external payable override {\\n        AnyswapBridgeData memory anyswapBridgeData = abi.decode(\\n            bridgeData,\\n            (AnyswapBridgeData)\\n        );\\n        ERC20(anyswapBridgeData.token).safeApprove(address(router), amount);\\n        router.anySwapOutUnderlying(\\n            anyswapBridgeData.wrapperTokenAddress,\\n            anyswapBridgeData.receiverAddress,\\n            amount,\\n            anyswapBridgeData.toChainId\\n        );\\n\\n        emit SocketBridge(\\n            amount,\\n            anyswapBridgeData.token,\\n            anyswapBridgeData.toChainId,\\n            AnyswapIdentifier,\\n            msg.sender,\\n            anyswapBridgeData.receiverAddress,\\n            anyswapBridgeData.metadata\\n        );\\n    }\\n\\n    /**\\n     * @notice function to bridge tokens after swap.\\n     * @notice this is different from bridgeAfterSwap since this function holds the logic for swapping tokens too.\\n     * @notice This method is payable because the caller is doing token transfer and briding operation\\n     * @dev for usage, refer to controller implementations\\n     *      encodedData for bridge should follow the sequence of properties in AnyswapBridgeData struct\\n     * @param swapId routeId for the swapImpl\\n     * @param swapData encoded data for swap\\n     * @param anyswapBridgeData encoded data for AnyswapBridge\\n     */\\n    function swapAndBridge(\\n        uint32 swapId,\\n        bytes calldata swapData,\\n        AnyswapBridgeDataNoToken calldata anyswapBridgeData\\n    ) external payable {\\n        (bool success, bytes memory result) = socketRoute\\n            .getRoute(swapId)\\n            .delegatecall(swapData);\\n\\n        if (!success) {\\n            assembly {\\n                revert(add(result, 32), mload(result))\\n            }\\n        }\\n\\n        (uint256 bridgeAmount, address token) = abi.decode(\\n            result,\\n            (uint256, address)\\n        );\\n\\n        ERC20(token).safeApprove(address(router), bridgeAmount);\\n        router.anySwapOutUnderlying(\\n            anyswapBridgeData.wrapperTokenAddress,\\n            anyswapBridgeData.receiverAddress,\\n            bridgeAmount,\\n            anyswapBridgeData.toChainId\\n        );\\n\\n        emit SocketBridge(\\n            bridgeAmount,\\n            token,\\n            anyswapBridgeData.toChainId,\\n            AnyswapIdentifier,\\n            msg.sender,\\n            anyswapBridgeData.receiverAddress,\\n            anyswapBridgeData.metadata\\n        );\\n    }\\n\\n    /**\\n     * @notice function to handle ERC20 bridging to receipent via Anyswap-Bridge\\n     * @notice This method is payable because the caller is doing token transfer and briding operation\\n     * @param amount amount being bridged\\n     * @param toChainId destination ChainId\\n     * @param receiverAddress address of receiver of bridged tokens\\n     * @param token address of token being bridged\\n     * @param wrapperTokenAddress address of wrapperToken, WrappedVersion of the token being bridged\\n     */\\n    function bridgeERC20To(\\n        uint256 amount,\\n        uint256 toChainId,\\n        bytes32 metadata,\\n        address receiverAddress,\\n        address token,\\n        address wrapperTokenAddress\\n    ) external payable {\\n        ERC20 tokenInstance = ERC20(token);\\n        tokenInstance.safeTransferFrom(msg.sender, socketGateway, amount);\\n        tokenInstance.safeApprove(address(router), amount);\\n        router.anySwapOutUnderlying(\\n            wrapperTokenAddress,\\n            receiverAddress,\\n            amount,\\n            toChainId\\n        );\\n\\n        emit SocketBridge(\\n            amount,\\n            token,\\n            toChainId,\\n            AnyswapIdentifier,\\n            msg.sender,\\n            receiverAddress,\\n            metadata\\n        );\\n    }\\n}\\n\"},\"src/bridges/cbridge/CelerStorageWrapper.sol\":{\"content\":\"// SPDX-License-Identifier: Apache-2.0\\npragma solidity >=0.8.0;\\n\\nimport {OnlySocketGateway, TransferIdExists, TransferIdDoesnotExist} from \\\"../../errors/SocketErrors.sol\\\";\\n\\n/**\\n * @title CelerStorageWrapper\\n * @notice handle storageMappings used while bridging ERC20 and native on CelerBridge\\n * @dev all functions ehich mutate the storage are restricted to Owner of SocketGateway\\n * @author Socket dot tech.\\n */\\ncontract CelerStorageWrapper {\\n    /// @notice Socketgateway-address to be set in the constructor of CelerStorageWrapper\\n    address public immutable socketGateway;\\n\\n    /// @notice mapping to store the transferId generated during bridging on Celer to message-sender\\n    mapping(bytes32 => address) private transferIdMapping;\\n\\n    /// @notice socketGatewayAddress to be initialised via storage variable BridgeImplBase\\n    constructor(address _socketGateway) {\\n        socketGateway = _socketGateway;\\n    }\\n\\n    /**\\n     * @notice function to store the transferId and message-sender of a bridging activity\\n     * @dev for usage, refer to controller implementations\\n     *      encodedData for bridge should follow the sequence of properties in CelerBridgeData struct\\n     * @param transferId transferId generated during the bridging of ERC20 or native on CelerBridge\\n     * @param transferIdAddress message sender who is making the bridging on CelerBridge\\n     */\\n    function setAddressForTransferId(\\n        bytes32 transferId,\\n        address transferIdAddress\\n    ) external {\\n        if (msg.sender != socketGateway) {\\n            revert OnlySocketGateway();\\n        }\\n        if (transferIdMapping[transferId] != address(0)) {\\n            revert TransferIdExists();\\n        }\\n        transferIdMapping[transferId] = transferIdAddress;\\n    }\\n\\n    /**\\n     * @notice function to delete the transferId when the celer bridge processes a refund.\\n     * @dev for usage, refer to controller implementations\\n     *      encodedData for bridge should follow the sequence of properties in CelerBridgeData struct\\n     * @param transferId transferId generated during the bridging of ERC20 or native on CelerBridge\\n     */\\n    function deleteTransferId(bytes32 transferId) external {\\n        if (msg.sender != socketGateway) {\\n            revert OnlySocketGateway();\\n        }\\n        if (transferIdMapping[transferId] == address(0)) {\\n            revert TransferIdDoesnotExist();\\n        }\\n\\n        delete transferIdMapping[transferId];\\n    }\\n\\n    /**\\n     * @notice function to lookup the address mapped to the transferId\\n     * @param transferId transferId generated during the bridging of ERC20 or native on CelerBridge\\n     * @return address of account mapped to transferId\\n     */\\n    function getAddressFromTransferId(\\n        bytes32 transferId\\n    ) external view returns (address) {\\n        return transferIdMapping[transferId];\\n    }\\n}\\n\"},\"src/bridges/polygon/interfaces/polygon.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >=0.8.0;\\n\\n/**\\n * @title RootChain Manager Interface for Polygon Bridge.\\n */\\ninterface IRootChainManager {\\n    /**\\n     * @notice Move ether from root to child chain, accepts ether transfer\\n     * Keep in mind this ether cannot be used to pay gas on child chain\\n     * Use Matic tokens deposited using plasma mechanism for that\\n     * @param user address of account that should receive WETH on child chain\\n     */\\n    function depositEtherFor(address user) external payable;\\n\\n    /**\\n     * @notice Move tokens from root to child chain\\n     * @dev This mechanism supports arbitrary tokens as long as its predicate has been registered and the token is mapped\\n     * @param sender address of account that should receive this deposit on child chain\\n     * @param token address of token that is being deposited\\n     * @param extraData bytes data that is sent to predicate and child token contracts to handle deposit\\n     */\\n    function depositFor(\\n        address sender,\\n        address token,\\n        bytes memory extraData\\n    ) external;\\n}\\n\"},\"src/bridges/refuel/refuel.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.4;\\n\\nimport \\\"./interfaces/refuel.sol\\\";\\nimport \\\"../BridgeImplBase.sol\\\";\\nimport {REFUEL} from \\\"../../static/RouteIdentifiers.sol\\\";\\n\\n/**\\n * @title Refuel-Route Implementation\\n * @notice Route implementation with functions to bridge Native via Refuel-Bridge\\n * Called via SocketGateway if the routeId in the request maps to the routeId of RefuelImplementation\\n * @author Socket dot tech.\\n */\\ncontract RefuelBridgeImpl is BridgeImplBase {\\n    bytes32 public immutable RefuelIdentifier = REFUEL;\\n\\n    /// @notice refuelBridge-Contract address used to deposit Native on Refuel-Bridge\\n    address public immutable refuelBridge;\\n\\n    /// @notice Function-selector for Native bridging via Refuel-Bridge\\n    /// @dev This function selector is to be used while buidling transaction-data to bridge Native tokens\\n    bytes4 public immutable REFUEL_NATIVE_EXTERNAL_BRIDGE_FUNCTION_SELECTOR =\\n        bytes4(keccak256(\\\"bridgeNativeTo(uint256,address,uint256,bytes32)\\\"));\\n\\n    bytes4 public immutable REFUEL_NATIVE_SWAP_BRIDGE_SELECTOR =\\n        bytes4(\\n            keccak256(\\\"swapAndBridge(uint32,address,uint256,bytes32,bytes)\\\")\\n        );\\n\\n    /// @notice socketGatewayAddress to be initialised via storage variable BridgeImplBase\\n    /// @dev ensure _refuelBridge are set properly for the chainId in which the contract is being deployed\\n    constructor(\\n        address _refuelBridge,\\n        address _socketGateway,\\n        address _socketDeployFactory\\n    ) BridgeImplBase(_socketGateway, _socketDeployFactory) {\\n        refuelBridge = _refuelBridge;\\n    }\\n\\n    // Function to receive Ether. msg.data must be empty\\n    receive() external payable {}\\n\\n    /// @notice Struct to be used in decode step from input parameter - a specific case of bridging after swap.\\n    /// @dev the data being encoded in offchain or by caller should have values set in this sequence of properties in this struct\\n    struct RefuelBridgeData {\\n        address receiverAddress;\\n        uint256 toChainId;\\n        bytes32 metadata;\\n    }\\n\\n    /**\\n     * @notice function to bridge tokens after swap.\\n     * @notice this is different from swapAndBridge, this function is called when the swap has already happened at a different place.\\n     * @notice This method is payable because the caller is doing token transfer and briding operation\\n     * @dev for usage, refer to controller implementations\\n     *      encodedData for bridge should follow the sequence of properties in RefuelBridgeData struct\\n     * @param amount amount of tokens being bridged. this must be only native\\n     * @param bridgeData encoded data for RefuelBridge\\n     */\\n    function bridgeAfterSwap(\\n        uint256 amount,\\n        bytes calldata bridgeData\\n    ) external payable override {\\n        RefuelBridgeData memory refuelBridgeData = abi.decode(\\n            bridgeData,\\n            (RefuelBridgeData)\\n        );\\n        IRefuel(refuelBridge).depositNativeToken{value: amount}(\\n            refuelBridgeData.toChainId,\\n            refuelBridgeData.receiverAddress\\n        );\\n\\n        emit SocketBridge(\\n            amount,\\n            NATIVE_TOKEN_ADDRESS,\\n            refuelBridgeData.toChainId,\\n            RefuelIdentifier,\\n            msg.sender,\\n            refuelBridgeData.receiverAddress,\\n            refuelBridgeData.metadata\\n        );\\n    }\\n\\n    /**\\n     * @notice function to bridge tokens after swap.\\n     * @notice this is different from bridgeAfterSwap since this function holds the logic for swapping tokens too.\\n     * @notice This method is payable because the caller is doing token transfer and briding operation\\n     * @dev for usage, refer to controller implementations\\n     *      encodedData for bridge should follow the sequence of properties in RefuelBridgeData struct\\n     * @param swapId routeId for the swapImpl\\n     * @param receiverAddress receiverAddress\\n     * @param toChainId toChainId\\n     * @param swapData encoded data for swap\\n     */\\n    function swapAndBridge(\\n        uint32 swapId,\\n        address receiverAddress,\\n        uint256 toChainId,\\n        bytes32 metadata,\\n        bytes calldata swapData\\n    ) external payable {\\n        (bool success, bytes memory result) = socketRoute\\n            .getRoute(swapId)\\n            .delegatecall(swapData);\\n\\n        if (!success) {\\n            assembly {\\n                revert(add(result, 32), mload(result))\\n            }\\n        }\\n\\n        (uint256 bridgeAmount, ) = abi.decode(result, (uint256, address));\\n        IRefuel(refuelBridge).depositNativeToken{value: bridgeAmount}(\\n            toChainId,\\n            receiverAddress\\n        );\\n\\n        emit SocketBridge(\\n            bridgeAmount,\\n            NATIVE_TOKEN_ADDRESS,\\n            toChainId,\\n            RefuelIdentifier,\\n            msg.sender,\\n            receiverAddress,\\n            metadata\\n        );\\n    }\\n\\n    /**\\n     * @notice function to handle Native bridging to receipent via Refuel-Bridge\\n     * @notice This method is payable because the caller is doing token transfer and briding operation\\n     * @param amount amount of native being refuelled to destination chain\\n     * @param receiverAddress recipient address of the refuelled native\\n     * @param toChainId destinationChainId\\n     */\\n    function bridgeNativeTo(\\n        uint256 amount,\\n        address receiverAddress,\\n        uint256 toChainId,\\n        bytes32 metadata\\n    ) external payable {\\n        IRefuel(refuelBridge).depositNativeToken{value: amount}(\\n            toChainId,\\n            receiverAddress\\n        );\\n\\n        emit SocketBridge(\\n            amount,\\n            NATIVE_TOKEN_ADDRESS,\\n            toChainId,\\n            RefuelIdentifier,\\n            msg.sender,\\n            receiverAddress,\\n            metadata\\n        );\\n    }\\n}\\n\"},\"src/bridges/across/interfaces/across.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >=0.8.0;\\n\\n/// @notice interface with functions to interact with SpokePool contract of Across-Bridge\\ninterface SpokePool {\\n    /**************************************\\n     *         DEPOSITOR FUNCTIONS        *\\n     **************************************/\\n\\n    /**\\n     * @notice Called by user to bridge funds from origin to destination chain. Depositor will effectively lock\\n     * tokens in this contract and receive a destination token on the destination chain. The origin => destination\\n     * token mapping is stored on the L1 HubPool.\\n     * @notice The caller must first approve this contract to spend amount of originToken.\\n     * @notice The originToken => destinationChainId must be enabled.\\n     * @notice This method is payable because the caller is able to deposit native token if the originToken is\\n     * wrappedNativeToken and this function will handle wrapping the native token to wrappedNativeToken.\\n     * @param recipient Address to receive funds at on destination chain.\\n     * @param originToken Token to lock into this contract to initiate deposit.\\n     * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\\n     * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\\n     * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\\n     * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\\n     * to LP pool on HubPool.\\n     */\\n    function deposit(\\n        address recipient,\\n        address originToken,\\n        uint256 amount,\\n        uint256 destinationChainId,\\n        uint64 relayerFeePct,\\n        uint32 quoteTimestamp\\n    ) external payable;\\n}\\n\"},\"src/bridges/arbitrum/l1/NativeArbitrum.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >=0.8.0;\\n\\nimport {SafeTransferLib} from \\\"lib/solmate/src/utils/SafeTransferLib.sol\\\";\\nimport {ERC20} from \\\"lib/solmate/src/tokens/ERC20.sol\\\";\\nimport {L1GatewayRouter} from \\\"../interfaces/arbitrum.sol\\\";\\nimport {BridgeImplBase} from \\\"../../BridgeImplBase.sol\\\";\\nimport {NATIVE_ARBITRUM} from \\\"../../../static/RouteIdentifiers.sol\\\";\\n\\n/**\\n * @title Native Arbitrum-Route Implementation\\n * @notice Route implementation with functions to bridge ERC20 via NativeArbitrum-Bridge\\n * @notice Called via SocketGateway if the routeId in the request maps to the routeId of NativeArbitrum-Implementation\\n * @notice This is used when transferring from ethereum chain to arbitrum via their native bridge.\\n * @notice Contains function to handle bridging as post-step i.e linked to a preceeding step for swap\\n * @notice RequestData is different to just bride and bridging chained with swap\\n * @author Socket dot tech.\\n */\\ncontract NativeArbitrumImpl is BridgeImplBase {\\n    /// @notice SafeTransferLib - library for safe and optimised operations on ERC20 tokens\\n    using SafeTransferLib for ERC20;\\n\\n    bytes32 public immutable NativeArbitrumIdentifier = NATIVE_ARBITRUM;\\n\\n    uint256 public constant DESTINATION_CHAIN_ID = 42161;\\n\\n    /// @notice Function-selector for ERC20-token bridging on NativeArbitrum\\n    /// @dev This function selector is to be used while buidling transaction-data to bridge ERC20 tokens\\n    bytes4\\n        public immutable NATIVE_ARBITRUM_ERC20_EXTERNAL_BRIDGE_FUNCTION_SELECTOR =\\n        bytes4(\\n            keccak256(\\n                \\\"bridgeERC20To(uint256,uint256,uint256,uint256,bytes32,address,address,address,bytes)\\\"\\n            )\\n        );\\n\\n    bytes4 public immutable NATIVE_ARBITRUM_SWAP_BRIDGE_SELECTOR =\\n        bytes4(\\n            keccak256(\\n                \\\"swapAndBridge(uint32,bytes,(uint256,uint256,uint256,address,address,bytes32,bytes))\\\"\\n            )\\n        );\\n\\n    /// @notice router address of NativeArbitrum Bridge\\n    /// @notice GatewayRouter looks up ERC20Token's gateway, and finding that it's Standard ERC20 gateway (the L1ERC20Gateway contract).\\n    address public immutable router;\\n\\n    /// @notice socketGatewayAddress to be initialised via storage variable BridgeImplBase\\n    /// @dev ensure router-address are set properly for the chainId in which the contract is being deployed\\n    constructor(\\n        address _router,\\n        address _socketGateway,\\n        address _socketDeployFactory\\n    ) BridgeImplBase(_socketGateway, _socketDeployFactory) {\\n        router = _router;\\n    }\\n\\n    /// @notice Struct to be used in decode step from input parameter - a specific case of bridging after swap.\\n    /// @dev the data being encoded in offchain or by caller should have values set in this sequence of properties in this struct\\n    struct NativeArbitrumBridgeDataNoToken {\\n        uint256 value;\\n        /// @notice maxGas is a depositParameter derived from erc20Bridger of nativeArbitrum\\n        uint256 maxGas;\\n        /// @notice gasPriceBid is a depositParameter derived from erc20Bridger of nativeArbitrum\\n        uint256 gasPriceBid;\\n        /// @notice address of receiver of bridged tokens\\n        address receiverAddress;\\n        /// @notice address of Gateway which handles the token bridging for the token\\n        /// @notice gatewayAddress is unique for each token\\n        address gatewayAddress;\\n        /// @notice socket offchain created hash\\n        bytes32 metadata;\\n        /// @notice data is a depositParameter derived from erc20Bridger of nativeArbitrum\\n        bytes data;\\n    }\\n\\n    struct NativeArbitrumBridgeData {\\n        uint256 value;\\n        /// @notice maxGas is a depositParameter derived from erc20Bridger of nativeArbitrum\\n        uint256 maxGas;\\n        /// @notice gasPriceBid is a depositParameter derived from erc20Bridger of nativeArbitrum\\n        uint256 gasPriceBid;\\n        /// @notice address of receiver of bridged tokens\\n        address receiverAddress;\\n        /// @notice address of Gateway which handles the token bridging for the token\\n        /// @notice gatewayAddress is unique for each token\\n        address gatewayAddress;\\n        /// @notice address of token being bridged\\n        address token;\\n        /// @notice socket offchain created hash\\n        bytes32 metadata;\\n        /// @notice data is a depositParameter derived from erc20Bridger of nativeArbitrum\\n        bytes data;\\n    }\\n\\n    /**\\n     * @notice function to bridge tokens after swap.\\n     * @notice this is different from swapAndBridge, this function is called when the swap has already happened at a different place.\\n     * @notice This method is payable because the caller is doing token transfer and briding operation\\n     * @dev for usage, refer to controller implementations\\n     *      encodedData for bridge should follow the sequence of properties in NativeArbitrumBridgeData struct\\n     * @param amount amount of tokens being bridged. this can be ERC20 or native\\n     * @param bridgeData encoded data for NativeArbitrumBridge\\n     */\\n    function bridgeAfterSwap(\\n        uint256 amount,\\n        bytes calldata bridgeData\\n    ) external payable override {\\n        NativeArbitrumBridgeData memory nativeArbitrumBridgeData = abi.decode(\\n            bridgeData,\\n            (NativeArbitrumBridgeData)\\n        );\\n        ERC20(nativeArbitrumBridgeData.token).safeApprove(\\n            nativeArbitrumBridgeData.gatewayAddress,\\n            amount\\n        );\\n\\n        L1GatewayRouter(router).outboundTransfer{\\n            value: nativeArbitrumBridgeData.value\\n        }(\\n            nativeArbitrumBridgeData.token,\\n            nativeArbitrumBridgeData.receiverAddress,\\n            amount,\\n            nativeArbitrumBridgeData.maxGas,\\n            nativeArbitrumBridgeData.gasPriceBid,\\n            nativeArbitrumBridgeData.data\\n        );\\n\\n        emit SocketBridge(\\n            amount,\\n            nativeArbitrumBridgeData.token,\\n            DESTINATION_CHAIN_ID,\\n            NativeArbitrumIdentifier,\\n            msg.sender,\\n            nativeArbitrumBridgeData.receiverAddress,\\n            nativeArbitrumBridgeData.metadata\\n        );\\n    }\\n\\n    /**\\n     * @notice function to bridge tokens after swap.\\n     * @notice this is different from bridgeAfterSwap since this function holds the logic for swapping tokens too.\\n     * @notice This method is payable because the caller is doing token transfer and briding operation\\n     * @dev for usage, refer to controller implementations\\n     *      encodedData for bridge should follow the sequence of properties in NativeArbitrumBridgeData struct\\n     * @param swapId routeId for the swapImpl\\n     * @param swapData encoded data for swap\\n     * @param nativeArbitrumBridgeData encoded data for NativeArbitrumBridge\\n     */\\n    function swapAndBridge(\\n        uint32 swapId,\\n        bytes calldata swapData,\\n        NativeArbitrumBridgeDataNoToken calldata nativeArbitrumBridgeData\\n    ) external payable {\\n        (bool success, bytes memory result) = socketRoute\\n            .getRoute(swapId)\\n            .delegatecall(swapData);\\n\\n        if (!success) {\\n            assembly {\\n                revert(add(result, 32), mload(result))\\n            }\\n        }\\n\\n        (uint256 bridgeAmount, address token) = abi.decode(\\n            result,\\n            (uint256, address)\\n        );\\n        ERC20(token).safeApprove(\\n            nativeArbitrumBridgeData.gatewayAddress,\\n            bridgeAmount\\n        );\\n\\n        L1GatewayRouter(router).outboundTransfer{\\n            value: nativeArbitrumBridgeData.value\\n        }(\\n            token,\\n            nativeArbitrumBridgeData.receiverAddress,\\n            bridgeAmount,\\n            nativeArbitrumBridgeData.maxGas,\\n            nativeArbitrumBridgeData.gasPriceBid,\\n            nativeArbitrumBridgeData.data\\n        );\\n\\n        emit SocketBridge(\\n            bridgeAmount,\\n            token,\\n            DESTINATION_CHAIN_ID,\\n            NativeArbitrumIdentifier,\\n            msg.sender,\\n            nativeArbitrumBridgeData.receiverAddress,\\n            nativeArbitrumBridgeData.metadata\\n        );\\n    }\\n\\n    /**\\n     * @notice function to handle ERC20 bridging to receipent via NativeArbitrum-Bridge\\n     * @notice This method is payable because the caller is doing token transfer and briding operation\\n     * @param amount amount being bridged\\n     * @param value value\\n     * @param maxGas maxGas is a depositParameter derived from erc20Bridger of nativeArbitrum\\n     * @param gasPriceBid gasPriceBid is a depositParameter derived from erc20Bridger of nativeArbitrum\\n     * @param receiverAddress address of receiver of bridged tokens\\n     * @param token address of token being bridged\\n     * @param gatewayAddress address of Gateway which handles the token bridging for the token, gatewayAddress is unique for each token\\n     * @param data data is a depositParameter derived from erc20Bridger of nativeArbitrum\\n     */\\n    function bridgeERC20To(\\n        uint256 amount,\\n        uint256 value,\\n        uint256 maxGas,\\n        uint256 gasPriceBid,\\n        bytes32 metadata,\\n        address receiverAddress,\\n        address token,\\n        address gatewayAddress,\\n        bytes memory data\\n    ) external payable {\\n        ERC20 tokenInstance = ERC20(token);\\n        tokenInstance.safeTransferFrom(msg.sender, socketGateway, amount);\\n        tokenInstance.safeApprove(gatewayAddress, amount);\\n\\n        L1GatewayRouter(router).outboundTransfer{value: value}(\\n            token,\\n            receiverAddress,\\n            amount,\\n            maxGas,\\n            gasPriceBid,\\n            data\\n        );\\n\\n        emit SocketBridge(\\n            amount,\\n            token,\\n            DESTINATION_CHAIN_ID,\\n            NativeArbitrumIdentifier,\\n            msg.sender,\\n            receiverAddress,\\n            metadata\\n        );\\n    }\\n}\\n\"},\"src/bridges/across/Across.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.4;\\n\\nimport \\\"./interfaces/across.sol\\\";\\nimport \\\"../BridgeImplBase.sol\\\";\\nimport {SafeTransferLib} from \\\"lib/solmate/src/utils/SafeTransferLib.sol\\\";\\nimport {ERC20} from \\\"lib/solmate/src/tokens/ERC20.sol\\\";\\nimport {ACROSS} from \\\"../../static/RouteIdentifiers.sol\\\";\\n\\n/**\\n * @title Across-Route Implementation\\n * @notice Route implementation with functions to bridge ERC20 and Native via Across-Bridge\\n * Called via SocketGateway if the routeId in the request maps to the routeId of AcrossImplementation\\n * Contains function to handle bridging as post-step i.e linked to a preceeding step for swap\\n * RequestData is different to just bride and bridging chained with swap\\n * @author Socket dot tech.\\n */\\ncontract AcrossImpl is BridgeImplBase {\\n    /// @notice SafeTransferLib - library for safe and optimised operations on ERC20 tokens\\n    using SafeTransferLib for ERC20;\\n\\n    bytes32 public immutable AcrossIdentifier = ACROSS;\\n\\n    /// @notice Function-selector for ERC20-token bridging on Across-Route\\n    /// @dev This function selector is to be used while buidling transaction-data to bridge ERC20 tokens\\n    bytes4 public immutable ACROSS_ERC20_EXTERNAL_BRIDGE_FUNCTION_SELECTOR =\\n        bytes4(\\n            keccak256(\\n                \\\"bridgeERC20To(uint256,uint256,bytes32,address,address,uint32,uint64)\\\"\\n            )\\n        );\\n\\n    /// @notice Function-selector for Native bridging on Across-Route\\n    /// @dev This function selector is to be used while buidling transaction-data to bridge Native tokens\\n    bytes4 public immutable ACROSS_NATIVE_EXTERNAL_BRIDGE_FUNCTION_SELECTOR =\\n        bytes4(\\n            keccak256(\\n                \\\"bridgeNativeTo(uint256,uint256,bytes32,address,uint32,uint64)\\\"\\n            )\\n        );\\n\\n    bytes4 public immutable ACROSS_SWAP_BRIDGE_SELECTOR =\\n        bytes4(\\n            keccak256(\\n                \\\"swapAndBridge(uint32,bytes,(uint256,address,uint32,uint64,bytes32))\\\"\\n            )\\n        );\\n\\n    /// @notice spokePool Contract instance used to deposit ERC20 and Native on to Across-Bridge\\n    /// @dev contract instance is to be initialized in the constructor using the spokePoolAddress passed as constructor argument\\n    SpokePool public immutable spokePool;\\n    address public immutable spokePoolAddress;\\n\\n    /// @notice address of WETH token to be initialised in constructor\\n    address public immutable WETH;\\n\\n    /// @notice Struct to be used in decode step from input parameter - a specific case of bridging after swap.\\n    /// @dev the data being encoded in offchain or by caller should have values set in this sequence of properties in this struct\\n    struct AcrossBridgeDataNoToken {\\n        uint256 toChainId;\\n        address receiverAddress;\\n        uint32 quoteTimestamp;\\n        uint64 relayerFeePct;\\n        bytes32 metadata;\\n    }\\n\\n    struct AcrossBridgeData {\\n        uint256 toChainId;\\n        address receiverAddress;\\n        address token;\\n        uint32 quoteTimestamp;\\n        uint64 relayerFeePct;\\n        bytes32 metadata;\\n    }\\n\\n    /// @notice socketGatewayAddress to be initialised via storage variable BridgeImplBase\\n    /// @dev ensure spokepool, weth-address are set properly for the chainId in which the contract is being deployed\\n    constructor(\\n        address _spokePool,\\n        address _wethAddress,\\n        address _socketGateway,\\n        address _socketDeployFactory\\n    ) BridgeImplBase(_socketGateway, _socketDeployFactory) {\\n        spokePool = SpokePool(_spokePool);\\n        spokePoolAddress = _spokePool;\\n        WETH = _wethAddress;\\n    }\\n\\n    /**\\n     * @notice function to bridge tokens after swap.\\n     * @notice this is different from swapAndBridge, this function is called when the swap has already happened at a different place.\\n     * @notice This method is payable because the caller is doing token transfer and briding operation\\n     * @dev for usage, refer to controller implementations\\n     *      encodedData for bridge should follow the sequence of properties in AcrossBridgeData struct\\n     * @param amount amount of tokens being bridged. this can be ERC20 or native\\n     * @param bridgeData encoded data for AcrossBridge\\n     */\\n    function bridgeAfterSwap(\\n        uint256 amount,\\n        bytes calldata bridgeData\\n    ) external payable override {\\n        AcrossBridgeData memory acrossBridgeData = abi.decode(\\n            bridgeData,\\n            (AcrossBridgeData)\\n        );\\n\\n        if (acrossBridgeData.token == NATIVE_TOKEN_ADDRESS) {\\n            spokePool.deposit{value: amount}(\\n                acrossBridgeData.receiverAddress,\\n                WETH,\\n                amount,\\n                acrossBridgeData.toChainId,\\n                acrossBridgeData.relayerFeePct,\\n                acrossBridgeData.quoteTimestamp\\n            );\\n        } else {\\n            spokePool.deposit(\\n                acrossBridgeData.receiverAddress,\\n                acrossBridgeData.token,\\n                amount,\\n                acrossBridgeData.toChainId,\\n                acrossBridgeData.relayerFeePct,\\n                acrossBridgeData.quoteTimestamp\\n            );\\n        }\\n\\n        emit SocketBridge(\\n            amount,\\n            acrossBridgeData.token,\\n            acrossBridgeData.toChainId,\\n            AcrossIdentifier,\\n            msg.sender,\\n            acrossBridgeData.receiverAddress,\\n            acrossBridgeData.metadata\\n        );\\n    }\\n\\n    /**\\n     * @notice function to bridge tokens after swap.\\n     * @notice this is different from bridgeAfterSwap since this function holds the logic for swapping tokens too.\\n     * @notice This method is payable because the caller is doing token transfer and briding operation\\n     * @dev for usage, refer to controller implementations\\n     *      encodedData for bridge should follow the sequence of properties in AcrossBridgeData struct\\n     * @param swapId routeId for the swapImpl\\n     * @param swapData encoded data for swap\\n     * @param acrossBridgeData encoded data for AcrossBridge\\n     */\\n    function swapAndBridge(\\n        uint32 swapId,\\n        bytes calldata swapData,\\n        AcrossBridgeDataNoToken calldata acrossBridgeData\\n    ) external payable {\\n        (bool success, bytes memory result) = socketRoute\\n            .getRoute(swapId)\\n            .delegatecall(swapData);\\n\\n        if (!success) {\\n            assembly {\\n                revert(add(result, 32), mload(result))\\n            }\\n        }\\n\\n        (uint256 bridgeAmount, address token) = abi.decode(\\n            result,\\n            (uint256, address)\\n        );\\n        if (token == NATIVE_TOKEN_ADDRESS) {\\n            spokePool.deposit{value: bridgeAmount}(\\n                acrossBridgeData.receiverAddress,\\n                WETH,\\n                bridgeAmount,\\n                acrossBridgeData.toChainId,\\n                acrossBridgeData.relayerFeePct,\\n                acrossBridgeData.quoteTimestamp\\n            );\\n        } else {\\n            spokePool.deposit(\\n                acrossBridgeData.receiverAddress,\\n                token,\\n                bridgeAmount,\\n                acrossBridgeData.toChainId,\\n                acrossBridgeData.relayerFeePct,\\n                acrossBridgeData.quoteTimestamp\\n            );\\n        }\\n\\n        emit SocketBridge(\\n            bridgeAmount,\\n            token,\\n            acrossBridgeData.toChainId,\\n            AcrossIdentifier,\\n            msg.sender,\\n            acrossBridgeData.receiverAddress,\\n            acrossBridgeData.metadata\\n        );\\n    }\\n\\n    /**\\n     * @notice function to handle ERC20 bridging to receipent via Across-Bridge\\n     * @notice This method is payable because the caller is doing token transfer and briding operation\\n     * @param amount amount being bridged\\n     * @param toChainId destination ChainId\\n     * @param receiverAddress address of receiver of bridged tokens\\n     * @param token address of token being bridged\\n     * @param quoteTimestamp timestamp for quote and this is to be used by Across-Bridge contract\\n     * @param relayerFeePct feePct that will be relayed by the Bridge to the relayer\\n     */\\n    function bridgeERC20To(\\n        uint256 amount,\\n        uint256 toChainId,\\n        bytes32 metadata,\\n        address receiverAddress,\\n        address token,\\n        uint32 quoteTimestamp,\\n        uint64 relayerFeePct\\n    ) external payable {\\n        ERC20 tokenInstance = ERC20(token);\\n        tokenInstance.safeTransferFrom(msg.sender, socketGateway, amount);\\n        spokePool.deposit(\\n            receiverAddress,\\n            address(token),\\n            amount,\\n            toChainId,\\n            relayerFeePct,\\n            quoteTimestamp\\n        );\\n\\n        emit SocketBridge(\\n            amount,\\n            token,\\n            toChainId,\\n            AcrossIdentifier,\\n            msg.sender,\\n            receiverAddress,\\n            metadata\\n        );\\n    }\\n\\n    /**\\n     * @notice function to handle Native bridging to receipent via Across-Bridge\\n     * @notice This method is payable because the caller is doing token transfer and briding operation\\n     * @param amount amount being bridged\\n     * @param toChainId destination ChainId\\n     * @param receiverAddress address of receiver of bridged tokens\\n     * @param quoteTimestamp timestamp for quote and this is to be used by Across-Bridge contract\\n     * @param relayerFeePct feePct that will be relayed by the Bridge to the relayer\\n     */\\n    function bridgeNativeTo(\\n        uint256 amount,\\n        uint256 toChainId,\\n        bytes32 metadata,\\n        address receiverAddress,\\n        uint32 quoteTimestamp,\\n        uint64 relayerFeePct\\n    ) external payable {\\n        spokePool.deposit{value: amount}(\\n            receiverAddress,\\n            WETH,\\n            amount,\\n            toChainId,\\n            relayerFeePct,\\n            quoteTimestamp\\n        );\\n\\n        emit SocketBridge(\\n            amount,\\n            NATIVE_TOKEN_ADDRESS,\\n            toChainId,\\n            AcrossIdentifier,\\n            msg.sender,\\n            receiverAddress,\\n            metadata\\n        );\\n    }\\n}\\n\"},\"src/bridges/cbridge/interfaces/ICelerStorageWrapper.sol\":{\"content\":\"// SPDX-License-Identifier: Apache-2.0\\npragma solidity >=0.8.0;\\n\\n/**\\n * @title Celer-StorageWrapper interface\\n * @notice Interface to handle storageMappings used while bridging ERC20 and native on CelerBridge\\n * @dev all functions ehich mutate the storage are restricted to Owner of SocketGateway\\n * @author Socket dot tech.\\n */\\ninterface ICelerStorageWrapper {\\n    /**\\n     * @notice function to store the transferId and message-sender of a bridging activity\\n     * @notice This method is payable because the caller is doing token transfer and briding operation\\n     * @dev for usage, refer to controller implementations\\n     *      encodedData for bridge should follow the sequence of properties in CelerBridgeData struct\\n     * @param transferId transferId generated during the bridging of ERC20 or native on CelerBridge\\n     * @param transferIdAddress message sender who is making the bridging on CelerBridge\\n     */\\n    function setAddressForTransferId(\\n        bytes32 transferId,\\n        address transferIdAddress\\n    ) external;\\n\\n    /**\\n     * @notice function to store the transferId and message-sender of a bridging activity\\n     * @notice This method is payable because the caller is doing token transfer and briding operation\\n     * @dev for usage, refer to controller implementations\\n     *      encodedData for bridge should follow the sequence of properties in CelerBridgeData struct\\n     * @param transferId transferId generated during the bridging of ERC20 or native on CelerBridge\\n     */\\n    function deleteTransferId(bytes32 transferId) external;\\n\\n    /**\\n     * @notice function to lookup the address mapped to the transferId\\n     * @param transferId transferId generated during the bridging of ERC20 or native on CelerBridge\\n     * @return address of account mapped to transferId\\n     */\\n    function getAddressFromTransferId(\\n        bytes32 transferId\\n    ) external view returns (address);\\n}\\n\"},\"src/bridges/optimism/interfaces/optimism.sol\":{\"content\":\"// SPDX-License-Identifier: Apache-2.0\\npragma solidity >=0.8.0;\\n\\ninterface L1StandardBridge {\\n    /**\\n     * @dev Performs the logic for deposits by storing the ETH and informing the L2 ETH Gateway of\\n     * the deposit.\\n     * @param _to Account to give the deposit to on L2.\\n     * @param _l2Gas Gas limit required to complete the deposit on L2.\\n     * @param _data Optional data to forward to L2. This data is provided\\n     *        solely as a convenience for external contracts. Aside from enforcing a maximum\\n     *        length, these contracts provide no guarantees about its content.\\n     */\\n    function depositETHTo(\\n        address _to,\\n        uint32 _l2Gas,\\n        bytes calldata _data\\n    ) external payable;\\n\\n    /**\\n     * @dev deposit an amount of ERC20 to a recipient's balance on L2.\\n     * @param _l1Token Address of the L1 ERC20 we are depositing\\n     * @param _l2Token Address of the L1 respective L2 ERC20\\n     * @param _to L2 address to credit the withdrawal to.\\n     * @param _amount Amount of the ERC20 to deposit.\\n     * @param _l2Gas Gas limit required to complete the deposit on L2.\\n     * @param _data Optional data to forward to L2. This data is provided\\n     *        solely as a convenience for external contracts. Aside from enforcing a maximum\\n     *        length, these contracts provide no guarantees about its content.\\n     */\\n    function depositERC20To(\\n        address _l1Token,\\n        address _l2Token,\\n        address _to,\\n        uint256 _amount,\\n        uint32 _l2Gas,\\n        bytes calldata _data\\n    ) external;\\n}\\n\\ninterface OldL1TokenGateway {\\n    /**\\n     * @dev Transfer SNX to L2 First, moves the SNX into the deposit escrow\\n     *\\n     * @param _to Account to give the deposit to on L2\\n     * @param _amount Amount of the ERC20 to deposit.\\n     */\\n    function depositTo(address _to, uint256 _amount) external;\\n\\n    /**\\n     * @dev Transfer SNX to L2 First, moves the SNX into the deposit escrow\\n     *\\n     * @param currencyKey currencyKey for the SynthToken\\n     * @param destination Account to give the deposit to on L2\\n     * @param amount Amount of the ERC20 to deposit.\\n     */\\n    function initiateSynthTransfer(\\n        bytes32 currencyKey,\\n        address destination,\\n        uint256 amount\\n    ) external;\\n}\\n\"},\"src/bridges/arbitrum/interfaces/arbitrum.sol\":{\"content\":\"// SPDX-License-Identifier: Apache-2.0\\n\\n/*\\n * Copyright 2021, Offchain Labs, Inc.\\n *\\n * Licensed under the Apache License, Version 2.0 (the \\\"License\\\");\\n * you may not use this file except in compliance with the License.\\n * You may obtain a copy of the License at\\n *\\n *    http://www.apache.org/licenses/LICENSE-2.0\\n *\\n * Unless required by applicable law or agreed to in writing, software\\n * distributed under the License is distributed on an \\\"AS IS\\\" BASIS,\\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\\n * See the License for the specific language governing permissions and\\n * limitations under the License.\\n */\\n\\npragma solidity >=0.8.0;\\n\\n/**\\n * @title L1gatewayRouter for native-arbitrum\\n */\\ninterface L1GatewayRouter {\\n    /**\\n     * @notice outbound function to bridge ERC20 via NativeArbitrum-Bridge\\n     * @param _token address of token being bridged via GatewayRouter\\n     * @param _to recipient of the token on arbitrum chain\\n     * @param _amount amount of ERC20 token being bridged\\n     * @param _maxGas a depositParameter for bridging the token\\n     * @param _gasPriceBid  a depositParameter for bridging the token\\n     * @param _data a depositParameter for bridging the token\\n     * @return calldata returns the output of transactioncall made on gatewayRouter\\n     */\\n    function outboundTransfer(\\n        address _token,\\n        address _to,\\n        uint256 _amount,\\n        uint256 _maxGas,\\n        uint256 _gasPriceBid,\\n        bytes calldata _data\\n    ) external payable returns (bytes calldata);\\n}\\n\"},\"src/deployFactory/DisabledSocketRoute.sol\":{\"content\":\"//SPDX-License-Identifier: MIT\\npragma solidity ^0.8.4;\\n\\nimport {SafeTransferLib} from \\\"lib/solmate/src/utils/SafeTransferLib.sol\\\";\\nimport {ERC20} from \\\"lib/solmate/src/tokens/ERC20.sol\\\";\\nimport {ISocketGateway} from \\\"../interfaces/ISocketGateway.sol\\\";\\nimport {OnlySocketGatewayOwner} from \\\"../errors/SocketErrors.sol\\\";\\n\\ncontract DisabledSocketRoute {\\n    using SafeTransferLib for ERC20;\\n\\n    /// @notice immutable variable to store the socketGateway address\\n    address public immutable socketGateway;\\n    error RouteDisabled();\\n\\n    /**\\n     * @notice Construct the base for all BridgeImplementations.\\n     * @param _socketGateway Socketgateway address, an immutable variable to set.\\n     */\\n    constructor(address _socketGateway) {\\n        socketGateway = _socketGateway;\\n    }\\n\\n    /// @notice Implementing contract needs to make use of the modifier where restricted access is to be used\\n    modifier isSocketGatewayOwner() {\\n        if (msg.sender != ISocketGateway(socketGateway).owner()) {\\n            revert OnlySocketGatewayOwner();\\n        }\\n        _;\\n    }\\n\\n    /**\\n     * @notice function to rescue the ERC20 tokens in the bridge Implementation contract\\n     * @notice this is a function restricted to Owner of SocketGateway only\\n     * @param token address of ERC20 token being rescued\\n     * @param userAddress receipient address to which ERC20 tokens will be rescued to\\n     * @param amount amount of ERC20 tokens being rescued\\n     */\\n    function rescueFunds(\\n        address token,\\n        address userAddress,\\n        uint256 amount\\n    ) external isSocketGatewayOwner {\\n        ERC20(token).safeTransfer(userAddress, amount);\\n    }\\n\\n    /**\\n     * @notice function to rescue the native-balance in the bridge Implementation contract\\n     * @notice this is a function restricted to Owner of SocketGateway only\\n     * @param userAddress receipient address to which native-balance will be rescued to\\n     * @param amount amount of native balance tokens being rescued\\n     */\\n    function rescueEther(\\n        address payable userAddress,\\n        uint256 amount\\n    ) external isSocketGatewayOwner {\\n        userAddress.transfer(amount);\\n    }\\n\\n    /**\\n     * @notice Handle route function calls gracefully.\\n     */\\n    fallback() external payable {\\n        revert RouteDisabled();\\n    }\\n\\n    /**\\n     * @notice Support receiving ether to handle refunds etc.\\n     */\\n    receive() external payable {}\\n}\\n\"},\"src/bridges/polygon/NativePolygon.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >=0.8.0;\\n\\nimport {SafeTransferLib} from \\\"lib/solmate/src/utils/SafeTransferLib.sol\\\";\\nimport {ERC20} from \\\"lib/solmate/src/tokens/ERC20.sol\\\";\\nimport \\\"./interfaces/polygon.sol\\\";\\nimport {BridgeImplBase} from \\\"../BridgeImplBase.sol\\\";\\nimport {NATIVE_POLYGON} from \\\"../../static/RouteIdentifiers.sol\\\";\\n\\n/**\\n * @title NativePolygon-Route Implementation\\n * @notice This is the L1 implementation, so this is used when transferring from ethereum to polygon via their native bridge.\\n * @author Socket dot tech.\\n */\\ncontract NativePolygonImpl is BridgeImplBase {\\n    /// @notice SafeTransferLib - library for safe and optimised operations on ERC20 tokens\\n    using SafeTransferLib for ERC20;\\n\\n    bytes32 public immutable NativePolyonIdentifier = NATIVE_POLYGON;\\n\\n    /// @notice destination-chain-Id for this router is always arbitrum\\n    uint256 public constant DESTINATION_CHAIN_ID = 137;\\n\\n    /// @notice Function-selector for ERC20-token bridging on NativePolygon-Route\\n    /// @dev This function selector is to be used while buidling transaction-data to bridge ERC20 tokens\\n    bytes4\\n        public immutable NATIVE_POLYGON_ERC20_EXTERNAL_BRIDGE_FUNCTION_SELECTOR =\\n        bytes4(keccak256(\\\"bridgeERC20To(uint256,bytes32,address,address)\\\"));\\n\\n    /// @notice Function-selector for Native bridging on NativePolygon-Route\\n    /// @dev This function selector is to be used while buidling transaction-data to bridge Native tokens\\n    bytes4\\n        public immutable NATIVE_POLYGON_NATIVE_EXTERNAL_BRIDGE_FUNCTION_SELECTOR =\\n        bytes4(keccak256(\\\"bridgeNativeTo(uint256,bytes32,address)\\\"));\\n\\n    bytes4 public immutable NATIVE_POLYGON_SWAP_BRIDGE_SELECTOR =\\n        bytes4(keccak256(\\\"swapAndBridge(uint32,address,bytes32,bytes)\\\"));\\n\\n    /// @notice root chain manager proxy on the ethereum chain\\n    /// @dev to be initialised in the constructor\\n    IRootChainManager public immutable rootChainManagerProxy;\\n\\n    /// @notice ERC20 Predicate proxy on the ethereum chain\\n    /// @dev to be initialised in the constructor\\n    address public immutable erc20PredicateProxy;\\n\\n    /**\\n     * // @notice We set all the required addresses in the constructor while deploying the contract.\\n     * // These will be constant addresses.\\n     * // @dev Please use the Proxy addresses and not the implementation addresses while setting these\\n     * // @param _rootChainManagerProxy address of the root chain manager proxy on the ethereum chain\\n     * // @param _erc20PredicateProxy address of the ERC20 Predicate proxy on the ethereum chain.\\n     * // @param _socketGateway address of the socketGateway contract that calls this contract\\n     */\\n    constructor(\\n        address _rootChainManagerProxy,\\n        address _erc20PredicateProxy,\\n        address _socketGateway,\\n        address _socketDeployFactory\\n    ) BridgeImplBase(_socketGateway, _socketDeployFactory) {\\n        rootChainManagerProxy = IRootChainManager(_rootChainManagerProxy);\\n        erc20PredicateProxy = _erc20PredicateProxy;\\n    }\\n\\n    /**\\n     * @notice function to bridge tokens after swap.\\n     * @notice this is different from swapAndBridge, this function is called when the swap has already happened at a different place.\\n     * @notice This method is payable because the caller is doing token transfer and briding operation\\n     * @dev for usage, refer to controller implementations\\n     *      encodedData for bridge should follow the sequence of properties in NativePolygon-BridgeData struct\\n     * @param amount amount of tokens being bridged. this can be ERC20 or native\\n     * @param bridgeData encoded data for NativePolygon-Bridge\\n     */\\n    function bridgeAfterSwap(\\n        uint256 amount,\\n        bytes calldata bridgeData\\n    ) external payable override {\\n        (address token, address receiverAddress, bytes32 metadata) = abi.decode(\\n            bridgeData,\\n            (address, address, bytes32)\\n        );\\n\\n        if (token == NATIVE_TOKEN_ADDRESS) {\\n            IRootChainManager(rootChainManagerProxy).depositEtherFor{\\n                value: amount\\n            }(receiverAddress);\\n        } else {\\n            ERC20(token).safeApprove(erc20PredicateProxy, amount);\\n\\n            // deposit into rootchain manager\\n            IRootChainManager(rootChainManagerProxy).depositFor(\\n                receiverAddress,\\n                token,\\n                abi.encodePacked(amount)\\n            );\\n        }\\n\\n        emit SocketBridge(\\n            amount,\\n            token,\\n            DESTINATION_CHAIN_ID,\\n            NativePolyonIdentifier,\\n            msg.sender,\\n            receiverAddress,\\n            metadata\\n        );\\n    }\\n\\n    /**\\n     * @notice function to bridge tokens after swap.\\n     * @notice this is different from bridgeAfterSwap since this function holds the logic for swapping tokens too.\\n     * @notice This method is payable because the caller is doing token transfer and briding operation\\n     * @dev for usage, refer to controller implementations\\n     *      encodedData for bridge should follow the sequence of properties in NativePolygon-BridgeData struct\\n     * @param swapId routeId for the swapImpl\\n     * @param receiverAddress address of the receiver\\n     * @param swapData encoded data for swap\\n     */\\n    function swapAndBridge(\\n        uint32 swapId,\\n        address receiverAddress,\\n        bytes32 metadata,\\n        bytes calldata swapData\\n    ) external payable {\\n        (bool success, bytes memory result) = socketRoute\\n            .getRoute(swapId)\\n            .delegatecall(swapData);\\n\\n        if (!success) {\\n            assembly {\\n                revert(add(result, 32), mload(result))\\n            }\\n        }\\n\\n        (uint256 bridgeAmount, address token) = abi.decode(\\n            result,\\n            (uint256, address)\\n        );\\n\\n        if (token == NATIVE_TOKEN_ADDRESS) {\\n            IRootChainManager(rootChainManagerProxy).depositEtherFor{\\n                value: bridgeAmount\\n            }(receiverAddress);\\n        } else {\\n            ERC20(token).safeApprove(erc20PredicateProxy, bridgeAmount);\\n\\n            // deposit into rootchain manager\\n            IRootChainManager(rootChainManagerProxy).depositFor(\\n                receiverAddress,\\n                token,\\n                abi.encodePacked(bridgeAmount)\\n            );\\n        }\\n\\n        emit SocketBridge(\\n            bridgeAmount,\\n            token,\\n            DESTINATION_CHAIN_ID,\\n            NativePolyonIdentifier,\\n            msg.sender,\\n            receiverAddress,\\n            metadata\\n        );\\n    }\\n\\n    /**\\n     * @notice function to handle ERC20 bridging to receipent via NativePolygon-Bridge\\n     * @notice This method is payable because the caller is doing token transfer and briding operation\\n     * @param amount amount of tokens being bridged\\n     * @param receiverAddress recipient address\\n     * @param token address of token being bridged\\n     */\\n    function bridgeERC20To(\\n        uint256 amount,\\n        bytes32 metadata,\\n        address receiverAddress,\\n        address token\\n    ) external payable {\\n        ERC20 tokenInstance = ERC20(token);\\n\\n        // set allowance for erc20 predicate\\n        tokenInstance.safeTransferFrom(msg.sender, socketGateway, amount);\\n        tokenInstance.safeApprove(erc20PredicateProxy, amount);\\n\\n        // deposit into rootchain manager\\n        rootChainManagerProxy.depositFor(\\n            receiverAddress,\\n            token,\\n            abi.encodePacked(amount)\\n        );\\n\\n        emit SocketBridge(\\n            amount,\\n            token,\\n            DESTINATION_CHAIN_ID,\\n            NativePolyonIdentifier,\\n            msg.sender,\\n            receiverAddress,\\n            metadata\\n        );\\n    }\\n\\n    /**\\n     * @notice function to handle Native bridging to receipent via NativePolygon-Bridge\\n     * @notice This method is payable because the caller is doing token transfer and briding operation\\n     * @param amount amount of tokens being bridged\\n     * @param receiverAddress recipient address\\n     */\\n    function bridgeNativeTo(\\n        uint256 amount,\\n        bytes32 metadata,\\n        address receiverAddress\\n    ) external payable {\\n        rootChainManagerProxy.depositEtherFor{value: amount}(receiverAddress);\\n\\n        emit SocketBridge(\\n            amount,\\n            NATIVE_TOKEN_ADDRESS,\\n            DESTINATION_CHAIN_ID,\\n            NativePolyonIdentifier,\\n            msg.sender,\\n            receiverAddress,\\n            metadata\\n        );\\n    }\\n}\\n\"},\"src/bridges/stargate/l1/Stargate.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.4;\\n\\nimport {SafeTransferLib} from \\\"lib/solmate/src/utils/SafeTransferLib.sol\\\";\\nimport {ERC20} from \\\"lib/solmate/src/tokens/ERC20.sol\\\";\\nimport \\\"../interfaces/stargate.sol\\\";\\nimport {BridgeImplBase} from \\\"../../BridgeImplBase.sol\\\";\\nimport {STARGATE} from \\\"../../../static/RouteIdentifiers.sol\\\";\\n\\n/**\\n * @title Stargate-L1-Route Implementation\\n * @notice Route implementation with functions to bridge ERC20 and Native via Stargate-L1-Bridge\\n * Called via SocketGateway if the routeId in the request maps to the routeId of Stargate-L1-Implementation\\n * Contains function to handle bridging as post-step i.e linked to a preceeding step for swap\\n * RequestData is different to just bride and bridging chained with swap\\n * @author Socket dot tech.\\n */\\ncontract StargateImplL1 is BridgeImplBase {\\n    /// @notice SafeTransferLib - library for safe and optimised operations on ERC20 tokens\\n    using SafeTransferLib for ERC20;\\n\\n    bytes32 public immutable StargateIdentifier = STARGATE;\\n\\n    /// @notice Function-selector for ERC20-token bridging on Stargate-L1-Route\\n    /// @dev This function selector is to be used while buidling transaction-data to bridge ERC20 tokens\\n    bytes4\\n        public immutable STARGATE_L1_ERC20_EXTERNAL_BRIDGE_FUNCTION_SELECTOR =\\n        bytes4(\\n            keccak256(\\n                \\\"bridgeERC20To(address,address,address,uint256,uint256,(uint256,uint256,uint256,uint256,bytes32,bytes,uint16))\\\"\\n            )\\n        );\\n\\n    /// @notice Function-selector for Native bridging on Stargate-L1-Route\\n    /// @dev This function selector is to be used while buidling transaction-data to bridge Native tokens\\n    bytes4\\n        public immutable STARGATE_L1_NATIVE_EXTERNAL_BRIDGE_FUNCTION_SELECTOR =\\n        bytes4(\\n            keccak256(\\n                \\\"bridgeNativeTo(address,address,uint16,uint256,uint256,uint256,bytes32)\\\"\\n            )\\n        );\\n\\n    bytes4 public immutable STARGATE_L1_SWAP_BRIDGE_SELECTOR =\\n        bytes4(\\n            keccak256(\\n                \\\"swapAndBridge(uint32,bytes,(address,address,uint16,uint256,uint256,uint256,uint256,uint256,uint256,bytes32,bytes))\\\"\\n            )\\n        );\\n\\n    /// @notice Stargate Router to bridge ERC20 tokens\\n    IBridgeStargate public immutable router;\\n\\n    /// @notice Stargate Router to bridge native tokens\\n    IBridgeStargate public immutable routerETH;\\n\\n    /// @notice socketGatewayAddress to be initialised via storage variable BridgeImplBase\\n    /// @dev ensure router, routerEth are set properly for the chainId in which the contract is being deployed\\n    constructor(\\n        address _router,\\n        address _routerEth,\\n        address _socketGateway,\\n        address _socketDeployFactory\\n    ) BridgeImplBase(_socketGateway, _socketDeployFactory) {\\n        router = IBridgeStargate(_router);\\n        routerETH = IBridgeStargate(_routerEth);\\n    }\\n\\n    struct StargateBridgeExtraData {\\n        uint256 srcPoolId;\\n        uint256 dstPoolId;\\n        uint256 destinationGasLimit;\\n        uint256 minReceivedAmt;\\n        bytes32 metadata;\\n        bytes destinationPayload;\\n        uint16 stargateDstChainId; // stargate defines chain id in its way\\n    }\\n\\n    /// @notice Struct to be used in decode step from input parameter - a specific case of bridging after swap.\\n    /// @dev the data being encoded in offchain or by caller should have values set in this sequence of properties in this struct\\n    struct StargateBridgeDataNoToken {\\n        address receiverAddress;\\n        address senderAddress;\\n        uint16 stargateDstChainId; // stargate defines chain id in its way\\n        uint256 value;\\n        // a unique identifier that is uses to dedup transfers\\n        // this value is the a timestamp sent from frontend, but in theory can be any unique number\\n        uint256 srcPoolId;\\n        uint256 dstPoolId;\\n        uint256 minReceivedAmt; // defines the slippage, the min qty you would accept on the destination\\n        uint256 optionalValue;\\n        uint256 destinationGasLimit;\\n        bytes32 metadata;\\n        bytes destinationPayload;\\n    }\\n\\n    struct StargateBridgeData {\\n        address token;\\n        address receiverAddress;\\n        address senderAddress;\\n        uint16 stargateDstChainId; // stargate defines chain id in its way\\n        uint256 value;\\n        // a unique identifier that is uses to dedup transfers\\n        // this value is the a timestamp sent from frontend, but in theory can be any unique number\\n        uint256 srcPoolId;\\n        uint256 dstPoolId;\\n        uint256 minReceivedAmt; // defines the slippage, the min qty you would accept on the destination\\n        uint256 optionalValue;\\n        uint256 destinationGasLimit;\\n        bytes32 metadata;\\n        bytes destinationPayload;\\n    }\\n\\n    /**\\n     * @notice function to bridge tokens after swap.\\n     * @notice this is different from swapAndBridge, this function is called when the swap has already happened at a different place.\\n     * @notice This method is payable because the caller is doing token transfer and briding operation\\n     * @dev for usage, refer to controller implementations\\n     *      encodedData for bridge should follow the sequence of properties in Stargate-BridgeData struct\\n     * @param amount amount of tokens being bridged. this can be ERC20 or native\\n     * @param bridgeData encoded data for Stargate-L1-Bridge\\n     */\\n    function bridgeAfterSwap(\\n        uint256 amount,\\n        bytes calldata bridgeData\\n    ) external payable override {\\n        StargateBridgeData memory stargateBridgeData = abi.decode(\\n            bridgeData,\\n            (StargateBridgeData)\\n        );\\n\\n        if (stargateBridgeData.token == NATIVE_TOKEN_ADDRESS) {\\n            // perform bridging\\n            routerETH.swapETH{value: amount + stargateBridgeData.optionalValue}(\\n                stargateBridgeData.stargateDstChainId,\\n                payable(stargateBridgeData.senderAddress),\\n                abi.encodePacked(stargateBridgeData.receiverAddress),\\n                amount,\\n                stargateBridgeData.minReceivedAmt\\n            );\\n        } else {\\n            ERC20(stargateBridgeData.token).safeApprove(\\n                address(router),\\n                amount\\n            );\\n            {\\n                router.swap{value: stargateBridgeData.value}(\\n                    stargateBridgeData.stargateDstChainId,\\n                    stargateBridgeData.srcPoolId,\\n                    stargateBridgeData.dstPoolId,\\n                    payable(stargateBridgeData.senderAddress), // default to refund to main contract\\n                    amount,\\n                    stargateBridgeData.minReceivedAmt,\\n                    IBridgeStargate.lzTxObj(\\n                        stargateBridgeData.destinationGasLimit,\\n                        0, // zero amount since this is a ERC20 bridging\\n                        \\\"0x\\\" //empty data since this is for only ERC20\\n                    ),\\n                    abi.encodePacked(stargateBridgeData.receiverAddress),\\n                    stargateBridgeData.destinationPayload\\n                );\\n            }\\n        }\\n\\n        emit SocketBridge(\\n            amount,\\n            stargateBridgeData.token,\\n            stargateBridgeData.stargateDstChainId,\\n            StargateIdentifier,\\n            msg.sender,\\n            stargateBridgeData.receiverAddress,\\n            stargateBridgeData.metadata\\n        );\\n    }\\n\\n    /**\\n     * @notice function to bridge tokens after swap.\\n     * @notice this is different from bridgeAfterSwap since this function holds the logic for swapping tokens too.\\n     * @notice This method is payable because the caller is doing token transfer and briding operation\\n     * @dev for usage, refer to controller implementations\\n     *      encodedData for bridge should follow the sequence of properties in Stargate-BridgeData struct\\n     * @param swapId routeId for the swapImpl\\n     * @param swapData encoded data for swap\\n     * @param stargateBridgeData encoded data for StargateBridgeData\\n     */\\n    function swapAndBridge(\\n        uint32 swapId,\\n        bytes calldata swapData,\\n        StargateBridgeDataNoToken calldata stargateBridgeData\\n    ) external payable {\\n        (bool success, bytes memory result) = socketRoute\\n            .getRoute(swapId)\\n            .delegatecall(swapData);\\n\\n        if (!success) {\\n            assembly {\\n                revert(add(result, 32), mload(result))\\n            }\\n        }\\n\\n        (uint256 bridgeAmount, address token) = abi.decode(\\n            result,\\n            (uint256, address)\\n        );\\n\\n        if (token == NATIVE_TOKEN_ADDRESS) {\\n            // perform bridging\\n            routerETH.swapETH{\\n                value: bridgeAmount + stargateBridgeData.optionalValue\\n            }(\\n                stargateBridgeData.stargateDstChainId,\\n                payable(stargateBridgeData.senderAddress),\\n                abi.encodePacked(stargateBridgeData.receiverAddress),\\n                bridgeAmount,\\n                stargateBridgeData.minReceivedAmt\\n            );\\n        } else {\\n            ERC20(token).safeApprove(address(router), bridgeAmount);\\n            {\\n                router.swap{value: stargateBridgeData.value}(\\n                    stargateBridgeData.stargateDstChainId,\\n                    stargateBridgeData.srcPoolId,\\n                    stargateBridgeData.dstPoolId,\\n                    payable(stargateBridgeData.senderAddress), // default to refund to main contract\\n                    bridgeAmount,\\n                    stargateBridgeData.minReceivedAmt,\\n                    IBridgeStargate.lzTxObj(\\n                        stargateBridgeData.destinationGasLimit,\\n                        0, // zero amount since this is a ERC20 bridging\\n                        \\\"0x\\\" //empty data since this is for only ERC20\\n                    ),\\n                    abi.encodePacked(stargateBridgeData.receiverAddress),\\n                    stargateBridgeData.destinationPayload\\n                );\\n            }\\n        }\\n\\n        emit SocketBridge(\\n            bridgeAmount,\\n            token,\\n            stargateBridgeData.stargateDstChainId,\\n            StargateIdentifier,\\n            msg.sender,\\n            stargateBridgeData.receiverAddress,\\n            stargateBridgeData.metadata\\n        );\\n    }\\n\\n    /**\\n     * @notice function to handle ERC20 bridging to receipent via Stargate-L1-Bridge\\n     * @notice This method is payable because the caller is doing token transfer and briding operation\\n     * @param token address of token being bridged\\n     * @param senderAddress address of sender\\n     * @param receiverAddress address of recipient\\n     * @param amount amount of token being bridge\\n     * @param value value\\n     * @param stargateBridgeExtraData stargate bridge extradata\\n     */\\n    function bridgeERC20To(\\n        address token,\\n        address senderAddress,\\n        address receiverAddress,\\n        uint256 amount,\\n        uint256 value,\\n        StargateBridgeExtraData calldata stargateBridgeExtraData\\n    ) external payable {\\n        ERC20 tokenInstance = ERC20(token);\\n        tokenInstance.safeTransferFrom(msg.sender, socketGateway, amount);\\n        tokenInstance.safeApprove(address(router), amount);\\n        {\\n            router.swap{value: value}(\\n                stargateBridgeExtraData.stargateDstChainId,\\n                stargateBridgeExtraData.srcPoolId,\\n                stargateBridgeExtraData.dstPoolId,\\n                payable(senderAddress), // default to refund to main contract\\n                amount,\\n                stargateBridgeExtraData.minReceivedAmt,\\n                IBridgeStargate.lzTxObj(\\n                    stargateBridgeExtraData.destinationGasLimit,\\n                    0, // zero amount since this is a ERC20 bridging\\n                    \\\"0x\\\" //empty data since this is for only ERC20\\n                ),\\n                abi.encodePacked(receiverAddress),\\n                stargateBridgeExtraData.destinationPayload\\n            );\\n        }\\n\\n        emit SocketBridge(\\n            amount,\\n            token,\\n            stargateBridgeExtraData.stargateDstChainId,\\n            StargateIdentifier,\\n            msg.sender,\\n            receiverAddress,\\n            stargateBridgeExtraData.metadata\\n        );\\n    }\\n\\n    /**\\n     * @notice function to handle Native bridging to receipent via Stargate-L1-Bridge\\n     * @notice This method is payable because the caller is doing token transfer and briding operation\\n     * @param receiverAddress address of receipient\\n     * @param senderAddress address of sender\\n     * @param stargateDstChainId stargate defines chain id in its way\\n     * @param amount amount of token being bridge\\n     * @param minReceivedAmt defines the slippage, the min qty you would accept on the destination\\n     * @param optionalValue optionalValue Native amount\\n     */\\n    function bridgeNativeTo(\\n        address receiverAddress,\\n        address senderAddress,\\n        uint16 stargateDstChainId,\\n        uint256 amount,\\n        uint256 minReceivedAmt,\\n        uint256 optionalValue,\\n        bytes32 metadata\\n    ) external payable {\\n        // perform bridging\\n        routerETH.swapETH{value: amount + optionalValue}(\\n            stargateDstChainId,\\n            payable(senderAddress),\\n            abi.encodePacked(receiverAddress),\\n            amount,\\n            minReceivedAmt\\n        );\\n\\n        emit SocketBridge(\\n            amount,\\n            NATIVE_TOKEN_ADDRESS,\\n            stargateDstChainId,\\n            StargateIdentifier,\\n            msg.sender,\\n            receiverAddress,\\n            metadata\\n        );\\n    }\\n}\\n\"},\"src/bridges/hop/l2/HopImplL2.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.4;\\n\\nimport \\\"../interfaces/amm.sol\\\";\\nimport {SafeTransferLib} from \\\"lib/solmate/src/utils/SafeTransferLib.sol\\\";\\nimport {ERC20} from \\\"lib/solmate/src/tokens/ERC20.sol\\\";\\nimport {BridgeImplBase} from \\\"../../BridgeImplBase.sol\\\";\\nimport {HOP} from \\\"../../../static/RouteIdentifiers.sol\\\";\\n\\n/**\\n * @title Hop-L2 Route Implementation\\n * @notice This is the L2 implementation, so this is used when transferring from l2 to supported l2s\\n * Called via SocketGateway if the routeId in the request maps to the routeId of HopL2-Implementation\\n * Contains function to handle bridging as post-step i.e linked to a preceeding step for swap\\n * RequestData is different to just bride and bridging chained with swap\\n * @author Socket dot tech.\\n */\\ncontract HopImplL2 is BridgeImplBase {\\n    /// @notice SafeTransferLib - library for safe and optimised operations on ERC20 tokens\\n    using SafeTransferLib for ERC20;\\n\\n    bytes32 public immutable HopIdentifier = HOP;\\n\\n    /// @notice Function-selector for ERC20-token bridging on Hop-L2-Route\\n    /// @dev This function selector is to be used while buidling transaction-data to bridge ERC20 tokens\\n    bytes4 public immutable HOP_L2_ERC20_EXTERNAL_BRIDGE_FUNCTION_SELECTOR =\\n        bytes4(\\n            keccak256(\\n                \\\"bridgeERC20To(address,address,address,uint256,uint256,(uint256,uint256,uint256,uint256,uint256,bytes32))\\\"\\n            )\\n        );\\n\\n    /// @notice Function-selector for Native bridging on Hop-L2-Route\\n    /// @dev This function selector is to be used while building transaction-data to bridge Native tokens\\n    bytes4 public immutable HOP_L2_NATIVE_EXTERNAL_BRIDGE_FUNCTION_SELECTOR =\\n        bytes4(\\n            keccak256(\\n                \\\"bridgeNativeTo(address,address,uint256,uint256,uint256,uint256,uint256,uint256,uint256,bytes32)\\\"\\n            )\\n        );\\n\\n    bytes4 public immutable HOP_L2_SWAP_BRIDGE_SELECTOR =\\n        bytes4(\\n            keccak256(\\n                \\\"swapAndBridge(uint32,bytes,(address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes32))\\\"\\n            )\\n        );\\n\\n    /// @notice socketGatewayAddress to be initialised via storage variable BridgeImplBase\\n    constructor(\\n        address _socketGateway,\\n        address _socketDeployFactory\\n    ) BridgeImplBase(_socketGateway, _socketDeployFactory) {}\\n\\n    /// @notice Struct to be used as a input parameter for Bridging tokens via Hop-L2-route\\n    /// @dev while building transactionData,values should be set in this sequence of properties in this struct\\n    struct HopBridgeRequestData {\\n        // fees passed to relayer\\n        uint256 bonderFee;\\n        // The minimum amount received after attempting to swap in the destination AMM market. 0 if no swap is intended.\\n        uint256 amountOutMin;\\n        // The deadline for swapping in the destination AMM market. 0 if no swap is intended.\\n        uint256 deadline;\\n        // Minimum amount expected to be received or bridged to destination\\n        uint256 amountOutMinDestination;\\n        // deadline for bridging to destination\\n        uint256 deadlineDestination;\\n        // socket offchain created hash\\n        bytes32 metadata;\\n    }\\n\\n    /// @notice Struct to be used in decode step from input parameter - a specific case of bridging after swap.\\n    /// @dev the data being encoded in offchain or by caller should have values set in this sequence of properties in this struct\\n    struct HopBridgeDataNoToken {\\n        // The address receiving funds at the destination\\n        address receiverAddress;\\n        // AMM address of Hop on L2\\n        address hopAMM;\\n        // The chainId of the destination chain\\n        uint256 toChainId;\\n        // fees passed to relayer\\n        uint256 bonderFee;\\n        // The minimum amount received after attempting to swap in the destination AMM market. 0 if no swap is intended.\\n        uint256 amountOutMin;\\n        // The deadline for swapping in the destination AMM market. 0 if no swap is intended.\\n        uint256 deadline;\\n        // Minimum amount expected to be received or bridged to destination\\n        uint256 amountOutMinDestination;\\n        // deadline for bridging to destination\\n        uint256 deadlineDestination;\\n        // socket offchain created hash\\n        bytes32 metadata;\\n    }\\n\\n    struct HopBridgeData {\\n        /// @notice address of token being bridged\\n        address token;\\n        // The address receiving funds at the destination\\n        address receiverAddress;\\n        // AMM address of Hop on L2\\n        address hopAMM;\\n        // The chainId of the destination chain\\n        uint256 toChainId;\\n        // fees passed to relayer\\n        uint256 bonderFee;\\n        // The minimum amount received after attempting to swap in the destination AMM market. 0 if no swap is intended.\\n        uint256 amountOutMin;\\n        // The deadline for swapping in the destination AMM market. 0 if no swap is intended.\\n        uint256 deadline;\\n        // Minimum amount expected to be received or bridged to destination\\n        uint256 amountOutMinDestination;\\n        // deadline for bridging to destination\\n        uint256 deadlineDestination;\\n        // socket offchain created hash\\n        bytes32 metadata;\\n    }\\n\\n    /**\\n     * @notice function to bridge tokens after swap.\\n     * @notice this is different from swapAndBridge, this function is called when the swap has already happened at a different place.\\n     * @notice This method is payable because the caller is doing token transfer and briding operation\\n     * @dev for usage, refer to controller implementations\\n     *      encodedData for bridge should follow the sequence of properties in HopBridgeData struct\\n     * @param amount amount of tokens being bridged. this can be ERC20 or native\\n     * @param bridgeData encoded data for Hop-L2-Bridge\\n     */\\n    function bridgeAfterSwap(\\n        uint256 amount,\\n        bytes calldata bridgeData\\n    ) external payable override {\\n        HopBridgeData memory hopData = abi.decode(bridgeData, (HopBridgeData));\\n\\n        if (hopData.token == NATIVE_TOKEN_ADDRESS) {\\n            HopAMM(hopData.hopAMM).swapAndSend{value: amount}(\\n                hopData.toChainId,\\n                hopData.receiverAddress,\\n                amount,\\n                hopData.bonderFee,\\n                hopData.amountOutMin,\\n                hopData.deadline,\\n                hopData.amountOutMinDestination,\\n                hopData.deadlineDestination\\n            );\\n        } else {\\n            // perform bridging\\n            HopAMM(hopData.hopAMM).swapAndSend(\\n                hopData.toChainId,\\n                hopData.receiverAddress,\\n                amount,\\n                hopData.bonderFee,\\n                hopData.amountOutMin,\\n                hopData.deadline,\\n                hopData.amountOutMinDestination,\\n                hopData.deadlineDestination\\n            );\\n        }\\n\\n        emit SocketBridge(\\n            amount,\\n            hopData.token,\\n            hopData.toChainId,\\n            HopIdentifier,\\n            msg.sender,\\n            hopData.receiverAddress,\\n            hopData.metadata\\n        );\\n    }\\n\\n    /**\\n     * @notice function to bridge tokens after swap.\\n     * @notice this is different from bridgeAfterSwap since this function holds the logic for swapping tokens too.\\n     * @notice This method is payable because the caller is doing token transfer and briding operation\\n     * @dev for usage, refer to controller implementations\\n     *      encodedData for bridge should follow the sequence of properties in HopBridgeData struct\\n     * @param swapId routeId for the swapImpl\\n     * @param swapData encoded data for swap\\n     * @param hopData encoded data for HopData\\n     */\\n    function swapAndBridge(\\n        uint32 swapId,\\n        bytes calldata swapData,\\n        HopBridgeDataNoToken calldata hopData\\n    ) external payable {\\n        (bool success, bytes memory result) = socketRoute\\n            .getRoute(swapId)\\n            .delegatecall(swapData);\\n\\n        if (!success) {\\n            assembly {\\n                revert(add(result, 32), mload(result))\\n            }\\n        }\\n\\n        (uint256 bridgeAmount, address token) = abi.decode(\\n            result,\\n            (uint256, address)\\n        );\\n\\n        if (token == NATIVE_TOKEN_ADDRESS) {\\n            HopAMM(hopData.hopAMM).swapAndSend{value: bridgeAmount}(\\n                hopData.toChainId,\\n                hopData.receiverAddress,\\n                bridgeAmount,\\n                hopData.bonderFee,\\n                hopData.amountOutMin,\\n                hopData.deadline,\\n                hopData.amountOutMinDestination,\\n                hopData.deadlineDestination\\n            );\\n        } else {\\n            // perform bridging\\n            HopAMM(hopData.hopAMM).swapAndSend(\\n                hopData.toChainId,\\n                hopData.receiverAddress,\\n                bridgeAmount,\\n                hopData.bonderFee,\\n                hopData.amountOutMin,\\n                hopData.deadline,\\n                hopData.amountOutMinDestination,\\n                hopData.deadlineDestination\\n            );\\n        }\\n\\n        emit SocketBridge(\\n            bridgeAmount,\\n            token,\\n            hopData.toChainId,\\n            HopIdentifier,\\n            msg.sender,\\n            hopData.receiverAddress,\\n            hopData.metadata\\n        );\\n    }\\n\\n    /**\\n     * @notice function to handle ERC20 bridging to receipent via Hop-L2-Bridge\\n     * @notice This method is payable because the caller is doing token transfer and briding operation\\n     * @param receiverAddress The address receiving funds at the destination\\n     * @param token token being bridged\\n     * @param hopAMM AMM address of Hop on L2\\n     * @param amount The amount being bridged\\n     * @param toChainId The chainId of the destination chain\\n     * @param hopBridgeRequestData extraData for Bridging across Hop-L2\\n     */\\n    function bridgeERC20To(\\n        address receiverAddress,\\n        address token,\\n        address hopAMM,\\n        uint256 amount,\\n        uint256 toChainId,\\n        HopBridgeRequestData calldata hopBridgeRequestData\\n    ) external payable {\\n        ERC20 tokenInstance = ERC20(token);\\n        tokenInstance.safeTransferFrom(msg.sender, socketGateway, amount);\\n\\n        HopAMM(hopAMM).swapAndSend(\\n            toChainId,\\n            receiverAddress,\\n            amount,\\n            hopBridgeRequestData.bonderFee,\\n            hopBridgeRequestData.amountOutMin,\\n            hopBridgeRequestData.deadline,\\n            hopBridgeRequestData.amountOutMinDestination,\\n            hopBridgeRequestData.deadlineDestination\\n        );\\n\\n        emit SocketBridge(\\n            amount,\\n            token,\\n            toChainId,\\n            HopIdentifier,\\n            msg.sender,\\n            receiverAddress,\\n            hopBridgeRequestData.metadata\\n        );\\n    }\\n\\n    /**\\n     * @notice function to handle Native bridging to receipent via Hop-L2-Bridge\\n     * @notice This method is payable because the caller is doing token transfer and briding operation\\n     * @param receiverAddress The address receiving funds at the destination\\n     * @param hopAMM AMM address of Hop on L2\\n     * @param amount The amount being bridged\\n     * @param toChainId The chainId of the destination chain\\n     * @param bonderFee fees passed to relayer\\n     * @param amountOutMin The minimum amount received after attempting to swap in the destination AMM market. 0 if no swap is intended.\\n     * @param deadline The deadline for swapping in the destination AMM market. 0 if no swap is intended.\\n     * @param amountOutMinDestination Minimum amount expected to be received or bridged to destination\\n     * @param deadlineDestination deadline for bridging to destination\\n     */\\n    function bridgeNativeTo(\\n        address receiverAddress,\\n        address hopAMM,\\n        uint256 amount,\\n        uint256 toChainId,\\n        uint256 bonderFee,\\n        uint256 amountOutMin,\\n        uint256 deadline,\\n        uint256 amountOutMinDestination,\\n        uint256 deadlineDestination,\\n        bytes32 metadata\\n    ) external payable {\\n        // token address might not be indication thats why passed through extraData\\n        // perform bridging\\n        HopAMM(hopAMM).swapAndSend{value: amount}(\\n            toChainId,\\n            receiverAddress,\\n            amount,\\n            bonderFee,\\n            amountOutMin,\\n            deadline,\\n            amountOutMinDestination,\\n            deadlineDestination\\n        );\\n\\n        emit SocketBridge(\\n            amount,\\n            NATIVE_TOKEN_ADDRESS,\\n            toChainId,\\n            HopIdentifier,\\n            msg.sender,\\n            receiverAddress,\\n            metadata\\n        );\\n    }\\n}\\n\"},\"src/bridges/anyswap-router-v4/l2/Anyswap.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.4;\\n\\nimport {SafeTransferLib} from \\\"lib/solmate/src/utils/SafeTransferLib.sol\\\";\\nimport {ERC20} from \\\"lib/solmate/src/tokens/ERC20.sol\\\";\\nimport {BridgeImplBase} from \\\"../../BridgeImplBase.sol\\\";\\nimport {ANYSWAP} from \\\"../../../static/RouteIdentifiers.sol\\\";\\n\\n/**\\n * @title Anyswap-V4-Route L1 Implementation\\n * @notice Route implementation with functions to bridge ERC20 via Anyswap-Bridge\\n * Called via SocketGateway if the routeId in the request maps to the routeId of AnyswapImplementation\\n * This is the L2 implementation, so this is used when transferring from l2.\\n * Contains function to handle bridging as post-step i.e linked to a preceeding step for swap\\n * RequestData is different to just bride and bridging chained with swap\\n * @author Socket dot tech.\\n */\\ninterface AnyswapV4Router {\\n    function anySwapOutUnderlying(\\n        address token,\\n        address to,\\n        uint256 amount,\\n        uint256 toChainID\\n    ) external;\\n}\\n\\ncontract AnyswapL2Impl is BridgeImplBase {\\n    /// @notice SafeTransferLib - library for safe and optimised operations on ERC20 tokens\\n    using SafeTransferLib for ERC20;\\n\\n    bytes32 public immutable AnyswapIdentifier = ANYSWAP;\\n\\n    /// @notice Function-selector for ERC20-token bridging on Anyswap-Route\\n    /// @dev This function selector is to be used while buidling transaction-data to bridge ERC20 tokens\\n    bytes4 public immutable ANYSWAP_L2_ERC20_EXTERNAL_BRIDGE_FUNCTION_SELECTOR =\\n        bytes4(\\n            keccak256(\\n                \\\"bridgeERC20To(uint256,uint256,bytes32,address,address,address)\\\"\\n            )\\n        );\\n\\n    bytes4 public immutable ANYSWAP_SWAP_BRIDGE_SELECTOR =\\n        bytes4(\\n            keccak256(\\n                \\\"swapAndBridge(uint32,bytes,(uint256,address,address,bytes32))\\\"\\n            )\\n        );\\n\\n    // polygon router multichain router v4\\n    AnyswapV4Router public immutable router;\\n\\n    /**\\n     * @notice Constructor sets the router address and socketGateway address.\\n     * @dev anyswap v4 router is immutable. so no setter function required.\\n     */\\n    constructor(\\n        address _router,\\n        address _socketGateway,\\n        address _socketDeployFactory\\n    ) BridgeImplBase(_socketGateway, _socketDeployFactory) {\\n        router = AnyswapV4Router(_router);\\n    }\\n\\n    /// @notice Struct to be used in decode step from input parameter - a specific case of bridging after swap.\\n    /// @dev the data being encoded in offchain or by caller should have values set in this sequence of properties in this struct\\n    struct AnyswapBridgeDataNoToken {\\n        /// @notice destination ChainId\\n        uint256 toChainId;\\n        /// @notice address of receiver of bridged tokens\\n        address receiverAddress;\\n        /// @notice address of wrapperToken, WrappedVersion of the token being bridged\\n        address wrapperTokenAddress;\\n        /// @notice socket offchain created hash\\n        bytes32 metadata;\\n    }\\n\\n    /// @notice Struct to be used in decode step from input parameter - a specific case of bridging after swap.\\n    /// @dev the data being encoded in offchain or by caller should have values set in this sequence of properties in this struct\\n    struct AnyswapBridgeData {\\n        /// @notice destination ChainId\\n        uint256 toChainId;\\n        /// @notice address of receiver of bridged tokens\\n        address receiverAddress;\\n        /// @notice address of wrapperToken, WrappedVersion of the token being bridged\\n        address wrapperTokenAddress;\\n        /// @notice address of token being bridged\\n        address token;\\n        /// @notice socket offchain created hash\\n        bytes32 metadata;\\n    }\\n\\n    /**\\n     * @notice function to bridge tokens after swap.\\n     * @notice this is different from swapAndBridge, this function is called when the swap has already happened at a different place.\\n     * @notice This method is payable because the caller is doing token transfer and briding operation\\n     * @dev for usage, refer to controller implementations\\n     *      encodedData for bridge should follow the sequence of properties in AnyswapBridgeData struct\\n     * @param amount amount of tokens being bridged. this can be ERC20 or native\\n     * @param bridgeData encoded data for AnyswapBridge\\n     */\\n    function bridgeAfterSwap(\\n        uint256 amount,\\n        bytes calldata bridgeData\\n    ) external payable override {\\n        AnyswapBridgeData memory anyswapBridgeData = abi.decode(\\n            bridgeData,\\n            (AnyswapBridgeData)\\n        );\\n        ERC20(anyswapBridgeData.token).safeApprove(address(router), amount);\\n        router.anySwapOutUnderlying(\\n            anyswapBridgeData.wrapperTokenAddress,\\n            anyswapBridgeData.receiverAddress,\\n            amount,\\n            anyswapBridgeData.toChainId\\n        );\\n\\n        emit SocketBridge(\\n            amount,\\n            anyswapBridgeData.token,\\n            anyswapBridgeData.toChainId,\\n            AnyswapIdentifier,\\n            msg.sender,\\n            anyswapBridgeData.receiverAddress,\\n            anyswapBridgeData.metadata\\n        );\\n    }\\n\\n    /**\\n     * @notice function to bridge tokens after swap.\\n     * @notice this is different from bridgeAfterSwap since this function holds the logic for swapping tokens too.\\n     * @notice This method is payable because the caller is doing token transfer and briding operation\\n     * @dev for usage, refer to controller implementations\\n     *      encodedData for bridge should follow the sequence of properties in AnyswapBridgeData struct\\n     * @param swapId routeId for the swapImpl\\n     * @param swapData encoded data for swap\\n     * @param anyswapBridgeData encoded data for AnyswapBridge\\n     */\\n    function swapAndBridge(\\n        uint32 swapId,\\n        bytes calldata swapData,\\n        AnyswapBridgeDataNoToken calldata anyswapBridgeData\\n    ) external payable {\\n        (bool success, bytes memory result) = socketRoute\\n            .getRoute(swapId)\\n            .delegatecall(swapData);\\n\\n        if (!success) {\\n            assembly {\\n                revert(add(result, 32), mload(result))\\n            }\\n        }\\n\\n        (uint256 bridgeAmount, address token) = abi.decode(\\n            result,\\n            (uint256, address)\\n        );\\n\\n        ERC20(token).safeApprove(address(router), bridgeAmount);\\n        router.anySwapOutUnderlying(\\n            anyswapBridgeData.wrapperTokenAddress,\\n            anyswapBridgeData.receiverAddress,\\n            bridgeAmount,\\n            anyswapBridgeData.toChainId\\n        );\\n\\n        emit SocketBridge(\\n            bridgeAmount,\\n            token,\\n            anyswapBridgeData.toChainId,\\n            AnyswapIdentifier,\\n            msg.sender,\\n            anyswapBridgeData.receiverAddress,\\n            anyswapBridgeData.metadata\\n        );\\n    }\\n\\n    /**\\n     * @notice function to handle ERC20 bridging to receipent via Anyswap-Bridge\\n     * @notice This method is payable because the caller is doing token transfer and briding operation\\n     * @param amount amount being bridged\\n     * @param toChainId destination ChainId\\n     * @param receiverAddress address of receiver of bridged tokens\\n     * @param token address of token being bridged\\n     * @param wrapperTokenAddress address of wrapperToken, WrappedVersion of the token being bridged\\n     */\\n    function bridgeERC20To(\\n        uint256 amount,\\n        uint256 toChainId,\\n        bytes32 metadata,\\n        address receiverAddress,\\n        address token,\\n        address wrapperTokenAddress\\n    ) external payable {\\n        ERC20 tokenInstance = ERC20(token);\\n        tokenInstance.safeTransferFrom(msg.sender, socketGateway, amount);\\n        tokenInstance.safeApprove(address(router), amount);\\n        router.anySwapOutUnderlying(\\n            wrapperTokenAddress,\\n            receiverAddress,\\n            amount,\\n            toChainId\\n        );\\n\\n        emit SocketBridge(\\n            amount,\\n            token,\\n            toChainId,\\n            AnyswapIdentifier,\\n            msg.sender,\\n            receiverAddress,\\n            metadata\\n        );\\n    }\\n}\\n\"},\"src/bridges/hyphen/Hyphen.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.4;\\n\\nimport \\\"./interfaces/hyphen.sol\\\";\\nimport \\\"../BridgeImplBase.sol\\\";\\nimport {SafeTransferLib} from \\\"lib/solmate/src/utils/SafeTransferLib.sol\\\";\\nimport {ERC20} from \\\"lib/solmate/src/tokens/ERC20.sol\\\";\\nimport {HYPHEN} from \\\"../../static/RouteIdentifiers.sol\\\";\\n\\n/**\\n * @title Hyphen-Route Implementation\\n * @notice Route implementation with functions to bridge ERC20 and Native via Hyphen-Bridge\\n * Called via SocketGateway if the routeId in the request maps to the routeId of HyphenImplementation\\n * Contains function to handle bridging as post-step i.e linked to a preceeding step for swap\\n * RequestData is different to just bride and bridging chained with swap\\n * @author Socket dot tech.\\n */\\ncontract HyphenImpl is BridgeImplBase {\\n    /// @notice SafeTransferLib - library for safe and optimised operations on ERC20 tokens\\n    using SafeTransferLib for ERC20;\\n\\n    bytes32 public immutable HyphenIdentifier = HYPHEN;\\n\\n    /// @notice Function-selector for ERC20-token bridging on Hyphen-Route\\n    /// @dev This function selector is to be used while buidling transaction-data to bridge ERC20 tokens\\n    bytes4 public immutable HYPHEN_ERC20_EXTERNAL_BRIDGE_FUNCTION_SELECTOR =\\n        bytes4(\\n            keccak256(\\\"bridgeERC20To(uint256,bytes32,address,address,uint256)\\\")\\n        );\\n\\n    /// @notice Function-selector for Native bridging on Hyphen-Route\\n    /// @dev This function selector is to be used while buidling transaction-data to bridge Native tokens\\n    bytes4 public immutable HYPHEN_NATIVE_EXTERNAL_BRIDGE_FUNCTION_SELECTOR =\\n        bytes4(keccak256(\\\"bridgeNativeTo(uint256,bytes32,address,uint256)\\\"));\\n\\n    bytes4 public immutable HYPHEN_SWAP_BRIDGE_SELECTOR =\\n        bytes4(\\n            keccak256(\\\"swapAndBridge(uint32,bytes,(address,uint256,bytes32))\\\")\\n        );\\n\\n    /// @notice liquidityPoolManager - liquidityPool Manager of Hyphen used to bridge ERC20 and native\\n    /// @dev this is to be initialized in constructor with a valid deployed address of hyphen-liquidityPoolManager\\n    HyphenLiquidityPoolManager public immutable liquidityPoolManager;\\n\\n    /// @notice socketGatewayAddress to be initialised via storage variable BridgeImplBase\\n    /// @dev ensure liquidityPoolManager-address are set properly for the chainId in which the contract is being deployed\\n    constructor(\\n        address _liquidityPoolManager,\\n        address _socketGateway,\\n        address _socketDeployFactory\\n    ) BridgeImplBase(_socketGateway, _socketDeployFactory) {\\n        liquidityPoolManager = HyphenLiquidityPoolManager(\\n            _liquidityPoolManager\\n        );\\n    }\\n\\n    /// @notice Struct to be used in decode step from input parameter - a specific case of bridging after swap.\\n    /// @dev the data being encoded in offchain or by caller should have values set in this sequence of properties in this struct\\n    struct HyphenData {\\n        /// @notice address of token being bridged\\n        address token;\\n        /// @notice address of receiver\\n        address receiverAddress;\\n        /// @notice chainId of destination\\n        uint256 toChainId;\\n        /// @notice socket offchain created hash\\n        bytes32 metadata;\\n    }\\n\\n    struct HyphenDataNoToken {\\n        /// @notice address of receiver\\n        address receiverAddress;\\n        /// @notice chainId of destination\\n        uint256 toChainId;\\n        /// @notice chainId of destination\\n        bytes32 metadata;\\n    }\\n\\n    /**\\n     * @notice function to bridge tokens after swap.\\n     * @notice this is different from swapAndBridge, this function is called when the swap has already happened at a different place.\\n     * @notice This method is payable because the caller is doing token transfer and briding operation\\n     * @dev for usage, refer to controller implementations\\n     *      encodedData for bridge should follow the sequence of properties in HyphenBridgeData struct\\n     * @param amount amount of tokens being bridged. this can be ERC20 or native\\n     * @param bridgeData encoded data for HyphenBridge\\n     */\\n    function bridgeAfterSwap(\\n        uint256 amount,\\n        bytes calldata bridgeData\\n    ) external payable override {\\n        HyphenData memory hyphenData = abi.decode(bridgeData, (HyphenData));\\n\\n        if (hyphenData.token == NATIVE_TOKEN_ADDRESS) {\\n            liquidityPoolManager.depositNative{value: amount}(\\n                hyphenData.receiverAddress,\\n                hyphenData.toChainId,\\n                \\\"SOCKET\\\"\\n            );\\n        } else {\\n            ERC20(hyphenData.token).safeApprove(\\n                address(liquidityPoolManager),\\n                amount\\n            );\\n            liquidityPoolManager.depositErc20(\\n                hyphenData.toChainId,\\n                hyphenData.token,\\n                hyphenData.receiverAddress,\\n                amount,\\n                \\\"SOCKET\\\"\\n            );\\n        }\\n\\n        emit SocketBridge(\\n            amount,\\n            hyphenData.token,\\n            hyphenData.toChainId,\\n            HyphenIdentifier,\\n            msg.sender,\\n            hyphenData.receiverAddress,\\n            hyphenData.metadata\\n        );\\n    }\\n\\n    /**\\n     * @notice function to bridge tokens after swap.\\n     * @notice this is different from bridgeAfterSwap since this function holds the logic for swapping tokens too.\\n     * @notice This method is payable because the caller is doing token transfer and briding operation\\n     * @dev for usage, refer to controller implementations\\n     *      encodedData for bridge should follow the sequence of properties in HyphenBridgeData struct\\n     * @param swapId routeId for the swapImpl\\n     * @param swapData encoded data for swap\\n     * @param hyphenData encoded data for hyphenData\\n     */\\n    function swapAndBridge(\\n        uint32 swapId,\\n        bytes calldata swapData,\\n        HyphenDataNoToken calldata hyphenData\\n    ) external payable {\\n        (bool success, bytes memory result) = socketRoute\\n            .getRoute(swapId)\\n            .delegatecall(swapData);\\n\\n        if (!success) {\\n            assembly {\\n                revert(add(result, 32), mload(result))\\n            }\\n        }\\n\\n        (uint256 bridgeAmount, address token) = abi.decode(\\n            result,\\n            (uint256, address)\\n        );\\n        if (token == NATIVE_TOKEN_ADDRESS) {\\n            liquidityPoolManager.depositNative{value: bridgeAmount}(\\n                hyphenData.receiverAddress,\\n                hyphenData.toChainId,\\n                \\\"SOCKET\\\"\\n            );\\n        } else {\\n            ERC20(token).safeApprove(\\n                address(liquidityPoolManager),\\n                bridgeAmount\\n            );\\n            liquidityPoolManager.depositErc20(\\n                hyphenData.toChainId,\\n                token,\\n                hyphenData.receiverAddress,\\n                bridgeAmount,\\n                \\\"SOCKET\\\"\\n            );\\n        }\\n\\n        emit SocketBridge(\\n            bridgeAmount,\\n            token,\\n            hyphenData.toChainId,\\n            HyphenIdentifier,\\n            msg.sender,\\n            hyphenData.receiverAddress,\\n            hyphenData.metadata\\n        );\\n    }\\n\\n    /**\\n     * @notice function to handle ERC20 bridging to receipent via Hyphen-Bridge\\n     * @notice This method is payable because the caller is doing token transfer and briding operation\\n     * @param amount amount to be sent\\n     * @param receiverAddress address of the token to bridged to the destination chain.\\n     * @param token address of token being bridged\\n     * @param toChainId chainId of destination\\n     */\\n    function bridgeERC20To(\\n        uint256 amount,\\n        bytes32 metadata,\\n        address receiverAddress,\\n        address token,\\n        uint256 toChainId\\n    ) external payable {\\n        ERC20 tokenInstance = ERC20(token);\\n        tokenInstance.safeTransferFrom(msg.sender, socketGateway, amount);\\n        tokenInstance.safeApprove(address(liquidityPoolManager), amount);\\n        liquidityPoolManager.depositErc20(\\n            toChainId,\\n            token,\\n            receiverAddress,\\n            amount,\\n            \\\"SOCKET\\\"\\n        );\\n\\n        emit SocketBridge(\\n            amount,\\n            token,\\n            toChainId,\\n            HyphenIdentifier,\\n            msg.sender,\\n            receiverAddress,\\n            metadata\\n        );\\n    }\\n\\n    /**\\n     * @notice function to handle Native bridging to receipent via Hyphen-Bridge\\n     * @notice This method is payable because the caller is doing token transfer and briding operation\\n     * @param amount amount to be sent\\n     * @param receiverAddress address of the token to bridged to the destination chain.\\n     * @param toChainId chainId of destination\\n     */\\n    function bridgeNativeTo(\\n        uint256 amount,\\n        bytes32 metadata,\\n        address receiverAddress,\\n        uint256 toChainId\\n    ) external payable {\\n        liquidityPoolManager.depositNative{value: amount}(\\n            receiverAddress,\\n            toChainId,\\n            \\\"SOCKET\\\"\\n        );\\n\\n        emit SocketBridge(\\n            amount,\\n            NATIVE_TOKEN_ADDRESS,\\n            toChainId,\\n            HyphenIdentifier,\\n            msg.sender,\\n            receiverAddress,\\n            metadata\\n        );\\n    }\\n}\\n\"},\"src/bridges/optimism/l1/NativeOptimism.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >=0.8.0;\\n\\nimport {SafeTransferLib} from \\\"lib/solmate/src/utils/SafeTransferLib.sol\\\";\\nimport {ERC20} from \\\"lib/solmate/src/tokens/ERC20.sol\\\";\\nimport \\\"../interfaces/optimism.sol\\\";\\nimport {BridgeImplBase} from \\\"../../BridgeImplBase.sol\\\";\\nimport {UnsupportedInterfaceId} from \\\"../../../errors/SocketErrors.sol\\\";\\nimport {NATIVE_OPTIMISM} from \\\"../../../static/RouteIdentifiers.sol\\\";\\n\\n/**\\n * @title NativeOptimism-Route Implementation\\n * @notice Route implementation with functions to bridge ERC20 and Native via NativeOptimism-Bridge\\n * Tokens are bridged from Ethereum to Optimism Chain.\\n * Called via SocketGateway if the routeId in the request maps to the routeId of NativeOptimism-Implementation\\n * Contains function to handle bridging as post-step i.e linked to a preceeding step for swap\\n * RequestData is different to just bride and bridging chained with swap\\n * @author Socket dot tech.\\n */\\ncontract NativeOptimismImpl is BridgeImplBase {\\n    using SafeTransferLib for ERC20;\\n\\n    bytes32 public immutable NativeOptimismIdentifier = NATIVE_OPTIMISM;\\n\\n    uint256 public constant DESTINATION_CHAIN_ID = 10;\\n\\n    /// @notice Function-selector for ERC20-token bridging on Native-Optimism-Route\\n    /// @dev This function selector is to be used while buidling transaction-data to bridge ERC20 tokens\\n    bytes4\\n        public immutable NATIVE_OPTIMISM_ERC20_EXTERNAL_BRIDGE_FUNCTION_SELECTOR =\\n        bytes4(\\n            keccak256(\\n                \\\"bridgeERC20To(address,address,address,uint32,(bytes32,bytes32),uint256,uint256,address,bytes)\\\"\\n            )\\n        );\\n\\n    /// @notice Function-selector for Native bridging on Native-Optimism-Route\\n    /// @dev This function selector is to be used while buidling transaction-data to bridge Native balance\\n    bytes4\\n        public immutable NATIVE_OPTIMISM_NATIVE_EXTERNAL_BRIDGE_FUNCTION_SELECTOR =\\n        bytes4(\\n            keccak256(\\n                \\\"bridgeNativeTo(address,address,uint32,uint256,bytes32,bytes)\\\"\\n            )\\n        );\\n\\n    bytes4 public immutable NATIVE_OPTIMISM_SWAP_BRIDGE_SELECTOR =\\n        bytes4(\\n            keccak256(\\n                \\\"swapAndBridge(uint32,bytes,(uint256,bytes32,bytes32,address,address,uint32,address,bytes))\\\"\\n            )\\n        );\\n\\n    /// @notice socketGatewayAddress to be initialised via storage variable BridgeImplBase\\n    constructor(\\n        address _socketGateway,\\n        address _socketDeployFactory\\n    ) BridgeImplBase(_socketGateway, _socketDeployFactory) {}\\n\\n    /// @notice Struct to be used in decode step from input parameter - a specific case of bridging after swap.\\n    /// @dev the data being encoded in offchain or by caller should have values set in this sequence of properties in this struct\\n    struct OptimismBridgeDataNoToken {\\n        // interfaceId to be set offchain which is used to select one of the 3 kinds of bridging (standard bridge / old standard / synthetic)\\n        uint256 interfaceId;\\n        // currencyKey of the token beingBridged\\n        bytes32 currencyKey;\\n        // socket offchain created hash\\n        bytes32 metadata;\\n        // address of receiver of bridged tokens\\n        address receiverAddress;\\n        /**\\n         * OptimismBridge that Performs the logic for deposits by informing the L2 Deposited Token\\n         * contract of the deposit and calling a handler to lock the L1 funds. (e.g. transferFrom)\\n         */\\n        address customBridgeAddress;\\n        // Gas limit required to complete the deposit on L2.\\n        uint32 l2Gas;\\n        // Address of the L1 respective L2 ERC20\\n        address l2Token;\\n        // additional data , for ll contracts this will be 0x data or empty data\\n        bytes data;\\n    }\\n\\n    struct OptimismBridgeData {\\n        // interfaceId to be set offchain which is used to select one of the 3 kinds of bridging (standard bridge / old standard / synthetic)\\n        uint256 interfaceId;\\n        // currencyKey of the token beingBridged\\n        bytes32 currencyKey;\\n        // socket offchain created hash\\n        bytes32 metadata;\\n        // address of receiver of bridged tokens\\n        address receiverAddress;\\n        /**\\n         * OptimismBridge that Performs the logic for deposits by informing the L2 Deposited Token\\n         * contract of the deposit and calling a handler to lock the L1 funds. (e.g. transferFrom)\\n         */\\n        address customBridgeAddress;\\n        /// @notice address of token being bridged\\n        address token;\\n        // Gas limit required to complete the deposit on L2.\\n        uint32 l2Gas;\\n        // Address of the L1 respective L2 ERC20\\n        address l2Token;\\n        // additional data , for ll contracts this will be 0x data or empty data\\n        bytes data;\\n    }\\n\\n    struct OptimismERC20Data {\\n        bytes32 currencyKey;\\n        bytes32 metadata;\\n    }\\n\\n    /**\\n     * @notice function to bridge tokens after swap.\\n     * @notice this is different from swapAndBridge, this function is called when the swap has already happened at a different place.\\n     * @notice This method is payable because the caller is doing token transfer and briding operation\\n     * @dev for usage, refer to controller implementations\\n     *      encodedData for bridge should follow the sequence of properties in OptimismBridgeData struct\\n     * @param amount amount of tokens being bridged. this can be ERC20 or native\\n     * @param bridgeData encoded data for Optimism-Bridge\\n     */\\n    function bridgeAfterSwap(\\n        uint256 amount,\\n        bytes calldata bridgeData\\n    ) external payable override {\\n        OptimismBridgeData memory optimismBridgeData = abi.decode(\\n            bridgeData,\\n            (OptimismBridgeData)\\n        );\\n\\n        emit SocketBridge(\\n            amount,\\n            optimismBridgeData.token,\\n            DESTINATION_CHAIN_ID,\\n            NativeOptimismIdentifier,\\n            msg.sender,\\n            optimismBridgeData.receiverAddress,\\n            optimismBridgeData.metadata\\n        );\\n        if (optimismBridgeData.token == NATIVE_TOKEN_ADDRESS) {\\n            L1StandardBridge(optimismBridgeData.customBridgeAddress)\\n                .depositETHTo{value: amount}(\\n                optimismBridgeData.receiverAddress,\\n                optimismBridgeData.l2Gas,\\n                optimismBridgeData.data\\n            );\\n        } else {\\n            if (optimismBridgeData.interfaceId == 0) {\\n                revert UnsupportedInterfaceId();\\n            }\\n\\n            ERC20(optimismBridgeData.token).safeApprove(\\n                optimismBridgeData.customBridgeAddress,\\n                amount\\n            );\\n\\n            if (optimismBridgeData.interfaceId == 1) {\\n                // deposit into standard bridge\\n                L1StandardBridge(optimismBridgeData.customBridgeAddress)\\n                    .depositERC20To(\\n                        optimismBridgeData.token,\\n                        optimismBridgeData.l2Token,\\n                        optimismBridgeData.receiverAddress,\\n                        amount,\\n                        optimismBridgeData.l2Gas,\\n                        optimismBridgeData.data\\n                    );\\n                return;\\n            }\\n\\n            // Deposit Using Old Standard - iOVM_L1TokenGateway(Example - SNX Token)\\n            if (optimismBridgeData.interfaceId == 2) {\\n                OldL1TokenGateway(optimismBridgeData.customBridgeAddress)\\n                    .depositTo(optimismBridgeData.receiverAddress, amount);\\n                return;\\n            }\\n\\n            if (optimismBridgeData.interfaceId == 3) {\\n                OldL1TokenGateway(optimismBridgeData.customBridgeAddress)\\n                    .initiateSynthTransfer(\\n                        optimismBridgeData.currencyKey,\\n                        optimismBridgeData.receiverAddress,\\n                        amount\\n                    );\\n                return;\\n            }\\n        }\\n    }\\n\\n    /**\\n     * @notice function to bridge tokens after swap.\\n     * @notice this is different from bridgeAfterSwap since this function holds the logic for swapping tokens too.\\n     * @notice This method is payable because the caller is doing token transfer and briding operation\\n     * @dev for usage, refer to controller implementations\\n     *      encodedData for bridge should follow the sequence of properties in OptimismBridgeData struct\\n     * @param swapId routeId for the swapImpl\\n     * @param swapData encoded data for swap\\n     * @param optimismBridgeData encoded data for OptimismBridgeData\\n     */\\n    function swapAndBridge(\\n        uint32 swapId,\\n        bytes calldata swapData,\\n        OptimismBridgeDataNoToken calldata optimismBridgeData\\n    ) external payable {\\n        (bool success, bytes memory result) = socketRoute\\n            .getRoute(swapId)\\n            .delegatecall(swapData);\\n\\n        if (!success) {\\n            assembly {\\n                revert(add(result, 32), mload(result))\\n            }\\n        }\\n\\n        (uint256 bridgeAmount, address token) = abi.decode(\\n            result,\\n            (uint256, address)\\n        );\\n\\n        emit SocketBridge(\\n            bridgeAmount,\\n            token,\\n            DESTINATION_CHAIN_ID,\\n            NativeOptimismIdentifier,\\n            msg.sender,\\n            optimismBridgeData.receiverAddress,\\n            optimismBridgeData.metadata\\n        );\\n        if (token == NATIVE_TOKEN_ADDRESS) {\\n            L1StandardBridge(optimismBridgeData.customBridgeAddress)\\n                .depositETHTo{value: bridgeAmount}(\\n                optimismBridgeData.receiverAddress,\\n                optimismBridgeData.l2Gas,\\n                optimismBridgeData.data\\n            );\\n        } else {\\n            if (optimismBridgeData.interfaceId == 0) {\\n                revert UnsupportedInterfaceId();\\n            }\\n\\n            ERC20(token).safeApprove(\\n                optimismBridgeData.customBridgeAddress,\\n                bridgeAmount\\n            );\\n\\n            if (optimismBridgeData.interfaceId == 1) {\\n                // deposit into standard bridge\\n                L1StandardBridge(optimismBridgeData.customBridgeAddress)\\n                    .depositERC20To(\\n                        token,\\n                        optimismBridgeData.l2Token,\\n                        optimismBridgeData.receiverAddress,\\n                        bridgeAmount,\\n                        optimismBridgeData.l2Gas,\\n                        optimismBridgeData.data\\n                    );\\n                return;\\n            }\\n\\n            // Deposit Using Old Standard - iOVM_L1TokenGateway(Example - SNX Token)\\n            if (optimismBridgeData.interfaceId == 2) {\\n                OldL1TokenGateway(optimismBridgeData.customBridgeAddress)\\n                    .depositTo(\\n                        optimismBridgeData.receiverAddress,\\n                        bridgeAmount\\n                    );\\n                return;\\n            }\\n\\n            if (optimismBridgeData.interfaceId == 3) {\\n                OldL1TokenGateway(optimismBridgeData.customBridgeAddress)\\n                    .initiateSynthTransfer(\\n                        optimismBridgeData.currencyKey,\\n                        optimismBridgeData.receiverAddress,\\n                        bridgeAmount\\n                    );\\n                return;\\n            }\\n        }\\n    }\\n\\n    /**\\n     * @notice function to handle ERC20 bridging to receipent via NativeOptimism-Bridge\\n     * @notice This method is payable because the caller is doing token transfer and briding operation\\n     * @param token address of token being bridged\\n     * @param receiverAddress address of receiver of bridged tokens\\n     * @param customBridgeAddress OptimismBridge that Performs the logic for deposits by informing the L2 Deposited Token\\n     *                           contract of the deposit and calling a handler to lock the L1 funds. (e.g. transferFrom)\\n     * @param l2Gas Gas limit required to complete the deposit on L2.\\n     * @param optimismData extra data needed for optimism bridge\\n     * @param amount amount being bridged\\n     * @param interfaceId interfaceId to be set offchain which is used to select one of the 3 kinds of bridging (standard bridge / old standard / synthetic)\\n     * @param l2Token Address of the L1 respective L2 ERC20\\n     * @param data additional data , for ll contracts this will be 0x data or empty data\\n     */\\n    function bridgeERC20To(\\n        address token,\\n        address receiverAddress,\\n        address customBridgeAddress,\\n        uint32 l2Gas,\\n        OptimismERC20Data calldata optimismData,\\n        uint256 amount,\\n        uint256 interfaceId,\\n        address l2Token,\\n        bytes calldata data\\n    ) external payable {\\n        if (interfaceId == 0) {\\n            revert UnsupportedInterfaceId();\\n        }\\n\\n        ERC20 tokenInstance = ERC20(token);\\n        tokenInstance.safeTransferFrom(msg.sender, socketGateway, amount);\\n        tokenInstance.safeApprove(customBridgeAddress, amount);\\n\\n        emit SocketBridge(\\n            amount,\\n            token,\\n            DESTINATION_CHAIN_ID,\\n            NativeOptimismIdentifier,\\n            msg.sender,\\n            receiverAddress,\\n            optimismData.metadata\\n        );\\n        if (interfaceId == 1) {\\n            // deposit into standard bridge\\n            L1StandardBridge(customBridgeAddress).depositERC20To(\\n                token,\\n                l2Token,\\n                receiverAddress,\\n                amount,\\n                l2Gas,\\n                data\\n            );\\n            return;\\n        }\\n\\n        // Deposit Using Old Standard - iOVM_L1TokenGateway(Example - SNX Token)\\n        if (interfaceId == 2) {\\n            OldL1TokenGateway(customBridgeAddress).depositTo(\\n                receiverAddress,\\n                amount\\n            );\\n            return;\\n        }\\n\\n        if (interfaceId == 3) {\\n            OldL1TokenGateway(customBridgeAddress).initiateSynthTransfer(\\n                optimismData.currencyKey,\\n                receiverAddress,\\n                amount\\n            );\\n            return;\\n        }\\n    }\\n\\n    /**\\n     * @notice function to handle native balance bridging to receipent via NativeOptimism-Bridge\\n     * @notice This method is payable because the caller is doing token transfer and briding operation\\n     * @param receiverAddress address of receiver of bridged tokens\\n     * @param customBridgeAddress OptimismBridge that Performs the logic for deposits by informing the L2 Deposited Token\\n     *                           contract of the deposit and calling a handler to lock the L1 funds. (e.g. transferFrom)\\n     * @param l2Gas Gas limit required to complete the deposit on L2.\\n     * @param amount amount being bridged\\n     * @param data additional data , for ll contracts this will be 0x data or empty data\\n     */\\n    function bridgeNativeTo(\\n        address receiverAddress,\\n        address customBridgeAddress,\\n        uint32 l2Gas,\\n        uint256 amount,\\n        bytes32 metadata,\\n        bytes calldata data\\n    ) external payable {\\n        L1StandardBridge(customBridgeAddress).depositETHTo{value: amount}(\\n            receiverAddress,\\n            l2Gas,\\n            data\\n        );\\n\\n        emit SocketBridge(\\n            amount,\\n            NATIVE_TOKEN_ADDRESS,\\n            DESTINATION_CHAIN_ID,\\n            NativeOptimismIdentifier,\\n            msg.sender,\\n            receiverAddress,\\n            metadata\\n        );\\n    }\\n}\\n\"},\"src/deployFactory/SocketDeployFactory.sol\":{\"content\":\"//SPDX-License-Identifier: MIT\\npragma solidity ^0.8.4;\\n\\nimport \\\"../utils/Ownable.sol\\\";\\nimport {SafeTransferLib} from \\\"lib/solmate/src/utils/SafeTransferLib.sol\\\";\\nimport {ERC20} from \\\"lib/solmate/src/tokens/ERC20.sol\\\";\\nimport {ISocketBridgeBase} from \\\"../interfaces/ISocketBridgeBase.sol\\\";\\n\\n/**\\n * @dev In the constructor, set up the initialization code for socket\\n * contracts as well as the keccak256 hash of the given initialization code.\\n * that will be used to deploy any transient contracts, which will deploy any\\n * socket contracts that require the use of a constructor.\\n *\\n * Socket contract initialization code (29 bytes):\\n *\\n *       0x5860208158601c335a63aaf10f428752fa158151803b80938091923cf3\\n *\\n * Description:\\n *\\n * pc|op|name         | [stack]                                | <memory>\\n *\\n * ** set the first stack item to zero - used later **\\n * 00 58 getpc          [0]                                       <>\\n *\\n * ** set second stack item to 32, length of word returned from staticcall **\\n * 01 60 push1\\n * 02 20 outsize        [0, 32]                                   <>\\n *\\n * ** set third stack item to 0, position of word returned from staticcall **\\n * 03 81 dup2           [0, 32, 0]                                <>\\n *\\n * ** set fourth stack item to 4, length of selector given to staticcall **\\n * 04 58 getpc          [0, 32, 0, 4]                             <>\\n *\\n * ** set fifth stack item to 28, position of selector given to staticcall **\\n * 05 60 push1\\n * 06 1c inpos          [0, 32, 0, 4, 28]                         <>\\n *\\n * ** set the sixth stack item to msg.sender, target address for staticcall **\\n * 07 33 caller         [0, 32, 0, 4, 28, caller]                 <>\\n *\\n * ** set the seventh stack item to msg.gas, gas to forward for staticcall **\\n * 08 5a gas            [0, 32, 0, 4, 28, caller, gas]            <>\\n *\\n * ** set the eighth stack item to selector, \\\"what\\\" to store via mstore **\\n * 09 63 push4\\n * 10 aaf10f42 selector [0, 32, 0, 4, 28, caller, gas, 0xaaf10f42]    <>\\n *\\n * ** set the ninth stack item to 0, \\\"where\\\" to store via mstore ***\\n * 11 87 dup8           [0, 32, 0, 4, 28, caller, gas, 0xaaf10f42, 0] <>\\n *\\n * ** call mstore, consume 8 and 9 from the stack, place selector in memory **\\n * 12 52 mstore         [0, 32, 0, 4, 0, caller, gas]             <0xaaf10f42>\\n *\\n * ** call staticcall, consume items 2 through 7, place address in memory **\\n * 13 fa staticcall     [0, 1 (if successful)]                    <address>\\n *\\n * ** flip success bit in second stack item to set to 0 **\\n * 14 15 iszero         [0, 0]                                    <address>\\n *\\n * ** push a third 0 to the stack, position of address in memory **\\n * 15 81 dup2           [0, 0, 0]                                 <address>\\n *\\n * ** place address from position in memory onto third stack item **\\n * 16 51 mload          [0, 0, address]                           <>\\n *\\n * ** place address to fourth stack item for extcodesize to consume **\\n * 17 80 dup1           [0, 0, address, address]                  <>\\n *\\n * ** get extcodesize on fourth stack item for extcodecopy **\\n * 18 3b extcodesize    [0, 0, address, size]                     <>\\n *\\n * ** dup and swap size for use by return at end of init code **\\n * 19 80 dup1           [0, 0, address, size, size]               <>\\n * 20 93 swap4          [size, 0, address, size, 0]               <>\\n *\\n * ** push code position 0 to stack and reorder stack items for extcodecopy **\\n * 21 80 dup1           [size, 0, address, size, 0, 0]            <>\\n * 22 91 swap2          [size, 0, address, 0, 0, size]            <>\\n * 23 92 swap3          [size, 0, size, 0, 0, address]            <>\\n *\\n * ** call extcodecopy, consume four items, clone runtime code to memory **\\n * 24 3c extcodecopy    [size, 0]                                 <code>\\n *\\n * ** return to deploy final code in memory **\\n * 25 f3 return         []                                        *deployed!*\\n */\\ncontract SocketDeployFactory is Ownable {\\n    using SafeTransferLib for ERC20;\\n    address public immutable disabledRouteAddress;\\n\\n    mapping(address => address) _implementations;\\n    mapping(uint256 => bool) isDisabled;\\n    mapping(uint256 => bool) isRouteDeployed;\\n    mapping(address => bool) canDisableRoute;\\n\\n    event Deployed(address _addr);\\n    event DisabledRoute(address _addr);\\n    event Destroyed(address _addr);\\n    error ContractAlreadyDeployed();\\n    error NothingToDestroy();\\n    error AlreadyDisabled();\\n    error CannotBeDisabled();\\n    error OnlyDisabler();\\n\\n    constructor(address _owner, address disabledRoute) Ownable(_owner) {\\n        disabledRouteAddress = disabledRoute;\\n        canDisableRoute[_owner] = true;\\n    }\\n\\n    modifier onlyDisabler() {\\n        if (!canDisableRoute[msg.sender]) {\\n            revert OnlyDisabler();\\n        }\\n        _;\\n    }\\n\\n    function addDisablerAddress(address disabler) external onlyOwner {\\n        canDisableRoute[disabler] = true;\\n    }\\n\\n    function removeDisablerAddress(address disabler) external onlyOwner {\\n        canDisableRoute[disabler] = false;\\n    }\\n\\n    /**\\n     * @notice Deploys a route contract at predetermined location\\n     * @notice Caller must first deploy the route contract at another location and pass its address as implementation.\\n     * @param routeId route identifier\\n     * @param implementationContract address of deployed route contract. Its byte code will be copied to predetermined location.\\n     */\\n    function deploy(\\n        uint256 routeId,\\n        address implementationContract\\n    ) external onlyOwner returns (address) {\\n        // assign the initialization code for the socket contract.\\n\\n        bytes memory initCode = (\\n            hex\\\"5860208158601c335a63aaf10f428752fa158151803b80938091923cf3\\\"\\n        );\\n\\n        // determine the address of the socket contract.\\n        address routeContractAddress = _getContractAddress(routeId);\\n\\n        if (isRouteDeployed[routeId]) {\\n            revert ContractAlreadyDeployed();\\n        }\\n\\n        isRouteDeployed[routeId] = true;\\n\\n        //first we deploy the code we want to deploy on a separate address\\n        // store the implementation to be retrieved by the socket contract.\\n        _implementations[routeContractAddress] = implementationContract;\\n        address addr;\\n        assembly {\\n            let encoded_data := add(0x20, initCode) // load initialization code.\\n            let encoded_size := mload(initCode) // load init code's length.\\n            addr := create2(0, encoded_data, encoded_size, routeId) // routeId is used as salt\\n        }\\n        require(\\n            addr == routeContractAddress,\\n            \\\"Failed to deploy the new socket contract.\\\"\\n        );\\n        emit Deployed(addr);\\n        return addr;\\n    }\\n\\n    /**\\n     * @notice Destroy the route deployed at a location.\\n     * @param routeId route identifier to be destroyed.\\n     */\\n    function destroy(uint256 routeId) external onlyDisabler {\\n        // determine the address of the socket contract.\\n        _destroy(routeId);\\n    }\\n\\n    /**\\n     * @notice Deploy a disabled contract at destroyed route to handle it gracefully.\\n     * @param routeId route identifier to be disabled.\\n     */\\n    function disableRoute(\\n        uint256 routeId\\n    ) external onlyDisabler returns (address) {\\n        return _disableRoute(routeId);\\n    }\\n\\n    /**\\n     * @notice Destroy a list of routeIds\\n     * @param routeIds array of routeIds to be destroyed.\\n     */\\n    function multiDestroy(uint256[] calldata routeIds) external onlyDisabler {\\n        for (uint32 index = 0; index < routeIds.length; ) {\\n            _destroy(routeIds[index]);\\n            unchecked {\\n                ++index;\\n            }\\n        }\\n    }\\n\\n    /**\\n     * @notice Deploy a disabled contract at list of routeIds.\\n     * @param routeIds array of routeIds to be disabled.\\n     */\\n    function multiDisableRoute(\\n        uint256[] calldata routeIds\\n    ) external onlyDisabler {\\n        for (uint32 index = 0; index < routeIds.length; ) {\\n            _disableRoute(routeIds[index]);\\n            unchecked {\\n                ++index;\\n            }\\n        }\\n    }\\n\\n    /**\\n     * @dev External view function for calculating a socket contract address\\n     * given a particular routeId.\\n     */\\n    function getContractAddress(\\n        uint256 routeId\\n    ) external view returns (address) {\\n        // determine the address of the socket contract.\\n        return _getContractAddress(routeId);\\n    }\\n\\n    //those two functions are getting called by the socket Contract\\n    function getImplementation()\\n        external\\n        view\\n        returns (address implementation)\\n    {\\n        return _implementations[msg.sender];\\n    }\\n\\n    function _disableRoute(uint256 routeId) internal returns (address) {\\n        // assign the initialization code for the socket contract.\\n        bytes memory initCode = (\\n            hex\\\"5860208158601c335a63aaf10f428752fa158151803b80938091923cf3\\\"\\n        );\\n\\n        // determine the address of the socket contract.\\n        address routeContractAddress = _getContractAddress(routeId);\\n\\n        if (!isRouteDeployed[routeId]) {\\n            revert CannotBeDisabled();\\n        }\\n\\n        if (isDisabled[routeId]) {\\n            revert AlreadyDisabled();\\n        }\\n\\n        isDisabled[routeId] = true;\\n\\n        //first we deploy the code we want to deploy on a separate address\\n        // store the implementation to be retrieved by the socket contract.\\n        _implementations[routeContractAddress] = disabledRouteAddress;\\n        address addr;\\n        assembly {\\n            let encoded_data := add(0x20, initCode) // load initialization code.\\n            let encoded_size := mload(initCode) // load init code's length.\\n            addr := create2(0, encoded_data, encoded_size, routeId) // routeId is used as salt.\\n        }\\n        require(\\n            addr == routeContractAddress,\\n            \\\"Failed to deploy the new socket contract.\\\"\\n        );\\n        emit Deployed(addr);\\n        return addr;\\n    }\\n\\n    function _destroy(uint256 routeId) internal {\\n        // determine the address of the socket contract.\\n        address routeContractAddress = _getContractAddress(routeId);\\n\\n        if (!isRouteDeployed[routeId]) {\\n            revert NothingToDestroy();\\n        }\\n        ISocketBridgeBase(routeContractAddress).killme();\\n        emit Destroyed(routeContractAddress);\\n    }\\n\\n    /**\\n     * @dev Internal view function for calculating a socket contract address\\n     * given a particular routeId.\\n     */\\n    function _getContractAddress(\\n        uint256 routeId\\n    ) internal view returns (address) {\\n        // determine the address of the socket contract.\\n\\n        bytes memory initCode = (\\n            hex\\\"5860208158601c335a63aaf10f428752fa158151803b80938091923cf3\\\"\\n        );\\n        return\\n            address(\\n                uint160( // downcast to match the address type.\\n                    uint256( // convert to uint to truncate upper digits.\\n                        keccak256( // compute the CREATE2 hash using 4 inputs.\\n                            abi.encodePacked( // pack all inputs to the hash together.\\n                                hex\\\"ff\\\", // start with 0xff to distinguish from RLP.\\n                                address(this), // this contract will be the caller.\\n                                routeId, // the routeId is used as salt.\\n                                keccak256(abi.encodePacked(initCode)) // the init code hash.\\n                            )\\n                        )\\n                    )\\n                )\\n            );\\n    }\\n\\n    /**\\n     * @notice Rescues the ERC20 token to an address\\n               this is a restricted function to be called by only socketGatewayOwner\\n     * @dev as this is a restricted to socketGatewayOwner, ensure the userAddress is a known address\\n     * @param token address of the ERC20 token being rescued\\n     * @param userAddress address to which ERC20 is to be rescued\\n     * @param amount amount of ERC20 tokens being rescued\\n     */\\n    function rescueFunds(\\n        address token,\\n        address userAddress,\\n        uint256 amount\\n    ) external onlyOwner {\\n        ERC20(token).safeTransfer(userAddress, amount);\\n    }\\n\\n    /**\\n     * @notice Rescues the native balance to an address\\n               this is a restricted function to be called by only socketGatewayOwner\\n     * @dev as this is a restricted to socketGatewayOwner, ensure the userAddress is a known address\\n     * @param userAddress address to which native-balance is to be rescued\\n     * @param amount amount of native-balance being rescued\\n     */\\n    function rescueEther(\\n        address payable userAddress,\\n        uint256 amount\\n    ) external onlyOwner {\\n        userAddress.transfer(amount);\\n    }\\n}\\n\"},\"src/interfaces/ISocketController.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.4;\\n\\n/**\\n * @title ISocketController\\n * @notice Interface for SocketController functions.\\n * @dev functions can be added here for invocation from external contracts or off-chain\\n *      only restriction is that this should have functions to manage controllers\\n * @author Socket dot tech.\\n */\\ninterface ISocketController {\\n    /**\\n     * @notice Add controller to the socketGateway\\n               This is a restricted function to be called by only socketGatewayOwner\\n     * @dev ensure controllerAddress is a verified controller implementation address\\n     * @param _controllerAddress The address of controller implementation contract deployed\\n     * @return Id of the controller added to the controllers-mapping in socketGateway storage\\n     */\\n    function addController(\\n        address _controllerAddress\\n    ) external returns (uint32);\\n\\n    /**\\n     * @notice disable controller by setting ZeroAddress to the entry in controllers-mapping\\n               identified by controllerId as key.\\n               This is a restricted function to be called by only socketGatewayOwner\\n     * @param _controllerId The Id of controller-implementation in the controllers mapping\\n     */\\n    function disableController(uint32 _controllerId) external;\\n\\n    /**\\n     * @notice Get controllerImplementation address mapped to the controllerId\\n     * @param _controllerId controllerId is the key in the mapping for controllers\\n     * @return controller-implementation address\\n     */\\n    function getController(uint32 _controllerId) external returns (address);\\n}\\n\"},\"lib/solmate/src/utils/SafeTransferLib.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity >=0.8.0;\\n\\nimport {ERC20} from \\\"../tokens/ERC20.sol\\\";\\n\\n/// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values.\\n/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol)\\n/// @dev Use with caution! Some functions in this library knowingly create dirty bits at the destination of the free memory pointer.\\n/// @dev Note that none of the functions in this library check that a token has code at all! That responsibility is delegated to the caller.\\nlibrary SafeTransferLib {\\n    /*//////////////////////////////////////////////////////////////\\n                             ETH OPERATIONS\\n    //////////////////////////////////////////////////////////////*/\\n\\n    function safeTransferETH(address to, uint256 amount) internal {\\n        bool success;\\n\\n        /// @solidity memory-safe-assembly\\n        assembly {\\n            // Transfer the ETH and store if it succeeded or not.\\n            success := call(gas(), to, amount, 0, 0, 0, 0)\\n        }\\n\\n        require(success, \\\"ETH_TRANSFER_FAILED\\\");\\n    }\\n\\n    /*//////////////////////////////////////////////////////////////\\n                            ERC20 OPERATIONS\\n    //////////////////////////////////////////////////////////////*/\\n\\n    function safeTransferFrom(\\n        ERC20 token,\\n        address from,\\n        address to,\\n        uint256 amount\\n    ) internal {\\n        bool success;\\n\\n        /// @solidity memory-safe-assembly\\n        assembly {\\n            // Get a pointer to some free memory.\\n            let freeMemoryPointer := mload(0x40)\\n\\n            // Write the abi-encoded calldata into memory, beginning with the function selector.\\n            mstore(freeMemoryPointer, 0x23b872dd00000000000000000000000000000000000000000000000000000000)\\n            mstore(add(freeMemoryPointer, 4), from) // Append the \\\"from\\\" argument.\\n            mstore(add(freeMemoryPointer, 36), to) // Append the \\\"to\\\" argument.\\n            mstore(add(freeMemoryPointer, 68), amount) // Append the \\\"amount\\\" argument.\\n\\n            success := and(\\n                // Set success to whether the call reverted, if not we check it either\\n                // returned exactly 1 (can't just be non-zero data), or had no return data.\\n                or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),\\n                // We use 100 because the length of our calldata totals up like so: 4 + 32 * 3.\\n                // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.\\n                // Counterintuitively, this call must be positioned second to the or() call in the\\n                // surrounding and() call or else returndatasize() will be zero during the computation.\\n                call(gas(), token, 0, freeMemoryPointer, 100, 0, 32)\\n            )\\n        }\\n\\n        require(success, \\\"TRANSFER_FROM_FAILED\\\");\\n    }\\n\\n    function safeTransfer(\\n        ERC20 token,\\n        address to,\\n        uint256 amount\\n    ) internal {\\n        bool success;\\n\\n        /// @solidity memory-safe-assembly\\n        assembly {\\n            // Get a pointer to some free memory.\\n            let freeMemoryPointer := mload(0x40)\\n\\n            // Write the abi-encoded calldata into memory, beginning with the function selector.\\n            mstore(freeMemoryPointer, 0xa9059cbb00000000000000000000000000000000000000000000000000000000)\\n            mstore(add(freeMemoryPointer, 4), to) // Append the \\\"to\\\" argument.\\n            mstore(add(freeMemoryPointer, 36), amount) // Append the \\\"amount\\\" argument.\\n\\n            success := and(\\n                // Set success to whether the call reverted, if not we check it either\\n                // returned exactly 1 (can't just be non-zero data), or had no return data.\\n                or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),\\n                // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2.\\n                // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.\\n                // Counterintuitively, this call must be positioned second to the or() call in the\\n                // surrounding and() call or else returndatasize() will be zero during the computation.\\n                call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)\\n            )\\n        }\\n\\n        require(success, \\\"TRANSFER_FAILED\\\");\\n    }\\n\\n    function safeApprove(\\n        ERC20 token,\\n        address to,\\n        uint256 amount\\n    ) internal {\\n        bool success;\\n\\n        /// @solidity memory-safe-assembly\\n        assembly {\\n            // Get a pointer to some free memory.\\n            let freeMemoryPointer := mload(0x40)\\n\\n            // Write the abi-encoded calldata into memory, beginning with the function selector.\\n            mstore(freeMemoryPointer, 0x095ea7b300000000000000000000000000000000000000000000000000000000)\\n            mstore(add(freeMemoryPointer, 4), to) // Append the \\\"to\\\" argument.\\n            mstore(add(freeMemoryPointer, 36), amount) // Append the \\\"amount\\\" argument.\\n\\n            success := and(\\n                // Set success to whether the call reverted, if not we check it either\\n                // returned exactly 1 (can't just be non-zero data), or had no return data.\\n                or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),\\n                // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2.\\n                // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.\\n                // Counterintuitively, this call must be positioned second to the or() call in the\\n                // surrounding and() call or else returndatasize() will be zero during the computation.\\n                call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)\\n            )\\n        }\\n\\n        require(success, \\\"APPROVE_FAILED\\\");\\n    }\\n}\\n\"},\"src/controllers/BaseController.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.4;\\n\\nimport {ISocketRequest} from \\\"../interfaces/ISocketRequest.sol\\\";\\nimport {ISocketRoute} from \\\"../interfaces/ISocketRoute.sol\\\";\\n\\n/// @title BaseController Controller\\n/// @notice Base contract for all controller contracts\\nabstract contract BaseController {\\n    /// @notice Address used to identify if it is a native token transfer or not\\n    address public immutable NATIVE_TOKEN_ADDRESS =\\n        address(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE);\\n\\n    /// @notice Address used to identify if it is a Zero address\\n    address public immutable NULL_ADDRESS = address(0);\\n\\n    /// @notice FunctionSelector used to delegatecall from swap to the function of bridge router implementation\\n    bytes4 public immutable BRIDGE_AFTER_SWAP_SELECTOR =\\n        bytes4(keccak256(\\\"bridgeAfterSwap(uint256,bytes)\\\"));\\n\\n    /// @notice immutable variable to store the socketGateway address\\n    address public immutable socketGatewayAddress;\\n\\n    /// @notice immutable variable with instance of SocketRoute to access route functions\\n    ISocketRoute public immutable socketRoute;\\n\\n    /**\\n     * @notice Construct the base for all controllers.\\n     * @param _socketGatewayAddress Socketgateway address, an immutable variable to set.\\n     * @notice initialize the immutable variables of SocketRoute, SocketGateway\\n     */\\n    constructor(address _socketGatewayAddress) {\\n        socketGatewayAddress = _socketGatewayAddress;\\n        socketRoute = ISocketRoute(_socketGatewayAddress);\\n    }\\n\\n    /**\\n     * @notice Construct the base for all BridgeImplementations.\\n     * @param routeId routeId mapped to the routrImplementation\\n     * @param data transactionData generated with arguments of bridgeRequest (offchain or by caller)\\n     * @return returns the bytes response of the route execution (bridging, refuel or swap executions)\\n     */\\n    function _executeRoute(\\n        uint32 routeId,\\n        bytes memory data\\n    ) internal returns (bytes memory) {\\n        (bool success, bytes memory result) = socketRoute\\n            .getRoute(routeId)\\n            .delegatecall(data);\\n\\n        if (!success) {\\n            assembly {\\n                revert(add(result, 32), mload(result))\\n            }\\n        }\\n\\n        return result;\\n    }\\n}\\n\"},\"src/interfaces/ISocketRoute.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.4;\\n\\n/**\\n * @title ISocketRoute\\n * @notice Interface for routeManagement functions in SocketGateway.\\n * @author Socket dot tech.\\n */\\ninterface ISocketRoute {\\n    /**\\n     * @notice Add route to the socketGateway\\n               This is a restricted function to be called by only socketGatewayOwner\\n     * @dev ensure routeAddress is a verified bridge or middleware implementation address\\n     * @param routeAddress The address of bridge or middleware implementation contract deployed\\n     * @return Id of the route added to the routes-mapping in socketGateway storage\\n     */\\n    function addRoute(address routeAddress) external returns (uint256);\\n\\n    /**\\n     * @notice disable a route by setting ZeroAddress to the entry in routes-mapping\\n               identified by routeId as key.\\n               This is a restricted function to be called by only socketGatewayOwner\\n     * @param routeId The Id of route-implementation in the routes mapping\\n     */\\n    function disableRoute(uint32 routeId) external;\\n\\n    /**\\n     * @notice Get routeImplementation address mapped to the routeId\\n     * @param routeId routeId is the key in the mapping for routes\\n     * @return route-implementation address\\n     */\\n    function getRoute(uint32 routeId) external view returns (address);\\n}\\n\"},\"src/SocketGatewayDeployment.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.4;\\n\\npragma experimental ABIEncoderV2;\\n\\nimport \\\"./utils/Ownable.sol\\\";\\nimport {SafeTransferLib} from \\\"lib/solmate/src/utils/SafeTransferLib.sol\\\";\\nimport {ERC20} from \\\"lib/solmate/src/tokens/ERC20.sol\\\";\\nimport {LibUtil} from \\\"./libraries/LibUtil.sol\\\";\\nimport \\\"./libraries/LibBytes.sol\\\";\\nimport {ISocketRoute} from \\\"./interfaces/ISocketRoute.sol\\\";\\nimport {ISocketRequest} from \\\"./interfaces/ISocketRequest.sol\\\";\\nimport {ISocketGateway} from \\\"./interfaces/ISocketGateway.sol\\\";\\nimport {IncorrectBridgeRatios, ZeroAddressNotAllowed, ArrayLengthMismatch} from \\\"./errors/SocketErrors.sol\\\";\\n\\n/// @title SocketGatewayContract\\n/// @notice Socketgateway is a contract with entrypoint functions for all interactions with socket liquidity layer\\n/// @author Socket Team\\ncontract SocketGateway is Ownable {\\n    using LibBytes for bytes;\\n    using LibBytes for bytes4;\\n    using SafeTransferLib for ERC20;\\n\\n    /// @notice FunctionSelector used to delegatecall from swap to the function of bridge router implementation\\n    bytes4 public immutable BRIDGE_AFTER_SWAP_SELECTOR =\\n        bytes4(keccak256(\\\"bridgeAfterSwap(uint256,bytes)\\\"));\\n\\n    /// @notice storage variable to keep track of total number of routes registered in socketgateway\\n    uint32 public routesCount = 385;\\n\\n    /// @notice storage variable to keep track of total number of controllers registered in socketgateway\\n    uint32 public controllerCount;\\n\\n    address public immutable disabledRouteAddress;\\n\\n    uint256 public constant CENT_PERCENT = 100e18;\\n\\n    /// @notice storage mapping for route implementation addresses\\n    mapping(uint32 => address) public routes;\\n\\n    /// storage mapping for controller implemenation addresses\\n    mapping(uint32 => address) public controllers;\\n\\n    // Events ------------------------------------------------------------------------------------------------------->\\n\\n    /// @notice Event emitted when a router is added to socketgateway\\n    event NewRouteAdded(uint32 indexed routeId, address indexed route);\\n\\n    /// @notice Event emitted when a route is disabled\\n    event RouteDisabled(uint32 indexed routeId);\\n\\n    /// @notice Event emitted when ownership transfer is requested by socket-gateway-owner\\n    event OwnershipTransferRequested(\\n        address indexed _from,\\n        address indexed _to\\n    );\\n\\n    /// @notice Event emitted when a controller is added to socketgateway\\n    event ControllerAdded(\\n        uint32 indexed controllerId,\\n        address indexed controllerAddress\\n    );\\n\\n    /// @notice Event emitted when a controller is disabled\\n    event ControllerDisabled(uint32 indexed controllerId);\\n\\n    constructor(address _owner, address _disabledRoute) Ownable(_owner) {\\n        disabledRouteAddress = _disabledRoute;\\n    }\\n\\n    // Able to receive ether\\n    // solhint-disable-next-line no-empty-blocks\\n    receive() external payable {}\\n\\n    /*******************************************\\n     *          EXTERNAL AND PUBLIC FUNCTIONS  *\\n     *******************************************/\\n\\n    /**\\n     * @notice executes functions in the routes identified using routeId and functionSelectorData\\n     * @notice The caller must first approve this contract to spend amount of ERC20-Token being bridged/swapped\\n     * @dev ensure the data in routeData to be built using the function-selector defined as a\\n     *         constant in the route implementation contract\\n     * @param routeId route identifier\\n     * @param routeData functionSelectorData generated using the function-selector defined in the route Implementation\\n     */\\n    function executeRoute(\\n        uint32 routeId,\\n        bytes calldata routeData\\n    ) external payable returns (bytes memory) {\\n        (bool success, bytes memory result) = addressAt(routeId).delegatecall(\\n            routeData\\n        );\\n\\n        if (!success) {\\n            assembly {\\n                revert(add(result, 32), mload(result))\\n            }\\n        }\\n\\n        return result;\\n    }\\n\\n    /**\\n     * @notice swaps a token on sourceChain and split it across multiple bridge-recipients\\n     * @notice The caller must first approve this contract to spend amount of ERC20-Token being swapped\\n     * @dev ensure the swap-data and bridge-data is generated using the function-selector defined as a constant in the implementation address\\n     * @param swapMultiBridgeRequest request\\n     */\\n    function swapAndMultiBridge(\\n        ISocketRequest.SwapMultiBridgeRequest calldata swapMultiBridgeRequest\\n    ) external payable {\\n        uint256 requestLength = swapMultiBridgeRequest.bridgeRouteIds.length;\\n\\n        if (\\n            requestLength != swapMultiBridgeRequest.bridgeImplDataItems.length\\n        ) {\\n            revert ArrayLengthMismatch();\\n        }\\n        uint256 ratioAggregate;\\n        for (uint256 index = 0; index < requestLength; ) {\\n            ratioAggregate += swapMultiBridgeRequest.bridgeRatios[index];\\n        }\\n\\n        if (ratioAggregate != CENT_PERCENT) {\\n            revert IncorrectBridgeRatios();\\n        }\\n\\n        (bool swapSuccess, bytes memory swapResult) = addressAt(\\n            swapMultiBridgeRequest.swapRouteId\\n        ).delegatecall(swapMultiBridgeRequest.swapImplData);\\n\\n        if (!swapSuccess) {\\n            assembly {\\n                revert(add(swapResult, 32), mload(swapResult))\\n            }\\n        }\\n\\n        uint256 amountReceivedFromSwap = abi.decode(swapResult, (uint256));\\n\\n        uint256 bridgedAmount;\\n\\n        for (uint256 index = 0; index < requestLength; ) {\\n            uint256 bridgingAmount;\\n\\n            // if it is the last bridge request, bridge the remaining amount\\n            if (index == requestLength - 1) {\\n                bridgingAmount = amountReceivedFromSwap - bridgedAmount;\\n            } else {\\n                // bridging amount is the multiplication of bridgeRatio and amountReceivedFromSwap\\n                bridgingAmount =\\n                    (amountReceivedFromSwap *\\n                        swapMultiBridgeRequest.bridgeRatios[index]) /\\n                    (CENT_PERCENT);\\n            }\\n\\n            // update the bridged amount, this would be used for computation for last bridgeRequest\\n            bridgedAmount += bridgingAmount;\\n\\n            bytes memory bridgeImpldata = abi.encodeWithSelector(\\n                BRIDGE_AFTER_SWAP_SELECTOR,\\n                bridgingAmount,\\n                swapMultiBridgeRequest.bridgeImplDataItems[index]\\n            );\\n\\n            (bool bridgeSuccess, bytes memory bridgeResult) = addressAt(\\n                swapMultiBridgeRequest.bridgeRouteIds[index]\\n            ).delegatecall(bridgeImpldata);\\n\\n            if (!bridgeSuccess) {\\n                assembly {\\n                    revert(add(bridgeResult, 32), mload(bridgeResult))\\n                }\\n            }\\n\\n            unchecked {\\n                ++index;\\n            }\\n        }\\n    }\\n\\n    /**\\n     * @notice sequentially executes functions in the routes identified using routeId and functionSelectorData\\n     * @notice The caller must first approve this contract to spend amount of ERC20-Token being bridged/swapped\\n     * @dev ensure the data in each dataItem to be built using the function-selector defined as a\\n     *         constant in the route implementation contract\\n     * @param routeIds a list of route identifiers\\n     * @param dataItems a list of functionSelectorData generated using the function-selector defined in the route Implementation\\n     */\\n    function executeRoutes(\\n        uint32[] calldata routeIds,\\n        bytes[] calldata dataItems\\n    ) external payable {\\n        uint256 routeIdslength = routeIds.length;\\n        if (routeIdslength != dataItems.length) revert ArrayLengthMismatch();\\n        for (uint256 index = 0; index < routeIdslength; ) {\\n            (bool success, bytes memory result) = addressAt(routeIds[index])\\n                .delegatecall(dataItems[index]);\\n\\n            if (!success) {\\n                assembly {\\n                    revert(add(result, 32), mload(result))\\n                }\\n            }\\n\\n            unchecked {\\n                ++index;\\n            }\\n        }\\n    }\\n\\n    /**\\n     * @notice execute a controller function identified using the controllerId in the request\\n     * @notice The caller must first approve this contract to spend amount of ERC20-Token being bridged/swapped\\n     * @dev ensure the data in request to be built using the function-selector defined as a\\n     *         constant in the controller implementation contract\\n     * @param socketControllerRequest socketControllerRequest with controllerId to identify the\\n     *                                   controllerAddress and byteData constructed using functionSelector\\n     *                                   of the function being invoked\\n     * @return bytes data received from the call delegated to controller\\n     */\\n    function executeController(\\n        ISocketGateway.SocketControllerRequest calldata socketControllerRequest\\n    ) external payable returns (bytes memory) {\\n        (bool success, bytes memory result) = controllers[\\n            socketControllerRequest.controllerId\\n        ].delegatecall(socketControllerRequest.data);\\n\\n        if (!success) {\\n            assembly {\\n                revert(add(result, 32), mload(result))\\n            }\\n        }\\n\\n        return result;\\n    }\\n\\n    /**\\n     * @notice sequentially executes all controller requests\\n     * @notice The caller must first approve this contract to spend amount of ERC20-Token being bridged/swapped\\n     * @dev ensure the data in each controller-request to be built using the function-selector defined as a\\n     *         constant in the controller implementation contract\\n     * @param controllerRequests a list of socketControllerRequest\\n     *                              Each controllerRequest contains controllerId to identify the controllerAddress and\\n     *                              byteData constructed using functionSelector of the function being invoked\\n     */\\n    function executeControllers(\\n        ISocketGateway.SocketControllerRequest[] calldata controllerRequests\\n    ) external payable {\\n        for (uint32 index = 0; index < controllerRequests.length; ) {\\n            (bool success, bytes memory result) = controllers[\\n                controllerRequests[index].controllerId\\n            ].delegatecall(controllerRequests[index].data);\\n\\n            if (!success) {\\n                assembly {\\n                    revert(add(result, 32), mload(result))\\n                }\\n            }\\n\\n            unchecked {\\n                ++index;\\n            }\\n        }\\n    }\\n\\n    /**************************************\\n     *          ADMIN FUNCTIONS           *\\n     **************************************/\\n\\n    /**\\n     * @notice Add route to the socketGateway\\n               This is a restricted function to be called by only socketGatewayOwner\\n     * @dev ensure routeAddress is a verified bridge or middleware implementation address\\n     * @param routeAddress The address of bridge or middleware implementation contract deployed\\n     * @return Id of the route added to the routes-mapping in socketGateway storage\\n     */\\n    function addRoute(\\n        address routeAddress\\n    ) external onlyOwner returns (uint32) {\\n        uint32 routeId = routesCount;\\n        routes[routeId] = routeAddress;\\n\\n        routesCount += 1;\\n\\n        emit NewRouteAdded(routeId, routeAddress);\\n\\n        return routeId;\\n    }\\n\\n    /**\\n     * @notice Give Infinite or 0 approval to bridgeRoute for the tokenAddress\\n               This is a restricted function to be called by only socketGatewayOwner\\n     */\\n\\n    function setApprovalForRouters(\\n        address[] memory routeAddresses,\\n        address[] memory tokenAddresses,\\n        bool isMax\\n    ) external onlyOwner {\\n        for (uint32 index = 0; index < routeAddresses.length; ) {\\n            ERC20(tokenAddresses[index]).approve(\\n                routeAddresses[index],\\n                isMax ? type(uint256).max : 0\\n            );\\n            unchecked {\\n                ++index;\\n            }\\n        }\\n    }\\n\\n    /**\\n     * @notice Add controller to the socketGateway\\n               This is a restricted function to be called by only socketGatewayOwner\\n     * @dev ensure controllerAddress is a verified controller implementation address\\n     * @param controllerAddress The address of controller implementation contract deployed\\n     * @return Id of the controller added to the controllers-mapping in socketGateway storage\\n     */\\n    function addController(\\n        address controllerAddress\\n    ) external onlyOwner returns (uint32) {\\n        uint32 controllerId = controllerCount;\\n\\n        controllers[controllerId] = controllerAddress;\\n\\n        controllerCount += 1;\\n\\n        emit ControllerAdded(controllerId, controllerAddress);\\n\\n        return controllerId;\\n    }\\n\\n    /**\\n     * @notice disable controller by setting ZeroAddress to the entry in controllers-mapping\\n               identified by controllerId as key.\\n               This is a restricted function to be called by only socketGatewayOwner\\n     * @param controllerId The Id of controller-implementation in the controllers mapping\\n     */\\n    function disableController(uint32 controllerId) public onlyOwner {\\n        controllers[controllerId] = disabledRouteAddress;\\n        emit ControllerDisabled(controllerId);\\n    }\\n\\n    /**\\n     * @notice disable a route by setting ZeroAddress to the entry in routes-mapping\\n               identified by routeId as key.\\n               This is a restricted function to be called by only socketGatewayOwner\\n     * @param routeId The Id of route-implementation in the routes mapping\\n     */\\n    function disableRoute(uint32 routeId) external onlyOwner {\\n        routes[routeId] = disabledRouteAddress;\\n        emit RouteDisabled(routeId);\\n    }\\n\\n    /*******************************************\\n     *          RESTRICTED RESCUE FUNCTIONS    *\\n     *******************************************/\\n\\n    /**\\n     * @notice Rescues the ERC20 token to an address\\n               this is a restricted function to be called by only socketGatewayOwner\\n     * @dev as this is a restricted to socketGatewayOwner, ensure the userAddress is a known address\\n     * @param token address of the ERC20 token being rescued\\n     * @param userAddress address to which ERC20 is to be rescued\\n     * @param amount amount of ERC20 tokens being rescued\\n     */\\n    function rescueFunds(\\n        address token,\\n        address userAddress,\\n        uint256 amount\\n    ) external onlyOwner {\\n        ERC20(token).safeTransfer(userAddress, amount);\\n    }\\n\\n    /**\\n     * @notice Rescues the native balance to an address\\n               this is a restricted function to be called by only socketGatewayOwner\\n     * @dev as this is a restricted to socketGatewayOwner, ensure the userAddress is a known address\\n     * @param userAddress address to which native-balance is to be rescued\\n     * @param amount amount of native-balance being rescued\\n     */\\n    function rescueEther(\\n        address payable userAddress,\\n        uint256 amount\\n    ) external onlyOwner {\\n        userAddress.transfer(amount);\\n    }\\n\\n    /*******************************************\\n     *          VIEW FUNCTIONS                  *\\n     *******************************************/\\n\\n    /**\\n     * @notice Get routeImplementation address mapped to the routeId\\n     * @param routeId routeId is the key in the mapping for routes\\n     * @return route-implementation address\\n     */\\n    function getRoute(uint32 routeId) public view returns (address) {\\n        return addressAt(routeId);\\n    }\\n\\n    /**\\n     * @notice Get controllerImplementation address mapped to the controllerId\\n     * @param controllerId controllerId is the key in the mapping for controllers\\n     * @return controller-implementation address\\n     */\\n    function getController(uint32 controllerId) public view returns (address) {\\n        return controllers[controllerId];\\n    }\\n\\n    function addressAt(uint32 routeId) public view returns (address) {\\n        if (routeId < 385) {\\n            if (routeId < 257) {\\n                if (routeId < 129) {\\n                    if (routeId < 65) {\\n                        if (routeId < 33) {\\n                            if (routeId < 17) {\\n                                if (routeId < 9) {\\n                                    if (routeId < 5) {\\n                                        if (routeId < 3) {\\n                                            if (routeId == 1) {\\n                                                return\\n                                                    0x8cd6BaCDAe46B449E2e5B34e348A4eD459c84D50;\\n                                            } else {\\n                                                return\\n                                                    0x31524750Cd865fF6A3540f232754Fb974c18585C;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 3) {\\n                                                return\\n                                                    0xEd9b37342BeC8f3a2D7b000732ec87498aA6EC6a;\\n                                            } else {\\n                                                return\\n                                                    0xE8704Ef6211F8988Ccbb11badC89841808d66890;\\n                                            }\\n                                        }\\n                                    } else {\\n                                        if (routeId < 7) {\\n                                            if (routeId == 5) {\\n                                                return\\n                                                    0x9aFF58C460a461578C433e11C4108D1c4cF77761;\\n                                            } else {\\n                                                return\\n                                                    0x2D1733886cFd465B0B99F1492F40847495f334C5;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 7) {\\n                                                return\\n                                                    0x715497Be4D130F04B8442F0A1F7a9312D4e54FC4;\\n                                            } else {\\n                                                return\\n                                                    0x90C8a40c38E633B5B0e0d0585b9F7FA05462CaaF;\\n                                            }\\n                                        }\\n                                    }\\n                                } else {\\n                                    if (routeId < 13) {\\n                                        if (routeId < 11) {\\n                                            if (routeId == 9) {\\n                                                return\\n                                                    0xa402b70FCfF3F4a8422B93Ef58E895021eAdE4F6;\\n                                            } else {\\n                                                return\\n                                                    0xc1B718522E15CD42C4Ac385a929fc2B51f5B892e;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 11) {\\n                                                return\\n                                                    0xa97bf2f7c26C43c010c349F52f5eA5dC49B2DD38;\\n                                            } else {\\n                                                return\\n                                                    0x969423d71b62C81d2f28d707364c9Dc4a0764c53;\\n                                            }\\n                                        }\\n                                    } else {\\n                                        if (routeId < 15) {\\n                                            if (routeId == 13) {\\n                                                return\\n                                                    0xF86729934C083fbEc8C796068A1fC60701Ea1207;\\n                                            } else {\\n                                                return\\n                                                    0xD7cC2571F5823caCA26A42690D2BE7803DD5393f;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 15) {\\n                                                return\\n                                                    0x7c8837a279bbbf7d8B93413763176de9F65d5bB9;\\n                                            } else {\\n                                                return\\n                                                    0x13b81C27B588C07D04458ed7dDbdbD26D1e39bcc;\\n                                            }\\n                                        }\\n                                    }\\n                                }\\n                            } else {\\n                                if (routeId < 25) {\\n                                    if (routeId < 21) {\\n                                        if (routeId < 19) {\\n                                            if (routeId == 17) {\\n                                                return\\n                                                    0x52560Ac678aFA1345D15474287d16Dc1eA3F78aE;\\n                                            } else {\\n                                                return\\n                                                    0x1E31e376551459667cd7643440c1b21CE69065A0;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 19) {\\n                                                return\\n                                                    0xc57D822CB3288e7b97EF8f8af0EcdcD1B783529B;\\n                                            } else {\\n                                                return\\n                                                    0x2197A1D9Af24b4d6a64Bff95B4c29Fcd3Ff28C30;\\n                                            }\\n                                        }\\n                                    } else {\\n                                        if (routeId < 23) {\\n                                            if (routeId == 21) {\\n                                                return\\n                                                    0xE3700feAa5100041Bf6b7AdBA1f72f647809Fd00;\\n                                            } else {\\n                                                return\\n                                                    0xc02E8a0Fdabf0EeFCEA025163d90B5621E2b9948;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 23) {\\n                                                return\\n                                                    0xF5144235E2926cAb3c69b30113254Fa632f72d62;\\n                                            } else {\\n                                                return\\n                                                    0xBa3F92313B00A1f7Bc53b2c24EB195c8b2F57682;\\n                                            }\\n                                        }\\n                                    }\\n                                } else {\\n                                    if (routeId < 29) {\\n                                        if (routeId < 27) {\\n                                            if (routeId == 25) {\\n                                                return\\n                                                    0x77a6856fe1fFA5bEB55A1d2ED86E27C7c482CB76;\\n                                            } else {\\n                                                return\\n                                                    0x4826Ff4e01E44b1FCEFBfb38cd96687Eb7786b44;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 27) {\\n                                                return\\n                                                    0x55FF3f5493cf5e80E76DEA7E327b9Cd8440Af646;\\n                                            } else {\\n                                                return\\n                                                    0xF430Db544bE9770503BE4aa51997aA19bBd5BA4f;\\n                                            }\\n                                        }\\n                                    } else {\\n                                        if (routeId < 31) {\\n                                            if (routeId == 29) {\\n                                                return\\n                                                    0x0f166446ce1484EE3B0663E7E67DF10F5D240115;\\n                                            } else {\\n                                                return\\n                                                    0x6365095D92537f242Db5EdFDd572745E72aC33d9;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 31) {\\n                                                return\\n                                                    0x5c7BC93f06ce3eAe75ADf55E10e23d2c1dE5Bc65;\\n                                            } else {\\n                                                return\\n                                                    0xe46383bAD90d7A08197ccF08972e9DCdccCE9BA4;\\n                                            }\\n                                        }\\n                                    }\\n                                }\\n                            }\\n                        } else {\\n                            if (routeId < 49) {\\n                                if (routeId < 41) {\\n                                    if (routeId < 37) {\\n                                        if (routeId < 35) {\\n                                            if (routeId == 33) {\\n                                                return\\n                                                    0xf0f21710c071E3B728bdc4654c3c0b873aAaa308;\\n                                            } else {\\n                                                return\\n                                                    0x63Bc9ed3AcAAeB0332531C9fB03b0a2352E9Ff25;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 35) {\\n                                                return\\n                                                    0xd1CE808625CB4007a1708824AE82CdB0ece57De9;\\n                                            } else {\\n                                                return\\n                                                    0x57BbB148112f4ba224841c3FE018884171004661;\\n                                            }\\n                                        }\\n                                    } else {\\n                                        if (routeId < 39) {\\n                                            if (routeId == 37) {\\n                                                return\\n                                                    0x037f7d6933036F34DFabd40Ff8e4D789069f92e3;\\n                                            } else {\\n                                                return\\n                                                    0xeF978c280915CfF3Dca4EDfa8932469e40ADA1e1;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 39) {\\n                                                return\\n                                                    0x92ee9e071B13f7ecFD62B7DED404A16CBc223CD3;\\n                                            } else {\\n                                                return\\n                                                    0x94Ae539c186e41ed762271338Edf140414D1E442;\\n                                            }\\n                                        }\\n                                    }\\n                                } else {\\n                                    if (routeId < 45) {\\n                                        if (routeId < 43) {\\n                                            if (routeId == 41) {\\n                                                return\\n                                                    0x30A64BBe4DdBD43dA2368EFd1eB2d80C10d84DAb;\\n                                            } else {\\n                                                return\\n                                                    0x3aEABf81c1Dc4c1b73d5B2a95410f126426FB596;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 43) {\\n                                                return\\n                                                    0x25b08aB3D0C8ea4cC9d967b79688C6D98f3f563a;\\n                                            } else {\\n                                                return\\n                                                    0xea40cB15C9A3BBd27af6474483886F7c0c9AE406;\\n                                            }\\n                                        }\\n                                    } else {\\n                                        if (routeId < 47) {\\n                                            if (routeId == 45) {\\n                                                return\\n                                                    0x9580113Cc04e5a0a03359686304EF3A80b936Dd3;\\n                                            } else {\\n                                                return\\n                                                    0xD211c826d568957F3b66a3F4d9c5f68cCc66E619;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 47) {\\n                                                return\\n                                                    0xCEE24D0635c4C56315d133b031984d4A6f509476;\\n                                            } else {\\n                                                return\\n                                                    0x3922e6B987983229798e7A20095EC372744d4D4c;\\n                                            }\\n                                        }\\n                                    }\\n                                }\\n                            } else {\\n                                if (routeId < 57) {\\n                                    if (routeId < 53) {\\n                                        if (routeId < 51) {\\n                                            if (routeId == 49) {\\n                                                return\\n                                                    0x2d92D03413d296e1F31450479349757187F2a2b7;\\n                                            } else {\\n                                                return\\n                                                    0x0fe5308eE90FC78F45c89dB6053eA859097860CA;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 51) {\\n                                                return\\n                                                    0x08Ba68e067C0505bAF0C1311E0cFB2B1B59b969c;\\n                                            } else {\\n                                                return\\n                                                    0x9bee5DdDF75C24897374f92A534B7A6f24e97f4a;\\n                                            }\\n                                        }\\n                                    } else {\\n                                        if (routeId < 55) {\\n                                            if (routeId == 53) {\\n                                                return\\n                                                    0x1FC5A90B232208704B930c1edf82FFC6ACc02734;\\n                                            } else {\\n                                                return\\n                                                    0x5b1B0417cb44c761C2a23ee435d011F0214b3C85;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 55) {\\n                                                return\\n                                                    0x9d70cDaCA12A738C283020760f449D7816D592ec;\\n                                            } else {\\n                                                return\\n                                                    0x95a23b9CB830EcCFDDD5dF56A4ec665e3381Fa12;\\n                                            }\\n                                        }\\n                                    }\\n                                } else {\\n                                    if (routeId < 61) {\\n                                        if (routeId < 59) {\\n                                            if (routeId == 57) {\\n                                                return\\n                                                    0x483a957Cf1251c20e096C35c8399721D1200A3Fc;\\n                                            } else {\\n                                                return\\n                                                    0xb4AD39Cb293b0Ec7FEDa743442769A7FF04987CD;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 59) {\\n                                                return\\n                                                    0x4C543AD78c1590D81BAe09Fc5B6Df4132A2461d0;\\n                                            } else {\\n                                                return\\n                                                    0x471d5E5195c563902781734cfe1FF3981F8B6c86;\\n                                            }\\n                                        }\\n                                    } else {\\n                                        if (routeId < 63) {\\n                                            if (routeId == 61) {\\n                                                return\\n                                                    0x1B12a54B5E606D95B8B8D123c9Cb09221Ee37584;\\n                                            } else {\\n                                                return\\n                                                    0xE4127cC550baC433646a7D998775a84daC16c7f3;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 63) {\\n                                                return\\n                                                    0xecb1b55AB12E7dd788D585c6C5cD61B5F87be836;\\n                                            } else {\\n                                                return\\n                                                    0xf91ef487C5A1579f70601b6D347e19756092eEBf;\\n                                            }\\n                                        }\\n                                    }\\n                                }\\n                            }\\n                        }\\n                    } else {\\n                        if (routeId < 97) {\\n                            if (routeId < 81) {\\n                                if (routeId < 73) {\\n                                    if (routeId < 69) {\\n                                        if (routeId < 67) {\\n                                            if (routeId == 65) {\\n                                                return\\n                                                    0x34a16a7e9BADEEFD4f056310cbE0b1423Fa1b760;\\n                                            } else {\\n                                                return\\n                                                    0x60E10E80c7680f429dBbC232830BEcd3D623c4CF;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 67) {\\n                                                return\\n                                                    0x66465285B8D65362A1d86CE00fE2bE949Fd6debF;\\n                                            } else {\\n                                                return\\n                                                    0x5aB231B7e1A3A74a48f67Ab7bde5Cdd4267022E0;\\n                                            }\\n                                        }\\n                                    } else {\\n                                        if (routeId < 71) {\\n                                            if (routeId == 69) {\\n                                                return\\n                                                    0x3A1C3633eE79d43366F5c67802a746aFD6b162Ba;\\n                                            } else {\\n                                                return\\n                                                    0x0C4BfCbA8dC3C811437521a80E81e41DAF479039;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 71) {\\n                                                return\\n                                                    0x6caf25d2e139C5431a1FA526EAf8d73ff2e6252C;\\n                                            } else {\\n                                                return\\n                                                    0x74ad21e09FDa68638CE14A3009A79B6D16574257;\\n                                            }\\n                                        }\\n                                    }\\n                                } else {\\n                                    if (routeId < 77) {\\n                                        if (routeId < 75) {\\n                                            if (routeId == 73) {\\n                                                return\\n                                                    0xD4923A61008894b99cc1CD3407eF9524f02aA0Ca;\\n                                            } else {\\n                                                return\\n                                                    0x6F159b5EB823BD415886b9271aA2A723a00a1987;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 75) {\\n                                                return\\n                                                    0x742a8aA42E7bfB4554dE30f4Fb07FFb6f2068863;\\n                                            } else {\\n                                                return\\n                                                    0x4AE9702d3360400E47B446e76DE063ACAb930101;\\n                                            }\\n                                        }\\n                                    } else {\\n                                        if (routeId < 79) {\\n                                            if (routeId == 77) {\\n                                                return\\n                                                    0x0E19a0a44ddA7dAD854ec5Cc867d16869c4E80F4;\\n                                            } else {\\n                                                return\\n                                                    0xE021A51968f25148F726E326C88d2556c5647557;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 79) {\\n                                                return\\n                                                    0x64287BDDDaeF4d94E4599a3D882bed29E6Ada4B6;\\n                                            } else {\\n                                                return\\n                                                    0xcBB57Fd2e19cc7e9D444d5b4325A2F1047d0C73f;\\n                                            }\\n                                        }\\n                                    }\\n                                }\\n                            } else {\\n                                if (routeId < 89) {\\n                                    if (routeId < 85) {\\n                                        if (routeId < 83) {\\n                                            if (routeId == 81) {\\n                                                return\\n                                                    0x373DE80DF7D82cFF6D76F29581b360C56331e957;\\n                                            } else {\\n                                                return\\n                                                    0x0466356E131AD61596a51F86BAd1C03A328960D8;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 83) {\\n                                                return\\n                                                    0x01726B960992f1b74311b248E2a922fC707d43A6;\\n                                            } else {\\n                                                return\\n                                                    0x2E21bdf9A4509b89795BCE7E132f248a75814CEc;\\n                                            }\\n                                        }\\n                                    } else {\\n                                        if (routeId < 87) {\\n                                            if (routeId == 85) {\\n                                                return\\n                                                    0x769512b23aEfF842379091d3B6E4B5456F631D42;\\n                                            } else {\\n                                                return\\n                                                    0xe7eD9be946a74Ec19325D39C6EEb57887ccB2B0D;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 87) {\\n                                                return\\n                                                    0xc4D01Ec357c2b511d10c15e6b6974380F0E62e67;\\n                                            } else {\\n                                                return\\n                                                    0x5bC49CC9dD77bECF2fd3A3C55611e84E69AFa3AE;\\n                                            }\\n                                        }\\n                                    }\\n                                } else {\\n                                    if (routeId < 93) {\\n                                        if (routeId < 91) {\\n                                            if (routeId == 89) {\\n                                                return\\n                                                    0x48bcD879954fA14e7DbdAeb56F79C1e9DDcb69ec;\\n                                            } else {\\n                                                return\\n                                                    0xE929bDde21b462572FcAA4de6F49B9D3246688D0;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 91) {\\n                                                return\\n                                                    0x85Aae300438222f0e3A9Bc870267a5633A9438bd;\\n                                            } else {\\n                                                return\\n                                                    0x51f72E1096a81C55cd142d66d39B688C657f9Be8;\\n                                            }\\n                                        }\\n                                    } else {\\n                                        if (routeId < 95) {\\n                                            if (routeId == 93) {\\n                                                return\\n                                                    0x3A8a05BF68ac54B01E6C0f492abF97465F3d15f9;\\n                                            } else {\\n                                                return\\n                                                    0x145aA67133F0c2C36b9771e92e0B7655f0D59040;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 95) {\\n                                                return\\n                                                    0xa030315d7DB11F9892758C9e7092D841e0ADC618;\\n                                            } else {\\n                                                return\\n                                                    0xdF1f8d81a3734bdDdEfaC6Ca1596E081e57c3044;\\n                                            }\\n                                        }\\n                                    }\\n                                }\\n                            }\\n                        } else {\\n                            if (routeId < 113) {\\n                                if (routeId < 105) {\\n                                    if (routeId < 101) {\\n                                        if (routeId < 99) {\\n                                            if (routeId == 97) {\\n                                                return\\n                                                    0xFF2833123B58aa05d04D7fb99f5FB768B2b435F8;\\n                                            } else {\\n                                                return\\n                                                    0xc8f09c1fD751C570233765f71b0e280d74e6e743;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 99) {\\n                                                return\\n                                                    0x3026DA6Ceca2E5A57A05153653D9212FFAaA49d8;\\n                                            } else {\\n                                                return\\n                                                    0xdE68Ee703dE0D11f67B0cE5891cB4a903de6D160;\\n                                            }\\n                                        }\\n                                    } else {\\n                                        if (routeId < 103) {\\n                                            if (routeId == 101) {\\n                                                return\\n                                                    0xE23a7730e81FB4E87A6D0bd9f63EE77ac86C3DA4;\\n                                            } else {\\n                                                return\\n                                                    0x8b1DBe04aD76a7d8bC079cACd3ED4D99B897F4a0;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 103) {\\n                                                return\\n                                                    0xBB227240FA459b69C6889B2b8cb1BE76F118061f;\\n                                            } else {\\n                                                return\\n                                                    0xC062b9b3f0dB28BB8afAfcD4d075729344114ffe;\\n                                            }\\n                                        }\\n                                    }\\n                                } else {\\n                                    if (routeId < 109) {\\n                                        if (routeId < 107) {\\n                                            if (routeId == 105) {\\n                                                return\\n                                                    0x553188Aa45f5FDB83EC4Ca485982F8fC082480D1;\\n                                            } else {\\n                                                return\\n                                                    0x0109d83D746EaCb6d4014953D9E12d6ca85e330b;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 107) {\\n                                                return\\n                                                    0x45B1bEd29812F5bf6711074ACD180B2aeB783AD9;\\n                                            } else {\\n                                                return\\n                                                    0xdA06eC8c19aea31D77F60299678Cba40E743e1aD;\\n                                            }\\n                                        }\\n                                    } else {\\n                                        if (routeId < 111) {\\n                                            if (routeId == 109) {\\n                                                return\\n                                                    0x3cC5235c97d975a9b4FD4501B3446c981ea3D855;\\n                                            } else {\\n                                                return\\n                                                    0xa1827267d6Bd989Ff38580aE3d9deff6Acf19163;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 111) {\\n                                                return\\n                                                    0x3663CAA0433A3D4171b3581Cf2410702840A735A;\\n                                            } else {\\n                                                return\\n                                                    0x7575D0a7614F655BA77C74a72a43bbd4fA6246a3;\\n                                            }\\n                                        }\\n                                    }\\n                                }\\n                            } else {\\n                                if (routeId < 121) {\\n                                    if (routeId < 117) {\\n                                        if (routeId < 115) {\\n                                            if (routeId == 113) {\\n                                                return\\n                                                    0x2516Defc18bc07089c5dAFf5eafD7B0EF64611E2;\\n                                            } else {\\n                                                return\\n                                                    0xfec5FF08E20fbc107a97Af2D38BD0025b84ee233;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 115) {\\n                                                return\\n                                                    0x0FB5763a87242B25243e23D73f55945fE787523A;\\n                                            } else {\\n                                                return\\n                                                    0xe4C00db89678dBf8391f430C578Ca857Dd98aDE1;\\n                                            }\\n                                        }\\n                                    } else {\\n                                        if (routeId < 119) {\\n                                            if (routeId == 117) {\\n                                                return\\n                                                    0x8F2A22061F9F35E64f14523dC1A5f8159e6a21B7;\\n                                            } else {\\n                                                return\\n                                                    0x18e4b838ae966917E20E9c9c5Ad359cDD38303bB;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 119) {\\n                                                return\\n                                                    0x61ACb1d3Dcb3e3429832A164Cc0fC9849fb75A4a;\\n                                            } else {\\n                                                return\\n                                                    0x7681e3c8e7A41DCA55C257cc0d1Ae757f5530E65;\\n                                            }\\n                                        }\\n                                    }\\n                                } else {\\n                                    if (routeId < 125) {\\n                                        if (routeId < 123) {\\n                                            if (routeId == 121) {\\n                                                return\\n                                                    0x806a2AB9748C3D1DB976550890E3f528B7E8Faec;\\n                                            } else {\\n                                                return\\n                                                    0xBDb8A5DD52C2c239fbC31E9d43B763B0197028FF;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 123) {\\n                                                return\\n                                                    0x474EC9203706010B9978D6bD0b105D36755e4848;\\n                                            } else {\\n                                                return\\n                                                    0x8dfd0D829b303F2239212E591a0F92a32880f36E;\\n                                            }\\n                                        }\\n                                    } else {\\n                                        if (routeId < 127) {\\n                                            if (routeId == 125) {\\n                                                return\\n                                                    0xad4BcE9745860B1adD6F1Bd34a916f050E4c82C2;\\n                                            } else {\\n                                                return\\n                                                    0xBC701115b9fe14bC8CC5934cdC92517173e308C4;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 127) {\\n                                                return\\n                                                    0x0D1918d786Db8546a11aDeD475C98370E06f255E;\\n                                            } else {\\n                                                return\\n                                                    0xee44f57cD6936DB55B99163f3Df367B01EdA785a;\\n                                            }\\n                                        }\\n                                    }\\n                                }\\n                            }\\n                        }\\n                    }\\n                } else {\\n                    if (routeId < 193) {\\n                        if (routeId < 161) {\\n                            if (routeId < 145) {\\n                                if (routeId < 137) {\\n                                    if (routeId < 133) {\\n                                        if (routeId < 131) {\\n                                            if (routeId == 129) {\\n                                                return\\n                                                    0x63044521fe5a1e488D7eD419cD0e35b7C24F2aa7;\\n                                            } else {\\n                                                return\\n                                                    0x410085E73BD85e90d97b84A68C125aDB9F91f85b;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 131) {\\n                                                return\\n                                                    0x7913fe97E07C7A397Ec274Ab1d4E2622C88EC5D1;\\n                                            } else {\\n                                                return\\n                                                    0x977f9fE93c064DCf54157406DaABC3a722e8184C;\\n                                            }\\n                                        }\\n                                    } else {\\n                                        if (routeId < 135) {\\n                                            if (routeId == 133) {\\n                                                return\\n                                                    0xCD2236468722057cFbbABad2db3DEA9c20d5B01B;\\n                                            } else {\\n                                                return\\n                                                    0x17c7287A491cf5Ff81E2678cF2BfAE4333F6108c;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 135) {\\n                                                return\\n                                                    0x354D9a5Dbf96c71B79a265F03B595C6Fdc04dadd;\\n                                            } else {\\n                                                return\\n                                                    0xb4e409EB8e775eeFEb0344f9eee884cc7ed21c69;\\n                                            }\\n                                        }\\n                                    }\\n                                } else {\\n                                    if (routeId < 141) {\\n                                        if (routeId < 139) {\\n                                            if (routeId == 137) {\\n                                                return\\n                                                    0xa1a3c4670Ad69D9be4ab2D39D1231FEC2a63b519;\\n                                            } else {\\n                                                return\\n                                                    0x4589A22199870729C1be5CD62EE93BeD858113E6;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 139) {\\n                                                return\\n                                                    0x8E7b864dB26Bd6C798C38d4Ba36EbA0d6602cF11;\\n                                            } else {\\n                                                return\\n                                                    0xA2D17C7260a4CB7b9854e89Fc367E80E87872a2d;\\n                                            }\\n                                        }\\n                                    } else {\\n                                        if (routeId < 143) {\\n                                            if (routeId == 141) {\\n                                                return\\n                                                    0xC7F0EDf0A1288627b0432304918A75e9084CBD46;\\n                                            } else {\\n                                                return\\n                                                    0xE4B4EF1f9A4aBFEdB371fA7a6143993B15d4df25;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 143) {\\n                                                return\\n                                                    0xfe3D84A2Ef306FEBb5452441C9BDBb6521666F6A;\\n                                            } else {\\n                                                return\\n                                                    0x8A12B6C64121920110aE58F7cd67DfEc21c6a4C3;\\n                                            }\\n                                        }\\n                                    }\\n                                }\\n                            } else {\\n                                if (routeId < 153) {\\n                                    if (routeId < 149) {\\n                                        if (routeId < 147) {\\n                                            if (routeId == 145) {\\n                                                return\\n                                                    0x76c4d9aFC4717a2BAac4e5f26CccF02351f7a3DA;\\n                                            } else {\\n                                                return\\n                                                    0xd4719BA550E397aeAcca1Ad2201c1ba69024FAAf;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 147) {\\n                                                return\\n                                                    0x9646126Ce025224d1682C227d915a386efc0A1Fb;\\n                                            } else {\\n                                                return\\n                                                    0x4DD8Af2E3F2044842f0247920Bc4BABb636915ea;\\n                                            }\\n                                        }\\n                                    } else {\\n                                        if (routeId < 151) {\\n                                            if (routeId == 149) {\\n                                                return\\n                                                    0x8e8a327183Af0cf8C2ece9F0ed547C42A160D409;\\n                                            } else {\\n                                                return\\n                                                    0x9D49614CaE1C685C71678CA6d8CDF7584bfd0740;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 151) {\\n                                                return\\n                                                    0x5a00ef257394cbc31828d48655E3d39e9c11c93d;\\n                                            } else {\\n                                                return\\n                                                    0xC9a2751b38d3dDD161A41Ca0135C5C6c09EC1d56;\\n                                            }\\n                                        }\\n                                    }\\n                                } else {\\n                                    if (routeId < 157) {\\n                                        if (routeId < 155) {\\n                                            if (routeId == 153) {\\n                                                return\\n                                                    0x7e1c261640a525C94Ca4f8c25b48CF754DD83590;\\n                                            } else {\\n                                                return\\n                                                    0x409Fe24ba6F6BD5aF31C1aAf8059b986A3158233;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 155) {\\n                                                return\\n                                                    0x704Cf5BFDADc0f55fDBb53B6ed8B582E018A72A2;\\n                                            } else {\\n                                                return\\n                                                    0x3982bF65d7d6E77E3b6661cd6F6468c247512737;\\n                                            }\\n                                        }\\n                                    } else {\\n                                        if (routeId < 159) {\\n                                            if (routeId == 157) {\\n                                                return\\n                                                    0x3982b9f26FFD67a13Ee371e2C0a9Da338BA70E7f;\\n                                            } else {\\n                                                return\\n                                                    0x6D834AB385900c1f49055D098e90264077FbC4f2;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 159) {\\n                                                return\\n                                                    0x11FE5F70779A094B7166B391e1Fb73d422eF4e4d;\\n                                            } else {\\n                                                return\\n                                                    0xD347e4E47280d21F13B73D89c6d16f867D50DD13;\\n                                            }\\n                                        }\\n                                    }\\n                                }\\n                            }\\n                        } else {\\n                            if (routeId < 177) {\\n                                if (routeId < 169) {\\n                                    if (routeId < 165) {\\n                                        if (routeId < 163) {\\n                                            if (routeId == 161) {\\n                                                return\\n                                                    0xb6035eDD53DDA28d8B69b4ae9836E40C80306CD7;\\n                                            } else {\\n                                                return\\n                                                    0x54c884e6f5C7CcfeCA990396c520C858c922b6CA;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 163) {\\n                                                return\\n                                                    0x5eA93E240b083d686558Ed607BC013d88057cE46;\\n                                            } else {\\n                                                return\\n                                                    0x4C7131eE812De685cBe4e2cCb033d46ecD46612E;\\n                                            }\\n                                        }\\n                                    } else {\\n                                        if (routeId < 167) {\\n                                            if (routeId == 165) {\\n                                                return\\n                                                    0xc1a5Be9F0c33D8483801D702111068669f81fF91;\\n                                            } else {\\n                                                return\\n                                                    0x9E5fAb91455Be5E5b2C05967E73F456c8118B1Fc;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 167) {\\n                                                return\\n                                                    0x3d9A05927223E0DC2F382831770405885e22F0d8;\\n                                            } else {\\n                                                return\\n                                                    0x6303A011fB6063f5B1681cb5a9938EA278dc6128;\\n                                            }\\n                                        }\\n                                    }\\n                                } else {\\n                                    if (routeId < 173) {\\n                                        if (routeId < 171) {\\n                                            if (routeId == 169) {\\n                                                return\\n                                                    0xe9c60795c90C66797e4c8E97511eA07CdAda32bE;\\n                                            } else {\\n                                                return\\n                                                    0xD56cC98e69A1e13815818b466a8aA6163d84234A;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 171) {\\n                                                return\\n                                                    0x47EbB9D36a6e40895316cD894E4860D774E2c531;\\n                                            } else {\\n                                                return\\n                                                    0xA5EB293629410065d14a7B1663A67829b0618292;\\n                                            }\\n                                        }\\n                                    } else {\\n                                        if (routeId < 175) {\\n                                            if (routeId == 173) {\\n                                                return\\n                                                    0x1b3B4C8146F939cE00899db8B3ddeF0062b7E023;\\n                                            } else {\\n                                                return\\n                                                    0x257Bbc11653625EbfB6A8587eF4f4FBe49828EB3;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 175) {\\n                                                return\\n                                                    0x44cc979C01b5bB1eAC21301E73C37200dFD06F59;\\n                                            } else {\\n                                                return\\n                                                    0x2972fDF43352225D82754C0174Ff853819D1ef2A;\\n                                            }\\n                                        }\\n                                    }\\n                                }\\n                            } else {\\n                                if (routeId < 185) {\\n                                    if (routeId < 181) {\\n                                        if (routeId < 179) {\\n                                            if (routeId == 177) {\\n                                                return\\n                                                    0x3e54144f032648A04D62d79f7B4b93FF3aC2333b;\\n                                            } else {\\n                                                return\\n                                                    0x444016102dB8adbE73C3B6703a1ea7F2f75A510D;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 179) {\\n                                                return\\n                                                    0xac079143f98a6eb744Fde34541ebF243DF5B5dED;\\n                                            } else {\\n                                                return\\n                                                    0xAe9010767Fb112d29d35CEdfba2b372Ad7A308d3;\\n                                            }\\n                                        }\\n                                    } else {\\n                                        if (routeId < 183) {\\n                                            if (routeId == 181) {\\n                                                return\\n                                                    0xfE0BCcF9cCC2265D5fB3450743f17DfE57aE1e56;\\n                                            } else {\\n                                                return\\n                                                    0x04ED8C0545716119437a45386B1d691C63234C7D;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 183) {\\n                                                return\\n                                                    0x636c14013e531A286Bc4C848da34585f0bB73d59;\\n                                            } else {\\n                                                return\\n                                                    0x2Fa67fc7ECC5cAA01C653d3BFeA98ecc5db9C42A;\\n                                            }\\n                                        }\\n                                    }\\n                                } else {\\n                                    if (routeId < 189) {\\n                                        if (routeId < 187) {\\n                                            if (routeId == 185) {\\n                                                return\\n                                                    0x23e9a0FC180818aA872D2079a985217017E97bd9;\\n                                            } else {\\n                                                return\\n                                                    0x79A95c3Ef81b3ae64ee03A9D5f73e570495F164E;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 187) {\\n                                                return\\n                                                    0xa7EA0E88F04a84ba0ad1E396cb07Fa3fDAD7dF6D;\\n                                            } else {\\n                                                return\\n                                                    0xd23cA1278a2B01a3C0Ca1a00d104b11c1Ebe6f42;\\n                                            }\\n                                        }\\n                                    } else {\\n                                        if (routeId < 191) {\\n                                            if (routeId == 189) {\\n                                                return\\n                                                    0x707bc4a9FA2E349AED5df4e9f5440C15aA9D14Bd;\\n                                            } else {\\n                                                return\\n                                                    0x7E290F2dd539Ac6CE58d8B4C2B944931a1fD3612;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 191) {\\n                                                return\\n                                                    0x707AA5503088Ce06Ba450B6470A506122eA5c8eF;\\n                                            } else {\\n                                                return\\n                                                    0xFbB3f7BF680deeb149f4E7BC30eA3DDfa68F3C3f;\\n                                            }\\n                                        }\\n                                    }\\n                                }\\n                            }\\n                        }\\n                    } else {\\n                        if (routeId < 225) {\\n                            if (routeId < 209) {\\n                                if (routeId < 201) {\\n                                    if (routeId < 197) {\\n                                        if (routeId < 195) {\\n                                            if (routeId == 193) {\\n                                                return\\n                                                    0xDE74aD8cCC3dbF14992f49Cf24f36855912f4934;\\n                                            } else {\\n                                                return\\n                                                    0x409BA83df7777F070b2B50a10a41DE2468d2a3B3;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 195) {\\n                                                return\\n                                                    0x5CB7Be90A5DD7CfDa54e87626e254FE8C18255B4;\\n                                            } else {\\n                                                return\\n                                                    0x0A684fE12BC64fb72B59d0771a566F49BC090356;\\n                                            }\\n                                        }\\n                                    } else {\\n                                        if (routeId < 199) {\\n                                            if (routeId == 197) {\\n                                                return\\n                                                    0xDf30048d91F8FA2bCfC54952B92bFA8e161D3360;\\n                                            } else {\\n                                                return\\n                                                    0x050825Fff032a547C47061CF0696FDB0f65AEa5D;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 199) {\\n                                                return\\n                                                    0xd55e671dAC1f03d366d8535073ada5DB2Aab1Ea2;\\n                                            } else {\\n                                                return\\n                                                    0x9470C704A9616c8Cd41c595Fcd2181B6fe2183C2;\\n                                            }\\n                                        }\\n                                    }\\n                                } else {\\n                                    if (routeId < 205) {\\n                                        if (routeId < 203) {\\n                                            if (routeId == 201) {\\n                                                return\\n                                                    0x2D9ffD275181F5865d5e11CbB4ced1521C4dF9f1;\\n                                            } else {\\n                                                return\\n                                                    0x816d28Dec10ec95DF5334f884dE85cA6215918d8;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 203) {\\n                                                return\\n                                                    0xd1f87267c4A43835E666dd69Df077e578A3b6299;\\n                                            } else {\\n                                                return\\n                                                    0x39E89Bde9DACbe5468C025dE371FbDa12bDeBAB1;\\n                                            }\\n                                        }\\n                                    } else {\\n                                        if (routeId < 207) {\\n                                            if (routeId == 205) {\\n                                                return\\n                                                    0x7b40A3207956ecad6686E61EfcaC48912FcD0658;\\n                                            } else {\\n                                                return\\n                                                    0x090cF10D793B1Efba9c7D76115878814B663859A;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 207) {\\n                                                return\\n                                                    0x312A59c06E41327878F2063eD0e9c282C1DA3AfC;\\n                                            } else {\\n                                                return\\n                                                    0x4F1188f46236DD6B5de11Ebf2a9fF08716E7DeB6;\\n                                            }\\n                                        }\\n                                    }\\n                                }\\n                            } else {\\n                                if (routeId < 217) {\\n                                    if (routeId < 213) {\\n                                        if (routeId < 211) {\\n                                            if (routeId == 209) {\\n                                                return\\n                                                    0x0A6F9a3f4fA49909bBfb4339cbE12B42F53BbBeD;\\n                                            } else {\\n                                                return\\n                                                    0x01d13d7aCaCbB955B81935c80ffF31e14BdFa71f;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 211) {\\n                                                return\\n                                                    0x691a14Fa6C7360422EC56dF5876f84d4eDD7f00A;\\n                                            } else {\\n                                                return\\n                                                    0x97Aad18d886d181a9c726B3B6aE15a0A69F5aF73;\\n                                            }\\n                                        }\\n                                    } else {\\n                                        if (routeId < 215) {\\n                                            if (routeId == 213) {\\n                                                return\\n                                                    0x2917241371D2099049Fa29432DC46735baEC33b4;\\n                                            } else {\\n                                                return\\n                                                    0x5F20F20F7890c2e383E29D4147C9695A371165f5;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 215) {\\n                                                return\\n                                                    0xeC0a60e639958335662C5219A320cCEbb56C6077;\\n                                            } else {\\n                                                return\\n                                                    0x96d63CF5062975C09845d17ec672E10255866053;\\n                                            }\\n                                        }\\n                                    }\\n                                } else {\\n                                    if (routeId < 221) {\\n                                        if (routeId < 219) {\\n                                            if (routeId == 217) {\\n                                                return\\n                                                    0xFF57429e57D383939CAB50f09ABBfB63C0e6c9AD;\\n                                            } else {\\n                                                return\\n                                                    0x18E393A7c8578fb1e235C242076E50013cDdD0d7;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 219) {\\n                                                return\\n                                                    0xE7E5238AF5d61f52E9B4ACC025F713d1C0216507;\\n                                            } else {\\n                                                return\\n                                                    0x428401D4d0F25A2EE1DA4d5366cB96Ded425D9bD;\\n                                            }\\n                                        }\\n                                    } else {\\n                                        if (routeId < 223) {\\n                                            if (routeId == 221) {\\n                                                return\\n                                                    0x42E5733551ff1Ee5B48Aa9fc2B61Af9b58C812E6;\\n                                            } else {\\n                                                return\\n                                                    0x64Df9c7A0551B056d860Bc2419Ca4c1EF75320bE;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 223) {\\n                                                return\\n                                                    0x46006925506145611bBf0263243D8627dAf26B0F;\\n                                            } else {\\n                                                return\\n                                                    0x8D64BE884314662804eAaB884531f5C50F4d500c;\\n                                            }\\n                                        }\\n                                    }\\n                                }\\n                            }\\n                        } else {\\n                            if (routeId < 241) {\\n                                if (routeId < 233) {\\n                                    if (routeId < 229) {\\n                                        if (routeId < 227) {\\n                                            if (routeId == 225) {\\n                                                return\\n                                                    0x157a62D92D07B5ce221A5429645a03bBaCE85373;\\n                                            } else {\\n                                                return\\n                                                    0xaF037D33e1F1F2F87309B425fe8a9d895Ef3722B;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 227) {\\n                                                return\\n                                                    0x921D1154E494A2f7218a37ad7B17701f94b4B40e;\\n                                            } else {\\n                                                return\\n                                                    0xF282b4555186d8Dea51B8b3F947E1E0568d09bc4;\\n                                            }\\n                                        }\\n                                    } else {\\n                                        if (routeId < 231) {\\n                                            if (routeId == 229) {\\n                                                return\\n                                                    0xa794E2E1869765a4600b3DFd8a4ebcF16350f6B6;\\n                                            } else {\\n                                                return\\n                                                    0xFEFb048e20c5652F7940A49B1980E0125Ec4D358;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 231) {\\n                                                return\\n                                                    0x220104b641971e9b25612a8F001bf48AbB23f1cF;\\n                                            } else {\\n                                                return\\n                                                    0xcB9D373Bb54A501B35dd3be5bF4Ba43cA31F7035;\\n                                            }\\n                                        }\\n                                    }\\n                                } else {\\n                                    if (routeId < 237) {\\n                                        if (routeId < 235) {\\n                                            if (routeId == 233) {\\n                                                return\\n                                                    0x37D627F56e3FF36aC316372109ea82E03ac97DAc;\\n                                            } else {\\n                                                return\\n                                                    0x4E81355FfB4A271B4EA59ff78da2b61c7833161f;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 235) {\\n                                                return\\n                                                    0xADd8D65cAF6Cc9ad73127B49E16eA7ac29d91e87;\\n                                            } else {\\n                                                return\\n                                                    0x630F9b95626487dfEAe3C97A44DB6C59cF35d996;\\n                                            }\\n                                        }\\n                                    } else {\\n                                        if (routeId < 239) {\\n                                            if (routeId == 237) {\\n                                                return\\n                                                    0x78CE2BC8238B679680A67FCB98C5A60E4ec17b2D;\\n                                            } else {\\n                                                return\\n                                                    0xA38D776028eD1310b9A6b086f67F788201762E21;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 239) {\\n                                                return\\n                                                    0x7Bb5178827B76B86753Ed62a0d662c72cEcb1bD3;\\n                                            } else {\\n                                                return\\n                                                    0x4faC26f61C76eC5c3D43b43eDfAFF0736Ae0e3da;\\n                                            }\\n                                        }\\n                                    }\\n                                }\\n                            } else {\\n                                if (routeId < 249) {\\n                                    if (routeId < 245) {\\n                                        if (routeId < 243) {\\n                                            if (routeId == 241) {\\n                                                return\\n                                                    0x791Bb49bfFA7129D6889FDB27744422Ac4571A85;\\n                                            } else {\\n                                                return\\n                                                    0x26766fFEbb5fa564777913A6f101dF019AB32afa;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 243) {\\n                                                return\\n                                                    0x05e98E5e95b4ECBbbAf3258c3999Cc81ed8048Be;\\n                                            } else {\\n                                                return\\n                                                    0xC5c4621e52f1D6A1825A5ed4F95855401a3D9C6b;\\n                                            }\\n                                        }\\n                                    } else {\\n                                        if (routeId < 247) {\\n                                            if (routeId == 245) {\\n                                                return\\n                                                    0xfcb15f909BA7FC7Ea083503Fb4c1020203c107EB;\\n                                            } else {\\n                                                return\\n                                                    0xbD27603279d969c74f2486ad14E71080829DFd38;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 247) {\\n                                                return\\n                                                    0xff2f756BcEcC1A55BFc09a30cc5F64720458cFCB;\\n                                            } else {\\n                                                return\\n                                                    0x3bfB968FEbC12F4e8420B2d016EfcE1E615f7246;\\n                                            }\\n                                        }\\n                                    }\\n                                } else {\\n                                    if (routeId < 253) {\\n                                        if (routeId < 251) {\\n                                            if (routeId == 249) {\\n                                                return\\n                                                    0x982EE9Ffe23051A2ec945ed676D864fa8345222b;\\n                                            } else {\\n                                                return\\n                                                    0xe101899100785E74767d454FFF0131277BaD48d9;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 251) {\\n                                                return\\n                                                    0x4F730C0c6b3B5B7d06ca511379f4Aa5BfB2E9525;\\n                                            } else {\\n                                                return\\n                                                    0x5499c36b365795e4e0Ef671aF6C2ce26D7c78265;\\n                                            }\\n                                        }\\n                                    } else {\\n                                        if (routeId < 255) {\\n                                            if (routeId == 253) {\\n                                                return\\n                                                    0x8AF51F7237Fc8fB2fc3E700488a94a0aC6Ad8b5a;\\n                                            } else {\\n                                                return\\n                                                    0xda8716df61213c0b143F2849785FB85928084857;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 255) {\\n                                                return\\n                                                    0xF040Cf9b1ebD11Bf28e04e80740DF3DDe717e4f5;\\n                                            } else {\\n                                                return\\n                                                    0xB87ba32f759D14023C7520366B844dF7f0F036C2;\\n                                            }\\n                                        }\\n                                    }\\n                                }\\n                            }\\n                        }\\n                    }\\n                }\\n            } else {\\n                if (routeId < 321) {\\n                    if (routeId < 289) {\\n                        if (routeId < 273) {\\n                            if (routeId < 265) {\\n                                if (routeId < 261) {\\n                                    if (routeId < 259) {\\n                                        if (routeId == 257) {\\n                                            return\\n                                                0x0Edde681b8478F0c3194f468EdD2dB5e75c65CDD;\\n                                        } else {\\n                                            return\\n                                                0x59C70900Fca06eE2aCE1BDd5A8D0Af0cc3BBA720;\\n                                        }\\n                                    } else {\\n                                        if (routeId == 259) {\\n                                            return\\n                                                0x8041F0f180D17dD07087199632c45E17AeB0BAd5;\\n                                        } else {\\n                                            return\\n                                                0x4fB4727064BA595995DD516b63b5921Df9B93aC6;\\n                                        }\\n                                    }\\n                                } else {\\n                                    if (routeId < 263) {\\n                                        if (routeId == 261) {\\n                                            return\\n                                                0x86e98b594565857eD098864F560915C0dAfd6Ea1;\\n                                        } else {\\n                                            return\\n                                                0x70f8818E8B698EFfeCd86A513a4c87c0c380Bef6;\\n                                        }\\n                                    } else {\\n                                        if (routeId == 263) {\\n                                            return\\n                                                0x78Ed227c8A897A21Da2875a752142dd80d865158;\\n                                        } else {\\n                                            return\\n                                                0xd02A30BB5C3a8C51d2751A029a6fcfDE2Af9fbc6;\\n                                        }\\n                                    }\\n                                }\\n                            } else {\\n                                if (routeId < 269) {\\n                                    if (routeId < 267) {\\n                                        if (routeId == 265) {\\n                                            return\\n                                                0x0F00d5c5acb24e975e2a56730609f7F40aa763b8;\\n                                        } else {\\n                                            return\\n                                                0xC3e2091edc2D3D9D98ba09269138b617B536834A;\\n                                        }\\n                                    } else {\\n                                        if (routeId == 267) {\\n                                            return\\n                                                0xa6FbaF7F30867C9633908998ea8C3da28920E75C;\\n                                        } else {\\n                                            return\\n                                                0xE6dDdcD41E2bBe8122AE32Ac29B8fbAB79CD21d9;\\n                                        }\\n                                    }\\n                                } else {\\n                                    if (routeId < 271) {\\n                                        if (routeId == 269) {\\n                                            return\\n                                                0x537aa8c1Ef6a8Eaf039dd6e1Eb67694a48195cE4;\\n                                        } else {\\n                                            return\\n                                                0x96ABAC485fd2D0B03CF4a10df8BD58b8dED28300;\\n                                        }\\n                                    } else {\\n                                        if (routeId == 271) {\\n                                            return\\n                                                0xda8e7D46d04Bd4F62705Cd80355BDB6d441DafFD;\\n                                        } else {\\n                                            return\\n                                                0xbE50018E7a5c67E2e5f5414393e971CC96F293f2;\\n                                        }\\n                                    }\\n                                }\\n                            }\\n                        } else {\\n                            if (routeId < 281) {\\n                                if (routeId < 277) {\\n                                    if (routeId < 275) {\\n                                        if (routeId == 273) {\\n                                            return\\n                                                0xa1b3907D6CB542a4cbe2eE441EfFAA909FAb62C3;\\n                                        } else {\\n                                            return\\n                                                0x6d08ee8511C0237a515013aC389e7B3968Cb1753;\\n                                        }\\n                                    } else {\\n                                        if (routeId == 275) {\\n                                            return\\n                                                0x22faa5B5Fe43eAdbB52745e35a5cdA8bD5F96bbA;\\n                                        } else {\\n                                            return\\n                                                0x7a673eB74D79e4868D689E7852abB5f93Ec2fD4b;\\n                                        }\\n                                    }\\n                                } else {\\n                                    if (routeId < 279) {\\n                                        if (routeId == 277) {\\n                                            return\\n                                                0x0b8531F8AFD4190b76F3e10deCaDb84c98b4d419;\\n                                        } else {\\n                                            return\\n                                                0x78eABC743A93583DeE403D6b84795490e652216B;\\n                                        }\\n                                    } else {\\n                                        if (routeId == 279) {\\n                                            return\\n                                                0x3A95D907b2a7a8604B59BccA08585F58Afe0Aa64;\\n                                        } else {\\n                                            return\\n                                                0xf4271f0C8c9Af0F06A80b8832fa820ccE64FAda8;\\n                                        }\\n                                    }\\n                                }\\n                            } else {\\n                                if (routeId < 285) {\\n                                    if (routeId < 283) {\\n                                        if (routeId == 281) {\\n                                            return\\n                                                0x74b2DF841245C3748c0d31542e1335659a25C33b;\\n                                        } else {\\n                                            return\\n                                                0xdFC99Fd0Ad7D16f30f295a5EEFcE029E04d0fa65;\\n                                        }\\n                                    } else {\\n                                        if (routeId == 283) {\\n                                            return\\n                                                0xE992416b6aC1144eD8148a9632973257839027F6;\\n                                        } else {\\n                                            return\\n                                                0x54ce55ba954E981BB1fd9399054B35Ce1f2C0816;\\n                                        }\\n                                    }\\n                                } else {\\n                                    if (routeId < 287) {\\n                                        if (routeId == 285) {\\n                                            return\\n                                                0xD4AB52f9e7E5B315Bd7471920baD04F405Ab1c38;\\n                                        } else {\\n                                            return\\n                                                0x3670C990994d12837e95eE127fE2f06FD3E2104B;\\n                                        }\\n                                    } else {\\n                                        if (routeId == 287) {\\n                                            return\\n                                                0xDcf190B09C47E4f551E30BBb79969c3FdEA1e992;\\n                                        } else {\\n                                            return\\n                                                0xa65057B967B59677237e57Ab815B209744b9bc40;\\n                                        }\\n                                    }\\n                                }\\n                            }\\n                        }\\n                    } else {\\n                        if (routeId < 305) {\\n                            if (routeId < 297) {\\n                                if (routeId < 293) {\\n                                    if (routeId < 291) {\\n                                        if (routeId == 289) {\\n                                            return\\n                                                0x6Efc86B40573e4C7F28659B13327D55ae955C483;\\n                                        } else {\\n                                            return\\n                                                0x06BcC25CF8e0E72316F53631b3aA7134E9f73Ae0;\\n                                        }\\n                                    } else {\\n                                        if (routeId == 291) {\\n                                            return\\n                                                0x710b6414E1D53882b1FCD3A168aD5Ccd435fc6D0;\\n                                        } else {\\n                                            return\\n                                                0x5Ebb2C3d78c4e9818074559e7BaE7FCc99781DC1;\\n                                        }\\n                                    }\\n                                } else {\\n                                    if (routeId < 295) {\\n                                        if (routeId == 293) {\\n                                            return\\n                                                0xAf0a409c3AEe0bD08015cfb29D89E90b6e89A88F;\\n                                        } else {\\n                                            return\\n                                                0x522559d8b99773C693B80cE06DF559036295Ce44;\\n                                        }\\n                                    } else {\\n                                        if (routeId == 295) {\\n                                            return\\n                                                0xB65290A5Bae838aaa7825c9ECEC68041841a1B64;\\n                                        } else {\\n                                            return\\n                                                0x801b8F2068edd5Bcb659E6BDa0c425909043C420;\\n                                        }\\n                                    }\\n                                }\\n                            } else {\\n                                if (routeId < 301) {\\n                                    if (routeId < 299) {\\n                                        if (routeId == 297) {\\n                                            return\\n                                                0x29b5F00515d093627E0B7bd0b5c8E84F6b4cDb87;\\n                                        } else {\\n                                            return\\n                                                0x652839Ae74683cbF9f1293F1019D938F87464D3E;\\n                                        }\\n                                    } else {\\n                                        if (routeId == 299) {\\n                                            return\\n                                                0x5Bc95dCebDDE9B79F2b6DC76121BC7936eF8D666;\\n                                        } else {\\n                                            return\\n                                                0x90db359CEA62E53051158Ab5F99811C0a07Fe686;\\n                                        }\\n                                    }\\n                                } else {\\n                                    if (routeId < 303) {\\n                                        if (routeId == 301) {\\n                                            return\\n                                                0x2c3625EedadbDcDbB5330eb0d17b3C39ff269807;\\n                                        } else {\\n                                            return\\n                                                0xC3f0324471b5c9d415acD625b8d8694a4e48e001;\\n                                        }\\n                                    } else {\\n                                        if (routeId == 303) {\\n                                            return\\n                                                0x8C60e7E05fa0FfB6F720233736f245134685799d;\\n                                        } else {\\n                                            return\\n                                                0x98fAF2c09aa4EBb995ad0B56152993E7291a500e;\\n                                        }\\n                                    }\\n                                }\\n                            }\\n                        } else {\\n                            if (routeId < 313) {\\n                                if (routeId < 309) {\\n                                    if (routeId < 307) {\\n                                        if (routeId == 305) {\\n                                            return\\n                                                0x802c1063a861414dFAEc16bacb81429FC0d40D6e;\\n                                        } else {\\n                                            return\\n                                                0x11C4AeFCC0dC156f64195f6513CB1Fb3Be0Ae056;\\n                                        }\\n                                    } else {\\n                                        if (routeId == 307) {\\n                                            return\\n                                                0xEff1F3258214E31B6B4F640b4389d55715C3Be2B;\\n                                        } else {\\n                                            return\\n                                                0x47e379Abe8DDFEA4289aBa01235EFF7E93758fd7;\\n                                        }\\n                                    }\\n                                } else {\\n                                    if (routeId < 311) {\\n                                        if (routeId == 309) {\\n                                            return\\n                                                0x3CC26384c3eA31dDc8D9789e8872CeA6F20cD3ff;\\n                                        } else {\\n                                            return\\n                                                0xEdd9EFa6c69108FAA4611097d643E20Ba0Ed1634;\\n                                        }\\n                                    } else {\\n                                        if (routeId == 311) {\\n                                            return\\n                                                0xCb93525CA5f3D371F74F3D112bC19526740717B8;\\n                                        } else {\\n                                            return\\n                                                0x7071E0124EB4438137e60dF1b8DD8Af1BfB362cF;\\n                                        }\\n                                    }\\n                                }\\n                            } else {\\n                                if (routeId < 317) {\\n                                    if (routeId < 315) {\\n                                        if (routeId == 313) {\\n                                            return\\n                                                0x4691096EB0b78C8F4b4A8091E5B66b18e1835c10;\\n                                        } else {\\n                                            return\\n                                                0x8d953c9b2d1C2137CF95992079f3A77fCd793272;\\n                                        }\\n                                    } else {\\n                                        if (routeId == 315) {\\n                                            return\\n                                                0xbdCc2A3Bf6e3Ba49ff86595e6b2b8D70d8368c92;\\n                                        } else {\\n                                            return\\n                                                0x95E6948aB38c61b2D294E8Bd896BCc4cCC0713cf;\\n                                        }\\n                                    }\\n                                } else {\\n                                    if (routeId < 319) {\\n                                        if (routeId == 317) {\\n                                            return\\n                                                0x607b27C881fFEE4Cb95B1c5862FaE7224ccd0b4A;\\n                                        } else {\\n                                            return\\n                                                0x09D28aFA166e566A2Ee1cB834ea8e78C7E627eD2;\\n                                        }\\n                                    } else {\\n                                        if (routeId == 319) {\\n                                            return\\n                                                0x9c01449b38bDF0B263818401044Fb1401B29fDfA;\\n                                        } else {\\n                                            return\\n                                                0x1F7723599bbB658c051F8A39bE2688388d22ceD6;\\n                                        }\\n                                    }\\n                                }\\n                            }\\n                        }\\n                    }\\n                } else {\\n                    if (routeId < 353) {\\n                        if (routeId < 337) {\\n                            if (routeId < 329) {\\n                                if (routeId < 325) {\\n                                    if (routeId < 323) {\\n                                        if (routeId == 321) {\\n                                            return\\n                                                0x52B71603f7b8A5d15B4482e965a0619aa3210194;\\n                                        } else {\\n                                            return\\n                                                0x01c0f072CB210406653752FecFA70B42dA9173a2;\\n                                        }\\n                                    } else {\\n                                        if (routeId == 323) {\\n                                            return\\n                                                0x3021142f021E943e57fc1886cAF58D06147D09A6;\\n                                        } else {\\n                                            return\\n                                                0xe6f2AF38e76AB09Db59225d97d3E770942D3D842;\\n                                        }\\n                                    }\\n                                } else {\\n                                    if (routeId < 327) {\\n                                        if (routeId == 325) {\\n                                            return\\n                                                0x06a25554e5135F08b9e2eD1DEC1fc3CEd52e0B48;\\n                                        } else {\\n                                            return\\n                                                0x71d75e670EE3511C8290C705E0620126B710BF8D;\\n                                        }\\n                                    } else {\\n                                        if (routeId == 327) {\\n                                            return\\n                                                0x8b9cE142b80FeA7c932952EC533694b1DF9B3c54;\\n                                        } else {\\n                                            return\\n                                                0xd7Be24f32f39231116B3fDc483C2A12E1521f73B;\\n                                        }\\n                                    }\\n                                }\\n                            } else {\\n                                if (routeId < 333) {\\n                                    if (routeId < 331) {\\n                                        if (routeId == 329) {\\n                                            return\\n                                                0xb40cafBC4797d4Ff64087E087F6D2e661f954CbE;\\n                                        } else {\\n                                            return\\n                                                0xBdDCe7771EfEe81893e838f62204A4c76D72757e;\\n                                        }\\n                                    } else {\\n                                        if (routeId == 331) {\\n                                            return\\n                                                0x5d3D299EA7Fd4F39AcDb336E26631Dfee41F9287;\\n                                        } else {\\n                                            return\\n                                                0x6BfEE09E1Fc0684e0826A9A0dC1352a14B136FAC;\\n                                        }\\n                                    }\\n                                } else {\\n                                    if (routeId < 335) {\\n                                        if (routeId == 333) {\\n                                            return\\n                                                0xd0001bB8E2Cb661436093f96458a4358B5156E3c;\\n                                        } else {\\n                                            return\\n                                                0x1867c6485CfD1eD448988368A22bfB17a7747293;\\n                                        }\\n                                    } else {\\n                                        if (routeId == 335) {\\n                                            return\\n                                                0x8997EF9F95dF24aB67703AB6C262aABfeEBE33bD;\\n                                        } else {\\n                                            return\\n                                                0x1e39E9E601922deD91BCFc8F78836302133465e2;\\n                                        }\\n                                    }\\n                                }\\n                            }\\n                        } else {\\n                            if (routeId < 345) {\\n                                if (routeId < 341) {\\n                                    if (routeId < 339) {\\n                                        if (routeId == 337) {\\n                                            return\\n                                                0x8A8ec6CeacFf502a782216774E5AF3421562C6ff;\\n                                        } else {\\n                                            return\\n                                                0x3B8FC561df5415c8DC01e97Ee6E38435A8F9C40A;\\n                                        }\\n                                    } else {\\n                                        if (routeId == 339) {\\n                                            return\\n                                                0xD5d5f5B37E67c43ceA663aEDADFFc3a93a2065B0;\\n                                        } else {\\n                                            return\\n                                                0xCC8F55EC43B4f25013CE1946FBB740c43Be5B96D;\\n                                        }\\n                                    }\\n                                } else {\\n                                    if (routeId < 343) {\\n                                        if (routeId == 341) {\\n                                            return\\n                                                0x18f586E816eEeDbb57B8011239150367561B58Fb;\\n                                        } else {\\n                                            return\\n                                                0xd0CD802B19c1a52501cb2f07d656e3Cd7B0Ce124;\\n                                        }\\n                                    } else {\\n                                        if (routeId == 343) {\\n                                            return\\n                                                0xe0AeD899b39C6e4f2d83e4913a1e9e0cf6368abE;\\n                                        } else {\\n                                            return\\n                                                0x0606e1b6c0f1A398C38825DCcc4678a7Cbc2737c;\\n                                        }\\n                                    }\\n                                }\\n                            } else {\\n                                if (routeId < 349) {\\n                                    if (routeId < 347) {\\n                                        if (routeId == 345) {\\n                                            return\\n                                                0x2d188e85b27d18EF80f16686EA1593ABF7Ed2A63;\\n                                        } else {\\n                                            return\\n                                                0x64412292fA4A135a3300E24366E99ff59Db2eAc1;\\n                                        }\\n                                    } else {\\n                                        if (routeId == 347) {\\n                                            return\\n                                                0x38b74c173f3733E8b90aAEf0e98B89791266149F;\\n                                        } else {\\n                                            return\\n                                                0x36DAA49A79aaEF4E7a217A11530D3cCD84414124;\\n                                        }\\n                                    }\\n                                } else {\\n                                    if (routeId < 351) {\\n                                        if (routeId == 349) {\\n                                            return\\n                                                0x10f088FE2C88F90270E4449c46c8B1b232511d58;\\n                                        } else {\\n                                            return\\n                                                0x4FeDbd25B58586838ABD17D10272697dF1dC3087;\\n                                        }\\n                                    } else {\\n                                        if (routeId == 351) {\\n                                            return\\n                                                0x685278209248CB058E5cEe93e37f274A80Faf6eb;\\n                                        } else {\\n                                            return\\n                                                0xDd9F8F1eeC3955f78168e2Fb2d1e808fa8A8f15b;\\n                                        }\\n                                    }\\n                                }\\n                            }\\n                        }\\n                    } else {\\n                        if (routeId < 369) {\\n                            if (routeId < 361) {\\n                                if (routeId < 357) {\\n                                    if (routeId < 355) {\\n                                        if (routeId == 353) {\\n                                            return\\n                                                0x7392aEeFD5825aaC28817031dEEBbFaAA20983D9;\\n                                        } else {\\n                                            return\\n                                                0x0Cc182555E00767D6FB8AD161A10d0C04C476d91;\\n                                        }\\n                                    } else {\\n                                        if (routeId == 355) {\\n                                            return\\n                                                0x90E52837d56715c79FD592E8D58bFD20365798b2;\\n                                        } else {\\n                                            return\\n                                                0x6F4451DE14049B6770ad5BF4013118529e68A40C;\\n                                        }\\n                                    }\\n                                } else {\\n                                    if (routeId < 359) {\\n                                        if (routeId == 357) {\\n                                            return\\n                                                0x89B97ef2aFAb9ed9c7f0FDb095d02E6840b52d9c;\\n                                        } else {\\n                                            return\\n                                                0x92A5cC5C42d94d3e23aeB1214fFf43Db2B97759E;\\n                                        }\\n                                    } else {\\n                                        if (routeId == 359) {\\n                                            return\\n                                                0x63ddc52F135A1dcBA831EAaC11C63849F018b739;\\n                                        } else {\\n                                            return\\n                                                0x692A691533B571C2c54C1D7F8043A204b3d8120E;\\n                                        }\\n                                    }\\n                                }\\n                            } else {\\n                                if (routeId < 365) {\\n                                    if (routeId < 363) {\\n                                        if (routeId == 361) {\\n                                            return\\n                                                0x97c7492CF083969F61C6f302d45c8270391b921c;\\n                                        } else {\\n                                            return\\n                                                0xDeFD2B8643553dAd19548eB14fd94A57F4B9e543;\\n                                        }\\n                                    } else {\\n                                        if (routeId == 363) {\\n                                            return\\n                                                0x30645C04205cA3f670B67b02F971B088930ACB8C;\\n                                        } else {\\n                                            return\\n                                                0xA6f80ed2d607Cd67aEB4109B64A0BEcc4D7d03CF;\\n                                        }\\n                                    }\\n                                } else {\\n                                    if (routeId < 367) {\\n                                        if (routeId == 365) {\\n                                            return\\n                                                0xBbbbC6c276eB3F7E674f2D39301509236001c42f;\\n                                        } else {\\n                                            return\\n                                                0xC20E77d349FB40CE88eB01824e2873ad9f681f3C;\\n                                        }\\n                                    } else {\\n                                        if (routeId == 367) {\\n                                            return\\n                                                0x5fCfD9a962De19294467C358C1FA55082285960b;\\n                                        } else {\\n                                            return\\n                                                0x4D87BD6a0E4E5cc6332923cb3E85fC71b287F58A;\\n                                        }\\n                                    }\\n                                }\\n                            }\\n                        } else {\\n                            if (routeId < 377) {\\n                                if (routeId < 373) {\\n                                    if (routeId < 371) {\\n                                        if (routeId == 369) {\\n                                            return\\n                                                0x3AA5B757cd6Dde98214E56D57Dde7fcF0F7aB04E;\\n                                        } else {\\n                                            return\\n                                                0xe28eFCE7192e11a2297f44059113C1fD6967b2d4;\\n                                        }\\n                                    } else {\\n                                        if (routeId == 371) {\\n                                            return\\n                                                0x3251cAE10a1Cf246e0808D76ACC26F7B5edA0eE5;\\n                                        } else {\\n                                            return\\n                                                0xbA2091cc9357Cf4c4F25D64F30d1b4Ba3A5a174B;\\n                                        }\\n                                    }\\n                                } else {\\n                                    if (routeId < 375) {\\n                                        if (routeId == 373) {\\n                                            return\\n                                                0x49c8e1Da9693692096F63C82D11b52d738566d55;\\n                                        } else {\\n                                            return\\n                                                0xA0731615aB5FFF451031E9551367A4F7dB27b39c;\\n                                        }\\n                                    } else {\\n                                        if (routeId == 375) {\\n                                            return\\n                                                0xFb214541888671AE1403CecC1D59763a12fc1609;\\n                                        } else {\\n                                            return\\n                                                0x1D6bCB17642E2336405df73dF22F07688cAec020;\\n                                        }\\n                                    }\\n                                }\\n                            } else {\\n                                if (routeId < 381) {\\n                                    if (routeId < 379) {\\n                                        if (routeId == 377) {\\n                                            return\\n                                                0xfC9c0C7bfe187120fF7f4E21446161794A617a9e;\\n                                        } else {\\n                                            return\\n                                                0xBa5bF37678EeE2dAB17AEf9D898153258252250E;\\n                                        }\\n                                    } else {\\n                                        if (routeId == 379) {\\n                                            return\\n                                                0x7c55690bd2C9961576A32c02f8EB29ed36415Ec7;\\n                                        } else {\\n                                            return\\n                                                0xcA40073E868E8Bc611aEc8Fe741D17E68Fe422f6;\\n                                        }\\n                                    }\\n                                } else {\\n                                    if (routeId < 383) {\\n                                        if (routeId == 381) {\\n                                            return\\n                                                0x31641bAFb87E9A58f78835050a7BE56921986339;\\n                                        } else {\\n                                            return\\n                                                0xA54766424f6dA74b45EbCc5Bf0Bd1D74D2CCcaAB;\\n                                        }\\n                                    } else {\\n                                        if (routeId == 383) {\\n                                            return\\n                                                0xc7bBa57F8C179EDDBaa62117ddA360e28f3F8252;\\n                                        } else {\\n                                            return\\n                                                0x5e663ED97ea77d393B8858C90d0683bF180E0ffd;\\n                                        }\\n                                    }\\n                                }\\n                            }\\n                        }\\n                    }\\n                }\\n            }\\n        }\\n\\n        if (routes[routeId] == address(0)) revert ZeroAddressNotAllowed();\\n        return routes[routeId];\\n    }\\n\\n    /// @notice fallback function to handle swap, bridge execution\\n    /// @dev ensure routeId is converted to bytes4 and sent as msg.sig in the transaction\\n    fallback() external payable {\\n        address routeAddress = addressAt(uint32(msg.sig));\\n\\n        bytes memory result;\\n\\n        assembly {\\n            // copy function selector and any arguments\\n            calldatacopy(0, 4, sub(calldatasize(), 4))\\n            // execute function call using the facet\\n            result := delegatecall(\\n                gas(),\\n                routeAddress,\\n                0,\\n                sub(calldatasize(), 4),\\n                0,\\n                0\\n            )\\n            // get any return value\\n            returndatacopy(0, 0, returndatasize())\\n            // return any return value or error back to the caller\\n            switch result\\n            case 0 {\\n                revert(0, returndatasize())\\n            }\\n            default {\\n                return(0, returndatasize())\\n            }\\n        }\\n    }\\n}\\n\"},\"src/bridges/hop/interfaces/IHopL1Bridge.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.4;\\n\\n/**\\n * @title L1Bridge Hop Interface\\n * @notice L1 Hop Bridge, Used to transfer from L1 to L2s.\\n */\\ninterface IHopL1Bridge {\\n    /**\\n     * @notice `amountOutMin` and `deadline` should be 0 when no swap is intended at the destination.\\n     * @notice `amount` is the total amount the user wants to send including the relayer fee\\n     * @dev Send tokens to a supported layer-2 to mint hToken and optionally swap the hToken in the\\n     * AMM at the destination.\\n     * @param chainId The chainId of the destination chain\\n     * @param recipient The address receiving funds at the destination\\n     * @param amount The amount being sent\\n     * @param amountOutMin The minimum amount received after attempting to swap in the destination\\n     * AMM market. 0 if no swap is intended.\\n     * @param deadline The deadline for swapping in the destination AMM market. 0 if no\\n     * swap is intended.\\n     * @param relayer The address of the relayer at the destination.\\n     * @param relayerFee The amount distributed to the relayer at the destination. This is subtracted from the `amount`.\\n     */\\n    function sendToL2(\\n        uint256 chainId,\\n        address recipient,\\n        uint256 amount,\\n        uint256 amountOutMin,\\n        uint256 deadline,\\n        address relayer,\\n        uint256 relayerFee\\n    ) external payable;\\n}\\n\"},\"src/bridges/refuel/interfaces/refuel.sol\":{\"content\":\"// SPDX-License-Identifier: Apache-2.0\\npragma solidity >=0.8.0;\\n\\n/// @notice interface with functions to interact with Refuel contract\\ninterface IRefuel {\\n    /**\\n     * @notice function to deposit nativeToken to Destination-address on destinationChain\\n     * @param destinationChainId chainId of the Destination chain\\n     * @param _to recipient address\\n     */\\n    function depositNativeToken(\\n        uint256 destinationChainId,\\n        address _to\\n    ) external payable;\\n}\\n\"},\"src/bridges/stargate/interfaces/stargate.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\n\\npragma solidity >=0.8.0;\\n\\n/**\\n * @title IBridgeStargate Interface Contract.\\n * @notice Interface used by Stargate-L1 and L2 Router implementations\\n * @dev router and routerETH addresses will be distinct for L1 and L2\\n */\\ninterface IBridgeStargate {\\n    // @notice Struct to hold the additional-data for bridging ERC20 token\\n    struct lzTxObj {\\n        // gas limit to bridge the token in Stargate to destinationChain\\n        uint256 dstGasForCall;\\n        // destination nativeAmount, this is always set as 0\\n        uint256 dstNativeAmount;\\n        // destination nativeAddress, this is always set as 0x\\n        bytes dstNativeAddr;\\n    }\\n\\n    /// @notice function in stargate bridge which is used to bridge ERC20 tokens to recipient on destinationChain\\n    function swap(\\n        uint16 _dstChainId,\\n        uint256 _srcPoolId,\\n        uint256 _dstPoolId,\\n        address payable _refundAddress,\\n        uint256 _amountLD,\\n        uint256 _minAmountLD,\\n        lzTxObj memory _lzTxParams,\\n        bytes calldata _to,\\n        bytes calldata _payload\\n    ) external payable;\\n\\n    /// @notice function in stargate bridge which is used to bridge native tokens to recipient on destinationChain\\n    function swapETH(\\n        uint16 _dstChainId, // destination Stargate chainId\\n        address payable _refundAddress, // refund additional messageFee to this address\\n        bytes calldata _toAddress, // the receiver of the destination ETH\\n        uint256 _amountLD, // the amount, in Local Decimals, to be swapped\\n        uint256 _minAmountLD // the minimum amount accepted out on destination\\n    ) external payable;\\n}\\n\"},\"src/controllers/FeesTakerController.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.4;\\n\\nimport {SafeTransferLib} from \\\"lib/solmate/src/utils/SafeTransferLib.sol\\\";\\nimport {ERC20} from \\\"lib/solmate/src/tokens/ERC20.sol\\\";\\nimport {BaseController} from \\\"./BaseController.sol\\\";\\nimport {ISocketRequest} from \\\"../interfaces/ISocketRequest.sol\\\";\\n\\n/**\\n * @title FeesTaker-Controller Implementation\\n * @notice Controller with composed actions to deduct-fees followed by Refuel, Swap and Bridge\\n *          to be executed Sequentially and this is atomic\\n * @author Socket dot tech.\\n */\\ncontract FeesTakerController is BaseController {\\n    using SafeTransferLib for ERC20;\\n\\n    /// @notice event emitted upon fee-deduction to fees-taker address\\n    event SocketFeesDeducted(\\n        uint256 fees,\\n        address feesToken,\\n        address feesTaker\\n    );\\n\\n    /// @notice Function-selector to invoke deduct-fees and swap token\\n    /// @dev This function selector is to be used while building transaction-data\\n    bytes4 public immutable FEES_TAKER_SWAP_FUNCTION_SELECTOR =\\n        bytes4(\\n            keccak256(\\\"takeFeesAndSwap((address,address,uint256,uint32,bytes))\\\")\\n        );\\n\\n    /// @notice Function-selector to invoke deduct-fees and bridge token\\n    /// @dev This function selector is to be used while building transaction-data\\n    bytes4 public immutable FEES_TAKER_BRIDGE_FUNCTION_SELECTOR =\\n        bytes4(\\n            keccak256(\\n                \\\"takeFeesAndBridge((address,address,uint256,uint32,bytes))\\\"\\n            )\\n        );\\n\\n    /// @notice Function-selector to invoke deduct-fees and bridge multiple tokens\\n    /// @dev This function selector is to be used while building transaction-data\\n    bytes4 public immutable FEES_TAKER_MULTI_BRIDGE_FUNCTION_SELECTOR =\\n        bytes4(\\n            keccak256(\\n                \\\"takeFeesAndMultiBridge((address,address,uint256,uint32[],bytes[]))\\\"\\n            )\\n        );\\n\\n    /// @notice Function-selector to invoke deduct-fees followed by swapping of a token and bridging the swapped bridge\\n    /// @dev This function selector is to be used while building transaction-data\\n    bytes4 public immutable FEES_TAKER_SWAP_BRIDGE_FUNCTION_SELECTOR =\\n        bytes4(\\n            keccak256(\\n                \\\"takeFeeAndSwapAndBridge((address,address,uint256,uint32,bytes,uint32,bytes))\\\"\\n            )\\n        );\\n\\n    /// @notice Function-selector to invoke deduct-fees refuel\\n    /// @notice followed by swapping of a token and bridging the swapped bridge\\n    /// @dev This function selector is to be used while building transaction-data\\n    bytes4 public immutable FEES_TAKER_REFUEL_SWAP_BRIDGE_FUNCTION_SELECTOR =\\n        bytes4(\\n            keccak256(\\n                \\\"takeFeeAndRefuelAndSwapAndBridge((address,address,uint256,uint32,bytes,uint32,bytes,uint32,bytes))\\\"\\n            )\\n        );\\n\\n    /// @notice socketGatewayAddress to be initialised via storage variable BaseController\\n    constructor(\\n        address _socketGatewayAddress\\n    ) BaseController(_socketGatewayAddress) {}\\n\\n    /**\\n     * @notice function to deduct-fees to fees-taker address on source-chain and swap token\\n     * @dev ensure correct function selector is used to generate transaction-data for bridgeRequest\\n     * @param ftsRequest feesTakerSwapRequest object generated either off-chain or the calling contract using\\n     *                   the function-selector FEES_TAKER_SWAP_FUNCTION_SELECTOR\\n     * @return output bytes from the swap operation (last operation in the composed actions)\\n     */\\n    function takeFeesAndSwap(\\n        ISocketRequest.FeesTakerSwapRequest calldata ftsRequest\\n    ) external payable returns (bytes memory) {\\n        if (ftsRequest.feesToken == NATIVE_TOKEN_ADDRESS) {\\n            //transfer the native amount to the feeTakerAddress\\n            payable(ftsRequest.feesTakerAddress).transfer(\\n                ftsRequest.feesAmount\\n            );\\n        } else {\\n            //transfer feesAmount to feesTakerAddress\\n            ERC20(ftsRequest.feesToken).safeTransferFrom(\\n                msg.sender,\\n                ftsRequest.feesTakerAddress,\\n                ftsRequest.feesAmount\\n            );\\n        }\\n\\n        emit SocketFeesDeducted(\\n            ftsRequest.feesAmount,\\n            ftsRequest.feesTakerAddress,\\n            ftsRequest.feesToken\\n        );\\n\\n        //call bridge function (executeRoute for the swapRequestData)\\n        return _executeRoute(ftsRequest.routeId, ftsRequest.swapRequestData);\\n    }\\n\\n    /**\\n     * @notice function to deduct-fees to fees-taker address on source-chain and bridge amount to destinationChain\\n     * @dev ensure correct function selector is used to generate transaction-data for bridgeRequest\\n     * @param ftbRequest feesTakerBridgeRequest object generated either off-chain or the calling contract using\\n     *                   the function-selector FEES_TAKER_BRIDGE_FUNCTION_SELECTOR\\n     * @return output bytes from the bridge operation (last operation in the composed actions)\\n     */\\n    function takeFeesAndBridge(\\n        ISocketRequest.FeesTakerBridgeRequest calldata ftbRequest\\n    ) external payable returns (bytes memory) {\\n        if (ftbRequest.feesToken == NATIVE_TOKEN_ADDRESS) {\\n            //transfer the native amount to the feeTakerAddress\\n            payable(ftbRequest.feesTakerAddress).transfer(\\n                ftbRequest.feesAmount\\n            );\\n        } else {\\n            //transfer feesAmount to feesTakerAddress\\n            ERC20(ftbRequest.feesToken).safeTransferFrom(\\n                msg.sender,\\n                ftbRequest.feesTakerAddress,\\n                ftbRequest.feesAmount\\n            );\\n        }\\n\\n        emit SocketFeesDeducted(\\n            ftbRequest.feesAmount,\\n            ftbRequest.feesTakerAddress,\\n            ftbRequest.feesToken\\n        );\\n\\n        //call bridge function (executeRoute for the bridgeData)\\n        return _executeRoute(ftbRequest.routeId, ftbRequest.bridgeRequestData);\\n    }\\n\\n    /**\\n     * @notice function to deduct-fees to fees-taker address on source-chain and bridge amount to destinationChain\\n     * @notice multiple bridge-requests are to be generated and sequence and number of routeIds should match with the bridgeData array\\n     * @dev ensure correct function selector is used to generate transaction-data for bridgeRequest\\n     * @param ftmbRequest feesTakerMultiBridgeRequest object generated either off-chain or the calling contract using\\n     *                   the function-selector FEES_TAKER_MULTI_BRIDGE_FUNCTION_SELECTOR\\n     */\\n    function takeFeesAndMultiBridge(\\n        ISocketRequest.FeesTakerMultiBridgeRequest calldata ftmbRequest\\n    ) external payable {\\n        if (ftmbRequest.feesToken == NATIVE_TOKEN_ADDRESS) {\\n            //transfer the native amount to the feeTakerAddress\\n            payable(ftmbRequest.feesTakerAddress).transfer(\\n                ftmbRequest.feesAmount\\n            );\\n        } else {\\n            //transfer feesAmount to feesTakerAddress\\n            ERC20(ftmbRequest.feesToken).safeTransferFrom(\\n                msg.sender,\\n                ftmbRequest.feesTakerAddress,\\n                ftmbRequest.feesAmount\\n            );\\n        }\\n\\n        emit SocketFeesDeducted(\\n            ftmbRequest.feesAmount,\\n            ftmbRequest.feesTakerAddress,\\n            ftmbRequest.feesToken\\n        );\\n\\n        // multiple bridge-requests are to be generated and sequence and number of routeIds should match with the bridgeData array\\n        for (\\n            uint256 index = 0;\\n            index < ftmbRequest.bridgeRouteIds.length;\\n            ++index\\n        ) {\\n            //call bridge function (executeRoute for the bridgeData)\\n            _executeRoute(\\n                ftmbRequest.bridgeRouteIds[index],\\n                ftmbRequest.bridgeRequestDataItems[index]\\n            );\\n        }\\n    }\\n\\n    /**\\n     * @notice function to deduct-fees to fees-taker address on source-chain followed by swap the amount on sourceChain followed by\\n     *         bridging the swapped amount to destinationChain\\n     * @dev while generating implData for swap and bridgeRequests, ensure correct function selector is used\\n     *      bridge action corresponds to the bridgeAfterSwap function of the bridgeImplementation\\n     * @param fsbRequest feesTakerSwapBridgeRequest object generated either off-chain or the calling contract using\\n     *                   the function-selector FEES_TAKER_SWAP_BRIDGE_FUNCTION_SELECTOR\\n     */\\n    function takeFeeAndSwapAndBridge(\\n        ISocketRequest.FeesTakerSwapBridgeRequest calldata fsbRequest\\n    ) external payable returns (bytes memory) {\\n        if (fsbRequest.feesToken == NATIVE_TOKEN_ADDRESS) {\\n            //transfer the native amount to the feeTakerAddress\\n            payable(fsbRequest.feesTakerAddress).transfer(\\n                fsbRequest.feesAmount\\n            );\\n        } else {\\n            //transfer feesAmount to feesTakerAddress\\n            ERC20(fsbRequest.feesToken).safeTransferFrom(\\n                msg.sender,\\n                fsbRequest.feesTakerAddress,\\n                fsbRequest.feesAmount\\n            );\\n        }\\n\\n        emit SocketFeesDeducted(\\n            fsbRequest.feesAmount,\\n            fsbRequest.feesTakerAddress,\\n            fsbRequest.feesToken\\n        );\\n\\n        // execute swap operation\\n        bytes memory swapResponseData = _executeRoute(\\n            fsbRequest.swapRouteId,\\n            fsbRequest.swapData\\n        );\\n\\n        uint256 swapAmount = abi.decode(swapResponseData, (uint256));\\n\\n        // swapped amount is to be bridged to the recipient on destinationChain\\n        bytes memory bridgeImpldata = abi.encodeWithSelector(\\n            BRIDGE_AFTER_SWAP_SELECTOR,\\n            swapAmount,\\n            fsbRequest.bridgeData\\n        );\\n\\n        // execute bridge operation and return the byte-data from response of bridge operation\\n        return _executeRoute(fsbRequest.bridgeRouteId, bridgeImpldata);\\n    }\\n\\n    /**\\n     * @notice function to deduct-fees to fees-taker address on source-chain followed by refuel followed by\\n     *          swap the amount on sourceChain followed by bridging the swapped amount to destinationChain\\n     * @dev while generating implData for refuel, swap and bridge Requests, ensure correct function selector is used\\n     *      bridge action corresponds to the bridgeAfterSwap function of the bridgeImplementation\\n     * @param frsbRequest feesTakerRefuelSwapBridgeRequest object generated either off-chain or the calling contract using\\n     *                   the function-selector FEES_TAKER_REFUEL_SWAP_BRIDGE_FUNCTION_SELECTOR\\n     */\\n    function takeFeeAndRefuelAndSwapAndBridge(\\n        ISocketRequest.FeesTakerRefuelSwapBridgeRequest calldata frsbRequest\\n    ) external payable returns (bytes memory) {\\n        if (frsbRequest.feesToken == NATIVE_TOKEN_ADDRESS) {\\n            //transfer the native amount to the feeTakerAddress\\n            payable(frsbRequest.feesTakerAddress).transfer(\\n                frsbRequest.feesAmount\\n            );\\n        } else {\\n            //transfer feesAmount to feesTakerAddress\\n            ERC20(frsbRequest.feesToken).safeTransferFrom(\\n                msg.sender,\\n                frsbRequest.feesTakerAddress,\\n                frsbRequest.feesAmount\\n            );\\n        }\\n\\n        emit SocketFeesDeducted(\\n            frsbRequest.feesAmount,\\n            frsbRequest.feesTakerAddress,\\n            frsbRequest.feesToken\\n        );\\n\\n        // refuel is also done via bridge execution via refuelRouteImplementation identified by refuelRouteId\\n        _executeRoute(frsbRequest.refuelRouteId, frsbRequest.refuelData);\\n\\n        // execute swap operation\\n        bytes memory swapResponseData = _executeRoute(\\n            frsbRequest.swapRouteId,\\n            frsbRequest.swapData\\n        );\\n\\n        uint256 swapAmount = abi.decode(swapResponseData, (uint256));\\n\\n        // swapped amount is to be bridged to the recipient on destinationChain\\n        bytes memory bridgeImpldata = abi.encodeWithSelector(\\n            BRIDGE_AFTER_SWAP_SELECTOR,\\n            swapAmount,\\n            frsbRequest.bridgeData\\n        );\\n\\n        // execute bridge operation and return the byte-data from response of bridge operation\\n        return _executeRoute(frsbRequest.bridgeRouteId, bridgeImpldata);\\n    }\\n}\\n\"},\"src/errors/SocketErrors.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.4;\\n\\nerror CelerRefundNotReady();\\nerror OnlySocketDeployer();\\nerror OnlySocketGatewayOwner();\\nerror OnlySocketGateway();\\nerror OnlyOwner();\\nerror OnlyNominee();\\nerror TransferIdExists();\\nerror TransferIdDoesnotExist();\\nerror Address0Provided();\\nerror SwapFailed();\\nerror UnsupportedInterfaceId();\\nerror InvalidCelerRefund();\\nerror CelerAlreadyRefunded();\\nerror IncorrectBridgeRatios();\\nerror ZeroAddressNotAllowed();\\nerror ArrayLengthMismatch();\\n\"},\"src/bridges/hop/l1/HopImplL1.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >=0.8.0;\\n\\nimport \\\"../interfaces/IHopL1Bridge.sol\\\";\\nimport {SafeTransferLib} from \\\"lib/solmate/src/utils/SafeTransferLib.sol\\\";\\nimport {ERC20} from \\\"lib/solmate/src/tokens/ERC20.sol\\\";\\nimport {BridgeImplBase} from \\\"../../BridgeImplBase.sol\\\";\\nimport {HOP} from \\\"../../../static/RouteIdentifiers.sol\\\";\\n\\n/**\\n * @title Hop-L1 Route Implementation\\n * @notice Route implementation with functions to bridge ERC20 and Native via Hop-Bridge from L1 to Supported L2s\\n * Called via SocketGateway if the routeId in the request maps to the routeId of HopImplementation\\n * Contains function to handle bridging as post-step i.e linked to a preceeding step for swap\\n * RequestData is different to just bride and bridging chained with swap\\n * @author Socket dot tech.\\n */\\ncontract HopImplL1 is BridgeImplBase {\\n    /// @notice SafeTransferLib - library for safe and optimised operations on ERC20 tokens\\n    using SafeTransferLib for ERC20;\\n\\n    bytes32 public immutable HopIdentifier = HOP;\\n\\n    /// @notice Function-selector for ERC20-token bridging on Hop-L1-Route\\n    /// @dev This function selector is to be used while buidling transaction-data to bridge ERC20 tokens\\n    bytes4 public immutable HOP_L1_ERC20_EXTERNAL_BRIDGE_FUNCTION_SELECTOR =\\n        bytes4(\\n            keccak256(\\n                \\\"bridgeERC20To(address,address,address,address,uint256,uint256,uint256,uint256,(uint256,bytes32))\\\"\\n            )\\n        );\\n\\n    /// @notice Function-selector for Native bridging on Hop-L1-Route\\n    /// @dev This function selector is to be used while building transaction-data to bridge Native tokens\\n    bytes4 public immutable HOP_L1_NATIVE_EXTERNAL_BRIDGE_FUNCTION_SELECTOR =\\n        bytes4(\\n            keccak256(\\n                \\\"bridgeNativeTo(address,address,address,uint256,uint256,uint256,uint256,uint256,bytes32)\\\"\\n            )\\n        );\\n\\n    bytes4 public immutable HOP_L1_SWAP_BRIDGE_SELECTOR =\\n        bytes4(\\n            keccak256(\\n                \\\"swapAndBridge(uint32,bytes,(address,address,address,uint256,uint256,uint256,uint256,bytes32))\\\"\\n            )\\n        );\\n\\n    /// @notice socketGatewayAddress to be initialised via storage variable BridgeImplBase\\n    constructor(\\n        address _socketGateway,\\n        address _socketDeployFactory\\n    ) BridgeImplBase(_socketGateway, _socketDeployFactory) {}\\n\\n    /// @notice Struct to be used in decode step from input parameter - a specific case of bridging after swap.\\n    /// @dev the data being encoded in offchain or by caller should have values set in this sequence of properties in this struct\\n    struct HopDataNoToken {\\n        // The address receiving funds at the destination\\n        address receiverAddress;\\n        // address of the Hop-L1-Bridge to handle bridging the tokens\\n        address l1bridgeAddr;\\n        // relayerFee The amount distributed to the relayer at the destination. This is subtracted from the `_amount`.\\n        address relayer;\\n        // The chainId of the destination chain\\n        uint256 toChainId;\\n        // The minimum amount received after attempting to swap in the destination AMM market. 0 if no swap is intended.\\n        uint256 amountOutMin;\\n        // The amount distributed to the relayer at the destination. This is subtracted from the `amount`.\\n        uint256 relayerFee;\\n        // The deadline for swapping in the destination AMM market. 0 if no swap is intended.\\n        uint256 deadline;\\n        // socket offchain created hash\\n        bytes32 metadata;\\n    }\\n\\n    struct HopData {\\n        /// @notice address of token being bridged\\n        address token;\\n        // The address receiving funds at the destination\\n        address receiverAddress;\\n        // address of the Hop-L1-Bridge to handle bridging the tokens\\n        address l1bridgeAddr;\\n        // relayerFee The amount distributed to the relayer at the destination. This is subtracted from the `_amount`.\\n        address relayer;\\n        // The chainId of the destination chain\\n        uint256 toChainId;\\n        // The minimum amount received after attempting to swap in the destination AMM market. 0 if no swap is intended.\\n        uint256 amountOutMin;\\n        // The amount distributed to the relayer at the destination. This is subtracted from the `amount`.\\n        uint256 relayerFee;\\n        // The deadline for swapping in the destination AMM market. 0 if no swap is intended.\\n        uint256 deadline;\\n        // socket offchain created hash\\n        bytes32 metadata;\\n    }\\n\\n    struct HopERC20Data {\\n        uint256 deadline;\\n        bytes32 metadata;\\n    }\\n\\n    /**\\n     * @notice function to bridge tokens after swap.\\n     * @notice this is different from swapAndBridge, this function is called when the swap has already happened at a different place.\\n     * @notice This method is payable because the caller is doing token transfer and briding operation\\n     * @dev for usage, refer to controller implementations\\n     *      encodedData for bridge should follow the sequence of properties in HopBridgeData struct\\n     * @param amount amount of tokens being bridged. this can be ERC20 or native\\n     * @param bridgeData encoded data for Hop-L1-Bridge\\n     */\\n    function bridgeAfterSwap(\\n        uint256 amount,\\n        bytes calldata bridgeData\\n    ) external payable override {\\n        HopData memory hopData = abi.decode(bridgeData, (HopData));\\n\\n        if (hopData.token == NATIVE_TOKEN_ADDRESS) {\\n            IHopL1Bridge(hopData.l1bridgeAddr).sendToL2{value: amount}(\\n                hopData.toChainId,\\n                hopData.receiverAddress,\\n                amount,\\n                hopData.amountOutMin,\\n                hopData.deadline,\\n                hopData.relayer,\\n                hopData.relayerFee\\n            );\\n        } else {\\n            ERC20(hopData.token).safeApprove(hopData.l1bridgeAddr, amount);\\n\\n            // perform bridging\\n            IHopL1Bridge(hopData.l1bridgeAddr).sendToL2(\\n                hopData.toChainId,\\n                hopData.receiverAddress,\\n                amount,\\n                hopData.amountOutMin,\\n                hopData.deadline,\\n                hopData.relayer,\\n                hopData.relayerFee\\n            );\\n        }\\n\\n        emit SocketBridge(\\n            amount,\\n            hopData.token,\\n            hopData.toChainId,\\n            HopIdentifier,\\n            msg.sender,\\n            hopData.receiverAddress,\\n            hopData.metadata\\n        );\\n    }\\n\\n    /**\\n     * @notice function to bridge tokens after swap.\\n     * @notice this is different from bridgeAfterSwap since this function holds the logic for swapping tokens too.\\n     * @notice This method is payable because the caller is doing token transfer and briding operation\\n     * @dev for usage, refer to controller implementations\\n     *      encodedData for bridge should follow the sequence of properties in HopBridgeData struct\\n     * @param swapId routeId for the swapImpl\\n     * @param swapData encoded data for swap\\n     * @param hopData encoded data for HopData\\n     */\\n    function swapAndBridge(\\n        uint32 swapId,\\n        bytes calldata swapData,\\n        HopDataNoToken calldata hopData\\n    ) external payable {\\n        (bool success, bytes memory result) = socketRoute\\n            .getRoute(swapId)\\n            .delegatecall(swapData);\\n\\n        if (!success) {\\n            assembly {\\n                revert(add(result, 32), mload(result))\\n            }\\n        }\\n\\n        (uint256 bridgeAmount, address token) = abi.decode(\\n            result,\\n            (uint256, address)\\n        );\\n\\n        if (token == NATIVE_TOKEN_ADDRESS) {\\n            IHopL1Bridge(hopData.l1bridgeAddr).sendToL2{value: bridgeAmount}(\\n                hopData.toChainId,\\n                hopData.receiverAddress,\\n                bridgeAmount,\\n                hopData.amountOutMin,\\n                hopData.deadline,\\n                hopData.relayer,\\n                hopData.relayerFee\\n            );\\n        } else {\\n            ERC20(token).safeApprove(hopData.l1bridgeAddr, bridgeAmount);\\n\\n            // perform bridging\\n            IHopL1Bridge(hopData.l1bridgeAddr).sendToL2(\\n                hopData.toChainId,\\n                hopData.receiverAddress,\\n                bridgeAmount,\\n                hopData.amountOutMin,\\n                hopData.deadline,\\n                hopData.relayer,\\n                hopData.relayerFee\\n            );\\n        }\\n\\n        emit SocketBridge(\\n            bridgeAmount,\\n            token,\\n            hopData.toChainId,\\n            HopIdentifier,\\n            msg.sender,\\n            hopData.receiverAddress,\\n            hopData.metadata\\n        );\\n    }\\n\\n    /**\\n     * @notice function to handle ERC20 bridging to receipent via Hop-L1-Bridge\\n     * @notice This method is payable because the caller is doing token transfer and briding operation\\n     * @param receiverAddress The address receiving funds at the destination\\n     * @param token token being bridged\\n     * @param l1bridgeAddr address of the Hop-L1-Bridge to handle bridging the tokens\\n     * @param relayer The amount distributed to the relayer at the destination. This is subtracted from the `_amount`.\\n     * @param toChainId The chainId of the destination chain\\n     * @param amount The amount being sent\\n     * @param amountOutMin The minimum amount received after attempting to swap in the destination AMM market. 0 if no swap is intended.\\n     * @param relayerFee The amount distributed to the relayer at the destination. This is subtracted from the `amount`.\\n     * @param hopData extra data needed to build the tx\\n     */\\n    function bridgeERC20To(\\n        address receiverAddress,\\n        address token,\\n        address l1bridgeAddr,\\n        address relayer,\\n        uint256 toChainId,\\n        uint256 amount,\\n        uint256 amountOutMin,\\n        uint256 relayerFee,\\n        HopERC20Data calldata hopData\\n    ) external payable {\\n        ERC20 tokenInstance = ERC20(token);\\n        tokenInstance.safeTransferFrom(msg.sender, socketGateway, amount);\\n        tokenInstance.safeApprove(l1bridgeAddr, amount);\\n\\n        // perform bridging\\n        IHopL1Bridge(l1bridgeAddr).sendToL2(\\n            toChainId,\\n            receiverAddress,\\n            amount,\\n            amountOutMin,\\n            hopData.deadline,\\n            relayer,\\n            relayerFee\\n        );\\n\\n        emit SocketBridge(\\n            amount,\\n            token,\\n            toChainId,\\n            HopIdentifier,\\n            msg.sender,\\n            receiverAddress,\\n            hopData.metadata\\n        );\\n    }\\n\\n    /**\\n     * @notice function to handle Native bridging to receipent via Hop-L1-Bridge\\n     * @notice This method is payable because the caller is doing token transfer and briding operation\\n     * @param receiverAddress The address receiving funds at the destination\\n     * @param l1bridgeAddr address of the Hop-L1-Bridge to handle bridging the tokens\\n     * @param relayer The amount distributed to the relayer at the destination. This is subtracted from the `_amount`.\\n     * @param toChainId The chainId of the destination chain\\n     * @param amount The amount being sent\\n     * @param amountOutMin The minimum amount received after attempting to swap in the destination AMM market. 0 if no swap is intended.\\n     * @param relayerFee The amount distributed to the relayer at the destination. This is subtracted from the `amount`.\\n     * @param deadline The deadline for swapping in the destination AMM market. 0 if no swap is intended.\\n     */\\n    function bridgeNativeTo(\\n        address receiverAddress,\\n        address l1bridgeAddr,\\n        address relayer,\\n        uint256 toChainId,\\n        uint256 amount,\\n        uint256 amountOutMin,\\n        uint256 relayerFee,\\n        uint256 deadline,\\n        bytes32 metadata\\n    ) external payable {\\n        IHopL1Bridge(l1bridgeAddr).sendToL2{value: amount}(\\n            toChainId,\\n            receiverAddress,\\n            amount,\\n            amountOutMin,\\n            deadline,\\n            relayer,\\n            relayerFee\\n        );\\n\\n        emit SocketBridge(\\n            amount,\\n            NATIVE_TOKEN_ADDRESS,\\n            toChainId,\\n            HopIdentifier,\\n            msg.sender,\\n            receiverAddress,\\n            metadata\\n        );\\n    }\\n}\\n\"},\"src/static/RouteIdentifiers.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.4;\\nbytes32 constant ACROSS = keccak256(\\\"Across\\\");\\n\\nbytes32 constant ANYSWAP = keccak256(\\\"Anyswap\\\");\\n\\nbytes32 constant CBRIDGE = keccak256(\\\"CBridge\\\");\\n\\nbytes32 constant HOP = keccak256(\\\"Hop\\\");\\n\\nbytes32 constant HYPHEN = keccak256(\\\"Hyphen\\\");\\n\\nbytes32 constant NATIVE_OPTIMISM = keccak256(\\\"NativeOptimism\\\");\\n\\nbytes32 constant NATIVE_ARBITRUM = keccak256(\\\"NativeArbitrum\\\");\\n\\nbytes32 constant NATIVE_POLYGON = keccak256(\\\"NativePolygon\\\");\\n\\nbytes32 constant REFUEL = keccak256(\\\"Refuel\\\");\\n\\nbytes32 constant STARGATE = keccak256(\\\"Stargate\\\");\\n\\nbytes32 constant ONEINCH = keccak256(\\\"OneInch\\\");\\n\\nbytes32 constant ZEROX = keccak256(\\\"Zerox\\\");\\n\\nbytes32 constant RAINBOW = keccak256(\\\"Rainbow\\\");\\n\"},\"src/SocketGateway.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.4;\\n\\npragma experimental ABIEncoderV2;\\n\\nimport \\\"./utils/Ownable.sol\\\";\\nimport {SafeTransferLib} from \\\"lib/solmate/src/utils/SafeTransferLib.sol\\\";\\nimport {ERC20} from \\\"lib/solmate/src/tokens/ERC20.sol\\\";\\nimport {LibUtil} from \\\"./libraries/LibUtil.sol\\\";\\nimport \\\"./libraries/LibBytes.sol\\\";\\nimport {ISocketRoute} from \\\"./interfaces/ISocketRoute.sol\\\";\\nimport {ISocketRequest} from \\\"./interfaces/ISocketRequest.sol\\\";\\nimport {ISocketGateway} from \\\"./interfaces/ISocketGateway.sol\\\";\\nimport {IncorrectBridgeRatios, ZeroAddressNotAllowed, ArrayLengthMismatch} from \\\"./errors/SocketErrors.sol\\\";\\n\\n/// @title SocketGatewayContract\\n/// @notice Socketgateway is a contract with entrypoint functions for all interactions with socket liquidity layer\\n/// @author Socket Team\\ncontract SocketGatewayTemplate is Ownable {\\n    using LibBytes for bytes;\\n    using LibBytes for bytes4;\\n    using SafeTransferLib for ERC20;\\n\\n    /// @notice FunctionSelector used to delegatecall from swap to the function of bridge router implementation\\n    bytes4 public immutable BRIDGE_AFTER_SWAP_SELECTOR =\\n        bytes4(keccak256(\\\"bridgeAfterSwap(uint256,bytes)\\\"));\\n\\n    /// @notice storage variable to keep track of total number of routes registered in socketgateway\\n    uint32 public routesCount = 385;\\n\\n    /// @notice storage variable to keep track of total number of controllers registered in socketgateway\\n    uint32 public controllerCount;\\n\\n    address public immutable disabledRouteAddress;\\n\\n    uint256 public constant CENT_PERCENT = 100e18;\\n\\n    /// @notice storage mapping for route implementation addresses\\n    mapping(uint32 => address) public routes;\\n\\n    /// storage mapping for controller implemenation addresses\\n    mapping(uint32 => address) public controllers;\\n\\n    // Events ------------------------------------------------------------------------------------------------------->\\n\\n    /// @notice Event emitted when a router is added to socketgateway\\n    event NewRouteAdded(uint32 indexed routeId, address indexed route);\\n\\n    /// @notice Event emitted when a route is disabled\\n    event RouteDisabled(uint32 indexed routeId);\\n\\n    /// @notice Event emitted when ownership transfer is requested by socket-gateway-owner\\n    event OwnershipTransferRequested(\\n        address indexed _from,\\n        address indexed _to\\n    );\\n\\n    /// @notice Event emitted when a controller is added to socketgateway\\n    event ControllerAdded(\\n        uint32 indexed controllerId,\\n        address indexed controllerAddress\\n    );\\n\\n    /// @notice Event emitted when a controller is disabled\\n    event ControllerDisabled(uint32 indexed controllerId);\\n\\n    constructor(address _owner, address _disabledRoute) Ownable(_owner) {\\n        disabledRouteAddress = _disabledRoute;\\n    }\\n\\n    // Able to receive ether\\n    // solhint-disable-next-line no-empty-blocks\\n    receive() external payable {}\\n\\n    /*******************************************\\n     *          EXTERNAL AND PUBLIC FUNCTIONS  *\\n     *******************************************/\\n\\n    /**\\n     * @notice executes functions in the routes identified using routeId and functionSelectorData\\n     * @notice The caller must first approve this contract to spend amount of ERC20-Token being bridged/swapped\\n     * @dev ensure the data in routeData to be built using the function-selector defined as a\\n     *         constant in the route implementation contract\\n     * @param routeId route identifier\\n     * @param routeData functionSelectorData generated using the function-selector defined in the route Implementation\\n     */\\n    function executeRoute(\\n        uint32 routeId,\\n        bytes calldata routeData\\n    ) external payable returns (bytes memory) {\\n        (bool success, bytes memory result) = addressAt(routeId).delegatecall(\\n            routeData\\n        );\\n\\n        if (!success) {\\n            assembly {\\n                revert(add(result, 32), mload(result))\\n            }\\n        }\\n\\n        return result;\\n    }\\n\\n    /**\\n     * @notice swaps a token on sourceChain and split it across multiple bridge-recipients\\n     * @notice The caller must first approve this contract to spend amount of ERC20-Token being swapped\\n     * @dev ensure the swap-data and bridge-data is generated using the function-selector defined as a constant in the implementation address\\n     * @param swapMultiBridgeRequest request\\n     */\\n    function swapAndMultiBridge(\\n        ISocketRequest.SwapMultiBridgeRequest calldata swapMultiBridgeRequest\\n    ) external payable {\\n        uint256 requestLength = swapMultiBridgeRequest.bridgeRouteIds.length;\\n\\n        if (\\n            requestLength != swapMultiBridgeRequest.bridgeImplDataItems.length\\n        ) {\\n            revert ArrayLengthMismatch();\\n        }\\n        uint256 ratioAggregate;\\n        for (uint256 index = 0; index < requestLength; ) {\\n            ratioAggregate += swapMultiBridgeRequest.bridgeRatios[index];\\n        }\\n\\n        if (ratioAggregate != CENT_PERCENT) {\\n            revert IncorrectBridgeRatios();\\n        }\\n\\n        (bool swapSuccess, bytes memory swapResult) = addressAt(\\n            swapMultiBridgeRequest.swapRouteId\\n        ).delegatecall(swapMultiBridgeRequest.swapImplData);\\n\\n        if (!swapSuccess) {\\n            assembly {\\n                revert(add(swapResult, 32), mload(swapResult))\\n            }\\n        }\\n\\n        uint256 amountReceivedFromSwap = abi.decode(swapResult, (uint256));\\n\\n        uint256 bridgedAmount;\\n\\n        for (uint256 index = 0; index < requestLength; ) {\\n            uint256 bridgingAmount;\\n\\n            // if it is the last bridge request, bridge the remaining amount\\n            if (index == requestLength - 1) {\\n                bridgingAmount = amountReceivedFromSwap - bridgedAmount;\\n            } else {\\n                // bridging amount is the multiplication of bridgeRatio and amountReceivedFromSwap\\n                bridgingAmount =\\n                    (amountReceivedFromSwap *\\n                        swapMultiBridgeRequest.bridgeRatios[index]) /\\n                    (CENT_PERCENT);\\n            }\\n\\n            // update the bridged amount, this would be used for computation for last bridgeRequest\\n            bridgedAmount += bridgingAmount;\\n\\n            bytes memory bridgeImpldata = abi.encodeWithSelector(\\n                BRIDGE_AFTER_SWAP_SELECTOR,\\n                bridgingAmount,\\n                swapMultiBridgeRequest.bridgeImplDataItems[index]\\n            );\\n\\n            (bool bridgeSuccess, bytes memory bridgeResult) = addressAt(\\n                swapMultiBridgeRequest.bridgeRouteIds[index]\\n            ).delegatecall(bridgeImpldata);\\n\\n            if (!bridgeSuccess) {\\n                assembly {\\n                    revert(add(bridgeResult, 32), mload(bridgeResult))\\n                }\\n            }\\n\\n            unchecked {\\n                ++index;\\n            }\\n        }\\n    }\\n\\n    /**\\n     * @notice sequentially executes functions in the routes identified using routeId and functionSelectorData\\n     * @notice The caller must first approve this contract to spend amount of ERC20-Token being bridged/swapped\\n     * @dev ensure the data in each dataItem to be built using the function-selector defined as a\\n     *         constant in the route implementation contract\\n     * @param routeIds a list of route identifiers\\n     * @param dataItems a list of functionSelectorData generated using the function-selector defined in the route Implementation\\n     */\\n    function executeRoutes(\\n        uint32[] calldata routeIds,\\n        bytes[] calldata dataItems\\n    ) external payable {\\n        uint256 routeIdslength = routeIds.length;\\n        if (routeIdslength != dataItems.length) revert ArrayLengthMismatch();\\n        for (uint256 index = 0; index < routeIdslength; ) {\\n            (bool success, bytes memory result) = addressAt(routeIds[index])\\n                .delegatecall(dataItems[index]);\\n\\n            if (!success) {\\n                assembly {\\n                    revert(add(result, 32), mload(result))\\n                }\\n            }\\n\\n            unchecked {\\n                ++index;\\n            }\\n        }\\n    }\\n\\n    /**\\n     * @notice execute a controller function identified using the controllerId in the request\\n     * @notice The caller must first approve this contract to spend amount of ERC20-Token being bridged/swapped\\n     * @dev ensure the data in request to be built using the function-selector defined as a\\n     *         constant in the controller implementation contract\\n     * @param socketControllerRequest socketControllerRequest with controllerId to identify the\\n     *                                   controllerAddress and byteData constructed using functionSelector\\n     *                                   of the function being invoked\\n     * @return bytes data received from the call delegated to controller\\n     */\\n    function executeController(\\n        ISocketGateway.SocketControllerRequest calldata socketControllerRequest\\n    ) external payable returns (bytes memory) {\\n        (bool success, bytes memory result) = controllers[\\n            socketControllerRequest.controllerId\\n        ].delegatecall(socketControllerRequest.data);\\n\\n        if (!success) {\\n            assembly {\\n                revert(add(result, 32), mload(result))\\n            }\\n        }\\n\\n        return result;\\n    }\\n\\n    /**\\n     * @notice sequentially executes all controller requests\\n     * @notice The caller must first approve this contract to spend amount of ERC20-Token being bridged/swapped\\n     * @dev ensure the data in each controller-request to be built using the function-selector defined as a\\n     *         constant in the controller implementation contract\\n     * @param controllerRequests a list of socketControllerRequest\\n     *                              Each controllerRequest contains controllerId to identify the controllerAddress and\\n     *                              byteData constructed using functionSelector of the function being invoked\\n     */\\n    function executeControllers(\\n        ISocketGateway.SocketControllerRequest[] calldata controllerRequests\\n    ) external payable {\\n        for (uint32 index = 0; index < controllerRequests.length; ) {\\n            (bool success, bytes memory result) = controllers[\\n                controllerRequests[index].controllerId\\n            ].delegatecall(controllerRequests[index].data);\\n\\n            if (!success) {\\n                assembly {\\n                    revert(add(result, 32), mload(result))\\n                }\\n            }\\n\\n            unchecked {\\n                ++index;\\n            }\\n        }\\n    }\\n\\n    /**************************************\\n     *          ADMIN FUNCTIONS           *\\n     **************************************/\\n\\n    /**\\n     * @notice Add route to the socketGateway\\n               This is a restricted function to be called by only socketGatewayOwner\\n     * @dev ensure routeAddress is a verified bridge or middleware implementation address\\n     * @param routeAddress The address of bridge or middleware implementation contract deployed\\n     * @return Id of the route added to the routes-mapping in socketGateway storage\\n     */\\n    function addRoute(\\n        address routeAddress\\n    ) external onlyOwner returns (uint32) {\\n        uint32 routeId = routesCount;\\n        routes[routeId] = routeAddress;\\n\\n        routesCount += 1;\\n\\n        emit NewRouteAdded(routeId, routeAddress);\\n\\n        return routeId;\\n    }\\n\\n    /**\\n     * @notice Give Infinite or 0 approval to bridgeRoute for the tokenAddress\\n               This is a restricted function to be called by only socketGatewayOwner\\n     */\\n\\n    function setApprovalForRouters(\\n        address[] memory routeAddresses,\\n        address[] memory tokenAddresses,\\n        bool isMax\\n    ) external onlyOwner {\\n        for (uint32 index = 0; index < routeAddresses.length; ) {\\n            ERC20(tokenAddresses[index]).approve(\\n                routeAddresses[index],\\n                isMax ? type(uint256).max : 0\\n            );\\n            unchecked {\\n                ++index;\\n            }\\n        }\\n    }\\n\\n    /**\\n     * @notice Add controller to the socketGateway\\n               This is a restricted function to be called by only socketGatewayOwner\\n     * @dev ensure controllerAddress is a verified controller implementation address\\n     * @param controllerAddress The address of controller implementation contract deployed\\n     * @return Id of the controller added to the controllers-mapping in socketGateway storage\\n     */\\n    function addController(\\n        address controllerAddress\\n    ) external onlyOwner returns (uint32) {\\n        uint32 controllerId = controllerCount;\\n\\n        controllers[controllerId] = controllerAddress;\\n\\n        controllerCount += 1;\\n\\n        emit ControllerAdded(controllerId, controllerAddress);\\n\\n        return controllerId;\\n    }\\n\\n    /**\\n     * @notice disable controller by setting ZeroAddress to the entry in controllers-mapping\\n               identified by controllerId as key.\\n               This is a restricted function to be called by only socketGatewayOwner\\n     * @param controllerId The Id of controller-implementation in the controllers mapping\\n     */\\n    function disableController(uint32 controllerId) public onlyOwner {\\n        controllers[controllerId] = disabledRouteAddress;\\n        emit ControllerDisabled(controllerId);\\n    }\\n\\n    /**\\n     * @notice disable a route by setting ZeroAddress to the entry in routes-mapping\\n               identified by routeId as key.\\n               This is a restricted function to be called by only socketGatewayOwner\\n     * @param routeId The Id of route-implementation in the routes mapping\\n     */\\n    function disableRoute(uint32 routeId) external onlyOwner {\\n        routes[routeId] = disabledRouteAddress;\\n        emit RouteDisabled(routeId);\\n    }\\n\\n    /*******************************************\\n     *          RESTRICTED RESCUE FUNCTIONS    *\\n     *******************************************/\\n\\n    /**\\n     * @notice Rescues the ERC20 token to an address\\n               this is a restricted function to be called by only socketGatewayOwner\\n     * @dev as this is a restricted to socketGatewayOwner, ensure the userAddress is a known address\\n     * @param token address of the ERC20 token being rescued\\n     * @param userAddress address to which ERC20 is to be rescued\\n     * @param amount amount of ERC20 tokens being rescued\\n     */\\n    function rescueFunds(\\n        address token,\\n        address userAddress,\\n        uint256 amount\\n    ) external onlyOwner {\\n        ERC20(token).safeTransfer(userAddress, amount);\\n    }\\n\\n    /**\\n     * @notice Rescues the native balance to an address\\n               this is a restricted function to be called by only socketGatewayOwner\\n     * @dev as this is a restricted to socketGatewayOwner, ensure the userAddress is a known address\\n     * @param userAddress address to which native-balance is to be rescued\\n     * @param amount amount of native-balance being rescued\\n     */\\n    function rescueEther(\\n        address payable userAddress,\\n        uint256 amount\\n    ) external onlyOwner {\\n        userAddress.transfer(amount);\\n    }\\n\\n    /*******************************************\\n     *          VIEW FUNCTIONS                  *\\n     *******************************************/\\n\\n    /**\\n     * @notice Get routeImplementation address mapped to the routeId\\n     * @param routeId routeId is the key in the mapping for routes\\n     * @return route-implementation address\\n     */\\n    function getRoute(uint32 routeId) public view returns (address) {\\n        return addressAt(routeId);\\n    }\\n\\n    /**\\n     * @notice Get controllerImplementation address mapped to the controllerId\\n     * @param controllerId controllerId is the key in the mapping for controllers\\n     * @return controller-implementation address\\n     */\\n    function getController(uint32 controllerId) public view returns (address) {\\n        return controllers[controllerId];\\n    }\\n\\n    function addressAt(uint32 routeId) public view returns (address) {\\n        if (routeId < 385) {\\n            if (routeId < 257) {\\n                if (routeId < 129) {\\n                    if (routeId < 65) {\\n                        if (routeId < 33) {\\n                            if (routeId < 17) {\\n                                if (routeId < 9) {\\n                                    if (routeId < 5) {\\n                                        if (routeId < 3) {\\n                                            if (routeId == 1) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 3) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        }\\n                                    } else {\\n                                        if (routeId < 7) {\\n                                            if (routeId == 5) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 7) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        }\\n                                    }\\n                                } else {\\n                                    if (routeId < 13) {\\n                                        if (routeId < 11) {\\n                                            if (routeId == 9) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 11) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        }\\n                                    } else {\\n                                        if (routeId < 15) {\\n                                            if (routeId == 13) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 15) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        }\\n                                    }\\n                                }\\n                            } else {\\n                                if (routeId < 25) {\\n                                    if (routeId < 21) {\\n                                        if (routeId < 19) {\\n                                            if (routeId == 17) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 19) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        }\\n                                    } else {\\n                                        if (routeId < 23) {\\n                                            if (routeId == 21) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 23) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        }\\n                                    }\\n                                } else {\\n                                    if (routeId < 29) {\\n                                        if (routeId < 27) {\\n                                            if (routeId == 25) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 27) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        }\\n                                    } else {\\n                                        if (routeId < 31) {\\n                                            if (routeId == 29) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 31) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        }\\n                                    }\\n                                }\\n                            }\\n                        } else {\\n                            if (routeId < 49) {\\n                                if (routeId < 41) {\\n                                    if (routeId < 37) {\\n                                        if (routeId < 35) {\\n                                            if (routeId == 33) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 35) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        }\\n                                    } else {\\n                                        if (routeId < 39) {\\n                                            if (routeId == 37) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 39) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        }\\n                                    }\\n                                } else {\\n                                    if (routeId < 45) {\\n                                        if (routeId < 43) {\\n                                            if (routeId == 41) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 43) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        }\\n                                    } else {\\n                                        if (routeId < 47) {\\n                                            if (routeId == 45) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 47) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        }\\n                                    }\\n                                }\\n                            } else {\\n                                if (routeId < 57) {\\n                                    if (routeId < 53) {\\n                                        if (routeId < 51) {\\n                                            if (routeId == 49) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 51) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        }\\n                                    } else {\\n                                        if (routeId < 55) {\\n                                            if (routeId == 53) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 55) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        }\\n                                    }\\n                                } else {\\n                                    if (routeId < 61) {\\n                                        if (routeId < 59) {\\n                                            if (routeId == 57) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 59) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        }\\n                                    } else {\\n                                        if (routeId < 63) {\\n                                            if (routeId == 61) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 63) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        }\\n                                    }\\n                                }\\n                            }\\n                        }\\n                    } else {\\n                        if (routeId < 97) {\\n                            if (routeId < 81) {\\n                                if (routeId < 73) {\\n                                    if (routeId < 69) {\\n                                        if (routeId < 67) {\\n                                            if (routeId == 65) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 67) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        }\\n                                    } else {\\n                                        if (routeId < 71) {\\n                                            if (routeId == 69) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 71) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        }\\n                                    }\\n                                } else {\\n                                    if (routeId < 77) {\\n                                        if (routeId < 75) {\\n                                            if (routeId == 73) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 75) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        }\\n                                    } else {\\n                                        if (routeId < 79) {\\n                                            if (routeId == 77) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 79) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        }\\n                                    }\\n                                }\\n                            } else {\\n                                if (routeId < 89) {\\n                                    if (routeId < 85) {\\n                                        if (routeId < 83) {\\n                                            if (routeId == 81) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 83) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        }\\n                                    } else {\\n                                        if (routeId < 87) {\\n                                            if (routeId == 85) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 87) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        }\\n                                    }\\n                                } else {\\n                                    if (routeId < 93) {\\n                                        if (routeId < 91) {\\n                                            if (routeId == 89) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 91) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        }\\n                                    } else {\\n                                        if (routeId < 95) {\\n                                            if (routeId == 93) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 95) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        }\\n                                    }\\n                                }\\n                            }\\n                        } else {\\n                            if (routeId < 113) {\\n                                if (routeId < 105) {\\n                                    if (routeId < 101) {\\n                                        if (routeId < 99) {\\n                                            if (routeId == 97) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 99) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        }\\n                                    } else {\\n                                        if (routeId < 103) {\\n                                            if (routeId == 101) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 103) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        }\\n                                    }\\n                                } else {\\n                                    if (routeId < 109) {\\n                                        if (routeId < 107) {\\n                                            if (routeId == 105) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 107) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        }\\n                                    } else {\\n                                        if (routeId < 111) {\\n                                            if (routeId == 109) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 111) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        }\\n                                    }\\n                                }\\n                            } else {\\n                                if (routeId < 121) {\\n                                    if (routeId < 117) {\\n                                        if (routeId < 115) {\\n                                            if (routeId == 113) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 115) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        }\\n                                    } else {\\n                                        if (routeId < 119) {\\n                                            if (routeId == 117) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 119) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        }\\n                                    }\\n                                } else {\\n                                    if (routeId < 125) {\\n                                        if (routeId < 123) {\\n                                            if (routeId == 121) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 123) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        }\\n                                    } else {\\n                                        if (routeId < 127) {\\n                                            if (routeId == 125) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 127) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        }\\n                                    }\\n                                }\\n                            }\\n                        }\\n                    }\\n                } else {\\n                    if (routeId < 193) {\\n                        if (routeId < 161) {\\n                            if (routeId < 145) {\\n                                if (routeId < 137) {\\n                                    if (routeId < 133) {\\n                                        if (routeId < 131) {\\n                                            if (routeId == 129) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 131) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        }\\n                                    } else {\\n                                        if (routeId < 135) {\\n                                            if (routeId == 133) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 135) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        }\\n                                    }\\n                                } else {\\n                                    if (routeId < 141) {\\n                                        if (routeId < 139) {\\n                                            if (routeId == 137) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 139) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        }\\n                                    } else {\\n                                        if (routeId < 143) {\\n                                            if (routeId == 141) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 143) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        }\\n                                    }\\n                                }\\n                            } else {\\n                                if (routeId < 153) {\\n                                    if (routeId < 149) {\\n                                        if (routeId < 147) {\\n                                            if (routeId == 145) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 147) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        }\\n                                    } else {\\n                                        if (routeId < 151) {\\n                                            if (routeId == 149) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 151) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        }\\n                                    }\\n                                } else {\\n                                    if (routeId < 157) {\\n                                        if (routeId < 155) {\\n                                            if (routeId == 153) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 155) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        }\\n                                    } else {\\n                                        if (routeId < 159) {\\n                                            if (routeId == 157) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 159) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        }\\n                                    }\\n                                }\\n                            }\\n                        } else {\\n                            if (routeId < 177) {\\n                                if (routeId < 169) {\\n                                    if (routeId < 165) {\\n                                        if (routeId < 163) {\\n                                            if (routeId == 161) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 163) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        }\\n                                    } else {\\n                                        if (routeId < 167) {\\n                                            if (routeId == 165) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 167) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        }\\n                                    }\\n                                } else {\\n                                    if (routeId < 173) {\\n                                        if (routeId < 171) {\\n                                            if (routeId == 169) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 171) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        }\\n                                    } else {\\n                                        if (routeId < 175) {\\n                                            if (routeId == 173) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 175) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        }\\n                                    }\\n                                }\\n                            } else {\\n                                if (routeId < 185) {\\n                                    if (routeId < 181) {\\n                                        if (routeId < 179) {\\n                                            if (routeId == 177) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 179) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        }\\n                                    } else {\\n                                        if (routeId < 183) {\\n                                            if (routeId == 181) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 183) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        }\\n                                    }\\n                                } else {\\n                                    if (routeId < 189) {\\n                                        if (routeId < 187) {\\n                                            if (routeId == 185) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 187) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        }\\n                                    } else {\\n                                        if (routeId < 191) {\\n                                            if (routeId == 189) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 191) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        }\\n                                    }\\n                                }\\n                            }\\n                        }\\n                    } else {\\n                        if (routeId < 225) {\\n                            if (routeId < 209) {\\n                                if (routeId < 201) {\\n                                    if (routeId < 197) {\\n                                        if (routeId < 195) {\\n                                            if (routeId == 193) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 195) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        }\\n                                    } else {\\n                                        if (routeId < 199) {\\n                                            if (routeId == 197) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 199) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        }\\n                                    }\\n                                } else {\\n                                    if (routeId < 205) {\\n                                        if (routeId < 203) {\\n                                            if (routeId == 201) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 203) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        }\\n                                    } else {\\n                                        if (routeId < 207) {\\n                                            if (routeId == 205) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 207) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        }\\n                                    }\\n                                }\\n                            } else {\\n                                if (routeId < 217) {\\n                                    if (routeId < 213) {\\n                                        if (routeId < 211) {\\n                                            if (routeId == 209) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 211) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        }\\n                                    } else {\\n                                        if (routeId < 215) {\\n                                            if (routeId == 213) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 215) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        }\\n                                    }\\n                                } else {\\n                                    if (routeId < 221) {\\n                                        if (routeId < 219) {\\n                                            if (routeId == 217) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 219) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        }\\n                                    } else {\\n                                        if (routeId < 223) {\\n                                            if (routeId == 221) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 223) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        }\\n                                    }\\n                                }\\n                            }\\n                        } else {\\n                            if (routeId < 241) {\\n                                if (routeId < 233) {\\n                                    if (routeId < 229) {\\n                                        if (routeId < 227) {\\n                                            if (routeId == 225) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 227) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        }\\n                                    } else {\\n                                        if (routeId < 231) {\\n                                            if (routeId == 229) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 231) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        }\\n                                    }\\n                                } else {\\n                                    if (routeId < 237) {\\n                                        if (routeId < 235) {\\n                                            if (routeId == 233) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 235) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        }\\n                                    } else {\\n                                        if (routeId < 239) {\\n                                            if (routeId == 237) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 239) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        }\\n                                    }\\n                                }\\n                            } else {\\n                                if (routeId < 249) {\\n                                    if (routeId < 245) {\\n                                        if (routeId < 243) {\\n                                            if (routeId == 241) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 243) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        }\\n                                    } else {\\n                                        if (routeId < 247) {\\n                                            if (routeId == 245) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 247) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        }\\n                                    }\\n                                } else {\\n                                    if (routeId < 253) {\\n                                        if (routeId < 251) {\\n                                            if (routeId == 249) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 251) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        }\\n                                    } else {\\n                                        if (routeId < 255) {\\n                                            if (routeId == 253) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        } else {\\n                                            if (routeId == 255) {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            } else {\\n                                                return\\n                                                    0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                            }\\n                                        }\\n                                    }\\n                                }\\n                            }\\n                        }\\n                    }\\n                }\\n            } else {\\n                if (routeId < 321) {\\n                    if (routeId < 289) {\\n                        if (routeId < 273) {\\n                            if (routeId < 265) {\\n                                if (routeId < 261) {\\n                                    if (routeId < 259) {\\n                                        if (routeId == 257) {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        } else {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        }\\n                                    } else {\\n                                        if (routeId == 259) {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        } else {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        }\\n                                    }\\n                                } else {\\n                                    if (routeId < 263) {\\n                                        if (routeId == 261) {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        } else {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        }\\n                                    } else {\\n                                        if (routeId == 263) {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        } else {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        }\\n                                    }\\n                                }\\n                            } else {\\n                                if (routeId < 269) {\\n                                    if (routeId < 267) {\\n                                        if (routeId == 265) {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        } else {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        }\\n                                    } else {\\n                                        if (routeId == 267) {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        } else {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        }\\n                                    }\\n                                } else {\\n                                    if (routeId < 271) {\\n                                        if (routeId == 269) {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        } else {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        }\\n                                    } else {\\n                                        if (routeId == 271) {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        } else {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        }\\n                                    }\\n                                }\\n                            }\\n                        } else {\\n                            if (routeId < 281) {\\n                                if (routeId < 277) {\\n                                    if (routeId < 275) {\\n                                        if (routeId == 273) {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        } else {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        }\\n                                    } else {\\n                                        if (routeId == 275) {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        } else {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        }\\n                                    }\\n                                } else {\\n                                    if (routeId < 279) {\\n                                        if (routeId == 277) {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        } else {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        }\\n                                    } else {\\n                                        if (routeId == 279) {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        } else {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        }\\n                                    }\\n                                }\\n                            } else {\\n                                if (routeId < 285) {\\n                                    if (routeId < 283) {\\n                                        if (routeId == 281) {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        } else {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        }\\n                                    } else {\\n                                        if (routeId == 283) {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        } else {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        }\\n                                    }\\n                                } else {\\n                                    if (routeId < 287) {\\n                                        if (routeId == 285) {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        } else {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        }\\n                                    } else {\\n                                        if (routeId == 287) {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        } else {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        }\\n                                    }\\n                                }\\n                            }\\n                        }\\n                    } else {\\n                        if (routeId < 305) {\\n                            if (routeId < 297) {\\n                                if (routeId < 293) {\\n                                    if (routeId < 291) {\\n                                        if (routeId == 289) {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        } else {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        }\\n                                    } else {\\n                                        if (routeId == 291) {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        } else {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        }\\n                                    }\\n                                } else {\\n                                    if (routeId < 295) {\\n                                        if (routeId == 293) {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        } else {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        }\\n                                    } else {\\n                                        if (routeId == 295) {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        } else {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        }\\n                                    }\\n                                }\\n                            } else {\\n                                if (routeId < 301) {\\n                                    if (routeId < 299) {\\n                                        if (routeId == 297) {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        } else {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        }\\n                                    } else {\\n                                        if (routeId == 299) {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        } else {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        }\\n                                    }\\n                                } else {\\n                                    if (routeId < 303) {\\n                                        if (routeId == 301) {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        } else {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        }\\n                                    } else {\\n                                        if (routeId == 303) {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        } else {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        }\\n                                    }\\n                                }\\n                            }\\n                        } else {\\n                            if (routeId < 313) {\\n                                if (routeId < 309) {\\n                                    if (routeId < 307) {\\n                                        if (routeId == 305) {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        } else {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        }\\n                                    } else {\\n                                        if (routeId == 307) {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        } else {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        }\\n                                    }\\n                                } else {\\n                                    if (routeId < 311) {\\n                                        if (routeId == 309) {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        } else {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        }\\n                                    } else {\\n                                        if (routeId == 311) {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        } else {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        }\\n                                    }\\n                                }\\n                            } else {\\n                                if (routeId < 317) {\\n                                    if (routeId < 315) {\\n                                        if (routeId == 313) {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        } else {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        }\\n                                    } else {\\n                                        if (routeId == 315) {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        } else {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        }\\n                                    }\\n                                } else {\\n                                    if (routeId < 319) {\\n                                        if (routeId == 317) {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        } else {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        }\\n                                    } else {\\n                                        if (routeId == 319) {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        } else {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        }\\n                                    }\\n                                }\\n                            }\\n                        }\\n                    }\\n                } else {\\n                    if (routeId < 353) {\\n                        if (routeId < 337) {\\n                            if (routeId < 329) {\\n                                if (routeId < 325) {\\n                                    if (routeId < 323) {\\n                                        if (routeId == 321) {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        } else {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        }\\n                                    } else {\\n                                        if (routeId == 323) {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        } else {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        }\\n                                    }\\n                                } else {\\n                                    if (routeId < 327) {\\n                                        if (routeId == 325) {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        } else {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        }\\n                                    } else {\\n                                        if (routeId == 327) {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        } else {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        }\\n                                    }\\n                                }\\n                            } else {\\n                                if (routeId < 333) {\\n                                    if (routeId < 331) {\\n                                        if (routeId == 329) {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        } else {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        }\\n                                    } else {\\n                                        if (routeId == 331) {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        } else {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        }\\n                                    }\\n                                } else {\\n                                    if (routeId < 335) {\\n                                        if (routeId == 333) {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        } else {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        }\\n                                    } else {\\n                                        if (routeId == 335) {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        } else {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        }\\n                                    }\\n                                }\\n                            }\\n                        } else {\\n                            if (routeId < 345) {\\n                                if (routeId < 341) {\\n                                    if (routeId < 339) {\\n                                        if (routeId == 337) {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        } else {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        }\\n                                    } else {\\n                                        if (routeId == 339) {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        } else {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        }\\n                                    }\\n                                } else {\\n                                    if (routeId < 343) {\\n                                        if (routeId == 341) {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        } else {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        }\\n                                    } else {\\n                                        if (routeId == 343) {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        } else {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        }\\n                                    }\\n                                }\\n                            } else {\\n                                if (routeId < 349) {\\n                                    if (routeId < 347) {\\n                                        if (routeId == 345) {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        } else {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        }\\n                                    } else {\\n                                        if (routeId == 347) {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        } else {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        }\\n                                    }\\n                                } else {\\n                                    if (routeId < 351) {\\n                                        if (routeId == 349) {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        } else {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        }\\n                                    } else {\\n                                        if (routeId == 351) {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        } else {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        }\\n                                    }\\n                                }\\n                            }\\n                        }\\n                    } else {\\n                        if (routeId < 369) {\\n                            if (routeId < 361) {\\n                                if (routeId < 357) {\\n                                    if (routeId < 355) {\\n                                        if (routeId == 353) {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        } else {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        }\\n                                    } else {\\n                                        if (routeId == 355) {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        } else {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        }\\n                                    }\\n                                } else {\\n                                    if (routeId < 359) {\\n                                        if (routeId == 357) {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        } else {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        }\\n                                    } else {\\n                                        if (routeId == 359) {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        } else {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        }\\n                                    }\\n                                }\\n                            } else {\\n                                if (routeId < 365) {\\n                                    if (routeId < 363) {\\n                                        if (routeId == 361) {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        } else {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        }\\n                                    } else {\\n                                        if (routeId == 363) {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        } else {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        }\\n                                    }\\n                                } else {\\n                                    if (routeId < 367) {\\n                                        if (routeId == 365) {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        } else {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        }\\n                                    } else {\\n                                        if (routeId == 367) {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        } else {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        }\\n                                    }\\n                                }\\n                            }\\n                        } else {\\n                            if (routeId < 377) {\\n                                if (routeId < 373) {\\n                                    if (routeId < 371) {\\n                                        if (routeId == 369) {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        } else {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        }\\n                                    } else {\\n                                        if (routeId == 371) {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        } else {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        }\\n                                    }\\n                                } else {\\n                                    if (routeId < 375) {\\n                                        if (routeId == 373) {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        } else {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        }\\n                                    } else {\\n                                        if (routeId == 375) {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        } else {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        }\\n                                    }\\n                                }\\n                            } else {\\n                                if (routeId < 381) {\\n                                    if (routeId < 379) {\\n                                        if (routeId == 377) {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        } else {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        }\\n                                    } else {\\n                                        if (routeId == 379) {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        } else {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        }\\n                                    }\\n                                } else {\\n                                    if (routeId < 383) {\\n                                        if (routeId == 381) {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        } else {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        }\\n                                    } else {\\n                                        if (routeId == 383) {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        } else {\\n                                            return\\n                                                0x822D4B4e63499a576Ab1cc152B86D1CFFf794F4f;\\n                                        }\\n                                    }\\n                                }\\n                            }\\n                        }\\n                    }\\n                }\\n            }\\n        }\\n\\n        if (routes[routeId] == address(0)) revert ZeroAddressNotAllowed();\\n        return routes[routeId];\\n    }\\n\\n    /// @notice fallback function to handle swap, bridge execution\\n    /// @dev ensure routeId is converted to bytes4 and sent as msg.sig in the transaction\\n    fallback() external payable {\\n        address routeAddress = addressAt(uint32(msg.sig));\\n\\n        bytes memory result;\\n\\n        assembly {\\n            // copy function selector and any arguments\\n            calldatacopy(0, 4, sub(calldatasize(), 4))\\n            // execute function call using the facet\\n            result := delegatecall(\\n                gas(),\\n                routeAddress,\\n                0,\\n                sub(calldatasize(), 4),\\n                0,\\n                0\\n            )\\n            // get any return value\\n            returndatacopy(0, 0, returndatasize())\\n            // return any return value or error back to the caller\\n            switch result\\n            case 0 {\\n                revert(0, returndatasize())\\n            }\\n            default {\\n                return(0, returndatasize())\\n            }\\n        }\\n    }\\n}\\n\"},\"src/swap/rainbow/Rainbow.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >=0.8.0;\\n\\nimport {SafeTransferLib} from \\\"lib/solmate/src/utils/SafeTransferLib.sol\\\";\\nimport {ERC20} from \\\"lib/solmate/src/tokens/ERC20.sol\\\";\\nimport \\\"../SwapImplBase.sol\\\";\\nimport {Address0Provided, SwapFailed} from \\\"../../errors/SocketErrors.sol\\\";\\nimport {RAINBOW} from \\\"../../static/RouteIdentifiers.sol\\\";\\n\\n/**\\n * @title Rainbow-Swap-Route Implementation\\n * @notice Route implementation with functions to swap tokens via Rainbow-Swap\\n * Called via SocketGateway if the routeId in the request maps to the routeId of RainbowImplementation\\n * @author Socket dot tech.\\n */\\ncontract RainbowSwapImpl is SwapImplBase {\\n    /// @notice SafeTransferLib - library for safe and optimised operations on ERC20 tokens\\n    using SafeTransferLib for ERC20;\\n\\n    bytes32 public immutable RainbowIdentifier = RAINBOW;\\n\\n    /// @notice unique name to identify the router, used to emit event upon successful bridging\\n    bytes32 public immutable NAME = keccak256(\\\"Rainbow-Router\\\");\\n\\n    /// @notice address of rainbow-swap-aggregator to swap the tokens on Chain\\n    address payable public immutable rainbowSwapAggregator;\\n\\n    /// @notice socketGatewayAddress to be initialised via storage variable SwapImplBase\\n    /// @notice rainbow swap aggregator contract is payable to allow ethereum swaps\\n    /// @dev ensure _rainbowSwapAggregator are set properly for the chainId in which the contract is being deployed\\n    constructor(\\n        address _rainbowSwapAggregator,\\n        address _socketGateway,\\n        address _socketDeployFactory\\n    ) SwapImplBase(_socketGateway, _socketDeployFactory) {\\n        rainbowSwapAggregator = payable(_rainbowSwapAggregator);\\n    }\\n\\n    receive() external payable {}\\n\\n    fallback() external payable {}\\n\\n    /**\\n     * @notice function to swap tokens on the chain and transfer to receiver address\\n     * @notice This method is payable because the caller is doing token transfer and swap operation\\n     * @param fromToken address of token being Swapped\\n     * @param toToken address of token that recipient will receive after swap\\n     * @param amount amount of fromToken being swapped\\n     * @param receiverAddress recipient-address\\n     * @param swapExtraData additional Data to perform Swap via Rainbow-Aggregator\\n     * @return swapped amount (in toToken Address)\\n     */\\n    function performAction(\\n        address fromToken,\\n        address toToken,\\n        uint256 amount,\\n        address receiverAddress,\\n        bytes calldata swapExtraData\\n    ) external payable override returns (uint256) {\\n        if (fromToken == address(0)) {\\n            revert Address0Provided();\\n        }\\n\\n        bytes memory swapCallData = abi.decode(swapExtraData, (bytes));\\n\\n        uint256 _initialBalanceTokenOut;\\n        uint256 _finalBalanceTokenOut;\\n\\n        ERC20 toTokenERC20 = ERC20(toToken);\\n        if (toToken != NATIVE_TOKEN_ADDRESS) {\\n            _initialBalanceTokenOut = toTokenERC20.balanceOf(socketGateway);\\n        } else {\\n            _initialBalanceTokenOut = address(this).balance;\\n        }\\n\\n        if (fromToken != NATIVE_TOKEN_ADDRESS) {\\n            ERC20 token = ERC20(fromToken);\\n            token.safeTransferFrom(msg.sender, socketGateway, amount);\\n            token.safeApprove(rainbowSwapAggregator, amount);\\n\\n            // solhint-disable-next-line\\n            (bool success, ) = rainbowSwapAggregator.call(swapCallData);\\n\\n            if (!success) {\\n                revert SwapFailed();\\n            }\\n\\n            token.safeApprove(rainbowSwapAggregator, 0);\\n        } else {\\n            (bool success, ) = rainbowSwapAggregator.call{value: amount}(\\n                swapCallData\\n            );\\n            if (!success) {\\n                revert SwapFailed();\\n            }\\n        }\\n\\n        if (toToken != NATIVE_TOKEN_ADDRESS) {\\n            _finalBalanceTokenOut = toTokenERC20.balanceOf(socketGateway);\\n        } else {\\n            _finalBalanceTokenOut = address(this).balance;\\n        }\\n\\n        uint256 returnAmount = _finalBalanceTokenOut - _initialBalanceTokenOut;\\n\\n        if (toToken == NATIVE_TOKEN_ADDRESS) {\\n            payable(receiverAddress).transfer(returnAmount);\\n        } else {\\n            toTokenERC20.transfer(receiverAddress, returnAmount);\\n        }\\n\\n        emit SocketSwapTokens(\\n            fromToken,\\n            toToken,\\n            returnAmount,\\n            amount,\\n            RainbowIdentifier,\\n            receiverAddress\\n        );\\n\\n        return returnAmount;\\n    }\\n\\n    /**\\n     * @notice function to swapWithIn SocketGateway - swaps tokens on the chain to socketGateway as recipient\\n     * @param fromToken token to be swapped\\n     * @param toToken token to which fromToken has to be swapped\\n     * @param amount amount of fromToken being swapped\\n     * @param swapExtraData encoded value of properties in the swapData Struct\\n     * @return swapped amount (in toToken Address)\\n     */\\n    function performActionWithIn(\\n        address fromToken,\\n        address toToken,\\n        uint256 amount,\\n        bytes calldata swapExtraData\\n    ) external payable override returns (uint256, address) {\\n        if (fromToken == address(0)) {\\n            revert Address0Provided();\\n        }\\n\\n        bytes memory swapCallData = abi.decode(swapExtraData, (bytes));\\n\\n        uint256 _initialBalanceTokenOut;\\n        uint256 _finalBalanceTokenOut;\\n\\n        ERC20 toTokenERC20 = ERC20(toToken);\\n        if (toToken != NATIVE_TOKEN_ADDRESS) {\\n            _initialBalanceTokenOut = toTokenERC20.balanceOf(socketGateway);\\n        } else {\\n            _initialBalanceTokenOut = address(this).balance;\\n        }\\n\\n        if (fromToken != NATIVE_TOKEN_ADDRESS) {\\n            ERC20 token = ERC20(fromToken);\\n            token.safeTransferFrom(msg.sender, socketGateway, amount);\\n            token.safeApprove(rainbowSwapAggregator, amount);\\n\\n            // solhint-disable-next-line\\n            (bool success, ) = rainbowSwapAggregator.call(swapCallData);\\n\\n            if (!success) {\\n                revert SwapFailed();\\n            }\\n\\n            token.safeApprove(rainbowSwapAggregator, 0);\\n        } else {\\n            (bool success, ) = rainbowSwapAggregator.call{value: amount}(\\n                swapCallData\\n            );\\n            if (!success) {\\n                revert SwapFailed();\\n            }\\n        }\\n\\n        if (toToken != NATIVE_TOKEN_ADDRESS) {\\n            _finalBalanceTokenOut = toTokenERC20.balanceOf(socketGateway);\\n        } else {\\n            _finalBalanceTokenOut = address(this).balance;\\n        }\\n\\n        uint256 returnAmount = _finalBalanceTokenOut - _initialBalanceTokenOut;\\n\\n        emit SocketSwapTokens(\\n            fromToken,\\n            toToken,\\n            returnAmount,\\n            amount,\\n            RainbowIdentifier,\\n            socketGateway\\n        );\\n\\n        return (returnAmount, toToken);\\n    }\\n}\\n\"},\"src/interfaces/ISocketBridgeBase.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.4;\\n\\ninterface ISocketBridgeBase {\\n    function killme() external;\\n}\\n\"},\"src/interfaces/ISocketRequest.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.4;\\n\\n/**\\n * @title ISocketRoute\\n * @notice Interface with Request DataStructures to invoke controller functions.\\n * @author Socket dot tech.\\n */\\ninterface ISocketRequest {\\n    struct SwapMultiBridgeRequest {\\n        uint32 swapRouteId;\\n        bytes swapImplData;\\n        uint32[] bridgeRouteIds;\\n        bytes[] bridgeImplDataItems;\\n        uint256[] bridgeRatios;\\n        bytes[] eventDataItems;\\n    }\\n\\n    // Datastructure for Refuel-Swap-Bridge function\\n    struct RefuelSwapBridgeRequest {\\n        uint32 refuelRouteId;\\n        bytes refuelData;\\n        uint32 swapRouteId;\\n        bytes swapData;\\n        uint32 bridgeRouteId;\\n        bytes bridgeData;\\n    }\\n\\n    // Datastructure for DeductFees-Swap function\\n    struct FeesTakerSwapRequest {\\n        address feesTakerAddress;\\n        address feesToken;\\n        uint256 feesAmount;\\n        uint32 routeId;\\n        bytes swapRequestData;\\n    }\\n\\n    // Datastructure for DeductFees-Bridge function\\n    struct FeesTakerBridgeRequest {\\n        address feesTakerAddress;\\n        address feesToken;\\n        uint256 feesAmount;\\n        uint32 routeId;\\n        bytes bridgeRequestData;\\n    }\\n\\n    // Datastructure for DeductFees-MultiBridge function\\n    struct FeesTakerMultiBridgeRequest {\\n        address feesTakerAddress;\\n        address feesToken;\\n        uint256 feesAmount;\\n        uint32[] bridgeRouteIds;\\n        bytes[] bridgeRequestDataItems;\\n    }\\n\\n    // Datastructure for DeductFees-Swap-Bridge function\\n    struct FeesTakerSwapBridgeRequest {\\n        address feesTakerAddress;\\n        address feesToken;\\n        uint256 feesAmount;\\n        uint32 swapRouteId;\\n        bytes swapData;\\n        uint32 bridgeRouteId;\\n        bytes bridgeData;\\n    }\\n\\n    // Datastructure for DeductFees-Refuel-Swap-Bridge function\\n    struct FeesTakerRefuelSwapBridgeRequest {\\n        address feesTakerAddress;\\n        address feesToken;\\n        uint256 feesAmount;\\n        uint32 refuelRouteId;\\n        bytes refuelData;\\n        uint32 swapRouteId;\\n        bytes swapData;\\n        uint32 bridgeRouteId;\\n        bytes bridgeData;\\n    }\\n}\\n\"},\"src/utils/Ownable.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\npragma solidity ^0.8.4;\\n\\nimport {OnlyOwner, OnlyNominee} from \\\"../errors/SocketErrors.sol\\\";\\n\\nabstract contract Ownable {\\n    address private _owner;\\n    address private _nominee;\\n\\n    event OwnerNominated(address indexed nominee);\\n    event OwnerClaimed(address indexed claimer);\\n\\n    constructor(address owner_) {\\n        _claimOwner(owner_);\\n    }\\n\\n    modifier onlyOwner() {\\n        if (msg.sender != _owner) {\\n            revert OnlyOwner();\\n        }\\n        _;\\n    }\\n\\n    function owner() public view returns (address) {\\n        return _owner;\\n    }\\n\\n    function nominee() public view returns (address) {\\n        return _nominee;\\n    }\\n\\n    function nominateOwner(address nominee_) external {\\n        if (msg.sender != _owner) {\\n            revert OnlyOwner();\\n        }\\n        _nominee = nominee_;\\n        emit OwnerNominated(_nominee);\\n    }\\n\\n    function claimOwner() external {\\n        if (msg.sender != _nominee) {\\n            revert OnlyNominee();\\n        }\\n        _claimOwner(msg.sender);\\n    }\\n\\n    function _claimOwner(address claimer_) internal {\\n        _owner = claimer_;\\n        _nominee = address(0);\\n        emit OwnerClaimed(claimer_);\\n    }\\n}\\n\"},\"lib/solmate/src/tokens/ERC20.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity >=0.8.0;\\n\\n/// @notice Modern and gas efficient ERC20 + EIP-2612 implementation.\\n/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol)\\n/// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol)\\n/// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it.\\nabstract contract ERC20 {\\n    /*//////////////////////////////////////////////////////////////\\n                                 EVENTS\\n    //////////////////////////////////////////////////////////////*/\\n\\n    event Transfer(address indexed from, address indexed to, uint256 amount);\\n\\n    event Approval(address indexed owner, address indexed spender, uint256 amount);\\n\\n    /*//////////////////////////////////////////////////////////////\\n                            METADATA STORAGE\\n    //////////////////////////////////////////////////////////////*/\\n\\n    string public name;\\n\\n    string public symbol;\\n\\n    uint8 public immutable decimals;\\n\\n    /*//////////////////////////////////////////////////////////////\\n                              ERC20 STORAGE\\n    //////////////////////////////////////////////////////////////*/\\n\\n    uint256 public totalSupply;\\n\\n    mapping(address => uint256) public balanceOf;\\n\\n    mapping(address => mapping(address => uint256)) public allowance;\\n\\n    /*//////////////////////////////////////////////////////////////\\n                            EIP-2612 STORAGE\\n    //////////////////////////////////////////////////////////////*/\\n\\n    uint256 internal immutable INITIAL_CHAIN_ID;\\n\\n    bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;\\n\\n    mapping(address => uint256) public nonces;\\n\\n    /*//////////////////////////////////////////////////////////////\\n                               CONSTRUCTOR\\n    //////////////////////////////////////////////////////////////*/\\n\\n    constructor(\\n        string memory _name,\\n        string memory _symbol,\\n        uint8 _decimals\\n    ) {\\n        name = _name;\\n        symbol = _symbol;\\n        decimals = _decimals;\\n\\n        INITIAL_CHAIN_ID = block.chainid;\\n        INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();\\n    }\\n\\n    /*//////////////////////////////////////////////////////////////\\n                               ERC20 LOGIC\\n    //////////////////////////////////////////////////////////////*/\\n\\n    function approve(address spender, uint256 amount) public virtual returns (bool) {\\n        allowance[msg.sender][spender] = amount;\\n\\n        emit Approval(msg.sender, spender, amount);\\n\\n        return true;\\n    }\\n\\n    function transfer(address to, uint256 amount) public virtual returns (bool) {\\n        balanceOf[msg.sender] -= amount;\\n\\n        // Cannot overflow because the sum of all user\\n        // balances can't exceed the max uint256 value.\\n        unchecked {\\n            balanceOf[to] += amount;\\n        }\\n\\n        emit Transfer(msg.sender, to, amount);\\n\\n        return true;\\n    }\\n\\n    function transferFrom(\\n        address from,\\n        address to,\\n        uint256 amount\\n    ) public virtual returns (bool) {\\n        uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.\\n\\n        if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;\\n\\n        balanceOf[from] -= amount;\\n\\n        // Cannot overflow because the sum of all user\\n        // balances can't exceed the max uint256 value.\\n        unchecked {\\n            balanceOf[to] += amount;\\n        }\\n\\n        emit Transfer(from, to, amount);\\n\\n        return true;\\n    }\\n\\n    /*//////////////////////////////////////////////////////////////\\n                             EIP-2612 LOGIC\\n    //////////////////////////////////////////////////////////////*/\\n\\n    function permit(\\n        address owner,\\n        address spender,\\n        uint256 value,\\n        uint256 deadline,\\n        uint8 v,\\n        bytes32 r,\\n        bytes32 s\\n    ) public virtual {\\n        require(deadline >= block.timestamp, \\\"PERMIT_DEADLINE_EXPIRED\\\");\\n\\n        // Unchecked because the only math done is incrementing\\n        // the owner's nonce which cannot realistically overflow.\\n        unchecked {\\n            address recoveredAddress = ecrecover(\\n                keccak256(\\n                    abi.encodePacked(\\n                        \\\"\\\\x19\\\\x01\\\",\\n                        DOMAIN_SEPARATOR(),\\n                        keccak256(\\n                            abi.encode(\\n                                keccak256(\\n                                    \\\"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)\\\"\\n                                ),\\n                                owner,\\n                                spender,\\n                                value,\\n                                nonces[owner]++,\\n                                deadline\\n                            )\\n                        )\\n                    )\\n                ),\\n                v,\\n                r,\\n                s\\n            );\\n\\n            require(recoveredAddress != address(0) && recoveredAddress == owner, \\\"INVALID_SIGNER\\\");\\n\\n            allowance[recoveredAddress][spender] = value;\\n        }\\n\\n        emit Approval(owner, spender, value);\\n    }\\n\\n    function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {\\n        return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();\\n    }\\n\\n    function computeDomainSeparator() internal view virtual returns (bytes32) {\\n        return\\n            keccak256(\\n                abi.encode(\\n                    keccak256(\\\"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)\\\"),\\n                    keccak256(bytes(name)),\\n                    keccak256(\\\"1\\\"),\\n                    block.chainid,\\n                    address(this)\\n                )\\n            );\\n    }\\n\\n    /*//////////////////////////////////////////////////////////////\\n                        INTERNAL MINT/BURN LOGIC\\n    //////////////////////////////////////////////////////////////*/\\n\\n    function _mint(address to, uint256 amount) internal virtual {\\n        totalSupply += amount;\\n\\n        // Cannot overflow because the sum of all user\\n        // balances can't exceed the max uint256 value.\\n        unchecked {\\n            balanceOf[to] += amount;\\n        }\\n\\n        emit Transfer(address(0), to, amount);\\n    }\\n\\n    function _burn(address from, uint256 amount) internal virtual {\\n        balanceOf[from] -= amount;\\n\\n        // Cannot underflow because a user's balance\\n        // will never be larger than the total supply.\\n        unchecked {\\n            totalSupply -= amount;\\n        }\\n\\n        emit Transfer(from, address(0), amount);\\n    }\\n}\\n\"},\"src/controllers/RefuelSwapAndBridgeController.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.4;\\n\\nimport {ISocketRequest} from \\\"../interfaces/ISocketRequest.sol\\\";\\nimport {ISocketRoute} from \\\"../interfaces/ISocketRoute.sol\\\";\\nimport {BaseController} from \\\"./BaseController.sol\\\";\\n\\n/**\\n * @title RefuelSwapAndBridge Controller Implementation\\n * @notice Controller with composed actions for Refuel,Swap and Bridge to be executed Sequentially and this is atomic\\n * @author Socket dot tech.\\n */\\ncontract RefuelSwapAndBridgeController is BaseController {\\n    /// @notice Function-selector to invoke refuel-swap-bridge function\\n    /// @dev This function selector is to be used while buidling transaction-data\\n    bytes4 public immutable REFUEL_SWAP_BRIDGE_FUNCTION_SELECTOR =\\n        bytes4(\\n            keccak256(\\n                \\\"refuelAndSwapAndBridge((uint32,bytes,uint32,bytes,uint32,bytes))\\\"\\n            )\\n        );\\n\\n    /// @notice socketGatewayAddress to be initialised via storage variable BaseController\\n    constructor(\\n        address _socketGatewayAddress\\n    ) BaseController(_socketGatewayAddress) {}\\n\\n    /**\\n     * @notice function to handle refuel followed by Swap and Bridge actions\\n     * @notice This method is payable because the caller is doing token transfer and briding operation\\n     * @param rsbRequest Request with data to execute refuel followed by swap and bridge\\n     * @return output data from bridging operation\\n     */\\n    function refuelAndSwapAndBridge(\\n        ISocketRequest.RefuelSwapBridgeRequest calldata rsbRequest\\n    ) public payable returns (bytes memory) {\\n        _executeRoute(rsbRequest.refuelRouteId, rsbRequest.refuelData);\\n\\n        // refuel is also a bridging activity via refuel-route-implementation\\n        bytes memory swapResponseData = _executeRoute(\\n            rsbRequest.swapRouteId,\\n            rsbRequest.swapData\\n        );\\n\\n        uint256 swapAmount = abi.decode(swapResponseData, (uint256));\\n\\n        //sequence of arguments for implData: amount, token, data\\n        // Bridging the swapAmount received in the preceeding step\\n        bytes memory bridgeImpldata = abi.encodeWithSelector(\\n            BRIDGE_AFTER_SWAP_SELECTOR,\\n            swapAmount,\\n            rsbRequest.bridgeData\\n        );\\n\\n        return _executeRoute(rsbRequest.bridgeRouteId, bridgeImpldata);\\n    }\\n}\\n\"},\"src/interfaces/ISocketGateway.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.4;\\n\\n/**\\n * @title ISocketGateway\\n * @notice Interface for SocketGateway functions.\\n * @dev functions can be added here for invocation from external contracts or off-chain\\n * @author Socket dot tech.\\n */\\ninterface ISocketGateway {\\n    /**\\n     * @notice Request-struct for controllerRequests\\n     * @dev ensure the value for data is generated using the function-selectors defined in the controllerImplementation contracts\\n     */\\n    struct SocketControllerRequest {\\n        // controllerId is the id mapped to the controllerAddress\\n        uint32 controllerId;\\n        // transactionImplData generated off-chain or by caller using function-selector of the controllerContract\\n        bytes data;\\n    }\\n\\n    // @notice view to get owner-address\\n    function owner() external view returns (address);\\n}\\n\"},\"src/libraries/Pb.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0-only\\n\\npragma solidity ^0.8.4;\\n\\n// runtime proto sol library\\nlibrary Pb {\\n    enum WireType {\\n        Varint,\\n        Fixed64,\\n        LengthDelim,\\n        StartGroup,\\n        EndGroup,\\n        Fixed32\\n    }\\n\\n    struct Buffer {\\n        uint256 idx; // the start index of next read. when idx=b.length, we're done\\n        bytes b; // hold serialized proto msg, readonly\\n    }\\n\\n    // create a new in-memory Buffer object from raw msg bytes\\n    function fromBytes(\\n        bytes memory raw\\n    ) internal pure returns (Buffer memory buf) {\\n        buf.b = raw;\\n        buf.idx = 0;\\n    }\\n\\n    // whether there are unread bytes\\n    function hasMore(Buffer memory buf) internal pure returns (bool) {\\n        return buf.idx < buf.b.length;\\n    }\\n\\n    // decode current field number and wiretype\\n    function decKey(\\n        Buffer memory buf\\n    ) internal pure returns (uint256 tag, WireType wiretype) {\\n        uint256 v = decVarint(buf);\\n        tag = v / 8;\\n        wiretype = WireType(v & 7);\\n    }\\n\\n    // read varint from current buf idx, move buf.idx to next read, return the int value\\n    function decVarint(Buffer memory buf) internal pure returns (uint256 v) {\\n        bytes10 tmp; // proto int is at most 10 bytes (7 bits can be used per byte)\\n        bytes memory bb = buf.b; // get buf.b mem addr to use in assembly\\n        v = buf.idx; // use v to save one additional uint variable\\n        assembly {\\n            tmp := mload(add(add(bb, 32), v)) // load 10 bytes from buf.b[buf.idx] to tmp\\n        }\\n        uint256 b; // store current byte content\\n        v = 0; // reset to 0 for return value\\n        for (uint256 i = 0; i < 10; i++) {\\n            assembly {\\n                b := byte(i, tmp) // don't use tmp[i] because it does bound check and costs extra\\n            }\\n            v |= (b & 0x7F) << (i * 7);\\n            if (b & 0x80 == 0) {\\n                buf.idx += i + 1;\\n                return v;\\n            }\\n        }\\n        revert(); // i=10, invalid varint stream\\n    }\\n\\n    // read length delimited field and return bytes\\n    function decBytes(\\n        Buffer memory buf\\n    ) internal pure returns (bytes memory b) {\\n        uint256 len = decVarint(buf);\\n        uint256 end = buf.idx + len;\\n        require(end <= buf.b.length); // avoid overflow\\n        b = new bytes(len);\\n        bytes memory bufB = buf.b; // get buf.b mem addr to use in assembly\\n        uint256 bStart;\\n        uint256 bufBStart = buf.idx;\\n        assembly {\\n            bStart := add(b, 32)\\n            bufBStart := add(add(bufB, 32), bufBStart)\\n        }\\n        for (uint256 i = 0; i < len; i += 32) {\\n            assembly {\\n                mstore(add(bStart, i), mload(add(bufBStart, i)))\\n            }\\n        }\\n        buf.idx = end;\\n    }\\n\\n    // move idx pass current value field, to beginning of next tag or msg end\\n    function skipValue(Buffer memory buf, WireType wire) internal pure {\\n        if (wire == WireType.Varint) {\\n            decVarint(buf);\\n        } else if (wire == WireType.LengthDelim) {\\n            uint256 len = decVarint(buf);\\n            buf.idx += len; // skip len bytes value data\\n            require(buf.idx <= buf.b.length); // avoid overflow\\n        } else {\\n            revert();\\n        } // unsupported wiretype\\n    }\\n\\n    function _uint256(bytes memory b) internal pure returns (uint256 v) {\\n        require(b.length <= 32); // b's length must be smaller than or equal to 32\\n        assembly {\\n            v := mload(add(b, 32))\\n        } // load all 32bytes to v\\n        v = v >> (8 * (32 - b.length)); // only first b.length is valid\\n    }\\n\\n    function _address(bytes memory b) internal pure returns (address v) {\\n        v = _addressPayable(b);\\n    }\\n\\n    function _addressPayable(\\n        bytes memory b\\n    ) internal pure returns (address payable v) {\\n        require(b.length == 20);\\n        //load 32bytes then shift right 12 bytes\\n        assembly {\\n            v := div(mload(add(b, 32)), 0x1000000000000000000000000)\\n        }\\n    }\\n\\n    function _bytes32(bytes memory b) internal pure returns (bytes32 v) {\\n        require(b.length == 32);\\n        assembly {\\n            v := mload(add(b, 32))\\n        }\\n    }\\n}\\n\"},\"src/bridges/BridgeImplBase.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.4;\\n\\nimport {SafeTransferLib} from \\\"lib/solmate/src/utils/SafeTransferLib.sol\\\";\\nimport {ERC20} from \\\"lib/solmate/src/tokens/ERC20.sol\\\";\\nimport {ISocketGateway} from \\\"../interfaces/ISocketGateway.sol\\\";\\nimport {ISocketRoute} from \\\"../interfaces/ISocketRoute.sol\\\";\\nimport {OnlySocketGatewayOwner, OnlySocketDeployer} from \\\"../errors/SocketErrors.sol\\\";\\n\\n/**\\n * @title Abstract Implementation Contract.\\n * @notice All Bridge Implementation will follow this interface.\\n */\\nabstract contract BridgeImplBase {\\n    /// @notice SafeTransferLib - library for safe and optimised operations on ERC20 tokens\\n    using SafeTransferLib for ERC20;\\n\\n    /// @notice Address used to identify if it is a native token transfer or not\\n    address public immutable NATIVE_TOKEN_ADDRESS =\\n        address(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE);\\n\\n    /// @notice immutable variable to store the socketGateway address\\n    address public immutable socketGateway;\\n\\n    /// @notice immutable variable to store the socketGateway address\\n    address public immutable socketDeployFactory;\\n\\n    /// @notice immutable variable with instance of SocketRoute to access route functions\\n    ISocketRoute public immutable socketRoute;\\n\\n    /// @notice FunctionSelector used to delegatecall from swap to the function of bridge router implementation\\n    bytes4 public immutable BRIDGE_AFTER_SWAP_SELECTOR =\\n        bytes4(keccak256(\\\"bridgeAfterSwap(uint256,bytes)\\\"));\\n\\n    /****************************************\\n     *               EVENTS                 *\\n     ****************************************/\\n\\n    event SocketBridge(\\n        uint256 amount,\\n        address token,\\n        uint256 toChainId,\\n        bytes32 bridgeName,\\n        address sender,\\n        address receiver,\\n        bytes32 metadata\\n    );\\n\\n    /**\\n     * @notice Construct the base for all BridgeImplementations.\\n     * @param _socketGateway Socketgateway address, an immutable variable to set.\\n     * @param _socketDeployFactory Socket Deploy Factory address, an immutable variable to set.\\n     */\\n    constructor(address _socketGateway, address _socketDeployFactory) {\\n        socketGateway = _socketGateway;\\n        socketDeployFactory = _socketDeployFactory;\\n        socketRoute = ISocketRoute(_socketGateway);\\n    }\\n\\n    /****************************************\\n     *               MODIFIERS              *\\n     ****************************************/\\n\\n    /// @notice Implementing contract needs to make use of the modifier where restricted access is to be used\\n    modifier isSocketGatewayOwner() {\\n        if (msg.sender != ISocketGateway(socketGateway).owner()) {\\n            revert OnlySocketGatewayOwner();\\n        }\\n        _;\\n    }\\n\\n    /// @notice Implementing contract needs to make use of the modifier where restricted access is to be used\\n    modifier isSocketDeployFactory() {\\n        if (msg.sender != socketDeployFactory) {\\n            revert OnlySocketDeployer();\\n        }\\n        _;\\n    }\\n\\n    /****************************************\\n     *    RESTRICTED FUNCTIONS              *\\n     ****************************************/\\n\\n    /**\\n     * @notice function to rescue the ERC20 tokens in the bridge Implementation contract\\n     * @notice this is a function restricted to Owner of SocketGateway only\\n     * @param token address of ERC20 token being rescued\\n     * @param userAddress receipient address to which ERC20 tokens will be rescued to\\n     * @param amount amount of ERC20 tokens being rescued\\n     */\\n    function rescueFunds(\\n        address token,\\n        address userAddress,\\n        uint256 amount\\n    ) external isSocketGatewayOwner {\\n        ERC20(token).safeTransfer(userAddress, amount);\\n    }\\n\\n    /**\\n     * @notice function to rescue the native-balance in the bridge Implementation contract\\n     * @notice this is a function restricted to Owner of SocketGateway only\\n     * @param userAddress receipient address to which native-balance will be rescued to\\n     * @param amount amount of native balance tokens being rescued\\n     */\\n    function rescueEther(\\n        address payable userAddress,\\n        uint256 amount\\n    ) external isSocketGatewayOwner {\\n        userAddress.transfer(amount);\\n    }\\n\\n    function killme() external isSocketDeployFactory {\\n        selfdestruct(payable(msg.sender));\\n    }\\n\\n    /******************************\\n     *    VIRTUAL FUNCTIONS       *\\n     *****************************/\\n\\n    /**\\n     * @notice function to bridge which is succeeding the swap function\\n     * @notice this function is to be used only when bridging as a succeeding step\\n     * @notice All bridge implementation contracts must implement this function\\n     * @notice bridge-implementations will have a bridge specific struct with properties used in bridging\\n     * @param bridgeData encoded value of properties in the bridgeData Struct\\n     */\\n    function bridgeAfterSwap(\\n        uint256 amount,\\n        bytes calldata bridgeData\\n    ) external payable virtual;\\n}\\n\"},\"src/bridges/cbridge/CelerImpl.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.4;\\n\\nimport \\\"../../libraries/Pb.sol\\\";\\nimport {SafeTransferLib} from \\\"lib/solmate/src/utils/SafeTransferLib.sol\\\";\\nimport {ERC20} from \\\"lib/solmate/src/tokens/ERC20.sol\\\";\\nimport \\\"./interfaces/cbridge.sol\\\";\\nimport \\\"./interfaces/ICelerStorageWrapper.sol\\\";\\nimport {TransferIdExists, InvalidCelerRefund, CelerAlreadyRefunded, CelerRefundNotReady} from \\\"../../errors/SocketErrors.sol\\\";\\nimport {BridgeImplBase} from \\\"../BridgeImplBase.sol\\\";\\nimport {CBRIDGE} from \\\"../../static/RouteIdentifiers.sol\\\";\\n\\n/**\\n * @title Celer-Route Implementation\\n * @notice Route implementation with functions to bridge ERC20 and Native via Celer-Bridge\\n * Called via SocketGateway if the routeId in the request maps to the routeId of CelerImplementation\\n * Contains function to handle bridging as post-step i.e linked to a preceeding step for swap\\n * RequestData is different to just bride and bridging chained with swap\\n * @author Socket dot tech.\\n */\\ncontract CelerImpl is BridgeImplBase {\\n    /// @notice SafeTransferLib - library for safe and optimised operations on ERC20 tokens\\n    using SafeTransferLib for ERC20;\\n\\n    bytes32 public immutable CBridgeIdentifier = CBRIDGE;\\n\\n    /// @notice Utility to perform operation on Buffer\\n    using Pb for Pb.Buffer;\\n\\n    /// @notice Function-selector for ERC20-token bridging on Celer-Route\\n    /// @dev This function selector is to be used while building transaction-data to bridge ERC20 tokens\\n    bytes4 public immutable CELER_ERC20_EXTERNAL_BRIDGE_FUNCTION_SELECTOR =\\n        bytes4(\\n            keccak256(\\n                \\\"bridgeERC20To(address,address,uint256,bytes32,uint64,uint64,uint32)\\\"\\n            )\\n        );\\n\\n    /// @notice Function-selector for Native bridging on Celer-Route\\n    /// @dev This function selector is to be used while building transaction-data to bridge Native tokens\\n    bytes4 public immutable CELER_NATIVE_EXTERNAL_BRIDGE_FUNCTION_SELECTOR =\\n        bytes4(\\n            keccak256(\\n                \\\"bridgeNativeTo(address,uint256,bytes32,uint64,uint64,uint32)\\\"\\n            )\\n        );\\n\\n    bytes4 public immutable CELER_SWAP_BRIDGE_SELECTOR =\\n        bytes4(\\n            keccak256(\\n                \\\"swapAndBridge(uint32,bytes,(address,uint64,uint32,uint64,bytes32))\\\"\\n            )\\n        );\\n\\n    /// @notice router Contract instance used to deposit ERC20 and Native on to Celer-Bridge\\n    /// @dev contract instance is to be initialized in the constructor using the routerAddress passed as constructor argument\\n    ICBridge public immutable router;\\n\\n    /// @notice celerStorageWrapper Contract instance used to store the transferId generated during ERC20 and Native bridge on to Celer-Bridge\\n    /// @dev contract instance is to be initialized in the constructor using the celerStorageWrapperAddress passed as constructor argument\\n    ICelerStorageWrapper public immutable celerStorageWrapper;\\n\\n    /// @notice WETH token address\\n    address public immutable weth;\\n\\n    /// @notice chainId used during generation of transferId generated while bridging ERC20 and Native on to Celer-Bridge\\n    /// @dev this is to be initialised in the constructor\\n    uint64 public immutable chainId;\\n\\n    struct WithdrawMsg {\\n        uint64 chainid; // tag: 1\\n        uint64 seqnum; // tag: 2\\n        address receiver; // tag: 3\\n        address token; // tag: 4\\n        uint256 amount; // tag: 5\\n        bytes32 refid; // tag: 6\\n    }\\n\\n    /// @notice socketGatewayAddress to be initialised via storage variable BridgeImplBase\\n    /// @dev ensure routerAddress, weth-address, celerStorageWrapperAddress are set properly for the chainId in which the contract is being deployed\\n    constructor(\\n        address _routerAddress,\\n        address _weth,\\n        address _celerStorageWrapperAddress,\\n        address _socketGateway,\\n        address _socketDeployFactory\\n    ) BridgeImplBase(_socketGateway, _socketDeployFactory) {\\n        router = ICBridge(_routerAddress);\\n        celerStorageWrapper = ICelerStorageWrapper(_celerStorageWrapperAddress);\\n        weth = _weth;\\n        chainId = uint64(block.chainid);\\n    }\\n\\n    // Function to receive Ether. msg.data must be empty\\n    receive() external payable {}\\n\\n    /// @notice Struct to be used in decode step from input parameter - a specific case of bridging after swap.\\n    /// @dev the data being encoded in offchain or by caller should have values set in this sequence of properties in this struct\\n    struct CelerBridgeDataNoToken {\\n        address receiverAddress;\\n        uint64 toChainId;\\n        uint32 maxSlippage;\\n        uint64 nonce;\\n        bytes32 metadata;\\n    }\\n\\n    struct CelerBridgeData {\\n        address token;\\n        address receiverAddress;\\n        uint64 toChainId;\\n        uint32 maxSlippage;\\n        uint64 nonce;\\n        bytes32 metadata;\\n    }\\n\\n    /**\\n     * @notice function to bridge tokens after swap.\\n     * @notice this is different from swapAndBridge, this function is called when the swap has already happened at a different place.\\n     * @notice This method is payable because the caller is doing token transfer and briding operation\\n     * @dev for usage, refer to controller implementations\\n     *      encodedData for bridge should follow the sequence of properties in CelerBridgeData struct\\n     * @param amount amount of tokens being bridged. this can be ERC20 or native\\n     * @param bridgeData encoded data for CelerBridge\\n     */\\n    function bridgeAfterSwap(\\n        uint256 amount,\\n        bytes calldata bridgeData\\n    ) external payable override {\\n        CelerBridgeData memory celerBridgeData = abi.decode(\\n            bridgeData,\\n            (CelerBridgeData)\\n        );\\n\\n        if (celerBridgeData.token == NATIVE_TOKEN_ADDRESS) {\\n            // transferId is generated using the request-params and nonce of the account\\n            // transferId should be unique for each request and this is used while handling refund from celerBridge\\n            bytes32 transferId = keccak256(\\n                abi.encodePacked(\\n                    address(this),\\n                    celerBridgeData.receiverAddress,\\n                    weth,\\n                    amount,\\n                    celerBridgeData.toChainId,\\n                    celerBridgeData.nonce,\\n                    chainId\\n                )\\n            );\\n\\n            // transferId is stored in CelerStorageWrapper with in a mapping where key is transferId and value is the msg-sender\\n            celerStorageWrapper.setAddressForTransferId(transferId, msg.sender);\\n\\n            router.sendNative{value: amount}(\\n                celerBridgeData.receiverAddress,\\n                amount,\\n                celerBridgeData.toChainId,\\n                celerBridgeData.nonce,\\n                celerBridgeData.maxSlippage\\n            );\\n        } else {\\n            // transferId is generated using the request-params and nonce of the account\\n            // transferId should be unique for each request and this is used while handling refund from celerBridge\\n            bytes32 transferId = keccak256(\\n                abi.encodePacked(\\n                    address(this),\\n                    celerBridgeData.receiverAddress,\\n                    celerBridgeData.token,\\n                    amount,\\n                    celerBridgeData.toChainId,\\n                    celerBridgeData.nonce,\\n                    chainId\\n                )\\n            );\\n\\n            // transferId is stored in CelerStorageWrapper with in a mapping where key is transferId and value is the msg-sender\\n            celerStorageWrapper.setAddressForTransferId(transferId, msg.sender);\\n            router.send(\\n                celerBridgeData.receiverAddress,\\n                celerBridgeData.token,\\n                amount,\\n                celerBridgeData.toChainId,\\n                celerBridgeData.nonce,\\n                celerBridgeData.maxSlippage\\n            );\\n        }\\n\\n        emit SocketBridge(\\n            amount,\\n            celerBridgeData.token,\\n            celerBridgeData.toChainId,\\n            CBridgeIdentifier,\\n            msg.sender,\\n            celerBridgeData.receiverAddress,\\n            celerBridgeData.metadata\\n        );\\n    }\\n\\n    /**\\n     * @notice function to bridge tokens after swap.\\n     * @notice this is different from bridgeAfterSwap since this function holds the logic for swapping tokens too.\\n     * @notice This method is payable because the caller is doing token transfer and briding operation\\n     * @dev for usage, refer to controller implementations\\n     *      encodedData for bridge should follow the sequence of properties in CelerBridgeData struct\\n     * @param swapId routeId for the swapImpl\\n     * @param swapData encoded data for swap\\n     * @param celerBridgeData encoded data for CelerBridgeData\\n     */\\n    function swapAndBridge(\\n        uint32 swapId,\\n        bytes calldata swapData,\\n        CelerBridgeDataNoToken calldata celerBridgeData\\n    ) external payable {\\n        (bool success, bytes memory result) = socketRoute\\n            .getRoute(swapId)\\n            .delegatecall(swapData);\\n\\n        if (!success) {\\n            assembly {\\n                revert(add(result, 32), mload(result))\\n            }\\n        }\\n\\n        (uint256 bridgeAmount, address token) = abi.decode(\\n            result,\\n            (uint256, address)\\n        );\\n\\n        if (token == NATIVE_TOKEN_ADDRESS) {\\n            // transferId is generated using the request-params and nonce of the account\\n            // transferId should be unique for each request and this is used while handling refund from celerBridge\\n            bytes32 transferId = keccak256(\\n                abi.encodePacked(\\n                    address(this),\\n                    celerBridgeData.receiverAddress,\\n                    weth,\\n                    bridgeAmount,\\n                    celerBridgeData.toChainId,\\n                    celerBridgeData.nonce,\\n                    chainId\\n                )\\n            );\\n\\n            // transferId is stored in CelerStorageWrapper with in a mapping where key is transferId and value is the msg-sender\\n            celerStorageWrapper.setAddressForTransferId(transferId, msg.sender);\\n\\n            router.sendNative{value: bridgeAmount}(\\n                celerBridgeData.receiverAddress,\\n                bridgeAmount,\\n                celerBridgeData.toChainId,\\n                celerBridgeData.nonce,\\n                celerBridgeData.maxSlippage\\n            );\\n        } else {\\n            // transferId is generated using the request-params and nonce of the account\\n            // transferId should be unique for each request and this is used while handling refund from celerBridge\\n            bytes32 transferId = keccak256(\\n                abi.encodePacked(\\n                    address(this),\\n                    celerBridgeData.receiverAddress,\\n                    token,\\n                    bridgeAmount,\\n                    celerBridgeData.toChainId,\\n                    celerBridgeData.nonce,\\n                    chainId\\n                )\\n            );\\n\\n            // transferId is stored in CelerStorageWrapper with in a mapping where key is transferId and value is the msg-sender\\n            celerStorageWrapper.setAddressForTransferId(transferId, msg.sender);\\n            router.send(\\n                celerBridgeData.receiverAddress,\\n                token,\\n                bridgeAmount,\\n                celerBridgeData.toChainId,\\n                celerBridgeData.nonce,\\n                celerBridgeData.maxSlippage\\n            );\\n        }\\n\\n        emit SocketBridge(\\n            bridgeAmount,\\n            token,\\n            celerBridgeData.toChainId,\\n            CBridgeIdentifier,\\n            msg.sender,\\n            celerBridgeData.receiverAddress,\\n            celerBridgeData.metadata\\n        );\\n    }\\n\\n    /**\\n     * @notice function to handle ERC20 bridging to receipent via Celer-Bridge\\n     * @notice This method is payable because the caller is doing token transfer and briding operation\\n     * @param receiverAddress address of recipient\\n     * @param token address of token being bridged\\n     * @param amount amount of token for bridging\\n     * @param toChainId destination ChainId\\n     * @param nonce nonce of the sender-account address\\n     * @param maxSlippage maximum Slippage for the bridging\\n     */\\n    function bridgeERC20To(\\n        address receiverAddress,\\n        address token,\\n        uint256 amount,\\n        bytes32 metadata,\\n        uint64 toChainId,\\n        uint64 nonce,\\n        uint32 maxSlippage\\n    ) external payable {\\n        /// @notice transferId is generated using the request-params and nonce of the account\\n        /// @notice transferId should be unique for each request and this is used while handling refund from celerBridge\\n        bytes32 transferId = keccak256(\\n            abi.encodePacked(\\n                address(this),\\n                receiverAddress,\\n                token,\\n                amount,\\n                toChainId,\\n                nonce,\\n                chainId\\n            )\\n        );\\n\\n        /// @notice stored in the CelerStorageWrapper contract\\n        celerStorageWrapper.setAddressForTransferId(transferId, msg.sender);\\n\\n        ERC20 tokenInstance = ERC20(token);\\n        tokenInstance.safeTransferFrom(msg.sender, socketGateway, amount);\\n        router.send(\\n            receiverAddress,\\n            token,\\n            amount,\\n            toChainId,\\n            nonce,\\n            maxSlippage\\n        );\\n\\n        emit SocketBridge(\\n            amount,\\n            token,\\n            toChainId,\\n            CBridgeIdentifier,\\n            msg.sender,\\n            receiverAddress,\\n            metadata\\n        );\\n    }\\n\\n    /**\\n     * @notice function to handle Native bridging to receipent via Celer-Bridge\\n     * @notice This method is payable because the caller is doing token transfer and briding operation\\n     * @param receiverAddress address of recipient\\n     * @param amount amount of token for bridging\\n     * @param toChainId destination ChainId\\n     * @param nonce nonce of the sender-account address\\n     * @param maxSlippage maximum Slippage for the bridging\\n     */\\n    function bridgeNativeTo(\\n        address receiverAddress,\\n        uint256 amount,\\n        bytes32 metadata,\\n        uint64 toChainId,\\n        uint64 nonce,\\n        uint32 maxSlippage\\n    ) external payable {\\n        bytes32 transferId = keccak256(\\n            abi.encodePacked(\\n                address(this),\\n                receiverAddress,\\n                weth,\\n                amount,\\n                toChainId,\\n                nonce,\\n                chainId\\n            )\\n        );\\n\\n        celerStorageWrapper.setAddressForTransferId(transferId, msg.sender);\\n\\n        router.sendNative{value: amount}(\\n            receiverAddress,\\n            amount,\\n            toChainId,\\n            nonce,\\n            maxSlippage\\n        );\\n\\n        emit SocketBridge(\\n            amount,\\n            NATIVE_TOKEN_ADDRESS,\\n            toChainId,\\n            CBridgeIdentifier,\\n            msg.sender,\\n            receiverAddress,\\n            metadata\\n        );\\n    }\\n\\n    /**\\n     * @notice function to handle refund from CelerBridge-Router\\n     * @param _request request data generated offchain using the celer-SDK\\n     * @param _sigs generated offchain using the celer-SDK\\n     * @param _signers  generated offchain using the celer-SDK\\n     * @param _powers generated offchain using the celer-SDK\\n     */\\n    function refundCelerUser(\\n        bytes calldata _request,\\n        bytes[] calldata _sigs,\\n        address[] calldata _signers,\\n        uint256[] calldata _powers\\n    ) external payable {\\n        WithdrawMsg memory request = decWithdrawMsg(_request);\\n        bytes32 transferId = keccak256(\\n            abi.encodePacked(\\n                request.chainid,\\n                request.seqnum,\\n                request.receiver,\\n                request.token,\\n                request.amount\\n            )\\n        );\\n        uint256 _initialNativeBalance = address(this).balance;\\n        uint256 _initialTokenBalance = ERC20(request.token).balanceOf(\\n            address(this)\\n        );\\n        if (!router.withdraws(transferId)) {\\n            router.withdraw(_request, _sigs, _signers, _powers);\\n        }\\n\\n        if (request.receiver != socketGateway) {\\n            revert InvalidCelerRefund();\\n        }\\n\\n        address _receiver = celerStorageWrapper.getAddressFromTransferId(\\n            request.refid\\n        );\\n        celerStorageWrapper.deleteTransferId(request.refid);\\n\\n        if (_receiver == address(0)) {\\n            revert CelerAlreadyRefunded();\\n        }\\n\\n        uint256 _nativeBalanceAfter = address(this).balance;\\n        uint256 _tokenBalanceAfter = ERC20(request.token).balanceOf(\\n            address(this)\\n        );\\n        if (_nativeBalanceAfter > _initialNativeBalance) {\\n            if ((_nativeBalanceAfter - _initialNativeBalance) != request.amount)\\n                revert CelerRefundNotReady();\\n            payable(_receiver).transfer(request.amount);\\n            return;\\n        }\\n\\n        if (_tokenBalanceAfter > _initialTokenBalance) {\\n            if ((_tokenBalanceAfter - _initialTokenBalance) != request.amount)\\n                revert CelerRefundNotReady();\\n            ERC20(request.token).safeTransfer(_receiver, request.amount);\\n            return;\\n        }\\n\\n        revert CelerRefundNotReady();\\n    }\\n\\n    function decWithdrawMsg(\\n        bytes memory raw\\n    ) internal pure returns (WithdrawMsg memory m) {\\n        Pb.Buffer memory buf = Pb.fromBytes(raw);\\n\\n        uint256 tag;\\n        Pb.WireType wire;\\n        while (buf.hasMore()) {\\n            (tag, wire) = buf.decKey();\\n            if (false) {}\\n            // solidity has no switch/case\\n            else if (tag == 1) {\\n                m.chainid = uint64(buf.decVarint());\\n            } else if (tag == 2) {\\n                m.seqnum = uint64(buf.decVarint());\\n            } else if (tag == 3) {\\n                m.receiver = Pb._address(buf.decBytes());\\n            } else if (tag == 4) {\\n                m.token = Pb._address(buf.decBytes());\\n            } else if (tag == 5) {\\n                m.amount = Pb._uint256(buf.decBytes());\\n            } else if (tag == 6) {\\n                m.refid = Pb._bytes32(buf.decBytes());\\n            } else {\\n                buf.skipValue(wire);\\n            } // skip value of unknown tag\\n        }\\n    } // end decoder WithdrawMsg\\n}\\n\"},\"src/libraries/LibBytes.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.4;\\n\\n// Functions taken out from https://github.com/GNSPS/solidity-bytes-utils/blob/master/contracts/BytesLib.sol\\nlibrary LibBytes {\\n    // solhint-disable no-inline-assembly\\n\\n    // LibBytes specific errors\\n    error SliceOverflow();\\n    error SliceOutOfBounds();\\n    error AddressOutOfBounds();\\n    error UintOutOfBounds();\\n\\n    // -------------------------\\n\\n    function concat(\\n        bytes memory _preBytes,\\n        bytes memory _postBytes\\n    ) internal pure returns (bytes memory) {\\n        bytes memory tempBytes;\\n\\n        assembly {\\n            // Get a location of some free memory and store it in tempBytes as\\n            // Solidity does for memory variables.\\n            tempBytes := mload(0x40)\\n\\n            // Store the length of the first bytes array at the beginning of\\n            // the memory for tempBytes.\\n            let length := mload(_preBytes)\\n            mstore(tempBytes, length)\\n\\n            // Maintain a memory counter for the current write location in the\\n            // temp bytes array by adding the 32 bytes for the array length to\\n            // the starting location.\\n            let mc := add(tempBytes, 0x20)\\n            // Stop copying when the memory counter reaches the length of the\\n            // first bytes array.\\n            let end := add(mc, length)\\n\\n            for {\\n                // Initialize a copy counter to the start of the _preBytes data,\\n                // 32 bytes into its memory.\\n                let cc := add(_preBytes, 0x20)\\n            } lt(mc, end) {\\n                // Increase both counters by 32 bytes each iteration.\\n                mc := add(mc, 0x20)\\n                cc := add(cc, 0x20)\\n            } {\\n                // Write the _preBytes data into the tempBytes memory 32 bytes\\n                // at a time.\\n                mstore(mc, mload(cc))\\n            }\\n\\n            // Add the length of _postBytes to the current length of tempBytes\\n            // and store it as the new length in the first 32 bytes of the\\n            // tempBytes memory.\\n            length := mload(_postBytes)\\n            mstore(tempBytes, add(length, mload(tempBytes)))\\n\\n            // Move the memory counter back from a multiple of 0x20 to the\\n            // actual end of the _preBytes data.\\n            mc := end\\n            // Stop copying when the memory counter reaches the new combined\\n            // length of the arrays.\\n            end := add(mc, length)\\n\\n            for {\\n                let cc := add(_postBytes, 0x20)\\n            } lt(mc, end) {\\n                mc := add(mc, 0x20)\\n                cc := add(cc, 0x20)\\n            } {\\n                mstore(mc, mload(cc))\\n            }\\n\\n            // Update the free-memory pointer by padding our last write location\\n            // to 32 bytes: add 31 bytes to the end of tempBytes to move to the\\n            // next 32 byte block, then round down to the nearest multiple of\\n            // 32. If the sum of the length of the two arrays is zero then add\\n            // one before rounding down to leave a blank 32 bytes (the length block with 0).\\n            mstore(\\n                0x40,\\n                and(\\n                    add(add(end, iszero(add(length, mload(_preBytes)))), 31),\\n                    not(31) // Round down to the nearest 32 bytes.\\n                )\\n            )\\n        }\\n\\n        return tempBytes;\\n    }\\n\\n    function slice(\\n        bytes memory _bytes,\\n        uint256 _start,\\n        uint256 _length\\n    ) internal pure returns (bytes memory) {\\n        if (_length + 31 < _length) {\\n            revert SliceOverflow();\\n        }\\n        if (_bytes.length < _start + _length) {\\n            revert SliceOutOfBounds();\\n        }\\n\\n        bytes memory tempBytes;\\n\\n        assembly {\\n            switch iszero(_length)\\n            case 0 {\\n                // Get a location of some free memory and store it in tempBytes as\\n                // Solidity does for memory variables.\\n                tempBytes := mload(0x40)\\n\\n                // The first word of the slice result is potentially a partial\\n                // word read from the original array. To read it, we calculate\\n                // the length of that partial word and start copying that many\\n                // bytes into the array. The first word we copy will start with\\n                // data we don't care about, but the last `lengthmod` bytes will\\n                // land at the beginning of the contents of the new array. When\\n                // we're done copying, we overwrite the full first word with\\n                // the actual length of the slice.\\n                let lengthmod := and(_length, 31)\\n\\n                // The multiplication in the next line is necessary\\n                // because when slicing multiples of 32 bytes (lengthmod == 0)\\n                // the following copy loop was copying the origin's length\\n                // and then ending prematurely not copying everything it should.\\n                let mc := add(\\n                    add(tempBytes, lengthmod),\\n                    mul(0x20, iszero(lengthmod))\\n                )\\n                let end := add(mc, _length)\\n\\n                for {\\n                    // The multiplication in the next line has the same exact purpose\\n                    // as the one above.\\n                    let cc := add(\\n                        add(\\n                            add(_bytes, lengthmod),\\n                            mul(0x20, iszero(lengthmod))\\n                        ),\\n                        _start\\n                    )\\n                } lt(mc, end) {\\n                    mc := add(mc, 0x20)\\n                    cc := add(cc, 0x20)\\n                } {\\n                    mstore(mc, mload(cc))\\n                }\\n\\n                mstore(tempBytes, _length)\\n\\n                //update free-memory pointer\\n                //allocating the array padded to 32 bytes like the compiler does now\\n                mstore(0x40, and(add(mc, 31), not(31)))\\n            }\\n            //if we want a zero-length slice let's just return a zero-length array\\n            default {\\n                tempBytes := mload(0x40)\\n                //zero out the 32 bytes slice we are about to return\\n                //we need to do it because Solidity does not garbage collect\\n                mstore(tempBytes, 0)\\n\\n                mstore(0x40, add(tempBytes, 0x20))\\n            }\\n        }\\n\\n        return tempBytes;\\n    }\\n}\\n\"},\"src/bridges/hyphen/interfaces/hyphen.sol\":{\"content\":\"// SPDX-License-Identifier: Apache-2.0\\npragma solidity >=0.8.0;\\n\\n/**\\n * @title HyphenLiquidityPoolManager\\n * @notice interface with functions to bridge ERC20 and Native via Hyphen-Bridge\\n * @author Socket dot tech.\\n */\\ninterface HyphenLiquidityPoolManager {\\n    /**\\n     * @dev Function used to deposit tokens into pool to initiate a cross chain token transfer.\\n     * @param toChainId Chain id where funds needs to be transfered\\n     * @param tokenAddress ERC20 Token address that needs to be transfered\\n     * @param receiver Address on toChainId where tokens needs to be transfered\\n     * @param amount Amount of token being transfered\\n     */\\n    function depositErc20(\\n        uint256 toChainId,\\n        address tokenAddress,\\n        address receiver,\\n        uint256 amount,\\n        string calldata tag\\n    ) external;\\n\\n    /**\\n     * @dev Function used to deposit native token into pool to initiate a cross chain token transfer.\\n     * @param receiver Address on toChainId where tokens needs to be transfered\\n     * @param toChainId Chain id where funds needs to be transfered\\n     */\\n    function depositNative(\\n        address receiver,\\n        uint256 toChainId,\\n        string calldata tag\\n    ) external payable;\\n}\\n\"},\"src/swap/SwapImplBase.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.4;\\n\\nimport {SafeTransferLib} from \\\"lib/solmate/src/utils/SafeTransferLib.sol\\\";\\nimport {ERC20} from \\\"lib/solmate/src/tokens/ERC20.sol\\\";\\nimport {ISocketGateway} from \\\"../interfaces/ISocketGateway.sol\\\";\\nimport {OnlySocketGatewayOwner, OnlySocketDeployer} from \\\"../errors/SocketErrors.sol\\\";\\n\\n/**\\n * @title Abstract Implementation Contract.\\n * @notice All Swap Implementation will follow this interface.\\n * @author Socket dot tech.\\n */\\nabstract contract SwapImplBase {\\n    /// @notice SafeTransferLib - library for safe and optimised operations on ERC20 tokens\\n    using SafeTransferLib for ERC20;\\n\\n    /// @notice Address used to identify if it is a native token transfer or not\\n    address public immutable NATIVE_TOKEN_ADDRESS =\\n        address(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE);\\n\\n    /// @notice immutable variable to store the socketGateway address\\n    address public immutable socketGateway;\\n\\n    /// @notice immutable variable to store the socketGateway address\\n    address public immutable socketDeployFactory;\\n\\n    /// @notice FunctionSelector used to delegatecall to the performAction function of swap-router-implementation\\n    bytes4 public immutable SWAP_FUNCTION_SELECTOR =\\n        bytes4(\\n            keccak256(\\\"performAction(address,address,uint256,address,bytes)\\\")\\n        );\\n\\n    /// @notice FunctionSelector used to delegatecall to the performActionWithIn function of swap-router-implementation\\n    bytes4 public immutable SWAP_WITHIN_FUNCTION_SELECTOR =\\n        bytes4(keccak256(\\\"performActionWithIn(address,address,uint256,bytes)\\\"));\\n\\n    /****************************************\\n     *               EVENTS                 *\\n     ****************************************/\\n\\n    event SocketSwapTokens(\\n        address fromToken,\\n        address toToken,\\n        uint256 buyAmount,\\n        uint256 sellAmount,\\n        bytes32 routeName,\\n        address receiver\\n    );\\n\\n    /**\\n     * @notice Construct the base for all SwapImplementations.\\n     * @param _socketGateway Socketgateway address, an immutable variable to set.\\n     */\\n    constructor(address _socketGateway, address _socketDeployFactory) {\\n        socketGateway = _socketGateway;\\n        socketDeployFactory = _socketDeployFactory;\\n    }\\n\\n    /****************************************\\n     *               MODIFIERS              *\\n     ****************************************/\\n\\n    /// @notice Implementing contract needs to make use of the modifier where restricted access is to be used\\n    modifier isSocketGatewayOwner() {\\n        if (msg.sender != ISocketGateway(socketGateway).owner()) {\\n            revert OnlySocketGatewayOwner();\\n        }\\n        _;\\n    }\\n\\n    /// @notice Implementing contract needs to make use of the modifier where restricted access is to be used\\n    modifier isSocketDeployFactory() {\\n        if (msg.sender != socketDeployFactory) {\\n            revert OnlySocketDeployer();\\n        }\\n        _;\\n    }\\n\\n    /****************************************\\n     *    RESTRICTED FUNCTIONS              *\\n     ****************************************/\\n\\n    /**\\n     * @notice function to rescue the ERC20 tokens in the Swap-Implementation contract\\n     * @notice this is a function restricted to Owner of SocketGateway only\\n     * @param token address of ERC20 token being rescued\\n     * @param userAddress receipient address to which ERC20 tokens will be rescued to\\n     * @param amount amount of ERC20 tokens being rescued\\n     */\\n    function rescueFunds(\\n        address token,\\n        address userAddress,\\n        uint256 amount\\n    ) external isSocketGatewayOwner {\\n        ERC20(token).safeTransfer(userAddress, amount);\\n    }\\n\\n    /**\\n     * @notice function to rescue the native-balance in the  Swap-Implementation contract\\n     * @notice this is a function restricted to Owner of SocketGateway only\\n     * @param userAddress receipient address to which native-balance will be rescued to\\n     * @param amount amount of native balance tokens being rescued\\n     */\\n    function rescueEther(\\n        address payable userAddress,\\n        uint256 amount\\n    ) external isSocketGatewayOwner {\\n        userAddress.transfer(amount);\\n    }\\n\\n    function killme() external isSocketDeployFactory {\\n        selfdestruct(payable(msg.sender));\\n    }\\n\\n    /******************************\\n     *    VIRTUAL FUNCTIONS       *\\n     *****************************/\\n\\n    /**\\n     * @notice function to swap tokens on the chain\\n     *         All swap implementation contracts must implement this function\\n     * @param fromToken token to be swapped\\n     * @param  toToken token to which fromToken has to be swapped\\n     * @param amount amount of fromToken being swapped\\n     * @param receiverAddress recipient address of toToken\\n     * @param data encoded value of properties in the swapData Struct\\n     */\\n    function performAction(\\n        address fromToken,\\n        address toToken,\\n        uint256 amount,\\n        address receiverAddress,\\n        bytes memory data\\n    ) external payable virtual returns (uint256);\\n\\n    /**\\n     * @notice function to swapWith - swaps tokens on the chain to socketGateway as recipient\\n     *         All swap implementation contracts must implement this function\\n     * @param fromToken token to be swapped\\n     * @param toToken token to which fromToken has to be swapped\\n     * @param amount amount of fromToken being swapped\\n     * @param swapExtraData encoded value of properties in the swapData Struct\\n     */\\n    function performActionWithIn(\\n        address fromToken,\\n        address toToken,\\n        uint256 amount,\\n        bytes memory swapExtraData\\n    ) external payable virtual returns (uint256, address);\\n}\\n\"},\"src/swap/zerox/ZeroXSwapImpl.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >=0.8.0;\\n\\nimport {SafeTransferLib} from \\\"lib/solmate/src/utils/SafeTransferLib.sol\\\";\\nimport {ERC20} from \\\"lib/solmate/src/tokens/ERC20.sol\\\";\\nimport \\\"../SwapImplBase.sol\\\";\\nimport {Address0Provided, SwapFailed} from \\\"../../errors/SocketErrors.sol\\\";\\nimport {ZEROX} from \\\"../../static/RouteIdentifiers.sol\\\";\\n\\n/**\\n * @title ZeroX-Swap-Route Implementation\\n * @notice Route implementation with functions to swap tokens via ZeroX-Swap\\n * Called via SocketGateway if the routeId in the request maps to the routeId of ZeroX-Swap-Implementation\\n * @author Socket dot tech.\\n */\\ncontract ZeroXSwapImpl is SwapImplBase {\\n    /// @notice SafeTransferLib - library for safe and optimised operations on ERC20 tokens\\n    using SafeTransferLib for ERC20;\\n\\n    bytes32 public immutable ZeroXIdentifier = ZEROX;\\n\\n    /// @notice unique name to identify the router, used to emit event upon successful bridging\\n    bytes32 public immutable NAME = keccak256(\\\"Zerox-Router\\\");\\n\\n    /// @notice address of ZeroX-Exchange-Proxy to swap the tokens on Chain\\n    address payable public immutable zeroXExchangeProxy;\\n\\n    /// @notice socketGatewayAddress to be initialised via storage variable SwapImplBase\\n    /// @notice ZeroXExchangeProxy contract is payable to allow ethereum swaps\\n    /// @dev ensure _zeroXExchangeProxy are set properly for the chainId in which the contract is being deployed\\n    constructor(\\n        address _zeroXExchangeProxy,\\n        address _socketGateway,\\n        address _socketDeployFactory\\n    ) SwapImplBase(_socketGateway, _socketDeployFactory) {\\n        zeroXExchangeProxy = payable(_zeroXExchangeProxy);\\n    }\\n\\n    receive() external payable {}\\n\\n    fallback() external payable {}\\n\\n    /**\\n     * @notice function to swap tokens on the chain and transfer to receiver address\\n     * @dev This is called only when there is a request for a swap.\\n     * @param fromToken token to be swapped\\n     * @param toToken token to which fromToken is to be swapped\\n     * @param amount amount to be swapped\\n     * @param receiverAddress address of toToken recipient\\n     * @param swapExtraData data required for zeroX Exchange to get the swap done\\n     */\\n    function performAction(\\n        address fromToken,\\n        address toToken,\\n        uint256 amount,\\n        address receiverAddress,\\n        bytes calldata swapExtraData\\n    ) external payable override returns (uint256) {\\n        if (fromToken == address(0)) {\\n            revert Address0Provided();\\n        }\\n\\n        bytes memory swapCallData = abi.decode(swapExtraData, (bytes));\\n\\n        uint256 _initialBalanceTokenOut;\\n        uint256 _finalBalanceTokenOut;\\n\\n        ERC20 erc20ToToken = ERC20(toToken);\\n        if (toToken != NATIVE_TOKEN_ADDRESS) {\\n            _initialBalanceTokenOut = erc20ToToken.balanceOf(address(this));\\n        } else {\\n            _initialBalanceTokenOut = address(this).balance;\\n        }\\n\\n        if (fromToken != NATIVE_TOKEN_ADDRESS) {\\n            ERC20 token = ERC20(fromToken);\\n            token.safeTransferFrom(msg.sender, address(this), amount);\\n            token.safeApprove(zeroXExchangeProxy, amount);\\n\\n            // solhint-disable-next-line\\n            (bool success, ) = zeroXExchangeProxy.call(swapCallData);\\n\\n            if (!success) {\\n                revert SwapFailed();\\n            }\\n\\n            token.safeApprove(zeroXExchangeProxy, 0);\\n        } else {\\n            (bool success, ) = zeroXExchangeProxy.call{value: amount}(\\n                swapCallData\\n            );\\n            if (!success) {\\n                revert SwapFailed();\\n            }\\n        }\\n\\n        if (toToken != NATIVE_TOKEN_ADDRESS) {\\n            _finalBalanceTokenOut = erc20ToToken.balanceOf(address(this));\\n        } else {\\n            _finalBalanceTokenOut = address(this).balance;\\n        }\\n\\n        uint256 returnAmount = _finalBalanceTokenOut - _initialBalanceTokenOut;\\n\\n        if (toToken == NATIVE_TOKEN_ADDRESS) {\\n            payable(receiverAddress).transfer(returnAmount);\\n        } else {\\n            erc20ToToken.transfer(receiverAddress, returnAmount);\\n        }\\n\\n        emit SocketSwapTokens(\\n            fromToken,\\n            toToken,\\n            returnAmount,\\n            amount,\\n            ZeroXIdentifier,\\n            receiverAddress\\n        );\\n\\n        return returnAmount;\\n    }\\n\\n    /**\\n     * @notice function to swapWithIn SocketGateway - swaps tokens on the chain to socketGateway as recipient\\n     * @param fromToken token to be swapped\\n     * @param toToken token to which fromToken has to be swapped\\n     * @param amount amount of fromToken being swapped\\n     * @param swapExtraData encoded value of properties in the swapData Struct\\n     * @return swapped amount (in toToken Address)\\n     */\\n    function performActionWithIn(\\n        address fromToken,\\n        address toToken,\\n        uint256 amount,\\n        bytes calldata swapExtraData\\n    ) external payable override returns (uint256, address) {\\n        if (fromToken == address(0)) {\\n            revert Address0Provided();\\n        }\\n\\n        bytes memory swapCallData = abi.decode(swapExtraData, (bytes));\\n\\n        uint256 _initialBalanceTokenOut;\\n        uint256 _finalBalanceTokenOut;\\n\\n        ERC20 erc20ToToken = ERC20(toToken);\\n        if (toToken != NATIVE_TOKEN_ADDRESS) {\\n            _initialBalanceTokenOut = erc20ToToken.balanceOf(address(this));\\n        } else {\\n            _initialBalanceTokenOut = address(this).balance;\\n        }\\n\\n        if (fromToken != NATIVE_TOKEN_ADDRESS) {\\n            ERC20 token = ERC20(fromToken);\\n            token.safeTransferFrom(msg.sender, address(this), amount);\\n            token.safeApprove(zeroXExchangeProxy, amount);\\n\\n            // solhint-disable-next-line\\n            (bool success, ) = zeroXExchangeProxy.call(swapCallData);\\n\\n            if (!success) {\\n                revert SwapFailed();\\n            }\\n\\n            token.safeApprove(zeroXExchangeProxy, 0);\\n        } else {\\n            (bool success, ) = zeroXExchangeProxy.call{value: amount}(\\n                swapCallData\\n            );\\n            if (!success) {\\n                revert SwapFailed();\\n            }\\n        }\\n\\n        if (toToken != NATIVE_TOKEN_ADDRESS) {\\n            _finalBalanceTokenOut = erc20ToToken.balanceOf(address(this));\\n        } else {\\n            _finalBalanceTokenOut = address(this).balance;\\n        }\\n\\n        uint256 returnAmount = _finalBalanceTokenOut - _initialBalanceTokenOut;\\n\\n        emit SocketSwapTokens(\\n            fromToken,\\n            toToken,\\n            returnAmount,\\n            amount,\\n            ZeroXIdentifier,\\n            socketGateway\\n        );\\n\\n        return (returnAmount, toToken);\\n    }\\n}\\n\"},\"src/bridges/cbridge/interfaces/cbridge.sol\":{\"content\":\"// SPDX-License-Identifier: Apache-2.0\\npragma solidity >=0.8.0;\\n\\ninterface ICBridge {\\n    function send(\\n        address _receiver,\\n        address _token,\\n        uint256 _amount,\\n        uint64 _dstChinId,\\n        uint64 _nonce,\\n        uint32 _maxSlippage\\n    ) external;\\n\\n    function sendNative(\\n        address _receiver,\\n        uint256 _amount,\\n        uint64 _dstChinId,\\n        uint64 _nonce,\\n        uint32 _maxSlippage\\n    ) external payable;\\n\\n    function withdraws(bytes32 withdrawId) external view returns (bool);\\n\\n    function withdraw(\\n        bytes calldata _wdmsg,\\n        bytes[] calldata _sigs,\\n        address[] calldata _signers,\\n        uint256[] calldata _powers\\n    ) external;\\n}\\n\"},\"src/bridges/stargate/l2/Stargate.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.4;\\n\\nimport {SafeTransferLib} from \\\"lib/solmate/src/utils/SafeTransferLib.sol\\\";\\nimport {ERC20} from \\\"lib/solmate/src/tokens/ERC20.sol\\\";\\nimport \\\"../interfaces/stargate.sol\\\";\\nimport \\\"../../../errors/SocketErrors.sol\\\";\\nimport {BridgeImplBase} from \\\"../../BridgeImplBase.sol\\\";\\nimport {STARGATE} from \\\"../../../static/RouteIdentifiers.sol\\\";\\n\\n/**\\n * @title Stargate-L2-Route Implementation\\n * @notice Route implementation with functions to bridge ERC20 and Native via Stargate-L2-Bridge\\n * Called via SocketGateway if the routeId in the request maps to the routeId of Stargate-L2-Implementation\\n * Contains function to handle bridging as post-step i.e linked to a preceeding step for swap\\n * RequestData is different to just bride and bridging chained with swap\\n * @author Socket dot tech.\\n */\\ncontract StargateImplL2 is BridgeImplBase {\\n    /// @notice SafeTransferLib - library for safe and optimised operations on ERC20 tokens\\n    using SafeTransferLib for ERC20;\\n\\n    bytes32 public immutable StargateIdentifier = STARGATE;\\n\\n    /// @notice Function-selector for ERC20-token bridging on Stargate-L2-Route\\n    /// @dev This function selector is to be used while buidling transaction-data to bridge ERC20 tokens\\n    bytes4\\n        public immutable STARGATE_L2_ERC20_EXTERNAL_BRIDGE_FUNCTION_SELECTOR =\\n        bytes4(\\n            keccak256(\\n                \\\"bridgeERC20To(address,address,address,uint256,uint256,uint256,(uint256,uint256,uint256,uint256,bytes32,bytes,uint16))\\\"\\n            )\\n        );\\n\\n    bytes4 public immutable STARGATE_L1_SWAP_BRIDGE_SELECTOR =\\n        bytes4(\\n            keccak256(\\n                \\\"swapAndBridge(uint32,bytes,(address,address,uint16,uint256,uint256,uint256,uint256,uint256,uint256,bytes32,bytes))\\\"\\n            )\\n        );\\n\\n    /// @notice Function-selector for Native bridging on Stargate-L2-Route\\n    /// @dev This function selector is to be used while buidling transaction-data to bridge Native tokens\\n    bytes4\\n        public immutable STARGATE_L2_NATIVE_EXTERNAL_BRIDGE_FUNCTION_SELECTOR =\\n        bytes4(\\n            keccak256(\\n                \\\"bridgeNativeTo(address,address,uint16,uint256,uint256,uint256,bytes32)\\\"\\n            )\\n        );\\n\\n    /// @notice Stargate Router to bridge ERC20 tokens\\n    IBridgeStargate public immutable router;\\n\\n    /// @notice Stargate Router to bridge native tokens\\n    IBridgeStargate public immutable routerETH;\\n\\n    /// @notice socketGatewayAddress to be initialised via storage variable BridgeImplBase\\n    /// @dev ensure router, routerEth are set properly for the chainId in which the contract is being deployed\\n    constructor(\\n        address _router,\\n        address _routerEth,\\n        address _socketGateway,\\n        address _socketDeployFactory\\n    ) BridgeImplBase(_socketGateway, _socketDeployFactory) {\\n        router = IBridgeStargate(_router);\\n        routerETH = IBridgeStargate(_routerEth);\\n    }\\n\\n    /// @notice Struct to be used as a input parameter for Bridging tokens via Stargate-L2-route\\n    /// @dev while building transactionData,values should be set in this sequence of properties in this struct\\n    struct StargateBridgeExtraData {\\n        uint256 srcPoolId;\\n        uint256 dstPoolId;\\n        uint256 destinationGasLimit;\\n        uint256 minReceivedAmt;\\n        bytes32 metadata;\\n        bytes destinationPayload;\\n        uint16 stargateDstChainId; // stargate defines chain id in its way\\n    }\\n\\n    /// @notice Struct to be used in decode step from input parameter - a specific case of bridging after swap.\\n    /// @dev the data being encoded in offchain or by caller should have values set in this sequence of properties in this struct\\n    struct StargateBridgeDataNoToken {\\n        address receiverAddress;\\n        address senderAddress;\\n        uint16 stargateDstChainId; // stargate defines chain id in its way\\n        uint256 value;\\n        // a unique identifier that is uses to dedup transfers\\n        // this value is the a timestamp sent from frontend, but in theory can be any unique number\\n        uint256 srcPoolId;\\n        uint256 dstPoolId;\\n        uint256 minReceivedAmt; // defines the slippage, the min qty you would accept on the destination\\n        uint256 optionalValue;\\n        uint256 destinationGasLimit;\\n        bytes32 metadata;\\n        bytes destinationPayload;\\n    }\\n\\n    struct StargateBridgeData {\\n        address token;\\n        address receiverAddress;\\n        address senderAddress;\\n        uint16 stargateDstChainId; // stargate defines chain id in its way\\n        uint256 value;\\n        // a unique identifier that is uses to dedup transfers\\n        // this value is the a timestamp sent from frontend, but in theory can be any unique number\\n        uint256 srcPoolId;\\n        uint256 dstPoolId;\\n        uint256 minReceivedAmt; // defines the slippage, the min qty you would accept on the destination\\n        uint256 optionalValue;\\n        uint256 destinationGasLimit;\\n        bytes32 metadata;\\n        bytes destinationPayload;\\n    }\\n\\n    /**\\n     * @notice function to bridge tokens after swap.\\n     * @notice this is different from swapAndBridge, this function is called when the swap has already happened at a different place.\\n     * @notice This method is payable because the caller is doing token transfer and briding operation\\n     * @dev for usage, refer to controller implementations\\n     *      encodedData for bridge should follow the sequence of properties in Stargate-BridgeData struct\\n     * @param amount amount of tokens being bridged. this can be ERC20 or native\\n     * @param bridgeData encoded data for Stargate-L1-Bridge\\n     */\\n    function bridgeAfterSwap(\\n        uint256 amount,\\n        bytes calldata bridgeData\\n    ) external payable override {\\n        StargateBridgeData memory stargateBridgeData = abi.decode(\\n            bridgeData,\\n            (StargateBridgeData)\\n        );\\n\\n        if (stargateBridgeData.token == NATIVE_TOKEN_ADDRESS) {\\n            // perform bridging\\n            routerETH.swapETH{value: amount + stargateBridgeData.optionalValue}(\\n                stargateBridgeData.stargateDstChainId,\\n                payable(stargateBridgeData.senderAddress),\\n                abi.encodePacked(stargateBridgeData.receiverAddress),\\n                amount,\\n                stargateBridgeData.minReceivedAmt\\n            );\\n        } else {\\n            ERC20(stargateBridgeData.token).safeApprove(\\n                address(router),\\n                amount\\n            );\\n            {\\n                router.swap{value: stargateBridgeData.value}(\\n                    stargateBridgeData.stargateDstChainId,\\n                    stargateBridgeData.srcPoolId,\\n                    stargateBridgeData.dstPoolId,\\n                    payable(stargateBridgeData.senderAddress), // default to refund to main contract\\n                    amount,\\n                    stargateBridgeData.minReceivedAmt,\\n                    IBridgeStargate.lzTxObj(\\n                        stargateBridgeData.destinationGasLimit,\\n                        0, // zero amount since this is a ERC20 bridging\\n                        \\\"0x\\\" //empty data since this is for only ERC20\\n                    ),\\n                    abi.encodePacked(stargateBridgeData.receiverAddress),\\n                    stargateBridgeData.destinationPayload\\n                );\\n            }\\n        }\\n\\n        emit SocketBridge(\\n            amount,\\n            stargateBridgeData.token,\\n            stargateBridgeData.stargateDstChainId,\\n            StargateIdentifier,\\n            msg.sender,\\n            stargateBridgeData.receiverAddress,\\n            stargateBridgeData.metadata\\n        );\\n    }\\n\\n    /**\\n     * @notice function to bridge tokens after swapping.\\n     * @notice this is different from bridgeAfterSwap since this function holds the logic for swapping tokens too.\\n     * @notice This method is payable because the caller is doing token transfer and briding operation\\n     * @dev for usage, refer to controller implementations\\n     *      encodedData for bridge should follow the sequence of properties in Stargate-BridgeData struct\\n     * @param swapId routeId for the swapImpl\\n     * @param swapData encoded data for swap\\n     * @param stargateBridgeData encoded data for StargateBridgeData\\n     */\\n    function swapAndBridge(\\n        uint32 swapId,\\n        bytes calldata swapData,\\n        StargateBridgeDataNoToken calldata stargateBridgeData\\n    ) external payable {\\n        (bool success, bytes memory result) = socketRoute\\n            .getRoute(swapId)\\n            .delegatecall(swapData);\\n\\n        if (!success) {\\n            assembly {\\n                revert(add(result, 32), mload(result))\\n            }\\n        }\\n\\n        (uint256 bridgeAmount, address token) = abi.decode(\\n            result,\\n            (uint256, address)\\n        );\\n\\n        if (token == NATIVE_TOKEN_ADDRESS) {\\n            routerETH.swapETH{\\n                value: bridgeAmount + stargateBridgeData.optionalValue\\n            }(\\n                stargateBridgeData.stargateDstChainId,\\n                payable(stargateBridgeData.senderAddress),\\n                abi.encodePacked(stargateBridgeData.receiverAddress),\\n                bridgeAmount,\\n                stargateBridgeData.minReceivedAmt\\n            );\\n        } else {\\n            ERC20(token).safeApprove(address(router), bridgeAmount);\\n            {\\n                router.swap{value: stargateBridgeData.value}(\\n                    stargateBridgeData.stargateDstChainId,\\n                    stargateBridgeData.srcPoolId,\\n                    stargateBridgeData.dstPoolId,\\n                    payable(stargateBridgeData.senderAddress), // default to refund to main contract\\n                    bridgeAmount,\\n                    stargateBridgeData.minReceivedAmt,\\n                    IBridgeStargate.lzTxObj(\\n                        stargateBridgeData.destinationGasLimit,\\n                        0,\\n                        \\\"0x\\\"\\n                    ),\\n                    abi.encodePacked(stargateBridgeData.receiverAddress),\\n                    stargateBridgeData.destinationPayload\\n                );\\n            }\\n        }\\n\\n        emit SocketBridge(\\n            bridgeAmount,\\n            token,\\n            stargateBridgeData.stargateDstChainId,\\n            StargateIdentifier,\\n            msg.sender,\\n            stargateBridgeData.receiverAddress,\\n            stargateBridgeData.metadata\\n        );\\n    }\\n\\n    /**\\n     * @notice function to handle ERC20 bridging to receipent via Stargate-L1-Bridge\\n     * @notice This method is payable because the caller is doing token transfer and briding operation\\n     * @param token address of token being bridged\\n     * @param senderAddress address of sender\\n     * @param receiverAddress address of recipient\\n     * @param amount amount of token being bridge\\n     * @param value value\\n     * @param optionalValue optionalValue\\n     * @param stargateBridgeExtraData stargate bridge extradata\\n     */\\n    function bridgeERC20To(\\n        address token,\\n        address senderAddress,\\n        address receiverAddress,\\n        uint256 amount,\\n        uint256 value,\\n        uint256 optionalValue,\\n        StargateBridgeExtraData calldata stargateBridgeExtraData\\n    ) external payable {\\n        // token address might not be indication thats why passed through extraData\\n        if (token == NATIVE_TOKEN_ADDRESS) {\\n            // perform bridging\\n            routerETH.swapETH{value: amount + optionalValue}(\\n                stargateBridgeExtraData.stargateDstChainId,\\n                payable(senderAddress),\\n                abi.encodePacked(receiverAddress),\\n                amount,\\n                stargateBridgeExtraData.minReceivedAmt\\n            );\\n        } else {\\n            ERC20 tokenInstance = ERC20(token);\\n            tokenInstance.safeTransferFrom(msg.sender, socketGateway, amount);\\n            tokenInstance.safeApprove(address(router), amount);\\n            {\\n                router.swap{value: value}(\\n                    stargateBridgeExtraData.stargateDstChainId,\\n                    stargateBridgeExtraData.srcPoolId,\\n                    stargateBridgeExtraData.dstPoolId,\\n                    payable(senderAddress), // default to refund to main contract\\n                    amount,\\n                    stargateBridgeExtraData.minReceivedAmt,\\n                    IBridgeStargate.lzTxObj(\\n                        stargateBridgeExtraData.destinationGasLimit,\\n                        0, // zero amount since this is a ERC20 bridging\\n                        \\\"0x\\\" //empty data since this is for only ERC20\\n                    ),\\n                    abi.encodePacked(receiverAddress),\\n                    stargateBridgeExtraData.destinationPayload\\n                );\\n            }\\n        }\\n\\n        emit SocketBridge(\\n            amount,\\n            token,\\n            stargateBridgeExtraData.stargateDstChainId,\\n            StargateIdentifier,\\n            msg.sender,\\n            receiverAddress,\\n            stargateBridgeExtraData.metadata\\n        );\\n    }\\n\\n    function bridgeNativeTo(\\n        address receiverAddress,\\n        address senderAddress,\\n        uint16 stargateDstChainId,\\n        uint256 amount,\\n        uint256 minReceivedAmt,\\n        uint256 optionalValue,\\n        bytes32 metadata\\n    ) external payable {\\n        // perform bridging\\n        routerETH.swapETH{value: amount + optionalValue}(\\n            stargateDstChainId,\\n            payable(senderAddress),\\n            abi.encodePacked(receiverAddress),\\n            amount,\\n            minReceivedAmt\\n        );\\n\\n        emit SocketBridge(\\n            amount,\\n            NATIVE_TOKEN_ADDRESS,\\n            stargateDstChainId,\\n            StargateIdentifier,\\n            msg.sender,\\n            receiverAddress,\\n            metadata\\n        );\\n    }\\n}\\n\"}},\"settings\":{\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"outputSelection\":{\"*\":{\"*\":[\"evm.bytecode\",\"evm.deployedBytecode\",\"devdoc\",\"userdoc\",\"metadata\",\"abi\"]}},\"metadata\":{\"useLiteralContent\":true},\"libraries\":{}}},\"ABI\":\"[{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"_owner\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"_disabledRoute\\\",\\\"type\\\":\\\"address\\\"}],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"constructor\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"ArrayLengthMismatch\\\",\\\"type\\\":\\\"error\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"IncorrectBridgeRatios\\\",\\\"type\\\":\\\"error\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"OnlyNominee\\\",\\\"type\\\":\\\"error\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"OnlyOwner\\\",\\\"type\\\":\\\"error\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"ZeroAddressNotAllowed\\\",\\\"type\\\":\\\"error\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":true,\\\"internalType\\\":\\\"uint32\\\",\\\"name\\\":\\\"controllerId\\\",\\\"type\\\":\\\"uint32\\\"},{\\\"indexed\\\":true,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"controllerAddress\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"ControllerAdded\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":true,\\\"internalType\\\":\\\"uint32\\\",\\\"name\\\":\\\"controllerId\\\",\\\"type\\\":\\\"uint32\\\"}],\\\"name\\\":\\\"ControllerDisabled\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":true,\\\"internalType\\\":\\\"uint32\\\",\\\"name\\\":\\\"routeId\\\",\\\"type\\\":\\\"uint32\\\"},{\\\"indexed\\\":true,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"route\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"NewRouteAdded\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":true,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"claimer\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"OwnerClaimed\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":true,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"nominee\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"OwnerNominated\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":true,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"_from\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":true,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"_to\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"OwnershipTransferRequested\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":true,\\\"internalType\\\":\\\"uint32\\\",\\\"name\\\":\\\"routeId\\\",\\\"type\\\":\\\"uint32\\\"}],\\\"name\\\":\\\"RouteDisabled\\\",\\\"type\\\":\\\"event\\\"},{\\\"stateMutability\\\":\\\"payable\\\",\\\"type\\\":\\\"fallback\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"BRIDGE_AFTER_SWAP_SELECTOR\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"bytes4\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"bytes4\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"CENT_PERCENT\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"controllerAddress\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"addController\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint32\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint32\\\"}],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"routeAddress\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"addRoute\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint32\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint32\\\"}],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"uint32\\\",\\\"name\\\":\\\"routeId\\\",\\\"type\\\":\\\"uint32\\\"}],\\\"name\\\":\\\"addressAt\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"address\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"claimOwner\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"controllerCount\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint32\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint32\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"uint32\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint32\\\"}],\\\"name\\\":\\\"controllers\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"address\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"uint32\\\",\\\"name\\\":\\\"controllerId\\\",\\\"type\\\":\\\"uint32\\\"}],\\\"name\\\":\\\"disableController\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"uint32\\\",\\\"name\\\":\\\"routeId\\\",\\\"type\\\":\\\"uint32\\\"}],\\\"name\\\":\\\"disableRoute\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"disabledRouteAddress\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"address\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"components\\\":[{\\\"internalType\\\":\\\"uint32\\\",\\\"name\\\":\\\"controllerId\\\",\\\"type\\\":\\\"uint32\\\"},{\\\"internalType\\\":\\\"bytes\\\",\\\"name\\\":\\\"data\\\",\\\"type\\\":\\\"bytes\\\"}],\\\"internalType\\\":\\\"struct ISocketGateway.SocketControllerRequest\\\",\\\"name\\\":\\\"socketControllerRequest\\\",\\\"type\\\":\\\"tuple\\\"}],\\\"name\\\":\\\"executeController\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"bytes\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"bytes\\\"}],\\\"stateMutability\\\":\\\"payable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"components\\\":[{\\\"internalType\\\":\\\"uint32\\\",\\\"name\\\":\\\"controllerId\\\",\\\"type\\\":\\\"uint32\\\"},{\\\"internalType\\\":\\\"bytes\\\",\\\"name\\\":\\\"data\\\",\\\"type\\\":\\\"bytes\\\"}],\\\"internalType\\\":\\\"struct ISocketGateway.SocketControllerRequest[]\\\",\\\"name\\\":\\\"controllerRequests\\\",\\\"type\\\":\\\"tuple[]\\\"}],\\\"name\\\":\\\"executeControllers\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"payable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"uint32\\\",\\\"name\\\":\\\"routeId\\\",\\\"type\\\":\\\"uint32\\\"},{\\\"internalType\\\":\\\"bytes\\\",\\\"name\\\":\\\"routeData\\\",\\\"type\\\":\\\"bytes\\\"}],\\\"name\\\":\\\"executeRoute\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"bytes\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"bytes\\\"}],\\\"stateMutability\\\":\\\"payable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"uint32[]\\\",\\\"name\\\":\\\"routeIds\\\",\\\"type\\\":\\\"uint32[]\\\"},{\\\"internalType\\\":\\\"bytes[]\\\",\\\"name\\\":\\\"dataItems\\\",\\\"type\\\":\\\"bytes[]\\\"}],\\\"name\\\":\\\"executeRoutes\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"payable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"uint32\\\",\\\"name\\\":\\\"controllerId\\\",\\\"type\\\":\\\"uint32\\\"}],\\\"name\\\":\\\"getController\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"address\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"uint32\\\",\\\"name\\\":\\\"routeId\\\",\\\"type\\\":\\\"uint32\\\"}],\\\"name\\\":\\\"getRoute\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"address\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"nominee_\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"nominateOwner\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"nominee\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"address\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"owner\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"address\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address payable\\\",\\\"name\\\":\\\"userAddress\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"amount\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"rescueEther\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"token\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"userAddress\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"amount\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"rescueFunds\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"uint32\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint32\\\"}],\\\"name\\\":\\\"routes\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"address\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"routesCount\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint32\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint32\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address[]\\\",\\\"name\\\":\\\"routeAddresses\\\",\\\"type\\\":\\\"address[]\\\"},{\\\"internalType\\\":\\\"address[]\\\",\\\"name\\\":\\\"tokenAddresses\\\",\\\"type\\\":\\\"address[]\\\"},{\\\"internalType\\\":\\\"bool\\\",\\\"name\\\":\\\"isMax\\\",\\\"type\\\":\\\"bool\\\"}],\\\"name\\\":\\\"setApprovalForRouters\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"components\\\":[{\\\"internalType\\\":\\\"uint32\\\",\\\"name\\\":\\\"swapRouteId\\\",\\\"type\\\":\\\"uint32\\\"},{\\\"internalType\\\":\\\"bytes\\\",\\\"name\\\":\\\"swapImplData\\\",\\\"type\\\":\\\"bytes\\\"},{\\\"internalType\\\":\\\"uint32[]\\\",\\\"name\\\":\\\"bridgeRouteIds\\\",\\\"type\\\":\\\"uint32[]\\\"},{\\\"internalType\\\":\\\"bytes[]\\\",\\\"name\\\":\\\"bridgeImplDataItems\\\",\\\"type\\\":\\\"bytes[]\\\"},{\\\"internalType\\\":\\\"uint256[]\\\",\\\"name\\\":\\\"bridgeRatios\\\",\\\"type\\\":\\\"uint256[]\\\"},{\\\"internalType\\\":\\\"bytes[]\\\",\\\"name\\\":\\\"eventDataItems\\\",\\\"type\\\":\\\"bytes[]\\\"}],\\\"internalType\\\":\\\"struct ISocketRequest.SwapMultiBridgeRequest\\\",\\\"name\\\":\\\"swapMultiBridgeRequest\\\",\\\"type\\\":\\\"tuple\\\"}],\\\"name\\\":\\\"swapAndMultiBridge\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"payable\\\",\\\"type\\\":\\\"function\\\"},{\\\"stateMutability\\\":\\\"payable\\\",\\\"type\\\":\\\"receive\\\"}]\",\"ContractName\":\"SocketGateway\",\"CompilerVersion\":\"v0.8.7+commit.e28d00a7\",\"OptimizationUsed\":1,\"Runs\":1000000,\"ConstructorArguments\":\"0x000000000000000000000000e8dd38e673a93ccfc2e3d7053efccb5c93f493650000000000000000000000000f34a522ff82151c90679b73211955068fd854f1\",\"EVMVersion\":\"Default\",\"Library\":\"\",\"LicenseType\":\"\",\"Proxy\":1,\"Implementation\":\"0xa3c4e32af0da5efaddb20cc9fb26159f55c8c42f\",\"SwarmSource\":\"\"}]"
  },
  {
    "path": "testdata/etherscan/0x71356E37e0368Bd10bFDbF41dC052fE5FA24cD05/creation_data.json",
    "content": "{\"contractAddress\":\"0x71356e37e0368bd10bfdbf41dc052fe5fa24cd05\",\"contractCreator\":\"0xaa1d342354d755ec515f40e7d5e83cb4184bb9ee\",\"txHash\":\"0x1c800c2c2d5230823602cae6896a8db1ab7d1341ca697c6c64d9f0edf11dabe2\"}"
  },
  {
    "path": "testdata/etherscan/0x71356E37e0368Bd10bFDbF41dC052fE5FA24cD05/metadata.json",
    "content": "[{\"SourceCode\":{\"language\":\"Solidity\",\"sources\":{\"@openzeppelin/contracts/access/IAccessControl.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev External interface of AccessControl declared to support ERC165 detection.\\n */\\ninterface IAccessControl {\\n    /**\\n     * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\\n     *\\n     * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\\n     * {RoleAdminChanged} not being emitted signaling this.\\n     *\\n     * _Available since v3.1._\\n     */\\n    event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\\n\\n    /**\\n     * @dev Emitted when `account` is granted `role`.\\n     *\\n     * `sender` is the account that originated the contract call, an admin role\\n     * bearer except when using {AccessControl-_setupRole}.\\n     */\\n    event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\\n\\n    /**\\n     * @dev Emitted when `account` is revoked `role`.\\n     *\\n     * `sender` is the account that originated the contract call:\\n     *   - if using `revokeRole`, it is the admin role bearer\\n     *   - if using `renounceRole`, it is the role bearer (i.e. `account`)\\n     */\\n    event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\\n\\n    /**\\n     * @dev Returns `true` if `account` has been granted `role`.\\n     */\\n    function hasRole(bytes32 role, address account) external view returns (bool);\\n\\n    /**\\n     * @dev Returns the admin role that controls `role`. See {grantRole} and\\n     * {revokeRole}.\\n     *\\n     * To change a role's admin, use {AccessControl-_setRoleAdmin}.\\n     */\\n    function getRoleAdmin(bytes32 role) external view returns (bytes32);\\n\\n    /**\\n     * @dev Grants `role` to `account`.\\n     *\\n     * If `account` had not been already granted `role`, emits a {RoleGranted}\\n     * event.\\n     *\\n     * Requirements:\\n     *\\n     * - the caller must have ``role``'s admin role.\\n     */\\n    function grantRole(bytes32 role, address account) external;\\n\\n    /**\\n     * @dev Revokes `role` from `account`.\\n     *\\n     * If `account` had been granted `role`, emits a {RoleRevoked} event.\\n     *\\n     * Requirements:\\n     *\\n     * - the caller must have ``role``'s admin role.\\n     */\\n    function revokeRole(bytes32 role, address account) external;\\n\\n    /**\\n     * @dev Revokes `role` from the calling account.\\n     *\\n     * Roles are often managed via {grantRole} and {revokeRole}: this function's\\n     * purpose is to provide a mechanism for accounts to lose their privileges\\n     * if they are compromised (such as when a trusted device is misplaced).\\n     *\\n     * If the calling account had been granted `role`, emits a {RoleRevoked}\\n     * event.\\n     *\\n     * Requirements:\\n     *\\n     * - the caller must be `account`.\\n     */\\n    function renounceRole(bytes32 role, address account) external;\\n}\\n\"},\"@openzeppelin/contracts/token/ERC721/IERC721.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC721/IERC721.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../../utils/introspection/IERC165.sol\\\";\\n\\n/**\\n * @dev Required interface of an ERC721 compliant contract.\\n */\\ninterface IERC721 is IERC165 {\\n    /**\\n     * @dev Emitted when `tokenId` token is transferred from `from` to `to`.\\n     */\\n    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);\\n\\n    /**\\n     * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.\\n     */\\n    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);\\n\\n    /**\\n     * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.\\n     */\\n    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);\\n\\n    /**\\n     * @dev Returns the number of tokens in ``owner``'s account.\\n     */\\n    function balanceOf(address owner) external view returns (uint256 balance);\\n\\n    /**\\n     * @dev Returns the owner of the `tokenId` token.\\n     *\\n     * Requirements:\\n     *\\n     * - `tokenId` must exist.\\n     */\\n    function ownerOf(uint256 tokenId) external view returns (address owner);\\n\\n    /**\\n     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients\\n     * are aware of the ERC721 protocol to prevent tokens from being forever locked.\\n     *\\n     * Requirements:\\n     *\\n     * - `from` cannot be the zero address.\\n     * - `to` cannot be the zero address.\\n     * - `tokenId` token must exist and be owned by `from`.\\n     * - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}.\\n     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\\n     *\\n     * Emits a {Transfer} event.\\n     */\\n    function safeTransferFrom(\\n        address from,\\n        address to,\\n        uint256 tokenId\\n    ) external;\\n\\n    /**\\n     * @dev Transfers `tokenId` token from `from` to `to`.\\n     *\\n     * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.\\n     *\\n     * Requirements:\\n     *\\n     * - `from` cannot be the zero address.\\n     * - `to` cannot be the zero address.\\n     * - `tokenId` token must be owned by `from`.\\n     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\\n     *\\n     * Emits a {Transfer} event.\\n     */\\n    function transferFrom(\\n        address from,\\n        address to,\\n        uint256 tokenId\\n    ) external;\\n\\n    /**\\n     * @dev Gives permission to `to` to transfer `tokenId` token to another account.\\n     * The approval is cleared when the token is transferred.\\n     *\\n     * Only a single account can be approved at a time, so approving the zero address clears previous approvals.\\n     *\\n     * Requirements:\\n     *\\n     * - The caller must own the token or be an approved operator.\\n     * - `tokenId` must exist.\\n     *\\n     * Emits an {Approval} event.\\n     */\\n    function approve(address to, uint256 tokenId) external;\\n\\n    /**\\n     * @dev Returns the account approved for `tokenId` token.\\n     *\\n     * Requirements:\\n     *\\n     * - `tokenId` must exist.\\n     */\\n    function getApproved(uint256 tokenId) external view returns (address operator);\\n\\n    /**\\n     * @dev Approve or remove `operator` as an operator for the caller.\\n     * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.\\n     *\\n     * Requirements:\\n     *\\n     * - The `operator` cannot be the caller.\\n     *\\n     * Emits an {ApprovalForAll} event.\\n     */\\n    function setApprovalForAll(address operator, bool _approved) external;\\n\\n    /**\\n     * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.\\n     *\\n     * See {setApprovalForAll}\\n     */\\n    function isApprovedForAll(address owner, address operator) external view returns (bool);\\n\\n    /**\\n     * @dev Safely transfers `tokenId` token from `from` to `to`.\\n     *\\n     * Requirements:\\n     *\\n     * - `from` cannot be the zero address.\\n     * - `to` cannot be the zero address.\\n     * - `tokenId` token must exist and be owned by `from`.\\n     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\\n     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\\n     *\\n     * Emits a {Transfer} event.\\n     */\\n    function safeTransferFrom(\\n        address from,\\n        address to,\\n        uint256 tokenId,\\n        bytes calldata data\\n    ) external;\\n}\\n\"},\"@openzeppelin/contracts/access/IAccessControlEnumerable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (access/IAccessControlEnumerable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IAccessControl.sol\\\";\\n\\n/**\\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\\n */\\ninterface IAccessControlEnumerable is IAccessControl {\\n    /**\\n     * @dev Returns one of the accounts that have `role`. `index` must be a\\n     * value between 0 and {getRoleMemberCount}, non-inclusive.\\n     *\\n     * Role bearers are not sorted in any particular way, and their ordering may\\n     * change at any point.\\n     *\\n     * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\\n     * you perform all queries on the same block. See the following\\n     * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\\n     * for more information.\\n     */\\n    function getRoleMember(bytes32 role, uint256 index) external view returns (address);\\n\\n    /**\\n     * @dev Returns the number of accounts that have `role`. Can be used\\n     * together with {getRoleMember} to enumerate all bearers of a role.\\n     */\\n    function getRoleMemberCount(bytes32 role) external view returns (uint256);\\n}\\n\"},\"@openzeppelin/contracts/utils/StorageSlot.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/StorageSlot.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Library for reading and writing primitive types to specific storage slots.\\n *\\n * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.\\n * This library helps with reading and writing to such slots without the need for inline assembly.\\n *\\n * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.\\n *\\n * Example usage to set ERC1967 implementation slot:\\n * ```\\n * contract ERC1967 {\\n *     bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\\n *\\n *     function _getImplementation() internal view returns (address) {\\n *         return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;\\n *     }\\n *\\n *     function _setImplementation(address newImplementation) internal {\\n *         require(Address.isContract(newImplementation), \\\"ERC1967: new implementation is not a contract\\\");\\n *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;\\n *     }\\n * }\\n * ```\\n *\\n * _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._\\n */\\nlibrary StorageSlot {\\n    struct AddressSlot {\\n        address value;\\n    }\\n\\n    struct BooleanSlot {\\n        bool value;\\n    }\\n\\n    struct Bytes32Slot {\\n        bytes32 value;\\n    }\\n\\n    struct Uint256Slot {\\n        uint256 value;\\n    }\\n\\n    /**\\n     * @dev Returns an `AddressSlot` with member `value` located at `slot`.\\n     */\\n    function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {\\n        assembly {\\n            r.slot := slot\\n        }\\n    }\\n\\n    /**\\n     * @dev Returns an `BooleanSlot` with member `value` located at `slot`.\\n     */\\n    function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {\\n        assembly {\\n            r.slot := slot\\n        }\\n    }\\n\\n    /**\\n     * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.\\n     */\\n    function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {\\n        assembly {\\n            r.slot := slot\\n        }\\n    }\\n\\n    /**\\n     * @dev Returns an `Uint256Slot` with member `value` located at `slot`.\\n     */\\n    function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {\\n        assembly {\\n            r.slot := slot\\n        }\\n    }\\n}\\n\"},\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../Strings.sol\\\";\\n\\n/**\\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\\n *\\n * These functions can be used to verify that a message was signed by the holder\\n * of the private keys of a given address.\\n */\\nlibrary ECDSA {\\n    enum RecoverError {\\n        NoError,\\n        InvalidSignature,\\n        InvalidSignatureLength,\\n        InvalidSignatureS,\\n        InvalidSignatureV\\n    }\\n\\n    function _throwError(RecoverError error) private pure {\\n        if (error == RecoverError.NoError) {\\n            return; // no error: do nothing\\n        } else if (error == RecoverError.InvalidSignature) {\\n            revert(\\\"ECDSA: invalid signature\\\");\\n        } else if (error == RecoverError.InvalidSignatureLength) {\\n            revert(\\\"ECDSA: invalid signature length\\\");\\n        } else if (error == RecoverError.InvalidSignatureS) {\\n            revert(\\\"ECDSA: invalid signature 's' value\\\");\\n        } else if (error == RecoverError.InvalidSignatureV) {\\n            revert(\\\"ECDSA: invalid signature 'v' value\\\");\\n        }\\n    }\\n\\n    /**\\n     * @dev Returns the address that signed a hashed message (`hash`) with\\n     * `signature` or error string. This address can then be used for verification purposes.\\n     *\\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n     * this function rejects them by requiring the `s` value to be in the lower\\n     * half order, and the `v` value to be either 27 or 28.\\n     *\\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n     * verification to be secure: it is possible to craft signatures that\\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n     * this is by receiving a hash of the original message (which may otherwise\\n     * be too long), and then calling {toEthSignedMessageHash} on it.\\n     *\\n     * Documentation for signature generation:\\n     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\\n     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\\n     *\\n     * _Available since v4.3._\\n     */\\n    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\\n        // Check the signature length\\n        // - case 65: r,s,v signature (standard)\\n        // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\\n        if (signature.length == 65) {\\n            bytes32 r;\\n            bytes32 s;\\n            uint8 v;\\n            // ecrecover takes the signature parameters, and the only way to get them\\n            // currently is to use assembly.\\n            assembly {\\n                r := mload(add(signature, 0x20))\\n                s := mload(add(signature, 0x40))\\n                v := byte(0, mload(add(signature, 0x60)))\\n            }\\n            return tryRecover(hash, v, r, s);\\n        } else if (signature.length == 64) {\\n            bytes32 r;\\n            bytes32 vs;\\n            // ecrecover takes the signature parameters, and the only way to get them\\n            // currently is to use assembly.\\n            assembly {\\n                r := mload(add(signature, 0x20))\\n                vs := mload(add(signature, 0x40))\\n            }\\n            return tryRecover(hash, r, vs);\\n        } else {\\n            return (address(0), RecoverError.InvalidSignatureLength);\\n        }\\n    }\\n\\n    /**\\n     * @dev Returns the address that signed a hashed message (`hash`) with\\n     * `signature`. This address can then be used for verification purposes.\\n     *\\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n     * this function rejects them by requiring the `s` value to be in the lower\\n     * half order, and the `v` value to be either 27 or 28.\\n     *\\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n     * verification to be secure: it is possible to craft signatures that\\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n     * this is by receiving a hash of the original message (which may otherwise\\n     * be too long), and then calling {toEthSignedMessageHash} on it.\\n     */\\n    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\\n        (address recovered, RecoverError error) = tryRecover(hash, signature);\\n        _throwError(error);\\n        return recovered;\\n    }\\n\\n    /**\\n     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\\n     *\\n     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\\n     *\\n     * _Available since v4.3._\\n     */\\n    function tryRecover(\\n        bytes32 hash,\\n        bytes32 r,\\n        bytes32 vs\\n    ) internal pure returns (address, RecoverError) {\\n        bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\\n        uint8 v = uint8((uint256(vs) >> 255) + 27);\\n        return tryRecover(hash, v, r, s);\\n    }\\n\\n    /**\\n     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\\n     *\\n     * _Available since v4.2._\\n     */\\n    function recover(\\n        bytes32 hash,\\n        bytes32 r,\\n        bytes32 vs\\n    ) internal pure returns (address) {\\n        (address recovered, RecoverError error) = tryRecover(hash, r, vs);\\n        _throwError(error);\\n        return recovered;\\n    }\\n\\n    /**\\n     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\\n     * `r` and `s` signature fields separately.\\n     *\\n     * _Available since v4.3._\\n     */\\n    function tryRecover(\\n        bytes32 hash,\\n        uint8 v,\\n        bytes32 r,\\n        bytes32 s\\n    ) internal pure returns (address, RecoverError) {\\n        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\\n        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\\n        // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\\n        // signatures from current libraries generate a unique signature with an s-value in the lower half order.\\n        //\\n        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\\n        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\\n        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\\n        // these malleable signatures as well.\\n        if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\\n            return (address(0), RecoverError.InvalidSignatureS);\\n        }\\n        if (v != 27 && v != 28) {\\n            return (address(0), RecoverError.InvalidSignatureV);\\n        }\\n\\n        // If the signature is valid (and not malleable), return the signer address\\n        address signer = ecrecover(hash, v, r, s);\\n        if (signer == address(0)) {\\n            return (address(0), RecoverError.InvalidSignature);\\n        }\\n\\n        return (signer, RecoverError.NoError);\\n    }\\n\\n    /**\\n     * @dev Overload of {ECDSA-recover} that receives the `v`,\\n     * `r` and `s` signature fields separately.\\n     */\\n    function recover(\\n        bytes32 hash,\\n        uint8 v,\\n        bytes32 r,\\n        bytes32 s\\n    ) internal pure returns (address) {\\n        (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\\n        _throwError(error);\\n        return recovered;\\n    }\\n\\n    /**\\n     * @dev Returns an Ethereum Signed Message, created from a `hash`. This\\n     * produces hash corresponding to the one signed with the\\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n     * JSON-RPC method as part of EIP-191.\\n     *\\n     * See {recover}.\\n     */\\n    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\\n        // 32 is the length in bytes of hash,\\n        // enforced by the type signature above\\n        return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n32\\\", hash));\\n    }\\n\\n    /**\\n     * @dev Returns an Ethereum Signed Message, created from `s`. This\\n     * produces hash corresponding to the one signed with the\\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n     * JSON-RPC method as part of EIP-191.\\n     *\\n     * See {recover}.\\n     */\\n    function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\\n        return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n\\\", Strings.toString(s.length), s));\\n    }\\n\\n    /**\\n     * @dev Returns an Ethereum Signed Typed Data, created from a\\n     * `domainSeparator` and a `structHash`. This produces hash corresponding\\n     * to the one signed with the\\n     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\\n     * JSON-RPC method as part of EIP-712.\\n     *\\n     * See {recover}.\\n     */\\n    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\\n        return keccak256(abi.encodePacked(\\\"\\\\x19\\\\x01\\\", domainSeparator, structHash));\\n    }\\n}\\n\"},\"contracts/v0.8/extensions/GatewayV2.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport \\\"@openzeppelin/contracts/security/Pausable.sol\\\";\\nimport \\\"../interfaces/IQuorum.sol\\\";\\nimport \\\"../interfaces/IWeightedValidator.sol\\\";\\nimport \\\"./HasProxyAdmin.sol\\\";\\n\\nabstract contract GatewayV2 is HasProxyAdmin, Pausable, IQuorum {\\n  /// @dev Emitted when the validator contract address is updated.\\n  event ValidatorContractUpdated(IWeightedValidator);\\n\\n  uint256 internal _num;\\n  uint256 internal _denom;\\n\\n  IWeightedValidator public validatorContract;\\n  uint256 public nonce;\\n\\n  /**\\n   * @dev This empty reserved space is put in place to allow future versions to add new\\n   * variables without shifting down storage in the inheritance chain.\\n   */\\n  uint256[50] private ______gap;\\n\\n  /**\\n   * @dev See {IQuorum-getThreshold}.\\n   */\\n  function getThreshold() external view virtual returns (uint256, uint256) {\\n    return (_num, _denom);\\n  }\\n\\n  /**\\n   * @dev See {IQuorum-checkThreshold}.\\n   */\\n  function checkThreshold(uint256 _voteWeight) external view virtual returns (bool) {\\n    return _voteWeight * _denom >= _num * validatorContract.totalWeights();\\n  }\\n\\n  /**\\n   * @dev See {IQuorum-setThreshold}.\\n   */\\n  function setThreshold(uint256 _numerator, uint256 _denominator)\\n    external\\n    virtual\\n    onlyAdmin\\n    returns (uint256, uint256)\\n  {\\n    return _setThreshold(_numerator, _denominator);\\n  }\\n\\n  /**\\n   * @dev Triggers paused state.\\n   */\\n  function pause() external onlyAdmin {\\n    _pause();\\n  }\\n\\n  /**\\n   * @dev Triggers unpaused state.\\n   */\\n  function unpause() external onlyAdmin {\\n    _unpause();\\n  }\\n\\n  /**\\n   * @dev Sets validator contract address.\\n   *\\n   * Requirements:\\n   * - The method caller is admin.\\n   *\\n   * Emits the `ValidatorContractUpdated` event.\\n   *\\n   */\\n  function setValidatorContract(IWeightedValidator _validatorContract) external virtual onlyAdmin {\\n    _setValidatorContract(_validatorContract);\\n  }\\n\\n  /**\\n   * @dev See {IQuorum-minimumVoteWeight}.\\n   */\\n  function minimumVoteWeight() public view virtual returns (uint256) {\\n    return _minimumVoteWeight(validatorContract.totalWeights());\\n  }\\n\\n  /**\\n   * @dev Sets validator contract address.\\n   *\\n   * Emits the `ValidatorContractUpdated` event.\\n   *\\n   */\\n  function _setValidatorContract(IWeightedValidator _validatorContract) internal virtual {\\n    validatorContract = _validatorContract;\\n    emit ValidatorContractUpdated(_validatorContract);\\n  }\\n\\n  /**\\n   * @dev Sets threshold and returns the old one.\\n   *\\n   * Emits the `ThresholdUpdated` event.\\n   *\\n   */\\n  function _setThreshold(uint256 _numerator, uint256 _denominator)\\n    internal\\n    virtual\\n    returns (uint256 _previousNum, uint256 _previousDenom)\\n  {\\n    require(_numerator <= _denominator, \\\"GatewayV2: invalid threshold\\\");\\n    _previousNum = _num;\\n    _previousDenom = _denom;\\n    _num = _numerator;\\n    _denom = _denominator;\\n    emit ThresholdUpdated(nonce++, _numerator, _denominator, _previousNum, _previousDenom);\\n  }\\n\\n  /**\\n   * @dev Returns minimum vote weight.\\n   */\\n  function _minimumVoteWeight(uint256 _totalWeight) internal view virtual returns (uint256) {\\n    return (_num * _totalWeight + _denom - 1) / _denom;\\n  }\\n}\\n\"},\"@openzeppelin/contracts/proxy/utils/Initializable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (proxy/utils/Initializable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../../utils/Address.sol\\\";\\n\\n/**\\n * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed\\n * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an\\n * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer\\n * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.\\n *\\n * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as\\n * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.\\n *\\n * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure\\n * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.\\n *\\n * [CAUTION]\\n * ====\\n * Avoid leaving a contract uninitialized.\\n *\\n * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation\\n * contract, which may impact the proxy. To initialize the implementation contract, you can either invoke the\\n * initializer manually, or you can include a constructor to automatically mark it as initialized when it is deployed:\\n *\\n * [.hljs-theme-light.nopadding]\\n * ```\\n * /// @custom:oz-upgrades-unsafe-allow constructor\\n * constructor() initializer {}\\n * ```\\n * ====\\n */\\nabstract contract Initializable {\\n    /**\\n     * @dev Indicates that the contract has been initialized.\\n     */\\n    bool private _initialized;\\n\\n    /**\\n     * @dev Indicates that the contract is in the process of being initialized.\\n     */\\n    bool private _initializing;\\n\\n    /**\\n     * @dev Modifier to protect an initializer function from being invoked twice.\\n     */\\n    modifier initializer() {\\n        // If the contract is initializing we ignore whether _initialized is set in order to support multiple\\n        // inheritance patterns, but we only do this in the context of a constructor, because in other contexts the\\n        // contract may have been reentered.\\n        require(_initializing ? _isConstructor() : !_initialized, \\\"Initializable: contract is already initialized\\\");\\n\\n        bool isTopLevelCall = !_initializing;\\n        if (isTopLevelCall) {\\n            _initializing = true;\\n            _initialized = true;\\n        }\\n\\n        _;\\n\\n        if (isTopLevelCall) {\\n            _initializing = false;\\n        }\\n    }\\n\\n    /**\\n     * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the\\n     * {initializer} modifier, directly or indirectly.\\n     */\\n    modifier onlyInitializing() {\\n        require(_initializing, \\\"Initializable: contract is not initializing\\\");\\n        _;\\n    }\\n\\n    function _isConstructor() private view returns (bool) {\\n        return !Address.isContract(address(this));\\n    }\\n}\\n\"},\"contracts/v0.8/extensions/WithdrawalLimitation.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport \\\"./GatewayV2.sol\\\";\\n\\nabstract contract WithdrawalLimitation is GatewayV2 {\\n  /// @dev Emitted when the high-tier vote weight threshold is updated\\n  event HighTierVoteWeightThresholdUpdated(\\n    uint256 indexed nonce,\\n    uint256 indexed numerator,\\n    uint256 indexed denominator,\\n    uint256 previousNumerator,\\n    uint256 previousDenominator\\n  );\\n  /// @dev Emitted when the thresholds for high-tier withdrawals that requires high-tier vote weights are updated\\n  event HighTierThresholdsUpdated(address[] tokens, uint256[] thresholds);\\n  /// @dev Emitted when the thresholds for locked withdrawals are updated\\n  event LockedThresholdsUpdated(address[] tokens, uint256[] thresholds);\\n  /// @dev Emitted when the fee percentages to unlock withdraw are updated\\n  event UnlockFeePercentagesUpdated(address[] tokens, uint256[] percentages);\\n  /// @dev Emitted when the daily limit thresholds are updated\\n  event DailyWithdrawalLimitsUpdated(address[] tokens, uint256[] limits);\\n\\n  uint256 public constant _MAX_PERCENTAGE = 1_000_000;\\n\\n  uint256 internal _highTierVWNum;\\n  uint256 internal _highTierVWDenom;\\n\\n  /// @dev Mapping from mainchain token => the amount thresholds for high-tier withdrawals that requires high-tier vote weights\\n  mapping(address => uint256) public highTierThreshold;\\n  /// @dev Mapping from mainchain token => the amount thresholds to lock withdrawal\\n  mapping(address => uint256) public lockedThreshold;\\n  /// @dev Mapping from mainchain token => unlock fee percentages for unlocker\\n  /// @notice Values 0-1,000,000 map to 0%-100%\\n  mapping(address => uint256) public unlockFeePercentages;\\n  /// @dev Mapping from mainchain token => daily limit amount for withdrawal\\n  mapping(address => uint256) public dailyWithdrawalLimit;\\n  /// @dev Mapping from token address => today withdrawal amount\\n  mapping(address => uint256) public lastSyncedWithdrawal;\\n  /// @dev Mapping from token address => last date synced to record the `lastSyncedWithdrawal`\\n  mapping(address => uint256) public lastDateSynced;\\n\\n  /**\\n   * @dev This empty reserved space is put in place to allow future versions to add new\\n   * variables without shifting down storage in the inheritance chain.\\n   */\\n  uint256[50] private ______gap;\\n\\n  /**\\n   * @dev Override {GatewayV2-setThreshold}.\\n   *\\n   * Requirements:\\n   * - The high-tier vote weight threshold must equal to or larger than the normal threshold.\\n   *\\n   */\\n  function setThreshold(uint256 _numerator, uint256 _denominator)\\n    external\\n    virtual\\n    override\\n    onlyAdmin\\n    returns (uint256 _previousNum, uint256 _previousDenom)\\n  {\\n    (_previousNum, _previousDenom) = _setThreshold(_numerator, _denominator);\\n    _verifyThresholds();\\n  }\\n\\n  /**\\n   * @dev Returns the high-tier vote weight threshold.\\n   */\\n  function getHighTierVoteWeightThreshold() external view virtual returns (uint256, uint256) {\\n    return (_highTierVWNum, _highTierVWDenom);\\n  }\\n\\n  /**\\n   * @dev Checks whether the `_voteWeight` passes the high-tier vote weight threshold.\\n   */\\n  function checkHighTierVoteWeightThreshold(uint256 _voteWeight) external view virtual returns (bool) {\\n    return _voteWeight * _highTierVWDenom >= _highTierVWNum * validatorContract.totalWeights();\\n  }\\n\\n  /**\\n   * @dev Sets high-tier vote weight threshold and returns the old one.\\n   *\\n   * Requirements:\\n   * - The method caller is admin.\\n   * - The high-tier vote weight threshold must equal to or larger than the normal threshold.\\n   *\\n   * Emits the `HighTierVoteWeightThresholdUpdated` event.\\n   *\\n   */\\n  function setHighTierVoteWeightThreshold(uint256 _numerator, uint256 _denominator)\\n    external\\n    virtual\\n    onlyAdmin\\n    returns (uint256 _previousNum, uint256 _previousDenom)\\n  {\\n    (_previousNum, _previousDenom) = _setHighTierVoteWeightThreshold(_numerator, _denominator);\\n    _verifyThresholds();\\n  }\\n\\n  /**\\n   * @dev Sets the thresholds for high-tier withdrawals that requires high-tier vote weights.\\n   *\\n   * Requirements:\\n   * - The method caller is admin.\\n   * - The arrays have the same length and its length larger than 0.\\n   *\\n   * Emits the `HighTierThresholdsUpdated` event.\\n   *\\n   */\\n  function setHighTierThresholds(address[] calldata _tokens, uint256[] calldata _thresholds)\\n    external\\n    virtual\\n    onlyAdmin\\n  {\\n    require(_tokens.length > 0, \\\"WithdrawalLimitation: invalid array length\\\");\\n    _setHighTierThresholds(_tokens, _thresholds);\\n  }\\n\\n  /**\\n   * @dev Sets the amount thresholds to lock withdrawal.\\n   *\\n   * Requirements:\\n   * - The method caller is admin.\\n   * - The arrays have the same length and its length larger than 0.\\n   *\\n   * Emits the `LockedThresholdsUpdated` event.\\n   *\\n   */\\n  function setLockedThresholds(address[] calldata _tokens, uint256[] calldata _thresholds) external virtual onlyAdmin {\\n    require(_tokens.length > 0, \\\"WithdrawalLimitation: invalid array length\\\");\\n    _setLockedThresholds(_tokens, _thresholds);\\n  }\\n\\n  /**\\n   * @dev Sets fee percentages to unlock withdrawal.\\n   *\\n   * Requirements:\\n   * - The method caller is admin.\\n   * - The arrays have the same length and its length larger than 0.\\n   *\\n   * Emits the `UnlockFeePercentagesUpdated` event.\\n   *\\n   */\\n  function setUnlockFeePercentages(address[] calldata _tokens, uint256[] calldata _percentages)\\n    external\\n    virtual\\n    onlyAdmin\\n  {\\n    require(_tokens.length > 0, \\\"WithdrawalLimitation: invalid array length\\\");\\n    _setUnlockFeePercentages(_tokens, _percentages);\\n  }\\n\\n  /**\\n   * @dev Sets daily limit amounts for the withdrawals.\\n   *\\n   * Requirements:\\n   * - The method caller is admin.\\n   * - The arrays have the same length and its length larger than 0.\\n   *\\n   * Emits the `DailyWithdrawalLimitsUpdated` event.\\n   *\\n   */\\n  function setDailyWithdrawalLimits(address[] calldata _tokens, uint256[] calldata _limits) external virtual onlyAdmin {\\n    require(_tokens.length > 0, \\\"WithdrawalLimitation: invalid array length\\\");\\n    _setDailyWithdrawalLimits(_tokens, _limits);\\n  }\\n\\n  /**\\n   * @dev Checks whether the withdrawal reaches the limitation.\\n   */\\n  function reachedWithdrawalLimit(address _token, uint256 _quantity) external view virtual returns (bool) {\\n    return _reachedWithdrawalLimit(_token, _quantity);\\n  }\\n\\n  /**\\n   * @dev Sets high-tier vote weight threshold and returns the old one.\\n   *\\n   * Emits the `HighTierVoteWeightThresholdUpdated` event.\\n   *\\n   */\\n  function _setHighTierVoteWeightThreshold(uint256 _numerator, uint256 _denominator)\\n    internal\\n    returns (uint256 _previousNum, uint256 _previousDenom)\\n  {\\n    require(_numerator <= _denominator, \\\"WithdrawalLimitation: invalid threshold\\\");\\n    _previousNum = _highTierVWNum;\\n    _previousDenom = _highTierVWDenom;\\n    _highTierVWNum = _numerator;\\n    _highTierVWDenom = _denominator;\\n    emit HighTierVoteWeightThresholdUpdated(nonce++, _numerator, _denominator, _previousNum, _previousDenom);\\n  }\\n\\n  /**\\n   * @dev Sets the thresholds for high-tier withdrawals that requires high-tier vote weights.\\n   *\\n   * Requirements:\\n   * - The array lengths are equal.\\n   *\\n   * Emits the `HighTierThresholdsUpdated` event.\\n   *\\n   */\\n  function _setHighTierThresholds(address[] calldata _tokens, uint256[] calldata _thresholds) internal virtual {\\n    require(_tokens.length == _thresholds.length, \\\"WithdrawalLimitation: invalid array length\\\");\\n    for (uint256 _i; _i < _tokens.length; _i++) {\\n      highTierThreshold[_tokens[_i]] = _thresholds[_i];\\n    }\\n    emit HighTierThresholdsUpdated(_tokens, _thresholds);\\n  }\\n\\n  /**\\n   * @dev Sets the amount thresholds to lock withdrawal.\\n   *\\n   * Requirements:\\n   * - The array lengths are equal.\\n   *\\n   * Emits the `LockedThresholdsUpdated` event.\\n   *\\n   */\\n  function _setLockedThresholds(address[] calldata _tokens, uint256[] calldata _thresholds) internal virtual {\\n    require(_tokens.length == _thresholds.length, \\\"WithdrawalLimitation: invalid array length\\\");\\n    for (uint256 _i; _i < _tokens.length; _i++) {\\n      lockedThreshold[_tokens[_i]] = _thresholds[_i];\\n    }\\n    emit LockedThresholdsUpdated(_tokens, _thresholds);\\n  }\\n\\n  /**\\n   * @dev Sets fee percentages to unlock withdrawal.\\n   *\\n   * Requirements:\\n   * - The array lengths are equal.\\n   * - The percentage is equal to or less than 100_000.\\n   *\\n   * Emits the `UnlockFeePercentagesUpdated` event.\\n   *\\n   */\\n  function _setUnlockFeePercentages(address[] calldata _tokens, uint256[] calldata _percentages) internal virtual {\\n    require(_tokens.length == _percentages.length, \\\"WithdrawalLimitation: invalid array length\\\");\\n    for (uint256 _i; _i < _tokens.length; _i++) {\\n      require(_percentages[_i] <= _MAX_PERCENTAGE, \\\"WithdrawalLimitation: invalid percentage\\\");\\n      unlockFeePercentages[_tokens[_i]] = _percentages[_i];\\n    }\\n    emit UnlockFeePercentagesUpdated(_tokens, _percentages);\\n  }\\n\\n  /**\\n   * @dev Sets daily limit amounts for the withdrawals.\\n   *\\n   * Requirements:\\n   * - The array lengths are equal.\\n   *\\n   * Emits the `DailyWithdrawalLimitsUpdated` event.\\n   *\\n   */\\n  function _setDailyWithdrawalLimits(address[] calldata _tokens, uint256[] calldata _limits) internal virtual {\\n    require(_tokens.length == _limits.length, \\\"WithdrawalLimitation: invalid array length\\\");\\n    for (uint256 _i; _i < _tokens.length; _i++) {\\n      dailyWithdrawalLimit[_tokens[_i]] = _limits[_i];\\n    }\\n    emit DailyWithdrawalLimitsUpdated(_tokens, _limits);\\n  }\\n\\n  /**\\n   * @dev Checks whether the withdrawal reaches the daily limitation.\\n   *\\n   * Requirements:\\n   * - The daily withdrawal threshold should not apply for locked withdrawals.\\n   *\\n   */\\n  function _reachedWithdrawalLimit(address _token, uint256 _quantity) internal view virtual returns (bool) {\\n    if (_lockedWithdrawalRequest(_token, _quantity)) {\\n      return false;\\n    }\\n\\n    uint256 _currentDate = block.timestamp / 1 days;\\n    if (_currentDate > lastDateSynced[_token]) {\\n      return dailyWithdrawalLimit[_token] <= _quantity;\\n    } else {\\n      return dailyWithdrawalLimit[_token] <= lastSyncedWithdrawal[_token] + _quantity;\\n    }\\n  }\\n\\n  /**\\n   * @dev Record withdrawal token.\\n   */\\n  function _recordWithdrawal(address _token, uint256 _quantity) internal virtual {\\n    uint256 _currentDate = block.timestamp / 1 days;\\n    if (_currentDate > lastDateSynced[_token]) {\\n      lastDateSynced[_token] = _currentDate;\\n      lastSyncedWithdrawal[_token] = _quantity;\\n    } else {\\n      lastSyncedWithdrawal[_token] += _quantity;\\n    }\\n  }\\n\\n  /**\\n   * @dev Returns whether the withdrawal request is locked or not.\\n   */\\n  function _lockedWithdrawalRequest(address _token, uint256 _quantity) internal view virtual returns (bool) {\\n    return lockedThreshold[_token] <= _quantity;\\n  }\\n\\n  /**\\n   * @dev Computes fee percentage.\\n   */\\n  function _computeFeePercentage(uint256 _amount, uint256 _percentage) internal view virtual returns (uint256) {\\n    return (_amount * _percentage) / _MAX_PERCENTAGE;\\n  }\\n\\n  /**\\n   * @dev Returns high-tier vote weight.\\n   */\\n  function _highTierVoteWeight(uint256 _totalWeight) internal view virtual returns (uint256) {\\n    return (_highTierVWNum * _totalWeight + _highTierVWDenom - 1) / _highTierVWDenom;\\n  }\\n\\n  /**\\n   * @dev Validates whether the high-tier vote weight threshold is larger than the normal threshold.\\n   */\\n  function _verifyThresholds() internal view {\\n    require(_num * _highTierVWDenom <= _highTierVWNum * _denom, \\\"WithdrawalLimitation: invalid thresholds\\\");\\n  }\\n}\\n\"},\"contracts/v0.8/interfaces/MappedTokenConsumer.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport \\\"../library/Token.sol\\\";\\n\\ninterface MappedTokenConsumer {\\n  struct MappedToken {\\n    Token.Standard erc;\\n    address tokenAddr;\\n  }\\n}\\n\"},\"contracts/v0.8/library/Token.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC721/IERC721.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/Strings.sol\\\";\\nimport \\\"../interfaces/IWETH.sol\\\";\\n\\nlibrary Token {\\n  enum Standard {\\n    ERC20,\\n    ERC721\\n  }\\n  struct Info {\\n    Standard erc;\\n    // For ERC20:  the id must be 0 and the quantity is larger than 0.\\n    // For ERC721: the quantity must be 0.\\n    uint256 id;\\n    uint256 quantity;\\n  }\\n\\n  // keccak256(\\\"TokenInfo(uint8 erc,uint256 id,uint256 quantity)\\\");\\n  bytes32 public constant INFO_TYPE_HASH = 0x1e2b74b2a792d5c0f0b6e59b037fa9d43d84fbb759337f0112fcc15ca414fc8d;\\n\\n  /**\\n   * @dev Returns token info struct hash.\\n   */\\n  function hash(Info memory _info) internal pure returns (bytes32) {\\n    return keccak256(abi.encode(INFO_TYPE_HASH, _info.erc, _info.id, _info.quantity));\\n  }\\n\\n  /**\\n   * @dev Validates the token info.\\n   */\\n  function validate(Info memory _info) internal pure {\\n    require(\\n      (_info.erc == Standard.ERC20 && _info.quantity > 0 && _info.id == 0) ||\\n        (_info.erc == Standard.ERC721 && _info.quantity == 0),\\n      \\\"Token: invalid info\\\"\\n    );\\n  }\\n\\n  /**\\n   * @dev Transfer asset from.\\n   *\\n   * Requirements:\\n   * - The `_from` address must approve for the contract using this library.\\n   *\\n   */\\n  function transferFrom(\\n    Info memory _info,\\n    address _from,\\n    address _to,\\n    address _token\\n  ) internal {\\n    bool _success;\\n    bytes memory _data;\\n    if (_info.erc == Standard.ERC20) {\\n      (_success, _data) = _token.call(abi.encodeWithSelector(IERC20.transferFrom.selector, _from, _to, _info.quantity));\\n      _success = _success && (_data.length == 0 || abi.decode(_data, (bool)));\\n    } else if (_info.erc == Standard.ERC721) {\\n      // bytes4(keccak256(\\\"transferFrom(address,address,uint256)\\\"))\\n      (_success, ) = _token.call(abi.encodeWithSelector(0x23b872dd, _from, _to, _info.id));\\n    } else {\\n      revert(\\\"Token: unsupported token standard\\\");\\n    }\\n\\n    if (!_success) {\\n      revert(\\n        string(\\n          abi.encodePacked(\\n            \\\"Token: could not transfer \\\",\\n            toString(_info),\\n            \\\" from \\\",\\n            Strings.toHexString(uint160(_from), 20),\\n            \\\" to \\\",\\n            Strings.toHexString(uint160(_to), 20),\\n            \\\" token \\\",\\n            Strings.toHexString(uint160(_token), 20)\\n          )\\n        )\\n      );\\n    }\\n  }\\n\\n  /**\\n   * @dev Transfers ERC721 token and returns the result.\\n   */\\n  function tryTransferERC721(\\n    address _token,\\n    address _to,\\n    uint256 _id\\n  ) internal returns (bool _success) {\\n    (_success, ) = _token.call(abi.encodeWithSelector(IERC721.transferFrom.selector, address(this), _to, _id));\\n  }\\n\\n  /**\\n   * @dev Transfers ERC20 token and returns the result.\\n   */\\n  function tryTransferERC20(\\n    address _token,\\n    address _to,\\n    uint256 _quantity\\n  ) internal returns (bool _success) {\\n    bytes memory _data;\\n    (_success, _data) = _token.call(abi.encodeWithSelector(IERC20.transfer.selector, _to, _quantity));\\n    _success = _success && (_data.length == 0 || abi.decode(_data, (bool)));\\n  }\\n\\n  /**\\n   * @dev Transfer assets from current address to `_to` address.\\n   */\\n  function transfer(\\n    Info memory _info,\\n    address _to,\\n    address _token\\n  ) internal {\\n    bool _success;\\n    if (_info.erc == Standard.ERC20) {\\n      _success = tryTransferERC20(_token, _to, _info.quantity);\\n    } else if (_info.erc == Standard.ERC721) {\\n      _success = tryTransferERC721(_token, _to, _info.id);\\n    } else {\\n      revert(\\\"Token: unsupported token standard\\\");\\n    }\\n\\n    if (!_success) {\\n      revert(\\n        string(\\n          abi.encodePacked(\\n            \\\"Token: could not transfer \\\",\\n            toString(_info),\\n            \\\" to \\\",\\n            Strings.toHexString(uint160(_to), 20),\\n            \\\" token \\\",\\n            Strings.toHexString(uint160(_token), 20)\\n          )\\n        )\\n      );\\n    }\\n  }\\n\\n  /**\\n   * @dev Tries minting and transfering assets.\\n   *\\n   * @notice Prioritizes transfer native token if the token is wrapped.\\n   *\\n   */\\n  function handleAssetTransfer(\\n    Info memory _info,\\n    address payable _to,\\n    address _token,\\n    IWETH _wrappedNativeToken\\n  ) internal {\\n    bool _success;\\n    if (_token == address(_wrappedNativeToken)) {\\n      // Try sending the native token before transferring the wrapped token\\n      if (!_to.send(_info.quantity)) {\\n        _wrappedNativeToken.deposit{ value: _info.quantity }();\\n        transfer(_info, _to, _token);\\n      }\\n    } else if (_info.erc == Token.Standard.ERC20) {\\n      uint256 _balance = IERC20(_token).balanceOf(address(this));\\n\\n      if (_balance < _info.quantity) {\\n        // bytes4(keccak256(\\\"mint(address,uint256)\\\"))\\n        (_success, ) = _token.call(abi.encodeWithSelector(0x40c10f19, address(this), _info.quantity - _balance));\\n        require(_success, \\\"Token: ERC20 minting failed\\\");\\n      }\\n\\n      transfer(_info, _to, _token);\\n    } else if (_info.erc == Token.Standard.ERC721) {\\n      if (!tryTransferERC721(_token, _to, _info.id)) {\\n        // bytes4(keccak256(\\\"mint(address,uint256)\\\"))\\n        (_success, ) = _token.call(abi.encodeWithSelector(0x40c10f19, _to, _info.id));\\n        require(_success, \\\"Token: ERC721 minting failed\\\");\\n      }\\n    } else {\\n      revert(\\\"Token: unsupported token standard\\\");\\n    }\\n  }\\n\\n  /**\\n   * @dev Returns readable string.\\n   */\\n  function toString(Info memory _info) internal pure returns (string memory) {\\n    return\\n      string(\\n        abi.encodePacked(\\n          \\\"TokenInfo(\\\",\\n          Strings.toHexString(uint160(_info.erc), 1),\\n          \\\",\\\",\\n          Strings.toHexString(_info.id),\\n          \\\",\\\",\\n          Strings.toHexString(_info.quantity),\\n          \\\")\\\"\\n        )\\n      );\\n  }\\n\\n  struct Owner {\\n    address addr;\\n    address tokenAddr;\\n    uint256 chainId;\\n  }\\n\\n  // keccak256(\\\"TokenOwner(address addr,address tokenAddr,uint256 chainId)\\\");\\n  bytes32 public constant OWNER_TYPE_HASH = 0x353bdd8d69b9e3185b3972e08b03845c0c14a21a390215302776a7a34b0e8764;\\n\\n  /**\\n   * @dev Returns ownership struct hash.\\n   */\\n  function hash(Owner memory _owner) internal pure returns (bytes32) {\\n    return keccak256(abi.encode(OWNER_TYPE_HASH, _owner.addr, _owner.tokenAddr, _owner.chainId));\\n  }\\n}\\n\"},\"contracts/v0.8/mainchain/IMainchainGatewayV2.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport \\\"../interfaces/IWETH.sol\\\";\\nimport \\\"../library/Transfer.sol\\\";\\nimport \\\"../interfaces/SignatureConsumer.sol\\\";\\nimport \\\"../interfaces/MappedTokenConsumer.sol\\\";\\n\\ninterface IMainchainGatewayV2 is SignatureConsumer, MappedTokenConsumer {\\n  /// @dev Emitted when the deposit is requested\\n  event DepositRequested(bytes32 receiptHash, Transfer.Receipt receipt);\\n  /// @dev Emitted when the assets are withdrawn\\n  event Withdrew(bytes32 receiptHash, Transfer.Receipt receipt);\\n  /// @dev Emitted when the tokens are mapped\\n  event TokenMapped(address[] mainchainTokens, address[] roninTokens, Token.Standard[] standards);\\n  /// @dev Emitted when the wrapped native token contract is updated\\n  event WrappedNativeTokenContractUpdated(IWETH weth);\\n  /// @dev Emitted when the withdrawal is locked\\n  event WithdrawalLocked(bytes32 receiptHash, Transfer.Receipt receipt);\\n  /// @dev Emitted when the withdrawal is unlocked\\n  event WithdrawalUnlocked(bytes32 receiptHash, Transfer.Receipt receipt);\\n\\n  /**\\n   * @dev Returns the domain seperator.\\n   */\\n  function DOMAIN_SEPARATOR() external view returns (bytes32);\\n\\n  /**\\n   * @dev Returns deposit count.\\n   */\\n  function depositCount() external view returns (uint256);\\n\\n  /**\\n   * @dev Sets the wrapped native token contract.\\n   *\\n   * Requirements:\\n   * - The method caller is admin.\\n   *\\n   * Emits the `WrappedNativeTokenContractUpdated` event.\\n   *\\n   */\\n  function setWrappedNativeTokenContract(IWETH _wrappedToken) external;\\n\\n  /**\\n   * @dev Returns whether the withdrawal is locked.\\n   */\\n  function withdrawalLocked(uint256 withdrawalId) external view returns (bool);\\n\\n  /**\\n   * @dev Returns the withdrawal hash.\\n   */\\n  function withdrawalHash(uint256 withdrawalId) external view returns (bytes32);\\n\\n  /**\\n   * @dev Locks the assets and request deposit.\\n   */\\n  function requestDepositFor(Transfer.Request calldata _request) external payable;\\n\\n  /**\\n   * @dev Withdraws based on the receipt and the validator signatures.\\n   * Returns whether the withdrawal is locked.\\n   *\\n   * Emits the `Withdrew` once the assets are released.\\n   *\\n   */\\n  function submitWithdrawal(Transfer.Receipt memory _receipt, Signature[] memory _signatures)\\n    external\\n    returns (bool _locked);\\n\\n  /**\\n   * @dev Approves a specific withdrawal.\\n   *\\n   * Requirements:\\n   * - The method caller is a validator.\\n   *\\n   * Emits the `Withdrew` once the assets are released.\\n   *\\n   */\\n  function unlockWithdrawal(Transfer.Receipt calldata _receipt) external;\\n\\n  /**\\n   * @dev Maps mainchain tokens to Ronin network.\\n   *\\n   * Requirement:\\n   * - The method caller is admin.\\n   * - The arrays have the same length and its length larger than 0.\\n   *\\n   * Emits the `TokenMapped` event.\\n   *\\n   */\\n  function mapTokens(\\n    address[] calldata _mainchainTokens,\\n    address[] calldata _roninTokens,\\n    Token.Standard[] calldata _standards\\n  ) external;\\n\\n  /**\\n   * @dev Maps mainchain tokens to Ronin network and sets thresholds.\\n   *\\n   * Requirement:\\n   * - The method caller is admin.\\n   * - The arrays have the same length and its length larger than 0.\\n   *\\n   * Emits the `TokenMapped` event.\\n   *\\n   */\\n  function mapTokensAndThresholds(\\n    address[] calldata _mainchainTokens,\\n    address[] calldata _roninTokens,\\n    Token.Standard[] calldata _standards,\\n    uint256[][4] calldata _thresholds\\n  ) external;\\n\\n  /**\\n   * @dev Returns token address on Ronin network.\\n   * @notice Reverts for unsupported token.\\n   */\\n  function getRoninToken(address _mainchainToken) external view returns (MappedToken memory _token);\\n}\\n\"},\"contracts/v0.8/mainchain/MainchainGatewayV2.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport \\\"@openzeppelin/contracts/access/AccessControlEnumerable.sol\\\";\\nimport \\\"@openzeppelin/contracts/proxy/utils/Initializable.sol\\\";\\nimport \\\"../extensions/GatewayV2.sol\\\";\\nimport \\\"../extensions/WithdrawalLimitation.sol\\\";\\nimport \\\"../library/Transfer.sol\\\";\\nimport \\\"./IMainchainGatewayV2.sol\\\";\\n\\ncontract MainchainGatewayV2 is WithdrawalLimitation, Initializable, AccessControlEnumerable, IMainchainGatewayV2 {\\n  using Token for Token.Info;\\n  using Transfer for Transfer.Request;\\n  using Transfer for Transfer.Receipt;\\n\\n  /// @dev Withdrawal unlocker role hash\\n  bytes32 public constant WITHDRAWAL_UNLOCKER_ROLE = keccak256(\\\"WITHDRAWAL_UNLOCKER_ROLE\\\");\\n\\n  /// @dev Wrapped native token address\\n  IWETH public wrappedNativeToken;\\n  /// @dev Ronin network id\\n  uint256 public roninChainId;\\n  /// @dev Total deposit\\n  uint256 public depositCount;\\n  /// @dev Domain seperator\\n  bytes32 internal _domainSeparator;\\n  /// @dev Mapping from mainchain token => token address on Ronin network\\n  mapping(address => MappedToken) internal _roninToken;\\n  /// @dev Mapping from withdrawal id => withdrawal hash\\n  mapping(uint256 => bytes32) public withdrawalHash;\\n  /// @dev Mapping from withdrawal id => locked\\n  mapping(uint256 => bool) public withdrawalLocked;\\n\\n  fallback() external payable {\\n    _fallback();\\n  }\\n\\n  receive() external payable {\\n    _fallback();\\n  }\\n\\n  /**\\n   * @dev Initializes contract storage.\\n   */\\n  function initialize(\\n    address _roleSetter,\\n    IWETH _wrappedToken,\\n    IWeightedValidator _validatorContract,\\n    uint256 _roninChainId,\\n    uint256 _numerator,\\n    uint256 _highTierVWNumerator,\\n    uint256 _denominator,\\n    // _addresses[0]: mainchainTokens\\n    // _addresses[1]: roninTokens\\n    // _addresses[2]: withdrawalUnlockers\\n    address[][3] calldata _addresses,\\n    // _thresholds[0]: highTierThreshold\\n    // _thresholds[1]: lockedThreshold\\n    // _thresholds[2]: unlockFeePercentages\\n    // _thresholds[3]: dailyWithdrawalLimit\\n    uint256[][4] calldata _thresholds,\\n    Token.Standard[] calldata _standards\\n  ) external payable virtual initializer {\\n    _setupRole(DEFAULT_ADMIN_ROLE, _roleSetter);\\n    roninChainId = _roninChainId;\\n\\n    _setWrappedNativeTokenContract(_wrappedToken);\\n    _setValidatorContract(_validatorContract);\\n    _updateDomainSeparator();\\n    _setThreshold(_numerator, _denominator);\\n    _setHighTierVoteWeightThreshold(_highTierVWNumerator, _denominator);\\n    _verifyThresholds();\\n\\n    if (_addresses[0].length > 0) {\\n      // Map mainchain tokens to ronin tokens\\n      _mapTokens(_addresses[0], _addresses[1], _standards);\\n      // Sets thresholds based on the mainchain tokens\\n      _setHighTierThresholds(_addresses[0], _thresholds[0]);\\n      _setLockedThresholds(_addresses[0], _thresholds[1]);\\n      _setUnlockFeePercentages(_addresses[0], _thresholds[2]);\\n      _setDailyWithdrawalLimits(_addresses[0], _thresholds[3]);\\n    }\\n\\n    // Grant role for withdrawal unlocker\\n    for (uint256 _i; _i < _addresses[2].length; _i++) {\\n      _grantRole(WITHDRAWAL_UNLOCKER_ROLE, _addresses[2][_i]);\\n    }\\n  }\\n\\n  /**\\n   * @dev Receives ether without doing anything. Use this function to topup native token.\\n   */\\n  function receiveEther() external payable {}\\n\\n  /**\\n   * @dev See {IMainchainGatewayV2-DOMAIN_SEPARATOR}.\\n   */\\n  function DOMAIN_SEPARATOR() external view virtual returns (bytes32) {\\n    return _domainSeparator;\\n  }\\n\\n  /**\\n   * @dev See {IMainchainGatewayV2-setWrappedNativeTokenContract}.\\n   */\\n  function setWrappedNativeTokenContract(IWETH _wrappedToken) external virtual onlyAdmin {\\n    _setWrappedNativeTokenContract(_wrappedToken);\\n  }\\n\\n  /**\\n   * @dev See {IMainchainGatewayV2-requestDepositFor}.\\n   */\\n  function requestDepositFor(Transfer.Request calldata _request) external payable virtual whenNotPaused {\\n    _requestDepositFor(_request, msg.sender);\\n  }\\n\\n  /**\\n   * @dev See {IMainchainGatewayV2-submitWithdrawal}.\\n   */\\n  function submitWithdrawal(Transfer.Receipt calldata _receipt, Signature[] calldata _signatures)\\n    external\\n    virtual\\n    whenNotPaused\\n    returns (bool _locked)\\n  {\\n    return _submitWithdrawal(_receipt, _signatures);\\n  }\\n\\n  /**\\n   * @dev See {IMainchainGatewayV2-unlockWithdrawal}.\\n   */\\n  function unlockWithdrawal(Transfer.Receipt calldata _receipt) external onlyRole(WITHDRAWAL_UNLOCKER_ROLE) {\\n    bytes32 _receiptHash = _receipt.hash();\\n    require(withdrawalHash[_receipt.id] == _receipt.hash(), \\\"MainchainGatewayV2: invalid receipt\\\");\\n    require(withdrawalLocked[_receipt.id], \\\"MainchainGatewayV2: query for approved withdrawal\\\");\\n    delete withdrawalLocked[_receipt.id];\\n    emit WithdrawalUnlocked(_receiptHash, _receipt);\\n\\n    address _token = _receipt.mainchain.tokenAddr;\\n    if (_receipt.info.erc == Token.Standard.ERC20) {\\n      Token.Info memory _feeInfo = _receipt.info;\\n      _feeInfo.quantity = _computeFeePercentage(_receipt.info.quantity, unlockFeePercentages[_token]);\\n      Token.Info memory _withdrawInfo = _receipt.info;\\n      _withdrawInfo.quantity = _receipt.info.quantity - _feeInfo.quantity;\\n\\n      _feeInfo.handleAssetTransfer(payable(msg.sender), _token, wrappedNativeToken);\\n      _withdrawInfo.handleAssetTransfer(payable(_receipt.mainchain.addr), _token, wrappedNativeToken);\\n    } else {\\n      _receipt.info.handleAssetTransfer(payable(_receipt.mainchain.addr), _token, wrappedNativeToken);\\n    }\\n\\n    emit Withdrew(_receiptHash, _receipt);\\n  }\\n\\n  /**\\n   * @dev See {IMainchainGatewayV2-mapTokens}.\\n   */\\n  function mapTokens(\\n    address[] calldata _mainchainTokens,\\n    address[] calldata _roninTokens,\\n    Token.Standard[] calldata _standards\\n  ) external virtual onlyAdmin {\\n    require(_mainchainTokens.length > 0, \\\"MainchainGatewayV2: query for empty array\\\");\\n    _mapTokens(_mainchainTokens, _roninTokens, _standards);\\n  }\\n\\n  /**\\n   * @dev See {IMainchainGatewayV2-mapTokensAndThresholds}.\\n   */\\n  function mapTokensAndThresholds(\\n    address[] calldata _mainchainTokens,\\n    address[] calldata _roninTokens,\\n    Token.Standard[] calldata _standards,\\n    // _thresholds[0]: highTierThreshold\\n    // _thresholds[1]: lockedThreshold\\n    // _thresholds[2]: unlockFeePercentages\\n    // _thresholds[3]: dailyWithdrawalLimit\\n    uint256[][4] calldata _thresholds\\n  ) external virtual onlyAdmin {\\n    require(_mainchainTokens.length > 0, \\\"MainchainGatewayV2: query for empty array\\\");\\n    _mapTokens(_mainchainTokens, _roninTokens, _standards);\\n    _setHighTierThresholds(_mainchainTokens, _thresholds[0]);\\n    _setLockedThresholds(_mainchainTokens, _thresholds[1]);\\n    _setUnlockFeePercentages(_mainchainTokens, _thresholds[2]);\\n    _setDailyWithdrawalLimits(_mainchainTokens, _thresholds[3]);\\n  }\\n\\n  /**\\n   * @dev See {IMainchainGatewayV2-getRoninToken}.\\n   */\\n  function getRoninToken(address _mainchainToken) public view returns (MappedToken memory _token) {\\n    _token = _roninToken[_mainchainToken];\\n    require(_token.tokenAddr != address(0), \\\"MainchainGatewayV2: unsupported token\\\");\\n  }\\n\\n  /**\\n   * @dev Maps mainchain tokens to Ronin network.\\n   *\\n   * Requirement:\\n   * - The arrays have the same length.\\n   *\\n   * Emits the `TokenMapped` event.\\n   *\\n   */\\n  function _mapTokens(\\n    address[] calldata _mainchainTokens,\\n    address[] calldata _roninTokens,\\n    Token.Standard[] calldata _standards\\n  ) internal virtual {\\n    require(\\n      _mainchainTokens.length == _roninTokens.length && _mainchainTokens.length == _standards.length,\\n      \\\"MainchainGatewayV2: invalid array length\\\"\\n    );\\n\\n    for (uint256 _i; _i < _mainchainTokens.length; _i++) {\\n      _roninToken[_mainchainTokens[_i]].tokenAddr = _roninTokens[_i];\\n      _roninToken[_mainchainTokens[_i]].erc = _standards[_i];\\n    }\\n\\n    emit TokenMapped(_mainchainTokens, _roninTokens, _standards);\\n  }\\n\\n  /**\\n   * @dev Submits withdrawal receipt.\\n   *\\n   * Requirements:\\n   * - The receipt kind is withdrawal.\\n   * - The receipt is to withdraw on this chain.\\n   * - The receipt is not used to withdraw before.\\n   * - The withdrawal is not reached the limit threshold.\\n   * - The signer weight total is larger than or equal to the minimum threshold.\\n   * - The signature signers are in order.\\n   *\\n   * Emits the `Withdrew` once the assets are released.\\n   *\\n   */\\n  function _submitWithdrawal(Transfer.Receipt calldata _receipt, Signature[] memory _signatures)\\n    internal\\n    virtual\\n    returns (bool _locked)\\n  {\\n    uint256 _id = _receipt.id;\\n    uint256 _quantity = _receipt.info.quantity;\\n    address _tokenAddr = _receipt.mainchain.tokenAddr;\\n\\n    _receipt.info.validate();\\n    require(_receipt.kind == Transfer.Kind.Withdrawal, \\\"MainchainGatewayV2: invalid receipt kind\\\");\\n    require(_receipt.mainchain.chainId == block.chainid, \\\"MainchainGatewayV2: invalid chain id\\\");\\n    MappedToken memory _token = getRoninToken(_receipt.mainchain.tokenAddr);\\n    require(\\n      _token.erc == _receipt.info.erc && _token.tokenAddr == _receipt.ronin.tokenAddr,\\n      \\\"MainchainGatewayV2: invalid receipt\\\"\\n    );\\n    require(withdrawalHash[_id] == bytes32(0), \\\"MainchainGatewayV2: query for processed withdrawal\\\");\\n    require(\\n      _receipt.info.erc == Token.Standard.ERC721 || !_reachedWithdrawalLimit(_tokenAddr, _quantity),\\n      \\\"MainchainGatewayV2: reached daily withdrawal limit\\\"\\n    );\\n\\n    bytes32 _receiptHash = _receipt.hash();\\n    bytes32 _receiptDigest = Transfer.receiptDigest(_domainSeparator, _receiptHash);\\n    IWeightedValidator _validatorContract = validatorContract;\\n\\n    uint256 _minimumVoteWeight;\\n    (_minimumVoteWeight, _locked) = _computeMinVoteWeight(_receipt.info.erc, _tokenAddr, _quantity, _validatorContract);\\n\\n    {\\n      bool _passed;\\n      address _signer;\\n      address _lastSigner;\\n      Signature memory _sig;\\n      uint256 _weight;\\n      for (uint256 _i; _i < _signatures.length; _i++) {\\n        _sig = _signatures[_i];\\n        _signer = ecrecover(_receiptDigest, _sig.v, _sig.r, _sig.s);\\n        require(_lastSigner < _signer, \\\"MainchainGatewayV2: invalid order\\\");\\n        _lastSigner = _signer;\\n\\n        _weight += _validatorContract.getValidatorWeight(_signer);\\n        if (_weight >= _minimumVoteWeight) {\\n          _passed = true;\\n          break;\\n        }\\n      }\\n      require(_passed, \\\"MainchainGatewayV2: query for insufficient vote weight\\\");\\n      withdrawalHash[_id] = _receiptHash;\\n    }\\n\\n    if (_locked) {\\n      withdrawalLocked[_id] = true;\\n      emit WithdrawalLocked(_receiptHash, _receipt);\\n      return _locked;\\n    }\\n\\n    _recordWithdrawal(_tokenAddr, _quantity);\\n    _receipt.info.handleAssetTransfer(payable(_receipt.mainchain.addr), _tokenAddr, wrappedNativeToken);\\n    emit Withdrew(_receiptHash, _receipt);\\n  }\\n\\n  /**\\n   * @dev Requests deposit made by `_requester` address.\\n   *\\n   * Requirements:\\n   * - The token info is valid.\\n   * - The `msg.value` is 0 while depositing ERC20 token.\\n   * - The `msg.value` is equal to deposit quantity while depositing native token.\\n   *\\n   * Emits the `DepositRequested` event.\\n   *\\n   */\\n  function _requestDepositFor(Transfer.Request memory _request, address _requester) internal virtual {\\n    MappedToken memory _token;\\n    address _weth = address(wrappedNativeToken);\\n\\n    _request.info.validate();\\n    if (_request.tokenAddr == address(0)) {\\n      require(_request.info.quantity == msg.value, \\\"MainchainGatewayV2: invalid request\\\");\\n      _token = getRoninToken(_weth);\\n      require(_token.erc == _request.info.erc, \\\"MainchainGatewayV2: invalid token standard\\\");\\n      _request.tokenAddr = _weth;\\n    } else {\\n      require(msg.value == 0, \\\"MainchainGatewayV2: invalid request\\\");\\n      _token = getRoninToken(_request.tokenAddr);\\n      require(_token.erc == _request.info.erc, \\\"MainchainGatewayV2: invalid token standard\\\");\\n      _request.info.transferFrom(_requester, address(this), _request.tokenAddr);\\n      // Withdraw if token is WETH\\n      if (_weth == _request.tokenAddr) {\\n        IWETH(_weth).withdraw(_request.info.quantity);\\n      }\\n    }\\n\\n    uint256 _depositId = depositCount++;\\n    Transfer.Receipt memory _receipt = _request.into_deposit_receipt(\\n      _requester,\\n      _depositId,\\n      _token.tokenAddr,\\n      roninChainId\\n    );\\n\\n    emit DepositRequested(_receipt.hash(), _receipt);\\n  }\\n\\n  /**\\n   * @dev Returns the minimum vote weight for the token.\\n   */\\n  function _computeMinVoteWeight(\\n    Token.Standard _erc,\\n    address _token,\\n    uint256 _quantity,\\n    IWeightedValidator _validatorContract\\n  ) internal virtual returns (uint256 _weight, bool _locked) {\\n    uint256 _totalWeights = _validatorContract.totalWeights();\\n    _weight = _minimumVoteWeight(_totalWeights);\\n    if (_erc == Token.Standard.ERC20) {\\n      if (highTierThreshold[_token] <= _quantity) {\\n        _weight = _highTierVoteWeight(_totalWeights);\\n      }\\n      _locked = _lockedWithdrawalRequest(_token, _quantity);\\n    }\\n  }\\n\\n  /**\\n   * @dev Update domain seperator.\\n   */\\n  function _updateDomainSeparator() internal {\\n    _domainSeparator = keccak256(\\n      abi.encode(\\n        keccak256(\\\"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)\\\"),\\n        keccak256(\\\"MainchainGatewayV2\\\"),\\n        keccak256(\\\"2\\\"),\\n        block.chainid,\\n        address(this)\\n      )\\n    );\\n  }\\n\\n  /**\\n   * @dev Sets the WETH contract.\\n   *\\n   * Emits the `WrappedNativeTokenContractUpdated` event.\\n   *\\n   */\\n  function _setWrappedNativeTokenContract(IWETH _wrapedToken) internal {\\n    wrappedNativeToken = _wrapedToken;\\n    emit WrappedNativeTokenContractUpdated(_wrapedToken);\\n  }\\n\\n  /**\\n   * @dev Receives ETH from WETH or creates deposit request.\\n   */\\n  function _fallback() internal virtual whenNotPaused {\\n    if (msg.sender != address(wrappedNativeToken)) {\\n      Transfer.Request memory _request;\\n      _request.recipientAddr = msg.sender;\\n      _request.info.quantity = msg.value;\\n      _requestDepositFor(_request, _request.recipientAddr);\\n    }\\n  }\\n}\\n\"},\"contracts/v0.8/interfaces/IWeightedValidator.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IQuorum.sol\\\";\\n\\ninterface IWeightedValidator is IQuorum {\\n  struct WeightedValidator {\\n    address validator;\\n    address governor;\\n    uint256 weight;\\n  }\\n\\n  /// @dev Emitted when the validators are added\\n  event ValidatorsAdded(uint256 indexed nonce, WeightedValidator[] validators);\\n  /// @dev Emitted when the validators are updated\\n  event ValidatorsUpdated(uint256 indexed nonce, WeightedValidator[] validators);\\n  /// @dev Emitted when the validators are removed\\n  event ValidatorsRemoved(uint256 indexed nonce, address[] validators);\\n\\n  /**\\n   * @dev Returns validator weight of the validator.\\n   */\\n  function getValidatorWeight(address _addr) external view returns (uint256);\\n\\n  /**\\n   * @dev Returns governor weight of the governor.\\n   */\\n  function getGovernorWeight(address _addr) external view returns (uint256);\\n\\n  /**\\n   * @dev Returns total validator weights of the address list.\\n   */\\n  function sumValidatorWeights(address[] calldata _addrList) external view returns (uint256 _weight);\\n\\n  /**\\n   * @dev Returns total governor weights of the address list.\\n   */\\n  function sumGovernorWeights(address[] calldata _addrList) external view returns (uint256 _weight);\\n\\n  /**\\n   * @dev Returns the validator list attached with governor address and weight.\\n   */\\n  function getValidatorInfo() external view returns (WeightedValidator[] memory _list);\\n\\n  /**\\n   * @dev Returns the validator list.\\n   */\\n  function getValidators() external view returns (address[] memory _validators);\\n\\n  /**\\n   * @dev Returns the validator at `_index` position.\\n   */\\n  function validators(uint256 _index) external view returns (WeightedValidator memory);\\n\\n  /**\\n   * @dev Returns total of validators.\\n   */\\n  function totalValidators() external view returns (uint256);\\n\\n  /**\\n   * @dev Returns total weights.\\n   */\\n  function totalWeights() external view returns (uint256);\\n\\n  /**\\n   * @dev Adds validators.\\n   *\\n   * Requirements:\\n   * - The weights are larger than 0.\\n   * - The validators are not added.\\n   * - The method caller is admin.\\n   *\\n   * Emits the `ValidatorsAdded` event.\\n   *\\n   */\\n  function addValidators(WeightedValidator[] calldata _validators) external;\\n\\n  /**\\n   * @dev Updates validators.\\n   *\\n   * Requirements:\\n   * - The weights are larger than 0.\\n   * - The validators are added.\\n   * - The method caller is admin.\\n   *\\n   * Emits the `ValidatorsUpdated` event.\\n   *\\n   */\\n  function updateValidators(WeightedValidator[] calldata _validators) external;\\n\\n  /**\\n   * @dev Removes validators.\\n   *\\n   * Requirements:\\n   * - The validators are added.\\n   * - The method caller is admin.\\n   *\\n   * Emits the `ValidatorsRemoved` event.\\n   *\\n   */\\n  function removeValidators(address[] calldata _validators) external;\\n}\\n\"},\"contracts/v0.8/extensions/HasProxyAdmin.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport \\\"@openzeppelin/contracts/utils/StorageSlot.sol\\\";\\n\\nabstract contract HasProxyAdmin {\\n  // bytes32(uint256(keccak256(\\\"eip1967.proxy.admin\\\")) - 1));\\n  bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;\\n\\n  modifier onlyAdmin() {\\n    require(msg.sender == _getAdmin(), \\\"HasProxyAdmin: unauthorized sender\\\");\\n    _;\\n  }\\n\\n  /**\\n   * @dev Returns proxy admin.\\n   */\\n  function _getAdmin() internal view returns (address) {\\n    return StorageSlot.getAddressSlot(_ADMIN_SLOT).value;\\n  }\\n}\\n\"},\"@openzeppelin/contracts/utils/introspection/IERC165.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC165 standard, as defined in the\\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\\n *\\n * Implementers can declare support of contract interfaces, which can then be\\n * queried by others ({ERC165Checker}).\\n *\\n * For an implementation, see {ERC165}.\\n */\\ninterface IERC165 {\\n    /**\\n     * @dev Returns true if this contract implements the interface defined by\\n     * `interfaceId`. See the corresponding\\n     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\\n     * to learn more about how these ids are created.\\n     *\\n     * This function call must use less than 30 000 gas.\\n     */\\n    function supportsInterface(bytes4 interfaceId) external view returns (bool);\\n}\\n\"},\"contracts/v0.8/interfaces/SignatureConsumer.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface SignatureConsumer {\\n  struct Signature {\\n    uint8 v;\\n    bytes32 r;\\n    bytes32 s;\\n  }\\n}\\n\"},\"@openzeppelin/contracts/utils/Strings.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev String operations.\\n */\\nlibrary Strings {\\n    bytes16 private constant _HEX_SYMBOLS = \\\"0123456789abcdef\\\";\\n\\n    /**\\n     * @dev Converts a `uint256` to its ASCII `string` decimal representation.\\n     */\\n    function toString(uint256 value) internal pure returns (string memory) {\\n        // Inspired by OraclizeAPI's implementation - MIT licence\\n        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\\n\\n        if (value == 0) {\\n            return \\\"0\\\";\\n        }\\n        uint256 temp = value;\\n        uint256 digits;\\n        while (temp != 0) {\\n            digits++;\\n            temp /= 10;\\n        }\\n        bytes memory buffer = new bytes(digits);\\n        while (value != 0) {\\n            digits -= 1;\\n            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\\n            value /= 10;\\n        }\\n        return string(buffer);\\n    }\\n\\n    /**\\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\\n     */\\n    function toHexString(uint256 value) internal pure returns (string memory) {\\n        if (value == 0) {\\n            return \\\"0x00\\\";\\n        }\\n        uint256 temp = value;\\n        uint256 length = 0;\\n        while (temp != 0) {\\n            length++;\\n            temp >>= 8;\\n        }\\n        return toHexString(value, length);\\n    }\\n\\n    /**\\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\\n     */\\n    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\\n        bytes memory buffer = new bytes(2 * length + 2);\\n        buffer[0] = \\\"0\\\";\\n        buffer[1] = \\\"x\\\";\\n        for (uint256 i = 2 * length + 1; i > 1; --i) {\\n            buffer[i] = _HEX_SYMBOLS[value & 0xf];\\n            value >>= 4;\\n        }\\n        require(value == 0, \\\"Strings: hex length insufficient\\\");\\n        return string(buffer);\\n    }\\n}\\n\"},\"@openzeppelin/contracts/utils/introspection/ERC165.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IERC165.sol\\\";\\n\\n/**\\n * @dev Implementation of the {IERC165} interface.\\n *\\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\\n * for the additional interface id that will be supported. For example:\\n *\\n * ```solidity\\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\\n *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\\n * }\\n * ```\\n *\\n * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.\\n */\\nabstract contract ERC165 is IERC165 {\\n    /**\\n     * @dev See {IERC165-supportsInterface}.\\n     */\\n    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\\n        return interfaceId == type(IERC165).interfaceId;\\n    }\\n}\\n\"},\"@openzeppelin/contracts/access/AccessControlEnumerable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (access/AccessControlEnumerable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IAccessControlEnumerable.sol\\\";\\nimport \\\"./AccessControl.sol\\\";\\nimport \\\"../utils/structs/EnumerableSet.sol\\\";\\n\\n/**\\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\\n */\\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\\n    using EnumerableSet for EnumerableSet.AddressSet;\\n\\n    mapping(bytes32 => EnumerableSet.AddressSet) private _roleMembers;\\n\\n    /**\\n     * @dev See {IERC165-supportsInterface}.\\n     */\\n    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\\n        return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\\n    }\\n\\n    /**\\n     * @dev Returns one of the accounts that have `role`. `index` must be a\\n     * value between 0 and {getRoleMemberCount}, non-inclusive.\\n     *\\n     * Role bearers are not sorted in any particular way, and their ordering may\\n     * change at any point.\\n     *\\n     * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\\n     * you perform all queries on the same block. See the following\\n     * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\\n     * for more information.\\n     */\\n    function getRoleMember(bytes32 role, uint256 index) public view virtual override returns (address) {\\n        return _roleMembers[role].at(index);\\n    }\\n\\n    /**\\n     * @dev Returns the number of accounts that have `role`. Can be used\\n     * together with {getRoleMember} to enumerate all bearers of a role.\\n     */\\n    function getRoleMemberCount(bytes32 role) public view virtual override returns (uint256) {\\n        return _roleMembers[role].length();\\n    }\\n\\n    /**\\n     * @dev Overload {_grantRole} to track enumerable memberships\\n     */\\n    function _grantRole(bytes32 role, address account) internal virtual override {\\n        super._grantRole(role, account);\\n        _roleMembers[role].add(account);\\n    }\\n\\n    /**\\n     * @dev Overload {_revokeRole} to track enumerable memberships\\n     */\\n    function _revokeRole(bytes32 role, address account) internal virtual override {\\n        super._revokeRole(role, account);\\n        _roleMembers[role].remove(account);\\n    }\\n}\\n\"},\"contracts/v0.8/library/Transfer.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport \\\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/Strings.sol\\\";\\nimport \\\"./Token.sol\\\";\\n\\nlibrary Transfer {\\n  using ECDSA for bytes32;\\n\\n  enum Kind {\\n    Deposit,\\n    Withdrawal\\n  }\\n\\n  struct Request {\\n    // For deposit request: Recipient address on Ronin network\\n    // For withdrawal request: Recipient address on mainchain network\\n    address recipientAddr;\\n    // Token address to deposit/withdraw\\n    // Value 0: native token\\n    address tokenAddr;\\n    Token.Info info;\\n  }\\n\\n  /**\\n   * @dev Converts the transfer request into the deposit receipt.\\n   */\\n  function into_deposit_receipt(\\n    Request memory _request,\\n    address _requester,\\n    uint256 _id,\\n    address _roninTokenAddr,\\n    uint256 _roninChainId\\n  ) internal view returns (Receipt memory _receipt) {\\n    _receipt.id = _id;\\n    _receipt.kind = Kind.Deposit;\\n    _receipt.mainchain.addr = _requester;\\n    _receipt.mainchain.tokenAddr = _request.tokenAddr;\\n    _receipt.mainchain.chainId = block.chainid;\\n    _receipt.ronin.addr = _request.recipientAddr;\\n    _receipt.ronin.tokenAddr = _roninTokenAddr;\\n    _receipt.ronin.chainId = _roninChainId;\\n    _receipt.info = _request.info;\\n  }\\n\\n  /**\\n   * @dev Converts the transfer request into the withdrawal receipt.\\n   */\\n  function into_withdrawal_receipt(\\n    Request memory _request,\\n    address _requester,\\n    uint256 _id,\\n    address _mainchainTokenAddr,\\n    uint256 _mainchainId\\n  ) internal view returns (Receipt memory _receipt) {\\n    _receipt.id = _id;\\n    _receipt.kind = Kind.Withdrawal;\\n    _receipt.ronin.addr = _requester;\\n    _receipt.ronin.tokenAddr = _request.tokenAddr;\\n    _receipt.ronin.chainId = block.chainid;\\n    _receipt.mainchain.addr = _request.recipientAddr;\\n    _receipt.mainchain.tokenAddr = _mainchainTokenAddr;\\n    _receipt.mainchain.chainId = _mainchainId;\\n    _receipt.info = _request.info;\\n  }\\n\\n  struct Receipt {\\n    uint256 id;\\n    Kind kind;\\n    Token.Owner mainchain;\\n    Token.Owner ronin;\\n    Token.Info info;\\n  }\\n\\n  // keccak256(\\\"Receipt(uint256 id,uint8 kind,TokenOwner mainchain,TokenOwner ronin,TokenInfo info)TokenInfo(uint8 erc,uint256 id,uint256 quantity)TokenOwner(address addr,address tokenAddr,uint256 chainId)\\\");\\n  bytes32 public constant TYPE_HASH = 0xb9d1fe7c9deeec5dc90a2f47ff1684239519f2545b2228d3d91fb27df3189eea;\\n\\n  /**\\n   * @dev Returns token info struct hash.\\n   */\\n  function hash(Receipt memory _receipt) internal pure returns (bytes32) {\\n    return\\n      keccak256(\\n        abi.encode(\\n          TYPE_HASH,\\n          _receipt.id,\\n          _receipt.kind,\\n          Token.hash(_receipt.mainchain),\\n          Token.hash(_receipt.ronin),\\n          Token.hash(_receipt.info)\\n        )\\n      );\\n  }\\n\\n  /**\\n   * @dev Returns the receipt digest.\\n   */\\n  function receiptDigest(bytes32 _domainSeparator, bytes32 _receiptHash) internal pure returns (bytes32) {\\n    return _domainSeparator.toTypedDataHash(_receiptHash);\\n  }\\n}\\n\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n    function _msgSender() internal view virtual returns (address) {\\n        return msg.sender;\\n    }\\n\\n    function _msgData() internal view virtual returns (bytes calldata) {\\n        return msg.data;\\n    }\\n}\\n\"},\"@openzeppelin/contracts/security/Pausable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (security/Pausable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../utils/Context.sol\\\";\\n\\n/**\\n * @dev Contract module which allows children to implement an emergency stop\\n * mechanism that can be triggered by an authorized account.\\n *\\n * This module is used through inheritance. It will make available the\\n * modifiers `whenNotPaused` and `whenPaused`, which can be applied to\\n * the functions of your contract. Note that they will not be pausable by\\n * simply including this module, only once the modifiers are put in place.\\n */\\nabstract contract Pausable is Context {\\n    /**\\n     * @dev Emitted when the pause is triggered by `account`.\\n     */\\n    event Paused(address account);\\n\\n    /**\\n     * @dev Emitted when the pause is lifted by `account`.\\n     */\\n    event Unpaused(address account);\\n\\n    bool private _paused;\\n\\n    /**\\n     * @dev Initializes the contract in unpaused state.\\n     */\\n    constructor() {\\n        _paused = false;\\n    }\\n\\n    /**\\n     * @dev Returns true if the contract is paused, and false otherwise.\\n     */\\n    function paused() public view virtual returns (bool) {\\n        return _paused;\\n    }\\n\\n    /**\\n     * @dev Modifier to make a function callable only when the contract is not paused.\\n     *\\n     * Requirements:\\n     *\\n     * - The contract must not be paused.\\n     */\\n    modifier whenNotPaused() {\\n        require(!paused(), \\\"Pausable: paused\\\");\\n        _;\\n    }\\n\\n    /**\\n     * @dev Modifier to make a function callable only when the contract is paused.\\n     *\\n     * Requirements:\\n     *\\n     * - The contract must be paused.\\n     */\\n    modifier whenPaused() {\\n        require(paused(), \\\"Pausable: not paused\\\");\\n        _;\\n    }\\n\\n    /**\\n     * @dev Triggers stopped state.\\n     *\\n     * Requirements:\\n     *\\n     * - The contract must not be paused.\\n     */\\n    function _pause() internal virtual whenNotPaused {\\n        _paused = true;\\n        emit Paused(_msgSender());\\n    }\\n\\n    /**\\n     * @dev Returns to normal state.\\n     *\\n     * Requirements:\\n     *\\n     * - The contract must be paused.\\n     */\\n    function _unpause() internal virtual whenPaused {\\n        _paused = false;\\n        emit Unpaused(_msgSender());\\n    }\\n}\\n\"},\"@openzeppelin/contracts/utils/structs/EnumerableSet.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/structs/EnumerableSet.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Library for managing\\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\\n * types.\\n *\\n * Sets have the following properties:\\n *\\n * - Elements are added, removed, and checked for existence in constant time\\n * (O(1)).\\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\\n *\\n * ```\\n * contract Example {\\n *     // Add the library methods\\n *     using EnumerableSet for EnumerableSet.AddressSet;\\n *\\n *     // Declare a set state variable\\n *     EnumerableSet.AddressSet private mySet;\\n * }\\n * ```\\n *\\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\\n * and `uint256` (`UintSet`) are supported.\\n */\\nlibrary EnumerableSet {\\n    // To implement this library for multiple types with as little code\\n    // repetition as possible, we write it in terms of a generic Set type with\\n    // bytes32 values.\\n    // The Set implementation uses private functions, and user-facing\\n    // implementations (such as AddressSet) are just wrappers around the\\n    // underlying Set.\\n    // This means that we can only create new EnumerableSets for types that fit\\n    // in bytes32.\\n\\n    struct Set {\\n        // Storage of set values\\n        bytes32[] _values;\\n        // Position of the value in the `values` array, plus 1 because index 0\\n        // means a value is not in the set.\\n        mapping(bytes32 => uint256) _indexes;\\n    }\\n\\n    /**\\n     * @dev Add a value to a set. O(1).\\n     *\\n     * Returns true if the value was added to the set, that is if it was not\\n     * already present.\\n     */\\n    function _add(Set storage set, bytes32 value) private returns (bool) {\\n        if (!_contains(set, value)) {\\n            set._values.push(value);\\n            // The value is stored at length-1, but we add 1 to all indexes\\n            // and use 0 as a sentinel value\\n            set._indexes[value] = set._values.length;\\n            return true;\\n        } else {\\n            return false;\\n        }\\n    }\\n\\n    /**\\n     * @dev Removes a value from a set. O(1).\\n     *\\n     * Returns true if the value was removed from the set, that is if it was\\n     * present.\\n     */\\n    function _remove(Set storage set, bytes32 value) private returns (bool) {\\n        // We read and store the value's index to prevent multiple reads from the same storage slot\\n        uint256 valueIndex = set._indexes[value];\\n\\n        if (valueIndex != 0) {\\n            // Equivalent to contains(set, value)\\n            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\\n            // the array, and then remove the last element (sometimes called as 'swap and pop').\\n            // This modifies the order of the array, as noted in {at}.\\n\\n            uint256 toDeleteIndex = valueIndex - 1;\\n            uint256 lastIndex = set._values.length - 1;\\n\\n            if (lastIndex != toDeleteIndex) {\\n                bytes32 lastvalue = set._values[lastIndex];\\n\\n                // Move the last value to the index where the value to delete is\\n                set._values[toDeleteIndex] = lastvalue;\\n                // Update the index for the moved value\\n                set._indexes[lastvalue] = valueIndex; // Replace lastvalue's index to valueIndex\\n            }\\n\\n            // Delete the slot where the moved value was stored\\n            set._values.pop();\\n\\n            // Delete the index for the deleted slot\\n            delete set._indexes[value];\\n\\n            return true;\\n        } else {\\n            return false;\\n        }\\n    }\\n\\n    /**\\n     * @dev Returns true if the value is in the set. O(1).\\n     */\\n    function _contains(Set storage set, bytes32 value) private view returns (bool) {\\n        return set._indexes[value] != 0;\\n    }\\n\\n    /**\\n     * @dev Returns the number of values on the set. O(1).\\n     */\\n    function _length(Set storage set) private view returns (uint256) {\\n        return set._values.length;\\n    }\\n\\n    /**\\n     * @dev Returns the value stored at position `index` in the set. O(1).\\n     *\\n     * Note that there are no guarantees on the ordering of values inside the\\n     * array, and it may change when more values are added or removed.\\n     *\\n     * Requirements:\\n     *\\n     * - `index` must be strictly less than {length}.\\n     */\\n    function _at(Set storage set, uint256 index) private view returns (bytes32) {\\n        return set._values[index];\\n    }\\n\\n    /**\\n     * @dev Return the entire set in an array\\n     *\\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\\n     */\\n    function _values(Set storage set) private view returns (bytes32[] memory) {\\n        return set._values;\\n    }\\n\\n    // Bytes32Set\\n\\n    struct Bytes32Set {\\n        Set _inner;\\n    }\\n\\n    /**\\n     * @dev Add a value to a set. O(1).\\n     *\\n     * Returns true if the value was added to the set, that is if it was not\\n     * already present.\\n     */\\n    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\\n        return _add(set._inner, value);\\n    }\\n\\n    /**\\n     * @dev Removes a value from a set. O(1).\\n     *\\n     * Returns true if the value was removed from the set, that is if it was\\n     * present.\\n     */\\n    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\\n        return _remove(set._inner, value);\\n    }\\n\\n    /**\\n     * @dev Returns true if the value is in the set. O(1).\\n     */\\n    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\\n        return _contains(set._inner, value);\\n    }\\n\\n    /**\\n     * @dev Returns the number of values in the set. O(1).\\n     */\\n    function length(Bytes32Set storage set) internal view returns (uint256) {\\n        return _length(set._inner);\\n    }\\n\\n    /**\\n     * @dev Returns the value stored at position `index` in the set. O(1).\\n     *\\n     * Note that there are no guarantees on the ordering of values inside the\\n     * array, and it may change when more values are added or removed.\\n     *\\n     * Requirements:\\n     *\\n     * - `index` must be strictly less than {length}.\\n     */\\n    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\\n        return _at(set._inner, index);\\n    }\\n\\n    /**\\n     * @dev Return the entire set in an array\\n     *\\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\\n     */\\n    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\\n        return _values(set._inner);\\n    }\\n\\n    // AddressSet\\n\\n    struct AddressSet {\\n        Set _inner;\\n    }\\n\\n    /**\\n     * @dev Add a value to a set. O(1).\\n     *\\n     * Returns true if the value was added to the set, that is if it was not\\n     * already present.\\n     */\\n    function add(AddressSet storage set, address value) internal returns (bool) {\\n        return _add(set._inner, bytes32(uint256(uint160(value))));\\n    }\\n\\n    /**\\n     * @dev Removes a value from a set. O(1).\\n     *\\n     * Returns true if the value was removed from the set, that is if it was\\n     * present.\\n     */\\n    function remove(AddressSet storage set, address value) internal returns (bool) {\\n        return _remove(set._inner, bytes32(uint256(uint160(value))));\\n    }\\n\\n    /**\\n     * @dev Returns true if the value is in the set. O(1).\\n     */\\n    function contains(AddressSet storage set, address value) internal view returns (bool) {\\n        return _contains(set._inner, bytes32(uint256(uint160(value))));\\n    }\\n\\n    /**\\n     * @dev Returns the number of values in the set. O(1).\\n     */\\n    function length(AddressSet storage set) internal view returns (uint256) {\\n        return _length(set._inner);\\n    }\\n\\n    /**\\n     * @dev Returns the value stored at position `index` in the set. O(1).\\n     *\\n     * Note that there are no guarantees on the ordering of values inside the\\n     * array, and it may change when more values are added or removed.\\n     *\\n     * Requirements:\\n     *\\n     * - `index` must be strictly less than {length}.\\n     */\\n    function at(AddressSet storage set, uint256 index) internal view returns (address) {\\n        return address(uint160(uint256(_at(set._inner, index))));\\n    }\\n\\n    /**\\n     * @dev Return the entire set in an array\\n     *\\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\\n     */\\n    function values(AddressSet storage set) internal view returns (address[] memory) {\\n        bytes32[] memory store = _values(set._inner);\\n        address[] memory result;\\n\\n        assembly {\\n            result := store\\n        }\\n\\n        return result;\\n    }\\n\\n    // UintSet\\n\\n    struct UintSet {\\n        Set _inner;\\n    }\\n\\n    /**\\n     * @dev Add a value to a set. O(1).\\n     *\\n     * Returns true if the value was added to the set, that is if it was not\\n     * already present.\\n     */\\n    function add(UintSet storage set, uint256 value) internal returns (bool) {\\n        return _add(set._inner, bytes32(value));\\n    }\\n\\n    /**\\n     * @dev Removes a value from a set. O(1).\\n     *\\n     * Returns true if the value was removed from the set, that is if it was\\n     * present.\\n     */\\n    function remove(UintSet storage set, uint256 value) internal returns (bool) {\\n        return _remove(set._inner, bytes32(value));\\n    }\\n\\n    /**\\n     * @dev Returns true if the value is in the set. O(1).\\n     */\\n    function contains(UintSet storage set, uint256 value) internal view returns (bool) {\\n        return _contains(set._inner, bytes32(value));\\n    }\\n\\n    /**\\n     * @dev Returns the number of values on the set. O(1).\\n     */\\n    function length(UintSet storage set) internal view returns (uint256) {\\n        return _length(set._inner);\\n    }\\n\\n    /**\\n     * @dev Returns the value stored at position `index` in the set. O(1).\\n     *\\n     * Note that there are no guarantees on the ordering of values inside the\\n     * array, and it may change when more values are added or removed.\\n     *\\n     * Requirements:\\n     *\\n     * - `index` must be strictly less than {length}.\\n     */\\n    function at(UintSet storage set, uint256 index) internal view returns (uint256) {\\n        return uint256(_at(set._inner, index));\\n    }\\n\\n    /**\\n     * @dev Return the entire set in an array\\n     *\\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\\n     */\\n    function values(UintSet storage set) internal view returns (uint256[] memory) {\\n        bytes32[] memory store = _values(set._inner);\\n        uint256[] memory result;\\n\\n        assembly {\\n            result := store\\n        }\\n\\n        return result;\\n    }\\n}\\n\"},\"contracts/v0.8/interfaces/IQuorum.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IQuorum {\\n  /// @dev Emitted when the threshold is updated\\n  event ThresholdUpdated(\\n    uint256 indexed nonce,\\n    uint256 indexed numerator,\\n    uint256 indexed denominator,\\n    uint256 previousNumerator,\\n    uint256 previousDenominator\\n  );\\n\\n  /**\\n   * @dev Returns the threshold.\\n   */\\n  function getThreshold() external view returns (uint256 _num, uint256 _denom);\\n\\n  /**\\n   * @dev Checks whether the `_voteWeight` passes the threshold.\\n   */\\n  function checkThreshold(uint256 _voteWeight) external view returns (bool);\\n\\n  /**\\n   * @dev Returns the minimum vote weight to pass the threshold.\\n   */\\n  function minimumVoteWeight() external view returns (uint256);\\n\\n  /**\\n   * @dev Sets the threshold.\\n   *\\n   * Requirements:\\n   * - The method caller is admin.\\n   *\\n   * Emits the `ThresholdUpdated` event.\\n   *\\n   */\\n  function setThreshold(uint256 _numerator, uint256 _denominator)\\n    external\\n    returns (uint256 _previousNum, uint256 _previousDenom);\\n}\\n\"},\"contracts/v0.8/interfaces/IWETH.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IWETH {\\n  function deposit() external payable;\\n\\n  function withdraw(uint256 _wad) external;\\n\\n  function balanceOf(address) external view returns (uint256);\\n}\\n\"},\"@openzeppelin/contracts/access/AccessControl.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (access/AccessControl.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IAccessControl.sol\\\";\\nimport \\\"../utils/Context.sol\\\";\\nimport \\\"../utils/Strings.sol\\\";\\nimport \\\"../utils/introspection/ERC165.sol\\\";\\n\\n/**\\n * @dev Contract module that allows children to implement role-based access\\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\\n * members except through off-chain means by accessing the contract event logs. Some\\n * applications may benefit from on-chain enumerability, for those cases see\\n * {AccessControlEnumerable}.\\n *\\n * Roles are referred to by their `bytes32` identifier. These should be exposed\\n * in the external API and be unique. The best way to achieve this is by\\n * using `public constant` hash digests:\\n *\\n * ```\\n * bytes32 public constant MY_ROLE = keccak256(\\\"MY_ROLE\\\");\\n * ```\\n *\\n * Roles can be used to represent a set of permissions. To restrict access to a\\n * function call, use {hasRole}:\\n *\\n * ```\\n * function foo() public {\\n *     require(hasRole(MY_ROLE, msg.sender));\\n *     ...\\n * }\\n * ```\\n *\\n * Roles can be granted and revoked dynamically via the {grantRole} and\\n * {revokeRole} functions. Each role has an associated admin role, and only\\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\\n *\\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\\n * that only accounts with this role will be able to grant or revoke other\\n * roles. More complex role relationships can be created by using\\n * {_setRoleAdmin}.\\n *\\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\\n * grant and revoke this role. Extra precautions should be taken to secure\\n * accounts that have been granted it.\\n */\\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\\n    struct RoleData {\\n        mapping(address => bool) members;\\n        bytes32 adminRole;\\n    }\\n\\n    mapping(bytes32 => RoleData) private _roles;\\n\\n    bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\\n\\n    /**\\n     * @dev Modifier that checks that an account has a specific role. Reverts\\n     * with a standardized message including the required role.\\n     *\\n     * The format of the revert reason is given by the following regular expression:\\n     *\\n     *  /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/\\n     *\\n     * _Available since v4.1._\\n     */\\n    modifier onlyRole(bytes32 role) {\\n        _checkRole(role, _msgSender());\\n        _;\\n    }\\n\\n    /**\\n     * @dev See {IERC165-supportsInterface}.\\n     */\\n    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\\n        return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\\n    }\\n\\n    /**\\n     * @dev Returns `true` if `account` has been granted `role`.\\n     */\\n    function hasRole(bytes32 role, address account) public view virtual override returns (bool) {\\n        return _roles[role].members[account];\\n    }\\n\\n    /**\\n     * @dev Revert with a standard message if `account` is missing `role`.\\n     *\\n     * The format of the revert reason is given by the following regular expression:\\n     *\\n     *  /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/\\n     */\\n    function _checkRole(bytes32 role, address account) internal view virtual {\\n        if (!hasRole(role, account)) {\\n            revert(\\n                string(\\n                    abi.encodePacked(\\n                        \\\"AccessControl: account \\\",\\n                        Strings.toHexString(uint160(account), 20),\\n                        \\\" is missing role \\\",\\n                        Strings.toHexString(uint256(role), 32)\\n                    )\\n                )\\n            );\\n        }\\n    }\\n\\n    /**\\n     * @dev Returns the admin role that controls `role`. See {grantRole} and\\n     * {revokeRole}.\\n     *\\n     * To change a role's admin, use {_setRoleAdmin}.\\n     */\\n    function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) {\\n        return _roles[role].adminRole;\\n    }\\n\\n    /**\\n     * @dev Grants `role` to `account`.\\n     *\\n     * If `account` had not been already granted `role`, emits a {RoleGranted}\\n     * event.\\n     *\\n     * Requirements:\\n     *\\n     * - the caller must have ``role``'s admin role.\\n     */\\n    function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {\\n        _grantRole(role, account);\\n    }\\n\\n    /**\\n     * @dev Revokes `role` from `account`.\\n     *\\n     * If `account` had been granted `role`, emits a {RoleRevoked} event.\\n     *\\n     * Requirements:\\n     *\\n     * - the caller must have ``role``'s admin role.\\n     */\\n    function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {\\n        _revokeRole(role, account);\\n    }\\n\\n    /**\\n     * @dev Revokes `role` from the calling account.\\n     *\\n     * Roles are often managed via {grantRole} and {revokeRole}: this function's\\n     * purpose is to provide a mechanism for accounts to lose their privileges\\n     * if they are compromised (such as when a trusted device is misplaced).\\n     *\\n     * If the calling account had been revoked `role`, emits a {RoleRevoked}\\n     * event.\\n     *\\n     * Requirements:\\n     *\\n     * - the caller must be `account`.\\n     */\\n    function renounceRole(bytes32 role, address account) public virtual override {\\n        require(account == _msgSender(), \\\"AccessControl: can only renounce roles for self\\\");\\n\\n        _revokeRole(role, account);\\n    }\\n\\n    /**\\n     * @dev Grants `role` to `account`.\\n     *\\n     * If `account` had not been already granted `role`, emits a {RoleGranted}\\n     * event. Note that unlike {grantRole}, this function doesn't perform any\\n     * checks on the calling account.\\n     *\\n     * [WARNING]\\n     * ====\\n     * This function should only be called from the constructor when setting\\n     * up the initial roles for the system.\\n     *\\n     * Using this function in any other way is effectively circumventing the admin\\n     * system imposed by {AccessControl}.\\n     * ====\\n     *\\n     * NOTE: This function is deprecated in favor of {_grantRole}.\\n     */\\n    function _setupRole(bytes32 role, address account) internal virtual {\\n        _grantRole(role, account);\\n    }\\n\\n    /**\\n     * @dev Sets `adminRole` as ``role``'s admin role.\\n     *\\n     * Emits a {RoleAdminChanged} event.\\n     */\\n    function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\\n        bytes32 previousAdminRole = getRoleAdmin(role);\\n        _roles[role].adminRole = adminRole;\\n        emit RoleAdminChanged(role, previousAdminRole, adminRole);\\n    }\\n\\n    /**\\n     * @dev Grants `role` to `account`.\\n     *\\n     * Internal function without access restriction.\\n     */\\n    function _grantRole(bytes32 role, address account) internal virtual {\\n        if (!hasRole(role, account)) {\\n            _roles[role].members[account] = true;\\n            emit RoleGranted(role, account, _msgSender());\\n        }\\n    }\\n\\n    /**\\n     * @dev Revokes `role` from `account`.\\n     *\\n     * Internal function without access restriction.\\n     */\\n    function _revokeRole(bytes32 role, address account) internal virtual {\\n        if (hasRole(role, account)) {\\n            _roles[role].members[account] = false;\\n            emit RoleRevoked(role, account, _msgSender());\\n        }\\n    }\\n}\\n\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n    /**\\n     * @dev Returns true if `account` is a contract.\\n     *\\n     * [IMPORTANT]\\n     * ====\\n     * It is unsafe to assume that an address for which this function returns\\n     * false is an externally-owned account (EOA) and not a contract.\\n     *\\n     * Among others, `isContract` will return false for the following\\n     * types of addresses:\\n     *\\n     *  - an externally-owned account\\n     *  - a contract in construction\\n     *  - an address where a contract will be created\\n     *  - an address where a contract lived, but was destroyed\\n     * ====\\n     *\\n     * [IMPORTANT]\\n     * ====\\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n     *\\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n     * constructor.\\n     * ====\\n     */\\n    function isContract(address account) internal view returns (bool) {\\n        // This method relies on extcodesize/address.code.length, which returns 0\\n        // for contracts in construction, since the code is only stored at the end\\n        // of the constructor execution.\\n\\n        return account.code.length > 0;\\n    }\\n\\n    /**\\n     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n     * `recipient`, forwarding all available gas and reverting on errors.\\n     *\\n     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n     * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n     * imposed by `transfer`, making them unable to receive funds via\\n     * `transfer`. {sendValue} removes this limitation.\\n     *\\n     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n     *\\n     * IMPORTANT: because control is transferred to `recipient`, care must be\\n     * taken to not create reentrancy vulnerabilities. Consider using\\n     * {ReentrancyGuard} or the\\n     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n     */\\n    function sendValue(address payable recipient, uint256 amount) internal {\\n        require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n        (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n        require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n    }\\n\\n    /**\\n     * @dev Performs a Solidity function call using a low level `call`. A\\n     * plain `call` is an unsafe replacement for a function call: use this\\n     * function instead.\\n     *\\n     * If `target` reverts with a revert reason, it is bubbled up by this\\n     * function (like regular Solidity function calls).\\n     *\\n     * Returns the raw returned data. To convert to the expected return value,\\n     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n     *\\n     * Requirements:\\n     *\\n     * - `target` must be a contract.\\n     * - calling `target` with `data` must not revert.\\n     *\\n     * _Available since v3.1._\\n     */\\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n        return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n    }\\n\\n    /**\\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n     * `errorMessage` as a fallback revert reason when `target` reverts.\\n     *\\n     * _Available since v3.1._\\n     */\\n    function functionCall(\\n        address target,\\n        bytes memory data,\\n        string memory errorMessage\\n    ) internal returns (bytes memory) {\\n        return functionCallWithValue(target, data, 0, errorMessage);\\n    }\\n\\n    /**\\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n     * but also transferring `value` wei to `target`.\\n     *\\n     * Requirements:\\n     *\\n     * - the calling contract must have an ETH balance of at least `value`.\\n     * - the called Solidity function must be `payable`.\\n     *\\n     * _Available since v3.1._\\n     */\\n    function functionCallWithValue(\\n        address target,\\n        bytes memory data,\\n        uint256 value\\n    ) internal returns (bytes memory) {\\n        return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n    }\\n\\n    /**\\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\\n     *\\n     * _Available since v3.1._\\n     */\\n    function functionCallWithValue(\\n        address target,\\n        bytes memory data,\\n        uint256 value,\\n        string memory errorMessage\\n    ) internal returns (bytes memory) {\\n        require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n        require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\\n        return verifyCallResult(success, returndata, errorMessage);\\n    }\\n\\n    /**\\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n     * but performing a static call.\\n     *\\n     * _Available since v3.3._\\n     */\\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n        return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n    }\\n\\n    /**\\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n     * but performing a static call.\\n     *\\n     * _Available since v3.3._\\n     */\\n    function functionStaticCall(\\n        address target,\\n        bytes memory data,\\n        string memory errorMessage\\n    ) internal view returns (bytes memory) {\\n        require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n        (bool success, bytes memory returndata) = target.staticcall(data);\\n        return verifyCallResult(success, returndata, errorMessage);\\n    }\\n\\n    /**\\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n     * but performing a delegate call.\\n     *\\n     * _Available since v3.4._\\n     */\\n    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n        return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n    }\\n\\n    /**\\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n     * but performing a delegate call.\\n     *\\n     * _Available since v3.4._\\n     */\\n    function functionDelegateCall(\\n        address target,\\n        bytes memory data,\\n        string memory errorMessage\\n    ) internal returns (bytes memory) {\\n        require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n        (bool success, bytes memory returndata) = target.delegatecall(data);\\n        return verifyCallResult(success, returndata, errorMessage);\\n    }\\n\\n    /**\\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n     * revert reason using the provided one.\\n     *\\n     * _Available since v4.3._\\n     */\\n    function verifyCallResult(\\n        bool success,\\n        bytes memory returndata,\\n        string memory errorMessage\\n    ) internal pure returns (bytes memory) {\\n        if (success) {\\n            return returndata;\\n        } else {\\n            // Look for revert reason and bubble it up if present\\n            if (returndata.length > 0) {\\n                // The easiest way to bubble the revert reason is using memory via assembly\\n\\n                assembly {\\n                    let returndata_size := mload(returndata)\\n                    revert(add(32, returndata), returndata_size)\\n                }\\n            } else {\\n                revert(errorMessage);\\n            }\\n        }\\n    }\\n}\\n\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n    /**\\n     * @dev Returns the amount of tokens in existence.\\n     */\\n    function totalSupply() external view returns (uint256);\\n\\n    /**\\n     * @dev Returns the amount of tokens owned by `account`.\\n     */\\n    function balanceOf(address account) external view returns (uint256);\\n\\n    /**\\n     * @dev Moves `amount` tokens from the caller's account to `to`.\\n     *\\n     * Returns a boolean value indicating whether the operation succeeded.\\n     *\\n     * Emits a {Transfer} event.\\n     */\\n    function transfer(address to, uint256 amount) external returns (bool);\\n\\n    /**\\n     * @dev Returns the remaining number of tokens that `spender` will be\\n     * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n     * zero by default.\\n     *\\n     * This value changes when {approve} or {transferFrom} are called.\\n     */\\n    function allowance(address owner, address spender) external view returns (uint256);\\n\\n    /**\\n     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n     *\\n     * Returns a boolean value indicating whether the operation succeeded.\\n     *\\n     * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n     * that someone may use both the old and the new allowance by unfortunate\\n     * transaction ordering. One possible solution to mitigate this race\\n     * condition is to first reduce the spender's allowance to 0 and set the\\n     * desired value afterwards:\\n     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n     *\\n     * Emits an {Approval} event.\\n     */\\n    function approve(address spender, uint256 amount) external returns (bool);\\n\\n    /**\\n     * @dev Moves `amount` tokens from `from` to `to` using the\\n     * allowance mechanism. `amount` is then deducted from the caller's\\n     * allowance.\\n     *\\n     * Returns a boolean value indicating whether the operation succeeded.\\n     *\\n     * Emits a {Transfer} event.\\n     */\\n    function transferFrom(\\n        address from,\\n        address to,\\n        uint256 amount\\n    ) external returns (bool);\\n\\n    /**\\n     * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n     * another (`to`).\\n     *\\n     * Note that `value` may be zero.\\n     */\\n    event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n    /**\\n     * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n     * a call to {approve}. `value` is the new allowance.\\n     */\\n    event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\"}},\"settings\":{\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000},\"remappings\":[],\"outputSelection\":{\"*\":{\"*\":[\"evm.bytecode\",\"evm.deployedBytecode\",\"devdoc\",\"userdoc\",\"metadata\",\"abi\"]}}}},\"ABI\":\"[{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":false,\\\"internalType\\\":\\\"address[]\\\",\\\"name\\\":\\\"tokens\\\",\\\"type\\\":\\\"address[]\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256[]\\\",\\\"name\\\":\\\"limits\\\",\\\"type\\\":\\\"uint256[]\\\"}],\\\"name\\\":\\\"DailyWithdrawalLimitsUpdated\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":false,\\\"internalType\\\":\\\"bytes32\\\",\\\"name\\\":\\\"receiptHash\\\",\\\"type\\\":\\\"bytes32\\\"},{\\\"components\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"id\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"enum Transfer.Kind\\\",\\\"name\\\":\\\"kind\\\",\\\"type\\\":\\\"uint8\\\"},{\\\"components\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"addr\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"tokenAddr\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"chainId\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"internalType\\\":\\\"struct Token.Owner\\\",\\\"name\\\":\\\"mainchain\\\",\\\"type\\\":\\\"tuple\\\"},{\\\"components\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"addr\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"tokenAddr\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"chainId\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"internalType\\\":\\\"struct Token.Owner\\\",\\\"name\\\":\\\"ronin\\\",\\\"type\\\":\\\"tuple\\\"},{\\\"components\\\":[{\\\"internalType\\\":\\\"enum Token.Standard\\\",\\\"name\\\":\\\"erc\\\",\\\"type\\\":\\\"uint8\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"id\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"quantity\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"internalType\\\":\\\"struct Token.Info\\\",\\\"name\\\":\\\"info\\\",\\\"type\\\":\\\"tuple\\\"}],\\\"indexed\\\":false,\\\"internalType\\\":\\\"struct Transfer.Receipt\\\",\\\"name\\\":\\\"receipt\\\",\\\"type\\\":\\\"tuple\\\"}],\\\"name\\\":\\\"DepositRequested\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":false,\\\"internalType\\\":\\\"address[]\\\",\\\"name\\\":\\\"tokens\\\",\\\"type\\\":\\\"address[]\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256[]\\\",\\\"name\\\":\\\"thresholds\\\",\\\"type\\\":\\\"uint256[]\\\"}],\\\"name\\\":\\\"HighTierThresholdsUpdated\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":true,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"nonce\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"indexed\\\":true,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"numerator\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"indexed\\\":true,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"denominator\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"previousNumerator\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"previousDenominator\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"HighTierVoteWeightThresholdUpdated\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":false,\\\"internalType\\\":\\\"address[]\\\",\\\"name\\\":\\\"tokens\\\",\\\"type\\\":\\\"address[]\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256[]\\\",\\\"name\\\":\\\"thresholds\\\",\\\"type\\\":\\\"uint256[]\\\"}],\\\"name\\\":\\\"LockedThresholdsUpdated\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":false,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"account\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"Paused\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":true,\\\"internalType\\\":\\\"bytes32\\\",\\\"name\\\":\\\"role\\\",\\\"type\\\":\\\"bytes32\\\"},{\\\"indexed\\\":true,\\\"internalType\\\":\\\"bytes32\\\",\\\"name\\\":\\\"previousAdminRole\\\",\\\"type\\\":\\\"bytes32\\\"},{\\\"indexed\\\":true,\\\"internalType\\\":\\\"bytes32\\\",\\\"name\\\":\\\"newAdminRole\\\",\\\"type\\\":\\\"bytes32\\\"}],\\\"name\\\":\\\"RoleAdminChanged\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":true,\\\"internalType\\\":\\\"bytes32\\\",\\\"name\\\":\\\"role\\\",\\\"type\\\":\\\"bytes32\\\"},{\\\"indexed\\\":true,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"account\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":true,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"sender\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"RoleGranted\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":true,\\\"internalType\\\":\\\"bytes32\\\",\\\"name\\\":\\\"role\\\",\\\"type\\\":\\\"bytes32\\\"},{\\\"indexed\\\":true,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"account\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":true,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"sender\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"RoleRevoked\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":true,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"nonce\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"indexed\\\":true,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"numerator\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"indexed\\\":true,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"denominator\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"previousNumerator\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"previousDenominator\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"ThresholdUpdated\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":false,\\\"internalType\\\":\\\"address[]\\\",\\\"name\\\":\\\"mainchainTokens\\\",\\\"type\\\":\\\"address[]\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"address[]\\\",\\\"name\\\":\\\"roninTokens\\\",\\\"type\\\":\\\"address[]\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"enum Token.Standard[]\\\",\\\"name\\\":\\\"standards\\\",\\\"type\\\":\\\"uint8[]\\\"}],\\\"name\\\":\\\"TokenMapped\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":false,\\\"internalType\\\":\\\"address[]\\\",\\\"name\\\":\\\"tokens\\\",\\\"type\\\":\\\"address[]\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256[]\\\",\\\"name\\\":\\\"percentages\\\",\\\"type\\\":\\\"uint256[]\\\"}],\\\"name\\\":\\\"UnlockFeePercentagesUpdated\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":false,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"account\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"Unpaused\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":false,\\\"internalType\\\":\\\"contract IWeightedValidator\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"ValidatorContractUpdated\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":false,\\\"internalType\\\":\\\"bytes32\\\",\\\"name\\\":\\\"receiptHash\\\",\\\"type\\\":\\\"bytes32\\\"},{\\\"components\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"id\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"enum Transfer.Kind\\\",\\\"name\\\":\\\"kind\\\",\\\"type\\\":\\\"uint8\\\"},{\\\"components\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"addr\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"tokenAddr\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"chainId\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"internalType\\\":\\\"struct Token.Owner\\\",\\\"name\\\":\\\"mainchain\\\",\\\"type\\\":\\\"tuple\\\"},{\\\"components\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"addr\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"tokenAddr\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"chainId\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"internalType\\\":\\\"struct Token.Owner\\\",\\\"name\\\":\\\"ronin\\\",\\\"type\\\":\\\"tuple\\\"},{\\\"components\\\":[{\\\"internalType\\\":\\\"enum Token.Standard\\\",\\\"name\\\":\\\"erc\\\",\\\"type\\\":\\\"uint8\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"id\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"quantity\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"internalType\\\":\\\"struct Token.Info\\\",\\\"name\\\":\\\"info\\\",\\\"type\\\":\\\"tuple\\\"}],\\\"indexed\\\":false,\\\"internalType\\\":\\\"struct Transfer.Receipt\\\",\\\"name\\\":\\\"receipt\\\",\\\"type\\\":\\\"tuple\\\"}],\\\"name\\\":\\\"WithdrawalLocked\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":false,\\\"internalType\\\":\\\"bytes32\\\",\\\"name\\\":\\\"receiptHash\\\",\\\"type\\\":\\\"bytes32\\\"},{\\\"components\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"id\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"enum Transfer.Kind\\\",\\\"name\\\":\\\"kind\\\",\\\"type\\\":\\\"uint8\\\"},{\\\"components\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"addr\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"tokenAddr\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"chainId\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"internalType\\\":\\\"struct Token.Owner\\\",\\\"name\\\":\\\"mainchain\\\",\\\"type\\\":\\\"tuple\\\"},{\\\"components\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"addr\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"tokenAddr\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"chainId\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"internalType\\\":\\\"struct Token.Owner\\\",\\\"name\\\":\\\"ronin\\\",\\\"type\\\":\\\"tuple\\\"},{\\\"components\\\":[{\\\"internalType\\\":\\\"enum Token.Standard\\\",\\\"name\\\":\\\"erc\\\",\\\"type\\\":\\\"uint8\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"id\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"quantity\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"internalType\\\":\\\"struct Token.Info\\\",\\\"name\\\":\\\"info\\\",\\\"type\\\":\\\"tuple\\\"}],\\\"indexed\\\":false,\\\"internalType\\\":\\\"struct Transfer.Receipt\\\",\\\"name\\\":\\\"receipt\\\",\\\"type\\\":\\\"tuple\\\"}],\\\"name\\\":\\\"WithdrawalUnlocked\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":false,\\\"internalType\\\":\\\"bytes32\\\",\\\"name\\\":\\\"receiptHash\\\",\\\"type\\\":\\\"bytes32\\\"},{\\\"components\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"id\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"enum Transfer.Kind\\\",\\\"name\\\":\\\"kind\\\",\\\"type\\\":\\\"uint8\\\"},{\\\"components\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"addr\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"tokenAddr\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"chainId\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"internalType\\\":\\\"struct Token.Owner\\\",\\\"name\\\":\\\"mainchain\\\",\\\"type\\\":\\\"tuple\\\"},{\\\"components\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"addr\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"tokenAddr\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"chainId\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"internalType\\\":\\\"struct Token.Owner\\\",\\\"name\\\":\\\"ronin\\\",\\\"type\\\":\\\"tuple\\\"},{\\\"components\\\":[{\\\"internalType\\\":\\\"enum Token.Standard\\\",\\\"name\\\":\\\"erc\\\",\\\"type\\\":\\\"uint8\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"id\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"quantity\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"internalType\\\":\\\"struct Token.Info\\\",\\\"name\\\":\\\"info\\\",\\\"type\\\":\\\"tuple\\\"}],\\\"indexed\\\":false,\\\"internalType\\\":\\\"struct Transfer.Receipt\\\",\\\"name\\\":\\\"receipt\\\",\\\"type\\\":\\\"tuple\\\"}],\\\"name\\\":\\\"Withdrew\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":false,\\\"internalType\\\":\\\"contract IWETH\\\",\\\"name\\\":\\\"weth\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"WrappedNativeTokenContractUpdated\\\",\\\"type\\\":\\\"event\\\"},{\\\"stateMutability\\\":\\\"payable\\\",\\\"type\\\":\\\"fallback\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"DEFAULT_ADMIN_ROLE\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"bytes32\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"bytes32\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"DOMAIN_SEPARATOR\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"bytes32\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"bytes32\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"WITHDRAWAL_UNLOCKER_ROLE\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"bytes32\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"bytes32\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"_MAX_PERCENTAGE\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"_voteWeight\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"checkHighTierVoteWeightThreshold\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"bool\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"bool\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"_voteWeight\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"checkThreshold\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"bool\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"bool\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"dailyWithdrawalLimit\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"depositCount\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"getHighTierVoteWeightThreshold\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"bytes32\\\",\\\"name\\\":\\\"role\\\",\\\"type\\\":\\\"bytes32\\\"}],\\\"name\\\":\\\"getRoleAdmin\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"bytes32\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"bytes32\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"bytes32\\\",\\\"name\\\":\\\"role\\\",\\\"type\\\":\\\"bytes32\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"index\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"getRoleMember\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"address\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"bytes32\\\",\\\"name\\\":\\\"role\\\",\\\"type\\\":\\\"bytes32\\\"}],\\\"name\\\":\\\"getRoleMemberCount\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"_mainchainToken\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"getRoninToken\\\",\\\"outputs\\\":[{\\\"components\\\":[{\\\"internalType\\\":\\\"enum Token.Standard\\\",\\\"name\\\":\\\"erc\\\",\\\"type\\\":\\\"uint8\\\"},{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"tokenAddr\\\",\\\"type\\\":\\\"address\\\"}],\\\"internalType\\\":\\\"struct MappedTokenConsumer.MappedToken\\\",\\\"name\\\":\\\"_token\\\",\\\"type\\\":\\\"tuple\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"getThreshold\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"bytes32\\\",\\\"name\\\":\\\"role\\\",\\\"type\\\":\\\"bytes32\\\"},{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"account\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"grantRole\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"bytes32\\\",\\\"name\\\":\\\"role\\\",\\\"type\\\":\\\"bytes32\\\"},{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"account\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"hasRole\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"bool\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"bool\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"highTierThreshold\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"_roleSetter\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"contract IWETH\\\",\\\"name\\\":\\\"_wrappedToken\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"contract IWeightedValidator\\\",\\\"name\\\":\\\"_validatorContract\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"_roninChainId\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"_numerator\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"_highTierVWNumerator\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"_denominator\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"address[][3]\\\",\\\"name\\\":\\\"_addresses\\\",\\\"type\\\":\\\"address[][3]\\\"},{\\\"internalType\\\":\\\"uint256[][4]\\\",\\\"name\\\":\\\"_thresholds\\\",\\\"type\\\":\\\"uint256[][4]\\\"},{\\\"internalType\\\":\\\"enum Token.Standard[]\\\",\\\"name\\\":\\\"_standards\\\",\\\"type\\\":\\\"uint8[]\\\"}],\\\"name\\\":\\\"initialize\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"payable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"lastDateSynced\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"lastSyncedWithdrawal\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"lockedThreshold\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address[]\\\",\\\"name\\\":\\\"_mainchainTokens\\\",\\\"type\\\":\\\"address[]\\\"},{\\\"internalType\\\":\\\"address[]\\\",\\\"name\\\":\\\"_roninTokens\\\",\\\"type\\\":\\\"address[]\\\"},{\\\"internalType\\\":\\\"enum Token.Standard[]\\\",\\\"name\\\":\\\"_standards\\\",\\\"type\\\":\\\"uint8[]\\\"}],\\\"name\\\":\\\"mapTokens\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address[]\\\",\\\"name\\\":\\\"_mainchainTokens\\\",\\\"type\\\":\\\"address[]\\\"},{\\\"internalType\\\":\\\"address[]\\\",\\\"name\\\":\\\"_roninTokens\\\",\\\"type\\\":\\\"address[]\\\"},{\\\"internalType\\\":\\\"enum Token.Standard[]\\\",\\\"name\\\":\\\"_standards\\\",\\\"type\\\":\\\"uint8[]\\\"},{\\\"internalType\\\":\\\"uint256[][4]\\\",\\\"name\\\":\\\"_thresholds\\\",\\\"type\\\":\\\"uint256[][4]\\\"}],\\\"name\\\":\\\"mapTokensAndThresholds\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"minimumVoteWeight\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"nonce\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"pause\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"paused\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"bool\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"bool\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"_token\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"_quantity\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"reachedWithdrawalLimit\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"bool\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"bool\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"receiveEther\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"payable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"bytes32\\\",\\\"name\\\":\\\"role\\\",\\\"type\\\":\\\"bytes32\\\"},{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"account\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"renounceRole\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"components\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"recipientAddr\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"tokenAddr\\\",\\\"type\\\":\\\"address\\\"},{\\\"components\\\":[{\\\"internalType\\\":\\\"enum Token.Standard\\\",\\\"name\\\":\\\"erc\\\",\\\"type\\\":\\\"uint8\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"id\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"quantity\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"internalType\\\":\\\"struct Token.Info\\\",\\\"name\\\":\\\"info\\\",\\\"type\\\":\\\"tuple\\\"}],\\\"internalType\\\":\\\"struct Transfer.Request\\\",\\\"name\\\":\\\"_request\\\",\\\"type\\\":\\\"tuple\\\"}],\\\"name\\\":\\\"requestDepositFor\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"payable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"bytes32\\\",\\\"name\\\":\\\"role\\\",\\\"type\\\":\\\"bytes32\\\"},{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"account\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"revokeRole\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"roninChainId\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address[]\\\",\\\"name\\\":\\\"_tokens\\\",\\\"type\\\":\\\"address[]\\\"},{\\\"internalType\\\":\\\"uint256[]\\\",\\\"name\\\":\\\"_limits\\\",\\\"type\\\":\\\"uint256[]\\\"}],\\\"name\\\":\\\"setDailyWithdrawalLimits\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address[]\\\",\\\"name\\\":\\\"_tokens\\\",\\\"type\\\":\\\"address[]\\\"},{\\\"internalType\\\":\\\"uint256[]\\\",\\\"name\\\":\\\"_thresholds\\\",\\\"type\\\":\\\"uint256[]\\\"}],\\\"name\\\":\\\"setHighTierThresholds\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"_numerator\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"_denominator\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"setHighTierVoteWeightThreshold\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"_previousNum\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"_previousDenom\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address[]\\\",\\\"name\\\":\\\"_tokens\\\",\\\"type\\\":\\\"address[]\\\"},{\\\"internalType\\\":\\\"uint256[]\\\",\\\"name\\\":\\\"_thresholds\\\",\\\"type\\\":\\\"uint256[]\\\"}],\\\"name\\\":\\\"setLockedThresholds\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"_numerator\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"_denominator\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"setThreshold\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"_previousNum\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"_previousDenom\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address[]\\\",\\\"name\\\":\\\"_tokens\\\",\\\"type\\\":\\\"address[]\\\"},{\\\"internalType\\\":\\\"uint256[]\\\",\\\"name\\\":\\\"_percentages\\\",\\\"type\\\":\\\"uint256[]\\\"}],\\\"name\\\":\\\"setUnlockFeePercentages\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"contract IWeightedValidator\\\",\\\"name\\\":\\\"_validatorContract\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"setValidatorContract\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"contract IWETH\\\",\\\"name\\\":\\\"_wrappedToken\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"setWrappedNativeTokenContract\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"components\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"id\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"enum Transfer.Kind\\\",\\\"name\\\":\\\"kind\\\",\\\"type\\\":\\\"uint8\\\"},{\\\"components\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"addr\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"tokenAddr\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"chainId\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"internalType\\\":\\\"struct Token.Owner\\\",\\\"name\\\":\\\"mainchain\\\",\\\"type\\\":\\\"tuple\\\"},{\\\"components\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"addr\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"tokenAddr\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"chainId\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"internalType\\\":\\\"struct Token.Owner\\\",\\\"name\\\":\\\"ronin\\\",\\\"type\\\":\\\"tuple\\\"},{\\\"components\\\":[{\\\"internalType\\\":\\\"enum Token.Standard\\\",\\\"name\\\":\\\"erc\\\",\\\"type\\\":\\\"uint8\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"id\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"quantity\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"internalType\\\":\\\"struct Token.Info\\\",\\\"name\\\":\\\"info\\\",\\\"type\\\":\\\"tuple\\\"}],\\\"internalType\\\":\\\"struct Transfer.Receipt\\\",\\\"name\\\":\\\"_receipt\\\",\\\"type\\\":\\\"tuple\\\"},{\\\"components\\\":[{\\\"internalType\\\":\\\"uint8\\\",\\\"name\\\":\\\"v\\\",\\\"type\\\":\\\"uint8\\\"},{\\\"internalType\\\":\\\"bytes32\\\",\\\"name\\\":\\\"r\\\",\\\"type\\\":\\\"bytes32\\\"},{\\\"internalType\\\":\\\"bytes32\\\",\\\"name\\\":\\\"s\\\",\\\"type\\\":\\\"bytes32\\\"}],\\\"internalType\\\":\\\"struct SignatureConsumer.Signature[]\\\",\\\"name\\\":\\\"_signatures\\\",\\\"type\\\":\\\"tuple[]\\\"}],\\\"name\\\":\\\"submitWithdrawal\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"bool\\\",\\\"name\\\":\\\"_locked\\\",\\\"type\\\":\\\"bool\\\"}],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"bytes4\\\",\\\"name\\\":\\\"interfaceId\\\",\\\"type\\\":\\\"bytes4\\\"}],\\\"name\\\":\\\"supportsInterface\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"bool\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"bool\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"unlockFeePercentages\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"components\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"id\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"enum Transfer.Kind\\\",\\\"name\\\":\\\"kind\\\",\\\"type\\\":\\\"uint8\\\"},{\\\"components\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"addr\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"tokenAddr\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"chainId\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"internalType\\\":\\\"struct Token.Owner\\\",\\\"name\\\":\\\"mainchain\\\",\\\"type\\\":\\\"tuple\\\"},{\\\"components\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"addr\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"tokenAddr\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"chainId\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"internalType\\\":\\\"struct Token.Owner\\\",\\\"name\\\":\\\"ronin\\\",\\\"type\\\":\\\"tuple\\\"},{\\\"components\\\":[{\\\"internalType\\\":\\\"enum Token.Standard\\\",\\\"name\\\":\\\"erc\\\",\\\"type\\\":\\\"uint8\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"id\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"quantity\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"internalType\\\":\\\"struct Token.Info\\\",\\\"name\\\":\\\"info\\\",\\\"type\\\":\\\"tuple\\\"}],\\\"internalType\\\":\\\"struct Transfer.Receipt\\\",\\\"name\\\":\\\"_receipt\\\",\\\"type\\\":\\\"tuple\\\"}],\\\"name\\\":\\\"unlockWithdrawal\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"unpause\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"validatorContract\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"contract IWeightedValidator\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"address\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"withdrawalHash\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"bytes32\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"bytes32\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"withdrawalLocked\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"bool\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"bool\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"wrappedNativeToken\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"contract IWETH\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"address\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"stateMutability\\\":\\\"payable\\\",\\\"type\\\":\\\"receive\\\"}]\",\"ContractName\":\"MainchainGatewayV2\",\"CompilerVersion\":\"v0.8.9+commit.e5eed63a\",\"OptimizationUsed\":1,\"Runs\":1000,\"ConstructorArguments\":\"0x\",\"EVMVersion\":\"Default\",\"Library\":\"\",\"LicenseType\":\"MIT\",\"Proxy\":0,\"SwarmSource\":\"\"}]"
  },
  {
    "path": "testdata/etherscan/0x8B3D32cf2bb4d0D16656f4c0b04Fa546274f1545/creation_data.json",
    "content": "{\"contractAddress\":\"0x8b3d32cf2bb4d0d16656f4c0b04fa546274f1545\",\"contractCreator\":\"0x958892b4a0512b28aaac890fc938868bbd42f064\",\"txHash\":\"0x79820495643caf5a1e7e96578361c9ddba0e0735cd684ada7450254f6fd58f51\"}"
  },
  {
    "path": "testdata/etherscan/0x8B3D32cf2bb4d0D16656f4c0b04Fa546274f1545/metadata.json",
    "content": "[{\"SourceCode\":{\"language\":\"Solidity\",\"sources\":{\"contracts/governance/governor/GovernorStorage.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.9;\\n\\nimport \\\"./IIpt.sol\\\";\\nimport \\\"./Structs.sol\\\";\\n\\ncontract GovernorCharlieDelegatorStorage {\\n  /// @notice Active brains of Governor\\n  address public implementation;\\n}\\n\\n/**\\n * @title Storage for Governor Charlie Delegate\\n * @notice For future upgrades, do not change GovernorCharlieDelegateStorage. Create a new\\n * contract which implements GovernorCharlieDelegateStorage and following the naming convention\\n * GovernorCharlieDelegateStorageVX.\\n */\\n//solhint-disable-next-line max-states-count\\ncontract GovernorCharlieDelegateStorage is GovernorCharlieDelegatorStorage {\\n  /// @notice The number of votes in support of a proposal required in order for a quorum to be reached and for a vote to succeed\\n  uint256 public quorumVotes;\\n\\n  /// @notice The number of votes in support of a proposal required in order for an emergency quorum to be reached and for a vote to succeed\\n  uint256 public emergencyQuorumVotes;\\n\\n  /// @notice The delay before voting on a proposal may take place, once proposed, in blocks\\n  uint256 public votingDelay;\\n\\n  /// @notice The duration of voting on a proposal, in blocks\\n  uint256 public votingPeriod;\\n\\n  /// @notice The number of votes required in order for a voter to become a proposer\\n  uint256 public proposalThreshold;\\n\\n  /// @notice Initial proposal id set at become\\n  uint256 public initialProposalId;\\n\\n  /// @notice The total number of proposals\\n  uint256 public proposalCount;\\n\\n  /// @notice The address of the Interest Protocol governance token\\n  IIpt public ipt;\\n\\n  /// @notice The official record of all proposals ever proposed\\n  mapping(uint256 => Proposal) public proposals;\\n\\n  /// @notice The latest proposal for each proposer\\n  mapping(address => uint256) public latestProposalIds;\\n\\n  /// @notice The latest proposal for each proposer\\n  mapping(bytes32 => bool) public queuedTransactions;\\n\\n  /// @notice The proposal holding period\\n  uint256 public proposalTimelockDelay;\\n\\n  /// @notice Stores the expiration of account whitelist status as a timestamp\\n  mapping(address => uint256) public whitelistAccountExpirations;\\n\\n  /// @notice Address which manages whitelisted proposals and whitelist accounts\\n  address public whitelistGuardian;\\n\\n  /// @notice The duration of the voting on a emergency proposal, in blocks\\n  uint256 public emergencyVotingPeriod;\\n\\n  /// @notice The emergency proposal holding period\\n  uint256 public emergencyTimelockDelay;\\n\\n  /// all receipts for proposal\\n  mapping(uint256 => mapping(address => Receipt)) public proposalReceipts;\\n\\n  /// @notice The emergency proposal holding period\\n  bool public initialized;\\n\\n  /// @notice The number of votes to reject an optimistic proposal\\n  uint256 public optimisticQuorumVotes; \\n\\n  /// @notice The delay period before voting begins\\n  uint256 public optimisticVotingDelay; \\n\\n  /// @notice The maximum number of seconds an address can be whitelisted for\\n  uint256 public maxWhitelistPeriod; \\n}\\n\"},\"hardhat/console.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >= 0.4.22 <0.9.0;\\n\\nlibrary console {\\n\\taddress constant CONSOLE_ADDRESS = address(0x000000000000000000636F6e736F6c652e6c6f67);\\n\\n\\tfunction _sendLogPayload(bytes memory payload) private view {\\n\\t\\tuint256 payloadLength = payload.length;\\n\\t\\taddress consoleAddress = CONSOLE_ADDRESS;\\n\\t\\tassembly {\\n\\t\\t\\tlet payloadStart := add(payload, 32)\\n\\t\\t\\tlet r := staticcall(gas(), consoleAddress, payloadStart, payloadLength, 0, 0)\\n\\t\\t}\\n\\t}\\n\\n\\tfunction log() internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log()\\\"));\\n\\t}\\n\\n\\tfunction logInt(int p0) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(int)\\\", p0));\\n\\t}\\n\\n\\tfunction logUint(uint p0) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint)\\\", p0));\\n\\t}\\n\\n\\tfunction logString(string memory p0) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string)\\\", p0));\\n\\t}\\n\\n\\tfunction logBool(bool p0) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool)\\\", p0));\\n\\t}\\n\\n\\tfunction logAddress(address p0) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address)\\\", p0));\\n\\t}\\n\\n\\tfunction logBytes(bytes memory p0) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bytes)\\\", p0));\\n\\t}\\n\\n\\tfunction logBytes1(bytes1 p0) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bytes1)\\\", p0));\\n\\t}\\n\\n\\tfunction logBytes2(bytes2 p0) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bytes2)\\\", p0));\\n\\t}\\n\\n\\tfunction logBytes3(bytes3 p0) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bytes3)\\\", p0));\\n\\t}\\n\\n\\tfunction logBytes4(bytes4 p0) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bytes4)\\\", p0));\\n\\t}\\n\\n\\tfunction logBytes5(bytes5 p0) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bytes5)\\\", p0));\\n\\t}\\n\\n\\tfunction logBytes6(bytes6 p0) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bytes6)\\\", p0));\\n\\t}\\n\\n\\tfunction logBytes7(bytes7 p0) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bytes7)\\\", p0));\\n\\t}\\n\\n\\tfunction logBytes8(bytes8 p0) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bytes8)\\\", p0));\\n\\t}\\n\\n\\tfunction logBytes9(bytes9 p0) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bytes9)\\\", p0));\\n\\t}\\n\\n\\tfunction logBytes10(bytes10 p0) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bytes10)\\\", p0));\\n\\t}\\n\\n\\tfunction logBytes11(bytes11 p0) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bytes11)\\\", p0));\\n\\t}\\n\\n\\tfunction logBytes12(bytes12 p0) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bytes12)\\\", p0));\\n\\t}\\n\\n\\tfunction logBytes13(bytes13 p0) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bytes13)\\\", p0));\\n\\t}\\n\\n\\tfunction logBytes14(bytes14 p0) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bytes14)\\\", p0));\\n\\t}\\n\\n\\tfunction logBytes15(bytes15 p0) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bytes15)\\\", p0));\\n\\t}\\n\\n\\tfunction logBytes16(bytes16 p0) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bytes16)\\\", p0));\\n\\t}\\n\\n\\tfunction logBytes17(bytes17 p0) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bytes17)\\\", p0));\\n\\t}\\n\\n\\tfunction logBytes18(bytes18 p0) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bytes18)\\\", p0));\\n\\t}\\n\\n\\tfunction logBytes19(bytes19 p0) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bytes19)\\\", p0));\\n\\t}\\n\\n\\tfunction logBytes20(bytes20 p0) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bytes20)\\\", p0));\\n\\t}\\n\\n\\tfunction logBytes21(bytes21 p0) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bytes21)\\\", p0));\\n\\t}\\n\\n\\tfunction logBytes22(bytes22 p0) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bytes22)\\\", p0));\\n\\t}\\n\\n\\tfunction logBytes23(bytes23 p0) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bytes23)\\\", p0));\\n\\t}\\n\\n\\tfunction logBytes24(bytes24 p0) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bytes24)\\\", p0));\\n\\t}\\n\\n\\tfunction logBytes25(bytes25 p0) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bytes25)\\\", p0));\\n\\t}\\n\\n\\tfunction logBytes26(bytes26 p0) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bytes26)\\\", p0));\\n\\t}\\n\\n\\tfunction logBytes27(bytes27 p0) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bytes27)\\\", p0));\\n\\t}\\n\\n\\tfunction logBytes28(bytes28 p0) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bytes28)\\\", p0));\\n\\t}\\n\\n\\tfunction logBytes29(bytes29 p0) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bytes29)\\\", p0));\\n\\t}\\n\\n\\tfunction logBytes30(bytes30 p0) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bytes30)\\\", p0));\\n\\t}\\n\\n\\tfunction logBytes31(bytes31 p0) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bytes31)\\\", p0));\\n\\t}\\n\\n\\tfunction logBytes32(bytes32 p0) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bytes32)\\\", p0));\\n\\t}\\n\\n\\tfunction log(uint p0) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint)\\\", p0));\\n\\t}\\n\\n\\tfunction log(string memory p0) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string)\\\", p0));\\n\\t}\\n\\n\\tfunction log(bool p0) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool)\\\", p0));\\n\\t}\\n\\n\\tfunction log(address p0) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address)\\\", p0));\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,uint)\\\", p0, p1));\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,string)\\\", p0, p1));\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,bool)\\\", p0, p1));\\n\\t}\\n\\n\\tfunction log(uint p0, address p1) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,address)\\\", p0, p1));\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,uint)\\\", p0, p1));\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,string)\\\", p0, p1));\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,bool)\\\", p0, p1));\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,address)\\\", p0, p1));\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,uint)\\\", p0, p1));\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,string)\\\", p0, p1));\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,bool)\\\", p0, p1));\\n\\t}\\n\\n\\tfunction log(bool p0, address p1) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,address)\\\", p0, p1));\\n\\t}\\n\\n\\tfunction log(address p0, uint p1) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,uint)\\\", p0, p1));\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,string)\\\", p0, p1));\\n\\t}\\n\\n\\tfunction log(address p0, bool p1) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,bool)\\\", p0, p1));\\n\\t}\\n\\n\\tfunction log(address p0, address p1) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,address)\\\", p0, p1));\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, uint p2) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,uint,uint)\\\", p0, p1, p2));\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, string memory p2) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,uint,string)\\\", p0, p1, p2));\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, bool p2) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,uint,bool)\\\", p0, p1, p2));\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, address p2) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,uint,address)\\\", p0, p1, p2));\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, uint p2) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,string,uint)\\\", p0, p1, p2));\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, string memory p2) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,string,string)\\\", p0, p1, p2));\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, bool p2) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,string,bool)\\\", p0, p1, p2));\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, address p2) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,string,address)\\\", p0, p1, p2));\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, uint p2) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,bool,uint)\\\", p0, p1, p2));\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, string memory p2) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,bool,string)\\\", p0, p1, p2));\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, bool p2) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,bool,bool)\\\", p0, p1, p2));\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, address p2) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,bool,address)\\\", p0, p1, p2));\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, uint p2) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,address,uint)\\\", p0, p1, p2));\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, string memory p2) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,address,string)\\\", p0, p1, p2));\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, bool p2) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,address,bool)\\\", p0, p1, p2));\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, address p2) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,address,address)\\\", p0, p1, p2));\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, uint p2) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,uint,uint)\\\", p0, p1, p2));\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, string memory p2) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,uint,string)\\\", p0, p1, p2));\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, bool p2) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,uint,bool)\\\", p0, p1, p2));\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, address p2) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,uint,address)\\\", p0, p1, p2));\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, uint p2) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,string,uint)\\\", p0, p1, p2));\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, string memory p2) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,string,string)\\\", p0, p1, p2));\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, bool p2) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,string,bool)\\\", p0, p1, p2));\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, address p2) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,string,address)\\\", p0, p1, p2));\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, uint p2) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,bool,uint)\\\", p0, p1, p2));\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, string memory p2) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,bool,string)\\\", p0, p1, p2));\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, bool p2) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,bool,bool)\\\", p0, p1, p2));\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, address p2) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,bool,address)\\\", p0, p1, p2));\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, uint p2) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,address,uint)\\\", p0, p1, p2));\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, string memory p2) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,address,string)\\\", p0, p1, p2));\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, bool p2) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,address,bool)\\\", p0, p1, p2));\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, address p2) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,address,address)\\\", p0, p1, p2));\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, uint p2) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,uint,uint)\\\", p0, p1, p2));\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, string memory p2) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,uint,string)\\\", p0, p1, p2));\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, bool p2) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,uint,bool)\\\", p0, p1, p2));\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, address p2) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,uint,address)\\\", p0, p1, p2));\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, uint p2) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,string,uint)\\\", p0, p1, p2));\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, string memory p2) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,string,string)\\\", p0, p1, p2));\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, bool p2) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,string,bool)\\\", p0, p1, p2));\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, address p2) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,string,address)\\\", p0, p1, p2));\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, uint p2) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,bool,uint)\\\", p0, p1, p2));\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, string memory p2) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,bool,string)\\\", p0, p1, p2));\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, bool p2) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,bool,bool)\\\", p0, p1, p2));\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, address p2) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,bool,address)\\\", p0, p1, p2));\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, uint p2) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,address,uint)\\\", p0, p1, p2));\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, string memory p2) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,address,string)\\\", p0, p1, p2));\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, bool p2) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,address,bool)\\\", p0, p1, p2));\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, address p2) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,address,address)\\\", p0, p1, p2));\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, uint p2) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,uint,uint)\\\", p0, p1, p2));\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, string memory p2) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,uint,string)\\\", p0, p1, p2));\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, bool p2) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,uint,bool)\\\", p0, p1, p2));\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, address p2) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,uint,address)\\\", p0, p1, p2));\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, uint p2) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,string,uint)\\\", p0, p1, p2));\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, string memory p2) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,string,string)\\\", p0, p1, p2));\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, bool p2) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,string,bool)\\\", p0, p1, p2));\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, address p2) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,string,address)\\\", p0, p1, p2));\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, uint p2) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,bool,uint)\\\", p0, p1, p2));\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, string memory p2) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,bool,string)\\\", p0, p1, p2));\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, bool p2) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,bool,bool)\\\", p0, p1, p2));\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, address p2) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,bool,address)\\\", p0, p1, p2));\\n\\t}\\n\\n\\tfunction log(address p0, address p1, uint p2) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,address,uint)\\\", p0, p1, p2));\\n\\t}\\n\\n\\tfunction log(address p0, address p1, string memory p2) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,address,string)\\\", p0, p1, p2));\\n\\t}\\n\\n\\tfunction log(address p0, address p1, bool p2) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,address,bool)\\\", p0, p1, p2));\\n\\t}\\n\\n\\tfunction log(address p0, address p1, address p2) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,address,address)\\\", p0, p1, p2));\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, uint p2, uint p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,uint,uint,uint)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, uint p2, string memory p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,uint,uint,string)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, uint p2, bool p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,uint,uint,bool)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, uint p2, address p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,uint,uint,address)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, string memory p2, uint p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,uint,string,uint)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, string memory p2, string memory p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,uint,string,string)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, string memory p2, bool p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,uint,string,bool)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, string memory p2, address p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,uint,string,address)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, bool p2, uint p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,uint,bool,uint)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, bool p2, string memory p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,uint,bool,string)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, bool p2, bool p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,uint,bool,bool)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, bool p2, address p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,uint,bool,address)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, address p2, uint p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,uint,address,uint)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, address p2, string memory p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,uint,address,string)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, address p2, bool p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,uint,address,bool)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, address p2, address p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,uint,address,address)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, uint p2, uint p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,string,uint,uint)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, uint p2, string memory p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,string,uint,string)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, uint p2, bool p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,string,uint,bool)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, uint p2, address p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,string,uint,address)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, string memory p2, uint p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,string,string,uint)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, string memory p2, string memory p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,string,string,string)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, string memory p2, bool p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,string,string,bool)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, string memory p2, address p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,string,string,address)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, bool p2, uint p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,string,bool,uint)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, bool p2, string memory p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,string,bool,string)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, bool p2, bool p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,string,bool,bool)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, bool p2, address p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,string,bool,address)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, address p2, uint p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,string,address,uint)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, address p2, string memory p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,string,address,string)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, address p2, bool p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,string,address,bool)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, address p2, address p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,string,address,address)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, uint p2, uint p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,bool,uint,uint)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, uint p2, string memory p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,bool,uint,string)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, uint p2, bool p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,bool,uint,bool)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, uint p2, address p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,bool,uint,address)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, string memory p2, uint p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,bool,string,uint)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, string memory p2, string memory p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,bool,string,string)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, string memory p2, bool p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,bool,string,bool)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, string memory p2, address p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,bool,string,address)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, bool p2, uint p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,bool,bool,uint)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, bool p2, string memory p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,bool,bool,string)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, bool p2, bool p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,bool,bool,bool)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, bool p2, address p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,bool,bool,address)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, address p2, uint p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,bool,address,uint)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, address p2, string memory p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,bool,address,string)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, address p2, bool p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,bool,address,bool)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, address p2, address p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,bool,address,address)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, uint p2, uint p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,address,uint,uint)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, uint p2, string memory p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,address,uint,string)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, uint p2, bool p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,address,uint,bool)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, uint p2, address p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,address,uint,address)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, string memory p2, uint p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,address,string,uint)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, string memory p2, string memory p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,address,string,string)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, string memory p2, bool p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,address,string,bool)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, string memory p2, address p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,address,string,address)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, bool p2, uint p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,address,bool,uint)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, bool p2, string memory p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,address,bool,string)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, bool p2, bool p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,address,bool,bool)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, bool p2, address p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,address,bool,address)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, address p2, uint p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,address,address,uint)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, address p2, string memory p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,address,address,string)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, address p2, bool p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,address,address,bool)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, address p2, address p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(uint,address,address,address)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, uint p2, uint p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,uint,uint,uint)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, uint p2, string memory p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,uint,uint,string)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, uint p2, bool p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,uint,uint,bool)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, uint p2, address p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,uint,uint,address)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, string memory p2, uint p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,uint,string,uint)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, string memory p2, string memory p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,uint,string,string)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, string memory p2, bool p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,uint,string,bool)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, string memory p2, address p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,uint,string,address)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, bool p2, uint p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,uint,bool,uint)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, bool p2, string memory p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,uint,bool,string)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, bool p2, bool p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,uint,bool,bool)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, bool p2, address p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,uint,bool,address)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, address p2, uint p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,uint,address,uint)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, address p2, string memory p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,uint,address,string)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, address p2, bool p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,uint,address,bool)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, address p2, address p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,uint,address,address)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, uint p2, uint p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,string,uint,uint)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, uint p2, string memory p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,string,uint,string)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, uint p2, bool p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,string,uint,bool)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, uint p2, address p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,string,uint,address)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, string memory p2, uint p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,string,string,uint)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, string memory p2, string memory p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,string,string,string)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, string memory p2, bool p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,string,string,bool)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, string memory p2, address p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,string,string,address)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, bool p2, uint p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,string,bool,uint)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, bool p2, string memory p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,string,bool,string)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, bool p2, bool p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,string,bool,bool)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, bool p2, address p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,string,bool,address)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, address p2, uint p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,string,address,uint)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, address p2, string memory p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,string,address,string)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, address p2, bool p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,string,address,bool)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, address p2, address p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,string,address,address)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, uint p2, uint p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,bool,uint,uint)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, uint p2, string memory p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,bool,uint,string)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, uint p2, bool p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,bool,uint,bool)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, uint p2, address p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,bool,uint,address)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, string memory p2, uint p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,bool,string,uint)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, string memory p2, string memory p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,bool,string,string)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, string memory p2, bool p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,bool,string,bool)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, string memory p2, address p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,bool,string,address)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, bool p2, uint p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,bool,bool,uint)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, bool p2, string memory p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,bool,bool,string)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, bool p2, bool p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,bool,bool,bool)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, bool p2, address p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,bool,bool,address)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, address p2, uint p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,bool,address,uint)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, address p2, string memory p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,bool,address,string)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, address p2, bool p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,bool,address,bool)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, address p2, address p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,bool,address,address)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, uint p2, uint p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,address,uint,uint)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, uint p2, string memory p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,address,uint,string)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, uint p2, bool p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,address,uint,bool)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, uint p2, address p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,address,uint,address)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, string memory p2, uint p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,address,string,uint)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, string memory p2, string memory p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,address,string,string)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, string memory p2, bool p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,address,string,bool)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, string memory p2, address p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,address,string,address)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, bool p2, uint p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,address,bool,uint)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, bool p2, string memory p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,address,bool,string)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, bool p2, bool p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,address,bool,bool)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, bool p2, address p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,address,bool,address)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, address p2, uint p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,address,address,uint)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, address p2, string memory p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,address,address,string)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, address p2, bool p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,address,address,bool)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, address p2, address p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(string,address,address,address)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, uint p2, uint p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,uint,uint,uint)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, uint p2, string memory p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,uint,uint,string)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, uint p2, bool p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,uint,uint,bool)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, uint p2, address p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,uint,uint,address)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, string memory p2, uint p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,uint,string,uint)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, string memory p2, string memory p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,uint,string,string)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, string memory p2, bool p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,uint,string,bool)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, string memory p2, address p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,uint,string,address)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, bool p2, uint p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,uint,bool,uint)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, bool p2, string memory p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,uint,bool,string)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, bool p2, bool p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,uint,bool,bool)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, bool p2, address p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,uint,bool,address)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, address p2, uint p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,uint,address,uint)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, address p2, string memory p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,uint,address,string)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, address p2, bool p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,uint,address,bool)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, address p2, address p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,uint,address,address)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, uint p2, uint p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,string,uint,uint)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, uint p2, string memory p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,string,uint,string)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, uint p2, bool p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,string,uint,bool)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, uint p2, address p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,string,uint,address)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, string memory p2, uint p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,string,string,uint)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, string memory p2, string memory p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,string,string,string)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, string memory p2, bool p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,string,string,bool)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, string memory p2, address p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,string,string,address)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, bool p2, uint p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,string,bool,uint)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, bool p2, string memory p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,string,bool,string)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, bool p2, bool p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,string,bool,bool)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, bool p2, address p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,string,bool,address)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, address p2, uint p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,string,address,uint)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, address p2, string memory p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,string,address,string)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, address p2, bool p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,string,address,bool)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, address p2, address p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,string,address,address)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, uint p2, uint p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,bool,uint,uint)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, uint p2, string memory p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,bool,uint,string)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, uint p2, bool p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,bool,uint,bool)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, uint p2, address p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,bool,uint,address)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, string memory p2, uint p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,bool,string,uint)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, string memory p2, string memory p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,bool,string,string)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, string memory p2, bool p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,bool,string,bool)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, string memory p2, address p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,bool,string,address)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, bool p2, uint p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,bool,bool,uint)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, bool p2, string memory p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,bool,bool,string)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, bool p2, bool p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,bool,bool,bool)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, bool p2, address p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,bool,bool,address)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, address p2, uint p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,bool,address,uint)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, address p2, string memory p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,bool,address,string)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, address p2, bool p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,bool,address,bool)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, address p2, address p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,bool,address,address)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, uint p2, uint p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,address,uint,uint)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, uint p2, string memory p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,address,uint,string)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, uint p2, bool p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,address,uint,bool)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, uint p2, address p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,address,uint,address)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, string memory p2, uint p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,address,string,uint)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, string memory p2, string memory p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,address,string,string)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, string memory p2, bool p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,address,string,bool)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, string memory p2, address p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,address,string,address)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, bool p2, uint p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,address,bool,uint)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, bool p2, string memory p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,address,bool,string)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, bool p2, bool p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,address,bool,bool)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, bool p2, address p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,address,bool,address)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, address p2, uint p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,address,address,uint)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, address p2, string memory p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,address,address,string)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, address p2, bool p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,address,address,bool)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, address p2, address p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(bool,address,address,address)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, uint p2, uint p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,uint,uint,uint)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, uint p2, string memory p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,uint,uint,string)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, uint p2, bool p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,uint,uint,bool)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, uint p2, address p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,uint,uint,address)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, string memory p2, uint p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,uint,string,uint)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, string memory p2, string memory p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,uint,string,string)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, string memory p2, bool p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,uint,string,bool)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, string memory p2, address p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,uint,string,address)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, bool p2, uint p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,uint,bool,uint)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, bool p2, string memory p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,uint,bool,string)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, bool p2, bool p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,uint,bool,bool)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, bool p2, address p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,uint,bool,address)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, address p2, uint p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,uint,address,uint)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, address p2, string memory p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,uint,address,string)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, address p2, bool p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,uint,address,bool)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, address p2, address p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,uint,address,address)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, uint p2, uint p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,string,uint,uint)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, uint p2, string memory p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,string,uint,string)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, uint p2, bool p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,string,uint,bool)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, uint p2, address p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,string,uint,address)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, string memory p2, uint p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,string,string,uint)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, string memory p2, string memory p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,string,string,string)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, string memory p2, bool p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,string,string,bool)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, string memory p2, address p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,string,string,address)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, bool p2, uint p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,string,bool,uint)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, bool p2, string memory p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,string,bool,string)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, bool p2, bool p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,string,bool,bool)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, bool p2, address p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,string,bool,address)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, address p2, uint p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,string,address,uint)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, address p2, string memory p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,string,address,string)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, address p2, bool p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,string,address,bool)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, address p2, address p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,string,address,address)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, uint p2, uint p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,bool,uint,uint)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, uint p2, string memory p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,bool,uint,string)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, uint p2, bool p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,bool,uint,bool)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, uint p2, address p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,bool,uint,address)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, string memory p2, uint p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,bool,string,uint)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, string memory p2, string memory p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,bool,string,string)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, string memory p2, bool p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,bool,string,bool)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, string memory p2, address p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,bool,string,address)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, bool p2, uint p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,bool,bool,uint)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, bool p2, string memory p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,bool,bool,string)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, bool p2, bool p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,bool,bool,bool)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, bool p2, address p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,bool,bool,address)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, address p2, uint p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,bool,address,uint)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, address p2, string memory p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,bool,address,string)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, address p2, bool p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,bool,address,bool)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, address p2, address p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,bool,address,address)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(address p0, address p1, uint p2, uint p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,address,uint,uint)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(address p0, address p1, uint p2, string memory p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,address,uint,string)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(address p0, address p1, uint p2, bool p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,address,uint,bool)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(address p0, address p1, uint p2, address p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,address,uint,address)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(address p0, address p1, string memory p2, uint p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,address,string,uint)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(address p0, address p1, string memory p2, string memory p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,address,string,string)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(address p0, address p1, string memory p2, bool p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,address,string,bool)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(address p0, address p1, string memory p2, address p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,address,string,address)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(address p0, address p1, bool p2, uint p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,address,bool,uint)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(address p0, address p1, bool p2, string memory p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,address,bool,string)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(address p0, address p1, bool p2, bool p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,address,bool,bool)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(address p0, address p1, bool p2, address p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,address,bool,address)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(address p0, address p1, address p2, uint p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,address,address,uint)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(address p0, address p1, address p2, string memory p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,address,address,string)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(address p0, address p1, address p2, bool p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,address,address,bool)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n\\tfunction log(address p0, address p1, address p2, address p3) internal view {\\n\\t\\t_sendLogPayload(abi.encodeWithSignature(\\\"log(address,address,address,address)\\\", p0, p1, p2, p3));\\n\\t}\\n\\n}\\n\"},\"contracts/governance/governor/IGovernor.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.9;\\n\\nimport \\\"./Structs.sol\\\";\\n\\n/// @title interface to interact with TokenDelgator\\ninterface IGovernorCharlieDelegator {\\n  function _setImplementation(address implementation_) external;\\n\\n  fallback() external payable;\\n\\n  receive() external payable;\\n}\\n\\n/// @title interface to interact with TokenDelgate\\ninterface IGovernorCharlieDelegate {\\n  function initialize(\\n    address ipt_\\n  ) external;\\n\\n  function propose(\\n    address[] memory targets,\\n    uint256[] memory values,\\n    string[] memory signatures,\\n    bytes[] memory calldatas,\\n    string memory description,\\n    bool emergency\\n  ) external returns (uint256);\\n\\n  function queue(uint256 proposalId) external;\\n\\n  function execute(uint256 proposalId) external payable;\\n\\n  function executeTransaction(\\n    address target,\\n    uint256 value,\\n    string memory signature,\\n    bytes memory data,\\n    uint256 eta\\n  ) external payable;\\n\\n  function cancel(uint256 proposalId) external;\\n\\n  function getActions(uint256 proposalId)\\n    external\\n    view\\n    returns (\\n      address[] memory targets,\\n      uint256[] memory values,\\n      string[] memory signatures,\\n      bytes[] memory calldatas\\n    );\\n\\n  function getReceipt(uint256 proposalId, address voter) external view returns (Receipt memory);\\n\\n  function state(uint256 proposalId) external view returns (ProposalState);\\n\\n  function castVote(uint256 proposalId, uint8 support) external;\\n\\n  function castVoteWithReason(\\n    uint256 proposalId,\\n    uint8 support,\\n    string calldata reason\\n  ) external;\\n\\n  function castVoteBySig(\\n    uint256 proposalId,\\n    uint8 support,\\n    uint8 v,\\n    bytes32 r,\\n    bytes32 s\\n  ) external;\\n\\n  function isWhitelisted(address account) external view returns (bool);\\n\\n  function _setDelay(uint256 proposalTimelockDelay_) external;\\n\\n  function _setEmergencyDelay(uint256 emergencyTimelockDelay_) external;\\n\\n  function _setVotingDelay(uint256 newVotingDelay) external;\\n\\n  function _setVotingPeriod(uint256 newVotingPeriod) external;\\n\\n  function _setEmergencyVotingPeriod(uint256 newEmergencyVotingPeriod) external;\\n\\n  function _setProposalThreshold(uint256 newProposalThreshold) external;\\n\\n  function _setQuorumVotes(uint256 newQuorumVotes) external;\\n\\n  function _setEmergencyQuorumVotes(uint256 newEmergencyQuorumVotes) external;\\n\\n  function _setWhitelistAccountExpiration(address account, uint256 expiration) external;\\n\\n  function _setWhitelistGuardian(address account) external;\\n\\n  function _setOptimisticDelay(uint256 newOptimisticVotingDelay) external;\\n\\n  function _setOptimisticQuorumVotes(uint256 newOptimisticQuorumVotes) external;\\n}\\n\\n/// @title interface which contains all events emitted by delegator & delegate\\ninterface GovernorCharlieEvents {\\n  /// @notice An event emitted when a new proposal is created\\n  event ProposalCreated(\\n    uint256 indexed id,\\n    address indexed proposer,\\n    address[] targets,\\n    uint256[] values,\\n    string[] signatures,\\n    bytes[] calldatas,\\n    uint256 indexed startBlock,\\n    uint256 endBlock,\\n    string description\\n  );\\n\\n  /// @notice An event emitted when a vote has been cast on a proposal\\n  /// @param voter The address which casted a vote\\n  /// @param proposalId The proposal id which was voted on\\n  /// @param support Support value for the vote. 0=against, 1=for, 2=abstain\\n  /// @param votes Number of votes which were cast by the voter\\n  /// @param reason The reason given for the vote by the voter\\n  event VoteCast(address indexed voter, uint256 indexed proposalId, uint8 support, uint256 votes, string reason);\\n\\n  /// @notice An event emitted when a proposal has been canceled\\n  event ProposalCanceled(uint256 indexed id);\\n\\n  /// @notice An event emitted when a proposal has been queued in the Timelock\\n  event ProposalQueued(uint256 indexed id, uint256 eta);\\n\\n  /// @notice An event emitted when a proposal has been executed in the Timelock\\n  event ProposalExecuted(uint256 indexed id);\\n\\n  /// @notice An event emitted when the voting delay is set\\n  event VotingDelaySet(uint256 oldVotingDelay, uint256 newVotingDelay);\\n\\n  /// @notice An event emitted when the voting period is set\\n  event VotingPeriodSet(uint256 oldVotingPeriod, uint256 newVotingPeriod);\\n\\n  /// @notice An event emitted when the emergency voting period is set\\n  event EmergencyVotingPeriodSet(uint256 oldEmergencyVotingPeriod, uint256 emergencyVotingPeriod);\\n\\n  /// @notice Emitted when implementation is changed\\n  event NewImplementation(address oldImplementation, address newImplementation);\\n\\n  /// @notice Emitted when proposal threshold is set\\n  event ProposalThresholdSet(uint256 oldProposalThreshold, uint256 newProposalThreshold);\\n\\n  /// @notice Emitted when pendingAdmin is changed\\n  event NewPendingAdmin(address oldPendingAdmin, address newPendingAdmin);\\n\\n  /// @notice Emitted when pendingAdmin is accepted, which means admin is updated\\n  event NewAdmin(address oldAdmin, address newAdmin);\\n\\n  /// @notice Emitted when whitelist account expiration is set\\n  event WhitelistAccountExpirationSet(address account, uint256 expiration);\\n\\n  /// @notice Emitted when the whitelistGuardian is set\\n  event WhitelistGuardianSet(address oldGuardian, address newGuardian);\\n\\n  /// @notice Emitted when the a new delay is set\\n  event NewDelay(uint256 oldTimelockDelay, uint256 proposalTimelockDelay);\\n\\n  /// @notice Emitted when the a new emergency delay is set\\n  event NewEmergencyDelay(uint256 oldEmergencyTimelockDelay, uint256 emergencyTimelockDelay);\\n\\n  /// @notice Emitted when the quorum is updated\\n  event NewQuorum(uint256 oldQuorumVotes, uint256 quorumVotes);\\n\\n  /// @notice Emitted when the emergency quorum is updated\\n  event NewEmergencyQuorum(uint256 oldEmergencyQuorumVotes, uint256 emergencyQuorumVotes);\\n\\n  /// @notice An event emitted when the optimistic voting delay is set\\n  event OptimisticVotingDelaySet(uint256 oldOptimisticVotingDelay, uint256 optimisticVotingDelay);\\n\\n  /// @notice Emitted when the optimistic quorum is updated\\n  event OptimisticQuorumVotesSet(uint256 oldOptimisticQuorumVotes, uint256 optimisticQuorumVotes);\\n\\n  /// @notice Emitted when a transaction is canceled\\n  event CancelTransaction(\\n    bytes32 indexed txHash,\\n    address indexed target,\\n    uint256 value,\\n    string signature,\\n    bytes data,\\n    uint256 eta\\n  );\\n\\n  /// @notice Emitted when a transaction is executed\\n  event ExecuteTransaction(\\n    bytes32 indexed txHash,\\n    address indexed target,\\n    uint256 value,\\n    string signature,\\n    bytes data,\\n    uint256 eta\\n  );\\n\\n  /// @notice Emitted when a transaction is queued\\n  event QueueTransaction(\\n    bytes32 indexed txHash,\\n    address indexed target,\\n    uint256 value,\\n    string signature,\\n    bytes data,\\n    uint256 eta\\n  );\\n}\\n\"},\"contracts/governance/governor/Structs.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.9;\\n\\nstruct Proposal {\\n  /// @notice Unique id for looking up a proposal\\n  uint256 id;\\n  /// @notice Creator of the proposal\\n  address proposer;\\n  /// @notice The timestamp that the proposal will be available for execution, set once the vote succeeds\\n  uint256 eta;\\n  /// @notice the ordered list of target addresses for calls to be made\\n  address[] targets;\\n  /// @notice The ordered list of values (i.e. msg.value) to be passed to the calls to be made\\n  uint256[] values;\\n  /// @notice The ordered list of function signatures to be called\\n  string[] signatures;\\n  /// @notice The ordered list of calldata to be passed to each call\\n  bytes[] calldatas;\\n  /// @notice The block at which voting begins: holders must delegate their votes prior to this block\\n  uint256 startBlock;\\n  /// @notice The block at which voting ends: votes must be cast prior to this block\\n  uint256 endBlock;\\n  /// @notice Current number of votes in favor of this proposal\\n  uint256 forVotes;\\n  /// @notice Current number of votes in opposition to this proposal\\n  uint256 againstVotes;\\n  /// @notice Current number of votes for abstaining for this proposal\\n  uint256 abstainVotes;\\n  /// @notice Flag marking whether the proposal has been canceled\\n  bool canceled;\\n  /// @notice Flag marking whether the proposal has been executed\\n  bool executed;\\n  /// @notice Whether the proposal is an emergency proposal\\n  bool emergency;\\n  /// @notice quorum votes requires\\n  uint256 quorumVotes;\\n  /// @notice time delay\\n  uint256 delay;\\n}\\n\\n/// @notice Ballot receipt record for a voter\\nstruct Receipt {\\n  /// @notice Whether or not a vote has been cast\\n  bool hasVoted;\\n  /// @notice Whether or not the voter supports the proposal or abstains\\n  uint8 support;\\n  /// @notice The number of votes the voter had, which were cast\\n  uint96 votes;\\n}\\n\\n/// @notice Possible states that a proposal may be in\\nenum ProposalState {\\n  Pending,\\n  Active,\\n  Canceled,\\n  Defeated,\\n  Succeeded,\\n  Queued,\\n  Expired,\\n  Executed\\n}\\n\"},\"contracts/governance/governor/IIpt.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.9;\\n\\ninterface IIpt {\\n  function getPriorVotes(address account, uint256 blockNumber) external view returns (uint96);\\n}\\n\"},\"contracts/governance/governor/GovernorDelegate.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.9;\\npragma experimental ABIEncoderV2;\\nimport \\\"hardhat/console.sol\\\";\\n\\nimport \\\"./IGovernor.sol\\\";\\nimport \\\"./GovernorStorage.sol\\\";\\n\\ncontract GovernorCharlieDelegate is GovernorCharlieDelegateStorage, GovernorCharlieEvents, IGovernorCharlieDelegate {\\n  /// @notice The name of this contract\\n  string public constant name = \\\"Interest Protocol Governor\\\";\\n\\n  /// @notice The maximum number of actions that can be included in a proposal\\n  uint256 public constant proposalMaxOperations = 10;\\n\\n  /// @notice The EIP-712 typehash for the contract's domain\\n  bytes32 public constant DOMAIN_TYPEHASH =\\n    keccak256(\\\"EIP712Domain(string name,uint256 chainId,address verifyingContract)\\\");\\n\\n  /// @notice The EIP-712 typehash for the ballot struct used by the contract\\n  bytes32 public constant BALLOT_TYPEHASH = keccak256(\\\"Ballot(uint256 proposalId,uint8 support)\\\");\\n\\n  /// @notice The time for a proposal to be executed after passing\\n  uint256 public constant GRACE_PERIOD = 14 days;\\n\\n  /**\\n   * @notice Used to initialize the contract during delegator contructor\\n   * @param ipt_ The address of the IPT token\\n   */\\n  function initialize(\\n    address ipt_\\n  ) external override {\\n    require(!initialized, \\\"already been initialized\\\");\\n    ipt = IIpt(ipt_);\\n    votingPeriod = 40320;\\n    votingDelay = 13140;\\n    proposalThreshold = 1000000000000000000000000;\\n    proposalTimelockDelay = 172800;\\n    proposalCount = 0;\\n    quorumVotes = 10000000000000000000000000;\\n    emergencyQuorumVotes = 40000000000000000000000000;\\n    emergencyVotingPeriod = 6570;\\n    emergencyTimelockDelay = 43200;\\n    optimisticQuorumVotes = 2000000000000000000000000;\\n    optimisticVotingDelay = 18000;\\n    maxWhitelistPeriod = 31536000;\\n\\n    initialized = true;\\n  }\\n\\n  /// @notice any function with this modifier will call the pay_interest() function before\\n  modifier onlyGov() {\\n    require(_msgSender() == address(this), \\\"must come from the gov.\\\");\\n    _;\\n  }\\n\\n  /**\\n   * @notice Function used to propose a new proposal. Sender must have delegates above the proposal threshold\\n   * @param targets Target addresses for proposal calls\\n   * @param values Eth values for proposal calls\\n   * @param signatures Function signatures for proposal calls\\n   * @param calldatas Calldatas for proposal calls\\n   * @param description String description of the proposal\\n   * @return Proposal id of new proposal\\n   */\\n  function propose(\\n    address[] memory targets,\\n    uint256[] memory values,\\n    string[] memory signatures,\\n    bytes[] memory calldatas,\\n    string memory description,\\n    bool emergency\\n  ) public override returns (uint256) {\\n    // Reject proposals before initiating as Governor\\n    require(quorumVotes != 0, \\\"Charlie not active\\\");\\n    // Allow addresses above proposal threshold and whitelisted addresses to propose\\n    require(\\n      ipt.getPriorVotes(_msgSender(), (block.number - 1)) >= proposalThreshold || isWhitelisted(_msgSender()),\\n      \\\"votes below proposal threshold\\\"\\n    );\\n    require(\\n      targets.length == values.length && targets.length == signatures.length && targets.length == calldatas.length,\\n      \\\"information arity mismatch\\\"\\n    );\\n    require(targets.length != 0, \\\"must provide actions\\\");\\n    require(targets.length <= proposalMaxOperations, \\\"too many actions\\\");\\n\\n    uint256 latestProposalId = latestProposalIds[_msgSender()];\\n    if (latestProposalId != 0) {\\n      ProposalState proposersLatestProposalState = state(latestProposalId);\\n      require(proposersLatestProposalState != ProposalState.Active, \\\"one live proposal per proposer\\\");\\n      require(proposersLatestProposalState != ProposalState.Pending, \\\"one live proposal per proposer\\\");\\n    }\\n\\n    proposalCount++;\\n    Proposal memory newProposal = Proposal({\\n      id: proposalCount,\\n      proposer: _msgSender(),\\n      eta: 0,\\n      targets: targets,\\n      values: values,\\n      signatures: signatures,\\n      calldatas: calldatas,\\n      startBlock: block.number + votingDelay,\\n      endBlock: block.number + votingDelay + votingPeriod,\\n      forVotes: 0,\\n      againstVotes: 0,\\n      abstainVotes: 0,\\n      canceled: false,\\n      executed: false,\\n      emergency: emergency,\\n      quorumVotes: quorumVotes,\\n      delay: proposalTimelockDelay\\n    });\\n\\n    //whitelist can't make emergency\\n    if (emergency && !isWhitelisted(_msgSender())) {\\n      newProposal.startBlock = block.number;\\n      newProposal.endBlock = block.number + emergencyVotingPeriod;\\n      newProposal.quorumVotes = emergencyQuorumVotes;\\n      newProposal.delay = emergencyTimelockDelay;\\n    }\\n\\n    //whitelist can only make optimistic proposals\\n    if (isWhitelisted(_msgSender())) {\\n      newProposal.quorumVotes = optimisticQuorumVotes;\\n      newProposal.startBlock = block.number + optimisticVotingDelay;\\n      newProposal.endBlock = block.number + optimisticVotingDelay + votingPeriod;\\n    }\\n\\n    proposals[newProposal.id] = newProposal;\\n    latestProposalIds[newProposal.proposer] = newProposal.id;\\n\\n    emit ProposalCreated(\\n      newProposal.id,\\n      _msgSender(),\\n      targets,\\n      values,\\n      signatures,\\n      calldatas,\\n      newProposal.startBlock,\\n      newProposal.endBlock,\\n      description\\n    );\\n    return newProposal.id;\\n  }\\n\\n  /**\\n   * @notice Queues a proposal of state succeeded\\n   * @param proposalId The id of the proposal to queue\\n   */\\n  function queue(uint256 proposalId) external override {\\n    require(state(proposalId) == ProposalState.Succeeded, \\\"can only be queued if succeeded\\\");\\n    Proposal storage proposal = proposals[proposalId];\\n    uint256 eta = block.timestamp + proposal.delay;\\n    for (uint256 i = 0; i < proposal.targets.length; i++) {\\n      require(\\n        !queuedTransactions[\\n          keccak256(\\n            abi.encode(proposal.targets[i], proposal.values[i], proposal.signatures[i], proposal.calldatas[i], eta)\\n          )\\n        ],\\n        \\\"proposal already queued\\\"\\n      );\\n      queueTransaction(\\n        proposal.targets[i],\\n        proposal.values[i],\\n        proposal.signatures[i],\\n        proposal.calldatas[i],\\n        eta,\\n        proposal.delay\\n      );\\n    }\\n    proposal.eta = eta;\\n    emit ProposalQueued(proposalId, eta);\\n  }\\n\\n  function queueTransaction(\\n    address target,\\n    uint256 value,\\n    string memory signature,\\n    bytes memory data,\\n    uint256 eta,\\n    uint256 delay\\n  ) internal returns (bytes32) {\\n    require(eta >= (getBlockTimestamp() + delay), \\\"must satisfy delay.\\\");\\n\\n    bytes32 txHash = keccak256(abi.encode(target, value, signature, data, eta));\\n    queuedTransactions[txHash] = true;\\n\\n    emit QueueTransaction(txHash, target, value, signature, data, eta);\\n    return txHash;\\n  }\\n\\n  /**\\n   * @notice Executes a queued proposal if eta has passed\\n   * @param proposalId The id of the proposal to execute\\n   */\\n  function execute(uint256 proposalId) external payable override {\\n    require(state(proposalId) == ProposalState.Queued, \\\"can only be exec'd if queued\\\");\\n    Proposal storage proposal = proposals[proposalId];\\n    proposal.executed = true;\\n    for (uint256 i = 0; i < proposal.targets.length; i++) {\\n      this.executeTransaction{value: proposal.values[i]}(\\n        proposal.targets[i],\\n        proposal.values[i],\\n        proposal.signatures[i],\\n        proposal.calldatas[i],\\n        proposal.eta\\n      );\\n    }\\n    emit ProposalExecuted(proposalId);\\n  }\\n\\n  function executeTransaction(\\n    address target,\\n    uint256 value,\\n    string memory signature,\\n    bytes memory data,\\n    uint256 eta\\n  ) external payable override {\\n    bytes32 txHash = keccak256(abi.encode(target, value, signature, data, eta));\\n    require(queuedTransactions[txHash], \\\"tx hasn't been queued.\\\");\\n    require(getBlockTimestamp() >= eta, \\\"tx hasn't surpassed timelock.\\\");\\n    require(getBlockTimestamp() <= eta + GRACE_PERIOD, \\\"tx is stale.\\\");\\n\\n    queuedTransactions[txHash] = false;\\n\\n    bytes memory callData;\\n\\n    if (bytes(signature).length == 0) {\\n      callData = data;\\n    } else {\\n      callData = abi.encodePacked(bytes4(keccak256(bytes(signature))), data);\\n    }\\n\\n    // solhint-disable-next-line avoid-low-level-calls\\n    (\\n      bool success, /*bytes memory returnData*/\\n\\n    ) = target.call{value: value}(callData);\\n    require(success, \\\"tx execution reverted.\\\");\\n\\n    emit ExecuteTransaction(txHash, target, value, signature, data, eta);\\n  }\\n\\n  /**\\n   * @notice Cancels a proposal only if sender is the proposer, or proposer delegates dropped below proposal threshold\\n   * @param proposalId The id of the proposal to cancel\\n   */\\n  function cancel(uint256 proposalId) external override {\\n    require(state(proposalId) != ProposalState.Executed, \\\"cant cancel executed proposal\\\");\\n\\n    Proposal storage proposal = proposals[proposalId];\\n\\n    // Proposer can cancel\\n    if (_msgSender() != proposal.proposer) {\\n      // Whitelisted proposers can't be canceled for falling below proposal threshold\\n      if (isWhitelisted(proposal.proposer)) {\\n        require(\\n          (ipt.getPriorVotes(proposal.proposer, (block.number - 1)) < proposalThreshold) &&\\n            _msgSender() == whitelistGuardian,\\n          \\\"cancel: whitelisted proposer\\\"\\n        );\\n      } else {\\n        require(\\n          (ipt.getPriorVotes(proposal.proposer, (block.number - 1)) < proposalThreshold),\\n          \\\"cancel: proposer above threshold\\\"\\n        );\\n      }\\n    }\\n\\n    proposal.canceled = true;\\n    for (uint256 i = 0; i < proposal.targets.length; i++) {\\n      cancelTransaction(\\n        proposal.targets[i],\\n        proposal.values[i],\\n        proposal.signatures[i],\\n        proposal.calldatas[i],\\n        proposal.eta\\n      );\\n    }\\n\\n    emit ProposalCanceled(proposalId);\\n  }\\n\\n  function cancelTransaction(\\n    address target,\\n    uint256 value,\\n    string memory signature,\\n    bytes memory data,\\n    uint256 eta\\n  ) internal {\\n    bytes32 txHash = keccak256(abi.encode(target, value, signature, data, eta));\\n    queuedTransactions[txHash] = false;\\n\\n    emit CancelTransaction(txHash, target, value, signature, data, eta);\\n  }\\n\\n  /**\\n   * @notice Gets actions of a proposal\\n   * @param proposalId the id of the proposal\\n   * @return targets proposal targets\\n   * @return values proposal values\\n   * @return signatures proposal signatures\\n   * @return calldatas proposal calldatae\\n   */\\n  function getActions(uint256 proposalId)\\n    external\\n    view\\n    override\\n    returns (\\n      address[] memory targets,\\n      uint256[] memory values,\\n      string[] memory signatures,\\n      bytes[] memory calldatas\\n    )\\n  {\\n    Proposal storage p = proposals[proposalId];\\n    return (p.targets, p.values, p.signatures, p.calldatas);\\n  }\\n\\n  /**\\n   * @notice Gets the receipt for a voter on a given proposal\\n   * @param proposalId the id of proposal\\n   * @param voter The address of the voter\\n   * @return The voting receipt\\n   */\\n  function getReceipt(uint256 proposalId, address voter) external view override returns (Receipt memory) {\\n    return proposalReceipts[proposalId][voter];\\n  }\\n\\n  /**\\n   * @notice Gets the state of a proposal\\n   * @param proposalId The id of the proposal\\n   * @return Proposal state\\n   */\\n  // solhint-disable-next-line code-complexity\\n  function state(uint256 proposalId) public view override returns (ProposalState) {\\n    require(proposalCount >= proposalId && proposalId > initialProposalId, \\\"state: invalid proposal id\\\");\\n    Proposal storage proposal = proposals[proposalId];\\n    bool whitelisted = isWhitelisted(proposal.proposer);\\n    if (proposal.canceled) {\\n      return ProposalState.Canceled;\\n    } else if (block.number <= proposal.startBlock) {\\n      return ProposalState.Pending;\\n    } else if (block.number <= proposal.endBlock) {\\n      return ProposalState.Active;\\n    } else if (\\n      (whitelisted && proposal.againstVotes > proposal.quorumVotes) ||\\n      (!whitelisted && proposal.forVotes <= proposal.againstVotes) ||\\n      (!whitelisted && proposal.forVotes < proposal.quorumVotes)\\n    ) {\\n      return ProposalState.Defeated;\\n    } else if (proposal.eta == 0) {\\n      return ProposalState.Succeeded;\\n    } else if (proposal.executed) {\\n      return ProposalState.Executed;\\n    } else if (block.timestamp >= (proposal.eta + GRACE_PERIOD)) {\\n      return ProposalState.Expired;\\n    }\\n    return ProposalState.Queued;\\n  }\\n\\n  /**\\n   * @notice Cast a vote for a proposal\\n   * @param proposalId The id of the proposal to vote on\\n   * @param support The support value for the vote. 0=against, 1=for, 2=abstain\\n   */\\n  function castVote(uint256 proposalId, uint8 support) external override {\\n    emit VoteCast(_msgSender(), proposalId, support, castVoteInternal(_msgSender(), proposalId, support), \\\"\\\");\\n  }\\n\\n  /**\\n   * @notice Cast a vote for a proposal with a reason\\n   * @param proposalId The id of the proposal to vote on\\n   * @param support The support value for the vote. 0=against, 1=for, 2=abstain\\n   * @param reason The reason given for the vote by the voter\\n   */\\n  function castVoteWithReason(\\n    uint256 proposalId,\\n    uint8 support,\\n    string calldata reason\\n  ) external override {\\n    emit VoteCast(_msgSender(), proposalId, support, castVoteInternal(_msgSender(), proposalId, support), reason);\\n  }\\n\\n  /**\\n   * @notice Cast a vote for a proposal by signature\\n   * @dev external override function that accepts EIP-712 signatures for voting on proposals.\\n   */\\n  function castVoteBySig(\\n    uint256 proposalId,\\n    uint8 support,\\n    uint8 v,\\n    bytes32 r,\\n    bytes32 s\\n  ) external override {\\n    bytes32 domainSeparator = keccak256(\\n      abi.encode(DOMAIN_TYPEHASH, keccak256(bytes(name)), getChainIdInternal(), address(this))\\n    );\\n    bytes32 structHash = keccak256(abi.encode(BALLOT_TYPEHASH, proposalId, support));\\n    bytes32 digest = keccak256(abi.encodePacked(\\\"\\\\x19\\\\x01\\\", domainSeparator, structHash));\\n    address signatory = ecrecover(digest, v, r, s);\\n    require(signatory != address(0), \\\"castVoteBySig: invalid signature\\\");\\n    emit VoteCast(signatory, proposalId, support, castVoteInternal(signatory, proposalId, support), \\\"\\\");\\n  }\\n\\n  /**\\n   * @notice Internal function that caries out voting logic\\n   * @param voter The voter that is casting their vote\\n   * @param proposalId The id of the proposal to vote on\\n   * @param support The support value for the vote. 0=against, 1=for, 2=abstain\\n   * @return The number of votes cast\\n   */\\n  function castVoteInternal(\\n    address voter,\\n    uint256 proposalId,\\n    uint8 support\\n  ) internal returns (uint96) {\\n    require(state(proposalId) == ProposalState.Active, \\\"voting is closed\\\");\\n    require(support <= 2, \\\"invalid vote type\\\");\\n    Proposal storage proposal = proposals[proposalId];\\n    Receipt storage receipt = proposalReceipts[proposalId][voter];\\n    require(receipt.hasVoted == false, \\\"voter already voted\\\");\\n    uint96 votes = ipt.getPriorVotes(voter, proposal.startBlock);\\n\\n    if (support == 0) {\\n      proposal.againstVotes = proposal.againstVotes + votes;\\n    } else if (support == 1) {\\n      proposal.forVotes = proposal.forVotes + votes;\\n    } else if (support == 2) {\\n      proposal.abstainVotes = proposal.abstainVotes + votes;\\n    }\\n\\n    receipt.hasVoted = true;\\n    receipt.support = support;\\n    receipt.votes = votes;\\n\\n    return votes;\\n  }\\n\\n  /**\\n   * @notice View function which returns if an account is whitelisted\\n   * @param account Account to check white list status of\\n   * @return If the account is whitelisted\\n   */\\n  function isWhitelisted(address account) public view override returns (bool) {\\n    return (whitelistAccountExpirations[account] > block.timestamp);\\n  }\\n\\n  /**\\n   * @notice Governance function for setting the governance token\\n   * @param  token_ new token addr\\n   */\\n  function _setNewToken(address token_) external onlyGov {\\n    ipt = IIpt(token_);\\n  }\\n\\n  /**\\n   * @notice Used to update the timelock period\\n   * @param proposalTimelockDelay_ The proposal holding period\\n   */\\n  function _setDelay(uint256 proposalTimelockDelay_) public override onlyGov {\\n    uint256 oldTimelockDelay = proposalTimelockDelay;\\n    proposalTimelockDelay = proposalTimelockDelay_;\\n\\n    emit NewDelay(oldTimelockDelay, proposalTimelockDelay);\\n  }\\n\\n  /**\\n   * @notice Used to update the emergency timelock period\\n   * @param emergencyTimelockDelay_ The proposal holding period\\n   */\\n  function _setEmergencyDelay(uint256 emergencyTimelockDelay_) public override onlyGov {\\n    uint256 oldEmergencyTimelockDelay = emergencyTimelockDelay;\\n    emergencyTimelockDelay = emergencyTimelockDelay_;\\n\\n    emit NewEmergencyDelay(oldEmergencyTimelockDelay, emergencyTimelockDelay);\\n  }\\n\\n  /**\\n   * @notice Governance function for setting the voting delay\\n   * @param newVotingDelay new voting delay, in blocks\\n   */\\n  function _setVotingDelay(uint256 newVotingDelay) external override onlyGov {\\n    uint256 oldVotingDelay = votingDelay;\\n    votingDelay = newVotingDelay;\\n\\n    emit VotingDelaySet(oldVotingDelay, votingDelay);\\n  }\\n\\n  /**\\n   * @notice Governance function for setting the voting period\\n   * @param newVotingPeriod new voting period, in blocks\\n   */\\n  function _setVotingPeriod(uint256 newVotingPeriod) external override onlyGov {\\n    uint256 oldVotingPeriod = votingPeriod;\\n    votingPeriod = newVotingPeriod;\\n\\n    emit VotingPeriodSet(oldVotingPeriod, votingPeriod);\\n  }\\n\\n  /**\\n   * @notice Governance function for setting the emergency voting period\\n   * @param newEmergencyVotingPeriod new voting period, in blocks\\n   */\\n  function _setEmergencyVotingPeriod(uint256 newEmergencyVotingPeriod) external override onlyGov {\\n    uint256 oldEmergencyVotingPeriod = emergencyVotingPeriod;\\n    emergencyVotingPeriod = newEmergencyVotingPeriod;\\n\\n    emit EmergencyVotingPeriodSet(oldEmergencyVotingPeriod, emergencyVotingPeriod);\\n  }\\n\\n  /**\\n   * @notice Governance function for setting the proposal threshold\\n   * @param newProposalThreshold new proposal threshold\\n   */\\n  function _setProposalThreshold(uint256 newProposalThreshold) external override onlyGov {\\n    uint256 oldProposalThreshold = proposalThreshold;\\n    proposalThreshold = newProposalThreshold;\\n\\n    emit ProposalThresholdSet(oldProposalThreshold, proposalThreshold);\\n  }\\n\\n  /**\\n   * @notice Governance function for setting the quorum\\n   * @param newQuorumVotes new proposal quorum\\n   */\\n  function _setQuorumVotes(uint256 newQuorumVotes) external override onlyGov {\\n    uint256 oldQuorumVotes = quorumVotes;\\n    quorumVotes = newQuorumVotes;\\n\\n    emit NewQuorum(oldQuorumVotes, quorumVotes);\\n  }\\n\\n  /**\\n   * @notice Governance function for setting the emergency quorum\\n   * @param newEmergencyQuorumVotes new proposal quorum\\n   */\\n  function _setEmergencyQuorumVotes(uint256 newEmergencyQuorumVotes) external override onlyGov {\\n    uint256 oldEmergencyQuorumVotes = emergencyQuorumVotes;\\n    emergencyQuorumVotes = newEmergencyQuorumVotes;\\n\\n    emit NewEmergencyQuorum(oldEmergencyQuorumVotes, emergencyQuorumVotes);\\n  }\\n\\n  /**\\n   * @notice Governance function for setting the whitelist expiration as a timestamp\\n   * for an account. Whitelist status allows accounts to propose without meeting threshold\\n   * @param account Account address to set whitelist expiration for\\n   * @param expiration Expiration for account whitelist status as timestamp (if now < expiration, whitelisted)\\n   */\\n  function _setWhitelistAccountExpiration(address account, uint256 expiration) external override onlyGov {\\n    require (expiration < (maxWhitelistPeriod + block.timestamp), \\\"expiration exceeds max\\\");\\n    whitelistAccountExpirations[account] = expiration;\\n\\n    emit WhitelistAccountExpirationSet(account, expiration);\\n  }\\n\\n  /**\\n   * @notice Governance function for setting the whitelistGuardian. WhitelistGuardian can cancel proposals from whitelisted addresses\\n   * @param account Account to set whitelistGuardian to (0x0 to remove whitelistGuardian)\\n   */\\n  function _setWhitelistGuardian(address account) external override onlyGov {\\n    address oldGuardian = whitelistGuardian;\\n    whitelistGuardian = account;\\n\\n    emit WhitelistGuardianSet(oldGuardian, whitelistGuardian);\\n  }\\n\\n  /**\\n   * @notice Governance function for setting the optimistic voting delay\\n   * @param newOptimisticVotingDelay new optimistic voting delay, in blocks\\n   */\\n  function _setOptimisticDelay(uint256 newOptimisticVotingDelay) external override onlyGov {\\n    uint256 oldOptimisticVotingDelay = optimisticVotingDelay;\\n    optimisticVotingDelay = newOptimisticVotingDelay;\\n\\n    emit OptimisticVotingDelaySet(oldOptimisticVotingDelay, optimisticVotingDelay);\\n  }\\n\\n  /**\\n   * @notice Governance function for setting the optimistic quorum\\n   * @param newOptimisticQuorumVotes new optimistic quorum votes, in blocks\\n   */\\n  function _setOptimisticQuorumVotes(uint256 newOptimisticQuorumVotes) external override onlyGov {\\n    uint256 oldOptimisticQuorumVotes = optimisticQuorumVotes;\\n    optimisticQuorumVotes = newOptimisticQuorumVotes;\\n\\n    emit OptimisticQuorumVotesSet(oldOptimisticQuorumVotes, optimisticQuorumVotes);\\n  }\\n\\n  function getChainIdInternal() internal view returns (uint256) {\\n    return block.chainid;\\n  }\\n\\n  function getBlockTimestamp() internal view returns (uint256) {\\n    // solium-disable-next-line security/no-block-members\\n    return block.timestamp;\\n  }\\n\\n  function _msgSender() internal view virtual returns (address) {\\n    return msg.sender;\\n  }\\n}\\n\"}},\"settings\":{\"optimizer\":{\"enabled\":true,\"runs\":200,\"details\":{\"orderLiterals\":true,\"deduplicate\":true,\"cse\":true,\"yul\":true}},\"outputSelection\":{\"*\":{\"*\":[\"evm.bytecode\",\"evm.deployedBytecode\",\"devdoc\",\"userdoc\",\"metadata\",\"abi\"]}},\"libraries\":{}}},\"ABI\":\"[{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":true,\\\"internalType\\\":\\\"bytes32\\\",\\\"name\\\":\\\"txHash\\\",\\\"type\\\":\\\"bytes32\\\"},{\\\"indexed\\\":true,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"target\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"value\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"string\\\",\\\"name\\\":\\\"signature\\\",\\\"type\\\":\\\"string\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"bytes\\\",\\\"name\\\":\\\"data\\\",\\\"type\\\":\\\"bytes\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"eta\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"CancelTransaction\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"oldEmergencyVotingPeriod\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"emergencyVotingPeriod\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"EmergencyVotingPeriodSet\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":true,\\\"internalType\\\":\\\"bytes32\\\",\\\"name\\\":\\\"txHash\\\",\\\"type\\\":\\\"bytes32\\\"},{\\\"indexed\\\":true,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"target\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"value\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"string\\\",\\\"name\\\":\\\"signature\\\",\\\"type\\\":\\\"string\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"bytes\\\",\\\"name\\\":\\\"data\\\",\\\"type\\\":\\\"bytes\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"eta\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"ExecuteTransaction\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":false,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"oldAdmin\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"newAdmin\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"NewAdmin\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"oldTimelockDelay\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"proposalTimelockDelay\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"NewDelay\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"oldEmergencyTimelockDelay\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"emergencyTimelockDelay\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"NewEmergencyDelay\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"oldEmergencyQuorumVotes\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"emergencyQuorumVotes\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"NewEmergencyQuorum\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":false,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"oldImplementation\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"newImplementation\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"NewImplementation\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":false,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"oldPendingAdmin\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"newPendingAdmin\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"NewPendingAdmin\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"oldQuorumVotes\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"quorumVotes\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"NewQuorum\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"oldOptimisticQuorumVotes\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"optimisticQuorumVotes\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"OptimisticQuorumVotesSet\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"oldOptimisticVotingDelay\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"optimisticVotingDelay\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"OptimisticVotingDelaySet\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":true,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"id\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"ProposalCanceled\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":true,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"id\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"indexed\\\":true,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"proposer\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"address[]\\\",\\\"name\\\":\\\"targets\\\",\\\"type\\\":\\\"address[]\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256[]\\\",\\\"name\\\":\\\"values\\\",\\\"type\\\":\\\"uint256[]\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"string[]\\\",\\\"name\\\":\\\"signatures\\\",\\\"type\\\":\\\"string[]\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"bytes[]\\\",\\\"name\\\":\\\"calldatas\\\",\\\"type\\\":\\\"bytes[]\\\"},{\\\"indexed\\\":true,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"startBlock\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"endBlock\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"string\\\",\\\"name\\\":\\\"description\\\",\\\"type\\\":\\\"string\\\"}],\\\"name\\\":\\\"ProposalCreated\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":true,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"id\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"ProposalExecuted\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":true,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"id\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"eta\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"ProposalQueued\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"oldProposalThreshold\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"newProposalThreshold\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"ProposalThresholdSet\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":true,\\\"internalType\\\":\\\"bytes32\\\",\\\"name\\\":\\\"txHash\\\",\\\"type\\\":\\\"bytes32\\\"},{\\\"indexed\\\":true,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"target\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"value\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"string\\\",\\\"name\\\":\\\"signature\\\",\\\"type\\\":\\\"string\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"bytes\\\",\\\"name\\\":\\\"data\\\",\\\"type\\\":\\\"bytes\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"eta\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"QueueTransaction\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":true,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"voter\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":true,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"proposalId\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint8\\\",\\\"name\\\":\\\"support\\\",\\\"type\\\":\\\"uint8\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"votes\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"string\\\",\\\"name\\\":\\\"reason\\\",\\\"type\\\":\\\"string\\\"}],\\\"name\\\":\\\"VoteCast\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"oldVotingDelay\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"newVotingDelay\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"VotingDelaySet\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"oldVotingPeriod\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"newVotingPeriod\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"VotingPeriodSet\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":false,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"account\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"expiration\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"WhitelistAccountExpirationSet\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":false,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"oldGuardian\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"newGuardian\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"WhitelistGuardianSet\\\",\\\"type\\\":\\\"event\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"BALLOT_TYPEHASH\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"bytes32\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"bytes32\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"DOMAIN_TYPEHASH\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"bytes32\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"bytes32\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"GRACE_PERIOD\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"proposalTimelockDelay_\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"_setDelay\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"emergencyTimelockDelay_\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"_setEmergencyDelay\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"newEmergencyQuorumVotes\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"_setEmergencyQuorumVotes\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"newEmergencyVotingPeriod\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"_setEmergencyVotingPeriod\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"token_\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"_setNewToken\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"newOptimisticVotingDelay\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"_setOptimisticDelay\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"newOptimisticQuorumVotes\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"_setOptimisticQuorumVotes\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"newProposalThreshold\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"_setProposalThreshold\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"newQuorumVotes\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"_setQuorumVotes\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"newVotingDelay\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"_setVotingDelay\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"newVotingPeriod\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"_setVotingPeriod\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"account\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"expiration\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"_setWhitelistAccountExpiration\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"account\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"_setWhitelistGuardian\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"proposalId\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"cancel\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"proposalId\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"uint8\\\",\\\"name\\\":\\\"support\\\",\\\"type\\\":\\\"uint8\\\"}],\\\"name\\\":\\\"castVote\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"proposalId\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"uint8\\\",\\\"name\\\":\\\"support\\\",\\\"type\\\":\\\"uint8\\\"},{\\\"internalType\\\":\\\"uint8\\\",\\\"name\\\":\\\"v\\\",\\\"type\\\":\\\"uint8\\\"},{\\\"internalType\\\":\\\"bytes32\\\",\\\"name\\\":\\\"r\\\",\\\"type\\\":\\\"bytes32\\\"},{\\\"internalType\\\":\\\"bytes32\\\",\\\"name\\\":\\\"s\\\",\\\"type\\\":\\\"bytes32\\\"}],\\\"name\\\":\\\"castVoteBySig\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"proposalId\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"uint8\\\",\\\"name\\\":\\\"support\\\",\\\"type\\\":\\\"uint8\\\"},{\\\"internalType\\\":\\\"string\\\",\\\"name\\\":\\\"reason\\\",\\\"type\\\":\\\"string\\\"}],\\\"name\\\":\\\"castVoteWithReason\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"emergencyQuorumVotes\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"emergencyTimelockDelay\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"emergencyVotingPeriod\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"proposalId\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"execute\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"payable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"target\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"value\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"string\\\",\\\"name\\\":\\\"signature\\\",\\\"type\\\":\\\"string\\\"},{\\\"internalType\\\":\\\"bytes\\\",\\\"name\\\":\\\"data\\\",\\\"type\\\":\\\"bytes\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"eta\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"executeTransaction\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"payable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"proposalId\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"getActions\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"address[]\\\",\\\"name\\\":\\\"targets\\\",\\\"type\\\":\\\"address[]\\\"},{\\\"internalType\\\":\\\"uint256[]\\\",\\\"name\\\":\\\"values\\\",\\\"type\\\":\\\"uint256[]\\\"},{\\\"internalType\\\":\\\"string[]\\\",\\\"name\\\":\\\"signatures\\\",\\\"type\\\":\\\"string[]\\\"},{\\\"internalType\\\":\\\"bytes[]\\\",\\\"name\\\":\\\"calldatas\\\",\\\"type\\\":\\\"bytes[]\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"proposalId\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"voter\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"getReceipt\\\",\\\"outputs\\\":[{\\\"components\\\":[{\\\"internalType\\\":\\\"bool\\\",\\\"name\\\":\\\"hasVoted\\\",\\\"type\\\":\\\"bool\\\"},{\\\"internalType\\\":\\\"uint8\\\",\\\"name\\\":\\\"support\\\",\\\"type\\\":\\\"uint8\\\"},{\\\"internalType\\\":\\\"uint96\\\",\\\"name\\\":\\\"votes\\\",\\\"type\\\":\\\"uint96\\\"}],\\\"internalType\\\":\\\"struct Receipt\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"tuple\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"implementation\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"address\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"initialProposalId\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"ipt_\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"initialize\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"initialized\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"bool\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"bool\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"ipt\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"contract IIpt\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"address\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"account\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"isWhitelisted\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"bool\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"bool\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"latestProposalIds\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"maxWhitelistPeriod\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"name\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"string\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"string\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"optimisticQuorumVotes\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"optimisticVotingDelay\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"proposalCount\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"proposalMaxOperations\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"proposalReceipts\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"bool\\\",\\\"name\\\":\\\"hasVoted\\\",\\\"type\\\":\\\"bool\\\"},{\\\"internalType\\\":\\\"uint8\\\",\\\"name\\\":\\\"support\\\",\\\"type\\\":\\\"uint8\\\"},{\\\"internalType\\\":\\\"uint96\\\",\\\"name\\\":\\\"votes\\\",\\\"type\\\":\\\"uint96\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"proposalThreshold\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"proposalTimelockDelay\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"proposals\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"id\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"proposer\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"eta\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"startBlock\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"endBlock\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"forVotes\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"againstVotes\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"abstainVotes\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"bool\\\",\\\"name\\\":\\\"canceled\\\",\\\"type\\\":\\\"bool\\\"},{\\\"internalType\\\":\\\"bool\\\",\\\"name\\\":\\\"executed\\\",\\\"type\\\":\\\"bool\\\"},{\\\"internalType\\\":\\\"bool\\\",\\\"name\\\":\\\"emergency\\\",\\\"type\\\":\\\"bool\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"quorumVotes\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"delay\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address[]\\\",\\\"name\\\":\\\"targets\\\",\\\"type\\\":\\\"address[]\\\"},{\\\"internalType\\\":\\\"uint256[]\\\",\\\"name\\\":\\\"values\\\",\\\"type\\\":\\\"uint256[]\\\"},{\\\"internalType\\\":\\\"string[]\\\",\\\"name\\\":\\\"signatures\\\",\\\"type\\\":\\\"string[]\\\"},{\\\"internalType\\\":\\\"bytes[]\\\",\\\"name\\\":\\\"calldatas\\\",\\\"type\\\":\\\"bytes[]\\\"},{\\\"internalType\\\":\\\"string\\\",\\\"name\\\":\\\"description\\\",\\\"type\\\":\\\"string\\\"},{\\\"internalType\\\":\\\"bool\\\",\\\"name\\\":\\\"emergency\\\",\\\"type\\\":\\\"bool\\\"}],\\\"name\\\":\\\"propose\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"proposalId\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"queue\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"bytes32\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"bytes32\\\"}],\\\"name\\\":\\\"queuedTransactions\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"bool\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"bool\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"quorumVotes\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"proposalId\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"state\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"enum ProposalState\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint8\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"votingDelay\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"votingPeriod\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"whitelistAccountExpirations\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"whitelistGuardian\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"address\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"}]\",\"ContractName\":\"GovernorCharlieDelegate\",\"CompilerVersion\":\"v0.8.9+commit.e5eed63a\",\"OptimizationUsed\":1,\"Runs\":200,\"ConstructorArguments\":\"0x\",\"EVMVersion\":\"Default\",\"Library\":\"\",\"LicenseType\":\"\",\"Proxy\":0,\"SwarmSource\":\"\"}]"
  },
  {
    "path": "testdata/etherscan/0x9AB6b21cDF116f611110b048987E58894786C244/creation_data.json",
    "content": "{\"contractAddress\":\"0x9ab6b21cdf116f611110b048987e58894786c244\",\"contractCreator\":\"0x603d50bad151da8becf405e51a8c4abc8ba1c95e\",\"txHash\":\"0x72be611ae1ade09242d9fc9c950a73d076f6c23514564a7b9ac730400dbaf2c0\"}"
  },
  {
    "path": "testdata/etherscan/0x9AB6b21cDF116f611110b048987E58894786C244/metadata.json",
    "content": "[{\"SourceCode\":{\"language\":\"Solidity\",\"sources\":{\"contracts/InterestRates/InterestRatePositionManager.f.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity 0.8.19;\\n\\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n    /**\\n     * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n     * another (`to`).\\n     *\\n     * Note that `value` may be zero.\\n     */\\n    event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n    /**\\n     * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n     * a call to {approve}. `value` is the new allowance.\\n     */\\n    event Approval(address indexed owner, address indexed spender, uint256 value);\\n\\n    /**\\n     * @dev Returns the amount of tokens in existence.\\n     */\\n    function totalSupply() external view returns (uint256);\\n\\n    /**\\n     * @dev Returns the amount of tokens owned by `account`.\\n     */\\n    function balanceOf(address account) external view returns (uint256);\\n\\n    /**\\n     * @dev Moves `amount` tokens from the caller's account to `to`.\\n     *\\n     * Returns a boolean value indicating whether the operation succeeded.\\n     *\\n     * Emits a {Transfer} event.\\n     */\\n    function transfer(address to, uint256 amount) external returns (bool);\\n\\n    /**\\n     * @dev Returns the remaining number of tokens that `spender` will be\\n     * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n     * zero by default.\\n     *\\n     * This value changes when {approve} or {transferFrom} are called.\\n     */\\n    function allowance(address owner, address spender) external view returns (uint256);\\n\\n    /**\\n     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n     *\\n     * Returns a boolean value indicating whether the operation succeeded.\\n     *\\n     * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n     * that someone may use both the old and the new allowance by unfortunate\\n     * transaction ordering. One possible solution to mitigate this race\\n     * condition is to first reduce the spender's allowance to 0 and set the\\n     * desired value afterwards:\\n     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n     *\\n     * Emits an {Approval} event.\\n     */\\n    function approve(address spender, uint256 amount) external returns (bool);\\n\\n    /**\\n     * @dev Moves `amount` tokens from `from` to `to` using the\\n     * allowance mechanism. `amount` is then deducted from the caller's\\n     * allowance.\\n     *\\n     * Returns a boolean value indicating whether the operation succeeded.\\n     *\\n     * Emits a {Transfer} event.\\n     */\\n    function transferFrom(\\n        address from,\\n        address to,\\n        uint256 amount\\n    ) external returns (bool);\\n}\\n\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)\\n\\n/**\\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\\n *\\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\\n * need to send a transaction, and thus is not required to hold Ether at all.\\n */\\ninterface IERC20Permit {\\n    /**\\n     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\\n     * given ``owner``'s signed approval.\\n     *\\n     * IMPORTANT: The same issues {IERC20-approve} has related to transaction\\n     * ordering also apply here.\\n     *\\n     * Emits an {Approval} event.\\n     *\\n     * Requirements:\\n     *\\n     * - `spender` cannot be the zero address.\\n     * - `deadline` must be a timestamp in the future.\\n     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\\n     * over the EIP712-formatted function arguments.\\n     * - the signature must use ``owner``'s current nonce (see {nonces}).\\n     *\\n     * For more information on the signature format, see the\\n     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\\n     * section].\\n     */\\n    function permit(\\n        address owner,\\n        address spender,\\n        uint256 value,\\n        uint256 deadline,\\n        uint8 v,\\n        bytes32 r,\\n        bytes32 s\\n    ) external;\\n\\n    /**\\n     * @dev Returns the current nonce for `owner`. This value must be\\n     * included whenever a signature is generated for {permit}.\\n     *\\n     * Every successful call to {permit} increases ``owner``'s nonce by one. This\\n     * prevents a signature from being used multiple times.\\n     */\\n    function nonces(address owner) external view returns (uint256);\\n\\n    /**\\n     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\\n     */\\n    // solhint-disable-next-line func-name-mixedcase\\n    function DOMAIN_SEPARATOR() external view returns (bytes32);\\n}\\n\\n/// Parameters for ERC20Permit.permit call\\nstruct ERC20PermitSignature {\\n    IERC20Permit token;\\n    uint256 value;\\n    uint256 deadline;\\n    uint8 v;\\n    bytes32 r;\\n    bytes32 s;\\n}\\n\\nlibrary PermitHelper {\\n    function applyPermit(\\n        ERC20PermitSignature calldata p,\\n        address owner,\\n        address spender\\n    ) internal {\\n        p.token.permit(owner, spender, p.value, p.deadline, p.v, p.r, p.s);\\n    }\\n\\n    function applyPermits(\\n        ERC20PermitSignature[] calldata permits,\\n        address owner,\\n        address spender\\n    ) internal {\\n        for (uint256 i = 0; i < permits.length; i++) {\\n            applyPermit(permits[i], owner, spender);\\n        }\\n    }\\n}\\n\\n// OpenZeppelin Contracts v4.4.1 (interfaces/IERC3156FlashLender.sol)\\n\\n// OpenZeppelin Contracts (last updated v4.7.0) (interfaces/IERC3156FlashBorrower.sol)\\n\\n/**\\n * @dev Interface of the ERC3156 FlashBorrower, as defined in\\n * https://eips.ethereum.org/EIPS/eip-3156[ERC-3156].\\n *\\n * _Available since v4.1._\\n */\\ninterface IERC3156FlashBorrower {\\n    /**\\n     * @dev Receive a flash loan.\\n     * @param initiator The initiator of the loan.\\n     * @param token The loan currency.\\n     * @param amount The amount of tokens lent.\\n     * @param fee The additional amount of tokens to repay.\\n     * @param data Arbitrary data structure, intended to contain user-defined parameters.\\n     * @return The keccak256 hash of \\\"IERC3156FlashBorrower.onFlashLoan\\\"\\n     */\\n    function onFlashLoan(\\n        address initiator,\\n        address token,\\n        uint256 amount,\\n        uint256 fee,\\n        bytes calldata data\\n    ) external returns (bytes32);\\n}\\n\\n/**\\n * @dev Interface of the ERC3156 FlashLender, as defined in\\n * https://eips.ethereum.org/EIPS/eip-3156[ERC-3156].\\n *\\n * _Available since v4.1._\\n */\\ninterface IERC3156FlashLender {\\n    /**\\n     * @dev The amount of currency available to be lended.\\n     * @param token The loan currency.\\n     * @return The amount of `token` that can be borrowed.\\n     */\\n    function maxFlashLoan(address token) external view returns (uint256);\\n\\n    /**\\n     * @dev The fee to be charged for a given loan.\\n     * @param token The loan currency.\\n     * @param amount The amount of tokens lent.\\n     * @return The amount of `token` to be charged for the loan, on top of the returned principal.\\n     */\\n    function flashFee(address token, uint256 amount) external view returns (uint256);\\n\\n    /**\\n     * @dev Initiate a flash loan.\\n     * @param receiver The receiver of the tokens in the loan, and the receiver of the callback.\\n     * @param token The loan currency.\\n     * @param amount The amount of tokens lent.\\n     * @param data Arbitrary data structure, intended to contain user-defined parameters.\\n     */\\n    function flashLoan(\\n        IERC3156FlashBorrower receiver,\\n        address token,\\n        uint256 amount,\\n        bytes calldata data\\n    ) external returns (bool);\\n}\\n\\n/// @dev Interface to be used by contracts that collect fees. Contains fee recipient that can be changed by owner.\\ninterface IFeeCollector {\\n    // --- Events ---\\n\\n    /// @dev Fee Recipient is changed to @param feeRecipient address.\\n    /// @param feeRecipient New fee recipient address.\\n    event FeeRecipientChanged(address feeRecipient);\\n\\n    // --- Errors ---\\n\\n    /// @dev Invalid fee recipient.\\n    error InvalidFeeRecipient();\\n\\n    // --- Functions ---\\n\\n    /// @return Address of the current fee recipient.\\n    function feeRecipient() external view returns (address);\\n\\n    /// @dev Sets new fee recipient address\\n    /// @param newFeeRecipient Address of the new fee recipient.\\n    function setFeeRecipient(address newFeeRecipient) external;\\n}\\n\\ninterface IPositionManagerDependent {\\n    // --- Errors ---\\n\\n    /// @dev Position Manager cannot be zero.\\n    error PositionManagerCannotBeZero();\\n\\n    /// @dev Caller is not Position Manager.\\n    error CallerIsNotPositionManager(address caller);\\n\\n    // --- Functions ---\\n\\n    /// @dev Returns address of the PositionManager contract.\\n    function positionManager() external view returns (address);\\n}\\n\\n/// @dev Interface of R stablecoin token. Implements some standards like IERC20, IERC20Permit, and IERC3156FlashLender.\\n/// Raft's specific implementation contains IFeeCollector and IPositionManagerDependent.\\n/// PositionManager can mint and burn R when particular actions happen with user's position.\\ninterface IRToken is IERC20, IERC20Permit, IERC3156FlashLender, IFeeCollector, IPositionManagerDependent {\\n    // --- Events ---\\n\\n    /// @dev New R token is deployed\\n    /// @param positionManager Address of the PositionManager contract that is authorized to mint and burn new tokens.\\n    /// @param flashMintFeeRecipient Address of flash mint fee recipient.\\n    event RDeployed(address positionManager, address flashMintFeeRecipient);\\n\\n    /// @dev The Flash Mint Fee Percentage has been changed.\\n    /// @param flashMintFeePercentage The new Flash Mint Fee Percentage value.\\n    event FlashMintFeePercentageChanged(uint256 flashMintFeePercentage);\\n\\n    /// --- Errors ---\\n\\n    /// @dev Proposed flash mint fee percentage is too big.\\n    /// @param feePercentage Proposed flash mint fee percentage.\\n    error FlashFeePercentageTooBig(uint256 feePercentage);\\n\\n    // --- Functions ---\\n\\n    /// @return Number representing 100 percentage.\\n    function PERCENTAGE_BASE() external view returns (uint256);\\n\\n    /// @dev Mints new tokens. Callable only by PositionManager contract.\\n    /// @param to Address that will receive newly minted tokens.\\n    /// @param amount Amount of tokens to mint.\\n    function mint(address to, uint256 amount) external;\\n\\n    /// @dev Mints new tokens. Callable only by PositionManager contract.\\n    /// @param from Address of user whose tokens are burnt.\\n    /// @param amount Amount of tokens to burn.\\n    function burn(address from, uint256 amount) external;\\n\\n    /// @return Maximum flash mint fee percentage that can be set by owner.\\n    function MAX_FLASH_MINT_FEE_PERCENTAGE() external view returns (uint256);\\n\\n    /// @return Current flash mint fee percentage.\\n    function flashMintFeePercentage() external view returns (uint256);\\n\\n    /// @dev Sets new flash mint fee percentage. Callable only by owner.\\n    /// @notice The proposed flash mint fee percentage cannot exceed `MAX_FLASH_MINT_FEE_PERCENTAGE`.\\n    /// @param feePercentage New flash fee percentage.\\n    function setFlashMintFeePercentage(uint256 feePercentage) external;\\n}\\n\\ninterface IPriceOracle {\\n    // --- Errors ---\\n\\n    /// @dev Contract initialized with an invalid deviation parameter.\\n    error InvalidDeviation();\\n\\n    // --- Types ---\\n\\n    struct PriceOracleResponse {\\n        bool isBrokenOrFrozen;\\n        bool priceChangeAboveMax;\\n        uint256 price;\\n    }\\n\\n    // --- Functions ---\\n\\n    /// @dev Return price oracle response which consists the following information: oracle is broken or frozen, the\\n    /// price change between two rounds is more than max, and the price.\\n    function getPriceOracleResponse() external returns (PriceOracleResponse memory);\\n\\n    /// @dev Maximum time period allowed since oracle latest round data timestamp, beyond which oracle is considered\\n    /// frozen.\\n    function timeout() external view returns (uint256);\\n\\n    /// @dev Used to convert a price answer to an 18-digit precision uint.\\n    function TARGET_DIGITS() external view returns (uint256);\\n\\n    /// @dev price deviation for the oracle in percentage.\\n    function DEVIATION() external view returns (uint256);\\n}\\n\\ninterface IPriceFeed {\\n    // --- Events ---\\n\\n    /// @dev Last good price has been updated.\\n    event LastGoodPriceUpdated(uint256 lastGoodPrice);\\n\\n    /// @dev Price difference between oracles has been updated.\\n    /// @param priceDifferenceBetweenOracles New price difference between oracles.\\n    event PriceDifferenceBetweenOraclesUpdated(uint256 priceDifferenceBetweenOracles);\\n\\n    /// @dev Primary oracle has been updated.\\n    /// @param primaryOracle New primary oracle.\\n    event PrimaryOracleUpdated(IPriceOracle primaryOracle);\\n\\n    /// @dev Secondary oracle has been updated.\\n    /// @param secondaryOracle New secondary oracle.\\n    event SecondaryOracleUpdated(IPriceOracle secondaryOracle);\\n\\n    // --- Errors ---\\n\\n    /// @dev Invalid primary oracle.\\n    error InvalidPrimaryOracle();\\n\\n    /// @dev Invalid secondary oracle.\\n    error InvalidSecondaryOracle();\\n\\n    /// @dev Primary oracle is broken or frozen or has bad result.\\n    error PrimaryOracleBrokenOrFrozenOrBadResult();\\n\\n    /// @dev Invalid price difference between oracles.\\n    error InvalidPriceDifferenceBetweenOracles();\\n\\n    // --- Functions ---\\n\\n    /// @dev Return primary oracle address.\\n    function primaryOracle() external returns (IPriceOracle);\\n\\n    /// @dev Return secondary oracle address\\n    function secondaryOracle() external returns (IPriceOracle);\\n\\n    /// @dev The last good price seen from an oracle by Raft.\\n    function lastGoodPrice() external returns (uint256);\\n\\n    /// @dev The maximum relative price difference between two oracle responses.\\n    function priceDifferenceBetweenOracles() external returns (uint256);\\n\\n    /// @dev Set primary oracle address.\\n    /// @param newPrimaryOracle Primary oracle address.\\n    function setPrimaryOracle(IPriceOracle newPrimaryOracle) external;\\n\\n    /// @dev Set secondary oracle address.\\n    /// @param newSecondaryOracle Secondary oracle address.\\n    function setSecondaryOracle(IPriceOracle newSecondaryOracle) external;\\n\\n    /// @dev Set the maximum relative price difference between two oracle responses.\\n    /// @param newPriceDifferenceBetweenOracles The maximum relative price difference between two oracle responses.\\n    function setPriceDifferenceBetweenOracles(uint256 newPriceDifferenceBetweenOracles) external;\\n\\n    /// @dev Returns the latest price obtained from the Oracle. Called by Raft functions that require a current price.\\n    ///\\n    /// Also callable by anyone externally.\\n    /// Non-view function - it stores the last good price seen by Raft.\\n    ///\\n    /// Uses a primary oracle and a fallback oracle in case primary fails. If both fail,\\n    /// it uses the last good price seen by Raft.\\n    ///\\n    /// @return currentPrice Returned price.\\n    /// @return deviation Deviation of the reported price in percentage.\\n    /// @notice Actual returned price is in range `currentPrice` +/- `currentPrice * deviation / ONE`\\n    function fetchPrice() external returns (uint256 currentPrice, uint256 deviation);\\n}\\n\\ninterface IERC20Indexable is IERC20, IPositionManagerDependent {\\n    // --- Events ---\\n\\n    /// @dev New token is deployed.\\n    /// @param positionManager Address of the PositionManager contract that is authorized to mint and burn new tokens.\\n    event ERC20IndexableDeployed(address positionManager);\\n\\n    /// @dev New index has been set.\\n    /// @param newIndex Value of the new index.\\n    event IndexUpdated(uint256 newIndex);\\n\\n    // --- Errors ---\\n\\n    /// @dev Unsupported action for ERC20Indexable contract.\\n    error NotSupported();\\n\\n    // --- Functions ---\\n\\n    /// @return Precision for token index. Represents index that is equal to 1.\\n    function INDEX_PRECISION() external view returns (uint256);\\n\\n    /// @return Current index value.\\n    function currentIndex() external view returns (uint256);\\n\\n    /// @dev Sets new token index. Callable only by PositionManager contract.\\n    /// @param backingAmount Amount of backing token that is covered by total supply.\\n    function setIndex(uint256 backingAmount) external;\\n\\n    /// @dev Mints new tokens. Callable only by PositionManager contract.\\n    /// @param to Address that will receive newly minted tokens.\\n    /// @param amount Amount of tokens to mint.\\n    function mint(address to, uint256 amount) external;\\n\\n    /// @dev Mints new tokens. Callable only by PositionManager contract.\\n    /// @param from Address of user whose tokens are burnt.\\n    /// @param amount Amount of tokens to burn.\\n    function burn(address from, uint256 amount) external;\\n}\\n\\ninterface ISplitLiquidationCollateral {\\n    // --- Functions ---\\n\\n    /// @dev Returns lowest total debt that will be split.\\n    function LOW_TOTAL_DEBT() external view returns (uint256);\\n\\n    /// @dev Minimum collateralization ratio for position\\n    function MCR() external view returns (uint256);\\n\\n    /// @dev Splits collateral between protocol and liquidator.\\n    /// @param totalCollateral Amount of collateral to split.\\n    /// @param totalDebt Amount of debt to split.\\n    /// @param price Price of collateral.\\n    /// @param isRedistribution True if this is a redistribution.\\n    /// @return collateralToSendToProtocol Amount of collateral to send to protocol.\\n    /// @return collateralToSentToLiquidator Amount of collateral to send to liquidator.\\n    function split(\\n        uint256 totalCollateral,\\n        uint256 totalDebt,\\n        uint256 price,\\n        bool isRedistribution\\n    )\\n        external\\n        view\\n        returns (uint256 collateralToSendToProtocol, uint256 collateralToSentToLiquidator);\\n}\\n\\n/// @dev Common interface for the Position Manager.\\ninterface IPositionManager is IFeeCollector {\\n    // --- Types ---\\n\\n    /// @dev Information for a Raft indexable collateral token.\\n    /// @param collateralToken The Raft indexable collateral token.\\n    /// @param debtToken Corresponding Raft indexable debt token.\\n    /// @param priceFeed The contract that provides a price for the collateral token.\\n    /// @param splitLiquidation The contract that calculates collateral split in case of liquidation.\\n    /// @param isEnabled Whether the token can be used as collateral or not.\\n    /// @param lastFeeOperationTime Timestamp of the last operation for the collateral token.\\n    /// @param borrowingSpread The current borrowing spread.\\n    /// @param baseRate The current base rate.\\n    /// @param redemptionSpread The current redemption spread.\\n    /// @param redemptionRebate Percentage of the redemption fee returned to redeemed positions.\\n    struct CollateralTokenInfo {\\n        IERC20Indexable collateralToken;\\n        IERC20Indexable debtToken;\\n        IPriceFeed priceFeed;\\n        ISplitLiquidationCollateral splitLiquidation;\\n        bool isEnabled;\\n        uint256 lastFeeOperationTime;\\n        uint256 borrowingSpread;\\n        uint256 baseRate;\\n        uint256 redemptionSpread;\\n        uint256 redemptionRebate;\\n    }\\n\\n    // --- Events ---\\n\\n    /// @dev New position manager has been token deployed.\\n    /// @param rToken The R token used by the position manager.\\n    /// @param feeRecipient The address of fee recipient.\\n    event PositionManagerDeployed(IRToken rToken, address feeRecipient);\\n\\n    /// @dev New collateral token has been added added to the system.\\n    /// @param collateralToken The token used as collateral.\\n    /// @param raftCollateralToken The Raft indexable collateral token for the given collateral token.\\n    /// @param raftDebtToken The Raft indexable debt token for given collateral token.\\n    /// @param priceFeed The contract that provides price for the collateral token.\\n    event CollateralTokenAdded(\\n        IERC20 collateralToken,\\n        IERC20Indexable raftCollateralToken,\\n        IERC20Indexable raftDebtToken,\\n        IPriceFeed priceFeed\\n    );\\n\\n    /// @dev Collateral token has been enabled or disabled.\\n    /// @param collateralToken The token used as collateral.\\n    /// @param isEnabled True if the token is enabled, false otherwise.\\n    event CollateralTokenModified(IERC20 collateralToken, bool isEnabled);\\n\\n    /// @dev A delegate has been whitelisted for a certain position.\\n    /// @param position The position for which the delegate was whitelisted.\\n    /// @param delegate The delegate which was whitelisted.\\n    /// @param whitelisted Specifies whether the delegate whitelisting has been enabled (true) or disabled (false).\\n    event DelegateWhitelisted(address indexed position, address indexed delegate, bool whitelisted);\\n\\n    /// @dev New position has been created.\\n    /// @param position The address of the user opening new position.\\n    /// @param collateralToken The token used as collateral for the created position.\\n    event PositionCreated(address indexed position, IERC20 indexed collateralToken);\\n\\n    /// @dev The position has been closed by either repayment, liquidation, or redemption.\\n    /// @param position The address of the user whose position is closed.\\n    event PositionClosed(address indexed position);\\n\\n    /// @dev Collateral amount for the position has been changed.\\n    /// @param position The address of the user that has opened the position.\\n    /// @param collateralToken The address of the collateral token being added to position.\\n    /// @param collateralAmount The amount of collateral added or removed.\\n    /// @param isCollateralIncrease Whether the collateral is added to the position or removed from it.\\n    event CollateralChanged(\\n        address indexed position, IERC20 indexed collateralToken, uint256 collateralAmount, bool isCollateralIncrease\\n    );\\n\\n    /// @dev Debt amount for position has been changed.\\n    /// @param position The address of the user that has opened the position.\\n    /// @param collateralToken The address of the collateral token backing the debt.\\n    /// @param debtAmount The amount of debt added or removed.\\n    /// @param isDebtIncrease Whether the debt is added to the position or removed from it.\\n    event DebtChanged(\\n        address indexed position, IERC20 indexed collateralToken, uint256 debtAmount, bool isDebtIncrease\\n    );\\n\\n    /// @dev Borrowing fee has been paid. Emitted only if the actual fee was paid - doesn't happen with no fees are\\n    /// paid.\\n    /// @param collateralToken Collateral token used to mint R.\\n    /// @param position The address of position's owner that triggered the fee payment.\\n    /// @param feeAmount The amount of tokens paid as the borrowing fee.\\n    event RBorrowingFeePaid(IERC20 collateralToken, address indexed position, uint256 feeAmount);\\n\\n    /// @dev Liquidation has been executed.\\n    /// @param liquidator The liquidator that executed the liquidation.\\n    /// @param position The address of position's owner whose position was liquidated.\\n    /// @param collateralToken The collateral token used for the liquidation.\\n    /// @param debtLiquidated The total debt that was liquidated or redistributed.\\n    /// @param collateralLiquidated The total collateral liquidated.\\n    /// @param collateralSentToLiquidator The collateral amount sent to the liquidator.\\n    /// @param collateralLiquidationFeePaid The total collateral paid as the liquidation fee to the fee recipient.\\n    /// @param isRedistribution Whether the executed liquidation was redistribution or not.\\n    event Liquidation(\\n        address indexed liquidator,\\n        address indexed position,\\n        IERC20 indexed collateralToken,\\n        uint256 debtLiquidated,\\n        uint256 collateralLiquidated,\\n        uint256 collateralSentToLiquidator,\\n        uint256 collateralLiquidationFeePaid,\\n        bool isRedistribution\\n    );\\n\\n    /// @dev Redemption has been executed.\\n    /// @param redeemer User that redeemed R.\\n    /// @param amount Amount of R that was redeemed.\\n    /// @param collateralSent The amount of collateral sent to the redeemer.\\n    /// @param fee The amount of fee paid to the fee recipient.\\n    /// @param rebate Redemption rebate amount.\\n    event Redemption(address indexed redeemer, uint256 amount, uint256 collateralSent, uint256 fee, uint256 rebate);\\n\\n    /// @dev Borrowing spread has been updated.\\n    /// @param borrowingSpread The new borrowing spread.\\n    event BorrowingSpreadUpdated(uint256 borrowingSpread);\\n\\n    /// @dev Redemption rebate has been updated.\\n    /// @param redemptionRebate The new redemption rebate.\\n    event RedemptionRebateUpdated(uint256 redemptionRebate);\\n\\n    /// @dev Redemption spread has been updated.\\n    /// @param collateralToken Collateral token that the spread was set for.\\n    /// @param redemptionSpread The new redemption spread.\\n    event RedemptionSpreadUpdated(IERC20 collateralToken, uint256 redemptionSpread);\\n\\n    /// @dev Base rate has been updated.\\n    /// @param collateralToken Collateral token that the baser rate was updated for.\\n    /// @param baseRate The new base rate.\\n    event BaseRateUpdated(IERC20 collateralToken, uint256 baseRate);\\n\\n    /// @dev Last fee operation time has been updated.\\n    /// @param collateralToken Collateral token that the baser rate was updated for.\\n    /// @param lastFeeOpTime The new operation time.\\n    event LastFeeOpTimeUpdated(IERC20 collateralToken, uint256 lastFeeOpTime);\\n\\n    /// @dev Split liquidation collateral has been changed.\\n    /// @param collateralToken Collateral token whose split liquidation collateral contract is set.\\n    /// @param newSplitLiquidationCollateral New value that was set to be split liquidation collateral.\\n    event SplitLiquidationCollateralChanged(\\n        IERC20 collateralToken, ISplitLiquidationCollateral indexed newSplitLiquidationCollateral\\n    );\\n\\n    // --- Errors ---\\n\\n    /// @dev Max fee percentage must be between borrowing spread and 100%.\\n    error InvalidMaxFeePercentage();\\n\\n    /// @dev Max fee percentage must be between 0.5% and 100%.\\n    error MaxFeePercentageOutOfRange();\\n\\n    /// @dev Amount is zero.\\n    error AmountIsZero();\\n\\n    /// @dev Nothing to liquidate.\\n    error NothingToLiquidate();\\n\\n    /// @dev Cannot liquidate last position.\\n    error CannotLiquidateLastPosition();\\n\\n    /// @dev Cannot redeem collateral below minimum debt threshold.\\n    /// @param collateralToken Collateral token used to redeem.\\n    /// @param newTotalDebt New total debt backed by collateral, which is lower than minimum debt.\\n    error TotalDebtCannotBeLowerThanMinDebt(IERC20 collateralToken, uint256 newTotalDebt);\\n\\n    /// @dev Cannot redeem collateral\\n    /// @param collateralToken Collateral token used to redeem.\\n    /// @param newTotalCollateral New total collateral, which is lower than minimum collateral.\\n    /// @param minimumCollateral Minimum collateral required to complete redeem\\n    error TotalCollateralCannotBeLowerThanMinCollateral(\\n        IERC20 collateralToken, uint256 newTotalCollateral, uint256 minimumCollateral\\n    );\\n\\n    /// @dev Fee would eat up all returned collateral.\\n    error FeeEatsUpAllReturnedCollateral();\\n\\n    /// @dev Borrowing spread exceeds maximum.\\n    error BorrowingSpreadExceedsMaximum();\\n\\n    /// @dev Redemption rebate exceeds maximum.\\n    error RedemptionRebateExceedsMaximum();\\n\\n    /// @dev Redemption spread is out of allowed range.\\n    error RedemptionSpreadOutOfRange();\\n\\n    /// @dev There must be either a collateral change or a debt change.\\n    error NoCollateralOrDebtChange();\\n\\n    /// @dev There is some collateral for position that doesn't have debt.\\n    error InvalidPosition();\\n\\n    /// @dev An operation that would result in ICR < MCR is not permitted.\\n    /// @param newICR Resulting ICR that is below MCR.\\n    error NewICRLowerThanMCR(uint256 newICR);\\n\\n    /// @dev Position's net debt must be greater than minimum.\\n    /// @param netDebt Net debt amount that is below minimum.\\n    error NetDebtBelowMinimum(uint256 netDebt);\\n\\n    /// @dev The provided delegate address is invalid.\\n    error InvalidDelegateAddress();\\n\\n    /// @dev A non-whitelisted delegate cannot adjust positions.\\n    error DelegateNotWhitelisted();\\n\\n    /// @dev Fee exceeded provided maximum fee percentage.\\n    /// @param fee The fee amount.\\n    /// @param amount The amount of debt or collateral.\\n    /// @param maxFeePercentage The maximum fee percentage.\\n    error FeeExceedsMaxFee(uint256 fee, uint256 amount, uint256 maxFeePercentage);\\n\\n    /// @dev Borrower uses a different collateral token already.\\n    error PositionCollateralTokenMismatch();\\n\\n    /// @dev Collateral token address cannot be zero.\\n    error CollateralTokenAddressCannotBeZero();\\n\\n    /// @dev Price feed address cannot be zero.\\n    error PriceFeedAddressCannotBeZero();\\n\\n    /// @dev Collateral token already added.\\n    error CollateralTokenAlreadyAdded();\\n\\n    /// @dev Collateral token is not added.\\n    error CollateralTokenNotAdded();\\n\\n    /// @dev Collateral token is not enabled.\\n    error CollateralTokenDisabled();\\n\\n    /// @dev Split liquidation collateral cannot be zero.\\n    error SplitLiquidationCollateralCannotBeZero();\\n\\n    /// @dev Cannot change collateral in case of repaying the whole debt.\\n    error WrongCollateralParamsForFullRepayment();\\n\\n    // --- Functions ---\\n\\n    /// @return The R token used by position manager.\\n    function rToken() external view returns (IRToken);\\n\\n    /// @dev Retrieves information about certain collateral type.\\n    /// @param collateralToken The token used as collateral.\\n    /// @return raftCollateralToken The Raft indexable collateral token.\\n    /// @return raftDebtToken The Raft indexable debt token.\\n    /// @return priceFeed The contract that provides a price for the collateral token.\\n    /// @return splitLiquidation The contract that calculates collateral split in case of liquidation.\\n    /// @return isEnabled Whether the collateral token can be used as collateral or not.\\n    /// @return lastFeeOperationTime Timestamp of the last operation for the collateral token.\\n    /// @return borrowingSpread The current borrowing spread.\\n    /// @return baseRate The current base rate.\\n    /// @return redemptionSpread The current redemption spread.\\n    /// @return redemptionRebate Percentage of the redemption fee returned to redeemed positions.\\n    function collateralInfo(IERC20 collateralToken)\\n        external\\n        view\\n        returns (\\n            IERC20Indexable raftCollateralToken,\\n            IERC20Indexable raftDebtToken,\\n            IPriceFeed priceFeed,\\n            ISplitLiquidationCollateral splitLiquidation,\\n            bool isEnabled,\\n            uint256 lastFeeOperationTime,\\n            uint256 borrowingSpread,\\n            uint256 baseRate,\\n            uint256 redemptionSpread,\\n            uint256 redemptionRebate\\n        );\\n\\n    /// @param collateralToken Collateral token whose raft collateral indexable token is being queried.\\n    /// @return Raft collateral token address for given collateral token.\\n    function raftCollateralToken(IERC20 collateralToken) external view returns (IERC20Indexable);\\n\\n    /// @param collateralToken Collateral token whose raft collateral indexable token is being queried.\\n    /// @return Raft debt token address for given collateral token.\\n    function raftDebtToken(IERC20 collateralToken) external view returns (IERC20Indexable);\\n\\n    /// @param collateralToken Collateral token whose price feed contract is being queried.\\n    /// @return Price feed contract address for given collateral token.\\n    function priceFeed(IERC20 collateralToken) external view returns (IPriceFeed);\\n\\n    /// @param collateralToken Collateral token whose split liquidation collateral is being queried.\\n    /// @return Returns address of the split liquidation collateral contract.\\n    function splitLiquidationCollateral(IERC20 collateralToken) external view returns (ISplitLiquidationCollateral);\\n\\n    /// @param collateralToken Collateral token whose split liquidation collateral is being queried.\\n    /// @return Returns whether collateral is enabled or nor.\\n    function collateralEnabled(IERC20 collateralToken) external view returns (bool);\\n\\n    /// @param collateralToken Collateral token we query last operation time fee for.\\n    /// @return The timestamp of the latest fee operation (redemption or new R issuance).\\n    function lastFeeOperationTime(IERC20 collateralToken) external view returns (uint256);\\n\\n    /// @param collateralToken Collateral token we query borrowing spread for.\\n    /// @return The current borrowing spread.\\n    function borrowingSpread(IERC20 collateralToken) external view returns (uint256);\\n\\n    /// @param collateralToken Collateral token we query base rate for.\\n    /// @return rate The base rate.\\n    function baseRate(IERC20 collateralToken) external view returns (uint256 rate);\\n\\n    /// @param collateralToken Collateral token we query redemption spread for.\\n    /// @return The current redemption spread for collateral token.\\n    function redemptionSpread(IERC20 collateralToken) external view returns (uint256);\\n\\n    /// @param collateralToken Collateral token we query redemption rebate for.\\n    /// @return rebate Percentage of the redemption fee returned to redeemed positions.\\n    function redemptionRebate(IERC20 collateralToken) external view returns (uint256);\\n\\n    /// @param collateralToken Collateral token we query redemption rate for.\\n    /// @return rate The current redemption rate for collateral token.\\n    function getRedemptionRate(IERC20 collateralToken) external view returns (uint256 rate);\\n\\n    /// @dev Returns the collateral token that a given position used for their position.\\n    /// @param position The address of the borrower.\\n    /// @return collateralToken The collateral token of the borrower's position.\\n    function collateralTokenForPosition(address position) external view returns (IERC20 collateralToken);\\n\\n    /// @dev Adds a new collateral token to the protocol.\\n    /// @param collateralToken The new collateral token.\\n    /// @param priceFeed The price feed for the collateral token.\\n    /// @param newSplitLiquidationCollateral split liquidation collateral contract address.\\n    function addCollateralToken(\\n        IERC20 collateralToken,\\n        IPriceFeed priceFeed,\\n        ISplitLiquidationCollateral newSplitLiquidationCollateral\\n    )\\n        external;\\n\\n    /// @dev Adds a new collateral token to the protocol.\\n    /// @param collateralToken The new collateral token.\\n    /// @param priceFeed The price feed for the collateral token.\\n    /// @param newSplitLiquidationCollateral split liquidation collateral contract address.\\n    /// @param raftCollateralToken_ Address of raft collateral token.\\n    /// @param raftDebtToken_ Address of raft debt token.\\n    function addCollateralToken(\\n        IERC20 collateralToken,\\n        IPriceFeed priceFeed,\\n        ISplitLiquidationCollateral newSplitLiquidationCollateral,\\n        IERC20Indexable raftCollateralToken_,\\n        IERC20Indexable raftDebtToken_\\n    )\\n        external;\\n\\n    /// @dev Enables or disables a collateral token. Reverts if the collateral token has not been added.\\n    /// @param collateralToken The collateral token.\\n    /// @param isEnabled Whether the collateral token can be used as collateral or not.\\n    function setCollateralEnabled(IERC20 collateralToken, bool isEnabled) external;\\n\\n    /// @dev Sets the new split liquidation collateral contract.\\n    /// @param collateralToken Collateral token whose split liquidation collateral is being set.\\n    /// @param newSplitLiquidationCollateral New split liquidation collateral contract address.\\n    function setSplitLiquidationCollateral(\\n        IERC20 collateralToken,\\n        ISplitLiquidationCollateral newSplitLiquidationCollateral\\n    )\\n        external;\\n\\n    /// @dev Liquidates the borrower if its position's ICR is lower than the minimum collateral ratio.\\n    /// @param position The address of the borrower.\\n    function liquidate(address position) external;\\n\\n    /// @dev Redeems the collateral token for a given debt amount. It sends @param debtAmount R to the system and\\n    /// redeems the corresponding amount of collateral from as many positions as are needed to fill the redemption\\n    /// request.\\n    /// @param collateralToken The token used as collateral.\\n    /// @param debtAmount The amount of debt to be redeemed. Must be greater than zero.\\n    /// @param maxFeePercentage The maximum fee percentage to pay for the redemption.\\n    function redeemCollateral(IERC20 collateralToken, uint256 debtAmount, uint256 maxFeePercentage) external;\\n\\n    /// @dev Manages the position on behalf of a given borrower.\\n    /// @param collateralToken The token the borrower used as collateral.\\n    /// @param position The address of the borrower.\\n    /// @param collateralChange The amount of collateral to add or remove.\\n    /// @param isCollateralIncrease True if the collateral is being increased, false otherwise.\\n    /// @param debtChange The amount of R to add or remove. In case of repayment (isDebtIncrease = false)\\n    /// `type(uint256).max` value can be used to repay the whole outstanding loan.\\n    /// @param isDebtIncrease True if the debt is being increased, false otherwise.\\n    /// @param maxFeePercentage The maximum fee percentage to pay for the position management.\\n    /// @param permitSignature Optional permit signature for tokens that support IERC20Permit interface.\\n    /// @notice `permitSignature` it is ignored if permit signature is not for `collateralToken`.\\n    /// @notice In case of full debt repayment, `isCollateralIncrease` is ignored and `collateralChange` must be 0.\\n    /// These values are set to `false`(collateral decrease), and the whole collateral balance of the user.\\n    /// @return actualCollateralChange Actual amount of collateral added/removed.\\n    /// Can be different to `collateralChange` in case of full repayment.\\n    /// @return actualDebtChange Actual amount of debt added/removed.\\n    /// Can be different to `debtChange` in case of passing type(uint256).max as `debtChange`.\\n    function managePosition(\\n        IERC20 collateralToken,\\n        address position,\\n        uint256 collateralChange,\\n        bool isCollateralIncrease,\\n        uint256 debtChange,\\n        bool isDebtIncrease,\\n        uint256 maxFeePercentage,\\n        ERC20PermitSignature calldata permitSignature\\n    )\\n        external\\n        returns (uint256 actualCollateralChange, uint256 actualDebtChange);\\n\\n    /// @return The max borrowing spread.\\n    function MAX_BORROWING_SPREAD() external view returns (uint256);\\n\\n    /// @return The max borrowing rate.\\n    function MAX_BORROWING_RATE() external view returns (uint256);\\n\\n    /// @dev Sets the new borrowing spread.\\n    /// @param collateralToken Collateral token we set borrowing spread for.\\n    /// @param newBorrowingSpread New borrowing spread to be used.\\n    function setBorrowingSpread(IERC20 collateralToken, uint256 newBorrowingSpread) external;\\n\\n    /// @param collateralToken Collateral token we query borrowing rate for.\\n    /// @return The current borrowing rate.\\n    function getBorrowingRate(IERC20 collateralToken) external view returns (uint256);\\n\\n    /// @param collateralToken Collateral token we query borrowing rate with decay for.\\n    /// @return The current borrowing rate with decay.\\n    function getBorrowingRateWithDecay(IERC20 collateralToken) external view returns (uint256);\\n\\n    /// @dev Returns the borrowing fee for a given debt amount.\\n    /// @param collateralToken Collateral token we query borrowing fee for.\\n    /// @param debtAmount The amount of debt.\\n    /// @return The borrowing fee.\\n    function getBorrowingFee(IERC20 collateralToken, uint256 debtAmount) external view returns (uint256);\\n\\n    /// @dev Sets the new redemption spread.\\n    /// @param newRedemptionSpread New redemption spread to be used.\\n    function setRedemptionSpread(IERC20 collateralToken, uint256 newRedemptionSpread) external;\\n\\n    /// @dev Sets new redemption rebate percentage.\\n    /// @param newRedemptionRebate Value that is being set as a redemption rebate percentage.\\n    function setRedemptionRebate(IERC20 collateralToken, uint256 newRedemptionRebate) external;\\n\\n    /// @param collateralToken Collateral token we query redemption rate with decay for.\\n    /// @return The current redemption rate with decay.\\n    function getRedemptionRateWithDecay(IERC20 collateralToken) external view returns (uint256);\\n\\n    /// @dev Returns the redemption fee for a given collateral amount.\\n    /// @param collateralToken Collateral token we query redemption fee for.\\n    /// @param collateralAmount The amount of collateral.\\n    /// @param priceDeviation Deviation for the reported price by oracle in percentage.\\n    /// @return The redemption fee.\\n    function getRedemptionFee(\\n        IERC20 collateralToken,\\n        uint256 collateralAmount,\\n        uint256 priceDeviation\\n    )\\n        external\\n        view\\n        returns (uint256);\\n\\n    /// @dev Returns the redemption fee with decay for a given collateral amount.\\n    /// @param collateralToken Collateral token we query redemption fee with decay for.\\n    /// @param collateralAmount The amount of collateral.\\n    /// @return The redemption fee with decay.\\n    function getRedemptionFeeWithDecay(\\n        IERC20 collateralToken,\\n        uint256 collateralAmount\\n    )\\n        external\\n        view\\n        returns (uint256);\\n\\n    /// @return Half-life of 12h (720 min).\\n    /// @dev (1/2) = d^720 => d = (1/2)^(1/720)\\n    function MINUTE_DECAY_FACTOR() external view returns (uint256);\\n\\n    /// @dev Returns if a given delegate is whitelisted for a given borrower.\\n    /// @param position The address of the borrower.\\n    /// @param delegate The address of the delegate.\\n    /// @return isWhitelisted True if the delegate is whitelisted for a given borrower, false otherwise.\\n    function isDelegateWhitelisted(address position, address delegate) external view returns (bool isWhitelisted);\\n\\n    /// @dev Whitelists a delegate.\\n    /// @param delegate The address of the delegate.\\n    /// @param whitelisted True if delegate is being whitelisted, false otherwise.\\n    function whitelistDelegate(address delegate, bool whitelisted) external;\\n\\n    /// @return Parameter by which to divide the redeemed fraction, in order to calc the new base rate from a\\n    /// redemption. Corresponds to (1 / ALPHA) in the white paper.\\n    function BETA() external view returns (uint256);\\n}\\n\\n/// @dev Common interface for the Position Manager.\\ninterface IInterestRatePositionManager is IPositionManager {\\n    // --- Events ---\\n\\n    /// @dev Fees coming from accrued interest are minted.\\n    /// @param collateralToken Collateral token that fees are paid for.\\n    /// @param amount Amount of R minted.\\n    event MintedFees(IERC20 collateralToken, uint256 amount);\\n\\n    // --- Errors ---\\n\\n    /// @dev Only registered debt token can be caller.\\n    /// @param sender Actual caller.\\n    error InvalidDebtToken(address sender);\\n\\n    // --- Functions ---\\n\\n    /// @dev Mints fees coming from accrued interest. Can be called only from matching debt token.\\n    /// @param collateralToken Collateral token to mint fees for.\\n    /// @param amount Amount of R to mint.\\n    function mintFees(IERC20 collateralToken, uint256 amount) external;\\n}\\n\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)\\n\\n/**\\n * @dev Standard math utilities missing in the Solidity language.\\n */\\nlibrary Math {\\n    enum Rounding {\\n        Down, // Toward negative infinity\\n        Up, // Toward infinity\\n        Zero // Toward zero\\n    }\\n\\n    /**\\n     * @dev Returns the largest of two numbers.\\n     */\\n    function max(uint256 a, uint256 b) internal pure returns (uint256) {\\n        return a > b ? a : b;\\n    }\\n\\n    /**\\n     * @dev Returns the smallest of two numbers.\\n     */\\n    function min(uint256 a, uint256 b) internal pure returns (uint256) {\\n        return a < b ? a : b;\\n    }\\n\\n    /**\\n     * @dev Returns the average of two numbers. The result is rounded towards\\n     * zero.\\n     */\\n    function average(uint256 a, uint256 b) internal pure returns (uint256) {\\n        // (a + b) / 2 can overflow.\\n        return (a & b) + (a ^ b) / 2;\\n    }\\n\\n    /**\\n     * @dev Returns the ceiling of the division of two numbers.\\n     *\\n     * This differs from standard division with `/` in that it rounds up instead\\n     * of rounding down.\\n     */\\n    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\\n        // (a + b - 1) / b can overflow on addition, so we distribute.\\n        return a == 0 ? 0 : (a - 1) / b + 1;\\n    }\\n\\n    /**\\n     * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0\\n     * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)\\n     * with further edits by Uniswap Labs also under MIT license.\\n     */\\n    function mulDiv(\\n        uint256 x,\\n        uint256 y,\\n        uint256 denominator\\n    ) internal pure returns (uint256 result) {\\n        unchecked {\\n            // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\\n            // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\\n            // variables such that product = prod1 * 2^256 + prod0.\\n            uint256 prod0; // Least significant 256 bits of the product\\n            uint256 prod1; // Most significant 256 bits of the product\\n            assembly {\\n                let mm := mulmod(x, y, not(0))\\n                prod0 := mul(x, y)\\n                prod1 := sub(sub(mm, prod0), lt(mm, prod0))\\n            }\\n\\n            // Handle non-overflow cases, 256 by 256 division.\\n            if (prod1 == 0) {\\n                return prod0 / denominator;\\n            }\\n\\n            // Make sure the result is less than 2^256. Also prevents denominator == 0.\\n            require(denominator > prod1);\\n\\n            ///////////////////////////////////////////////\\n            // 512 by 256 division.\\n            ///////////////////////////////////////////////\\n\\n            // Make division exact by subtracting the remainder from [prod1 prod0].\\n            uint256 remainder;\\n            assembly {\\n                // Compute remainder using mulmod.\\n                remainder := mulmod(x, y, denominator)\\n\\n                // Subtract 256 bit number from 512 bit number.\\n                prod1 := sub(prod1, gt(remainder, prod0))\\n                prod0 := sub(prod0, remainder)\\n            }\\n\\n            // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.\\n            // See https://cs.stackexchange.com/q/138556/92363.\\n\\n            // Does not overflow because the denominator cannot be zero at this stage in the function.\\n            uint256 twos = denominator & (~denominator + 1);\\n            assembly {\\n                // Divide denominator by twos.\\n                denominator := div(denominator, twos)\\n\\n                // Divide [prod1 prod0] by twos.\\n                prod0 := div(prod0, twos)\\n\\n                // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.\\n                twos := add(div(sub(0, twos), twos), 1)\\n            }\\n\\n            // Shift in bits from prod1 into prod0.\\n            prod0 |= prod1 * twos;\\n\\n            // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\\n            // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\\n            // four bits. That is, denominator * inv = 1 mod 2^4.\\n            uint256 inverse = (3 * denominator) ^ 2;\\n\\n            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works\\n            // in modular arithmetic, doubling the correct bits in each step.\\n            inverse *= 2 - denominator * inverse; // inverse mod 2^8\\n            inverse *= 2 - denominator * inverse; // inverse mod 2^16\\n            inverse *= 2 - denominator * inverse; // inverse mod 2^32\\n            inverse *= 2 - denominator * inverse; // inverse mod 2^64\\n            inverse *= 2 - denominator * inverse; // inverse mod 2^128\\n            inverse *= 2 - denominator * inverse; // inverse mod 2^256\\n\\n            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\\n            // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\\n            // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\\n            // is no longer required.\\n            result = prod0 * inverse;\\n            return result;\\n        }\\n    }\\n\\n    /**\\n     * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.\\n     */\\n    function mulDiv(\\n        uint256 x,\\n        uint256 y,\\n        uint256 denominator,\\n        Rounding rounding\\n    ) internal pure returns (uint256) {\\n        uint256 result = mulDiv(x, y, denominator);\\n        if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {\\n            result += 1;\\n        }\\n        return result;\\n    }\\n\\n    /**\\n     * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.\\n     *\\n     * Inspired by Henry S. Warren, Jr.'s \\\"Hacker's Delight\\\" (Chapter 11).\\n     */\\n    function sqrt(uint256 a) internal pure returns (uint256) {\\n        if (a == 0) {\\n            return 0;\\n        }\\n\\n        // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.\\n        //\\n        // We know that the \\\"msb\\\" (most significant bit) of our target number `a` is a power of 2 such that we have\\n        // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.\\n        //\\n        // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`\\n        // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`\\n        // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`\\n        //\\n        // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.\\n        uint256 result = 1 << (log2(a) >> 1);\\n\\n        // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,\\n        // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at\\n        // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision\\n        // into the expected uint128 result.\\n        unchecked {\\n            result = (result + a / result) >> 1;\\n            result = (result + a / result) >> 1;\\n            result = (result + a / result) >> 1;\\n            result = (result + a / result) >> 1;\\n            result = (result + a / result) >> 1;\\n            result = (result + a / result) >> 1;\\n            result = (result + a / result) >> 1;\\n            return min(result, a / result);\\n        }\\n    }\\n\\n    /**\\n     * @notice Calculates sqrt(a), following the selected rounding direction.\\n     */\\n    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {\\n        unchecked {\\n            uint256 result = sqrt(a);\\n            return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);\\n        }\\n    }\\n\\n    /**\\n     * @dev Return the log in base 2, rounded down, of a positive value.\\n     * Returns 0 if given 0.\\n     */\\n    function log2(uint256 value) internal pure returns (uint256) {\\n        uint256 result = 0;\\n        unchecked {\\n            if (value >> 128 > 0) {\\n                value >>= 128;\\n                result += 128;\\n            }\\n            if (value >> 64 > 0) {\\n                value >>= 64;\\n                result += 64;\\n            }\\n            if (value >> 32 > 0) {\\n                value >>= 32;\\n                result += 32;\\n            }\\n            if (value >> 16 > 0) {\\n                value >>= 16;\\n                result += 16;\\n            }\\n            if (value >> 8 > 0) {\\n                value >>= 8;\\n                result += 8;\\n            }\\n            if (value >> 4 > 0) {\\n                value >>= 4;\\n                result += 4;\\n            }\\n            if (value >> 2 > 0) {\\n                value >>= 2;\\n                result += 2;\\n            }\\n            if (value >> 1 > 0) {\\n                result += 1;\\n            }\\n        }\\n        return result;\\n    }\\n\\n    /**\\n     * @dev Return the log in base 2, following the selected rounding direction, of a positive value.\\n     * Returns 0 if given 0.\\n     */\\n    function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {\\n        unchecked {\\n            uint256 result = log2(value);\\n            return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);\\n        }\\n    }\\n\\n    /**\\n     * @dev Return the log in base 10, rounded down, of a positive value.\\n     * Returns 0 if given 0.\\n     */\\n    function log10(uint256 value) internal pure returns (uint256) {\\n        uint256 result = 0;\\n        unchecked {\\n            if (value >= 10**64) {\\n                value /= 10**64;\\n                result += 64;\\n            }\\n            if (value >= 10**32) {\\n                value /= 10**32;\\n                result += 32;\\n            }\\n            if (value >= 10**16) {\\n                value /= 10**16;\\n                result += 16;\\n            }\\n            if (value >= 10**8) {\\n                value /= 10**8;\\n                result += 8;\\n            }\\n            if (value >= 10**4) {\\n                value /= 10**4;\\n                result += 4;\\n            }\\n            if (value >= 10**2) {\\n                value /= 10**2;\\n                result += 2;\\n            }\\n            if (value >= 10**1) {\\n                result += 1;\\n            }\\n        }\\n        return result;\\n    }\\n\\n    /**\\n     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\\n     * Returns 0 if given 0.\\n     */\\n    function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {\\n        unchecked {\\n            uint256 result = log10(value);\\n            return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);\\n        }\\n    }\\n\\n    /**\\n     * @dev Return the log in base 256, rounded down, of a positive value.\\n     * Returns 0 if given 0.\\n     *\\n     * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.\\n     */\\n    function log256(uint256 value) internal pure returns (uint256) {\\n        uint256 result = 0;\\n        unchecked {\\n            if (value >> 128 > 0) {\\n                value >>= 128;\\n                result += 16;\\n            }\\n            if (value >> 64 > 0) {\\n                value >>= 64;\\n                result += 8;\\n            }\\n            if (value >> 32 > 0) {\\n                value >>= 32;\\n                result += 4;\\n            }\\n            if (value >> 16 > 0) {\\n                value >>= 16;\\n                result += 2;\\n            }\\n            if (value >> 8 > 0) {\\n                result += 1;\\n            }\\n        }\\n        return result;\\n    }\\n\\n    /**\\n     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\\n     * Returns 0 if given 0.\\n     */\\n    function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {\\n        unchecked {\\n            uint256 result = log256(value);\\n            return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0);\\n        }\\n    }\\n}\\n\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\\n\\n/**\\n * @dev Interface for the optional metadata functions from the ERC20 standard.\\n *\\n * _Available since v4.1._\\n */\\ninterface IERC20Metadata is IERC20 {\\n    /**\\n     * @dev Returns the name of the token.\\n     */\\n    function name() external view returns (string memory);\\n\\n    /**\\n     * @dev Returns the symbol of the token.\\n     */\\n    function symbol() external view returns (string memory);\\n\\n    /**\\n     * @dev Returns the decimals places of the token.\\n     */\\n    function decimals() external view returns (uint8);\\n}\\n\\n// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol)\\n\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n    /**\\n     * @dev Returns true if `account` is a contract.\\n     *\\n     * [IMPORTANT]\\n     * ====\\n     * It is unsafe to assume that an address for which this function returns\\n     * false is an externally-owned account (EOA) and not a contract.\\n     *\\n     * Among others, `isContract` will return false for the following\\n     * types of addresses:\\n     *\\n     *  - an externally-owned account\\n     *  - a contract in construction\\n     *  - an address where a contract will be created\\n     *  - an address where a contract lived, but was destroyed\\n     * ====\\n     *\\n     * [IMPORTANT]\\n     * ====\\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n     *\\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n     * constructor.\\n     * ====\\n     */\\n    function isContract(address account) internal view returns (bool) {\\n        // This method relies on extcodesize/address.code.length, which returns 0\\n        // for contracts in construction, since the code is only stored at the end\\n        // of the constructor execution.\\n\\n        return account.code.length > 0;\\n    }\\n\\n    /**\\n     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n     * `recipient`, forwarding all available gas and reverting on errors.\\n     *\\n     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n     * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n     * imposed by `transfer`, making them unable to receive funds via\\n     * `transfer`. {sendValue} removes this limitation.\\n     *\\n     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n     *\\n     * IMPORTANT: because control is transferred to `recipient`, care must be\\n     * taken to not create reentrancy vulnerabilities. Consider using\\n     * {ReentrancyGuard} or the\\n     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n     */\\n    function sendValue(address payable recipient, uint256 amount) internal {\\n        require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n        (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n        require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n    }\\n\\n    /**\\n     * @dev Performs a Solidity function call using a low level `call`. A\\n     * plain `call` is an unsafe replacement for a function call: use this\\n     * function instead.\\n     *\\n     * If `target` reverts with a revert reason, it is bubbled up by this\\n     * function (like regular Solidity function calls).\\n     *\\n     * Returns the raw returned data. To convert to the expected return value,\\n     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n     *\\n     * Requirements:\\n     *\\n     * - `target` must be a contract.\\n     * - calling `target` with `data` must not revert.\\n     *\\n     * _Available since v3.1._\\n     */\\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n        return functionCallWithValue(target, data, 0, \\\"Address: low-level call failed\\\");\\n    }\\n\\n    /**\\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n     * `errorMessage` as a fallback revert reason when `target` reverts.\\n     *\\n     * _Available since v3.1._\\n     */\\n    function functionCall(\\n        address target,\\n        bytes memory data,\\n        string memory errorMessage\\n    ) internal returns (bytes memory) {\\n        return functionCallWithValue(target, data, 0, errorMessage);\\n    }\\n\\n    /**\\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n     * but also transferring `value` wei to `target`.\\n     *\\n     * Requirements:\\n     *\\n     * - the calling contract must have an ETH balance of at least `value`.\\n     * - the called Solidity function must be `payable`.\\n     *\\n     * _Available since v3.1._\\n     */\\n    function functionCallWithValue(\\n        address target,\\n        bytes memory data,\\n        uint256 value\\n    ) internal returns (bytes memory) {\\n        return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n    }\\n\\n    /**\\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\\n     *\\n     * _Available since v3.1._\\n     */\\n    function functionCallWithValue(\\n        address target,\\n        bytes memory data,\\n        uint256 value,\\n        string memory errorMessage\\n    ) internal returns (bytes memory) {\\n        require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\\n        return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n    }\\n\\n    /**\\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n     * but performing a static call.\\n     *\\n     * _Available since v3.3._\\n     */\\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n        return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n    }\\n\\n    /**\\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n     * but performing a static call.\\n     *\\n     * _Available since v3.3._\\n     */\\n    function functionStaticCall(\\n        address target,\\n        bytes memory data,\\n        string memory errorMessage\\n    ) internal view returns (bytes memory) {\\n        (bool success, bytes memory returndata) = target.staticcall(data);\\n        return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n    }\\n\\n    /**\\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n     * but performing a delegate call.\\n     *\\n     * _Available since v3.4._\\n     */\\n    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n        return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n    }\\n\\n    /**\\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n     * but performing a delegate call.\\n     *\\n     * _Available since v3.4._\\n     */\\n    function functionDelegateCall(\\n        address target,\\n        bytes memory data,\\n        string memory errorMessage\\n    ) internal returns (bytes memory) {\\n        (bool success, bytes memory returndata) = target.delegatecall(data);\\n        return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n    }\\n\\n    /**\\n     * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\\n     * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\\n     *\\n     * _Available since v4.8._\\n     */\\n    function verifyCallResultFromTarget(\\n        address target,\\n        bool success,\\n        bytes memory returndata,\\n        string memory errorMessage\\n    ) internal view returns (bytes memory) {\\n        if (success) {\\n            if (returndata.length == 0) {\\n                // only check isContract if the call was successful and the return data is empty\\n                // otherwise we already know that it was a contract\\n                require(isContract(target), \\\"Address: call to non-contract\\\");\\n            }\\n            return returndata;\\n        } else {\\n            _revert(returndata, errorMessage);\\n        }\\n    }\\n\\n    /**\\n     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\\n     * revert reason or using the provided one.\\n     *\\n     * _Available since v4.3._\\n     */\\n    function verifyCallResult(\\n        bool success,\\n        bytes memory returndata,\\n        string memory errorMessage\\n    ) internal pure returns (bytes memory) {\\n        if (success) {\\n            return returndata;\\n        } else {\\n            _revert(returndata, errorMessage);\\n        }\\n    }\\n\\n    function _revert(bytes memory returndata, string memory errorMessage) private pure {\\n        // Look for revert reason and bubble it up if present\\n        if (returndata.length > 0) {\\n            // The easiest way to bubble the revert reason is using memory via assembly\\n            /// @solidity memory-safe-assembly\\n            assembly {\\n                let returndata_size := mload(returndata)\\n                revert(add(32, returndata), returndata_size)\\n            }\\n        } else {\\n            revert(errorMessage);\\n        }\\n    }\\n}\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n    using Address for address;\\n\\n    function safeTransfer(\\n        IERC20 token,\\n        address to,\\n        uint256 value\\n    ) internal {\\n        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n    }\\n\\n    function safeTransferFrom(\\n        IERC20 token,\\n        address from,\\n        address to,\\n        uint256 value\\n    ) internal {\\n        _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n    }\\n\\n    /**\\n     * @dev Deprecated. This function has issues similar to the ones found in\\n     * {IERC20-approve}, and its usage is discouraged.\\n     *\\n     * Whenever possible, use {safeIncreaseAllowance} and\\n     * {safeDecreaseAllowance} instead.\\n     */\\n    function safeApprove(\\n        IERC20 token,\\n        address spender,\\n        uint256 value\\n    ) internal {\\n        // safeApprove should only be called when setting an initial allowance,\\n        // or when resetting it to zero. To increase and decrease it, use\\n        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n        require(\\n            (value == 0) || (token.allowance(address(this), spender) == 0),\\n            \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n        );\\n        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n    }\\n\\n    function safeIncreaseAllowance(\\n        IERC20 token,\\n        address spender,\\n        uint256 value\\n    ) internal {\\n        uint256 newAllowance = token.allowance(address(this), spender) + value;\\n        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n    }\\n\\n    function safeDecreaseAllowance(\\n        IERC20 token,\\n        address spender,\\n        uint256 value\\n    ) internal {\\n        unchecked {\\n            uint256 oldAllowance = token.allowance(address(this), spender);\\n            require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n            uint256 newAllowance = oldAllowance - value;\\n            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n        }\\n    }\\n\\n    function safePermit(\\n        IERC20Permit token,\\n        address owner,\\n        address spender,\\n        uint256 value,\\n        uint256 deadline,\\n        uint8 v,\\n        bytes32 r,\\n        bytes32 s\\n    ) internal {\\n        uint256 nonceBefore = token.nonces(owner);\\n        token.permit(owner, spender, value, deadline, v, r, s);\\n        uint256 nonceAfter = token.nonces(owner);\\n        require(nonceAfter == nonceBefore + 1, \\\"SafeERC20: permit did not succeed\\\");\\n    }\\n\\n    /**\\n     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n     * on the return value: the return value is optional (but if data is returned, it must not be false).\\n     * @param token The token targeted by the call.\\n     * @param data The call data (encoded using abi.encode or one of its variants).\\n     */\\n    function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n        // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\\n        // the target address contains contract code and also asserts for success in the low-level call.\\n\\n        bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n        if (returndata.length > 0) {\\n            // Return data is optional\\n            require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n        }\\n    }\\n}\\n\\nlibrary Fixed256x18 {\\n    uint256 internal constant ONE = 1e18; // 18 decimal places\\n\\n    function mulDown(uint256 a, uint256 b) internal pure returns (uint256) {\\n        return (a * b) / ONE;\\n    }\\n\\n    function mulUp(uint256 a, uint256 b) internal pure returns (uint256) {\\n        uint256 product = a * b;\\n\\n        if (product == 0) {\\n            return 0;\\n        } else {\\n            return ((product - 1) / ONE) + 1;\\n        }\\n    }\\n\\n    function divDown(uint256 a, uint256 b) internal pure returns (uint256) {\\n        return (a * ONE) / b;\\n    }\\n\\n    function divUp(uint256 a, uint256 b) internal pure returns (uint256) {\\n        if (a == 0) {\\n            return 0;\\n        } else {\\n            return (((a * ONE) - 1) / b) + 1;\\n        }\\n    }\\n\\n    function complement(uint256 x) internal pure returns (uint256) {\\n        return (x < ONE) ? (ONE - x) : 0;\\n    }\\n}\\n\\nlibrary MathUtils {\\n    // --- Constants ---\\n\\n    /// @notice Represents 100%.\\n    /// @dev 1e18 is the scaling factor (100% == 1e18).\\n    uint256 public constant _100_PERCENT = Fixed256x18.ONE;\\n\\n    /// @notice Precision for Nominal ICR (independent of price).\\n    /// @dev Rationale for the value:\\n    /// - Making it “too high” could lead to overflows.\\n    /// - Making it “too low” could lead to an ICR equal to zero, due to truncation from floor division.\\n    ///\\n    /// This value of 1e20 is chosen for safety: the NICR will only overflow for numerator > ~1e39 collateralToken,\\n    /// and will only truncate to 0 if the denominator is at least 1e20 times greater than the numerator.\\n    uint256 internal constant _NICR_PRECISION = 1e20;\\n\\n    /// @notice Number of minutes in 1000 years.\\n    uint256 internal constant _MINUTES_IN_1000_YEARS = 1000 * 365 days / 1 minutes;\\n\\n    // --- Functions ---\\n\\n    /// @notice Multiplies two decimal numbers and use normal rounding rules:\\n    /// - round product up if 19'th mantissa digit >= 5\\n    /// - round product down if 19'th mantissa digit < 5.\\n    /// @param x First number.\\n    /// @param y Second number.\\n    function _decMul(uint256 x, uint256 y) internal pure returns (uint256 decProd) {\\n        decProd = (x * y + Fixed256x18.ONE / 2) / Fixed256x18.ONE;\\n    }\\n\\n    /// @notice Exponentiation function for 18-digit decimal base, and integer exponent n.\\n    ///\\n    /// @dev Uses the efficient \\\"exponentiation by squaring\\\" algorithm. O(log(n)) complexity. The exponent is capped to\\n    /// avoid reverting due to overflow.\\n    ///\\n    /// If a period of > 1000 years is ever used as an exponent in either of the above functions, the result will be\\n    /// negligibly different from just passing the cap, since the decayed base rate will be 0 for 1000 years or > 1000\\n    /// years.\\n    /// @param base The decimal base.\\n    /// @param exponent The exponent.\\n    /// @return The result of the exponentiation.\\n    function _decPow(uint256 base, uint256 exponent) internal pure returns (uint256) {\\n        if (exponent == 0) {\\n            return Fixed256x18.ONE;\\n        }\\n\\n        uint256 y = Fixed256x18.ONE;\\n        uint256 x = base;\\n        uint256 n = Math.min(exponent, _MINUTES_IN_1000_YEARS); // cap to avoid overflow\\n\\n        // Exponentiation-by-squaring\\n        while (n > 1) {\\n            if (n % 2 != 0) {\\n                y = _decMul(x, y);\\n            }\\n            x = _decMul(x, x);\\n            n /= 2;\\n        }\\n\\n        return _decMul(x, y);\\n    }\\n\\n    /// @notice Computes the Nominal Individual Collateral Ratio (NICR) for given collateral and debt. If debt is zero,\\n    /// it returns the maximal value for uint256 (represents \\\"infinite\\\" CR).\\n    /// @param collateral Collateral amount.\\n    /// @param debt Debt amount.\\n    /// @return NICR.\\n    function _computeNominalCR(uint256 collateral, uint256 debt) internal pure returns (uint256) {\\n        return debt > 0 ? collateral * _NICR_PRECISION / debt : type(uint256).max;\\n    }\\n\\n    /// @notice Computes the Collateral Ratio for given collateral, debt and price. If debt is zero, it returns the\\n    /// maximal value for uint256 (represents \\\"infinite\\\" CR).\\n    /// @param collateral Collateral amount.\\n    /// @param debt Debt amount.\\n    /// @param price Collateral price.\\n    /// @return Collateral ratio.\\n    function _computeCR(uint256 collateral, uint256 debt, uint256 price) internal pure returns (uint256) {\\n        return debt > 0 ? collateral * price / debt : type(uint256).max;\\n    }\\n}\\n\\n// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/ERC20.sol)\\n\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n    function _msgSender() internal view virtual returns (address) {\\n        return msg.sender;\\n    }\\n\\n    function _msgData() internal view virtual returns (bytes calldata) {\\n        return msg.data;\\n    }\\n}\\n\\n/**\\n * @dev Implementation of the {IERC20} interface.\\n *\\n * This implementation is agnostic to the way tokens are created. This means\\n * that a supply mechanism has to be added in a derived contract using {_mint}.\\n * For a generic mechanism see {ERC20PresetMinterPauser}.\\n *\\n * TIP: For a detailed writeup see our guide\\n * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How\\n * to implement supply mechanisms].\\n *\\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\\n * instead returning `false` on failure. This behavior is nonetheless\\n * conventional and does not conflict with the expectations of ERC20\\n * applications.\\n *\\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\\n * This allows applications to reconstruct the allowance for all accounts just\\n * by listening to said events. Other implementations of the EIP may not emit\\n * these events, as it isn't required by the specification.\\n *\\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\\n * functions have been added to mitigate the well-known issues around setting\\n * allowances. See {IERC20-approve}.\\n */\\ncontract ERC20 is Context, IERC20, IERC20Metadata {\\n    mapping(address => uint256) private _balances;\\n\\n    mapping(address => mapping(address => uint256)) private _allowances;\\n\\n    uint256 private _totalSupply;\\n\\n    string private _name;\\n    string private _symbol;\\n\\n    /**\\n     * @dev Sets the values for {name} and {symbol}.\\n     *\\n     * The default value of {decimals} is 18. To select a different value for\\n     * {decimals} you should overload it.\\n     *\\n     * All two of these values are immutable: they can only be set once during\\n     * construction.\\n     */\\n    constructor(string memory name_, string memory symbol_) {\\n        _name = name_;\\n        _symbol = symbol_;\\n    }\\n\\n    /**\\n     * @dev Returns the name of the token.\\n     */\\n    function name() public view virtual override returns (string memory) {\\n        return _name;\\n    }\\n\\n    /**\\n     * @dev Returns the symbol of the token, usually a shorter version of the\\n     * name.\\n     */\\n    function symbol() public view virtual override returns (string memory) {\\n        return _symbol;\\n    }\\n\\n    /**\\n     * @dev Returns the number of decimals used to get its user representation.\\n     * For example, if `decimals` equals `2`, a balance of `505` tokens should\\n     * be displayed to a user as `5.05` (`505 / 10 ** 2`).\\n     *\\n     * Tokens usually opt for a value of 18, imitating the relationship between\\n     * Ether and Wei. This is the value {ERC20} uses, unless this function is\\n     * overridden;\\n     *\\n     * NOTE: This information is only used for _display_ purposes: it in\\n     * no way affects any of the arithmetic of the contract, including\\n     * {IERC20-balanceOf} and {IERC20-transfer}.\\n     */\\n    function decimals() public view virtual override returns (uint8) {\\n        return 18;\\n    }\\n\\n    /**\\n     * @dev See {IERC20-totalSupply}.\\n     */\\n    function totalSupply() public view virtual override returns (uint256) {\\n        return _totalSupply;\\n    }\\n\\n    /**\\n     * @dev See {IERC20-balanceOf}.\\n     */\\n    function balanceOf(address account) public view virtual override returns (uint256) {\\n        return _balances[account];\\n    }\\n\\n    /**\\n     * @dev See {IERC20-transfer}.\\n     *\\n     * Requirements:\\n     *\\n     * - `to` cannot be the zero address.\\n     * - the caller must have a balance of at least `amount`.\\n     */\\n    function transfer(address to, uint256 amount) public virtual override returns (bool) {\\n        address owner = _msgSender();\\n        _transfer(owner, to, amount);\\n        return true;\\n    }\\n\\n    /**\\n     * @dev See {IERC20-allowance}.\\n     */\\n    function allowance(address owner, address spender) public view virtual override returns (uint256) {\\n        return _allowances[owner][spender];\\n    }\\n\\n    /**\\n     * @dev See {IERC20-approve}.\\n     *\\n     * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\\n     * `transferFrom`. This is semantically equivalent to an infinite approval.\\n     *\\n     * Requirements:\\n     *\\n     * - `spender` cannot be the zero address.\\n     */\\n    function approve(address spender, uint256 amount) public virtual override returns (bool) {\\n        address owner = _msgSender();\\n        _approve(owner, spender, amount);\\n        return true;\\n    }\\n\\n    /**\\n     * @dev See {IERC20-transferFrom}.\\n     *\\n     * Emits an {Approval} event indicating the updated allowance. This is not\\n     * required by the EIP. See the note at the beginning of {ERC20}.\\n     *\\n     * NOTE: Does not update the allowance if the current allowance\\n     * is the maximum `uint256`.\\n     *\\n     * Requirements:\\n     *\\n     * - `from` and `to` cannot be the zero address.\\n     * - `from` must have a balance of at least `amount`.\\n     * - the caller must have allowance for ``from``'s tokens of at least\\n     * `amount`.\\n     */\\n    function transferFrom(\\n        address from,\\n        address to,\\n        uint256 amount\\n    ) public virtual override returns (bool) {\\n        address spender = _msgSender();\\n        _spendAllowance(from, spender, amount);\\n        _transfer(from, to, amount);\\n        return true;\\n    }\\n\\n    /**\\n     * @dev Atomically increases the allowance granted to `spender` by the caller.\\n     *\\n     * This is an alternative to {approve} that can be used as a mitigation for\\n     * problems described in {IERC20-approve}.\\n     *\\n     * Emits an {Approval} event indicating the updated allowance.\\n     *\\n     * Requirements:\\n     *\\n     * - `spender` cannot be the zero address.\\n     */\\n    function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\\n        address owner = _msgSender();\\n        _approve(owner, spender, allowance(owner, spender) + addedValue);\\n        return true;\\n    }\\n\\n    /**\\n     * @dev Atomically decreases the allowance granted to `spender` by the caller.\\n     *\\n     * This is an alternative to {approve} that can be used as a mitigation for\\n     * problems described in {IERC20-approve}.\\n     *\\n     * Emits an {Approval} event indicating the updated allowance.\\n     *\\n     * Requirements:\\n     *\\n     * - `spender` cannot be the zero address.\\n     * - `spender` must have allowance for the caller of at least\\n     * `subtractedValue`.\\n     */\\n    function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\\n        address owner = _msgSender();\\n        uint256 currentAllowance = allowance(owner, spender);\\n        require(currentAllowance >= subtractedValue, \\\"ERC20: decreased allowance below zero\\\");\\n        unchecked {\\n            _approve(owner, spender, currentAllowance - subtractedValue);\\n        }\\n\\n        return true;\\n    }\\n\\n    /**\\n     * @dev Moves `amount` of tokens from `from` to `to`.\\n     *\\n     * This internal function is equivalent to {transfer}, and can be used to\\n     * e.g. implement automatic token fees, slashing mechanisms, etc.\\n     *\\n     * Emits a {Transfer} event.\\n     *\\n     * Requirements:\\n     *\\n     * - `from` cannot be the zero address.\\n     * - `to` cannot be the zero address.\\n     * - `from` must have a balance of at least `amount`.\\n     */\\n    function _transfer(\\n        address from,\\n        address to,\\n        uint256 amount\\n    ) internal virtual {\\n        require(from != address(0), \\\"ERC20: transfer from the zero address\\\");\\n        require(to != address(0), \\\"ERC20: transfer to the zero address\\\");\\n\\n        _beforeTokenTransfer(from, to, amount);\\n\\n        uint256 fromBalance = _balances[from];\\n        require(fromBalance >= amount, \\\"ERC20: transfer amount exceeds balance\\\");\\n        unchecked {\\n            _balances[from] = fromBalance - amount;\\n            // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by\\n            // decrementing then incrementing.\\n            _balances[to] += amount;\\n        }\\n\\n        emit Transfer(from, to, amount);\\n\\n        _afterTokenTransfer(from, to, amount);\\n    }\\n\\n    /** @dev Creates `amount` tokens and assigns them to `account`, increasing\\n     * the total supply.\\n     *\\n     * Emits a {Transfer} event with `from` set to the zero address.\\n     *\\n     * Requirements:\\n     *\\n     * - `account` cannot be the zero address.\\n     */\\n    function _mint(address account, uint256 amount) internal virtual {\\n        require(account != address(0), \\\"ERC20: mint to the zero address\\\");\\n\\n        _beforeTokenTransfer(address(0), account, amount);\\n\\n        _totalSupply += amount;\\n        unchecked {\\n            // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.\\n            _balances[account] += amount;\\n        }\\n        emit Transfer(address(0), account, amount);\\n\\n        _afterTokenTransfer(address(0), account, amount);\\n    }\\n\\n    /**\\n     * @dev Destroys `amount` tokens from `account`, reducing the\\n     * total supply.\\n     *\\n     * Emits a {Transfer} event with `to` set to the zero address.\\n     *\\n     * Requirements:\\n     *\\n     * - `account` cannot be the zero address.\\n     * - `account` must have at least `amount` tokens.\\n     */\\n    function _burn(address account, uint256 amount) internal virtual {\\n        require(account != address(0), \\\"ERC20: burn from the zero address\\\");\\n\\n        _beforeTokenTransfer(account, address(0), amount);\\n\\n        uint256 accountBalance = _balances[account];\\n        require(accountBalance >= amount, \\\"ERC20: burn amount exceeds balance\\\");\\n        unchecked {\\n            _balances[account] = accountBalance - amount;\\n            // Overflow not possible: amount <= accountBalance <= totalSupply.\\n            _totalSupply -= amount;\\n        }\\n\\n        emit Transfer(account, address(0), amount);\\n\\n        _afterTokenTransfer(account, address(0), amount);\\n    }\\n\\n    /**\\n     * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\\n     *\\n     * This internal function is equivalent to `approve`, and can be used to\\n     * e.g. set automatic allowances for certain subsystems, etc.\\n     *\\n     * Emits an {Approval} event.\\n     *\\n     * Requirements:\\n     *\\n     * - `owner` cannot be the zero address.\\n     * - `spender` cannot be the zero address.\\n     */\\n    function _approve(\\n        address owner,\\n        address spender,\\n        uint256 amount\\n    ) internal virtual {\\n        require(owner != address(0), \\\"ERC20: approve from the zero address\\\");\\n        require(spender != address(0), \\\"ERC20: approve to the zero address\\\");\\n\\n        _allowances[owner][spender] = amount;\\n        emit Approval(owner, spender, amount);\\n    }\\n\\n    /**\\n     * @dev Updates `owner` s allowance for `spender` based on spent `amount`.\\n     *\\n     * Does not update the allowance amount in case of infinite allowance.\\n     * Revert if not enough allowance is available.\\n     *\\n     * Might emit an {Approval} event.\\n     */\\n    function _spendAllowance(\\n        address owner,\\n        address spender,\\n        uint256 amount\\n    ) internal virtual {\\n        uint256 currentAllowance = allowance(owner, spender);\\n        if (currentAllowance != type(uint256).max) {\\n            require(currentAllowance >= amount, \\\"ERC20: insufficient allowance\\\");\\n            unchecked {\\n                _approve(owner, spender, currentAllowance - amount);\\n            }\\n        }\\n    }\\n\\n    /**\\n     * @dev Hook that is called before any transfer of tokens. This includes\\n     * minting and burning.\\n     *\\n     * Calling conditions:\\n     *\\n     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n     * will be transferred to `to`.\\n     * - when `from` is zero, `amount` tokens will be minted for `to`.\\n     * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\\n     * - `from` and `to` are never both zero.\\n     *\\n     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n     */\\n    function _beforeTokenTransfer(\\n        address from,\\n        address to,\\n        uint256 amount\\n    ) internal virtual {}\\n\\n    /**\\n     * @dev Hook that is called after any transfer of tokens. This includes\\n     * minting and burning.\\n     *\\n     * Calling conditions:\\n     *\\n     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n     * has been transferred to `to`.\\n     * - when `from` is zero, `amount` tokens have been minted for `to`.\\n     * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\\n     * - `from` and `to` are never both zero.\\n     *\\n     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n     */\\n    function _afterTokenTransfer(\\n        address from,\\n        address to,\\n        uint256 amount\\n    ) internal virtual {}\\n}\\n\\n// OpenZeppelin Contracts (last updated v4.8.0) (access/Ownable2Step.sol)\\n\\n// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * By default, the owner account will be the one that deploys the contract. This\\n * can later be changed with {transferOwnership}.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\nabstract contract Ownable is Context {\\n    address private _owner;\\n\\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n    /**\\n     * @dev Initializes the contract setting the deployer as the initial owner.\\n     */\\n    constructor() {\\n        _transferOwnership(_msgSender());\\n    }\\n\\n    /**\\n     * @dev Throws if called by any account other than the owner.\\n     */\\n    modifier onlyOwner() {\\n        _checkOwner();\\n        _;\\n    }\\n\\n    /**\\n     * @dev Returns the address of the current owner.\\n     */\\n    function owner() public view virtual returns (address) {\\n        return _owner;\\n    }\\n\\n    /**\\n     * @dev Throws if the sender is not the owner.\\n     */\\n    function _checkOwner() internal view virtual {\\n        require(owner() == _msgSender(), \\\"Ownable: caller is not the owner\\\");\\n    }\\n\\n    /**\\n     * @dev Leaves the contract without owner. It will not be possible to call\\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\\n     *\\n     * NOTE: Renouncing ownership will leave the contract without an owner,\\n     * thereby removing any functionality that is only available to the owner.\\n     */\\n    function renounceOwnership() public virtual onlyOwner {\\n        _transferOwnership(address(0));\\n    }\\n\\n    /**\\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n     * Can only be called by the current owner.\\n     */\\n    function transferOwnership(address newOwner) public virtual onlyOwner {\\n        require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n        _transferOwnership(newOwner);\\n    }\\n\\n    /**\\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n     * Internal function without access restriction.\\n     */\\n    function _transferOwnership(address newOwner) internal virtual {\\n        address oldOwner = _owner;\\n        _owner = newOwner;\\n        emit OwnershipTransferred(oldOwner, newOwner);\\n    }\\n}\\n\\n/**\\n * @dev Contract module which provides access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * By default, the owner account will be the one that deploys the contract. This\\n * can later be changed with {transferOwnership} and {acceptOwnership}.\\n *\\n * This module is used through inheritance. It will make available all functions\\n * from parent (Ownable).\\n */\\nabstract contract Ownable2Step is Ownable {\\n    address private _pendingOwner;\\n\\n    event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);\\n\\n    /**\\n     * @dev Returns the address of the pending owner.\\n     */\\n    function pendingOwner() public view virtual returns (address) {\\n        return _pendingOwner;\\n    }\\n\\n    /**\\n     * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.\\n     * Can only be called by the current owner.\\n     */\\n    function transferOwnership(address newOwner) public virtual override onlyOwner {\\n        _pendingOwner = newOwner;\\n        emit OwnershipTransferStarted(owner(), newOwner);\\n    }\\n\\n    /**\\n     * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.\\n     * Internal function without access restriction.\\n     */\\n    function _transferOwnership(address newOwner) internal virtual override {\\n        delete _pendingOwner;\\n        super._transferOwnership(newOwner);\\n    }\\n\\n    /**\\n     * @dev The new owner accepts the ownership transfer.\\n     */\\n    function acceptOwnership() external {\\n        address sender = _msgSender();\\n        require(pendingOwner() == sender, \\\"Ownable2Step: caller is not the new owner\\\");\\n        _transferOwnership(sender);\\n    }\\n}\\n\\n/**\\n * @dev Extension of {ERC20} that adds a cap to the supply of tokens.\\n */\\nabstract contract ERC20Capped is ERC20, Ownable2Step {\\n    uint256 public cap;\\n\\n    /**\\n     * @dev Total supply cap has been exceeded.\\n     */\\n    error ERC20ExceededCap();\\n\\n    /**\\n     * @dev The supplied cap is not a valid cap.\\n     */\\n    error ERC20InvalidCap(uint256 cap);\\n\\n    constructor(uint256 cap_) {\\n        setCap(cap_);\\n    }\\n\\n    /**\\n     * @dev Sets the value of the `cap`.\\n     */\\n    function setCap(uint256 cap_) public onlyOwner {\\n        if (cap_ == 0) {\\n            revert ERC20InvalidCap(0);\\n        }\\n        cap = cap_;\\n    }\\n\\n    /**\\n     * @dev See {ERC20-_mint}.\\n     */\\n    function _mint(address account, uint256 amount) internal virtual override {\\n        if (totalSupply() + amount > cap) {\\n            revert ERC20ExceededCap();\\n        }\\n        super._mint(account, amount);\\n    }\\n}\\n\\nabstract contract PositionManagerDependent is IPositionManagerDependent {\\n    // --- Immutable variables ---\\n\\n    address public immutable override positionManager;\\n\\n    // --- Modifiers ---\\n\\n    modifier onlyPositionManager() {\\n        if (msg.sender != positionManager) {\\n            revert CallerIsNotPositionManager(msg.sender);\\n        }\\n        _;\\n    }\\n\\n    // --- Constructor ---\\n\\n    constructor(address positionManager_) {\\n        if (positionManager_ == address(0)) {\\n            revert PositionManagerCannotBeZero();\\n        }\\n        positionManager = positionManager_;\\n    }\\n}\\n\\ncontract ERC20Indexable is IERC20Indexable, ERC20Capped, PositionManagerDependent {\\n    // --- Types ---\\n\\n    using Fixed256x18 for uint256;\\n\\n    // --- Constants ---\\n\\n    uint256 public constant override INDEX_PRECISION = Fixed256x18.ONE;\\n\\n    // --- Variables ---\\n\\n    uint256 internal storedIndex;\\n\\n    // --- Constructor ---\\n\\n    constructor(\\n        address positionManager_,\\n        string memory name_,\\n        string memory symbol_,\\n        uint256 cap_\\n    )\\n        ERC20(name_, symbol_)\\n        ERC20Capped(cap_)\\n        PositionManagerDependent(positionManager_)\\n    {\\n        storedIndex = INDEX_PRECISION;\\n        emit ERC20IndexableDeployed(positionManager_);\\n    }\\n\\n    // --- Functions ---\\n\\n    function mint(address to, uint256 amount) public virtual override onlyPositionManager {\\n        _mint(to, amount.divUp(storedIndex));\\n    }\\n\\n    function burn(address from, uint256 amount) public virtual override onlyPositionManager {\\n        _burn(from, amount == type(uint256).max ? ERC20.balanceOf(from) : amount.divUp(storedIndex));\\n    }\\n\\n    function setIndex(uint256 backingAmount) external override onlyPositionManager {\\n        uint256 supply = ERC20.totalSupply();\\n        uint256 newIndex = (backingAmount == 0 && supply == 0) ? INDEX_PRECISION : backingAmount.divUp(supply);\\n        storedIndex = newIndex;\\n        emit IndexUpdated(newIndex);\\n    }\\n\\n    function currentIndex() public view virtual override returns (uint256) {\\n        return storedIndex;\\n    }\\n\\n    function totalSupply() public view virtual override(IERC20, ERC20) returns (uint256) {\\n        return ERC20.totalSupply().mulDown(currentIndex());\\n    }\\n\\n    function balanceOf(address account) public view virtual override(IERC20, ERC20) returns (uint256) {\\n        return ERC20.balanceOf(account).mulDown(currentIndex());\\n    }\\n\\n    function transfer(address, uint256) public virtual override(IERC20, ERC20) returns (bool) {\\n        revert NotSupported();\\n    }\\n\\n    function allowance(address, address) public view virtual override(IERC20, ERC20) returns (uint256) {\\n        revert NotSupported();\\n    }\\n\\n    function approve(address, uint256) public virtual override(IERC20, ERC20) returns (bool) {\\n        revert NotSupported();\\n    }\\n\\n    function transferFrom(address, address, uint256) public virtual override(IERC20, ERC20) returns (bool) {\\n        revert NotSupported();\\n    }\\n\\n    function increaseAllowance(address, uint256) public virtual override returns (bool) {\\n        revert NotSupported();\\n    }\\n\\n    function decreaseAllowance(address, uint256) public virtual override returns (bool) {\\n        revert NotSupported();\\n    }\\n}\\n\\nabstract contract FeeCollector is Ownable2Step, IFeeCollector {\\n    // --- Variables ---\\n\\n    address public override feeRecipient;\\n\\n    // --- Constructor ---\\n\\n    /// @param feeRecipient_ Address of the fee recipient to initialize contract with.\\n    constructor(address feeRecipient_) {\\n        if (feeRecipient_ == address(0)) {\\n            revert InvalidFeeRecipient();\\n        }\\n\\n        feeRecipient = feeRecipient_;\\n    }\\n\\n    // --- Functions ---\\n\\n    function setFeeRecipient(address newFeeRecipient) external onlyOwner {\\n        if (newFeeRecipient == address(0)) {\\n            revert InvalidFeeRecipient();\\n        }\\n\\n        feeRecipient = newFeeRecipient;\\n        emit FeeRecipientChanged(newFeeRecipient);\\n    }\\n}\\n\\n// OpenZeppelin Contracts (last updated v4.8.0) (security/ReentrancyGuard.sol)\\n\\n/**\\n * @dev Contract module that helps prevent reentrant calls to a function.\\n *\\n * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier\\n * available, which can be applied to functions to make sure there are no nested\\n * (reentrant) calls to them.\\n *\\n * Note that because there is a single `nonReentrant` guard, functions marked as\\n * `nonReentrant` may not call one another. This can be worked around by making\\n * those functions `private`, and then adding `external` `nonReentrant` entry\\n * points to them.\\n *\\n * TIP: If you would like to learn more about reentrancy and alternative ways\\n * to protect against it, check out our blog post\\n * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].\\n */\\nabstract contract ReentrancyGuard {\\n    // Booleans are more expensive than uint256 or any type that takes up a full\\n    // word because each write operation emits an extra SLOAD to first read the\\n    // slot's contents, replace the bits taken up by the boolean, and then write\\n    // back. This is the compiler's defense against contract upgrades and\\n    // pointer aliasing, and it cannot be disabled.\\n\\n    // The values being non-zero value makes deployment a bit more expensive,\\n    // but in exchange the refund on every call to nonReentrant will be lower in\\n    // amount. Since refunds are capped to a percentage of the total\\n    // transaction's gas, it is best to keep them low in cases like this one, to\\n    // increase the likelihood of the full refund coming into effect.\\n    uint256 private constant _NOT_ENTERED = 1;\\n    uint256 private constant _ENTERED = 2;\\n\\n    uint256 private _status;\\n\\n    constructor() {\\n        _status = _NOT_ENTERED;\\n    }\\n\\n    /**\\n     * @dev Prevents a contract from calling itself, directly or indirectly.\\n     * Calling a `nonReentrant` function from another `nonReentrant`\\n     * function is not supported. It is possible to prevent this from happening\\n     * by making the `nonReentrant` function external, and making it call a\\n     * `private` function that does the actual work.\\n     */\\n    modifier nonReentrant() {\\n        _nonReentrantBefore();\\n        _;\\n        _nonReentrantAfter();\\n    }\\n\\n    function _nonReentrantBefore() private {\\n        // On the first call to nonReentrant, _status will be _NOT_ENTERED\\n        require(_status != _ENTERED, \\\"ReentrancyGuard: reentrant call\\\");\\n\\n        // Any calls to nonReentrant after this point will fail\\n        _status = _ENTERED;\\n    }\\n\\n    function _nonReentrantAfter() private {\\n        // By storing the original value once again, a refund is triggered (see\\n        // https://eips.ethereum.org/EIPS/eip-2200)\\n        _status = _NOT_ENTERED;\\n    }\\n}\\n\\n// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/extensions/draft-ERC20Permit.sol)\\n\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/ECDSA.sol)\\n\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol)\\n\\n/**\\n * @dev String operations.\\n */\\nlibrary Strings {\\n    bytes16 private constant _SYMBOLS = \\\"0123456789abcdef\\\";\\n    uint8 private constant _ADDRESS_LENGTH = 20;\\n\\n    /**\\n     * @dev Converts a `uint256` to its ASCII `string` decimal representation.\\n     */\\n    function toString(uint256 value) internal pure returns (string memory) {\\n        unchecked {\\n            uint256 length = Math.log10(value) + 1;\\n            string memory buffer = new string(length);\\n            uint256 ptr;\\n            /// @solidity memory-safe-assembly\\n            assembly {\\n                ptr := add(buffer, add(32, length))\\n            }\\n            while (true) {\\n                ptr--;\\n                /// @solidity memory-safe-assembly\\n                assembly {\\n                    mstore8(ptr, byte(mod(value, 10), _SYMBOLS))\\n                }\\n                value /= 10;\\n                if (value == 0) break;\\n            }\\n            return buffer;\\n        }\\n    }\\n\\n    /**\\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\\n     */\\n    function toHexString(uint256 value) internal pure returns (string memory) {\\n        unchecked {\\n            return toHexString(value, Math.log256(value) + 1);\\n        }\\n    }\\n\\n    /**\\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\\n     */\\n    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\\n        bytes memory buffer = new bytes(2 * length + 2);\\n        buffer[0] = \\\"0\\\";\\n        buffer[1] = \\\"x\\\";\\n        for (uint256 i = 2 * length + 1; i > 1; --i) {\\n            buffer[i] = _SYMBOLS[value & 0xf];\\n            value >>= 4;\\n        }\\n        require(value == 0, \\\"Strings: hex length insufficient\\\");\\n        return string(buffer);\\n    }\\n\\n    /**\\n     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\\n     */\\n    function toHexString(address addr) internal pure returns (string memory) {\\n        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\\n    }\\n}\\n\\n/**\\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\\n *\\n * These functions can be used to verify that a message was signed by the holder\\n * of the private keys of a given address.\\n */\\nlibrary ECDSA {\\n    enum RecoverError {\\n        NoError,\\n        InvalidSignature,\\n        InvalidSignatureLength,\\n        InvalidSignatureS,\\n        InvalidSignatureV // Deprecated in v4.8\\n    }\\n\\n    function _throwError(RecoverError error) private pure {\\n        if (error == RecoverError.NoError) {\\n            return; // no error: do nothing\\n        } else if (error == RecoverError.InvalidSignature) {\\n            revert(\\\"ECDSA: invalid signature\\\");\\n        } else if (error == RecoverError.InvalidSignatureLength) {\\n            revert(\\\"ECDSA: invalid signature length\\\");\\n        } else if (error == RecoverError.InvalidSignatureS) {\\n            revert(\\\"ECDSA: invalid signature 's' value\\\");\\n        }\\n    }\\n\\n    /**\\n     * @dev Returns the address that signed a hashed message (`hash`) with\\n     * `signature` or error string. This address can then be used for verification purposes.\\n     *\\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n     * this function rejects them by requiring the `s` value to be in the lower\\n     * half order, and the `v` value to be either 27 or 28.\\n     *\\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n     * verification to be secure: it is possible to craft signatures that\\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n     * this is by receiving a hash of the original message (which may otherwise\\n     * be too long), and then calling {toEthSignedMessageHash} on it.\\n     *\\n     * Documentation for signature generation:\\n     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\\n     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\\n     *\\n     * _Available since v4.3._\\n     */\\n    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\\n        if (signature.length == 65) {\\n            bytes32 r;\\n            bytes32 s;\\n            uint8 v;\\n            // ecrecover takes the signature parameters, and the only way to get them\\n            // currently is to use assembly.\\n            /// @solidity memory-safe-assembly\\n            assembly {\\n                r := mload(add(signature, 0x20))\\n                s := mload(add(signature, 0x40))\\n                v := byte(0, mload(add(signature, 0x60)))\\n            }\\n            return tryRecover(hash, v, r, s);\\n        } else {\\n            return (address(0), RecoverError.InvalidSignatureLength);\\n        }\\n    }\\n\\n    /**\\n     * @dev Returns the address that signed a hashed message (`hash`) with\\n     * `signature`. This address can then be used for verification purposes.\\n     *\\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n     * this function rejects them by requiring the `s` value to be in the lower\\n     * half order, and the `v` value to be either 27 or 28.\\n     *\\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n     * verification to be secure: it is possible to craft signatures that\\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n     * this is by receiving a hash of the original message (which may otherwise\\n     * be too long), and then calling {toEthSignedMessageHash} on it.\\n     */\\n    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\\n        (address recovered, RecoverError error) = tryRecover(hash, signature);\\n        _throwError(error);\\n        return recovered;\\n    }\\n\\n    /**\\n     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\\n     *\\n     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\\n     *\\n     * _Available since v4.3._\\n     */\\n    function tryRecover(\\n        bytes32 hash,\\n        bytes32 r,\\n        bytes32 vs\\n    ) internal pure returns (address, RecoverError) {\\n        bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\\n        uint8 v = uint8((uint256(vs) >> 255) + 27);\\n        return tryRecover(hash, v, r, s);\\n    }\\n\\n    /**\\n     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\\n     *\\n     * _Available since v4.2._\\n     */\\n    function recover(\\n        bytes32 hash,\\n        bytes32 r,\\n        bytes32 vs\\n    ) internal pure returns (address) {\\n        (address recovered, RecoverError error) = tryRecover(hash, r, vs);\\n        _throwError(error);\\n        return recovered;\\n    }\\n\\n    /**\\n     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\\n     * `r` and `s` signature fields separately.\\n     *\\n     * _Available since v4.3._\\n     */\\n    function tryRecover(\\n        bytes32 hash,\\n        uint8 v,\\n        bytes32 r,\\n        bytes32 s\\n    ) internal pure returns (address, RecoverError) {\\n        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\\n        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\\n        // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\\n        // signatures from current libraries generate a unique signature with an s-value in the lower half order.\\n        //\\n        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\\n        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\\n        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\\n        // these malleable signatures as well.\\n        if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\\n            return (address(0), RecoverError.InvalidSignatureS);\\n        }\\n\\n        // If the signature is valid (and not malleable), return the signer address\\n        address signer = ecrecover(hash, v, r, s);\\n        if (signer == address(0)) {\\n            return (address(0), RecoverError.InvalidSignature);\\n        }\\n\\n        return (signer, RecoverError.NoError);\\n    }\\n\\n    /**\\n     * @dev Overload of {ECDSA-recover} that receives the `v`,\\n     * `r` and `s` signature fields separately.\\n     */\\n    function recover(\\n        bytes32 hash,\\n        uint8 v,\\n        bytes32 r,\\n        bytes32 s\\n    ) internal pure returns (address) {\\n        (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\\n        _throwError(error);\\n        return recovered;\\n    }\\n\\n    /**\\n     * @dev Returns an Ethereum Signed Message, created from a `hash`. This\\n     * produces hash corresponding to the one signed with the\\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n     * JSON-RPC method as part of EIP-191.\\n     *\\n     * See {recover}.\\n     */\\n    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\\n        // 32 is the length in bytes of hash,\\n        // enforced by the type signature above\\n        return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n32\\\", hash));\\n    }\\n\\n    /**\\n     * @dev Returns an Ethereum Signed Message, created from `s`. This\\n     * produces hash corresponding to the one signed with the\\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n     * JSON-RPC method as part of EIP-191.\\n     *\\n     * See {recover}.\\n     */\\n    function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\\n        return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n\\\", Strings.toString(s.length), s));\\n    }\\n\\n    /**\\n     * @dev Returns an Ethereum Signed Typed Data, created from a\\n     * `domainSeparator` and a `structHash`. This produces hash corresponding\\n     * to the one signed with the\\n     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\\n     * JSON-RPC method as part of EIP-712.\\n     *\\n     * See {recover}.\\n     */\\n    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\\n        return keccak256(abi.encodePacked(\\\"\\\\x19\\\\x01\\\", domainSeparator, structHash));\\n    }\\n}\\n\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/EIP712.sol)\\n\\n/**\\n * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.\\n *\\n * The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible,\\n * thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding\\n * they need in their contracts using a combination of `abi.encode` and `keccak256`.\\n *\\n * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding\\n * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA\\n * ({_hashTypedDataV4}).\\n *\\n * The implementation of the domain separator was designed to be as efficient as possible while still properly updating\\n * the chain id to protect against replay attacks on an eventual fork of the chain.\\n *\\n * NOTE: This contract implements the version of the encoding known as \\\"v4\\\", as implemented by the JSON RPC method\\n * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].\\n *\\n * _Available since v3.4._\\n */\\nabstract contract EIP712 {\\n    /* solhint-disable var-name-mixedcase */\\n    // Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to\\n    // invalidate the cached domain separator if the chain id changes.\\n    bytes32 private immutable _CACHED_DOMAIN_SEPARATOR;\\n    uint256 private immutable _CACHED_CHAIN_ID;\\n    address private immutable _CACHED_THIS;\\n\\n    bytes32 private immutable _HASHED_NAME;\\n    bytes32 private immutable _HASHED_VERSION;\\n    bytes32 private immutable _TYPE_HASH;\\n\\n    /* solhint-enable var-name-mixedcase */\\n\\n    /**\\n     * @dev Initializes the domain separator and parameter caches.\\n     *\\n     * The meaning of `name` and `version` is specified in\\n     * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:\\n     *\\n     * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.\\n     * - `version`: the current major version of the signing domain.\\n     *\\n     * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart\\n     * contract upgrade].\\n     */\\n    constructor(string memory name, string memory version) {\\n        bytes32 hashedName = keccak256(bytes(name));\\n        bytes32 hashedVersion = keccak256(bytes(version));\\n        bytes32 typeHash = keccak256(\\n            \\\"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)\\\"\\n        );\\n        _HASHED_NAME = hashedName;\\n        _HASHED_VERSION = hashedVersion;\\n        _CACHED_CHAIN_ID = block.chainid;\\n        _CACHED_DOMAIN_SEPARATOR = _buildDomainSeparator(typeHash, hashedName, hashedVersion);\\n        _CACHED_THIS = address(this);\\n        _TYPE_HASH = typeHash;\\n    }\\n\\n    /**\\n     * @dev Returns the domain separator for the current chain.\\n     */\\n    function _domainSeparatorV4() internal view returns (bytes32) {\\n        if (address(this) == _CACHED_THIS && block.chainid == _CACHED_CHAIN_ID) {\\n            return _CACHED_DOMAIN_SEPARATOR;\\n        } else {\\n            return _buildDomainSeparator(_TYPE_HASH, _HASHED_NAME, _HASHED_VERSION);\\n        }\\n    }\\n\\n    function _buildDomainSeparator(\\n        bytes32 typeHash,\\n        bytes32 nameHash,\\n        bytes32 versionHash\\n    ) private view returns (bytes32) {\\n        return keccak256(abi.encode(typeHash, nameHash, versionHash, block.chainid, address(this)));\\n    }\\n\\n    /**\\n     * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this\\n     * function returns the hash of the fully encoded EIP712 message for this domain.\\n     *\\n     * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:\\n     *\\n     * ```solidity\\n     * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(\\n     *     keccak256(\\\"Mail(address to,string contents)\\\"),\\n     *     mailTo,\\n     *     keccak256(bytes(mailContents))\\n     * )));\\n     * address signer = ECDSA.recover(digest, signature);\\n     * ```\\n     */\\n    function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {\\n        return ECDSA.toTypedDataHash(_domainSeparatorV4(), structHash);\\n    }\\n}\\n\\n// OpenZeppelin Contracts v4.4.1 (utils/Counters.sol)\\n\\n/**\\n * @title Counters\\n * @author Matt Condon (@shrugs)\\n * @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number\\n * of elements in a mapping, issuing ERC721 ids, or counting request ids.\\n *\\n * Include with `using Counters for Counters.Counter;`\\n */\\nlibrary Counters {\\n    struct Counter {\\n        // This variable should never be directly accessed by users of the library: interactions must be restricted to\\n        // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add\\n        // this feature: see https://github.com/ethereum/solidity/issues/4637\\n        uint256 _value; // default: 0\\n    }\\n\\n    function current(Counter storage counter) internal view returns (uint256) {\\n        return counter._value;\\n    }\\n\\n    function increment(Counter storage counter) internal {\\n        unchecked {\\n            counter._value += 1;\\n        }\\n    }\\n\\n    function decrement(Counter storage counter) internal {\\n        uint256 value = counter._value;\\n        require(value > 0, \\\"Counter: decrement overflow\\\");\\n        unchecked {\\n            counter._value = value - 1;\\n        }\\n    }\\n\\n    function reset(Counter storage counter) internal {\\n        counter._value = 0;\\n    }\\n}\\n\\n/**\\n * @dev Implementation of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\\n *\\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\\n * presenting a message signed by the account. By not relying on `{IERC20-approve}`, the token holder account doesn't\\n * need to send a transaction, and thus is not required to hold Ether at all.\\n *\\n * _Available since v3.4._\\n */\\nabstract contract ERC20Permit is ERC20, IERC20Permit, EIP712 {\\n    using Counters for Counters.Counter;\\n\\n    mapping(address => Counters.Counter) private _nonces;\\n\\n    // solhint-disable-next-line var-name-mixedcase\\n    bytes32 private constant _PERMIT_TYPEHASH =\\n        keccak256(\\\"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)\\\");\\n    /**\\n     * @dev In previous versions `_PERMIT_TYPEHASH` was declared as `immutable`.\\n     * However, to ensure consistency with the upgradeable transpiler, we will continue\\n     * to reserve a slot.\\n     * @custom:oz-renamed-from _PERMIT_TYPEHASH\\n     */\\n    // solhint-disable-next-line var-name-mixedcase\\n    bytes32 private _PERMIT_TYPEHASH_DEPRECATED_SLOT;\\n\\n    /**\\n     * @dev Initializes the {EIP712} domain separator using the `name` parameter, and setting `version` to `\\\"1\\\"`.\\n     *\\n     * It's a good idea to use the same `name` that is defined as the ERC20 token name.\\n     */\\n    constructor(string memory name) EIP712(name, \\\"1\\\") {}\\n\\n    /**\\n     * @dev See {IERC20Permit-permit}.\\n     */\\n    function permit(\\n        address owner,\\n        address spender,\\n        uint256 value,\\n        uint256 deadline,\\n        uint8 v,\\n        bytes32 r,\\n        bytes32 s\\n    ) public virtual override {\\n        require(block.timestamp <= deadline, \\\"ERC20Permit: expired deadline\\\");\\n\\n        bytes32 structHash = keccak256(abi.encode(_PERMIT_TYPEHASH, owner, spender, value, _useNonce(owner), deadline));\\n\\n        bytes32 hash = _hashTypedDataV4(structHash);\\n\\n        address signer = ECDSA.recover(hash, v, r, s);\\n        require(signer == owner, \\\"ERC20Permit: invalid signature\\\");\\n\\n        _approve(owner, spender, value);\\n    }\\n\\n    /**\\n     * @dev See {IERC20Permit-nonces}.\\n     */\\n    function nonces(address owner) public view virtual override returns (uint256) {\\n        return _nonces[owner].current();\\n    }\\n\\n    /**\\n     * @dev See {IERC20Permit-DOMAIN_SEPARATOR}.\\n     */\\n    // solhint-disable-next-line func-name-mixedcase\\n    function DOMAIN_SEPARATOR() external view override returns (bytes32) {\\n        return _domainSeparatorV4();\\n    }\\n\\n    /**\\n     * @dev \\\"Consume a nonce\\\": return the current value and increment.\\n     *\\n     * _Available since v4.1._\\n     */\\n    function _useNonce(address owner) internal virtual returns (uint256 current) {\\n        Counters.Counter storage nonce = _nonces[owner];\\n        current = nonce.current();\\n        nonce.increment();\\n    }\\n}\\n\\n// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/extensions/ERC20FlashMint.sol)\\n\\n/**\\n * @dev Implementation of the ERC3156 Flash loans extension, as defined in\\n * https://eips.ethereum.org/EIPS/eip-3156[ERC-3156].\\n *\\n * Adds the {flashLoan} method, which provides flash loan support at the token\\n * level. By default there is no fee, but this can be changed by overriding {flashFee}.\\n *\\n * _Available since v4.1._\\n */\\nabstract contract ERC20FlashMint is ERC20, IERC3156FlashLender {\\n    bytes32 private constant _RETURN_VALUE = keccak256(\\\"ERC3156FlashBorrower.onFlashLoan\\\");\\n\\n    /**\\n     * @dev Returns the maximum amount of tokens available for loan.\\n     * @param token The address of the token that is requested.\\n     * @return The amount of token that can be loaned.\\n     */\\n    function maxFlashLoan(address token) public view virtual override returns (uint256) {\\n        return token == address(this) ? type(uint256).max - ERC20.totalSupply() : 0;\\n    }\\n\\n    /**\\n     * @dev Returns the fee applied when doing flash loans. This function calls\\n     * the {_flashFee} function which returns the fee applied when doing flash\\n     * loans.\\n     * @param token The token to be flash loaned.\\n     * @param amount The amount of tokens to be loaned.\\n     * @return The fees applied to the corresponding flash loan.\\n     */\\n    function flashFee(address token, uint256 amount) public view virtual override returns (uint256) {\\n        require(token == address(this), \\\"ERC20FlashMint: wrong token\\\");\\n        return _flashFee(token, amount);\\n    }\\n\\n    /**\\n     * @dev Returns the fee applied when doing flash loans. By default this\\n     * implementation has 0 fees. This function can be overloaded to make\\n     * the flash loan mechanism deflationary.\\n     * @param token The token to be flash loaned.\\n     * @param amount The amount of tokens to be loaned.\\n     * @return The fees applied to the corresponding flash loan.\\n     */\\n    function _flashFee(address token, uint256 amount) internal view virtual returns (uint256) {\\n        // silence warning about unused variable without the addition of bytecode.\\n        token;\\n        amount;\\n        return 0;\\n    }\\n\\n    /**\\n     * @dev Returns the receiver address of the flash fee. By default this\\n     * implementation returns the address(0) which means the fee amount will be burnt.\\n     * This function can be overloaded to change the fee receiver.\\n     * @return The address for which the flash fee will be sent to.\\n     */\\n    function _flashFeeReceiver() internal view virtual returns (address) {\\n        return address(0);\\n    }\\n\\n    /**\\n     * @dev Performs a flash loan. New tokens are minted and sent to the\\n     * `receiver`, who is required to implement the {IERC3156FlashBorrower}\\n     * interface. By the end of the flash loan, the receiver is expected to own\\n     * amount + fee tokens and have them approved back to the token contract itself so\\n     * they can be burned.\\n     * @param receiver The receiver of the flash loan. Should implement the\\n     * {IERC3156FlashBorrower-onFlashLoan} interface.\\n     * @param token The token to be flash loaned. Only `address(this)` is\\n     * supported.\\n     * @param amount The amount of tokens to be loaned.\\n     * @param data An arbitrary datafield that is passed to the receiver.\\n     * @return `true` if the flash loan was successful.\\n     */\\n    // This function can reenter, but it doesn't pose a risk because it always preserves the property that the amount\\n    // minted at the beginning is always recovered and burned at the end, or else the entire function will revert.\\n    // slither-disable-next-line reentrancy-no-eth\\n    function flashLoan(\\n        IERC3156FlashBorrower receiver,\\n        address token,\\n        uint256 amount,\\n        bytes calldata data\\n    ) public virtual override returns (bool) {\\n        require(amount <= maxFlashLoan(token), \\\"ERC20FlashMint: amount exceeds maxFlashLoan\\\");\\n        uint256 fee = flashFee(token, amount);\\n        _mint(address(receiver), amount);\\n        require(\\n            receiver.onFlashLoan(msg.sender, token, amount, fee, data) == _RETURN_VALUE,\\n            \\\"ERC20FlashMint: invalid return value\\\"\\n        );\\n        address flashFeeReceiver = _flashFeeReceiver();\\n        _spendAllowance(address(receiver), address(this), amount + fee);\\n        if (fee == 0 || flashFeeReceiver == address(0)) {\\n            _burn(address(receiver), amount + fee);\\n        } else {\\n            _burn(address(receiver), amount);\\n            _transfer(address(receiver), flashFeeReceiver, fee);\\n        }\\n        return true;\\n    }\\n}\\n\\ncontract RToken is ReentrancyGuard, ERC20Permit, ERC20FlashMint, PositionManagerDependent, FeeCollector, IRToken {\\n    // --- Constants ---\\n\\n    uint256 public constant override PERCENTAGE_BASE = 10_000;\\n    uint256 public constant override MAX_FLASH_MINT_FEE_PERCENTAGE = 500;\\n\\n    // --- Variables ---\\n\\n    uint256 public override flashMintFeePercentage;\\n\\n    // --- Constructor ---\\n\\n    /// @dev Deploys new R token. Sets flash mint fee percentage to 0. Transfers ownership to @param feeRecipient_.\\n    /// @param positionManager_ Address of the PositionManager contract that is authorized to mint and burn new tokens.\\n    /// @param feeRecipient_ Address of flash mint fee recipient.\\n    constructor(\\n        address positionManager_,\\n        address feeRecipient_\\n    )\\n        ERC20Permit(\\\"R Stablecoin\\\")\\n        ERC20(\\\"R Stablecoin\\\", \\\"R\\\")\\n        PositionManagerDependent(positionManager_)\\n        FeeCollector(feeRecipient_)\\n    {\\n        setFlashMintFeePercentage(PERCENTAGE_BASE / 200); // 0.5%\\n\\n        transferOwnership(feeRecipient_);\\n\\n        emit RDeployed(positionManager_, feeRecipient_);\\n    }\\n\\n    // --- Functions ---\\n\\n    function mint(address to, uint256 amount) external override onlyPositionManager {\\n        _mint(to, amount);\\n    }\\n\\n    function burn(address from, uint256 amount) external override onlyPositionManager {\\n        _burn(from, amount);\\n    }\\n\\n    function setFlashMintFeePercentage(uint256 feePercentage) public override onlyOwner {\\n        if (feePercentage > MAX_FLASH_MINT_FEE_PERCENTAGE) {\\n            revert FlashFeePercentageTooBig(feePercentage);\\n        }\\n\\n        flashMintFeePercentage = feePercentage;\\n        emit FlashMintFeePercentageChanged(flashMintFeePercentage);\\n    }\\n\\n    function flashLoan(\\n        IERC3156FlashBorrower receiver,\\n        address token,\\n        uint256 amount,\\n        bytes calldata data\\n    )\\n        public\\n        override(ERC20FlashMint, IERC3156FlashLender)\\n        nonReentrant\\n        returns (bool)\\n    {\\n        return super.flashLoan(receiver, token, amount, data);\\n    }\\n\\n    /// @dev Inherited from ERC20FlashMint. Defines maximum size of the flash mint.\\n    /// @param token Token to be flash minted. Returns 0 amount in case of token != address(this).\\n    function maxFlashLoan(address token)\\n        public\\n        view\\n        virtual\\n        override(ERC20FlashMint, IERC3156FlashLender)\\n        returns (uint256)\\n    {\\n        return token == address(this) ? Math.min(totalSupply() / 10, ERC20FlashMint.maxFlashLoan(address(this))) : 0;\\n    }\\n\\n    /// @dev Inherited from ERC20FlashMint. Defines flash mint fee for the flash mint of @param amount tokens.\\n    /// @param token Token to be flash minted. Returns 0 fee in case of token != address(this).\\n    /// @param amount Size of the flash mint.\\n    function _flashFee(address token, uint256 amount) internal view virtual override returns (uint256) {\\n        return token == address(this) ? amount * flashMintFeePercentage / PERCENTAGE_BASE : 0;\\n    }\\n\\n    /// @dev Inherited from ERC20FlashMint. Defines flash mint fee receiver.\\n    /// @return Address that will receive flash mint fees.\\n    function _flashFeeReceiver() internal view virtual override returns (address) {\\n        return feeRecipient;\\n    }\\n}\\n\\n/// @dev Implementation of Position Manager. Current implementation does not support rebasing tokens as collateral.\\ncontract PositionManager is FeeCollector, IPositionManager {\\n    // --- Types ---\\n\\n    using SafeERC20 for IERC20;\\n    using Fixed256x18 for uint256;\\n\\n    // --- Constants ---\\n\\n    uint256 public constant override MINUTE_DECAY_FACTOR = 999_037_758_833_783_000;\\n\\n    uint256 public constant override MAX_BORROWING_SPREAD = MathUtils._100_PERCENT / 100; // 1%\\n    uint256 public constant override MAX_BORROWING_RATE = MathUtils._100_PERCENT / 100 * 5; // 5%\\n\\n    uint256 public constant override BETA = 2;\\n\\n    // --- Immutables ---\\n\\n    IRToken public immutable override rToken;\\n\\n    // --- Variables ---\\n\\n    mapping(address position => IERC20 collateralToken) public override collateralTokenForPosition;\\n\\n    mapping(address position => mapping(address delegate => bool isWhitelisted)) public override isDelegateWhitelisted;\\n\\n    mapping(IERC20 collateralToken => CollateralTokenInfo collateralTokenInfo) public override collateralInfo;\\n\\n    // --- Modifiers ---\\n\\n    /// @dev Checks if the collateral token has been added to the position manager, or reverts otherwise.\\n    /// @param collateralToken The collateral token to check.\\n    modifier collateralTokenExists(IERC20 collateralToken) {\\n        if (address(collateralInfo[collateralToken].collateralToken) == address(0)) {\\n            revert CollateralTokenNotAdded();\\n        }\\n        _;\\n    }\\n\\n    /// @dev Checks if the collateral token has enabled, or reverts otherwise. When the condition is false, the check\\n    /// is skipped.\\n    /// @param collateralToken The collateral token to check.\\n    /// @param condition If true, the check will be performed.\\n    modifier onlyEnabledCollateralTokenWhen(IERC20 collateralToken, bool condition) {\\n        if (condition && !collateralInfo[collateralToken].isEnabled) {\\n            revert CollateralTokenDisabled();\\n        }\\n        _;\\n    }\\n\\n    /// @dev Checks if the borrower has a position with the collateral token or doesn't have a position at all, or\\n    /// reverts otherwise.\\n    /// @param position The borrower to check.\\n    /// @param collateralToken The collateral token to check.\\n    modifier onlyDepositedCollateralTokenOrNew(address position, IERC20 collateralToken) {\\n        if (\\n            collateralTokenForPosition[position] != IERC20(address(0))\\n                && collateralTokenForPosition[position] != collateralToken\\n        ) {\\n            revert PositionCollateralTokenMismatch();\\n        }\\n        _;\\n    }\\n\\n    /// @dev Checks if the max fee percentage is between the borrowing spread and 100%, or reverts otherwise. When the\\n    /// condition is false, the check is skipped.\\n    /// @param maxFeePercentage The max fee percentage to check.\\n    /// @param condition If true, the check will be performed.\\n    modifier validMaxFeePercentageWhen(uint256 maxFeePercentage, bool condition) {\\n        if (condition && maxFeePercentage > MathUtils._100_PERCENT) {\\n            revert InvalidMaxFeePercentage();\\n        }\\n        _;\\n    }\\n\\n    // --- Constructor ---\\n\\n    /// @dev Initializes the position manager.\\n    constructor(address rToken_) FeeCollector(msg.sender) {\\n        rToken = rToken_ == address(0) ? new RToken(address(this), msg.sender) : IRToken(rToken_);\\n        emit PositionManagerDeployed(rToken, msg.sender);\\n    }\\n\\n    // --- External functions ---\\n\\n    function managePosition(\\n        IERC20 collateralToken,\\n        address position,\\n        uint256 collateralChange,\\n        bool isCollateralIncrease,\\n        uint256 debtChange,\\n        bool isDebtIncrease,\\n        uint256 maxFeePercentage,\\n        ERC20PermitSignature calldata permitSignature\\n    )\\n        public\\n        virtual\\n        override\\n        collateralTokenExists(collateralToken)\\n        validMaxFeePercentageWhen(maxFeePercentage, isDebtIncrease)\\n        onlyDepositedCollateralTokenOrNew(position, collateralToken)\\n        onlyEnabledCollateralTokenWhen(collateralToken, isDebtIncrease && debtChange > 0)\\n        returns (uint256 actualCollateralChange, uint256 actualDebtChange)\\n    {\\n        if (position != msg.sender && !isDelegateWhitelisted[position][msg.sender]) {\\n            revert DelegateNotWhitelisted();\\n        }\\n        if (collateralChange == 0 && debtChange == 0) {\\n            revert NoCollateralOrDebtChange();\\n        }\\n        if (address(permitSignature.token) == address(collateralToken)) {\\n            PermitHelper.applyPermit(permitSignature, msg.sender, address(this));\\n        }\\n\\n        CollateralTokenInfo storage collateralTokenInfo = collateralInfo[collateralToken];\\n        IERC20Indexable raftCollateralToken = collateralTokenInfo.collateralToken;\\n        IERC20Indexable raftDebtToken = collateralTokenInfo.debtToken;\\n\\n        uint256 debtBefore = raftDebtToken.balanceOf(position);\\n        if (!isDebtIncrease && (debtChange == type(uint256).max || (debtBefore != 0 && debtChange == debtBefore))) {\\n            if (collateralChange != 0 || isCollateralIncrease) {\\n                revert WrongCollateralParamsForFullRepayment();\\n            }\\n            collateralChange = raftCollateralToken.balanceOf(position);\\n            debtChange = debtBefore;\\n        }\\n\\n        _adjustDebt(position, collateralToken, raftDebtToken, debtChange, isDebtIncrease, maxFeePercentage);\\n        _adjustCollateral(collateralToken, raftCollateralToken, position, collateralChange, isCollateralIncrease);\\n\\n        uint256 positionDebt = raftDebtToken.balanceOf(position);\\n        uint256 positionCollateral = raftCollateralToken.balanceOf(position);\\n\\n        if (positionDebt == 0) {\\n            if (positionCollateral != 0) {\\n                revert InvalidPosition();\\n            }\\n            // position was closed, remove it\\n            _closePosition(raftCollateralToken, raftDebtToken, position, false);\\n        } else {\\n            _checkValidPosition(collateralToken, positionDebt, positionCollateral);\\n\\n            if (debtBefore == 0) {\\n                collateralTokenForPosition[position] = collateralToken;\\n                emit PositionCreated(position, collateralToken);\\n            }\\n        }\\n        return (collateralChange, debtChange);\\n    }\\n\\n    function liquidate(address position) external override {\\n        IERC20 collateralToken = collateralTokenForPosition[position];\\n        CollateralTokenInfo storage collateralTokenInfo = collateralInfo[collateralToken];\\n        IERC20Indexable raftCollateralToken = collateralTokenInfo.collateralToken;\\n        IERC20Indexable raftDebtToken = collateralTokenInfo.debtToken;\\n        ISplitLiquidationCollateral splitLiquidation = collateralTokenInfo.splitLiquidation;\\n\\n        if (address(collateralToken) == address(0)) {\\n            revert NothingToLiquidate();\\n        }\\n        (uint256 price,) = collateralTokenInfo.priceFeed.fetchPrice();\\n        uint256 entireCollateral = raftCollateralToken.balanceOf(position);\\n        uint256 entireDebt = raftDebtToken.balanceOf(position);\\n        uint256 icr = MathUtils._computeCR(entireCollateral, entireDebt, price);\\n\\n        if (icr >= splitLiquidation.MCR()) {\\n            revert NothingToLiquidate();\\n        }\\n\\n        uint256 totalDebt = raftDebtToken.totalSupply();\\n        if (entireDebt == totalDebt) {\\n            revert CannotLiquidateLastPosition();\\n        }\\n        bool isRedistribution = icr <= MathUtils._100_PERCENT;\\n\\n        // prettier: ignore\\n        (uint256 collateralLiquidationFee, uint256 collateralToSendToLiquidator) =\\n            splitLiquidation.split(entireCollateral, entireDebt, price, isRedistribution);\\n\\n        if (!isRedistribution) {\\n            _burnRTokens(msg.sender, entireDebt);\\n            totalDebt -= entireDebt;\\n\\n            // Collateral is sent to protocol as a fee only in case of liquidation\\n            collateralToken.safeTransfer(feeRecipient, collateralLiquidationFee);\\n        }\\n\\n        collateralToken.safeTransfer(msg.sender, collateralToSendToLiquidator);\\n\\n        _closePosition(raftCollateralToken, raftDebtToken, position, true);\\n\\n        _updateDebtAndCollateralIndex(collateralToken, raftCollateralToken, raftDebtToken, totalDebt);\\n\\n        emit Liquidation(\\n            msg.sender,\\n            position,\\n            collateralToken,\\n            entireDebt,\\n            entireCollateral,\\n            collateralToSendToLiquidator,\\n            collateralLiquidationFee,\\n            isRedistribution\\n        );\\n    }\\n\\n    function redeemCollateral(\\n        IERC20 collateralToken,\\n        uint256 debtAmount,\\n        uint256 maxFeePercentage\\n    )\\n        public\\n        virtual\\n        override\\n    {\\n        if (maxFeePercentage > MathUtils._100_PERCENT) {\\n            revert MaxFeePercentageOutOfRange();\\n        }\\n        if (debtAmount == 0) {\\n            revert AmountIsZero();\\n        }\\n        IERC20Indexable raftDebtToken = collateralInfo[collateralToken].debtToken;\\n\\n        uint256 newTotalDebt = raftDebtToken.totalSupply() - debtAmount;\\n        uint256 lowTotalDebt = collateralInfo[collateralToken].splitLiquidation.LOW_TOTAL_DEBT();\\n        if (newTotalDebt < lowTotalDebt) {\\n            revert TotalDebtCannotBeLowerThanMinDebt(collateralToken, newTotalDebt);\\n        }\\n\\n        (uint256 price, uint256 deviation) = collateralInfo[collateralToken].priceFeed.fetchPrice();\\n        uint256 collateralToRedeem = debtAmount.divDown(price);\\n        uint256 totalCollateral = collateralToken.balanceOf(address(this));\\n        if (\\n            totalCollateral - collateralToRedeem == 0\\n                || totalCollateral - collateralToRedeem < lowTotalDebt.divDown(price)\\n        ) {\\n            revert TotalCollateralCannotBeLowerThanMinCollateral(\\n                collateralToken, totalCollateral - collateralToRedeem, lowTotalDebt.divDown(price)\\n            );\\n        }\\n\\n        // Decay the baseRate due to time passed, and then increase it according to the size of this redemption.\\n        // Use the saved total R supply value, from before it was reduced by the redemption.\\n        _updateBaseRateFromRedemption(collateralToken, collateralToRedeem, price, rToken.totalSupply());\\n\\n        // Calculate the redemption fee\\n        uint256 redemptionFee = getRedemptionFee(collateralToken, collateralToRedeem, deviation);\\n        uint256 rebate = redemptionFee.mulDown(collateralInfo[collateralToken].redemptionRebate);\\n\\n        _checkValidFee(redemptionFee, collateralToRedeem, maxFeePercentage);\\n\\n        // Send the redemption fee to the recipient\\n        collateralToken.safeTransfer(feeRecipient, redemptionFee - rebate);\\n\\n        // Burn the total R that is cancelled with debt, and send the redeemed collateral to msg.sender\\n        _burnRTokens(msg.sender, debtAmount);\\n\\n        // Send collateral to account\\n        collateralToken.safeTransfer(msg.sender, collateralToRedeem - redemptionFee);\\n\\n        _updateDebtAndCollateralIndex(\\n            collateralToken, collateralInfo[collateralToken].collateralToken, raftDebtToken, newTotalDebt\\n        );\\n\\n        emit Redemption(msg.sender, debtAmount, collateralToRedeem, redemptionFee, rebate);\\n    }\\n\\n    function whitelistDelegate(address delegate, bool whitelisted) external override {\\n        if (delegate == address(0)) {\\n            revert InvalidDelegateAddress();\\n        }\\n        isDelegateWhitelisted[msg.sender][delegate] = whitelisted;\\n\\n        emit DelegateWhitelisted(msg.sender, delegate, whitelisted);\\n    }\\n\\n    function setBorrowingSpread(IERC20 collateralToken, uint256 newBorrowingSpread) external override onlyOwner {\\n        if (newBorrowingSpread > MAX_BORROWING_SPREAD) {\\n            revert BorrowingSpreadExceedsMaximum();\\n        }\\n        collateralInfo[collateralToken].borrowingSpread = newBorrowingSpread;\\n        emit BorrowingSpreadUpdated(newBorrowingSpread);\\n    }\\n\\n    function setRedemptionRebate(IERC20 collateralToken, uint256 newRedemptionRebate) public override onlyOwner {\\n        if (newRedemptionRebate > MathUtils._100_PERCENT) {\\n            revert RedemptionRebateExceedsMaximum();\\n        }\\n        collateralInfo[collateralToken].redemptionRebate = newRedemptionRebate;\\n        emit RedemptionRebateUpdated(newRedemptionRebate);\\n    }\\n\\n    function getRedemptionFeeWithDecay(\\n        IERC20 collateralToken,\\n        uint256 collateralAmount\\n    )\\n        external\\n        view\\n        override\\n        returns (uint256 redemptionFee)\\n    {\\n        redemptionFee = getRedemptionRateWithDecay(collateralToken).mulDown(collateralAmount);\\n        if (redemptionFee >= collateralAmount) {\\n            revert FeeEatsUpAllReturnedCollateral();\\n        }\\n    }\\n\\n    // --- Public functions ---\\n\\n    function addCollateralToken(\\n        IERC20 collateralToken,\\n        IPriceFeed priceFeed,\\n        ISplitLiquidationCollateral newSplitLiquidationCollateral\\n    )\\n        public\\n        virtual\\n        override\\n    {\\n        addCollateralToken(\\n            collateralToken,\\n            priceFeed,\\n            newSplitLiquidationCollateral,\\n            new ERC20Indexable(\\n                address(this),\\n                string(bytes.concat(\\\"Raft \\\", bytes(IERC20Metadata(address(collateralToken)).name()), \\\" collateral\\\")),\\n                string(bytes.concat(\\\"r\\\", bytes(IERC20Metadata(address(collateralToken)).symbol()), \\\"-c\\\")),\\n                type(uint256).max\\n            ),\\n            new ERC20Indexable(\\n                address(this),\\n                string(bytes.concat(\\\"Raft \\\", bytes(IERC20Metadata(address(collateralToken)).name()), \\\" debt\\\")),\\n                string(bytes.concat(\\\"r\\\", bytes(IERC20Metadata(address(collateralToken)).symbol()), \\\"-d\\\")),\\n                type(uint256).max\\n            )\\n        );\\n    }\\n\\n    function addCollateralToken(\\n        IERC20 collateralToken,\\n        IPriceFeed priceFeed,\\n        ISplitLiquidationCollateral newSplitLiquidationCollateral,\\n        IERC20Indexable raftCollateralToken_,\\n        IERC20Indexable raftDebtToken_\\n    )\\n        public\\n        override\\n        onlyOwner\\n    {\\n        if (address(collateralToken) == address(0)) {\\n            revert CollateralTokenAddressCannotBeZero();\\n        }\\n        if (address(priceFeed) == address(0)) {\\n            revert PriceFeedAddressCannotBeZero();\\n        }\\n        if (address(collateralInfo[collateralToken].collateralToken) != address(0)) {\\n            revert CollateralTokenAlreadyAdded();\\n        }\\n\\n        CollateralTokenInfo memory raftCollateralTokenInfo;\\n        raftCollateralTokenInfo.collateralToken = raftCollateralToken_;\\n        raftCollateralTokenInfo.debtToken = raftDebtToken_;\\n        raftCollateralTokenInfo.isEnabled = true;\\n        raftCollateralTokenInfo.priceFeed = priceFeed;\\n\\n        collateralInfo[collateralToken] = raftCollateralTokenInfo;\\n\\n        setRedemptionSpread(collateralToken, MathUtils._100_PERCENT);\\n        setRedemptionRebate(collateralToken, MathUtils._100_PERCENT);\\n\\n        setSplitLiquidationCollateral(collateralToken, newSplitLiquidationCollateral);\\n\\n        emit CollateralTokenAdded(\\n            collateralToken, raftCollateralTokenInfo.collateralToken, raftCollateralTokenInfo.debtToken, priceFeed\\n        );\\n    }\\n\\n    function setCollateralEnabled(\\n        IERC20 collateralToken,\\n        bool isEnabled\\n    )\\n        public\\n        override\\n        onlyOwner\\n        collateralTokenExists(collateralToken)\\n    {\\n        bool previousIsEnabled = collateralInfo[collateralToken].isEnabled;\\n        collateralInfo[collateralToken].isEnabled = isEnabled;\\n\\n        if (previousIsEnabled != isEnabled) {\\n            emit CollateralTokenModified(collateralToken, isEnabled);\\n        }\\n    }\\n\\n    function setSplitLiquidationCollateral(\\n        IERC20 collateralToken,\\n        ISplitLiquidationCollateral newSplitLiquidationCollateral\\n    )\\n        public\\n        override\\n        onlyOwner\\n    {\\n        if (address(newSplitLiquidationCollateral) == address(0)) {\\n            revert SplitLiquidationCollateralCannotBeZero();\\n        }\\n        collateralInfo[collateralToken].splitLiquidation = newSplitLiquidationCollateral;\\n        emit SplitLiquidationCollateralChanged(collateralToken, newSplitLiquidationCollateral);\\n    }\\n\\n    function setRedemptionSpread(IERC20 collateralToken, uint256 newRedemptionSpread) public override onlyOwner {\\n        if (newRedemptionSpread > MathUtils._100_PERCENT) {\\n            revert RedemptionSpreadOutOfRange();\\n        }\\n        collateralInfo[collateralToken].redemptionSpread = newRedemptionSpread;\\n        emit RedemptionSpreadUpdated(collateralToken, newRedemptionSpread);\\n    }\\n\\n    function getRedemptionRateWithDecay(IERC20 collateralToken) public view override returns (uint256) {\\n        return _calcRedemptionRate(collateralToken, _calcDecayedBaseRate(collateralToken));\\n    }\\n\\n    function raftCollateralToken(IERC20 collateralToken) external view override returns (IERC20Indexable) {\\n        return collateralInfo[collateralToken].collateralToken;\\n    }\\n\\n    function raftDebtToken(IERC20 collateralToken) external view override returns (IERC20Indexable) {\\n        return collateralInfo[collateralToken].debtToken;\\n    }\\n\\n    function priceFeed(IERC20 collateralToken) external view override returns (IPriceFeed) {\\n        return collateralInfo[collateralToken].priceFeed;\\n    }\\n\\n    function splitLiquidationCollateral(IERC20 collateralToken) external view returns (ISplitLiquidationCollateral) {\\n        return collateralInfo[collateralToken].splitLiquidation;\\n    }\\n\\n    function collateralEnabled(IERC20 collateralToken) external view override returns (bool) {\\n        return collateralInfo[collateralToken].isEnabled;\\n    }\\n\\n    function lastFeeOperationTime(IERC20 collateralToken) external view override returns (uint256) {\\n        return collateralInfo[collateralToken].lastFeeOperationTime;\\n    }\\n\\n    function borrowingSpread(IERC20 collateralToken) external view override returns (uint256) {\\n        return collateralInfo[collateralToken].borrowingSpread;\\n    }\\n\\n    function baseRate(IERC20 collateralToken) external view override returns (uint256) {\\n        return collateralInfo[collateralToken].baseRate;\\n    }\\n\\n    function redemptionSpread(IERC20 collateralToken) external view override returns (uint256) {\\n        return collateralInfo[collateralToken].redemptionSpread;\\n    }\\n\\n    function redemptionRebate(IERC20 collateralToken) external view override returns (uint256) {\\n        return collateralInfo[collateralToken].redemptionRebate;\\n    }\\n\\n    function getRedemptionRate(IERC20 collateralToken) public view override returns (uint256) {\\n        return _calcRedemptionRate(collateralToken, collateralInfo[collateralToken].baseRate);\\n    }\\n\\n    function getRedemptionFee(\\n        IERC20 collateralToken,\\n        uint256 collateralAmount,\\n        uint256 priceDeviation\\n    )\\n        public\\n        view\\n        override\\n        returns (uint256)\\n    {\\n        return Math.min(getRedemptionRate(collateralToken) + priceDeviation, MathUtils._100_PERCENT).mulDown(\\n            collateralAmount\\n        );\\n    }\\n\\n    function getBorrowingRate(IERC20 collateralToken) public view override returns (uint256) {\\n        return _calcBorrowingRate(collateralToken, collateralInfo[collateralToken].baseRate);\\n    }\\n\\n    function getBorrowingRateWithDecay(IERC20 collateralToken) public view override returns (uint256) {\\n        return _calcBorrowingRate(collateralToken, _calcDecayedBaseRate(collateralToken));\\n    }\\n\\n    function getBorrowingFee(IERC20 collateralToken, uint256 debtAmount) public view override returns (uint256) {\\n        return getBorrowingRate(collateralToken).mulDown(debtAmount);\\n    }\\n\\n    // --- Helper functions ---\\n\\n    /// @dev Adjusts the debt of a given borrower by burning or minting the corresponding amount of R and the Raft\\n    /// debt token. If the debt is being increased, the borrowing fee is also triggered.\\n    /// @param position The address of the borrower.\\n    /// @param debtChange The amount of R to add or remove. Must be positive.\\n    /// @param isDebtIncrease True if the debt is being increased, false otherwise.\\n    /// @param maxFeePercentage The maximum fee percentage.\\n    function _adjustDebt(\\n        address position,\\n        IERC20 collateralToken,\\n        IERC20Indexable raftDebtToken,\\n        uint256 debtChange,\\n        bool isDebtIncrease,\\n        uint256 maxFeePercentage\\n    )\\n        internal\\n    {\\n        if (debtChange == 0) {\\n            return;\\n        }\\n\\n        if (isDebtIncrease) {\\n            uint256 totalDebtChange =\\n                debtChange + _triggerBorrowingFee(collateralToken, position, debtChange, maxFeePercentage);\\n            raftDebtToken.mint(position, totalDebtChange);\\n            _mintRTokens(msg.sender, debtChange);\\n        } else {\\n            raftDebtToken.burn(position, debtChange);\\n            _burnRTokens(msg.sender, debtChange);\\n        }\\n\\n        emit DebtChanged(position, collateralToken, debtChange, isDebtIncrease);\\n    }\\n\\n    /// @dev Mints R tokens\\n    function _mintRTokens(address to, uint256 amount) internal virtual {\\n        rToken.mint(to, amount);\\n    }\\n\\n    /// @dev Burns R tokens\\n    function _burnRTokens(address from, uint256 amount) internal virtual {\\n        rToken.burn(from, amount);\\n    }\\n\\n    /// @dev Adjusts the collateral of a given borrower by burning or minting the corresponding amount of Raft\\n    /// collateral token and transferring the corresponding amount of collateral token.\\n    /// @param collateralToken The token the borrower used as collateral.\\n    /// @param position The address of the borrower.\\n    /// @param collateralChange The amount of collateral to add or remove. Must be positive.\\n    /// @param isCollateralIncrease True if the collateral is being increased, false otherwise.\\n    function _adjustCollateral(\\n        IERC20 collateralToken,\\n        IERC20Indexable raftCollateralToken,\\n        address position,\\n        uint256 collateralChange,\\n        bool isCollateralIncrease\\n    )\\n        internal\\n    {\\n        if (collateralChange == 0) {\\n            return;\\n        }\\n\\n        if (isCollateralIncrease) {\\n            raftCollateralToken.mint(position, collateralChange);\\n            collateralToken.safeTransferFrom(msg.sender, address(this), collateralChange);\\n        } else {\\n            raftCollateralToken.burn(position, collateralChange);\\n            collateralToken.safeTransfer(msg.sender, collateralChange);\\n        }\\n\\n        emit CollateralChanged(position, collateralToken, collateralChange, isCollateralIncrease);\\n    }\\n\\n    /// @dev Updates debt and collateral indexes for a given collateral token.\\n    /// @param collateralToken The collateral token for which to update the indexes.\\n    /// @param raftCollateralToken The raft collateral indexable token.\\n    /// @param raftDebtToken The raft debt indexable token.\\n    /// @param totalDebtForCollateral Totam amount of debt backed by collateral token.\\n    function _updateDebtAndCollateralIndex(\\n        IERC20 collateralToken,\\n        IERC20Indexable raftCollateralToken,\\n        IERC20Indexable raftDebtToken,\\n        uint256 totalDebtForCollateral\\n    )\\n        internal\\n    {\\n        raftDebtToken.setIndex(totalDebtForCollateral);\\n        raftCollateralToken.setIndex(collateralToken.balanceOf(address(this)));\\n    }\\n\\n    function _closePosition(\\n        IERC20Indexable raftCollateralToken,\\n        IERC20Indexable raftDebtToken,\\n        address position,\\n        bool burnTokens\\n    )\\n        internal\\n    {\\n        collateralTokenForPosition[position] = IERC20(address(0));\\n\\n        if (burnTokens) {\\n            raftDebtToken.burn(position, type(uint256).max);\\n            raftCollateralToken.burn(position, type(uint256).max);\\n        }\\n        emit PositionClosed(position);\\n    }\\n\\n    // --- Borrowing & redemption fee helper functions ---\\n\\n    /// @dev Updates the base rate from a redemption operation. Impacts on the base rate:\\n    /// 1. decays the base rate based on time passed since last redemption or R borrowing operation,\\n    /// 2. increases the base rate based on the amount redeemed, as a proportion of total supply.\\n    function _updateBaseRateFromRedemption(\\n        IERC20 collateralToken,\\n        uint256 collateralDrawn,\\n        uint256 price,\\n        uint256 totalDebtSupply\\n    )\\n        internal\\n        returns (uint256)\\n    {\\n        uint256 decayedBaseRate = _calcDecayedBaseRate(collateralToken);\\n\\n        /* Convert the drawn collateral back to R at face value rate (1 R:1 USD), in order to get\\n        * the fraction of total supply that was redeemed at face value. */\\n        uint256 redeemedFraction = collateralDrawn * price / totalDebtSupply;\\n\\n        uint256 newBaseRate = decayedBaseRate + redeemedFraction / BETA;\\n        newBaseRate = Math.min(newBaseRate, MathUtils._100_PERCENT); // cap baseRate at a maximum of 100%\\n        assert(newBaseRate > 0); // Base rate is always non-zero after redemption\\n\\n        // Update the baseRate state variable\\n        collateralInfo[collateralToken].baseRate = newBaseRate;\\n        emit BaseRateUpdated(collateralToken, newBaseRate);\\n\\n        _updateLastFeeOpTime(collateralToken);\\n\\n        return newBaseRate;\\n    }\\n\\n    function _calcRedemptionRate(IERC20 collateralToken, uint256 baseRate_) internal view returns (uint256) {\\n        return baseRate_ + collateralInfo[collateralToken].redemptionSpread;\\n    }\\n\\n    function _calcBorrowingRate(IERC20 collateralToken, uint256 baseRate_) internal view returns (uint256) {\\n        return Math.min(collateralInfo[collateralToken].borrowingSpread + baseRate_, MAX_BORROWING_RATE);\\n    }\\n\\n    /// @dev Updates the base rate based on time elapsed since the last redemption or R borrowing operation.\\n    function _decayBaseRateFromBorrowing(IERC20 collateralToken) internal {\\n        uint256 decayedBaseRate = _calcDecayedBaseRate(collateralToken);\\n        assert(decayedBaseRate <= MathUtils._100_PERCENT); // The baseRate can decay to 0\\n\\n        collateralInfo[collateralToken].baseRate = decayedBaseRate;\\n        emit BaseRateUpdated(collateralToken, decayedBaseRate);\\n\\n        _updateLastFeeOpTime(collateralToken);\\n    }\\n\\n    /// @dev Update the last fee operation time only if time passed >= decay interval. This prevents base rate\\n    /// griefing.\\n    function _updateLastFeeOpTime(IERC20 collateralToken) internal {\\n        uint256 timePassed = block.timestamp - collateralInfo[collateralToken].lastFeeOperationTime;\\n\\n        if (timePassed >= 1 minutes) {\\n            collateralInfo[collateralToken].lastFeeOperationTime = block.timestamp;\\n            emit LastFeeOpTimeUpdated(collateralToken, block.timestamp);\\n        }\\n    }\\n\\n    function _calcDecayedBaseRate(IERC20 collateralToken) internal view returns (uint256) {\\n        uint256 minutesPassed = (block.timestamp - collateralInfo[collateralToken].lastFeeOperationTime) / 1 minutes;\\n        uint256 decayFactor = MathUtils._decPow(MINUTE_DECAY_FACTOR, minutesPassed);\\n\\n        return collateralInfo[collateralToken].baseRate.mulDown(decayFactor);\\n    }\\n\\n    function _triggerBorrowingFee(\\n        IERC20 collateralToken,\\n        address position,\\n        uint256 debtAmount,\\n        uint256 maxFeePercentage\\n    )\\n        internal\\n        virtual\\n        returns (uint256 borrowingFee)\\n    {\\n        _decayBaseRateFromBorrowing(collateralToken); // decay the baseRate state variable\\n        borrowingFee = getBorrowingFee(collateralToken, debtAmount);\\n\\n        _checkValidFee(borrowingFee, debtAmount, maxFeePercentage);\\n\\n        if (borrowingFee > 0) {\\n            _mintRTokens(feeRecipient, borrowingFee);\\n            emit RBorrowingFeePaid(collateralToken, position, borrowingFee);\\n        }\\n    }\\n\\n    // --- Validation check helper functions ---\\n\\n    function _checkValidPosition(IERC20 collateralToken, uint256 positionDebt, uint256 positionCollateral) internal {\\n        ISplitLiquidationCollateral splitCollateral = collateralInfo[collateralToken].splitLiquidation;\\n        if (positionDebt < splitCollateral.LOW_TOTAL_DEBT()) {\\n            revert NetDebtBelowMinimum(positionDebt);\\n        }\\n\\n        (uint256 price,) = collateralInfo[collateralToken].priceFeed.fetchPrice();\\n        uint256 newICR = MathUtils._computeCR(positionCollateral, positionDebt, price);\\n        if (newICR < splitCollateral.MCR()) {\\n            revert NewICRLowerThanMCR(newICR);\\n        }\\n    }\\n\\n    function _checkValidFee(uint256 fee, uint256 amount, uint256 maxFeePercentage) internal pure {\\n        uint256 feePercentage = fee.divDown(amount);\\n\\n        if (feePercentage > maxFeePercentage) {\\n            revert FeeExceedsMaxFee(fee, amount, maxFeePercentage);\\n        }\\n    }\\n}\\n\\ninterface IRMinter {\\n    /// @dev Emitted when tokens are recovered from the contract.\\n    /// @param token The address of the token being recovered.\\n    /// @param to The address receiving the recovered tokens.\\n    /// @param amount The amount of tokens recovered.\\n    event TokensRecovered(IERC20 token, address to, uint256 amount);\\n\\n    /// @return Address of the R token.\\n    function r() external view returns (IRToken);\\n\\n    /// @return Address of the Position manager contract responsible for minting R.\\n    function positionManager() external view returns (IPositionManager);\\n\\n    /// @dev Recover accidentally sent tokens to the contract\\n    /// @param token Address of the token contract.\\n    /// @param to Address of the receiver of the tokens.\\n    /// @param amount Number of tokens to recover.\\n    function recoverTokens(IERC20 token, address to, uint256 amount) external;\\n}\\n\\ninterface ILock {\\n    /// @dev Thrown when contract usage is locked.\\n    error ContractLocked();\\n\\n    /// @dev Unauthorized call to lock/unlock.\\n    error Unauthorized();\\n\\n    /// @dev Retrieves if contract is currently locked or not.\\n    function locked() external view returns (bool);\\n\\n    /// @dev Retrieves address of the locker who can unlock contract.\\n    function locker() external view returns (address);\\n\\n    /// @dev Unlcoks the usage of the contract.\\n    function unlock() external;\\n\\n    /// @dev Locks the usage of the contract.\\n    function lock() external;\\n}\\n\\nabstract contract ERC20RMinter is IRMinter, ERC20, Ownable2Step {\\n    using SafeERC20 for IERC20;\\n\\n    IRToken public immutable override r;\\n    IPositionManager public immutable override positionManager;\\n\\n    constructor(IRToken rToken_, string memory name_, string memory symbol_) ERC20(name_, symbol_) {\\n        r = rToken_;\\n        positionManager = IPositionManager(rToken_.positionManager());\\n\\n        _approve(address(this), address(positionManager), type(uint256).max);\\n    }\\n\\n    modifier unlockCall() {\\n        ILock lockContract = ILock(address(positionManager.priceFeed(IERC20(this))));\\n        lockContract.unlock();\\n        _;\\n        lockContract.lock();\\n    }\\n\\n    function recoverTokens(IERC20 token, address to, uint256 amount) external override onlyOwner {\\n        token.safeTransfer(to, amount);\\n        emit TokensRecovered(token, to, amount);\\n    }\\n\\n    function _mintR(address to, uint256 amount) internal unlockCall {\\n        _mint(address(this), amount);\\n        ERC20PermitSignature memory emptySignature;\\n        positionManager.managePosition(\\n            IERC20(address(this)),\\n            address(this),\\n            amount,\\n            true, // collateral increase\\n            amount,\\n            true, // debt increase\\n            1e18, // 100%\\n            emptySignature\\n        );\\n        r.transfer(to, amount);\\n    }\\n\\n    function _burnR(address from, uint256 amount) internal unlockCall {\\n        r.transferFrom(from, address(this), amount);\\n        ERC20PermitSignature memory emptySignature;\\n        positionManager.managePosition(\\n            IERC20(address(this)),\\n            address(this),\\n            amount,\\n            false, // collateral decrease\\n            amount,\\n            false, // debt decrease\\n            1e18, // 100%\\n            emptySignature\\n        );\\n        _burn(address(this), amount);\\n    }\\n}\\n\\ncontract InterestRateDebtToken is ERC20Indexable {\\n    // --- Types ---\\n\\n    using Fixed256x18 for uint256;\\n\\n    // --- Events ---\\n\\n    event IndexIncreasePerSecondSet(uint256 indexIncreasePerSecond);\\n\\n    // --- Immutables ---\\n\\n    IERC20 immutable collateralToken;\\n\\n    // --- Variables ---\\n\\n    uint256 internal storedIndexUpdatedAt;\\n\\n    uint256 public indexIncreasePerSecond;\\n\\n    // --- Constructor ---\\n\\n    constructor(\\n        address positionManager_,\\n        string memory name_,\\n        string memory symbol_,\\n        IERC20 collateralToken_,\\n        uint256 cap_,\\n        uint256 indexIncreasePerSecond_\\n    )\\n        ERC20Indexable(positionManager_, name_, symbol_, cap_)\\n    {\\n        storedIndexUpdatedAt = block.timestamp;\\n        collateralToken = collateralToken_;\\n        setIndexIncreasePerSecond(indexIncreasePerSecond_);\\n    }\\n\\n    // --- Functions ---\\n\\n    function mint(address to, uint256 amount) public virtual override {\\n        updateIndexAndPayFees();\\n        super.mint(to, amount);\\n    }\\n\\n    function burn(address from, uint256 amount) public virtual override {\\n        updateIndexAndPayFees();\\n        super.burn(from, amount);\\n    }\\n\\n    function currentIndex() public view virtual override returns (uint256) {\\n        return storedIndex.mulUp(INDEX_PRECISION + indexIncreasePerSecond * (block.timestamp - storedIndexUpdatedAt));\\n    }\\n\\n    function updateIndexAndPayFees() public {\\n        uint256 currentIndex_ = currentIndex();\\n        _payFees(currentIndex_);\\n        storedIndexUpdatedAt = block.timestamp;\\n        storedIndex = currentIndex_;\\n        emit IndexUpdated(currentIndex_);\\n    }\\n\\n    function setIndexIncreasePerSecond(uint256 indexIncreasePerSecond_) public onlyOwner {\\n        updateIndexAndPayFees();\\n        indexIncreasePerSecond = indexIncreasePerSecond_;\\n        emit IndexIncreasePerSecondSet(indexIncreasePerSecond_);\\n    }\\n\\n    function unpaidFees() external view returns (uint256) {\\n        return _unpaidFees(currentIndex());\\n    }\\n\\n    function _unpaidFees(uint256 currentIndex_) private view returns (uint256) {\\n        return totalSupply().mulDown(currentIndex_ - storedIndex);\\n    }\\n\\n    function _payFees(uint256 currentIndex_) private {\\n        uint256 unpaidFees = _unpaidFees(currentIndex_);\\n        if (unpaidFees > 0) {\\n            IInterestRatePositionManager(positionManager).mintFees(collateralToken, unpaidFees);\\n        }\\n    }\\n}\\n\\n/// @dev Implementation of Position Manager. Current implementation does not support rebasing tokens as collateral.\\ncontract InterestRatePositionManager is ERC20RMinter, PositionManager, IInterestRatePositionManager {\\n    // --- Errors ---\\n\\n    error Unsupported();\\n\\n    // --- Constructor ---\\n\\n    /// @dev Initializes the position manager.\\n    constructor(IRToken rToken_)\\n        PositionManager(address(rToken_))\\n        ERC20RMinter(rToken_, \\\"Interest Rate Posman\\\", \\\"IRPM\\\")\\n    { }\\n\\n    // --- External functions ---\\n\\n    function managePosition(\\n        IERC20 collateralToken,\\n        address position,\\n        uint256 collateralChange,\\n        bool isCollateralIncrease,\\n        uint256 debtChange,\\n        bool isDebtIncrease,\\n        uint256 maxFeePercentage,\\n        ERC20PermitSignature calldata permitSignature\\n    )\\n        public\\n        virtual\\n        override(IPositionManager, PositionManager)\\n        returns (uint256 actualCollateralChange, uint256 actualDebtChange)\\n    {\\n        if (address(permitSignature.token) == address(r)) {\\n            PermitHelper.applyPermit(permitSignature, msg.sender, address(this));\\n        }\\n        return super.managePosition(\\n            collateralToken,\\n            position,\\n            collateralChange,\\n            isCollateralIncrease,\\n            debtChange,\\n            isDebtIncrease,\\n            maxFeePercentage,\\n            permitSignature\\n        );\\n    }\\n\\n    function mintFees(IERC20 collateralToken, uint256 amount) external {\\n        if (msg.sender != address(collateralInfo[collateralToken].debtToken)) {\\n            revert InvalidDebtToken(msg.sender);\\n        }\\n        _mintR(feeRecipient, amount);\\n\\n        emit MintedFees(collateralToken, amount);\\n    }\\n\\n    function redeemCollateral(IERC20, uint256, uint256) public virtual override(IPositionManager, PositionManager) {\\n        revert Unsupported();\\n    }\\n\\n    function addCollateralToken(\\n        IERC20,\\n        IPriceFeed,\\n        ISplitLiquidationCollateral\\n    )\\n        public\\n        override(IPositionManager, PositionManager)\\n    {\\n        revert Unsupported();\\n    }\\n\\n    // --- Helper functions ---\\n\\n    function _mintRTokens(address to, uint256 amount) internal virtual override {\\n        _mintR(to, amount);\\n    }\\n\\n    function _burnRTokens(address from, uint256 amount) internal virtual override {\\n        _burnR(from, amount);\\n    }\\n\\n    function _triggerBorrowingFee(\\n        IERC20,\\n        address,\\n        uint256,\\n        uint256\\n    )\\n        internal\\n        pure\\n        virtual\\n        override\\n        returns (uint256)\\n    {\\n        return 0;\\n    }\\n}\\n\"}},\"settings\":{\"remappings\":[\"@balancer-labs/=node_modules/@balancer-labs/\",\"@balancer-labs/v2-interfaces/contracts/=lib/balancer-v2-monorepo/pkg/interfaces/contracts/\",\"@chainlink/=node_modules/@chainlink/\",\"@eth-optimism/=node_modules/@eth-optimism/\",\"@openzeppelin/=node_modules/@openzeppelin/\",\"@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/\",\"@redstone-finance/=node_modules/@redstone-finance/\",\"@smartcontractkit/chainlink/=lib/chainlink/contracts/src/v0.8/\",\"@tempusfinance/=node_modules/@tempusfinance/\",\"@tempusfinance/tempus-utils/contracts/=lib/tempus-utils/contracts/\",\"balancer-v2-monorepo/=lib/balancer-v2-monorepo/\",\"chainlink/=lib/chainlink/\",\"ds-test/=lib/forge-std/lib/ds-test/src/\",\"erc4626-tests/=lib/chainlink/contracts/foundry-lib/openzeppelin-contracts/lib/erc4626-tests/\",\"eth-gas-reporter/=node_modules/eth-gas-reporter/\",\"forge-std/=lib/forge-std/src/\",\"hardhat/=node_modules/hardhat/\",\"openzeppelin-contracts/=lib/openzeppelin-contracts/\",\"tempus-utils/=lib/tempus-utils/contracts/\"],\"optimizer\":{\"enabled\":true,\"runs\":200000},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"appendCBOR\":true},\"outputSelection\":{\"*\":{\"*\":[\"evm.bytecode\",\"evm.deployedBytecode\",\"devdoc\",\"userdoc\",\"metadata\",\"abi\"]}},\"evmVersion\":\"london\",\"viaIR\":true,\"libraries\":{}}},\"ABI\":\"[{\\\"inputs\\\":[{\\\"internalType\\\":\\\"contract IRToken\\\",\\\"name\\\":\\\"rToken_\\\",\\\"type\\\":\\\"address\\\"}],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"constructor\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"AmountIsZero\\\",\\\"type\\\":\\\"error\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"BorrowingSpreadExceedsMaximum\\\",\\\"type\\\":\\\"error\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"CannotLiquidateLastPosition\\\",\\\"type\\\":\\\"error\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"CollateralTokenAddressCannotBeZero\\\",\\\"type\\\":\\\"error\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"CollateralTokenAlreadyAdded\\\",\\\"type\\\":\\\"error\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"CollateralTokenDisabled\\\",\\\"type\\\":\\\"error\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"CollateralTokenNotAdded\\\",\\\"type\\\":\\\"error\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"DelegateNotWhitelisted\\\",\\\"type\\\":\\\"error\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"FeeEatsUpAllReturnedCollateral\\\",\\\"type\\\":\\\"error\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"fee\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"amount\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"maxFeePercentage\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"FeeExceedsMaxFee\\\",\\\"type\\\":\\\"error\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"sender\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"InvalidDebtToken\\\",\\\"type\\\":\\\"error\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"InvalidDelegateAddress\\\",\\\"type\\\":\\\"error\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"InvalidFeeRecipient\\\",\\\"type\\\":\\\"error\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"InvalidMaxFeePercentage\\\",\\\"type\\\":\\\"error\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"InvalidPosition\\\",\\\"type\\\":\\\"error\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"MaxFeePercentageOutOfRange\\\",\\\"type\\\":\\\"error\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"netDebt\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"NetDebtBelowMinimum\\\",\\\"type\\\":\\\"error\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"newICR\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"NewICRLowerThanMCR\\\",\\\"type\\\":\\\"error\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"NoCollateralOrDebtChange\\\",\\\"type\\\":\\\"error\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"NothingToLiquidate\\\",\\\"type\\\":\\\"error\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"PositionCollateralTokenMismatch\\\",\\\"type\\\":\\\"error\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"PriceFeedAddressCannotBeZero\\\",\\\"type\\\":\\\"error\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"RedemptionRebateExceedsMaximum\\\",\\\"type\\\":\\\"error\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"RedemptionSpreadOutOfRange\\\",\\\"type\\\":\\\"error\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"SplitLiquidationCollateralCannotBeZero\\\",\\\"type\\\":\\\"error\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"contract IERC20\\\",\\\"name\\\":\\\"collateralToken\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"newTotalCollateral\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"minimumCollateral\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"TotalCollateralCannotBeLowerThanMinCollateral\\\",\\\"type\\\":\\\"error\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"contract IERC20\\\",\\\"name\\\":\\\"collateralToken\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"newTotalDebt\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"TotalDebtCannotBeLowerThanMinDebt\\\",\\\"type\\\":\\\"error\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"Unsupported\\\",\\\"type\\\":\\\"error\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"WrongCollateralParamsForFullRepayment\\\",\\\"type\\\":\\\"error\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":true,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"owner\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":true,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"spender\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"value\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"Approval\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":false,\\\"internalType\\\":\\\"contract IERC20\\\",\\\"name\\\":\\\"collateralToken\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"baseRate\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"BaseRateUpdated\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"borrowingSpread\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"BorrowingSpreadUpdated\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":true,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"position\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":true,\\\"internalType\\\":\\\"contract IERC20\\\",\\\"name\\\":\\\"collateralToken\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"collateralAmount\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"bool\\\",\\\"name\\\":\\\"isCollateralIncrease\\\",\\\"type\\\":\\\"bool\\\"}],\\\"name\\\":\\\"CollateralChanged\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":false,\\\"internalType\\\":\\\"contract IERC20\\\",\\\"name\\\":\\\"collateralToken\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"contract IERC20Indexable\\\",\\\"name\\\":\\\"raftCollateralToken\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"contract IERC20Indexable\\\",\\\"name\\\":\\\"raftDebtToken\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"contract IPriceFeed\\\",\\\"name\\\":\\\"priceFeed\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"CollateralTokenAdded\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":false,\\\"internalType\\\":\\\"contract IERC20\\\",\\\"name\\\":\\\"collateralToken\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"bool\\\",\\\"name\\\":\\\"isEnabled\\\",\\\"type\\\":\\\"bool\\\"}],\\\"name\\\":\\\"CollateralTokenModified\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":true,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"position\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":true,\\\"internalType\\\":\\\"contract IERC20\\\",\\\"name\\\":\\\"collateralToken\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"debtAmount\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"bool\\\",\\\"name\\\":\\\"isDebtIncrease\\\",\\\"type\\\":\\\"bool\\\"}],\\\"name\\\":\\\"DebtChanged\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":true,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"position\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":true,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"delegate\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"bool\\\",\\\"name\\\":\\\"whitelisted\\\",\\\"type\\\":\\\"bool\\\"}],\\\"name\\\":\\\"DelegateWhitelisted\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":false,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"feeRecipient\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"FeeRecipientChanged\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":false,\\\"internalType\\\":\\\"contract IERC20\\\",\\\"name\\\":\\\"collateralToken\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"lastFeeOpTime\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"LastFeeOpTimeUpdated\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":true,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"liquidator\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":true,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"position\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":true,\\\"internalType\\\":\\\"contract IERC20\\\",\\\"name\\\":\\\"collateralToken\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"debtLiquidated\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"collateralLiquidated\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"collateralSentToLiquidator\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"collateralLiquidationFeePaid\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"bool\\\",\\\"name\\\":\\\"isRedistribution\\\",\\\"type\\\":\\\"bool\\\"}],\\\"name\\\":\\\"Liquidation\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":false,\\\"internalType\\\":\\\"contract IERC20\\\",\\\"name\\\":\\\"collateralToken\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"amount\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"MintedFees\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":true,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"previousOwner\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":true,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"newOwner\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"OwnershipTransferStarted\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":true,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"previousOwner\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":true,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"newOwner\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"OwnershipTransferred\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":true,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"position\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"PositionClosed\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":true,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"position\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":true,\\\"internalType\\\":\\\"contract IERC20\\\",\\\"name\\\":\\\"collateralToken\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"PositionCreated\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":false,\\\"internalType\\\":\\\"contract IRToken\\\",\\\"name\\\":\\\"rToken\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"feeRecipient\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"PositionManagerDeployed\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":false,\\\"internalType\\\":\\\"contract IERC20\\\",\\\"name\\\":\\\"collateralToken\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":true,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"position\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"feeAmount\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"RBorrowingFeePaid\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":true,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"redeemer\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"amount\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"collateralSent\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"fee\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"rebate\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"Redemption\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"redemptionRebate\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"RedemptionRebateUpdated\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":false,\\\"internalType\\\":\\\"contract IERC20\\\",\\\"name\\\":\\\"collateralToken\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"redemptionSpread\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"RedemptionSpreadUpdated\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":false,\\\"internalType\\\":\\\"contract IERC20\\\",\\\"name\\\":\\\"collateralToken\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":true,\\\"internalType\\\":\\\"contract ISplitLiquidationCollateral\\\",\\\"name\\\":\\\"newSplitLiquidationCollateral\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"SplitLiquidationCollateralChanged\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":false,\\\"internalType\\\":\\\"contract IERC20\\\",\\\"name\\\":\\\"token\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"to\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"amount\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"TokensRecovered\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":true,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"from\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":true,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"to\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"value\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"Transfer\\\",\\\"type\\\":\\\"event\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"BETA\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"MAX_BORROWING_RATE\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"MAX_BORROWING_SPREAD\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"MINUTE_DECAY_FACTOR\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"acceptOwnership\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"contract IERC20\\\",\\\"name\\\":\\\"collateralToken\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"contract IPriceFeed\\\",\\\"name\\\":\\\"priceFeed\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"contract ISplitLiquidationCollateral\\\",\\\"name\\\":\\\"newSplitLiquidationCollateral\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"contract IERC20Indexable\\\",\\\"name\\\":\\\"raftCollateralToken_\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"contract IERC20Indexable\\\",\\\"name\\\":\\\"raftDebtToken_\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"addCollateralToken\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"contract IERC20\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"contract IPriceFeed\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"contract ISplitLiquidationCollateral\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"addCollateralToken\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"owner\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"spender\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"allowance\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"spender\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"amount\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"approve\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"bool\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"bool\\\"}],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"account\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"balanceOf\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"contract IERC20\\\",\\\"name\\\":\\\"collateralToken\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"baseRate\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"contract IERC20\\\",\\\"name\\\":\\\"collateralToken\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"borrowingSpread\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"contract IERC20\\\",\\\"name\\\":\\\"collateralToken\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"collateralEnabled\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"bool\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"bool\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"contract IERC20\\\",\\\"name\\\":\\\"collateralToken\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"collateralInfo\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"contract IERC20Indexable\\\",\\\"name\\\":\\\"collateralToken\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"contract IERC20Indexable\\\",\\\"name\\\":\\\"debtToken\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"contract IPriceFeed\\\",\\\"name\\\":\\\"priceFeed\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"contract ISplitLiquidationCollateral\\\",\\\"name\\\":\\\"splitLiquidation\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"bool\\\",\\\"name\\\":\\\"isEnabled\\\",\\\"type\\\":\\\"bool\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"lastFeeOperationTime\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"borrowingSpread\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"baseRate\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"redemptionSpread\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"redemptionRebate\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"position\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"collateralTokenForPosition\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"contract IERC20\\\",\\\"name\\\":\\\"collateralToken\\\",\\\"type\\\":\\\"address\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"decimals\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint8\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint8\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"spender\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"subtractedValue\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"decreaseAllowance\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"bool\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"bool\\\"}],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"feeRecipient\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"address\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"contract IERC20\\\",\\\"name\\\":\\\"collateralToken\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"debtAmount\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"getBorrowingFee\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"contract IERC20\\\",\\\"name\\\":\\\"collateralToken\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"getBorrowingRate\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"contract IERC20\\\",\\\"name\\\":\\\"collateralToken\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"getBorrowingRateWithDecay\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"contract IERC20\\\",\\\"name\\\":\\\"collateralToken\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"collateralAmount\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"priceDeviation\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"getRedemptionFee\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"contract IERC20\\\",\\\"name\\\":\\\"collateralToken\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"collateralAmount\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"getRedemptionFeeWithDecay\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"redemptionFee\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"contract IERC20\\\",\\\"name\\\":\\\"collateralToken\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"getRedemptionRate\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"contract IERC20\\\",\\\"name\\\":\\\"collateralToken\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"getRedemptionRateWithDecay\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"spender\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"addedValue\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"increaseAllowance\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"bool\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"bool\\\"}],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"position\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"delegate\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"isDelegateWhitelisted\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"bool\\\",\\\"name\\\":\\\"isWhitelisted\\\",\\\"type\\\":\\\"bool\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"contract IERC20\\\",\\\"name\\\":\\\"collateralToken\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"lastFeeOperationTime\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"position\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"liquidate\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"contract IERC20\\\",\\\"name\\\":\\\"collateralToken\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"position\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"collateralChange\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"bool\\\",\\\"name\\\":\\\"isCollateralIncrease\\\",\\\"type\\\":\\\"bool\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"debtChange\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"bool\\\",\\\"name\\\":\\\"isDebtIncrease\\\",\\\"type\\\":\\\"bool\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"maxFeePercentage\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"components\\\":[{\\\"internalType\\\":\\\"contract IERC20Permit\\\",\\\"name\\\":\\\"token\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"value\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"deadline\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"uint8\\\",\\\"name\\\":\\\"v\\\",\\\"type\\\":\\\"uint8\\\"},{\\\"internalType\\\":\\\"bytes32\\\",\\\"name\\\":\\\"r\\\",\\\"type\\\":\\\"bytes32\\\"},{\\\"internalType\\\":\\\"bytes32\\\",\\\"name\\\":\\\"s\\\",\\\"type\\\":\\\"bytes32\\\"}],\\\"internalType\\\":\\\"struct ERC20PermitSignature\\\",\\\"name\\\":\\\"permitSignature\\\",\\\"type\\\":\\\"tuple\\\"}],\\\"name\\\":\\\"managePosition\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"actualCollateralChange\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"actualDebtChange\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"contract IERC20\\\",\\\"name\\\":\\\"collateralToken\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"amount\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"mintFees\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"name\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"string\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"string\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"owner\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"address\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"pendingOwner\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"address\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"positionManager\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"contract IPositionManager\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"address\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"contract IERC20\\\",\\\"name\\\":\\\"collateralToken\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"priceFeed\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"contract IPriceFeed\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"address\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"r\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"contract IRToken\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"address\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"rToken\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"contract IRToken\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"address\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"contract IERC20\\\",\\\"name\\\":\\\"collateralToken\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"raftCollateralToken\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"contract IERC20Indexable\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"address\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"contract IERC20\\\",\\\"name\\\":\\\"collateralToken\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"raftDebtToken\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"contract IERC20Indexable\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"address\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"contract IERC20\\\",\\\"name\\\":\\\"token\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"to\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"amount\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"recoverTokens\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"contract IERC20\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"redeemCollateral\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"contract IERC20\\\",\\\"name\\\":\\\"collateralToken\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"redemptionRebate\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"contract IERC20\\\",\\\"name\\\":\\\"collateralToken\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"redemptionSpread\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"renounceOwnership\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"contract IERC20\\\",\\\"name\\\":\\\"collateralToken\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"newBorrowingSpread\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"setBorrowingSpread\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"contract IERC20\\\",\\\"name\\\":\\\"collateralToken\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"bool\\\",\\\"name\\\":\\\"isEnabled\\\",\\\"type\\\":\\\"bool\\\"}],\\\"name\\\":\\\"setCollateralEnabled\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"newFeeRecipient\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"setFeeRecipient\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"contract IERC20\\\",\\\"name\\\":\\\"collateralToken\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"newRedemptionRebate\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"setRedemptionRebate\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"contract IERC20\\\",\\\"name\\\":\\\"collateralToken\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"newRedemptionSpread\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"setRedemptionSpread\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"contract IERC20\\\",\\\"name\\\":\\\"collateralToken\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"contract ISplitLiquidationCollateral\\\",\\\"name\\\":\\\"newSplitLiquidationCollateral\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"setSplitLiquidationCollateral\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"contract IERC20\\\",\\\"name\\\":\\\"collateralToken\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"splitLiquidationCollateral\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"contract ISplitLiquidationCollateral\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"address\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"symbol\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"string\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"string\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"totalSupply\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"to\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"amount\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"transfer\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"bool\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"bool\\\"}],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"from\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"to\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"amount\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"transferFrom\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"bool\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"bool\\\"}],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"newOwner\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"transferOwnership\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"delegate\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"bool\\\",\\\"name\\\":\\\"whitelisted\\\",\\\"type\\\":\\\"bool\\\"}],\\\"name\\\":\\\"whitelistDelegate\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"}]\",\"ContractName\":\"InterestRatePositionManager\",\"CompilerVersion\":\"v0.8.19+commit.7dd6d404\",\"OptimizationUsed\":1,\"Runs\":200000,\"ConstructorArguments\":\"0x000000000000000000000000183015a9ba6ff60230fdeadc3f43b3d788b13e21\",\"EVMVersion\":\"london\",\"Library\":\"\",\"LicenseType\":\"\",\"Proxy\":0,\"SwarmSource\":\"\"}]"
  },
  {
    "path": "testdata/etherscan/0x9d27527Ada2CF29fBDAB2973cfa243845a08Bd3F/creation_data.json",
    "content": "{\n  \"contractAddress\": \"0x9d27527ada2cf29fbdab2973cfa243845a08bd3f\",\n  \"contractCreator\": \"0x7773ae67403d2e30102a84c48cc939919c4c881c\",\n  \"txHash\": \"0xc757719b7ae11ea651b1b23249978a3e8fca94d358610f5809a5dc19fbf850ce\"\n}"
  },
  {
    "path": "testdata/etherscan/0x9d27527Ada2CF29fBDAB2973cfa243845a08Bd3F/metadata.json",
    "content": "[\n  {\n    \"SourceCode\": {\n      \"language\": \"Solidity\",\n      \"sources\": {\n        \"@openzeppelin/contracts/utils/Address.sol\": {\n          \"content\": \"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n    /**\\n     * @dev Returns true if `account` is a contract.\\n     *\\n     * [IMPORTANT]\\n     * ====\\n     * It is unsafe to assume that an address for which this function returns\\n     * false is an externally-owned account (EOA) and not a contract.\\n     *\\n     * Among others, `isContract` will return false for the following\\n     * types of addresses:\\n     *\\n     *  - an externally-owned account\\n     *  - a contract in construction\\n     *  - an address where a contract will be created\\n     *  - an address where a contract lived, but was destroyed\\n     * ====\\n     */\\n    function isContract(address account) internal view returns (bool) {\\n        // This method relies on extcodesize, which returns 0 for contracts in\\n        // construction, since the code is only stored at the end of the\\n        // constructor execution.\\n\\n        uint256 size;\\n        assembly {\\n            size := extcodesize(account)\\n        }\\n        return size > 0;\\n    }\\n\\n    /**\\n     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n     * `recipient`, forwarding all available gas and reverting on errors.\\n     *\\n     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n     * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n     * imposed by `transfer`, making them unable to receive funds via\\n     * `transfer`. {sendValue} removes this limitation.\\n     *\\n     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n     *\\n     * IMPORTANT: because control is transferred to `recipient`, care must be\\n     * taken to not create reentrancy vulnerabilities. Consider using\\n     * {ReentrancyGuard} or the\\n     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n     */\\n    function sendValue(address payable recipient, uint256 amount) internal {\\n        require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n        (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n        require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n    }\\n\\n    /**\\n     * @dev Performs a Solidity function call using a low level `call`. A\\n     * plain `call` is an unsafe replacement for a function call: use this\\n     * function instead.\\n     *\\n     * If `target` reverts with a revert reason, it is bubbled up by this\\n     * function (like regular Solidity function calls).\\n     *\\n     * Returns the raw returned data. To convert to the expected return value,\\n     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n     *\\n     * Requirements:\\n     *\\n     * - `target` must be a contract.\\n     * - calling `target` with `data` must not revert.\\n     *\\n     * _Available since v3.1._\\n     */\\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n        return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n    }\\n\\n    /**\\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n     * `errorMessage` as a fallback revert reason when `target` reverts.\\n     *\\n     * _Available since v3.1._\\n     */\\n    function functionCall(\\n        address target,\\n        bytes memory data,\\n        string memory errorMessage\\n    ) internal returns (bytes memory) {\\n        return functionCallWithValue(target, data, 0, errorMessage);\\n    }\\n\\n    /**\\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n     * but also transferring `value` wei to `target`.\\n     *\\n     * Requirements:\\n     *\\n     * - the calling contract must have an ETH balance of at least `value`.\\n     * - the called Solidity function must be `payable`.\\n     *\\n     * _Available since v3.1._\\n     */\\n    function functionCallWithValue(\\n        address target,\\n        bytes memory data,\\n        uint256 value\\n    ) internal returns (bytes memory) {\\n        return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n    }\\n\\n    /**\\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\\n     *\\n     * _Available since v3.1._\\n     */\\n    function functionCallWithValue(\\n        address target,\\n        bytes memory data,\\n        uint256 value,\\n        string memory errorMessage\\n    ) internal returns (bytes memory) {\\n        require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n        require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\\n        return verifyCallResult(success, returndata, errorMessage);\\n    }\\n\\n    /**\\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n     * but performing a static call.\\n     *\\n     * _Available since v3.3._\\n     */\\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n        return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n    }\\n\\n    /**\\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n     * but performing a static call.\\n     *\\n     * _Available since v3.3._\\n     */\\n    function functionStaticCall(\\n        address target,\\n        bytes memory data,\\n        string memory errorMessage\\n    ) internal view returns (bytes memory) {\\n        require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n        (bool success, bytes memory returndata) = target.staticcall(data);\\n        return verifyCallResult(success, returndata, errorMessage);\\n    }\\n\\n    /**\\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n     * but performing a delegate call.\\n     *\\n     * _Available since v3.4._\\n     */\\n    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n        return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n    }\\n\\n    /**\\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n     * but performing a delegate call.\\n     *\\n     * _Available since v3.4._\\n     */\\n    function functionDelegateCall(\\n        address target,\\n        bytes memory data,\\n        string memory errorMessage\\n    ) internal returns (bytes memory) {\\n        require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n        (bool success, bytes memory returndata) = target.delegatecall(data);\\n        return verifyCallResult(success, returndata, errorMessage);\\n    }\\n\\n    /**\\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n     * revert reason using the provided one.\\n     *\\n     * _Available since v4.3._\\n     */\\n    function verifyCallResult(\\n        bool success,\\n        bytes memory returndata,\\n        string memory errorMessage\\n    ) internal pure returns (bytes memory) {\\n        if (success) {\\n            return returndata;\\n        } else {\\n            // Look for revert reason and bubble it up if present\\n            if (returndata.length > 0) {\\n                // The easiest way to bubble the revert reason is using memory via assembly\\n\\n                assembly {\\n                    let returndata_size := mload(returndata)\\n                    revert(add(32, returndata), returndata_size)\\n                }\\n            } else {\\n                revert(errorMessage);\\n            }\\n        }\\n    }\\n}\\n\"\n        },\n        \"src/base/ERC721Checkpointable.sol\": {\n          \"content\": \"// SPDX-License-Identifier: BSD-3-Clause\\n\\n/// @title Vote checkpointing for an ERC-721 token\\n\\n/*********************************\\n * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *\\n * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *\\n * ░░░░░░█████████░░█████████░░░ *\\n * ░░░░░░██░░░████░░██░░░████░░░ *\\n * ░░██████░░░████████░░░████░░░ *\\n * ░░██░░██░░░████░░██░░░████░░░ *\\n * ░░██░░██░░░████░░██░░░████░░░ *\\n * ░░░░░░█████████░░█████████░░░ *\\n * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *\\n * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *\\n *********************************/\\n\\n// LICENSE\\n// ERC721Checkpointable.sol uses and modifies part of Compound Lab's Comp.sol:\\n// https://github.com/compound-finance/compound-protocol/blob/ae4388e780a8d596d97619d9704a931a2752c2bc/contracts/Governance/Comp.sol\\n//\\n// Comp.sol source code Copyright 2020 Compound Labs, Inc. licensed under the BSD-3-Clause license.\\n// With modifications by Nounders DAO.\\n//\\n// Additional conditions of BSD-3-Clause can be found here: https://opensource.org/licenses/BSD-3-Clause\\n//\\n// MODIFICATIONS\\n// Checkpointing logic from Comp.sol has been used with the following modifications:\\n// - `delegates` is renamed to `_delegates` and is set to private\\n// - `delegates` is a public function that uses the `_delegates` mapping look-up, but unlike\\n//   Comp.sol, returns the delegator's own address if there is no delegate.\\n//   This avoids the delegator needing to \\\"delegate to self\\\" with an additional transaction\\n// - `_transferTokens()` is renamed `_beforeTokenTransfer()` and adapted to hook into OpenZeppelin's ERC721 hooks.\\n\\npragma solidity 0.8.9;\\n\\nimport \\\"./ERC721BaseWithERC4494Permit.sol\\\";\\n\\nabstract contract ERC721Checkpointable is ERC721BaseWithERC4494Permit {\\n    bool internal _useCheckpoints = true; // can only be disabled and never re-enabled\\n\\n    /// @notice Defines decimals as per ERC-20 convention to make integrations with 3rd party governance platforms easier\\n    uint8 public constant decimals = 0;\\n\\n    /// @notice A record of each accounts delegate\\n    mapping(address => address) private _delegates;\\n\\n    /// @notice A checkpoint for marking number of votes from a given block\\n    struct Checkpoint {\\n        uint32 fromBlock;\\n        uint96 votes;\\n    }\\n\\n    /// @notice A record of votes checkpoints for each account, by index\\n    mapping(address => mapping(uint32 => Checkpoint)) public checkpoints;\\n\\n    /// @notice The number of checkpoints for each account\\n    mapping(address => uint32) public numCheckpoints;\\n\\n    /// @notice The EIP-712 typehash for the delegation struct used by the contract\\n    bytes32 public constant DELEGATION_TYPEHASH =\\n        keccak256(\\\"Delegation(address delegatee,uint256 nonce,uint256 expiry)\\\");\\n\\n    /// @notice An event thats emitted when an account changes its delegate\\n    event DelegateChanged(address indexed delegator, address indexed fromDelegate, address indexed toDelegate);\\n\\n    /// @notice An event thats emitted when a delegate account's vote balance changes\\n    event DelegateVotesChanged(address indexed delegate, uint256 previousBalance, uint256 newBalance);\\n\\n    /**\\n     * @notice The votes a delegator can delegate, which is the current balance of the delegator.\\n     * @dev Used when calling `_delegate()`\\n     */\\n    function votesToDelegate(address delegator) public view returns (uint96) {\\n        return safe96(balanceOf(delegator), \\\"ERC721Checkpointable::votesToDelegate: amount exceeds 96 bits\\\");\\n    }\\n\\n    /**\\n     * @notice Overrides the standard `Comp.sol` delegates mapping to return\\n     * the delegator's own address if they haven't delegated.\\n     * This avoids having to delegate to oneself.\\n     */\\n    function delegates(address delegator) public view returns (address) {\\n        address current = _delegates[delegator];\\n        return current == address(0) ? delegator : current;\\n    }\\n\\n    /**\\n     * @notice Adapted from `_transferTokens()` in `Comp.sol` to update delegate votes.\\n     * @dev hooks into ERC721Base's `ERC721._transfer`\\n     */\\n    function _beforeTokenTransfer(\\n        address from,\\n        address to,\\n        uint256 tokenId\\n    ) internal override {\\n        super._beforeTokenTransfer(from, to, tokenId);\\n        if (_useCheckpoints) {\\n            /// @notice Differs from `_transferTokens()` to use `delegates` override method to simulate auto-delegation\\n            _moveDelegates(delegates(from), delegates(to), 1);\\n        }\\n    }\\n\\n    /**\\n     * @notice Delegate votes from `msg.sender` to `delegatee`\\n     * @param delegatee The address to delegate votes to\\n     */\\n    function delegate(address delegatee) public {\\n        if (delegatee == address(0)) delegatee = msg.sender;\\n        return _delegate(msg.sender, delegatee);\\n    }\\n\\n    /**\\n     * @notice Delegates votes from signatory to `delegatee`\\n     * @param delegatee The address to delegate votes to\\n     * @param nonce The contract state required to match the signature\\n     * @param expiry The time at which to expire the signature\\n     * @param v The recovery byte of the signature\\n     * @param r Half of the ECDSA signature pair\\n     * @param s Half of the ECDSA signature pair\\n     */\\n    function delegateBySig(\\n        address delegatee,\\n        uint256 nonce,\\n        uint256 expiry,\\n        uint8 v,\\n        bytes32 r,\\n        bytes32 s\\n    ) public {\\n        bytes32 digest = keccak256(\\n            abi.encodePacked(\\n                \\\"\\\\x19\\\\x01\\\",\\n                _DOMAIN_SEPARATOR(),\\n                keccak256(abi.encode(DELEGATION_TYPEHASH, delegatee, nonce, expiry))\\n            )\\n        );\\n        // TODO support smart contract wallet via IERC721, require change in function signature to know which signer to call first\\n        address signatory = ecrecover(digest, v, r, s);\\n        require(signatory != address(0), \\\"ERC721Checkpointable::delegateBySig: invalid signature\\\");\\n        require(nonce == _userNonces[signatory]++, \\\"ERC721Checkpointable::delegateBySig: invalid nonce\\\");\\n        require(block.timestamp <= expiry, \\\"ERC721Checkpointable::delegateBySig: signature expired\\\");\\n        return _delegate(signatory, delegatee);\\n    }\\n\\n    /**\\n     * @notice Gets the current votes balance for `account`\\n     * @param account The address to get votes balance\\n     * @return The number of current votes for `account`\\n     */\\n    function getCurrentVotes(address account) public view returns (uint96) {\\n        uint32 nCheckpoints = numCheckpoints[account];\\n        return nCheckpoints > 0 ? checkpoints[account][nCheckpoints - 1].votes : 0;\\n    }\\n\\n    /**\\n     * @notice Gets the current votes balance for `account`\\n     * @param account The address to get votes balance\\n     * @return The number of current votes for `account`\\n     */\\n    function getVotes(address account) external view returns (uint96) {\\n        return getCurrentVotes(account);\\n    }\\n\\n    /**\\n     * @notice Determine the prior number of votes for an account as of a block number\\n     * @dev Block number must be a finalized block or else this function will revert to prevent misinformation.\\n     * @param account The address of the account to check\\n     * @param blockNumber The block number to get the vote balance at\\n     * @return The number of votes the account had as of the given block\\n     */\\n    function getPriorVotes(address account, uint256 blockNumber) public view returns (uint96) {\\n        require(blockNumber < block.number, \\\"ERC721Checkpointable::getPriorVotes: not yet determined\\\");\\n\\n        uint32 nCheckpoints = numCheckpoints[account];\\n        if (nCheckpoints == 0) {\\n            return 0;\\n        }\\n\\n        // First check most recent balance\\n        if (checkpoints[account][nCheckpoints - 1].fromBlock <= blockNumber) {\\n            return checkpoints[account][nCheckpoints - 1].votes;\\n        }\\n\\n        // Next check implicit zero balance\\n        if (checkpoints[account][0].fromBlock > blockNumber) {\\n            return 0;\\n        }\\n\\n        uint32 lower = 0;\\n        uint32 upper = nCheckpoints - 1;\\n        while (upper > lower) {\\n            uint32 center = upper - (upper - lower) / 2; // ceil, avoiding overflow\\n            Checkpoint memory cp = checkpoints[account][center];\\n            if (cp.fromBlock == blockNumber) {\\n                return cp.votes;\\n            } else if (cp.fromBlock < blockNumber) {\\n                lower = center;\\n            } else {\\n                upper = center - 1;\\n            }\\n        }\\n        return checkpoints[account][lower].votes;\\n    }\\n\\n    /**\\n     * @notice Determine the prior number of votes for an account as of a block number\\n     * @dev Block number must be a finalized block or else this function will revert to prevent misinformation.\\n     * @param account The address of the account to check\\n     * @param blockNumber The block number to get the vote balance at\\n     * @return The number of votes the account had as of the given block\\n     */\\n    function getPastVotes(address account, uint256 blockNumber) external view returns (uint96) {\\n        return this.getPriorVotes(account, blockNumber);\\n    }\\n\\n    function _delegate(address delegator, address delegatee) internal {\\n        /// @notice differs from `_delegate()` in `Comp.sol` to use `delegates` override method to simulate auto-delegation\\n        address currentDelegate = delegates(delegator);\\n\\n        _delegates[delegator] = delegatee;\\n\\n        emit DelegateChanged(delegator, currentDelegate, delegatee);\\n\\n        uint96 amount = votesToDelegate(delegator);\\n\\n        _moveDelegates(currentDelegate, delegatee, amount);\\n    }\\n\\n    function _moveDelegates(\\n        address srcRep,\\n        address dstRep,\\n        uint96 amount\\n    ) internal {\\n        if (srcRep != dstRep && amount > 0) {\\n            if (srcRep != address(0)) {\\n                uint32 srcRepNum = numCheckpoints[srcRep];\\n                uint96 srcRepOld = srcRepNum > 0 ? checkpoints[srcRep][srcRepNum - 1].votes : 0;\\n                uint96 srcRepNew = sub96(srcRepOld, amount, \\\"ERC721Checkpointable::_moveDelegates: amount underflows\\\");\\n                _writeCheckpoint(srcRep, srcRepNum, srcRepOld, srcRepNew);\\n            }\\n\\n            if (dstRep != address(0)) {\\n                uint32 dstRepNum = numCheckpoints[dstRep];\\n                uint96 dstRepOld = dstRepNum > 0 ? checkpoints[dstRep][dstRepNum - 1].votes : 0;\\n                uint96 dstRepNew = add96(dstRepOld, amount, \\\"ERC721Checkpointable::_moveDelegates: amount overflows\\\");\\n                _writeCheckpoint(dstRep, dstRepNum, dstRepOld, dstRepNew);\\n            }\\n        }\\n    }\\n\\n    function _writeCheckpoint(\\n        address delegatee,\\n        uint32 nCheckpoints,\\n        uint96 oldVotes,\\n        uint96 newVotes\\n    ) internal {\\n        uint32 blockNumber = safe32(\\n            block.number,\\n            \\\"ERC721Checkpointable::_writeCheckpoint: block number exceeds 32 bits\\\"\\n        );\\n\\n        if (nCheckpoints > 0 && checkpoints[delegatee][nCheckpoints - 1].fromBlock == blockNumber) {\\n            checkpoints[delegatee][nCheckpoints - 1].votes = newVotes;\\n        } else {\\n            checkpoints[delegatee][nCheckpoints] = Checkpoint(blockNumber, newVotes);\\n            numCheckpoints[delegatee] = nCheckpoints + 1;\\n        }\\n\\n        emit DelegateVotesChanged(delegatee, oldVotes, newVotes);\\n    }\\n\\n    function safe32(uint256 n, string memory errorMessage) internal pure returns (uint32) {\\n        require(n < 2**32, errorMessage);\\n        return uint32(n);\\n    }\\n\\n    function safe96(uint256 n, string memory errorMessage) internal pure returns (uint96) {\\n        require(n < 2**96, errorMessage);\\n        return uint96(n);\\n    }\\n\\n    function add96(\\n        uint96 a,\\n        uint96 b,\\n        string memory errorMessage\\n    ) internal pure returns (uint96) {\\n        uint96 c = a + b;\\n        require(c >= a, errorMessage);\\n        return c;\\n    }\\n\\n    function sub96(\\n        uint96 a,\\n        uint96 b,\\n        string memory errorMessage\\n    ) internal pure returns (uint96) {\\n        require(b <= a, errorMessage);\\n        return a - b;\\n    }\\n}\\n\"\n        },\n        \"src/base/ERC721Base.sol\": {\n          \"content\": \"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.9;\\n\\nimport \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC721/IERC721.sol\\\";\\nimport \\\"@openzeppelin/contracts/interfaces/IERC165.sol\\\";\\n\\nabstract contract ERC721Base is IERC165, IERC721 {\\n    using Address for address;\\n\\n    bytes4 internal constant ERC721_RECEIVED = 0x150b7a02;\\n    bytes4 internal constant ERC165ID = 0x01ffc9a7;\\n\\n    uint256 internal constant OPERATOR_FLAG = 0x8000000000000000000000000000000000000000000000000000000000000000;\\n    uint256 internal constant NOT_OPERATOR_FLAG = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;\\n\\n    mapping(uint256 => uint256) internal _owners;\\n    mapping(address => uint256) internal _balances;\\n    mapping(address => mapping(address => bool)) internal _operatorsForAll;\\n    mapping(uint256 => address) internal _operators;\\n\\n    function name() public pure virtual returns (string memory) {\\n        revert(\\\"NOT_IMPLEMENTED\\\");\\n    }\\n\\n    /// @notice Approve an operator to transfer a specific token on the senders behalf.\\n    /// @param operator The address receiving the approval.\\n    /// @param id The id of the token.\\n    function approve(address operator, uint256 id) external override {\\n        (address owner, uint256 blockNumber) = _ownerAndBlockNumberOf(id);\\n        require(owner != address(0), \\\"NONEXISTENT_TOKEN\\\");\\n        require(msg.sender == owner || isApprovedForAll(owner, msg.sender), \\\"UNAUTHORIZED_APPROVAL\\\");\\n        _approveFor(owner, blockNumber, operator, id);\\n    }\\n\\n    /// @notice Transfer a token between 2 addresses.\\n    /// @param from The sender of the token.\\n    /// @param to The recipient of the token.\\n    /// @param id The id of the token.\\n    function transferFrom(\\n        address from,\\n        address to,\\n        uint256 id\\n    ) external override {\\n        (address owner, bool operatorEnabled) = _ownerAndOperatorEnabledOf(id);\\n        require(owner != address(0), \\\"NONEXISTENT_TOKEN\\\");\\n        require(owner == from, \\\"NOT_OWNER\\\");\\n        require(to != address(0), \\\"NOT_TO_ZEROADDRESS\\\");\\n        require(to != address(this), \\\"NOT_TO_THIS\\\");\\n        if (msg.sender != from) {\\n            require(\\n                (operatorEnabled && _operators[id] == msg.sender) || isApprovedForAll(from, msg.sender),\\n                \\\"UNAUTHORIZED_TRANSFER\\\"\\n            );\\n        }\\n        _transferFrom(from, to, id);\\n    }\\n\\n    /// @notice Transfer a token between 2 addresses letting the receiver know of the transfer.\\n    /// @param from The send of the token.\\n    /// @param to The recipient of the token.\\n    /// @param id The id of the token.\\n    function safeTransferFrom(\\n        address from,\\n        address to,\\n        uint256 id\\n    ) external override {\\n        safeTransferFrom(from, to, id, \\\"\\\");\\n    }\\n\\n    /// @notice Set the approval for an operator to manage all the tokens of the sender.\\n    /// @param operator The address receiving the approval.\\n    /// @param approved The determination of the approval.\\n    function setApprovalForAll(address operator, bool approved) external override {\\n        _setApprovalForAll(msg.sender, operator, approved);\\n    }\\n\\n    /// @notice Get the number of tokens owned by an address.\\n    /// @param owner The address to look for.\\n    /// @return balance The number of tokens owned by the address.\\n    function balanceOf(address owner) public view override returns (uint256 balance) {\\n        require(owner != address(0), \\\"ZERO_ADDRESS_OWNER\\\");\\n        balance = _balances[owner];\\n    }\\n\\n    /// @notice Get the owner of a token.\\n    /// @param id The id of the token.\\n    /// @return owner The address of the token owner.\\n    function ownerOf(uint256 id) external view override returns (address owner) {\\n        owner = _ownerOf(id);\\n        require(owner != address(0), \\\"NONEXISTENT_TOKEN\\\");\\n    }\\n\\n    /// @notice Get the owner of a token and the blockNumber of the last transfer, useful to voting mechanism.\\n    /// @param id The id of the token.\\n    /// @return owner The address of the token owner.\\n    /// @return blockNumber The blocknumber at which the last transfer of that id happened.\\n    function ownerAndLastTransferBlockNumberOf(uint256 id) internal view returns (address owner, uint256 blockNumber) {\\n        return _ownerAndBlockNumberOf(id);\\n    }\\n\\n    struct OwnerData {\\n        address owner;\\n        uint256 lastTransferBlockNumber;\\n    }\\n\\n    /// @notice Get the list of owner of a token and the blockNumber of its last transfer, useful to voting mechanism.\\n    /// @param ids The list of token ids to check.\\n    /// @return ownersData The list of (owner, lastTransferBlockNumber) for each ids given as input.\\n    function ownerAndLastTransferBlockNumberList(uint256[] calldata ids)\\n        external\\n        view\\n        returns (OwnerData[] memory ownersData)\\n    {\\n        ownersData = new OwnerData[](ids.length);\\n        for (uint256 i = 0; i < ids.length; i++) {\\n            uint256 data = _owners[ids[i]];\\n            ownersData[i].owner = address(uint160(data));\\n            ownersData[i].lastTransferBlockNumber = (data >> 160) & 0xFFFFFFFFFFFFFFFFFFFFFF;\\n        }\\n    }\\n\\n    /// @notice Get the approved operator for a specific token.\\n    /// @param id The id of the token.\\n    /// @return The address of the operator.\\n    function getApproved(uint256 id) external view override returns (address) {\\n        (address owner, bool operatorEnabled) = _ownerAndOperatorEnabledOf(id);\\n        require(owner != address(0), \\\"NONEXISTENT_TOKEN\\\");\\n        if (operatorEnabled) {\\n            return _operators[id];\\n        } else {\\n            return address(0);\\n        }\\n    }\\n\\n    /// @notice Check if the sender approved the operator.\\n    /// @param owner The address of the owner.\\n    /// @param operator The address of the operator.\\n    /// @return isOperator The status of the approval.\\n    function isApprovedForAll(address owner, address operator) public view virtual override returns (bool isOperator) {\\n        return _operatorsForAll[owner][operator];\\n    }\\n\\n    /// @notice Transfer a token between 2 addresses letting the receiver knows of the transfer.\\n    /// @param from The sender of the token.\\n    /// @param to The recipient of the token.\\n    /// @param id The id of the token.\\n    /// @param data Additional data.\\n    function safeTransferFrom(\\n        address from,\\n        address to,\\n        uint256 id,\\n        bytes memory data\\n    ) public override {\\n        (address owner, bool operatorEnabled) = _ownerAndOperatorEnabledOf(id);\\n        require(owner != address(0), \\\"NONEXISTENT_TOKEN\\\");\\n        require(owner == from, \\\"NOT_OWNER\\\");\\n        require(to != address(0), \\\"NOT_TO_ZEROADDRESS\\\");\\n        require(to != address(this), \\\"NOT_TO_THIS\\\");\\n        if (msg.sender != from) {\\n            require(\\n                (operatorEnabled && _operators[id] == msg.sender) || isApprovedForAll(from, msg.sender),\\n                \\\"UNAUTHORIZED_TRANSFER\\\"\\n            );\\n        }\\n        _safeTransferFrom(from, to, id, data);\\n    }\\n\\n    /// @notice Check if the contract supports an interface.\\n    /// @param id The id of the interface.\\n    /// @return Whether the interface is supported.\\n    function supportsInterface(bytes4 id) public pure virtual override returns (bool) {\\n        /// 0x01ffc9a7 is ERC165.\\n        /// 0x80ac58cd is ERC721\\n        /// 0x5b5e139f is for ERC721 metadata\\n        return id == 0x01ffc9a7 || id == 0x80ac58cd || id == 0x5b5e139f;\\n    }\\n\\n    function _safeTransferFrom(\\n        address from,\\n        address to,\\n        uint256 id,\\n        bytes memory data\\n    ) internal {\\n        _transferFrom(from, to, id);\\n        if (to.isContract()) {\\n            require(_checkOnERC721Received(msg.sender, from, to, id, data), \\\"ERC721_TRANSFER_REJECTED\\\");\\n        }\\n    }\\n\\n    function _beforeTokenTransfer(\\n        address from,\\n        address to,\\n        uint256 id\\n    ) internal virtual {}\\n\\n    function _transferFrom(\\n        address from,\\n        address to,\\n        uint256 id\\n    ) internal {\\n        _beforeTokenTransfer(from, to, id);\\n        unchecked {\\n            _balances[to]++;\\n            if (from != address(0)) {\\n                _balances[from]--;\\n            }\\n        }\\n        _owners[id] = (block.number << 160) | uint256(uint160(to));\\n        emit Transfer(from, to, id);\\n    }\\n\\n    /// @dev See approve.\\n    function _approveFor(\\n        address owner,\\n        uint256 blockNumber,\\n        address operator,\\n        uint256 id\\n    ) internal {\\n        if (operator == address(0)) {\\n            _owners[id] = (blockNumber << 160) | uint256(uint160(owner));\\n        } else {\\n            _owners[id] = OPERATOR_FLAG | (blockNumber << 160) | uint256(uint160(owner));\\n            _operators[id] = operator;\\n        }\\n        emit Approval(owner, operator, id);\\n    }\\n\\n    /// @dev See setApprovalForAll.\\n    function _setApprovalForAll(\\n        address sender,\\n        address operator,\\n        bool approved\\n    ) internal {\\n        _operatorsForAll[sender][operator] = approved;\\n\\n        emit ApprovalForAll(sender, operator, approved);\\n    }\\n\\n    /// @dev Check if receiving contract accepts erc721 transfers.\\n    /// @param operator The address of the operator.\\n    /// @param from The from address, may be different from msg.sender.\\n    /// @param to The adddress we want to transfer to.\\n    /// @param id The id of the token we would like to transfer.\\n    /// @param _data Any additional data to send with the transfer.\\n    /// @return Whether the expected value of 0x150b7a02 is returned.\\n    function _checkOnERC721Received(\\n        address operator,\\n        address from,\\n        address to,\\n        uint256 id,\\n        bytes memory _data\\n    ) internal returns (bool) {\\n        bytes4 retval = IERC721Receiver(to).onERC721Received(operator, from, id, _data);\\n        return (retval == ERC721_RECEIVED);\\n    }\\n\\n    /// @dev See ownerOf\\n    function _ownerOf(uint256 id) internal view returns (address owner) {\\n        return address(uint160(_owners[id]));\\n    }\\n\\n    /// @dev Get the owner and operatorEnabled status of a token.\\n    /// @param id The token to query.\\n    /// @return owner The owner of the token.\\n    /// @return operatorEnabled Whether or not operators are enabled for this token.\\n    function _ownerAndOperatorEnabledOf(uint256 id) internal view returns (address owner, bool operatorEnabled) {\\n        uint256 data = _owners[id];\\n        owner = address(uint160(data));\\n        operatorEnabled = (data & OPERATOR_FLAG) == OPERATOR_FLAG;\\n    }\\n\\n    // @dev Get the owner and operatorEnabled status of a token.\\n    /// @param id The token to query.\\n    /// @return owner The owner of the token.\\n    /// @return blockNumber the blockNumber at which the owner became the owner (last transfer).\\n    function _ownerAndBlockNumberOf(uint256 id) internal view returns (address owner, uint256 blockNumber) {\\n        uint256 data = _owners[id];\\n        owner = address(uint160(data));\\n        blockNumber = (data >> 160) & 0xFFFFFFFFFFFFFFFFFFFFFF;\\n    }\\n\\n    // from https://github.com/Uniswap/v3-periphery/blob/main/contracts/base/Multicall.sol\\n    /// @notice Call multiple functions in the current contract and return the data from all of them if they all succeed.\\n    /// @dev The `msg.value` should not be trusted for any method callable from multicall.\\n    /// @param data The encoded function data for each of the calls to make to this contract.\\n    /// @return results The results from each of the calls passed in via data.\\n    function multicall(bytes[] calldata data) public payable returns (bytes[] memory results) {\\n        results = new bytes[](data.length);\\n        for (uint256 i = 0; i < data.length; i++) {\\n            (bool success, bytes memory result) = address(this).delegatecall(data[i]);\\n\\n            if (!success) {\\n                // Next 5 lines from https://ethereum.stackexchange.com/a/83577\\n                if (result.length < 68) revert();\\n                assembly {\\n                    result := add(result, 0x04)\\n                }\\n                revert(abi.decode(result, (string)));\\n            }\\n\\n            results[i] = result;\\n        }\\n    }\\n}\\n\"\n        },\n        \"@openzeppelin/contracts/token/ERC20/IERC20.sol\": {\n          \"content\": \"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n    /**\\n     * @dev Returns the amount of tokens in existence.\\n     */\\n    function totalSupply() external view returns (uint256);\\n\\n    /**\\n     * @dev Returns the amount of tokens owned by `account`.\\n     */\\n    function balanceOf(address account) external view returns (uint256);\\n\\n    /**\\n     * @dev Moves `amount` tokens from the caller's account to `recipient`.\\n     *\\n     * Returns a boolean value indicating whether the operation succeeded.\\n     *\\n     * Emits a {Transfer} event.\\n     */\\n    function transfer(address recipient, uint256 amount) external returns (bool);\\n\\n    /**\\n     * @dev Returns the remaining number of tokens that `spender` will be\\n     * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n     * zero by default.\\n     *\\n     * This value changes when {approve} or {transferFrom} are called.\\n     */\\n    function allowance(address owner, address spender) external view returns (uint256);\\n\\n    /**\\n     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n     *\\n     * Returns a boolean value indicating whether the operation succeeded.\\n     *\\n     * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n     * that someone may use both the old and the new allowance by unfortunate\\n     * transaction ordering. One possible solution to mitigate this race\\n     * condition is to first reduce the spender's allowance to 0 and set the\\n     * desired value afterwards:\\n     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n     *\\n     * Emits an {Approval} event.\\n     */\\n    function approve(address spender, uint256 amount) external returns (bool);\\n\\n    /**\\n     * @dev Moves `amount` tokens from `sender` to `recipient` using the\\n     * allowance mechanism. `amount` is then deducted from the caller's\\n     * allowance.\\n     *\\n     * Returns a boolean value indicating whether the operation succeeded.\\n     *\\n     * Emits a {Transfer} event.\\n     */\\n    function transferFrom(\\n        address sender,\\n        address recipient,\\n        uint256 amount\\n    ) external returns (bool);\\n\\n    /**\\n     * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n     * another (`to`).\\n     *\\n     * Note that `value` may be zero.\\n     */\\n    event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n    /**\\n     * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n     * a call to {approve}. `value` is the new allowance.\\n     */\\n    event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\"\n        },\n        \"src/base/IERC4494.sol\": {\n          \"content\": \"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.9;\\n\\ninterface IERC4494 {\\n    function DOMAIN_SEPARATOR() external view returns (bytes32);\\n\\n    /// @notice Allows to retrieve current nonce for token\\n    /// @param tokenId token id\\n    /// @return current token nonce\\n    function nonces(uint256 tokenId) external view returns (uint256);\\n\\n    /// @notice function to be called by anyone to approve `spender` using a Permit signature\\n    /// @dev Anyone can call this to approve `spender`, even a third-party\\n    /// @param spender the actor to approve\\n    /// @param tokenId the token id\\n    /// @param deadline the deadline for the permit to be used\\n    /// @param signature permit\\n    function permit(\\n        address spender,\\n        uint256 tokenId,\\n        uint256 deadline,\\n        bytes memory signature\\n    ) external;\\n}\\n\\ninterface IERC4494Alternative {\\n    function DOMAIN_SEPARATOR() external view returns (bytes32);\\n\\n    /// @notice Allows to retrieve current nonce for token\\n    /// @param tokenId token id\\n    /// @return current token nonce\\n    function tokenNonces(uint256 tokenId) external view returns (uint256);\\n\\n    /// @notice function to be called by anyone to approve `spender` using a Permit signature\\n    /// @dev Anyone can call this to approve `spender`, even a third-party\\n    /// @param spender the actor to approve\\n    /// @param tokenId the token id\\n    /// @param deadline the deadline for the permit to be used\\n    /// @param signature permit\\n    function permit(\\n        address spender,\\n        uint256 tokenId,\\n        uint256 deadline,\\n        bytes memory signature\\n    ) external;\\n}\\n\"\n        },\n        \"src/bleeps/BleepsRoles.sol\": {\n          \"content\": \"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.9;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\ninterface ReverseRegistrar {\\n    function setName(string memory name) external returns (bytes32);\\n}\\n\\ninterface ENS {\\n    function owner(bytes32 node) external view returns (address);\\n}\\n\\ncontract BleepsRoles {\\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n    event TokenURIAdminSet(address newTokenURIAdmin);\\n    event RoyaltyAdminSet(address newRoyaltyAdmin);\\n    event MinterAdminSet(address newMinterAdmin);\\n    event GuardianSet(address newGuardian);\\n    event MinterSet(address newMinter);\\n\\n    bytes32 internal constant ADDR_REVERSE_NODE = 0x91d1777781884d03a6757a803996e38de2a42967fb37eeaca72729271025a9e2;\\n    ENS internal immutable _ens;\\n\\n    ///@notice the address of the current owner, that is able to set ENS names and withdraw ERC20 owned by the contract.\\n    address public owner;\\n\\n    /// @notice tokenURIAdmin can update the tokenURI contract, this is intended to be relinquished once the tokenURI has been heavily tested in the wild and that no modification are needed.\\n    address public tokenURIAdmin;\\n\\n    /// @notice address allowed to set royalty parameters\\n    address public royaltyAdmin;\\n\\n    /// @notice minterAdmin can update the minter. At the time being there is 576 Bleeps but there is space for extra instrument and the upper limit is 1024.\\n    /// could be given to the DAO later so instrument can be added, the sale of these new bleeps could benenfit the DAO too and add new members.\\n    address public minterAdmin;\\n\\n    /// @notice address allowed to mint, allow the sale contract to be separated from the token contract that can focus on the core logic\\n    /// Once all 1024 potential bleeps (there could be less, at minimum there are 576 bleeps) are minted, no minter can mint anymore\\n    address public minter;\\n\\n    /// @notice guardian has some special vetoing power to guide the direction of the DAO. It can only remove rights from the DAO. It could be used to immortalize rules.\\n    /// For example: the royalty setup could be frozen.\\n    address public guardian;\\n\\n    constructor(\\n        address ens,\\n        address initialOwner,\\n        address initialTokenURIAdmin,\\n        address initialMinterAdmin,\\n        address initialRoyaltyAdmin,\\n        address initialGuardian\\n    ) {\\n        _ens = ENS(ens);\\n        owner = initialOwner;\\n        tokenURIAdmin = initialTokenURIAdmin;\\n        royaltyAdmin = initialRoyaltyAdmin;\\n        minterAdmin = initialMinterAdmin;\\n        guardian = initialGuardian;\\n        emit OwnershipTransferred(address(0), initialOwner);\\n        emit TokenURIAdminSet(initialTokenURIAdmin);\\n        emit RoyaltyAdminSet(initialRoyaltyAdmin);\\n        emit MinterAdminSet(initialMinterAdmin);\\n        emit GuardianSet(initialGuardian);\\n    }\\n\\n    function setENSName(string memory name) external {\\n        require(msg.sender == owner, \\\"NOT_AUTHORIZED\\\");\\n        ReverseRegistrar reverseRegistrar = ReverseRegistrar(_ens.owner(ADDR_REVERSE_NODE));\\n        reverseRegistrar.setName(name);\\n    }\\n\\n    function withdrawERC20(IERC20 token, address to) external {\\n        require(msg.sender == owner, \\\"NOT_AUTHORIZED\\\");\\n        token.transfer(to, token.balanceOf(address(this)));\\n    }\\n\\n    /**\\n     * @notice Transfers ownership of the contract to a new account (`newOwner`).\\n     * Can only be called by the current owner.\\n     */\\n    function transferOwnership(address newOwner) external {\\n        address oldOwner = owner;\\n        require(msg.sender == oldOwner);\\n        owner = newOwner;\\n        emit OwnershipTransferred(oldOwner, newOwner);\\n    }\\n\\n    /**\\n     * @notice set the new tokenURIAdmin that can change the tokenURI\\n     * Can only be called by the current tokenURI admin.\\n     */\\n    function setTokenURIAdmin(address newTokenURIAdmin) external {\\n        require(\\n            msg.sender == tokenURIAdmin || (msg.sender == guardian && newTokenURIAdmin == address(0)),\\n            \\\"NOT_AUTHORIZED\\\"\\n        );\\n        tokenURIAdmin = newTokenURIAdmin;\\n        emit TokenURIAdminSet(newTokenURIAdmin);\\n    }\\n\\n    /**\\n     * @notice set the new royaltyAdmin that can change the royalties\\n     * Can only be called by the current royalty admin.\\n     */\\n    function setRoyaltyAdmin(address newRoyaltyAdmin) external {\\n        require(\\n            msg.sender == royaltyAdmin || (msg.sender == guardian && newRoyaltyAdmin == address(0)),\\n            \\\"NOT_AUTHORIZED\\\"\\n        );\\n        royaltyAdmin = newRoyaltyAdmin;\\n        emit RoyaltyAdminSet(newRoyaltyAdmin);\\n    }\\n\\n    /**\\n     * @notice set the new minterAdmin that can set the minter for Bleeps\\n     * Can only be called by the current minter admin.\\n     */\\n    function setMinterAdmin(address newMinterAdmin) external {\\n        require(\\n            msg.sender == minterAdmin || (msg.sender == guardian && newMinterAdmin == address(0)),\\n            \\\"NOT_AUTHORIZED\\\"\\n        );\\n        minterAdmin = newMinterAdmin;\\n        emit MinterAdminSet(newMinterAdmin);\\n    }\\n\\n    /**\\n     * @notice set the new guardian that can freeze the other admins (except owner).\\n     * Can only be called by the current guardian.\\n     */\\n    function setGuardian(address newGuardian) external {\\n        require(msg.sender == guardian, \\\"NOT_AUTHORIZED\\\");\\n        guardian = newGuardian;\\n        emit GuardianSet(newGuardian);\\n    }\\n\\n    /**\\n     * @notice set the new minter that can mint Bleeps (up to 1024).\\n     * Can only be called by the minter admin.\\n     */\\n    function setMinter(address newMinter) external {\\n        require(msg.sender == minterAdmin, \\\"NOT_AUTHORIZED\\\");\\n        minter = newMinter;\\n        emit MinterSet(newMinter);\\n    }\\n}\\n\"\n        },\n        \"@openzeppelin/contracts/token/ERC721/IERC721.sol\": {\n          \"content\": \"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../../utils/introspection/IERC165.sol\\\";\\n\\n/**\\n * @dev Required interface of an ERC721 compliant contract.\\n */\\ninterface IERC721 is IERC165 {\\n    /**\\n     * @dev Emitted when `tokenId` token is transferred from `from` to `to`.\\n     */\\n    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);\\n\\n    /**\\n     * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.\\n     */\\n    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);\\n\\n    /**\\n     * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.\\n     */\\n    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);\\n\\n    /**\\n     * @dev Returns the number of tokens in ``owner``'s account.\\n     */\\n    function balanceOf(address owner) external view returns (uint256 balance);\\n\\n    /**\\n     * @dev Returns the owner of the `tokenId` token.\\n     *\\n     * Requirements:\\n     *\\n     * - `tokenId` must exist.\\n     */\\n    function ownerOf(uint256 tokenId) external view returns (address owner);\\n\\n    /**\\n     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients\\n     * are aware of the ERC721 protocol to prevent tokens from being forever locked.\\n     *\\n     * Requirements:\\n     *\\n     * - `from` cannot be the zero address.\\n     * - `to` cannot be the zero address.\\n     * - `tokenId` token must exist and be owned by `from`.\\n     * - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}.\\n     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\\n     *\\n     * Emits a {Transfer} event.\\n     */\\n    function safeTransferFrom(\\n        address from,\\n        address to,\\n        uint256 tokenId\\n    ) external;\\n\\n    /**\\n     * @dev Transfers `tokenId` token from `from` to `to`.\\n     *\\n     * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.\\n     *\\n     * Requirements:\\n     *\\n     * - `from` cannot be the zero address.\\n     * - `to` cannot be the zero address.\\n     * - `tokenId` token must be owned by `from`.\\n     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\\n     *\\n     * Emits a {Transfer} event.\\n     */\\n    function transferFrom(\\n        address from,\\n        address to,\\n        uint256 tokenId\\n    ) external;\\n\\n    /**\\n     * @dev Gives permission to `to` to transfer `tokenId` token to another account.\\n     * The approval is cleared when the token is transferred.\\n     *\\n     * Only a single account can be approved at a time, so approving the zero address clears previous approvals.\\n     *\\n     * Requirements:\\n     *\\n     * - The caller must own the token or be an approved operator.\\n     * - `tokenId` must exist.\\n     *\\n     * Emits an {Approval} event.\\n     */\\n    function approve(address to, uint256 tokenId) external;\\n\\n    /**\\n     * @dev Returns the account approved for `tokenId` token.\\n     *\\n     * Requirements:\\n     *\\n     * - `tokenId` must exist.\\n     */\\n    function getApproved(uint256 tokenId) external view returns (address operator);\\n\\n    /**\\n     * @dev Approve or remove `operator` as an operator for the caller.\\n     * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.\\n     *\\n     * Requirements:\\n     *\\n     * - The `operator` cannot be the caller.\\n     *\\n     * Emits an {ApprovalForAll} event.\\n     */\\n    function setApprovalForAll(address operator, bool _approved) external;\\n\\n    /**\\n     * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.\\n     *\\n     * See {setApprovalForAll}\\n     */\\n    function isApprovedForAll(address owner, address operator) external view returns (bool);\\n\\n    /**\\n     * @dev Safely transfers `tokenId` token from `from` to `to`.\\n     *\\n     * Requirements:\\n     *\\n     * - `from` cannot be the zero address.\\n     * - `to` cannot be the zero address.\\n     * - `tokenId` token must exist and be owned by `from`.\\n     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\\n     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\\n     *\\n     * Emits a {Transfer} event.\\n     */\\n    function safeTransferFrom(\\n        address from,\\n        address to,\\n        uint256 tokenId,\\n        bytes calldata data\\n    ) external;\\n}\\n\"\n        },\n        \"@openzeppelin/contracts/utils/introspection/IERC165.sol\": {\n          \"content\": \"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC165 standard, as defined in the\\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\\n *\\n * Implementers can declare support of contract interfaces, which can then be\\n * queried by others ({ERC165Checker}).\\n *\\n * For an implementation, see {ERC165}.\\n */\\ninterface IERC165 {\\n    /**\\n     * @dev Returns true if this contract implements the interface defined by\\n     * `interfaceId`. See the corresponding\\n     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\\n     * to learn more about how these ids are created.\\n     *\\n     * This function call must use less than 30 000 gas.\\n     */\\n    function supportsInterface(bytes4 interfaceId) external view returns (bool);\\n}\\n\"\n        },\n        \"src/interfaces/ITokenURI.sol\": {\n          \"content\": \"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.9;\\n\\ninterface ITokenURI {\\n    function tokenURI(uint256 id) external view returns (string memory);\\n\\n    function contractURI(address receiver, uint96 per10Thousands) external view returns (string memory);\\n}\\n\"\n        },\n        \"src/base/WithSupportForOpenSeaProxies.sol\": {\n          \"content\": \"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.9;\\n\\ncontract OwnableDelegateProxy {}\\n\\ncontract ProxyRegistry {\\n    mapping(address => OwnableDelegateProxy) public proxies;\\n}\\n\\nabstract contract WithSupportForOpenSeaProxies {\\n    address internal immutable _proxyRegistryAddress;\\n\\n    constructor(address proxyRegistryAddress) {\\n        _proxyRegistryAddress = proxyRegistryAddress;\\n    }\\n\\n    function _isOpenSeaProxy(address owner, address operator) internal view returns (bool) {\\n        if (_proxyRegistryAddress == address(0)) {\\n            return false;\\n        }\\n        // Whitelist OpenSea proxy contract for easy trading.\\n        ProxyRegistry proxyRegistry = ProxyRegistry(_proxyRegistryAddress);\\n        return address(proxyRegistry.proxies(owner)) == operator;\\n    }\\n}\\n\"\n        },\n        \"@openzeppelin/contracts/interfaces/IERC1271.sol\": {\n          \"content\": \"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC1271 standard signature validation method for\\n * contracts as defined in https://eips.ethereum.org/EIPS/eip-1271[ERC-1271].\\n *\\n * _Available since v4.1._\\n */\\ninterface IERC1271 {\\n    /**\\n     * @dev Should return whether the signature provided is valid for the provided data\\n     * @param hash      Hash of the data to be signed\\n     * @param signature Signature byte array associated with _data\\n     */\\n    function isValidSignature(bytes32 hash, bytes memory signature) external view returns (bytes4 magicValue);\\n}\\n\"\n        },\n        \"@openzeppelin/contracts/interfaces/IERC165.sol\": {\n          \"content\": \"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../utils/introspection/IERC165.sol\\\";\\n\"\n        },\n        \"src/bleeps/Bleeps.sol\": {\n          \"content\": \"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.9;\\n\\nimport \\\"./BleepsRoles.sol\\\";\\nimport \\\"../base/ERC721Checkpointable.sol\\\";\\n\\nimport \\\"../interfaces/ITokenURI.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC721/IERC721.sol\\\";\\n\\nimport \\\"../base/WithSupportForOpenSeaProxies.sol\\\";\\n\\ncontract Bleeps is IERC721, WithSupportForOpenSeaProxies, ERC721Checkpointable, BleepsRoles {\\n    event RoyaltySet(address receiver, uint256 royaltyPer10Thousands);\\n    event TokenURIContractSet(ITokenURI newTokenURIContract);\\n    event CheckpointingDisablerSet(address newCheckpointingDisabler);\\n    event CheckpointingDisabled();\\n\\n    /// @notice the contract that actually generate the sound (and all metadata via the a data: uri via tokenURI call).\\n    ITokenURI public tokenURIContract;\\n\\n    struct Royalty {\\n        address receiver;\\n        uint96 per10Thousands;\\n    }\\n\\n    Royalty internal _royalty;\\n\\n    /// @dev address that is able to switch off the use of checkpointing, this will make token transfers much cheaper in term of gas, but require the design of a new governance system.\\n    address public checkpointingDisabler;\\n\\n    /// @dev Create the Bleeps contract\\n    /// @param ens ENS address for the network the contract is deployed to\\n    /// @param initialOwner address that can set the ENS name of the contract and that can witthdraw ERC20 tokens sent by mistake here.\\n    /// @param initialTokenURIAdmin admin able to update the tokenURI contract.\\n    /// @param initialMinterAdmin admin able to set the minter contract.\\n    /// @param initialRoyaltyAdmin admin able to update the royalty receiver and rates.\\n    /// @param initialGuardian guardian able to immortalize rules\\n    /// @param openseaProxyRegistry allow Bleeps to be sold on opensea without prior approval tx as long as the user have already an opensea proxy.\\n    /// @param initialRoyaltyReceiver receiver of royalties\\n    /// @param imitialRoyaltyPer10Thousands amount of royalty in 10,000 basis point\\n    /// @param initialTokenURIContract initial tokenURI contract that generate the metadata including the wav file.\\n    /// @param initialCheckpointingDisabler admin able to cancel checkpointing\\n    constructor(\\n        address ens,\\n        address initialOwner,\\n        address initialTokenURIAdmin,\\n        address initialMinterAdmin,\\n        address initialRoyaltyAdmin,\\n        address initialGuardian,\\n        address openseaProxyRegistry,\\n        address initialRoyaltyReceiver,\\n        uint96 imitialRoyaltyPer10Thousands,\\n        ITokenURI initialTokenURIContract,\\n        address initialCheckpointingDisabler\\n    )\\n        WithSupportForOpenSeaProxies(openseaProxyRegistry)\\n        BleepsRoles(ens, initialOwner, initialTokenURIAdmin, initialMinterAdmin, initialRoyaltyAdmin, initialGuardian)\\n    {\\n        tokenURIContract = initialTokenURIContract;\\n        emit TokenURIContractSet(initialTokenURIContract);\\n        checkpointingDisabler = initialCheckpointingDisabler;\\n        emit CheckpointingDisablerSet(initialCheckpointingDisabler);\\n\\n        _royalty.receiver = initialRoyaltyReceiver;\\n        _royalty.per10Thousands = imitialRoyaltyPer10Thousands;\\n        emit RoyaltySet(initialRoyaltyReceiver, imitialRoyaltyPer10Thousands);\\n    }\\n\\n    /// @notice A descriptive name for a collection of NFTs in this contract.\\n    function name() public pure override returns (string memory) {\\n        return \\\"Bleeps\\\";\\n    }\\n\\n    /// @notice An abbreviated name for NFTs in this contract.\\n    function symbol() external pure returns (string memory) {\\n        return \\\"BLEEP\\\";\\n    }\\n\\n    /// @notice Returns the Uniform Resource Identifier (URI) for the token collection.\\n    function contractURI() external view returns (string memory) {\\n        return tokenURIContract.contractURI(_royalty.receiver, _royalty.per10Thousands);\\n    }\\n\\n    /// @notice Returns the Uniform Resource Identifier (URI) for token `id`.\\n    function tokenURI(uint256 id) external view returns (string memory) {\\n        return tokenURIContract.tokenURI(id);\\n    }\\n\\n    /// @notice set a new tokenURI contract, that generate the metadata including the wav file, Can only be set by the `tokenURIAdmin`.\\n    /// @param newTokenURIContract The address of the new tokenURI contract.\\n    function setTokenURIContract(ITokenURI newTokenURIContract) external {\\n        require(msg.sender == tokenURIAdmin, \\\"NOT_AUTHORIZED\\\");\\n        tokenURIContract = newTokenURIContract;\\n        emit TokenURIContractSet(newTokenURIContract);\\n    }\\n\\n    /// @notice give the list of owners for the list of ids given.\\n    /// @param ids The list if token ids to check.\\n    /// @return addresses The list of addresses, corresponding to the list of ids.\\n    function owners(uint256[] calldata ids) external view returns (address[] memory addresses) {\\n        addresses = new address[](ids.length);\\n        for (uint256 i = 0; i < ids.length; i++) {\\n            uint256 id = ids[i];\\n            addresses[i] = address(uint160(_owners[id]));\\n        }\\n    }\\n\\n    /// @notice Check if the sender approved the operator.\\n    /// @param owner The address of the owner.\\n    /// @param operator The address of the operator.\\n    /// @return isOperator The status of the approval.\\n    function isApprovedForAll(address owner, address operator)\\n        public\\n        view\\n        virtual\\n        override(ERC721Base, IERC721)\\n        returns (bool isOperator)\\n    {\\n        return super.isApprovedForAll(owner, operator) || _isOpenSeaProxy(owner, operator);\\n    }\\n\\n    /// @notice Check if the contract supports an interface.\\n    /// @param id The id of the interface.\\n    /// @return Whether the interface is supported.\\n    function supportsInterface(bytes4 id)\\n        public\\n        pure\\n        virtual\\n        override(ERC721BaseWithERC4494Permit, IERC165)\\n        returns (bool)\\n    {\\n        return super.supportsInterface(id) || id == 0x2a55205a; /// 0x2a55205a is ERC2981 (royalty standard)\\n    }\\n\\n    /// @notice Called with the sale price to determine how much royalty is owed and to whom.\\n    /// @param id - the token queried for royalty information.\\n    /// @param salePrice - the sale price of the token specified by id.\\n    /// @return receiver - address of who should be sent the royalty payment.\\n    /// @return royaltyAmount - the royalty payment amount for salePrice.\\n    function royaltyInfo(uint256 id, uint256 salePrice)\\n        external\\n        view\\n        returns (address receiver, uint256 royaltyAmount)\\n    {\\n        receiver = _royalty.receiver;\\n        royaltyAmount = (salePrice * uint256(_royalty.per10Thousands)) / 10000;\\n    }\\n\\n    /// @notice set a new royalty receiver and rate, Can only be set by the `royaltyAdmin`.\\n    /// @param newReceiver the address that should receive the royalty proceeds.\\n    /// @param royaltyPer10Thousands the share of the salePrice (in 1/10000) given to the receiver.\\n    function setRoyaltyParameters(address newReceiver, uint96 royaltyPer10Thousands) external {\\n        require(msg.sender == royaltyAdmin, \\\"NOT_AUTHORIZED\\\");\\n        // require(royaltyPer10Thousands <= 50, \\\"ROYALTY_TOO_HIGH\\\"); ?\\n        _royalty.receiver = newReceiver;\\n        _royalty.per10Thousands = royaltyPer10Thousands;\\n        emit RoyaltySet(newReceiver, royaltyPer10Thousands);\\n    }\\n\\n    /// @notice disable checkpointing overhead\\n    /// This can be used if the governance system can switch to use ownerAndLastTransferBlockNumberOf instead of checkpoints\\n    function disableTheUseOfCheckpoints() external {\\n        require(msg.sender == checkpointingDisabler, \\\"NOT_AUTHORIZED\\\");\\n        _useCheckpoints = false;\\n        checkpointingDisabler = address(0);\\n        emit CheckpointingDisablerSet(address(0));\\n        emit CheckpointingDisabled();\\n    }\\n\\n    /// @notice update the address that can disable the use of checkpinting, can be used to disable it entirely.\\n    /// @param newCheckpointingDisabler new address that can disable the use of checkpointing. can be the zero address to remove the ability to change.\\n    function setCheckpointingDisabler(address newCheckpointingDisabler) external {\\n        require(msg.sender == checkpointingDisabler, \\\"NOT_AUTHORIZED\\\");\\n        checkpointingDisabler = newCheckpointingDisabler;\\n        emit CheckpointingDisablerSet(newCheckpointingDisabler);\\n    }\\n\\n    /// @notice mint one of bleep if not already minted. Can only be called by `minter`.\\n    /// @param id bleep id which represent a pair of (note, instrument).\\n    /// @param to address that will receive the Bleep.\\n    function mint(uint16 id, address to) external {\\n        require(msg.sender == minter, \\\"ONLY_MINTER_ALLOWED\\\");\\n        require(id < 1024, \\\"INVALID_BLEEP\\\");\\n\\n        require(to != address(0), \\\"NOT_TO_ZEROADDRESS\\\");\\n        require(to != address(this), \\\"NOT_TO_THIS\\\");\\n        address owner = _ownerOf(id);\\n        require(owner == address(0), \\\"ALREADY_CREATED\\\");\\n        _safeTransferFrom(address(0), to, id, \\\"\\\");\\n    }\\n\\n    /// @notice mint multiple bleeps if not already minted. Can only be called by `minter`.\\n    /// @param ids list of bleep id which represent each a pair of (note, instrument).\\n    /// @param tos addresses that will receive the Bleeps. (if only one, use for all)\\n    function multiMint(uint16[] calldata ids, address[] calldata tos) external {\\n        require(msg.sender == minter, \\\"ONLY_MINTER_ALLOWED\\\");\\n\\n        address to;\\n        if (tos.length == 1) {\\n            to = tos[0];\\n        }\\n        for (uint256 i = 0; i < ids.length; i++) {\\n            uint256 id = ids[i];\\n            if (tos.length > 1) {\\n                to = tos[i];\\n            }\\n            require(to != address(0), \\\"NOT_TO_ZEROADDRESS\\\");\\n            require(to != address(this), \\\"NOT_TO_THIS\\\");\\n            require(id < 1024, \\\"INVALID_BLEEP\\\");\\n            address owner = _ownerOf(id);\\n            require(owner == address(0), \\\"ALREADY_CREATED\\\");\\n            _safeTransferFrom(address(0), to, id, \\\"\\\");\\n        }\\n    }\\n\\n    /// @notice gives the note and instrument for a particular Bleep id.\\n    /// @param id bleep id which represent a pair of (note, instrument).\\n    /// @return note the note index (0 to 63) starting from C2 to D#7\\n    /// @return instrument the instrument index (0 to 16). At launch there is only 9 instrument but the DAO could add more (up to 16 in total).\\n    function sound(uint256 id) external pure returns (uint8 note, uint8 instrument) {\\n        note = uint8(id & 0x3F);\\n        instrument = uint8(uint256(id >> 6) & 0x0F);\\n    }\\n}\\n\"\n        },\n        \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\": {\n          \"content\": \"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\\n *\\n * These functions can be used to verify that a message was signed by the holder\\n * of the private keys of a given address.\\n */\\nlibrary ECDSA {\\n    enum RecoverError {\\n        NoError,\\n        InvalidSignature,\\n        InvalidSignatureLength,\\n        InvalidSignatureS,\\n        InvalidSignatureV\\n    }\\n\\n    function _throwError(RecoverError error) private pure {\\n        if (error == RecoverError.NoError) {\\n            return; // no error: do nothing\\n        } else if (error == RecoverError.InvalidSignature) {\\n            revert(\\\"ECDSA: invalid signature\\\");\\n        } else if (error == RecoverError.InvalidSignatureLength) {\\n            revert(\\\"ECDSA: invalid signature length\\\");\\n        } else if (error == RecoverError.InvalidSignatureS) {\\n            revert(\\\"ECDSA: invalid signature 's' value\\\");\\n        } else if (error == RecoverError.InvalidSignatureV) {\\n            revert(\\\"ECDSA: invalid signature 'v' value\\\");\\n        }\\n    }\\n\\n    /**\\n     * @dev Returns the address that signed a hashed message (`hash`) with\\n     * `signature` or error string. This address can then be used for verification purposes.\\n     *\\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n     * this function rejects them by requiring the `s` value to be in the lower\\n     * half order, and the `v` value to be either 27 or 28.\\n     *\\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n     * verification to be secure: it is possible to craft signatures that\\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n     * this is by receiving a hash of the original message (which may otherwise\\n     * be too long), and then calling {toEthSignedMessageHash} on it.\\n     *\\n     * Documentation for signature generation:\\n     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\\n     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\\n     *\\n     * _Available since v4.3._\\n     */\\n    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\\n        // Check the signature length\\n        // - case 65: r,s,v signature (standard)\\n        // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\\n        if (signature.length == 65) {\\n            bytes32 r;\\n            bytes32 s;\\n            uint8 v;\\n            // ecrecover takes the signature parameters, and the only way to get them\\n            // currently is to use assembly.\\n            assembly {\\n                r := mload(add(signature, 0x20))\\n                s := mload(add(signature, 0x40))\\n                v := byte(0, mload(add(signature, 0x60)))\\n            }\\n            return tryRecover(hash, v, r, s);\\n        } else if (signature.length == 64) {\\n            bytes32 r;\\n            bytes32 vs;\\n            // ecrecover takes the signature parameters, and the only way to get them\\n            // currently is to use assembly.\\n            assembly {\\n                r := mload(add(signature, 0x20))\\n                vs := mload(add(signature, 0x40))\\n            }\\n            return tryRecover(hash, r, vs);\\n        } else {\\n            return (address(0), RecoverError.InvalidSignatureLength);\\n        }\\n    }\\n\\n    /**\\n     * @dev Returns the address that signed a hashed message (`hash`) with\\n     * `signature`. This address can then be used for verification purposes.\\n     *\\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n     * this function rejects them by requiring the `s` value to be in the lower\\n     * half order, and the `v` value to be either 27 or 28.\\n     *\\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n     * verification to be secure: it is possible to craft signatures that\\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n     * this is by receiving a hash of the original message (which may otherwise\\n     * be too long), and then calling {toEthSignedMessageHash} on it.\\n     */\\n    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\\n        (address recovered, RecoverError error) = tryRecover(hash, signature);\\n        _throwError(error);\\n        return recovered;\\n    }\\n\\n    /**\\n     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\\n     *\\n     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\\n     *\\n     * _Available since v4.3._\\n     */\\n    function tryRecover(\\n        bytes32 hash,\\n        bytes32 r,\\n        bytes32 vs\\n    ) internal pure returns (address, RecoverError) {\\n        bytes32 s;\\n        uint8 v;\\n        assembly {\\n            s := and(vs, 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)\\n            v := add(shr(255, vs), 27)\\n        }\\n        return tryRecover(hash, v, r, s);\\n    }\\n\\n    /**\\n     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\\n     *\\n     * _Available since v4.2._\\n     */\\n    function recover(\\n        bytes32 hash,\\n        bytes32 r,\\n        bytes32 vs\\n    ) internal pure returns (address) {\\n        (address recovered, RecoverError error) = tryRecover(hash, r, vs);\\n        _throwError(error);\\n        return recovered;\\n    }\\n\\n    /**\\n     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\\n     * `r` and `s` signature fields separately.\\n     *\\n     * _Available since v4.3._\\n     */\\n    function tryRecover(\\n        bytes32 hash,\\n        uint8 v,\\n        bytes32 r,\\n        bytes32 s\\n    ) internal pure returns (address, RecoverError) {\\n        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\\n        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\\n        // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\\n        // signatures from current libraries generate a unique signature with an s-value in the lower half order.\\n        //\\n        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\\n        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\\n        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\\n        // these malleable signatures as well.\\n        if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\\n            return (address(0), RecoverError.InvalidSignatureS);\\n        }\\n        if (v != 27 && v != 28) {\\n            return (address(0), RecoverError.InvalidSignatureV);\\n        }\\n\\n        // If the signature is valid (and not malleable), return the signer address\\n        address signer = ecrecover(hash, v, r, s);\\n        if (signer == address(0)) {\\n            return (address(0), RecoverError.InvalidSignature);\\n        }\\n\\n        return (signer, RecoverError.NoError);\\n    }\\n\\n    /**\\n     * @dev Overload of {ECDSA-recover} that receives the `v`,\\n     * `r` and `s` signature fields separately.\\n     */\\n    function recover(\\n        bytes32 hash,\\n        uint8 v,\\n        bytes32 r,\\n        bytes32 s\\n    ) internal pure returns (address) {\\n        (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\\n        _throwError(error);\\n        return recovered;\\n    }\\n\\n    /**\\n     * @dev Returns an Ethereum Signed Message, created from a `hash`. This\\n     * produces hash corresponding to the one signed with the\\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n     * JSON-RPC method as part of EIP-191.\\n     *\\n     * See {recover}.\\n     */\\n    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\\n        // 32 is the length in bytes of hash,\\n        // enforced by the type signature above\\n        return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n32\\\", hash));\\n    }\\n\\n    /**\\n     * @dev Returns an Ethereum Signed Typed Data, created from a\\n     * `domainSeparator` and a `structHash`. This produces hash corresponding\\n     * to the one signed with the\\n     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\\n     * JSON-RPC method as part of EIP-712.\\n     *\\n     * See {recover}.\\n     */\\n    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\\n        return keccak256(abi.encodePacked(\\\"\\\\x19\\\\x01\\\", domainSeparator, structHash));\\n    }\\n}\\n\"\n        },\n        \"@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol\": {\n          \"content\": \"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./ECDSA.sol\\\";\\nimport \\\"../Address.sol\\\";\\nimport \\\"../../interfaces/IERC1271.sol\\\";\\n\\n/**\\n * @dev Signature verification helper: Provide a single mechanism to verify both private-key (EOA) ECDSA signature and\\n * ERC1271 contract sigantures. Using this instead of ECDSA.recover in your contract will make them compatible with\\n * smart contract wallets such as Argent and Gnosis.\\n *\\n * Note: unlike ECDSA signatures, contract signature's are revocable, and the outcome of this function can thus change\\n * through time. It could return true at block N and false at block N+1 (or the opposite).\\n *\\n * _Available since v4.1._\\n */\\nlibrary SignatureChecker {\\n    function isValidSignatureNow(\\n        address signer,\\n        bytes32 hash,\\n        bytes memory signature\\n    ) internal view returns (bool) {\\n        (address recovered, ECDSA.RecoverError error) = ECDSA.tryRecover(hash, signature);\\n        if (error == ECDSA.RecoverError.NoError && recovered == signer) {\\n            return true;\\n        }\\n\\n        (bool success, bytes memory result) = signer.staticcall(\\n            abi.encodeWithSelector(IERC1271.isValidSignature.selector, hash, signature)\\n        );\\n        return (success && result.length == 32 && abi.decode(result, (bytes4)) == IERC1271.isValidSignature.selector);\\n    }\\n}\\n\"\n        },\n        \"src/base/ERC721BaseWithERC4494Permit.sol\": {\n          \"content\": \"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.9;\\n\\nimport \\\"./ERC721Base.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol\\\";\\nimport \\\"./IERC4494.sol\\\";\\n\\nabstract contract ERC721BaseWithERC4494Permit is ERC721Base {\\n    using Address for address;\\n\\n    bytes32 public constant PERMIT_TYPEHASH =\\n        keccak256(\\\"Permit(address spender,uint256 tokenId,uint256 nonce,uint256 deadline)\\\");\\n    bytes32 public constant PERMIT_FOR_ALL_TYPEHASH =\\n        keccak256(\\\"PermitForAll(address spender,uint256 nonce,uint256 deadline)\\\");\\n    bytes32 public constant DOMAIN_TYPEHASH =\\n        keccak256(\\\"EIP712Domain(string name,uint256 chainId,address verifyingContract)\\\");\\n\\n    uint256 private immutable _deploymentChainId;\\n    bytes32 private immutable _deploymentDomainSeparator;\\n\\n    mapping(address => uint256) internal _userNonces;\\n\\n    constructor() {\\n        uint256 chainId;\\n        //solhint-disable-next-line no-inline-assembly\\n        assembly {\\n            chainId := chainid()\\n        }\\n        _deploymentChainId = chainId;\\n        _deploymentDomainSeparator = _calculateDomainSeparator(chainId);\\n    }\\n\\n    /// @dev Return the DOMAIN_SEPARATOR.\\n    function DOMAIN_SEPARATOR() external view returns (bytes32) {\\n        return _DOMAIN_SEPARATOR();\\n    }\\n\\n    /// @notice return the account nonce, used for approvalForAll permit or other account related matter\\n    /// @param account the account to query\\n    /// @return nonce\\n    function nonces(address account) external view virtual returns (uint256 nonce) {\\n        return _userNonces[account];\\n    }\\n\\n    /// @notice return the token nonce, used for individual approve permit or other token related matter\\n    /// @param id token id to query\\n    /// @return nonce\\n    function nonces(uint256 id) public view virtual returns (uint256 nonce) {\\n        (address owner, uint256 blockNumber) = _ownerAndBlockNumberOf(id);\\n        require(owner != address(0), \\\"NONEXISTENT_TOKEN\\\");\\n        return blockNumber;\\n    }\\n\\n    /// @notice return the token nonce, used for individual approve permit or other token related matter\\n    /// @param id token id to query\\n    /// @return nonce\\n    function tokenNonces(uint256 id) external view returns (uint256 nonce) {\\n        return nonces(id);\\n    }\\n\\n    function permit(\\n        address spender,\\n        uint256 tokenId,\\n        uint256 deadline,\\n        bytes memory sig\\n    ) external {\\n        require(deadline >= block.timestamp, \\\"PERMIT_DEADLINE_EXPIRED\\\");\\n\\n        (address owner, uint256 blockNumber) = _ownerAndBlockNumberOf(tokenId);\\n        require(owner != address(0), \\\"NONEXISTENT_TOKEN\\\");\\n\\n        // We use blockNumber as nonce as we already store it per tokens. It can thus act as an increasing transfer counter.\\n        // while technically multiple transfer could happen in the same block, the signed message would be using a previous block.\\n        // And the transfer would use then a more recent blockNumber, invalidating that message when transfer is executed.\\n        _requireValidPermit(owner, spender, tokenId, deadline, blockNumber, sig);\\n\\n        _approveFor(owner, blockNumber, spender, tokenId);\\n    }\\n\\n    function permitForAll(\\n        address signer,\\n        address spender,\\n        uint256 deadline,\\n        bytes memory sig\\n    ) external {\\n        require(deadline >= block.timestamp, \\\"PERMIT_DEADLINE_EXPIRED\\\");\\n\\n        _requireValidPermitForAll(signer, spender, deadline, _userNonces[signer]++, sig);\\n\\n        _setApprovalForAll(signer, spender, true);\\n    }\\n\\n    /// @notice Check if the contract supports an interface.\\n    /// @param id The id of the interface.\\n    /// @return Whether the interface is supported.\\n    function supportsInterface(bytes4 id) public pure virtual override returns (bool) {\\n        return\\n            super.supportsInterface(id) ||\\n            id == type(IERC4494).interfaceId ||\\n            id == type(IERC4494Alternative).interfaceId;\\n    }\\n\\n    // -------------------------------------------------------- INTERNAL --------------------------------------------------------------------\\n\\n    function _requireValidPermit(\\n        address signer,\\n        address spender,\\n        uint256 id,\\n        uint256 deadline,\\n        uint256 nonce,\\n        bytes memory sig\\n    ) internal view {\\n        bytes32 digest = keccak256(\\n            abi.encodePacked(\\n                \\\"\\\\x19\\\\x01\\\",\\n                _DOMAIN_SEPARATOR(),\\n                keccak256(abi.encode(PERMIT_TYPEHASH, spender, id, nonce, deadline))\\n            )\\n        );\\n        require(SignatureChecker.isValidSignatureNow(signer, digest, sig), \\\"INVALID_SIGNATURE\\\");\\n    }\\n\\n    function _requireValidPermitForAll(\\n        address signer,\\n        address spender,\\n        uint256 deadline,\\n        uint256 nonce,\\n        bytes memory sig\\n    ) internal view {\\n        bytes32 digest = keccak256(\\n            abi.encodePacked(\\n                \\\"\\\\x19\\\\x01\\\",\\n                _DOMAIN_SEPARATOR(),\\n                keccak256(abi.encode(PERMIT_FOR_ALL_TYPEHASH, spender, nonce, deadline))\\n            )\\n        );\\n        require(SignatureChecker.isValidSignatureNow(signer, digest, sig), \\\"INVALID_SIGNATURE\\\");\\n    }\\n\\n    /// @dev Return the DOMAIN_SEPARATOR.\\n    function _DOMAIN_SEPARATOR() internal view returns (bytes32) {\\n        uint256 chainId;\\n        //solhint-disable-next-line no-inline-assembly\\n        assembly {\\n            chainId := chainid()\\n        }\\n\\n        // in case a fork happen, to support the chain that had to change its chainId,, we compute the domain operator\\n        return chainId == _deploymentChainId ? _deploymentDomainSeparator : _calculateDomainSeparator(chainId);\\n    }\\n\\n    /// @dev Calculate the DOMAIN_SEPARATOR.\\n    function _calculateDomainSeparator(uint256 chainId) private view returns (bytes32) {\\n        return keccak256(abi.encode(DOMAIN_TYPEHASH, keccak256(bytes(name())), chainId, address(this)));\\n    }\\n}\\n\"\n        },\n        \"@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol\": {\n          \"content\": \"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title ERC721 token receiver interface\\n * @dev Interface for any contract that wants to support safeTransfers\\n * from ERC721 asset contracts.\\n */\\ninterface IERC721Receiver {\\n    /**\\n     * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}\\n     * by `operator` from `from`, this function is called.\\n     *\\n     * It must return its Solidity selector to confirm the token transfer.\\n     * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.\\n     *\\n     * The selector can be obtained in Solidity with `IERC721.onERC721Received.selector`.\\n     */\\n    function onERC721Received(\\n        address operator,\\n        address from,\\n        uint256 tokenId,\\n        bytes calldata data\\n    ) external returns (bytes4);\\n}\\n\"\n        }\n      },\n      \"settings\": {\n        \"evmVersion\": \"london\",\n        \"libraries\": {},\n        \"metadata\": {\n          \"bytecodeHash\": \"ipfs\",\n          \"useLiteralContent\": true\n        },\n        \"optimizer\": {\n          \"enabled\": true,\n          \"runs\": 999999\n        },\n        \"remappings\": [],\n        \"outputSelection\": {\n          \"*\": {\n            \"*\": [\n              \"evm.bytecode\",\n              \"evm.deployedBytecode\",\n              \"devdoc\",\n              \"userdoc\",\n              \"metadata\",\n              \"abi\"\n            ]\n          }\n        }\n      }\n    },\n    \"ABI\": \"[{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"ens\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"initialOwner\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"initialTokenURIAdmin\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"initialMinterAdmin\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"initialRoyaltyAdmin\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"initialGuardian\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"openseaProxyRegistry\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"initialRoyaltyReceiver\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"uint96\\\",\\\"name\\\":\\\"imitialRoyaltyPer10Thousands\\\",\\\"type\\\":\\\"uint96\\\"},{\\\"internalType\\\":\\\"contract ITokenURI\\\",\\\"name\\\":\\\"initialTokenURIContract\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"initialCheckpointingDisabler\\\",\\\"type\\\":\\\"address\\\"}],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"constructor\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":true,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"owner\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":true,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"approved\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":true,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"tokenId\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"Approval\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":true,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"owner\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":true,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"operator\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"bool\\\",\\\"name\\\":\\\"approved\\\",\\\"type\\\":\\\"bool\\\"}],\\\"name\\\":\\\"ApprovalForAll\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[],\\\"name\\\":\\\"CheckpointingDisabled\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":false,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"newCheckpointingDisabler\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"CheckpointingDisablerSet\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":true,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"delegator\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":true,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"fromDelegate\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":true,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"toDelegate\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"DelegateChanged\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":true,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"delegate\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"previousBalance\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"newBalance\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"DelegateVotesChanged\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":false,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"newGuardian\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"GuardianSet\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":false,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"newMinterAdmin\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"MinterAdminSet\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":false,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"newMinter\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"MinterSet\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":true,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"previousOwner\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":true,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"newOwner\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"OwnershipTransferred\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":false,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"newRoyaltyAdmin\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"RoyaltyAdminSet\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":false,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"receiver\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"royaltyPer10Thousands\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"RoyaltySet\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":false,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"newTokenURIAdmin\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"TokenURIAdminSet\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":false,\\\"internalType\\\":\\\"contract ITokenURI\\\",\\\"name\\\":\\\"newTokenURIContract\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"TokenURIContractSet\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":true,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"from\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":true,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"to\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":true,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"tokenId\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"Transfer\\\",\\\"type\\\":\\\"event\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"DELEGATION_TYPEHASH\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"bytes32\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"bytes32\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"DOMAIN_SEPARATOR\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"bytes32\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"bytes32\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"DOMAIN_TYPEHASH\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"bytes32\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"bytes32\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"PERMIT_FOR_ALL_TYPEHASH\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"bytes32\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"bytes32\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"PERMIT_TYPEHASH\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"bytes32\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"bytes32\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"operator\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"id\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"approve\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"owner\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"balanceOf\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"balance\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"checkpointingDisabler\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"address\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"uint32\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint32\\\"}],\\\"name\\\":\\\"checkpoints\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint32\\\",\\\"name\\\":\\\"fromBlock\\\",\\\"type\\\":\\\"uint32\\\"},{\\\"internalType\\\":\\\"uint96\\\",\\\"name\\\":\\\"votes\\\",\\\"type\\\":\\\"uint96\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"contractURI\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"string\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"string\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"decimals\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint8\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint8\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"delegatee\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"delegate\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"delegatee\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"nonce\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"expiry\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"uint8\\\",\\\"name\\\":\\\"v\\\",\\\"type\\\":\\\"uint8\\\"},{\\\"internalType\\\":\\\"bytes32\\\",\\\"name\\\":\\\"r\\\",\\\"type\\\":\\\"bytes32\\\"},{\\\"internalType\\\":\\\"bytes32\\\",\\\"name\\\":\\\"s\\\",\\\"type\\\":\\\"bytes32\\\"}],\\\"name\\\":\\\"delegateBySig\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"delegator\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"delegates\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"address\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"disableTheUseOfCheckpoints\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"id\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"getApproved\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"address\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"account\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"getCurrentVotes\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint96\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint96\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"account\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"blockNumber\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"getPastVotes\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint96\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint96\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"account\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"blockNumber\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"getPriorVotes\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint96\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint96\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"account\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"getVotes\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint96\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint96\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"guardian\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"address\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"owner\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"operator\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"isApprovedForAll\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"bool\\\",\\\"name\\\":\\\"isOperator\\\",\\\"type\\\":\\\"bool\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"uint16\\\",\\\"name\\\":\\\"id\\\",\\\"type\\\":\\\"uint16\\\"},{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"to\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"mint\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"minter\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"address\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"minterAdmin\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"address\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"uint16[]\\\",\\\"name\\\":\\\"ids\\\",\\\"type\\\":\\\"uint16[]\\\"},{\\\"internalType\\\":\\\"address[]\\\",\\\"name\\\":\\\"tos\\\",\\\"type\\\":\\\"address[]\\\"}],\\\"name\\\":\\\"multiMint\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"bytes[]\\\",\\\"name\\\":\\\"data\\\",\\\"type\\\":\\\"bytes[]\\\"}],\\\"name\\\":\\\"multicall\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"bytes[]\\\",\\\"name\\\":\\\"results\\\",\\\"type\\\":\\\"bytes[]\\\"}],\\\"stateMutability\\\":\\\"payable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"name\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"string\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"string\\\"}],\\\"stateMutability\\\":\\\"pure\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"id\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"nonces\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"nonce\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"account\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"nonces\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"nonce\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"numCheckpoints\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint32\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint32\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"owner\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"address\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"uint256[]\\\",\\\"name\\\":\\\"ids\\\",\\\"type\\\":\\\"uint256[]\\\"}],\\\"name\\\":\\\"ownerAndLastTransferBlockNumberList\\\",\\\"outputs\\\":[{\\\"components\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"owner\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"lastTransferBlockNumber\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"internalType\\\":\\\"struct ERC721Base.OwnerData[]\\\",\\\"name\\\":\\\"ownersData\\\",\\\"type\\\":\\\"tuple[]\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"id\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"ownerOf\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"owner\\\",\\\"type\\\":\\\"address\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"uint256[]\\\",\\\"name\\\":\\\"ids\\\",\\\"type\\\":\\\"uint256[]\\\"}],\\\"name\\\":\\\"owners\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"address[]\\\",\\\"name\\\":\\\"addresses\\\",\\\"type\\\":\\\"address[]\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"spender\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"tokenId\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"deadline\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"bytes\\\",\\\"name\\\":\\\"sig\\\",\\\"type\\\":\\\"bytes\\\"}],\\\"name\\\":\\\"permit\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"signer\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"spender\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"deadline\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"bytes\\\",\\\"name\\\":\\\"sig\\\",\\\"type\\\":\\\"bytes\\\"}],\\\"name\\\":\\\"permitForAll\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"royaltyAdmin\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"address\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"id\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"salePrice\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"royaltyInfo\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"receiver\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"royaltyAmount\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"from\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"to\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"id\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"safeTransferFrom\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"from\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"to\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"id\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"bytes\\\",\\\"name\\\":\\\"data\\\",\\\"type\\\":\\\"bytes\\\"}],\\\"name\\\":\\\"safeTransferFrom\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"operator\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"bool\\\",\\\"name\\\":\\\"approved\\\",\\\"type\\\":\\\"bool\\\"}],\\\"name\\\":\\\"setApprovalForAll\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"newCheckpointingDisabler\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"setCheckpointingDisabler\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"string\\\",\\\"name\\\":\\\"name\\\",\\\"type\\\":\\\"string\\\"}],\\\"name\\\":\\\"setENSName\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"newGuardian\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"setGuardian\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"newMinter\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"setMinter\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"newMinterAdmin\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"setMinterAdmin\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"newRoyaltyAdmin\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"setRoyaltyAdmin\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"newReceiver\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"uint96\\\",\\\"name\\\":\\\"royaltyPer10Thousands\\\",\\\"type\\\":\\\"uint96\\\"}],\\\"name\\\":\\\"setRoyaltyParameters\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"newTokenURIAdmin\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"setTokenURIAdmin\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"contract ITokenURI\\\",\\\"name\\\":\\\"newTokenURIContract\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"setTokenURIContract\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"id\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"sound\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint8\\\",\\\"name\\\":\\\"note\\\",\\\"type\\\":\\\"uint8\\\"},{\\\"internalType\\\":\\\"uint8\\\",\\\"name\\\":\\\"instrument\\\",\\\"type\\\":\\\"uint8\\\"}],\\\"stateMutability\\\":\\\"pure\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"bytes4\\\",\\\"name\\\":\\\"id\\\",\\\"type\\\":\\\"bytes4\\\"}],\\\"name\\\":\\\"supportsInterface\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"bool\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"bool\\\"}],\\\"stateMutability\\\":\\\"pure\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"symbol\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"string\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"string\\\"}],\\\"stateMutability\\\":\\\"pure\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"id\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"tokenNonces\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"nonce\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"id\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"tokenURI\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"string\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"string\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"tokenURIAdmin\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"address\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[],\\\"name\\\":\\\"tokenURIContract\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"contract ITokenURI\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"address\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"from\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"to\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"id\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"transferFrom\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"newOwner\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"transferOwnership\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"delegator\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"votesToDelegate\\\",\\\"outputs\\\":[{\\\"internalType\\\":\\\"uint96\\\",\\\"name\\\":\\\"\\\",\\\"type\\\":\\\"uint96\\\"}],\\\"stateMutability\\\":\\\"view\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"contract IERC20\\\",\\\"name\\\":\\\"token\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"to\\\",\\\"type\\\":\\\"address\\\"}],\\\"name\\\":\\\"withdrawERC20\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"}]\",\n    \"ContractName\": \"Bleeps\",\n    \"CompilerVersion\": \"v0.8.9+commit.e5eed63a\",\n    \"OptimizationUsed\": 1,\n    \"Runs\": 999999,\n    \"ConstructorArguments\": \"0x00000000000000000000000000000000000c2e074ec69a0dfb2997ba6c7d2e1e0000000000000000000000007773ae67403d2e30102a84c48cc939919c4c881c000000000000000000000000dca9d1fa839bb9fe65ddc4de5161bca43751d4b40000000000000000000000007773ae67403d2e30102a84c48cc939919c4c881c000000000000000000000000dca9d1fa839bb9fe65ddc4de5161bca43751d4b4000000000000000000000000dca9d1fa839bb9fe65ddc4de5161bca43751d4b4000000000000000000000000a5409ec958c83c3f309868babaca7c86dcb077c10000000000000000000000008350c9989ef11325b36ce6f7549004d418dbcee700000000000000000000000000000000000000000000000000000000000001f4000000000000000000000000e114dce59a333f8d351371f54188f92c287b73e6000000000000000000000000dca9d1fa839bb9fe65ddc4de5161bca43751d4b4\",\n    \"EVMVersion\": \"Default\",\n    \"Library\": \"\",\n    \"LicenseType\": \"MIT\",\n    \"Proxy\": 0,\n    \"SwarmSource\": \"\"\n  }\n]"
  },
  {
    "path": "testdata/etherscan/0xDb53f47aC61FE54F456A4eb3E09832D08Dd7BEec/creation_data.json",
    "content": "{\"contractAddress\":\"0xdb53f47ac61fe54f456a4eb3e09832d08dd7beec\",\"contractCreator\":\"0xc7f8d87734ab2cbf70030ac8aa82abfe3e8126cb\",\"txHash\":\"0x196898c69f6b1944f1011120b15c0903329d46259c8cdc0fbcad71da1fe58245\"}"
  },
  {
    "path": "testdata/etherscan/0xDb53f47aC61FE54F456A4eb3E09832D08Dd7BEec/metadata.json",
    "content": "[{\"SourceCode\":{\"language\":\"Solidity\",\"sources\":{\"@solidstate/contracts/token/ERC1155/base/ERC1155Base.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.0;\\n\\nimport { IERC1155 } from '../IERC1155.sol';\\nimport { IERC1155Receiver } from '../IERC1155Receiver.sol';\\nimport { ERC1155BaseInternal, ERC1155BaseStorage } from './ERC1155BaseInternal.sol';\\n\\n/**\\n * @title Base ERC1155 contract\\n * @dev derived from https://github.com/OpenZeppelin/openzeppelin-contracts/ (MIT license)\\n */\\nabstract contract ERC1155Base is IERC1155, ERC1155BaseInternal {\\n    /**\\n     * @inheritdoc IERC1155\\n     */\\n    function balanceOf(address account, uint256 id)\\n        public\\n        view\\n        virtual\\n        override\\n        returns (uint256)\\n    {\\n        return _balanceOf(account, id);\\n    }\\n\\n    /**\\n     * @inheritdoc IERC1155\\n     */\\n    function balanceOfBatch(address[] memory accounts, uint256[] memory ids)\\n        public\\n        view\\n        virtual\\n        override\\n        returns (uint256[] memory)\\n    {\\n        require(\\n            accounts.length == ids.length,\\n            'ERC1155: accounts and ids length mismatch'\\n        );\\n\\n        mapping(uint256 => mapping(address => uint256))\\n            storage balances = ERC1155BaseStorage.layout().balances;\\n\\n        uint256[] memory batchBalances = new uint256[](accounts.length);\\n\\n        unchecked {\\n            for (uint256 i; i < accounts.length; i++) {\\n                require(\\n                    accounts[i] != address(0),\\n                    'ERC1155: batch balance query for the zero address'\\n                );\\n                batchBalances[i] = balances[ids[i]][accounts[i]];\\n            }\\n        }\\n\\n        return batchBalances;\\n    }\\n\\n    /**\\n     * @inheritdoc IERC1155\\n     */\\n    function isApprovedForAll(address account, address operator)\\n        public\\n        view\\n        virtual\\n        override\\n        returns (bool)\\n    {\\n        return ERC1155BaseStorage.layout().operatorApprovals[account][operator];\\n    }\\n\\n    /**\\n     * @inheritdoc IERC1155\\n     */\\n    function setApprovalForAll(address operator, bool status)\\n        public\\n        virtual\\n        override\\n    {\\n        require(\\n            msg.sender != operator,\\n            'ERC1155: setting approval status for self'\\n        );\\n        ERC1155BaseStorage.layout().operatorApprovals[msg.sender][\\n            operator\\n        ] = status;\\n        emit ApprovalForAll(msg.sender, operator, status);\\n    }\\n\\n    /**\\n     * @inheritdoc IERC1155\\n     */\\n    function safeTransferFrom(\\n        address from,\\n        address to,\\n        uint256 id,\\n        uint256 amount,\\n        bytes memory data\\n    ) public virtual override {\\n        require(\\n            from == msg.sender || isApprovedForAll(from, msg.sender),\\n            'ERC1155: caller is not owner nor approved'\\n        );\\n        _safeTransfer(msg.sender, from, to, id, amount, data);\\n    }\\n\\n    /**\\n     * @inheritdoc IERC1155\\n     */\\n    function safeBatchTransferFrom(\\n        address from,\\n        address to,\\n        uint256[] memory ids,\\n        uint256[] memory amounts,\\n        bytes memory data\\n    ) public virtual override {\\n        require(\\n            from == msg.sender || isApprovedForAll(from, msg.sender),\\n            'ERC1155: caller is not owner nor approved'\\n        );\\n        _safeTransferBatch(msg.sender, from, to, ids, amounts, data);\\n    }\\n}\\n\"},\"@solidstate/contracts/introspection/IERC165.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title ERC165 interface registration interface\\n * @dev see https://eips.ethereum.org/EIPS/eip-165\\n */\\ninterface IERC165 {\\n    /**\\n     * @notice query whether contract has registered support for given interface\\n     * @param interfaceId interface id\\n     * @return bool whether interface is supported\\n     */\\n    function supportsInterface(bytes4 interfaceId) external view returns (bool);\\n}\\n\"},\"abdk-libraries-solidity/ABDKMath64x64.sol\":{\"content\":\"// SPDX-License-Identifier: BSD-4-Clause\\n/*\\n * ABDK Math 64.64 Smart Contract Library.  Copyright © 2019 by ABDK Consulting.\\n * Author: Mikhail Vladimirov <mikhail.vladimirov@gmail.com>\\n */\\npragma solidity ^0.8.0;\\n\\n/**\\n * Smart contract library of mathematical functions operating with signed\\n * 64.64-bit fixed point numbers.  Signed 64.64-bit fixed point number is\\n * basically a simple fraction whose numerator is signed 128-bit integer and\\n * denominator is 2^64.  As long as denominator is always the same, there is no\\n * need to store it, thus in Solidity signed 64.64-bit fixed point numbers are\\n * represented by int128 type holding only the numerator.\\n */\\nlibrary ABDKMath64x64 {\\n  /*\\n   * Minimum value signed 64.64-bit fixed point number may have. \\n   */\\n  int128 private constant MIN_64x64 = -0x80000000000000000000000000000000;\\n\\n  /*\\n   * Maximum value signed 64.64-bit fixed point number may have. \\n   */\\n  int128 private constant MAX_64x64 = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;\\n\\n  /**\\n   * Convert signed 256-bit integer number into signed 64.64-bit fixed point\\n   * number.  Revert on overflow.\\n   *\\n   * @param x signed 256-bit integer number\\n   * @return signed 64.64-bit fixed point number\\n   */\\n  function fromInt (int256 x) internal pure returns (int128) {\\n    unchecked {\\n      require (x >= -0x8000000000000000 && x <= 0x7FFFFFFFFFFFFFFF);\\n      return int128 (x << 64);\\n    }\\n  }\\n\\n  /**\\n   * Convert signed 64.64 fixed point number into signed 64-bit integer number\\n   * rounding down.\\n   *\\n   * @param x signed 64.64-bit fixed point number\\n   * @return signed 64-bit integer number\\n   */\\n  function toInt (int128 x) internal pure returns (int64) {\\n    unchecked {\\n      return int64 (x >> 64);\\n    }\\n  }\\n\\n  /**\\n   * Convert unsigned 256-bit integer number into signed 64.64-bit fixed point\\n   * number.  Revert on overflow.\\n   *\\n   * @param x unsigned 256-bit integer number\\n   * @return signed 64.64-bit fixed point number\\n   */\\n  function fromUInt (uint256 x) internal pure returns (int128) {\\n    unchecked {\\n      require (x <= 0x7FFFFFFFFFFFFFFF);\\n      return int128 (int256 (x << 64));\\n    }\\n  }\\n\\n  /**\\n   * Convert signed 64.64 fixed point number into unsigned 64-bit integer\\n   * number rounding down.  Revert on underflow.\\n   *\\n   * @param x signed 64.64-bit fixed point number\\n   * @return unsigned 64-bit integer number\\n   */\\n  function toUInt (int128 x) internal pure returns (uint64) {\\n    unchecked {\\n      require (x >= 0);\\n      return uint64 (uint128 (x >> 64));\\n    }\\n  }\\n\\n  /**\\n   * Convert signed 128.128 fixed point number into signed 64.64-bit fixed point\\n   * number rounding down.  Revert on overflow.\\n   *\\n   * @param x signed 128.128-bin fixed point number\\n   * @return signed 64.64-bit fixed point number\\n   */\\n  function from128x128 (int256 x) internal pure returns (int128) {\\n    unchecked {\\n      int256 result = x >> 64;\\n      require (result >= MIN_64x64 && result <= MAX_64x64);\\n      return int128 (result);\\n    }\\n  }\\n\\n  /**\\n   * Convert signed 64.64 fixed point number into signed 128.128 fixed point\\n   * number.\\n   *\\n   * @param x signed 64.64-bit fixed point number\\n   * @return signed 128.128 fixed point number\\n   */\\n  function to128x128 (int128 x) internal pure returns (int256) {\\n    unchecked {\\n      return int256 (x) << 64;\\n    }\\n  }\\n\\n  /**\\n   * Calculate x + y.  Revert on overflow.\\n   *\\n   * @param x signed 64.64-bit fixed point number\\n   * @param y signed 64.64-bit fixed point number\\n   * @return signed 64.64-bit fixed point number\\n   */\\n  function add (int128 x, int128 y) internal pure returns (int128) {\\n    unchecked {\\n      int256 result = int256(x) + y;\\n      require (result >= MIN_64x64 && result <= MAX_64x64);\\n      return int128 (result);\\n    }\\n  }\\n\\n  /**\\n   * Calculate x - y.  Revert on overflow.\\n   *\\n   * @param x signed 64.64-bit fixed point number\\n   * @param y signed 64.64-bit fixed point number\\n   * @return signed 64.64-bit fixed point number\\n   */\\n  function sub (int128 x, int128 y) internal pure returns (int128) {\\n    unchecked {\\n      int256 result = int256(x) - y;\\n      require (result >= MIN_64x64 && result <= MAX_64x64);\\n      return int128 (result);\\n    }\\n  }\\n\\n  /**\\n   * Calculate x * y rounding down.  Revert on overflow.\\n   *\\n   * @param x signed 64.64-bit fixed point number\\n   * @param y signed 64.64-bit fixed point number\\n   * @return signed 64.64-bit fixed point number\\n   */\\n  function mul (int128 x, int128 y) internal pure returns (int128) {\\n    unchecked {\\n      int256 result = int256(x) * y >> 64;\\n      require (result >= MIN_64x64 && result <= MAX_64x64);\\n      return int128 (result);\\n    }\\n  }\\n\\n  /**\\n   * Calculate x * y rounding towards zero, where x is signed 64.64 fixed point\\n   * number and y is signed 256-bit integer number.  Revert on overflow.\\n   *\\n   * @param x signed 64.64 fixed point number\\n   * @param y signed 256-bit integer number\\n   * @return signed 256-bit integer number\\n   */\\n  function muli (int128 x, int256 y) internal pure returns (int256) {\\n    unchecked {\\n      if (x == MIN_64x64) {\\n        require (y >= -0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF &&\\n          y <= 0x1000000000000000000000000000000000000000000000000);\\n        return -y << 63;\\n      } else {\\n        bool negativeResult = false;\\n        if (x < 0) {\\n          x = -x;\\n          negativeResult = true;\\n        }\\n        if (y < 0) {\\n          y = -y; // We rely on overflow behavior here\\n          negativeResult = !negativeResult;\\n        }\\n        uint256 absoluteResult = mulu (x, uint256 (y));\\n        if (negativeResult) {\\n          require (absoluteResult <=\\n            0x8000000000000000000000000000000000000000000000000000000000000000);\\n          return -int256 (absoluteResult); // We rely on overflow behavior here\\n        } else {\\n          require (absoluteResult <=\\n            0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);\\n          return int256 (absoluteResult);\\n        }\\n      }\\n    }\\n  }\\n\\n  /**\\n   * Calculate x * y rounding down, where x is signed 64.64 fixed point number\\n   * and y is unsigned 256-bit integer number.  Revert on overflow.\\n   *\\n   * @param x signed 64.64 fixed point number\\n   * @param y unsigned 256-bit integer number\\n   * @return unsigned 256-bit integer number\\n   */\\n  function mulu (int128 x, uint256 y) internal pure returns (uint256) {\\n    unchecked {\\n      if (y == 0) return 0;\\n\\n      require (x >= 0);\\n\\n      uint256 lo = (uint256 (int256 (x)) * (y & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)) >> 64;\\n      uint256 hi = uint256 (int256 (x)) * (y >> 128);\\n\\n      require (hi <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);\\n      hi <<= 64;\\n\\n      require (hi <=\\n        0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - lo);\\n      return hi + lo;\\n    }\\n  }\\n\\n  /**\\n   * Calculate x / y rounding towards zero.  Revert on overflow or when y is\\n   * zero.\\n   *\\n   * @param x signed 64.64-bit fixed point number\\n   * @param y signed 64.64-bit fixed point number\\n   * @return signed 64.64-bit fixed point number\\n   */\\n  function div (int128 x, int128 y) internal pure returns (int128) {\\n    unchecked {\\n      require (y != 0);\\n      int256 result = (int256 (x) << 64) / y;\\n      require (result >= MIN_64x64 && result <= MAX_64x64);\\n      return int128 (result);\\n    }\\n  }\\n\\n  /**\\n   * Calculate x / y rounding towards zero, where x and y are signed 256-bit\\n   * integer numbers.  Revert on overflow or when y is zero.\\n   *\\n   * @param x signed 256-bit integer number\\n   * @param y signed 256-bit integer number\\n   * @return signed 64.64-bit fixed point number\\n   */\\n  function divi (int256 x, int256 y) internal pure returns (int128) {\\n    unchecked {\\n      require (y != 0);\\n\\n      bool negativeResult = false;\\n      if (x < 0) {\\n        x = -x; // We rely on overflow behavior here\\n        negativeResult = true;\\n      }\\n      if (y < 0) {\\n        y = -y; // We rely on overflow behavior here\\n        negativeResult = !negativeResult;\\n      }\\n      uint128 absoluteResult = divuu (uint256 (x), uint256 (y));\\n      if (negativeResult) {\\n        require (absoluteResult <= 0x80000000000000000000000000000000);\\n        return -int128 (absoluteResult); // We rely on overflow behavior here\\n      } else {\\n        require (absoluteResult <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);\\n        return int128 (absoluteResult); // We rely on overflow behavior here\\n      }\\n    }\\n  }\\n\\n  /**\\n   * Calculate x / y rounding towards zero, where x and y are unsigned 256-bit\\n   * integer numbers.  Revert on overflow or when y is zero.\\n   *\\n   * @param x unsigned 256-bit integer number\\n   * @param y unsigned 256-bit integer number\\n   * @return signed 64.64-bit fixed point number\\n   */\\n  function divu (uint256 x, uint256 y) internal pure returns (int128) {\\n    unchecked {\\n      require (y != 0);\\n      uint128 result = divuu (x, y);\\n      require (result <= uint128 (MAX_64x64));\\n      return int128 (result);\\n    }\\n  }\\n\\n  /**\\n   * Calculate -x.  Revert on overflow.\\n   *\\n   * @param x signed 64.64-bit fixed point number\\n   * @return signed 64.64-bit fixed point number\\n   */\\n  function neg (int128 x) internal pure returns (int128) {\\n    unchecked {\\n      require (x != MIN_64x64);\\n      return -x;\\n    }\\n  }\\n\\n  /**\\n   * Calculate |x|.  Revert on overflow.\\n   *\\n   * @param x signed 64.64-bit fixed point number\\n   * @return signed 64.64-bit fixed point number\\n   */\\n  function abs (int128 x) internal pure returns (int128) {\\n    unchecked {\\n      require (x != MIN_64x64);\\n      return x < 0 ? -x : x;\\n    }\\n  }\\n\\n  /**\\n   * Calculate 1 / x rounding towards zero.  Revert on overflow or when x is\\n   * zero.\\n   *\\n   * @param x signed 64.64-bit fixed point number\\n   * @return signed 64.64-bit fixed point number\\n   */\\n  function inv (int128 x) internal pure returns (int128) {\\n    unchecked {\\n      require (x != 0);\\n      int256 result = int256 (0x100000000000000000000000000000000) / x;\\n      require (result >= MIN_64x64 && result <= MAX_64x64);\\n      return int128 (result);\\n    }\\n  }\\n\\n  /**\\n   * Calculate arithmetics average of x and y, i.e. (x + y) / 2 rounding down.\\n   *\\n   * @param x signed 64.64-bit fixed point number\\n   * @param y signed 64.64-bit fixed point number\\n   * @return signed 64.64-bit fixed point number\\n   */\\n  function avg (int128 x, int128 y) internal pure returns (int128) {\\n    unchecked {\\n      return int128 ((int256 (x) + int256 (y)) >> 1);\\n    }\\n  }\\n\\n  /**\\n   * Calculate geometric average of x and y, i.e. sqrt (x * y) rounding down.\\n   * Revert on overflow or in case x * y is negative.\\n   *\\n   * @param x signed 64.64-bit fixed point number\\n   * @param y signed 64.64-bit fixed point number\\n   * @return signed 64.64-bit fixed point number\\n   */\\n  function gavg (int128 x, int128 y) internal pure returns (int128) {\\n    unchecked {\\n      int256 m = int256 (x) * int256 (y);\\n      require (m >= 0);\\n      require (m <\\n          0x4000000000000000000000000000000000000000000000000000000000000000);\\n      return int128 (sqrtu (uint256 (m)));\\n    }\\n  }\\n\\n  /**\\n   * Calculate x^y assuming 0^0 is 1, where x is signed 64.64 fixed point number\\n   * and y is unsigned 256-bit integer number.  Revert on overflow.\\n   *\\n   * @param x signed 64.64-bit fixed point number\\n   * @param y uint256 value\\n   * @return signed 64.64-bit fixed point number\\n   */\\n  function pow (int128 x, uint256 y) internal pure returns (int128) {\\n    unchecked {\\n      bool negative = x < 0 && y & 1 == 1;\\n\\n      uint256 absX = uint128 (x < 0 ? -x : x);\\n      uint256 absResult;\\n      absResult = 0x100000000000000000000000000000000;\\n\\n      if (absX <= 0x10000000000000000) {\\n        absX <<= 63;\\n        while (y != 0) {\\n          if (y & 0x1 != 0) {\\n            absResult = absResult * absX >> 127;\\n          }\\n          absX = absX * absX >> 127;\\n\\n          if (y & 0x2 != 0) {\\n            absResult = absResult * absX >> 127;\\n          }\\n          absX = absX * absX >> 127;\\n\\n          if (y & 0x4 != 0) {\\n            absResult = absResult * absX >> 127;\\n          }\\n          absX = absX * absX >> 127;\\n\\n          if (y & 0x8 != 0) {\\n            absResult = absResult * absX >> 127;\\n          }\\n          absX = absX * absX >> 127;\\n\\n          y >>= 4;\\n        }\\n\\n        absResult >>= 64;\\n      } else {\\n        uint256 absXShift = 63;\\n        if (absX < 0x1000000000000000000000000) { absX <<= 32; absXShift -= 32; }\\n        if (absX < 0x10000000000000000000000000000) { absX <<= 16; absXShift -= 16; }\\n        if (absX < 0x1000000000000000000000000000000) { absX <<= 8; absXShift -= 8; }\\n        if (absX < 0x10000000000000000000000000000000) { absX <<= 4; absXShift -= 4; }\\n        if (absX < 0x40000000000000000000000000000000) { absX <<= 2; absXShift -= 2; }\\n        if (absX < 0x80000000000000000000000000000000) { absX <<= 1; absXShift -= 1; }\\n\\n        uint256 resultShift = 0;\\n        while (y != 0) {\\n          require (absXShift < 64);\\n\\n          if (y & 0x1 != 0) {\\n            absResult = absResult * absX >> 127;\\n            resultShift += absXShift;\\n            if (absResult > 0x100000000000000000000000000000000) {\\n              absResult >>= 1;\\n              resultShift += 1;\\n            }\\n          }\\n          absX = absX * absX >> 127;\\n          absXShift <<= 1;\\n          if (absX >= 0x100000000000000000000000000000000) {\\n              absX >>= 1;\\n              absXShift += 1;\\n          }\\n\\n          y >>= 1;\\n        }\\n\\n        require (resultShift < 64);\\n        absResult >>= 64 - resultShift;\\n      }\\n      int256 result = negative ? -int256 (absResult) : int256 (absResult);\\n      require (result >= MIN_64x64 && result <= MAX_64x64);\\n      return int128 (result);\\n    }\\n  }\\n\\n  /**\\n   * Calculate sqrt (x) rounding down.  Revert if x < 0.\\n   *\\n   * @param x signed 64.64-bit fixed point number\\n   * @return signed 64.64-bit fixed point number\\n   */\\n  function sqrt (int128 x) internal pure returns (int128) {\\n    unchecked {\\n      require (x >= 0);\\n      return int128 (sqrtu (uint256 (int256 (x)) << 64));\\n    }\\n  }\\n\\n  /**\\n   * Calculate binary logarithm of x.  Revert if x <= 0.\\n   *\\n   * @param x signed 64.64-bit fixed point number\\n   * @return signed 64.64-bit fixed point number\\n   */\\n  function log_2 (int128 x) internal pure returns (int128) {\\n    unchecked {\\n      require (x > 0);\\n\\n      int256 msb = 0;\\n      int256 xc = x;\\n      if (xc >= 0x10000000000000000) { xc >>= 64; msb += 64; }\\n      if (xc >= 0x100000000) { xc >>= 32; msb += 32; }\\n      if (xc >= 0x10000) { xc >>= 16; msb += 16; }\\n      if (xc >= 0x100) { xc >>= 8; msb += 8; }\\n      if (xc >= 0x10) { xc >>= 4; msb += 4; }\\n      if (xc >= 0x4) { xc >>= 2; msb += 2; }\\n      if (xc >= 0x2) msb += 1;  // No need to shift xc anymore\\n\\n      int256 result = msb - 64 << 64;\\n      uint256 ux = uint256 (int256 (x)) << uint256 (127 - msb);\\n      for (int256 bit = 0x8000000000000000; bit > 0; bit >>= 1) {\\n        ux *= ux;\\n        uint256 b = ux >> 255;\\n        ux >>= 127 + b;\\n        result += bit * int256 (b);\\n      }\\n\\n      return int128 (result);\\n    }\\n  }\\n\\n  /**\\n   * Calculate natural logarithm of x.  Revert if x <= 0.\\n   *\\n   * @param x signed 64.64-bit fixed point number\\n   * @return signed 64.64-bit fixed point number\\n   */\\n  function ln (int128 x) internal pure returns (int128) {\\n    unchecked {\\n      require (x > 0);\\n\\n      return int128 (int256 (\\n          uint256 (int256 (log_2 (x))) * 0xB17217F7D1CF79ABC9E3B39803F2F6AF >> 128));\\n    }\\n  }\\n\\n  /**\\n   * Calculate binary exponent of x.  Revert on overflow.\\n   *\\n   * @param x signed 64.64-bit fixed point number\\n   * @return signed 64.64-bit fixed point number\\n   */\\n  function exp_2 (int128 x) internal pure returns (int128) {\\n    unchecked {\\n      require (x < 0x400000000000000000); // Overflow\\n\\n      if (x < -0x400000000000000000) return 0; // Underflow\\n\\n      uint256 result = 0x80000000000000000000000000000000;\\n\\n      if (x & 0x8000000000000000 > 0)\\n        result = result * 0x16A09E667F3BCC908B2FB1366EA957D3E >> 128;\\n      if (x & 0x4000000000000000 > 0)\\n        result = result * 0x1306FE0A31B7152DE8D5A46305C85EDEC >> 128;\\n      if (x & 0x2000000000000000 > 0)\\n        result = result * 0x1172B83C7D517ADCDF7C8C50EB14A791F >> 128;\\n      if (x & 0x1000000000000000 > 0)\\n        result = result * 0x10B5586CF9890F6298B92B71842A98363 >> 128;\\n      if (x & 0x800000000000000 > 0)\\n        result = result * 0x1059B0D31585743AE7C548EB68CA417FD >> 128;\\n      if (x & 0x400000000000000 > 0)\\n        result = result * 0x102C9A3E778060EE6F7CACA4F7A29BDE8 >> 128;\\n      if (x & 0x200000000000000 > 0)\\n        result = result * 0x10163DA9FB33356D84A66AE336DCDFA3F >> 128;\\n      if (x & 0x100000000000000 > 0)\\n        result = result * 0x100B1AFA5ABCBED6129AB13EC11DC9543 >> 128;\\n      if (x & 0x80000000000000 > 0)\\n        result = result * 0x10058C86DA1C09EA1FF19D294CF2F679B >> 128;\\n      if (x & 0x40000000000000 > 0)\\n        result = result * 0x1002C605E2E8CEC506D21BFC89A23A00F >> 128;\\n      if (x & 0x20000000000000 > 0)\\n        result = result * 0x100162F3904051FA128BCA9C55C31E5DF >> 128;\\n      if (x & 0x10000000000000 > 0)\\n        result = result * 0x1000B175EFFDC76BA38E31671CA939725 >> 128;\\n      if (x & 0x8000000000000 > 0)\\n        result = result * 0x100058BA01FB9F96D6CACD4B180917C3D >> 128;\\n      if (x & 0x4000000000000 > 0)\\n        result = result * 0x10002C5CC37DA9491D0985C348C68E7B3 >> 128;\\n      if (x & 0x2000000000000 > 0)\\n        result = result * 0x1000162E525EE054754457D5995292026 >> 128;\\n      if (x & 0x1000000000000 > 0)\\n        result = result * 0x10000B17255775C040618BF4A4ADE83FC >> 128;\\n      if (x & 0x800000000000 > 0)\\n        result = result * 0x1000058B91B5BC9AE2EED81E9B7D4CFAB >> 128;\\n      if (x & 0x400000000000 > 0)\\n        result = result * 0x100002C5C89D5EC6CA4D7C8ACC017B7C9 >> 128;\\n      if (x & 0x200000000000 > 0)\\n        result = result * 0x10000162E43F4F831060E02D839A9D16D >> 128;\\n      if (x & 0x100000000000 > 0)\\n        result = result * 0x100000B1721BCFC99D9F890EA06911763 >> 128;\\n      if (x & 0x80000000000 > 0)\\n        result = result * 0x10000058B90CF1E6D97F9CA14DBCC1628 >> 128;\\n      if (x & 0x40000000000 > 0)\\n        result = result * 0x1000002C5C863B73F016468F6BAC5CA2B >> 128;\\n      if (x & 0x20000000000 > 0)\\n        result = result * 0x100000162E430E5A18F6119E3C02282A5 >> 128;\\n      if (x & 0x10000000000 > 0)\\n        result = result * 0x1000000B1721835514B86E6D96EFD1BFE >> 128;\\n      if (x & 0x8000000000 > 0)\\n        result = result * 0x100000058B90C0B48C6BE5DF846C5B2EF >> 128;\\n      if (x & 0x4000000000 > 0)\\n        result = result * 0x10000002C5C8601CC6B9E94213C72737A >> 128;\\n      if (x & 0x2000000000 > 0)\\n        result = result * 0x1000000162E42FFF037DF38AA2B219F06 >> 128;\\n      if (x & 0x1000000000 > 0)\\n        result = result * 0x10000000B17217FBA9C739AA5819F44F9 >> 128;\\n      if (x & 0x800000000 > 0)\\n        result = result * 0x1000000058B90BFCDEE5ACD3C1CEDC823 >> 128;\\n      if (x & 0x400000000 > 0)\\n        result = result * 0x100000002C5C85FE31F35A6A30DA1BE50 >> 128;\\n      if (x & 0x200000000 > 0)\\n        result = result * 0x10000000162E42FF0999CE3541B9FFFCF >> 128;\\n      if (x & 0x100000000 > 0)\\n        result = result * 0x100000000B17217F80F4EF5AADDA45554 >> 128;\\n      if (x & 0x80000000 > 0)\\n        result = result * 0x10000000058B90BFBF8479BD5A81B51AD >> 128;\\n      if (x & 0x40000000 > 0)\\n        result = result * 0x1000000002C5C85FDF84BD62AE30A74CC >> 128;\\n      if (x & 0x20000000 > 0)\\n        result = result * 0x100000000162E42FEFB2FED257559BDAA >> 128;\\n      if (x & 0x10000000 > 0)\\n        result = result * 0x1000000000B17217F7D5A7716BBA4A9AE >> 128;\\n      if (x & 0x8000000 > 0)\\n        result = result * 0x100000000058B90BFBE9DDBAC5E109CCE >> 128;\\n      if (x & 0x4000000 > 0)\\n        result = result * 0x10000000002C5C85FDF4B15DE6F17EB0D >> 128;\\n      if (x & 0x2000000 > 0)\\n        result = result * 0x1000000000162E42FEFA494F1478FDE05 >> 128;\\n      if (x & 0x1000000 > 0)\\n        result = result * 0x10000000000B17217F7D20CF927C8E94C >> 128;\\n      if (x & 0x800000 > 0)\\n        result = result * 0x1000000000058B90BFBE8F71CB4E4B33D >> 128;\\n      if (x & 0x400000 > 0)\\n        result = result * 0x100000000002C5C85FDF477B662B26945 >> 128;\\n      if (x & 0x200000 > 0)\\n        result = result * 0x10000000000162E42FEFA3AE53369388C >> 128;\\n      if (x & 0x100000 > 0)\\n        result = result * 0x100000000000B17217F7D1D351A389D40 >> 128;\\n      if (x & 0x80000 > 0)\\n        result = result * 0x10000000000058B90BFBE8E8B2D3D4EDE >> 128;\\n      if (x & 0x40000 > 0)\\n        result = result * 0x1000000000002C5C85FDF4741BEA6E77E >> 128;\\n      if (x & 0x20000 > 0)\\n        result = result * 0x100000000000162E42FEFA39FE95583C2 >> 128;\\n      if (x & 0x10000 > 0)\\n        result = result * 0x1000000000000B17217F7D1CFB72B45E1 >> 128;\\n      if (x & 0x8000 > 0)\\n        result = result * 0x100000000000058B90BFBE8E7CC35C3F0 >> 128;\\n      if (x & 0x4000 > 0)\\n        result = result * 0x10000000000002C5C85FDF473E242EA38 >> 128;\\n      if (x & 0x2000 > 0)\\n        result = result * 0x1000000000000162E42FEFA39F02B772C >> 128;\\n      if (x & 0x1000 > 0)\\n        result = result * 0x10000000000000B17217F7D1CF7D83C1A >> 128;\\n      if (x & 0x800 > 0)\\n        result = result * 0x1000000000000058B90BFBE8E7BDCBE2E >> 128;\\n      if (x & 0x400 > 0)\\n        result = result * 0x100000000000002C5C85FDF473DEA871F >> 128;\\n      if (x & 0x200 > 0)\\n        result = result * 0x10000000000000162E42FEFA39EF44D91 >> 128;\\n      if (x & 0x100 > 0)\\n        result = result * 0x100000000000000B17217F7D1CF79E949 >> 128;\\n      if (x & 0x80 > 0)\\n        result = result * 0x10000000000000058B90BFBE8E7BCE544 >> 128;\\n      if (x & 0x40 > 0)\\n        result = result * 0x1000000000000002C5C85FDF473DE6ECA >> 128;\\n      if (x & 0x20 > 0)\\n        result = result * 0x100000000000000162E42FEFA39EF366F >> 128;\\n      if (x & 0x10 > 0)\\n        result = result * 0x1000000000000000B17217F7D1CF79AFA >> 128;\\n      if (x & 0x8 > 0)\\n        result = result * 0x100000000000000058B90BFBE8E7BCD6D >> 128;\\n      if (x & 0x4 > 0)\\n        result = result * 0x10000000000000002C5C85FDF473DE6B2 >> 128;\\n      if (x & 0x2 > 0)\\n        result = result * 0x1000000000000000162E42FEFA39EF358 >> 128;\\n      if (x & 0x1 > 0)\\n        result = result * 0x10000000000000000B17217F7D1CF79AB >> 128;\\n\\n      result >>= uint256 (int256 (63 - (x >> 64)));\\n      require (result <= uint256 (int256 (MAX_64x64)));\\n\\n      return int128 (int256 (result));\\n    }\\n  }\\n\\n  /**\\n   * Calculate natural exponent of x.  Revert on overflow.\\n   *\\n   * @param x signed 64.64-bit fixed point number\\n   * @return signed 64.64-bit fixed point number\\n   */\\n  function exp (int128 x) internal pure returns (int128) {\\n    unchecked {\\n      require (x < 0x400000000000000000); // Overflow\\n\\n      if (x < -0x400000000000000000) return 0; // Underflow\\n\\n      return exp_2 (\\n          int128 (int256 (x) * 0x171547652B82FE1777D0FFDA0D23A7D12 >> 128));\\n    }\\n  }\\n\\n  /**\\n   * Calculate x / y rounding towards zero, where x and y are unsigned 256-bit\\n   * integer numbers.  Revert on overflow or when y is zero.\\n   *\\n   * @param x unsigned 256-bit integer number\\n   * @param y unsigned 256-bit integer number\\n   * @return unsigned 64.64-bit fixed point number\\n   */\\n  function divuu (uint256 x, uint256 y) private pure returns (uint128) {\\n    unchecked {\\n      require (y != 0);\\n\\n      uint256 result;\\n\\n      if (x <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)\\n        result = (x << 64) / y;\\n      else {\\n        uint256 msb = 192;\\n        uint256 xc = x >> 192;\\n        if (xc >= 0x100000000) { xc >>= 32; msb += 32; }\\n        if (xc >= 0x10000) { xc >>= 16; msb += 16; }\\n        if (xc >= 0x100) { xc >>= 8; msb += 8; }\\n        if (xc >= 0x10) { xc >>= 4; msb += 4; }\\n        if (xc >= 0x4) { xc >>= 2; msb += 2; }\\n        if (xc >= 0x2) msb += 1;  // No need to shift xc anymore\\n\\n        result = (x << 255 - msb) / ((y - 1 >> msb - 191) + 1);\\n        require (result <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);\\n\\n        uint256 hi = result * (y >> 128);\\n        uint256 lo = result * (y & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);\\n\\n        uint256 xh = x >> 192;\\n        uint256 xl = x << 64;\\n\\n        if (xl < lo) xh -= 1;\\n        xl -= lo; // We rely on overflow behavior here\\n        lo = hi << 128;\\n        if (xl < lo) xh -= 1;\\n        xl -= lo; // We rely on overflow behavior here\\n\\n        assert (xh == hi >> 128);\\n\\n        result += xl / y;\\n      }\\n\\n      require (result <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);\\n      return uint128 (result);\\n    }\\n  }\\n\\n  /**\\n   * Calculate sqrt (x) rounding down, where x is unsigned 256-bit integer\\n   * number.\\n   *\\n   * @param x unsigned 256-bit integer number\\n   * @return unsigned 128-bit integer number\\n   */\\n  function sqrtu (uint256 x) private pure returns (uint128) {\\n    unchecked {\\n      if (x == 0) return 0;\\n      else {\\n        uint256 xx = x;\\n        uint256 r = 1;\\n        if (xx >= 0x100000000000000000000000000000000) { xx >>= 128; r <<= 64; }\\n        if (xx >= 0x10000000000000000) { xx >>= 64; r <<= 32; }\\n        if (xx >= 0x100000000) { xx >>= 32; r <<= 16; }\\n        if (xx >= 0x10000) { xx >>= 16; r <<= 8; }\\n        if (xx >= 0x100) { xx >>= 8; r <<= 4; }\\n        if (xx >= 0x10) { xx >>= 4; r <<= 2; }\\n        if (xx >= 0x8) { r <<= 1; }\\n        r = (r + x / r) >> 1;\\n        r = (r + x / r) >> 1;\\n        r = (r + x / r) >> 1;\\n        r = (r + x / r) >> 1;\\n        r = (r + x / r) >> 1;\\n        r = (r + x / r) >> 1;\\n        r = (r + x / r) >> 1; // Seven iterations should be enough\\n        uint256 r1 = x / r;\\n        return uint128 (r < r1 ? r : r1);\\n      }\\n    }\\n  }\\n}\\n\"},\"@solidstate/contracts/token/ERC20/metadata/IERC20Metadata.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title ERC20 metadata interface\\n */\\ninterface IERC20Metadata {\\n    /**\\n     * @notice return token name\\n     * @return token name\\n     */\\n    function name() external view returns (string memory);\\n\\n    /**\\n     * @notice return token symbol\\n     * @return token symbol\\n     */\\n    function symbol() external view returns (string memory);\\n\\n    /**\\n     * @notice return token decimals, generally used only for display purposes\\n     * @return token decimals\\n     */\\n    function decimals() external view returns (uint8);\\n}\\n\"},\"contracts/staking/FeeDiscountStorage.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\n// For further clarification please see https://license.premia.legal\\r\\n\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nlibrary FeeDiscountStorage {\\r\\n    bytes32 internal constant STORAGE_SLOT =\\r\\n        keccak256(\\\"premia.contracts.staking.PremiaFeeDiscount\\\");\\r\\n\\r\\n    struct UserInfo {\\r\\n        uint256 balance; // Balance staked by user\\r\\n        uint64 stakePeriod; // Stake period selected by user\\r\\n        uint64 lockedUntil; // Timestamp at which the lock ends\\r\\n    }\\r\\n\\r\\n    struct Layout {\\r\\n        // User data with xPREMIA balance staked and date at which lock ends\\r\\n        mapping(address => UserInfo) userInfo;\\r\\n    }\\r\\n\\r\\n    function layout() internal pure returns (Layout storage l) {\\r\\n        bytes32 slot = STORAGE_SLOT;\\r\\n        assembly {\\r\\n            l.slot := slot\\r\\n        }\\r\\n    }\\r\\n}\\r\\n\"},\"contracts/libraries/OptionMath.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\n// For further clarification please see https://license.premia.legal\\r\\n\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport {ABDKMath64x64} from \\\"abdk-libraries-solidity/ABDKMath64x64.sol\\\";\\r\\n\\r\\nlibrary OptionMath {\\r\\n    using ABDKMath64x64 for int128;\\r\\n\\r\\n    struct QuoteArgs {\\r\\n        int128 varianceAnnualized64x64; // 64x64 fixed point representation of annualized variance\\r\\n        int128 strike64x64; // 64x64 fixed point representation of strike price\\r\\n        int128 spot64x64; // 64x64 fixed point representation of spot price\\r\\n        int128 timeToMaturity64x64; // 64x64 fixed point representation of duration of option contract (in years)\\r\\n        int128 oldCLevel64x64; // 64x64 fixed point representation of C-Level of Pool before purchase\\r\\n        int128 oldPoolState; // 64x64 fixed point representation of current state of the pool\\r\\n        int128 newPoolState; // 64x64 fixed point representation of state of the pool after trade\\r\\n        int128 steepness64x64; // 64x64 fixed point representation of Pool state delta multiplier\\r\\n        int128 minAPY64x64; // 64x64 fixed point representation of minimum APY for capital locked up to underwrite options\\r\\n        bool isCall; // whether to price \\\"call\\\" or \\\"put\\\" option\\r\\n    }\\r\\n\\r\\n    struct CalculateCLevelDecayArgs {\\r\\n        int128 timeIntervalsElapsed64x64; // 64x64 fixed point representation of quantity of discrete arbitrary intervals elapsed since last update\\r\\n        int128 oldCLevel64x64; // 64x64 fixed point representation of C-Level prior to accounting for decay\\r\\n        int128 utilization64x64; // 64x64 fixed point representation of pool capital utilization rate\\r\\n        int128 utilizationLowerBound64x64;\\r\\n        int128 utilizationUpperBound64x64;\\r\\n        int128 cLevelLowerBound64x64;\\r\\n        int128 cLevelUpperBound64x64;\\r\\n        int128 cConvergenceULowerBound64x64;\\r\\n        int128 cConvergenceUUpperBound64x64;\\r\\n    }\\r\\n\\r\\n    // 64x64 fixed point integer constants\\r\\n    int128 internal constant ONE_64x64 = 0x10000000000000000;\\r\\n    int128 internal constant THREE_64x64 = 0x30000000000000000;\\r\\n\\r\\n    // 64x64 fixed point constants used in Choudhury’s approximation of the Black-Scholes CDF\\r\\n    int128 private constant CDF_CONST_0 = 0x09109f285df452394; // 2260 / 3989\\r\\n    int128 private constant CDF_CONST_1 = 0x19abac0ea1da65036; // 6400 / 3989\\r\\n    int128 private constant CDF_CONST_2 = 0x0d3c84b78b749bd6b; // 3300 / 3989\\r\\n\\r\\n    /**\\r\\n     * @notice recalculate C-Level based on change in liquidity\\r\\n     * @param initialCLevel64x64 64x64 fixed point representation of C-Level of Pool before update\\r\\n     * @param oldPoolState64x64 64x64 fixed point representation of liquidity in pool before update\\r\\n     * @param newPoolState64x64 64x64 fixed point representation of liquidity in pool after update\\r\\n     * @param steepness64x64 64x64 fixed point representation of steepness coefficient\\r\\n     * @return 64x64 fixed point representation of new C-Level\\r\\n     */\\r\\n    function calculateCLevel(\\r\\n        int128 initialCLevel64x64,\\r\\n        int128 oldPoolState64x64,\\r\\n        int128 newPoolState64x64,\\r\\n        int128 steepness64x64\\r\\n    ) external pure returns (int128) {\\r\\n        return\\r\\n            newPoolState64x64\\r\\n                .sub(oldPoolState64x64)\\r\\n                .div(\\r\\n                    oldPoolState64x64 > newPoolState64x64\\r\\n                        ? oldPoolState64x64\\r\\n                        : newPoolState64x64\\r\\n                )\\r\\n                .mul(steepness64x64)\\r\\n                .neg()\\r\\n                .exp()\\r\\n                .mul(initialCLevel64x64);\\r\\n    }\\r\\n\\r\\n    /**\\r\\n     * @notice calculate the price of an option using the Premia Finance model\\r\\n     * @param args arguments of quotePrice\\r\\n     * @return premiaPrice64x64 64x64 fixed point representation of Premia option price\\r\\n     * @return cLevel64x64 64x64 fixed point representation of C-Level of Pool after purchase\\r\\n     */\\r\\n    function quotePrice(QuoteArgs memory args)\\r\\n        external\\r\\n        pure\\r\\n        returns (\\r\\n            int128 premiaPrice64x64,\\r\\n            int128 cLevel64x64,\\r\\n            int128 slippageCoefficient64x64\\r\\n        )\\r\\n    {\\r\\n        int128 deltaPoolState64x64 = args\\r\\n            .newPoolState\\r\\n            .sub(args.oldPoolState)\\r\\n            .div(args.oldPoolState)\\r\\n            .mul(args.steepness64x64);\\r\\n        int128 tradingDelta64x64 = deltaPoolState64x64.neg().exp();\\r\\n\\r\\n        int128 blackScholesPrice64x64 = _blackScholesPrice(\\r\\n            args.varianceAnnualized64x64,\\r\\n            args.strike64x64,\\r\\n            args.spot64x64,\\r\\n            args.timeToMaturity64x64,\\r\\n            args.isCall\\r\\n        );\\r\\n\\r\\n        cLevel64x64 = tradingDelta64x64.mul(args.oldCLevel64x64);\\r\\n        slippageCoefficient64x64 = ONE_64x64.sub(tradingDelta64x64).div(\\r\\n            deltaPoolState64x64\\r\\n        );\\r\\n\\r\\n        premiaPrice64x64 = blackScholesPrice64x64.mul(cLevel64x64).mul(\\r\\n            slippageCoefficient64x64\\r\\n        );\\r\\n\\r\\n        int128 intrinsicValue64x64;\\r\\n\\r\\n        if (args.isCall && args.strike64x64 < args.spot64x64) {\\r\\n            intrinsicValue64x64 = args.spot64x64.sub(args.strike64x64);\\r\\n        } else if (!args.isCall && args.strike64x64 > args.spot64x64) {\\r\\n            intrinsicValue64x64 = args.strike64x64.sub(args.spot64x64);\\r\\n        }\\r\\n\\r\\n        int128 collateralValue64x64 = args.isCall\\r\\n            ? args.spot64x64\\r\\n            : args.strike64x64;\\r\\n\\r\\n        int128 minPrice64x64 = intrinsicValue64x64.add(\\r\\n            collateralValue64x64.mul(args.minAPY64x64).mul(\\r\\n                args.timeToMaturity64x64\\r\\n            )\\r\\n        );\\r\\n\\r\\n        if (minPrice64x64 > premiaPrice64x64) {\\r\\n            premiaPrice64x64 = minPrice64x64;\\r\\n        }\\r\\n    }\\r\\n\\r\\n    /**\\r\\n     * @notice calculate the decay of C-Level based on heat diffusion function\\r\\n     * @param args structured CalculateCLevelDecayArgs\\r\\n     * @return cLevelDecayed64x64 C-Level after accounting for decay\\r\\n     */\\r\\n    function calculateCLevelDecay(CalculateCLevelDecayArgs memory args)\\r\\n        external\\r\\n        pure\\r\\n        returns (int128 cLevelDecayed64x64)\\r\\n    {\\r\\n        int128 convFHighU64x64 = (args.utilization64x64 >=\\r\\n            args.utilizationUpperBound64x64 &&\\r\\n            args.oldCLevel64x64 <= args.cLevelLowerBound64x64)\\r\\n            ? ONE_64x64\\r\\n            : int128(0);\\r\\n\\r\\n        int128 convFLowU64x64 = (args.utilization64x64 <=\\r\\n            args.utilizationLowerBound64x64 &&\\r\\n            args.oldCLevel64x64 >= args.cLevelUpperBound64x64)\\r\\n            ? ONE_64x64\\r\\n            : int128(0);\\r\\n\\r\\n        cLevelDecayed64x64 = args\\r\\n            .oldCLevel64x64\\r\\n            .sub(args.cConvergenceULowerBound64x64.mul(convFLowU64x64))\\r\\n            .sub(args.cConvergenceUUpperBound64x64.mul(convFHighU64x64))\\r\\n            .mul(\\r\\n                convFLowU64x64\\r\\n                    .mul(ONE_64x64.sub(args.utilization64x64))\\r\\n                    .add(convFHighU64x64.mul(args.utilization64x64))\\r\\n                    .mul(args.timeIntervalsElapsed64x64)\\r\\n                    .neg()\\r\\n                    .exp()\\r\\n            )\\r\\n            .add(\\r\\n                args.cConvergenceULowerBound64x64.mul(convFLowU64x64).add(\\r\\n                    args.cConvergenceUUpperBound64x64.mul(convFHighU64x64)\\r\\n                )\\r\\n            );\\r\\n    }\\r\\n\\r\\n    /**\\r\\n     * @notice calculate the exponential decay coefficient for a given interval\\r\\n     * @param oldTimestamp timestamp of previous update\\r\\n     * @param newTimestamp current timestamp\\r\\n     * @return 64x64 fixed point representation of exponential decay coefficient\\r\\n     */\\r\\n    function _decay(uint256 oldTimestamp, uint256 newTimestamp)\\r\\n        internal\\r\\n        pure\\r\\n        returns (int128)\\r\\n    {\\r\\n        return\\r\\n            ONE_64x64.sub(\\r\\n                (-ABDKMath64x64.divu(newTimestamp - oldTimestamp, 7 days)).exp()\\r\\n            );\\r\\n    }\\r\\n\\r\\n    /**\\r\\n     * @notice calculate Choudhury’s approximation of the Black-Scholes CDF\\r\\n     * @param input64x64 64x64 fixed point representation of random variable\\r\\n     * @return 64x64 fixed point representation of the approximated CDF of x\\r\\n     */\\r\\n    function _N(int128 input64x64) internal pure returns (int128) {\\r\\n        // squaring via mul is cheaper than via pow\\r\\n        int128 inputSquared64x64 = input64x64.mul(input64x64);\\r\\n\\r\\n        int128 value64x64 = (-inputSquared64x64 >> 1).exp().div(\\r\\n            CDF_CONST_0.add(CDF_CONST_1.mul(input64x64.abs())).add(\\r\\n                CDF_CONST_2.mul(inputSquared64x64.add(THREE_64x64).sqrt())\\r\\n            )\\r\\n        );\\r\\n\\r\\n        return input64x64 > 0 ? ONE_64x64.sub(value64x64) : value64x64;\\r\\n    }\\r\\n\\r\\n    /**\\r\\n     * @notice calculate the price of an option using the Black-Scholes model\\r\\n     * @param varianceAnnualized64x64 64x64 fixed point representation of annualized variance\\r\\n     * @param strike64x64 64x64 fixed point representation of strike price\\r\\n     * @param spot64x64 64x64 fixed point representation of spot price\\r\\n     * @param timeToMaturity64x64 64x64 fixed point representation of duration of option contract (in years)\\r\\n     * @param isCall whether to price \\\"call\\\" or \\\"put\\\" option\\r\\n     * @return 64x64 fixed point representation of Black-Scholes option price\\r\\n     */\\r\\n    function _blackScholesPrice(\\r\\n        int128 varianceAnnualized64x64,\\r\\n        int128 strike64x64,\\r\\n        int128 spot64x64,\\r\\n        int128 timeToMaturity64x64,\\r\\n        bool isCall\\r\\n    ) internal pure returns (int128) {\\r\\n        int128 cumulativeVariance64x64 = timeToMaturity64x64.mul(\\r\\n            varianceAnnualized64x64\\r\\n        );\\r\\n        int128 cumulativeVarianceSqrt64x64 = cumulativeVariance64x64.sqrt();\\r\\n\\r\\n        int128 d1_64x64 = spot64x64\\r\\n            .div(strike64x64)\\r\\n            .ln()\\r\\n            .add(cumulativeVariance64x64 >> 1)\\r\\n            .div(cumulativeVarianceSqrt64x64);\\r\\n        int128 d2_64x64 = d1_64x64.sub(cumulativeVarianceSqrt64x64);\\r\\n\\r\\n        if (isCall) {\\r\\n            return\\r\\n                spot64x64.mul(_N(d1_64x64)).sub(strike64x64.mul(_N(d2_64x64)));\\r\\n        } else {\\r\\n            return\\r\\n                -spot64x64.mul(_N(-d1_64x64)).sub(\\r\\n                    strike64x64.mul(_N(-d2_64x64))\\r\\n                );\\r\\n        }\\r\\n    }\\r\\n}\\r\\n\"},\"@solidstate/contracts/access/IERC173.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Contract ownership standard interface\\n * @dev see https://eips.ethereum.org/EIPS/eip-173\\n */\\ninterface IERC173 {\\n    event OwnershipTransferred(\\n        address indexed previousOwner,\\n        address indexed newOwner\\n    );\\n\\n    /**\\n     * @notice get the ERC173 contract owner\\n     * @return conract owner\\n     */\\n    function owner() external view returns (address);\\n\\n    /**\\n     * @notice transfer contract ownership to new account\\n     * @param account address of new owner\\n     */\\n    function transferOwnership(address account) external;\\n}\\n\"},\"contracts/libraries/ABDKMath64x64Token.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\n// For further clarification please see https://license.premia.legal\\r\\n\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport {ABDKMath64x64} from \\\"abdk-libraries-solidity/ABDKMath64x64.sol\\\";\\r\\n\\r\\nlibrary ABDKMath64x64Token {\\r\\n    using ABDKMath64x64 for int128;\\r\\n\\r\\n    /**\\r\\n     * @notice convert 64x64 fixed point representation of token amount to decimal\\r\\n     * @param value64x64 64x64 fixed point representation of token amount\\r\\n     * @param decimals token display decimals\\r\\n     * @return value decimal representation of token amount\\r\\n     */\\r\\n    function toDecimals(int128 value64x64, uint8 decimals)\\r\\n        internal\\r\\n        pure\\r\\n        returns (uint256 value)\\r\\n    {\\r\\n        value = value64x64.mulu(10**decimals);\\r\\n    }\\r\\n\\r\\n    /**\\r\\n     * @notice convert decimal representation of token amount to 64x64 fixed point\\r\\n     * @param value decimal representation of token amount\\r\\n     * @param decimals token display decimals\\r\\n     * @return value64x64 64x64 fixed point representation of token amount\\r\\n     */\\r\\n    function fromDecimals(uint256 value, uint8 decimals)\\r\\n        internal\\r\\n        pure\\r\\n        returns (int128 value64x64)\\r\\n    {\\r\\n        value64x64 = ABDKMath64x64.divu(value, 10**decimals);\\r\\n    }\\r\\n\\r\\n    /**\\r\\n     * @notice convert 64x64 fixed point representation of token amount to wei (18 decimals)\\r\\n     * @param value64x64 64x64 fixed point representation of token amount\\r\\n     * @return value wei representation of token amount\\r\\n     */\\r\\n    function toWei(int128 value64x64) internal pure returns (uint256 value) {\\r\\n        value = toDecimals(value64x64, 18);\\r\\n    }\\r\\n\\r\\n    /**\\r\\n     * @notice convert wei representation (18 decimals) of token amount to 64x64 fixed point\\r\\n     * @param value wei representation of token amount\\r\\n     * @return value64x64 64x64 fixed point representation of token amount\\r\\n     */\\r\\n    function fromWei(uint256 value) internal pure returns (int128 value64x64) {\\r\\n        value64x64 = fromDecimals(value, 18);\\r\\n    }\\r\\n}\\r\\n\"},\"@solidstate/contracts/token/ERC1155/IERC1155.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.0;\\n\\nimport { IERC1155Internal } from './IERC1155Internal.sol';\\nimport { IERC165 } from '../../introspection/IERC165.sol';\\n\\n/**\\n * @notice ERC1155 interface\\n * @dev see https://github.com/ethereum/EIPs/issues/1155\\n */\\ninterface IERC1155 is IERC1155Internal, IERC165 {\\n    /**\\n     * @notice query the balance of given token held by given address\\n     * @param account address to query\\n     * @param id token to query\\n     * @return token balance\\n     */\\n    function balanceOf(address account, uint256 id)\\n        external\\n        view\\n        returns (uint256);\\n\\n    /**\\n     * @notice query the balances of given tokens held by given addresses\\n     * @param accounts addresss to query\\n     * @param ids tokens to query\\n     * @return token balances\\n     */\\n    function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids)\\n        external\\n        view\\n        returns (uint256[] memory);\\n\\n    /**\\n     * @notice query approval status of given operator with respect to given address\\n     * @param account address to query for approval granted\\n     * @param operator address to query for approval received\\n     * @return whether operator is approved to spend tokens held by account\\n     */\\n    function isApprovedForAll(address account, address operator)\\n        external\\n        view\\n        returns (bool);\\n\\n    /**\\n     * @notice grant approval to or revoke approval from given operator to spend held tokens\\n     * @param operator address whose approval status to update\\n     * @param status whether operator should be considered approved\\n     */\\n    function setApprovalForAll(address operator, bool status) external;\\n\\n    /**\\n     * @notice transfer tokens between given addresses, checking for ERC1155Receiver implementation if applicable\\n     * @param from sender of tokens\\n     * @param to receiver of tokens\\n     * @param id token ID\\n     * @param amount quantity of tokens to transfer\\n     * @param data data payload\\n     */\\n    function safeTransferFrom(\\n        address from,\\n        address to,\\n        uint256 id,\\n        uint256 amount,\\n        bytes calldata data\\n    ) external;\\n\\n    /**\\n     * @notice transfer batch of tokens between given addresses, checking for ERC1155Receiver implementation if applicable\\n     * @param from sender of tokens\\n     * @param to receiver of tokens\\n     * @param ids list of token IDs\\n     * @param amounts list of quantities of tokens to transfer\\n     * @param data data payload\\n     */\\n    function safeBatchTransferFrom(\\n        address from,\\n        address to,\\n        uint256[] calldata ids,\\n        uint256[] calldata amounts,\\n        bytes calldata data\\n    ) external;\\n}\\n\"},\"contracts/staking/IFeeDiscount.sol\":{\"content\":\"// SPDX-License-Identifier: LGPL-3.0-or-later\\r\\n\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport {FeeDiscountStorage} from \\\"./FeeDiscountStorage.sol\\\";\\r\\n\\r\\ninterface IFeeDiscount {\\r\\n    event Staked(\\r\\n        address indexed user,\\r\\n        uint256 amount,\\r\\n        uint256 stakePeriod,\\r\\n        uint256 lockedUntil\\r\\n    );\\r\\n    event Unstaked(address indexed user, uint256 amount);\\r\\n\\r\\n    struct StakeLevel {\\r\\n        uint256 amount; // Amount to stake\\r\\n        uint256 discount; // Discount when amount is reached\\r\\n    }\\r\\n\\r\\n    /**\\r\\n     * @notice Stake using IERC2612 permit\\r\\n     * @param amount The amount of xPremia to stake\\r\\n     * @param period The lockup period (in seconds)\\r\\n     * @param deadline Deadline after which permit will fail\\r\\n     * @param v V\\r\\n     * @param r R\\r\\n     * @param s S\\r\\n     */\\r\\n    function stakeWithPermit(\\r\\n        uint256 amount,\\r\\n        uint256 period,\\r\\n        uint256 deadline,\\r\\n        uint8 v,\\r\\n        bytes32 r,\\r\\n        bytes32 s\\r\\n    ) external;\\r\\n\\r\\n    /**\\r\\n     * @notice Lockup xPremia for protocol fee discounts\\r\\n     *          Longer period of locking will apply a multiplier on the amount staked, in the fee discount calculation\\r\\n     * @param amount The amount of xPremia to stake\\r\\n     * @param period The lockup period (in seconds)\\r\\n     */\\r\\n    function stake(uint256 amount, uint256 period) external;\\r\\n\\r\\n    /**\\r\\n     * @notice Unstake xPremia (If lockup period has ended)\\r\\n     * @param amount The amount of xPremia to unstake\\r\\n     */\\r\\n    function unstake(uint256 amount) external;\\r\\n\\r\\n    //////////\\r\\n    // View //\\r\\n    //////////\\r\\n\\r\\n    /**\\r\\n     * Calculate the stake amount of a user, after applying the bonus from the lockup period chosen\\r\\n     * @param user The user from which to query the stake amount\\r\\n     * @return The user stake amount after applying the bonus\\r\\n     */\\r\\n    function getStakeAmountWithBonus(address user)\\r\\n        external\\r\\n        view\\r\\n        returns (uint256);\\r\\n\\r\\n    /**\\r\\n     * @notice Calculate the % of fee discount for user, based on his stake\\r\\n     * @param user The _user for which the discount is for\\r\\n     * @return Percentage of protocol fee discount (in basis point)\\r\\n     *         Ex : 1000 = 10% fee discount\\r\\n     */\\r\\n    function getDiscount(address user) external view returns (uint256);\\r\\n\\r\\n    /**\\r\\n     * @notice Get stake levels\\r\\n     * @return Stake levels\\r\\n     *         Ex : 2500 = -25%\\r\\n     */\\r\\n    function getStakeLevels() external returns (StakeLevel[] memory);\\r\\n\\r\\n    /**\\r\\n     * @notice Get stake period multiplier\\r\\n     * @param period The duration (in seconds) for which tokens are locked\\r\\n     * @return The multiplier for this staking period\\r\\n     *         Ex : 20000 = x2\\r\\n     */\\r\\n    function getStakePeriodMultiplier(uint256 period)\\r\\n        external\\r\\n        returns (uint256);\\r\\n\\r\\n    /**\\r\\n     * @notice Get staking infos of a user\\r\\n     * @param user The user address for which to get staking infos\\r\\n     * @return The staking infos of the user\\r\\n     */\\r\\n    function getUserInfo(address user)\\r\\n        external\\r\\n        view\\r\\n        returns (FeeDiscountStorage.UserInfo memory);\\r\\n}\\r\\n\"},\"@solidstate/contracts/token/ERC1155/base/ERC1155BaseInternal.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.0;\\n\\nimport { AddressUtils } from '../../../utils/AddressUtils.sol';\\nimport { IERC1155Internal } from '../IERC1155Internal.sol';\\nimport { IERC1155Receiver } from '../IERC1155Receiver.sol';\\nimport { ERC1155BaseStorage } from './ERC1155BaseStorage.sol';\\n\\n/**\\n * @title Base ERC1155 internal functions\\n * @dev derived from https://github.com/OpenZeppelin/openzeppelin-contracts/ (MIT license)\\n */\\nabstract contract ERC1155BaseInternal is IERC1155Internal {\\n    using AddressUtils for address;\\n\\n    /**\\n     * @notice query the balance of given token held by given address\\n     * @param account address to query\\n     * @param id token to query\\n     * @return token balance\\n     */\\n    function _balanceOf(address account, uint256 id)\\n        internal\\n        view\\n        virtual\\n        returns (uint256)\\n    {\\n        require(\\n            account != address(0),\\n            'ERC1155: balance query for the zero address'\\n        );\\n        return ERC1155BaseStorage.layout().balances[id][account];\\n    }\\n\\n    /**\\n     * @notice mint given quantity of tokens for given address\\n     * @dev ERC1155Receiver implementation is not checked\\n     * @param account beneficiary of minting\\n     * @param id token ID\\n     * @param amount quantity of tokens to mint\\n     * @param data data payload\\n     */\\n    function _mint(\\n        address account,\\n        uint256 id,\\n        uint256 amount,\\n        bytes memory data\\n    ) internal virtual {\\n        require(account != address(0), 'ERC1155: mint to the zero address');\\n\\n        _beforeTokenTransfer(\\n            msg.sender,\\n            address(0),\\n            account,\\n            _asSingletonArray(id),\\n            _asSingletonArray(amount),\\n            data\\n        );\\n\\n        mapping(address => uint256) storage balances = ERC1155BaseStorage\\n            .layout()\\n            .balances[id];\\n        balances[account] += amount;\\n\\n        emit TransferSingle(msg.sender, address(0), account, id, amount);\\n    }\\n\\n    /**\\n     * @notice mint given quantity of tokens for given address\\n     * @param account beneficiary of minting\\n     * @param id token ID\\n     * @param amount quantity of tokens to mint\\n     * @param data data payload\\n     */\\n    function _safeMint(\\n        address account,\\n        uint256 id,\\n        uint256 amount,\\n        bytes memory data\\n    ) internal virtual {\\n        _mint(account, id, amount, data);\\n\\n        _doSafeTransferAcceptanceCheck(\\n            msg.sender,\\n            address(0),\\n            account,\\n            id,\\n            amount,\\n            data\\n        );\\n    }\\n\\n    /**\\n     * @notice mint batch of tokens for given address\\n     * @dev ERC1155Receiver implementation is not checked\\n     * @param account beneficiary of minting\\n     * @param ids list of token IDs\\n     * @param amounts list of quantities of tokens to mint\\n     * @param data data payload\\n     */\\n    function _mintBatch(\\n        address account,\\n        uint256[] memory ids,\\n        uint256[] memory amounts,\\n        bytes memory data\\n    ) internal virtual {\\n        require(account != address(0), 'ERC1155: mint to the zero address');\\n        require(\\n            ids.length == amounts.length,\\n            'ERC1155: ids and amounts length mismatch'\\n        );\\n\\n        _beforeTokenTransfer(\\n            msg.sender,\\n            address(0),\\n            account,\\n            ids,\\n            amounts,\\n            data\\n        );\\n\\n        mapping(uint256 => mapping(address => uint256))\\n            storage balances = ERC1155BaseStorage.layout().balances;\\n\\n        for (uint256 i; i < ids.length; i++) {\\n            balances[ids[i]][account] += amounts[i];\\n        }\\n\\n        emit TransferBatch(msg.sender, address(0), account, ids, amounts);\\n    }\\n\\n    /**\\n     * @notice mint batch of tokens for given address\\n     * @param account beneficiary of minting\\n     * @param ids list of token IDs\\n     * @param amounts list of quantities of tokens to mint\\n     * @param data data payload\\n     */\\n    function _safeMintBatch(\\n        address account,\\n        uint256[] memory ids,\\n        uint256[] memory amounts,\\n        bytes memory data\\n    ) internal virtual {\\n        _mintBatch(account, ids, amounts, data);\\n\\n        _doSafeBatchTransferAcceptanceCheck(\\n            msg.sender,\\n            address(0),\\n            account,\\n            ids,\\n            amounts,\\n            data\\n        );\\n    }\\n\\n    /**\\n     * @notice burn given quantity of tokens held by given address\\n     * @param account holder of tokens to burn\\n     * @param id token ID\\n     * @param amount quantity of tokens to burn\\n     */\\n    function _burn(\\n        address account,\\n        uint256 id,\\n        uint256 amount\\n    ) internal virtual {\\n        require(account != address(0), 'ERC1155: burn from the zero address');\\n\\n        _beforeTokenTransfer(\\n            msg.sender,\\n            account,\\n            address(0),\\n            _asSingletonArray(id),\\n            _asSingletonArray(amount),\\n            ''\\n        );\\n\\n        mapping(address => uint256) storage balances = ERC1155BaseStorage\\n            .layout()\\n            .balances[id];\\n\\n        unchecked {\\n            require(\\n                balances[account] >= amount,\\n                'ERC1155: burn amount exceeds balances'\\n            );\\n            balances[account] -= amount;\\n        }\\n\\n        emit TransferSingle(msg.sender, account, address(0), id, amount);\\n    }\\n\\n    /**\\n     * @notice burn given batch of tokens held by given address\\n     * @param account holder of tokens to burn\\n     * @param ids token IDs\\n     * @param amounts quantities of tokens to burn\\n     */\\n    function _burnBatch(\\n        address account,\\n        uint256[] memory ids,\\n        uint256[] memory amounts\\n    ) internal virtual {\\n        require(account != address(0), 'ERC1155: burn from the zero address');\\n        require(\\n            ids.length == amounts.length,\\n            'ERC1155: ids and amounts length mismatch'\\n        );\\n\\n        _beforeTokenTransfer(msg.sender, account, address(0), ids, amounts, '');\\n\\n        mapping(uint256 => mapping(address => uint256))\\n            storage balances = ERC1155BaseStorage.layout().balances;\\n\\n        unchecked {\\n            for (uint256 i; i < ids.length; i++) {\\n                uint256 id = ids[i];\\n                require(\\n                    balances[id][account] >= amounts[i],\\n                    'ERC1155: burn amount exceeds balance'\\n                );\\n                balances[id][account] -= amounts[i];\\n            }\\n        }\\n\\n        emit TransferBatch(msg.sender, account, address(0), ids, amounts);\\n    }\\n\\n    /**\\n     * @notice transfer tokens between given addresses\\n     * @dev ERC1155Receiver implementation is not checked\\n     * @param operator executor of transfer\\n     * @param sender sender of tokens\\n     * @param recipient receiver of tokens\\n     * @param id token ID\\n     * @param amount quantity of tokens to transfer\\n     * @param data data payload\\n     */\\n    function _transfer(\\n        address operator,\\n        address sender,\\n        address recipient,\\n        uint256 id,\\n        uint256 amount,\\n        bytes memory data\\n    ) internal virtual {\\n        require(\\n            recipient != address(0),\\n            'ERC1155: transfer to the zero address'\\n        );\\n\\n        _beforeTokenTransfer(\\n            operator,\\n            sender,\\n            recipient,\\n            _asSingletonArray(id),\\n            _asSingletonArray(amount),\\n            data\\n        );\\n\\n        mapping(uint256 => mapping(address => uint256))\\n            storage balances = ERC1155BaseStorage.layout().balances;\\n\\n        unchecked {\\n            uint256 senderBalance = balances[id][sender];\\n            require(\\n                senderBalance >= amount,\\n                'ERC1155: insufficient balances for transfer'\\n            );\\n            balances[id][sender] = senderBalance - amount;\\n        }\\n\\n        balances[id][recipient] += amount;\\n\\n        emit TransferSingle(operator, sender, recipient, id, amount);\\n    }\\n\\n    /**\\n     * @notice transfer tokens between given addresses\\n     * @param operator executor of transfer\\n     * @param sender sender of tokens\\n     * @param recipient receiver of tokens\\n     * @param id token ID\\n     * @param amount quantity of tokens to transfer\\n     * @param data data payload\\n     */\\n    function _safeTransfer(\\n        address operator,\\n        address sender,\\n        address recipient,\\n        uint256 id,\\n        uint256 amount,\\n        bytes memory data\\n    ) internal virtual {\\n        _transfer(operator, sender, recipient, id, amount, data);\\n\\n        _doSafeTransferAcceptanceCheck(\\n            operator,\\n            sender,\\n            recipient,\\n            id,\\n            amount,\\n            data\\n        );\\n    }\\n\\n    /**\\n     * @notice transfer batch of tokens between given addresses\\n     * @dev ERC1155Receiver implementation is not checked\\n     * @param operator executor of transfer\\n     * @param sender sender of tokens\\n     * @param recipient receiver of tokens\\n     * @param ids token IDs\\n     * @param amounts quantities of tokens to transfer\\n     * @param data data payload\\n     */\\n    function _transferBatch(\\n        address operator,\\n        address sender,\\n        address recipient,\\n        uint256[] memory ids,\\n        uint256[] memory amounts,\\n        bytes memory data\\n    ) internal virtual {\\n        require(\\n            recipient != address(0),\\n            'ERC1155: transfer to the zero address'\\n        );\\n        require(\\n            ids.length == amounts.length,\\n            'ERC1155: ids and amounts length mismatch'\\n        );\\n\\n        _beforeTokenTransfer(operator, sender, recipient, ids, amounts, data);\\n\\n        mapping(uint256 => mapping(address => uint256))\\n            storage balances = ERC1155BaseStorage.layout().balances;\\n\\n        for (uint256 i; i < ids.length; i++) {\\n            uint256 token = ids[i];\\n            uint256 amount = amounts[i];\\n\\n            unchecked {\\n                uint256 senderBalance = balances[token][sender];\\n                require(\\n                    senderBalance >= amount,\\n                    'ERC1155: insufficient balances for transfer'\\n                );\\n                balances[token][sender] = senderBalance - amount;\\n            }\\n\\n            balances[token][recipient] += amount;\\n        }\\n\\n        emit TransferBatch(operator, sender, recipient, ids, amounts);\\n    }\\n\\n    /**\\n     * @notice transfer batch of tokens between given addresses\\n     * @param operator executor of transfer\\n     * @param sender sender of tokens\\n     * @param recipient receiver of tokens\\n     * @param ids token IDs\\n     * @param amounts quantities of tokens to transfer\\n     * @param data data payload\\n     */\\n    function _safeTransferBatch(\\n        address operator,\\n        address sender,\\n        address recipient,\\n        uint256[] memory ids,\\n        uint256[] memory amounts,\\n        bytes memory data\\n    ) internal virtual {\\n        _transferBatch(operator, sender, recipient, ids, amounts, data);\\n\\n        _doSafeBatchTransferAcceptanceCheck(\\n            operator,\\n            sender,\\n            recipient,\\n            ids,\\n            amounts,\\n            data\\n        );\\n    }\\n\\n    /**\\n     * @notice wrap given element in array of length 1\\n     * @param element element to wrap\\n     * @return singleton array\\n     */\\n    function _asSingletonArray(uint256 element)\\n        private\\n        pure\\n        returns (uint256[] memory)\\n    {\\n        uint256[] memory array = new uint256[](1);\\n        array[0] = element;\\n        return array;\\n    }\\n\\n    /**\\n     * @notice revert if applicable transfer recipient is not valid ERC1155Receiver\\n     * @param operator executor of transfer\\n     * @param from sender of tokens\\n     * @param to receiver of tokens\\n     * @param id token ID\\n     * @param amount quantity of tokens to transfer\\n     * @param data data payload\\n     */\\n    function _doSafeTransferAcceptanceCheck(\\n        address operator,\\n        address from,\\n        address to,\\n        uint256 id,\\n        uint256 amount,\\n        bytes memory data\\n    ) private {\\n        if (to.isContract()) {\\n            try\\n                IERC1155Receiver(to).onERC1155Received(\\n                    operator,\\n                    from,\\n                    id,\\n                    amount,\\n                    data\\n                )\\n            returns (bytes4 response) {\\n                require(\\n                    response == IERC1155Receiver.onERC1155Received.selector,\\n                    'ERC1155: ERC1155Receiver rejected tokens'\\n                );\\n            } catch Error(string memory reason) {\\n                revert(reason);\\n            } catch {\\n                revert('ERC1155: transfer to non ERC1155Receiver implementer');\\n            }\\n        }\\n    }\\n\\n    /**\\n     * @notice revert if applicable transfer recipient is not valid ERC1155Receiver\\n     * @param operator executor of transfer\\n     * @param from sender of tokens\\n     * @param to receiver of tokens\\n     * @param ids token IDs\\n     * @param amounts quantities of tokens to transfer\\n     * @param data data payload\\n     */\\n    function _doSafeBatchTransferAcceptanceCheck(\\n        address operator,\\n        address from,\\n        address to,\\n        uint256[] memory ids,\\n        uint256[] memory amounts,\\n        bytes memory data\\n    ) private {\\n        if (to.isContract()) {\\n            try\\n                IERC1155Receiver(to).onERC1155BatchReceived(\\n                    operator,\\n                    from,\\n                    ids,\\n                    amounts,\\n                    data\\n                )\\n            returns (bytes4 response) {\\n                require(\\n                    response ==\\n                        IERC1155Receiver.onERC1155BatchReceived.selector,\\n                    'ERC1155: ERC1155Receiver rejected tokens'\\n                );\\n            } catch Error(string memory reason) {\\n                revert(reason);\\n            } catch {\\n                revert('ERC1155: transfer to non ERC1155Receiver implementer');\\n            }\\n        }\\n    }\\n\\n    /**\\n     * @notice ERC1155 hook, called before all transfers including mint and burn\\n     * @dev function should be overridden and new implementation must call super\\n     * @dev called for both single and batch transfers\\n     * @param operator executor of transfer\\n     * @param from sender of tokens\\n     * @param to receiver of tokens\\n     * @param ids token IDs\\n     * @param amounts quantities of tokens to transfer\\n     * @param data data payload\\n     */\\n    function _beforeTokenTransfer(\\n        address operator,\\n        address from,\\n        address to,\\n        uint256[] memory ids,\\n        uint256[] memory amounts,\\n        bytes memory data\\n    ) internal virtual {}\\n}\\n\"},\"@solidstate/contracts/token/ERC20/IERC20Internal.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Partial ERC20 interface needed by internal functions\\n */\\ninterface IERC20Internal {\\n    event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n    event Approval(\\n        address indexed owner,\\n        address indexed spender,\\n        uint256 value\\n    );\\n}\\n\"},\"@chainlink/contracts/src/v0.8/interfaces/AggregatorInterface.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface AggregatorInterface {\\n  function latestAnswer()\\n    external\\n    view\\n    returns (\\n      int256\\n    );\\n  \\n  function latestTimestamp()\\n    external\\n    view\\n    returns (\\n      uint256\\n    );\\n\\n  function latestRound()\\n    external\\n    view\\n    returns (\\n      uint256\\n    );\\n\\n  function getAnswer(\\n    uint256 roundId\\n  )\\n    external\\n    view\\n    returns (\\n      int256\\n    );\\n\\n  function getTimestamp(\\n    uint256 roundId\\n  )\\n    external\\n    view\\n    returns (\\n      uint256\\n    );\\n\\n  event AnswerUpdated(\\n    int256 indexed current,\\n    uint256 indexed roundId,\\n    uint256 updatedAt\\n  );\\n\\n  event NewRound(\\n    uint256 indexed roundId,\\n    address indexed startedBy,\\n    uint256 startedAt\\n  );\\n}\\n\"},\"contracts/pool/PoolExercise.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\n// For further clarification please see https://license.premia.legal\\r\\n\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport {ERC1155BaseStorage} from \\\"@solidstate/contracts/token/ERC1155/base/ERC1155BaseStorage.sol\\\";\\r\\n\\r\\nimport {PoolInternal} from \\\"./PoolInternal.sol\\\";\\r\\nimport {IPoolExercise} from \\\"./IPoolExercise.sol\\\";\\r\\n\\r\\n/**\\r\\n * @title Premia option pool\\r\\n * @dev deployed standalone and referenced by PoolProxy\\r\\n */\\r\\ncontract PoolExercise is IPoolExercise, PoolInternal {\\r\\n    constructor(\\r\\n        address ivolOracle,\\r\\n        address weth,\\r\\n        address premiaMining,\\r\\n        address feeReceiver,\\r\\n        address feeDiscountAddress,\\r\\n        int128 fee64x64\\r\\n    )\\r\\n        PoolInternal(\\r\\n            ivolOracle,\\r\\n            weth,\\r\\n            premiaMining,\\r\\n            feeReceiver,\\r\\n            feeDiscountAddress,\\r\\n            fee64x64\\r\\n        )\\r\\n    {}\\r\\n\\r\\n    /**\\r\\n     * @inheritdoc IPoolExercise\\r\\n     */\\r\\n    function exerciseFrom(\\r\\n        address holder,\\r\\n        uint256 longTokenId,\\r\\n        uint256 contractSize\\r\\n    ) external override {\\r\\n        if (msg.sender != holder) {\\r\\n            require(\\r\\n                ERC1155BaseStorage.layout().operatorApprovals[holder][\\r\\n                    msg.sender\\r\\n                ],\\r\\n                \\\"not approved\\\"\\r\\n            );\\r\\n        }\\r\\n\\r\\n        _exercise(holder, longTokenId, contractSize);\\r\\n    }\\r\\n\\r\\n    /**\\r\\n     * @inheritdoc IPoolExercise\\r\\n     */\\r\\n    function processExpired(uint256 longTokenId, uint256 contractSize)\\r\\n        external\\r\\n        override\\r\\n    {\\r\\n        _exercise(address(0), longTokenId, contractSize);\\r\\n    }\\r\\n}\\r\\n\"},\"contracts/pool/IPoolExercise.sol\":{\"content\":\"// SPDX-License-Identifier: LGPL-3.0-or-later\\r\\n\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\n/**\\r\\n * @notice Pool interface for exercising and processing of expired options\\r\\n */\\r\\ninterface IPoolExercise {\\r\\n    /**\\r\\n     * @notice exercise option on behalf of holder\\r\\n     * @param holder owner of long option tokens to exercise\\r\\n     * @param longTokenId long option token id\\r\\n     * @param contractSize quantity of tokens to exercise\\r\\n     */\\r\\n    function exerciseFrom(\\r\\n        address holder,\\r\\n        uint256 longTokenId,\\r\\n        uint256 contractSize\\r\\n    ) external;\\r\\n\\r\\n    /**\\r\\n     * @notice process expired option, freeing liquidity and distributing profits\\r\\n     * @param longTokenId long option token id\\r\\n     * @param contractSize quantity of tokens to process\\r\\n     */\\r\\n    function processExpired(uint256 longTokenId, uint256 contractSize) external;\\r\\n}\\r\\n\"},\"contracts/pool/PoolStorage.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\n// For further clarification please see https://license.premia.legal\\r\\n\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport {AggregatorInterface} from \\\"@chainlink/contracts/src/v0.8/interfaces/AggregatorInterface.sol\\\";\\r\\nimport {AggregatorV3Interface} from \\\"@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol\\\";\\r\\nimport {EnumerableSet, ERC1155EnumerableStorage} from \\\"@solidstate/contracts/token/ERC1155/enumerable/ERC1155EnumerableStorage.sol\\\";\\r\\n\\r\\nimport {ABDKMath64x64} from \\\"abdk-libraries-solidity/ABDKMath64x64.sol\\\";\\r\\nimport {ABDKMath64x64Token} from \\\"../libraries/ABDKMath64x64Token.sol\\\";\\r\\nimport {OptionMath} from \\\"../libraries/OptionMath.sol\\\";\\r\\n\\r\\nlibrary PoolStorage {\\r\\n    using ABDKMath64x64 for int128;\\r\\n    using PoolStorage for PoolStorage.Layout;\\r\\n\\r\\n    enum TokenType {\\r\\n        UNDERLYING_FREE_LIQ,\\r\\n        BASE_FREE_LIQ,\\r\\n        UNDERLYING_RESERVED_LIQ,\\r\\n        BASE_RESERVED_LIQ,\\r\\n        LONG_CALL,\\r\\n        SHORT_CALL,\\r\\n        LONG_PUT,\\r\\n        SHORT_PUT\\r\\n    }\\r\\n\\r\\n    struct PoolSettings {\\r\\n        address underlying;\\r\\n        address base;\\r\\n        address underlyingOracle;\\r\\n        address baseOracle;\\r\\n    }\\r\\n\\r\\n    struct QuoteArgsInternal {\\r\\n        address feePayer; // address of the fee payer\\r\\n        uint64 maturity; // timestamp of option maturity\\r\\n        int128 strike64x64; // 64x64 fixed point representation of strike price\\r\\n        int128 spot64x64; // 64x64 fixed point representation of spot price\\r\\n        uint256 contractSize; // size of option contract\\r\\n        bool isCall; // true for call, false for put\\r\\n    }\\r\\n\\r\\n    struct QuoteResultInternal {\\r\\n        int128 baseCost64x64; // 64x64 fixed point representation of option cost denominated in underlying currency (without fee)\\r\\n        int128 feeCost64x64; // 64x64 fixed point representation of option fee cost denominated in underlying currency for call, or base currency for put\\r\\n        int128 cLevel64x64; // 64x64 fixed point representation of C-Level of Pool after purchase\\r\\n        int128 slippageCoefficient64x64; // 64x64 fixed point representation of slippage coefficient for given order size\\r\\n    }\\r\\n\\r\\n    struct BatchData {\\r\\n        uint256 eta;\\r\\n        uint256 totalPendingDeposits;\\r\\n    }\\r\\n\\r\\n    bytes32 internal constant STORAGE_SLOT =\\r\\n        keccak256(\\\"premia.contracts.storage.Pool\\\");\\r\\n\\r\\n    uint256 private constant C_DECAY_BUFFER = 12 hours;\\r\\n    uint256 private constant C_DECAY_INTERVAL = 4 hours;\\r\\n\\r\\n    struct Layout {\\r\\n        // ERC20 token addresses\\r\\n        address base;\\r\\n        address underlying;\\r\\n        // AggregatorV3Interface oracle addresses\\r\\n        address baseOracle;\\r\\n        address underlyingOracle;\\r\\n        // token metadata\\r\\n        uint8 underlyingDecimals;\\r\\n        uint8 baseDecimals;\\r\\n        // minimum amounts\\r\\n        uint256 baseMinimum;\\r\\n        uint256 underlyingMinimum;\\r\\n        // deposit caps\\r\\n        uint256 basePoolCap;\\r\\n        uint256 underlyingPoolCap;\\r\\n        // market state\\r\\n        int128 _deprecated_steepness64x64;\\r\\n        int128 cLevelBase64x64;\\r\\n        int128 cLevelUnderlying64x64;\\r\\n        uint256 cLevelBaseUpdatedAt;\\r\\n        uint256 cLevelUnderlyingUpdatedAt;\\r\\n        uint256 updatedAt;\\r\\n        // User -> isCall -> depositedAt\\r\\n        mapping(address => mapping(bool => uint256)) depositedAt;\\r\\n        mapping(address => mapping(bool => uint256)) divestmentTimestamps;\\r\\n        // doubly linked list of free liquidity intervals\\r\\n        // isCall -> User -> User\\r\\n        mapping(bool => mapping(address => address)) liquidityQueueAscending;\\r\\n        mapping(bool => mapping(address => address)) liquidityQueueDescending;\\r\\n        // minimum resolution price bucket => price\\r\\n        mapping(uint256 => int128) bucketPrices64x64;\\r\\n        // sequence id (minimum resolution price bucket / 256) => price update sequence\\r\\n        mapping(uint256 => uint256) priceUpdateSequences;\\r\\n        // isCall -> batch data\\r\\n        mapping(bool => BatchData) nextDeposits;\\r\\n        // user -> batch timestamp -> isCall -> pending amount\\r\\n        mapping(address => mapping(uint256 => mapping(bool => uint256))) pendingDeposits;\\r\\n        EnumerableSet.UintSet tokenIds;\\r\\n        // user -> isCallPool -> total value locked of user (Used for liquidity mining)\\r\\n        mapping(address => mapping(bool => uint256)) userTVL;\\r\\n        // isCallPool -> total value locked\\r\\n        mapping(bool => uint256) totalTVL;\\r\\n        // steepness values\\r\\n        int128 steepnessBase64x64;\\r\\n        int128 steepnessUnderlying64x64;\\r\\n    }\\r\\n\\r\\n    function layout() internal pure returns (Layout storage l) {\\r\\n        bytes32 slot = STORAGE_SLOT;\\r\\n        assembly {\\r\\n            l.slot := slot\\r\\n        }\\r\\n    }\\r\\n\\r\\n    /**\\r\\n     * @notice calculate ERC1155 token id for given option parameters\\r\\n     * @param tokenType TokenType enum\\r\\n     * @param maturity timestamp of option maturity\\r\\n     * @param strike64x64 64x64 fixed point representation of strike price\\r\\n     * @return tokenId token id\\r\\n     */\\r\\n    function formatTokenId(\\r\\n        TokenType tokenType,\\r\\n        uint64 maturity,\\r\\n        int128 strike64x64\\r\\n    ) internal pure returns (uint256 tokenId) {\\r\\n        tokenId =\\r\\n            (uint256(tokenType) << 248) +\\r\\n            (uint256(maturity) << 128) +\\r\\n            uint256(int256(strike64x64));\\r\\n    }\\r\\n\\r\\n    /**\\r\\n     * @notice derive option maturity and strike price from ERC1155 token id\\r\\n     * @param tokenId token id\\r\\n     * @return tokenType TokenType enum\\r\\n     * @return maturity timestamp of option maturity\\r\\n     * @return strike64x64 option strike price\\r\\n     */\\r\\n    function parseTokenId(uint256 tokenId)\\r\\n        internal\\r\\n        pure\\r\\n        returns (\\r\\n            TokenType tokenType,\\r\\n            uint64 maturity,\\r\\n            int128 strike64x64\\r\\n        )\\r\\n    {\\r\\n        assembly {\\r\\n            tokenType := shr(248, tokenId)\\r\\n            maturity := shr(128, tokenId)\\r\\n            strike64x64 := tokenId\\r\\n        }\\r\\n    }\\r\\n\\r\\n    function getTokenDecimals(Layout storage l, bool isCall)\\r\\n        internal\\r\\n        view\\r\\n        returns (uint8 decimals)\\r\\n    {\\r\\n        decimals = isCall ? l.underlyingDecimals : l.baseDecimals;\\r\\n    }\\r\\n\\r\\n    /**\\r\\n     * @notice get the total supply of free liquidity tokens, minus pending deposits\\r\\n     * @param l storage layout struct\\r\\n     * @param isCall whether query is for call or put pool\\r\\n     * @return 64x64 fixed point representation of total free liquidity\\r\\n     */\\r\\n    function totalFreeLiquiditySupply64x64(Layout storage l, bool isCall)\\r\\n        internal\\r\\n        view\\r\\n        returns (int128)\\r\\n    {\\r\\n        uint256 tokenId = formatTokenId(\\r\\n            isCall ? TokenType.UNDERLYING_FREE_LIQ : TokenType.BASE_FREE_LIQ,\\r\\n            0,\\r\\n            0\\r\\n        );\\r\\n\\r\\n        return\\r\\n            ABDKMath64x64Token.fromDecimals(\\r\\n                ERC1155EnumerableStorage.layout().totalSupply[tokenId] -\\r\\n                    l.nextDeposits[isCall].totalPendingDeposits,\\r\\n                l.getTokenDecimals(isCall)\\r\\n            );\\r\\n    }\\r\\n\\r\\n    function getReinvestmentStatus(\\r\\n        Layout storage l,\\r\\n        address account,\\r\\n        bool isCallPool\\r\\n    ) internal view returns (bool) {\\r\\n        uint256 timestamp = l.divestmentTimestamps[account][isCallPool];\\r\\n        return timestamp == 0 || timestamp > block.timestamp;\\r\\n    }\\r\\n\\r\\n    function addUnderwriter(\\r\\n        Layout storage l,\\r\\n        address account,\\r\\n        bool isCallPool\\r\\n    ) internal {\\r\\n        require(account != address(0));\\r\\n\\r\\n        mapping(address => address) storage asc = l.liquidityQueueAscending[\\r\\n            isCallPool\\r\\n        ];\\r\\n        mapping(address => address) storage desc = l.liquidityQueueDescending[\\r\\n            isCallPool\\r\\n        ];\\r\\n\\r\\n        if (_isInQueue(account, asc, desc)) return;\\r\\n\\r\\n        address last = desc[address(0)];\\r\\n\\r\\n        asc[last] = account;\\r\\n        desc[account] = last;\\r\\n        desc[address(0)] = account;\\r\\n    }\\r\\n\\r\\n    function removeUnderwriter(\\r\\n        Layout storage l,\\r\\n        address account,\\r\\n        bool isCallPool\\r\\n    ) internal {\\r\\n        require(account != address(0));\\r\\n\\r\\n        mapping(address => address) storage asc = l.liquidityQueueAscending[\\r\\n            isCallPool\\r\\n        ];\\r\\n        mapping(address => address) storage desc = l.liquidityQueueDescending[\\r\\n            isCallPool\\r\\n        ];\\r\\n\\r\\n        if (!_isInQueue(account, asc, desc)) return;\\r\\n\\r\\n        address prev = desc[account];\\r\\n        address next = asc[account];\\r\\n        asc[prev] = next;\\r\\n        desc[next] = prev;\\r\\n        delete asc[account];\\r\\n        delete desc[account];\\r\\n    }\\r\\n\\r\\n    function isInQueue(\\r\\n        Layout storage l,\\r\\n        address account,\\r\\n        bool isCallPool\\r\\n    ) internal view returns (bool) {\\r\\n        mapping(address => address) storage asc = l.liquidityQueueAscending[\\r\\n            isCallPool\\r\\n        ];\\r\\n        mapping(address => address) storage desc = l.liquidityQueueDescending[\\r\\n            isCallPool\\r\\n        ];\\r\\n\\r\\n        return _isInQueue(account, asc, desc);\\r\\n    }\\r\\n\\r\\n    function _isInQueue(\\r\\n        address account,\\r\\n        mapping(address => address) storage asc,\\r\\n        mapping(address => address) storage desc\\r\\n    ) private view returns (bool) {\\r\\n        return asc[account] != address(0) || desc[address(0)] == account;\\r\\n    }\\r\\n\\r\\n    /**\\r\\n     * @notice get current C-Level, without accounting for pending adjustments\\r\\n     * @param l storage layout struct\\r\\n     * @param isCall whether query is for call or put pool\\r\\n     * @return cLevel64x64 64x64 fixed point representation of C-Level\\r\\n     */\\r\\n    function getRawCLevel64x64(Layout storage l, bool isCall)\\r\\n        internal\\r\\n        view\\r\\n        returns (int128 cLevel64x64)\\r\\n    {\\r\\n        cLevel64x64 = isCall ? l.cLevelUnderlying64x64 : l.cLevelBase64x64;\\r\\n    }\\r\\n\\r\\n    /**\\r\\n     * @notice get current C-Level, accounting for unrealized decay\\r\\n     * @param l storage layout struct\\r\\n     * @param isCall whether query is for call or put pool\\r\\n     * @return cLevel64x64 64x64 fixed point representation of C-Level\\r\\n     */\\r\\n    function getDecayAdjustedCLevel64x64(Layout storage l, bool isCall)\\r\\n        internal\\r\\n        view\\r\\n        returns (int128 cLevel64x64)\\r\\n    {\\r\\n        // get raw C-Level from storage\\r\\n        cLevel64x64 = l.getRawCLevel64x64(isCall);\\r\\n\\r\\n        // account for C-Level decay\\r\\n        cLevel64x64 = l.applyCLevelDecayAdjustment(cLevel64x64, isCall);\\r\\n    }\\r\\n\\r\\n    /**\\r\\n     * @notice calculate updated C-Level, accounting for unrealized decay\\r\\n     * @param l storage layout struct\\r\\n     * @param oldCLevel64x64 64x64 fixed point representation pool C-Level before accounting for decay\\r\\n     * @param isCall whether query is for call or put pool\\r\\n     * @return cLevel64x64 64x64 fixed point representation of C-Level of Pool after accounting for decay\\r\\n     */\\r\\n    function applyCLevelDecayAdjustment(\\r\\n        Layout storage l,\\r\\n        int128 oldCLevel64x64,\\r\\n        bool isCall\\r\\n    ) internal view returns (int128 cLevel64x64) {\\r\\n        uint256 timeElapsed = block.timestamp -\\r\\n            (isCall ? l.cLevelUnderlyingUpdatedAt : l.cLevelBaseUpdatedAt);\\r\\n\\r\\n        // do not apply C decay if less than 24 hours have elapsed\\r\\n\\r\\n        if (timeElapsed > C_DECAY_BUFFER) {\\r\\n            timeElapsed -= C_DECAY_BUFFER;\\r\\n        } else {\\r\\n            return oldCLevel64x64;\\r\\n        }\\r\\n\\r\\n        int128 timeIntervalsElapsed64x64 = ABDKMath64x64.divu(\\r\\n            timeElapsed,\\r\\n            C_DECAY_INTERVAL\\r\\n        );\\r\\n\\r\\n        uint256 tokenId = formatTokenId(\\r\\n            isCall ? TokenType.UNDERLYING_FREE_LIQ : TokenType.BASE_FREE_LIQ,\\r\\n            0,\\r\\n            0\\r\\n        );\\r\\n\\r\\n        uint256 tvl = l.totalTVL[isCall];\\r\\n\\r\\n        int128 utilization = ABDKMath64x64.divu(\\r\\n            tvl -\\r\\n                (ERC1155EnumerableStorage.layout().totalSupply[tokenId] -\\r\\n                    l.nextDeposits[isCall].totalPendingDeposits),\\r\\n            tvl\\r\\n        );\\r\\n\\r\\n        return\\r\\n            OptionMath.calculateCLevelDecay(\\r\\n                OptionMath.CalculateCLevelDecayArgs(\\r\\n                    timeIntervalsElapsed64x64,\\r\\n                    oldCLevel64x64,\\r\\n                    utilization,\\r\\n                    0xb333333333333333, // 0.7\\r\\n                    0xe666666666666666, // 0.9\\r\\n                    0x10000000000000000, // 1.0\\r\\n                    0x10000000000000000, // 1.0\\r\\n                    0xe666666666666666, // 0.9\\r\\n                    0x56fc2a2c515da32ea // 2e\\r\\n                )\\r\\n            );\\r\\n    }\\r\\n\\r\\n    /**\\r\\n     * @notice calculate updated C-Level, accounting for pending deposits\\r\\n     * @param l storage layout struct\\r\\n     * @param oldCLevel64x64 64x64 fixed point representation pool C-Level before accounting for liquidity change\\r\\n     * @param oldLiquidity64x64 64x64 fixed point representation of previous liquidity\\r\\n     * @param isCall whether to update C-Level for call or put pool\\r\\n     * @return cLevel64x64 64x64 fixed point representation of C-Level\\r\\n     * @return liquidity64x64 64x64 fixed point representation of new liquidity amount\\r\\n     */\\r\\n    function applyCLevelPendingDepositAdjustment(\\r\\n        Layout storage l,\\r\\n        int128 oldCLevel64x64,\\r\\n        int128 oldLiquidity64x64,\\r\\n        bool isCall\\r\\n    ) internal view returns (int128 cLevel64x64, int128 liquidity64x64) {\\r\\n        PoolStorage.BatchData storage batchData = l.nextDeposits[isCall];\\r\\n        int128 pendingDeposits64x64;\\r\\n\\r\\n        if (\\r\\n            batchData.totalPendingDeposits > 0 &&\\r\\n            batchData.eta != 0 &&\\r\\n            block.timestamp >= batchData.eta\\r\\n        ) {\\r\\n            pendingDeposits64x64 = ABDKMath64x64Token.fromDecimals(\\r\\n                batchData.totalPendingDeposits,\\r\\n                l.getTokenDecimals(isCall)\\r\\n            );\\r\\n\\r\\n            liquidity64x64 = oldLiquidity64x64.add(pendingDeposits64x64);\\r\\n\\r\\n            cLevel64x64 = l.applyCLevelLiquidityChangeAdjustment(\\r\\n                oldCLevel64x64,\\r\\n                oldLiquidity64x64,\\r\\n                liquidity64x64,\\r\\n                isCall\\r\\n            );\\r\\n        } else {\\r\\n            cLevel64x64 = oldCLevel64x64;\\r\\n            liquidity64x64 = oldLiquidity64x64;\\r\\n        }\\r\\n    }\\r\\n\\r\\n    /**\\r\\n     * @notice calculate updated C-Level, accounting for change in liquidity\\r\\n     * @param l storage layout struct\\r\\n     * @param oldCLevel64x64 64x64 fixed point representation pool C-Level before accounting for liquidity change\\r\\n     * @param oldLiquidity64x64 64x64 fixed point representation of previous liquidity\\r\\n     * @param newLiquidity64x64 64x64 fixed point representation of current liquidity\\r\\n     * @param isCallPool whether to update C-Level for call or put pool\\r\\n     * @return cLevel64x64 64x64 fixed point representation of C-Level\\r\\n     */\\r\\n    function applyCLevelLiquidityChangeAdjustment(\\r\\n        Layout storage l,\\r\\n        int128 oldCLevel64x64,\\r\\n        int128 oldLiquidity64x64,\\r\\n        int128 newLiquidity64x64,\\r\\n        bool isCallPool\\r\\n    ) internal view returns (int128 cLevel64x64) {\\r\\n        int128 steepness64x64 = isCallPool\\r\\n            ? l.steepnessUnderlying64x64\\r\\n            : l.steepnessBase64x64;\\r\\n\\r\\n        // fallback to deprecated storage value if side-specific value is not set\\r\\n        if (steepness64x64 == 0) steepness64x64 = l._deprecated_steepness64x64;\\r\\n\\r\\n        cLevel64x64 = OptionMath.calculateCLevel(\\r\\n            oldCLevel64x64,\\r\\n            oldLiquidity64x64,\\r\\n            newLiquidity64x64,\\r\\n            steepness64x64\\r\\n        );\\r\\n\\r\\n        if (cLevel64x64 < 0xb333333333333333) {\\r\\n            cLevel64x64 = int128(0xb333333333333333); // 64x64 fixed point representation of 0.7\\r\\n        }\\r\\n    }\\r\\n\\r\\n    /**\\r\\n     * @notice set C-Level to arbitrary pre-calculated value\\r\\n     * @param cLevel64x64 new C-Level of pool\\r\\n     * @param isCallPool whether to update C-Level for call or put pool\\r\\n     */\\r\\n    function setCLevel(\\r\\n        Layout storage l,\\r\\n        int128 cLevel64x64,\\r\\n        bool isCallPool\\r\\n    ) internal {\\r\\n        if (isCallPool) {\\r\\n            l.cLevelUnderlying64x64 = cLevel64x64;\\r\\n            l.cLevelUnderlyingUpdatedAt = block.timestamp;\\r\\n        } else {\\r\\n            l.cLevelBase64x64 = cLevel64x64;\\r\\n            l.cLevelBaseUpdatedAt = block.timestamp;\\r\\n        }\\r\\n    }\\r\\n\\r\\n    function setOracles(\\r\\n        Layout storage l,\\r\\n        address baseOracle,\\r\\n        address underlyingOracle\\r\\n    ) internal {\\r\\n        require(\\r\\n            AggregatorV3Interface(baseOracle).decimals() ==\\r\\n                AggregatorV3Interface(underlyingOracle).decimals(),\\r\\n            \\\"Pool: oracle decimals must match\\\"\\r\\n        );\\r\\n\\r\\n        l.baseOracle = baseOracle;\\r\\n        l.underlyingOracle = underlyingOracle;\\r\\n    }\\r\\n\\r\\n    function fetchPriceUpdate(Layout storage l)\\r\\n        internal\\r\\n        view\\r\\n        returns (int128 price64x64)\\r\\n    {\\r\\n        int256 priceUnderlying = AggregatorInterface(l.underlyingOracle)\\r\\n            .latestAnswer();\\r\\n        int256 priceBase = AggregatorInterface(l.baseOracle).latestAnswer();\\r\\n\\r\\n        return ABDKMath64x64.divi(priceUnderlying, priceBase);\\r\\n    }\\r\\n\\r\\n    /**\\r\\n     * @notice set price update for hourly bucket corresponding to given timestamp\\r\\n     * @param l storage layout struct\\r\\n     * @param timestamp timestamp to update\\r\\n     * @param price64x64 64x64 fixed point representation of price\\r\\n     */\\r\\n    function setPriceUpdate(\\r\\n        Layout storage l,\\r\\n        uint256 timestamp,\\r\\n        int128 price64x64\\r\\n    ) internal {\\r\\n        uint256 bucket = timestamp / (1 hours);\\r\\n        l.bucketPrices64x64[bucket] = price64x64;\\r\\n        l.priceUpdateSequences[bucket >> 8] += 1 << (255 - (bucket & 255));\\r\\n    }\\r\\n\\r\\n    /**\\r\\n     * @notice get price update for hourly bucket corresponding to given timestamp\\r\\n     * @param l storage layout struct\\r\\n     * @param timestamp timestamp to query\\r\\n     * @return 64x64 fixed point representation of price\\r\\n     */\\r\\n    function getPriceUpdate(Layout storage l, uint256 timestamp)\\r\\n        internal\\r\\n        view\\r\\n        returns (int128)\\r\\n    {\\r\\n        return l.bucketPrices64x64[timestamp / (1 hours)];\\r\\n    }\\r\\n\\r\\n    /**\\r\\n     * @notice get first price update available following given timestamp\\r\\n     * @param l storage layout struct\\r\\n     * @param timestamp timestamp to query\\r\\n     * @return 64x64 fixed point representation of price\\r\\n     */\\r\\n    function getPriceUpdateAfter(Layout storage l, uint256 timestamp)\\r\\n        internal\\r\\n        view\\r\\n        returns (int128)\\r\\n    {\\r\\n        // price updates are grouped into hourly buckets\\r\\n        uint256 bucket = timestamp / (1 hours);\\r\\n        // divide by 256 to get the index of the relevant price update sequence\\r\\n        uint256 sequenceId = bucket >> 8;\\r\\n\\r\\n        // get position within sequence relevant to current price update\\r\\n\\r\\n        uint256 offset = bucket & 255;\\r\\n        // shift to skip buckets from earlier in sequence\\r\\n        uint256 sequence = (l.priceUpdateSequences[sequenceId] << offset) >>\\r\\n            offset;\\r\\n\\r\\n        // iterate through future sequences until a price update is found\\r\\n        // sequence corresponding to current timestamp used as upper bound\\r\\n\\r\\n        uint256 currentPriceUpdateSequenceId = block.timestamp / (256 hours);\\r\\n\\r\\n        while (sequence == 0 && sequenceId <= currentPriceUpdateSequenceId) {\\r\\n            sequence = l.priceUpdateSequences[++sequenceId];\\r\\n        }\\r\\n\\r\\n        // if no price update is found (sequence == 0) function will return 0\\r\\n        // this should never occur, as each relevant external function triggers a price update\\r\\n\\r\\n        // the most significant bit of the sequence corresponds to the offset of the relevant bucket\\r\\n\\r\\n        uint256 msb;\\r\\n\\r\\n        for (uint256 i = 128; i > 0; i >>= 1) {\\r\\n            if (sequence >> i > 0) {\\r\\n                msb += i;\\r\\n                sequence >>= i;\\r\\n            }\\r\\n        }\\r\\n\\r\\n        return l.bucketPrices64x64[((sequenceId + 1) << 8) - msb - 1];\\r\\n    }\\r\\n\\r\\n    function fromBaseToUnderlyingDecimals(Layout storage l, uint256 value)\\r\\n        internal\\r\\n        view\\r\\n        returns (uint256)\\r\\n    {\\r\\n        int128 valueFixed64x64 = ABDKMath64x64Token.fromDecimals(\\r\\n            value,\\r\\n            l.baseDecimals\\r\\n        );\\r\\n        return\\r\\n            ABDKMath64x64Token.toDecimals(\\r\\n                valueFixed64x64,\\r\\n                l.underlyingDecimals\\r\\n            );\\r\\n    }\\r\\n\\r\\n    function fromUnderlyingToBaseDecimals(Layout storage l, uint256 value)\\r\\n        internal\\r\\n        view\\r\\n        returns (uint256)\\r\\n    {\\r\\n        int128 valueFixed64x64 = ABDKMath64x64Token.fromDecimals(\\r\\n            value,\\r\\n            l.underlyingDecimals\\r\\n        );\\r\\n        return ABDKMath64x64Token.toDecimals(valueFixed64x64, l.baseDecimals);\\r\\n    }\\r\\n}\\r\\n\"},\"@solidstate/contracts/utils/AddressUtils.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.0;\\n\\nlibrary AddressUtils {\\n    function toString(address account) internal pure returns (string memory) {\\n        bytes32 value = bytes32(uint256(uint160(account)));\\n        bytes memory alphabet = '0123456789abcdef';\\n        bytes memory chars = new bytes(42);\\n\\n        chars[0] = '0';\\n        chars[1] = 'x';\\n\\n        for (uint256 i = 0; i < 20; i++) {\\n            chars[2 + i * 2] = alphabet[uint8(value[i + 12] >> 4)];\\n            chars[3 + i * 2] = alphabet[uint8(value[i + 12] & 0x0f)];\\n        }\\n\\n        return string(chars);\\n    }\\n\\n    function isContract(address account) internal view returns (bool) {\\n        uint256 size;\\n        assembly {\\n            size := extcodesize(account)\\n        }\\n        return size > 0;\\n    }\\n\\n    function sendValue(address payable account, uint256 amount) internal {\\n        (bool success, ) = account.call{ value: amount }('');\\n        require(success, 'AddressUtils: failed to send value');\\n    }\\n\\n    function functionCall(address target, bytes memory data)\\n        internal\\n        returns (bytes memory)\\n    {\\n        return\\n            functionCall(target, data, 'AddressUtils: failed low-level call');\\n    }\\n\\n    function functionCall(\\n        address target,\\n        bytes memory data,\\n        string memory error\\n    ) internal returns (bytes memory) {\\n        return _functionCallWithValue(target, data, 0, error);\\n    }\\n\\n    function functionCallWithValue(\\n        address target,\\n        bytes memory data,\\n        uint256 value\\n    ) internal returns (bytes memory) {\\n        return\\n            functionCallWithValue(\\n                target,\\n                data,\\n                value,\\n                'AddressUtils: failed low-level call with value'\\n            );\\n    }\\n\\n    function functionCallWithValue(\\n        address target,\\n        bytes memory data,\\n        uint256 value,\\n        string memory error\\n    ) internal returns (bytes memory) {\\n        require(\\n            address(this).balance >= value,\\n            'AddressUtils: insufficient balance for call'\\n        );\\n        return _functionCallWithValue(target, data, value, error);\\n    }\\n\\n    function _functionCallWithValue(\\n        address target,\\n        bytes memory data,\\n        uint256 value,\\n        string memory error\\n    ) private returns (bytes memory) {\\n        require(\\n            isContract(target),\\n            'AddressUtils: function call to non-contract'\\n        );\\n\\n        (bool success, bytes memory returnData) = target.call{ value: value }(\\n            data\\n        );\\n\\n        if (success) {\\n            return returnData;\\n        } else if (returnData.length > 0) {\\n            assembly {\\n                let returnData_size := mload(returnData)\\n                revert(add(32, returnData), returnData_size)\\n            }\\n        } else {\\n            revert(error);\\n        }\\n    }\\n}\\n\"},\"@solidstate/contracts/token/ERC1155/enumerable/ERC1155Enumerable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.0;\\n\\nimport { EnumerableSet } from '../../../utils/EnumerableSet.sol';\\nimport { ERC1155Base, ERC1155BaseInternal } from '../base/ERC1155Base.sol';\\nimport { IERC1155Enumerable } from './IERC1155Enumerable.sol';\\nimport { ERC1155EnumerableInternal, ERC1155EnumerableStorage } from './ERC1155EnumerableInternal.sol';\\n\\n/**\\n * @title ERC1155 implementation including enumerable and aggregate functions\\n */\\nabstract contract ERC1155Enumerable is\\n    IERC1155Enumerable,\\n    ERC1155Base,\\n    ERC1155EnumerableInternal\\n{\\n    using EnumerableSet for EnumerableSet.AddressSet;\\n    using EnumerableSet for EnumerableSet.UintSet;\\n\\n    /**\\n     * @inheritdoc IERC1155Enumerable\\n     */\\n    function totalSupply(uint256 id)\\n        public\\n        view\\n        virtual\\n        override\\n        returns (uint256)\\n    {\\n        return ERC1155EnumerableStorage.layout().totalSupply[id];\\n    }\\n\\n    /**\\n     * @inheritdoc IERC1155Enumerable\\n     */\\n    function totalHolders(uint256 id)\\n        public\\n        view\\n        virtual\\n        override\\n        returns (uint256)\\n    {\\n        return ERC1155EnumerableStorage.layout().accountsByToken[id].length();\\n    }\\n\\n    /**\\n     * @inheritdoc IERC1155Enumerable\\n     */\\n    function accountsByToken(uint256 id)\\n        public\\n        view\\n        virtual\\n        override\\n        returns (address[] memory)\\n    {\\n        EnumerableSet.AddressSet storage accounts = ERC1155EnumerableStorage\\n            .layout()\\n            .accountsByToken[id];\\n\\n        address[] memory addresses = new address[](accounts.length());\\n\\n        for (uint256 i; i < accounts.length(); i++) {\\n            addresses[i] = accounts.at(i);\\n        }\\n\\n        return addresses;\\n    }\\n\\n    /**\\n     * @inheritdoc IERC1155Enumerable\\n     */\\n    function tokensByAccount(address account)\\n        public\\n        view\\n        virtual\\n        override\\n        returns (uint256[] memory)\\n    {\\n        EnumerableSet.UintSet storage tokens = ERC1155EnumerableStorage\\n            .layout()\\n            .tokensByAccount[account];\\n\\n        uint256[] memory ids = new uint256[](tokens.length());\\n\\n        for (uint256 i; i < tokens.length(); i++) {\\n            ids[i] = tokens.at(i);\\n        }\\n\\n        return ids;\\n    }\\n\\n    /**\\n     * @notice ERC1155 hook: update aggregate values\\n     * @inheritdoc ERC1155EnumerableInternal\\n     */\\n    function _beforeTokenTransfer(\\n        address operator,\\n        address from,\\n        address to,\\n        uint256[] memory ids,\\n        uint256[] memory amounts,\\n        bytes memory data\\n    )\\n        internal\\n        virtual\\n        override(ERC1155BaseInternal, ERC1155EnumerableInternal)\\n    {\\n        super._beforeTokenTransfer(operator, from, to, ids, amounts, data);\\n    }\\n}\\n\"},\"@solidstate/contracts/token/ERC1155/IERC1155Receiver.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.0;\\n\\nimport { IERC165 } from '../../introspection/IERC165.sol';\\n\\n/**\\n * @title ERC1155 transfer receiver interface\\n */\\ninterface IERC1155Receiver is IERC165 {\\n    /**\\n     * @notice validate receipt of ERC1155 transfer\\n     * @param operator executor of transfer\\n     * @param from sender of tokens\\n     * @param id token ID received\\n     * @param value quantity of tokens received\\n     * @param data data payload\\n     * @return function's own selector if transfer is accepted\\n     */\\n    function onERC1155Received(\\n        address operator,\\n        address from,\\n        uint256 id,\\n        uint256 value,\\n        bytes calldata data\\n    ) external returns (bytes4);\\n\\n    /**\\n     * @notice validate receipt of ERC1155 batch transfer\\n     * @param operator executor of transfer\\n     * @param from sender of tokens\\n     * @param ids token IDs received\\n     * @param values quantities of tokens received\\n     * @param data data payload\\n     * @return function's own selector if transfer is accepted\\n     */\\n    function onERC1155BatchReceived(\\n        address operator,\\n        address from,\\n        uint256[] calldata ids,\\n        uint256[] calldata values,\\n        bytes calldata data\\n    ) external returns (bytes4);\\n}\\n\"},\"contracts/pool/IPoolEvents.sol\":{\"content\":\"// SPDX-License-Identifier: LGPL-3.0-or-later\\r\\n\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\ninterface IPoolEvents {\\r\\n    event Purchase(\\r\\n        address indexed user,\\r\\n        uint256 longTokenId,\\r\\n        uint256 contractSize,\\r\\n        uint256 baseCost,\\r\\n        uint256 feeCost,\\r\\n        int128 spot64x64\\r\\n    );\\r\\n\\r\\n    event Exercise(\\r\\n        address indexed user,\\r\\n        uint256 longTokenId,\\r\\n        uint256 contractSize,\\r\\n        uint256 exerciseValue,\\r\\n        uint256 fee\\r\\n    );\\r\\n\\r\\n    event Underwrite(\\r\\n        address indexed underwriter,\\r\\n        address indexed longReceiver,\\r\\n        uint256 shortTokenId,\\r\\n        uint256 intervalContractSize,\\r\\n        uint256 intervalPremium,\\r\\n        bool isManualUnderwrite\\r\\n    );\\r\\n\\r\\n    event AssignExercise(\\r\\n        address indexed underwriter,\\r\\n        uint256 shortTokenId,\\r\\n        uint256 freedAmount,\\r\\n        uint256 intervalContractSize,\\r\\n        uint256 fee\\r\\n    );\\r\\n\\r\\n    event Deposit(address indexed user, bool isCallPool, uint256 amount);\\r\\n\\r\\n    event Withdrawal(\\r\\n        address indexed user,\\r\\n        bool isCallPool,\\r\\n        uint256 depositedAt,\\r\\n        uint256 amount\\r\\n    );\\r\\n\\r\\n    event FeeWithdrawal(bool indexed isCallPool, uint256 amount);\\r\\n\\r\\n    event Annihilate(uint256 shortTokenId, uint256 amount);\\r\\n\\r\\n    event UpdateCLevel(\\r\\n        bool indexed isCall,\\r\\n        int128 cLevel64x64,\\r\\n        int128 oldLiquidity64x64,\\r\\n        int128 newLiquidity64x64\\r\\n    );\\r\\n\\r\\n    event UpdateSteepness(int128 steepness64x64, bool isCallPool);\\r\\n}\\r\\n\"},\"contracts/oracle/VolatilitySurfaceOracleStorage.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\n// For further clarification please see https://license.premia.legal\\r\\n\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport {EnumerableSet} from \\\"@solidstate/contracts/utils/EnumerableSet.sol\\\";\\r\\n\\r\\nlibrary VolatilitySurfaceOracleStorage {\\r\\n    bytes32 internal constant STORAGE_SLOT =\\r\\n        keccak256(\\\"premia.contracts.storage.VolatilitySurfaceOracle\\\");\\r\\n\\r\\n    uint256 internal constant COEFF_BITS = 51;\\r\\n    uint256 internal constant COEFF_BITS_MINUS_ONE = 50;\\r\\n    uint256 internal constant COEFF_AMOUNT = 5;\\r\\n    // START_BIT = COEFF_BITS * (COEFF_AMOUNT - 1)\\r\\n    uint256 internal constant START_BIT = 204;\\r\\n\\r\\n    struct Update {\\r\\n        uint256 updatedAt;\\r\\n        bytes32 callCoefficients;\\r\\n        bytes32 putCoefficients;\\r\\n    }\\r\\n\\r\\n    struct Layout {\\r\\n        // Base token -> Underlying token -> Update\\r\\n        mapping(address => mapping(address => Update)) volatilitySurfaces;\\r\\n        // Relayer addresses which can be trusted to provide accurate option trades\\r\\n        EnumerableSet.AddressSet whitelistedRelayers;\\r\\n    }\\r\\n\\r\\n    function layout() internal pure returns (Layout storage l) {\\r\\n        bytes32 slot = STORAGE_SLOT;\\r\\n        assembly {\\r\\n            l.slot := slot\\r\\n        }\\r\\n    }\\r\\n\\r\\n    function getCoefficients(\\r\\n        Layout storage l,\\r\\n        address baseToken,\\r\\n        address underlyingToken,\\r\\n        bool isCall\\r\\n    ) internal view returns (bytes32) {\\r\\n        Update storage u = l.volatilitySurfaces[baseToken][underlyingToken];\\r\\n        return isCall ? u.callCoefficients : u.putCoefficients;\\r\\n    }\\r\\n\\r\\n    function parseVolatilitySurfaceCoefficients(bytes32 input)\\r\\n        internal\\r\\n        pure\\r\\n        returns (int256[] memory coefficients)\\r\\n    {\\r\\n        coefficients = new int256[](COEFF_AMOUNT);\\r\\n\\r\\n        // Value to add to negative numbers to cast them to int256\\r\\n        int256 toAdd = (int256(-1) >> COEFF_BITS) << COEFF_BITS;\\r\\n\\r\\n        assembly {\\r\\n            let i := 0\\r\\n            // Value equal to -1\\r\\n            let mid := shl(COEFF_BITS_MINUS_ONE, 1)\\r\\n\\r\\n            for {\\r\\n\\r\\n            } lt(i, COEFF_AMOUNT) {\\r\\n\\r\\n            } {\\r\\n                let offset := sub(START_BIT, mul(COEFF_BITS, i))\\r\\n                let coeff := shr(\\r\\n                    offset,\\r\\n                    sub(\\r\\n                        input,\\r\\n                        shl(\\r\\n                            add(offset, COEFF_BITS),\\r\\n                            shr(add(offset, COEFF_BITS), input)\\r\\n                        )\\r\\n                    )\\r\\n                )\\r\\n\\r\\n                // Check if value is a negative number and needs casting\\r\\n                if or(eq(coeff, mid), gt(coeff, mid)) {\\r\\n                    coeff := add(coeff, toAdd)\\r\\n                }\\r\\n\\r\\n                // Store result in the coefficients array\\r\\n                mstore(add(coefficients, add(0x20, mul(0x20, i))), coeff)\\r\\n\\r\\n                i := add(i, 1)\\r\\n            }\\r\\n        }\\r\\n    }\\r\\n\\r\\n    function formatVolatilitySurfaceCoefficients(int256[5] memory coefficients)\\r\\n        internal\\r\\n        pure\\r\\n        returns (bytes32 result)\\r\\n    {\\r\\n        for (uint256 i = 0; i < COEFF_AMOUNT; i++) {\\r\\n            int256 max = int256(1 << COEFF_BITS_MINUS_ONE);\\r\\n            require(\\r\\n                coefficients[i] < max && coefficients[i] > -max,\\r\\n                \\\"Out of bounds\\\"\\r\\n            );\\r\\n        }\\r\\n\\r\\n        assembly {\\r\\n            let i := 0\\r\\n\\r\\n            for {\\r\\n\\r\\n            } lt(i, COEFF_AMOUNT) {\\r\\n\\r\\n            } {\\r\\n                let offset := sub(START_BIT, mul(COEFF_BITS, i))\\r\\n                let coeff := mload(add(coefficients, mul(0x20, i)))\\r\\n\\r\\n                result := add(\\r\\n                    result,\\r\\n                    shl(\\r\\n                        offset,\\r\\n                        sub(coeff, shl(COEFF_BITS, shr(COEFF_BITS, coeff)))\\r\\n                    )\\r\\n                )\\r\\n\\r\\n                i := add(i, 1)\\r\\n            }\\r\\n        }\\r\\n    }\\r\\n}\\r\\n\"},\"@solidstate/contracts/token/ERC1155/enumerable/IERC1155Enumerable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title ERC1155 enumerable and aggregate function interface\\n */\\ninterface IERC1155Enumerable {\\n    /**\\n     * @notice query total minted supply of given token\\n     * @param id token id to query\\n     * @return token supply\\n     */\\n    function totalSupply(uint256 id) external view returns (uint256);\\n\\n    /**\\n     * @notice query total number of holders for given token\\n     * @param id token id to query\\n     * @return quantity of holders\\n     */\\n    function totalHolders(uint256 id) external view returns (uint256);\\n\\n    /**\\n     * @notice query holders of given token\\n     * @param id token id to query\\n     * @return list of holder addresses\\n     */\\n    function accountsByToken(uint256 id)\\n        external\\n        view\\n        returns (address[] memory);\\n\\n    /**\\n     * @notice query tokens held by given address\\n     * @param account address to query\\n     * @return list of token ids\\n     */\\n    function tokensByAccount(address account)\\n        external\\n        view\\n        returns (uint256[] memory);\\n}\\n\"},\"@solidstate/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.0;\\n\\nimport { IERC20Internal } from './IERC20Internal.sol';\\n\\n/**\\n * @title ERC20 interface\\n * @dev see https://github.com/ethereum/EIPs/issues/20\\n */\\ninterface IERC20 is IERC20Internal {\\n    /**\\n     * @notice query the total minted token supply\\n     * @return token supply\\n     */\\n    function totalSupply() external view returns (uint256);\\n\\n    /**\\n     * @notice query the token balance of given account\\n     * @param account address to query\\n     * @return token balance\\n     */\\n    function balanceOf(address account) external view returns (uint256);\\n\\n    /**\\n     * @notice query the allowance granted from given holder to given spender\\n     * @param holder approver of allowance\\n     * @param spender recipient of allowance\\n     * @return token allowance\\n     */\\n    function allowance(address holder, address spender)\\n        external\\n        view\\n        returns (uint256);\\n\\n    /**\\n     * @notice grant approval to spender to spend tokens\\n     * @dev prefer ERC20Extended functions to avoid transaction-ordering vulnerability (see https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729)\\n     * @param spender recipient of allowance\\n     * @param amount quantity of tokens approved for spending\\n     * @return success status (always true; otherwise function should revert)\\n     */\\n    function approve(address spender, uint256 amount) external returns (bool);\\n\\n    /**\\n     * @notice transfer tokens to given recipient\\n     * @param recipient beneficiary of token transfer\\n     * @param amount quantity of tokens to transfer\\n     * @return success status (always true; otherwise function should revert)\\n     */\\n    function transfer(address recipient, uint256 amount)\\n        external\\n        returns (bool);\\n\\n    /**\\n     * @notice transfer tokens to given recipient on behalf of given holder\\n     * @param holder holder of tokens prior to transfer\\n     * @param recipient beneficiary of token transfer\\n     * @param amount quantity of tokens to transfer\\n     * @return success status (always true; otherwise function should revert)\\n     */\\n    function transferFrom(\\n        address holder,\\n        address recipient,\\n        uint256 amount\\n    ) external returns (bool);\\n}\\n\"},\"contracts/mining/IPremiaMining.sol\":{\"content\":\"// SPDX-License-Identifier: LGPL-3.0-or-later\\r\\n\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport {PremiaMiningStorage} from \\\"./PremiaMiningStorage.sol\\\";\\r\\n\\r\\ninterface IPremiaMining {\\r\\n    function addPremiaRewards(uint256 _amount) external;\\r\\n\\r\\n    function premiaRewardsAvailable() external view returns (uint256);\\r\\n\\r\\n    function getTotalAllocationPoints() external view returns (uint256);\\r\\n\\r\\n    function getPoolInfo(address pool, bool isCallPool)\\r\\n        external\\r\\n        view\\r\\n        returns (PremiaMiningStorage.PoolInfo memory);\\r\\n\\r\\n    function getPremiaPerYear() external view returns (uint256);\\r\\n\\r\\n    function addPool(address _pool, uint256 _allocPoints) external;\\r\\n\\r\\n    function setPoolAllocPoints(\\r\\n        address[] memory _pools,\\r\\n        uint256[] memory _allocPoints\\r\\n    ) external;\\r\\n\\r\\n    function pendingPremia(\\r\\n        address _pool,\\r\\n        bool _isCallPool,\\r\\n        address _user\\r\\n    ) external view returns (uint256);\\r\\n\\r\\n    function updatePool(\\r\\n        address _pool,\\r\\n        bool _isCallPool,\\r\\n        uint256 _totalTVL\\r\\n    ) external;\\r\\n\\r\\n    function allocatePending(\\r\\n        address _user,\\r\\n        address _pool,\\r\\n        bool _isCallPool,\\r\\n        uint256 _userTVLOld,\\r\\n        uint256 _userTVLNew,\\r\\n        uint256 _totalTVL\\r\\n    ) external;\\r\\n\\r\\n    function claim(\\r\\n        address _user,\\r\\n        address _pool,\\r\\n        bool _isCallPool,\\r\\n        uint256 _userTVLOld,\\r\\n        uint256 _userTVLNew,\\r\\n        uint256 _totalTVL\\r\\n    ) external;\\r\\n}\\r\\n\"},\"@solidstate/contracts/token/ERC1155/enumerable/ERC1155EnumerableStorage.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.0;\\n\\nimport { EnumerableSet } from '../../../utils/EnumerableSet.sol';\\n\\nlibrary ERC1155EnumerableStorage {\\n    struct Layout {\\n        mapping(uint256 => uint256) totalSupply;\\n        mapping(uint256 => EnumerableSet.AddressSet) accountsByToken;\\n        mapping(address => EnumerableSet.UintSet) tokensByAccount;\\n    }\\n\\n    bytes32 internal constant STORAGE_SLOT =\\n        keccak256('solidstate.contracts.storage.ERC1155Enumerable');\\n\\n    function layout() internal pure returns (Layout storage l) {\\n        bytes32 slot = STORAGE_SLOT;\\n        assembly {\\n            l.slot := slot\\n        }\\n    }\\n}\\n\"},\"@solidstate/contracts/token/ERC1155/enumerable/ERC1155EnumerableInternal.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.0;\\n\\nimport { EnumerableSet } from '../../../utils/EnumerableSet.sol';\\nimport { ERC1155BaseInternal, ERC1155BaseStorage } from '../base/ERC1155BaseInternal.sol';\\nimport { ERC1155EnumerableStorage } from './ERC1155EnumerableStorage.sol';\\n\\n/**\\n * @title ERC1155Enumerable internal functions\\n */\\nabstract contract ERC1155EnumerableInternal is ERC1155BaseInternal {\\n    using EnumerableSet for EnumerableSet.AddressSet;\\n    using EnumerableSet for EnumerableSet.UintSet;\\n\\n    /**\\n     * @notice ERC1155 hook: update aggregate values\\n     * @inheritdoc ERC1155BaseInternal\\n     */\\n    function _beforeTokenTransfer(\\n        address operator,\\n        address from,\\n        address to,\\n        uint256[] memory ids,\\n        uint256[] memory amounts,\\n        bytes memory data\\n    ) internal virtual override {\\n        super._beforeTokenTransfer(operator, from, to, ids, amounts, data);\\n\\n        if (from != to) {\\n            ERC1155EnumerableStorage.Layout storage l = ERC1155EnumerableStorage\\n                .layout();\\n            mapping(uint256 => EnumerableSet.AddressSet)\\n                storage tokenAccounts = l.accountsByToken;\\n            EnumerableSet.UintSet storage fromTokens = l.tokensByAccount[from];\\n            EnumerableSet.UintSet storage toTokens = l.tokensByAccount[to];\\n\\n            for (uint256 i; i < ids.length; i++) {\\n                uint256 amount = amounts[i];\\n\\n                if (amount > 0) {\\n                    uint256 id = ids[i];\\n\\n                    if (from == address(0)) {\\n                        l.totalSupply[id] += amount;\\n                    } else if (_balanceOf(from, id) == amount) {\\n                        tokenAccounts[id].remove(from);\\n                        fromTokens.remove(id);\\n                    }\\n\\n                    if (to == address(0)) {\\n                        l.totalSupply[id] -= amount;\\n                    } else if (_balanceOf(to, id) == 0) {\\n                        tokenAccounts[id].add(to);\\n                        toTokens.add(id);\\n                    }\\n                }\\n            }\\n        }\\n    }\\n}\\n\"},\"contracts/oracle/IVolatilitySurfaceOracle.sol\":{\"content\":\"// SPDX-License-Identifier: LGPL-3.0-or-later\\r\\n\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport {VolatilitySurfaceOracleStorage} from \\\"./VolatilitySurfaceOracleStorage.sol\\\";\\r\\n\\r\\ninterface IVolatilitySurfaceOracle {\\r\\n    function getWhitelistedRelayers() external view returns (address[] memory);\\r\\n\\r\\n    function getVolatilitySurface(address baseToken, address underlyingToken)\\r\\n        external\\r\\n        view\\r\\n        returns (VolatilitySurfaceOracleStorage.Update memory);\\r\\n\\r\\n    function getVolatilitySurfaceCoefficientsUnpacked(\\r\\n        address baseToken,\\r\\n        address underlyingToken,\\r\\n        bool isCall\\r\\n    ) external view returns (int256[] memory);\\r\\n\\r\\n    function getTimeToMaturity64x64(uint64 maturity)\\r\\n        external\\r\\n        view\\r\\n        returns (int128);\\r\\n\\r\\n    function getAnnualizedVolatility64x64(\\r\\n        address baseToken,\\r\\n        address underlyingToken,\\r\\n        int128 spot64x64,\\r\\n        int128 strike64x64,\\r\\n        int128 timeToMaturity64x64,\\r\\n        bool isCall\\r\\n    ) external view returns (int128);\\r\\n\\r\\n    function getBlackScholesPrice64x64(\\r\\n        address baseToken,\\r\\n        address underlyingToken,\\r\\n        int128 strike64x64,\\r\\n        int128 spot64x64,\\r\\n        int128 timeToMaturity64x64,\\r\\n        bool isCall\\r\\n    ) external view returns (int128);\\r\\n\\r\\n    function getBlackScholesPrice(\\r\\n        address baseToken,\\r\\n        address underlyingToken,\\r\\n        int128 strike64x64,\\r\\n        int128 spot64x64,\\r\\n        int128 timeToMaturity64x64,\\r\\n        bool isCall\\r\\n    ) external view returns (uint256);\\r\\n}\\r\\n\"},\"contracts/pool/PoolInternal.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\n// For further clarification please see https://license.premia.legal\\r\\n\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nimport {IERC173} from \\\"@solidstate/contracts/access/IERC173.sol\\\";\\r\\nimport {OwnableStorage} from \\\"@solidstate/contracts/access/OwnableStorage.sol\\\";\\r\\nimport {IERC20} from \\\"@solidstate/contracts/token/ERC20/IERC20.sol\\\";\\r\\nimport {ERC1155EnumerableInternal, ERC1155EnumerableStorage, EnumerableSet} from \\\"@solidstate/contracts/token/ERC1155/enumerable/ERC1155Enumerable.sol\\\";\\r\\nimport {IWETH} from \\\"@solidstate/contracts/utils/IWETH.sol\\\";\\r\\n\\r\\nimport {PoolStorage} from \\\"./PoolStorage.sol\\\";\\r\\n\\r\\nimport {ABDKMath64x64} from \\\"abdk-libraries-solidity/ABDKMath64x64.sol\\\";\\r\\nimport {ABDKMath64x64Token} from \\\"../libraries/ABDKMath64x64Token.sol\\\";\\r\\nimport {OptionMath} from \\\"../libraries/OptionMath.sol\\\";\\r\\nimport {IFeeDiscount} from \\\"../staking/IFeeDiscount.sol\\\";\\r\\nimport {IPoolEvents} from \\\"./IPoolEvents.sol\\\";\\r\\nimport {IPremiaMining} from \\\"../mining/IPremiaMining.sol\\\";\\r\\nimport {IVolatilitySurfaceOracle} from \\\"../oracle/IVolatilitySurfaceOracle.sol\\\";\\r\\n\\r\\n/**\\r\\n * @title Premia option pool\\r\\n * @dev deployed standalone and referenced by PoolProxy\\r\\n */\\r\\ncontract PoolInternal is IPoolEvents, ERC1155EnumerableInternal {\\r\\n    using ABDKMath64x64 for int128;\\r\\n    using EnumerableSet for EnumerableSet.AddressSet;\\r\\n    using EnumerableSet for EnumerableSet.UintSet;\\r\\n    using PoolStorage for PoolStorage.Layout;\\r\\n\\r\\n    address internal immutable WETH_ADDRESS;\\r\\n    address internal immutable PREMIA_MINING_ADDRESS;\\r\\n    address internal immutable FEE_RECEIVER_ADDRESS;\\r\\n    address internal immutable FEE_DISCOUNT_ADDRESS;\\r\\n    address internal immutable IVOL_ORACLE_ADDRESS;\\r\\n\\r\\n    int128 internal immutable FEE_64x64;\\r\\n\\r\\n    uint256 internal immutable UNDERLYING_FREE_LIQ_TOKEN_ID;\\r\\n    uint256 internal immutable BASE_FREE_LIQ_TOKEN_ID;\\r\\n\\r\\n    uint256 internal immutable UNDERLYING_RESERVED_LIQ_TOKEN_ID;\\r\\n    uint256 internal immutable BASE_RESERVED_LIQ_TOKEN_ID;\\r\\n\\r\\n    uint256 internal constant INVERSE_BASIS_POINT = 1e4;\\r\\n    uint256 internal constant BATCHING_PERIOD = 260;\\r\\n\\r\\n    // Minimum APY for capital locked up to underwrite options.\\r\\n    // The quote will return a minimum price corresponding to this APY\\r\\n    int128 internal constant MIN_APY_64x64 = 0x4ccccccccccccccd; // 0.3\\r\\n\\r\\n    constructor(\\r\\n        address ivolOracle,\\r\\n        address weth,\\r\\n        address premiaMining,\\r\\n        address feeReceiver,\\r\\n        address feeDiscountAddress,\\r\\n        int128 fee64x64\\r\\n    ) {\\r\\n        IVOL_ORACLE_ADDRESS = ivolOracle;\\r\\n        WETH_ADDRESS = weth;\\r\\n        PREMIA_MINING_ADDRESS = premiaMining;\\r\\n        FEE_RECEIVER_ADDRESS = feeReceiver;\\r\\n        // PremiaFeeDiscount contract address\\r\\n        FEE_DISCOUNT_ADDRESS = feeDiscountAddress;\\r\\n        FEE_64x64 = fee64x64;\\r\\n\\r\\n        UNDERLYING_FREE_LIQ_TOKEN_ID = PoolStorage.formatTokenId(\\r\\n            PoolStorage.TokenType.UNDERLYING_FREE_LIQ,\\r\\n            0,\\r\\n            0\\r\\n        );\\r\\n        BASE_FREE_LIQ_TOKEN_ID = PoolStorage.formatTokenId(\\r\\n            PoolStorage.TokenType.BASE_FREE_LIQ,\\r\\n            0,\\r\\n            0\\r\\n        );\\r\\n\\r\\n        UNDERLYING_RESERVED_LIQ_TOKEN_ID = PoolStorage.formatTokenId(\\r\\n            PoolStorage.TokenType.UNDERLYING_RESERVED_LIQ,\\r\\n            0,\\r\\n            0\\r\\n        );\\r\\n        BASE_RESERVED_LIQ_TOKEN_ID = PoolStorage.formatTokenId(\\r\\n            PoolStorage.TokenType.BASE_RESERVED_LIQ,\\r\\n            0,\\r\\n            0\\r\\n        );\\r\\n    }\\r\\n\\r\\n    modifier onlyProtocolOwner() {\\r\\n        require(\\r\\n            msg.sender == IERC173(OwnableStorage.layout().owner).owner(),\\r\\n            \\\"Not protocol owner\\\"\\r\\n        );\\r\\n        _;\\r\\n    }\\r\\n\\r\\n    function _getFeeDiscount(address feePayer)\\r\\n        internal\\r\\n        view\\r\\n        returns (uint256 discount)\\r\\n    {\\r\\n        if (FEE_DISCOUNT_ADDRESS != address(0)) {\\r\\n            discount = IFeeDiscount(FEE_DISCOUNT_ADDRESS).getDiscount(feePayer);\\r\\n        }\\r\\n    }\\r\\n\\r\\n    function _getFeeWithDiscount(address feePayer, uint256 fee)\\r\\n        internal\\r\\n        view\\r\\n        returns (uint256)\\r\\n    {\\r\\n        uint256 discount = _getFeeDiscount(feePayer);\\r\\n        return fee - ((fee * discount) / INVERSE_BASIS_POINT);\\r\\n    }\\r\\n\\r\\n    function _withdrawFees(bool isCall) internal returns (uint256 amount) {\\r\\n        uint256 tokenId = _getReservedLiquidityTokenId(isCall);\\r\\n        amount = _balanceOf(FEE_RECEIVER_ADDRESS, tokenId);\\r\\n\\r\\n        if (amount > 0) {\\r\\n            _burn(FEE_RECEIVER_ADDRESS, tokenId, amount);\\r\\n            emit FeeWithdrawal(isCall, amount);\\r\\n        }\\r\\n    }\\r\\n\\r\\n    /**\\r\\n     * @notice calculate price of option contract\\r\\n     * @param args structured quote arguments\\r\\n     * @return result quote result\\r\\n     */\\r\\n    function _quote(PoolStorage.QuoteArgsInternal memory args)\\r\\n        internal\\r\\n        view\\r\\n        returns (PoolStorage.QuoteResultInternal memory result)\\r\\n    {\\r\\n        require(\\r\\n            args.strike64x64 > 0 && args.spot64x64 > 0 && args.maturity > 0,\\r\\n            \\\"invalid args\\\"\\r\\n        );\\r\\n        PoolStorage.Layout storage l = PoolStorage.layout();\\r\\n\\r\\n        int128 contractSize64x64 = ABDKMath64x64Token.fromDecimals(\\r\\n            args.contractSize,\\r\\n            l.underlyingDecimals\\r\\n        );\\r\\n        bool isCall = args.isCall;\\r\\n\\r\\n        (int128 adjustedCLevel64x64, int128 oldLiquidity64x64) = l\\r\\n            .applyCLevelPendingDepositAdjustment(\\r\\n                l.getDecayAdjustedCLevel64x64(isCall),\\r\\n                l.totalFreeLiquiditySupply64x64(isCall),\\r\\n                isCall\\r\\n            );\\r\\n\\r\\n        require(oldLiquidity64x64 > 0, \\\"no liq\\\");\\r\\n\\r\\n        int128 timeToMaturity64x64 = ABDKMath64x64.divu(\\r\\n            args.maturity - block.timestamp,\\r\\n            365 days\\r\\n        );\\r\\n\\r\\n        int128 annualizedVolatility64x64 = IVolatilitySurfaceOracle(\\r\\n            IVOL_ORACLE_ADDRESS\\r\\n        ).getAnnualizedVolatility64x64(\\r\\n                l.base,\\r\\n                l.underlying,\\r\\n                args.spot64x64,\\r\\n                args.strike64x64,\\r\\n                timeToMaturity64x64,\\r\\n                isCall\\r\\n            );\\r\\n\\r\\n        require(annualizedVolatility64x64 > 0, \\\"vol = 0\\\");\\r\\n\\r\\n        (\\r\\n            int128 price64x64,\\r\\n            int128 cLevel64x64,\\r\\n            int128 slippageCoefficient64x64\\r\\n        ) = OptionMath.quotePrice(\\r\\n                OptionMath.QuoteArgs(\\r\\n                    annualizedVolatility64x64.mul(annualizedVolatility64x64),\\r\\n                    args.strike64x64,\\r\\n                    args.spot64x64,\\r\\n                    timeToMaturity64x64,\\r\\n                    adjustedCLevel64x64,\\r\\n                    oldLiquidity64x64,\\r\\n                    oldLiquidity64x64.sub(contractSize64x64),\\r\\n                    0x10000000000000000, // 64x64 fixed point representation of 1\\r\\n                    MIN_APY_64x64,\\r\\n                    isCall\\r\\n                )\\r\\n            );\\r\\n\\r\\n        result.baseCost64x64 = isCall\\r\\n            ? price64x64.mul(contractSize64x64).div(args.spot64x64)\\r\\n            : price64x64.mul(contractSize64x64);\\r\\n        result.feeCost64x64 = result.baseCost64x64.mul(FEE_64x64);\\r\\n        result.cLevel64x64 = cLevel64x64;\\r\\n        result.slippageCoefficient64x64 = slippageCoefficient64x64;\\r\\n\\r\\n        int128 discount = ABDKMath64x64.divu(\\r\\n            _getFeeDiscount(args.feePayer),\\r\\n            INVERSE_BASIS_POINT\\r\\n        );\\r\\n        result.feeCost64x64 -= result.feeCost64x64.mul(discount);\\r\\n    }\\r\\n\\r\\n    /**\\r\\n     * @notice burn corresponding long and short option tokens\\r\\n     * @param account holder of tokens to annihilate\\r\\n     * @param maturity timestamp of option maturity\\r\\n     * @param strike64x64 64x64 fixed point representation of strike price\\r\\n     * @param isCall true for call, false for put\\r\\n     * @param contractSize quantity of option contract tokens to annihilate\\r\\n     */\\r\\n    function _annihilate(\\r\\n        address account,\\r\\n        uint64 maturity,\\r\\n        int128 strike64x64,\\r\\n        bool isCall,\\r\\n        uint256 contractSize\\r\\n    ) internal {\\r\\n        uint256 longTokenId = PoolStorage.formatTokenId(\\r\\n            _getTokenType(isCall, true),\\r\\n            maturity,\\r\\n            strike64x64\\r\\n        );\\r\\n        uint256 shortTokenId = PoolStorage.formatTokenId(\\r\\n            _getTokenType(isCall, false),\\r\\n            maturity,\\r\\n            strike64x64\\r\\n        );\\r\\n\\r\\n        _burn(account, longTokenId, contractSize);\\r\\n        _burn(account, shortTokenId, contractSize);\\r\\n\\r\\n        emit Annihilate(shortTokenId, contractSize);\\r\\n    }\\r\\n\\r\\n    /**\\r\\n     * @notice purchase option\\r\\n     * @param l storage layout struct\\r\\n     * @param account recipient of purchased option\\r\\n     * @param maturity timestamp of option maturity\\r\\n     * @param strike64x64 64x64 fixed point representation of strike price\\r\\n     * @param isCall true for call, false for put\\r\\n     * @param contractSize size of option contract\\r\\n     * @param newPrice64x64 64x64 fixed point representation of current spot price\\r\\n     * @return baseCost quantity of tokens required to purchase long position\\r\\n     * @return feeCost quantity of tokens required to pay fees\\r\\n     */\\r\\n    function _purchase(\\r\\n        PoolStorage.Layout storage l,\\r\\n        address account,\\r\\n        uint64 maturity,\\r\\n        int128 strike64x64,\\r\\n        bool isCall,\\r\\n        uint256 contractSize,\\r\\n        int128 newPrice64x64\\r\\n    ) internal returns (uint256 baseCost, uint256 feeCost) {\\r\\n        require(maturity > block.timestamp, \\\"expired\\\");\\r\\n        require(contractSize >= l.underlyingMinimum, \\\"too small\\\");\\r\\n\\r\\n        {\\r\\n            uint256 size = isCall\\r\\n                ? contractSize\\r\\n                : l.fromUnderlyingToBaseDecimals(\\r\\n                    strike64x64.mulu(contractSize)\\r\\n                );\\r\\n\\r\\n            require(\\r\\n                size <=\\r\\n                    ERC1155EnumerableStorage.layout().totalSupply[\\r\\n                        _getFreeLiquidityTokenId(isCall)\\r\\n                    ] -\\r\\n                        l.nextDeposits[isCall].totalPendingDeposits,\\r\\n                \\\"insuf liq\\\"\\r\\n            );\\r\\n        }\\r\\n\\r\\n        PoolStorage.QuoteResultInternal memory quote = _quote(\\r\\n            PoolStorage.QuoteArgsInternal(\\r\\n                account,\\r\\n                maturity,\\r\\n                strike64x64,\\r\\n                newPrice64x64,\\r\\n                contractSize,\\r\\n                isCall\\r\\n            )\\r\\n        );\\r\\n\\r\\n        baseCost = ABDKMath64x64Token.toDecimals(\\r\\n            quote.baseCost64x64,\\r\\n            l.getTokenDecimals(isCall)\\r\\n        );\\r\\n\\r\\n        feeCost = ABDKMath64x64Token.toDecimals(\\r\\n            quote.feeCost64x64,\\r\\n            l.getTokenDecimals(isCall)\\r\\n        );\\r\\n\\r\\n        uint256 longTokenId = PoolStorage.formatTokenId(\\r\\n            _getTokenType(isCall, true),\\r\\n            maturity,\\r\\n            strike64x64\\r\\n        );\\r\\n\\r\\n        uint256 shortTokenId = PoolStorage.formatTokenId(\\r\\n            _getTokenType(isCall, false),\\r\\n            maturity,\\r\\n            strike64x64\\r\\n        );\\r\\n\\r\\n        // mint long option token for buyer\\r\\n        _mint(account, longTokenId, contractSize);\\r\\n\\r\\n        int128 oldLiquidity64x64 = l.totalFreeLiquiditySupply64x64(isCall);\\r\\n        // burn free liquidity tokens from other underwriters\\r\\n        _mintShortTokenLoop(\\r\\n            l,\\r\\n            account,\\r\\n            contractSize,\\r\\n            baseCost,\\r\\n            shortTokenId,\\r\\n            isCall\\r\\n        );\\r\\n        int128 newLiquidity64x64 = l.totalFreeLiquiditySupply64x64(isCall);\\r\\n\\r\\n        _setCLevel(l, oldLiquidity64x64, newLiquidity64x64, isCall);\\r\\n\\r\\n        // mint reserved liquidity tokens for fee receiver\\r\\n        _mint(\\r\\n            FEE_RECEIVER_ADDRESS,\\r\\n            _getReservedLiquidityTokenId(isCall),\\r\\n            feeCost\\r\\n        );\\r\\n\\r\\n        emit Purchase(\\r\\n            account,\\r\\n            longTokenId,\\r\\n            contractSize,\\r\\n            baseCost,\\r\\n            feeCost,\\r\\n            newPrice64x64\\r\\n        );\\r\\n    }\\r\\n\\r\\n    /**\\r\\n     * @notice reassign short position to new underwriter\\r\\n     * @param l storage layout struct\\r\\n     * @param account holder of positions to be reassigned\\r\\n     * @param maturity timestamp of option maturity\\r\\n     * @param strike64x64 64x64 fixed point representation of strike price\\r\\n     * @param isCall true for call, false for put\\r\\n     * @param contractSize quantity of option contract tokens to reassign\\r\\n     * @param newPrice64x64 64x64 fixed point representation of current spot price\\r\\n     * @return baseCost quantity of tokens required to reassign short position\\r\\n     * @return feeCost quantity of tokens required to pay fees\\r\\n     * @return amountOut quantity of liquidity freed\\r\\n     */\\r\\n    function _reassign(\\r\\n        PoolStorage.Layout storage l,\\r\\n        address account,\\r\\n        uint64 maturity,\\r\\n        int128 strike64x64,\\r\\n        bool isCall,\\r\\n        uint256 contractSize,\\r\\n        int128 newPrice64x64\\r\\n    )\\r\\n        internal\\r\\n        returns (\\r\\n            uint256 baseCost,\\r\\n            uint256 feeCost,\\r\\n            uint256 amountOut\\r\\n        )\\r\\n    {\\r\\n        (baseCost, feeCost) = _purchase(\\r\\n            l,\\r\\n            account,\\r\\n            maturity,\\r\\n            strike64x64,\\r\\n            isCall,\\r\\n            contractSize,\\r\\n            newPrice64x64\\r\\n        );\\r\\n\\r\\n        _annihilate(account, maturity, strike64x64, isCall, contractSize);\\r\\n\\r\\n        uint256 annihilateAmount = isCall\\r\\n            ? contractSize\\r\\n            : l.fromUnderlyingToBaseDecimals(strike64x64.mulu(contractSize));\\r\\n\\r\\n        amountOut = annihilateAmount - baseCost - feeCost;\\r\\n    }\\r\\n\\r\\n    /**\\r\\n     * @notice exercise option on behalf of holder\\r\\n     * @dev used for processing of expired options if passed holder is zero address\\r\\n     * @param holder owner of long option tokens to exercise\\r\\n     * @param longTokenId long option token id\\r\\n     * @param contractSize quantity of tokens to exercise\\r\\n     */\\r\\n    function _exercise(\\r\\n        address holder,\\r\\n        uint256 longTokenId,\\r\\n        uint256 contractSize\\r\\n    ) internal {\\r\\n        uint64 maturity;\\r\\n        int128 strike64x64;\\r\\n        bool isCall;\\r\\n\\r\\n        bool onlyExpired = holder == address(0);\\r\\n\\r\\n        {\\r\\n            PoolStorage.TokenType tokenType;\\r\\n            (tokenType, maturity, strike64x64) = PoolStorage.parseTokenId(\\r\\n                longTokenId\\r\\n            );\\r\\n            require(\\r\\n                tokenType == PoolStorage.TokenType.LONG_CALL ||\\r\\n                    tokenType == PoolStorage.TokenType.LONG_PUT,\\r\\n                \\\"invalid type\\\"\\r\\n            );\\r\\n            require(!onlyExpired || maturity < block.timestamp, \\\"not expired\\\");\\r\\n            isCall = tokenType == PoolStorage.TokenType.LONG_CALL;\\r\\n        }\\r\\n\\r\\n        PoolStorage.Layout storage l = PoolStorage.layout();\\r\\n\\r\\n        int128 spot64x64 = _update(l);\\r\\n\\r\\n        if (maturity < block.timestamp) {\\r\\n            spot64x64 = l.getPriceUpdateAfter(maturity);\\r\\n        }\\r\\n\\r\\n        require(\\r\\n            onlyExpired ||\\r\\n                (\\r\\n                    isCall\\r\\n                        ? (spot64x64 > strike64x64)\\r\\n                        : (spot64x64 < strike64x64)\\r\\n                ),\\r\\n            \\\"not ITM\\\"\\r\\n        );\\r\\n\\r\\n        uint256 exerciseValue;\\r\\n        // option has a non-zero exercise value\\r\\n        if (isCall) {\\r\\n            if (spot64x64 > strike64x64) {\\r\\n                exerciseValue = spot64x64.sub(strike64x64).div(spot64x64).mulu(\\r\\n                    contractSize\\r\\n                );\\r\\n            }\\r\\n        } else {\\r\\n            if (spot64x64 < strike64x64) {\\r\\n                exerciseValue = l.fromUnderlyingToBaseDecimals(\\r\\n                    strike64x64.sub(spot64x64).mulu(contractSize)\\r\\n                );\\r\\n            }\\r\\n        }\\r\\n\\r\\n        uint256 totalFee;\\r\\n\\r\\n        if (onlyExpired) {\\r\\n            totalFee += _burnLongTokenLoop(\\r\\n                contractSize,\\r\\n                exerciseValue,\\r\\n                longTokenId,\\r\\n                isCall\\r\\n            );\\r\\n        } else {\\r\\n            // burn long option tokens from sender\\r\\n            _burn(holder, longTokenId, contractSize);\\r\\n\\r\\n            uint256 fee;\\r\\n\\r\\n            if (exerciseValue > 0) {\\r\\n                fee = _getFeeWithDiscount(\\r\\n                    holder,\\r\\n                    FEE_64x64.mulu(exerciseValue)\\r\\n                );\\r\\n                totalFee += fee;\\r\\n\\r\\n                _pushTo(holder, _getPoolToken(isCall), exerciseValue - fee);\\r\\n            }\\r\\n\\r\\n            emit Exercise(\\r\\n                holder,\\r\\n                longTokenId,\\r\\n                contractSize,\\r\\n                exerciseValue,\\r\\n                fee\\r\\n            );\\r\\n        }\\r\\n\\r\\n        totalFee += _burnShortTokenLoop(\\r\\n            contractSize,\\r\\n            exerciseValue,\\r\\n            PoolStorage.formatTokenId(\\r\\n                _getTokenType(isCall, false),\\r\\n                maturity,\\r\\n                strike64x64\\r\\n            ),\\r\\n            isCall\\r\\n        );\\r\\n\\r\\n        _mint(\\r\\n            FEE_RECEIVER_ADDRESS,\\r\\n            _getReservedLiquidityTokenId(isCall),\\r\\n            totalFee\\r\\n        );\\r\\n    }\\r\\n\\r\\n    function _mintShortTokenLoop(\\r\\n        PoolStorage.Layout storage l,\\r\\n        address buyer,\\r\\n        uint256 contractSize,\\r\\n        uint256 premium,\\r\\n        uint256 shortTokenId,\\r\\n        bool isCall\\r\\n    ) internal {\\r\\n        uint256 freeLiqTokenId = _getFreeLiquidityTokenId(isCall);\\r\\n        (, , int128 strike64x64) = PoolStorage.parseTokenId(shortTokenId);\\r\\n\\r\\n        uint256 toPay = isCall\\r\\n            ? contractSize\\r\\n            : l.fromUnderlyingToBaseDecimals(strike64x64.mulu(contractSize));\\r\\n\\r\\n        while (toPay > 0) {\\r\\n            address underwriter = l.liquidityQueueAscending[isCall][address(0)];\\r\\n            uint256 balance = _balanceOf(underwriter, freeLiqTokenId);\\r\\n\\r\\n            // If dust left, we remove underwriter and skip to next\\r\\n            if (balance < _getMinimumAmount(l, isCall)) {\\r\\n                l.removeUnderwriter(underwriter, isCall);\\r\\n                continue;\\r\\n            }\\r\\n\\r\\n            if (!l.getReinvestmentStatus(underwriter, isCall)) {\\r\\n                _burn(underwriter, freeLiqTokenId, balance);\\r\\n                _mint(\\r\\n                    underwriter,\\r\\n                    _getReservedLiquidityTokenId(isCall),\\r\\n                    balance\\r\\n                );\\r\\n                _subUserTVL(l, underwriter, isCall, balance);\\r\\n                continue;\\r\\n            }\\r\\n\\r\\n            // amount of liquidity provided by underwriter, accounting for reinvested premium\\r\\n            uint256 intervalContractSize = ((balance -\\r\\n                l.pendingDeposits[underwriter][l.nextDeposits[isCall].eta][\\r\\n                    isCall\\r\\n                ]) * (toPay + premium)) / toPay;\\r\\n            if (intervalContractSize == 0) continue;\\r\\n            if (intervalContractSize > toPay) intervalContractSize = toPay;\\r\\n\\r\\n            // amount of premium paid to underwriter\\r\\n            uint256 intervalPremium = (premium * intervalContractSize) / toPay;\\r\\n            premium -= intervalPremium;\\r\\n            toPay -= intervalContractSize;\\r\\n            _addUserTVL(l, underwriter, isCall, intervalPremium);\\r\\n\\r\\n            // burn free liquidity tokens from underwriter\\r\\n            _burn(\\r\\n                underwriter,\\r\\n                freeLiqTokenId,\\r\\n                intervalContractSize - intervalPremium\\r\\n            );\\r\\n\\r\\n            if (isCall == false) {\\r\\n                // For PUT, conversion to contract amount is done here (Prior to this line, it is token amount)\\r\\n                intervalContractSize = l.fromBaseToUnderlyingDecimals(\\r\\n                    strike64x64.inv().mulu(intervalContractSize)\\r\\n                );\\r\\n            }\\r\\n\\r\\n            // mint short option tokens for underwriter\\r\\n            // toPay == 0 ? contractSize : intervalContractSize : To prevent minting less than amount,\\r\\n            // because of rounding (Can happen for put, because of fixed point precision)\\r\\n            _mint(\\r\\n                underwriter,\\r\\n                shortTokenId,\\r\\n                toPay == 0 ? contractSize : intervalContractSize\\r\\n            );\\r\\n\\r\\n            emit Underwrite(\\r\\n                underwriter,\\r\\n                buyer,\\r\\n                shortTokenId,\\r\\n                toPay == 0 ? contractSize : intervalContractSize,\\r\\n                intervalPremium,\\r\\n                false\\r\\n            );\\r\\n\\r\\n            contractSize -= intervalContractSize;\\r\\n        }\\r\\n    }\\r\\n\\r\\n    function _burnLongTokenLoop(\\r\\n        uint256 contractSize,\\r\\n        uint256 exerciseValue,\\r\\n        uint256 longTokenId,\\r\\n        bool isCall\\r\\n    ) internal returns (uint256 totalFee) {\\r\\n        EnumerableSet.AddressSet storage holders = ERC1155EnumerableStorage\\r\\n            .layout()\\r\\n            .accountsByToken[longTokenId];\\r\\n\\r\\n        while (contractSize > 0) {\\r\\n            address longTokenHolder = holders.at(holders.length() - 1);\\r\\n\\r\\n            uint256 intervalContractSize = _balanceOf(\\r\\n                longTokenHolder,\\r\\n                longTokenId\\r\\n            );\\r\\n            if (intervalContractSize > contractSize)\\r\\n                intervalContractSize = contractSize;\\r\\n\\r\\n            uint256 intervalExerciseValue;\\r\\n\\r\\n            uint256 fee;\\r\\n            if (exerciseValue > 0) {\\r\\n                intervalExerciseValue =\\r\\n                    (exerciseValue * intervalContractSize) /\\r\\n                    contractSize;\\r\\n\\r\\n                fee = _getFeeWithDiscount(\\r\\n                    longTokenHolder,\\r\\n                    FEE_64x64.mulu(intervalExerciseValue)\\r\\n                );\\r\\n                totalFee += fee;\\r\\n\\r\\n                exerciseValue -= intervalExerciseValue;\\r\\n                _pushTo(\\r\\n                    longTokenHolder,\\r\\n                    _getPoolToken(isCall),\\r\\n                    intervalExerciseValue - fee\\r\\n                );\\r\\n            }\\r\\n\\r\\n            contractSize -= intervalContractSize;\\r\\n\\r\\n            emit Exercise(\\r\\n                longTokenHolder,\\r\\n                longTokenId,\\r\\n                intervalContractSize,\\r\\n                intervalExerciseValue - fee,\\r\\n                fee\\r\\n            );\\r\\n\\r\\n            _burn(longTokenHolder, longTokenId, intervalContractSize);\\r\\n        }\\r\\n    }\\r\\n\\r\\n    function _burnShortTokenLoop(\\r\\n        uint256 contractSize,\\r\\n        uint256 exerciseValue,\\r\\n        uint256 shortTokenId,\\r\\n        bool isCall\\r\\n    ) internal returns (uint256 totalFee) {\\r\\n        EnumerableSet.AddressSet storage underwriters = ERC1155EnumerableStorage\\r\\n            .layout()\\r\\n            .accountsByToken[shortTokenId];\\r\\n        (, , int128 strike64x64) = PoolStorage.parseTokenId(shortTokenId);\\r\\n\\r\\n        while (contractSize > 0) {\\r\\n            address underwriter = underwriters.at(underwriters.length() - 1);\\r\\n\\r\\n            // amount of liquidity provided by underwriter\\r\\n            uint256 intervalContractSize = _balanceOf(\\r\\n                underwriter,\\r\\n                shortTokenId\\r\\n            );\\r\\n            if (intervalContractSize > contractSize)\\r\\n                intervalContractSize = contractSize;\\r\\n\\r\\n            // amount of value claimed by buyer\\r\\n            uint256 intervalExerciseValue = (exerciseValue *\\r\\n                intervalContractSize) / contractSize;\\r\\n            exerciseValue -= intervalExerciseValue;\\r\\n            contractSize -= intervalContractSize;\\r\\n\\r\\n            uint256 freeLiq = isCall\\r\\n                ? intervalContractSize - intervalExerciseValue\\r\\n                : PoolStorage.layout().fromUnderlyingToBaseDecimals(\\r\\n                    strike64x64.mulu(intervalContractSize)\\r\\n                ) - intervalExerciseValue;\\r\\n\\r\\n            uint256 fee = _getFeeWithDiscount(\\r\\n                underwriter,\\r\\n                FEE_64x64.mulu(freeLiq)\\r\\n            );\\r\\n            totalFee += fee;\\r\\n\\r\\n            uint256 tvlToSubtract = intervalExerciseValue;\\r\\n\\r\\n            // mint free liquidity tokens for underwriter\\r\\n            if (\\r\\n                PoolStorage.layout().getReinvestmentStatus(underwriter, isCall)\\r\\n            ) {\\r\\n                _addToDepositQueue(underwriter, freeLiq - fee, isCall);\\r\\n                tvlToSubtract += fee;\\r\\n            } else {\\r\\n                _mint(\\r\\n                    underwriter,\\r\\n                    _getReservedLiquidityTokenId(isCall),\\r\\n                    freeLiq - fee\\r\\n                );\\r\\n                tvlToSubtract += freeLiq;\\r\\n            }\\r\\n\\r\\n            _subUserTVL(\\r\\n                PoolStorage.layout(),\\r\\n                underwriter,\\r\\n                isCall,\\r\\n                tvlToSubtract\\r\\n            );\\r\\n\\r\\n            // burn short option tokens from underwriter\\r\\n            _burn(underwriter, shortTokenId, intervalContractSize);\\r\\n\\r\\n            emit AssignExercise(\\r\\n                underwriter,\\r\\n                shortTokenId,\\r\\n                freeLiq - fee,\\r\\n                intervalContractSize,\\r\\n                fee\\r\\n            );\\r\\n        }\\r\\n    }\\r\\n\\r\\n    function _addToDepositQueue(\\r\\n        address account,\\r\\n        uint256 amount,\\r\\n        bool isCallPool\\r\\n    ) internal {\\r\\n        PoolStorage.Layout storage l = PoolStorage.layout();\\r\\n\\r\\n        _mint(account, _getFreeLiquidityTokenId(isCallPool), amount);\\r\\n\\r\\n        uint256 nextBatch = (block.timestamp / BATCHING_PERIOD) *\\r\\n            BATCHING_PERIOD +\\r\\n            BATCHING_PERIOD;\\r\\n        l.pendingDeposits[account][nextBatch][isCallPool] += amount;\\r\\n\\r\\n        PoolStorage.BatchData storage batchData = l.nextDeposits[isCallPool];\\r\\n        batchData.totalPendingDeposits += amount;\\r\\n        batchData.eta = nextBatch;\\r\\n    }\\r\\n\\r\\n    function _processPendingDeposits(PoolStorage.Layout storage l, bool isCall)\\r\\n        internal\\r\\n    {\\r\\n        PoolStorage.BatchData storage data = l.nextDeposits[isCall];\\r\\n\\r\\n        if (data.eta == 0 || block.timestamp < data.eta) return;\\r\\n\\r\\n        int128 oldLiquidity64x64 = l.totalFreeLiquiditySupply64x64(isCall);\\r\\n\\r\\n        _setCLevel(\\r\\n            l,\\r\\n            oldLiquidity64x64,\\r\\n            oldLiquidity64x64.add(\\r\\n                ABDKMath64x64Token.fromDecimals(\\r\\n                    data.totalPendingDeposits,\\r\\n                    l.getTokenDecimals(isCall)\\r\\n                )\\r\\n            ),\\r\\n            isCall\\r\\n        );\\r\\n\\r\\n        delete l.nextDeposits[isCall];\\r\\n    }\\r\\n\\r\\n    function _getFreeLiquidityTokenId(bool isCall)\\r\\n        internal\\r\\n        view\\r\\n        returns (uint256 freeLiqTokenId)\\r\\n    {\\r\\n        freeLiqTokenId = isCall\\r\\n            ? UNDERLYING_FREE_LIQ_TOKEN_ID\\r\\n            : BASE_FREE_LIQ_TOKEN_ID;\\r\\n    }\\r\\n\\r\\n    function _getReservedLiquidityTokenId(bool isCall)\\r\\n        internal\\r\\n        view\\r\\n        returns (uint256 reservedLiqTokenId)\\r\\n    {\\r\\n        reservedLiqTokenId = isCall\\r\\n            ? UNDERLYING_RESERVED_LIQ_TOKEN_ID\\r\\n            : BASE_RESERVED_LIQ_TOKEN_ID;\\r\\n    }\\r\\n\\r\\n    function _getPoolToken(bool isCall) internal view returns (address token) {\\r\\n        token = isCall\\r\\n            ? PoolStorage.layout().underlying\\r\\n            : PoolStorage.layout().base;\\r\\n    }\\r\\n\\r\\n    function _getTokenType(bool isCall, bool isLong)\\r\\n        internal\\r\\n        pure\\r\\n        returns (PoolStorage.TokenType tokenType)\\r\\n    {\\r\\n        if (isCall) {\\r\\n            tokenType = isLong\\r\\n                ? PoolStorage.TokenType.LONG_CALL\\r\\n                : PoolStorage.TokenType.SHORT_CALL;\\r\\n        } else {\\r\\n            tokenType = isLong\\r\\n                ? PoolStorage.TokenType.LONG_PUT\\r\\n                : PoolStorage.TokenType.SHORT_PUT;\\r\\n        }\\r\\n    }\\r\\n\\r\\n    function _getMinimumAmount(PoolStorage.Layout storage l, bool isCall)\\r\\n        internal\\r\\n        view\\r\\n        returns (uint256 minimumAmount)\\r\\n    {\\r\\n        minimumAmount = isCall ? l.underlyingMinimum : l.baseMinimum;\\r\\n    }\\r\\n\\r\\n    function _getPoolCapAmount(PoolStorage.Layout storage l, bool isCall)\\r\\n        internal\\r\\n        view\\r\\n        returns (uint256 poolCapAmount)\\r\\n    {\\r\\n        poolCapAmount = isCall ? l.underlyingPoolCap : l.basePoolCap;\\r\\n    }\\r\\n\\r\\n    function _setCLevel(\\r\\n        PoolStorage.Layout storage l,\\r\\n        int128 oldLiquidity64x64,\\r\\n        int128 newLiquidity64x64,\\r\\n        bool isCallPool\\r\\n    ) internal {\\r\\n        int128 oldCLevel64x64 = l.getDecayAdjustedCLevel64x64(isCallPool);\\r\\n\\r\\n        int128 cLevel64x64 = l.applyCLevelLiquidityChangeAdjustment(\\r\\n            oldCLevel64x64,\\r\\n            oldLiquidity64x64,\\r\\n            newLiquidity64x64,\\r\\n            isCallPool\\r\\n        );\\r\\n\\r\\n        l.setCLevel(cLevel64x64, isCallPool);\\r\\n\\r\\n        emit UpdateCLevel(\\r\\n            isCallPool,\\r\\n            cLevel64x64,\\r\\n            oldLiquidity64x64,\\r\\n            newLiquidity64x64\\r\\n        );\\r\\n    }\\r\\n\\r\\n    /**\\r\\n     * @notice calculate and store updated market state\\r\\n     * @param l storage layout struct\\r\\n     * @return newPrice64x64 64x64 fixed point representation of current spot price\\r\\n     */\\r\\n    function _update(PoolStorage.Layout storage l)\\r\\n        internal\\r\\n        returns (int128 newPrice64x64)\\r\\n    {\\r\\n        if (l.updatedAt == block.timestamp) {\\r\\n            return (l.getPriceUpdate(block.timestamp));\\r\\n        }\\r\\n\\r\\n        newPrice64x64 = l.fetchPriceUpdate();\\r\\n\\r\\n        if (l.getPriceUpdate(block.timestamp) == 0) {\\r\\n            l.setPriceUpdate(block.timestamp, newPrice64x64);\\r\\n        }\\r\\n\\r\\n        l.updatedAt = block.timestamp;\\r\\n\\r\\n        _processPendingDeposits(l, true);\\r\\n        _processPendingDeposits(l, false);\\r\\n    }\\r\\n\\r\\n    /**\\r\\n     * @notice transfer ERC20 tokens to message sender\\r\\n     * @param token ERC20 token address\\r\\n     * @param amount quantity of token to transfer\\r\\n     */\\r\\n    function _pushTo(\\r\\n        address to,\\r\\n        address token,\\r\\n        uint256 amount\\r\\n    ) internal {\\r\\n        if (amount == 0) return;\\r\\n\\r\\n        require(IERC20(token).transfer(to, amount), \\\"ERC20 transfer failed\\\");\\r\\n    }\\r\\n\\r\\n    /**\\r\\n     * @notice transfer ERC20 tokens from message sender\\r\\n     * @param from address from which tokens are pulled from\\r\\n     * @param token ERC20 token address\\r\\n     * @param amount quantity of token to transfer\\r\\n     * @param skipWethDeposit if false, will not try to deposit weth from attach eth\\r\\n     */\\r\\n    function _pullFrom(\\r\\n        address from,\\r\\n        address token,\\r\\n        uint256 amount,\\r\\n        bool skipWethDeposit\\r\\n    ) internal {\\r\\n        if (!skipWethDeposit) {\\r\\n            if (token == WETH_ADDRESS) {\\r\\n                if (msg.value > 0) {\\r\\n                    if (msg.value > amount) {\\r\\n                        IWETH(WETH_ADDRESS).deposit{value: amount}();\\r\\n\\r\\n                        (bool success, ) = payable(msg.sender).call{\\r\\n                            value: msg.value - amount\\r\\n                        }(\\\"\\\");\\r\\n\\r\\n                        require(success, \\\"ETH refund failed\\\");\\r\\n\\r\\n                        amount = 0;\\r\\n                    } else {\\r\\n                        unchecked {\\r\\n                            amount -= msg.value;\\r\\n                        }\\r\\n\\r\\n                        IWETH(WETH_ADDRESS).deposit{value: msg.value}();\\r\\n                    }\\r\\n                }\\r\\n            } else {\\r\\n                require(msg.value == 0, \\\"not WETH deposit\\\");\\r\\n            }\\r\\n        }\\r\\n\\r\\n        if (amount > 0) {\\r\\n            require(\\r\\n                IERC20(token).transferFrom(from, address(this), amount),\\r\\n                \\\"ERC20 transfer failed\\\"\\r\\n            );\\r\\n        }\\r\\n    }\\r\\n\\r\\n    function _mint(\\r\\n        address account,\\r\\n        uint256 tokenId,\\r\\n        uint256 amount\\r\\n    ) internal {\\r\\n        _mint(account, tokenId, amount, \\\"\\\");\\r\\n    }\\r\\n\\r\\n    function _addUserTVL(\\r\\n        PoolStorage.Layout storage l,\\r\\n        address user,\\r\\n        bool isCallPool,\\r\\n        uint256 amount\\r\\n    ) internal {\\r\\n        uint256 userTVL = l.userTVL[user][isCallPool];\\r\\n        uint256 totalTVL = l.totalTVL[isCallPool];\\r\\n\\r\\n        IPremiaMining(PREMIA_MINING_ADDRESS).allocatePending(\\r\\n            user,\\r\\n            address(this),\\r\\n            isCallPool,\\r\\n            userTVL,\\r\\n            userTVL + amount,\\r\\n            totalTVL\\r\\n        );\\r\\n\\r\\n        l.userTVL[user][isCallPool] = userTVL + amount;\\r\\n        l.totalTVL[isCallPool] = totalTVL + amount;\\r\\n    }\\r\\n\\r\\n    function _subUserTVL(\\r\\n        PoolStorage.Layout storage l,\\r\\n        address user,\\r\\n        bool isCallPool,\\r\\n        uint256 amount\\r\\n    ) internal {\\r\\n        uint256 userTVL = l.userTVL[user][isCallPool];\\r\\n        uint256 totalTVL = l.totalTVL[isCallPool];\\r\\n\\r\\n        IPremiaMining(PREMIA_MINING_ADDRESS).allocatePending(\\r\\n            user,\\r\\n            address(this),\\r\\n            isCallPool,\\r\\n            userTVL,\\r\\n            userTVL - amount,\\r\\n            totalTVL\\r\\n        );\\r\\n        l.userTVL[user][isCallPool] = userTVL - amount;\\r\\n        l.totalTVL[isCallPool] = totalTVL - amount;\\r\\n    }\\r\\n\\r\\n    /**\\r\\n     * @notice ERC1155 hook: track eligible underwriters\\r\\n     * @param operator transaction sender\\r\\n     * @param from token sender\\r\\n     * @param to token receiver\\r\\n     * @param ids token ids transferred\\r\\n     * @param amounts token quantities transferred\\r\\n     * @param data data payload\\r\\n     */\\r\\n    function _beforeTokenTransfer(\\r\\n        address operator,\\r\\n        address from,\\r\\n        address to,\\r\\n        uint256[] memory ids,\\r\\n        uint256[] memory amounts,\\r\\n        bytes memory data\\r\\n    ) internal virtual override {\\r\\n        super._beforeTokenTransfer(operator, from, to, ids, amounts, data);\\r\\n\\r\\n        PoolStorage.Layout storage l = PoolStorage.layout();\\r\\n\\r\\n        for (uint256 i; i < ids.length; i++) {\\r\\n            uint256 id = ids[i];\\r\\n            uint256 amount = amounts[i];\\r\\n\\r\\n            if (amount == 0) continue;\\r\\n\\r\\n            if (from == address(0)) {\\r\\n                l.tokenIds.add(id);\\r\\n            }\\r\\n\\r\\n            if (\\r\\n                to == address(0) &&\\r\\n                ERC1155EnumerableStorage.layout().totalSupply[id] == 0\\r\\n            ) {\\r\\n                l.tokenIds.remove(id);\\r\\n            }\\r\\n\\r\\n            // prevent transfer of free and reserved liquidity during waiting period\\r\\n\\r\\n            if (\\r\\n                id == UNDERLYING_FREE_LIQ_TOKEN_ID ||\\r\\n                id == BASE_FREE_LIQ_TOKEN_ID ||\\r\\n                id == UNDERLYING_RESERVED_LIQ_TOKEN_ID ||\\r\\n                id == BASE_RESERVED_LIQ_TOKEN_ID\\r\\n            ) {\\r\\n                if (from != address(0) && to != address(0)) {\\r\\n                    bool isCallPool = id == UNDERLYING_FREE_LIQ_TOKEN_ID ||\\r\\n                        id == UNDERLYING_RESERVED_LIQ_TOKEN_ID;\\r\\n\\r\\n                    require(\\r\\n                        l.depositedAt[from][isCallPool] + (1 days) <\\r\\n                            block.timestamp,\\r\\n                        \\\"liq lock 1d\\\"\\r\\n                    );\\r\\n                }\\r\\n            }\\r\\n\\r\\n            if (\\r\\n                id == UNDERLYING_FREE_LIQ_TOKEN_ID ||\\r\\n                id == BASE_FREE_LIQ_TOKEN_ID\\r\\n            ) {\\r\\n                bool isCallPool = id == UNDERLYING_FREE_LIQ_TOKEN_ID;\\r\\n                uint256 minimum = _getMinimumAmount(l, isCallPool);\\r\\n\\r\\n                if (from != address(0)) {\\r\\n                    uint256 balance = _balanceOf(from, id);\\r\\n\\r\\n                    if (balance > minimum && balance <= amount + minimum) {\\r\\n                        require(\\r\\n                            balance -\\r\\n                                l.pendingDeposits[from][\\r\\n                                    l.nextDeposits[isCallPool].eta\\r\\n                                ][isCallPool] >=\\r\\n                                amount,\\r\\n                            \\\"Insuf balance\\\"\\r\\n                        );\\r\\n                        l.removeUnderwriter(from, isCallPool);\\r\\n                    }\\r\\n\\r\\n                    if (to != address(0)) {\\r\\n                        _subUserTVL(l, from, isCallPool, amounts[i]);\\r\\n                        _addUserTVL(l, to, isCallPool, amounts[i]);\\r\\n                    }\\r\\n                }\\r\\n\\r\\n                if (to != address(0)) {\\r\\n                    uint256 balance = _balanceOf(to, id);\\r\\n\\r\\n                    if (balance <= minimum && balance + amount > minimum) {\\r\\n                        l.addUnderwriter(to, isCallPool);\\r\\n                    }\\r\\n                }\\r\\n            }\\r\\n\\r\\n            // Update userTVL on SHORT options transfers\\r\\n            (\\r\\n                PoolStorage.TokenType tokenType,\\r\\n                ,\\r\\n                int128 strike64x64\\r\\n            ) = PoolStorage.parseTokenId(id);\\r\\n\\r\\n            if (\\r\\n                (from != address(0) && to != address(0)) &&\\r\\n                (tokenType == PoolStorage.TokenType.SHORT_CALL ||\\r\\n                    tokenType == PoolStorage.TokenType.SHORT_PUT)\\r\\n            ) {\\r\\n                bool isCall = tokenType == PoolStorage.TokenType.SHORT_CALL;\\r\\n                uint256 collateral = isCall\\r\\n                    ? amount\\r\\n                    : l.fromUnderlyingToBaseDecimals(strike64x64.mulu(amount));\\r\\n\\r\\n                _subUserTVL(l, from, isCall, collateral);\\r\\n                _addUserTVL(l, to, isCall, collateral);\\r\\n            }\\r\\n        }\\r\\n    }\\r\\n}\\r\\n\"},\"@solidstate/contracts/token/ERC1155/base/ERC1155BaseStorage.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.0;\\n\\nlibrary ERC1155BaseStorage {\\n    struct Layout {\\n        mapping(uint256 => mapping(address => uint256)) balances;\\n        mapping(address => mapping(address => bool)) operatorApprovals;\\n    }\\n\\n    bytes32 internal constant STORAGE_SLOT =\\n        keccak256('solidstate.contracts.storage.ERC1155Base');\\n\\n    function layout() internal pure returns (Layout storage l) {\\n        bytes32 slot = STORAGE_SLOT;\\n        assembly {\\n            l.slot := slot\\n        }\\n    }\\n}\\n\"},\"@solidstate/contracts/utils/EnumerableSet.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Set implementation with enumeration functions\\n * @dev derived from https://github.com/OpenZeppelin/openzeppelin-contracts (MIT license)\\n */\\nlibrary EnumerableSet {\\n    struct Set {\\n        bytes32[] _values;\\n        // 1-indexed to allow 0 to signify nonexistence\\n        mapping(bytes32 => uint256) _indexes;\\n    }\\n\\n    struct Bytes32Set {\\n        Set _inner;\\n    }\\n\\n    struct AddressSet {\\n        Set _inner;\\n    }\\n\\n    struct UintSet {\\n        Set _inner;\\n    }\\n\\n    function at(Bytes32Set storage set, uint256 index)\\n        internal\\n        view\\n        returns (bytes32)\\n    {\\n        return _at(set._inner, index);\\n    }\\n\\n    function at(AddressSet storage set, uint256 index)\\n        internal\\n        view\\n        returns (address)\\n    {\\n        return address(uint160(uint256(_at(set._inner, index))));\\n    }\\n\\n    function at(UintSet storage set, uint256 index)\\n        internal\\n        view\\n        returns (uint256)\\n    {\\n        return uint256(_at(set._inner, index));\\n    }\\n\\n    function contains(Bytes32Set storage set, bytes32 value)\\n        internal\\n        view\\n        returns (bool)\\n    {\\n        return _contains(set._inner, value);\\n    }\\n\\n    function contains(AddressSet storage set, address value)\\n        internal\\n        view\\n        returns (bool)\\n    {\\n        return _contains(set._inner, bytes32(uint256(uint160(value))));\\n    }\\n\\n    function contains(UintSet storage set, uint256 value)\\n        internal\\n        view\\n        returns (bool)\\n    {\\n        return _contains(set._inner, bytes32(value));\\n    }\\n\\n    function indexOf(Bytes32Set storage set, bytes32 value)\\n        internal\\n        view\\n        returns (uint256)\\n    {\\n        return _indexOf(set._inner, value);\\n    }\\n\\n    function indexOf(AddressSet storage set, address value)\\n        internal\\n        view\\n        returns (uint256)\\n    {\\n        return _indexOf(set._inner, bytes32(uint256(uint160(value))));\\n    }\\n\\n    function indexOf(UintSet storage set, uint256 value)\\n        internal\\n        view\\n        returns (uint256)\\n    {\\n        return _indexOf(set._inner, bytes32(value));\\n    }\\n\\n    function length(Bytes32Set storage set) internal view returns (uint256) {\\n        return _length(set._inner);\\n    }\\n\\n    function length(AddressSet storage set) internal view returns (uint256) {\\n        return _length(set._inner);\\n    }\\n\\n    function length(UintSet storage set) internal view returns (uint256) {\\n        return _length(set._inner);\\n    }\\n\\n    function add(Bytes32Set storage set, bytes32 value)\\n        internal\\n        returns (bool)\\n    {\\n        return _add(set._inner, value);\\n    }\\n\\n    function add(AddressSet storage set, address value)\\n        internal\\n        returns (bool)\\n    {\\n        return _add(set._inner, bytes32(uint256(uint160(value))));\\n    }\\n\\n    function add(UintSet storage set, uint256 value) internal returns (bool) {\\n        return _add(set._inner, bytes32(value));\\n    }\\n\\n    function remove(Bytes32Set storage set, bytes32 value)\\n        internal\\n        returns (bool)\\n    {\\n        return _remove(set._inner, value);\\n    }\\n\\n    function remove(AddressSet storage set, address value)\\n        internal\\n        returns (bool)\\n    {\\n        return _remove(set._inner, bytes32(uint256(uint160(value))));\\n    }\\n\\n    function remove(UintSet storage set, uint256 value)\\n        internal\\n        returns (bool)\\n    {\\n        return _remove(set._inner, bytes32(value));\\n    }\\n\\n    function _at(Set storage set, uint256 index)\\n        private\\n        view\\n        returns (bytes32)\\n    {\\n        require(\\n            set._values.length > index,\\n            'EnumerableSet: index out of bounds'\\n        );\\n        return set._values[index];\\n    }\\n\\n    function _contains(Set storage set, bytes32 value)\\n        private\\n        view\\n        returns (bool)\\n    {\\n        return set._indexes[value] != 0;\\n    }\\n\\n    function _indexOf(Set storage set, bytes32 value)\\n        private\\n        view\\n        returns (uint256)\\n    {\\n        unchecked {\\n            return set._indexes[value] - 1;\\n        }\\n    }\\n\\n    function _length(Set storage set) private view returns (uint256) {\\n        return set._values.length;\\n    }\\n\\n    function _add(Set storage set, bytes32 value) private returns (bool) {\\n        if (!_contains(set, value)) {\\n            set._values.push(value);\\n            set._indexes[value] = set._values.length;\\n            return true;\\n        } else {\\n            return false;\\n        }\\n    }\\n\\n    function _remove(Set storage set, bytes32 value) private returns (bool) {\\n        uint256 valueIndex = set._indexes[value];\\n\\n        if (valueIndex != 0) {\\n            uint256 index = valueIndex - 1;\\n            bytes32 last = set._values[set._values.length - 1];\\n\\n            // move last value to now-vacant index\\n\\n            set._values[index] = last;\\n            set._indexes[last] = index + 1;\\n\\n            // clear last index\\n\\n            set._values.pop();\\n            delete set._indexes[value];\\n\\n            return true;\\n        } else {\\n            return false;\\n        }\\n    }\\n}\\n\"},\"contracts/mining/PremiaMiningStorage.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\n// For further clarification please see https://license.premia.legal\\r\\n\\r\\npragma solidity ^0.8.0;\\r\\n\\r\\nlibrary PremiaMiningStorage {\\r\\n    bytes32 internal constant STORAGE_SLOT =\\r\\n        keccak256(\\\"premia.contracts.storage.PremiaMining\\\");\\r\\n\\r\\n    // Info of each pool.\\r\\n    struct PoolInfo {\\r\\n        uint256 allocPoint; // How many allocation points assigned to this pool. PREMIA to distribute per block.\\r\\n        uint256 lastRewardTimestamp; // Last timestamp that PREMIA distribution occurs\\r\\n        uint256 accPremiaPerShare; // Accumulated PREMIA per share, times 1e12. See below.\\r\\n    }\\r\\n\\r\\n    // Info of each user.\\r\\n    struct UserInfo {\\r\\n        uint256 reward; // Total allocated unclaimed reward\\r\\n        uint256 rewardDebt; // Reward debt. See explanation below.\\r\\n        //\\r\\n        // We do some fancy math here. Basically, any point in time, the amount of PREMIA\\r\\n        // entitled to a user but is pending to be distributed is:\\r\\n        //\\r\\n        //   pending reward = (user.amount * pool.accPremiaPerShare) - user.rewardDebt\\r\\n        //\\r\\n        // Whenever a user deposits or withdraws LP tokens to a pool. Here's what happens:\\r\\n        //   1. The pool's `accPremiaPerShare` (and `lastRewardBlock`) gets updated.\\r\\n        //   2. User receives the pending reward sent to his/her address.\\r\\n        //   3. User's `amount` gets updated.\\r\\n        //   4. User's `rewardDebt` gets updated.\\r\\n    }\\r\\n\\r\\n    struct Layout {\\r\\n        // Total PREMIA left to distribute\\r\\n        uint256 premiaAvailable;\\r\\n        // Amount of premia distributed per year\\r\\n        uint256 premiaPerYear;\\r\\n        // pool -> isCallPool -> PoolInfo\\r\\n        mapping(address => mapping(bool => PoolInfo)) poolInfo;\\r\\n        // pool -> isCallPool -> user -> UserInfo\\r\\n        mapping(address => mapping(bool => mapping(address => UserInfo))) userInfo;\\r\\n        // Total allocation points. Must be the sum of all allocation points in all pools.\\r\\n        uint256 totalAllocPoint;\\r\\n    }\\r\\n\\r\\n    function layout() internal pure returns (Layout storage l) {\\r\\n        bytes32 slot = STORAGE_SLOT;\\r\\n        assembly {\\r\\n            l.slot := slot\\r\\n        }\\r\\n    }\\r\\n}\\r\\n\"},\"@solidstate/contracts/utils/IWETH.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.0;\\n\\nimport { IERC20 } from '../token/ERC20/IERC20.sol';\\nimport { IERC20Metadata } from '../token/ERC20/metadata/IERC20Metadata.sol';\\n\\n/**\\n * @title WETH (Wrapped ETH) interface\\n */\\ninterface IWETH is IERC20, IERC20Metadata {\\n    /**\\n     * @notice convert ETH to WETH\\n     */\\n    function deposit() external payable;\\n\\n    /**\\n     * @notice convert WETH to ETH\\n     * @dev if caller is a contract, it should have a fallback or receive function\\n     * @param amount quantity of WETH to convert, denominated in wei\\n     */\\n    function withdraw(uint256 amount) external;\\n}\\n\"},\"@solidstate/contracts/token/ERC1155/IERC1155Internal.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.0;\\n\\nimport { IERC165 } from '../../introspection/IERC165.sol';\\n\\n/**\\n * @notice Partial ERC1155 interface needed by internal functions\\n */\\ninterface IERC1155Internal {\\n    event TransferSingle(\\n        address indexed operator,\\n        address indexed from,\\n        address indexed to,\\n        uint256 id,\\n        uint256 value\\n    );\\n\\n    event TransferBatch(\\n        address indexed operator,\\n        address indexed from,\\n        address indexed to,\\n        uint256[] ids,\\n        uint256[] values\\n    );\\n\\n    event ApprovalForAll(\\n        address indexed account,\\n        address indexed operator,\\n        bool approved\\n    );\\n}\\n\"},\"@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface AggregatorV3Interface {\\n\\n  function decimals()\\n    external\\n    view\\n    returns (\\n      uint8\\n    );\\n\\n  function description()\\n    external\\n    view\\n    returns (\\n      string memory\\n    );\\n\\n  function version()\\n    external\\n    view\\n    returns (\\n      uint256\\n    );\\n\\n  // getRoundData and latestRoundData should both raise \\\"No data present\\\"\\n  // if they do not have data to report, instead of returning unset values\\n  // which could be misinterpreted as actual reported values.\\n  function getRoundData(\\n    uint80 _roundId\\n  )\\n    external\\n    view\\n    returns (\\n      uint80 roundId,\\n      int256 answer,\\n      uint256 startedAt,\\n      uint256 updatedAt,\\n      uint80 answeredInRound\\n    );\\n\\n  function latestRoundData()\\n    external\\n    view\\n    returns (\\n      uint80 roundId,\\n      int256 answer,\\n      uint256 startedAt,\\n      uint256 updatedAt,\\n      uint80 answeredInRound\\n    );\\n\\n}\\n\"},\"@solidstate/contracts/access/OwnableStorage.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.0;\\n\\nlibrary OwnableStorage {\\n    struct Layout {\\n        address owner;\\n    }\\n\\n    bytes32 internal constant STORAGE_SLOT =\\n        keccak256('solidstate.contracts.storage.Ownable');\\n\\n    function layout() internal pure returns (Layout storage l) {\\n        bytes32 slot = STORAGE_SLOT;\\n        assembly {\\n            l.slot := slot\\n        }\\n    }\\n\\n    function setOwner(Layout storage l, address owner) internal {\\n        l.owner = owner;\\n    }\\n}\\n\"}},\"settings\":{\"optimizer\":{\"enabled\":true,\"runs\":200},\"outputSelection\":{\"*\":{\"*\":[\"evm.bytecode\",\"evm.deployedBytecode\",\"devdoc\",\"userdoc\",\"metadata\",\"abi\"]}},\"libraries\":{\"contracts/libraries/OptionMath.sol\":{\"OptionMath\":\"0x0f6e8ef18fb5bb61d545fee60f779d8aed60408f\"}}}},\"ABI\":\"[{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"ivolOracle\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"weth\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"premiaMining\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"feeReceiver\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"feeDiscountAddress\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"int128\\\",\\\"name\\\":\\\"fee64x64\\\",\\\"type\\\":\\\"int128\\\"}],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"constructor\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"shortTokenId\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"amount\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"Annihilate\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":true,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"account\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":true,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"operator\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"bool\\\",\\\"name\\\":\\\"approved\\\",\\\"type\\\":\\\"bool\\\"}],\\\"name\\\":\\\"ApprovalForAll\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":true,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"underwriter\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"shortTokenId\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"freedAmount\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"intervalContractSize\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"fee\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"AssignExercise\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":true,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"user\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"bool\\\",\\\"name\\\":\\\"isCallPool\\\",\\\"type\\\":\\\"bool\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"amount\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"Deposit\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":true,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"user\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"longTokenId\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"contractSize\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"exerciseValue\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"fee\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"Exercise\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":true,\\\"internalType\\\":\\\"bool\\\",\\\"name\\\":\\\"isCallPool\\\",\\\"type\\\":\\\"bool\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"amount\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"FeeWithdrawal\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":true,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"user\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"longTokenId\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"contractSize\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"baseCost\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"feeCost\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"int128\\\",\\\"name\\\":\\\"spot64x64\\\",\\\"type\\\":\\\"int128\\\"}],\\\"name\\\":\\\"Purchase\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":true,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"operator\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":true,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"from\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":true,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"to\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256[]\\\",\\\"name\\\":\\\"ids\\\",\\\"type\\\":\\\"uint256[]\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256[]\\\",\\\"name\\\":\\\"values\\\",\\\"type\\\":\\\"uint256[]\\\"}],\\\"name\\\":\\\"TransferBatch\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":true,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"operator\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":true,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"from\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":true,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"to\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"id\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"value\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"TransferSingle\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":true,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"underwriter\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":true,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"longReceiver\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"shortTokenId\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"intervalContractSize\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"intervalPremium\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"bool\\\",\\\"name\\\":\\\"isManualUnderwrite\\\",\\\"type\\\":\\\"bool\\\"}],\\\"name\\\":\\\"Underwrite\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":true,\\\"internalType\\\":\\\"bool\\\",\\\"name\\\":\\\"isCall\\\",\\\"type\\\":\\\"bool\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"int128\\\",\\\"name\\\":\\\"cLevel64x64\\\",\\\"type\\\":\\\"int128\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"int128\\\",\\\"name\\\":\\\"oldLiquidity64x64\\\",\\\"type\\\":\\\"int128\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"int128\\\",\\\"name\\\":\\\"newLiquidity64x64\\\",\\\"type\\\":\\\"int128\\\"}],\\\"name\\\":\\\"UpdateCLevel\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":false,\\\"internalType\\\":\\\"int128\\\",\\\"name\\\":\\\"steepness64x64\\\",\\\"type\\\":\\\"int128\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"bool\\\",\\\"name\\\":\\\"isCallPool\\\",\\\"type\\\":\\\"bool\\\"}],\\\"name\\\":\\\"UpdateSteepness\\\",\\\"type\\\":\\\"event\\\"},{\\\"anonymous\\\":false,\\\"inputs\\\":[{\\\"indexed\\\":true,\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"user\\\",\\\"type\\\":\\\"address\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"bool\\\",\\\"name\\\":\\\"isCallPool\\\",\\\"type\\\":\\\"bool\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"depositedAt\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"indexed\\\":false,\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"amount\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"Withdrawal\\\",\\\"type\\\":\\\"event\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"address\\\",\\\"name\\\":\\\"holder\\\",\\\"type\\\":\\\"address\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"longTokenId\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"contractSize\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"exerciseFrom\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"},{\\\"inputs\\\":[{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"longTokenId\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"internalType\\\":\\\"uint256\\\",\\\"name\\\":\\\"contractSize\\\",\\\"type\\\":\\\"uint256\\\"}],\\\"name\\\":\\\"processExpired\\\",\\\"outputs\\\":[],\\\"stateMutability\\\":\\\"nonpayable\\\",\\\"type\\\":\\\"function\\\"}]\",\"ContractName\":\"PoolExercise\",\"CompilerVersion\":\"v0.8.9+commit.e5eed63a\",\"OptimizationUsed\":1,\"Runs\":200,\"ConstructorArguments\":\"0x0000000000000000000000003a87bb29b984d672664aa1dd2d19d2e8b24f0f2a000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000009abb27581c2e46a114f8c367355851e0580e9703000000000000000000000000c4b2c51f969e0713e799de73b7f130fb7bb604cf000000000000000000000000f1bb87563a122211d40d393ebf1c633c330377f900000000000000000000000000000000000000000000000007ae147ae147ae14\",\"EVMVersion\":\"Default\",\"Library\":\"\",\"LicenseType\":\"\",\"Proxy\":0,\"SwarmSource\":\"\"}]"
  },
  {
    "path": "testdata/fixtures/Derive/mnemonic_chinese_simplified.txt",
    "content": "谐 谐 谐 谐 谐 谐 谐 谐 谐 谐 谐 宗"
  },
  {
    "path": "testdata/fixtures/Derive/mnemonic_chinese_traditional.txt",
    "content": "諧 諧 諧 諧 諧 諧 諧 諧 諧 諧 諧 宗"
  },
  {
    "path": "testdata/fixtures/Derive/mnemonic_czech.txt",
    "content": "uzenina uzenina uzenina uzenina uzenina uzenina uzenina uzenina uzenina uzenina uzenina nevina"
  },
  {
    "path": "testdata/fixtures/Derive/mnemonic_english.txt",
    "content": "test test test test test test test test test test test junk"
  },
  {
    "path": "testdata/fixtures/Derive/mnemonic_french.txt",
    "content": "sonde sonde sonde sonde sonde sonde sonde sonde sonde sonde sonde hématome"
  },
  {
    "path": "testdata/fixtures/Derive/mnemonic_italian.txt",
    "content": "surgelato surgelato surgelato surgelato surgelato surgelato surgelato surgelato surgelato surgelato surgelato mansarda"
  },
  {
    "path": "testdata/fixtures/Derive/mnemonic_japanese.txt",
    "content": "ほんけ ほんけ ほんけ ほんけ ほんけ ほんけ ほんけ ほんけ ほんけ ほんけ ほんけ ぜんご"
  },
  {
    "path": "testdata/fixtures/Derive/mnemonic_korean.txt",
    "content": "큰어머니 큰어머니 큰어머니 큰어머니 큰어머니 큰어머니 큰어머니 큰어머니 큰어머니 큰어머니 큰어머니 시스템"
  },
  {
    "path": "testdata/fixtures/Derive/mnemonic_portuguese.txt",
    "content": "sobra sobra sobra sobra sobra sobra sobra sobra sobra sobra sobra guarani"
  },
  {
    "path": "testdata/fixtures/Derive/mnemonic_spanish.txt",
    "content": "tacto tacto tacto tacto tacto tacto tacto tacto tacto tacto tacto lacra"
  },
  {
    "path": "testdata/fixtures/Dir/depth1",
    "content": "Wow! 😀"
  },
  {
    "path": "testdata/fixtures/Dir/nested/depth2",
    "content": ""
  },
  {
    "path": "testdata/fixtures/Dir/nested/nested2/depth3",
    "content": ""
  },
  {
    "path": "testdata/fixtures/File/ignored/.gitignore",
    "content": ".\n"
  },
  {
    "path": "testdata/fixtures/File/read.txt",
    "content": "hello readable world\nthis is the second line!"
  },
  {
    "path": "testdata/fixtures/GetCode/HardhatWorkingContract.json",
    "content": "{\n  \"_format\": \"hh-sol-artifact-1\",\n  \"contractName\": \"WorkingContract\",\n  \"sourceName\": \"contracts/WorkingContract.sol\",\n  \"abi\": [\n    {\n      \"inputs\": [],\n      \"name\": \"secret\",\n      \"outputs\": [\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"stateMutability\": \"view\",\n      \"type\": \"function\"\n    }\n  ],\n  \"bytecode\": \"0x608060405234801561001057600080fd5b5060b28061001f6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063d1efd30d14602d575b600080fd5b60336047565b604051603e91906059565b60405180910390f35b602a81565b6053816072565b82525050565b6000602082019050606c6000830184604c565b92915050565b600081905091905056fea26469706673582212202a44b7c3c3e248a5736aa9345986f7114ee9e00d36ea034566db99648a17870564736f6c63430008040033\",\n  \"deployedBytecode\": \"0x6080604052348015600f57600080fd5b506004361060285760003560e01c8063d1efd30d14602d575b600080fd5b60336047565b604051603e91906059565b60405180910390f35b602a81565b6053816072565b82525050565b6000602082019050606c6000830184604c565b92915050565b600081905091905056fea26469706673582212202a44b7c3c3e248a5736aa9345986f7114ee9e00d36ea034566db99648a17870564736f6c63430008040033\",\n  \"linkReferences\": {},\n  \"deployedLinkReferences\": {}\n}\n"
  },
  {
    "path": "testdata/fixtures/GetCode/HuffWorkingContract.json",
    "content": "{\n    \"file\": {\n      \"path\": \"src/WorkingContract.huff\"\n    },\n    \"bytecode\": \"602d8060093d393df33d3560e01c63d1efd30d14610012573d3dfd5b6f656d6f2e6574682077757a206865726560801b3d523d6020f3\",\n    \"runtime\": \"3d3560e01c63d1efd30d14610012573d3dfd5b6f656d6f2e6574682077757a206865726560801b3d523d6020f3\",\n    \"abi\": {\n      \"constructor\": null,\n      \"functions\": {\n        \"secret\": {\n          \"name\": \"secret\",\n          \"inputs\": [],\n          \"outputs\": [\n            {\n              \"name\": \"\",\n              \"kind\": {\n                \"Uint\": 256\n              },\n              \"internal_type\": null\n            }\n          ],\n          \"constant\": false,\n          \"state_mutability\": \"View\"\n        }\n      },\n      \"events\": {},\n      \"errors\": {},\n      \"receive\": false,\n      \"fallback\": false\n    }\n  }\n  "
  },
  {
    "path": "testdata/fixtures/GetCode/Override.json",
    "content": "{\n  \"bytecode\": {\n    \"object\": \"0x608060405234801561001057600080fd5b506101a4806100206000396000f3fe60806040526004361061001e5760003560e01c806340e04f5e14610023575b600080fd5b610036610031366004610091565b610048565b60405190815260200160405180910390f35b60007fda9986ad4da7abb3f55b2d1f2009ab6ee50c5ad054092c04464c112acc4bc1103385858560405161007f9493929190610122565b60405180910390a15060009392505050565b6000806000604084860312156100a657600080fd5b83356001600160a01b03811681146100bd57600080fd5b9250602084013567ffffffffffffffff808211156100da57600080fd5b818601915086601f8301126100ee57600080fd5b8135818111156100fd57600080fd5b87602082850101111561010f57600080fd5b6020830194508093505050509250925092565b6001600160a01b0385811682528416602082015260606040820181905281018290526000828460808401376000608084840101526080601f19601f85011683010190509594505050505056fea26469706673582212202b0ba0fa4073d6f681bb1f99f0529e44583f2dc612a629f3ff0564eaa7257d1f64736f6c63430008110033\",\n    \"sourceMap\": \"65:263:0:-:0;;;;;;;;;;;;;;;;;;;\",\n    \"linkReferences\": {}\n  },\n  \"deployedBytecode\": {\n    \"object\": \"0x60806040526004361061001e5760003560e01c806340e04f5e14610023575b600080fd5b610036610031366004610091565b610048565b60405190815260200160405180910390f35b60007fda9986ad4da7abb3f55b2d1f2009ab6ee50c5ad054092c04464c112acc4bc1103385858560405161007f9493929190610122565b60405180910390a15060009392505050565b6000806000604084860312156100a657600080fd5b83356001600160a01b03811681146100bd57600080fd5b9250602084013567ffffffffffffffff808211156100da57600080fd5b818601915086601f8301126100ee57600080fd5b8135818111156100fd57600080fd5b87602082850101111561010f57600080fd5b6020830194508093505050509250925092565b6001600160a01b0385811682528416602082015260606040820181905281018290526000828460808401376000608084840101526080601f19601f85011683010190509594505050505056fea26469706673582212202b0ba0fa4073d6f681bb1f99f0529e44583f2dc612a629f3ff0564eaa7257d1f64736f6c63430008110033\",\n    \"sourceMap\": \"65:263:0:-:0;;;;;;;;;;;;;;;;;;;;;154:172;;;;;;:::i;:::-;;:::i;:::-;;;930:25:1;;;918:2;903:18;154:172:0;;;;;;;;241:7;265:36;273:10;285:6;293:7;;265:36;;;;;;;;;:::i;:::-;;;;;;;;-1:-1:-1;318:1:0;154:172;;;;;:::o;14:765:1:-;93:6;101;109;162:2;150:9;141:7;137:23;133:32;130:52;;;178:1;175;168:12;130:52;204:23;;-1:-1:-1;;;;;256:31:1;;246:42;;236:70;;302:1;299;292:12;236:70;325:5;-1:-1:-1;381:2:1;366:18;;353:32;404:18;434:14;;;431:34;;;461:1;458;451:12;431:34;499:6;488:9;484:22;474:32;;544:7;537:4;533:2;529:13;525:27;515:55;;566:1;563;556:12;515:55;606:2;593:16;632:2;624:6;621:14;618:34;;;648:1;645;638:12;618:34;693:7;688:2;679:6;675:2;671:15;667:24;664:37;661:57;;;714:1;711;704:12;661:57;745:2;741;737:11;727:21;;767:6;757:16;;;;;14:765;;;;;:::o;966:589::-;-1:-1:-1;;;;;1217:15:1;;;1199:34;;1269:15;;1264:2;1249:18;;1242:43;1321:2;1316;1301:18;;1294:30;;;1340:18;;1333:34;;;1142:4;1360:6;1410;1404:3;1389:19;;1376:49;1475:1;1469:3;1460:6;1449:9;1445:22;1441:32;1434:43;1545:3;1538:2;1534:7;1529:2;1521:6;1517:15;1513:29;1502:9;1498:45;1494:55;1486:63;;966:589;;;;;;;:::o\",\n    \"linkReferences\": {}\n  }\n}"
  },
  {
    "path": "testdata/fixtures/GetCode/Override.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.13;\n\ncontract Override {\n    event Payload(address sender, address target, bytes data);\n\n    function emitPayload(address target, bytes calldata message) external payable returns (uint256) {\n        emit Payload(msg.sender, target, message);\n        return 0;\n    }\n}\n"
  },
  {
    "path": "testdata/fixtures/GetCode/UnlinkedContract.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nlibrary SmolLibrary {\n    function add(uint256 a, uint256 b) public pure returns (uint256 c) {\n        c = a + b;\n    }\n}\n\ncontract UnlinkedContract {\n    function complicated(uint256 a, uint256 b, uint256 c) public pure returns (uint256 d) {\n        d = SmolLibrary.add(SmolLibrary.add(a, b), c);\n    }\n}\n"
  },
  {
    "path": "testdata/fixtures/GetCode/WorkingContract.json",
    "content": "{\n  \"abi\": [\n    {\n      \"inputs\": [],\n      \"name\": \"secret\",\n      \"outputs\": [\n        {\n          \"internalType\": \"uint256\",\n          \"name\": \"\",\n          \"type\": \"uint256\"\n        }\n      ],\n      \"stateMutability\": \"view\",\n      \"type\": \"function\"\n    }\n  ],\n  \"bytecode\": {\n    \"object\": \"0x6080604052348015600f57600080fd5b50607c8061001e6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063d1efd30d14602d575b600080fd5b6034602a81565b60405190815260200160405180910390f3fea26469706673582212206740fcc626175d58a151da7fbfca1775ea4d3ababf7f3168347dab89488f6a4264736f6c634300080a0033\",\n    \"sourceMap\": \"64:69:28:-:0;;;;;;;;;;;;;;;;;;;\",\n    \"linkReferences\": {}\n  },\n  \"deployedBytecode\": {\n    \"object\": \"0x6080604052348015600f57600080fd5b506004361060285760003560e01c8063d1efd30d14602d575b600080fd5b6034602a81565b60405190815260200160405180910390f3fea26469706673582212206740fcc626175d58a151da7fbfca1775ea4d3ababf7f3168347dab89488f6a4264736f6c634300080a0033\",\n    \"sourceMap\": \"64:69:28:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;95:35;;128:2;95:35;;;;;160:25:35;;;148:2;133:18;95:35:28;;;;;;\",\n    \"linkReferences\": {}\n  }\n}\n"
  },
  {
    "path": "testdata/fixtures/GetCode/WorkingContract.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\ncontract WorkingContract {\n    uint256 public constant secret = 42;\n}\n"
  },
  {
    "path": "testdata/fixtures/Json/Issue4402.json",
    "content": "{\n  \"tokens\": [\"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\"],\n  \"empty\": []\n}"
  },
  {
    "path": "testdata/fixtures/Json/Issue4630.json",
    "content": "{\n  \"local\": {\n    \"prop1\": 10\n  },\n  \"localempty\": {\n  }\n}\n"
  },
  {
    "path": "testdata/fixtures/Json/nested_json_struct.json",
    "content": "{\n    \"members\": [\n        {\n            \"a\": 100,\n            \"arr\": [\n                [\n                    1,\n                    -2,\n                    -5\n                ],\n                [\n                    1000,\n                    2000,\n                    0\n                ]\n            ],\n            \"str\": \"some string\",\n            \"b\": \"0x\",\n            \"addr\": \"0x0000000000000000000000000000000000000000\",\n            \"fixedBytes\": \"0x8ae3fc6bd1b150a73ec4afe3ef136fa2f88e9c96131c883c5e4a4714811c1598\"\n        },\n        {\n            \"a\": 200,\n            \"arr\": [],\n            \"str\": \"some other string\",\n            \"b\": \"0x0000000000000000000000000000000000000000\",\n            \"addr\": \"0x167D91deaEEE3021161502873d3bcc6291081648\",\n            \"fixedBytes\": \"0xed1c7beb1f00feaaaec5636950d6edb25a8d4fedc8deb2711287b64c4d27719d\"\n        }\n    ],\n    \"inner\": {\n        \"fixedBytes\": \"0x12345678\"\n    },\n    \"name\": \"test\"\n}"
  },
  {
    "path": "testdata/fixtures/Json/test.json",
    "content": "{\n  \"basicString\": \"hai\",\n  \"null\": null,\n  \"stringArray\": [\"hai\", \"there\"],\n  \"address\": \"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266\",\n  \"addressArray\": [\n    \"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266\",\n    \"0x7109709ECfa91a80626fF3989D68f67F5b1DD12D\"\n  ],\n  \"H160NotAddress\": \"0000000000000000000000000000000000001337\",\n  \"boolTrue\": true,\n  \"boolFalse\": false,\n  \"boolArray\": [true, false],\n  \"boolString\": \"true\",\n  \"boolStringArray\": [true, \"false\"],\n  \"uintNumber\": 115792089237316195423570985008687907853269984665640564039457584007913129639935,\n  \"uintString\": \"115792089237316195423570985008687907853269984665640564039457584007913129639935\",\n  \"uintHex\": \"0x12C980\",\n  \"uintArray\": [42, 43],\n  \"uintStringArray\": [1231232, \"0x12C980\", \"1231232\"],\n  \"intNumber\": -12,\n  \"intString\": \"-12\",\n  \"intHex\": \"-0xC\",\n  \"bytesString\": \"0x01\",\n  \"bytesStringArray\": [\"0x01\", \"0x02\"],\n  \"nestedObject\": {\n    \"number\": 115792089237316195423570985008687907853269984665640564039457584007913129639935,\n    \"str\": \"NEST\"\n  },\n  \"advancedJsonPath\": [{ \"id\": 1 }, { \"id\": 2 }]\n}\n"
  },
  {
    "path": "testdata/fixtures/Json/test_allocs.json",
    "content": "{\n  \"0x0000000000000000000000000000000000000420\": {\n    \"balance\": \"0xabcd\",\n    \"code\": \"0x604260005260206000F3\",\n    \"storage\": {\n      \"0x1000000000000000000000000000000000000000000000000000000000000000\": \"0x000000000000000000000000000000000000000000000000000000000000beef\"\n    }\n  },\n  \"0x0000000000000000000000000000000000000421\": {\n    \"balance\": \"0x0\",\n    \"storage\": {\n      \"0x1000000000000000000000000000000000000000000000000000000000000000\": \"0x000000000000000000000000000000000000000000000000000000000000beef\"\n    }\n  }\n}\n"
  },
  {
    "path": "testdata/fixtures/Json/whole_json.json",
    "content": "{\n  \"str\": \"hai\",\n  \"uintArray\": [42, 43],\n  \"strArray\": [\"hai\", \"there\"]\n}\n"
  },
  {
    "path": "testdata/fixtures/Json/write_complex_test.json",
    "content": "{\n  \"a\": 123,\n  \"b\": \"test\",\n  \"c\": {\n    \"a\": 123,\n    \"b\": \"test\"\n  }\n}"
  },
  {
    "path": "testdata/fixtures/Json/write_test.json",
    "content": "{\n  \"a\": 123,\n  \"b\": \"0x000000000000000000000000000000000000bEEF\"\n}"
  },
  {
    "path": "testdata/fixtures/Rpc/README.md",
    "content": "# Fixture Generation Instructions\n\n### `eth_getLogs.json`\n\nTo generate this fixture, send a POST request to a Eth Mainnet (chainId = 1) RPC\n\n```\n{\n    \"jsonrpc\": \"2.0\",\n    \"method\": \"eth_getLogs\",\n    \"id\": \"1\",\n    \"params\": [\n        {\n            \"address\": \"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2\",\n            \"fromBlock\": \"0x10CEB1B\",\n            \"toBlock\": \"0x10CEB1B\",\n            \"topics\": [\n                \"0x7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65\"\n            ]\n        }\n    ]\n}\n```\n\nThen you must change the `address` key to `emitter` because in Solidity, a struct's name cannot be `address` as that is a keyword.\n"
  },
  {
    "path": "testdata/fixtures/Rpc/balance_params.json",
    "content": "[\"0x8D97689C9818892B700e27F316cc3E41e17fBeb9\", \"0x117BC09\"]"
  },
  {
    "path": "testdata/fixtures/Rpc/eth_getLogs.json",
    "content": "[\n    {\n        \"emitter\": \"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2\",\n        \"topics\": [\n            \"0x7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65\",\n            \"0x0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d\"\n        ],\n        \"data\": \"0x0000000000000000000000000000000000000000000000000186faccfe3e2bcc\",\n        \"blockNumber\": \"0x10ceb1b\",\n        \"transactionHash\": \"0xa08f7b4aaa57cb2baec601ad96878d227ae3289a8dd48df98cce30c168588ce7\",\n        \"transactionIndex\": \"0xc\",\n        \"blockHash\": \"0xe4299c95a140ddad351e9831cfb16c35cc0014e8cbd8465de2e5112847d70465\",\n        \"logIndex\": \"0x42\",\n        \"removed\": false\n    },\n    {\n        \"emitter\": \"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2\",\n        \"topics\": [\n            \"0x7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65\",\n            \"0x0000000000000000000000002ec705d306b51e486b1bc0d6ebee708e0661add1\"\n        ],\n        \"data\": \"0x000000000000000000000000000000000000000000000000004befaedcfaea00\",\n        \"blockNumber\": \"0x10ceb1b\",\n        \"transactionHash\": \"0x2cd5355bd917ec5c28194735ad539a4cb58e4b08815a038f6e2373290caeee1d\",\n        \"transactionIndex\": \"0x11\",\n        \"blockHash\": \"0xe4299c95a140ddad351e9831cfb16c35cc0014e8cbd8465de2e5112847d70465\",\n        \"logIndex\": \"0x56\",\n        \"removed\": false\n    },\n    {\n        \"emitter\": \"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2\",\n        \"topics\": [\n            \"0x7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65\",\n            \"0x0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d\"\n        ],\n        \"data\": \"0x000000000000000000000000000000000000000000000000003432a29cd0ed22\",\n        \"blockNumber\": \"0x10ceb1b\",\n        \"transactionHash\": \"0x4e762d9a572084e0ec412ddf6c4e6d0b746b10e9714d4e786c13579e2e3c3187\",\n        \"transactionIndex\": \"0x16\",\n        \"blockHash\": \"0xe4299c95a140ddad351e9831cfb16c35cc0014e8cbd8465de2e5112847d70465\",\n        \"logIndex\": \"0x68\",\n        \"removed\": false\n    }\n]"
  },
  {
    "path": "testdata/fixtures/Toml/Issue4402.toml",
    "content": "tokens = [\"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\"]\nempty = []\n"
  },
  {
    "path": "testdata/fixtures/Toml/nested_toml_struct.toml",
    "content": "name = \"test\"\n\n[[members]]\na = 100\narr = [\n    [1, -2, -5],\n    [1000, 2000, 0]\n]\nstr = \"some string\"\nb = \"0x\"\naddr = \"0x0000000000000000000000000000000000000000\"\nfixedBytes = \"0x8ae3fc6bd1b150a73ec4afe3ef136fa2f88e9c96131c883c5e4a4714811c1598\"\n\n[[members]]\na = 200\narr = []\nstr = \"some other string\"\nb = \"0x0000000000000000000000000000000000000000\"\naddr = \"0x167D91deaEEE3021161502873d3bcc6291081648\"\nfixedBytes = \"0xed1c7beb1f00feaaaec5636950d6edb25a8d4fedc8deb2711287b64c4d27719d\"\n\n[inner]\nfixedBytes = \"0x12345678\"\n"
  },
  {
    "path": "testdata/fixtures/Toml/test.toml",
    "content": "nanFloat = nan\ninfFloat = +inf\nneginfFloat = -inf\n\nbasicString = \"hai\"\nnullString = \"null\"\nmultilineString = \"\"\"\nhai\nthere\n\"\"\"\nstringArray = [\"hai\", \"there\"]\n\naddress = \"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266\"\naddressArray = [\n    \"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266\",\n    \"0x7109709ECfa91a80626fF3989D68f67F5b1DD12D\",\n]\nH160NotAddress = \"0000000000000000000000000000000000001337\"\n\nboolTrue = true\nboolFalse = false\nboolArray = [true, false]\nboolString = \"true\"\nboolStringArray = [\"true\", \"false\"] # Array values can't have mixed types\n\ndatetime = 2021-08-10T14:48:00Z\ndatetimeArray = [2021-08-10T14:48:00Z, 2021-08-10T14:48:00Z]\n\nuintNumber = 9223372036854775807 # TOML is limited to 64-bit integers\nuintString = \"115792089237316195423570985008687907853269984665640564039457584007913129639935\"\nuintHex = \"0x12C980\"\nuintArray = [42, 43]\nuintStringArray = [\n    \"1231232\",\n    \"0x12C980\",\n    \"1231232\",\n] # Array values can't have mixed types\n\nintNumber = -12\nintString = \"-12\"\nintHex = \"-0xC\"\n\nbytesString = \"0x01\"\nbytesStringArray = [\"0x01\", \"0x02\"]\n\n[nestedObject]\nnumber = 9223372036854775807 # TOML is limited to 64-bit integers\nstr = \"NEST\"\n\n[[advancedTomlPath]]\nid = 1\n\n[[advancedTomlPath]]\nid = 2\n\n\n"
  },
  {
    "path": "testdata/fixtures/Toml/whole_toml.toml",
    "content": "str = \"hai\"\nuintArray = [42, 43]\nstrArray = [\"hai\", \"there\"]\n"
  },
  {
    "path": "testdata/fixtures/Toml/write_complex_test.toml",
    "content": "a = 123\nb = \"test\"\n\n[c]\na = 123\nb = \"test\"\n"
  },
  {
    "path": "testdata/fixtures/Toml/write_test.toml",
    "content": "a = 123\nb = \"0x000000000000000000000000000000000000bEEF\"\n"
  },
  {
    "path": "testdata/fixtures/broadcast.log.json",
    "content": "{\n  \"transactions\": [\n    {\n      \"hash\": \"0x1e96239f222cb37343e403f10d1fba3c1e6da307d536d81c798c776a7eedf29a\",\n      \"transactionType\": \"CREATE\",\n      \"contractName\": null,\n      \"contractAddress\": \"0x5FbDB2315678afecb367f032d93F642f64180aa3\",\n      \"function\": null,\n      \"arguments\": null,\n      \"transaction\": {\n        \"type\": \"0x02\",\n        \"from\": \"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266\",\n        \"gas\": \"0x19efe\",\n        \"data\": \"0x6082610038600b82828239805160001a607314602b57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe730000000000000000000000000000000000000000301460806040526004361060335760003560e01c8063baf2f868146038575b600080fd5b600160405190815260200160405180910390f3fea26469706673582212201a010366ffe2b32bf2336555e3279be3d2b70bb4dac5f73512e68b0f2aa4abd464736f6c63430008130033\",\n        \"nonce\": \"0x0\",\n        \"accessList\": []\n      },\n      \"additionalContracts\": [],\n      \"isFixedGasLimit\": false\n    },\n    {\n      \"hash\": \"0x585a60fdff43ed25c0602c005f4ec893596ff8f8ecc384f354386a3a94b027ea\",\n      \"transactionType\": \"CREATE\",\n      \"contractName\": \"Test\",\n      \"contractAddress\": \"0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512\",\n      \"function\": null,\n      \"arguments\": null,\n      \"transaction\": {\n        \"type\": \"0x02\",\n        \"from\": \"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266\",\n        \"gas\": \"0x7a043\",\n        \"value\": \"0x0\",\n        \"data\": \"0x60806040526000805460ff1916600190811782555534801561002057600080fd5b5061058d806100306000396000f3fe608060405234801561001057600080fd5b50600436106100885760003560e01c8063afe29f711161005b578063afe29f71146100d6578063ba414fa6146100e9578063f6e62afc14610101578063fa7626d41461011357600080fd5b80630d3a6aee1461008d5780631e91f8cb146100a957806323e99187146100b7578063371303c0146100ce575b600080fd5b61009660015481565b6040519081526020015b60405180910390f35b6040513381526020016100a0565b6100966100c536600461036c565b60009392505050565b610096610120565b6100966100e4366004610454565b61013e565b6100f161022b565b60405190151581526020016100a0565b6000546100f190610100900460ff1681565b6000546100f19060ff1681565b600060018060008282546101349190610483565b9250508190555090565b600080805b838110156101d657735fbdb2315678afecb367f032d93f642f64180aa363baf2f8686040518163ffffffff1660e01b8152600401602060405180830381865af4158015610194573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101b8919061049c565b6101c29083610483565b9150806101ce816104b5565b915050610143565b507f0b2e13ff20ac7b474198655583edf70dedd2c1dc980e329c4fbb2fc0748b796b60405161021d906020808252600490820152636865726560e01b604082015260600190565b60405180910390a192915050565b60008054610100900460ff161561024b5750600054610100900460ff1690565b6000737109709ecfa91a80626ff3989d68f67f5b1dd12d3b156103515760408051737109709ecfa91a80626ff3989d68f67f5b1dd12d602082018190526519985a5b195960d21b828401528251808303840181526060830190935260009290916102d9917f667f9d70ca411d70ead50d8d5c22070dafc36ad75f3dcf5e7237b22ade9aecc4916080016104fe565b60408051601f19818403018152908290526102f391610522565b6000604051808303816000865af19150503d8060008114610330576040519150601f19603f3d011682016040523d82523d6000602084013e610335565b606091505b509150508080602001905181019061034d9190610535565b9150505b919050565b634e487b7160e01b600052604160045260246000fd5b60008060006060848603121561038157600080fd5b833592506020808501356001600160a01b03811681146103a057600080fd5b9250604085013567ffffffffffffffff808211156103bd57600080fd5b818701915087601f8301126103d157600080fd5b8135818111156103e3576103e3610356565b8060051b604051601f19603f8301168101818110858211171561040857610408610356565b60405291825284820192508381018501918a83111561042657600080fd5b938501935b828510156104445784358452938501939285019261042b565b8096505050505050509250925092565b60006020828403121561046657600080fd5b5035919050565b634e487b7160e01b600052601160045260246000fd5b808201808211156104965761049661046d565b92915050565b6000602082840312156104ae57600080fd5b5051919050565b6000600182016104c7576104c761046d565b5060010190565b6000815160005b818110156104ef57602081850181015186830152016104d5565b50600093019283525090919050565b6001600160e01b031983168152600061051a60048301846104ce565b949350505050565b600061052e82846104ce565b9392505050565b60006020828403121561054757600080fd5b8151801515811461052e57600080fdfea2646970667358221220b97e9a7f6f57b8eec57cf4a4b99912e375b000ed1db9c39554338fbc24e0238164736f6c63430008130033\",\n        \"nonce\": \"0x1\",\n        \"accessList\": []\n      },\n      \"additionalContracts\": [],\n      \"isFixedGasLimit\": false\n    },\n    {\n      \"hash\": \"0x58480c8e39cb861ec12c7e8c95def65920a757be223852e8d08f32b472cfe512\",\n      \"transactionType\": \"CALL\",\n      \"contractName\": \"Test\",\n      \"contractAddress\": \"0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512\",\n      \"function\": \"t(uint256):(uint256)\",\n      \"arguments\": [\n        \"2\"\n      ],\n      \"transaction\": {\n        \"type\": \"0x02\",\n        \"from\": \"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266\",\n        \"to\": \"0xe7f1725e7734ce288f8367e1bb143e90bb3f0512\",\n        \"gas\": \"0x915c\",\n        \"value\": \"0x0\",\n        \"data\": \"0xafe29f710000000000000000000000000000000000000000000000000000000000000002\",\n        \"nonce\": \"0x2\",\n        \"accessList\": []\n      },\n      \"additionalContracts\": [],\n      \"isFixedGasLimit\": false\n    },\n    {\n      \"hash\": \"0xf1376c34ccb8e1a5caa05442dc6c281f5622157aa0a204636354131914a15d5d\",\n      \"transactionType\": \"CREATE\",\n      \"contractName\": \"NoLink\",\n      \"contractAddress\": \"0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9\",\n      \"function\": null,\n      \"arguments\": null,\n      \"transaction\": {\n        \"type\": \"0x02\",\n        \"from\": \"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266\",\n        \"gas\": \"0x562c8\",\n        \"value\": \"0x0\",\n        \"data\": \"0x60806040526000805460ff1916600117905534801561001d57600080fd5b5061038c8061002d6000396000f3fe608060405234801561001057600080fd5b50600436106100575760003560e01c8063afe29f711461005c578063ba414fa614610082578063bc47b4a31461009a578063f6e62afc146100a2578063fa7626d4146100b4575b600080fd5b61006f61006a36600461026c565b6100c1565b6040519081526020015b60405180910390f35b61008a610141565b6040519015158152602001610079565b61053961006f565b60005461008a90610100900460ff1681565b60005461008a9060ff1681565b600080805b838110156100ec576100d8818361029b565b9150806100e4816102b4565b9150506100c6565b507f0b2e13ff20ac7b474198655583edf70dedd2c1dc980e329c4fbb2fc0748b796b604051610133906020808252600490820152636865726560e01b604082015260600190565b60405180910390a192915050565b60008054610100900460ff16156101615750600054610100900460ff1690565b6000737109709ecfa91a80626ff3989d68f67f5b1dd12d3b156102675760408051737109709ecfa91a80626ff3989d68f67f5b1dd12d602082018190526519985a5b195960d21b828401528251808303840181526060830190935260009290916101ef917f667f9d70ca411d70ead50d8d5c22070dafc36ad75f3dcf5e7237b22ade9aecc4916080016102fd565b60408051601f198184030181529082905261020991610321565b6000604051808303816000865af19150503d8060008114610246576040519150601f19603f3d011682016040523d82523d6000602084013e61024b565b606091505b50915050808060200190518101906102639190610334565b9150505b919050565b60006020828403121561027e57600080fd5b5035919050565b634e487b7160e01b600052601160045260246000fd5b808201808211156102ae576102ae610285565b92915050565b6000600182016102c6576102c6610285565b5060010190565b6000815160005b818110156102ee57602081850181015186830152016102d4565b50600093019283525090919050565b6001600160e01b031983168152600061031960048301846102cd565b949350505050565b600061032d82846102cd565b9392505050565b60006020828403121561034657600080fd5b8151801515811461032d57600080fdfea264697066735822122058e562bb01400d526afd803cd6afca170e53e3e8d7da8d3e0f6a272d77e0338364736f6c63430008130033\",\n        \"nonce\": \"0x3\",\n        \"accessList\": []\n      },\n      \"additionalContracts\": [],\n      \"isFixedGasLimit\": false\n    },\n    {\n      \"hash\": \"0x1572d2b255c59012349c56a71ec059c8f04d094c47cd1cfd7f62febe714e87e9\",\n      \"transactionType\": \"CREATE\",\n      \"contractName\": \"Test\",\n      \"contractAddress\": \"0xDc64a140Aa3E981100a9becA4E685f962f0cF6C9\",\n      \"function\": null,\n      \"arguments\": null,\n      \"transaction\": {\n        \"type\": \"0x02\",\n        \"from\": \"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266\",\n        \"gas\": \"0x7a043\",\n        \"value\": \"0x0\",\n        \"data\": \"0x60806040526000805460ff1916600190811782555534801561002057600080fd5b5061058d806100306000396000f3fe608060405234801561001057600080fd5b50600436106100885760003560e01c8063afe29f711161005b578063afe29f71146100d6578063ba414fa6146100e9578063f6e62afc14610101578063fa7626d41461011357600080fd5b80630d3a6aee1461008d5780631e91f8cb146100a957806323e99187146100b7578063371303c0146100ce575b600080fd5b61009660015481565b6040519081526020015b60405180910390f35b6040513381526020016100a0565b6100966100c536600461036c565b60009392505050565b610096610120565b6100966100e4366004610454565b61013e565b6100f161022b565b60405190151581526020016100a0565b6000546100f190610100900460ff1681565b6000546100f19060ff1681565b600060018060008282546101349190610483565b9250508190555090565b600080805b838110156101d657735fbdb2315678afecb367f032d93f642f64180aa363baf2f8686040518163ffffffff1660e01b8152600401602060405180830381865af4158015610194573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101b8919061049c565b6101c29083610483565b9150806101ce816104b5565b915050610143565b507f0b2e13ff20ac7b474198655583edf70dedd2c1dc980e329c4fbb2fc0748b796b60405161021d906020808252600490820152636865726560e01b604082015260600190565b60405180910390a192915050565b60008054610100900460ff161561024b5750600054610100900460ff1690565b6000737109709ecfa91a80626ff3989d68f67f5b1dd12d3b156103515760408051737109709ecfa91a80626ff3989d68f67f5b1dd12d602082018190526519985a5b195960d21b828401528251808303840181526060830190935260009290916102d9917f667f9d70ca411d70ead50d8d5c22070dafc36ad75f3dcf5e7237b22ade9aecc4916080016104fe565b60408051601f19818403018152908290526102f391610522565b6000604051808303816000865af19150503d8060008114610330576040519150601f19603f3d011682016040523d82523d6000602084013e610335565b606091505b509150508080602001905181019061034d9190610535565b9150505b919050565b634e487b7160e01b600052604160045260246000fd5b60008060006060848603121561038157600080fd5b833592506020808501356001600160a01b03811681146103a057600080fd5b9250604085013567ffffffffffffffff808211156103bd57600080fd5b818701915087601f8301126103d157600080fd5b8135818111156103e3576103e3610356565b8060051b604051601f19603f8301168101818110858211171561040857610408610356565b60405291825284820192508381018501918a83111561042657600080fd5b938501935b828510156104445784358452938501939285019261042b565b8096505050505050509250925092565b60006020828403121561046657600080fd5b5035919050565b634e487b7160e01b600052601160045260246000fd5b808201808211156104965761049661046d565b92915050565b6000602082840312156104ae57600080fd5b5051919050565b6000600182016104c7576104c761046d565b5060010190565b6000815160005b818110156104ef57602081850181015186830152016104d5565b50600093019283525090919050565b6001600160e01b031983168152600061051a60048301846104ce565b949350505050565b600061052e82846104ce565b9392505050565b60006020828403121561054757600080fd5b8151801515811461052e57600080fdfea2646970667358221220b97e9a7f6f57b8eec57cf4a4b99912e375b000ed1db9c39554338fbc24e0238164736f6c63430008130033\",\n        \"nonce\": \"0x4\",\n        \"accessList\": []\n      },\n      \"additionalContracts\": [],\n      \"isFixedGasLimit\": false\n    },\n    {\n      \"hash\": \"0xba07558b550c650b07b665781bb3a90d4e186c2c6a9eb79bd483127f53fa8dd7\",\n      \"transactionType\": \"CALL\",\n      \"contractName\": \"Test\",\n      \"contractAddress\": \"0xDc64a140Aa3E981100a9becA4E685f962f0cF6C9\",\n      \"function\": \"t(uint256):(uint256)\",\n      \"arguments\": [\n        \"3\"\n      ],\n      \"transaction\": {\n        \"type\": \"0x02\",\n        \"from\": \"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266\",\n        \"to\": \"0xdc64a140aa3e981100a9beca4e685f962f0cf6c9\",\n        \"gas\": \"0x94de\",\n        \"value\": \"0x0\",\n        \"data\": \"0xafe29f710000000000000000000000000000000000000000000000000000000000000003\",\n        \"nonce\": \"0x5\",\n        \"accessList\": []\n      },\n      \"additionalContracts\": [],\n      \"isFixedGasLimit\": false\n    }\n  ],\n  \"receipts\": [\n    {\n      \"transactionHash\": \"0x1e96239f222cb37343e403f10d1fba3c1e6da307d536d81c798c776a7eedf29a\",\n      \"transactionIndex\": \"0x0\",\n      \"blockHash\": \"0xf503074db2d26b36658d9a02b46f8451b66586e208bda70880ef47c83c7abb75\",\n      \"blockNumber\": \"0x1\",\n      \"from\": \"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266\",\n      \"to\": null,\n      \"cumulativeGasUsed\": \"0x13f46\",\n      \"gasUsed\": \"0x13f46\",\n      \"contractAddress\": \"0x5FbDB2315678afecb367f032d93F642f64180aa3\",\n      \"logs\": [],\n      \"status\": \"0x1\",\n      \"logsBloom\": \"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\n      \"type\": \"0x2\",\n      \"effectiveGasPrice\": \"0xee6b2800\"\n    },\n    {\n      \"transactionHash\": \"0x585a60fdff43ed25c0602c005f4ec893596ff8f8ecc384f354386a3a94b027ea\",\n      \"transactionIndex\": \"0x0\",\n      \"blockHash\": \"0xea32aeb5e74c6e50c10bc4a0821a4b34b3a16746eaf0ee59763b94cda0d93c60\",\n      \"blockNumber\": \"0x2\",\n      \"from\": \"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266\",\n      \"to\": null,\n      \"cumulativeGasUsed\": \"0x5de1a\",\n      \"gasUsed\": \"0x5de1a\",\n      \"contractAddress\": \"0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512\",\n      \"logs\": [],\n      \"status\": \"0x1\",\n      \"logsBloom\": \"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\n      \"type\": \"0x2\",\n      \"effectiveGasPrice\": \"0xe702335d\"\n    },\n    {\n      \"transactionHash\": \"0x58480c8e39cb861ec12c7e8c95def65920a757be223852e8d08f32b472cfe512\",\n      \"transactionIndex\": \"0x0\",\n      \"blockHash\": \"0x34accc835ffe8727ae9353d8f776b0541b232460b97b9ece21bdc72d34deed5f\",\n      \"blockNumber\": \"0x3\",\n      \"from\": \"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266\",\n      \"to\": \"0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512\",\n      \"cumulativeGasUsed\": \"0x693e\",\n      \"gasUsed\": \"0x693e\",\n      \"contractAddress\": null,\n      \"logs\": [\n        {\n          \"address\": \"0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512\",\n          \"topics\": [\n            \"0x0b2e13ff20ac7b474198655583edf70dedd2c1dc980e329c4fbb2fc0748b796b\"\n          ],\n          \"data\": \"0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000046865726500000000000000000000000000000000000000000000000000000000\",\n          \"blockHash\": \"0x34accc835ffe8727ae9353d8f776b0541b232460b97b9ece21bdc72d34deed5f\",\n          \"blockNumber\": \"0x3\",\n          \"transactionHash\": \"0x58480c8e39cb861ec12c7e8c95def65920a757be223852e8d08f32b472cfe512\",\n          \"transactionIndex\": \"0x0\",\n          \"logIndex\": \"0x0\",\n          \"transactionLogIndex\": \"0x0\",\n          \"removed\": false\n        }\n      ],\n      \"status\": \"0x1\",\n      \"logsBloom\": \"0x00000000000000000000000000000010000000000000000000000000000100000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000100\",\n      \"type\": \"0x2\",\n      \"effectiveGasPrice\": \"0xe0a6ca0b\"\n    },\n    {\n      \"transactionHash\": \"0xf1376c34ccb8e1a5caa05442dc6c281f5622157aa0a204636354131914a15d5d\",\n      \"transactionIndex\": \"0x1\",\n      \"blockHash\": \"0x34accc835ffe8727ae9353d8f776b0541b232460b97b9ece21bdc72d34deed5f\",\n      \"blockNumber\": \"0x3\",\n      \"from\": \"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266\",\n      \"to\": null,\n      \"cumulativeGasUsed\": \"0x48e14\",\n      \"gasUsed\": \"0x424d6\",\n      \"contractAddress\": \"0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9\",\n      \"logs\": [],\n      \"status\": \"0x1\",\n      \"logsBloom\": \"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\n      \"type\": \"0x2\",\n      \"effectiveGasPrice\": \"0xe0a6ca0b\"\n    },\n    {\n      \"transactionHash\": \"0x1572d2b255c59012349c56a71ec059c8f04d094c47cd1cfd7f62febe714e87e9\",\n      \"transactionIndex\": \"0x2\",\n      \"blockHash\": \"0x34accc835ffe8727ae9353d8f776b0541b232460b97b9ece21bdc72d34deed5f\",\n      \"blockNumber\": \"0x3\",\n      \"from\": \"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266\",\n      \"to\": null,\n      \"cumulativeGasUsed\": \"0xa6c2e\",\n      \"gasUsed\": \"0x5de1a\",\n      \"contractAddress\": \"0xDc64a140Aa3E981100a9becA4E685f962f0cF6C9\",\n      \"logs\": [],\n      \"status\": \"0x1\",\n      \"logsBloom\": \"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\n      \"type\": \"0x2\",\n      \"effectiveGasPrice\": \"0xe0a6ca0b\"\n    },\n    {\n      \"transactionHash\": \"0xba07558b550c650b07b665781bb3a90d4e186c2c6a9eb79bd483127f53fa8dd7\",\n      \"transactionIndex\": \"0x3\",\n      \"blockHash\": \"0x34accc835ffe8727ae9353d8f776b0541b232460b97b9ece21bdc72d34deed5f\",\n      \"blockNumber\": \"0x3\",\n      \"from\": \"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266\",\n      \"to\": \"0xDc64a140Aa3E981100a9becA4E685f962f0cF6C9\",\n      \"cumulativeGasUsed\": \"0xad7f6\",\n      \"gasUsed\": \"0x6bc8\",\n      \"contractAddress\": null,\n      \"logs\": [\n        {\n          \"address\": \"0xDc64a140Aa3E981100a9becA4E685f962f0cF6C9\",\n          \"topics\": [\n            \"0x0b2e13ff20ac7b474198655583edf70dedd2c1dc980e329c4fbb2fc0748b796b\"\n          ],\n          \"data\": \"0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000046865726500000000000000000000000000000000000000000000000000000000\",\n          \"blockHash\": \"0x34accc835ffe8727ae9353d8f776b0541b232460b97b9ece21bdc72d34deed5f\",\n          \"blockNumber\": \"0x3\",\n          \"transactionHash\": \"0xba07558b550c650b07b665781bb3a90d4e186c2c6a9eb79bd483127f53fa8dd7\",\n          \"transactionIndex\": \"0x3\",\n          \"logIndex\": \"0x3\",\n          \"transactionLogIndex\": \"0x0\",\n          \"removed\": false\n        }\n      ],\n      \"status\": \"0x1\",\n      \"logsBloom\": \"0x00000000000000000000000000000010000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000001000000000100000000000100\",\n      \"type\": \"0x2\",\n      \"effectiveGasPrice\": \"0xe0a6ca0b\"\n    }\n  ],\n  \"libraries\": [\n    \"src/Broadcast.t.sol:F:0x5fbdb2315678afecb367f032d93f642f64180aa3\"\n  ],\n  \"pending\": [],\n  \"returns\": {},\n  \"timestamp\": 1685438820,\n  \"chain\": 31337,\n  \"multi\": false,\n  \"commit\": null\n}"
  },
  {
    "path": "testdata/fixtures/broadcast.sensitive.log.json",
    "content": "{\n  \"transactions\": [\n    {\n      \"rpc\": \"http://127.0.0.1:57544\"\n    },\n    {\n      \"rpc\": \"http://127.0.0.1:57544\"\n    },\n    {\n      \"rpc\": \"http://127.0.0.1:57544\"\n    },\n    {\n      \"rpc\": \"http://127.0.0.1:57544\"\n    },\n    {\n      \"rpc\": \"http://127.0.0.1:57544\"\n    },\n    {\n      \"rpc\": \"http://127.0.0.1:57544\"\n    }\n  ]\n}"
  },
  {
    "path": "testdata/forge-std-rev",
    "content": "0844d7e1fc5e60d77b68e469bff60265f236c398"
  },
  {
    "path": "testdata/foundry.toml",
    "content": "[profile.default]\nsrc = \"src\"\ntest = \"./\"\noptimizer = true\noptimizer_runs = 200\nvia_ir = false\nignored_error_codes = [\n    1878, # SPDX license identifier not provided\n    2018, # Function state mutability can be restricted\n    2072, # Unused local variable\n    2424, # Natspec memory-safe-assembly special comment deprecated\n    2519, # This declaration shadows an existing declaration\n    3860, # Contract init code size exceeds limit\n    5159, # Selfdestruct has been deprecated\n    5574, # Contract code size exceeds limit\n    5667, # Unused function parameter\n    9207, # 'transfer' is deprecated\n]\nextra_output = [\"storageLayout\"]\n\nadditional_compiler_profiles = [\n    # paris\n    { name = \"paris\", evm_version = \"paris\" },\n]\ncompilation_restrictions = [\n    # paris\n    { paths = \"paris/**\", evm_version = \"paris\" },\n]\n\nffi = true\nfs_permissions = [\n    { access = \"read-write\", path = \"out/\" },\n    { access = \"read-write\", path = \"fixtures/\" },\n]\nverbosity = 3\nprompt_timeout = 0\n\n[profile.default.rpc_storage_caching]\nchains = \"all\"\nendpoints = \"all\"\n\n[profile.default.invariant]\ndepth = 15\n\n[fmt]\nignore = [\"cheats/Vm.sol\"]\n\n[lint]\nlint_on_build = false\n\n# These are set in .env, which is populated when running through `cargo (nex)test`.\n[rpc_endpoints]\nmainnet = \"${RPC_MAINNET}\"\nmainnet2 = \"${RPC_MAINNET2}\"\nsepolia = \"${RPC_SEPOLIA}\"\noptimism = \"${RPC_OPTIMISM}\"\narbitrum = \"${RPC_ARBITRUM}\"\npolygon = \"${RPC_POLYGON}\"\nbsc = \"${RPC_BSC}\"\navaxTestnet = \"https://api.avax-test.network/ext/bc/C/rpc\"\nmoonbeam = \"https://moonbeam-rpc.publicnode.com\"\npolkadotTestnet = \"https://eth-rpc-testnet.polkadot.io\"\nkusama = \"https://eth-rpc-kusama.polkadot.io\"\npolkadot = \"https://eth-rpc.polkadot.io\"\nrpcEnvAlias = \"${RPC_ENV_ALIAS}\"\n"
  },
  {
    "path": "testdata/multi-version/Counter.sol",
    "content": "pragma solidity ^0.8.4;\n\ncontract Counter {\n    uint256 public number;\n\n    function setNumber(uint256 newNumber) public {\n        number = newNumber;\n    }\n\n    function increment() public {\n        number++;\n    }\n}\n"
  },
  {
    "path": "testdata/multi-version/Importer.sol",
    "content": "pragma solidity 0.8.17;\n\nimport \"./Counter.sol\";\n\n// Please do not remove or change version pragma for this file.\n// If you need to ensure that some of the files are compiled with\n// solc 0.8.17, you should add imports of them to this file.\n"
  },
  {
    "path": "testdata/multi-version/cheats/GetCode.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity =0.8.18;\n\nimport \"utils/Test.sol\";\nimport \"../Counter.sol\";\n\ncontract GetCodeTest is Test {\n    function testGetCodeMultiVersion() public {\n        assertEq(vm.getCode(\"Counter.sol\"), type(Counter).creationCode);\n        require(\n            keccak256(vm.getCode(\"Counter.sol\")) != keccak256(vm.getCode(\"Counter.sol:Counter:0.8.17\")),\n            \"Invalid artifact\"\n        );\n        assertEq(vm.getCode(\"Counter.sol\"), vm.getCode(\"Counter.sol:Counter:0.8.18\"));\n    }\n\n    function testGetCodeByNameMultiVersion() public {\n        assertEq(vm.getCode(\"Counter\"), type(Counter).creationCode);\n        require(keccak256(vm.getCode(\"Counter\")) != keccak256(vm.getCode(\"Counter:0.8.17\")), \"Invalid artifact\");\n        assertEq(vm.getCode(\"Counter\"), vm.getCode(\"Counter:0.8.18\"));\n    }\n}\n"
  },
  {
    "path": "testdata/multi-version/cheats/GetCode17.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity =0.8.17;\n\nimport \"utils/Test.sol\";\nimport \"../Counter.sol\";\n\n// Same as GetCode.t.sol but for 0.8.17 version\ncontract GetCodeTest17 is Test {\n    function testGetCodeMultiVersion() public {\n        assertEq(vm.getCode(\"Counter.sol\"), type(Counter).creationCode);\n        require(\n            keccak256(vm.getCode(\"Counter.sol\")) != keccak256(vm.getCode(\"Counter.sol:Counter:0.8.18\")),\n            \"Invalid artifact\"\n        );\n        assertEq(vm.getCode(\"Counter.sol\"), vm.getCode(\"Counter.sol:Counter:0.8.17\"));\n    }\n\n    function testGetCodeByNameMultiVersion() public {\n        assertEq(vm.getCode(\"Counter\"), type(Counter).creationCode);\n        require(keccak256(vm.getCode(\"Counter\")) != keccak256(vm.getCode(\"Counter:0.8.18\")), \"Invalid artifact\");\n        assertEq(vm.getCode(\"Counter.sol\"), vm.getCode(\"Counter:0.8.17\"));\n    }\n}\n"
  },
  {
    "path": "testdata/paris/cheats/Fork.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ninterface IWETH {\n    function deposit() external payable;\n    function balanceOf(address) external view returns (uint256);\n}\n\ncontract ForkTest is Test {\n    address constant WETH_TOKEN_ADDR = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;\n    uint256 constant mainblock = 14_608_400;\n\n    IWETH WETH = IWETH(WETH_TOKEN_ADDR);\n\n    uint256 forkA;\n    uint256 forkB;\n\n    uint256 testValue;\n\n    // this will create two _different_ forks during setup\n    function setUp() public {\n        forkA = vm.createFork(\"mainnet\", mainblock);\n        forkB = vm.createFork(\"mainnet2\", mainblock - 1);\n        testValue = 999;\n    }\n\n    // ensures forks use different ids\n    function testForkIdDiffer() public {\n        assert(forkA != forkB);\n    }\n\n    // ensures we can create and select in one step\n    function testCreateSelect() public {\n        uint256 fork = vm.createSelectFork(\"mainnet\");\n        assertEq(fork, vm.activeFork());\n    }\n\n    // ensures forks use different ids\n    function testCanSwitchForks() public {\n        vm.selectFork(forkA);\n        vm.selectFork(forkB);\n        vm.selectFork(forkB);\n        vm.selectFork(forkA);\n    }\n\n    function testForksHaveSeparatedStorage() public {\n        vm.selectFork(forkA);\n        // read state from forkA\n        assert(WETH.balanceOf(0x0000000000000000000000000000000000000000) != 1);\n\n        vm.selectFork(forkB);\n        // read state from forkB\n        uint256 forkBbalance = WETH.balanceOf(0x0000000000000000000000000000000000000000);\n        assert(forkBbalance != 1);\n\n        vm.selectFork(forkA);\n\n        // modify state\n        bytes32 value = bytes32(uint256(1));\n        // \"0x3617319a054d772f909f7c479a2cebe5066e836a939412e32403c99029b92eff\" is the slot storing the balance of zero address for the weth contract\n        // `cast index address uint 0x0000000000000000000000000000000000000000 3`\n        bytes32 zero_address_balance_slot = 0x3617319a054d772f909f7c479a2cebe5066e836a939412e32403c99029b92eff;\n        vm.store(WETH_TOKEN_ADDR, zero_address_balance_slot, value);\n        assertEq(\n            WETH.balanceOf(0x0000000000000000000000000000000000000000),\n            1,\n            \"Cheatcode did not change value at the storage slot.\"\n        );\n\n        // switch forks and ensure the balance on forkB remains untouched\n        vm.selectFork(forkB);\n        assert(forkBbalance != 1);\n        // balance of forkB is untouched\n        assertEq(\n            WETH.balanceOf(0x0000000000000000000000000000000000000000),\n            forkBbalance,\n            \"Cheatcode did not change value at the storage slot.\"\n        );\n    }\n\n    function testCanShareDataAcrossSwaps() public {\n        assertEq(testValue, 999);\n\n        uint256 val = 300;\n        vm.selectFork(forkA);\n        assertEq(val, 300);\n\n        testValue = 100;\n\n        vm.selectFork(forkB);\n        assertEq(val, 300);\n        assertEq(testValue, 100);\n\n        val = 99;\n        testValue = 300;\n\n        vm.selectFork(forkA);\n        assertEq(val, 99);\n        assertEq(testValue, 300);\n    }\n\n    // ensures forks use different ids\n    function testCanChangeChainId() public {\n        vm.selectFork(forkA);\n        uint256 newChainId = 1337;\n        vm.chainId(newChainId);\n        uint256 expected = block.chainid;\n        assertEq(newChainId, expected);\n    }\n\n    // ensures forks change chain ids automatically\n    function testCanAutoUpdateChainId() public {\n        vm.createSelectFork(\"sepolia\");\n        assertEq(block.chainid, 11155111);\n    }\n\n    // ensures forks storage is cached at block\n    function testStorageCaching() public {\n        vm.createSelectFork(\"mainnet\", 19800000);\n    }\n}\n"
  },
  {
    "path": "testdata/paris/cheats/GasSnapshots.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract GasSnapshotTest is Test {\n    uint256 public slot0;\n    Flare public flare;\n\n    function setUp() public {\n        flare = new Flare();\n    }\n\n    function testSnapshotGasSectionExternal() public {\n        vm.startSnapshotGas(\"testAssertGasExternal\");\n        flare.run(1);\n        uint256 gasUsed = vm.stopSnapshotGas();\n\n        assertGt(gasUsed, 0);\n    }\n\n    function testSnapshotGasSectionInternal() public {\n        vm.startSnapshotGas(\"testAssertGasInternalA\");\n        slot0 = 1;\n        vm.stopSnapshotGas();\n\n        vm.startSnapshotGas(\"testAssertGasInternalB\");\n        slot0 = 2;\n        vm.stopSnapshotGas();\n\n        vm.startSnapshotGas(\"testAssertGasInternalC\");\n        slot0 = 0;\n        vm.stopSnapshotGas();\n\n        vm.startSnapshotGas(\"testAssertGasInternalD\");\n        slot0 = 1;\n        vm.stopSnapshotGas();\n\n        vm.startSnapshotGas(\"testAssertGasInternalE\");\n        slot0 = 2;\n        vm.stopSnapshotGas();\n    }\n\n    // Writes to `GasSnapshotTest` group with custom names.\n    function testSnapshotValueDefaultGroupA() public {\n        uint256 a = 123;\n        uint256 b = 456;\n        uint256 c = 789;\n\n        vm.snapshotValue(\"a\", a);\n        vm.snapshotValue(\"b\", b);\n        vm.snapshotValue(\"c\", c);\n    }\n\n    // Writes to same `GasSnapshotTest` group with custom names.\n    function testSnapshotValueDefaultGroupB() public {\n        uint256 d = 123;\n        uint256 e = 456;\n        uint256 f = 789;\n\n        vm.snapshotValue(\"d\", d);\n        vm.snapshotValue(\"e\", e);\n        vm.snapshotValue(\"f\", f);\n    }\n\n    // Writes to `CustomGroup` group with custom names.\n    // Asserts that the order of the values is alphabetical.\n    function testSnapshotValueCustomGroupA() public {\n        uint256 o = 123;\n        uint256 i = 456;\n        uint256 q = 789;\n\n        vm.snapshotValue(\"CustomGroup\", \"q\", q);\n        vm.snapshotValue(\"CustomGroup\", \"i\", i);\n        vm.snapshotValue(\"CustomGroup\", \"o\", o);\n    }\n\n    // Writes to `CustomGroup` group with custom names.\n    // Asserts that the order of the values is alphabetical.\n    function testSnapshotValueCustomGroupB() public {\n        uint256 x = 123;\n        uint256 e = 456;\n        uint256 z = 789;\n\n        vm.snapshotValue(\"CustomGroup\", \"z\", z);\n        vm.snapshotValue(\"CustomGroup\", \"x\", x);\n        vm.snapshotValue(\"CustomGroup\", \"e\", e);\n    }\n\n    // Writes to `GasSnapshotTest` group with `testSnapshotGasDefault` name.\n    function testSnapshotGasSectionDefaultGroupStop() public {\n        vm.startSnapshotGas(\"testSnapshotGasSection\");\n\n        flare.run(8);\n\n        // vm.stopSnapshotGas() will use the last snapshot name.\n        uint256 gasUsed = vm.stopSnapshotGas();\n        assertGt(gasUsed, 0);\n    }\n\n    // Writes to `GasSnapshotTest` group with `testSnapshotGasCustom` name.\n    function testSnapshotGasSectionCustomGroupStop() public {\n        vm.startSnapshotGas(\"CustomGroup\", \"testSnapshotGasSection\");\n\n        flare.run(8);\n\n        // vm.stopSnapshotGas() will use the last snapshot name, even with custom group.\n        uint256 gasUsed = vm.stopSnapshotGas();\n        assertGt(gasUsed, 0);\n    }\n\n    // Writes to `GasSnapshotTest` group with `testSnapshotGasSection` name.\n    function testSnapshotGasSectionName() public {\n        vm.startSnapshotGas(\"testSnapshotGasSectionName\");\n\n        flare.run(8);\n\n        uint256 gasUsed = vm.stopSnapshotGas(\"testSnapshotGasSectionName\");\n        assertGt(gasUsed, 0);\n    }\n\n    // Writes to `CustomGroup` group with `testSnapshotGasSection` name.\n    function testSnapshotGasSectionGroupName() public {\n        vm.startSnapshotGas(\"CustomGroup\", \"testSnapshotGasSectionGroupName\");\n\n        flare.run(8);\n\n        uint256 gasUsed = vm.stopSnapshotGas(\"CustomGroup\", \"testSnapshotGasSectionGroupName\");\n        assertGt(gasUsed, 0);\n    }\n\n    // Writes to `GasSnapshotTest` group with `testSnapshotGas` name.\n    function testSnapshotGasLastCallName() public {\n        flare.run(1);\n\n        uint256 gasUsed = vm.snapshotGasLastCall(\"testSnapshotGasLastCallName\");\n        assertGt(gasUsed, 0);\n    }\n\n    // Writes to `CustomGroup` group with `testSnapshotGas` name.\n    function testSnapshotGasLastCallGroupName() public {\n        flare.run(1);\n\n        uint256 gasUsed = vm.snapshotGasLastCall(\"CustomGroup\", \"testSnapshotGasLastCallGroupName\");\n        assertGt(gasUsed, 0);\n    }\n}\n\ncontract GasComparisonTest is Test {\n    uint256 public slot0;\n    uint256 public slot1;\n\n    uint256 public cachedGas;\n\n    function testGasComparisonEmpty() public {\n        // Start a cheatcode snapshot.\n        vm.startSnapshotGas(\"ComparisonGroup\", \"testGasComparisonEmptyA\");\n        uint256 a = vm.stopSnapshotGas();\n\n        // Start a comparative Solidity snapshot.\n        _snapStart();\n        uint256 b = _snapEnd();\n        vm.snapshotValue(\"ComparisonGroup\", \"testGasComparisonEmptyB\", b);\n\n        assertEq(a, b);\n    }\n\n    function testGasComparisonInternalCold() public {\n        // Start a cheatcode snapshot.\n        vm.startSnapshotGas(\"ComparisonGroup\", \"testGasComparisonInternalColdA\");\n        slot0 = 1;\n        uint256 a = vm.stopSnapshotGas();\n\n        // Start a comparative Solidity snapshot.\n        _snapStart();\n        slot1 = 1;\n        uint256 b = _snapEnd();\n        vm.snapshotValue(\"ComparisonGroup\", \"testGasComparisonInternalColdB\", b);\n\n        vm.assertApproxEqAbs(a, b, 6);\n    }\n\n    function testGasComparisonInternalWarm() public {\n        // Warm up the cache.\n        slot0 = 1;\n\n        // Start a cheatcode snapshot.\n        vm.startSnapshotGas(\"ComparisonGroup\", \"testGasComparisonInternalWarmA\");\n        slot0 = 2;\n        uint256 a = vm.stopSnapshotGas();\n\n        // Start a comparative Solidity snapshot.\n        _snapStart();\n        slot0 = 3;\n        uint256 b = _snapEnd();\n        vm.snapshotValue(\"ComparisonGroup\", \"testGasComparisonInternalWarmB\", b);\n\n        vm.assertApproxEqAbs(a, b, 6);\n    }\n\n    function testGasComparisonExternal() public {\n        // Warm up the cache.\n        TargetB target = new TargetB();\n        target.update(1);\n\n        // Start a cheatcode snapshot.\n        vm.startSnapshotGas(\"ComparisonGroup\", \"testGasComparisonExternalA\");\n        target.update(2);\n        uint256 a = vm.stopSnapshotGas();\n\n        // Start a comparative Solidity snapshot.\n        _snapStart();\n        target.update(3);\n        uint256 b = _snapEnd();\n        vm.snapshotValue(\"ComparisonGroup\", \"testGasComparisonExternalB\", b);\n\n        assertEq(a, b);\n    }\n\n    function testGasComparisonCreate() public {\n        // Start a cheatcode snapshot.\n        vm.startSnapshotGas(\"ComparisonGroup\", \"testGasComparisonCreateA\");\n        new TargetC();\n        uint256 a = vm.stopSnapshotGas();\n\n        // Start a comparative Solidity snapshot.\n        _snapStart();\n        new TargetC();\n        uint256 b = _snapEnd();\n        vm.snapshotValue(\"ComparisonGroup\", \"testGasComparisonCreateB\", b);\n\n        assertEq(a, b);\n    }\n\n    function testGasComparisonNestedCalls() public {\n        // Warm up the cache.\n        TargetA target = new TargetA();\n        target.update(1);\n\n        // Start a cheatcode snapshot.\n        vm.startSnapshotGas(\"ComparisonGroup\", \"testGasComparisonNestedCallsA\");\n        target.update(2);\n        uint256 a = vm.stopSnapshotGas();\n\n        // Start a comparative Solidity snapshot.\n        _snapStart();\n        target.update(3);\n        uint256 b = _snapEnd();\n        vm.snapshotValue(\"ComparisonGroup\", \"testGasComparisonNestedCallsB\", b);\n\n        assertEq(a, b);\n    }\n\n    function testGasComparisonFlare() public {\n        // Warm up the cache.\n        Flare flare = new Flare();\n        flare.run(1);\n\n        // Start a cheatcode snapshot.\n        vm.startSnapshotGas(\"ComparisonGroup\", \"testGasComparisonFlareA\");\n        flare.run(8);\n        uint256 a = vm.stopSnapshotGas();\n\n        // Start a comparative Solidity snapshot.\n        _snapStart();\n        flare.run(8);\n        uint256 b = _snapEnd();\n        vm.snapshotValue(\"ComparisonGroup\", \"testGasComparisonFlareB\", b);\n\n        assertEq(a, b);\n    }\n\n    // Internal function to start a Solidity snapshot.\n    function _snapStart() internal {\n        cachedGas = 1;\n        cachedGas = gasleft();\n    }\n\n    // Internal function to end a Solidity snapshot.\n    function _snapEnd() internal returns (uint256 gasUsed) {\n        gasUsed = cachedGas - gasleft() - 138;\n        cachedGas = 2;\n    }\n}\n\ncontract Flare {\n    bytes32[] public data;\n\n    function run(uint256 n_) public {\n        for (uint256 i = 0; i < n_; i++) {\n            data.push(keccak256(abi.encodePacked(i)));\n        }\n    }\n}\n\ncontract TargetA {\n    TargetB public target;\n\n    constructor() {\n        target = new TargetB();\n    }\n\n    function update(uint256 x_) public {\n        target.update(x_);\n    }\n}\n\ncontract TargetB {\n    uint256 public x;\n\n    function update(uint256 x_) public {\n        x = x_;\n    }\n}\n\ncontract TargetC {}\n"
  },
  {
    "path": "testdata/paris/cheats/LastCallGas.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract Target {\n    uint256 public slot0;\n\n    function expandMemory(uint256 n) public pure returns (uint256) {\n        uint256[] memory arr = new uint256[](n);\n\n        for (uint256 i = 0; i < n; i++) {\n            arr[i] = i;\n        }\n\n        return arr.length;\n    }\n\n    function setValue(uint256 value) public {\n        slot0 = value;\n    }\n\n    function resetValue() public {\n        slot0 = 0;\n    }\n\n    fallback() external {}\n}\n\nabstract contract LastCallGasFixture is Test {\n    Target public target;\n\n    struct Gas {\n        uint64 gasTotalUsed;\n        uint64 gasMemoryUsed;\n        int64 gasRefunded;\n    }\n\n    function testRevertNoCachedLastCallGas() public {\n        vm._expectCheatcodeRevert();\n        vm.lastCallGas();\n    }\n\n    function _setup() internal {\n        // Cannot be set in `setUp` due to `testRevertNoCachedLastCallGas`\n        // relying on no calls being made before `lastCallGas` is called.\n        target = new Target();\n    }\n\n    function _performCall() internal returns (bool success) {\n        (success,) = address(target).call(\"\");\n    }\n\n    function _performRefund() internal {\n        target.setValue(1);\n        target.resetValue();\n    }\n\n    function _assertGas(Vm.Gas memory lhs, Gas memory rhs) internal {\n        assertGt(lhs.gasLimit, 0);\n        assertGt(lhs.gasRemaining, 0);\n        assertEq(lhs.gasTotalUsed, rhs.gasTotalUsed);\n        assertEq(lhs.gasMemoryUsed, rhs.gasMemoryUsed);\n        assertEq(lhs.gasRefunded, rhs.gasRefunded);\n    }\n}\n\n/// forge-config: default.isolate = true\ncontract LastCallGasIsolatedTest is LastCallGasFixture {\n    function testRecordLastCallGas() public {\n        _setup();\n        _performCall();\n        _assertGas(vm.lastCallGas(), Gas({gasTotalUsed: 21064, gasMemoryUsed: 0, gasRefunded: 0}));\n\n        _performCall();\n        _assertGas(vm.lastCallGas(), Gas({gasTotalUsed: 21064, gasMemoryUsed: 0, gasRefunded: 0}));\n\n        _performCall();\n        _assertGas(vm.lastCallGas(), Gas({gasTotalUsed: 21064, gasMemoryUsed: 0, gasRefunded: 0}));\n    }\n\n    function testRecordGasRefund() public {\n        _setup();\n        _performRefund();\n        _assertGas(vm.lastCallGas(), Gas({gasTotalUsed: 21380, gasMemoryUsed: 0, gasRefunded: 4800}));\n    }\n}\n\n// Without isolation mode enabled the gas usage will be incorrect.\ncontract LastCallGasDefaultTest is LastCallGasFixture {\n    function testRecordLastCallGas() public {\n        _setup();\n        _performCall();\n        _assertGas(vm.lastCallGas(), Gas({gasTotalUsed: 64, gasMemoryUsed: 0, gasRefunded: 0}));\n\n        _performCall();\n        _assertGas(vm.lastCallGas(), Gas({gasTotalUsed: 64, gasMemoryUsed: 0, gasRefunded: 0}));\n\n        _performCall();\n        _assertGas(vm.lastCallGas(), Gas({gasTotalUsed: 64, gasMemoryUsed: 0, gasRefunded: 0}));\n    }\n\n    function testRecordGasRefund() public {\n        _setup();\n        _performRefund();\n        _assertGas(vm.lastCallGas(), Gas({gasTotalUsed: 216, gasMemoryUsed: 0, gasRefunded: 19900}));\n    }\n}\n"
  },
  {
    "path": "testdata/paris/core/BeforeTest.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract SelfDestructor {\n    function kill() external {\n        selfdestruct(payable(msg.sender));\n    }\n}\n\n// https://github.com/foundry-rs/foundry/issues/1543\ncontract BeforeTestSelfDestructTest is Test {\n    SelfDestructor killer;\n    uint256 a;\n    uint256 b;\n\n    function setUp() public {\n        killer = new SelfDestructor();\n    }\n\n    function beforeTestSetup(bytes4 testSelector) public pure returns (bytes[] memory beforeTestCalldata) {\n        if (testSelector == this.testKill.selector) {\n            beforeTestCalldata = new bytes[](1);\n            beforeTestCalldata[0] = abi.encodePacked(this.kill_contract.selector);\n        }\n\n        if (testSelector == this.testA.selector) {\n            beforeTestCalldata = new bytes[](3);\n            beforeTestCalldata[0] = abi.encodePacked(this.testA.selector);\n            beforeTestCalldata[1] = abi.encodePacked(this.testA.selector);\n            beforeTestCalldata[2] = abi.encodePacked(this.testA.selector);\n        }\n\n        if (testSelector == this.testB.selector) {\n            beforeTestCalldata = new bytes[](1);\n            beforeTestCalldata[0] = abi.encodePacked(this.setB.selector);\n        }\n\n        if (testSelector == this.testC.selector) {\n            beforeTestCalldata = new bytes[](2);\n            beforeTestCalldata[0] = abi.encodePacked(this.testA.selector);\n            beforeTestCalldata[1] = abi.encodeWithSignature(\"setBWithValue(uint256)\", 111);\n        }\n    }\n\n    function kill_contract() external {\n        uint256 killer_size = getSize(address(killer));\n        assertEq(killer_size, 106);\n        killer.kill();\n        assertEq(killer_size, 106);\n    }\n\n    /// forge-config: default.evm_version = \"paris\"\n    function testKill() public {\n        uint256 killer_size = getSize(address(killer));\n        assertEq(killer_size, 0);\n    }\n\n    function getSize(address c) internal view returns (uint32) {\n        uint32 size;\n        assembly {\n            size := extcodesize(c)\n        }\n        return size;\n    }\n\n    function testA() public {\n        assertLe(a, 3);\n        a += 1;\n    }\n\n    function testSimpleA() public {\n        assertEq(a, 0);\n    }\n\n    function setB() public {\n        b = 100;\n    }\n\n    function testB() public {\n        assertEq(b, 100);\n    }\n\n    function setBWithValue(uint256 value) public {\n        b = value;\n    }\n\n    function testC(uint256 h) public {\n        assertEq(a, 1);\n        assertEq(b, 111);\n    }\n}\n"
  },
  {
    "path": "testdata/paris/fork/Transact.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ninterface IERC20 {\n    function transfer(address to, uint256 amount) external returns (bool);\n\n    function balanceOf(address account) external view returns (uint256);\n}\n\ncontract TransactOnForkTest is Test {\n    IERC20 constant USDT = IERC20(0xdAC17F958D2ee523a2206206994597C13D831ec7);\n\n    event Transfer(address indexed from, address indexed to, uint256 value);\n\n    function testTransact() public {\n        // A random block https://etherscan.io/block/17134913\n        uint256 fork = vm.createFork(\"mainnet\", 17134913);\n        vm.selectFork(fork);\n        // a random transfer transaction in the next block: https://etherscan.io/tx/0xaf6201d435b216a858c580e20512a16136916d894aa33260650e164e3238c771\n        bytes32 transaction = 0xaf6201d435b216a858c580e20512a16136916d894aa33260650e164e3238c771;\n\n        address sender = address(0x9B315A70FEe05a70A9F2c832E93a7095FEb32Bfe);\n        address recipient = address(0xDB358B93157Df9b3B1eE9Ea5CDB7D0aE9a1D8110);\n\n        assertEq(sender.balance, 110231651357268209);\n        assertEq(recipient.balance, 892860016357511);\n\n        // transfer amount: 0.015 Ether\n        uint256 transferAmount = 15000000000000000;\n        uint256 expectedRecipientBalance = recipient.balance + transferAmount;\n        uint256 expectedSenderBalance = sender.balance - transferAmount;\n\n        // execute the transaction\n        vm.transact(transaction);\n\n        // recipient received transfer\n        assertEq(recipient.balance, expectedRecipientBalance);\n\n        // decreased by transferAmount and gas\n        assert(sender.balance < expectedSenderBalance);\n    }\n\n    function testTransactCooperatesWithCheatcodes() public {\n        // A random block https://etherscan.io/block/16260609\n        uint256 fork = vm.createFork(\"mainnet\", 16260609);\n        vm.selectFork(fork);\n\n        // a random ERC20 USDT transfer transaction in the next block: https://etherscan.io/tx/0x33350512fec589e635865cbdb38fa3a20a2aa160c52611f1783d0ba24ad13c8c\n        bytes32 transaction = 0x33350512fec589e635865cbdb38fa3a20a2aa160c52611f1783d0ba24ad13c8c;\n\n        address sender = address(0x2e09BB78B3D64d98Da44D1C776fa77dcd133ED54);\n        address recipient = address(0x23a6B9711B711b1d404F2AA740bde350c67a6F06);\n\n        uint256 senderBalance = USDT.balanceOf(sender);\n        uint256 recipientBalance = USDT.balanceOf(recipient);\n\n        assertEq(senderBalance, 20041000000);\n        assertEq(recipientBalance, 66000000);\n\n        // transfer amount: 14000 USDT\n        uint256 transferAmount = 14000000000;\n        uint256 expectedRecipientBalance = recipientBalance + transferAmount;\n        uint256 expectedSenderBalance = senderBalance - transferAmount;\n\n        // expect a call to USDT's transfer\n        // With the current expect call behavior, in which we expect calls to be matched in the next call's subcalls,\n        // expecting calls on vm.transact is impossible. This is because transact essentially creates another call context\n        // that operates independently of the current one, meaning that depths won't match and will trigger a panic on REVM,\n        // as the transact storage is not persisted as well and can't be checked.\n        // vm.expectCall(address(USDT), abi.encodeWithSelector(IERC20.transfer.selector, recipient, transferAmount));\n\n        // expect a Transfer event to be emitted\n        vm.expectEmit(true, true, false, true, address(USDT));\n        emit Transfer(address(sender), address(recipient), transferAmount);\n\n        // start recording logs\n        vm.recordLogs();\n\n        // execute the transaction\n        vm.transact(transaction);\n\n        // extract recorded logs\n        Vm.Log[] memory logs = vm.getRecordedLogs();\n\n        senderBalance = USDT.balanceOf(sender);\n        recipientBalance = USDT.balanceOf(recipient);\n\n        // recipient received transfer\n        assertEq(recipientBalance, expectedRecipientBalance);\n\n        // decreased by transferAmount\n        assertEq(senderBalance, expectedSenderBalance);\n\n        // recorded a `Transfer` log\n        assertEq(logs.length, 1);\n    }\n}\n"
  },
  {
    "path": "testdata/paris/spec/ShanghaiCompat.t.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"utils/Test.sol\";\n\ncontract ShanghaiCompat is Test {\n    function testPush0() public {\n        address target = address(uint160(uint256(0xc4f3)));\n\n        bytes memory bytecode = hex\"365f5f37365ff3\";\n        // 36 CALLDATASIZE\n        // 5F PUSH0\n        // 5F PUSH0\n        // 37 CALLDATACOPY -> copies calldata at mem[0..calldatasize]\n\n        // 36 CALLDATASIZE\n        // 5F PUSH0\n        // F3 RETURN -> returns mem[0..calldatasize]\n\n        vm.etch(target, bytecode);\n\n        (bool success, bytes memory result) = target.call(bytes(\"hello PUSH0\"));\n        assertTrue(success);\n        assertEq(string(result), \"hello PUSH0\");\n    }\n}\n"
  },
  {
    "path": "testdata/src/Counter.vy",
    "content": "from . import ICounter\nimplements: ICounter\n\nnumber: public(uint256)\n\n@external\ndef set_number(new_number: uint256):\n    self.number = new_number\n\n@external\ndef increment():\n    self.number += 1\n"
  },
  {
    "path": "testdata/src/ICounter.vyi",
    "content": "@view\n@external\ndef number() -> uint256:\n    ...\n\n@external\ndef set_number(new_number: uint256):\n    ...\n\n@external\ndef increment():\n    ..."
  },
  {
    "path": "testdata/utils/DSTest.sol",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n\n// You should have received a copy of the GNU General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\npragma solidity >=0.4.23;\n\ncontract DSTest {\n    event log(string);\n    event logs(bytes);\n\n    event log_address(address);\n    event log_bytes32(bytes32);\n    event log_int(int256);\n    event log_uint(uint256);\n    event log_bytes(bytes);\n    event log_string(string);\n\n    event log_named_address(string key, address val);\n    event log_named_bytes32(string key, bytes32 val);\n    event log_named_decimal_int(string key, int256 val, uint256 decimals);\n    event log_named_decimal_uint(string key, uint256 val, uint256 decimals);\n    event log_named_int(string key, int256 val);\n    event log_named_uint(string key, uint256 val);\n    event log_named_bytes(string key, bytes val);\n    event log_named_string(string key, string val);\n\n    bool public IS_TEST = true;\n    bool public _failed;\n\n    address constant HEVM_ADDRESS = address(bytes20(uint160(uint256(keccak256(\"hevm cheat code\")))));\n\n    modifier mayRevert() {\n        _;\n    }\n\n    modifier testopts(string memory) {\n        _;\n    }\n\n    function failed() public returns (bool) {\n        if (_failed) {\n            return _failed;\n        } else {\n            bool globalFailed = false;\n            if (hasHEVMContext()) {\n                (, bytes memory retdata) = HEVM_ADDRESS.call(\n                    abi.encodePacked(\n                        bytes4(keccak256(\"load(address,bytes32)\")), abi.encode(HEVM_ADDRESS, bytes32(\"failed\"))\n                    )\n                );\n                globalFailed = abi.decode(retdata, (bool));\n            }\n            return globalFailed;\n        }\n    }\n\n    function fail() internal {\n        if (hasHEVMContext()) {\n            (bool status,) = HEVM_ADDRESS.call(\n                abi.encodePacked(\n                    bytes4(keccak256(\"store(address,bytes32,bytes32)\")),\n                    abi.encode(HEVM_ADDRESS, bytes32(\"failed\"), bytes32(uint256(0x01)))\n                )\n            );\n            status; // Silence compiler warnings\n        }\n        _failed = true;\n    }\n\n    function hasHEVMContext() internal view returns (bool) {\n        uint256 hevmCodeSize = 0;\n        assembly {\n            hevmCodeSize := extcodesize(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D)\n        }\n        return hevmCodeSize > 0;\n    }\n\n    modifier logs_gas() {\n        uint256 startGas = gasleft();\n        _;\n        uint256 endGas = gasleft();\n        emit log_named_uint(\"gas\", startGas - endGas);\n    }\n\n    function assertTrue(bool condition) internal {\n        if (!condition) {\n            emit log(\"Error: Assertion Failed\");\n            fail();\n        }\n    }\n\n    function assertTrue(bool condition, string memory err) internal {\n        if (!condition) {\n            emit log_named_string(\"Error\", err);\n            assertTrue(condition);\n        }\n    }\n\n    function assertEq(address a, address b) internal {\n        if (a != b) {\n            emit log(\"Error: a == b not satisfied [address]\");\n            emit log_named_address(\"  Expected\", b);\n            emit log_named_address(\"    Actual\", a);\n            fail();\n        }\n    }\n\n    function assertEq(address a, address b, string memory err) internal {\n        if (a != b) {\n            emit log_named_string(\"Error\", err);\n            assertEq(a, b);\n        }\n    }\n\n    function assertEq(bytes32 a, bytes32 b) internal {\n        if (a != b) {\n            emit log(\"Error: a == b not satisfied [bytes32]\");\n            emit log_named_bytes32(\"  Expected\", b);\n            emit log_named_bytes32(\"    Actual\", a);\n            fail();\n        }\n    }\n\n    function assertEq(bytes32 a, bytes32 b, string memory err) internal {\n        if (a != b) {\n            emit log_named_string(\"Error\", err);\n            assertEq(a, b);\n        }\n    }\n\n    function assertEq32(bytes32 a, bytes32 b) internal {\n        assertEq(a, b);\n    }\n\n    function assertEq32(bytes32 a, bytes32 b, string memory err) internal {\n        assertEq(a, b, err);\n    }\n\n    function assertEq(int256 a, int256 b) internal {\n        if (a != b) {\n            emit log(\"Error: a == b not satisfied [int]\");\n            emit log_named_int(\"  Expected\", b);\n            emit log_named_int(\"    Actual\", a);\n            fail();\n        }\n    }\n\n    function assertEq(int256 a, int256 b, string memory err) internal {\n        if (a != b) {\n            emit log_named_string(\"Error\", err);\n            assertEq(a, b);\n        }\n    }\n\n    function assertEq(uint256 a, uint256 b) internal {\n        if (a != b) {\n            emit log(\"Error: a == b not satisfied [uint]\");\n            emit log_named_uint(\"  Expected\", b);\n            emit log_named_uint(\"    Actual\", a);\n            fail();\n        }\n    }\n\n    function assertEq(uint256 a, uint256 b, string memory err) internal {\n        if (a != b) {\n            emit log_named_string(\"Error\", err);\n            assertEq(a, b);\n        }\n    }\n\n    function assertEqDecimal(int256 a, int256 b, uint256 decimals) internal {\n        if (a != b) {\n            emit log(\"Error: a == b not satisfied [decimal int]\");\n            emit log_named_decimal_int(\"  Expected\", b, decimals);\n            emit log_named_decimal_int(\"    Actual\", a, decimals);\n            fail();\n        }\n    }\n\n    function assertEqDecimal(int256 a, int256 b, uint256 decimals, string memory err) internal {\n        if (a != b) {\n            emit log_named_string(\"Error\", err);\n            assertEqDecimal(a, b, decimals);\n        }\n    }\n\n    function assertEqDecimal(uint256 a, uint256 b, uint256 decimals) internal {\n        if (a != b) {\n            emit log(\"Error: a == b not satisfied [decimal uint]\");\n            emit log_named_decimal_uint(\"  Expected\", b, decimals);\n            emit log_named_decimal_uint(\"    Actual\", a, decimals);\n            fail();\n        }\n    }\n\n    function assertEqDecimal(uint256 a, uint256 b, uint256 decimals, string memory err) internal {\n        if (a != b) {\n            emit log_named_string(\"Error\", err);\n            assertEqDecimal(a, b, decimals);\n        }\n    }\n\n    function assertGt(uint256 a, uint256 b) internal {\n        if (a <= b) {\n            emit log(\"Error: a > b not satisfied [uint]\");\n            emit log_named_uint(\"  Value a\", a);\n            emit log_named_uint(\"  Value b\", b);\n            fail();\n        }\n    }\n\n    function assertGt(uint256 a, uint256 b, string memory err) internal {\n        if (a <= b) {\n            emit log_named_string(\"Error\", err);\n            assertGt(a, b);\n        }\n    }\n\n    function assertGt(int256 a, int256 b) internal {\n        if (a <= b) {\n            emit log(\"Error: a > b not satisfied [int]\");\n            emit log_named_int(\"  Value a\", a);\n            emit log_named_int(\"  Value b\", b);\n            fail();\n        }\n    }\n\n    function assertGt(int256 a, int256 b, string memory err) internal {\n        if (a <= b) {\n            emit log_named_string(\"Error\", err);\n            assertGt(a, b);\n        }\n    }\n\n    function assertGtDecimal(int256 a, int256 b, uint256 decimals) internal {\n        if (a <= b) {\n            emit log(\"Error: a > b not satisfied [decimal int]\");\n            emit log_named_decimal_int(\"  Value a\", a, decimals);\n            emit log_named_decimal_int(\"  Value b\", b, decimals);\n            fail();\n        }\n    }\n\n    function assertGtDecimal(int256 a, int256 b, uint256 decimals, string memory err) internal {\n        if (a <= b) {\n            emit log_named_string(\"Error\", err);\n            assertGtDecimal(a, b, decimals);\n        }\n    }\n\n    function assertGtDecimal(uint256 a, uint256 b, uint256 decimals) internal {\n        if (a <= b) {\n            emit log(\"Error: a > b not satisfied [decimal uint]\");\n            emit log_named_decimal_uint(\"  Value a\", a, decimals);\n            emit log_named_decimal_uint(\"  Value b\", b, decimals);\n            fail();\n        }\n    }\n\n    function assertGtDecimal(uint256 a, uint256 b, uint256 decimals, string memory err) internal {\n        if (a <= b) {\n            emit log_named_string(\"Error\", err);\n            assertGtDecimal(a, b, decimals);\n        }\n    }\n\n    function assertGe(uint256 a, uint256 b) internal {\n        if (a < b) {\n            emit log(\"Error: a >= b not satisfied [uint]\");\n            emit log_named_uint(\"  Value a\", a);\n            emit log_named_uint(\"  Value b\", b);\n            fail();\n        }\n    }\n\n    function assertGe(uint256 a, uint256 b, string memory err) internal {\n        if (a < b) {\n            emit log_named_string(\"Error\", err);\n            assertGe(a, b);\n        }\n    }\n\n    function assertGe(int256 a, int256 b) internal {\n        if (a < b) {\n            emit log(\"Error: a >= b not satisfied [int]\");\n            emit log_named_int(\"  Value a\", a);\n            emit log_named_int(\"  Value b\", b);\n            fail();\n        }\n    }\n\n    function assertGe(int256 a, int256 b, string memory err) internal {\n        if (a < b) {\n            emit log_named_string(\"Error\", err);\n            assertGe(a, b);\n        }\n    }\n\n    function assertGeDecimal(int256 a, int256 b, uint256 decimals) internal {\n        if (a < b) {\n            emit log(\"Error: a >= b not satisfied [decimal int]\");\n            emit log_named_decimal_int(\"  Value a\", a, decimals);\n            emit log_named_decimal_int(\"  Value b\", b, decimals);\n            fail();\n        }\n    }\n\n    function assertGeDecimal(int256 a, int256 b, uint256 decimals, string memory err) internal {\n        if (a < b) {\n            emit log_named_string(\"Error\", err);\n            assertGeDecimal(a, b, decimals);\n        }\n    }\n\n    function assertGeDecimal(uint256 a, uint256 b, uint256 decimals) internal {\n        if (a < b) {\n            emit log(\"Error: a >= b not satisfied [decimal uint]\");\n            emit log_named_decimal_uint(\"  Value a\", a, decimals);\n            emit log_named_decimal_uint(\"  Value b\", b, decimals);\n            fail();\n        }\n    }\n\n    function assertGeDecimal(uint256 a, uint256 b, uint256 decimals, string memory err) internal {\n        if (a < b) {\n            emit log_named_string(\"Error\", err);\n            assertGeDecimal(a, b, decimals);\n        }\n    }\n\n    function assertLt(uint256 a, uint256 b) internal {\n        if (a >= b) {\n            emit log(\"Error: a < b not satisfied [uint]\");\n            emit log_named_uint(\"  Value a\", a);\n            emit log_named_uint(\"  Value b\", b);\n            fail();\n        }\n    }\n\n    function assertLt(uint256 a, uint256 b, string memory err) internal {\n        if (a >= b) {\n            emit log_named_string(\"Error\", err);\n            assertLt(a, b);\n        }\n    }\n\n    function assertLt(int256 a, int256 b) internal {\n        if (a >= b) {\n            emit log(\"Error: a < b not satisfied [int]\");\n            emit log_named_int(\"  Value a\", a);\n            emit log_named_int(\"  Value b\", b);\n            fail();\n        }\n    }\n\n    function assertLt(int256 a, int256 b, string memory err) internal {\n        if (a >= b) {\n            emit log_named_string(\"Error\", err);\n            assertLt(a, b);\n        }\n    }\n\n    function assertLtDecimal(int256 a, int256 b, uint256 decimals) internal {\n        if (a >= b) {\n            emit log(\"Error: a < b not satisfied [decimal int]\");\n            emit log_named_decimal_int(\"  Value a\", a, decimals);\n            emit log_named_decimal_int(\"  Value b\", b, decimals);\n            fail();\n        }\n    }\n\n    function assertLtDecimal(int256 a, int256 b, uint256 decimals, string memory err) internal {\n        if (a >= b) {\n            emit log_named_string(\"Error\", err);\n            assertLtDecimal(a, b, decimals);\n        }\n    }\n\n    function assertLtDecimal(uint256 a, uint256 b, uint256 decimals) internal {\n        if (a >= b) {\n            emit log(\"Error: a < b not satisfied [decimal uint]\");\n            emit log_named_decimal_uint(\"  Value a\", a, decimals);\n            emit log_named_decimal_uint(\"  Value b\", b, decimals);\n            fail();\n        }\n    }\n\n    function assertLtDecimal(uint256 a, uint256 b, uint256 decimals, string memory err) internal {\n        if (a >= b) {\n            emit log_named_string(\"Error\", err);\n            assertLtDecimal(a, b, decimals);\n        }\n    }\n\n    function assertLe(uint256 a, uint256 b) internal {\n        if (a > b) {\n            emit log(\"Error: a <= b not satisfied [uint]\");\n            emit log_named_uint(\"  Value a\", a);\n            emit log_named_uint(\"  Value b\", b);\n            fail();\n        }\n    }\n\n    function assertLe(uint256 a, uint256 b, string memory err) internal {\n        if (a > b) {\n            emit log_named_string(\"Error\", err);\n            assertLe(a, b);\n        }\n    }\n\n    function assertLe(int256 a, int256 b) internal {\n        if (a > b) {\n            emit log(\"Error: a <= b not satisfied [int]\");\n            emit log_named_int(\"  Value a\", a);\n            emit log_named_int(\"  Value b\", b);\n            fail();\n        }\n    }\n\n    function assertLe(int256 a, int256 b, string memory err) internal {\n        if (a > b) {\n            emit log_named_string(\"Error\", err);\n            assertLe(a, b);\n        }\n    }\n\n    function assertLeDecimal(int256 a, int256 b, uint256 decimals) internal {\n        if (a > b) {\n            emit log(\"Error: a <= b not satisfied [decimal int]\");\n            emit log_named_decimal_int(\"  Value a\", a, decimals);\n            emit log_named_decimal_int(\"  Value b\", b, decimals);\n            fail();\n        }\n    }\n\n    function assertLeDecimal(int256 a, int256 b, uint256 decimals, string memory err) internal {\n        if (a > b) {\n            emit log_named_string(\"Error\", err);\n            assertLeDecimal(a, b, decimals);\n        }\n    }\n\n    function assertLeDecimal(uint256 a, uint256 b, uint256 decimals) internal {\n        if (a > b) {\n            emit log(\"Error: a <= b not satisfied [decimal uint]\");\n            emit log_named_decimal_uint(\"  Value a\", a, decimals);\n            emit log_named_decimal_uint(\"  Value b\", b, decimals);\n            fail();\n        }\n    }\n\n    function assertLeDecimal(uint256 a, uint256 b, uint256 decimals, string memory err) internal {\n        if (a > b) {\n            emit log_named_string(\"Error\", err);\n            assertGeDecimal(a, b, decimals);\n        }\n    }\n\n    function assertEq(string memory a, string memory b) internal {\n        if (keccak256(abi.encodePacked(a)) != keccak256(abi.encodePacked(b))) {\n            emit log(\"Error: a == b not satisfied [string]\");\n            emit log_named_string(\"  Value a\", a);\n            emit log_named_string(\"  Value b\", b);\n            fail();\n        }\n    }\n\n    function assertEq(string memory a, string memory b, string memory err) internal {\n        if (keccak256(abi.encodePacked(a)) != keccak256(abi.encodePacked(b))) {\n            emit log_named_string(\"Error\", err);\n            assertEq(a, b);\n        }\n    }\n\n    function checkEq0(bytes memory a, bytes memory b) internal pure returns (bool ok) {\n        ok = true;\n        if (a.length == b.length) {\n            for (uint256 i = 0; i < a.length; i++) {\n                if (a[i] != b[i]) {\n                    ok = false;\n                }\n            }\n        } else {\n            ok = false;\n        }\n    }\n\n    function assertEq0(bytes memory a, bytes memory b) internal {\n        if (!checkEq0(a, b)) {\n            emit log(\"Error: a == b not satisfied [bytes]\");\n            emit log_named_bytes(\"  Expected\", a);\n            emit log_named_bytes(\"    Actual\", b);\n            fail();\n        }\n    }\n\n    function assertEq0(bytes memory a, bytes memory b, string memory err) internal {\n        if (!checkEq0(a, b)) {\n            emit log_named_string(\"Error\", err);\n            assertEq0(a, b);\n        }\n    }\n\n    function assertEq(bytes memory a, bytes memory b) internal {\n        assertEq0(a, b);\n    }\n\n    function assertEq(bytes memory a, bytes memory b, string memory err) internal {\n        assertEq0(a, b, err);\n    }\n\n    function assertEq(bool a, bool b) internal {\n        if (a != b) {\n            emit log(\"Error: a == b not satisfied [bool]\");\n            emit log_named_string(\"  Expected\", b ? \"true\" : \"false\");\n            emit log_named_string(\"    Actual\", a ? \"true\" : \"false\");\n            fail();\n        }\n    }\n}\n"
  },
  {
    "path": "testdata/utils/Test.sol",
    "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity >=0.6.2 <0.9.0;\npragma experimental ABIEncoderV2;\n\nimport \"./DSTest.sol\";\nimport \"./Vm.sol\";\nimport \"./console.sol\";\n\ncontract Test is DSTest {\n    Vm public constant vm = Vm(HEVM_ADDRESS);\n}\n"
  },
  {
    "path": "testdata/utils/Vm.sol",
    "content": "// Automatically generated from `foundry-cheatcodes` Vm definitions. Do not modify manually.\n// This interface is just for internal testing purposes. Use `forge-std` instead.\n\n// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity >=0.6.2 <0.9.0;\npragma experimental ABIEncoderV2;\n\ninterface Vm {\n    enum CallerMode { None, Broadcast, RecurrentBroadcast, Prank, RecurrentPrank }\n    enum AccountAccessKind { Call, DelegateCall, CallCode, StaticCall, Create, SelfDestruct, Resume, Balance, Extcodesize, Extcodehash, Extcodecopy }\n    enum ForgeContext { TestGroup, Test, Coverage, Snapshot, ScriptGroup, ScriptDryRun, ScriptBroadcast, ScriptResume, Unknown }\n    enum BroadcastTxType { Call, Create, Create2 }\n    struct Log { bytes32[] topics; bytes data; address emitter; }\n    struct Rpc { string key; string url; }\n    struct EthGetLogs { address emitter; bytes32[] topics; bytes data; bytes32 blockHash; uint64 blockNumber; bytes32 transactionHash; uint64 transactionIndex; uint256 logIndex; bool removed; }\n    struct DirEntry { string errorMessage; string path; uint64 depth; bool isDir; bool isSymlink; }\n    struct FsMetadata { bool isDir; bool isSymlink; uint256 length; bool readOnly; uint256 modified; uint256 accessed; uint256 created; }\n    struct Wallet { address addr; uint256 publicKeyX; uint256 publicKeyY; uint256 privateKey; }\n    struct FfiResult { int32 exitCode; bytes stdout; bytes stderr; }\n    struct ChainInfo { uint256 forkId; uint256 chainId; }\n    struct Chain { string name; uint256 chainId; string chainAlias; string rpcUrl; }\n    struct AccountAccess { ChainInfo chainInfo; AccountAccessKind kind; address account; address accessor; bool initialized; uint256 oldBalance; uint256 newBalance; bytes deployedCode; uint256 value; bytes data; bool reverted; StorageAccess[] storageAccesses; uint64 depth; uint64 oldNonce; uint64 newNonce; }\n    struct StorageAccess { address account; bytes32 slot; bool isWrite; bytes32 previousValue; bytes32 newValue; bool reverted; }\n    struct Gas { uint64 gasLimit; uint64 gasTotalUsed; uint64 gasMemoryUsed; int64 gasRefunded; uint64 gasRemaining; }\n    struct DebugStep { uint256[] stack; bytes memoryInput; uint8 opcode; uint64 depth; bool isOutOfGas; address contractAddr; }\n    struct BroadcastTxSummary { bytes32 txHash; BroadcastTxType txType; address contractAddress; uint64 blockNumber; bool success; }\n    struct SignedDelegation { uint8 v; bytes32 r; bytes32 s; uint64 nonce; address implementation; }\n    struct PotentialRevert { address reverter; bool partialMatch; bytes revertData; }\n    struct AccessListItem { address target; bytes32[] storageKeys; }\n    function _expectCheatcodeRevert() external;\n    function _expectCheatcodeRevert(bytes4 revertData) external;\n    function _expectCheatcodeRevert(bytes calldata revertData) external;\n    function accessList(AccessListItem[] calldata access) external;\n    function accesses(address target) external view returns (bytes32[] memory readSlots, bytes32[] memory writeSlots);\n    function activeFork() external view returns (uint256 forkId);\n    function addr(uint256 privateKey) external pure returns (address keyAddr);\n    function allowCheatcodes(address account) external;\n    function assertApproxEqAbsDecimal(uint256 left, uint256 right, uint256 maxDelta, uint256 decimals) external pure;\n    function assertApproxEqAbsDecimal(uint256 left, uint256 right, uint256 maxDelta, uint256 decimals, string calldata error) external pure;\n    function assertApproxEqAbsDecimal(int256 left, int256 right, uint256 maxDelta, uint256 decimals) external pure;\n    function assertApproxEqAbsDecimal(int256 left, int256 right, uint256 maxDelta, uint256 decimals, string calldata error) external pure;\n    function assertApproxEqAbs(uint256 left, uint256 right, uint256 maxDelta) external pure;\n    function assertApproxEqAbs(uint256 left, uint256 right, uint256 maxDelta, string calldata error) external pure;\n    function assertApproxEqAbs(int256 left, int256 right, uint256 maxDelta) external pure;\n    function assertApproxEqAbs(int256 left, int256 right, uint256 maxDelta, string calldata error) external pure;\n    function assertApproxEqRelDecimal(uint256 left, uint256 right, uint256 maxPercentDelta, uint256 decimals) external pure;\n    function assertApproxEqRelDecimal(uint256 left, uint256 right, uint256 maxPercentDelta, uint256 decimals, string calldata error) external pure;\n    function assertApproxEqRelDecimal(int256 left, int256 right, uint256 maxPercentDelta, uint256 decimals) external pure;\n    function assertApproxEqRelDecimal(int256 left, int256 right, uint256 maxPercentDelta, uint256 decimals, string calldata error) external pure;\n    function assertApproxEqRel(uint256 left, uint256 right, uint256 maxPercentDelta) external pure;\n    function assertApproxEqRel(uint256 left, uint256 right, uint256 maxPercentDelta, string calldata error) external pure;\n    function assertApproxEqRel(int256 left, int256 right, uint256 maxPercentDelta) external pure;\n    function assertApproxEqRel(int256 left, int256 right, uint256 maxPercentDelta, string calldata error) external pure;\n    function assertEqDecimal(uint256 left, uint256 right, uint256 decimals) external pure;\n    function assertEqDecimal(uint256 left, uint256 right, uint256 decimals, string calldata error) external pure;\n    function assertEqDecimal(int256 left, int256 right, uint256 decimals) external pure;\n    function assertEqDecimal(int256 left, int256 right, uint256 decimals, string calldata error) external pure;\n    function assertEq(bool left, bool right) external pure;\n    function assertEq(bool left, bool right, string calldata error) external pure;\n    function assertEq(string calldata left, string calldata right) external pure;\n    function assertEq(string calldata left, string calldata right, string calldata error) external pure;\n    function assertEq(bytes calldata left, bytes calldata right) external pure;\n    function assertEq(bytes calldata left, bytes calldata right, string calldata error) external pure;\n    function assertEq(bool[] calldata left, bool[] calldata right) external pure;\n    function assertEq(bool[] calldata left, bool[] calldata right, string calldata error) external pure;\n    function assertEq(uint256[] calldata left, uint256[] calldata right) external pure;\n    function assertEq(uint256[] calldata left, uint256[] calldata right, string calldata error) external pure;\n    function assertEq(int256[] calldata left, int256[] calldata right) external pure;\n    function assertEq(int256[] calldata left, int256[] calldata right, string calldata error) external pure;\n    function assertEq(uint256 left, uint256 right) external pure;\n    function assertEq(address[] calldata left, address[] calldata right) external pure;\n    function assertEq(address[] calldata left, address[] calldata right, string calldata error) external pure;\n    function assertEq(bytes32[] calldata left, bytes32[] calldata right) external pure;\n    function assertEq(bytes32[] calldata left, bytes32[] calldata right, string calldata error) external pure;\n    function assertEq(string[] calldata left, string[] calldata right) external pure;\n    function assertEq(string[] calldata left, string[] calldata right, string calldata error) external pure;\n    function assertEq(bytes[] calldata left, bytes[] calldata right) external pure;\n    function assertEq(bytes[] calldata left, bytes[] calldata right, string calldata error) external pure;\n    function assertEq(uint256 left, uint256 right, string calldata error) external pure;\n    function assertEq(int256 left, int256 right) external pure;\n    function assertEq(int256 left, int256 right, string calldata error) external pure;\n    function assertEq(address left, address right) external pure;\n    function assertEq(address left, address right, string calldata error) external pure;\n    function assertEq(bytes32 left, bytes32 right) external pure;\n    function assertEq(bytes32 left, bytes32 right, string calldata error) external pure;\n    function assertFalse(bool condition) external pure;\n    function assertFalse(bool condition, string calldata error) external pure;\n    function assertGeDecimal(uint256 left, uint256 right, uint256 decimals) external pure;\n    function assertGeDecimal(uint256 left, uint256 right, uint256 decimals, string calldata error) external pure;\n    function assertGeDecimal(int256 left, int256 right, uint256 decimals) external pure;\n    function assertGeDecimal(int256 left, int256 right, uint256 decimals, string calldata error) external pure;\n    function assertGe(uint256 left, uint256 right) external pure;\n    function assertGe(uint256 left, uint256 right, string calldata error) external pure;\n    function assertGe(int256 left, int256 right) external pure;\n    function assertGe(int256 left, int256 right, string calldata error) external pure;\n    function assertGtDecimal(uint256 left, uint256 right, uint256 decimals) external pure;\n    function assertGtDecimal(uint256 left, uint256 right, uint256 decimals, string calldata error) external pure;\n    function assertGtDecimal(int256 left, int256 right, uint256 decimals) external pure;\n    function assertGtDecimal(int256 left, int256 right, uint256 decimals, string calldata error) external pure;\n    function assertGt(uint256 left, uint256 right) external pure;\n    function assertGt(uint256 left, uint256 right, string calldata error) external pure;\n    function assertGt(int256 left, int256 right) external pure;\n    function assertGt(int256 left, int256 right, string calldata error) external pure;\n    function assertLeDecimal(uint256 left, uint256 right, uint256 decimals) external pure;\n    function assertLeDecimal(uint256 left, uint256 right, uint256 decimals, string calldata error) external pure;\n    function assertLeDecimal(int256 left, int256 right, uint256 decimals) external pure;\n    function assertLeDecimal(int256 left, int256 right, uint256 decimals, string calldata error) external pure;\n    function assertLe(uint256 left, uint256 right) external pure;\n    function assertLe(uint256 left, uint256 right, string calldata error) external pure;\n    function assertLe(int256 left, int256 right) external pure;\n    function assertLe(int256 left, int256 right, string calldata error) external pure;\n    function assertLtDecimal(uint256 left, uint256 right, uint256 decimals) external pure;\n    function assertLtDecimal(uint256 left, uint256 right, uint256 decimals, string calldata error) external pure;\n    function assertLtDecimal(int256 left, int256 right, uint256 decimals) external pure;\n    function assertLtDecimal(int256 left, int256 right, uint256 decimals, string calldata error) external pure;\n    function assertLt(uint256 left, uint256 right) external pure;\n    function assertLt(uint256 left, uint256 right, string calldata error) external pure;\n    function assertLt(int256 left, int256 right) external pure;\n    function assertLt(int256 left, int256 right, string calldata error) external pure;\n    function assertNotEqDecimal(uint256 left, uint256 right, uint256 decimals) external pure;\n    function assertNotEqDecimal(uint256 left, uint256 right, uint256 decimals, string calldata error) external pure;\n    function assertNotEqDecimal(int256 left, int256 right, uint256 decimals) external pure;\n    function assertNotEqDecimal(int256 left, int256 right, uint256 decimals, string calldata error) external pure;\n    function assertNotEq(bool left, bool right) external pure;\n    function assertNotEq(bool left, bool right, string calldata error) external pure;\n    function assertNotEq(string calldata left, string calldata right) external pure;\n    function assertNotEq(string calldata left, string calldata right, string calldata error) external pure;\n    function assertNotEq(bytes calldata left, bytes calldata right) external pure;\n    function assertNotEq(bytes calldata left, bytes calldata right, string calldata error) external pure;\n    function assertNotEq(bool[] calldata left, bool[] calldata right) external pure;\n    function assertNotEq(bool[] calldata left, bool[] calldata right, string calldata error) external pure;\n    function assertNotEq(uint256[] calldata left, uint256[] calldata right) external pure;\n    function assertNotEq(uint256[] calldata left, uint256[] calldata right, string calldata error) external pure;\n    function assertNotEq(int256[] calldata left, int256[] calldata right) external pure;\n    function assertNotEq(int256[] calldata left, int256[] calldata right, string calldata error) external pure;\n    function assertNotEq(uint256 left, uint256 right) external pure;\n    function assertNotEq(address[] calldata left, address[] calldata right) external pure;\n    function assertNotEq(address[] calldata left, address[] calldata right, string calldata error) external pure;\n    function assertNotEq(bytes32[] calldata left, bytes32[] calldata right) external pure;\n    function assertNotEq(bytes32[] calldata left, bytes32[] calldata right, string calldata error) external pure;\n    function assertNotEq(string[] calldata left, string[] calldata right) external pure;\n    function assertNotEq(string[] calldata left, string[] calldata right, string calldata error) external pure;\n    function assertNotEq(bytes[] calldata left, bytes[] calldata right) external pure;\n    function assertNotEq(bytes[] calldata left, bytes[] calldata right, string calldata error) external pure;\n    function assertNotEq(uint256 left, uint256 right, string calldata error) external pure;\n    function assertNotEq(int256 left, int256 right) external pure;\n    function assertNotEq(int256 left, int256 right, string calldata error) external pure;\n    function assertNotEq(address left, address right) external pure;\n    function assertNotEq(address left, address right, string calldata error) external pure;\n    function assertNotEq(bytes32 left, bytes32 right) external pure;\n    function assertNotEq(bytes32 left, bytes32 right, string calldata error) external pure;\n    function assertTrue(bool condition) external pure;\n    function assertTrue(bool condition, string calldata error) external pure;\n    function assume(bool condition) external pure;\n    function assumeNoRevert() external pure;\n    function assumeNoRevert(PotentialRevert calldata potentialRevert) external pure;\n    function assumeNoRevert(PotentialRevert[] calldata potentialReverts) external pure;\n    function attachBlob(bytes calldata blob) external;\n    function attachDelegation(SignedDelegation calldata signedDelegation) external;\n    function attachDelegation(SignedDelegation calldata signedDelegation, bool crossChain) external;\n    function blobBaseFee(uint256 newBlobBaseFee) external;\n    function blobhashes(bytes32[] calldata hashes) external;\n    function bound(uint256 current, uint256 min, uint256 max) external view returns (uint256);\n    function bound(int256 current, int256 min, int256 max) external view returns (int256);\n    function breakpoint(string calldata char) external pure;\n    function breakpoint(string calldata char, bool value) external pure;\n    function broadcastRawTransaction(bytes calldata data) external;\n    function broadcast() external;\n    function broadcast(address signer) external;\n    function broadcast(uint256 privateKey) external;\n    function chainId(uint256 newChainId) external;\n    function clearMockedCalls() external;\n    function cloneAccount(address source, address target) external;\n    function closeFile(string calldata path) external;\n    function coinbase(address newCoinbase) external;\n    function computeCreate2Address(bytes32 salt, bytes32 initCodeHash, address deployer) external pure returns (address);\n    function computeCreate2Address(bytes32 salt, bytes32 initCodeHash) external pure returns (address);\n    function computeCreateAddress(address deployer, uint256 nonce) external pure returns (address);\n    function contains(string calldata subject, string calldata search) external pure returns (bool result);\n    function cool(address target) external;\n    function coolSlot(address target, bytes32 slot) external;\n    function copyFile(string calldata from, string calldata to) external returns (uint64 copied);\n    function copyStorage(address from, address to) external;\n    function createDir(string calldata path, bool recursive) external;\n    function createEd25519Key(bytes32 salt) external pure returns (bytes32 publicKey, bytes32 privateKey);\n    function createFork(string calldata urlOrAlias) external returns (uint256 forkId);\n    function createFork(string calldata urlOrAlias, uint256 blockNumber) external returns (uint256 forkId);\n    function createFork(string calldata urlOrAlias, bytes32 txHash) external returns (uint256 forkId);\n    function createSelectFork(string calldata urlOrAlias) external returns (uint256 forkId);\n    function createSelectFork(string calldata urlOrAlias, uint256 blockNumber) external returns (uint256 forkId);\n    function createSelectFork(string calldata urlOrAlias, bytes32 txHash) external returns (uint256 forkId);\n    function createWallet(string calldata walletLabel) external returns (Wallet memory wallet);\n    function createWallet(uint256 privateKey) external returns (Wallet memory wallet);\n    function createWallet(uint256 privateKey, string calldata walletLabel) external returns (Wallet memory wallet);\n    function currentFilePath() external view returns (string memory path);\n    function deal(address account, uint256 newBalance) external;\n    function deleteSnapshot(uint256 snapshotId) external returns (bool success);\n    function deleteSnapshots() external;\n    function deleteStateSnapshot(uint256 snapshotId) external returns (bool success);\n    function deleteStateSnapshots() external;\n    function deployCode(string calldata artifactPath) external returns (address deployedAddress);\n    function deployCode(string calldata artifactPath, bytes calldata constructorArgs) external returns (address deployedAddress);\n    function deployCode(string calldata artifactPath, uint256 value) external returns (address deployedAddress);\n    function deployCode(string calldata artifactPath, bytes calldata constructorArgs, uint256 value) external returns (address deployedAddress);\n    function deployCode(string calldata artifactPath, bytes32 salt) external returns (address deployedAddress);\n    function deployCode(string calldata artifactPath, bytes calldata constructorArgs, bytes32 salt) external returns (address deployedAddress);\n    function deployCode(string calldata artifactPath, uint256 value, bytes32 salt) external returns (address deployedAddress);\n    function deployCode(string calldata artifactPath, bytes calldata constructorArgs, uint256 value, bytes32 salt) external returns (address deployedAddress);\n    function deriveKey(string calldata mnemonic, uint32 index) external pure returns (uint256 privateKey);\n    function deriveKey(string calldata mnemonic, string calldata derivationPath, uint32 index) external pure returns (uint256 privateKey);\n    function deriveKey(string calldata mnemonic, uint32 index, string calldata language) external pure returns (uint256 privateKey);\n    function deriveKey(string calldata mnemonic, string calldata derivationPath, uint32 index, string calldata language) external pure returns (uint256 privateKey);\n    function difficulty(uint256 newDifficulty) external;\n    function dumpState(string calldata pathToStateJson) external;\n    function eip712HashStruct(string calldata typeNameOrDefinition, bytes calldata abiEncodedData) external pure returns (bytes32 typeHash);\n    function eip712HashStruct(string calldata bindingsPath, string calldata typeName, bytes calldata abiEncodedData) external pure returns (bytes32 typeHash);\n    function eip712HashType(string calldata typeNameOrDefinition) external pure returns (bytes32 typeHash);\n    function eip712HashType(string calldata bindingsPath, string calldata typeName) external pure returns (bytes32 typeHash);\n    function eip712HashTypedData(string calldata jsonData) external pure returns (bytes32 digest);\n    function ensNamehash(string calldata name) external pure returns (bytes32);\n    function envAddress(string calldata name) external view returns (address value);\n    function envAddress(string calldata name, string calldata delim) external view returns (address[] memory value);\n    function envBool(string calldata name) external view returns (bool value);\n    function envBool(string calldata name, string calldata delim) external view returns (bool[] memory value);\n    function envBytes32(string calldata name) external view returns (bytes32 value);\n    function envBytes32(string calldata name, string calldata delim) external view returns (bytes32[] memory value);\n    function envBytes(string calldata name) external view returns (bytes memory value);\n    function envBytes(string calldata name, string calldata delim) external view returns (bytes[] memory value);\n    function envExists(string calldata name) external view returns (bool result);\n    function envInt(string calldata name) external view returns (int256 value);\n    function envInt(string calldata name, string calldata delim) external view returns (int256[] memory value);\n    function envOr(string calldata name, bool defaultValue) external view returns (bool value);\n    function envOr(string calldata name, uint256 defaultValue) external view returns (uint256 value);\n    function envOr(string calldata name, string calldata delim, address[] calldata defaultValue) external view returns (address[] memory value);\n    function envOr(string calldata name, string calldata delim, bytes32[] calldata defaultValue) external view returns (bytes32[] memory value);\n    function envOr(string calldata name, string calldata delim, string[] calldata defaultValue) external view returns (string[] memory value);\n    function envOr(string calldata name, string calldata delim, bytes[] calldata defaultValue) external view returns (bytes[] memory value);\n    function envOr(string calldata name, int256 defaultValue) external view returns (int256 value);\n    function envOr(string calldata name, address defaultValue) external view returns (address value);\n    function envOr(string calldata name, bytes32 defaultValue) external view returns (bytes32 value);\n    function envOr(string calldata name, string calldata defaultValue) external view returns (string memory value);\n    function envOr(string calldata name, bytes calldata defaultValue) external view returns (bytes memory value);\n    function envOr(string calldata name, string calldata delim, bool[] calldata defaultValue) external view returns (bool[] memory value);\n    function envOr(string calldata name, string calldata delim, uint256[] calldata defaultValue) external view returns (uint256[] memory value);\n    function envOr(string calldata name, string calldata delim, int256[] calldata defaultValue) external view returns (int256[] memory value);\n    function envString(string calldata name) external view returns (string memory value);\n    function envString(string calldata name, string calldata delim) external view returns (string[] memory value);\n    function envUint(string calldata name) external view returns (uint256 value);\n    function envUint(string calldata name, string calldata delim) external view returns (uint256[] memory value);\n    function etch(address target, bytes calldata newRuntimeBytecode) external;\n    function eth_getLogs(uint256 fromBlock, uint256 toBlock, address target, bytes32[] calldata topics) external view returns (EthGetLogs[] memory logs);\n    function executeTransaction(bytes calldata rawTx) external returns (bytes memory);\n    function exists(string calldata path) external view returns (bool result);\n    function expectCallMinGas(address callee, uint256 msgValue, uint64 minGas, bytes calldata data) external;\n    function expectCallMinGas(address callee, uint256 msgValue, uint64 minGas, bytes calldata data, uint64 count) external;\n    function expectCall(address callee, bytes calldata data) external;\n    function expectCall(address callee, bytes calldata data, uint64 count) external;\n    function expectCall(address callee, uint256 msgValue, bytes calldata data) external;\n    function expectCall(address callee, uint256 msgValue, bytes calldata data, uint64 count) external;\n    function expectCall(address callee, uint256 msgValue, uint64 gas, bytes calldata data) external;\n    function expectCall(address callee, uint256 msgValue, uint64 gas, bytes calldata data, uint64 count) external;\n    function expectCreate(bytes calldata bytecode, address deployer) external;\n    function expectCreate2(bytes calldata bytecode, address deployer) external;\n    function expectEmitAnonymous(bool checkTopic0, bool checkTopic1, bool checkTopic2, bool checkTopic3, bool checkData) external;\n    function expectEmitAnonymous(bool checkTopic0, bool checkTopic1, bool checkTopic2, bool checkTopic3, bool checkData, address emitter) external;\n    function expectEmitAnonymous() external;\n    function expectEmitAnonymous(address emitter) external;\n    function expectEmit(bool checkTopic1, bool checkTopic2, bool checkTopic3, bool checkData) external;\n    function expectEmit(bool checkTopic1, bool checkTopic2, bool checkTopic3, bool checkData, address emitter) external;\n    function expectEmit() external;\n    function expectEmit(address emitter) external;\n    function expectEmit(bool checkTopic1, bool checkTopic2, bool checkTopic3, bool checkData, uint64 count) external;\n    function expectEmit(bool checkTopic1, bool checkTopic2, bool checkTopic3, bool checkData, address emitter, uint64 count) external;\n    function expectEmit(uint64 count) external;\n    function expectEmit(address emitter, uint64 count) external;\n    function expectPartialRevert(bytes4 revertData) external;\n    function expectPartialRevert(bytes4 revertData, address reverter) external;\n    function expectRevert() external;\n    function expectRevert(bytes4 revertData) external;\n    function expectRevert(bytes4 revertData, address reverter, uint64 count) external;\n    function expectRevert(bytes calldata revertData, address reverter, uint64 count) external;\n    function expectRevert(bytes calldata revertData) external;\n    function expectRevert(address reverter) external;\n    function expectRevert(bytes4 revertData, address reverter) external;\n    function expectRevert(bytes calldata revertData, address reverter) external;\n    function expectRevert(uint64 count) external;\n    function expectRevert(bytes4 revertData, uint64 count) external;\n    function expectRevert(bytes calldata revertData, uint64 count) external;\n    function expectRevert(address reverter, uint64 count) external;\n    function expectSafeMemory(uint64 min, uint64 max) external;\n    function expectSafeMemoryCall(uint64 min, uint64 max) external;\n    function fee(uint256 newBasefee) external;\n    function ffi(string[] calldata commandInput) external returns (bytes memory result);\n    function foundryVersionAtLeast(string calldata version) external view returns (bool);\n    function foundryVersionCmp(string calldata version) external view returns (int256);\n    function fromRlp(bytes calldata rlp) external pure returns (bytes[] memory data);\n    function fsMetadata(string calldata path) external view returns (FsMetadata memory metadata);\n    function getArtifactPathByCode(bytes calldata code) external view returns (string memory path);\n    function getArtifactPathByDeployedCode(bytes calldata deployedCode) external view returns (string memory path);\n    function getBlobBaseFee() external view returns (uint256 blobBaseFee);\n    function getBlobhashes() external view returns (bytes32[] memory hashes);\n    function getBlockNumber() external view returns (uint256 height);\n    function getBlockTimestamp() external view returns (uint256 timestamp);\n    function getBroadcast(string calldata contractName, uint64 chainId, BroadcastTxType txType) external view returns (BroadcastTxSummary memory);\n    function getBroadcasts(string calldata contractName, uint64 chainId, BroadcastTxType txType) external view returns (BroadcastTxSummary[] memory);\n    function getBroadcasts(string calldata contractName, uint64 chainId) external view returns (BroadcastTxSummary[] memory);\n    function getChainId() external view returns (uint256 blockChainId);\n    function getChain(string calldata chainAlias) external view returns (Chain memory chain);\n    function getChain(uint256 chainId) external view returns (Chain memory chain);\n    function getCode(string calldata artifactPath) external view returns (bytes memory creationBytecode);\n    function getDeployedCode(string calldata artifactPath) external view returns (bytes memory runtimeBytecode);\n    function getDeployment(string calldata contractName) external view returns (address deployedAddress);\n    function getDeployment(string calldata contractName, uint64 chainId) external view returns (address deployedAddress);\n    function getDeployments(string calldata contractName, uint64 chainId) external view returns (address[] memory deployedAddresses);\n    function getEvmVersion() external pure returns (string memory evm);\n    function getFoundryVersion() external view returns (string memory version);\n    function getLabel(address account) external view returns (string memory currentLabel);\n    function getMappingKeyAndParentOf(address target, bytes32 elementSlot) external view returns (bool found, bytes32 key, bytes32 parent);\n    function getMappingLength(address target, bytes32 mappingSlot) external view returns (uint256 length);\n    function getMappingSlotAt(address target, bytes32 mappingSlot, uint256 idx) external view returns (bytes32 value);\n    function getNonce(address account) external view returns (uint64 nonce);\n    function getNonce(Wallet calldata wallet) external view returns (uint64 nonce);\n    function getRawBlockHeader(uint256 blockNumber) external view returns (bytes memory rlpHeader);\n    function getRecordedLogs() external view returns (Log[] memory logs);\n    function getRecordedLogsJson() external view returns (string memory logsJson);\n    function getStateDiff() external view returns (string memory diff);\n    function getStateDiffJson() external view returns (string memory diff);\n    function getStorageAccesses() external view returns (StorageAccess[] memory storageAccesses);\n    function getStorageSlots(address target, string calldata variableName) external view returns (uint256[] memory slots);\n    function getWallets() external view returns (address[] memory wallets);\n    function indexOf(string calldata input, string calldata key) external pure returns (uint256);\n    function interceptInitcode() external;\n    function isContext(ForgeContext context) external view returns (bool result);\n    function isDir(string calldata path) external view returns (bool result);\n    function isFile(string calldata path) external view returns (bool result);\n    function isPersistent(address account) external view returns (bool persistent);\n    function keyExists(string calldata json, string calldata key) external view returns (bool);\n    function keyExistsJson(string calldata json, string calldata key) external view returns (bool);\n    function keyExistsToml(string calldata toml, string calldata key) external view returns (bool);\n    function label(address account, string calldata newLabel) external;\n    function lastCallGas() external view returns (Gas memory gas);\n    function load(address target, bytes32 slot) external view returns (bytes32 data);\n    function loadAllocs(string calldata pathToAllocsJson) external;\n    function makePersistent(address account) external;\n    function makePersistent(address account0, address account1) external;\n    function makePersistent(address account0, address account1, address account2) external;\n    function makePersistent(address[] calldata accounts) external;\n    function mockCallRevert(address callee, bytes calldata data, bytes calldata revertData) external;\n    function mockCallRevert(address callee, uint256 msgValue, bytes calldata data, bytes calldata revertData) external;\n    function mockCallRevert(address callee, bytes4 data, bytes calldata revertData) external;\n    function mockCallRevert(address callee, uint256 msgValue, bytes4 data, bytes calldata revertData) external;\n    function mockCall(address callee, bytes calldata data, bytes calldata returnData) external;\n    function mockCall(address callee, uint256 msgValue, bytes calldata data, bytes calldata returnData) external;\n    function mockCall(address callee, bytes4 data, bytes calldata returnData) external;\n    function mockCall(address callee, uint256 msgValue, bytes4 data, bytes calldata returnData) external;\n    function mockCalls(address callee, bytes calldata data, bytes[] calldata returnData) external;\n    function mockCalls(address callee, uint256 msgValue, bytes calldata data, bytes[] calldata returnData) external;\n    function mockFunction(address callee, address target, bytes calldata data) external;\n    function noAccessList() external;\n    function parseAddress(string calldata stringifiedValue) external pure returns (address parsedValue);\n    function parseBool(string calldata stringifiedValue) external pure returns (bool parsedValue);\n    function parseBytes(string calldata stringifiedValue) external pure returns (bytes memory parsedValue);\n    function parseBytes32(string calldata stringifiedValue) external pure returns (bytes32 parsedValue);\n    function parseInt(string calldata stringifiedValue) external pure returns (int256 parsedValue);\n    function parseJsonAddress(string calldata json, string calldata key) external pure returns (address);\n    function parseJsonAddressArray(string calldata json, string calldata key) external pure returns (address[] memory);\n    function parseJsonBool(string calldata json, string calldata key) external pure returns (bool);\n    function parseJsonBoolArray(string calldata json, string calldata key) external pure returns (bool[] memory);\n    function parseJsonBytes(string calldata json, string calldata key) external pure returns (bytes memory);\n    function parseJsonBytes32(string calldata json, string calldata key) external pure returns (bytes32);\n    function parseJsonBytes32Array(string calldata json, string calldata key) external pure returns (bytes32[] memory);\n    function parseJsonBytesArray(string calldata json, string calldata key) external pure returns (bytes[] memory);\n    function parseJsonInt(string calldata json, string calldata key) external pure returns (int256);\n    function parseJsonIntArray(string calldata json, string calldata key) external pure returns (int256[] memory);\n    function parseJsonKeys(string calldata json, string calldata key) external pure returns (string[] memory keys);\n    function parseJsonString(string calldata json, string calldata key) external pure returns (string memory);\n    function parseJsonStringArray(string calldata json, string calldata key) external pure returns (string[] memory);\n    function parseJsonTypeArray(string calldata json, string calldata key, string calldata typeDescription) external pure returns (bytes memory);\n    function parseJsonType(string calldata json, string calldata typeDescription) external pure returns (bytes memory);\n    function parseJsonType(string calldata json, string calldata key, string calldata typeDescription) external pure returns (bytes memory);\n    function parseJsonUint(string calldata json, string calldata key) external pure returns (uint256);\n    function parseJsonUintArray(string calldata json, string calldata key) external pure returns (uint256[] memory);\n    function parseJson(string calldata json) external pure returns (bytes memory abiEncodedData);\n    function parseJson(string calldata json, string calldata key) external pure returns (bytes memory abiEncodedData);\n    function parseTomlAddress(string calldata toml, string calldata key) external pure returns (address);\n    function parseTomlAddressArray(string calldata toml, string calldata key) external pure returns (address[] memory);\n    function parseTomlBool(string calldata toml, string calldata key) external pure returns (bool);\n    function parseTomlBoolArray(string calldata toml, string calldata key) external pure returns (bool[] memory);\n    function parseTomlBytes(string calldata toml, string calldata key) external pure returns (bytes memory);\n    function parseTomlBytes32(string calldata toml, string calldata key) external pure returns (bytes32);\n    function parseTomlBytes32Array(string calldata toml, string calldata key) external pure returns (bytes32[] memory);\n    function parseTomlBytesArray(string calldata toml, string calldata key) external pure returns (bytes[] memory);\n    function parseTomlInt(string calldata toml, string calldata key) external pure returns (int256);\n    function parseTomlIntArray(string calldata toml, string calldata key) external pure returns (int256[] memory);\n    function parseTomlKeys(string calldata toml, string calldata key) external pure returns (string[] memory keys);\n    function parseTomlString(string calldata toml, string calldata key) external pure returns (string memory);\n    function parseTomlStringArray(string calldata toml, string calldata key) external pure returns (string[] memory);\n    function parseTomlTypeArray(string calldata toml, string calldata key, string calldata typeDescription) external pure returns (bytes memory);\n    function parseTomlType(string calldata toml, string calldata typeDescription) external pure returns (bytes memory);\n    function parseTomlType(string calldata toml, string calldata key, string calldata typeDescription) external pure returns (bytes memory);\n    function parseTomlUint(string calldata toml, string calldata key) external pure returns (uint256);\n    function parseTomlUintArray(string calldata toml, string calldata key) external pure returns (uint256[] memory);\n    function parseToml(string calldata toml) external pure returns (bytes memory abiEncodedData);\n    function parseToml(string calldata toml, string calldata key) external pure returns (bytes memory abiEncodedData);\n    function parseUint(string calldata stringifiedValue) external pure returns (uint256 parsedValue);\n    function pauseGasMetering() external;\n    function pauseTracing() external view;\n    function prank(address msgSender) external;\n    function prank(address msgSender, address txOrigin) external;\n    function prank(address msgSender, bool delegateCall) external;\n    function prank(address msgSender, address txOrigin, bool delegateCall) external;\n    function prevrandao(bytes32 newPrevrandao) external;\n    function prevrandao(uint256 newPrevrandao) external;\n    function projectRoot() external view returns (string memory path);\n    function prompt(string calldata promptText) external returns (string memory input);\n    function promptAddress(string calldata promptText) external returns (address);\n    function promptSecret(string calldata promptText) external returns (string memory input);\n    function promptSecretUint(string calldata promptText) external returns (uint256);\n    function promptUint(string calldata promptText) external returns (uint256);\n    function publicKeyEd25519(bytes32 privateKey) external pure returns (bytes32 publicKey);\n    function publicKeyP256(uint256 privateKey) external pure returns (uint256 publicKeyX, uint256 publicKeyY);\n    function randomAddress() external view returns (address);\n    function randomBool() external view returns (bool);\n    function randomBytes(uint256 len) external view returns (bytes memory);\n    function randomBytes4() external view returns (bytes4);\n    function randomBytes8() external view returns (bytes8);\n    function randomInt() external view returns (int256);\n    function randomInt(uint256 bits) external view returns (int256);\n    function randomUint() external view returns (uint256);\n    function randomUint(uint256 min, uint256 max) external view returns (uint256);\n    function randomUint(uint256 bits) external view returns (uint256);\n    function readCallers() external view returns (CallerMode callerMode, address msgSender, address txOrigin);\n    function readDir(string calldata path) external view returns (DirEntry[] memory entries);\n    function readDir(string calldata path, uint64 maxDepth) external view returns (DirEntry[] memory entries);\n    function readDir(string calldata path, uint64 maxDepth, bool followLinks) external view returns (DirEntry[] memory entries);\n    function readFile(string calldata path) external view returns (string memory data);\n    function readFileBinary(string calldata path) external view returns (bytes memory data);\n    function readLine(string calldata path) external view returns (string memory line);\n    function readLink(string calldata linkPath) external view returns (string memory targetPath);\n    function record() external;\n    function recordLogs() external;\n    function rememberKey(uint256 privateKey) external returns (address keyAddr);\n    function rememberKeys(string calldata mnemonic, string calldata derivationPath, uint32 count) external returns (address[] memory keyAddrs);\n    function rememberKeys(string calldata mnemonic, string calldata derivationPath, string calldata language, uint32 count) external returns (address[] memory keyAddrs);\n    function removeDir(string calldata path, bool recursive) external;\n    function removeFile(string calldata path) external;\n    function replace(string calldata input, string calldata from, string calldata to) external pure returns (string memory output);\n    function resetGasMetering() external;\n    function resetNonce(address account) external;\n    function resolveEnv(string calldata input) external returns (string memory);\n    function resumeGasMetering() external;\n    function resumeTracing() external view;\n    function revertTo(uint256 snapshotId) external returns (bool success);\n    function revertToAndDelete(uint256 snapshotId) external returns (bool success);\n    function revertToState(uint256 snapshotId) external returns (bool success);\n    function revertToStateAndDelete(uint256 snapshotId) external returns (bool success);\n    function revokePersistent(address account) external;\n    function revokePersistent(address[] calldata accounts) external;\n    function roll(uint256 newHeight) external;\n    function rollFork(uint256 blockNumber) external;\n    function rollFork(bytes32 txHash) external;\n    function rollFork(uint256 forkId, uint256 blockNumber) external;\n    function rollFork(uint256 forkId, bytes32 txHash) external;\n    function rpcUrl(string calldata rpcAlias) external view returns (string memory json);\n    function rpcUrlStructs() external view returns (Rpc[] memory urls);\n    function rpcUrls() external view returns (string[2][] memory urls);\n    function rpc(string calldata method, string calldata params) external returns (bytes memory data);\n    function rpc(string calldata urlOrAlias, string calldata method, string calldata params) external returns (bytes memory data);\n    function selectFork(uint256 forkId) external;\n    function serializeAddress(string calldata objectKey, string calldata valueKey, address value) external returns (string memory json);\n    function serializeAddress(string calldata objectKey, string calldata valueKey, address[] calldata values) external returns (string memory json);\n    function serializeBool(string calldata objectKey, string calldata valueKey, bool value) external returns (string memory json);\n    function serializeBool(string calldata objectKey, string calldata valueKey, bool[] calldata values) external returns (string memory json);\n    function serializeBytes32(string calldata objectKey, string calldata valueKey, bytes32 value) external returns (string memory json);\n    function serializeBytes32(string calldata objectKey, string calldata valueKey, bytes32[] calldata values) external returns (string memory json);\n    function serializeBytes(string calldata objectKey, string calldata valueKey, bytes calldata value) external returns (string memory json);\n    function serializeBytes(string calldata objectKey, string calldata valueKey, bytes[] calldata values) external returns (string memory json);\n    function serializeInt(string calldata objectKey, string calldata valueKey, int256 value) external returns (string memory json);\n    function serializeInt(string calldata objectKey, string calldata valueKey, int256[] calldata values) external returns (string memory json);\n    function serializeJson(string calldata objectKey, string calldata value) external returns (string memory json);\n    function serializeJsonType(string calldata typeDescription, bytes calldata value) external pure returns (string memory json);\n    function serializeJsonType(string calldata objectKey, string calldata valueKey, string calldata typeDescription, bytes calldata value) external returns (string memory json);\n    function serializeString(string calldata objectKey, string calldata valueKey, string calldata value) external returns (string memory json);\n    function serializeString(string calldata objectKey, string calldata valueKey, string[] calldata values) external returns (string memory json);\n    function serializeUintToHex(string calldata objectKey, string calldata valueKey, uint256 value) external returns (string memory json);\n    function serializeUint(string calldata objectKey, string calldata valueKey, uint256 value) external returns (string memory json);\n    function serializeUint(string calldata objectKey, string calldata valueKey, uint256[] calldata values) external returns (string memory json);\n    function setArbitraryStorage(address target) external;\n    function setArbitraryStorage(address target, bool overwrite) external;\n    function setBlockhash(uint256 blockNumber, bytes32 blockHash) external;\n    function setEnv(string calldata name, string calldata value) external;\n    function setEvmVersion(string calldata evm) external;\n    function setNonce(address account, uint64 newNonce) external;\n    function setNonceUnsafe(address account, uint64 newNonce) external;\n    function setSeed(uint256 seed) external;\n    function shuffle(uint256[] calldata array) external returns (uint256[] memory);\n    function signAndAttachDelegation(address implementation, uint256 privateKey) external returns (SignedDelegation memory signedDelegation);\n    function signAndAttachDelegation(address implementation, uint256 privateKey, uint64 nonce) external returns (SignedDelegation memory signedDelegation);\n    function signAndAttachDelegation(address implementation, uint256 privateKey, bool crossChain) external returns (SignedDelegation memory signedDelegation);\n    function signCompact(Wallet calldata wallet, bytes32 digest) external pure returns (bytes32 r, bytes32 vs);\n    function signCompact(uint256 privateKey, bytes32 digest) external pure returns (bytes32 r, bytes32 vs);\n    function signCompact(bytes32 digest) external pure returns (bytes32 r, bytes32 vs);\n    function signCompact(address signer, bytes32 digest) external pure returns (bytes32 r, bytes32 vs);\n    function signDelegation(address implementation, uint256 privateKey) external returns (SignedDelegation memory signedDelegation);\n    function signDelegation(address implementation, uint256 privateKey, uint64 nonce) external returns (SignedDelegation memory signedDelegation);\n    function signDelegation(address implementation, uint256 privateKey, bool crossChain) external returns (SignedDelegation memory signedDelegation);\n    function signEd25519(bytes calldata namespace, bytes calldata message, bytes32 privateKey) external pure returns (bytes memory signature);\n    function signP256(uint256 privateKey, bytes32 digest) external pure returns (bytes32 r, bytes32 s);\n    function signWithNonceUnsafe(uint256 privateKey, bytes32 digest, uint256 nonce) external pure returns (uint8 v, bytes32 r, bytes32 s);\n    function sign(Wallet calldata wallet, bytes32 digest) external pure returns (uint8 v, bytes32 r, bytes32 s);\n    function sign(uint256 privateKey, bytes32 digest) external pure returns (uint8 v, bytes32 r, bytes32 s);\n    function sign(bytes32 digest) external pure returns (uint8 v, bytes32 r, bytes32 s);\n    function sign(address signer, bytes32 digest) external pure returns (uint8 v, bytes32 r, bytes32 s);\n    function skip(bool skipTest) external;\n    function skip(bool skipTest, string calldata reason) external;\n    function sleep(uint256 duration) external;\n    function snapshot() external returns (uint256 snapshotId);\n    function snapshotGasLastCall(string calldata name) external returns (uint256 gasUsed);\n    function snapshotGasLastCall(string calldata group, string calldata name) external returns (uint256 gasUsed);\n    function snapshotState() external returns (uint256 snapshotId);\n    function snapshotValue(string calldata name, uint256 value) external;\n    function snapshotValue(string calldata group, string calldata name, uint256 value) external;\n    function sort(uint256[] calldata array) external returns (uint256[] memory);\n    function split(string calldata input, string calldata delimiter) external pure returns (string[] memory outputs);\n    function startBroadcast() external;\n    function startBroadcast(address signer) external;\n    function startBroadcast(uint256 privateKey) external;\n    function startDebugTraceRecording() external;\n    function startMappingRecording() external;\n    function startPrank(address msgSender) external;\n    function startPrank(address msgSender, address txOrigin) external;\n    function startPrank(address msgSender, bool delegateCall) external;\n    function startPrank(address msgSender, address txOrigin, bool delegateCall) external;\n    function startSnapshotGas(string calldata name) external;\n    function startSnapshotGas(string calldata group, string calldata name) external;\n    function startStateDiffRecording() external;\n    function stopAndReturnDebugTraceRecording() external returns (DebugStep[] memory step);\n    function stopAndReturnStateDiff() external returns (AccountAccess[] memory accountAccesses);\n    function stopBroadcast() external;\n    function stopExpectSafeMemory() external;\n    function stopMappingRecording() external;\n    function stopPrank() external;\n    function stopRecord() external;\n    function stopSnapshotGas() external returns (uint256 gasUsed);\n    function stopSnapshotGas(string calldata name) external returns (uint256 gasUsed);\n    function stopSnapshotGas(string calldata group, string calldata name) external returns (uint256 gasUsed);\n    function store(address target, bytes32 slot, bytes32 value) external;\n    function toBase64URL(bytes calldata data) external pure returns (string memory);\n    function toBase64URL(string calldata data) external pure returns (string memory);\n    function toBase64(bytes calldata data) external pure returns (string memory);\n    function toBase64(string calldata data) external pure returns (string memory);\n    function toLowercase(string calldata input) external pure returns (string memory output);\n    function toRlp(bytes[] calldata data) external pure returns (bytes memory);\n    function toString(address value) external pure returns (string memory stringifiedValue);\n    function toString(bytes calldata value) external pure returns (string memory stringifiedValue);\n    function toString(bytes32 value) external pure returns (string memory stringifiedValue);\n    function toString(bool value) external pure returns (string memory stringifiedValue);\n    function toString(uint256 value) external pure returns (string memory stringifiedValue);\n    function toString(int256 value) external pure returns (string memory stringifiedValue);\n    function toUppercase(string calldata input) external pure returns (string memory output);\n    function transact(bytes32 txHash) external;\n    function transact(uint256 forkId, bytes32 txHash) external;\n    function trim(string calldata input) external pure returns (string memory output);\n    function tryFfi(string[] calldata commandInput) external returns (FfiResult memory result);\n    function txGasPrice(uint256 newGasPrice) external;\n    function unixTime() external view returns (uint256 milliseconds);\n    function verifyEd25519(bytes calldata signature, bytes calldata namespace, bytes calldata message, bytes32 publicKey) external pure returns (bool valid);\n    function warmSlot(address target, bytes32 slot) external;\n    function warp(uint256 newTimestamp) external;\n    function writeFile(string calldata path, string calldata data) external;\n    function writeFileBinary(string calldata path, bytes calldata data) external;\n    function writeJson(string calldata json, string calldata path) external;\n    function writeJson(string calldata json, string calldata path, string calldata valueKey) external;\n    function writeLine(string calldata path, string calldata data) external;\n    function writeToml(string calldata json, string calldata path) external;\n    function writeToml(string calldata json, string calldata path, string calldata valueKey) external;\n}\n"
  },
  {
    "path": "testdata/utils/console.sol",
    "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.4.22 <0.9.0;\n\nlibrary console {\n    address constant CONSOLE_ADDRESS = 0x000000000000000000636F6e736F6c652e6c6f67;\n\n    function _sendLogPayloadImplementation(bytes memory payload) internal view {\n        address consoleAddress = CONSOLE_ADDRESS;\n        /// @solidity memory-safe-assembly\n        assembly {\n            pop(staticcall(gas(), consoleAddress, add(payload, 32), mload(payload), 0, 0))\n        }\n    }\n\n    function _castToPure(function(bytes memory) internal view fnIn)\n        internal\n        pure\n        returns (function(bytes memory) pure fnOut)\n    {\n        assembly {\n            fnOut := fnIn\n        }\n    }\n\n    function _sendLogPayload(bytes memory payload) internal pure {\n        _castToPure(_sendLogPayloadImplementation)(payload);\n    }\n\n    function log() internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log()\"));\n    }\n\n    function logInt(int256 p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(int256)\", p0));\n    }\n\n    function logUint(uint256 p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256)\", p0));\n    }\n\n    function logString(string memory p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string)\", p0));\n    }\n\n    function logBool(bool p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool)\", p0));\n    }\n\n    function logAddress(address p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address)\", p0));\n    }\n\n    function logBytes(bytes memory p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bytes)\", p0));\n    }\n\n    function logBytes1(bytes1 p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bytes1)\", p0));\n    }\n\n    function logBytes2(bytes2 p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bytes2)\", p0));\n    }\n\n    function logBytes3(bytes3 p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bytes3)\", p0));\n    }\n\n    function logBytes4(bytes4 p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bytes4)\", p0));\n    }\n\n    function logBytes5(bytes5 p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bytes5)\", p0));\n    }\n\n    function logBytes6(bytes6 p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bytes6)\", p0));\n    }\n\n    function logBytes7(bytes7 p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bytes7)\", p0));\n    }\n\n    function logBytes8(bytes8 p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bytes8)\", p0));\n    }\n\n    function logBytes9(bytes9 p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bytes9)\", p0));\n    }\n\n    function logBytes10(bytes10 p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bytes10)\", p0));\n    }\n\n    function logBytes11(bytes11 p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bytes11)\", p0));\n    }\n\n    function logBytes12(bytes12 p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bytes12)\", p0));\n    }\n\n    function logBytes13(bytes13 p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bytes13)\", p0));\n    }\n\n    function logBytes14(bytes14 p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bytes14)\", p0));\n    }\n\n    function logBytes15(bytes15 p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bytes15)\", p0));\n    }\n\n    function logBytes16(bytes16 p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bytes16)\", p0));\n    }\n\n    function logBytes17(bytes17 p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bytes17)\", p0));\n    }\n\n    function logBytes18(bytes18 p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bytes18)\", p0));\n    }\n\n    function logBytes19(bytes19 p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bytes19)\", p0));\n    }\n\n    function logBytes20(bytes20 p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bytes20)\", p0));\n    }\n\n    function logBytes21(bytes21 p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bytes21)\", p0));\n    }\n\n    function logBytes22(bytes22 p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bytes22)\", p0));\n    }\n\n    function logBytes23(bytes23 p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bytes23)\", p0));\n    }\n\n    function logBytes24(bytes24 p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bytes24)\", p0));\n    }\n\n    function logBytes25(bytes25 p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bytes25)\", p0));\n    }\n\n    function logBytes26(bytes26 p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bytes26)\", p0));\n    }\n\n    function logBytes27(bytes27 p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bytes27)\", p0));\n    }\n\n    function logBytes28(bytes28 p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bytes28)\", p0));\n    }\n\n    function logBytes29(bytes29 p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bytes29)\", p0));\n    }\n\n    function logBytes30(bytes30 p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bytes30)\", p0));\n    }\n\n    function logBytes31(bytes31 p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bytes31)\", p0));\n    }\n\n    function logBytes32(bytes32 p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bytes32)\", p0));\n    }\n\n    function log(uint256 p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256)\", p0));\n    }\n\n    function log(int256 p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(int256)\", p0));\n    }\n\n    function log(string memory p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string)\", p0));\n    }\n\n    function log(bool p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool)\", p0));\n    }\n\n    function log(address p0) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address)\", p0));\n    }\n\n    function log(uint256 p0, uint256 p1) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256)\", p0, p1));\n    }\n\n    function log(uint256 p0, string memory p1) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string)\", p0, p1));\n    }\n\n    function log(uint256 p0, bool p1) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool)\", p0, p1));\n    }\n\n    function log(uint256 p0, address p1) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address)\", p0, p1));\n    }\n\n    function log(string memory p0, uint256 p1) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256)\", p0, p1));\n    }\n\n    function log(string memory p0, int256 p1) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,int256)\", p0, p1));\n    }\n\n    function log(string memory p0, string memory p1) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,string)\", p0, p1));\n    }\n\n    function log(string memory p0, bool p1) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,bool)\", p0, p1));\n    }\n\n    function log(string memory p0, address p1) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,address)\", p0, p1));\n    }\n\n    function log(bool p0, uint256 p1) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256)\", p0, p1));\n    }\n\n    function log(bool p0, string memory p1) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,string)\", p0, p1));\n    }\n\n    function log(bool p0, bool p1) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool)\", p0, p1));\n    }\n\n    function log(bool p0, address p1) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,address)\", p0, p1));\n    }\n\n    function log(address p0, uint256 p1) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256)\", p0, p1));\n    }\n\n    function log(address p0, string memory p1) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,string)\", p0, p1));\n    }\n\n    function log(address p0, bool p1) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,bool)\", p0, p1));\n    }\n\n    function log(address p0, address p1) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,address)\", p0, p1));\n    }\n\n    function log(uint256 p0, uint256 p1, uint256 p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,uint256)\", p0, p1, p2));\n    }\n\n    function log(uint256 p0, uint256 p1, string memory p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,string)\", p0, p1, p2));\n    }\n\n    function log(uint256 p0, uint256 p1, bool p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,bool)\", p0, p1, p2));\n    }\n\n    function log(uint256 p0, uint256 p1, address p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,address)\", p0, p1, p2));\n    }\n\n    function log(uint256 p0, string memory p1, uint256 p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,uint256)\", p0, p1, p2));\n    }\n\n    function log(uint256 p0, string memory p1, string memory p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,string)\", p0, p1, p2));\n    }\n\n    function log(uint256 p0, string memory p1, bool p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,bool)\", p0, p1, p2));\n    }\n\n    function log(uint256 p0, string memory p1, address p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,address)\", p0, p1, p2));\n    }\n\n    function log(uint256 p0, bool p1, uint256 p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,uint256)\", p0, p1, p2));\n    }\n\n    function log(uint256 p0, bool p1, string memory p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,string)\", p0, p1, p2));\n    }\n\n    function log(uint256 p0, bool p1, bool p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,bool)\", p0, p1, p2));\n    }\n\n    function log(uint256 p0, bool p1, address p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,address)\", p0, p1, p2));\n    }\n\n    function log(uint256 p0, address p1, uint256 p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,uint256)\", p0, p1, p2));\n    }\n\n    function log(uint256 p0, address p1, string memory p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,string)\", p0, p1, p2));\n    }\n\n    function log(uint256 p0, address p1, bool p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,bool)\", p0, p1, p2));\n    }\n\n    function log(uint256 p0, address p1, address p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,address)\", p0, p1, p2));\n    }\n\n    function log(string memory p0, uint256 p1, uint256 p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,uint256)\", p0, p1, p2));\n    }\n\n    function log(string memory p0, uint256 p1, string memory p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,string)\", p0, p1, p2));\n    }\n\n    function log(string memory p0, uint256 p1, bool p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,bool)\", p0, p1, p2));\n    }\n\n    function log(string memory p0, uint256 p1, address p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,address)\", p0, p1, p2));\n    }\n\n    function log(string memory p0, string memory p1, uint256 p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,string,uint256)\", p0, p1, p2));\n    }\n\n    function log(string memory p0, string memory p1, string memory p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,string,string)\", p0, p1, p2));\n    }\n\n    function log(string memory p0, string memory p1, bool p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,string,bool)\", p0, p1, p2));\n    }\n\n    function log(string memory p0, string memory p1, address p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,string,address)\", p0, p1, p2));\n    }\n\n    function log(string memory p0, bool p1, uint256 p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,uint256)\", p0, p1, p2));\n    }\n\n    function log(string memory p0, bool p1, string memory p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,string)\", p0, p1, p2));\n    }\n\n    function log(string memory p0, bool p1, bool p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,bool)\", p0, p1, p2));\n    }\n\n    function log(string memory p0, bool p1, address p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,address)\", p0, p1, p2));\n    }\n\n    function log(string memory p0, address p1, uint256 p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,address,uint256)\", p0, p1, p2));\n    }\n\n    function log(string memory p0, address p1, string memory p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,address,string)\", p0, p1, p2));\n    }\n\n    function log(string memory p0, address p1, bool p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,address,bool)\", p0, p1, p2));\n    }\n\n    function log(string memory p0, address p1, address p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,address,address)\", p0, p1, p2));\n    }\n\n    function log(bool p0, uint256 p1, uint256 p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,uint256)\", p0, p1, p2));\n    }\n\n    function log(bool p0, uint256 p1, string memory p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,string)\", p0, p1, p2));\n    }\n\n    function log(bool p0, uint256 p1, bool p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,bool)\", p0, p1, p2));\n    }\n\n    function log(bool p0, uint256 p1, address p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,address)\", p0, p1, p2));\n    }\n\n    function log(bool p0, string memory p1, uint256 p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,uint256)\", p0, p1, p2));\n    }\n\n    function log(bool p0, string memory p1, string memory p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,string)\", p0, p1, p2));\n    }\n\n    function log(bool p0, string memory p1, bool p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,bool)\", p0, p1, p2));\n    }\n\n    function log(bool p0, string memory p1, address p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,address)\", p0, p1, p2));\n    }\n\n    function log(bool p0, bool p1, uint256 p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,uint256)\", p0, p1, p2));\n    }\n\n    function log(bool p0, bool p1, string memory p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,string)\", p0, p1, p2));\n    }\n\n    function log(bool p0, bool p1, bool p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,bool)\", p0, p1, p2));\n    }\n\n    function log(bool p0, bool p1, address p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,address)\", p0, p1, p2));\n    }\n\n    function log(bool p0, address p1, uint256 p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,uint256)\", p0, p1, p2));\n    }\n\n    function log(bool p0, address p1, string memory p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,string)\", p0, p1, p2));\n    }\n\n    function log(bool p0, address p1, bool p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,bool)\", p0, p1, p2));\n    }\n\n    function log(bool p0, address p1, address p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,address)\", p0, p1, p2));\n    }\n\n    function log(address p0, uint256 p1, uint256 p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,uint256)\", p0, p1, p2));\n    }\n\n    function log(address p0, uint256 p1, string memory p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,string)\", p0, p1, p2));\n    }\n\n    function log(address p0, uint256 p1, bool p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,bool)\", p0, p1, p2));\n    }\n\n    function log(address p0, uint256 p1, address p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,address)\", p0, p1, p2));\n    }\n\n    function log(address p0, string memory p1, uint256 p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,string,uint256)\", p0, p1, p2));\n    }\n\n    function log(address p0, string memory p1, string memory p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,string,string)\", p0, p1, p2));\n    }\n\n    function log(address p0, string memory p1, bool p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,string,bool)\", p0, p1, p2));\n    }\n\n    function log(address p0, string memory p1, address p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,string,address)\", p0, p1, p2));\n    }\n\n    function log(address p0, bool p1, uint256 p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,uint256)\", p0, p1, p2));\n    }\n\n    function log(address p0, bool p1, string memory p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,string)\", p0, p1, p2));\n    }\n\n    function log(address p0, bool p1, bool p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,bool)\", p0, p1, p2));\n    }\n\n    function log(address p0, bool p1, address p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,address)\", p0, p1, p2));\n    }\n\n    function log(address p0, address p1, uint256 p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,address,uint256)\", p0, p1, p2));\n    }\n\n    function log(address p0, address p1, string memory p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,address,string)\", p0, p1, p2));\n    }\n\n    function log(address p0, address p1, bool p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,address,bool)\", p0, p1, p2));\n    }\n\n    function log(address p0, address p1, address p2) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,address,address)\", p0, p1, p2));\n    }\n\n    function log(uint256 p0, uint256 p1, uint256 p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,uint256,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, uint256 p1, uint256 p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,uint256,string)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, uint256 p1, uint256 p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,uint256,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, uint256 p1, uint256 p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,uint256,address)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, uint256 p1, string memory p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,string,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, uint256 p1, string memory p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,string,string)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, uint256 p1, string memory p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,string,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, uint256 p1, string memory p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,string,address)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, uint256 p1, bool p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,bool,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, uint256 p1, bool p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,bool,string)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, uint256 p1, bool p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,bool,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, uint256 p1, bool p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,bool,address)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, uint256 p1, address p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,address,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, uint256 p1, address p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,address,string)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, uint256 p1, address p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,address,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, uint256 p1, address p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,uint256,address,address)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, string memory p1, uint256 p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,uint256,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, string memory p1, uint256 p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,uint256,string)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, string memory p1, uint256 p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,uint256,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, string memory p1, uint256 p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,uint256,address)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, string memory p1, string memory p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,string,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, string memory p1, string memory p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,string,string)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, string memory p1, string memory p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,string,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, string memory p1, string memory p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,string,address)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, string memory p1, bool p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,bool,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, string memory p1, bool p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,bool,string)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, string memory p1, bool p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,bool,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, string memory p1, bool p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,bool,address)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, string memory p1, address p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,address,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, string memory p1, address p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,address,string)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, string memory p1, address p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,address,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, string memory p1, address p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,string,address,address)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, bool p1, uint256 p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,uint256,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, bool p1, uint256 p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,uint256,string)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, bool p1, uint256 p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,uint256,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, bool p1, uint256 p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,uint256,address)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, bool p1, string memory p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,string,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, bool p1, string memory p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,string,string)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, bool p1, string memory p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,string,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, bool p1, string memory p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,string,address)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, bool p1, bool p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,bool,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, bool p1, bool p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,bool,string)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, bool p1, bool p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,bool,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, bool p1, bool p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,bool,address)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, bool p1, address p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,address,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, bool p1, address p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,address,string)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, bool p1, address p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,address,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, bool p1, address p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,bool,address,address)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, address p1, uint256 p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,uint256,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, address p1, uint256 p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,uint256,string)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, address p1, uint256 p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,uint256,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, address p1, uint256 p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,uint256,address)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, address p1, string memory p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,string,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, address p1, string memory p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,string,string)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, address p1, string memory p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,string,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, address p1, string memory p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,string,address)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, address p1, bool p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,bool,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, address p1, bool p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,bool,string)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, address p1, bool p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,bool,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, address p1, bool p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,bool,address)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, address p1, address p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,address,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, address p1, address p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,address,string)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, address p1, address p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,address,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(uint256 p0, address p1, address p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(uint256,address,address,address)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, uint256 p1, uint256 p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,uint256,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, uint256 p1, uint256 p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,uint256,string)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, uint256 p1, uint256 p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,uint256,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, uint256 p1, uint256 p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,uint256,address)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, uint256 p1, string memory p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,string,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, uint256 p1, string memory p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,string,string)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, uint256 p1, string memory p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,string,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, uint256 p1, string memory p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,string,address)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, uint256 p1, bool p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,bool,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, uint256 p1, bool p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,bool,string)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, uint256 p1, bool p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,bool,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, uint256 p1, bool p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,bool,address)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, uint256 p1, address p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,address,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, uint256 p1, address p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,address,string)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, uint256 p1, address p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,address,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, uint256 p1, address p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,uint256,address,address)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, string memory p1, uint256 p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,string,uint256,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, string memory p1, uint256 p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,string,uint256,string)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, string memory p1, uint256 p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,string,uint256,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, string memory p1, uint256 p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,string,uint256,address)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, string memory p1, string memory p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,string,string,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, string memory p1, string memory p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,string,string,string)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, string memory p1, string memory p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,string,string,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, string memory p1, string memory p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,string,string,address)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, string memory p1, bool p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,string,bool,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, string memory p1, bool p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,string,bool,string)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, string memory p1, bool p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,string,bool,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, string memory p1, bool p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,string,bool,address)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, string memory p1, address p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,string,address,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, string memory p1, address p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,string,address,string)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, string memory p1, address p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,string,address,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, string memory p1, address p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,string,address,address)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, bool p1, uint256 p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,uint256,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, bool p1, uint256 p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,uint256,string)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, bool p1, uint256 p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,uint256,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, bool p1, uint256 p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,uint256,address)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, bool p1, string memory p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,string,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, bool p1, string memory p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,string,string)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, bool p1, string memory p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,string,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, bool p1, string memory p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,string,address)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, bool p1, bool p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,bool,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, bool p1, bool p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,bool,string)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, bool p1, bool p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,bool,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, bool p1, bool p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,bool,address)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, bool p1, address p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,address,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, bool p1, address p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,address,string)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, bool p1, address p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,address,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, bool p1, address p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,bool,address,address)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, address p1, uint256 p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,address,uint256,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, address p1, uint256 p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,address,uint256,string)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, address p1, uint256 p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,address,uint256,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, address p1, uint256 p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,address,uint256,address)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, address p1, string memory p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,address,string,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, address p1, string memory p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,address,string,string)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, address p1, string memory p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,address,string,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, address p1, string memory p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,address,string,address)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, address p1, bool p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,address,bool,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, address p1, bool p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,address,bool,string)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, address p1, bool p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,address,bool,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, address p1, bool p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,address,bool,address)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, address p1, address p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,address,address,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, address p1, address p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,address,address,string)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, address p1, address p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,address,address,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(string memory p0, address p1, address p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(string,address,address,address)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, uint256 p1, uint256 p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,uint256,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, uint256 p1, uint256 p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,uint256,string)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, uint256 p1, uint256 p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,uint256,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, uint256 p1, uint256 p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,uint256,address)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, uint256 p1, string memory p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,string,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, uint256 p1, string memory p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,string,string)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, uint256 p1, string memory p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,string,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, uint256 p1, string memory p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,string,address)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, uint256 p1, bool p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,bool,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, uint256 p1, bool p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,bool,string)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, uint256 p1, bool p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,bool,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, uint256 p1, bool p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,bool,address)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, uint256 p1, address p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,address,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, uint256 p1, address p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,address,string)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, uint256 p1, address p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,address,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, uint256 p1, address p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,uint256,address,address)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, string memory p1, uint256 p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,uint256,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, string memory p1, uint256 p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,uint256,string)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, string memory p1, uint256 p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,uint256,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, string memory p1, uint256 p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,uint256,address)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, string memory p1, string memory p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,string,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, string memory p1, string memory p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,string,string)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, string memory p1, string memory p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,string,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, string memory p1, string memory p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,string,address)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, string memory p1, bool p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,bool,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, string memory p1, bool p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,bool,string)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, string memory p1, bool p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,bool,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, string memory p1, bool p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,bool,address)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, string memory p1, address p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,address,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, string memory p1, address p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,address,string)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, string memory p1, address p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,address,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, string memory p1, address p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,string,address,address)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, bool p1, uint256 p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,uint256,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, bool p1, uint256 p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,uint256,string)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, bool p1, uint256 p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,uint256,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, bool p1, uint256 p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,uint256,address)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, bool p1, string memory p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,string,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, bool p1, string memory p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,string,string)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, bool p1, string memory p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,string,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, bool p1, string memory p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,string,address)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, bool p1, bool p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,bool,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, bool p1, bool p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,bool,string)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, bool p1, bool p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,bool,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, bool p1, bool p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,bool,address)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, bool p1, address p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,address,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, bool p1, address p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,address,string)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, bool p1, address p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,address,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, bool p1, address p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,bool,address,address)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, address p1, uint256 p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,uint256,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, address p1, uint256 p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,uint256,string)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, address p1, uint256 p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,uint256,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, address p1, uint256 p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,uint256,address)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, address p1, string memory p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,string,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, address p1, string memory p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,string,string)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, address p1, string memory p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,string,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, address p1, string memory p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,string,address)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, address p1, bool p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,bool,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, address p1, bool p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,bool,string)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, address p1, bool p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,bool,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, address p1, bool p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,bool,address)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, address p1, address p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,address,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, address p1, address p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,address,string)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, address p1, address p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,address,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(bool p0, address p1, address p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(bool,address,address,address)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, uint256 p1, uint256 p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,uint256,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, uint256 p1, uint256 p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,uint256,string)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, uint256 p1, uint256 p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,uint256,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, uint256 p1, uint256 p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,uint256,address)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, uint256 p1, string memory p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,string,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, uint256 p1, string memory p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,string,string)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, uint256 p1, string memory p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,string,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, uint256 p1, string memory p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,string,address)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, uint256 p1, bool p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,bool,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, uint256 p1, bool p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,bool,string)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, uint256 p1, bool p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,bool,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, uint256 p1, bool p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,bool,address)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, uint256 p1, address p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,address,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, uint256 p1, address p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,address,string)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, uint256 p1, address p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,address,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, uint256 p1, address p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,uint256,address,address)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, string memory p1, uint256 p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,string,uint256,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, string memory p1, uint256 p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,string,uint256,string)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, string memory p1, uint256 p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,string,uint256,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, string memory p1, uint256 p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,string,uint256,address)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, string memory p1, string memory p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,string,string,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, string memory p1, string memory p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,string,string,string)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, string memory p1, string memory p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,string,string,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, string memory p1, string memory p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,string,string,address)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, string memory p1, bool p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,string,bool,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, string memory p1, bool p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,string,bool,string)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, string memory p1, bool p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,string,bool,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, string memory p1, bool p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,string,bool,address)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, string memory p1, address p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,string,address,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, string memory p1, address p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,string,address,string)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, string memory p1, address p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,string,address,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, string memory p1, address p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,string,address,address)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, bool p1, uint256 p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,uint256,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, bool p1, uint256 p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,uint256,string)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, bool p1, uint256 p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,uint256,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, bool p1, uint256 p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,uint256,address)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, bool p1, string memory p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,string,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, bool p1, string memory p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,string,string)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, bool p1, string memory p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,string,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, bool p1, string memory p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,string,address)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, bool p1, bool p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,bool,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, bool p1, bool p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,bool,string)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, bool p1, bool p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,bool,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, bool p1, bool p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,bool,address)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, bool p1, address p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,address,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, bool p1, address p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,address,string)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, bool p1, address p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,address,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, bool p1, address p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,bool,address,address)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, address p1, uint256 p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,address,uint256,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, address p1, uint256 p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,address,uint256,string)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, address p1, uint256 p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,address,uint256,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, address p1, uint256 p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,address,uint256,address)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, address p1, string memory p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,address,string,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, address p1, string memory p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,address,string,string)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, address p1, string memory p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,address,string,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, address p1, string memory p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,address,string,address)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, address p1, bool p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,address,bool,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, address p1, bool p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,address,bool,string)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, address p1, bool p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,address,bool,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, address p1, bool p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,address,bool,address)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, address p1, address p2, uint256 p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,address,address,uint256)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, address p1, address p2, string memory p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,address,address,string)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, address p1, address p2, bool p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,address,address,bool)\", p0, p1, p2, p3));\n    }\n\n    function log(address p0, address p1, address p2, address p3) internal pure {\n        _sendLogPayload(abi.encodeWithSignature(\"log(address,address,address,address)\", p0, p1, p2, p3));\n    }\n}\n"
  },
  {
    "path": "typos.toml",
    "content": "[files]\nextend-exclude = [\n    \".git\",\n    \"target\",\n    \"testdata\",\n    \"Cargo.toml\",\n    \"Cargo.lock\",\n    \"*.json\",\n    \"*.js\",\n    \"*.css\",\n    \"*.html\",\n    \"**/tests/**\",\n    \"**/test/**\",\n    \"**/*_test.*\",\n    \"**/*_tests.*\",\n]\n\n[default.extend-words]\nser = \"ser\"\nratatui = \"ratatui\"\nCaf = \"Caf\"\nfroms = \"froms\"\nstrat = \"strat\"\nba = \"ba\"\nconsts = \"consts\"\n"
  }
]